ref: d990c25d5795b16c181e875bf2f55aa06c2f75f9
parent: 70f57939ef437a822bfacde3a6e487633b6ba706
author: henesy <devnull@localhost>
date: Sun Nov 4 06:03:02 EST 2018
init 3
--- /dev/null
+++ b/lib/acid/386
@@ -1,0 +1,205 @@
+// 386 support
+
+defn acidinit() // Called after all the init modules are loaded
+{
+ bpl = {};
+ bpid = -1;
+ bpfmt = 'b';
+
+ srcpath = {
+ "./",
+ };
+
+ nopstop = 0;
+ srcfiles = {}; // list of loaded files
+ srctext = {}; // the text of the files
+ Labspoff = 4; // adjustment to Label's sp
+ Labpcoff = 0; // adjustment to Label's pc
+}
+
+defn linkreg(addr)
+{
+ return 0;
+}
+
+defn stk() // trace
+{
+ _stk(*PC, *SP, 0, 0);
+}
+
+defn lstk() // trace with locals
+{
+ _stk(*PC, *SP, 0, 1);
+}
+
+defn kstk() // kernel stack, PC and SP point to kernel
+{
+ _stk(*PC, *SP, 0, 0);
+}
+
+defn lkstk() // kernel stack and locals, PC and SP are kernel's
+{
+ _stk(*PC, *SP, 0, 1);
+}
+defn gpr() // print general(hah hah!) purpose registers
+{
+ print("AX\t", *AX, " BX\t", *BX, " CX\t", *CX, " DX\t", *DX, "\n");
+ print("DI\t", *DI, " SI\t", *SI, " BP\t", *BP, "\n");
+}
+
+defn spr() // print special processor registers
+{
+ local pc;
+ local cause;
+
+ pc = *PC;
+ print("PC\t", pc, " ", fmt(pc, 'a'), " ");
+ pfl(pc);
+ print("SP\t", *SP, " ECODE ", *ECODE, " EFLAG ", *EFLAGS, "\n");
+ print("CS\t", *CS, " DS\t ", *DS, " SS\t", *SS, "\n");
+ print("GS\t", *GS, " FS\t ", *FS, " ES\t", *ES, "\n");
+
+ cause = *TRAP;
+ print("TRAP\t", cause, " ", reason(cause), "\n");
+}
+
+defn regs() // print all registers
+{
+ spr();
+ gpr();
+}
+
+defn step()
+{
+ local ur;
+ local addrs;
+ local id;
+ local l;
+ local b;
+ local bl;
+ local sl;
+ local pc;
+
+ complex Proc proc;
+ ur = proc.dbgreg;
+ if ur == 0 then
+ error("step: process not in breakpoint trap");
+ complex Ureg ur;
+
+ //
+ // stop all kprocs that could potentially hit this breakpoint
+ // make a list of all the breakpoints at this address
+ //
+ bl = {};
+ sl = {};
+ l = bpl;
+
+ while l do {
+ b = head l;
+ if ((b[2] & *PC) == b[2]) then {
+ if status(b[1]) != "Stopped" then {
+ stop(b[1]);
+ sl = append sl, b[1];
+ }
+ bl = append bl, b;
+ }
+ l = tail l;
+ }
+
+ //
+ // delete all the breakpoints at this address
+ //
+ if bl then {
+ l = bl;
+ while l do {
+ b = head l;
+ _bpconddel(b[0]);
+ l = tail l;
+ }
+ }
+
+ //
+ // single step to the following address
+ //
+ addrs = follow(*PC);
+ id = bpset(addrs[0]);
+ startstop(pid);
+ bpdel(id);
+
+ //
+ // restore all the breakpoints at this address
+ //
+ if bl then {
+ l = bl;
+ while l do {
+ b = head l;
+ _bpcondset(b[0], b[1], b[2], b[3]);
+ l = tail l;
+ }
+ }
+
+ //
+ // restart all kprocs that could potentially hit this breakpoint
+ //
+ if sl then {
+ l = sl;
+ while l do {
+ start(head l);
+ l = tail l;
+ }
+ }
+}
+
+aggr Ureg
+{
+ 'X' 0 di;
+ 'X' 4 si;
+ 'X' 8 bp;
+ 'X' 12 nsp;
+ 'X' 16 bx;
+ 'X' 20 dx;
+ 'X' 24 cx;
+ 'X' 28 ax;
+ 'X' 32 gs;
+ 'X' 36 fs;
+ 'X' 40 es;
+ 'X' 44 ds;
+ 'X' 48 trap;
+ 'X' 52 ecode;
+ 'X' 56 pc;
+ 'X' 60 cs;
+ 'X' 64 flags;
+ {
+ 'X' 68 usp;
+ 'X' 68 sp;
+ };
+ 'X' 72 ss;
+};
+
+
+defn
+Ureg(addr) {
+ complex Ureg addr;
+ print(" di ", addr.di, "\n");
+ print(" si ", addr.si, "\n");
+ print(" bp ", addr.bp, "\n");
+ print(" nsp ", addr.nsp, "\n");
+ print(" bx ", addr.bx, "\n");
+ print(" dx ", addr.dx, "\n");
+ print(" cx ", addr.cx, "\n");
+ print(" ax ", addr.ax, "\n");
+ print(" gs ", addr.gs, "\n");
+ print(" fs ", addr.fs, "\n");
+ print(" es ", addr.es, "\n");
+ print(" ds ", addr.ds, "\n");
+ print(" trap ", addr.trap, "\n");
+ print(" ecode ", addr.ecode, "\n");
+ print(" pc ", addr.pc, "\n");
+ print(" cs ", addr.cs, "\n");
+ print(" flags ", addr.flags, "\n");
+ print(" sp ", addr.sp, "\n");
+ print("}\n");
+ print(" ss ", addr.ss, "\n");
+};
+
+print("/sys/lib/acid/386");
--- /dev/null
+++ b/lib/acid/amd64
@@ -1,0 +1,123 @@
+// amd64
+
+defn acidinit()
+{
+ bplist = {};
+ bpfmt = 'b';
+
+ srcpath = {
+ "./",
+ "/sys/src/libc/port/",
+ "/sys/src/libc/9sys/",
+ "/sys/src/libc/amd64/"
+ };
+
+ srcfiles = {}; // list of loaded files
+ srctext = {}; // the text of the files
+}
+
+defn gpr()
+{
+ print("AX ", *AX, "\n");
+ print("BX ", *BX, "\n");
+ print("CX ", *CX, "\n");
+ print("DX ", *DX, "\n");
+ print("DI ", *DI, "\n");
+ print("SI ", *SI, "\n");
+ print("BP ", *BP, "\n");
+ print("R8 ", *R8, "\n");
+ print("R9 ", *R9, "\n");
+ print("R10 ", *R10, "\n");
+ print("R11 ", *R11, "\n");
+ print("R12 ", *R12, "\n");
+ print("R13 ", *R13, "\n");
+ print("R14 ", *R14, "\n");
+ print("R15 ", *R15, "\n");
+}
+
+defn spr()
+{
+ print("DS ", *DS, " ES ", *ES, " FS ", *FS, " GS ", *GS, "\n");
+ print("TYPE ", *TYPE, "\n");
+ print("ERROR ", *ERROR, "\n");
+ print("PC ", *PC, "\n");
+ print("CS ", *CS, "\n");
+ print("FLAGS ", *FLAGS, "\n");
+ print("SP ", *SP, "\n");
+ print("SS ", *SS, "\n");
+}
+
+defn x87r()
+{
+ print("FCW ", *FCW, " FSW ", *FSW, " FTW ", *FTW, " FOP ", *FOP, "\n");
+ print("RIP ", *RIP, " RDP ", *RDP, "\n");
+ print("M0 ", *M0, "\n");
+ print("M1 ", *M1, "\n");
+ print("M2 ", *M2, "\n");
+ print("M3 ", *M3, "\n");
+ print("M4 ", *M4, "\n");
+ print("M5 ", *M5, "\n");
+ print("M6 ", *M6, "\n");
+ print("M7 ", *M7, "\n");
+}
+
+defn xmmr()
+{
+ print("MXCSR ", *MXCSR, " MXCSRMASK ", *MXCSRMASK, "\n");
+ print("X0 ", *X0, "\n");
+ print("X1 ", *X1, "\n");
+ print("X2 ", *X2, "\n");
+ print("X3 ", *X3, "\n");
+ print("X4 ", *X4, "\n");
+ print("X5 ", *X5, "\n");
+ print("X6 ", *X6, "\n");
+ print("X7 ", *X7, "\n");
+ print("X8 ", *X8, "\n");
+ print("X9 ", *X9, "\n");
+ print("X10 ", *X10, "\n");
+ print("X11 ", *X11, "\n");
+ print("X12 ", *X12, "\n");
+ print("X13 ", *X13, "\n");
+ print("X14 ", *X14, "\n");
+ print("X15 ", *X15, "\n");
+}
+
+defn fpr()
+{
+ xmmr();
+}
+
+defn regs()
+{
+ gpr();
+ spr();
+}
+
+defn pstop(pid)
+{
+ local l;
+ local pc;
+
+ pc = *PC;
+
+ print(pid,": ", reason(*TRAP), "\t");
+ print(fmt(pc, 'a'), "\t", fmt(pc, 'i'), "\n");
+
+ if notes then {
+ if notes[0] != "sys: breakpoint" then {
+ print("Notes pending:\n");
+ l = notes;
+ while l do {
+ print("\t", head l, "\n");
+ l = tail l;
+ }
+ }
+ }
+}
+
+defn stk()
+{
+ _stk(*PC, *SP, 0, 0);
+}
+
+print("/sys/lib/acid/amd64");
--- /dev/null
+++ b/lib/acid/arm
@@ -1,0 +1,84 @@
+// ARM support
+
+defn acidinit() // Called after all the init modules are loaded
+{
+ bpl = {};
+ bpid = -1;
+ bpfmt = 'X';
+ nopstop = 0;
+
+ srcpath = {
+ "./",
+ };
+
+ srcfiles = {}; // list of loaded files
+ srctext = {}; // the text of the files
+}
+
+defn linkreg(addr)
+{
+ return 0;
+}
+
+defn stk() // trace
+{
+ _stk(*PC, *SP, linkreg(0), 0);
+}
+
+defn lstk() // trace with locals
+{
+ _stk(*PC, *SP, linkreg(0), 1);
+}
+
+defn kstk()
+{
+ local lab;
+ complex Proc proc;
+ lab = proc.sched;
+ complex Label lab;
+ _stk(lab.pc\X, lab.sp\X, linkreg(0), 0);
+}
+
+defn lkstk()
+{
+ local lab;
+ complex Proc proc;
+ lab = proc.sched;
+ complex Label lab;
+ _stk(lab.pc\X, lab.sp\X, linkreg(0), 1);
+}
+
+defn gpr() // print general purpose registers
+{
+ print("R0\t", *R0, " R1\t", *R1, " R2\t", *R2, " R3\t", *R3, "\n");
+ print("R4\t", *R4, " R5\t", *R5, " R6\t", *R6, " R7\t", *R7, "\n");
+ print("R8\t", *R8, " R9\t", *R9, " R10\t", *R10, " R11\t", *R11, "\n");
+ print("R12\t", *R12, "\n");
+ return 0;
+}
+
+defn spr() // print special processor registers
+{
+ local pc;
+ local cause;
+ local lr;
+
+ pc = *PC;
+ lr = *LINK;
+ print("PC\t", pc, " ", fmt(pc, 'a'), " ");
+ pfl(pc);
+ print("LINK\t", lr, " ", fmt(lr, 'a'), " ");
+ pfl(lr);
+ print("TYPE: ", reason(*TYPE), "\n");
+ print("SP\t", *SP, "\n");
+
+ return 0;
+}
+
+defn regs() // print all registers
+{
+ spr();
+ gpr();
+}
+
+print("$ROOT/lib/acid/arm");
--- /dev/null
+++ b/lib/acid/gpa
@@ -1,0 +1,88 @@
+//
+// generate ``General Purpose Ascii'' file for HP logic analyser
+//
+// usage: gpa()
+// note: output has to be postprocessed with "sed 's/0x//g' "...
+//
+
+defn functions(start, end)
+{
+ print("[FUNCTIONS]\n");
+ pc = start;
+ while pc < end do {
+ bnd = fnbound(pc);
+ print(pc\a, "\t", bnd[0], "..", bnd[1]-1, "\n");
+ pc = bnd[1];
+ }
+ print("\n");
+}
+
+defn variables(start, end)
+{
+ print("[VARIABLES]\n");
+ // TODO: how do we get this one?
+ print("\n");
+}
+
+defn sourcelines(start, end)
+{
+ local pc, curfile, curline, newfile, newline;
+
+ print("[SOURCE LINES]\n");
+ pc = txtstart;
+ curfile = "<no-file>";
+ curline = -1;
+ while pc < txtend do {
+ newfile = pcfile(pc);
+ newline = pcline(pc);
+ if newfile != curfile then {
+ if curline != -1 then
+ print("\n");
+ print("File: ", newfile, "\n");
+ curfile = newfile;
+ }
+ if newline != curline then {
+ print(newline, "\t", pc, "\n");
+ curline = newline;
+ }
+ pc++;
+ }
+ print("\n");
+}
+
+defn gpa()
+{
+ local l, ent, txtstart, txtend, datastart, dataend, pc, bnd;
+
+ print("[SECTIONS]\n");
+ l = map();
+ while l do {
+ ent = head l;
+ if ent[0] == "text" || ent[0] == "data" then {
+ if ent[0] == "text" then {
+ txtstart = ent[1];
+ txtend = ent[2];
+ }
+ else {
+ datastart = ent[1];
+ dataend = ent[2];
+ }
+ print(ent[0], "\t", ent[1], "..", ent[2]-1, "\n");
+ }
+ l = tail l;
+ }
+ print("\n");
+
+ functions(txtstart, txtend);
+// variables(datastart, dataend);
+ sourcelines(datastart, dataend);
+
+ print("[START ADDRESS]\n");
+ print(txtstart, "\n");
+ print("\n");
+}
+
+defn acidinit()
+{
+ gpa();
+}
--- /dev/null
+++ b/lib/acid/inferno
@@ -1,0 +1,63 @@
+//
+// experimental acid functions for Inferno (common to native and emu)
+//
+// problems arise because of unnamed substructures having to be
+// named in emu, for instance Ref. We cheat by ``knowing'' that Ref
+// is first in the structure, to keep this code portable between native
+// and emu.
+//
+
+//
+// ps() - Process Listing
+//
+complex Ref pidalloc;
+
+defn
+ps()
+{
+ local i;
+ local n;
+ local done;
+ local p;
+ local curpid;
+
+ i = 0;
+ done = 0;
+ n = pidalloc.ref;
+ curpid = pid;
+ p = procalloc.arena;
+
+ if n > conf.nproc then
+ n = conf.nproc;
+
+ print("PID PC PRI STATE NAME\n");
+ while n > 0 && i < conf.nproc do {
+ complex Proc p;
+ if p.state != 0 then {
+ print(p.pid, "\t", p.pc\X, "\t", p.pri, "\t", status(p.pid), "\t");
+ mem(p.text, "s");
+ n = n - 1;
+ }
+ i = i + 1;
+ p = p + sizeofProc;
+ }
+}
+
+defn labels()
+{
+ local n;
+ local l;
+ complex Proc proc;
+
+ n = proc.nerrlab;
+ l = proc.errlab;
+ while n > 0 do {
+ complex Label l;
+ print(l.pc\a, " ");
+ pfl(l.pc);
+ l = l + sizeofLabel;
+ n = n - 1;
+ }
+}
+
+print("$ROOT/lib/acid/inferno");
--- /dev/null
+++ b/lib/acid/mips
@@ -1,0 +1,217 @@
+// Mips support
+
+defn acidinit() // Called after all the init modules are loaded
+{
+ bplist = {};
+ bpfmt = 'X';
+
+ srcpath = {
+ "./",
+ "/sys/src/libc/port/",
+ "/sys/src/libc/9sys/",
+ "/sys/src/libc/mips/"
+ };
+
+ srcfiles = {}; // list of loaded files
+ srctext = {}; // the text of the files
+}
+
+defn stk() // trace
+{
+ _stk(*PC, *SP, linkreg(0), 0);
+}
+
+defn lstk() // trace with locals
+{
+ _stk(*PC, *SP, linkreg(0), 1);
+}
+
+defn gpr() // print general purpose registers
+{
+ print("R1\t", *R1, " R2\t", *R2, " R3\t", *R3, "\n");
+ print("R4\t", *R4, " R5\t", *R5, " R6\t", *R6, "\n");
+ print("R7\t", *R7, " R8\t", *R8, " R9\t", *R9, "\n");
+ print("R10\t", *R10, " R11\t", *R11, " R12\t", *R12, "\n");
+ print("R13\t", *R13, " R14\t", *R14, " R15\t", *R15, "\n");
+ print("R16\t", *R16, " R17\t", *R17, " R18\t", *R18, "\n");
+ print("R19\t", *R19, " R20\t", *R20, " R21\t", *R21, "\n");
+ print("R22\t", *R22, " R23\t", *R23, " R24\t", *R24, "\n");
+ print("R25\t", *R25, " R26\t", *R26, " R27\t", *R27, "\n");
+ print("R28\t", *R28, " R29\t", *SP, " R30\t", *R30, "\n");
+ print("R31\t", *R31, "\n");
+}
+
+defn Fpr()
+{
+ print("F0\t", *fmt(F0, 'G'), "\tF2\t", *fmt(F2, 'G'), "\n");
+ print("F4\t", *fmt(F4, 'G'), "\tF6\t", *fmt(F6, 'G'), "\n");
+ print("F8\t", *fmt(F8, 'G'), "\tF10\t", *fmt(F10, 'G'), "\n");
+ print("F12\t", *fmt(F12, 'G'), "\tF14\t", *fmt(F14, 'G'), "\n");
+ print("F16\t", *fmt(F16, 'G'), "\tF18\t", *fmt(F18, 'G'), "\n");
+ print("F20\t", *fmt(F20, 'G'), "\tF22\t", *fmt(F22, 'G'), "\n");
+ print("F24\t", *fmt(F24, 'G'), "\tF26\t", *fmt(F26, 'G'), "\n");
+ print("F28\t", *fmt(F28, 'G'), "\tF30\t", *fmt(F30, 'G'), "\n");
+}
+
+defn fpr()
+{
+ print("F0\t", *fmt(F0, 'g'), "\tF1\t", *fmt(F1, 'g'), "\n");
+ print("F2\t", *fmt(F2, 'g'), "\tF3\t", *fmt(F3, 'g'), "\n");
+ print("F4\t", *fmt(F4, 'g'), "\tF5\t", *fmt(F5, 'g'), "\n");
+ print("F6\t", *fmt(F6, 'g'), "\tF7\t", *fmt(F7, 'g'), "\n");
+ print("F8\t", *fmt(F8, 'g'), "\tF9\t", *fmt(F9, 'g'), "\n");
+ print("F10\t", *fmt(F10, 'g'), "\tF11\t", *fmt(F11, 'g'), "\n");
+ print("F12\t", *fmt(F12, 'g'), "\tF13\t", *fmt(F13, 'g'), "\n");
+ print("F14\t", *fmt(F14, 'g'), "\tF15\t", *fmt(F15, 'g'), "\n");
+ print("F16\t", *fmt(F16, 'g'), "\tF17\t", *fmt(F17, 'g'), "\n");
+ print("F18\t", *fmt(F18, 'g'), "\tF19\t", *fmt(F19, 'g'), "\n");
+ print("F20\t", *fmt(F20, 'g'), "\tF21\t", *fmt(F21, 'g'), "\n");
+ print("F22\t", *fmt(F22, 'g'), "\tF23\t", *fmt(F23, 'g'), "\n");
+ print("F24\t", *fmt(F24, 'g'), "\tF25\t", *fmt(F25, 'g'), "\n");
+ print("F26\t", *fmt(F26, 'g'), "\tF27\t", *fmt(F27, 'g'), "\n");
+ print("F28\t", *fmt(F28, 'g'), "\tF29\t", *fmt(F29, 'g'), "\n");
+ print("F30\t", *fmt(F30, 'g'), "\tF31\t", *fmt(F31, 'g'), "\n");
+}
+
+defn spr() // print special processor registers
+{
+ local pc, link, cause;
+
+ pc = *PC;
+ print("PC\t", pc, " ", fmt(pc, 'a'), " ");
+ pfl(pc);
+
+ link = *R31;
+ print("SP\t", *SP, "\tLINK\t", link, " ", fmt(link, 'a'), " ");
+ pfl(link);
+
+ cause = *CAUSE;
+ print("STATUS\t", *STATUS, "\tCAUSE\t", cause, " ", reason(cause), "\n");
+ print("TLBVIR\t", *TLBVIRT, "\tBADVADR\t", *BADVADDR, "\n");
+
+ print("HI\t", *HI, "\tLO\t", *LO, "\n");
+}
+
+defn regs() // print all registers
+{
+ spr();
+ gpr();
+}
+
+defn pstop(pid)
+{
+ local l, pc;
+
+ pc = *PC;
+
+ print(pid,": ", reason(*CAUSE), "\t");
+ print(fmt(pc, 'a'), "\t", fmt(pc, 'i'), "\n");
+
+ if notes then {
+ if notes[0] != "sys: breakpoint" then {
+ print("Notes pending:\n");
+ l = notes;
+ while l do {
+ print("\t", head l, "\n");
+ l = tail l;
+ }
+ }
+ }
+}
+
+sizeofUreg = 152;
+aggr Ureg
+{
+ 'X' 0 status;
+ 'X' 4 pc;
+ {
+ 'X' 8 sp;
+ 'X' 8 usp;
+ };
+ 'X' 12 cause;
+ 'X' 16 badvaddr;
+ 'X' 20 tlbvirt;
+ 'X' 24 hi;
+ 'X' 28 lo;
+ 'X' 32 r31;
+ 'X' 36 r30;
+ 'X' 40 r28;
+ 'X' 44 r27;
+ 'X' 48 r26;
+ 'X' 52 r25;
+ 'X' 56 r24;
+ 'X' 60 r23;
+ 'X' 64 r22;
+ 'X' 68 r21;
+ 'X' 72 r20;
+ 'X' 76 r19;
+ 'X' 80 r18;
+ 'X' 84 r17;
+ 'X' 88 r16;
+ 'X' 92 r15;
+ 'X' 96 r14;
+ 'X' 100 r13;
+ 'X' 104 r12;
+ 'X' 108 r11;
+ 'X' 112 r10;
+ 'X' 116 r9;
+ 'X' 120 r8;
+ 'X' 124 r7;
+ 'X' 128 r6;
+ 'X' 132 r5;
+ 'X' 136 r4;
+ 'X' 140 r3;
+ 'X' 144 r2;
+ 'X' 148 r1;
+};
+
+defn
+Ureg(addr) {
+ complex Ureg addr;
+ print(" status ", addr.status, "\n");
+ print(" pc ", addr.pc, "\n");
+ print(" sp ", addr.sp, "\n");
+ print(" cause ", addr.cause, "\n");
+ print(" badvaddr ", addr.badvaddr, "\n");
+ print(" tlbvirt ", addr.tlbvirt, "\n");
+ print(" hi ", addr.hi, "\n");
+ print(" lo ", addr.lo, "\n");
+ print(" r31 ", addr.r31, "\n");
+ print(" r30 ", addr.r30, "\n");
+ print(" r28 ", addr.r28, "\n");
+ print(" r27 ", addr.r27, "\n");
+ print(" r26 ", addr.r26, "\n");
+ print(" r25 ", addr.r25, "\n");
+ print(" r24 ", addr.r24, "\n");
+ print(" r23 ", addr.r23, "\n");
+ print(" r22 ", addr.r22, "\n");
+ print(" r21 ", addr.r21, "\n");
+ print(" r20 ", addr.r20, "\n");
+ print(" r19 ", addr.r19, "\n");
+ print(" r18 ", addr.r18, "\n");
+ print(" r17 ", addr.r17, "\n");
+ print(" r16 ", addr.r16, "\n");
+ print(" r15 ", addr.r15, "\n");
+ print(" r14 ", addr.r14, "\n");
+ print(" r13 ", addr.r13, "\n");
+ print(" r12 ", addr.r12, "\n");
+ print(" r11 ", addr.r11, "\n");
+ print(" r10 ", addr.r10, "\n");
+ print(" r9 ", addr.r9, "\n");
+ print(" r8 ", addr.r8, "\n");
+ print(" r7 ", addr.r7, "\n");
+ print(" r6 ", addr.r6, "\n");
+ print(" r5 ", addr.r5, "\n");
+ print(" r4 ", addr.r4, "\n");
+ print(" r3 ", addr.r3, "\n");
+ print(" r2 ", addr.r2, "\n");
+ print(" r1 ", addr.r1, "\n");
+};
+
+defn linkreg(addr)
+{
+ complex Ureg addr;
+ return addr.r31\X;
+}
+
+print("/sys/lib/acid/mips");
--- /dev/null
+++ b/lib/acid/port
@@ -1,0 +1,547 @@
+// portable acid for all architectures
+
+defn pfl(addr)
+{
+ print(pcfile(addr), ":", pcline(addr), "\n");
+}
+
+defn
+notestk(addr)
+{
+ local pc, sp;
+ complex Ureg addr;
+
+ pc = addr.pc\X;
+ sp = addr.sp\X;
+
+ print("Note pc:", pc, " sp:", sp, " ", fmt(pc, 'a'), " ");
+ pfl(pc);
+ _stk(pc, sp, linkreg(addr), 1);
+}
+
+defn labstk(l) // trace from a label
+{
+ _stk(*(l+4), *l, linkreg(0), 0);
+}
+
+defn params(param)
+{
+ while param do {
+ sym = head param;
+ print(sym[0], "=", sym[1]);
+ param = tail param;
+ if param then
+ print (",");
+ }
+}
+
+defn locals(l)
+{
+ local sym;
+
+ while l do {
+ sym = head l;
+ print("\t", sym[0], "=", sym[1], "\n");
+ l = tail l;
+ }
+}
+
+defn _stk(pc, sp, link, dolocals)
+{
+ local stk;
+
+ print("At pc:", pc, ":", fmt(pc, 'a'), " ");
+ pfl(pc);
+
+ stk = strace(pc, sp, link);
+
+ while stk do {
+ frame = head stk;
+ print(fmt(frame[0], 'a'), "(");
+ params(frame[2]);
+ print(") ", pcfile(frame[0]), ":", pcline(frame[0]));
+ print("\n\tcalled from ", fmt(frame[1], 'a'), " ");
+ pfl(frame[1]);
+ stk = tail stk;
+ if dolocals then
+ locals(frame[3]);
+ }
+}
+
+defn findsrc(file)
+{
+ local lst, src;
+
+ if file[0] == '/' then {
+ src = file(file);
+ if src != {} then {
+ srcfiles = append srcfiles, file;
+ srctext = append srctext, src;
+ return src;
+ }
+ return {};
+ }
+
+ lst = srcpath;
+ while head lst do {
+ src = file(head lst+file);
+ if src != {} then {
+ srcfiles = append srcfiles, file;
+ srctext = append srctext, src;
+ return src;
+ }
+ lst = tail lst;
+ }
+}
+
+defn line(addr)
+{
+ local src, file;
+
+ file = pcfile(addr);
+ src = match(file, srcfiles);
+
+ if src >= 0 then
+ src = srctext[src];
+ else
+ src = findsrc(file);
+
+ if src == {} then {
+ print("no source for ", file, "\n");
+ return {};
+ }
+ line = pcline(addr)-1;
+ print(file, ":", src[line], "\n");
+}
+
+defn addsrcdir(dir)
+{
+ dir = dir+"/";
+
+ if match(dir, srcpath) >= 0 then {
+ print("already in srcpath\n");
+ return {};
+ }
+
+ srcpath = {dir}+srcpath;
+}
+
+defn source()
+{
+ local l;
+
+ l = srcpath;
+ while l do {
+ print(head l, "\n");
+ l = tail l;
+ }
+ l = srcfiles;
+
+ while l do {
+ print("\t", head l, "\n");
+ l = tail l;
+ }
+}
+
+defn Bsrc(addr)
+{
+ local lst;
+
+ lst = srcpath;
+ file = pcfile(addr);
+ if file[0] == '/' && access(file) then {
+ rc("B "+itoa(-pcline(addr))+" "+file);
+ return {};
+ }
+ while head lst do {
+ name = head lst+file;
+ if access(name) then {
+ rc("B "+itoa(-pcline(addr))+" "+name);
+ return {};
+ }
+ lst = tail lst;
+ }
+ print("no source for ", file, "\n");
+}
+
+defn src(addr)
+{
+ local src, file, line, cline, text;
+
+ file = pcfile(addr);
+ src = match(file, srcfiles);
+
+ if src >= 0 then
+ src = srctext[src];
+ else
+ src = findsrc(file);
+
+ if src == {} then {
+ print("no source for ", file, "\n");
+ return {};
+ }
+
+ cline = pcline(addr)-1;
+ print(file, ":", cline, "\n");
+ line = cline-5;
+ loop 0,10 do {
+ if line >= 0 then {
+ if line == cline then
+ print(">");
+ else
+ print(" ");
+ text = src[line];
+ if text == {} then
+ return {};
+ print(line, "\t", text, "\n");
+ }
+ line = line+1;
+ }
+}
+
+defn stopped(pid) // called from acid when a process changes state
+{
+ pstop(pid); // stub so this is easy to replace
+}
+
+defn procs() // print status of processes
+{
+ local c, lst, cpid;
+
+ cpid = pid;
+ lst = proclist;
+ while lst do {
+ np = head lst;
+ setproc(np);
+ if np == cpid then
+ c = '>';
+ else
+ c = ' ';
+ print(fmt(c, 'c'), np, ": ", status(np), " at ", fmt(*PC, 'a'), " setproc(", np, ")\n");
+ lst = tail lst;
+ }
+ pid = cpid;
+ if pid != 0 then
+ setproc(pid);
+}
+
+defn asm(addr)
+{
+ local bound;
+
+ bound = fnbound(addr);
+
+ addr = fmt(addr, 'i');
+ loop 1,30 do {
+ print(fmt(addr, 'a'), " ", fmt(addr, 'X'));
+ print("\t", @addr++, "\n");
+ if bound != {} && addr > bound[1] then {
+ lasmaddr = addr;
+ return {};
+ }
+ }
+ lasmaddr = addr;
+}
+
+defn casm()
+{
+ asm(lasmaddr);
+}
+
+defn new()
+{
+ bplist = {};
+ newproc(progargs);
+ // Dont miss the delay slot calls
+ bpset(follow(main)[0]);
+ cont();
+ bpdel(*PC);
+}
+
+defn stmnt() // step one statement
+{
+ local line;
+
+ line = pcline(*PC);
+ while 1 do {
+ step();
+ if line != pcline(*PC) then {
+ src(*PC);
+ return {};
+ }
+ }
+}
+
+defn func() // step until we leave the current function
+{
+ local bound, end, start, pc;
+
+ bound = fnbound(*PC);
+ if bound == {} then {
+ print("cannot locate text symbol\n");
+ return {};
+ }
+
+ pc = *PC;
+ start = bound[0];
+ end = bound[1];
+ while pc >= start && pc < end do {
+ step();
+ pc = *PC;
+ }
+}
+
+defn next()
+{
+ local sp, bound;
+
+ sp = *SP;
+ bound = fnbound(*PC);
+ stmnt();
+ pc = *PC;
+ if pc >= bound[0] && pc < bound[1] then
+ return {};
+
+ while (pc < bound[0] || pc > bound[1]) && sp >= *SP do {
+ step();
+ pc = *PC;
+ }
+ src(*PC);
+}
+
+defn dump(addr, n, fmt)
+{
+ loop 0, n do {
+ print(fmt(addr, 'X'), ": ");
+ addr = mem(addr, fmt);
+ }
+}
+
+defn mem(addr, fmt)
+{
+
+ local i, c, n;
+
+ i = 0;
+ while fmt[i] != 0 do {
+ c = fmt[i];
+ n = 0;
+ while '0' <= fmt[i] && fmt[i] <= '9' do {
+ n = 10*n + fmt[i]-'0';
+ i = i+1;
+ }
+ if n <= 0 then n = 1;
+ addr = fmt(addr, fmt[i]);
+ while n > 0 do {
+ print(*addr++, " ");
+ n = n-1;
+ }
+ i = i+1;
+ }
+ print("\n");
+ return addr;
+}
+
+defn symbols(pattern)
+{
+ local l, s;
+
+ l = symbols;
+ while l do {
+ s = head l;
+ if regexp(pattern, s[0]) then
+ print(s[0], "\t", s[1], "\t", s[2], "\n");
+ l = tail l;
+ }
+}
+
+defn spsrch(len)
+{
+ local addr, a, s, e;
+
+ addr = *SP;
+ s = origin & 0x7fffffff;
+ e = etext & 0x7fffffff;
+ loop 1, len do {
+ a = *addr++;
+ c = a & 0x7fffffff;
+ if c > s && c < e then {
+ print("src(", a, ")\n");
+ pfl(a);
+ }
+ }
+}
+
+defn bppush(val)
+{
+ return {"p", val};
+}
+
+defn bpderef()
+{
+ return {"*", 0};
+}
+
+defn bpmask()
+{
+ return {"&", 0};
+}
+
+defn bpeq()
+{
+ return {"=", 0};
+}
+
+defn bpneq()
+{
+ return {"!", 0};
+}
+
+defn bpand()
+{
+ return {"a", 0};
+}
+
+defn bpor()
+{
+ return {"o", 0};
+}
+
+defn bpcondset(pid, addr, conds)
+{
+ local l;
+ local id;
+ local found;
+
+ if status(pid) != "Stopped" then {
+ print("Waiting...\n");
+ stop(pid);
+ }
+
+ id = 0;
+ found = 0;
+
+ while !found && id <= 255 do {
+ l = bpl;
+ while l && head head l != id do {
+ l = tail l;
+ }
+
+ if !l then
+ found = 1;
+ else
+ id = id + 1;
+ }
+
+ if !found then {
+ print("error: no breakpoints available\n");
+ return -1;
+ }
+
+ bpl = append bpl, {id\d, pid\d, addr\X, conds};
+
+ _bpcondset(id, pid, addr, conds);
+
+ return id;
+}
+
+defn bpconddel(id)
+{
+ local i;
+ local l;
+
+ l = bpl;
+ i = 0;
+ while l do {
+ if id == head head l then {
+ bpl = delete bpl, i;
+ _bpconddel(id);
+ if id == bpid then
+ bpid = -1;
+ return {};
+ }
+ i = i + 1;
+ l = tail l;
+ }
+ print("no breakpoint with id ", id\d, ".\n");
+}
+
+defn bpprint(b)
+{
+ local l;
+
+ print(b[0], "\t", b[1], "\t", fmt(b[2], 'a'), " ", b[2]);
+ print("\t{");
+ l = b[3];
+ while l do {
+ print("\n\t\t\t\t\t", head l);
+ l = tail l;
+ }
+ print(" }\n");
+}
+
+defn bptab()
+{
+ local l;
+
+ l = bpl;
+ print("ID PID ADDR CONDITIONS\n");
+ while l do {
+ bpprint(head l);
+ l = tail l;
+ }
+}
+
+defn cont()
+{
+ local b, c, l, found;
+
+ l = bpl;
+ found = 0;
+ c = *PC;
+ while !found && l do {
+ b = head l;
+ if b[2] == c then {
+ nopstop = 1;
+ step();
+ nopstop = 0;
+ found = 1;
+ } else {
+ l = tail l;
+ }
+ }
+
+ return startstop(pid);
+}
+
+defn bpset(addr) // set a breakpoint
+{
+ return bpcondset(pid, addr, {});
+}
+
+defn bpdel(id)
+{
+ bpconddel(id);
+}
+
+defn bpaddr(id)
+{
+ local i;
+ local l;
+ local b;
+
+ l = bpl;
+ i = 0;
+ while l do {
+ b = head l;
+ if id == b[0] then
+ return b[2];
+ i = i + 1;
+ l = tail l;
+ }
+ print("bpaddr(", id\d, "): no match\n");
+ return {};
+}
+
+progargs="";
+print("$ROOT/lib/acid/port");
--- /dev/null
+++ b/lib/acid/power
@@ -1,0 +1,233 @@
+// Power PC support
+
+defn acidinit() // Called after all the init modules are loaded
+{
+ bpl = {};
+ bpid = -1;
+ bpfmt = 'X';
+ nopstop = 0;
+ bplist = {};
+
+ srcpath = {
+ "./",
+ "/sys/src/libc/port/",
+ "/sys/src/libc/9sys/",
+ "/sys/src/libc/power/"
+ };
+
+ srcfiles = {}; // list of loaded files
+ srctext = {}; // the text of the files
+}
+
+// defn stk() // trace
+// {
+// _stk(*PC, *SP, linkreg(0), 0);
+// }
+
+// defn lstk() // trace with locals
+// {
+// _stk(*PC, *SP, linkreg(0), 1);
+// }
+
+defn ustk(ur)
+{
+ complex Ureg ur;
+ _stk(ur.pc, ur.sp, 0, 0);
+}
+
+defn lustk(ur)
+{
+ complex Ureg ur;
+ _stk(ur.pc, ur.sp, 0, 1);
+}
+
+defn stk()
+{
+ ustk(0);
+}
+
+defn lstk()
+{
+ lustk(0);
+}
+
+defn kstk()
+{
+ local lab;
+ complex Proc proc;
+ lab = proc.sched;
+ complex Label lab;
+ _stk(lab.pc\X, lab.sp\X, 0, 0);
+}
+
+defn lkstk()
+{
+ local lab;
+ complex Proc proc;
+ lab = proc.sched;
+ complex Label lab;
+ _stk(lab.pc\X, lab.sp\X, 0, 1);
+}
+
+defn gpr() // print general purpose registers
+{
+ print("SP\t", *SP, " R2\t", *R2, " R3\t", *R3, "\n");
+ print("R4\t", *R4, " R5\t", *R5, " R6\t", *R6, "\n");
+ print("R7\t", *R7, " R8\t", *R8, " R9\t", *R9, "\n");
+ print("R10\t", *R10, " R11\t", *R11, " R12\t", *R12, "\n");
+ print("R13\t", *R13, " R14\t", *R14, " R15\t", *R15, "\n");
+ print("R16\t", *R16, " R17\t", *R17, " R18\t", *R18, "\n");
+ print("R19\t", *R19, " R20\t", *R20, " R21\t", *R21, "\n");
+ print("R22\t", *R22, " R23\t", *R23, " R24\t", *R24, "\n");
+ print("R25\t", *R25, " R26\t", *R26, " R27\t", *R27, "\n");
+ print("R28\t", *R28, " R29\t", *R29, " R30\t", *R30, "\n");
+ print("R31\t", *R31, "\n");
+}
+
+defn Fpr()
+{
+ fpr();
+}
+
+defn fpr()
+{
+ print("F0\t", *fmt(F0, 'G'), "\tF1\t", *fmt(F1, 'G'), "\n");
+ print("F2\t", *fmt(F2, 'G'), "\tF3\t", *fmt(F3, 'G'), "\n");
+ print("F4\t", *fmt(F4, 'G'), "\tF5\t", *fmt(F5, 'G'), "\n");
+ print("F6\t", *fmt(F6, 'G'), "\tF7\t", *fmt(F7, 'G'), "\n");
+ print("F8\t", *fmt(F8, 'G'), "\tF9\t", *fmt(F9, 'G'), "\n");
+ print("F10\t", *fmt(F10, 'G'), "\tF11\t", *fmt(F11, 'G'), "\n");
+ print("F12\t", *fmt(F12, 'G'), "\tF13\t", *fmt(F13, 'G'), "\n");
+ print("F14\t", *fmt(F14, 'G'), "\tF15\t", *fmt(F15, 'G'), "\n");
+ print("F16\t", *fmt(F16, 'G'), "\tF17\t", *fmt(F17, 'G'), "\n");
+ print("F18\t", *fmt(F18, 'G'), "\tF19\t", *fmt(F19, 'G'), "\n");
+ print("F20\t", *fmt(F20, 'G'), "\tF21\t", *fmt(F21, 'G'), "\n");
+ print("F22\t", *fmt(F22, 'G'), "\tF23\t", *fmt(F23, 'G'), "\n");
+ print("F24\t", *fmt(F24, 'G'), "\tF25\t", *fmt(F25, 'G'), "\n");
+ print("F26\t", *fmt(F26, 'G'), "\tF27\t", *fmt(F27, 'G'), "\n");
+ print("F28\t", *fmt(F28, 'G'), "\tF29\t", *fmt(F29, 'G'), "\n");
+ print("F30\t", *fmt(F30, 'G'), "\tF31\t", *fmt(F31, 'G'), "\n");
+}
+
+defn spr() // print special processor registers
+{
+ local pc, link, cause;
+
+ pc = *PC;
+ print("PC\t", pc, " ", fmt(pc, 'a'), " ");
+ pfl(pc);
+
+ link = *R31;
+ print("SP\t", *SP, "\tLINK\t", link, " ", fmt(link, 'a'), " ");
+ pfl(link);
+
+ cause = *CAUSE;
+ print("SRR1\t", *SRR1, "\tCAUSE\t", cause, " ", reason(cause), "\n");
+ print("LR\t", *LR, "\tCR\t", *CR, "\n");
+
+ print("XER\t", *XER, "\tCTR\t", *CTR, "\n");
+}
+
+defn regs() // print all registers
+{
+ spr();
+ gpr();
+}
+
+
+defn linkreg(addr)
+{
+ return *LR;
+}
+
+sizeofUreg = 160;
+aggr Ureg
+{
+ 'U' 0 cause;
+ 'U' 4 status;
+ 'U' 8 pc;
+ 'U' 12 pad;
+ 'U' 16 lr;
+ 'U' 20 cr;
+ 'U' 24 xer;
+ 'U' 28 ctr;
+ 'U' 32 r0;
+ 'U' 36 sp;
+ 'U' 40 r2;
+ 'U' 44 r3;
+ 'U' 48 r4;
+ 'U' 52 r5;
+ 'U' 56 r6;
+ 'U' 60 r7;
+ 'U' 64 r8;
+ 'U' 68 r9;
+ 'U' 72 r10;
+ 'U' 76 r11;
+ 'U' 80 r12;
+ 'U' 84 r13;
+ 'U' 88 r14;
+ 'U' 92 r15;
+ 'U' 96 r16;
+ 'U' 100 r17;
+ 'U' 104 r18;
+ 'U' 108 r19;
+ 'U' 112 r20;
+ 'U' 116 r21;
+ 'U' 120 r22;
+ 'U' 124 r23;
+ 'U' 128 r24;
+ 'U' 132 r25;
+ 'U' 136 r26;
+ 'U' 140 r27;
+ 'U' 144 r28;
+ 'U' 148 r29;
+ 'U' 152 r30;
+ 'U' 156 r31;
+};
+
+defn
+Ureg(addr) {
+ complex Ureg addr;
+ print(" cause ", addr.cause, "\n");
+ print(" status ", addr.status, "\n");
+ print(" pc ", addr.pc, "\n");
+ print(" pad ", addr.pad, "\n");
+ print(" lr ", addr.lr, "\n");
+ print(" cr ", addr.cr, "\n");
+ print(" xer ", addr.xer, "\n");
+ print(" ctr ", addr.ctr, "\n");
+ print(" r0 ", addr.r0, "\n");
+ print(" sp ", addr.sp, "\n");
+ print(" r2 ", addr.r2, "\n");
+ print(" r3 ", addr.r3, "\n");
+ print(" r4 ", addr.r4, "\n");
+ print(" r5 ", addr.r5, "\n");
+ print(" r6 ", addr.r6, "\n");
+ print(" r7 ", addr.r7, "\n");
+ print(" r8 ", addr.r8, "\n");
+ print(" r9 ", addr.r9, "\n");
+ print(" r10 ", addr.r10, "\n");
+ print(" r11 ", addr.r11, "\n");
+ print(" r12 ", addr.r12, "\n");
+ print(" r13 ", addr.r13, "\n");
+ print(" r14 ", addr.r14, "\n");
+ print(" r15 ", addr.r15, "\n");
+ print(" r16 ", addr.r16, "\n");
+ print(" r17 ", addr.r17, "\n");
+ print(" r18 ", addr.r18, "\n");
+ print(" r19 ", addr.r19, "\n");
+ print(" r20 ", addr.r20, "\n");
+ print(" r21 ", addr.r21, "\n");
+ print(" r22 ", addr.r22, "\n");
+ print(" r23 ", addr.r23, "\n");
+ print(" r24 ", addr.r24, "\n");
+ print(" r25 ", addr.r25, "\n");
+ print(" r26 ", addr.r26, "\n");
+ print(" r27 ", addr.r27, "\n");
+ print(" r28 ", addr.r28, "\n");
+ print(" r29 ", addr.r29, "\n");
+ print(" r30 ", addr.r30, "\n");
+ print(" r31 ", addr.r31, "\n");
+};
+
+print("/sys/lib/acid/power");
--- /dev/null
+++ b/lib/acid/rdebug
@@ -1,0 +1,116 @@
+// Acid remote debug (using devdbg.c)
+
+defn step()
+{
+ local ur;
+ local addrs;
+ local id;
+ local l;
+ local b;
+ local bl;
+ local sl;
+
+ complex Proc proc;
+ ur = proc.dbgreg;
+ if ur == 0 then
+ error("step: process not in breakpoint trap");
+ complex Ureg ur;
+
+ //
+ // stop all kprocs that could potentially hit this breakpoint
+ // make a list of all the breakpoints at this address
+ //
+ bl = {};
+ sl = {};
+ l = bpl;
+ while l do {
+ b = head l;
+ if b[2] == ur.pc then {
+ if status(b[1]) != "Stopped" then {
+ stop(b[1]);
+ sl = append sl, b[1];
+ }
+ bl = append bl, b;
+ }
+ l = tail l;
+ }
+
+ //
+ // delete all the breakpoints at this address
+ //
+ if bl then {
+ l = bl;
+ while l do {
+ b = head l;
+ _bpconddel(b[0]);
+ l = tail l;
+ }
+ }
+
+ //
+ // single step to the following address
+ //
+ addrs = follow(ur.pc);
+ id = bpset(addrs[0]);
+ startstop(pid);
+ bpdel(id);
+
+ //
+ // restore all the breakpoints at this address
+ //
+ if bl then {
+ l = bl;
+ while l do {
+ b = head l;
+ _bpcondset(b[0], b[1], b[2], b[3]);
+ l = tail l;
+ }
+ }
+
+ //
+ // restart all kprocs that could potentially hit this breakpoint
+ //
+ if sl then {
+ l = sl;
+ while l do {
+ start(head l);
+ l = tail l;
+ }
+ }
+}
+
+defn pstop(pid)
+{
+ local l;
+ local pc;
+ local ur;
+
+ if nopstop then
+ return {};
+
+ complex Proc proc;
+ ur = proc.dbgreg;
+ complex Ureg ur;
+ pc = ur.pc;
+
+ if _breakid != -1 then {
+ print("break ", _breakid\d, ": pid ");
+ _breakid = -1;
+ }
+ print(pid,": ", status(pid), "\t");
+
+ print(fmt(pc, 'a'), "\t", fmt(pc, 'i'), "\n");
+
+ if notes then {
+ if notes[0] != "sys: breakpoint" then {
+ print("Notes pending:\n");
+ l = notes;
+ while l do {
+ print("\t", head l, "\n");
+ l = tail l;
+ }
+ }
+ }
+}
+
+print("$ROOT/lib/acid/rdebug");
--- /dev/null
+++ b/lib/acid/sparc
@@ -1,0 +1,218 @@
+// Sparc support
+
+defn acidinit() // Called after all the init modules are loaded
+{
+ bplist = {};
+ bpfmt = 'X';
+
+ srcpath = {
+ "./",
+ "/sys/src/libc/port/",
+ "/sys/src/libc/9sys/",
+ "/sys/src/libc/sparc/"
+ };
+
+ srcfiles = {}; // list of loaded files
+ srctext = {}; // the text of the files
+}
+
+defn stk() // trace
+{
+ _stk(*PC, *R1, linkreg(0), 0);
+}
+
+defn lstk() // trace with locals
+{
+ _stk(*PC, *R1, linkreg(0), 1);
+}
+
+defn gpr() // print general purpose registers
+{
+ print("R1\t", *R1, "R2\t", *R2, "R3\t", *R3, "\n");
+ print("R4\t", *R4, "R5\t", *R5, "R6\t", *R6, "\n");
+ print("R7\t", *R7, "R8\t", *R8, "R9\t", *R9, "\n");
+ print("R10\t", *R10, "R11\t", *R11, "R12\t", *R12, "\n");
+ print("R13\t", *R13, "R14\t", *R14, "R15\t", *R15, "\n");
+ print("R16\t", *R16, "R17\t", *R17, "R18\t", *R18, "\n");
+ print("R19\t", *R19, "R20\t", *R20, "R21\t", *R21, "\n");
+ print("R22\t", *R22, "R23\t", *R23, "R24\t", *R24, "\n");
+ print("R25\t", *R25, "R26\t", *R26, "R27\t", *R27, "\n");
+ print("R28\t", *R28, "R29\t", *R29, "R30\t", *R30, "\n");
+ print("R31\t", *R31, "\n");
+}
+
+defn spr() // print special processor registers
+{
+ local pc;
+ local link;
+ local cause;
+
+ pc = *PC;
+ print("PC\t", pc, " ", fmt(pc, 'a'), " ");
+ pfl(pc);
+ print("PSR\t", *PSR, "\n");
+
+ link = *R15;
+ print("SP\t", *R1, "\tLINK\t\t", link, " ", fmt(link, 'a'));
+ pfl(link);
+
+ cause = *TBR;
+ print("Y\t", *Y, "\tCAUSE\t", *Y, cause, " ", reason(cause), "\n");
+}
+
+defn Fpr()
+{
+ print("F0\t", *fmt(F0, 'G'), "\tF2\t", *fmt(F2, 'G'), "\n");
+ print("F4\t", *fmt(F4, 'G'), "\tF6\t", *fmt(F6, 'G'), "\n");
+ print("F8\t", *fmt(F8, 'G'), "\tF10\t", *fmt(F10, 'G'), "\n");
+ print("F12\t", *fmt(F12, 'G'), "\tF14\t", *fmt(F14, 'G'), "\n");
+ print("F16\t", *fmt(F16, 'G'), "\tF18\t", *fmt(F18, 'G'), "\n");
+ print("F20\t", *fmt(F20, 'G'), "\tF22\t", *fmt(F22, 'G'), "\n");
+ print("F24\t", *fmt(F24, 'G'), "\tF26\t", *fmt(F26, 'G'), "\n");
+ print("F28\t", *fmt(F28, 'G'), "\tF30\t", *fmt(F30, 'G'), "\n");
+}
+
+defn fpr()
+{
+ print("F0\t", *fmt(F0, 'g'), "\tF1\t", *fmt(F1, 'g'), "\n");
+ print("F2\t", *fmt(F2, 'g'), "\tF3\t", *fmt(F3, 'g'), "\n");
+ print("F4\t", *fmt(F4, 'g'), "\tF5\t", *fmt(F5, 'g'), "\n");
+ print("F6\t", *fmt(F6, 'g'), "\tF7\t", *fmt(F7, 'g'), "\n");
+ print("F8\t", *fmt(F8, 'g'), "\tF9\t", *fmt(F9, 'g'), "\n");
+ print("F10\t", *fmt(F10, 'g'), "\tF11\t", *fmt(F11, 'g'), "\n");
+ print("F12\t", *fmt(F12, 'g'), "\tF13\t", *fmt(F13, 'g'), "\n");
+ print("F14\t", *fmt(F14, 'g'), "\tF15\t", *fmt(F15, 'g'), "\n");
+ print("F16\t", *fmt(F16, 'g'), "\tF17\t", *fmt(F17, 'g'), "\n");
+ print("F18\t", *fmt(F18, 'g'), "\tF19\t", *fmt(F19, 'g'), "\n");
+ print("F20\t", *fmt(F20, 'g'), "\tF21\t", *fmt(F21, 'g'), "\n");
+ print("F22\t", *fmt(F22, 'g'), "\tF23\t", *fmt(F23, 'g'), "\n");
+ print("F24\t", *fmt(F24, 'g'), "\tF25\t", *fmt(F25, 'g'), "\n");
+ print("F26\t", *fmt(F26, 'g'), "\tF27\t", *fmt(F27, 'g'), "\n");
+ print("F28\t", *fmt(F28, 'g'), "\tF29\t", *fmt(F29, 'g'), "\n");
+ print("F30\t", *fmt(F30, 'g'), "\tF31\t", *fmt(F31, 'g'), "\n");
+}
+
+defn regs() // print all registers
+{
+ spr();
+ gpr();
+}
+
+defn pstop(pid)
+{
+ local l;
+ local pc;
+
+ pc = *PC;
+
+ print(pid,": ", reason(*TBR), "\t");
+ print(fmt(pc, 'a'), "\t", fmt(pc, 'i'), "\n");
+
+ if notes then {
+ if notes[0] != "sys: breakpoint" then {
+ print("Notes pending:\n");
+ l = notes;
+ while l do {
+ print("\t", head l, "\n");
+ l = tail l;
+ }
+ }
+ }
+}
+
+aggr Ureg
+{
+ 'U' 0 r0;
+ {
+ 'U' 4 sp;
+ 'U' 4 usp;
+ 'U' 4 r1;
+ };
+ 'U' 8 r2;
+ 'U' 12 r3;
+ 'U' 16 r4;
+ 'U' 20 r5;
+ 'U' 24 r6;
+ 'U' 28 r7;
+ 'U' 32 r8;
+ 'U' 36 r9;
+ 'U' 40 r10;
+ 'U' 44 r11;
+ 'U' 48 r12;
+ 'U' 52 r13;
+ 'U' 56 r14;
+ 'U' 60 r15;
+ 'U' 64 r16;
+ 'U' 68 r17;
+ 'U' 72 r18;
+ 'U' 76 r19;
+ 'U' 80 r20;
+ 'U' 84 r21;
+ 'U' 88 r22;
+ 'U' 92 r23;
+ 'U' 96 r24;
+ 'U' 100 r25;
+ 'U' 104 r26;
+ 'U' 108 r27;
+ 'U' 112 r28;
+ 'U' 116 r29;
+ 'U' 120 r30;
+ 'U' 124 r31;
+ 'U' 128 y;
+ 'U' 132 tbr;
+ 'U' 136 psr;
+ 'U' 140 npc;
+ 'U' 144 pc;
+ 'U' 148 pad;
+};
+
+defn
+Ureg(addr) {
+ complex Ureg addr;
+ print(" r0 ", addr.r0, "\n");
+ print(" sp ", addr.sp, "\n");
+ print(" r2 ", addr.r2, "\n");
+ print(" r3 ", addr.r3, "\n");
+ print(" r4 ", addr.r4, "\n");
+ print(" r5 ", addr.r5, "\n");
+ print(" r6 ", addr.r6, "\n");
+ print(" r7 ", addr.r7, "\n");
+ print(" r8 ", addr.r8, "\n");
+ print(" r9 ", addr.r9, "\n");
+ print(" r10 ", addr.r10, "\n");
+ print(" r11 ", addr.r11, "\n");
+ print(" r12 ", addr.r12, "\n");
+ print(" r13 ", addr.r13, "\n");
+ print(" r14 ", addr.r14, "\n");
+ print(" r15 ", addr.r15, "\n");
+ print(" r16 ", addr.r16, "\n");
+ print(" r17 ", addr.r17, "\n");
+ print(" r18 ", addr.r18, "\n");
+ print(" r19 ", addr.r19, "\n");
+ print(" r20 ", addr.r20, "\n");
+ print(" r21 ", addr.r21, "\n");
+ print(" r22 ", addr.r22, "\n");
+ print(" r23 ", addr.r23, "\n");
+ print(" r24 ", addr.r24, "\n");
+ print(" r25 ", addr.r25, "\n");
+ print(" r26 ", addr.r26, "\n");
+ print(" r27 ", addr.r27, "\n");
+ print(" r28 ", addr.r28, "\n");
+ print(" r29 ", addr.r29, "\n");
+ print(" r30 ", addr.r30, "\n");
+ print(" r31 ", addr.r31, "\n");
+ print(" y ", addr.y, "\n");
+ print(" tbr ", addr.tbr, "\n");
+ print(" psr ", addr.psr, "\n");
+ print(" npc ", addr.npc, "\n");
+ print(" pc ", addr.pc, "\n");
+ print(" pad ", addr.pad, "\n");
+};
+
+defn linkreg(addr)
+{
+ complex Ureg addr;
+ return addr.r15\X;
+}
+
+print("/sys/lib/acid/sparc");
--- /dev/null
+++ b/lib/convcs/big5
@@ -1,0 +1,1 @@
+ ,、。.・;:?!︰…‥﹐﹑﹒·﹔﹕﹖﹗︲–︱—︳�︴﹏()︵︶{}︷︸〔〕︹︺【】︻︼《》︽︾〈〉︿﹀「」﹁﹂『』﹃﹄﹙﹚﹛﹜﹝﹞‘’“”〝〞‵′#&*※§〃○●△▲◎☆★◇◆□■▽▼㊣℅‾�_�﹉﹊﹍﹎﹋﹌#&*+-×÷±√<>=≤≥≠∞≒≡﹢﹣﹤﹥﹦∼∩∪⊥∠∟⊿㏒㏑∫∮∵∴♀♂♁☉↑↓←→↖↗↙↘∥∣��/\$¥〒¢£%@℃℉$%@㏕㎜㎝㎞㏎㎡㎎㎏㏄°兙兛兞兝兡兣嗧瓩糎▁▂▃▄▅▆▇█▏▎▍▌▋▊▉┼┴┬┤├▔─│▕┌┐└┘╭╮╰╯═╞╪╡◢◣◥◤╱╲╳0123456789ⅠⅡⅢⅣⅤⅥⅦⅧⅨⅩ〡〢〣〤〥〦〧〨〩�卄�ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyzΑΒΓΔΕΖΗΘΙΚΛΜΝΞΟΠΡΣΤΥΦΧΨΩαβγδεζηθικλμνξοπρστυφχψωㄅㄆㄇㄈㄉㄊㄋㄌㄍㄎㄏㄐㄑㄒㄓㄔㄕㄖㄗㄘㄙㄚㄛㄜㄝㄞㄟㄠㄡㄢㄣㄤㄥㄦㄧㄨㄩ˙ˉˊˇˋ���������������������������������������������������������������一乙丁七乃九了二人儿入八几刀刁力匕十卜又三下丈上丫丸凡久么也乞于亡兀刃勺千叉口土士夕大女子孑孓寸小尢尸山川工己已巳巾干廾弋弓才丑丐不中丰丹之尹予云井互五亢仁什仃仆仇仍今介仄元允內六兮公冗凶分切刈勻勾勿化匹午升卅卞厄友及反壬天夫太夭孔少尤尺屯巴幻廿弔引心戈戶手扎支文斗斤方日曰月木欠止歹毋比毛氏水火爪父爻片牙牛犬王丙世丕且丘主乍乏乎以付仔仕他仗代令仙仞充兄冉冊冬凹出凸刊加功包匆北匝仟半卉卡占卯卮去可古右召叮叩叨叼司叵叫另只史叱台句叭叻四囚外央失奴奶孕它尼巨巧左市布平幼弁弘弗必戊打扔扒扑斥旦朮本未末札正母民氐永汁汀氾犯玄玉瓜瓦甘生用甩田由甲申疋白皮皿目矛矢石示禾穴立丞丟乒乓乩亙交亦亥仿伉伙伊伕伍伐休伏仲件任仰仳份企伋光兇兆先全共再冰列刑划刎刖劣匈匡匠印危吉吏同吊吐吁吋各向名合吃后吆吒因回囝圳地在圭圬圯圩夙多夷夸妄奸妃好她如妁字存宇守宅安寺尖屹州帆并年式弛忙忖戎戌戍成扣扛托收早旨旬旭曲曳有朽朴朱朵次此死氖汝汗汙江池汐汕污汛汍汎灰牟牝百竹米糸缶羊羽老考而耒耳聿肉肋肌臣自至臼舌舛舟艮色艾虫血行衣西阡串亨位住佇佗佞伴佛何估佐佑伽伺伸佃佔似但佣作你伯低伶余佝佈佚兌克免兵冶冷別判利刪刨劫助努劬匣即卵吝吭吞吾否呎吧呆呃吳呈呂君吩告吹吻吸吮吵吶吠吼呀吱含吟听囪困囤囫坊坑址坍均坎圾坐坏圻壯夾妝妒妨妞妣妙妖妍妤妓妊妥孝孜孚孛完宋宏尬局屁尿尾岐岑岔岌巫希序庇床廷弄弟彤形彷役忘忌志忍忱快忸忪戒我抄抗抖技扶抉扭把扼找批扳抒扯折扮投抓抑抆改攻攸旱更束李杏材村杜杖杞杉杆杠杓杗步每求汞沙沁沈沉沅沛汪決沐汰沌汨沖沒汽沃汲汾汴沆汶沍沔沘沂灶灼災灸牢牡牠狄狂玖甬甫男甸皂盯矣私秀禿究系罕肖肓肝肘肛肚育良芒芋芍見角言谷豆豕貝赤走足身車辛辰迂迆迅迄巡邑邢邪邦那酉釆里防阮阱阪阬並乖乳事些亞享京佯依侍佳使佬供例來侃佰併侈佩佻侖佾侏侑佺兔兒兕兩具其典冽函刻券刷刺到刮制剁劾劻卒協卓卑卦卷卸卹取叔受味呵咖呸咕咀呻呷咄咒咆呼咐呱呶和咚呢周咋命咎固垃坷坪坩坡坦坤坼夜奉奇奈奄奔妾妻委妹妮姑姆姐姍始姓姊妯妳姒姅孟孤季宗定官宜宙宛尚屈居屆岷岡岸岩岫岱岳帘帚帖帕帛帑幸庚店府底庖延弦弧弩往征彿彼忝忠忽念忿怏怔怯怵怖怪怕怡性怩怫怛或戕房戾所承拉拌拄抿拂抹拒招披拓拔拋拈抨抽押拐拙拇
\ No newline at end of file
--- /dev/null
+++ b/lib/convcs/charsets
@@ -1,0 +1,225 @@
+iso_8859-1:1987=iso-8859-1
+iso-ir-100=iso-8859-1
+iso_8859-1=iso-8859-1
+8859_1=iso-8859-1 # botched alias
+iso8859-1=iso-8859-1 # commonly seen non IANA alias
+iso8859_1=iso-8859-1 # lookup should probably map _ to -
+latin1=iso-8859-1
+iso-latin-1=iso-8859-1
+l1=iso-8859-1
+ibm819=iso-8859-1
+cp819=iso-8859-1
+iso-8859-1=
+ desc=Latin-1
+ stob=/dis/lib/convcs/cp_stob.dis arg=/lib/convcs/iso-8859-1.cp
+ btos=/dis/lib/convcs/cp_btos.dis arg=/lib/convcs/iso-8859-1.cp
+
+iso_8859-2:1987=iso-8859-2
+iso-ir-101=iso-8859-2
+iso_8859-2=iso-8859-2
+latin2=iso-8859-2
+l2=iso-8859-2
+iso-8859-2=
+ desc=Latin-2
+ stob=/dis/lib/convcs/cp_stob.dis arg=/lib/convcs/iso-8859-2.cp
+ btos=/dis/lib/convcs/cp_btos.dis arg=/lib/convcs/iso-8859-2.cp
+
+iso_8859-3:1988=iso-8859-3
+iso-ir-109=iso-8859-3
+iso_8859-3=iso-8859-3
+latin3=iso-8859-3
+l3=iso-8859-3
+iso-8859-3=
+ desc=Latin-3
+ stob=/dis/lib/convcs/cp_stob.dis arg=/lib/convcs/iso-8859-3.cp
+ btos=/dis/lib/convcs/cp_btos.dis arg=/lib/convcs/iso-8859-3.cp
+
+iso_8859-4:1988=iso-8859-4
+iso-ir-110=iso-8859-4
+iso_8859-4=iso-8859-4
+latin4=iso-8859-4
+l4=iso-8859-4
+iso-8859-4=
+ desc=Latin-4
+ stob=/dis/lib/convcs/cp_stob.dis arg=/lib/convcs/iso-8859-4.cp
+ btos=/dis/lib/convcs/cp_btos.dis arg=/lib/convcs/iso-8859-4.cp
+
+iso_8859-5:1988=iso-8859-5
+iso-ir-144=iso-8859-5
+iso_8859-5=iso-8859-5
+cyrillic=iso-8859-5
+iso-8859-5=
+ desc='Part 5 (Cyrillic)'
+ stob=/dis/lib/convcs/cp_stob.dis arg=/lib/convcs/iso-8859-5.cp
+ btos=/dis/lib/convcs/cp_btos.dis arg=/lib/convcs/iso-8859-5.cp
+
+iso_8859-6:1987=iso-8859-6
+iso-ir-127=iso-8859-6
+iso_8859-6=iso-8859-6
+ecma-114=iso-8859-6
+asmo-708=iso-8859-6
+arabic=iso-8859-6
+iso-8859-6=
+ desc='Part 6 (Arabic)'
+ stob=/dis/lib/convcs/cp_stob.dis arg=/lib/convcs/iso-8859-6.cp
+ btos=/dis/lib/convcs/cp_btos.dis arg=/lib/convcs/iso-8859-6.cp
+
+iso_8859-7:1987=iso-8859-7
+iso-ir-126=iso-8859-7
+iso_8859-7=iso-8859-7
+elot_928=iso-8859-7
+ecma-118=iso-8859-7
+greek=iso-8859-7
+greek8=iso-8859-7
+iso-8859-7=
+ desc='Part 7 (Greek)'
+ stob=/dis/lib/convcs/cp_stob.dis arg=/lib/convcs/iso-8859-7.cp
+ btos=/dis/lib/convcs/cp_btos.dis arg=/lib/convcs/iso-8859-7.cp
+
+iso_8859-8:1988=iso-8859-8
+iso-ir-138=iso-8859-8
+iso_8859-8=iso-8859-8
+hebrew=iso-8859-8
+iso-8859-8=
+ desc='Part 8 (Hebrew)'
+ stob=/dis/lib/convcs/cp_stob.dis arg=/lib/convcs/iso-8859-8.cp
+ btos=/dis/lib/convcs/cp_btos.dis arg=/lib/convcs/iso-8859-8.cp
+
+iso_8859-9:1989=iso-8859-9
+iso-ir-148=iso-8859-9
+iso_8859-9=iso-8859-9
+latin5=iso-8859-9
+l5=iso-8859-9
+iso-8859-9=
+ desc=Latin-5
+ stob=/dis/lib/convcs/cp_stob.dis arg=/lib/convcs/iso-8859-9.cp
+ btos=/dis/lib/convcs/cp_btos.dis arg=/lib/convcs/iso-8859-9.cp
+
+iso-ir-157=iso-8859-10
+l6=iso-8859-10
+iso_8859-10:1992=iso-8859-10
+latin6=iso-8859-10
+iso-8859-10=
+ # originally from dkuug.dk:i18n/charmaps/ISO_8859-10:1993
+ desc=Latin-6
+ stob=/dis/lib/convcs/cp_stob.dis arg=/lib/convcs/iso-8859-10.cp
+ btos=/dis/lib/convcs/cp_btos.dis arg=/lib/convcs/iso-8859-10.cp
+
+l9-iso-8859-15
+latin9=iso-8859-15
+iso-8859-15=
+ desc=Latin-9
+ stob=/dis/lib/convcs/cp_stob.dis arg=/lib/convcs/iso-8859-15.cp
+ btos=/dis/lib/convcs/cp_btos.dis arg=/lib/convcs/iso-8859-15.cp
+
+# Traditional Chinese
+big5=
+ desc='Big 5 (HKU)'
+ stob=/dis/lib/convcs/big5_stob.dis
+ btos=/dis/lib/convcs/big5_btos.dis
+
+# UTF-8
+ascii=utf-8
+us-ascii=utf-8
+utf8=utf-8 # commonly seen non IANA alias
+utf-8=
+ desc='Unicode UTF-8'
+ stob=/dis/lib/convcs/utf8_stob.dis
+ btos=/dis/lib/convcs/utf8_btos.dis
+
+utf16=utf-16
+utf-16=
+ desc='Unicode UTF-16'
+ btos=/dis/lib/convcs/utf16_btos.dis
+ stob=/dis/lib/convcs/utf16_stob.dis
+
+utf16le=utf-16le
+utf-16le=
+ desc='Unicode UTF-16 little endian'
+ btos=/dis/lib/convcs/utf16_btos.dis arg=le
+ stob=/dis/lib/convcs/utf16_stob.dis arg=le
+
+utf16be=utf-16be
+utf-16be=
+ desc='Unicode UTF-16 big endian'
+ btos=/dis/lib/convcs/utf16_btos.dis arg=be
+ stob=/dis/lib/convcs/utf16_stob.dis arg=be
+
+# UTF-7
+#utf-7=
+# desc='Unicode UTF-7'
+# stob=/dis/lib/convcs/utf7_stob.dis
+# btos=/dis/lib/convcs/utf7_btos.dis
+
+
+cp437=ibm437
+437=ibm437
+ibm437=
+ # originally from jhelling@cs.ruu.nl (Jeroen Hellingman)
+ desc='IBM PC: CP 437'
+ stob=/dis/lib/convcs/cp_stob.dis arg=/lib/convcs/ibm437.cp
+ btos=/dis/lib/convcs/cp_btos.dis arg=/lib/convcs/ibm437.cp
+
+cp850=ibm850
+850=ibm850
+ibm850=
+ # originally from jhelling@cs.ruu.nl (Jeroen Hellingman)
+ desc='IBM PS/2: CP 850'
+ stob=/dis/lib/convcs/cp_stob.dis arg=/lib/convcs/ibm850.cp
+ btos=/dis/lib/convcs/cp_btos.dis arg=/lib/convcs/ibm850.cp
+
+cp866=ibm866
+866=ibm866
+ibm866=
+ desc='Russian MS-DOS CP 866'
+ stob=/dis/lib/convcs/cp_stob.dis arg=/lib/convcs/ibm866.cp
+ btos=/dis/lib/convcs/cp_btos.dis arg=/lib/convcs/ibm866.cp
+
+windows-1250=
+ desc='MS Windows CP 1250 (Central Europe)'
+ stob=/dis/lib/convcs/cp_stob.dis arg=/lib/convcs/windows-1250.cp
+ btos=/dis/lib/convcs/cp_btos.dis arg=/lib/convcs/windows-1250.cp
+
+windows-1251=
+ desc='MS Windows CP 1251 (Cyrillic)'
+ stob=/dis/lib/convcs/cp_stob.dis arg=/lib/convcs/windows-1251.cp
+ btos=/dis/lib/convcs/cp_btos.dis arg=/lib/convcs/windows-1251.cp
+
+windows-1252=
+ desc='MS Windows CP 1252 (Latin 1)'
+ stob=/dis/lib/convcs/cp_stob.dis arg=/lib/convcs/windows-1252.cp
+ btos=/dis/lib/convcs/cp_btos.dis arg=/lib/convcs/windows-1252.cp
+
+koi8-r=
+ desc='KOI8-R (RFC1489)'
+ stob=/dis/lib/convcs/cp_stob.dis arg=/lib/convcs/koi8-r.cp
+ btos=/dis/lib/convcs/cp_btos.dis arg=/lib/convcs/koi8-r.cp
+
+gb_2312-80=gb2312
+iso-ir-58=gb2312
+chinese=gb2312
+gb2312=
+ desc="Chinese mixed one byte"
+ btos=/dis/lib/convcs/gb2312_btos.dis
+
+
+x-euc-jp=euc-jp # often seen non-IANA alias
+euc-jp=
+ desc="Japanese Extended UNIX Code"
+ btos=/dis/lib/convcs/euc-jp_btos.dis
+
+cp932=windows-31j
+windows-31j=
+ desc="MS-Windows Japanese (cp932)"
+ btos=/dis/lib/convcs/cp932_btos.dis arg=cp932
+
+ms_kanji=shift_jis
+x-sjis=shift_jis # often seen non-IANA alias
+shift_jis=
+ desc="Shift-JIS Japanese",
+ btos=/dis/lib/convcs/cp932_btos.dis arg=shiftjis
+
+# special converter for raw 8bit data that has been converted to utf-8
+8bit=
+ desc="raw 8-bit data"
+ stob=/dis/lib/convcs/8bit_stob.dis
--- /dev/null
+++ b/lib/convcs/cp932
@@ -1,0 +1,1 @@
+ 、。,.・:;?!゛゜´`¨^ ̄_ヽヾゝゞ〃仝々〆〇ー―‐/\~∥|…‥‘’“”()〔〕[]{}〈〉《》「」『』【】+-±×�÷=≠<>≦≧∞∴♂♀°′″℃¥$¢£%#&*@§☆★○●◎◇◆□■△▲▽▼※〒→←↑↓〓�����������∈∋⊆⊇⊂⊃∪∩��������∧∨¬⇒⇔∀∃�����������∠⊥⌒∂∇≡≒≪≫√∽∝∵∫∬�������ʼn♯♭♪†‡¶����◯���������������0123456789�������ABCDEFGHIJKLMNOPQRSTUVWXYZ�������abcdefghijklmnopqrstuvwxyz����ぁあぃいぅうぇえぉおかがきぎくぐけげこごさざしじすずせぜそぞただちぢっつづてでとどなにぬねのはばぱひびぴふぶぷへべぺほぼぽまみむめもゃやゅゆょよらりるれろゎわゐゑをん�����������ァアィイゥウェエォオカガキギクグケゲコゴサザシジスズセゼソゾタダチヂッツヅテデトドナニヌネノハバパヒビピフブプヘベペホボポマミ�ムメモャヤュユョヨラリルレロヮワヰヱヲンヴヵヶ��������ΑΒΓΔΕΖΗΘΙΚΛΜΝΞΟΠΡΣΤΥΦΧΨΩ��������αβγδεζηθικλμνξοπρστυφχψω��������������������������������������АБВГДЕЁЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЫЬЭЮЯ���������������абвгдеёжзийклмн�опрстуфхцчшщъыьэюя�������������─│┌┐┘└├┬┤┴┼━┃┏┓┛┗┣┳┫┻╋┠┯┨┷┿┝┰┥┸╂��������������������������������������������������������������①②③④⑤⑥⑦⑧⑨⑩⑪⑫⑬⑭⑮⑯⑰⑱⑲⑳ⅠⅡⅢⅣⅤⅥⅦⅧⅨⅩ�㍉㌔㌢㍍㌘㌧㌃㌶㍑㍗㌍㌦㌣㌫㍊㌻㎜㎝㎞㎎㎏㏄㎡��������㍻�〝〟№㏍℡㊤㊥㊦㊧㊨㈱㈲㈹㍾㍽㍼≒≡∫∮∑√⊥∠∟⊿∵∩∪�����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������亜唖娃阿哀愛挨姶逢葵茜穐悪握渥旭葦芦鯵梓圧斡扱宛姐虻飴絢綾鮎或粟袷安庵按暗案闇鞍杏以伊位依偉囲夷委威尉惟意慰易椅為畏異移維緯胃萎衣謂違遺医井亥域育郁磯一壱溢逸稲茨芋鰯允印咽員因姻引飲淫胤蔭院陰隠韻吋右宇烏羽迂雨卯鵜窺丑碓臼渦嘘唄欝蔚鰻姥厩浦瓜閏噂云運雲荏餌叡営嬰影映曳栄永泳洩瑛盈穎頴英衛詠鋭液疫益駅悦謁越閲榎厭円�園堰奄宴延怨掩援沿演炎焔煙燕猿縁艶苑薗遠鉛鴛塩於汚甥凹央奥往応押旺横欧殴王翁襖鴬鴎黄岡沖荻億屋憶臆桶牡乙俺卸恩温穏音下化仮何伽価佳加可嘉夏嫁家寡科暇果架歌河火珂禍禾稼箇花苛茄荷華菓蝦課嘩貨迦過霞蚊俄峨我牙画臥芽蛾賀雅餓駕介会解回塊壊廻快怪悔恢懐戒拐改魁晦械海灰界皆絵芥蟹開階貝凱劾外咳害崖慨概涯碍蓋街該鎧骸浬馨蛙垣柿蛎鈎劃嚇各廓拡撹格核殻獲確穫覚角赫較郭閣隔革学岳楽額顎掛笠樫�橿梶鰍潟割喝恰括活渇滑葛褐轄且鰹叶椛
\ No newline at end of file
--- /dev/null
+++ b/lib/convcs/gb2312
@@ -1,0 +1,1 @@
+����������������������������������������������������������������������������������������������������� 、。・ˉˇ¨〃々―〜∥…‘’“”〔〕〈〉《》「」『』〖〗【】±×÷∶∧∨∑∏∪∩∈∷√⊥∥∠⌒⊙∫∮≡≌≈∽∝≠≮≯≤≥∞∵∴♂♀°′″℃$¤¢£‰§№☆★○●◎◇◆□■△▲※→←↑↓〓����������������������⒈⒉⒊⒋⒌⒍⒎⒏⒐⒑⒒⒓⒔⒕⒖⒗⒘⒙⒚⒛⑴⑵⑶⑷⑸⑹⑺⑻⑼⑽⑾⑿⒀⒁⒂⒃⒄⒅⒆⒇①②③④⑤⑥⑦⑧⑨⑩��㈠㈡㈢㈣㈤㈥㈦㈧㈨㈩��ⅠⅡⅢⅣⅤⅥⅦⅧⅨⅩⅪⅫ��������!"#¥%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|} ̄������ぁあぃいぅうぇえぉおかがきぎくぐけげこごさざしじすずせぜそぞただちぢっつづてでとどなにぬねのはばぱひびぴふぶぷへべぺほぼぽまみむめもゃやゅゆょよらりるれろゎわゐゑをん�����������������ァアィイゥウェエォオカガキギクグケゲコゴサザシジスズセゼソゾタダチヂッツヅテデトドナニヌネノハバパヒビピフブプヘベペホボポマミムメモャヤュユョヨラリルレロヮワヰヱヲンヴヵヶ��������������ΑΒΓΔΕΖΗΘΙΚΛΜΝΞΟΠΡΣΤΥΦΧΨΩ��������αβγδεζηθικλμνξοπρστυφχψω��������������������������������������������АБВГДЕЁЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЫЬЭЮЯ���������������абвгдеёжзийклмнопрстуфхцчшщъыьэюя�������������������āáǎàēéěèīíǐìōóǒòūúǔùǖǘǚǜüê����������ㄅㄆㄇㄈㄉㄊㄋㄌㄍㄎㄏㄐㄑㄒㄓㄔㄕㄖㄗㄘㄙㄚㄛㄜㄝㄞㄟㄠㄡㄢㄣㄤㄥㄦㄧㄨㄩ������������������������������─━│┃┄┅┆┇┈┉┊┋┌┍┎┏┐┑┒┓└┕┖┗┘┙┚┛├┝┞┟┠┡┢┣┤┥┦┧┨┩┪┫┬┭┮┯┰┱┲┳┴┵┶┷┸┹┺┻┼┽┾┿╀╁╂╃╄╅╆╇╈╉╊╋��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������
\ No newline at end of file
binary files /dev/null b/lib/convcs/ibm437.cp differ
binary files /dev/null b/lib/convcs/ibm850.cp differ
binary files /dev/null b/lib/convcs/ibm866.cp differ
binary files /dev/null b/lib/convcs/iso-8859-1.cp differ
binary files /dev/null b/lib/convcs/iso-8859-10.cp differ
binary files /dev/null b/lib/convcs/iso-8859-15.cp differ
binary files /dev/null b/lib/convcs/iso-8859-2.cp differ
binary files /dev/null b/lib/convcs/iso-8859-3.cp differ
binary files /dev/null b/lib/convcs/iso-8859-4.cp differ
binary files /dev/null b/lib/convcs/iso-8859-5.cp differ
binary files /dev/null b/lib/convcs/iso-8859-6.cp differ
binary files /dev/null b/lib/convcs/iso-8859-7.cp differ
binary files /dev/null b/lib/convcs/iso-8859-8.cp differ
binary files /dev/null b/lib/convcs/iso-8859-9.cp differ
--- /dev/null
+++ b/lib/convcs/jisx0201kana
@@ -1,0 +1,1 @@
+。「」、・ヲァィゥェォャュョッーアイウエオカキクケコサシスセソタチツテトナニヌネノハヒフヘホマミムメモヤユヨラリルレロワン゙゚
\ No newline at end of file
--- /dev/null
+++ b/lib/convcs/jisx0208-1997
@@ -1,0 +1,1 @@
+ 、。,.・:;?!゛゜´`¨^ ̄_ヽヾゝゞ〃仝々〆〇ー―‐/\〜‖|…‥‘’“”()〔〕[]{}〈〉《》「」『』【】+−±×÷=≠<>≦≧∞∴♂♀°′″℃¥$¢£%#&*@§☆★○●◎◇◆□■△▲▽▼※〒→←↑↓〓�����������∈∋⊆⊇⊂⊃∪∩��������∧∨¬⇒⇔∀∃�����������∠⊥⌒∂∇≡≒≪≫√∽∝∵∫∬�������ʼn♯♭♪†‡¶����◯���������������0123456789�������ABCDEFGHIJKLMNOPQRSTUVWXYZ������abcdefghijklmnopqrstuvwxyz����ぁあぃいぅうぇえぉおかがきぎくぐけげこごさざしじすずせぜそぞただちぢっつづてでとどなにぬねのはばぱひびぴふぶぷへべぺほぼぽまみむめもゃやゅゆょよらりるれろゎわゐゑをん�����������ァアィイゥウェエォオカガキギクグケゲコゴサザシジスズセゼソゾタダチヂッツヅテデトドナニヌネノハバパヒビピフブプヘベペホボポマミムメモャヤュユョヨラリルレロヮワヰヱヲンヴヵヶ��������ΑΒΓΔΕΖΗΘΙΚΛΜΝΞΟΠΡΣΤΥΦΧΨΩ��������αβγδεζηθικλμνξοπρστυφχψω��������������������������������������АБВГДЕЁЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЫЬЭЮЯ���������������абвгдеёжзийклмнопрстуфхцчшщъыьэюя�������������─│┌┐┘└├┬┤┴┼━┃┏┓┛┗┣┳┫┻╋┠┯┨┷┿┝┰┥┸╂��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������
\ No newline at end of file
--- /dev/null
+++ b/lib/convcs/jisx0212
@@ -1,0 +1,1 @@
+������������������������������������������������������������������������������������������������������������˘ˇ¸˙˝¯˛˚~΄΅��������¡¦¿��������������������������������������ºª©®™¤№�����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ΆΈΉΊΪ�Ό�ΎΫ�Ώ����άέήίϊΐόςύϋΰώ�����������������������������������ЂЃЄЅІЇЈЉЊЋЌЎЏ�����������������������������������ђѓєѕіїјљњћќўџ����������������������������������������������������������������������������������������������ÆĐ�Ħ�IJ�ŁĿ�ŊØŒ�ŦÞ����������������æđðħıijĸłŀʼnŋøœßŧþ����������������������������������������������ÁÀÄÂĂǍĀĄÅÃĆĈČÇĊĎÉÈËÊĚĖĒĘ�ĜĞĢĠĤÍÌÏÎǏİĪĮĨĴĶĹĽĻŃŇŅÑÓÒÖÔǑŐŌÕŔŘŖŚŜŠŞŤŢÚÙÜÛŬǓŰŪŲŮŨǗǛǙǕŴÝŸŶŹŽŻ�������áàäâăǎāąåãćĉčçċďéèëêěėēęǵĝğ�ġĥíìïîǐ�īįĩĵķĺľļńňņñóòöôǒőōõŕřŗśŝšşťţúùüûŭǔűūųůũǘǜǚǖŵýÿŷźžż�����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������丂丄丅丌丒丟丣两丨丫丮丯丰丵乀乁乄乇乑乚乜乣乨乩乴乵乹乿亍亖亗亝亯亹仃仐仚仛仠仡仢仨
\ No newline at end of file
binary files /dev/null b/lib/convcs/koi8-r.cp differ
binary files /dev/null b/lib/convcs/windows-1250.cp differ
binary files /dev/null b/lib/convcs/windows-1251.cp differ
binary files /dev/null b/lib/convcs/windows-1252.cp differ
--- /dev/null
+++ b/lib/ebook/default.css
@@ -1,0 +1,116 @@
+body {
+ margin: 1em;
+ font-family: serif;
+ background: white;
+ color: black;
+}
+
+h1, h2, h3, h4, h5, h6, p, ul, ol, dir, menu, div,
+dt, dd, address, blockquote, pre, br, hr, form, dl {
+ display: block;
+}
+
+b, strong, i, em, cite, var, tt, code, kbd, samp,
+img, span {
+ display: inline;
+}
+
+li {
+ display: inline;
+}
+
+h1, h2, h3, h4 {
+ margin-top: 1em;
+ margin-bottom: 1em;
+}
+
+h5, h6 {
+ margin-top: 1em;
+}
+
+h1 {
+ text-align: center;
+}
+
+h1, h2, h4, h6 {
+ font-weight: bold;
+}
+
+h3, h5 {
+ font-style: italic;
+}
+
+h1 {
+ font-size: xx-large;
+}
+
+h2 {
+ font-size: x-large;
+}
+
+h3 {
+ font-size: large;
+}
+
+b, strong {
+ font-weight: bold
+}
+
+i, cite, em, var, address, blockquote {
+ font-style: italic
+}
+
+pre, tt, code, kbd, samp {
+ font-family: monospace
+}
+
+pre {
+ white-space: pre
+}
+
+address {
+ margin-left: 3em
+}
+
+blockquote {
+ margin-left: 2em;
+ margin-right: 2em
+}
+
+ul, dir {
+ list-style: disc
+}
+ol {
+ list-style: decimal
+}
+
+menu {
+ margin: 0
+}
+
+li {
+ margin-left: 1em
+}
+
+dt {
+ margin-bottom: 0
+}
+
+dd {
+ margin-top: 0;
+ margin-left: 1em
+}
+
+hr {
+ border-top: solid
+}
+
+a {
+ color: blue;
+ text-decoration: underline
+}
+
+p {
+ margin-top: 1em;
+ margin-bottom: 1em
+}
--- /dev/null
+++ b/lib/ebooks/devils/A.html
@@ -1,0 +1,586 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE html PUBLIC "+//ISBN 0-9673008-1-9//DTD OEB 1.0 Document//EN"
+ "http://openebook.org/dtds/oeb-1.0/oebdoc1.dtd">
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/x-oeb1-document; charset=utf-8" />
+<link rel="stylesheet" type="text/x-oeb1-css" href="devil.css" />
+<title>The Devil’s Dictionary: A</title>
+</head>
+
+<body lang="en-us">
+
+<h1>A</h1>
+
+<p class="entry"><span class="def">abasement,</span> <span class="pos">n.</span> A decent and customary
+mental attitude in the presence of wealth of power. Peculiarly appropriate in an employee when addressing
+an employer.</p>
+
+<p class="entry"><span class="def">abatis,</span> <span class="pos">n.</span> Rubbish in front of a fort,
+to prevent the rubbish outside from molesting the rubbish inside.</p>
+
+<p class="entry" id="abdication"><span class="def">abdication,</span> <span class="pos">n.</span> An act
+whereby a sovereign attests his sense of the high temperature of the throne.</p>
+
+<blockquote>
+<div class="stanza">
+<p class="po">Poor Isabella’s Dead, whose abdication</p>
+<p class="po">Set all tongues wagging in the Spanish nation.</p>
+<p class="po">For that performance ’twere unfair to scold her:</p>
+<p class="po">She wisely left a throne too hot to hold her.</p>
+<p class="po">To History she’ll be no royal riddle—</p>
+<p class="po">Merely a plain parched pea that jumped the griddle.</p>
+<p class="citepoet">G. J.</p>
+</div>
+</blockquote>
+
+<p class="entry"><span class="def">abdomen,</span> <span class="pos">n.</span> The temple of the god
+Stomach, in whose worship, with sacrificial rights, all true men engage. From women this ancient faith commands but a
+stammering assent. They sometimes minister at the altar in a half-hearted and ineffective way, but true reverence
+for the one deity that men really adore they know not. If woman had a free hand in the world’s
+marketing the race would become graminivorous.</p>
+
+<p class="entry"><span class="def">ability,</span> <span class="pos">n.</span> The natural equipment to accomplish
+some small part of the meaner ambitions distinguishing able men from dead ones. In the last analysis ability is commonly
+found to consist mainly in a high degree of solemnity. Perhaps, however, this impressive quality is
+rightly appraised; it is no easy task to be solemn.</p>
+
+<p class="entry"><span class="def">abnormal,</span> <span class="pos">adj.</span> Not conforming to
+standard. In matters of thought and conduct, to be independent is to be abnormal, to be abnormal is to
+be detested. Wherefore the lexicographer adviseth a striving toward the straiter resemblance of the
+Average Man than he hath to himself. Whoso attaineth thereto shall have peace, the prospect of death
+and the hope of Hell.</p>
+
+<p class="entry"><span class="def">aboriginies,</span> <span class="pos">n.</span> Persons of little worth found
+cumbering the soil of a newly discovered country. They soon cease to cumber; they fertilize.</p>
+
+<p class="entry" id="abracadabra"><span class="def">abracadabra.</span></p>
+
+<blockquote>
+<div class="stanza">
+<p class="poem">By <i>Abracadabra</i> we signify<br />
+<span class="ind1">An infinite number of things.</span><br />
+’Tis the answer to What? and How? and Why?<br />
+And Whence? and Whither?—a word whereby<br />
+<span class="ind1">The Truth (with the comfort it brings)</span><br />
+Is open to all who grope in night,<br />
+Crying for Wisdom’s holy light.</p>
+</div>
+
+<div class="stanza">
+<p class="poem">Whether the word is a verb or a noun<br />
+<span class="ind1">Is knowledge beyond my reach.</span><br />
+I only know that ’tis handed down.<br />
+<span class="ind3">From sage to sage,</span><br />
+<span class="ind3">From age to age—</span><br />
+<span class="ind1">An immortal part of speech!</span></p>
+</div>
+
+<div class="stanza">
+<p class="poem">Of an ancient man the tale is told<br />
+That he lived to be ten centuries old,<br />
+<span class="ind1">In a cave on a mountain side.</span><br />
+<span class="ind1">(True, he finally died.)</span><br />
+The fame of his wisdom filled the land,<br />
+For his head was bald, and you’ll understand<br />
+<span class="ind1">His beard was long and white</span><br />
+<span class="ind1">And his eyes uncommonly bright.</span></p>
+</div>
+
+<div class="stanza">
+<p class="poem">Philosophers gathered from far and near<br />
+To sit at his feat and hear and hear,<br />
+<span class="ind3">Though he never was heard</span><br />
+<span class="ind3">To utter a word</span><br />
+<span class="ind1">But “<i>Abracadabra</i>, abracadab,</span><br />
+<span class="ind3">Abracada, abracad,</span><br />
+<span class="ind1">Abraca, abrac, abra, ab!”</span><br />
+<span class="ind3">’Twas all he had,</span><br />
+’Twas all they wanted to hear, and each<br />
+Made copious notes of the mystical speech,<br />
+<span class="ind3">Which they published next—</span><br />
+<span class="ind3">A trickle of text</span><br />
+In the meadow of commentary.<br />
+<span class="ind1">Mighty big books were these,</span><br />
+<span class="ind1">In a number, as leaves of trees;</span><br />
+In learning, remarkably—very!</p>
+</div>
+
+<div class="stanza">
+<p class="poem"><span class="ind3">He’s dead,</span><br />
+<span class="ind3">As I said,</span><br />
+And the books of the sages have perished,<br />
+But his wisdom is sacredly cherished.<br />
+In <i>Abracadabra</i> it solemnly rings,<br />
+Like an ancient bell that forever swings.<br />
+<span class="poind3">O, I love to hear</span><br />
+<span class="poind3">That word make clear</span><br />
+Humanity’s General Sense of Things.</p>
+<p class="citepoet">Jamrach Holobom.</p>
+</div>
+</blockquote>
+
+<p class="entry"><span class="def">abridge,</span> <span class="pos">v.t.</span> To shorten.</p>
+
+<p class="quote">When in the course of human events it becomes necessary for people to abridge their
+king, a decent respect for the opinions of mankind requires that they should declare the
+causes which impel them to the separation.—<i>Oliver Cromwell</i></p>
+
+<p class="entry"><span class="def">abrupt,</span> <span class="pos">adj.</span> Sudden, without
+ceremony, like the arrival of a cannon-shot and the departure of the soldier whose interests are most
+affected by it. Dr. Samuel Johnson beautifully said of another author’s ideas that they were]
+“concatenated without abruption.”</p>
+
+<p class="entry" id="abscond"><span class="def">abscond,</span> <span class="pos">v.i.</span> To “move
+in a mysterious way,” commonly with the property of another.</p>
+
+<blockquote>
+<div class="stanza">
+<p class="poem">Spring beckons! All things to the call respond;<br />
+The trees are leaving and cashiers abscond.</p>
+<p class="citepoet">Phela Orm.</p>
+</div>
+</blockquote>
+
+<p class="entry" id="absent"><span class="def">absent,</span> <span class="pos">adj.</span> Peculiarly
+exposed to the tooth of detraction; vilifed; hopelessly in the wrong; superseded in the consideration
+and affection of another.</p>
+
+<blockquote>
+<div class="stanza">
+<p class="poem">To men a man is but a mind. Who cares<br />
+What face he carries or what form he wears?<br />
+But woman’s body is the woman. O,<br />
+Stay thou, my sweetheart, and do never go,<br />
+But heed the warning words the sage hath said:<br />
+A woman absent is a woman dead.<br />
+</p>
+<p class="citepoet">Jogo Tyree.</p>
+</div>
+</blockquote>
+
+<p class="entry"><span class="def">absentee,</span><span class="pos">n.</span> A person
+with an <a href="I.html#income">income</a> who has had the forethought to remove himself from the sphere of exaction.</p>
+
+<p class="entry"><span class="def">absolute,</span> <span class="pos">adj.</span> Independent, irresponsible.
+An absolute monarchy is one in which the sovereign does as he pleases so long as he pleases the assassins.
+Not many absolute monarchies are left, most of them having been replaced by limited monarchies, where the
+sovereign’s power for evil (and for good) is greatly curtailed, and by republics, which are
+governed by chance.</p>
+
+<p class="entry" id="abstainer"><span class="def">abstainer,</span> <span class="pos">n.</span> A weak
+person who yields to the temptation of denying himself a <a href="P.html#pleasure">pleasure</a>. A total abstainer is one who abstains
+from everything but abstention, and especially from inactivity in the affairs of others.</p>
+
+<blockquote>
+<div class="stanza">
+<p class="poem">Said a man to a crapulent youth: “I thought<br />
+<span class="ind1">You a total abstainer, my son.”</span><br />
+“So I am, so I am,” said the scrapgrace caught—<br />
+<span class="ind1">“But not, sir, a bigoted one.”</span></p>
+<p class="citepoet">G. J.</p>
+</div>
+</blockquote>
+
+<p class="entry"><span class="def">absurdity,</span> <span class="pos">n.</span> A statement or belief
+manifestly inconsistent with one’s own opinion.</p>
+
+<p class="entry"><span class="def">academe,</span> <span class="pos">n.</span> An ancient school where
+morality and philosophy were taught.</p>
+
+<p class="entry"><span class="def">academy,</span> <span class="pos">n.</span>
+(from academe). A modern school where football is taught.</p>
+
+<p class="entry"><span class="def">accident,</span> <span class="pos">n.</span> An inevitable
+occurrence due to the action of immutable natural laws.</p>
+
+<p class="entry"><span class="def">accomplice,</span> <span class="pos">n.</span> One associated
+with another in a crime, having guilty knowledge and complicity, as an <a href="L.html#lawyer">attorney</a> who defends a
+criminal, knowing him guilty. This view of the attorney’s position in the matter has not hitherto
+commanded the assent of attorneys, no one having offered them a fee for assenting.</p>
+
+<p class="entry"><span class="def">accord,</span> <span class="pos">n.</span> Harmony.</p>
+
+<p class="entry"><span class="def">accordion,</span> <span class="pos">n.</span> An instrument
+in harmony with the sentiments of an assassin.</p>
+
+<p class="entry" id="accountability"><span class="def">accountability,</span> <span class="pos">n.</span> The
+mother of caution.</p>
+
+<blockquote>
+<div class="stanza">
+<p class="poem">“My accountability, bear in mind,”<br />
+<span class="ind1">Said the Grand Vizier: “Yes, yes,”</span><br />
+Said the Shah: “I do—’tis the only kind<br />
+<span class="ind1">Of ability you possess.”</span></p>
+<p class="citepoet">Joram Tate.</p>
+</div>
+</blockquote>
+
+<p class="entry"><span class="def">accuse,</span> <span class="pos">v.t.</span> To affirm another’s guilt
+or unworth; most commonly as a justification of ourselves for having wronged him.</p>
+
+<p class="entry"><span class="def">acephalous,</span> <span class="pos">adj.</span> In the surprising condition of the
+Crusader who absently pulled at his forelock some hours after a Saracen scimitar had, unconsciously to him,
+passed through his neck, as related by de Joinville.</p>
+
+<p class="entry"><span class="def">achievement,</span> <span class="pos">n.</span> The death of endeavor
+and the birth of disgust.</p>
+
+<p class="entry"><span class="def">acknowledge,</span> <span class="pos">v.t.</span> To confess.
+Acknowledgement of one another’s faults is the highest duty imposed by our love of
+<a href="T.html#truth">truth</a>.</p>
+
+<p class="entry"><span class="def">acquaintance,</span> <span class="pos">n.</span> A person whom we
+know well enough to borrow from, but not well enough to lend to. A degree of friendship called slight when
+its object is poor or obscure, and intimate when he is <a href="R.html#rich">rich</a> or
+<a href="F.html#famous">famous.</a></p>
+
+<p class="entry"><span class="def">actually,</span> <span class="pos">adv.</span> Perhaps; possibly.</p>
+
+<p class="entry"><span class="def">adage,</span> <span class="pos">n.</span> Boned wisdom for weak teeth.</p>
+
+<p class="entry"><span class="def">adamant,</span> <span class="pos">n.</span> A mineral frequently found
+beneath a corset. Soluble in solicitate of gold.</p>
+
+<p class="entry"><span class="def">adder,</span> <span class="pos">n.</span> A species of snake. So called
+from its habit of adding <a href="F.html#funeral">funeral</a> outlays to the other expenses of living.</p>
+
+<p class="entry"><span class="def">adherent,</span> <span class="pos">n.</span> A follower who has not
+yet obtained all that he expects to get.</p>
+
+<p class="entry"><span class="def">administration,</span> <span class="pos">n.</span> An ingenious
+abstraction in <a href="P.html#politics">politics</a>, designed to receive the kicks and cuffs due to
+the premier or <a href="P.html#president">president</a>. A man of straw, proof against bad-egging
+and dead-catting.</p>
+
+<p class="entry"><span class="def">admiral,</span> <span class="pos">n.</span> That part of a war-ship
+which does the talking while the figure-head does the thinking.</p>
+
+<p class="entry"><span class="def">admiration,</span> <span class="pos">n.</span> Our polite recognition of
+another’s resemblance to ourselves.</p>
+
+<p class="entry" id="admonition"><span class="def">admonition,</span> <span class="pos">n.</span> Gentle
+reproof, as with a meat-axe. Friendly warning.</p>
+
+<blockquote>
+<div class="stanza">
+<p class="poem">Consigned by way of admonition,<br />
+His soul foever to perdition.</p>
+<p class="citepoet">Judibras.</p>
+</div>
+</blockquote>
+
+<p class="entry"><span class="def">adore,</span> <span class="pos">v.t.</span> To venerate expectantly.</p>
+
+<p class="entry" id="advice"><span class="def">advice,</span> <span class="pos">n.</span> The smallest
+current coin.</p>
+
+<blockquote>
+<div class="stanza">
+<p class="poem">“The man was in such deep distress,”<br />
+Said Tom, “that I could do no less<br />
+Than give him good advice.” Said Jim:<br />
+“If less could have been done for him<br />
+I know you well enough, my son,<br />
+To know that’s what you would have done.”</p>
+</div>
+</blockquote>
+
+<p class="entry"><span class="def">affianced,</span> <span class="pos">pp.</span> Fitted with an
+ankle-ring for the ball-and-chain.</p>
+
+<p class="entry"><span class="def">affliction,</span> <span class="pos">n.</span> An acclimatizing
+process preparing the <a href="S.html#soul">soul</a> for another and bitter world.</p>
+
+<p class="entry"><span class="def">African,</span> <span class="pos">n.</span> A nigger that votes our way.</p>
+
+<p class="entry"><span class="def">age,</span> <span class="pos">n.</span> That period of life in which
+we compound for the vices that we still cherish by reviling those that we have no longer the
+enterprise to commit.</p>
+
+<p class="entry"><span class="def">agitator,</span> <span class="pos">n.</span> A statesman who shakes
+the fruit trees of his neighbors—to dislodge the worms.</p>
+
+<p class="entry" id="aim"><span class="def">aim,</span> <span class="pos">n.</span> The task we set our wishes to.</p>
+
+<blockquote>
+<div class="stanza">
+<p class="poem">“Cheer up! Have you no aim in life?”<br />
+<span class="ind1">She tenderly inquired.</span><br />
+“An aim? Well, no, I haven’t, wife;<br />
+<span class="ind1">The fact is—I have fired.”</span></p>
+<p class="citepoet">G. J.</p>
+</div>
+</blockquote>
+
+<p class="entry"><span class="def">air,</span> <span class="pos">n.</span> A nutritious substance supplied by a
+bountiful Providence for the fattening of the poor.</p>
+
+<p class="entry"><span class="def">alderman,</span> <span class="pos">n.</span> An ingenious criminal
+who covers his secret thieving with a pretence of open marauding.</p>
+
+<p class="entry"><span class="def">alien,</span> <span class="pos">n.</span> An American sovereign
+in his probationary state.</p>
+
+<p class="entry" id="allah"><span class="def">Allah,</span> <span class="pos">n.</span> The Mahometan
+Supreme Being, as distinguished from the Christian, Jewish, and so forth.</p>
+
+<blockquote>
+<div class="stanza">
+<p class="poem">Allah’s good laws I faithfully have kept,<br />
+And ever for the sins of man have wept;<br />
+<span class="ind1">And sometimes kneeling in the temple I</span><br />
+Have reverently crossed my hands and slept.</p>
+<p class="citepoet">Junker Barlow.</p>
+</div>
+</blockquote>
+
+<p class="entry" id="allegiance"><span class="def">allegiance,</span> <span class="pos">n.</span> </p>
+
+<blockquote>
+<div class="stanza">
+<p class="poem">This thing Allegiance, as I suppose,<br />
+Is a ring fitted in the subject’s nose,<br />
+Whereby that organ is kept rightly pointed<br />
+To smell the sweetness of the Lord’s anointed.</p>
+<p class="citepoet">G. J.</p>
+</div>
+</blockquote>
+
+<p class="entry"><span class="def">alliance,</span> <span class="pos">n.</span> In international politics,
+the union of two thieves who have their hands so deeply inserted in each other’s pockets that
+they cannot separately plunder a third.</p>
+
+<p class="entry"><span class="def">alligator,</span> <span class="pos">n.</span> The crocodile of
+America, superior in every detail to the crocodile of the effete monarchies of the Old World.
+Herodotus says the Indus is, with one exception, the only river that produces crocodiles, but they
+appear to have gone West and grown up with the other rivers. From the notches on his back the
+alligator is called a sawrian.</p>
+
+<p class="entry" id="alone"><span class="def">alone,</span> <span class="pos">adj.</span> In bad company.</p>
+
+<blockquote>
+<div class="stanza">
+<p class="poem">In contact, lo! the flint and steel,<br />
+By spark and flame, the thought reveal<br />
+That he the metal, she the stone,<br />
+Had cherished secretly alone.</p>
+</div>
+</blockquote>
+
+<p class="entry" id="altar"><span class="def">altar,</span> <span class="pos">n.</span> The place whereupon
+the priest formerly raveled out the small intestine of the sacrificial victim for purposes of divination and
+cooked its flesh for the gods. The word is now seldom used, except with reference to the sacrifice of
+their liberty and peace by a male and a female tool.</p>
+
+<blockquote>
+<div class="stanza">
+<p class="poem">They stood before the altar and supplied<br />
+The fire themselves in which their fat was fried.<br />
+In vain the sacrifice!—no god will claim<br />
+An offering burnt with an unholy flame.</p>
+<p class="citepoet">M. P. Nopput.</p>
+</div>
+</blockquote>
+
+<p class="entry"><span class="def">ambidextrous,</span> <span class="pos">adj.</span> Able to pick
+with equal skill a right-hand pocket or a left.</p>
+
+<p class="entry"><span class="def">ambition,</span> <span class="pos">n.</span> An overmastering
+desire to be vilified by enemies while living and made ridiculous by friends when dead.</p>
+
+<p class="entry"><span class="def">amnesty,</span> <span class="pos">n.</span> The state’s
+magnanimity to those offenders whom it would be too expensive to punish.</p>
+
+<p class="entry" id="anoint"><span class="def">anoint,</span> <span class="pos">v.t.</span> To grease a
+<a href="K.html#king">king</a> or other great functionary already sufficiently slippery.</p>
+
+<blockquote>
+<div class="stanza">
+<p class="poem">As sovereigns are anointed by the priesthood,<br />
+So pigs to lead the populace are greased good.</p>
+<p class="citepoet">Judibras.</p>
+</div>
+</blockquote>
+
+<p class="entry"><span class="def">antipathy,</span> <span class="pos">n.</span> The sentiment
+inspired by one’s friend’s friend.</p>
+
+<p class="entry" id="aphorism"><span class="def">aphorism,</span> <span class="pos">n.</span> Predigested wisdom.</p>
+
+<blockquote>
+<div class="stanza">
+<p class="poem">The flabby wine-skin of his brain<br />
+Yields to some pathologic strain,<br />
+And voids from its unstored abysm<br />
+The driblet of an aphorism.</p>
+<p class="citepoet"> “The Mad Philosopher,”<span style="font-style: normal"> 1697.</span></p>
+</div>
+</blockquote>
+
+<p class="entry"><span class="def">apologize,</span> <span class="pos">v.i.</span> To lay the foundation for a future
+offence.</p>
+
+<p class="entry"><span class="def">apostate,</span> <span class="pos">n.</span> A leech who, having
+penetrated the shell of a turtle only to find that the creature has long been dead, deems it expedient
+to form a new attachment to a fresh turtle.</p>
+
+<p class="entry" id="apothecary"><span class="def">apothecary,</span> <span class="pos">n.</span> The
+physician’s accomplice, undertaker’s benefactor and grave worm’s provider.</p>
+
+<blockquote>
+<div class="stanza">
+<p class="poem">When Jove sent blessings to all men that are,<br />
+And Mercury conveyed them in a jar,<br />
+That friend of tricksters introduced by stealth<br />
+Disease for the apothecary’s health,<br />
+Whose gratitude impelled him to proclaim:<br />
+“My deadliest drug shall bear my patron’s name!”</p>
+<p class="citepoet">G. J.</p>
+</div>
+</blockquote>
+
+<p class="entry"><span class="def">appeal,</span> <span class="pos">v.t.</span> In <a href="L.html#law">law</a>,
+to put the dice into the box for another throw.</p>
+
+<p class="entry"><span class="def">appetite,</span> <span class="pos">n.</span> An instinct thoughtfully
+implanted by Providence as a solution to the labor question.</p>
+
+<p class="entry"><span class="def">applause,</span> <span class="pos">n.</span> The echo of
+a <a href="P.html#platitude">platitude</a>.</p>
+
+<p class="entry"><span class="def">April Fool,</span> <span class="pos">n.</span> The March
+<a href="F.html#fool">fool</a> with another month added to his folly.</p>
+
+<p class="entry" id="archbishop"><span class="def">archbishop,</span> <span class="pos">n.</span> An ecclesiastical
+dignitary one point holier than a bishop.</p>
+
+<blockquote>
+<div class="stanza">
+<p class="poem">If I were a jolly archbishop,<br />
+On Fridays I’d eat all the fish up—<br />
+Salmon and flounders and smelts;<br />
+On other days everything else.<br />
+</p>
+<p class="citepoet">Jodo Rem.</p>
+</div>
+</blockquote>
+
+<p class="entry"><span class="def">architect,</span> <span class="pos">n.</span> One who drafts a plan
+of your <a href="H.html#house">house</a>, and plans a draft of your money.</p>
+
+<p class="entry"><span class="def">ardor,</span> <span class="pos">n.</span> The quality that distinguishes
+love without knowledge.</p>
+
+<p class="entry"><span class="def">arena,</span> <span class="pos">n.</span> In politics, an imaginary rat-pit
+in which the statesman wrestles with his record.</p>
+
+<p class="entry"><span class="def">aristocracy,</span> <span class="pos">n.</span> Government by the
+best men. (In this sense the word is obsolete; so is that kind of government.) Fellows that wear downy hats
+and clean shirts—guilty of education and suspected of bank accounts.</p>
+
+<p class="entry"><span class="def">armor,</span> <span class="pos">n.</span> The kind of clothing worn
+by a man whose tailor is a blacksmith.</p>
+
+<p class="entry"><span class="def">arrayed,</span> <span class="pos">pp.</span> Drawn up and given an
+orderly disposition, as a rioter hanged to a lamppost.</p>
+
+<p class="entry"><span class="def">arrest,</span> <span class="pos">v.t.</span> Formally to detain one
+accused of unusualness.</p>
+
+<p class="quote">God made the world in six days and was arrested on the
+seventh.—<i>The Unauthorized Version</i></p>
+
+<p class="entry" id="arsenic"><span class="def">arsenic,</span> <span class="pos">n.</span> A kind of
+cosmetic greatly affected by the ladies, whom it greatly affects in turn.</p>
+
+<blockquote>
+<div class="stanza">
+<p class="poem">“Eat arsenic? Yes, all you get,”<br />
+<span class="ind1">Consenting, he did speak up;</span><br />
+“’Tis better you should eat it, pet,<br />
+<span class="ind1">Than put it in my teacup.”</span></p>
+<p class="citepoet">Joel Huck.</p>
+</div>
+</blockquote>
+
+<p class="entry" id="art"><span class="def">art,</span> <span class="pos">n.</span> This word has no
+definition. Its origin is related as follows by the ingenious Father Gassalasca Jape, S. J.</p>
+
+<blockquote>
+<div class="stanza">
+<p class="poem">One day a wag—what would the wretch be at?—<br />
+Shifted a letter of the cipher RAT,<br />
+And said it was a god’s name! Straight arose<br />
+Fantastic priests and postulants (with shows,<br />
+And mysteries, and mummeries, and hymns,<br />
+And disputations dire that lamed their limbs)<br />
+To serve his temple and maintain the fires,<br />
+Expound the law, manipulate the wires.<br />
+Amazed, the populace that rites attend,<br />
+Believe whate’er they cannot comprehend,<br />
+And, inly edified to learn that two<br />
+Half-hairs joined so and so (as Art can do)<br />
+Have sweeter values and a grace more fit<br />
+Than Nature’s hairs that never have been split,<br />
+Bring cates and wines for sacrificial feasts,<br />
+And sell their garments to support the priests.</p>
+</div>
+</blockquote>
+
+<p class="entry"><span class="def">artlessness,</span> <span class="pos">n.</span> A certain engaging
+quality to which women attain by long study and severe practice upon the admiring <a href="M.html#male">male</a>,
+who is pleased to fancy it resembles the candid simplicity of his young.</p>
+
+<p class="entry"><span class="def">asperse,</span> <span class="pos">v.t.</span> Maliciously to ascribe
+to another vicious actions which one has not had the temptation and opportunity to commit.</p>
+
+<p class="entry" id="ass"><span class="def">ass,</span> <span class="pos">n.</span> A public singer with
+a good voice but no ear. In Virginia City, Nevada, he is called the Washoe Canary, in Dakota, the Senator,
+and everywhere the Donkey. The animal is widely and variously celebrated in the literature, <a href="#art">art</a>
+and <a href="R.html#religion">religion</a> of every age and country; no other so engages and fires the human
+imagination as this noble vertebrate. Indeed, it is doubted by some (Ramasilus, <span xml:lang="la"><i>lib. II.,
+De Clem.</i></span>, and C. Stantatus, <span xml:lang="la"><i>De Temperamente</i></span>)
+if it is not a god; and as such we know it was worshiped by the Etruscans, and, if we may believe Macrobious,
+by the Cupasians also. Of the only two animals admitted into the Mahometan Paradise along with the souls of
+men, the ass that carried Balaam is one, the <a href="D.html#dog">dog</a> of the Seven Sleepers the other.
+This is no small distinction. From what has been written about this beast might be compiled a library of great
+splendor and magnitude, rivalling that of the Shakespearean cult, and that which clusters about the Bible. It
+may be said, generally, that all literature is more or less Asinine.</p>
+
+<blockquote>
+<div class="stanza">
+<p class="poem">“Hail, holy Ass!”the quiring angels sing;<br />
+“Priest of Unreason, and of Discords King!”<br />
+Great co-Creator, let Thy glory shine:<br />
+God made all else, the Mule, the Mule is thine!”</p>
+<p class="citepoet">G. J.</p>
+</div>
+</blockquote>
+
+<p class="entry"><span class="def">auctioneer,</span> <span class="pos">n.</span> The man who proclaims
+with a hammer that he has picked a pocket with his tongue.</p>
+
+<p class="entry"><span class="def">Australia,</span> <span class="pos">n.</span> A country lying in the
+South Sea, whose industrial and commercial development has been unspeakably retarded by an unfortunate
+dispute among geographers as to whether it is a continent or an island.</p>
+
+<p class="entry"><span class="def">avernus,</span> <span class="pos">n.</span> The lake by which the
+ancients entered the infernal regions. The fact that access to the infernal regions was obtained by a lake
+is believed by the learned Marcus Ansello Scrutator to have suggested the <a href="C.html#christian">Christian</a>
+rite of <a href="B.html#baptism">baptism</a> by immersion. This, however, has been shown by Lactantius to be
+an error.</p>
+
+<blockquote>
+<div class="stanza">
+<p class="poem" xml:lang="la"><i>Facilis descensus Averni,</i><br />
+<span class="ind1">The poet remarks; and the sense</span><br />
+Of it is that when down-hill I turn I<br />
+<span class="ind1">Will get more of punches than pence.</span></p>
+<p class="citepoet">Jehal Dai Lupe.</p>
+</div>
+</blockquote>
+
+</body>
+</html>
\ No newline at end of file
--- /dev/null
+++ b/lib/ebooks/devils/A.html.i
@@ -1,0 +1,53 @@
+15 pages
+size 400 552
+length 28806
+400 2 11 body html
+0
+1984 2 43 body html
+73
+3135 2 59 body html
+331
+3135 2 59 body html
+874
+7242 2 149 body html
+142
+9706 2 197 body html
+0
+11725 2 234 body html
+56
+14044 2 279 body html
+43
+16224 2 326 body html
+22
+17952 2 363 body html
+43
+19588 2 399 body html
+90
+21737 2 450 body html
+0
+23824 2 495 body html
+0
+25445 2 532 body html
+56
+27720 2 565 body html
+22
+abracadabra 1
+arsenic 11
+anoint 9
+allah 7
+aphorism 10
+absent 3
+aim 7
+abstainer 4
+abscond 3
+art 12
+ass 13
+advice 6
+apothecary 10
+altar 9
+admonition 6
+alone 8
+archbishop 11
+abdication 0
+accountability 5
+allegiance 8
--- /dev/null
+++ b/lib/ebooks/devils/B.html
@@ -1,0 +1,398 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE html PUBLIC "+//ISBN 0-9673008-1-9//DTD OEB 1.0 Document//EN"
+ "http://openebook.org/dtds/oeb-1.0/oebdoc1.dtd">
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/x-oeb1-document; charset=utf-8" />
+<link rel="stylesheet" type="text/x-oeb1-css" href="devil.css" />
+<title>The Devil’s Dictionary: B</title>
+</head>
+
+<body lang="en-US">
+
+<h1>B</h1>
+
+<p class="entry"><span class="def">Baal,</span> <span class="pos">n.</span> An old deity formerly
+much worshiped under various names.
+As Baal he was popular with the Phoenicians; as Belus or Bel he had the honor to
+be served by the priest Berosus, who wrote the famous account of the Deluge;
+as Babel he had a tower partly erected to his glory on the Plain of Shinar. From Babel comes our English word
+“babble.” Under whatever name worshiped,
+Baal is the Sun-god. As Beelzebub he is the god of flies, which are begotten
+of the sun’s rays on the stagnant water. In Physicia Baal is still
+worshiped as Bolus, and as Belly he is adored and served with abundant
+sacrifice by the priests of Guttledom.</p>
+
+<p class="entry"><span class="def">babe</span> or <span class="def">baby,</span> <span class="pos">n.</span> A
+misshapen creature of no particular age, sex, or
+condition, chiefly remarkable for the violence of the sympathies and
+antipathies it excites in others, itself without sentiment or emotion. There
+have been famous babes; for example, little Moses, from whose adventure in the
+bulrushes the Egyptian hierophants of seven centuries before doubtless derived
+their idle tale of the child Osiris being preserved on a floating lotus leaf.</p>
+
+<blockquote class="poem">
+<div class="stanza">
+<p class="poind3">Ere babes were invented</p>
+<p class="poind3">The girls were contended.</p>
+<p class="poind3">Now man is tormented</p>
+<p class="po">Until to buy babes he has squandered</p>
+<p class="po">His money. And so I have pondered</p>
+<p class="poind3">This thing, and thought may be</p>
+<p class="poind3">’T were better that Baby</p>
+<p class="po">The First had been eagled or condored.</p>
+<p class="citeauth">Ro Amil.</p>
+</div>
+</blockquote>
+
+<p class="entry"><span class="def">Bacchus,</span> <span class="pos">n.</span> A convenient
+deity invented by the ancients as an excuse for getting drunk.</p>
+
+<blockquote class="poem">
+<div class="stanza">
+<p class="po">Is public worship, then, a sin,</p>
+<p class="poind2">That for devotions paid to Bacchus</p>
+<p class="po">The lictors dare to run us in,</p>
+<p class="poind2">And resolutely thump and whack us?</p>
+<p class="citeauth">Jorace.</p>
+</div>
+</blockquote>
+
+<p class="entry"><span class="def">back,</span> <span class="pos">n.</span> That part of your
+friend which it is your privilege to contemplate in your adversity.</p>
+
+<p class="entry"><span class="def">backbite,</span> <span class="pos">v.t.</span> To speak of a man as
+you find him when he can’t find you.</p>
+
+<p class="entry"><span class="def">bait,</span> <span class="pos">n.</span> A preparation
+that renders the hook more palatable. The best kind is beauty.</p>
+
+<p id="baptism" class="entry"><span class="def">baptism,</span> <span class="pos">n.</span> A sacred rite of
+such efficacy that he who finds himself in heaven without having undergone it will be unhappy forever.
+It is performed with water in two ways by immersion, or plunging, and by aspersion, or sprinkling.</p>
+
+<blockquote class="poem">
+<div class="stanza">
+<p class="po">But whether the plan of immersion</p>
+<p class="po">Is better than simple aspersion</p>
+<p class="poind1">Let those immersed</p>
+<p class="poind1">And those aspersed</p>
+<p class="po">Decide by the Authorized Version,</p>
+<p class="po">And by matching their agues tertian.</p>
+<p class="citeauth">G. J.</p>
+</div>
+</blockquote>
+
+<p class="entry"><span class="def">barometer,</span> <span class="pos">n.</span> An ingenious
+instrument which indicates what kind of weather we are having.</p>
+
+<p class="entry"><span class="def">barrack,</span> <span class="pos">n.</span> A house in which
+soldiers enjoy a portion of that of which it is their business to deprive others.</p>
+
+<p class="entry"><span class="def">basilisk,</span> <span class="pos">n.</span> The cockatrice.
+A sort of serpent hatched form the egg of a cock. The basilisk had a bad eye, and its glance was
+fatal. Many infidels deny this creature’s existence, but Semprello Aurator saw and handled one
+that had been blinded by lightning as a punishment for having fatally gazed on
+a lady of rank whom Jupiter loved. Juno afterward restored the reptile’s
+sight and hid it in a cave. Nothing is so well attested by the ancients as
+the existence of the basilisk, but the cocks have stopped laying.</p>
+
+<p class="entry"><span class="def">bastinado,</span> <span class="pos">n.</span> The act of walking
+on wood without exertion.</p>
+
+<p class="entry"><span class="def">bath,</span> <span class="pos">n.</span> A kind of mystic ceremony
+substituted for religious worship, with what spiritual efficacy has not been determined.</p>
+
+<blockquote class="poem">
+<div class="stanza">
+<p class="po">The man who taketh a steam bath</p>
+<p class="po">He loseth all the skin he hath,</p>
+<p class="po">And, for he’s boiled a brilliant red,</p>
+<p class="po">Thinketh to cleanliness he’s wed,</p>
+<p class="po">Forgetting that his lungs he’s soiling</p>
+<p class="po">With dirty vapors of the boiling.</p>
+<p class="citeauth">Richard Gwow.</p>
+</div>
+</blockquote>
+
+<p class="entry"><span class="def">battle,</span> <span class="pos">n.</span> A method of untying
+with the teeth of a political knot that would not yield to the tongue.</p>
+
+<p class="entry"><span class="def">beard,</span> <span class="pos">n.</span> The hair that is commonly
+cut off by those who justly execrate the absurd Chinese custom of shaving the head.</p>
+
+<p class="entry"><span class="def">beauty,</span> <span class="pos">n.</span> The power by which a woman
+charms a lover and terrifies a husband.</p>
+
+<p class="entry"><span class="def">befriend,</span> <span class="pos">v.t.</span> To make an ingrate.</p>
+
+<p class="entry" id="beg"><span class="def">beg,</span> <span class="pos">v.</span> To ask for something with
+an earnestness proportioned to the belief that it will not be given.</p>
+
+<blockquote class="poem">
+<div class="stanza">
+<p class="po">Who is that, father?</p>
+</div>
+
+<div class="stanza">
+<p class="po" style="text-align: right">A mendicant, child,</p>
+<p class="po">Haggard, morose, and unaffable—wild!</p>
+<p class="po">See how he glares through the bars of his cell!</p>
+<p class="po">With Citizen Mendicant all is not well.</p>
+</div>
+
+<div class="stanza">
+<p class="po">Why did they put him there, father?</p>
+</div>
+
+<div class="stanza">
+<p class="po" style="text-align: right">Because</p>
+<p class="po">Obeying his belly he struck at the laws.</p>
+</div>
+
+<div class="stanza">
+<p class="po">His belly?</p>
+</div>
+
+<div class="stanza">
+<p class="po" style="text-align: right">Oh, well, he was starving, my boy—</p>
+<p class="po">A state in which, doubtless, there’s little of joy.</p>
+<p class="po">No bite had he eaten for days, and his cry</p>
+<p class="po">Was “Bread!” ever “Bread!”</p>
+</div>
+
+<div class="stanza">
+<p class="po" style="text-align: right">What’s the matter with pie?</p>
+</div>
+
+<div class="stanza">
+<p class="po">With little to wear, he had nothing to sell;</p>
+<p class="po">To beg was unlawful—improper as well.</p>
+</div>
+
+<div class="stanza">
+<p class="po">Why didn’t he work?</p>
+</div>
+
+<div class="stanza">
+<p class="po" style="text-align: right">He would even have done that,</p>
+<p class="po">But men said: “Get out!” and the State remarked:</p>
+<p class="po">“Scat!”</p>
+<p class="po">I mention these incidents merely to show</p>
+<p class="po">That the vengeance he took was uncommonly low.</p>
+<p class="po">Revenge, at the best, is the act of a Siou,</p>
+<p class="po">But for trifles—</p>
+</div>
+
+<div class="stanza">
+<p class="po" style="text-align: right">Pray what did bad Mendicant do?</p>
+</div>
+
+<div class="stanza">
+<p class="po">Stole two loaves of bread to replenish his lack</p>
+<p class="po">And tuck out the belly that clung to his back.</p>
+</div>
+
+<div class="stanza">
+<p class="po">Is that <i>all</i> father dear?</p>
+</div>
+
+<div class="stanza">
+<p class="po" style="text-align: right">There’s little to tell:</p>
+<p class="po">They sent him to jail, and they’ll send him to—well,</p>
+<p class="po">The company’s better than here we can boast,</p>
+<p class="po">And there’s—</p>
+</div>
+
+<div class="stanza">
+<p class="po" style="text-align: center">Bread for the needy, dear father?</p>
+</div>
+
+<div class="stanza">
+<p class="po" style="text-align: right">Um—toast.</p>
+<p class="citeauth">Atka Mip.</p>
+</div>
+</blockquote>
+
+<p class="entry"><span class="def">beggar,</span> <span class="pos">n.</span> One who has relied
+on the assistance of his friends.</p>
+
+<p class="entry"><span class="def">behavior,</span> <span class="pos">n.</span> Conduct, as determined,
+not by principle, but by breeding. The word seems to be somewhat loosely used in Dr. Jamrach Holobom’s
+translation of the following lines from the <i>Dies Iræ</i>:</p>
+
+<blockquote class="poem">
+<div class="stanza">
+<div xml:lang="la">
+<p class="poind2">Recordare, Jesu pie,</p>
+<p class="poind2">Quod sum causa tuae viæ.</p>
+<p class="poind2">Ne me perdas illa die.</p></div>
+</div>
+
+<div class="stanza">
+<p class="po">Pray remember, sacred Savior,</p>
+<p class="po">Whose the thoughtless hand that gave your</p>
+<p class="po">Death-blow. Pardon such behavior.</p>
+</div>
+</blockquote>
+
+<p class="entry"><span class="def">Belladonna,</span> <span class="pos">n.</span> In Italian a beautiful
+lady; in English a deadly poison. A striking example of the essential identity of the two tongues.</p>
+
+<p class="entry"><span class="def">Benedictines,</span> <span class="pos">n.</span> An order of monks
+otherwise known as black friars.</p>
+
+<blockquote class="poem">
+<div class="stanza">
+<p class="po">She thought it a crow, but it turn out to be</p>
+<p class="poind1">A monk of St. Benedict croaking a text.</p>
+<p class="po">“Here’s one of an order of cooks,” said she—</p>
+<p class="poind1">“Black friars in this world, fried black in the next.”</p>
+<p class="citeauth">“The Devil on Earth” <span style="font-style: normal">(<i>London</i>, 1712.)</span></p>
+</div>
+</blockquote>
+
+<p class="entry"><span class="def">benefactor,</span> <span class="pos">n.</span> One who makes
+heavy purchases of ingratitude, without, however, materially affecting the price, which is still within
+the means of all.</p>
+
+<p class="entry"><span class="def">Berenice’s Hair,</span> <span class="pos">n.</span> A constellation
+(<span xml:lang="la"><i>Coma Berenices</i></span>) named in honor of one who sacrificed her hair to
+save her husband.</p>
+
+<blockquote class="poem">
+<div class="stanza">
+<p class="po">Her locks an ancient lady gave</p>
+<p class="po">Her loving husband’s life to save;</p>
+<p class="po">And men—they honored so the dame—</p>
+<p class="po">Upon some stars bestowed her name.</p>
+</div>
+
+<div class="stanza">
+<p class="po">But to our modern married fair,</p>
+<p class="po">Who’d give their lords to save their hair,</p>
+<p class="po">No stellar recognition’s given.</p>
+<p class="po">There are not stars enough in heaven.</p>
+<p class="citeauth">G. J.</p>
+</div>
+</blockquote>
+
+<p class="entry"><span class="def">bigamy,</span> <span class="pos">n.</span> A mistake in taste
+for which the wisdom of the future will adjudge a punishment called trigamy.</p>
+
+<p class="entry"><span class="def">bigot,</span> <span class="pos">n.</span> One who is obstinately
+and zealously attached to an opinion that you do not entertain.</p>
+
+<p class="entry"><span class="def">billingsgate,</span> <span class="pos">n.</span> The invective of
+an opponent.</p>
+
+<p class="entry"><span class="def">birth,</span> <span class="pos">n.</span> The first and direst of
+all disasters. As to the nature of it there appears to be no uniformity. Castor and Pollux were born
+from the egg. Pallas came out of a skull. Galatea was once a block of stone. Peresilis, who wrote in
+the tenth century, avers that he grew up out of the ground where a priest had spilled holy water. It
+is known that Arimaxus was derived from a hole in the earth, made by a stroke of lightning. Leucomedon
+was the son of a cavern in Mount Ætna, and I have myself seen a man come out of a wine cellar.</p>
+
+<p class="entry"><span class="def">blackguard,</span> <span class="pos">n.</span> A man whose qualities,
+prepared for display like a box of berries in a market—the fine ones on top—have been opened on the wrong
+side. An inverted gentleman.</p>
+
+<p class="entry"><span class="def">blank-verse,</span> <span class="pos">n.</span> Unrhymed iambic
+pentameters—the most difficult kind of English verse to write acceptably; a kind, therefore, much affected
+by those who cannot acceptably write any kind.</p>
+
+<p class="entry"><span class="def">body-snatcher,</span> <span class="pos">n.</span> A robber of grave-worms.
+One who supplies the young physicians with that with which the old physicians have supplied the undertaker.
+The hyena.</p>
+
+<blockquote class="poem">
+<div class="stanza">
+<p class="po">“One night,” a doctor said, “last fall,</p>
+<p class="po">I and my comrades, four in all,</p>
+<p class="poind1">When visiting a graveyard stood</p>
+<p class="po">Within the shadow of a wall.</p>
+</div>
+
+<div class="stanza">
+<p class="po">“While waiting for the moon to sink</p>
+<p class="po">We saw a wild hyena slink</p>
+<p class="poind1">About a new-made grave, and then</p>
+<p class="po">Begin to excavate its brink!</p>
+</div>
+
+<div class="stanza">
+<p class="po">“Shocked by the horrid act, we made</p>
+<p class="po">A sally from our ambuscade,</p>
+<p class="poind1">And, falling on the unholy beast,</p>
+<p class="po">Dispatched him with a pick and spade.”</p>
+<p class="citeauth">Bettel K. Jhones.</p>
+</div>
+</blockquote>
+
+<p class="entry"><span class="def">bondsman,</span> <span class="pos">n.</span> A fool who, having
+property of his own, undertakes to become responsible for that entrusted to another to a third.</p>
+
+<p class="indentpara">Philippe of Orleans wishing to appoint one of his favorites, a dissolute
+nobleman, to a high office, asked him what security he would be able to give. “I need no
+bondsmen,” he replied, “for I can give you my word of honor.” “And
+pray what may be the value of that?” inquired the amused Regent. “Monsieur, it
+is worth its weight in gold.”</p>
+
+<p class="entry"><span class="def">bore,</span> <span class="pos">n.</span> A person who talks
+when you wish him to listen.</p>
+
+<p class="entry"><span class="def">botany,</span> <span class="pos">n.</span> The science of
+vegetables—those that are not good to eat, as well as those that are. It deals largely with
+their flowers, which are commonly badly designed, inartistic in color, and ill-smelling.</p>
+
+<p class="entry"><span class="def">bottle-nosed,</span> <span class="pos">adj.</span> Having a
+nose created in the image of its maker.</p>
+
+<p class="entry"><span class="def">boundary,</span> <span class="pos">n.</span> In political
+geography, an imaginary line between two nations, separating the imaginary rights of one from
+the imaginary rights of the other.</p>
+
+<p class="entry"><span class="def">bounty,</span> <span class="pos">n.</span> The liberality
+of one who has much, in permitting one who has nothing to get all that he can.</p>
+
+<p class="quote">A single swallow, it is said, devours ten millions of insects every year. The
+supplying of these insects I take to be a signal instance of the Creator’s bounty in providing
+for the lives of His creatures.—<i>Henry Ward Beecher</i></p>
+
+<p class="entry"><span class="def">brahma,</span> <span class="pos">n.</span> He who created
+the Hindoos, who are preserved by Vishnu and destroyed by Siva—a rather neater division of labor
+than is found among the deities of some other nations. The Abracadabranese, for example, are created
+by Sin, maintained by Theft and destroyed by Folly. The priests of Brahma, like those of Abracadabranese,
+are holy and learned men who are never naughty.</p>
+
+<blockquote class="poem">
+<div class="stanza">
+<p class="po">O Brahma, thou rare old Divinity,</p>
+<p class="po">First Person of the Hindoo Trinity,</p>
+<p class="po">You sit there so calm and securely,</p>
+<p class="po">With feet folded up so demurely—</p>
+<p class="po">You’re the First Person Singular, surely.</p>
+<p class="citeauth">Polydore Smith.</p>
+</div>
+</blockquote>
+
+<p class="entry"><span class="def">brain,</span> <span class="pos">n.</span> An apparatus with which
+we think what we think. That which distinguishes the man who is content to <i>be</i> something from
+the man who wishes to <i>do</i> something. A man of great wealth, or one who has been pitchforked
+into high station, has commonly such a headful of brain that his neighbors cannot keep their hats on.
+In our civilization, and under our republican form of government, brain is so highly honored that it is
+rewarded by exemption from the cares of office.</p>
+
+<p class="entry"><span class="def">brandy,</span> <span class="pos">n.</span> A cordial composed of
+one part thunder-and-lightning, one part remorse, two parts bloody murder, one part death-hell-and-the-grave
+and four parts clarified Satan. Dose, a headful all the time. Brandy is said by Dr. Johnson to be the drink of
+heroes. Only a hero will venture to drink it.</p>
+
+<p class="entry"><span class="def">bride,</span> <span class="pos">n.</span> A woman with a fine prospect
+of happiness behind her.</p>
+
+<p class="entry"><span class="def">brute,</span> <span class="pos">n.</span> See
+<a href="H.html#husband"><span class="def">husband</span></a>.</p>
+
+</body>
+</html>
\ No newline at end of file
--- /dev/null
+++ b/lib/ebooks/devils/B.html.i
@@ -1,0 +1,23 @@
+9 pages
+size 400 552
+length 18309
+400 2 11 body html
+0
+1681 2 34 body html
+117
+4008 2 89 body html
+0
+6365 2 132 body html
+0
+6365 2 132 body html
+547
+10201 2 245 body html
+13
+12195 2 289 body html
+90
+14590 2 335 body html
+0
+16688 2 368 body html
+13
+baptism 1
+beg 2
--- /dev/null
+++ b/lib/ebooks/devils/C.html
@@ -1,0 +1,528 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE html PUBLIC "+//ISBN 0-9673008-1-9//DTD OEB 1.0 Document//EN"
+ "http://openebook.org/dtds/oeb-1.0/oebdoc1.dtd">
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/x-oeb1-document; charset=utf-8" />
+<link rel="stylesheet" type="text/x-oeb1-css" href="devil.css" />
+<title>The Devil’s Dictionary: C</title>
+</head>
+
+<body lang="en-us">
+
+<h1>C</h1>
+
+<p class="entry"><span class="def">Caaba,</span> <span class="pos">n.</span> A large stone
+presented by the archangel Gabriel to the patriarch Abraham, and preserved at Mecca. The
+patriarch had perhaps asked the archangel for bread.</p>
+
+<p class="entry"><span class="def">cabbage,</span> <span class="pos">n.</span> A familiar
+kitchen-garden vegetable about as large and wise as a man’s head.</p>
+
+<p class="indentpara">The cabbage is so called from Cabagius, a prince who on ascending
+the throne issued a decree appointing a High Council of Empire consisting of the members of his
+predecessor’s Ministry and the cabbages in the royal garden. When any of his Majesty’s measures
+of state policy miscarried conspicuously it was gravely announced that several members
+of the High Council had been beheaded, and his murmuring subjects were appeased.</p>
+
+<p class="entry"><span class="def">calamity,</span> <span class="pos">n.</span> A more than commonly
+plain and unmistakable reminder that the affairs of this life are not of our own ordering. Calamities are
+of two kinds: misfortune to ourselves, and good fortune to others.</p>
+
+<p class="entry"><span class="def">callous,</span> <span class="pos">adj.</span> Gifted with great
+fortitude to bear the evils afflicting another.</p>
+
+<p class="indentpara">When Zeno was told that one of his enemies was no more he was observed to
+be deeply moved. “What!” said one of his disciples, “you weep at the death of an
+enemy?” “Ah, ’tis true,”
+replied the great Stoic; “but you should see me smile at the death of a friend.”</p>
+
+<p class="entry"><span class="def">calumnus,</span> <span class="pos">n.</span> A graduate of the School
+for Scandal.</p>
+
+<p class="entry"><span class="def">camel,</span> <span class="pos">n.</span> A quadruped (the <i>Splaypes
+humpidorsus</i>) of great value to the show business. There are two kinds of camels—the camel proper and
+the camel improper. It is the latter that is always exhibited.</p>
+
+<p class="entry"><span class="def">cannibal,</span> <span class="pos">n.</span> A gastronome of the old
+school who preserves the simple tastes and adheres to the natural diet of the pre-pork period.</p>
+
+<p class="entry"><span class="def">cannon,</span> <span class="pos">n.</span> An instrument employed
+in the rectification of national boundaries.</p>
+
+<p class="entry"><span class="def">canonicals,</span> <span class="pos">n.</span> The motley worm by
+Jesters of the Court of Heaven.</p>
+
+<p class="entry"><span class="def">capital,</span> <span class="pos">n.</span> The seat of misgovernment.
+That which provides the fire, the pot, the dinner, the table and the knife and fork for the anarchist; the
+part of the repast that himself supplies is the disgrace before meat. <i>Capital Punishment</i>, a penalty
+regarding the justice and expediency of which many worthy persons—including all the assassins—entertain
+grave misgivings.</p>
+
+<p class="entry" id="carmelite"><span class="def">carmelite,</span> <span class="pos">n.</span> A mendicant friar of
+the order of Mount Carmel.</p>
+
+<table class="poem">
+<tr><td class="poem">
+<p class="po">As Death was a-rising out one day,</p>
+<p class="po">Across Mount Camel he took his way,</p>
+<p class="poind1">Where he met a mendicant monk,</p>
+<p class="poind1">Some three or four quarters drunk,</p>
+<p class="po">With a holy leer and a pious grin,</p>
+<p class="po">Ragged and fat and as saucy as sin,</p>
+<p class="poind1">Who held out his hands and cried:</p>
+<p class="po">“Give, give in Charity’s name, I pray.</p>
+<p class="po">Give in the name of the Church. O give,</p>
+<p class="po">Give that her holy sons may live!”</p>
+<p class="poind1">And Death replied,</p>
+<p class="poind1">Smiling long and wide:</p>
+<p class="poind1">“I’ll give, holy father, I’ll give thee—a ride.”</p>
+</td></tr>
+<tr><td class="poem">
+<p class="poind1">With a rattle and bang</p>
+<p class="poind1">Of his bones, he sprang</p>
+<p class="po">From his famous Pale Horse, with his spear;</p>
+<p class="poind1">By the neck and the foot</p>
+<p class="poind1">Seized the fellow, and put</p>
+<p class="po">Him astride with his face to the rear.</p>
+</td></tr>
+<tr><td class="poem">
+<p class="po">The Monarch laughed loud with a sound that fell</p>
+<p class="po">Like clods on the coffin’s sounding shell:</p>
+<p class="po">“Ho, ho! A beggar on horseback, they say,</p>
+<p class="poind1">Will ride to the devil!”—and thump</p>
+<p class="poind1">Fell the flat of his dart on the rump</p>
+<p class="po">Of the charger, which galloped away.</p>
+</td></tr>
+<tr><td class="poem">
+<p class="po">Faster and faster and faster it flew,</p>
+<p class="po">Till the rocks and the flocks and the trees that grew</p>
+<p class="po">By the road were dim and blended and blue</p>
+<p class="poind1">To the wild, wild eyes</p>
+<p class="poind1">Of the rider—in size</p>
+</td></tr>
+<tr><td class="poem">
+<p class="poind1">Resembling a couple of blackberry pies.</p>
+<p class="po">Death laughed again, as a tomb might laugh</p>
+<p class="poind1">At a burial service spoiled,</p>
+<p class="poind1">And the mourners’ intentions foiled</p>
+<p class="poind1">By the body erecting</p>
+<p class="poind1">Its head and objecting</p>
+<p class="po">To further proceedings in its behalf.</p>
+</td></tr>
+<tr><td class="poem">
+<p class="poind1">Resembling a couple of blackberry pies.</p>
+<p class="po">Death laughed again, as a tomb might laugh</p>
+<p class="poind1">At a burial service spoiled,</p>
+<p class="poind1">And the mourners’ intentions foiled</p>
+<p class="poind1">By the body erecting</p>
+<p class="poind1">Its head and objecting</p>
+<p class="po">To further proceedings in its behalf.</p>
+</td></tr>
+<tr><td class="poem">
+<p class="po">Many a year and many a day</p>
+<p class="po">Have passed since these events away.</p>
+<p class="po">The monk has long been a dusty corse,</p>
+<p class="po">And Death has never recovered his horse.</p>
+<p class="poind1">For the friar got hold of its tail,</p>
+<p class="poind1">And steered it within the pale</p>
+<p class="po">Of the monastery gray,</p>
+<p class="po">Where the beast was stabled and fed</p>
+<p class="po">With barley and oil and bread</p>
+<p class="po">Till fatter it grew than the fattest friar,</p>
+<p class="po">And so in due course was appointed Prior.</p>
+<p class="citeauth">G. J.</p>
+</td></tr>
+</table>
+
+<p class="entry"><span class="def">carnivorous,</span> <span class="pos">adj.</span> Addicted to the
+cruelty of devouring the timorous vegetarian, his heirs and assigns.</p>
+
+<p class="entry"><span class="def">cartesian,</span> <span class="pos">adj.</span> Relating to Descartes,
+a famous philosopher, author of the celebrated dictum, <span xml:lang="la"><i>Cogito ergo sum</i></span>—whereby
+he was pleased to suppose he demonstrated the reality of human existence. The dictum might be improved,
+however, thus: <i>Cogito cogito ergo cogito sum</i>—“I think that I think, therefore I think that I am;” as
+close an approach to certainty as any philosopher has yet made.</p>
+
+<p class="entry"><span class="def">cat,</span> <span class="pos">n.</span> A soft, indestructible automaton
+provided by nature to be kicked when things go wrong in the domestic circle.</p>
+
+<table class="poem">
+<tr><td class="poem">
+<p class="po">This is a dog,</p>
+<p class="poind1">This is a cat.</p>
+<p class="po">This is a frog,</p>
+<p class="poind1">This is a rat.</p>
+<p class="po">Run, dog, mew, cat.</p>
+<p class="po">Jump, frog, gnaw, rat.</p>
+<p class="citeauth">Elevenson.</p>
+</td></tr>
+</table>
+
+<p class="entry"><span class="def">caviler,</span> <span class="pos">n.</span> A critic of our own work.</p>
+
+<p class="entry"><span class="def">cemetery,</span> <span class="pos">n.</span> An isolated suburban
+spot where mourners match lies, poets write at a target and stone-cutters spell for a wager. The
+inscriptions following will serve to illustrate the success attained in these Olympian games:</p>
+
+<p class="quote">His virtues were so conspicuous that his enemies, unable to overlook them, denied
+them, and his friends, to whose loose lives they were a rebuke, represented them as vices. They are
+here commemorated by his family, who shared them.</p>
+
+<table class="poem">
+<tr><td class="poem">
+<p class="po">In the earth we here prepare a</p>
+<p class="po">Place to lay our little Clara.</p>
+<p class="citepoet">Thomas M. and Mary Frazer</p>
+<p class="po">P.S.—Gabriel will raise her.</p>
+</td></tr>
+</table>
+
+<p class="entry"><span class="def">centaur,</span> <span class="pos">n.</span> One of a race of
+persons who lived before the division of labor had been carried to such a pitch of differentiation, and
+who followed the primitive economic maxim, “Every man his own horse.” The best of the lot was Chiron,
+who to the wisdom and virtues of the horse added the fleetness of man. The scripture story of the head
+of John the Baptist on a charger shows that pagan myths have somewhat sophisticated sacred history.</p>
+
+<p class="entry"><span class="def">Cerberus,</span> <span class="pos">n.</span> The watch-dog of
+Hades, whose duty it was to guard the entrance—against whom or what does not clearly appear;
+everybody, sooner or later, had to go there, and nobody wanted to carry off the entrance. Cerberus
+is known to have had three heads, and some of the poets have credited him with as many as a hundred.
+Professor Graybill, whose clerky erudition and profound knowledge of Greek give his opinion great weight,
+has averaged all the estimates, and makes the number twenty-seven—a judgment that would be entirely
+conclusive is Professor Graybill had known (<i>a</i>) something about dogs, and (<i>b</i>) something about
+arithmetic.</p>
+
+<p class="entry"><span class="def">childhood,</span> <span class="pos">n.</span> The period of human
+life intermediate between the idiocy of infancy and the folly of youth—two removes from the sin of
+manhood and three from the remorse of age.</p>
+
+<p id="christian" class="entry"><span class="def">Christian,</span> <span class="pos">n.</span> One who believes that
+the New Testament is a divinely inspired book admirably suited to the spiritual needs of his neighbor. One
+who follows the teachings of Christ in so far as they are not inconsistent with a life of sin.</p>
+
+<table class="poem">
+<tr><td class="poem">
+<p class="po">I dreamed I stood upon a hill, and, lo!</p>
+<p class="po">The godly multitudes walked to and fro</p>
+<p class="po">Beneath, in Sabbath garments fitly clad,</p>
+<p class="po">With pious mien, appropriately sad,</p>
+<p class="po">While all the church bells made a solemn din—</p>
+<p class="po">A fire-alarm to those who lived in sin.</p>
+<p class="po">Then saw I gazing thoughtfully below,</p>
+<p class="po">With tranquil face, upon that holy show</p>
+<p class="po">A tall, spare figure in a robe of white,</p>
+<p class="po">Whose eyes diffused a melancholy light.</p>
+<p class="po">“God keep you, strange,” I exclaimed. “You are</p>
+<p class="po">No doubt (your habit shows it) from afar;</p>
+<p class="po">And yet I entertain the hope that you,</p>
+<p class="po">Like these good people, are a Christian too.”</p>
+<p class="po">He raised his eyes and with a look so stern</p>
+<p class="po">It made me with a thousand blushes burn</p>
+<p class="po">Replied—his manner with disdain was spiced:</p>
+<p class="po">“What! I a Christian? No, indeed! I’m Christ.”</p>
+<p class="citeauth">G. J.</p>
+</td></tr>
+</table>
+
+<p class="entry"><span class="def">circus,</span> <span class="pos">n.</span> A place where horses,
+ponies and elephants are permitted to see men, women and children acting the fool.</p>
+
+<p class="entry"><span class="def">clairvoyant,</span> <span class="pos">n.</span> A person, commonly
+a woman, who has the power of seeing that which is invisible to her patron, namely, that he is a blockhead.</p>
+
+<p class="entry"><span class="def">clarionet,</span> <span class="pos">n.</span> An instrument of torture
+operated by a person with cotton in his ears. There are two instruments that are worse than a clarionet—two
+clarionets.</p>
+
+<p class="entry"><span class="def">clergyman,</span> <span class="pos">n.</span> A man who undertakes
+the management of our spiritual affairs as a method of better his temporal ones.</p>
+
+<p class="entry"><span class="def">Clio,</span> <span class="pos">n.</span> One of the nine Muses. Clio’s
+function was to preside over history—which she did with great dignity, many of the prominent citizens of
+Athens occupying seats on the platform, the meetings being addressed by Messrs. Xenophon, Herodotus and
+other popular speakers.</p>
+
+<p class="entry"><span class="def">clock,</span> <span class="pos">n.</span> A machine of great moral
+value to man, allaying his concern for the future by reminding him what a lot of time remains to him.</p>
+
+<table class="poem">
+<tr><td class="poem">
+<p class="po">A busy man complained one day:</p>
+<p class="po">“I get no time!” “What’s that you say?”</p>
+<p class="po">Cried out his friend, a lazy quiz;</p>
+<p class="po">“You have, sir, all the time there is.</p>
+<p class="po">There’s plenty, too, and don’t you doubt it—</p>
+<p class="po">We’re never for an hour without it.”</p>
+<p class="citeauth">Purzil Crofe.</p>
+</td></tr>
+</table>
+
+<p class="entry"><span class="def">close-fisted,</span> <span class="pos">adj.</span> Unduly desirous
+of keeping that which many meritorious persons wish to obtain.</p>
+
+<table class="poem">
+<tr><td class="poem">
+<p class="po">“Close-fisted Scotchman!” Johnson cried</p>
+<p class="poind1">To thrifty J. Macpherson;</p>
+<p class="po">“See me—I’m ready to divide</p>
+<p class="poind1">With any worthy person.”</p>
+<p class="po">Sad Jamie: “That is very true—</p>
+<p class="poind1">The boast requires no backing;</p>
+<p class="po">And all are worthy, sir, to you,</p>
+<p class="poind1">Who have what you are lacking.”</p>
+<p class="citeauth">Anita M. Bobe.</p>
+</td></tr>
+</table>
+
+<p class="entry"><span class="def">cœnobite,</span> <span class="pos">n.</span> A man who piously
+shuts himself up to meditate upon the sin of wickedness; and to keep it fresh in his mind joins a brotherhood
+of awful examples.</p>
+
+<table class="poem">
+<tr><td class="poem">
+<p class="po">O Cœnobite, O cœnobite,</p>
+<p class="poind1">Monastical gregarian,</p>
+<p class="po">You differ from the anchorite,</p>
+<p class="poind1">That solitudinarian:</p>
+<p class="po">With vollied prayers you wound Old Nick;</p>
+<p class="po">With dropping shots he makes him sick.</p>
+<p class="citeauth">Quincy Giles.</p>
+</td></tr>
+</table>
+
+<p class="entry"><span class="def">comfort,</span> <span class="pos">n.</span> A state of mind
+produced by contemplation of a neighbor’s uneasiness.</p>
+
+<p class="entry"><span class="def">commendation,</span> <span class="pos">n.</span> The tribute
+that we pay to achievements that resembles, but do not equal, our own.</p>
+
+<p class="entry"><span class="def">commerce,</span> <span class="pos">n.</span> A kind of
+transaction in which A plunders from B the goods of C, and for compensation B picks the pocket of D
+of money belonging to E.</p>
+
+<p class="entry"><span class="def">commonwealth,</span> <span class="pos">n.</span> An administrative
+entity operated by an incalculable multitude of political parasites, logically active but fortuitously efficient.</p>
+
+<table class="poem">
+<tr><td class="poem">
+<p class="po">This commonwealth’s capitol’s corridors view,</p>
+<p class="po">So thronged with a hungry and indolent crew</p>
+<p class="po">Of clerks, pages, porters and all attaches</p>
+<p class="po">Whom rascals appoint and the populace pays</p>
+<p class="po">That a cat cannot slip through the thicket of shins</p>
+<p class="po">Nor hear its own shriek for the noise of their chins.</p>
+<p class="po">On clerks and on pages, and porters, and all,</p>
+<p class="po">Misfortune attend and disaster befall!</p>
+<p class="po">May life be to them a succession of hurts;</p>
+<p class="po">May fleas by the bushel inhabit their shirts;</p>
+<p class="po">May aches and diseases encamp in their bones,</p>
+<p class="po">Their lungs full of tubercles, bladders of stones;</p>
+<p class="po">May microbes, bacilli, their tissues infest,</p>
+<p class="po">And tapeworms securely their bowels digest;</p>
+<p class="po">May corn-cobs be snared without hope in their hair,</p>
+<p class="po">And frequent impalement their pleasure impair.</p>
+<p class="po">Disturbed be their dreams by the awful discourse</p>
+<p class="po">Of audible sofas sepulchrally hoarse,</p>
+<p class="po">By chairs acrobatic and wavering floors—</p>
+<p class="po">The mattress that kicks and the pillow that snores!</p>
+<p class="po">Sons of cupidity, cradled in sin!</p>
+<p class="po">Your criminal ranks may the death angel thin,</p>
+<p class="po">Avenging the friend whom I couldn’t work in.</p>
+<p class="citeauth">K. Q.</p>
+</td></tr>
+</table>
+
+<p class="entry"><span class="def">compromise,</span> <span class="pos">n.</span> Such an adjustment
+of conflicting interests as gives each adversary the satisfaction of thinking he has got what he ought not
+to have, and is deprived of nothing except what was justly his due.</p>
+
+<p class="entry"><span class="def">compulsion,</span> <span class="pos">n.</span> The eloquence of power.</p>
+
+<p class="entry"><span class="def">condole,</span> <span class="pos">v.i.</span> To show that bereavement
+is a smaller evil than sympathy.</p>
+
+<p class="entry"><span class="def">confidant,</span> <span class="def">confidante,</span> <span class="pos">n.</span> One
+entrusted by A with the secrets of B, confided by <i>him </i>to C.</p>
+
+<p class="entry"><span class="def">congratulation,</span> <span class="pos">n.</span> The civility of envy.</p>
+
+<p class="entry"><span class="def">congress,</span> <span class="pos">n.</span> A body of men who meet to repeal laws.</p>
+
+<p class="entry"><span class="def">connoisseur,</span> <span class="pos">n.</span> A specialist who knows everything
+about something and nothing about anything else.</p>
+
+<p class="indentpara">An old wine-bibber having been smashed in a railway collision, some wine was pouted on his lips to
+revive him. “Pauillac, 1873,” he murmured and died.</p>
+
+<p class="entry"><span class="def">conservative,</span> <span class="pos">n.</span> A statesman who is enamored of
+existing evils, as distinguished from the Liberal, who wishes to replace them
+with others.</p>
+
+<p class="entry"><span class="def">consolation,</span> <span class="pos">n.</span> The knowledge that a better man is
+more unfortunate than yourself.</p>
+
+<p class="entry"><span class="def">consul,</span> <span class="pos">n.</span> In American politics, a person who having
+failed to secure and office from the people is given one by the Administration
+on condition that he leave the country.</p>
+
+<p class="entry"><span class="def">consult,</span> <span class="pos">v.i.</span> To seek another’s disapproval of a course already decided on.</p>
+
+<p class="entry"><span class="def">contempt,</span> <span class="pos">n.</span> The feeling of a prudent man for an enemy who is too formidable safely to be opposed.</p>
+
+<p class="entry"><span class="def">controversy,</span> <span class="pos">n.</span> A battle in which spittle or ink replaces the injurious cannon-ball and the inconsiderate bayonet.</p>
+
+<table class="poem">
+<tr><td class="poem">
+<p class="po">In controversy with the facile tongue—</p>
+<p class="po">That bloodless warfare of the old and young—</p>
+<p class="po">So seek your adversary to engage</p>
+<p class="po">That on himself he shall exhaust his rage,</p>
+<p class="po">And, like a snake that’s fastened to the ground,</p>
+<p class="po">With his own fangs inflict the fatal wound.</p>
+<p class="po">You ask me how this miracle is done?</p>
+<p class="po">Adopt his own opinions, one by one,</p>
+<p class="po">And taunt him to refute them; in his wrath</p>
+<p class="po">He’ll sweep them pitilessly from his path.</p>
+<p class="po">Advance then gently all you wish to prove,</p>
+<p class="po">Each proposition prefaced with, “As you’ve</p>
+<p class="po">So well remarked,” or, “As you wisely say,</p>
+<p class="po">And I cannot dispute,” or, “By the way,</p>
+<p class="po">This view of it which, better far expressed,</p>
+<p class="po">Runs through your argument.” Then leave the rest</p>
+<p class="po">To him, secure that he’ll perform his trust</p>
+<p class="po">And prove your views intelligent and just.</p>
+<p class="citeauth">Conmore Apel Brune.</p>
+</td></tr>
+</table>
+
+<p class="entry"><span class="def">convent,</span> <span class="pos">n.</span> A place of retirement for woman who wish for leisure to meditate upon the vice of idleness.</p>
+
+<p class="entry"><span class="def">conversation,</span> <span class="pos">n.</span> A fair to the display of the minor
+mental commodities, each exhibitor being too intent upon the arrangement of his
+own wares to observe those of his neighbor.</p>
+
+<p class="entry"><span class="def">coronation,</span> <span class="pos">n.</span> The ceremony of investing a
+sovereign with the outward and visible signs of his divine right to be blown
+skyhigh with a dynamite bomb.</p>
+
+<p class="entry"><span class="def">corporal,</span> <span class="pos">n.</span> A man who occupies the lowest rung of the military ladder.</p>
+
+<table class="poem">
+<tr><td class="poem">
+<p class="po">Fiercely the battle raged and, sad to tell,</p>
+<p class="po">Our corporal heroically fell!</p>
+<p class="po">Fame from her height looked down upon the brawl</p>
+<p class="po">And said: “He hadn’t very far to fall.”</p>
+<p class="citeauth">Giacomo Smith.</p>
+</td></tr>
+</table>
+
+<p class="entry"><span class="def">corporation,</span> <span class="pos">n.</span> An ingenious device for obtaining individual profit without individual responsibility.</p>
+
+<p class="entry"><span class="def">Corsair,</span> <span class="pos">n.</span> A politician of the seas.</p>
+
+<p class="entry"><span class="def">court fool,</span> <span class="pos">n.</span> The plaintiff.</p>
+
+<p class="entry"><span class="def">coward,</span> <span class="pos">n.</span> One who in a perilous emergency thinks with his legs.</p>
+
+<p class="entry"><span class="def">crayfish,</span> n. A small crustacean very much resembling the lobster, but less indigestible.</p>
+
+<p class="quote">In this small fish I take it that human wisdom is admirably figured and symbolized; for whereas
+the crayfish doth move only backward, and can have only retrospection, seeing
+naught but the perils already passed, so the wisdom of man doth not enable him
+to avoid the follies that beset his course, but only to apprehend their nature afterward.—<i>Sir James Merivale</i></p>
+
+<p class="entry"><span class="def">creditor,</span> <span class="pos">n.</span> One of a tribe of savages dwelling beyond the Financial Straits and dreaded for their desolating incursions.</p>
+
+<p class="entry"><span class="def">Cremona,</span> <span class="pos">n.</span> A high-priced violin made in Connecticut.</p>
+
+<p class="entry"><span class="def">critic,</span> <span class="pos">n.</span> A person who boasts himself hard to please
+because nobody tries to please him.</p>
+
+<table class="poem">
+<tr><td class="poem">
+<p class="po">There is a land of pure delight,</p>
+<p class="poind1">Beyond the Jordan’s flood,</p>
+<p class="po">Where saints, apparelled all in white,</p>
+<p class="poind1">Fling back the critic’s mud.</p>
+</td></tr>
+<tr><td class="poem">
+<p class="po">And as he legs it through the skies,</p>
+<p class="poind1">His pelt a sable hue,</p>
+<p class="po">He sorrows sore to recognize</p>
+<p class="poind1">The missiles that he threw.</p>
+<p class="citeauth">Orrin Goof.</p>
+</td></tr>
+</table>
+
+<p class="entry"><span class="def">cross,</span> <span class="pos">n.</span> An ancient religious symbol erroneously
+supposed to owe its significance to the most solemn event in the history of
+Christianity, but really antedating it by thousands of years. By many it has been believed to be identical
+with the <span xml:lang="la"><i>crux ansata</i></span> of the
+ancient phallic worship, but it has been traced even beyond all that we know of
+that, to the rites of primitive peoples. We have to-day the White Cross as a symbol of chastity, and the Red
+Cross as a badge of benevolent neutrality in war. Having in mind the former, the reverend Father Gassalasca Jape
+smites the lyre to the effect following:</p>
+
+
+<table class="poem">
+<tr><td class="poem">
+<p class="po">“Be good, be good!” the sisterhood</p>
+<p class="poind1">Cry out in holy chorus,</p>
+<p class="po">And, to dissuade from sin, parade</p>
+<p class="poind1">Their various charms before us.</p>
+</td></tr>
+
+<tr><td class="poem">
+<p class="po">But why, O why, has ne’er an eye</p>
+<p class="poind1">Seen her of winsome manner</p>
+<p class="po">And youthful grace and pretty face</p>
+<p class="poind1">Flaunting the White Cross banner?</p>
+</td></tr>
+
+<tr><td class="poem">
+<p class="po">Now where’s the need of speech and screed</p>
+<p class="poind1">To better our behaving?</p>
+<p class="po">A simpler plan for saving man</p>
+<p class="poind1">(But, first, is he worth saving?)</p>
+</td></tr>
+
+<tr><td class="poem">
+<p class="po">Is, dears, when he declines to flee</p>
+<p class="poind1">From bad thoughts that beset him,</p>
+<p class="po">Ignores the Law as ’t were a straw,</p>
+<p class="poind1">And wants to sin—don’t let him.</p>
+</td></tr>
+</table>
+
+<p class="entry"><span class="def" lang="la">Cui Bono?</span> (Latin). What good would that do <i>me</i>?</p>
+
+<p class="entry"><span class="def">cunning,</span> <span class="pos">n.</span> The faculty that distinguishes
+a weak animal or person from a strong one. It brings its possessor much mental satisfaction and great material
+adversity. An Italian proverb says: “The furrier gets the skins of more foxes than asses.”</p>
+
+<p class="entry"><span class="def">Cupid,</span> <span class="pos">n.</span> The so-called god of love. This bastard creation of a barbarous fancy
+was no doubt inflicted upon mythology for the sins of its deities. Of all unbeautiful and inappropriate
+conceptions this is the most reasonless and offensive. The notion of symbolizing sexual love by a
+semisexless babe, and comparing the pains of passion to the wounds of an
+arrow—of introducing this pudgy homunculus into art grossly to materialize the
+subtle spirit and suggestion of the work—this is eminently worthy of the age
+that, giving it birth, laid it on the doorstep of prosperity.</p>
+
+<p class="entry"><span class="def">curiosity,</span> <span class="pos">n.</span> An objectionable quality of the female
+mind. The desire to know whether or not
+a woman is cursed with curiosity is one of the most active and insatiable
+passions of the masculine soul.</p>
+
+<p class="entry"><span class="def">curse,</span> <span class="pos">v.t.</span> Energetically to belabor with a verbal
+slap-stick. This is an operation which
+in literature, particularly in the drama, is commonly fatal to the victim. Nevertheless, the liability to a cursing is
+a risk that cuts but a small figure in fixing the rates of life insurance.</p>
+
+<p class="entry"><span class="def">cynic,</span> <span class="pos">n.</span> A blackguard whose faulty vision sees things
+as they are, not as they ought to be. Hence the custom among the Scythians of plucking out a cynic’s eyes to
+improve his vision.</p>
+
+</body>
+</html>
\ No newline at end of file
--- /dev/null
+++ b/lib/ebooks/devils/C.html.i
@@ -1,0 +1,33 @@
+14 pages
+size 400 552
+length 28562
+397 2 11 body html
+0
+1712 2 35 body html
+85
+3565 2 65 body html
+0
+3565 2 65 body html
+552
+8255 2 164 body html
+22
+10580 2 200 body html
+0
+12955 2 241 body html
+22
+14994 2 282 body html
+0
+16175 2 307 body html
+0
+18725 2 352 body html
+0
+20230 2 375 body html
+0
+22655 2 421 body html
+0
+24758 2 459 body html
+90
+26978 2 505 body html
+141
+carmelite 1
+christian 4
--- /dev/null
+++ b/lib/ebooks/devils/D.html
@@ -1,0 +1,536 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE html PUBLIC "+//ISBN 0-9673008-1-9//DTD OEB 1.0 Document//EN"
+ "http://openebook.org/dtds/oeb-1.0/oebdoc1.dtd">
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/x-oeb1-document; charset=utf-8" />
+<link rel="stylesheet" type="text/x-oeb1-css" href="devil.css" />
+<title>The Devil’s Dictionary: D</title>
+</head>
+
+<body lang="en-us">
+
+
+<h1>D</h1>
+
+<p class="entry"><span class="def">damn,</span> <span class="pos">v.</span> A word formerly much used by the
+Paphlagonians, the meaning of which is lost. By the learned Dr. Dolabelly Gak it is believed to have been a term of
+satisfaction, implying the highest possible degree of mental tranquillity.
+Professor Groke, on the contrary, thinks it
+expressed an emotion of tumultuous delight, because it so frequently occurs in
+combination with the word <i>jod</i> or <i>god</i>, meaning “joy.” It would be with great diffidence that I
+should advance an opinion conflicting with that of either of these formidable
+authorities.</p>
+
+<p class="entry"><span class="def">dance,</span> <span class="pos">v.i.</span> To leap about to the sound of tittering
+music, preferably with arms about your neighbor’s wife or daughter. There are many kinds of dances, but all
+those requiring the participation of the two sexes have two characteristics in
+common: they are conspicuously innocent, and warmly loved by the vicious.</p>
+
+<p class="entry"><span class="def">danger,</span> <span class="pos">n.</span></p>
+
+ <table align="center" border="0">
+ <tr>
+ <td valign="top" align="left">
+
+<p class="poetry">A savage beast which, when it sleeps,<br />
+<span class="ind1">
+Man girds at and despises,</span><br />
+But takes himself away by leaps<br />
+<span class="ind1">
+And bounds when it arises.</span></p>
+
+<p class="citeauth">Ambat Delaso.</p>
+
+ </td>
+ </tr>
+ </table>
+
+<p class="entry"><span class="def">daring,</span> <span class="pos">n.</span> One of the most conspicuous qualities of a man in security.</p>
+
+<p class="entry"><span class="def">datary,</span> <span class="pos">n.</span> A high ecclesiastic official of the Roman
+Catholic Church, whose important function is to brand the Pope’s bulls with the
+words <i>Datum Romae</i>.He enjoys a princely revenue and the friendship of God.</p>
+
+<p class="entry"><span class="def">dawn,</span> <span class="pos">n.</span> The time when men of reason go to
+bed. Certain old men prefer to rise at about that
+time, taking a cold bath and a long walk with an empty stomach, and otherwise
+mortifying the flesh. They then point
+with pride to these practices as the cause of their sturdy health and ripe
+years; the truth being that they are hearty and old, not because of their
+habits, but in spite of them. The
+reason we find only robust persons doing this thing is that it has killed all
+the others who have tried it.</p>
+
+<p class="entry"><span class="def">day,</span> <span class="pos">n.</span> A period of twenty-four hours, mostly
+misspent. This period is divided into
+two parts, the day proper and the night, or day improper—the former devoted to
+sins of business, the latter consecrated to the other sort. These two kinds of social activity overlap.</p>
+
+<p class="entry"><span class="def">dead,</span> <span class="pos">adj.</span></p>
+
+ <table align="center" border="0">
+ <tr>
+ <td valign="top" align="left">
+
+<p class="poetry">
+Done with the work of breathing;
+done<br />
+
+With all the world; the mad race
+run<br />
+
+Though to the end; the golden goal<br />
+
+Attained and found to be a hole!</p>
+
+<p class="citeauth">Squatol Johnes.</p>
+
+ </td>
+ </tr>
+ </table>
+
+<p class="entry"><span class="def">debauchee,</span> <span class="pos">n.</span> One who has so earnestly pursued pleasure
+that he has had the misfortune to overtake it.</p>
+
+<p class="entry"><span class="def">debt,</span> <span class="pos">n.</span> An ingenious substitute for the chain and
+whip of the slave-driver.</p>
+
+ <table align="center" border="0">
+ <tr>
+ <td valign="top" align="left">
+
+<p class="poetry">As, pent in an aquarium, the troutlet<br />
+
+Swims round and round his tank to find an outlet,<br />
+Pressing his nose against the glass that
+holds him,<br />
+Nor ever sees the prison that enfolds him;<br />
+
+So the poor debtor, seeing naught around him,<br />
+Yet feels the narrow limits that impound him,<br />
+Grieves at his debt and studies to evade it,<br />
+And finds at last he might as well
+have paid it.</p>
+
+<p class="citeauth">Barlow S. Vode.</p>
+
+ </td>
+ </tr>
+ </table>
+
+
+<p class="entry"><span class="def">decalogue,</span> <span class="pos">n.</span> A series of commandments, ten in number—just
+enough to permit an intelligent selection for observance, but not enough to
+embarrass the choice. Following is the
+revised edition of the Decalogue, calculated for this meridian.</p>
+
+ <table align="center" border="0">
+ <tr>
+ <td valign="top" align="left">
+
+<p class="poetry">Thou shalt no God but me adore:<br />
+
+‘Twere too expensive to have more.</p>
+
+<p class="poetry">No images nor idols make<br />
+
+For Robert Ingersoll to break.</p>
+
+<p class="poetry">Take not God’s name in vain; select<br />
+A time when it will have effect.</p>
+
+<p class="poetry">Work not on Sabbath days at all,<br />
+But go to see the teams play ball.</p>
+
+<p class="poetry">Honor thy parents. That creates<br />
+For life insurance lower rates.</p>
+
+<p class="poetry">Kill not, abet not those who kill;<br />
+Thou shalt not pay thy butcher’s bill.</p>
+
+<p class="poetry">Kiss not thy neighbor’s wife, unless<br />
+Thine own thy neighbor doth caress</p>
+
+<p class="poetry">Don’t steal; thou’lt never thus compete<br />
+Successfully in business. Cheat.</p>
+
+<p class="poetry">Bear not false witness—that is low—<br />
+But “hear ‘tis rumored so and so.”</p>
+
+<p class="poetry">Covet thou naught that thou hast not<br />
+By hook or crook, or somehow, got.</p>
+
+<p class="citeauth">G. J.</p>
+
+ </td>
+ </tr>
+ </table>
+
+
+
+<p class="entry"><span class="def">decide,</span> <span class="pos">v.i.</span> To succumb to the preponderance of one set
+of influences over another set.</p>
+
+ <table align="center" border="0">
+ <tr>
+ <td valign="top" align="left">
+
+<p class="poetry">A leaf was riven from a tree,<br />
+“I mean to fall to earth,” said he.</p>
+
+<p class="poetry">The west wind, rising, made him veer.<br />
+“Eastward,” said he, “I now shall steer.”</p>
+
+<p class="poetry">The east wind rose with greater force.<br />
+Said he: “’Twere wise to change my course.”</p>
+
+<p class="poetry">With equal power they contend.<br />
+He said: “My judgment I suspend.”</p>
+
+<p class="poetry">Down died the winds; the leaf, elate,<br />
+Cried: “I’ve decided to fall straight.”</p>
+
+<p class="poetry">“First thoughts are best?” That’s not the moral;<br />
+Just choose your own and we’ll not quarrel.</p>
+
+<p class="poetry">Howe’er your choice may chance to fall,<br />
+You’ll have no hand in it at all.</p>
+
+<p class="citeauth">G. J.</p>
+
+ </td>
+ </tr>
+ </table>
+
+<p class="entry"><span class="def">defame,</span> <span class="pos">v.t.</span> To lie about
+another. To tell the truth about another.</p>
+
+<p class="entry"><span class="def">defenceless,</span> <span class="pos">adj. </span>Unable to attack.</p>
+
+<p class="entry"><span class="def">degenerate,</span> <span class="pos">adj. </span>Less conspicuously admirable than
+one’s ancestors. The contemporaries of
+Homer were striking examples of degeneracy; it required ten of them to raise a
+rock or a riot that one of the heroes of the Trojan war could have raised with
+ease. Homer never tires of sneering at
+“men who live in these degenerate days,” which is perhaps why they suffered him
+to beg his bread—a marked instance of returning good for evil, by the way, for
+if they had forbidden him he would certainly have starved.</p>
+
+<p class="entry"><span class="def">degradation,</span> <span class="pos">n.</span> One of the stages of moral and
+social progress from private station to political preferment.</p>
+
+<p class="entry"><span class="def">deinotherium,</span> <span class="pos">n.</span> An extinct pachyderm that flourished
+when the Pterodactyl was in fashion. The latter was a native of Ireland, its name being pronounced Terry
+Dactyl or Peter O’Dactyl, as the man pronouncing it may chance to have heard it spoken or seen it printed.</p>
+
+<p class="entry"><span class="def">dejeuner,</span> <span class="pos">n.</span> The breakfast of an American who has been in
+Paris. Variously pronounced.</p>
+
+<p class="entry"><span class="def">delegation,</span> <span class="pos">n.</span> In American politics, an article of
+merchandise that comes in sets.</p>
+
+<p class="entry"><span class="def">deliberation,</span> <span class="pos">n.</span> The act of examining one’s bread to
+determine which side it is buttered on.</p>
+
+<p class="entry"><span class="def">deluge,</span> <span class="pos">n.</span> A notable first experiment in baptism which
+washed away the sins (and sinners) of the world.</p>
+
+<p class="entry"><span class="def">delusion,</span> <span class="pos">n.</span> The father of a most respectable family,
+comprising Enthusiasm, Affection, Self-denial, Faith, Hope, Charity and many
+other goodly sons and daughters.</p>
+
+ <table align="center" border="0">
+ <tr>
+ <td valign="top" align="left">
+
+<p class="poetry">All hail, Delusion! Were it not for thee<br />
+The world turned topsy-turvy we should see;<br />
+For Vice, respectable with cleanly fancies,<br />
+Would fly abandoned Virtue’s gross advances.</p>
+
+<p class="citeauth">Mumfrey Mappel.</p>
+
+ </td>
+ </tr>
+ </table>
+
+<p class="entry"><span class="def">dentist,</span> <span class="pos">n.</span> A prestidigitator who, putting metal into
+your mouth, pulls coins out of your pocket.</p>
+
+<p class="entry"><span class="def">dependent,</span> <span class="pos">adj.</span> Reliant upon another’s generosity
+for the support which you are not in a position to exact from his fears.</p>
+
+<p class="entry"><span class="def">deputy,</span> <span class="pos">n.</span> A male relative of an office-holder, or of
+his bondsman. The deputy is commonly a beautiful young man, with a red necktie and an intricate system of cobwebs
+extending from his nose to his desk. When accidentally struck by the janitor’s broom, he gives off a cloud of dust.</p>
+
+ <table align="center" border="0">
+ <tr>
+ <td valign="top" align="left">
+
+<p class="poetry">“Chief Deputy,” the Master cried,<br />
+“To-day the books are to be tried<br />
+By experts and accountants who<br />
+Have been commissioned to go through<br />
+Our office here, to see if we<br />
+Have stolen injudiciously.<br />
+Please have the proper entries made,<br />
+The proper balances displayed,<br />
+Conforming to the whole amount<br />
+Of cash on hand—which they will count.<br />
+I’ve long admired your punctual way—<br />
+Here at the break and close of day,<br />
+Confronting in your chair the crowd<br />
+Of business men, whose voices loud<br />
+And gestures violent you quell<br />
+By some mysterious, calm spell—<br />
+Some magic lurking in your look<br />
+That brings the noisiest to book<br />
+And spreads a holy and profound<br />
+Tranquillity o’er all around.<br />
+So orderly all’s done that they<br />
+Who came to draw remain to pay.<br />
+But now the time demands, at last,<br />
+That you employ your genius vast<br />
+In energies more active. Rise<br />
+And shake the lightnings from your eyes;<br />
+Inspire your underlings, and fling<br />
+Your spirit into everything!”<br />
+The Master’s hand here dealt a whack<br />
+Upon the Deputy’s bent back,<br />
+When straightway to the floor there fell<br />
+A shrunken globe, a rattling shell<br />
+A blackened, withered, eyeless head!<br />
+The man had been a twelvemonth dead.</p>
+<p class="citeauth">Jamrach Holobom.</p>
+
+ </td>
+ </tr>
+ </table>
+
+
+
+<p class="entry"><span class="def">destiny,</span> <span class="pos">n.</span> A tyrant’s authority for crime and fool’s excuse for failure.</p>
+
+<p class="entry"><span class="def">diagnosis,</span> <span class="pos">n.</span> A physician’s forecast of the disease by the
+patient’s pulse and purse.</p>
+
+<p class="entry"><span class="def">diaphragm,</span> <span class="pos">n.</span> A muscular partition separating disorders of
+the chest from disorders of the bowels.</p>
+
+<p class="entry"><span class="def">diary,</span> <span class="pos">n.</span> A daily record of that part of one’s life,
+which he can relate to himself without blushing.</p>
+
+ <table align="center" border="0">
+ <tr>
+ <td valign="top" align="left">
+
+<p class="poetry">Hearst kept a diary wherein were writ<br />
+All that he had of wisdom and of wit.<br />
+So the Recording Angel, when Hearst died,<br />
+Erased all entries of his own and cried:<br />
+“I’ll judge you by your diary.” Said Hearst:<br />
+“Thank you; ‘twill show you I am Saint the First”—<br />
+Straightway producing, jubilant and proud,<br />
+That record from a pocket in his shroud.<br />
+The Angel slowly turned the pages o’er,<br />
+Each stupid line of which he knew before,<br />
+Glooming and
+gleaming as by turns he hit<br />
+On Shallow sentiment and stolen wit;<br />
+Then gravely closed the book and gave it back.<br />
+“My friend, you’ve wandered from your proper track:<br />
+You’d never be content this side the tomb—<br />
+For big ideas Heaven has little room,<br />
+And Hell’s no latitude for making mirth,”<br />
+He said, and
+kicked the fellow back to earth.</p>
+
+<p class="citeauth">“The Mad Philosopher.”</p>
+
+ </td>
+ </tr>
+ </table>
+
+<p class="entry"><span class="def">dictator,</span> <span class="pos">n.</span> The chief of a nation that prefers the
+pestilence of despotism to the plague of anarchy.</p>
+
+<p class="entry"><span class="def">dictionary,</span> <span class="pos">n.</span> A malevolent literary device for cramping the growth of a language
+and making it hard and inelastic. This dictionary, however, is a most useful work.</p>
+
+<p class="entry"><span class="def">die,</span> <span class="pos">n.</span> The singular of “dice.”
+We seldom hear the word, because there is a
+prohibitory proverb, “Never say die.” At long intervals, however, some one says:
+“The die is cast,” which is not true, for it is cut. The word is found in an immortal couplet by
+that eminent poet and domestic economist, Senator Depew:</p>
+
+ <table align="center" border="0">
+ <tr>
+ <td valign="top" align="left">
+
+<p class="poetry">A cube of cheese no larger than a die</p>
+ May bait the trap to catch a nibbling mie.
+
+ </td>
+ </tr>
+ </table>
+
+<p class="entry"><span class="def">digestion,</span> <span class="pos">n.</span> The conversion of victuals into
+virtues. When the process is imperfect,
+vices are evolved instead—a circumstance from which that wicked writer, Dr.
+Jeremiah Blenn, infers that the ladies are the greater sufferers from dyspepsia.</p>
+
+<p class="entry"><span class="def">diplomacy,</span> <span class="pos">n.</span> The patriotic art of lying for one’s country.</p>
+
+<p class="entry"><span class="def">disabuse,</span> <span class="pos">v.t.</span> The present your neighbor with another and better error than the one
+which he has deemed it advantageous to embrace.</p>
+
+<p class="entry"><span class="def">discriminate,</span> <span class="pos">v.i.</span> To note the particulars in which
+one person or thing is, if possible, more objectionable than another.</p>
+
+<p class="entry"><span class="def">discussion,</span> <span class="pos">n.</span> A method of confirming others in their errors.</p>
+
+<p class="entry"><span class="def">disobedience,</span> <span class="pos">n.</span> The silver lining to the cloud of servitude.</p>
+
+<p class="entry"><span class="def">disobey,</span> <span class="pos">v.t.</span> To celebrate with an appropriate ceremony the maturity of a command.</p>
+
+ <table align="center" border="0">
+ <tr>
+ <td valign="top" align="left">
+
+<p class="poetry">His right to govern me is clear as day,<br />
+My duty manifest to disobey;<br />
+And if that fit observance e’er I shut<br />
+May I and duty be alike undone.</p>
+
+<p class="citeauth">Israfel Brown.</p>
+
+ </td>
+ </tr>
+ </table>
+
+
+
+<p class="entry"><span class="def">dissemble,</span> <span class="pos">v.i.</span> To put a clean shirt upon the character.</p>
+
+<p class="quote" style="text-align: center">Let us dissemble.—<i>Adam.</i></p>
+
+<p class="entry"><span class="def">distance,</span> <span class="pos">n.</span> The only thing that the rich are willing for
+the poor to call theirs, and keep.</p>
+
+<p class="entry"><span class="def">distress,</span> <span class="pos">n.</span> A disease incurred by exposure to the prosperity of a friend.</p>
+
+<p class="entry"><span class="def">divination,</span> <span class="pos">n.</span> The art of nosing out the
+occult. Divination is of as many kinds
+as there are fruit-bearing varieties of the flowering dunce and the early fool.</p>
+
+<p id="dog" class="entry"><span class="def">dog,</span> <span class="pos">n.</span> A kind of additional or subsidiary Deity
+designed to catch the overflow and surplus of the world’s worship. This Divine Being in some of his smaller and
+silkier incarnations takes, in the affection of Woman, the place to which there
+is no human male aspirant. The Dog is a survival—an anachronism. He toils not,
+neither does he spin, yet Solomon in all his glory never lay upon a door-mat
+all day long, sun-soaked and fly-fed and fat, while his master worked for the
+means wherewith to purchase the idle wag of the Solomonic tail, seasoned with a
+look of tolerant recognition.</p>
+
+<p class="entry"><span class="def">dragoon,</span> <span class="pos">n.</span> A soldier who combines dash and steadiness in so equal measure
+that he makes his advances on foot and his retreats on horseback.</p>
+
+<p class="entry"><span class="def">dramatist,</span> <span class="pos">n.</span> One who adapts plays from the French.</p>
+
+<p class="entry"><span class="def">druids,</span> <span class="pos">n.</span> Priests and ministers of an ancient Celtic
+religion which did not disdain to employ the humble allurement of human
+sacrifice. Very little is now known
+about the Druids and their faith. Pliny
+says their religion, originating in Britain, spread eastward as far as
+Persia. Caesar says those who desired
+to study its mysteries went to Britain. Caesar himself went to Britain, but does not appear to have obtained any
+high preferment in the Druidical Church, although his talent for human sacrifice
+was considerable.</p>
+
+<p class="indentpara">Druids performed their
+religious rites in groves, and knew nothing of church mortgages and the
+season-ticket system of pew rents. They
+were, in short, heathens and—as they were once complacently catalogued by a
+distinguished prelate of the Church of England—<i>Dissenters.</i></p>
+
+<p class="entry"><span class="def">duck-bill,</span> <span class="pos">n.</span> Your account at your restaurant during the canvas-back season.</p>
+
+<p class="entry"><span class="def">duel,</span> <span class="pos">n.</span> A formal ceremony preliminary to the
+reconciliation of two enemies. Great skill is necessary to its satisfactory observance; if awkwardly performed the
+most unexpected and deplorable consequences sometimes ensue. A long time ago a man lost his life in a duel.</p>
+
+ <table align="center" border="0">
+ <tr>
+ <td valign="top" align="left">
+
+<p class="poetry">That dueling’s a gentlemanly vice<br />
+<span class="ind1">
+I hold; and wish that it had been my lot</span><br />
+<span class="ind1">
+To live my life out in some favored spot—</span><br />
+Some country where it is considered nice<br />
+To split a rival like a fish, or slice<br />
+<span class="ind1">
+A husband like a spud, or with a shot</span><br />
+<span class="ind1">
+Bring down a debtor doubled in a knot</span><br />
+And ready to be put upon the ice.<br />
+Some miscreants there are, whom I do long<br />
+<span class="ind1">
+To shoot, to stab, or some such way reclaim</span><br />
+The scurvy rogues to better lives and manners,<br />
+I seem
+to see them now—a mighty throng.<br />
+<span class="ind1">
+It looks as if to challenge me they came,</span><br />
+Jauntily marching with brass bands and banners!</p>
+
+<p class="citeauth">Xamba Q. Dar.</p>
+
+ </td>
+ </tr>
+ </table>
+
+
+<p class="entry"><span class="def">Dullard,</span> <span class="pos">n.</span> A member of the reigning dynasty in letters
+and life. The Dullards came in with
+Adam, and being both numerous and sturdy have overrun the habitable world. The secret of their power is their
+insensibility to blows; tickle them with a bludgeon and they laugh with a
+platitude. The Dullards came originally
+from Boeotia, whence they were driven by stress of starvation, their dullness
+having blighted the crops. For some
+centuries they infested Philistia, and many of them are called Philistines to
+this day. In the turbulent times of the
+Crusades they withdrew thence and gradually overspread all Europe, occupying
+most of the high places in politics, art, literature, science and
+theology. Since a detachment of
+Dullards came over with the Pilgrims in the <i>Mayflower</i>
+and made a favorable report of the country, their increase by birth, immigration,
+and conversion has been rapid and steady. According to the most trustworthy statistics the number of adult
+Dullards in the United States is but little short of thirty millions, including
+the statisticians. The intellectual
+centre of the race is somewhere about Peoria, Illinois, but the New England
+Dullard is the most shockingly moral.</p>
+
+<p class="entry"><span class="def">duty,</span> <span class="pos">n.</span> That which sternly impels us in the direction of profit, along the line of desire.</p>
+
+ <table align="center" border="0">
+ <tr>
+ <td valign="top" align="left">
+
+<p class="poetry">Sir Lavender Portwine, in favor at court,</p>
+Was wroth at his master, who’d kissed Lady Port.<br />
+His anger provoked him to take the king’s head,<br />
+But duty prevailed, and he took the king’s bread,<br />
+<span class="ind3">
+Instead.</span>
+<p class="citeauth">G. J.</p>
+
+ </td>
+ </tr>
+ </table>
+
+</body>
+</html>
\ No newline at end of file
--- /dev/null
+++ b/lib/ebooks/devils/D.html.i
@@ -1,0 +1,30 @@
+13 pages
+size 400 552
+length 24257
+399 2 11 body html
+0
+2156 2 51 body html
+39
+4271 2 99 body html
+0
+5258 2 128 body html
+0
+6732 2 175 body html
+0
+8859 2 223 body html
+39
+11359 2 268 body html
+0
+11359 2 268 body html
+552
+14896 2 356 body html
+0
+17380 2 398 body html
+0
+19636 2 442 body html
+22
+21129 2 464 body html
+0
+22215 2 497 body html
+277
+dog 9
--- /dev/null
+++ b/lib/ebooks/devils/DevilsDictionary.opf
@@ -1,0 +1,119 @@
+<?xml version="1.0"?>
+<!DOCTYPE package PUBLIC "+//ISBN 0-9673008-1-9//DTD OEB 1.0 Package//EN" "oebpkg1.dtd">
+<package unique-identifier="oeb10devilsdictionary">
+<metadata>
+<dc-metadata xmlns:dc="http://purl.org/dc/elements/1.0/"
+ xmlns:oebpackage="http://openebook.org/namespaces/oeb-package/1.0">
+<dc:Title>The Devil's Dictionary</dc:Title>
+<dc:Type>Essay</dc:Type>
+<dc:Identifier scheme="none">123456789X</dc:Identifier>
+<dc:Creator role="aut" file-as="Bierce, Ambrose">Ambrose Bierce</dc:Creator>
+<dc:Subject>acidic commentary</dc:Subject>
+<dc:Publisher>PetesGuide.com</dc:Publisher>
+<dc:Contributor>Peter K. Sheerin</dc:Contributor>
+<dc:Contributor>Peter K. Sheerin</dc:Contributor>
+<dc:Date event="creation">1911</dc:Date>
+<dc:Date event="electronic publication">2000/07/21</dc:Date>
+<dc:Rights>This work is now in the public domain. This edition is based on the Project Guttenberg plain ASCII edition.</dc:Rights>
+<dc:Language>en-us</dc:Language>
+<dc:Coverage>Commentary on the use of language in the early 1900’s</dc:Coverage>
+</dc-metadata>
+<x-metadata>
+<meta name="price" content="US $0.00" />
+</x-metadata>
+</metadata>
+<manifest>
+<item id="toc" href="index.html" media-type="text/x-oeb1-document"/>
+<item id="preface" href="preface.html" media-type="text/x-oeb1-document"/>
+<item id="foreword" href="foreword.html" media-type="text/x-oeb1-document"/>
+<item id="titlepage" href="TitlePage.html" media-type="text/x-oeb1-document"/>
+<item id="A" href="A.html" media-type="text/x-oeb1-document"/>
+<item id="B" href="B.html" media-type="text/x-oeb1-document"/>
+<item id="C" href="C.html" media-type="text/x-oeb1-document"/>
+<item id="D" href="D.html" media-type="text/x-oeb1-document"/>
+<item id="E" href="E.html" media-type="text/x-oeb1-document"/>
+<item id="F" href="F.html" media-type="text/x-oeb1-document"/>
+<item id="G" href="G.html" media-type="text/x-oeb1-document"/>
+<item id="H" href="H.html" media-type="text/x-oeb1-document"/>
+<item id="I" href="I.html" media-type="text/x-oeb1-document"/>
+<item id="J" href="J.html" media-type="text/x-oeb1-document"/>
+<item id="K" href="K.html" media-type="text/x-oeb1-document"/>
+<item id="L" href="L.html" media-type="text/x-oeb1-document"/>
+<item id="M" href="M.html" media-type="text/x-oeb1-document"/>
+<item id="N" href="N.html" media-type="text/x-oeb1-document"/>
+<item id="O" href="O.html" media-type="text/x-oeb1-document"/>
+<item id="P" href="P.html" media-type="text/x-oeb1-document"/>
+<item id="Q" href="Q.html" media-type="text/x-oeb1-document"/>
+<item id="R" href="R.html" media-type="text/x-oeb1-document"/>
+<item id="S" href="S.html" media-type="text/x-oeb1-document"/>
+<item id="T" href="T.html" media-type="text/x-oeb1-document"/>
+<item id="U" href="U.html" media-type="text/x-oeb1-document"/>
+<item id="V" href="V.html" media-type="text/x-oeb1-document"/>
+<item id="W" href="W.html" media-type="text/x-oeb1-document"/>
+<item id="X" href="X.html" media-type="text/x-oeb1-document"/>
+<item id="Y" href="Y.html" media-type="text/x-oeb1-document"/>
+<item id="Z" href="Z.html" media-type="text/x-oeb1-document"/>
+<item id="StyleSheet" href="devil.css" media-type="text/x-oeb1-css"/>
+</manifest>
+<spine>
+<itemref idref="titlepage"/>
+<itemref idref="toc"/>
+<itemref idref="foreword"/>
+<itemref idref="preface"/>
+<itemref idref="A"/>
+<itemref idref="B"/>
+<itemref idref="C"/>
+<itemref idref="D"/>
+<itemref idref="E"/>
+<itemref idref="F"/>
+<itemref idref="G"/>
+<itemref idref="H"/>
+<itemref idref="I"/>
+<itemref idref="J"/>
+<itemref idref="K"/>
+<itemref idref="L"/>
+<itemref idref="M"/>
+<itemref idref="N"/>
+<itemref idref="O"/>
+<itemref idref="P"/>
+<itemref idref="Q"/>
+<itemref idref="R"/>
+<itemref idref="S"/>
+<itemref idref="T"/>
+<itemref idref="U"/>
+<itemref idref="V"/>
+<itemref idref="W"/>
+<itemref idref="X"/>
+<itemref idref="Y"/>
+<itemref idref="Z"/>
+</spine>
+<tours>
+<tour id="poetrytour" title="Alphabetical Tour of Poetry Citations">
+<site title="Poor Isabella’s Dead" href="A.html#abdication"/>
+<site title="Abracadabra" href="A.html#abracadabra"/>
+<site title="Spring Beckons!" href="A.html#abscond"/>
+<site title="Poor Isabella's Dead" href="A.html#absent"/>
+<site title="Poor Isabella's Dead" href="A.html#abstainer"/>
+<site title="Poor Isabella's Dead" href="A.html#accountability"/>
+<site title="Poor Isabella's Dead" href="A.html#admonition"/>
+<site title="Poor Isabella's Dead" href="A.html#advice"/>
+<site title="Poor Isabella's Dead" href="A.html#aim"/>
+<site title="Poor Isabella's Dead" href="A.html#allah"/>
+<site title="Poor Isabella's Dead" href="A.html#allegiance"/>
+<site title="Poor Isabella's Dead" href="A.html#alone"/>
+<site title="Poor Isabella's Dead" href="A.html#altar"/>
+<site title="Poor Isabella's Dead" href="A.html#anoint"/>
+<site title="Poor Isabella's Dead" href="A.html#aphorism"/>
+<site title="Poor Isabella's Dead" href="A.html#apothecary"/>
+<site title="Poor Isabella's Dead" href="A.html#archbishop"/>
+<site title="Poor Isabella's Dead" href="A.html#arsenic"/>
+<site title="Poor Isabella's Dead" href="A.html#art"/>
+</tour>
+</tours>
+<guide>
+<reference type="toc" title="Table of Contents" href="index.html"/>
+<reference type="foreword" title="Foreword" href="foreword.html"/>
+<reference type="preface" title="Preface" href="preface.html"/>
+<reference type="other.ms-firstpage" title="" href="foreword.html"/>
+</guide>
+</package>
--- /dev/null
+++ b/lib/ebooks/devils/E.html
@@ -1,0 +1,629 @@
+<?xml version="1.0" encoding="utf-16"?>
+<!DOCTYPE html PUBLIC "+//ISBN 0-9673008-1-9//DTD OEB 1.0 Document//EN"
+ "http://openebook.org/dtds/oeb-1.0/oebdoc1.dtd">
+<html>
+<head>
+<meta http-equiv="Content-type" content="text/x-oeb1-document; charset=utf-8" />
+<link rel="stylesheet" type="text/x-oeb1-css" href="devil.css" />
+<title>The Devil’s Dictionary: E</title>
+</head>
+
+<body lang="en-us">
+
+<h1>E</h1>
+
+<p class="entry"><span class="def">eat,</span> <span class="pos">v.i.</span> To perform
+successively (and successfully) the functions of mastication, humectation, and deglutition.</p>
+
+<p class="indentpara">“I was in the drawing-room, enjoying my dinner,” said Brillat-Savarin, beginning
+an anecdote. “What!” interrupted Rochebriant; “eating dinner in a drawing-room?” “I must beg you to
+observe, monsieur,” explained the great gastronome, “that I did not say I was eating my dinner, but enjoying it. I
+had dined an hour before.”</p>
+
+<p class="entry"><span class="def">eavesdrop,</span> <span class="pos">v.i.</span> Secretly
+to overhear a catalogue
+of the crimes and vices of another or yourself.</p>
+
+ <table align="center" border="0">
+ <tr>
+ <td valign="top" align="left">
+
+<p class="poetry">A lady with one of her ears applied<br />
+To an open keyhole heard, inside,<br />
+Two female gossips in converse
+free—<br />
+The subject engaging them was she.<br />
+“I think,” said
+one, “and my husband thinks<br />
+That she’s a prying, inquisitive minx!”<br />
+As soon as no more of it she could
+hear<br />
+The lady, indignant, removed her
+ear.<br />
+“I will not stay,”
+she said, with a pout,<br />
+“To hear my character lied about!”</p>
+
+<p class="citeauth">Gopete Sherany.</p>
+
+ </td>
+ </tr>
+ </table>
+
+<p class="entry"><span class="def">eccentricity,</span> <span class="pos">n.</span> A method of distinction so cheap
+that fools employ it to accentuate their incapacity.</p>
+
+<p class="entry"><span class="def">economy,</span> <span class="pos">n.</span> Purchasing
+the barrel of whiskey that you do
+not need for the price of the cow that you cannot afford.</p>
+
+<p class="entry"><span class="def">edible,</span> <span class="pos">adj.</span> Good to eat,
+and wholesome to digest, as a
+worm to a toad, a toad to a snake, a snake to a pig, a pig to a man, and a man
+to a worm.</p>
+
+<p class="entry"><span class="def">editor,</span> <span class="pos">n.</span> A person who combines the judicial functions
+of Minos, Rhadamanthus and Aeacus, but is placable with an obolus; a severely
+virtuous censor, but so charitable withal that he tolerates the virtues of
+others and the vices of himself; who flings about him the splintering lightning
+and sturdy thunders of admonition till he resembles a bunch of firecrackers
+petulantly uttering his mind at the tail of a dog; then straightway murmurs a
+mild, melodious lay, soft as the cooing of a donkey intoning its prayer to the
+evening star. Master of mysteries and
+lord of law, high-pinnacled upon the throne of thought, his face suffused with
+the dim splendors of the Transfiguration, his legs intertwisted and his tongue
+a-cheek, the editor spills his will along the paper and cuts it off in lengths
+to suit. And at intervals from behind
+the veil of the temple is heard the voice of the foreman demanding three inches
+of wit and six lines of religious meditation, or bidding him turn off the wisdom
+and whack up some pathos.</p>
+
+ <table align="center" border="0">
+ <tr>
+ <td valign="top" align="left">
+
+<p class="poetry">O, the Lord of Law
+on the Throne of Thought,<br />
+<span class="ind1">A gilded impostor is he.</span><br />
+Of shreds and
+patches his robes are wrought,<br />
+<span class="ind3">
+His crown is brass,</span><br />
+<span class="ind3">
+Himself an ass,</span><br />
+<span class="ind1">
+And his power is fiddle-dee-dee.</span><br />
+Prankily, crankily prating of
+naught,<br />
+Silly old quilly old Monarch of
+Thought.<br />
+<span class="ind1">
+Public opinion’s
+camp-follower he,</span><br />
+<span class="ind1">Thundering, blundering, plundering free.</span><br />
+<span class="ind3">
+Affected,</span><br />
+<span class="ind6">
+Ungracious,</span><br />
+<span class="ind3">
+Suspected,</span><br />
+<span class="ind6">
+Mendacious,</span><br />
+Respected contemporaree!</p>
+
+<p class="citeauth">J.H. Bumbleshook.</p>
+
+ </td>
+ </tr>
+ </table>
+
+<p class="entry"><span class="def">education,</span> <span class="pos"> n.</span> That
+which discloses to the wise and disguises from the foolish their lack of
+understanding.</p>
+
+<p class="entry"><span class="def">effect,</span> <span class="pos">n.</span> The second of two phenomena which always
+occur together in the same order. The
+first, called a Cause, is said to generate the other—which is no more sensible
+than it would be for one who has never seen a dog except in the pursuit of a
+rabbit to declare the rabbit the cause of a dog.</p>
+
+<p class="entry"><span class="def">egotist,</span> <span class="pos">n.</span> A
+person of low taste, more interested in himself than in me.</p>
+
+ <table align="center" border="0">
+ <tr>
+ <td valign="top" align="left">
+
+<p class="poetry">Megaceph, chosen to serve the State<br />
+In the halls of legislative debate,<br />
+One day with all his credentials
+came<br />
+To the capitol’s door and announced
+his name.<br />
+The doorkeeper looked, with a
+comical twist<br />
+Of the face, at the eminent
+egotist,<br />
+And said: “Go away, for we settle here<br />
+All manner of questions, knotty and
+queer,<br />
+And we cannot have, when the
+speaker demands<br />
+To be told how every member stands,<br />
+A man who to all things under the
+sky<br />
+Assents by eternally voting ‘I’.”
+ </p>
+ </td>
+ </tr>
+ </table>
+
+<p class="entry"><span class="def">ejection,</span> <span class="pos">n.</span> An approved remedy for the disease of
+garrulity. It is also much used in
+cases of extreme poverty.</p>
+
+<p class="entry"><span class="def">elector,</span> <span class="pos">n.</span> One who enjoys the sacred privilege of
+voting for the man of another man’s choice.</p>
+
+<p class="entry"><span class="def">electricity,</span> <span class="pos">n.</span> The power that causes all natural
+phenomena not known to be caused by something else. It is the same thing as lightning, and its famous attempt to
+strike Dr. Franklin is one of the most picturesque incidents in that great and
+good man’s career. The memory of Dr.
+Franklin is justly held in great reverence, particularly in France, where a
+waxen effigy of him was recently on exhibition, bearing the following touching
+account of his life and services to science:</p>
+
+<p class="quote">“Monsieur
+Franqulin, inventor of electricity.
+This illustrious savant, after having made several voyages around the
+world, died on the Sandwich Islands and was devoured by savages, of whom not a
+single fragment was ever recovered.”</p>
+
+<p class="indentpara">Electricity seems
+destined to play a most important part in the arts and industries. The question of its economical application
+to some purposes is still unsettled, but experiment has already proved that it
+will propel a street car better than a gas jet and give more light than a
+horse.</p>
+
+<p class="entry"><span class="def">elegy,</span> <span class="pos">n.</span> A composition in verse, in which, without
+employing any of the methods of humor, the writer aims to produce in the
+reader’s mind the dampest kind of dejection.
+The most famous English example begins somewhat like this:</p>
+
+ <table align="center" border="0">
+ <tr>
+ <td valign="top" align="left">
+
+<p class="poetry">The cur foretells
+the knell of parting day;<br />
+<span class="ind1">
+The loafing herd
+winds slowly o’er the lea;</span><br />
+The wise man
+homeward plods; I only stay<br />
+<span class="ind1">
+To fiddle-faddle
+in a minor key.</span>
+ </p>
+ </td>
+ </tr>
+ </table>
+
+<p class="entry"><span class="def">eloquence,</span> <span class="pos">n.</span>
+The art of orally persuading fools that white
+is the color that it appears to be. It
+includes the gift of making any color appear white.</p>
+
+<p class="entry"><span class="def">elysium,</span> <span class="pos">n.</span> An imaginary delightful country which the
+ancients foolishly believed to be inhabited by the spirits of the good. This ridiculous and mischievous fable was
+swept off the face of the earth by the early Christians—may their souls be
+happy in Heaven!</p>
+
+<p class="entry"><span class="def">emancipation,</span> <span class="pos">
+n.</span> A bondman’s change from the tyranny
+of another to the despotism of himself.</p>
+
+ <table align="center" border="0">
+ <tr>
+ <td valign="top" align="left">
+
+<p class="poetry">He was a
+slave: at word he went and came;<br />
+<span class="ind1">
+His iron collar cut
+him to the bone.</span><br />
+Then Liberty
+erased his owner’s name,<br />
+<span class="ind1">
+Tightened the
+rivets and inscribed his own.</span></p>
+
+<p class="citeauth">G. J.</p>
+
+ </td>
+ </tr>
+ </table>
+
+<p class="entry"><span class="def">embalm,</span> <span class="pos">v.i.</span> To cheat vegetation by locking up the gases
+upon which it feeds. By embalming their
+dead and thereby deranging the natural balance between animal and vegetable
+life, the Egyptians made their once fertile and populous country barren and
+incapable of supporting more than a meagre crew. The modern metallic burial casket is a step in the same direction,
+and many a dead man who ought now to be ornamenting his neighbor’s lawn as a
+tree, or enriching his table as a bunch of radishes, is doomed to a long
+inutility. We shall get him after
+awhile if we are spared, but in the meantime the violet and rose are
+languishing for a nibble at his <i>glutoeus
+maximus</i>.</p>
+
+<p class="entry"><span class="def">emotion,</span> <span class="pos">n.</span> A prostrating disease caused by a
+determination of the heart to the head.
+It is sometimes accompanied by a copious discharge of hydrated chloride
+of sodium from the eyes.</p>
+
+<p class="entry"><span class="def">encomiast,</span> <span class="pos">n.</span> A special (but not particular) kind of liar.</p>
+
+<p class="entry"><span class="def">end,</span> <span class="pos">n.</span> The position farthest removed on either hand
+from the Interlocutor.</p>
+
+ <table align="center" border="0">
+ <tr>
+ <td valign="top" align="left">
+
+<p class="poetry">The man was
+perishing apace<br />
+<span class="ind1">
+Who played the
+tambourine;</span><br />
+The seal of death
+was on his face—<br />
+<span class="ind1">
+‘Twas pallid, for
+‘twas clean.</span></p>
+
+<p class="poetry">“This is the end,”
+the sick man said<br />
+<span class="ind1">
+In faint and
+failing tones.</span><br />
+A moment later he
+was dead,<br />
+<span class="ind1">
+And Tambourine was
+Bones.</span></p>
+
+<p class="citeauth">Tinley Roquot.</p>
+
+ </td>
+ </tr>
+ </table>
+
+<p></p>
+
+<p class="entry"><span class="def">enough,</span> <span class="pos">pro.</span> All there is in the world if you like it.</p>
+
+ <table align="center" border="0">
+ <tr>
+ <td valign="top" align="left">
+
+<p class="poetry">Enough is as good
+as a feast—for that matter<br />
+Enougher’s as good as a feast for the platter.</p>
+<p class="citeauth">Arbely C. Strunk. </p>
+
+ </td>
+ </tr>
+ </table>
+
+<p class="entry"><span class="def">entertainment,</span> <span class="pos">n.</span> Any kind of amusement whose inroads
+stop short of death by injection.</p>
+
+<p class="entry"><span class="def">enthusiasm,</span> <span class="pos">n.</span> A distemper of youth, curable by
+small doses of repentance in connection with outward applications of
+experience. Byron, who recovered long
+enough to call it “entuzy-muzy,” had a relapse, which carried him off—to
+Missolonghi.</p>
+
+<p class="entry"><span class="def">envelope,</span> <span class="pos">n.</span> The coffin of a document; the scabbard of a
+bill; the husk of a remittance; the bed-gown of a love-letter.</p>
+
+<p class="entry"><span class="def">envy,</span> <span class="pos">n.</span> Emulation adapted to the meanest capacity.</p>
+
+<p class="entry"><span class="def">epaulet,</span> <span class="pos">n.</span> An ornamented badge, serving to distinguish
+a military officer from the enemy—that is to say, from the officer of lower
+rank to whom his death would give promotion.</p>
+
+<p class="entry"><span class="def">epicure,</span> <span class="pos">n.</span> An opponent of Epicurus, an abstemious
+philosopher who, holding that pleasure should be the chief aim of man, wasted
+no time in gratification from the senses.</p>
+
+<p class="entry"><span class="def">epigram,</span> <span class="pos">n.</span> A short, sharp saying in prose or verse,
+frequently characterize by acidity or acerbity and sometimes by wisdom. Following are some of the more notable
+epigrams of the learned and ingenious Dr. Jamrach Holobom:</p>
+
+ <blockquote>
+<p>We know better the
+needs of ourselves than of others. To
+serve oneself is economy of administration.</p>
+<p>In each human
+heart are a tiger, a pig, an ass and a nightingale. Diversity of character is due to their unequal activity.</p>
+<p>There are three
+sexes; males, females and girls.</p>
+<p>Beauty in women
+and distinction in men are alike in this:
+they seem to be
+the unthinking a kind of credibility.</p>
+<p>Women in love are
+less ashamed than men. They have less
+to be ashamed of.</p>
+<p>While your friend
+holds you affectionately by both your hands you are safe, for you can watch
+both his.</p>
+ </blockquote>
+
+
+
+<p class="entry"><span class="def">epitaph,</span> <span class="pos">n.</span> An inscription on a tomb, showing that
+virtues acquired by death have a retroactive effect. Following is a touching example:</p>
+
+ <table align="center" border="0">
+ <tr>
+ <td valign="top" align="left">
+
+<p class="poetry">Here lie the bones of Parson Platt,<br />
+Wise, pious, humble and all that,<br />
+Who showed us life as all should
+live it;<br />
+Let that be said—and God forgive
+it! </p>
+
+ </td>
+ </tr>
+ </table>
+
+<p class="entry"><span class="def">erudition,</span> <span class="pos">n.</span> Dust shaken out of a book into an empty
+skull.</p>
+
+ <table align="center" border="0">
+ <tr>
+ <td valign="top" align="left">
+
+<p class="poetry">So wide his erudition’s mighty
+span,<br />
+He knew Creation’s origin and plan<br />
+And only came by accident to grief—<br />
+He thought, poor man, ‘twas right
+to be a thief.</p>
+
+<p></p>
+
+<p class="citeauth">Romach Pute.</p>
+
+ </td>
+ </tr>
+ </table>
+
+<p></p>
+
+<p class="entry"><span class="def">esoteric,</span> <span class="pos">adj.</span> Very particularly abstruse and
+consummately occult. The ancient
+philosophies were of two kinds,<i>—exoteric</i>,
+those that the philosophers themselves could partly understand, and <i>esoteric</i>, those that nobody could
+understand. It is the latter that have
+most profoundly affected modern thought and found greatest acceptance in our
+time.</p>
+
+<p class="entry"><span class="def">ethnology,</span> <span class="pos">n.</span> The science that treats of the various
+tribes of Man, as robbers, thieves, swindlers, dunces, lunatics, idiots and
+ethnologists.</p>
+
+<p class="entry"><span class="def">Eucharist,</span> <span class="pos">n.</span> A sacred feast of the religious sect of
+Theophagi.</p>
+
+<p class="indentpara">A dispute once
+unhappily arose among the members of this sect as to what it was that they
+ate. In this controversy some five
+hundred thousand have already been slain, and the question is still unsettled.</p>
+
+<p class="entry"><span class="def">eulogy,</span> <span class="pos">n.</span> Praise of a person who has either the
+advantages of wealth and power, or the consideration to be dead.</p>
+
+<p class="entry"><span class="def">evangelist,</span> <span class="pos">n.</span> A bearer of good tidings,
+particularly (in a religious sense) such as assure us of our own salvation and
+the damnation of our neighbors.</p>
+
+<p class="entry"><span class="def">everlasting,</span> <span class="pos">adj.</span> Lasting forever. It is with no small diffidence that I
+venture to offer this brief and elementary definition, for I am not unaware of
+the existence of a bulky volume by a sometime Bishop of Worcester, entitled, <i>A
+Partial Definition of the Word “Everlasting,” as Used in the Authorized Version
+of the Holy Scriptures</i>. His book was
+once esteemed of great authority in the Anglican Church, and is still, I
+understand, studied with pleasure to the mind and profit of the soul.</p>
+
+<p class="entry"><span class="def">exception,</span> <span class="pos">n.</span> A thing which takes the liberty to differ
+from other things of its class, as an honest man, a truthful woman, etc. “The exception proves the rule” is an
+expression constantly upon the lips of the ignorant, who parrot it from one
+another with never a thought of its absurdity.
+In the Latin, “<i>Exceptio probat regulam</i>” means that the exception <i>tests</i> the rule, puts it to the proof, not <i>confirms</i> it.
+The malefactor who drew the meaning from this excellent dictum
+and substituted a contrary one of his own exerted an evil power which appears
+to be immortal.</p>
+
+<p class="entry"><span class="def">excess,</span> <span class="pos">n.</span> In morals, an indulgence that enforces by
+appropriate penalties the law of moderation.</p>
+
+ <table align="center" border="0">
+ <tr>
+ <td valign="top" align="left">
+
+<p class="poetry">
+
+Hail, high
+Excess—especially in wine,<br />
+<span class="ind1">
+To thee in worship
+do I bend the knee</span><br />
+<span class="ind1">
+ Who preach abstemiousness unto me—</span><br />
+My skull thy
+pulpit, as my paunch thy shrine.<br />
+Precept on
+precept, aye, and line on line,<br />
+<span class="ind1">
+Could ne’er
+persuade so sweetly to agree</span><br />
+<span class="ind1">
+With reason as thy
+touch, exact and free,</span><br />
+Upon my forehead
+and along my spine.<br />
+At thy command
+eschewing pleasure’s cup,<br />
+<span class="ind1">
+With the hot grape
+I warm no more my wit;</span><br />
+<span class="ind1">
+When on thy stool
+of penitence I sit</span><br />
+I’m quite converted, for I can’t
+get up.<br />
+Ungrateful he who afterward would
+falter<br />
+To make new sacrifices at thine
+altar!</p>
+
+ </td>
+ </tr>
+ </table>
+
+<p class="entry"><span class="def">excommunication,</span> <span class="pos">n.</span></p>
+
+ <table align="center" border="0">
+ <tr>
+ <td valign="top" align="left">
+
+<p class="poetry">This “excommunication” is a word<br />
+In speech ecclesiastical oft heard,<br />
+And means the
+damning, with bell, book and candle,<br />
+Some sinner whose opinions are a scandal—<br />
+A rite permitting
+Satan to enslave him<br />
+Forever, and forbidding Christ to save him.</p>
+
+<p class="citeauth">Gat Huckle.</p>
+
+ </td>
+ </tr>
+ </table>
+
+<p></p>
+
+<p class="entry"><span class="def">executive,</span> <span class="pos">n.</span> An officer of the Government, whose duty it
+is to enforce the wishes of the legislative power until such time as the
+judicial department shall be pleased to pronounce them invalid and of no
+effect. Following is an extract from an
+old book entitled, <i>The Lunarian Astonished—</i>Pfeiffer & Co., Boston,
+1803:</p>
+<blockquote>
+<p>Lunarian: Then when your Congress has passed a law it
+goes directly to the Supreme Court in order that it may at once be known whether it is constitutional?</p>
+
+<p>Terrestrain: O no; it does not require the approval of
+the Supreme Court until having perhaps been enforced for many years somebody objects to its
+operation against himself—I mean his client.
+The President, if he approves it, begins to execute it at once.</p>
+
+<p>Lunarian: Ah, the executive power is a part of the legislative.</p>
+
+<p>Do your policemen also have to approve the local ordinances that they enforce?</p>
+
+<p>Terrestrian: Not yet—at least not in their character of constables.
+Generally speaking, though, all laws require the approval of those whom they are intended to restrain.</p>
+
+<p>Lunarian: I see. The death warrant is not valid until signed by the murderer.</p>
+
+<p>Terrestrian: My friend, you put it too strongly; we are not so consistent.</p>
+
+<p>Lunarian: But this system of maintaining an expensive
+judicial machinery to pass upon the validity of laws only after they have long been executed, and then
+only when brought before the court by some private person—does it not cause great confusion?</p>
+
+<p>Terrestrian: It does.</p>
+
+<p>Lunarian: Why then should not your laws, previously to
+being executed, be validated, not by the signature of your President, but by that of the Chief
+Justice of the Supreme Court?</p>
+
+<p>Terrestrian: There is no precedent for any such course.</p>
+
+<p>Lunarian: Precedent. What is that?</p>
+
+<p>Terrestrian: It has been defined by five hundred lawyers
+in three volumes each. So how can any one know?</p>
+</blockquote>
+
+<p class="entry"><span class="def">exhort,</span> <span class="pos">v.t.</span> In
+religious affairs, to put the conscience of another upon the spit and roast it
+to a nut-brown discomfort.</p>
+
+<p class="entry"><span class="def">exile,</span> <span class="pos">n.</span> One who serves his country by residing
+abroad, yet is not an ambassador.</p>
+
+<p class="indentpara">An English
+sea-captain being asked if he had read “The Exile of Erin,” replied: “No, sir, but I should like to anchor on
+it.” Years afterwards, when he had been
+hanged as a pirate after a career of unparalleled atrocities, the following
+memorandum was found in the ship’s log that he had kept at the time of his
+reply:</p>
+
+<p class="quote">Aug. 3d,
+1842. Made a joke on the ex-Isle of Erin. Coldly received. War with the whole world!</p>
+
+<p class="entry"><span class="def">existence,</span> <span class="pos">n.</span></p>
+
+ <table align="center" border="0">
+ <tr>
+ <td valign="top" align="left">
+
+<p class="poetry">A transient,
+horrible, fantastic dream,<br />
+Wherein is nothing yet all things do seem:<br />
+From which we’re
+wakened by a friendly nudge<br />
+Of our bedfellow Death, and cry: “O fudge!”</p>
+
+ </td>
+ </tr>
+ </table>
+
+<p class="entry"><span class="def">experience,</span> <span class="pos">n.</span> The wisdom that enables us to recognize
+as an undesirable old acquaintance the folly that we have already embraced.</p>
+
+ <table align="center" border="0">
+ <tr>
+ <td valign="top" align="left">
+
+<p class="poetry">To one who,
+journeying through night and fog,<br />
+Is mired neck-deep in an unwholesome bog,<br />
+Experience, like the rising of the dawn,<br />
+Reveals the path that he should not
+have gone.</p>
+
+<p class="citeauth">Joel Frad Bink.</p>
+
+ </td>
+ </tr>
+ </table>
+
+<p class="entry"><span class="def">expostulation,</span> <span class="pos">n.</span> One of the many methods by which
+fools prefer to lose their friends.</p>
+
+<p class="entry"><span class="def">extinction,</span> <span class="pos">n.</span> The raw material out of which
+theology created the future state.</p>
+
+
+</body>
+
+</html>
--- /dev/null
+++ b/lib/ebooks/devils/E.html.i
@@ -1,0 +1,31 @@
+14 pages
+size 400 552
+length 26246
+397 2 11 body html
+0
+2053 2 56 body html
+0
+3718 2 81 body html
+0
+5641 2 133 body html
+0
+7742 2 182 body html
+51
+10267 2 247 body html
+39
+12629 2 305 body html
+0
+14666 2 344 body html
+118
+16609 2 408 body html
+22
+18788 2 443 body html
+56
+20989 2 501 body html
+0
+21978 2 528 body html
+284
+21978 2 528 body html
+823
+25433 2 603 body html
+0
--- /dev/null
+++ b/lib/ebooks/devils/F.html
@@ -1,0 +1,578 @@
+<?xml version="1.0"?>
+<!DOCTYPE package PUBLIC "+//ISBN 0-9673008-1-9//DTD OEB 1.0 Package//EN"
+ "http://openebook.org/dtds/oeb-1.0/oebdoc1.dtd">
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/x-oeb1-document; charset=utf-8" />
+<link rel="stylesheet" type="text/css" href="devil.css" />
+<title>The Devil’s Dictionary: F</title>
+</head>
+
+<body lang="en-US">
+
+<h1>F</h1>
+
+<p class="entry"><span class="def">fairy,</span> <span class="pos"> n.</span> A creature, variously fashioned and endowed,
+that formerly inhabited the meadows and forests. It was nocturnal in its habits,
+and somewhat addicted to dancing and the theft of children. The fairies
+are now believed by naturalist to be extinct, though a clergyman of the Church
+of England saw three near Colchester as lately as 1855, while passing through a
+park after dining with the lord of the manor.
+The sight greatly staggered him, and he was so affected that his account
+of it was incoherent. In the year 1807
+a troop of fairies visited a wood near Aix and carried off the daughter of a
+peasant, who had been seen to enter it with a bundle of clothing. The son of a wealthy
+<i>bourgeois</i> disappeared about the same time,
+but afterward returned. He had seen the
+abduction been in pursuit of the fairies.
+Justinian Gaux, a writer of the fourteenth century, avers that so great
+is the fairies’ power of transformation that he saw one change itself into two
+opposing armies and fight a battle with great slaughter, and that the next day,
+after it had resumed its original shape and gone away, there were seven hundred
+bodies of the slain which the villagers had to bury. He does not say if any of the
+wounded recovered. In the time of Henry III, of England, a law
+was made which prescribed the death penalty for “Kyllynge, wowndynge, or
+mamynge” a fairy, and it was universally respected.</p>
+
+<p class="entry"><span class="def">faith,</span> <span class="pos"> n.</span> Belief without evidence in what is told by
+one who speaks without knowledge, of things without parallel.</p>
+
+<p id="famous" class="entry"><span class="def">famous,</span> <span class="pos">adj.</span> Conspicuously miserable.</p>
+
+ <table align="center" border="0">
+ <tr>
+ <td valign="top" align="left">
+
+<p class="poetry">Done to a turn on
+the iron, behold<br />
+Him who to be
+famous aspired.<br />
+Content? Well, his grill has a plating of gold,<br />
+And his twistings
+are greatly admired.</p>
+
+<p class="citeauth">Hassan Brubuddy.</p>
+
+ </td>
+ </tr>
+ </table>
+
+<p class="entry"> </p>
+
+<p class="entry"><span class="def">fashion,</span> <span class="pos"> n.</span> A despot whom the wise ridicule and obey.</p>
+
+ <table align="center" border="0">
+ <tr>
+ <td valign="top" align="left">
+
+<p class="poetry">A king there was
+who lost an eye<br />
+In some excess of
+passion;<br />
+And straight his
+courtiers all did try<br />
+To follow the new
+fashion.<br />
+Each dropped one
+eyelid when before<br />
+The throne he
+ventured, thinking<br />
+‘Twould please the
+king. That monarch swore<br />
+He’d slay them all
+for winking.<br />
+What should they
+do? They were not hot<br />
+To hazard such
+disaster;<br />
+They dared not
+close an eye—dared not<br />
+See better than
+their master.<br />
+Seeing them
+lacrymose and glum,<br />
+A leech consoled
+the weepers:<br />
+He spread small
+rags with liquid gum<br />
+And covered half
+their peepers.<br />
+The court all wore
+the stuff, the flame<br />
+Of royal anger
+dying.<br />
+That’s how
+court-plaster got its name<br />
+Unless I’m greatly
+lying.</p>
+
+<p class="citeauth">Naramy Oof.</p>
+
+ </td>
+ </tr>
+ </table>
+
+<p class="entry"><span class="def">feast,</span> <span class="pos"> n.</span> A festival.
+A religious celebration usually signalized by gluttony and drunkenness, frequently
+in honor of some holy person distinguished for abstemiousness. In the Roman Catholic
+Church feasts are
+“movable” and “immovable,” but the celebrants are uniformly immovable until
+they are full. In their earliest
+development these entertainments took the form of feasts for the dead; such
+were held by the Greeks, under the name <i>Nemeseia</i>,
+by the Aztecs and Peruvians, as in modern times they are popular with the
+Chinese; though it is believed that the ancient dead, like the modern, were
+light eaters. Among the many feasts of
+the Romans was the <i>Novemdiale</i>,
+which was held, according to Livy, whenever stones fell from heaven.</p>
+
+<p class="entry"><span class="def">felon,</span> <span class="pos"> n.</span> A person of greater enterprise than
+discretion, who in embracing an opportunity has formed an unfortunate
+attachment.</p>
+
+<p class="entry"><span class="def">female,</span> <span class="pos"> n.</span> One of the opposing, or unfair, sex.</p>
+
+ <table align="center" border="0">
+ <tr>
+ <td valign="top" align="left">
+
+<p class="poetry">The Maker, at Creation’s birth,<br />
+With living things had stocked the
+earth.<br />
+From elephants to bats and snails,<br />
+They all were good, for all were
+males.<br />
+But when the Devil came and saw<br />
+He said: “By Thine eternal law<br />
+Of growth, maturity, decay,<br />
+These all must quickly pass away<br />
+And leave untenanted the earth<br />
+Unless Thou dost establish birth”—<br />
+Then tucked his head beneath his
+wing<br />
+To laugh—he had no sleeve—the thing<br />
+With deviltry did so accord,<br />
+That he’d suggested to the Lord.<br />
+The Master pondered this advice,<br />
+Then shook and threw the fateful
+dice<br />
+Wherewith all matters here below<br />
+Are ordered, and observed the
+throw;<br />
+Then bent His head in awful state,<br />
+Confirming the decree of Fate.<br />
+From every part of earth anew<br />
+The conscious dust consenting flew,<br />
+While rivers from their courses rolled<br />
+To make it plastic for the mould.<br />
+Enough collected (but no more,<br />
+For niggard Nature hoards her store)<br />
+He kneaded it to flexible clay,<br />
+While Nick unseen threw some away.<br />
+And then the various forms He cast,<br />
+Gross organs first and finer last;<br />
+No one at once evolved, but all<br />
+By even touches grew and small<br />
+Degrees advanced, till, shade by shade,<br />
+To match all living things He’d made<br />
+Females, complete in all their parts<br />
+Except (His clay gave out) thec hearts.<br />
+“No matter,” Satan cried; “with speed<br />
+I’ll fetch the very hearts they need”—<br />
+So flew away and soon brought back<br />
+The number needed, in a sack.<br />
+That night earth range with sounds of strife—<br />
+Ten million males each had a wife;<br />
+That night sweet Peace her pinions spread<br />
+O’er Hell—ten million devils dead!</p>
+
+<p class="citeauth">G. J.</p>
+
+
+
+ </td>
+ </tr>
+ </table>
+
+
+
+<p class="entry"><span class="def">fib,</span> <span class="pos"> n.</span> A lie that has not cut its teeth. An habitual liar’s
+nearest approach to truth: the perigee of his eccentric orbit.</p>
+
+ <table align="center" border="0">
+ <tr>
+ <td valign="top" align="left">
+
+<p class="poetry">When David said: “All men are liars,” Dave,<br />
+Himself a liar, fibbed like any thief.<br />
+Perhaps he thought to weaken disbelief<br />
+By proof that even himself was not a slave<br />
+To Truth; though I suspect the aged knave<br />
+Had been of all her servitors the chief<br />
+Had he but known a fig’s reluctant leaf<br />
+Is more than e’er she wore on land or wave.<br />
+No, David served not Naked Truth when he<br />
+Struck that sledge-hammer blow at all his race;<br />
+Nor did he hit the nail upon the head:<br />
+For reason shows that it could never be,<br />
+And the facts contradict him to his face.<br />
+Men are not liars all, for some are dead.</p>
+
+<p class="citeauth">Bartle Quinker.</p>
+
+ </td>
+ </tr>
+ </table>
+
+<p class="entry"><span class="def">fickleness,</span> <span class="pos"> n.</span> The iterated satiety of an
+enterprising affection.</p>
+
+<p class="entry"><span class="def">fiddle,</span> <span class="pos"> n.</span> An instrument to tickle human ears by
+friction of a horse’s tail on the entrails of a cat.</p>
+
+<p class="quote">To Rome said
+Nero: “If to smoke you turn I shall not
+cease to fiddle while you burn.” To Nero Rome replied: “Pray do your worst,
+‘Tis my excuse that you were fiddling first.”—<i>Orm Pludge</i></p>
+
+<p class="entry"><span class="def">fidelity,</span> <span class="pos"> n.</span> A virtue peculiar to those who are about to
+be betrayed.</p>
+
+<p class="entry"><span class="def">finance,</span> <span class="pos"> n.</span> The art or science of managing revenues and resources
+for the best advantage of the manager.
+The pronunciation of this word with the i long and the accent on the
+first syllable is one of America’s most precious discoveries and possessions.</p>
+
+<p class="entry"><span class="def">flag,</span> <span class="pos"> n.</span> A colored rag borne above troops and hoisted
+on forts and ships. It appears to serve
+the same purpose as certain signs that one sees and vacant lots in
+London—“Rubbish may be shot here.”</p>
+
+<p class="entry"><span class="def">flesh,</span> <span class="pos"> n.</span> The Second Person of the secular Trinity.</p>
+
+<p class="entry"><span class="def">flop,</span> <span class="pos"> v.</span> Suddenly to change one’s opinions and go
+over to another party. The most notable
+flop on record was that of Saul of Tarsus, who has been severely criticised as
+a turn-coat by some of our partisan journals.</p>
+
+<p class="entry"><span class="def">fly-speck,</span> <span class="pos"> n.</span> The prototype of punctuation. It is observed by
+Garvinus that the systems
+of punctuation in use by the various literary nations depended originally upon
+the social habits and general diet of the flies infesting the several
+countries. These creatures, which have
+always been distinguished for a neighborly and companionable familiarity with
+authors, liberally or niggardly embellish the manuscripts in process of growth
+under the pen, according to their bodily habit, bringing out the sense of the
+work by a species of interpretation superior to, and independent of, the
+writer’s powers. The “old masters” of
+literature—that is to say, the early writers whose work is so esteemed by later
+scribes and critics in the same language—never punctuated at all, but worked
+right along free-handed, without that abruption of the thought which comes from
+the use of points. (We observe the same
+thing in children to-day, whose usage in this particular is a striking and
+beautiful instance of the law that the infancy of individuals reproduces the
+methods and stages of development characterizing the infancy of races.)
+In the work of these primitive scribes all
+the punctuation is found, by the modern investigator with his optical
+instruments and chemical tests, to have been inserted by the writers’ ingenious
+and serviceable collaborator, the common house-fly—<i>Musca maledicta</i>.
+In transcribing these ancient MSS, for the purpose of either
+making the work their own or preserving what they naturally regard as divine
+revelations, later writers reverently and accurately copy whatever marks they
+find upon the papyrus or parchment, to the unspeakable enhancement of the
+lucidity of the thought and value of the work.
+Writers contemporary with the copyists naturally avail themselves of the
+obvious advantages of these marks in their own work, and with such assistance
+as the flies of their own household may be willing to grant, frequently rival
+and sometimes surpass the older compositions, in respect at least of
+punctuation, which is no small glory.
+Fully to understand the important services that flies perform to
+literature it is only necessary to lay a page of some popular novelist
+alongside a saucer of cream-and-molasses in a sunny room and observe “how the
+wit brightens and the style refines” in accurate proportion to the duration of
+exposure.</p>
+
+<p class="entry"><span class="def">folly,</span> <span class="pos"> n.</span> That “gift and faculty divine” whose
+creative and controlling energy inspires Man’s mind, guides his actions and
+adorns his life.</p>
+
+ <table align="center" border="0">
+ <tr>
+ <td valign="top" align="left">
+
+<p class="poetry">Folly! although Erasmus praised thee once<br />
+In a thick volume, and all authors known,<br />
+If not thy glory yet thy power have shown,<br />
+Deign to take homage from thy son who hunts<br />
+Through all thy maze his brothers, fool and dunce,<br />
+To mend their lives and to sustain his own,<br />
+However feebly be his arrows thrown,<br />
+Howe’er each hide the flying weapons blunts.<br />
+All-Father Folly! be it mine to raise,<br />
+With lusty lung, here on his western strand<br />
+With all thine offspring thronged from every land,<br />
+Thyself inspiring me, the song of praise.<br />
+And if too weak, I’ll hire, to help me bawl,<br />
+Dick Watson Gilder, gravest of us all.</p>
+
+<p class="citeauth">Aramis Loto Frope.</p>
+
+ </td>
+ </tr>
+ </table>
+
+<p id="fool" class="entry"><span class="def">fool,</span> <span class="pos"> n.</span> A person who pervades the domain of
+intellectual speculation and diffuses himself through the channels of moral
+activity. He is omnific, omniform,
+omnipercipient, omniscience, omnipotent.
+He it was who invented letters, printing, the railroad, the steamboat,
+the telegraph, the platitude and the circle of the sciences. He created
+patriotism and taught the nations
+war—founded theology, philosophy, law, medicine and Chicago. He established
+monarchical and republican
+government. He is from everlasting to
+everlasting—such as creation’s dawn beheld he fooleth now. In the morning
+of time he sang upon
+primitive hills, and in the noonday of existence headed the procession of
+being. His grandmotherly hand was
+warmly tucked-in the set sun of civilization, and in the twilight he prepares
+Man’s evening meal of milk-and-morality and turns down the covers of the
+universal grave. And after the rest of
+us shall have retired for the night of eternal oblivion he will sit up to write
+a history of human civilization.</p>
+
+<p class="entry"><span class="def">force,</span> <span class="pos"> n.</span></p>
+
+ <table align="center" border="0">
+ <tr>
+ <td valign="top" align="left">
+
+<p class="poetry">“Force is but might,” the teacher said—<br />
+“That definition’s just.”<br />
+The boy said naught but through instead,<br />
+Remembering his pounded head:<br />
+“Force is not might but must!”</p>
+
+ </td>
+ </tr>
+ </table>
+
+<p class="entry"><span class="def">forefinger,</span> <span class="pos"> n.</span> The finger commonly used in pointing out two malefactors.</p>
+
+<p class="entry"><span class="def">foreordination,</span> <span class="pos"> n.</span> This looks like an easy word to
+define, but when I consider that pious and learned theologians have spent long
+lives in explaining it, and written libraries to explain their explanations;
+when I remember the nations have been divided and bloody battles caused by the
+difference between foreordination and predestination, and that millions of
+treasure have been expended in the effort to prove and disprove its
+compatibility with freedom of the will and the efficacy of prayer, praise, and
+a religious life,𔃐recalling these awful facts in the history of the word, I
+stand appalled before the mighty problem of its signification, abase my
+spiritual eyes, fearing to contemplate its portentous magnitude, reverently
+uncover and humbly refer it to His Eminence Cardinal Gibbons and His Grace
+Bishop Potter.</p>
+
+<p class="entry"><span class="def">forgetfulness,</span> <span class="pos"> n.</span> A gift of God bestowed upon doctors
+in compensation for their destitution of conscience.</p>
+
+<p class="entry"><span class="def">fork,</span> <span class="pos"> n.</span> An instrument used chiefly for the purpose
+of putting dead animals into the mouth.
+Formerly the knife was employed for this purpose, and by many worthy
+persons is still thought to have many advantages over the other tool, which,
+however, they do not altogether reject, but use to assist in charging the
+knife. The immunity of these persons
+from swift and awful death is one of the most striking proofs of God’s mercy to
+those that hate Him.</p>
+
+<p class="entry"><span class="def">forma pauperis.</span> <span class="pos"> [Latin]</span> In the character of a poor person—a method
+by which a litigant without money for lawyers is considerately permitted to
+lose his case.</p>
+
+ <table align="center" border="0">
+ <tr>
+ <td valign="top" align="left">
+
+<p class="poetry">When Adam long ago in Cupid’s awful court<br />
+(For Cupid ruled ere Adam was invented)<br />
+Sued for Eve’s favor, says an ancient law report,<br />
+He stood and pleaded unhabilimented.<br />
+“You sue <i>in forma pauperis</i>, I see,” Eve cried;<br />
+“Actions can’t here be that way prosecuted.”<br />
+So all poor Adam’s motions coldly were denied:<br />
+He went away—as he had come—nonsuited.</p>
+
+<p class="citeauth">G. J.</p>
+
+ </td>
+ </tr>
+ </table>
+
+<p class="entry"><span class="def">Frankalmoigne,</span> <span class="pos"> n.</span> The tenure by which a religious
+corporation holds lands on condition of praying for the soul of the donor.
+In mediaeval times many of the wealthiest
+fraternities obtained their estates in this simple and cheap manner, and once
+when Henry VIII of England sent an officer to confiscate certain vast
+possessions which a fraternity of monks held by frankalmoigne, “What!” said the
+Prior, “would you master stay our benefactor’s soul in Purgatory?” “Ay,”
+said the officer, coldly, “an ye will
+not pray him thence for naught he must e’en roast.” “But look you, my son,”
+persisted the good man, “this act hath
+rank as robbery of God!” “Nay, nay,
+good father, my master the king doth but deliver him from the manifold
+temptations of too great wealth.”</p>
+
+<p class="entry"><span class="def">freebooter,</span> <span class="pos"> n.</span> A conqueror in a small way of
+business, whose annexations lack of the sanctifying merit of magnitude.</p>
+
+<p class="entry"><span class="def">freedom,</span> <span class="pos"> n.</span> Exemption from the stress of authority in a
+beggarly half dozen of restraint’s infinite multitude of methods. A political
+condition that every nation
+supposes itself to enjoy in virtual monopoly.
+Liberty. The distinction between
+freedom and liberty is not accurately known; naturalists have never been able
+to find a living specimen of either.</p>
+
+ <table align="center" border="0">
+ <tr>
+ <td valign="top" align="left">
+
+<p class="poetry">Freedom, as every schoolboy knows,<br />
+Once shrieked as Kosciusko fell;<br />
+On every wind, indeed, that blows<br />
+I hear her yell.<br />
+She screams whenever monarchs meet,<br />
+And parliaments as well,<br />
+To bind the chains about her feet<br />
+And toll her knell.<br />
+And when the sovereign people cast<br />
+The votes they cannot spell,<br />
+Upon the pestilential blast<br />
+Her clamors swell.<br />
+For all to whom the power’s given<br />
+To sway or to compel,<br />
+Among themselves apportion Heaven<br />
+And give her Hell.</p>
+
+<p class="citeauth">Blary O’Gary.</p>
+
+ </td>
+ </tr>
+ </table>
+
+<p class="entry"><span class="def">Freemasons,</span> <span class="pos"> n.</span> An order with secret rites,
+grotesque ceremonies and fantastic costumes, which, originating in the reign of
+Charles II, among working artisans of London, has been joined successively by
+the dead of past centuries in unbroken retrogression until now it embraces all
+the generations of man on the hither side of Adam and is drumming up
+distinguished recruits among the pre-Creational inhabitants of Chaos and
+Formless Void. The order was founded at
+different times by Charlemagne, Julius Caesar, Cyrus, Solomon, Zoroaster,
+Confucious, Thothmes, and Buddha. Its
+emblems and symbols have been found in the Catacombs of Paris and Rome, on the
+stones of the Parthenon and the Chinese Great Wall, among the temples of Karnak
+and Palmyra and in the Egyptian Pyramids—always by a Freemason.</p>
+
+<p class="entry"><span class="def">friendless,</span> <span class="pos"> adj.</span> Having no favors to bestow. Destitute of fortune.
+Addicted to utterance of truth and common sense. </p>
+
+<p class="entry"><span class="def">friendship,</span> <span class="pos"> n.</span> A ship big enough to carry two in fair weather, but only one in foul.</p>
+
+ <table align="center" border="0">
+ <tr>
+ <td valign="top" align="left">
+
+<p class="poetry">The sea was calm and the sky was blue;<br />
+Merrily, merrily sailed we two.<br />
+(High barometer maketh glad.)<br />
+On the tipsy ship, with a dreadful shout,<br />
+The tempest descended and we fell out.<br />
+(O the walking is nasty bad!)</p>
+
+<p class="citeauth">Armit Huff Bettle.</p>
+
+ </td>
+ </tr>
+ </table>
+
+<p class="entry"><span class="def">frog,</span> <span class="pos"> n.</span> A reptile with edible legs. The first mention of frogs in profane
+literature is in Homer’s narrative of the war between them and the mice.
+Skeptical persons have doubted Homer’s
+authorship of the work, but the learned, ingenious and industrious Dr. Schliemann
+has set the question forever at rest by uncovering the bones of the slain
+frogs. One of the forms of moral
+suasion by which Pharaoh was besought to favor the Israelities was a plague of
+frogs, but Pharaoh, who liked them <i>fricasees</i>,
+remarked, with truly oriental stoicism, that he could stand it as long as the
+frogs and the Jews could; so the programme was changed. The frog is a
+diligent songster, having a
+good voice but no ear. The libretto of
+his favorite opera, as written by Aristophanes, is brief, simple and
+effective—“brekekex-koax”; the music is apparently by that eminent composer,
+Richard Wagner. Horses have a frog in
+each hoof—a thoughtful provision of nature, enabling them to shine in a hurdle
+race.</p>
+
+<p class="entry"><span class="def">frying-pan,</span> <span class="pos"> n.</span> One part of the penal apparatus
+employed in that punitive institution, a woman’s kitchen. The frying-pan was
+invented by Calvin, and
+by him used in cooking span-long infants that had died without baptism; and
+observing one day the horrible torment of a tramp who had incautiously pulled a
+fried babe from the waste-dump and devoured it, it occurred to the great divine
+to rob death of its terrors by introducing the frying-pan into every household
+in Geneva. Thence it spread to all
+corners of the world, and has been of invaluable assistance in the propagation
+of his sombre faith. The following
+lines (said to be from the pen of his Grace Bishop Potter) seem to imply that
+the usefulness of this utensil is not limited to this world; but as the
+consequences of its employment in this life reach over into the life to come,
+so also itself may be found on the other side, rewarding its devotees:</p>
+
+ <table align="center" border="0">
+ <tr>
+ <td valign="top" align="left">
+
+<p class="poetry">Old Nick was summoned to the skies.<br />
+Said Peter: “Your intentions<br />
+Are good, but you lack enterprise<br />
+Concerning new inventions.<br />
+“Now, broiling in an ancient plan<br />
+Of torment, but I hear it<br />
+Reported that the frying-pan<br />
+Sears best the wicked spirit.<br />
+“Go get one—fill it up with fat—<br />
+Fry sinners brown and good in’t.”<br />
+“I know a trick worth two o’ that,”<br />
+Said Nick—“I’ll cook their food in’t.”</p>
+
+<p class="citeauth"> </p>
+
+ </td>
+ </tr>
+ </table>
+
+<p id="funeral" class="entry"><span class="def">funeral,</span> <span class="pos"> n.</span> A pageant whereby we attest our respect for
+the dead by enriching the undertaker, and strengthen our grief by an
+expenditure that deepens our groans and doubles our tears.</p>
+
+ <table align="center" border="0">
+ <tr>
+ <td valign="top" align="left">
+
+<p class="poetry">The savage dies—they sacrifice a horse<br />
+To bear to happy hunting-grounds the corse.<br />
+Our friends expire—we make the money fly<br />
+In
+hope their souls will chase it to the sky.</p>
+
+<p class="citeauth">Jex Wopley.</p>
+
+ </td>
+ </tr>
+ </table>
+
+<p class="entry"><span class="def">future,</span> <span class="pos"> n.</span> That period of time in which our affairs
+prosper, our friends are true and our happiness is assured.</p>
+
+</body>
+
+</html>
\ No newline at end of file
--- /dev/null
+++ b/lib/ebooks/devils/F.html.i
@@ -1,0 +1,34 @@
+14 pages
+size 400 552
+length 25380
+390 2 11 body html
+0
+2225 2 42 body html
+0
+3791 2 115 body html
+39
+4962 2 135 body html
+0
+4962 2 135 body html
+552
+8145 2 227 body html
+0
+9883 2 258 body html
+141
+12382 2 295 body html
+22
+13518 2 324 body html
+243
+16357 2 378 body html
+39
+18626 2 424 body html
+0
+20026 2 462 body html
+90
+21721 2 497 body html
+175
+23819 2 530 body html
+0
+famous 0
+funeral 12
+fool 7
--- /dev/null
+++ b/lib/ebooks/devils/G.html
@@ -1,0 +1,313 @@
+<?xml version="1.0"?>
+<!DOCTYPE package PUBLIC "+//ISBN 0-9673008-1-9//DTD OEB 1.0 Package//EN"
+ "http://openebook.org/dtds/oeb-1.0/oebdoc1.dtd">
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/x-oeb1-document; charset=utf-8" />
+<link rel="stylesheet" type="text/x-oeb1-css" href="devil.css" />
+<title>The Devil’s Dictionary: D</title>
+</head>
+<body lang="en-US">
+
+<h1>G</h1>
+
+
+<p class="entry"><span class="def">gallows</span>, <span class="pos">n.</span> A stage for the performance of miracle plays, in which the leading actor is
+translated to heaven. In this country the gallows is chiefly remarkable for the
+number of persons who escape it.</p>
+
+<div class="poem">
+<p class="poetry">Whether on the gallows high</p>
+<p class="poetry">Or where blood flows the reddest, The noblest place for man to die—</p>
+<p class="poetry">Is where he died the deadest.</p>
+<p class="citeauth">(Old play)</p>
+</div>
+
+<p class="entry"><span class="def">gargoyle</span>, <span class="pos">n.</span> A rain-pout projecting from the eaves of mediaeval buildings, commonly fashioned
+into a grotesque caricature of some personal enemy of the architect or owner of
+the building. This was especially the case in churches and ecclesiastical
+structures generally, in which the gargoyles presented a perfect rogues’
+gallery of local heretics and controversialists. Sometimes when a new dean and
+chapter were installed the old gargoyles were removed and others substituted
+having a closer relation to the private animosities of the new incumbents.</p>
+
+<p class="entry"><span class="def">garther</span>, <span class="pos">n.</span> An elastic band intended to keep a woman from coming out of her stockings and
+desolating the country.</p>
+
+<p class="entry"><span class="def">generous</span>, <span class="pos">adj.</span> Originally this word meant noble by birth and was rightly applied to a great multitude of
+persons. It now means noble by nature and is taking a bit of a rest.</p>
+
+<p class="entry"><span class="def">genealogy</span>, <span class="pos">n.</span> An account of one’s descent from an ancestor who did not particularly care to trace his own.</p>
+
+<p class="entry"><span class="def">genteel</span>, <span class="pos">adj.</span> Refined, after the fashion of a gent.</p>
+
+<div class="poem">
+<p class="poetry">Observe with care, my son, the distinction I reveal:</p>
+<p class="poetry">A gentleman is gentle and a gent genteel.</p>
+<p class="poetry">Heed not the definitions your “Unabridged” presents,</p>
+<p class="poetry">For dictionary makers are generally gents.</p>
+<p class="citeauth">G. J.</p>
+</div>
+
+<p class="entry"><span class="def">geographer</span>, <span class="pos">n.</span> A chap who can tell you offhand the difference between the outside of the world and the inside.</p>
+
+<div class="poem">
+<p class="poetry">Habeam, geographer of wide reknown,</p>
+<p class="poetry">Native of Abu-Keber’s ancient town,</p>
+<p class="poetry">In passing thence along the river Zam</p>
+<p class="poetry">To the adjacent village of Xelam,</p>
+<p class="poetry">Bewildered by the multitude of roads,</p>
+<p class="poetry">Got lost, lived long on migratory toads,</p>
+<p class="poetry">Then from exposure miserably died,</p>
+<p class="poetry">And grateful travelers bewailed their guide.</p>
+<p class="citeauth">Henry Haukhorn</p>
+</div>
+
+<p class="entry"><span class="def">geology</span>, <span class="pos">n.</span> The science of the earth’s crust—to which, doubtless, will be added that of its
+interior whenever a man shall come up garrulous out of a well. The geological
+formations of the globe already noted are catalogued thus: The Primary, or
+lower one, consists of rocks, bones or mired mules, gas-pipes, miners’ tools,
+antique statues minus the nose, Spanish doubloons and ancestors. The Secondary
+is largely made up of red worms and moles. The Tertiary comprises railway
+tracks, patent pavements, grass, snakes, mouldy boots, beer bottles, tomato
+cans, intoxicated citizens, garbage, anarchists, snap-dogs and fools.</p>
+
+<p class="entry"><span class="def">ghost</span>, <span class="pos">n.</span> The outward and visible sign of an inward fear.</p>
+
+<div class="poem">
+<p class="poetry">He saw a ghost.</p>
+<p class="poetry">It occupied—that dismal thing!—</p>
+<p class="poetry">The path that he was following.</p>
+<p class="poetry">Before he’d time to stop and fly,</p>
+<p class="poetry">An earthquake trifled with the eye</p>
+<p class="poetry">That saw a ghost.</p>
+<p class="poetry">He fell as fall the early good;</p>
+<p class="poetry">Unmoved that awful vision stood.</p>
+<p class="poetry">The stars that danced before his ken</p>
+<p class="poetry">He wildly brushed away, and then</p>
+<p class="poetry">He saw a post.</p>
+<p class="citeauth">Jared Macphester</p>
+</div>
+
+<p class="indentpara">Accounting for the uncommon behavior of ghosts, Heine mentions somebody’s ingenious theory to the
+effect that they are as much afraid of us as we of them. Not quite, if I may
+judge from such tables of comparative speed as I am able to compile from
+memories of my own experience.</p>
+
+<p class="indentpara">There is one insuperable obstacle to a belief in ghosts. A ghost never comes naked: he
+appears either in a winding-sheet or “in his habit as he lived.” To believe in
+him, then, is to believe that not only have the dead the power to make
+themselves visible after there is nothing left of them, but that the same power
+inheres in textile fabrics. Supposing the products of the loom to have this
+ability, what object would they have in exercising it? And why does not the
+apparition of a suit of clothes sometimes walk abroad without a ghost in it? These
+be riddles of significance. They reach away down and get a convulsive grip on
+the very tap-root of this flourishing faith.</p>
+
+<p class="entry"><span class="def">ghoul</span>, <span class="pos">n.</span> A demon addicted to the reprehensible habit of devouring the dead. The existence of
+ghouls has been disputed by that class of controversialists who are more
+concerned to deprive the world of comforting beliefs than to give it anything
+good in their place. In 1640 Father Secchi saw one in a cemetery near Florence
+and frightened it away with the sign of the cross. He describes it as gifted
+with many heads an an uncommon allowance of limbs, and he saw it in more than
+one place at a time. The good man was coming away from dinner at the time and
+explains that if he had not been “heavy with eating” he would have seized the
+demon at all hazards. Atholston relates that a ghoul was caught by some sturdy
+peasants in a churchyard at Sudbury and ducked in a horsepond. (He appears to
+think that so distinguished a criminal should have been ducked in a tank of
+rosewater.) The water turned at once to blood “and so contynues unto ys daye.” The
+pond has since been bled with a ditch. As late as the beginning of the
+fourteenth century a ghoul was cornered in the crypt of the cathedral at Amiens
+and the whole population surrounded the place. Twenty armed men with a priest
+at their head, bearing a crucifix, entered and captured the ghoul, which,
+thinking to escape by the stratagem, had transformed itself to the semblance of
+a well known citizen, but was nevertheless hanged, drawn and quartered in the
+midst of hideous popular orgies. The citizen whose shape the demon had assumed
+was so affected by the sinister occurrence that he never again showed himself
+in Amiens and his fate remains a mystery.</p>
+
+<p class="entry"><span class="def">glutton</span>, <span class="pos">n.</span> A person who escapes the evils of moderation by committing dyspepsia.</p>
+
+<p class="entry"><span class="def">gnome</span>, <span class="pos">n.</span> In North-European mythology, a dwarfish imp inhabiting the interior parts of the
+earth and having special custody of mineral treasures. Bjorsen, who died in
+1765, says gnomes were common enough in the southern parts of Sweden in his
+boyhood, and he frequently saw them scampering on the hills in the evening
+twilight. Ludwig Binkerhoof saw three as recently as 1792, in the Black Forest,
+and Sneddeker avers that in 1803 they drove a party of miners out of a Silesian
+mine. Basing our computations upon data supplied by these statements, we find
+that the gnomes were probably extinct as early as 1764.</p>
+
+<p class="entry"><span class="def">gnostics</span>, <span class="pos">n.</span> A sect of philosophers who tried to engineer a fusion between the early
+Christians and the Platonists. The former would not go into the caucus and the
+combination failed, greatly to the chagrin of the fusion managers.</p>
+
+<p class="entry"><span class="def">gnu</span>, <span class="pos">n.</span> An animal of South Africa, which in its domesticated state resembles a horse, a buffalo
+and a stag. In its wild condition it is something like a thunderbolt, an
+earthquake and a cyclone.</p>
+
+<div class="poem">
+<p class="poetry">A hunter from Kew caught a distant view</p>
+<p class="poetry">Of a peacefully meditative gnu,</p>
+<p class="poetry">And he said: “I’ll pursue, and my hands imbrue</p>
+<p class="poetry">In its blood at a closer interview.”</p>
+<p class="poetry">But that beast did ensue and the hunter it threw</p>
+<p class="poetry">O’er the top of a palm that adjacent grew;</p>
+<p class="poetry">And he said as he flew: “It is well I withdrew</p>
+<p class="poetry">Ere, losing my temper, I wickedly slew That really meritorious gnu.”</p>
+<p class="citeauth">Jarn Leffer</p>
+</div>
+
+<p class="entry"><span class="def">good</span>, <span class="pos">adj.</span> Sensible, madam,
+to the worth of this present writer.</p>
+
+<p>Alive, sir, to the advantages of letting him alone.</p>
+
+<p class="entry"><span class="def">goose</span>, <span class="pos">n.</span> A bird that supplies quills for writing. These, by some occult process of nature, are
+penetrated and suffused with various degrees of the bird’s intellectual
+energies and emotional character, so that when inked and drawn mechanically
+across paper by a person called an “author,” there results a very fair and
+accurate transcript of the fowl’s thought and feeling. The difference in geese,
+as discovered by this ingenious method, is considerable: many are found to have
+only trivial and insignificant powers, but some are seen to be very great geese
+indeed.</p>
+
+<p class="entry"><span class="def">gorgon</span>, <span class="pos">n.</span></p>
+
+<div class="poem">
+<p class="poetry">The Gorgon was a maiden bold</p>
+<p class="poetry">Who turned to stone the Greeks of old</p>
+<p class="poetry">That looked upon her awful brow.</p>
+<p class="poetry">We dig them out of ruins now,</p>
+<p class="poetry">And swear that workmanship so bad</p>
+<p class="poetry">Proves all the ancient sculptors mad.</p>
+</div>
+<p class="entry"><span class="def">gout</span>, <span class="pos">n.</span> A physician’s name for the rheumatism of a rich patient.</p>
+
+<p class="entry"><span class="def">graces</span>, <span class="pos">n.</span> Three beautiful goddesses, Aglaia, Thalia and Euphrosyne, who attended upon Venus,
+serving without salary. They were at no expense for board and clothing, for
+they ate nothing to speak of and dressed according to the weather, wearing
+whatever breeze happened to be blowing.</p>
+
+<p class="entry"><span class="def">grammar</span>, <span class="pos">n.</span> A system of pitfalls thoughtfully prepared for the feet for the self-made man,
+along the path by which he advances to distinction.</p>
+
+<p class="entry"><span class="def">grape</span>, <span class="pos">n.</span></p>
+
+<div class="poem">
+<p class="poetry">Hail noble fruit!—by Homer sung,</p>
+<p class="poetry">Anacreon and Khayyam;</p>
+<p class="poetry">Thy praise is ever on the tongue</p>
+<p class="poetry">Of better men than I am.</p>
+<p class="poetry">The lyre in my hand has never swept,</p>
+<p class="poetry">The song I cannot offer:</p>
+<p class="poetry">My humbler service pray accept—</p>
+<p class="poetry">I’ll help to kill the scoffer.</p>
+<p class="poetry">The water-drinkers and the cranks</p>
+<p class="poetry">Who load their skins with liquor—</p>
+<p class="poetry">I’ll gladly bear their belly-tanks</p>
+<p class="poetry">And tap them with my sticker.</p>
+<p class="poetry">Fill up, fill up, for wisdom cools</p>
+<p class="poetry">When e’er we let the wine rest.</p>
+<p class="poetry">Here’s death to Prohibition’s fools,</p>
+<p class="poetry">And every kind of vine-pest!</p>
+<p class="citeauth">Jamrach Holobom</p>
+</div>
+
+<p class="entry"><span class="def">grapeshot</span>, <span class="pos">n.</span> An argument which the future is preparing in answer to the demands of American Socialism.</p>
+
+<p class="entry"><span class="def">grave</span>, <span class="pos">n.</span> A place in which the dead are laid to await the coming of the medical student.</p>
+
+<div class="poem">
+<p class="poetry">Beside a lonely grave I stood—</p>
+<p class="poetry">With brambles ‘twas encumbered;</p>
+<p class="poetry">The winds were moaning in the wood,</p>
+<p class="poetry">Unheard by him who slumbered,</p>
+<p class="poetry">A rustic standing near, I said:</p>
+<p class="poetry">“He cannot hear it blowing!”</p>
+<p class="poetry">“’Course not,” said he: “the feller’s dead—</p>
+<p class="poetry">He can’t hear nowt [sic] that’s going.”</p>
+<p class="poetry">“Too true,” I said; “alas, too true—</p>
+<p class="poetry">No sound his sense can quicken!”</p>
+<p class="poetry">“Well, mister, wot is that to you?—</p>
+<p class="poetry">The deadster ain’t a-kickin’.”</p>
+<p class="poetry">I knelt and prayed: “O Father, smile</p>
+<p class="poetry">On him, and mercy show him!”</p>
+<p class="poetry">That countryman looked on the while,</p>
+<p class="poetry">And said: “Ye didn’t know him.”</p>
+<p class="citeauth">Pobeter Dunko</p>
+</div>
+
+<p class="entry"><span class="def">gravitation</span>, <span class="pos">n.</span> The tendency of all bodies to approach one another with a strength proportion to
+the quantity of matter they contain—the quantity of matter they contain being
+ascertained by the strength of their tendency to approach one another. This is
+a lovely and edifying illustration of how science, having made A the proof of
+B, makes B the proof of A.</p>
+
+<p class="entry"><span class="def">great</span>, <span class="pos">adj.</span></p>
+
+<div class="poem">
+<p class="poetry">“I’m great,” the Lion said—“I reign</p>
+<p class="poetry">The monarch of the wood and plain!”</p>
+<p class="poetry">The Elephant replied: “I’m great—</p>
+<p class="poetry">No quadruped can match my weight!”</p>
+<p class="poetry">“I’m great—no animal has half</p>
+<p class="poetry">So long a neck!” said the Giraffe.</p>
+<p class="poetry">“I’m great,” the Kangaroo said—“see</p>
+<p class="poetry">My femoral muscularity!”</p>
+<p class="poetry">The ‘Possum said: “I’m great—behold,</p>
+<p class="poetry">My tail is lithe and bald and cold!”</p>
+<p class="poetry">An Oyster fried was understood</p>
+<p class="poetry">To say: “I’m great because I’m good!”</p>
+<p class="poetry">Each reckons greatness to consist</p>
+<p class="poetry">In that in which he heads the list,</p>
+<p class="poetry">And Vierick thinks he tops his class</p>
+<p class="poetry">Because he is the greatest ass.</p>
+<p class="citeauth">Arion Spurl Doke</p>
+</div>
+
+<p class="entry"><span class="def">guillotine</span>, <span class="pos">n.</span> A machine which makes a Frenchman shrug his shoulders with good reason.</p>
+
+<p>In his great work on <i>Divergent Lines of Racial Evolution</i>,
+the learned Professor Brayfugle argues from the prevalence of this gesture—
+the shrug—among Frenchmen, that they are descended from turtles and it is
+simply a survival of the habit of retracing the head inside the shell. It is
+with reluctance that I differ with so eminent an authority, but in my judgment
+(as more elaborately set forth and enforced in my work entitled <i>Hereditary Emotions</i>—lib. II, c. XI) the
+shrug is a poor foundation upon which to build so important a theory, for
+previously to the Revolution the gesture was unknown. I have not a doubt that
+it is directly referable to the terror inspired by the guillotine during the
+period of that instrument’s activity.</p>
+
+<p class="entry"><span class="def">gunpowder</span>, <span class="pos">n.</span> An agency employed by civilized nations for the settlement of disputes which might
+become troublesome if left unadjusted. By most writers the invention of
+gunpowder is ascribed to the Chinese, but not upon very convincing evidence. Milton
+says it was invented by the devil to dispel angels with, and this opinion seems
+to derive some support from the scarcity of angels. Moreover, it has the hearty
+concurrence of the Hon. James Wilson, Secretary of Agriculture.</p>
+
+<p>Secretary Wilson became interested in gunpowder through an event that occurred on the Government
+experimental farm in the District of Columbia. One day, several years ago, a
+rogue imperfectly reverent of the Secretary’s profound attainments and personal
+character presented him with a sack of gunpowder, representing it as the sed of
+the <i>Flashawful flabbergastor</i>, a
+Patagonian cereal of great commercial value, admirably adapted to this climate.
+The good Secretary was instructed to spill it along in a furrow and afterward
+inhume it with soil. This he at once proceeded to do, and had made a continuous
+line of it all the way across a ten-acre field, when he was made to look
+backward by a shout from the generous donor, who at once dropped a lighted
+match into the furrow at the starting-point. Contact with the earth had
+somewhat dampened the powder, but the startled functionary saw himself pursued
+by a tall moving pillar of fire and smoke and fierce evolution. He stood for a
+moment paralyzed and speechless, then he recollected an engagement and,
+dropping all, absented himself thence with such surprising celerity that to the
+eyes of spectators along the route selected he appeared like a long, dim streak
+prolonging itself with inconceivable rapidity through seven villages, and
+audibly refusing to be comforted. “Great Scott! what is that?” cried a
+surveyor’s chainman, shading his eyes and gazing at the fading line of
+agriculturist which bisected his visible horizon. “That,” said the surveyor,
+carelessly glancing at the phenomenon and again centering his attention upon
+his instrument, “is the Meridian of Washington.”</p>
+
+
+</body>
+</html>
\ No newline at end of file
--- /dev/null
+++ b/lib/ebooks/devils/G.html.i
@@ -1,0 +1,31 @@
+14 pages
+size 400 552
+length 18661
+396 2 10 body html
+0
+1752 2 37 body html
+0
+2826 2 54 body html
+199
+4203 2 77 body html
+199
+5148 2 97 body html
+187
+7699 2 131 body html
+0
+8953 2 148 body html
+199
+10495 2 176 body html
+127
+11649 2 196 body html
+252
+12929 2 220 body html
+91
+13952 2 240 body html
+0
+14469 2 248 body html
+415
+16428 2 281 body html
+56
+16977 2 288 body html
+459
--- /dev/null
+++ b/lib/ebooks/devils/H.html
@@ -1,0 +1,432 @@
+<?xml version="1.0"?>
+<!DOCTYPE package PUBLIC "+//ISBN 0-9673008-1-9//DTD OEB 1.0 Package//EN"
+ "http://openebook.org/dtds/oeb-1.0/oebdoc1.dtd">
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/x-oeb1-document; charset=utf-8" />
+<link rel="stylesheet" type="text/x-oeb1-css" href="devil.css" />
+<title>The Devil’s Dictionary: H</title>
+</head>
+<body lang="en-US">
+
+
+<h1>H</h1>
+
+
+<p class="entry"><span class="def">habeas corpus.</span> A writ by which a man may be taken out of jail when confined for the wrong crime.</p>
+
+<p class="entry"><span class="def">habit</span>, <span class="pos">n.</span> A shackle for the free.</p>
+
+<p class="entry"><span class="def">hades</span>, <span class="pos">n.</span> The lower world;
+the residence of departed spirits; the place where the dead live.</p>
+
+<p>Among the ancients the idea of Hades was not synonymous with our Hell, many of the most
+respectable men of antiquity residing there in a very comfortable kind of way. Indeed,
+the Elysian Fields themselves were a part of Hades, though they have since been
+removed to Paris. When the Jacobean version of the New Testament was in process
+of evolution the pious and learned men engaged in the work insisted by a
+majority vote on translating the Greek word “Aides” as “Hell”; but a
+conscientious minority member secretly possessed himself of the record and
+struck out the objectional word wherever he could find it. At the next meeting,
+the Bishop of Salisbury, looking over the work, suddenly sprang to his feet and
+said with considerable excitement: “Gentlemen, somebody has been razing ‘Hell’
+here!” Years afterward the good prelate’s death was made sweet by the
+reflection that he had been the means (under Providence) of making an
+important, serviceable and immortal addition to the phraseology of the English
+tongue.</p>
+
+<p class="entry"><span class="def">hag</span>, <span class="pos">n.</span> An elderly lady whom you do not happen to like; sometimes called, also, a hen, or cat. Old
+witches, sorceresses, etc., were called hags from the belief that their heads
+were surrounded by a kind of baleful lumination or nimbus—hag being the popular
+name of that peculiar electrical light sometimes observed in the hair. At one
+time hag was not a word of reproach: Drayton speaks of a “beautiful hag, all
+smiles,” much as Shakespeare said, “sweet wench.” It would not now be proper to
+call your sweetheart a hag—that compliment is reserved for the use of her
+grandchildren.</p>
+
+<p class="entry"><span class="def">half</span>, <span class="pos">n.</span> One of two equal parts into which a thing may be divided, or considered as divided. In
+the fourteenth century a heated discussion arose among theologists and
+philosophers as to whether Omniscience could part an object into three halves;
+and the pious Father Aldrovinus publicly prayed in the cathedral at Rouen that
+God would demonstrate the affirmative of the proposition in some signal and
+unmistakable way, and particularly (if it should please Him) upon the body of
+that hardy blasphemer, Manutius Procinus, who maintained the negative. Procinus,
+however, was spared to die of the bite of a viper.</p>
+
+<p class="entry"><span class="def">halo</span>, <span class="pos">n.</span> Properly, a luminous ring encircling an astronomical body, but not infrequently
+confounded with “aureola,” or “nimbus,” a somewhat similar phenomenon worn as a
+head-dress by divinities and saints. The halo is a purely optical illusion,
+produced by moisture in the air, in the manner of a rainbow; but the aureola is
+conferred as a sign of superior sanctity, in the same way as a bishop’s mitre,
+or the Pope’s tiara. In the painting of the Nativity, by Szedgkin, a pious artist
+of Pesth, not only do the Virgin and the Child wear the nimbus, but an ass
+nibbling hay from the sacred manger is similarly decorated and, to his lasting
+honor be it said, appears to bear his unaccustomed dignity with a truly saintly
+grace.</p>
+
+<p class="entry"><span class="def">hand</span>, <span class="pos">n.</span> A singular instrument worn at the end of the human arm and commonly thrust into
+somebody’s pocket.</p>
+
+<p class="entry"><span class="def">handkerchief</span>, <span class="pos">n.</span> A small square of silk or linen, used in various ignoble offices about the face
+and especially serviceable at funerals to conceal the lack of tears. The
+handkerchief is of recent invention; our ancestors knew nothing of it and
+intrusted its duties to the sleeve. Shakespeare’s introducing it into the play
+of “Othello” is an anachronism: Desdemona dried her nose with her skirt, as Dr.
+Mary Walker and other reformers have done with their coattails in our own
+day—an evidence that revolutions sometimes go backward.</p>
+
+<p class="entry"><span class="def">hangman</span>, <span class="pos">n.</span> An officer of the law charged with duties of the highest dignity and utmost
+gravity, and held in hereditary disesteem by a populace having a criminal
+ancestry. In some of the American States his functions are now performed by an
+electrician, as in New Jersey, where executions by electricity have recently
+been ordered—the first instance known to this lexicographer of anybody
+questioning the expediency of hanging Jerseymen.</p>
+
+<p class="entry"><span class="def">happiness</span>, <span class="pos">n.</span> An agreeable sensation arising from contemplating the misery of another.</p>
+
+<p class="entry"><span class="def">harangue</span>, <span class="pos">n.</span> A speech by an opponent, who is known as an harrangue- outang.</p>
+
+<p class="entry"><span class="def">harbor</span>, <span class="pos">n.</span> A place where ships taking shelter from stores are exposed to the fury of the customs.</p>
+
+<p class="entry"><span class="def">harmonists</span>, <span class="pos">n.</span> A sect of Protestants, now extinct, who came from Europe in the beginning of the
+last century and were distinguished for the bitterness of their internal controversies and dissensions.</p>
+
+<p class="entry"><span class="def">hash,</span> <span class="pos">x.</span> There is no definition for this word—nobody knows what hash is.</p>
+
+<p class="entry"><span class="def">hatchet</span>, <span class="pos">n.</span> A young axe, known among Indians as a Thomashawk.</p>
+
+<div class="poem">
+<p class="poetry">“O bury the hatchet, irascible Red,</p>
+<p class="poetry">For peace is a blessing,” the White Man said.</p>
+<p class="poetry">The Savage concurred, and that weapon interred, With imposing rites, in the White Man’s head.</p>
+<p class="poetry">John Lukkus</p>
+</div>
+
+<p class="entry"><span class="def">hatred</span>, <span class="pos">n.</span> A sentiment appropriate to the occasion of another’s superiority.</p>
+
+<p class="entry"><span class="def">head-money</span>, <span class="pos">n.</span> A capitation tax, or poll-tax.</p>
+
+<div class="poem">
+<p class="poetry">In ancient times there lived a king</p>
+<p class="poetry">Whose tax-collectors could not wring</p>
+<p class="poetry">From all his subjects gold enough</p>
+<p class="poetry">To make the royal way less rough.</p>
+<p class="poetry">For pleasure’s highway, like the dames</p>
+<p class="poetry">Whose premises adjoin it, claims</p>
+<p class="poetry">Perpetual repairing. So</p>
+<p class="poetry">The tax-collectors in a row</p>
+<p class="poetry">Appeared before the throne to pray</p>
+<p class="poetry">Their master to devise some way</p>
+<p class="poetry">To swell the revenue. “So great,”</p>
+<p class="poetry">Said they, “are the demands of state</p>
+<p class="poetry">A tithe of all that we collect</p>
+<p class="poetry">Will scarcely meet them. Pray reflect:</p>
+<p class="poetry">How, if one-tenth we must resign,</p>
+<p class="poetry">Can we exist on t’other nine?”</p>
+<p class="poetry">The monarch asked them in reply:</p>
+<p class="poetry">“Has it occurred to you to try</p>
+<p class="poetry">The advantage of economy?”</p>
+<p class="poetry">“It has,” the spokesman said: “we sold</p>
+<p class="poetry">All of our gray garrotes of gold;</p>
+<p class="poetry">With plated-ware we now compress</p>
+<p class="poetry">The necks of those whom we assess.</p>
+<p class="poetry">Plain iron forceps we employ</p>
+<p class="poetry">To mitigate the miser’s joy</p>
+<p class="poetry">Who hoards, with greed that never tires,</p>
+<p class="poetry">That which your Majesty requires.”</p>
+<p class="poetry">Deep lines of thought were seen to plow</p>
+<p class="poetry">Their way across the royal brow.</p>
+<p class="poetry">“Your state is desperate, no question;</p>
+<p class="poetry">Pray favor me with a suggestion.”</p>
+<p class="poetry">“O King of Men,” the spokesman said,</p>
+<p class="poetry">“If you’ll impose upon each head</p>
+<p class="poetry">A tax, the augmented revenue</p>
+<p class="poetry">We’ll cheerfully divide with you.”</p>
+<p class="poetry">As flashes of the sun illume</p>
+<p class="poetry">The parted storm-cloud’s sullen gloom,</p>
+<p class="poetry">The king smiled grimly. “I decree</p>
+<p class="poetry">That it be so—and, not to be</p>
+<p class="poetry">In generosity outdone,</p>
+<p class="poetry">Declare you, each and every one,</p>
+<p class="poetry">Exempted from the operation</p>
+<p class="poetry">Of this new law of capitation.</p>
+<p class="poetry">But lest the people censure me</p>
+<p class="poetry">Because they’re bound and you are free,</p>
+<p class="poetry">‘Twere well some clever scheme were laid</p>
+<p class="poetry">By you this poll-tax to evade.</p>
+<p class="poetry">I’ll leave you now while you confer</p>
+<p class="poetry">With my most trusted minister.”</p>
+<p class="poetry">The monarch from the throne-room walked</p>
+<p class="poetry">And straightway in among them stalked</p>
+<p class="poetry">A silent man, with brow concealed,</p>
+<p class="poetry">Bare-armed—his gleaming axe revealed!</p>
+<p class="citeauth">G. J.</p>
+</div>
+
+<p class="entry"><span class="def">hearse</span>, <span class="pos">n.</span> Death’s baby-carriage.</p>
+
+<p class="entry"><span class="def">heart</span>, <span class="pos">n.</span> An automatic, muscular blood-pump. Figuratively, this useful organ is said to be
+the esat of emotions and sentiments—a very pretty fancy which, however, is
+nothing but a survival of a once universal belief. It is now known that the
+sentiments and emotions reside in the stomach, being evolved from food by
+chemical action of the gastric fluid. The exact process by which a beefsteak
+becomes a feeling—tender or not, according to the age of the animal from which
+it was cut; the successive stages of elaboration through which a caviar
+sandwich is transmuted to a quaint fancy and reappears as a pungent epigram;
+the marvelous functional methods of converting a hard-boiled egg into religious
+contrition, or a cream-puff into a sigh of sensibility—these things have been
+patiently ascertained by M. Pasteur, and by him expounded with convincing
+lucidity. (See, also, my monograph, <i>The Essential Identity of the Spiritual
+Affections and Certain Intestinal Gases Freed in Digestion</i>—4to, 687 pp.) In
+a scientific work entitled, I believe, <i>Delectatio
+Demonorum</i> (John Camden Hotton, London, 1873) this view of the
+sentiments receives a striking illustration; and for further light consult
+Professor Dam’s famous treatise on <i>Love as a
+Product of Alimentary Maceration</i>.</p>
+
+<p class="entry"><span class="def">heat</span>, <span class="pos">n.</span></p>
+
+<div class="poem">
+<p class="poetry">Heat, says Professor Tyndall, is a mode</p>
+<p class="poetry">Of motion, but I know now how he’s proving</p>
+<p class="poetry">His point; but this I know—hot words bestowed</p>
+<p class="poetry">With skill will set the human fist a-moving, And where it stops the stars burn free and wild. <i>Crede expertum</i>—I have seen them, child.</p>
+<p class="citeauth">Gorton Swope</p>
+</div>
+
+<p class="entry"><span class="def">heathen</span>, <span class="pos">n.</span> A benighted creature who has the folly to worship something that he can see and
+feel. According to Professor Howison, of the California State University,
+Hebrews are heathens.</p>
+
+<div class="poem">
+<p class="poetry">“The Hebrews are heathens!” says Howison. He’s</p>
+<p class="poetry">A Christian philosopher. I’m</p>
+<p class="poetry">A scurril agnostical chap, if you please,</p>
+<p class="poetry">Addicted too much to the crime</p>
+<p class="poetry">Of religious discussion in my rhyme.</p>
+<p class="poetry">Though Hebrew and Howison cannot agree</p>
+<p class="poetry">On a <i>modus vivendi</i>—not they!—</p>
+<p class="poetry">Yet Heaven has had the designing of me,</p>
+<p class="poetry">And I haven’t been reared in a way</p>
+<p class="poetry">To joy in the thick of the fray.</p>
+<p class="poetry">For this of my creed is the soul and the gist,</p>
+<p class="poetry">And the truth of it I aver:</p>
+<p class="poetry">Who differs from me in his faith is an ‘ist,</p>
+<p class="poetry">And ‘ite, an ‘ie, or an ‘er—</p>
+<p class="poetry">And I’m down upon him or her!</p>
+<p class="poetry">Let Howison urge with perfunctory chin</p>
+<p class="poetry">Toleration—that’s all very well,</p>
+<p class="poetry">But a roast is “nuts” to his nostril thin,</p>
+<p class="poetry">And he’s running—I know by the smell—</p>
+<p class="poetry">A secret and personal Hell!</p>
+<p class="citeauth">Bissell Gip</p>
+</div>
+
+<p class="entry"><span class="def">heaven</span>, <span class="pos">n.</span> A place where the wicked cease from troubling you with talk of their personal affairs,
+and the good listen with attention while you expound your own.</p>
+
+<p class="entry"><span class="def">hebrew</span>, <span class="pos">n.</span> A male Jew, as distinguished from the Shebrew, an altogether superior creation.</p>
+
+<p class="entry"><span class="def">helpmate</span>, <span class="pos">n.</span> A wife, or bitter half.</p>
+
+<div class="poem">
+<p class="poetry">“Now, why is yer wife called a helpmate, Pat?”</p>
+<p class="poetry">Says the priest. “Since the time ‘o yer wooin’ She’s niver [sic] assisted in what ye were at—</p>
+<p class="poetry">For it’s naught ye are ever doin’.”</p>
+<p class="poetry">“That’s true of yer Riverence [sic],” Patrick replies,</p>
+<p class="poetry">And no sign of contrition envices;</p>
+<p class="poetry">“But, bedad, it’s a fact which the word implies,</p>
+<p class="poetry">For she helps to mate the expinses [sic]!”</p>
+<p class="citeauth">Marley Wottel</p>
+</div>
+
+<p class="entry"><span class="def">hemp</span>, <span class="pos">n.</span> A plant from whose fibrous bark is made an article of neckwear which is frequently put
+on after public speaking in the open air and prevents the wearer from taking cold.</p>
+
+<p class="entry"><span class="def">hermit</span>, <span class="pos">n.</span> A person whose vices and follies are not sociable.</p>
+
+<p class="entry"><span class="def">hers,</span> <span class="pos">pron.</span> His.</p>
+
+<p class="entry"><span class="def">hibernate</span>, <span class="pos">v.i.</span> To pass the winter season in domestic seclusion. There have been many singular
+popular notions about the hibernation of various animals. Many believe that the
+bear hibernates during the whole winter and subsists by mechanically sucking
+its paws. It is admitted that it comes out of its retirement in the spring so
+lean that it had to try twice before it can cast a shadow. Three or four centuries
+ago, in England, no fact was better attested than that swallows passed the
+winter months in the mud at the bottom of their brooks, clinging together in
+globular masses. They have apparently been compelled to give up the custom and
+account of the foulness of the brooks. Sotus Ecobius discovered in Central Asia
+a whole nation of people who hibernate. By some investigators, the fasting of
+Lent is supposed to have been originally a modified form of hibernation, to
+which the Church gave a religious significance; but this view was strenuously
+opposed by that eminent authority, Bishop Kip, who did not wish any honors
+denied to the memory of the Founder of his family.</p>
+
+<p class="entry"><span class="def">hippogriff</span>, <span class="pos">n.</span> An animal (now extinct) which was half horse and half griffin. The griffin was
+itself a compound creature, half lion and half eagle. The hippogriff was
+actually, therefore, a one-quarter eagle, which is two dollars and fifty cents
+in gold. The study of zoology is full of surprises.</p>
+
+<p class="entry"><span class="def">historian</span>, <span class="pos">n.</span> A broad-gauge gossip.</p>
+
+<p class="entry"><span class="def">history</span>, <span class="pos">n.</span> An account mostly false, of events mostly unimportant, which are brought about by
+rulers mostly knaves, and soldiers mostly fools.</p>
+
+<div class="poem">
+<p class="poetry">Of Roman history, great Niebuhr’s shown</p>
+<p class="poetry">‘Tis nine-tenths lying.<br />
+Faith, I wish ‘twere known, Ere we accept great Niebuhr as a guide,<br />
+Wherein he blundered and how much he lied.</p>
+<p class="citeauth">Salder Bupp</p>
+</div>
+
+<p class="entry"><span class="def">hog</span>, <span class="pos">n.</span> A bird remarkable for the catholicity of its appetite and serving to illustrate that
+of ours. Among the Mahometans and Jews, the hog is not in favor as an article
+of diet, but is respected for the delicacy and the melody of its voice. It is
+chiefly as a songster that the fowl is esteemed; the cage of him in full chorus
+has been known to draw tears from two persons at once. The scientific name of
+this dicky-bird is <i>Porcus Rockefelleri</i>.
+Mr. Rockefeller did not discover the hog, but it is considered his by right of
+resemblance.</p>
+
+<p class="entry"><span class="def">homoeopathist</span>, <span class="pos">n.</span> The humorist of the medical profession.</p>
+
+<p class="entry"><span class="def">homoeopathy</span>, <span class="pos">n.</span> A school of medicine midway between Allopathy and Christian Science. To the last
+both the others are distinctly inferior, for Christian Science will cure
+imaginary diseases, and they can not.</p>
+
+<p class="entry"><span class="def">homicide</span>, <span class="pos">n.</span> The slaying of one human being by another. There are four kinds of homocide: felonious,
+excusable, justifiable, and praiseworthy, but it makes no great difference to
+the person slain whether he fell by one kind or another—the classification is
+for advantage of the lawyers.</p>
+
+<p class="entry"><span class="def">homiletics</span>, <span class="pos">n.</span> The science of adapting sermons to the spiritual needs, capacities and conditions
+of the congregation.</p>
+
+<div class="poem">
+<p class="poetry">So skilled the parson was in homiletics</p>
+<p class="poetry">That all his normal purges and emetics</p>
+<p class="poetry">To medicine the spirit were compounded</p>
+<p class="poetry">With a most just discrimination founded</p>
+<p class="poetry">Upon a rigorous examination</p>
+<p class="poetry">Of tongue and pulse and heart and respiration.</p>
+<p class="poetry">Then, having diagnosed each one’s condition,</p>
+<p class="poetry">His scriptural specifics this physician</p>
+<p class="poetry">Administered—his pills so efficacious</p>
+<p class="poetry">And pukes of disposition so vivacious</p>
+<p class="poetry">That souls afflicted with ten kinds of Adam<br />
+Were convalescent ere they knew they had ‘em.<br />
+But Slander’s tongue—itself all coated—uttered<br />
+Her bilious mind and scandalously muttered<br />
+That in the case of patients having money<br />
+The pills were sugar and the pukes were honey.</p>
+<p class="citeauth"><i>Biography of Bishop Potter</i></p>
+</div>
+
+<p class="entry"><span class="def">honorable</span>, <span class="pos">adj.</span> Afflicted with an impediment in one’s reach. In legislative bodies it is customary to
+mention all members as honorable; as, “the honorable gentleman is a scurvy cur.”</p>
+
+<p class="entry"><span class="def">hope</span>, <span class="pos">n.</span> Desire and expectation rolled into one.</p>
+
+<div class="poem">
+<p class="poetry">Delicious Hope! when naught to man it left—</p>
+<p class="poetry">Of fortune destitute, of friends bereft;</p>
+<p class="poetry">When even his dog deserts him, and his goat
+With tranquil disaffection chews his coat
+While yet it hangs upon his back; then thou,
+The star far-flaming on thine angel brow,
+Descendest, radiant, from the skies to hint
+The promise of a clerkship in the Mint.</p>
+<p class="citeauth"><span class="def">Fogarty Weffing</span></p>
+</div>
+
+<p class="entry"><span class="def">hospitality</span>, <span class="pos">n.</span> The virtue which induces us to feed and lodge certain persons who are not in need
+of food and lodging.</p>
+
+<p class="entry"><span class="def">hostility</span>, <span class="pos">n.</span> A peculiarly sharp and specially applied sense of the earth’s overpopulation. Hostility
+is classified as active and passive; as (respectively) the feeling of a woman
+for her female friends, and that which she entertains for all the rest of her sex.</p>
+
+<p class="entry"><span class="def">Houri</span>, <span class="pos">n.</span> A comely female inhabiting the Mohammedan Paradise to make things cheery for the good
+Mussulman, whose belief in her existence marks a noble discontent with his
+earthly spouse, whom he denies a soul. By that good lady the Houris are said to
+be held in deficient esteem.</p>
+
+<p id="house" class="entry"><span class="def">house</span>, <span class="pos">n.</span> A hollow edifice erected for the habitation of man, rat, mouse, beelte, cockroach, fly,
+mosquito, flea, bacillus and microbe. <i>House
+of Correction</i>, a place of reward for political and personal service,
+and for the detention of offenders and appropriations. <i>House of God</i>, a building with a steeple
+and a mortgage on it. <i>House-dog</i>,
+a pestilent beast kept on domestic premises to insult persons passing by and
+appal the hardy visitor. <i>House-maid</i>,
+a youngerly person of the opposing sex employed to be variously disagreeable
+and ingeniously unclean in the station in which it has pleased God to place her.</p>
+
+<p class="entry"><span class="def">houseless</span>, <span class="pos">adj.</span> Having paid all taxes on household goods.</p>
+
+<p class="entry"><span class="def">hovel</span>, <span class="pos">n.</span> The fruit of a flower called the Palace.</p>
+
+<div class="poem">
+<p class="poetry">Twaddle had a hovel,</p>
+<p class="poetry">Twiddle had a palace;</p>
+<p class="poetry">Twaddle said: “I’ll grovel</p>
+<p class="poetry">Or he’ll think I bear him malice”—</p>
+<p class="poetry">A sentiment as novel</p>
+<p class="poetry">As a castor on a chalice.</p>
+<p class="poetry">Down upon the middle</p>
+<p class="poetry">Of his legs fell Twaddle</p>
+<p class="poetry">And astonished Mr. Twiddle,</p>
+<p class="poetry">Who began to lift his noddle.</p>
+<p class="poetry">Feed upon the fiddle—</p>
+<p class="poetry">Faddle flummery, unswaddle</p>
+<p class="poetry">A new-born self-sufficiency and think himself a [mockery.]</p>
+<p class="citeauth">G. J.</p>
+</div>
+
+<p class="entry"><span class="def">humanity</span>, <span class="pos">n.</span> The human race, collectively, exclusive of the anthropoid poets.</p>
+
+<p class="entry"><span class="def">humorist</span>, <span class="pos">n.</span> A plague that would have softened down the hoar austerity of Pharaoh’s heart and
+persuaded him to dismiss Israel with his best wishes, cat-quick.</p>
+
+<div class="poem">
+<p class="poetry">Lo! the poor humorist, whose tortured mind</p>
+<p class="poetry">See jokes in crowds, though still to gloom inclined—</p>
+<p class="poetry">Whose simple appetite, untaught to stray, His brains, renewed by night, consumes by day.</p>
+<p class="poetry">He thinks, admitted to an equal sty,</p>
+<p class="poetry">A graceful hog would bear his company.</p>
+<p class="citeauth">Alexander Poke</p>
+</div>
+
+<p class="entry"><span class="def">hurricane</span>, <span class="pos">n.</span> An atmospheric demonstration once very common but now generally abandoned for the
+tornado and cyclone. The hurricane is still in popular use in the West Indies
+and is preferred by certain old-fashioned sea-captains. It is also used in the
+construction of the upper decks of steamboats, but generally speaking, the
+hurricane’s usefulness has outlasted it.</p>
+
+<p class="entry"><span class="def">hurry</span>, <span class="pos">n.</span> The dispatch of bunglers.</p>
+
+<p id="husband" class="entry"><span class="def">husband</span>, <span class="pos">n.</span> One who, having dined, is charged with the care of the plate.</p>
+
+<p class="entry"><span class="def">hybrid</span>, <span class="pos">n.</span> A pooled issue.</p>
+
+<p class="entry"><span class="def">hydra</span>, <span class="pos">n.</span> A kind of animal that the ancients catalogued under many heads.</p>
+
+<p class="entry"><span class="def">hyena</span>, <span class="pos">n.</span> A beast held in reverence by some oriental nations from its habit of frequenting at
+night the burial-places of the dead. But the medical student does that.</p>
+
+<p class="entry"><span class="def">hypochondriasis</span>, <span class="pos">n.</span> Depression of one’s own spirits.</p>
+
+<div class="poem">
+<p class="poetry">Some heaps of trash upon a vacant lot<br />
+Where long the village rubbish had been shot<br />
+Displayed a sign among the stuff and stumps—<br />
+“Hypochondriasis.” It meant The Dumps.</p>
+<p class="citeauth">Bogul S. Purvy</p>
+</div>
+
+<p class="entry"><span class="def">hypocrite</span>, <span class="pos">n.</span> One who, profession virtues that he does not respect secures the advantage of
+seeming to be what he depises.</p>
+
+
+</body>
+</html>
\ No newline at end of file
--- /dev/null
+++ b/lib/ebooks/devils/H.html.annot
@@ -1,0 +1,1 @@
+22841 Hello
\ No newline at end of file
--- /dev/null
+++ b/lib/ebooks/devils/H.html.i
@@ -1,0 +1,41 @@
+18 pages
+size 400 552
+length 26002
+396 2 10 body html
+0
+1871 2 38 body html
+39
+4030 2 67 body html
+22
+6233 2 96 body html
+0
+6945 2 109 body html
+271
+6945 2 109 body html
+811
+6945 2 109 body html
+1351
+6945 2 109 body html
+1891
+11584 2 189 body html
+72
+12276 2 201 body html
+324
+13953 2 230 body html
+0
+15146 2 250 body html
+107
+17293 2 283 body html
+0
+18872 2 306 body html
+163
+20286 2 331 body html
+91
+22520 2 367 body html
+0
+23366 2 386 body html
+0
+24997 2 412 body html
+0
+husband 16
+house 14
--- /dev/null
+++ b/lib/ebooks/devils/I.html
@@ -1,0 +1,681 @@
+<?xml version="1.0"?>
+<!DOCTYPE package PUBLIC "+//ISBN 0-9673008-1-9//DTD OEB 1.0 Package//EN"
+ "http://openebook.org/dtds/oeb-1.0/oebdoc1.dtd">
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/x-oeb1-document; charset=utf-8" />
+<link rel="stylesheet" type="text/x-oeb1-css" href="devil.css" />
+<title>The Devil’s Dictionary: I</title>
+</head>
+<body lang="en-US">
+
+
+<h1>I</h1>
+
+
+<p>I is the first letter of the alphabet, the first word of the language, the first thought of
+the mind, the first object of affection. In grammar it is a pronoun of the
+first person and singular number. Its plural is said to be <i>We</i>, but how there can be more than one
+myself is doubtless clearer the grammarians than it is to the author of this
+incomparable dictionary. Conception of two myselfs is difficult, but fine. The
+frank yet graceful use of “I” distinguishes a good writer from a bad; the
+latter carries it with the manner of a thief trying to cloak his loot.</p>
+
+<p class="entry"><span class="def">Ichor</span>, <span class="pos">n.</span> A fluid that serves the gods and goddesses in place of blood.</p>
+
+<div class="poem">
+<p class="poetry">Fair Venus, speared by Diomed,</p>
+<p class="poetry">Restrained the raging chief and said:</p>
+<p class="poetry">“Behold, rash mortal, whom you’ve bled—</p>
+<p class="poetry">Your soul’s stained white with ichorshed!”</p>
+<p class="citeauth">Mary Doke</p>
+</div>
+
+<p class="entry"><span class="def">iconoclast</span>, <span class="pos">n.</span> A breaker of idols, the worshipers whereof are imperfectly gratified by the
+performance, and most strenuously protest that he unbuildeth but doth not
+reedify, that he pulleth down but pileth not up. For the poor things would have
+other idols in place of those he thwacketh upon the mazzard and dispelleth. But
+the iconoclast saith: “Ye shall have none at all, for ye need them not; and if
+the rebuilder fooleth round hereabout, behold I will depress the head of him
+and sit thereon till he squawk it.”</p>
+
+<p class="entry"><span class="def">idiot</span>, <span class="pos">n.</span> A member of a large and powerful tribe whose influence in human affairs has always been
+dominant and controlling. The Idiot’s activity is not confined to any special
+field of thought or action, but “pervades and regulates the whole.” He has the
+last word in everything; his decision is unappealable. He sets the fashions and
+opinion of taste, dictates the limitations of speech and circumscribes conduct
+with a dead-line.</p>
+
+<p class="entry"><span class="def">idleness</span>, <span class="pos">n.</span> A model farm where the
+devil experiments with seeds of new sins and promotes the growth of staple vices.</p>
+
+<p class="entry"><span class="def">ignoramus</span>, <span class="pos">n.</span> A person unacquainted with certain kinds of knowledge familiar to yourself, and
+having certain other kinds that you know nothing about.</p>
+
+<div class="poem">
+<p class="poetry">Dumble was an ignoramus,</p>
+<p class="poetry">Mumble was for learning famous.</p>
+<p class="poetry">Mumble said one day to Dumble:</p>
+<p class="poetry">“Ignorance should be more humble.</p>
+<p class="poetry">Not a spark have you of knowledge</p>
+<p class="poetry">That was got in any college.”</p>
+<p class="poetry">Dumble said to Mumble: “Truly</p>
+<p class="poetry">You’re self-satisfied unduly.</p>
+<p class="poetry">Of things in college I’m denied</p>
+<p class="poetry">A knowledge—you of all beside.”</p>
+<p class="citeauth">Borelli</p>
+</div>
+
+<p class="entry"><span class="def">illuminati</span>, <span class="pos">n.</span> A sect of Spanish heretics of the latter part of the sixteenth century; so called
+because they were light weights—<i>cunctationes illuminati</i>.</p>
+
+<p class="entry"><span class="def">illustrious</span>, <span class="pos">adj.</span> Suitably placed for the shafts of malice, envy and detraction.</p>
+
+<p class="entry"><span class="def">imagination</span>, <span class="pos">n.</span> A warehouse of facts, with poet and liar in joint ownership.</p>
+
+<p class="entry"><span class="def">imbecility</span>, <span class="pos">n.</span> A kind of divine inspiration, or sacred fire affecting censorious critics of this dictionary.</p>
+
+<p class="entry"><span class="def">immigrant</span>, <span class="pos">n.</span> An unenlightened person who thinks one country better than another.</p>
+
+<p class="entry"><span class="def">immodest</span>, <span class="pos">adj.</span> Having a strong sense of one’s own merit, coupled with a feeble conception of worth in others.</p>
+
+<div class="poem">
+<p class="poetry">There was once a man in Ispahan</p>
+<p class="poetry">Ever and ever so long ago,</p>
+<p class="poetry">And he had a head, the phrenologists said,</p>
+<p class="poetry">That fitted him for a show.</p>
+<p class="poetry">For his modesty’s bump was so large a lump</p>
+<p class="poetry">(Nature, they said, had taken a freak)</p>
+<p class="poetry">That its summit stood far above the wood</p>
+<p class="poetry">Of his hair, like a mountain peak.</p>
+<p class="poetry">So modest a man in all Ispahan,</p>
+<p class="poetry">Over and over again they swore—</p>
+<p class="poetry">So humble and meek, you would vainly seek;</p>
+<p class="poetry">None ever was found before.</p>
+<p class="poetry">Meantime the hump of that awful bump</p>
+<p class="poetry">Into the heavens contrived to get</p>
+<p class="poetry">To so great a height that they called the wight</p>
+<p class="poetry">The man with the minaret.</p>
+<p class="poetry">There wasn’t a man in all Ispahan</p>
+<p class="poetry">Prouder, or louder in praise of his chump:</p>
+<p class="poetry">With a tireless tongue and a brazen lung</p>
+<p class="poetry">He bragged of that beautiful bump</p>
+<p class="poetry">Till the Shah in a rage sent a trusty page</p>
+<p class="poetry">Bearing a sack and a bow-string too,</p>
+<p class="poetry">And that gentle child explained as he smiled:</p>
+<p class="poetry">“A little present for you.”</p>
+<p class="poetry">The saddest man in all Ispahan,</p>
+<p class="poetry">Sniffed at the gift, yet accepted the same.</p>
+<p class="poetry">“If I’d lived,” said he, “my humility</p>
+<p class="poetry">Had given me deathless fame!”</p>
+<p class="citeauth">Sukker Uffro</p>
+</div>
+
+<p class="entry"><span class="def">immoral</span>, <span class="pos">adj.</span> Inexpedient. Whatever in the long run and with regard to the greater number of instances men
+find to be generally inexpedient comes to be considered wrong, wicked, immoral.
+If man’s notions of right and wrong have any other basis than this of
+expediency; if they originated, or could have originated, in any other way; if
+actions have in themselves a moral character apart from, and nowise dependent
+on, their consequences—then all philosophy is a lie and reason a disorder of the mind.</p>
+
+<p class="entry"><span class="def">immorality</span>, <span class="pos">n.</span></p>
+
+<div class="poem">
+<p class="poetry">A toy which people cry for,</p>
+<p class="poetry">And on their knees apply for,</p>
+<p class="poetry">Dispute, contend and lie for,</p>
+<p class="poetry">And if allowed</p>
+<p class="poetry">Would be right proud</p>
+<p class="poetry">Eternally to die for.</p>
+<p class="citeauth">G. J.</p>
+</div>
+
+<p class="entry"><span class="def">impale</span>, <span class="pos">v.t.</span> In popular usage to pierce with any weapon which remains fixed in the wound. This,
+however, is inaccurate; to imaple is, properly, to put to death by thrusting an
+upright sharp stake into the body, the victim being left in a sitting position.
+This was a common mode of punishment among many of the nations of antiquity,
+and is still in high favor in China and other parts of Asia. Down to the
+beginning of the fifteenth century it was widely employed in “churching”
+heretics and schismatics. Wolecraft calls it the “stoole of repentynge,” and
+among the common people it was jocularly known as “riding the one legged
+horse.” Ludwig Salzmann informs us that in Thibet impalement is considered the
+most appropriate punishment for crimes against religion; and although in China
+it is sometimes awarded for secular offences, it is most frequently adjudged in
+cases of sacrilege. To the person in actual experience of impalement it must be
+a matter of minor importance by what kind of civil or religious dissent he was
+made acquainted with its discomforts; but doubtless he would feel a certain
+satisfaction if able to contemplate himself in the character of a weather-cock
+on the spire of the True Church.</p>
+
+<p class="entry"><span class="def">impartial</span>, <span class="pos">adj.</span> Unable to perceive any promise of personal advantage from espousing either side of a
+controversy or adopting either of two conflicting opinions.</p>
+
+<p class="entry"><span class="def">impenitence</span>, <span class="pos">n.</span> A state of mind intermediate in point of time between sin and punishment.</p>
+
+<p class="entry"><span class="def">impiety</span>, <span class="pos">n.</span> Your irreverence toward my deity.</p>
+
+<p class="entry"><span class="def">imposition</span>, <span class="pos">n.</span> The act of blessing
+or consecrating by the laying on of hands—a ceremony common to many ecclesiastical systems, but performed
+with the frankest sincerity by the sect known as Thieves.</p>
+
+<div class="poem">
+<p class="poetry">“Lo! by the laying on of hands,”</p>
+<p class="poetry">Say parson, priest and dervise,</p>
+<p class="poetry">“We consecrate your cash and lands</p>
+<p class="poetry">To ecclesiastical service.</p>
+<p class="poetry">No doubt you’ll swear till all is blue</p>
+<p class="poetry">At such an imposition. Do.”</p>
+<p class="poetry">Pollo Doncas</p>
+<p class="poetry">impostor n. A rival aspirant to public honors.</p>
+<p class="poetry">improbability, <span class="pos">n.</span></p>
+<p class="poetry">His tale he told with a solemn face</p>
+<p class="poetry">And a tender, melancholy grace.</p>
+<p class="poetry">Improbable ‘twas, no doubt,</p>
+<p class="poetry">When you came to think it out,</p>
+<p class="poetry">But the fascinated crowd</p>
+<p class="poetry">Their deep surprise avowed</p>
+<p class="poetry">And all with a single voice averred ‘Twas the most amazing thing they’d heard—</p>
+<p class="poetry">All save one who spake never a word,</p>
+<p class="poetry">But sat as mum</p>
+<p class="poetry">As if deaf and dumb,</p>
+<p class="poetry">Serene, indifferent and unstirred.</p>
+<p class="poetry">Then all the others turned to him And scrutinized him limb from limb—</p>
+<p class="poetry">Scanned him alive;</p>
+<p class="poetry">But he seemed to thrive</p>
+<p class="poetry">And tranquiler grow each minute,</p>
+<p class="poetry">As if there were nothing in it.</p>
+<p class="poetry">“What! what!” cried one, “are you not amazed</p>
+<p class="poetry">At what our friend has told?” He raised</p>
+<p class="poetry">Soberly then his eyes and gazed</p>
+<p class="poetry">In a natural way</p>
+<p class="poetry">And proceeded to say,</p>
+<p class="poetry">As he crossed his feet on the mantel-shelf:</p>
+<p class="poetry">“O no—not at all; I’m a liar myself.”</p>
+</div>
+
+<p class="entry"><span class="def">improvidence</span>, <span class="pos">n.</span> Provision for the needs of to-day from the revenues of to-morrow.</p>
+
+<p class="entry"><span class="def">impunity</span>, <span class="pos">n.</span> Wealth.</p>
+
+<p class="entry"><span class="def">inadmissible</span>, <span class="pos">adj.</span> Not competent to be considered. Said of certain kinds of testimony which juries
+are supposed to be unfit to be entrusted with, and which judges, therefore,
+rule out, even of proceedings before themselves alone. Hearsay evidence is
+inadmissible because the person quoted was unsworn and is not before the court
+for examination; yet most momentous actions, military, political, commercial
+and of every other kind, are daily undertaken on hearsay evidence. There is no
+religion in the world that has any other basis than hearsay evidence. Revelation
+is hearsay evidence; that the Scriptures are the word of God we have only the
+testimony of men long dead whose identity is not clearly established and who
+are not known to have been sworn in any sense. Under the rules of evidence as
+they now exist in this country, no single assertion in the Bible has in its
+support any evidence admissible in a court of law. It cannot be proved that the
+battle of Blenheim ever was fought, that there was such as person as Julius
+Caesar, such an empire as Assyria.</p>
+
+<p>But as records of courts of justice are admissible, it can easily be proved that powerful and
+malevolent magicians once existed and were a scourge to mankind. The evidence
+(including confession) upon which certain women were convicted of witchcraft
+and executed was without a flaw; it is still unimpeachable. The judges’
+decisions based on it were sound in logic and in law. Nothing in any existing
+court was ever more thoroughly proved than the charges of witchcraft and
+sorcery for which so many suffered death. If there were no witches, human
+testimony and human reason are alike destitute of value.</p>
+
+<p class="entry"><span class="def">inauspiciously</span>, <span class="pos">adv.</span> In an unpromising manner, the auspices being unfavorable. Among the Romans
+it was customary before undertaking any important action or enterprise to
+obtain from the augurs, or state prophets, some hint of its probable outcome;
+and one of their favorite and most trustworthy modes of divination consisted in
+observing the flight of birds—the omens thence derived being called <i>auspices</i>. Newspaper reporters and certain
+miscreant lexicographers have decided that the word—always in the plural—shall
+mean “patronage” or “management”; as, “The festivities were under the auspices
+of the Ancient and Honorable Order of Body-Snatchers”; or, “The hilarities were
+auspicated by the Knights of Hunger.”</p>
+
+<div class="poem">
+<p class="poetry">A Roman slave appeared one day</p>
+<p class="poetry">Before the Augur. “Tell me, pray,</p>
+<p class="poetry">If—“ here the Augur, smiling, made</p>
+<p class="poetry">A checking gesture and displayed</p>
+<p class="poetry">His open palm, which plainly itched,</p>
+<p class="poetry">For visibly its surface twitched.</p>
+<p class="poetry">A <i>denarius</i> (the Latin nickel)</p>
+<p class="poetry">Successfully allayed the tickle,</p>
+<p class="poetry">And then the slave proceeded: “Please</p>
+<p class="poetry">Inform me whether Fate decrees</p>
+<p class="poetry">Success or failure in what I</p>
+<p class="poetry">To-night (if it be dark) shall try.</p>
+<p class="poetry">Its nature? Never mind—I think</p>
+<p class="poetry">‘Tis writ on this”—and with a wink</p>
+<p class="poetry">Which darkened half the earth, he drew</p>
+<p class="poetry">Another denarius to view,</p>
+<p class="poetry">Its shining face attentive scanned,</p>
+<p class="poetry">Then slipped it into the good man’s hand,</p>
+<p class="poetry">Who with great gravity said: “Wait</p>
+<p class="poetry">While I retire to question Fate.”</p>
+<p class="poetry">That holy person then withdrew</p>
+<p class="poetry">His scared clay and, passing through</p>
+<p class="poetry">The temple’s rearward gate, cried “Shoo!”</p>
+<p class="poetry">Waving his robe of office. Straight</p>
+<p class="poetry">Each sacred peacock and its mate</p>
+<p class="poetry">(Maintained for Juno’s favor) fled</p>
+<p class="poetry">With clamor from the trees o’erhead,</p>
+<p class="poetry">Where they were perching for the night.</p>
+<p class="poetry">The temple’s roof received their flight,</p>
+<p class="poetry">For thither they would always go,</p>
+<p class="poetry">When danger threatened them below.</p>
+<p class="poetry">Back to the slave the Augur went:</p>
+<p class="poetry">“My son, forecasting the event</p>
+<p class="poetry">By flight of birds, I must confess</p>
+<p class="poetry">The auspices deny success.”</p>
+<p class="poetry">That slave retired, a sadder man,</p>
+<p class="poetry">Abandoning his secret plan—</p>
+<p class="poetry">Which was (as well the craft seer</p>
+<p class="poetry">Had from the first divined) to clear</p>
+<p class="poetry">The wall and fraudulently seize</p>
+<p class="poetry">On Juno’s poultry in the trees.</p>
+<p class="citeauth">G. J.</p>
+</div>
+
+<p id="income" class="entry"><span class="def">income</span>, <span class="pos">n.</span> The natural and rational gauge and measure of respectability, the commonly accepted
+standards being artificial, arbitrary and fallacious; for, as “Sir Sycophas
+Chrysolater” in the play has justly remarked, “the true use and function of
+property (in whatsoever it consisteth—coins, or land, or houses, or merchant-stuff,
+or anything which may be named as holden of right to one’s own
+subservience) as also of honors, titles, preferments and place, and all favor
+and acquaintance of persons of quality or ableness, are but to get money. Hence
+it followeth that all things are truly to be rated as of worth in measure of
+their serviceableness to that end; and their possessors should take rank in
+agreement thereto, neither the lord of an unproducing manor, howsoever broad
+and ancient, nor he who bears an unremunerate dignity, nor yet the pauper
+favorite of a king, being esteemed of level excellency with him whose riches
+are of daily accretion; and hardly should they whose wealth is barren claim and
+rightly take more honor than the poor and unworthy.”</p>
+
+<p class="entry"><span class="def">incompatibility</span>, <span class="pos">n.</span> In matrimony a similarity of tastes, particularly the taste for domination. Incompatibility
+may, however, consist of a meek-eyed matron living just around the corner. It
+has even been known to wear a moustache.</p>
+
+<p class="entry"><span class="def">incompossible</span>, <span class="pos">adj.</span> Unable to exist if something else exists. Two things are incompossible
+when the world of being has scope enough for one of them, but not enough for
+both—as Walt Whitman’s poetry and God’s mercy to man. Incompossibility, it will
+be seen, is only incompatibility let loose. Instead of such low language as “Go
+heel yourself—I mean to kill you on sight,” the words, “Sir, we are
+incompossible,” would convey and equally significant intimation and in stately
+courtesy are altogether superior.</p>
+
+<p class="entry"><span class="def">Incubus</span>, <span class="pos">n.</span> One of a race of highly improper demons who, though probably not wholly extinct, may
+be said to have seen their best nights. For a complete account of <i>incubi</i> and <i>succubi</i>, including <i>incubae</i>
+and <i>succubae</i>, see the <i>Liber Demonorum</i> of Protassus (Paris,
+1328), which contains much curious information that would be out of place in a
+dictionary intended as a text-book for the public schools.</p>
+
+<p>Victor Hugo relates that in the Channel Islands Satan himself—tempted more than elsewhere
+by the beauty of the women, doubtless—sometimes plays at <i>incubus</i>, greatly to the inconvenience and
+alarm of the good dames who wish to be loyal to their marriage vows, generally
+speaking. A certain lady applied to the parish priest to learn how they might,
+in the dark, distinguish the hardy intruder from their husbands. The holy man
+said they must feel his brown for horns; but Hugo is ungallant enough to hint a
+doubt of the efficacy of the test.</p>
+
+<p class="entry"><span class="def">incumbent</span>, <span class="pos">n.</span> A
+person of the liveliest interest to the outcumbents.</p>
+
+<p class="entry"><span class="def">indecision</span>, <span class="pos">n.</span> The
+chief element of success; “for whereas,” saith Sir Thomas Brewbold, “there is
+but one way to do nothing and divers way to do something, whereof, to a surety,
+only one is the right way, it followeth that he who from indecision standeth
+still hath not so many chances of going astray as he who pusheth forwards”—a
+most clear and satisfactory exposition on the matter.</p>
+
+<p class="dialog">“Your prompt decision to attack,” said Genera Grant
+on a certain occasion to General Gordon Granger, “was admirable; you had but five minutes
+to make up your mind in.”</p>
+
+<p class="dialog">“Yes, sir,” answered the victorious subordinate,
+“it is a great thing to be know exactly what to do in an emergency. When in doubt
+whether to attack or retreat I never hesitate a moment—I toss us a copper.”</p>
+
+<p class="dialog">“Do you mean to say that’s what you did this time?”</p>
+<p class="dialog">“Yes, General; but for Heaven’s sake don’t reprimand me: I disobeyed the coin.”</p>
+
+<p class="entry"><span class="def">indifferent</span>, <span class="pos">adj.</span> Imperfectly
+sensible to distinctions among things.</p>
+
+<div class="poem">
+<p class="poetry">“You tiresome man!” cried Indolentio’s wife,<br />
+“You’ve grown indifferent to all in life.”<br />
+“Indifferent?” he drawled with a slow smile;<br />
+“I would be, dear, but it is not worth while.”</p>
+<p class="citeauth">Apuleius M. Gokul</p>
+</div>
+
+<p class="entry"><span class="def">indigestion</span>, <span class="pos">n.</span> A
+disease which the patient and his friends frequently mistake for deep religious
+conviction and concern for the salvation of mankind. As the simple Red Man of
+the western wild put it, with, it must be confessed, a certain force: “Plenty
+well, no pray; big bellyache, heap God.”</p>
+
+<p class="entry"><span class="def">indiscretion</span>, <span class="pos">n.</span> The guilt of woman.</p>
+
+<p class="entry"><span class="def">inexpedient</span>, <span class="pos">adj.</span> Not calculated
+to advance one’s interests.</p>
+
+<p class="entry"><span class="def">infancy</span>, <span class="pos">n.</span> The
+period of our lives when, according to Wordsworth, “Heaven lies about us.” The
+world begins lying about us pretty soon afterward.</p>
+
+<p class="entry"><span class="def">Inferiae,</span> <span class="pos">n.</span> [Latin] Among the Greeks and Romans, sacrifices
+for propitation of the <i>Dii Manes</i>, or souls of the dead heroes;
+for the pious ancients could not invent enough gods to satisfy their spiritual
+needs, and had to have a number of makeshift deities, or, as a sailor might
+say, jury-gods, which they made out of the most unpromising materials. It was
+while sacrificing a bullock to the spirit of Agamemnon that Laiaides, a priest
+of Aulis, was favored with an audience of that illustrious warrior’s shade, who
+prophetically recounted to him the birth of Christ and the triumph of
+Christianity, giving him also a rapid but tolerably complete review of events
+down to the reign of Saint Louis. The narrative ended abruptly at the point,
+owing to the inconsiderate crowing of a cock, which compelled the ghosted King
+of Men to scamper back to Hades. There is a fine mediaeval flavor to this
+story, and as it has not been traced back further than Pere Brateille, a pious
+but obscure writer at the court of Saint Louis, we shall probably not err on
+the side of presumption in considering it apocryphal, though Monsignor Capel’s
+judgment of the matter might be different; and to that I bow—wow.</p>
+
+<p class="entry"><span class="def">infidel</span>, <span class="pos">n.</span> In New
+York, one who does not believe in the Christian religion; in Constantinople,
+one who does. (See GIAOUR.) A kind of scoundrel imperfectly reverent of, and
+niggardly contributory to, divines, ecclesiastics, popes, parsons, canons,
+monks, mollahs, voodoos, presbyters, hierophants, prelates, obeah-men, abbes,
+nuns, missionaries, exhorters, deacons, friars, hadjis, high-priests, muezzins,
+brahmins, medicine-men, confessors, eminences, elders, primates, prebendaries,
+pilgrims, prophets, imaums, beneficiaries, clerks, vicars-choral, archbishops,
+bishops, abbots, priors, preachers, padres, abbotesses, caloyers, palmers,
+curates, patriarchs, bonezs, santons, beadsmen, canonesses, residentiaries,
+diocesans, deans, subdeans, rural deans, abdals, charm-sellers, archdeacons,
+hierarchs, class-leaders, incumbents, capitulars, sheiks, talapoins,
+postulants, scribes, gooroos, precentors, beadles, fakeers, sextons,
+reverences, revivalists, cenobites, perpetual curates, chaplains, mudjoes,
+readers, novices, vicars, pastors, rabbis, ulemas, lamas, sacristans, vergers,
+dervises, lectors, church wardens, cardinals, prioresses, suffragans, acolytes,
+rectors, cures, sophis, mutifs and pumpums.</p>
+
+<p class="entry"><span class="def">influence</span>, <span class="pos">n.</span> In politics,
+a visionary <i>quo</i> given in exchange for a substantial <i>quid</i>.</p>
+
+<p class="entry"><span class="def">Infalapsarian</span>, <span class="pos">n.</span> One
+who ventures to believe that Adam need not have sinned unless he had a mind
+to—in opposition to the Supralapsarians, who hold that that luckless person’s
+fall was decreed from the beginning. Infralapsarians are sometimes called
+Sublapsarians without material effect upon the importance and lucidity of their
+views about Adam.</p>
+
+<div class="poem">
+<p class="poetry">Two theologues once, as they wended their way</p>
+<p class="poetry">To chapel, engaged in colloquial fray—</p>
+<p class="poetry">An earnest logomachy, bitter as gall,</p>
+<p class="poetry">Concerning poor Adam and what made him fall.<br />
+“’Twas Predestination,” cried one—“for the Lord<br />
+Decreed he should fall of his own accord.”<br />
+“Not so—‘twas Free will,” the other maintained,<br />
+“Which led him to choose what the Lord had ordained.”<br />
+So fierce and so fiery grew the debate<br />
+That nothing but bloodshed their dudgeon could sate;</p>
+<p class="poetry">So off flew their
+cassocks and caps to the ground And, moved by the spirit, their hands went
+round. Ere either had proved his theology right By winning, or even beginning,
+the fight, A gray old professor of Latin came by, A staff in his hand and a
+scowl in his eye, And learning the cause of their quarrel (for still As they
+clumsily sparred they disputed with skill Of foreordination freedom of will)</p>
+<p class="poetry">Cried: “Sirrahs! this reasonless warfare compose:</p>
+<p class="poetry">Atwixt ye’s no
+difference worthy of blows. The sects ye belong to—I’m ready to swear Ye
+wrongly interpret the names that they bear. <i>You</i>
+—Infralapsarian son of a clown!—</p>
+<p class="poetry">Should only contend that Adam slipped down;</p>
+<p class="poetry">While <i>you</i>—you Supralapsarian pup!—</p>
+<p class="poetry">Should nothing aver but that Adam slipped up.</p>
+<p class="poetry">It’s all the same whether up or down</p>
+<p class="poetry">You slip on a peel of banana brown.</p>
+<p class="poetry">Even Adam analyzed not his blunder,</p>
+<p class="poetry">But thought he had slipped on a peal of thunder!</p>
+<p class="citeauth">G. J.</p>
+</div>
+<p class="entry"><span class="def">ingrate</span>, <span class="pos">n.</span> One
+who receives a benefit from another, or is otherwise an object of charity.</p>
+
+<div class="poem">
+<p class="poetry">“All men are ingrates,” sneered the cynic. “Nay,”</p>
+<p class="poetry">The good philanthropist replied;</p>
+<p class="poetry">“I did great service to a man one day</p>
+<p class="poetry">Who never since has cursed me to repay,</p>
+<p class="poetry">Nor vilified.”</p>
+<p class="poetry">“Ho!” cried the cynic, “lead me to him straight—</p>
+<p class="poetry">With veneration I am overcome,</p>
+<p class="poetry">And fain would have his blessing.” “Sad your fate—</p>
+<p class="poetry">He cannot bless you, for AI grieve to state</p>
+<p class="poetry">This man is dumb.”</p>
+<p class="citeauth">Ariel Selp</p>
+</div>
+
+<p class="entry"><span class="def">injury</span>, <span class="pos">n.</span> An
+offense next in degree of enormity to a slight.</p>
+
+<p class="entry"><span class="def">injustice</span>, <span class="pos">n.</span> A
+burden which of all those that we load upon others and carry ourselves is
+lightest in the hands and heaviest upon the back.</p>
+
+<p class="entry"><span class="def">ink</span>, <span class="pos">n.</span> A
+villainous compound of tannogallate of iron, gum-arabic and water, chiefly used
+to facilitate the infection of idiocy and promote intellectual crime. The
+properties of ink are peculiar and contradictory: it may be used to make
+reputations and unmake them; to blacken them and to make them white; but it is
+most generally and acceptably employed as a mortar to bind together the stones
+of an edifice of fame, and as a whitewash to conceal afterward the rascal
+quality of the material. There are men called journalists who have established
+ink baths which some persons pay money to get into, others to get out of. Not
+infrequently it occurs that a person who has paid to get in pays twice as much
+to get out.</p>
+
+<p class="entry"><span class="def">innate</span>, <span class="pos">adj.</span> Natural,
+inherent—as innate ideas, that is to say, ideas that we are born with, having
+had them previously imparted to us. The doctrine of innate ideas is one of the
+most admirable faiths of philosophy, being itself an innate idea and therefore
+inaccessible to disproof, though Locke foolishly supposed himself to have given
+it “a black eye.” Among innate ideas may be mentioned the belief in one’s
+ability to conduct a newspaper, in the greatness of one’s country, in the
+superiority of one’s civilization, in the importance of one’s personal affairs
+and in the interesting nature of one’s diseases.</p>
+
+<p class="entry"><span class="def">in’ards</span>, <span class="pos">n.</span> The
+stomach, heart, soul and other bowels. Many eminent investigators do not class
+the soul as an in’ard, but that acute observer and renowned authority, Dr.
+Gunsaulus, is persuaded that the mysterious organ known as the spleen is
+nothing less than our important part. To the contrary, Professor Garrett P.
+Servis holds that man’s soul is that prolongation of his spinal marrow which
+forms the pith of his no tail; and for demonstration of his faith points
+confidently to the fact that no tailed animals have no souls. Concerning these
+two theories, it is best to suspend judgment by believing both.</p>
+
+<p class="entry"><span class="def">inscription</span>, <span class="pos">n.</span> Something
+written on another thing. Inscriptions are of many kinds, but mostly memorial,
+intended to commemorate the fame of some illustrious person and hand down to
+distant ages the record of his services and virtues. To this class of
+inscriptions belongs the name of John Smith, penciled on the Washington
+monument. Following are examples of memorial inscriptions on tombstones: (See
+EPITAPH.)</p>
+
+<div class="poem">
+<p class="poetry">“In the sky my soul is found,</p>
+<p class="poetry">And my body in the ground.</p>
+<p class="poetry">By and by my body’ll rise</p>
+<p class="poetry">To my spirit in the skies,</p>
+<p class="poetry">Soaring up to Heaven’s gate.</p>
+<p class="poetry">1878.”</p>
+<p class="poetry">“Sacred to the memory of Jeremiah Tree. Cut down May 9<sup>th</sup>, 1862, aged 27 yrs. 4 mos.
+and 12 ds. Indigenous.”</p>
+<p class="poetry">“Affliction sore long time she boar,</p>
+<p class="poetry">Phisicians was in vain,</p>
+<p class="poetry">Till Deth released the dear deceased</p>
+<p class="poetry">And left her a remain.</p>
+<p class="poetry">Gone to join Ananias in the regions of bliss.”</p>
+<p class="poetry">“The clay that rests beneath this stone</p>
+<p class="poetry">As Silas Wood was widely known.</p>
+<p class="poetry">Now, lying here, I ask what good</p>
+<p class="poetry">It was to let me be S. Wood.</p>
+<p class="poetry">O Man, let not ambition trouble you,</p>
+<p class="poetry">Is the advice of Silas W.”</p>
+<p class="citeauth">“Richard Haymon, of Heaven. Fell to Earth Jan. 20, 1807, and had the dust brushed off him Oct.
+3, 1874.”</p>
+</div>
+
+<p class="entry"><span class="def">insectivora</span>, <span class="pos">n.</span></p>
+
+<div class="poem">
+<p class="poetry">“See,” cries the chorus of admiring preachers, “How Providence provides for all His creatures!”</p>
+<p class="poetry">“His care,” the gnat said, “even the insects follows:</p>
+<p class="poetry">For us He has provided wrens and swallows.”</p>
+<p class="citeauth">Sempen Railey</p>
+</div>
+
+<p class="entry"><span class="def">insurance</span>, <span class="pos">n.</span> An
+ingenious modern game of chance in which the player is permitted to enjoy the
+comfortable conviction that he is beating the man who keeps the table.</p>
+
+<p class="dialog">INSURANCE AGENT: My
+dear sir, that is a fine house—pray let me insure it.</p>
+
+<p class="dialog">HOUSE OWNER: With pleasure. Please make the annual premium so low that by the
+time when, according to the tables of your actuary, it will probably be
+destroyed by fire I will have paid you considerably less than the face of the policy.</p>
+
+<p class="dialog">INSURANCE AGENT: O dear, no—we could not afford to do that. </p>
+
+<p class="dialog">We must fix the premium so that you will have paid more.</p>
+
+<p class="dialog">HOUSE OWNER: How, then, can <i>I</i> afford <i>that</i>?</p>
+
+<p class="dialog">INSURANCE AGENT: Why, your house may burn down at any time. </p>
+
+<p class="dialog">There was Smith’s house, for example, which—</p>
+
+<p class="dialog">HOUSE OWNER: Spare me—there were Brown’s house, on the contrary, and
+Jones’s house, and Robinson’s house, which—</p>
+
+<p class="dialog">INSURANCE AGENT: Spare <i>me</i>!</p>
+
+<p class="dialog">HOUSE OWNER: Let us understand each other. You want me to pay you money on the
+supposition that something will occur previously to the time set by yourself
+for its occurrence. In other words, you expect me to bet that my house will not
+last so long as you say that it will probably last.</p>
+
+<p class="dialog">INSURANCE AGENT: But if your house burns without insurance it will be a total loss.</p>
+
+<p class="dialog">HOUSE OWNER: Beg your pardon—by your own actuary’s tables I shall probably
+have saved, when it burns, all the premiums I would otherwise have paid to
+you—amounting to more than the face of the policy they would have bought. But
+suppose it to burn, uninsured, before the time upon which your figures are
+based. If I could not afford that, how could you if it were insured?</p>
+
+<p class="dialog">INSURANCE AGENT: O, we should make ourselves whole from our luckier ventures
+with other clients. Virtually, they pay your loss.</p>
+
+<p class="dialog">HOUSE OWNER: And virtually, then, don’t I help to pay their losses? Are not
+their houses as likely as mine to burn before they have paid you as much as you
+must pay them? The case stands this way: you expect to take more money from
+your clients than you pay to them, do you not?</p>
+
+<p class="dialog">INSURANCE AGENT: Certainly; if we did not—</p>
+
+<p class="dialog">HOUSE OWNER: I would not trust you with my money. Very well then. If it is <i>certain</i>, with
+reference to the whole body of your clients, that they lose money on you it is <i>probable</i>, with
+reference to any one of them, that <i>he</i> will. It is these individual
+probabilities that make the aggregate certainty.</p>
+
+<p class="dialog">INSURANCE AGENT: I will not deny it—but look at the figures in this pamph—</p>
+
+<p class="dialog">HOUSE OWNER: Heaven forbid!</p>
+
+<p class="dialog">INSURANCE AGENT: You spoke of saving the premiums which you would otherwise pay to
+me. Will you not be more likely to squander them? We offer you an incentive to thrift.</p>
+
+<p class="dialog">HOUSE OWNER: The willingness of A to take care of B’s money is not peculiar to
+insurance, but as a charitable institution you command esteem. Deign to accept
+its expression from a Deserving Object.</p>
+
+<p class="entry"><span class="def">insurrection</span>, <span class="pos">n.</span> An
+unsuccessful revolution. Disaffection’s failure to substitute misrule for bad government.</p>
+
+<p class="entry"><span class="def">intention</span>, <span class="pos">n.</span> The
+mind’s sense of the prevalence of one set of influences over another set; an
+effect whose cause is the imminence, immediate or remote, of the performance of
+an involuntary act.</p>
+
+<p class="entry"><span class="def">interpreter</span>, <span class="pos">n.</span> One
+who enables two persons of different languages to understand each other by
+repeating to each what it would have been to the interpreter’s advantage for
+the other to have said.</p>
+
+<p class="entry"><span class="def">interregnum</span>, <span class="pos">n.</span> The
+period during which a monarchical country is governed by a warm spot on the
+cushion of the throne. The experiment of letting the spot grow cold has
+commonly been attended by most unhappy results from the zeal of many worthy
+persons to make it warm again.</p>
+
+<p class="entry"><span class="def">intimacy</span>, <span class="pos">n.</span> A
+relation into which fools are providentially drawn for their mutual destruction.</p>
+
+<div class="poem">
+<p class="poetry">Two Seidlitz powders, one in blue</p>
+<p class="poetry">And one in white, together drew</p>
+<p class="poetry">And having each a pleasant sense</p>
+<p class="poetry">Of t’other powder’s excellence,</p>
+<p class="poetry">Forsook their jackets for the snug</p>
+<p class="poetry">Enjoyment of a common mug.</p>
+<p class="poetry">So close their intimacy grew</p>
+<p class="poetry">One paper would have held the two.</p>
+<p class="poetry">To confidences straight they fell,</p>
+<p class="poetry">Less anxious each to hear than tell;</p>
+<p class="poetry">Then each remorsefully confessed</p>
+<p class="poetry">To all the virtues he possessed,</p>
+<p class="poetry">Acknowledging he had them in</p>
+<p class="poetry">So high degree it was a sin.</p>
+<p class="poetry">The more they said, the more they felt</p>
+<p class="poetry">Their spirits with emotion melt,</p>
+<p class="poetry">Till tears of sentiment expressed</p>
+<p class="poetry">Their feelings. Then they effervesced!</p>
+<p class="poetry">So Nature executes her feats</p>
+<p class="poetry">Of wrath on friends and sympathetes</p>
+<p class="poetry">The good old rule who don’t apply,</p>
+<p class="poetry">That you are you and I am I.</p>
+</div>
+
+<p class="entry"><span class="def">introduction</span>, <span class="pos">n.</span> A
+social ceremony invented by the devil for the gratification of his servants and
+the plaguing of his enemies. The introduction attains its most malevolent
+development in this century, being, indeed, closely related to our political
+system. Every American being the equal of every other American, it follows that
+everybody has the right to know everybody else, which implies the right to
+introduce without request or permission. The Declaration of Independence should
+have read thus:</p>
+
+<p class="quote">“We hold these truths to be self-evident: that all men are created equal; that they are
+endowed by their Creator with certain inalienable rights; that among these are
+life, and the right to make that of another miserable by thrusting upon him an
+incalculable quantity of acquaintances; liberty, particularly the liberty to
+introduce persons to one another without first ascertaining if they are not
+already acquainted as enemies; and the pursuit of another’s happiness with a
+running pack of strangers.”</p>
+
+<p class="entry"><span class="def">inventor</span>, <span class="pos">n.</span> A
+person who makes an ingenious arrangement of wheels, levers and springs, and
+believes it civilization.</p>
+
+<p class="entry"><span class="def">irreligion</span>, <span class="pos">n.</span> The
+principal one of the great faiths of the world.</p>
+
+<p class="entry"><span class="def">itch</span>, <span class="pos">n.</span> The
+patriotism of a Scotchman.</p>
+
+
+</body>
+</html>
\ No newline at end of file
--- /dev/null
+++ b/lib/ebooks/devils/I.html.i
@@ -1,0 +1,62 @@
+29 pages
+size 400 552
+length 40130
+396 2 10 body html
+0
+1452 2 34 body html
+56
+2967 2 55 body html
+216
+4626 2 82 body html
+108
+4626 2 82 body html
+648
+6344 2 114 body html
+141
+7343 2 133 body html
+243
+9427 2 161 body html
+252
+9427 2 161 body html
+790
+11521 2 200 body html
+73
+13272 2 224 body html
+124
+14087 2 234 body html
+451
+14087 2 234 body html
+991
+16500 2 279 body html
+0
+18562 2 306 body html
+0
+20433 2 334 body html
+0
+22151 2 367 body html
+0
+23431 2 384 body html
+209
+25306 2 412 body html
+246
+27137 2 443 body html
+0
+28326 2 467 body html
+22
+30507 2 499 body html
+0
+30991 2 507 body html
+413
+32627 2 540 body html
+39
+34139 2 571 body html
+0
+35615 2 596 body html
+0
+37320 2 627 body html
+36
+37320 2 627 body html
+576
+39859 2 673 body html
+0
+income 12
--- /dev/null
+++ b/lib/ebooks/devils/J.html
@@ -1,0 +1,74 @@
+<?xml version="1.0"?>
+<!DOCTYPE package PUBLIC "+//ISBN 0-9673008-1-9//DTD OEB 1.0 Package//EN"
+ "http://openebook.org/dtds/oeb-1.0/oebdoc1.dtd">
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/x-oeb1-document; charset=utf-8" />
+<link rel="stylesheet" type="text/x-oeb1-css" href="devil.css" />
+<title>The Devil’s Dictionary: J</title>
+</head>
+<body lang="en-US">
+
+<h1>J</h1>
+
+<p class="firstpara">J is a consonant in English, but some nations use it as a vowel—than which nothing could be more
+absurd. Its original form, which has been but slightly modified, was that of
+the tail of a subdued dog, and it was not a letter but a character, standing
+for a Latin verb, <i>jacere</i>, “to throw,” because when a stone is thrown at a dog the dog’s tail assumes that
+shape. This is the origin of the letter, as expounded by the renowned Dr.
+Jocolpus Bumer, of the University of Belgrade, who established his conclusions
+on the subject in a work of three quarto volumes and committed suicide on being
+reminded that the j in the Roman alphabet had originally no curl.</p>
+
+<p class="entry"><span class="def">jealous</span>, <span class="pos">adj.</span> Unduly
+concerned about the preservation of that which can be lost only if not worth keeping.</p>
+
+<p class="entry"><span class="def">jester</span>, <span class="pos">n.</span> An
+officer formerly attached to a king’s household, whose business it was to amuse
+the court by ludicrous actions and utterances, the absurdity being attested by
+his motley costume. The king himself being attired with dignity, it took the
+world some centuries to discover that his own conduct and decrees were
+sufficiently ridiculous for the amusement not only of his court but of all
+mankind. The jester was commonly called a fool, but the poets and romancers have
+ever delighted to represent him as a singularly wise and witty person. In the
+circus of to-day the melancholy ghost of the court fool effects the dejection
+of humbler audiences with the same jests wherewith in life he gloomed the
+marble hall, panged the patrician sense of humor and tapped the tank of royal tears.</p>
+
+<div class="poem">
+<p class="poetry">The widow-queen of Portugal</p>
+<p class="poetry">Had an audacious jester</p>
+<p class="poetry">Who entered the confessional</p>
+<p class="poetry">Disguised, and there confessed her.</p>
+<p class="poetry">“Father,” she said, “thine ear bend down—</p>
+<p class="poetry">My sins are more than scarlet:</p>
+<p class="poetry">I love my fool—blaspheming clown,</p>
+<p class="poetry">And common, base-born varlet.”</p>
+<p class="poetry">“Daughter,” the mimic priest replied,</p>
+<p class="poetry">“That sin, indeed, is awful:</p>
+<p class="poetry">The church’s pardon is denied</p>
+<p class="poetry"> To love that is unlawful.</p>
+<p class="poetry">“But since thy stubborn heart will be</p>
+<p class="poetry">For him forever pleading,</p>
+<p class="poetry">Thou’dst better make him, by decree,</p>
+<p class="poetry">A man of birth and breeding.”</p>
+<p class="poetry">She made the fool a duke, in hope</p>
+<p class="poetry">With Heaven’s taboo to palter;</p>
+<p class="poetry">Then told a priest, who told the Pope,</p>
+<p class="poetry">Who damned her from the altar!</p>
+<p class="citeauth">Barel Dort</p>
+</div>
+
+<p class="entry"><span class="def">Jews-harp</span>, <span class="pos">n.</span> An
+unmusical instrument, played by holding it fast with the teeth and trying to brush it away with the finger.</p>
+
+<p class="entry"><span class="def">Joss-sticks</span>, <span class="pos">n.</span> Small
+sticks burned by the Chinese in their pagan tomfoolery, in imitation of certain sacred rites of our holy religion.</p>
+
+<p class="entry"><span class="def">justice</span>, <span class="pos">n.</span> A
+commodity which is a more or less adulterated condition the State sells to the
+citizen as a reward for his allegiance, taxes and personal service.</p>
+
+
+</body>
+</html>
\ No newline at end of file
--- /dev/null
+++ b/lib/ebooks/devils/J.html.i
@@ -1,0 +1,9 @@
+3 pages
+size 400 552
+length 3986
+396 2 10 body html
+0
+1286 2 26 body html
+209
+2152 2 38 body html
+523
--- /dev/null
+++ b/lib/ebooks/devils/K.html
@@ -1,0 +1,137 @@
+<?xml version="1.0"?>
+<!DOCTYPE package PUBLIC "+//ISBN 0-9673008-1-9//DTD OEB 1.0 Package//EN"
+ "http://openebook.org/dtds/oeb-1.0/oebdoc1.dtd">
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/x-oeb1-document; charset=utf-8" />
+<link rel="stylesheet" type="text/x-oeb1-css" href="devil.css" />
+<title>The Devil’s Dictionary: K</title>
+</head>
+<body lang="en-US">
+
+
+<h1>K</h1>
+
+<p class="firstpara">K is a consonant that we get from the Greeks, but it can be traced away back beyond them to the
+Cerathians, a small commercial nation inhabiting the peninsula of Smero. In
+their tongue it was called <i>Klatch</i>, which means “destroyed.” The form of the letter was originally precisely that
+of our H, but the erudite Dr. Snedeker explains that it was altered to its
+present shape to commemorate the destruction of the great temple of Jarute by
+an earthquake, <i>circa</i> 730 B.C. This building was famous for the two lofty columns of its portico, one of which was
+broken in half by the catastrophe, the other remaining intact. As the earlier
+form of the letter is supposed to have been suggested by these pillars, so, it
+is thought by the great antiquary, its later was adopted as a simple and
+natural—not to say touching—means of keeping the calamity ever in the national
+memory. It is not known if the name of the letter was altered as an additional
+mnemonic, or if the name was always <i>Klatch</i> and the destruction one of nature’s pums. As each theory seems probable enough,
+I see no objection to believing both—and Dr. Snedeker arrayed himself on that side of the question.</p>
+
+<p class="entry"><span class="def">keep</span>, <span class="pos">v.t.</span></p>
+
+<div class="poem">
+<p class="poetry">He willed away his whole estate,</p>
+<p class="poetry">And then in death he fell asleep,</p>
+<p class="poetry">Murmuring: “Well, at any rate,</p>
+<p class="poetry">My name unblemished I shall keep.”</p>
+<p class="poetry">But when upon the tomb ‘twas wrought Whose was it?—for the dead keep naught.</p>
+<p class="citeauth">Durang Gophel Arn</p>
+</div>
+
+<p class="entry"><span class="def">kill</span>, <span class="pos">v.t.</span> To
+create a vacancy without nominating a successor.</p>
+
+<p class="entry"><span class="def">kilt</span>, <span class="pos">n.</span> A costume
+sometimes worn by Scotchmen in America and Americans in Scotland.</p>
+
+<p class="entry"><span class="def">kindness</span>, <span class="pos">n.</span> A
+brief preface to ten volumes of exaction.</p>
+
+<p id="king" class="entry"><span class="def">king</span>, <span class="pos">n.</span> A male
+person commonly known in America as a “crowned head,” although he never wears a
+crown and has usually no head to speak of.</p>
+
+<div class="poem">
+<p class="poetry">A king, in times long, long gone by,</p>
+<p class="poetry">Said to his lazy jester:</p>
+<p class="poetry">“If I were you and you were I</p>
+<p class="poetry">My moments merrily would fly—</p>
+<p class="poetry">Nor care nor grief to pester.”</p>
+<p class="poetry">“The reason, Sire, that you would thrive,”</p>
+<p class="poetry">The fool said—“if you’ll hear it—</p>
+<p class="poetry">Is that of all the fools alive</p>
+<p class="poetry">Who own you for their sovereign, I’ve</p>
+<p class="poetry">The most forgiving spirit.”</p>
+<p class="citeauth">Oogum Bem</p>
+</div>
+
+<p class="entry"><span class="def">King’s Evil</span>, <span class="pos">n.</span> A
+malady that was formerly cured by the touch of the sovereign, but has now to be
+treated by the physicians. Thus ‘the most pious Edward” of England used to lay
+his royal hand upon the ailing subjects and make them whole—</p>
+
+<div class="poem">
+<p class="poetry">a crowd of wretched souls</p>
+<p class="poetry">That stay his cure: their malady convinces</p>
+<p class="poetry">The great essay of art; but at his touch,</p>
+<p class="poetry">Such sanctity hath Heaven given his hand,</p>
+<p class="poetry">They presently amend,</p>
+<p class="poetry">as the “Doctor” in <i>Macbeth</i> hath it. This useful property of the </p>
+<p class="poetry">royal hand could, it appears, be transmitted along with other crown </p>
+<p class="poetry">properties; for according to “Malcolm,”</p>
+<p class="poetry">‘tis spoken To the succeeding royalty he leaves The healing benediction.</p>
+<p class="poetry">But the gift somewhere dropped out of the line of succession: the later sovereigns of
+England have not been tactual healers, and the disease once honored with the
+name “king’s evil” now bears the humbler one of “scrofula,” from <i>scrofa</i>, a sow. The date and author of the
+following epigram are known only to the author of this dictionary, but it is
+old enough to show that the jest about Scotland’s national disorder is not a
+thing of yesterday.</p>
+<p class="poetry">Ye Kynge his evill in me laye,</p>
+<p class="poetry">Wh. he of Scottlande charmed awaye.</p>
+<p class="poetry">He layde his hand on mine and sayd:</p>
+<p class="poetry">“Be gone!” Ye ill no longer stayd.</p>
+<p class="poetry">But O ye wofull plyght in wh.</p>
+<p class="poetry">I’m now y-pight: I have ye itche!</p>
+<p class="poetry">The superstitionth at maladies can be cured by royal taction is </p>
+<p class="poetry">dead, but like many a departed conviction it has left a monument of </p>
+<p class="poetry">custom to keep its memory green. The practice of forming a line and </p>
+<p class="poetry">shaking the President’s hand had no other origin, and when that great </p>
+<p class="poetry">dignitary bestows his healing salutation on</p>
+<p class="poetry">strangely visited people,</p>
+<p class="poetry">All swoln and ulcerous, pitiful to the eye,</p>
+<p class="poetry">The mere despair of surgery,</p>
+<p class="poetry">he and his patients are handing along an extinguished torch which once was kindled at the
+altar-fire of a faith long held by all classes of men. It is a beautiful and
+edifying “survival”—one which brings the sainted past close home in our “business and bosoms.”</p>
+</div>
+
+<p class="entry"><span class="def">kiss</span>, <span class="pos">n.</span> A word
+invented by the poets as a rhyme for “bliss.” It is supposed to signify, in a
+general way, some kind of rite or ceremony appertaining to a good
+understanding; but the manner of its performance is unknown to this lexicographer.</p>
+
+<p class="entry"><span class="def">kleptomaniac</span>, <span class="pos">n.</span> A
+rich thief.</p>
+
+<p class="entry"><span class="def">knight</span>, <span class="pos">n.</span></p>
+
+<div class="poem">
+<p class="poetry">Once a warrior gentle of birth,</p>
+<p class="poetry">Then a person of civic worth,</p>
+<p class="poetry">Now a fellow to move our mirth.</p>
+<p class="poetry">Warrior, person, and fellow—no more:</p>
+<p class="poetry">We must knight our dogs to get any lower.</p>
+<p class="poetry">Brave Knights Kennelers then shall be,</p>
+<p class="poetry">Noble Knights of the Golden Flea,</p>
+<p class="poetry">Knights of the Order of St. Steboy,</p>
+<p class="poetry">Knights of St. Gorge and Sir Knights Jawy.</p>
+<p class="poetry">God speed the day when this knighting fad</p>
+<p class="poetry">Shall go to the dogs and the dogs go mad.</p>
+</div>
+
+<p class="entry"><span class="def">Koran</span>, <span class="pos">n.</span> A book
+which the Mohammedans foolishly believe to have been written by divine
+inspiration, but which Christians know to be a wicked imposture, contradictory
+to the Holy Scriptures.</p>
+
+</body>
+</html>
\ No newline at end of file
--- /dev/null
+++ b/lib/ebooks/devils/K.html.i
@@ -1,0 +1,16 @@
+6 pages
+size 400 552
+length 7556
+396 2 10 body html
+0
+1716 2 31 body html
+91
+2763 2 53 body html
+252
+3711 2 72 body html
+305
+3711 2 72 body html
+854
+6594 2 117 body html
+91
+king 1
--- /dev/null
+++ b/lib/ebooks/devils/L.html
@@ -1,0 +1,525 @@
+<?xml version="1.0"?>
+<!DOCTYPE package PUBLIC "+//ISBN 0-9673008-1-9//DTD OEB 1.0 Package//EN"
+ "http://openebook.org/dtds/oeb-1.0/oebdoc1.dtd">
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/x-oeb1-document; charset=utf-8" />
+<link rel="stylesheet" type="text/x-oeb1-css" href="devil.css" />
+<title>The Devil’s Dictionary: L</title>
+</head>
+<body lang="en-US">
+
+<h1>L</h1>
+
+<p class="entry"><span class="def">labor</span>, <span class="pos">n.</span> One of
+the processes by which A acquires property for B.</p>
+
+<p class="entry"><span class="def">land</span>, <span class="pos">n.</span> A part of
+the earth’s surface, considered as property. The theory that land is property
+subject to private ownership and control is the foundation of modern society,
+and is eminently worthy of the superstructure. Carried to its logical
+conclusion, it means that some have the right to prevent others from living;
+for the right to own implies the right exclusively to occupy; and in fact laws
+of trespass are enacted wherever property in land is recognized. It follows
+that if the whole area of <i>terra firma</i>
+is owned by A, B and C, there will be no place for D, E, F and G to be born,
+or, born as trespassers, to exist.</p>
+
+<div class="poem">
+<p class="poetry">A life on the ocean wave,</p>
+<p class="poetry">A home on the rolling deep,</p>
+<p class="poetry">For the spark the nature gave</p>
+<p class="poetry">I have there the right to keep.</p>
+<p class="poetry">They give me the cat-o’-nine</p>
+<p class="poetry">Whenever I go ashore.</p>
+<p class="poetry">Then ho! for the flashing brine—</p>
+<p class="poetry">I’m a natural commodore!</p>
+<p class="citeauth">Dodle</p>
+</div>
+
+<p class="entry"><span class="def">language</span>, <span class="pos">n.</span> The
+music with which we charm the serpents guarding another’s treasure.</p>
+
+<p class="entry"><span class="def">Laocoon</span>, <span class="pos">n.</span> A
+famous piece of antique scripture representing a priest of that name and his
+two sons in the folds of two enormous serpents. The skill and diligence with
+which the old man and lads support the serpents and keep them up to their work
+have been justly regarded as one of the noblest artistic illustrations of the
+mastery of human intelligence over brute inertia.</p>
+
+<p class="entry"><span class="def">lap</span>, <span class="pos">n.</span> One of the
+most important organs of the female system—an admirable provision of nature for
+the repose of infancy, but chiefly useful in rural festivities to support
+plates of cold chicken and heads of adult males. The male of our species has a
+rudimentary lap, imperfectly developed and in no way contributing to the
+animal’s substantial welfare.</p>
+
+<p class="entry"><span class="def">last</span>, <span class="pos">n.</span> A
+shoemaker’s implement, named by a frowning Providence as opportunity to the
+maker of puns.</p>
+
+<div class="poem">
+<p class="poetry">Ah, punster, would my lot were cast,</p>
+<p class="poetry">Where the cobbler is unknown,</p>
+<p class="poetry">So that I might forget his last</p>
+<p class="poetry">And hear your own.</p>
+<p class="citeauth">Gargo Repsky</p>
+</div>
+
+<p class="entry"><span class="def">laughter</span>, <span class="pos">n.</span> An
+interior convulsion, producing a distortion of the features and accompanied by
+inarticulate noises. It is infectious and, though intermittent, incurable. Liability
+to attacks of laughter is one of the characteristics distinguishing man from
+the animals—these being not only inaccessible to the provocation of his
+example, but impregnable to the microbes having original jurisdiction in
+bestowal of the disease. Whether laughter could be imparted to animals by
+inoculation from the human patient is a question that has not been answered by
+experimentation. Dr. Meir Witchell holds that the infection character of
+laughter is due to the instantaneous fermentation of <i>sputa</i> diffused in a spray. From this peculiarity he names
+the disorder <i>Convulsio spargens</i>.</p>
+
+<p class="entry"><span class="def">laureate</span>, <span class="pos">adj.</span> Crowned
+with leaves of the laurel. In England the Poet Laureate is an officer of the
+sovereign’s court, acting as dancing skeleton at every royal feast and
+singing-mute at every royal funeral. Of all incumbents of that high office,
+Robert Southey had the most notable knack at drugging the Samson of public joy
+and cutting his hair to the quick; and he had an artistic color-sense which
+enabled him so to blacken a public grief as to give it the aspect of a national
+crime.</p>
+
+<p class="entry"><span class="def">laurel</span>, <span class="pos">n.</span> The <i>laurus</i>, a vegetable dedicated to Apollo,
+and formerly defoliated to wreathe the brows of victors and such poets as had
+influence at court. (<i>Vide supra.</i>)</p>
+
+<p id="law" class="entry"><span class="def">law</span>, <span class="pos">n.</span></p>
+
+<div class="poem">
+<p class="poetry">Once Law was sitting on the bench,</p>
+<p class="poetry">And Mercy knelt a-weeping.</p>
+<p class="poetry">“Clear out!” he cried, “disordered wench!</p>
+<p class="poetry">Nor come before me creeping.</p>
+<p class="poetry">Upon your knees if you appear,</p>
+<p class="poetry">‘Tis plain your have no standing here.”</p>
+<p class="poetry">Then Justice came. His Honor cried:</p>
+<p class="poetry">“<i>Your</i> status?—devil seize you!”</p>
+<p class="poetry">“<i>Amica curiae,</i>” she replied—</p>
+<p class="poetry">“Friend of the court, so please you.”</p>
+<p class="poetry">“Begone!” he shouted—“there’s the door—</p>
+<p class="poetry">I never saw your face before!”</p>
+<p class="citeauth">G. J.</p>
+</div>
+
+<p class="entry"><span class="def">lawful</span>, <span class="pos">adj.</span> Compatible
+with the will of a judge having jurisdiction.</p>
+
+<p id="lawyer" class="entry"><span class="def">lawyer</span>, <span class="pos">n.</span> One
+skilled in circumvention of the law.</p>
+
+<p class="entry"><span class="def">laziness</span>, <span class="pos">n.</span> Unwarranted
+repose of manner in a person of low degree.</p>
+
+<p class="entry"><span class="def">lead</span>, <span class="pos">n.</span> A heavy
+blue-gray metal much used in giving stability to light lovers—particularly to
+those who love not wisely but other men’s wives. Lead is also of great service
+as a counterpoise to an argument of such weight that it turns the scale of
+debate the wrong way. An interesting fact in the chemistry of international
+controversy is that at the point of contact of two patriotisms lead is
+precipitated in great quantities.</p>
+
+<div class="poem">
+<p class="poetry">Hail, holy Lead!—of human feuds the great</p>
+<p class="poetry">And universal arbiter; endowed</p>
+<p class="poetry">With penetration to pierce any cloud</p>
+<p class="poetry">Fogging the field of controversial hate,</p>
+<p class="poetry">And with a sift, inevitable, straight,</p>
+<p class="poetry">Searching precision find the unavowed</p>
+<p class="poetry">But vital point. Thy judgment, when allowed</p>
+<p class="poetry">By the chirurgeon, settles the debate.</p>
+<p class="poetry">O useful metal!—were it not for thee</p>
+<p class="poetry">We’d grapple one another’s ears alway:</p>
+<p class="poetry">But when we hear thee buzzing like a bee</p>
+<p class="poetry">We, like old Muhlenberg, “care not to stay.”</p>
+<p class="poetry">And when the quick have run away like pellets</p>
+<p class="poetry">Jack Satan smelts the dead to make new bullets.</p>
+</div>
+
+<p class="entry"><span class="def">learning</span>, <span class="pos">n.</span> The
+kind of ignorance distinguishing the studious.</p>
+
+<p class="entry"><span class="def">lecturer</span>, <span class="pos">n.</span> One
+with his hand in your pocket, his tongue in your ear and his faith in your patience.</p>
+
+<p class="entry"><span class="def">legacy</span>, <span class="pos">n.</span> A gift
+from one who is legging it out of this vale of tears.</p>
+
+<p class="entry"><span class="def">leonine</span>, <span class="pos">adj.</span> Unlike
+a menagerie lion. Leonine verses are those in which a word in the middle of a
+line rhymes with a word at the end, as in this famous passage from Bella Peeler Silcox:</p>
+
+<div class="poem">
+<p class="poetry">The electric light invades the dunnest deep of Hades.</p>
+<p class="poetry">Cries Pluto, ‘twixt his snores: “O tempora! O mores!”</p>
+<p class="poetry">It should be explained that Mrs. Silcox does not undertake to teach pronunciation of the
+Greek and Latin tongues. Leonine verses are so called in honor of a poet named
+Leo, whom prosodists appear to find a pleasure in believing to have been the
+first to discover that a rhyming couplet could be run into a single line.</p>
+</div>
+
+<p class="entry"><span class="def">lettuce</span>, <span class="pos">n.</span> An
+herb of the genus <i>Lactuca</i>, “Wherewith,” says that pious gastronome, Hengist Pelly, “God has been pleased
+to reward the good and punish the wicked. For by his inner light the righteous
+man has discerned a manner of compounding for it a dressing to the appetency
+whereof a multitude of gustible condiments conspire, being reconciled and
+ameliorated with profusion of oil, the entire comestible making glad the heart
+of the godly and causing his face to shine. But the person of spiritual unworth
+is successfully tempted to the Adversary to eat of lettuce with destitution of
+oil, mustard, egg, salt and garlic, and with a rascal bath of vinegar polluted
+with sugar. Wherefore the person of spiritual unworth suffers an intestinal
+pang of strange complexity and raises the song.”</p>
+
+<p class="entry"><span class="def">leviathan</span>, <span class="pos">n.</span> An
+enormous aquatic animal mentioned by Job. Some suppose it to have been the
+whale, but that distinguished ichthyologer, Dr. Jordan, of Stanford University,
+maintains with considerable heat that it was a species of gigantic Tadpole
+(<i>Thaddeus Polandensis</i>) or Polliwig—<i>Maria
+pseudo-hirsuta</i>. For an exhaustive description and history of the
+Tadpole consult the famous monograph of Jane Potter, <i>Thaddeus of Warsaw</i>.</p>
+
+<p class="entry"><span class="def">lexicographer</span>, <span class="pos">n.</span> A
+pestilent fellow who, under the pretense of recording some particular stage in
+the development of a language, does what he can to arrest its growth, stiffen
+its flexibility and mechanize its methods. For your lexicographer, having
+written his dictionary, comes to be considered “as one having authority,”
+whereas his function is only to make a record, not to give a law. The natural
+servility of the human understanding having invested him with judicial power,
+surrenders its right of reason and submits itself to a chronicle as if it were
+a statue. Let the dictionary (for example) mark a good word as “obsolete” or
+“obsolescent” and few men thereafter venture to use it, whatever their need of
+it and however desirable its restoration to favor—whereby the process of
+improverishment is accelerated and speech decays. On the contrary, recognizing
+the truth that language must grow by innovation if it grow at all, makes new
+words and uses the old in an unfamiliar sense, has no following and is tartly
+reminded that “it isn’t in the dictionary”—although down to the time of the
+first lexicographer (Heaven forgive him!) no author ever had used a word that <i>was</i> in the dictionary. In the golden prime
+and high noon of English speech; when from the lips of the great Elizabethans
+fell words that made their own meaning and carried it in their very sound; when
+a Shakespeare and a Bacon were possible, and the language now rapidly perishing
+at one end and slowly renewed at the other was in vigorous growth and hardy
+preservation—sweeter than honey and stronger than a lion—the lexicographer was
+a person unknown, the dictionary a creation which his Creator had not created
+him to create.</p>
+
+<div class="poem">
+<p class="poetry">God said: “Let Spirit perish into Form,”</p>
+<p class="poetry">And lexicographers arose, a swarm!</p>
+<p class="poetry">Thought fled and left her clothing, which they took,</p>
+<p class="poetry">And catalogued each garment in a book.</p>
+<p class="poetry">Now, from her leafy covert when she cries:</p>
+<p class="poetry">“Give me my clothes and I’ll return,” they rise</p>
+<p class="poetry">And scan the list, and say without compassion:</p>
+<p class="poetry">“Excuse us—they are mostly out of fashion.”</p>
+<p class="citeauth">Sigismund Smith</p>
+</div>
+
+<p class="entry"><span class="def">liar</span>, <span class="pos">n.</span> A lawyer
+with a roving commission.</p>
+
+<p class="entry"><span class="def">liberty</span>, <span class="pos">n.</span> One of
+Imagination’s most precious possessions.</p>
+
+<div class="poem">
+<p class="poetry">The rising People, hot and out of breath,</p>
+<p class="poetry">Roared around the palace: “Liberty or death!”</p>
+<p class="poetry">“If death will do,” the King said, “let me reign;</p>
+<p class="poetry">You’ll have, I’m sure, no reason to complain.”</p>
+<p class="citeauth">Martha Braymance</p>
+</div>
+
+<p class="entry"><span class="def">lickspittle</span>, <span class="pos">n.</span> A
+useful functionary, not infrequently found editing a newspaper. In his
+character of editor he is closely allied to the blackmailer by the tie of
+occasional identity; for in truth the lickspittle is only the blackmailer under
+another aspect, although the latter is frequently found as an independent
+species. Lickspittling is more detestable than blackmailing, precisely as the
+business of a confidence man is more detestable than that of a highway robber;
+and the parallel maintains itself throughout, for whereas few robbers will
+cheat, every sneak will plunder if he dare.</p>
+
+<p class="entry"><span class="def">life</span>, <span class="pos">n.</span> A
+spiritual pickle preserving the body from decay. We live in daily apprehension
+of its loss; yet when lost it is not missed. The question, “Is life worth
+living?” has been much discussed; particularly by those who think it is not,
+many of whom have written at great length in support of their view and by
+careful observance of the laws of health enjoyed for long terms of years the
+honors of successful controversy.</p>
+
+<div class="poem">
+<p class="poetry">“Life’s not worth living, and that’s the truth,”</p>
+<p class="poetry">Carelessly caroled the golden youth.</p>
+<p class="poetry">In manhood still he maintained that view</p>
+<p class="poetry">And held it more strongly the older he grew.</p>
+<p class="poetry">When kicked by a jackass at eighty-three,</p>
+<p class="poetry">“Go fetch me a surgeon at once!” cried he.</p>
+<p class="citeauth">Han Soper</p>
+</div>
+
+<p class="entry"><span class="def">lighthouse</span>, <span class="pos">n.</span> A
+tall building on the seashore in which the government maintains a lamp and the friend of a politician.</p>
+
+<p class="entry"><span class="def">limb</span>, <span class="pos">n.</span> The
+branch of a tree or the leg of an American woman.</p>
+
+<div class="poem">
+<p class="poetry">‘Twas a pair of boots that the lady bought,</p>
+<p class="poetry">And the salesman laced them tight</p>
+<p class="poetry">To a very remarkable height—</p>
+<p class="poetry">Higher, indeed, than I think he ought—</p>
+<p class="poetry">Higher than <i>can</i> be right.</p>
+<p class="poetry">For the Bible declares—but never mind:</p>
+<p class="poetry">It is hardly fit</p>
+<p class="poetry">To censure freely and fault to find</p>
+<p class="poetry">With others for sins that I’m not inclined</p>
+<p class="poetry">Myself to commit.</p>
+<p class="poetry">Each has his weakness, and though my own</p>
+<p class="poetry">Is freedom from every sin,</p>
+<p class="poetry">It still were unfair to pitch in,</p>
+<p class="poetry">Discharging the first censorious stone.</p>
+<p class="poetry">Besides, the truth compels me to say,</p>
+<p class="poetry">The boots in question were <i>made</i> that way.</p>
+<p class="poetry">As he drew the lace she made a grimace,</p>
+<p class="poetry">And blushingly said to him:</p>
+<p class="poetry">“This boot, I’m sure, is too high to endure, It hurts my—hurts my—limb.”</p>
+<p class="poetry">The salesman smiled in a manner mild,</p>
+<p class="poetry">Like an artless, undesigning child;</p>
+<p class="poetry">Then, checking himself, to his face he gave</p>
+<p class="poetry">A look as sorrowful as the grave,</p>
+<p class="poetry">Though he didn’t care two figs</p>
+<p class="poetry">For her paints and throes,</p>
+<p class="poetry">As he stroked her toes,</p>
+<p class="poetry">Remarking with speech and manner just</p>
+<p class="poetry">Befitting his calling: “Madam, I trust</p>
+<p class="poetry">That it doesn’t hurt your twigs.”</p>
+<p class="citeauth">B. Percival Dike</p>
+</div>
+
+<p class="entry"><span class="def">linen</span>, <span class="pos">n.</span> “A kind
+of cloth the making of which, when made of hemp, entails a great waste of
+hemp.”—Calcraft the Hangman.</p>
+
+<p class="entry"><span class="def">litigant</span>, <span class="pos">n.</span> A
+person about to give up his skin for the hope of retaining his bones.</p>
+
+<p class="entry"><span class="def">litigation</span>, <span class="pos">n.</span> A
+machine which you go into as a pig and come out of as a sausage.</p>
+
+<p class="entry"><span class="def">liver</span>, <span class="pos">n.</span> A large
+red organ thoughtfully provided by nature to be bilious with. The sentiments
+and emotions which every literary anatomist now knows to haunt the heart were
+anciently believed to infest the liver; and even Gascoygne, speaking of the
+emotional side of human nature, calls it “our hepaticall parte.” It was at one
+time considered the seat of life; hence its name—liver, the thing we live with.
+The liver is heaven’s best gift to the goose; without it that bird would be
+unable to supply us with the Strasbourg <i>pate</i>.</p>
+
+<p>LL.D. Letters indicating the degree <i>Legumptionorum Doctor</i>,
+one learned in laws, gifted with legal gumption. Some suspicion is cast upon
+this derivation by the fact that the title was formerly <i>LL.d.</i>, and conferred only upon gentlemen
+distinguished for their wealth. At the date of this writing Columbia University
+is considering the expediency of making another degree for clergymen, in place
+of the old D.D.—<i>Damnator Diaboli</i>.
+The new honor will be known as <i>Sanctorum Custus</i>, and written <i>$$c</i>. The name of the Rev. John Satan has
+been suggested as a suitable recipient by a lover of consistency, who points
+out that Professor Harry Thurston Peck has long enjoyed the advantage of a
+degree.</p>
+
+<p class="entry"><span class="def">lock-and-key</span>, <span class="pos">n.</span> The
+distinguishing device of civilization and enlightenment.</p>
+
+<p class="entry"><span class="def">Lodger</span>, <span class="pos">n.</span> A less
+popular name for the Second Person of that delectable newspaper Trinity, the
+Roomer, the Bedder, and the Mealer.</p>
+
+<p class="entry"><span class="def">logic</span>, <span class="pos">n.</span> The art
+of thinking and reasoning in strict accordance with the limitations and
+incapacities of the human misunderstanding. The basic of logic is the
+syllogism, consisting of a major and a minor premise and a conclusion—thus:</p>
+
+<p><i>Major Premise</i>: Sixty men can do a piece of work sixty times as quickly as one man.</p>
+
+<p><i>Minor Premise</i>: One man can dig a posthole in sixty seconds; therefore—</p>
+
+<p><i>Conclusion</i>: Sixty men can dig a posthole in one second.</p>
+
+<p>This may be called the syllogism arithmetical, in which, by combining logic and mathematics, we
+obtain a double certainty and are twice blessed.</p>
+
+<p class="entry"><span class="def">logomachy</span>, <span class="pos">n.</span> A
+war in which the weapons are words and the wounds punctures in the swim-bladder
+of self-esteem—a kind of contest in which, the vanquished being unconscious of
+defeat, the victor is denied the reward of success.</p>
+
+<div class="poem">
+<p class="poetry">‘Tis said by divers of the scholar-men That poor Salmasius died of Milton’s pen.</p>
+<p class="poetry">Alas! we cannot know if this is true,</p>
+<p class="poetry">For reading Milton’s wit we perish too.</p>
+</div>
+
+<p class="entry"><span class="def">loganimity</span>, <span class="pos">n.</span> The
+disposition to endure injury with meek forbearance while maturing a plan of revenge.</p>
+
+<p class="entry"><span class="def">longevity</span>, <span class="pos">n.</span> Uncommon
+extension of the fear of death.</p>
+
+<p class="entry"><span class="def">looking-glass</span>, <span class="pos">n.</span> A
+vitreous plane upon which to display a fleeting show for man’s disillusion given.</p>
+
+<p class="cite">The King of
+Manchuria had a magic looking-glass, whereon whoso looked saw, not his own
+image, but only that of the king. A certain courtier who had long enjoyed the
+king’s favor and was thereby enriched beyond any other subject of the realm,
+said to the king: </p>
+
+<p class="cite">“Give me, I pray,
+thy wonderful mirror, so that when absent out of thine august presence I may
+yet do homage before thy visible shadow, prostrating myself night and morning
+in the glory of thy benign countenance, as which nothing has so divine
+splendor, O Noonday Sun of the Universe!”</p>
+
+<p class="cite">Please with the
+speech, the king commanded that the mirror be conveyed to the courtier’s
+palace; but after, having gone thither without apprisal, he found it in an
+apartment where was naught but idle lumber. And the mirror was dimmed with dust
+and overlaced with cobwebs. This so angered him that he fisted it hard,
+shattering the glass, and was sorely hurt. Enraged all the more by this
+mischance, he commanded that the ungrateful courtier be thrown into prison, and
+that the glass be repaired and taken back to his own palace; and this was done.
+But when the king looked again on the mirror he saw not his image as before,
+but only the figure of a crowned ass, having a bloody bandage on one of its
+hinder hooves—as the artificers and all who had looked upon it had before
+discerned but feared to report. Taught wisdom and charity, the king restored
+his courtier to liberty, had the mirror set into the back of the throne and
+reigned many years with justice and humility; and one day when he fell asleep
+in death while on the throne, the whole court saw in the mirror the luminous
+figure of an angel, which remains to this day.</p>
+
+<p class="entry"><span class="def">loquacity</span>, <span class="pos">n.</span> A
+disorder which renders the sufferer unable to curb his tongue when you wish to
+talk.</p>
+
+<p class="entry"><span class="def">lord</span>, <span class="pos">n.</span> In
+American society, an English tourist above the state of a costermonger, as,
+lord ‘Aberdasher, Lord Hartisan and so forth. The traveling Briton of lesser
+degree is addressed as “Sir,” as, Sir ‘Arry Donkiboi, or ‘Amstead ‘Eath. The
+word “Lord” is sometimes used, also, as a title of the Supreme Being; but this
+is thought to be rather flattery than true reverence.</p>
+
+<div class="poem">
+<p class="poetry">Miss Sallie Ann Splurge, of her own accord,<br />
+Wedded a wandering English lord—</p>
+<p class="poetry">Wedded and took him to dwell with her “paw,”<br />
+A parent who throve by the practice of Draw.</p>
+<p class="poetry">Lord Cadde I don’t hesitate to declare</p>
+<p class="poetry">Unworthy the father-in-legal care</p>
+<p class="poetry">Of that elderly sport, notwithstanding the truth<br />
+That Cadde had renounced all the follies of youth;</p>
+<p class="poetry">For, sad to relate, he’d arrived at the stage<br />
+Of existence that’s marked by the vices of age.<br />
+Among them, cupidity caused him to urge<br />
+Repeated demands on the pocket of Splurge,<br />
+Till, wrecked in his fortune, that gentleman saw<br />
+Inadequate aid in the practice of Draw,<br />
+And took, as a means of augmenting his pelf,<br />
+To the business of being a lord himself.</p>
+<p class="poetry">His neat-fitting garments he wilfully shed<br />
+And sacked himself strangely in checks instead;</p>
+<p class="poetry">Denuded his chin, but retained at each ear<br />
+A whisker that looked like a blasted career.<br />
+He painted his neck an incarnadine hue<br />
+Each morning and varnished it all that he knew.</p>
+<p class="poetry">The moony monocular set in his eye</p>
+<p class="poetry">Appeared to be scanning the Sweet Bye-and-Bye.<br />
+His head was enroofed with a billycock hat, And
+his low-necked shoes were aduncous and flat.</p>
+<p class="poetry">In speech he eschewed his American ways,</p>
+<p class="poetry">Denying his nose to the use of his A’s</p>
+<p class="poetry">And dulling their edge till the delicate sense<br />
+Of a babe at their temper could take no offence.<br />
+His H’s—‘twas most inexpressibly sweet,<br />
+The patter they made as they fell at his feet!</p>
+<p class="poetry">Re-outfitted thus, Mr. Splurge without fear</p>
+<p class="poetry">Began as Lord Splurge his recouping career.</p>
+<p class="poetry">Alas, the Divinity shaping his end</p>
+<p class="poetry">Entertained other views and decided to send</p>
+<p class="poetry">His lordship in horror, despair and dismay</p>
+<p class="poetry">From the land of the nobleman’s natural prey.</p>
+<p class="poetry">For, smit with his Old World ways,</p>
+<p class="poetry">Lady Cadde Fell—suffering Caesar!—in love with her dad!</p>
+<p class="citeauth">G. J.</p>
+</div>
+
+<p class="entry"><span class="def">lore</span>, <span class="pos">n.</span> Learning—particularly
+that sort which is not derived from a regular course of instruction but comes
+of the reading of occult books, or by nature. This latter is commonly
+designated as folk-lore and embraces popularly myths and superstitions. In
+Baring-Gould’s <i>Curious Myths of the Middle
+Ages</i> the reader will find many of these traced backward, through
+various people son converging lines, toward a common origin in remote
+antiquity. Among these are the fables of “Teddy the Giant Killer,” “The
+Sleeping John Sharp Williams,” “Little Red Riding Hood and the Sugar Trust,”
+“Beauty and the Brisbane,” “The Seven Aldermen of Ephesus,” “Rip Van
+Fairbanks,” and so forth. The fable with Goethe so affectingly relates under
+the title of “The Erl- King” was known two thousand years ago in Greece as “The
+Demos and the Infant Industry.” One of the most general and ancient of these
+myths is that Arabian tale of “Ali Baba and the Forty Rockefellers.”</p>
+
+<p class="entry"><span class="def">loss</span>, <span class="pos">n.</span> Privation
+of that which we had, or had not. Thus, in the latter sense, it is said of a
+defeated candidate that he “lost his election”; and of that eminent man, the
+poet Gilder, that he has “lost his mind.” It is in the former and more
+legitimate sense, that the word is used in the famous epitaph:</p>
+
+<div class="poem">
+<p class="poetry">Here Huntington’s ashes long have lain</p>
+<p class="poetry">Whose loss is our eternal gain,</p>
+<p class="poetry">For while he exercised all his powers</p>
+<p class="poetry">Whatever he gained, the loss was ours.</p>
+</div>
+
+<p class="entry"><span class="def">love</span>, <span class="pos">n.</span> A
+temporary insanity curable by marriage or by removal of the patient from the
+influences under which he incurred the disorder. This disease, like <i>caries</i> and many other ailments, is
+prevalent only among civilized races living under artificial conditions;
+barbarous nations breathing pure air and eating simple food enjoy immunity from
+its ravages. It is sometimes fatal, but more frequently to the physician than to the patient.</p>
+
+<p class="entry"><span class="def">low-bred</span>, <span class="pos">adj.</span> “Raised”
+instead of brought up.</p>
+
+<p class="entry"><span class="def">luminary</span>, <span class="pos">n.</span> One
+who throws light upon a subject; as an editor by not writing about it.</p>
+
+<p class="entry"><span class="def">lunarian</span>, <span class="pos">n.</span> An
+inhabitant of the moon, as distinguished from Lunatic, one whom the moon
+inhabits. The Lunarians have been described by Lucian, Locke and other
+observers, but without much agreement. For example, Bragellos avers their
+anatomical identity with Man, but Professor Newcomb says they are more like the
+hill tribes of Vermont.</p>
+
+<p class="entry"><span class="def">lyre</span>, <span class="pos">n.</span> An
+ancient instrument of torture. The word is now used in a figurative sense to
+denote the poetic faculty, as in the following fiery lines of our great poet,
+Ella Wheeler Wilcox:</p>
+
+<div class="poem">
+<p class="poetry">I sit astride Parnassus with my lyre,</p>
+<p class="poetry">And pick with care the disobedient wire.</p>
+<p class="poetry">That stupid shepherd lolling on his crook With deaf attention scarcely deigns to look. I
+bide my time, and it shall come at length, When, with a Titan’s energy and
+strength, I’ll grab a fistful of the strings, and O, The word shall suffer when
+I let them go!</p>
+<p class="citeauth">Farquharson Harris</p>
+</div>
+
+
+</body>
+</html>
\ No newline at end of file
--- /dev/null
+++ b/lib/ebooks/devils/L.html.i
@@ -1,0 +1,45 @@
+20 pages
+size 400 552
+length 29470
+396 2 10 body html
+0
+1257 2 28 body html
+235
+2934 2 61 body html
+127
+4970 2 96 body html
+36
+6178 2 121 body html
+0
+6684 2 129 body html
+415
+8845 2 168 body html
+73
+10249 2 188 body html
+260
+12064 2 212 body html
+320
+13945 2 248 body html
+107
+15236 2 272 body html
+199
+15236 2 272 body html
+737
+17527 2 315 body html
+56
+19544 2 347 body html
+34
+20992 2 376 body html
+51
+22915 2 409 body html
+0
+23378 2 416 body html
+439
+23378 2 416 body html
+990
+27237 2 481 body html
+36
+28972 2 513 body html
+72
+law 2
+lawyer 3
--- /dev/null
+++ b/lib/ebooks/devils/M.html
@@ -1,0 +1,580 @@
+<?xml version="1.0"?>
+<!DOCTYPE package PUBLIC "+//ISBN 0-9673008-1-9//DTD OEB 1.0 Package//EN"
+ "http://openebook.org/dtds/oeb-1.0/oebdoc1.dtd">
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/x-oeb1-document; charset=utf-8" />
+<link rel="stylesheet" type="text/x-oeb1-css" href="devil.css" />
+<title>The Devil’s Dictionary: M</title>
+</head>
+<body lang="en-US">
+
+
+<h1>M</h1>
+
+<p class="entry"><span class="def">mace</span>, <span class="pos">n.</span> A staff
+of office signifying authority. Its form, that of a heavy club, indicates its
+original purpose and use in dissuading from dissent.</p>
+
+<p class="entry"><span class="def">machination</span>, <span class="pos">n.</span> The
+method employed by one’s opponents in baffling one’s open and honorable efforts
+to do the right thing.</p>
+
+<div class="poem">
+<p class="poetry">So plain the advantages of machination</p>
+<p class="poetry">It constitutes a moral obligation,</p>
+<p class="poetry">And honest wolves who think upon’t with loathing</p>
+<p class="poetry">Feel bound to don the sheep’s deceptive clothing.</p>
+<p class="poetry">So prospers still the diplomatic art,</p>
+<p class="poetry">And Satan bows, with hand upon his heart.</p>
+<p class="citeauth">R. S. K.</p>
+</div>
+
+<p class="entry"><span class="def">macrobian</span>, <span class="pos">n.</span> One
+forgotten of the gods and living to a great age. History is abundantly supplied
+with examples, from Methuselah to Old Parr, but some notable instances of
+longevity are less well known. A Calabrian peasant named Coloni, born in 1753,
+lived so long that he had what he considered a glimpse of the dawn of universal
+peace. Scanavius relates that he knew an archbishop who was so old that he
+could remember a time when he did not deserve hanging. In 1566 a linen draper
+of Bristol, England, declared that he had lived five hundred years, and that in
+all that time he had never told a lie. There are instances of longevity
+(<i>macrobiosis</i>) in our own country. Senator Chauncey Depew is old enough to
+know better. The editor of <i>The American</i>,
+a newspaper in New York City, has a memory that goes back to the time when he
+was a rascal, but not to the fact. The President of the United States was born
+so long ago that many of the friends of his youth have risen to high political
+and military preferment without the assistance of personal merit. The verses
+following were written by a macrobian:</p>
+
+<div class="poem">
+<p class="poetry">When I was young the world was fair</p>
+<p class="poetry">And amiable and sunny.</p>
+<p class="poetry">A brightness was in all the air,</p>
+<p class="poetry">In all the waters, honey.</p>
+<p class="poetry">The jokes were fine and funny,</p>
+<p class="poetry">The statesmen honest in their views,</p>
+<p class="poetry">And in their lives, as well,</p>
+<p class="poetry">And when you heard a bit of news</p>
+<p class="poetry">‘Twas true enough to tell.</p>
+<p class="poetry">Men were not ranting, shouting, reeking,</p>
+<p class="poetry">Nor women “generally speaking.”</p>
+<p class="poetry">The Summer then was long indeed:</p>
+<p class="poetry">It lasted one whole season!</p>
+<p class="poetry">The sparkling Winter gave no heed</p>
+<p class="poetry">When ordered by Unreason</p>
+<p class="poetry">To bring the early peas on.</p>
+<p class="poetry">Now, where the dickens is the sense</p>
+<p class="poetry"> In calling that a year</p>
+<p class="poetry">Which does no more than just commence</p>
+<p class="poetry">Before the end is near?</p>
+<p class="poetry">When I was young the year extended</p>
+<p class="poetry">From month to month until it ended.</p>
+<p class="poetry">I know not why the world has changed</p>
+<p class="poetry">To something dark and dreary,</p>
+<p class="poetry">And everything is now arranged</p>
+<p class="poetry">To make a fellow weary.</p>
+<p class="poetry">The Weather Man—I fear he</p>
+<p class="poetry">Has much to do with it, for, sure,</p>
+<p class="poetry">The air is not the same:</p>
+<p class="poetry">It chokes you when it is impure,</p>
+<p class="poetry">When pure it makes you lame.</p>
+<p class="poetry">With windows closed you are asthmatic;</p>
+<p class="poetry">Open, neuralgic or sciatic.</p>
+<p class="poetry">Well, I suppose this new regime</p>
+<p class="poetry">Of dun degeneration</p>
+<p class="poetry">Seems eviler than it would seem</p>
+<p class="poetry">To a better observation,</p>
+<p class="poetry">And has for compensation</p>
+<p class="poetry">Some blessings in a deep disguise</p>
+<p class="poetry">Which mortal sight has failed</p>
+<p class="poetry">To pierce, although to angels’ eyes</p>
+<p class="poetry">They’re visible unveiled.</p>
+<p class="poetry">If Age is such a boon, good land!</p>
+<p class="poetry">He’s costumed by a master hand!</p>
+<p class="citeauth">Venable Strigg</p>
+</div>
+
+<p class="entry"><span class="def">mad</span>, <span class="pos">adj.</span> Affected
+with a high degree of intellectual independence; not conforming to standards of
+thought, speech and action derived by the conformants from study of themselves;
+at odds with the majority; in short, unusual. It is noteworthy that persons are
+pronounced mad by officials destitute of evidence that themselves are sane. For
+illustration, this present (and illustrious) lexicographer is no firmer in the
+faith of his own sanity than is any inmate of any madhouse in the land; yet for
+aught he knows to the contrary, instead of the lofty occupation that seems to
+him to be engaging his powers he may really be beating his hands against the
+window bars of an asylum and declaring himself Noah Webster, to the innocent
+delight of many thoughtless spectators.</p>
+
+<p class="entry"><span class="def">Magdalene</span>, <span class="pos">n.</span> An
+inhabitant of Magdala. Popularly, a woman found out. This definition of the
+word has the authority of ignorance, Mary of Magdala being another person than
+the penitent woman mentioned by St. Luke. It has also the official sanction of
+the governments of Great Britain and the United States. In England the word is
+pronounced Maudlin, whence maudlin, adjective, unpleasantly sentimental. With
+their Maudlin for Magdalene, and their Bedlam for Bethlehem, the English may
+justly boast themselves the greatest of revisers.</p>
+
+<p class="entry"><span class="def">magic</span>, <span class="pos">n.</span> An art
+of converting superstition into coin. There are other arts serving the same
+high purpose, but the discreet lexicographer does not name them.</p>
+
+<p class="entry"><span class="def">magnet</span>, <span class="pos">n.</span> Something
+acted upon by magnetism.</p>
+
+<p class="entry"><span class="def">magnetism</span>, <span class="pos">n.</span> Something
+acting upon a magnet.</p>
+
+<p class="indentpara">The two definitions immediately foregoing are condensed from the works of one thousand
+eminent scientists, who have illuminated the subject with a great white light,
+to the inexpressible advancement of human knowledge.</p>
+
+<p class="entry"><span class="def">magnificient</span>, <span class="pos">adj.</span> Having
+a grandeur or splendor superior to that to which the spectator is accustomed,
+as the ears of an ass, to a rabbit, or the glory of a glowworm, to a maggot.</p>
+
+<p class="entry"><span class="def">magnitude</span>, <span class="pos">n.</span> Size.
+Magnitude being purely relative, nothing is large and nothing small. If
+everything in the universe were increased in bulk one thousand diameters
+nothing would be any larger than it was before, but if one thing remain
+unchanged all the others would be larger than they had been. To an
+understanding familiar with the relativity of magnitude and distance the spaces
+and masses of the astronomer would be no more impressive than those of the
+microscopist. For anything we know to the contrary, the visible universe may be
+a small part of an atom, with its component ions, floating in the life- fluid
+(luminiferous ether) of some animal. Possibly the wee creatures peopling the
+corpuscles of our own blood are overcome with the proper emotion when
+contemplating the unthinkable distance from one of these to another.</p>
+
+<p class="entry"><span class="def">magpie</span>, <span class="pos">n.</span> A bird
+whose thievish disposition suggested to someone that it might be taught to talk.</p>
+
+<p class="entry"><span class="def">maiden</span>, <span class="pos">n.</span> A young
+person of the unfair sex addicted to clewless conduct and views that madden to
+crime. The genus has a wide geographical distribution, being found wherever
+sought and deplored wherever found. The maiden is not altogether unpleasing to
+the eye, nor (without her piano and her views) insupportable to the ear, though
+in respect to comeliness distinctly inferior to the rainbow, and, with regard
+to the part of her that is audible, bleating out of the field by the
+canary—which, also, is more portable.</p>
+
+<div class="poem">
+<p class="poetry">A lovelorn maiden she sat and sang—</p>
+<p class="poetry">This quaint, sweet song sang she;</p>
+<p class="poetry">“It’s O for a youth with a football bang</p>
+<p class="poetry">And a muscle fair to see!</p>
+<p class="poetry">The Captain he</p>
+<p class="poetry">Of a team to be!</p>
+<p class="poetry">On the gridiron he shall shine,</p>
+<p class="poetry">A monarch by right divine,</p>
+<p class="poetry">And never to roast on it—me!”</p>
+<p class="citeauth">Opoline Jones</p>
+</div>
+
+<p class="entry"><span class="def">majesty</span>, <span class="pos">n.</span> The
+state and title of a king. Regarded with a just contempt by the Most Eminent
+Grand Masters, Grand Chancellors, Great Incohonees and Imperial Potentates of
+the ancient and honorable orders of republican America.</p>
+
+<p id="male" class="entry"><span class="def">male</span>, <span class="pos">n.</span> A member
+of the unconsidered, or negligible sex. The male of the human race is commonly
+known (to the female) as Mere Man. The genus has two varieties: good providers
+and bad providers.</p>
+
+<p class="entry"><span class="def">malefactor</span>, <span class="pos">n.</span> The
+chief factor in the progress of the human race.</p>
+
+<p class="entry"><span class="def">malthusian</span>, <span class="pos">adj.</span> Pertaining
+to Malthus and his doctrines. Malthus believed in artificially limiting
+population, but found that it could not be done by talking. One of the most
+practical exponents of the Malthusian idea was Herod of Judea, though all the
+famous soldiers have been of the same way of thinking.</p>
+
+<p class="entry"><span class="def">mammalia</span>, <span class="pos">n.</span>pl. A
+family of vertebrate animals whose females in a state of nature suckle their
+young, but when civilized and enlightened put them out to nurse, or use the bottle.</p>
+
+<p class="entry"><span class="def">Mammon</span>, <span class="pos">n.</span> The god
+of the world’s leading religion. The chief temple is in the holy city of New York.</p>
+
+<div class="poem">
+<p class="poetry">He swore that all other religions were</p>
+<p class="poetry">gammon, And wore out his knees in the worship of Mammon.</p>
+<p class="citeauth">Jared Oopf</p>
+</div>
+
+<p class="entry"><span class="def">man</span>, <span class="pos">n.</span> An animal
+so lost in rapturous contemplation of what he thinks he is as to overlook what
+he indubitably ought to be. His chief occupation is extermination of other
+animals and his own species, which, however, multiplies with such insistent
+rapidity as to infest the whole habitable earh and Canada.</p>
+
+<div class="poem">
+<p class="poetry">When the world was young and Man was new,</p>
+<p class="poetry">And everything was pleasant,</p>
+<p class="poetry">Distinctions Nature never drew</p>
+<p class="poetry">‘Mongst kings and priest and peasant.</p>
+<p class="poetry">We’re not that way at present,</p>
+<p class="poetry">Save here in this Republic, where</p>
+<p class="poetry">We have that old regime,</p>
+<p class="poetry">For all are kings, however bare</p>
+<p class="poetry">Their backs, howe’er extreme</p>
+<p class="poetry">Their hunger. And, indeed, each has a voice</p>
+<p class="poetry">To accept the tyrant of his party’s choice.</p>
+<p class="poetry">A citizen who would not vote,</p>
+<p class="poetry">And, therefore, was detested,</p>
+<p class="poetry">Was one day with a tarry coat</p>
+<p class="poetry">(With feathers backed and breasted)</p>
+<p class="poetry">By patriots invested.</p>
+<p class="poetry">“It is your duty,” cried the crowd,</p>
+<p class="poetry">“Your ballot true to cast</p>
+<p class="poetry">For the man o’ your choice.” He humbly bowed,</p>
+<p class="poetry">And explained his wicked past:</p>
+<p class="poetry">“That’s what I very gladly would have done, Dear patriots, but he has never run.”</p>
+<p class="citeauth">Apperton Duke</p>
+</div>
+
+<p class="entry"><span class="def">manes</span>, <span class="pos">n.</span> The
+immortal parts of dead Greeks and Romans. They were in a state of dull
+discomfort until the bodies from which they had exhaled were buried and burned;
+and they seem not to have been particularly happy afterward.</p>
+
+<p class="entry"><span class="def">Manicheism</span>, <span class="pos">n.</span> The
+ancient Persian doctrine of an incessant warfare between Good and Evil. When
+Good gave up the fight the Persians joined the victorious Opposition.</p>
+
+<p class="entry"><span class="def">Manna</span>, <span class="pos">n.</span> A food
+miraculously given to the Israelites in the wilderness. When it was no longer
+supplied to them they settled down and tilled the soil, fertilizing it, as a
+rule, with the bodies of the original occupants.</p>
+
+<p class="entry"><span class="def">marriage</span>, <span class="pos">n.</span> The
+state or condition of a community consisting of a master, a mistress and two
+slaves, making in all, two.</p>
+
+<p class="entry"><span class="def">martyr</span>, <span class="pos">n.</span> One who
+moves along the line of least reluctance to a desired death.</p>
+
+<p class="entry"><span class="def">material</span>, <span class="pos">adj.</span> Having
+an actual existence, as distinguished from an imaginary one. Important.</p>
+
+<div class="poem">
+<p class="poetry">Material things I know, or fell, or see;</p>
+<p class="poetry">All else is immaterial to me.</p>
+<p class="citeauth">Jamrach Holobom</p>
+</div>
+
+<p class="entry"><span class="def">mausoleum</span>, <span class="pos">n.</span> The
+final and funniest folly of the rich.</p>
+
+<p class="entry"><span class="def">mayonnaise</span>, <span class="pos">n.</span> One
+of the sauces which serve the French in place of a state religion.</p>
+
+<p class="entry"><span class="def">me,</span> <span class="pos">pro.</span> The
+objectionable case of I. The personal pronoun in English has three cases, the
+dominative, the objectionable and the oppressive. Each is all three.</p>
+
+<p class="entry"><span class="def">meander</span>, <span class="pos">n.</span> To
+proceed sinuously and aimlessly. The word is the ancient name of a river about
+one hundred and fifty miles south of Troy, which turned and twisted in the
+effort to get out of hearing when the Greeks and Trojans boasted of their prowess.</p>
+
+<p class="entry"><span class="def">medal</span>, <span class="pos">n.</span> A small
+metal disk given as a reward for virtues, attainments or services more or less
+authentic.</p>
+
+<p class="indentpara">It is related of Bismark, who had been awarded a medal for gallantly rescuing a drowning person,
+that, being asked the meaning of the medal, he replied: “I save lives
+sometimes.” And sometimes he didn’t.</p>
+
+<p class="entry"><span class="def">medicine</span>, <span class="pos">n.</span> A stone
+flung down the Bowery to kill a dog in Broadway.</p>
+
+<p class="entry"><span class="def">meekness</span>, <span class="pos">n.</span> Uncommon
+patience in planning a revenge that is worth while.</p>
+
+<div class="poem">
+<p class="poetry">M is for Moses,</p>
+<p class="poetry">Who slew the Egyptian.</p>
+<p class="poetry">As sweet as a rose is</p>
+<p class="poetry">The meekness of Moses.</p>
+<p class="poetry">No monument shows his</p>
+<p class="poetry">Post-mortem inscription,</p>
+<p class="poetry">But M is for Moses</p>
+<p class="poetry">Who slew the Egyptian.</p>
+<p class="citeauth"><i>The Biographical Alphabet</i></p>
+</div>
+
+<p class="entry"><span class="def">meerschaum</span>, <span class="pos">n.</span> (Literally,
+seafoam, and by many erroneously supposed to be made of it.) A fine white clay,
+which for convenience in coloring it brown is made into tobacco pipes and smoked
+by the workmen engaged in that industry. The purpose of coloring it has not
+been disclosed by the manufacturers.</p>
+
+<div class="poem">
+<p class="poetry">There was a youth (you’ve heard before,</p>
+<p class="poetry">This woeful tale, may be),</p>
+<p class="poetry">Who bought a meerschaum pipe and swore</p>
+<p class="poetry">That color it would he!</p>
+<p class="poetry">He shut himself from the world away,</p>
+<p class="poetry">Nor any soul he saw.</p>
+<p class="poetry">He smoke by night, he smoked by day,</p>
+<p class="poetry">As hard as he could draw.</p>
+<p class="poetry">His dog died moaning in the wrath</p>
+<p class="poetry">Of winds that blew aloof;</p>
+<p class="poetry">The weeds were in the gravel path,</p>
+<p class="poetry">The owl was on the roof.</p>
+<p class="poetry">“He’s gone afar, he’ll come no more,”</p>
+<p class="poetry">The neighbors sadly say.</p>
+<p class="poetry">And so they batter in the door</p>
+<p class="poetry">To take his goods away.</p>
+<p class="poetry">Dead, pipe in mouth, the youngster lay,</p>
+<p class="poetry">Nut-brown in face and limb.</p>
+<p class="poetry">“That pipe’s a lovely white,” they say,</p>
+<p class="poetry">“But it has colored him!”</p>
+<p class="poetry">The moral there’s small need to sing—</p>
+<p class="poetry">‘Tis plain as day to you:</p>
+<p class="poetry">Don’t play your game on any thing</p>
+<p class="poetry">That is a gamester too.</p>
+<p class="citeauth">Martin Bulstrode</p>
+</div>
+
+<p class="entry"><span class="def">mendacious</span>, <span class="pos">adj.</span> Addicted to rhetoric.</p>
+
+<p class="entry"><span class="def">merchant</span>, <span class="pos">n.</span> One
+engaged in a commercial pursuit. A commercial pursuit is one in which the thing
+pursued is a dollar.</p>
+
+<p class="entry"><span class="def">mercy</span>, <span class="pos">n.</span> An
+attribute beloved of detected offenders.</p>
+
+<p class="entry"><span class="def">mesmerism</span>, <span class="pos">n.</span> Hypnotism
+before it wore good clothes, kept a carriage and asked Incredulity to dinner.</p>
+
+<p class="entry"><span class="def">metropolis</span>, <span class="pos">n.</span> A
+stronghold of provincialism.</p>
+
+<p class="entry"><span class="def">millennium</span>, <span class="pos">n.</span> The
+period of a thousand years when the lid is to be screwed down, with all reformers on the under side.</p>
+
+<p class="entry"><span class="def">mind</span>, <span class="pos">n.</span> A
+mysterious form of matter secreted by the brain. Its chief activity consists in
+the endeavor to ascertain its own nature, the futility of the attempt being due
+to the fact that it has nothing but itself to know itself with. From the Latin <i>mens</i>, a fact unknown to that honest
+shoe-seller, who, observing that his learned competitor over the way had
+displayed the motto “<i>Mens conscia recti</i>,” emblazoned his own front with the
+words “Men’s, women’s and children’s conscia recti.”</p>
+
+<p class="entry"><span class="def">mine</span>, <span class="pos">adj.</span> Belonging
+to me if I can hold or seize it.</p>
+
+<p class="entry"><span class="def">minister</span>, <span class="pos">n.</span> An
+agent of a higher power with a lower responsibility. In diplomacy and officer
+sent into a foreign country as the visible embodiment of his sovereign’s
+hostility. His principal qualification is a degree of plausible inveracity next
+below that of an ambassador.</p>
+
+<p class="entry"><span class="def">minor</span>, <span class="pos">adj.</span> Less
+objectionable.</p>
+
+<p class="entry"><span class="def">minstrel</span>, <span class="pos">adj.</span> Formerly
+a poet, singer or musician; now a nigger with a color less than skin deep and a
+humor more than flesh and blood can bear.</p>
+
+<p class="entry"><span class="def">miracle</span>, <span class="pos">n.</span> An act
+or event out of the order of nature and unaccountable, as beating a normal hand
+of four kings and an ace with four aces and a king.</p>
+
+<p class="entry"><span class="def">miscreant</span>, <span class="pos">n.</span> A
+person of the highest degree of unworth. Etymologically, the word means
+unbeliever, and its present signification may be regarded as theology’s noblest
+contribution to the development of our language.</p>
+
+<p class="entry"><span class="def">misdemeanor</span>, <span class="pos">n.</span> An
+infraction of the law having less dignity than a felony and constituting no
+claim to admittance into the best criminal society.</p>
+
+<div class="poem">
+<p class="poetry">By misdemeanors he essays to climb</p>
+<p class="poetry">Into the aristocracy of crime.</p>
+<p class="poetry">O, woe was him!—with manner chill and grand “Captains of industry” refused his hand, “Kings of
+finance” denied him recognition And “railway magnates” jeered his low
+condition. He robbed a bank to make himself respected.</p>
+<p class="poetry">They still rebuffed him, for he was detected.</p>
+<p class="citeauth">S. V. Hanipur</p>
+</div>
+
+<p class="entry"><span class="def">misericorde</span>, <span class="pos">n.</span> A
+dagger which in mediaeval warfare was used by the foot soldier to remind an
+unhorsed knight that he was mortal.</p>
+
+<p class="entry"><span class="def">misfortune</span>, <span class="pos">n.</span> The
+kind of fortune that never misses.</p>
+
+<p class="entry"><span class="def">miss</span>, <span class="pos">n.</span> The title
+with which we brand unmarried women to indicate that they are in the market. Miss,
+Missis (Mrs.) and Mister (Mr.) are the three most distinctly disagreeable words
+in the language, in sound and sense. Two are corruptions of Mistress, the other
+of Master. In the general abolition of social titles in this our country they
+miraculously escaped to plague us. If we must have them let us be consistent
+and give one to the unmarried man. I venture to suggest Mush, abbreviated to
+Mh.</p>
+
+<p class="entry"><span class="def">molecule</span>, <span class="pos">n.</span> The
+ultimate, indivisible unit of matter. It is distinguished from the corpuscle,
+also the ultimate, indivisible unit of matter, by a closer resemblance to the
+atom, also the ultimate, indivisible unit of matter. Three great scientific
+theories of the structure of the universe are the molecular, the corpuscular
+and the atomic. A fourth affirms, with Haeckel, the condensation of
+precipitation of matter from ether—whose existence is proved by the
+condensation of precipitation. The present trend of scientific thought is
+toward the theory of ions. The ion differs from the molecule, the corpuscle and
+the atom in that it is an ion. A fifth theory is held by idiots, but it is
+doubtful if they know any more about the matter than the others.</p>
+
+<p class="entry"><span class="def">monad</span>, <span class="pos">n.</span> The
+ultimate, indivisible unit of matter. (See <i>Molecule</i>.)
+According to Leibnitz, as nearly as he seems willing to be understood, the
+monad has body without bulk, and mind without manifestation—Leibnitz knows him
+by the innate power of considering. He has founded upon him a theory of the
+universe, which the creature bears without resentment, for the monad is a
+gentlmean. Small as he is, the monad contains all the powers and possibilities
+needful to his evolution into a German philosopher of the first class—
+altogether a very capable little fellow. He is not to be confounded with the
+microbe, or bacillus; by its inability to discern him, a good microscope shows
+him to be of an entirely distinct species.</p>
+
+<p class="entry"><span class="def">monarch</span>, <span class="pos">n.</span> A
+person engaged in reigning. Formerly the monarch ruled, as the derivation of
+the word attests, and as many subjects have had occasion to learn. In Russia
+and the Orient the monarch has still a considerable influence in public affairs
+and in the disposition of the human head, but in western Europe political
+administration is mostly entrusted to his ministers, he being somewhat
+preoccupied with reflections relating to the status of his own head.</p>
+
+<p class="entry"><span class="def">monarchical government</span>, <span class="pos">n.</span> Government.</p>
+
+<p class="entry"><span class="def">Monday</span>, <span class="pos">n.</span> In
+Christian countries, the day after the baseball game.</p>
+
+<p class="entry"><span class="def">money</span>, <span class="pos">n.</span> A
+blessing that is of no advantage to us excepting when we part with it. An
+evidence of culture and a passport to polite society. Supportable property.</p>
+
+<p class="entry"><span class="def">monkey</span>, <span class="pos">n.</span> An
+arboreal animal which makes itself at home in genealogical trees.</p>
+
+<p class="entry"><span class="def">monosyllabic</span>, <span class="pos">adj.</span>
+Composed of words of one syllable, for literary babes who never tire of
+testifying their delight in the vapid compound by appropriate googoogling. The
+words are commonly Saxon—that is to say, words of a barbarous people destitute
+of ideas and incapable of any but the most elementary sentiments and emotions.</p>
+
+<div class="poem">
+<p class="poetry">The man who writes in Saxon</p>
+<p class="poetry">Is the man to use an ax on</p>
+<p class="citeauth">Judibras</p>
+</div>
+
+<p class="entry"><span class="def">monsignor</span>, <span class="pos">n.</span> A
+high ecclesiastical title, of which the Founder of our religion overlooked the advantages.</p>
+
+<p class="entry"><span class="def">monument</span>, <span class="pos">n.</span> A
+structure intended to commemorate something which either needs no commemoration
+or cannot be commemorated.</p>
+
+<div class="poem">
+<p class="poetry">The bones of Agammemnon are a show,</p>
+<p class="poetry">And ruined is his royal monument,</p>
+<p class="poetry">but Agammemnon’s
+fame suffers no diminution in consequence. The monument custom has its <i>reductiones ad absurdum</i> in monuments “to
+the unknown dead”—that is to say, monuments to perpetuate the memory of those
+who have left no memory.</p>
+</div>
+
+<p class="entry"><span class="def">moral</span>, <span class="pos">adj.</span> Conforming
+to a local and mutable standard of right. </p>
+
+<div class="poem">
+<p class="poetry">Having the quality of general expediency.</p>
+<p class="poetry">It is sayd there
+be a raunge of mountaynes in the Easte, on one syde of the which certayn
+conducts are immorall, yet on the other syde they are holden in good esteeme;
+wherebye the mountayneer is much conveenyenced, for it is given to him to goe
+downe eyther way and act as it shall suite his moode, withouten offence.</p>
+<p class="citeauth"><i>Gooke’s Meditations</i></p>
+</div>
+
+<p class="entry"><span class="def">more</span>, <span class="pos">adj.</span> The
+comparative degree of too much.</p>
+
+<p class="entry"><span class="def">mouse</span>, <span class="pos">n.</span> An
+animal which strews its path with fainting women. As in Rome Christians were
+thrown to the lions, so centuries earlier in Otumwee, the most ancient and
+famous city of the world, female heretics were thrown to the mice. Jakak-Zotp,
+the historian, the only Otumwump whose writings have descended to us, says that
+these martyrs met their death with little dignity and much exertion. He even
+attempts to exculpate the mice (such is the malice of bigotry) by declaring
+that the unfortunate women perished, some from exhaustion, some of broken necks
+from falling over their own feet, and some from lack of restoratives. The mice,
+he avers, enjoyed the pleasures of the chase with composure. But if “Roman
+history is nine-tenths lying,” we can hardly expect a smaller proportion of
+that rhetorical figure in the annals of a people capable of so incredible
+cruelty to a lovely women; for a hard heart has a false tongue.</p>
+
+<p class="entry"><span class="def">mousquetaire</span>, <span class="pos">n.</span> A
+long glove covering a part of the arm. Worn in New Jersey. But “mousquetaire”
+is a might poor way to spell muskeeter.</p>
+
+<p class="entry"><span class="def">mouth</span>, <span class="pos">n.</span> In man,
+the gateway to the soul; in woman, the outlet of the heart.</p>
+
+<p class="entry"><span class="def">mugwump</span>, <span class="pos">n.</span> In
+politics one afflicted with self-respect and addicted to the vice of
+independence. A term of contempt.</p>
+
+<p class="entry"><span class="def">mulatto</span>, <span class="pos">n.</span> A
+child of two races, ashamed of both.</p>
+
+<p class="entry"><span class="def">multitude</span>, <span class="pos">n.</span> A
+crowd; the source of political wisdom and virtue. In a republic, the object of
+the statesman’s adoration. “In a multitude of consellors there is wisdom,”
+saith the proverb. If many men of equal individual wisdom are wiser than any
+one of them, it must be that they acquire the excess of wisdom by the mere act
+of getting together. Whence comes it? Obviously from nowhere—as well say that a
+range of mountains is higher than the single mountains composing it. A
+multitude is as wise as its wisest member if it obey him; if not, it is no
+wiser than its most foolish.</p>
+
+<p class="entry"><span class="def">mummy</span>, <span class="pos">n.</span> An
+ancient Egyptian, formerly in universal use among modern civilized nations as
+medicine, and now engaged in supplying art with an excellent pigment. He is
+handy, too, in museums in gratifying the vulgar curiosity that serves to
+distinguish man from the lower animals.</p>
+
+<div class="poem">
+<p class="poetry">By means of the
+Mummy, mankind, it is said, Attests to the gods its respect for the dead. We
+plunder his tomb, be he sinner or saint, Distil him for physic and grind him
+for paint, Exhibit for money his poor, shrunken frame, And with levity flock to
+the scene of the shame.</p>
+<p class="poetry">O, tell me, ye gods, for the use of my rhyme:</p>
+<p class="poetry">For respecting the dead what’s the limit of time?</p>
+<p class="citeauth">Scopas Brune</p>
+</div>
+
+<p class="entry"><span class="def">mustang</span>, <span class="pos">n.</span> An
+indocile horse of the western plains. In English society, the American wife of
+an English nobleman.</p>
+
+<p class="entry"><span class="def">myrmidon</span>, <span class="pos">n.</span> A
+follower of Achilles—particularly when he didn’t lead.</p>
+
+<p class="entry"><span class="def">mythology</span>, <span class="pos">n.</span> The
+body of a primitive people’s beliefs concerning its origin, early history,
+heroes, deities and so forth, as distinguished from the true accounts which it
+invents later.</p>
+
+</body>
+</html>
\ No newline at end of file
--- /dev/null
+++ b/lib/ebooks/devils/M.html.i
@@ -1,0 +1,46 @@
+21 pages
+size 400 552
+length 31261
+396 2 10 body html
+0
+1279 2 33 body html
+90
+2468 2 50 body html
+324
+2468 2 50 body html
+864
+2468 2 50 body html
+1404
+5710 2 110 body html
+90
+7282 2 137 body html
+226
+8950 2 162 body html
+324
+11206 2 207 body html
+0
+11585 2 213 body html
+451
+13420 2 247 body html
+39
+15429 2 287 body html
+34
+16387 2 309 body html
+73
+16760 2 315 body html
+523
+18848 2 358 body html
+0
+20940 2 394 body html
+39
+22560 2 424 body html
+56
+24843 2 458 body html
+22
+26303 2 487 body html
+108
+27455 2 512 body html
+226
+30146 2 556 body html
+87
+male 7
--- /dev/null
+++ b/lib/ebooks/devils/N.html
@@ -1,0 +1,130 @@
+<?xml version="1.0"?>
+<!DOCTYPE package PUBLIC "+//ISBN 0-9673008-1-9//DTD OEB 1.0 Package//EN"
+ "http://openebook.org/dtds/oeb-1.0/oebdoc1.dtd">
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/x-oeb1-document; charset=utf-8" />
+<link rel="stylesheet" type="text/x-oeb1-css" href="devil.css" />
+<title>The Devil’s Dictionary: N</title>
+</head>
+<body lang="en-US">
+
+
+<h1>N</h1>
+
+<p class="entry"><span class="def">nectar</span>, <span class="pos">n.</span> A drink
+served at banquets of the Olympian deities. The secret of its preparation is
+lost, but the modern Kentuckians believe that they come pretty near to a
+knowledge of its chief ingredient.</p>
+
+<div class="poem">
+<p class="poetry">Juno drank a cup of nectar,</p>
+<p class="poetry">But the draught did not affect her.</p>
+<p class="poetry">Juno drank a cup of rye—</p>
+<p class="poetry">Then she bad herself good-bye.</p>
+<p class="citeauth">J. G.</p>
+</div>
+
+<p class="entry"><span class="def">negro</span>, <span class="pos">n.</span> The <i>piece de resistance</i> in the American
+political problem. Representing him by the letter n, the Republicans begin to
+build their equation thus: “Let n = the white man.” This, however, appears to
+give an unsatisfactory solution.</p>
+
+<p class="entry"><span class="def">neighbor</span>, <span class="pos">n.</span> One
+whom we are commanded to love as ourselves, and who does all he knows how to
+make us disobedient.</p>
+
+<p class="entry"><span class="def">nepotism</span>, <span class="pos">n.</span> Appointing
+your grandmother to office for the good of the party.</p>
+
+<p class="entry"><span class="def">Newtonian</span>, <span class="pos">adj.</span> Pertaining
+to a philosophy of the universe invented by Newton, who discovered that an
+apple will fall to the ground, but was unable to say why. His successors and
+disciples have advanced so far as to be able to say when.</p>
+
+<p class="entry"><span class="def">nihilist</span>, <span class="pos">n.</span> A
+Russian who denies the existence of anything but Tolstoi. The leader of the
+school is Tolstoi.</p>
+
+<p class="entry"><span class="def">Nirvana</span>, <span class="pos">n.</span> In the
+Buddhist religion, a state of pleasurable annihilation awarded to the wise,
+particularly to those wise enough to understand it.</p>
+
+<p class="entry"><span class="def">nobleman</span>, <span class="pos">n.</span> Nature’s
+provision for wealthy American minds ambitious to incur social distinction and
+suffer high life.</p>
+
+<p class="entry"><span class="def">noise</span>, <span class="pos">n.</span> A stench
+in the ear. Undomesticated music. The chief product and authenticating sign of
+civilization.</p>
+
+<p class="entry"><span class="def">nominate</span>, <span class="pos">v.</span> To
+designate for the heaviest political assessment. To put forward a suitable
+person to incur the mudgobbling and deadcatting of the opposition.</p>
+
+<p class="entry"><span class="def">nominee</span>, <span class="pos">n.</span> A
+modest gentleman shrinking from the distinction of private life and diligently
+seeking the honorable obscurity of public office.</p>
+
+<p class="entry"><span class="def">non-combatant</span>, <span class="pos">n.</span> A
+dead Quaker.</p>
+
+<p class="entry"><span class="def">nonsense</span>, <span class="pos">n.</span> The
+objections that are urged against this excellent dictionary.</p>
+
+<p class="entry"><span class="def">nose</span>, <span class="pos">n.</span> The
+extreme outpost of the face. From the circumstance that great conquerors have
+great noses, Getius, whose writings antedate the age of humor, calls the nose
+the organ of quell. It has been observed that one’s nose is never so happy as
+when thrust into the affairs of others, from which some physiologists have
+drawn the inference that the nose is devoid of the sense of smell.</p>
+
+<div class="poem">
+<p class="poetry">There’s a man with a Nose,</p>
+<p class="poetry">And wherever he goes</p>
+<p class="poetry">The people run from him and shout:</p>
+<p class="poetry">“No cotton have we</p>
+<p class="poetry">For our ears if so be</p>
+<p class="poetry">He blow that interminous snout!”</p>
+<p class="poetry">So the lawyers applied</p>
+<p class="poetry">For injunction. “Denied,”</p>
+<p class="poetry">Said the Judge: “the defendant prefixion,</p>
+<p class="poetry">Whate’er it portend,</p>
+<p class="poetry">Appears to transcend</p>
+<p class="poetry">The bounds of this court’s jurisdiction.”</p>
+<p class="citeauth">Arpad Singiny</p>
+</div>
+
+<p class="entry"><span class="def">notoriety</span>, <span class="pos">n.</span> The
+fame of one’s competitor for public honors. The kind of renown most accessible
+and acceptable to mediocrity. A Jacob’s-ladder leading to the vaudeville stage,
+with angels ascending and descending.</p>
+
+<p class="entry"><span class="def">noumenon</span>, <span class="pos">n.</span> That
+which exists, as distinguished from that which merely seems to exist, the
+latter being a phenomenon. The noumenon is a bit difficult to locate; it can be
+apprehended only be a process of reasoning—which is a phenomenon. Nevertheless,
+the discovery and exposition of noumena offer a rich field for what Lewes calls
+“the endless variety and excitement of philosophic thought.” Hurrah (therefore)
+for the noumenon!</p>
+
+<p class="entry"><span class="def">novel</span>, <span class="pos">n.</span> A short
+story padded. A species of composition bearing the same relation to literature
+that the panorama bears to art. As it is too long to be read at a sitting the
+impressions made by its successive parts are successively effaced, as in the
+panorama. Unity, totality of effect, is impossible; for besides the few pages
+last read all that is carried in mind is the mere plot of what has gone before.
+To the romance the novel is what photography is to painting. Its distinguishing
+principle, probability, corresponds to the literal actuality of the photograph
+and puts it distinctly into the category of reporting; whereas the free wing of
+the romancer enables him to mount to such altitudes of imagination as he may be
+fitted to attain; and the first three essentials of the literary art are
+imagination, imagination and imagination. The art of writing novels, such as it
+was, is long dead everywhere except in Russia, where it is new. Peace to its
+ashes—some of which have a large sale.</p>
+
+<p class="entry"><span class="def">November</span>, <span class="pos">n.</span> The
+eleventh twelfth of a weariness.</p>
+
+</body>
+</html>
\ No newline at end of file
--- /dev/null
+++ b/lib/ebooks/devils/N.html.i
@@ -1,0 +1,11 @@
+4 pages
+size 400 552
+length 6554
+396 2 10 body html
+0
+1613 2 40 body html
+22
+3863 2 82 body html
+19
+4833 2 103 body html
+0
--- /dev/null
+++ b/lib/ebooks/devils/O.html
@@ -1,0 +1,304 @@
+<?xml version="1.0"?>
+<!DOCTYPE package PUBLIC "+//ISBN 0-9673008-1-9//DTD OEB 1.0 Package//EN"
+ "http://openebook.org/dtds/oeb-1.0/oebdoc1.dtd">
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/x-oeb1-document; charset=utf-8" />
+<link rel="stylesheet" type="text/x-oeb1-css" href="devil.css" />
+<title>The Devil’s Dictionary: O</title>
+</head>
+<body lang="en-US">
+
+
+<h1>O</h1>
+
+<p class="entry"><span class="def">oath</span>, <span class="pos">n.</span> In law, a
+solemn appeal to the Deity, made binding upon the conscience by a penalty for
+perjury.</p>
+
+<p class="entry"><span class="def">oblivion</span>, <span class="pos">n.</span> The
+state or condition in which the wicked cease from struggling and the dreary are
+at rest. Fame’s eternal dumping ground. Cold storage for high hopes. A place
+where ambitious authors meet their works without pride and their betters
+without envy. A dormitory without an alarm clock.</p>
+
+<p class="entry"><span class="def">observatory</span>, <span class="pos">n.</span> A
+place where astronomers conjecture away the guesses of their predecessors.</p>
+
+<p class="entry"><span class="def">obsessed,</span> <span class="pos">p.p.</span> Vexed
+by an evil spirit, like the Gadarene swine and other critics. Obsession was once
+more common than it is now. Arasthus tells of a peasant who was occupied by a
+different devil for every day in the week, and on Sundays by two. They were
+frequently seen, always walking in his shadow, when he had one, but were
+finally driven away by the village notary, a holy man; but they took the
+peasant with them, for he vanished utterly. A devil thrown out of a woman by
+the Archbishop of Rheims ran through the trees, pursued by a hundred persons,
+until the open country was reached, where by a leap higher than a church spire
+he escaped into a bird. A chaplain in Cromwell’s army exorcised a soldier’s
+obsessing devil by throwing the soldier into the water, when the devil came to
+the surface. The soldier, unfortunately, did not.</p>
+
+<p class="entry"><span class="def">obsolete</span>, <span class="pos">adj.</span> No longer
+used by the timid. Said chiefly of words. A word which some lexicographer has
+marked obsolete is ever thereafter an object of dread and loathing to the fool
+writer, but if it is a good word and has no exact modern equivalent equally
+good, it is good enough for the good writer. Indeed, a writer’s attitude toward
+“obsolete” words is as true a measure of his literary ability as anything
+except the character of his work. A dictionary of obsolete and obsolescent
+words would not only be singularly rich in strong and sweet parts of speech; it
+would add large possessions to the vocabulary of every competent writer who
+might not happen to be a competent reader.</p>
+
+<p class="entry"><span class="def">obstinate</span>, <span class="pos">adj.</span> Inaccessible
+to the truth as it is manifest in the splendor and stress of our advocacy.</p>
+
+<p>The popular type and exponent of obstinacy is the mule, a most intelligent animal.</p>
+
+<p class="entry"><span class="def">occasional</span>, <span class="pos">adj.</span> Afflicting us with
+greater or less frequency. That, however, is not the sense in which the word is used in the phrase
+“occasional verses,” which are verses written for an “occasion,” such as an anniversary, a celebration or
+other event. True, they afflict us a little worse than other sorts of verse, but their name has no reference to
+irregular recurrence.</p>
+
+<p class="entry"><span class="def">occident</span>, <span class="pos">n.</span> The
+part of the world lying west (or east) of the Orient. It is largely inhabited
+by Christians, a powerful subtribe of the Hypocrites, whose principal
+industries are murder and cheating, which they are pleased to call “war” and
+“commerce.” These, also, are the principal industries of the Orient.</p>
+
+<p class="entry"><span class="def">ocean</span>, <span class="pos">n.</span> A body
+of water occupying about two-thirds of a world made for man—who has no gills.</p>
+
+<p class="entry"><span class="def">offensive</span>, <span class="pos">adj.</span> Generating
+disagreeable emotions or sensations, as the advance of an army against its enemy.</p>
+
+<p>“Were the enemy’s tactics offensive?” the king asked. “I should say so!” replied the unsuccessful
+general. “The blackguard wouldn’t come out of his works!”</p>
+
+<p class="entry"><span class="def">old</span>, <span class="pos">adj.</span> In that
+stage of usefulness which is not inconsistent with general inefficiency, as an <i>old man</i>. Discredited by lapse of time and
+offensive to the popular taste, as an <i>old</i>
+book.</p>
+
+<div class="poem">
+<p class="poetry">“Old books? The devil take them!” Goby said.</p>
+<p class="poetry">“Fresh every day must be my books and bread.”</p>
+<p class="poetry">Nature herself approves the Goby rule</p>
+<p class="poetry">And gives us every moment a fresh fool.</p>
+<p class="citeauth">Harley Shum</p>
+</div>
+
+<p class="entry"><span class="def">oleginous</span>, <span class="pos">adj.</span> Oily,
+smooth, sleek.</p>
+
+<p>Disraeli once described the manner of Bishop Wilberforce as “unctuous, oleaginous,
+saponaceous.” And the good prelate was ever afterward known as Soapy Sam. For
+every man there is something in the vocabulary that would stick to him like a
+second skin. His enemies have only to find it.</p>
+
+<p class="entry"><span class="def">Olympian</span>, <span class="pos">adj.</span> Relating
+to a mountain in Thessaly, once inhabited by gods, now a repository of
+yellowing newspapers, beer bottles and mutilated sardine cans, attesting the
+presence of the tourist and his appetite.</p>
+
+<div class="poem">
+<p class="poetry">His name the smirking tourist scrawls</p>
+<p class="poetry">Upon Minerva’s temple walls,</p>
+<p class="poetry">Where thundered once Olympian Zeus,</p>
+<p class="poetry">And marks his appetite’s abuse.</p>
+<p class="citeauth">Averil Joop</p>
+</div>
+
+<p class="entry"><span class="def">omen</span>, <span class="pos">n.</span> A sign
+that something will happen if nothing happens.</p>
+
+<p class="entry"><span class="def">once</span>, <span class="pos">adv.</span> Enough.</p>
+
+<p class="entry"><span class="def">opera</span>, <span class="pos">n.</span> A play
+representing life in another world, whose inhabitants have no speech but song,
+no motions but gestures and no postures but attitudes. All acting is
+simulation, and the word <i>simulation</i> is from <i>simia</i>, an ape; but in
+opera the actor takes for his model <i>Simia audibilis</i> (or <i>Pithecanthropos
+stentor</i>)—the ape that howls.</p>
+
+<div class="poem">
+<p class="poetry">The actor apes a man—at least in shape;</p>
+<p class="poetry">The opera performer apes and ape.</p>
+</div>
+
+<p class="entry"><span class="def">Opiate</span>, <span class="pos">n.</span> An
+unlocked door in the prison of Identity. It leads into the jail yard.</p>
+
+<p class="entry"><span class="def">opportunity</span>, <span class="pos">n.</span> A
+favorable occasion for grasping a disappointment.</p>
+
+<p class="entry"><span class="def">oppose</span>, <span class="pos">v.</span> To
+assist with obstructions and objections.</p>
+
+<div class="poem">
+<p class="poetry">How lonely he who thinks to vex</p>
+<p class="poetry">With bandinage the Solemn Sex!</p>
+<p class="poetry">Of levity, Mere Man, beware;</p>
+<p class="poetry">None but the Grave deserve the Unfair.</p>
+<p class="citeauth">Percy P. Orminder</p>
+</div>
+
+<p class="entry"><span class="def">opposition</span>, <span class="pos">n.</span> In
+politics the party that prevents the Government from running amuck by hamstringing it.</p>
+
+<p>The King of Ghargaroo, who had been abroad to study the science of government, appointed
+one hundred of his fattest subjects as members of a parliament to make laws for
+the collection of revenue. Forty of these he named the Party of Opposition and
+had his Prime Minister carefully instruct them in their duty of opposing every
+royal measure. Nevertheless, the first one that was submitted passed unanimously.
+Greatly displeased, the King vetoed it, informing the Opposition that if they
+did that again they would pay for their obstinacy with their heads. The entire
+forty promptly disemboweled themselves.</p>
+
+<p>“What shall we do now?” the King asked. “Liberal institutions cannot be maintained without a
+party of Opposition.”</p>
+
+<p>“Splendor of the universe,” replied the Prime Minister, “it is true these dogs of darkness have
+no longer their credentials, but all is not lost. Leave the matter to this worm of the dust.”</p>
+
+<p>So the Minister had the bodies of his Majesty’s Opposition embalmed and stuffed with straw, put
+back into the seats of power and nailed there. Forty votes were recorded
+against every bill and the nation prospered. But one day a bill imposing a tax
+on warts was defeated—the members of the Government party had not been nailed
+to their seats! This so enraged the King that the Prime Minister was put to
+death, the parliament was dissolved with a battery of artillery, and government
+of the people, by the people, for the people perished from Ghargaroo.</p>
+
+<p class="entry"><span class="def">optimism</span>, <span class="pos">n.</span> The
+doctrine, or belief, that everything is beautiful, including what is ugly,
+everything good, especially the bad, and everything right that is wrong. It is
+held with greatest tenacity by those most accustomed to the mischance of
+falling into adversity, and is most acceptably expounded with the grin that
+apes a smile. Being a blind faith, it is inaccessible to the light of
+disproof—an intellectual disorder, yielding to no treatment but death. It is
+hereditary, but fortunately not contagious.</p>
+
+<p class="entry"><span class="def">optimist</span>, <span class="pos">n.</span> A proponent of the
+doctrine that black is white.</p>
+
+<p>A pessimist applied to God for relief.</p>
+<p>“Ah, you wish me to restore your hope and cheerfulness,” said God.</p>
+<p>“No,” replied the petitioner, “I wish you to create something that would justify them.”</p>
+<p>“The world is all created,” said God, “but you have overlooked something—the mortality of the optimist.”</p>
+
+<p class="entry"><span class="def">oratory</span>, <span class="pos">n.</span> A
+conspiracy between speech and action to cheat the understanding. A tyranny
+tempered by stenography.</p>
+
+<p class="entry"><span class="def">orphan</span>, <span class="pos">n.</span> A
+living person whom death has deprived of the power of filial ingratitude—a
+privation appealing with a particular eloquence to all that is sympathetic in
+human nature. When young the orphan is commonly sent to an asylum, where by
+careful cultivation of its rudimentary sense of locality it is taught to know
+its place. It is then instructed in the arts of dependence and servitude and
+eventually turned loose to prey upon the world as a bootblack or scullery maid.</p>
+
+<p class="entry"><span class="def">orthodox</span>, <span class="pos">n.</span> An ox
+wearing the popular religious joke.</p>
+
+<p class="entry"><span class="def">orthography</span>, <span class="pos">n.</span> The
+science of spelling by the eye instead of the ear. Advocated with more heat
+than light by the outmates of every asylum for the insane. They have had to
+concede a few things since the time of Chaucer, but are none the less hot in
+defence of those to be conceded hereafter.</p>
+
+<div class="poem">
+<p class="poetry">A spelling reformer indicted</p>
+<p class="poetry">For fudge was before the court cicted.</p>
+<p class="poetry">The judge said: “Enough—</p>
+<p class="poetry">His candle we’ll snough,</p>
+<p class="poetry">And his sepulchre shall not be whicted.”</p>
+</div>
+
+<p class="entry"><span class="def">ostrich</span>, <span class="pos">n.</span> A large
+bird to which (for its sins, doubtless) nature has denied that hinder toe in
+which so many pious naturalists have seen a conspicuous evidence of design. The
+absence of a good working pair of wings is no defect, for, as has been
+ingeniously pointed out, the ostrich does not fly.</p>
+
+<p class="entry"><span class="def">otherwise</span>, <span class="pos">adv.</span> No better.</p>
+
+<p class="entry"><span class="def">outcome</span>, <span class="pos">n.</span> A
+particular type of disappointment. By the kind of intelligence that sees in an
+exception a proof of the rule the wisdom of an act is judged by the outcome,
+the result. This is immortal nonsense; the wisdom of an act is to be juded by
+the light that the doer had when he performed it.</p>
+
+<p class="entry"><span class="def">outdo</span>, <span class="pos">v.t.</span> To
+make an enemy.</p>
+
+<p class="entry"><span class="def">out-of-doors</span>, <span class="pos">n.</span> That
+part of one’s environment upon which no government has been able to collect
+taxes. Chiefly useful to inspire poets.</p>
+
+<div class="poem">
+<p class="poetry">I climbed to the top of a mountain one day</p>
+<p class="poetry">To see the sun setting in glory,</p>
+<p class="poetry">And I thought, as I looked at his vanishing ray,</p>
+<p class="poetry">Of a perfectly splendid story.</p>
+<p class="poetry">‘Twas about an old man and the ass he bestrode</p>
+<p class="poetry">Till the strength of the beast was o’ertested;</p>
+<p class="poetry">Then the man would carry him miles on the road</p>
+<p class="poetry">Till Neddy was pretty well rested.</p>
+<p class="poetry">The moon rising solemnly over the crest</p>
+<p class="poetry">Of the hills to the east of my station</p>
+<p class="poetry">Displayed her broad disk to the darkening west</p>
+<p class="poetry">Like a visible new creation.</p>
+<p class="poetry">And I thought of a joke (and I laughed till I cried)</p>
+<p class="poetry">Of an idle young woman who tarried</p>
+<p class="poetry">About a church-door for a look at the bride,</p>
+<p class="poetry">Although ‘twas herself that was married.</p>
+<p class="poetry">To poets all Nature is pregnant with grand</p>
+<p class="poetry">Ideas—with thought and emotion.</p>
+<p class="poetry">I pity the dunces who don’t understand</p>
+<p class="poetry">The speech of earth, heaven and ocean.</p>
+<p class="citeauth">Stromboli Smith</p>
+</div>
+
+<p class="entry"><span class="def">ovation</span>, <span class="pos">n.</span> n
+ancient Rome, a definite, formal pageant in honor of one who had been
+disserviceable to the enemies of the nation. A lesser “triumph.” In modern
+English the word is improperly used to signify any loose and spontaneous
+expression of popular homage to the hero of the hour and place.</p>
+
+<div class="poem">
+<p class="poetry">“I had an ovation!” the actor man said,</p>
+<p class="poetry">But I thought it uncommonly queer,</p>
+<p class="poetry">That people and critics by him had been led</p>
+<p class="poetry">By the ear.</p>
+<p class="poetry">The Latin lexicon makes his absurd</p>
+<p class="poetry">Assertion as plain as a peg;</p>
+<p class="poetry">In “ovum” we find the true root of the word.</p>
+<p class="poetry">It means egg.</p>
+<p class="citeauth">Dudley Spink</p>
+</div>
+
+<p class="entry"><span class="def">overeat</span>, <span class="pos">v.</span> To
+dine.</p>
+
+<div class="poem">
+<p class="poetry">Hail, Gastronome, Apostle of Excess, Well skilled to overeat without distress!</p>
+<p class="poetry">Thy great invention, the unfatal feast,</p>
+<p class="poetry">Shows Man’s superiority to Beast.</p>
+<p class="citeauth">John Boop</p>
+</div>
+
+<p class="entry"><span class="def">overwork</span>, <span class="pos">n.</span> A
+dangerous disorder affecting high public functionaries who want to go fishing.</p>
+
+<p class="entry"><span class="def">owe</span>, <span class="pos">v.</span> To have
+(and to hold) a debt. The word formerly signified not indebtedness, but possession;
+it meant “own,” and in the minds of debtors there is still a good deal of
+confusion between assets and liabilities.</p>
+
+<p class="entry"><span class="def">oyster</span>, <span class="pos">n.</span> A
+slimy, gobby shellfish which civilization gives men the hardihood to eat
+without removing its entrails! The shells are sometimes given to the poor.</p>
+
+</body>
+</html>
\ No newline at end of file
--- /dev/null
+++ b/lib/ebooks/devils/O.html.i
@@ -1,0 +1,25 @@
+11 pages
+size 400 552
+length 16292
+396 2 10 body html
+0
+2042 2 41 body html
+39
+4269 2 75 body html
+0
+5743 2 104 body html
+0
+7267 2 138 body html
+0
+8683 2 164 body html
+0
+10316 2 189 body html
+0
+11848 2 218 body html
+56
+13002 2 239 body html
+324
+14705 2 269 body html
+0
+15582 2 291 body html
+0
--- /dev/null
+++ b/lib/ebooks/devils/P.html
@@ -1,0 +1,653 @@
+<?xml version="1.0"?>
+<!DOCTYPE package PUBLIC "+//ISBN 0-9673008-1-9//DTD OEB 1.0 Package//EN"
+ "http://openebook.org/dtds/oeb-1.0/oebdoc1.dtd">
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/x-oeb1-document; charset=utf-8" />
+<link rel="stylesheet" type="text/x-oeb1-css" href="devil.css" />
+<title>The Devil’s Dictionary: P</title>
+</head>
+<body lang="en-US">
+
+
+<h1>P</h1>
+
+<p class="entry"><span class="def">pain</span>, <span class="pos">n.</span> An
+uncomfortable frame of mind that may have a physical basis in something that is
+being done to the body, or may be purely mental, caused by the good fortune of
+another.</p>
+
+<p class="entry"><span class="def">painting</span>, <span class="pos">n.</span> The
+art of protecting flat surfaces from the weather and exposing them to the critic.</p>
+
+<p>Formerly, painting and sculpture were combined in the same work: </p>
+
+<p>the ancients painted their statues. The only present alliance between the two arts is that
+the modern painter chisels his patrons.</p>
+
+<p class="entry"><span class="def">palace</span>, <span class="pos">n.</span> A fine
+and costly residence, particularly that of a great official. The residence of a
+high dignitary of the Christian Church is called a palace; that of the Founder
+of his religion was known as a field, or wayside. There is progress.</p>
+
+<p class="entry"><span class="def">palm</span>, <span class="pos">n.</span> A species
+of tree having several varieties, of which the familiar “itching palm” (<i>Palma
+hominis</i>) is most widely distributed and sedulously cultivated. This noble
+vegetable exudes a kind of invisible gum, which may be detected by applying to
+the bark a piece of gold or silver. The metal will adhere with remarkable
+tenacity. The fruit of the itching palm is so bitter and unsatisfying that a
+considerable percentage of it is sometimes given away in what are known as
+“benefactions.”</p>
+
+<p class="entry"><span class="def">palmistry</span>, <span class="pos">n.</span> The
+947<sup>th</sup> method (according to Mimbleshaw’s classification) of obtaining
+money by false pretences. It consists in “reading character” in the wrinkles
+made by closing the hand. The pretence is not altogether false; character can
+really be read very accurately in this way, for the wrinkles in every hand
+submitted plainly spell the word “dupe.” The imposture consists in not reading
+it aloud.</p>
+
+<p class="entry"><span class="def">pandemonium </span>, <span class="pos">n.</span> Literally,
+the Place of All the Demons. Most of them have escaped into politics and
+finance, and the place is now used as a lecture hall by the Audible Reformer. When
+disturbed by his voice the ancient echoes clamor appropriate responses most
+gratifying to his pride of distinction.</p>
+
+<p class="entry"><span class="def">pantaloons</span>, <span class="pos">n.</span> A
+nether habiliment of the adult civilized male. The garment is tubular and
+unprovided with hinges at the points of flexion. Supposed to have been invented
+by a humorist. Called “trousers” by the enlightened and “pants” by the
+unworthy.</p>
+
+<p class="entry"><span class="def">pantheism</span>, <span class="pos">n.</span> The
+doctrine that everything is God, in contradistinction to the doctrine that God is everything.</p>
+
+<p class="entry"><span class="def">pantomime</span>, <span class="pos">n.</span> A
+play in which the story is told without violence to the language. The least
+disagreeable form of dramatic action.</p>
+
+<p class="entry"><span class="def">pardon</span>, <span class="pos">v.</span> To
+remit a penalty and restore to the life of crime. To add to the lure of crime
+the temptation of ingratitude.</p>
+
+<p class="entry"><span class="def">passport</span>, <span class="pos">n.</span> A
+document treacherously inflicted upon a citizen going abroad, exposing him as
+an alien and pointing him out for special reprobation and outrage.</p>
+
+<p class="entry"><span class="def">past</span>, <span class="pos">n.</span> That part
+of Eternity with some small fraction of which we have a slight and regrettable
+acquaintance. A moving line called the Present parts it from an imaginary
+period known as the Future. These two grand divisions of Eternity, of which the
+one is continually effacing the other, are entirely unlike. The one is dark
+with sorrow and disappointment, the other bright with prosperity and joy. The
+Past is the region of sobs, the Future is the realm of song. In the one
+crouches Memory, clad in sackcloth and ashes, mumbling penitential prayer; in
+the sunshine of the other Hope flies with a free wing, beckoning to temples of
+success and bowers of ease. Yet the Past is the Future of yesterday, the Future
+is the Past of to-morrow. They are one—the knowledge and the dream.</p>
+
+<p class="entry"><span class="def">pastime</span>, <span class="pos">n.</span> A
+device for promoting dejection. Gentle exercise for intellectual debility.</p>
+
+<p class="entry"><span class="def">patience</span>, <span class="pos">n.</span> A
+minor form of despair, disguised as a virtue.</p>
+
+<p class="entry"><span class="def">patriot</span>, <span class="pos">n.</span> One to
+whom the interests of a part seem superior to those of the whole. The dupe of
+statesmen and the tool of conquerors.</p>
+
+<p class="entry"><span class="def">patriotism</span>, <span class="pos">n.</span> Combustible
+rubbish read to the torch of any one ambitious to illuminate his name.</p>
+
+<p>In Dr. Johnson’s famous dictionary patriotism is defined as the last resort of a scoundrel. With
+all due respect to an enlightened but inferior lexicographer I beg to submit
+that it is the first.</p>
+
+<p class="entry"><span class="def">peace</span>, <span class="pos">n.</span> In
+international affairs, a period of cheating between two periods of fighting.</p>
+
+<div class="poem">
+<p class="poetry">O, what’s the loud uproar assailing</p>
+<p class="poetry">Mine ears without cease?</p>
+<p class="poetry">‘Tis the voice of the hopeful, all-hailing</p>
+<p class="poetry">The horrors of peace.</p>
+<p class="poetry">Ah, Peace Universal; they woo it—</p>
+<p class="poetry">Would marry it, too.</p>
+<p class="poetry">If only they knew how to do it</p>
+<p class="poetry">‘Twere easy to do.</p>
+<p class="poetry">They’re working by night and by day</p>
+<p class="poetry">On their problem, like moles.</p>
+<p class="poetry">Have mercy, O Heaven, I pray,</p>
+<p class="poetry">On their meddlesome souls!</p>
+<p class="citeauth">Ro Amil</p>
+</div>
+
+<p class="entry"><span class="def">pedestrian</span>, <span class="pos">n.</span> The
+variable (an audible) part of the roadway for an automobile.</p>
+
+<p class="entry"><span class="def">pedigree</span>, <span class="pos">n.</span> The
+known part of the route from an arboreal ancestor with a swim bladder to an
+urban descendant with a cigarette.</p>
+
+<p class="entry"><span class="def">penitentN</span>, <span class="pos">adj.</span> Undergoing
+or awaiting punishment.</p>
+
+<p class="entry"><span class="def">perfection</span>, <span class="pos">n.</span> An
+imaginary state of quality distinguished from the actual by an element known as
+excellence; an attribute of the critic.</p>
+
+<p class="indentpara">The editor of an English magazine having received a letter pointing out the erroneous nature of
+his views and style, and signed “Perfection,” promptly wrote at the foot of the
+letter: “I don’t agree with you,” and mailed it to Matthew Arnold.</p>
+
+<p class="entry"><span class="def">peripatetic</span>, <span class="pos">adj.</span> Walking
+about. Relating to the philosophy of Aristotle, who, while expounding it, moved
+from place to place in order to avoid his pupil’s objections. A needless
+precaution—they knew no more of the matter than he.</p>
+
+<p class="entry"><span class="def">peroration</span>, <span class="pos">n.</span> The
+explosion of an oratorical rocket. It dazzles, but to an observer having the
+wrong kind of nose its most conspicuous peculiarity is the smell of the several
+kinds of powder used in preparing it.</p>
+
+<p class="entry"><span class="def">perseverance</span>, <span class="pos">n.</span> A
+lowly virtue whereby mediocrity achieves an inglorious success.</p>
+
+<div class="poem">
+<p class="poetry">“Persevere, persevere!” cry the homilists all,<br />
+Themselves, day and night, persevering to bawl.<br />
+“Remember the fable of tortoise and hare—</p>
+<p class="poetry">The one at the goal while the other is—where?”<br />
+Why, back there in Dreamland, renewing his lease<br />
+Of life, all his muscles preserving the peace,<br />
+The goal and the rival forgotten alike,<br />
+And the long fatigue of the needless hike.</p>
+<p class="poetry">His spirit a-squat in the grass and the dew</p>
+<p class="poetry">Of the dogless Land beyond the Stew,</p>
+<p class="poetry">He sleeps, like a saint in a holy place,</p>
+<p class="poetry">A winner of all that is good in a race.</p>
+<p class="citeauth">Sukker Uffro</p>
+</div>
+
+<p class="entry"><span class="def">pessimism</span>, <span class="pos">n.</span> A
+philosophy forced upon the convictions of the observer by the disheartening
+prevalence of the optimist with his scarecrow hope and his unsightly smile.</p>
+
+<p class="entry"><span class="def">philanthropist</span>, <span class="pos">n.</span>
+A rich (and usually bald) old gentleman who has trained himself to grin while
+his conscience is picking his pocket.</p>
+
+<p class="entry"><span class="def">philistine</span>, <span class="pos">n.</span> One
+whose mind is the creature of its environment, following the fashion in
+thought, feeling and sentiment. He is sometimes learned, frequently prosperous,
+commonly clean and always solemn.</p>
+
+<p class="entry"><span class="def">philosophy</span>, <span class="pos">n.</span> A
+route of many roads leading from nowhere to nothing.</p>
+
+<p class="entry"><span class="def">Phoenix</span>, <span class="pos">n.</span> The classical
+prototype of the modern “small hot bird.”</p>
+
+<p class="entry"><span class="def">phonograph</span>, <span class="pos">n.</span> An
+irritating toy that restores life to dead noises.</p>
+
+<p class="entry"><span class="def">photograph</span>, <span class="pos">n.</span> A
+picture painted by the sun without instruction in art. It is a little better
+than the work of an Apache, but not quite so good as that of a Cheyenne.</p>
+
+<p class="entry"><span class="def">phrenology</span>, <span class="pos">n.</span> The
+science of picking the pocket through the scalp. It consists in locating and
+exploiting the organ that one is a dupe with.</p>
+
+<p class="entry"><span class="def">physician</span>, <span class="pos">n.</span> One
+upon whom we set our hopes when ill and our dogs when well.</p>
+
+<p class="entry"><span class="def">physiognomy</span>, <span class="pos">n.</span> The
+art of determining the character of another by the resemblances and differences
+between his face and our own, which is the standard of excellence.</p>
+
+<div class="poem">
+<p class="poetry">“There is no art,” says Shakespeare, foolish man,</p>
+<p class="poetry">“To read the mind’s construction in the face.”</p>
+<p class="poetry">The physiognomists his portrait scan,</p>
+<p class="poetry">And say: “How little wisdom here we trace! He knew his face disclosed his mind and heart, So,
+in his own defence, denied our art.”</p>
+<p class="poetry">Lavatar Shunk</p>
+</div>
+
+<p class="entry"><span class="def">piano</span>, <span class="pos">n.</span> A parlor
+utensil for subduing the impenitent visitor. It is operated by pressing the
+keys of the machine and the spirits of the audience.</p>
+
+<p class="entry"><span class="def">pickaninny</span>, <span class="pos">n.</span> The
+young of the <i>Procyanthropos</i>, or <i>Americanus dominans</i>. It is small, black and charged with political
+fatalities.</p>
+
+<p class="entry"><span class="def">picture</span>, <span class="pos">n.</span> A
+representation in two dimensions of something wearisome in three.</p>
+
+<div class="poem">
+<p class="poetry">“Behold great Daubert’s picture here on view—</p>
+<p class="poetry">Taken from Life.” If that description’s true, Grant, heavenly Powers, that I be taken, too.</p>
+<p class="citeauth">Jali Hane</p>
+</div>
+
+<p class="entry"><span class="def">pie</span>, <span class="pos">n.</span> An advance
+agent of the reaper whose name is Indigestion.</p>
+
+<div class="poem">
+<p class="poetry">Cold pie was highly esteemed by the remains.</p>
+<p class="poetry">Rev. Dr. Mucker</p>
+<p class="poetry">(in a funeral sermon over a British nobleman)</p>
+<p class="poetry">Cold pie is a detestable</p>
+<p class="poetry">American comestible.</p>
+<p class="poetry">That’s why I’m done—or undone—</p>
+<p class="poetry">So far from that dear London.</p>
+<p class="citeauth">(from the headstone of a British nobleman in Kalamazoo)</p>
+</div>
+
+<p class="entry"><span class="def">piety</span>, <span class="pos">n.</span> Reverence
+for the Supreme Being, based upon His supposed resemblance to man.</p>
+
+<div class="poem">
+<p class="poetry">The pig is taught by sermons and epistles<br />
+To think the God of Swine has snout and bristles.</p>
+<p class="citeauth">Judibras</p>
+</div>
+
+<p class="entry"><span class="def">pig</span>, <span class="pos">n.</span> An animal
+(<i>Porcus omnivorus</i>) closely allied to the human race by the splendor and
+vivacity of its appetite, which, however, is inferior in scope, for it sticks
+at pig.</p>
+
+<p class="entry"><span class="def">pigmy</span>, <span class="pos">n.</span> One of a
+tribe of very small men found by ancient travelers in many parts of the world,
+but by modern in Central Africa only. The Pigmies are so called to distinguish
+them from the bulkier Caucasians—who are Hogmies.</p>
+
+<p class="entry"><span class="def">Pilgrim</span>, <span class="pos">n.</span> A
+traveler that is taken seriously. A Pilgrim Father was one who, leaving Europe
+in 1620 because not permitted to sing psalms through his nose, followed it to
+Massachusetts, where he could personate God according to the dictates of his
+conscience.</p>
+
+<p class="entry"><span class="def">pillory</span>, <span class="pos">n.</span> A
+mechanical device for inflicting personal distinction—prototype of the
+modern newspaper conducted by persons of austere virtues and blameless lives.</p>
+
+<p class="entry"><span class="def">piracy</span>, <span class="pos">n.</span> Commerce
+without its folly-swaddles, just as God made it.</p>
+
+<p class="entry"><span class="def">pitiful</span>, <span class="pos">adj.</span> The
+state of an enemy of opponent after an imaginary encounter with oneself.</p>
+
+<p class="entry"><span class="def">pity</span>, <span class="pos">n.</span> A failing
+sense of exemption, inspired by contrast.</p>
+
+<p class="entry"><span class="def">plagiarism</span>, <span class="pos">n.</span> A
+literary coincidence compounded of a discreditable priority and an honorable subsequence.</p>
+
+<p class="entry"><span class="def">plagiarize</span>, <span class="pos">v.</span> To
+take the thought or style of another writer whom one has never, never read.</p>
+
+<p class="entry"><span class="def">plague</span>, <span class="pos">n.</span> In
+ancient times a general punishment of the innocent for admonition of their
+ruler, as in the familiar instance of Pharaoh the Immune. The plague as we of
+to-day have the happiness to know it is merely Nature’s fortuitous
+manifestation of her purposeless objectionableness.</p>
+
+<p class="entry"><span class="def">plan</span>, <span class="pos">v.t.</span> To
+bother about the best method of accomplishing an accidental result.</p>
+
+<p id="platitude" class="entry"><span class="def">platitude</span>, <span class="pos">n.</span> The
+fundamental element and special glory of popular literature. A thought that
+snores in words that smoke. The wisdom of a million fools in the diction of a
+dullard. A fossil sentiment in artificial rock. A moral without the fable. All
+that is mortal of a departed truth. A demi-tasse of milk-and-mortality. The
+Pope’s-nose of a featherless peacock. A jelly-fish withering on the shore of
+the sea of thought. The cackle surviving the egg. A desiccated epigram.</p>
+
+<p class="entry"><span class="def">platonic</span>, <span class="pos">adj.</span> Pertaining
+to the philosophy of Socrates. Platonic Love is a fool’s name for the affection
+between a disability and a frost.</p>
+
+<p class="entry"><span class="def">plaudits</span>, <span class="pos">n.</span> Coins
+with which the populace pays those who tickle and devour it.</p>
+
+<p class="entry"><span class="def">please</span>, <span class="pos">v.</span> To lay
+the foundation for a superstructure of imposition.</p>
+
+<p id="pleasure" class="entry"><span class="def">pleasure</span>, <span class="pos">n.</span> The
+least hateful form of dejection.</p>
+
+<p class="entry"><span class="def">plebeian</span>, <span class="pos">n.</span> An
+ancient Roman who in the blood of his country stained nothing but his hands. Distinguished
+from the Patrician, who was a saturated solution.</p>
+
+<p class="entry"><span class="def">plebiscite</span>, <span class="pos">n.</span> A
+popular vote to ascertain the will of the sovereign.</p>
+
+<p class="entry"><span class="def">plenipotentiary,</span> <span class="pos">adj.</span> Having full power.
+A Minister Plenipotentiary is a diplomatist possessing
+absolute authority on condition that he never exert it.</p>
+
+<p class="entry"><span class="def">pleonasm</span>, <span class="pos">n.</span> An
+army of words escorting a corporal of thought.</p>
+
+<p class="entry"><span class="def">plow</span>, <span class="pos">n.</span> An
+implement that cries aloud for hands accustomed to the pen.</p>
+
+<p class="entry"><span class="def">plunder</span>, <span class="pos">v.</span> To
+take the property of another without observing the decent and customary
+reticences of theft. To effect a change of ownership with the candid
+concomitance of a brass band. To wrest the wealth of A from B and leave C
+lamenting a vanishing opportunity.</p>
+
+<p class="entry"><span class="def">pocket</span>, <span class="pos">n.</span> The
+cradle of motive and the grave of conscience. In woman this organ is lacking;
+so she acts without motive, and her conscience, denied burial, remains ever
+alive, confessing the sins of others.</p>
+
+<p class="entry"><span class="def">poetry</span>, <span class="pos">n.</span> A form
+of expression peculiar to the Land beyond the Magazines.</p>
+
+<p class="entry"><span class="def">poker</span>, <span class="pos">n.</span> A game
+said to be played with cards for some purpose to this lexicographer unknown.</p>
+
+<p class="entry"><span class="def">police</span>, <span class="pos">n.</span> An
+armed force for protection and participation.</p>
+
+<p class="entry"><span class="def">politeness</span>, <span class="pos">n.</span> The
+most acceptable hypocrisy.</p>
+
+<p id="politics" class="entry"><span class="def">politics</span>, <span class="pos">n.</span> A
+strife of interests masquerading as a contest of principles. The conduct of
+public affairs for private advantage.</p>
+
+<p class="entry"><span class="def">politician</span>, <span class="pos">n.</span> An
+eel in the fundamental mud upon which the superstructure of organized society
+is reared. When we wriggles he mistakes the agitation of his tail for the
+trembling of the edifice. As compared with the statesman, he suffers the
+disadvantage of being alive.</p>
+
+<p class="entry"><span class="def">polygamy</span>, <span class="pos">n.</span> A
+house of atonement, or expiatory chapel, fitted with several stools of
+repentance, as distinguished from monogamy, which has but one.</p>
+
+<p class="entry"><span class="def">populist</span>, <span class="pos">n.</span> A
+fossil patriot of the early agricultural period, found in the old red soapstone
+underlying Kansas; characterized by an uncommon spread of ear, which some
+naturalists contend gave him the power of flight, though Professors Morse and
+Whitney, pursuing independent lines of thought, have ingeniously pointed out
+that had he possessed it he would have gone elsewhere. In the picturesque
+speech of his period, some fragments of which have come down to us, he was
+known as “The Matter with Kansas.”</p>
+
+<p class="entry"><span class="def">portable</span>, <span class="pos">adj.</span> Exposed
+to a mutable ownership through vicissitudes of possession.</p>
+
+<div class="poem">
+<p class="poetry">His light estate, if neither he did make it<br />
+Nor yet its former guardian forsake it,<br />
+Is portable improperly, I take it.</p>
+<p class="citeauth">Worgum Slupsky</p>
+</div>
+
+<p class="entry"><span class="def">Portuguese</span>, <span class="pos">n.</span>pl. A
+species of geese indigenous to Portugal. They are mostly without feathers and
+imperfectly edible, even when stuffed with garlic.</p>
+
+<p class="entry"><span class="def">positive</span>, <span class="pos">adj.</span> Mistaken
+at the top of one’s voice.</p>
+
+<p class="entry"><span class="def">positivism</span>, <span class="pos">n.</span> A
+philosophy that denies our knowledge of the Real and affirms our ignorance of
+the Apparent. Its longest exponent is Comte, its broadest Mill and its thickest
+Spencer.</p>
+
+<p class="entry"><span class="def">posterity</span>, <span class="pos">n.</span> An
+appellate court which reverses the judgment of a popular author’s
+contemporaries, the appellant being his obscure competitor.</p>
+
+<p class="entry"><span class="def">potable</span>, <span class="pos">n.</span> Suitable
+for drinking. Water is said to be potable; indeed, some declare it our natural
+beverage, although even they find it palatable only when suffering from the
+recurrent disorder known as thirst, for which it is a medicine. Upon nothing
+has so great and diligent ingenuity been brought to bear in all ages and in all
+countries, except the most uncivilized, as upon the invention of substitutes
+for water. To hold that this general aversion to that liquid has no basis in
+the preservative instinct of the race is to be unscientific—and without science
+we are as the snakes and toads.</p>
+
+<p class="entry"><span class="def">poverty</span>, <span class="pos">n.</span> A file
+provided for the teeth of the rats of reform. The number of plans for its
+abolition equals that of the reformers who suffer from it, plus that of the
+philosophers who know nothing about it. Its victims are distinguished by
+possession of all the virtues and by their faith in leaders seeking to conduct
+them into a prosperity where they believe these to be unknown.</p>
+
+<p class="entry"><span class="def">pray</span>, <span class="pos">v.</span> To ask
+that the laws of the universe be annulled in behalf of a single petitioner
+confessedly unworthy.</p>
+
+<p class="entry"><span class="def">Pre-Adamite</span>, <span class="pos">n.</span> One
+of an experimental and apparently unsatisfactory race of antedated Creation and
+lived under conditions not easily conceived. Melsius believed them to have
+inhabited “the Void” and to have been something intermediate between fishes and
+birds. Little its known of them beyond the fact that they supplied Cain with a
+wife and theologians with a controversy.</p>
+
+<p class="entry"><span class="def">precedent</span>, <span class="pos">n.</span> In
+Law, a previous decision, rule or practice which, in the absence of a definite
+statute, has whatever force and authority a Judge may choose to give it,
+thereby greatly simplifying his task of doing as he pleases. As there are
+precedents for everything, he has only to ignore those that make against his
+interest and accentuate those in the line of his desire. Invention of the
+precedent elevates the trial-at-law from the low estate of a fortuitous ordeal
+to the noble attitude of a dirigible arbitrament.</p>
+
+<p class="entry"><span class="def">precipitate</span>, <span class="pos">adj.</span> Anteprandial.</p>
+
+<div class="poem">
+<p class="poetry">Precipitate in all, this sinner</p>
+<p class="poetry">Took action first, and then his dinner.</p>
+<p class="citeauth">Judibras</p>
+</div>
+
+<p class="entry"><span class="def">predestination</span>, <span class="pos">n.</span>
+The doctrine that all things occur according to programme. This doctrine should
+not be confused with that of foreordination, which means that all things are
+programmed, but does not affirm their occurrence, that being only an
+implication from other doctrines by which this is entailed. The difference is
+great enough to have deluged Christendom with ink, to say nothing of the gore. With
+the distinction of the two doctrines kept well in mind, and a reverent belief
+in both, one may hope to escape perdition if spared.</p>
+
+<p class="entry"><span class="def">predicament</span>, <span class="pos">n.</span> The
+wage of consistency.</p>
+
+<p class="entry"><span class="def">predilection</span>, <span class="pos">n.</span> The
+preparatory stage of disillusion.</p>
+
+<p class="entry"><span class="def">pre-existence</span>, <span class="pos">n.</span> An
+unnoted factor in creation.</p>
+
+<p class="entry"><span class="def">preference</span>, <span class="pos">n.</span> A
+sentiment, or frame of mind, induced by the erroneous belief that one thing is
+better than another.</p>
+
+<p>An ancient philosopher, expounding his conviction that life is no better than death, was
+asked by a disciple why, then, he did not die. “Because,” he replied, “death is
+no better than life.” It is longer.</p>
+
+<p class="entry"><span class="def">prehistoric</span>, <span class="pos">adj.</span> Belonging
+to an early period and a museum. </p>
+
+<div class="poem">
+<p class="poetry">Antedating the art and practice of perpetuating falsehood.</p>
+<p class="poetry">He lived in a period prehistoric,</p>
+<p class="poetry">When all was absurd and phantasmagoric.</p>
+<p class="poetry">Born later, when Clio, celestial recorded,</p>
+<p class="poetry">Set down great events in succession and order,</p>
+<p class="poetry">He surely had seen nothing droll or fortuitous</p>
+<p class="poetry">In anything here but the lies that she threw at us.</p>
+<p class="citeauth">Orpheus Bowen</p>
+</div>
+
+<p class="entry"><span class="def">prejudice</span>, <span class="pos">n.</span> A
+vagrant opinion without visible means of support.</p>
+
+<p class="entry"><span class="def">prelate</span>, <span class="pos">n.</span> A
+church officer having a superior degree of holiness and a fat preferment. One
+of Heaven’s aristocracy. A gentleman of God.</p>
+
+<p class="entry"><span class="def">prerogative</span>, <span class="pos">n.</span> A
+sovereign’s right to do wrong.</p>
+
+<p class="entry"><span class="def">Presbyterian</span>, <span class="pos">n.</span> One
+who holds the conviction that the government authorities of the Church should
+be called presbyters.</p>
+
+<p class="entry"><span class="def">prescription</span>, <span class="pos">n.</span> A
+physician’s guess at what will best prolong the situation with least harm to the patient.</p>
+
+<p class="entry"><span class="def">present</span>, <span class="pos">n.</span> That
+part of eternity dividing the domain of disappointment from the realm of hope.</p>
+
+<p class="entry"><span class="def">presentable</span>, <span class="pos">adj.</span> Hideously
+appareled after the manner of the time and place.</p>
+
+<p>In Boorioboola-Gha a man is presentable on occasions of ceremony if he have his abdomen painted a
+bright blue and wear a cow’s tail; in New York he may, if it please him, omit
+the paint, but after sunset he must wear two tails made of the wool of a sheep
+and dyed black.</p>
+
+<p class="entry"><span class="def">preside</span>, <span class="pos">v.</span> To
+guide the action of a deliberative body to a desirable result. In Journalese,
+to perform upon a musical instrument; as, “He presided at the piccolo.”</p>
+
+<div class="poem">
+<p class="poetry">The Headliner, holding the copy in hand,</p>
+<p class="poetry">Read with a solemn face:</p>
+<p class="poetry">“The music was very uncommonly grand—</p>
+<p class="poetry">The best that was every provided,</p>
+<p class="poetry">For our townsman Brown presided</p>
+<p class="poetry">At the organ with skill and grace.”</p>
+<p class="poetry">The Headliner discontinued to read,</p>
+<p class="poetry">And, spread the paper down</p>
+<p class="poetry">On the desk, he dashed in at the top of the screed:</p>
+<p class="poetry">“Great playing by President Brown.”</p>
+<p class="citeauth">Orpheus Bowen</p>
+</div>
+
+<p class="entry"><span class="def">presidency</span>, <span class="pos">n.</span> The
+greased pig in the field game of American politics.</p>
+
+<p id="president" class="entry"><span class="def">president</span>, <span class="pos">n.</span> The
+leading figure in a small group of men of whom—and of whom only—it is
+positively known that immense numbers of their countrymen did not want any of
+them for President.</p>
+
+<div class="poem">
+<p class="poetry">If that’s an honor surely ‘tis a greater<br />
+To have been a simple and undamned spectator.</p>
+<p class="poetry">Behold in me a man of mark and note</p>
+<p class="poetry">Whom no elector e’er denied a vote!—</p>
+<p class="poetry">An undiscredited, unhooted gent</p>
+<p class="poetry">Who might, for all we know, be President</p>
+<p class="poetry">By acclimation. Cheer, ye varlets, cheer—</p>
+<p class="poetry">I’m passing with a wide and open ear!</p>
+<p class="citeauth">Jonathan Fomry</p>
+</div>
+
+<p class="entry"><span class="def">prevaricator</span>, <span class="pos">n.</span> A
+liar in the caterpillar estate.</p>
+
+<p class="entry"><span class="def">price</span>, <span class="pos">n.</span> Value,
+plus a reasonable sum for the wear and tear of conscience in demanding it.</p>
+
+<p class="entry"><span class="def">primate</span>, <span class="pos">n.</span> The
+head of a church, especially a State church supported by involuntary
+contributions. The Primate of England is the Archbishop of Canterbury, an
+amiable old gentleman, who occupies Lambeth Palace when living and Westminster
+Abbey when dead. He is commonly dead.</p>
+
+<p class="entry"><span class="def">prisonu</span>, <span class="pos">n.</span> A place
+of punishments and rewards. The poet assures us that—</p>
+
+<div class="poem">
+<p class="poetry">“Stone walls do not a prison make,”</p>
+<p class="poetry">but a combination of the stone wall, the political parasite and the moral instructor is no garden
+of sweets.</p>
+</div>
+
+<p class="entry"><span class="def">private</span>, <span class="pos">n.</span> A
+military gentleman with a field-marshal’s baton in his knapsack and an
+impediment in his hope.</p>
+
+<p class="entry"><span class="def">proboscis</span>, <span class="pos">n.</span> The
+rudimentary organ of an elephant which serves him in place of the
+knife-and-fork that Evolution has as yet denied him. For purposes of humor it
+is popularly called a trunk.</p>
+
+<p>Asked how he knew that an elephant was going on a journey, the illustrious Jo. Miller cast a
+reproachful look upon his tormentor, and answered, absently: “When it is ajar,”
+and threw himself from a high promontory into the sea. Thus perished in his
+pride the most famous humorist of antiquity, leaving to mankind a heritage of
+woe! No successor worthy of the title has appeared, though Mr. Edward bok, of <i>The Ladies’ Home Journal</i>, is much
+respected for the purity and sweetness of his personal character.</p>
+
+<p class="entry"><span class="def">projectile</span>, <span class="pos">n.</span> The
+final arbiter in international disputes. Formerly these disputes were settled
+by physical contact of the disputants, with such simple arguments as the
+rudimentary logic of the times could supply—the sword, the spear, and so forth.
+With the growth of prudence in military affairs the projectile came more and
+more into favor, and is now held in high esteem by the most courageous. Its
+capital defect is that it requires personal attendance at the point of
+propulsion.</p>
+
+<p class="entry"><span class="def">proof</span>, <span class="pos">n.</span> Evidence
+having a shade more of plausibility than of unlikelihood. The testimony of two
+credible witnesses as opposed to that of only one.</p>
+
+<p class="entry"><span class="def">proof-reader</span>, <span class="pos">n.</span> A
+malefactor who atones for making your writing nonsense by permitting the
+compositor to make it unintelligible.</p>
+
+<p class="entry"><span class="def">property</span>, <span class="pos">n.</span> Any
+material thing, having no particular value, that may be held by A against the
+cupidity of B. Whatever gratifies the passion for possession in one and
+disappoints it in all others. The object of man’s brief rapacity and long indifference.</p>
+
+<p class="entry"><span class="def">prophecy</span>, <span class="pos">n.</span> The
+art and practice of selling one’s credibility for future delivery.</p>
+
+<p class="entry"><span class="def">prospect</span>, <span class="pos">n.</span> An
+outlook, usually forbidding. An expectation, usually forbidden.</p>
+
+<div class="poem">
+<p class="poetry">Blow, blow, ye spicy breezes—</p>
+<p class="poetry">O’er Ceylon blow your breath,</p>
+<p class="poetry">Where every prospect pleases,</p>
+<p class="poetry">Save only that of death.</p>
+<p class="citeauth">Bishop Sheber</p>
+</div>
+
+<p class="entry"><span class="def">providential</span>, <span class="pos">adj.</span>
+Unexpectedly and conspicuously beneficial to the person so describing it.</p>
+
+<p class="entry"><span class="def">prude</span>, <span class="pos">n.</span> A bawd
+hiding behind the back of her demeanor.</p>
+
+<p class="entry"><span class="def">publish</span>, <span class="pos">n.</span> In
+literary affairs, to become the fundamental element in a cone of critics.</p>
+
+<p class="entry"><span class="def">push</span>, <span class="pos">n.</span> One of
+the two things mainly conducive to success, especially in politics. The other is Pull.</p>
+
+<p class="entry"><span class="def">pyrrhonism</span>, <span class="pos">n.</span> An
+ancient philosophy, named for its inventor. It consisted of an absolute
+disbelief in everything but Pyrrhonism. Its modern professors have added that.</p>
+
+</body>
+</html>
\ No newline at end of file
--- /dev/null
+++ b/lib/ebooks/devils/P.html.i
@@ -1,0 +1,47 @@
+20 pages
+size 400 552
+length 34265
+396 2 10 body html
+0
+1944 2 42 body html
+22
+3960 2 77 body html
+90
+5856 2 109 body html
+127
+7228 2 139 body html
+0
+8256 2 156 body html
+265
+10628 2 202 body html
+22
+12036 2 229 body html
+89
+13249 2 258 body html
+22
+15524 2 299 body html
+22
+17760 2 340 body html
+22
+19719 2 377 body html
+90
+21495 2 412 body html
+124
+23959 2 451 body html
+36
+25650 2 486 body html
+72
+27357 2 520 body html
+0
+27879 2 529 body html
+379
+29793 2 569 body html
+22
+31481 2 600 body html
+39
+33103 2 628 body html
+176
+president 16
+platitude 9
+politics 10
+pleasure 9
--- /dev/null
+++ b/lib/ebooks/devils/Q.html
@@ -1,0 +1,71 @@
+<?xml version="1.0"?>
+<!DOCTYPE package PUBLIC "+//ISBN 0-9673008-1-9//DTD OEB 1.0 Package//EN"
+ "http://openebook.org/dtds/oeb-1.0/oebdoc1.dtd">
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/x-oeb1-document; charset=utf-8" />
+<link rel="stylesheet" type="text/x-oeb1-css" href="devil.css" />
+<title>The Devil’s Dictionary: Q</title>
+</head>
+<body lang="en-US">
+
+
+<h1>Q</h1>
+
+<p class="entry"><span class="def">queen</span>, <span class="pos">n.</span> A woman
+by whom the realm is ruled when there is a king, and through whom it is ruled
+when there is not.</p>
+
+<p class="entry"><span class="def">quill</span>, <span class="pos">n.</span> An
+implement of torture yielded by a goose and commonly wielded by an ass. This
+use of the quill is now obsolete, but its modern equivalent, the steel pen, is
+wielded by the same everlasting Presence.</p>
+
+<p class="entry"><span class="def">quiver</span>, <span class="pos">n.</span> A
+portable sheath in which the ancient statesman and the aboriginal lawyer
+carried their lighter arguments.</p>
+
+<div class="poem">
+<p class="poetry">He extracted from his quiver,</p>
+<p class="poetry">Did the controversial Roman,</p>
+<p class="poetry">An argument well fitted</p>
+<p class="poetry">To the question as submitted,</p>
+<p class="poetry">Then addressed it to the liver,</p>
+<p class="poetry">Of the unpersuaded foeman.</p>
+<p class="citeauth">Oglum P. Boomp</p>
+</div>
+
+<p class="entry"><span class="def">quixotic</span>, <span class="pos">adj.</span> Absurdly
+chivalric, like Don Quixote. An insight into the beauty and excellence of this
+incomparable adjective is unhappily denied to him who has the misfortune to
+know that the gentleman’s name is pronounced Ke-ho-tay.</p>
+
+<div class="poem">
+<p class="poetry">When ignorance from out of our lives can banish Philology, ‘tis folly to know Spanish.</p>
+<p class="citeauth">Juan Smith</p>
+</div>
+
+<p class="entry"><span class="def">quorum</span>, <span class="pos">n.</span> A
+sufficient number of members of a deliberative body to have their own way and
+their own way of having it. In the United States Senate a quorum consists of
+the chairman of the Committee on Finance and a messenger from the White House;
+in the House of Representatives, of the Speaker and the devil.</p>
+
+<p class="entry"><span class="def">quotation</span>, <span class="pos">n.</span> The
+act of repeating erroneously the words of another. </p>
+
+<div class="poem">
+<p class="poetry">The words erroneously repeated.</p>
+<p class="poetry">Intent on making his quotation truer,</p>
+<p class="poetry">He sought the page infallible of Brewer,</p>
+<p class="poetry">Then made a solemn vow that we would be</p>
+<p class="poetry">Condemned eternally. Ah, me, ah, me!</p>
+<p class="citeauth">Stumpo Gaker</p>
+</div>
+
+<p class="entry"><span class="def">quotient</span>, <span class="pos">n.</span> A
+number showing how many times a sum of money belonging to one person is
+contained in the pocket of another—usually about as many times as it can be got there.</p>
+
+</body>
+</html>
\ No newline at end of file
--- /dev/null
+++ b/lib/ebooks/devils/Q.html.i
@@ -1,0 +1,7 @@
+2 pages
+size 400 552
+length 3077
+396 2 10 body html
+0
+1442 2 38 body html
+39
--- /dev/null
+++ b/lib/ebooks/devils/R.html
@@ -1,0 +1,728 @@
+<?xml version="1.0"?>
+<!DOCTYPE package PUBLIC "+//ISBN 0-9673008-1-9//DTD OEB 1.0 Package//EN"
+ "http://openebook.org/dtds/oeb-1.0/oebdoc1.dtd">
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/x-oeb1-document; charset=utf-8" />
+<link rel="stylesheet" type="text/x-oeb1-css" href="devil.css" />
+<title>The Devil’s Dictionary: R</title>
+</head>
+<body lang="en-US">
+
+
+
+<h1>R</h1>
+
+<p class="entry"><span class="def">rabble</span>, <span class="pos">n.</span> In a
+republic, those who exercise a supreme authority tempered by fraudulent
+elections. The rabble is like the sacred Simurgh, of Arabian fable—omnipotent
+on condition that it do nothing. (The word is Aristocratese, and has no exact
+equivalent in our tongue, but means, as nearly as may be, “soaring swine.”)</p>
+
+<p class="entry"><span class="def">rack</span>, <span class="pos">n.</span> An
+argumentative implement formerly much used in persuading devotees of a false
+faith to embrace the living truth. As a call to the unconverted the rack never
+had any particular efficacy, and is now held in light popular esteem.</p>
+
+<p class="entry"><span class="def">rank</span>, <span class="pos">n.</span> Relative
+elevation in the scale of human worth.</p>
+
+<div class="poem">
+<p class="poetry">He held at court a rank so high</p>
+<p class="poetry">That other noblemen asked why.</p>
+<p class="poetry">“Because,” ‘twas answered, “others lack</p>
+<p class="poetry">His skill to scratch the royal back.”</p>
+<p class="citeauth">Aramis Jukes</p>
+</div>
+
+<p class="entry"><span class="def">ransom</span>, <span class="pos">n.</span> The
+purchase of that which neither belongs to the seller, nor can belong to the
+buyer. The most unprofitable of investments.</p>
+
+<p class="entry"><span class="def">rapacity</span>, <span class="pos">n.</span> Providence
+without industry. The thrift of power.</p>
+
+<p class="entry"><span class="def">rarebit</span>, <span class="pos">n.</span> A
+Welsh rabbit, in the speech of the humorless, who point out that it is not a
+rabbit. To whom it may be solemnly explained that the comestible known as
+toad-in-a-hole is really not a toad, and that <i>riz-de-veau
+a la financiere</i> is not the smile of a calf prepared after the recipe
+of a she banker.</p>
+
+<p class="entry"><span class="def">rascal</span>, <span class="pos">n.</span> A fool
+considered under another aspect.</p>
+
+<p class="entry"><span class="def">rascality</span>, <span class="pos">n.</span> Stupidity
+militant. The activity of a clouded intellect.</p>
+
+<p class="entry"><span class="def">rash</span>, <span class="pos">adj.</span> Insensible
+to the value of our advice.</p>
+
+<div class="poem">
+<p class="poetry">“Now lay your bet with mine, nor let</p>
+<p class="poetry">These gamblers take your cash.”</p>
+<p class="poetry">“Nay, this child makes no bet.” “Great snakes!</p>
+<p class="poetry">How can you be so rash?”</p>
+<p class="citeauth">Bootle P. Gish</p>
+</div>
+
+<p class="entry"><span class="def">rational</span>, <span class="pos">adj.</span> Devoid
+of all delusions save those of observation, experience and reflection.</p>
+
+<p class="entry"><span class="def">rattlesnake</span>, <span class="pos">n.</span> Our
+prostrate brother, <i>Homo ventrambulans</i>.</p>
+
+<p class="entry"><span class="def">razor</span>, <span class="pos">n.</span> An
+instrument used by the Caucasian to enhance his beauty, by the Mongolian to make
+a guy of himself, and by the Afro-American to affirm his worth.</p>
+
+<p class="entry"><span class="def">reach</span>, <span class="pos">n.</span> The
+radius of action of the human hand. The area within which it is possible (and
+customary) to gratify directly the propensity to provide.</p>
+
+<div class="poem">
+<p class="poetry">This is a truth, as old as the hills,</p>
+<p class="poetry">That life and experience teach:</p>
+<p class="poetry">The poor man suffers that keenest of ills,</p>
+<p class="poetry">An impediment of his reach.</p>
+<p class="citeauth">G. J.</p>
+</div>
+
+<p class="entry"><span class="def">reading</span>, <span class="pos">n.</span> The
+general body of what one reads. In our country it consists, as a rule, of
+Indiana novels, short stories in “dialect” and humor in slang.</p>
+
+<div class="poem">
+<p class="poetry">We know by one’s reading</p>
+<p class="poetry">His learning and breeding;</p>
+<p class="poetry">By what draws his laughter</p>
+<p class="poetry">We know his Hereafter.</p>
+<p class="poetry">Read nothing, laugh never—</p>
+<p class="poetry">The Sphinx was less clever!</p>
+<p class="citeauth">Jupiter Muke</p>
+</div>
+
+<p class="entry"><span class="def">radicalsim</span>, <span class="pos">n.</span> The
+conservatism of to-morrow injected into the affairs of to-day.</p>
+
+<p class="entry"><span class="def">radium</span>, <span class="pos">n.</span> A
+mineral that gives off heat and stimulates the organ that a scientist is a fool
+with.</p>
+
+<p class="entry"><span class="def">railroad</span>, <span class="pos">n.</span> The
+chief of many mechanical devices enabling us to get away from where we are to
+wher we are no better off. For this purpose the railroad is held in highest
+favor by the optimist, for it permits him to make the transit with great expedition.</p>
+
+<p class="entry"><span class="def">ramshackle</span>, <span class="pos">adj.</span> Pertaining
+to a certain order of architecture, otherwise known as the Normal American. Most
+of the public buildings of the United States are of the Ramshackle order,
+though some of our earlier architects preferred the Ironic. Recent additions to
+the White House in Washington are Theo-Doric, the ecclesiastic order of the
+Dorians. They are exceedingly fine and cost one hundred dollars a brick.</p>
+
+<p class="entry"><span class="def">realism</span>, <span class="pos">n.</span> The
+art of depicting nature as it is seem by toads. The charm suffusing a landscape
+painted by a mole, or a story written by a measuring-worm.</p>
+
+<p class="entry"><span class="def">reality</span>, <span class="pos">n.</span> The
+dream of a mad philosopher. That which would remain in the cupel if one should
+assay a phantom. The nucleus of a vacuum.</p>
+
+<p class="entry"><span class="def">really</span>, <span class="pos">adv.</span> Apparently.</p>
+
+<p class="entry"><span class="def">rear</span>, <span class="pos">n.</span> In
+American military matters, that exposed part of the army that is nearest to Congress.</p>
+
+<p class="entry"><span class="def">reason</span>, <span class="pos">v.i.</span> To
+weight probabilities in the scales of desire.</p>
+
+<p class="entry"><span class="def">reason</span>, <span class="pos">n.</span> Propensitate of prejudice.</p>
+
+<p class="entry"><span class="def">reasonable</span>, <span class="pos">adj.</span> Accessible
+to the infection of our own opinions. </p>
+
+<p>Hospitable to persuasion, dissuasion and evasion.</p>
+
+<p class="entry"><span class="def">rebel</span>, <span class="pos">n.</span> A
+proponent of a new misrule who has failed to establish it.</p>
+
+<p class="entry"><span class="def">recollect</span>, <span class="pos">v.</span> To
+recall with additions something not previously known.</p>
+
+<p class="entry"><span class="def">reconciliation</span>, <span class="pos">n.</span>
+A suspension of hostilities. An armed truce for the purpose of digging up the dead.</p>
+
+<p class="entry"><span class="def">reconsider</span>, <span class="pos">v.</span> To
+seek a justification for a decision already made.</p>
+
+<p class="entry"><span class="def">recount</span>, <span class="pos">n.</span> In
+American politics, another throw of the dice, accorded to the player against
+whom they are loaded.</p>
+
+<p class="entry"><span class="def">recreation</span>, <span class="pos">n.</span> A
+particular kind of dejection to relieve a general fatigue.</p>
+
+<p class="entry"><span class="def">recruit</span>, <span class="pos">n.</span> A
+person distinguishable from a civilian by his uniform and from a soldier by his gait.</p>
+
+<div class="poem">
+<p class="poetry">Fresh from the farm or factory or street,</p>
+
+<p class="poetry">His marching, in pursuit or in retreat,</p>
+<p class="poetry">Were an impressive martial spectacle</p>
+<p class="poetry">Except for two impediments—his feet.</p>
+
+<p class="citeauth">Thompson Johnson</p>
+</div>
+
+<p class="entry"><span class="def">rector</span>, <span class="pos">n.</span> In the
+Church of England, the Third Person of the parochial Trinity, the Cruate and
+the Vicar being the other two.</p>
+
+<p class="entry"><span class="def">redemption</span>, <span class="pos">n.</span> Deliverance
+of sinners from the penalty of their sin, through their murder of the deity
+against whom they sinned. The doctrine of Redemption is the fundamental mystery
+of our holy religion, and whoso believeth in it shall not perish, but have
+everlasting life in which to try to understand it.</p>
+
+<div class="poem">
+<p class="poetry">We must awake Man’s spirit from his sin,</p>
+<p class="poetry">And take some special measure for redeeming it;</p>
+<p class="poetry">Though hard indeed the task to get it in</p>
+<p class="poetry">Among the angels any way but teaming it,</p>
+<p class="poetry">Or purify it otherwise than steaming it.</p>
+<p class="poetry">I’m awkward at Redemption—a beginner:</p>
+<p class="poetry">My method is to crucify the sinner.</p>
+<p class="citeauth">Golgo Brone</p>
+</div>
+
+<p class="entry"><span class="def">redress</span>, <span class="pos">n.</span> Reparation
+without satisfaction.</p>
+
+<p>Among the Anglo-Saxon a subject conceiving himself wronged by the king was permitted, on
+proving his injury, to beat a brazen image of the royal offender with a switch
+that was afterward applied to his own naked back. The latter rite was performed
+by the public hangman, and it assured moderation in the plaintiff’s choice of a switch.</p>
+
+<p class="entry"><span class="def">red-skin</span>, <span class="pos">n.</span> A
+North American Indian, whose skin is not red—at least not on the outside.</p>
+
+<p class="entry"><span class="def">redundant</span>, <span class="pos">adj.</span> Superfluous;
+needless; <i>de trop</i>.</p>
+
+<div class="poem">The Sultan said: “There’s evidence abundant<br />
+To prove this unbelieving dog redundant.”<br />
+To whom the Grand Vizier, with mien impressive,<br />
+Replied: “His head, at least, appears excessive.”<br />
+<p class="citeauth">Habeeb Suleiman</p>
+</div>
+
+<p class="quote">Mr. Debs is a redundant citizen. Theodore Roosevelt</p>
+
+<p class="entry"><span class="def">referendum</span>, <span class="pos">n.</span> A
+law for submission of proposed legislation to a popular vote to learn the
+nonsensus of public opinion.</p>
+
+<p class="entry"><span class="def">reflection</span>, <span class="pos">n.</span> An
+action of the mind whereby we obtain a clearer view of our relation to the
+things of yesterday and are able to avoid the perils that we shall not again encounter.</p>
+
+<p class="entry"><span class="def">reform</span>, <span class="pos">v.</span> A thing
+that mostly satisfies reformers opposed to reformation.</p>
+
+<p class="entry"><span class="def">refuge</span>, <span class="pos">n.</span> Anything
+assuring protection to one in peril. Moses and Joshua provided six cities of
+refuge—Bezer, Golan, Ramoth, Kadesh, Schekem and Hebron—to which one who had
+taken life inadvertently could flee when hunted by relatives of the deceased. This
+admirable expedient supplied him with wholesome exercise and enabled them to
+enjoy the pleasures of the chase; whereby the soul of the dead man was
+appropriately honored by observations akin to the funeral games of early
+Greece.</p>
+
+<p class="entry"><span class="def">refusal</span>, <span class="pos">n.</span> Denial
+of something desired; as an elderly maiden’s hand in marriage, to a rich and
+handsome suitor; a valuable franchise to a rich corporation, by an alderman;
+absolution to an impenitent king, by a priest, and so forth. Refusals are
+graded in a descending scale of finality thus: the refusal absolute, the
+refusal condition, the refusal tentative and the refusal feminine. The last is
+called by some casuists the refusal assentive.</p>
+
+<p class="entry"><span class="def">regalia</span>, <span class="pos">n.</span> Distinguishing
+insignia, jewels and costume of such ancient and honorable orders as Knights of
+Adam; Visionaries of Detectable Bosh; the Ancient Order of Modern Troglodytes;
+the League of Holy Humbug; the Golden Phalanx of Phalangers; the Genteel
+Society of Expurgated Hoodlums; the Mystic Alliances of Georgeous Regalians; Knights and Ladies
+of the Yellow Dog; the Oriental Order of Sons of the West; the Blatherhood of
+Insufferable Stuff; Warriors of the Long Bow; Guardians of the Great Horn
+Spoon; the Band of Brutes; the Impenitent Order of Wife-Beaters; the Sublime Legion
+of Flamboyant Conspicuants; Worshipers at the Electroplated Shrine; Shining
+Inaccessibles; Fee-Faw-Fummers of the inimitable Grip; Jannissaries of the
+Broad-Blown Peacock; Plumed Increscencies of the Magic Temple; the Grand Cabal
+of Able-Bodied Sedentarians; Associated Deities of the Butter Trade; the Garden
+of Galoots; the Affectionate Fraternity of Men Similarly Warted; the Flashing
+Astonishers; Ladies of Horror; Cooperative Association for Breaking into the Spotlight; Dukes of Eden;
+Disciples Militant of the Hidden Faith; Knights-Champions of the Domestic Dog; the Holy
+Gregarians; the Resolute Optimists; the Ancient Sodality of Inhospitable Hogs;
+Associated Sovereigns of Mendacity; Dukes-Guardian of the Mystic Cess-Pool; the Society for
+Prevention of Prevalence; Kings of Drink;
+Polite Federation of Gents-Consequential; the Mysterious Order of the
+Undecipherable Scroll; Uniformed Rank of Lousy Cats; Monarchs of Worth and
+Hunger; Sons of the South Star; Prelates of the Tub-and-Sword.</p>
+
+<p id="religion" class="entry"><span class="def">religion</span>, <span class="pos">n.</span> A
+daughter of Hope and Fear, explaining to Ignorance the nature of the Unknowable.</p>
+
+<span class="dialoge">
+<p>“What is your religion my son?” inquired the Archbishop of Rheims.</p>
+<p>“Pardon, monseigneur,” replied Rochebriant; “I am ashamed of it.”</p>
+<p>“Then why do you not become an atheist?”</p>
+<p>“Impossible! I should be ashamed of atheism.”</p>
+<p>“In that case, monseiegneur, you should join the Protestants.”</p>
+</span>
+
+<p class="entry"><span class="def">reliquary</span>, <span class="pos">n.</span> A
+receptacle for such sacred objects as pieces of the true cross, short-ribs of
+the saints, the ears of Balaam’s ass, the lung of the cock that called Peter to
+repentance and so forth. Reliquaries are commonly of metal, and provided with a
+lock to prevent the contents from coming out and performing miracles at
+unseasonable times. A feather from the wing of the Angel of the Annunciation
+once escaped during a sermon in Saint Peter’s and so tickled the noses of the
+congregation that they woke and sneezed with great vehemence three times each. It
+is related in the “Gesta Sanctorum” that a sacristan in the Canterbury
+cathedral surprised the head of Saint Dennis in the library. Reprimanded by its
+stern custodian, it explained that it was seeking a body of doctrine. This
+unseemly levity so raged the diocesan that the offender was publicly
+anathematized, thrown into the Stour and replaced by another head of Saint
+Dennis, brought from Rome.</p>
+
+<p class="entry"><span class="def">renown</span>, <span class="pos">n.</span> A
+degree of distinction between notoriety and fame—a little more supportable than
+the one and a little more intolerable than the other. Sometimes it is conferred
+by an unfriendly and inconsiderate hand.</p>
+
+<div class="poem">
+<p class="poetry">I touched the harp in every key,</p>
+<p class="poetry">But found no heeding ear;</p>
+<p class="poetry">And then Ithuriel touched me</p>
+<p class="poetry">With a revealing spear.</p>
+<p class="poetry">Not all my genius, great as ‘tis,</p>
+<p class="poetry">Could urge me out of night.</p>
+<p class="poetry">I felt the faint appulse of his,</p>
+<p class="poetry">And leapt into the light!</p>
+<p class="citeauth">W. J. Candleton</p>
+</div>
+
+<p class="entry"><span class="def">reparation</span>, <span class="pos">n.</span> Satisfaction
+that is made for a wrong and deducted from the satisfaction felt in committing it.</p>
+
+<p class="entry"><span class="def">repartee</span>, <span class="pos">n.</span> Prudent
+insult in retort. Practiced by gentlemen with a constitutional aversion to
+violence, but a strong disposition to offend. In a war of words, the tactics of
+the North American Indian.</p>
+
+<p class="entry"><span class="def">repentance</span>, <span class="pos">n.</span> The
+faithful attendant and follower of Punishment. It is usually manifest in a
+degree of reformation that is not inconsistent with continuity of sin.</p>
+
+<div class="poem">
+<p class="poetry">Desirous to avoid the pains of Hell,</p>
+<p class="poetry">You will repent and join the Church, Parnell?</p>
+<p class="poetry">How needless!—Nick will keep you off the coals
+And add you to the woes of other souls.</p>
+<p class="citeauth">Jomater Abemy</p>
+</div>
+
+<p class="entry"><span class="def">replica</span>, <span class="pos">n.</span> A
+reproduction of a work of art, by the artist that made the original. It is so
+called to distinguish it from a “copy,” which is made by another artist. When
+the two are mae with equal skill the replica is the more valuable, for it is
+supposed to be more beautiful than it looks.</p>
+
+<p class="entry"><span class="def">reporter</span>, <span class="pos">n.</span> A
+writer who guesses his way to the truth and dispels it with a tempest of words.</p>
+
+<div class="poem">
+<p class="poetry">“More dear than all my bosom knows, O thou Whose ‘lips are sealed’ and will not disavow!” So
+sang the blithe reporter-man as grew Beneath his hand the leg-long “interview.”</p>
+<p class="citeauth">Barson Maith</p>
+</div>
+
+<p class="entry"><span class="def">repose</span>, <span class="pos">v.i.</span> To
+cease from troubling.</p>
+
+<p class="entry"><span class="def">representative</span>, <span class="pos">n.</span>
+In national politics, a member of the Lower House in this world, and without
+discernible hope of promotion in the next.</p>
+
+<p class="entry"><span class="def">reprobation</span>, <span class="pos">n.</span> In
+theology, the state of a luckless mortal prenatally damned. The doctrine of
+reprobation was taught by Calvin, whose joy in it was somewhat marred by the
+sad sincerity of his conviction that although some are foredoomed to perdition,
+others are predestined to salvation.</p>
+
+<p class="entry"><span class="def">republic</span>, <span class="pos">n.</span> A
+nation in which, the thing governing and the thing governed being the same,
+there is only a permitted authority to enforce an optional obedience. In a
+republic, the foundation of public order is the ever lessening habit of
+submission inherited from ancestors who, being truly governed, submitted
+because they had to. There are as many kinds of republics as there are
+graduations between the despotism whence they came and the anarchy whither they
+lead.</p>
+
+<p class="entry"><span class="def">requiem</span>, <span class="pos">n.</span> A mass
+for the dead which the minor poets assure us the winds sing o’er the graves of
+their favorites. Sometimes, by way of providing a varied entertainment, they sing a dirge.</p>
+
+<p class="entry"><span class="def">resident</span>, <span class="pos">adj.</span> Unable
+to leave.</p>
+
+<p class="entry"><span class="def">resign</span>, <span class="pos">v.t.</span> To
+renounce an honor for an advantage. To renounce an advantage for a greater advantage.</p>
+
+<div class="poem">
+<p class="poetry">‘Twas rumored Leonard Wood had signed</p>
+<p class="poetry">A true renunciation</p>
+<p class="poetry">Of title, rank and every kind</p>
+<p class="poetry">Of military station—</p>
+<p class="poetry">Each honorable station.</p>
+<p class="poetry">By his example fired—inclined</p>
+<p class="poetry">To noble emulation,</p>
+<p class="poetry">The country humbly was resigned</p>
+<p class="poetry">To Leonard’s resignation—</p>
+<p class="poetry">His Christian resignation.</p>
+<p class="citeauth">Politian Greame</p>
+</div>
+
+<p class="entry"><span class="def">resolute</span>, <span class="pos">adj.</span> Obstinate
+in a course that we approve.</p>
+
+<p class="entry"><span class="def">respectability</span>, <span class="pos">n.</span>
+The offspring of a <i>liaison</i> between a bald head and a bank account.</p>
+
+<p class="entry"><span class="def">respirator</span>, <span class="pos">n.</span> An
+apparatus fitted over the nose and mouth of an inhabitant of London, whereby to
+filter the visible universe in its passage to the lungs.</p>
+
+<p class="entry"><span class="def">respite</span>, <span class="pos">n.</span> A
+suspension of hostilities against a sentenced assassin, to enable the Executive
+to determine whether the murder may not have been done by the prosecuting
+attorney. Any break in the continuity of a disagreeable expectation.</p>
+
+<div class="poem">
+<p class="poetry">Altgeld upon his incandescend bed</p>
+<p class="poetry">Lay, an attendant demon at his head.</p>
+<p class="poetry">“O cruel cook, pray grant me some relief—</p>
+<p class="poetry">Some respite from the roast, however brief.”</p>
+<p class="poetry">“Remember how on earth I pardoned all Your friends in Illinois when held in thrall.”</p>
+<p class="poetry">“Unhappy soul! for that alone you squirm O’er fire unquenched, a never-dying worm.</p>
+<p class="poetry">“Yet, for I pity your uneasy state,</p>
+<p class="poetry">Your doom I’ll mollify and pains abate.</p>
+<p class="poetry">“Naught, for a season, shall your comfort mar,</p>
+<p class="poetry">Not even the memory of who you are.”</p>
+<p class="poetry">Throughout eternal space dread silence fell;</p>
+<p class="poetry">Heaven trembled as Compassion entered Hell.</p>
+<p class="poetry">“As long, sweet demon, let my respite be As, governing down here, I’d respite thee.”</p>
+<p class="poetry">“As long, poor soul, as any of the pack You thrust from jail consumed in getting back.”</p>
+<p class="poetry">A genial chill affected Altgeld’s hide While they were turning him on t’other side.</p>
+<p class="citeauth">Joel Spate Woop</p>
+</div>
+
+<p class="entry"><span class="def">resplendent</span>, <span class="pos">adj.</span> Like
+a simple American citizen beduking himself in his lodge, or affirming his
+consequence in the Scheme of Things as an elemental unit of a parade.</p>
+
+<p class="cite">The Knights of
+Dominion were so resplendent in their velvet- and-gold that their masters would
+hardly have known them. “Chronicles of the Classes”</p>
+
+<p class="entry"><span class="def">respond</span>, <span class="pos">v.i.</span> To
+make answer, or disclose otherwise a consciousness of having inspired an interest
+in what Herbert Spencer calls “external coexistences,” as Satan “squat like a
+toad” at the ear of Eve, responded to the touch of the angel’s spear. To
+respond in damages is to contribute to the maintenance of the plaintiff’s
+attorney and, incidentally, to the gratification of the plaintiff.</p>
+
+<p class="entry"><span class="def">responsibility</span>, <span class="pos">n.</span>
+A detachable burden easily shifted to the shoulders of God, Fate, Fortune, Luck
+or one’s neighbor. In the days of astrology it was customary to unload it upon a star.</p>
+
+<div class="poem">
+<p class="poetry">Alas, things ain’t what we should see</p>
+<p class="poetry">If Eve had let that apple be;</p>
+<p class="poetry">And many a feller which had ought</p>
+<p class="poetry">To set with monarchses of thought,</p>
+<p class="poetry">Or play some rosy little game</p>
+<p class="poetry">With battle-chaps on fields of fame,</p>
+<p class="poetry">Is downed by his unlucky star</p>
+<p class="poetry">And hollers: “Peanuts!—here you are!”</p>
+<p class="citeauth">“The Sturdy Beggar”</p>
+</div>
+
+<p class="entry"><span class="def">restitutions</span>, <span class="pos">n.</span> The
+founding or endowing of universities and public libraries by gift or bequest.</p>
+
+<p class="entry"><span class="def">restitutor</span>, <span class="pos">n.</span> Benefactor;
+philanthropist.</p>
+
+<p class="entry"><span class="def">retaliation</span>, <span class="pos">n.</span> The
+natural rock upon which is reared the Temple of Law.</p>
+
+<p class="entry"><span class="def">retribution</span>, <span class="pos">n.</span> A
+rain of fire-and-brimstone that falls alike upon the just and such of the
+unjust as have not procured shelter by evicting them.</p>
+
+<p>In the lines following, addressed to an Emperor in exile by Father Gassalasca Jape, the
+reverend poet appears to hint his sense of the improduence of turning about to
+face Retribution when it is talking exercise:</p>
+
+<p>What, what! Dom Pedro, you desire to go</p>
+
+<p>Back to Brazil to end your days in quiet?</p>
+
+<p>Why, what assurance have you ‘twould be so?</p>
+
+<p>‘Tis not so long since you were in a riot,</p>
+
+<p>And your dear subjects showed a will to fly at</p>
+
+<p>Your throat and shake you like a rat. You know That empires are ungrateful; are you certain
+Republics are less handy to get hurt in?</p>
+
+<p class="entry"><span class="def">reveille</span>, <span class="pos">n.</span> A
+signal to sleeping soldiers to dream of battlefields no more, but get up and
+have their blue noses counted. In the American army it is ingeniously called
+“rev-e-lee,” and to that pronunciation our countrymen have pledged their lives,
+their misfortunes and their sacred dishonor.</p>
+
+<p class="entry"><span class="def">revelation</span>, <span class="pos">n.</span> A
+famous book in which St. John the Divine concealed all that he knew. The
+revealing is done by the commentators, who know nothing.</p>
+
+<p class="entry"><span class="def">reverence</span>, <span class="pos">n.</span> The
+spiritual attitude of a man to a god and a dog to a man.</p>
+
+<p class="entry"><span class="def">review</span>, <span class="pos">v.t.</span></p>
+
+<div class="poem">
+<p class="poetry">To set your wisdom (holding not a doubt of it,</p>
+<p class="poetry">Although in truth there’s neither bone nor skin to it)</p>
+<p class="poetry">At work upon a book, and so read out of it</p>
+<p class="poetry">The qualities that you have first read into it.</p>
+</div>
+
+<p class="entry"><span class="def">revolution</span>, <span class="pos">n.</span> In
+politics, an abrupt change in the form of misgovernment. Specifically, in
+American history, the substitution of the rule of an Administration for that of
+a Ministry, whereby the welfare and happiness of the people were advanced a
+full half-inch. Revolutions are usually accompanied by a considerable effusion
+of blood, but are accounted worth it—this appraisement being made by
+beneficiaries whose blood had not the mischance to be shed. The French
+revolution is of incalculable value to the Socialist of to-day; when he pulls
+the string actuating its bones its gestures are inexpressibly terrifying to
+gory tyrants suspected of fomenting law and order.</p>
+
+<p class="entry"><span class="def">rhadomancer</span>, <span class="pos">n.</span> One
+who uses a divining-rod in prospecting for precious metals in the pocket of a fool.</p>
+
+<p class="entry"><span class="def">ribaldry</span>, <span class="pos">n.</span> Censorious
+language by another concerning oneself.</p>
+
+<p class="entry"><span class="def">ribroaster</span>, <span class="pos">n.</span> Censorious
+language by oneself concerning another. The word is of classical refinement,
+and is even said to have been used in a fable by Georgius Coadjutor, one of the
+most fastidious writers of the fifteenth century—commonly, indeed, regarded as
+the founder of the Fastidiotic School.</p>
+
+<p class="entry"><span class="def">rice-water</span>, <span class="pos">n.</span> A
+mystic beverage secretly used by our most popular novelists and poets to
+regulate the imagination and narcotize the conscience. It is said to be rich in
+both obtundite and lethargine, and is brewed in a midnight fog by a fat which
+of the Dismal Swamp.</p>
+
+<p id="rich" class="entry"><span class="def">rich</span>, <span class="pos">adj.</span> Holding
+in trust and subject to an accounting the property of the indolent, the
+incompetent, the unthrifty, the envious and the luckless. That is the view that
+prevails in the underworld, where the Brotherhood of Man finds its most logical
+development and candid advocacy. To denizens of the midworld the word means
+good and wise.</p>
+
+<p class="entry"><span class="def">riches</span>, <span class="pos">n.</span></p>
+
+<p class="cite">A gift from Heaven signifying, “This is my beloved son, in whom I am well pleased.” John D. Rockefeller</p>
+
+<p class="cite">The reward of toil and virtue. J.P. Morgan</p>
+
+<p class="cite">The sayings of many in the hands of one. Eugene Debs</p>
+
+<p class="indentpara">To these excellent definitions the inspired lexicographer feels that he can add nothing of value.</p>
+
+<p class="entry"><span class="def">ridicule</span>, <span class="pos">n.</span> Words
+designed to show that the person of whom they are uttered is devoid of the
+dignity of character distinguishing him who utters them. It may be graphic,
+mimetic or merely rident. Shaftesbury is quoted as having pronounced it the
+test of truth—a ridiculous assertion, for many a solemn fallacy has undergone
+centuries of ridicule with no abatement of its popular acceptance. What, for
+example, has been more valorously derided than the doctrine of Infant
+Respectability?</p>
+
+<p class="entry"><span class="def">right</span>, <span class="pos">n.</span> Legitimate
+authority to be, to do or to have; as the right to be a king, the right to do
+one’s neighbor, the right to have measles, and the like. The first of these
+rights was once universally believed to be derived directly from the will of
+God; and this is still sometimes affirmed <i>in
+partibus infidelium</i> outside the enlightened realms of Democracy; as
+the well known lines of Sir Abednego Bink, following:</p>
+
+<div class="poem">
+<p class="poetry">By what right, then, do royal rulers rule?</p>
+<p class="poetry">Whose is the sanction of their state and pow’r?</p>
+<p class="poetry">He surely were as stubborn as a mule</p>
+<p class="poetry">Who, God unwilling, could maintain an hour
+His uninvited session on the throne, or air
+His pride securely in the Presidential chair.</p>
+<p class="poetry">Whatever is is so by Right Divine;</p>
+<p class="poetry">Whate’er occurs, God wills it so. Good land!</p>
+<p class="poetry">It were a wondrous thing if His design</p>
+<p class="poetry">A fool could baffle or a rogue withstand!</p>
+<p class="poetry">If so, then God, Isay (intending no offence)</p>
+<p class="poetry">Is guilty of contributory negligence.</p>
+</div>
+
+<p class="entry"><span class="def">righteousness</span>, <span class="pos">n.</span> A
+sturdy virtue that was once found among the Pantidoodles inhabiting the lower
+part of the peninsula of Oque. Some feeble attempts were made by returned
+missionaries to introduce it into several European countries, but it appears to
+have been imperfectly expounded. An example of this faulty exposition is found
+in the only extant sermon of the pious Bishop Rowley, a characteristic passage
+from which is here given:</p>
+
+<p>“Now righteousness consisteth not merely in a holy state of mind, nor yet in performance of
+religious rites and obedience to the letter of the law. It is not enough that
+one be pious and just: one must see to it that others also are in the same
+state; and to this end compulsion is a proper means. Forasmuch as my injustice
+may work ill to another, so by his injustice may evil be wrought upon still
+another, the which it is as manifestly my duty to estop as to forestall mine
+own tort. Wherefore if I would be righteous I am bound to restrain my neighbor,
+by force if needful, in all those injurious enterprises from which, through a
+better disposition and by the help of Heaven, I do myself restrain.”</p>
+
+<p class="entry"><span class="def">rime</span>, <span class="pos">n.</span> Agreeing
+sounds in the terminals of verse, mostly bad. The verses themselves, as
+distinguished from prose, mostly dull. Usually (and wickedly) spelled “rhyme.”</p>
+
+<div class="poem">
+<p class="entry"><span class="def">rimer</span>, <span class="pos">n.</span> A poet
+regarded with indifference or disesteem.</p>
+<p class="poetry">The rimer quenches his unheeded fires,<br />
+The sound surceases and the sense expires.<br />
+Then the domestic dog, to east and west,<br />
+Expounds the passions burning in his breast.</p>
+<p class="poetry">The rising moon o’er that enchanted land</p>
+<p class="poetry">Pauses to hear and yearns to understand.</p>
+<p class="citeauth">Mowbray Myles</p>
+</div>
+
+<p class="entry"><span class="def">riot</span>, <span class="pos">n.</span> A popular
+entertainment given to the military by innocent bystanders.</p>
+
+<p class="entry"><span class="def">R.I.P.</span> A careless abbreviation of <i>requiescat in pace</i>,
+attesting to indolent goodwill to the dead. According to the learned Dr.
+Drigge, however, the letters originally meant nothing more than <i>reductus in pulvis</i>.</p>
+
+<p class="entry"><span class="def">riteE</span>, <span class="pos">n.</span> A
+religious or semi-religious ceremony fixed by law, precept or custom, with the
+essential oil of sincerity carefully squeezed out of it.</p>
+
+<p class="entry"><span class="def">ritualism</span>, <span class="pos">n.</span> A
+Dutch Garden of God where He may walk in rectilinear freedom, keeping off the
+grass.</p>
+
+<p class="entry"><span class="def">road</span>, <span class="pos">n.</span> A strip
+of land along which one may pass from where it is too tiresome to be to where
+it is futile to go.</p>
+
+<div class="poem">
+<p class="poetry">All roads, howsoe’er they diverge, lead to Rome,<br />
+Whence, thank the good Lord, at least one leads back home.</p>
+<p class="citeauth">Borey the Bald</p>
+</div>
+
+<p class="entry"><span class="def">robber</span>, <span class="pos">n.</span> A
+candid man of affairs.</p>
+
+<p class="indentpara">It is related of Voltaire that one night he and some traveling companion lodged at a wayside
+inn. The surroundings were suggestive, and after supper they agreed to tell
+robber stories in turn. “Once there was a Farmer-General of the Revenues.” Saying
+nothing more, he was encouraged to continue. “That,” he said, “is the story.”</p>
+
+<p class="entry"><span class="def">romance</span>, <span class="pos">n.</span> Fiction
+that owes no allegiance to the God of Things as They Are. In the novel the
+writer’s thought is tethered to probability, as a domestic horse to the
+hitching-post, but in romance it ranges at will over the entire region of the
+imagination—free, lawless, immune to bit and rein. Your novelist is a poor
+creature, as Carlyle might say—a mere reporter. He may invent his characters
+and plot, but he must not imagine anything taking place that might not occur,
+albeit his entire narrative is candidly a lie. Why he imposes this hard
+condition on himself, and “drags at each remove a lengthening chain” of his own
+forging he can explain in ten thick volumes without illuminating by so much as
+a candle’s ray the black profound of his own ignorance of the matter. There are
+great novels, for great writers have “laid waste their powers” to write them,
+but it remains true that far and away the most fascinating fiction that we have
+is “The Thousand and One Nights.”</p>
+
+<p class="entry"><span class="def">rope</span>, <span class="pos">n.</span> An
+obsolescent appliance for reminding assassins that they too are mortal. It is
+put about the neck and remains in place one’s whole life long. It has been
+largely superseded by a more complex electrical device worn upon another part
+of the person; and this is rapidly giving place to an apparatus known as the
+preachment.</p>
+
+<p class="entry"><span class="def">rostrum</span>, <span class="pos">n.</span> In
+Latin, the beak of a bird or the prow of a ship. In America, a place from which
+a candidate for office energetically expounds the wisdom, virtue and power of
+the rabble.</p>
+
+<p class="entry"><span class="def">roundhead</span>, <span class="pos">n.</span> A
+member of the Parliamentarian party in the English civil war—so called from his
+habit of wearing his hair short, whereas his enemy, the Cavalier, wore his
+long. There were other points of difference between them, but the fashion in
+hair was the fundamental cause of quarrel. The Cavaliers were royalists because
+the king, an indolent fellow, found it more convenient to let his hair grow
+than to wash his neck. This the Roundheads, who were mostly barbers and
+soap-boilers, deemed an injury to trade, and the royal neck was therefore the
+object of their particular indignation. Descendants of the belligerents now
+wear their hair all alike, but the fires of animosity enkindled in that ancient
+strife smoulder to this day beneath the snows of British civility.</p>
+
+<p class="entry"><span class="def">rubbish</span>, <span class="pos">n.</span> Worthless
+matter, such as the religions, philosophies, literatures, arts and sciences of
+the tribes infesting the regions lying due south from Boreaplas.</p>
+
+<p class="entry"><span class="def">ruin</span>, <span class="pos">v.</span> To
+destroy. Specifically, to destroy a maid’s belief in the virtue of maids.</p>
+
+<p class="entry"><span class="def">rum</span>, <span class="pos">n.</span> Generically,
+fiery liquors that produce madness in total abstainers.</p>
+
+<p class="entry"><span class="def">rumor</span>, <span class="pos">n.</span> A
+favorite weapon of the assassins of character.</p>
+
+<div class="poem">
+<p class="poetry">Sharp, irresistible by mail or shield,</p>
+<p class="poetry">By guard unparried as by flight unstayed,</p>
+<p class="poetry">O serviceable Rumor, let me wield</p>
+<p class="poetry">Against my enemy no other blade.</p>
+<p class="poetry">His be the terror of a foe unseen,</p>
+<p class="poetry">His the inutile hand upon the hilt,</p>
+<p class="poetry">And mine the deadly tongue, long, slender, keen,</p>
+<p class="poetry">Hinting a rumor of some ancient guilt. So shall I slay the wretch without a blow, Spare me to
+celebrate his overthrow, And nurse my valor for another foe.</p>
+<p class="citeauth">Joel Buxter</p>
+</div>
+
+<p class="entry"><span class="def">Russian</span>, <span class="pos">n.</span> A
+person with a Caucasian body and a Mongolian soul. A Tartar Emetic.</p>
+
+</body>
+</html>
\ No newline at end of file
--- /dev/null
+++ b/lib/ebooks/devils/R.html.i
@@ -1,0 +1,53 @@
+24 pages
+size 400 552
+length 38788
+396 2 10 body html
+0
+1895 2 45 body html
+0
+3733 2 83 body html
+19
+4759 2 108 body html
+0
+6886 2 147 body html
+0
+8507 2 183 body html
+39
+10023 2 211 body html
+0
+12182 2 251 body html
+0
+14402 2 284 body html
+56
+15730 2 304 body html
+252
+17578 2 342 body html
+22
+19605 2 380 body html
+22
+20862 2 407 body html
+0
+21171 2 412 body html
+466
+23582 2 450 body html
+19
+24766 2 475 body html
+68
+26209 2 507 body html
+72
+28293 2 543 body html
+0
+29753 2 569 body html
+90
+31009 2 592 body html
+90
+32478 2 614 body html
+222
+34691 2 659 body html
+22
+36424 2 686 body html
+124
+37953 2 711 body html
+288
+religion 7
+rich 16
--- /dev/null
+++ b/lib/ebooks/devils/S.html
@@ -1,0 +1,844 @@
+<?xml version="1.0"?>
+<!DOCTYPE package PUBLIC "+//ISBN 0-9673008-1-9//DTD OEB 1.0 Package//EN"
+ "http://openebook.org/dtds/oeb-1.0/oebdoc1.dtd">
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/x-oeb1-document; charset=utf-8" />
+<link rel="stylesheet" type="text/x-oeb1-css" href="devil.css" />
+<title>The Devil’s Dictionary: S</title>
+</head>
+<body lang="en-US">
+
+
+<h1>S</h1>
+
+<p class="entry"><span class="def">Sabbath</span>, <span class="pos">n.</span> A
+weekly festival having its origin in the fact that God made the world in six
+days and was arrested on the seventh. Among the Jews observance of the day was
+enforced by a Commandment of which this is the Christian version: “Remember the
+seventh day to make thy neighbor keep it wholly.” To the Creator it seemed fit
+and expedient that the Sabbath should be the last day of the week, but the
+Early Fathers of the Church held other views. So great is the sanctity of the
+day that even where the Lord holds a doubtful and precarious jurisdiction over
+those who go down to (and down into) the sea it is reverently recognized, as is
+manifest in the following deep-water version of the Fourth Commandment:</p>
+
+<p>Six days shalt thou labor and do all thou art able, And on the seventh holystone the deck and
+scrape the cable.</p>
+
+<p>Decks are no longer holystoned, but the cable still supplies the captain with opportunity to
+attest a pious respect for the divine ordinance.</p>
+
+<p class="entry"><span class="def">sacerdotalist</span>, <span class="pos">n.</span> One
+who holds the belief that a clergyman is a priest. Denial of this momentous
+doctrine is the hardest challenge that is now flung into the teeth of the
+Episcopalian church by the Neo-Dictionarians.</p>
+
+<p class="entry"><span class="def">sacrament</span>, <span class="pos">n.</span> A
+solemn religious ceremony to which several degrees of authority and
+significance are attached. Rome has seven sacraments, but the Protestant
+churches, being less prosperous, feel that they can afford only two, and these
+of inferior sanctity. Some of the smaller sects have no sacraments at all—for
+which mean economy they will indubitable be damned.</p>
+
+<p class="entry"><span class="def">sacred</span>, <span class="pos">adj.</span> Dedicated
+to some religious purpose; having a divine character; inspiring solemn thoughts
+or emotions; as, the Dalai Lama of Thibet; the Moogum of M’bwango; the temple
+of Apes in Ceylon; the Cow in India; the Crocodile, the Cat and the Onion of
+ancient Egypt; the Mufti of Moosh; the hair of the dog that bit Noah, etc.</p>
+
+<div class="poem">
+<p class="poetry">All things are either sacred or profane.</p>
+<p class="poetry">The former to ecclesiasts bring gain;</p>
+<p class="poetry">The latter to the devil appertain.</p>
+<p class="citeauth">Dumbo Omohundro</p>
+</div>
+
+<p class="entry"><span class="def">sandlotter</span>, <span class="pos">n.</span> A
+vertebrate mammal holding the political views of Denis Kearney, a notorious
+demagogue of San Francisco, whose audiences gathered in the open spaces
+(sandlots) of the town. True to the traditions of his species, this leader of
+the proletariat was finally bought off by his law-and-order enemies, living
+prosperously silent and dying impenitently rich. But before his treason he
+imposed upon California a constitution that was a confection of sin in a
+diction of solecisms. The similarity between the words “sandlotter” and
+“sansculotte” is problematically significant, but indubitably suggestive.</p>
+
+<p class="entry"><span class="def">safety-clutch</span>, <span class="pos">n.</span> A
+mechanical device acting automatically to prevent the fall of an elevator, or
+cage, in case of an accident to the hoisting apparatus.</p>
+
+<div class="poem">
+<p class="poetry">Once I seen a human ruin</p>
+<p class="poetry">In an elevator-well,</p>
+<p class="poetry">And his members was bestrewin’</p>
+<p class="poetry">All the place where he had fell.</p>
+<p class="poetry">And I says, apostrophisin’</p>
+<p class="poetry">That uncommon woful wreck:</p>
+<p class="poetry">“Your position’s so surprisin’</p>
+<p class="poetry">That I tremble for your neck!”</p>
+<p class="poetry">Then that ruin, smilin’ sadly</p>
+<p class="poetry">And impressive, up and spoke:</p>
+<p class="poetry">“Well, I wouldn’t tremble badly,</p>
+<p class="poetry">For it’s been a fortnight broke.”</p>
+<p class="poetry">Then, for further comprehension</p>
+<p class="poetry">Of his attitude, he begs</p>
+<p class="poetry">I will focus my attention</p>
+<p class="poetry">On his various arms and legs—</p>
+<p class="poetry">How they all are contumacious;</p>
+<p class="poetry">Where they each, respective, lie;</p>
+<p class="poetry">How one trotter proves ungracious,</p>
+<p class="poetry">T’other one an <i>alibi</i>.</p>
+<p class="poetry">These particulars is mentioned</p>
+<p class="poetry">For to show his dismal state,</p>
+<p class="poetry">Which I wasn’t first intentioned</p>
+<p class="poetry">To specifical relate.</p>
+<p class="poetry">None is worser to be dreaded</p>
+<p class="poetry">That I ever have heard tell</p>
+<p class="poetry">Than the gent’s who there was spreaded</p>
+<p class="poetry">In that elevator-well.</p>
+<p class="poetry">Now this tale is allegoric—</p>
+<p class="poetry">It is figurative all,</p>
+<p class="poetry">For the well is metaphoric</p>
+<p class="poetry">And the feller didn’t fall.</p>
+<p class="poetry">I opine it isn’t moral</p>
+<p class="poetry">For a writer-man to cheat,</p>
+<p class="poetry">And despise to wear a laurel</p>
+<p class="poetry">As was gotten by deceit.</p>
+<p class="poetry">For ‘tis Politics intended</p>
+<p class="poetry">By the elevator, mind,</p>
+<p class="poetry">It will boost a person splendid</p>
+<p class="poetry">If his talent is the kind.</p>
+<p class="poetry">Col. Bryan had the talent</p>
+<p class="poetry">(For the busted man is him)</p>
+<p class="poetry">And it shot him up right gallant</p>
+<p class="poetry">Till his head begun to swim.</p>
+<p class="poetry">Then the rope it broke above him</p>
+<p class="poetry">And he painful come to earth</p>
+<p class="poetry">Where there’s nobody to love him</p>
+<p class="poetry">For his detrimented worth.</p>
+<p class="poetry">Though he’s livin’ none would know him,</p>
+<p class="poetry">Or at leastwise not as such.</p>
+<p class="poetry">Moral of this woful poem:</p>
+<p class="poetry">Frequent oil your safety-clutch.</p>
+<p class="citeauth">Porfer Poog</p>
+</div>
+
+<p class="entry"><span class="def">saint</span>, <span class="pos">n.</span> A dead
+sinner revised and edited.</p>
+
+<p class="indentpara">The Duchess of Orleans relates that the irreverent old calumniator, Marshal Villeroi, who in
+his youth had known St. Francis de Sales, said, on hearing him called saint: “I
+am delighted to hear that Monsieur de Sales is a saint. He was fond of saying
+indelicate things, and used to cheat at cards. In other respects he was a
+perfect gentleman, though a fool.”</p>
+
+<p class="entry"><span class="def">salacity</span>, <span class="pos">n.</span> A
+certain literary quality frequently observed in popular novels, especially in
+those written by women and young girls, who give it another name and think that
+in introducing it they are occupying a neglected field of letters and reaping
+an overlooked harvest. If they have the misfortune to live long enough they are
+tormented with a desire to burn their sheaves.</p>
+
+<p class="entry"><span class="def">salamander</span>, <span class="pos">n.</span> Originally
+a reptile inhabiting fire; later, an anthropomorphous immortal, but still a pyrophile.
+Salamanders are now believed to be extinct, the last one of which we have an
+account having been seen in Carcassonne by the Abbe Belloc, who exorcised it
+with a bucket of holy water.</p>
+
+<p class="entry"><span class="def">sarcophagus</span>, <span class="pos">n.</span> Among
+the Greeks a coffin which being made of a certain kind of carnivorous stone,
+had the peculiar property of devouring the body placed in it. The sarcophagus
+known to modern obsequiographers is commonly a product of the carpenter’s art.</p>
+
+<p class="entry"><span class="def">Satan</span>, <span class="pos">n.</span> One of
+the Creator’s lamentable mistakes, repented in sashcloth and axes. Being
+instated as an archangel, Satan made himself multifariously objectionable and
+was finally expelled from Heaven. Halfway in his descent he paused, bent his
+head in thought a moment and at last went back. “There is one favor that I
+should like to ask,” said he.</p>
+<p>“Name it.”</p>
+<p>“Man, I understand, is about to be created. He will need laws.”</p>
+<p>“What, wretch! you his appointed adversary, charged from the dawn </p>
+<p>of eternity with hatred of his soul—you ask for the right to make his laws?”</p>
+<p>“Pardon; what I have to ask is that he be permitted to make them himself.”</p>
+<p>It was so ordered.</p>
+
+<p class="entry"><span class="def">satiety</span>, <span class="pos">n.</span> The
+feeling that one has for the plate after he has eaten its contents, madam.</p>
+
+<p class="entry"><span class="def">satire</span>, <span class="pos">n.</span> An
+obsolete kind of literary composition in which the vices and follies of the
+author’s enemies were expounded with imperfect tenderness. In this country
+satire never had more than a sickly and uncertain existence, for the soul of it
+is wit, wherein we are dolefully deficient, the humor that we mistake for it,
+like all humor, being tolerant and sympathetic. Moreover, although Americans
+are “endowed by their Creator” with abundant vice and folly, it is not
+generally known that these are reprehensible qualities, wherefore the satirist
+is popularly regarded as a soul-spirited knave, and his ever victim’s outcry
+for codefendants evokes a national assent.</p>
+
+<div class="poem">
+<p class="poetry">Hail Satire! be thy praises ever sung</p>
+In the dead language of a mummy’s tongue,<br />
+For thou thyself art dead, and damned as well—<br />
+Thy spirit (usefully employed) in Hell.<br />
+Had it been such as consecrates the Bible<br />
+Thou hadst not perished by the law of libel.<br />
+<p class="citeauth">Barney Stims</p>
+</div>
+
+<p class="entry"><span class="def">satyr</span>, <span class="pos">n.</span> One of
+the few characters of the Grecian mythology accorded recognition in the Hebrew.
+(Leviticus, xvii, 7.) The satyr was at first a member of the dissolute
+community acknowledging a loose allegiance with Dionysius, but underwent many
+transformations and improvements. Not infrequently he is confounded with the
+faun, a later and decenter creation of the Romans, who was less like a man and more
+like a goat.</p>
+
+<p class="entry"><span class="def">sauce</span>, <span class="pos">n.</span> The one
+infallible sign of civilization and enlightenment. A people with no sauces has
+one thousand vices; a people with one sauce has only nine hundred and
+ninety-nine. For every sauce invented and accepted a vice is renounced and
+forgiven.</p>
+
+<p class="entry"><span class="def">saw</span>, <span class="pos">n.</span> A trite
+popular saying, or proverb. (Figurative and colloquial.) So called because it
+makes its way into a wooden head. Following are examples of old saws fitted
+with new teeth.</p>
+
+<div class="poem">
+<p class="poetry">A penny saved is a penny to squander.</p>
+<p class="poetry">A man is known by the company that he organizes.</p>
+<p class="poetry">A bad workman quarrels with the man who calls him that.</p>
+<p class="poetry">A bird in the hand is worth what it will bring.</p>
+<p class="poetry">Better late than before anybody has invited you.</p>
+<p class="poetry">Example is better than following it.</p>
+<p class="poetry">Half a loaf is better than a whole one if there is much else.</p>
+<p class="poetry">Think twice before you speak to a friend in need.</p>
+<p class="poetry">What is worth doing is worth the trouble of asking somebody to do it.</p>
+<p class="poetry">Least said is soonest disavowed.</p>
+<p class="poetry">He laughs best who laughs least.</p>
+<p class="poetry">Speak of the Devil and he will hear about it.</p>
+<p class="poetry">Of two evils choose to be the least.</p>
+<p class="poetry">Strike while your employer has a big contract.</p>
+<p class="poetry">Where there’s a will there’s a won’t.</p>
+</div>
+
+<p class="entry"><span class="def">Sacrabaeus</span>, <span class="pos">n.</span> The
+sacred beetle of the ancient Egyptians, allied to our familiar “tumble-bug.” It
+was supposed to symbolize immortality, the fact that God knew why giving it its
+peculiar sanctity. Its habit of incubating its eggs in a ball of ordure may
+also have commended it to the favor of the priesthood, and may some day assure
+it an equal reverence among ourselves. True, the American beetle is an inferior
+beetle, but the American priest is an inferior priest.</p>
+
+<p class="entry"><span class="def">Scarabee</span>, <span class="pos">n.</span> The
+same as scarabaeus.</p>
+
+<div class="poem">
+<p class="poetry">He fell by his own hand<br />
+Beneath the great oak tree.<br />
+He’d traveled in a foreign land.<br />
+He tried to make her understand<br />
+The dance that’s called the Saraband,<br />
+But he called it Scarabee.<br />
+He had called it so through an afternoon,<br />
+And she, the light of his harem if so might be,<br />
+Had smiled and said naught. O the body was fair to see,<br />
+All frosted there in the shine o’ the moon—<br />
+Dead for a Scarabee And a recollection that came too late.<br />
+O Fate!<br />
+They buried him where he lay,<br />
+He sleeps awaiting the Day,<br />
+In state, And two Possible Puns, moon-eyed and wan,<br />
+Gloom over the grave and then move on.<br />
+Dead for a Scarabee!</p>
+<p class="citeauth">Fernando Tapple</p>
+</div>
+
+<p class="entry"><span class="def">scarification</span>, <span class="pos">n.</span> A
+form of penance practised by the mediaeval pious. The rite was performed,
+sometimes with a knife, sometimes with a hot iron, but always, says Arsenius
+Asceticus, acceptably if the penitent spared himself no pain nor harmless
+disfigurement. Scarification, with other crude penances, has now been
+superseded by benefaction. The founding of a library or endowment of a
+university is said to yield to the penitent a sharper and more lasting pain
+than is conferred by the knife or iron, and is therefore a surer means of
+grace. There are, however, two grave objections to it as a penitential method: the
+good that it does and the taint of justice.</p>
+
+<p class="entry"><span class="def">scepter</span>, <span class="pos">n.</span> A
+king’s staff of office, the sign and symbol of his authority. It was originally
+a mace with which the sovereign admonished his jester and vetoed ministerial
+measures by breaking the bones of their proponents.</p>
+
+<p class="entry"><span class="def">scimetar</span>, <span class="pos">n.</span> A
+curved sword of exceeding keenness, in the conduct of which certain Orientals
+attain a surprising proficiency, as the incident here related will serve to
+show. The account is translated from the Japanese by Shusi Itama, a famous
+writer of the thirteenth century.</p>
+
+<p class="indentpara">When the great Gichi-Kuktai was Mikado he condemned to decapitation Jijiji Ri, a high officer
+of the Court. Soon after the hour appointed for performance of the rite what
+was his Majesty’s surprise to see calmly approaching the throne the man who
+should have been at that time ten minutes dead!</p>
+
+<p class="indentpara">“Seventeen hundred impossible dragons!” shouted the enraged monarch. “Did I not sentence you to
+stand in the market-place and have your head struck off by the public
+executioner at three o’clock? And is it not now 3:10?”</p>
+
+<p class="indentpara">“Son of a thousand illustrious deities,” answered the condemned minister, “all that you say is so
+true that the truth is a lie in comparison. But your heavenly Majesty’s sunny
+and vitalizing wishes have been pestilently disregarded. With joy I ran and
+placed my unworthy body in the market-place. The executioner appeared with his
+bare scimetar, ostentatiously whirled it in air, and then, tapping me lightly
+upon the neck, strode away, pelted by the populace, with whom I was ever a
+favorite. I am come to pray for justice upon his own dishonorable and
+treasonous head.”</p>
+
+<p class="indentpara">“To what regiment
+of executioners does the black-boweled caitiff belong?” asked the Mikado.</p>
+
+<p class="indentpara">“To the gallant Ninety-eight Hundred and Thirty-seventh—I know the man. His name is
+Sakko-Samshi.”</p>
+
+<p class="indentpara">“Let him be
+brought before me,” said the Mikado to an attendant, and a half-hour later the
+culprit stood in the Presence.</p>
+
+<p class="indentpara">“Thou bastard son
+of a three-legged hunchback without thumbs!” roared the sovereign—“why didst
+thou but lightly tap the neck that it should have been thy pleasure to sever?”</p>
+
+<p class="indentpara">“Lord of Cranes of
+Cherry Blooms,” replied the executioner, unmoved, “command him to blow his nose
+with his fingers.”</p>
+
+<p class="indentpara">Being commanded,
+Jijiji Ri laid hold of his nose and trumpeted like an elephant, all expecting
+to see the severed head flung violently from him. Nothing occurred: the
+performance prospered peacefully to the close, without incident.</p>
+
+<p class="indentpara">All eyes were now
+turned on the executioner, who had grown as white as the snows on the summit of
+Fujiama. His legs trembled and his breath came in gasps of terror.</p>
+
+<p class="indentpara">“Several kinds of
+spike-tailed brass lions!” he cried; “I am a ruined and disgraced swordsman! I
+struck the villain feebly because in flourishing the scimetar I had
+accidentally passed it through my own neck! Father of the Moon, I resign my office.”</p>
+
+<p class="indentpara">So saying, he
+gasped his top-knot, lifted off his head, and advancing to the throne laid it
+humbly at the Mikado’s feet.</p>
+
+<p class="entry"><span class="def">scrap-book</span>, <span class="pos">n.</span> A
+book that is commonly edited by a fool. Many persons of some small distinction
+compile scrap-books containing whatever they happen to read about themselves or
+employ others to collect. One of these egotists was addressed in the lines
+following, by Agamemnon Melancthon Peters:</p>
+
+<div class="poem">
+<p class="poetry">Dear Frank, that scrap-book where you boast<br />
+You keep a record true<br />
+Of every kind of peppered roast<br />
+That’s made of you;<br />
+Wherein you paste the printed gibes<br />
+That revel round your name,<br />
+Thinking the laughter of the scribes<br />
+Attests your fame;<br />
+Where all the pictures you arrange<br />
+That comic pencils trace—<br />
+Your funny figure and your strange<br />
+Semitic face—<br />
+Pray lend it me. Wit I have not,<br />
+Nor art, but there I’ll list<br />
+The daily drubbings you’d have got<br />
+Had God a fist.</p>
+</div>
+
+<p class="entry"><span class="def">scribbler</span>, <span class="pos">n.</span> A
+professional writer whose views are antagonistic to one’s own.</p>
+
+<p class="entry"><span class="def">scriptures</span>, <span class="pos">n.</span> The
+sacred books of our holy religion, as distinguished from the false and profane
+writings on which all other faiths are based.</p>
+
+<p class="entry"><span class="def">seal</span>, <span class="pos">n.</span> A mark
+impressed upon certain kinds of documents to attest their authenticity and
+authority. Sometimes it is stamped upon wax, and attached to the paper,
+sometimes into the paper itself. Sealing, in this sense, is a survival of an
+ancient custom of inscribing important papers with cabalistic words or signs to
+give them a magical efficacy independent of the authority that they represent. In
+the British museum are preserved many ancient papers, mostly of a sacerdotal
+character, validated by necromantic pentagrams and other devices, frequently
+initial letters of words to conjure with; and in many instances these are
+attached in the same way that seals are appended now. As nearly every
+reasonless and apparently meaningless custom, rite or observance of modern
+times had origin in some remote utility, it is pleasing to note an example of
+ancient nonsense evolving in the process of ages into something really useful. Our
+word “sincere” is derived from <i>sine cero</i>,
+without wax, but the learned are not in agreement as to whether this refers to
+the absence of the cabalistic signs, or to that of the wax with which letters
+were formerly closed from public scrutiny. Either view of the matter will serve
+one in immediate need of an hypothesis. The initials L.S., commonly appended to
+signatures of legal documents, mean <i>locum sigillis</i>, the place of the seal,
+although the seal is no longer used—an admirable example of conservatism
+distinguishing Man from the beasts that perish. The words <i>locum sigillis</i> are humbly suggested as a
+suitable motto for the Pribyloff Islands whenever they shall take their place
+as a sovereign State of the American Union.</p>
+
+<p class="entry"><span class="def">seine</span>, <span class="pos">n.</span> A kind
+of net for effecting an involuntary change of environment. For fish it is made
+strong and coarse, but women are more easily taken with a singularly delicate
+fabric weighted with small, cut stones.</p>
+
+<div class="poem">
+<p class="poetry">The devil casting a seine of lace,<br />
+(With precious stones ‘twas weighted)<br />
+Drew it into the landing place<br />
+And its contents calculated.<br />
+All souls of women were in that sack—<br />
+A draft miraculous, precious!<br />
+But ere he could throw it across his back<br />
+They’d all escaped through the meshes.</p>
+<p class="citeauth">Baruch de Loppis</p>
+</div>
+
+<p class="entry"><span class="def">self-esteem</span>, <span class="pos">n.</span> An
+erroneous appraisement.</p>
+
+<p class="entry"><span class="def">self-evident</span>, <span class="pos">adj.</span>
+Evident to one’s self and to nobody else.</p>
+
+<p class="entry"><span class="def">selfish</span>, <span class="pos">adj.</span> Devoid
+of consideration for the selfishness of others.</p>
+
+<p class="entry"><span class="def">senate</span>, <span class="pos">n.</span> A body
+of elderly gentlemen charged with high duties and misdemeanors.</p>
+
+<p class="entry"><span class="def">serial</span>, <span class="pos">n.</span> A
+literary work, usually a story that is not true, creeping through several issues
+of a newspaper or magazine. Frequently appended to each installment is a
+“synposis of preceding chapters” for those who have not read them, but a direr
+need is a synposis of succeeding chapters for those who do not intend to read <i>them</i>. A synposis of the entire work would
+be still better.</p>
+
+<p class="indentpara">The late James F. Bowman was writing a serial tale for a weekly paper in collaboration with a
+genius whose name has not come down to us. They wrote, not jointly but
+alternately, Bowman supplying the installment for one week, his friend for the
+next, and so on, world without end, they hoped. Unfortunately they quarreled,
+and one Monday morning when Bowman read the paper to prepare himself for his
+task, he found his work cut out for him in a way to surprise and pain him. His
+collaborator had embarked every character of the narrative on a ship and sunk
+them all in the deepest part of the Atlantic.</p>
+
+<p class="entry"><span class="def">severalty</span>, <span class="pos">n.</span> Separateness,
+as, lands in severalty, i.e., lands held individually, not in joint ownership. Certain
+tribes of Indians are believed now to be sufficiently civilized to have in
+severalty the lands that they have hitherto held as tribal organizations, and
+could not sell to the Whites for waxen beads and potato whiskey.</p>
+
+<div class="poem">
+<p class="poetry">Lo! the poor Indian whose unsuited mind<br />
+Saw death before, hell and the grave behind;<br />
+Whom thrifty settler ne’er besought to stay—<br />
+His small belongings their appointed prey;<br />
+Whom Dispossession, with alluring wile,<br />
+Persuaded elsewhere every little while!<br />
+His fire unquenched and his undying worm<br />
+By “land in severalty” (charming term!)<br />
+Are cooled and killed, respectively, at last,<br />
+And he to his new holding anchored fast!</p>
+</div>
+
+<p class="entry"><span class="def">sheriff</span>, <span class="pos">n.</span> In
+America the chief executive office of a country, whose most characteristic
+duties, in some of the Western and Southern States, are the catching and
+hanging of rogues.</p>
+
+<div class="poem">
+<p class="poetry">John Elmer Pettibone Cajee<br />
+(I write of him with little glee)<br />
+Was just as bad as he could be.</p>
+
+<p class="poetry">‘Twas frequently remarked: “I swon!<br />
+The sun has never looked upon<br />
+So bad a man as Neighbor John.”</p>
+
+<p class="poetry">A sinner through and through, he had<br />
+This added fault: it made him mad<br />
+To know another man was bad.</p>
+
+<p class="poetry">In such a case he thought it right<br />
+To rise at any hour of night<br />
+And quench that wicked person’s light.</p>
+
+<p class="poetry">Despite the town’s entreaties, he<br />
+Would hale him to the nearest tree<br />
+And leave him swinging wide and free.</p>
+
+<p class="poetry">Or sometimes, if the humor came,<br />
+A luckless wight’s reluctant frame<br />
+Was given to the cheerful flame.</p>
+
+<p class="poetry">While it was turning nice and brown,<br />
+All unconcerned John met the frown<br />
+Of that austere and righteous town.</p>
+
+<p class="poetry">“How sad,” his neighbors said, “that he<br />
+So scornful of the law should be—<br />
+An anar c, h, i, s, t.”</p>
+
+<p class="poetry">(That is the way that they preferred<br />
+To utter the abhorrent word,<br />
+So strong the aversion that it stirred.)</p>
+
+<p class="poetry">“Resolved,” they said, continuing,<br />
+“That Badman John must cease this thing<br />
+Of having his unlawful fling.</p>
+
+<p class="poetry">“Now, by these sacred relics”—here<br />
+Each man had out a souvenir<br />
+Got at a lynching yesteryear—</p>
+
+<p class="poetry">“By these we swear he shall forsake<br />
+His ways, nor cause our hearts to ache<br />
+By sins of rope and torch and stake.</p>
+
+<p class="poetry">“We’ll tie his red right hand until<br />
+He’ll have small freedom to fulfil<br />
+The mandates of his lawless will.”</p>
+
+<p class="poetry">So, in convention then and there,<br />
+They named him Sheriff. The affair<br />
+Was opened, it is said, with prayer.</p>
+<p class="citeauth">J. Milton Sloluck</p>
+</div>
+
+<p class="entry"><span class="def">siren</span>, <span class="pos">n.</span> One of several
+musical prodigies famous for a vain attempt to dissuade Odysseus from a life on
+the ocean wave. Figuratively, any lady of splendid promise, dissembled purpose
+and disappointing performance.</p>
+
+<p class="entry"><span class="def">slang</span>, <span class="pos">n.</span> The
+grunt of the human hog (<i>Pignoramus intolerabilis</i>) with an audible memory. The
+speech of one who utters with his tongue what he thinks with his ear, and feels
+the pride of a creator in accomplishing the feat of a parrot. A means (under
+Providence) of setting up as a wit without a capital of sense.</p>
+
+<p class="entry"><span class="def">smithareen</span>, <span class="pos">n.</span> A
+fragment, a decomponent part, a remain. The word is used variously, but in the
+following verse on a noted female reformer who opposed bicycle-riding by women
+because it “led them to the devil” it is seen at its best:</p>
+
+<div class="poem">
+<p class="poetry">The wheels go round without a sound—<br />
+The maidens hold high revel;<br />
+In sinful mood, insanely gay,<br />
+True spinsters spin adown the way<br />
+From duty to the devil!<br />
+They laugh, they sing, and—ting-a-ling!<br />
+Their bells go all the morning;<br />
+Their lanterns bright bestar the night<br />
+Pedestrians a-warning.<br />
+With lifted hands Miss Charlotte stands,<br />
+Good-Lording and O-mying,<br />
+Her rheumatism forgotten quite,<br />
+Her fat with anger frying.<br />
+She blocks the path that leads to wrath,<br />
+Jack Satan’s power defying.<br />
+The wheels go round without a sound<br />
+The lights burn red and blue and green.<br />
+What’s this that’s found upon the ground?<br />
+Poor Charlotte Smith’s a smithareen!</p>
+<p class="citeauth">John William Yope</p>
+</div>
+
+<p class="entry"><span class="def">sophistry</span>, <span class="pos">n.</span> The
+controversial method of an opponent, distinguished from one’s own by superior
+insincerity and fooling. This method is that of the later Sophists, a Grecian
+sect of philosophers who began by teaching wisdom, prudence, science, art and,
+in brief, whatever men ought to know, but lost themselves in a maze of quibbles
+and a fog of words.</p>
+
+<div class="poem">
+<p class="poetry">His bad opponent’s “facts” he sweeps away, And drags his sophistry to light of day;<br />
+Then swears they’re pushed to madness who resort To falsehood of so desperate a sort.<br />
+Not so; like sods upon a dead man’s breast, He lies most lightly who the least is pressed.</p>
+<p class="citeauth">Polydore Smith</p>
+</div>
+<p class="entry"><span class="def">sorcery</span>, <span class="pos">n.</span> The
+ancient prototype and forerunner of political influence. It was, however,
+deemed less respectable and sometimes was punished by torture and death. Augustine
+Nicholas relates that a poor peasant who had been accused of sorcery was put to
+the torture to compel a confession. After enduring a few gentle agonies the
+suffering simpleton admitted his guilt, but naively asked his tormentors if it
+were not possible to be a sorcerer without knowing it.</p>
+
+<p id="soul" class="entry"><span class="def">soul</span>, <span class="pos">n.</span> A
+spiritual entity concerning which there hath been brave disputation. Plato held
+that those souls which in a previous state of existence (antedating Athens) had
+obtained the clearest glimpses of eternal truth entered into the bodies of
+persons who became philosophers. Plato himself was a philosopher. The souls
+that had least contemplated divine truth animated the bodies of usurpers and
+despots. Dionysius I, who had threatened to decapitate the broad- browed
+philosopher, was a usurper and a despot. Plato, doubtless, was not the first to
+construct a system of philosophy that could be quoted against his enemies;
+certainly he was not the last.</p>
+
+<p class="indentpara">“Concerning the nature of the soul,” saith the renowned author
+of <i>Diversiones Sanctorum</i>, “there hath been hardly more argument
+than that of its place in the body. Mine own belief is that the soul hath her
+seat in the abdomen—in which faith we may discern and interpret a truth
+hitherto unintelligible, namely that the glutton is of all men most devout. He
+is said in the Scripture to ‘make a god of his belly’—why, then, should he
+not be pious, having ever his Deity with him to freshen his faith? Who so well
+as he can know the might and majesty that he shrines? Truly and soberly, the
+soul and the stomach are one Divine Entity; and such was the belief of Promasius,
+who nevertheless erred in denying it immortality. He had observed that its
+visible and material substance failed and decayed with the rest of the body
+after death, but of its immaterial essence he knew nothing. This is what we
+call the Appetite, and it survives the wreck and reek of mortality, to be
+rewarded or punished in another world, according to what it hath demanded in
+the flesh. The Appetite whose coarse clamoring was for the unwholesome viands
+of the general market and the public refectory shall be cast into eternal
+famine, whilst that which firmly through civilly insisted on ortolans, caviare,
+terrapin, anchovies, <i>pates de foie gras</i>
+and all such Christian comestibles shall flesh its spiritual tooth in the souls
+of them forever and ever, and wreak its divine thirst upon the immortal parts
+of the rarest and richest wines ever quaffed here below. Such is my religious
+faith, though I grieve to confess that neither His Holiness the Pope nor His
+Grace the Archbishop of Canterbury (whom I equally and profoundly revere) will
+assent to its dissemination.”</p>
+
+<p class="entry"><span class="def">spooker</span>, <span class="pos">n.</span> A
+writer whose imagination concerns itself with supernatural phenomena,
+especially in the doings of spooks. One of the most illustrious spookers of our
+time is Mr. William D. Howells, who introduces a well-credentialed reader to as
+respectable and mannerly a company of spooks as one could wish to meet. To the
+terror that invests the chairman of a district school board, the Howells ghost
+adds something of the mystery enveloping a farmer from another township.</p>
+
+<p class="entry"><span class="def">story</span>, <span class="pos">n.</span> A
+narrative, commonly untrue. The truth of the stories here following has,
+however, not been successfully impeached.</p>
+
+<p>One evening Mr. Rudolph Block, of New York, found himself seated at dinner alongside Mr.
+Percival Pollard, the distinguished critic.</p>
+
+<p>“Mr. Pollard,” said he, “my book, <i>The Biography of a Dead
+Cow</i>, is published anonymously, but you can hardly be ignorant of its
+authorship. Yet in reviewing it you speak of it as the work of the Idiot of the
+Century. Do you think that fair criticism?”</p>
+
+<p>“I am very sorry, sir,” replied the critic, amiably, “but it did not occur to me that you really
+might not wish the public to know who wrote it.”</p>
+
+<p>Mr. W.C. Morrow, who used to live in San Jose, California, was addicted to writing ghost stories
+which made the reader feel as if a stream of lizards, fresh from the ice, were
+streaking it up his back and hiding in his hair. San Jose was at that time
+believed to be haunted by the visible spirit of a noted bandit named Vasquez,
+who had been hanged there. The town was not very well lighted, and it is
+putting it mildly to say that San Jose was reluctant to be out o’ nights. One
+particularly dark night two gentlemen were abroad in the loneliest spot within
+the city limits, talking loudly to keep up their courage, when they came upon
+Mr. J.J. Owen, a well-known journalist.</p>
+
+<p>“Why, Owen,” said one, “what brings you here on such a night as this? You told me that this is
+one of Vasquez’ favorite haunts! And you are a believer. Aren’t you afraid to be out?”</p>
+
+<p>“My dear fellow,” the journalist replied with a drear autumnal cadence in his speech, like the
+moan of a leaf-laden wind, “I am afraid to be in. I have one of Will Morrow’s
+stories in my pocket and I don’t dare to go where there is light enough to read it.”</p>
+
+<p>Rear-Admiral Schley and Representative Charles F. Joy were standing near the Peace Monument,
+in Washington, discussing the question, Is success a failure? Mr. Joy suddenly
+broke off in the middle of an eloquent sentence, exclaiming: “Hello! I’ve heard
+that band before. Santlemann’s, I think.”</p>
+
+<p>“I don’t hear any band,” said Schley.</p>
+
+<p>“Come to think, I don’t either,” said Joy; “but I see General </p>
+
+<p>Miles coming down the avenue, and that pageant always affects me in the same way as a brass band. One has to
+scrutinize one’s impressions pretty closely, or one will mistake their origin.”</p>
+
+<p>While the Admiral was digesting this hasty meal of philosophy General Miles passed in review, a
+spectacle of impressive dignity. When the tail of the seeming procession had
+passed and the two observers had recovered from the transient blindness caused
+by its effulgence—</p>
+
+<p>“He seems to be enjoying himself,” said the Admiral.</p>
+
+<p>“There is nothing,” assented Joy, thoughtfully, “that he enjoys one-half so well.”</p>
+
+<p>The illustrious statesman, Champ Clark, once lived about a mile from the village of Jebigue, in
+Missouri. One day he rode into town on a favorite mule, and, hitching the beast
+on the sunny side of a street, in front of a saloon, he went inside in his
+character of teetotaler, to apprise the barkeeper that wine is a mocker. It was
+a dreadfully hot day. Pretty soon a neighbor came in and seeing Clark, said:</p>
+
+<p>“Champ, it is not right to leave that mule out there in the sun. </p>
+
+<p>He’ll roast, sure!—he was smoking as I passed him.”</p>
+
+<p>“O, he’s all right,” said Clark, lightly; “he’s an inveterate smoker.”</p>
+
+<p>The neighbor took a lemonade, but shook his head and repeated that it was not right.</p>
+
+<p>He was a conspirator. There had been a fire the night before: a stable just around the
+corner had burned and a number of horses had put on their immortality, among
+them a young colt, which was roasted to a rich nut-brown. Some of the boys had
+turned Mr. Clark’s mule loose and substituted the mortal part of the colt. Presently
+another man entered the saloon.</p>
+
+<p>“For mercy’s sake!” he said, taking it with sugar, “do remove that mule, barkeeper: it smells.”</p>
+
+<p>“Yes,” interposed Clark, “that animal has the best nose in Missouri. But if he doesn’t mind, you
+shouldn’t.”</p>
+
+<p>In the course of human events Mr. Clark went out, and there, apparently, lay the incinerated and
+shrunken remains of his charger. The boys idd not have any fun out of Mr.
+Clarke, who looked at the body and, with the non-committal expression to which
+he owes so much of his political preferment, went away. But walking home late
+that night he saw his mule standing silent and solemn by the wayside in the
+misty moonlight. Mentioning the name of Helen Blazes with uncommon emphasis,
+Mr. Clark took the back track as hard as ever he could hook it, and passed the
+night in town.</p>
+
+<p>General H.H. Wotherspoon, president of the Army War College, has a pet rib-nosed baboon, an
+animal of uncommon intelligence but imperfectly beautiful. Returning to his
+apartment one evening, the General was surprised and pained to find Adam (for
+so the creature is named, the general being a Darwinian) sitting up for him and
+wearing his master’s best uniform coat, epaulettes and all.</p>
+
+<p>“You confounded remote ancestor!” thundered the great strategist, “what do you mean by being
+out of bed after naps?—and with my coat on!”</p>
+
+<p>Adam rose and with a reproachful look got down on all fours in the manner of his kind and,
+scuffling across the room to a table, returned with a visiting-card: General
+Barry had called and, judging by an empty champagne bottle and several
+cigar-stumps, had been hospitably entertained while waiting. The general
+apologized to his faithful progenitor and retired. The next day he met General
+Barry, who said:</p>
+
+<p>“Spoon, old man, when leaving you last evening I forgot to ask you about those excellent cigars.
+Where did you get them?”</p>
+
+<p>General Wotherspoon did not deign to reply, but walked away.</p>
+
+<p>“Pardon me, please,” said Barry, moving after him; “I was joking of course. Why, I knew it was not
+you before I had been in the room fifteen minutes.”</p>
+
+<p class="entry"><span class="def">success</span>, <span class="pos">n.</span> The
+one unpardonable sin against one’s fellows. In literature, and particularly in
+poetry, the elements of success are exceedingly simple, and are admirably set
+forth in the following lines by the reverend Father Gassalasca Jape, entitled,
+for some mysterious reason, “John A. Joyce.”</p>
+
+<div class="poem">
+<p class="poetry">The bard who would prosper must carry a book,<br />
+Do his thinking in prose and wear<br />
+A crimson cravat, a far-away look<br />
+And a head of hexameter hair.<br />
+Be thin in your thought and your body’ll be fat;<br />
+If you wear your hair long you needn’t your hat.</p>
+</div>
+
+<p class="entry"><span class="def">suffrage</span>, <span class="pos">n.</span> Expression
+of opinion by means of a ballot. The right of suffrage (which is held to be
+both a privilege and a duty) means, as commonly interpreted, the right to vote
+for the man of another man’s choice, and is highly prized. Refusal to do so has
+the bad name of “incivism.” The incivilian, however, cannot be properly
+arraigned for his crime, for there is no legitimate accuser. If the accuser is
+himself guilty he has no standing in the court of opinion; if not, he profits
+by the crime, for A’s abstention from voting gives greater weight to the vote
+of B. By female suffrage is meant the right of a woman to vote as some man
+tells her to. It is based on female responsibility, which is somewhat limited. The
+woman most eager to jump out of her petticoat to assert her rights is first to
+jump back into it when threatened with a switching for misusing them.</p>
+
+<p class="entry"><span class="def">sycophant</span>, <span class="pos">n.</span> One
+who approaches Greatness on his belly so that he may not be commanded to turn
+and be kicked. He is sometimes an editor.</p>
+
+<div class="poem">
+<p class="poetry">As the lean leech, its victim found, is pleased<br />
+To fix itself upon a part diseased<br />
+Till, its black hide distended with bad blood,<br />
+It drops to die of surfeit in the mud,<br />
+So the base sycophant with joy descries<br />
+His neighbor’s weak spot and his mouth applies,<br />
+Gorges and prospers like the leech, although,
+Unlike that reptile, he will not let go.<br />
+Gelasma, if it paid you to devote<br />
+Your talent to the service of a goat,<br />
+Showing by forceful logic that its beard<br />
+Is more than Aaron’s fit to be revered;<br />
+If to the task of honoring its smell<br />
+Profit had prompted you, and love as well,<br />
+The world would benefit at last by you<br />
+And wealthy malefactors weep anew—<br />
+Your favor for a moment’s space denied<br />
+And to the nobler object turned aside.<br />
+Is’t not enough that thrifty millionaires<br />
+Who loot in freight and spoliate in fares,<br />
+Or, cursed with consciences that bid them fly<br />
+To safer villainies of darker dye,<br />
+Forswearing robbery and fain, instead,<br />
+To steal (they call it “cornering”) our bread<br />
+May see you groveling their boots to lick<br />
+And begging for the favor of a kick?<br />
+Still must you follow to the bitter end<br />
+Your sycophantic disposition’s trend,<br />
+And in your eagerness to please the rich<br />
+Hunt hungry sinners to their final ditch?<br />
+In Morgan’s praise you smite the sounding wire,
+And sing hosannas to great Havemeyher!<br />
+What’s Satan done that him you should eschew?<br />
+He too is reeking rich—deducting <i>you</i>.</p>
+</div>
+
+<p class="entry"><span class="def">syllogism</span>, <span class="pos">n.</span> A
+logical formula consisting of a major and a minor assumption and an
+inconsequent. (See logic.)</p>
+
+<p class="entry"><span class="def">sylph</span>, <span class="pos">n.</span> An
+immaterial but visible being that inhabited the air when the air was an element
+and before it was fatally polluted with factory smoke, sewer gas and similar
+products of civilization. Sylphs were allied to gnomes, nymphs and salamanders,
+which dwelt, respectively, in earth, water and fire, all now insalubrious. Sylphs,
+like fowls of the air, were male and female, to no purpose, apparently, for if
+they had progeny they must have nested in accessible places, none of the chicks
+having ever been seen.</p>
+
+<p class="entry"><span class="def">symbol</span>, <span class="pos">n.</span> Something
+that is supposed to typify or stand for something else. Many symbols are mere
+“survivals”—things which having no longer any utility continue to exist because
+we have inherited the tendency to make them; as funereal urns carved on
+memorial monuments. They were once real urns holding the ashes of the dead. We
+cannot stop making them, but we can give them a name that conceals our helplessness.</p>
+
+<p class="entry"><span class="def">symbolic</span>, <span class="pos">adj.</span> Pertaining
+to symbols and the use and interpretation of symbols.</p>
+
+<div class="poem">
+<p class="poetry">They say ‘tis conscience feels compunction;<br />
+I hold that that’s the stomach’s function,<br />
+For of the sinner I have noted<br />
+<br />That when he’s sinned he’s somewhat bloated,<br />
+Or ill some other ghastly fashion<br />
+Within that bowel of compassion.<br />
+True, I believe the only sinner<br />
+Is he that eats a shabby dinner.<br />
+You know how Adam with good reason,<br />
+For eating apples out of season,<br />
+Was “cursed.” But that is all symbolic:<br />
+The truth is, Adam had the colic.</p>
+<p class="poetry">G. J.</p>
+</div>
+
+</body>
+</html>
\ No newline at end of file
--- /dev/null
+++ b/lib/ebooks/devils/S.html.i
@@ -1,0 +1,64 @@
+30 pages
+size 400 552
+length 44914
+396 2 10 body html
+0
+1760 2 37 body html
+39
+3547 2 67 body html
+39
+3773 2 71 body html
+523
+3773 2 71 body html
+1063
+3773 2 71 body html
+1603
+7045 2 136 body html
+73
+8967 2 165 body html
+0
+10281 2 191 body html
+90
+11355 2 210 body html
+360
+13065 2 239 body html
+172
+15249 2 282 body html
+0
+16848 2 310 body html
+0
+18464 2 342 body html
+36
+19444 2 368 body html
+175
+21497 2 397 body html
+187
+23557 2 437 body html
+90
+24748 2 461 body html
+263
+24748 2 461 body html
+806
+27777 2 536 body html
+70
+29053 2 566 body html
+121
+30698 2 591 body html
+170
+33246 2 628 body html
+34
+34990 2 656 body html
+0
+36077 2 677 body html
+119
+37436 2 702 body html
+153
+39361 2 735 body html
+0
+41224 2 767 body html
+19
+41224 2 767 body html
+563
+44294 2 827 body html
+138
+soul 20
--- /dev/null
+++ b/lib/ebooks/devils/T.html
@@ -1,0 +1,397 @@
+<?xml version="1.0"?>
+<!DOCTYPE package PUBLIC "+//ISBN 0-9673008-1-9//DTD OEB 1.0 Package//EN"
+ "http://openebook.org/dtds/oeb-1.0/oebdoc1.dtd">
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/x-oeb1-document; charset=utf-8" />
+<link rel="stylesheet" type="text/x-oeb1-css" href="devil.css" />
+<title>The Devil’s Dictionary: T</title>
+</head>
+<body lang="en-US">
+
+
+
+<h1>T</h1>
+
+<p class="entry">T, the twentieth letter of the English alphabet, was by the Greeks absurdly
+called <i>tau</i>. In the alphabet whence ours comes it
+had the form of the rude corkscrew of the period, and when it stood alone
+(which was more than the Phoenicians could always do) signified <i>Tallegal</i>, translated by the learned Dr.
+Brownrigg, “tanglefoot.”</p>
+
+<p class="entry"><span class="def">Table D’Hote</span>, <span class="pos">n.</span> A
+caterer’s thrifty concession to the universal passion for irresponsibility.</p>
+
+<div class="poem">
+<p class="poetry">Old Paunchinello, freshly wed,<br />
+Took Madam P. to table,<br />
+And there deliriously fed<br />
+As fast as he was able.<br />
+“I dote upon good grub,” he cried,<br />
+Intent upon its throatage.<br />
+“Ah, yes,” said the neglected bride,<br />
+“You’re in your <i>table d’hotage</i>.”</p>
+
+<p class="citeauth">Associated Poets</p>
+</div>
+
+<p class="entry"><span class="def">tail</span>, <span class="pos">n.</span> The part
+of an animal’s spine that has transcended its natural limitations to set up an
+independent existence in a world of its own. Excepting in its foetal state, Man
+is without a tail, a privation of which he attests an hereditary and uneasy
+consciousness by the coat-skirt of the male and the train of the female, and by
+a marked tendency to ornament that part of his attire where the tail should be,
+and indubitably once was. This tendency is most observable in the female of the
+species, in whom the ancestral sense is strong and persistent. The tailed men
+described by Lord Monboddo are now generally regarded as a product of an
+imagination unusually susceptible to influences generated in the golden age of
+our pithecan past.</p>
+
+<p class="entry"><span class="def">take</span>, <span class="pos">v.t.</span> To
+acquire, frequently by force but preferably by stealth.</p>
+
+<p class="entry"><span class="def">talk</span>, <span class="pos">v.t.</span> To
+commit an indiscretion without temptation, from an impulse without purpose.</p>
+
+<p class="entry"><span class="def">tariff</span>, <span class="pos">n.</span> A scale
+of taxes on imports, designed to protect the domestic producer against the
+greed of his consumer.</p>
+
+<div class="poem">
+<p class="poetry">The Enemy of Human Souls<br />
+Sat grieving at the cost of coals;<br />
+For Hell had been annexed of late,<br />
+And was a sovereign Southern State.</p>
+
+<p class="poetry">“It were no more than right,” said he,<br />
+“That I should get my fuel free.<br />
+The duty, neither just nor wise,<br />
+Compels me to economize—<br />
+Whereby my broilers, every one,<br />
+Are execrably underdone.<br />
+What would they have?—although I yearn<br />
+To do them nicely to a turn,<br />
+I can’t afford an honest heat.<br />
+This tariff makes even devils cheat!<br />
+I’m ruined, and my humble trade<br />
+All rascals may at will invade:<br />
+Beneath my nose the public press<br />
+Outdoes me in sulphureousness;<br />
+The bar ingeniously applies<br />
+To my undoing my own lies;<br />
+My medicines the doctors use<br />
+(Albeit vainly) to refuse<br />
+To me my fair and rightful prey<br />
+And keep their own in shape to pay;<br />
+The preachers by example teach<br />
+What, scorning to perform, I teach;<br />
+And statesmen, aping me, all make<br />
+More promises than they can break.<br />
+Against such competition I<br />
+Lift up a disregarded cry.<br />
+Since all ignore my just complaint,<br />
+By Hokey-Pokey! I’ll turn saint!”<br />
+Now, the Republicans, who all<br />
+Are saints, began at once to bawl<br />
+Against <i>his</i> competition; so<br />
+There was a devil of a go!<br />
+They locked horns with him, tete-a-tete<br />
+In acrimonious debate,<br />
+Till Democrats, forlorn and lone,<br />
+Had hopes of coming by their own.<br />
+That evil to avert, in haste<br />
+The two belligerents embraced;<br />
+But since ‘twere wicked to relax<br />
+A tittle of the Sacred Tax,<br />
+‘Twas finally agreed to grant<br />
+The bold Insurgent-protestant<br />
+A bounty on each soul that fell<br />
+Into his ineffectual Hell.</p>
+<p class="citeauth">Edam Smith</p>
+</div>
+
+<p class="entry"><span class="def">technicality</span>, <span class="pos">n.</span> In
+an English court a man named Home was tried for slander in having accused his
+neighbor of murder. His exact words were: “Sir Thomas Holt hath taken a cleaver
+and stricken his cook upon the head, so that one side of the head fell upon one
+shoulder and the other side upon the other shoulder.” The defendant was
+acquitted by instruction of the court, the learned judges holding that the
+words did not charge murder, for they did not affirm the death of the cook,
+that being only an inference.</p>
+
+<p class="entry"><span class="def">tedium</span>, <span class="pos">n.</span> Ennui,
+the state or condition of one that is bored. Many fanciful derivations of the
+word have been affirmed, but so high an authority as Father Jape says that it
+comes from a very obvious source—the first words of the ancient Latin hymn <i>Te
+Deum Laudamus</i>. In this apparently natural derivation there is something that
+saddens.</p>
+
+<p class="entry"><span class="def">teetotaler</span>, <span class="pos">n.</span> One
+who abstains from strong drink, sometimes totally, sometimes tolerably totally.</p>
+
+<p class="entry"><span class="def">telephone</span>, <span class="pos">n.</span> An
+invention of the devil which abrogates some of the advantages of making a
+disagreeable person keep his distance.</p>
+
+<p class="entry"><span class="def">telescope</span>, <span class="pos">n.</span> A
+device having a relation to the eye similar to that of the telephone to the
+ear, enabling distant objects to plague us with a multitude of needless
+details. Luckily it is unprovided with a bell summoning us to the sacrifice.</p>
+
+<p class="entry"><span class="def">tenacity</span>, <span class="pos">n.</span> A
+certain quality of the human hand in its relation to the coin of the realm. It
+attains its highest development in the hand of authority and is considered a
+serviceable equipment for a career in politics. The following illustrative
+lines were written of a Californian gentleman in high political preferment, who
+has passed to his accounting:</p>
+
+<div class="poem">
+<p class="poetry">Of such tenacity his grip<br />
+That nothing from his hand can slip.<br />
+Well-buttered eels you may o’erwhelm<br />
+In tubs of liquid slippery-elm<br />
+In vain—from his detaining pinch<br />
+They cannot struggle half an inch!<br />
+‘Tis lucky that he so is planned<br />
+That breath he draws not with his hand,<br />
+For if he did, so great his greed<br />
+He’d draw his last with eager speed.<br />
+Nay, that were well, you say. Not so<br />
+He’d draw but never let it go!</p>
+</div>
+
+<p class="entry"><span class="def">theosophy</span>, <span class="pos">n.</span> An
+ancient faith having all the certitude of religion and all the mystery of
+science. The modern Theosophist holds, with the Buddhists, that we live an
+incalculable number of times on this earth, in as many several bodies, because
+one life is not long enough for our complete spiritual development; that is, a
+single lifetime does not suffice for us to become as wise and good as we choose
+to wish to become. To be absolutely wise and good—that is perfection; and the
+Theosophist is so keen-sighted as to have observed that everything desirous of
+improvement eventually attains perfection. Less competent observers are
+disposed to except cats, which seem neither wiser nor better than they were
+last year. The greatest and fattest of recent Theosophists was the late Madame
+Blavatsky, who had no cat.</p>
+
+<p class="entry"><span class="def">tights</span>, <span class="pos">n.</span> An
+habiliment of the stage designed to reinforce the general acclamation of the
+press agent with a particular publicity. Public attention was once somewhat
+diverted from this garment to Miss Lillian Russell’s refusal to wear it, and
+many were the conjectures as to her motive, the guess of Miss Pauline Hall
+showing a high order of ingenuity and sustained reflection. It was Miss Hall’s
+belief that nature had not endowed Miss Russell with beautiful legs. This
+theory was impossible of acceptance by the male understanding, but the
+conception of a faulty female leg was of so prodigious originality as to rank
+among the most brilliant feats of philosophical speculation! It is strange that
+in all the controversy regarding Miss Russell’s aversion to tights no one seems
+to have thought to ascribe it to what was known among the ancients as
+“modesty.” The nature of that sentiment is now imperfectly understood, and
+possibly incapable of exposition with the vocabulary that remains to us. The
+study of lost arts has, however, been recently revived and some of the arts
+themselves recovered. This is an epoch of <i>renaissances</i>,
+and there is ground for hope that the primitive “blush” may be dragged from its
+hiding-place amongst the tombs of antiquity and hissed on to the stage.</p>
+
+<p class="entry"><span class="def">tomb</span>, <span class="pos">n.</span> The House
+of Indifference. Tombs are now by common consent invested with a certain
+sanctity, but when they have been long tenanted it is considered no sin to
+break them open and rifle them, the famous Egyptologist, Dr. Huggyns,
+explaining that a tomb may be innocently “glened” as soon as its occupant is
+done “smellynge,” the soul being then all exhaled. This reasonable view is now
+generally accepted by archaeologists, whereby the noble science of Curiosity
+has been greatly dignified.</p>
+
+<p class="entry"><span class="def">tope</span>, <span class="pos">v.</span> To tipple,
+booze, swill, soak, guzzle, lush, bib, or swig. In the individual, toping is
+regarded with disesteem, but toping nations are in the forefront of
+civilization and power. When pitted against the hard-drinking Christians the
+absemious Mahometans go down like grass before the scythe. In India one hundred
+thousand beef-eating and brandy-and-soda guzzling Britons hold in subjection
+two hundred and fifty million vegetarian abstainers of the same Aryan race. With
+what an easy grace the whisky-loving American pushed the temperate Spaniard out
+of his possessions! From the time when the Berserkers ravaged all the coasts of
+western Europe and lay drunk in every conquered port it has been the same way: everywhere
+the nations that drink too much are observed to fight rather well and not too
+righteously. Wherefore the estimable old ladies who abolished the canteen from
+the American army may justly boast of having materially augmented the nation’s
+military power.</p>
+
+<p class="entry"><span class="def">tortoise</span>, <span class="pos">n.</span> A
+creature thoughtfully created to supply occasion for the following lines by the
+illustrious Ambat Delaso:</p>
+
+<div class="poem">
+<p class="poetry">TO MY PET TORTOISE</p>
+
+<p class="poetry">My friend, you are not graceful—not at all;<br />
+Your gait’s between a stagger and a sprawl.<br />
+Nor are you beautiful: your head’s a snake’s<br />
+To look at, and I do not doubt it aches.<br />
+As to your feet, they’d make an angel weep.<br />
+‘Tis true you take them in whene’er you sleep.<br />
+No, you’re not pretty, but you have, I own,<br />
+A certain firmness—mostly you’re [sic] backbone.<br />
+Firmness and strength (you have a giant’s thews)<br />
+Are virtues that the great know how to use—<br />
+I wish that they did not; yet, on the whole,<br />
+You lack—excuse my mentioning it—Soul.<br />
+So, to be candid, unreserved and true,<br />
+I’d rather you were I than I were you.</p>
+
+<p class="poetry">Perhaps, however, in a time to be,<br />
+When Man’s extinct, a better world may see<br />
+Your progeny in power and control,<br />
+Due to the genesis and growth of Soul.</p>
+
+<p class="poetry">So I salute you as a reptile grand<br />
+Predestined to regenerate the land.</p>
+
+<p class="poetry">Father of Possibilities, O deign<br />
+To accept the homage of a dying reign!<br />
+In the far region of the unforeknown<br />
+I dream a tortoise upon every throne.</p>
+
+<p class="poetry">I see an Emperor his head withdraw<br />
+Into his carapace for fear of Law;</p>
+
+<p class="poetry">A King who carries something else than fat,<br />
+Howe’er acceptably he carries that;<br />
+A President not strenuously bent<br />
+On punishment of audible dissent—</p>
+
+<p class="poetry">Who never shot (it were a vain attack)<br />
+An armed or unarmed tortoise in the back;<br />
+Subject and citizens that feel no need<br />
+To make the March of Mind a wild stampede;<br />
+All progress slow, contemplative, sedate,<br />
+And “Take your time” the word, in Church and State.<br />
+O Tortoise, ‘tis a happy, happy dream,<br />
+My glorious testudinous regime!</p>
+
+<p class="poetry">I wish in Eden you’d brought this about<br />
+By slouching in and chasing Adam out.</p>
+</div>
+
+<p class="entry"><span class="def">tree</span>, <span class="pos">n.</span> A tall
+vegetable intended by nature to serve as a penal apparatus, though through a
+miscarriage of justice most trees bear only a negligible fruit, or none at all.
+When naturally fruited, the tree is a beneficient agency of civilization and an
+important factor in public morals. In the stern West and the sensitive South
+its fruit (white and black respectively) though not eaten, is agreeable to the
+public taste and, though not exported, profitable to the general welfare. That
+the legitimate relation of the tree to justice was no discovery of Judge Lynch
+(who, indeed, conceded it no primacy over the lamp-post and the bridge-girder)
+is made plain by the following passage from Morryster, who antedated him by two
+centuries:</p>
+
+<p>While in yt londe
+I was carried to see ye Ghogo tree, whereof I had hearde moch talk; but sayynge
+yt I saw naught remarkabyll in it, ye hed manne of ye villayge where it grewe
+made answer as followeth:</p>
+
+<p>“Ye tree is not nowe in fruite, but in his seasonne you shall see dependynge fr. his braunches
+all soch as have affroynted ye King his Majesty.”</p>
+
+<p>And I was furder tolde yt ye worde “Ghogo” sygnifyeth in yr tong ye same as “rapscal” in our
+owne.</p>
+
+<p><i>Trauvells in ye Easte</i></p>
+
+<p class="entry"><span class="def">trial</span>, <span class="pos">n.</span> A formal
+inquiry designed to prove and put upon record the blameless characters of
+judges, advocates and jurors. In order to effect this purpose it is necessary
+to supply a contrast in the person of one who is called the defendant, the
+prisoner, or the accused. If the contrast is made sufficiently clear this
+person is made to undergo such an affliction as will give the virtuous
+gentlemen a comfortable sense of their immunity, added to that of their worth. In
+our day the accused is usually a human being, or a socialist, but in mediaeval
+times, animals, fishes, reptiles and insects were brought to trial. A beast
+that had taken human life, or practiced sorcery, was duly arrested, tried and,
+if condemned, put to death by the public executioner. Insects ravaging grain
+fields, orchards or vineyards were cited to appeal by counsel before a civil
+tribunal, and after testimony, argument and condemnation, if they continued <i>in
+contumaciam</i> the matter was taken to a high ecclesiastical court, where they
+were solemnly excommunicated and anathematized. In a street of Toledo, some
+pigs that had wickedly run between the viceroy’s legs, upsetting him, were arrested
+on a warrant, tried and punished. In Naples and ass was condemned to be burned
+at the stake, but the sentence appears not to have been executed. D’Addosio
+relates from the court records many trials of pigs, bulls, horses, cocks, dogs,
+goats, etc., greatly, it is believed, to the betterment of their conduct and
+morals. In 1451 a suit was brought against the leeches infesting some ponds
+about Berne, and the Bishop of Lausanne, instructed by the faculty of
+Heidelberg University, directed that some of “the aquatic worms” be brought
+before the local magistracy. This was done and the leeches, both present and
+absent, were ordered to leave the places that they had infested within three
+days on pain of incurring “the malediction of God.” In the voluminous records
+of this <i>cause celebre</i> nothing is
+found to show whether the offenders braved the punishment, or departed
+forthwith out of that inhospitable jurisdiction.</p>
+
+<p class="entry"><span class="def">trichinosis</span>, <span class="pos">n.</span> The
+pig’s reply to proponents of porcophagy.</p>
+
+<p class="indentpara">Moses Mendlessohn
+having fallen ill sent for a Christian physician, who at once diagnosed the
+philosopher’s disorder as trichinosis, but tactfully gave it another name. “You
+need and immediate change of diet,” he said; “you must eat six ounces of pork
+every other day.”</p>
+
+<p class="dialog">“Pork?” shrieked the patient—“pork? Nothing shall induce me to touch it!”</p>
+
+<p class="dialog">“Do you mean that?” the doctor gravely asked.</p>
+
+<p class="dialog">“I swear it!”</p>
+
+<p class="dialog">“Good!—then I will undertake to cure you.”</p>
+
+<p class="entry"><span class="def">Trinity</span>, <span class="pos">n.</span> In the
+multiplex theism of certain Christian churches, three entirely distinct deities
+consistent with only one. Subordinate deities of the polytheistic faith, such
+as devils and angels, are not dowered with the power of combination, and must
+urge individually their clames to adoration and propitiation. The Trinity is
+one of the most sublime mysteries of our holy religion. In rejecting it because
+it is incomprehensible, Unitarians betray their inadequate sense of theological
+fundamentals. In religion we believe only what we do not understand, except in
+the instance of an intelligible doctrine that contradicts an incomprehensible
+one. In that case we believe the former as a part of the latter.</p>
+
+<p class="entry"><span class="def">Troglodyte</span>, <span class="pos">n.</span> Specifically,
+a cave-dweller of the paleolithic period, after the Tree and before the Flat. A
+famous community of troglodytes dwelt with David in the Cave of Adullam. The
+colony consisted of “every one that was in distress, and every one that was in
+debt, and every one that was discontented”—in brief, all the Socialists of
+Judah.</p>
+
+<p class="entry"><span class="def">truce</span>, <span class="pos">n.</span> Friendship.</p>
+
+<p id="truth" class="entry"><span class="def">truth</span>, <span class="pos">n.</span> An
+ingenious compound of desirability and appearance. Discovery of truth is the
+sole purpose of philosophy, which is the most ancient occupation of the human
+mind and has a fair prospect of existing with increasing activity to the end of time.</p>
+
+<p class="entry"><span class="def">truthful</span>, <span class="pos">adj.</span> Dumb
+and illiterate.</p>
+
+<p class="entry"><span class="def">trust</span>, <span class="pos">n.</span> In
+American politics, a large corporation composed in greater part of thrifty
+working men, widows of small means, orphans in the care of guardians and the
+courts, with many similar malefactors and public enemies.</p>
+
+<p class="entry"><span class="def">turkey</span>, <span class="pos">n.</span> A large
+bird whose flesh when eaten on certain religious anniversaries has the peculiar
+property of attesting piety and gratitude. Incidentally, it is pretty good eating.</p>
+
+<p class="entry"><span class="def">twice</span>, <span class="pos">adv.</span> Once
+too often.</p>
+
+<p class="entry"><span class="def">type</span>, <span class="pos">n.</span> Pestilent
+bits of metal suspected of destroying civilization and enlightenment, despite
+their obvious agency in this incomparable dictionary.</p>
+
+<p class="entry"><span class="def">Tzetze (or Tsetse) Fly</span>, <span class="pos">n.</span> An African
+insect (<i>Glossina morsitans</i>) whose bite is commonly
+regarded as nature’s most efficacious remedy for insomnia, though some patients
+prefer that of the American novelist (<i>Mendax interminabilis</i>).</p>
+
+</body>
+</html>
\ No newline at end of file
--- /dev/null
+++ b/lib/ebooks/devils/T.html.i
@@ -1,0 +1,30 @@
+13 pages
+size 400 552
+length 20645
+396 2 10 body html
+0
+1344 2 38 body html
+107
+2653 2 60 body html
+327
+2653 2 60 body html
+873
+6271 2 141 body html
+73
+8124 2 176 body html
+22
+10082 2 204 body html
+39
+11331 2 223 body html
+242
+11331 2 223 body html
+781
+14716 2 298 body html
+0
+14753 2 300 body html
+498
+17685 2 347 body html
+175
+20307 2 391 body html
+56
+truth 11
--- /dev/null
+++ b/lib/ebooks/devils/TitlePage.html
@@ -1,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE html PUBLIC "+//ISBN 0-9673008-1-9//DTD OEB 1.0 Document//EN"
+ "http://openebook.org/dtds/oeb-1.0/oebdoc1.dtd">
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/x-oeb1-document; charset=utf-8" />
+<link rel="stylesheet" type="text/x-oeb1-css" href="devil.css" />
+<title>The Devil’s Dictionary</title>
+</head>
+<body lang="en-us">
+
+<h1 class="title">The Devil’s Dictionary</h1>
+
+<h2 class="title">AMBROSE BIERCE</h2>
+
+<p class="title">Originally published by Neale Publishing Company in 1911.</p>
+
+<p class="title">This version began as a plain ASCII text from Project
+Gutenberg, and was entered by Aloysius of &tSftDotIotE (aloysius@west.darkside.com)</p>
+
+<p class="title">Open eBook formatting and editing was performed July–September, 2000 by
+Peter K. Sheerin (psheerin@petesguide.com), with formatting based on that found in the 1993
+Dover Publications edition.</p>
+</body>
+</html>
\ No newline at end of file
--- /dev/null
+++ b/lib/ebooks/devils/TitlePage.html.i
@@ -1,0 +1,5 @@
+1 pages
+size 400 552
+length 969
+396 2 10 body html
+0
--- /dev/null
+++ b/lib/ebooks/devils/U.html
@@ -1,0 +1,118 @@
+<?xml version="1.0"?>
+<!DOCTYPE package PUBLIC "+//ISBN 0-9673008-1-9//DTD OEB 1.0 Package//EN"
+ "http://openebook.org/dtds/oeb-1.0/oebdoc1.dtd">
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/x-oeb1-document; charset=utf-8" />
+<link rel="stylesheet" type="text/x-oeb1-css" href="devil.css" />
+<title>The Devil’s Dictionary: U</title>
+</head>
+<body lang="en-US">
+
+
+<h1>U</h1>
+
+<p class="entry"><span class="def">ubiquity</span>, <span class="pos">n.</span> The
+gift or power of being in all places at one time, but not in all places at all
+times, which is omnipresence, an attribute of God and the luminiferous ether
+only. This important distinction between ubiquity and omnipresence was not
+clear to the mediaeval Church and there was much bloodshed about it. Certain
+Lutherans, who affirmed the presence everywhere of Christ’s body were known as
+Ubiquitarians. For this error they were doubtless damned, for Christ’s body is
+present only in the eucharist, though that sacrament may be performed in more
+than one place simultaneously. In recent times ubiquity has not always been
+understood—not even by Sir Boyle Roche, for example, who held that a man cannot
+be in two places at once unless he is a bird.</p>
+
+<p class="entry"><span class="def">ugliness</span>, <span class="pos">n.</span> A
+gift of the gods to certain women, entailing virtue without humility.</p>
+
+<p class="entry"><span class="def">ultimatum</span>, <span class="pos">n.</span> In
+diplomacy, a last demand before resorting to concessions.</p>
+
+<p>Having received an ultimatum from Austria, the Turkish Ministry met to consider it.</p>
+
+<p>“O servant of the Prophet,” said the Sheik of the Imperial Chibouk to the Mamoosh of the
+Invincible Army, “how many unconquerable soldiers have we in arms?”</p>
+
+<p>“Upholder of the Faith,” that dignitary replied after examining his memoranda, “they are in
+numbers as the leaves of the forest!”</p>
+
+<p>“And how many impenetrable battleships strike terror to the hearts of all Christian swine?”
+he asked the Imaum of the Ever Victorious Navy.</p>
+
+<p>“Uncle of the Full Moon,” was the reply, “deign to know that they are as the waves of the ocean,
+the sands of the desert and the stars of Heaven!”</p>
+
+<p>For eight hours the broad brow of the Sheik of the Imperial Chibouk was corrugated with
+evidences of deep thought: he was calculating the chances of war. Then, “Sons
+of angels,” he said, “the die is cast! I shall suggest to the Ulema of the
+Imperial Ear that he advise inaction. In the name of Allah, the council is adjourned.”</p>
+
+<p class="entry"><span class="def">un-American</span>, <span class="pos">adj.</span> Wicked,
+intolerable, heathenish.</p>
+
+<p class="entry"><span class="def">unction</span>, <span class="pos">n.</span> An
+oiling, or greasing. The rite of extreme unction consists in touching with oil
+consecrated by a bishop several parts of the body of one engaged in dying. Marbury
+relates that after the rite had been administered to a certain wicked English
+nobleman it was discovered that the oil had not been properly consecrated and
+no other could be obtained. When informed of this the sick man said in anger: </p>
+
+<p>“Then I’ll be damned if I die!”</p>
+
+<p>“My son,” said the priest, “this is what we fear.”</p>
+
+<p class="entry"><span class="def">understanding</span>, <span class="pos">n.</span> A
+cerebral secretion that enables one having it to know a house from a horse by
+the roof on the house. Its nature and laws have been exhaustively expounded by
+Locke, who rode a house, and Kant, who lived in a horse.</p>
+
+<div class="poem">
+<p class="poetry">His understanding was so keen<br />
+That all things which he’d felt, heard, seen,<br />
+He could interpret without fail<br />
+If he was in or out of jail.<br />
+He wrote at Inspiration’s call<br />
+Deep disquisitions on them all,<br />
+Then, pent at last in an asylum,<br />
+Performed the service to compile ‘em.<br />
+So great a writer, all men swore,<br />
+They never had not read before.</p>
+<p class="citeauth">Jorrock Wormley</p>
+</div>
+
+<p class="entry"><span class="def">Unitarian</span>, <span class="pos">n.</span> One
+who denies the divinity of a Trinitarian.</p>
+
+<p class="entry"><span class="def">universalist</span>, <span class="pos">n.</span> One
+who forgoes the advantage of a Hell for persons of another faith.</p>
+
+<p class="entry"><span class="def">urbanity</span>, <span class="pos">n.</span> The
+kind of civility that urban observers ascribe to dwellers in all cities but New
+York. Its commonest expression is heard in the words, “I beg your pardon,” and
+it is not consistent with disregard of the rights of others.</p>
+
+<div class="poem">
+<p class="poetry">The owner of a powder mill<br />
+Was musing on a distant hill—<br />
+Something his mind foreboded—<br />
+When from the cloudless sky there fell<br />
+A deviled human kidney! Well,<br />
+The man’s mill had exploded.<br />
+His hat he lifted from his head;<br />
+“I beg your pardon, sir,” he said;<br />
+“I didn’t know ‘twas loaded.”</p>
+<p class="citeauth">Swatkin</p>
+</div>
+
+<p class="entry"><span class="def">usage</span>, <span class="pos">n.</span> The First
+Person of the literary Trinity, the Second and Third being Custom and
+Conventionality. Imbued with a decent reverence for this Holy Triad an
+industrious writer may hope to produce books that will live as long as the fashion.</p>
+
+<p class="entry"><span class="def">uxoriousness</span>, <span class="pos">n.</span> A
+perverted affection that has strayed to one’s own wife.</p>
+
+</body>
+</html>
\ No newline at end of file
--- /dev/null
+++ b/lib/ebooks/devils/U.html.i
@@ -1,0 +1,11 @@
+4 pages
+size 400 552
+length 5657
+396 2 10 body html
+0
+1821 2 38 body html
+34
+3346 2 66 body html
+39
+4742 2 96 body html
+138
--- /dev/null
+++ b/lib/ebooks/devils/V.html
@@ -1,0 +1,57 @@
+<?xml version="1.0"?>
+<!DOCTYPE package PUBLIC "+//ISBN 0-9673008-1-9//DTD OEB 1.0 Package//EN"
+ "http://openebook.org/dtds/oeb-1.0/oebdoc1.dtd">
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/x-oeb1-document; charset=utf-8" />
+<link rel="stylesheet" type="text/x-oeb1-css" href="devil.css" />
+<title>The Devil’s Dictionary: V</title>
+</head>
+<body lang="en-US">
+
+
+<h1>V</h1>
+
+<p class="entry"><span class="def">valor</span>, <span class="pos">n.</span> A
+soldierly compound of vanity, duty and the gambler’s hope.</p>
+
+<p>“Why have you halted?” roared the commander of a division and Chickamauga, who had ordered a
+charge; “move forward, sir, at once.”</p>
+
+<p>“General,” said the commander of the delinquent brigade, “I am persuaded that any further
+display of valor by my troops will bring them into collision with the enemy.”</p>
+
+<p class="entry"><span class="def">vanity</span>, <span class="pos">n.</span> The
+tribute of a fool to the worth of the nearest ass.</p>
+
+<div class="poem">
+<p class="poetry">They say that hens do cackle loudest when<br />
+There’s nothing vital in the eggs they’ve laid;<br />
+And there are hens, professing to have made<br />
+A study of mankind, who say that men<br />
+Whose business ‘tis to drive the tongue or pen<br />
+Make the most clamorous fanfaronade<br />
+O’er their most worthless work; and I’m afraid<br />
+They’re not entirely different from the hen.<br />
+Lo! the drum-major in his coat of gold,<br />
+His blazing breeches and high-towering cap—<br />
+Imperiously pompous, grandly bold,<br />
+Grim, resolute, an awe-inspiring chap!<br />
+Who’d think this gorgeous creature’s only virtue Is that in
+battle he will never hurt you?</p>
+
+<p class="citeauth">Hannibal Hunsiker</p>
+</div>
+
+<p class="entry"><span class="def">virtues</span>, <span class="pos">n.</span>pl. Certain
+abstentions.</p>
+
+<p class="entry"><span class="def">vituperation</span>, <span class="pos">n.</span> Saite,
+as understood by dunces and all such as suffer from an impediment in their wit.</p>
+
+<p class="entry"><span class="def">vote</span>, <span class="pos">n.</span> The
+instrument and symbol of a freeman’s power to make a fool of himself and a
+wreck of his country.</p>
+
+</body>
+</html>
\ No newline at end of file
--- /dev/null
+++ b/lib/ebooks/devils/V.html.i
@@ -1,0 +1,7 @@
+2 pages
+size 400 552
+length 2289
+396 2 10 body html
+0
+1025 2 27 body html
+240
--- /dev/null
+++ b/lib/ebooks/devils/W.html
@@ -1,0 +1,275 @@
+<?xml version="1.0"?>
+<!DOCTYPE package PUBLIC "+//ISBN 0-9673008-1-9//DTD OEB 1.0 Package//EN"
+ "http://openebook.org/dtds/oeb-1.0/oebdoc1.dtd">
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/x-oeb1-document; charset=utf-8" />
+<link rel="stylesheet" type="text/x-oeb1-css" href="devil.css" />
+<title>The Devil’s Dictionary: W</title>
+</head>
+<body lang="en-US">
+
+
+<h1>W</h1>
+
+<p class="firstpara">W (double U) has,
+of all the letters in our alphabet, the only cumbrous name, the names of the
+others being monosyllabic. This advantage of the Roman alphabet over the Grecian
+is the more valued after audibly spelling out some simple Greek word, like <i>epixoriambikos</i>. Still, it is now thought
+by the learned that other agencies than the difference of the two alphabets may
+have been concerned in the decline of “the glory that was Greece” and the rise
+of “the grandeur that was Rome.” There can be no doubt, however, that by
+simplifying the name of W (calling it “wow,” for example) our civilization
+could be, if not promoted, at least better endured.</p>
+
+<p class="entry"><span class="def">Wall Street</span>, <span class="pos">n.</span> A
+symbol for sin for every devil to rebuke. That Wall Street is a den of thieves
+is a belief that serves every unsuccessful thief in place of a hope in Heaven. Even
+the great and good Andrew Carnegie has made his profession of faith in the
+matter.</p>
+
+<div class="poem">
+<p class="poetry">Carnegie the dauntless
+has uttered his call To battle: “The brokers are parasites all!” Carnegie,
+Carnegie, you’ll never prevail;</p>
+
+<p class="poetry">Keep the wind of your slogan to belly your sail, Go back to your isle of perpetual brume,
+Silence your pibroch, doff tartan and plume:</p>
+
+<p class="poetry">Ben Lomond is calling his son from the fray—</p>
+
+<p class="poetry">Fly, fly from the region of Wall Street away! While still you’re possessed of a single baubee (I
+wish it were pledged to endowment of me) ‘Twere wise to retreat from the wars
+of finance Lest its value decline ere your credit advance. For a man ‘twixt a
+king of finance and the sea, Carnegie, Carnegie, your tongue is too free!</p>
+
+<p class="citeauth">Anonymus Bink</p>
+</div>
+
+<p class="entry"><span class="def">war</span>, <span class="pos">n.</span> A by-product of the arts of
+peace. The most menacing political condition is a period of
+international amity. The student of history who has not been taught
+to expect the unexpected may justly boast himself inaccessible to the
+light. “In time of peace prepare for war” has a deeper meaning than
+is commonly discerned; it means, not merely that all things earthly
+have an end—that change is the one immutable and eternal law—but
+that the soil of peace is thickly sown with the seeds of war and
+singularly suited to their germination and growth. It was when Kubla Khan
+had decreed his “stately pleasure dome”—when, that is to say, there
+were peace and fat feasting in Xanadu—that he heard from afar
+Ancestral voices prophesying war.</p>
+
+<p class="indentpara">One of the
+greatest of poets, Coleridge was one of the wisest of men, and it was not for
+nothing that he read us this parable. Let us have a little less of “hands
+across the sea,” and a little more of that elemental distrust that is the
+security of nations. War loves to come like a thief in the night; professions
+of eternal amity provide the night.</p>
+
+<p class="entry"><span class="def">Washingtonian</span>, <span class="pos">n.</span> A
+Potomac tribesman who exchanged the privilege of governing himself for the
+advantage of good government. In justice to him it should be said that he did
+not want to.</p>
+
+<div class="poem">
+<p class="poetry">They took away his vote and gave instead<br />
+The right, when he had earned, to <i>eat</i> his bread.<br />
+In vain—he clamors for his “boss,” pour soul,<br />
+To come again and part him from his roll.</p>
+
+<p class="citeauth">Offenbach Stutz</p>
+</div>
+
+<p class="entry"><span class="def">weaknesses</span>, <span class="pos">n.</span>pl. Certain
+primal powers of Tyrant Woman wherewith she holds dominion over the male of her
+species, binding him to the service of her will and paralyzing his rebellious
+energies.</p>
+
+<p class="entry"><span class="def">weather</span>, <span class="pos">n.</span> The
+climate of the hour. A permanent topic of conversation among persons whom it
+does not interest, but who have inherited the tendency to chatter about it from
+naked arboreal ancestors whom it keenly concerned. The setting up official
+weather bureaus and their maintenance in mendacity prove that even governments
+are accessible to suasion by the rude forefathers of the jungle.</p>
+
+<div class="poem">
+<p class="poetry">Once I dipt into
+the future far as human eye could see, And I saw the Chief Forecaster, dead as
+any one can be—</p>
+
+<p class="poetry">Dead and damned
+and shut in Hades as a liar from his birth, With a record of unreason seldom
+paralleled on earth. While I looked he reared him solemnly, that incadescent
+youth, From the coals that he’d preferred to the advantages of truth. He cast
+his eyes about him and above him; then he wrote On a slab of thin asbestos what
+I venture here to quote—</p>
+
+<p class="poetry">For I read it in
+the rose-light of the everlasting glow:</p>
+
+<p class="poetry">“Cloudy; variable
+winds, with local showers; cooler; snow.”</p>
+
+<p class="citeauth">Halcyon Jones</p>
+</div>
+
+<p class="entry"><span class="def">wedding</span>, <span class="pos">n.</span> A
+ceremony at which two persons undertake to become one, one undertakes to become
+nothing, and nothing undertakes to become supportable.</p>
+
+<p class="entry"><span class="def">werewolf</span>, <span class="pos">n.</span> A
+wolf that was once, or is sometimes, a man. All werewolves are of evil
+disposition, having assumed a bestial form to gratify a beastial appetite, but
+some, transformed by sorcery, are as humane and is consistent with an acquired
+taste for human flesh.</p>
+
+<p>Some Bavarian peasants having caught a wolf one evening, tied it to a post by the tail and
+went to bed. The next morning nothing was there! Greatly perplexed, they
+consulted the local priest, who told them that their captive was undoubtedly a
+werewolf and had resumed its human for during the night. “The next time that
+you take a wolf,” the good man said, “see that you chain it by the leg, and in
+the morning you will find a Lutheran.”</p>
+
+<p class="entry"><span class="def">Whangdepootenawah,</span> <span class="pos">n.</span> In the
+Ojibwa tongue, disaster; an unexpected affliction that strikes hard.</p>
+
+<div class="poem">
+<p class="poetry">Should you ask me whence this laughter,</p>
+<p class="poetry">Whence this audible big-smiling,</p>
+<p class="poetry">With its labial extension,</p>
+<p class="poetry">With its maxillar distortion</p>
+<p class="poetry">And its diaphragmic rhythmus</p>
+<p class="poetry">Like the billowing of an ocean,</p>
+<p class="poetry">Like the shaking of a carpet,</p>
+<p class="poetry">I should answer, I should tell you:</p>
+<p class="poetry">From the great deeps of the spirit,</p>
+<p class="poetry">From the unplummeted abysmus</p>
+<p class="poetry">Of the soul this laughter welleth</p>
+<p class="poetry">As the fountain, the gug-guggle,</p>
+<p class="poetry">Like the river from the canon [sic],</p>
+<p class="poetry">To entoken and give warning</p>
+<p class="poetry">That my present mood is sunny.</p>
+<p class="poetry">Should you ask me further question—</p>
+<p class="poetry">Why the great deeps of the spirit,</p>
+<p class="poetry">Why the unplummeted abysmus</p>
+<p class="poetry">Of the soule extrudes this laughter,</p>
+<p class="poetry">This all audible big-smiling,</p>
+<p class="poetry">I should answer, I should tell you</p>
+<p class="poetry">With a white heart, tumpitumpy,</p>
+<p class="poetry">With a true tongue, honest Injun:</p>
+<p class="poetry">William Bryan, he has Caught It,</p>
+<p class="poetry">Caught the Whangdepootenawah!</p>
+<p class="poetry">Is’t the sandhill crane, the shankank,</p>
+<p class="poetry">Standing in the marsh, the kneedeep,</p>
+<p class="poetry">Standing silent in the kneedeep</p>
+<p class="poetry">With his wing-tips crossed behind him</p>
+<p class="poetry">And his neck close-reefed before him,</p>
+<p class="poetry">With his bill, his william, buried</p>
+<p class="poetry">In the down upon his bosom,</p>
+<p class="poetry">With his head retracted inly,</p>
+<p class="poetry">While his shoulders overlook it?</p>
+<p class="poetry">Does the sandhill crane, the shankank,</p>
+<p class="poetry">Shiver grayly in the north wind,</p>
+<p class="poetry">Wishing he had died when little,</p>
+<p class="poetry">As the sparrow, the chipchip, does?</p>
+<p class="poetry">No ‘tis not the Shankank standing,</p>
+<p class="poetry">Standing in the gray and dismal</p>
+<p class="poetry">Marsh, the gray and dismal kneedeep.</p>
+<p class="poetry">No, ‘tis peerless William Bryan</p>
+<p class="poetry">Realizing that he’s Caught It,</p>
+<p class="poetry">Caught the Whangdepootenawah!</p>
+</div>
+
+<p class="entry"><span class="def">wheat</span>, <span class="pos">n.</span> A cereal
+from which a tolerably good whisky can with some difficulty be made, and which
+is used also for bread. The French are said to eat more bread <i>per capita</i> of population than any other
+people, which is natural, for only they know how to make the stuff palatable.</p>
+
+<p class="entry"><span class="def">white</span>, <span class="pos">adj.</span> and n.
+Black.</p>
+
+<p class="entry"><span class="def">widow</span>, <span class="pos">n.</span> A
+pathetic figure that the Christian world has agreed to take humorously,
+although Christ’s tenderness towards widows was one of the most marked features
+of his character.</p>
+
+<p class="entry"><span class="def">wine</span>, <span class="pos">n.</span> Fermented
+grape-juice known to the Women’s Christian Union as “liquor,” sometimes as
+“rum.” Wine, madam, is God’s next best gift to man.</p>
+
+<p class="entry"><span class="def">wit</span>, <span class="pos">n.</span> The salt
+with which the American humorist spoils his intellectual cookery by leaving it
+out.</p>
+
+<p class="entry"><span class="def">witch</span>, <span class="pos">n.</span> (1) Any
+ugly and repulsive old woman, in a wicked league with the devil. (2) A
+beautiful and attractive young woman, in wickedness a league beyond the devil.</p>
+
+<p class="entry"><span class="def">witticism</span>, <span class="pos">n.</span> A
+sharp and clever remark, usually quoted, and seldom noted; what the Philistine
+is pleased to call a “joke.”</p>
+
+<p class="entry"><span class="def">woman</span>, <span class="pos">n.</span></p>
+
+<p>An animal usually
+living in the vicinity of Man, and having a rudimentary susceptibility to
+domestication. It is credited by many of the elder zoologists with a certain
+vestigial docility acquired in a former state of seclusion, but naturalists of
+the postsusananthony period, having no knowledge of the seclusion, deny the
+virtue and declare that such as creation’s dawn beheld, it roareth now. The
+species is the most widely distributed of all beasts of prey, infesting all
+habitable parts of the globe, from Greeland’s spicy mountains to India’s moral
+strand. The popular name (wolfman) is incorrect, for the creature is of the cat
+kind. The woman is lithe and graceful in its movement, especially the American
+variety (<i>felis pugnans</i>), is omnivorous and can be taught not to talk.</p>
+
+<p class="citeauth">Balthasar Pober</p>
+
+<p class="entry"><span class="def">worms’-meat</span>, <span class="pos">n.</span> The
+finished product of which we are the raw material. The contents of the Taj
+Mahal, the Tombeau Napoleon and the Granitarium. Worms’-meat is usually
+outlasted by the structure that houses it, but “this too must pass away.” Probably
+the silliest work in which a human being can engage is construction of a tomb
+for himself. The solemn purpose cannot dignify, but only accentuates by
+contrast the foreknown futility.</p>
+
+<div class="poem">
+<p class="poetry">Ambitious fool! so mad to be a show!<br />
+How profitless the labor you bestow<br />
+Upon a dwelling whose magnificence<br />
+The tenant neither can admire nor know.<br />
+Build deep, build high, build massive as you can,<br />
+The wanton grass-roots will defeat the plan<br />
+By shouldering asunder all the stones<br />
+In what to you would be a moment’s span.<br />
+Time to the dead so all unreckoned flies<br />
+That when your marble is all dust, arise,<br />
+If wakened, stretch your limbs and yawn—<br />
+You’ll think you scarcely can have closed your eyes.<br />
+What though of all man’s works your tomb alone
+Should stand till Time himself be overthrown?<br />
+Would it advantage you to dwell therein<br />
+Forever as a stain upon a stone?</p>
+
+<p class="citeauth">Joel Huck</p>
+</div>
+
+<p class="entry"><span class="def">worship</span>, <span class="pos">n.</span> Homo
+Creator’s testimony to the sound construction and fine finish of Deus Creatus. A
+popular form of abjection, having an element of pride.</p>
+
+<p class="entry"><span class="def">wrath</span>, <span class="pos">n.</span> Anger of
+a superior quality and degree, appropriate to exalted characters and momentous
+occasions; as, “the wrath of God,” “the day of wrath,” etc. Amongst the
+ancients the wrath of kings was deemed sacred, for it could usually command the
+agency of some god for its fit manifestation, as could also that of a priest. The
+Greeks before Troy were so harried by Apollo that they jumped out of the
+frying-pan of the wrath of Cryses into the fire of the wrath of Achilles,
+though Agamemnon, the sole offender, was neither fried nor roasted. A similar
+noted immunity was that of David when he incurred the wrath of Yahveh by
+numbering his people, seventy thousand of whom paid the penalty with their
+lives. God is now Love, and a director of the census performs his work without
+apprehension of disaster.</p>
+
+</body>
+</html>
\ No newline at end of file
--- /dev/null
+++ b/lib/ebooks/devils/W.html.i
@@ -1,0 +1,23 @@
+10 pages
+size 400 552
+length 14117
+396 2 10 body html
+0
+1443 2 31 body html
+159
+3459 2 69 body html
+22
+4746 2 95 body html
+157
+6679 2 136 body html
+72
+6679 2 136 body html
+612
+6679 2 136 body html
+1152
+9503 2 188 body html
+0
+11587 2 226 body html
+0
+13208 2 261 body html
+0
--- /dev/null
+++ b/lib/ebooks/devils/X.html
@@ -1,0 +1,25 @@
+<?xml version="1.0"?>
+<!DOCTYPE package PUBLIC "+//ISBN 0-9673008-1-9//DTD OEB 1.0 Package//EN"
+ "http://openebook.org/dtds/oeb-1.0/oebdoc1.dtd">
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/x-oeb1-document; charset=utf-8" />
+<link rel="stylesheet" type="text/x-oeb1-css" href="devil.css" />
+<title>The Devil’s Dictionary: X</title>
+</head>
+<body lang="en-US">
+
+
+<h1>X</h1>
+
+<p class="firstpara">X in our alphabet being a needless letter has an added invincibility to the attacks of the
+spelling reformers, and like them, will doubtless last as long as the language.
+X is the sacred symbol of ten dollars, and in such words as Xmas, Xn, etc.,
+stands for Christ, not, as is popular supposed, because it represents a cross,
+but because the corresponding letter in the Greek alphabet is the initial of
+his name—<i>Xristos</i>. If it represented a cross it would stand for St. Andrew, who “testified” upon one of
+that shape. In the algebra of psychology x stands for Woman’s mind. Words
+beginning with X are Grecian and will not be defined in this standard English dictionary.</p>
+
+</body>
+</html>
\ No newline at end of file
--- /dev/null
+++ b/lib/ebooks/devils/X.html.i
@@ -1,0 +1,5 @@
+1 pages
+size 400 552
+length 1145
+396 2 10 body html
+0
--- /dev/null
+++ b/lib/ebooks/devils/Y.html
@@ -1,0 +1,72 @@
+<?xml version="1.0"?>
+<!DOCTYPE package PUBLIC "+//ISBN 0-9673008-1-9//DTD OEB 1.0 Package//EN"
+ "http://openebook.org/dtds/oeb-1.0/oebdoc1.dtd">
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/x-oeb1-document; charset=utf-8" />
+<link rel="stylesheet" type="text/x-oeb1-css" href="devil.css" />
+<title>The Devil’s Dictionary: Y</title>
+</head>
+<body lang="en-US">
+
+
+<h1>Y</h1>
+
+<p class="entry"><span class="def">Yankee</span>, <span class="pos">n.</span> In
+Europe, an American. In the Northern States of our Union, a New Englander. In
+the Southern States the word is unknown. (See DAMNYANK.)</p>
+
+<p class="entry"><span class="def">year</span>, <span class="pos">n.</span> A period
+of three hundred and sixty-five disappointments.</p>
+
+<p class="entry"><span class="def">yesterday</span>, <span class="pos">n.</span> The
+infancy of youth, the youth of manhood, the entire past of age.</p>
+
+<div class="poem">
+<p class="poetry">But yesterday I should have thought me blest<br />
+To stand high-pinnacled upon the peak<br />
+Of middle life and look adown the bleak<br />
+And unfamiliar foreslope to the West,<br />
+Where solemn shadows all the land invest<br />
+And stilly voices, half-remembered, speak<br />
+Unfinished prophecy, and witch-fires freak<br />
+The haunted twilight of the Dark of Rest.<br />
+Yea, yesterday my soul was all aflame<br />
+To stay the shadow on the dial’s face<br />
+At manhood’s noonmark! Now, in God His name<br />
+I chide aloud the little interspace<br />
+Disparting me from Certitude, and fain<br />
+Would know the dream and vision ne’er again.</p>
+
+<p class="citeauth">Baruch Arnegriff</p>
+</div>
+
+<p class="indentpara">It is said that in his last illness the poet Arnegriff was attended at different times by seven
+doctors.</p>
+
+<p class="entry"><span class="def">yoke</span>, <span class="pos">n.</span> An
+implement, madam, to whose Latin name, <i>jugum</i>,
+we owe one of the most illuminating words in our language—a word that defines
+the matrimonial situation with precision, point and poignancy. A thousand
+apologies for withholding it.</p>
+
+<p class="entry"><span class="def">youth</span>, <span class="pos">n.</span> The
+Period of Possibility, when Archimedes finds a fulcrum, Cassandra has a
+following and seven cities compete for the honor of endowing a living Homer.</p>
+
+<p class="poetry">Youth is the true Saturnian Reign,<br />
+the Golden Age on earth again,<br />
+when figs are grown on thistles,<br />
+and pigs betailed with whistles and,<br />
+wearing silken bristles,<br />
+live ever in clover,<br />
+and clows fly over,<br />
+delivering milk at every door,<br />
+and Justice never is heard to snore,<br />
+and every assassin is made a ghost<br />
+and, howling, is cast into Baltimost!</p>
+
+<p class="citeauth">Polydore Smith</p>
+
+</body>
+</html>
\ No newline at end of file
--- /dev/null
+++ b/lib/ebooks/devils/Y.html.i
@@ -1,0 +1,7 @@
+2 pages
+size 400 552
+length 2842
+396 2 10 body html
+0
+1669 2 44 body html
+0
--- /dev/null
+++ b/lib/ebooks/devils/Z.html
@@ -1,0 +1,96 @@
+<?xml version="1.0"?>
+<!DOCTYPE package PUBLIC "+//ISBN 0-9673008-1-9//DTD OEB 1.0 Package//EN"
+ "http://openebook.org/dtds/oeb-1.0/oebdoc1.dtd">
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/x-oeb1-document; charset=utf-8" />
+<link rel="stylesheet" type="text/x-oeb1-css" href="devil.css" />
+<title>The Devil’s Dictionary: Z</title>
+</head>
+<body lang="en-US">
+
+
+<h1>Z</h1>
+
+<p class="entry"><span class="def">zany</span>, <span class="pos">n.</span> A popular
+character in old Italian plays, who imitated with ludicrous incompetence the <i>buffone</i>, or clown, and was therefore the
+ape of an ape; for the clown himself imitated the serious characters of the
+play. The zany was progenitor to the specialist in humor, as we to-day have the
+unhappiness to know him. In the zany we see an example of creation; in the
+humorist, of transmission. Another excellent specimen of the modern zany is the
+curate, who apes the rector, who apes the bishop, who apes the archbishop, who
+apes the devil.</p>
+
+<p class="entry"><span class="def">Zanzibari</span>, <span class="pos">n.</span> An
+inhabitant of the Sultanate of Zanzibar, off the eastern coast of Africa. The
+Zanzibaris, a warlike people, are best known in this country through a
+threatening diplomatic incident that occurred a few years ago. The American
+consul at the capital occupied a dwelling that faced the sea, with a sandy
+beach between. Greatly to the scandal of this official’s family, and against
+repeated remonstrances of the official himself, the people of the city
+persisted in using the beach for bathing. One day a woman came down to the edge
+of the water and was stooping to remove her attire (a pair of sandals) when the
+consul, incensed beyond restraint, fired a charge of bird-shot into the most
+conspicuous part of her person. Unfortunately for the existing <i>entente cordiale</i> between two great
+nations, she was the Sultana.</p>
+
+<p class="entry"><span class="def">zeal</span>, <span class="pos">n.</span> A certain
+nervous disorder afflicting the young and inexperienced. A passion that goeth
+before a sprawl.</p>
+
+<div class="poem">
+<p class="poetry">When Zeal sought Gratitude for his reward<br />
+He went away exclaiming: “O my Lord!”<br />
+“What do you want?” the Lord asked, bending down.<br />
+“An ointment for my cracked and bleeding crown.”</p>
+
+<p class="citeauth">Jum Coople</p>
+</div>
+
+<p class="entry"><span class="def">zenith</span>, <span class="pos">n.</span> The
+point in the heavens directly overhead to a man standing or a growing cabbage. A
+man in bed or a cabbage in the pot is not considered as having a zenith, though
+from this view of the matter there was once a considerably dissent among the
+learned, some holding that the posture of the body was immaterial. These were
+called Horizontalists, their opponents, Verticalists. The Horizontalist heresy
+was finally extinguished by Xanobus, the philosopher-king of Abara, a zealous
+Verticalist. Entering an assembly of philosophers who were debating the matter,
+he cast a severed human head at the feet of his opponents and asked them to
+determine its zenith, explaining that its body was hanging by the heels
+outside. Observing that it was the head of their leader, the Horizontalists
+hastened to profess themselves converted to whatever opinion the Crown might be
+pleased to hold, and Horizontalism took its place among <i>fides defuncti</i>.</p>
+
+<p class="entry"><span class="def">Zeus</span>, <span class="pos">n.</span> The chief
+of Grecian gods, adored by the Romans as Jupiter and by the modern Americans as
+God, Gold, Mob and Dog. Some explorers who have touched upon the shores of
+America, and one who professes to have penetrated a considerable distance to
+the interior, have thought that these four names stand for as many distinct
+deities, but in his monumental work on Surviving Faiths, Frumpp insists that
+the natives are monotheists, each having no other god than himself, whom he
+worships under many sacred names.</p>
+
+<p class="entry"><span class="def">zigzag</span>, <span class="pos">v.t.</span> To
+move forward uncertainly, from side to side, as one carrying the white man’s
+burden. (From <i>zed</i>, <i>z</i>, and <i>jag</i>,
+an Icelandic word of unknown meaning.)</p>
+
+<div class="poem">
+<p class="poetry">He zedjagged so uncomen wyde<br />
+Thet non coude pas on eyder syde;<br />
+So, to com saufly thruh, I been<br />
+Constreynet for to doodge betwene.</p>
+
+<p class="citeauth">Munwele</p>
+</div>
+
+<p class="entry"><span class="def">zoology</span>, <span class="pos">n.</span> The science
+and history of the animal kingdom, including its king, the House Fly (<i>Musca
+maledicta</i>). The father of Zoology was Aristotle, as is universally conceded,
+but the name of its mother has not come down to us. Two of the science’s most
+illustrious expounders were Buffon and Oliver Goldsmith, from both of whom we
+learn (<i>L’Histoire generale des animaux</i> and <i>A History of Animated Nature</i>)
+that the domestic cow sheds its horn every two years.</p>
+
+</body>
+</html>
\ No newline at end of file
--- /dev/null
+++ b/lib/ebooks/devils/Z.html.i
@@ -1,0 +1,9 @@
+3 pages
+size 400 552
+length 5097
+396 2 10 body html
+0
+2130 2 41 body html
+19
+3447 2 64 body html
+141
--- /dev/null
+++ b/lib/ebooks/devils/devil.css
@@ -1,0 +1,203 @@
+p {
+ text-align: justify
+ }
+
+p.title {
+ margin-bottom: 1em
+ }
+
+p.entry {
+ margin-top: .33em;
+ text-indent: 0em;
+ margin-bottom: 0em
+ }
+
+p.firstpara {
+ text-indent: 0pt;
+ }
+
+p.indentpara {
+ text-indent: 1em;
+ }
+
+p.poem {
+ font-size: smaller;
+ text-align: left;
+ text-indent: 0em
+ }
+
+p.po {
+ font-size: smaller;
+ text-align: left;
+ margin-bottom: 0;
+ margin-top: 0em;
+ text-indent: 0em
+ }
+
+p.poind1 {
+ font-size: smaller;
+ text-align: left;
+ margin-bottom: 0;
+ margin-top: 0em;
+ text-indent: 1em
+ }
+p.poind2 {
+ font-size: smaller;
+ text-align: left;
+ margin-bottom: 0;
+ margin-top: 0em;
+ text-indent: 2em
+ }
+p.poind3 {
+ font-size: smaller;
+ text-align: left;
+ margin-bottom: 0;
+ margin-top: 0em;
+ text-indent: 3em
+ }
+
+div.poem {
+text-align: center
+}
+
+span.stanza {
+ page-break-inside: avoid;
+ margin-bottom: 1em
+}
+div.stanza {
+ page-break-inside: avoid;
+ margin-bottom: 1em
+}
+
+blockquote.poem {
+ page-break-inside: avoid
+}
+
+table.poem {
+ float: center;
+ text-align: center
+}
+
+td.poem {
+ margin-bottom: 1em
+}
+
+p.citepoet {
+ font-style: italic;
+ font-size: smaller;
+ text-align: right;
+ margin-top: 0;
+ }
+
+p.citeauth {
+ font-style: italic;
+ font-size: smaller;
+ text-align: right;
+ margin-top: 0;
+ }
+
+p.quote {
+ text-indent: 1em;
+ margin-top: 0em;
+ margin-bottom: .5em;
+ font-size: smaller
+ }
+
+cite {
+ text-indent: 12pt;
+ margin-top: 1em;
+ margin-bottom: 1em;
+ font-size: smaller
+ }
+
+.title {
+ text-align: center
+ }
+
+span.def {
+ font-weight: bold
+ }
+
+span.pos {
+ font-style: italic;
+ } /* part of speech formatting */
+
+/*SPAN.smallcap {
+ text-transform: small-caps;
+ }
+*/
+
+span.rj {
+ text-align: right
+ }
+
+span.ind1 {
+ margin-left: 30px
+ }
+span.ind2 {
+ margin-left: 2em
+ }
+span.ind3 {
+ margin-left: 3em
+ }
+span.ind4 {
+ margin-left: 4em
+ }
+span.ind5 {
+ margin-left: 5em
+ }
+span.ind6 {
+ margin-left: 6em
+ }
+
+a:link {
+ color: rgb(204,0,0);
+ text-decoration: none
+}
+
+a:visited {color: rgb(51,0,153)}
+
+a:active {color: rgb(255,204,51)}
+
+body {
+ color: rgb(0,0,0);
+ background-color: rgb(255,255,255);
+ font-family: 'Times New Roman', Times, Serif}
+
+h1 {
+ font-weight: normal;
+ font-style: normal;
+ font-size: 24pt;
+ text-align: center
+ }
+
+/*H1.title {
+ text-transform: capitalize
+ }
+*/
+
+h2 {
+ font-weight: normal;
+ font-style: normal;
+ font-size: 18pt}
+
+h3 {
+ font-weight: normal;
+ font-style: normal;
+ font-size: 14pt}
+
+h4 {
+ font-weight: normal;
+ font-style: normal;
+ font-size: 12pt}
+
+h5 {
+ font-weight: normal;
+ font-style: normal;
+ font-size: 10pt}
+
+h6 {
+ font-weight: normal;
+ font-style: normal;
+ font-size: 8pt
+ }
\ No newline at end of file
--- /dev/null
+++ b/lib/ebooks/devils/foreword.html
@@ -1,0 +1,99 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE html PUBLIC "+//ISBN 0-9673008-1-9//DTD OEB 1.0 Document//EN"
+ "http://openebook.org/dtds/oeb-1.0/oebdoc1.dtd">
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/x-oeb1-document; charset=utf-8" />
+<link rel="stylesheet" type="text/x-oeb1-css" href="devil.css" />
+<title>The Devil’s Dictionary: Editor’s Foreword</title>
+</head>
+<body lang="en-us">
+
+<h1>Editor’s Foreword</h1>
+
+<p class="firstpara">This Open eBook edition of <i>The Devil’s Dictionary</i> was begun as a way for
+me to learn the Open eBook (OEB) structure and how to write clean XHTML that duplicates the original formatting of the
+typeset edition.</p>
+
+<p class="indentpara">Having hit the limitations of the OEB format and current OEB readers in this attempt, I am
+posting this early version of my conversion effort as a test document that illustrates the shortcomings of the
+format and is meant to encourage the developers to address these issues in forthcoming versions of their software
+and the OEB specification itself.</p>
+
+<p class="indentpara">The most difficult problem I have faced in formatting <i>The Devil’s Dictionary</i>
+has been poetry. The print copy I own has the poems formatted so that the attribution line is right justified
+with the end of the longest line of the poem, no stanza is broken across pages, and the whole thing is centered
+within the margins of the body text. This is a very natural way to format the poetry, yet it is impossible to
+duplicate this structure with the current eBook readers—most notably, with Microsoft Reader.</p>
+
+<p>First, the only
+way to create the desired justification and centering with HTML is to place the whole poem inside one table. This
+works for small poems, but not for larger ones because MS Reader cuts off all text in a table cell when the end
+of the page is reached, preventing long poems from being displayed in their entirity. Additionally, if each stanza
+is placed inside a pair of paragraph tags (as would seem natural) many of the indents must be accomplished by
+adjusting the left margin of that individual line with a <code><span></code> tag. This should work, since
+both this tag and the left margin property are applied to all elements (block and inline) according to the HTML and
+CSS specifications. MS Reader, however, ignores this instruction. An example of this formatting
+is found in the “A” section of the <i>Dictionary</i>.</p>
+
+<p>An alternate way to format the poems is to enclose each poem in a <code><blockquote></code> tag,
+each line in its own paragraph tag (with different CSS classes to handle the needed indents and close up
+the line spacing) and, each stanza in a <code><span></code> tag (with the CSS page-break-after property set
+to avoid breaking across pages). However, the blockquote’s margins causes many poems towrap, does not
+center the poem, places the attribution line (and any right-justified lines of the poem) almost at the right margin
+of the book (sometimes far away from the poem itself), and MS Reader ignores the instructions to not
+wrap the stanzas. This method is demonstrated in the “B” section of the <i>Dictionary</i>.</p>
+
+<p>As I was writing this, I thought of what should have been an obvious construct for these poems: putting
+each stanza in a separate table cell. This solves many, but not all, of the problems described above. For poems
+with short- or medium-length stanzas viewed with the PC version of MS Reader on a large-screen laptop
+it should work fine. But for a PocketPC, or even for poems with long single stanzas on a PC, the bottom of each long
+stanza will still be lost. You can see the results of this experiment in the “C” section of the
+<i>Dictionary</i>.</p>
+
+<p>These issues can best be demonstrated by one representative poem in each of the first three sections, when
+reading the book in the desktop version of MS Reader. <a href="A.html#abracadabra">Abracadabra</a> should
+be separated into stanzas with 1em of space between each, but since Reader ignores the <code><span></code>
+tag, it is just one long block. The poem cited under the definition of <a href="B.html#beg">beg</a> exemplifies
+the problems with the wide right margin described above. Although not perfect, the poem cited under
+<a href="C.html#carmelite">carmelite</a> is presented almost exactly as it should be. The poem is properly
+centered, the indents and right justification appear as intended, and the poem is broken across pages only
+between stanzas. But when viewed on a smaller screen (almost certainly with a Pocket PC) the first stanza
+alone will likely be cut off.</p>
+
+<p>A major additional problem, not specific to this book, is the inability of any current OEB reader to handle
+Unicode text, as mandated in the OEB specification. An example of how such a Unicode document appears is
+demonstrated in sections “D” (UTF-8) and “E” (UTF-16) of the <i>Dictionary</i>. Notice that
+the Unicode signature/byte-order mark which appears at the beginning of each of these files causes problems with
+both the readers and with the authoring tools. The MobiPocket Publisher can not complete the conversion
+process at all, and while ReaderWorks handles both relatively OK, MS Reader can not display UTF-8 files
+correctly (the Unicode signature causes it to ignore all CSS formatting and UTF-8 characters are displayed
+as their literal byte sequence, something specifically forbidden by the OEB specification) and the whole
+section “E” disappears because of the byte-order mark.</p>
+
+<p>Most sections beyond E have not yet been fully formatted, so please do not expect them to look pretty.</p>
+
+<h2>Project Gutenberg</h2>
+
+<p class="indentpara">Another goal is much broader. I have long known of Project Gutenberg, but have
+always found its insistence on plain ASCII to be a handicap that limited its appeal and usability. Don’t
+get me wrong—the effort has provided a tremendous resource, and at the time the project was begun
+(and until very recently) plain ASCII was clearly the best choice. But you can’t properly format a book
+with just ASCII characters. Not only must basic things such as *bold* and _italics_ be indicated in a funky
+manner, it is simply impossible to preserve the accented characters, ligatures, and many other important
+features. And trying to display such a work legibly on a PDA or eBbook reader with a small screen is
+impossible, given the hard line breaks that are present (keeping the text from flowing properly).</p>
+
+<p class="indentpara">With is footing solidly in HTML and XML and its completely open nature, the Open eBook
+format is the ideal structure in which to continue the goals of Project Gutenberg on into the 21<sup>st</sup>
+century. So this edition of <i>The Devil’s Dictionary</i> is not meant just as a personal learning
+project, but as an example of the benefits to offering current and future editions as Open eBooks. I don’t
+dispute the benefits of the current plain ASCII versions, but with the right automation tools, future editions
+could begin as Open eBooks and then be converted to plain ASCII, making both versions available without
+duplicated effort. This would be far preferable to starting with plain ASCII versions and converting them to
+Open eBook. This is the method I obviously used for this edition, and I assure you that it is quite tedious
+and not well-suited as a standard practice.</p>
+
+<p style="text-align: right">Peter K. Sheerin</p>
+</body>
+</html>
\ No newline at end of file
--- /dev/null
+++ b/lib/ebooks/devils/foreword.html.i
@@ -1,0 +1,13 @@
+5 pages
+size 400 552
+length 7632
+421 2 10 body html
+0
+1633 2 29 body html
+119
+3826 2 54 body html
+34
+5770 2 76 body html
+0
+6646 2 87 body html
+238
--- /dev/null
+++ b/lib/ebooks/devils/index.html
@@ -1,0 +1,44 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE package PUBLIC "+//ISBN 0-9673008-1-9//DTD OEB 1.0 Package//EN"
+ "http://openebook.org/dtds/oeb-1.0/oebdoc1.dtd">
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+<link rel="stylesheet" type="text/css" href="devil.css" />
+<title>The Devil’s Dictionary: Table of Contents</title>
+</head>
+<body lang="en-US">
+<h1 align="center">Table of Contents</h1>
+<p><a href="TitlePage.html">Title Page</a></p>
+<p><a href="foreword.html">Foreword</a></p>
+<p><a href="preface.html">Author’s Preface</a></p>
+<ul>
+ <li><a href="A.html">A</a></li>
+ <li><a href="B.html">B</a></li>
+ <li><a href="C.html">C</a></li>
+ <li><a href="D.html">D</a></li>
+ <li><a href="E.html">E</a></li>
+ <li><a href="F.html">F</a></li>
+ <li><a href="G.html">G</a></li>
+ <li><a href="H.html">H</a></li>
+ <li><a href="I.html">I</a></li>
+ <li><a href="J.html">J</a></li>
+ <li><a href="K.html">K</a></li>
+ <li><a href="L.html">L</a></li>
+ <li><a href="M.html">M</a></li>
+ <li><a href="N.html">N</a></li>
+ <li><a href="O.html">O</a></li>
+ <li><a href="P.html">P</a></li>
+ <li><a href="Q.html">Q</a></li>
+ <li><a href="R.html">R</a></li>
+ <li><a href="S.html">S</a></li>
+ <li><a href="T.html">T</a></li>
+ <li><a href="U.html">U</a></li>
+ <li><a href="V.html">V</a></li>
+ <li><a href="W.html">W</a></li>
+ <li><a href="X.html">X</a></li>
+ <li><a href="Y.html">Y</a></li>
+ <li><a href="Z.html">Z</a></li>
+</ul>
+</body>
+</html>
--- /dev/null
+++ b/lib/ebooks/devils/index.html.i
@@ -1,0 +1,7 @@
+2 pages
+size 400 552
+length 1530
+400 2 10 body html
+0
+603 2 15 body html
+357
--- /dev/null
+++ b/lib/ebooks/devils/preface.html
@@ -1,0 +1,48 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE html PUBLIC "+//ISBN 0-9673008-1-9//DTD OEB 1.0 Document//EN"
+ "http://openebook.org/dtds/oeb-1.0/oebdoc1.dtd">
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/x-oeb1-document; charset=utf-8" />
+<link rel="stylesheet" type="text/x-oeb1-css" href="devil.css" />
+<title>The Devil’s Dictionary: Preface</title>
+</head>
+<body lang="en-us">
+
+<h1>Preface</h1>
+
+<p class="firstpara"><i>The Devil’s Dictionary</i>
+was begun in a weekly paper in 1881, and was continued in a desultory way at
+long intervals until 1906. In that year a large part of it was published in
+covers with the title <i>The Cynic’s Word Book</i>,
+a name which the author had not the power to reject or happiness to approve. To
+quote the publishers of the present work:</p>
+
+<p class="indentpara">“This more reverent title had previously been forced upon him by the religious scruples of
+the last newspaper in which a part of the work had appeared, with the natural
+consequence that when it came out in covers the country already had been
+flooded by its imitators with a score of ‘cynic’ books—<i>The Cynic’s This</i>, <i>The Cynic’s That</i>,
+and <i>The Cynic’s t’Other</i>. Most of these books
+were merely stupid, though some of them added the distinction of silliness.
+Among them, they brought the word ‘cynic’ into disfavor so deep that any book
+bearing it was discredited in advance of publication.”</p>
+
+<p class="indentpara">Meantime, too, some of the enterprising humorists of the country had helped themselves to such
+parts of the work as served their needs, and many of its definitions,
+anecdotes, phrases and so forth, had become more or less current in popular
+speech. This explanation is made, not with any pride of priority in trifles,
+but in simple denial of possible charges of plagiarism, which is no trifle. In
+merely resuming his own the author hopes to be held guiltless by those to whom
+the work is addressed—enlightened souls who prefer dry wines to sweet, sense to
+sentiment, wit to humor and clean English to slang.</p>
+
+<p class="indentpara">A conspicuous, and it is hope not unpleasant, feature of the book is its abundant illustrative
+quotations from eminent poets, chief of whom is that learned and ingenius
+cleric, Father Gassalasca Jape, S.J., whose lines bear his initials. To Father
+Jape’s kindly encouragement and assistance the author of the prose text is
+greatly indebted.</p>
+
+<p style="text-align: right">A. B.</p>
+
+</body>
+</html>
\ No newline at end of file
--- /dev/null
+++ b/lib/ebooks/devils/preface.html.i
@@ -1,0 +1,7 @@
+2 pages
+size 400 552
+length 2629
+405 2 10 body html
+0
+1546 2 30 body html
+170
--- /dev/null
+++ b/lib/ebooks/oebtest/BART.html
@@ -1,0 +1,323 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE html PUBLIC "+//ISBN 0-9673008-1-9//DTD OEB 1.0 Document//EN"
+ "http://openebook.org/dtds/oeb-1.0/oebdoc1.dtd">
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/x-oeb1-document; charset=utf-8" />
+<link rel="stylesheet" type="text/x-oeb1-css" href="DrBillBio.css" />
+<title>Bill Wattenburg’s Background: Fixing BART Safety</title>
+</head>
+
+<body>
+
+<h1>Fixing BART Safety (Bay Area Rapid Transit System)</h1>
+
+<h2>(1972–1974)</h2>
+
+<p>Wattenburg’s two-year running battle with the BART agency appears to be the first time
+he publicly confronted a government agency as a scientist. We found over fifty-five
+press reports with his name involved with this subject during the period 1972 to 1974. Some of
+the history we summarize below comes from a U.S. Department of Transportation (DOT) internal
+report we obtained from a congressional staff member. DOT was evidently funding BART and
+concerned about Wattenburg’s highly publicized criticisms of BART management.</p>
+
+<p>The State of California asked Wattenburg to fix the electronic train control problems that
+plagued the new Bay Area Rapid Transit System (BART). BART and Westinghouse Corp.
+engineers who designed the system insisted that there were no problems and essentially told the
+State of California safety officials to go to hell. BART claimed that the state safety officials were
+needlessly preventing Bay Area commuters from getting full benefit of the BART system.</p>
+
+<p>With the encouragement of exasperated state officials, Wattenburg, acting only as a taxpayer,
+confronted the local BART managers at their bi-weekly public meetings for two years running
+while many of his public predictions of safety problems came true. BART management was
+eventually fired, and the State demanded that Wattenburg’s clever design modifications be
+installed before the BART system could run full service. The press confirmed that Wattenburg
+refused all payment from BART and the State for his efforts.</p>
+
+<p>During this nationally publicized battle, Wattenburg first described many of his design
+improvements for BART to the press and over KGO Radio in terms that the lay public could
+understand. It became a popular game for his listeners to know more—and sooner—about BART
+design problems than the BART engineers. He generated press headlines the next day for months
+on end. His radio shows and the subsequent press stories each week carried his predictions of the
+next problem or accident that would occur on BART—and they invariably happened on schedule.
+He literally intimidated the incompetent BART management out of office with the power of talk radio.</p>
+
+<br />
+<p><b>Here is a summary of the sequence of events:</b></p>
+<br />
+
+<p>BART as an independent agency experienced some early safety problems with a new
+electronic train control system built by Westinghouse Corp. One train ran away during trial runs
+of the new BART system. BART and Westinghouse engineers insisted that this was a “one in a
+hundred-million failure that could never happen again.” BART would not cooperate with state
+agencies that wanted to investigate these problems before giving BART approval to operate the
+trains.</p>
+
+<p>The noted California legislative analyst, A. Alan Post, enlisted U. C. Berkeley Professor
+Bill Wattenburg to evaluate the design of the BART automated train control system designed by
+Westinghouse. Wattenburg subsequently testified at a state senate committee hearing that he had
+found some serious design flaws in the Westinghouse design and warned that the system was
+unsafe to operate. Westinghouse and BART both protested vehemently that Wattenburg was
+unqualified in the field and that he was “just a headline grabbing radio talk-show host and only a
+junior faculty member at Berkeley looking to impress his students.”</p>
+
+<p>Wattenburg was the sole expert witness for the state. Seven senior Westinghouse and
+BART executives told the confused state senators that Wattenburg was wrong.</p>
+
+<p>A flurry of front-page stories report that Wattenburg then responded by offering a list of
+the most probable dangerous failures that would occur in the BART system that could lead to
+collisions between high-speed trains. He even estimated the time periods for when these failures
+would likely occur. BART and Westinghouse engineers were furious. They denied that any of
+these failures could ever happen. Both BART and Westinghouse threatened to “take legal action
+against Wattenburg if he persisted in making inflammatory statements that destroyed the public’s
+confidence in the BART system.”</p>
+
+<p>Wattenburg’s answer to the BART threats was to give a quote to Herb Caen, the most
+widely read columnist on the west coast. The item appeared the next day in the San Francisco
+Chronicle. Wattenburg said that if the BART train control system was not fixed, it would be “the
+world’s most expensive, computer-controlled, track-mounted pinball machine.” The battle lines
+were drawn. Bay Area readers who were riding BART were shocked by the front-page stories
+that appeared the next day.</p>
+
+<p>The first of Wattenburg’s predictions actually occurred the following week as the
+California Public Utilities Commission (PUC) inspectors were monitoring the BART operation.
+They discovered that trains disappeared at certain times from the master control panel. Central
+controllers didn’t know where some trains were on the tracks for several minutes at a time. This
+meant that the automated train control system could be telling one train to speed right into
+another train parked ahead—a train that it didn’t know about. This is the most dangerous
+situation that can happen on any railroad.</p>
+
+<p>Naturally, the PUC and the press swarmed all over Wattenburg to explain why he was able
+to predict that this would happen. He told them he could only show them with “a little
+experiment”, and that BART would have to cooperate to let him demonstrate the cause of the
+problem. BART objected. The PUC threatened to shut BART down completely unless BART
+could identify the problem or prove it was corrected immediately. BART allowed Wattenburg to do
+his experiment.</p>
+
+<p>Wattenburg led everyone to a section of unused BART track early on a foggy morning.
+He pointed to the rusty surface on the normally shiny track. He motioned for a waiting train to
+move forward. He told a PUC inspector to call his colleagues waiting at BART central.
+Wattenburg said: “I’ll bet they can’t see that train right now.” The reporters watched the PUC
+inspector get the word from BART central and then nod that Wattenburg was right.</p>
+
+<p>Next, Wattenburg ordered the train to run back and forth over this stretch of track several
+times. He announced: “Now they can see the train.” The PUC inspector on the portable phone
+confirmed that he was right again. Then Wattenburg gave them the answer and how he was able
+to predict the problem.</p>
+
+<p>He explained that he had first noticed that the Westinghouse designers had used very low-voltage (less than a volt) to shunt a current across the rails through the steel wheels and axle of a
+train. This shunt signal is what tells central control that a train is at a given location. Standard
+train control systems use a much higher voltage, like 15 volts. He explained how this low-voltage
+scheme probably worked very well in the nice, clean Westinghouse factory where they tested their
+new design. But it doesn’t rain inside the factory. When it rains, or there is heavy fog, the shiny
+steel rails take on a thin layer of rust very quickly. The rusty surface has a much higher electrical
+resistance that clean rails. The low voltage cannot drive a current through the rusty surface on
+the rails. Hence, there is no signal of where the train is on the tracks.</p>
+
+<p>Then, according to the press reports, he made another seemingly arrogant prediction. He
+told them that a train would only disappear when:</p>
+
+<ol>
+ <li>The track had not been used for several hours during rain or heavy fog, and</li>
+ <li>The missing train would be the first or second train to use the track after the
+ unused period during which the track had been exposed to rain or fog.</li>
+</ol>
+
+<p>“Other than that,” he said, “the BART system was marginally safe and
+riders shouldn’t worry.”</p>
+
+<p>The PUC inspectors rushed to check their records of past missing trains. BART public
+relations issued a press release saying that Wattenburg was trying to “dazzle the press with
+scientific hocus-pocus.” The Bay Area papers all included the BART accusation in their stories.</p>
+
+<p>The PUC confirmed that Wattenburg was right two days later. Trains had only disappeared on the BART tracks in the early mornings after it had rained or been very foggy the
+night before, and it was almost always the first or second train over the tracks. But, there was one
+case in which a third train had been missing for short intervals as well.</p>
+
+<p>BART public relations next tried to suggest that everything that Wattenburg said shouldn’t
+be believed because he had not been accurate about how many trains were required to clean the
+tracks so that BART could run safely. When the press asked Wattenburg for his comments on this,
+he said: “Well, I guess I screwed up on that third train. I’ll have to take back what I said. The
+system is not as safe as I thought it was.”</p>
+
+<p>BART soon announced that it had solved the missing train problem by installing special
+“scrubbers” on its trains. (The scrubbers were nothing more than pieces of metal dragged along
+the track to scrape off the rust.) BART would run special “pilot” trains every morning to make sure
+the tracks were clean before passenger trains moved onto the tracks. Their press release stated
+that no one could have predicted this problem because “the special rails that they had ordered for
+this futuristic system had never before been tested.”</p>
+
+<p>Wattenburg countered with his usual stinging sarcasm: “This is really a futuristic system,
+alright. I wonder if anyone ever reminded them that in the eighteen hundreds the cities used to
+hire boys to walk along behind horse-drawn carriages to scoop up the horse manure so it wouldn’t
+blow in the citizens’ faces?”</p>
+
+<p>He then announced his next challenge. He said that he had had his electrical engineering
+students at CAL design a simple battery-powered electronic package that any BART rider could
+carry along with him on the train to make sure that the train control system knew where the train
+was at all times. “I mean these are my undergraduate students. They don’t know enough yet to
+design anything fancy. So, it’s cheap and it works great. Just ask the PUC inspectors. I’ll bet they
+were wondering why train number 102 never disappeared this morning even though it rained last
+night.”</p>
+
+<p>A reporter hinted that one of Wattenburg’s students had been on that train. The story
+reported that the device his students had built was nothing more than a radio frequency noise
+generator that messed up the normal train control signals in the track immediately below the train
+wherever it went. This caused the train control error detection circuits to report a problem at
+that location. This created a moving problem indicator with the train number on it to appear on
+the central control screen. Hence, the error indicator told central control where the train was at
+all times.</p>
+
+<p>Westinghouse engineers immediately complained that this scheme would disable their
+error detection circuits and endanger the whole BART system. Wattenburg countered with:
+“Why in the hell do you need error detection electronics when you know the whole damn system
+is broken down all the time anyway without even asking? Why not put these unemployed circuits
+to work so that we can get some people to work for a change?”</p>
+
+<p>The PUC wanted to test the device immediately. BART threatened to have Wattenburg
+arrested if he took any electronic device on a train that interfered with the train control system.
+Wattenburg offered the press an estimate of how long it would be before the BART track
+scrubbers would cut so much metal off the rails that they would have to be replaced. A later story
+suggested that the PUC did test Wattenburg’s device and BART agreed to use it so long as the
+PUC ordered BART to do so and Wattenburg agreed to say no more about it. However,
+Westinghouse notified BART that all its warranties would be voided if any foreign device was
+installed or used without their permission. It’s not clear what happened thereafter, but the missing
+train problem did suddenly disappear—at least from the press coverage.</p>
+
+<p>After this episode, the press evidently began to believe that Wattenburg was for real. The
+stories that followed looked into both his background and the qualifications of the Westinghouse
+designers.</p>
+
+<p>A reporter discovered that NASA had hired Wattenburg in 1963 to 1967 to do extensive
+design work on the electronic control and computer systems for the Apollo man-to-the moon
+project. Westinghouse and BART had earlier claimed that their engineers had worked on the
+Apollo project to support their claims to the state senate committee that they were “the world’s
+experts on advanced automated control systems of this nature and that no one else was qualified
+to evaluate the BART train control design.” Press stories verified that the Westinghouse
+engineers who were later assigned to the BART project had actually worked several levels below
+Wattenburg’s design responsibility in NASA. (Evidently, Legislative Analyst A. Alan Post had
+known this when he first contacted Wattenburg for help.)</p>
+
+<p>When one irritated reporter asked Wattenburg why he had not told the press for months
+about his NASA experience, he answered: “You should have asked me. I noticed that you print
+every handout that the BART bullshitters give you, so why should I bother to tell you the truth.”
+This newspaper later ran an editorial which indirectly apologized to Wattenburg for some of the
+snide stories about him that their reporter had filed after he first challenged BART before the
+state senate committee.</p>
+
+<p>After the dramatic sequence of events described above, the PUC refused permission for
+BART to operate their trains at designed speeds until all of Wattenburg’s technical objections
+were investigated. More state senate hearings were called. Wattenburg appeared at the next
+hearing with alarming data from some more experiments that he had done on his own. BART and
+Westinghouse again protested that he had interfered without their permission. Wattenburg
+described how he had given his engineering students who ride BART some simple instruments
+that measured BART train control signals without interfering with the operation in any way.
+Then he described several more design changes that should be made to the train control
+electronics to make the system safer.</p>
+
+<p>At this dramatic hearing, he gave his new design documents to the state senate committee
+and the Legislative Analyst and asked them to hand these documents to the irate BART General
+Manager, Billy Stokes, who was sitting in the hearing room with a group of Westinghouse
+executives. One story reported that Wattenburg turned to Billy Stokes and announced: “Here’s a
+present for you. Be my guest. That’ll fix the hundred million dollar screw job you guys have
+given the taxpayers.”</p>
+
+<p>The public standoff escalated when the BART District Directors were told by their
+General Manager that Wattenburg was part of a political conspiracy to discredit the District and
+this was the only reason he was trying to embarrass the BART and Westinghouse engineers. This
+made headlines. Wattenburg appeared at the next public BART board meeting and requested to
+speak as a taxpayer. One group of concerned BART directors demanded that he be allowed to
+speak at all meetings as a public representative and rebut anything he felt was not accurate in what
+the general manager and the BART engineers were telling the directors.</p>
+
+<p>The state officials could not direct BART to take any specific action to correct the
+alleged problems, but through the California PUC they could and did withhold permission for
+BART to operate their trains at full speed until the safety problems were resolved. A majority of
+the BART directors refused to allow Wattenburg to test his ideas or order Westinghouse to make
+the simple changes that Wattenburg had specified. The argument was that this would violate the
+warranties in the Westinghouse contract and open up BART to lawsuits from both Westinghouse
+and the taxpayers. Almost weekly front-page stories in the San Francisco Chronicle and other Bay
+Area papers detail how BART was forced to operate their new trains under severe restrictions
+that guaranteed that trains could not collide if the train control system malfunctioned.</p>
+
+<p>More serious problems and near accidents did occur over the next six months. These were
+witnessed by PUC inspectors stationed in BART central control. Some of these were on the list
+that Wattenburg had originally given to the state senate committee and A. Alan Post. Wattenburg
+appeared at every BART board meeting and battled with the BART and Westinghouse engineers.
+Wattenburg challenged the credentials of three successive chief engineers at BART. All of them
+left or were fired. These confrontations became the media event of the week for the press as the
+controversy raged.</p>
+
+<p>The matter finally came to a head when BART ran out of money and had to appeal to the
+state for financial assistance to operate the system. The State Senate Transportation
+Committee
+headed by Senator Alfred Alquist demanded that Billy Stokes be fired as a condition for approval
+of any state funds. Wattenburg was in attendance. A story reports that he stood up and
+announced to Mr. Stokes: “I told you that the truth would catch up with you, you lying bastard.”
+(Wattenburg had earlier called Stokes a liar at several public BART meetings when Stokes and his
+chief engineers gave engineering reports to the board members that Wattenburg proved were false
+or incomplete. Stokes had been forced to apologize for these
+“oversights”. The chief engineers were replaced shortly thereafter.)</p>
+
+<p>The state legislature finally passed a law that required elected board members for BART
+as a condition for state financial assistance. All the Billy Stokes supporters on the BART board
+were replaced in the election. Wattenburg refused requests that he run for the board or agree to be
+the new general manager (two papers editorialized that he should serve). The new board
+immediately ordered BART engineers to incorporate Wattenburg’s design changes into the train
+control system. Wattenburg recommended that BART hire the University of California Lawrence
+Berkeley Laboratory to supervise the design modifications. BART hired Hewlett-Packard
+Corporation to build and install the equipment.</p>
+
+<p>Wattenburg issued a press release in which he stated that he had done all he could and that
+he wanted nothing more to do with BART other than ride the trains when they could “safely
+move faster than he could walk.”</p>
+
+<p>Hewlett-Packard and Lawrence Berkeley Laboratory were paid over two million dollars
+for their work over the next two years which consisted mostly of installing improved versions of
+the train control design changes that Wattenburg had originally specified. There were press
+reports that Hewlett Packard engineers later insisted that all the new design changes were their
+own ideas and that this created some friction between them and Lawrence Berkeley scientists who
+claimed otherwise. Wattenburg refused to get into the argument or comment to the press. His
+only comment was that he “never wanted to hear about BART again.”</p>
+
+<p>The new BART board filed suit against Westinghouse after the design changes proved to
+solve the missing train problem and other safety problems. The PUC allowed them to run trains at
+design speeds for the first time in five years. Wattenburg agreed to testify for BART if requested.
+Westinghouse settled the suit for a reported sixteen million dollars.</p>
+
+<p>When the press inquired whether Wattenburg had received any payment for his services
+over two years, he gave them the following statement: “Hell, if I had even asked for a free ride on
+their silly trains somebody would have claimed that I did it just to get a handout. The taxpayers of
+the State of California gave me a great education. All I want is for them to know that I paid them
+back in full.”</p>
+
+<p>Some BART directors suggested offering Wattenburg $50,000 for his services after his
+solution to the BART train control problem was adopted. He declined, saying that he might have
+to criticize them again in the future if they didn’t do their job.</p>
+
+<p>The Department of Transportation internal report points out that another real beneficiary of
+Wattenburg’s efforts is the Washington D.C. Metro system. All of Wattenburg’s design
+improvements were incorporated into the Metro system before it was opened. As a consequence,
+the Metro did not suffer the long delays and safety problems that BART suffered. The author of
+this report notes the curious fact that Westinghouse had to have been making some of these
+changes in the Metro equipment they delivered to Washington even while they were still insisting
+that Wattenburg’s changes were not necessary in the BART system. Otherwise, there would have
+been long delays in starting operation in Washington. The writer suggests that DOT might
+consider some sort of recognition to Wattenburg for his contribution to the mass transit industry
+in the U.S.</p>
+
+<p>It is not surprising that such recognition never came. We talked to a long-time BART
+employee who was on the scene at the time all this happened. He said that the new general
+manager selected for BART was none other than the former Secretary of Transportation who had
+given some support to Billy Stokes during his battles with Wattenburg, and that Billy Stokes
+himself moved upstairs as the new Director of the Urban Mass Transit Association
+(UMTA) representing such companies as Westinghouse. The UMTA and DOT officials work very closely
+together.</p>
+
+<p>During our visits to this KGO radio show in October 1990, several callers to his show
+wanted to talk about the most recent problems with the BART system. He absolutely refused to
+discuss the subject on his show. He said to one caller, “I’ll tell you what though, why don’t you
+ask me about my first wife?”</p>
+
+</body>
+</html>
\ No newline at end of file
--- /dev/null
+++ b/lib/ebooks/oebtest/BART.html.i
@@ -1,0 +1,33 @@
+15 pages
+size 400 562
+length 22832
+408 2 11 body html
+0
+1503 2 30 body html
+34
+2772 2 49 body html
+136
+4665 2 75 body html
+34
+6253 2 97 body html
+34
+7896 2 117 body html
+34
+9056 2 137 body html
+136
+10974 2 163 body html
+34
+11997 2 177 body html
+238
+13838 2 201 body html
+170
+15608 2 225 body html
+85
+17088 2 243 body html
+136
+18478 2 262 body html
+221
+20407 2 288 body html
+102
+21936 2 309 body html
+119
--- /dev/null
+++ b/lib/ebooks/oebtest/BentSub.html
@@ -1,0 +1,31 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE html PUBLIC "+//ISBN 0-9673008-1-9//DTD OEB 1.0 Document//EN"
+ "http://openebook.org/dtds/oeb-1.0/oebdoc1.dtd">
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/x-oeb1-document; charset=utf-8" />
+<link rel="stylesheet" type="text/x-oeb1-css" href="DrBillBio.css" />
+<title>Bill Wattenburg’s Background: Downhole Drillbit</title>
+</head>
+
+<body>
+
+<h1>Downhole Drillbit</h1>
+
+<h2>(1990’s)</h2>
+
+<p>We were told by some Livermore engineers in November 1992 that Bill Wattenburg has
+been working on a device for drilling oil wells that could save enormous amounts of money and
+improve the safety of drilling if he is successful. Neither he nor they would tell us what it was.
+They would only tell us that everyone else has failed for fifty years to achieve this “driller’s
+dream”. They said that some company with a lot of money bet Wattenburg that it couldn’t be
+done. They said that his first experiment failed. Because of that alone, they figured he would
+have it solved before long. <q>That’s how he gets warmed up.</q></p>
+
+<hr />
+
+<p><i>[Note: Bill did succeed in this task, and has since received two patents
+on the resulting invention—PKS]</i></p>
+
+</body>
+</html>
\ No newline at end of file
--- /dev/null
+++ b/lib/ebooks/oebtest/BentSub.html.index
@@ -1,0 +1,5 @@
+1 pages
+size 400 562
+length 1245
+407 2 11 body html
+0
--- /dev/null
+++ b/lib/ebooks/oebtest/BlueWater.html
@@ -1,0 +1,293 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE html PUBLIC "+//ISBN 0-9673008-1-9//DTD OEB 1.0 Document//EN"
+ "http://openebook.org/dtds/oeb-1.0/oebdoc1.dtd">
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/x-oeb1-document; charset=utf-8" />
+<link rel="stylesheet" type="text/x-oeb1-css" href="DrBillBio.css" />
+<title>Bill Wattenburg’s Background: Blue Water Contamination</title>
+</head>
+
+<body>
+
+<h1>Blue Water (Copper) Contamination in Homes</h1>
+
+<h2>(1991)</h2>
+
+<p>This is the latest of Wattenburg’s bizarre escapades reported in press stories all over the
+country. We contacted many of the people who were on the scene to get interesting parts of
+this story that were not covered by the press.</p>
+
+<p>Hundreds of expensive new homes in the affluent area of Danville, California, had suffered
+serious copper contamination (blue water) for several years. Lawsuits were filed in all directions
+because homeowners had to use bottled water, children in schools had become sick, and home
+values were dropping. Neither the water company (EBMUD) nor the home builders would take
+responsibility. Both had spent over $5,000,000 on water corrosion experts and lawyers who were
+investigating the problem.</p>
+
+<p>A professor of civil engineering who was on the project at times has told us that he could
+show us hundreds of technical reports on blue water from around the world in the last fifty years
+where corrosion experts have been unable to completely explain the cause of “blue water”. He
+told us: “In many cases the problem just mysteriously goes away for reasons that ‘corrosion
+experts’ cannot adequately explain, although most take credit for doing something the solved their
+local problem. However, each one claims he found a different solution that does not seem to
+work everywhere else.”</p>
+
+<p>We called Wattenburg to tell us why and how he solved the problem in Danville. He
+cautioned us immediately that he did not completely solve the problem, in spite of what the
+newspaper and technical journals reported. He said: “It is one thing to isolate a problem and then
+make it go away. I do that with obnoxious people all the time. But it is another thing to explain
+why they came around in the first place.” (This may have been a message to us, but he softened
+up after that.)</p>
+
+<br />
+<p><b>Here is his story:</b></p>
+<br />
+
+<p>He said he got involved when some Danville home owners called him on his KGO radio
+show in May 1991. They pleaded with him to help them because they were losing their life
+savings in the value of their homes. They described the blue water problem to him on the air.
+They told him that there was conclusive proof that the contamination was copper hydroxide.
+They told him that the only copper pipes were the water pipes in their homes. He says he “shot
+his mouth off and told them that good scientists should have no problem finding the problem very
+quickly if they did the proper experiments.”</p>
+
+<blockquote>
+<p>“They asked me how much I thought it should cost. I stupidly said that it shouldn’t cost
+more than a few thousand dollars for a good scientist to make the right measurements. I told
+them to call the Lawrence Livermore National Laboratory which is right near them. The next day,
+I got a call from the Livermore Lab saying they were getting calls from people pleading with them
+to help, and the newspapers were asking them why the laboratory didn’t help solve this serious
+problem. Livermore said they couldn’t get involved because there was litigation going on and the
+water company was a public agency that had not requested their services. I got the picture, but I
+was stuck. I went out there the next day to take a look.”</p>
+</blockquote>
+
+<p>A civil engineering professor who was working on the problem as a consultant to the
+homebuilders told us the story we summarize below:</p>
+
+<p>He says that Wattenburg quickly made a startling discovery right in the faces of the water
+corrosion experts who had been working on the problem for a year. They had been studying
+only the corrosion characteristics of the water in the house pipes. They had expensive water
+chemistry testing laboratories set up in the garages of two blue water homes supplied by the
+builders. Wattenburg walked out of one of these laboratories while they were still telling him
+about all their experiments. He got some things out of his car. Then he stuck some small copper
+rods into the ground at various points around the house and measured the voltages between these
+points with a little voltmeter that he carried in his pocket. They thought he was a little strange.</p>
+
+<p>He found electrical voltages of about half a volt in the ground all around the homes and
+between the ground and the water pipes in the homes. “He did this within about twenty minutes
+after he arrived. The gadgets he had in the trunk of his car looked like an electronics laboratory.
+He then told us to go to the hardware store and buy all the small copper wire we could find, I
+remember the driver asking him how much? He calmly said: ‘Oh, about a mile of it, if you can.’ It
+was rather amazing what we did all the rest of that day.”</p>
+
+<blockquote>
+<p>“Wattenburg made some more measurements around and inside several more blue water
+houses. Then he told all the corrosion consultants who were gathered around that the problem
+probably wasn’t in the houses or in their copper water pipes. The real cause was most
+likely coming from the power lines or EBMUD water mains somehow. At that point, most of them
+walked away shaking their heads. Wattenburg told me that he was surprised that these guys were
+corrosion experts. He said that the corrosion was most likely happening because there was
+electrochemistry going on in the copper pipes. He said that they obviously hadn’t worried about
+what was producing the ‘electro’ part of the electrochemistry they thought they were studying.
+It made sense to me after I thought about it a while. …</p>
+
+<p>“I remember one of them asking him what degrees or credentials he had as a corrosion
+engineer. I’ll never forget what Wattenburg said to the guy. He asked the guy how long he had
+been working on this problem. This very huffy guy said he had been working on the project for a
+year. Wattenburg told him: ‘Where I went to school. we don’t give degrees to engineers who
+can’t solve a problem in a year.’</p>
+
+<p>“Fortunately, I knew who Wattenburg was. I remembered what he had done to a lot of
+big-time engineers on the BART project many years earlier. I found it best to just help him and
+see what would happen. …</p>
+
+<p>“The water company, EBMUD, claimed that Wattenburg’s theory was nonsense. The
+water mains leading into the houses were plastic lines. They said these lines couldn’t possibly
+feed electrical current into the house water pipes. Wattenburg asked them to explain the electrical
+voltages he found in the ground and between the houses. They pointed the finger at the power
+company, PG&E. I remember Wattenburg smiling as he told us: ‘Well, that will get PG&E out
+here to help us in a hurry, won’t it?’</p>
+
+<p>“The next thing he did was cut all the electrical power off from the test houses and measure
+the voltages again. The voltages in the ground and on the house water pipes were still there. I
+saw him go down the street opening manholes to the water mains all over the place while
+suspicious EBMUD employees got on their mobile phones and called their office.</p>
+
+<p>“Over the next few weeks, Wattenburg used his long copper wires to measure voltages
+along the large steel water mains which were buried deep underground. The water company had
+told him that there was no way they would dig up the lines at various points so he could measure
+them. So, he figured out a very clever way that no one had thought about before. The water
+mains were protected by devices called sacrificial anodes which are connected to the lines below
+ground. But electrical wires attached to these devices are brought up to the ground at various
+places along the lines, about every half mile. This is why he wanted the mile of copper wire. We
+stretched the copper wire between the anode stations and he measured the voltage from one to
+the next. In this way, he mapped the voltages on the steel water mains all the way to the water
+storage tanks where the lines began up on the hills.”</p>
+</blockquote>
+
+<p>The home builders assigned one of their construction superintendents to help Wattenburg.
+Here is what he observed: </p>
+
+<blockquote>
+ <p>“The Power company, PG&E, was real happy to help him. He was getting them off the
+ hook for ten million dollars of liability. I remember one day he calmly told them to cut the power
+ off of a whole area in Danville because he had to be sure that these water main voltages were not
+ coming from the PG&E power lines. I couldn’t believe it when a whole goddamn shopping center
+ went dead right before my eyes about fifteen minutes later. … He only wanted it off for a few
+ minutes. … Hell, they’d have put me in jail if I had even cut their power accidentally.</p>
+
+ <p>“It really became a circus after that. The water company, EBMUD, realized what he was
+ doing. They refused to give him permission to measure the voltages on their water mains at
+ places where their lines were behind fences and near their pumping plants. Wattenburg just told
+ us to get more copper wire. PG&E sent out two more line crews that very day and they helped
+ stretch the copper wires around these areas for a mile or more while EBMUD employees stood
+ guard at their gates to make sure he didn’t trespass on their property. It was like two armies
+ facing off each other on the battle line. It was ludicrous. These are two companies that are
+ supposed to be public utilities. …</p>
+
+ <p>“Wattenburg’s answer was to call the newspapers and tell them to come out and watch
+ what was happening. The reporters showed up in droves. It was on the TV news for several
+ days. Finally, the general manager of EBMUD threw in the towel and asked to see Wattenburg.
+ Wattenburg told him to come out where he was working. They had a private conversation while
+ Wattenburg continued to make measurements along the water mains. EBMUD announced that
+ they were going to join the investigation the next day. The EBMUD gates and all the pumping
+ plants were opened for Wattenburg.</p>
+
+ <p>“A PG&E engineer told me that an hour after Wattenburg walked into the first EBMUD
+ pumping plant, I think it was called the New Scenic East Plant, he found a major problem that
+ EBMUD engineers had told the newspapers just couldn’t possibly happen. I remember this
+ big-shot from EBMUD saying on television that all the EBMUD water mains and their pumping plants
+ were completely isolated from the power lines. He said that they had double-checked that there
+ was no electricity getting into their water mains or plants.</p>
+
+ <p>“Wattenburg got PG&E to cut off the power to the plant for a few minutes and he did
+ some measurements that even the PG&E engineers didn’t understand. They objected as well as
+ the EBMUD engineers. However, the PG&E manager ordered them to do what Wattenburg
+ wanted. I think the PG&E manager’s name was Walt Musso from Walnut Creek. Wattenburg
+ then showed EBMUD that they had a major electrical short across the water mains leading into
+ and out of the plant.</p>
+
+ <p>“This hit the newspapers the next day. The EBMUD public relations people were eating
+ crow. EBMUD construction crews were working for the next month digging enormous holes
+ around the plant to find and fix the short in the water mains that were supposed to be isolated
+ from the PG&E lines.”</p>
+</blockquote>
+
+<p>He told us a funny story that happened next:</p>
+
+<blockquote>
+ <p>“Wattenburg casually told the EBMUD construction foreman one day that they should not do something he had observed them doing
+ with a big backhoe near this enormous water main that led into the pumping plant. The foreman
+ said that he had been operating backhoes for twenty years and he had never broken a water line
+ yet. He said that he was going to dig out all the dirt around the large main line for about a
+ hundred feet. He bragged that they wouldn’t even have to turn off the water pressure in the line
+ and interrupt service to their customers while they were doing it. Wattenburg told them that that
+ was what he was afraid of. Wattenburg did a quick calculation of the pressure forces in the
+ curved pipe they were exposing. The foreman laughed and said that EBMUD engineers had done
+ their own calculations, or something to that effect.</p>
+
+ <p>“Wattenburg told the PG&E crews working with us that they should get the hell out there
+ for a while. About an hour later, while we were having coffee at the Blackhawk Cafe, the water
+ main burst and it looked like Niagara Falls had appeared on the hillside above Danville.
+ Wattenburg didn’t even look surprised when we hollered at him to come see what had happened.
+ He didn’t even look up from the newspaper he was reading…”</p>
+</blockquote>
+
+<p>A PG&E lineman remembered:</p>
+
+<blockquote>
+ <p>“Wattenburg did most of his work at night for the next two months. He would show up
+ sometimes at two in the morning and work until dawn. PG&E would send my crew out to help
+ him whenever he wanted us.”</p>
+</blockquote>
+
+<p>Finally, Wattenburg put the word out that he had located the source of the blue water
+problem. There was a big news conference. Wattenburg showed the press some maps of how he
+had traced the electrical voltages all over the maze of water mains in the
+Danville–Blackhawk area. The voltages all followed one new water main that EBMUD had installed a few years
+earlier, the New Scenic Line, I believe. This was one of the new super-insulated water mains that
+was wrapped with a thick plastic coating so that no electrical current from the ground could get
+into the line and corrode it. Wattenburg explained that this also turned this new water main into
+a very good insulated electrical power line that could carry small electrical currents for long
+distances without the current being dissipated into the ground. Older water mains that are not so
+well insulated quickly lose any current that gets onto them.</p>
+
+<p>Walt Musso, the PG&E manager who was assigned to work with Wattenburg tells about
+the dramatic meeting that he attended with Wattenburg the day before the press conference:</p>
+<p>They met the engineering and operations managers from EBMUD at a PG&E office in
+Dublin. Wattenburg had asked them to bring their maps of the entire EBMUD water system in
+the Danville area with them. The EBMUD engineering manager had been very defiant toward
+Wattenburg all along. He had been insisting to the press that Wattenburg was just on a wild
+goose chase and a publicity stunt.</p>
+
+<p>Musso remembered that Wattenburg began the meeting with a short discussion of what
+happened to all the top BART engineers years earlier when they had refused to tell the truth about
+technical problems in the BART system that endangered many people. Then he pushed a map
+across the table to the EBMUD managers. This map showed that the voltages he had measured
+all centered around one new water main that Wattenburg had tracked for so many days and
+nights. Wattenburg let them study the map for a while. The EBMUD engineering manager said
+this was “all a lot of bullshit.”</p>
+
+<p>“Wattenburg turned to the EBMUD operations manager and told him very sternly:
+‘You know damn well that all the blue water houses are served by just this one new water main, don’t
+you?’ The engineering manager got up and walked out. The others wouldn’t answer for several
+minutes. Wattenburg confronted the operations manager: ‘You’ve known this all along, haven’t
+you? God-damn-it, I’m giving you a chance to keep your asses out of a lot of trouble. Now make
+it quick, or I’m going to turn all of my maps and yours over to the district attorney. I notice on
+your new water service maps that you carefully didn’t show which water mains all the blue water
+houses are connected to, but you show the connections for all the other houses in the
+area.’</p>
+
+<p>“The operations manager nodded sheepishly and admitted that Wattenburg was right. That
+is all he would say for a few minutes. We just sat there looking at each other in disbelief. Finally,
+Wattenburg demanded: ‘Is it true that you have known all along that the blue water houses are all
+fed from this one new line?’ One EBMUD guy tried to say that the new and old water mains are
+crisscrossed all over the area such that one house may be connected to an old line and the house
+next door is connected to the new line. Wattenburg snapped: ‘Yes, and that is why some of the
+poor bastards put their life savings into a house they thought was safe because the neighbor didn’t
+have blue water. They had no way of knowing that their dream house was connected to your
+new water main. How long have you known this?’</p>
+
+<p>“The operations manager pulled out a map that they had not shown us at the beginning of
+the meeting. He said they had just made this map ‘a few weeks ago.’ Wattenburg looked at it. It
+confirmed what he had discovered in all his work. This crude EBMUD map showed that all the
+blue water houses were connected to the New Scenic East Line. Wattenburg told them he hoped
+that they could convince a judge that they had just discovered this and hadn’t known it for all the
+time that EBMUD had been blaming the home builders and letting homeowners suffer and spend
+million of dollars… .</p>
+
+<p>“Wattenburg asked them why they hadn’t told anybody about this. The operations manager
+said that EBMUD engineers and attorneys didn’t consider it significant because it didn’t prove
+what was really causing the blue water. It just localized where it was occurring. They still insisted
+that the only copper was in the copper water pipes in the homes and that the EBMUD water lines
+couldn’t be the problem no matter how the homes were hooked up. Wattenburg told them that
+they weren’t sending the copper into the houses. EBMUD’s new water main was clearly sending
+something worse that was making the copper come off the water pipes in the blue water houses.
+‘And you guys had better find out what it is. I’m sure as hell not going to do it for
+you.’</p>
+
+<p>“The EBMUD engineering manager came back to the meeting and didn’t say a word. He
+picked up their maps and they left. Wattenburg commented as we left: ‘You want to bet that
+even the FBI won’t be able to find that one map anywhere tomorrow?’ We went over to a
+nearby bar for lunch. He curled up in his car afterwards and went to sleep.”</p>
+
+<p>Wattenburg quit the investigation after the newspapers announced his discovery of the
+“Blue Water Pipeline” (San Francisco Chronicle, September 19, 1991, page A17). He said that he
+had done his part and he didn’t want to get involved in litigation. EBMUD’s New Scenic East
+Line became known as the ’Blue Water Line’ after that. EBMUD didn’t deny it any longer. They
+organized a multi-million dollar task force to solve the problem. Later press reports say that they
+and the homebuilders are working together to try to cure the problem with the water line.</p>
+
+<p>Our professor contact says that he is surprised that Wattenburg didn’t continue with his
+research and publish the results of his investigation in the technical journals somewhere. He
+points out that blue water is still a serious problem around the world. He feels that maybe
+Wattenburg didn’t want to be associated with “corrosion engineers” whom he often described as
+“guess-work artists”. He says that Wattenburg was the only one who wasn’t paid by one side or
+the other in the controversy. He said he once asked Wattenburg whom he was working for and
+Wattenburg answered: “Me. That way I don’t have to go to court. This is what happens to you
+when you shoot your mouth off at the wrong time.”</p>
+
+</body>
+</html>
\ No newline at end of file
--- /dev/null
+++ b/lib/ebooks/oebtest/BlueWater.html.i
@@ -1,0 +1,31 @@
+14 pages
+size 400 562
+length 20263
+414 2 11 body html
+0
+1226 2 28 body html
+119
+2982 2 55 body html
+51
+3894 2 69 body html
+221
+5205 2 85 body html
+307
+5205 2 85 body html
+863
+8598 2 133 body html
+19
+8598 2 133 body html
+569
+8598 2 133 body html
+1119
+11904 2 180 body html
+323
+13529 2 206 body html
+187
+15610 2 233 body html
+0
+17216 2 253 body html
+34
+18946 2 276 body html
+0
binary files /dev/null b/lib/ebooks/oebtest/DrBill.jpg differ
binary files /dev/null b/lib/ebooks/oebtest/DrBill.png differ
binary files /dev/null b/lib/ebooks/oebtest/DrBill.tif differ
--- /dev/null
+++ b/lib/ebooks/oebtest/DrBillBio.css
@@ -1,0 +1,92 @@
+P {
+ text-align: justify
+ }
+
+P.right {
+ text-align: right
+ }
+
+P.title {
+ margin-bottom: 1em
+ }
+
+P.firstpara {
+ text-indent: 0pt;
+ }
+
+P.indentpara {
+ text-indent: 1em;
+ }
+
+.pagebreak {
+ page-break-before: right
+ }
+
+CITE {
+ text-indent: 12pt;
+ margin-top: 1em;
+ margin-bottom: 1em;
+ font-size: smaller
+ }
+
+.title {
+ text-align: center
+ }
+
+SPAN.rj {
+ text-align: right
+ }
+
+A {
+ color: blue;
+ text-decoration: none
+}
+
+DIV.image {
+ page-break-before: right;
+ page-break-after: left;
+ height: 100%
+ }
+
+BODY {
+ color: rgb(0,0,0);
+ background-color: rgb(255,255,255);
+ font-family: 'Times New Roman', Times, Serif}
+
+H1 {
+ font-weight: normal;
+ font-style: normal;
+ font-size: 24pt;
+ text-align: center;
+ }
+
+H1.title {
+ font-weight: bold
+ }
+
+H2 {
+ font-weight: normal;
+ font-style: normal;
+ font-size: 18pt}
+
+H3 {
+ font-weight: normal;
+ font-style: normal;
+ font-size: 14pt}
+
+H4 {
+ font-weight: normal;
+ font-style: normal;
+ font-size: 12pt}
+
+H5 {
+ font-weight: normal;
+ font-style: normal;
+ font-size: 10pt
+ }
+
+H6 {
+ font-weight: normal;
+ font-style: normal;
+ font-size: 8pt
+ }
\ No newline at end of file
--- /dev/null
+++ b/lib/ebooks/oebtest/DrBillBio.opf
@@ -1,0 +1,100 @@
+<?xml version="1.0"?>
+<!DOCTYPE package PUBLIC "+//ISBN 0-9673008-1-9//DTD OEB 1.0.1 Package//EN" "http://openebook.org/dtds/oeb-1.0.1/oebpkg101.dtd">
+<package unique-identifier="DrBillBio">
+<metadata>
+<dc-metadata xmlns:dc="http://purl.org/dc/elements/1.0/"
+ xmlns:oebpackage="http://openebook.org/namespaces/oeb-package/1.0">
+<dc:Title>Bill Wattenburg’s Background</dc:Title>
+<dc:Type>Biography</dc:Type>
+<dc:Identifier scheme="none">DrBillBackground</dc:Identifier>
+<dc:Subject>background report</dc:Subject>
+<dc:Publisher>PetesGuide.com</dc:Publisher>
+<dc:Contributor role="edt">Peter K. Sheerin</dc:Contributor>
+<dc:Date event="creation">1992</dc:Date>
+<dc:Date event="electronic publication">2000/09</dc:Date>
+<dc:Rights>This work was provided to me by a government agency.</dc:Rights>
+<dc:Language>en-us</dc:Language>
+<dc:Coverage>Biographical background on Dr. Bill Wattenburg</dc:Coverage>
+</dc-metadata>
+<x-metadata>
+<meta name="price" content="US $0.00" />
+</x-metadata>
+</metadata>
+<manifest>
+<item id="about" href="about.html" media-type="text/x-oeb1-document" />
+<item id="copyright" href="copyright.html" media-type="text/x-oeb1-document" />
+<item id="TofC" href="toc.html" media-type="text/x-oeb1-document" />
+<item id="titlepage" href="TitlePage.html" media-type="text/x-oeb1-document" />
+<item id="foreword" href="foreword.html" media-type="text/x-oeb1-document" />
+<item id="summary" href="ExecutiveSummary.html" media-type="text/x-oeb1-document" />
+<item id="TalkRadio" href="TalkRadio.html" media-type="text/x-oeb1-document" />
+<item id="movies" href="movies.html" media-type="text/x-oeb1-document" />
+<item id="TV" href="television.html" media-type="text/x-oeb1-document" />
+<item id="publishing" href="publishing.html" media-type="text/x-oeb1-document" />
+<item id="education" href="background-education.html" media-type="text/x-oeb1-document" />
+<item id="business" href="business.html" media-type="text/x-oeb1-document" />
+<item id="patents" href="patents.html" media-type="text/x-oeb1-document" />
+<item id="awards" href="awards.html" media-type="text/x-oeb1-document" />
+<item id="hobbies" href="hobbies.html" media-type="text/x-oeb1-document" />
+<item id="covert" href="covert.html" media-type="text/x-oeb1-document" />
+<item id="colleague" href="colleague.html" media-type="text/x-oeb1-document" />
+<item id="bloodbanks" href="bloodbanks.html" media-type="text/x-oeb1-document" />
+<item id="chainmatrix" href="HelicopterMinesweeper.html" media-type="text/x-oeb1-document" />
+<item id="confrontations" href="confrontations.html" media-type="text/x-oeb1-document" />
+<item id="BART" href="BART.html" media-type="text/x-oeb1-document" />
+<item id="creditcards" href="creditcards.html" media-type="text/x-oeb1-document" />
+<item id="carpooling" href="dial-a-ride.html" media-type="text/x-oeb1-document" />
+<item id="hiddenoil" href="MeasuringOilTanks.html" media-type="text/x-oeb1-document" />
+<item id="barrier" href="GoldenGate.html" media-type="text/x-oeb1-document" />
+<item id="bluewater" href="BlueWater.html" media-type="text/x-oeb1-document" />
+<item id="GoldMine" href="GoldMine.html" media-type="text/x-oeb1-document" />
+<item id="drillbit" href="BentSub.html" media-type="text/x-oeb1-document" />
+<item id="DrBill" href="DrBill.tif" media-type="image/tiff" fallback="DrBilljpeg" />
+<item id="DrBilljpeg" href="DrBill.jpg" media-type="image/jpeg" fallback="DrBillpng" />
+<item id="DrBillpng" href="DrBill.png" media-type="image/png" />
+<item id="raportIMG" href="raport.png" media-type="image/png" />
+<item id="QuotesFromBill" href="QuotesFromBill.html" media-type="text/x-oeb1-document" />
+<item id="QuotesAboutBill" href="QuotesAboutBill.html" media-type="text/x-oeb1-document" />
+<item id="resume" href="resume.html" media-type="text/x-oeb1-document" />
+<item id="StyleSheet" href="DrBillBio.css" media-type="text/x-oeb1-css" />
+</manifest>
+<spine>
+<itemref idref="titlepage" />
+<itemref idref="TofC" />
+<itemref idref="foreword" />
+<itemref idref="summary" />
+<itemref idref="TalkRadio" />
+<itemref idref="movies" />
+<itemref idref="TV" />
+<itemref idref="publishing" />
+<itemref idref="education" />
+<itemref idref="business" />
+<itemref idref="patents" />
+<itemref idref="awards" />
+<itemref idref="hobbies" />
+<itemref idref="covert" />
+<itemref idref="colleague" />
+<itemref idref="bloodbanks" />
+<itemref idref="chainmatrix" />
+<itemref idref="confrontations" />
+<itemref idref="BART" />
+<itemref idref="creditcards" />
+<itemref idref="carpooling" />
+<itemref idref="hiddenoil" />
+<itemref idref="barrier" />
+<itemref idref="bluewater" />
+<itemref idref="GoldMine" />
+<itemref idref="drillbit" />
+</spine>
+<tours>
+<tour id="chapterTourName" title="These are the chapters">
+<site title="TOC" href="toc.html" />
+</tour>
+</tours>
+<guide>
+<reference type="title-page" title="About This Book" href="about.html" />
+<reference type="other.ms-firstpage" title="First Page" href="TitlePage.html" />
+<reference type="foreword" title="Foreword" href="foreword.html" />
+<reference type="toc" title="Table of Contents" href="toc.html" />
+</guide>
+</package>
\ No newline at end of file
--- /dev/null
+++ b/lib/ebooks/oebtest/ExecutiveSummary.html
@@ -1,0 +1,97 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE html PUBLIC "+//ISBN 0-9673008-1-9//DTD OEB 1.0 Document//EN"
+ "http://openebook.org/dtds/oeb-1.0/oebdoc1.dtd">
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/x-oeb1-document; charset=utf-8" />
+<link rel="stylesheet" type="text/x-oeb1-css" href="DrBillBio.css" />
+<title>Bill Wattenburg’s Background: Executive Summary</title>
+</head>
+
+<body>
+
+<h1>Executive Summary</h1>
+
+<p>Bill Wattenburg is one of the most interesting, if not bizarre, media
+personalities we have ever researched. Most professional broadcasters would be
+jealous of the high celebrity Bill Wattenburg has gained on the West Coast. He
+is a ruggedly handsome and athletic man with a brilliant mind. He has both a
+voice and a presence on the air that is the envy of many in radio and
+television. He switches easily between serious intellectual and humorous
+entertainer as the occasion demands. <i>But he seems to deal with his media role
+as if it is just a pleasant hobby.</i> An ABC executive in San Francisco told us
+that he will only do radio and television shows on weekends. This position may
+be explained by his other activities and accomplishments. He is a well-known
+scientist of some notoriety in the public eye. He presently holds the title of
+research scientist at California State University, Chico, where he works during
+the week.</p>
+
+<p>A news organization may have some difficulty in forcing him to confine
+himself to reporting the news instead of trying to make the news. He has
+displayed considerable news-making desires in his very public dealings with
+government agencies. This should be of concern to a network news organization
+that must protect confidential relationships with high-level contacts in the
+government. This observation is supported by his confrontational tactics
+reported in the section <a href="confrontations.html">Public Confrontations</a>.</p>
+
+<p>We do believe, however, that he would be a very effective and popular
+network news commentator or show host. Both his credibility and integrity appear
+to be very high.</p>
+
+<p>Our contacts in the media have told us that since 1988 he has turned down
+numerous offers to host major radio and television shows in Los Angeles and New
+York as well as San Francisco. One LA radio station executive said that he
+offered Wattenburg three times his KGO Radio salary and he turned it down.
+Contacts at a major movie studio say he also passed up another movie role that was
+offered after his <a href="movies.html">appearance in two Clint Eastwood movies in 1988 and
+1989</a>, saying that he did not have the time.</p>
+
+<p>Our general impression is that it may be difficult to convince him to expand
+his media role because of his interests in his scientific work and other
+activities. From what we were able to observe of his considerable financial
+resources, it would appear that money will not be a big factor in what he
+chooses to do in the near future.</p>
+
+<h2>Our Recommendation for Executive Negotiations with Bill Wattenburg</h2>
+
+<p>For those who do not have time to read this lengthy report in full, we
+suggest three sections in particular that we believe provide the best analysis
+of his talents, his personality, and his style in dealing with professional and
+business associates. These sections are: <a href="TalkRadio.html">Talk Radio</a>,
+<a href="colleague.html">A Colleague’s Observations</a>,
+and the <a href="BlueWater.html">Blue Water project</a>. We suggest careful review of his other
+projects on the <a href="creditcards.html">Magnetic Credit Cards</a> and
+<a href="GoldMine.html">the Gold Mine</a> before any contract negotiations of
+a legal nature with him.</p>
+
+<p>An astute reviewer of this report who specializes in resolving executive
+conflicts in major corporations has offered this observation:</p>
+
+<blockquote>“His behavior appears to be iconoclastic in his dealings with other
+professionals in their own fields if they challenge him in some arrogant or pompous
+manner. This behavior pattern and an obsessive desire to maintain independence
+seem to be common elements in all his public exploits. He seems to enjoy his
+accomplishments in very private ways and is not driven by a desire for career
+advancement or immediate monetary rewards. However, this may be deceiving. He
+has obviously achieved great notoriety and professional respect in his own ways.
+This may have been financially rewarding beyond what most professionals might
+achieve in a conventional manner. In dealing with him an any business or
+professional situation, one should be on guard to not unnecessarily challenge
+his competitive instincts unless there is a major mutual objective to be
+accomplished.”</blockquote>
+
+<p><b>We strongly recommend that you see him in action <i>when he is live on the
+air in the studio</i> before making any appraisal of his media talents. In
+private interviews, he is very laid back. He responds with vigor only when you
+aggressively challenge him on some subject. Otherwise, he displays very little
+of the brilliance and wit that he delivers when he is on the air. We doubt that
+he will sell himself in an executive interview. In our interviews with him, he
+didn’t mention any of his many exploits detailed herein until we brought up the
+subjects and asked him to comment on the press reports and interviews with
+others. His attitude seems to be that if you don’t already know something about
+him, why should he tell you. He will try to deflect a conversation toward the
+interviewer (Who are you? Where are you coming from? What do you like to do?)
+This is complimentary, but often evasive.</b></p>
+
+</body>
+</html>
\ No newline at end of file
--- /dev/null
+++ b/lib/ebooks/oebtest/ExecutiveSummary.html.i
@@ -1,0 +1,11 @@
+4 pages
+size 400 562
+length 5673
+407 2 11 body html
+0
+1382 2 29 body html
+170
+3053 2 57 body html
+0
+3847 2 70 body html
+304
--- /dev/null
+++ b/lib/ebooks/oebtest/ExecutiveSummary.html.index
@@ -1,0 +1,11 @@
+4 pages
+size 400 562
+length 5673
+407 2 11 body html
+0
+1382 2 29 body html
+170
+3053 2 57 body html
+0
+3847 2 70 body html
+304
--- /dev/null
+++ b/lib/ebooks/oebtest/GoldMine.html
@@ -1,0 +1,389 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE html PUBLIC "+//ISBN 0-9673008-1-9//DTD OEB 1.0 Document//EN"
+ "http://openebook.org/dtds/oeb-1.0/oebdoc1.dtd">
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/x-oeb1-document; charset=utf-8" />
+<link rel="stylesheet" type="text/x-oeb1-css" href="DrBillBio.css" />
+<title>Bill Wattenburg’s Background: The Gold Mine</title>
+</head>
+
+<body>
+<h1>The Gold Mine</h1>
+
+<h2>(1985–1986)</h2>
+
+<p>In our 1990 report, we had no information on Bill Wattenburg’s activities for 1985 and
+1986. He declined to volunteer anything about this period during our two interviews with him in
+1990. However, we picked up some information on this period during our 1992 interview with
+him at his ranch in Plumas County, California. People in the town told us that he was working on,
+of all things, a gold mine in 1985. They told us that this venture became the largest industry in
+the area for the unemployed loggers and construction workers in Plumas County. We left one of
+our staff in the area for a week to learn about this activity. The story we got suggests that
+Wattenburg had an almost complete change of lifestyle for these two years, as well as a purpose
+in what he was doing. He returned to the profession that he learned from his father when he was
+young, that is, operating heavy construction equipment. He took on another strange challenge at
+the same time.</p>
+
+<p>The following individuals can confirm the events that we summarize below: Clifford Gibbs was the
+general manager on the job for Sunbelt. Earl Arlin, was the Sunbelt chief engineer. James Moak and
+Bill Pinkston were the job supervisors that Wattenburg hired. Attorney John Burghardt, of the law
+firm of Marshall, Burghardt & Kelleher, Chico, California, was Wattenburg’s attorney who set
+up Wattenburg’s mining company called Wattexco and handled his later negotiations with Sunbelt
+Mining Company.</p>
+
+<br />
+<p><b>Here is the story, with references to the individuals who confirmed it for us:</b></p>
+<br />
+
+<p>The logging and lumbering industry in Plumas County began to fade away in the early
+eighties. Many skilled equipment operators and mechanics in the area were unemployed. Bill
+Wattenburg’s classmates from high school and his father’s old friends were among them. They
+had asked Bill Wattenburg to help them find some new industry for the town.</p>
+
+<p>The Sunbelt Mining Company from New Mexico was planning to open a large gold mine
+near Bill’s ranch. It was called the Calgom Mine. Sunbelt had discovered an
+enormous body of low-grade gold ore under a mountain top at five thousand feet elevation. Sunbelt was going to
+put the work of extracting and transporting the gold ore out to bid to several large mining
+construction companies from Nevada and Utah. These companies typically brought in their own
+employees and their own equipment for such jobs. The idle construction equipment owned by the
+local people would not have been used by an outside mining contractor. The locals had no way
+of bidding for the job because this required posting a $2,000,000 performance bond and
+substantial operating capital that they did not have available.</p>
+
+<p>They appealed to Bill Wattenburg to get the job for them somehow when he was vacationing
+at his ranch in December 1984. Wattenburg studied the specifications for the job and
+the manner in which the standard mining companies normally did such work. He concluded that
+there was a much less expensive way to do the job using a lot of the surplus logging equipment in
+the area. But, Sunbelt did not believe that this could be done.</p>
+
+<p>Wattenburg made them an offer they couldn’t refuse. He agreed to a penalty clause in the
+contract whereby he would pay Sunbelt for any loss of projected productivity based on the
+estimates that Sunbelt had made for the progress that standard mining companies should achieve.
+Furthermore, he would start the work immediately that winter (December 1984), whereas the
+other mining companies would not start until the snow melted in the spring. Sunbelt agreed to let
+him try it.</p>
+
+<p>The rest appears to be typical Bill Wattenburg. Local workmen and supervisors at the
+Calgom mine told us numerous stories of the unorthodox and “absolutely crazy” things that
+Wattenburg organized with the local workmen and their equipment that winter.</p>
+
+<p>Wattenburg used his own bulldozer and personally built a road to the top of the mountain
+during the Christmas week of 1984. He then put out the call for all the locals who wanted to go to
+work with their equipment, Several workmen told us that they all got a lecture when they first
+arrived. Wattenburg told them that they had no damn business even trying to beat the big mining
+companies at their own game. But if they wanted to try, he had a plan. He told
+them, “Of course, if you don’t think it will work, you can always go back home where it is nice and warm
+and slowly go bankrupt.” The workmen told us that everybody stayed.</p>
+
+<p>The first task was to cut 2,000,000 tons of “overburden” dirt and rock off the top of the
+mountain and move it a half mile away where it was dumped into a deep canyon. Overburden is
+the dirt and rock on top of the ore body beneath it. The gold ore body was at a depth of a two-hundred
+feet below the surface. Mining companies use very large off-highway trucks for this kind of
+job where the dirt has to be moved some distance. They dig the dirt with enormous excavators
+and load it into the trucks that haul it away. These machines typically cost $200,000 to $400,000 apiece.
+The loggers had no such equipment. All they had were medium-sized bulldozers and small loaders.</p>
+
+<p>They said that Wattenburg told them: “Well, if we can’t haul the damn dirt, I guess we’ll
+just have to push it where we want it to go.” The problem was that a bulldozer is only good for
+pushing dirt very short distances. The dirt falls away from the bulldozer blade if you try to push a
+blade-full of dirt more than a few hundred feet. But Wattenburg showed them how to do it
+anyway.</p>
+
+<p>Here is how one seasoned operator described it: </p>
+
+<blockquote>
+<p>“He dug a big trench starting from the top and all the way down the side of the mountain to the canyon. This trench was about six feet
+deep and just the width of a bulldozer blade. We stood around wondering what the hell he was
+doing. We thought maybe he was going to run water down this trench to carry the dirt away.
+But then he put maybe five or six of us on bulldozers to start pushing dirt on the mountain top
+into this trench, up at the top of the trench. Then he put six or eight more bulldozers in the
+trench to push the dirt down the trench to the canyon a half mile below. He lined them up one
+right after the other in the trench. He had to teach a lot of us how to keep a load of dirt in front
+of the bulldozer blade without loosing it all on the way down. You know, his daddy taught him
+how to give you a shave with a bulldozer blade if you sit still. … When the dozers reached the
+bottom, they just climbed out of the trench and went back up another road to get another load of
+dirt at the top. We thought it would be tough trying to push dirt with a dozer down that trench
+that far, but it was easy once you got the hang of it. Hell, in a couple of days we were moving
+20,000 tons a day. That’s more than you can haul in trucks that cost three times as much to own
+and operate. … Some of the guys had dozers that were so old and worn out that they could hardly
+climb back up the mountain. It was pathetic. But Bill just told the others guys with new
+equipment to give the old boys a push back up the mountain. The old dozers did just as good as
+the new ones when they were pushing dirt down the hill. … Bill fired one guy with a new Cat
+who was complaining about helping the others. He told this asshole that he could go back home
+and wait by the fire for the bank to come and repossess his new bulldozer. … The guy should have
+realized that Bill’s father always had to work with beat up old equipment. He never could afford
+a new piece of equipment in his life.”</p>
+</blockquote>
+
+<p>The former Sunbelt chief engineer, Earl Arlin, told us that his bosses from Sunbelt
+headquarters came out and saw what Wattenburg was doing and got unhappy as hell. He was
+moving the dirt with loggers and cheap equipment for less than half the cost that Sunbelt had
+estimated it would cost a mining company using regular loaders and big trucks. And they had
+agreed to pay Wattenburg what they were going to pay the other contractors. Wattenburg and
+the loggers were obviously making a killing.</p>
+
+<p>Mr. Arlin remembers that the Sunbelt executives called Wattenburg into a meeting where
+they tried to get him to modify their contract. Wattenburg asked them what they would be saying
+if they had discovered that he was behind on schedule instead of ahead of schedule. Arlin says
+that they just looked at him and smiled. They admitted that they would be fining him for lost
+productivity. At that, Wattenburg told them that he appreciated honest men and he
+would consider reducing the amount they were paying him because he was moving the dirt for much less than
+even he thought was possible. He offered to reduce his payments by ten percent. They wanted
+him to reduce it by twenty percent. They settled on a fifteen percent reduction. The Sunbelt
+executives went home to New Mexico very happy. They told Wattenburg that he could have all
+the work he wanted in the future. Mr. Arlin suggests that he knew something was wrong.
+Contractors just don’t give up money. They usually sue you for more.</p>
+
+<p>Mr. Arlin laughed as he told us: “By the next week, Wattenburg’s crazy crew was moving
+30,000 tons a day down the mountain, not 20,000! Hell, they were now making more money than
+they were before he gave Sunbelt back the fifteen percent reduction. Some of the
+poor loggers were making more money in a week than they made all year when they were starving to death
+working in the logging woods with their equipment.”</p>
+
+<p>Wattenburg paid each of the loggers a percentage of the total income he received so that
+the more dirt they moved the more money they made. One workman told us that most of them
+were fighting over who could work two shifts a day. He said that he made as much as $1000
+dollars a day. He was able to pay off the loan on his bulldozer in two months. He said they were
+working in four feet of snow most of the time that winter, and yet they were as happy as a bunch
+of kids playing at a ski resort.</p>
+
+<p>Wattenburg’s job supervisors James Moak and Bill Pinkston told us that the one who was
+having the most fun was Bill Wattenburg. “He couldn’t be on the job during the day because he
+had to be at the university in Chico during the weekdays, but he came up and worked the
+graveyard shift most nights. He loved to get on a big Cat and push dirt. Everybody else got their
+asses in gear when he was there. The two daytime shifts had to go like hell to keep up with the
+graveyard shift. Chico was only an hour away. Some of the equipment operators lived down
+there. They would pick him up at 11pm and get him back to Chico in the morning by 9am. We
+had our management meetings with him on weekends.”</p>
+
+<p>Wattenburg’s crew finished the first phase of the job in April 1985. This was a month
+earlier than the other companies could even have started. Apparently, his company, Wattexco,
+made so much money that he was able to buy a new fleet of bulldozers and earth movers (called
+scrappers) for the second phase of the job.</p>
+
+<p>The second phase was to start digging the gold ore out of the enormous open pit they had
+made at the top of mountain and then transport the ore to the processing plant two miles down
+the mountain. His contract with Sunbelt included this work at a predetermined price which,
+again, was based on what other mining contractors normally charged. Sunbelt was soon very
+unhappy about this, according to those on the scene we talked to.</p>
+
+<p>Supervisors Moak and Pinkston told us that Wattenburg again figured out a way to do
+this next job for about half the estimated costs. Instead of using big trucks to haul the ore down
+the mountain, he told them that they were going to use the rubber-tired Cat earthmovers
+(scrappers) they already had. Wattenburg told them that this way they wouldn’t have to use
+extra loaders to dig the ore and load big haul trucks—and they didn’t have to buy ten of the
+$200,000 trucks either. He argued that the scrapers could load themselves with bulldozers
+pushing them. Once they were loaded, they could go straight down the road to the plant. The
+equipment operators protested that no one in his right mind would do this because these big
+earthmovers are not designed to go long distances downhill with a load of fifty tons of dirt. They
+don’t have enough brakes to keep from running away. Everyone told him it was suicide.</p>
+
+<p>They said that Bill Wattenburg got on the first scrapper and showed them how to do it.
+They recall that he made all the nervous scrapper operators walk alongside the loaded scrapper
+and watch what he was doing as he slowly took it down the hill. An hour later, they were all
+going down the mountain in their scrappers with fifty-ton loads.</p>
+
+<p>Wattenburg’s scheme was something that no decent equipment operator would ever do.
+He told them to drag their scrapper blades on the dirt road surface as they went down the
+mountain. This would give them the braking power they needed. (The scrapper blade is what
+digs the dirt up as a scrapper is being loaded.) Any operator would be fired on a normal
+construction job if he ever let his scrapper blade dig into the road he was running over after he
+was loaded. This would tear up the road as well as wear out the expensive steel cutting edge on
+the scrapper blade.</p>
+
+<p>But this wasn’t a normal job, Wattenburg told them. Supervisor Moak remembers that
+Wattenburg told them: “I am the one who pays for the scrapper blades, and who cares about the
+goddamn road! So you cut the surface level of the road down ten feet over the next year? So
+what? I could have built that damn dirt road ten feet lower to begin with. When we’re through,
+I’ll put it back where it was when we began. You guys just get your asses down that road with
+all the ore you can haul, and I’ll worry about the rest.”</p>
+
+<p>One of Wattenburg’s equipment mechanics told us that he hired two more unemployed
+mechanics to work every night to replace the worn-out blades on the scrappers. He said that a
+truck load of new scrapper blades worth about ten thousand dollars was delivered to the job each
+week. “Normally, you wouldn’t use this many scrapper blades on a job in a year.”</p>
+
+<p>The Sunbelt manager on the job, Mr.Gibbs, said that he soon figured out what
+Wattenburg was doing. The ten thousand dollars worth of scrapper blades each week was only
+about one-tenth of the cost of the only other alternative, that is, using conventional haul trucks to
+do the job the way that mining contractors would do it. He realized that Wattenburg was making
+a killing again. He was probably digging and hauling the ore for about 60 percent of the normal
+cost of $1.40 per ton. There was at least 4,000,000 tons of ore to be hauled. Wattenburg was
+being paid $1.50 per ton under his contract. That meant that he was going to make about sixty
+cents a ton profit instead of the usual ten cents a ton. It wasn’t long before the Sunbelt executives
+from headquarters in New Mexico wanted another meeting with Wattenburg.</p>
+
+<p>Wattenburg agreed to a ten percent reduction in what they were paying him to deliver the
+ore. But Wattenburg made them agree to give him the third phase of the job which was to build
+the biggest part of the gold processing plant, the buildings and the laboratory. They gave him the
+job on a time and materials basis plus ten percent profit because they had learned their lesson with
+this guy and they figured that he already knew some way to do this job at a lot less cost. The
+local Sunbelt building supervisor objected like hell because he had his own favorite contractor
+from New Mexico already lined up to do the job, but the headquarters guys insisted that they had
+just cut “a hell of a deal with Wattenburg that would save the company six hundred thousand
+dollars.” Arlin told us:</p>
+
+<blockquote>
+<p>“I knew this guy Wattenburg had something up his sleeve again.”</p>
+
+<p>“Sure enough, the next week the place looked like a flea market with all the characters
+who showed up in beat-up old pickups with a hammer or a saw in their hands. Wattenburg hired
+just about every unemployed carpenter and small building contractor in the county. He gave
+them all a piece of the action and turned them loose. They had the damn buildings up in about
+half of the time we expected. You know, this meant that he got paid for what the contractors
+charged to do the job, plus he got a ten percent profit on top of that. But nobody in headquarters
+complained. He got the job done for about ten percent less than we expected.</p>
+
+<p>…</p>
+
+<p>“Later one of our engineers sat down and figured out how much lumber we paid for on
+that building job. It turned that we paid for about twice as much lumber as they used in the
+finished buildings! Right then we realized that these hick contractors who built the buildings for
+us probably were building something for themselves somewhere else at the same time. Where
+else could that much lumber have gone?</p>
+
+<p>“When we asked Wattenburg about this, he said: ‘I sure as hell don’t need to steal lumber.
+But you corporate guys have got to realize that life is pretty rough for these people who have to
+make a living up here nowadays. Most of their families never dreamed of having a home. What
+are you bitching about? They saved you a lot of money, didn’t they?.’ We dropped the subject.”</p>
+</blockquote>
+
+<p>The Calgom Mine was in full operation by August 1985. They began producing
+3,000 to 4,000 ounces of gold a month. Wattenburg was building one of the biggest fleets of dirt moving
+equipment anywhere to deliver the ore from the mountain top to the processing plant. He bought
+every used D9 Cat bulldozer and Cat 631C scrapper he could find on the west coast, according to
+Mr. Al Pissetti, Dillingham Construction Co., Benicia, Ca., and Mr. Roger Ash
+of Wershow, Ash and Lewis, Equipment Auctioneers of Los Angeles and Portland, Oregon.</p>
+
+<p>Mr. Pissetti told us that Wattenburg once called him up in the summer of 1985 and
+bought two of Dillingham’s used D9 bulldozers, sight unseen, for $50,000 apiece. But
+Wattenburg wanted them delivered to the mine site the next day. Pissetti said he had never heard
+of anything like that before. He said that Wattenburg told him on the phone: “I believe you
+when you tell me that the bulldozers are in good shape. If you’re lying to me, you’ll find out who
+I am quick enough.” Pissetti said that he called the bank and found out that Wattenburg had
+already wired the money to the Dillingham account—and the banker told him who Wattenburg
+was. He said he found some truckers to haul the bulldozers to Plumas County that afternoon.
+(Our staff saw pictures in the bars and restaurants in the area in 1992 which showed
+Wattenburg’s enormous fleet of equipment working at the open pit mine in 1985).</p>
+
+<p>Wattenburg was employing 100 equipment operators by that time to run the equipment
+around the clock, seven days a week. He even rented a restaurant to feed them. We were told
+that the reason he did that was too encourage the operators to show up on time. Loggers and
+construction workers are evidently notorious for having hangovers on Monday mornings. He
+gave them free meals if they showed up on time before the shift started. If they were late, they
+didn’t get any free meals for a week after that.</p>
+
+<p>After the mine had been in full operation for only six months, Sunbelt Mining Company
+executives decided that it would be to their advantage to buy out Wattenburg. He was making
+more money than they were, and they owned the mine.</p>
+
+<p>Wattenburg gave us permission to talk to his attorney, John Burghardt at the law firm of
+Marshall, Burghardt, and Kelleher, Chico, California. Burghardt handled the final negotiations with Sunbelt for him. Burghardt told us that Sunbelt first said that they were
+going to get another contractor who could deliver the ore at a lower price. Bill Wattenburg’s
+answer was, “be my guest”. Evidently, Sunbelt couldn’t find another contractor at a lower price
+than they were paying Wattenburg. Burghardt said that he then realized why Wattenburg had
+earlier given them the reduction in price that he, Burghardt, had opposed. He said that
+Wattenburg must have known that this would eventually happen and that no one else would be
+able to do the job any cheaper. But Wattenburg was still making a good profit. By not being
+too greedy, Wattenburg had put Sunbelt in a real bind.</p>
+
+<p>They negotiated for several months. Wattenburg said that he just wanted to keep on
+working because the job was providing employment to so many local workmen. Sunbelt
+finally offered to keep most of Wattenburg’s employees if he would sell. Wattenburg agreed to a
+deal whereby Sunbelt would buy his company, Wattexco, and as much of his equipment as they
+needed to operate the mine, but it would have to be all cash.</p>
+
+<p>Burghardt told us about the scene when he appeared with Wattenburg at the Sunbelt
+office to sign the papers and collect the cashier’s check that Wattenburg had demanded:</p>
+
+<blockquote>
+<p>“The Sunbelt representative came with several lawyers and accountants in three piece
+suits. Wattenburg was in his boots and greasy Levis. At the last minute, the Sunbelt boss
+announced that they had thought it over and determined that Wattenburg’s equipment was not
+worth what they had earlier agreed upon. He pushed a cashier’s check across the table to
+Wattenburg. It was for $200,000 less than what it was supposed to be. But it was still more
+money than I had ever seen. My heart started pounding. I nudged Wattenburg to take it, and let’s
+get out of there before they change their minds completely. But, Wattenburg just
+slid the cashier’s check back across the table and told them that if they were a little short of money, he
+might be interested in buying out their interest in the mine. They had a meeting in the next
+room for a while and finally came back with another check for the missing $200,000.
+Wattenburg handed me the check, we shook hands with them, and he motioned for us to go.
+There was no more conversation. That was it—It was all over.”</p>
+</blockquote>
+
+<p>Burghardt told us he was sweating when he left. Wattenburg said to him later:</p>
+
+<blockquote>
+<p>“Don’t feel bad about leaving without sticking around for small talk. Those Wall Street lawyers always
+pull that bullshit of bringing two or more checks to a closing to see if they can get an anxious
+seller to chicken out at the last minute and take less money. They figure most suckers are so
+anxious to get a few million dollars cash in their hands that they will always take a few hundred
+thousand less. That way they can go back to headquarters and brag about how much money they
+saved the company. But when you call their bluff, they feel sort of stupid on the spot. It’s best
+not to rub it in by sticking around too long. You might have to deal with them again someday.”</p>
+</blockquote>
+
+<p>Attorney Burghardt said that this was his trial-by-fire in corporate mergers. Burghardt
+admitted that he didn’t realize what Wattenburg really knew about big business until after this was
+all over. Much later he learned that “this guy in greasy Levis” had built and sold two high-tech
+companies to the Wall Street crowd before he got in the dirt moving business. He said that he
+later realized that Wattenburg had been playing a chess game with them all along, but that
+Wattenburg was always about three moves ahead of them. “I was his attorney, but he never
+really told me what he had up his sleeve.”</p>
+
+<p>In terms of how much money Wattenburg made, Attorney Burghardt would only volunteer: “He did all right, but he didn’t walk away with what he could have by any means. He
+got his capital back with a decent profit and he created thirty million dollars of business in the area
+and a lot of jobs. I’m sure he could have made a lot more money doing other things for the time
+he put in.”</p>
+
+<p>Calgom Mine chief engineer Earl Arlin, now retired, was on the job every
+day supervising the mining operation. He probably saw more of this story first-hand than anyone.
+He was an engineer on major mining jobs for thirty years. His analysis of the scene may be the
+best overall:</p>
+
+<blockquote>
+<p>“I knew who this fellow Wattenburg was. I listened to him on the radio for years. It
+was always hard to believe that he was up there running a bulldozer or fixing a piece of broken-down equipment in the middle of the night. It was not
+surprising what he did. I knew he wouldn’t do things in ordinary ways. I sort of felt sorry for my own company
+every time they negotiated a contract with him.</p>
+
+<p>…</p>
+
+ <p>“He gave those old loggers their moment of glory and the chance to do one big job. I
+ think he wanted them to know that they could be somebody … that they could do better than the
+ big-city contractors with all their new equipment. … He was reliving his childhood. I don’t think it
+ was just the money. I think he had been dreaming about going back and doing something like
+ this in the construction business that would have made his father proud.</p>
+
+<p>…</p>
+
+<p>“When a man drives his new Mercedes up a dirt road with greasy tools in the back seat, he
+is not there because he has to be. … We had calls coming into the office for him all the time from
+important people in San Francisco and Hollywood and Washington. He wouldn’t come down off
+the mountain to call them back, and he wouldn’t use the portable telephones we gave him
+either. … He left a lot of his money on the table to take care of the people who worked with him. In the
+deal he made with Sunbelt, they didn’t buy all of his equipment by any means. But he agreed to
+leave some of his extra equipment on the job for us to use, I mean big bulldozers and scrappers.
+He let us use that equipment for free so long as we employed some of his old-timers from
+the area to operate the equipment. They had jobs for the next two years … some of those old
+boys were running new bulldozers that they never before in their lives even dreamed of touching
+All the next year, he would stop by the job whenever he was in town and just watch his old
+crew working on the mountain. He’d climb on a Cat and do a little work while the crew was
+having lunch or he’d give some suggestions to the mechanics working on a piece of equipment
+that broke down. He never came in the office to tell us how we ought to be running the
+operation.</p>
+
+<p>…</p>
+
+<p>“We had one real emergency in the winter of 1986. Heavy rains for two weeks almost
+washed out our cyanide ponds. The mine would have been out of business if the cyanide had
+washed into the river below. Wattenburg showed up with a truckload of big water pumps that
+we hadn’t been able to rent from anybody because everybody in northern California was being
+flooded. He stayed up there to help us day and night for almost a week. We asked him later
+where he found the pumps we needed. He told us that Dillingham Construction Company, the
+big contractor in Benicia, owed him a favor. He never sent us a bill.”</p>
+</blockquote>
+
+</body>
+</html>
\ No newline at end of file
--- /dev/null
+++ b/lib/ebooks/oebtest/GoldMine.html.i
@@ -1,0 +1,41 @@
+19 pages
+size 400 562
+length 27915
+403 2 11 body html
+0
+1423 2 28 body html
+102
+3201 2 54 body html
+0
+4386 2 71 body html
+136
+6172 2 95 body html
+35
+6172 2 95 body html
+595
+8711 2 126 body html
+221
+10645 2 151 body html
+102
+12119 2 171 body html
+136
+13973 2 195 body html
+51
+15711 2 217 body html
+0
+16511 2 227 body html
+262
+18082 2 252 body html
+119
+19539 2 270 body html
+170
+21599 2 297 body html
+0
+22887 2 315 body html
+0
+23693 2 327 body html
+187
+24997 2 345 body html
+249
+24997 2 345 body html
+799
--- /dev/null
+++ b/lib/ebooks/oebtest/GoldMine.html.index
@@ -1,0 +1,41 @@
+19 pages
+size 400 562
+length 27949
+403 2 11 body html
+0
+1423 2 28 body html
+102
+3203 2 54 body html
+0
+4388 2 71 body html
+136
+6182 2 95 body html
+35
+6182 2 95 body html
+595
+8721 2 126 body html
+221
+10655 2 151 body html
+102
+12129 2 171 body html
+136
+13987 2 195 body html
+51
+15729 2 217 body html
+0
+16529 2 227 body html
+262
+18102 2 252 body html
+119
+19559 2 270 body html
+170
+21619 2 297 body html
+0
+22907 2 315 body html
+0
+23713 2 327 body html
+187
+25025 2 345 body html
+249
+25025 2 345 body html
+799
--- /dev/null
+++ b/lib/ebooks/oebtest/GoldenGate.html
@@ -1,0 +1,68 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE html PUBLIC "+//ISBN 0-9673008-1-9//DTD OEB 1.0 Document//EN"
+ "http://openebook.org/dtds/oeb-1.0/oebdoc1.dtd">
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/x-oeb1-document; charset=utf-8" />
+<link rel="stylesheet" type="text/x-oeb1-css" href="DrBillBio.css" />
+<title>Bill Wattenburg’s Background: Golden Gate Bridge Traffic Barrier</title>
+</head>
+
+<body>
+
+<h1>Golden Gate Bridge Traffic Barrier</h1>
+
+<h2>(1982–1984)</h2>
+
+<p>Another series of newspaper articles in 1982–1984 describe how Wattenburg did the
+“<a href="BART.html">BART story</a>” again on the over-confident Golden Gate Bridge
+engineers who insisted that a moveable
+anti-collision barrier could not be designed that would fit between the traffic lanes on the bridge
+and meet the requirement that it be moved twice each day to allow reallocation of the lanes for
+rush hour flow. The Bridge’s private engineering firm was being paid over a million dollars a
+year to advise the bridge district. Numerous fatal head-on collisions had made this a very
+controversial subject. A frustrated bridge director called on Wattenburg to find a solution. A few
+weeks later he came up with a design that stunned the confident engineers—and evidently
+fascinated the press and the public because it was so simple.</p>
+
+<p>His solution was to use sections of large-diameter (24″) round steel pipe which are strung together
+on a strong steel cable like a spaghetti necklace. He later proved that the steel pipe is as strong as
+conventional concrete lane dividers. The steel pipe can be rolled from lane to lane quite easily to
+change traffic flow patterns. Once Wattenburg had proved that the problem could be solved by at
+least one inexpensive scheme, two other companies quickly came forth with alternate designs of
+their own. Internal politics over where and how money should be spent on bridge improvements
+has delayed installation of any of these anti-collision barriers to date. However, other bridges
+around the world have installed movable traffic barriers which are renditions of Wattenburg’s
+patented design that he offered to give the Golden Gate Bridge District free-of-charge.</p>
+
+<p>The head of one embarrassed engineering firm working for the bridge district attacked
+Wattenburg’s credentials to be doing work for the district without having a license as a
+professional engineer (he evidently assumed that Wattenburg must be getting paid). Wattenburg’s
+terse response to the press was: “I don’t take public money for exposing high-priced fools who
+pretend to be competent engineers.”</p>
+
+<p>Bill Wattenburg and his son, Eric, who was an engineering student at California State
+University, Chico, were issued a patent on their movable pipe barrier design in 1987. His son
+had designed the mechanism that automatically rolls the pipe barrier from lane to lane while
+keeping it tied down securely to the bridge deck or roadway at all times. Wattenburg said that he
+was about to give up on the pipe barrier idea because he hadn’t solved this problem. Eric picked
+up the problem one weekend and found a clever solution that made the whole scheme practical.
+Eric built a fully operational scale model that he demonstrated to the Golden Gate Bridge
+Directors.</p>
+
+<p>Wattenburg told us that movable pipe barriers are still the cheapest and best traffic barriers
+that can be quickly installed around many places that could be attacked by vehicles carrying
+bombs or terrorists, such as government buildings, embassies oversees, and troop encampments
+in hostile places. “The military will get around to it someday, after we lose another few hundred
+of our people.”</p>
+
+<hr />
+
+<p><i>Note: It took until late 1998 before anyone paid serious attention to
+Wattenburg’s idea of using the barrier to protect against truck bombs. The San
+Francisco Chronicle reported
+on the successful testing performed by Lawrence Livermore National Labs (October 8, 1988).
+Unfortunately, the device still has not been used to this date.—PKS</i></p>
+
+</body>
+</html>
\ No newline at end of file
--- /dev/null
+++ b/lib/ebooks/oebtest/GoldenGate.html.i
@@ -1,0 +1,9 @@
+3 pages
+size 400 562
+length 4104
+424 2 11 body html
+0
+1348 2 28 body html
+136
+3318 2 53 body html
+0
--- /dev/null
+++ b/lib/ebooks/oebtest/HelicopterMinesweeper.html
@@ -1,0 +1,41 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE html PUBLIC "+//ISBN 0-9673008-1-9//DTD OEB 1.0 Document//EN"
+ "http://openebook.org/dtds/oeb-1.0/oebdoc1.dtd">
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/x-oeb1-document; charset=utf-8" />
+<link rel="stylesheet" type="text/x-oeb1-css" href="DrBillBio.css" />
+<title>Bill Wattenburg’s Background: Helicopter Minesweeper</title>
+</head>
+
+<body>
+
+<h1>Helicopters to Clear Minefields</h1>
+
+<h2>(1990)</h2>
+
+<p>His most recent invention is a new device for clearing minefields out of war zones during
+the Gulf War. He designed a thing called a “chain matrix” which is pulled by a helicopter over the
+ground to dig up the mines and explode them without endangering people. The story (San
+Francisco Chronicle, March 8, 1991, front page) picked up the human interest side because he
+had used a small blacksmith’s shop in a farming town to build the first prototypes and local
+farmers to test the devices when major defense contractors would not move fast enough to please
+him.</p>
+
+<p>Wattenburg really didn’t want to talk about it beyond what was disclosed in the many
+press stories about his helicopter minesweeper. He told us to contact the Livermore National
+Laboratory for anything more we wanted to know. He mentioned that some parts of his design
+were now classified and that the full details of the design were not disclosed to the press for
+obvious reasons. He did say that the version that was tested at the Yuma Proving Grounds was
+“not quite as clumsy and contained things a little more sophisticated than what the newspaper
+stories showed.”</p>
+
+<p>The Livermore Lab spokesperson would not comment beyond the press stories. He did
+say that Wattenburg would soon be issued a patent on the unclassified portions of the
+minesweeper design. He said that this device also appears to have great application in farming
+operations in areas where the ground is very rocky. He said that Livermore engineers were
+already in contact with manufacturers of agriculture equipment. He laughed when he told us that
+“Wattenburg says that the last thing he ever wants to see again is a farm.”</p>
+
+</body>
+</html>
\ No newline at end of file
--- /dev/null
+++ b/lib/ebooks/oebtest/MeasuringOilTanks.html
@@ -1,0 +1,76 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE html PUBLIC "+//ISBN 0-9673008-1-9//DTD OEB 1.0 Document//EN"
+ "http://openebook.org/dtds/oeb-1.0/oebdoc1.dtd">
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/x-oeb1-document; charset=utf-8" />
+<link rel="stylesheet" type="text/x-oeb1-css" href="DrBillBio.css" />
+<title>Bill Wattenburg’s Background: Don’t Call the FBI!</title>
+</head>
+
+<body>
+
+<h1>Don’t Call the FBI!</h1>
+
+<h2>(1974)</h2>
+
+<p>This next story amused our staff to no end when they found the first of the newspaper
+stories. Wattenburg seemed excited himself when we showed him how widely the story had been
+publicized around the world. He said that he hadn’t realized it at the time.</p>
+
+<p>In 1974, Wattenburg again embarrassed government scientists and bureaucrats alike. He saved
+the country millions of dollars during the first oil crisis when he showed that he could measure
+how much oil was in oil refinery storage tanks by simply pointing a special infra-red camera at the
+tanks from a distance. This story was first reported in the San Francisco Chronicle, February 6,
+1974, with the headline: “How to See Inside Their Oil Tanks”.</p>
+
+<p>During the oil crisis, Energy Department officials announced that they were going to use
+a thousand FBI agents to crawl into all the oil tanks in all the refineries of the country to see how
+much gas and oil the oil companies were hoarding. Embarrassed officials in Washington quickly
+cancelled their plans to use FBI agents after the story of Wattenburg’s feat was carried by the
+wire services all over the country.</p>
+
+<p>Wattenburg treated the viewers of the ABC network to a dramatic film that showed how he
+stood back at a distance and measured the oil levels in all the storage tanks at the Richmond,
+California, Chevron Oil Co. refinery—without really trying! As his special TV-like camera
+scanned the tank farm, the screen showed the surface of each oil tank glowing brightly up to the
+liquid level in the tank. The empty upper portion of each tank showed black. The liquid levels of
+a hundred oil tanks in the distance could be measured to an accuracy of 5% just by looking at
+their images on the camera screen.</p>
+
+<p>Wattenburg had made the film in a few minutes using a commercially available infra-red TV
+camera—from a distance of a mile away! He showed that the government could easily measure
+the oil in all the refinery tank farms of the country. He proved that they could do this in a day by
+simply flying over the tank farms with military reconnaissance aircraft that carried the same infra-red camera. </p>
+
+<p>This is the story he gave one reporter at the time:</p>
+
+<blockquote>
+ <p>The idea came to him when he remembered that water tanks on the farms near where he
+ grew up often had a very visible dew line on them early in the morning because the portion of the
+ tank filled with water stayed at a warmer temperature overnight than the empty upper portion that
+ was cooled down by the nighttime air temperature. Conversely, the sun warmed the upper
+ surface more quickly than the lower surface in the afternoon. This meant that the portions of oil
+ tanks filled with oil would be warmer in the morning and cooler in the evening than the empty
+ portions which followed the local air temperature. This temperature difference is easily measured
+ and displayed by infra-red TV cameras of the kind Wattenburg borrowed for his dramatic
+ experiment (Thermovision by AGA Corporation). This technology was first developed for satellite
+ reconnaissance of rocket launchings (Wattenburg worked on this as a consultant to Lockheed
+ Missiles and Space Co. in 1965–1968.)</p>
+
+ <p>The congressional subcommittee that had initially insisted that the Energy Department use
+ FBI agents later asked Wattenburg to testify at a hearing in Washington. They wanted to
+ investigate why the Energy Dept. had not thought of his idea. He wrote the committee staff a
+ widely publicized letter in which he gave them complete instructions on how to do it themselves
+ and where they could find a suitable infra-red camera in the Pentagon! He suggested that this
+ would save the taxpayers his airfare—and that “they would really find it a lot more fun to do it
+ themselves.”</p>
+
+<p>The subcommittee staff insisted that he appear. Then he wrote back that he would be
+ delighted to appear because he had “just discovered something else that your subcommittee has
+ told a government agency to do that is even more foolish than using FBI agents to crawl into oil
+ tanks.” They evidently cancelled the hearing.</p>
+</blockquote>
+
+</body>
+</html>
\ No newline at end of file
--- /dev/null
+++ b/lib/ebooks/oebtest/MeasuringOilTanks.html.i
@@ -1,0 +1,11 @@
+4 pages
+size 400 562
+length 4646
+411 2 11 body html
+0
+1614 2 33 body html
+0
+2685 2 48 body html
+147
+2685 2 48 body html
+697
--- /dev/null
+++ b/lib/ebooks/oebtest/QuotesAboutBill.html
@@ -1,0 +1,52 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE html PUBLIC "+//ISBN 0-9673008-1-9//DTD OEB 1.0 Document//EN"
+ "http://openebook.org/dtds/oeb-1.0/oebdoc1.dtd">
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/x-oeb1-document; charset=utf-8" />
+<link rel="stylesheet" type="text/x-oeb1-css" href="DrBillBio.css" />
+<title>Bill Wattenburg’s Background: Quotes About Bill Wattenburg</title>
+</head>
+
+<body>
+
+<html>
+
+<h1>Quotes about Bill Wattenburg</h1>
+
+<p>From a well-known scientist who once worked with Wattenburg:</p>
+
+<blockquote><q>If anyone has spent $10 or $20 million on a difficult technical problem and not
+found a solution, they probably should have asked Bill Wattenburg First.</q></blockquote>
+
+
+<p class=pagebreak>Said to Bill by a woman who pulled up next to his Mercedes 280SL in traffic (his licence
+plate read “PILL”):</p>
+
+<blockquote><q>Hey, thanks for reminding me!</q>—<i>SF Chronicle, Aug. 16,
+1974, p. 25, in Herb Caen’s column.</i></blockquote>
+
+<p class="pagebreak">From a colleague at the Nevada nuclear weapons test site:</p>
+
+<blockquote><p><q>He was always looking for the simple solution that everyone else had
+ overlooked. His favorite saying was: <q>A smart cowboy just wouldn’t work
+ this hard to make things so goddamn difficult.</q> Then he would throw up his
+ hands and go off to tease the ladies in some local bar down the highway
+ while the rest of us were working our butts off.</q></p>
+ <p><q>You are always wondering when he is going to make a fool out of
+ you, and do it in some simple way or with some crazy experiment that
+ forces you to stand and applaud your own ignorance.</q></p>
+ <p><q>But if you want to know what I really think of him, I’ll tell
+ you. If I am ever trapped in a spaceship and everyone says it is hopeless,
+ I hope he is still around, and near a telephone…</q></p></blockquote>
+
+<p class="pagebreak">From a U.S. Forest Service Supervisor in Plumas County, Calif.:</p>
+
+<blockquote><q>There are not many old pros like him left anymore who can chase a forest fire on
+a bulldozer in the night over mountains so rugged that you can’t walk on them. I mean fire crews
+won’t go where he takes a bulldozer. This guy attacks a fire just like it was trying to kill his
+kids. We called him once when he was on the radio in San Francisco—we just needed his equipment
+on the fire. He was on the fire <i>himself</i> four hours later.</q></blockquote>
+
+</body>
+</html>
\ No newline at end of file
--- /dev/null
+++ b/lib/ebooks/oebtest/QuotesFromBill.html
@@ -1,0 +1,82 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE html PUBLIC "+//ISBN 0-9673008-1-9//DTD OEB 1.0 Document//EN"
+ "http://openebook.org/dtds/oeb-1.0/oebdoc1.dtd">
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/x-oeb1-document; charset=utf-8" />
+<link rel="stylesheet" type="text/x-oeb1-css" href="DrBillBio.css" />
+<title>Bill Wattenburg’s Background: Quotes From Bill Wattenburg</title>
+</head>
+
+<body>
+
+<html>
+
+<h1>Quotes From Bill Wattenburg</h1>
+
+<p>In response to a California state Senator asking his opinion of BART management:</p>
+
+<blockquote><q>I’m still looking for the front end of the horse.</q>—<i>SF Chronicle,
+Nov. 19, 1973, p. 29 in Herb Caen’s column.</i></blockquote>
+
+<p class="pagebreak">To the Maitre d’Hotel (while slipping him $20) after his date made him take back a bottle of
+wine—but one of many complaints:</p>
+
+<blockquote><q>Take <i>her</i> away!</q>—<i>San Francisco Chronicle, Apr. 19, 1974,
+p. 27, in Herb Caen’s column.</i></blockquote>
+
+<p class="pagebreak">Describing BART General Manager Billy Stokes at a Commonwealth Club meeting:</p>
+
+<blockquote><q>The extraction by some farmers of methane gas from manure piles is interesting,
+but how can you top a genius who is trying to run a subway system on pure bullshit?</q>—<i>San
+Francisco Chronicle, Mar. 29, 1974, p. 29, in Herb Caen’s column.</i></blockquote>
+
+<p class="pagebreak">On why he hasn’t written more books:</strong></p>
+
+<blockquote><q>You can sometimes beat the pros at their own game once. But they don’t often let
+you get away with it a second time. It’s much easier to find another field.</q></blockquote>
+
+<p class="pagebreak">A favorite saying at the Nevada test site:</p>
+
+<blockquote><q>A smart cowboy just wouldn’t work this hard to make things so goddamn
+difficult.</q></blockquote>
+
+<p class="pagebreak">In response to a fellow scientist asking if he had been in an accident:</p>
+
+<blockquote><q>No, some women just like to make their cowboys jealous. I guess it makes him better
+in bed after she takes him home and patches him up.</q></blockquote>
+
+<p class="pagebreak">Describing the BART train control system in the 1970s:</p>
+
+<blockquote><q>…the world’s most expensive, computer-controlled, track-mounted
+pinball machine.</q></blockquote>
+
+<p class="pagebreak">On why it was so easy for him to find a easy, reliable way to duplicate the
+early BART magstripe tickets (and thus credit cards, until he helped the banks find a more reliable
+encryption design):</p>
+
+<blockquote><q>It’s not my fault. When engineers have too much money, they usually
+think only of the most sophisticated ways they can spend it. No one asks them to play devil’s
+advocate and think of the obvious until it’s too late.</q></blockquote>
+
+<p class="pagebreak">In response to an allegation that he was working for the Golden Gate Bridge district
+(designing a traffic barrier to prevent head-on collisions that the bridge engineers said could not be designed)
+without a professional engineer’s license:</p>
+
+<blockquote><q>I don’t take public money for exposing high-priced fools who pretend
+to be competent engineers.</q></blockquote>
+
+<p class="pagebreak">In response to a corrosion engineer who had been working on the EBMUD blue water problem
+for a year:</p>
+
+<blockquote><q>Where I went to school, we don’t give degrees to engineers who can’t
+solve a problem in a year.</q></blockquote>
+
+<p class="pagebreak">Upon being asked why other talk show hosts don’t follow his format of welcoming callers
+on any subject:</p>
+
+<blockquote><q>If you do, you’d better be ready to spend three hours on the air
+admitting your ignorance. You’d better be prepared for what smart people will ask
+you.</q></blockquote>
+</body>
+</html>
\ No newline at end of file
--- /dev/null
+++ b/lib/ebooks/oebtest/TalkRadio.html
@@ -1,0 +1,117 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE html PUBLIC "+//ISBN 0-9673008-1-9//DTD OEB 1.0 Document//EN"
+ "http://openebook.org/dtds/oeb-1.0/oebdoc1.dtd">
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/x-oeb1-document; charset=utf-8" />
+<link rel="stylesheet" type="text/x-oeb1-css" href="DrBillBio.css" />
+<title>Bill Wattenburg’s Background: Talk Radio on the West Coast</title>
+</head>
+
+<body>
+
+<h1>Talk Radio on the West Coast</h1>
+
+<p>The ratings for Bill Wattenburg’s night-time talk show “The Open Line To
+The West Coast” on KGO Radio (ABC),
+San Francisco, have been three to four times above the average of the next best-rated
+shows (AM and FM) in the market for at least the last eleven years running (since 1982).
+His show gains 11 to 20 shares in his time slot compared to 3 to 4 shares for his closest competitors.
+He has been a regular on KGO talk radio since 1972. His nighttime radio shows
+reach the entire west coast from Alaska to Mexico, as he announces when he comes
+on the air. Based on his Bay Area audience ratings, we estimate that at least
+1,200,000 in the eleven western states and Alaska hear some part of each of his
+three-hour, 10pm to 1am KGO shows on weekends. We estimate that at least
+13,000,000 on the west coast have listened to him at some time in the last three
+years on radio and recognize his name or his voice. Out-of-market numbers say
+that his total listening audience in southern California is substantially larger
+than in the Bay Area in the 10pm to 12pm time slot.</p>
+
+<p>Our staff evaluated tapes of sixteen of his KGO Radio shows and three of his
+TV shows picked at random for the period January 1988 to December 1992. He
+allowed us to observe him in-studio during four of his live KGO radio talk shows
+in October 1992. A recent feature story on his KGO radio performances appeared
+in the Capitol Cities/ABC employee magazine. We believe this to be a fair
+analysis of his radio performances.</p>
+
+<p><i>[The story from the employee magazine, <i>ABC Ink</i>, is not included here because
+ABC does not grant permission for this content to be reproduced electronicly, but it is quite
+interesting.—PKS]</i></p>
+
+<hr />
+
+<p>We picked up some sour notes however, from one KGO Radio producer who has
+been with the station for many years. This producer said that Wattenburg almost
+never takes guests on his show and that he ignores advice from producers who
+offer him important material and topics for his shows. We asked this producer to
+give us an example. The producer mentioned that Wattenburg ignored some news
+stories during the Gulf War that reported the danger of nuclear material being
+scattered all over the desert, or that the Iraqis could have retrieved a nuclear
+warhead and used it against us. We asked the producer if he/she knew that
+Wattenburg was probably very familiar with the safeguards on our nuclear weapons
+because he worked on the design of nuclear weapons at one time and was an
+advisor to the Air Force. The producer said that he/she did not know that
+Wattenburg had ever done that.</p>
+
+<p>As to the second complaint—no guests on his shows—we politely asked if
+anyone could explain why Wattenburg’s ratings were more than twice as high as
+the top-rated daytime KGO shows that specialized in interviewing guests booked
+on the shows by producers. The answer we got was that it was easier for him to
+hold high ratings in the nighttime slot at 10pm to 1am than during the daytime.
+We pointed out that all the other major radio shows on the west coast in the
+same time slot had much lower ratings that Wattenburg. And, we asked why
+Wattenburg still had higher ratings when he did the KGO daytime shows in the
+seventies.</p>
+
+<p>The last response we were offered by this senior producer was: “Well,
+he’s been around for twenty years, you know. All the rednecks listen to
+him.”</p>
+
+<p>Another KGO producer who works Wattenburg’s shows commented that some of the
+older KGO producers don’t like Wattenburg just because he won’t take guests that
+they try to book on his shows. “They get a lot of flak from their public
+relations friends in New York who want to book authors on Wattenburg’s shows.
+Wattenburg won’t take even his own best friends on his shows. Why should he take
+theirs? … The younger producers here fight to work Wattenburg’s shows. It’s a
+lot of fun, and it’s sort of satisfying. And it’s a snap. … He tells us to take
+every caller who calls on his show. We get a lot of really bright young kids who
+call his show late at night. He gets a little mad if you even refuse to let a
+drunk on his show. He says a lot of drunks make more sense than the sober ones,
+and people love to hear them on the air because if you work them right they will
+tell the whole world the truth that they will be sorry about tomorrow. … It’s
+sort of nice to start a show when the switchboard is already full of calls
+before he goes on the air … our biggest problem is when people start to call
+before the end of the previous show and only want to know if Wattenburg is going
+to be there later. The host on that show gets mad at you if he is pleading for
+callers and he sees calls coming in, but none of them are for him…”</p>
+
+<p><b>We verified that Wattenburg started and promoted two major environmental
+campaigns on his radio shows. These were: stopping the giveaway of the Tongass
+National Forest in Alaska to foreign-owned (Japanese) interests, and saving the
+old-growth redwoods in the Headwaters Forest owned by Pacific Lumber Company.</b></p>
+
+<p>He began alerting his west coast audience to these dangers in 1989, well before
+national environmental organizations were on the bandwagon. He first warned that
+the takeover of Pacific Lumber by a Houston investor in a junk bond deal would
+lead to the cutting of the last of the privately-owned virgin redwoods. State
+and federal officials didn’t believe him until Pacific Lumber’s new owners filed
+for a logging permit the next year. Major public campaigns and legislation have
+since stopped the cutting for the near future.</p>
+
+<p>For two years, Wattenburg’s audience bombarded congress with protests over
+the fifty-year contracts given to foreign-owned lumber companies to cut the
+virgin forests in the Tongass Forest for as little as a few dollars a tree. Most
+members of congress admitted that they didn’t even know that this country’s
+largest national forest existed, let alone where it was. Wattenburg’s favorite
+ploy was to remind politicians that they were hypocrites for complaining about
+the cutting of rain forests in other countries while they allowed the
+clear-cutting of this country’s only temperate rain forest.</p>
+
+<p>The U.S. Forest Service finally modified the contracts extensively in 1992
+and set aside large areas in the Tongass that can not be cut. Wattenburg still
+delights in reminding the environmental lobbies that they only later got
+interested in this problem to get contributions to save a forest that was
+actually rescued by his audience on KGO Radio.</p>
+
+</body>
+</html>
\ No newline at end of file
--- /dev/null
+++ b/lib/ebooks/oebtest/TitlePage.html
@@ -1,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE html PUBLIC "+//ISBN 0-9673008-1-9//DTD OEB 1.0 Document//EN"
+ "http://openebook.org/dtds/oeb-1.0/oebdoc1.dtd">
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/x-oeb1-document; charset=utf-8" />
+<link rel="stylesheet" type="text/x-oeb1-css" href="DrBillBio.css" />
+<title>Bill Wattenburg’s Background</title>
+</head>
+<body lang="en-us">
+
+<h1 class="title">Bill Wattenburg’s Background</h1>
+
+<p style="text-align: center">Originally compiled in 1992</p>
+
+<br />
+
+<center><img src="DrBill.tif" /></center>
+
+</body>
+</html>
\ No newline at end of file
--- /dev/null
+++ b/lib/ebooks/oebtest/TitlePage.html.i
@@ -1,0 +1,5 @@
+1 pages
+size 400 562
+length 586
+400 2 10 body html
+0
--- /dev/null
+++ b/lib/ebooks/oebtest/TitlePage.html.index
@@ -1,0 +1,5 @@
+1 pages
+size 400 562
+length 586
+400 2 10 body html
+0
--- /dev/null
+++ b/lib/ebooks/oebtest/about.html
@@ -1,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE html PUBLIC "+//ISBN 0-9673008-1-9//DTD OEB 1.0 Document//EN"
+ "http://openebook.org/dtds/oeb-1.0/oebdoc1.dtd">
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/x-oeb1-document; charset=utf-8" />
+<link rel="stylesheet" type="text/x-oeb1-css" href="DrBillBio.css" />
+<title>Bill Wattenburg’s Background: About This Report</title>
+</head>
+<body lang="en-us">
+
+<h1 class="title">About This Book</h1>
+
+<h2 class="title">Peter K. Sheerin</h2>
+
+<p class="title">I received the report from a government agency that wanted more people to know more of Bill
+Wattenburg’s interesting and varied background.</p>
+
+</body>
+</html>
\ No newline at end of file
--- /dev/null
+++ b/lib/ebooks/oebtest/awards.html
@@ -1,0 +1,32 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE html PUBLIC "+//ISBN 0-9673008-1-9//DTD OEB 1.0 Document//EN"
+ "http://openebook.org/dtds/oeb-1.0/oebdoc1.dtd">
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/x-oeb1-document; charset=utf-8" />
+<link rel="stylesheet" type="text/x-oeb1-css" href="DrBillBio.css" />
+<title>Bill Wattenburg’s Background: Awards</title>
+</head>
+
+<body>
+
+<h1>Awards</h1>
+
+<p>Wattenburg received a Certificate of Merit from the Secretary of Defense in 1970 for his
+service on the U.S. Air Force Scientific Advisory Board from 1966 to 1970. Members of this
+Board were authorized by Congress to oversee and advise the Secretary of Defense and the
+President on the strategic defense programs of the Air Force. Members are given the equivalent
+military rank of General and the authority to request briefings from the staffs of any Air Force
+command concerning the defense programs and forces at their command.</p>
+
+<p>Wattenburg served on a sub-committee headed by Dr. Edward Teller which reviewed and
+evaluated this nation’s nuclear defense and missile capability. Wattenburg proposed
+significant defense strategy changes which are recorded in still classified documents from this period.</p>
+
+<hr />
+
+<p><i>I also found out that Bill was named a Distinguished Alumni of Chico State
+for 1999, in the College of Engineering, Computer Science, and Technology.</i>—PKS</p>
+
+</body>
+</html>
\ No newline at end of file
--- /dev/null
+++ b/lib/ebooks/oebtest/awards.html.i
@@ -1,0 +1,5 @@
+1 pages
+size 400 562
+length 1429
+396 2 11 body html
+0
--- /dev/null
+++ b/lib/ebooks/oebtest/background-education.html
@@ -1,0 +1,114 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE html PUBLIC "+//ISBN 0-9673008-1-9//DTD OEB 1.0 Document//EN"
+ "http://openebook.org/dtds/oeb-1.0/oebdoc1.dtd">
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/x-oeb1-document; charset=utf-8" />
+<link rel="stylesheet" type="text/x-oeb1-css" href="DrBillBio.css" />
+<title>Bill Wattenburg’s Background: Education</title>
+</head>
+
+<body>
+
+<h1>Background and Education</h1>
+
+<p>Bill Wattenburg’s academic training explains some of the technical tricks he has pulled off
+in the public domain. He has a Ph.D. in electrical engineering and physics from
+U.C. Berkeley, and he has kept up very successful careers in science and business throughout the entire time he
+has been doing radio, television and publishing.</p>
+
+<h2 id="Hometown">Hometown</h2>
+
+<p><i>(The following comes from KGO Radio promotional material.)</i></p>
+
+<blockquote><p>Bill Wattenburg was born in Chico, California, on February 9, 1936. He grew up in the
+mountains of northeastern California in the lumber industry and ranching areas of Plumas County. His
+mother died when he was nine. He and his younger sister were raised by
+their father. They often lived with family friends when their father was away seeking work as a
+logger, road builder and mechanic. When he was nine to thirteen years old, Bill lived and worked
+with an old gold miner friend of his father’s most of the time. The family friend had a mining claim
+and cabin twenty miles from the nearest town and located at 7,000 feet in the Sierra. They were
+snowed in several months each winter and Bill got his education from books, a short-wave radio,
+and correspondence courses supplied by the school district.</p>
+
+<p>When asked how he got where he is today, Wattenburg says it began shortly after he
+graduated from high school when he was 15. His father walked up to him one afternoon on their
+logging job and told him to get off the bulldozer he was operating. He said that he had told his
+father that he wanted to work as a logger instead of going to college. His father then threatened
+to “knock him on his butt” if he didn’t get on the Greyhound bus that very night and go to
+U.C. Berkeley where he had been offered a scholarship. He had never been out of the mountains of
+northern California except for a few trips to nearby Reno to buy school clothes. His high school
+science teacher had insisted that he take a National Science Foundation examination before he
+graduated. This teacher helped him apply to several universities. He had never opened the
+letters that came back from the universities. But his father, who had not finished high school, had
+opened the letters and seen the scholarship offer from U.C. Berkeley.</blockquote>
+
+<h2 id="Education">Education</h2>
+
+<p>Bill Wattenburg enrolled at Berkeley as an engineering major and finished his freshmen year
+with honors. The following year he moved to California State University at Chico because it was
+closer to home and his father needed help to support the family in Plumas County. He worked
+in the logging woods and as a ranch hand. He commuted to college at Chico during the week.
+His records at Chico State show that he played football and boxed on the Chico State teams for
+three years.</p>
+
+<p>Young Bill Wattenburg evidently had some trouble with the law in his home town
+in Plumas County. Some of the local people we interviewed remembered that Bill was
+involved in some fights in local bars around the county when he was eighteen or nineteen. The
+other men involved had reputedly threatened or attacked Bill’s father while Bill was away in
+college. These were disgruntled former employees whom his father had given jobs when no
+one else would hire them.</p>
+
+<p>However, the Plumas County Sheriff’s Department and the local newspaper have records of
+only one incident in 1955 involving a man who was formerly convicted of assault with a deadly
+weapon. Bill’s father had given him a job while he was on probation, but later fired him over
+some disagreement. This man later got in a fight with Bill and then filed assault and battery
+charges against Bill. The charges were dismissed after witnesses said that the man threatened Bill
+with a hunting knife. The news story quoted witnesses as saying that Bill approached the man in
+a local bar and asked him: “Would you like to point that knife at me the same way you did
+my father?” The man was returned to county jail after he was released from the county hospital
+with a cast on his broken right arm.</p>
+
+<h2 id="GraduateSchool">Graduate School</h2>
+
+<p>Bill Wattenburg graduated summa cum laude from California State University, Chico,
+with a double major in electrical engineering and physics. He returned to Berkeley as a graduate
+student on a National Science Foundation scholarship in 1958. There he studied electrical
+engineering under Professor Harry D. Huskey, who was intimately involved in some
+of the world’s first digital
+computers <i>[and was the president of the Association for Computing Machinery
+in the early 1960s—PKS]</i>. Professor Edward Teller (known to many as the “father of the
+hydrogen bomb”) was one of his physics teachers. He was awarded a Ph.D. in electrical
+engineering and physics at Berkeley (summa cum laude) in 1961, after only three years in
+graduate school. He was immediately offered a position as Assistant Professor of Electrical
+Engineering on the prestigious Berkeley faculty.</p>
+
+<p>The following year he was captivated, he says, by President John F. Kennedy’s call for an end
+to atmospheric nuclear testing and the development of cleaner underground testing procedures.
+He took a leave of absence from Berkeley and moved to the Livermore National Laboratory
+where he worked in the physics division on the design of nuclear devices and the first
+underground nuclear tests. He then spent six months at the Nevada nuclear test site.</p>
+
+<p>A Lawrence Livermore National Laboratory official confirmed that he was the
+inventor of still-classified nuclear test measurement and diagnostic procedures that are essential to
+our nuclear test ban treaty verification technology today.</p>
+
+<h2 id="AcademicWork">Academic Work</h2>
+
+<p>He returned to teaching and research at the University of California, Berkeley campus in 1964
+where he continued his research in the design of digital computers systems and supervised a large
+group of graduate students. He taught the main graduate courses in digital computer design and
+programming at Berkeley for the next five years. Many of his graduate students are today high
+level executives in major American computer and communication companies. He also continued
+his work in nuclear weapons testing at Livermore as a part-time consultant and became a
+consultant to IBM, General Electric, and Lockheed Missiles and Space Company in various
+defense and space projects at those companies from 1964–1970. He was a member of the U.S. Air
+Force Scientific Advisory Board from 1966 to 1970.</p>
+
+<p>From 1961 to date, he has published over twenty scientific research papers and technical
+articles and has been awarded six U.S. and foreign patents. <i>[The total is now
+eight U.S. patents—PKS]</i></p>
+
+</body>
+</html>
+
--- /dev/null
+++ b/lib/ebooks/oebtest/background-education.html.i
@@ -1,0 +1,19 @@
+6 pages
+size 400 562
+length 7245
+399 2 11 body html
+0
+886 2 24 body html
+227
+2747 2 46 body html
+0
+3742 2 62 body html
+153
+5472 2 86 body html
+68
+7020 2 108 body html
+0
+AcademicWork 4
+Education 1
+GraduateSchool 3
+Hometown 0
--- /dev/null
+++ b/lib/ebooks/oebtest/bloodbanks.html
@@ -1,0 +1,83 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE html PUBLIC "+//ISBN 0-9673008-1-9//DTD OEB 1.0 Document//EN"
+ "http://openebook.org/dtds/oeb-1.0/oebdoc1.dtd">
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/x-oeb1-document; charset=utf-8" />
+<link rel="stylesheet" type="text/x-oeb1-css" href="DrBillBio.css" />
+<title>Bill Wattenburg’s Background: Blood Banks</title>
+</head>
+
+<body>
+
+<h1>Blood Banks</h1>
+
+<p>Bill Wattenburg’s first reported entry in the public domain happened when he was a young
+assistant professor at Berkeley. The Director of the Alameda County Blood Bank, Dr. David
+Singman, a pathologist at Alta Bates Hospital in Berkeley, came to him in 1965 with a problem at
+the Alameda–Contra Costa Blood Bank that was costing a great deal of money and loss of life
+around the country. In the traditional way that blood banks distributed blood to local hospitals,
+up to twenty percent of the blood was being lost because of “outdating”. This spoilage
+occurred because the blood sat in refrigerators in the hospitals past the thirty-day limit during which it
+could be safely used somewhere else. Once a unit of blood was sent to a hospital, it was usually
+cross-matched and set aside for a particular patient. Even if the patient didn’t need it later, this
+particular unit of blood was seldom ever sent to another hospital before it became outdated and
+had to be thrown away.</p>
+
+<p>Dr. Singman knew that Wattenburg was designing computers at U.C Berkeley at the time.
+He told Wattenburg about this problem and asked him if he could solve it.</p>
+
+<p>On his own time, Wattenburg first designed a method to positively identify each pint of
+blood by a special code before it left the blood bank. He then designed a computer system to
+track each pint of blood as it went into hospital inventories. Frustrated with writing proposals and
+waiting for government money to buy the computer equipment he needed, Wattenburg convinced
+Lockheed Missiles & Space Co. in Sunnyvale to contribute time on one of their large defense
+computers during nighttime. Wattenburg had earlier helped design this computer for an Air Force
+project. He made a deal with Lockheed—He promised to show them how to save at least an hour
+of computer time a day on the Air Force project in return for the fifteen minutes at night he
+needed for the blood bank.</p>
+
+<p>Next, he devised a scheme to hook up all hospitals and the Alameda Blood Bank to the
+Lockheed Sunnyvale central computer over telephone lines. This was ten years before remote
+data terminals for computers were commonly available.</p>
+
+<p>Finally, he designed the computer programs that allowed the Alameda blood bank to keep
+track of every pint of blood in its inventory and sitting at the hospitals it served, His system
+allowed the blood bank to order all blood units approaching outdating at the hospitals to be
+located everyday and sent to other hospitals where they were needed instead of sending new units
+from the blood bank while the old units went to waste in hospital refrigerators.</p>
+
+<p><b>His clever solution stopped the needless waste of ten percent of the blood supply in the Bay
+Area in the first year it was used. The average age of transfused blood was reduced by ten percent,
+and the need for outside donors was reduced by thirty-three percent. His system was quickly
+adopted by the Red Cross nationwide. The results were published in The Journal of the American
+Medical Association (JAMA), November 8, 1965, pp 583–586, “Computerized Blood Bank
+Control”. Wattenburg’s design was soon adopted by most blood banks throughout the country.</b></p>
+
+<p>Dr. Singman has died, but we talked to a retired Red Cross medical advisor who knew Dr.
+Singman at Alta Bates Hospital in Berkeley when he was working with Wattenburg on this
+project. He remembers when all this happened twenty-five years ago. He says that some top
+Red Cross administrators were defensive and annoyed over the attention that Wattenburg’s
+innovation received in the press. “They were forced to admit that it was a great improvement and
+that they would use it as soon as possible, but they were uncomfortable because his idea and the
+JAMA article also brought public attention to the fact that large amounts of blood had been lost in
+the past because they had not recognized something that seemed so simple.” He said he
+remembers how he kicked himself when he saw it. He says that, for certain, hundreds of lives
+have been saved in the twenty-five years since then because desperately needed blood has been
+available were and when it is needed, and the cost of blood has been reduced significantly. He
+remembers that Wattenburg was invited to a blood bank association meeting in San Francisco
+shortly after the JAMA article appeared. Wattenburg announced that he was giving the rights to
+his idea to any blood bank that wanted to use it, free of charge. However, Lockheed built a
+substantial business supplying the computer programs and equipment to hundreds of blood banks
+around the country.</p>
+
+<p>In one of our interviews with him, we showed Wattenburg the nice comments above and
+said that he must be very proud of what he had done at such an early age (29). He displayed
+some annoyance. He then told us that a U.C. Berkeley faculty promotions committee in 1966
+concluded that this work for the nation’s blood banks was “more in the line of public service than
+university level scientific research worthy of promotion consideration.” He said that this
+disappointment was the second time that, “This sort of thing happened to me, but I grew up after
+that.” He wouldn’t elaborate on what the first time was.</p>
+
+</body>
+</html>
\ No newline at end of file
--- /dev/null
+++ b/lib/ebooks/oebtest/business.html
@@ -1,0 +1,87 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE html PUBLIC "+//ISBN 0-9673008-1-9//DTD OEB 1.0 Document//EN"
+ "http://openebook.org/dtds/oeb-1.0/oebdoc1.dtd">
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/x-oeb1-document; charset=utf-8" />
+<link rel="stylesheet" type="text/x-oeb1-css" href="DrBillBio.css" />
+<title>Bill Wattenburg’s Background: Business</title>
+</head>
+
+<body>
+
+<h1>Business</h1>
+
+<p>In 1966, Bill Wattenburg and physicist Donald Glaser
+(winner of the Nobel Prize in Physics, 1960, for the invention of the bubble chamber)
+formed a company called Berkeley Scientific Laboratories (BSL) which grew to a thirty-million
+dollar a year enterprise within three years. Wattenburg served as president of the company until
+1970. The scientific staff at BSL directed by Wattenburg received major NASA contracts for
+work on the spacecraft guidance computer for the Apollo man-to-the-moon project and
+Department of Defense contracts for the computer systems for the Navy’s Poseidon missile. BSL later developed
+a number of very successful commercial products, including the first small medical data computer
+systems used in hospitals around the world to automate and improve medical testing procedures
+in clinical and radiology laboratories.</p>
+
+<p>Berkeley Scientific Laboratories was purchased by Tracor, Inc., a high-technology
+conglomerate in Austin, Texas, in 1969. Wattenburg became a major stockholder in
+Tracor. He resigned as president of BSL and sold his substantial interests in Tracor in 1970. Tracor stock
+dropped considerably over the next few years. He later reinvested heavily in Tracor in 1975
+shortly before it entered a long and profitable growth period over the following ten years under
+the leadership of president Frank McBee, a friend of Wattenburg’s. Wattenburg sold all his
+interests in Tracor again when the company was taken over by Admiral Bobby Inman in the eighties.</p>
+
+<p><i>(The following comes from investment banker Faris Chesley, The Chicago Corporation,
+Chicago, who has known Bill Wattenburg since 1967.)</i></p>
+
+<p>In 1969 Wattenburg and a group of physicians and medical specialists started a company
+in San Francisco called Comprehensive Health Services (CHS), later renamed Comprehensive
+Computer Systems, which developed health screening programs for professional groups such as
+the California Teachers Association and operated a large clinical laboratory in San Francisco. He
+joined the company as director of research in 1972 and developed another very successful product
+line of medical computer systems for radiology which was marketed worldwide by General
+Electric Co. CHS also acquired Bakte-Bennet Laboratories, a major supplier of growth media to
+hospitals and clinical laboratories on the west coast.</p>
+
+<p>Wattenburg and his technical staff at CHS developed a unique system of “marked-sense”
+Medical documents that allow a radiologist to report his full diagnostic findings by simply
+marking a few spots on one of a series of special diagnostic reporting forms. We have attached
+one of these “Raport” forms to this report. General Electric Medical
+Systems division invested over eight million dollars in this development from 1972 to 1976.</p>
+
+<p>The reader will find the following explanation much easier to understand by first
+examining the radiology report form and computer-generated radiology report attached.</p>
+
+<div class="image">
+<img src="raport.png" height="100%" />
+</div>
+
+<p>The computer-readable forms they developed cover the full human anatomy with pictorial diagrams
+showing the areas of interest to a radiologist. Each color-code form also contains a set of
+symbols that describe almost all qualifying statements that a radiologist would normally dictate in
+a report of his examination of an X-ray film.</p>
+
+<p>Wattenburg cautioned us that the original idea for all this came from Dr. Richard
+Mani, a young radiologist at the University of California San Francisco Medical Center who later worked
+with CHS. Several major computer companies and the U.C. computer center staff had told Dr.
+Mani that his idea was not workable.</p>
+
+<p>Wattenburg and his staff worked for two years to build the computer hardware and special
+programs that could read the marked-sense documents and produce medical prose in the
+computer-generated diagnostic reports that would be both accurate and pleasing to radiologists.</p>
+
+<p>General Electric sold hundreds of these small computer systems to major hospitals and
+radiology groups around the world from 1975 to 1980. The product line was sold to National
+Computer Systems, Minneapolis, in 1980.</p>
+
+<p>National Computer Systems bought Comprehensive Computer Systems CHS) from Wattenburg and his group in 1979.
+National Computer Systems was the world’s biggest supplier
+of marked-sense computer equipment and technology. (They still were in 1990. NCS supplies most
+of the multiple choice forms and data processing for schools and educational testing services
+world wide.) Wattenburg became a major stockholder in National Computer Systems.</p>
+
+<p>Wattenburg was doing <a href="TalkRadio.html">talk radio on KGO</a> and <a href="television.html">television
+shows</a> on nights and weekends throughout this period from 1972 on.</p>
+
+</body>
+</html>
--- /dev/null
+++ b/lib/ebooks/oebtest/business.html.i
@@ -1,0 +1,15 @@
+6 pages
+size 400 562
+length 5301
+398 2 11 body html
+0
+1275 2 26 body html
+187
+3241 2 52 body html
+34
+3417 2 55 body html
+0
+3417 2 55 body html
+562
+4148 2 69 body html
+85
--- /dev/null
+++ b/lib/ebooks/oebtest/colleague.html
@@ -1,0 +1,193 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE html PUBLIC "+//ISBN 0-9673008-1-9//DTD OEB 1.0 Document//EN"
+ "http://openebook.org/dtds/oeb-1.0/oebdoc1.dtd">
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/x-oeb1-document; charset=utf-8" />
+<link rel="stylesheet" type="text/x-oeb1-css" href="DrBillBio.css" />
+<title>Bill Wattenburg’s Background: A Colleague’s Observations</title>
+</head>
+
+<body>
+
+<h1>A Colleague’s Observations</h1>
+
+<p>We interviewed a professor of engineering at a major California university who worked with
+Bill Wattenburg at the Nevada Nuclear Test Site in 1962–1963 and at the Livermore
+National Laboratory for some time after that. Like many of his former scientific colleagues we interviewed,
+this man has followed Wattenburg’s public career ever since.</p>
+
+<p>His candid recollections give a good picture of Bill Wattenburg’s personality and style as a young
+scientist. We believe these observations explain a lot about Wattenburg’s public activities and
+personality in later years, as we have summarized it in the following sections of this report.</p>
+
+<p>These are the professor’s comments taped and included here with his permission:</p>
+
+<hr />
+
+<blockquote>
+<p>“Bill Wattenburg’s mind just doesn’t work the same way that everyone else’s does. He is
+bored to death with complicated solutions to difficult scientific problems. He obviously
+understands scientific fundamentals as well as any of the rest of us, but he is basically lazy. … He
+was always looking for the simple solution that everyone else had overlooked. His favorite saying
+was: ‘A smart cowboy just wouldn’t work this hard to make things so goddamn difficult.’ Then
+he would throw up his hands and go off to tease the ladies in some local bar down the
+highway while the rest of us were working our butts off.</p>
+
+<p>…</p>
+
+<p>“But, all too often, he would come back to wake us all up in our trailers in the middle of
+the night and march us into the laboratory to see some Rube Goldberg solution he had discovered,
+or a clever gadget he had built to do the same thing we had worked months to do.</p>
+
+<p>…</p>
+
+<p>“I admired the guy’s genius, but I have to admit that I came to simply dread working with
+him for the first few months that I knew him. You are always wondering when he is going to
+make a fool out of you, and do it in some simple way or with some crazy experiment that forces
+you to stand and applaud your own ignorance. … He was always watching everything what
+everybody else was doing. He seldom ever criticized, but you always had the feeling that he was
+seeing something about your work that you didn’t realize yourself. It was very unnerving in the
+beginning. … But I have to admit that now I try to teach my own graduate students some of the
+things I learned from him.</p>
+
+<p>…</p>
+
+<p>“He was only twenty-five when I began working for him at the Test Site. It was hard to
+believe that he was a nuclear weapons designer from ‘A’ division. Most of us were ten years
+older and we were working for him. … The guy never slept. … A tennis game was the only thing
+that seemed to hold his attention in one place for more than an hour … or maybe a cute cowgirl on
+a barstool somewhere.</p>
+
+<p>“There was a problem with him on this score. Once in a while they would have to send
+out the Test Site security guards to scout every country bar within 50 miles of the test site to find
+him if a problem came up on a weekend. I remember once when they brought him back to the
+trailers and he had blood all over his shirt. Someone asked him if he had been in an accident. He
+said, ‘No, some women just like to make their cowboys jealous. I guess it makes him better in bed
+after she takes him home and patches him up.’</p>
+
+<p>“Once when an underground nuclear test at Mercury was delayed and there was absolutely
+nothing we could do for two days but catch up on our sleep, he kept busy tuning up every
+secretary’s car in the parking lot, free of charge of course. We all knew what he was doing … he
+always found a lady friend out in that god-forsaken desert somewhere who took real good care of
+him. We would get hamburgers for dinner in the cafeteria and he would get a steak with all the
+trimmings.</p>
+
+<p>…</p>
+
+<p>“He would try any damn thing that popped into his mind—even at
+the very last minute before a nuclear shot. He was always pushing everybody to try add-on
+experiments that he cooked up. He was always fooling around with your equipment in the test
+shack in the middle of the night. You’d come back the next morning and something would be
+changed. It was hard enough to carry out the main experiments that we were supposed to do.
+And, he was supposed to be the group leader. But his attitude was that once he showed you how
+to do something, and he was very good at that, it was all over as far as he was concerned. It was
+of no interest to him whatsoever after that. I didn’t feel that he was a good manager in that sense,
+but he made up for it in other ways that I’ll tell you about later.<p>
+
+<p>…</p>
+
+<p>We actually got to the point that we would hide any extra test equipment, like
+oscilloscopes and cameras, and even dumb things like extra pieces of wire and signal cable. If you
+didn’t, he would try to use them for some other quirky experiment that could be wired
+up at the last minute before the shot. He always liked to find things he could add on to other
+people’s equipments that we had been working on for months to get checked out. Most of the
+other physicists made jokes about his ideas. But, on one underground nuclear shot in 1962, they
+all got a real jolt of a different sort.</p>
+
+<p>“One of his ‘midnight’ experiments hit the jackpot. The results shocked all the experts.
+And it was one that the bosses in ‘L’ division at Livermore had said could not possibly work. I
+remember that he was really pissed off because they wouldn’t even let him use some spare test
+equipment from the Livermore shops to do it. How he got permission and the equipment I don’t
+know. Another physicist from ‘A’ division named Russ Duff worked with him, I recall. Yes, I
+think it was Russ Duff who was showing everybody the surprising results of Wattenburg’s
+experiment right after the shot. … I mean the pictures from the Polaroid cameras we used in those
+days to record test results from a shot. They were all gathered around Russ Duff talking about it.
+Someone asked Wattenburg at dinner that night in the cafeteria what he thought about his
+experiment and he said something like ‘Yeah, I thought it would be interesting. Now maybe those
+assholes will wake up next time.’ I think he was talking about the bosses at
+‘L’ division who wouldn’t help him do it.</p>
+
+<p>“What Wattenburg discovered in this experiment really changed the way we instrumented
+bomb tests after that. The report on his Nevada Test Site experiment was still classified for many
+years after that for reasons that I never understood. I was going to talk about it in a classified
+seminar I was going to give to new test engineers in 1975, and I discovered that his report was
+still classified beyond my need to know, which I thought was fairly high at the time. I told the
+head of the division that I thought it was a valuable example for new test engineers … which means
+that I’m a hell of a hypocrite for what I said a while ago about Wattenburg’s crazy ideas. The
+division head, I’ll leave his name out of this, told me that I shouldn’t discuss his report. He said it
+was a “sensitive matter” that he didn’t want to have to get into right then. I dropped
+the subject.</p>
+
+<p>…</p>
+
+<p>“A year or so later, I saw Wattenburg and asked him what was the big deal with his report
+on the 1962 experiment. We all knew that the scheme he discovered—invented would be a better
+description—was being used by everybody in the nuclear testing business since 1963. He just
+shrugged his shoulders and muttered something like ‘It looks like everybody but me has made a
+career out of being the real expert on that subject.’ I sensed that there was some annoyance on
+his part over it, so I dropped the subject.</p>
+
+<p>“This wasn’t the only startling thing he did when he was at the lab by any means. After I
+was no longer working with him in Nevada, I heard through the grapevine at the lab that he shook
+them up a few more times in ‘A’ division, that’s the H-bomb design division. I heard a few of the
+bomb designers say later that they were happy when he finally went back to teaching at
+Berkeley. … But if he went back to Berkeley you’d never have known it. I saw him at
+the lab at night for years after that. I would go in late at night or on weekends to check on one of my
+experiments or a computer run, and I’d see him in the computer room or in the cafeteria, sometimes
+at two in the morning.</p>
+
+<p>…</p>
+
+<p>“A guy in ‘A’ division told me a story about how Wattenburg learned to deal with the
+bureaucracy at the Laboratory after his first successful experiment. He said that Wattenburg had
+another idea and he desperately wanted money to do the experiment. He bragged that this idea
+was so good that he was going to convince them to give him two hundred thousand dollars to do
+this experiment. Everyone laughed at him. When he went to see the the bosses, they would only
+agree to give him twenty thousand. He was happy as a lark when he came back to the physics
+department. Some thought that he had gotten what he wanted. One of the physicists asked him:
+‘Did you get the two-hundred thousand you wanted?’</p>
+
+<p>“He answered: ‘No. I got twice as much as I needed.’ ”</p>
+</blockquote>
+
+<p><i>(The professor now talks at length about other scientists at the Livermore lab that
+Wattenburg used to pal around with, how he taught them to ride a horse in a local rodeo, shoot a
+pistol, water-ski, go deer hunting in the Sierra, and some of his amusing escapades with women
+at the lab. None of this is relevant here, but it is consistent with Wattenburg’s general playfulness
+and hobbies that are reported elsewhere in this report.)</i></p>
+
+<br />
+
+<p>He continues:</p>
+
+<blockquote>
+<p>“Bill Wattenburg’s latest hobby on radio and television is just the right place for him to show off what a clever
+smart-ass he can be. … On the other hand, there are probably few good scientists who can explain complex technical things to the lay public as well as
+he can. … He can cook up the most clever little experiments for people to do at home so that they
+can explain science to themselves. He’s really good with bright kids. I’ve heard ten-year olds call
+him on the radio at midnight. They love him … but that’s because he’s still just a kid at heart
+himself.</p>
+
+<p>“I’m sure a lot of people are happy he is spending his time as a radio celebrity nowadays
+instead of on their backs in the laboratory. … It’s probably a good thing that the crazy guy got
+rich from his early inventions because the ordinary engineers of the world simply wouldn’t be safe
+with him wondering around looking for consulting contracts to beat them at their own
+game. …Anyone who has ever worked with him would never bet money that he couldn’t open a bank
+vault with the manager’s own pocketknife.</p>
+
+<p>…</p>
+
+<p>“I think he has been away from the scientific laboratory too long now to still be up on the
+cutting edge of scientific research. … That means he’ll probably walk into my lab any day now and
+tell me how much he enjoyed reading my latest scientific papers. Then he’ll probably show me all
+the simple things I overlooked.</p>
+
+<p>…</p>
+
+<p>“But if you want to know what I really think of him, I’ll tell you. If I am ever trapped in a
+spaceship and everyone says it is hopeless, I hope he is still around, and near a telephone. …”</p>
+</blockquote>
+
+</body>
+</html>
\ No newline at end of file
--- /dev/null
+++ b/lib/ebooks/oebtest/confrontations.html
@@ -1,0 +1,46 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE html PUBLIC "+//ISBN 0-9673008-1-9//DTD OEB 1.0 Document//EN"
+ "http://openebook.org/dtds/oeb-1.0/oebdoc1.dtd">
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/x-oeb1-document; charset=utf-8" />
+<link rel="stylesheet" type="text/x-oeb1-css" href="DrBillBio.css" />
+<title>Bill Wattenburg’s Background: Public Confrontations</title>
+</head>
+
+<body>
+
+<h1>Public Confrontations</h1>
+
+<p>The episodes that follow show that Wattenburg seemed to delight in exposing the failures
+of over-confident engineers who managed public projects. His style, however, was not just to
+criticize them. He typically offered them a better idea or a clever design of his own which he
+then contributed free of charge to the public agencies in question. The trouble seems to have
+started when they said that his ideas wouldn’t work or that he didn’t know what
+he was talking about. (See <a href="BART.html">BART</a>, <a href="GoldenGate.html">Golden
+Gate Bridge Barrier</a>, and <a href="BlueWater.html">Blue Water</a> projects described below.)</p>
+
+<p>We were rather astounded at what we found from database searches of newspaper and wire
+service stories on Bill Wattenburg. At first, we were ignoring those on “Willard”
+Wattenburg, “William” Wattenburg, “Professor W. H.” Wattenburg,
+and “Ben Wattenberg” because we thought they were all different people. Then we
+realized that all but “Ben Wattenberg”, the columnist, are Bill Wattenburg. He has used
+“Willard” and “Professor W. H.” at various times and places for reasons
+of his own. His most recent mention in the New York Times uses “Willard”. We asked him
+why. He said that his driver’s license says “Willard”, so when he was out of the Bay
+Area he told press people who might have wanted to check up on him that his name is Willard Wattenburg.
+Sometimes the press was confused and used “William”. He said he never bothered to correct
+a reporter. Apparently, the importance of building national name recognition as media personality Bill
+Wattenburg did not occur to him.</p>
+
+<ul>
+ <li><a href="BART.html">Fixing BART Safety</a>(Bay Area Rapid Transit System)</li>
+ <li><a href="creditcards.html">Magnetic Credit Cards</a></li>
+ <li><a href="dial-a-ride.html">Dial-A-Ride Carpooling</a></li>
+ <li><a href="MeasuringOilTanks.html">Don’t Call the FBI!</a></li>
+ <li><a href="GoldenGate.html">Golden Gate Bridge Traffic Barrier</a></li>
+ <li><a href="BlueWater.html">Blue Water (Copper) Contamination in Homes</a></li>
+</ul>
+
+</body>
+</html>
\ No newline at end of file
--- /dev/null
+++ b/lib/ebooks/oebtest/confrontations.html.i
@@ -1,0 +1,7 @@
+2 pages
+size 400 562
+length 2593
+411 2 11 body html
+0
+1096 2 23 body html
+272
--- /dev/null
+++ b/lib/ebooks/oebtest/copyright.html
@@ -1,0 +1,15 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE html PUBLIC "+//ISBN 0-9673008-1-9//DTD OEB 1.0 Document//EN"
+ "http://openebook.org/dtds/oeb-1.0/oebdoc1.dtd">
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/x-oeb1-document; charset=utf-8" />
+<link rel="stylesheet" type="text/x-oeb1-css" href="DrBillBio.css" />
+<title>Bill Wattenburg’s Background: About This Report</title>
+</head>
+<body lang="en-us">
+
+<p>Text goes here.</p>
+
+</body>
+</html>
\ No newline at end of file
--- /dev/null
+++ b/lib/ebooks/oebtest/covert.html
@@ -1,0 +1,32 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE html PUBLIC "+//ISBN 0-9673008-1-9//DTD OEB 1.0 Document//EN"
+ "http://openebook.org/dtds/oeb-1.0/oebdoc1.dtd">
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/x-oeb1-document; charset=utf-8" />
+<link rel="stylesheet" type="text/x-oeb1-css" href="DrBillBio.css" />
+<title>Bill Wattenburg’s Background: Covert Activities?</title>
+</head>
+
+<body>
+
+<h1>Covert Activities?</h1>
+
+<p>We could find no evidence that Wattenburg has ever been involved in government
+intelligence or covert activities. We enlisted the services of an investigative firm in Washington,
+D.C., whose staff is knowledgeable about the intelligence services. They have reported to us that
+their inquiries indicated no knowledge of Wattenburg having any involvement with the services in
+the past. However, they pointed out that knowledge of any covert activates would never be
+disclosed by their contacts for obvious reasons.</p>
+
+<p>They reported that Wattenburg had been asked by one service to help correct a problem
+with Soviet spying on our new embassy building in Moscow, but that Wattenburg had insisted
+that anything he did would have to be made public because he was working for ABC. He
+evidently made this activity public in the San Francisco Chronicle, April 22, 1987, page 18. The
+U.S. State Dept. did not seem too happy with his comments.</p>
+
+<p>We verified that he was in the country during the period 1985 to 1986 for which we had
+no information in our 1990 report (see his work on <a href="GoldMine.html">The Gold Mine project</a>).</p>
+
+</body>
+</html>
\ No newline at end of file
--- /dev/null
+++ b/lib/ebooks/oebtest/covert.html.i
@@ -1,0 +1,5 @@
+1 pages
+size 400 562
+length 1599
+408 2 11 body html
+0
--- /dev/null
+++ b/lib/ebooks/oebtest/creditcards.html
@@ -1,0 +1,241 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE html PUBLIC "+//ISBN 0-9673008-1-9//DTD OEB 1.0 Document//EN"
+ "http://openebook.org/dtds/oeb-1.0/oebdoc1.dtd">
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/x-oeb1-document; charset=utf-8" />
+<link rel="stylesheet" type="text/x-oeb1-css" href="DrBillBio.css" />
+<title>Bill Wattenburg’s Background: Magnetic Credit Cards</title>
+</head>
+
+<body>
+
+<h1>Magnetic Credit Cards</h1>
+
+<h2>(1973)</h2>
+
+<p>We believe that this event lends some insight into Wattenburg’s integrity in honoring
+contractual commitments and confidentiality agreements.</p>
+
+<p>The San Francisco Chronicle reported another of Wattenburg’s startling
+technical tricks during the BART controversy in 1973. A subsequent story in
+Business Week (August 11, 1973, page 120) stunned and sobered the nation’s
+banking and credit card industry which was planning to convert all credit cards
+to the same magnetic stripe system used in the new BART cards. Chronicle
+reporter Michael Harris approached Wattenburg in his Berkeley laboratory and
+asked Wattenburg whether it was possible to counterfeit the new multi-million
+dollar, “fool-proof” BART ticket magnetic stripe designed by IBM.
+This system was the first to use a magnetic stripe to record the value of a
+transit rider’s ticket. BART officials, IBM, and the nation’s banks had all said
+that “anyone would need at least $500,000 worth of specialized electronic
+equipment to copy the magnetic stripe and fool their reading machines.”
+(Anyone but Bill Wattenburg, as it turned out.)</p>
+
+<p>We located one of the technical people, now retired, who was on the scene in 1973 in
+order to verify a couple of minor items about Wattenburg’s financial involvement in this
+event. We got a lot more than we expected. We were able to get some of “the rest of the story” at this
+late date that was not available to the press in 1973.</p>
+
+<br />
+<p><b>Here is the story from press reports:</b></p>
+<br />
+
+<p>On June 4, 1973, in the San Francisco Chronicle (page 22), reporter Harris described how
+he was able to “boost” a 5-cent BART ticket to any value he wanted using an inexpensive scheme
+that Wattenburg had invented in a few hours. Worse yet, Wattenburg devised a simple scheme
+that any housewife could do in her kitchen! Harris described how the idea came to Wattenburg,
+and how he, reporter Harris, was later able to give startled officials a private demonstration at the
+Chronicle offices. The banking industry was about to issue the first of millions of credit cards
+that could have been counterfeited “by any high school kid”, according to Wattenburg. IBM and
+the banks went back to the drawing board for another year before they came up with a better
+scheme (that Wattenburg said he couldn’t easily beat—see story below).</p>
+
+<p>When Wattenburg was later asked by the press and angry government officials how he
+could so easily defeat the efforts of this country’s best engineers, he sent them the following
+apology:</p>
+
+<blockquote>“It’s not my fault. When engineers have too much money, they usually think only of the
+most sophisticated ways they can spend it. No one asks them to play devil’s advocate and think of
+the obvious until it’s too late. I never would have bothered to think about the subject. It was none
+of my business. Hell, I didn’t know that BART and banks all over the country were really planning
+to use this silly scheme.”</blockquote>
+
+<p>He continued:</p>
+
+<blockquote>
+<p>“All that happened is that this reporter Michael Harris, who is a very
+clever guy by the way, came along and bet me that I couldn’t find an easy way to copy this
+funny-looking BART ticket with a magnetic stripe. I thought it was just someone’s prototype idea. But
+he said that IBM had bragged that no one could do it for less than a half-million dollars. Now,
+that kind of gets a scientist’s juices flowing. I mean I didn’t interrupt my serious scientific work at
+Berkeley, but his challenge was on my mind for a few hours.</p>
+
+<p>“Suddenly, I remembered an obscure little thing about the physics of magnetic materials
+that most scientists don’t bother with very often. This phenomenon had given me fits in an
+experiment that I had done as a graduate student. Even my professor at the time didn’t believe it
+until I showed it to him. I thought, ‘Oh my God, the IBM guys couldn’t possibly have
+overlooked that! They’re the world’s experts on magnetic recording.’</p>
+
+<p>“I did a quick experiment with some magnetic tape that I bought at lunchtime in a music
+store on Shattuck Avenue, and damned if I wasn’t able to make a good copy of the BART ticket
+magnetic stripe that Harris had left with me to play with. I didn’t even have time to go to a BART
+station and see if my counterfeit ticket worked. When Harris came back the next day, I gave him
+the materials he would need and showed him how to do it in his kitchen at home. Well, you know
+the rest of the story. …”</p>
+</blockquote>
+
+<p>Wattenburg recently told us that he believed that the 1973 Business Week story contained
+some half-truths to steer thieves in the wrong direction. The press reports show him copying a
+credit card with another piece of magnetic tape. But the stories don’t explain that this was no
+ordinary piece of magnetic tape. He said that the 22 other ways discovered by Cal Tech students
+were all too clumsy or unreliable to be any threat. He believed that IBM and the banks didn’t
+really care if thieves concentrated on these. He said that the banks wanted the Business Week
+story written that way. He agreed to go along with the story for the sake of all the innocent
+people who could have lost their money, but it wasn’t pleasing to him to know all the things that
+were not disclosed to the press.</p>
+
+<p>He told us ruefully:</p>
+
+<blockquote><p>“At least I didn’t say anything dishonest to Business Week. They came around to
+see how I did it and I showed them the mechanics of how it could be done, They
+didn’t ask the right questions and I didn’t volunteer anything more. I hoped they would go out and
+try to copy a card with a piece of ordinary iron oxide magnetic tape, the way Michael Harris did.
+They would have discovered in a hurry that the scheme required something else special. But they
+didn’t. I was really surprised that they wrote the story without checking that. … That was the last
+time I ever took money to keep my mouth shut. I needed money at the time to do a lot of
+important scientific experiments that were on my mind, and I had a lot of good graduate students
+who needed support. The bankers were the big boys. Who was I to tell them what was ethical?
+But you know, when I asked them to provide a few scholarships, they turned me down. That is
+why it eventually cost them a hell of a lot more than a few scholarships.”</p>
+</blockquote>
+
+<p>One of Wattenburg’s scientist colleagues whom we interviewed in August 1990 told us
+what he thinks happened with the magnetic stripe. He said that obviously the whole thing was
+hushed up very quickly because of the potential losses due to thieves learning how to copy the
+magnetic stripe on the new bank credit cards. He said the rumor was that IBM or the
+banks, or both, paid Wattenburg a very handsome sum to help them devise a better scheme. He said that
+one of Wattenburg’s former Berkeley students who worked at IBM was asked to approach
+Wattenburg and that Wattenburg agreed to help them under the condition that he work only
+through his former student.</p>
+
+<p>This IBM engineer, Wattenburg’s former student, later went to work at Livermore. We
+were told that he took great joy in telling the funny stories that happened when the banking
+association attorneys tried to negotiate a deal with Wattenburg. He said they offered Wattenburg
+a very large amount of money if he would help them design a new scheme that couldn’t be
+counterfeited by anyone who did not have at least a hundred thousand dollars of specialized
+equipment which they itemized in the agreement. And Wattenburg had to agree to never again
+talk about or disclose to anyone how he had copied the BART card or anything about new
+schemes that would be developed. He said that Wattenburg agreed that the payment they offered
+seemed quite fair, provided there were a few minor changes. One change Wattenburg made to
+the agreement he sent back was “by anyone other than Wattenburg” in the clause “couldn’t be
+counterfeited by anyone”. The attorneys saw no problem with this because if he helped develop a
+new scheme, obviously he would be one of the few who would know how to beat it as well.
+They accepted the agreement.</p>
+
+<p>But then the bankers realized that Wattenburg could collect his money by only proving
+that “other people” could not copy some new magnetic stripe that he helped them develop. They
+protested that they already had a scheme that “other people” could not easily copy. They had paid
+large sums to universities and major consulting firms to have it tested and no one could copy it
+easily and reliably until Wattenburg came along.</p>
+
+<p>They demanded that Wattenburg change the language of the agreement. Wattenburg
+responded: “Well, tell me how much it is worth to you if I take it out.” Before it was over with,
+they had tripled the amount they first agreed to pay him. The former student said that Wattenburg
+succeeded in beating the next two magnetic stripe recording schemes that they proposed until
+they finally came up with one that he said he couldn’t beat without expensive equipment.</p>
+
+<p>Our contact laughed when he recalled what the former student often told his Livermore
+friends about Wattenburg’s assurance that he couldn’t beat the latest magnetic stripe scheme that
+is now used worldwide. He said: “I’ll bet that Wattenburg just got tired of fooling around with this
+business and told them it was OK. But, do you want to bet what will happen if Wattenburg is ever
+broke and he gets a hold of your credit card for a few hours?”</p>
+
+<hr />
+
+<p>We later learned that some of the 1973 press stories were probably encouraged for public
+consumption, and that maybe even Wattenburg left out a little of the story he told us—for a
+proper reason.</p>
+
+<p>Since this was the only episode in Wattenburg’s public exploits for which he admitted
+taking payment for his services, we decided to investigate it more deeply. In particular, we thought
+this would be a good situation in which to explore how he handled the confidentiality of his
+dealings with those who paid him in return for the same. We were able to locate the “former
+student” mentioned above. Now retired, he was willing to tell us almost all of “the rest of the
+story” since he felt that there was no danger at this late date.</p>
+
+<p>All of the above story is mostly true, as far as it goes. But there was more that the public
+was not told, and for good reason. He said that in the contract that they wanted Wattenburg to
+sign, he refused to disclose, even to IBM and the banks, the nature of the magnetic material he
+used to copy the BART and bank cards. Wattenburg had made some magnetic strips that looked
+like the ordinary Mylar-backed audio magnetic tape with the usual iron oxide magnetic surface,
+but it really had been coated with another special material. Wattenburg gave the reporter Michael
+Harris enough of this special magnetic tape to do his experiment at the BART ticket machines
+and for Harris to later give another demonstration to various officials at the Chronicle offices.
+They never knew for sure what the material was.</p>
+
+<p>He further explained that, unknown to Wattenburg, IBM and others had deliberately
+arranged the competition with Cal Tech students to see who could counterfeit the BART cards.
+But, the BART cards didn’t include all the coding safeguards that were used in the scheme that
+was designed for bank credit cards. He says he believes that IBM knew that most anyone could
+use simple magnetic tape reading equipment to read a BART card magnetic stripe and make a
+copy, as the Cal Tech students and others quickly proved. But, they were confident that no one
+could counterfeit the more valuable bank cards the same way because ordinary magnetic reading
+equipment could not read the special magnetic coding that they intended to use on the bank
+cards.</p>
+
+<p>In other words, he felt that the well-publicized student competition for copying the BART
+cards and the 22 schemes they came up with was a ruse to cause potential thieves to go in the
+wrong direction and frustrate themselves when the bank cards were issued. He said he learned
+that the first thing that IBM had tested was to make sure that their magnetic coding scheme on
+the bank cards could be not read by ordinary magnetic tape reading equipment. They were no
+fools.</p>
+
+<p>But they did not count on Wattenburg coming along. He found a way to physically copy
+the magnetic coding on the IBM stripe directly onto another magnetic stripe without using any
+intermediate electronic read-write cycle. His scheme copied everything, including the magnetic
+special coding on the bank cards that couldn’t be copied by inexpensive magnetic tape reading
+equipment. In fact, they found out that Wattenburg’s copies had as much resolution (were as
+good) as the original magnetic stripe that he had copied. This scared the hell out of them. This
+meant that he could copy the new bank cards as well.</p>
+
+<p>He said that Wattenburg refused to tell IBM or the bankers what the material was that he
+had used to make his special magnetic tape that could capture an image of their magnetic
+stripes—and could be accomplished in the kitchen. This was the real sticking point in the agreement that
+they wanted with him. Wattenburg insisted that if IBM scientists used their heads they would
+soon figure it our on their own. He felt that he didn’t want to be the one who gave license to
+thieves by being the first one to disclose it. He felt that the university would get a bad name. They
+finally settled on an agreement with him to help them anyway. And, they had to pay him
+handsomely to take out the “anyone other than Wattenburg” clause.</p>
+
+<p>He said that it became an obsession at IBM San Jose for the next year to figure out what
+Wattenburg had done. He remembers engineers and scientists meeting at lunch time to compare
+notes on their latest ideas and experiments. They even hired a guy from Livermore who had
+worked with Wattenburg to help them as a consultant. They found all sorts of new ways, but none
+of them could be accomplished with something so simple as a clothes iron the kitchen. He said
+that the attorneys got very angry with Wattenburg. They essentially accused Wattenburg of
+being a fraud and demanded that he disclose the answer or they would recommend that his future
+payments due under their contract be stopped. Our contact says that he had to take these
+communications to Wattenburg at the university. Wattenburg’s answer to the attorneys was that
+IBM ought to be very happy that their engineers were discovering so many new ways on their
+own that they never would have considered if they had not been trying to discover his way. He
+offered to demonstrate his scheme again anytime they would like.</p>
+
+<p>He says that he never heard whether they figured it out on their own or whether
+Wattenburg eventually told them. All he knows is that they eventually came up with a new scheme
+that could not be easily counterfeited by Wattenburg, so he said.</p>
+
+<p>He told us that he was impressed that, for ten years, Wattenburg would never tell even
+his best friends at Livermore who insisted that he could tell them his method under the strict
+security rules that prevailed at this nuclear weapons laboratory. He heard one senior laboratory
+official jokingly promise Wattenburg that he would personally stamp the document “classified” if
+Wattenburg would write it down for them. He said that Wattenburg would not even confirm
+what the answer was long after it had became generally known to scientists and engineers what
+the special material was that he had used.</p>
+
+<p>Our contact said that he always respected Wattenburg for never violating the agreement
+that he knew Wattenburg had signed with the bankers. But then he added: “if you knew how
+much they paid him in real dollars today, you would not have taken a chance on losing it either by
+opening your mouth just to show off.”</p>
+
+</body>
+</html>
\ No newline at end of file
--- /dev/null
+++ b/lib/ebooks/oebtest/dial-a-ride.html
@@ -1,0 +1,76 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE html PUBLIC "+//ISBN 0-9673008-1-9//DTD OEB 1.0 Document//EN"
+ "http://openebook.org/dtds/oeb-1.0/oebdoc1.dtd">
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/x-oeb1-document; charset=utf-8" />
+<link rel="stylesheet" type="text/x-oeb1-css" href="DrBillBio.css" />
+<title>Bill Wattenburg’s Background: Better Carpooling</title>
+</head>
+
+<body>
+
+<h1>Dial-A-Ride Carpooling</h1>
+
+<h2>(1973)</h2>
+
+<p>Bill Wattenburg upstaged the government bureaucracies during the 1973 energy
+crisis when the U.S. Energy Department proposed spending millions to organize
+all the state departments of motor vehicles across the country to use their
+files on motorists to match up citizens for carpools. They told Congress that
+they needed at least fifty million to subsidize the state agencies so that they
+could write the special computer programs required to do this within eighteen
+months. Wattenburg announced that the telephone companies could do the same
+thing immediately—at no extra cost to the taxpayers. And he proved it with a
+simple experiment.</p>
+
+<p>The San Francisco Chronicle reported Wattenburg’s idea on December 22, 1973.
+He pointed out that a person’s telephone numbers at home and at work were all
+that was needed to match him up with the nearest other person who drove
+approximately the same route. The telephone companies had all the address data
+for every telephone number. Their computer programs were ready to do the job
+with very little modification. All the government had to do was ask them. And,
+it wouldn’t cost the taxpayers a dime.</p>
+
+<p>He suggested that a person who wanted a carpool partner could simply dial a
+special “carpool” request code into his telephone and provide his work
+number. The telephone company, for a small charge, could then send him a list of
+all others who drove a similar route. Officials from Pacific Telephone Company
+in San Francisco agreed that Wattenburg was right. They said they would do it.</p>
+
+<p>The czar of the energy department appeared to like the idea and promised to
+implement it, but nothing official was announced. We asked Bill Wattenburg
+whatever happened to this neat idea. He told us:</p>
+
+<blockquote>
+<p>“All the state departments of motor vehicles were already counting the
+millions they had been promised from Washington. Some powerful congressmen
+complained that my idea was illegal according to the consent decree that
+prohibited telephone companies from using their computers to process data. It
+was stupid, but the Justice Department was never formally asked to waive the
+prohibition. The federal pork barrel money was sent out as promised.</p>
+
+<p>“However, most of the state motor vehicle people realized that my scheme was a
+lot easier and more comprehensive because the telephone company data is always
+far more complete than address data in the motor vehicle files. So, they just
+got the files from the telephone company that they needed and did the same
+thing. Obviously, they used the millions they got from Washington to pay for
+other things. The sad part is that most people still can’t simply use their
+telephones to arrange carpooling with the ease that should be available to them
+everywhere. But, California does this with a special 800 number.</p>
+
+<p>“As always, the state bureaucracies invented forms that people have to fill
+out to make a carpool request. This discourages most. But it keeps a lot of
+idiot bureaucrats busy. The people who could benefit the most from carpooling
+are not going to allow themselves to be matched up with other people by the
+government. And they avoid giving personal information to the government.
+However, most trust the telephone company.”</p>
+</blockquote>
+
+<p>We asked Wattenburg what he thought about not getting any official
+recognition for this. His answer was: “Ah, what the hell. That’s the usual
+case when you deal with bureaucrats. They know I made them do what I wanted. I
+made them jump. That’s good enough.”</p>
+
+</body>
+</html>
\ No newline at end of file
--- /dev/null
+++ b/lib/ebooks/oebtest/dial-a-ride.html.i
@@ -1,0 +1,9 @@
+3 pages
+size 400 562
+length 4055
+407 2 11 body html
+0
+1623 2 35 body html
+0
+2229 2 45 body html
+294
--- /dev/null
+++ b/lib/ebooks/oebtest/foreword.html
@@ -1,0 +1,40 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE html PUBLIC "+//ISBN 0-9673008-1-9//DTD OEB 1.0 Document//EN"
+ "http://openebook.org/dtds/oeb-1.0/oebdoc1.dtd">
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/x-oeb1-document; charset=utf-8" />
+<link rel="stylesheet" type="text/x-oeb1-css" href="DrBillBio.css" />
+<title>Bill Wattenburg’s Background: Editor’s Foreword</title>
+</head>
+
+<body>
+<a name="begin"></a>
+<h1>Editor’s Foreword</h1>
+
+<p>I received this report on Bill Wattenburg from a government agency as a
+public document, and am making it publicly available so that the public may learn of his many
+accomplishments and some insight into his character.</p>
+
+<p>If this little report isn’t enough, you can follow Bill’s continuing exploits at
+www.DrBill.org, which is a shortcut to a section of my main Web site, PushBack.com, that closely
+follows his radio show and other exploits.</p>
+
+<p>As a means of introduction to this report, you can start with Bill’s <a href="resume.html">résumé</a>,
+and some of the more interesting quotations that I are taken from this report
+<a href="QuotesFromBill.html">from Bill</a> and <a href="QuotesAboutBill.html">about Bill</a>. They
+are all interesting and provide a great introduction to Bill’s iconoclastic personality.</p>
+
+<p class="right">—Peter K. Sheerin<br />
+Webmaster and Editor-in-Chief, PushBack.com</p>
+
+<br />
+
+<p>P.S. If some of what you read seems hard to believe, then this quote from a very well known scientist who
+has worked with Bill should serve as a good introduction:</p>
+
+<blockquote><q>If anyone has spent $10 or $20 million on a difficult technical problem and not found a
+solution, they probably should have asked Bill Wattenburg First.”</q></blockquote>
+
+</body>
+</html>
\ No newline at end of file
--- /dev/null
+++ b/lib/ebooks/oebtest/foreword.html.i
@@ -1,0 +1,8 @@
+2 pages
+size 400 562
+length 1785
+409 2 11 body html
+0
+1581 2 36 body html
+32
+begin 0
--- /dev/null
+++ b/lib/ebooks/oebtest/foreword.html.index
@@ -1,0 +1,8 @@
+2 pages
+size 400 562
+length 1785
+409 2 11 body html
+0
+1581 2 36 body html
+32
+begin 0
--- /dev/null
+++ b/lib/ebooks/oebtest/hobbies.html
@@ -1,0 +1,44 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE html PUBLIC "+//ISBN 0-9673008-1-9//DTD OEB 1.0 Document//EN"
+ "http://openebook.org/dtds/oeb-1.0/oebdoc1.dtd">
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/x-oeb1-document; charset=utf-8" />
+<link rel="stylesheet" type="text/x-oeb1-css" href="DrBillBio.css" />
+<title>Bill Wattenburg’s Background: Hobbies</title>
+</head>
+
+<body>
+
+<h1>Hobbies</h1>
+
+<p>Wattenburg is an avid tennis player. He has played in many celebrity tennis tournaments
+around the country with his friends from Hollywood. He says that the decision as to where he
+travels nowadays depends a lot on where the sun is shining and where there is a tennis court. (We
+had to wait two hours at the Berkeley Tennis Club for the first interview we got with him.)</p>
+
+<p>Access to tennis courts will certainly be an important consideration to him before working in
+another city. We recommend that guaranteed membership in a first-class tennis club be part of
+any offer made to him.</p>
+
+<p>In the summertime, he still runs the bulldozers he learned to operate when he worked with his
+father in the logging woods years ago. He spends two to three weeks average each year fighting
+forest fires as a bulldozer operator (Catskinner) on the west coast with U.S. Forest Service
+firefighting crews. A U.S. Forest Service Supervisor in Plumas County, Calif., told us that,
+“There are not many old pros like him left anymore who can chase a forest fire on a bulldozer in the night
+over mountains so rugged that you can’t walk on them.” He said, “I mean fire crews won’t go
+where he takes a bulldozer. This guy attacks a fire just like it was trying to kill his kids. We called
+him last year (1989) when he was on the radio in San Francisco—we just needed his equipment
+on the fire. He was on the fire himself four hours later.”</p>
+
+<p>Wattenburg keeps two large bulldozers specially equipped for fire fighting at his ranch in
+northern California. He mentioned to us that nothing makes him so sad as to see the last of our
+virgin forests go up in smoke. There was anger in his voice when he told us that a lot of the
+heavy equipment operators nowadays (he called them hard-hat executives) just sit back and let a
+fire go until it changes course on its own and burns itself out. “Then they brag about how they
+bravely stopped this ten-thousand acre fire.” (We found him running a bulldozer when we
+interviewed him the second time at his ranch in Northern California. He gave one of us, who
+never learned to drive a car, a lesson on the bulldozer.)</p>
+
+</body>
+</html>
\ No newline at end of file
--- /dev/null
+++ b/lib/ebooks/oebtest/hobbies.html.i
@@ -1,0 +1,7 @@
+2 pages
+size 400 562
+length 2604
+397 2 11 body html
+0
+1015 2 24 body html
+255
--- /dev/null
+++ b/lib/ebooks/oebtest/index.html
@@ -1,0 +1,60 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE html PUBLIC "+//ISBN 0-9673008-1-9//DTD OEB 1.0 Document//EN"
+ "http://openebook.org/dtds/oeb-1.0/oebdoc1.dtd">
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/x-oeb1-document; charset=utf-8" />
+<link rel="stylesheet" type="text/x-oeb1-css" href="DrBillBio.css" />
+<title>Bill Wattenburg’s Background: Table of Contents</title>
+</head>
+
+<body lang="en-us">
+<a name="toc"></a>
+<h1>Table of contents</h1>
+<ol>
+ <li><a href="foreword.html">Editor’s Foreword</a></li>
+ <li><a href="ExecutiveSummary.html">Executive Summary</a></li>
+ <li>On The Air and Publishing
+ <ol>
+ <li><a href="TalkRadio.html">Talk Radio on the West Coast</a></li>
+ <li><a href="movies.html">Movies</a></li>
+ <li><a href="television.html">Television Shows</a></li>
+ <li><a href="publishing.html">Publishing</a></li>
+ </ol>
+ </li>
+ <li><a href="background-education.html">Background and Education</a>
+ <ol>
+ <li><a href="background-education.html#Hometown">Hometown</a></li>
+ <li><a href="background-education.html#Education">Education</a></li>
+ <li><a href="background-education.html#GraduateSchool">Graduate School</a></li>
+ <li><a href="background-education.html#AcademicWork">Academic Work</a></li>
+ </ol>
+ </li>
+ <li><a href="business.html">Business</a></li>
+ <li><a href="patents.html">Patents and Inventions</a></li>
+ <li><a href="awards.html">Awards</a></li>
+ <li><a href="hobbies.html">Hobbies</a></li>
+ <li><a href="covert.html">Covert Activities?</a></li>
+ <li><a href="colleague.html">A Colleague’s Observations</a></li>
+ <li>Public Service
+ <ol>
+ <li><a href="bloodbanks.html">Blood Banks</a></li>
+ <li><a href="HelicopterMinesweeper.html">Helicopters to Clear Minefields</a></li>
+ </ol>
+ </li>
+ <li><a href="confrontations.html">Public Confrontations</a>
+ <ol>
+ <li><a href="BART.html">Fixing BART Safety (Bay Area Rapid Transit System)</a></li>
+ <li><a href="creditcards.html">Magnetic Credit Cards</a></li>
+ <li><a href="dial-a-ride.html">Dial-A-Ride Carpooling</a></li>
+ <li><a href="MeasuringOilTanks.html">Seeing Inside Oil Tanks!</a></li>
+ <li><a href="GoldenGate.html">Golden Gate Bridge Traffic Barrier</a></li>
+ <li><a href="BlueWater.html">Blue Water (Copper) Contamination in Homes</a></li>
+ </ol>
+ </li>
+ <li><a href="GoldMine.html">The Gold Mine</a></li>
+ <li><a href="BentSub.html">Downhole Drillbit</a></li>
+</ol>
+</ol>
+</body>
+</html>
\ No newline at end of file
--- /dev/null
+++ b/lib/ebooks/oebtest/movies.html
@@ -1,0 +1,31 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE html PUBLIC "+//ISBN 0-9673008-1-9//DTD OEB 1.0 Document//EN"
+ "http://openebook.org/dtds/oeb-1.0/oebdoc1.dtd">
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/x-oeb1-document; charset=utf-8" />
+<link rel="stylesheet" type="text/x-oeb1-css" href="DrBillBio.css" />
+<title>Bill Wattenburg’s Background: Movie Projects</title>
+</head>
+
+<body>
+
+<h1>Movies</h1>
+
+<p>Bill Wattenburg played the tough guy talk show host and tennis player (Nolan
+Kennard) in Clint Eastwood’s 1988 Dirty Harry movie, “The
+Dead Pool”. He next worked with Eastwood and played the role of the pit boss in the
+filming of “Pink Cadillac”.</p>
+
+<p>Clint Eastwood made one of his rare public appearances on Wattenburg’s talk
+show to express his views on the political issues on the California ballot in
+November 1990. The two of them teamed up for two hours, live on KGO, before the
+California audience to support the Legislative Term Limit initiative,
+Proposition 140. This “voter’s revolt” was strongly opposed by the
+political powerhouses who were unleashing a multi-million dollar, last-minute TV
+blitz using other Hollywood personalities to defeat the initiative. The polls
+were predicting that Proposition 140 would be defeated. It passed two days
+later.</p>
+
+</body>
+</html>
\ No newline at end of file
--- /dev/null
+++ b/lib/ebooks/oebtest/patents.html
@@ -1,0 +1,53 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE html PUBLIC "+//ISBN 0-9673008-1-9//DTD OEB 1.0 Document//EN"
+ "http://openebook.org/dtds/oeb-1.0/oebdoc1.dtd">
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/x-oeb1-document; charset=utf-8" />
+<link rel="stylesheet" type="text/x-oeb1-css" href="DrBillBio.css" />
+<title>Bill Wattenburg’s Background: Patents</title>
+</head>
+
+<body>
+
+<h1>Patents and Inventions</h1>
+
+<p>Wattenburg holds patents on ideas as diverse as computer design, medical diagnostic
+instruments, power line communication systems, tennis training devices for handicapped people,
+movable traffic barriers for multi-lane highways, and home alarm systems. Asked which one he was
+most proud of, he singled out the home alarm systems he invented in 1964 when he was a young
+professor at U.C. Berkeley. This invention (patent 3,460,121, Signaling and Communication
+System, 1965) has saved thousands of lives over the last twenty years. Hundreds of thousands of
+home fire and smoke alarm systems based on his patent were installed in homes in the U.S.,
+Canada, and Europe.</p>
+
+<p>He holds the original patent on the use of existing electrical house wiring as a means for
+communicating alarm signals from sensors, such as smoke detectors, to receivers placed
+elsewhere in the building. His inexpensive design was the first that eliminated the need for
+separate wiring to connect multiple alarm devices to remote receivers far away in the same
+building or even outside the building on the same power line.</p>
+
+<p>His home and building alarm systems were originally marketed by the Heath Company
+(Heathkit) in Benton Harbor, Michigan. They were able to sell smoke and fire alarm systems to
+protect all areas of a home for less than $100. The technology in his original patent is now used
+by many companies all over the world for a wide variety or electronic and alarm devices that plug
+into power receptacles and use the power lines to communicate electrical signals. He also
+invented one of the first inexpensive smoke alarms for homes which was installed in hundreds of
+thousands of homes throughout the U.S. beginning in 1967. His two inventions allowed several
+hundred thousand homeowners to have reliable fire and smoke alarm systems that would
+otherwise have been too expensive by the old procedure of installing special wiring for an alarm
+system.</p>
+
+<p>Since this was his first patent, we asked him what it was like and how did he come up with
+the idea. He said that a friend of his was going to have to pay over twenty thousand dollars to
+have a standard fire alarm system put in a warehouse that he owned. Wattenburg said that he
+asked his friend if he could have half that much if he could find a cheaper way than having to put
+special wiring in the whole building. He shrugged his shoulders and told us: “Well anyway, I
+needed some money for more important experiments that I wanted to do about that time. I had
+no choice.”</p>
+
+<p>We asked him if it made a lot of money. He answered: “Oh yes, about twenty times what
+I needed in those days. It carried me over until I got some really expensive ideas.”</p>
+
+</body>
+</html>
--- /dev/null
+++ b/lib/ebooks/oebtest/patents.html.i
@@ -1,0 +1,7 @@
+2 pages
+size 400 562
+length 3173
+397 2 11 body html
+0
+1538 2 30 body html
+85
--- /dev/null
+++ b/lib/ebooks/oebtest/publishing.html
@@ -1,0 +1,73 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE html PUBLIC "+//ISBN 0-9673008-1-9//DTD OEB 1.0 Document//EN"
+ "http://openebook.org/dtds/oeb-1.0/oebdoc1.dtd">
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/x-oeb1-document; charset=utf-8" />
+<link rel="stylesheet" type="text/x-oeb1-css" href="DrBillBio.css" />
+<title>Bill Wattenburg’s Background: Publishing</title>
+</head>
+
+<body>
+
+<h1>Publishing</h1>
+
+<p>Bill Wattenburg is also the comical author Will Harvey who once entertained
+nationwide audiences on major TV shows such as “The Phil Donahue Show” and
+“The Tonight Show”. Wattenburg’s media career began when he wrote a surprising
+best-seller while he was the president of a scientific laboratory in Berkeley.
+He had written short stories during his college days. He told us that in 1971 a
+group of women at a University cocktail party, who had read some of his short
+stories, bet him that he couldn’t write a book that was funnier than the New
+York Times’ then best-seller on sexual fantasies,
+<i>The Sensuous Woman</i>. So, he whipped
+out a book for them in three weeks with the title <i>How To Be Good To A Woman</i>,
+which they liked enough to make hundreds of Xerox copies of the manuscript to
+send to friends all over the country. But New York publishers said it wouldn’t
+sell when he tried to give it to them to publish, free—so his friends could buy
+cheaper copies. Unconvinced, he changed the title of the book to <i>How To Find
+And Fascinate A Mistress</i>, changed “woman” to “mistress”
+in the text, and had a Berkeley printer produce the first five thousand
+hardcover with a catchy jacket designed by his engineering draftsmen. He then
+gave away 200 copies to airline flight attendants (for whom he had written a complimentary
+chapter in the book). Orders began coming in from all over the country.</p>
+
+<p>Three months later, his kitchen publishing company, Montgomery Street Press,
+had shipped over sixty-thousand hardcover copies to every major bookstore chain
+in the country. The New York publishing houses that could have had the book for
+nothing were soon bidding for the paperback rights. Pocketbooks (Simon and
+Schuster) finally bought the paperback rights for a reported $650,000.
+Pocketbooks sent him out on a national promotion tour to a few major TV shows.
+Requests then poured in from other shows all over the country who wanted him.
+Over the next year, he appeared as funnyman Will Harvey on over 130 local and
+national TV and radio shows. He was invited back to some major shows several
+times in 1972. Paperback sales of his book climbed to over 2,000,000 as he
+tickled audiences all over the country with his cowboy humor and the image of
+the hapless male struggling to keep up with the sexually aggressive women of the
+burgeoning feminist movement.</p>
+
+<p>A former Pocketbooks executive has told us that Wattenburg received an
+advance for the paperback rights of “over $500,000”. She remembered
+that he caused quite a problem at Simon and Schuster during the bidding for the
+paperback rights to his book. She recalled: “He didn’t have an agent. He
+thought that our standard royalty contracts with authors were crazy. He demanded
+a guaranteed cash payment up front—not conditioned on future book sales, as was
+the usual case. He cleaned up after that. I think he still owns the
+hardcover. … He wouldn’t stay at some of the best hotels we booked him into
+during the promotion tours. He found out that travel expenses were being
+deducted from his royalties after sales went above, I think, 2,000,000. … He
+drove us nuts. We had to plead with some famous newspaper columnists and book
+reviewers to meet him for interviews at Holiday Inns. …”</p>
+
+<p>Before it was over, the book that he had tried to give away had earned him
+over $1,300,000! It was published in six countries. Bantam books bought the
+rights to his next book for an undisclosed sum. He says he still has to explain
+on the radio to women who like to tease him that “in no way could I ever
+live up to the exploits of Will Harvey.”</p>
+
+<p>We asked him in 1990 why he didn’t write more books. He said: “You can
+sometimes beat the pros at their own game once. But they don’t often let you get
+away with it a second time. It’s much easier to find another field.”</p>
+
+</body>
+</html>
\ No newline at end of file
binary files /dev/null b/lib/ebooks/oebtest/raport-small.png differ
binary files /dev/null b/lib/ebooks/oebtest/raport.png differ
--- /dev/null
+++ b/lib/ebooks/oebtest/resume.html
@@ -1,0 +1,64 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE html PUBLIC "+//ISBN 0-9673008-1-9//DTD OEB 1.0 Document//EN"
+ "http://openebook.org/dtds/oeb-1.0/oebdoc1.dtd">
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/x-oeb1-document; charset=utf-8" />
+<link rel="stylesheet" type="text/x-oeb1-css" href="DrBillBio.css" />
+<title>Bill Wattenburg’s Background: Résumé</title>
+</head>
+
+<body>
+
+<h1>Dr. Bill Wattenburg’s Résumé</h1>
+
+<h2>1980–Present</h2>
+<ul>
+ <li>Research Scientist and Adjunct Professor of Science, University Foundation, California
+State University, Chico.</li>
+ <li>Consultant, Lawrence Livermore National Laboratory.</li>
+ <li>Talk show host, “The Open Line to the West Coast” (Sat. and Sun. 10pm to 1am), KGO Radio AM-810,
+ American Broadcasting Company, San Francisco (since 1972).</li>
+</ul>
+<h2>1965–1980</h2>
+<ul>
+ <li>Co-founder of Berkeley Scientific Laboratories, Berkeley, California, 1966, with Dr. Donald Glaser,
+ (Nobel Prize, Physics, 1960).</li>
+ <li>President, Berkeley Scientific Laboratories, 1966–1970.</li>
+ <li>Co-founder and Chairman of the Board, Comprehensive Health Services (later reorganized as
+ Comprehensive Computer Services and Bakte-Bennent Medical Laboratories), 1970–1980.</li>
+ <li>Member of:<br />
+ U.S. Air Force Scientific Advisory Board, 1967–1970.<br />
+ Subcommittee on Nuclear Defense Systems (headed by Dr. Edward Teller).</li>
+</ul>
+<h2>1961–1967</h2>
+<ul>
+ <li>Assistant Professor, Electrical Engineering, U.C. Berkeley</li>
+ <li>Staff member, Lawrence Livermore National Laboratory, Physics Division.</li>
+ <li>Consultant:
+ <ul>
+ <li>Lockheed Missiles and Space Company</li>
+ <li>IBM Corporation</li>
+ <li>General Electric Co.</li>
+ <li>Bellcom (NASA Apollo Project)</li>
+ </ul>
+ </li>
+</ul>
+<h2>Education</h2>
+<ul>
+ <li>1961: Ph.D., Electrical Engineering and Physics, U.C. Berkeley</li>
+ <li>1959: Master’s Degree, Electrical Engineering, U.C. Berkeley</li>
+ <li>1958: B.S., Electrical Engineering, California State University, Chico.</li>
+</ul>
+<h2>References</h2>
+<ul>
+ <li>Dr. John Nuckolls, former Director, Lawrence Livermore National
+ Laboratory, Livermore, California (currently Director Emeritus)</li>
+ <li>Mr. Michael Luckoff, President, KGO Radio, San Francisco, California.</li>
+ <li>Dr. Edward Teller, Hoover Institute, Stanford University.</li>
+ <li>Mr. James Roberts, Chief Engineer, California Department of Transportation,
+ Sacramento, California.</li>
+</ul>
+
+</body>
+</html>
\ No newline at end of file
--- /dev/null
+++ b/lib/ebooks/oebtest/television.html
@@ -1,0 +1,38 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE html PUBLIC "+//ISBN 0-9673008-1-9//DTD OEB 1.0 Document//EN"
+ "http://openebook.org/dtds/oeb-1.0/oebdoc1.dtd">
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/x-oeb1-document; charset=utf-8" />
+<link rel="stylesheet" type="text/x-oeb1-css" href="DrBillBio.css" />
+<title>Bill Wattenburg’s Background: Television Shows</title>
+</head>
+
+<body>
+
+<h1>Television Shows</h1>
+
+<p id="dolphins">Bill Wattenburg’s first television show was an expose on the slaughter of
+dolphins by tuna fishing fleets called “The Last Days of the Dolphins”,
+which Westinghouse Broadcasting aired nationally in 1975. Strong complaints from
+major food company advertisers who market tuna almost cancelled the show. The
+original celebrity host had backed out after major advertisers complained.
+Wattenburg agreed to replace him. This shocking documentary showed the needless
+slaughter of 500,000 dolphins a year because tuna fisherman refused to change
+the crude nets they had been using for decades. Congress outlawed the old nets a
+week after this dramatic show was aired nationwide.</p>
+
+<p id="KPIX">Westinghouse Broadcasting Co. (KPIX Channel 5 TV, San Francisco) then asked Bill
+Wattenburg to host a new half-hour newsmagazine show which aired on Friday
+nights primetime (The People’s Five Show) from September 1975 to 1977. They used one of
+the first TV mini-cams to shoot the show “on the street” with only one
+cameraman-director, host Wattenburg, and no scriptwriters.</p>
+
+<p>This show and its format were later expanded to become Westinghouse’s
+“Evening Magazine”, which has been syndicated nationwide since 1977 <i>[usually
+under the name “P.M. Magazine” outside of the SF broadcasting area</i>—<i>PKS]</i>.
+Wattenburg returned to weekend talk radio and his scientific work at the
+university when the TV show went to five nights a week.</p>
+
+</body>
+</html>
\ No newline at end of file
--- /dev/null
+++ b/lib/ebooks/oebtest/toc.html
@@ -1,0 +1,59 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE html PUBLIC "+//ISBN 0-9673008-1-9//DTD OEB 1.0 Document//EN"
+ "http://openebook.org/dtds/oeb-1.0/oebdoc1.dtd">
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/x-oeb1-document; charset=utf-8" />
+<link rel="stylesheet" type="text/x-oeb1-css" href="DrBillBio.css" />
+<title>Bill Wattenburg’s Background: Table of Contents</title>
+</head>
+
+<body lang="en-us">
+<a name="toc"></a>
+<h1>Table of contents</h1>
+<ol>
+ <li><a href="foreword.html">Editor’s Foreword</a></li>
+ <li><a href="ExecutiveSummary.html">Executive Summary</a></li>
+ <li>On The Air and Publishing
+ <ol>
+ <li><a href="TalkRadio.html">Talk Radio on the West Coast</a></li>
+ <li><a href="movies.html">Movies</a></li>
+ <li><a href="television.html">Television Shows</a></li>
+ <li><a href="publishing.html">Publishing</a></li>
+ </ol>
+ </li>
+ <li><a href="background-education.html">Background and Education</a>
+ <ol>
+ <li><a href="background-education.html#Hometown">Hometown</a></li>
+ <li><a href="background-education.html#Education">Education</a></li>
+ <li><a href="background-education.html#GraduateSchool">Graduate School</a></li>
+ <li><a href="background-education.html#AcademicWork">Academic Work</a></li>
+ </ol>
+ </li>
+ <li><a href="business.html">Business</a></li>
+ <li><a href="patents.html">Patents and Inventions</a></li>
+ <li><a href="awards.html">Awards</a></li>
+ <li><a href="hobbies.html">Hobbies</a></li>
+ <li><a href="covert.html">Covert Activities?</a></li>
+ <li><a href="colleague.html">A Colleague’s Observations</a></li>
+ <li>Public Service
+ <ol>
+ <li><a href="bloodbanks.html">Blood Banks</a></li>
+ <li><a href="HelicopterMinesweeper.html">Helicopters to Clear Minefields</a></li>
+ </ol>
+ </li>
+ <li><a href="confrontations.html">Public Confrontations</a>
+ <ol>
+ <li><a href="BART.html">Fixing BART Safety (Bay Area Rapid Transit System)</a></li>
+ <li><a href="creditcards.html">Magnetic Credit Cards</a></li>
+ <li><a href="dial-a-ride.html">Dial-A-Ride Carpooling</a></li>
+ <li><a href="MeasuringOilTanks.html">Seeing Inside Oil Tanks!</a></li>
+ <li><a href="GoldenGate.html">Golden Gate Bridge Traffic Barrier</a></li>
+ <li><a href="BlueWater.html">Blue Water (Copper) Contamination in Homes</a></li>
+ </ol>
+ </li>
+ <li><a href="GoldMine.html">The Gold Mine</a></li>
+ <li><a href="BentSub.html">Downhole Drillbit</a></li>
+</ol>
+</body>
+</html>
\ No newline at end of file
--- /dev/null
+++ b/lib/ebooks/oebtest/toc.html.i
@@ -1,0 +1,8 @@
+2 pages
+size 400 562
+length 2515
+420 2 11 body html
+0
+467 2 14 body html
+459
+toc 0
--- /dev/null
+++ b/lib/ebooks/oebtest/toc.html.index
@@ -1,0 +1,8 @@
+2 pages
+size 400 562
+length 2533
+420 2 11 body html
+0
+467 2 14 body html
+459
+toc 0
binary files /dev/null b/lib/ebooks/understandingoeb/OEBActivityDiagram.png differ
binary files /dev/null b/lib/ebooks/understandingoeb/OEBClassDiagram.png differ
--- /dev/null
+++ b/lib/ebooks/understandingoeb/chapter1.html
@@ -1,0 +1,114 @@
+<?xml version='1.0'?>
+<!DOCTYPE html PUBLIC "+//ISBN 0-9673008-1-9//DTD OEB 1.0.1 Document//EN" "http://openebook.org/dtds/oeb-1.0.1/oebdoc101.dtd">
+<?xml-stylesheet href="understandingoeb.css" type="text/x-oeb1-css"?>
+
+<html>
+<head>
+ <link rel="stylesheet" type="text/x-oeb1-css" href="understandingoeb.css" />
+<title>Understanding OEB Chapter 1</title>
+ <meta name="author" content="Garret Wilson" />
+ <meta name="copyright" content="Copyright (c) 2000-2001 Garret Wilson. All rights reserved." />
+</head>
+
+<body>
+
+<h2 id="chapter1">1. Defining a Beginning</h2>
+
+<p>eBooks are by no means new. For years educators have been creating multimedia learning systems, businesses have been showing interactive kiosks, entrepreneurs have been showing electronic presentations, and corporations have been distributing PDF documents. Michael Hart's Project Gutenberg has been giving away electronic texts for, well, practically since computers were invented. A student creates an eBook when she writes a report for college. Your brother writes an eBook when he enters recipes into his computer. I listen to an eBook when I download an MP3 from...</p>
+
+<p>"Wait," you might say. "Those aren't really eBooks." You might say that because you've noticed some fundamental difference between eBooks and other electronic things, but more likely you would say that because you have an intuitive notion of what an eBook is.</p>
+
+<p>Unfortunately, many people have conflicting ideas about which electronic "things" are eBooks. Are eBooks hardware devices, or software? Are eBooks merely textual electronic content? Normal books can be shown on overhead projectors — is an electronic presentation an eBook? What's the difference between a file of recipes and a book full of recipies? An MP3 file isn't an eBook because you can't hear books — yet don't many companies sucessfully sell "audio books" on cassette?</p>
+
+<p>It should be painfully obvious at this point that to adequately discuss the Open eBook specification, it might be wise to find out exactly what an <dfn>eBook</dfn> is. Somewhat less obvious but no less painful is that I don't really know what an eBook is, either. Sorry. Even if I did, well, it probably wouldn't be the same thing that <em>you</em> think an eBook is. And whatever we thought, we'd likely change our minds once we thought about it a little longer. But don't worry, you're in good company — no one else in the "eBook industry" knows what an eBook is, either, although they all have ideas about what they want you to think an eBook is.</p>
+
+<h3 id="definingEBook">Defining "eBook"</h3>
+
+<p>In this book we'll try to skirt the issue of creating an authoritative definition of an eBook, considering an eBook to broadly mean whatever electronic content you want to present. We'll specifically discuss the <em>Open eBook Publication Structure</em> and the types of content it allows one to publish, allowing you to determine whether this format is right for your content. While we discuss the <em>Open eBook Publication Structure</em> and related publications, though, we'll need to come to some definitions that we agree upon, at least in the context of our discussion, which will allow us to know what the other is talking about.</p>
+
+<div class="sidebar" id="oebDefinitions">
+<h4 class="sidebarTitle">More Information: OEB and Definitions</h4>
+<p>Most specifications, the OEB Publication Structure included, recognize the definition problem soon enough, as industry leaders sit around a table arguing for hours before realizing that they agree — they just used different words to express their viewpoints. For this reason, most specifications include a <dfn>glossary</dfn> of terms and their definitions as used within the specification.</p>
+
+<p>Glossaries are fine for one specification, but in the eBook world there are many separate relevant documents that use different terminologies to mean the same thing, or use the same terminology to mean different things. The OEB Forum has recently therefore committed to creating a terminology that can be used as a common language for the eBook industry as a whole. The Forum has even gone so far as to create a framework for explaining how different players in the eBook industry might give different meanings, based upon their backgrounds, for the words they use.</p>
+
+<p>Such a defining of terms is a necessity for the eBook industry to be able to efficiently move forward with other open, interdependent specifications related to the OEB Publication Structure. Currently the effort refers to this framework as an <dfn>ontology</dfn>, referring to the eBook industry as a whole as an <dfn>ePublishing ecology</dfn>. This framework is not yet finalized, but there have been reports that the terms "ontology" and "ecology" will be defined Real Soon Now.</p>
+</div>
+
+<h4 id="eText">Electronic Book as an "Etext"</h4>
+
+<p>One of the first and most famous popularizations of books in electronic format was Project Gutenberg (<a href="http://www.gutenberg.org">http://www.gutenberg.org</a>). According to his own rendition (<a href="http://promo.net/pg/history.html">http://promo.net/pg/history.html</a>), Michael Hart in 1971 was granted access to a mainframe at the University of Illinois. Wanting to make productive use of the precious time he had been allotted on such a scarce resource, he entered the United States "Declaration of Independence" electronically and attempted to send it to everyone on the networks.</p>
+
+<p>Luckily, such an act occurred before the concept of spam and before the notoriety of computer viruses, so whatever negative repercussions of such unrequested correspondence did not spread far. Michael soon changed from actively sending these <dfn>electronic texts</dfn> (Etexts), as he calls them, to instead archiving them so that they can be downloaded from anyone at any time from anywhere. According to their published figures, Project Gutenberg went from archiving only 100 Etexts in January 1994 to 3333 Etexts in April 2001.</p>
+
+<p>Michael Hart's Etexts were certainly related to books — they did contain the same text word for word (more or less, in many cases page numbers and all) as the book from which they were taken. There was nothing "book-like" about these works, though. A user can read an Etext with whatever tool he/she has available, such as a text editor or word processor. As electronic versions of textual content of a book, though, Etexts could certainly fit one definition of an "eBook."</p>
+
+<h4 id="eBookHype">"eBook" as a Marketing Tool</h4>
+
+<p>By the late 1990s, several companies were attempting to make electronic versions of books that not only replicated the book's content but also duplicated the look of a book. Nuvomedia made a device the size of a small paperback named the Rocket eBook, and Softbook created a somewhat larger device called the Softbook Reader. Both were <dfn>dedicated</dfn> eBook reading devices; their only purpose in their electronic life was to show electronic texts. It seemed that so much attention was paid to the small packages of plastic and silicon that the devices themselves were referred to as "eBooks". It never really seemed clear what the textual content was called.</p>
+
+<p>One thing was clear, though: there needed to be some way for this textual content to somehow interoperate with both devices. Either company assumed it could win any war of device creation and marketing, but there were more immediate concerns: if the market for these new devices was to explode as these two companies hoped, they needed the help of the publishers from whom the textual content originated. They knew that publishers would not want to create electronic versions of their text in two separate formats, one for the Rocket eBook and another for the Softbook Reader.</p>
+
+<p>In late 1998 these two companies were joined by a third: Microsoft. Together these corporations formed an informal group of companies that vowed to prevent a "VHS vs. Betamax" war of formats in the eBook industry by inventing a common format in which electronic information could be stored. The Open eBook (OEB) Authoring Group they formed set out to create a specification that would allow publishers to release content in one format and know that any of the devices could access the stored information.</p>
+
+<p>Further divorcing the term "eBook" from the concept of a particular device was Microsoft's announcement in 1999 that it would be releasing the Microsoft Reader software. This software would run on any Windows-based computer and would allow eBooks to be downloaded and read without the need for a dedicated reading device. With the support of these two device manufacturers, a software giant, and other members of the OEB Authoring Group such as Versaware, Nokia, and GlobalMentor, the idea of an electronic book became a marketable idea around which each proponent could advance its own desires of profitability. The term "eBook" began to represent not just electronic text, but electronic text in the context of a new industry that would, it was claimed, change reading forever.</p>
+
+<h4 id="eBookInevitibility">The eBook as Inevitable</h4>
+
+<p>At this point we haven't really come any closer to knowing what an eBook is, but we've picked up a few other terms such as "reader" and "publisher" which themselves cry out for definitions. Before inevitably drawing artificial lines in the sand, it would be profitable to examine just what is significant about the eBook as an industry.</p>
+
+<p>It could be that the "universal format" argument of OEB is somewhat of a hollow one. As you'll learn, some parts of OEB by themselves are inadequate for complex textual content. Furthermore, although some software programs allow you to read OEB-based eBooks directly, on other devices and software products what you'll read is not OEB, but OEB text that has been manipulated and transformed into something specific to that device or software. eBooks in general and OEB in particular do in fact represent something very significant, though: the inevitability of electronic information storage and interaction.</p>
+
+<ol>
+ <li><strong>Convenience</strong>. Electronic song storage and listening is already too popular to fade. The convenience and space-saving efficiency of electronic music are no less significant in the world of electronic texts.</li>
+ <li><strong>Versatility</strong>. Once a book is in electronic format, it can be manipulated and presented in a variety of formats on a number of different devices.</li>
+ <li><strong>Storage</strong> Books that are stored electronically take up no physical space and can be transported with ease.</li>
+</ol>
+
+<p>eBooks give the promise of true foreverness and universality to information. OEB is significant because its authors were wise enough to base it on several elegant standards that were already popular, robust, and that provide no roadblocks to international access. Will the OEB texts you create five years from now look like the OEB works you create today? Maybe. But because of OEB's foundations, the OEB eBooks you write will either work just as well as they do now or will be easily manipulated so that they can. In short, OEB is important because of the standards-compliant ways it requires you to encode your works. Whatever "OEB" means five years from now, the OEB works of today will still be useful.</p>
+
+<h3 id="oebMeaning">The Meaning of OEB</h3>
+
+<p>A year of hard work by the Open eBook Authoring Group led to the release on 16 September 1999 of the <em class="title">Open eBook Publication Structure 1.0</em>. This specification, which has recently been clarified and refined by version 1.0.1, defines a <dfn>publication structure</dfn> or format in which one can store a particular work. A work created in OEB format is called, appropriately, an <dfn>OEB publication</dfn>.</p>
+
+<p>In early 2000 the OEB Authoring Group became a formal body named the Open eBook Forum (OEBF) (<a href="http://www.openebook.org">http://www.openebook.org</a>). The term "OEB" itself is used in a multitude of contexts. Sometimes the OEB Forum is referred to as "OEB"; at other times, "OEB" refers to the <em class="title">OEB Publication Structure</em> which defines OEB Publications. Here we'll try to be specific about how we use OEB unless the meaning is clear from the context. In general, "OEB" will be used to designate that something has been produced by the OEB Forum, such as the <em>Open eBook Publication Structure</em> itself.</p>
+
+<p><object data="OEBClassDiagram.png" type="image/png">OEB Class Diagram</object></p>
+
+<p>The <em>Open eBook Publication Structure</em> is a specification for a document format, but to understand this format in context the specification divides the world into several abstract parts. In particular, a <dfn>publication</dfn> is meant for storing eBook content, and this content is processed and displayed to the user by a <dfn>reading system</dfn>. OEB calls the person reading the content the <dfn>reader</dfn>, which may be confusing to those who use software packages that contain "Reader" in their names.</p>
+
+<p><object data="OEBActivityDiagram.png" type="image/png">OEB Activity Diagram</object></p>
+
+<p><em class="rhetoricalQuestion">Is a reading system a piece of software?</em> Perhaps, but it could also be a hardware device. In fact, the reading system could be a piece of software that processes the OEB publication and stores it in a different form to be read by the reader on a hardware device.</p>
+
+<p><object data="ReadingSystemClassDiagram.png" type="image/png">Reading System Class Diagram</object></p>
+
+<p>The reading system is a convenient abstraction that allows the OEB publication structure specification to define how an OEB publication must be constructed, as well as how it must be interpreted and presented to a reader. As long as the rules in the <em>OEB Publication Structure</em> are followed, any number of things could work together and be classified as one "reading system". This allows a strict definition of how pieces of a system interact, without restricting innovation in implementing the various system components.</p>
+
+<p><em class="rhetoricalQuestion">Is the OEB publication actually delivered to the reader?</em> This depends on the particular reading system being used. Some reading systems may combine both the processing and the display of the OEB publication into one piece of software or into one hardware device. In other instances, a reading system may be composed of several components: one piece of software may read the OEB publication and interpret it and store it in a proprietary format that only the second display portion of the reading system can understand. It is then this proprietary version of the text that is used to display the data to the reader. In this scenario, the two pieces together would comprise the reading system.</p>
+
+<p>OEB does not care what type (if any) of intermediate files are produced before the content is shown to the user. The usefulness of the OEB publication, therefore, is not directly related to the user, but to the publisher. The author and/or publisher must convert content to only <em>one</em> format: the OEB publication structure format. Any OEB-compliant reading system will have the means to either display the OEB publication directly, or to convert it into a format that it can display or allow another component to display.</p>
+
+<p>The most important task as far as an author or publisher is concerned is therefore ensuring a work is in the OEB publication structure format. Any OEB-compliant reading system will be able to do whatever it needs to do to allow your content to be accessed by a reader.</p>
+
+<h3 id="usingOEB">Using OEB</h3>
+
+<p>All examples in this book (and this book itself) should be fully compliant with the <em>Open eBook Publication Structure</em> version 1.0.1. It should be possible to read each example using a OEB reading system that fully complies with the specification. As explained above, various OEB reading systems are available — some that use software combined with hardware, some that use separate software components, and some that can natively read an OEB-encoded work and display the eBook to the reader immediately.</p>
+
+<p>The Mentoract™ Reader from GlobalMentor, Inc. is one example of a native software-based OEB reading system. To read the example eBooks presented here, simply load an OEB package file or an individual OEB document (both of which will be explained in upcoming chapters) in the Mentoract Reader by selecting <code>File|Open...</code> from the pull-down menu. The Mentoract Reader is written in the Java programming language and can therefore run on a variety of desktop and notebook operating systems. The Mentoract™ Reader is available from <a href="http://www.globalmentor.com/software/reader/">http://www.globalmentor.com/software/reader/</a> as a free download.</p>
+
+<p>Other software-based reading systems, such as the Microsoft Reader from Microsoft Corporation, require two components for processing an eBook. The first component, such as the ReaderWorks software from OverDrive, Inc., manipulates the OEB files into a proprietary Microsoft file format named LIT. This LIT file can then be read using the Microsoft Reader. ReaderWorks is available from <a href="http://www.overdrive.com/readerworks/">http://www.overdrive.com/readerworks/</a> and the Microsoft Reader is available from the <a href="http://www.microsoft.com/reader/">http://www.microsoft.com/reader/</a> site.</p>
+
+<p>Various hardware eBook devices exist as well. Each usually comes with the appropriate software to process your OEB files so that they can be used with the device. Check with your specific eBook hardware vendor for more information on regarding the level of OEB support.</p>
+
+<h3 id="review">Review</h3>
+
+<h4 id="summary">Summary</h4>
+<ul>
+ <li>In the OEB world, an OEB Publication is processed by a reading system and presented to a reader.</li>
+ <li>A reading system is an abstract concept; a reading system implementation may be composed of hardware, software, or both.</li>
+ <li>A reading system may present information to the reader directly from the OEB publication, or it may create one or more intermediate files. The OEB publication structure specification only defines that an OEB publication must be input to the reading system, and that the reading system correctly present the information to the reader.</li>
+</ul>
+
+</body>
+</html>
--- /dev/null
+++ b/lib/ebooks/understandingoeb/chapter2.html
@@ -1,0 +1,442 @@
+<?xml version='1.0'?>
+<!DOCTYPE html PUBLIC "+//ISBN 0-9673008-1-9//DTD OEB 1.0.1 Document//EN" "http://openebook.org/dtds/oeb-1.0.1/oebdoc101.dtd">
+<?xml-stylesheet href="understandingoeb.css" type="text/x-oeb1-css"?>
+
+<html>
+<head>
+ <link rel="stylesheet" type="text/x-oeb1-css" href="understandingoeb.css" />
+<title>Understanding OEB Chapter 2</title>
+ <meta name="author" content="Garret Wilson" />
+ <meta name="copyright" content="Copyright (c) 2000-2001 Garret Wilson. All rights reserved." />
+</head>
+
+<body>
+
+<h2 id="chapter2">2. Understanding an OEB Publication</h2>
+
+<p>When you write a letter or create a report, you usually think of your end product as one entity: "my essay" or "Ralph's grocery list." Depending on how fancy you get, your document might have several pages with graphs, pictures, links, or even a sound clip. Depending on which application you use to create the document, the pictures might be separate clip art files or they might be embedded directly in the document. You may not know where the pictures are stored, and you may not care.</p>
+
+<p>Here you'll learn how to create a book in the OEB format by hand. Doing so is straightforward and easy, but there are several things you <em>will</em> have to know about and keep track of, such as the location of whatever graphics (if any) you have in your book. To keep things straight in the discussion, OEB uses the term <dfn>OEB Publication</dfn> to refer to all of the items — the pictures, charts, text, and everything else in your book — that are included in your work. We'll sometimes use just <dfn>publication</dfn> to mean the same thing.</p>
+
+<p><object data="OEBPublicationClassDiagram.png" type="image/png">OEB Publication Class Diagram</object></p>
+
+<p>You'll therefore be creating a publication, which consists of several items: an <dfn>OEB Package</dfn>, one or more <dfn>OEB Documents</dfn>, and other related files. The simplest publication would simply have two files: a package and a document. In fact, the first publication we'll create here will be that simple, including the book itself (the document) and a separate file (the package) that simply gives information about the book.</p>
+
+<h3 id="oebdocument">An OEB Document</h3>
+
+<p>Let's assume you already have a book. Your book is quite short — only one paragraph long. You've spent hours on every word, and now you're ready to introduce it to the world. Your book reads:</p>
+
+<blockquote>
+Years ago, when strange creatures ruled the earth, the seas were beginning to form, and humans had yet to appear, there lived a young blovjus named Karl. Karl had three siblings: Kris, Krista, and Karla. Being extremely smaller than other blovji his age, Karl constantly ran into trouble at the dinner table.
+</blockquote>
+
+<p>You have yet to decide whether this work is science fiction, poetry, or a science textbook, but you decide to put off that decision until the sequel — right now, the important thing is to get it into OEB format!</p>
+
+<h4 id="needmarkup">The Need for Markup</h4>
+
+<p>To publish this work, you would have to decide the format in which it should be stored. The first option would be to simply store the text of the book in a file with no formatting whatsoever. The file might be named <code>karl.txt</code>, and you could use a simple text editor such as the <code>Notepad</code> program that comes with Microsoft Windows. This method, sometimes referred to as <dfn>plain text</dfn> or <dfn>ASCII</dfn>, has several advantages, one of the most important being that your file can be read on basically any computer that has a text editor (most do).</p>
+
+<p>On the downside, your text doesn't look so great: you can't specify the font, you can't change styles, and you certainly can't embed pictures. Supporting multiple languages quickly becomes a problem, and when you realize that some text editors don't wrap lines, you'll have to go back and manually specify where each line ends.</p>
+
+<p>You may then decide to use a word processor to publish your work. This certainly works if you plan to print hard copies on a printer, but if you want to distribute your work electronically there are several issues to deal with. Instead of storing your book in plain text in a file, the word processor will add many codes to the file to specify the font, the style, the pictures, the default printer, among other things. If you were to examine your word processor file using a text editor, it might look something like this (although this particular example is completely fabricated):</p>
+
+<blockquote>@#$5098aa23150J:being @#$@$extremely@!$@...</blockquote>
+
+<p>You might see some familiar words somewhere in the file, but the rest of the "garbage" comprise codes recognizable to your word processor. The problem that arises is that each word processor uses a different format to store data. In fact, most word processors change storage formats whenever a new version is released, and sometimes have different formats for different operating systems. Furthermore, the format is <em>not</em> something that you could edit manually, without the help of the word processor itself.</p>
+
+<p>To solve problems such as these, <dfn>markup languages</dfn> were invented. Markup languages allow documents to be created in plain text format, just as we used earlier, with the addition of special symbols called <dfn>markup</dfn>. This allows files to be easily read, transported to several systems, and even edited by hand if needed, as we'll soon do here.</p>
+
+<p>An early markup language, SGML, stands for "Standard Generalized Markup Language" and was created before the World Wide Web even existed. If you've ever surfed the Web, you've definitely used (though maybe not created) HTML, a particular implementation of SGML which stands for "HyperText Markup Language." Most important to OEB is a markup language named XML, which stands for "eXtensible Markup Language." OEB uses XML to define what markup can be used in a particular document.</p>
+
+<p>As you've noticed already, OEB, like everything else in the computer industry, is rife with acronyms — don't let that confuse you. To see just how easy it is to create and OEB document, assume you want to emphasize that Karl was <em>extremely</em> small. You might then modify your story as follows:</p>
+
+<blockquote>
+Years ago, when strange creatures ruled the earth, the seas were beginning to form, and humans had yet to appear, there lived a young blovjus named Karl. Karl had three siblings: Kris, Krista, and Karla. Being <code><em></code>extremely<code></em></code> smaller than other blovji his age, Karl constantly ran into trouble at the dinner table.
+</blockquote>
+
+<p>The word "extremely" doesn't look any different — it just has <code><em></code> on one side and <code></em></code> on the other. However, when this gets displayed using an actual OEB reading system, it will look like this: <em>extremely</em>. We refer to the <code><em></code> and the <code></em></code> as the beginning and ending <dfn>tags</dfn>. In this case, "em" stands for "emphasized," and the "em" has to be in lowercase.</p>
+
+<div class="sidebar" id="markupalphabetsoup">
+<h4 class="sidebarTitle">More Information: Markup Alphabet Soup</h4>
+<p>Standard Generalized Markup Language (SGML) can be considered the parent of all the markup languages we'll be discussing here. In reality, SGML is more like a markup language construction set — it allows one to create other markup languages by defining which tags can be used, for example. The Hypertext Markup Language (HTML), used on the World Wide Web, is a specific <dfn>application</dfn> of SGML. That is, SGML was used to create a certain set of tags and other markup to be used in the web; this set of tags is what is known as HTML.</p>
+
+<p>SGML is a very broad, generic language, allowing other markup languages to be constructed with a wide range of possibilities in the way actual tags are used. While this allows a lot of flexibility in designing markup languages using SGML, it's somewhat more difficult to actually process the documents based upon markup languages created with SGML. HTML in particular is notorious for allowing so many possible tag representations that in many cases it is ambiguous as to what was intended.</p>
+
+<p>In order to make SGML easier to use, easier to process, and to increase its popularity, the eXstensible Markup Language (XML) was created. XML simply takes the rules of SGML and makes them stricter. XML is therefore a subset of SGML, and all correct XML documents will be correct SGML documents. This doesn't necessarily work the other way around, though: even though HTML is an application of SGML, many (perhaps most) HTML documents are not correct XML documents because they don't meet XML's stricter rules.</p>
+
+<p>The OEB publication structure is an application of XML in the same way HTML is an application of SGML. The OEBPS uses XML to define a set of tags to be used for storing electronic book information. OEB documents are by definition correct XML documents. Since XML is a subset of SGML, this means that all correct OEB documents are by definition correct SGML documents.</p>
+
+<p>To say that XML has become popular is certainly an understatement; indeed, it's likely that in the future you can ignore the fact that SGML even exists. What about HTML, though? It's still used on the web and, HTML being an SGML application only, most HTML documents don't meet the strict requirements of XML. To address this situation, the World Wide Web Consortium has now released the XHTML specification at <a href="http://www.w3.org/TR/xhtml1/">http://www.w3.org/TR/xhtml1/</a>. XHTML is a modified version of HTML that correctly follows the rules of XML. Since XML is the way of the future, it is recommended you use XHTML for creating new web pages.</p>
+</div>
+
+<h4 id="usingxml">Using XML</h4>
+
+<p>XML is powerful, but it's quite a simple markup language to use. Its basic rule is that markup consists of a beginning <dfn>tag</dfn> and a matching ending <dfn>tag</dfn>, and this pair of tags says something about the text which appears between them. In our example above, the beginning OEB tag <code><em></code> and the ending OEB tag <code></em></code> mean that the text between them should be emphasized, which usually means that they should be displayed in italics. In XML, an ending tag always has the same name as its beginning tag, with an extra slash (/) at the beginning. We usually refer to the <code><em></code> <code></em></code> tag pair in general as simply the "<code><em></code> tag" or more correctly, the "<code><em></code> element" which refers to both the beginning and ending tags and all text between them.</p>
+
+<ul>
+ <li><strong>XML Rule 1:</strong> Every beginning tag must be matched by an ending tag which has the same name, except that the ending tag begins with a forward slash (/).</li>
+</ul>
+
+<p>Another important OEB tag to know about is the <code><p></code> tag, which indicates a paragraph. (You know by now that the <code><p></code> tag has a beginning tag part, <code><p></code>, and ending tag part, <code></p></code>.) Your soon-to-be bestseller, to correctly use OEB, should use the <code><p></code> tag for each paragraph. Since you have only one paragraph in your story, adding the <code><p></code> tag would look like this:</p>
+
+<blockquote>
+<code><p></code>Years ago, when strange creatures ruled the earth, the seas were beginning to form, and humans had yet to appear, there lived a young blovjus named Karl. Karl had three siblings: Kris, Krista, and Karla. Being <code><em></code>extremely<code></em></code> smaller than other blovji his age, Karl constantly ran into trouble at the dinner table.<code></p></code>
+</blockquote>
+
+<p>You'll notice that the <code><em></code> tag is inside the <code><p></code> tag. That's fine. In fact, there's even a name for it: a <dfn>nested tag</dfn>. OEB has certain rules about which tags can go inside which other tags, but one thing that applies to <em>all</em> nested XML tags (OEB tags included), is that they must fit neatly inside one another and not be crossed. In other words, <code><p></code><code><em></code><code></em></code><code></p></code> is fine, but <code><p></code><code><em></code><code></p></code><code></em></code> is not.</p>
+
+<ul>
+ <li><strong>XML Rule 2:</strong> A nested tag must have both its beginning and ending tags inside the tag in which it is found; that is, two tags cannot be crossed.</li>
+</ul>
+
+<p>At this point you may be wondering, <em class="rhetoricalQuestion">If the less than (<) and greater than (>) symbols are markup characters, used to indicate tags, how do I present them in the text simply as characters, not as markup?</em> If you use one of these characters in your OEB document, it's likely to be confused as a tag, even if you're writing a mathematical expression such as <code>1 + 2 < 4</code>. For this reason, it is illegal in XML to use the less than (<) or greater than (>) character literally except as part of markup.</p>
+
+<p>To represent one of these characters, you'll need to use a <dfn>general entity</dfn>, which takes the form <code>&<em>entityName</em>;</code>, replacing <code><em>entityName</em></code> with the name of the character. To represent the less than (<) character, for example, you would use <code>&lt;</code>, and to represent the greater than (>) character you would use <code>&gt;</code>. This implies another question: <em class="rhetoricalQuestion">If the ampersand (&) character is used in general entities, how can I place an ampersand itself in the text?</em> There is a general entity for ampersand (&) as well: &amp;.</p>
+
+<p>XML defines five general entities that may be used in any XML document, including OEB documents. These are &amp; (&), &lt; (<), &gt; (>), &apos; ('), and &quot; (").</p>
+
+<ul>
+ <li><strong>XML Rule 3:</strong> A general entity takes the form <code>&<em>entityName</em>;</code> and represents one or more characters by name. XML defines five general entities that may always be used: &amp; (&), &lt; (<), &gt; (>), &apos; ('), and &quot; (").</li>
+</ul>
+
+<h4 id="creatingoebdocument">Creating an OEB Document</h4>
+
+<p>There are only two more tags you should know about before you create your first OEB document: <code><html></code> and <code><body></code>. There's nothing difficult here, it's just a requirement set forth by OEB for a standard OEB document: each document must be inside an <code><html></code> tag, and the actual text of your work must be inside a <code><body></code> tag. You'll learn why later. For now, they are easy enough to add:</p>
+
+<blockquote>
+<code><html></code><br />
+<code><body></code><br />
+<code><p></code>Years ago, when strange creatures ruled the earth, the seas were beginning to form, and humans had yet to appear, there lived a young blovjus named Karl. Karl had three siblings: Kris, Krista, and Karla. Being <code><em></code>extremely<code></em></code> smaller than other blovji his age, Karl constantly ran into trouble at the dinner table.<code></p></code><br />
+<code></body></code><br />
+<code></html></code>
+</blockquote>
+
+<p>That's it! You've created your first OEB document. Although it's not a complete <em>OEB publication</em>, it is a an <em>OEB document</em>. The way the OEB Publication Structure 1.0 was written, each OEB document is also more or less an HTML file, which means that you can use an Internet World Wide Web browser to look at the document, even though your entire OEB publication isn't yet finished. Just name the file <code>karl.html</code>, for example, and load it into your favorite Web browser application.</p>
+
+<p>OK, actually, it's an HTML document but not <em>quite</em> an OEB document. Why? Because it doesn't <em>say</em> it is. The document needs to declare that it is an OEB document, and doing so requires two more lines that are always the same in OEB documents. Again, you'll learn more about these lines later, but in short, the first one says, "I'm an XML file:"</p>
+
+<blockquote>
+<code><?xml version='1.0'?></code>
+</blockquote>
+
+<p>(Note that this line uses an single quotes (') rather than double quotes ("). As in most cases in XML, either can be used.)</p>
+
+<p>The second one says, "Specifically, I'm an OEB document file — even more specifically, a 1.0.1 OEB document file:"</p>
+
+<blockquote>
+<code><!DOCTYPE html PUBLIC "+//ISBN 0-9673008-1-9//DTD OEB 1.0.1 Document//EN" "http://openebook.org/dtds/oeb-1.0.1/oebdoc101.dtd"></code>
+</blockquote>
+
+<p>These two lines go at the top of the file, making the final OEB document look like this:</p>
+
+<blockquote>
+<code><?xml version='1.0'?></code><br />
+<code><!DOCTYPE html PUBLIC "+//ISBN 0-9673008-1-9//DTD OEB 1.0.1 Document//EN" "http://openebook.org/dtds/oeb-1.0.1/oebdoc101.dtd"></code><br />
+<code><html></code><br />
+<code><body></code><br />
+ <code><p></code>Years ago, when strange creatures ruled the earth, the seas were beginning to form, and humans had yet to appear, there lived a young blovjus named Karl. Karl had three siblings: Kris, Krista, and Karla. Being <code><em></code>extremely<code></em></code> smaller than other blovji his age, Karl constantly ran into trouble at the dinner table.<code></p></code><br />
+<code></body></code><br />
+<code></html></code>
+</blockquote>
+
+<h4 id="formattingoebtext">Formatting OEB Text</h4>
+
+<p>In this example, we've entered a <dfn>line break</dfn> at the end of each line by pressing the <code>Enter</code> or <code>Return</code> key on the computer keyboard. We've placed line breaks, for example after the <code><html></code> and <code><body></code> beginning tags. We've done this purely out of convenience: it's easier to edit the file with the beginning <code><body></code> tag directly above and in line with the ending <code><body></code> tag, for example.</p>
+
+<p>Our formatting of the document text (what programmers call the <dfn>source file</dfn>, or the text originally entered before it is displayed) does not always affect the appearance of the OEB document when it is displayed. We could have instead not entered any line breaks, making that section of the file look like this:</p>
+
+<blockquote>
+...<br />
+<code><html></code><code><body></code><code><p></code>Years ago...<code></p></code><code></body></code><code></html></code>
+</blockquote>
+
+<p>Any <dfn>whitespace</dfn> between elements, such as space, tab, and line breaks, are ignored when the document is displayed.</p>
+
+<ul>
+ <li><strong>XML Rule 4:</strong> Whitespace characters between elements are ignored; spaces, tabs, and line breaks can therefore be used arbitrarily to aid in text entry.</li>
+</ul>
+
+<p>What about whitespace that appears in displayed sections, such as inside the beginning and ending <code><p></code> tags? They obviously aren't ignored; when your document is displayed, spaces appear between words. However, multiple whitespace characters are replaced by a single space before being displayed.</p>
+
+<ul>
+ <li><strong>OEB Rule 1:</strong> (<em>Display of Whitespace</em>) If two or more whitespace characters (such as spaces, tabs, and line breaks) appear in a row, they will be <dfn>collapsed</dfn> into (that is, replaced by) a single space character before being displayed.</li>
+</ul>
+
+<p>This means that the following examples will all be displayed identically:</p>
+
+<blockquote>
+<code><p></code>Years ago, when strange creatures ruled the earth...<code></p></code>
+</blockquote>
+
+<blockquote>
+<pre><code><p></code>Years ago,<br /> when strange creatures<br />ruled the earth...<code></p></code></pre>
+</blockquote>
+
+<p>Both of these examples will collapse all spaces, tabs, and line breaks into single spaces, displaying the following:</p>
+
+<blockquote>Years ago, when strange creatures ruled the earth...</blockquote>
+
+<h3 id="oebpackage">An OEB Package</h3>
+
+<p>Half of the job is now done and you have an OEB document. The other half of an OEB publication, as you learned earlier, is an OEB package. The package is where an <dfn>OEB Reading System</dfn> (such as a software reader or a separate eBook device) will look to find out information about your book. What sort of things would a reading system need to know before displaying your book? At minimum, there are three things that a reading system <em>must</em> know:</p>
+
+<ol>
+ <li>Which book is this?</li>
+ <li>What files are in the book?</li>
+ <li>In what order should the files be displayed?</li>
+</ol>
+
+<p>Although the first item sounds reasonable, for your short masterpiece the last two items may seem ridiculous; there is, after all, only one document — and it's obvious in what order it should be displayed! As we discussed at the beginning of this chapter, though, many people will have several documents and even pictures in their masterpieces. While OEB certainly could have created an exception for one-document publications (and may even decide to do this in a future version of the specification), currently you still need to specifically supply information you may think is obvious. Besides, you may want more than one document in your sequel, so you would have had to learn this information anyway!</p>
+
+<p>The OEB package is an XML file just like the OEB document, and accordingly follows XML rules, including the ones you've learned already. Instead of using HTML tags (as the OEB document does), it will use a special set of tags made especially for an OEB package.</p>
+
+<p>The first two lines look very similar to the first two lines of an OEB document. The first one says, "I'm an XML file, too:"</p>
+
+<blockquote>
+<code><?xml version='1.0'?></code>
+</blockquote>
+
+<p>The second one says, "I'm not an OEB document, though; I'm an OEB <em>package</em>:"</p>
+
+<blockquote>
+<code><!DOCTYPE package PUBLIC "+//ISBN 0-9673008-1-9//DTD OEB 1.0.1 Package//EN" "http://openebook.org/dtds/oeb-1.0.1/oebpkg101.dtd"></code>
+</blockquote>
+
+<p>Like all XML files, there is a beginning and ending tag which together contain the main part of the file. In the OEB document, it was the <code><html></code> tag. In contrast, the OEB package uses the <code><package></code> tag (for obvious reasons), making the "outside" portion of the package look like this:</p>
+
+<blockquote>
+<code><?xml version='1.0'?></code><br />
+<code><!DOCTYPE package PUBLIC "+//ISBN 0-9673008-1-9//DTD OEB 1.0.1 Package//EN" "http://openebook.org/dtds/oeb-1.0.1/oebpkg101.dtd"></code><br />
+<code><package></code><br />
+ <em>Actual package goes here...</em><br />
+<code></package></code>
+</blockquote>
+
+<p>Inside the package are several required sections; each one answers one of the questions raised above. Each section has its corresponding tag which reflects the function of that section: <code><metadata></code>, <code><manifest></code>, and <code><spine></code>:</p>
+
+<blockquote>
+<code><?xml version='1.0'?></code><br />
+<code><!DOCTYPE package PUBLIC "+//ISBN 0-9673008-1-9//DTD OEB 1.0.1 Package//EN" "http://openebook.org/dtds/oeb-1.0.1/oebpkg101.dtd"></code><br />
+<code><package></code>
+ <blockquote>
+ <code><metadata></code><br />
+ <em>Which book is this?</em><br />
+ <code></metadata></code>
+ </blockquote>
+ <blockquote>
+ <code><manifest></code><br />
+ <em>What files are in the book?</em><br />
+ <code></manifest></code>
+ </blockquote>
+ <blockquote>
+ <code><spine></code><br />
+ <em>In what order should the files be displayed?</em><br />
+ <code></spine></code>
+ </blockquote>
+<code></package></code>
+</blockquote>
+
+<p>As we examine the structure of the OEB package, we'll display the text using spaces and tabs so as to make the sections easier to read. When you create your document, you can enter the package in any way you like, using spaces, tabs, or new lines. In fact, XML (and OEB) doesn't even care if everything is entered on one line — it's just harder for you to read that way, so we've decided not to do that here.</p>
+
+<h4 id="packageelement">The <code><package></code> Element</h4>
+
+<p>The surrounding <code><package></code> element, made up of the <code><package></code> and <code></package></code> tags, is pretty straightforward except that it specifies a unique identifier which will be used later for identifying the document. The exact unique identifier you used is up to you. In this case, it might be appropriate to use the identifier, "karlpackage", like this:</p>
+
+<blockquote>
+<code><package unique-identifier="karlpackage"></code>
+</blockquote>
+
+<p>You'll notice that we specify the identifier inside the tag itself! In XML terms, <code>unique-identifier</code> is referred to an <dfn>attribute</dfn> of the tag.</p>
+
+<ul>
+ <li><strong>XML Rule 5:</strong> An element's beginning tag may have one or more attributes in the form <code>attributeName="value"</code> or <code>attributeName='value'</code>.</li>
+</ul>
+
+<p>The value can be surrounded by single or double quotes, as long as you are consistent on both sides of the value.</p>
+
+<h4 id="packagemetadata">The Package Metadata</h4>
+
+<p>The first section inside the <code><package></code> element contains metadata. In answering the question, "Which document is this?" the <code><metadata></code> element contains several elements, each of which specify something about the book, such as its title and author(s). These items are called <dfn>metadata</dfn> items, hence the name of the element.</p>
+
+<p>In an added twist, the elements in the metadata section are inside another element named <code><dc-metadata></code>. The OEB Authoring Group did not create these metadata identifiers from scratch; instead, they used a set of metadata identifiers already defined by a group named the <a href="http://purl.org/dc/">Dublin Core</a>. Since the OEB publication structure allows you to create your own metadata items, the Authoring Group decided to group together the special metadata items from the Dublin core inside its own <code><dc-metadata></code> element. Moreover, the <code><dc-metadata></code> element takes certain attributes that specify that these metadata are Dublin Code metadata. Your book's metadata section, therefore, might turn out to look something like this:</p>
+
+<blockquote>
+<code><metadata></code>
+ <blockquote>
+ <code><dc-metadata xmlns:dc="http://purl.org/dc/elements/1.0/" xmlns:oebpackage="http://openebook.org/namespaces/oeb-package/1.0/"></code>
+ <blockquote>
+ <code><dc:Title></code>Karl the Kreature<code></dc:Title></code><br />
+ <code><dc:Identifier id="karlpackage" scheme="ISBN"></code>123456789X<code></dc:Identifier></code><br />
+ <code><dc:Creator role="aut"></code>Jane Doe<code></dc:Creator></code>
+ </blockquote>
+ <code></dc-metadata></code>
+ </blockquote>
+<code></metadata></code>
+</blockquote>
+
+<p>The parts from the above example that will change for each book are the metadata elements: the required elements <code><dc:Title></code> and <code><dc:Identifier></code>, and the optional (but important to you!) element <code><dc:Creator></code>. The metadata elements in this section all begin with "dc:", another requirement that simply specifies that these are Dublin Core metadata.</p>
+
+<p>The <code><dc:Title></code> element is simple enough: it holds the title of the book. Similarly, the <code><dc:Identifier></code> element holds an identifier that hopefully uniquely identifies the book in the world, even if two books by two separate authors have identical titles. Since there are several methods of identifying books uniquely, the <code>scheme</code> attribute is necessary to specify the identifier used. In this case, we're using an ISBN for the identifier, so we set <code>scheme="ISBN"</code>.</p>
+
+<p>As there are several methods of uniquely identifying a single book, the OEB Authoring Group allowed for several methods to be used together in the same package. However, one identifier must be chosen as the main identifer; this identifier's element must have an <code>id</code> attribute set to the unique ID we specified earlier in the beginning <code><package></code> tag. Here we only have one identifier, and we've appropriately set the <code>id</code> attribute to <code>id="karlpackage"</code>.</p>
+
+<p>You can identify yourself as the creator of the work using the <code><dc:Creator></code> element. The <code>role</code> attribute, is optional, specifying what role you played during the creation of the book. Common values are <code>"aut"</code> (representing "author"), <code>"edt"</code> ("editor"), and <code>"trl"</code> ("translator"). Probably the role used the most, and the one recommended here that should always be included, is <code>"aut"</code>. As with <code><dc:Identifier></code>, you can include several <code><dc:Creator></code> elements to identify several creators of your work.</p>
+
+<h4 id="packagemanifest">The Package Manifest</h4>
+
+<p>The next section of the package is referred to as the <dfn>manifest</dfn>, holding information about which files should be included with the book. The Open eBook specification was designed to be distributed and read on a variety of systems and platforms; the manifest guarantees that each system can have a complete list of the minimum files that will be needed to display the contents of the book.</p>
+
+<p>Each item in the manifest specifies three things:</p>
+
+<ul>
+ <li>A unique identifier for the item, so that other parts of the book can unambiguously refer to it.</li>
+ <li>The name of the file in which the actual item is stored.</li>
+ <li>The type of the item (such as a document or a picture).</li>
+</ul>
+
+<p>The manifest of our example, then, will be quite simple:</p>
+
+<blockquote>
+<code><manifest></code>
+ <blockquote>
+ <code><item id="karl" href="karl.html" media-type="text/x-oeb1-document"></code>
+ </blockquote>
+<code></manifest></code>
+</blockquote>
+
+<p>Each item in the book will be represented by an <code><item></code> element. Here, there is only one item in the book, the OEB document we created earlier. You can choose any unique ID you like; here we'll use <code>id="karl"</code>. For the <code>href</code> attribute (so-named from the hypertext references used in HTML), specify the filename you gave the OEB document. There are a standard set of <code>media-type</code> attribute values you can use, such as <code>"image/jpeg"</code> and <code>"image/png"</code> for certain types of images. In this case, the item is an OEB document, so we must state as much by setting <code>media-type="text/x-oeb1-document"</code>.</p>
+
+<h4 id="packagespine">The Package Spine</h4>
+
+<p>Now that we've given information about the book and specified which items are in the book, the last required step is to specify the order in which the book should be read, and this is done inside the <code><spine></code> element. Although electronic books bring all sorts of possibilities as far as interaction and reader-influenced reading orders, there must still be one default reading order specified, or what the OEB specification refers to as the <dfn>primary linear reading order</dfn>. (Writers of adventure stories that have no predetermined reading order are in luck; how to format such interactive stories will be explained in a later version of this work.)</p>
+
+<p>The <dfn>spine</dfn> is even simpler than the manifest, because the information about each item has already been specified in the manifest. Therefore, the spine only needs to identify which items from the manifest appear in what order. This implies that only items defined in the manifest can appear in the spine. Furthermore, only OEB documents (that is, items included in the manifest that are of type "text/x-oeb1-document") can appear in the spine. Specifically, only those OEB documents that should be displayed as part of the normal linear reading order of the book should be included in the spine.</p>
+
+<p>The spine of our book is certainly straightforward. Its one item reference (the <code><itemref></code> element) identifies the one item in the manifest by referencing the unique ID we assigned it: <code>idref="karl"</code>.</p>
+
+<blockquote>
+<code><spine></code>
+ <blockquote>
+ <code><itemref idref="karl"></code>
+ </blockquote>
+<code></spine></code>
+</blockquote>
+
+<p>With that, we've answered all three questions a reading system requires, and are thus finished with the OEB package. The complete listings of both the finished document and package appear at the end of this chapter.</p>
+
+<h3 id="xmlrepresentdata">Using XML to Represent Data</h3>
+
+<p>You've probably noticed at least two different ways in which we've used XML tag pairs, or elements. The first was to specify formatting: the <code><em></code> element made a section of text appear in italics. The second was to represent data, or information about the work: we used the <code><dc:Creator></code> element to specify the author of the book, without specifying how (or if) the author's name would actually be displayed. The latter is simply for storing information about the book.</p>
+
+<p>A closer examination reveals that the uses of both of these elements, <code><em></code> and <code><dc:Creator></code>, are actually virtually identical. As it turns out, the <code><em></code> element does not specify that italics should be used; it rather specifies that the text should be emphasized without specifying exactly <em>how</em> the text should be emphasized. Although the default display method for text inside an <code><em></code> element is to use italics, it's certainly conceivable that you could decide later to display emphasis using the color red, so that your book displays, "Being <span style="color: red;">extremely</span> smaller..." instead of "Being <span style="font-style: italic;">extremely</span> smaller..."</p>
+
+<p>If you consistently use <code><em></code> to represent emphasis, it's relatively simple using XML (and, by definition, OEB) to change how emphasized text appears — without changing the actual text of your book! This is an important concept in creating documents, and it's often referred to as a <dfn>separation of content and presentation</dfn>. As you'll learn soon, the way a document appears should be kept distinct (in a completely separate file, in fact) from the actual content of your book.</p>
+
+<ul>
+ <li><strong>OEB Tip 1:</strong> (<em>Separation of Content and Presentation</em>) Do not use an element to specify how text should appear, but rather use elements to specify the content or meaning of sections of your work.</li>
+</ul>
+
+<p>To provide an example of how useful it is to encode <em>meaning</em> into a document rather than trying to specify how a document should be displayed, consider the following extract:</p>
+
+<blockquote>
+<p>In the Urdu language, there is a class of descriptive words called <span style="font-style: italic;">postpositions</span>. These are similar to English prepositions except that they come <span style="font-style: italic;">after</span> the words they modify; hence the name "post"+"position".</p>
+</blockquote>
+
+<p>Since we want "postposition" to be displayed (or <dfn>rendered</dfn>) in italics, it would be tempting at first to use the <code><em></code> tag like this: <code><em></code>postposition<code></em></code>. However, if you take a moment to think about why we want the word "postposition" displayed differently, you'll realize that we really don't want to emphasize the word but want rather to indicate that we are defining the word for the first time.</p>
+
+<p>There so happens to be an OEB tag that does just that — the <code><dfn></code> tag specifies that a new word is being defined or used for the first time. Text which uses the <code><dfn></code> tag is also usually displayed in italics as well, so you might wonder why it matters which tag is used. The concept of separation of content and presentation answers this question. What if we make a reading system that automatically generates a glossary in the back of the book, listing all the new terms introduced and where they were first defined? If we have used the <code><dfn></code> tag in the correct places, these terms could be found easily and placed in the glossary automatically.</p>
+
+<p>It's important to note that, in the section above, we would not want to use the <code><dfn></code> tag for the second italicized word, "after." Instead, we would want to use the <code><em></code> tag; we are not wanting to define the word "after," but merely emphasize the position of a "postposition". Keeping in mind our concept of separation of content and presentation, we'd probably enter the above section like this:</p>
+
+<blockquote>
+<p><p>In the Urdu language, there is a class of descriptive words called <dfn>postpositions</dfn>. These are similar to English prepositions except that they come <em>after</em> the words they modify; hence the name "post"+"position".</p></p>
+</blockquote>
+
+<p>As you will see later, there are several methods of displaying italics in OEB. A popular method in the past was the <code><i></code> tag, which actually means "italics". This is now considered bad practice, considering the need to separate content from presentation. Unfortunately, since OEB uses many tags from HTML, the <code><i></code> tag is available to use in OEB documents. For reasons we've just explained, we strongly recommend against using the <code><i></code> tag in your documents, and using the <code><em></code> instead in most cases.</p>
+
+<p>The concept of separation of content and presentation is a very important one, and we'll revisit this topic.</p>
+
+<p>You now know the basic structure of an OEB publication. There are several tags which we haven't covered yet which you'll want to use when you create real-world documents. After discussing <a href="chapter3.html">styles and style sheets</a>, we'll cover the <a href="chapter4.html">tags you'll normally need</a> when working in the real world.</p>
+
+<h3 id="review">Review</h3>
+
+<h4 id="summary">Summary</h4>
+<ul>
+ <li>An OEB Publication consists of an OEB Package, one or more OEB Documents, and other related files such as images.</li>
+ <li>The OEB Publication Structure is a markup language which follows the rules of XML; therefore, all OEB files are XML files.</li>
+ <li>OEB in its basic form specifies a set of tags which should be used, always following the rules of XML. OEB also contains the flexibility to use custom tags.</li>
+ <li>The set of basic tags specified by OEB is very similar to, for better or for worse, the set of tags specified by HTML.</li>
+</ul>
+
+<h4 id="xmlrules">XML Rules</h4>
+<ul>
+ <li><strong>XML Rule 1:</strong> Every beginning tag must be matched by an ending tag which has the same name, except that it begins with a forward slash (/). (Special <a href="chapter4.html#emptyElement">empty tags</a> will be discussed later.)</li>
+ <li><strong>XML Rule 2:</strong> A nested tag must have both its beginning and ending tags inside the tag in which it is found; that is, two tags cannot be crossed.</li>
+ <li><strong>XML Rule 3:</strong> A general entity takes the form <code>&<em>entityName</em>;</code> and represents one or more characters by name. XML defines five general entities that may always be used: &amp; (&), &lt; (<), &gt; (>), &apos; ('), and &quot; (").</li>
+ <li><strong>XML Rule 4:</strong> Whitespace characters between elements are ignored; spaces, tabs, and line breaks can therefore be used arbitrarily to aid in text entry.</li>
+ <li><strong>XML Rule 5:</strong> An element's beginning tag may have one or more attributes in the form <code>attributeName="value"</code> or <code>attributeName='value'</code>.</li>
+</ul>
+
+<h4 id="oebrules">OEB Rules</h4>
+<ul>
+ <li><strong>OEB Rule 1:</strong> (<em>Display of Whitespace</em>) If two or more whitespace characters (such as spaces, tabs, and line breaks) appear in a row, they will be <dfn>collapsed</dfn> into (that is, replaced by) a single space character before being displayed.</li>
+ <li><strong>OEB Tip 1:</strong> (<em>Separation of Content and Presentation</em>) Do not use an element to specify how text should appear, but rather use elements to specify the content or meaning of sections of your work.</li>
+</ul>
+
+<h4 id="oebtags">OEB Tags</h4>
+<ul>
+ <li><code><dfn></code> Specifies that a term is being used for the first time; usually rendered in italics.</li>
+ <li><code><em></code> Emphasizes text; usually rendered in italics.</li>
+</ul>
+
+<h3 id="exampleoebdocument">Completed Example OEB Document (<code>karl.html</code>)</h3>
+
+<blockquote>
+<code><?xml version='1.0'?></code><br />
+<code><!DOCTYPE html PUBLIC "+//ISBN 0-9673008-1-9//DTD OEB 1.0.1 Document//EN" "http://openebook.org/dtds/oeb-1.0.1/oebdoc101.dtd"></code><br />
+<code><html></code><br />
+<code><body></code><br />
+ <code><p></code>Years ago, when strange creatures ruled the earth, the seas were beginning to form, and humans had yet to appear, there lived a young blovjus named Karl. Karl had three siblings: Kris, Krista, and Karla. Being <code><em></code>extremely<code></em></code> smaller than other blovji his age, Karl constantly ran into trouble at the dinner table.<code></p></code><br />
+<code></body></code><br />
+<code></html></code>
+</blockquote>
+
+<h3 id="exampleoebpackage">Completed Example OEB Package (<code>karl.opf</code>)</h3>
+
+<blockquote>
+<code><?xml version='1.0'?></code><br />
+<code><!DOCTYPE package PUBLIC "+//ISBN 0-9673008-1-9//DTD OEB 1.0.1 Package//EN" "http://openebook.org/dtds/oeb-1.0.1/oebpkg101.dtd"></code><br />
+<code><package unique-identifier="karlpackage"></code>
+
+ <blockquote>
+ <code><metadata></code>
+ <blockquote>
+ <code><dc-metadata xmlns:dc="http://purl.org/dc/elements/1.0/" xmlns:oebpackage="http://openebook.org/namespaces/oeb-package/1.0/"></code>
+ <blockquote>
+ <code><dc:Title></code>Karl the Kreature<code></dc:Title></code><br />
+ <code><dc:Identifier id="karlpackage" scheme="ISBN"></code>123456789X<code></dc:Identifier></code><br />
+ <code><dc:Creator role="aut"></code>Jane Doe<code></dc:Creator></code>
+ </blockquote>
+ <code></dc-metadata></code>
+ </blockquote>
+ <code></metadata></code>
+ </blockquote>
+ <blockquote>
+ <code><manifest></code>
+ <blockquote>
+ <code><item id="karl" href="karl.html" media-type="text/x-oeb1-document"></code>
+ </blockquote>
+ <code></manifest></code>
+ </blockquote>
+ <blockquote>
+ <code><spine></code>
+ <blockquote>
+ <code><itemref idref="karl"></code>
+ </blockquote>
+ <code></spine></code>
+ </blockquote>
+<code></package></code>
+</blockquote>
+
+</body>
+</html>
--- /dev/null
+++ b/lib/ebooks/understandingoeb/chapter3.html
@@ -1,0 +1,230 @@
+<?xml version='1.0'?>
+<!DOCTYPE html PUBLIC "+//ISBN 0-9673008-1-9//DTD OEB 1.0.1 Document//EN" "http://openebook.org/dtds/oeb-1.0.1/oebdoc101.dtd">
+<?xml-stylesheet href="understandingoeb.css" type="text/x-oeb1-css"?>
+
+<html>
+<head>
+ <link rel="stylesheet" type="text/x-oeb1-css" href="understandingoeb.css" />
+<title>Understanding OEB Chapter 3</title>
+ <meta name="author" content="Garret Wilson" />
+ <meta name="copyright" content="Copyright (c) 2000-2001 Garret Wilson. All rights reserved." />
+</head>
+
+<body>
+
+<h2 id="chapter3">3. Styles and Style Sheets</h2>
+
+<p>One of the most integral parts of OEB is the concept of <dfn>style sheets</dfn>. A style sheet is a tool that helps to separate content from presentation and is used not only with OEB but with XML and (increasingly) with HTML web pages as well. You've been told that the separation of content and presentation is a "Good Thing" — after you understand style sheets, you'll begin to see why this concept is so important.</p>
+
+<p>Style sheets have a few unusual properties: you could write OEB-compliant eBooks all your life and never use a stylesheet. Stranger still, someone might create a style sheet that could be used with your work long after you've written it. That's what makes stylesheets so useful: they represent the <dfn>encapsulation</dfn> (or bundling) of the presentation part of the <em>publication=content+presentation</em> equation, and therefore help keep the two completely separate. Your OEB document, with its text and tags, is the content and holds the meaning of what you're written; the style sheet(s) hold how your work is presented to the user.</p>
+
+<p>How is this supposed to work? Imagine that you're writing a book to be published by the Happy Publishing Company. Happy has its own ideas about how your book should look — that is, which fonts it should have, how it should be spaced, etc. (Happy Publishing Company might have ideas about what your book should <em>say</em> as well, but that's another story; it should be clear to you by now that these are two separate concepts.) If you write a book and concentrate on the content, Happy Publishing Company can simply use its style sheet with your work after you're finished, and the book will look just like Happy wants it to. What happens when you change publishers? Your new publisher can simply substitute their standard style sheet and your book will suddenly take on its new look, without your having to make one single change to the actual content of the book — <em>if</em> you've correctly separated the content from the presentation.</p>
+
+<p>That's a big "if", and one that takes a little thinking on your part, at least to begin with. Since OEB comes from a legacy of HTML which didn't stress as strongly such a separation of content and presentation, OEB in some cases makes it easier for you to put style information where it doesn't belong: mixed in with the content of your work. It is hoped that you'll be able not only to overcome these temptations, but to understand why the current emphasis of information storage and retrieval formats is going in a direction that stresses that these elements be separated.</p>
+
+<p>Before going any further into the theory of style sheets, we'll examine a few examples of using styles, from the least desired to the most appropriate.</p>
+
+<h3 id="emphasisrevisited">Emphasis Revisited</h3>
+
+<p>The previous chapter hinted that OEB has a tag named <code><i></code> which causes the specified text to be rendered (or displayed) in italics. We've told you that this is not recommended.</p>
+
+<ul>
+ <li><strong>Not Recommended:</strong> <code><p></code>Being <code><i></code>extremely<code></i></code> smaller than other blovji his age...<code></p></code></li>
+</ul>
+
+<blockquote>Being <span style="font-style: italic;">extremely</span> smaller than other blovji his age...</blockquote>
+
+<p>What's the alternative? We've stressed that in many places, the <code><em></code> tag, specifying "emphasis", can be used in place of the <code><i></code> tag for the same effect. We've answered the question, "If they both have the same effect, what's the difference?" by saying that <code><em></code> specifies simply that a section of text should be emphasized, not <em>how</em> the text should be emphasized.</p>
+
+<ul>
+ <li><strong>Recommended:</strong> <code><p></code>Being <code><em></code>extremely<code></em></code> smaller than other blovji his age...<code></p></code></li>
+</ul>
+
+<blockquote>Being <span style="font-style: italic;">extremely</span> smaller than other blovji his age...</blockquote>
+
+<p>The point is that, although <code><em></code> is usually rendered in italics by default, there's nothing that prevents you from changing how <code><em></code> gets displayed — nothing except a lack of knowledge, of course. We'll now address how that's done.</p>
+
+<p>OEB has specified that every element has an optional <code>style</code> attribute. As you might guess, you can use this attribute to override the style of that element. We'll explain later the specifics of the style information, but here's a quick example of how you could guarantee that <code><em></code> is displayed in italics:</p>
+
+<ul>
+ <li><strong>Not Recommended:</strong> <code><p></code>Being <code><em style="font-style: italic"></code>extremely<code></em></code> smaller than other blovji his age...<code></p></code></li>
+</ul>
+
+<blockquote>Being <span style="font-style: italic;">extremely</span> smaller than other blovji his age...</blockquote>
+
+<p>If you wanted the emphasized text to not only be displayed in italics but also in red, you'd use the following:</p>
+
+<ul>
+ <li><strong>Not Recommended:</strong> <code><p></code>Being <code><em style="color: red"></code>extremely<code></em></code> smaller than other blovji his age...<code></p></code></li>
+</ul>
+
+<blockquote>Being <span style="font-style: italic; color: red">extremely</span> smaller than other blovji his age...</blockquote>
+
+<p>Notice that the text is still displayed in italics, because we didn't specify that the italics should be removed (there's a way to do this, which you'll see later). Instead, we specified that the color red should be added to whatever style was there already.</p>
+
+<p>As you can see, we don't recommend this method, and it's not hard to figure out why. If you specify the style of the tag directly, you've gained nothing over just using the <code><i></code> tag and manually making changes. After all, this method still mixes our presentation information inside the content of our book.</p>
+
+<p>Let's continue with the assumption that we'd like all emphasized text to be displayed using not only italics, but also the color red. We'll also assume you've followed the recommendations here and used the <code><em></code> tag for emphasized text. The secret to style sheets is that they use the same format you just saw used inside the <code>style</code> attribute, only that they've been removed from the content and placed in a separate location. This is the first way we could do it:</p>
+
+<ul>
+ <li><strong>Recommended:</strong></li>
+</ul>
+
+<blockquote>
+<code><?xml version='1.0'?></code><br />
+<code><!DOCTYPE html PUBLIC "+//ISBN 0-9673008-1-9//DTD OEB 1.0.1 Document//EN" "http://openebook.org/dtds/oeb-1.0.1/oebdoc101.dtd"></code><br />
+<code><html></code><br />
+<code><head></code><br />
+ <code><title></code>Karl the Creature<code></title></code><br />
+ <code><style></code>em {color: red}<code></style></code><br />
+<code></head></code><br />
+<code><body></code><br />
+ <code><p></code>...Being <code><em></code>extremely<code></em></code> smaller than other blovji his age...<code></p></code><br />
+<code></body></code><br />
+<code></html></code>
+</blockquote>
+
+<blockquote>Being <span style="font-style: italic; color: red">extremely</span> smaller than other blovji his age...</blockquote>
+
+<p>This example correctly specifies that <em>all</em> occurrences of the <code><em></code> element should be displayed in red. Furthermore, the actual body of the document does not need to be changed; all text marked as emphasized will be shown with the new style.</p>
+
+<p>In the previous chapter we touched on the essential components of an OEB document. In the above example you'll notice several elements we didn't discuss. OEB specifies that the <code><head></code> element is optional in a document, but if included it should contain a <code><title></code> element. The element we're interested in, <code><style></code> must be inside the <code><head></code> element. This means that whenever we include a <code><style></code> element, we'll have to include both a <code><head></code> and a <code><title></code> element as well. Both of these elements will be discussed in depth later. For now, note simply that we are specifying style information outside the actual body of the document, in a separate element named <code><style></code>.</p>
+
+<p>You might wonder at this point, if we were to take our concept of separation of content and presentation to the extreme, why we place any style information at all in the same file as the document. Wouldn't it be better to store presentation information in a completely separate location? Yes, in many circumstances it would. We'll explain how a little later; for now, to make things simple, we'll keep the style information in the same file as the document.</p>
+
+<h3 id="cascadingstylesheets">Cascading Style Sheets (CSS)</h3>
+
+<p>You've seen how OEB has used XML to create a set of tags and rules to use those tags, in many instances borrowing tags from HTML. Similarly, there is a set of rules for specifying style information in an OEB document. Here, OEB borrowed the format of a specification for <dfn>Cascading Style Sheets</dfn> (CSS). Although there are a few differences between OEB's version of CSS and standard CSS, these differences are very minor; in most instances, OEB simply specifies which CSS constructs cannot be used. There's only one instance where OEB actually creates new identifiers. For the most part, then, if you're familiar with CSS at all you can apply your knowledge to OEB.</p>
+
+<p>XML, on which OEB is based, uses a set of elements, each of which have a beginning and ending tag. CSS, on the other hand, uses different constructs. In general, CSS styles consist of <dfn>selectors</dfn> and <dfn>declarations</dfn>, the latter of which contains one or more sets of a <dfn>property</dfn> and a <dfn>value</dfn>. Although this sounds complicated, it's quite simple in practice; once you understand these basic parts, there isn't much more to learn for most things you'll want to do.</p>
+
+<div class="sidebar" id="cssvsxsl">
+<h4 class="sidebarTitle">More Information: CSS vs. XSL</h4>
+
+<p>OEB uses XML to store content, but uses a separate language named CSS to store style (presentation) information. Why must one use two separate formats? Why doesn't OEB simply use XML for storing both content and presentation information, even if these things are stored separately?</p>
+
+<p>That's a legitimate and important question. It so happens that there is a method for specifying style and formatting information using XML — it's called <dfn>XML Style Language</dfn> (XSL). Since it uses XML, XSL doesn't force one to learn another format just to create style information, and XSL is even more powerful than CSS</p>
+
+<p>Why doesn't OEB use XSL instead of CSS, then? There are several reasons. When the OEB Publication Structure 1.0 specification was being written, there were not any tools available specifically for viewing OEB documents. Since an OEB document is very similar to a normal HTML document, it was possible however to view OEB documents using a web browser. The OEB Authoring Group chose to use CSS, which most browsers at the time supported, rather than to use XSL, which most browsers couldn't handle.</p>
+
+<p>More importantly, the XSL specification was not yet finalized at the time the OEB specification was being written, so any use of XSL would have had to predict the final form in which XSL would appear. OEB therefore relies primarily on CSS, although future version of OEB may well rely on XSL. It's even possible to use XSL stylesheets with OEBPS 1.0, as long as an appropriate CSS stylesheet is included for those reading systems that do not understand XSL.</p>
+
+</div>
+
+<p>The particular style we specified for <code><em></code> looks like this:</p>
+
+<blockquote><code>em {color: red}</code></blockquote>
+
+<p>This style represents how most styles you specify will appear. Each will have the same parts introduced earlier:</p>
+
+<ul>
+ <li><strong>selector</strong> - <code>em</code> - Specifies which elements will be "selected" to receive this style. In this case, we indicate that this style applies to every <code><em></code> element.</li>
+ <li><strong>declaration</strong> - <code>{color: red}</code> - Specifies the style of the selected element(s). In this case, we've specified that the color of the text should be red. As noted earlier, the declaration is divided up into one or more properties and corresponding values.</li>
+ <li><strong>property</strong> - <code>color</code> - Specifies a particular property to be modified. Here the color of the text is being modified. Each declaration could modify several properties — both the color and the size of the text could be changed, for example.</li>
+ <li><strong>value</strong> - <code>red</code> - The new value of the property. Each property will have at least one value, although more than one value can be specified in some instances in which the first value might not be available.</li>
+</ul>
+
+<p>There are, of course, a few more intricacies which we'll go into later, especially concerning the selector part of the equation. There are probably a couple of questions about exactly what's happening here that should probably be cleared up first.</p>
+
+<p><em class="rhetoricalQuestion">Why does my emphasized text show up both in red <em>and</em> italics, even though I specified just the color red?</em> If you specify no styles at all, there is a default style which will be applied to text between OEB tags. In OEB, the <code><em></code> tag is usually rendered in italics by default. In fact, the effect is exactly as if you had specified the following style in your document:</p>
+
+<blockquote><code>em {font-style: italic}</code></blockquote>
+
+<p>In other words, there's effectively a default style sheet used which specifies the standard style of OEB elements. In our example, specifying that the color red should be used did not state that the default style of italics should not be used. The color red was therefore added to the existing default style of italics, giving all text between <code><em></code> tags both the italic style and the color red.</p>
+
+<p><em class="rhetoricalQuestion">If styles can be specified in multiple places, such as on the actual tag and elsewhere in the document, what happens when I declare the same style in multiple places?</em> This question relates to the previous one. If you specify in the document's <code><style></code> tag, for example, the style <code>em {color: red}</code>, then every occurrence of the <code><em></code> tag will be rendered in red. If you specify, using the <code>style</code> attribute, that a particular <code><em></code> tag should have be underlined using <code><em style="text-decoration: underline"></code>, then that particular portion of text will be underlined. But it will also be shown in red, because you've already specified that <em>all</em> occurrences of the <code><em></code> tag should be in red.</p>
+
+<p>Each particular instance of the <code><em></code> tag, therefore, <dfn>inherits</dfn> the properties already defined for it. Since you specified a property for <em>all</em> <code><em></code> tags, this property <dfn>cascades</dfn> down to each of the individual <code><em></code> tags similar to the way water from a waterfall cascades down to each level of rocks before it reaches the pool below. In fact, that's why CSS uses the name "Cascading Style Sheets."</p>
+
+<p><em class="rhetoricalQuestion">What happens if the properties I specify in several places conflict with each other?</em> As a rule of thumb, the most specific declaration is used. If you've specified, for example, that all <code><em></code> elements should be red, but then in a particular instance specified that a particular <code><em></code> element should instead be blue, the blue wins.</p>
+
+<h4 id="cssselectors">CSS Selectors</h4>
+
+<p>A selector determines (or selects) the element(s) to which a particular style declaration applies. In our example above, <code>em {color: red}</code>, the selector is simple: this style will be applied to every <code><em></code> element. There are several other additions to the selector syntax that make it easy to select exactly which element(s) you prefer.</p>
+
+<p><strong>Select Multiple Elements:</strong> You could always duplicate a style declaration for several elements with different names, but CSS has an easier way to select several elements for the same style. Just place several element names in a row, separated by commas (,). For example, <code>em, dfn {color: red}</code> would make all emphasized text (<code><em></code>) <em>and</em> all defined words (<code><dfn></code>) appear in red.</p>
+
+<p><strong>Select Elements Only in Certain Contexts:</strong> So far, we've only seen the <code><em></code> element appear inside a paragraph (<code><p></code>). As we'll see later, emphasized text could appear in several places, such as inside a list or a heading. To specify that <em>only</em> emphasized text inside a paragraph should be red, you would list the nested elements in the correct order, separated by whitespace.: <code>p em {color: red}</code>. This would mean that emphasized text inside a paragraph (e.g. <code><p><em></em></p></code>) would appear in red, but not emphasized text inside a list (e.g. <code><li><em></em></li></code>). Again, we'll discuss lists later; for now, simply realize that an element can appear in different contexts, and CSS provides a way to specify these situations.</p>
+
+<p><strong>Select Elements by Class</strong> CSS allows a style to be created and given a name, and then later used with any element you decide. After specifying a name (or <dfn>class</dfn>) for a style, you can use the style with a particular element simply by specifying the style name in the <code>class</code> attribute of an element. The <code>class</code> attribute, like the <code>style</code> attribute, is an optional attribute that can be used with many elements.</p>
+
+<p>For example, instead of explicitly specifying that every <code><em></code> element should appear in red, we could create a class that would allow you to specify to which <code><em></code> element the style applied. A style class is always preceded by a period or full stop character (.), like this: <code>em.colorful {color: red}</code>. We could then specify that a particular emphasized portion of text would use this style:"this is <code><em class="colorful"></code>emphasized<code></em></code> text".</p>
+
+<p>A style class can be made even more generic by omitting an element designation altogether. A modification of the previous example yields <code>.colorful {color: red}</code> (don't forget the '.' character), a style class which can apply to <em>any</em> element. This change still allows the <code><em></code> tag be made colorful as in the previous example: <code><em class="colorful"></code>emphasized<code></em></code>. Furthermore, the class can be applied to other elements, such as the <code><p></code> tag: <code><p class="colorful"></code>emphasized<code></em></code> would assure that all the text in the specified paragraph appeared in the color red. Note, however, that the text would not appear in italics, since the <code><p></code> tag does not have an italic style by default, as does the <code><em></code> tag.</p>
+
+<h3 id="linkingstylesheets">Linking to Style Sheets</h3>
+
+<p>As we've seen, there are several places where we can store style information, from the most specific to the most general:</p>
+
+<ol>
+ <li>By putting style information in an element's <code>style</code> attribute.</li>
+ <li>By specifying a style class in an element's <code>class</code> attribute.</li>
+ <li>By defining styles in a <code><style></code> element inside the document <code><head></code>.</li>
+ <li>By defining styles in separate style sheet file linked to the document.</li>
+</ol>
+
+<p>The last method, linking to an external style sheet, has only been touched upon briefly. Using this method is straightforward: simply take the style information from inside the <code><style></code> element and place it inside a separate file (preferably with a ".css" extension). The entire <code><style></code> element can then be removed, and the document can simply specify that it uses the external stylesheet.</p>
+
+<p>By placing style information in a separate file, we've arrived at our ultimate goal of separating content from presentation. If there are multiple documents in a given book, the style information does not have be be duplicated inside each document; each document can rather <dfn>link</dfn> to one style sheet, which contains all relevant presentation information. Furthermore, a book's style can be changed simply by making the document link to another style sheet. To carry on the example at the beginning of this chapter, if Happy Publishing Company decides it wants to redesign the appearance of its entire selection of books, none of the books' contents need to be changed. Instead, Happy can simply supply an updated style sheet.</p>
+
+<h4 id="linkelement">Linking Style Sheets with the <code><link></code> Element</h4>
+
+<p>There are several ways to actually link a style sheet to a document, reflecting the evolution of HTML and markup languages in general. When HTML first allowed style sheets, it specified a <code><link></code> element that appears inside the <code><head></code> element in place of <code><style></code>. After moving our style information out of our sample document, our style link information might look like this:</p>
+
+<blockquote><code><link href="karl.css" type="text/x-oeb1-css"></code></blockquote>
+
+<p>As before, the <code>href</code> attribute specifies the style sheet to which the document is linking. The <code>type</code> attribute specifies the type of the style sheet. Although normal CSS style sheets have the type <code>text/css</code>, OEB requires that your standard style sheet have the type <code>text/x-oeb1-css</code> to indicate it meets the modified requirements of OEB style information.</p>
+
+<p>Using <code><link></code> will make your document compatible with HTML and allow your style information to show up in a typical HTML browser. The <code><link></code> tag is not, however, a standard way of linking XML documents in general, which is why OEB allows (and the authors of this work recommend) another linking mechanism which is standardized for XML.</p>
+
+<h4 id="linkxml">Linking Style Sheets with XML</h4>
+
+<p>XML now defines a standard method of linking style sheets to any XML document, which includes OEB documents. This method was still being standardized while the OEB Publication Structure specification was first being written, and that's why OEBPS 1.0 does not give examples of XML style linking. However, on 29 June 1999, version 1.0 of "Associating Style Sheets with XML documents" became an official W3C recommendation, and can be found at <a href="http://www.w3.org/TR/xml-stylesheet/">http://www.w3.org/TR/xml-stylesheet/</a>. This new development was unfortunately missed as OEB was released, so the OEB specification still states that the final form of XML style association has yet to be finalized.</p>
+
+<p>With the final recommendation of XML style association by the W3C, we can recommend that all OEB books use this method for linking to style sheets. Doing so will ensure that OEB works are standard XML documents that can endure as older versions of HTML fade. Using the XML style association mechanism is very similar to the HTML method:</p>
+
+<blockquote><code><?xml-stylesheet href="karl.css" type="text/x-oeb1-css"?></code></blockquote>
+
+<p>The attributes here are identical to those in the <code><link></code> element, and have the same usage. The location in the document, however, is different: the <code><?xml-stylesheet></code> instruction appears before the <code><html></code> element.</p>
+
+<h3 id="review">Review</h3>
+
+<h4 id="summary">Summary</h4>
+<ul>
+ <li>OEB allows style sheets to be defined which specify how parts of an OEB document should be displayed or rendered.</li>
+ <li>Style sheets, when correctly used, help separate the content of a document from its presentation information.</li>
+ <li>OEB by default uses a modified form of CSS to specify style information.</li>
+ <li>A particular CSS style consists of a selector (such as <code>em</code>) and a style declaration which consists of one or more properties (e.g. <code>color:</code>) and associated values (e.g. <code>red</code>), such as <code>em {color: red}</code>.</li>
+ <li>A style can specify a style class that can be used for particular elements inside the <code>class</code> attribute. The style <code>em.colorful {color: red}</code>, for example, can be used with a particular <code><em></code> element: <code><em class="colorful"></code>...<code></em></code>.</li>
+ <li>Although not normally recommended, style information can be specified for a particular element inside its <code>style</code> attribute, such as <code><em style="color: red"></code>...<code></em></code>.</li>
+ <li>External style sheets can be associated with the document using the <code><link></code> element, a carryover from HTML, inside the <code><head></code> element.</li>
+ <li>The recommended standard way for associating a style sheet with a document is to instead use the <code><?xml-stylesheet></code> instruction before the <code><head></code> element.</li>
+</ul>
+
+<h4 id="cssproperties">CSS Properties</h4>
+<ul>
+ <li><code>font-style:</code> Specifies the style of the font; although several values are available, we only addressed <code>italic</code>.</li>
+ <li><code>color:</code> Specifies the color of the font; although several values are available, we only addressed <code>red</code>.</li>
+</ul>
+
+<h3 id="exampleoebdocument">Completed Example OEB Document with Styles (<code>karl.html</code>)</h3>
+
+<blockquote>
+<code><?xml version='1.0'?></code><br />
+<code><!DOCTYPE html PUBLIC "+//ISBN 0-9673008-1-9//DTD OEB 1.0.1 Document//EN" "http://openebook.org/dtds/oeb-1.0.1/oebdoc101.dtd"></code><br />
+<code><?xml-stylesheet href="karl.css" type="text/x-oeb1-css"></code><br />
+<code><html></code><br />
+<code><body></code><br />
+ <code><p></code>Years ago, when strange creatures ruled the earth, the seas were beginning to form, and humans had yet to appear, there lived a young blovjus named Karl. Karl had three siblings: Kris, Krista, and Karla. Being <code><em></code>extremely<code></em></code> smaller than other blovji his age, Karl constantly ran into trouble at the dinner table.<code></p></code><br />
+<code></body></code><br />
+<code></html></code>
+</blockquote>
+
+<h3 id="examplestylesheet">Completed Example Style Sheet (<code>karl.css</code>)</h3>
+
+<blockquote>
+ em {color: red}
+</blockquote>
+
+</body>
+</html>
--- /dev/null
+++ b/lib/ebooks/understandingoeb/chapter4.html
@@ -1,0 +1,442 @@
+<?xml version='1.0'?>
+<!DOCTYPE html PUBLIC "+//ISBN 0-9673008-1-9//DTD OEB 1.0.1 Document//EN" "http://openebook.org/dtds/oeb-1.0.1/oebdoc101.dtd">
+<?xml-stylesheet href="understandingoeb.css" type="text/x-oeb1-css"?>
+
+<html>
+<head>
+ <link rel="stylesheet" type="text/x-oeb1-css" href="understandingoeb.css" />
+<title>Understanding OEB Chapter 4</title>
+ <meta name="author" content="Garret Wilson" />
+ <meta name="copyright" content="Copyright (c) 2000-2001 Garret Wilson. All rights reserved." />
+</head>
+
+<body>
+
+<h2 id="chapter4">4. Essential OEB Elements</h2>
+
+<p>You now know the minimum structural requirements of creating a publication in OEB format. You're beginning to understand some of the reasoning behind latest directions of information storage formats such as XML, which OEB is based on. Right now, you could place almost any work in a few OEB documents and an OEB package, and it would at least be legal OEB and work with a compliant OEB reading system. You also know how to create style sheets and associate them with your documents.</p>
+
+<p>What you've learned so far will work fine for your one-paragraph masterpiece. But once you try to use OEB to create a slightly longer sequel, you'll probably very soon run into some very real needs: "How do I display lists?" "How do I change the font?" "How so I create links from one section of my book to another?" The OEB Publication Structure has some very real answers to these questions. Even better yet, since OEB is built upon XML, the following chapters will show you how to create your own answers in areas that OEB does not yet address.</p>
+
+<p>You've had a glance at a few elements defined by OEB, such as <code><p></code>, <code><em></code> and <code><dfn></code>. OEB has a substantial number of other tags already defined for you to use; obviously, you'll need to know at least some of the others to do anything useful with OEB. We'll now look at essential elements and styles that you'll need in day-to-day use of OEB. If you've already started putting together an OEB publication, hopefully we'll answer some of the issues you've already encountered. Otherwise, we'll get a lot of common questions out of the way and prepare you for the real-world OEB creation project found in the next chapter.</p>
+
+<p>It's important to note that the OEB elements discussed here are a basic set of elements defined by OEB. OEB is flexible enough to allow extended documents that include user-defined elements, and this process is likely to be enhanced even more in future OEB versions. Creating user-defined elements is beyond the scope of this current edition, but will likely be addressed in an upcoming version of this book.</p>
+
+<h3 id="inlineelements">Inline Elements</h3>
+
+<p>Although XML allows any number of elements to be defined, OEB has defined a certain set of elements to be used in documents. You've seen and used a few of those, such as <code><p></code>, <code><em></code> and <code><dfn></code>. Besides defining which tags can be used, OEB also specifies the location and contexts in which these elements can appear. You've probably understood intuitively, for example, that emphasized text goes inside a paragraph, like this:</p>
+
+<blockquote><code><p></code>This is <code><em></code>emphasized<code></em></code> text.<code></p></code></blockquote>
+
+<p>You probably didn't even consider putting a paragraph inside of emphasized text:</p>
+
+<blockquote><strong>Illegal!</strong> <code><p></code>This is <code><em></code>emphasized text with a <code><p></code>paragraph<code></p></code> inside<code></em></code> the emphasized text.<code></p></code></blockquote>
+
+<p>As you might have guessed, this sort of construction is not allowed. The elements <code><em></code> and <code><dfn></code> can only appear inside paragraphs (and lists and other similar elements), and are therefore considered <em>inline</em> elements. Those are the elements we'll examine here.</p>
+
+<div class="sidebar" id="xmlcontentmodels">
+<h4 class="sidebarTitle">More Information: XML Content Models</h4>
+
+<p>XML could be considered a general markup language that acts as a toolkit for creating other markup languages. OEB uses XML to create its own markup language called the OEB Publication Structure. OEB uses XML not only to create a set of elements to be used (the <dfn>tag set</dfn>), but also to specify where the elements may appear. The specification of the correct locations of elements is called a <dfn>content model</dfn>.</p>
+
+<p>HTML uses a very lenient content model; a web browser will read HTML files that have elements that appear just about anywhere. This is not only notoriously hard to process, it also results in many ambiguities in what was actually meant by the author of the document. Since we'd like to follow the trend in encoding data and meaning into documents, this ambiguity is not acceptable.</p>
+
+<p>The content model used by OEB is therefore more strict than traditional HTML, and closely follows <a href="http://www.w3.org/TR/xhtml1/">XHTML</a>, a new version of HTML created specifically to be used with XML. This means that some constructs which could be used in HTML are not allowed in OEB. For example, the inline element <code><em></code> could be used in HTML to make several paragraphs emphasized:</p>
+
+<blockquote><strong>Legal HTML, Illegal OEB:</strong><br />
+ <code><em></code><br />
+ <code><p></code>Paragraph 1<code></p></code><br />
+ <code><p></code>Paragraph 2<code></p></code><br />
+ <code></em></code>
+</blockquote>
+
+<p>Since <code><em></code> is an inline element, this will not work in an OEB document. Fixing this problem is simple, however: just bring the <code><em></code> back inside each <code><p></code> element:</p>
+
+<blockquote><strong>Legal HTML, Legal OEB:</strong><br />
+ <code><p><em></code>Paragraph 1<code></em></p></code><br />
+ <code><p><em></code>Paragraph 2<code></em></p></code><br />
+</blockquote>
+
+<p>The actual OEB content model is not discussed explitely in the OEB specification, but it is defined in the OEB XML Document Type Declaration (DTD), which will be discussed later. Many times, such as in the case of the <code><em></code> element, the you can probably tell intuitively where an element can appear. In all cases, OEB validation software will be able to check your document against the OEB DTD and tell you whether or not your document has all its elements in the correct places.</p>
+
+</div>
+
+<h4 id="emelement">The <code><em></code> Element</h4>
+
+<p>You've already seen the <code><em></code> element — perhaps more than you've wanted. It bears repeating that the <code><em></code> element should be used instead of the <code><i></code> (italics) element in most cases, designating that the text should be emphasized but not specifying how the emphasized text should appear. An example of how specific text could be emphasized might be this:</p>
+
+<blockquote><code><p></code>Although the venture capital company seemed <code><em></code>really<code></em></code> interested in our project, perhaps the representative only <code><em></code>seemed<code></em></code> really interested.<code></p></code></blockquote>
+
+<blockquote>Although the venture capital company seemed <span style="font-style: italic">really</span> interested in our project, perhaps the representative only <span style="font-style: italic">seemed</span> really interested.</blockquote>
+
+<h4 id="strongelement">The <code><strong></code> Element</h4>
+
+<p>The <code><strong></code> element is similarly to the <code><em></code> in that it specifies that a section of text should be emphasized, but is used in most cases where bold text would be used. In fact, the default rendering of the <code><strong></code> element is using a bold font, although we've seen that any default rendering can be changed using styles.</p>
+
+<p>Also similar to the <code><em></code> tag, OEB has a carryover tag from HTML that functions similar to the <code><strong></code> tag but that specifies actual formatting: the <code><b></code> tag, representing bold text. For reasons we've explained earlier, we don't recommend using tags that specify presentation information within a document itself. Therefore, you should in most cases use <code><strong></code> rather than <code><b></code> whenever marking up text usually rendered in bold.</p>
+
+<blockquote><code><p></code>The Hindi letter "ka" is pronounced similarly to the first part of the English word, "<code><strong></code>cu<code></strong></code>p".<code></p></code></blockquote>
+
+<blockquote>The Hindi letter "ka" is pronounced similarly to the first part of the English word, "<span style="font-weight: bolder">cu</span>p".<code></p></code></blockquote>
+
+<h4 id="dfnelement">The <code><dfn></code> Element</h4>
+
+<p>We've already discussed using the <code><dfn></code> element to represent a word or words that are being defined for the first time.</p>
+
+<blockquote><code><p></code>The Hindi alphabet is usually specified as being a <code><dfn></code>syllabary<code></dfn></code>, since each letter of a word represents a syllable.<code></p></code></blockquote>
+
+<blockquote>The Hindi alphabet is usually specified as being a <dfn>syllabary</dfn>, since each letter of a word represents a syllable.</blockquote>
+
+<h4 id="codeelement">The <code><code></code> Element</h4>
+
+<p>OEB has several inline elements, some of which you'll use and some of which you'll never need unless creating certain esoteric documents. We mention that <code><code></code> element here because, since OEB was created by the computer-using community, it's likely that the first applications of OEB (this work included) will refer to computer programs or software.</p>
+
+<p>The <code><code></code> element was created to represent a section of computer program code, or data that should be entered by the user. This element is usually rendered in a monospaced font such as Courier, but as we've repeatedly stressed, you can change this behavior using styles.</p>
+
+<blockquote><code><p></code>In many programming languages, the statement <code><code></code>variable=16<code></code></code> represents an assignment operation, assigning the value on the right to the variable on the left of the equals sign.<code></p></code></blockquote>
+
+<blockquote>In many programming languages, the statement <code>variable=16</code> represents an assignment operation, assigning the value on the right to the variable on the left of the equals sign.</blockquote>
+
+<h4 id="citeelement">The <code><cite></code> Element</h4>
+
+<p>Many nonfiction works include information from other sources, and when they do so it is proper to cite the source from which the material was derived. The <code><cite></code> provides a standard way to indicate a cited source.</p>
+
+<blockquote>
+ <code><p></code>"The UN, like the League of Nations before it, was designed around the concept of state sovereignty" (<code><cite></code>Calvocoressi 1996<code></cite></code>).
+</blockquote>
+
+<blockquote>
+ "The UN, like the League of Nations before it, was designed around the concept of state sovereignty" (<cite>Calvocoressi 1996</cite>).
+</blockquote>
+
+<h4 id="spanelement">The <code><span></code> Element</h4>
+
+<p>Our discussion of inline elements has thus far assumed that, if you looked hard enough, you could find an OEB element that represented more or less the meaning of the section of text to which you're referring. We've stressed that you can always later change the style of the particular element you chose.</p>
+
+<p>What if you can't find an element that's appropriate, but still want to specify a style for a section of text? OEB provides (again borrowed from HTML) a generic element, <code><span></code>, that has no meaning other than to specify a section of text. The <code><span></code> element has the normal <code>style</code> and <code>class</code> attributes, allowing you to specify style for an arbitrary section of text. For example, imagine you want to somehow highlight the vowels in an alphabet, but don't want to use <code><em></code> because you'd like to use some separate style. You could always create a specific style class for <code><em></code>, but you might rather specify style information from scratch using <code><span></code>, like this:</p>
+
+<blockquote><code><p></code>English Alphabet: <code><span style="color: red"></code>A<code></span></code> B C D <code><span style="color: red"></code>E<code></span></code> F G...<code></p></code></blockquote>
+
+<blockquote>English Alphabet: <span style="color: red">A</span> B C D <span style="color: red">E</span> F G...</blockquote>
+
+<p>You should immediately protest that actual style information should not be included in the document itself. A slight modification resolves this problem and makes the use of <code><span></code> acceptable. First specify a style class, such as <code>.vowel {color:red}</code>, and then use this class in the <code><span></code> element:</p>
+
+<blockquote><strong>Style Sheet:</strong> <code>.vowel {color:red}</code></blockquote>
+
+<blockquote><strong>Document:</strong> <code><p></code>English Alphabet: <code><span class="vowel"></code>A<code></span></code> B C D <code><span class="vowel"></code>E<code></span></code> F G...<code></p></code></blockquote>
+
+<blockquote>English Alphabet: <span style="color: red">A</span> B C D <span style="color: red">E</span> F G...</blockquote>
+
+<div class="sidebar" id="customelements">
+<h4 class="sidebarTitle">More Information: Creating Custom Elements</h4>
+
+<p>Using the <code><span></code> element in the way we've just outlined is remarkably close to creating a new element named <code><vowel></code>; instead, we've used the <code><span></code> element with a style class named "vowel", which ends of serving the same function.</p>
+
+<p>The <code><span></code> element was introduced in HTML before XML was available, and is therefore the only way standard HTML can add what may be called pseudo-elements into an HTML document. XML, on the other hand, includes a method (which will be discussed later) for creating real custom elements from scratch. Since OEB is based on XML, it does allow one to create something called an <dfn>extended</dfn> OEB document which includes custom-built tags, meaning that the <code><span></code> element is little more than an a clumsy, inefficient way to do something that is much more elegantly done using standard XML techniques.</p>
+
+<p>Why then does OEB include the <code><span></code> element? One of the reasons should be quite familiar by now: since this tag is included in HTML, it was brought over into OEB so that standard HTML pages could be converted to OEB with minimal modification. The creation of custom elements using XML is furthermore more difficult than using the <code><span></code> element. Another reason should also be familiar: custom XML elements do not display correctly on HTML browsers.</p>
+
+<p>The majority of the OEB Authoring Group therefore felt it a higher priority to quickly release a specification that would bring about consensus in a quickly growing eBook industry than to force the adoption of barely released technologies such as custom XML elements. Happily, the OEBPS 1.0.1 still allows those who wish to follow useful standardization trends can still use XML to create custom elements. A discussion of how this is done is outside the scope of the current release of this book.</p>
+
+</div>
+
+<h4 id="brelement">The <code><br></code> Element</h4>
+
+<p>You learned in an earlier chapter that multiple adjacent whitespace characters, such as spaces and line breaks, are always replaced with a single space character before the text is displayed. This seems reasonable until you encounters a situation in which you'd like to display text on a separate line, perhaps like this:</p>
+
+<blockquote>
+<code><p></code>...Karl had three siblings:<br />
+Kris<br />
+Krista<br />
+Karla<code></p></code>
+</blockquote>
+
+<p>As you'll soon realize, if you've forgotten our earlier discussion about whitespace, what is displayed is not exactly what was entered:</p>
+
+<blockquote>...Karl had three siblings: Kris Krista Karla</blockquote>
+
+<p>You could always put the name of each of Karl's siblings in a separate paragraph, but they aren't really separate paragraphs. Besides, you don't want to risk their being formatted like paragraphs when displayed (either indented or separated by blank lines, depending on the reading system).</p>
+
+<p>The real solution here is to use a separate list element, which you'll learn about later in this chapter. But you might insist that these items should go <em>inside</em> the paragraph, and you want to choose where the line breaks appear. A better example might be a poem, in which you'd like to guarantee that a line break appears after each line:</p>
+
+<blockquote>
+<code><p></code>There was a young creature named Karl<br />
+Whose siblings would say with a snarl<br />
+We'll share what we eat:<br />
+Just some bones from the meat<br />
+And a little of "ic" from the "garl".<code></p></code>
+</blockquote>
+
+<p>Here again, it would be more preferable if there were a <code><poem></code> element in OEB. There isn't. Short of creating your own tag for this situation, OEB provides an element that specifies that a line break should appear: the <code><br></code> element.</p>
+
+<p>The <code><br></code> element is different than the elements examined so far in that it cannot have content; since it signifies a line break at a particular location in the text, it doesn't display text and has no need to hold text. The <code><br></code> element is therefore referred to as an <dfn>empty element</dfn>. You might expect the <code><br></code> element to simply have a beginning and ending tag with nothing in between (<code><br></code><code></br></code>). However, XML specifies a special format for empty elements by combining the beginning and ending tags into one tag: <code><br /></code></p>
+
+<ul>
+ <li id="emptyElement"><strong>XML Rule 6:</strong> (<em>Empty Elements</em>) An element that cannot have text between its beginning and ending tags is classified as a <dfn>empty element</dfn>, and has a special form of a single tag with the element name followed by a slash (/): <code><name /></code></li>
+</ul>
+
+<p><strong>Important:</strong> While not required by XML, OEB specifies that all empty tags must have a space between the tag name and the slash character. This is to ensure that OEB documents can be displayed more or less correctly in HTML browsers.</p>
+
+<p>The <code><br></code> element might therefore be used in a re-write of Lewis Carroll's <i>Alice's Adventures in Wonderland</i>:</p>
+
+<blockquote>
+<code><p></code>Alice fell down the rabbit hole...<code><br /></code><br />
+Down...<code><br /></code><br />
+Down...<code><br /></code><br />
+Down...<code></p></code>
+</blockquote>
+
+<p>This would be correctly displayed as expected:</p>
+
+<blockquote>
+Alice fell down the rabbit hole...<br />
+Down...<br />
+Down...<br />
+Down...
+</blockquote>
+
+<p>The <code><br></code> element, however, has the potential of being abused and overused. In most places, items might more appropriately be placed in separate paragraphs, or perhaps in a list. In keeping with our goal of using markup to encode meaning into a document, it would probably be better to place a poem inside a <code><poem></code> element or something similar, although in this case we would have to define such an element before it could be used. The use of <code><br></code> to show the plight of Alice, above, is certainly the easiest and perhaps even an appropriate way to create the desired visual effect. We'd just like to encourage you to make sure that the <code><br></code> element is appropriate for the situation before using it.</p>
+
+<h4 id="aelement">The <code><a></code> Element</h4>
+
+<p>The anchor element, <code><a></code>, was first made popular by HTML. Since the <code><a></code> element is responsible for linking documents and sections of documents, this element is responsible for the "hypertext" part of HTML. Without <code><a></code>, HTML might otherwise have only been "TML", a text markup language with no linking capabilities. The OEB Publication Structure incorporated <code><a></code> into its tag set with hardly any modifications to its fundamental form.</p>
+
+<p>With its linking capabilites, <code><a></code> is the first tag we've discussed that starts to allow static pages in a book to come to life, to allow interaction with the user. The Open eBook specification begins with the assumption that a user will be provided with a paging function that will allow traversal through the contents of a book. The most fundamental purpose for hypertext anchors might be to link to reference sections or a glossary; however, the <code><a></code> element allows the author to provide many more complex navigation capabilites, allowing readers to even choose an arbitrary path through the book as they read.</p>
+
+<p>The most important attribute of the <code><a></code> element is <code>href</code>. As you've seen in elements both in the OEB package and in OEB style sheets, the <code>href</code> attribute specifies a "hypertext reference" location. Usually, the value of this attribute refers to a file; in other instances is can refer to a specific location within a file.</p>
+
+<p>Let's revisit a section from the first work we created.</p>
+
+<blockquote>
+ <code><p></code>Years ago, when strange creatures ruled the earth, the seas were beginning to form, and humans had yet to appear, there lived a young blovjus named Karl.<code></p></code>
+</blockquote>
+
+<p>Now, some uninformed readers may not know what a "blovjus" is. You may wish to provide a definition a reader can read. Having a definition in the text is unacceptable; you don't want to bother your many readers who know exactly what a blovjus is and do not want to be told again. Instead, you elect to place the definition in a separate OEB document file named <code>blovjus.html</code>:</p>
+
+<blockquote>
+<code><?xml version='1.0'?></code><br />
+<code><!DOCTYPE html PUBLIC "+//ISBN 0-9673008-1-9//DTD OEB 1.0.1 Document//EN" "http://openebook.org/dtds/oeb-1.0.1/oebdoc101.dtd"></code><br />
+<code><html></code><br />
+<code><body></code><br />
+ <code><p><strong></code>blovjus<code></strong></code> A strange, mythical creature which lived many years ago; sometimes it stole supper from its siblings.<code></p></code><br />
+<code></body></code><br />
+<code></html></code>
+</blockquote>
+
+<p>Using the <code><a></code> tag, it's a simple job to link "blovjus" in the text to its definition:</p>
+
+<blockquote>
+ <code><p></code>Years ago, when strange creatures ruled the earth, the seas were beginning to form, and humans had yet to appear, there lived a young <code><a href="blovjus.html"></code>blovjus<code></a></code> named Karl.<code></p></code>
+</blockquote>
+
+<p>Anchor elements can also be used to mark, or <dfn>anchor</dfn>, a section of text in a document (although this function is less important since each element in OEB contains an <code>id</code> attribute). This way, two <code><a></code> elements can be used together, one to mark a location and another to link to that location. This allows links not only to files, but to a specific location in a file. The tag serving as an anchor will use the <code>id</code> tag to provide a name for the anchor. The tag serving as a link will use the <code>href</code> as before to refer to a file, except that a pound sign (#) will be appended followed by the id of the anchor which serves as the link <dfn>target</dfn>.</p>
+
+<p>This is actually quite simple in practice. Assume that you have so many uninformed readers that you've created an entire glossary with many definitions. This glossary replaces the <code>blovjus.html</code> document file you created earlier, containing "blovjus" and other terms:</p>
+
+<blockquote>
+<code><?xml version='1.0'?></code><br />
+<code><!DOCTYPE html PUBLIC "+//ISBN 0-9673008-1-9//DTD OEB 1.0.1 Document//EN" "http://openebook.org/dtds/oeb-1.0.1/oebdoc101.dtd"></code><br />
+<code><html></code><br />
+<code><body></code><br />
+ <code><p><a id="blovjus"><strong></code>blovjus<code></strong></a></code> A strange, mythical creature which lived many years ago; sometimes it stole supper from its siblings.<code></p></code><br />
+ <code><p><a id="earth"><strong></code>earth<code></strong></a></code> The third planet from the sun.<code></p></code><br />
+<code></body></code><br />
+<code></html></code>
+</blockquote>
+
+<p>Note that we've placed an <code><a></code> element around each term to serve as an anchor to mark the link targer. We've specified a name for each target using the <code>id</code> attribute. Here, we've used names that match the terms we're defining, but we could have used any names as long as they are unique and we use the same names in the links. Here's what the links look like in our original file:</p>
+
+<blockquote>
+ <code><p></code>Years ago, when strange creatures ruled the <code><a href="glossary.html#earth"></code>earth<code></a></code>, the seas were beginning to form, and humans had yet to appear, there lived a young <code><a href="glossary.html#blovjus"></code>blovjus<code></a></code> named Karl.<code></p></code>
+</blockquote>
+
+<p>In each link, we specify the document in which the definitions reside (<code>glossary.html</code> in this example), followed by a pound sign (#) and then the ID of the appropriate definition (here, <code>earth</code> and <code>blovjus</code>). It is here that we must always make sure the name in the <code>href</code> attribute always matches the name in the target anchor tag's <code>id</code> attribute.</p>
+
+<p>This application of the anchor tag as a true anchor is less useful since OEB provides an <code>id</code> attribute for most elements. Instead of adding an <code><a></code> element and <code>id</code> attribute to serve as an anchor, you can instead add an <code>id</code> to the element to which you want to link. The above example, then, would appear like this:</p>
+
+<blockquote>
+<code><?xml version='1.0'?></code><br />
+<code><!DOCTYPE html PUBLIC "+//ISBN 0-9673008-1-9//DTD OEB 1.0.1 Document//EN" "http://openebook.org/dtds/oeb-1.0.1/oebdoc101.dtd"></code><br />
+<code><html></code><br />
+<code><body></code><br />
+ <code><p id="blovjus"><strong></code>blovjus<code></strong></code> A strange, mythical creature which lived many years ago; sometimes it stole supper from its siblings.<code></p></code><br />
+ <code><p id="earth"><strong></code>earth<code></strong></code> The third planet from the sun.<code></p></code><br />
+<code></body></code><br />
+<code></html></code>
+</blockquote>
+
+<p>This version of specifying a link target is the recommended one — there is no need to specify an anchor for the target because almost any OEB element can contain an ID attribute. The <code><a></code> element will still be needed, of course, to link <em>to</em> the referenced location.</p>
+
+<p>Anchor tags are the first step in leveraging the capabilities of electronic books which static books do not have. Hypertext linking has many uses, from creating tables of contents to providing user-initiated changes in a plot. We'll address some of these uses in the following chapters.</p>
+
+<h3 id="blockelements">Block Elements</h3>
+
+<p>Block elements could be considered the opposite of inline elements. They are the enclosing elements within which inline elements are placed. That is, inline elements have to have some element to be inside; this element is ultimately a block element (although inline elements can appear inside other inline elements). You've already seen one example of a block element, the <code><p></code> element representing a paragraph. Block elements could also be classified as elements that automatically have a line break before and after them; they might therefore also be appropriately called "out-of-line" elements.</p>
+
+<p>Traditionally, block elements in HTML also had a blank line immediately before and immediately after them, but OEB reading systems may prefer to display block elements differently, indenting the first line of text in a <code><p></code> element, for example.</p>
+
+<h4 id="pelement">The <code><p></code> Element</h4>
+
+<p>The <code><p></code> element is probably the most straightforward block-level element, and probably the most common. Every paragraph in OEB should be surrounded by <code><p></code>...<code></p></code>. As we've certainly used plenty of paragraphs up to this point, we won't give any examples here. Instead, we'll just give one precaution: be careful not to <em> overuse</em> the <code><p></code> tag. Make sure the block of text you're marking up is really a paragraph and not, say, a list or a heading, both of which are covered in the sections below.</p>
+
+<h4 id="headingelements">The <code><h1></code>...<code><h6></code> Heading Elements</h4>
+
+<p>Perhaps the second most common block element is actually a group of similar elements: <code><h1></code>, <code><h2></code>, <code><h3></code>, <code><h4></code>, <code><h5></code>, and <code><h6></code>. These elements represent different levels of headings in your document.</p>
+
+<p>What does "heading" mean? It represents whatever you want it to represent. You could use <code><h1></code> to represent the title of your book on the title page, and use <code><h2></code> to represent the title of each chapter. Alternatively, you could use <code><h1></code> to represent each chapter title, <code><h2></code> to represent each chapter subtitle, and use a completely separate style class (or custom XML element) to represent the book title on the title page.</p>
+
+<p>All this is at your discretion because the heading elements do not directly correspond to any particular division of a book; they do not have a particular meaning, such as "chapter title" or "subtitle". The only thing that you can be sure of is that the default rendering method for each higher-numbered heading (such as <code><h1></code>) will be larger than a lower-numbered heading (such as <code><h2></code>).</p>
+
+<p>The lack of a particular meaning for the <code><hX></code> elements makes them slightly less useful than one might expect. Some early eBook reading systems assigned meanings to the <code><hX></code> elements, allowing the reading system to automatically find and understand when chapters begin, for example. Other markup languages have specific tags that represent chapters and other divisions. OEBPS 1.0, however, has no elements that specifically indicate book structure, so you'll have to make do with the heading elements. While OEB may introduce such elements in the future, for now using the heading elements is highly preferable to specifying the styles of headings manually, of course. Just remember that the meanings assigned to the heading elements are completely up to you. You might choose, for example, to use them like this:</p>
+
+<blockquote>
+ <code><h1></code>Karl the Creature<code></h1></code><br />
+ <code><h2></code>Chapter 1: Karl as a Kid<code></h2></code><br />
+ <code><p></code>Years ago...<code></p></code><br />
+</blockquote>
+
+<blockquote>
+ <h1>Karl the Creature</h1>
+ <h2>Episode 1: Karl as a Kid</h2>
+ <p>Years ago...</p>
+</blockquote>
+
+<h4 id="lists">Lists, Ordered (<code><ol></code>) and Unordered (<code><ul></code>)</h4>
+
+<p>Almost every work, especially non-fiction educational works (like this one), have instances in which a list of items must be displayed. Many times the items in these lists are shown in a particular order, each item with a particular number. These lists are called <dfn>ordered lists</dfn>:</p>
+
+<blockquote>
+The names of the first three planets from the sun, in order, are:<br />
+1. Mercury<br />
+2. Venus<br />
+3. Earth
+</blockquote>
+
+<p>Not only must the numbers of each item in the list be carefully considered, care must be taken to ensure that the list is formatted correctly. Whenever the list is modified or reordered, care must be taken in modifying the numbering involved. Furthermore, there's no indication encoded in the file that this is a list; no meaning has been added to text that a computer or data-retrieval program could extract.</p>
+
+<p>OEB provides elements that solves all of these problems. In this case, we can use markup to specify that we have an ordered list (using the <code><ul></code> element), and that each item in the list is (as you would expect) a list item (using the <code><li></code> element). Ordered lists in OEB therefore consist of two separate elements, <code><ol></code> and <code><li></code>, used in conjunction like this:</p>
+
+<blockquote>
+<code><p></code>The names of the first three planets from the sun, in order, are:<code></p></code><br />
+<code><ol></code><br />
+<code><li></code>Mercury<code></li></code><br />
+<code><li></code>Venus<code></li></code><br />
+<code><li></code>Earth<code></li></code><br />
+<code></ol></code>
+</blockquote>
+
+<blockquote>
+<p>The names of the first three planets from the sun, in order, are:</p>
+<ol>
+<li>Mercury</li>
+<li>Venus</li>
+<li>Earth</li>
+</ol>
+</blockquote>
+
+<p>Notice two things: first, the number of each list item does not need to be specified; it is supplied automatically when the list is displayed. Second, the introductory statement, "The names of the first three planets...", is not technically part of the list, so it is not placed within the <code><ol></code>...<code></ol></code> tags. The OEB publication structure allows you to specify the formatting, the type, and even a language-specific representation of the numbers used in a list.</p>
+
+<p>Some types of lists do not have numbers associated with them; they are <dfn>unordered lists</dfn>. If you're listing items in a grocery list, for example, you may not care about the order in which they are purchased. You would therefore use the <code><ul></code> for the unordered list, which functions exactly like the <code><ol></code> element used for ordered lists:</p>
+
+<blockquote>
+<code><p></code>Please purchase the following items:<code></p></code><br />
+<code><ul></code><br />
+<code><li></code>Bread<code></li></code><br />
+<code><li></code>Eggs<code></li></code><br />
+<code><li></code>Milk<code></li></code><br />
+<code></ul></code>
+</blockquote>
+
+<blockquote>
+<p>Please purchase the following items:</p>
+<ul>
+<li>Bread</li>
+<li>Eggs</li>
+<li>Milk</li>
+</ul>
+</blockquote>
+
+<p>The default rendering method for unordered lists is to display a small round circle next to each item. You'll learn later how to use styles to modify this behavior. Most importantly, we've specified that the information is actually a list of items, and we can later, if we wish, arbitrarily change the way this list is displayed using styles, without changing the actual text of the document.</p>
+
+<h4 id="divelement">The <code><div></code> Element</h4>
+
+<p>The <code><span></code> element, as you saw earlier, provided a convenient way to specify style information about an arbitrary set of characters inside a block element. That last aspect somewhat limits its applicability, though: since <code><span></code> is an inline element, it can't be used to specify style information for more than one block element. That's why <code><div></code> in included in OEB.</p>
+
+<p>The <code><div></code> element is the block-level equivalent to the inline <code><span></code> span. It has no meaning in itself; its sole purpose is to group several block-level elements for the purpose of applying styles, for example. To see an example of where the <code><div></code> element could be applied, let's revisit an example of an inappropriate use of the <code><em></code> element:</p>
+
+<blockquote><strong>Illegal:</strong><br />
+ <code><em></code><br />
+ <code><p></code>Paragraph 1<code></p></code><br />
+ <code><p></code>Paragraph 2<code></p></code><br />
+ <code></em></code>
+</blockquote>
+
+<p>As we noted when discussing the OEB content model, the <code><em></code> element, being an inline element, cannot enclose the <code><p></code> element, a block element. We explained that the <code><em></code> element could simply be moved inside the <code><p></code>, like this:</p>
+
+<blockquote><strong>Legal OEB:</strong><br />
+ <code><p><em></code>Paragraph 1<code></em></p></code><br />
+ <code><p><em></code>Paragraph 2<code></em></p></code><br />
+</blockquote>
+
+<p>The same effect could be achieved using the <code><div></code> element in a similar manner to that used in the first example. An emphasis style class could be created and applied to a surrounding <code><div></code> element:</p>
+
+<blockquote><strong>Style Sheet:</strong> <code>.emphasis {font-style: italic}</code></blockquote>
+
+<blockquote><strong>Document:</strong><br />
+ <code><div class="emphasis"></code><br />
+ <code><p></code>Paragraph 1<code></p></code><br />
+ <code><p></code>Paragraph 2<code></p></code><br />
+ <code></div></code>
+</blockquote>
+
+<p>As with the <code><span></code> element, the <code><div></code> element is another carryover from HTML that allows one to simulate the creation of a custom tag. Also similarly to how the <code><span></code> element is used, XML allows true custom elements to be created, making <code><div></code>, although convenient, somewhat redundant. It's this convenience that makes <code><div></code> quite attractive and perhaps acceptable in some situations. Before using it, however, make sure that a custom XML element wouldn't be more appropriate.</p>
+
+<h4 id="centerelement">The <code><center></code> Element (deprecated)</h4>
+
+<p>OEB includes <code><center></code> but marks it as <dfn>deprecated</dfn>: its use is allowed so that HTML documents will not require much modification, but its use is discouraged. In fact, the <code><center></code> element is mentioned here only because its use has become <em>very</em> popular over the years in HTML documents. We echo the exhortation of the OEBPS specification (and the latest version of HTML) that the <code><center></code> element should not be used in new OEB document; explicitly specifying that a section of text should be centered goes against the concept of separation of content and presentation.</p>
+
+<blockquote>
+ <strong>Deprecated:</strong> <code><center></code>Chapter 1: Karl as a Kid<code></center></code>
+</blockquote>
+
+<blockquote>
+ <div style="text-align: center">Chapter 1: Karl as a Kid</div>
+</blockquote>
+
+<p>As an alternative, OEB (and HTML) allow text to be centered using styles. Specifically, the <code>text-align</code> property, which we'll discuss later in this chapter, allows a <code>"center"</code> value that gives the desired effect. Using style classes with the <code><div></code> element we just discussed might yield something like this:</p>
+
+<blockquote><strong>Style Sheet:</strong> <code>.chapterhead {text-align: center}</code></blockquote>
+
+<blockquote><strong>Document:</strong>
+ <code><div class="chapterhead"></code>Chapter 1: Karl as a Kid<code></div></code>
+</blockquote>
+
+<p>As is usually the case with <code><div></code>, there are better ways to specify which text should be centered. If you're already using <code><h1></code> for chapter headings, for example, specifying that the chapter headings should be centered is quite easy using styles, and illustrates how convenient and appropriate style sheets can be:</p>
+
+<blockquote><strong>Style Sheet:</strong> <code>h1 {text-align: center}</code></blockquote>
+
+<blockquote><strong>Document:</strong>
+ <code><h1></code>Chapter 1: Karl as a Kid<code></h1></code>
+</blockquote>
+
+<p>Whatever method you choose to use to center text, we encourage you that it not be the <code><center></code> element.</p>
+
+<h4 id="blockquoteelement">The <code><blockquote></code> Element</h4>
+
+<p>In contrast to the <code><center></code> element, <code><blockquote></code> is a good example of how elements should encode meaning into a document and assist in separating content from presentation. Many nonfiction works have sentences quoted from other works. If a quote is several sentences or even several paragraphs long, it is usually placed in a separate, indented paragraph or group of paragraphs. The <code><blockquote></code> element allows text to be specified as a block of quoted text without worrying how it will be formatted. Usually, the default indented style is acceptable, but this can easily be changed using styles.</p>
+
+<p>The <code><blockquote></code> element has one optional attribute, <code>cite</code>, which allows the web address location of the quote to be specified. Note that the inline element with the same name as the attribute, <code><cite></code>, is often used in conjunction with the <code><blockquote></code> element:</p>
+
+<blockquote>
+ <code><blockquote cite="http://www.un.org/Overview/rights.html"></code><br />
+ Everyone is entitled to all the rights and freedoms set forth in this Declaration, without distinction of any kind, such as race, colour, sex, language, religion, political or other opinion, national or social origin, property, birth or other status. Furthermore, no distinction shall be made on the basis of the political, jurisdictional or international status of the country or territory to which a person belongs, whether it be independent, trust, non-self-governing or under any other limitation of sovereignty.
+ (<code><cite></code>UN Declaration of Universal Human Rights, Article 2, December 10, 1948<code></cite></code>)<br />
+ <code></blockquote></code>
+</blockquote>
+
+<blockquote cite="http://www.un.org/Overview/rights.html">
+Everyone is entitled to all the rights and freedoms set forth in this Declaration, without distinction of any kind, such as race, colour, sex, language, religion, political or other opinion, national or social origin, property, birth or other status. Furthermore, no distinction shall be made on the basis of the political, jurisdictional or international status of the country or territory to which a person belongs, whether it be independent, trust, non-self-governing or under any other limitation of sovereignty. (<cite>UN Declaration of Universal Human Rights, Article 2, December 10, 1948</cite>)
+</blockquote>
+
+</body>
+</html>
--- /dev/null
+++ b/lib/ebooks/understandingoeb/chapter5.html
@@ -1,0 +1,156 @@
+<?xml version='1.0'?>
+<!DOCTYPE html PUBLIC "+//ISBN 0-9673008-1-9//DTD OEB 1.0.1 Document//EN" "http://openebook.org/dtds/oeb-1.0.1/oebdoc101.dtd">
+<?xml-stylesheet href="understandingoeb.css" type="text/x-oeb1-css"?>
+
+<html>
+<head>
+ <link rel="stylesheet" type="text/x-oeb1-css" href="understandingoeb.css" />
+<title>Understanding OEB Chapter 5</title>
+ <meta name="author" content="Garret Wilson" />
+ <meta name="copyright" content="Copyright (c) 2000-2001 Garret Wilson. All rights reserved." />
+</head>
+
+<body>
+
+<h2 id="chapter5">5. Essential OEB Styles</h2>
+
+<p>You've learned the essentials of styles in OEB, but you would be hard-pressed at this point to put this knowledge to use without knowing which styles are actually allowed. You probably have visions of how you'd like to change the appearance of your document: its fonts, its indentation, even its color. Here we'll address some of the most important style properties available for your use. Keep in mind that OEB style sheets are little more (and a little more less) than a subset of Cascading Style Sheets (CSS); what you'll learn here will in large part be transferable (although somewhat restricted) to CSS as it is used in general.</p>
+
+<h3 id="styleunits">Style Units</h3>
+
+<p>The styles you have seen so far in the examples have been qualitative, specifying whether a particular property applies to a particular section of text. We've seen how to specify italics: the <code>font-style</code> of text is either <code>italic</code> or it isn't. Similarly with color, the CSS <code>color</code> property can take color names such as <code>black</code> and <code>red</code>.</p>
+
+<p>Other style values can be quantitative, specifying numerical values for style properties. There are many cases in which you would want to specify the length, the height, or the width of something such as a font size or an indentation amount. Implicit in each of these cases is a <dfn>unit</dfn> of measurement: if you want a font of size <code>12</code>, does that "12" represent a height of 12 pixels, 12 centimeters, or 12 kilometers?</p>
+
+<p>When a <dfn>length</dfn> (the CSS term for instances of numeric value) is used, CSS requests that you specify a <dfn>unit</dfn>, unless in specific cases which we'll discuss later. A percentage, for example, does not need a unit specified, nor does a property which takes a count of something rather than a measurement. In all other cases, a unit will be used from the following list of those supported by CSS (and by OEB):</p>
+
+<ul>
+ <li><strong><code>px</code></strong> (pixels) The length represents a number of pixels.</li>
+ <li><strong><code>ex</code></strong> (x-height) The length represents multiples of the height of the lowercase letter "x" in the current font.</li>
+ <li><strong><code>em</code></strong> (m-width) The length represents the size of the font. (The name comes from its originally representing multiples of the width of the letter "M" in the current font.)</li>
+ <li><strong><code>pt</code></strong> (points) The length represents a number of points, with one point being equal to 1/72 of an inch.</li>
+ <li><strong><code>cn</code></strong> (centimeters) The length represents a number of centimeters.</li>
+ <li><strong><code>mm</code></strong> (millimeters) The length represents a number of millimeters.</li>
+ <li><strong><code>pc</code></strong> (picas) The length represents a number of picas, with one pica being equal to 12 points.</li>
+</ul>
+
+<p>This list can be used as a short reference; the units themselves will become more straightforward in their actual use.</p>
+
+<h3 id="fontproperties">Font Properties</h3>
+
+<p>CSS font-related properties specify how a portion of text looks: the size, the type family, and the style, for instance. Specifically, we'll consider <code>font-family</code>, <code>font-size</code>, <code>font-style</code>, and <code>font-weight</code>, throwing <code>text-decoration</code>, <code>color</code> and <code>background-color</code> in for good measure.</p>
+
+<h4 id="fontfamilyproperty">The <code>font-family</code> Property</h4>
+
+<p>When you think of changing a font in a word processor, you usually think of specifying its name: "Times New Roman" and "Arial" are common examples. These names do not really specify the entire font itself (remember, the font includes the size, style and everything else about the font), but instead indicates the <dfn>font family</dfn>, the group of fonts of varying styles and sizes that look similar.</p>
+
+<p>The <code>font-family</code> property allows you to specify the name of a font family in the normal CSS way, specifying the property and value in a declaration:</p>
+
+<blockquote><code>{font-family: "Times New Roman"}</code></blockquote>
+
+<p>Since this particular font family, "Times New Roman", has spaces in its name, we've placed it inside quotes. Family names without spaces do not need quotes.</p>
+
+<p>In a real style sheet, you would also need to specify one or more elements to which to apply the style, using a selector. For example, you might wish to specify the default font for the entire OEB document. Since all text in an OEB document appears inside an enclosing <code><body></code> element, you can specify a default font by using <code>body</code> as the selector:</p>
+
+<blockquote><code>body {font-family: "Times New Roman"}</code></blockquote>
+
+<p>The font family "Times New Roman" is quite popular and comes installed on many computer operating platforms. There's no way to guarantee that it will be installed on the device or software the person reading your book is using, however. You might even decide to use a font family that no one else is using (after all, style sheets are about specifying custom styles). Perhaps you've created a custom font family, and it only exists on your machine! Your book will look quite nice on your own computer or reading device, but what about on other systems?</p>
+
+<p>CSS defines several generic font families (or more accurately, generic divisions of font families), three of which OEB uses. These font familes are guaranteed to be present on any OEB compliant reading system. They are:</p>
+
+<ul>
+ <li><strong>serif</strong> A font family with serifs present (such as "Times New Roman").</li>
+ <li><strong>sans-serif</strong> A font family without serifs present (such as "Arial").</li>
+ <li><strong>monospace</strong> A font family in which each character takes up the same amount of horizontal space (such as "Courier").</li>
+</ul>
+
+<p>Using one of these three fonts will guarantee that your text will be assigned a font with the same properties you intended on every OEB compliant reading system. But what about customization? OEB does not yet specify a way to deliver custom fonts to a reading system, but there is a middle ground: CSS allows one to specify the preferred font family, yet also specify the font family to use if the preferred font is not present.</p>
+
+<p>Specify a list of preferred <code>font-family</code> values by separating them with commas (,) with the most preferred font first. If you use "Book Antiqua", a serif font family, you might specify the following as the default font:</p>
+
+<blockquote><code>body {font-family: "Book Antiqua", "Times New Roman", serif}</code></blockquote>
+
+<p>Notice that we've specified <code>serif</code>, the generic font family guaranteed to be present, as our last choice. We always want the text displayed, and even if the reading system offers no frills whatsoever, this font family is guaranteed to be present. In fact, it is recommended that you <em>always</em> provide one of the generic font families as your last choice in your fallback list.</p>
+
+<ul>
+ <li><strong>CSS Tip 1:</strong> (<em>Supplying Default Generic Font Family Names</em>) Always provide one of the generic font family names in your <code>font-family</code> fallback list.</li>
+</ul>
+
+<h4 id="fontsizeproperty">The <code>font-size</code> Property</h4>
+
+<p>CSS allows a font size to be specified absolutely, using the <code>font-size</code> property and one of the units specified earlier. (Note that there is no whitespace between the value and the unit name.) A 12 point font could be selected as the default using the following:</p>
+
+<blockquote><code>body {font-size: 12pt}</code></blockquote>
+
+<p>While it might be appropriate to specify the absolute size of the default font, which applies to everything inside the <code><body></code> tag (and thereby everything in the document), it's not wise to specify an absolute value for elements within the document. For example, to make all emphasized text a little larger than the surrounding text, an absolute value might be used like this:</p>
+
+<blockquote><strong>Not Recommended:</strong> <code>em {font-size: 14pt}</code></blockquote>
+
+<p>There are several reasons this isn't a good idea. What if you were to later change the default font for <code><body></code> to 16 points? You'd then have to make sure that every other absolute value, such as that for <code><em></code>, was changed as well, or the emphasized text would be <em>smaller</em> than the surrounding text — the 14-point emphasized text didn't change, but the surrounding text changed to 16 points. Furthermore, remember that the <code><em></code> element can appear several places, such as within an <code><h1></code> element, which traditionally is larger than the default text. You'd want the emphasized text even larger than the 14 points you specified. In short, it would be ideal to be able to specify that a particular element's size in relation to its surrounding text (or rather, relative to the size of the enclosing element's font).</p>
+
+<p>One way CSS allows this to be done is using percentages. If you want emphasized text to be slightly larger than the text that surrounds it, it would be better to use something like this:</p>
+
+<blockquote><code>em {font-size: 120%}</code></blockquote>
+
+<p>In this case, if the <code><em></code> tag appeared inside an element of 12-point text, it would be rendered in a 14.4-point font (12 multiplied by 120% is 14.4). If the <code><em></code> element were to appear inside 16-point text, it would be rendered in a 19.2-point font. The following example shows how using a percentage can make relative sizes appear correctly in several locations:</p>
+
+<p>Style Sheet:</p>
+
+<blockquote>
+ <code>body {font-size: 12pt}</code><br />
+ <code>em {font-size: 120%}</code>
+</blockquote>
+
+<p>Document Extract:</p>
+
+<blockquote>
+ <code><h2></code>The <code><em></code>Extremely<code></em></code> Small Blovjus<code></h2></code><br />
+ <code><p></code>...Being <code><em></code>extremely<code></em></code> smaller than other blovji his age...<code></p></code><br />
+</blockquote>
+
+<blockquote>
+ <h2>The <em style="font-size: 120%">Extremely</em> Small Blovjus</h2>
+ <p>...Being <em style="font-size: 120%">extremely</em> smaller than other blovji his age...</p>
+</blockquote>
+
+<p>There are several other ways to represent relative sizes. You can use the units "em" or "ex", which specifies that the font should be so many multiples of the width of the "m" character or the height of the "ex" character, respectively, in the current font. We won't discuss these methods here.</p>
+
+<p>Just like <code>font-family</code>, which allows certain pre-defined font family names to be used, the <code>font-size</code> property has several pre-defined sizes. Some of these are relative sizes, functioning exactly as if percentages were used, and others are absolute, functioning exactly as if absolute sizes were used.</p>
+
+<p>Predefined relative <code>font-size</code> values:</p>
+
+<ul>
+ <li><strong>smaller</strong> Specifies the font size should be smaller than that of the enclosing element.</li>
+ <li><strong>larger</strong> Specifies the font size should be larger than that of the enclosing element.</li>
+</ul>
+
+<p>CSS recommends that a difference of 120% be used, which would make using <code>font-size: larger</code> equivalent to using <code>font-size: 120%</code>, for example, but this difference is not guaranteed.</p>
+
+<p>The other pre-defined <code>font-size</code> values are the following:</p>
+
+<ul>
+ <li><strong>xx-small</strong></li>
+ <li><strong>x-small</strong></li>
+ <li><strong>small</strong></li>
+ <li><strong>medium</strong></li>
+ <li><strong>large</strong></li>
+ <li><strong>x-large</strong></li>
+ <li><strong>xx-large</strong></li>
+</ul>
+
+<p>Although these are equivalent to using absolute font sizes, the actual font sizes these values stand for may very from platform to platform. CSS does say that you can expect values of <code>larger</code> and <code>smaller</code> to change between these absolute values. That is, for a current font size of <code>small</code>, an element with <code>font-size: larger</code> would give the equivalent of a font of size <code>medium</code>.</p>
+
+<h4 id="fontstyleproperty">The <code>font-style</code> Property</h4>
+
+<p>The <code>font-style</code>, as implemented by OEB, allows a font to be specified as <code>italic</code> or <code>normal</code> (that is, not italic). Although CSS allows another value, <code>oblique</code>, OEB reading systems are not required to support it, and may represent it as synonymous with <code>italic</code>.</p>
+
+<h4 id="fontweightproperty">The <code>font-weight</code> Property</h4>
+
+<p>Although CSS allows several values to be used with the <code>font-weight</code> property, OEB eliminates all but two of them, making <code>font-weight</code> simply a way to designate that text should be rendered as bold, in much the same way that <code>font-style</code> represented italics. The two values OEB allows for <code>font-weight</code> are <code>bold</code> and <code>normal</code>.</p>
+
+<h4 id="textdecorationproperty">The <code>text-decoration</code> Property</h4>
+
+<p>The <code>text-decoration</code> property allows underlining to be specified, in much the same way that previous properties allowed italics and bold to be specified. The two values allowed are <code>none</code> (the default), and <code>underline</code>.</p>
+
+</body>
+</html>
--- /dev/null
+++ b/lib/ebooks/understandingoeb/chapter6.html
@@ -1,0 +1,626 @@
+<?xml version='1.0'?>
+<!DOCTYPE html PUBLIC "+//ISBN 0-9673008-1-9//DTD OEB 1.0.1 Document//EN" "http://openebook.org/dtds/oeb-1.0.1/oebdoc101.dtd">
+<?xml-stylesheet href="understandingoeb.css" type="text/x-oeb1-css"?>
+
+<html>
+<head>
+ <link rel="stylesheet" type="text/x-oeb1-css" href="understandingoeb.css" />
+<title>Understanding OEB Chapter 6</title>
+ <meta name="author" content="Garret Wilson" />
+ <meta name="copyright" content="Copyright (c) 2000-2001 Garret Wilson. All rights reserved." />
+</head>
+
+<body>
+
+<h2 id="chapter6">6. Real-World OEB: Charter of the United Nations</h2>
+
+<p>At this point you should be able to create a fairly complex real-world OEB publication. We could demonstrate creating an OEB publication from the ground up by writing a book-length work from scratch, but it will probably be more illustrative to take a publication that already exists and convert it to OEB.</p>
+
+<p>Here, we'll take the Charter of the United Nations — available on the Internet at <a href="http://www.un.org/aboutun/charter/">http://www.un.org/aboutun/charter/</a> — and convert it into an OEB publication in the same step-by-step manner you would use with your own publication, or one you are converting. You can find the finished product at <a href="http://www.globalmentor.com/bookstore/search?text=un+charter">http://www.globalmentor.com/bookstore/search?text=un+charter</a>.</p>
+
+<p>It's best to first take a broad look of how the work is organized, so that we can correctly model its structure using OEB elements. In general, the UN Charter is organized in the following hierarchy:</p>
+
+<ul>
+ <li>Charter of the United Nations<br />
+ <ul>
+ <li>Chapters<br />
+ <ul>
+ <li>Articles</li>
+ </ul>
+ </li>
+ </ul>
+ </li>
+</ul>
+
+<p>Since OEB, being modeled so closely after HTML, has no concept of hierarchical divisions, we'll divide the UN Charter using whatever method we feel appropriate. While we could certainly put the entire Charter into one OEB document, it will probably be easier for us to keep track of things if we use several OEB document files. We'll place each chapter and all its article into a separate OEB document file, and do the same with the Introductory Note and the Preamble.</p>
+
+<p>Without specific elements to represent hierarchical divisions, we'll use own arbitrary method of representing headings within each division. There are a number of ways the division headings could be represented, none really being any better than the others, so we'll choose the following representation:</p>
+
+<ul>
+ <li><strong><code><h1></code></strong> Title of entire UN Charter.</li>
+ <li><strong><code><h2></code></strong> Title of each chapter.</li>
+ <li><strong><code><h3></code></strong> Title of each article.</li>
+</ul>
+
+<h3 id="uncharterchapter2">UN Charter Chapter 2: <code>chapter2.html</code></h3>
+
+<p>Since we're using separate document files for each chapter, this makes it easy to analyze different parts of the Charter separately. Although it might seem strange that we're not starting from the beginning, it's probably best to first jump into the midst of the document and see how the "mundane" structures will be implemented; we can look at the "Introductory Note", "Preamble", and trimmings such as a table of contents later, after you're comfortable with producing more common OEB elements.</p>
+
+<p>The second chapter of the UN charter begins with the chapter name and title, then proceeds with each separate article title and the article's contents:</p>
+
+<blockquote>
+<p>CHAPTER II</p>
+<p>MEMBERSHIP</p>
+<p>Article 3</p>
+<p>The original Members of the United Nations shall be the states which, having participated in the United Nations Conference on International Organization at San Francisco, or having previously signed the Declaration by United Nations of 1 January 1942, sign the present Charter and ratify it in accordance with Article 110.</p>
+<p>Article 4</p>
+<p>1. Membership in the United Nations is open to all other peace-loving states which accept the obligations contained in the present Charter and, in the judgment of the Organization, are able and willing to carry out these obligations.</p>
+<p>2. The admission of any such state to membership in the United Nations will be effected by a decision of the General Assembly upon the recommendation of the Security Council.</p>
+<p><em>. . .</em></p>
+</blockquote>
+
+<p>We've already decided to represent the chapter title using the <code><h2></code> element, and the title for each article using the <code><h3></code> element. After this is done, the first part of our converted text looks like this:</p>
+
+<blockquote>
+ <code><h2></code>Chapter II: Membership<code></h2></code><br />
+ <code><h3></code>Article 3<code></h3></code>
+</blockquote>
+
+<p>The text of "Article 3", being a simple paragraph, will simply go inside a <code><p></code> element:</p>
+
+<blockquote>
+ <code><h2></code>Chapter II: Membership<code></h2></code><br />
+ <code><h3></code>Article 3<code></h3></code><br />
+ <code><p></code>The original Members of the United Nations shall be the states which, having participated in the United Nations Conference on International Organization at San Francisco, or having previously signed the Declaration by United Nations of 1 January 1942, sign the present Charter and ratify it in accordance with Article 110.<code></p></code>
+</blockquote>
+
+<p>The title of "Article 4" can obviously be placed inside a <code><h3></code> element, as was "Article 3", but what about the article's contents? While we could simply use two <code><p></code> elements, these two paragraphs are numbered; it would be more appropriate to use an ordered list, with each paragraph appearing inside one of the items in the list:</p>
+
+<blockquote>
+<p><em>. . .</em></p>
+ <code><h3></code>Article 4<code></h3></code><br />
+ <code><ol></code><br />
+ <code><li><p></code>Membership in the United Nations is open to all other peace-loving states which accept the obligations contained in the present Charter and, in the judgment of the Organization, are able and willing to carry out these obligations.<code></p></li></code><br />
+ <code><li><p></code>The admission of any such state to membership in the United Nations will be effected by a decision of the General Assembly upon the recommendation of the Security Council.<code></p></li></code><br />
+ <code></ol></code>
+</blockquote>
+
+<p>Note that we remove the literal numbers in each paragraph; the <code><ol></code> element combined with the <code><li></code> elements will add the correct numbers automatically when the book is displayed.</p>
+
+<p>Markup added to articles five and six will be identical to that added to the first article. The last step is even more important than the others: add the <code><body></code> element and the other required OEB document markup. The resulting document file <code>chapter2.html</code> appears below:</p>
+
+<blockquote>
+<code><?xml version='1.0'?></code><br />
+<code><!DOCTYPE html PUBLIC "+//ISBN 0-9673008-1-9//DTD OEB 1.0.1 Document//EN" "http://openebook.org/dtds/oeb-1.0.1/oebdoc101.dtd"></code><br />
+<code><html></code><br />
+<code><body></code><br />
+ <code><h2></code>Chapter II: Membership<code></h2></code><br />
+ <code><h3></code>Article 3<code></h3></code><br />
+ <code><p></code>The original Members of the United Nations shall be the states which, having participated in the United Nations Conference on International Organization at San Francisco, or having previously signed the Declaration by United Nations of 1 January 1942, sign the present Charter and ratify it in accordance with Article 110.<code></p></code><br />
+ <code><h3></code>Article 4<code></h3></code><br />
+ <code><ol></code><br />
+ <code><li><p></code>Membership in the United Nations is open to all other peace-loving states which accept the obligations contained in the present Charter and, in the judgment of the Organization, are able and willing to carry out these obligations.<code></p></li></code><br />
+ <code><li><p></code>The admission of any such state to membership in the United Nations will be effected by a decision of the General Assembly upon the recommendation of the Security Council.<code></p></li></code><br />
+ <code></ol></code>
+ <code><h3></code>Article 5<code></h3></code><br />
+ <code><p></code>A Member of the United Nations against which preventive or enforcement action has been taken by the Security Council may be suspended from the exercise of the rights and privileges of membership by the General Assembly upon the recommendation of the Security Council. The exercise of these rights and privileges may be restored by the Security Council.<code></p></code><br />
+ <code><h3></code>Article 6<code></h3></code><br />
+ <code><p></code>A Member of the United Nations which has persistently violated the Principles contained in the present Charter may be expelled from the Organization by the General Assembly upon the recommendation of the Security Council.<code></p></code><br />
+<code></body></code><br />
+<code></html></code>
+</blockquote>
+
+<p>When this chapter is displayed, here's how it will appear:</p>
+
+<blockquote>
+ <h2>Chapter II: Membership</h2>
+ <h3>Article 3</h3>
+ <p>The original Members of the United Nations shall be the states which, having participated in the United Nations Conference on International Organization at San Francisco, or having previously signed the Declaration by United Nations of 1 January 1942, sign the present Charter and ratify it in accordance with Article 110.</p>
+ <h3>Article 4</h3>
+ <ol>
+ <li><p>Membership in the United Nations is open to all other peace-loving states which accept the obligations contained in the present Charter and, in the judgment of the Organization, are able and willing to carry out these obligations.</p></li>
+ <li><p>The admission of any such state to membership in the United Nations will be effected by a decision of the General Assembly upon the recommendation of the Security Council.</p></li>
+ </ol>
+ <h3>Article 5</h3>
+ <p>A Member of the United Nations against which preventive or enforcement action has been taken by the Security Council may be suspended from the exercise of the rights and privileges of membership by the General Assembly upon the recommendation of the Security Council. The exercise of these rights and privileges may be restored by the Security Council.</p>
+ <h3>Article 6</h3>
+ <p>A Member of the United Nations which has persistently violated the Principles contained in the present Charter may be expelled from the Organization by the General Assembly upon the recommendation of the Security Council.</p>
+</blockquote>
+
+<h3 id="uncharterchapter3">UN Charter Chapter 3: <code>chapter3.html</code></h3>
+
+<p>After applying markup to the second chapter of the UN Charter, doing the same for the first chapter is straightforward; we'll therefore examine the following chapter, chapter three:</p>
+
+
+<blockquote>
+<p>CHAPTER III</p>
+<p>ORGANS</p>
+<p>Article 7</p>
+<p>1. There are established as the principal organs of the United Nations:<br />
+a General Assembly<br />
+a Security Council<br />
+an Economic and Social Council<br />
+a Trusteeship Council<br />
+an International Court of Justice<br />
+and a Secretariat.
+</p>
+<p>2. Such subsidiary organs as may be found necessary may be established in accordance with the present Charter.</p>
+<p>Article 8</p>
+<p>The United Nations shall place no restrictions on the eligibility of men and women to participate in any capacity and under conditions of equality in its principal and subsidiary organs.</p>
+</blockquote>
+
+<p>Since we've already established a consistent way to use heading elements, the chapter and article titles can be converted as before:</p>
+
+<blockquote>
+ <code><h2></code>Chapter III: Organs<code></h2></code><br />
+ <code><h3></code>Article 7<code></h3></code><br />
+ <p><em>. . .</em></p>
+</blockquote>
+
+<p>Similar to Chapter II, Article 4, the individual items in Chapter II, Article 7 are numbered (ordered) items in a list. We'll therefore begin the text as follows:</p>
+
+<blockquote>
+ <p><em>. . .</em></p>
+ <code><ol></code><br />
+ <code><li><p></code>There are established as the principal organs of the United Nations:<code></p></li></code><br />
+ <p><em>. . .</em></p>
+</blockquote>
+
+<p>At this point there seems to be a problem: The first listed item, beginning with "There are established...," itself contains a list of items, including "a General Assembly," "a Security Council," etc. These items are unordered (that is, they have no number beside them), but they represent a list nonetheless. It seems as if the first list item itself contains a list.</p>
+
+<p>These <dfn>nested lists</dfn> present no problem any more than common nested elements. They do require that you take special care in making sure which list elements appear in which other elements. We should first decide which type of list element to use for the list of "principal organs." As before, we'll present each of these items using the <code><li></code> tag. Together, these tags go inside an enclosing list element, but these particular items shouldn't be listed in any particular order; more precisely, we don't want these items to be represented with numbers beside them. We'll therefore use an unordered list <code><ul></code> instead of an ordered list <code><ul></code>.</p>
+
+<p>We'll therefore put the <code><li></code> list items of the unordered list <code><ui></code> inside the first <code><li></code> list item of the ordered list <code><ol></code>. Looking at the finished product should help to understand how this works:</p>
+
+<blockquote>
+ <code><h2></code>Chapter III: Organs<code></h2></code><br />
+ <code><h3></code>Article 7<code></h3></code><br />
+ <code><ol></code><br />
+ <code><li><p></code>There are established as the principal organs of the United Nations:<code></p></code><br />
+ <blockquote>
+ <code><ul></code><br />
+ <code><li></code>a General Assembly<code></li></code><br />
+ <code><li></code>a Security Council<code></li></code><br />
+ <code><li></code>an Economic and Social Council<code></li></code><br />
+ <code><li></code>a Trusteeship Council<code></li></code><br />
+ <code><li></code>an International Court of Justice<code></li></code><br />
+ <code><li></code>and a Secretariat.<code></li></code><br />
+ <code></ul></code>
+ </blockquote>
+ <code></li></code>
+ <p><em>. . .</em></p>
+</blockquote>
+
+<p>Notice that the ending tag <code></li></code> of the first item in the ordered list comes <em>after</em> the end of the entire unordered list <code><ul></code>. This means that the entire unordered list <code><ul></code> is actually part of one list item element: the first list item in the ordered list <code><ol></code></p>
+
+<p>We're still not finished with Article 7; we still must add the second item, beginning with, "Such subsidiary organs...:"</p>
+
+<blockquote>
+ <code><h2></code>Chapter III: Organs<code></h2></code><br />
+ <code><h3></code>Article 7<code></h3></code><br />
+ <code><ol></code><br />
+ <code><li><p></code>There are established as the principal organs of the United Nations:<code></p></code><br />
+ <blockquote>
+ <code><ul></code>
+ <code><li></code>a General Assembly<code></li></code><br />
+ <code><li></code>a Security Council<code></li></code><br />
+ <code><li></code>an Economic and Social Council<code></li></code><br />
+ <code><li></code>a Trusteeship Council<code></li></code><br />
+ <code><li></code>an International Court of Justice<code></li></code><br />
+ <code><li></code>and a Secretariat.<code></li></code><br />
+ <code></ul></code>
+ </blockquote>
+ <code></li></code><br />
+ <code><li><p></code>Such subsidiary organs as may be found necessary may be established in accordance with the present Charter.<code></p></li></code><br />
+ <code></ol></code>
+</blockquote>
+
+<p>The following article, Article 8, which ends this chapter of the UN Charter, is quite simple structurally. As with any OEB document file, we'll also need to add the enclosing <code><html></code> and <code><body> elements:</code></p>
+
+<blockquote>
+<code><?xml version='1.0'?></code><br />
+<code><!DOCTYPE html PUBLIC "+//ISBN 0-9673008-1-9//DTD OEB 1.0.1 Document//EN" "http://openebook.org/dtds/oeb-1.0.1/oebdoc101.dtd"></code><br />
+<code><html></code><br />
+<code><body></code><br />
+ <code><h2></code>Chapter III: Organs<code></h2></code><br />
+ <code><h3></code>Article 7<code></h3></code><br />
+ <code><ol></code><br />
+ <code><li><p></code>There are established as the principal organs of the United Nations:<code></p></code><br />
+ <blockquote>
+ <code><ul></code>
+ <code><li></code>a General Assembly<code></li></code><br />
+ <code><li></code>a Security Council<code></li></code><br />
+ <code><li></code>an Economic and Social Council<code></li></code><br />
+ <code><li></code>a Trusteeship Council<code></li></code><br />
+ <code><li></code>an International Court of Justice<code></li></code><br />
+ <code><li></code>and a Secretariat.<code></li></code><br />
+ <code></ul></code>
+ </blockquote>
+ <code></li></code><br />
+ <code><li><p></code>Such subsidiary organs as may be found necessary may be established in accordance with the present Charter.<code></p></li></code><br />
+ <code></ol></code><br />
+ <code><h3></code>Article 8<code></h3></code><br />
+ <code><p></code>The United Nations shall place no restrictions on the eligibility of men and women to participate in any capacity and under conditions of equality in its principal and subsidiary organs.<code></p></code><br />
+<code></body></code><br />
+<code></html></code>
+</blockquote>
+
+<p>The chapter will then appear like this when it's displayed:</p>
+
+<blockquote>
+ <h2>Chapter III: Organs</h2>
+ <h3>Article 7</h3>
+ <ol>
+ <li><p>There are established as the principal organs of the United Nations:</p>
+ <ul>
+ <li>a General Assembly</li>
+ <li>a Security Council</li>
+ <li>an Economic and Social Council</li>
+ <li>a Trusteeship Council</li>
+ <li>an International Court of Justice</li>
+ <li>and a Secretariat.</li>
+ </ul>
+ </li>
+ <li><p>Such subsidiary organs as may be found necessary may be established in accordance with the present Charter.</p></li>
+ </ol>
+ <h3>Article 8</h3>
+ <p>The United Nations shall place no restrictions on the eligibility of men and women to participate in any capacity and under conditions of equality in its principal and subsidiary organs.</p>
+</blockquote>
+
+<h3 id="uncharterchapter1">UN Charter Chapter 1: <code>chapter1.html</code></h3>
+
+<p>Now that we've examined chapters two and three, we can return to Chapter One. At first the structure of the content looks relatively straightforward compared to the chapters we've already examined.</p>
+
+<blockquote>
+<p>CHAPTER I</p>
+<p>PURPOSES AND PRINCIPLES</p>
+<p>Article 1</p>
+<p>The Purposes of the United Nations are:</p>
+<p><em>. . .</em></p>
+<p>Article 2</p>
+<p>The Organization and its Members, in pursuit of the Purposes stated in Article 1, shall act in accordance with the following Principles.</p>
+<p><em>. . .</em></p>
+</blockquote>
+
+<p>You should be able to easily mark up the information using the OEB publication structure, resulting in something similar to the following:</p>
+
+<blockquote>
+ <code><h2></code>Chapter I: Purposes and Principles<code></h2></code><br />
+ <code><h3></code>Article 1<code></h3></code><br />
+ <code><p></code>The Purposes of the United Nations are:<code></p></code><br />
+ <p><em>. . .</em></p><br />
+ <code><h3></code>Article 2<code></h3></code><br />
+ <code><p></code>The Organization and its Members, in pursuit of the Purposes stated in Article 1, shall act in accordance with the following Principles.<code></p></code><br />
+ <p><em>. . .</em></p>
+</blockquote>
+
+<p>It is at this point that the power of OEB can be put to use to store information within the document. Since these are the first places that the UN <dfn>Purposes</dfn> and <dfn>Principles</dfn> are being defined, we can make good use of the <code><dfn></code> element to indicate this:</p>
+
+<blockquote>
+ <code><p></code>The <code><dfn></code>Purposes<code></dfn></code> of the United Nations are:<code></p></code><br />
+ <p><em>. . .</em></p><br />
+ <code><p></code>The Organization and its Members, in pursuit of the Purposes stated in Article 1, shall act in accordance with the following <code><dfn></code>Principles<code></dfn></code>.<code></p></code><br />
+ <p><em>. . .</em></p>
+</blockquote>
+
+<p>Adding the <code><dfn></code> tag encodes meaning into the document, explicitly stating that these two concepts are being defined for the first time. We can go one step further and mark these definitions with anchors, in case we want to refer to these specific definitions later in the document (remember that, instead of using actual <code><a></code> elements for anchors, we can simply add <code>id</code> attributes to the target elements):</p>
+
+<blockquote>
+ <code><p></code>The <code><dfn id="purposesDefinition"></code>Purposes<code></dfn></code> of the United Nations are:<code></p></code><br />
+ <p><em>. . .</em></p><br />
+ <code><p></code>The Organization and its Members, in pursuit of the Purposes stated in Article 1, shall act in accordance with the following <code><dfn id="principlesDefinition"></code>Principles<code></dfn></code>.<code></p></code><br />
+ <p><em>. . .</em></p>
+</blockquote>
+
+<p>In fact, it's a good idea if we place anchors on every heading in the document so that the respective sections can be linked to later. For example, adding anchors to the sections of this chapter results in the markup below. (If we were to use actual anchor elements for anchors, we would place the anchor element, <code><a></code>, inside the heading element, <code><h2></code>. This order cannot be reversed, for the same reason that the <code><p></code> element cannot go inside an <code><em></code> element: inline elements must go inside block elements, and not vice-versa. Here we don't even use anchor elements at all, but simply add <code>id</code> attributes to the <code><h2></code> and <code><h3></code> elements.)</p>
+
+<blockquote>
+ <code><h2 id="chapter1"></code>Chapter I: Purposes and Principles<code></h2></code><br />
+ <code><h3 id="article1"></code>Article 1<code></h3></code><br />
+ <code><p></code>The Purposes of the United Nations are:<code></p></code><br />
+ <p><em>. . .</em></p><br />
+ <code><h3 id="article2"></code>Article 2<code></h3></code><br />
+ <code><p></code>The Organization and its Members, in pursuit of the Purposes stated in Article 1, shall act in accordance with the following Principles.<code></p></code><br />
+ <p><em>. . .</em></p>
+</blockquote>
+
+<p></p>
+
+<p>Assuming we add anchor elements to every division in the entire UN Charter, and assuming Chapter VII is placed in a file named <code>chapter7.html</code>, we can provide links from this chapter. The last principle in Article 2 states that "this principle shall not prejudice the application of enforcement measures under Chapter Vll."; with anchor tags appropriately placed throughout our documents, we can provide a direct hypertext link to the chapter by using the anchor element <code><a></code> like this:</p>
+
+<blockquote>
+ <code><p></code>...this principle shall not prejudice the application of enforcement measures under <code><a href="chapter7.html#chapter7"></code>Chapter Vll<code></a></code>.<code><p></code>
+</blockquote>
+
+<p>Notice that we've not only linked to the file, <code>chapter7.html</code>, we've also provided the ID of the anchor, <code>#chapter7</code>, which marks the beginning of the actual chapter in the file. Since Chapter 7 is at the beginning of <code>chapter7.html</code>, we could have simply linked to the document file itself: <code><a href="chapter7.html"></code>. However, in many cases the target anchor within the file will be important as well when the anchor is not at the beginning of the document — in the case of articles, for instance.</p>
+
+<h3 id="uncharterintro">UN Charter Introductory Note: <code>intro.html</code></h3>
+
+<p>Moving back another step to the UN Charter's Introductory Note provides more examples of linking, provided the appropriate anchor elements have been placed at the start of every chapter and article:</p>
+
+<blockquote>
+ <code><h2 id="chapter1"></code>Introductory Note<code></h2></code><br />
+ <code><p></code>The Charter of the United Nations was signed on 26 June 1945, in San Francisco, at the conclusion of the United Nations Conference on International Organization, and came into force on 24 October 1945. The Statute of the International Court of Justice is an integral part of the Charter.<code></p></code><br />
+ <code><p></code>Amendments to <code><a href="chapter5.html#article23"></code>Articles 23<code></a></code>, <code><a href="chapter5.html#article27"></code>27<code></a></code> and <code><a href="chapter10.html#article61"></code>61<code></a></code> of the Charter were adopted by the General Assembly on 17 December 1963 and came into force on 31 August 1965. A further amendment to <code><a href="chapter10.html#article61"></code>Article 61<code></a></code> was adopted by the General Assembly on 20 December 1971, and came into force on 24 September 1973. An amendment to <code><a href="chapter18.html#article109"></code>Article 109<code></a></code>, adopted by the General Assembly on 20 December 1965, came into force on 12 June 1968.<code></p></code><br />
+ <p><em>. . .</em></p>
+</blockquote>
+
+<p>Note that we had to first check and see in which document files the articles appear before we could link to them.</p>
+
+<h3 id="unchartertoc">Table of Contents: <code>toc.html</code></h3>
+
+<p>The first version of the Open eBook Publication Structure has no specific elements for creating a table of contents; this means that, outside of creating a new set of elements specifically for a table of contents, we'll be forced to use generic elements to do the job. Here we'll use the standard elements to create a table of contents inside a normal OEB document.</p>
+
+<p>A table of contents is usually one of the last things you'll add to your OEB publication, for good reason: not only does it provide a hierarchical view of the structure of the publication, it provides links to each one of publication sections. You may, however, elect to create a table of contents early and use it as a working design of your entire publication, if you are writing the work from scratch; you'd still have to wait until the document was finished to test all of the hyperlinks, though.</p>
+
+<p>The table of contents therefore has two elements: its reflection of the publication's structure, as well as hyperlinks to parts of the publication. Reflecting the work's structure can be accomplished in several ways; here we'll use unordered list <code><ol></code> elements. An OEB document displaying the top-level UN Charter structure (that is, the level containing the Introductory Note, Preamble, and chapters), might be marked up like this:</p>
+
+<blockquote>
+<code><ul></code><br />
+ <code><li></code>Introductory Note<code></li></code><br />
+ <code><li></code>Preamble<code></li></code><br />
+ <code><li></code>Chapter I: Purposes and Principles<code></li></code><br />
+ <code><li></code>Chapter II: Membership<code></li></code><br />
+ <em>. . .</em><br />
+<code></ul></code>
+</blockquote>
+
+<p>This would appear something like this:</p>
+
+<blockquote>
+<ul>
+ <li>Introductory Note</li>
+ <li>Preamble</li>
+ <li>Chapter I: Purposes and Principles</li>
+ <li>Chapter II: Membership</li>
+ <li><em>. . .</em></li>
+</ul>
+</blockquote>
+
+<p>Displaying the second level of organization, the level containing the articles, requires a bit more concentration on details. It's evident that each list of articles that appear within a chapter will be marked up using a separate list element, but it's important to remember that all of these lists are actually sub-lists of the chapter item in which they appear. Each chapter item is enclosed within a list item <code><li></code><em>...</em><code></li></code> beginning and ending tag pair. Each sub-list of articles must appear <em>inside</em> that list item's beginning and ending tags. OEB's content model does not allow lists to appear between list items; sub-lists must appear inside the list item to which they belong.</p>
+
+<blockquote>
+<code><ul></code><br />
+ <code><li></code>Introductory Note<code></li></code><br />
+ <code><li></code>Preamble<code></li></code><br />
+ <code><li></code>Chapter I: Purposes and Principles<br />
+ <blockquote>
+ <code><ul></code><br />
+ <code><li></code>Article 1<code></li></code><br />
+ <code><li></code>Article 2<code></li></code><br />
+ <code></ul></code>
+ </blockquote>
+ <code></li></code><br />
+ <code><li></code>Chapter II: Membership<br />
+ <blockquote>
+ <code><ul></code><br />
+ <code><li></code>Article 3<code></li></code><br />
+ <code><li></code>Article 4<code></li></code><br />
+ <code><li></code>Article 5<code></li></code><br />
+ <code><li></code>Article 6<code></li></code><br />
+ <code></ul></code>
+ </blockquote>
+ <code></li></code><br />
+ <em>. . .</em><br />
+<code></ul></code>
+</blockquote>
+
+<p>When displayed, the table of contents would now appear like this:</p>
+
+<blockquote>
+<ul>
+ <li>Introductory Note</li>
+ <li>Preamble</li>
+ <li>Chapter I: Purposes and Principles
+ <ul>
+ <li>Article 1</li>
+ <li>Article 2</li>
+ </ul>
+ </li>
+ <li>Chapter II: Membership
+ <ul>
+ <li>Article 3</li>
+ <li>Article 4</li>
+ <li>Article 5</li>
+ <li>Article 6</li>
+ </ul>
+ </li>
+ <li><em>. . .</em></li>
+</ul>
+</blockquote>
+
+<p>That's all we need to do regarding structure, since the UN Charter has only these levels of hierarchy. The other issue to address is hyperlinking: each item in the table of contents must link to the respective section of the publication. If that section lies somewhere in the middle of the physical document file in which it appears, we must have first provided anchors with unique IDs for the table of contents to link to.</p>
+
+<p>After adding hyperlinks, our table of contents is basically finished:</p>
+
+<blockquote>
+<code><ul></code><br />
+ <code><li><a href="intro.html"></code>Introductory Note<code></a></li></code><br />
+ <code><li><a href="preamble.html"></code>Preamble<code></a></li></code><br />
+ <code><li><a href="chapter1.html"></code>Chapter I: Purposes and Principles</a><br />
+ <blockquote>
+ <code><ul></code><br />
+ <code><li><a href="chapter1.html#article1"></code>Article 1<code></a></li></code><br />
+ <code><li><a href="chapter1.html#article2"></code>Article 2<code></a></li></code><br />
+ <code></ul></code>
+ </blockquote>
+ <code></li></code><br />
+ <code><li><a href="chapter2.html"></code>Chapter II: Membership</a><br />
+ <blockquote>
+ <code><ul></code><br />
+ <code><li><a href="chapter2.html#article3"></code>Article 3<code></a></li></code><br />
+ <code><li><a href="chapter2.html#article4"></code>Article 4<code></a></li></code><br />
+ <code><li><a href="chapter2.html#article5"></code>Article 5<code></a></li></code><br />
+ <code><li><a href="chapter2.html#article6"></code>Article 6<code></a></li></code><br />
+ <code></ul></code>
+ </blockquote>
+ <code></li></code><br />
+ <em>. . .</em><br />
+<code></ul></code>
+</blockquote>
+
+<h3 id="uncharterpackage">UN Charter Package File: <code>uncharter.opf</code></h3>
+
+<p>From the examples covered so far, marking up the rest of the UN Charter should be a simple task. There's still one more file we need to create, however, to tie all the pieces together and make our series of OEB documents into a complete OEB publication: the OEB package file.</p>
+
+<p>Creating the package file, as you know by now, requires less thinking and planning than cutting, pasting, and altering to match the particular publication you're working with. In this example, we'll simply start from the top of the file and work our way downwards — although we'll include ending tags when appropriate, which may occur at the end of the file. The first part should be familiar — it appears at the top of every package file:</p>
+
+<blockquote>
+<code><?xml version='1.0'?></code><br />
+<code><!DOCTYPE package PUBLIC "+//ISBN 0-9673008-1-9//DTD OEB 1.0.1 Package//EN" "http://openebook.org/dtds/oeb-1.0.1/oebpkg101.dtd"></code><br />
+<code><package unique-identifier="uncharterpackage"></code>
+
+ <blockquote>
+ <em>. . .</em>
+ </blockquote>
+
+<code></package></code>
+</blockquote>
+
+<p>Inside the <code><package></code> element, we'll place the metadata. In particular, we'll include the title of the publication (<em>Charter of the United Nations</em>) and we'll create our own type of "charter", although this particular type of document has not been standardized.</p>
+
+<p>The <code><dc:Identifier></code> element requires particular attention. Notice that we've given the <code>id</code> attribute the value <code>"uncharterpackage"</code> to match the <code>unique-identifier</code> attribute in the earlier <code><package></code> element. Furthermore, we've used a <code>scheme</code> of <code>"url"</code>, although this value is not standard. It would be better to include a <code>scheme</code> of <code>ISBN</code> or some other similar identifier more useful to third parties such as bookstores and libraries.</p>
+
+<p>There are two <code><dc:Creator></code> elements; one specifies an author (<code>"aut"</code>) of <code>United Nations</code> and a book publisher (<code>"bkp"</code>) of <code>Mentor Publishing</code>. The <code><dc:Date</code> element contains the date this package file was created, July 11, 2001.</p>
+
+<p>Three arbitrary subjects have been added using the <code><ds:Subject></code> element: <code>United Nations</code>, <code>Historical Documents</code>, and <code>International Politics</code>. Lastly, a <code><dc:Source></code> element shows that we originally found the content at <code><a href="http://www.un.org/aboutun/charter/">http://www.un.org/aboutun/charter/</a></code>.</p>
+
+<blockquote>
+ <code><dc-metadata xmlns:dc="http://purl.org/dc/elements/1.0/" xmlns:oebpackage="http://openebook.org/namespaces/oeb-package/1.0/"></code><br />
+ <code><dc:Title></code>Charter of the United Nations<code></dc:Title></code><br />
+ <code><dc:Type></code>charter<code></dc:Type></code><br />
+ <code><dc:Identifier id="uncharterpackage" scheme="url"></code>http://www.un.org/aboutun/charter/<code></dc:Identifier></code><br />
+ <code><dc:Creator role="aut"></code>United Nations<code></dc:Creator></code><br />
+ <code><dc:Creator role="bkp"></code>Mentor Publishing<code></dc:Creator></code><br />
+ <code><dc:Date></code>2001-07-11<code></dc:Date></code><br />
+ <code><dc:Subject></code>United Nations<code></dc:Subject></code><br />
+ <code><dc:Subject></code>Historical Documents<code></dc:Subject></code><br />
+ <code><dc:Subject></code>International Politics<code></dc:Subject></code><br />
+ <code><dc:Source></code>http://www.un.org/aboutun/charter/<code></dc:Source></code><br />
+ <code></dc-metadata></code>
+</blockquote>
+
+<p>We next need to specify the files which will be included in the publication; this information will appear inside the <code><manifest></code> element. Since our version of the the UN Charter has no images associated with it, each <code><item></code> element in the manifest will represent an OEB document file, with <code>media-type="text/x-oeb1-document"</code>. It doesn't matter what order we present the files, just so we include all the files used in the publication. This includes the table of contents, the introduction, the preamble, and all the chapters, including chapters we haven't listed here.</p>
+
+<blockquote>
+ <code><manifest></code><br />
+ <code><item id="toc" href="toc.html" media-type="text/x-oeb1-document" /></code><br />
+ <code><item id="intro" href="intro.html" media-type="text/x-oeb1-document" /></code><br />
+ <code><item id="preamble" href="preamble.html" media-type="text/x-oeb1-document" /></code><br />
+ <code><item id="chapter1" href="chapter1.html" media-type="text/x-oeb1-document" /></code><br />
+ <code><item id="chapter2" href="chapter2.html" media-type="text/x-oeb1-document" /></code><br />
+ <em>. . .</em><br />
+ <code></manifest></code>
+</blockquote>
+
+<p>It is inside the <code><spine></code> element that we specify the reading order of the documents we listed in the <code><manifest></code> section. The order here is all that's important; having already listed the essential information about each document, we simply reference the unique ID we've assigned each item earlier:</p>
+
+<blockquote>
+ <code><spine></code><br />
+ <code><itemref idref="toc" /></code><br />
+ <code><itemref idref="intro" /></code><br />
+ <code><itemref idref="preamble" /></code><br />
+ <code><itemref idref="chapter1" /></code><br />
+ <code><itemref idref="chapter2" /></code><br />
+ <em>. . .</em><br />
+ <code></spine></code>
+</blockquote>
+
+<p>That's all that OEB requires for a complete OEB publication, and we could at this point read the UN Charter on any OEB-compliant reading system. As an example of optional OEB functionality that we can add to allow future OEB reading systems to manipulate our work in various ways, we'll add a <code><guide></code> element and specify that our table of contents is one of the <dfn>guide</dfn> types recognized by OEB; specifically, it is a <code>"toc"</code>, a table of contents. In short, we're simply identifying a particular document as a table of contents; other types of guides may be found in the <em>Open eBook Publication Structure 1.0.1 Specification</em>.</p>
+
+<p>There is currently no guarantee that a particular OEB reading system will recognize guides, but it's still a good idea to include at least the table of contents. More information on guides and a related concept, <dfn>tours</dfn>, can be found in the <em>Open eBook Publication Structure 1.0 Specification</em>, and will likely be covered in depth in a later edition of this book.</p>
+
+<blockquote>
+ <code><guide></code><br />
+ <code><reference type="toc" title="Table of Contents" href="toc.html" /></code><br />
+ <code></guide></code>
+</blockquote>
+
+<p>At this point, we've finished the package file, completing our publication. Assuming the rest of the chapters have been marked up and included, the group of files can be presented to an OEB-compliant reading system and, based upon the function of the reading system, either be presented to a user or passed along the chain to another piece of software and/or hardware for further manipulation. The complete package file, <code>uncharter.opf</code>, is presented below:</p>
+
+
+<blockquote>
+<code><?xml version='1.0'?></code><br />
+<code><!DOCTYPE package PUBLIC "+//ISBN 0-9673008-1-9//DTD OEB 1.0.1 Package//EN" "http://openebook.org/dtds/oeb-1.0.1/oebpkg101.dtd"></code><br />
+<code><package unique-identifier="uncharterpackage"></code><br />
+
+ <blockquote>
+ <code><dc-metadata xmlns:dc="http://purl.org/dc/elements/1.0/" xmlns:oebpackage="http://openebook.org/namespaces/oeb-package/1.0/"></code><br />
+ <code><dc:Title></code>Charter of the United Nations<code></dc:Title></code><br />
+ <code><dc:Type></code>charter<code></dc:Type></code><br />
+ <code><dc:Identifier id="uncharterpackage" scheme="url"></code>http://www.un.org/aboutun/charter/<code></dc:Identifier></code><br />
+ <code><dc:Creator role="aut"></code>United Nations<code></dc:Creator></code><br />
+ <code><dc:Creator role="bkp"></code>Mentor Publishing<code></dc:Creator></code><br />
+ <code><dc:Date></code>2001-07-11<code></dc:Date></code><br />
+ <code><dc:Subject></code>United Nations<code></dc:Subject></code><br />
+ <code><dc:Subject></code>Historical Documents<code></dc:Subject></code><br />
+ <code><dc:Subject></code>International Politics<code></dc:Subject></code><br />
+ <code><dc:Source></code>http://www.un.org/aboutun/charter/<code></dc:Source></code><br />
+ <code></dc-metadata></code>
+ </blockquote>
+
+ <blockquote>
+ <code><manifest></code><br />
+ <code><item id="toc" href="toc.html" media-type="text/x-oeb1-document" /></code><br />
+ <code><item id="intro" href="intro.html" media-type="text/x-oeb1-document" /></code><br />
+ <code><item id="preamble" href="preamble.html" media-type="text/x-oeb1-document" /></code><br />
+ <code><item id="chapter1" href="chapter1.html" media-type="text/x-oeb1-document" /></code><br />
+ <code><item id="chapter2" href="chapter2.html" media-type="text/x-oeb1-document" /></code><br />
+ <code><item id="chapter3" href="chapter3.html" media-type="text/x-oeb1-document" /></code><br />
+ <code><item id="chapter4" href="chapter4.html" media-type="text/x-oeb1-document" /></code><br />
+ <code><item id="chapter5" href="chapter5.html" media-type="text/x-oeb1-document" /></code><br />
+ <code><item id="chapter6" href="chapter6.html" media-type="text/x-oeb1-document" /></code><br />
+ <code><item id="chapter7" href="chapter7.html" media-type="text/x-oeb1-document" /></code><br />
+ <code><item id="chapter8" href="chapter8.html" media-type="text/x-oeb1-document" /></code><br />
+ <code><item id="chapter9" href="chapter9.html" media-type="text/x-oeb1-document" /></code><br />
+ <code><item id="chapter10" href="chapter10.html" media-type="text/x-oeb1-document" /></code><br />
+ <code><item id="chapter11" href="chapter11.html" media-type="text/x-oeb1-document" /></code><br />
+ <code><item id="chapter12" href="chapter12.html" media-type="text/x-oeb1-document" /></code><br />
+ <code><item id="chapter13" href="chapter13.html" media-type="text/x-oeb1-document" /></code><br />
+ <code><item id="chapter14" href="chapter14.html" media-type="text/x-oeb1-document" /></code><br />
+ <code><item id="chapter15" href="chapter15.html" media-type="text/x-oeb1-document" /></code><br />
+ <code><item id="chapter16" href="chapter16.html" media-type="text/x-oeb1-document" /></code><br />
+ <code><item id="chapter17" href="chapter17.html" media-type="text/x-oeb1-document" /></code><br />
+ <code><item id="chapter18" href="chapter18.html" media-type="text/x-oeb1-document" /></code><br />
+ <code><item id="chapter19" href="chapter19.html" media-type="text/x-oeb1-document" /></code><br />
+ <code></manifest></code>
+ </blockquote>
+
+ <blockquote>
+ <code><spine></code><br />
+ <code><itemref idref="toc" /></code><br />
+ <code><itemref idref="intro" /></code><br />
+ <code><itemref idref="preamble" /></code><br />
+ <code><itemref idref="chapter1" /></code><br />
+ <code><itemref idref="chapter2" /></code><br />
+ <code><itemref idref="chapter3" /></code><br />
+ <code><itemref idref="chapter4" /></code><br />
+ <code><itemref idref="chapter5" /></code><br />
+ <code><itemref idref="chapter6" /></code><br />
+ <code><itemref idref="chapter7" /></code><br />
+ <code><itemref idref="chapter8" /></code><br />
+ <code><itemref idref="chapter9" /></code><br />
+ <code><itemref idref="chapter10" /></code><br />
+ <code><itemref idref="chapter11" /></code><br />
+ <code><itemref idref="chapter12" /></code><br />
+ <code><itemref idref="chapter13" /></code><br />
+ <code><itemref idref="chapter14" /></code><br />
+ <code><itemref idref="chapter15" /></code><br />
+ <code><itemref idref="chapter16" /></code><br />
+ <code><itemref idref="chapter17" /></code><br />
+ <code><itemref idref="chapter18" /></code><br />
+ <code><itemref idref="chapter19" /></code><br />
+ <code></spine></code>
+ </blockquote>
+
+ <blockquote>
+ <code><guide></code><br />
+ <code><reference type="toc" title="Table of Contents" href="toc.html" /></code><br />
+ <code></guide></code>
+ </blockquote>
+
+<code></package></code>
+</blockquote>
+
+</body>
+</html>
--- /dev/null
+++ b/lib/ebooks/understandingoeb/foreword.html
@@ -1,0 +1,27 @@
+<?xml version='1.0'?>
+<!DOCTYPE html PUBLIC "+//ISBN 0-9673008-1-9//DTD OEB 1.0.1 Document//EN" "http://openebook.org/dtds/oeb-1.0.1/oebdoc101.dtd">
+<?xml-stylesheet href="understandingoeb.css" type="text/x-oeb1-css"?>
+
+<html>
+<head>
+ <link rel="stylesheet" type="text/x-oeb1-css" href="understandingoeb.css" />
+<title>Understanding OEB Foreword</title>
+ <meta name="author" content="Garret Wilson" />
+ <meta name="copyright" content="Copyright (c) 2000-2001 Garret Wilson. All rights reserved." />
+</head>
+
+<body>
+
+<h2 id="foreword">Foreword</h2>
+
+<p>When Garret told me he was writing this book, I thought "Thank, God!" The world really needs a good book about the Open eBook Publication Structure. And when I read a draft, I was even happier. It's clear and concise, direct and thorough and addresses a crucial audience. The authors of the publication structure did a great job designing and writing the technical specification, but the specification is, well, let's just say it's not gentle prose you'd read at night to relax! It's unforgivingly hard-nosed, technical and (usually!) unambiguous. And that's what a technical specification needs to be. The primary audience for the specification is software developers who are building tools and reading systems, and the
+hyper-concise form is needed for those folks.</p>
+
+<p>But that doesn't help the rest of the world understand what the specification is, what it allows, how it works and how it nails the needs of the eBook world on its head. <em>Understanding OEB</em> tackles this task.</p>
+
+<p><em>David Ornstein</em></p>
+<p><em>President, Open eBook Forum</em></p>
+<p><em>Manager of Planning and Architecture for eReading, Microsoft</em></p>
+
+</body>
+</html>
--- /dev/null
+++ b/lib/ebooks/understandingoeb/preface.html
@@ -1,0 +1,33 @@
+<?xml version='1.0'?>
+<!DOCTYPE html PUBLIC "+//ISBN 0-9673008-1-9//DTD OEB 1.0.1 Document//EN" "http://openebook.org/dtds/oeb-1.0.1/oebdoc101.dtd">
+<?xml-stylesheet href="understandingoeb.css" type="text/x-oeb1-css"?>
+
+<html>
+<head>
+ <link rel="stylesheet" type="text/x-oeb1-css" href="understandingoeb.css" />
+<title>Understanding OEB Preface</title>
+ <meta name="author" content="Garret Wilson" />
+ <meta name="copyright" content="Copyright (c) 2000-2001 Garret Wilson. All rights reserved." />
+</head>
+
+<body>
+
+<h2 id="preface">Preface</h2>
+
+<p>Last night the finishing touches were placed on the <em>Open eBook Publication Structure 1.0.1</em>, a revision of the original specification which had as its purpose the task of clearing up ambiguities, fixing errors, and ensuring that the specification could continue to be useful as the Open eBook Forum produces new specifications for the eBook industry. As the original <em>Open eBook Publication Structure 1.0</em> was produced by the Open eBook Authoring Group (most of whom now make up the new Open eBook Forum), this updated document is the first official specification to be released by the OEBF.</p>
+
+<p>As chair of the maintenance subgroup of the publication structure working group (yes, the OEBF has a more complicated hierarchy than our original group of authors), I was responsible for overseeing the relatively easy task of updating and correcting the existing specification. As it turned out, even such minor changes are never straightforward, with such last-minute issues as corrupted logo image files. I cannot help but feel admiration (and some pity) for Gene Golovchinsky and Jerry Dunietz, who are supervising the development subgroup which is working towards the next major version of the OEB PS: <em>Open eBook Publication Structure 2.0</em></p>
+
+<p>Version 2.0 will certainly require a new "Understanding" book to be written, but the OEBF believes version 1.0.1 to be an unambiguous foundation on which to build today, a foundation that won't render content useless when new versions add new features. From the experience that version 1.0 has brought, it appears the OEB Authoring Group was correct in choosing <em>its</em> foundations: open, standards-based international specifications that can be used by all. It's my wish that this book will allow you to understand the steps you need to take to be one of those who use the specification for your next eBook.</p>
+
+<p>Thanks to Horace Dediu, Dorothea Salo, Merv Matson and Roger Sperberg for all their help in reviewing and proofreading the early drafts. Thanks to Gunter Hille and David Ornstein for their support and encouragment. Scott Oaks and Henry Wong in their <em>Java Threads</em> (O'Reilly, 1999) provided excellent examples of using rhetorical questions in a tutorial. I'm grateful to Garth Conboy for introducing me to the very useful technical term, "Real Soon Now."</p>
+
+<p>All diagrams in this book use the <a href="http://www.uml.org">Unified Modeling Language (UML)</a> and were created using the <a href="http://www.magicdraw.com">MagicDraw UML</a> modeling software.</p>
+
+<p><em>Garret Wilson</em></p>
+<p><em>President, GlobalMentor, Inc.</em></p>
+<p><em><a href="http://www.globalmentor.com">http://www.globalmentor.com</a></em></p>
+<p><em>14 June 2001</em></p>
+
+</body>
+</html>
--- /dev/null
+++ b/lib/ebooks/understandingoeb/title.html
@@ -1,0 +1,26 @@
+<?xml version='1.0'?>
+<!DOCTYPE html PUBLIC "+//ISBN 0-9673008-1-9//DTD OEB 1.0.1 Document//EN" "http://openebook.org/dtds/oeb-1.0.1/oebdoc101.dtd">
+<?xml-stylesheet href="understandingoeb.css" type="text/x-oeb1-css"?>
+
+<html>
+<head>
+ <link rel="stylesheet" type="text/x-oeb1-css" href="understandingoeb.css" />
+<title>Understanding OEB Title Page</title>
+ <meta name="author" content="Garret Wilson" />
+ <meta name="copyright" content="Copyright (c) 2000-2001 Garret Wilson. All rights reserved." />
+</head>
+
+<body>
+
+<h1>Understanding OEB</h1>
+
+<h2>Revised and Updated for OEB PS 1.0.1</h2>
+
+<p>by <a href="mailto:garret@globalmentor.com">Garret Wilson</a></p>
+
+<p>Copyright © 2000-2001 Garret Wilson. All rights reserved.</p>
+
+<p>Published by <a href="http://www.globalmentor.com/publishing/">Mentor Publishing</a>, a division of <a href="http://www.globalmentor.com">GlobalMentor, Inc.</a></p>
+
+</body>
+</html>
--- /dev/null
+++ b/lib/ebooks/understandingoeb/toc.html
@@ -1,0 +1,150 @@
+<?xml version='1.0'?>
+<!DOCTYPE html PUBLIC "+//ISBN 0-9673008-1-9//DTD OEB 1.0.1 Document//EN" "http://openebook.org/dtds/oeb-1.0.1/oebdoc101.dtd">
+<?xml-stylesheet href="understandingoeb.css" type="text/x-oeb1-css"?>
+
+<html>
+<head>
+ <link rel="stylesheet" type="text/x-oeb1-css" href="understandingoeb.css" />
+<title>Understanding OEB Table of Contents</title>
+ <meta name="author" content="Garret Wilson" />
+ <meta name="copyright" content="Copyright (c) 2000-2001 Garret Wilson. All rights reserved." />
+</head>
+
+<body>
+
+<h1>Table of Contents</h1>
+
+<ul>
+ <li><a href="foreword.html">Foreword</a></li>
+ <li><a href="preface.html">Preface</a></li>
+ <li><a href="chapter1.html">1. Defining a Beginning</a>
+ <ul>
+ <li><a href="chapter1.html#definingEBook">Defining "eBook"</a>
+ <ul>
+ <li><a href="chapter1.html#eText">Electronic Book as an "Etext"</a></li>
+ <li><a href="chapter1.html#eBookHype">"eBook" as a Marketing Tool</a></li>
+ <li><a href="chapter1.html#eBookInevitibility">The eBook as Inevitable</a></li>
+ </ul>
+ </li>
+ <li><a href="chapter1.html#oebMeaning">The Meaning of OEB</a></li>
+ <li><a href="chapter1.html#usingOEB">Using OEB</a></li>
+ <li><a href="chapter1.html#review">Review</a>
+ <ul>
+ <li><a href="chapter1.html#summary">Summary</a></li>
+ </ul>
+ </li>
+ </ul>
+ </li>
+ <li><a href="chapter2.html#chapter2">2. Understanding an OEB Publication</a>
+ <ul>
+ <li><a href="chapter2.html#oebdocument">An OEB Document</a>
+ <ul>
+ <li><a href="chapter2.html#needmarkup">The Need for Markup</a></li>
+ <li><a href="chapter2.html#markupalphabetsoup">More Information: Markup Alphabet Soup</a></li>
+ <li><a href="chapter2.html#usingxml">Using XML</a></li>
+ <li><a href="chapter2.html#creatingoebdocument">Creating an OEB Document</a></li>
+ <li><a href="chapter2.html#formattingoebtext">Formatting OEB Text</a></li>
+ </ul>
+ </li>
+ <li><a href="chapter2.html#oebpackage">An OEB Package</a>
+ <ul>
+ <li><a href="chapter2.html#packageelement">The <code><package></code> Element</a></li>
+ <li><a href="chapter2.html#packagemetadata">The Package Metadata</a></li>
+ <li><a href="chapter2.html#packagemanifest">The Package Manifest</a></li>
+ <li><a href="chapter2.html#packagespine">The Package Spine</a></li>
+ </ul>
+ </li>
+ <li><a href="chapter2.html#xmlrepresentdata">Using XML to Represent Data</a></li>
+ <li><a href="chapter2.html#review">Review</a>
+ <ul>
+ <li><a href="chapter2.html#summary">Summary</a></li>
+ <li><a href="chapter2.html#xmlrules">XML Rules</a></li>
+ <li><a href="chapter2.html#oebrules">OEB Rules</a></li>
+ <li><a href="chapter2.html#oebtags">OEB Tags</a></li>
+ </ul>
+ </li>
+ <li><a href="chapter2.html#exampleoebdocument">Completed Example OEB Document (<code>karl.html</code>)</a></li>
+ <li><a href="chapter2.html#exampleoebpackage">Completed Example OEB Package (<code>karl.opf</code>)</a></li>
+ </ul>
+ </li>
+ <li><a href="chapter3.html#chapter3">3. Styles and Style Sheets</a>
+ <ul>
+ <li><a href="chapter3.html#emphasisrevisited">Emphasis Revisited</a></li>
+ <li><a href="chapter3.html#cascadingstylesheets">Cascading Style Sheets (CSS)</a>
+ <ul>
+ <li><a href="chapter3.html#cssvsxsl">More Information: CSS vs. XSL</a></li>
+ <li><a href="chapter3.html#cssselectors">CSS Selectors</a></li>
+ </ul>
+ </li>
+ <li><a href="chapter3.html#linkingstylesheets">Linking to Style Sheets</a>
+ <ul>
+ <li><a href="chapter3.html#linkelement">Linking Style Sheets with the <code><link></code> Element</a></li>
+ <li><a href="chapter3.html#linkxml">Linking Style Sheets with XML</a></li>
+ </ul>
+ </li>
+ <li><a href="chapter3.html#review">Review</a>
+ <ul>
+ <li><a href="chapter3.html#summary">Summary</a></li>
+ <li><a href="chapter3.html#cssproperties">CSS Properties</a></li>
+ </ul>
+ </li>
+ <li><a href="chapter3.html#exampleoebdocument">Completed Example OEB Document with Styles (<code>karl.html</code>)</a></li>
+ <li><a href="chapter3.html#examplestylesheet">Completed Example Style Sheet (<code>karl.css</code>)</a></li>
+ </ul>
+ </li>
+ <li><a href="chapter4.html#chapter4">4. Essential OEB Elements</a>
+ <ul>
+ <li><a href="chapter4.html#inlineelements">Inline Elements</a>
+ <ul>
+ <li><a href="chapter4.html#xmlcontentmodels">More Information: XML Content Models</a></li>
+ <li><a href="chapter4.html#emelement">The <code><em></code> Element</a></li>
+ <li><a href="chapter4.html#strongelement">The <code><strong></code> Element</a></li>
+ <li><a href="chapter4.html#dfnelement">The <code><dfn></code> Element</a></li>
+ <li><a href="chapter4.html#codeelement">The <code><code></code> Element</a></li>
+ <li><a href="chapter4.html#citeelement">The <code><cite></code> Element</a></li>
+ <li><a href="chapter4.html#spanelement">The <code><span></code> Element</a></li>
+ <li><a href="chapter4.html#customelements">More Information: Creating Custom Elements</a></li>
+ <li><a href="chapter4.html#brelement">The <code><br></code> Element</a></li>
+ <li><a href="chapter4.html#aelement">The <code><a></code> Element</a></li>
+ </ul>
+ </li>
+ <li><a href="chapter4.html#blockelements">Block Elements</a>
+ <ul>
+ <li><a href="chapter4.html#pelement">The <code><p></code> Element</a></li>
+ <li><a href="chapter4.html#headingelements">The <code><h1></code>...<code><h6></code> Heading Elements</a></li>
+ <li><a href="chapter4.html#lists">Lists, Ordered (<code><ol></code>) and Unordered (<code><ul></code>)</a></li>
+ <li><a href="chapter4.html#divelement">The <code><div></code> Element</a></li>
+ <li><a href="chapter4.html#centerelement">The <code><center></code> Element (deprecated)</a></li>
+ <li><a href="chapter4.html#blockquoteelement">The <code><blockquote></code> Element</a></li>
+ </ul>
+ </li>
+ </ul>
+ </li>
+ <li><a href="chapter5.html#chapter5">5. Essential OEB Styles</a>
+ <ul>
+ <li><a href="chapter5.html#styleunits">Style Units</a></li>
+ <li><a href="chapter5.html#fontproperties">Font Properties</a>
+ <ul>
+ <li><a href="chapter5.html#fontfamilyproperty">The <code>font-family</code> Property</a></li>
+ <li><a href="chapter5.html#fontsizeproperty">The <code>font-size</code> Property</a></li>
+ <li><a href="chapter5.html#fontstyleproperty">The <code>font-style</code> Property</a></li>
+ <li><a href="chapter5.html#fontweightproperty">The <code>font-weight</code> Property</a></li>
+ <li><a href="chapter5.html#textdecorationproperty">The <code>text-decoration</code> Property</a></li>
+ </ul>
+ </li>
+ </ul>
+ </li>
+ <li><a href="chapter6.html#chapter6">6. Real-World OEB: Charter of the United Nations</a>
+ <ul>
+ <li><a href="chapter6.html#uncharterchapter2">UN Charter Chapter 2: <code>chapter2.html</code></a></li>
+ <li><a href="chapter6.html#uncharterchapter3">UN Charter Chapter 3: <code>chapter3.html</code></a></li>
+ <li><a href="chapter6.html#uncharterchapter1">UN Charter Chapter 1: <code>chapter1.html</code></a></li>
+ <li><a href="chapter6.html#uncharterintro">UN Charter Introductory Note: <code>intro.html</code></a></li>
+ <li><a href="chapter6.html#unchartertoc">Table of Contents: <code>toc.html</code></a></li>
+ <li><a href="chapter6.html#uncharterpackage">UN Charter Package File: <code>uncharter.opf</code></a></li>
+ </ul>
+ </li>
+</ul>
+
+</body>
+</html>
--- /dev/null
+++ b/lib/ebooks/understandingoeb/understandingoeb.css
@@ -1,0 +1,28 @@
+.sidebar, sidebarTitle
+{
+ display: block;
+ background-color: silver;
+}
+
+h1
+{
+ font-family: sans-serif;
+ font-size: 130%;
+}
+
+h2
+{
+ font-family: sans-serif;
+ font-size: 120%;
+}
+
+h3
+{
+ font-family: sans-serif;
+ font-size: 110%;
+}
+
+blockquote
+{
+ font-size: 90%;
+}
--- /dev/null
+++ b/lib/ebooks/understandingoeb/understandingoeb.opf
@@ -1,0 +1,65 @@
+<?xml version="1.0"?>
+<!DOCTYPE package PUBLIC "+//ISBN 0-9673008-1-9//DTD OEB 1.0.1 Package//EN" "http://openebook.org/dtds/oeb-1.0.1/oebpkg101.dtd">
+<package unique-identifier="understandingoebpackage">
+ <metadata>
+ <dc-metadata xmlns:dc="http://purl.org/dc/elements/1.0/" xmlns:oebpackage="http://openebook.org/namespaces/oeb-package/1.0/">
+ <dc:Title>Understanding OEB</dc:Title>
+ <dc:Type>Tutorial</dc:Type>
+ <dc:Identifier id="understandingoebpackage" scheme="url">http://www.globalmentor.com/publishing/understandingoeb/</dc:Identifier>
+ <dc:Creator role="aut">Garret Wilson</dc:Creator>
+ <dc:Creator role="bkp">Mentor Publishing</dc:Creator>
+ <dc:Creator role="spn">GlobalMentor, Inc.</dc:Creator>
+ <dc:Contributor role="aui">David Ornstein</dc:Contributor>
+ <dc:Rights>Copyright © 2000-2001 Garret Wilson. All Rights Reserved.</dc:Rights>
+ <dc:Date>2001-07-11</dc:Date>
+ <dc:Subject>OEB</dc:Subject>
+ <dc:Subject>eBooks</dc:Subject>
+ <dc:Subject>ePublishing</dc:Subject>
+ </dc-metadata>
+ </metadata>
+
+ <manifest>
+ <!--OEB Documents-->
+ <item id="title" href="title.html" media-type="text/x-oeb1-document" />
+ <item id="toc" href="toc.html" media-type="text/x-oeb1-document" />
+ <item id="foreword" href="foreword.html" media-type="text/x-oeb1-document" />
+ <item id="preface" href="preface.html" media-type="text/x-oeb1-document" />
+ <item id="chapter1" href="chapter1.html" media-type="text/x-oeb1-document" />
+ <item id="chapter2" href="chapter2.html" media-type="text/x-oeb1-document" />
+ <item id="chapter3" href="chapter3.html" media-type="text/x-oeb1-document" />
+ <item id="chapter4" href="chapter4.html" media-type="text/x-oeb1-document" />
+ <item id="chapter5" href="chapter5.html" media-type="text/x-oeb1-document" />
+ <item id="chapter6" href="chapter6.html" media-type="text/x-oeb1-document" />
+ <!--Images-->
+ <item id="OEBActivityDiagram" href="OEBActivityDiagram.png" media-type="image/png" />
+ <item id="OEBClassDiagram" href="OEBClassDiagram.png" media-type="image/png" />
+ <item id="OEBPublicationClassDiagram" href="OEBPublicationClassDiagram.png" media-type="image/png" />
+ <item id="ReadingSystemClassDiagram" href="ReadingSystemClassDiagram.png" media-type="image/png" />
+ </manifest>
+
+ <spine>
+ <itemref idref="title" />
+ <itemref idref="toc" />
+ <itemref idref="foreword" />
+ <itemref idref="preface" />
+ <itemref idref="chapter1" />
+ <itemref idref="chapter2" />
+ <itemref idref="chapter3" />
+ <itemref idref="chapter4" />
+ <itemref idref="chapter5" />
+ <itemref idref="chapter6" />
+ </spine>
+
+ <guide>
+ <reference type="toc" title="Table of Contents" href="toc.html" />
+ <reference type="foreword" title="Foreword" href="foreword.html" />
+ <reference type="preface" title="Preface" href="preface.html" />
+ <reference type="other.chapter1" title="Chapter 1" href="chapter1.html" />
+ <reference type="other.chapter2" title="Chapter 2" href="chapter2.html" />
+ <reference type="other.chapter3" title="Chapter 3" href="chapter3.html" />
+ <reference type="other.chapter4" title="Chapter 4" href="chapter4.html" />
+ <reference type="other.chapter5" title="Chapter 5" href="chapter5.html" />
+ <reference type="other.chapter6" title="Chapter 6" href="chapter6.html" />
+ </guide>
+
+</package>
--- /dev/null
+++ b/lib/emptydirs
@@ -1,0 +1,85 @@
+FreeBSD/386/lib
+Inferno/386/bin
+Inferno/386/lib
+Inferno/arm/bin
+Inferno/arm/lib
+Inferno/mips/bin
+Inferno/mips/lib
+Inferno/power/bin
+Inferno/power/lib
+Inferno/sparc/bin
+Inferno/sparc/lib
+Irix/mips/lib
+Linux/386/lib
+Linux/arm/bin
+Linux/arm/lib
+MacOSX/386/lib
+MacOSX/power/lib
+NetBSD/386/lib
+Nt/386/lib
+OpenBSD/386/bin
+OpenBSD/386/lib
+OpenBSD/arm/bin
+OpenBSD/arm/lib
+Plan9/386/bin
+Plan9/386/lib
+Plan9/arm/bin
+Plan9/arm/lib
+Plan9/mips/bin
+Plan9/mips/lib
+Plan9/power/bin
+Plan9/power/lib
+Plan9/sparc/bin
+Plan9/sparc/lib
+Solaris/sparc/lib
+keydb/countersigned
+keydb/countersigned
+keydb/signed
+keydb/signed
+man/lib/man
+man/lib/permind
+mnt
+mnt/9win
+mnt/acme
+mnt/arch
+mnt/diary
+mnt/factotum
+mnt/gossip
+mnt/icontact
+mnt/ilog
+mnt/incall
+mnt/isubs
+mnt/itrack
+mnt/keys
+mnt/keysrv
+mnt/quiz
+mnt/registry
+mnt/rstyxreg
+mnt/schedule
+mnt/vmail
+mnt/wm
+mnt/wrap
+mnt/wsys
+n
+n/cd
+n/client
+n/client/chan
+n/client/dev
+n/disk
+n/dist
+n/dump
+n/ftp
+n/gridfs
+n/kfs
+n/local
+n/rdbg
+n/registry
+n/remote
+services/logs
+services/ppp
+src
+tmp
+usr/inferno/charon
+usr/inferno/keyring
+usr/inferno/tmp
--- /dev/null
+++ b/lib/games/fortunes
@@ -1,0 +1,8 @@
+We are all interested in the future, for that is where you and I are going to spend the rest of our lives. --Criswell, Plan 9 from Outer Space
+And remember my friend, future events such as these will affect you in the future. --Criswell, Plan 9 from Outer Space
+We should all be concerned about the future because we will have to spend the rest of our lives there. --Charles F Kettering
+For I dipped into the future far as human eye could see. Saw the vision of the world and all the wonder that would be. --Locksley Hall, Alfred, Lord Tennyson
+Excess on occasion is exhilarating. It prevents moderation from acquiring the deadening effect of a habit. -- W Somerset Maugham
+The instruction at "0x77fcae88" referenced memory at "0x63610073". The memory could not be "read".
+A company formed ``for carrying on an undertaking of great advantage, but nobody to know what it is.'' --Charles Mackay, ``Memoirs of Extraordinary Popular Delusions and the Madness of Crowds''
+You should be glad that bridge fell down — I was planning to build 13 more to the same design. -- Remark attributed to I K Brunel, addressing the Directors of the Great Western Railway.
binary files /dev/null b/lib/games/fortunes.index differ
--- /dev/null
+++ b/lib/ircnames
@@ -1,0 +1,1 @@
+#inferno 'Inferno general chat' 'freenode group reg'
--- /dev/null
+++ b/lib/keyboard
@@ -1,0 +1,559 @@
+00A1 !! ¡ inverted exclamation mark
+00A2 c$ ¢ cent sign
+00A3 l$ £ pound sign
+00A4 g$ ¤ currency sign
+00A5 y$ ¥ yen sign
+00A6 || ¦ broken vertical bar
+00A7 SS § section sign
+00A8 "" ¨ spacing diaeresis
+00A9 Oc cO © copyright sign
+00AA sa ª feminine ordinal indicator
+00AB << « left pointing guillemet
+00AC no ¬ not sign
+00AD -- soft hyphen
+00AE Or rO ® registered trade mark sign
+00AF __ ¯ spacing macron
+00B0 de ° degree sign
+00B1 +- ± plus-or-minus sign
+00B2 S2 ² superscript digit two
+00B3 S3 ³ superscript digit three
+00B4 '' ´ spacing acute
+00B5 mi µ micro sign
+00B6 pg ¶ paragraph sign
+00B7 .. · middle dot
+00B8 ,, ¸ spacing cedilla
+00B9 S1 ¹ superscript digit one
+00BA so º masculine ordinal indicator
+00BB >> » right pointing guillemet
+00BC 14 ¼ fraction one quarter
+00BD 12 ½ fraction one half
+00BE 34 ¾ fraction three quarters
+00BF ?? ¿ inverted question mark
+00C0 `A À latin capital letter a grave
+00C1 'A Á latin capital letter a acute
+00C2 ^A Â latin capital letter a circumflex
+00C3 ~A Ã latin capital letter a tilde
+00C4 "A Ä latin capital letter a diaeresis
+00C5 oA Å latin capital letter a ring
+00C6 AE Æ latin capital letter a e
+00C7 ,C Ç latin capital letter c cedilla
+00C8 `E È latin capital letter e grave
+00C9 'E É latin capital letter e acute
+00CA ^E Ê latin capital letter e circumflex
+00CB "E Ë latin capital letter e diaeresis
+00CC `I Ì latin capital letter i grave
+00CD 'I Í latin capital letter i acute
+00CE ^I Î latin capital letter i circumflex
+00CF "I Ï latin capital letter i diaeresis
+00D0 -D D- Ð latin capital letter eth
+00D1 ~N Ñ latin capital letter n tilde
+00D2 `O Ò latin capital letter o grave
+00D3 'O Ó latin capital letter o acute
+00D4 ^O Ô latin capital letter o circumflex
+00D5 ~O Õ latin capital letter o tilde
+00D6 "O Ö latin capital letter o diaeresis
+00D7 mu × multiplication sign
+00D8 /O Ø latin capital letter o slash
+00D9 `U Ù latin capital letter u grave
+00DA 'U Ú latin capital letter u acute
+00DB ^U Û latin capital letter u circumflex
+00DC "U Ü latin capital letter u diaeresis
+00DD 'Y Ý latin capital letter y acute
+00DE |P Þ latin capital letter thorn
+00DF ss ß latin small letter sharp s
+00E0 `a à latin small letter a grave
+00E1 'a á latin small letter a acute
+00E2 ^a â latin small letter a circumflex
+00E3 ~a ã latin small letter a tilde
+00E4 "a ä latin small letter a diaeresis
+00E5 oa å latin small letter a ring
+00E6 ae æ latin small letter a e
+00E7 ,c ç latin small letter c cedilla
+00E8 `e è latin small letter e grave
+00E9 'e é latin small letter e acute
+00EA ^e ê latin small letter e circumflex
+00EB "e ë latin small letter e diaeresis
+00EC `i ì latin small letter i grave
+00ED 'i í latin small letter i acute
+00EE ^i î latin small letter i circumflex
+00EF "i ï latin small letter i diaeresis
+00F0 -d d- ð latin small letter eth
+00F1 ~n ñ latin small letter n tilde
+00F2 `o ò latin small letter o grave
+00F3 'o ó latin small letter o acute
+00F4 ^o ô latin small letter o circumflex
+00F5 ~o õ latin small letter o tilde
+00F6 "o ö latin small letter o diaeresis
+00F7 -: :- ÷ division sign
+00F8 /o ø latin small letter o slash
+00F9 `u ù latin small letter u grave
+00FA 'u ú latin small letter u acute
+00FB ^u û latin small letter u circumflex
+00FC "u ü latin small letter u diaeresis
+00FD 'y ý latin small letter y acute
+00FE |p þ latin small letter thorn
+00FF "y ÿ latin small letter y diaeresis
+0100 _A Ā latin capital letter a macron
+0101 _a ā latin small letter a macron
+0102 uA Ă latin capital letter a breve
+0104 ,A Ą latin capital letter a ogonek
+0105 ,a ą latin small letter a ogonek
+0106 'C Ć latin capital letter c acute
+0107 'c ć latin small letter c acute
+0108 ^C Ĉ latin capital letter c circumflex
+0109 ^c ĉ latin small letter c circumflex
+010A .C Ċ latin capital letter c dot
+010B .c ċ latin small letter c dot
+010C vC Č latin capital letter c hacek
+010D vc č latin small letter c hacek
+010E vD Ď latin capital letter d hacek
+010F vd ď latin small letter d hacek
+0112 _E Ē latin capital letter e macron
+0113 _e ē latin small letter e macron
+0114 uE Ĕ latin capital letter e breve
+0115 ue ĕ latin small letter e breve
+0116 .E Ė latin capital letter e dot
+0117 .e ė latin small letter e dot
+0118 ,E Ę latin capital letter e ogonek
+0119 ,e ę latin small letter e ogonek
+011A vE Ě latin capital letter e hacek
+011B ve ě latin small letter e hacek
+011C ^G Ĝ latin capital letter g circumflex
+011D ^g ĝ latin small letter g circumflex
+011E uG Ğ latin capital letter g breve
+011F ug ğ latin small letter g breve
+0120 .G Ġ latin capital letter g dot
+0121 .g ġ latin small letter g dot
+0122 ,G Ģ latin capital letter g cedilla
+0123 'g ,g ģ latin small letter g cedilla
+0124 ^H Ĥ latin capital letter h circumflex
+0125 ^h ĥ latin small letter h circumflex
+0126 -H H- Ħ latin capital letter h bar
+0128 ~I Ĩ latin capital letter i tilde
+0129 ~i ĩ latin small letter i tilde
+012A _I Ī latin capital letter i macron
+012B _i ī latin small letter i macron
+012C uI Ĭ latin capital letter i breve
+012D ui ĭ latin small letter i breve
+012E ,I Į latin capital letter i ogonek
+012F ,i į latin small letter i ogonek
+0130 .I İ latin capital letter i dot
+0131 i ı latin small letter dotless i
+0132 IJ IJ latin capital letter i j
+0133 ij ij latin small letter i j
+0134 ^J Ĵ latin capital letter j circumflex
+0135 ^j ĵ latin small letter j circumflex
+0136 ,K Ķ latin capital letter k cedilla
+0137 ,k ķ latin small letter k cedilla
+0139 'L Ĺ latin capital letter l acute
+013A 'l ĺ latin small letter l acute
+013B ,L Ļ latin capital letter l cedilla
+013C ,l ļ latin small letter l cedilla
+013D vL Ľ latin capital letter l hacek
+013E vl ľ latin small letter l hacek
+013F .L Ŀ latin capital letter l with middle dot
+0140 .l ŀ latin small letter l with middle dot
+0141 -L L- Ł latin capital letter l slash
+0142 -l l- ł latin small letter l slash
+0143 'N Ń latin capital letter n acute
+0144 'n ń latin small letter n acute
+0145 ,N Ņ latin capital letter n cedilla
+0146 ,n ņ latin small letter n cedilla
+0147 vN Ň latin capital letter n hacek
+0148 vn ň latin small letter n hacek
+014C _O Ō latin capital letter o macron
+014D _o ō latin small letter o macron
+014E uO Ŏ latin capital letter o breve
+014F uo ŏ latin small letter o breve
+0152 OE Œ latin capital letter o e
+0153 oe œ latin small letter o e
+0154 'R Ŕ latin capital letter r acute
+0155 'r ŕ latin small letter r acute
+0156 ,R Ŗ latin capital letter r cedilla
+0157 ,r ŗ latin small letter r cedilla
+0158 vR Ř latin capital letter r hacek
+0159 vr ř latin small letter r hacek
+015A 'S Ś latin capital letter s acute
+015B 's ś latin small letter s acute
+015C ^S Ŝ latin capital letter s circumflex
+015D ^s ŝ latin small letter s circumflex
+015E ,S Ş latin capital letter s cedilla
+015F ,s ş latin small letter s cedilla
+0160 vS Š latin capital letter s hacek
+0161 vs š latin small letter s hacek
+0162 ,T Ţ latin capital letter t cedilla
+0163 ,t ţ latin small letter t cedilla
+0164 vT Ť latin capital letter t hacek
+0165 vt ť latin small letter t hacek
+0166 -T T- Ŧ latin capital letter t bar
+0167 -t t- ŧ latin small letter t bar
+0168 ~U Ũ latin capital letter u tilde
+0169 ~u ũ latin small letter u tilde
+016A _U Ū latin capital letter u macron
+016B _u ū latin small letter u macron
+016C uU Ŭ latin capital letter u breve
+016D uu ŭ latin small letter u breve
+016E oU Ů latin capital letter u ring
+016F ou ů latin small letter u ring
+0172 ,U Ų latin capital letter u ogonek
+0173 ,u ų latin small letter u ogonek
+0174 ^W Ŵ latin capital letter w circumflex
+0175 ^w ŵ latin small letter w circumflex
+0176 ^Y Ŷ latin capital letter y circumflex
+0177 ^y ŷ latin small letter y circumflex
+0178 "Y Ÿ latin capital letter y diaeresis
+0179 'Z Ź latin capital letter z acute
+017A 'z ź latin small letter z acute
+017B .Z Ż latin capital letter z dot
+017C .z ż latin small letter z dot
+017D vZ Ž latin capital letter z hacek
+017E vz ž latin small letter z hacek
+0180 -b ƀ latin small letter b bar
+0192 $f ƒ latin small letter script f
+0195 hv ƕ latin small letter h v
+0197 -I I- Ɨ latin capital letter barred i
+019B -*l ƛ latin small letter barred lambda
+01A2 OI Ƣ latin capital letter o i
+01A3 oi ƣ latin small letter o i
+01A6 YR Ʀ latin letter y r
+01B2 $V Ʋ latin capital letter script v
+01B5 -Z Z- Ƶ latin capital letter z bar
+01B6 -z z- ƶ latin small letter z bar
+01BB -2 2- ƻ latin letter two bar
+01C4 DvZ DŽ latin capital letter d z hacek
+01C5 Dvz Dž latin letter capital d small z hacek
+01C6 dvz dž latin small letter d z hacek
+01C7 LJ LJ latin capital letter l j
+01C8 Lj Lj latin letter capital l small j
+01C9 lj lj latin small letter l j
+01CA NJ NJ latin capital letter n j
+01CB Nj Nj latin letter capital n small j
+01CC nj nj latin small letter n j
+01CD vA Ǎ latin capital letter a hacek
+01CE va ǎ latin small letter a hacek
+01CF vI Ǐ latin capital letter i hacek
+01D0 vi ǐ latin small letter i hacek
+01D1 vO Ǒ latin capital letter o hacek
+01D2 vo ǒ latin small letter o hacek
+01D3 vU Ǔ latin capital letter u hacek
+01D4 vu ǔ latin small letter u hacek
+01D5 _"U Ǖ latin capital letter u diaeresis macron
+01D6 _"u ǖ latin small letter u diaeresis macron
+01D7 '"U Ǘ latin capital letter u diaeresis acute
+01D8 '"u ǘ latin small letter u diaeresis acute
+01D9 v"U Ǚ latin capital letter u diaeresis hacek
+01DA v"u ǚ latin small letter u diaeresis hacek
+01DB `"U Ǜ latin capital letter u diaeresis grave
+01DC `"u ǜ latin small letter u diaeresis grave
+01DE _"A Ǟ latin capital letter a diaeresis macron
+01DF _"a ǟ latin small letter a diaeresis macron
+01E0 _.A Ǡ latin capital letter a dot macron
+01E1 _.a ǡ latin small letter a dot macron
+01E4 -G G- Ǥ latin capital letter g bar
+01E5 -g g- ǥ latin small letter g bar
+01E6 vG Ǧ latin capital letter g hacek
+01E7 vg ǧ latin small letter g hacek
+01E8 vK Ǩ latin capital letter k hacek
+01E9 vk ǩ latin small letter k hacek
+01EA ,O Ǫ latin capital letter o ogonek
+01EB ,o ǫ latin small letter o ogonek
+01EC _,O Ǭ latin capital letter o ogonek macron
+01ED _,o ǭ latin small letter o ogonek macron
+01F0 vj ǰ latin small letter j hacek
+0251 $a ɑ latin small letter script a
+0268 -i i- ɨ latin small letter barred i
+0289 -u u- ʉ latin small letter u bar
+028B $v ʋ latin small letter script v
+02A3 dz ʣ latin small letter d z
+0391 *A Α greek capital letter alpha
+0392 *B Β greek capital letter beta
+0393 *G Γ greek capital letter gamma
+0394 *D Δ greek capital letter delta
+0395 *E Ε greek capital letter epsilon
+0396 *Z Ζ greek capital letter zeta
+0397 *Y Η greek capital letter eta
+0398 *H Θ greek capital letter theta
+0399 *I Ι greek capital letter iota
+039A *K Κ greek capital letter kappa
+039B *L Λ greek capital letter lambda
+039C *M Μ greek capital letter mu
+039D *N Ν greek capital letter nu
+039E *C Ξ greek capital letter xi
+039F *O Ο greek capital letter omicron
+03A0 *P Π greek capital letter pi
+03A1 *R Ρ greek capital letter rho
+03A3 *S Σ greek capital letter sigma
+03A4 *T Τ greek capital letter tau
+03A5 *U Υ greek capital letter upsilon
+03A6 *F Φ greek capital letter phi
+03A7 *X Χ greek capital letter chi
+03A8 *Q Ψ greek capital letter psi
+03A9 *W Ω greek capital letter omega
+03AA "*I Ϊ greek capital letter iota diaeresis
+03AB "*U Ϋ greek capital letter upsilon diaeresis
+03B1 *a α greek small letter alpha
+03B2 *b β greek small letter beta
+03B3 *g γ greek small letter gamma
+03B4 *d δ greek small letter delta
+03B5 *e ε greek small letter epsilon
+03B6 *z ζ greek small letter zeta
+03B7 *y η greek small letter eta
+03B8 *h θ greek small letter theta
+03B9 *i ι greek small letter iota
+03BA *k κ greek small letter kappa
+03BB *l λ greek small letter lambda
+03BC *m μ greek small letter mu
+03BD *n ν greek small letter nu
+03BE *c ξ greek small letter xi
+03BF *o ο greek small letter omicron
+03C0 *p π greek small letter pi
+03C1 *r ρ greek small letter rho
+03C2 ts ς greek small letter final sigma
+03C3 *s σ greek small letter sigma
+03C4 *t τ greek small letter tau
+03C5 *u υ greek small letter upsilon
+03C6 *f φ greek small letter phi
+03C7 *x χ greek small letter chi
+03C8 *q ψ greek small letter psi
+03C9 *w ω greek small letter omega
+03CA "*i ϊ greek small letter iota diaeresis
+03CB "*u ϋ greek small letter upsilon diaeresis
+03D1 $*h ϑ greek small letter script theta
+03D5 $*f ϕ greek small letter script phi
+03F0 $*k ϰ greek small letter script kappa
+0401 @YO @Yo Ё cyrillic capital letter io
+0410 @A А cyrillic capital letter a
+0411 @B Б cyrillic capital letter be
+0412 @V В cyrillic capital letter ve
+0413 @G Г cyrillic capital letter ge
+0414 @D Д cyrillic capital letter de
+0415 @@E @YE @Ye Е cyrillic capital letter ie
+0416 @ZH @Zh Ж cyrillic capital letter zhe
+0417 @@Z З cyrillic capital letter ze
+0418 @I И cyrillic capital letter ii
+0419 @J Й cyrillic capital letter short ii
+041A @@K К cyrillic capital letter ka
+041B @L Л cyrillic capital letter el
+041C @M М cyrillic capital letter em
+041D @N Н cyrillic capital letter en
+041E @O О cyrillic capital letter o
+041F @P П cyrillic capital letter pe
+0420 @R Р cyrillic capital letter er
+0421 @@S С cyrillic capital letter es
+0422 @@T Т cyrillic capital letter te
+0423 @U У cyrillic capital letter u
+0424 @F Ф cyrillic capital letter ef
+0425 @KH @Kh @X Х cyrillic capital letter kha
+0426 @TS @Ts Ц cyrillic capital letter tse
+0427 @CH @Ch Ч cyrillic capital letter che
+0428 @SH @Sh Ш cyrillic capital letter sha
+0429 @SC @Sc Щ cyrillic capital letter shcha
+042B @@Y Ы cyrillic capital letter yeri
+042D @EH @Eh Э cyrillic capital letter reversed e
+042E @YU @Yu Ю cyrillic capital letter iu
+042F @YA @Ya Я cyrillic capital letter ia
+0430 @a а cyrillic small letter a
+0431 @b б cyrillic small letter be
+0432 @v в cyrillic small letter ve
+0433 @g г cyrillic small letter ge
+0434 @d д cyrillic small letter de
+0435 @@e @ye е cyrillic small letter ie
+0436 @zh ж cyrillic small letter zhe
+0437 @@z з cyrillic small letter ze
+0438 @i и cyrillic small letter ii
+0439 @j й cyrillic small letter short ii
+043A @@k к cyrillic small letter ka
+043B @l л cyrillic small letter el
+043C @m м cyrillic small letter em
+043D @n н cyrillic small letter en
+043E @o о cyrillic small letter o
+043F @p п cyrillic small letter pe
+0440 @r р cyrillic small letter er
+0441 @@s с cyrillic small letter es
+0442 @@t т cyrillic small letter te
+0443 @u у cyrillic small letter u
+0444 @f ф cyrillic small letter ef
+0445 @kh @x х cyrillic small letter kha
+0446 @ts ц cyrillic small letter tse
+0447 @ch ч cyrillic small letter che
+0448 @sh ш cyrillic small letter sha
+0449 @sc щ cyrillic small letter shcha
+044A @'' ъ cyrillic small letter hard sign
+044B @@y ы cyrillic small letter yeri
+044C @@' ь cyrillic small letter soft sign
+044D @eh э cyrillic small letter reversed e
+044E @yu ю cyrillic small letter iu
+044F @ya я cyrillic small letter ia
+0451 @yo ё cyrillic small letter io
+2018 l' ‘ single turned comma quotation mark
+2019 r' ’ single comma quotation mark
+201C l" “ double turned comma quotation mark
+201D r" ” double comma quotation mark
+2020 dg † dagger
+2021 dd ‡ double dagger
+2022 bu • bullet
+203D !? ?! ‽ interrobang
+2070 s0 ⁰ superscript digit zero
+2071 s1 ⁱ superscript digit one
+2072 s2 superscript digit two
+2073 s3 superscript digit three
+2074 s4 ⁴ superscript digit four
+2075 s5 ⁵ superscript digit five
+2076 s6 ⁶ superscript digit six
+2077 s7 ⁷ superscript digit seven
+2078 s8 ⁸ superscript digit eight
+2079 s9 ⁹ superscript digit nine
+207A s+ ⁺ superscript plus sign
+207B s- ⁻ superscript hyphen-minus
+207C s= ⁼ superscript equals sign
+207D s( ⁽ superscript opening parenthesis
+207E s) ⁾ superscript closing parenthesis
+207F sn ⁿ superscript latin small letter n
+2013 en – en dash
+2014 em – em dash
+2080 b0 ₀ subscript digit zero
+2081 b1 ₁ subscript digit one
+2082 b2 ₂ subscript digit two
+2083 b3 ₃ subscript digit three
+2084 b4 ₄ subscript digit four
+2085 b5 ₅ subscript digit five
+2086 b6 ₆ subscript digit six
+2087 b7 ₇ subscript digit seven
+2088 b8 ₈ subscript digit eight
+2089 b9 ₉ subscript digit nine
+208A b+ ₊ subscript plus sign
+208B b- ₋ subscript hyphen-minus
+208C b= ₌ subscript equals sign
+208D b( ₍ subscript opening parenthesis
+208E b) ₎ subscript closing parenthesis
+20AC e$ € euro symbol
+2102 CC ℂ double-struck capital c
+210A $g ℊ script small g
+210B $H ℋ script capital h
+210D HH ℍ double-struck capital h
+210F -h h- ℏ planck constant over 2 pi
+2110 $I ℐ script capital i
+2112 $L ℒ script capital l
+2113 $l ℓ script small l
+2115 NN ℕ double-struck capital n
+2117 Op pO ℗ sound recording copyright
+2118 $p ℘ script p
+2119 PP ℙ double-struck capital p
+211A QQ ℚ double-struck capital q
+211B $R ℛ script capital r
+211D RR ℝ double-struck capital r
+2122 tm ™ trademark
+2124 ZZ ℤ double-struck capital z
+212C $B ℬ script capital b
+212F $e ℯ script small e
+2130 $E ℰ script capital e
+2131 $F ℱ script capital f
+2133 $M ℳ script capital m
+2134 $o ℴ script small o
+2153 13 ⅓ fraction one third
+2154 23 ⅔ fraction two thirds
+2155 15 ⅕ fraction one fifth
+2156 25 ⅖ fraction two fifths
+2157 35 ⅗ fraction three fifths
+2158 45 ⅘ fraction four fifths
+2159 16 ⅙ fraction one sixth
+215A 56 ⅚ fraction five sixths
+215B 18 ⅛ fraction one eighth
+215C 38 ⅜ fraction three eighths
+215D 58 ⅝ fraction five eighths
+215E 78 ⅞ fraction seven eighths
+2190 <- ← left arrow
+2191 ua ↑ up arrow
+2192 -> → right arrow
+2193 da ↓ down arrow
+2194 ab ↔ left right arrow
+21D0 V= ⇐ left double arrow
+21D2 =V ⇒ right double arrow
+2200 fa ∀ for all
+2202 pd ∂ partial differential
+2203 te ∃ there exists
+2205 es ∅ empty set
+2206 De ∆ increment
+2207 gr ∇ nabla
+2208 mo ∈ element of
+2209 !m ∉ not an element of
+220D st ∍ small contains as member
+220F pr ∏ n-ary product
+2211 su ∑ n-ary summation
+2213 -+ ∓ minus-or-plus sign
+2217 ** ∗ asterisk operator
+221A sr √ square root
+221D pt ∝ proportional to
+221E if ∞ infinity
+2220 an ∠ angle
+2227 l& ∧ logical and
+2228 l| ∨ logical or
+2229 ca ∩ intersection
+222A cu ∪ union
+222B is ∫ integral
+2234 tf ∴ therefore
+2242 -~ ≂ minus tilde
+2243 ~- ≃ asymptotically equal to
+2244 !~- ≄ not asymptotically equal to
+2245 cg ~= ≅ approximately equal to
+2246 ~!= ≆ approximately but not actually equal to
+2247 !~= ≇ neither approximately nor actually equal to
+2248 ~~ ≈ almost equal to
+2249 !~~ ≉ not almost equal to
+2254 := ≔ colon equal
+2255 =: ≕ equal colon
+2260 != ≠ not equal to
+2261 == ≡ identical to
+2264 <= ≤ less than or equal to
+2265 >= ≥ greater than or equal to
+2268 <!= ≨ less than but not equal to
+2269 >!= ≩ greater than but not equal to
+226E !< ≮ not less than
+226F !> ≯ not greater than
+2272 <~ ≲ less than or equivalent to
+2273 >~ ≳ greater than or equivalent to
+2276 <> ≶ less than or greater than
+2277 >< ≷ greater than or less than
+2282 sb ⊂ subset of
+2283 sp ⊃ superset of
+2284 !b ⊄ not a subset of
+2285 !p ⊅ not a superset of
+2286 ib ⊆ subset of or equal to
+2287 ip ⊇ superset of or equal to
+2295 +O O+ ⊕ circled plus
+2296 -O O- ⊖ circled minus
+2297 Ox xO ⊗ circled times
+2298 O/ ⊘ circled division slash
+2299 .O O. ⊙ circled dot operator
+229A Oo oO ⊚ circled ring operator
+229B O* ⊛ circled asterisk operator
+229C =O O= ⊜ circled equals
+22A2 tu ⊢ right tack
+22A8 Tu ⊨ true
+22C0 L& ⋀ n-ary logical and
+22C1 L| ⋁ n-ary logical or
+22C2 CA ⋂ n-ary intersection
+22C3 CU ⋃ n-ary union
+22C4 lz ⋄ diamond operator
+22DC =< ⋜ equal to or less than
+22DD => ⋝ equal to or greater than
+22E6 <!~ ⋦ less than but not equivalent to
+22E7 >!~ ⋧ greater than but not equivalent to
+22EF el ⋯ midline horizontal ellipsis
+2423 ␣ open box, visible space
+263A :) ☺ smiley face
+2654 wk ♔ white chess king
+2655 wq ♕ white chess queen
+2656 wr ♖ white chess rook
+2657 wb ♗ white chess bishop
+2658 wn ♘ white chess knight
+2659 wp ♙ white chess pawn
+265A bk ♚ black chess king
+265B bq ♛ black chess queen
+265C br ♜ black chess rook
+265D bb ♝ black chess bishop
+265E bn ♞ black chess knight
+265F bp ♟ black chess pawn
+F015 ZA raw alt (plan 9 specific)
+F016 ZS raw shift (plan 9 specific)
+F017 ZC raw ctl (plan 9 specific)
--- /dev/null
+++ b/lib/legal/GPL
@@ -1,0 +1,339 @@
+ GNU GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+ 675 Mass Ave, Cambridge, MA 02139, USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users. This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it. (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.) You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+ To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have. You must make sure that they, too, receive or can get the
+source code. And you must show them these terms so they know their
+rights.
+
+ We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+ Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software. If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+ Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary. To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ GNU GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License. The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language. (Hereinafter, translation is included without limitation in
+the term "modification".) Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+ 1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+ 2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) You must cause the modified files to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ b) You must cause any work that you distribute or publish, that in
+ whole or in part contains or is derived from the Program or any
+ part thereof, to be licensed as a whole at no charge to all third
+ parties under the terms of this License.
+
+ c) If the modified program normally reads commands interactively
+ when run, you must cause it, when started running for such
+ interactive use in the most ordinary way, to print or display an
+ announcement including an appropriate copyright notice and a
+ notice that there is no warranty (or else, saying that you provide
+ a warranty) and that users may redistribute the program under
+ these conditions, and telling the user how to view a copy of this
+ License. (Exception: if the Program itself is interactive but
+ does not normally print such an announcement, your work based on
+ the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+ a) Accompany it with the complete corresponding machine-readable
+ source code, which must be distributed under the terms of Sections
+ 1 and 2 above on a medium customarily used for software interchange; or,
+
+ b) Accompany it with a written offer, valid for at least three
+ years, to give any third party, for a charge no more than your
+ cost of physically performing source distribution, a complete
+ machine-readable copy of the corresponding source code, to be
+ distributed under the terms of Sections 1 and 2 above on a medium
+ customarily used for software interchange; or,
+
+ c) Accompany it with the information you received as to the offer
+ to distribute corresponding source code. (This alternative is
+ allowed only for noncommercial distribution and only if you
+ received the program in object code or executable form with such
+ an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it. For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable. However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License. Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+ 5. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Program or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+ 6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+ 7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all. For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded. In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+ 9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation. If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+ 10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission. For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this. Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+ NO WARRANTY
+
+ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+ Appendix: How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) 19yy <name of author>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+ Gnomovision version 69, Copyright (C) 19yy name of author
+ Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+ `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+ <signature of Ty Coon>, 1 April 1989
+ Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs. If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library. If this is what you want to do, use the GNU Library General
+Public License instead of this License.
--- /dev/null
+++ b/lib/legal/LGPL
@@ -1,0 +1,450 @@
+GNU LESSER GENERAL PUBLIC LICENSE
+
+Version 2.1, February 1999
+
+Copyright (C) 1991, 1999 Free Software Foundation, Inc.
+59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+Everyone is permitted to copy and distribute verbatim copies
+of this license document, but changing it is not allowed.
+[This is the first released version of the Lesser GPL. It also counts
+as the successor of the GNU Library Public License, version 2, hence
+the version number 2.1.]
+
+Preamble
+
+The licenses for most software are designed to take away your freedom
+to share and change it. By contrast, the GNU General Public Licenses
+are intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users.
+
+This license, the Lesser General Public License, applies to some
+specially designated software packages--typically libraries--of the
+Free Software Foundation and other authors who decide to use it. You
+can use it too, but we suggest you first think carefully about whether
+this license or the ordinary General Public License is the better
+strategy to use in any particular case, based on the explanations
+below.
+
+When we speak of free software, we are referring to freedom of use,
+not price. Our General Public Licenses are designed to make sure that
+you have the freedom to distribute copies of free software (and charge
+for this service if you wish); that you receive source code or can get
+it if you want it; that you can change the software and use pieces of
+it in new free programs; and that you are informed that you can do
+these things.
+
+To protect your rights, we need to make restrictions that forbid
+distributors to deny you these rights or to ask you to surrender these
+rights. These restrictions translate to certain responsibilities for
+you if you distribute copies of the library or if you modify it.
+
+For example, if you distribute copies of the library, whether gratis
+or for a fee, you must give the recipients all the rights that we gave
+you. You must make sure that they, too, receive or can get the source
+code. If you link other code with the library, you must provide
+complete object files to the recipients, so that they can relink them
+with the library after making changes to the library and recompiling
+it. And you must show them these terms so they know their rights.
+
+We protect your rights with a two-step method: (1) we copyright the
+library, and (2) we offer you this license, which gives you legal
+permission to copy, distribute and/or modify the library.
+
+To protect each distributor, we want to make it very clear that there
+is no warranty for the free library. Also, if the library is modified
+by someone else and passed on, the recipients should know that what
+they have is not the original version, so that the original author's
+reputation will not be affected by problems that might be introduced
+by others.
+
+Finally, software patents pose a constant threat to the existence of
+any free program. We wish to make sure that a company cannot
+effectively restrict the users of a free program by obtaining a
+restrictive license from a patent holder. Therefore, we insist that
+any patent license obtained for a version of the library must be
+consistent with the full freedom of use specified in this license.
+
+Most GNU software, including some libraries, is covered by the
+ordinary GNU General Public License. This license, the GNU Lesser
+General Public License, applies to certain designated libraries, and
+is quite different from the ordinary General Public License. We use
+this license for certain libraries in order to permit linking those
+libraries into non-free programs.
+
+When a program is linked with a library, whether statically or using a
+shared library, the combination of the two is legally speaking a
+combined work, a derivative of the original library. The ordinary
+General Public License therefore permits such linking only if the
+entire combination fits its criteria of freedom. The Lesser General
+Public License permits more lax criteria for linking other code with
+the library.
+
+We call this license the"Lesser" General Public License because it
+does Less to protect the user's freedom than the ordinary General
+Public License. It also provides other free software developers Less
+of an advantage over competing non-free programs. These disadvantages
+are the reason we use the ordinary General Public License for many
+libraries. However, the Lesser license provides advantages in certain
+special circumstances.
+
+For example, on rare occasions, there may be a special need to
+encourage the widest possible use of a certain library, so that it
+becomes a de-facto standard. To achieve this, non-free programs must
+be allowed to use the library. A more frequent case is that a free
+library does the same job as widely used non-free libraries. In this
+case, there is little to gain by limiting the free library to free
+software only, so we use the Lesser General Public License.
+
+In other cases, permission to use a particular library in non-free
+programs enables a greater number of people to use a large body of
+free software. For example, permission to use the GNU C Library in
+non-free programs enables many more people to use the whole GNU
+operating system, as well as its variant, the GNU/Linux operating
+system.
+
+Although the Lesser General Public License is Less protective of the
+users' freedom, it does ensure that the user of a program that is
+linked with the Library has the freedom and the wherewithal to run
+that program using a modified version of the Library.
+
+The precise terms and conditions for copying, distribution and
+modification follow. Pay close attention to the difference between a
+"work based on the library" and a"work that uses the library". The
+former contains code derived from the library, whereas the latter must
+be combined with the library in order to run.
+
+TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+0. This License Agreement applies to any software library or other
+program which contains a notice placed by the copyright holder or
+other authorized party saying it may be distributed under the terms of
+this Lesser General Public License (also called"this License"). Each
+licensee is addressed as"you".
+
+A"library" means a collection of software functions and/or data
+prepared so as to be conveniently linked with application programs
+(which use some of those functions and data) to form executables.
+
+The"Library", below, refers to any such software library or work which
+has been distributed under these terms. A"work based on the Library"
+means either the Library or any derivative work under copyright law:
+that is to say, a work containing the Library or a portion of it,
+either verbatim or with modifications and/or translated
+straightforwardly into another language. (Hereinafter, translation is
+included without limitation in the term"modification".)
+
+"Source code" for a work means the preferred form of the work for
+making modifications to it. For a library, complete source code means
+all the source code for all modules it contains, plus any associated
+interface definition files, plus the scripts used to control
+compilation and installation of the library.
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running a program using the Library is not restricted, and output from
+such a program is covered only if its contents constitute a work based
+on the Library (independent of the use of the Library in a tool for
+writing it). Whether that is true depends on what the Library does and
+what the program that uses the Library does.
+
+1. You may copy and distribute verbatim copies of the Library's
+complete source code as you receive it, in any medium, provided that
+you conspicuously and appropriately publish on each copy an
+appropriate copyright notice and disclaimer of warranty; keep intact
+all the notices that refer to this License and to the absence of any
+warranty; and distribute a copy of this License along with the
+Library.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a
+fee.
+
+2. You may modify your copy or copies of the Library or any portion of
+it, thus forming a work based on the Library, and copy and distribute
+such modifications or work under the terms of Section 1 above,
+provided that you also meet all of these conditions:
+
+• a) The modified work must itself be a software library.
+• b) You must cause the files modified to carry prominent notices
+stating that you changed the files and the date of any change.
+• c) You must cause the whole of the work to be licensed at no charge
+to all third parties under the terms of this License.
+• d) If a facility in the modified Library refers to a function or a
+table of data to be supplied by an application program that uses the
+facility, other than as an argument passed when the facility is
+invoked, then you must make a good faith effort to ensure that, in the
+event an application does not supply such function or table, the
+facility still operates, and performs whatever part of its purpose
+remains meaningful.
+
+(For example, a function in a library to compute square roots has a
+purpose that is entirely well-defined independent of the application.
+Therefore, Subsection 2d requires that any application-supplied
+function or table used by this function must be optional: if the
+application does not supply it, the square root function must still
+compute square roots.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Library,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Library, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote
+it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Library.
+
+In addition, mere aggregation of another work not based on the Library
+with the Library (or with a work based on the Library) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+3. You may opt to apply the terms of the ordinary GNU General Public
+License instead of this License to a given copy of the Library. To do
+this, you must alter all the notices that refer to this License, so
+that they refer to the ordinary GNU General Public License, version 2,
+instead of to this License. (If a newer version than version 2 of the
+ordinary GNU General Public License has appeared, then you can specify
+that version instead if you wish.) Do not make any other change in
+these notices.
+
+Once this change is made in a given copy, it is irreversible for that
+copy, so the ordinary GNU General Public License applies to all
+subsequent copies and derivative works made from that copy.
+
+This option is useful when you wish to copy part of the code of the
+Library into a program that is not a library.
+
+4. You may copy and distribute the Library (or a portion or derivative
+of it, under Section 2) in object code or executable form under the
+terms of Sections 1 and 2 above provided that you accompany it with
+the complete corresponding machine-readable source code, which must be
+distributed under the terms of Sections 1 and 2 above on a medium
+customarily used for software interchange.
+
+If distribution of object code is made by offering access to copy from
+a designated place, then offering equivalent access to copy the source
+code from the same place satisfies the requirement to distribute the
+source code, even though third parties are not compelled to copy the
+source along with the object code.
+
+5. A program that contains no derivative of any portion of the
+Library, but is designed to work with the Library by being compiled or
+linked with it, is called a"work that uses the Library". Such a work,
+in isolation, is not a derivative work of the Library, and therefore
+falls outside the scope of this License.
+
+However, linking a"work that uses the Library" with the Library
+creates an executable that is a derivative of the Library (because it
+contains portions of the Library), rather than a"work that uses the
+library". The executable is therefore covered by this License. Section
+6 states terms for distribution of such executables.
+
+When a"work that uses the Library" uses material from a header file
+that is part of the Library, the object code for the work may be a
+derivative work of the Library even though the source code is not.
+Whether this is true is especially significant if the work can be
+linked without the Library, or if the work is itself a library. The
+threshold for this to be true is not precisely defined by law.
+
+If such an object file uses only numerical parameters, data structure
+layouts and accessors, and small macros and small inline functions
+(ten lines or less in length), then the use of the object file is
+unrestricted, regardless of whether it is legally a derivative work.
+(Executables containing this object code plus portions of the Library
+will still fall under Section 6.)
+
+Otherwise, if the work is a derivative of the Library, you may
+distribute the object code for the work under the terms of Section 6.
+Any executables containing that work also fall under Section 6,
+whether or not they are linked directly with the Library itself.
+
+6. As an exception to the Sections above, you may also combine or link
+a"work that uses the Library" with the Library to produce a work
+containing portions of the Library, and distribute that work under
+terms of your choice, provided that the terms permit modification of
+the work for the customer's own use and reverse engineering for
+debugging such modifications.
+
+You must give prominent notice with each copy of the work that the
+Library is used in it and that the Library and its use are covered by
+this License. You must supply a copy of this License. If the work
+during execution displays copyright notices, you must include the
+copyright notice for the Library among them, as well as a reference
+directing the user to the copy of this License. Also, you must do one
+of these things:
+
+• a) Accompany the work with the complete corresponding
+machine-readable source code for the Library including whatever
+changes were used in the work (which must be distributed under
+Sections 1 and 2 above); and, if the work is an executable linked with
+the Library, with the complete machine-readable"work that uses the
+Library", as object code and/or source code, so that the user can
+modify the Library and then relink to produce a modified executable
+containing the modified Library. (It is understood that the user who
+changes the contents of definitions files in the Library will not
+necessarily be able to recompile the application to use the modified
+definitions.)
+• b) Use a suitable shared library mechanism for linking with the
+Library. A suitable mechanism is one that (1) uses at run time a copy
+of the library already present on the user's computer system, rather
+than copying library functions into the executable, and (2) will
+operate properly with a modified version of the library, if the user
+installs one, as long as the modified version is interface-compatible
+with the version that the work was made with.
+• c) Accompany the work with a written offer, valid for at least three
+years, to give the same user the materials specified in Subsection 6a,
+above, for a charge no more than the cost of performing this
+distribution.
+• d) If distribution of the work is made by offering access to copy
+from a designated place, offer equivalent access to copy the above
+specified materials from the same place.
+• e) Verify that the user has already received a copy of these
+materials or that you have already sent this user a copy.
+
+For an executable, the required form of the"work that uses the
+Library" must include any data and utility programs needed for
+reproducing the executable from it. However, as a special exception,
+the materials to be distributed need not include anything that is
+normally distributed (in either source or binary form) with the major
+components (compiler, kernel, and so on) of the operating system on
+which the executable runs, unless that component itself accompanies
+the executable.
+
+It may happen that this requirement contradicts the license
+restrictions of other proprietary libraries that do not normally
+accompany the operating system. Such a contradiction means you cannot
+use both them and the Library together in an executable that you
+distribute.
+
+7. You may place library facilities that are a work based on the
+Library side-by-side in a single library together with other library
+facilities not covered by this License, and distribute such a combined
+library, provided that the separate distribution of the work based on
+the Library and of the other library facilities is otherwise
+permitted, and provided that you do these two things:
+
+• a) Accompany the combined library with a copy of the same work based
+on the Library, uncombined with any other library facilities. This
+must be distributed under the terms of the Sections above.
+• b) Give prominent notice with the combined library of the fact that
+part of it is a work based on the Library, and explaining where to
+find the accompanying uncombined form of the same work.
+
+8. You may not copy, modify, sublicense, link with, or distribute the
+Library except as expressly provided under this License. Any attempt
+otherwise to copy, modify, sublicense, link with, or distribute the
+Library is void, and will automatically terminate your rights under
+this License. However, parties who have received copies, or rights,
+from you under this License will not have their licenses terminated so
+long as such parties remain in full compliance.
+
+9. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Library or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Library (or any work based on the
+Library), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Library or works based on it.
+
+10. Each time you redistribute the Library (or any work based on the
+Library), the recipient automatically receives a license from the
+original licensor to copy, distribute, link with or modify the Library
+subject to these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties with
+this License.
+
+11. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Library at all. For example, if a patent
+license would not permit royalty-free redistribution of the Library by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Library.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply, and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+12. If the distribution and/or use of the Library is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Library under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded. In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+13. The Free Software Foundation may publish revised and/or new
+versions of the Lesser General Public License from time to time. Such
+new versions will be similar in spirit to the present version, but may
+differ in detail to address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Library
+specifies a version number of this License which applies to it and"any
+later version", you have the option of following the terms and
+conditions either of that version or of any later version published by
+the Free Software Foundation. If the Library does not specify a
+license version number, you may choose any version ever published by
+the Free Software Foundation.
+
+14. If you wish to incorporate parts of the Library into other free
+programs whose distribution conditions are incompatible with these,
+write to the author to ask for permission. For software which is
+copyrighted by the Free Software Foundation, write to the Free
+Software Foundation; we sometimes make exceptions for this. Our
+decision will be guided by the two goals of preserving the free status
+of all derivatives of our free software and of promoting the sharing
+and reuse of software generally.
+
+NO WARRANTY
+
+15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
+WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
+EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
+OTHER PARTIES PROVIDE THE LIBRARY"AS IS" WITHOUT WARRANTY OF ANY KIND,
+EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
+LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
+THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
+WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
+AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
+FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
+CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
+LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
+RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
+FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
+SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+DAMAGES.
+
+END OF TERMS AND CONDITIONS
--- /dev/null
+++ b/lib/legal/NOTICE.app
@@ -1,0 +1,4 @@
+This Inferno® software distribution is subject to your Inferno system and application commercial licence(s).
+It must not be used except as allowed by that licence.
+It must not be redistributed outside your organisation unless otherwise agreed,
+or deployed in greater numbers than allowed by your licence.
--- /dev/null
+++ b/lib/legal/NOTICE.ffal
@@ -1,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.
+ Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
+ Portions Copyright © 1997-1999 Vita Nuova Limited
+ Portions Copyright © 2000-2005 Vita Nuova Holdings Limited (www.vitanuova.com)
+ Portions Copyright © 2004,2005 Bruce Ellis
+ Portions Copyright © 2005 C H Forsyth (forsyth@terzarima.net)
+ Revisions Copyright © 2000-2005 Lucent Technologies Inc. and others
+
+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.
+
--- /dev/null
+++ b/lib/legal/NOTICE.gpl
@@ -1,0 +1,25 @@
+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 © 1995-1999 Lucent Technologies Inc.
+Portions Copyright © 1997-2000 Vita Nuova Limited
+Portions Copyright © 2000-2005 Vita Nuova Holdings Limited
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
--- /dev/null
+++ b/lib/legal/NOTICE.lgpl
@@ -1,0 +1,25 @@
+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 © 1995-1999 Lucent Technologies Inc.
+Portions Copyright © 1997-2000 Vita Nuova Limited
+Portions Copyright © 2000-2005 Vita Nuova Holdings Limited
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU Lesser General Public License (`LGPL') as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
--- /dev/null
+++ b/lib/legal/NOTICE.liberal
@@ -1,0 +1,38 @@
+This Inferno® distribution includes software from various sources and
+different portions are therefore subject to different licence terms.
+
+You may copy and redistribute the package as a whole,
+with or without modification, subject to the terms of the Vita Nuova
+Liberal Source Licence (see the file LICENCE), which applies to the
+package as a whole, and to individual components unless otherwise
+specified either in an individual source file or in a NOTICE file
+in a directory or directory tree. If the terms of that licence are not acceptable,
+you must negotiate other terms with Vita Nuova (www.vitanuova.com).
+
+Individual components (eg, some of the libraries, Freetype, and the
+B&H fonts) might have their own NOTICE and licence files (LICENCE or
+COPYING) that cover their content. Be sure to read them before
+considering redistribution of them on their own.
+With the exception of the B&H font licence, each is typically
+some variety of Free Software licence.
+
+Where a given section of source code is distributed elsewhere (as a separable component) under
+another licence or licences, and we include it here as well under ours, you can obviously
+regard it as subject to whichever licence you like.
+
+When making non-trivial extracts, or your own modifications, you must
+retain the copyright of the original source file or files (either that
+present in the file or in a NOTICE file covering the directory or
+directories in which the file resides).
+
+The following copyright notice covers the contents of this
+distribution unless otherwise specified by a given file, directory, or
+directory tree:
+
+Inferno® Copyright © 1996-1999 Lucent Technologies Inc. All rights reserved.
+Inferno revisions Copyright © 1997-1999 Vita Nuova Limited. All rights reserved.
+Inferno revisions Copyright © 2000-2003 Vita Nuova Holdings Limited. All rights reserved.
+Inferno new material Copyright © 2000-2003 Vita Nuova Holdings Limited. All rights reserved.
+
+Inferno, Styx, Dis and Limbo are registered trademarks of Vita Nuova Holdings Limited in the USA and other countries.
+Plan 9 is a registered trademark of Lucent Technologies Inc.
--- /dev/null
+++ b/lib/legal/calderalic.pdf
@@ -1,0 +1,80 @@
+%PDF-1.2 %����
+3 0 obj << /Linearized 1 /O 5 /H [ 1100 188 ] /L 12298 /E 12048 /N 1 /T 12121 >> endobj xref 3 32 0000000016 00000 n
+0000000984 00000 n
+0000001288 00000 n
+0000001492 00000 n
+0000001692 00000 n
+0000001799 00000 n
+0000002084 00000 n
+0000002158 00000 n
+0000002343 00000 n
+0000002392 00000 n
+0000002572 00000 n
+0000003072 00000 n
+0000003093 00000 n
+0000003928 00000 n
+0000003949 00000 n
+0000004804 00000 n
+0000004825 00000 n
+0000005513 00000 n
+0000005534 00000 n
+0000006207 00000 n
+0000006228 00000 n
+0000007010 00000 n
+0000007031 00000 n
+0000007787 00000 n
+0000007808 00000 n
+0000008568 00000 n
+0000008589 00000 n
+0000008999 00000 n
+0000009279 00000 n
+0000011745 00000 n
+0000001100 00000 n
+0000001268 00000 n
+trailer << /Size 35 /Info 1 0 R /Root 4 0 R /Prev 12112 /ID[<8db5c844284c4d38daa1aaf376efa260><8db5c844284c4d38daa1aaf376efa260>] >> startxref 0 %%EOF 4 0 obj << /Type /Catalog /Pages 2 0 R /OpenAction [ 5 0 R /XYZ null null null ] /PageMode /UseNone >> endobj 33 0 obj << /S 36 /Filter /FlateDecode /Length 34 0 R >> stream
+H�b``�c``+�40�O`����g� �<��%H@�+H�T����0��>�G��މ�����4q�Hĉ�t�ۓ�b�%���9��ֻ�L+YR�P�E�,H�[{m�l?_��f���H���M��jd���u�D)�!|_�;�,��+endstream endobj 9 0 obj << /Type /Encoding /Differences [ 1 /registersans ] >> endobj 10 0 obj << /Type /FontDescriptor /Ascent 891 /CapHeight 0 /Descent -216 /Flags 34 /FontBBox [ -77 -216 1009 877 ] /FontName /TimesNewRoman /ItalicAngle 0 /StemV 0 >> endobj 11 0 obj [ /Indexed 12 0 R 255 30 0 R ] endobj 12 0 obj [ /CalRGB << /WhitePoint [ 0.9505 1 1.089 ] /Gamma [ 2.22221 2.22221 2.22221 ] /Matrix [ 0.4124 0.2126 0.0193 0.3576 0.71519 0.1192 0.1805 0.0722 0.9505 ] >> ] endobj 13 0 obj << /Type /Font /Subtype /TrueType /FirstChar 32 /LastChar 121 /Widths [ 250 0 0 0 0 0 0 180 333 333 500 0 250 333 250 278 500 500 500 500 500 500 500 500 500 500 278 278 0 0 0 0 0 722 667 667 722 611 556 722 722 333 389 0 611 889 722 722 556 722 667 556 611 722 722 944 722 722 0 0 0 0 0 0 333 444 500 444 500 444 333 500 500 278 0 500 278 778 500 500 500 0 333 389 278 500 500 722 500 500 ] /Encoding /WinAnsiEncoding /BaseFont /TimesNewRoman /FontDescriptor 10 0 R >> endobj 14 0 obj 757 endobj 15 0 obj << /Filter /FlateDecode /Length 14 0 R >> stream
+H��TMo�@U���9�Jf�,�^�(UrhU�����ʱ[ M��;3�8�*��%3��f����M�)���\�����
+��+h���c��c��N�um ��!�������QFk5�l�ډ��6I�Ҙ�&�����ad�9U+S�U�$+|�2�L+�Ō�B9,
+�;k%�Q���ndZ���}?˻�:��2��6����hgDY}�G�rb�E0\�-��Qjؒ���d��f0^�g�O�*ԯ8��Q5"ˢ���V��X��(z���օ��'��DR �W>�:�͔պ����3x_7�/�译����`�/iH�����,��ܻ���eL܁;}3����ϲ���/#����$�i���o8��9��/L�b��-�NA�^i�'m�54�>�<�.�����pκ? [jnd��mp���w�̌�: M���1�<�y^DCHX�G���+=��}LÍ���餸��F�^�A��$�� �KaA�9h�mѡ ̻�P+"�퉵N�9��>�k��� ���yȍ�V��Q�L�ၷnp<��8P�2f>�8�?���rx5��O"^�u�����^��|a]ub]���7��H��[1���m��C�Á��>��;��B;�xb� "DF2b��"a�8�},հ>����1��x�B�v�B��ãf�G`�M9����{Z�?'RP�%���������q1?KS*bo�L���X�n���$�̯��+H�dT�n�0��+�H� �Z��\�C�NP��A�G�b�����'�Egy3on�/�_E^��;+��e�+�j@�
++� �@��[>������+�6�BC�7XU�}0"��� ��%�P�g�%ԟ� g�� �WR�Az��ju���L�D�ǽ� �N���~�y�tWB2^&KzY�3X��Q��8YV��@��8��ئP2Q�a�݀�L#MDC(�d��$V�Fʖ�lÏG�y�m�#i���~F����)Z�*h]����}��h!�>A(gA���+H�tTMo�0��W�( �`��w+��v|[{p51�5��)�� l�D��G>�Oݏ]�2g]Uת���m�{��!��Vu��/���i��1�t���n2Wk�4��z�+��y��P7/�ׄ�He}6�-uP�)�+[�i�{�W���>s�BR�>�_5���}?�kl�gq>�5e��b9&�CP�����aQ�T�+ y�7����h�P��q�L�Qm ����l��B�ګH���{��TL�-J��w�'~ ��%���"�w��*LL�}�z�j�+0+H�tT�n�0��,E`͈:�~�-w��,�dˠh��g�R�mD���x���&U[k�r��7�I�ԪC�JK����{w�����^�f�L��GQ<uel���Z��<��ΦI�hw�Y�dRӸ�sz[PX۩z�t�I�� �V��"ݴ�!2��}��U9���7����+�����_ٷS�q��:��ξp��C���U\�\D���~��2�I 1�j�&ծ����v�չ�瞚U�qf0ƞ���eUŕV^�����),u[S$�.I���0e���P"(�mSSъD�t�I�3�O���v+:hY�t�3J�k�[0�hχ���ܢ�x��w�Q����x�aQY�����r�YN�?��`}�� JD��O��,��ȁ9�+�����^�ˎ�E-�6�-���x+�Ģ!�Ԥ �7C+H�lT=��0��+�D��A�mH�I��"]&J�< ߍ�}�Kܤ1�~�ݷ^����Cj������!��<����T��};�H���4A7�Ԟ��jNY�8�e�d�2�1Ϛ�b�cvJ~��Xd6y1�Ɋ����汛4~Yc����N��rr_k�m_◩)�sc�l�/n/}�Ľ�]+\ ����~���A[^��������PU���^±A@�� �g�|�D���wS��+O�+%�b��b��<�L��^!pE����m�^jF>[�+�0'g��;�a�+�~Ga�v�o[cl@!��J)-{�`xvp�\�]*8�2xE�q��]ŃJ���e`J��k��+n�R+H�lT�n�0��+��� Q�me��Yhq(9�QЏ��wRv�^,s�f{o����������)3Y�������KX~?�T���t�Eome*u��?���l?�vo����)8��mmjt����w��ӄ���T��ع���g��a^oKcU�F,�H*u�rl�(�.�'�~LyP�R�1���Oc#7������D�lY�V����a/la��䊂[d�<�v��%r<���?W�!.�'>��1��Ll������Je�������"�AW���9a+Tg��&s��]�4&�LDZ�����V't�fH#w_��N��IΥW+����c
+��b.�g�U5�U������)��j�W��B�P�GA����-V��[i�}�����W�Ţ/����,(�MӌKZ"7��t^L�d45=�+H��uPq�ܛ�f���M���:���s��}�Bw�\iY�g*a C)��獱&>G1�gx���z�gy�6&��:�L_8���YU��}�E#t�!/���L(*��He�'O����4�3���z~`�x��[�b�˽�!�{��^�m���h�qJ5͚0�zM�}#��S�0Aj`�d�����+H�|TMo�0��W�( �k���)��DEc ��"Xz��!X�튡�~�D9M�d����������a��2M6�Y|�G���N4|�L��w"?X7K�ID�'o!��/덐2n.|�E���iQ���R`������|K2Q|9�4m ��j��Ǭ����)<
+�k�隟#�6�t���Y5��sռ� �#CT�B����< ���v��H�2�K6vPƤHJ_�ɪ%�V3n���D�k�k�2x�mu���u�e&�7�7�Q���W{5�֧#|����b�C��llI�>�\b��)3�.Ci��(�8}q���E��B���`����!��=�+IpK��"�b0���e֬GBX0�0C=���e�t{����$�q-`�����L��$�^'̬L`\܆��Z(h���לnwn��2Ҟ��h��s�?�)��n���a.�8/���Q+�@��=�=A�o~��`$�������H�Bs��3��px ��_�,��|����e/���ƛ����黈
+��S ���m7�IwU*��|�'��",�Q4�}:=�+H�\QMK1�ﯘcRLH�;W��E�����lc mwe[��;+��L^7o֮
+�(�TJ�`�X�5��b�����f�t�\�\T�c���>�k����#��B��R7-�-�^IʪO�K?��:�w��[�y) ��{Y�- ��Cw]c�?�K�륪A���
+���BWc����俀 A�% {�#�%<� N�s��g��{�9$.Cb�9��]����;\�K~�у;�N���8R����`?�^È�}0�1,�O��3ND��:�hdl+�d7�MR^��11��a�qb��<����0+���}�&��0߃-+H�b``�ͬu��}=�(''g����8�r����mM###����gQ�2�K�����?m.ikkM�9>{挖��-��nݺ�[o~߳����[�=|{v���O^}��ַ[�n��u����O�>�������~~z����}��}���ߏ��������?�?����������������߯��}���������$��g��z+endstream endobj 31 0 obj << /Type /XObject /Subtype /Image /Width 156 /Height 81 /BitsPerComponent 8 /ColorSpace 11 0 R /Length 2298 /Filter /FlateDecode >> stream
+H�̗�r���f�,��`0q";7��*_��lw�$��äV����T�ҧ����ڦ��aհ5�'6��털l��ކ4��ǭ9��p�rR��j�o���c����;�|�
+>O������8���-C�<%{��P��I�Q\�� ����j&��4���w�X����;�$6$�P�c&�-#K�\�4�����i��� =;�Y`9��*l�`�I�j�N���UU�б/����V�.Q������ƀ-�o���]|05,��Z��J� � Us@���3�;�Ee�'�bZK�sv���~���K��sV���N����\�W>�q��c�[9G����C9.��_�ņ٥) %��i%��0�lʼne�p���~�d����n241�-5p����ܹ �~띕F��qp5����0��7��!�TR�E�9�'3tC�I�dgN����5�U����������Bf+-3�BL�^h�?��͂��Kl�ү�M��* ]e����"Ƌ�M٢n連��A�cDy4FD�%�����5���;R=Q+��ھ�� T\��Khp
+�%�l�W�\+��,+h�$�3�l��A���ѳɡ�R�K4��O�m�d+H��B���hř'/V��;68v�u �E��c;�Oo+��D���SR�>�[F04�ۺ(�,��V��l�� P51"��|�TnBq��F��`�+b�0#��UF�s�B�f�/���̓l8[Vp�;��R�!��!�ؓ
+8ϳ��$7*^�G�8R�>����wFZڨ��EP��ྡྷ���4�y�m��KM����P���z~�CT
+��<��d�,E���2��#�!����(��R$�Dn�:��'�(*�8�����j���<�9�EpD����}R��!,����_�ֶ���-�Ri�#�.�p"���r;6�+�G:�+_a��B��>0#��<ow%����m���Gt3��m��츷�a���O�v��hӡ�<�gG��V��'�t<�d����k��+endstream endobj 32 0 obj << /Type /ExtGState /SA false /SM 0.02 /TR /Identity >> endobj 1 0 obj << /Producer (Acrobat Distiller 4.05 for Windows) /Creator (Microsoft Word 8.0) /ModDate (D:20020123204028-08'00') /Author (Bill Broderick) /Title (Dear Unix enthusiasts,) /CreationDate (D:20020123203956) >> endobj 2 0 obj << /Type /Pages /Kids [ 5 0 R ] /Count 1 >> endobj xref 0 3 0000000000 65535 f
+0000011823 00000 n
+0000012048 00000 n
+trailer << /Size 3 /ID[<8db5c844284c4d38daa1aaf376efa260><8db5c844284c4d38daa1aaf376efa260>] >> startxref 173 %%EOF
\ No newline at end of file
--- /dev/null
+++ b/lib/legal/lucent
@@ -1,0 +1,237 @@
+Lucent Public License Version 1.02
+
+THE ACCOMPANYING PROGRAM IS PROVIDED UNDER THE TERMS OF THIS PUBLIC
+LICENSE ("AGREEMENT"). ANY USE, REPRODUCTION OR DISTRIBUTION OF THE
+PROGRAM CONSTITUTES RECIPIENT'S ACCEPTANCE OF THIS AGREEMENT.
+
+1. DEFINITIONS
+
+"Contribution" means:
+
+ a. in the case of Lucent Technologies Inc. ("LUCENT"), the Original
+ Program, and
+ b. in the case of each Contributor,
+
+ i. changes to the Program, and
+ ii. additions to the Program;
+
+ where such changes and/or additions to the Program were added to the
+ Program by such Contributor itself or anyone acting on such
+ Contributor's behalf, and the Contributor explicitly consents, in
+ accordance with Section 3C, to characterization of the changes and/or
+ additions as Contributions.
+
+"Contributor" means LUCENT and any other entity that has Contributed a
+Contribution to the Program.
+
+"Distributor" means a Recipient that distributes the Program,
+modifications to the Program, or any part thereof.
+
+"Licensed Patents" mean patent claims licensable by a Contributor
+which are necessarily infringed by the use or sale of its Contribution
+alone or when combined with the Program.
+
+"Original Program" means the original version of the software
+accompanying this Agreement as released by LUCENT, including source
+code, object code and documentation, if any.
+
+"Program" means the Original Program and Contributions or any part
+thereof
+
+"Recipient" means anyone who receives the Program under this
+Agreement, including all Contributors.
+
+2. GRANT OF RIGHTS
+
+ a. Subject to the terms of this Agreement, each Contributor hereby
+ grants Recipient a non-exclusive, worldwide, royalty-free copyright
+ license to reproduce, prepare derivative works of, publicly display,
+ publicly perform, distribute and sublicense the Contribution of such
+ Contributor, if any, and such derivative works, in source code and
+ object code form.
+
+ b. Subject to the terms of this Agreement, each Contributor hereby
+ grants Recipient a non-exclusive, worldwide, royalty-free patent
+ license under Licensed Patents to make, use, sell, offer to sell,
+ import and otherwise transfer the Contribution of such Contributor, if
+ any, in source code and object code form. The patent license granted
+ by a Contributor shall also apply to the combination of the
+ Contribution of that Contributor and the Program if, at the time the
+ Contribution is added by the Contributor, such addition of the
+ Contribution causes such combination to be covered by the Licensed
+ Patents. The patent license granted by a Contributor shall not apply
+ to (i) any other combinations which include the Contribution, nor to
+ (ii) Contributions of other Contributors. No hardware per se is
+ licensed hereunder.
+
+ c. Recipient understands that although each Contributor grants the
+ licenses to its Contributions set forth herein, no assurances are
+ provided by any Contributor that the Program does not infringe the
+ patent or other intellectual property rights of any other entity. Each
+ Contributor disclaims any liability to Recipient for claims brought by
+ any other entity based on infringement of intellectual property rights
+ or otherwise. As a condition to exercising the rights and licenses
+ granted hereunder, each Recipient hereby assumes sole responsibility
+ to secure any other intellectual property rights needed, if any. For
+ example, if a third party patent license is required to allow
+ Recipient to distribute the Program, it is Recipient's responsibility
+ to acquire that license before distributing the Program.
+
+ d. Each Contributor represents that to its knowledge it has sufficient
+ copyright rights in its Contribution, if any, to grant the copyright
+ license set forth in this Agreement.
+
+3. REQUIREMENTS
+
+A. Distributor may choose to distribute the Program in any form under
+this Agreement or under its own license agreement, provided that:
+
+ a. it complies with the terms and conditions of this Agreement;
+
+ b. if the Program is distributed in source code or other tangible
+ form, a copy of this Agreement or Distributor's own license agreement
+ is included with each copy of the Program; and
+
+ c. if distributed under Distributor's own license agreement, such
+ license agreement:
+
+ i. effectively disclaims on behalf of all Contributors all warranties
+ and conditions, express and implied, including warranties or
+ conditions of title and non-infringement, and implied warranties or
+ conditions of merchantability and fitness for a particular purpose;
+ ii. effectively excludes on behalf of all Contributors all liability
+ for damages, including direct, indirect, special, incidental and
+ consequential damages, such as lost profits; and
+ iii. states that any provisions which differ from this Agreement are
+ offered by that Contributor alone and not by any other party.
+
+B. Each Distributor must include the following in a conspicuous
+ location in the Program:
+
+ Copyright (C) 2003, Lucent Technologies Inc. and others. All Rights
+ Reserved.
+
+C. In addition, each Contributor must identify itself as the
+originator of its Contribution in a manner that reasonably allows
+subsequent Recipients to identify the originator of the Contribution.
+Also, each Contributor must agree that the additions and/or changes
+are intended to be a Contribution. Once a Contribution is contributed,
+it may not thereafter be revoked.
+
+4. COMMERCIAL DISTRIBUTION
+
+Commercial distributors of software may accept certain
+responsibilities with respect to end users, business partners and the
+like. While this license is intended to facilitate the commercial use
+of the Program, the Distributor who includes the Program in a
+commercial product offering should do so in a manner which does not
+create potential liability for Contributors. Therefore, if a
+Distributor includes the Program in a commercial product offering,
+such Distributor ("Commercial Distributor") hereby agrees to defend
+and indemnify every Contributor ("Indemnified Contributor") against
+any losses, damages and costs (collectively"Losses") arising from
+claims, lawsuits and other legal actions brought by a third party
+against the Indemnified Contributor to the extent caused by the acts
+or omissions of such Commercial Distributor in connection with its
+distribution of the Program in a commercial product offering. The
+obligations in this section do not apply to any claims or Losses
+relating to any actual or alleged intellectual property infringement.
+In order to qualify, an Indemnified Contributor must: a) promptly
+notify the Commercial Distributor in writing of such claim, and b)
+allow the Commercial Distributor to control, and cooperate with the
+Commercial Distributor in, the defense and any related settlement
+negotiations. The Indemnified Contributor may participate in any such
+claim at its own expense.
+
+For example, a Distributor might include the Program in a commercial
+product offering, Product X. That Distributor is then a Commercial
+Distributor. If that Commercial Distributor then makes performance
+claims, or offers warranties related to Product X, those performance
+claims and warranties are such Commercial Distributor's responsibility
+alone. Under this section, the Commercial Distributor would have to
+defend claims against the Contributors related to those performance
+claims and warranties, and if a court requires any Contributor to pay
+any damages as a result, the Commercial Distributor must pay those
+damages.
+
+5. NO WARRANTY
+
+EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, THE PROGRAM IS
+PROVIDED ON AN"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT LIMITATION, ANY
+WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, MERCHANTABILITY
+OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is solely
+responsible for determining the appropriateness of using and
+distributing the Program and assumes all risks associated with its
+exercise of rights under this Agreement, including but not limited to
+the risks and costs of program errors, compliance with applicable
+laws, damage to or loss of data, programs or equipment, and
+unavailability or interruption of operations.
+
+6. DISCLAIMER OF LIABILITY
+
+EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, NEITHER RECIPIENT NOR
+ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY DIRECT, INDIRECT,
+INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING
+WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND ON ANY THEORY OF
+LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OR
+DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED
+HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
+
+7. EXPORT CONTROL
+
+Recipient agrees that Recipient alone is responsible for compliance
+with the United States export administration regulations (and the
+export control laws and regulation of any other countries).
+
+8. GENERAL
+
+If any provision of this Agreement is invalid or unenforceable under
+applicable law, it shall not affect the validity or enforceability of
+the remainder of the terms of this Agreement, and without further
+action by the parties hereto, such provision shall be reformed to the
+minimum extent necessary to make such provision valid and enforceable.
+
+If Recipient institutes patent litigation against a Contributor with
+respect to a patent applicable to software (including a cross-claim or
+counterclaim in a lawsuit), then any patent licenses granted by that
+Contributor to such Recipient under this Agreement shall terminate as
+of the date such litigation is filed. In addition, if Recipient
+institutes patent litigation against any entity (including a
+cross-claim or counterclaim in a lawsuit) alleging that the Program
+itself (excluding combinations of the Program with other software or
+hardware) infringes such Recipient's patent(s), then such Recipient's
+rights granted under Section 2(b) shall terminate as of the date such
+litigation is filed.
+
+All Recipient's rights under this Agreement shall terminate if it
+fails to comply with any of the material terms or conditions of this
+Agreement and does not cure such failure in a reasonable period of
+time after becoming aware of such noncompliance. If all Recipient's
+rights under this Agreement terminate, Recipient agrees to cease use
+and distribution of the Program as soon as reasonably practicable.
+However, Recipient's obligations under this Agreement and any licenses
+granted by Recipient relating to the Program shall continue and
+survive.
+
+LUCENT may publish new versions (including revisions) of this
+Agreement from time to time. Each new version of the Agreement will be
+given a distinguishing version number. The Program (including
+Contributions) may always be distributed subject to the version of the
+Agreement under which it was received. In addition, after a new
+version of the Agreement is published, Contributor may elect to
+distribute the Program (including its Contributions) under the new
+version. No one other than LUCENT has the right to modify this
+Agreement. Except as expressly stated in Sections 2(a) and 2(b) above,
+Recipient receives no rights or licenses to the intellectual property
+of any Contributor under this Agreement, whether expressly, by
+implication, estoppel or otherwise. All rights in the Program not
+expressly granted under this Agreement are reserved.
+
+This Agreement is governed by the laws of the State of New York and
+the intellectual property laws of the United States of America. No
+party to this Agreement will bring a legal action under this Agreement
+more than one year after the cause of action arose. Each party waives
+its rights to a jury trial in any resulting litigation.
+
--- /dev/null
+++ b/lib/lego/llp.h
@@ -1,0 +1,4 @@
+#define LLP_ALTERNATING 0x01
+#define LLP_POLL_IMMEDIATE 0x02
+#define LLP_POLL_PERIODIC 0x04
+#define LLP_COMPRESSION 0x08
--- /dev/null
+++ b/lib/lego/styx.c
@@ -1,0 +1,1113 @@
+/*
+ * styx.c
+ *
+ * A Styx fileserver for a Lego RCX
+ *
+ * Nigel Roles
+ * Vita Nuova
+ *
+ * This is a heavily modified version of test5.c
+ *
+ * I couldn't have done this without Kekoa...
+ *
+ *
+ * The contents of this file are subject to the Mozilla Public License
+ * Version 1.0 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS"
+ * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
+ * License for the specific language governing rights and limitations
+ * under the License.
+ *
+ * The Original Code is Librcx sample program code, released February 9,
+ * 1999.
+ *
+ * The Initial Developer of the Original Code is Kekoa Proudfoot.
+ * Portions created by Kekoa Proudfoot are Copyright (C) 1999
+ * Kekoa Proudfoot. All Rights Reserved.
+ *
+ * Contributor(s): Kekoa Proudfoot <kekoa@graphics.stanford.edu>
+ */
+
+//#include "stdlib.h"
+#include "rom.h"
+
+#include "lib9.h"
+#include "styx.h"
+
+#include "llp.h"
+
+#define ASSERT(cond) if (!(cond)) fatal(__LINE__)
+#define FATAL fatal(__LINE__)
+#define PROGRESS progress(__LINE__)
+
+#if 0
+#define ABP
+#endif
+
+uchar *send_fid_reply_payload(void);
+void send_fid_reply(uchar type, ushort tag, ushort fid, uchar *msg, short len);
+void send_error_reply(unsigned short tag, char *msg);
+
+static unsigned short msgcount;
+static unsigned char compressed_incoming[150];
+static unsigned char incoming[1024];
+static unsigned char compressed_reply[150];
+short compressed_reply_len;
+static unsigned char reply[1024];
+unsigned short reply_len;
+unsigned short transmitted_reply_len;
+unsigned char alternating_bit;
+static uchar dir[116];
+uchar prepared;
+uchar reader_count;
+uchar dispatch[6];
+
+/* ROM pseudofunctions */
+
+static inline void
+set_data_pointer (void *ptr)
+{
+ play_sound_or_set_data_pointer(0x1771, (short)ptr, 0);
+}
+
+static inline char
+check_valid (void)
+{
+ char valid;
+ check_for_data(&valid, NULL);
+ return valid;
+}
+
+static inline int
+receive_message (void *ptr, int len)
+{
+ char bytes = 0;
+ receive_data(ptr, len, &bytes);
+ /* Bytes includes checksum, since we don't want that, return bytes-1 */
+ return bytes - 1;
+}
+
+static inline void
+send_message (void *ptr, int len)
+{
+ if (len)
+ while (send_data(0x1776, 0, ptr, len));
+}
+
+int
+poll_power(void)
+{
+ static short debounce = 0;
+ static short state = -1;
+ short status;
+ get_power_status(0x4000, &status);
+ if (state != status)
+ debounce = 0;
+ else if (debounce < 10)
+ debounce++;
+ state = status;
+ return debounce >= 10 ? state : -1;
+}
+
+static void
+progress(short line)
+{
+ set_lcd_number(LCD_UNSIGNED, line, LCD_DECIMAL_0);
+ refresh_display();
+}
+
+static void
+fatal(short line)
+{
+ set_lcd_segment(LCD_STANDING);
+ progress(line);
+ while (poll_power() != 0)
+ ;
+}
+
+typedef struct Reader {
+ ushort tag;
+ ushort fid;
+ ushort offset;
+ ushort count;
+ struct Reader *next;
+} Reader;
+
+typedef struct DirectoryEntry {
+ char *name;
+ uchar qid;
+ const struct DirectoryEntry *sub;
+ short (*read)(const struct DirectoryEntry *dp, ushort tag, ushort fid, ushort offset, ushort count);
+ short (*write)(const struct DirectoryEntry *dp, ushort offset, ushort count, uchar *buf);
+} DirectoryEntry;
+
+#define QID_ROOT 0
+#define QID_MOTOR 1
+#define QID_MOTOR_0 2
+#define QID_MOTOR_1 3
+#define QID_MOTOR_2 4
+#define QID_MOTOR_012 5
+#define QID_SENSOR 6
+#define QID_SENSOR_0 7
+#define QID_SENSOR_1 8
+#define QID_SENSOR_2 9
+
+typedef struct Sensor {
+ sensor_t sensor;
+ uchar active;
+ uchar greater;
+ ushort thresh;
+ Reader *reader;
+} Sensor;
+
+Sensor sensor[3];
+
+short
+atoin(char *s, short lim)
+{
+ short total = 0;
+ while (*s && lim) {
+ char c = *s++;
+ if (c >= '0' && c <= '9')
+ total = total * 10 + c - '0';
+ else
+ break;
+ lim--;
+ }
+ return total;
+}
+
+short
+itoa(char *buf, short value)
+{
+ char *bp = buf;
+ short divisor;
+ if (value < 0) {
+ *bp++ = '-';
+ value = -value;
+ }
+ if (value == 0)
+ *bp++ = '0';
+ else {
+ divisor = 10000;
+ while (divisor > value)
+ divisor /= 10;
+ while (divisor) {
+ *bp++ = '0' + value / divisor;
+ value %= divisor;
+ divisor /= 10;
+ }
+ }
+ return bp - buf;
+}
+
+Reader *
+readercreate(ushort tag, ushort fid, ushort offset, ushort count)
+{
+ Reader *rp = malloc(sizeof(Reader));
+ rp->tag = tag;
+ rp->fid = fid;
+ rp->offset = offset;
+ rp->count = count;
+ rp->next = 0;
+ reader_count++;
+ return rp;
+}
+
+void
+readerfree(Reader *rp)
+{
+ free(rp);
+ reader_count--;
+}
+
+int
+senderrorreset(Reader *rp, void *magic)
+{
+ send_error_reply(rp->tag, "reset");
+ return 1;
+}
+
+void
+readerlistfindanddestroy(Reader **rpp, int (*action)(Reader *rp, void *magic), void *magic)
+{
+ while (*rpp) {
+ Reader *rp = *rpp;
+ if ((*action)(rp, magic)) {
+ *rpp = rp->next;
+ readerfree(rp);
+ }
+ else
+ rpp = &(rp->next);
+ }
+}
+
+void
+allreaderlistfindanddestroy(int (*action)(Reader *rp, void *magic), void *magic)
+{
+ short i;
+ for (i = 0; i < 3; i++)
+ readerlistfindanddestroy(&sensor[i].reader, action, magic);
+}
+
+short
+sensorwrite(const DirectoryEntry *dp, ushort offset, ushort count, uchar *data)
+{
+ short i;
+ Sensor *sp;
+ uchar greater;
+ short type, mode;
+ ushort k;
+
+ if (offset != 0)
+ return -1;
+ i = dp->qid - QID_SENSOR_0;
+ sp = &sensor[i];
+ k = count;
+ if (k == 0)
+ return -1;
+ switch (data[0]) {
+ case 'b':
+ type = SENSOR_TYPE_TOUCH;
+ mode = SENSOR_MODE_PULSE;
+ break;
+ case 'l':
+ type = SENSOR_TYPE_TOUCH;
+ mode = SENSOR_MODE_RAW;
+ break;
+ default:
+ return -1;
+ }
+ data++; k--;
+ if (k == 0)
+ return -1;
+ if (*data == '>') {
+ greater = 1;
+ data++;
+ k--;
+ }
+ else if (*data == '<') {
+ greater = 0;
+ data++;
+ k--;
+ }
+ else
+ greater = 1;
+ if (k == 0)
+ return -1;
+ readerlistfindanddestroy(&sp->reader, senderrorreset, 0);
+ set_sensor_passive(SENSOR_0 + i);
+ sp->sensor.type = type;
+ sp->sensor.mode = mode;
+ sp->thresh = atoin(data, k);
+ sp->sensor.raw = 0;
+ sp->sensor.value = 0;
+ sp->sensor.boolean = 0;
+ sp->active = 1;
+ sp->greater = greater;
+ set_sensor_active(SENSOR_0 + i);
+ return count;
+}
+
+void
+send_read_reply(ushort tag, ushort fid, ushort offset, ushort len, uchar *answer, short answerlen)
+{
+ uchar *out = send_fid_reply_payload();
+ ushort actual;
+ if (offset < answerlen) {
+ actual = answerlen - offset;
+ if (actual > len)
+ actual = len;
+ memcpy(out + 3, answer + offset, actual);
+ }
+ else
+ actual = 0;
+ out[0] = actual;
+ out[1] = actual >> 8;
+ out[2] = 0;
+ send_fid_reply(Rread, tag, fid, 0, actual + 3);
+}
+
+void
+send_sensor_read_reply(ushort tag, ushort fid, ushort offset, ushort count, short value)
+{
+ short answerlen;
+ char answer[8];
+ /* reply is countlow counthigh pad data[count] */
+ answerlen = itoa(answer, value);
+ send_read_reply(tag, fid, offset, count, answer, answerlen);
+}
+
+int
+sensortriggered(Sensor *sp)
+{
+ if (sp->greater)
+ return sp->sensor.value >= sp->thresh;
+ else
+ return sp->sensor.value < sp->thresh;
+}
+
+short
+sensorread(const struct DirectoryEntry *dp, ushort tag, ushort fid, ushort offset, ushort count)
+{
+ short i;
+ Sensor *sp;
+ i = dp->qid - QID_SENSOR_0;
+ sp = sensor + i;
+ if (!sp->active)
+ return -1;
+ if (sensortriggered(sp))
+ send_sensor_read_reply(tag, fid, offset, count, sp->sensor.value);
+ else {
+ /* add to queue */
+ Reader *rp = readercreate(tag, fid, offset, count);
+ rp->next = sp->reader;
+ sp->reader = rp;
+ }
+ return 0;
+}
+
+void
+sensorpoll(void)
+{
+ short i;
+ Sensor *sp;
+
+ if ((dispatch[0] & 0x80) == 0) {
+ return;
+ }
+ dispatch[0] &= 0x7f;
+ /* do the following every 3 ms with a following wind */
+ for (i = 0; i < 3; i++) {
+ sp = sensor + i;
+ if (sp->active) {
+ /*
+ * read sensor 4 times to reduce debounce on each
+ * edge to effectively 25 counts, or 75ms
+ * allowing about 8 pulses a second
+ */
+ read_sensor(SENSOR_0 + i, &sp->sensor);
+ read_sensor(SENSOR_0 + i, &sp->sensor);
+ read_sensor(SENSOR_0 + i, &sp->sensor);
+ read_sensor(SENSOR_0 + i, &sp->sensor);
+ if (sensortriggered(sp)) {
+ /* complete any outstanding reads */
+ while (sp->reader) {
+ Reader *rp = sp->reader;
+ sp->reader = rp->next;
+ send_sensor_read_reply(rp->tag, rp->fid, rp->offset, rp->count, sp->sensor.value);
+ readerfree(rp);
+ }
+ }
+ }
+ }
+}
+
+short
+motorparse(uchar *flag, short *mode, short *power, uchar *data)
+{
+ switch (data[0]) {
+ case 'f': *mode = MOTOR_FWD; break;
+ case 'r': *mode = MOTOR_REV; break;
+ case 's': *mode = MOTOR_STOP; break;
+ case 'F': *mode = MOTOR_FLOAT; break;
+ case '-': return 1;
+ default:
+ return 0;
+ }
+ if (data[1] >= '0' && data[1] <= '7')
+ *power = data[1] - '0';
+ else
+ return 0;
+ *flag = 1;
+ return 1;
+}
+
+short
+motorwrite(const DirectoryEntry *dp, ushort offset, ushort count, uchar *data)
+{
+ short mode[3], power[3];
+ uchar flag[3];
+ short i;
+
+ if (offset != 0)
+ return -1;
+ flag[0] = flag[1] = flag[2] = 0;
+ if (dp->qid == QID_MOTOR_012) {
+ if (count != 6)
+ return -1;
+ if (!motorparse(flag, mode, power, data)
+ || !motorparse(flag + 1, mode + 1, power + 1, data + 2)
+ || !motorparse(flag + 2, mode + 2, power + 2, data + 4))
+ return -1;
+ }
+ else {
+ if (count != 2)
+ return -1;
+ i = dp->qid - QID_MOTOR_0;
+ if (!motorparse(flag + i, mode + i, power + i, data))
+ return -1;
+ }
+ for (i = 0; i < 3; i++)
+ if (flag[i])
+ control_motor(MOTOR_0 + i, mode[i], power[i]);
+ return count;
+}
+
+const uchar qid_root[8] = { QID_ROOT, 0, 0, 0x80 };
+
+const DirectoryEntry dir_root[], dir_slash[];
+
+const DirectoryEntry dir_motor[] = {
+ { "..", QID_ROOT, dir_root },
+ { "0", QID_MOTOR_0, 0, 0, motorwrite },
+ { "1", QID_MOTOR_1, 0, 0, motorwrite },
+ { "2", QID_MOTOR_2, 0, 0, motorwrite },
+ { "012", QID_MOTOR_012, 0, 0, motorwrite },
+ { 0 }
+};
+
+const DirectoryEntry dir_sensor[] = {
+ { "..", QID_ROOT, dir_root },
+ { "0", QID_SENSOR_0, 0, sensorread, sensorwrite },
+ { "1", QID_SENSOR_1, 0, sensorread, sensorwrite },
+ { "2", QID_SENSOR_2, 0, sensorread, sensorwrite },
+ { 0 }
+};
+
+const DirectoryEntry dir_root[] = {
+ { "..", QID_ROOT, dir_slash },
+ { "motor", QID_MOTOR, dir_motor },
+ { "sensor", QID_SENSOR, dir_sensor },
+ { 0 }
+};
+
+const DirectoryEntry dir_slash[] = {
+ { "/", QID_ROOT, dir_root },
+ { 0 }
+};
+
+const DirectoryEntry *qid_map[] = {
+ /* QID_ROOT */ &dir_slash[0],
+ /* QID_MOTOR */ &dir_root[1],
+ /* QID_MOTOR_0 */ &dir_motor[1],
+ /* QID_MOTOR_1 */ &dir_motor[2],
+ /* QID_MOTOR_2 */ &dir_motor[3],
+ /* QID_MOTOR_012 */ &dir_motor[4],
+ /* QID_SENSOR */ &dir_root[2],
+ /* QID_SENSOR_0 */ &dir_sensor[1],
+ /* QID_SENSOR_1 */ &dir_sensor[2],
+ /* QID_SENSOR_2 */ &dir_sensor[3],
+};
+
+#define QID_MAP_MAX (sizeof(qid_map) / sizeof(qid_map[0]))
+
+typedef struct Fid {
+ struct Fid *next;
+ ushort fid;
+ uchar open;
+ uchar qid[8];
+} Fid;
+
+Fid *fids;
+
+Fid *
+fidfind(ushort fid)
+{
+ Fid *fp;
+ for (fp = fids; fp && fp->fid != fid; fp = fp->next)
+ ;
+ return fp;
+}
+
+Fid *
+fidcreate(ushort fid, const uchar qid[8])
+{
+ Fid *fp;
+ fp = malloc(sizeof(Fid));
+ ASSERT(fp);
+ fp->open = 0;
+ fp->fid = fid;
+ fp->next = fids;
+ memcpy(fp->qid, qid, 8);
+ fids = fp;
+ return fp;
+}
+
+int
+matchfp(Reader *rp, void *magic)
+{
+ if (rp->fid == ((Fid *)magic)->fid) {
+ return 1;
+ }
+ return 0;
+}
+
+void
+fiddelete(Fid *fp)
+{
+ Fid **fpp;
+ /* clobber any outstanding reads on this fid */
+ allreaderlistfindanddestroy(matchfp, fp);
+ /* now clobber the fid */
+ for (fpp = &fids; *fpp; fpp = &(*fpp)->next)
+ if (*fpp == fp) {
+ *fpp = fp->next;
+ free(fp);
+ return;
+ }
+ FATAL;
+}
+
+const DirectoryEntry *
+nthentry(const DirectoryEntry *dp, ushort n)
+{
+ const DirectoryEntry *sdp;
+ ASSERT(dp->sub);
+ for (sdp = dp->sub; sdp->name; sdp++)
+ if (strcmp(sdp->name, "..") != 0) {
+ if (n == 0)
+ return sdp;
+ n--;
+ }
+ return 0;
+}
+
+int
+fidwalk(Fid *fp, char name[28])
+{
+ const DirectoryEntry *sdp;
+ const DirectoryEntry *dp;
+
+ if (fp->open)
+ return -1;
+ ASSERT(fp->qid[0] < QID_MAP_MAX);
+ dp = qid_map[fp->qid[0]];
+ if (dp->sub == 0)
+ return -1;
+ for (sdp = dp->sub; sdp->name; sdp++)
+ if (strcmp(sdp->name, name) == 0) {
+ fp->qid[0] = sdp->qid;
+ fp->qid[3] = sdp->sub ? 0x80 : 0;
+ return 1;
+ }
+ return 0;
+}
+
+void
+mkdirent(const DirectoryEntry *dp, uchar *dir)
+{
+ memset(dir, 0, DIRLEN);
+ strcpy(dir, dp->name);
+ strcpy(dir + 28, "lego");
+ strcpy(dir + 56, "lego");
+ dir[84] = dp->qid;
+ dir[92] = dp->sub ? 0555 : 0666;
+ dir[93] = dp->sub ? (0555 >> 8) : (0666 >> 8);
+ dir[95] = dp->sub ? 0x80 : 0;
+}
+
+int
+fidstat(Fid *fp, uchar *dir)
+{
+ const DirectoryEntry *dp;
+ if (fp->open)
+ return -1;
+ ASSERT(fp->qid[0] < QID_MAP_MAX);
+ dp = qid_map[fp->qid[0]];
+ mkdirent(dp, dir);
+ return 1;
+}
+
+int
+fidopen(Fid *fp, uchar mode)
+{
+ if (fp->open
+ || (mode & ORCLOSE)
+ /*|| (mode & OTRUNC) */)
+ return 0;
+ if (fp->qid[3] && (mode == OWRITE || mode == ORDWR))
+ /* can't write directories */
+ return 0;
+ fp->open = 1;
+ return 1;
+}
+
+short
+fidread(Fid *fp, ushort tag, ushort offset, ushort count)
+{
+ short k;
+ uchar *p;
+ const DirectoryEntry *dp;
+ uchar *buf;
+
+ ASSERT(fp->qid[0] < QID_MAP_MAX);
+ dp = qid_map[fp->qid[0]];
+
+ if (fp->qid[3] & 0x80) {
+ if (!fp->open)
+ return -1;
+ if (count % DIRLEN != 0 || offset % DIRLEN != 0)
+ return -1;
+ count /= DIRLEN;
+ offset /= DIRLEN;
+ buf = send_fid_reply_payload();
+ p = buf + 3;
+ for (k = 0; k < count; k++) {
+ const DirectoryEntry *sdp = nthentry(dp, offset + k);
+ if (sdp == 0)
+ break;
+ mkdirent(sdp, p);
+ p += DIRLEN;
+ }
+/* a read beyond just returns 0
+ if (k == 0 && count)
+ return -1;
+*/
+ k *= DIRLEN;
+ buf[0] = k;
+ buf[1] = k >> 8;
+ buf[2] = 0;
+ send_fid_reply(Rread, tag, fp->fid, 0, k + 3);
+ return 0;
+ }
+ /* right, that's that out of the way */
+ if (!dp->read)
+ return -1;
+ return (*dp->read)(dp, tag, fp->fid, offset, count);
+}
+
+short
+fidwrite(Fid *fp, ushort offset, ushort count, uchar *buf)
+{
+ const DirectoryEntry *dp;
+ if (fp->qid[3] & 0x80)
+ return -1; /* can't write directories */
+ if (!fp->open)
+ return -1;
+ ASSERT(fp->qid[0] < QID_MAP_MAX);
+ dp = qid_map[fp->qid[0]];
+ if (!dp->write)
+ return -1; /* no write method */
+ return (*dp->write)(dp, offset, count, buf);
+}
+
+int
+rlencode(unsigned char *out, int limit, unsigned char *in, int len)
+{
+ unsigned char *ip, *op;
+ int oc, zc;
+
+ if (len == 0)
+ return -1;
+ ip = in;
+ op = out;
+ zc = 0;
+
+ oc = 0;
+
+ for (;;) {
+ int last = ip >= in + len;
+ if (*ip != 0 || last)
+ {
+ switch (zc) {
+ case 1:
+ if (oc >= len - 1)
+ return -1;
+ *op++ = 0;
+ oc++;
+ break;
+ case 2:
+ if (oc >= len - 2)
+ return -1;
+ *op++ = 0;
+ *op++ = 0;
+ oc += 2;
+ break;
+ case 0:
+ break;
+ default:
+ if (oc >= len - 2)
+ return -1;
+ *op++ = 0x88;
+ *op++ = zc - 2;
+ oc += 2;
+ break;
+ }
+ zc = 0;
+ }
+ if (last)
+ break;
+ if (*ip == 0x88) {
+ if (oc >= len - 2)
+ return -1;
+ *op++ = 0x88;
+ *op++ = 0x00;
+ oc += 2;
+ }
+ else if (*ip == 0x00)
+ {
+ zc++;
+ }
+ else {
+ if (oc >= len - 1)
+ return -1;
+ *op++ = *ip;
+ oc++;
+ }
+ ip++;
+ }
+ return oc;
+}
+
+int
+rldecode(unsigned char *out, unsigned char *in, int len)
+{
+ int oc, k;
+
+ oc = 0;
+
+ while (len) {
+ if (*in != 0x88) {
+ *out++ = *in++;
+ oc++;
+ len--;
+ continue;
+ }
+ in++;
+ switch (*in) {
+ case 0:
+ *out++ = 0x88;
+ oc++;
+ break;
+ default:
+ k = *in + 2;
+ oc += k;
+ while (k-- > 0)
+ *out++ = 0;
+ }
+ in++;
+ len -= 2;
+ }
+ return oc;
+}
+
+void
+prepare_transmission(void)
+{
+ if (prepared)
+ return;
+ compressed_reply_len = rlencode(compressed_reply + 3, sizeof(compressed_reply) - 3, reply, reply_len);
+ if (compressed_reply_len < 0) {
+ memcpy(compressed_reply + 3, reply, reply_len);
+ compressed_reply_len = reply_len;
+ compressed_reply[2] = 0x0;
+ }
+ else
+ compressed_reply[2] = LLP_COMPRESSION;
+ if (reader_count)
+ compressed_reply[2] |= LLP_POLL_PERIODIC;
+ compressed_reply[2] |= !alternating_bit;
+ compressed_reply_len++;
+ compressed_reply[0] = compressed_reply_len;
+ compressed_reply[1] = compressed_reply_len >> 8;
+ compressed_reply_len += 2;
+ prepared = 1;
+}
+
+void
+transmit(void)
+{
+ prepare_transmission();
+ transmitted_reply_len = reply_len;
+ send_message(compressed_reply, compressed_reply_len);
+}
+
+void
+flush_reply_buffer(void)
+{
+ if (reply_len > transmitted_reply_len)
+ memcpy(reply, reply + transmitted_reply_len, reply_len - transmitted_reply_len);
+ reply_len -= transmitted_reply_len;
+ prepared = 0;
+}
+
+void
+send_reply(unsigned char type, unsigned short tag, unsigned char *msg, short len)
+{
+ uchar *p = reply + reply_len;
+ p[0] = type;
+ p[1] = tag & 0xff;
+ p[2] = tag >> 8;
+ if (msg)
+ memcpy(p + 3, msg, len);
+ reply_len += len + 3;
+ prepared = 0;
+}
+
+void
+send_error_reply(unsigned short tag, char *msg)
+{
+ short len;
+ uchar *p = reply + reply_len;
+ p[0] = Rerror;
+ p[1] = tag & 0xff;
+ p[2] = tag >> 8;
+ len = (short)strlen(msg);
+ if (len > 64)
+ len = 64;
+ memcpy(p + 3, msg, len);
+ reply_len += 67;
+ prepared = 0;
+}
+
+uchar *
+send_fid_reply_payload(void)
+{
+ return reply + reply_len + 5;
+}
+
+void
+send_fid_reply(uchar type, ushort tag, ushort fid, uchar *msg, short len)
+{
+ uchar *p = reply + reply_len;
+ p[0] = type;
+ p[1] = tag & 0xff;
+ p[2] = tag >> 8;
+ p[3] = fid & 0xff;
+ p[4] = fid >> 8;
+ if (msg)
+ memcpy(p + 5, msg, len);
+ reply_len += len + 5;
+ prepared = 0;
+}
+
+int
+matchtag(Reader *rp, void *oldtag)
+{
+ if (rp->tag == (ushort)oldtag) {
+ return 1;
+ }
+ return 0;
+}
+
+void
+flushtag(ushort oldtag)
+{
+ /* a little inefficient this - there can be at most one match! */
+ allreaderlistfindanddestroy(matchtag, (void *)oldtag);
+}
+
+void
+process_styx_message(unsigned char *msg, short len)
+{
+ unsigned char type;
+ ushort tag, oldtag, fid, newfid;
+ ushort offset, count;
+ short extra;
+ Fid *fp, *nfp;
+ short written;
+ uchar buf[2];
+
+ ASSERT(len >= 3);
+
+ type = *msg++; len--;
+ tag = (msg[1] << 8) | msg[0]; len -= 2; msg += 2;
+
+ switch (type) {
+ case Tnop:
+ send_reply(Rnop, tag, 0, 0);
+ goto done;
+ case Tflush:
+ ASSERT(len == 2);
+ oldtag = (msg[1] << 8) | msg[0];
+ flushtag(oldtag);
+ send_reply(Rflush, tag, 0, 0);
+ goto done;
+ }
+ /* all other messages take a fid as well */
+ ASSERT(len >= 2);
+ fid = (msg[1] << 8) | msg[0]; len -= 2; msg += 2;
+ fp = fidfind(fid);
+
+ switch (type) {
+ case Tattach:
+ ASSERT(len == 56);
+ if (fp) {
+ fid_in_use:
+ send_error_reply(tag, "fid in use");
+ }
+ else {
+ fp = fidcreate(fid, qid_root);
+ send_fid_reply(Rattach, tag, fid, fp->qid, 8);
+ }
+ break;
+ case Tclunk:
+ case Tremove:
+ ASSERT(len == 0);
+ if (!fp) {
+ no_such_fid:
+ send_error_reply(tag, "no such fid");
+ }
+ else {
+ fiddelete(fp);
+ if (type == Tremove)
+ send_error_reply(tag, "can't remove");
+ else
+ send_fid_reply(Rclunk, tag, fid, 0, 0);
+ }
+ break;
+ case Tclone:
+ ASSERT(len == 2);
+ newfid = (msg[1] << 8) | msg[0];
+ nfp = fidfind(newfid);
+ if (!fp)
+ goto no_such_fid;
+ if (fp->open) {
+ send_error_reply(tag, "can't clone");
+ break;
+ }
+ if (nfp)
+ goto fid_in_use;
+ nfp = fidcreate(newfid, fp->qid);
+ send_fid_reply(Rclone, tag, fid, 0, 0);
+ break;
+ case Twalk:
+ ASSERT(len == 28);
+ if (!fidwalk(fp, msg))
+ send_error_reply(tag, "no such name");
+ else
+ send_fid_reply(Rwalk, tag, fid, fp->qid, 8);
+ break;
+ case Tstat:
+ ASSERT(len == 0);
+ if (!fidstat(fp, dir))
+ send_error_reply(tag, "can't stat");
+ else
+ send_fid_reply(Rstat, tag, fid, dir, 116);
+ break;
+ ASSERT(len == 0);
+ case Tcreate:
+ ASSERT(len == 33);
+ send_error_reply(tag, "can't create");
+ break;
+ case Topen:
+ ASSERT(len == 1);
+ if (!fidopen(fp, msg[0]))
+ send_error_reply(tag, "can't open");
+ else
+ send_fid_reply(Ropen, tag, fid, fp->qid, 8);
+ break;
+ case Tread:
+ ASSERT(len == 10);
+ offset = (msg[1] << 8) | msg[0];
+ count = (msg[9] << 8) | msg[8];
+ if (fidread(fp, tag, offset, count) < 0)
+ send_error_reply(tag, "can't read");
+ break;
+ case Twrite:
+ ASSERT(len >= 11);
+ offset = (msg[1] << 8) | msg[0];
+ count = (msg[9] << 8) | msg[8];
+ msg += 11;
+ len -= 11;
+ ASSERT(count == len);
+ written = fidwrite(fp, offset, count, msg);
+ if (written < 0)
+ send_error_reply(tag, "can't write");
+ else {
+ buf[0] = written;
+ buf[1] = written >> 8;
+ send_fid_reply(Rwrite, tag, fid, buf, 2);
+ }
+ break;
+ default:
+ FATAL;
+ }
+done:
+ ;
+}
+
+void
+process_llp_message(unsigned char *msg, short len)
+{
+ short styxlen;
+ switch (msg[0]) {
+ case 0x45:
+ case 0x4d:
+ if (len != 5)
+ FATAL;
+ styxlen = compressed_incoming[0] | (compressed_incoming[1] << 8);
+ /* transfer the transmitted checksum to the end */
+ compressed_incoming[styxlen + 2 - 1] = msg[3];
+ /* check alternating bit */
+#ifdef ABP
+ if ((compressed_incoming[2] & 1) != alternating_bit ||
+ ((msg[0] & 8) != 0) != alternating_bit) {
+ transmit();
+ break;
+ }
+#endif
+ alternating_bit = !alternating_bit;
+ flush_reply_buffer();
+ if (styxlen > 1) {
+ if (compressed_incoming[2] & LLP_COMPRESSION) {
+ /* decompress everything but length and link header */
+ styxlen = rldecode(incoming, compressed_incoming + 3, styxlen - 1);
+ process_styx_message(incoming, styxlen);
+ }
+ else
+ process_styx_message(compressed_incoming + 3, styxlen - 1);
+ }
+ transmit();
+ break;
+ default:
+ FATAL;
+ }
+}
+
+int
+main (void)
+{
+ int count = 0;
+ char buf[16];
+ char temp[64];
+
+ mem_init();
+ memset(temp,0, sizeof(temp));
+
+ /* Initialize */
+
+ init_timer(&temp[6], &dispatch[0]);
+ init_power();
+ init_sensors();
+ init_serial(&temp[4], &temp[6], 1, 1);
+
+ set_lcd_number(LCD_UNSIGNED, 0, LCD_DECIMAL_0);
+ set_lcd_segment(LCD_WALKING);
+ refresh_display();
+
+ set_data_pointer(compressed_incoming);
+
+ alternating_bit = 0;
+ compressed_reply_len = 0;
+ reply_len = 0;
+ prepared = 0;
+
+ while (poll_power() != 0) {
+
+ /* If a message has arrived, send a response with opcode inverted */
+
+ if (check_valid()) {
+ int len = receive_message(buf, sizeof(buf));
+ msgcount++;
+ process_llp_message(buf, len);
+ }
+ sensorpoll();
+ }
+
+ return 0;
+}
--- /dev/null
+++ b/lib/lego/styx.srec
@@ -1,0 +1,329 @@
+S00C0000737479782E7372656340
+S11880006DF06DF16DF26DF35E00967E6D736D726D716D7054AD
+S118801570446F20796F7520627974652C207768656E20492057
+S10B802A6B6E6F636B3F0000F5
+S11880326DF60D761B870D621B8279014000790029F25E00965F
+S1188047AC6B039A0A6F62FFFE1D23470819226B829A084012E9
+S118805C6B039A08790200091D234E060B036B839A086F61FF76
+S1188071FE6B819A0A6B039A08790200097900FFFF1D234F02CC
+S11880860D100B876D7654706DF60D760D02790330026DF3790F
+S118809B01301F79001FF25E0096BC0B87790027C85E0096D480
+S11880B06D7654706DF60D766DF40D047901300679001B625EB4
+S11880C50096DE0D405E00808E5E0080320D0046F86D746D7656
+S11880DA54706DF60D766DF40D041900684B473C0D1147380B7A
+S11880EF040CBA8AD0AA09422E0CB8F00088D090FF1B01684BC7
+S118810447200D11471C0B040CBA8AD0AA0942120D0209220901
+S118811922092009000CBAF200092040D66D746D7654706DF617
+S118812E0D761B871B876DF46DF56FE0FFFE0D146FE0FFFC0DEA
+S1188143444C16FA2D688A6F62FFFE0D230B036FE3FFFC170CE8
+S118815817040B040D444610FA306F63FFFC68BA0B036FE3FFC5
+S118816DFC404C790527101D454F407901000A0D505E0096EA0C
+S11881820D051D454EF0402E0D510D405E0096EA0C8A8A306F7C
+S118819763FFFC68BA0B036FE3FFFC0D510D405E0096FC0D0448
+S11881AC7901000A0D505E0096EA0D050D5546CE6F62FFFC6F38
+S11881C163FFFE19326FE2FFFC6F60FFFC6D756D740B870B87FD
+S11881D66D7654706DF60D761B876DF46DF50D040D156FE2FF1B
+S11881EBFE7900000A5E00972269846F8500026F62FFFE6F8241
+S118820000046F6200046F82000619226F8200086A0AA40A8AB5
+S1188215016A8AA40A6D756D740B876D7654706DF60D765E006D
+S118822A979C6A0AA40A8AFF6A8AA40A6D7654706DF60D7669C5
+S118823F00790198885E008FD6790000016D7654706DF60D76C2
+S11882541B871B876DF46DF50D056FE1FFFE6FE2FFFC40266990
+S1188269546F61FFFC0D406F62FFFE5D200D00470E6F4200082A
+S118827E69D20D405E0082244006790500080945695246D66DFD
+S1188293756D740B870B876D7654706DF60D761B871B876DF426
+S11882A86DF56FE0FFFE6FE1FFFC19557904A3DC6F62FFFC6F1F
+S11882BD61FFFE0D405E0082508C0E94000B05790200021D25D0
+S11882D24FE46D756D740B870B876D7654706DF60D7679030070
+S11882E70C19376DF46DF56FE2FFFE6F6400040D1147045A0077
+S11882FC83FE6E080002F00088F990FF6FE0FFFC6F65FFFC094E
+S11883115509550955190509557902A3D009520D256F62FFFE7D
+S118832646045A0083FE684BF300790200621D23470C79020088
+S118833B6C1D23470A5A0083FE79020060400219226FE2FFF8B1
+S11883500B046F63FFFE1B030D3346045A0083FE684AAA3E46D3
+S118836504FA014006AA3C460C18AA6EEAFFFB0B041B034006FB
+S118837AFA016EEAFFFB0D3346045A0083FE7901823A0D50881D
+S118838F0C900019226FE3FFF45E0082506F62FFFC8A00921091
+S11883A46FE2FFF66F61FFF6790019C45E0096DEFA0168DA6EE2
+S11883B96AFFF96EDA00016F63FFF40D310D405E0080DC6FD0B7
+S11883CE000A19226FD200026FD200046EDA0006FA016EDA0038
+S11883E3086E6AFFFB6EDA00096F61FFF6790019465E0096DEE7
+S11883F86F60FFFE40047900FFFF6D756D747903000C09376DED
+S118840D7654706DF60D767903000619376DF46DF56FE0FFFE55
+S11884226FE1FFFC0D256F6400085E0090340D031D45443219C6
+S1188437546F6000041D0443046F6400046F62000609526FE243
+S118844C00060D300B800B000D426F6100066FE3FFFA5E0097D9
+S1188461AE6F63FFFA4002194468BC0D420C2A18226EBA0001DE
+S118847618AA6EBA00020B840B046DF419226DF26F62FFFC6F2D
+S118848B61FFFEF80F5E0090480B870B876D756D7479030006D4
+S11884A009376D7654706DF60D767903000C19376DF46DF56FEC
+S11884B5E0FFF66FE1FFF40D257904FFF809646F6100060D4060
+S11884CA5E00812C6DF06DF46F6200046DF20D526F61FFF46F0B
+S11884DF60FFF65E0084108F0697006D756D747903000C093786
+S11884F46D7654706DF60D766E0A0009471019116F0300046FFB
+S118850902000A1D234514400E19116F0300046F02000A1D230B
+S118851E4404790100010D106D7654706DF60D761B876DF46D67
+S1188533F56FE1FFFE0D256E0A0002F2008AF992FF0D240944BD
+S118854809440944192409447902A3D009420D246E4A00084686
+S118855D067900FFFF404E0D405E0084F80D0047206F420004AA
+S11885726DF26F6200066DF26F6200040D516F60FFFE5E00847A
+S1188587A60B870B8740226F6200066DF26F6200040D516F6077
+S118859CFFFE5E0081DA6F42000C6F8200086FC0000C0B871974
+S11885B1006D756D740B876D7654706DF60D761B876DF46DF56A
+S11885C67903A400683A4D045A008686EA7F68BA19440D4509E0
+S11885DB5509550955194509557902A3D009520D256E5A00086F
+S11885F00D430B036FE3FFFE0CAA46045A0086768C0094100D32
+S1188605520D41790014C05E0096AC0D520D41790014C05E0077
+S118861A96AC0D520D41790014C05E0096AC0D520D4179001431
+S118862FC05E0096AC0D505E0084F80D00473840306F54000CD0
+S11886446F4200086FD2000C6F41000269406F5200046DF26F29
+S11886594200066DF26F4200045E0084A60D405E0082240B8741
+S118866E0B876F52000C46CA6F64FFFE790200021D244E045A4A
+S11886830085D86D756D740B876D7654706DF60D766DF46DF5DC
+S11886980D050D246F600004680BF300790200661D2347244E73
+S11886AD127902002D1D234750790200461D23472440327902CA
+S11886C200721D23470E0B021D23470E4022790200014010794F
+S11886D7020002400A7902000340047902000469926E0A000187
+S11886EC8AD0AA074304190040146E0A0001F2008AD092FF69F7
+S1188701C2FA0168DA790000016D756D746D7654706DF60D7696
+S11887167903001A19376DF46DF56FE2FFEE0D1147045A008818
+S118872B1A6EE9FFF26EE9FFF16EE9FFF06E0A0002AA054704D2
+S11887405A0087CC790200066F60FFEE1D2047045A00881A7939
+S118875504FFF409647905FFFA09657902FFF009626FE2FFECB1
+S118876A6F6300046DF30D420D516F60FFEC5E0086900B870D46
+S118877F0046045A00881A0D611B811B817900FFF109606F6252
+S118879400040B826DF21B826FE200047902FFF609625E00862B
+S11887A9900B870D00476A0D611B817900FFF209606F63000424
+S11887BE0B830B836DF37902FFF809624044790200026F63FF77
+S11887D3EE1D2346426E0B0002F3001B837900FFF409606FE0A7
+S11887E8FFEA0D3209227905FFFA09650D5109217904FFF00943
+S11887FD640D4009306F6300046DF36F63FFEA09230D325E00BF
+S118881286900B870D0046067900FFFF405019337904FFF40980
+S1188827647900FFF009606FE0FFE86F60FFE86C0A6FE0FFE86B
+S118883C0CAA471E0D318900912069426DF2695279001A4E6F7B
+S1188851E3FFE65E0096BC0B876F63FFE60B840B850B037902A5
+S118886600021D234FC66F60FFEE6D756D747903001A09376DE0
+S118887B7654706DF60D760D036B00A408400269000D00470896
+S11888906F0200021D3246F26D7654706DF60D761B876DF46DD8
+S11888A5F50D056FE1FFFE7900000E5E0097220D0446087900F0
+S11888BA02135E0080B418AA6ECA00046FC500026B02A4086948
+S11888CFC20D4088059000790200086F61FFFE5E0097AE6B8482
+S11888E4A4080D406D756D740B876D7654706DF60D766F03002E
+S11888F9026F1200021D23470419004004790000016D765470D8
+S118890E6DF60D766DF40D04790088F20D415E00829E7903A419
+S118892308401269301D40460A690269B25E00979C400E0D0326
+S1188938693246EA790002325E0080B46D746D7654706DF60D24
+S118894D766DF46DF50D040D156F4200044608790002395E0090
+S118896280B46F440004401C6940790198DC5E0097D20D004703
+S11889770A0D5546040D40400C1B058C0A9400694246E0190064
+S118898C6D756D746D7654706DF60D761B876DF46DF50D056F9C
+S11889A1E1FFFE6E5A000446226E5A0005AA0943087900024B1A
+S11889B65E0080B46E5A0005F20009226F229A0C6F220004461A
+S11889CB067900FFFF403E0D20690247360D0469406F61FFFEFC
+S11889E05E0097D20D00461E6E4A00026EDA00056F4200041872
+S11889F5BB0D224702FB806EDB000879000001400A8C0A94007C
+S1188A0A694246CC19006D756D740B876D7654706DF60D761B80
+S1188A1F876DF46DF56FE0FFFE0D157902007419110D505E00B2
+S1188A3498086F62FFFE69210D505E00981E0D50881C900079B6
+S1188A490400050D427901995E5E0097AE0D50883890000D42AC
+S1188A5E7901995E5E0097AE6F63FFFE6E3A00026EDA00546F67
+S1188A73320004FBB60D224702FB6D6EDB005CFA016EDA005DDE
+S1188A886F63FFFE6F32000418BB0D224702FB806EDB005F6D86
+S1188A9D756D740B876D7654706DF60D766DF46DF50D040D1555
+S1188AB26E4A000447067900FFFF40266E4A0005AA0943087991
+S1188AC700026B5E0080B46E4A0005F20009226F209A0C0D512A
+S1188ADC5E008A1A790000016D756D746D7654706DF60D766E47
+S1188AF10A000446107369460C6E0A0008470A89FFA901420491
+S1188B061900400AFA016E8A0004790000016D7654706DF60D6B
+S1188B1B767903000A19376DF46DF56FE0FFFE6FE1FFFC6FE24A
+S1188B30FFFA6E0A0005AA094308790002875E0080B46F60FF56
+S1188B45FE6E0A0005F20009226F229A0C6FE2FFF86E0A000880
+S1188B5AEA8046045A008C3A6E0A00044720790100746F60008E
+S1188B6F045E0098320D004610790100746F60FFFA5E00983280
+S1188B840D0047087900FFFF5A008C6C790100746F6000045E94
+S1188B990098446FE00004790100746F60FFFA5E0098446FE055
+S1188BAEFFFA5E0090346FE0FFF66F64FFF60B840B041955403B
+S1188BC30C0D415E008A1A8C7494000B056F6200041D2544122C
+S1188BD86F61FFFA09516F60FFF85E00894A0D0046DA0D5209D5
+S1188BED22092209221952092209220925095509556F63FFF685
+S1188C0268BD0D520C2A10021E226EBA000118AA6EBA00020B2D
+S1188C17850B056DF519226DF26F63FFFE6F3200026F61FFFC76
+S1188C2CF80F5E00904819000B870B8740326F60FFF86F03000B
+S1188C410647246F6200046DF26F60FFFA6DF06F60FFFE6F0213
+S1188C5600026F61FFFC6F60FFF85D300B870B8740047900FF05
+S1188C6BFF6D756D747903000A09376D7654706DF60D761B8739
+S1188C806DF46DF50D046FE1FFFE0D256E4A0008EA8046066EA4
+S1188C954A000446067900FFFF403C6E4A0005AA094308790005
+S1188CAA02B35E0080B46E4A0005F20009226F209A0C6F0200EA
+S1188CBF0847166F6200046DF26F0300080D526F61FFFE5D30D0
+S1188CD40B8740047900FFFF6D756D740B876D7654706DF60DCE
+S1188CE9761B876DF46DF56F63000446087900FFFF5A008DD243
+S1188CFE0D25194419116F6300040D5209326FE2FFFE40386806
+S1188D135BAB8846186F6200041B821D214CD4688B0B0018AACB
+S1188D28688A0B000B8140180CBB46040B0440106F6200041BF1
+S1188D3D021D214CB4688B0B000B010B0519336F62FFFE1D2567
+S1188D52450479030001685A46040D3347B2790200011D2447F9
+S1188D67124E060D4447584038790200021D24471A402E6F62C7
+S1188D7C00041B021D214D045A008CF618AA688A0B000B014047
+S1188D91346F6200041B821D214D045A008CF618AA688A0B00F9
+S1188DA640186F6200041B821D214D045A008CF6FA88688A0B00
+S1188DBB000CCA8AFE688A0B000B8119440D3346045A008D12D8
+S1188DD00D106D756D740B876D7654706DF60D761B876DF46D1B
+S1188DE5F50D040D2519226FE2FFFE0D55475E681AAA8847149E
+S1188DFA68CA0B010B046F62FFFE0B026FE2FFFE1B0540E20B9D
+S1188E0F016818F0000D00461468CA0B046F62FFFE0B026FE205
+S1188E24FFFE0B011B8540C40D030B836F62FFFE09326FE2FF91
+S1188E39FE0D321B030B011B854FAC188868C80B040D321B03E2
+S1188E4E4EF6409E6F60FFFE6D756D740B876D7654706DF60DB1
+S1188E63766DF46DF56A0CA40E47045A008F0079059F586B027F
+S1188E78A4106DF20D527901009379009EC35E008CE66B80A429
+S1188E8D060B870D004C206B02A4100D5179009EC35E0097AEBF
+S1188EA26B02A4106B82A40679029EC268AC0D23400879039E7E
+S1188EB7C2FA0868BA6A0AA40A47047D3070206838F0006A0A0E
+S1188ECCA40F4602C80168B86B00A4060D020B026B82A4066A77
+S1188EE10BA4076A8B9EC00C2A10021E226A8A9EC10B800B00FE
+S1188EF66B80A406FA016A8AA40E6D756D746D7654706DF60D53
+S1188F0B766DF46DF55E008E606B02A4106B82A40C79059EC02E
+S1188F206B04A406471A6DF46DF51922790117767900343E5E70
+S1188F350098560B870B870C8846E66D756D746D7654706DF684
+S1188F4A0D766B02A4106B03A40C1D32430E79009F580D3109F5
+S1188F5F0119325E0097AE6B02A40C6B03A41019230D326B8263
+S1188F74A41018AA6A8AA40E6D7654706DF60D766DF46DF50D6B
+S1188F89246F6500046B03A41079029F5809320D2368B86EB98D
+S1188F9E00010C1918116EB900020D44470E0B830B030D520D94
+S1188FB3410D305E0097AE6B02A4100B820B0209526B82A410CD
+S1188FC818AA6A8AA40E6D756D746D7654706DF60D766DF46D0A
+S1188FDDF50D156B04A41079029F5809420D24FA0368CA6EC8EE
+S1188FF200010C0818006EC800020D505E009874790200401D62
+S1189007204F020D200B840B040D020D510D405E0097AE6B024A
+S118901CA4108A4392006B82A41018AA6A8AA40E6D756D746DEF
+S11890317654706DF60D766B00A41079029F5D09020D206D7655
+S118904654706DF60D766DF46DF56F6400046B03A41079059F8E
+S118905B5809350D5368B86EB900010C1918116EB900026EBA1F
+S118907000030C2A18226EBA00040D4447108B0593006F6200AC
+S1189085060D410D305E0097AE6B02A4108A0592006F60000687
+S118909A09026B82A41018AA6A8AA40E6D756D746D7654706DD2
+S11890AFF60D7669021D12470419004004790000016D765470CC
+S11890C46DF60D760D01790090AE5E00829E6D7654706DF60D53
+S11890D9767903000E19376DF46DF50D050D14790000021D049C
+S11890EE4E08790003935E0080B46C5A6EEAFFFD6E5B00010C82
+S1189103B318BB685AF20014AB14236FE3FFFA1B841B040B858A
+S11891186E6BFFFDF3000D33470A790200041D23470E40446DE0
+S118912DF319226F61FFFAF801402E790200021D244708790045
+S1189142039D5E0080B46E5800010C801888685AF20014A8146B
+S1189157205E0090C419226DF26F61FFFAF8055E008F800B87CE
+S118916C5A009496790200011D244E08790003A45E0080B46E33
+S11891815800010C801888685AF20014A814206FE0FFF81B84C7
+S11891960B855E00887E6FE0FFF46E6BFFFDF3008BFA93FF7932
+S11891AB0200161D2343045A00948E09336F3299DA592079024C
+S11891C000381D244708790003AA5E0080B46F63FFF447087989
+S11891D50199635A0094567901988E6F60FFF85E00889C6FE009
+S11891EAFFF4790200086DF2880590006DF06F62FFF86F61FF86
+S11891FFFAF81D5A0094840D444708790003B65E0080B46F62A1
+S1189214FFF446087901996E5A0094566F60FFF45E00890E6E16
+S11892296BFFFDAB1446087901997A5A00945619226DF26DF2EE
+S118923E6F62FFF86F61FFFAF8135A009484790200021D244704
+S118925308790003C45E0080B46E5C00010CC418CC685AF200F5
+S118926814AC14240D405E00887E6F62FFF446045A0092186EC4
+S118927D2A00044708790199875A0094560D0047045A0091D466
+S11892926F61FFF4890591000D405E00889C19226DF26DF26FAA
+S11892A762FFF86F61FFFAF8075A0094847902001C1D244708F4
+S11892BC790003D35E0080B40D516F60FFF45E0089940D0046CA
+S11892D108790199935A009456790200086DF26F63FFF48B055B
+S11892E693006DF36F62FFF86F61FFFAF8095A0094840D4447E0
+S11892FB08790003DA5E0080B47904A3580D416F60FFF45E0084
+S11893108AA60D004608790199A05A009456790200746DF26D07
+S1189325F46F62FFF86F61FFFAF8175A009484790200211D244C
+S118933A4708790003E25E0080B4790199AB5A0094567902005E
+S118934F011D244708790003E65E0080B468596F60FFF45E009F
+S11893648AEC0D004608790199B85A009456790200086DF26FBF
+S118937960FFF4880590006DF06F62FFF86F61FFFAF80B5A0020
+S118938E94847902000A1D244708790003ED5E0080B46E5A00D6
+S11893A3010CA218AA6859F1006E5B00090CB318BB6E5800085C
+S11893B8F000148B14036DF3149A14126F61FFFA6F60FFF45ED9
+S11893CD008B180B870D004D045A009496790199C35A00945656
+S11893E27902000A1D244E08790003F45E0080B46E5A00010C7F
+S11893F7A218AA6FE2FFF6685AF2006F60FFF614A814206FE0FC
+S118940CFFF66E5B00090CB318BB6E5A0008F20014AB14238DA9
+S11894210B95008CF594FF1D434710790003F96FE3FFF25E00B1
+S118943680B46F63FFF26DF50D326F61FFF66F60FFF45E008C14
+S118944B7A0B870D004C0E790199CE6F60FFFA5E008FD64036B3
+S11894606EE8FFFE0C0810001E006EE8FFFF790200026DF20D21
+S1189475621B826DF26F62FFF86F61FFFAF8115E0090480B871E
+S118948A0B874008790004045E0080B46D756D747903000E0986
+S118949F376D7654706DF60D766DF46DF50D04684BF3007902FB
+S11894B400451D23470C7902004D1D2347045A009548790200C2
+S11894C9051D214708790004125E0080B479039A28683DF500FF
+S11894DE6A0A9A290CA218AA14AD14250D5209326E4B00036E10
+S11894F3AB000118BB6A0AA40F4602FB016A8BA40F5E008F4899
+S1189508790200011D254F326A0A9A2AEA08471E79019A2B79C4
+S118951D049AC00D521B020D405E008DDC0D050D510D405E002C
+S118953290D6400C79009A2B0D511B015E0090D65E008F0840BD
+S1189547087900042C5E0080B46D756D746D7654706DF60D7678
+S118955C7903005219376DF45E00970E7900FFB0096079020068
+S11895714019115E0098087902A4007901FFB6096179003B9A73
+S11895865E0096AC790029645E0096D4790014985E0096D479F8
+S118959B0200016DF26DF27902FFB609627901FFB4096179004B
+S11895B030D05E0098560B870B87790230026DF2192279013041
+S11895C51F79001FF25E0096BC0B877901300779001B625E009D
+S11895DA96DE790027C85E0096D419446DF479029A2879011748
+S11895EF717900327C5E0096BC0B876A8CA40F6B84A4066B8458
+S1189604A4106A8CA40E405C19227901FFAF0961790034265E57
+S11896190096AC6E6AFFAFF2000CAA473E18AA6EEAFFAE790201
+S118962EFFAE09626DF2790200107901FFF00961790033B05E94
+S11896430096BC0B876E69FFAEF1006B029A200B026B829A20DA
+S11896581B017900FFF009605E0094A45E0085BC5E0080320DBA
+S114966D00469C19006D747903005209376D76547057
+S118967E6DF60D7679029A207903A4121D32470A188868A80B2B
+S1189693021D3246F85E009558FA016A8AFFCC6B0200005D2040
+S10796A86D76547013
+S11396AC6DF66DF20D165D000D600B876D765470C2
+S11896BC6DF66F7300046DF36DF20D165D000D600B870B876D0F
+S10696D176547058
+S10D96D46DF65D000D606D765470B4
+S10F96DE6DF60D165D000D606D76547085
+S11596EA6DF56DF60D060D155F520D606D766D755470C9
+S11596FC6DF56DF60D060D155F500D606D766D755470B9
+S118970E6DF60D767903A4127902EF00193269B26D7654706D46
+S1189723F60D766DF46DF50D040B04ECFE0B841D04455C79001D
+S1189738A4120D01404C69024D4209217902EEFF1D2142144068
+S118974D0E690209326982691209211D51420469134CEE6903E9
+S11897621D4345220D428A0692001D23450A0D02094219436908
+S1189777A369846902C28069820B804010E27F09210D107905B0
+S118978CEEFF1D5043AC19006D756D746D7654706DF60D766FA3
+S11097A102FFFEE27F6F82FFFE6D765470C2
+S11897AE6DF60D766DF40D140D010D0309231D31470A6C4A6833
+S11297C38A0B001D3046F60D106D746D765470D0
+S11897D26DF60D76401C680B681A1CAB430679000001401E1C43
+S11897E7AB44067900FFFF40140B000B01680A46E0681A19005F
+S10F97FC0CAA47047900FFFF6D7654703E
+S11898086DF60D760D0309231D3047066CB91D3046FA6D7654A2
+S104981D70D6
+S117981E6DF60D760D036C1A68BA0B030CAA46F66D765470ED
+S11598326DF56DF60D060D155F4C0D606D766D75547085
+S11598446DF56DF60D060D155F4E0D606D766D75547071
+S11898566DF66F7300066DF36F7300066DF36DF20D165D000D1A
+S10C986B608F0697006D765470BD
+S11798746DF60D76193340020B036C0A46FA0D306D765470C0
+S1189888726573657400000000800000000098DC000099120005
+S118989D00000098DA020000000000871298D803000000000032
+S11898B2871298D6040000000000871298D20500000000008703
+S11898C712000000000000000000003031320032003100300050
+S11898DC2E2E000098DC000099120000000098DA0700000085FA
+S11898F12A82E098D808000000852A82E098D609000000852A23
+S118990682E00000000000000000000098DC0000994800000091
+S118991B0099410100989600000000993A060098E000000000D9
+S11899300000000000000000000073656E736F72006D6F746FC5
+S1189945720000995C00009912000000000000000000000000F7
+S118995A00002F006C65676F0066696420696E20757365006E19
+S118996F6F2073756368206669640063616E27742072656D6FAA
+S118998476650063616E277420636C6F6E65006E6F20737563A9
+S118999968206E616D650063616E277420737461740063616EB1
+S11899AE2774206372656174650063616E2774206F70656E00D2
+S11899C363616E277420726561640063616E277420777269744F
+S11899D86500924C948E92B4948E934C948E9334948E93909408
+S11899ED8E93E2948E9206948E9206948E92F8948E948E948ED8
+S1099A02948E948E91BEC7
+S1189A080000FFFF9948991C98A098AA98B498BE992698EA98BC
+S1069A1DF498FEB8
+S90380007C
--- /dev/null
+++ b/lib/lego/styx_abp.srec
@@ -1,0 +1,331 @@
+S0100000737479785F6162702E73726563AA
+S11880006DF06DF16DF26DF35E0096A66D736D726D716D705485
+S118801570446F20796F7520627974652C207768656E20492057
+S10B802A6B6E6F636B3F0000F5
+S11880326DF60D761B870D621B8279014000790029F25E00965F
+S1188047D46B039A326F62FFFE1D23470819226B829A30401271
+S118805C6B039A30790200091D234E060B036B839A306F61FF26
+S1188071FE6B819A326B039A30790200097900FFFF1D234F027C
+S11880860D100B876D7654706DF60D760D02790330026DF3790F
+S118809B01301F79001FF25E0096E40B87790027C85E0096FC30
+S11880B06D7654706DF60D766DF40D047901300679001B625EB4
+S11880C50097060D405E00808E5E0080320D0046F86D746D762D
+S11880DA54706DF60D766DF40D041900684B473C0D1147380B7A
+S11880EF040CBA8AD0AA09422E0CB8F00088D090FF1B01684BC7
+S118810447200D11471C0B040CBA8AD0AA0942120D0209220901
+S118811922092009000CBAF200092040D66D746D7654706DF617
+S118812E0D761B871B876DF46DF56FE0FFFE0D146FE0FFFC0DEA
+S1188143444C16FA2D688A6F62FFFE0D230B036FE3FFFC170CE8
+S118815817040B040D444610FA306F63FFFC68BA0B036FE3FFC5
+S118816DFC404C790527101D454F407901000A0D505E009712E3
+S11881820D051D454EF0402E0D510D405E0097120C8A8A306F53
+S118819763FFFC68BA0B036FE3FFFC0D510D405E0097240D041F
+S11881AC7901000A0D505E0097120D050D5546CE6F62FFFC6F0F
+S11881C163FFFE19326FE2FFFC6F60FFFC6D756D740B870B87FD
+S11881D66D7654706DF60D761B876DF46DF50D040D156FE2FF1B
+S11881EBFE7900000A5E00974A69846F8500026F62FFFE6F8219
+S118820000046F6200046F82000619226F8200086A0AA43A8A85
+S1188215016A8AA43A6D756D740B876D7654706DF60D765E003D
+S118822A97C46A0AA43A8AFF6A8AA43A6D7654706DF60D76693D
+S118823F00790198B05E008FD6790000016D7654706DF60D769A
+S11882541B871B876DF46DF50D056FE1FFFE6FE2FFFC40266990
+S1188269546F61FFFC0D406F62FFFE5D200D00470E6F4200082A
+S118827E69D20D405E0082244006790500080945695246D66DFD
+S1188293756D740B870B876D7654706DF60D761B871B876DF426
+S11882A86DF56FE0FFFE6FE1FFFC19557904A40C6F62FFFC6FEE
+S11882BD61FFFE0D405E0082508C0E94000B05790200021D25D0
+S11882D24FE46D756D740B870B876D7654706DF60D7679030070
+S11882E70C19376DF46DF56FE2FFFE6F6400040D1147045A0077
+S11882FC83FE6E080002F00088F990FF6FE0FFFC6F65FFFC094E
+S11883115509550955190509557902A40009520D256F62FFFE4C
+S118832646045A0083FE684BF300790200621D23470C79020088
+S118833B6C1D23470A5A0083FE79020060400219226FE2FFF8B1
+S11883500B046F63FFFE1B030D3346045A0083FE684AAA3E46D3
+S118836504FA014006AA3C460C18AA6EEAFFFB0B041B034006FB
+S118837AFA016EEAFFFB0D3346045A0083FE7901823A0D50881D
+S118838F0C900019226FE3FFF45E0082506F62FFFC8A00921091
+S11883A46FE2FFF66F61FFF6790019C45E009706FA0168DA6EB9
+S11883B96AFFF96EDA00016F63FFF40D310D405E0080DC6FD0B7
+S11883CE000A19226FD200026FD200046EDA0006FA016EDA0038
+S11883E3086E6AFFFB6EDA00096F61FFF6790019465E009706BE
+S11883F86F60FFFE40047900FFFF6D756D747903000C09376DED
+S118840D7654706DF60D767903000619376DF46DF56FE0FFFE55
+S11884226FE1FFFC0D256F6400085E0090340D031D45443219C6
+S1188437546F6000041D0443046F6400046F62000609526FE243
+S118844C00060D300B800B000D426F6100066FE3FFFA5E0097D9
+S1188461D66F63FFFA4002194468BC0D420C2A18226EBA0001B6
+S118847618AA6EBA00020B840B046DF419226DF26F62FFFC6F2D
+S118848B61FFFEF80F5E0090480B870B876D756D7479030006D4
+S11884A009376D7654706DF60D767903000C19376DF46DF56FEC
+S11884B5E0FFF66FE1FFF40D257904FFF809646F6100060D4060
+S11884CA5E00812C6DF06DF46F6200046DF20D526F61FFF46F0B
+S11884DF60FFF65E0084108F0697006D756D747903000C093786
+S11884F46D7654706DF60D766E0A0009471019116F0300046FFB
+S118850902000A1D234514400E19116F0300046F02000A1D230B
+S118851E4404790100010D106D7654706DF60D761B876DF46D67
+S1188533F56FE1FFFE0D256E0A0002F2008AF992FF0D240944BD
+S118854809440944192409447902A40009420D246E4A00084655
+S118855D067900FFFF404E0D405E0084F80D0047206F420004AA
+S11885726DF26F6200066DF26F6200040D516F60FFFE5E00847A
+S1188587A60B870B8740226F6200066DF26F6200040D516F6077
+S118859CFFFE5E0081DA6F42000C6F8200086FC0000C0B871974
+S11885B1006D756D740B876D7654706DF60D761B876DF46DF56A
+S11885C67903A430683A4D045A008686EA7F68BA19440D4509B0
+S11885DB5509550955194509557902A40009520D256E5A00083E
+S11885F00D430B036FE3FFFE0CAA46045A0086768C0094100D32
+S1188605520D41790014C05E0096D40D520D41790014C05E004F
+S118861A96D40D520D41790014C05E0096D40D520D41790014E1
+S118862FC05E0096D40D505E0084F80D00473840306F54000CA8
+S11886446F4200086FD2000C6F41000269406F5200046DF26F29
+S11886594200066DF26F4200045E0084A60D405E0082240B8741
+S118866E0B876F52000C46CA6F64FFFE790200021D244E045A4A
+S11886830085D86D756D740B876D7654706DF60D766DF46DF5DC
+S11886980D050D246F600004680BF300790200661D2347244E73
+S11886AD127902002D1D234750790200461D23472440327902CA
+S11886C200721D23470E0B021D23470E4022790200014010794F
+S11886D7020002400A7902000340047902000469926E0A000187
+S11886EC8AD0AA074304190040146E0A0001F2008AD092FF69F7
+S1188701C2FA0168DA790000016D756D746D7654706DF60D7696
+S11887167903001A19376DF46DF56FE2FFEE0D1147045A008818
+S118872B1A6EE9FFF26EE9FFF16EE9FFF06E0A0002AA054704D2
+S11887405A0087CC790200066F60FFEE1D2047045A00881A7939
+S118875504FFF409647905FFFA09657902FFF009626FE2FFECB1
+S118876A6F6300046DF30D420D516F60FFEC5E0086900B870D46
+S118877F0046045A00881A0D611B811B817900FFF109606F6252
+S118879400040B826DF21B826FE200047902FFF609625E00862B
+S11887A9900B870D00476A0D611B817900FFF209606F63000424
+S11887BE0B830B836DF37902FFF809624044790200026F63FF77
+S11887D3EE1D2346426E0B0002F3001B837900FFF409606FE0A7
+S11887E8FFEA0D3209227905FFFA09650D5109217904FFF00943
+S11887FD640D4009306F6300046DF36F63FFEA09230D325E00BF
+S118881286900B870D0046067900FFFF405019337904FFF40980
+S1188827647900FFF009606FE0FFE86F60FFE86C0A6FE0FFE86B
+S118883C0CAA471E0D318900912069426DF2695279001A4E6F7B
+S1188851E3FFE65E0096E40B876F63FFE60B840B850B0379027D
+S118886600021D234FC66F60FFEE6D756D747903001A09376DE0
+S118887B7654706DF60D760D036B00A438400269000D00470866
+S11888906F0200021D3246F26D7654706DF60D761B876DF46DD8
+S11888A5F50D056FE1FFFE7900000E5E00974A0D0446087900C8
+S11888BA02135E0080B418AA6ECA00046FC500026B02A4386918
+S11888CFC20D4088059000790200086F61FFFE5E0097D66B845A
+S11888E4A4380D406D756D740B876D7654706DF60D766F0300FE
+S11888F9026F1200021D23470419004004790000016D765470D8
+S118890E6DF60D766DF40D04790088F20D415E00829E7903A419
+S118892338401269301D40460A690269B25E0097C4400E0D03CE
+S1188938693246EA790002325E0080B46D746D7654706DF60D24
+S118894D766DF46DF50D040D156F4200044608790002395E0090
+S118896280B46F440004401C6940790199045E0097FA0D0047B2
+S11889770A0D5546040D40400C1B058C0A9400694246E0190064
+S118898C6D756D746D7654706DF60D761B876DF46DF50D056F9C
+S11889A1E1FFFE6E5A000446226E5A0005AA0943087900024B1A
+S11889B65E0080B46E5A0005F20009226F229A346F22000446F2
+S11889CB067900FFFF403E0D20690247360D0469406F61FFFEFC
+S11889E05E0097FA0D00461E6E4A00026EDA00056F420004184A
+S11889F5BB0D224702FB806EDB000879000001400A8C0A94007C
+S1188A0A694246CC19006D756D740B876D7654706DF60D761B80
+S1188A1F876DF46DF56FE0FFFE0D157902007419110D505E00B2
+S1188A3498306F62FFFE69210D505E0098460D50881C90007966
+S1188A490400050D42790199865E0097D60D50883890000D425C
+S1188A5E790199865E0097D66F63FFFE6E3A00026EDA00546F17
+S1188A73320004FBB60D224702FB6D6EDB005CFA016EDA005DDE
+S1188A886F63FFFE6F32000418BB0D224702FB806EDB005F6D86
+S1188A9D756D740B876D7654706DF60D766DF46DF50D040D1555
+S1188AB26E4A000447067900FFFF40266E4A0005AA0943087991
+S1188AC700026B5E0080B46E4A0005F20009226F209A340D5102
+S1188ADC5E008A1A790000016D756D746D7654706DF60D766E47
+S1188AF10A000446107369460C6E0A0008470A89FFA901420491
+S1188B061900400AFA016E8A0004790000016D7654706DF60D6B
+S1188B1B767903000A19376DF46DF56FE0FFFE6FE1FFFC6FE24A
+S1188B30FFFA6E0A0005AA094308790002875E0080B46F60FF56
+S1188B45FE6E0A0005F20009226F229A346FE2FFF86E0A000858
+S1188B5AEA8046045A008C3A6E0A00044720790100746F60008E
+S1188B6F045E00985A0D004610790100746F60FFFA5E00985A30
+S1188B840D0047087900FFFF5A008C6C790100746F6000045E94
+S1188B9900986C6FE00004790100746F60FFFA5E00986C6FE005
+S1188BAEFFFA5E0090346FE0FFF66F64FFF60B840B041955403B
+S1188BC30C0D415E008A1A8C7494000B056F6200041D2544122C
+S1188BD86F61FFFA09516F60FFF85E00894A0D0046DA0D5209D5
+S1188BED22092209221952092209220925095509556F63FFF685
+S1188C0268BD0D520C2A10021E226EBA000118AA6EBA00020B2D
+S1188C17850B056DF519226DF26F63FFFE6F3200026F61FFFC76
+S1188C2CF80F5E00904819000B870B8740326F60FFF86F03000B
+S1188C410647246F6200046DF26F60FFFA6DF06F60FFFE6F0213
+S1188C5600026F61FFFC6F60FFF85D300B870B8740047900FF05
+S1188C6BFF6D756D747903000A09376D7654706DF60D761B8739
+S1188C806DF46DF50D046FE1FFFE0D256E4A0008EA8046066EA4
+S1188C954A000446067900FFFF403C6E4A0005AA094308790005
+S1188CAA02B35E0080B46E4A0005F20009226F209A346F0200C2
+S1188CBF0847166F6200046DF26F0300080D526F61FFFE5D30D0
+S1188CD40B8740047900FFFF6D756D740B876D7654706DF60DCE
+S1188CE9761B876DF46DF56F63000446087900FFFF5A008DD243
+S1188CFE0D25194419116F6300040D5209326FE2FFFE40386806
+S1188D135BAB8846186F6200041B821D214CD4688B0B0018AACB
+S1188D28688A0B000B8140180CBB46040B0440106F6200041BF1
+S1188D3D021D214CB4688B0B000B010B0519336F62FFFE1D2567
+S1188D52450479030001685A46040D3347B2790200011D2447F9
+S1188D67124E060D4447584038790200021D24471A402E6F62C7
+S1188D7C00041B021D214D045A008CF618AA688A0B000B014047
+S1188D91346F6200041B821D214D045A008CF618AA688A0B00F9
+S1188DA640186F6200041B821D214D045A008CF6FA88688A0B00
+S1188DBB000CCA8AFE688A0B000B8119440D3346045A008D12D8
+S1188DD00D106D756D740B876D7654706DF60D761B876DF46D1B
+S1188DE5F50D040D2519226FE2FFFE0D55475E681AAA8847149E
+S1188DFA68CA0B010B046F62FFFE0B026FE2FFFE1B0540E20B9D
+S1188E0F016818F0000D00461468CA0B046F62FFFE0B026FE205
+S1188E24FFFE0B011B8540C40D030B836F62FFFE09326FE2FF91
+S1188E39FE0D321B030B011B854FAC188868C80B040D321B03E2
+S1188E4E4EF6409E6F60FFFE6D756D740B876D7654706DF60DB1
+S1188E63766DF46DF56A0CA43E47045A008F0079059F886B021F
+S1188E78A4406DF20D527901009379009EF35E008CE66B80A4C9
+S1188E8D360B870D004C206B02A4400D5179009EF35E0097D607
+S1188EA26B02A4406B82A43679029EF268AC0D23400879039EEE
+S1188EB7F2FA0868BA6A0AA43A47047D3070206838F0006A0AAE
+S1188ECCA43F4602C80168B86B00A4360D020B026B82A4366AE7
+S1188EE10BA4376A8B9EF00C2A10021E226A8A9EF10B800B006E
+S1188EF66B80A436FA016A8AA43E6D756D746D7654706DF60DF3
+S1188F0B766DF46DF55E008E606B02A4406B82A43C79059EF09E
+S1188F206B04A436471A6DF46DF51922790117767900343E5E40
+S1188F3500987E0B870B870C8846E66D756D746D7654706DF65C
+S1188F4A0D766B02A4406B03A43C1D32430E79009F880D310965
+S1188F5F0119325E0097D66B02A43C6B03A44019230D326B82DB
+S1188F74A44018AA6A8AA43E6D7654706DF60D766DF46DF50D0B
+S1188F89246F6500046B03A44079029F8809320D2368B86EB92D
+S1188F9E00010C1918116EB900020D44470E0B830B030D520D94
+S1188FB3410D305E0097D66B02A4400B820B0209526B82A44045
+S1188FC818AA6A8AA43E6D756D746D7654706DF60D766DF46DDA
+S1188FDDF50D156B04A44079029F8809420D24FA0368CA6EC88E
+S1188FF200010C0818006EC800020D505E00989C790200401D3A
+S1189007204F020D200B840B040D020D510D405E0097D66B0222
+S118901CA4408A4392006B82A44018AA6A8AA43E6D756D746D5F
+S11890317654706DF60D766B00A44079029F8D09020D206D76F5
+S118904654706DF60D766DF46DF56F6400046B03A44079059F5E
+S118905B8809350D5368B86EB900010C1918116EB900026EBAEF
+S118907000030C2A18226EBA00040D4447108B0593006F6200AC
+S1189085060D410D305E0097D66B02A4408A0592006F6000062F
+S118909A09026B82A44018AA6A8AA43E6D756D746D7654706D72
+S11890AFF60D7669021D12470419004004790000016D765470CC
+S11890C46DF60D760D01790090AE5E00829E6D7654706DF60D53
+S11890D9767903000E19376DF46DF50D050D14790000021D049C
+S11890EE4E08790003935E0080B46C5A6EEAFFFD6E5B00010C82
+S1189103B318BB685AF20014AB14236FE3FFFA1B841B040B858A
+S11891186E6BFFFDF3000D33470A790200041D23470E40446DE0
+S118912DF319226F61FFFAF801402E790200021D244708790045
+S1189142039D5E0080B46E5800010C801888685AF20014A8146B
+S1189157205E0090C419226DF26F61FFFAF8055E008F800B87CE
+S118916C5A009496790200011D244E08790003A45E0080B46E33
+S11891815800010C801888685AF20014A814206FE0FFF81B84C7
+S11891960B855E00887E6FE0FFF46E6BFFFDF3008BFA93FF7932
+S11891AB0200161D2343045A00948E09336F329A025920790223
+S11891C000381D244708790003AA5E0080B46F63FFF447087989
+S11891D501998B5A009456790198B66F60FFF85E00889C6FE0B9
+S11891EAFFF4790200086DF2880590006DF06F62FFF86F61FF86
+S11891FFFAF81D5A0094840D444708790003B65E0080B46F62A1
+S1189214FFF44608790199965A0094566F60FFF45E00890E6EEE
+S11892296BFFFDAB144608790199A25A00945619226DF26DF2C6
+S118923E6F62FFF86F61FFFAF8135A009484790200021D244704
+S118925308790003C45E0080B46E5C00010CC418CC685AF200F5
+S118926814AC14240D405E00887E6F62FFF446045A0092186EC4
+S118927D2A00044708790199AF5A0094560D0047045A0091D43E
+S11892926F61FFF4890591000D405E00889C19226DF26DF26FAA
+S11892A762FFF86F61FFFAF8075A0094847902001C1D244708F4
+S11892BC790003D35E0080B40D516F60FFF45E0089940D0046CA
+S11892D108790199BB5A009456790200086DF26F63FFF48B0533
+S11892E693006DF36F62FFF86F61FFFAF8095A0094840D4447E0
+S11892FB08790003DA5E0080B47904A3880D416F60FFF45E0054
+S11893108AA60D004608790199C85A009456790200746DF26DDF
+S1189325F46F62FFF86F61FFFAF8175A009484790200211D244C
+S118933A4708790003E25E0080B4790199D35A00945679020036
+S118934F011D244708790003E65E0080B468596F60FFF45E009F
+S11893648AEC0D004608790199E05A009456790200086DF26F97
+S118937960FFF4880590006DF06F62FFF86F61FFFAF80B5A0020
+S118938E94847902000A1D244708790003ED5E0080B46E5A00D6
+S11893A3010CA218AA6859F1006E5B00090CB318BB6E5800085C
+S11893B8F000148B14036DF3149A14126F61FFFA6F60FFF45ED9
+S11893CD008B180B870D004D045A009496790199EB5A0094562E
+S11893E27902000A1D244E08790003F45E0080B46E5A00010C7F
+S11893F7A218AA6FE2FFF6685AF2006F60FFF614A814206FE0FC
+S118940CFFF66E5B00090CB318BB6E5A0008F20014AB14238DA9
+S11894210B95008CF594FF1D434710790003F96FE3FFF25E00B1
+S118943680B46F63FFF26DF50D326F61FFF66F60FFF45E008C14
+S118944B7A0B870D004C0E790199F66F60FFFA5E008FD640368B
+S11894606EE8FFFE0C0810001E006EE8FFFF790200026DF20D21
+S1189475621B826DF26F62FFF86F61FFFAF8115E0090480B871E
+S118948A0B874008790004045E0080B46D756D747903000E0986
+S118949F376D7654706DF60D766DF46DF50D04684BF3007902FB
+S11894B400451D23470C7902004D1D2347045A0095707902009A
+S11894C9051D214708790004125E0080B479039A58683DF500CF
+S11894DE6A0A9A590CA218AA14AD14250D5209326E4B00036EE0
+S11894F3AB00016A089A5AE8016A0AA43F1CA84666684A1102D9
+S1189508130A1102130A1102130AEA01E2006A0BA43FF3001D98
+S118951D32464A18AA0C884602FA016A8AA43F5E008F48790253
+S118953200011D254F326A0A9A5A733A471E79019A5B79049A5C
+S1189547F00D521B020D405E008DDC0D050D510D405E0090D60A
+S118955C400C79009A5B0D511B015E0090D65E008F0840087948
+S118957100042C5E0080B46D756D746D7654706DF60D76790353
+S1189586005219376DF45E0097367900FFB00960790200401939
+S118959B115E0098307902A4307901FFB6096179003B9A5E00EC
+S11895B096D4790029645E0096FC790014985E0096FC790200B2
+S11895C5016DF26DF27902FFB609627901FFB40961790030D023
+S11895DA5E00987E0B870B87790230026DF219227901301F7957
+S11895EF001FF25E0096E40B877901300779001B625E00970646
+S1189604790027C85E0096FC19446DF479029A5879011771794F
+S118961900327C5E0096E40B876A8CA43F6B84A4366B84A440AB
+S118962E6A8CA43E405C19227901FFAF0961790034265E00961B
+S1189643D46E6AFFAFF2000CAA473E18AA6EEAFFAE7902FFAE98
+S118965809626DF2790200107901FFF00961790033B05E009681
+S118966DE40B876E69FFAEF1006B029A500B026B829A501B01A2
+S11896827900FFF009605E0094A45E0085BC5E0080320D004666
+S11296979C19006D747903005209376D76547075
+S11896A66DF60D7679029A507903A4421D32470A188868A80BA3
+S11896BB021D3246F85E009580FA016A8AFFCC6B0200005D20F0
+S10796D06D765470EB
+S11396D46DF66DF20D165D000D600B876D7654709A
+S11896E46DF66F7300046DF36DF20D165D000D600B870B876DE7
+S10696F976547030
+S10D96FC6DF65D000D606D7654708C
+S10F97066DF60D165D000D606D7654705C
+S11597126DF56DF60D060D155F520D606D766D755470A0
+S11597246DF56DF60D060D155F500D606D766D75547090
+S11897366DF60D767903A4427902EF00193269B26D7654706DEE
+S118974BF60D766DF46DF50D040B04ECFE0B841D04455C7900F5
+S1189760A4420D01404C69024D4209217902EEFF1D2142144010
+S11897750E690209326982691209211D51420469134CEE6903C1
+S118978A1D4345220D428A0692001D23450A0D020942194369E0
+S118979FA369846902C28069820B804010E27F09210D10790588
+S11897B4EEFF1D5043AC19006D756D746D7654706DF60D766F7B
+S11097C902FFFEE27F6F82FFFE6D7654709A
+S11897D66DF60D766DF40D140D010D0309231D31470A6C4A680B
+S11297EB8A0B001D3046F60D106D746D765470A8
+S11897FA6DF60D76401C680B681A1CAB430679000001401E1C1B
+S118980FAB44067900FFFF40140B000B01680A46E0681A190036
+S10F98240CAA47047900FFFF6D76547015
+S11898306DF60D760D0309231D3047066CB91D3046FA6D76547A
+S104984570AE
+S11798466DF60D760D036C1A68BA0B030CAA46F66D765470C5
+S115985A6DF56DF60D060D155F4C0D606D766D7554705D
+S115986C6DF56DF60D060D155F4E0D606D766D75547049
+S118987E6DF66F7300066DF36F7300066DF36DF20D165D000DF2
+S10C9893608F0697006D76547095
+S117989C6DF60D76193340020B036C0A46FA0D306D76547098
+S11898B0726573657400000000800000000099040000993A008C
+S11898C5000000990202000000000087129900030000000000B8
+S11898DA871298FE040000000000871298FA050000000000878B
+S11898EF12000000000000000000003031320032003100300028
+S11899042E2E000099040000993A000000009902070000008557
+S11899192A82E0990008000000852A82E098FE09000000852AA9
+S118992E82E00000000000000000000099040000997000000018
+S1189943009969010098BE000000009962060099080000000010
+S11899580000000000000000000073656E736F72006D6F746F9D
+S118996D72000099840000993A0000000000000000000000007F
+S118998200002F006C65676F0066696420696E20757365006EF1
+S11899976F2073756368206669640063616E27742072656D6F82
+S11899AC76650063616E277420636C6F6E65006E6F2073756381
+S11899C168206E616D650063616E277420737461740063616E89
+S11899D62774206372656174650063616E2774206F70656E00AA
+S11899EB63616E277420726561640063616E2774207772697427
+S1189A006500924C948E92B4948E934C948E9334948E939094DF
+S1189A158E93E2948E9206948E9206948E92F8948E948E948EAF
+S1099A2A948E948E91BE9F
+S1189A300000FFFF9970994498C898D298DC98E6994E99129952
+S1069A451C99263F
+S90380007C
--- /dev/null
+++ b/lib/limbo.vim
@@ -1,0 +1,92 @@
+" Vim syntax file
+" Language: Limbo
+" Maintainer: Alex Efros <powerman-asdf@ya.ru>
+" Version: 0.5
+" Updated: 2008-10-17
+
+" Remove any old syntax stuff that was loaded (5.x) or quit when a syntax file
+" was already loaded (6.x).
+if version < 600
+ syntax clear
+elseif exists("b:current_syntax")
+ finish
+endif
+
+syn keyword lTodo TODO TBD FIXME XXX BUG contained
+syn match lComment "#.*" contains=@Spell,lTodo
+
+syn keyword lInclude include
+
+syn match lSpecialChar display contained "\\\(u\x\{4}\|['\"\\tnrbavf0]\)"
+syn match lSpecialError display contained "\(\\[^'\"\\tnrbavf0u]\+\|\\u.\{0,3}\X\)"
+syn match lCharError display contained "\([^\\'][^']\+\|\\[^'][^']\+\)"
+syn region lString start=+"+ end=+"+ skip=+\\"+ contains=@Spell,lSpecialChar,lSpecialError
+syn region lCharacter start=+'+ end=+'+ skip=+\\'+ contains=lSpecialChar,lSpecialError,lCharError
+
+syn keyword lSpecial nil iota
+
+syn keyword lFunction tl hd len tagof
+syn match lFunction "<-=\?"
+
+syn keyword lStatement alt break continue exit return spawn implement import load raise
+syn keyword lRepeat for while do
+syn keyword lConditional if else case
+
+syn keyword lType array big byte chan con int list real string fn fixed
+syn keyword lStructure adt pick module
+syn keyword lStorageClass ref self cyclic type of
+
+syn keyword lDelimiter or to
+syn match lDelimiter "=>\|->\|\.\|::"
+
+
+if version >= 508 || !exists("did_icgiperl_syn_inits")
+ if version < 508
+ let did_icgiperl_syn_inits = 1
+ command -nargs=+ HiLink hi link <args>
+ else
+ command -nargs=+ HiLink hi def link <args>
+ endif
+
+ " Comment
+ HiLink lComment Comment
+
+ " PreProc (Include, PreCondit)
+ HiLink lInclude Include
+
+ " Constant (String, Character, Number, Boolean, Float)
+ HiLink lString String
+ HiLink lCharacter Character
+
+ " Special (Tag, SpecialChar, SpecialComment, Debug)
+ HiLink lSpecial Special
+ HiLink lSpecialChar SpecialChar
+
+ " Identifier (Function)
+ HiLink lFunction Function
+
+ " Statement (Conditional, Repeat, Label, Operator, Keyword, Exception)
+ HiLink lStatement Statement
+ HiLink lRepeat Repeat
+ HiLink lConditional Conditional
+
+ " Type (StorageClass, Structure, Typedef)
+ HiLink lType Type
+ HiLink lStructure Structure
+ HiLink lStorageClass StorageClass
+
+ " Error
+ HiLink lSpecialError Error
+ HiLink lCharError Error
+
+ " Todo
+ HiLink lTodo Todo
+
+ " Delimiter
+ HiLink lDelimiter Delimiter
+
+ delcommand HiLink
+endif
+
+
+let b:current_syntax = "limbo"
--- /dev/null
+++ b/lib/mashinit
@@ -1,0 +1,4 @@
+sysname = `{ cat /dev/sysname };
+user = `{ cat /dev/user };
+home = /usr/$user;
+run - $home/lib/mashinit;
--- /dev/null
+++ b/lib/mimetype
@@ -1,0 +1,171 @@
+#suffix generic type specific type encoding safe? y=yes, m=maybe, n=no, p=previous.suffix, r=mailreject
+.3gp video 3gpp - y
+.3gpp video 3gpp - y
+.C text plain - y # C++ program
+.Z - - compress m
+.a application octet-stream - y
+.ada text plain - y # ada program
+.ai application postscript - y
+.aif audio x-aiff - y
+.aifc audio x-aiff - y
+.aiff audio x-aiff - y
+.asf video x-ms-asf - m # MS streaming
+.asc application text - y # sometimes application/pgp-signature
+.asx video x-ms-asf - m # MS streaming
+.au audio basic - y # sun audio
+.avi video x-msvideo - m
+.awk text plain - y # awk program
+.bas text plain - y # basic program
+.bat application octet-stream - r # DOS executable
+.bbl text plain - y # BibTex output
+.bcpio application x-bcpio - m
+.bib text plain - y # BibTex input
+.bmp image bmp - y # bitmapped image
+.bz2 - - bzip2 m # bzipped file
+.c text plain - y # C program
+.c++ text plain - y # C++ program
+.cacert application x-x509-ca-cert - y # DER X.509 CA certificate
+.cc text plain - y
+.cdf application x-netcdf - y
+.class application java - y # Java bytecodes
+.com application octet-stream - r # DOS executable
+.cpio application x-cpio - y
+.cpl application octet-stream - r # Windows Control Panel Applet
+.cpp text plain - y # DOS C++ program
+.crt application x-x509-ca-cert - y # DER X.509 CA certificate
+.css text css - m
+.csv application vnd.ms-excel - y # Microsoft Excel comma-separated-values
+.dat text plain - y # AMPL et al.
+.diff text plain - y
+.doc application msword - n # Microsoft Word
+.dvi application x-dvi - y # TeX output
+.enc application octet-stream - y # encrypted file
+.eps application postscript - y
+.etx text x-setext - m
+.exe application octet-stream - r # DOS executable
+.executable application octet-stream - r # DOS executable
+.exz application octet-stream gzip n # gzipped DOS executable
+.f text plain - y # fortran-77 program
+.fm application framemaker - y
+.f90 text plain - y # fortran-90 program
+.flc video x-flc - m
+.fli video x-fli - m
+.gcd text x-pcs-gcd - y # helper file for .qcp
+.gif image gif - y
+.gtar application x-gtar - m
+.gz - - gzip m # gzipped file
+.h text plain - y # C header file
+.hdf application x-hdf - y
+.hdml text x-hdml - y
+.hqx application octet-stream - m # Mac BinHex
+.htm text html - m
+.html text html - m
+.ico image x-icon - y
+.ief image ief - y
+.iso application octet-stream - y # ISO9660 image
+.jad text vnd.sun.j2me.app-descriptor - y
+.jar application java-archive - y
+.jfif image jpeg - y
+.jfif-tbnl image jpeg - y
+.jpe image jpeg - y
+.jpeg image jpeg - y
+.jpg image jpeg - y
+#.jpg image pjpeg - y
+.js application x-javascript - y
+.latex application x-latex - y
+.ltx application x-latex - y
+.man application x-troff-man - y
+.me application x-troff-me - y
+.mid audio midi - y # MIDI music
+.mime message rfc822 - y
+.mod text plain - y # AMPL et al.
+.mov video quicktime - y
+.movie video x-sgi-movie - y
+.mpe video mpeg - y
+.mpeg video mpeg - y
+.mpg video mpeg - y
+.ms application x-troff-ms - y
+.mv video x-sgi-movie - y
+.nc application x-netcdf - y
+.o application octet-stream - y
+.oda application oda - m
+.p text plain - y # Pascal program
+.p7m application x-pkcs7-mime - y # SMIME
+.p7s application x-pkcs7-signature - y # SMIME
+.pbm image x-portable-bitmap - y
+.pdf application pdf - y # Adobe Portable Document Format
+.pif application octet-stream - r # DOS executable
+.pgm image x-portable-graymap - y
+.pl text plain - y
+.png image png - y
+.pnm image x-portable-anymap - y
+.ppm image x-portable-pixmap - y
+.ppt application vnd.ms-powerpoint - n # Microsoft PowerPoint
+.ps application postscript - m
+.qcp audio vnd.qcelp - y # Qualcomm CELP
+.qcp2 audio qcp - y # Qualcomm CELP
+.qt video quicktime - y
+.r text plain - y # ratfor program
+.ra audio x-pn-realaudio - y # G2 RealAudio
+.ram audio x-pn-realaudio - y # G2 RealAudio
+.ras image x-cmu-rast - y
+.rc text plain - y # rc
+.rfr text plain - y # refer
+.rgb image x-rgb - y
+.rm application x-pn-realmedia - y # G2 RealAudio
+.roff application x-troff - y
+.rpm audio x-pn-realaudio-plugin - y # G2 RealAudio
+.rtf application rtf - y
+.rtx text richtext - y
+.scr application octet-stream - r # DOS executable (screen saver)
+.sh application x-shar - m
+.shar application x-shar - m
+.smi application smil - m # sync multimedia
+.smil application smil - m # sync multimedia
+.snd audio basic - y
+.suspect application octet-stream - y # upas/vf
+.sv4cpio application x-sv4cpio - m
+.sv4crc application x-sv4crc - y
+.swf application x-shockwave-flash - y
+.t application x-troff - y
+.tar application x-tar - m
+.tardist application x-tardist - n # SGI SoftwareManager
+.taz application x-tar compress m
+.tcl application x-tcl - y
+.tex application x-tex - y # Tex input
+.texi application x-texinfo - y
+.texinfo application x-texinfo - y
+.text text plain - y
+.tgz application x-tar gzip m
+.tif image tiff - y
+.tiff image tiff - y
+.toc text plain - y # table of contents
+.tr application x-troff - y
+.trz application x-tar compress m
+.tsv text tab-separated-values - y
+.txt text - - y
+.txt text plain - y
+.ucert application x-x509-user-cert - y # DER X.509 user certificate
+.ustar application x-ustar - m
+.vcf text x-vcard - y # vCard
+.wav audio x-wav - y
+.wbmp image vnd.wap.wbmp - y # wireless bitmap
+.wml text vnd.wap.wml - m # WML doc
+.wmlc application vnd.wap.wmlc - m # compiled WML doc
+.wmls text vnd.wap.wmlscript - m # WMLScript
+.wmlsc application vnd.wap.wmlscriptc - m # compiled WMLScript
+.wsrc application x-wais-source - y
+.xbm image x-xbitmap - y # X bitmap
+.xgz - - x-gzip m # gzipped file
+.xls application vnd.ms-excel - n # Microsoft Excel
+.xml text xml - m
+.xpm image x-xpixmap - y
+.xwd image x-xwindowdump - y
+.z - - compress m
+.Z - - compress m
+.zip application zip - n
+.zzz application sleep - n # testing
+- application x-gunzip - p # type for .tar.gz
+- message delivery-status - y # mail bounces
+- application pgp-signature - y
+- application pgp-encrypted - y
--- /dev/null
+++ b/lib/mk/binds
@@ -1,0 +1,2 @@
+/lib/mk/mkconfig /mkconfig
+/lib/mk/mksubdirs /mkfiles/mksubdirs
--- /dev/null
+++ b/lib/mk/mkconfig
@@ -1,0 +1,28 @@
+#
+# Set the following 4 variables. The host system is the system where
+# the software will be built; the target system is where it will run.
+# They are almost always the same.
+
+# On Nt systems, the ROOT path MUST be of the form `drive:/path'
+ROOT=
+
+#
+# Except for building kernels, SYSTARG must always be the same as SYSHOST
+#
+SYSHOST=Plan9 # build system OS type (Hp, Inferno, Irix, Linux, Nt, Plan9, Solaris)
+SYSTARG=$SYSHOST # target system OS type (Hp, Inferno, Irix, Linux, Nt, Plan9, Solaris)
+
+#
+# specify the architecture of the target system - Inferno imports it from the
+# environment; for other systems it is usually just hard-coded
+#
+#OBJTYPE=386 # target system object type (s800, mips, 386, arm, sparc)
+OBJTYPE=386
+
+#
+# no changes required beyond this point
+#
+OBJDIR=$SYSTARG/$OBJTYPE
+
+<$ROOT/mkfiles/mkhost-$SYSHOST # variables appropriate for host system
+<$ROOT/mkfiles/mkfile-$SYSTARG-$OBJTYPE # variables used to build target object type
--- /dev/null
+++ b/lib/mk/mksubdirs
@@ -1,0 +1,13 @@
+all:V: all-$SHELLTYPE
+install:V: install-$SHELLTYPE
+uninstall:V: uninstall-$SHELLTYPE
+nuke:V: nuke-$SHELLTYPE
+clean:V: clean-$SHELLTYPE
+
+%-rc %-nt %-sh:QV:
+ for j in $DIRS {
+ if { ftest -d $j } {
+ echo 'cd' $j '; mk' $MKFLAGS $stem
+ cd $j; mk $MKFLAGS $stem; cd ..
+ }
+ }
--- /dev/null
+++ b/lib/ndb/common
@@ -1,0 +1,242 @@
+#
+# ip protocol numbers
+#
+protocol=reserved ipv4proto=0
+protocol=icmp ipv4proto=1
+protocol=igmp ipv4proto=2
+protocol=ggp ipv4proto=3
+protocol=ip ipv4proto=4
+protocol=st ipv4proto=5
+protocol=tcp ipv4proto=6
+protocol=ucl ipv4proto=7
+protocol=egp ipv4proto=8
+protocol=igp ipv4proto=9
+protocol=bbn-rcc-mon ipv4proto=10
+protocol=nvp-ii ipv4proto=11
+protocol=pup ipv4proto=12
+protocol=argus ipv4proto=13
+protocol=emcon ipv4proto=14
+protocol=xnet ipv4proto=15
+protocol=chaos ipv4proto=16
+protocol=udp ipv4proto=17
+protocol=mux ipv4proto=18
+protocol=dcn-meas ipv4proto=19
+protocol=hmp ipv4proto=20
+protocol=prm ipv4proto=21
+protocol=xns-idp ipv4proto=22
+protocol=trunk-1 ipv4proto=23
+protocol=trunk-2 ipv4proto=24
+protocol=leaf-1 ipv4proto=25
+protocol=leaf-2 ipv4proto=26
+protocol=rdp ipv4proto=27
+protocol=irtp ipv4proto=28
+protocol=iso-tp4 ipv4proto=29
+protocol=netblt ipv4proto=30
+protocol=mfe-nsp ipv4proto=31
+protocol=merit-inp ipv4proto=32
+protocol=sep ipv4proto=33
+protocol=3pc ipv4proto=34
+protocol=idpr ipv4proto=35
+protocol=xtp ipv4proto=36
+protocol=ddp ipv4proto=37
+protocol=idpr-cmtp ipv4proto=38
+protocol=tp++ ipv4proto=39
+protocol=il ipv4proto=40
+protocol=sip ipv4proto=41
+protocol=sdrp ipv4proto=42
+protocol=sip-sr ipv4proto=43
+protocol=sip-frag ipv4proto=44
+protocol=idrp ipv4proto=45
+protocol=rsvp ipv4proto=46
+protocol=gre ipv4proto=47
+protocol=mhrp ipv4proto=48
+protocol=bna ipv4proto=49
+protocol=sipp-esp ipv4proto=50
+protocol=sipp-ah ipv4proto=51
+protocol=i-nlsp ipv4proto=52
+protocol=swipe ipv4proto=53
+protocol=nhrp ipv4proto=54
+protocol=any ipv4proto=61
+protocol=cftp ipv4proto=62
+protocol=any ipv4proto=63
+protocol=sat-expak ipv4proto=64
+protocol=kryptolan ipv4proto=65
+protocol=rvd ipv4proto=66
+protocol=ippc ipv4proto=67
+protocol=any ipv4proto=68
+protocol=sat-mon ipv4proto=69
+protocol=visa ipv4proto=70
+protocol=ipcv ipv4proto=71
+protocol=cpnx ipv4proto=72
+protocol=cphb ipv4proto=73
+protocol=wsn ipv4proto=74
+protocol=pvp ipv4proto=75
+protocol=br-sat-mon ipv4proto=76
+protocol=sun-nd ipv4proto=77
+protocol=wb-mon ipv4proto=78
+protocol=wb-expak ipv4proto=79
+protocol=iso-ip ipv4proto=80
+protocol=vmtp ipv4proto=81
+protocol=secure-vmtp ipv4proto=82
+protocol=vines ipv4proto=83
+protocol=ttp ipv4proto=84
+protocol=nsfnet-igp ipv4proto=85
+protocol=dgp ipv4proto=86
+protocol=tcf ipv4proto=87
+protocol=igrp ipv4proto=88
+protocol=ospfigp ipv4proto=89 protocol=ospf
+protocol=sprite-rpc ipv4proto=90
+protocol=larp ipv4proto=91
+protocol=mtp ipv4proto=92
+protocol=ax.25 ipv4proto=93
+protocol=ipip ipv4proto=94
+protocol=micp ipv4proto=95
+protocol=scc-sp ipv4proto=96
+protocol=etherip ipv4proto=97
+protocol=encap ipv4proto=98
+protocol=any ipv4proto=99
+protocol=gmtp ipv4proto=100
+protocol=rudp ipv4proto=254 # unofficial
+
+#
+# services
+#
+tcp=cs port=1
+tcp=echo port=7
+tcp=discard port=9
+tcp=systat port=11
+tcp=daytime port=13
+tcp=netstat port=15
+tcp=chargen port=19
+tcp=ftp-data port=20
+tcp=ftp port=21
+tcp=ssh port=22
+tcp=telnet port=23
+tcp=smtp port=25
+tcp=time port=37
+tcp=whois port=43
+tcp=dns port=53
+tcp=domain port=53
+tcp=uucp port=64
+tcp=gopher port=70
+tcp=rje port=77
+tcp=finger port=79
+tcp=http port=80
+tcp=link port=87
+tcp=supdup port=95
+tcp=hostnames port=101
+tcp=iso-tsap port=102
+tcp=x400 port=103
+tcp=x400-snd port=104
+tcp=csnet-ns port=105
+tcp=pop-2 port=109
+tcp=pop3 port=110
+tcp=sunrpc port=111
+tcp=uucp-path port=117
+tcp=nntp port=119
+tcp=profile port=136
+tcp=netbios port=139
+tcp=imap4 port=143
+tcp=NeWS port=144
+tcp=print-srv port=170
+tcp=z39.50 port=210
+tcp=fsb port=400
+tcp=sysmon port=401
+tcp=proxy port=402
+tcp=proxyd port=404
+tcp=https port=443
+tcp=ssmtp port=465
+tcp=rexec port=512 restricted=
+tcp=login port=513 restricted=
+tcp=shell port=514 restricted=
+tcp=printer port=515
+tcp=courier port=530
+tcp=cscan port=531
+tcp=uucp port=540
+tcp=snntp port=563
+tcp=9fs port=564
+tcp=whoami port=565
+tcp=guard port=566
+tcp=ticket port=567
+tcp=dlsftp port=666
+tcp=fmclient port=729
+tcp=imaps port=993
+tcp=pop3s port=995
+tcp=ingreslock port=1524
+tcp=pptp port=1723
+tcp=webster port=2627
+tcp=weather port=3000
+tcp=secstore port=5356
+tcp=Xdisplay port=6000
+tcp=styx port=6666
+tcp=mpeg port=6667
+tcp=rstyx port=6668
+tcp=infdb port=6669
+tcp=infsigner port=6671
+tcp=infcsigner port=6672
+tcp=inflogin port=6673
+tcp=registry port=6675
+tcp=internalreg port=6676
+tcp=bandt port=7330
+tcp=face port=32000
+tcp=exportfs port=17007
+tcp=rexexec port=17009
+tcp=ncpu port=17010
+tcp=cpu port=17013
+tcp=glenglenda1 port=17020
+tcp=glenglenda2 port=17021
+tcp=glenglenda3 port=17022
+tcp=glenglenda4 port=17023
+tcp=glenglenda5 port=17024
+tcp=glenglenda6 port=17025
+tcp=glenglenda7 port=17026
+tcp=glenglenda8 port=17027
+tcp=glenglenda9 port=17028
+tcp=glenglenda10 port=17029
+tcp=flyboy port=17032
+tcp=dlsftp port=17033
+tcp=venti port=17034
+tcp=wiki port=17035
+tcp=vica port=17036
+
+il=echo port=7
+il=discard port=9
+il=chargen port=19
+il=whoami port=565
+il=ticket port=566
+il=challbox port=567
+il=ocpu port=17005
+il=ocpunote port=17006
+il=exportfs port=17007
+il=9fs port=17008
+il=rexexec port=17009
+il=ncpu port=17010
+il=ncpunote port=17011
+il=tcpu port=17012
+il=cpu port=17013
+il=fsauth port=17020
+il=rexauth port=17021
+il=changekey port=17022
+il=chal port=17023
+il=check port=17024
+il=juke port=17026
+il=ramfs port=17031
+
+udp=echo port=7
+udp=tacacs port=49
+udp=tftp port=69
+udp=bootpc port=68
+udp=bootp port=67
+udp=domain port=53
+udp=dns port=53
+udp=ntp port=123
+udp=profile port=136
+udp=snmp port=161
+udp=rip port=520
+udp=bfs port=2201
+udp=virgil port=2202
+udp=bandt2 port=7331
+udp=oradius port=1645
+udp=chord-dhash port=11865
+
+gre=ppp port=34827
--- /dev/null
+++ b/lib/ndb/dns
@@ -1,0 +1,31 @@
+#
+# optional bootstrap data for ndb/dns
+# (it has got a.root-servers.net built-in if necessary)
+#
+dom=
+ ns=m.root-servers.net
+ ns=c.root-servers.net
+ ns=d.root-servers.net
+ ns=e.root-servers.net
+ ns=l.root-servers.net
+ ns=f.root-servers.net
+ ns=a.root-servers.net
+ ns=b.root-servers.net
+ ns=g.root-servers.net
+ ns=h.root-servers.net
+ ns=i.root-servers.net
+ ns=j.root-servers.net
+ ns=k.root-servers.net
+dom=a.root-servers.net ip=198.41.0.4
+dom=b.root-servers.net ip=128.9.0.107
+dom=c.root-servers.net ip=192.33.4.12
+dom=d.root-servers.net ip=128.8.10.90
+dom=e.root-servers.net ip=192.203.230.10
+dom=f.root-servers.net ip=192.5.5.241
+dom=g.root-servers.net ip=192.112.36.4
+dom=h.root-servers.net ip=128.63.2.53
+dom=i.root-servers.net ip=192.36.148.17
+dom=j.root-servers.net ip=198.41.0.10
+dom=k.root-servers.net ip=193.0.14.129
+dom=l.root-servers.net ip=198.32.64.12
+dom=m.root-servers.net ip=202.12.27.33
--- /dev/null
+++ b/lib/ndb/inferno
@@ -1,0 +1,21 @@
+#
+# inferno port assignment
+#
+
+tcp=infgamelogin port=6660 # inferno games login service
+tcp=styx port=6666 # main file service
+tcp=mpeg port=6667 # mpeg stream
+tcp=rstyx port=6668 # remote invocation
+tcp=infdb port=6669 # database server
+tcp=infweb port=6670 # inferno web server
+tcp=infsigner port=6671 # inferno signing services
+tcp=infcsigner port=6672 # inferno countersigner
+tcp=inflogin port=6673 # inferno credential service
+tcp=infsds port=6674 # software download
+tcp=registry port=6675 # default registry
+tcp=internalreg port=6676 # cpupool registry
+tcp=infkey port=6677 # key-changing service
+tcp=infsched port=6678 # grid scheduler
+
+udp=virgil port=2202 # naming service
+udp=gossip port=2666 # gossip protocol
--- /dev/null
+++ b/lib/ndb/local
@@ -1,0 +1,20 @@
+database=
+ file=/lib/ndb/local
+ file=/lib/ndb/dns
+ file=/lib/ndb/inferno
+ file=/lib/ndb/common
+
+#
+# default site-wide resources
+#
+infernosite=
+ #dnsdomain=your.domain.com
+ #dns=1.2.3.4 # resolver
+ SIGNER=your_signer_here
+ FILESERVER=your_fileserver_here
+ smtp=your_smtpserver_here
+ pop3=your_pop3server_here
+ PROXY=your_httpproxy_here
+ GAMES=your_games_server
+ registry=your_registry_server
+ gridsched=your_inferno_grid_scheduler
--- /dev/null
+++ b/lib/ndb/registry
@@ -1,0 +1,2 @@
+# this file is given to the local registry(4) by svc/registry (see svc(8))
+# as its initial data. you could put static local service descriptions here.
--- /dev/null
+++ b/lib/ndb/services
@@ -1,0 +1,21 @@
+# this is not an ndb file, but a file in Unix /etc/services format
+# that might be added to the Unix file (or the similar one on Windows)
+# if needed for host applications to access Inferno.
+# Inferno uses the ndb files when ndb/cs and ndb/dns are running
+#
+# Assignment of inferno port numbers
+#
+
+styx 6666/tcp # Main file service
+mpeg 6667/tcp # Mpeg stream
+rstyx 6668/tcp # Remote invocation
+infdb 6669/tcp # Database connection
+infweb 6670/tcp # inferno web server
+infsigner 6671/tcp # inferno signing services
+infcsigner 6672/tcp # inferno signing services
+inflogin 6673/tcp # inferno login service
+virgil 2202/udp virgild # inferno info
+infsds 6674/tcp # SDS
+infgamelogin 6660/tcp # inferno games login service
+registry 6675/tcp # default registry
+cpupoolreg 6676/tcp # cpupool registry
--- /dev/null
+++ b/lib/polyhedra
@@ -1,0 +1,2459 @@
+# data generated by kaleido written by Dr. Zvi Har'El (rl@math.technion.ac.il)
+pentagonal prism
+pentagonal dipyramid
+2 5|2
+(4.4.5)
+dihedral group
+D
+2{5}+5{4}
+0 10 15 7 10 1 0 0 2 2 3 20 2 0 -1
+ 0.0000000000 0.0000000000 1.0000000000
+ 0.8737108351 0.0000000000 0.4864456563
+-0.3018596695 0.8199093629 0.4864456563
+-0.6651309335 -0.5665434359 0.4864456563
+ 0.5718511657 0.8199093629 -0.0271086873
+ 0.7485628941 -0.5665434359 -0.3445027268
+-0.9669906029 0.2533659270 -0.0271086873
+-0.2024936222 -0.9166865354 -0.3445027268
+ 0.4467032247 0.2533659270 -0.8580570704
+-0.5043532916 -0.0967771725 -0.8580570704
+ 0.2978495106 0.4270509831 0.5067318540
+-0.5036584607 0.1319660113 0.5067318540
+ 0.2978495106 -0.8090169944 0.5067318540
+ 0.6877395818 0.1319660113 -0.1935543450
+-0.2978495106 0.8090169944 -0.5067318540
+-0.6091275581 -0.3454915028 -0.1935543450
+ 0.1271969263 -0.3454915028 -0.6263550179
+4 0 2 4 1
+4 0 3 6 2
+5 0 1 5 7 3
+4 1 4 8 5
+5 2 6 9 8 4
+4 3 7 9 6
+4 5 8 9 7
+3 2 0 1
+3 2 3 0
+3 0 4 1
+3 1 5 2
+3 3 4 0
+3 2 6 3
+3 4 5 1
+3 5 6 2
+3 6 4 3
+3 4 5 6
+pentagonal antiprism
+pentagonal deltohedron
+|2 2 5
+(3.3.3.5)
+dihedral group
+D
+2{5}+10{3}
+1 10 20 12 10 1 0 0 2 2 4 20 2 0 -1
+ 0.0000000000 0.0000000000 1.0000000000
+ 0.8944271910 0.0000000000 0.4472135955
+ 0.2763932023 0.8506508084 0.4472135955
+-0.7236067977 0.5257311121 0.4472135955
+-0.7236067977 -0.5257311121 0.4472135955
+ 0.7236067977 -0.5257311121 -0.4472135955
+ 0.7236067977 0.5257311121 -0.4472135955
+-0.8944271910 -0.0000000000 -0.4472135955
+-0.2763932023 -0.8506508084 -0.4472135955
+-0.0000000000 -0.0000000000 -1.0000000000
+ 0.2763932023 0.2008114159 0.4472135955
+-0.1055728090 0.3249196962 0.4472135955
+-0.3416407865 -0.0000000000 0.4472135955
+ 0.2763932023 -0.8506508084 0.4472135955
+ 0.5527864045 0.0000000000 -0.1055728090
+ 0.4472135955 0.3249196962 0.1055728090
+-0.2763932023 0.8506508084 -0.4472135955
+-0.5527864045 -0.0000000000 0.1055728090
+-0.4472135955 -0.3249196962 -0.1055728090
+ 0.1055728090 -0.3249196962 -0.4472135955
+ 0.3416407865 0.0000000000 -0.4472135955
+-0.2763932023 -0.2008114159 -0.4472135955
+3 0 2 1
+3 0 3 2
+3 0 4 3
+5 0 1 5 8 4
+3 1 6 5
+3 1 2 6
+5 2 3 7 9 6
+3 3 4 7
+3 4 8 7
+3 5 9 8
+3 5 6 9
+3 7 8 9
+4 3 0 1 2
+4 3 4 5 0
+4 5 6 1 0
+4 6 7 2 1
+4 7 8 3 2
+4 3 9 10 4
+4 10 6 5 4
+4 6 11 8 7
+4 11 9 3 8
+4 9 10 6 11
+tetrahedron
+tetrahedron
+3|2 3
+(3.3.3)
+tetrahedral group
+A4
+4{3}
+5 4 6 4 4 1 0 0 2 1 3 24 3 0 -1
+ 0.0000000000 0.0000000000 1.0000000000
+ 0.9428090416 0.0000000000 -0.3333333333
+-0.4714045208 0.8164965809 -0.3333333333
+-0.4714045208 -0.8164965809 -0.3333333333
+ 0.4714045208 0.8164965809 0.3333333333
+-0.9428090416 -0.0000000000 0.3333333333
+ 0.4714045208 -0.8164965809 0.3333333333
+-0.0000000000 0.0000000000 -1.0000000000
+3 0 2 1
+3 0 3 2
+3 0 1 3
+3 1 2 3
+3 2 0 1
+3 2 3 0
+3 3 1 0
+3 1 2 3
+truncated tetrahedron
+triakistetrahedron
+2 3|3
+(6.6.3)
+tetrahedral group
+A4
+4{6}+4{3}
+6 12 18 8 12 1 0 0 2 2 3 24 3 0 -1
+ 0.0000000000 0.0000000000 1.0000000000
+ 0.7713892158 0.0000000000 0.6363636364
+-0.6428243465 0.4264014327 0.6363636364
+ 0.2999846950 -0.7106690545 0.6363636364
+ 0.8999540851 0.4264014327 -0.0909090909
+-0.9856639980 0.1421338109 -0.0909090909
+-0.5142594772 0.8528028654 -0.0909090909
+-0.0428549564 -0.9949366763 -0.0909090909
+ 0.5571144337 0.1421338109 -0.8181818182
+ 0.2571297386 0.8528028654 -0.4545454545
+-0.6856793030 -0.5685352436 -0.4545454545
+ 0.0857099129 -0.5685352436 -0.8181818182
+ 0.2461829820 0.8164965809 0.5222329679
+-0.6564879519 -0.5443310540 0.5222329679
+ 0.2461829820 -0.1632993162 0.5222329679
+ 0.8206099399 -0.5443310540 -0.1740776560
+-0.4923659639 0.3265986324 0.1044465936
+ 0.3938927711 0.3265986324 -0.3133397807
+-0.4103049699 0.2721655270 -0.8703882798
+-0.1477097892 -0.4898979486 -0.3133397807
+6 0 2 6 9 4 1
+6 0 3 7 10 5 2
+3 0 1 3
+6 1 4 8 11 7 3
+3 2 5 6
+3 4 9 8
+6 5 10 11 8 9 6
+3 7 11 10
+3 2 0 1
+3 2 3 0
+3 0 4 1
+3 1 3 2
+3 3 5 0
+3 4 6 1
+3 0 6 4
+3 1 7 3
+3 3 6 5
+3 5 0 6
+3 6 7 1
+3 7 3 6
+octahedron
+hexahedron
+4|2 3
+(3.3.3.3)
+octahedral group
+S4
+8{3}
+9 6 12 8 6 1 0 0 2 1 4 48 4 0 -1
+ 0.0000000000 0.0000000000 1.0000000000
+ 1.0000000000 0.0000000000 -0.0000000000
+-0.0000000000 1.0000000000 -0.0000000000
+-1.0000000000 -0.0000000000 -0.0000000000
+ 0.0000000000 -1.0000000000 -0.0000000000
+-0.0000000000 -0.0000000000 -1.0000000000
+ 0.5773502692 0.5773502692 0.5773502692
+-0.5773502692 0.5773502692 0.5773502692
+-0.5773502692 -0.5773502692 0.5773502692
+ 0.5773502692 -0.5773502692 0.5773502692
+ 0.5773502692 -0.5773502692 -0.5773502692
+ 0.5773502692 0.5773502692 -0.5773502692
+-0.5773502692 0.5773502692 -0.5773502692
+-0.5773502692 -0.5773502692 -0.5773502692
+3 0 2 1
+3 0 3 2
+3 0 4 3
+3 0 1 4
+3 1 5 4
+3 1 2 5
+3 2 3 5
+3 3 4 5
+4 3 0 1 2
+4 3 4 5 0
+4 5 6 1 0
+4 6 7 2 1
+4 7 4 3 2
+4 4 5 6 7
+hexahedron
+octahedron
+3|2 4
+(4.4.4)
+octahedral group
+S4
+6{4}
+10 8 12 6 8 1 0 0 2 1 3 48 4 0 -1
+ 0.0000000000 0.0000000000 1.0000000000
+ 0.9428090416 0.0000000000 0.3333333333
+-0.4714045208 0.8164965809 0.3333333333
+-0.4714045208 -0.8164965809 0.3333333333
+ 0.4714045208 0.8164965809 -0.3333333333
+ 0.4714045208 -0.8164965809 -0.3333333333
+-0.9428090416 -0.0000000000 -0.3333333333
+-0.0000000000 -0.0000000000 -1.0000000000
+ 0.4082482905 0.7071067812 0.5773502692
+-0.8164965809 -0.0000000000 0.5773502692
+ 0.4082482905 -0.7071067812 0.5773502692
+ 0.8164965809 -0.0000000000 -0.5773502692
+-0.4082482905 0.7071067812 -0.5773502692
+-0.4082482905 -0.7071067812 -0.5773502692
+4 0 2 4 1
+4 0 3 6 2
+4 0 1 5 3
+4 1 4 7 5
+4 2 6 7 4
+4 3 5 7 6
+3 2 0 1
+3 2 3 0
+3 0 4 1
+3 1 5 2
+3 3 4 0
+3 5 3 2
+3 4 5 1
+3 3 4 5
+cuboctahedron
+rhombic dodecahedron
+2|3 4
+(3.4.3.4)
+octahedral group
+S4
+6{4}+8{3}
+11 12 24 14 12 1 0 0 2 2 4 48 4 0 -1
+ 0.0000000000 0.0000000000 1.0000000000
+ 0.8660254038 0.0000000000 0.5000000000
+ 0.2886751346 0.8164965809 0.5000000000
+-0.8660254038 -0.0000000000 0.5000000000
+-0.2886751346 -0.8164965809 0.5000000000
+ 0.8660254038 -0.0000000000 -0.5000000000
+ 0.5773502692 -0.8164965809 -0.0000000000
+-0.5773502692 0.8164965809 -0.0000000000
+ 0.2886751346 0.8164965809 -0.5000000000
+-0.8660254038 0.0000000000 -0.5000000000
+-0.2886751346 -0.8164965809 -0.5000000000
+-0.0000000000 -0.0000000000 -1.0000000000
+ 0.4082482905 0.2886751346 0.7071067812
+-0.4082482905 0.5773502692 0.7071067812
+-0.4082482905 -0.2886751346 0.7071067812
+ 0.4082482905 -0.5773502692 0.7071067812
+ 0.8164965809 -0.2886751346 -0.0000000000
+ 0.8164965809 0.5773502692 -0.0000000000
+ 0.0000000000 0.8660254038 -0.0000000000
+-0.8164965809 0.2886751346 -0.0000000000
+-0.8164965809 -0.5773502692 -0.0000000000
+-0.0000000000 -0.8660254038 -0.0000000000
+ 0.4082482905 -0.5773502692 -0.7071067812
+ 0.4082482905 0.2886751346 -0.7071067812
+-0.4082482905 0.5773502692 -0.7071067812
+-0.4082482905 -0.2886751346 -0.7071067812
+3 0 2 1
+4 0 3 7 2
+3 0 4 3
+4 0 1 6 4
+3 1 5 6
+4 1 2 8 5
+3 2 7 8
+3 3 9 7
+4 3 4 10 9
+3 4 6 10
+4 5 11 10 6
+3 5 8 11
+4 7 9 11 8
+3 9 10 11
+4 3 0 1 2
+4 3 4 5 0
+4 5 6 1 0
+4 1 7 8 2
+4 8 9 3 2
+4 4 10 11 5
+4 9 10 4 3
+4 6 12 7 1
+4 11 12 6 5
+4 12 13 8 7
+4 13 10 9 8
+4 10 11 12 13
+truncated octahedron
+tetrakishexahedron
+2 4|3
+(6.6.4)
+octahedral group
+S4
+8{6}+6{4}
+12 24 36 14 24 1 0 0 2 2 3 48 4 0 -1
+ 0.0000000000 0.0000000000 1.0000000000
+ 0.6000000000 0.0000000000 0.8000000000
+-0.4000000000 0.4472135955 0.8000000000
+-0.0666666667 -0.5962847940 0.8000000000
+ 0.8000000000 0.4472135955 0.4000000000
+ 0.5333333333 -0.5962847940 0.6000000000
+-0.8666666667 0.2981423970 0.4000000000
+-0.2000000000 0.8944271910 0.4000000000
+-0.5333333333 -0.7453559925 0.4000000000
+ 0.9333333333 0.2981423970 -0.2000000000
+ 0.4000000000 0.8944271910 0.2000000000
+ 0.6666666667 -0.7453559925 -0.0000000000
+-0.6666666667 0.7453559925 -0.0000000000
+-0.9333333333 -0.2981423970 0.2000000000
+-0.4000000000 -0.8944271910 -0.2000000000
+ 0.5333333333 0.7453559925 -0.4000000000
+ 0.8666666667 -0.2981423970 -0.4000000000
+ 0.2000000000 -0.8944271910 -0.4000000000
+-0.5333333333 0.5962847940 -0.6000000000
+-0.8000000000 -0.4472135955 -0.4000000000
+ 0.0666666667 0.5962847940 -0.8000000000
+ 0.4000000000 -0.4472135955 -0.8000000000
+-0.6000000000 0.0000000000 -0.8000000000
+-0.0000000000 0.0000000000 -1.0000000000
+ 0.2581988897 0.5773502692 0.7745966692
+-0.6024640761 -0.1924500897 0.7745966692
+ 0.2581988897 -0.2886751346 0.7745966692
+ 0.9467292624 -0.1924500897 0.2581988897
+-0.5163977795 0.5773502692 0.3872983346
+ 0.0860662966 -0.9622504486 0.2581988897
+ 0.6454972244 0.5773502692 -0.0000000000
+-0.9467292624 0.1924500897 -0.2581988897
+-0.0860662966 0.9622504486 -0.2581988897
+-0.6454972244 -0.5773502692 -0.0000000000
+ 0.6024640761 0.1924500897 -0.7745966692
+ 0.5163977795 -0.5773502692 -0.3872983346
+-0.2581988897 -0.5773502692 -0.7745966692
+-0.2581988897 0.2886751346 -0.7745966692
+6 0 2 7 10 4 1
+6 0 3 8 13 6 2
+4 0 1 5 3
+6 1 4 9 16 11 5
+4 2 6 12 7
+6 3 5 11 17 14 8
+4 4 10 15 9
+6 6 13 19 22 18 12
+6 7 12 18 20 15 10
+4 8 14 19 13
+6 9 15 20 23 21 16
+4 11 16 21 17
+6 14 17 21 23 22 19
+4 18 22 23 20
+3 2 0 1
+3 2 3 0
+3 0 4 1
+3 1 5 2
+3 3 6 0
+3 5 3 2
+3 4 7 1
+3 0 8 4
+3 1 9 5
+3 3 10 6
+3 6 8 0
+3 5 11 3
+3 8 7 4
+3 7 9 1
+3 9 12 5
+3 10 8 6
+3 11 10 3
+3 12 11 5
+3 8 13 7
+3 7 12 9
+3 10 13 8
+3 12 10 11
+3 13 12 7
+3 10 13 12
+truncated hexahedron
+triakisoctahedron
+2 3|4
+(8.8.3)
+octahedral group
+S4
+6{8}+8{3}
+13 24 36 14 24 1 0 0 2 2 3 48 4 0 -1
+ 0.0000000000 0.0000000000 1.0000000000
+ 0.5395042868 0.0000000000 0.8419828529
+-0.4604957132 0.2810846377 0.8419828529
+ 0.2466110680 -0.4798414911 0.8419828529
+ 0.8419828529 0.2810846377 0.4604957132
+-0.8651239283 0.1987568534 0.4604957132
+-0.5722307095 0.6785983445 0.4604957132
+ 0.1348760717 -0.8773551980 0.4604957132
+ 0.9768589246 0.1987568534 -0.0790085736
+ 0.7302478566 0.6785983445 0.0790085736
+-0.9768589246 -0.1987568534 0.0790085736
+-0.2697521434 0.9596829823 0.0790085736
+-0.2697521434 -0.9596829823 0.0790085736
+ 0.2697521434 -0.9596829823 -0.0790085736
+ 0.8651239283 -0.1987568534 -0.4604957132
+ 0.2697521434 0.9596829823 -0.0790085736
+-0.7302478566 -0.6785983445 -0.0790085736
+-0.8419828529 -0.2810846377 -0.4604957132
+-0.1348760717 0.8773551980 -0.4604957132
+ 0.5722307095 -0.6785983445 -0.4604957132
+ 0.4604957132 -0.2810846377 -0.8419828529
+-0.5395042868 0.0000000000 -0.8419828529
+-0.2466110680 0.4798414911 -0.8419828529
+-0.0000000000 0.0000000000 -1.0000000000
+ 0.1987568534 0.7071067812 0.6785983445
+-0.5380560257 -0.5000000000 0.6785983445
+ 0.1987568534 -0.1213203436 0.6785983445
+ 0.8191406634 -0.5000000000 0.2810846377
+-0.4798414911 0.2928932188 0.4457402063
+ 0.6444970597 0.2928932188 0.1164290691
+-0.8191406634 0.5000000000 -0.2810846377
+ 0.0341012848 -0.7071067812 0.1164290691
+ 0.5380560257 0.5000000000 -0.6785983445
+-0.6444970597 -0.2928932188 -0.1164290691
+-0.0341012848 0.7071067812 -0.1164290691
+-0.1987568534 -0.7071067812 -0.6785983445
+ 0.4798414911 -0.2928932188 -0.4457402063
+-0.1987568534 0.1213203436 -0.6785983445
+8 0 2 6 11 15 9 4 1
+8 0 3 7 12 16 10 5 2
+3 0 1 3
+8 1 4 8 14 19 13 7 3
+3 2 5 6
+3 4 9 8
+8 5 10 17 21 22 18 11 6
+3 7 13 12
+8 8 9 15 18 22 23 20 14
+3 10 16 17
+3 11 18 15
+8 12 13 19 20 23 21 17 16
+3 14 20 19
+3 21 23 22
+3 2 0 1
+3 2 3 0
+3 0 4 1
+3 1 3 2
+3 3 5 0
+3 4 6 1
+3 0 6 4
+3 1 7 3
+3 3 8 5
+3 8 0 5
+3 6 9 1
+3 0 10 6
+3 1 11 7
+3 11 3 7
+3 3 12 8
+3 8 10 0
+3 9 11 1
+3 6 11 9
+3 8 6 10
+3 11 12 3
+3 11 8 12
+3 6 13 11
+3 8 13 6
+3 11 8 13
+small rhombicuboctahedron
+deltoidal icositetrahedron
+3 4|2
+(4.3.4.4)
+octahedral group
+S4
+18{4}+8{3}
+14 24 48 26 24 1 0 0 2 2 4 48 4 0 -1
+ 0.0000000000 0.0000000000 1.0000000000
+ 0.6675992222 0.0000000000 0.7445208382
+-0.0977676425 0.6604015517 0.7445208382
+-0.6389637427 0.1934271362 0.7445208382
+-0.0977676425 -0.6604015517 0.7445208382
+ 0.5698315797 0.6604015517 0.4890416764
+ 0.9727633538 0.1934271362 0.1277395809
+ 0.5698315797 -0.6604015517 0.4890416764
+-0.3337996111 0.9339488311 0.1277395809
+-0.7367313852 -0.4669744155 0.4890416764
+-0.8749957112 0.4669744155 0.1277395809
+-0.3337996111 -0.9339488311 0.1277395809
+ 0.3337996111 0.9339488311 -0.1277395809
+ 0.8749957112 -0.4669744155 -0.1277395809
+ 0.7367313852 0.4669744155 -0.4890416764
+ 0.3337996111 -0.9339488311 -0.1277395809
+-0.5698315797 0.6604015517 -0.4890416764
+-0.9727633538 -0.1934271362 -0.1277395809
+-0.5698315797 -0.6604015517 -0.4890416764
+ 0.0977676425 0.6604015517 -0.7445208382
+ 0.6389637427 -0.1934271362 -0.7445208382
+ 0.0977676425 -0.6604015517 -0.7445208382
+-0.6675992222 0.0000000000 -0.7445208382
+-0.0000000000 0.0000000000 -1.0000000000
+ 0.3302007759 0.3826834324 0.8628562095
+-0.2553967884 0.2959899757 0.8628562095
+-0.4269143440 -0.2705980501 0.8628562095
+ 0.3302007759 -0.3826834324 0.8628562095
+ 0.8938887595 -0.2705980501 0.3574067443
+ 0.7661903653 0.2959899757 0.4719117310
+ 0.1367736397 0.9238795325 0.3574067443
+-0.5636879836 0.6532814824 0.5054494651
+-0.9339488311 -0.0000000000 0.3574067443
+-0.4050047633 -0.7145830136 0.4719117310
+ 0.1367736397 -0.9238795325 0.3574067443
+ 0.7571151198 0.6532814824 -0.0000000000
+ 0.9339488311 -0.0000000000 -0.3574067443
+ 0.6165823904 -0.7145830136 0.0809672526
+-0.1367736397 0.9238795325 -0.3574067443
+-0.6165823904 0.7145830136 -0.0809672526
+-0.7571151198 -0.6532814824 -0.0000000000
+-0.8938887595 0.2705980501 -0.3574067443
+-0.1367736397 -0.9238795325 -0.3574067443
+ 0.4050047633 0.7145830136 -0.4719117310
+ 0.5636879836 -0.6532814824 -0.5054494651
+ 0.4269143440 0.2705980501 -0.8628562095
+-0.3302007759 0.3826834324 -0.8628562095
+-0.7661903653 -0.2959899757 -0.4719117310
+-0.3302007759 -0.3826834324 -0.8628562095
+ 0.2553967884 -0.2959899757 -0.8628562095
+4 0 2 5 1
+3 0 3 2
+4 0 4 9 3
+4 0 1 7 4
+4 1 6 13 7
+3 1 5 6
+4 2 8 12 5
+4 2 3 10 8
+4 3 9 17 10
+3 4 11 9
+4 4 7 15 11
+4 5 12 14 6
+4 6 14 20 13
+3 7 13 15
+4 8 16 19 12
+3 8 10 16
+4 9 11 18 17
+4 10 17 22 16
+4 11 15 21 18
+3 12 19 14
+4 13 20 21 15
+4 14 19 23 20
+4 16 22 23 19
+3 17 18 22
+4 18 21 23 22
+3 20 23 21
+4 3 0 1 2
+4 3 4 5 0
+4 0 6 7 1
+4 7 8 2 1
+4 2 9 10 3
+4 5 11 6 0
+4 4 12 11 5
+4 10 13 4 3
+4 6 14 15 7
+4 8 16 9 2
+4 15 17 8 7
+4 16 18 10 9
+4 11 19 14 6
+4 13 20 12 4
+4 12 21 19 11
+4 18 20 13 10
+4 14 22 17 15
+4 17 23 16 8
+4 23 24 18 16
+4 21 22 14 19
+4 20 25 21 12
+4 24 25 20 18
+4 22 24 23 17
+4 21 22 24 25
+truncated cuboctahedron
+disdyakisdodecahedron
+2 3 4|
+(4.6.8)
+octahedral group
+S4
+6{8}+8{6}+12{4}
+15 48 72 26 48 1 0 0 2 3 3 48 4 0 -1
+ 0.0000000000 0.0000000000 1.0000000000
+ 0.4213179058 0.0000000000 0.9069130180
+-0.0205668596 0.4208156152 0.9069130180
+-0.3330265737 -0.2580737859 0.9069130180
+ 0.4007510462 0.4208156152 0.8138260361
+ 0.6841248285 -0.2580737859 0.6821811637
+-0.3741602929 0.5835574446 0.7207390541
+-0.3826793651 -0.6230452339 0.6821811637
+-0.6866200070 -0.0953319565 0.7207390541
+ 0.6429911093 0.5835574446 0.4960071997
+ 0.6344720372 -0.6230452339 0.4574493093
+ 0.9263648917 -0.0953319565 0.3643623273
+-0.4528990160 0.8137091469 0.3643623273
+-0.7071868666 0.3254836587 0.6276520721
+-0.7362727984 -0.4603034045 0.4960071997
+-0.1198724423 -0.8811190198 0.4574493093
+ 0.5642523862 0.8137091469 0.1396304730
+ 0.9057980321 0.3254836587 0.2712753454
+ 0.8767121003 -0.4603034045 0.1396304730
+ 0.3014454635 -0.8811190198 0.3643623273
+-0.7859255897 0.5556353610 0.2712753454
+-0.2106589529 0.9764509762 0.0465434910
+-0.8270593089 -0.5556353610 0.0851013814
+-0.2106589529 -0.9764509762 0.0465434910
+ 0.8270593089 0.5556353610 -0.0851013814
+ 0.2106589529 0.9764509762 -0.0465434910
+ 0.7859255897 -0.5556353610 -0.2712753454
+ 0.2106589529 -0.9764509762 -0.0465434910
+-0.8767121003 0.4603034045 -0.1396304730
+-0.3014454635 0.8811190198 -0.3643623273
+-0.9057980321 -0.3254836587 -0.2712753454
+-0.5642523862 -0.8137091469 -0.1396304730
+ 0.7362727984 0.4603034045 -0.4960071997
+ 0.1198724423 0.8811190198 -0.4574493093
+ 0.7071868666 -0.3254836587 -0.6276520721
+ 0.4528990160 -0.8137091469 -0.3643623273
+-0.9263648917 0.0953319565 -0.3643623273
+-0.6344720372 0.6230452339 -0.4574493093
+-0.6429911093 -0.5835574446 -0.4960071997
+ 0.6866200070 0.0953319565 -0.7207390541
+ 0.3826793651 0.6230452339 -0.6821811637
+ 0.3741602929 -0.5835574446 -0.7207390541
+-0.6841248285 0.2580737859 -0.6821811637
+-0.4007510462 -0.4208156152 -0.8138260361
+ 0.3330265737 0.2580737859 -0.9069130180
+ 0.0205668596 -0.4208156152 -0.9069130180
+-0.4213179058 -0.0000000000 -0.9069130180
+-0.0000000000 -0.0000000000 -1.0000000000
+ 0.1824857240 0.1916223125 0.8259425910
+-0.3588578683 0.1651647923 0.8259425910
+ 0.1824857240 -0.5334020968 0.8259425910
+ 0.6734372751 0.1651647923 0.5978648424
+ 0.1150758511 0.8458618109 0.5208409981
+-0.4869154353 -0.3271197492 0.6388327969
+ 0.7107416431 -0.3271197492 0.3742195883
+-0.5282559191 0.5187420617 0.4517230027
+-0.4805150176 -0.7290726662 0.2753141970
+-0.9764509762 0.0000000000 0.2157394053
+ 0.6694011593 0.5187420617 0.1871097942
+ 0.5517801258 -0.7290726662 0.0472364484
+ 0.9764509762 0.0000000000 -0.2157394053
+-0.5517801258 0.7290726662 -0.0472364484
+ 0.0413404837 -0.8458618109 0.1871097942
+ 0.4805150176 0.7290726662 -0.2753141970
+-0.0413404837 0.8458618109 -0.1871097942
+-0.6694011593 -0.5187420617 -0.1871097942
+-0.1150758511 -0.8458618109 -0.5208409981
+ 0.5282559191 -0.5187420617 -0.4517230027
+-0.7107416431 0.3271197492 -0.3742195883
+-0.1824857240 0.5334020968 -0.8259425910
+-0.6734372751 -0.1651647923 -0.5978648424
+ 0.4869154353 0.3271197492 -0.6388327969
+ 0.3588578683 -0.1651647923 -0.8259425910
+-0.1824857240 -0.1916223125 -0.8259425910
+4 0 2 4 1
+6 0 3 8 13 6 2
+8 0 1 5 10 19 15 7 3
+6 1 4 9 17 11 5
+8 2 6 12 21 25 16 9 4
+4 3 7 14 8
+4 5 11 18 10
+4 6 13 20 12
+6 7 15 23 31 22 14
+8 8 14 22 30 36 28 20 13
+4 9 16 24 17
+6 10 18 26 35 27 19
+8 11 17 24 32 39 34 26 18
+6 12 20 28 37 29 21
+4 15 19 27 23
+6 16 25 33 40 32 24
+4 21 29 33 25
+4 22 31 38 30
+8 23 27 35 41 45 43 38 31
+4 26 34 41 35
+4 28 36 42 37
+8 29 37 42 46 47 44 40 33
+6 30 38 43 46 42 36
+4 32 40 44 39
+6 34 39 44 47 45 41
+4 43 45 47 46
+3 2 0 1
+3 2 3 0
+3 0 4 1
+3 1 5 2
+3 3 4 0
+3 2 6 3
+3 4 7 1
+3 5 8 2
+3 1 9 5
+3 3 10 4
+3 2 11 6
+3 6 12 3
+3 4 13 7
+3 7 9 1
+3 9 8 5
+3 8 14 2
+3 10 15 4
+3 12 10 3
+3 11 12 6
+3 14 11 2
+3 13 9 7
+3 4 16 13
+3 9 17 8
+3 8 18 14
+3 12 15 10
+3 15 16 4
+3 11 19 12
+3 18 11 14
+3 13 20 9
+3 16 21 13
+3 9 22 17
+3 17 18 8
+3 12 23 15
+3 15 21 16
+3 19 24 12
+3 18 19 11
+3 20 22 9
+3 21 20 13
+3 22 18 17
+3 24 23 12
+3 23 21 15
+3 18 24 19
+3 21 22 20
+3 22 25 18
+3 24 21 23
+3 25 24 18
+3 21 25 22
+3 24 21 25
+snub hexahedron
+pentagonal icositetrahedron
+|2 3 4
+(3.3.3.3.4)
+octahedral group
+S4
+6{4}+32{3}
+16 24 60 38 24 1 0 0 2 2 5 48 4 0 -1
+ 0.0000000000 0.0000000000 1.0000000000
+ 0.6907659000 0.0000000000 0.7230784683
+ 0.2898753354 0.6270006527 0.7230784683
+-0.4474773703 0.5262333434 0.7230784683
+-0.6654371656 -0.1853399775 0.7230784683
+-0.1110152292 -0.6817867317 0.7230784683
+ 0.5797506708 -0.6817867317 0.4461569367
+ 0.9806412354 -0.1853399775 0.0631811688
+ 0.8230392005 0.5262333434 0.2137403629
+ 0.2432885297 0.9678940186 0.0631811688
+-0.4940641761 0.8671267092 0.0631811688
+-0.9340544297 0.2861072869 0.2137403629
+-0.6516662110 -0.7277679621 0.2137403629
+ 0.0253287344 -0.9976806078 0.0631811688
+ 0.6188503599 -0.7277679621 -0.2955977425
+ 0.7626814402 -0.0845726681 -0.6412210887
+ 0.6050794053 0.6270006527 -0.4906618946
+-0.1110152292 0.8123406303 -0.5725192742
+-0.7511236604 0.4416606752 -0.4906618946
+-0.9202834751 -0.2563206977 -0.2955977425
+-0.4146615192 -0.7663593998 -0.4906618946
+ 0.1788601062 -0.4964467542 -0.8494408059
+ 0.1713729895 0.2401260565 -0.9554950421
+-0.4687354417 -0.1305538986 -0.8736376625
+ 0.3408933659 0.2179597953 0.8503402074
+-0.0547860790 0.4008905646 0.8503402074
+-0.3868745963 0.1185023459 0.8503402074
+-0.2699126456 -0.3014331152 0.8503402074
+ 0.3408933659 -0.4008905646 0.8503402074
+ 0.7825540411 -0.3014331152 0.4284162431
+ 0.8671267092 0.1185023459 0.3476229160
+ 0.6270006527 0.4008905646 0.5770183396
+ 0.4714472644 0.7373527058 0.3476229160
+-0.1200630282 0.8785468151 0.4623206278
+-0.6520001425 0.5838213339 0.3476229160
+-0.7115733209 0.2179597953 0.5770183396
+-0.9324036585 -0.2596964552 0.2513586457
+-0.4964467542 -0.5544219364 0.5770183396
+-0.2563206977 -0.8368101551 0.3476229160
+ 0.1717480296 -0.8208260257 0.4284162431
+ 0.4254660340 -0.8368101551 0.0743010482
+ 0.7575545513 -0.5544219364 0.0743010482
+ 0.8211454788 -0.3468166421 -0.3036964718
+ 0.9324036585 0.2596964552 -0.2513586457
+ 0.5810194223 0.7373527058 -0.0743010482
+ 0.2563206977 0.8368101551 -0.3476229160
+-0.1257667992 0.9202834751 -0.1550943753
+-0.4714472644 0.7373527058 -0.3476229160
+-0.7575545513 0.5544219364 -0.0743010482
+-0.9057181469 0.1638858728 -0.1990208196
+-0.6905915802 -0.6084958589 -0.1990208196
+-0.3618751065 -0.8662095526 -0.0743010482
+ 0.1200630282 -0.8785468151 -0.4623206278
+ 0.5424279846 -0.4549644871 -0.6209447838
+ 0.3868745963 -0.1185023459 -0.8503402074
+ 0.5350381919 0.2720337177 -0.7256204361
+ 0.2313212079 0.5838213339 -0.7017381110
+-0.3408933659 0.4008905646 -0.8503402074
+-0.7439626034 0.0190448965 -0.5770183396
+-0.6270006527 -0.4008905646 -0.5770183396
+-0.2449131559 -0.4843638846 -0.7695468803
+-0.0411941310 -0.1344864753 -0.9311335345
+3 0 2 1
+3 0 3 2
+3 0 4 3
+3 0 5 4
+4 0 1 6 5
+3 1 7 6
+3 1 8 7
+3 1 2 8
+3 2 9 8
+4 2 3 10 9
+3 3 11 10
+3 3 4 11
+4 4 12 19 11
+3 4 5 12
+3 5 13 12
+3 5 6 13
+3 6 14 13
+3 6 7 14
+3 7 15 14
+4 7 8 16 15
+3 8 9 16
+3 9 17 16
+3 9 10 17
+3 10 18 17
+3 10 11 18
+3 11 19 18
+3 12 20 19
+3 12 13 20
+4 13 14 21 20
+3 14 15 21
+3 15 22 21
+3 15 16 22
+3 16 17 22
+4 17 18 23 22
+3 18 19 23
+3 19 20 23
+3 20 21 23
+3 21 22 23
+5 4 0 1 2 3
+5 4 5 6 7 0
+5 7 8 9 1 0
+5 9 10 11 2 1
+5 11 12 13 3 2
+5 13 14 15 4 3
+5 15 16 17 5 4
+5 17 18 19 6 5
+5 19 20 8 7 6
+5 20 21 22 9 8
+5 22 23 24 10 9
+5 24 25 12 11 10
+5 12 26 27 14 13
+5 27 28 16 15 14
+5 28 29 18 17 16
+5 29 30 31 19 18
+5 31 32 21 20 19
+5 32 33 23 22 21
+5 33 34 25 24 23
+5 34 35 26 12 25
+5 35 36 28 27 26
+5 36 37 30 29 28
+5 37 33 32 31 30
+5 33 34 35 36 37
+icosahedron
+dodecahedron
+5|2 3
+(3.3.3.3.3)
+icosahedral group
+A5
+20{3}
+26 12 30 20 12 1 0 0 2 1 5 120 5 0 -1
+ 0.0000000000 0.0000000000 1.0000000000
+ 0.8944271910 0.0000000000 0.4472135955
+ 0.2763932023 0.8506508084 0.4472135955
+-0.7236067977 0.5257311121 0.4472135955
+-0.7236067977 -0.5257311121 0.4472135955
+ 0.2763932023 -0.8506508084 0.4472135955
+ 0.7236067977 0.5257311121 -0.4472135955
+ 0.7236067977 -0.5257311121 -0.4472135955
+-0.2763932023 0.8506508084 -0.4472135955
+-0.8944271910 -0.0000000000 -0.4472135955
+-0.2763932023 -0.8506508084 -0.4472135955
+-0.0000000000 -0.0000000000 -1.0000000000
+ 0.4911234732 0.3568220898 0.7946544723
+-0.1875924741 0.5773502692 0.7946544723
+-0.6070619982 -0.0000000000 0.7946544723
+-0.1875924741 -0.5773502692 0.7946544723
+ 0.4911234732 -0.3568220898 0.7946544723
+ 0.7946544723 -0.5773502692 0.1875924741
+ 0.9822469464 -0.0000000000 -0.1875924741
+ 0.7946544723 0.5773502692 0.1875924741
+ 0.3035309991 0.9341723590 -0.1875924741
+-0.3035309991 0.9341723590 0.1875924741
+-0.7946544723 0.5773502692 -0.1875924741
+-0.9822469464 -0.0000000000 0.1875924741
+-0.7946544723 -0.5773502692 -0.1875924741
+-0.3035309991 -0.9341723590 0.1875924741
+ 0.3035309991 -0.9341723590 -0.1875924741
+ 0.6070619982 -0.0000000000 -0.7946544723
+ 0.1875924741 0.5773502692 -0.7946544723
+ 0.1875924741 -0.5773502692 -0.7946544723
+-0.4911234732 0.3568220898 -0.7946544723
+-0.4911234732 -0.3568220898 -0.7946544723
+3 0 2 1
+3 0 3 2
+3 0 4 3
+3 0 5 4
+3 0 1 5
+3 1 7 5
+3 1 6 7
+3 1 2 6
+3 2 8 6
+3 2 3 8
+3 3 9 8
+3 3 4 9
+3 4 10 9
+3 4 5 10
+3 5 7 10
+3 6 11 7
+3 6 8 11
+3 7 11 10
+3 8 9 11
+3 9 10 11
+5 4 0 1 2 3
+5 4 5 6 7 0
+5 7 8 9 1 0
+5 9 10 11 2 1
+5 11 12 13 3 2
+5 13 14 5 4 3
+5 6 15 16 8 7
+5 14 17 15 6 5
+5 16 18 10 9 8
+5 18 19 12 11 10
+5 19 17 14 13 12
+5 15 16 18 19 17
+dodecahedron
+icosahedron
+3|2 5
+(5.5.5)
+icosahedral group
+A5
+12{5}
+27 20 30 12 20 1 0 0 2 1 3 120 5 0 -1
+ 0.0000000000 0.0000000000 1.0000000000
+ 0.6666666667 0.0000000000 0.7453559925
+-0.3333333333 0.5773502692 0.7453559925
+-0.3333333333 -0.5773502692 0.7453559925
+ 0.7453559925 0.5773502692 0.3333333333
+ 0.7453559925 -0.5773502692 0.3333333333
+-0.8726779962 0.3568220898 0.3333333333
+ 0.1273220038 0.9341723590 0.3333333333
+ 0.1273220038 -0.9341723590 0.3333333333
+-0.8726779962 -0.3568220898 0.3333333333
+ 0.8726779962 0.3568220898 -0.3333333333
+ 0.8726779962 -0.3568220898 -0.3333333333
+-0.7453559925 0.5773502692 -0.3333333333
+-0.1273220038 0.9341723590 -0.3333333333
+-0.1273220038 -0.9341723590 -0.3333333333
+-0.7453559925 -0.5773502692 -0.3333333333
+ 0.3333333333 0.5773502692 -0.7453559925
+ 0.3333333333 -0.5773502692 -0.7453559925
+-0.6666666667 -0.0000000000 -0.7453559925
+-0.0000000000 -0.0000000000 -1.0000000000
+ 0.3035309991 0.5257311121 0.7946544723
+-0.6070619982 -0.0000000000 0.7946544723
+ 0.3035309991 -0.5257311121 0.7946544723
+ 0.9822469464 -0.0000000000 0.1875924741
+-0.4911234732 0.8506508084 0.1875924741
+-0.4911234732 -0.8506508084 0.1875924741
+ 0.4911234732 0.8506508084 -0.1875924741
+ 0.4911234732 -0.8506508084 -0.1875924741
+-0.9822469464 -0.0000000000 -0.1875924741
+ 0.6070619982 -0.0000000000 -0.7946544723
+-0.3035309991 0.5257311121 -0.7946544723
+-0.3035309991 -0.5257311121 -0.7946544723
+5 0 2 7 4 1
+5 0 3 9 6 2
+5 0 1 5 8 3
+5 1 4 10 11 5
+5 2 6 12 13 7
+5 3 8 14 15 9
+5 4 7 13 16 10
+5 5 11 17 14 8
+5 6 9 15 18 12
+5 10 16 19 17 11
+5 12 18 19 16 13
+5 14 17 19 18 15
+3 2 0 1
+3 2 3 0
+3 0 4 1
+3 1 5 2
+3 3 6 0
+3 2 7 3
+3 4 8 1
+3 6 4 0
+3 5 7 2
+3 8 5 1
+3 3 9 6
+3 7 9 3
+3 4 10 8
+3 6 10 4
+3 5 11 7
+3 8 11 5
+3 9 10 6
+3 11 9 7
+3 10 11 8
+3 9 10 11
+icosidodecahedron
+rhombic triacontahedron
+2|3 5
+(3.5.3.5)
+icosahedral group
+A5
+12{5}+20{3}
+28 30 60 32 30 1 0 0 2 2 4 120 5 0 -1
+ 0.0000000000 0.0000000000 1.0000000000
+ 0.5877852523 0.0000000000 0.8090169944
+ 0.2628655561 0.5257311121 0.8090169944
+-0.5877852523 -0.0000000000 0.8090169944
+-0.2628655561 -0.5257311121 0.8090169944
+ 0.9510565163 -0.0000000000 0.3090169944
+ 0.6881909602 -0.5257311121 0.5000000000
+-0.1624598481 0.8506508084 0.5000000000
+ 0.4253254042 0.8506508084 0.3090169944
+-0.9510565163 0.0000000000 0.3090169944
+-0.6881909602 0.5257311121 0.5000000000
+ 0.1624598481 -0.8506508084 0.5000000000
+-0.4253254042 -0.8506508084 0.3090169944
+ 0.9510565163 -0.0000000000 -0.3090169944
+ 0.8506508084 0.5257311121 -0.0000000000
+ 0.5257311121 -0.8506508084 -0.0000000000
+-0.5257311121 0.8506508084 -0.0000000000
+ 0.4253254042 0.8506508084 -0.3090169944
+-0.9510565163 0.0000000000 -0.3090169944
+-0.8506508084 -0.5257311121 -0.0000000000
+-0.4253254042 -0.8506508084 -0.3090169944
+ 0.5877852523 -0.0000000000 -0.8090169944
+ 0.6881909602 -0.5257311121 -0.5000000000
+ 0.1624598481 -0.8506508084 -0.5000000000
+-0.6881909602 0.5257311121 -0.5000000000
+-0.1624598481 0.8506508084 -0.5000000000
+ 0.2628655561 0.5257311121 -0.8090169944
+-0.5877852523 0.0000000000 -0.8090169944
+-0.2628655561 -0.5257311121 -0.8090169944
+-0.0000000000 0.0000000000 -1.0000000000
+ 0.2763932023 0.1708203932 0.8506508084
+-0.2763932023 0.4472135955 0.8506508084
+-0.2763932023 -0.1708203932 0.8506508084
+ 0.2763932023 -0.4472135955 0.8506508084
+ 0.7236067977 -0.1708203932 0.5257311121
+ 0.7236067977 0.4472135955 0.5257311121
+ 0.1708203932 0.7236067977 0.5257311121
+-0.7236067977 0.1708203932 0.5257311121
+-0.7236067977 -0.4472135955 0.5257311121
+-0.1708203932 -0.7236067977 0.5257311121
+ 0.8944271910 -0.4472135955 -0.0000000000
+ 0.8944271910 0.1708203932 -0.0000000000
+ 0.4472135955 -0.7236067977 0.3249196962
+-0.0000000000 1.0000000000 -0.0000000000
+-0.4472135955 0.7236067977 0.3249196962
+ 0.5527864045 0.7236067977 -0.0000000000
+-0.8944271910 0.4472135955 -0.0000000000
+-0.8944271910 -0.1708203932 -0.0000000000
+-0.0000000000 -1.0000000000 -0.0000000000
+-0.5527864045 -0.7236067977 -0.0000000000
+ 0.7236067977 -0.1708203932 -0.5257311121
+ 0.7236067977 0.4472135955 -0.5257311121
+ 0.4472135955 -0.7236067977 -0.3249196962
+-0.4472135955 0.7236067977 -0.3249196962
+ 0.1708203932 0.7236067977 -0.5257311121
+-0.7236067977 0.1708203932 -0.5257311121
+-0.7236067977 -0.4472135955 -0.5257311121
+-0.1708203932 -0.7236067977 -0.5257311121
+ 0.2763932023 -0.4472135955 -0.8506508084
+ 0.2763932023 0.1708203932 -0.8506508084
+-0.2763932023 0.4472135955 -0.8506508084
+-0.2763932023 -0.1708203932 -0.8506508084
+3 0 2 1
+5 0 3 10 7 2
+3 0 4 3
+5 0 1 6 11 4
+3 1 5 6
+5 1 2 8 14 5
+3 2 7 8
+3 3 9 10
+5 3 4 12 19 9
+3 4 11 12
+5 5 13 22 15 6
+3 5 14 13
+3 6 15 11
+5 7 16 25 17 8
+3 7 10 16
+3 8 17 14
+5 9 18 24 16 10
+3 9 19 18
+5 11 15 23 20 12
+3 12 20 19
+3 13 21 22
+5 13 14 17 26 21
+3 15 22 23
+3 16 24 25
+3 17 25 26
+3 18 27 24
+5 18 19 20 28 27
+3 20 23 28
+5 21 29 28 23 22
+3 21 26 29
+5 24 27 29 26 25
+3 27 28 29
+4 3 0 1 2
+4 3 4 5 0
+4 5 6 1 0
+4 1 7 8 2
+4 8 9 3 2
+4 4 10 11 5
+4 3 12 10 4
+4 6 13 14 1
+4 5 15 13 6
+4 7 16 17 8
+4 14 16 7 1
+4 9 18 12 3
+4 8 19 18 9
+4 10 20 21 11
+4 21 15 5 11
+4 18 22 10 12
+4 13 23 16 14
+4 21 24 13 15
+4 16 25 26 17
+4 26 19 8 17
+4 26 27 18 19
+4 20 28 29 21
+4 22 28 20 10
+4 27 28 22 18
+4 23 30 25 16
+4 24 30 23 13
+4 29 30 24 21
+4 30 31 26 25
+4 31 28 27 26
+4 28 29 30 31
+truncated icosahedron
+pentakisdodecahedron
+2 5|3
+(6.6.5)
+icosahedral group
+A5
+20{6}+12{5}
+29 60 90 32 60 1 0 0 2 2 3 120 5 0 -1
+ 0.0000000000 0.0000000000 1.0000000000
+ 0.3952480672 0.0000000000 0.9185744202
+-0.2227859215 0.3264773618 0.9185744202
+-0.1440965957 -0.3680451137 0.9185744202
+ 0.5677102129 0.3264773618 0.7557232605
+ 0.4954282110 -0.3680451137 0.7868250644
+-0.5896684388 0.2849096099 0.7557232605
+-0.0503237759 0.6529547237 0.7557232605
+ 0.1620948777 -0.5955095034 0.7868250644
+-0.5109791130 -0.4096128656 0.7557232605
+ 0.8403525023 0.2849096099 0.4611227451
+ 0.3449242913 0.6529547237 0.6742976806
+ 0.7680705005 -0.4096128656 0.4922245490
+-0.6439521587 0.5856966883 0.4922245490
+-0.7337650345 -0.0831355038 0.6742976806
+-0.3106188254 0.8131610779 0.4922245490
+ 0.1014038338 -0.8645416449 0.4922245490
+-0.5716701569 -0.6786450072 0.4611227451
+ 0.7860687824 0.5856966883 0.1976240336
+ 0.9405326461 -0.0831355038 0.3293733893
+ 0.4798773090 0.8131610779 0.3293733893
+ 0.7073794566 -0.6786450072 0.1976240336
+-0.8423324743 0.5184386529 0.1473002577
+-0.9321453501 -0.1503935392 0.3293733893
+-0.1756658076 0.9733674322 0.1473002577
+ 0.3740461233 -0.9061093968 0.1976240336
+-0.2654786835 -0.9061093968 0.3293733893
+-0.8319652063 -0.5184386529 0.1976240336
+ 0.8319652063 0.5184386529 -0.1976240336
+ 0.9864290700 -0.1503935392 -0.0658746779
+ 0.2195822596 0.9733674322 0.0658746779
+ 0.8423324743 -0.5184386529 -0.1473002577
+-0.7073794566 0.6786450072 -0.1976240336
+-0.9864290700 0.1503935392 0.0658746779
+-0.3740461233 0.9061093968 -0.1976240336
+ 0.1756658076 -0.9733674322 -0.1473002577
+-0.2195822596 -0.9733674322 -0.0658746779
+-0.7860687824 -0.5856966883 -0.1976240336
+ 0.5716701569 0.6786450072 -0.4611227451
+ 0.9321453501 0.1503935392 -0.3293733893
+ 0.2654786835 0.9061093968 -0.3293733893
+ 0.6439521587 -0.5856966883 -0.4922245490
+-0.7680705005 0.4096128656 -0.4922245490
+-0.9405326461 0.0831355038 -0.3293733893
+-0.1014038338 0.8645416449 -0.4922245490
+ 0.3106188254 -0.8131610779 -0.4922245490
+-0.4798773090 -0.8131610779 -0.3293733893
+-0.8403525023 -0.2849096099 -0.4611227451
+ 0.5109791130 0.4096128656 -0.7557232605
+ 0.7337650345 0.0831355038 -0.6742976806
+ 0.5896684388 -0.2849096099 -0.7557232605
+-0.4954282110 0.3680451137 -0.7868250644
+-0.1620948777 0.5955095034 -0.7868250644
+ 0.0503237759 -0.6529547237 -0.7557232605
+-0.3449242913 -0.6529547237 -0.6742976806
+-0.5677102129 -0.3264773618 -0.7557232605
+ 0.1440965957 0.3680451137 -0.9185744202
+ 0.2227859215 -0.3264773618 -0.9185744202
+-0.3952480672 -0.0000000000 -0.9185744202
+-0.0000000000 -0.0000000000 -1.0000000000
+ 0.1884917927 0.3568220898 0.9149583817
+-0.4009827382 -0.0454313035 0.9149583817
+ 0.1884917927 -0.2762216876 0.9149583817
+ 0.7299680182 -0.0454313035 0.6819697127
+-0.3769835855 0.5524433752 0.7082839194
+-0.2238218084 -0.6962909658 0.6819697127
+ 0.6262353286 0.5524433752 0.5016094570
+ 0.4751441987 -0.6962909658 0.5379747963
+-0.8612946448 0.2378813932 0.4489810437
+ 0.0924951818 0.8887410555 0.4489810437
+-0.7427296631 -0.3817289838 0.5016094570
+ 0.9686221187 0.2378813932 0.0719974582
+ 0.8805126380 -0.3817289838 0.1672031523
+-0.5563085176 0.8152316624 0.1609912108
+ 0.0344457437 -0.9590792530 0.1672031523
+-0.5746422389 -0.8152316624 0.0719974582
+ 0.5746422389 0.8152316624 -0.0719974582
+ 0.5563085176 -0.8152316624 -0.1609912108
+-0.8805126380 0.3817289838 -0.1672031523
+-0.9686221187 -0.2378813932 -0.0719974582
+-0.0344457437 0.9590792530 -0.1672031523
+ 0.7427296631 0.3817289838 -0.5016094570
+ 0.8612946448 -0.2378813932 -0.4489810437
+-0.4751441987 0.6962909658 -0.5379747963
+-0.0924951818 -0.8887410555 -0.4489810437
+-0.6262353286 -0.5524433752 -0.5016094570
+ 0.2238218084 0.6962909658 -0.6819697127
+ 0.3769835855 -0.5524433752 -0.7082839194
+-0.7299680182 0.0454313035 -0.6819697127
+ 0.4009827382 0.0454313035 -0.9149583817
+-0.1884917927 0.2762216876 -0.9149583817
+-0.1884917927 -0.3568220898 -0.9149583817
+6 0 2 7 11 4 1
+6 0 3 9 14 6 2
+5 0 1 5 8 3
+6 1 4 10 19 12 5
+5 2 6 13 15 7
+6 3 8 16 26 17 9
+5 4 11 20 18 10
+6 5 12 21 25 16 8
+6 6 14 23 33 22 13
+6 7 15 24 30 20 11
+5 9 17 27 23 14
+6 10 18 28 39 29 19
+5 12 19 29 31 21
+6 13 22 32 34 24 15
+5 16 25 35 36 26
+6 17 26 36 46 37 27
+6 18 20 30 40 38 28
+6 21 31 41 45 35 25
+5 22 33 43 42 32
+6 23 27 37 47 43 33
+5 24 34 44 40 30
+5 28 38 48 49 39
+6 29 39 49 50 41 31
+6 32 42 51 52 44 34
+6 35 45 53 54 46 36
+5 37 46 54 55 47
+6 38 40 44 52 56 48
+5 41 50 57 53 45
+6 42 43 47 55 58 51
+6 48 56 59 57 50 49
+5 51 58 59 56 52
+6 53 57 59 58 55 54
+3 2 0 1
+3 2 3 0
+3 0 4 1
+3 1 5 2
+3 3 6 0
+3 2 7 3
+3 4 8 1
+3 0 9 4
+3 5 7 2
+3 1 10 5
+3 3 11 6
+3 6 9 0
+3 7 12 3
+3 4 13 8
+3 8 10 1
+3 9 13 4
+3 5 14 7
+3 10 15 5
+3 11 16 6
+3 12 11 3
+3 16 9 6
+3 7 17 12
+3 13 18 8
+3 8 19 10
+3 9 20 13
+3 14 17 7
+3 15 14 5
+3 19 15 10
+3 11 21 16
+3 12 22 11
+3 16 20 9
+3 17 22 12
+3 13 23 18
+3 18 19 8
+3 20 23 13
+3 14 24 17
+3 15 24 14
+3 19 25 15
+3 21 26 16
+3 22 21 11
+3 26 20 16
+3 17 27 22
+3 23 28 18
+3 28 19 18
+3 26 23 20
+3 24 27 17
+3 25 24 15
+3 28 25 19
+3 21 29 26
+3 22 29 21
+3 27 29 22
+3 23 30 28
+3 26 30 23
+3 24 31 27
+3 25 31 24
+3 28 31 25
+3 29 30 26
+3 31 29 27
+3 30 31 28
+3 29 30 31
+truncated dodecahedron
+triakisicosahedron
+2 3|5
+(10.10.3)
+icosahedral group
+A5
+12{10}+20{3}
+30 60 90 32 60 1 0 0 2 2 3 120 5 0 -1
+ 0.0000000000 0.0000000000 1.0000000000
+ 0.3319544852 0.0000000000 0.9432954043
+-0.2860795036 0.1683814059 0.9432954043
+ 0.1611340919 -0.2902233358 0.9432954043
+ 0.5829886213 0.1683814059 0.7948408455
+-0.5878317720 0.1506049079 0.7948408455
+-0.4170113787 0.4408282437 0.7948408455
+ 0.1357750258 -0.5914331516 0.7948408455
+ 0.8183499926 0.1506049079 0.5546363234
+ 0.6572159007 0.4408282437 0.6113409191
+-0.7899976948 -0.0465394760 0.6113409191
+-0.3427840993 0.7132750815 0.6113409191
+-0.0663908970 -0.7885775354 0.6113409191
+ 0.2655635881 -0.7885775354 0.5546363234
+ 0.9481385550 -0.0465394760 0.3144318014
+ 0.5262840256 0.7132750815 0.4628863603
+-0.8153567609 -0.3477492917 0.4628863603
+-0.9462886360 -0.0753024539 0.3144318014
+-0.3935022315 0.8638799894 0.3144318014
+-0.0917499632 0.8816564874 0.4628863603
+-0.3681431654 -0.8063540334 0.4628863603
+ 0.5009249595 -0.8063540334 0.3144318014
+ 0.9227794888 -0.3477492917 0.1659772426
+ 0.9970067683 -0.0753024539 -0.0175226837
+ 0.4755658933 0.8638799894 0.1659772426
+ 0.2402045220 0.8816564874 0.4061817646
+-0.6542226690 -0.6379726275 0.4061817646
+-0.9970067683 0.0753024539 0.0175226837
+-0.5497931728 0.8351170114 0.0175226837
+-0.5244341067 -0.8351170114 0.1659772426
+ 0.5497931728 -0.8351170114 -0.0175226837
+ 0.7519590956 -0.6379726275 0.1659772426
+ 0.9462886360 0.0753024539 -0.3144318014
+ 0.5244341067 0.8351170114 -0.1659772426
+-0.9481385550 0.0465394760 -0.3144318014
+-0.9227794888 0.3477492917 -0.1659772426
+-0.7519590956 0.6379726275 -0.1659772426
+-0.5009249595 0.8063540334 -0.3144318014
+-0.4755658933 -0.8638799894 -0.1659772426
+ 0.3935022315 -0.8638799894 -0.3144318014
+ 0.7899976948 0.0465394760 -0.6113409191
+ 0.8153567609 0.3477492917 -0.4628863603
+ 0.6542226690 0.6379726275 -0.4061817646
+ 0.3681431654 0.8063540334 -0.4628863603
+-0.8183499926 -0.1506049079 -0.5546363234
+-0.2655635881 0.7885775354 -0.5546363234
+-0.5262840256 -0.7132750815 -0.4628863603
+-0.2402045220 -0.8816564874 -0.4061817646
+ 0.0917499632 -0.8816564874 -0.4628863603
+ 0.3427840993 -0.7132750815 -0.6113409191
+ 0.5878317720 -0.1506049079 -0.7948408455
+ 0.0663908970 0.7885775354 -0.6113409191
+-0.6572159007 -0.4408282437 -0.6113409191
+-0.5829886213 -0.1683814059 -0.7948408455
+-0.1357750258 0.5914331516 -0.7948408455
+ 0.4170113787 -0.4408282437 -0.7948408455
+ 0.2860795036 -0.1683814059 -0.9432954043
+-0.3319544852 0.0000000000 -0.9432954043
+-0.1611340919 0.2902233358 -0.9432954043
+-0.0000000000 -0.0000000000 -1.0000000000
+ 0.1432337790 0.5257311121 0.8385051474
+-0.3901124942 -0.3804226065 0.8385051474
+ 0.1432337790 -0.0843049040 0.8385051474
+ 0.6463368675 -0.3804226065 0.6614584599
+-0.3749909018 0.2207131041 0.7357864254
+ 0.5979747984 0.2207131041 0.5695840419
+-0.7989163046 0.4702282018 0.3749909018
+ 0.0972965700 -0.6299377043 0.5695840419
+ 0.8780939903 0.4702282018 0.0885233438
+-0.7412085774 -0.1364082001 0.4033816583
+-0.2405303491 0.7142426083 0.4033816583
+ 0.0151215924 -0.9959593140 0.0885233438
+ 0.8330829954 -0.1364082001 0.1344605528
+ 0.3607955236 0.7142426083 0.3006629363
+-0.8780939903 -0.4702282018 -0.0885233438
+-0.0151215924 0.9959593140 -0.0885233438
+-0.4493188674 -0.6621393122 0.3006629363
+ 0.5236468329 -0.6621393122 0.1344605528
+ 0.7989163046 -0.4702282018 -0.3749909018
+-0.8330829954 0.1364082001 -0.1344605528
+-0.5236468329 0.6621393122 -0.1344605528
+ 0.7412085774 0.1364082001 -0.4033816583
+ 0.4493188674 0.6621393122 -0.3006629363
+-0.6463368675 0.3804226065 -0.6614584599
+-0.3607955236 -0.7142426083 -0.3006629363
+ 0.2405303491 -0.7142426083 -0.4033816583
+ 0.3901124942 0.3804226065 -0.8385051474
+-0.5979747984 -0.2207131041 -0.5695840419
+-0.0972965700 0.6299377043 -0.5695840419
+-0.1432337790 -0.5257311121 -0.8385051474
+ 0.3749909018 -0.2207131041 -0.7357864254
+-0.1432337790 0.0843049040 -0.8385051474
+10 0 2 6 11 19 25 15 9 4 1
+10 0 3 7 12 20 26 16 10 5 2
+3 0 1 3
+10 1 4 8 14 22 31 21 13 7 3
+3 2 5 6
+3 4 9 8
+10 5 10 17 27 35 36 28 18 11 6
+3 7 13 12
+10 8 9 15 24 33 42 41 32 23 14
+3 10 16 17
+3 11 18 19
+10 12 13 21 30 39 48 47 38 29 20
+3 14 23 22
+3 15 25 24
+10 16 26 29 38 46 52 44 34 27 17
+10 18 28 37 45 51 43 33 24 25 19
+3 20 29 26
+3 21 31 30
+10 22 23 32 40 50 55 49 39 30 31
+3 27 34 35
+3 28 36 37
+3 32 41 40
+3 33 43 42
+10 34 44 53 57 58 54 45 37 36 35
+3 38 47 46
+3 39 49 48
+10 40 41 42 43 51 54 58 59 56 50
+3 44 52 53
+3 45 54 51
+10 46 47 48 49 55 56 59 57 53 52
+3 50 56 55
+3 57 59 58
+3 2 0 1
+3 2 3 0
+3 0 4 1
+3 1 3 2
+3 3 5 0
+3 4 6 1
+3 0 6 4
+3 1 7 3
+3 3 8 5
+3 8 0 5
+3 6 9 1
+3 0 10 6
+3 1 11 7
+3 11 3 7
+3 3 12 8
+3 8 13 0
+3 9 14 1
+3 6 14 9
+3 10 15 6
+3 0 15 10
+3 1 16 11
+3 11 17 3
+3 3 18 12
+3 18 8 12
+3 8 15 13
+3 13 0 15
+3 14 16 1
+3 6 19 14
+3 15 20 6
+3 14 11 16
+3 11 18 17
+3 17 3 18
+3 18 21 8
+3 8 22 15
+3 19 23 14
+3 6 23 19
+3 20 23 6
+3 15 23 20
+3 14 24 11
+3 11 25 18
+3 18 26 21
+3 26 8 21
+3 26 22 8
+3 26 15 22
+3 23 27 14
+3 15 28 23
+3 14 29 24
+3 29 11 24
+3 29 25 11
+3 29 18 25
+3 18 30 26
+3 26 28 15
+3 27 29 14
+3 23 29 27
+3 26 23 28
+3 29 30 18
+3 29 26 30
+3 23 31 29
+3 26 31 23
+3 29 26 31
+rhombicosidodecahedron
+deltoidal hexecontahedron
+3 5|2
+(4.3.4.5)
+icosahedral group
+A5
+12{5}+30{4}+20{3}
+31 60 120 62 60 1 0 0 2 3 4 120 5 0 -1
+ 0.0000000000 0.0000000000 1.0000000000
+ 0.4364663517 0.0000000000 0.8997205810
+-0.0230394894 0.4358578416 0.8997205810
+-0.3947875239 0.1861335198 0.8997205810
+-0.1650346033 -0.4040624406 0.8997205810
+ 0.4134268623 0.4358578416 0.7994411620
+ 0.7478962199 0.1861335198 0.6371856536
+ 0.5411827887 -0.4040624406 0.7374650726
+-0.2253527696 0.7370282030 0.6371856536
+-0.5598221272 -0.2179289208 0.7994411620
+-0.5971008041 0.4873038812 0.6371856536
+ 0.1694347542 -0.6537867624 0.7374650726
+-0.4551056902 -0.6219913614 0.6371856536
+ 0.4808646224 0.7370282030 0.4749301452
+ 0.8526126568 -0.2179289208 0.4749301452
+ 0.8153339799 0.4873038812 0.3126746369
+ 0.6875780535 -0.6219913614 0.3746507262
+ 0.0860770985 0.9231617228 0.3746507262
+-0.5296630440 0.7884742426 0.3126746369
+-0.8641324015 -0.1664828812 0.4749301452
+-0.8871718909 0.2693749604 0.3746507262
+-0.1206363326 -0.8717156832 0.4749301452
+ 0.3158300191 -0.8717156832 0.3746507262
+-0.7594159645 -0.5705453218 0.3126746369
+ 0.6130206997 0.7884742426 0.0501397095
+ 0.9847687342 -0.1664828812 0.0501397095
+ 0.9617292448 0.2693749604 -0.0501397095
+ 0.8197341309 -0.5705453218 -0.0501397095
+-0.2182331759 0.9746077624 0.0501397095
+ 0.2182331759 0.9746077624 -0.0501397095
+-0.8197341309 0.5705453218 0.0501397095
+-0.9617292448 -0.2693749604 0.0501397095
+-0.9847687342 0.1664828812 -0.0501397095
+-0.2182331759 -0.9746077624 0.0501397095
+ 0.2182331759 -0.9746077624 -0.0501397095
+-0.6130206997 -0.7884742426 -0.0501397095
+ 0.7594159645 0.5705453218 -0.3126746369
+ 0.8871718909 -0.2693749604 -0.3746507262
+ 0.8641324015 0.1664828812 -0.4749301452
+ 0.5296630440 -0.7884742426 -0.3126746369
+-0.3158300191 0.8717156832 -0.3746507262
+ 0.1206363326 0.8717156832 -0.4749301452
+-0.6875780535 0.6219913614 -0.3746507262
+-0.8153339799 -0.4873038812 -0.3126746369
+-0.8526126568 0.2179289208 -0.4749301452
+-0.0860770985 -0.9231617228 -0.3746507262
+-0.4808646224 -0.7370282030 -0.4749301452
+ 0.4551056902 0.6219913614 -0.6371856536
+ 0.5971008041 -0.4873038812 -0.6371856536
+ 0.5598221272 0.2179289208 -0.7994411620
+ 0.2253527696 -0.7370282030 -0.6371856536
+-0.1694347542 0.6537867624 -0.7374650726
+-0.5411827887 0.4040624406 -0.7374650726
+-0.7478962199 -0.1861335198 -0.6371856536
+-0.4134268623 -0.4358578416 -0.7994411620
+ 0.1650346033 0.4040624406 -0.8997205810
+ 0.3947875239 -0.1861335198 -0.8997205810
+ 0.0230394894 -0.4358578416 -0.8997205810
+-0.4364663517 -0.0000000000 -0.8997205810
+ 0.0000000000 0.0000000000 -1.0000000000
+ 0.2124281962 0.2239537475 0.9245941063
+-0.1379991118 0.2054301247 0.9245941063
+-0.2876494382 -0.1119768737 0.9245941063
+ 0.2124281962 -0.3162277660 0.9245941063
+ 0.6623583361 -0.1119768737 0.7063270456
+ 0.5277148574 0.2054301247 0.7716443776
+ 0.1583346290 0.7071067812 0.6891517578
+-0.3186422944 0.4743416490 0.7896976442
+-0.7144788670 0.1207882584 0.6891517578
+-0.3897157456 -0.4108602493 0.7716443776
+-0.1467842735 -0.6555240367 0.7063270456
+ 0.6313654799 0.4743416490 0.5714305835
+ 0.9436228948 0.1207882584 0.3081980354
+ 0.4403528206 -0.6555240367 0.5714305835
+ 0.6874320834 -0.4108602493 0.5241665181
+-0.2279246243 0.8794777841 0.3531635228
+-0.4465745066 0.6647858481 0.5241665181
+-0.6778547641 -0.4051361351 0.5714305835
+-0.7280022588 0.5435471629 0.3531635228
+ 0.1204287884 -0.7917486474 0.5241665181
+-0.4686190076 -0.8278950396 0.3081980354
+ 0.6305733224 0.6647858481 0.2766886585
+ 0.3592124698 0.8794777841 0.2182670607
+ 0.8592901042 -0.4051361351 0.2182670607
+ 0.8091426096 0.5435471629 -0.0000000000
+ 0.5561442379 -0.8278950396 0.0727556869
+ 0.0284293805 0.9486832981 0.1237389298
+-0.5561442379 0.8278950396 -0.0727556869
+-0.9500077743 0.0000000000 0.2182670607
+-0.8538605757 -0.3323929240 0.2766886585
+-0.8890012226 0.3323929240 0.1237389298
+ 0.0501474947 -0.9486832981 0.2182670607
+-0.8091426096 -0.5435471629 -0.0000000000
+ 0.4686190076 0.8278950396 -0.3081980354
+ 0.8890012226 -0.3323929240 -0.1237389298
+ 0.9500077743 0.0000000000 -0.2182670607
+ 0.8538605757 0.3323929240 -0.2766886585
+ 0.7280022588 -0.5435471629 -0.3531635228
+-0.0501474947 0.9486832981 -0.2182670607
+-0.8592901042 0.4051361351 -0.2182670607
+-0.9436228948 -0.1207882584 -0.3081980354
+-0.3592124698 -0.8794777841 -0.2182670607
+-0.0284293805 -0.9486832981 -0.1237389298
+ 0.2279246243 -0.8794777841 -0.3531635228
+-0.6305733224 -0.6647858481 -0.2766886585
+ 0.6778547641 0.4051361351 -0.5714305835
+ 0.7144788670 -0.1207882584 -0.6891517578
+ 0.4465745066 -0.6647858481 -0.5241665181
+-0.1204287884 0.7917486474 -0.5241665181
+-0.4403528206 0.6555240367 -0.5714305835
+ 0.1467842735 0.6555240367 -0.7063270456
+-0.6874320834 0.4108602493 -0.5241665181
+-0.6313654799 -0.4743416490 -0.5714305835
+-0.6623583361 0.1119768737 -0.7063270456
+-0.1583346290 -0.7071067812 -0.6891517578
+ 0.3897157456 0.4108602493 -0.7716443776
+ 0.3186422944 -0.4743416490 -0.7896976442
+ 0.2876494382 0.1119768737 -0.9245941063
+-0.2124281962 0.3162277660 -0.9245941063
+-0.5277148574 -0.2054301247 -0.7716443776
+-0.2124281962 -0.2239537475 -0.9245941063
+ 0.1379991118 -0.2054301247 -0.9245941063
+4 0 2 5 1
+3 0 3 2
+4 0 4 9 3
+5 0 1 7 11 4
+4 1 6 14 7
+3 1 5 6
+5 2 8 17 13 5
+4 2 3 10 8
+5 3 9 19 20 10
+3 4 12 9
+4 4 11 21 12
+4 5 13 15 6
+5 6 15 26 25 14
+4 7 16 22 11
+3 7 14 16
+4 8 18 28 17
+3 8 10 18
+4 9 12 23 19
+4 10 20 30 18
+3 11 22 21
+5 12 21 33 35 23
+3 13 24 15
+4 13 17 29 24
+4 14 25 27 16
+4 15 24 36 26
+5 16 27 39 34 22
+3 17 28 29
+5 18 30 42 40 28
+4 19 31 32 20
+3 19 23 31
+3 20 32 30
+4 21 22 34 33
+4 23 35 43 31
+5 24 29 41 47 36
+3 25 37 27
+4 25 26 38 37
+3 26 36 38
+4 27 37 48 39
+4 28 40 41 29
+4 30 32 44 42
+5 31 43 53 44 32
+4 33 45 46 35
+3 33 34 45
+4 34 39 50 45
+3 35 46 43
+4 36 47 49 38
+5 37 38 49 56 48
+3 39 48 50
+3 40 51 41
+4 40 42 52 51
+4 41 51 55 47
+3 42 44 52
+4 43 46 54 53
+4 44 53 58 52
+5 45 50 57 54 46
+3 47 55 49
+4 48 56 57 50
+4 49 55 59 56
+5 51 52 58 59 55
+3 53 54 58
+4 54 57 59 58
+3 56 59 57
+4 3 0 1 2
+4 3 4 5 0
+4 0 6 7 1
+4 7 8 2 1
+4 2 9 10 3
+4 5 11 6 0
+4 4 12 11 5
+4 3 13 14 4
+4 6 15 16 7
+4 8 17 9 2
+4 16 18 8 7
+4 10 19 13 3
+4 17 20 10 9
+4 11 21 22 6
+4 14 23 12 4
+4 12 24 21 11
+4 13 25 23 14
+4 22 26 15 6
+4 15 27 18 16
+4 8 28 29 17
+4 18 30 28 8
+4 20 31 19 10
+4 31 25 13 19
+4 29 32 20 17
+4 24 33 22 21
+4 23 34 35 12
+4 35 36 24 12
+4 25 37 34 23
+4 26 38 27 15
+4 33 38 26 22
+4 27 39 30 18
+4 28 40 32 29
+4 39 40 28 30
+4 20 41 42 31
+4 42 43 25 31
+4 32 44 41 20
+4 36 45 33 24
+4 37 46 35 34
+4 46 45 36 35
+4 43 47 37 25
+4 38 48 49 27
+4 33 50 48 38
+4 49 51 39 27
+4 40 52 44 32
+4 51 53 40 39
+4 41 54 43 42
+4 52 54 41 44
+4 45 55 50 33
+4 47 56 46 37
+4 46 57 55 45
+4 54 56 47 43
+4 50 58 49 48
+4 58 53 51 49
+4 53 59 52 40
+4 59 60 54 52
+4 57 58 50 55
+4 56 61 57 46
+4 60 61 56 54
+4 58 60 59 53
+4 57 58 60 61
+truncated icosidodecahedron
+disdyakistriacontahedron
+2 3 5|
+(4.6.10)
+icosahedral group
+A5
+12{10}+20{6}+30{4}
+32 120 180 62 120 1 0 0 2 3 3 120 5 0 -1
+ 0.0000000000 0.0000000000 1.0000000000
+ 0.2607080006 0.0000000000 0.9654177015
+-0.0045873783 0.2606676380 0.9654177015
+-0.2192156342 -0.1411140222 0.9654177015
+ 0.2561208549 0.2606676380 0.9308353722
+ 0.4633267724 -0.1411140222 0.8748800687
+-0.2283903908 0.3802212538 0.8962531046
+-0.3132059807 -0.3694413065 0.8748800687
+-0.4430186467 -0.0215604065 0.8962531046
+ 0.4541524811 0.3802212538 0.8057154101
+ 0.5304628314 -0.3694413065 0.7629694001
+ 0.6613583986 -0.0215604065 0.7497601066
+-0.3298032754 0.5736633003 0.7497601066
+-0.4476060250 0.2391072316 0.8616708061
+-0.5370090771 -0.2498878945 0.8057153910
+-0.2460699217 -0.5977685908 0.7629694001
+ 0.5138663784 0.5736633003 0.6378493263
+ 0.6567712529 0.2391072316 0.7151777773
+ 0.7284945175 -0.2498878945 0.6378493381
+ 0.4364724850 -0.5977685908 0.6724317673
+-0.5490190001 0.4325494506 0.7151776775
+-0.2700897570 0.7671054904 0.5818940537
+-0.6936761144 -0.3586617667 0.6246400447
+-0.0434511498 -0.7388826131 0.6724317673
+-0.4027369590 -0.7065424630 0.5818940537
+ 0.7164852035 0.4325494506 0.5473115438
+ 0.4124538677 0.7671054904 0.4913562594
+ 0.8325358571 -0.3586617667 0.4221916434
+ 0.2172568508 -0.7388826131 0.6378494688
+ 0.5405138246 -0.7065424630 0.4567740725
+-0.7085212064 0.4848777911 0.5127291954
+-0.0720583700 0.8866594825 0.4567740725
+-0.4295919633 0.8194338309 0.3794455716
+-0.8531785590 -0.3063341981 0.4221915508
+-0.6265400554 -0.5869890510 0.5127293760
+-0.2001180064 -0.8476566112 0.4913563402
+ 0.8176915179 0.4848777911 0.3102806942
+ 0.1886510811 0.8866594825 0.4221915817
+ 0.5136601821 0.8194338309 0.2543254098
+ 0.9337423985 -0.3063341981 0.1851607203
+ 0.7385455107 -0.5869890510 0.3316540106
+ 0.3212979948 -0.8476566112 0.4221917432
+-0.8651885085 0.3761046523 0.3316536375
+-0.6488076880 0.6783199813 0.3448631425
+-0.2315603996 0.9389879297 0.2543254788
+-0.7860426423 -0.5346614357 0.3102807015
+-0.9545918983 -0.1128925413 0.2756983531
+-0.0960768624 -0.9564306093 0.2756986145
+ 0.9217330580 0.3761046523 0.0946227263
+ 0.7162790072 0.6783199813 0.1637876273
+ 0.2898571959 0.9389879297 0.1851606704
+ 0.8397521423 -0.5346614357 0.0946228761
+ 0.9934566827 -0.1128925413 0.0172943252
+ 0.1646311382 -0.9564306093 0.2411163161
+-0.8054751299 0.5695467454 0.1637874231
+-0.9591793219 0.1477776761 0.2411157125
+-0.1303544328 0.9913166095 0.0172945558
+-0.8203200648 -0.5695470165 0.0518766546
+-0.9888693637 -0.1477781439 0.0172916663
+-0.1303536668 -0.9913167102 0.0172945558
+ 0.8203206401 0.5695467454 -0.0518705331
+ 0.9888694917 0.1477776761 -0.0172883463
+ 0.1303553059 0.9913166095 -0.0172879732
+ 0.8054761704 -0.5695470165 -0.1637813633
+ 0.9591800640 -0.1477781439 -0.2411124739
+ 0.1303545664 -0.9913167102 -0.0172877735
+-0.8397525647 0.5346618623 -0.0946167165
+-0.9934567883 0.1128921245 -0.0172909812
+-0.1646312678 0.9564322465 -0.2411097335
+-0.7162795951 -0.6783208443 -0.1637814823
+-0.9217334041 -0.3761053597 -0.0946165431
+-0.2898558028 -0.9389895580 -0.1851545936
+ 0.7860446559 0.5346618623 -0.3102748651
+ 0.9545928720 0.1128921245 -0.2756951522
+ 0.0960787036 0.9564322465 -0.2756922934
+ 0.6488098576 -0.6783208443 -0.3448573632
+ 0.8651904546 -0.3761053597 -0.3316477584
+ 0.2315606390 -0.9389895580 -0.2543192490
+-0.7385472639 0.5869902473 -0.3316479890
+-0.9337433781 0.3063348862 -0.1851546415
+-0.3212992842 0.8476584134 -0.4221871436
+-0.8176928415 -0.4848792845 -0.3102748723
+-0.5136611563 -0.8194350139 -0.2543196306
+-0.1886494644 -0.8866613987 -0.4221882798
+ 0.6265433179 0.5869902473 -0.5127240198
+ 0.8531810896 0.3063348862 -0.4221859376
+ 0.2001204504 0.8476584134 -0.4913522358
+ 0.7085240020 -0.4848792845 -0.5127239199
+ 0.4295944104 -0.8194350139 -0.3794402462
+ 0.0720576700 -0.8866613987 -0.4567704634
+-0.8325379870 0.3586633178 -0.4221861255
+-0.5405162125 0.7065442357 -0.4567685048
+-0.2172590958 0.7388844270 -0.6378466030
+-0.7164876491 -0.4325518944 -0.5473064108
+-0.4124548660 -0.7671068289 -0.4913533317
+ 0.6936796092 0.3586633178 -0.6246352729
+ 0.4027407159 0.7065442357 -0.5818893011
+ 0.0434540643 0.7388844270 -0.6724295858
+ 0.5490226993 -0.4325518944 -0.7151733596
+ 0.2700914841 -0.7671068289 -0.5818914876
+-0.7284976588 0.2498903768 -0.6378447779
+-0.4364761587 0.5977701626 -0.6724279854
+-0.6567747682 -0.2391103983 -0.7151734903
+-0.5138692103 -0.5736660641 -0.6378445591
+ 0.5370132986 0.2498903768 -0.8057118075
+ 0.2460744543 0.5977701626 -0.7629667067
+ 0.4476105365 -0.2391103983 -0.8616675838
+ 0.3298072522 -0.5736660641 -0.7497562426
+-0.6613622562 0.0215634725 -0.7497566156
+-0.5304666075 0.3694443652 -0.7629652937
+-0.4541562762 -0.3802243954 -0.8057117884
+ 0.4430232811 0.0215634725 -0.8962507401
+ 0.3132106967 0.3694443652 -0.8748770888
+ 0.2283949989 -0.3802243954 -0.8962505976
+-0.4633311450 0.1411172572 -0.8748772313
+-0.2561255056 -0.2606708670 -0.9308331883
+ 0.2192205953 0.1411172572 -0.9654161022
+ 0.0045924376 -0.2606708670 -0.9654168056
+-0.2607129987 0.0000032913 -0.9654163518
+ 0.0000051771 0.0000032912 -0.9999999999
+ 0.1200387571 0.1221698550 0.9049446030
+-0.2175780247 0.1162282816 0.9049446030
+ 0.1200387571 -0.4082474279 0.9049446030
+ 0.4459799746 0.1162282816 0.8169252068
+ 0.1016985225 0.6339220449 0.7666817889
+-0.3544276914 -0.1832548434 0.8300952867
+ 0.5585832497 -0.1832548434 0.7089865490
+-0.3643565320 0.3809295903 0.7552459704
+-0.4568036952 -0.4649138222 0.6745068322
+-0.7747432361 0.0697368203 0.6284189748
+ 0.5486549126 0.3809295903 0.6341371659
+ 0.6168557011 -0.4649138222 0.5320884576
+ 0.9117846887 0.0697368203 0.4047050422
+-0.4756956529 0.6085799433 0.5320883790
+-0.2091195905 -0.6774423865 0.5878778112
+ 0.5979647013 0.6085799433 0.3896698773
+ 0.3551522032 -0.6774423865 0.5130284950
+-0.2351136470 0.7996124516 0.3919196492
+-0.6935150612 -0.4186830921 0.4381790039
+ 0.0589047087 -0.8240793946 0.4440690614
+-0.5063278658 -0.8431340489 0.1809911096
+ 0.3291594648 0.7996124516 0.3170701581
+ 0.7837684883 -0.4186830921 0.2422208418
+ 0.5360037147 -0.8431340489 0.0427282955
+-0.7095802914 0.4941881267 0.3170700500
+ 0.0283375922 0.9128709077 0.2136305953
+-0.5360037809 0.8431342740 -0.0427230226
+-0.8627717620 -0.3317288924 0.1592318224
+ 0.7677040727 0.4941881267 0.1211117799
+ 0.5063293044 0.8431342740 -0.1809860363
+ 0.8744481415 -0.3317288924 -0.0712062810
+-0.8744476717 0.3317288831 0.0712120936
+-0.9130127824 -0.0000002089 0.1211105323
+ 0.0160652247 -0.9128709077 0.1211120373
+ 0.8627728239 0.3317288831 -0.1592260883
+ 0.9130131866 -0.0000002089 -0.1211074853
+-0.0160644264 0.9128718312 -0.1211060185
+-0.7677045094 -0.4941888273 -0.1211061534
+-0.9117856757 -0.0697383469 -0.4047106460
+-0.0283368549 -0.9128720729 -0.2136250368
+ 0.7095821798 -0.4941888273 -0.3170647319
+ 0.7747427279 -0.0697383469 -0.6284246421
+-0.7837697662 0.4186839017 -0.2422153076
+-0.0589041897 0.8240821079 -0.4440651491
+-0.5979663637 -0.6085817063 -0.3896645730
+-0.3291594183 -0.7996144008 -0.3170661961
+ 0.6935177376 0.4186839017 -0.4381739942
+ 0.4756986407 -0.6085817063 -0.5320836915
+ 0.2351146351 -0.7996144008 -0.3919158121
+-0.6168583888 0.4649158905 -0.5320835344
+-0.3551545140 0.6774441676 -0.5130247732
+-0.1016986410 -0.6339226751 -0.7666826828
+ 0.4568075735 0.4649158905 -0.6745027800
+ 0.2091227917 0.6774441676 -0.5878748207
+-0.1200394924 0.4082445693 -0.9049501465
+-0.5486577777 -0.3809323480 -0.6341330304
+ 0.3643603762 -0.3809323480 -0.7552427249
+-0.5585867166 0.1832576685 -0.7089830873
+-0.4459830958 -0.1162285368 -0.8169244453
+ 0.3544319409 0.1832576685 -0.8300928486
+ 0.2175812365 -0.1162285368 -0.9049446815
+-0.1200388929 -0.1221699932 -0.9049456265
+4 0 2 4 1
+6 0 3 8 13 6 2
+10 0 1 5 10 19 28 23 15 7 3
+6 1 4 9 17 11 5
+10 2 6 12 21 31 37 26 16 9 4
+4 3 7 14 8
+4 5 11 18 10
+4 6 13 20 12
+6 7 15 24 34 22 14
+10 8 14 22 33 46 55 42 30 20 13
+4 9 16 25 17
+6 10 18 27 40 29 19
+10 11 17 25 36 48 61 52 39 27 18
+6 12 20 30 43 32 21
+4 15 23 35 24
+6 16 26 38 49 36 25
+4 19 29 41 28
+4 21 32 44 31
+4 22 34 45 33
+6 23 28 41 53 47 35
+10 24 35 47 59 71 82 69 57 45 34
+4 26 37 50 38
+4 27 39 51 40
+10 29 40 51 63 75 88 77 65 53 41
+4 30 42 54 43
+6 31 44 56 62 50 37
+10 32 43 54 66 78 91 80 68 56 44
+6 33 45 57 70 58 46
+4 36 49 60 48
+10 38 50 62 74 86 96 84 72 60 49
+6 39 52 64 76 63 51
+6 42 55 67 79 66 54
+4 46 58 67 55
+4 47 53 65 59
+6 48 60 72 85 73 61
+4 52 61 73 64
+4 56 68 74 62
+4 57 69 81 70
+10 58 70 81 93 102 108 100 90 79 67
+6 59 65 77 89 83 71
+4 63 76 87 75
+10 64 73 85 95 104 111 106 98 87 76
+4 66 79 90 78
+6 68 80 92 97 86 74
+6 69 82 94 103 93 81
+4 71 83 94 82
+4 72 84 95 85
+6 75 87 98 107 99 88
+4 77 88 99 89
+6 78 90 100 109 101 91
+4 80 91 101 92
+10 83 89 99 107 113 117 115 110 103 94
+6 84 96 105 112 104 95
+4 86 97 105 96
+10 92 101 109 114 118 119 116 112 105 97
+4 93 103 110 102
+4 98 106 113 107
+4 100 108 114 109
+6 102 110 115 118 114 108
+4 104 112 116 111
+6 106 111 116 119 117 113
+4 115 117 119 118
+3 2 0 1
+3 2 3 0
+3 0 4 1
+3 1 5 2
+3 3 4 0
+3 2 6 3
+3 4 7 1
+3 5 8 2
+3 1 9 5
+3 3 10 4
+3 2 11 6
+3 6 12 3
+3 4 13 7
+3 7 9 1
+3 9 8 5
+3 8 14 2
+3 10 15 4
+3 12 10 3
+3 11 12 6
+3 2 16 11
+3 13 9 7
+3 4 17 13
+3 9 18 8
+3 14 19 2
+3 8 20 14
+3 12 15 10
+3 15 21 4
+3 11 22 12
+3 19 16 2
+3 16 23 11
+3 13 24 9
+3 4 25 17
+3 17 26 13
+3 9 27 18
+3 18 20 8
+3 20 19 14
+3 12 28 15
+3 21 25 4
+3 15 29 21
+3 22 30 12
+3 23 22 11
+3 19 23 16
+3 24 31 9
+3 26 24 13
+3 25 26 17
+3 27 20 18
+3 9 32 27
+3 20 33 19
+3 12 34 28
+3 28 29 15
+3 29 25 21
+3 23 30 22
+3 30 35 12
+3 33 23 19
+3 26 31 24
+3 31 32 9
+3 25 36 26
+3 27 37 20
+3 32 38 27
+3 20 39 33
+3 34 29 28
+3 35 34 12
+3 29 36 25
+3 23 40 30
+3 30 41 35
+3 39 23 33
+3 26 42 31
+3 31 38 32
+3 36 43 26
+3 37 44 20
+3 38 37 27
+3 20 45 39
+3 34 46 29
+3 41 34 35
+3 29 43 36
+3 23 47 40
+3 40 41 30
+3 39 48 23
+3 26 49 42
+3 42 38 31
+3 43 50 26
+3 38 44 37
+3 44 45 20
+3 45 51 39
+3 46 52 29
+3 41 46 34
+3 29 53 43
+3 47 41 40
+3 48 47 23
+3 51 48 39
+3 49 38 42
+3 50 49 26
+3 43 54 50
+3 38 55 44
+3 44 51 45
+3 41 52 46
+3 52 53 29
+3 53 54 43
+3 47 56 41
+3 51 47 48
+3 49 57 38
+3 54 49 50
+3 38 58 55
+3 55 51 44
+3 41 59 52
+3 52 54 53
+3 56 60 41
+3 51 56 47
+3 57 58 38
+3 54 57 49
+3 58 51 55
+3 60 59 41
+3 59 54 52
+3 51 60 56
+3 54 58 57
+3 58 61 51
+3 60 54 59
+3 61 60 51
+3 54 61 58
+3 60 54 61
+snub dodecahedron
+pentagonal hexecontahedron
+|2 3 5
+(3.3.3.3.5)
+icosahedral group
+A5
+12{5}+80{3}
+33 60 150 92 60 1 0 0 2 2 5 120 5 0 -1
+ 0.0000000000 0.0000000000 1.0000000000
+ 0.4512088258 0.0000000000 0.8924183971
+ 0.2127790861 0.3978875029 0.8924183971
+-0.2505259628 0.3752680994 0.8924183971
+-0.4490629634 -0.0439529224 0.8924183971
+-0.1730083366 -0.4167223535 0.8924183971
+ 0.5570628795 -0.4167223535 0.7183477071
+ 0.8034191070 -0.0439529224 0.5937894232
+ 0.6262410352 0.3752680994 0.6833710701
+ 0.3401140582 0.7292026799 0.5937894232
+-0.4095292581 0.6926037162 0.5937894232
+-0.6598181766 0.3124803264 0.6833710701
+-0.5867073299 -0.4344864666 0.6833710701
+-0.2674638242 -0.7588657481 0.5937894232
+ 0.1712754568 -0.6742709318 0.7183477071
+ 0.5066126656 -0.7588657481 0.4092265672
+ 0.8319314730 -0.4344864666 0.3451253896
+ 0.9853200794 -0.0345183587 0.1671909808
+ 0.6986399371 0.6437955034 0.3121371303
+ 0.3534611035 0.9196768661 0.1710546996
+-0.0444936500 0.9113473168 0.4092265672
+-0.4413672010 0.8808718883 0.1710546996
+-0.7580304168 0.5726781810 0.3121371303
+-0.9277164283 0.1422346447 0.3451253896
+-0.8825314401 -0.3194162218 0.3451253896
+-0.6326042630 -0.7087892905 0.3121371303
+ 0.0822881568 -0.9349423109 0.3451253896
+ 0.3841470954 -0.9232462719 -0.0068797092
+ 0.9105239830 -0.3983895691 -0.1105975932
+ 0.9561362417 0.0261888093 -0.2917492648
+ 0.9205629910 0.3905335442 -0.0068797092
+ 0.6521763631 0.7453882542 -0.1380664403
+-0.0487110154 0.9977300839 -0.0464964156
+-0.4177242369 0.8604584989 -0.2917492648
+-0.9300960831 0.3617906055 -0.0634730968
+-0.9941677927 -0.0973061317 -0.0464964156
+-0.8422948163 -0.5352668572 -0.0634730968
+-0.5085214838 -0.8539169004 -0.1105975932
+-0.0666936701 -0.9936871537 -0.0902097278
+ 0.2171184410 -0.8730158634 -0.4366954143
+ 0.6337780180 -0.7004597412 -0.3281487085
+ 0.7752228621 -0.3165232566 -0.5466649267
+ 0.7846911652 0.4275505711 -0.4488432737
+ 0.4346204276 0.7157251860 -0.5466649267
+ 0.0014482055 0.8716810135 -0.4900715391
+-0.3439002478 0.6359394784 -0.6908788601
+-0.7197752973 0.5396486232 -0.4366954143
+-0.8871554693 0.1072142198 -0.4488432737
+-0.6414198315 -0.6014211198 -0.4763121208
+-0.2422737833 -0.8373370292 -0.4900715391
+ 0.4183769714 -0.5607792259 -0.7144839884
+ 0.4919671680 -0.1269691999 -0.8613054788
+ 0.4978189011 0.3328937158 -0.8008483725
+ 0.0947401619 0.5614556665 -0.8220655912
+-0.5854826930 0.2482988995 -0.7717238319
+-0.6691452398 -0.2043459771 -0.7144839884
+-0.3249352618 -0.5030496595 -0.8008483725
+ 0.0833693593 -0.3321275372 -0.9395428936
+ 0.1242523988 0.1277815601 -0.9839884218
+-0.2961484454 -0.0657599657 -0.9528755035
+ 0.2190839064 0.1312836377 0.9188614921
+-0.0124546442 0.2551039658 0.9188614921
+-0.2308305197 0.1093179889 0.9188614921
+-0.2052534511 -0.1520005669 0.9188614921
+ 0.2190839064 -0.3281703830 0.9188614921
+ 0.5977703708 -0.1520005669 0.7273967313
+ 0.6205958173 0.1093179889 0.7158561322
+ 0.4257131685 0.2551039658 0.8143892546
+ 0.3890572668 0.4957055924 0.7158561322
+-0.0330094857 0.6761213397 0.7360504792
+-0.4354944038 0.4554494653 0.7158561322
+-0.4485386151 0.2124213879 0.8143892546
+-0.7630826557 -0.0746882186 0.6419708175
+-0.3988385021 -0.2953600929 0.8143892546
+-0.3389195666 -0.5312467586 0.7158561322
+-0.0888218963 -0.6103640383 0.7273967313
+ 0.4074741194 -0.6103640383 0.6090650015
+ 0.6254586613 -0.5312467586 0.4859196824
+ 0.7233904360 -0.2953600929 0.5468165011
+ 0.8646946053 -0.1692512546 0.3649614304
+ 0.8780829721 0.2897337362 0.3808210291
+ 0.5493678557 0.5768433427 0.5243913714
+ 0.4593636674 0.7564719129 0.3553517403
+ 0.2141655150 0.8447510749 0.3873865601
+-0.2954354429 0.8198714201 0.3873865601
+-0.5308680756 0.7081269803 0.3553517403
+-0.6029463352 0.5205852472 0.5243913714
+-0.7739230465 0.3389900646 0.4423442636
+-0.6935065744 -0.4826176302 0.4423442636
+-0.4905640004 -0.6276147261 0.5243913714
+-0.3032002312 -0.9251016481 0.2285969389
+-0.0045863974 -0.7813515677 0.5468165011
+ 0.2508214168 -0.7813515677 0.4859196824
+ 0.3210587649 -0.8635013917 0.2466297006
+ 0.7110959079 -0.6998764938 0.0671974935
+ 0.9000340357 -0.2861982107 0.1325477729
+ 0.9410156039 -0.1341976438 -0.0775900694
+ 0.9443279912 0.1261088383 -0.0433681826
+ 0.7494453424 0.5872206583 0.0551649398
+ 0.5623291395 0.7618123698 0.1138746914
+ 0.3032002312 0.9251016481 -0.2285969389
+ 0.0858720409 0.9333521346 0.1761231918
+-0.1763828687 0.9205483682 0.1761231918
+-0.2995309163 0.9037575188 -0.0551649398
+-0.7110959079 0.6998764938 -0.0671974935
+-0.8631016874 0.3552600725 0.1959217993
+-0.9410156039 0.1341976438 0.0775900694
+-0.9253215715 -0.0905676721 0.2124078137
+-0.8971365698 -0.3141104098 0.0775900694
+-0.7778380870 -0.5158702863 0.1959217993
+-0.6544328852 -0.6922296665 0.0455552496
+ 0.1318953941 -0.9409811017 0.0818398716
+ 0.1763828687 -0.9205483682 -0.1761231918
+ 0.4075046572 -0.8237974999 -0.2546315508
+ 0.7653310532 -0.4670045122 -0.3251380596
+ 0.8716936806 -0.2272456248 -0.3131280032
+ 0.7630826557 0.0746882186 -0.6419708175
+ 0.8781301501 0.2785692436 -0.2466297006
+ 0.7778380870 0.5158702863 -0.1959217993
+ 0.6175005369 0.6231678047 -0.3740248218
+-0.1534232428 0.9007249745 -0.2733046324
+-0.2508214168 0.7813515677 -0.4859196824
+-0.4887903007 0.6717969331 -0.4683081420
+-0.8370961923 0.3328068685 -0.3131280032
+-0.9276324486 0.1226425968 -0.1843812002
+-0.8780829721 -0.2897337362 -0.3808210291
+-0.6573415966 -0.6568033615 -0.2145948808
+-0.4593636674 -0.7564719129 -0.3553517403
+-0.2697318228 -0.8859007376 -0.2279566191
+-0.0303057331 -0.8922024719 -0.3355531328
+ 0.0330094857 -0.6761213397 -0.7360504792
+ 0.4187988612 -0.7042009004 -0.4881067495
+ 0.6029463352 -0.5205852472 -0.5243913714
+ 0.5561556114 -0.3313610975 -0.7003073269
+ 0.5665700378 0.4870645516 -0.5927108132
+ 0.3389195666 0.5312467586 -0.7158561322
+ 0.1751412372 0.7090205159 -0.6133148036
+-0.0817329434 0.6826950901 -0.6608984288
+-0.2190839064 0.3281703830 -0.9188614921
+-0.5441424799 0.4698138638 -0.6266765419
+-0.7233904360 0.2953600929 -0.5468165011
+-0.7066849651 0.0498778478 -0.6384732991
+-0.5396360317 -0.4318462468 -0.6571463807
+-0.3987890908 -0.6407026882 -0.5831011230
+ 0.3278774074 -0.3365097556 -0.8299380599
+ 0.2308305197 -0.1093179889 -0.9188614921
+ 0.3675788294 0.1101068700 -0.8730990062
+ 0.2365131238 0.3372537898 -0.8601517406
+-0.5116812230 -0.0071952699 -0.8047795644
+-0.4257131685 -0.2551039658 -0.8143892546
+-0.1774197357 -0.2972657023 -0.8886478115
+-0.0292095264 -0.0891219012 -0.9490751728
+3 0 2 1
+3 0 3 2
+3 0 4 3
+3 0 5 4
+5 0 1 6 14 5
+3 1 7 6
+3 1 8 7
+3 1 2 8
+3 2 9 8
+5 2 3 10 20 9
+3 3 11 10
+3 3 4 11
+5 4 12 24 23 11
+3 4 5 12
+3 5 13 12
+3 5 14 13
+3 6 15 14
+3 6 16 15
+3 6 7 16
+3 7 17 16
+5 7 8 18 30 17
+3 8 9 18
+3 9 19 18
+3 9 20 19
+3 10 21 20
+3 10 22 21
+3 10 11 22
+3 11 23 22
+3 12 25 24
+3 12 13 25
+5 13 26 38 37 25
+3 13 14 26
+3 14 15 26
+3 15 27 26
+5 15 16 28 40 27
+3 16 17 28
+3 17 29 28
+3 17 30 29
+3 18 31 30
+3 18 19 31
+5 19 32 44 43 31
+3 19 20 32
+3 20 21 32
+3 21 33 32
+5 21 22 34 46 33
+3 22 23 34
+3 23 35 34
+3 23 24 35
+3 24 36 35
+3 24 25 36
+3 25 37 36
+3 26 27 38
+3 27 39 38
+3 27 40 39
+3 28 41 40
+3 28 29 41
+5 29 42 52 51 41
+3 29 30 42
+3 30 31 42
+3 31 43 42
+3 32 33 44
+3 33 45 44
+3 33 46 45
+3 34 47 46
+3 34 35 47
+5 35 36 48 55 47
+3 36 37 48
+3 37 49 48
+3 37 38 49
+3 38 39 49
+5 39 50 57 56 49
+3 39 40 50
+3 40 41 50
+3 41 51 50
+3 42 43 52
+3 43 53 52
+3 43 44 53
+3 44 45 53
+5 45 54 59 58 53
+3 45 46 54
+3 46 47 54
+3 47 55 54
+3 48 56 55
+3 48 49 56
+3 50 51 57
+3 51 58 57
+3 51 52 58
+3 52 53 58
+3 54 55 59
+3 55 56 59
+3 56 57 59
+3 57 58 59
+5 4 0 1 2 3
+5 4 5 6 7 0
+5 7 8 9 1 0
+5 9 10 11 2 1
+5 11 12 13 3 2
+5 13 14 15 4 3
+5 4 16 17 18 5
+5 18 19 20 6 5
+5 20 21 8 7 6
+5 21 22 23 9 8
+5 9 24 25 26 10
+5 26 27 12 11 10
+5 12 28 29 14 13
+5 29 30 31 15 14
+5 31 32 16 4 15
+5 32 33 34 17 16
+5 34 35 19 18 17
+5 35 36 37 20 19
+5 20 38 39 22 21
+5 39 40 41 23 22
+5 41 42 24 9 23
+5 42 43 44 25 24
+5 44 45 27 26 25
+5 45 46 47 12 27
+5 47 48 49 28 12
+5 49 50 30 29 28
+5 30 51 33 32 31
+5 51 52 53 34 33
+5 34 54 55 36 35
+5 55 56 57 37 36
+5 57 58 38 20 37
+5 58 59 40 39 38
+5 40 60 43 42 41
+5 60 61 62 44 43
+5 44 63 64 46 45
+5 64 65 48 47 46
+5 65 66 50 49 48
+5 66 67 68 30 50
+5 68 69 52 51 30
+5 69 70 71 53 52
+5 71 72 54 34 53
+5 72 73 56 55 54
+5 56 74 59 58 57
+5 74 75 76 40 59
+5 76 77 61 60 40
+5 77 78 79 62 61
+5 79 80 63 44 62
+5 80 81 65 64 63
+5 65 82 83 67 66
+5 83 70 69 68 67
+5 70 84 73 72 71
+5 84 85 86 56 73
+5 86 87 75 74 56
+5 87 78 77 76 75
+5 78 88 81 80 79
+5 88 89 82 65 81
+5 89 90 70 83 82
+5 90 91 85 84 70
+5 91 78 87 86 85
+5 78 88 89 90 91
--- /dev/null
+++ b/lib/polyhedra.all
@@ -1,0 +1,13258 @@
+pentagonal prism
+pentagonal dipyramid
+2 5|2
+(4.4.5)
+dihedral group
+D
+2{5}+5{4}
+0 10 15 7 10 1 0 0 2 2 3 20 2 0 -1
+ 0.0000000000 0.0000000000 1.0000000000
+ 0.8737108351 0.0000000000 0.4864456563
+-0.3018596695 0.8199093629 0.4864456563
+-0.6651309335 -0.5665434359 0.4864456563
+ 0.5718511657 0.8199093629 -0.0271086873
+ 0.7485628941 -0.5665434359 -0.3445027268
+-0.9669906029 0.2533659270 -0.0271086873
+-0.2024936222 -0.9166865354 -0.3445027268
+ 0.4467032247 0.2533659270 -0.8580570704
+-0.5043532916 -0.0967771725 -0.8580570704
+ 0.2978495106 0.4270509831 0.5067318540
+-0.5036584607 0.1319660113 0.5067318540
+ 0.2978495106 -0.8090169944 0.5067318540
+ 0.6877395818 0.1319660113 -0.1935543450
+-0.2978495106 0.8090169944 -0.5067318540
+-0.6091275581 -0.3454915028 -0.1935543450
+ 0.1271969263 -0.3454915028 -0.6263550179
+4 0 2 4 1
+4 0 3 6 2
+5 0 1 5 7 3
+4 1 4 8 5
+5 2 6 9 8 4
+4 3 7 9 6
+4 5 8 9 7
+3 2 0 1
+3 2 3 0
+3 0 4 1
+3 1 5 2
+3 3 4 0
+3 2 6 3
+3 4 5 1
+3 5 6 2
+3 6 4 3
+3 4 5 6
+pentagonal antiprism
+pentagonal deltohedron
+|2 2 5
+(3.3.3.5)
+dihedral group
+D
+2{5}+10{3}
+1 10 20 12 10 1 0 0 2 2 4 20 2 0 -1
+ 0.0000000000 0.0000000000 1.0000000000
+ 0.8944271910 0.0000000000 0.4472135955
+ 0.2763932023 0.8506508084 0.4472135955
+-0.7236067977 0.5257311121 0.4472135955
+-0.7236067977 -0.5257311121 0.4472135955
+ 0.7236067977 -0.5257311121 -0.4472135955
+ 0.7236067977 0.5257311121 -0.4472135955
+-0.8944271910 -0.0000000000 -0.4472135955
+-0.2763932023 -0.8506508084 -0.4472135955
+-0.0000000000 -0.0000000000 -1.0000000000
+ 0.2763932023 0.2008114159 0.4472135955
+-0.1055728090 0.3249196962 0.4472135955
+-0.3416407865 -0.0000000000 0.4472135955
+ 0.2763932023 -0.8506508084 0.4472135955
+ 0.5527864045 0.0000000000 -0.1055728090
+ 0.4472135955 0.3249196962 0.1055728090
+-0.2763932023 0.8506508084 -0.4472135955
+-0.5527864045 -0.0000000000 0.1055728090
+-0.4472135955 -0.3249196962 -0.1055728090
+ 0.1055728090 -0.3249196962 -0.4472135955
+ 0.3416407865 0.0000000000 -0.4472135955
+-0.2763932023 -0.2008114159 -0.4472135955
+3 0 2 1
+3 0 3 2
+3 0 4 3
+5 0 1 5 8 4
+3 1 6 5
+3 1 2 6
+5 2 3 7 9 6
+3 3 4 7
+3 4 8 7
+3 5 9 8
+3 5 6 9
+3 7 8 9
+4 3 0 1 2
+4 3 4 5 0
+4 5 6 1 0
+4 6 7 2 1
+4 7 8 3 2
+4 3 9 10 4
+4 10 6 5 4
+4 6 11 8 7
+4 11 9 3 8
+4 9 10 6 11
+pentagrammic prism
+pentagrammic dipyramid
+2 5/2|2
+(4.4.5/2)
+dihedral group
+D
+5{4}+2{5/2}
+2 10 15 7 10 2 0 0 2 2 3 20 2 0 -1
+ 0.0000000000 0.0000000000 1.0000000000
+ 0.9987422138 0.0000000000 0.0501397095
+-0.9033708188 0.4259192097 0.0501397095
+ 0.6354709497 -0.7704950886 0.0501397095
+ 0.0953713949 0.4259192097 -0.8997205810
+ 0.0182143157 -0.7704950886 0.6371856536
+-0.2678998691 -0.3445758789 -0.8997205810
+ 0.6059995679 0.4761921529 0.6371856536
+-0.8851565032 -0.3445758789 -0.3126746369
+-0.2973712509 0.9021113626 -0.3126746369
+ 0.2129596049 0.9510565163 0.2239189798
+-0.5982071492 -0.7694208843 0.2239189798
+ 0.2129596049 -0.1004057079 0.2239189798
+ 0.2536312703 -0.7694208843 -0.5862274998
+-0.2129596049 0.1004057079 -0.2239189798
+ 0.7549598948 0.2938926261 -0.5862274998
+-0.6233436208 0.2938926261 0.7246170401
+4 0 2 4 1
+4 0 3 6 2
+5 0 1 5 7 3 2
+4 1 4 8 5
+5 2 6 9 8 4 2
+4 3 7 9 6
+4 5 8 9 7
+3 2 0 1
+3 2 3 0
+3 0 4 1
+3 1 5 2
+3 3 4 0
+3 2 6 3
+3 4 5 1
+3 5 6 2
+3 6 4 3
+3 4 5 6
+pentagrammic antiprism
+pentagrammic deltohedron
+|2 2 5/2
+(3.3.3.5/2)
+dihedral group
+D
+10{3}+2{5/2}
+3 10 20 12 10 2 0 0 2 2 4 20 2 0 -1
+ 0.0000000000 0.0000000000 1.0000000000
+ 0.9870590084 0.0000000000 -0.1603574566
+-0.1885114962 0.9688905521 -0.1603574566
+-0.9150540242 -0.3700832595 -0.1603574566
+ 0.5380310318 -0.8275313256 -0.1603574566
+-0.0720049843 -0.8275313256 0.5567828907
+-0.3050180081 -0.3700832595 -0.8774978039
+ 0.1440099685 0.4574480661 -0.8774978039
+ 0.6545375437 0.5114424860 0.5567828907
+-0.8430490399 0.4574480661 0.2828596527
+ 0.5593892211 0.6787159473 0.4758448931
+-0.7730568906 0.4194695241 0.4758448931
+-0.2641077641 -0.8389390482 0.4758448931
+ 0.5593892211 -0.3035309991 0.4758448931
+ 0.4273353390 -0.8389390482 -0.3369952245
+ 0.3457215516 0.4194695241 -0.8393580447
+-0.5593892211 0.3035309991 -0.4758448931
+-0.1632275749 -0.5184928463 -0.8393580447
+ 0.9362844655 0.0990233222 -0.3369952245
+-0.1824939766 0.0990233222 0.9782077132
+-0.8546706780 -0.5184928463 -0.0265179270
+-0.0311736929 0.9991621492 -0.0265179270
+3 0 2 1
+3 0 3 2
+3 0 4 3
+5 0 1 5 8 4 2
+3 1 6 5
+3 1 2 6
+5 2 3 7 9 6 2
+3 3 4 7
+3 4 8 7
+3 5 9 8
+3 5 6 9
+3 7 8 9
+4 3 0 1 2
+4 3 4 5 0
+4 5 6 1 0
+4 6 7 2 1
+4 7 8 3 2
+4 3 9 10 4
+4 10 6 5 4
+4 6 11 8 7
+4 11 9 3 8
+4 9 10 6 11
+pentagrammic crossed antiprism
+pentagrammic concave deltohedron
+|2 2 5/3
+(3.3.3.5/3)
+dihedral group
+D
+10{3}+2{5/3}
+4 10 20 12 10 3 0 0 2 2 4 20 2 0 -1
+ 0.0000000000 0.0000000000 1.0000000000
+ 0.8944271910 0.0000000000 -0.4472135955
+-0.7236067977 0.5257311121 -0.4472135955
+ 0.2763932023 -0.8506508084 -0.4472135955
+ 0.2763932023 0.8506508084 -0.4472135955
+-0.2763932023 0.8506508084 0.4472135955
+-0.2763932023 -0.8506508084 0.4472135955
+-0.8944271910 0.0000000000 0.4472135955
+ 0.7236067977 -0.5257311121 0.4472135955
+-0.0000000000 0.0000000000 -1.0000000000
+ 0.3035309991 0.9341723590 0.1875924741
+-0.7946544723 -0.5773502692 0.1875924741
+ 0.9822469464 0.0000000000 0.1875924741
+ 0.3035309991 0.2205281794 0.1875924741
+ 0.6070619982 -0.0000000000 0.7946544723
+-0.1875924741 -0.5773502692 -0.7946544723
+-0.3035309991 -0.2205281794 -0.1875924741
+-0.6070619982 -0.0000000000 -0.7946544723
+ 0.1875924741 0.5773502692 0.7946544723
+ 0.7946544723 0.5773502692 -0.1875924741
+-0.9822469464 0.0000000000 -0.1875924741
+-0.3035309991 -0.9341723590 -0.1875924741
+3 0 2 1
+3 0 3 2
+3 0 4 3
+5 0 1 5 8 4 3
+3 1 6 5
+3 1 2 6
+5 2 3 7 9 6 3
+3 3 4 7
+3 4 8 7
+3 5 9 8
+3 5 6 9
+3 7 8 9
+4 3 0 1 2
+4 3 4 5 0
+4 5 6 1 0
+4 6 7 2 1
+4 7 8 3 2
+4 3 9 10 4
+4 10 6 5 4
+4 6 11 8 7
+4 11 9 3 8
+4 9 10 6 11
+tetrahedron
+tetrahedron
+3|2 3
+(3.3.3)
+tetrahedral group
+A4
+4{3}
+5 4 6 4 4 1 0 0 2 1 3 24 3 0 -1
+ 0.0000000000 0.0000000000 1.0000000000
+ 0.9428090416 0.0000000000 -0.3333333333
+-0.4714045208 0.8164965809 -0.3333333333
+-0.4714045208 -0.8164965809 -0.3333333333
+ 0.4714045208 0.8164965809 0.3333333333
+-0.9428090416 0.0000000000 0.3333333333
+ 0.4714045208 -0.8164965809 0.3333333333
+-0.0000000000 0.0000000000 -1.0000000000
+3 0 2 1
+3 0 3 2
+3 0 1 3
+3 1 2 3
+3 2 0 1
+3 2 3 0
+3 3 1 0
+3 1 2 3
+truncated tetrahedron
+triakistetrahedron
+2 3|3
+(6.6.3)
+tetrahedral group
+A4
+4{6}+4{3}
+6 12 18 8 12 1 0 0 2 2 3 24 3 0 -1
+ 0.0000000000 0.0000000000 1.0000000000
+ 0.7713892158 0.0000000000 0.6363636364
+-0.6428243465 0.4264014327 0.6363636364
+ 0.2999846950 -0.7106690545 0.6363636364
+ 0.8999540851 0.4264014327 -0.0909090909
+-0.9856639980 0.1421338109 -0.0909090909
+-0.5142594772 0.8528028654 -0.0909090909
+-0.0428549564 -0.9949366763 -0.0909090909
+ 0.5571144337 0.1421338109 -0.8181818182
+ 0.2571297386 0.8528028654 -0.4545454545
+-0.6856793030 -0.5685352436 -0.4545454545
+ 0.0857099129 -0.5685352436 -0.8181818182
+ 0.2461829820 0.8164965809 0.5222329679
+-0.6564879519 -0.5443310540 0.5222329679
+ 0.2461829820 -0.1632993162 0.5222329679
+ 0.8206099399 -0.5443310540 -0.1740776560
+-0.4923659639 0.3265986324 0.1044465936
+ 0.3938927711 0.3265986324 -0.3133397807
+-0.4103049699 0.2721655270 -0.8703882798
+-0.1477097892 -0.4898979486 -0.3133397807
+6 0 2 6 9 4 1
+6 0 3 7 10 5 2
+3 0 1 3
+6 1 4 8 11 7 3
+3 2 5 6
+3 4 9 8
+6 5 10 11 8 9 6
+3 7 11 10
+3 2 0 1
+3 2 3 0
+3 0 4 1
+3 1 3 2
+3 3 5 0
+3 4 6 1
+3 0 6 4
+3 1 7 3
+3 3 6 5
+3 5 0 6
+3 6 7 1
+3 7 3 6
+octahemioctahedron
+octahemioctacron
+3/2 3|3
+(6.3/2.6.3)
+tetrahedral group
+A4
+4{6}+4{3}+4{3/2}
+7 12 24 12 12 0 1 0 0 3 4 24 3 1 -1
+ 0.0000000000 0.0000000000 1.0000000000
+ 0.8660254038 0.0000000000 0.5000000000
+-0.8660254038 0.0000000000 0.5000000000
+-0.2886751346 0.8164965809 0.5000000000
+ 0.2886751346 -0.8164965809 0.5000000000
+ 0.8660254038 0.0000000000 -0.5000000000
+ 0.5773502692 0.8164965809 0.0000000000
+-0.5773502692 -0.8164965809 0.0000000000
+-0.8660254038 -0.0000000000 -0.5000000000
+-0.2886751346 0.8164965809 -0.5000000000
+ 0.2886751346 -0.8164965809 -0.5000000000
+-0.0000000000 0.0000000000 -1.0000000000
+ 0.0000000000 1.0000000000 0.0000000000
+-0.4714045208 0.3333333333 0.8164965809
+-0.9428090416 -0.3333333333 0.0000000000
+ 0.4714045208 -0.3333333333 0.8164965809
+ 0.4714045208 -0.3333333333 -0.8164965809
+ 0.9428090416 0.3333333333 0.0000000000
+-0.9428090416 -0.3333333333 0.0000000000
+ 0.4714045208 -0.3333333333 0.8164965809
+ 0.0000000000 1.0000000000 0.0000000000
+-0.0000000000 -1.0000000000 0.0000000000
+ 0.4714045208 -0.3333333333 -0.8164965809
+-0.4714045208 0.3333333333 -0.8164965809
+6 0 1 5 11 8 2
+3 0 2 3 2
+6 0 3 9 11 10 4
+3 0 1 4
+6 1 4 7 8 9 6
+3 1 6 5 2
+3 2 8 7
+6 2 7 10 5 6 3
+3 3 6 9
+3 4 10 7 2
+3 5 10 11
+3 8 11 9 2
+4 3 0 1 2
+4 3 4 5 0
+4 6 0 1 7
+4 8 7 1 2
+4 9 2 3 4
+4 5 7 10 0
+4 8 4 5 7
+4 6 4 9 7
+4 11 0 6 4
+4 11 2 8 4
+4 10 2 9 7
+4 10 0 11 2
+tetrahemihexahedron
+tetrahemihexacron
+3/2 3|2
+(4.3/2.4.3)
+tetrahedral group
+A4
+3{4}+2{3}+2{3/2}
+8 6 12 7 6 0 1 1 1 3 4 24 3 1 -1
+ 0.0000000000 0.0000000000 1.0000000000
+ 1.0000000000 0.0000000000 0.0000000000
+-1.0000000000 0.0000000000 0.0000000000
+-0.0000000000 1.0000000000 0.0000000000
+-0.0000000000 -1.0000000000 0.0000000000
+ 0.0000000000 0.0000000000 -1.0000000000
+ 0.0000000000 1.0000000000 0.0000000000
+-0.5773502692 0.5773502692 0.5773502692
+-1.0000000000 0.0000000000 0.0000000000
+ 0.5773502692 -0.5773502692 0.5773502692
+-0.0000000000 0.0000000000 -1.0000000000
+ 0.5773502692 0.5773502692 -0.5773502692
+-0.5773502692 -0.5773502692 -0.5773502692
+4 0 1 5 2
+3 0 2 3 2
+4 0 3 5 4
+3 0 1 4
+4 1 4 2 3
+3 1 3 5 2
+3 2 5 4
+4 3 0 1 2
+4 3 4 5 0
+4 6 0 1 4
+4 5 2 1 4
+4 6 2 3 4
+4 5 0 6 2
+octahedron
+hexahedron
+4|2 3
+(3.3.3.3)
+octahedral group
+S4
+8{3}
+9 6 12 8 6 1 0 0 2 1 4 48 4 0 -1
+ 0.0000000000 0.0000000000 1.0000000000
+ 1.0000000000 0.0000000000 0.0000000000
+ 0.0000000000 1.0000000000 0.0000000000
+-1.0000000000 0.0000000000 0.0000000000
+ 0.0000000000 -1.0000000000 0.0000000000
+ 0.0000000000 0.0000000000 -1.0000000000
+ 0.5773502692 0.5773502692 0.5773502692
+-0.5773502692 0.5773502692 0.5773502692
+-0.5773502692 -0.5773502692 0.5773502692
+ 0.5773502692 -0.5773502692 0.5773502692
+ 0.5773502692 -0.5773502692 -0.5773502692
+ 0.5773502692 0.5773502692 -0.5773502692
+-0.5773502692 0.5773502692 -0.5773502692
+-0.5773502692 -0.5773502692 -0.5773502692
+3 0 2 1
+3 0 3 2
+3 0 4 3
+3 0 1 4
+3 1 5 4
+3 1 2 5
+3 2 3 5
+3 3 4 5
+4 3 0 1 2
+4 3 4 5 0
+4 5 6 1 0
+4 6 7 2 1
+4 7 4 3 2
+4 4 5 6 7
+hexahedron
+octahedron
+3|2 4
+(4.4.4)
+octahedral group
+S4
+6{4}
+10 8 12 6 8 1 0 0 2 1 3 48 4 0 -1
+ 0.0000000000 0.0000000000 1.0000000000
+ 0.9428090416 0.0000000000 0.3333333333
+-0.4714045208 0.8164965809 0.3333333333
+-0.4714045208 -0.8164965809 0.3333333333
+ 0.4714045208 0.8164965809 -0.3333333333
+ 0.4714045208 -0.8164965809 -0.3333333333
+-0.9428090416 0.0000000000 -0.3333333333
+ 0.0000000000 0.0000000000 -1.0000000000
+ 0.4082482905 0.7071067812 0.5773502692
+-0.8164965809 0.0000000000 0.5773502692
+ 0.4082482905 -0.7071067812 0.5773502692
+ 0.8164965809 0.0000000000 -0.5773502692
+-0.4082482905 0.7071067812 -0.5773502692
+-0.4082482905 -0.7071067812 -0.5773502692
+4 0 2 4 1
+4 0 3 6 2
+4 0 1 5 3
+4 1 4 7 5
+4 2 6 7 4
+4 3 5 7 6
+3 2 0 1
+3 2 3 0
+3 0 4 1
+3 1 5 2
+3 3 4 0
+3 5 3 2
+3 4 5 1
+3 3 4 5
+cuboctahedron
+rhombic dodecahedron
+2|3 4
+(3.4.3.4)
+octahedral group
+S4
+6{4}+8{3}
+11 12 24 14 12 1 0 0 2 2 4 48 4 0 -1
+ 0.0000000000 0.0000000000 1.0000000000
+ 0.8660254038 0.0000000000 0.5000000000
+ 0.2886751346 0.8164965809 0.5000000000
+-0.8660254038 0.0000000000 0.5000000000
+-0.2886751346 -0.8164965809 0.5000000000
+ 0.8660254038 0.0000000000 -0.5000000000
+ 0.5773502692 -0.8164965809 0.0000000000
+-0.5773502692 0.8164965809 0.0000000000
+ 0.2886751346 0.8164965809 -0.5000000000
+-0.8660254038 0.0000000000 -0.5000000000
+-0.2886751346 -0.8164965809 -0.5000000000
+ 0.0000000000 0.0000000000 -1.0000000000
+ 0.4082482905 0.2886751346 0.7071067812
+-0.4082482905 0.5773502692 0.7071067812
+-0.4082482905 -0.2886751346 0.7071067812
+ 0.4082482905 -0.5773502692 0.7071067812
+ 0.8164965809 -0.2886751346 0.0000000000
+ 0.8164965809 0.5773502692 0.0000000000
+ 0.0000000000 0.8660254038 0.0000000000
+-0.8164965809 0.2886751346 -0.0000000000
+-0.8164965809 -0.5773502692 0.0000000000
+-0.0000000000 -0.8660254038 -0.0000000000
+ 0.4082482905 -0.5773502692 -0.7071067812
+ 0.4082482905 0.2886751346 -0.7071067812
+-0.4082482905 0.5773502692 -0.7071067812
+-0.4082482905 -0.2886751346 -0.7071067812
+3 0 2 1
+4 0 3 7 2
+3 0 4 3
+4 0 1 6 4
+3 1 5 6
+4 1 2 8 5
+3 2 7 8
+3 3 9 7
+4 3 4 10 9
+3 4 6 10
+4 5 11 10 6
+3 5 8 11
+4 7 9 11 8
+3 9 10 11
+4 3 0 1 2
+4 3 4 5 0
+4 5 6 1 0
+4 1 7 8 2
+4 8 9 3 2
+4 4 10 11 5
+4 9 10 4 3
+4 6 12 7 1
+4 11 12 6 5
+4 12 13 8 7
+4 13 10 9 8
+4 10 11 12 13
+truncated octahedron
+tetrakishexahedron
+2 4|3
+(6.6.4)
+octahedral group
+S4
+8{6}+6{4}
+12 24 36 14 24 1 0 0 2 2 3 48 4 0 -1
+ 0.0000000000 0.0000000000 1.0000000000
+ 0.6000000000 0.0000000000 0.8000000000
+-0.4000000000 0.4472135955 0.8000000000
+-0.0666666667 -0.5962847940 0.8000000000
+ 0.8000000000 0.4472135955 0.4000000000
+ 0.5333333333 -0.5962847940 0.6000000000
+-0.8666666667 0.2981423970 0.4000000000
+-0.2000000000 0.8944271910 0.4000000000
+-0.5333333333 -0.7453559925 0.4000000000
+ 0.9333333333 0.2981423970 -0.2000000000
+ 0.4000000000 0.8944271910 0.2000000000
+ 0.6666666667 -0.7453559925 0.0000000000
+-0.6666666667 0.7453559925 0.0000000000
+-0.9333333333 -0.2981423970 0.2000000000
+-0.4000000000 -0.8944271910 -0.2000000000
+ 0.5333333333 0.7453559925 -0.4000000000
+ 0.8666666667 -0.2981423970 -0.4000000000
+ 0.2000000000 -0.8944271910 -0.4000000000
+-0.5333333333 0.5962847940 -0.6000000000
+-0.8000000000 -0.4472135955 -0.4000000000
+ 0.0666666667 0.5962847940 -0.8000000000
+ 0.4000000000 -0.4472135955 -0.8000000000
+-0.6000000000 -0.0000000000 -0.8000000000
+ 0.0000000000 -0.0000000000 -1.0000000000
+ 0.2581988897 0.5773502692 0.7745966692
+-0.6024640761 -0.1924500897 0.7745966692
+ 0.2581988897 -0.2886751346 0.7745966692
+ 0.9467292624 -0.1924500897 0.2581988897
+-0.5163977795 0.5773502692 0.3872983346
+ 0.0860662966 -0.9622504486 0.2581988897
+ 0.6454972244 0.5773502692 0.0000000000
+-0.9467292624 0.1924500897 -0.2581988897
+-0.0860662966 0.9622504486 -0.2581988897
+-0.6454972244 -0.5773502692 -0.0000000000
+ 0.6024640761 0.1924500897 -0.7745966692
+ 0.5163977795 -0.5773502692 -0.3872983346
+-0.2581988897 -0.5773502692 -0.7745966692
+-0.2581988897 0.2886751346 -0.7745966692
+6 0 2 7 10 4 1
+6 0 3 8 13 6 2
+4 0 1 5 3
+6 1 4 9 16 11 5
+4 2 6 12 7
+6 3 5 11 17 14 8
+4 4 10 15 9
+6 6 13 19 22 18 12
+6 7 12 18 20 15 10
+4 8 14 19 13
+6 9 15 20 23 21 16
+4 11 16 21 17
+6 14 17 21 23 22 19
+4 18 22 23 20
+3 2 0 1
+3 2 3 0
+3 0 4 1
+3 1 5 2
+3 3 6 0
+3 5 3 2
+3 4 7 1
+3 0 8 4
+3 1 9 5
+3 3 10 6
+3 6 8 0
+3 5 11 3
+3 8 7 4
+3 7 9 1
+3 9 12 5
+3 10 8 6
+3 11 10 3
+3 12 11 5
+3 8 13 7
+3 7 12 9
+3 10 13 8
+3 12 10 11
+3 13 12 7
+3 10 13 12
+truncated hexahedron
+triakisoctahedron
+2 3|4
+(8.8.3)
+octahedral group
+S4
+6{8}+8{3}
+13 24 36 14 24 1 0 0 2 2 3 48 4 0 -1
+ 0.0000000000 0.0000000000 1.0000000000
+ 0.5395042868 0.0000000000 0.8419828529
+-0.4604957132 0.2810846377 0.8419828529
+ 0.2466110680 -0.4798414911 0.8419828529
+ 0.8419828529 0.2810846377 0.4604957132
+-0.8651239283 0.1987568534 0.4604957132
+-0.5722307095 0.6785983445 0.4604957132
+ 0.1348760717 -0.8773551980 0.4604957132
+ 0.9768589246 0.1987568534 -0.0790085736
+ 0.7302478566 0.6785983445 0.0790085736
+-0.9768589246 -0.1987568534 0.0790085736
+-0.2697521434 0.9596829823 0.0790085736
+-0.2697521434 -0.9596829823 0.0790085736
+ 0.2697521434 -0.9596829823 -0.0790085736
+ 0.8651239283 -0.1987568534 -0.4604957132
+ 0.2697521434 0.9596829823 -0.0790085736
+-0.7302478566 -0.6785983445 -0.0790085736
+-0.8419828529 -0.2810846377 -0.4604957132
+-0.1348760717 0.8773551980 -0.4604957132
+ 0.5722307095 -0.6785983445 -0.4604957132
+ 0.4604957132 -0.2810846377 -0.8419828529
+-0.5395042868 0.0000000000 -0.8419828529
+-0.2466110680 0.4798414911 -0.8419828529
+-0.0000000000 0.0000000000 -1.0000000000
+ 0.1987568534 0.7071067812 0.6785983445
+-0.5380560257 -0.5000000000 0.6785983445
+ 0.1987568534 -0.1213203436 0.6785983445
+ 0.8191406634 -0.5000000000 0.2810846377
+-0.4798414911 0.2928932188 0.4457402063
+ 0.6444970597 0.2928932188 0.1164290691
+-0.8191406634 0.5000000000 -0.2810846377
+ 0.0341012848 -0.7071067812 0.1164290691
+ 0.5380560257 0.5000000000 -0.6785983445
+-0.6444970597 -0.2928932188 -0.1164290691
+-0.0341012848 0.7071067812 -0.1164290691
+-0.1987568534 -0.7071067812 -0.6785983445
+ 0.4798414911 -0.2928932188 -0.4457402063
+-0.1987568534 0.1213203436 -0.6785983445
+8 0 2 6 11 15 9 4 1
+8 0 3 7 12 16 10 5 2
+3 0 1 3
+8 1 4 8 14 19 13 7 3
+3 2 5 6
+3 4 9 8
+8 5 10 17 21 22 18 11 6
+3 7 13 12
+8 8 9 15 18 22 23 20 14
+3 10 16 17
+3 11 18 15
+8 12 13 19 20 23 21 17 16
+3 14 20 19
+3 21 23 22
+3 2 0 1
+3 2 3 0
+3 0 4 1
+3 1 3 2
+3 3 5 0
+3 4 6 1
+3 0 6 4
+3 1 7 3
+3 3 8 5
+3 8 0 5
+3 6 9 1
+3 0 10 6
+3 1 11 7
+3 11 3 7
+3 3 12 8
+3 8 10 0
+3 9 11 1
+3 6 11 9
+3 8 6 10
+3 11 12 3
+3 11 8 12
+3 6 13 11
+3 8 13 6
+3 11 8 13
+small rhombicuboctahedron
+deltoidal icositetrahedron
+3 4|2
+(4.3.4.4)
+octahedral group
+S4
+18{4}+8{3}
+14 24 48 26 24 1 0 0 2 2 4 48 4 0 -1
+ 0.0000000000 0.0000000000 1.0000000000
+ 0.6675992222 0.0000000000 0.7445208382
+-0.0977676425 0.6604015517 0.7445208382
+-0.6389637427 0.1934271362 0.7445208382
+-0.0977676425 -0.6604015517 0.7445208382
+ 0.5698315797 0.6604015517 0.4890416764
+ 0.9727633538 0.1934271362 0.1277395809
+ 0.5698315797 -0.6604015517 0.4890416764
+-0.3337996111 0.9339488311 0.1277395809
+-0.7367313852 -0.4669744155 0.4890416764
+-0.8749957112 0.4669744155 0.1277395809
+-0.3337996111 -0.9339488311 0.1277395809
+ 0.3337996111 0.9339488311 -0.1277395809
+ 0.8749957112 -0.4669744155 -0.1277395809
+ 0.7367313852 0.4669744155 -0.4890416764
+ 0.3337996111 -0.9339488311 -0.1277395809
+-0.5698315797 0.6604015517 -0.4890416764
+-0.9727633538 -0.1934271362 -0.1277395809
+-0.5698315797 -0.6604015517 -0.4890416764
+ 0.0977676425 0.6604015517 -0.7445208382
+ 0.6389637427 -0.1934271362 -0.7445208382
+ 0.0977676425 -0.6604015517 -0.7445208382
+-0.6675992222 -0.0000000000 -0.7445208382
+ 0.0000000000 -0.0000000000 -1.0000000000
+ 0.3302007759 0.3826834324 0.8628562095
+-0.2553967884 0.2959899757 0.8628562095
+-0.4269143440 -0.2705980501 0.8628562095
+ 0.3302007759 -0.3826834324 0.8628562095
+ 0.8938887595 -0.2705980501 0.3574067443
+ 0.7661903653 0.2959899757 0.4719117310
+ 0.1367736397 0.9238795325 0.3574067443
+-0.5636879836 0.6532814824 0.5054494651
+-0.9339488311 0.0000000000 0.3574067443
+-0.4050047633 -0.7145830136 0.4719117310
+ 0.1367736397 -0.9238795325 0.3574067443
+ 0.7571151198 0.6532814824 0.0000000000
+ 0.9339488311 0.0000000000 -0.3574067443
+ 0.6165823904 -0.7145830136 0.0809672526
+-0.1367736397 0.9238795325 -0.3574067443
+-0.6165823904 0.7145830136 -0.0809672526
+-0.7571151198 -0.6532814824 0.0000000000
+-0.8938887595 0.2705980501 -0.3574067443
+-0.1367736397 -0.9238795325 -0.3574067443
+ 0.4050047633 0.7145830136 -0.4719117310
+ 0.5636879836 -0.6532814824 -0.5054494651
+ 0.4269143440 0.2705980501 -0.8628562095
+-0.3302007759 0.3826834324 -0.8628562095
+-0.7661903653 -0.2959899757 -0.4719117310
+-0.3302007759 -0.3826834324 -0.8628562095
+ 0.2553967884 -0.2959899757 -0.8628562095
+4 0 2 5 1
+3 0 3 2
+4 0 4 9 3
+4 0 1 7 4
+4 1 6 13 7
+3 1 5 6
+4 2 8 12 5
+4 2 3 10 8
+4 3 9 17 10
+3 4 11 9
+4 4 7 15 11
+4 5 12 14 6
+4 6 14 20 13
+3 7 13 15
+4 8 16 19 12
+3 8 10 16
+4 9 11 18 17
+4 10 17 22 16
+4 11 15 21 18
+3 12 19 14
+4 13 20 21 15
+4 14 19 23 20
+4 16 22 23 19
+3 17 18 22
+4 18 21 23 22
+3 20 23 21
+4 3 0 1 2
+4 3 4 5 0
+4 0 6 7 1
+4 7 8 2 1
+4 2 9 10 3
+4 5 11 6 0
+4 4 12 11 5
+4 10 13 4 3
+4 6 14 15 7
+4 8 16 9 2
+4 15 17 8 7
+4 16 18 10 9
+4 11 19 14 6
+4 13 20 12 4
+4 12 21 19 11
+4 18 20 13 10
+4 14 22 17 15
+4 17 23 16 8
+4 23 24 18 16
+4 21 22 14 19
+4 20 25 21 12
+4 24 25 20 18
+4 22 24 23 17
+4 21 22 24 25
+truncated cuboctahedron
+disdyakisdodecahedron
+2 3 4|
+(4.6.8)
+octahedral group
+S4
+6{8}+8{6}+12{4}
+15 48 72 26 48 1 0 0 2 3 3 48 4 0 -1
+ 0.0000000000 0.0000000000 1.0000000000
+ 0.4213179058 0.0000000000 0.9069130180
+-0.0205668596 0.4208156152 0.9069130180
+-0.3330265737 -0.2580737859 0.9069130180
+ 0.4007510462 0.4208156152 0.8138260361
+ 0.6841248285 -0.2580737859 0.6821811637
+-0.3741602929 0.5835574446 0.7207390541
+-0.3826793651 -0.6230452339 0.6821811637
+-0.6866200070 -0.0953319565 0.7207390541
+ 0.6429911093 0.5835574446 0.4960071997
+ 0.6344720372 -0.6230452339 0.4574493093
+ 0.9263648917 -0.0953319565 0.3643623273
+-0.4528990160 0.8137091469 0.3643623273
+-0.7071868666 0.3254836587 0.6276520721
+-0.7362727984 -0.4603034045 0.4960071997
+-0.1198724423 -0.8811190198 0.4574493093
+ 0.5642523862 0.8137091469 0.1396304730
+ 0.9057980321 0.3254836587 0.2712753454
+ 0.8767121003 -0.4603034045 0.1396304730
+ 0.3014454635 -0.8811190198 0.3643623273
+-0.7859255897 0.5556353610 0.2712753454
+-0.2106589529 0.9764509762 0.0465434910
+-0.8270593089 -0.5556353610 0.0851013814
+-0.2106589529 -0.9764509762 0.0465434910
+ 0.8270593089 0.5556353610 -0.0851013814
+ 0.2106589529 0.9764509762 -0.0465434910
+ 0.7859255897 -0.5556353610 -0.2712753454
+ 0.2106589529 -0.9764509762 -0.0465434910
+-0.8767121003 0.4603034045 -0.1396304730
+-0.3014454635 0.8811190198 -0.3643623273
+-0.9057980321 -0.3254836587 -0.2712753454
+-0.5642523862 -0.8137091469 -0.1396304730
+ 0.7362727984 0.4603034045 -0.4960071997
+ 0.1198724423 0.8811190198 -0.4574493093
+ 0.7071868666 -0.3254836587 -0.6276520721
+ 0.4528990160 -0.8137091469 -0.3643623273
+-0.9263648917 0.0953319565 -0.3643623273
+-0.6344720372 0.6230452339 -0.4574493093
+-0.6429911093 -0.5835574446 -0.4960071997
+ 0.6866200070 0.0953319565 -0.7207390541
+ 0.3826793651 0.6230452339 -0.6821811637
+ 0.3741602929 -0.5835574446 -0.7207390541
+-0.6841248285 0.2580737859 -0.6821811637
+-0.4007510462 -0.4208156152 -0.8138260361
+ 0.3330265737 0.2580737859 -0.9069130180
+ 0.0205668596 -0.4208156152 -0.9069130180
+-0.4213179058 -0.0000000000 -0.9069130180
+-0.0000000000 -0.0000000000 -1.0000000000
+ 0.1824857240 0.1916223125 0.8259425910
+-0.3588578683 0.1651647923 0.8259425910
+ 0.1824857240 -0.5334020968 0.8259425910
+ 0.6734372751 0.1651647923 0.5978648424
+ 0.1150758511 0.8458618109 0.5208409981
+-0.4869154353 -0.3271197492 0.6388327969
+ 0.7107416431 -0.3271197492 0.3742195883
+-0.5282559191 0.5187420617 0.4517230027
+-0.4805150176 -0.7290726662 0.2753141970
+-0.9764509762 0.0000000000 0.2157394053
+ 0.6694011593 0.5187420617 0.1871097942
+ 0.5517801258 -0.7290726662 0.0472364484
+ 0.9764509762 0.0000000000 -0.2157394053
+-0.5517801258 0.7290726662 -0.0472364484
+ 0.0413404837 -0.8458618109 0.1871097942
+ 0.4805150176 0.7290726662 -0.2753141970
+-0.0413404837 0.8458618109 -0.1871097942
+-0.6694011593 -0.5187420617 -0.1871097942
+-0.1150758511 -0.8458618109 -0.5208409981
+ 0.5282559191 -0.5187420617 -0.4517230027
+-0.7107416431 0.3271197492 -0.3742195883
+-0.1824857240 0.5334020968 -0.8259425910
+-0.6734372751 -0.1651647923 -0.5978648424
+ 0.4869154353 0.3271197492 -0.6388327969
+ 0.3588578683 -0.1651647923 -0.8259425910
+-0.1824857240 -0.1916223125 -0.8259425910
+4 0 2 4 1
+6 0 3 8 13 6 2
+8 0 1 5 10 19 15 7 3
+6 1 4 9 17 11 5
+8 2 6 12 21 25 16 9 4
+4 3 7 14 8
+4 5 11 18 10
+4 6 13 20 12
+6 7 15 23 31 22 14
+8 8 14 22 30 36 28 20 13
+4 9 16 24 17
+6 10 18 26 35 27 19
+8 11 17 24 32 39 34 26 18
+6 12 20 28 37 29 21
+4 15 19 27 23
+6 16 25 33 40 32 24
+4 21 29 33 25
+4 22 31 38 30
+8 23 27 35 41 45 43 38 31
+4 26 34 41 35
+4 28 36 42 37
+8 29 37 42 46 47 44 40 33
+6 30 38 43 46 42 36
+4 32 40 44 39
+6 34 39 44 47 45 41
+4 43 45 47 46
+3 2 0 1
+3 2 3 0
+3 0 4 1
+3 1 5 2
+3 3 4 0
+3 2 6 3
+3 4 7 1
+3 5 8 2
+3 1 9 5
+3 3 10 4
+3 2 11 6
+3 6 12 3
+3 4 13 7
+3 7 9 1
+3 9 8 5
+3 8 14 2
+3 10 15 4
+3 12 10 3
+3 11 12 6
+3 14 11 2
+3 13 9 7
+3 4 16 13
+3 9 17 8
+3 8 18 14
+3 12 15 10
+3 15 16 4
+3 11 19 12
+3 18 11 14
+3 13 20 9
+3 16 21 13
+3 9 22 17
+3 17 18 8
+3 12 23 15
+3 15 21 16
+3 19 24 12
+3 18 19 11
+3 20 22 9
+3 21 20 13
+3 22 18 17
+3 24 23 12
+3 23 21 15
+3 18 24 19
+3 21 22 20
+3 22 25 18
+3 24 21 23
+3 25 24 18
+3 21 25 22
+3 24 21 25
+snub hexahedron
+pentagonal icositetrahedron
+|2 3 4
+(3.3.3.3.4)
+octahedral group
+S4
+6{4}+32{3}
+16 24 60 38 24 1 0 0 2 2 5 48 4 0 -1
+ 0.0000000000 0.0000000000 1.0000000000
+ 0.6907659000 0.0000000000 0.7230784683
+ 0.2898753354 0.6270006527 0.7230784683
+-0.4474773703 0.5262333434 0.7230784683
+-0.6654371656 -0.1853399775 0.7230784683
+-0.1110152292 -0.6817867317 0.7230784683
+ 0.5797506708 -0.6817867317 0.4461569367
+ 0.9806412354 -0.1853399775 0.0631811688
+ 0.8230392005 0.5262333434 0.2137403629
+ 0.2432885297 0.9678940186 0.0631811688
+-0.4940641761 0.8671267092 0.0631811688
+-0.9340544297 0.2861072869 0.2137403629
+-0.6516662110 -0.7277679621 0.2137403629
+ 0.0253287344 -0.9976806078 0.0631811688
+ 0.6188503599 -0.7277679621 -0.2955977425
+ 0.7626814402 -0.0845726681 -0.6412210887
+ 0.6050794053 0.6270006527 -0.4906618946
+-0.1110152292 0.8123406303 -0.5725192742
+-0.7511236604 0.4416606752 -0.4906618946
+-0.9202834751 -0.2563206977 -0.2955977425
+-0.4146615192 -0.7663593998 -0.4906618946
+ 0.1788601062 -0.4964467542 -0.8494408059
+ 0.1713729895 0.2401260565 -0.9554950421
+-0.4687354417 -0.1305538986 -0.8736376625
+ 0.3408933659 0.2179597953 0.8503402074
+-0.0547860790 0.4008905646 0.8503402074
+-0.3868745963 0.1185023459 0.8503402074
+-0.2699126456 -0.3014331152 0.8503402074
+ 0.3408933659 -0.4008905646 0.8503402074
+ 0.7825540411 -0.3014331152 0.4284162431
+ 0.8671267092 0.1185023459 0.3476229160
+ 0.6270006527 0.4008905646 0.5770183396
+ 0.4714472644 0.7373527058 0.3476229160
+-0.1200630282 0.8785468151 0.4623206278
+-0.6520001425 0.5838213339 0.3476229160
+-0.7115733209 0.2179597953 0.5770183396
+-0.9324036585 -0.2596964552 0.2513586457
+-0.4964467542 -0.5544219364 0.5770183396
+-0.2563206977 -0.8368101551 0.3476229160
+ 0.1717480296 -0.8208260257 0.4284162431
+ 0.4254660340 -0.8368101551 0.0743010482
+ 0.7575545513 -0.5544219364 0.0743010482
+ 0.8211454788 -0.3468166421 -0.3036964718
+ 0.9324036585 0.2596964552 -0.2513586457
+ 0.5810194223 0.7373527058 -0.0743010482
+ 0.2563206977 0.8368101551 -0.3476229160
+-0.1257667992 0.9202834751 -0.1550943753
+-0.4714472644 0.7373527058 -0.3476229160
+-0.7575545513 0.5544219364 -0.0743010482
+-0.9057181469 0.1638858728 -0.1990208196
+-0.6905915802 -0.6084958589 -0.1990208196
+-0.3618751065 -0.8662095526 -0.0743010482
+ 0.1200630282 -0.8785468151 -0.4623206278
+ 0.5424279846 -0.4549644871 -0.6209447838
+ 0.3868745963 -0.1185023459 -0.8503402074
+ 0.5350381919 0.2720337177 -0.7256204361
+ 0.2313212079 0.5838213339 -0.7017381110
+-0.3408933659 0.4008905646 -0.8503402074
+-0.7439626034 0.0190448965 -0.5770183396
+-0.6270006527 -0.4008905646 -0.5770183396
+-0.2449131559 -0.4843638846 -0.7695468803
+-0.0411941310 -0.1344864753 -0.9311335345
+3 0 2 1
+3 0 3 2
+3 0 4 3
+3 0 5 4
+4 0 1 6 5
+3 1 7 6
+3 1 8 7
+3 1 2 8
+3 2 9 8
+4 2 3 10 9
+3 3 11 10
+3 3 4 11
+4 4 12 19 11
+3 4 5 12
+3 5 13 12
+3 5 6 13
+3 6 14 13
+3 6 7 14
+3 7 15 14
+4 7 8 16 15
+3 8 9 16
+3 9 17 16
+3 9 10 17
+3 10 18 17
+3 10 11 18
+3 11 19 18
+3 12 20 19
+3 12 13 20
+4 13 14 21 20
+3 14 15 21
+3 15 22 21
+3 15 16 22
+3 16 17 22
+4 17 18 23 22
+3 18 19 23
+3 19 20 23
+3 20 21 23
+3 21 22 23
+5 4 0 1 2 3
+5 4 5 6 7 0
+5 7 8 9 1 0
+5 9 10 11 2 1
+5 11 12 13 3 2
+5 13 14 15 4 3
+5 15 16 17 5 4
+5 17 18 19 6 5
+5 19 20 8 7 6
+5 20 21 22 9 8
+5 22 23 24 10 9
+5 24 25 12 11 10
+5 12 26 27 14 13
+5 27 28 16 15 14
+5 28 29 18 17 16
+5 29 30 31 19 18
+5 31 32 21 20 19
+5 32 33 23 22 21
+5 33 34 25 24 23
+5 34 35 26 12 25
+5 35 36 28 27 26
+5 36 37 30 29 28
+5 37 33 32 31 30
+5 33 34 35 36 37
+small cubicuboctahedron
+small hexacronic icositetrahedron
+3/2 4|4
+(8.3/2.8.4)
+octahedral group
+S4
+6{8}+6{4}+8{3/2}
+17 24 48 20 24 2 0 0 -4 3 4 48 4 0 -1
+ 0.0000000000 0.0000000000 1.0000000000
+ 0.6675992222 0.0000000000 0.7445208382
+-0.6389637427 0.1934271362 0.7445208382
+-0.0977676425 0.6604015517 0.7445208382
+-0.0977676425 -0.6604015517 0.7445208382
+ 0.9727633538 0.1934271362 0.1277395809
+ 0.5698315797 0.6604015517 0.4890416764
+ 0.5698315797 -0.6604015517 0.4890416764
+-0.7367313852 -0.4669744155 0.4890416764
+-0.8749957112 0.4669744155 0.1277395809
+-0.3337996111 0.9339488311 0.1277395809
+-0.3337996111 -0.9339488311 0.1277395809
+ 0.8749957112 -0.4669744155 -0.1277395809
+ 0.7367313852 0.4669744155 -0.4890416764
+ 0.3337996111 0.9339488311 -0.1277395809
+ 0.3337996111 -0.9339488311 -0.1277395809
+-0.9727633538 -0.1934271362 -0.1277395809
+-0.5698315797 0.6604015517 -0.4890416764
+-0.5698315797 -0.6604015517 -0.4890416764
+ 0.6389637427 -0.1934271362 -0.7445208382
+ 0.0977676425 0.6604015517 -0.7445208382
+ 0.0977676425 -0.6604015517 -0.7445208382
+-0.6675992222 0.0000000000 -0.7445208382
+ 0.0000000000 0.0000000000 -1.0000000000
+ 0.1367736397 0.9238795325 0.3574067443
+-0.1057888136 0.1226030622 0.3574067443
+-0.9339488311 -0.0000000000 0.3574067443
+ 0.1367736397 -0.1585126678 0.3574067443
+ 0.9339488311 -0.0000000000 -0.3574067443
+ 0.3173664407 0.1226030622 0.1954722392
+-0.3868542724 -0.0000000000 0.1480427208
+ 0.3302007759 -0.3826834324 0.8628562095
+ 0.0566534965 0.3826834324 0.1480427208
+-0.1677584658 -0.2959899757 0.1954722392
+-0.1367736397 -0.9238795325 -0.3574067443
+ 0.3868542724 -0.0000000000 -0.1480427208
+ 0.2553967884 -0.2959899757 0.0335377341
+-0.2553967884 0.2959899757 -0.0335377341
+-0.3302007759 0.3826834324 -0.8628562095
+-0.0566534965 -0.3826834324 -0.1480427208
+ 0.1677584658 0.2959899757 -0.1954722392
+-0.3173664407 -0.1226030622 -0.1954722392
+-0.1367736397 0.1585126678 -0.3574067443
+ 0.1057888136 -0.1226030622 -0.3574067443
+8 0 2 9 17 20 13 5 1
+3 0 3 2 2
+8 0 4 11 18 22 17 10 3
+4 0 1 7 4
+8 1 6 14 20 23 21 15 7
+3 1 5 6 2
+4 2 8 16 9
+8 2 3 6 5 12 15 11 8
+4 3 10 14 6
+3 4 8 11 2
+8 4 7 12 19 23 22 16 8
+4 5 13 19 12
+3 7 15 12 2
+3 9 10 17 2
+8 9 16 18 21 19 13 14 10
+4 11 15 21 18
+3 13 20 14 2
+3 16 22 18 2
+4 17 22 23 20
+3 19 21 23 2
+4 3 0 1 2
+4 3 4 5 0
+4 0 6 7 1
+4 7 8 2 1
+4 2 9 10 3
+4 5 7 11 0
+4 4 8 7 5
+4 10 12 4 3
+4 6 10 9 7
+4 0 13 14 6
+4 8 14 13 2
+4 2 15 7 9
+4 7 12 10 11
+4 11 14 16 0
+4 4 16 14 8
+4 15 4 12 7
+4 14 17 10 6
+4 0 18 2 13
+4 2 17 14 15
+4 10 19 14 11
+4 4 18 0 16
+4 19 4 15 14
+4 18 10 17 2
+4 10 19 4 18
+great cubicuboctahedron
+great hexacronic icositetrahedron
+3 4|4/3
+(8/3.3.8/3.4)
+octahedral group
+S4
+6{4}+8{3}+6{8/3}
+18 24 48 20 24 4 0 0 -4 3 4 48 4 0 -1
+ 0.0000000000 0.0000000000 1.0000000000
+ 0.9968739365 0.0000000000 0.0790085736
+ 0.4556778364 0.8866314650 0.0790085736
+-0.8508851285 0.5193766874 0.0790085736
+-0.8508851285 -0.5193766874 0.0790085736
+ 0.0427591319 0.8866314650 0.4604957132
+ 0.1459888080 0.5193766874 -0.8419828529
+ 0.1459888080 -0.5193766874 -0.8419828529
+-0.3952072921 0.3672547776 -0.8419828529
+ 0.8081259966 -0.3672547776 0.4604957132
+-0.4984369683 -0.7345095553 0.4604957132
+-0.4984369683 0.7345095553 0.4604957132
+-0.8081259966 0.3672547776 -0.4604957132
+ 0.3952072921 -0.3672547776 0.8419828529
+ 0.4984369683 -0.7345095553 -0.4604957132
+ 0.4984369683 0.7345095553 -0.4604957132
+-0.0427591319 -0.8866314650 -0.4604957132
+-0.1459888080 0.5193766874 0.8419828529
+-0.1459888080 -0.5193766874 0.8419828529
+-0.4556778364 -0.8866314650 -0.0790085736
+ 0.8508851285 0.5193766874 -0.0790085736
+ 0.8508851285 -0.5193766874 -0.0790085736
+-0.9968739365 0.0000000000 -0.0790085736
+ 0.0000000000 0.0000000000 -1.0000000000
+ 0.2596883437 0.1585126678 0.2810846377
+-0.0959283710 0.3412793093 0.2810846377
+-0.3042438195 0.0000000000 0.2810846377
+ 0.2596883437 -0.9238795325 0.2810846377
+ 0.3042438195 0.0000000000 -0.2810846377
+ 0.2877851131 0.3412793093 -0.0734203966
+ 0.7345095553 -0.0000000000 -0.6785983445
+-0.1075664339 0.3826834324 -0.1164290691
+-0.6269431213 -0.3826834324 -0.6785983445
+-0.4234483164 0.1413625185 -0.0734203966
+-0.2596883437 -0.1585126678 -0.2810846377
+-0.7345095553 -0.0000000000 0.6785983445
+-0.0397348323 0.1413625185 -0.4279254308
+ 0.0397348323 -0.1413625185 0.4279254308
+ 0.1075664339 -0.3826834324 0.1164290691
+ 0.6269431213 0.3826834324 0.6785983445
+ 0.4234483164 -0.1413625185 0.0734203966
+-0.2877851131 -0.3412793093 0.0734203966
+-0.2596883437 0.9238795325 -0.2810846377
+ 0.0959283710 -0.3412793093 -0.2810846377
+8 0 2 9 17 20 13 5 1 3
+3 0 3 2
+8 0 4 11 18 22 17 10 3 3
+4 0 1 7 4
+8 1 6 14 20 23 21 15 7 3
+3 1 5 6
+4 2 8 16 9
+8 2 3 6 5 12 15 11 8 3
+4 3 10 14 6
+3 4 8 11
+8 4 7 12 19 23 22 16 8 3
+4 5 13 19 12
+3 7 15 12
+3 9 10 17
+8 9 16 18 21 19 13 14 10 3
+4 11 15 21 18
+3 13 20 14
+3 16 22 18
+4 17 22 23 20
+3 19 21 23
+4 3 0 1 2
+4 3 4 5 0
+4 0 6 7 1
+4 7 8 2 1
+4 2 9 10 3
+4 5 7 11 0
+4 4 8 7 5
+4 10 12 4 3
+4 6 10 9 7
+4 0 13 14 6
+4 8 14 13 2
+4 2 15 7 9
+4 7 12 10 11
+4 11 14 16 0
+4 4 16 14 8
+4 15 4 12 7
+4 14 17 10 6
+4 0 18 2 13
+4 2 17 14 15
+4 10 19 14 11
+4 4 18 0 16
+4 19 4 15 14
+4 18 10 17 2
+4 10 19 4 18
+cubohemioctahedron
+hexahemioctacron
+4/3 4|3
+(6.4/3.6.4)
+octahedral group
+S4
+4{6}+3{4}+3{4/3}
+19 12 24 10 12 0 1 1 -2 3 4 48 4 1 -1
+ 0.0000000000 0.0000000000 1.0000000000
+ 0.8660254038 0.0000000000 0.5000000000
+-0.8660254038 0.0000000000 0.5000000000
+ 0.2886751346 0.8164965809 0.5000000000
+-0.2886751346 -0.8164965809 0.5000000000
+ 0.8660254038 0.0000000000 -0.5000000000
+ 0.5773502692 -0.8164965809 -0.0000000000
+-0.5773502692 0.8164965809 0.0000000000
+-0.8660254038 -0.0000000000 -0.5000000000
+ 0.2886751346 0.8164965809 -0.5000000000
+-0.2886751346 -0.8164965809 -0.5000000000
+ 0.0000000000 -0.0000000000 -1.0000000000
+ 0.0000000000 1.0000000000 0.0000000000
+-0.4082482905 0.5773502692 0.7071067812
+-0.9428090416 0.3333333333 0.0000000000
+ 0.4082482905 -0.5773502692 0.7071067812
+ 0.4714045208 0.3333333333 -0.8164965809
+ 0.8164965809 0.5773502692 0.0000000000
+-0.8164965809 -0.5773502692 0.0000000000
+ 0.4714045208 0.3333333333 0.8164965809
+ 0.4082482905 -0.5773502692 -0.7071067812
+-0.4082482905 0.5773502692 -0.7071067812
+6 0 1 5 11 8 2
+4 0 2 7 3 3
+6 0 3 9 11 10 4
+4 0 1 6 4
+6 1 6 10 8 7 3
+4 1 3 9 5 3
+4 2 8 10 4
+6 2 4 6 5 9 7
+4 5 6 10 11
+4 7 9 11 8
+4 3 0 1 2
+4 3 4 5 0
+4 6 0 1 7
+4 1 4 5 2
+4 6 2 3 7
+4 5 7 8 0
+4 8 4 3 7
+4 9 7 1 4
+4 9 0 6 4
+4 9 2 5 7
+4 8 2 6 4
+4 8 0 9 2
+cubitruncated cuboctahedron
+tetradyakishexahedron
+4/3 3 4|
+(8/3.6.8)
+octahedral group
+S4
+6{8}+8{6}+6{8/3}
+20 48 72 20 48 4 0 0 -4 3 3 48 4 0 -1
+ 0.0000000000 0.0000000000 1.0000000000
+ 0.6998542122 0.0000000000 0.7142857143
+ 0.4607079005 0.5268245902 0.7142857143
+-0.6939926379 -0.0903888097 0.7142857143
+ 0.1708187941 0.5268245902 0.8326324464
+ 0.9956048929 -0.0903888097 0.0245104108
+ 0.2274231631 0.9632603706 0.1428571429
+ 0.5090227516 -0.2182178902 0.8326324464
+-0.9755922264 -0.2182178902 0.0245104108
+-0.9272773753 0.3460469708 0.1428571429
+-0.0624659433 0.9632603706 0.2612038750
+ 0.2191336452 -0.2182178902 0.9509791785
+ 0.7140053045 -0.2182178902 -0.6652648928
+ 0.7623201555 0.3460469708 -0.5469181607
+-0.0541764254 0.8354312901 -0.5469181607
+-0.4665694748 0.8728715609 -0.1428571429
+-0.0200126666 0.3086066999 0.9509791785
+ 0.3440655318 -0.8354312901 0.4285714286
+-0.8106350066 0.3989955096 0.4285714286
+-0.6798415456 -0.3086066999 -0.6652648928
+-0.8789625242 -0.3989955096 0.2612038750
+-0.3440655318 0.8354312901 -0.4285714286
+ 0.2332847374 0.8728715609 -0.4285714286
+ 0.6798415456 0.3086066999 0.6652648928
+ 0.0541764254 -0.8354312901 0.5469181607
+ 0.8789625242 0.3989955096 -0.2612038750
+ 0.0200126666 -0.3086066999 -0.9509791785
+ 0.8106350066 -0.3989955096 -0.4285714286
+-0.3499271061 0.9258200998 0.1428571429
+-0.2191336452 0.2182178902 -0.9509791785
+-0.7140053045 0.2182178902 0.6652648928
+ 0.0624659433 -0.9632603706 -0.2612038750
+-0.3499271061 -0.9258200998 0.1428571429
+-0.7623201555 -0.3460469708 0.5469181607
+ 0.3499271061 0.9258200998 -0.1428571429
+-0.5090227516 0.2182178902 -0.8326324464
+ 0.9755922264 0.2182178902 -0.0245104108
+-0.2274231631 -0.9632603706 -0.1428571429
+ 0.3499271061 -0.9258200998 -0.1428571429
+ 0.9272773753 -0.3460469708 -0.1428571429
+-0.1708187941 -0.5268245902 -0.8326324464
+-0.9956048929 0.0903888097 -0.0245104108
+-0.2332847374 -0.8728715609 0.4285714286
+-0.4607079005 -0.5268245902 -0.7142857143
+ 0.6939926379 0.0903888097 -0.7142857143
+ 0.4665694748 -0.8728715609 0.1428571429
+-0.6998542122 0.0000000000 -0.7142857143
+ 0.0000000000 0.0000000000 -1.0000000000
+ 0.0639145403 0.0290133127 0.1565580108
+-0.0852193870 0.1594308745 0.1565580108
+ 0.0639145403 -0.9855985597 0.1565580108
+ 0.1704387741 0.1594308745 0.0521860036
+ 0.9258200998 -0.0000000000 -0.3779644730
+-0.1588456165 0.0000000000 0.0648484514
+-0.9258200998 -0.0000000000 0.3779644730
+ 0.1588456165 0.0000000000 -0.0648484514
+-0.0109660014 0.1691019787 -0.0268611081
+-0.0675698741 -0.1127346525 0.1997903117
+-0.1880882870 0.1127346525 -0.0954183045
+-0.3725212402 -0.1691019787 -0.9124869568
+ 0.1880882870 -0.1127346525 0.0954183045
+ 0.0675698741 0.1127346525 -0.1997903117
+-0.0639145403 0.9855985597 -0.1565580108
+ 0.0109660014 -0.1691019787 0.0268611081
+ 0.3725212402 0.1691019787 0.9124869568
+-0.0639145403 -0.0290133127 -0.1565580108
+-0.1704387741 -0.1594308745 -0.0521860036
+ 0.0852193870 -0.1594308745 -0.1565580108
+8 0 2 7 16 23 11 4 1 3
+6 0 3 9 15 6 2
+8 0 1 5 12 26 19 8 3
+6 1 4 10 22 13 5
+8 2 6 14 29 40 31 17 7
+8 3 8 18 33 41 30 20 9 3
+8 4 11 24 37 43 35 21 10
+8 5 13 27 36 44 39 25 12 3
+8 6 15 22 10 21 34 28 14 3
+6 7 17 32 20 30 16
+6 8 19 29 14 28 18
+8 9 20 32 38 27 13 22 15
+6 11 23 36 27 38 24
+6 12 25 34 21 35 26
+8 16 30 41 46 47 44 36 23
+8 17 31 42 45 37 24 38 32 3
+8 18 28 34 25 39 45 42 33
+8 19 26 35 43 47 46 40 29 3
+6 31 40 46 41 33 42
+6 37 45 39 44 47 43
+3 2 0 1
+3 2 3 0
+3 0 4 1
+3 1 5 2
+3 3 6 0
+3 2 7 3
+3 4 8 1
+3 0 9 4
+3 5 10 2
+3 1 11 5
+3 3 8 6
+3 6 12 0
+3 2 13 7
+3 7 11 3
+3 4 10 8
+3 8 11 1
+3 0 14 9
+3 9 15 4
+3 5 16 10
+3 10 17 2
+3 11 9 5
+3 8 13 6
+3 3 8 11
+3 12 14 0
+3 6 15 12
+3 13 16 7
+3 17 13 2
+3 7 12 11
+3 16 8 10
+3 4 17 10
+3 14 5 9
+3 15 18 4
+3 11 15 9
+3 5 18 16
+3 8 13 16
+3 17 6 13
+3 7 14 12
+3 6 19 15
+3 15 12 11
+3 16 19 7
+3 18 17 4
+3 14 18 5
+3 15 16 18
+3 17 19 6
+3 19 14 7
+3 19 15 16
+3 14 17 18
+3 17 19 14
+great rhombicuboctahedron
+great deltoidal icositetrahedron
+3/2 4|2
+(4.3/2.4.4)
+octahedral group
+S4
+18{4}+8{3/2}
+21 24 48 26 24 5 0 0 2 2 4 48 4 0 -1
+ 0.0000000000 0.0000000000 1.0000000000
+ 0.9968739365 0.0000000000 0.0790085736
+-0.8508851285 0.5193766874 0.0790085736
+ 0.4556778364 0.8866314650 0.0790085736
+-0.8508851285 -0.5193766874 0.0790085736
+ 0.1459888080 0.5193766874 -0.8419828529
+ 0.0427591319 0.8866314650 0.4604957132
+ 0.1459888080 -0.5193766874 -0.8419828529
+-0.4984369683 -0.7345095553 0.4604957132
+-0.3952072921 0.3672547776 -0.8419828529
+ 0.8081259966 -0.3672547776 0.4604957132
+-0.4984369683 0.7345095553 0.4604957132
+ 0.4984369683 -0.7345095553 -0.4604957132
+-0.8081259966 0.3672547776 -0.4604957132
+ 0.3952072921 -0.3672547776 0.8419828529
+ 0.4984369683 0.7345095553 -0.4604957132
+-0.1459888080 0.5193766874 0.8419828529
+-0.0427591319 -0.8866314650 -0.4604957132
+-0.1459888080 -0.5193766874 0.8419828529
+ 0.8508851285 0.5193766874 -0.0790085736
+-0.4556778364 -0.8866314650 -0.0790085736
+ 0.8508851285 -0.5193766874 -0.0790085736
+-0.9968739365 0.0000000000 -0.0790085736
+ 0.0000000000 0.0000000000 -1.0000000000
+ 0.2596883437 0.9238795325 0.2810846377
+-0.0959283710 0.3412793093 0.2810846377
+-0.7030040762 0.6532814824 0.2810846377
+ 0.2596883437 -0.9238795325 0.2810846377
+ 0.3357492986 0.6532814824 -0.6785983445
+ 0.2877851131 0.3412793093 -0.0734203966
+-0.6269431213 -0.3826834324 -0.6785983445
+-0.0760609549 0.2705980501 0.9596829823
+ 0.7345095553 0.0000000000 -0.6785983445
+-0.4234483164 0.1413625185 -0.0734203966
+-0.6269431213 0.3826834324 -0.6785983445
+ 0.9626924199 0.2705980501 0.0000000000
+-0.7345095553 0.0000000000 0.6785983445
+-0.0397348323 0.1413625185 -0.4279254308
+ 0.6269431213 -0.3826834324 0.6785983445
+ 0.0397348323 -0.1413625185 0.4279254308
+-0.9626924199 -0.2705980501 0.0000000000
+-0.3357492986 -0.6532814824 0.6785983445
+ 0.6269431213 0.3826834324 0.6785983445
+ 0.4234483164 -0.1413625185 0.0734203966
+ 0.0760609549 -0.2705980501 -0.9596829823
+ 0.7030040762 -0.6532814824 -0.2810846377
+-0.2596883437 0.9238795325 -0.2810846377
+-0.2877851131 -0.3412793093 0.0734203966
+-0.2596883437 -0.9238795325 -0.2810846377
+ 0.0959283710 -0.3412793093 -0.2810846377
+4 0 2 5 1
+3 0 3 2 2
+4 0 4 9 3
+4 0 1 7 4
+4 1 6 13 7
+3 1 5 6 2
+4 2 8 12 5
+4 2 3 10 8
+4 3 9 17 10
+3 4 11 9 2
+4 4 7 15 11
+4 5 12 14 6
+4 6 14 20 13
+3 7 13 15 2
+4 8 16 19 12
+3 8 10 16 2
+4 9 11 18 17
+4 10 17 22 16
+4 11 15 21 18
+3 12 19 14 2
+4 13 20 21 15
+4 14 19 23 20
+4 16 22 23 19
+3 17 18 22 2
+4 18 21 23 22
+3 20 23 21 2
+4 3 0 1 2
+4 3 4 5 0
+4 0 6 7 1
+4 7 8 2 1
+4 2 9 10 3
+4 5 11 6 0
+4 4 12 11 5
+4 10 13 4 3
+4 6 14 15 7
+4 8 16 9 2
+4 15 17 8 7
+4 16 18 10 9
+4 11 19 14 6
+4 13 20 12 4
+4 12 21 19 11
+4 18 20 13 10
+4 14 22 17 15
+4 17 23 16 8
+4 23 24 18 16
+4 21 22 14 19
+4 20 25 21 12
+4 24 25 20 18
+4 22 24 23 17
+4 21 22 24 25
+small rhombihexahedron
+small rhombihexacron
+3/2 2 4|
+(8.4.8/7.4/3)
+octahedral group
+S4
+3{8}+6{4}+6{4/3}+3{8/7}
+22 24 48 18 24 0 0 1 -6 4 4 48 4 0 2
+ 0.0000000000 0.0000000000 1.0000000000
+ 0.6675992222 0.0000000000 0.7445208382
+-0.6389637427 -0.1934271362 0.7445208382
+ 0.2849157898 -0.6037480552 0.7445208382
+-0.0977676425 0.6604015517 0.7445208382
+ 0.9727633538 -0.1934271362 0.1277395809
+ 0.5698315797 0.6604015517 0.4890416764
+-0.3540479528 -0.7971751914 0.4890416764
+-0.7367313852 0.4669744155 0.4890416764
+-0.8749957112 -0.4669744155 0.1277395809
+ 0.5900799214 -0.7971751914 0.1277395809
+ 0.0488838213 0.9906023276 0.1277395809
+ 0.8749957112 0.4669744155 -0.1277395809
+ 0.7367313852 -0.4669744155 -0.4890416764
+-0.0488838213 -0.9906023276 -0.1277395809
+-0.9727633538 0.1934271362 -0.1277395809
+-0.5900799214 0.7971751914 -0.1277395809
+-0.5698315797 -0.6604015517 -0.4890416764
+ 0.3540479528 0.7971751914 -0.4890416764
+ 0.6389637427 0.1934271362 -0.7445208382
+ 0.0977676425 -0.6604015517 -0.7445208382
+-0.6675992222 -0.0000000000 -0.7445208382
+-0.2849157898 0.6037480552 -0.7445208382
+-0.0000000000 -0.0000000000 -1.0000000000
+ 0.1367736397 -0.9238795325 0.3574067443
+-0.0849802448 -0.1913417162 0.3574067443
+ 0.8938887595 0.2705980501 0.3574067443
+ 0.1367736397 0.1585126678 0.3574067443
+-0.4269143440 0.2705980501 0.8628562095
+ 0.3018740276 -0.1913417162 0.2093640235
+-0.3868542724 -0.0000000000 0.1480427208
+-0.8938887595 -0.2705980501 -0.3574067443
+-0.1651003879 0.3498543840 0.1480427208
+-0.1367736397 0.9238795325 -0.3574067443
+ 0.4269143440 -0.2705980501 -0.8628562095
+ 0.3868542724 -0.0000000000 -0.1480427208
+ 0.2217538845 0.3498543840 -0.0000000000
+-0.2217538845 -0.3498543840 -0.0000000000
+ 0.1651003879 -0.3498543840 -0.1480427208
+-0.3018740276 0.1913417162 -0.2093640235
+-0.1367736397 -0.1585126678 -0.3574067443
+ 0.0849802448 0.1913417162 -0.3574067443
+8 0 2 9 17 20 13 5 1
+4 0 3 7 2
+8 0 4 11 18 19 13 10 3 7
+4 0 1 6 4 3
+8 1 3 7 9 15 16 11 6 7
+4 1 5 10 3
+4 2 8 15 9 3
+8 2 7 14 20 23 22 16 8 7
+4 4 8 16 11
+8 4 6 12 19 23 21 15 8
+8 5 12 18 22 21 17 14 10 7
+4 5 13 19 12 3
+4 6 11 18 12
+4 7 9 17 14 3
+4 10 13 20 14
+4 15 21 22 16
+4 17 21 23 20 3
+4 18 22 23 19
+4 3 0 1 2
+4 3 4 5 0
+4 0 6 7 1
+4 1 4 5 2
+4 2 8 9 3
+4 5 10 11 0
+4 9 12 4 3
+4 7 13 4 1
+4 6 9 8 7
+4 0 13 4 6
+4 10 14 2 5
+4 2 12 4 8
+4 10 12 9 11
+4 11 2 14 0
+4 7 14 10 13
+4 4 15 9 6
+4 15 7 8 4
+4 0 16 10 13
+4 2 17 10 12
+4 9 17 2 11
+4 7 16 0 14
+4 15 10 16 9
+4 17 7 15 10
+4 9 17 7 16
+stellated truncated hexahedron
+great triakisoctahedron
+2 3|4/3
+(8/3.8/3.3)
+octahedral group
+S4
+8{3}+6{8/3}
+23 24 36 14 24 7 0 0 2 2 3 48 4 0 -1
+ 0.0000000000 0.0000000000 1.0000000000
+ 0.8722604191 0.0000000000 -0.4890416764
+-0.1277395809 0.8628562095 -0.4890416764
+-0.8348463621 -0.2527247326 -0.4890416764
+-0.4890416764 0.8628562095 0.1277395809
+-0.7819348952 -0.6101314769 0.1277395809
+ 0.9251718860 -0.3574067443 0.1277395809
+ 0.2180651048 0.9675382212 0.1277395809
+-0.2709765716 -0.6101314769 -0.7445208382
+ 0.5638697904 -0.3574067443 0.7445208382
+ 0.2709765716 0.6101314769 0.7445208382
+-0.4361302096 0.5054494651 0.7445208382
+-0.4361302096 -0.5054494651 0.7445208382
+ 0.4361302096 -0.5054494651 -0.7445208382
+ 0.7819348952 0.6101314769 -0.1277395809
+ 0.4361302096 0.5054494651 -0.7445208382
+-0.5638697904 0.3574067443 -0.7445208382
+ 0.4890416764 -0.8628562095 -0.1277395809
+-0.2180651048 -0.9675382212 -0.1277395809
+-0.9251718860 0.3574067443 -0.1277395809
+ 0.1277395809 -0.8628562095 0.4890416764
+-0.8722604191 -0.0000000000 0.4890416764
+ 0.8348463621 0.2527247326 0.4890416764
+ 0.0000000000 -0.0000000000 -1.0000000000
+ 0.1459106924 0.1691019787 0.0854725047
+-0.1886469447 0.1195731559 0.0854725047
+ 0.1459106924 -0.9855985597 0.0854725047
+-0.0177019353 0.1195731559 -0.2063488801
+ 0.0604381877 -0.4082482905 -0.9108680249
+-0.7649573325 -0.4082482905 0.4981702648
+ 0.0177019353 -0.1195731559 0.2063488801
+ 0.8504298372 -0.1691019787 0.4981702648
+ 0.1886469447 -0.1195731559 -0.0854725047
+ 0.7649573325 0.4082482905 -0.4981702648
+-0.8504298372 0.1691019787 -0.4981702648
+-0.1459106924 -0.1691019787 -0.0854725047
+-0.0604381877 0.4082482905 0.9108680249
+-0.1459106924 0.9855985597 -0.0854725047
+8 0 2 6 11 15 9 4 1 3
+8 0 3 7 12 16 10 5 2 3
+3 0 1 3
+8 1 4 8 14 19 13 7 3 3
+3 2 5 6
+3 4 9 8
+8 5 10 17 21 22 18 11 6 3
+3 7 13 12
+8 8 9 15 18 22 23 20 14 3
+3 10 16 17
+3 11 18 15
+8 12 13 19 20 23 21 17 16 3
+3 14 20 19
+3 21 23 22
+3 2 0 1
+3 2 3 0
+3 0 4 1
+3 1 3 2
+3 3 5 0
+3 4 6 1
+3 0 6 4
+3 1 7 3
+3 3 8 5
+3 8 0 5
+3 6 9 1
+3 0 10 6
+3 1 11 7
+3 11 3 7
+3 3 12 8
+3 8 10 0
+3 9 11 1
+3 6 11 9
+3 8 6 10
+3 11 12 3
+3 11 8 12
+3 6 13 11
+3 8 13 6
+3 11 8 13
+great truncated cuboctahedron
+great disdyakisdodecahedron
+4/3 2 3|
+(8/3.4.6)
+octahedral group
+S4
+8{6}+12{4}+6{8/3}
+24 48 72 26 48 1 0 0 2 3 3 48 4 0 -1
+ 0.0000000000 0.0000000000 1.0000000000
+ 0.8305094692 0.0000000000 0.5570045077
+ 0.5180497550 0.6491305182 0.5570045077
+-0.7696968212 0.3119499667 0.5570045077
+ 0.1740414692 0.6491305182 0.7404992487
+ 0.8913221171 0.3119499667 -0.3289864768
+-0.2516470662 0.9610804849 0.1140090155
+ 0.6159262346 -0.2688786644 0.7404992487
+-0.7088841733 0.6238999334 -0.3289864768
+ 0.2348541172 0.9610804849 -0.1454917358
+ 0.2719179488 -0.2688786644 0.9239939897
+ 0.1216252958 0.6238999334 -0.7719819690
+-0.9234674078 0.3550212690 -0.1454917358
+-0.0405417653 0.3802518538 0.9239939897
+-0.0558941070 -0.8749378802 0.4809984974
+-0.2768364897 0.8318665779 0.4809984974
+ 0.3935432447 0.3550212690 -0.8479879793
+ 0.7899677039 0.3802518538 0.4809984974
+ 0.4306070763 -0.8749378802 0.2214977461
+ 0.5536729794 0.8318665779 0.0380030052
+-0.4914197242 0.5629879135 0.6644932384
+-0.8255909283 -0.5629879135 0.0380030052
+-0.7123621069 -0.2258073621 0.6644932384
+-0.9486568314 0.2258073621 0.2214977461
+ 0.8255909283 0.5629879135 -0.0380030052
+ 0.4914197242 -0.5629879135 -0.6644932384
+ 0.9486568314 -0.2258073621 -0.2214977461
+ 0.7123621069 0.2258073621 -0.6644932384
+-0.3935432447 -0.3550212690 0.8479879793
+-0.4306070763 0.8749378802 -0.2214977461
+-0.5536729794 -0.8318665779 -0.0380030052
+-0.7899677039 -0.3802518538 -0.4809984974
+ 0.9234674078 -0.3550212690 0.1454917358
+ 0.0558941070 0.8749378802 -0.4809984974
+ 0.2768364897 -0.8318665779 -0.4809984974
+ 0.0405417653 -0.3802518538 -0.9239939897
+-0.2348541172 -0.9610804849 0.1454917358
+-0.2719179488 0.2688786644 -0.9239939897
+-0.1216252958 -0.6238999334 0.7719819690
+ 0.2516470662 -0.9610804849 -0.1140090155
+-0.6159262346 0.2688786644 -0.7404992487
+ 0.7088841733 -0.6238999334 0.3289864768
+-0.8913221171 -0.3119499667 0.3289864768
+-0.1740414692 -0.6491305182 -0.7404992487
+ 0.7696968212 -0.3119499667 -0.5570045077
+-0.5180497550 -0.6491305182 -0.5570045077
+-0.8305094692 0.0000000000 -0.5570045077
+ 0.0000000000 0.0000000000 -1.0000000000
+ 0.1801043973 0.0866934567 0.3376522109
+-0.0762733399 0.2913001116 0.3376522109
+ 0.1801043973 0.9238795325 0.3376522109
+ 0.3229079525 0.2913001116 0.1247280725
+-0.4554111647 0.1275611441 0.8810952421
+-0.2736567697 0.2705980501 0.0764920424
+ 0.9854240134 0.1275611441 0.1125507370
+ 0.2159554198 0.2705980501 -0.1846681261
+-0.0292293734 -0.1499375931 0.4258482767
+-0.0470439665 0.4412377047 -0.0881960659
+ 0.3699519190 -0.1499375931 0.2129241384
+-0.3991812924 0.0000000000 0.2129241384
+ 0.3499084514 -0.6687572443 0.6559937682
+-0.2159554198 -0.2705980501 0.1846681261
+-0.3499084514 0.6687572443 -0.6559937682
+ 0.3991812924 0.0000000000 -0.2129241384
+ 0.2736567697 -0.2705980501 -0.0764920424
+-0.9854240134 -0.1275611441 -0.1125507370
+-0.3699519190 0.1499375931 -0.2129241384
+ 0.4554111647 -0.1275611441 -0.8810952421
+ 0.0292293734 0.1499375931 -0.4258482767
+ 0.0470439665 -0.4412377047 0.0881960659
+-0.1801043973 -0.0866934567 -0.3376522109
+-0.3229079525 -0.2913001116 -0.1247280725
+-0.1801043973 -0.9238795325 -0.3376522109
+ 0.0762733399 -0.2913001116 -0.3376522109
+8 0 2 7 13 17 10 4 1 3
+4 0 3 6 2
+6 0 1 5 11 8 3
+4 1 4 9 5
+6 2 6 12 21 14 7
+8 3 8 15 23 29 20 12 6 3
+6 4 10 18 25 16 9
+8 5 9 16 24 33 27 19 11 3
+4 7 14 22 13
+4 8 11 19 15
+4 10 17 26 18
+4 12 20 28 21
+6 13 22 30 34 26 17
+8 14 21 28 36 42 38 30 22 3
+6 15 19 27 35 31 23
+4 16 25 32 24
+8 18 26 34 41 44 39 32 25 3
+6 20 29 37 43 36 28
+4 23 31 37 29
+6 24 32 39 45 40 33
+4 27 33 40 35
+4 30 38 41 34
+8 31 35 40 45 47 46 43 37 3
+4 36 43 46 42
+6 38 42 46 47 44 41
+4 39 44 47 45
+3 2 0 1
+3 2 3 0
+3 0 4 1
+3 1 5 2
+3 3 6 0
+3 2 7 3
+3 4 5 1
+3 0 8 4
+3 5 9 2
+3 7 6 3
+3 6 10 0
+3 9 7 2
+3 4 11 5
+3 0 12 8
+3 8 13 4
+3 5 14 9
+3 7 15 6
+3 10 12 0
+3 6 16 10
+3 14 7 9
+3 11 17 5
+3 13 11 4
+3 12 13 8
+3 5 18 14
+3 7 19 15
+3 15 16 6
+3 16 12 10
+3 14 20 7
+3 13 17 11
+3 17 18 5
+3 12 21 13
+3 18 22 14
+3 19 16 15
+3 20 19 7
+3 16 21 12
+3 22 20 14
+3 13 23 17
+3 17 22 18
+3 21 24 13
+3 19 25 16
+3 22 19 20
+3 16 24 21
+3 24 23 13
+3 23 22 17
+3 25 24 16
+3 22 25 19
+3 24 22 23
+3 25 24 22
+great rhombihexahedron
+great rhombihexacron
+4/3 3/2 2|
+(4.8/3.4/3.8/5)
+octahedral group
+S4
+6{4}+3{8/3}+3{8/5}+6{4/3}
+25 24 48 18 24 0 0 1 -6 4 4 48 4 0 1
+ 0.0000000000 0.0000000000 1.0000000000
+ 0.9968739365 0.0000000000 0.0790085736
+-0.8508851285 -0.5193766874 0.0790085736
+ 0.0729944040 -0.9941978990 0.0790085736
+ 0.4556778364 0.8866314650 0.0790085736
+ 0.1459888080 -0.5193766874 -0.8419828529
+ 0.0427591319 0.8866314650 0.4604957132
+ 0.4254425643 -0.7790650311 0.4604957132
+-0.3952072921 0.3672547776 -0.8419828529
+ 0.5286722404 -0.1075664339 -0.8419828529
+-0.8811204006 -0.1075664339 0.4604957132
+ 0.8081259966 -0.3672547776 0.4604957132
+-0.8081259966 0.3672547776 -0.4604957132
+ 0.3952072921 -0.3672547776 0.8419828529
+ 0.8811204006 0.1075664339 -0.4604957132
+-0.5286722404 0.1075664339 0.8419828529
+-0.0427591319 -0.8866314650 -0.4604957132
+-0.4254425643 0.7790650311 -0.4604957132
+-0.1459888080 0.5193766874 0.8419828529
+-0.4556778364 -0.8866314650 -0.0790085736
+ 0.8508851285 0.5193766874 -0.0790085736
+-0.0729944040 0.9941978990 -0.0790085736
+-0.9968739365 0.0000000000 -0.0790085736
+ 0.0000000000 0.0000000000 -1.0000000000
+ 0.2596883437 -0.9238795325 0.2810846377
+-0.1390719130 -0.2705980501 0.2810846377
+ 0.9404146820 -0.1913417162 0.2810846377
+ 0.2596883437 0.1585126678 0.2810846377
+ 0.2059051267 -0.1913417162 0.9596829823
+ 0.2911938228 -0.2705980501 -0.1164290691
+-0.2596883437 -0.1585126678 -0.2810846377
+ 0.0537832170 -0.7325378163 -0.6785983445
+ 0.1390719130 0.2705980501 -0.2810846377
+ 0.7345095553 -0.0000000000 -0.6785983445
+-0.6807263383 -0.7325378163 -0.0000000000
+-0.7345095553 -0.0000000000 0.6785983445
+-0.2911938228 0.2705980501 0.1164290691
+ 0.6807263383 0.7325378163 -0.0000000000
+-0.0537832170 0.7325378163 0.6785983445
+-0.2059051267 0.1913417162 -0.9596829823
+-0.9404146820 0.1913417162 -0.2810846377
+-0.2596883437 0.9238795325 -0.2810846377
+4 0 2 5 1
+8 0 3 10 13 19 15 7 2 3
+4 0 4 9 3 3
+8 0 1 6 13 20 18 11 4 5
+4 1 3 10 6 3
+8 1 5 7 14 16 11 9 3 3
+8 2 8 16 22 23 19 12 5 5
+4 2 7 14 8 3
+8 4 8 14 21 23 20 17 9 3
+4 4 11 16 8
+4 5 12 15 7 3
+4 6 12 19 13
+8 6 10 17 18 22 21 15 12 3
+4 9 17 18 11
+4 10 17 20 13 3
+4 14 16 22 21
+4 15 19 23 21 3
+4 18 20 23 22
+4 3 0 1 2
+4 3 4 5 0
+4 0 6 7 1
+4 1 4 5 2
+4 2 8 9 3
+4 5 10 6 0
+4 3 11 12 4
+4 7 5 10 1
+4 6 9 8 7
+4 5 13 8 2
+4 1 14 12 4
+4 9 5 13 3
+4 10 12 11 6
+4 3 14 1 11
+4 8 15 5 7
+4 12 16 1 10
+4 6 15 5 9
+4 13 12 14 8
+4 12 17 3 13
+4 16 6 11 1
+4 17 8 14 3
+4 8 16 12 15
+4 6 17 12 15
+4 16 6 17 8
+icosahedron
+dodecahedron
+5|2 3
+(3.3.3.3.3)
+icosahedral group
+A5
+20{3}
+26 12 30 20 12 1 0 0 2 1 5 120 5 0 -1
+ 0.0000000000 0.0000000000 1.0000000000
+ 0.8944271910 0.0000000000 0.4472135955
+ 0.2763932023 0.8506508084 0.4472135955
+-0.7236067977 0.5257311121 0.4472135955
+-0.7236067977 -0.5257311121 0.4472135955
+ 0.2763932023 -0.8506508084 0.4472135955
+ 0.7236067977 0.5257311121 -0.4472135955
+ 0.7236067977 -0.5257311121 -0.4472135955
+-0.2763932023 0.8506508084 -0.4472135955
+-0.8944271910 -0.0000000000 -0.4472135955
+-0.2763932023 -0.8506508084 -0.4472135955
+ 0.0000000000 0.0000000000 -1.0000000000
+ 0.4911234732 0.3568220898 0.7946544723
+-0.1875924741 0.5773502692 0.7946544723
+-0.6070619982 -0.0000000000 0.7946544723
+-0.1875924741 -0.5773502692 0.7946544723
+ 0.4911234732 -0.3568220898 0.7946544723
+ 0.7946544723 -0.5773502692 0.1875924741
+ 0.9822469464 0.0000000000 -0.1875924741
+ 0.7946544723 0.5773502692 0.1875924741
+ 0.3035309991 0.9341723590 -0.1875924741
+-0.3035309991 0.9341723590 0.1875924741
+-0.7946544723 0.5773502692 -0.1875924741
+-0.9822469464 -0.0000000000 0.1875924741
+-0.7946544723 -0.5773502692 -0.1875924741
+-0.3035309991 -0.9341723590 0.1875924741
+ 0.3035309991 -0.9341723590 -0.1875924741
+ 0.6070619982 0.0000000000 -0.7946544723
+ 0.1875924741 0.5773502692 -0.7946544723
+ 0.1875924741 -0.5773502692 -0.7946544723
+-0.4911234732 0.3568220898 -0.7946544723
+-0.4911234732 -0.3568220898 -0.7946544723
+3 0 2 1
+3 0 3 2
+3 0 4 3
+3 0 5 4
+3 0 1 5
+3 1 7 5
+3 1 6 7
+3 1 2 6
+3 2 8 6
+3 2 3 8
+3 3 9 8
+3 3 4 9
+3 4 10 9
+3 4 5 10
+3 5 7 10
+3 6 11 7
+3 6 8 11
+3 7 11 10
+3 8 9 11
+3 9 10 11
+5 4 0 1 2 3
+5 4 5 6 7 0
+5 7 8 9 1 0
+5 9 10 11 2 1
+5 11 12 13 3 2
+5 13 14 5 4 3
+5 6 15 16 8 7
+5 14 17 15 6 5
+5 16 18 10 9 8
+5 18 19 12 11 10
+5 19 17 14 13 12
+5 15 16 18 19 17
+dodecahedron
+icosahedron
+3|2 5
+(5.5.5)
+icosahedral group
+A5
+12{5}
+27 20 30 12 20 1 0 0 2 1 3 120 5 0 -1
+ 0.0000000000 0.0000000000 1.0000000000
+ 0.6666666667 0.0000000000 0.7453559925
+-0.3333333333 0.5773502692 0.7453559925
+-0.3333333333 -0.5773502692 0.7453559925
+ 0.7453559925 0.5773502692 0.3333333333
+ 0.7453559925 -0.5773502692 0.3333333333
+-0.8726779962 0.3568220898 0.3333333333
+ 0.1273220038 0.9341723590 0.3333333333
+ 0.1273220038 -0.9341723590 0.3333333333
+-0.8726779962 -0.3568220898 0.3333333333
+ 0.8726779962 0.3568220898 -0.3333333333
+ 0.8726779962 -0.3568220898 -0.3333333333
+-0.7453559925 0.5773502692 -0.3333333333
+-0.1273220038 0.9341723590 -0.3333333333
+-0.1273220038 -0.9341723590 -0.3333333333
+-0.7453559925 -0.5773502692 -0.3333333333
+ 0.3333333333 0.5773502692 -0.7453559925
+ 0.3333333333 -0.5773502692 -0.7453559925
+-0.6666666667 0.0000000000 -0.7453559925
+ 0.0000000000 0.0000000000 -1.0000000000
+ 0.3035309991 0.5257311121 0.7946544723
+-0.6070619982 0.0000000000 0.7946544723
+ 0.3035309991 -0.5257311121 0.7946544723
+ 0.9822469464 0.0000000000 0.1875924741
+-0.4911234732 0.8506508084 0.1875924741
+-0.4911234732 -0.8506508084 0.1875924741
+ 0.4911234732 0.8506508084 -0.1875924741
+ 0.4911234732 -0.8506508084 -0.1875924741
+-0.9822469464 -0.0000000000 -0.1875924741
+ 0.6070619982 0.0000000000 -0.7946544723
+-0.3035309991 0.5257311121 -0.7946544723
+-0.3035309991 -0.5257311121 -0.7946544723
+5 0 2 7 4 1
+5 0 3 9 6 2
+5 0 1 5 8 3
+5 1 4 10 11 5
+5 2 6 12 13 7
+5 3 8 14 15 9
+5 4 7 13 16 10
+5 5 11 17 14 8
+5 6 9 15 18 12
+5 10 16 19 17 11
+5 12 18 19 16 13
+5 14 17 19 18 15
+3 2 0 1
+3 2 3 0
+3 0 4 1
+3 1 5 2
+3 3 6 0
+3 2 7 3
+3 4 8 1
+3 6 4 0
+3 5 7 2
+3 8 5 1
+3 3 9 6
+3 7 9 3
+3 4 10 8
+3 6 10 4
+3 5 11 7
+3 8 11 5
+3 9 10 6
+3 11 9 7
+3 10 11 8
+3 9 10 11
+icosidodecahedron
+rhombic triacontahedron
+2|3 5
+(3.5.3.5)
+icosahedral group
+A5
+12{5}+20{3}
+28 30 60 32 30 1 0 0 2 2 4 120 5 0 -1
+ 0.0000000000 0.0000000000 1.0000000000
+ 0.5877852523 0.0000000000 0.8090169944
+ 0.2628655561 0.5257311121 0.8090169944
+-0.5877852523 -0.0000000000 0.8090169944
+-0.2628655561 -0.5257311121 0.8090169944
+ 0.9510565163 0.0000000000 0.3090169944
+ 0.6881909602 -0.5257311121 0.5000000000
+-0.1624598481 0.8506508084 0.5000000000
+ 0.4253254042 0.8506508084 0.3090169944
+-0.9510565163 -0.0000000000 0.3090169944
+-0.6881909602 0.5257311121 0.5000000000
+ 0.1624598481 -0.8506508084 0.5000000000
+-0.4253254042 -0.8506508084 0.3090169944
+ 0.9510565163 -0.0000000000 -0.3090169944
+ 0.8506508084 0.5257311121 0.0000000000
+ 0.5257311121 -0.8506508084 0.0000000000
+-0.5257311121 0.8506508084 0.0000000000
+ 0.4253254042 0.8506508084 -0.3090169944
+-0.9510565163 -0.0000000000 -0.3090169944
+-0.8506508084 -0.5257311121 0.0000000000
+-0.4253254042 -0.8506508084 -0.3090169944
+ 0.5877852523 -0.0000000000 -0.8090169944
+ 0.6881909602 -0.5257311121 -0.5000000000
+ 0.1624598481 -0.8506508084 -0.5000000000
+-0.6881909602 0.5257311121 -0.5000000000
+-0.1624598481 0.8506508084 -0.5000000000
+ 0.2628655561 0.5257311121 -0.8090169944
+-0.5877852523 -0.0000000000 -0.8090169944
+-0.2628655561 -0.5257311121 -0.8090169944
+ 0.0000000000 0.0000000000 -1.0000000000
+ 0.2763932023 0.1708203932 0.8506508084
+-0.2763932023 0.4472135955 0.8506508084
+-0.2763932023 -0.1708203932 0.8506508084
+ 0.2763932023 -0.4472135955 0.8506508084
+ 0.7236067977 -0.1708203932 0.5257311121
+ 0.7236067977 0.4472135955 0.5257311121
+ 0.1708203932 0.7236067977 0.5257311121
+-0.7236067977 0.1708203932 0.5257311121
+-0.7236067977 -0.4472135955 0.5257311121
+-0.1708203932 -0.7236067977 0.5257311121
+ 0.8944271910 -0.4472135955 0.0000000000
+ 0.8944271910 0.1708203932 0.0000000000
+ 0.4472135955 -0.7236067977 0.3249196962
+ 0.0000000000 1.0000000000 0.0000000000
+-0.4472135955 0.7236067977 0.3249196962
+ 0.5527864045 0.7236067977 -0.0000000000
+-0.8944271910 0.4472135955 -0.0000000000
+-0.8944271910 -0.1708203932 0.0000000000
+-0.0000000000 -1.0000000000 0.0000000000
+-0.5527864045 -0.7236067977 -0.0000000000
+ 0.7236067977 -0.1708203932 -0.5257311121
+ 0.7236067977 0.4472135955 -0.5257311121
+ 0.4472135955 -0.7236067977 -0.3249196962
+-0.4472135955 0.7236067977 -0.3249196962
+ 0.1708203932 0.7236067977 -0.5257311121
+-0.7236067977 0.1708203932 -0.5257311121
+-0.7236067977 -0.4472135955 -0.5257311121
+-0.1708203932 -0.7236067977 -0.5257311121
+ 0.2763932023 -0.4472135955 -0.8506508084
+ 0.2763932023 0.1708203932 -0.8506508084
+-0.2763932023 0.4472135955 -0.8506508084
+-0.2763932023 -0.1708203932 -0.8506508084
+3 0 2 1
+5 0 3 10 7 2
+3 0 4 3
+5 0 1 6 11 4
+3 1 5 6
+5 1 2 8 14 5
+3 2 7 8
+3 3 9 10
+5 3 4 12 19 9
+3 4 11 12
+5 5 13 22 15 6
+3 5 14 13
+3 6 15 11
+5 7 16 25 17 8
+3 7 10 16
+3 8 17 14
+5 9 18 24 16 10
+3 9 19 18
+5 11 15 23 20 12
+3 12 20 19
+3 13 21 22
+5 13 14 17 26 21
+3 15 22 23
+3 16 24 25
+3 17 25 26
+3 18 27 24
+5 18 19 20 28 27
+3 20 23 28
+5 21 29 28 23 22
+3 21 26 29
+5 24 27 29 26 25
+3 27 28 29
+4 3 0 1 2
+4 3 4 5 0
+4 5 6 1 0
+4 1 7 8 2
+4 8 9 3 2
+4 4 10 11 5
+4 3 12 10 4
+4 6 13 14 1
+4 5 15 13 6
+4 7 16 17 8
+4 14 16 7 1
+4 9 18 12 3
+4 8 19 18 9
+4 10 20 21 11
+4 21 15 5 11
+4 18 22 10 12
+4 13 23 16 14
+4 21 24 13 15
+4 16 25 26 17
+4 26 19 8 17
+4 26 27 18 19
+4 20 28 29 21
+4 22 28 20 10
+4 27 28 22 18
+4 23 30 25 16
+4 24 30 23 13
+4 29 30 24 21
+4 30 31 26 25
+4 31 28 27 26
+4 28 29 30 31
+truncated icosahedron
+pentakisdodecahedron
+2 5|3
+(6.6.5)
+icosahedral group
+A5
+20{6}+12{5}
+29 60 90 32 60 1 0 0 2 2 3 120 5 0 -1
+ 0.0000000000 0.0000000000 1.0000000000
+ 0.3952480672 0.0000000000 0.9185744202
+-0.2227859215 0.3264773618 0.9185744202
+-0.1440965957 -0.3680451137 0.9185744202
+ 0.5677102129 0.3264773618 0.7557232605
+ 0.4954282110 -0.3680451137 0.7868250644
+-0.5896684388 0.2849096099 0.7557232605
+-0.0503237759 0.6529547237 0.7557232605
+ 0.1620948777 -0.5955095034 0.7868250644
+-0.5109791130 -0.4096128656 0.7557232605
+ 0.8403525023 0.2849096099 0.4611227451
+ 0.3449242913 0.6529547237 0.6742976806
+ 0.7680705005 -0.4096128656 0.4922245490
+-0.6439521587 0.5856966883 0.4922245490
+-0.7337650345 -0.0831355038 0.6742976806
+-0.3106188254 0.8131610779 0.4922245490
+ 0.1014038338 -0.8645416449 0.4922245490
+-0.5716701569 -0.6786450072 0.4611227451
+ 0.7860687824 0.5856966883 0.1976240336
+ 0.9405326461 -0.0831355038 0.3293733893
+ 0.4798773090 0.8131610779 0.3293733893
+ 0.7073794566 -0.6786450072 0.1976240336
+-0.8423324743 0.5184386529 0.1473002577
+-0.9321453501 -0.1503935392 0.3293733893
+-0.1756658076 0.9733674322 0.1473002577
+ 0.3740461233 -0.9061093968 0.1976240336
+-0.2654786835 -0.9061093968 0.3293733893
+-0.8319652063 -0.5184386529 0.1976240336
+ 0.8319652063 0.5184386529 -0.1976240336
+ 0.9864290700 -0.1503935392 -0.0658746779
+ 0.2195822596 0.9733674322 0.0658746779
+ 0.8423324743 -0.5184386529 -0.1473002577
+-0.7073794566 0.6786450072 -0.1976240336
+-0.9864290700 0.1503935392 0.0658746779
+-0.3740461233 0.9061093968 -0.1976240336
+ 0.1756658076 -0.9733674322 -0.1473002577
+-0.2195822596 -0.9733674322 -0.0658746779
+-0.7860687824 -0.5856966883 -0.1976240336
+ 0.5716701569 0.6786450072 -0.4611227451
+ 0.9321453501 0.1503935392 -0.3293733893
+ 0.2654786835 0.9061093968 -0.3293733893
+ 0.6439521587 -0.5856966883 -0.4922245490
+-0.7680705005 0.4096128656 -0.4922245490
+-0.9405326461 0.0831355038 -0.3293733893
+-0.1014038338 0.8645416449 -0.4922245490
+ 0.3106188254 -0.8131610779 -0.4922245490
+-0.4798773090 -0.8131610779 -0.3293733893
+-0.8403525023 -0.2849096099 -0.4611227451
+ 0.5109791130 0.4096128656 -0.7557232605
+ 0.7337650345 0.0831355038 -0.6742976806
+ 0.5896684388 -0.2849096099 -0.7557232605
+-0.4954282110 0.3680451137 -0.7868250644
+-0.1620948777 0.5955095034 -0.7868250644
+ 0.0503237759 -0.6529547237 -0.7557232605
+-0.3449242913 -0.6529547237 -0.6742976806
+-0.5677102129 -0.3264773618 -0.7557232605
+ 0.1440965957 0.3680451137 -0.9185744202
+ 0.2227859215 -0.3264773618 -0.9185744202
+-0.3952480672 -0.0000000000 -0.9185744202
+-0.0000000000 -0.0000000000 -1.0000000000
+ 0.1884917927 0.3568220898 0.9149583817
+-0.4009827382 -0.0454313035 0.9149583817
+ 0.1884917927 -0.2762216876 0.9149583817
+ 0.7299680182 -0.0454313035 0.6819697127
+-0.3769835855 0.5524433752 0.7082839194
+-0.2238218084 -0.6962909658 0.6819697127
+ 0.6262353286 0.5524433752 0.5016094570
+ 0.4751441987 -0.6962909658 0.5379747963
+-0.8612946448 0.2378813932 0.4489810437
+ 0.0924951818 0.8887410555 0.4489810437
+-0.7427296631 -0.3817289838 0.5016094570
+ 0.9686221187 0.2378813932 0.0719974582
+ 0.8805126380 -0.3817289838 0.1672031523
+-0.5563085176 0.8152316624 0.1609912108
+ 0.0344457437 -0.9590792530 0.1672031523
+-0.5746422389 -0.8152316624 0.0719974582
+ 0.5746422389 0.8152316624 -0.0719974582
+ 0.5563085176 -0.8152316624 -0.1609912108
+-0.8805126380 0.3817289838 -0.1672031523
+-0.9686221187 -0.2378813932 -0.0719974582
+-0.0344457437 0.9590792530 -0.1672031523
+ 0.7427296631 0.3817289838 -0.5016094570
+ 0.8612946448 -0.2378813932 -0.4489810437
+-0.4751441987 0.6962909658 -0.5379747963
+-0.0924951818 -0.8887410555 -0.4489810437
+-0.6262353286 -0.5524433752 -0.5016094570
+ 0.2238218084 0.6962909658 -0.6819697127
+ 0.3769835855 -0.5524433752 -0.7082839194
+-0.7299680182 0.0454313035 -0.6819697127
+ 0.4009827382 0.0454313035 -0.9149583817
+-0.1884917927 0.2762216876 -0.9149583817
+-0.1884917927 -0.3568220898 -0.9149583817
+6 0 2 7 11 4 1
+6 0 3 9 14 6 2
+5 0 1 5 8 3
+6 1 4 10 19 12 5
+5 2 6 13 15 7
+6 3 8 16 26 17 9
+5 4 11 20 18 10
+6 5 12 21 25 16 8
+6 6 14 23 33 22 13
+6 7 15 24 30 20 11
+5 9 17 27 23 14
+6 10 18 28 39 29 19
+5 12 19 29 31 21
+6 13 22 32 34 24 15
+5 16 25 35 36 26
+6 17 26 36 46 37 27
+6 18 20 30 40 38 28
+6 21 31 41 45 35 25
+5 22 33 43 42 32
+6 23 27 37 47 43 33
+5 24 34 44 40 30
+5 28 38 48 49 39
+6 29 39 49 50 41 31
+6 32 42 51 52 44 34
+6 35 45 53 54 46 36
+5 37 46 54 55 47
+6 38 40 44 52 56 48
+5 41 50 57 53 45
+6 42 43 47 55 58 51
+6 48 56 59 57 50 49
+5 51 58 59 56 52
+6 53 57 59 58 55 54
+3 2 0 1
+3 2 3 0
+3 0 4 1
+3 1 5 2
+3 3 6 0
+3 2 7 3
+3 4 8 1
+3 0 9 4
+3 5 7 2
+3 1 10 5
+3 3 11 6
+3 6 9 0
+3 7 12 3
+3 4 13 8
+3 8 10 1
+3 9 13 4
+3 5 14 7
+3 10 15 5
+3 11 16 6
+3 12 11 3
+3 16 9 6
+3 7 17 12
+3 13 18 8
+3 8 19 10
+3 9 20 13
+3 14 17 7
+3 15 14 5
+3 19 15 10
+3 11 21 16
+3 12 22 11
+3 16 20 9
+3 17 22 12
+3 13 23 18
+3 18 19 8
+3 20 23 13
+3 14 24 17
+3 15 24 14
+3 19 25 15
+3 21 26 16
+3 22 21 11
+3 26 20 16
+3 17 27 22
+3 23 28 18
+3 28 19 18
+3 26 23 20
+3 24 27 17
+3 25 24 15
+3 28 25 19
+3 21 29 26
+3 22 29 21
+3 27 29 22
+3 23 30 28
+3 26 30 23
+3 24 31 27
+3 25 31 24
+3 28 31 25
+3 29 30 26
+3 31 29 27
+3 30 31 28
+3 29 30 31
+truncated dodecahedron
+triakisicosahedron
+2 3|5
+(10.10.3)
+icosahedral group
+A5
+12{10}+20{3}
+30 60 90 32 60 1 0 0 2 2 3 120 5 0 -1
+ 0.0000000000 0.0000000000 1.0000000000
+ 0.3319544852 0.0000000000 0.9432954043
+-0.2860795036 0.1683814059 0.9432954043
+ 0.1611340919 -0.2902233358 0.9432954043
+ 0.5829886213 0.1683814059 0.7948408455
+-0.5878317720 0.1506049079 0.7948408455
+-0.4170113787 0.4408282437 0.7948408455
+ 0.1357750258 -0.5914331516 0.7948408455
+ 0.8183499926 0.1506049079 0.5546363234
+ 0.6572159007 0.4408282437 0.6113409191
+-0.7899976948 -0.0465394760 0.6113409191
+-0.3427840993 0.7132750815 0.6113409191
+-0.0663908970 -0.7885775354 0.6113409191
+ 0.2655635881 -0.7885775354 0.5546363234
+ 0.9481385550 -0.0465394760 0.3144318014
+ 0.5262840256 0.7132750815 0.4628863603
+-0.8153567609 -0.3477492917 0.4628863603
+-0.9462886360 -0.0753024539 0.3144318014
+-0.3935022315 0.8638799894 0.3144318014
+-0.0917499632 0.8816564874 0.4628863603
+-0.3681431654 -0.8063540334 0.4628863603
+ 0.5009249595 -0.8063540334 0.3144318014
+ 0.9227794888 -0.3477492917 0.1659772426
+ 0.9970067683 -0.0753024539 -0.0175226837
+ 0.4755658933 0.8638799894 0.1659772426
+ 0.2402045220 0.8816564874 0.4061817646
+-0.6542226690 -0.6379726275 0.4061817646
+-0.9970067683 0.0753024539 0.0175226837
+-0.5497931728 0.8351170114 0.0175226837
+-0.5244341067 -0.8351170114 0.1659772426
+ 0.5497931728 -0.8351170114 -0.0175226837
+ 0.7519590956 -0.6379726275 0.1659772426
+ 0.9462886360 0.0753024539 -0.3144318014
+ 0.5244341067 0.8351170114 -0.1659772426
+-0.9481385550 0.0465394760 -0.3144318014
+-0.9227794888 0.3477492917 -0.1659772426
+-0.7519590956 0.6379726275 -0.1659772426
+-0.5009249595 0.8063540334 -0.3144318014
+-0.4755658933 -0.8638799894 -0.1659772426
+ 0.3935022315 -0.8638799894 -0.3144318014
+ 0.7899976948 0.0465394760 -0.6113409191
+ 0.8153567609 0.3477492917 -0.4628863603
+ 0.6542226690 0.6379726275 -0.4061817646
+ 0.3681431654 0.8063540334 -0.4628863603
+-0.8183499926 -0.1506049079 -0.5546363234
+-0.2655635881 0.7885775354 -0.5546363234
+-0.5262840256 -0.7132750815 -0.4628863603
+-0.2402045220 -0.8816564874 -0.4061817646
+ 0.0917499632 -0.8816564874 -0.4628863603
+ 0.3427840993 -0.7132750815 -0.6113409191
+ 0.5878317720 -0.1506049079 -0.7948408455
+ 0.0663908970 0.7885775354 -0.6113409191
+-0.6572159007 -0.4408282437 -0.6113409191
+-0.5829886213 -0.1683814059 -0.7948408455
+-0.1357750258 0.5914331516 -0.7948408455
+ 0.4170113787 -0.4408282437 -0.7948408455
+ 0.2860795036 -0.1683814059 -0.9432954043
+-0.3319544852 0.0000000000 -0.9432954043
+-0.1611340919 0.2902233358 -0.9432954043
+-0.0000000000 0.0000000000 -1.0000000000
+ 0.1432337790 0.5257311121 0.8385051474
+-0.3901124942 -0.3804226065 0.8385051474
+ 0.1432337790 -0.0843049040 0.8385051474
+ 0.6463368675 -0.3804226065 0.6614584599
+-0.3749909018 0.2207131041 0.7357864254
+ 0.5979747984 0.2207131041 0.5695840419
+-0.7989163046 0.4702282018 0.3749909018
+ 0.0972965700 -0.6299377043 0.5695840419
+ 0.8780939903 0.4702282018 0.0885233438
+-0.7412085774 -0.1364082001 0.4033816583
+-0.2405303491 0.7142426083 0.4033816583
+ 0.0151215924 -0.9959593140 0.0885233438
+ 0.8330829954 -0.1364082001 0.1344605528
+ 0.3607955236 0.7142426083 0.3006629363
+-0.8780939903 -0.4702282018 -0.0885233438
+-0.0151215924 0.9959593140 -0.0885233438
+-0.4493188674 -0.6621393122 0.3006629363
+ 0.5236468329 -0.6621393122 0.1344605528
+ 0.7989163046 -0.4702282018 -0.3749909018
+-0.8330829954 0.1364082001 -0.1344605528
+-0.5236468329 0.6621393122 -0.1344605528
+ 0.7412085774 0.1364082001 -0.4033816583
+ 0.4493188674 0.6621393122 -0.3006629363
+-0.6463368675 0.3804226065 -0.6614584599
+-0.3607955236 -0.7142426083 -0.3006629363
+ 0.2405303491 -0.7142426083 -0.4033816583
+ 0.3901124942 0.3804226065 -0.8385051474
+-0.5979747984 -0.2207131041 -0.5695840419
+-0.0972965700 0.6299377043 -0.5695840419
+-0.1432337790 -0.5257311121 -0.8385051474
+ 0.3749909018 -0.2207131041 -0.7357864254
+-0.1432337790 0.0843049040 -0.8385051475
+10 0 2 6 11 19 25 15 9 4 1
+10 0 3 7 12 20 26 16 10 5 2
+3 0 1 3
+10 1 4 8 14 22 31 21 13 7 3
+3 2 5 6
+3 4 9 8
+10 5 10 17 27 35 36 28 18 11 6
+3 7 13 12
+10 8 9 15 24 33 42 41 32 23 14
+3 10 16 17
+3 11 18 19
+10 12 13 21 30 39 48 47 38 29 20
+3 14 23 22
+3 15 25 24
+10 16 26 29 38 46 52 44 34 27 17
+10 18 28 37 45 51 43 33 24 25 19
+3 20 29 26
+3 21 31 30
+10 22 23 32 40 50 55 49 39 30 31
+3 27 34 35
+3 28 36 37
+3 32 41 40
+3 33 43 42
+10 34 44 53 57 58 54 45 37 36 35
+3 38 47 46
+3 39 49 48
+10 40 41 42 43 51 54 58 59 56 50
+3 44 52 53
+3 45 54 51
+10 46 47 48 49 55 56 59 57 53 52
+3 50 56 55
+3 57 59 58
+3 2 0 1
+3 2 3 0
+3 0 4 1
+3 1 3 2
+3 3 5 0
+3 4 6 1
+3 0 6 4
+3 1 7 3
+3 3 8 5
+3 8 0 5
+3 6 9 1
+3 0 10 6
+3 1 11 7
+3 11 3 7
+3 3 12 8
+3 8 13 0
+3 9 14 1
+3 6 14 9
+3 10 15 6
+3 0 15 10
+3 1 16 11
+3 11 17 3
+3 3 18 12
+3 18 8 12
+3 8 15 13
+3 13 0 15
+3 14 16 1
+3 6 19 14
+3 15 20 6
+3 14 11 16
+3 11 18 17
+3 17 3 18
+3 18 21 8
+3 8 22 15
+3 19 23 14
+3 6 23 19
+3 20 23 6
+3 15 23 20
+3 14 24 11
+3 11 25 18
+3 18 26 21
+3 26 8 21
+3 26 22 8
+3 26 15 22
+3 23 27 14
+3 15 28 23
+3 14 29 24
+3 29 11 24
+3 29 25 11
+3 29 18 25
+3 18 30 26
+3 26 28 15
+3 27 29 14
+3 23 29 27
+3 26 23 28
+3 29 30 18
+3 29 26 30
+3 23 31 29
+3 26 31 23
+3 29 26 31
+rhombicosidodecahedron
+deltoidal hexecontahedron
+3 5|2
+(4.3.4.5)
+icosahedral group
+A5
+12{5}+30{4}+20{3}
+31 60 120 62 60 1 0 0 2 3 4 120 5 0 -1
+ 0.0000000000 0.0000000000 1.0000000000
+ 0.4364663517 0.0000000000 0.8997205810
+-0.0230394894 0.4358578416 0.8997205810
+-0.3947875239 0.1861335198 0.8997205810
+-0.1650346033 -0.4040624406 0.8997205810
+ 0.4134268623 0.4358578416 0.7994411620
+ 0.7478962199 0.1861335198 0.6371856536
+ 0.5411827887 -0.4040624406 0.7374650726
+-0.2253527696 0.7370282030 0.6371856536
+-0.5598221272 -0.2179289208 0.7994411620
+-0.5971008041 0.4873038812 0.6371856536
+ 0.1694347542 -0.6537867624 0.7374650726
+-0.4551056902 -0.6219913614 0.6371856536
+ 0.4808646224 0.7370282030 0.4749301452
+ 0.8526126568 -0.2179289208 0.4749301452
+ 0.8153339799 0.4873038812 0.3126746369
+ 0.6875780535 -0.6219913614 0.3746507262
+ 0.0860770985 0.9231617228 0.3746507262
+-0.5296630440 0.7884742426 0.3126746369
+-0.8641324015 -0.1664828812 0.4749301452
+-0.8871718909 0.2693749604 0.3746507262
+-0.1206363326 -0.8717156832 0.4749301452
+ 0.3158300191 -0.8717156832 0.3746507262
+-0.7594159645 -0.5705453218 0.3126746369
+ 0.6130206997 0.7884742426 0.0501397095
+ 0.9847687342 -0.1664828812 0.0501397095
+ 0.9617292448 0.2693749604 -0.0501397095
+ 0.8197341309 -0.5705453218 -0.0501397095
+-0.2182331759 0.9746077624 0.0501397095
+ 0.2182331759 0.9746077624 -0.0501397095
+-0.8197341309 0.5705453218 0.0501397095
+-0.9617292448 -0.2693749604 0.0501397095
+-0.9847687342 0.1664828812 -0.0501397095
+-0.2182331759 -0.9746077624 0.0501397095
+ 0.2182331759 -0.9746077624 -0.0501397095
+-0.6130206997 -0.7884742426 -0.0501397095
+ 0.7594159645 0.5705453218 -0.3126746369
+ 0.8871718909 -0.2693749604 -0.3746507262
+ 0.8641324015 0.1664828812 -0.4749301452
+ 0.5296630440 -0.7884742426 -0.3126746369
+-0.3158300191 0.8717156832 -0.3746507262
+ 0.1206363326 0.8717156832 -0.4749301452
+-0.6875780535 0.6219913614 -0.3746507262
+-0.8153339799 -0.4873038812 -0.3126746369
+-0.8526126568 0.2179289208 -0.4749301452
+-0.0860770985 -0.9231617228 -0.3746507262
+-0.4808646224 -0.7370282030 -0.4749301452
+ 0.4551056902 0.6219913614 -0.6371856536
+ 0.5971008041 -0.4873038812 -0.6371856536
+ 0.5598221272 0.2179289208 -0.7994411620
+ 0.2253527696 -0.7370282030 -0.6371856536
+-0.1694347542 0.6537867624 -0.7374650726
+-0.5411827887 0.4040624406 -0.7374650726
+-0.7478962199 -0.1861335198 -0.6371856536
+-0.4134268623 -0.4358578416 -0.7994411620
+ 0.1650346033 0.4040624406 -0.8997205810
+ 0.3947875239 -0.1861335198 -0.8997205810
+ 0.0230394894 -0.4358578416 -0.8997205810
+-0.4364663517 -0.0000000000 -0.8997205810
+-0.0000000000 -0.0000000000 -1.0000000000
+ 0.2124281962 0.2239537475 0.9245941063
+-0.1379991118 0.2054301247 0.9245941063
+-0.2876494382 -0.1119768737 0.9245941063
+ 0.2124281962 -0.3162277660 0.9245941063
+ 0.6623583361 -0.1119768737 0.7063270456
+ 0.5277148574 0.2054301247 0.7716443776
+ 0.1583346290 0.7071067812 0.6891517578
+-0.3186422944 0.4743416490 0.7896976442
+-0.7144788670 0.1207882584 0.6891517578
+-0.3897157456 -0.4108602493 0.7716443776
+-0.1467842735 -0.6555240367 0.7063270456
+ 0.6313654799 0.4743416490 0.5714305835
+ 0.9436228948 0.1207882584 0.3081980354
+ 0.4403528206 -0.6555240367 0.5714305835
+ 0.6874320834 -0.4108602493 0.5241665181
+-0.2279246243 0.8794777841 0.3531635228
+-0.4465745066 0.6647858481 0.5241665181
+-0.6778547641 -0.4051361351 0.5714305835
+-0.7280022588 0.5435471629 0.3531635228
+ 0.1204287884 -0.7917486474 0.5241665181
+-0.4686190076 -0.8278950396 0.3081980354
+ 0.6305733224 0.6647858481 0.2766886585
+ 0.3592124698 0.8794777841 0.2182670607
+ 0.8592901042 -0.4051361351 0.2182670607
+ 0.8091426096 0.5435471629 -0.0000000000
+ 0.5561442379 -0.8278950396 0.0727556869
+ 0.0284293805 0.9486832981 0.1237389298
+-0.5561442379 0.8278950396 -0.0727556869
+-0.9500077743 0.0000000000 0.2182670607
+-0.8538605757 -0.3323929240 0.2766886585
+-0.8890012226 0.3323929240 0.1237389298
+ 0.0501474947 -0.9486832981 0.2182670607
+-0.8091426096 -0.5435471629 -0.0000000000
+ 0.4686190076 0.8278950396 -0.3081980354
+ 0.8890012226 -0.3323929240 -0.1237389298
+ 0.9500077743 0.0000000000 -0.2182670607
+ 0.8538605757 0.3323929240 -0.2766886585
+ 0.7280022588 -0.5435471629 -0.3531635228
+-0.0501474947 0.9486832981 -0.2182670607
+-0.8592901042 0.4051361351 -0.2182670607
+-0.9436228948 -0.1207882584 -0.3081980354
+-0.3592124698 -0.8794777841 -0.2182670607
+-0.0284293805 -0.9486832981 -0.1237389298
+ 0.2279246243 -0.8794777841 -0.3531635228
+-0.6305733224 -0.6647858481 -0.2766886585
+ 0.6778547641 0.4051361351 -0.5714305835
+ 0.7144788670 -0.1207882584 -0.6891517578
+ 0.4465745066 -0.6647858481 -0.5241665181
+-0.1204287884 0.7917486474 -0.5241665181
+-0.4403528206 0.6555240367 -0.5714305835
+ 0.1467842735 0.6555240367 -0.7063270456
+-0.6874320834 0.4108602493 -0.5241665181
+-0.6313654799 -0.4743416490 -0.5714305835
+-0.6623583361 0.1119768737 -0.7063270456
+-0.1583346290 -0.7071067812 -0.6891517578
+ 0.3897157456 0.4108602493 -0.7716443776
+ 0.3186422944 -0.4743416490 -0.7896976442
+ 0.2876494382 0.1119768737 -0.9245941063
+-0.2124281962 0.3162277660 -0.9245941063
+-0.5277148574 -0.2054301247 -0.7716443776
+-0.2124281962 -0.2239537475 -0.9245941063
+ 0.1379991118 -0.2054301247 -0.9245941063
+4 0 2 5 1
+3 0 3 2
+4 0 4 9 3
+5 0 1 7 11 4
+4 1 6 14 7
+3 1 5 6
+5 2 8 17 13 5
+4 2 3 10 8
+5 3 9 19 20 10
+3 4 12 9
+4 4 11 21 12
+4 5 13 15 6
+5 6 15 26 25 14
+4 7 16 22 11
+3 7 14 16
+4 8 18 28 17
+3 8 10 18
+4 9 12 23 19
+4 10 20 30 18
+3 11 22 21
+5 12 21 33 35 23
+3 13 24 15
+4 13 17 29 24
+4 14 25 27 16
+4 15 24 36 26
+5 16 27 39 34 22
+3 17 28 29
+5 18 30 42 40 28
+4 19 31 32 20
+3 19 23 31
+3 20 32 30
+4 21 22 34 33
+4 23 35 43 31
+5 24 29 41 47 36
+3 25 37 27
+4 25 26 38 37
+3 26 36 38
+4 27 37 48 39
+4 28 40 41 29
+4 30 32 44 42
+5 31 43 53 44 32
+4 33 45 46 35
+3 33 34 45
+4 34 39 50 45
+3 35 46 43
+4 36 47 49 38
+5 37 38 49 56 48
+3 39 48 50
+3 40 51 41
+4 40 42 52 51
+4 41 51 55 47
+3 42 44 52
+4 43 46 54 53
+4 44 53 58 52
+5 45 50 57 54 46
+3 47 55 49
+4 48 56 57 50
+4 49 55 59 56
+5 51 52 58 59 55
+3 53 54 58
+4 54 57 59 58
+3 56 59 57
+4 3 0 1 2
+4 3 4 5 0
+4 0 6 7 1
+4 7 8 2 1
+4 2 9 10 3
+4 5 11 6 0
+4 4 12 11 5
+4 3 13 14 4
+4 6 15 16 7
+4 8 17 9 2
+4 16 18 8 7
+4 10 19 13 3
+4 17 20 10 9
+4 11 21 22 6
+4 14 23 12 4
+4 12 24 21 11
+4 13 25 23 14
+4 22 26 15 6
+4 15 27 18 16
+4 8 28 29 17
+4 18 30 28 8
+4 20 31 19 10
+4 31 25 13 19
+4 29 32 20 17
+4 24 33 22 21
+4 23 34 35 12
+4 35 36 24 12
+4 25 37 34 23
+4 26 38 27 15
+4 33 38 26 22
+4 27 39 30 18
+4 28 40 32 29
+4 39 40 28 30
+4 20 41 42 31
+4 42 43 25 31
+4 32 44 41 20
+4 36 45 33 24
+4 37 46 35 34
+4 46 45 36 35
+4 43 47 37 25
+4 38 48 49 27
+4 33 50 48 38
+4 49 51 39 27
+4 40 52 44 32
+4 51 53 40 39
+4 41 54 43 42
+4 52 54 41 44
+4 45 55 50 33
+4 47 56 46 37
+4 46 57 55 45
+4 54 56 47 43
+4 50 58 49 48
+4 58 53 51 49
+4 53 59 52 40
+4 59 60 54 52
+4 57 58 50 55
+4 56 61 57 46
+4 60 61 56 54
+4 58 60 59 53
+4 57 58 60 61
+truncated icosidodecahedron
+disdyakistriacontahedron
+2 3 5|
+(4.6.10)
+icosahedral group
+A5
+12{10}+20{6}+30{4}
+32 120 180 62 120 1 0 0 2 3 3 120 5 0 -1
+ 0.0000000000 0.0000000000 1.0000000000
+ 0.2607080006 0.0000000000 0.9654177015
+-0.0045873783 0.2606676380 0.9654177015
+-0.2192156342 -0.1411140222 0.9654177015
+ 0.2561208549 0.2606676380 0.9308353722
+ 0.4633267724 -0.1411140222 0.8748800687
+-0.2283903908 0.3802212538 0.8962531046
+-0.3132059807 -0.3694413065 0.8748800687
+-0.4430186467 -0.0215604065 0.8962531046
+ 0.4541524811 0.3802212538 0.8057154101
+ 0.5304628314 -0.3694413065 0.7629694001
+ 0.6613583986 -0.0215604065 0.7497601066
+-0.3298032754 0.5736633003 0.7497601066
+-0.4476060250 0.2391072316 0.8616708061
+-0.5370090771 -0.2498878945 0.8057153910
+-0.2460699217 -0.5977685908 0.7629694001
+ 0.5138663784 0.5736633003 0.6378493263
+ 0.6567712529 0.2391072316 0.7151777773
+ 0.7284945175 -0.2498878945 0.6378493381
+ 0.4364724850 -0.5977685908 0.6724317673
+-0.5490190001 0.4325494506 0.7151776775
+-0.2700897570 0.7671054904 0.5818940537
+-0.6936761144 -0.3586617667 0.6246400447
+-0.0434511498 -0.7388826131 0.6724317673
+-0.4027369590 -0.7065424630 0.5818940537
+ 0.7164852035 0.4325494506 0.5473115438
+ 0.4124538677 0.7671054904 0.4913562594
+ 0.8325358571 -0.3586617667 0.4221916434
+ 0.2172568508 -0.7388826131 0.6378494688
+ 0.5405138246 -0.7065424630 0.4567740725
+-0.7085212064 0.4848777911 0.5127291954
+-0.0720583700 0.8866594825 0.4567740725
+-0.4295919633 0.8194338309 0.3794455716
+-0.8531785590 -0.3063341981 0.4221915508
+-0.6265400554 -0.5869890510 0.5127293760
+-0.2001180064 -0.8476566112 0.4913563402
+ 0.8176915179 0.4848777911 0.3102806942
+ 0.1886510811 0.8866594825 0.4221915817
+ 0.5136601821 0.8194338309 0.2543254098
+ 0.9337423985 -0.3063341981 0.1851607203
+ 0.7385455107 -0.5869890510 0.3316540106
+ 0.3212979948 -0.8476566112 0.4221917432
+-0.8651885085 0.3761046523 0.3316536375
+-0.6488076880 0.6783199813 0.3448631425
+-0.2315603996 0.9389879297 0.2543254788
+-0.7860426423 -0.5346614357 0.3102807015
+-0.9545918983 -0.1128925413 0.2756983531
+-0.0960768624 -0.9564306093 0.2756986145
+ 0.9217330580 0.3761046523 0.0946227263
+ 0.7162790072 0.6783199813 0.1637876273
+ 0.2898571959 0.9389879297 0.1851606704
+ 0.8397521423 -0.5346614357 0.0946228761
+ 0.9934566827 -0.1128925413 0.0172943252
+ 0.1646311382 -0.9564306093 0.2411163161
+-0.8054751299 0.5695467454 0.1637874231
+-0.9591793219 0.1477776761 0.2411157125
+-0.1303544328 0.9913166095 0.0172945558
+-0.8203200648 -0.5695470165 0.0518766546
+-0.9888693637 -0.1477781439 0.0172916663
+-0.1303536668 -0.9913167102 0.0172945558
+ 0.8203206401 0.5695467454 -0.0518705331
+ 0.9888694917 0.1477776761 -0.0172883463
+ 0.1303553059 0.9913166095 -0.0172879732
+ 0.8054761704 -0.5695470165 -0.1637813633
+ 0.9591800640 -0.1477781439 -0.2411124739
+ 0.1303545664 -0.9913167102 -0.0172877735
+-0.8397525647 0.5346618623 -0.0946167165
+-0.9934567883 0.1128921245 -0.0172909812
+-0.1646312678 0.9564322465 -0.2411097335
+-0.7162795951 -0.6783208443 -0.1637814823
+-0.9217334041 -0.3761053597 -0.0946165431
+-0.2898558028 -0.9389895580 -0.1851545936
+ 0.7860446559 0.5346618623 -0.3102748651
+ 0.9545928720 0.1128921245 -0.2756951522
+ 0.0960787036 0.9564322465 -0.2756922934
+ 0.6488098576 -0.6783208443 -0.3448573632
+ 0.8651904546 -0.3761053597 -0.3316477584
+ 0.2315606390 -0.9389895580 -0.2543192490
+-0.7385472639 0.5869902473 -0.3316479890
+-0.9337433781 0.3063348862 -0.1851546415
+-0.3212992842 0.8476584134 -0.4221871436
+-0.8176928415 -0.4848792845 -0.3102748723
+-0.5136611563 -0.8194350139 -0.2543196306
+-0.1886494644 -0.8866613987 -0.4221882798
+ 0.6265433179 0.5869902473 -0.5127240198
+ 0.8531810896 0.3063348862 -0.4221859376
+ 0.2001204504 0.8476584134 -0.4913522358
+ 0.7085240020 -0.4848792845 -0.5127239199
+ 0.4295944105 -0.8194350139 -0.3794402462
+ 0.0720576700 -0.8866613987 -0.4567704634
+-0.8325379870 0.3586633178 -0.4221861255
+-0.5405162125 0.7065442357 -0.4567685048
+-0.2172590958 0.7388844270 -0.6378466030
+-0.7164876491 -0.4325518944 -0.5473064108
+-0.4124548660 -0.7671068289 -0.4913533317
+ 0.6936796092 0.3586633178 -0.6246352729
+ 0.4027407159 0.7065442357 -0.5818893011
+ 0.0434540643 0.7388844270 -0.6724295858
+ 0.5490226993 -0.4325518944 -0.7151733596
+ 0.2700914841 -0.7671068289 -0.5818914876
+-0.7284976588 0.2498903768 -0.6378447779
+-0.4364761587 0.5977701626 -0.6724279854
+-0.6567747682 -0.2391103983 -0.7151734903
+-0.5138692103 -0.5736660641 -0.6378445591
+ 0.5370132986 0.2498903768 -0.8057118075
+ 0.2460744543 0.5977701626 -0.7629667067
+ 0.4476105365 -0.2391103983 -0.8616675839
+ 0.3298072522 -0.5736660641 -0.7497562426
+-0.6613622562 0.0215634725 -0.7497566156
+-0.5304666075 0.3694443652 -0.7629652937
+-0.4541562762 -0.3802243954 -0.8057117884
+ 0.4430232811 0.0215634725 -0.8962507401
+ 0.3132106967 0.3694443652 -0.8748770888
+ 0.2283949989 -0.3802243954 -0.8962505976
+-0.4633311450 0.1411172572 -0.8748772313
+-0.2561255056 -0.2606708670 -0.9308331883
+ 0.2192205953 0.1411172572 -0.9654161022
+ 0.0045924376 -0.2606708671 -0.9654168058
+-0.2607129987 0.0000032913 -0.9654163518
+ 0.0000051772 0.0000032913 -1.0000000002
+ 0.1200387571 0.1221698550 0.9049446030
+-0.2175780247 0.1162282816 0.9049446030
+ 0.1200387571 -0.4082474279 0.9049446030
+ 0.4459799746 0.1162282816 0.8169252068
+ 0.1016985225 0.6339220449 0.7666817889
+-0.3544276914 -0.1832548434 0.8300952867
+ 0.5585832497 -0.1832548434 0.7089865490
+-0.3643565320 0.3809295903 0.7552459704
+-0.4568036952 -0.4649138222 0.6745068322
+-0.7747432361 0.0697368203 0.6284189748
+ 0.5486549126 0.3809295903 0.6341371659
+ 0.6168557011 -0.4649138222 0.5320884576
+ 0.9117846887 0.0697368203 0.4047050422
+-0.4756956529 0.6085799433 0.5320883790
+-0.2091195905 -0.6774423865 0.5878778112
+ 0.5979647013 0.6085799433 0.3896698773
+ 0.3551522032 -0.6774423865 0.5130284950
+-0.2351136470 0.7996124516 0.3919196492
+-0.6935150612 -0.4186830921 0.4381790039
+ 0.0589047087 -0.8240793946 0.4440690614
+-0.5063278658 -0.8431340489 0.1809911096
+ 0.3291594648 0.7996124516 0.3170701581
+ 0.7837684883 -0.4186830921 0.2422208418
+ 0.5360037147 -0.8431340489 0.0427282955
+-0.7095802914 0.4941881267 0.3170700500
+ 0.0283375922 0.9128709077 0.2136305953
+-0.5360037809 0.8431342740 -0.0427230226
+-0.8627717620 -0.3317288924 0.1592318224
+ 0.7677040727 0.4941881267 0.1211117799
+ 0.5063293044 0.8431342740 -0.1809860363
+ 0.8744481415 -0.3317288924 -0.0712062810
+-0.8744476717 0.3317288831 0.0712120936
+-0.9130127824 -0.0000002089 0.1211105323
+ 0.0160652247 -0.9128709077 0.1211120373
+ 0.8627728239 0.3317288831 -0.1592260883
+ 0.9130131866 -0.0000002089 -0.1211074853
+-0.0160644264 0.9128718312 -0.1211060185
+-0.7677045094 -0.4941888273 -0.1211061534
+-0.9117856757 -0.0697383469 -0.4047106460
+-0.0283368549 -0.9128720729 -0.2136250368
+ 0.7095821798 -0.4941888273 -0.3170647319
+ 0.7747427279 -0.0697383469 -0.6284246421
+-0.7837697662 0.4186839017 -0.2422153076
+-0.0589041897 0.8240821079 -0.4440651491
+-0.5979663637 -0.6085817063 -0.3896645730
+-0.3291594183 -0.7996144008 -0.3170661961
+ 0.6935177376 0.4186839017 -0.4381739941
+ 0.4756986407 -0.6085817062 -0.5320836915
+ 0.2351146351 -0.7996144008 -0.3919158120
+-0.6168583888 0.4649158905 -0.5320835344
+-0.3551545140 0.6774441676 -0.5130247732
+-0.1016986410 -0.6339226751 -0.7666826828
+ 0.4568075735 0.4649158905 -0.6745027800
+ 0.2091227917 0.6774441676 -0.5878748206
+-0.1200394925 0.4082445693 -0.9049501464
+-0.5486577777 -0.3809323480 -0.6341330304
+ 0.3643603763 -0.3809323480 -0.7552427249
+-0.5585867166 0.1832576685 -0.7089830873
+-0.4459830958 -0.1162285368 -0.8169244453
+ 0.3544319410 0.1832576685 -0.8300928485
+ 0.2175812366 -0.1162285368 -0.9049446814
+-0.1200388933 -0.1221699931 -0.9049456264
+4 0 2 4 1
+6 0 3 8 13 6 2
+10 0 1 5 10 19 28 23 15 7 3
+6 1 4 9 17 11 5
+10 2 6 12 21 31 37 26 16 9 4
+4 3 7 14 8
+4 5 11 18 10
+4 6 13 20 12
+6 7 15 24 34 22 14
+10 8 14 22 33 46 55 42 30 20 13
+4 9 16 25 17
+6 10 18 27 40 29 19
+10 11 17 25 36 48 61 52 39 27 18
+6 12 20 30 43 32 21
+4 15 23 35 24
+6 16 26 38 49 36 25
+4 19 29 41 28
+4 21 32 44 31
+4 22 34 45 33
+6 23 28 41 53 47 35
+10 24 35 47 59 71 82 69 57 45 34
+4 26 37 50 38
+4 27 39 51 40
+10 29 40 51 63 75 88 77 65 53 41
+4 30 42 54 43
+6 31 44 56 62 50 37
+10 32 43 54 66 78 91 80 68 56 44
+6 33 45 57 70 58 46
+4 36 49 60 48
+10 38 50 62 74 86 96 84 72 60 49
+6 39 52 64 76 63 51
+6 42 55 67 79 66 54
+4 46 58 67 55
+4 47 53 65 59
+6 48 60 72 85 73 61
+4 52 61 73 64
+4 56 68 74 62
+4 57 69 81 70
+10 58 70 81 93 102 108 100 90 79 67
+6 59 65 77 89 83 71
+4 63 76 87 75
+10 64 73 85 95 104 111 106 98 87 76
+4 66 79 90 78
+6 68 80 92 97 86 74
+6 69 82 94 103 93 81
+4 71 83 94 82
+4 72 84 95 85
+6 75 87 98 107 99 88
+4 77 88 99 89
+6 78 90 100 109 101 91
+4 80 91 101 92
+10 83 89 99 107 113 117 115 110 103 94
+6 84 96 105 112 104 95
+4 86 97 105 96
+10 92 101 109 114 118 119 116 112 105 97
+4 93 103 110 102
+4 98 106 113 107
+4 100 108 114 109
+6 102 110 115 118 114 108
+4 104 112 116 111
+6 106 111 116 119 117 113
+4 115 117 119 118
+3 2 0 1
+3 2 3 0
+3 0 4 1
+3 1 5 2
+3 3 4 0
+3 2 6 3
+3 4 7 1
+3 5 8 2
+3 1 9 5
+3 3 10 4
+3 2 11 6
+3 6 12 3
+3 4 13 7
+3 7 9 1
+3 9 8 5
+3 8 14 2
+3 10 15 4
+3 12 10 3
+3 11 12 6
+3 2 16 11
+3 13 9 7
+3 4 17 13
+3 9 18 8
+3 14 19 2
+3 8 20 14
+3 12 15 10
+3 15 21 4
+3 11 22 12
+3 19 16 2
+3 16 23 11
+3 13 24 9
+3 4 25 17
+3 17 26 13
+3 9 27 18
+3 18 20 8
+3 20 19 14
+3 12 28 15
+3 21 25 4
+3 15 29 21
+3 22 30 12
+3 23 22 11
+3 19 23 16
+3 24 31 9
+3 26 24 13
+3 25 26 17
+3 27 20 18
+3 9 32 27
+3 20 33 19
+3 12 34 28
+3 28 29 15
+3 29 25 21
+3 23 30 22
+3 30 35 12
+3 33 23 19
+3 26 31 24
+3 31 32 9
+3 25 36 26
+3 27 37 20
+3 32 38 27
+3 20 39 33
+3 34 29 28
+3 35 34 12
+3 29 36 25
+3 23 40 30
+3 30 41 35
+3 39 23 33
+3 26 42 31
+3 31 38 32
+3 36 43 26
+3 37 44 20
+3 38 37 27
+3 20 45 39
+3 34 46 29
+3 41 34 35
+3 29 43 36
+3 23 47 40
+3 40 41 30
+3 39 48 23
+3 26 49 42
+3 42 38 31
+3 43 50 26
+3 38 44 37
+3 44 45 20
+3 45 51 39
+3 46 52 29
+3 41 46 34
+3 29 53 43
+3 47 41 40
+3 48 47 23
+3 51 48 39
+3 49 38 42
+3 50 49 26
+3 43 54 50
+3 38 55 44
+3 44 51 45
+3 41 52 46
+3 52 53 29
+3 53 54 43
+3 47 56 41
+3 51 47 48
+3 49 57 38
+3 54 49 50
+3 38 58 55
+3 55 51 44
+3 41 59 52
+3 52 54 53
+3 56 60 41
+3 51 56 47
+3 57 58 38
+3 54 57 49
+3 58 51 55
+3 60 59 41
+3 59 54 52
+3 51 60 56
+3 54 58 57
+3 58 61 51
+3 60 54 59
+3 61 60 51
+3 54 61 58
+3 60 54 61
+snub dodecahedron
+pentagonal hexecontahedron
+|2 3 5
+(3.3.3.3.5)
+icosahedral group
+A5
+12{5}+80{3}
+33 60 150 92 60 1 0 0 2 2 5 120 5 0 -1
+ 0.0000000000 0.0000000000 1.0000000000
+ 0.4512088258 0.0000000000 0.8924183971
+ 0.2127790861 0.3978875029 0.8924183971
+-0.2505259628 0.3752680994 0.8924183971
+-0.4490629634 -0.0439529224 0.8924183971
+-0.1730083366 -0.4167223535 0.8924183971
+ 0.5570628795 -0.4167223535 0.7183477071
+ 0.8034191070 -0.0439529224 0.5937894232
+ 0.6262410352 0.3752680994 0.6833710701
+ 0.3401140582 0.7292026799 0.5937894232
+-0.4095292581 0.6926037162 0.5937894232
+-0.6598181766 0.3124803264 0.6833710701
+-0.5867073299 -0.4344864666 0.6833710701
+-0.2674638242 -0.7588657481 0.5937894232
+ 0.1712754568 -0.6742709318 0.7183477071
+ 0.5066126656 -0.7588657481 0.4092265672
+ 0.8319314730 -0.4344864666 0.3451253896
+ 0.9853200794 -0.0345183587 0.1671909808
+ 0.6986399371 0.6437955034 0.3121371303
+ 0.3534611035 0.9196768661 0.1710546996
+-0.0444936500 0.9113473168 0.4092265672
+-0.4413672010 0.8808718883 0.1710546996
+-0.7580304168 0.5726781810 0.3121371303
+-0.9277164283 0.1422346447 0.3451253896
+-0.8825314401 -0.3194162218 0.3451253896
+-0.6326042630 -0.7087892905 0.3121371303
+ 0.0822881568 -0.9349423109 0.3451253896
+ 0.3841470954 -0.9232462719 -0.0068797092
+ 0.9105239830 -0.3983895691 -0.1105975932
+ 0.9561362417 0.0261888093 -0.2917492648
+ 0.9205629910 0.3905335442 -0.0068797092
+ 0.6521763631 0.7453882542 -0.1380664403
+-0.0487110154 0.9977300839 -0.0464964156
+-0.4177242369 0.8604584989 -0.2917492648
+-0.9300960831 0.3617906055 -0.0634730968
+-0.9941677927 -0.0973061317 -0.0464964156
+-0.8422948163 -0.5352668572 -0.0634730968
+-0.5085214838 -0.8539169004 -0.1105975932
+-0.0666936701 -0.9936871537 -0.0902097278
+ 0.2171184410 -0.8730158634 -0.4366954143
+ 0.6337780180 -0.7004597412 -0.3281487085
+ 0.7752228621 -0.3165232566 -0.5466649267
+ 0.7846911652 0.4275505711 -0.4488432737
+ 0.4346204276 0.7157251860 -0.5466649267
+ 0.0014482055 0.8716810135 -0.4900715391
+-0.3439002478 0.6359394784 -0.6908788601
+-0.7197752973 0.5396486232 -0.4366954143
+-0.8871554693 0.1072142198 -0.4488432737
+-0.6414198315 -0.6014211198 -0.4763121208
+-0.2422737833 -0.8373370292 -0.4900715391
+ 0.4183769714 -0.5607792259 -0.7144839884
+ 0.4919671680 -0.1269691999 -0.8613054788
+ 0.4978189011 0.3328937158 -0.8008483725
+ 0.0947401619 0.5614556665 -0.8220655912
+-0.5854826930 0.2482988995 -0.7717238319
+-0.6691452398 -0.2043459771 -0.7144839884
+-0.3249352618 -0.5030496595 -0.8008483725
+ 0.0833693593 -0.3321275372 -0.9395428936
+ 0.1242523988 0.1277815601 -0.9839884218
+-0.2961484454 -0.0657599657 -0.9528755035
+ 0.2190839064 0.1312836377 0.9188614921
+-0.0124546442 0.2551039658 0.9188614921
+-0.2308305197 0.1093179889 0.9188614921
+-0.2052534511 -0.1520005669 0.9188614921
+ 0.2190839064 -0.3281703830 0.9188614921
+ 0.5977703708 -0.1520005669 0.7273967313
+ 0.6205958173 0.1093179889 0.7158561322
+ 0.4257131685 0.2551039658 0.8143892546
+ 0.3890572668 0.4957055924 0.7158561322
+-0.0330094857 0.6761213397 0.7360504792
+-0.4354944038 0.4554494653 0.7158561322
+-0.4485386151 0.2124213879 0.8143892546
+-0.7630826557 -0.0746882186 0.6419708175
+-0.3988385021 -0.2953600929 0.8143892546
+-0.3389195666 -0.5312467586 0.7158561322
+-0.0888218963 -0.6103640383 0.7273967313
+ 0.4074741194 -0.6103640383 0.6090650015
+ 0.6254586613 -0.5312467586 0.4859196824
+ 0.7233904360 -0.2953600929 0.5468165011
+ 0.8646946053 -0.1692512546 0.3649614304
+ 0.8780829721 0.2897337362 0.3808210291
+ 0.5493678557 0.5768433427 0.5243913714
+ 0.4593636674 0.7564719129 0.3553517403
+ 0.2141655150 0.8447510749 0.3873865601
+-0.2954354429 0.8198714201 0.3873865601
+-0.5308680756 0.7081269803 0.3553517403
+-0.6029463352 0.5205852472 0.5243913714
+-0.7739230465 0.3389900646 0.4423442636
+-0.6935065744 -0.4826176302 0.4423442636
+-0.4905640004 -0.6276147261 0.5243913714
+-0.3032002312 -0.9251016481 0.2285969389
+-0.0045863974 -0.7813515677 0.5468165011
+ 0.2508214168 -0.7813515677 0.4859196824
+ 0.3210587649 -0.8635013917 0.2466297006
+ 0.7110959079 -0.6998764938 0.0671974935
+ 0.9000340357 -0.2861982107 0.1325477729
+ 0.9410156039 -0.1341976438 -0.0775900694
+ 0.9443279912 0.1261088383 -0.0433681826
+ 0.7494453424 0.5872206583 0.0551649398
+ 0.5623291395 0.7618123698 0.1138746914
+ 0.3032002312 0.9251016481 -0.2285969389
+ 0.0858720409 0.9333521346 0.1761231918
+-0.1763828687 0.9205483682 0.1761231918
+-0.2995309163 0.9037575188 -0.0551649398
+-0.7110959079 0.6998764938 -0.0671974935
+-0.8631016874 0.3552600725 0.1959217993
+-0.9410156039 0.1341976438 0.0775900694
+-0.9253215715 -0.0905676721 0.2124078137
+-0.8971365698 -0.3141104098 0.0775900694
+-0.7778380870 -0.5158702863 0.1959217993
+-0.6544328852 -0.6922296665 0.0455552496
+ 0.1318953941 -0.9409811017 0.0818398716
+ 0.1763828687 -0.9205483682 -0.1761231918
+ 0.4075046572 -0.8237974999 -0.2546315508
+ 0.7653310532 -0.4670045122 -0.3251380596
+ 0.8716936806 -0.2272456248 -0.3131280032
+ 0.7630826557 0.0746882186 -0.6419708175
+ 0.8781301501 0.2785692436 -0.2466297006
+ 0.7778380870 0.5158702863 -0.1959217993
+ 0.6175005369 0.6231678047 -0.3740248218
+-0.1534232428 0.9007249745 -0.2733046324
+-0.2508214168 0.7813515677 -0.4859196824
+-0.4887903007 0.6717969331 -0.4683081420
+-0.8370961923 0.3328068685 -0.3131280032
+-0.9276324486 0.1226425968 -0.1843812002
+-0.8780829721 -0.2897337362 -0.3808210291
+-0.6573415966 -0.6568033615 -0.2145948808
+-0.4593636674 -0.7564719129 -0.3553517403
+-0.2697318228 -0.8859007376 -0.2279566191
+-0.0303057331 -0.8922024719 -0.3355531328
+ 0.0330094857 -0.6761213397 -0.7360504792
+ 0.4187988612 -0.7042009004 -0.4881067495
+ 0.6029463352 -0.5205852472 -0.5243913714
+ 0.5561556114 -0.3313610975 -0.7003073269
+ 0.5665700378 0.4870645516 -0.5927108132
+ 0.3389195666 0.5312467586 -0.7158561322
+ 0.1751412372 0.7090205159 -0.6133148036
+-0.0817329434 0.6826950901 -0.6608984288
+-0.2190839064 0.3281703830 -0.9188614921
+-0.5441424799 0.4698138638 -0.6266765419
+-0.7233904360 0.2953600929 -0.5468165011
+-0.7066849651 0.0498778478 -0.6384732991
+-0.5396360317 -0.4318462468 -0.6571463807
+-0.3987890908 -0.6407026882 -0.5831011230
+ 0.3278774074 -0.3365097556 -0.8299380599
+ 0.2308305197 -0.1093179889 -0.9188614921
+ 0.3675788294 0.1101068700 -0.8730990062
+ 0.2365131238 0.3372537898 -0.8601517406
+-0.5116812230 -0.0071952699 -0.8047795644
+-0.4257131685 -0.2551039658 -0.8143892546
+-0.1774197357 -0.2972657023 -0.8886478115
+-0.0292095264 -0.0891219012 -0.9490751728
+3 0 2 1
+3 0 3 2
+3 0 4 3
+3 0 5 4
+5 0 1 6 14 5
+3 1 7 6
+3 1 8 7
+3 1 2 8
+3 2 9 8
+5 2 3 10 20 9
+3 3 11 10
+3 3 4 11
+5 4 12 24 23 11
+3 4 5 12
+3 5 13 12
+3 5 14 13
+3 6 15 14
+3 6 16 15
+3 6 7 16
+3 7 17 16
+5 7 8 18 30 17
+3 8 9 18
+3 9 19 18
+3 9 20 19
+3 10 21 20
+3 10 22 21
+3 10 11 22
+3 11 23 22
+3 12 25 24
+3 12 13 25
+5 13 26 38 37 25
+3 13 14 26
+3 14 15 26
+3 15 27 26
+5 15 16 28 40 27
+3 16 17 28
+3 17 29 28
+3 17 30 29
+3 18 31 30
+3 18 19 31
+5 19 32 44 43 31
+3 19 20 32
+3 20 21 32
+3 21 33 32
+5 21 22 34 46 33
+3 22 23 34
+3 23 35 34
+3 23 24 35
+3 24 36 35
+3 24 25 36
+3 25 37 36
+3 26 27 38
+3 27 39 38
+3 27 40 39
+3 28 41 40
+3 28 29 41
+5 29 42 52 51 41
+3 29 30 42
+3 30 31 42
+3 31 43 42
+3 32 33 44
+3 33 45 44
+3 33 46 45
+3 34 47 46
+3 34 35 47
+5 35 36 48 55 47
+3 36 37 48
+3 37 49 48
+3 37 38 49
+3 38 39 49
+5 39 50 57 56 49
+3 39 40 50
+3 40 41 50
+3 41 51 50
+3 42 43 52
+3 43 53 52
+3 43 44 53
+3 44 45 53
+5 45 54 59 58 53
+3 45 46 54
+3 46 47 54
+3 47 55 54
+3 48 56 55
+3 48 49 56
+3 50 51 57
+3 51 58 57
+3 51 52 58
+3 52 53 58
+3 54 55 59
+3 55 56 59
+3 56 57 59
+3 57 58 59
+5 4 0 1 2 3
+5 4 5 6 7 0
+5 7 8 9 1 0
+5 9 10 11 2 1
+5 11 12 13 3 2
+5 13 14 15 4 3
+5 4 16 17 18 5
+5 18 19 20 6 5
+5 20 21 8 7 6
+5 21 22 23 9 8
+5 9 24 25 26 10
+5 26 27 12 11 10
+5 12 28 29 14 13
+5 29 30 31 15 14
+5 31 32 16 4 15
+5 32 33 34 17 16
+5 34 35 19 18 17
+5 35 36 37 20 19
+5 20 38 39 22 21
+5 39 40 41 23 22
+5 41 42 24 9 23
+5 42 43 44 25 24
+5 44 45 27 26 25
+5 45 46 47 12 27
+5 47 48 49 28 12
+5 49 50 30 29 28
+5 30 51 33 32 31
+5 51 52 53 34 33
+5 34 54 55 36 35
+5 55 56 57 37 36
+5 57 58 38 20 37
+5 58 59 40 39 38
+5 40 60 43 42 41
+5 60 61 62 44 43
+5 44 63 64 46 45
+5 64 65 48 47 46
+5 65 66 50 49 48
+5 66 67 68 30 50
+5 68 69 52 51 30
+5 69 70 71 53 52
+5 71 72 54 34 53
+5 72 73 56 55 54
+5 56 74 59 58 57
+5 74 75 76 40 59
+5 76 77 61 60 40
+5 77 78 79 62 61
+5 79 80 63 44 62
+5 80 81 65 64 63
+5 65 82 83 67 66
+5 83 70 69 68 67
+5 70 84 73 72 71
+5 84 85 86 56 73
+5 86 87 75 74 56
+5 87 78 77 76 75
+5 78 88 81 80 79
+5 88 89 82 65 81
+5 89 90 70 83 82
+5 90 91 85 84 70
+5 91 78 87 86 85
+5 78 88 89 90 91
+small ditrigonal icosidodecahedron
+small triambic icosahedron
+3|5/2 3
+(5/2.3.5/2.3.5/2.3)
+icosahedral group
+A5
+20{3}+12{5/2}
+34 20 60 32 20 2 0 0 -8 2 6 120 5 0 -1
+ 0.0000000000 0.0000000000 1.0000000000
+ 0.9428090416 0.0000000000 0.3333333333
+ 0.6727182848 0.6605596098 0.3333333333
+-0.4714045208 0.8164965809 0.3333333333
+-0.9084205452 0.2523113194 0.3333333333
+-0.4714045208 -0.8164965809 0.3333333333
+ 0.2357022604 -0.9128709292 0.3333333333
+ 0.0900302522 0.6605596098 0.7453559925
+ 0.4714045208 0.8164965809 -0.3333333333
+ 0.6170765289 0.2523113194 -0.7453559925
+ 0.4714045208 -0.8164965809 -0.3333333333
+-0.2357022604 0.9128709292 -0.3333333333
+ 0.9084205452 -0.2523113194 -0.3333333333
+ 0.5270462767 -0.4082482905 0.7453559925
+-0.6170765289 -0.2523113194 0.7453559925
+-0.9428090416 0.0000000000 -0.3333333333
+-0.5270462767 0.4082482905 -0.7453559925
+-0.6727182848 -0.6605596098 -0.3333333333
+-0.0900302522 -0.6605596098 -0.7453559925
+ 0.0000000000 0.0000000000 -1.0000000000
+ 0.5270462767 0.2154995940 0.7453559925
+ 0.0900302522 0.6605596098 0.7453559925
+-0.4501512612 0.3486856676 0.7453559925
+-0.6170765289 -0.2523113194 0.7453559925
+-0.0768950155 -0.5641852616 0.7453559925
+ 0.5270462767 -0.4082482905 0.7453559925
+ 0.7283600407 -0.5641852616 0.1759546817
+ 0.9084205452 -0.2523113194 -0.3333333333
+ 0.8527787893 0.3486856676 -0.1759546817
+ 0.6727182848 0.6605596098 0.3333333333
+ 0.9428090416 -0.0000000000 0.3333333333
+ 0.4714045208 0.8164965809 -0.3333333333
+ 0.1244187486 0.9128709292 0.1759546817
+-0.2357022604 0.9128709292 -0.3333333333
+-0.7283600407 0.5641852616 -0.1759546817
+-0.9084205452 0.2523113194 0.3333333333
+-0.4714045208 0.8164965809 0.3333333333
+-0.9428090416 -0.0000000000 -0.3333333333
+-0.8527787893 -0.3486856676 0.1759546817
+-0.6727182848 -0.6605596098 -0.3333333333
+-0.1244187486 -0.9128709292 -0.1759546817
+ 0.2357022604 -0.9128709292 0.3333333333
+-0.4714045208 -0.8164965809 0.3333333333
+ 0.4714045208 -0.8164965809 -0.3333333333
+ 0.0000000000 -0.0000000000 1.0000000000
+ 0.6170765289 0.2523113194 -0.7453559925
+ 0.0768950155 0.5641852616 -0.7453559925
+ 0.4501512612 -0.3486856676 -0.7453559925
+-0.0000000000 0.0000000000 -1.0000000000
+-0.0900302522 -0.6605596098 -0.7453559925
+-0.5270462767 0.4082482905 -0.7453559925
+-0.5270462767 -0.2154995940 -0.7453559925
+5 0 2 13 7 1 2
+3 0 3 2
+5 0 4 7 14 3 2
+3 0 5 4
+5 0 6 14 13 5 2
+3 0 1 6
+5 1 10 13 12 6 2
+3 1 9 10
+5 1 8 12 2 9 2
+3 1 7 8
+3 2 12 13
+3 2 11 9
+5 2 3 8 7 11 2
+3 3 16 8
+5 3 15 11 4 16 2
+3 3 14 15
+3 4 11 7
+3 4 17 16
+5 4 5 15 14 17 2
+3 5 18 15
+5 5 10 17 6 18 2
+3 5 13 10
+3 6 17 14
+3 6 12 18
+3 7 13 14
+3 8 19 12
+5 8 16 9 11 19 2
+5 9 18 12 19 10 2
+3 9 16 18
+3 10 19 17
+3 11 15 19
+5 15 18 16 17 19 2
+6 5 0 1 2 3 4
+6 5 6 7 8 9 0
+6 0 10 8 11 12 1
+6 12 13 14 15 2 1
+6 2 16 14 17 18 3
+6 18 19 20 21 4 3
+6 4 22 20 23 6 5
+6 9 12 16 2 24 0
+6 8 25 26 13 12 9
+6 7 27 28 26 11 8
+6 6 21 20 29 27 7
+6 26 30 14 16 12 11
+6 10 6 23 27 25 8
+6 24 4 21 6 10 0
+6 15 18 22 4 24 2
+6 30 31 19 18 15 14
+6 28 31 17 14 13 26
+6 31 29 20 22 18 17
+6 19 20 23 27 28 31
+6 25 26 30 31 29 27
+small icosicosidodecahedron
+small icosacronic hexecontahedron
+5/2 3|3
+(6.5/2.6.3)
+icosahedral group
+A5
+20{6}+20{3}+12{5/2}
+35 60 120 52 60 2 0 0 -8 3 4 120 5 0 -1
+ 0.0000000000 0.0000000000 1.0000000000
+ 0.5558508647 0.0000000000 0.8312820317
+-0.3547421326 0.4279348118 0.8312820317
+-0.5423346067 0.1218333214 0.8312820317
+ 0.2523198656 -0.4952826155 0.8312820317
+ 0.7569595968 0.4279348118 0.4938460950
+ 0.9129018498 0.1218333214 0.3895726561
+-0.3230919115 -0.1426449373 0.9355554706
+-0.6764070948 0.6250652668 0.3895726561
+-0.1536334005 0.8558696236 0.4938460950
+-0.8323493477 -0.2516159727 0.4938460950
+-0.8639995688 0.3189637764 0.3895726561
+-0.0195609124 0.3526376782 0.9355554706
+ 0.3058398516 -0.8687319096 0.3895726561
+-0.0376948755 -0.8687319096 0.4938460950
+ 0.7886098179 -0.1426449373 0.5981195340
+ 0.7788293617 0.6250652668 -0.0521367195
+ 0.4022174642 0.8558696236 0.3251281267
+ 0.9664218358 -0.2516159727 -0.0521367195
+ 0.9347716147 0.3189637764 -0.1564101584
+ 0.5362899523 0.3526376782 0.7668375023
+-0.6131066526 -0.5160942314 0.5981195340
+-0.0707720459 -0.6379275528 0.7668375023
+-0.8421298039 0.5160942314 -0.1564101584
+-0.9664218358 0.2516159727 0.0521367195
+ 0.2034175846 0.9777029450 0.0521367195
+-0.7788293617 -0.6250652668 0.0521367195
+-0.5800294821 -0.7468985882 0.3251281267
+-0.6628908367 0.7468985882 0.0521367195
+ 0.1815478197 0.7805724901 0.5981195340
+ 0.1401171424 -0.9777029450 -0.1564101584
+ 0.6628908367 -0.7468985882 -0.0521367195
+-0.2034175846 -0.9777029450 -0.0521367195
+ 0.4850788188 -0.6379275528 0.5981195340
+ 0.8421298039 -0.5160942314 0.1564101584
+ 0.6131066526 0.5160942314 -0.5981195340
+ 0.8323493477 0.2516159727 -0.4938460950
+-0.1401171424 0.9777029450 0.1564101584
+ 0.6764070948 -0.6250652668 -0.3895726561
+ 0.5800294821 0.7468985882 -0.3251281267
+-0.9347716147 -0.3189637764 0.1564101584
+-0.7886098179 0.1426449373 -0.5981195340
+-0.4850788188 0.6379275528 -0.5981195340
+-0.9129018498 -0.1218333214 -0.3895726561
+ 0.0376948755 0.8687319096 -0.4938460950
+-0.4022174642 -0.8558696236 -0.3251281267
+-0.7569595968 -0.4279348118 -0.4938460950
+-0.3058398516 0.8687319096 -0.3895726561
+-0.1815478197 -0.7805724901 -0.5981195340
+ 0.8639995688 -0.3189637764 -0.3895726561
+ 0.1536334005 -0.8558696236 -0.4938460950
+ 0.3230919115 0.1426449373 -0.9355554706
+ 0.0707720459 0.6379275528 -0.7668375023
+ 0.5423346067 -0.1218333214 -0.8312820317
+ 0.3547421326 -0.4279348118 -0.8312820317
+-0.5362899523 -0.3526376782 -0.7668375023
+-0.5558508647 -0.0000000000 -0.8312820317
+-0.2523198656 0.4952826155 -0.8312820317
+ 0.0195609124 -0.3526376782 -0.9355554706
+-0.0000000000 -0.0000000000 -1.0000000000
+ 0.2470682788 0.5257311121 0.8139803827
+-0.2225822414 0.1364082001 0.8139803827
+-0.3562920523 -0.4587939735 0.8139803827
+ 0.2470682788 -0.1514143222 0.8139803827
+ 0.7486308807 -0.4587939735 0.4786020209
+ 0.6374803174 0.1364082001 0.5529247349
+-0.3622034226 0.5835662368 0.5242062787
+-0.7921037010 0.0669371386 0.6067051560
+-0.4192065089 0.6754071043 0.6067051560
+-0.6843946014 0.0578351247 0.5242062787
+ 0.1678297972 -0.6299377043 0.5529247349
+ 0.9956991595 0.0669371386 0.0640515676
+ 0.5924737103 0.5835662368 0.2344321747
+ 0.8603054480 0.0578351247 0.0553419293
+ 0.6857164240 0.6754071043 0.2713267942
+-0.3078439816 -0.3964078418 0.7032965240
+ 0.2859515514 -0.1752437040 0.9420835178
+-0.3923388284 0.9175879470 -0.0640515676
+-0.7202912637 0.4414262081 0.1305278239
+ 0.0885913156 0.7985475123 0.2918690871
+-0.9956991595 -0.0669371386 -0.0640515676
+-0.6713191889 -0.4414262081 0.2918690871
+ 0.2134722966 0.4542429665 0.7032965240
+-0.2905410991 -0.9175879470 0.2713267942
+ 0.3389891699 -0.7928156837 0.0553419293
+-0.2510337466 -0.7928156837 0.2344321747
+ 0.3923388284 -0.9175879470 0.0640515676
+ 0.6468331514 -0.3964078418 0.4135224200
+ 0.6713191889 0.4414262081 -0.2918690871
+ 0.2905410991 0.9175879470 -0.2713267942
+ 0.7202912637 -0.4414262081 -0.1305278239
+ 0.7921037010 -0.0669371386 -0.6067051560
+-0.6468331514 0.3964078418 -0.4135224200
+-0.7486308807 0.4587939735 -0.4786020209
+-0.8603054480 -0.0578351247 -0.0553419293
+ 0.2510337466 0.7928156837 -0.2344321747
+-0.5924737103 -0.5835662368 -0.2344321747
+-0.6857164240 -0.6754071043 -0.2713267942
+-0.3389891699 0.7928156837 -0.0553419293
+-0.0885913156 -0.7985475123 -0.2918690871
+ 0.4192065089 -0.6754071043 -0.6067051560
+ 0.3078439816 0.3964078418 -0.7032965240
+ 0.6843946014 -0.0578351247 -0.5242062787
+ 0.3562920523 0.4587939735 -0.8139803827
+ 0.3622034226 -0.5835662368 -0.5242062787
+-0.2859515514 0.1752437040 -0.9420835178
+-0.6374803174 -0.1364082001 -0.5529247349
+-0.1678297972 0.6299377043 -0.5529247349
+-0.2470682788 -0.5257311121 -0.8139803827
+-0.2134722966 -0.4542429665 -0.7032965240
+ 0.2225822414 -0.1364082001 -0.8139803827
+-0.2470682788 0.1514143222 -0.8139803827
+6 0 2 9 17 5 1
+5 0 3 12 7 2 2
+6 0 4 14 27 10 3
+3 0 1 4
+6 1 6 18 31 13 4
+5 1 5 15 20 6 2
+3 2 8 9
+6 2 7 21 40 24 8
+6 3 11 28 37 29 12
+3 3 10 11
+5 4 13 22 33 14 2
+6 5 16 36 49 34 15
+3 5 17 16
+3 6 19 18
+6 6 20 29 25 39 19
+3 7 22 21
+6 7 12 20 15 33 22
+6 8 23 42 44 25 9
+5 8 24 28 11 23 2
+5 9 25 29 37 17 2
+6 10 26 46 41 23 11
+5 10 27 40 21 26 2
+3 12 29 20
+6 13 30 45 26 21 22
+3 13 31 30
+3 14 32 27
+6 14 33 34 38 50 32
+3 15 34 33
+5 16 35 19 39 36 2
+6 16 17 37 47 52 35
+5 18 38 34 49 31 2
+6 18 19 35 51 54 38
+3 23 41 42
+6 24 43 56 57 47 28
+3 24 40 43
+3 25 44 39
+3 26 45 46
+6 27 32 48 55 43 40
+3 28 47 37
+5 30 48 32 50 45 2
+6 30 31 49 53 58 48
+3 35 52 51
+3 36 53 49
+6 36 39 44 57 59 53
+3 38 54 50
+6 41 55 58 51 52 42
+5 41 46 56 43 55 2
+5 42 52 47 57 44 2
+6 45 50 54 59 56 46
+3 48 58 55
+5 51 58 53 59 54 2
+3 56 59 57
+4 3 0 1 2
+4 3 4 5 0
+4 0 6 7 1
+4 1 8 9 2
+4 2 10 4 3
+4 5 11 12 0
+4 4 13 14 5
+4 7 15 16 1
+4 6 17 18 7
+4 0 19 17 6
+4 9 20 21 2
+4 8 18 20 9
+4 16 22 8 1
+4 10 23 24 4
+4 2 25 26 10
+4 5 16 27 11
+4 11 28 29 12
+4 29 19 0 12
+4 4 30 31 13
+4 31 28 14 13
+4 14 22 16 5
+4 7 21 23 15
+4 10 16 15 23
+4 17 32 20 18
+4 18 33 34 7
+4 19 14 35 17
+4 20 36 23 21
+4 21 37 25 2
+4 8 38 33 18
+4 19 8 22 14
+4 23 39 40 24
+4 40 30 4 24
+4 37 39 26 25
+4 26 27 16 10
+4 26 30 11 27
+4 31 41 29 28
+4 11 42 43 28
+4 29 38 8 19
+4 26 44 31 30
+4 43 35 14 28
+4 34 37 21 7
+4 32 45 46 20
+4 17 47 45 32
+4 33 46 37 34
+4 43 47 17 35
+4 36 48 39 23
+4 46 48 36 20
+4 29 47 33 38
+4 37 49 40 39
+4 40 42 11 30
+4 48 44 26 39
+4 31 50 45 41
+4 41 29 47 45
+4 40 50 43 42
+4 48 50 31 44
+4 45 49 37 46
+4 33 51 48 46
+4 43 51 33 47
+4 49 40 50 45
+4 50 43 51 48
+small snub icosicosidodecahedron
+small hexagonal hexecontahedron
+|5/2 3 3
+(3.5/2.3.3.3.3)
+icosahedral group
+A5
+100{3}+12{5/2}
+36 60 180 112 60 2 0 0 -8 2 6 120 5 0 -1
+ 0.0000000000 0.0000000000 1.0000000000
+ 0.6442062214 0.0000000000 0.7648518447
+ 0.2791862208 0.5805658531 0.7648518447
+-0.1419451564 0.6283734783 0.7648518447
+-0.6278134281 0.1444020607 0.7648518447
+-0.4022186612 -0.5032114906 0.7648518447
+ 0.2791862208 -0.5805658531 0.7648518447
+ 0.8003600018 -0.5032114906 0.3258865804
+ 0.9729065754 -0.1444020607 0.1805570281
+ 0.8003600018 0.5032114906 0.3258865804
+ 0.2915016934 0.9393752830 0.1805570281
+-0.3057103174 0.8142132953 0.4935563915
+-0.3144917300 0.2695640484 0.9101813971
+ 0.3669131520 0.1922096859 0.9101813971
+ 0.4804410603 0.7249679138 0.4935563915
+-0.0735183072 0.9808130393 0.1805570281
+-0.6671962580 0.6698112346 0.3258865804
+-0.9805179561 0.0773543625 0.1805570281
+-0.8927910249 -0.3110018047 0.3258865804
+-0.4946496843 -0.8501299015 0.1805570281
+ 0.1154210597 -0.8620209205 0.4935563915
+-0.3057103174 -0.8142132953 0.4935563915
+ 0.2915016934 -0.9393752830 0.1805570281
+ 0.6671962580 -0.6698112346 -0.3258865804
+ 0.9805179561 -0.0773543625 -0.1805570281
+ 0.8763982317 0.1665997441 0.4518524813
+ 0.5972120109 -0.4139661090 0.6870006366
+ 0.6584148454 -0.7471655971 0.0907384251
+ 0.8167527950 -0.3588094299 -0.4518524813
+ 0.8927910249 0.3110018047 -0.3258865804
+ 0.4946496843 0.8501299015 -0.1805570281
+ 0.8091414144 0.5805658531 -0.0907384251
+ 0.3057103174 0.8142132953 -0.4935563915
+-0.2915016934 0.9393752830 -0.1805570281
+-0.6584148454 0.7471655971 -0.0907384251
+-0.8167527950 0.3588094299 0.4518524813
+-0.6748076386 -0.2695640484 0.6870006366
+-0.0407327207 -0.3588094299 0.9325216558
+-0.1154210597 0.8620209205 -0.4935563915
+-0.8003600018 0.5032114906 -0.3258865804
+-0.8763982317 -0.1665997441 -0.4518524813
+-0.8091414144 -0.5805658531 0.0907384251
+-0.9729065754 0.1444020607 -0.1805570281
+-0.8003600018 -0.5032114906 -0.3258865804
+-0.4804410603 -0.7249679138 -0.4935563915
+ 0.0735183072 -0.9808130393 -0.1805570281
+-0.2915016934 -0.9393752830 -0.1805570281
+ 0.3057103174 -0.8142132953 -0.4935563915
+ 0.1419451564 -0.6283734783 -0.7648518447
+ 0.6278134281 -0.1444020607 -0.7648518447
+ 0.6748076386 0.2695640484 -0.6870006366
+ 0.3144917300 -0.2695640484 -0.9101813971
+ 0.4022186612 0.5032114906 -0.7648518447
+ 0.0407327207 0.3588094299 -0.9325216558
+-0.2791862208 0.5805658531 -0.7648518447
+-0.5972120109 0.4139661090 -0.6870006366
+-0.6442062214 -0.0000000000 -0.7648518447
+-0.3669131520 -0.1922096859 -0.9101813971
+-0.2791862208 -0.5805658531 -0.7648518447
+-0.0000000000 -0.0000000000 -1.0000000000
+ 0.3351898516 0.2107443956 0.9182780424
+ 0.0400368356 0.3526794657 0.9182780424
+-0.2794210283 0.2805161775 0.9182780424
+-0.3738998581 -0.1302471994 0.9182780424
+-0.0446605620 -0.3934092920 0.9182780424
+ 0.3351898516 -0.2107443956 0.9182780424
+ 0.6257191411 -0.3934092920 0.6735760428
+ 0.8213888526 -0.1889259414 0.5087707326
+ 0.8775384241 0.1302471994 0.4614780399
+ 0.6257191411 0.3934092920 0.6735760428
+ 0.4976880105 0.7344008871 0.4614780399
+ 0.0961864071 0.8472940016 0.5223418899
+-0.1237881524 0.6041536876 0.7871942677
+ 0.2560622612 0.5610323550 0.7871942677
+ 0.0961864071 0.8472940016 0.5223418899
+-0.3204039448 0.8272722230 0.4614780399
+-0.5216121103 0.5236564915 0.6735760428
+-0.8260125790 0.3236375102 0.4614780399
+-0.8428360805 0.0000000000 0.5087707326
+-0.6979814484 -0.2431403140 0.6735760428
+-0.6496432409 -0.6041536876 0.4614780399
+-0.2836640065 -0.8041726690 0.5223418899
+-0.0747391792 -0.6583680602 0.7281386332
+ 0.0961864071 -0.8472940016 0.5223418899
+ 0.4976880105 -0.7344008871 0.4614780399
+ 0.6385349796 -0.7667968054 0.0655418874
+ 0.8886466854 -0.4538847096 -0.0655418874
+ 0.9645866382 -0.1502689781 0.2167760402
+ 0.8089537623 -0.4739064882 0.3478598150
+ 0.8886466854 -0.4538847096 -0.0655418874
+ 0.9737248312 -0.0697717819 -0.2167760402
+ 0.9677742757 0.2431403140 0.0655418874
+ 0.7941678555 0.6041536876 -0.0655418874
+ 0.6071295333 0.7595733041 0.1538260133
+ 0.5105038490 0.8472940016 -0.1465561155
+ 0.1109723139 0.9775412010 -0.1791601123
+-0.1109723139 0.9775412010 0.1791601123
+-0.4214180402 0.8763359572 0.1538260133
+-0.6464556034 0.6970250235 0.3102438870
+-0.5216121103 0.5236564915 0.6735760428
+-0.6555937963 0.1302471994 0.7437959675
+-0.3738998581 -0.1302471994 0.9182780424
+ 0.0042429783 0.0373758635 0.9992922705
+ 0.3351898516 -0.2107443956 0.9182780424
+ 0.6681067932 -0.0200217787 0.7437959675
+ 0.6257191411 0.3934092920 0.6735760428
+ 0.7862472317 0.5343819058 0.3102438870
+ 0.3272692278 0.9277911978 0.1791601123
+ 0.1109723139 0.9775412010 -0.1791601123
+-0.3075881063 0.9401653375 -0.1465561155
+-0.6385349796 0.7667968054 -0.0655418874
+-0.8886466854 0.4538847096 0.0655418874
+-0.9645866382 0.1502689781 -0.2167760402
+-0.9677742757 -0.2431403140 -0.0655418874
+-0.8945972408 -0.2805161775 0.3478598150
+-0.9737248312 0.0697717819 0.2167760402
+-0.9677742757 -0.2431403140 -0.0655418874
+-0.7941678555 -0.6041536876 0.0655418874
+-0.6071295333 -0.7595733041 -0.1538260133
+-0.3272692278 -0.9277911978 -0.1791601123
+-0.1109723139 -0.9775412010 0.1791601123
+ 0.3075881063 -0.9401653375 0.1465561155
+ 0.4976880105 -0.7344008871 0.4614780399
+ 0.2438986592 -0.5934282734 0.7670438895
+-0.3707122206 -0.5236564915 0.7670438895
+-0.6496432409 -0.6041536876 0.4614780399
+-0.5105038490 -0.8472940016 0.1465561155
+-0.1109723139 -0.9775412010 0.1791601123
+ 0.1109723139 -0.9775412010 -0.1791601123
+ 0.4214180402 -0.8763359572 -0.1538260133
+ 0.3204039448 -0.8272722230 -0.4614780399
+ 0.5216121103 -0.5236564915 -0.6735760428
+ 0.8260125790 -0.3236375102 -0.4614780399
+ 0.8428360805 0.0000000000 -0.5087707326
+ 0.8945972408 0.2805161775 -0.3478598150
+ 0.9677742757 0.2431403140 0.0655418874
+ 0.6464556034 -0.6970250235 -0.3102438870
+ 0.5216121103 -0.5236564915 -0.6735760428
+ 0.6555937963 -0.1302471994 -0.7437959675
+ 0.6979814484 0.2431403140 -0.6735760428
+ 0.6496432409 0.6041536876 -0.4614780399
+ 0.2836640065 0.8041726690 -0.5223418899
+ 0.6496432409 0.6041536876 -0.4614780399
+ 0.3707122206 0.5236564915 -0.7670438895
+ 0.0747391792 0.6583680602 -0.7281386332
+-0.0961864071 0.8472940016 -0.5223418899
+-0.4976880105 0.7344008871 -0.4614780399
+-0.4976880105 0.7344008871 -0.4614780399
+-0.8089537623 0.4739064882 -0.3478598150
+-0.8886466854 0.4538847096 0.0655418874
+-0.2438986592 0.5934282734 -0.7670438895
+-0.6257191411 0.3934092920 -0.6735760428
+-0.8213888526 0.1889259414 -0.5087707326
+-0.6681067932 0.0200217787 -0.7437959675
+-0.6257191411 -0.3934092920 -0.6735760428
+-0.7862472317 -0.5343819058 -0.3102438870
+-0.8775384241 -0.1302471994 -0.4614780399
+-0.6257191411 -0.3934092920 -0.6735760428
+-0.4976880105 -0.7344008871 -0.4614780399
+-0.2560622612 -0.5610323550 -0.7871942677
+-0.0961864071 -0.8472940016 -0.5223418899
+-0.0961864071 -0.8472940016 -0.5223418899
+ 0.1237881524 -0.6041536876 -0.7871942677
+-0.0400368356 -0.3526794657 -0.9182780424
+ 0.2794210283 -0.2805161775 -0.9182780424
+ 0.3738998581 0.1302471994 -0.9182780424
+ 0.3738998581 0.1302471994 -0.9182780424
+-0.0042429783 -0.0373758635 -0.9992922705
+ 0.0446605620 0.3934092920 -0.9182780424
+-0.3351898516 0.2107443956 -0.9182780424
+-0.3351898516 0.2107443956 -0.9182780424
+-0.3351898516 -0.2107443956 -0.9182780424
+3 0 2 1
+5 0 3 13 12 2 2
+3 0 4 3
+3 0 5 4
+3 0 6 5
+3 0 1 6
+3 1 7 6
+5 1 8 26 25 7 2
+3 1 9 8
+3 1 2 9
+3 2 10 9
+3 2 11 10
+3 2 12 11
+3 3 14 13
+3 3 15 14
+3 3 16 15
+3 3 4 16
+3 4 17 16
+5 4 18 35 36 17 2
+3 4 5 18
+3 5 19 18
+3 5 20 19
+5 5 6 21 37 20 2
+3 6 22 21
+3 6 7 22
+3 7 23 22
+3 7 24 23
+3 7 25 24
+3 8 27 26
+3 8 28 27
+3 8 29 28
+3 8 9 29
+3 9 30 29
+5 9 10 31 14 30 2
+3 10 32 31
+3 10 33 32
+3 10 11 33
+5 11 34 15 16 33 2
+3 11 35 34
+3 11 12 35
+3 12 36 35
+3 12 37 36
+3 12 13 37
+3 13 26 37
+3 13 25 26
+3 13 14 25
+3 14 31 25
+3 14 15 30
+3 15 38 30
+3 15 34 38
+3 16 39 33
+3 16 17 39
+3 17 40 39
+3 17 41 40
+3 17 36 41
+3 18 42 35
+3 18 43 42
+3 18 19 43
+5 19 44 41 46 43 2
+3 19 45 44
+3 19 20 45
+3 20 27 45
+3 20 26 27
+3 20 37 26
+3 21 36 37
+3 21 41 36
+3 21 46 41
+3 21 22 46
+3 22 47 46
+5 22 23 45 27 47 2
+3 23 48 45
+3 23 49 48
+3 23 24 49
+5 24 50 28 29 49 2
+3 24 31 50
+3 24 25 31
+3 27 28 47
+3 28 51 47
+3 28 50 51
+3 29 52 49
+3 29 30 52
+3 30 38 52
+3 31 32 50
+3 32 53 50
+5 32 54 52 38 53 2
+3 32 33 54
+3 33 39 54
+3 34 55 38
+3 34 42 55
+3 34 35 42
+3 38 55 53
+3 39 56 54
+5 39 40 55 42 56 2
+3 40 57 55
+3 40 44 57
+3 40 41 44
+3 42 43 56
+3 43 58 56
+3 43 46 58
+3 44 48 57
+3 44 45 48
+3 46 47 58
+3 47 51 58
+5 48 59 58 51 57 2
+3 48 49 59
+3 49 52 59
+3 50 53 51
+3 51 53 57
+3 52 54 59
+3 53 55 57
+3 54 56 59
+3 56 58 59
+6 5 0 1 2 3 4
+6 5 6 7 8 9 0
+6 9 10 11 12 1 0
+6 1 13 14 15 16 2
+6 16 17 18 19 3 2
+6 19 20 21 22 4 3
+6 22 23 24 6 5 4
+6 24 25 26 27 7 6
+6 7 28 29 30 31 8
+6 31 32 33 10 9 8
+6 33 34 35 36 11 10
+6 36 37 38 39 12 11
+6 39 40 41 42 1 12
+6 42 43 44 45 13 1
+6 45 46 33 47 14 13
+6 47 48 49 37 15 14
+6 37 50 51 17 16 15
+6 51 52 53 54 18 17
+6 18 55 56 57 20 19
+6 57 58 59 60 21 20
+6 60 61 62 63 22 21
+6 22 64 65 66 67 23
+6 67 68 69 25 24 23
+6 69 70 71 72 26 25
+6 72 73 74 75 27 26
+6 75 46 45 44 7 27
+6 43 63 62 28 7 44
+6 61 69 76 29 28 62
+6 76 77 78 73 30 29
+6 73 79 80 32 31 30
+6 80 81 48 47 33 32
+6 74 82 34 33 46 75
+6 82 83 84 85 35 34
+6 85 86 50 37 36 35
+6 49 87 88 89 38 37
+6 89 55 18 40 39 38
+6 54 65 64 41 40 18
+6 41 42 43 63 22 64
+6 81 84 90 87 49 48
+6 86 91 92 52 51 50
+6 92 93 94 95 53 52
+6 95 58 66 65 54 53
+6 88 92 96 56 55 89
+6 96 97 98 58 57 56
+6 94 99 100 59 58 95
+6 100 70 69 61 60 59
+6 98 101 68 67 66 58
+6 101 102 77 76 69 68
+6 99 103 104 71 70 100
+6 104 105 79 73 72 71
+6 78 106 83 82 74 73
+6 102 103 107 106 78 77
+6 105 108 84 81 80 79
+6 107 109 90 84 83 106
+6 108 110 91 86 85 84
+6 109 93 92 88 87 90
+6 110 111 97 96 92 91
+6 93 94 99 103 107 109
+6 111 103 102 101 98 97
+6 103 104 105 108 110 111
+small dodecicosidodecahedron
+small dodecacronic hexecontahedron
+3/2 5|5
+(10.3/2.10.5)
+icosahedral group
+A5
+12{10}+12{5}+20{3/2}
+37 60 120 44 60 2 0 0 -16 3 4 120 5 0 -1
+ 0.0000000000 0.0000000000 1.0000000000
+ 0.4364663517 0.0000000000 0.8997205810
+-0.3947875239 0.1861335198 0.8997205810
+-0.0230394894 0.4358578416 0.8997205810
+-0.1650346033 -0.4040624406 0.8997205810
+ 0.7478962199 0.1861335198 0.6371856536
+ 0.4134268623 0.4358578416 0.7994411620
+ 0.5411827887 -0.4040624406 0.7374650726
+-0.5598221272 -0.2179289208 0.7994411620
+-0.5971008041 0.4873038812 0.6371856536
+-0.2253527696 0.7370282030 0.6371856536
+ 0.1694347542 -0.6537867624 0.7374650726
+-0.4551056902 -0.6219913614 0.6371856536
+ 0.8526126568 -0.2179289208 0.4749301452
+ 0.8153339799 0.4873038812 0.3126746369
+ 0.4808646224 0.7370282030 0.4749301452
+ 0.6875780535 -0.6219913614 0.3746507262
+-0.8641324015 -0.1664828812 0.4749301452
+-0.5296630440 0.7884742426 0.3126746369
+-0.8871718909 0.2693749604 0.3746507262
+ 0.0860770985 0.9231617228 0.3746507262
+ 0.3158300191 -0.8717156832 0.3746507262
+-0.1206363326 -0.8717156832 0.4749301452
+-0.7594159645 -0.5705453218 0.3126746369
+ 0.9847687342 -0.1664828812 0.0501397095
+ 0.6130206997 0.7884742426 0.0501397095
+ 0.9617292448 0.2693749604 -0.0501397095
+ 0.8197341309 -0.5705453218 -0.0501397095
+-0.9617292448 -0.2693749604 0.0501397095
+-0.8197341309 0.5705453218 0.0501397095
+-0.2182331759 0.9746077624 0.0501397095
+-0.9847687342 0.1664828812 -0.0501397095
+ 0.2182331759 0.9746077624 -0.0501397095
+ 0.2182331759 -0.9746077624 -0.0501397095
+-0.2182331759 -0.9746077624 0.0501397095
+-0.6130206997 -0.7884742426 -0.0501397095
+ 0.8871718909 -0.2693749604 -0.3746507262
+ 0.7594159645 0.5705453218 -0.3126746369
+ 0.8641324015 0.1664828812 -0.4749301452
+ 0.5296630440 -0.7884742426 -0.3126746369
+-0.8153339799 -0.4873038812 -0.3126746369
+-0.6875780535 0.6219913614 -0.3746507262
+-0.3158300191 0.8717156832 -0.3746507262
+-0.8526126568 0.2179289208 -0.4749301452
+ 0.1206363326 0.8717156832 -0.4749301452
+-0.0860770985 -0.9231617228 -0.3746507262
+-0.4808646224 -0.7370282030 -0.4749301452
+ 0.5971008041 -0.4873038812 -0.6371856536
+ 0.4551056902 0.6219913614 -0.6371856536
+ 0.5598221272 0.2179289208 -0.7994411620
+ 0.2253527696 -0.7370282030 -0.6371856536
+-0.7478962199 -0.1861335198 -0.6371856536
+-0.5411827887 0.4040624406 -0.7374650726
+-0.1694347542 0.6537867624 -0.7374650726
+-0.4134268623 -0.4358578416 -0.7994411620
+ 0.3947875239 -0.1861335198 -0.8997205810
+ 0.1650346033 0.4040624406 -0.8997205810
+ 0.0230394894 -0.4358578416 -0.8997205810
+-0.4364663517 0.0000000000 -0.8997205810
+-0.0000000000 0.0000000000 -1.0000000000
+ 0.1583346290 0.7071067812 0.6891517578
+-0.1028584649 0.1531185745 0.6891517578
+-0.7144788670 0.1207882584 0.6891517578
+ 0.1583346290 -0.2357022604 0.6891517578
+ 0.9436228948 0.1207882584 0.3081980354
+ 0.3933354313 0.1531185745 0.5751497609
+-0.5325411050 0.0900302522 0.5136633924
+ 0.2124281962 -0.3162277660 0.9245941063
+ 0.1180156646 0.5270462767 0.5136633924
+-0.2904769664 -0.3062371489 0.5751497609
+-0.4686190076 -0.8278950396 0.3081980354
+ 0.7033349793 0.0900302522 0.2297172526
+ 0.5561442379 -0.8278950396 0.0727556869
+ 0.5123816228 -0.3062371489 0.3906906553
+-0.3328569846 0.4955021156 0.3906906553
+-0.5561442379 0.8278950396 -0.0727556869
+ 0.0897623191 -0.5901345989 0.3906906553
+-0.3492879855 -0.6170765289 0.2297172526
+ 0.4686190076 0.8278950396 -0.3081980354
+ 0.4700016046 0.4955021156 0.2062315497
+ 0.4145254404 -0.6170765289 0.0542288872
+-0.9436228948 -0.1207882584 -0.3081980354
+-0.6364300969 -0.2477510578 0.2062315497
+-0.4145254404 0.6170765289 -0.0542288872
+-0.6626223886 0.2477510578 0.0922295528
+ 0.0211900091 0.7071067812 0.0922295528
+ 0.6626223886 -0.2477510578 -0.0922295528
+ 0.7144788670 -0.1207882584 -0.6891517578
+ 0.3492879855 0.6170765289 -0.2297172526
+ 0.6364300969 0.2477510578 -0.2062315497
+-0.7033349793 -0.0900302522 -0.2297172526
+-0.0211900091 -0.7071067812 -0.0922295528
+-0.1583346290 -0.7071067812 -0.6891517578
+-0.4700016046 -0.4955021156 -0.2062315497
+ 0.5325411050 -0.0900302522 -0.5136633924
+ 0.3328569846 -0.4955021156 -0.3906906553
+-0.2124281962 0.3162277660 -0.9245941063
+-0.5123816228 0.3062371489 -0.3906906553
+-0.0897623191 0.5901345989 -0.3906906553
+-0.1180156646 -0.5270462767 -0.5136633924
+ 0.2904769664 0.3062371489 -0.5751497609
+-0.3933354313 -0.1531185745 -0.5751497609
+-0.1583346290 0.2357022604 -0.6891517578
+ 0.1028584649 -0.1531185745 -0.6891517578
+10 0 2 9 18 30 32 25 14 5 1
+3 0 3 2 2
+10 0 4 12 23 28 31 29 18 10 3
+5 0 1 7 11 4
+10 1 6 15 25 37 38 36 27 16 7
+3 1 5 6 2
+5 2 8 17 19 9
+10 2 3 6 5 13 16 21 22 12 8
+5 3 10 20 15 6
+3 4 8 12 2
+10 4 11 21 33 45 46 40 28 17 8
+5 5 14 26 24 13
+10 7 13 24 36 47 50 45 34 22 11
+3 7 16 13 2
+3 9 10 18 2
+10 9 19 31 43 52 53 44 32 20 10
+3 11 22 21 2
+5 12 22 34 35 23
+10 14 15 20 30 42 53 56 49 38 26
+3 14 25 15 2
+5 16 27 39 33 21
+10 17 23 35 46 54 58 52 41 29 19
+3 17 28 23 2
+5 18 29 41 42 30
+3 19 29 31 2
+3 20 32 30 2
+3 24 27 36 2
+10 24 26 37 48 56 59 57 50 39 27
+5 25 32 44 48 37
+3 26 38 37 2
+5 28 40 51 43 31
+3 33 34 45 2
+10 33 39 47 55 59 58 51 40 35 34
+3 35 40 46 2
+5 36 38 49 55 47
+3 39 50 47 2
+10 41 43 51 54 57 55 49 48 44 42
+3 41 52 43 2
+3 42 44 53 2
+5 45 50 57 54 46
+3 48 49 56 2
+3 51 58 54 2
+5 52 58 59 56 53
+3 55 57 59 2
+4 3 0 1 2
+4 3 4 5 0
+4 0 6 7 1
+4 7 8 2 1
+4 2 9 10 3
+4 5 7 11 0
+4 4 8 7 5
+4 3 12 13 4
+4 6 10 9 7
+4 0 14 15 6
+4 8 15 14 2
+4 10 16 12 3
+4 2 17 7 9
+4 7 13 12 11
+4 11 18 19 0
+4 4 19 18 8
+4 7 20 4 13
+4 6 21 22 10
+4 0 23 2 14
+4 15 24 21 6
+4 18 25 15 8
+4 10 20 7 16
+4 17 12 16 7
+4 2 22 21 17
+4 12 26 27 11
+4 4 28 0 19
+4 27 29 18 11
+4 20 27 26 4
+4 2 30 10 22
+4 23 21 24 2
+4 0 25 18 23
+4 15 30 2 24
+4 28 15 25 0
+4 10 31 32 20
+4 17 32 31 12
+4 21 33 32 17
+4 12 34 4 26
+4 4 29 27 28
+4 34 18 29 4
+4 32 35 27 20
+4 30 32 33 10
+4 23 36 37 21
+4 18 38 36 23
+4 15 37 36 30
+4 28 36 38 15
+4 10 39 12 31
+4 21 39 10 33
+4 12 35 32 34
+4 27 40 36 28
+4 34 36 40 18
+4 39 27 35 12
+4 36 41 32 30
+4 15 42 21 37
+4 18 42 15 38
+4 21 41 36 39
+4 32 43 36 34
+4 27 42 18 40
+4 43 27 39 36
+4 42 32 41 21
+4 32 43 27 42
+small stellated dodecahedron
+great dodecahedron
+5|2 5/2
+(5/2.5/2.5/2.5/2.5/2)
+icosahedral group
+A5
+12{5/2}
+38 12 30 12 12 3 0 0 -6 1 5 120 5 0 -1
+ 0.0000000000 0.0000000000 1.0000000000
+ 0.8944271910 0.0000000000 -0.4472135955
+ 0.2763932023 0.8506508084 -0.4472135955
+-0.7236067977 0.5257311121 -0.4472135955
+-0.7236067977 -0.5257311121 -0.4472135955
+ 0.2763932023 -0.8506508084 -0.4472135955
+-0.2763932023 0.8506508084 0.4472135955
+-0.2763932023 -0.8506508084 0.4472135955
+-0.8944271910 -0.0000000000 0.4472135955
+ 0.7236067977 -0.5257311121 0.4472135955
+ 0.7236067977 0.5257311121 0.4472135955
+ 0.0000000000 -0.0000000000 -1.0000000000
+ 0.7236067977 0.5257311121 0.4472135955
+-0.2763932023 0.8506508084 0.4472135955
+-0.8944271910 -0.0000000000 0.4472135955
+-0.2763932023 -0.8506508084 0.4472135955
+ 0.7236067977 -0.5257311121 0.4472135955
+ 0.2763932023 -0.8506508084 -0.4472135955
+-0.0000000000 0.0000000000 -1.0000000000
+ 0.2763932023 0.8506508084 -0.4472135955
+ 0.8944271910 0.0000000000 -0.4472135955
+-0.7236067977 0.5257311121 -0.4472135955
+-0.7236067977 -0.5257311121 -0.4472135955
+ 0.0000000000 -0.0000000000 1.0000000000
+5 0 2 9 6 1 2
+5 0 3 10 8 2 2
+5 0 4 6 7 3 2
+5 0 5 8 9 4 2
+5 0 1 7 10 5 2
+5 1 4 9 11 7 2
+5 1 3 5 2 4 2
+5 1 6 11 10 3 2
+5 2 5 10 11 9 2
+5 2 8 11 6 4 2
+5 3 7 11 8 5 2
+5 6 9 8 10 7 2
+5 4 0 1 2 3
+5 4 5 6 7 0
+5 0 8 6 9 1
+5 1 7 6 10 2
+5 2 9 6 5 3
+5 3 10 6 8 4
+5 7 9 2 11 0
+5 4 11 2 10 5
+5 9 10 3 11 1
+5 5 8 0 11 3
+5 8 7 1 11 4
+5 7 9 10 5 8
+great dodecahedron
+small stellated dodecahedron
+5/2|2 5
+(5.5.5.5.5)/2
+icosahedral group
+A5
+12{5}
+39 12 30 12 12 3 0 0 -6 1 5 120 5 0 -1
+ 0.0000000000 0.0000000000 1.0000000000
+ 0.8944271910 0.0000000000 0.4472135955
+-0.7236067977 0.5257311121 0.4472135955
+ 0.2763932023 -0.8506508084 0.4472135955
+ 0.2763932023 0.8506508084 0.4472135955
+-0.7236067977 -0.5257311121 0.4472135955
+ 0.7236067977 0.5257311121 -0.4472135955
+ 0.7236067977 -0.5257311121 -0.4472135955
+-0.8944271910 -0.0000000000 -0.4472135955
+-0.2763932023 0.8506508084 -0.4472135955
+-0.2763932023 -0.8506508084 -0.4472135955
+-0.0000000000 -0.0000000000 -1.0000000000
+ 0.2763932023 0.8506508084 0.4472135955
+-0.7236067977 -0.5257311121 0.4472135955
+ 0.8944271910 0.0000000000 0.4472135955
+-0.7236067977 0.5257311121 0.4472135955
+ 0.2763932023 -0.8506508084 0.4472135955
+ 0.7236067977 0.5257311121 -0.4472135955
+ 0.0000000000 0.0000000000 1.0000000000
+ 0.7236067977 -0.5257311121 -0.4472135955
+-0.8944271910 -0.0000000000 -0.4472135955
+-0.2763932023 0.8506508084 -0.4472135955
+-0.2763932023 -0.8506508084 -0.4472135955
+-0.0000000000 -0.0000000000 -1.0000000000
+5 0 2 9 6 1
+5 0 3 10 8 2
+5 0 4 6 7 3
+5 0 5 8 9 4
+5 0 1 7 10 5
+5 1 4 9 11 7
+5 1 3 5 2 4
+5 1 6 11 10 3
+5 2 5 10 11 9
+5 2 8 11 6 4
+5 3 7 11 8 5
+5 6 9 8 10 7
+5 4 0 1 2 3
+5 4 5 6 7 0
+5 0 8 6 9 1
+5 1 7 6 10 2
+5 2 9 6 5 3
+5 3 10 6 8 4
+5 7 9 2 11 0
+5 4 11 2 10 5
+5 9 10 3 11 1
+5 5 8 0 11 3
+5 8 7 1 11 4
+5 7 9 10 5 8
+great dodecadodecahedron
+medial rhombic triacontahedron
+2|5/2 5
+(5/2.5.5/2.5)
+icosahedral group
+A5
+12{5}+12{5/2}
+40 30 60 24 30 3 0 0 -6 2 4 120 5 0 -1
+ 0.0000000000 0.0000000000 1.0000000000
+ 0.8660254038 0.0000000000 0.5000000000
+ 0.6454972244 0.5773502692 0.5000000000
+-0.8660254038 -0.0000000000 0.5000000000
+-0.6454972244 -0.5773502692 0.5000000000
+ 0.1102640897 0.5773502692 0.8090169944
+ 0.8660254038 -0.0000000000 -0.5000000000
+ 0.7557613141 -0.5773502692 -0.3090169944
+ 0.1784110449 0.9341723590 -0.3090169944
+ 0.6454972244 0.5773502692 -0.5000000000
+ 0.4670861795 -0.3568220898 0.8090169944
+-0.1102640897 -0.5773502692 0.8090169944
+-0.8660254038 0.0000000000 -0.5000000000
+-0.7557613141 0.5773502692 -0.3090169944
+-0.1784110449 -0.9341723590 -0.3090169944
+-0.6454972244 -0.5773502692 -0.5000000000
+-0.4670861795 0.3568220898 0.8090169944
+-0.3568220898 0.9341723590 -0.0000000000
+-0.7557613141 0.5773502692 0.3090169944
+ 0.7557613141 -0.5773502692 0.3090169944
+-0.0000000000 0.0000000000 -1.0000000000
+ 0.1102640897 0.5773502692 -0.8090169944
+-0.1102640897 -0.5773502692 -0.8090169944
+ 0.9341723590 0.3568220898 0.0000000000
+-0.4670861795 0.3568220898 -0.8090169944
+ 0.4670861795 -0.3568220898 -0.8090169944
+ 0.1784110449 0.9341723590 0.3090169944
+-0.1784110449 -0.9341723590 0.3090169944
+ 0.3568220898 -0.9341723590 -0.0000000000
+-0.9341723590 -0.3568220898 0.0000000000
+ 0.3035309991 0.1159385250 0.5257311121
+-0.3035309991 0.7946544723 0.5257311121
+-0.3035309991 -0.1159385250 0.5257311121
+ 0.3035309991 -0.7946544723 0.5257311121
+ 0.6070619982 -0.1159385250 -0.0000000000
+ 0.6070619982 0.7946544723 -0.0000000000
+ 0.9822469464 -0.1875924741 -0.0000000000
+ 0.3751849482 0.4911234732 -0.0000000000
+-0.6070619982 0.1159385250 -0.0000000000
+-0.6070619982 -0.7946544723 -0.0000000000
+-0.9822469464 0.1875924741 -0.0000000000
+-0.3751849482 -0.4911234732 -0.0000000000
+-0.1875924741 0.4911234732 0.3249196962
+-0.4911234732 -0.1875924741 0.8506508084
+ 0.3035309991 -0.7946544723 -0.5257311121
+ 0.3035309991 0.1159385250 -0.5257311121
+ 0.1875924741 -0.4911234732 -0.3249196962
+ 0.4911234732 0.1875924741 -0.8506508084
+-0.1875924741 0.4911234732 -0.3249196962
+-0.3035309991 0.7946544723 -0.5257311121
+ 0.1875924741 -0.4911234732 0.3249196962
+ 0.4911234732 0.1875924741 0.8506508084
+-0.3035309991 -0.1159385250 -0.5257311121
+-0.4911234732 -0.1875924741 -0.8506508084
+5 0 2 10 5 1 2
+5 0 3 13 8 2
+5 0 4 16 11 3 2
+5 0 1 7 14 4
+5 1 6 19 23 7 2
+5 1 5 17 21 6
+5 2 9 25 28 10
+5 2 8 23 26 9 2
+5 3 12 18 29 13 2
+5 3 11 28 22 12
+5 4 15 24 17 16
+5 4 14 29 27 15 2
+5 5 18 26 16 17 2
+5 5 10 27 29 18
+5 6 20 15 27 19
+5 6 21 25 9 20 2
+5 7 22 28 25 14 2
+5 7 23 8 24 22
+5 8 13 21 17 24 2
+5 9 26 18 12 20
+5 10 28 11 19 27 2
+5 11 16 26 23 19
+5 12 22 24 15 20 2
+5 13 29 14 25 21
+4 3 0 1 2
+4 3 4 5 0
+4 0 6 7 1
+4 1 8 9 2
+4 2 10 11 3
+4 5 12 13 0
+4 4 14 15 5
+4 3 16 17 4
+4 7 17 18 1
+4 6 15 19 7
+4 13 20 6 0
+4 9 20 21 2
+4 8 19 22 9
+4 18 23 8 1
+4 11 23 16 3
+4 10 22 14 11
+4 21 12 10 2
+4 5 18 10 12
+4 12 19 8 13
+4 4 21 20 14
+4 14 15 19 22
+4 15 23 18 5
+4 16 9 22 17
+4 7 21 4 17
+4 17 18 10 22
+4 6 16 23 15
+4 19 7 21 12
+4 13 11 14 20
+4 20 6 16 9
+4 23 8 13 11
+truncated great dodecahedron
+small stellapentakisdodecahedron
+2 5/2|5
+(10.10.5/2)
+icosahedral group
+A5
+12{10}+12{5/2}
+41 60 90 24 60 3 0 0 -6 2 3 120 5 0 -1
+ 0.0000000000 0.0000000000 1.0000000000
+ 0.5135543437 0.0000000000 0.8580570704
+-0.4864456563 0.1646471601 0.8580570704
+ 0.4079815347 -0.3119120569 0.8580570704
+ 0.8580570704 0.1646471601 0.4864456563
+ 0.0905874952 -0.3119120569 0.9457826254
+-0.8655497273 0.1191398043 0.4864456563
+-0.7599769183 0.4310518612 0.4864456563
+ 0.2614078885 0.1927722527 0.9457826254
+ 0.5816638682 -0.6519492065 0.4864456563
+ 0.9925073431 0.1191398043 -0.0271086873
+ 0.9019198479 0.4310518612 0.0271086873
+-0.2492845149 -0.6519492065 0.7161141409
+-0.5256777172 0.4591769538 0.7161141409
+-0.9925073431 -0.1191398043 0.0271086873
+-0.7161141409 0.6974565623 0.0271086873
+-0.6964981104 -0.0455073558 0.7161141409
+ 0.1979290806 0.6693314697 0.7161141409
+ 0.4547062524 -0.8902288150 0.0271086873
+ 0.7161141409 -0.6974565623 -0.0271086873
+ 0.8188250096 0.4591769538 0.3445027268
+ 0.8655497273 -0.1191398043 -0.4864456563
+ 0.6283885859 0.6974565623 -0.3445027268
+ 0.9653986558 -0.0455073558 0.2567771718
+-0.3762421307 -0.8902288150 0.2567771718
+-0.6283885859 -0.6974565623 0.3445027268
+-0.1027108687 0.7710890108 0.6283885859
+-0.8188250096 -0.4591769538 -0.3445027268
+-0.8580570704 -0.1646471601 -0.4864456563
+-0.5816638682 0.6519492065 -0.4864456563
+-0.3716114141 0.8621037224 -0.3445027268
+-0.5499244642 -0.5501916655 0.6283885859
+-0.0756021814 0.9357361708 0.3445027268
+ 0.2417918580 0.9357361708 0.2567771718
+ 0.7945782625 -0.5501916655 0.2567771718
+ 0.0756021814 -0.9357361708 -0.3445027268
+ 0.7599769183 -0.4310518612 -0.4864456563
+ 0.3716114141 -0.8621037224 0.3445027268
+ 0.4108434749 0.7710890108 0.4864456563
+ 0.5256777172 -0.4591769538 -0.7161141409
+ 0.4864456563 -0.1646471601 -0.8580570704
+ 0.2492845149 0.6519492065 -0.7161141409
+ 0.1419429296 0.8621037224 -0.4864456563
+-0.2417918580 -0.9357361708 -0.2567771718
+-0.9019198479 -0.4310518612 -0.0271086873
+-0.1419429296 -0.8621037224 0.4864456563
+-0.9653986558 0.0455073558 -0.2567771718
+-0.4108434749 -0.7710890108 -0.4864456563
+-0.5135543437 0.0000000000 -0.8580570704
+-0.4547062524 0.8902288150 -0.0271086873
+-0.4079815347 0.3119120569 -0.8580570704
+-0.7945782625 0.5501916655 -0.2567771718
+ 0.3762421307 0.8902288150 -0.2567771718
+-0.1979290806 -0.6693314697 -0.7161141409
+ 0.6964981104 0.0455073558 -0.7161141409
+ 0.1027108687 -0.7710890108 -0.6283885859
+ 0.0000000000 -0.0000000000 -1.0000000000
+-0.0905874952 0.3119120569 -0.9457826254
+ 0.5499244642 0.5501916655 -0.6283885859
+-0.2614078885 -0.1927722527 -0.9457826254
+ 0.1400572398 0.8506508084 0.5067318540
+-0.4053854832 -0.7608452130 0.5067318540
+ 0.1400572398 -0.0474051448 0.5067318540
+ 0.6080782248 -0.7608452130 0.2266173744
+-0.3666746142 0.1241082803 0.3588694917
+ 0.9451803665 0.2351141009 0.2266173744
+ 0.4989267315 0.1241082803 0.1196231639
+-0.6946383593 0.2351141009 0.6798521231
+-0.6080782248 0.7608452130 -0.2266173744
+-0.9451803665 -0.2351141009 -0.2266173744
+ 0.3209826314 -0.4016228318 0.1196231639
+ 0.4053854832 0.7608452130 -0.5067318540
+ 0.6946383593 -0.2351141009 -0.6798521231
+-0.2139884209 -0.4016228318 0.2674855262
+ 0.2653282434 -0.0898055953 0.9599666027
+-0.4989267315 -0.1241082803 -0.1196231639
+-0.3209826314 0.4016228318 -0.1196231639
+ 0.0739311811 0.4490279766 0.2674855262
+-0.1400572398 -0.8506508084 -0.5067318540
+ 0.3666746142 -0.1241082803 -0.3588694917
+ 0.2139884209 0.4016228318 -0.2674855262
+-0.2653282434 0.0898055953 -0.9599666027
+-0.0739311811 -0.4490279766 -0.2674855262
+-0.1400572398 0.0474051448 -0.5067318540
+10 0 2 7 15 30 42 22 11 4 1
+10 0 3 9 18 35 47 27 14 6 2
+5 0 1 5 8 3 2
+10 1 4 10 21 39 55 43 24 12 5
+5 2 6 13 16 7 2
+10 3 8 17 33 52 58 54 36 19 9
+5 4 11 23 20 10 2
+10 5 12 25 44 46 51 49 32 17 8
+10 6 14 28 48 57 41 52 33 26 13
+10 7 16 31 24 43 53 59 50 29 15
+5 9 19 37 34 18 2
+10 10 20 38 32 49 29 50 56 40 21
+10 11 22 41 57 59 53 35 18 34 23
+5 12 24 31 45 25 2
+10 13 26 38 20 23 34 37 45 31 16
+5 14 27 46 44 28 2
+5 15 29 49 51 30 2
+5 17 32 38 26 33 2
+10 19 36 40 56 48 28 44 25 45 37
+5 21 40 36 54 39 2
+5 22 42 58 52 41 2
+10 27 47 55 39 54 58 42 30 51 46
+5 35 53 43 55 47 2
+5 48 56 50 59 57 2
+3 2 0 1
+3 2 3 0
+3 0 4 1
+3 1 5 2
+3 3 6 0
+3 2 7 3
+3 4 8 1
+3 0 9 4
+3 5 7 2
+3 1 10 5
+3 3 11 6
+3 6 12 0
+3 7 13 3
+3 4 14 8
+3 8 15 1
+3 0 16 9
+3 9 14 4
+3 5 17 7
+3 1 12 10
+3 10 18 5
+3 11 14 6
+3 3 19 11
+3 12 20 0
+3 14 12 6
+3 13 9 3
+3 7 18 13
+3 14 17 8
+3 15 21 1
+3 8 18 15
+3 16 11 9
+3 0 21 16
+3 13 14 9
+3 17 11 7
+3 5 8 17
+3 14 10 12
+3 1 22 12
+3 18 19 5
+3 14 18 10
+3 11 14 17
+3 3 21 19
+3 18 11 19
+3 12 8 20
+3 20 21 0
+3 9 22 3
+3 7 15 18
+3 18 13 14
+3 7 21 15
+3 21 22 1
+3 8 23 18
+3 16 7 11
+3 11 23 9
+3 21 16 7
+3 5 20 8
+3 9 12 22
+3 21 5 19
+3 3 21 22
+3 18 11 23
+3 12 23 8
+3 20 21 5
+3 23 9 12
+rhombidodecadodecahedron
+medial deltoidal hexecontahedron
+5/2 5|2
+(4.5/2.4.5)
+icosahedral group
+A5
+12{5}+30{4}+12{5/2}
+42 60 120 54 60 3 0 0 -6 3 4 120 5 0 -1
+ 0.0000000000 0.0000000000 1.0000000000
+ 0.6998542122 0.0000000000 0.7142857143
+-0.1166423687 0.6900655593 0.7142857143
+-0.5248906592 0.4629100499 0.7142857143
+-0.3689536881 -0.5947008445 0.7142857143
+ 0.5832118435 0.6900655593 0.4285714286
+ 0.8748177653 0.4629100499 0.1428571429
+ 0.7634342145 -0.5947008445 0.2519902889
+-0.4528017108 0.0364260797 0.8908668539
+-0.6022384255 0.7854302742 0.1428571429
+-0.8938443472 -0.1317907946 0.4285714286
+-0.3499271061 0.9258200998 0.1428571429
+ 0.2077578990 0.4039714148 0.8908668539
+ 0.1028746047 -0.9622461795 0.2519902889
+-0.8545497448 -0.4993361296 0.1428571429
+ 0.9469067137 0.0364260797 0.3194382825
+ 0.5301494771 0.7854302742 -0.3194382825
+ 0.9383977675 -0.1317907946 -0.3194382825
+ 0.3499271061 0.9258200998 -0.1428571429
+ 0.4750784209 0.4039714148 0.7817337079
+ 0.7103718480 -0.4993361296 -0.4960194221
+-0.9383977675 0.1317907946 0.3194382825
+-0.0891068406 -0.6172133998 0.7817337079
+-0.2024990811 0.8443689093 -0.4960194221
+-0.9711921135 0.1907294297 -0.1428571429
+-0.9469067137 -0.0364260797 -0.3194382825
+-0.5301494771 -0.7854302742 0.3194382825
+ 0.3827214521 0.8668814647 0.3194382825
+-0.6107473716 0.6172133998 -0.4960194221
+ 0.5714527692 -0.2496680648 0.7817337079
+-0.3827214521 -0.8668814647 -0.3194382825
+ 0.0498122382 -0.8668814647 -0.4960194221
+-0.5937294793 -0.1907294297 0.7817337079
+ 0.8938443472 0.1317907946 -0.4285714286
+ 0.6107473716 -0.6172133998 0.4960194221
+ 0.5937294793 0.1907294297 -0.7817337079
+ 0.4528017108 -0.0364260797 -0.8908668539
+ 0.6022384255 -0.7854302742 -0.1428571429
+-0.0498122382 0.8668814647 0.4960194221
+ 0.0891068406 0.6172133998 -0.7817337079
+ 0.1389190789 -0.2496680648 0.9583148475
+ 0.9711921135 -0.1907294297 0.1428571429
+-0.8748177653 -0.4629100499 -0.1428571429
+-0.7634342145 0.5947008445 -0.2519902889
+-0.3499271061 -0.9258200998 0.1428571429
+-0.5714527692 0.2496680648 -0.7817337079
+-0.1389190789 0.2496680648 -0.9583148475
+-0.7103718480 0.4993361296 0.4960194221
+-0.5832118435 -0.6900655593 -0.4285714286
+-0.4750784209 -0.4039714148 -0.7817337079
+ 0.2024990811 -0.8443689093 0.4960194221
+-0.1028746047 0.9622461795 -0.2519902889
+ 0.8545497448 0.4993361296 -0.1428571429
+ 0.3499271061 -0.9258200998 -0.1428571429
+-0.2077578990 -0.4039714148 -0.8908668539
+ 0.5248906592 -0.4629100499 -0.7142857143
+ 0.3689536881 0.5947008445 -0.7142857143
+ 0.1166423687 -0.6900655593 -0.7142857143
+-0.6998542122 0.0000000000 -0.7142857143
+-0.0000000000 0.0000000000 -1.0000000000
+ 0.3126527364 0.3699357065 0.7658396707
+-0.1612652036 0.2898289539 0.7658396707
+-0.4791790224 -0.0706514331 0.7658396707
+ 0.3126527364 -0.5619055661 0.7658396707
+ 0.8782468497 -0.0706514331 0.2116728790
+ 0.6511655506 0.2898289539 0.4341662042
+ 0.0501361976 0.9911632216 0.1228081018
+-0.5655941134 0.4405871397 0.5541667917
+-0.0762151731 0.7128849670 0.5541667917
+-0.8686716880 0.4799246488 0.1228081018
+-0.5895677240 -0.4005337633 0.4341662042
+-0.4029638493 -0.7835364001 0.2116728790
+ 0.7918317588 0.4405871397 -0.0000000000
+ 0.7064275445 0.4799246488 -0.5202234672
+ 0.4422753728 0.7128849670 0.3424939127
+ 0.4359714769 -0.7835364001 -0.1308210337
+ 0.7249728497 -0.4005337633 -0.1024927377
+-0.7064275445 -0.4799246488 0.5202234672
+ 0.0636073813 -0.1143164201 0.8966607045
+-0.6292014946 0.5549035598 -0.3424939127
+-0.7249728497 0.4005337633 0.1024927377
+-0.7918317588 -0.4405871397 -0.0000000000
+ 0.0418424850 0.8272013871 0.1024927377
+-0.1398225544 0.8272013871 -0.3424939127
+ 0.7802348436 0.3472767383 0.5202234672
+-0.0418424850 -0.8272013871 -0.1024927377
+-0.8389353262 0.0000000000 0.3424939127
+-0.7802348436 -0.3472767383 -0.5202234672
+ 0.5820979272 -0.1143164201 0.6849878255
+ 0.8686716880 -0.4799246488 -0.1228081018
+ 0.5895677240 0.4005337633 -0.4341662042
+ 0.2097338315 0.5549035598 -0.6849878255
+ 0.5655941134 -0.4405871397 -0.5541667917
+-0.1932300177 0.3472767383 0.9176388327
+ 0.1932300177 -0.3472767383 -0.9176388327
+ 0.8389353262 -0.0000000000 -0.3424939127
+-0.8782468497 0.0706514331 -0.2116728790
+ 0.1398225544 -0.8272013871 0.3424939127
+ 0.2609325806 -0.4689530983 0.6391516797
+-0.2609325806 0.4689530983 -0.6391516797
+-0.5820979272 0.1143164201 -0.6849878255
+-0.6511655506 -0.2898289539 -0.4341662042
+-0.0501361976 -0.9911632216 -0.1228081018
+-0.2097338315 -0.5549035598 0.6849878255
+ 0.4029638493 0.7835364001 -0.2116728790
+ 0.6292014946 -0.5549035598 0.3424939127
+ 0.0762151731 -0.7128849670 -0.5541667917
+-0.4422753728 -0.7128849670 -0.3424939127
+ 0.4791790224 0.0706514331 -0.7658396707
+ 0.1612652036 -0.2898289539 -0.7658396707
+-0.0636073813 0.1143164201 -0.8966607045
+-0.4359714769 0.7835364001 0.1308210337
+-0.3126527364 0.5619055661 -0.7658396707
+-0.3126527364 -0.3699357065 -0.7658396707
+4 0 2 5 1
+5 0 3 12 8 2 2
+4 0 4 10 3
+5 0 1 7 13 4
+4 1 6 17 7
+5 1 5 15 19 6 2
+5 2 9 23 16 5
+4 2 8 21 9
+4 3 11 27 12
+5 3 10 25 28 11
+5 4 14 32 26 10 2
+4 4 13 30 14
+4 5 16 33 15
+5 6 18 39 36 17
+4 6 19 38 18
+4 7 20 31 13
+5 7 17 37 41 20 2
+5 8 22 44 42 21
+4 8 12 29 22
+4 9 24 45 23
+5 9 21 43 47 24 2
+4 10 26 48 25
+5 11 18 38 51 27 2
+4 11 28 39 18
+5 12 27 52 41 29
+5 13 31 44 53 30 2
+4 14 24 47 32
+5 14 30 54 45 24
+4 15 34 40 19
+5 15 33 55 53 34
+5 16 35 52 56 33 2
+4 16 23 46 35
+4 17 36 57 37
+5 19 40 32 47 38
+5 20 35 46 49 31
+4 20 41 52 35
+4 21 42 58 43
+4 22 34 53 44
+5 22 29 50 40 34 2
+5 23 45 39 28 46 2
+4 25 49 46 28
+5 25 48 58 42 49 2
+5 26 50 37 57 48
+4 26 32 40 50
+4 27 51 56 52
+4 29 41 37 50
+4 30 53 55 54
+4 31 49 42 44
+4 33 56 59 55
+5 36 54 55 59 57 2
+4 36 39 45 54
+4 38 47 43 51
+5 43 58 59 56 51
+4 48 57 59 58
+4 3 0 1 2
+4 3 4 5 0
+4 0 6 7 1
+4 1 8 9 2
+4 2 10 11 3
+4 5 12 6 0
+4 4 13 14 5
+4 3 15 16 4
+4 7 17 18 1
+4 6 19 20 7
+4 9 21 10 2
+4 8 22 23 9
+4 18 24 8 1
+4 11 25 15 3
+4 10 26 27 11
+4 5 28 29 12
+4 12 30 31 6
+4 16 32 13 4
+4 13 23 22 14
+4 14 33 28 5
+4 15 34 35 16
+4 20 36 17 7
+4 17 37 38 18
+4 31 39 19 6
+4 19 27 26 20
+4 9 40 41 21
+4 21 42 43 10
+4 24 44 22 8
+4 23 39 40 9
+4 38 45 24 18
+4 27 46 25 11
+4 25 47 34 15
+4 43 33 26 10
+4 29 48 30 12
+4 28 38 37 29
+4 30 35 34 31
+4 32 49 50 13
+4 16 45 42 32
+4 22 51 33 14
+4 50 39 23 13
+4 43 38 28 33
+4 35 24 45 16
+4 36 41 47 17
+4 20 51 52 36
+4 25 37 17 47
+4 50 27 19 39
+4 34 40 39 31
+4 26 20 51 33
+4 41 53 42 21
+4 40 41 47 34
+4 42 43 38 45
+4 44 52 51 22
+4 30 44 24 35
+4 46 29 37 25
+4 49 46 27 50
+4 49 48 29 46
+4 48 52 44 30
+4 53 49 32 42
+4 52 53 41 36
+4 49 48 52 53
+small rhombidodecahedron
+small rhombidodecacron
+2 5/2 5|
+(10.4.10/9.4/3)
+icosahedral group
+A5
+6{10}+15{4}+15{4/3}+6{10/9}
+43 60 120 42 60 0 0 1 -18 4 4 120 5 0 1
+ 0.0000000000 0.0000000000 1.0000000000
+ 0.4364663517 0.0000000000 0.8997205810
+-0.3947875239 0.1861335198 0.8997205810
+-0.1650346033 -0.4040624406 0.8997205810
+-0.0230394894 0.4358578416 0.8997205810
+ 0.7478962199 0.1861335198 0.6371856536
+ 0.5411827887 -0.4040624406 0.7374650726
+ 0.4134268623 0.4358578416 0.7994411620
+-0.5598221272 -0.2179289208 0.7994411620
+-0.5971008041 0.4873038812 0.6371856536
+-0.4551056902 -0.6219913614 0.6371856536
+ 0.1694347542 -0.6537867624 0.7374650726
+-0.2253527696 0.7370282030 0.6371856536
+ 0.8526126568 -0.2179289208 0.4749301452
+ 0.8153339799 0.4873038812 0.3126746369
+ 0.6875780535 -0.6219913614 0.3746507262
+ 0.4808646224 0.7370282030 0.4749301452
+-0.8641324015 -0.1664828812 0.4749301452
+-0.5296630440 0.7884742426 0.3126746369
+-0.8871718909 0.2693749604 0.3746507262
+-0.1206363326 -0.8717156832 0.4749301452
+-0.7594159645 -0.5705453218 0.3126746369
+ 0.3158300191 -0.8717156832 0.3746507262
+ 0.0860770985 0.9231617228 0.3746507262
+ 0.9847687342 -0.1664828812 0.0501397095
+ 0.6130206997 0.7884742426 0.0501397095
+ 0.9617292448 0.2693749604 -0.0501397095
+ 0.8197341309 -0.5705453218 -0.0501397095
+-0.9617292448 -0.2693749604 0.0501397095
+-0.8197341309 0.5705453218 0.0501397095
+-0.2182331759 0.9746077624 0.0501397095
+-0.9847687342 0.1664828812 -0.0501397095
+-0.2182331759 -0.9746077624 0.0501397095
+-0.6130206997 -0.7884742426 -0.0501397095
+ 0.2182331759 -0.9746077624 -0.0501397095
+ 0.2182331759 0.9746077624 -0.0501397095
+ 0.8871718909 -0.2693749604 -0.3746507262
+ 0.7594159645 0.5705453218 -0.3126746369
+ 0.8641324015 0.1664828812 -0.4749301452
+ 0.5296630440 -0.7884742426 -0.3126746369
+-0.8153339799 -0.4873038812 -0.3126746369
+-0.6875780535 0.6219913614 -0.3746507262
+-0.3158300191 0.8717156832 -0.3746507262
+-0.8526126568 0.2179289208 -0.4749301452
+-0.0860770985 -0.9231617228 -0.3746507262
+-0.4808646224 -0.7370282030 -0.4749301452
+ 0.1206363326 0.8717156832 -0.4749301452
+ 0.5971008041 -0.4873038812 -0.6371856536
+ 0.4551056902 0.6219913614 -0.6371856536
+ 0.5598221272 0.2179289208 -0.7994411620
+ 0.2253527696 -0.7370282030 -0.6371856536
+-0.7478962199 -0.1861335198 -0.6371856536
+-0.5411827887 0.4040624406 -0.7374650726
+-0.1694347542 0.6537867624 -0.7374650726
+-0.4134268623 -0.4358578416 -0.7994411620
+ 0.3947875239 -0.1861335198 -0.8997205810
+ 0.1650346033 0.4040624406 -0.8997205810
+ 0.0230394894 -0.4358578416 -0.8997205810
+-0.4364663517 0.0000000000 -0.8997205810
+ 0.0000000000 -0.0000000000 -1.0000000000
+ 0.1583346290 0.7071067812 0.6891517578
+-0.2144012325 -0.0834626339 0.6891517578
+-0.7144788670 0.1207882584 0.6891517578
+ 0.1583346290 0.1669252677 0.6891517578
+ 0.9436228948 0.1207882584 0.3081980354
+ 0.4936927550 -0.0834626339 0.5264650961
+-0.2375019436 0.3535533906 0.5886058714
+ 0.2124281962 -0.3162277660 0.9245941063
+-0.4686190076 -0.8278950396 0.3081980354
+-0.1094065379 -0.4885987690 0.5264650961
+ 0.4705920439 0.3535533906 0.4259192097
+ 0.3282196136 -0.4885987690 0.4259192097
+ 0.5561442379 -0.8278950396 0.0727556869
+-0.5052431105 -0.3019706461 0.4259192097
+-0.5426208461 0.4051361351 0.2632325481
+-0.5561442379 0.8278950396 -0.0727556869
+-0.1698849846 0.6555240367 0.2632325481
+ 0.6404770285 -0.3019706461 0.1626866616
+ 0.4686190076 0.8278950396 -0.3081980354
+ 0.6030992928 0.4051361351 0.0000000000
+ 0.2677411669 0.6555240367 0.1626866616
+-0.9436228948 -0.1207882584 -0.3081980354
+-0.7080939875 0.0000000000 0.1626866616
+ 0.0373777356 -0.7071067812 0.1626866616
+-0.6030992928 -0.4051361351 -0.0000000000
+ 0.7080939875 -0.0000000000 -0.1626866616
+ 0.7144788670 -0.1207882584 -0.6891517578
+ 0.5426208461 -0.4051361351 -0.2632325481
+-0.6404770285 0.3019706461 -0.1626866616
+-0.0373777356 0.7071067812 -0.1626866616
+-0.2677411669 -0.6555240367 -0.1626866616
+-0.1583346290 -0.7071067812 -0.6891517578
+ 0.1698849846 -0.6555240367 -0.2632325481
+ 0.5052431105 0.3019706461 -0.4259192097
+-0.4705920439 -0.3535533906 -0.4259192097
+-0.2124281962 0.3162277660 -0.9245941063
+-0.3282196136 0.4885987690 -0.4259192097
+-0.4936927550 0.0834626339 -0.5264650961
+ 0.1094065379 0.4885987690 -0.5264650961
+ 0.2375019436 -0.3535533906 -0.5886058714
+ 0.2144012325 0.0834626339 -0.6891517578
+-0.1583346290 -0.1669252677 -0.6891517578
+10 0 2 9 18 30 35 25 14 5 1
+4 0 3 8 2
+10 0 4 12 18 29 31 28 21 10 3 9
+4 0 1 7 4 3
+10 1 6 15 27 36 38 37 25 16 7 9
+4 1 5 13 6
+4 2 4 12 9 3
+10 2 8 10 20 22 15 13 5 7 4 9
+10 3 11 22 34 44 45 40 28 17 8
+4 3 10 20 11 3
+4 5 14 16 7 3
+4 6 11 22 15 3
+10 6 13 24 36 47 50 44 32 20 11
+4 8 17 21 10 3
+4 9 19 29 18
+10 9 12 23 35 46 53 52 43 31 19 9
+4 12 23 30 18 3
+4 13 15 27 24 3
+10 14 26 38 49 56 53 42 30 23 16 9
+4 14 25 37 26
+4 16 25 35 23 3
+10 17 19 29 41 52 58 54 45 33 21 9
+4 17 28 31 19
+4 20 22 34 32
+4 21 28 40 33 3
+4 24 26 38 36
+10 24 27 39 50 57 59 56 48 37 26 9
+4 27 39 47 36 3
+4 29 41 43 31 3
+4 30 42 46 35
+4 32 33 45 44 3
+10 32 34 39 47 55 59 58 51 40 33
+4 34 39 50 44
+4 37 38 49 48 3
+4 40 45 54 51
+10 41 42 46 48 49 55 57 54 51 43 9
+4 41 52 53 42
+4 43 52 58 51 3
+4 46 53 56 48
+4 47 55 57 50
+4 49 55 59 56 3
+4 54 57 59 58
+4 3 0 1 2
+4 3 4 5 0
+4 0 6 7 1
+4 1 8 9 2
+4 2 6 7 3
+4 5 7 10 0
+4 4 11 12 5
+4 10 4 3 7
+4 7 13 8 1
+4 0 14 15 6
+4 9 7 13 2
+4 8 11 12 9
+4 2 16 15 6
+4 12 17 7 5
+4 10 18 19 0
+4 4 17 7 11
+4 18 20 4 10
+4 13 21 22 8
+4 0 16 2 14
+4 14 21 22 15
+4 12 23 7 9
+4 21 24 2 13
+4 8 23 7 11
+4 16 18 20 15
+4 12 25 26 17
+4 19 4 20 0
+4 18 25 26 19
+4 4 27 26 17
+4 22 2 24 8
+4 2 28 21 14
+4 0 29 18 16
+4 28 15 22 2
+4 12 30 31 23
+4 21 30 31 24
+4 8 32 31 23
+4 29 15 20 0
+4 12 27 4 25
+4 26 33 4 19
+4 18 33 4 25
+4 27 31 32 26
+4 31 34 8 24
+4 28 35 36 21
+4 29 35 36 18
+4 35 37 15 28
+4 12 32 8 30
+4 21 34 8 30
+4 35 38 15 29
+4 12 39 31 27
+4 26 38 35 33
+4 18 40 35 33
+4 39 26 32 12
+4 31 37 35 34
+4 36 15 37 21
+4 38 18 36 15
+4 21 41 35 34
+4 39 35 40 31
+4 26 40 18 38
+4 41 26 39 35
+4 31 41 21 37
+4 40 31 41 26
+snub dodecadodecahedron
+medial pentagonal hexecontahedron
+|2 5/2 5
+(3.3.5/2.3.5)
+icosahedral group
+A5
+12{5}+60{3}+12{5/2}
+44 60 150 84 60 3 0 0 -6 3 5 120 5 0 -1
+ 0.0000000000 0.0000000000 1.0000000000
+ 0.7217483383 0.0000000000 0.6921555722
+ 0.2952223438 0.6586079498 0.6921555722
+-0.4802341493 0.5387910779 0.6921555722
+-0.7128072909 0.1132538291 0.6921555722
+-0.3949112124 -0.6041239924 0.6921555722
+ 0.7729021303 -0.6041239924 0.1940528249
+ 0.9929356725 0.1132538291 -0.0353881415
+ 0.6298389795 0.6967741838 0.3432325693
+ 0.8934465412 0.2897320856 0.3432325693
+ 0.5094943059 0.8597460274 -0.0353881415
+-0.7452206567 0.6658782563 -0.0353881415
+-0.9392275176 0.0065630428 0.3432325693
+-0.4160062641 -0.2197373699 0.8824138918
+-0.0396950161 0.4687963622 0.8824138918
+-0.5127015231 0.7869743017 0.3432325693
+-0.9061974527 -0.4015688916 0.1324711369
+-0.6380905382 -0.7691476741 -0.0353881415
+ 0.0827685741 -0.9774931531 0.1940528249
+ 0.4161165893 -0.7691476741 -0.4850348850
+ 0.8899385998 -0.1459468565 -0.4320981413
+ 0.7539503920 -0.5893107329 -0.2902958256
+ 0.6655112749 0.0439566123 -0.7450923159
+ 0.0780084845 0.9881123794 -0.1324711369
+-0.1041736883 0.7897513117 0.6045169215
+ 0.3520254514 0.2279778217 0.9078018475
+ 0.6780508743 -0.4180984375 0.6045169215
+ 0.8524892978 0.2817520197 -0.4403155647
+ 0.5063993531 0.4753594049 -0.7194394563
+-0.1335348318 0.8642393240 -0.4850348850
+-0.6262555055 0.3003513119 -0.7194394563
+-0.9884363197 -0.0737905134 -0.1324711369
+-0.8685334856 0.3336886979 -0.3664716051
+-0.8461505251 -0.4469425270 -0.2902958256
+ 0.0004392467 -0.8131042863 0.5821178804
+ 0.3680207594 -0.2011380776 0.9078018475
+ 0.2609051739 0.9140614801 0.3105158625
+-0.5824195190 0.6885337320 -0.4320981413
+-0.8256133779 -0.0460263585 -0.5623558700
+-0.4967433944 -0.7479092215 -0.4403155647
+-0.3220982637 -0.8943336110 0.3105158625
+-0.7559043639 -0.2995786473 0.5821178804
+-0.0593841233 -0.8247602084 -0.5623558700
+-0.2654045267 -0.9535247958 -0.1426565840
+-0.2602607645 -0.5330006997 -0.8050929068
+ 0.8544020838 0.5193160172 -0.0175486021
+ 0.9206031564 -0.1699152137 0.3515944377
+ 0.4508730059 -0.7963143545 0.4032331602
+ 0.1682912484 -0.5593947155 -0.8116376088
+-0.0520696708 -0.1637734841 -0.9851228326
+ 0.1000551755 0.5846489317 -0.8050929068
+-0.4001067482 0.9095681836 -0.1122511001
+-0.7889119713 0.4637034829 0.4032331602
+-0.0507662577 -0.4452651179 0.8939584788
+ 0.5039717878 -0.8635418251 -0.0175486021
+ 0.6117806625 -0.4310104555 -0.6632905911
+ 0.2552292055 0.2091181436 -0.9439955798
+ 0.2944167902 0.8325793470 -0.4691805458
+-0.2044629478 0.2361469744 -0.9499628990
+-0.4635135922 -0.0992132343 -0.8805179635
+ 0.3176067784 0.2056876888 0.7446363937
+-0.0577804302 0.3739557632 0.7446363937
+-0.2958960533 0.1617190385 0.7446363937
+-0.3459479328 -0.1533020508 0.7446363937
+ 0.3176067784 -0.5870626674 0.7446363937
+ 0.7768898692 -0.1533020508 0.2657168836
+ 0.7322102858 0.2529771921 0.3123067203
+ 0.5190711176 0.3361595084 0.5345585472
+ 0.5303477767 0.5646774283 0.3123067203
+-0.1488707758 0.9634937711 0.2225247069
+-0.6760448370 0.3782760112 0.3123067203
+-0.5732289698 0.1016922995 0.5989424632
+-0.3951316587 0.4275555494 0.5989424632
+-0.9507295624 0.3065030456 0.0465744808
+-0.6289594872 -0.2787147143 0.4737012997
+-0.5414902536 -0.5327952207 0.3018417444
+-0.2967642069 -0.7341596510 0.2657168836
+ 0.3971877186 -0.7341596510 -0.0302716515
+ 0.6492723420 -0.4744621543 -0.2258228062
+ 0.7771543287 -0.2505446113 -0.0380713515
+ 0.7534079011 -0.1349478249 -0.3344106292
+ 0.6624305789 0.6517935348 -0.3692572492
+ 0.1885313770 0.7728460386 0.2546169088
+ 0.2741087173 0.5354509080 0.5795011528
+ 0.6007291180 0.0311093314 0.5795011528
+ 0.9507295624 -0.3065030456 -0.0465744808
+ 0.7043859914 0.4469827888 -0.0413716263
+ 0.5414902536 0.5327952207 -0.3018417444
+ 0.2755665915 0.6868701477 -0.3872173856
+-0.4700250476 0.5716677363 -0.3872173856
+-0.7370165274 0.2787147143 -0.2771093578
+-0.7771543287 0.2505446113 0.0380713515
+-0.8288344054 -0.0333202496 -0.0979190443
+-0.6624305789 -0.6517935348 0.3692572492
+-0.0148490159 -0.3853801636 0.7408957323
+-0.0273832159 0.0149660237 0.8346801947
+ 0.6350041919 0.4112397892 0.6539506954
+-0.0910347123 0.6776531605 0.4797538171
+-0.1216913541 0.7875881686 0.1818982454
+-0.3176510871 0.7694052113 -0.0691249417
+-0.6959924610 -0.3733640806 -0.2717694010
+-0.5387413071 -0.6382961364 0.0008343070
+-0.7440492812 -0.3568156856 0.1293757453
+-0.6350041919 -0.4112397892 -0.6539506954
+-0.1919768421 -0.8030658240 -0.1260754705
+ 0.1216913541 -0.7875881686 -0.1818982454
+-0.0342127958 -0.7044618897 -0.4474681893
+ 0.3619836047 -0.1978385309 -0.9109488381
+ 0.7029212391 0.2650636348 -0.3651134768
+ 0.8322798705 0.0635400349 -0.0306223940
+ 0.6637849964 -0.4858056897 0.1450763943
+ 0.1488707758 -0.9634937711 -0.2225247069
+ 0.4958659056 -0.3450204858 -0.5768385544
+ 0.2958960533 -0.1617190385 -0.7446363937
+ 0.2228298392 0.1451701761 -0.7917937437
+-0.1262830522 0.7062176385 -0.4277547049
+-0.4038726796 0.6755266122 0.2796703500
+-0.3619836047 0.1978385309 0.9109488381
+ 0.3058451155 -0.1984352346 0.7514965554
+ 0.2596211293 -0.4798823043 0.6086877063
+ 0.3692908006 -0.6542027999 0.3651134768
+ 0.5370111450 0.0186945890 -0.6394797825
+ 0.4378962749 0.4133221760 -0.5788579109
+ 0.0525929431 0.4921159726 -0.6728452286
+-0.2596211293 0.4798823043 -0.6086877063
+-0.1805976074 0.2252439638 -0.7837821833
+-0.7911518284 0.0282120159 0.2663601255
+-0.6425873810 0.5330951931 -0.0235758922
+-0.3176067784 0.5870626674 -0.7446363937
+-0.6802657495 -0.0663548917 -0.4801045596
+-0.5190711176 -0.3361595084 -0.5345585472
+-0.4284272985 -0.6038350569 -0.3866498724
+ 0.0746433386 -0.8214200499 0.1317661698
+ 0.5432565786 -0.3645767609 0.5192503492
+ 0.4402662939 0.7076735504 -0.0550325933
+ 0.0484747550 0.8295519246 -0.0846088198
+-0.5035932888 0.2744096577 -0.6072544682
+-0.4029809447 -0.1070837544 -0.7237432401
+-0.2473362223 -0.4392647648 -0.6659850669
+ 0.0243625739 -0.6670600099 0.5020978570
+-0.3525221086 -0.5119261104 0.5579647573
+ 0.1562554434 -0.4433331772 -0.6904381075
+ 0.3299109277 -0.6618755327 -0.3882581729
+-0.0124901259 -0.1403786872 -0.8232877205
+3 0 2 1
+3 0 3 2
+5 0 4 14 13 3 2
+3 0 5 4
+5 0 1 6 18 5
+3 1 7 6
+3 1 8 7
+5 1 2 9 25 8 2
+3 2 10 9
+5 2 3 11 29 10
+3 3 12 11
+3 3 13 12
+3 4 15 14
+5 4 16 38 37 15
+3 4 5 16
+5 5 17 41 40 16 2
+3 5 18 17
+3 6 19 18
+3 6 20 19
+5 6 7 21 46 20 2
+3 7 22 21
+5 7 8 23 50 22
+3 8 24 23
+3 8 25 24
+3 9 26 25
+5 9 27 55 54 26
+3 9 10 27
+5 10 28 45 57 27 2
+3 10 29 28
+3 11 30 29
+3 11 31 30
+5 11 12 32 52 31 2
+3 12 33 32
+5 12 13 34 43 33
+3 13 35 34
+3 13 14 35
+5 14 36 45 46 35
+3 14 15 36
+5 15 23 24 51 36 2
+3 15 37 23
+3 16 39 38
+3 16 40 39
+3 17 31 41
+5 17 42 49 30 31
+3 17 18 42
+5 18 19 43 54 42 2
+3 19 44 43
+5 19 20 28 58 44
+3 20 45 28
+3 20 46 45
+3 21 47 46
+5 21 48 39 40 47
+3 21 22 48
+5 22 49 55 56 48 2
+3 22 50 49
+3 23 37 50
+3 24 52 51
+5 24 25 53 41 52
+3 25 26 53
+5 26 34 35 47 53 2
+3 26 54 34
+3 27 56 55
+3 27 57 56
+3 28 29 58
+5 29 30 50 37 58 2
+3 30 49 50
+3 31 52 41
+3 32 51 52
+5 32 59 56 57 51
+3 32 33 59
+5 33 44 38 39 59 2
+3 33 43 44
+3 34 54 43
+3 35 46 47
+3 36 57 45
+3 36 51 57
+3 37 38 58
+3 38 44 58
+3 39 48 59
+3 40 53 47
+3 40 41 53
+3 42 55 49
+3 42 54 55
+3 48 56 59
+5 4 0 1 2 3
+5 4 5 6 7 0
+5 7 8 9 1 0
+5 9 10 11 2 1
+5 2 12 13 14 3
+5 14 15 16 4 3
+5 4 17 18 19 5
+5 19 20 21 6 5
+5 21 22 23 7 6
+5 7 24 25 26 8
+5 26 27 28 9 8
+5 9 29 30 31 10
+5 31 32 33 11 10
+5 33 34 35 2 11
+5 35 36 37 12 2
+5 37 38 39 13 12
+5 13 40 41 15 14
+5 15 42 43 44 16
+5 44 45 17 4 16
+5 45 46 47 18 17
+5 47 48 49 19 18
+5 19 50 51 52 20
+5 52 53 54 21 20
+5 21 55 39 38 22
+5 38 56 57 23 22
+5 57 58 24 7 23
+5 58 59 60 25 24
+5 25 61 62 27 26
+5 27 48 47 63 28
+5 63 64 29 9 28
+5 64 65 43 30 29
+5 42 66 31 30 43
+5 31 67 68 69 32
+5 69 70 71 33 32
+5 33 72 60 59 34
+5 59 73 36 35 34
+5 36 74 75 38 37
+5 55 64 76 13 39
+5 76 77 70 40 13
+5 70 78 51 41 40
+5 51 79 80 15 41
+5 80 57 66 42 15
+5 43 81 82 45 44
+5 45 72 33 71 46
+5 77 47 46 71 70
+5 27 74 36 49 48
+5 73 50 19 49 36
+5 59 79 51 50 73
+5 78 83 53 52 51
+5 53 81 43 65 54
+5 54 21 55 64 65
+5 75 68 67 56 38
+5 56 57 66 31 67
+5 57 58 59 79 80
+5 82 25 60 72 45
+5 53 61 25 82 81
+5 83 68 62 61 53
+5 62 27 74 75 68
+5 47 63 64 76 77
+5 68 69 70 78 83
+ditrigonal dodecadodecahedron
+medial triambic icosahedron
+3|5/3 5
+(5/3.5.5/3.5.5/3.5)
+icosahedral group
+A5
+12{5}+12{5/3}
+45 20 60 24 20 4 0 0 -16 2 6 120 5 0 -1
+ 0.0000000000 0.0000000000 1.0000000000
+ 0.9428090416 0.0000000000 0.3333333333
+ 0.6727182848 -0.6605596098 0.3333333333
+-0.4714045208 0.8164965809 0.3333333333
+ 0.2357022604 0.9128709292 0.3333333333
+-0.4714045208 -0.8164965809 0.3333333333
+-0.9084205452 -0.2523113194 0.3333333333
+ 0.0900302522 -0.6605596098 0.7453559925
+ 0.4714045208 0.8164965809 -0.3333333333
+ 0.4714045208 -0.8164965809 -0.3333333333
+ 0.6170765289 -0.2523113194 -0.7453559925
+ 0.9084205452 0.2523113194 -0.3333333333
+-0.2357022604 -0.9128709292 -0.3333333333
+ 0.5270462767 0.4082482905 0.7453559925
+-0.9428090416 -0.0000000000 -0.3333333333
+-0.0900302522 0.6605596098 -0.7453559925
+-0.6727182848 0.6605596098 -0.3333333333
+-0.6170765289 0.2523113194 0.7453559925
+-0.5270462767 -0.4082482905 -0.7453559925
+ 0.0000000000 0.0000000000 -1.0000000000
+ 0.1326479105 -0.0542373073 0.1875924741
+ 0.7765343938 0.6015009550 0.1875924741
+-0.0193530693 0.1419951139 0.1875924741
+-0.9091823043 0.3717480345 0.1875924741
+-0.1132948412 -0.0877578066 0.1875924741
+ 0.1326479105 -0.9732489895 0.1875924741
+ 0.2146288278 -0.0877578066 -0.0442845760
+ 0.4799246488 0.3717480345 -0.7946544723
+ 0.1833149038 0.1419951139 0.0442845760
+-0.0819809172 0.6015009550 0.7946544723
+-0.4799246488 -0.3717480345 0.7946544723
+ 0.0313139240 -0.2297529205 0.0442845760
+ 0.0819809172 -0.6015009550 -0.7946544723
+-0.0313139240 0.2297529205 -0.0442845760
+-0.5619055661 0.2297529205 -0.7946544723
+-0.2146288278 0.0877578066 0.0442845760
+ 0.5619055661 -0.2297529205 0.7946544723
+-0.1833149038 -0.1419951139 -0.0442845760
+-0.7765343938 -0.6015009550 -0.1875924741
+ 0.9091823043 -0.3717480345 -0.1875924741
+ 0.1132948412 0.0877578066 -0.1875924741
+ 0.0193530693 -0.1419951139 -0.1875924741
+-0.1326479105 0.9732489895 -0.1875924741
+-0.1326479105 0.0542373073 -0.1875924741
+5 0 2 13 7 1 3
+5 0 3 15 10 2
+5 0 4 17 13 3 3
+5 0 5 18 15 4
+5 0 6 7 17 5 3
+5 0 1 10 18 6
+5 1 9 11 2 10 3
+5 1 4 16 18 9
+5 1 8 13 11 4 3
+5 1 7 6 16 8
+5 2 12 14 3 13
+5 2 5 9 7 12 3
+5 2 11 15 14 5
+5 3 8 16 4 15 3
+5 3 6 12 10 8
+5 3 14 17 16 6 3
+5 4 11 9 5 17
+5 5 14 12 6 18 3
+5 7 9 19 16 17
+5 7 13 8 19 12
+5 8 10 15 11 19 3
+5 9 18 10 12 19 3
+5 11 13 17 14 19
+5 14 15 18 16 19 3
+6 5 0 1 2 3 4
+6 5 6 7 8 9 0
+6 0 10 11 12 6 1
+6 1 13 14 15 10 2
+6 2 16 8 7 13 3
+6 3 17 12 11 16 4
+6 4 9 15 14 17 5
+6 4 18 11 19 0 9
+6 8 19 20 14 13 9
+6 6 16 11 18 21 7
+6 5 21 14 20 1 6
+6 12 20 22 8 16 6
+6 10 17 14 21 19 11
+6 22 2 10 0 19 8
+6 15 22 23 12 17 10
+6 23 3 13 1 20 12
+6 7 23 18 15 9 13
+6 2 16 4 18 15 22
+6 3 17 5 21 7 23
+6 19 20 22 23 18 21
+great ditrigonal dodecicosidodecahedron
+great ditrigonal dodecacronic hexecontahedron
+3 5|5/3
+(10/3.3.10/3.5)
+icosahedral group
+A5
+12{5}+12{10/3}+20{3}
+46 60 120 44 60 4 0 0 -16 3 4 120 5 0 -1
+ 0.0000000000 0.0000000000 1.0000000000
+ 0.7913673487 0.0000000000 0.6113409191
+ 0.1126514014 0.7833083316 0.6113409191
+-0.6820030709 0.4014151117 0.6113409191
+-0.4944105968 -0.6179162098 0.6113409191
+ 0.4149268310 0.7833083316 0.4628863603
+ 0.9007316265 0.4014151117 -0.1659772426
+ 0.7860486710 -0.6179162098 -0.0175226837
+-0.2691077939 0.9487004534 -0.1659772426
+ 0.8343963552 0.2991971590 0.4628863603
+-0.7549125894 -0.4645892808 0.4628863603
+-0.5726387930 0.8028302234 -0.1659772426
+-0.0086058013 -0.9998094297 -0.0175226837
+-0.8761697921 -0.4525240881 -0.1659772426
+-0.8708511144 0.1653921218 0.4628863603
+ 0.0331676357 0.9487004534 -0.3144318014
+-0.1437874830 0.2991971590 0.9432954043
+ 0.8278221080 -0.4645892808 -0.3144318014
+ 0.2187285557 0.8028302234 -0.5546363234
+ 0.4042894756 -0.4525240881 -0.7948408455
+ 0.8987000724 0.1653921218 -0.4061817646
+ 0.2166970016 0.5668072335 -0.7948408455
+-0.7635183907 0.3307842435 -0.5546363234
+-0.8278221080 0.4645892808 0.3144318014
+ 0.2756820411 -0.1849140136 0.9432954043
+ 0.7614868366 -0.5668072335 0.3144318014
+-0.6906088722 -0.5983943180 -0.4061817646
+-0.0331676357 -0.9487004534 0.3144318014
+-0.0278489580 -0.3307842435 0.9432954043
+ 0.1544248384 0.9366352607 0.3144318014
+-0.5779574707 0.1849140136 -0.7948408455
+ 0.1007584765 -0.5983943180 -0.7948408455
+-0.1544248384 -0.9366352607 -0.3144318014
+-0.7614868366 0.5668072335 -0.3144318014
+ 0.0278489580 0.3307842435 -0.9432954043
+ 0.7549125894 0.4645892808 -0.4628863603
+ 0.5779574707 -0.1849140136 0.7948408455
+-0.2166970016 -0.5668072335 0.7948408455
+ 0.2691077939 -0.9487004534 0.1659772426
+ 0.7635183907 -0.3307842435 0.5546363234
+-0.2756820411 0.1849140136 -0.9432954043
+ 0.1437874830 -0.2991971590 -0.9432954043
+-0.1007584765 0.5983943180 0.7948408455
+-0.9007316265 -0.4014151117 0.1659772426
+-0.2187285557 -0.8028302234 0.5546363234
+ 0.8708511144 -0.1653921218 -0.4628863603
+-0.4149268310 -0.7833083316 -0.4628863603
+-0.4042894756 0.4525240881 0.7948408455
+ 0.8761697921 0.4525240881 0.1659772426
+ 0.5726387930 -0.8028302234 0.1659772426
+-0.8343963552 -0.2991971590 -0.4628863603
+ 0.6906088722 0.5983943180 0.4061817646
+ 0.6820030709 -0.4014151117 -0.6113409191
+-0.8987000724 -0.1653921218 0.4061817646
+-0.1126514014 -0.7833083316 -0.6113409191
+ 0.0086058013 0.9998094297 0.0175226837
+-0.7913673487 0.0000000000 -0.6113409191
+ 0.4944105968 0.6179162098 -0.6113409191
+-0.7860486710 0.6179162098 0.0175226837
+-0.0000000000 0.0000000000 -1.0000000000
+ 0.3248577762 0.2814806691 0.6614584599
+-0.1694360713 0.3525674843 0.6614584599
+-0.4227424795 -0.0777993435 0.6614584599
+ 0.3248577762 -0.6759734692 0.6614584599
+ 0.7818964037 -0.0777993435 0.0698320276
+ 0.6270398312 0.3525674843 0.2702904483
+ 0.5422372365 0.8355491589 -0.0885233438
+-0.3167615539 0.6591266154 0.2958132161
+-0.9911796417 0.0986232000 -0.0885233438
+-0.6670382619 -0.2693375914 0.2702904483
+-0.4277462201 -0.6591266154 0.0698320276
+ 0.4277462201 0.6591266154 -0.0698320276
+-0.4015462944 0.8355491589 0.3749909018
+ 0.5358941893 0.0986232000 -0.8385051474
+ 0.3167615539 -0.6591266154 -0.2958132161
+ 0.6216868196 -0.2693375914 -0.3626326897
+-0.2562654803 0.5332446333 -0.5217944046
+-0.5536596562 0.5190272703 -0.1208775632
+ 0.5569679993 -0.1346687957 0.5120455748
+-0.2428162464 -0.5190272703 0.5120455748
+-0.0593658087 0.7565738714 -0.1208775632
+-0.1780974260 -0.6536960660 -0.3626326897
+-0.7818964037 0.0777993435 -0.0698320276
+-0.4118095603 -0.3568220898 -0.8385051474
+ 0.2428162464 0.5190272703 -0.5120455748
+ 0.0647188203 -0.1346687957 0.7538007012
+ 0.5536596562 -0.5190272703 0.1208775632
+ 0.4227424795 0.0777993435 -0.6614584599
+-0.0647188203 0.1346687957 -0.7538007012
+-0.5358941893 -0.0986232000 0.8385051474
+ 0.2562654803 -0.5332446333 0.5217944046
+ 0.4015462944 -0.8355491589 -0.3749909018
+-0.3248577762 -0.2814806691 -0.6614584599
+ 0.4118095603 0.3568220898 0.8385051474
+ 0.0593658087 -0.7565738714 0.1208775632
+-0.5569679993 0.1346687957 -0.5120455748
+ 0.9911796417 -0.0986232000 0.0885233438
+-0.5422372365 -0.8355491589 0.0885233438
+ 0.1780974260 0.6536960660 0.3626326897
+-0.6270398312 -0.3525674843 -0.2702904483
+ 0.6670382619 0.2693375914 -0.2702904483
+-0.6216868196 0.2693375914 0.3626326897
+ 0.1694360713 -0.3525674843 -0.6614584599
+-0.3248577762 0.6759734692 -0.6614584599
+10 0 2 9 24 42 51 36 16 5 1 3
+3 0 3 2
+10 0 4 14 16 37 53 47 28 10 3 3
+5 0 1 7 12 4
+10 1 6 17 39 48 45 25 9 20 7 3
+3 1 5 6
+5 2 8 21 20 9
+10 2 3 11 29 47 58 55 42 23 8 3
+5 3 10 26 30 11
+3 4 13 14
+10 4 12 26 10 27 46 43 44 32 13 3
+10 5 15 35 51 55 57 48 29 18 6 3
+5 5 16 14 33 15
+5 6 18 40 31 17
+10 7 19 32 49 52 54 38 17 31 12 3
+3 7 20 19
+10 8 22 34 15 33 40 18 11 30 21 3
+3 8 23 22
+3 9 25 24
+3 10 28 27
+3 11 18 29
+3 12 31 26
+10 13 22 23 43 56 58 53 50 33 14 3
+5 13 32 19 34 22
+3 15 34 35
+3 16 36 37
+3 17 38 39
+10 19 20 21 41 45 57 59 52 35 34 3
+3 21 30 41
+5 23 42 24 44 43
+10 24 25 27 28 39 38 37 36 49 44 3
+5 25 45 41 46 27
+10 26 31 40 50 54 59 56 46 41 30 3
+5 28 47 29 48 39
+3 32 44 49
+3 33 50 40
+5 35 52 49 36 51
+5 37 38 54 50 53
+3 42 55 51
+3 43 46 56
+3 45 48 57
+3 47 53 58
+3 52 59 54
+5 55 58 56 59 57
+4 3 0 1 2
+4 3 4 5 0
+4 0 6 7 1
+4 7 8 2 1
+4 2 9 10 3
+4 5 11 12 0
+4 4 13 11 5
+4 3 14 15 4
+4 6 16 17 7
+4 0 18 4 6
+4 8 10 19 2
+4 7 20 16 8
+4 10 21 14 3
+4 9 22 23 10
+4 2 12 22 9
+4 11 24 16 12
+4 2 25 0 12
+4 4 26 14 13
+4 13 16 20 11
+4 14 23 27 15
+4 27 6 4 15
+4 27 28 16 6
+4 16 23 22 17
+4 22 29 7 17
+4 0 29 30 18
+4 30 31 4 18
+4 8 32 21 10
+4 10 31 30 19
+4 30 33 2 19
+4 7 33 11 20
+4 28 32 8 16
+4 32 13 14 21
+4 14 34 10 23
+4 16 35 22 12
+4 24 27 23 16
+4 11 36 27 24
+4 25 30 36 0
+4 2 37 30 25
+4 26 30 37 14
+4 4 33 30 26
+4 32 35 16 13
+4 27 31 32 28
+4 0 38 7 29
+4 22 39 10 29
+4 34 30 29 10
+4 27 40 4 31
+4 39 32 31 10
+4 7 41 2 33
+4 40 11 33 4
+4 14 36 30 34
+4 32 37 22 35
+4 11 38 0 36
+4 14 42 27 36
+4 41 22 37 2
+4 32 42 14 37
+4 11 43 7 38
+4 22 43 32 39
+4 27 43 11 40
+4 7 41 22 43
+4 42 27 43 32
+small ditrigonal dodecicosidodecahedron
+small ditrigonal dodecacronic hexecontahedron
+5/3 3|5
+(10.5/3.10.3)
+icosahedral group
+A5
+12{10}+20{3}+12{5/3}
+47 60 120 44 60 4 0 0 -16 3 4 120 5 0 -1
+ 0.0000000000 0.0000000000 1.0000000000
+ 0.5558508647 0.0000000000 0.8312820317
+-0.5423346067 0.1218333214 0.8312820317
+-0.3547421326 0.4279348118 0.8312820317
+ 0.2523198656 -0.4952826155 0.8312820317
+ 0.9129018498 0.1218333214 0.3895726561
+ 0.7569595968 0.4279348118 0.4938460950
+-0.0195609124 0.3526376782 0.9355554706
+-0.8323493477 -0.2516159727 0.4938460950
+-0.8639995688 0.3189637764 0.3895726561
+-0.6764070948 0.6250652668 0.3895726561
+-0.1536334005 0.8558696236 0.4938460950
+-0.3230919115 -0.1426449373 0.9355554706
+-0.0376948755 -0.8687319096 0.4938460950
+ 0.3058398516 -0.8687319096 0.3895726561
+ 0.5362899523 0.3526376782 0.7668375023
+ 0.9664218358 -0.2516159727 -0.0521367195
+ 0.9347716147 0.3189637764 -0.1564101584
+ 0.7788293617 0.6250652668 -0.0521367195
+ 0.4022174642 0.8558696236 0.3251281267
+ 0.7886098179 -0.1426449373 0.5981195340
+ 0.1815478197 0.7805724901 0.5981195340
+-0.5800294821 -0.7468985882 0.3251281267
+-0.7788293617 -0.6250652668 0.0521367195
+-0.8421298039 0.5160942314 -0.1564101584
+-0.6628908367 0.7468985882 0.0521367195
+-0.9664218358 0.2516159727 0.0521367195
+ 0.2034175846 0.9777029450 0.0521367195
+-0.6131066526 -0.5160942314 0.5981195340
+-0.0707720459 -0.6379275528 0.7668375023
+ 0.4850788188 -0.6379275528 0.5981195340
+-0.2034175846 -0.9777029450 -0.0521367195
+ 0.1401171424 -0.9777029450 -0.1564101584
+ 0.6628908367 -0.7468985882 -0.0521367195
+ 0.6764070948 -0.6250652668 -0.3895726561
+ 0.6131066526 0.5160942314 -0.5981195340
+ 0.5800294821 0.7468985882 -0.3251281267
+ 0.8323493477 0.2516159727 -0.4938460950
+-0.1401171424 0.9777029450 0.1564101584
+ 0.8421298039 -0.5160942314 0.1564101584
+-0.9347716147 -0.3189637764 0.1564101584
+-0.4022174642 -0.8558696236 -0.3251281267
+-0.7569595968 -0.4279348118 -0.4938460950
+-0.7886098179 0.1426449373 -0.5981195340
+-0.4850788188 0.6379275528 -0.5981195340
+-0.3058398516 0.8687319096 -0.3895726561
+-0.9129018498 -0.1218333214 -0.3895726561
+ 0.0376948755 0.8687319096 -0.4938460950
+-0.1815478197 -0.7805724901 -0.5981195340
+ 0.1536334005 -0.8558696236 -0.4938460950
+ 0.8639995688 -0.3189637764 -0.3895726561
+ 0.3547421326 -0.4279348118 -0.8312820317
+ 0.3230919115 0.1426449373 -0.9355554706
+ 0.0707720459 0.6379275528 -0.7668375023
+ 0.5423346067 -0.1218333214 -0.8312820317
+-0.5558508647 0.0000000000 -0.8312820317
+-0.5362899523 -0.3526376782 -0.7668375023
+-0.2523198656 0.4952826155 -0.8312820317
+ 0.0195609124 -0.3526376782 -0.9355554706
+-0.0000000000 0.0000000000 -1.0000000000
+ 0.1036376133 0.9341723590 0.3414399638
+-0.0933664669 0.0572190828 0.3414399638
+-0.7853356508 -0.5163977795 0.3414399638
+ 0.1036376133 -0.0635136937 0.3414399638
+ 0.8426251145 -0.5163977795 -0.1526965938
+ 0.2674035654 0.0572190828 0.2319350754
+-0.2870826778 0.0242600722 0.2198885583
+ 0.1963339127 -0.7369259589 0.6468331514
+ 0.7457496051 0.1595756897 0.6468331514
+-0.1519332973 0.2447882516 0.2198885583
+ 0.0703994852 -0.2642396690 0.2319350754
+ 0.3608719169 0.0242600722 0.0232142528
+ 0.2485246653 0.2447882516 0.0983371527
+-0.2603854803 0.1595756897 0.9522263391
+ 0.0895451227 0.1905410810 0.2950114582
+-0.8426251145 0.5163977795 0.1526965938
+-0.7457496051 -0.1595756897 -0.6468331514
+-0.2815979407 -0.1851648415 0.1224301871
+-0.3021402336 0.1851648415 0.0547524442
+-0.1963339127 0.7369259589 -0.6468331514
+ 0.0371613570 0.3349663450 0.1224301871
+-0.1291311684 -0.1662810088 0.2950114582
+-0.1053010062 -0.3325620175 0.0983371527
+ 0.1421956258 -0.3325620175 0.0232142528
+ 0.7853356508 0.5163977795 -0.3414399638
+ 0.3021402336 -0.1851648415 -0.0547524442
+ 0.2603854803 -0.1595756897 -0.9522263391
+ 0.2815979407 0.1851648415 -0.1224301871
+ 0.2713267942 -0.1662810088 0.1734600527
+-0.2485246653 -0.2447882516 -0.0983371527
+-0.2713267942 0.1662810088 -0.1734600527
+-0.1421956258 0.3325620175 -0.0232142528
+-0.3608719169 -0.0242600722 -0.0232142528
+ 0.1053010062 0.3325620175 -0.0983371527
+-0.1036376133 -0.9341723590 -0.3414399638
+-0.0371613570 -0.3349663450 -0.1224301871
+ 0.1519332973 -0.2447882516 -0.2198885583
+ 0.1291311684 0.1662810088 -0.2950114582
+ 0.2870826778 -0.0242600722 -0.2198885583
+-0.2674035654 -0.0572190828 -0.2319350754
+-0.0703994852 0.2642396690 -0.2319350754
+-0.0895451227 -0.1905410810 -0.2950114582
+ 0.0933664669 -0.0572190828 -0.3414399638
+-0.1036376133 0.0635136937 -0.3414399638
+10 0 2 9 24 44 53 35 17 5 1
+5 0 3 12 7 2 3
+10 0 4 14 32 48 56 43 24 10 3
+3 0 1 4
+10 1 6 18 35 52 58 48 31 13 4
+5 1 5 15 20 6 3
+3 2 8 9
+10 2 7 15 5 16 34 49 41 23 8
+10 3 11 27 36 37 50 33 14 29 12
+3 3 10 11
+5 4 13 30 29 14 3
+3 5 17 16
+3 6 19 18
+10 6 20 30 13 22 40 26 25 38 19
+3 7 21 15
+10 7 12 28 23 42 55 57 47 27 21
+10 8 22 31 49 51 52 53 45 25 9
+5 8 23 28 40 22 3
+5 9 25 26 10 24 3
+10 10 26 46 56 58 54 37 18 19 11
+5 11 19 38 21 27 3
+3 12 29 28
+3 13 31 22
+3 14 33 32
+10 15 21 38 45 57 59 51 34 39 20
+5 16 33 50 39 34 3
+10 16 17 36 47 44 43 42 41 32 33
+5 17 35 18 37 36 3
+3 20 39 30
+3 23 41 42
+3 24 43 44
+3 25 45 38
+3 26 40 46
+3 27 47 36
+10 28 29 30 39 50 54 59 55 46 40
+5 31 48 32 41 49 3
+3 34 51 49
+3 35 53 52
+3 37 54 50
+5 42 43 56 46 55 3
+5 44 47 57 45 53 3
+3 48 58 56
+5 51 59 54 58 52 3
+3 55 59 57
+4 3 0 1 2
+4 3 4 5 0
+4 0 6 7 1
+4 1 8 9 2
+4 2 10 4 3
+4 5 7 11 0
+4 4 12 13 5
+4 7 14 15 1
+4 6 16 17 7
+4 0 18 16 6
+4 9 19 18 2
+4 8 20 19 9
+4 15 21 8 1
+4 10 13 22 4
+4 2 23 8 10
+4 5 24 14 7
+4 7 25 26 11
+4 26 27 0 11
+4 4 27 19 12
+4 20 13 12 19
+4 13 28 24 5
+4 24 20 15 14
+4 16 22 13 17
+4 17 15 29 7
+4 0 30 2 18
+4 18 13 31 16
+4 19 32 13 18
+4 8 33 15 20
+4 17 34 21 15
+4 34 10 8 21
+4 34 28 13 10
+4 16 35 4 22
+4 2 35 26 23
+4 25 8 23 26
+4 7 36 24 25
+4 4 37 0 27
+4 26 33 8 27
+4 8 38 19 27
+4 24 31 13 20
+4 34 25 24 28
+4 32 34 17 13
+4 29 26 35 7
+4 15 39 26 29
+4 30 26 39 2
+4 0 40 26 30
+4 24 40 16 31
+4 19 39 34 32
+4 40 15 33 26
+4 2 41 4 35
+4 16 36 7 35
+4 34 38 8 25
+4 16 42 24 36
+4 4 42 16 37
+4 37 0 40 16
+4 34 42 19 38
+4 15 43 34 39
+4 19 41 2 39
+4 24 43 15 40
+4 41 4 42 19
+4 42 24 43 34
+icosidodecadodecahedron
+medial icosacronic hexecontahedron
+5/3 5|3
+(6.5/3.6.5)
+icosahedral group
+A5
+20{6}+12{5}+12{5/3}
+48 60 120 44 60 4 0 0 -16 3 4 120 5 0 -1
+ 0.0000000000 0.0000000000 1.0000000000
+ 0.6998542122 0.0000000000 0.7142857143
+-0.5248906592 0.4629100499 0.7142857143
+-0.1166423687 0.6900655593 0.7142857143
+-0.3689536881 -0.5947008445 0.7142857143
+ 0.8748177653 0.4629100499 0.1428571429
+ 0.5832118435 0.6900655593 0.4285714286
+ 0.7634342145 -0.5947008445 0.2519902889
+ 0.2077578990 0.4039714148 0.8908668539
+-0.8938443472 -0.1317907946 0.4285714286
+-0.3499271061 0.9258200998 0.1428571429
+-0.6022384255 0.7854302742 0.1428571429
+-0.4528017108 0.0364260797 0.8908668539
+ 0.1028746047 -0.9622461795 0.2519902889
+-0.8545497448 -0.4993361296 0.1428571429
+ 0.4750784209 0.4039714148 0.7817337079
+ 0.9383977675 -0.1317907946 -0.3194382825
+ 0.3499271061 0.9258200998 -0.1428571429
+ 0.5301494771 0.7854302742 -0.3194382825
+ 0.9469067137 0.0364260797 0.3194382825
+ 0.7103718480 -0.4993361296 -0.4960194221
+ 0.5714527692 -0.2496680648 0.7817337079
+ 0.3827214521 0.8668814647 0.3194382825
+-0.9469067137 -0.0364260797 -0.3194382825
+-0.5301494771 -0.7854302742 0.3194382825
+-0.6107473716 0.6172133998 -0.4960194221
+-0.2024990811 0.8443689093 -0.4960194221
+-0.9383977675 0.1317907946 0.3194382825
+-0.9711921135 0.1907294297 -0.1428571429
+-0.0891068406 -0.6172133998 0.7817337079
+ 0.0498122382 -0.8668814647 -0.4960194221
+-0.3827214521 -0.8668814647 -0.3194382825
+-0.5937294793 -0.1907294297 0.7817337079
+ 0.1389190789 -0.2496680648 0.9583148475
+-0.0498122382 0.8668814647 0.4960194221
+ 0.4528017108 -0.0364260797 -0.8908668539
+ 0.6022384255 -0.7854302742 -0.1428571429
+ 0.0891068406 0.6172133998 -0.7817337079
+ 0.8938443472 0.1317907946 -0.4285714286
+ 0.5937294793 0.1907294297 -0.7817337079
+ 0.6107473716 -0.6172133998 0.4960194221
+ 0.9711921135 -0.1907294297 0.1428571429
+ 0.2024990811 -0.8443689093 0.4960194221
+-0.1028746047 0.9622461795 -0.2519902889
+ 0.8545497448 0.4993361296 -0.1428571429
+-0.4750784209 -0.4039714148 -0.7817337079
+-0.5832118435 -0.6900655593 -0.4285714286
+-0.1389190789 0.2496680648 -0.9583148475
+-0.5714527692 0.2496680648 -0.7817337079
+-0.7634342145 0.5947008445 -0.2519902889
+-0.8748177653 -0.4629100499 -0.1428571429
+-0.7103718480 0.4993361296 0.4960194221
+-0.3499271061 -0.9258200998 0.1428571429
+-0.2077578990 -0.4039714148 -0.8908668539
+ 0.3499271061 -0.9258200998 -0.1428571429
+ 0.1166423687 -0.6900655593 -0.7142857143
+ 0.3689536881 0.5947008445 -0.7142857143
+ 0.5248906592 -0.4629100499 -0.7142857143
+-0.6998542122 0.0000000000 -0.7142857143
+-0.0000000000 0.0000000000 -1.0000000000
+ 0.2672612419 0.7071067812 0.6546536707
+-0.1378524272 0.2477510578 0.6546536707
+-0.7417602291 0.1456720081 0.6546536707
+ 0.2672612419 -0.4803270912 0.6546536707
+ 0.9879908641 0.1456720081 -0.0515142560
+ 0.5566281484 0.2477510578 0.3711331629
+-0.7425563482 0.4102483131 0.1049785976
+-0.2462306350 -0.2913440163 0.9243858169
+ 0.3773789295 0.0556417559 0.9243858169
+ 0.0428573330 0.8472643375 0.1049785976
+-0.5039732067 -0.3423835411 0.3711331629
+-0.6446401714 -0.7627485371 -0.0515142560
+ 0.8228143327 -0.2913440163 0.4879500365
+ 0.6038671053 0.4102483131 -0.4446964755
+ 0.4244047962 -0.7627485371 -0.4879500365
+ 0.6197199693 -0.3423835411 -0.0876126552
+ 0.6669589261 0.2968584681 0.4446964755
+-0.4244047962 0.7627485371 0.4879500365
+ 0.0357677167 0.7071067812 0.0876126552
+ 0.1862071383 0.8527787893 -0.4879500365
+-0.8228143327 0.2913440163 -0.4879500365
+-0.6197199693 0.3423835411 0.0876126552
+-0.6038671053 -0.4102483131 0.4446964755
+-0.0357677167 -0.7071067812 -0.0876126552
+-0.6669589261 -0.2968584681 -0.4446964755
+-0.1862071383 -0.8527787893 0.4879500365
+ 0.6446401714 0.7627485371 0.0515142560
+-0.1651765314 0.2968584681 0.7844143535
+-0.4744989872 0.8527787893 -0.2182178902
+ 0.5039732067 0.3423835411 -0.3711331629
+ 0.2462306350 0.2913440163 -0.9243858169
+ 0.7425563482 -0.4102483131 -0.1049785976
+ 0.4744989872 -0.8527787893 0.2182178902
+ 0.1651765314 -0.2968584681 -0.7844143535
+ 0.2230499127 -0.4008696323 0.5463584732
+-0.3773789295 -0.0556417559 -0.9243858169
+-0.5566281484 -0.2477510578 -0.3711331629
+-0.9879908641 -0.1456720081 0.0515142560
+-0.0428573330 -0.8472643375 -0.1049785976
+-0.2230499127 0.4008696323 -0.5463584732
+ 0.1378524272 -0.2477510578 -0.6546536707
+ 0.7417602291 -0.1456720081 -0.6546536707
+-0.2672612419 0.4803270912 -0.6546536707
+-0.2672612419 -0.7071067812 -0.6546536707
+6 0 2 10 17 5 1
+5 0 3 12 8 2 3
+6 0 4 14 28 11 3
+5 0 1 7 13 4
+6 1 6 18 39 20 7
+5 1 5 15 19 6 3
+5 2 9 23 25 10
+6 2 8 21 42 24 9
+6 3 6 19 40 29 12
+5 3 11 26 18 6
+5 4 9 24 32 14 3
+6 4 13 30 45 23 9
+6 5 16 36 42 33 15
+5 5 17 37 35 16
+6 7 16 35 53 31 13
+5 7 20 41 36 16 3
+5 8 22 44 41 21
+6 8 12 27 49 43 22
+5 10 22 43 34 17 3
+6 10 25 47 39 44 22
+6 11 27 50 45 47 26
+5 11 28 51 49 27 3
+5 12 29 52 50 27
+5 13 31 54 52 30 3
+5 14 31 53 48 28
+6 14 32 33 40 54 31
+6 15 34 43 56 38 19
+5 15 33 32 51 34
+6 17 34 51 28 48 37
+5 18 38 56 44 39 3
+6 18 26 48 53 57 38
+5 19 38 57 54 40
+6 20 30 52 29 21 41
+5 20 39 47 45 30
+5 21 29 40 33 42 3
+6 23 46 55 35 37 25
+5 23 45 50 58 46 3
+6 24 46 58 49 51 32
+5 24 42 36 55 46
+5 25 37 48 26 47 3
+5 35 55 59 57 53 3
+6 36 41 44 56 59 55
+5 43 49 58 59 56
+6 50 52 54 57 59 58
+4 3 0 1 2
+4 3 4 5 0
+4 0 6 7 1
+4 1 8 9 2
+4 2 10 11 3
+4 5 12 13 0
+4 4 9 8 5
+4 3 14 15 4
+4 7 16 17 1
+4 6 11 10 7
+4 0 18 19 6
+4 9 20 21 2
+4 17 22 8 1
+4 11 23 14 3
+4 2 24 25 10
+4 5 26 27 12
+4 12 15 14 13
+4 13 28 18 0
+4 4 29 30 9
+4 8 31 26 5
+4 15 32 33 4
+4 7 34 32 16
+4 16 19 18 17
+4 6 35 36 11
+4 10 37 38 7
+4 19 39 35 6
+4 30 39 20 9
+4 20 22 17 21
+4 21 28 24 2
+4 22 32 34 8
+4 11 33 32 23
+4 23 25 24 14
+4 25 27 37 10
+4 25 34 12 27
+4 26 18 28 27
+4 14 40 35 13
+4 12 38 41 15
+4 39 28 13 35
+4 29 26 31 30
+4 33 19 29 4
+4 25 31 8 34
+4 41 16 32 15
+4 7 34 12 38
+4 26 42 17 18
+4 41 29 19 16
+4 36 20 33 11
+4 35 38 37 36
+4 19 39 20 33
+4 30 24 28 39
+4 42 37 21 17
+4 36 43 22 20
+4 21 28 27 37
+4 43 23 32 22
+4 30 40 14 24
+4 43 31 25 23
+4 40 41 38 35
+4 41 42 26 29
+4 43 40 30 31
+4 42 43 36 37
+4 40 41 42 43
+icositruncated dodecadodecahedron
+tridyakisicosahedron
+5/3 3 5|
+(10/3.6.10)
+icosahedral group
+A5
+12{10}+20{6}+12{10/3}
+49 120 180 44 120 4 0 0 -16 3 3 120 5 0 -1
+ 0.0000000000 0.0000000000 1.0000000000
+ 0.4841229183 0.0000000000 0.8750000000
+ 0.1273008285 0.4670861795 0.8750000000
+-0.4500494407 -0.1784110449 0.8750000000
+ 0.3122193286 0.4670861795 0.8272542486
+ 0.8174008141 -0.1784110449 0.5477457514
+-0.1954477837 0.7557613141 0.6250000000
+ 0.5327475080 0.1784110449 0.8272542486
+-0.6941218141 -0.4670861795 0.5477457514
+-0.7727980529 0.1102640897 0.6250000000
+ 0.4735936346 0.7557613141 0.4522542486
+-0.0656613285 0.1784110449 0.9817627458
+ 0.8725328589 -0.4670861795 0.1432372542
+ 0.9787751202 0.1102640897 0.1727457514
+-0.3122193286 0.9341723590 0.1727457514
+-0.6454972244 0.5773502692 0.5000000000
+ 0.1548668509 -0.1102640897 0.9817627458
+ 0.8660254038 -0.0000000000 0.5000000000
+-0.8660254038 0.0000000000 0.5000000000
+-0.6389897692 -0.7557613141 0.1432372542
+-0.8174008141 -0.3568220898 0.4522542486
+ 0.3568220898 0.9341723590 0.0000000000
+ 0.8068715305 0.5773502692 0.1250000000
+ 0.3397853510 -0.1102640897 0.9340169944
+-0.5157107692 -0.0000000000 0.8567627458
+ 0.9998336874 0.0000000000 0.0182372542
+ 0.6284604856 -0.7557613141 -0.1840169944
+ 0.9341723590 -0.3568220898 0.0000000000
+-0.6900999856 0.6454972244 0.3272542486
+-0.1784110449 0.9341723590 -0.3090169944
+-0.4841229183 0.8660254038 0.1250000000
+ 0.1102640897 -0.5773502692 0.8090169944
+-0.0170367388 0.3568220898 0.9340169944
+ 0.8214226426 -0.4670861795 0.3272542486
+-0.9827969487 0.1784110449 0.0477457514
+-0.3057118734 -0.9341723590 -0.1840169944
+-0.7557613141 -0.5773502692 -0.3090169944
+-0.4670861795 -0.3568220898 0.8090169944
+-0.7622687692 -0.6454972244 0.0477457514
+ 0.7622687692 0.6454972244 -0.0477457514
+ 0.0065074552 0.9341723590 -0.3567627458
+ 0.4841229183 0.8660254038 -0.1250000000
+ 0.2951825898 -0.5773502692 0.7612712430
+ 0.4670861795 0.3568220898 0.8090169944
+-0.5603135304 -0.4670861795 0.6840169944
+ 0.8830621426 0.1784110449 -0.4340169944
+ 0.1784110449 -0.9341723590 -0.3090169944
+ 0.5116889407 -0.5773502692 -0.6362712430
+ 0.8003640753 -0.3568220898 0.4817627458
+ 0.6900999856 -0.6454972244 -0.3272542486
+-0.9341723590 0.3568220898 0.0000000000
+-0.3397853510 0.6454972244 0.6840169944
+ 0.1548668509 0.7557613141 -0.6362712430
+-0.4224834183 0.6454972244 -0.6362712430
+-0.1338082837 0.8660254038 0.4817627458
+-0.3503146346 0.8660254038 -0.3567627458
+-0.1338082837 -0.8660254038 0.4817627458
+ 0.4435419855 -0.7557613141 0.4817627458
+ 0.9827969487 -0.1784110449 -0.0477457514
+-0.8214226426 0.4670861795 -0.3272542486
+-0.9276649038 -0.1102640897 -0.3567627458
+-0.6284604856 -0.6454972244 -0.4340169944
+-0.3503146346 -0.8660254038 -0.3567627458
+-0.0616395000 -0.6454972244 0.7612712430
+-0.6389897692 0.1102640897 0.7612712430
+-0.3568220898 -0.9341723590 -0.0000000000
+ 0.8174008141 0.3568220898 -0.4522542486
+ 0.6284604856 0.6454972244 0.4340169944
+-0.4435419855 0.7557613141 -0.4817627458
+ 0.0616395000 0.6454972244 -0.7612712430
+ 0.3503146346 0.8660254038 0.3567627458
+ 0.1338082837 0.8660254038 -0.4817627458
+ 0.3503146346 -0.8660254038 0.3567627458
+-0.1548668509 -0.7557613141 0.6362712430
+-0.8830621426 -0.1784110449 0.4340169944
+ 0.5603135304 0.4670861795 -0.6840169944
+ 0.6389897692 -0.1102640897 -0.7612712430
+ 0.3397853510 -0.6454972244 -0.6840169944
+ 0.1338082837 -0.8660254038 -0.4817627458
+ 0.4224834183 -0.6454972244 0.6362712430
+ 0.9276649038 0.1102640897 0.3567627458
+ 0.3122193286 -0.9341723590 -0.1727457514
+-0.9787751202 -0.1102640897 -0.1727457514
+-0.8003640753 0.3568220898 -0.4817627458
+-0.1784110449 0.9341723590 0.3090169944
+-0.2951825898 0.5773502692 -0.7612712430
+-0.5116889407 0.5773502692 0.6362712430
+-0.4841229183 -0.8660254038 0.1250000000
+-0.0065074552 -0.9341723590 0.3567627458
+ 0.8660254038 0.0000000000 -0.5000000000
+-0.8660254038 -0.0000000000 -0.5000000000
+-0.4670861795 -0.3568220898 -0.8090169944
+-0.4735936346 -0.7557613141 -0.4522542486
+ 0.7727980529 -0.1102640897 -0.6250000000
+ 0.4670861795 0.3568220898 -0.8090169944
+ 0.3057118734 0.9341723590 0.1840169944
+-0.1102640897 0.5773502692 -0.8090169944
+ 0.7557613141 0.5773502692 0.3090169944
+ 0.4841229183 -0.8660254038 -0.1250000000
+ 0.1784110449 -0.9341723590 0.3090169944
+-0.9998336874 0.0000000000 -0.0182372542
+ 0.5157107692 -0.0000000000 -0.8567627458
+ 0.0170367388 -0.3568220898 -0.9340169944
+ 0.1954477837 -0.7557613141 -0.6250000000
+-0.8174008141 0.1784110449 -0.5477457514
+-0.8068715305 -0.5773502692 -0.1250000000
+-0.6284604856 0.7557613141 0.1840169944
+-0.3397853510 0.1102640897 -0.9340169944
+ 0.6941218141 0.4670861795 -0.5477457514
+-0.5327475080 -0.1784110449 -0.8272542486
+-0.3122193286 -0.4670861795 -0.8272542486
+ 0.4500494407 0.1784110449 -0.8750000000
+ 0.6454972244 -0.5773502692 -0.5000000000
+ 0.6389897692 0.7557613141 -0.1432372542
+-0.1548668509 0.1102640897 -0.9817627458
+-0.8725328589 0.4670861795 -0.1432372542
+ 0.0656613285 -0.1784110449 -0.9817627458
+-0.1273008285 -0.4670861795 -0.8750000000
+-0.4841229183 -0.0000000000 -0.8750000000
+-0.0000000000 -0.0000000000 -1.0000000000
+ 0.1517654996 0.1159385250 0.5877852523
+-0.2529424993 0.2262386491 0.5877852523
+ 0.1517654996 -0.7946544723 0.5877852523
+ 0.5058849985 0.2262386491 0.3918568349
+ 0.5849197102 0.7946544723 0.1624598481
+-0.4331542107 -0.1159385250 0.4253254042
+-0.4331542107 0.7946544723 0.4253254042
+ 0.5849197102 -0.1159385250 0.1624598481
+-0.2677040246 0.4911234732 0.2628655561
+ 0.3825657108 -0.2262386491 0.5129472562
+-0.6355082101 -0.2262386491 0.0748379961
+-0.9464199718 0.1875924741 -0.2628655561
+ 0.3615002616 0.4911234732 0.1004057079
+-0.0864154744 -0.2262386491 0.6340376775
+ 0.5923004729 -0.2262386491 -0.2421808427
+ 0.7008582352 0.1875924741 -0.6881909602
+-0.4359734112 0.5058849985 -0.1210904213
+-0.7008582352 -0.1875924741 0.6881909602
+-0.3615002616 -0.4911234732 -0.1004057079
+-0.3228540866 -0.5058849985 0.3170188388
+ 0.3228540866 0.5058849985 -0.3170188388
+ 0.9464199718 -0.1875924741 0.2628655561
+ 0.2677040246 -0.4911234732 -0.2628655561
+ 0.4359734112 -0.5058849985 0.1210904213
+-0.0937962370 0.4911234732 -0.3632712640
+ 0.0000000000 0.6787159473 -0.0000000000
+ 0.0937962370 -0.4911234732 0.3632712640
+ 0.1131193245 0.5058849985 0.4381092601
+ 0.4331542107 -0.7946544723 -0.4253254042
+-0.5849197102 0.1159385250 -0.1624598481
+-0.1131193245 -0.5058849985 -0.4381092601
+-0.2455617366 -0.1875924741 -0.9510565163
+ 0.2455617366 0.1875924741 0.9510565163
+-0.5849197102 -0.7946544723 -0.1624598481
+ 0.4331542107 0.1159385250 -0.4253254042
+ 0.0864154744 0.2262386491 -0.6340376775
+-0.0000000000 -0.6787159473 -0.0000000000
+ 0.6355082101 0.2262386491 -0.0748379961
+-0.3825657108 0.2262386491 -0.5129472562
+-0.5923004729 0.2262386491 0.2421808427
+-0.5058849985 -0.2262386491 -0.3918568349
+-0.1517654996 0.7946544723 -0.5877852523
+-0.1517654996 -0.1159385250 -0.5877852523
+ 0.2529424993 -0.2262386491 -0.5877852523
+10 0 2 7 16 32 43 23 11 4 1 3
+6 0 3 9 15 6 2
+10 0 1 5 12 26 46 35 19 8 3
+6 1 4 10 22 13 5
+10 2 6 14 29 52 75 45 25 17 7
+10 3 8 18 24 44 74 64 37 20 9 3
+10 4 11 24 18 34 59 68 40 21 10
+10 5 13 27 48 80 58 33 17 25 12 3
+10 6 15 30 54 86 106 84 51 28 14 3
+6 7 17 33 57 31 16
+6 8 19 36 60 34 18
+10 9 20 38 61 91 107 85 55 30 15
+10 10 21 39 67 95 113 97 70 41 22 3
+6 11 23 42 73 44 24
+6 12 25 45 76 47 26
+10 13 22 41 71 96 114 102 77 49 27
+6 14 28 50 83 53 29
+10 16 31 56 87 105 82 50 28 51 32
+10 19 35 61 38 65 92 105 87 62 36 3
+6 20 37 63 88 65 38
+6 21 40 69 94 66 39
+10 23 43 67 39 66 93 112 98 72 42
+10 26 47 78 98 112 103 81 49 77 46 3
+6 27 49 81 99 79 48
+10 29 53 69 40 68 96 71 55 85 52 3
+6 30 55 71 41 70 54
+10 31 57 88 63 79 99 73 42 72 56 3
+6 32 51 84 95 67 43
+10 33 58 89 101 116 110 92 65 88 57
+10 34 60 83 50 82 104 115 100 90 59 3
+6 35 46 77 102 91 61
+10 36 62 78 47 76 94 69 53 83 60
+10 37 64 86 54 70 97 80 48 79 63
+10 44 73 99 81 103 117 109 90 100 74
+10 45 75 101 89 108 111 93 66 94 76 3
+6 52 85 107 116 101 75
+6 56 72 98 78 62 87
+6 58 80 97 113 108 89
+6 59 90 109 114 96 68
+6 64 74 100 115 106 86
+6 82 105 92 110 118 104
+10 84 106 115 104 118 119 111 108 113 95
+10 91 102 114 109 117 119 118 110 116 107 3
+6 93 111 119 117 103 112
+3 2 0 1
+3 2 3 0
+3 0 4 1
+3 1 5 2
+3 3 6 0
+3 2 7 3
+3 4 8 1
+3 0 9 4
+3 5 10 2
+3 1 11 5
+3 3 12 6
+3 6 13 0
+3 2 14 7
+3 7 15 3
+3 4 16 8
+3 8 11 1
+3 0 17 9
+3 9 7 4
+3 5 6 10
+3 10 18 2
+3 11 19 5
+3 12 20 6
+3 15 12 3
+3 13 21 0
+3 5 13 6
+3 14 4 7
+3 2 22 14
+3 7 23 15
+3 16 17 8
+3 4 24 16
+3 8 25 11
+3 17 26 9
+3 0 27 17
+3 9 28 7
+3 6 29 10
+3 18 30 2
+3 10 31 18
+3 19 32 5
+3 11 18 19
+3 12 21 20
+3 20 24 6
+3 15 25 12
+3 13 26 21
+3 21 27 0
+3 5 33 13
+3 14 34 4
+3 30 22 2
+3 22 31 14
+3 7 32 23
+3 23 22 15
+3 16 29 17
+3 27 8 17
+3 4 35 24
+3 24 31 16
+3 8 32 25
+3 25 24 11
+3 17 36 26
+3 26 28 9
+3 28 37 7
+3 6 38 29
+3 29 31 10
+3 11 30 18
+3 31 36 18
+3 19 26 32
+3 32 39 5
+3 18 28 19
+3 21 34 20
+3 12 27 21
+3 24 38 6
+3 20 31 24
+3 32 12 25
+3 15 24 25
+3 36 21 26
+3 33 26 13
+3 39 33 5
+3 34 35 4
+3 31 34 14
+3 30 15 22
+3 22 36 31
+3 26 23 32
+3 37 32 7
+3 23 33 22
+3 29 40 17
+3 16 29 31
+3 27 41 8
+3 35 11 24
+3 8 39 32
+3 17 18 36
+3 26 28 19
+3 28 34 37
+3 38 33 29
+3 11 42 30
+3 18 40 28
+3 21 43 34
+3 34 20 31
+3 12 41 27
+3 15 38 24
+3 37 12 32
+3 22 21 36
+3 33 26 23
+3 39 29 33
+3 28 35 34
+3 42 15 30
+3 33 43 22
+3 29 41 40
+3 40 17 18
+3 41 39 8
+3 35 42 11
+3 34 41 37
+3 38 42 33
+3 40 42 28
+3 43 41 34
+3 21 43 22
+3 12 41 37
+3 15 38 42
+3 39 29 41
+3 28 35 42
+3 42 43 33
+3 41 42 40
+3 43 41 42
+snub icosidodecadodecahedron
+medial hexagonal hexecontahedron
+|5/3 3 5
+(3.5/3.3.3.3.5)
+icosahedral group
+A5
+12{5}+80{3}+12{5/3}
+50 60 180 104 60 4 0 0 -16 3 6 120 5 0 -1
+ 0.0000000000 0.0000000000 1.0000000000
+ 0.7952605037 0.0000000000 0.6062678709
+ 0.3001621965 0.7364386767 0.6062678709
+ 0.7055094406 0.3670091252 0.6062678709
+-0.0735764581 0.7918495902 0.6062678709
+-0.7610506656 0.2307404455 0.6062678709
+-0.5009236922 -0.6176687813 0.6062678709
+ 0.7858348327 -0.6176687813 -0.0308040965
+ 0.9435414590 0.2307404455 -0.2376728044
+ 0.9243781868 -0.3167862469 -0.2125357417
+ 0.8269101315 0.5559211096 -0.0846838490
+ 0.0555412250 0.9755735394 -0.2125357417
+-0.3193254687 0.1889119844 0.9286245243
+ 0.5199990010 -0.0881350076 0.8496077091
+-0.1358666171 0.5096145631 0.8496077091
+ 0.2176453044 -0.3004779764 0.9286245243
+ 0.8327355166 -0.4593916847 0.3090482801
+-0.3170460053 0.9181467577 -0.2376728044
+-0.8371873340 0.4512278009 0.3090482801
+-0.6300413753 0.7719303797 -0.0846838490
+-0.7338395293 -0.6049534741 0.3090482801
+-0.1585581578 -0.3354337541 0.9286245243
+-0.9468108730 0.0896567415 0.3090482801
+-0.7735370212 -0.5874964807 -0.2376728044
+-0.0152510561 -0.9994090819 -0.0308040965
+ 0.2799588487 -0.5874964807 -0.7592568262
+ 0.0348116018 -0.9174921690 -0.3962275509
+ 0.5102070354 -0.2920835591 -0.8089350873
+ 0.3115674381 0.5713622348 -0.7592568262
+ 0.8637423423 0.4265251132 0.2683756583
+ 0.6801235098 -0.3583093162 0.6395673892
+ 0.3474601540 -0.9361396763 0.0539809952
+ 0.1222522224 0.8245736843 -0.5523881184
+ 0.1385433541 0.9344550281 0.3280236873
+ 0.6152755562 0.6750955630 0.4070405025
+ 0.7537879313 0.4809955435 -0.4477131243
+-0.0043310515 0.4244359070 -0.9054476257
+-0.7151305151 0.5758403202 -0.3962275509
+-0.8732845400 -0.2677538824 0.4070405025
+-0.1486782288 -0.6603643877 0.7360799276
+ 0.5996272266 -0.7539374610 0.2683756583
+-0.1581038998 0.9824462228 0.0990079602
+-0.2651930296 -0.8595294620 0.4369001728
+ 0.0873995822 -0.9406177617 0.3280236873
+ 0.8765539540 -0.0526433046 -0.4784159782
+-0.5218620448 0.2707102338 -0.8089350873
+-0.7977285113 0.2418606808 -0.5523881184
+-0.9171154526 -0.3949497421 0.0539809952
+-0.4932731016 0.4635385501 0.7360799276
+-0.5860128319 -0.5802507864 -0.5655952490
+-0.3294249208 -0.8312834534 -0.4477131243
+-0.8249774859 -0.3008825344 -0.4784159782
+-0.2157822605 0.1179027501 -0.9692971462
+ 0.7441167318 -0.4021954364 -0.5334127111
+ 0.1582993033 -0.2824850577 -0.9461202475
+ 0.4809752902 0.7416267119 -0.4676030266
+-0.0705157735 -0.7139676727 -0.6966187538
+ 0.1610261654 0.0935730734 -0.9825042768
+-0.8730256855 0.4832272272 -0.0657084418
+-0.6757924584 -0.0661265908 -0.7341197635
+ 0.3247276953 0.2183102780 0.6558852870
+ 0.2330291401 0.2556853380 0.6558852870
+ 0.1873305537 0.3435327018 0.6558852870
+-0.2474173141 0.3031371410 0.6558852870
+-0.3741003584 -0.1147012443 0.6558852870
+ 0.3247276953 -0.6814443588 0.6558852870
+ 0.7484046915 -0.1147012443 0.1001349371
+ 0.7309860539 -0.0199380975 0.1229835081
+ 0.7549003045 0.0708892675 0.0916144386
+ 0.5698573801 0.3831078312 0.3343410226
+ 0.3505745987 0.6723073767 0.0916144386
+-0.4956852875 0.7825823548 0.3766443331
+ 0.1484680132 0.2481846593 0.7068624953
+ 0.2333841167 0.1707929452 0.7068624953
+ 0.5205170549 -0.1164597889 0.5466187670
+ 0.7357021020 0.0410148862 0.2008809586
+ 0.4787409949 0.8779303974 -0.0067288271
+-0.3639725977 0.6406744508 0.2008809586
+-0.3675642883 0.5803063628 0.2792921431
+-0.4341871188 0.5319685985 0.3343410226
+-0.9857841031 0.0268878721 -0.1658515735
+-0.4901491203 -0.2103680745 0.5466187670
+-0.4381469231 -0.1343382762 0.5829610478
+-0.5238282283 -0.1005230031 0.5466187670
+-0.6584749455 -0.3306819467 0.2008809586
+-0.3823228516 -0.6535252059 0.1001349371
+ 0.3114234217 -0.6535252059 -0.2433376685
+ 0.3675642883 -0.5803063628 -0.2792921431
+ 0.3945189195 -0.5416693466 -0.3663906446
+ 0.6639032878 -0.2012866519 -0.3193885901
+ 0.5233112059 0.1511903430 -0.5353315097
+ 0.7316875924 -0.0736863580 0.2061469163
+ 0.5786406224 -0.4776354422 0.1425916469
+ 0.4600155947 -0.5455758087 -0.2720765570
+ 0.5908707414 0.1811642457 -0.7861623770
+ 0.3224400660 0.6862449721 -0.0916144386
+ 0.3549996288 0.6510095616 -0.0049896105
+ 0.4223105883 0.6319118158 -0.0750612237
+ 0.2386340718 0.5576061324 -0.4641359113
+-0.1968129036 0.5857219691 -0.4488735002
+-0.3976122076 -0.2191307095 0.6141491902
+ 0.0154135158 -0.1658843935 0.7453440513
+ 0.2878283477 -0.4453831909 0.5496195218
+ 0.9857841031 -0.0268878721 0.1658515735
+ 0.2962650281 0.3250693188 0.6243796397
+ 0.0952478389 0.6424329954 0.4018714458
+-0.3353210426 0.5760695154 0.3728225786
+-0.5908707414 -0.1811642457 0.7861623770
+ 0.1636587448 -0.5673708569 0.4843543014
+ 0.2407945267 -0.5053097542 0.4863569987
+ 0.3372842356 -0.5040934076 0.4641359113
+ 0.4956852875 -0.7825823548 -0.3766443331
+ 0.7627509365 -0.0253485937 0.0293499730
+-0.1563251351 0.5218003355 -0.5353315097
+-0.2407945267 0.5053097542 -0.4863569987
+-0.3317482574 0.4696932387 -0.5026174674
+-0.5786406224 0.4776354422 -0.1425916469
+-0.7565255326 0.0883804086 -0.0561336374
+-0.2919260821 0.6432534269 0.2903397229
+-0.1094594235 0.7502788765 -0.0916144386
+-0.3052303557 0.5535180122 -0.4286551102
+-0.3957787761 -0.6476079559 -0.0851825046
+-0.3549996288 -0.6510095616 0.0049896105
+-0.2892859071 -0.7045960843 0.0561336374
+-0.2386340718 -0.5576061324 0.4641359113
+ 0.1805218931 -0.4844908053 0.5621151741
+ 0.3142555466 0.3448089608 0.8845056427
+-0.4521061491 -0.0413976504 0.6141491902
+-0.7372235705 0.1080865268 -0.1676653603
+-0.7309860539 0.0199380975 -0.1229835081
+-0.7464599260 -0.0758825700 -0.1425916469
+-0.3142555466 -0.3448089608 -0.8845056427
+-0.2976021258 -0.7009390227 -0.0583988402
+-0.0952478389 -0.6424329954 -0.4018714458
+-0.1546934172 -0.3112164741 -0.6800788309
+ 0.4086597528 -0.6147065316 -0.1960256353
+ 0.1094594235 -0.7502788765 0.0916144386
+ 0.3734154496 0.1818211793 -0.6409328546
+ 0.4381469231 0.1343382762 -0.5829610478
+ 0.3991336762 0.0700292964 -0.6473647886
+-0.0154135158 0.1658843935 -0.7453440513
+ 0.6584749455 0.3306819467 -0.2008809586
+ 0.4396986858 0.6232979081 0.0381804502
+ 0.2605432005 -0.5794859313 0.4237997869
+-0.4787409949 -0.8779303974 0.0067288271
+ 0.3026839061 -0.6083857431 -0.3486290347
+-0.2397197699 0.4500906365 -0.5685471081
+ 0.2781047861 0.7112108017 0.0113967858
+ 0.4917743484 0.0510983985 -0.5820995682
+-0.5205170549 0.1164597889 -0.5466187670
+-0.6639032878 0.2012866519 0.3193885901
+-0.7622339142 -0.0253187462 -0.0406372303
+-0.3247276953 0.6814443588 -0.6558852870
+-0.4518947536 0.5718966444 0.2280752574
+-0.4481390643 -0.6183046056 0.0127967581
+ 0.4501613836 0.2319814646 -0.5716924804
+-0.2814926945 -0.1755003908 -0.6879349090
+-0.7310026836 0.0065664230 -0.2210993487
+-0.5698573801 -0.3831078312 -0.3343410226
+-0.2330291401 -0.2556853380 -0.6558852870
+-0.2510608506 -0.3497687395 -0.6308115736
+-0.3294271137 -0.2658915873 -0.6356668969
+ 0.2474173141 -0.3031371410 -0.6558852870
+-0.1735013310 -0.2035127114 -0.7153829937
+3 0 2 1
+5 0 3 14 13 2 3
+3 0 4 3
+3 0 5 4
+3 0 6 5
+5 0 1 7 24 6
+3 1 8 7
+5 1 9 29 16 8 3
+3 1 10 9
+3 1 2 10
+3 2 11 10
+5 2 12 22 37 11
+3 2 13 12
+3 3 15 14
+3 3 16 15
+3 3 8 16
+5 3 4 17 28 8
+3 4 18 17
+5 4 19 48 41 18 3
+3 4 5 19
+5 5 20 49 45 19
+3 5 21 20
+5 5 6 12 38 21 3
+3 6 22 12
+3 6 23 22
+3 6 24 23
+3 7 25 24
+5 7 26 53 31 25 3
+3 7 27 26
+3 7 8 27
+3 8 28 27
+3 9 30 29
+3 9 31 30
+3 9 25 31
+5 9 10 32 52 25
+3 10 33 32
+5 10 11 34 55 33 3
+3 11 35 34
+3 11 36 35
+3 11 37 36
+3 12 39 38
+3 12 13 39
+3 13 40 39
+5 13 34 35 53 40
+3 13 14 34
+3 14 41 34
+3 14 18 41
+5 14 15 42 47 18
+3 15 40 42
+5 15 43 30 39 40 3
+3 15 16 43
+5 16 44 54 50 43
+3 16 29 44
+3 17 45 28
+5 17 36 37 32 45 3
+3 17 46 36
+3 17 18 46
+3 18 47 46
+3 19 33 48
+3 19 32 33
+3 19 45 32
+3 20 24 49
+5 20 50 42 23 24 3
+3 20 43 50
+3 20 21 43
+3 21 30 43
+5 21 48 33 29 30
+3 21 38 48
+3 22 51 37
+5 22 46 47 58 51 3
+3 22 23 46
+5 23 26 27 36 46
+3 23 42 26
+3 24 25 49
+3 25 52 49
+3 26 40 53
+3 26 42 40
+3 27 35 36
+5 27 28 44 57 35 3
+3 28 54 44
+3 28 45 54
+3 29 55 44
+3 29 33 55
+3 30 31 39
+5 31 56 51 38 39
+3 31 53 56
+3 32 37 52
+3 34 41 55
+3 35 57 53
+3 37 51 52
+3 38 58 48
+3 38 51 58
+5 41 58 59 57 55
+3 41 48 58
+3 42 50 47
+3 44 55 57
+3 45 49 54
+3 47 59 58
+3 47 50 59
+5 49 52 56 59 54 3
+3 50 54 59
+3 51 56 52
+3 53 57 56
+3 56 57 59
+6 5 0 1 2 3 4
+6 5 6 7 8 9 0
+6 9 10 11 12 1 0
+6 1 13 14 15 16 2
+6 16 17 18 19 3 2
+6 19 20 21 22 4 3
+6 22 23 24 25 5 4
+6 5 26 27 28 29 6
+6 29 30 16 15 7 6
+6 7 31 32 33 34 8
+6 34 35 36 10 9 8
+6 36 37 38 39 11 10
+6 11 23 22 40 41 12
+6 41 42 43 44 1 12
+6 44 45 46 47 13 1
+6 47 48 49 50 14 13
+6 50 51 52 7 15 14
+6 16 53 54 55 56 17
+6 56 57 47 46 18 17
+6 18 58 59 60 20 19
+6 20 61 62 63 64 21
+6 64 65 66 67 22 21
+6 11 68 69 70 24 23
+6 70 71 72 62 25 24
+6 61 73 26 5 25 62
+6 73 74 34 33 27 26
+6 27 75 76 72 71 28
+6 71 77 78 30 29 28
+6 78 79 80 53 16 30
+6 52 81 82 66 31 7
+6 65 49 83 32 31 66
+6 83 84 85 27 33 32
+6 34 86 54 60 59 35
+6 58 66 82 36 35 59
+6 36 87 45 44 43 37
+6 43 88 78 77 38 37
+6 71 55 54 39 38 77
+6 86 89 68 11 39 54
+6 67 90 91 84 40 22
+6 49 42 41 40 84 83
+6 48 76 75 43 42 49
+6 87 92 93 18 46 45
+6 47 94 62 72 76 48
+6 63 51 50 49 65 64
+6 51 79 78 95 81 52
+6 80 96 20 60 54 53
+6 69 57 56 55 71 70
+6 69 97 98 94 47 57
+6 93 90 67 66 58 18
+6 96 99 74 73 61 20
+6 98 100 51 63 62 94
+6 89 101 84 91 69 68
+6 99 101 89 86 34 74
+6 85 102 88 43 75 27
+6 100 99 96 80 79 51
+6 95 92 87 36 82 81
+6 99 103 102 85 84 101
+6 103 92 95 78 88 102
+6 92 97 69 91 90 93
+6 97 98 100 99 103 92
+great ditrigonal icosidodecahedron
+great triambic icosahedron
+3/2|3 5
+(3.5.3.5.3.5)/2
+icosahedral group
+A5
+12{5}+20{3}
+51 20 60 32 20 6 0 0 -8 2 6 120 5 0 -1
+ 0.0000000000 0.0000000000 1.0000000000
+ 0.9428090416 0.0000000000 0.3333333333
+ 0.2357022604 0.9128709292 0.3333333333
+-0.4714045208 -0.8164965809 0.3333333333
+ 0.6727182848 -0.6605596098 0.3333333333
+-0.4714045208 0.8164965809 0.3333333333
+-0.9084205452 -0.2523113194 0.3333333333
+ 0.4714045208 -0.8164965809 -0.3333333333
+ 0.0900302522 -0.6605596098 0.7453559925
+ 0.4714045208 0.8164965809 -0.3333333333
+ 0.6170765289 -0.2523113194 -0.7453559925
+-0.0900302522 0.6605596098 -0.7453559925
+ 0.9084205452 0.2523113194 -0.3333333333
+-0.6170765289 0.2523113194 0.7453559925
+-0.6727182848 0.6605596098 -0.3333333333
+-0.9428090416 0.0000000000 -0.3333333333
+-0.5270462767 -0.4082482905 -0.7453559925
+-0.2357022604 -0.9128709292 -0.3333333333
+ 0.5270462767 0.4082482905 0.7453559925
+-0.0000000000 0.0000000000 -1.0000000000
+ 0.1326479105 0.1027486297 0.1875924741
+-0.9091823043 0.3717480345 0.1875924741
+ 0.0226589682 -0.1662507751 0.1875924741
+ 0.7765343938 0.6015009550 0.1875924741
+-0.1553068788 0.0635021454 0.1875924741
+ 0.1326479105 -0.9732489895 0.1875924741
+ 0.2286328403 0.0635021454 -0.0838939048
+-0.0819809172 0.6015009550 0.7946544723
+ 0.1693108913 -0.1662507751 0.0838939048
+ 0.4799246488 0.3717480345 -0.7946544723
+-0.1186438980 0.2054972593 0.0838939048
+ 0.5619055661 -0.2297529205 0.7946544723
+ 0.1186438980 0.2054972593 -0.0838939048
+-0.0593219490 -0.2297529205 -0.0838939048
+-0.2286328403 -0.0635021454 0.0838939048
+ 0.0819809172 -0.6015009550 -0.7946544723
+ 0.2372877960 0.0000000000 0.0838939048
+-0.4799246488 -0.3717480345 0.7946544723
+ 0.1186438980 -0.2054972593 -0.0838939048
+-0.1693108913 0.1662507751 -0.0838939048
+ 0.0593219490 0.2297529205 0.0838939048
+-0.5619055661 0.2297529205 -0.7946544723
+-0.1186438980 -0.2054972593 0.0838939048
+-0.2372877960 -0.0000000000 -0.0838939048
+-0.7765343938 -0.6015009550 -0.1875924741
+ 0.1553068788 -0.0635021454 -0.1875924741
+ 0.9091823043 -0.3717480345 -0.1875924741
+ 0.0000000000 0.0000000000 0.2516817145
+-0.0226589682 0.1662507751 -0.1875924741
+ 0.0000000000 -0.0000000000 -0.2516817145
+-0.1326479105 0.9732489895 -0.1875924741
+-0.1326479105 -0.1027486297 -0.1875924741
+3 0 2 1
+5 0 3 16 11 2
+3 0 4 3
+5 0 5 11 10 4
+3 0 6 5
+5 0 1 10 16 6
+3 1 9 10
+5 1 8 6 14 9
+3 1 7 8
+5 1 2 14 16 7
+3 2 13 14
+5 2 12 7 3 13
+3 2 11 12
+3 3 7 16
+3 3 15 13
+5 3 4 12 11 15
+3 4 18 12
+5 4 17 15 5 18
+3 4 10 17
+3 5 15 11
+3 5 9 18
+5 5 6 17 10 9
+3 6 8 17
+3 6 16 14
+5 7 19 14 13 8
+3 7 12 19
+5 8 18 9 19 17
+3 8 13 18
+3 9 14 19
+3 10 11 16
+5 12 18 13 15 19
+3 15 17 19
+6 5 0 1 2 3 4
+6 5 6 7 8 9 0
+6 9 10 11 12 1 0
+6 1 13 11 14 15 2
+6 15 16 17 18 3 2
+6 3 19 17 20 21 4
+6 21 22 7 23 5 4
+6 8 24 25 11 13 9
+6 22 26 27 24 8 7
+6 6 21 20 26 28 7
+6 5 29 3 18 21 6
+6 12 15 19 3 29 1
+6 25 30 16 15 12 11
+6 10 24 27 30 14 11
+6 9 23 7 28 24 10
+6 30 31 17 19 15 14
+6 1 13 9 23 5 29
+6 31 26 22 21 18 17
+6 16 17 20 26 27 30
+6 24 25 30 31 26 28
+great icosicosidodecahedron
+great icosacronic hexecontahedron
+3/2 5|3
+(6.3/2.6.5)
+icosahedral group
+A5
+20{6}+12{5}+20{3/2}
+52 60 120 52 60 6 0 0 -8 3 4 120 5 0 -1
+ 0.0000000000 0.0000000000 1.0000000000
+ 0.7913673487 0.0000000000 0.6113409191
+-0.6820030709 0.4014151117 0.6113409191
+ 0.1126514014 0.7833083316 0.6113409191
+-0.4944105968 -0.6179162098 0.6113409191
+ 0.9007316265 0.4014151117 -0.1659772426
+ 0.4149268310 0.7833083316 0.4628863603
+ 0.7860486710 -0.6179162098 -0.0175226837
+-0.7549125894 -0.4645892808 0.4628863603
+-0.5726387930 0.8028302234 -0.1659772426
+-0.2691077939 0.9487004534 -0.1659772426
+ 0.8343963552 0.2991971590 0.4628863603
+-0.0086058013 -0.9998094297 -0.0175226837
+-0.8708511144 0.1653921218 0.4628863603
+-0.8761697921 -0.4525240881 -0.1659772426
+ 0.8278221080 -0.4645892808 -0.3144318014
+ 0.2187285557 0.8028302234 -0.5546363234
+ 0.0331676357 0.9487004534 -0.3144318014
+-0.1437874830 0.2991971590 0.9432954043
+ 0.8987000724 0.1653921218 -0.4061817646
+ 0.4042894756 -0.4525240881 -0.7948408455
+-0.6906088722 -0.5983943180 -0.4061817646
+-0.0278489580 -0.3307842435 0.9432954043
+-0.0331676357 -0.9487004534 0.3144318014
+ 0.1544248384 0.9366352607 0.3144318014
+-0.5779574707 0.1849140136 -0.7948408455
+ 0.2166970016 0.5668072335 -0.7948408455
+-0.8278221080 0.4645892808 0.3144318014
+-0.7635183907 0.3307842435 -0.5546363234
+ 0.7614868366 -0.5668072335 0.3144318014
+ 0.2756820411 -0.1849140136 0.9432954043
+ 0.1007584765 -0.5983943180 -0.7948408455
+-0.7614868366 0.5668072335 -0.3144318014
+-0.1544248384 -0.9366352607 -0.3144318014
+ 0.7635183907 -0.3307842435 0.5546363234
+ 0.2691077939 -0.9487004534 0.1659772426
+-0.2756820411 0.1849140136 -0.9432954043
+ 0.7549125894 0.4645892808 -0.4628863603
+ 0.0278489580 0.3307842435 -0.9432954043
+-0.2166970016 -0.5668072335 0.7948408455
+ 0.5779574707 -0.1849140136 0.7948408455
+-0.4042894756 0.4525240881 0.7948408455
+-0.4149268310 -0.7833083316 -0.4628863603
+ 0.8761697921 0.4525240881 0.1659772426
+ 0.1437874830 -0.2991971590 -0.9432954043
+-0.1007584765 0.5983943180 0.7948408455
+-0.9007316265 -0.4014151117 0.1659772426
+ 0.8708511144 -0.1653921218 -0.4628863603
+-0.2187285557 -0.8028302234 0.5546363234
+-0.8343963552 -0.2991971590 -0.4628863603
+ 0.5726387930 -0.8028302234 0.1659772426
+-0.1126514014 -0.7833083316 -0.6113409191
+ 0.6906088722 0.5983943180 0.4061817646
+ 0.6820030709 -0.4014151117 -0.6113409191
+-0.8987000724 -0.1653921218 0.4061817646
+-0.7860486710 0.6179162098 0.0175226837
+-0.7913673487 0.0000000000 -0.6113409191
+ 0.4944105968 0.6179162098 -0.6113409191
+ 0.0086058013 0.9998094297 0.0175226837
+ 0.0000000000 0.0000000000 -1.0000000000
+ 0.2317571228 0.8506508084 0.4718917654
+-0.1208775632 0.2515255344 0.4718917654
+-0.8089973662 0.3504874081 0.4718917654
+ 0.2317571228 -0.4822469333 0.4718917654
+ 0.8680129287 0.3504874081 -0.3517273552
+ 0.4473371359 0.2515255344 0.1928281889
+-0.7071184954 0.0703588793 -0.0631535304
+ 0.0842182165 -0.1752437040 0.9809163757
+ 0.3868380289 0.5960899915 -0.0631535304
+-0.4758724578 -0.1921484102 0.1928281889
+-0.8159632084 -0.4587939735 -0.3517273552
+ 0.7247791497 -0.1752437040 0.6663218655
+ 0.3823128290 0.0703588793 -0.5981988263
+-0.2864675581 0.5960899915 0.2675226479
+ 0.2204861533 -0.4587939735 -0.8607519655
+ 0.4435182383 -0.1921484102 -0.2587061630
+ 0.0772523743 -0.9845250856 0.1572972551
+-0.1732277900 -0.3702797828 0.3652989642
+-0.0423522231 0.5397481497 -0.0862353877
+ 0.3159753393 0.6754071043 -0.6663218655
+-0.7247791497 0.1752437040 -0.6663218655
+-0.3949869091 0.3702797828 -0.0862353877
+ 0.3973471176 -0.0960742051 0.3652989642
+ 0.7204740224 -0.6754071043 0.1572972551
+-0.1270566693 -0.4663539879 -0.2587061630
+-0.3159753393 -0.6754071043 0.6663218655
+-0.2937894852 -0.2545608169 -0.5981988263
+ 0.3949869091 -0.3702797828 0.0862353877
+-0.7204740224 0.6754071043 -0.1572972551
+ 0.1732277900 0.3702797828 -0.3652989642
+-0.0842182165 0.1752437040 -0.9809163757
+ 0.0461711207 -0.0960742051 0.5377697395
+ 0.2937894852 0.2545608169 0.5981988263
+-0.8680129287 -0.3504874081 0.3517273552
+ 0.2864675581 -0.5960899915 -0.2675226479
+-0.0461711207 0.0960742051 -0.5377697395
+-0.3823128290 -0.0703588793 0.5981988263
+-0.0772523743 0.9845250856 -0.1572972551
+ 0.8159632084 0.4587939735 0.3517273552
+-0.3973471176 0.0960742051 -0.3652989642
+ 0.0423522231 -0.5397481497 0.0862353877
+ 0.8089973662 -0.3504874081 -0.4718917654
+-0.3868380289 -0.5960899915 0.0631535304
+ 0.7071184954 -0.0703588793 0.0631535304
+-0.2204861533 0.4587939735 0.8607519655
+-0.4435182383 0.1921484102 0.2587061630
+-0.4473371359 -0.2515255344 -0.1928281889
+ 0.4758724578 0.1921484102 -0.1928281889
+ 0.1270566693 0.4663539879 0.2587061630
+-0.2317571228 -0.8506508084 -0.4718917654
+ 0.1208775632 -0.2515255344 -0.4718917654
+-0.2317571228 0.4822469333 -0.4718917654
+6 0 2 9 16 5 1
+3 0 3 2 2
+6 0 4 14 28 10 3
+5 0 1 7 12 4
+6 1 6 17 38 20 7
+3 1 5 6 2
+5 2 8 21 25 9
+6 2 3 11 29 23 8
+5 3 10 26 19 11
+3 4 13 14 2
+6 4 12 31 36 32 13
+6 5 15 35 39 18 6
+5 5 16 36 31 15
+5 6 18 13 32 17
+6 7 19 26 25 21 12
+3 7 20 19 2
+6 8 22 34 15 31 21
+3 8 23 22 2
+3 9 24 16 2
+6 9 25 44 47 43 24
+6 10 27 46 42 44 26
+3 10 28 27 2
+3 11 30 29 2
+6 11 19 20 33 48 30
+3 12 21 31 2
+6 13 18 40 50 33 14
+5 14 33 20 38 28
+3 15 34 35 2
+6 16 24 41 54 49 36
+3 17 37 38 2
+6 17 32 49 51 53 37
+3 18 39 40 2
+5 22 41 24 43 34
+6 22 23 42 56 55 41
+5 23 29 47 44 42
+3 25 26 44 2
+5 27 45 30 48 46
+6 27 28 38 37 52 45
+6 29 30 45 58 57 47
+3 32 36 49 2
+3 33 50 48 2
+6 34 43 57 59 51 35
+5 35 51 49 54 39
+5 37 53 50 40 52
+6 39 54 55 58 52 40
+3 41 55 54 2
+3 42 46 56 2
+3 43 47 57 2
+3 45 52 58 2
+6 46 48 50 53 59 56
+3 51 59 53 2
+5 55 56 59 57 58
+4 3 0 1 2
+4 3 4 5 0
+4 0 6 7 1
+4 7 8 2 1
+4 2 9 10 3
+4 5 11 12 0
+4 4 13 11 5
+4 3 14 15 4
+4 6 16 17 7
+4 0 18 19 6
+4 8 20 21 2
+4 7 22 23 8
+4 10 24 14 3
+4 9 25 13 10
+4 2 26 25 9
+4 11 27 16 12
+4 12 28 18 0
+4 4 29 30 13
+4 25 31 11 13
+4 14 8 23 15
+4 23 26 4 15
+4 6 14 24 16
+4 16 32 33 17
+4 33 34 7 17
+4 28 32 19 18
+4 19 35 14 6
+4 35 20 8 14
+4 20 36 37 21
+4 37 26 2 21
+4 34 38 22 7
+4 38 36 23 22
+4 10 12 16 24
+4 30 39 10 13
+4 23 40 25 26
+4 27 41 32 16
+4 11 42 41 27
+4 39 28 12 10
+4 29 37 43 30
+4 4 29 37 26
+4 31 44 42 11
+4 25 43 44 31
+4 28 45 33 32
+4 33 46 20 34
+4 41 47 19 32
+4 19 34 20 35
+4 38 48 37 36
+4 46 49 36 20
+4 47 38 34 19
+4 49 40 23 36
+4 30 42 28 39
+4 49 43 25 40
+4 30 50 41 42
+4 48 44 43 37
+4 49 50 30 43
+4 44 45 28 42
+4 44 51 33 45
+4 51 49 46 33
+4 41 51 38 47
+4 38 48 44 51
+4 50 41 51 49
+small icosihemidodecahedron
+small icosihemidodecacron
+3/2 3|5
+(10.3/2.10.3)
+icosahedral group
+A5
+6{10}+10{3}+10{3/2}
+53 30 60 26 30 0 1 1 -4 3 4 120 5 1 -1
+ 0.0000000000 0.0000000000 1.0000000000
+ 0.5877852523 0.0000000000 0.8090169944
+-0.5877852523 0.0000000000 0.8090169944
+-0.2628655561 0.5257311121 0.8090169944
+ 0.2628655561 -0.5257311121 0.8090169944
+ 0.9510565163 0.0000000000 0.3090169944
+ 0.6881909602 0.5257311121 0.5000000000
+-0.6881909602 -0.5257311121 0.5000000000
+-0.9510565163 0.0000000000 0.3090169944
+-0.4253254042 0.8506508084 0.3090169944
+ 0.1624598481 0.8506508084 0.5000000000
+-0.1624598481 -0.8506508084 0.5000000000
+ 0.4253254042 -0.8506508084 0.3090169944
+ 0.8506508084 -0.5257311121 0.0000000000
+ 0.9510565163 0.0000000000 -0.3090169944
+ 0.5257311121 0.8506508084 0.0000000000
+-0.5257311121 -0.8506508084 0.0000000000
+-0.9510565163 0.0000000000 -0.3090169944
+-0.8506508084 0.5257311121 0.0000000000
+-0.4253254042 0.8506508084 -0.3090169944
+ 0.4253254042 -0.8506508084 -0.3090169944
+ 0.5877852523 0.0000000000 -0.8090169944
+ 0.6881909602 0.5257311121 -0.5000000000
+ 0.1624598481 0.8506508084 -0.5000000000
+-0.1624598481 -0.8506508084 -0.5000000000
+-0.6881909602 -0.5257311121 -0.5000000000
+-0.5877852523 0.0000000000 -0.8090169944
+-0.2628655561 0.5257311121 -0.8090169944
+ 0.2628655561 -0.5257311121 -0.8090169944
+ 0.0000000000 0.0000000000 -1.0000000000
+ 0.0000000000 1.0000000000 0.0000000000
+-0.3035309991 0.1875924741 0.9341723590
+-0.8944271910 -0.4472135955 0.0000000000
+ 0.3035309991 -0.1875924741 0.9341723590
+ 0.7236067977 -0.4472135955 -0.5257311121
+ 0.7946544723 0.1875924741 0.5773502692
+-0.7946544723 -0.1875924741 0.5773502692
+ 0.7236067977 -0.4472135955 0.5257311121
+-0.1875924741 0.7946544723 0.5773502692
+ 0.1875924741 -0.7946544723 0.5773502692
+-0.2763932023 -0.4472135955 0.8506508084
+ 0.9822469464 -0.1875924741 0.0000000000
+ 0.4911234732 0.7946544723 0.3568220898
+-0.2763932023 -0.4472135955 -0.8506508084
+-0.4911234732 -0.7946544723 0.3568220898
+-0.9822469464 0.1875924741 0.0000000000
+-0.6070619982 0.7946544723 0.0000000000
+ 0.6070619982 -0.7946544723 0.0000000000
+ 0.7946544723 0.1875924741 -0.5773502692
+ 0.4911234732 0.7946544723 -0.3568220898
+-0.4911234732 -0.7946544723 -0.3568220898
+-0.7946544723 -0.1875924741 -0.5773502692
+-0.1875924741 0.7946544723 -0.5773502692
+ 0.1875924741 -0.7946544723 -0.5773502692
+ 0.3035309991 -0.1875924741 -0.9341723590
+-0.3035309991 0.1875924741 -0.9341723590
+10 0 1 5 14 21 29 26 17 8 2
+3 0 2 3 2
+10 0 3 9 19 27 29 28 20 12 4
+3 0 1 4
+10 1 4 11 16 25 26 27 23 15 6
+3 1 6 5 2
+3 2 8 7
+10 2 7 16 24 28 21 22 15 10 3
+3 3 10 9
+3 4 12 11 2
+10 5 6 10 9 18 17 25 24 20 13
+3 5 13 14
+3 6 15 10
+10 7 8 18 19 23 22 14 13 12 11
+3 7 11 16 2
+3 8 17 18 2
+3 9 18 19 2
+3 12 20 13
+3 14 22 21 2
+3 15 23 22 2
+3 16 25 24
+3 17 26 25
+3 19 23 27
+3 20 28 24 2
+3 21 28 29
+3 26 29 27 2
+4 3 0 1 2
+4 3 4 5 0
+4 6 0 1 7
+4 8 7 1 2
+4 9 2 3 4
+4 5 10 11 0
+4 12 4 5 10
+4 6 13 14 7
+4 15 0 6 13
+4 8 10 16 2
+4 12 7 8 10
+4 9 13 14 4
+4 17 2 9 13
+4 17 10 11 13
+4 18 13 11 0
+4 19 4 12 7
+4 20 4 14 7
+4 21 0 15 10
+4 16 13 15 10
+4 22 13 16 2
+4 23 2 17 10
+4 18 7 24 0
+4 19 13 18 7
+4 22 4 19 13
+4 20 10 23 7
+4 21 4 20 10
+4 25 0 21 4
+4 25 2 22 4
+4 24 2 23 7
+4 24 0 25 2
+small dodecicosahedron
+small dodecicosacron
+3/2 3 5|
+(10.6.10/9.6/5)
+icosahedral group
+A5
+6{10}+10{6}+10{6/5}+6{10/9}
+54 60 120 32 60 0 0 1 -28 4 4 120 5 0 2
+ 0.0000000000 0.0000000000 1.0000000000
+ 0.5558508647 0.0000000000 0.8312820317
+-0.5423346067 0.1218333214 0.8312820317
+ 0.2523198656 -0.4952826155 0.8312820317
+-0.3547421326 0.4279348118 0.8312820317
+ 0.9129018498 0.1218333214 0.3895726561
+ 0.7569595968 0.4279348118 0.4938460950
+-0.8323493477 -0.2516159727 0.4938460950
+-0.0195609124 0.3526376782 0.9355554706
+-0.8639995688 0.3189637764 0.3895726561
+ 0.3058398516 -0.8687319096 0.3895726561
+-0.0376948755 -0.8687319096 0.4938460950
+-0.1536334005 0.8558696236 0.4938460950
+-0.3230919115 -0.1426449373 0.9355554706
+-0.6764070948 0.6250652668 0.3895726561
+ 0.9664218358 -0.2516159727 -0.0521367195
+ 0.5362899523 0.3526376782 0.7668375023
+ 0.9347716147 0.3189637764 -0.1564101584
+ 0.4022174642 0.8558696236 0.3251281267
+ 0.7886098179 -0.1426449373 0.5981195340
+ 0.7788293617 0.6250652668 -0.0521367195
+-0.7788293617 -0.6250652668 0.0521367195
+-0.5800294821 -0.7468985882 0.3251281267
+ 0.1815478197 0.7805724901 0.5981195340
+-0.8421298039 0.5160942314 -0.1564101584
+-0.6628908367 0.7468985882 0.0521367195
+ 0.6628908367 -0.7468985882 -0.0521367195
+-0.0707720459 -0.6379275528 0.7668375023
+ 0.1401171424 -0.9777029450 -0.1564101584
+ 0.4850788188 -0.6379275528 0.5981195340
+-0.2034175846 -0.9777029450 -0.0521367195
+ 0.2034175846 0.9777029450 0.0521367195
+-0.6131066526 -0.5160942314 0.5981195340
+-0.9664218358 0.2516159727 0.0521367195
+ 0.6764070948 -0.6250652668 -0.3895726561
+ 0.6131066526 0.5160942314 -0.5981195340
+ 0.5800294821 0.7468985882 -0.3251281267
+-0.1401171424 0.9777029450 0.1564101584
+ 0.8421298039 -0.5160942314 0.1564101584
+ 0.8323493477 0.2516159727 -0.4938460950
+-0.7569595968 -0.4279348118 -0.4938460950
+-0.4022174642 -0.8558696236 -0.3251281267
+-0.9347716147 -0.3189637764 0.1564101584
+-0.7886098179 0.1426449373 -0.5981195340
+-0.4850788188 0.6379275528 -0.5981195340
+-0.3058398516 0.8687319096 -0.3895726561
+ 0.8639995688 -0.3189637764 -0.3895726561
+-0.1815478197 -0.7805724901 -0.5981195340
+ 0.1536334005 -0.8558696236 -0.4938460950
+ 0.0376948755 0.8687319096 -0.4938460950
+-0.9129018498 -0.1218333214 -0.3895726561
+ 0.3547421326 -0.4279348118 -0.8312820317
+ 0.3230919115 0.1426449373 -0.9355554706
+ 0.0707720459 0.6379275528 -0.7668375023
+ 0.5423346067 -0.1218333214 -0.8312820317
+-0.5558508647 -0.0000000000 -0.8312820317
+-0.5362899523 -0.3526376782 -0.7668375023
+-0.2523198656 0.4952826155 -0.8312820317
+ 0.0195609124 -0.3526376782 -0.9355554706
+ 0.0000000000 -0.0000000000 -1.0000000000
+ 0.1036376133 0.9341723590 0.3414399638
+-0.1494536576 -0.1924500897 0.3414399638
+-0.7853356508 -0.5163977795 0.3414399638
+ 0.1036376133 0.2205281794 0.3414399638
+ 0.8426251145 -0.5163977795 -0.1526965938
+ 0.3140278393 -0.1924500897 0.2007589619
+-0.1758443548 0.2833126966 0.2544943231
+ 0.1963339127 -0.7369259589 0.6468331514
+-0.3322633625 0.0280780897 0.2544943231
+ 0.7457496051 0.1595756897 0.6468331514
+ 0.2876371421 0.2833126966 0.1138133213
+-0.2603854803 0.1595756897 0.9522263391
+ 0.4176654526 0.0280780897 0.0268676806
+-0.4176654526 -0.0280780897 -0.0268676806
+-0.7457496051 -0.1595756897 -0.6468331514
+-0.8426251145 0.5163977795 0.1526965938
+ 0.1199479612 -0.0735093931 0.3951753249
+-0.1218731366 -0.3849001795 0.1138133213
+ 0.1645741816 -0.3849001795 0.0268676806
+-0.1645741816 0.3849001795 -0.0268676806
+-0.1963339127 0.7369259589 -0.6468331514
+ 0.2603854803 -0.1595756897 -0.9522263391
+ 0.3322633625 -0.0280780897 -0.2544943231
+ 0.7853356508 0.5163977795 -0.3414399638
+ 0.1218731366 0.3849001795 -0.1138133213
+-0.2876371421 -0.2833126966 -0.1138133213
+-0.3140278393 0.1924500897 -0.2007589619
+ 0.1758443548 -0.2833126966 -0.2544943231
+-0.1036376133 -0.9341723590 -0.3414399638
+ 0.1494536576 0.1924500897 -0.3414399638
+-0.1036376133 -0.2205281794 -0.3414399638
+-0.1199479612 0.0735093931 -0.3951753249
+10 0 2 9 24 44 53 35 17 5 1
+6 0 3 11 22 7 2
+10 0 4 14 24 43 56 47 28 10 3 9
+6 0 1 6 18 12 4 5
+10 1 3 11 30 47 58 52 35 20 6 9
+6 1 5 15 26 10 3
+6 2 8 23 37 25 9 5
+10 2 7 21 41 48 34 15 5 16 8 9
+6 4 13 32 42 33 14
+10 4 12 31 36 39 46 26 10 27 13
+6 5 17 36 31 23 16 5
+10 6 19 29 11 22 42 33 25 37 18
+6 6 20 39 46 38 19
+6 7 9 24 43 40 21 5
+10 7 22 30 48 51 52 53 45 25 9
+10 8 13 32 21 40 55 57 49 31 23
+6 8 16 19 29 27 13
+6 10 28 41 21 32 27
+6 11 30 48 34 38 29 5
+6 12 14 24 44 49 31
+10 12 18 20 39 54 58 56 50 33 14 9
+10 15 17 36 49 44 43 40 41 28 26
+6 15 34 51 52 35 17 5
+10 16 23 37 45 57 59 51 34 38 19
+6 18 37 45 53 35 20
+6 22 42 50 56 47 30 5
+6 25 33 50 55 57 45
+6 26 46 54 58 47 28
+10 27 32 42 50 55 59 54 46 38 29 9
+6 36 49 57 59 54 39
+6 40 41 48 51 59 55
+6 43 44 53 52 58 56 5
+4 3 0 1 2
+4 3 4 5 0
+4 0 6 7 1
+4 1 4 5 2
+4 2 8 9 3
+4 5 7 10 0
+4 3 11 12 4
+4 7 13 14 1
+4 6 15 16 7
+4 0 13 14 6
+4 5 9 17 2
+4 1 11 18 4
+4 9 19 20 3
+4 8 15 16 9
+4 2 19 20 8
+4 5 21 22 7
+4 16 23 10 7
+4 10 21 22 0
+4 20 24 11 3
+4 11 16 23 12
+4 12 20 24 4
+4 7 17 15 13
+4 14 25 11 1
+4 6 23 10 15
+4 0 19 2 13
+4 14 26 11 6
+4 21 27 9 5
+4 16 28 17 9
+4 17 21 27 2
+4 28 18 11 16
+4 18 14 25 4
+4 9 10 15 19
+4 8 28 17 15
+4 20 26 11 8
+4 22 23 18 7
+4 22 4 24 0
+4 9 29 21 10
+4 24 23 6 11
+4 28 12 23 18
+4 12 9 29 20
+4 15 30 21 13
+4 7 30 21 17
+4 25 28 8 11
+4 2 31 21 13
+4 0 31 21 19
+4 14 24 23 26
+4 27 28 12 9
+4 27 4 25 2
+4 30 14 18 7
+4 15 29 21 19
+4 20 25 28 26
+4 22 14 30 23
+4 14 31 4 22
+4 24 0 31 14
+4 29 28 27 20
+4 15 26 28 30
+4 20 31 2 25
+4 23 29 15 26
+4 27 4 31 20
+4 30 23 29 28
+small dodecahemidodecahedron
+small dodecahemidodecacron
+5/4 5|5
+(10.5/4.10.5)
+icosahedral group
+A5
+6{10}+6{5}+6{5/4}
+55 30 60 18 30 0 1 1 -12 3 4 120 5 1 -1
+ 0.0000000000 0.0000000000 1.0000000000
+ 0.5877852523 0.0000000000 0.8090169944
+-0.5877852523 0.0000000000 0.8090169944
+ 0.2628655561 0.5257311121 0.8090169944
+-0.2628655561 -0.5257311121 0.8090169944
+ 0.9510565163 0.0000000000 0.3090169944
+ 0.6881909602 -0.5257311121 0.5000000000
+-0.6881909602 0.5257311121 0.5000000000
+-0.9510565163 -0.0000000000 0.3090169944
+ 0.4253254042 0.8506508084 0.3090169944
+-0.1624598481 0.8506508084 0.5000000000
+ 0.1624598481 -0.8506508084 0.5000000000
+-0.4253254042 -0.8506508084 0.3090169944
+ 0.8506508084 0.5257311121 0.0000000000
+ 0.9510565163 0.0000000000 -0.3090169944
+ 0.5257311121 -0.8506508084 0.0000000000
+-0.5257311121 0.8506508084 0.0000000000
+-0.9510565163 -0.0000000000 -0.3090169944
+-0.8506508084 -0.5257311121 0.0000000000
+ 0.4253254042 0.8506508084 -0.3090169944
+-0.4253254042 -0.8506508084 -0.3090169944
+ 0.5877852523 0.0000000000 -0.8090169944
+ 0.6881909602 -0.5257311121 -0.5000000000
+ 0.1624598481 -0.8506508084 -0.5000000000
+-0.6881909602 0.5257311121 -0.5000000000
+-0.1624598481 0.8506508084 -0.5000000000
+-0.5877852523 -0.0000000000 -0.8090169944
+ 0.2628655561 0.5257311121 -0.8090169944
+-0.2628655561 -0.5257311121 -0.8090169944
+ 0.0000000000 0.0000000000 -1.0000000000
+ 0.0000000000 1.0000000000 0.0000000000
+-0.2763932023 0.4472135955 0.8506508084
+-0.8944271910 0.4472135955 0.0000000000
+ 0.2763932023 -0.4472135955 0.8506508084
+ 0.7236067977 0.4472135955 -0.5257311121
+ 0.7236067977 0.4472135955 0.5257311121
+-0.7236067977 -0.4472135955 0.5257311121
+ 0.7236067977 0.4472135955 0.5257311121
+-0.2763932023 0.4472135955 0.8506508084
+ 0.8944271910 -0.4472135955 0.0000000000
+-0.8944271910 0.4472135955 0.0000000000
+ 0.2763932023 -0.4472135955 0.8506508084
+-0.0000000000 1.0000000000 0.0000000000
+ 0.0000000000 -1.0000000000 0.0000000000
+ 0.7236067977 0.4472135955 -0.5257311121
+-0.7236067977 -0.4472135955 -0.5257311121
+ 0.2763932023 -0.4472135955 -0.8506508084
+-0.2763932023 0.4472135955 -0.8506508084
+10 0 1 5 14 21 29 26 17 8 2
+5 0 2 7 10 3 4
+10 0 3 9 19 27 29 28 20 12 4
+5 0 1 6 11 4
+10 1 6 15 23 28 26 24 16 10 3
+5 1 3 9 13 5 4
+5 2 8 18 12 4
+10 2 4 11 15 22 21 27 25 16 7
+10 5 13 19 25 24 17 18 12 11 6
+5 5 6 15 22 14
+5 7 16 24 17 8
+10 7 8 18 20 23 22 14 13 9 10
+5 9 10 16 25 19 4
+5 11 15 23 20 12 4
+5 13 14 21 27 19
+5 17 26 28 20 18
+5 21 22 23 28 29
+5 24 26 29 27 25 4
+4 3 0 1 2
+4 3 4 5 0
+4 6 0 1 7
+4 1 4 5 2
+4 6 2 3 7
+4 5 8 9 0
+4 3 8 9 4
+4 10 7 1 11
+4 10 0 6 11
+4 5 11 12 2
+4 12 4 1 11
+4 13 7 3 8
+4 13 2 6 8
+4 14 11 5 8
+4 9 11 14 0
+4 9 7 13 4
+4 12 7 10 4
+4 15 0 10 8
+4 15 11 6 8
+4 12 8 14 2
+4 15 2 13 11
+4 14 7 16 0
+4 16 11 9 7
+4 16 4 13 11
+4 17 4 10 8
+4 17 7 12 8
+4 17 0 15 4
+4 17 2 14 7
+4 16 2 15 4
+4 16 0 17 2
+great stellated dodecahedron
+great icosahedron
+3|2 5/2
+(5/2.5/2.5/2)
+icosahedral group
+A5
+12{5/2}
+56 20 30 12 20 7 0 0 2 1 3 120 5 0 -1
+ 0.0000000000 0.0000000000 1.0000000000
+ 0.6666666667 0.0000000000 -0.7453559925
+-0.3333333333 0.5773502692 -0.7453559925
+-0.3333333333 -0.5773502692 -0.7453559925
+-0.7453559925 0.5773502692 0.3333333333
+-0.7453559925 -0.5773502692 0.3333333333
+-0.1273220038 -0.9341723590 0.3333333333
+ 0.8726779962 -0.3568220898 0.3333333333
+ 0.8726779962 0.3568220898 0.3333333333
+-0.1273220038 0.9341723590 0.3333333333
+ 0.1273220038 -0.9341723590 -0.3333333333
+ 0.1273220038 0.9341723590 -0.3333333333
+ 0.7453559925 0.5773502692 -0.3333333333
+-0.8726779962 -0.3568220898 -0.3333333333
+-0.8726779962 0.3568220898 -0.3333333333
+ 0.7453559925 -0.5773502692 -0.3333333333
+ 0.3333333333 0.5773502692 0.7453559925
+ 0.3333333333 -0.5773502692 0.7453559925
+-0.6666666667 0.0000000000 0.7453559925
+ 0.0000000000 0.0000000000 -1.0000000000
+ 0.4911234732 0.8506508084 0.1875924741
+-0.9822469464 0.0000000000 0.1875924741
+ 0.4911234732 -0.8506508084 0.1875924741
+-0.6070619982 0.0000000000 -0.7946544723
+ 0.3035309991 -0.5257311121 -0.7946544723
+ 0.3035309991 0.5257311121 -0.7946544723
+-0.3035309991 -0.5257311121 0.7946544723
+-0.3035309991 0.5257311121 0.7946544723
+ 0.6070619982 -0.0000000000 0.7946544723
+ 0.9822469464 0.0000000000 -0.1875924741
+-0.4911234732 0.8506508084 -0.1875924741
+-0.4911234732 -0.8506508084 -0.1875924741
+5 0 2 7 4 1 2
+5 0 3 9 6 2 2
+5 0 1 5 8 3 2
+5 1 4 10 11 5 2
+5 2 6 12 13 7 2
+5 3 8 14 15 9 2
+5 4 7 13 16 10 2
+5 5 11 17 14 8 2
+5 6 9 15 18 12 2
+5 10 16 19 17 11 2
+5 12 18 19 16 13 2
+5 14 17 19 18 15 2
+3 2 0 1
+3 2 3 0
+3 0 4 1
+3 1 5 2
+3 3 6 0
+3 2 7 3
+3 4 8 1
+3 6 4 0
+3 5 7 2
+3 8 5 1
+3 3 9 6
+3 7 9 3
+3 4 10 8
+3 6 10 4
+3 5 11 7
+3 8 11 5
+3 9 10 6
+3 11 9 7
+3 10 11 8
+3 9 10 11
+great icosahedron
+great stellated dodecahedron
+5/2|2 3
+(3.3.3.3.3)/2
+icosahedral group
+A5
+20{3}
+57 12 30 20 12 7 0 0 2 1 5 120 5 0 -1
+ 0.0000000000 0.0000000000 1.0000000000
+ 0.8944271910 0.0000000000 -0.4472135955
+-0.7236067977 0.5257311121 -0.4472135955
+ 0.2763932023 -0.8506508084 -0.4472135955
+ 0.2763932023 0.8506508084 -0.4472135955
+-0.7236067977 -0.5257311121 -0.4472135955
+-0.2763932023 -0.8506508084 0.4472135955
+-0.2763932023 0.8506508084 0.4472135955
+ 0.7236067977 0.5257311121 0.4472135955
+-0.8944271910 -0.0000000000 0.4472135955
+ 0.7236067977 -0.5257311121 0.4472135955
+ 0.0000000000 -0.0000000000 -1.0000000000
+ 0.3035309991 0.9341723590 0.1875924741
+-0.7946544723 -0.5773502692 0.1875924741
+ 0.9822469464 0.0000000000 0.1875924741
+-0.7946544723 0.5773502692 0.1875924741
+ 0.3035309991 -0.9341723590 0.1875924741
+-0.1875924741 0.5773502692 -0.7946544723
+ 0.6070619982 0.0000000000 0.7946544723
+-0.1875924741 -0.5773502692 -0.7946544723
+-0.4911234732 0.3568220898 0.7946544723
+ 0.4911234732 0.3568220898 -0.7946544723
+ 0.1875924741 -0.5773502692 0.7946544723
+-0.6070619982 -0.0000000000 -0.7946544723
+ 0.1875924741 0.5773502692 0.7946544723
+ 0.4911234732 -0.3568220898 -0.7946544723
+-0.4911234732 -0.3568220898 0.7946544723
+-0.9822469464 -0.0000000000 -0.1875924741
+ 0.7946544723 -0.5773502692 -0.1875924741
+ 0.7946544723 0.5773502692 -0.1875924741
+-0.3035309991 0.9341723590 -0.1875924741
+-0.3035309991 -0.9341723590 -0.1875924741
+3 0 2 1
+3 0 3 2
+3 0 4 3
+3 0 5 4
+3 0 1 5
+3 1 7 5
+3 1 6 7
+3 1 2 6
+3 2 8 6
+3 2 3 8
+3 3 9 8
+3 3 4 9
+3 4 10 9
+3 4 5 10
+3 5 7 10
+3 6 11 7
+3 6 8 11
+3 7 11 10
+3 8 9 11
+3 9 10 11
+5 4 0 1 2 3
+5 4 5 6 7 0
+5 7 8 9 1 0
+5 9 10 11 2 1
+5 11 12 13 3 2
+5 13 14 5 4 3
+5 6 15 16 8 7
+5 14 17 15 6 5
+5 16 18 10 9 8
+5 18 19 12 11 10
+5 19 17 14 13 12
+5 15 16 18 19 17
+great icosidodecahedron
+great rhombic triacontahedron
+2|5/2 3
+(5/2.3.5/2.3)
+icosahedral group
+A5
+20{3}+12{5/2}
+58 30 60 32 30 7 0 0 2 2 4 120 5 0 -1
+ 0.0000000000 0.0000000000 1.0000000000
+ 0.9510565163 0.0000000000 -0.3090169944
+ 0.4253254042 0.8506508084 -0.3090169944
+-0.9510565163 0.0000000000 -0.3090169944
+-0.4253254042 -0.8506508084 -0.3090169944
+-0.1624598481 0.8506508084 0.5000000000
+-0.5877852523 0.0000000000 -0.8090169944
+-0.2628655561 -0.5257311121 -0.8090169944
+ 0.6881909602 -0.5257311121 0.5000000000
+ 0.1624598481 -0.8506508084 0.5000000000
+ 0.5877852523 -0.0000000000 -0.8090169944
+ 0.2628655561 0.5257311121 -0.8090169944
+-0.6881909602 0.5257311121 0.5000000000
+-0.8506508084 -0.5257311121 -0.0000000000
+ 0.5257311121 -0.8506508084 -0.0000000000
+-0.5877852523 -0.0000000000 0.8090169944
+-0.2628655561 -0.5257311121 0.8090169944
+-0.5257311121 0.8506508084 0.0000000000
+ 0.8506508084 0.5257311121 -0.0000000000
+ 0.5877852523 -0.0000000000 0.8090169944
+ 0.2628655561 0.5257311121 0.8090169944
+ 0.6881909602 -0.5257311121 -0.5000000000
+-0.1624598481 0.8506508084 -0.5000000000
+ 0.9510565163 -0.0000000000 0.3090169944
+ 0.4253254042 0.8506508084 0.3090169944
+-0.6881909602 0.5257311121 -0.5000000000
+ 0.1624598481 -0.8506508084 -0.5000000000
+-0.9510565163 0.0000000000 0.3090169944
+-0.4253254042 -0.8506508084 0.3090169944
+ 0.0000000000 0.0000000000 -1.0000000000
+ 0.4911234732 0.3035309991 0.3568220898
+-0.4911234732 0.7946544723 0.3568220898
+-0.4911234732 -0.3035309991 0.3568220898
+ 0.4911234732 -0.7946544723 0.3568220898
+ 0.1875924741 -0.3035309991 -0.5773502692
+ 0.1875924741 0.7946544723 -0.5773502692
+ 0.7946544723 -0.1875924741 -0.5773502692
+-0.1875924741 0.3035309991 -0.5773502692
+-0.1875924741 -0.7946544723 -0.5773502692
+-0.7946544723 0.1875924741 -0.5773502692
+-0.6070619982 0.3035309991 -0.0000000000
+-0.3035309991 -0.1875924741 0.9341723590
+-0.6070619982 -0.7946544723 -0.0000000000
+-0.0000000000 -0.6787159473 -0.0000000000
+-0.9822469464 -0.1875924741 0.0000000000
+ 0.6070619982 -0.3035309991 -0.0000000000
+ 0.3035309991 0.1875924741 0.9341723590
+ 0.6070619982 0.7946544723 -0.0000000000
+ 0.0000000000 0.6787159473 0.0000000000
+ 0.9822469464 0.1875924741 0.0000000000
+-0.3035309991 -0.1875924741 -0.9341723590
+ 0.1875924741 -0.3035309991 0.5773502692
+ 0.1875924741 0.7946544723 0.5773502692
+ 0.7946544723 -0.1875924741 0.5773502692
+-0.1875924741 0.3035309991 0.5773502692
+ 0.3035309991 0.1875924741 -0.9341723590
+-0.1875924741 -0.7946544723 0.5773502692
+-0.7946544723 0.1875924741 0.5773502692
+ 0.4911234732 0.3035309991 -0.3568220898
+ 0.4911234732 -0.7946544723 -0.3568220898
+-0.4911234732 0.7946544723 -0.3568220898
+-0.4911234732 -0.3035309991 -0.3568220898
+5 0 2 8 5 1 2
+3 0 3 2
+5 0 4 12 9 3 2
+3 0 1 4
+5 1 6 14 11 4 2
+3 1 5 6
+3 2 7 8
+5 2 3 10 17 7 2
+3 3 9 10
+3 4 11 12
+5 5 13 22 15 6 2
+3 5 8 13
+3 6 15 14
+5 7 16 21 13 8 2
+3 7 17 16
+5 9 18 26 19 10 2
+3 9 12 18
+3 10 19 17
+5 11 20 25 18 12 2
+3 11 14 20
+3 13 21 22
+5 14 15 23 28 20 2
+3 15 22 23
+3 16 24 21
+5 16 17 19 27 24 2
+3 18 25 26
+3 19 26 27
+3 20 28 25
+5 21 24 29 23 22 2
+3 23 29 28
+3 24 27 29
+5 25 28 29 27 26 2
+4 3 0 1 2
+4 3 4 5 0
+4 0 6 7 1
+4 7 8 2 1
+4 2 9 4 3
+4 5 10 11 0
+4 4 12 10 5
+4 6 13 14 7
+4 11 13 6 0
+4 8 15 16 2
+4 7 17 15 8
+4 9 18 19 4
+4 16 18 9 2
+4 10 20 13 11
+4 19 21 12 4
+4 21 22 10 12
+4 13 23 24 14
+4 24 17 7 14
+4 15 25 18 16
+4 24 26 15 17
+4 18 27 21 19
+4 20 28 23 13
+4 22 28 20 10
+4 21 29 28 22
+4 28 30 24 23
+4 25 31 27 18
+4 26 31 25 15
+4 30 31 26 24
+4 31 29 21 27
+4 29 28 30 31
+great truncated icosahedron
+great stellapentakisdodecahedron
+2 5/2|3
+(6.6.5/2)
+icosahedral group
+A5
+20{6}+12{5/2}
+59 60 90 32 60 7 0 0 2 2 3 120 5 0 -1
+ 0.0000000000 0.0000000000 1.0000000000
+ 0.8356150397 0.0000000000 0.5493154881
+-0.7824189491 0.2933821444 0.5493154881
+ 0.6296037101 -0.5494102864 0.5493154881
+ 0.8888111303 0.2933821444 -0.3520535357
+ 0.1131652141 -0.5494102864 0.8278538347
+-0.9352341880 0.0373540025 -0.3520535357
+-0.7292228585 0.5867642889 -0.3520535357
+ 0.4464985474 0.3395542307 0.8278538347
+ 0.4767884711 -0.8054384283 -0.3520535357
+ 0.2195573953 0.0373540025 -0.9748842130
+ 0.1063921812 0.5867642889 -0.8027380476
+-0.5560885209 -0.8054384283 0.2050231574
+-0.6347778468 0.7449983827 0.2050231574
+-0.3056304780 -0.5120562839 -0.8027380476
+-0.9681111801 -0.1439661345 0.2050231574
+ 0.1105781457 0.9724906059 0.2050231574
+ 0.1408680694 -0.1725020531 -0.9748842130
+ 0.5200137365 0.7449983827 -0.4178075198
+-0.5028924303 -0.5120562839 -0.6963458664
+ 0.7031188992 -0.1439661345 -0.6963458664
+-0.8920089226 -0.1725020531 -0.4178075198
+ 0.2952822046 0.9032324765 0.3114153386
+ 0.6244295734 -0.3538221901 -0.6963458664
+-0.3713844621 -0.8746965578 0.3114153386
+-0.5586755893 0.7164624640 -0.4178075198
+-0.0422370933 0.7164624640 -0.6963458664
+-0.0980202522 -0.9032324765 -0.4178075198
+ 0.0980202522 0.9032324765 0.4178075198
+-0.9248859147 -0.3538221901 0.1392691733
+ 0.4642305776 -0.8746965578 -0.1392691733
+-0.2952822046 -0.9032324765 -0.3114153386
+ 0.8920089226 0.1725020531 0.4178075198
+ 0.9248859147 0.3538221901 -0.1392691733
+ 0.5586755893 -0.7164624640 0.4178075198
+ 0.3713844621 0.8746965578 -0.3114153386
+-0.4642305776 0.8746965578 0.1392691733
+-0.5200137365 -0.7449983827 0.4178075198
+-0.1408680694 0.1725020531 0.9748842130
+-0.6244295734 0.3538221901 0.6963458664
+ 0.0422370933 -0.7164624640 0.6963458664
+ 0.6347778468 -0.7449983827 -0.2050231574
+ 0.5560885209 0.8054384283 -0.2050231574
+ 0.5028924303 0.5120562839 0.6963458664
+-0.1105781457 -0.9724906059 -0.2050231574
+ 0.9681111801 0.1439661345 -0.2050231574
+-0.7031188992 0.1439661345 0.6963458664
+-0.2195573953 -0.0373540025 0.9748842130
+-0.4767884711 0.8054384283 0.3520535357
+ 0.3056304780 0.5120562839 0.8027380476
+ 0.9352341880 -0.0373540025 0.3520535357
+-0.1131652141 0.5494102864 -0.8278538347
+-0.4464985474 -0.3395542307 -0.8278538347
+ 0.7292228585 -0.5867642889 0.3520535357
+-0.1063921812 -0.5867642889 0.8027380476
+-0.8888111303 -0.2933821444 0.3520535357
+-0.6296037101 0.5494102864 -0.5493154881
+ 0.7824189491 -0.2933821444 -0.5493154881
+-0.8356150397 -0.0000000000 -0.5493154881
+ 0.0000000000 -0.0000000000 -1.0000000000
+ 0.1693842601 0.9341723590 0.3140556896
+-0.4865864368 -0.8152316624 0.3140556896
+ 0.1693842601 -0.0635136937 0.3140556896
+ 0.5297191236 -0.8152316624 -0.2340832902
+-0.3387685201 0.1270273873 0.0213524160
+ 0.9351313099 0.2659594829 -0.2340832902
+ 0.2039331950 0.1270273873 -0.2713508575
+-0.7092856298 0.2659594829 0.6528242098
+-0.0164752203 0.6227815726 -0.7822222701
+-0.4218874066 -0.4584095726 -0.7822222701
+ 0.0701362950 -0.2297947024 -0.2713508575
+-0.6445865996 0.6227815726 -0.4434537500
+-0.2652718107 -0.2297947024 -0.0904502858
+-0.1211604502 0.0454313035 0.9915927299
+-0.0487838789 0.3475555668 -0.0904502858
+-0.8951451102 -0.0454313035 -0.4434537500
+ 0.8951451102 0.0454313035 0.4434537500
+ 0.1211604502 -0.0454313035 -0.9915927299
+ 0.2652718107 0.2297947024 0.0904502858
+ 0.6445865996 -0.6227815726 0.4434537500
+ 0.0487838789 -0.3475555668 0.0904502858
+-0.0701362950 0.2297947024 0.2713508575
+ 0.0164752203 -0.6227815726 0.7822222701
+ 0.7092856298 -0.2659594829 -0.6528242098
+ 0.4218874066 0.4584095726 0.7822222701
+-0.2039331950 -0.1270273873 0.2713508575
+-0.9351313099 -0.2659594829 0.2340832902
+ 0.3387685201 -0.1270273873 -0.0213524160
+-0.5297191236 0.8152316624 0.2340832902
+ 0.4865864368 0.8152316624 -0.3140556896
+-0.1693842601 0.0635136937 -0.3140556896
+-0.1693842601 -0.9341723590 -0.3140556896
+6 0 2 7 11 4 1
+6 0 3 9 14 6 2
+5 0 1 5 8 3 2
+6 1 4 10 19 12 5
+5 2 6 13 15 7 2
+6 3 8 16 26 17 9
+5 4 11 20 18 10 2
+6 5 12 21 25 16 8
+6 6 14 23 33 22 13
+6 7 15 24 30 20 11
+5 9 17 27 23 14 2
+6 10 18 28 39 29 19
+5 12 19 29 31 21 2
+6 13 22 32 34 24 15
+5 16 25 35 36 26 2
+6 17 26 36 46 37 27
+6 18 20 30 40 38 28
+6 21 31 41 45 35 25
+5 22 33 43 42 32 2
+6 23 27 37 47 43 33
+5 24 34 44 40 30 2
+5 28 38 48 49 39 2
+6 29 39 49 50 41 31
+6 32 42 51 52 44 34
+6 35 45 53 54 46 36
+5 37 46 54 55 47 2
+6 38 40 44 52 56 48
+5 41 50 57 53 45 2
+6 42 43 47 55 58 51
+6 48 56 59 57 50 49
+5 51 58 59 56 52 2
+6 53 57 59 58 55 54
+3 2 0 1
+3 2 3 0
+3 0 4 1
+3 1 5 2
+3 3 6 0
+3 2 7 3
+3 4 8 1
+3 0 9 4
+3 5 7 2
+3 1 10 5
+3 3 11 6
+3 6 9 0
+3 7 12 3
+3 4 13 8
+3 8 10 1
+3 9 13 4
+3 5 14 7
+3 10 15 5
+3 11 16 6
+3 12 11 3
+3 16 9 6
+3 7 17 12
+3 13 18 8
+3 8 19 10
+3 9 20 13
+3 14 17 7
+3 15 14 5
+3 19 15 10
+3 11 21 16
+3 12 22 11
+3 16 20 9
+3 17 22 12
+3 13 23 18
+3 18 19 8
+3 20 23 13
+3 14 24 17
+3 15 24 14
+3 19 25 15
+3 21 26 16
+3 22 21 11
+3 26 20 16
+3 17 27 22
+3 23 28 18
+3 28 19 18
+3 26 23 20
+3 24 27 17
+3 25 24 15
+3 28 25 19
+3 21 29 26
+3 22 29 21
+3 27 29 22
+3 23 30 28
+3 26 30 23
+3 24 31 27
+3 25 31 24
+3 28 31 25
+3 29 30 26
+3 31 29 27
+3 30 31 28
+3 29 30 31
+rhombicosahedron
+rhombicosacron
+2 5/2 3|
+(6.4.6/5.4/3)
+icosahedral group
+A5
+10{6}+15{4}+15{4/3}+10{6/5}
+60 60 120 50 60 0 0 1 -10 4 4 120 5 0 1
+ 0.0000000000 0.0000000000 1.0000000000
+ 0.6998542122 0.0000000000 0.7142857143
+-0.5248906592 0.4629100499 0.7142857143
+-0.3689536881 -0.5947008445 0.7142857143
+-0.1166423687 0.6900655593 0.7142857143
+ 0.8748177653 0.4629100499 0.1428571429
+ 0.7634342145 -0.5947008445 0.2519902889
+ 0.5832118435 0.6900655593 0.4285714286
+-0.8938443472 -0.1317907946 0.4285714286
+ 0.2077578990 0.4039714148 0.8908668539
+-0.3499271061 0.9258200998 0.1428571429
+-0.8545497448 -0.4993361296 0.1428571429
+ 0.1028746047 -0.9622461795 0.2519902889
+-0.4528017108 0.0364260797 0.8908668539
+-0.6022384255 0.7854302742 0.1428571429
+ 0.9383977675 -0.1317907946 -0.3194382825
+ 0.4750784209 0.4039714148 0.7817337079
+ 0.3499271061 0.9258200998 -0.1428571429
+ 0.7103718480 -0.4993361296 -0.4960194221
+ 0.9469067137 0.0364260797 0.3194382825
+ 0.5301494771 0.7854302742 -0.3194382825
+-0.5301494771 -0.7854302742 0.3194382825
+-0.9469067137 -0.0364260797 -0.3194382825
+ 0.3827214521 0.8668814647 0.3194382825
+ 0.5714527692 -0.2496680648 0.7817337079
+-0.6107473716 0.6172133998 -0.4960194221
+-0.3827214521 -0.8668814647 -0.3194382825
+-0.5937294793 -0.1907294297 0.7817337079
+-0.9711921135 0.1907294297 -0.1428571429
+ 0.0498122382 -0.8668814647 -0.4960194221
+-0.9383977675 0.1317907946 0.3194382825
+-0.0891068406 -0.6172133998 0.7817337079
+-0.2024990811 0.8443689093 -0.4960194221
+ 0.6022384255 -0.7854302742 -0.1428571429
+ 0.4528017108 -0.0364260797 -0.8908668539
+-0.0498122382 0.8668814647 0.4960194221
+ 0.1389190789 -0.2496680648 0.9583148475
+ 0.0891068406 0.6172133998 -0.7817337079
+ 0.9711921135 -0.1907294297 0.1428571429
+ 0.5937294793 0.1907294297 -0.7817337079
+ 0.8938443472 0.1317907946 -0.4285714286
+ 0.6107473716 -0.6172133998 0.4960194221
+-0.5832118435 -0.6900655593 -0.4285714286
+ 0.2024990811 -0.8443689093 0.4960194221
+-0.4750784209 -0.4039714148 -0.7817337079
+-0.1028746047 0.9622461795 -0.2519902889
+ 0.8545497448 0.4993361296 -0.1428571429
+-0.1389190789 0.2496680648 -0.9583148475
+ 0.3499271061 -0.9258200998 -0.1428571429
+-0.2077578990 -0.4039714148 -0.8908668539
+-0.7103718480 0.4993361296 0.4960194221
+-0.5714527692 0.2496680648 -0.7817337079
+-0.3499271061 -0.9258200998 0.1428571429
+-0.7634342145 0.5947008445 -0.2519902889
+-0.8748177653 -0.4629100499 -0.1428571429
+ 0.1166423687 -0.6900655593 -0.7142857143
+ 0.3689536881 0.5947008445 -0.7142857143
+ 0.5248906592 -0.4629100499 -0.7142857143
+-0.6998542122 0.0000000000 -0.7142857143
+-0.0000000000 0.0000000000 -1.0000000000
+ 0.2672612419 0.7071067812 0.6546536707
+-0.4096109381 -0.0603941292 0.6546536707
+-0.7417602291 0.1456720081 0.6546536707
+ 0.2672612419 0.3162277660 0.6546536707
+ 0.9879908641 0.1456720081 -0.0515142560
+ 0.7507413705 -0.0603941292 0.1809418244
+-0.0651501153 0.6093870274 0.4737118463
+-0.2462306350 -0.2913440163 0.9243858169
+-0.6446401714 -0.7627485371 -0.0515142560
+-0.3444608228 -0.6697811566 0.1809418244
+-0.4834801286 0.3766218952 0.4737118463
+ 0.3773789295 0.0556417559 0.9243858169
+ 0.8228143327 -0.2913440163 0.4879500365
+ 0.3780650276 0.6093870274 0.2927700219
+ 0.3726763428 -0.6697811566 -0.1118281975
+ 0.4244047962 -0.7627485371 -0.4879500365
+ 0.6768721800 0.3766218952 -0.0000000000
+-0.6768721800 -0.3766218952 -0.0000000000
+-0.4244047962 0.7627485371 0.4879500365
+ 0.0543727456 -0.0977197538 0.7664818682
+-0.1195228609 0.7071067812 -0.2927700219
+ 0.1862071383 0.8527787893 -0.4879500365
+-0.1862071383 -0.8527787893 0.4879500365
+-0.7171371656 0.0000000000 0.2927700219
+-0.5378528742 0.4743416490 -0.2927700219
+-0.8228143327 0.2913440163 -0.4879500365
+ 0.4834801286 -0.3766218952 -0.4737118463
+ 0.4975878886 -0.0977197538 0.5855400438
+ 0.6446401714 0.7627485371 0.0515142560
+-0.4744989872 0.8527787893 -0.2182178902
+ 0.7171371656 0.0000000000 -0.2927700219
+ 0.4744989872 -0.8527787893 0.2182178902
+ 0.2462306350 0.2913440163 -0.9243858169
+ 0.1792842914 0.4743416490 -0.5855400438
+-0.1792842914 -0.4743416490 0.5855400438
+-0.9879908641 -0.1456720081 0.0515142560
+-0.3773789295 -0.0556417559 -0.9243858169
+-0.4975878886 0.0977197538 -0.5855400438
+ 0.3444608228 0.6697811566 -0.1809418244
+ 0.5378528742 -0.4743416490 0.2927700219
+ 0.0651501153 -0.6093870274 -0.4737118463
+-0.3780650276 -0.6093870274 -0.2927700219
+-0.7507413705 0.0603941292 -0.1809418244
+ 0.1195228609 -0.7071067812 0.2927700219
+ 0.7417602291 -0.1456720081 -0.6546536707
+-0.0543727456 0.0977197538 -0.7664818682
+-0.3726763428 0.6697811566 0.1118281975
+ 0.4096109381 0.0603941292 -0.6546536707
+-0.2672612419 -0.3162277660 -0.6546536707
+-0.2672612419 -0.7071067812 -0.6546536707
+6 0 2 10 17 5 1
+4 0 3 8 2
+6 0 4 14 28 11 3 5
+4 0 1 7 4 3
+6 1 6 18 39 20 7 5
+4 1 5 15 6
+4 2 9 23 10 3
+6 2 8 21 43 24 9 5
+6 3 12 29 44 22 8
+4 3 11 26 12 3
+4 4 13 30 14
+6 4 7 19 41 31 13
+6 5 16 36 43 33 15 5
+4 5 17 35 16 3
+4 6 12 29 18 3
+6 6 15 34 49 26 12
+4 7 20 40 19
+4 8 22 42 21 3
+6 9 13 30 53 45 23
+4 9 24 31 13
+4 10 25 37 17
+6 10 23 46 39 47 25 5
+6 11 27 36 41 48 26
+4 11 28 50 27
+4 14 32 51 28 3
+6 14 30 54 44 47 32
+4 15 33 55 34 3
+4 16 19 41 36
+6 16 35 45 56 40 19
+6 17 37 51 28 50 35 5
+4 18 38 46 39
+6 18 29 52 31 24 38
+6 20 32 51 49 57 40
+4 20 39 47 32 3
+4 21 27 36 43
+6 21 42 58 53 50 27
+6 22 25 37 34 55 42 5
+4 22 44 47 25
+4 23 45 56 46
+4 24 43 33 38 3
+4 26 48 57 49
+4 29 52 54 44 3
+4 30 53 58 54 3
+4 31 41 48 52
+6 33 38 46 56 59 55
+4 34 37 51 49
+4 35 50 53 45
+4 40 57 59 56 3
+4 42 55 59 58
+6 48 52 54 58 59 57 5
+4 3 0 1 2
+4 3 4 5 0
+4 0 6 7 1
+4 1 8 9 2
+4 2 10 11 3
+4 5 12 13 0
+4 4 14 15 5
+4 11 16 4 3
+4 7 17 8 1
+4 6 18 19 7
+4 0 20 21 6
+4 9 22 23 2
+4 8 14 15 9
+4 10 18 19 11
+4 2 24 25 10
+4 15 26 12 5
+4 12 27 28 13
+4 13 29 20 0
+4 4 30 31 14
+4 11 27 28 16
+4 16 32 33 4
+4 7 34 35 17
+4 17 36 37 8
+4 21 38 18 6
+4 19 31 39 7
+4 20 36 37 21
+4 15 40 22 9
+4 22 34 35 23
+4 23 29 24 2
+4 8 41 31 14
+4 25 42 18 10
+4 31 43 11 19
+4 24 32 33 25
+4 26 44 39 12
+4 15 45 36 26
+4 28 46 29 13
+4 12 34 22 27
+4 29 45 36 20
+4 30 44 39 31
+4 33 21 30 4
+4 28 47 32 16
+4 43 22 27 11
+4 35 48 36 17
+4 7 34 12 39
+4 37 25 41 8
+4 38 28 46 18
+4 44 38 21 30
+4 37 21 33 25
+4 40 49 43 22
+4 45 32 40 15
+4 35 46 29 23
+4 29 24 32 45
+4 41 49 43 31
+4 42 35 46 18
+4 49 42 25 41
+4 48 44 26 36
+4 44 47 28 38
+4 47 49 40 32
+4 49 48 35 42
+4 48 44 47 49
+great snub icosidodecahedron
+great pentagonal hexecontahedron
+|2 5/2 3
+(3.3.5/2.3.3)
+icosahedral group
+A5
+80{3}+12{5/2}
+61 60 150 92 60 7 0 0 2 2 5 120 5 0 -1
+ 0.0000000000 0.0000000000 1.0000000000
+ 0.9684429470 0.0000000000 0.2492353475
+ 0.1932143650 0.9489731033 0.2492353475
+-0.8913464263 0.3786598604 0.2492353475
+-0.8913464263 -0.3786598604 0.2492353475
+ 0.1932143650 -0.9489731033 0.2492353475
+ 0.4635252507 -0.3786598604 -0.8010999015
+ 0.3781705098 0.7978800013 -0.4694406981
+ 0.8572881225 0.2113823691 -0.4694406981
+-0.2785691059 0.5297529623 -0.8010999015
+-0.6600348160 -0.5864976322 -0.4694406981
+-0.3404640391 -0.6126845243 0.7132334203
+-0.3404640391 0.6126845243 0.7132334203
+-0.6600348160 0.5864976322 -0.4694406981
+-0.2785691059 -0.5297529623 -0.8010999015
+-0.4456304207 -0.8822259307 -0.1519570181
+-0.6325889612 0.1672774913 -0.7562072778
+-0.5650434654 0.7637776262 0.3120410548
+ 0.5580227938 0.4558561435 0.6934015705
+ 0.6356904263 -0.7060651967 0.3120410548
+ 0.0377064707 -0.6532448048 -0.7562072778
+ 0.2734652451 0.0366360026 -0.9611839382
+ 0.4921267272 -0.8571582987 -0.1519570181
+ 0.7205513597 0.0000000000 0.6934015705
+ 0.4921267272 0.8571582987 -0.1519570181
+ 0.5168240834 0.4013021552 -0.7562072778
+ 0.7551034710 -0.6377521562 -0.1519570181
+ 0.0981457100 -0.4820430356 0.8706330636
+-0.8937570446 0.0933806725 0.4387235978
+-0.9355024568 -0.2752766852 -0.2214901802
+-0.3809719027 -0.3112209470 0.8706330636
+-0.5885888579 -0.7537751235 0.2922092050
+-0.8555038721 0.1446351965 -0.4971858654
+ 0.0022546911 0.9751599953 -0.2214901802
+ 0.9655218191 0.2590922959 0.0252744751
+ 0.8243476323 -0.2706606665 -0.4971858654
+-0.1952509108 0.2340246639 -0.9524229830
+-0.2352120726 0.9716153981 0.0252744751
+ 0.7860944598 0.4354045303 0.4387235978
+ 0.1281650723 0.7271416236 0.6744173585
+-0.4036327131 0.8094483719 -0.4264668406
+ 0.0235453925 -0.1967638477 -0.9801681502
+ 0.0397430165 -0.9978022901 -0.0530196423
+ 0.3756743067 -0.2817345907 0.8828898208
+-0.6139292842 0.4101853978 0.6744173585
+ 0.1126975629 0.4558561435 0.8828898208
+ 0.4279771028 -0.6898808074 0.5838664839
+-0.2411041472 -0.8717768201 -0.4264668406
+-0.9984623093 0.0161843893 -0.0530196423
+-0.2970106376 0.1601278451 0.9413520884
+ 0.7675414736 -0.3119126878 0.5599915727
+ 0.7838397687 0.5197504596 -0.3397862220
+ 0.9607558386 -0.2013798664 -0.1907730799
+ 0.4935202029 0.8050296475 0.3291885112
+-0.6821867327 0.7311328287 -0.0081270187
+-0.7497814649 -0.3524729683 0.5599915727
+-0.2817083791 -0.9012631765 0.3291885112
+ 0.4908680726 -0.6442100617 -0.5865508773
+ 0.2046118584 0.5226033161 -0.8276592061
+-0.6840824376 -0.3047630416 -0.6626844702
+ 0.5478898766 0.4475784305 0.7067462286
+-0.3292705043 0.6261714648 0.7067462286
+-0.5952793113 -0.0000000000 0.7067462286
+-0.3292705043 -0.6261714648 0.7067462286
+ 0.5478898766 -0.4475784305 0.7067462286
+ 0.7665092489 -0.6261714648 -0.1427335557
+ 0.8537428920 0.1977230883 -0.4816935277
+ 0.7140436788 0.5833116520 0.0611296277
+ 0.3640785289 0.7971312126 -0.4816935277
+-0.4606562335 0.8760268070 -0.1427335557
+-0.8630869536 0.1518296938 -0.4816935277
+-0.8922793901 -0.3869952480 0.2325342297
+-0.8922793901 0.3869952480 0.2325342297
+-0.8630869536 -0.1518296938 -0.4816935277
+-0.4606562335 -0.8760268070 -0.1427335557
+ 0.1661538022 -0.8160650441 -0.4003479086
+-0.2899174208 -0.5157948995 -0.8061659326
+ 0.0986241788 0.2766186827 -0.9559055266
+-0.3864951254 0.8154436245 -0.4308981471
+ 0.1750509698 0.9515503064 0.2528026353
+ 0.9673445525 -0.0183124119 0.2528026353
+ 0.7219399541 -0.5414143418 -0.4308981471
+ 0.2907340063 0.0414531285 -0.9559055266
+-0.3583185855 -0.1277530350 -0.8421013261
+ 0.0497855062 -0.6636139307 -0.7464167431
+-0.2397711783 -0.9698627183 0.0433138518
+ 0.4113754049 -0.6932440356 0.5917626073
+ 0.0186881231 -0.0000000000 0.9998253618
+ 0.4113754049 0.6932440356 0.5917626073
+-0.2397711783 0.9698627183 0.0433138518
+-0.0197040197 0.7371093263 -0.5568925235
+-0.1989303569 0.2160355002 -0.9559055266
+ 0.4685125572 -0.3613758057 -0.8061659326
+ 0.1922513550 -0.9442432760 0.2672902024
+-0.5854254823 -0.5994081243 0.5458817685
+-0.9300728450 -0.2931593368 -0.2214093636
+-0.8289101298 0.3766028993 -0.1578795205
+-0.8874084967 0.0836132249 0.4533376099
+-0.1829947623 0.4284483765 0.8848417405
+ 0.3833253882 -0.2647956591 0.8848417405
+ 0.0197040197 -0.7371093263 0.5568925235
+ 0.0399992886 -0.9966260588 -0.0716697696
+-0.6633150639 -0.5953974618 -0.4533376099
+-0.2734522013 0.5454250043 -0.7922975819
+ 0.5854254823 0.5994081243 -0.5458817685
+ 0.8164711846 -0.2647956591 -0.5130867994
+ 0.8289101298 -0.3766028993 0.1578795205
+ 0.9607530194 0.2766186827 0.0208743890
+ 0.5288194467 0.3869952480 -0.7553705520
+ 0.5035784309 0.8528860904 -0.1378190139
+ 0.9706558172 0.0938359113 -0.2214093636
+ 0.7731882508 -0.3227894416 0.5458817685
+ 0.3583185855 0.1277530350 0.8421013261
+-0.3147977002 0.1596420548 0.9356371210
+-0.5514589905 0.7687675350 0.3238664214
+-0.6204913561 0.1591367242 -0.7678971155
+-0.4113754049 -0.6932440356 -0.5917626073
+-0.6021639693 -0.7472271556 0.2811585531
+-0.3899767705 -0.2949310946 0.8723151769
+-0.9706558172 -0.0938359113 0.2214093636
+-0.6919874045 0.7216077133 -0.0208743890
+-0.1661538022 0.8160650441 0.4003479086
+ 0.5096002070 0.7971312126 0.3238664214
+ 0.7103900588 0.0118230236 0.7037088748
+ 0.4769371461 -0.8642037834 -0.1602584767
+ 0.1829947623 -0.4284483765 -0.8848417405
+-0.6767244541 -0.2931593368 -0.6753529569
+-0.6739454866 0.5762674078 -0.4622914188
+-0.7219399541 0.5414143418 0.4308981471
+ 0.1197373444 0.7391374301 0.6628263934
+ 0.7921496414 0.4409783680 0.4219443382
+ 0.2397711783 0.9698627183 -0.0433138518
+ 0.1904278281 0.5341073114 -0.8236908535
+ 0.5952793113 -0.0000000000 -0.7067462286
+ 0.4829853613 -0.6583909696 -0.5772750401
+ 0.6490652071 -0.6984669967 0.3014269586
+ 0.8630869536 0.1518296938 0.4816935277
+ 0.1203945702 0.4402714001 0.8897562822
+-0.6222274141 0.3935953105 0.6766947441
+-0.0986241788 -0.2766186827 0.9559055266
+-0.2654929905 -0.9027901475 0.3383539886
+-0.7140436788 -0.5833116520 -0.0611296277
+-0.7438697051 -0.3419194956 0.5742376863
+ 0.0890571699 -0.4966648455 0.8633613680
+ 0.4606562335 -0.8760268070 0.1427335557
+ 0.9632167023 -0.2058128138 -0.1727850402
+ 0.7824062032 0.5311916554 -0.3250783883
+ 0.0075205347 0.9710066165 -0.2389342846
+-0.5478898766 0.4475784305 -0.7067462286
+-0.9980247269 0.0348530660 -0.0522676607
+-0.2239949432 -0.8726547120 -0.4339355010
+ 0.0053755709 -0.2010951833 -0.9795569562
+3 0 2 1
+3 0 3 2
+5 0 4 12 11 3 2
+3 0 5 4
+3 0 1 5
+3 1 6 5
+3 1 7 6
+5 1 2 8 18 7 2
+3 2 9 8
+3 2 3 9
+3 3 10 9
+3 3 11 10
+3 4 13 12
+3 4 14 13
+3 4 5 14
+5 5 6 15 26 14 2
+3 6 16 15
+3 6 7 16
+3 7 17 16
+3 7 18 17
+3 8 19 18
+3 8 20 19
+3 8 9 20
+5 9 10 21 32 20 2
+3 10 22 21
+3 10 11 22
+3 11 23 22
+3 11 12 23
+3 12 24 23
+3 12 13 24
+5 13 25 37 36 24 2
+3 13 14 25
+3 14 26 25
+3 15 27 26
+3 15 28 27
+3 15 16 28
+5 16 17 29 40 28 2
+3 17 30 29
+3 17 18 30
+3 18 19 30
+5 19 31 43 42 30 2
+3 19 20 31
+3 20 32 31
+3 21 33 32
+3 21 34 33
+3 21 22 34
+5 22 23 35 46 34 2
+3 23 24 35
+3 24 36 35
+3 25 38 37
+3 25 26 38
+3 26 27 38
+5 27 39 50 49 38 2
+3 27 28 39
+3 28 40 39
+3 29 41 40
+3 29 42 41
+3 29 30 42
+3 31 44 43
+3 31 32 44
+3 32 33 44
+5 33 45 54 53 44 2
+3 33 34 45
+3 34 46 45
+3 35 47 46
+3 35 36 47
+3 36 48 47
+3 36 37 48
+3 37 49 48
+3 37 38 49
+3 39 51 50
+3 39 40 51
+3 40 41 51
+5 41 52 58 57 51 2
+3 41 42 52
+3 42 43 52
+3 43 53 52
+3 43 44 53
+3 45 55 54
+3 45 46 55
+3 46 47 55
+5 47 48 56 59 55 2
+3 48 49 56
+3 49 50 56
+3 50 57 56
+3 50 51 57
+3 52 53 58
+3 53 54 58
+3 54 59 58
+3 54 55 59
+3 56 57 59
+3 57 58 59
+5 4 0 1 2 3
+5 4 5 6 7 0
+5 7 8 9 1 0
+5 9 10 11 2 1
+5 2 12 13 14 3
+5 14 15 5 4 3
+5 15 16 17 6 5
+5 17 18 19 7 6
+5 7 20 21 22 8
+5 22 23 10 9 8
+5 23 24 25 11 10
+5 25 26 27 2 11
+5 27 28 29 12 2
+5 29 30 31 13 12
+5 31 32 15 14 13
+5 15 33 34 35 16
+5 35 36 18 17 16
+5 36 37 38 19 18
+5 38 39 20 7 19
+5 39 40 41 21 20
+5 41 42 23 22 21
+5 23 43 44 45 24
+5 45 46 26 25 24
+5 46 47 28 27 26
+5 47 48 30 29 28
+5 30 49 50 32 31
+5 50 51 33 15 32
+5 51 52 53 34 33
+5 53 54 36 35 34
+5 36 55 56 57 37
+5 57 40 39 38 37
+5 40 58 59 42 41
+5 59 60 43 23 42
+5 60 61 62 44 43
+5 62 63 46 45 44
+5 46 64 65 48 47
+5 65 66 67 30 48
+5 67 68 69 49 30
+5 69 52 51 50 49
+5 52 70 71 54 53
+5 71 72 55 36 54
+5 72 73 74 56 55
+5 74 75 40 57 56
+5 75 76 77 58 40
+5 77 61 60 59 58
+5 61 78 79 63 62
+5 79 80 64 46 63
+5 80 81 66 65 64
+5 81 82 68 67 66
+5 82 83 52 69 68
+5 83 84 85 70 52
+5 85 73 72 71 70
+5 73 86 76 75 74
+5 86 87 61 77 76
+5 87 88 89 78 61
+5 89 81 80 79 78
+5 81 90 84 83 82
+5 90 91 73 85 84
+5 91 88 87 86 73
+5 88 89 81 90 91
+small stellated truncated dodecahedron
+great pentakisdodekahedron
+2 5|5/3
+(10/3.10/3.5)
+icosahedral group
+A5
+12{5}+12{10/3}
+62 60 90 24 60 9 0 0 -6 2 3 120 5 0 -1
+ 0.0000000000 0.0000000000 1.0000000000
+ 0.9498602905 0.0000000000 0.3126746369
+-0.0501397095 0.9485360199 0.3126746369
+-0.9445669005 -0.1001396121 0.3126746369
+ 0.3126746369 0.9485360199 0.0501397095
+ 0.5923393341 -0.1001396121 -0.7994411620
+-0.9637185654 0.2621689080 0.0501397095
+ 0.9307086256 0.3623085200 0.0501397095
+-0.5784810592 -0.1620292959 -0.7994411620
+-0.4109321609 0.9102860917 0.0501397095
+ 0.3489560715 0.2621689080 -0.8997205810
+-0.2433832625 0.3623085200 0.8997205810
+ 0.1761137832 0.9102860917 -0.3746507262
+-0.5474930145 -0.7482567958 -0.3746507262
+-0.3489560715 -0.2621689080 0.8997205810
+ 0.3746507262 -0.2239189798 0.8997205810
+ 0.6233273787 -0.6863671119 -0.3746507262
+-0.2710998123 0.8866463360 -0.3746507262
+ 0.2038303330 0.3859482757 0.8997205810
+-0.3746507262 0.2239189798 -0.8997205810
+-0.1846786681 -0.7482567958 -0.6371856536
+ 0.9637185654 -0.2621689080 -0.0501397095
+ 0.7374650726 -0.2239189798 0.6371856536
+-0.5507645094 -0.6863671119 0.4749301452
+ 0.7908762771 0.3859482757 0.4749301452
+-0.7374650726 0.2239189798 -0.6371856536
+-0.1899720581 -0.6481171837 0.7374650726
+ 0.1846786681 0.7482567958 0.6371856536
+-0.3126746369 -0.9485360199 -0.0501397095
+ 0.4109321609 -0.9102860917 -0.0501397095
+-0.2625349274 0.7246170401 0.6371856536
+ 0.2572415374 -0.6244774280 0.7374650726
+ 0.7097485229 0.3004188362 -0.6371856536
+-0.8271577117 0.3004188362 0.4749301452
+ 0.6200558838 -0.6244774280 0.4749301452
+-0.7097485229 -0.3004188362 0.6371856536
+-0.9307086256 -0.3623085200 -0.0501397095
+ 0.2625349274 -0.7246170401 -0.6371856536
+ 0.7598882324 -0.6481171837 0.0501397095
+ 0.5474930145 0.7482567958 0.3746507262
+ 0.0501397095 -0.9485360199 -0.3126746369
+-0.1761137832 -0.9102860917 0.3746507262
+ 0.6873253631 0.7246170401 -0.0501397095
+ 0.8271577117 -0.3004188362 -0.4749301452
+ 0.2433832625 -0.3623085200 -0.8997205810
+-0.6873253631 -0.7246170401 0.0501397095
+ 0.5507645094 0.6863671119 -0.4749301452
+-0.7598882324 0.6481171837 -0.0501397095
+-0.9498602905 0.0000000000 -0.3126746369
+-0.2038303330 -0.3859482757 -0.8997205810
+ 0.9445669005 0.1001396121 -0.3126746369
+-0.6200558838 0.6244774280 -0.4749301452
+-0.7908762771 -0.3859482757 -0.4749301452
+ 0.2710998123 -0.8866463360 0.3746507262
+-0.6233273787 0.6863671119 0.3746507262
+ 0.1899720581 0.6481171837 -0.7374650726
+ 0.0000000000 0.0000000000 -1.0000000000
+-0.5923393341 0.1001396121 0.7994411620
+-0.2572415374 0.6244774280 -0.7374650726
+ 0.5784810592 0.1620292959 0.7994411620
+ 0.0526465096 0.0555029103 0.0727556869
+-0.0582045495 0.0496433121 0.0727556869
+ 0.0526465096 -0.9959593140 0.0727556869
+ 0.0873068243 0.0496433121 -0.0325373323
+-0.0201091773 0.3804226065 -0.9245941063
+-0.0920539571 0.0401622832 -0.0325373323
+-0.8719475967 0.3804226065 -0.3081980354
+-0.0021229823 0.0401622832 -0.0976119970
+-0.0873068243 -0.0496433121 0.0325373323
+ 0.0920539571 -0.0401622832 0.0325373323
+ 0.8269821093 0.4702282018 -0.3081980354
+ 0.0582045495 -0.0496433121 -0.0727556869
+ 0.0021229823 -0.0401622832 0.0976119970
+-0.5513214062 0.4702282018 0.6891517578
+ 0.0055580399 -0.1051462224 0.0076810222
+ 0.8719475967 -0.3804226065 0.3081980354
+-0.8269821093 -0.4702282018 0.3081980354
+ 0.4986748966 0.5257311121 0.6891517578
+-0.0526465096 -0.0555029103 -0.0727556869
+ 0.0201091773 -0.3804226065 0.9245941063
+ 0.5513214062 -0.4702282018 -0.6891517578
+-0.0055580399 0.1051462224 -0.0076810222
+-0.4986748966 -0.5257311121 -0.6891517578
+-0.0526465096 0.9959593140 -0.0727556869
+10 0 2 7 15 30 42 22 11 4 1 3
+10 0 3 9 18 35 47 27 14 6 2 3
+5 0 1 5 8 3
+10 1 4 10 21 39 55 43 24 12 5 3
+5 2 6 13 16 7
+10 3 8 17 33 52 58 54 36 19 9 3
+5 4 11 23 20 10
+10 5 12 25 44 46 51 49 32 17 8 3
+10 6 14 28 48 57 41 52 33 26 13 3
+10 7 16 31 24 43 53 59 50 29 15 3
+5 9 19 37 34 18
+10 10 20 38 32 49 29 50 56 40 21 3
+10 11 22 41 57 59 53 35 18 34 23 3
+5 12 24 31 45 25
+10 13 26 38 20 23 34 37 45 31 16 3
+5 14 27 46 44 28
+5 15 29 49 51 30
+5 17 32 38 26 33
+10 19 36 40 56 48 28 44 25 45 37 3
+5 21 40 36 54 39
+5 22 42 58 52 41
+10 27 47 55 39 54 58 42 30 51 46 3
+5 35 53 43 55 47
+5 48 56 50 59 57
+3 2 0 1
+3 2 3 0
+3 0 4 1
+3 1 5 2
+3 3 6 0
+3 2 7 3
+3 4 8 1
+3 0 9 4
+3 5 7 2
+3 1 10 5
+3 3 11 6
+3 6 12 0
+3 7 13 3
+3 4 14 8
+3 8 15 1
+3 0 16 9
+3 9 14 4
+3 5 17 7
+3 1 12 10
+3 10 18 5
+3 11 14 6
+3 3 19 11
+3 12 20 0
+3 14 12 6
+3 13 9 3
+3 7 18 13
+3 14 17 8
+3 15 21 1
+3 8 18 15
+3 16 11 9
+3 0 21 16
+3 13 14 9
+3 17 11 7
+3 5 8 17
+3 14 10 12
+3 1 22 12
+3 18 19 5
+3 14 18 10
+3 11 14 17
+3 3 21 19
+3 18 11 19
+3 12 8 20
+3 20 21 0
+3 9 22 3
+3 7 15 18
+3 18 13 14
+3 7 21 15
+3 21 22 1
+3 8 23 18
+3 16 7 11
+3 11 23 9
+3 21 16 7
+3 5 20 8
+3 9 12 22
+3 21 5 19
+3 3 21 22
+3 18 11 23
+3 12 23 8
+3 20 21 5
+3 23 9 12
+truncated dodecadodecahedron
+medial disdyakistriacontahedron
+5/3 2 5|
+(10/3.4.10)
+icosahedral group
+A5
+12{10}+30{4}+12{10/3}
+63 120 180 54 120 3 0 0 -6 3 3 120 5 0 -1
+ 0.0000000000 0.0000000000 1.0000000000
+ 0.5749595746 0.0000000000 0.8181818182
+ 0.1379435501 0.5581667218 0.8181818182
+-0.5691632311 0.0814354272 0.8181818182
+ 0.3575585655 0.5581667218 0.7487334525
+ 0.9361004773 0.0814354272 0.3421756384
+-0.4312196809 0.6396021491 0.6363636364
+ 0.6276493222 0.2132007164 0.7487334525
+-0.9151291095 0.2132007164 0.3421756384
+ 0.7186994682 0.6396021491 0.2727272727
+-0.0830397963 0.2132007164 0.9734730848
+ 0.9454791582 0.2132007164 -0.2462003575
+-0.8624393619 0.4264014327 0.2727272727
+ 0.1870509604 -0.1317652891 0.9734730848
+ 0.8508466748 -0.2635305783 0.4545454545
+-0.5633668875 0.6899320110 0.4545454545
+-0.9057504287 0.3449660055 -0.2462003575
+ 0.8624393619 0.4264014327 -0.2727272727
+ 0.4066659758 -0.1317652891 0.9040247191
+-0.4348020182 -0.2635305783 0.8611032686
+ 0.7222818055 0.6899320110 0.0479876405
+ 0.5995132797 0.3449660055 -0.7222065373
+-0.7338744926 0.0000000000 0.6792850868
+-0.9910042312 0.0000000000 -0.1338305414
+ 0.4102483131 -0.6084965838 0.6792850868
+-0.0303500487 0.4264014327 0.9040247191
+ 0.7222818055 -0.6899320110 0.0479876405
+-0.5539882067 0.8216973001 -0.1338305414
+-0.4348020182 0.2635305783 0.8611032686
+-0.5446095259 0.4264014327 -0.7222065373
+ 0.9910042312 0.0000000000 0.1338305414
+ 0.7338744926 0.0000000000 -0.6792850868
+ 0.0549037538 -0.6084965838 0.7916549030
+ 0.5446095259 0.4264014327 0.7222065373
+-0.5633668875 -0.6899320110 0.4545454545
+ 0.3763159271 0.8216973001 -0.4280185393
+ 0.8508466748 0.2635305783 0.4545454545
+ 0.0303500487 0.4264014327 -0.9040247191
+-0.8624393619 -0.4264014327 0.2727272727
+-0.3821122706 0.4767312946 0.7916549030
+-0.7678068785 -0.4767312946 -0.4280185393
+ 0.5539882067 -0.8216973001 0.1338305414
+-0.1589149180 0.8528028654 0.4974669050
+ 0.3611409028 -0.7713674382 0.5239938202
+ 0.2910621246 -0.9031327273 -0.3156487232
+-0.4102483131 0.6084965838 -0.6792850868
+-0.8660216992 0.0503298619 0.4974669050
+-0.2174010091 -0.2946361436 0.9305516343
+-0.4160446566 0.8528028654 -0.3156487232
+ 0.8624393619 -0.4264014327 -0.2727272727
+ 0.7678068785 0.4767312946 0.4280185393
+ 0.3821122706 -0.4767312946 -0.7916549030
+-0.3763159271 -0.8216973001 0.4280185393
+ 0.4160446566 0.8528028654 0.3156487232
+ 0.0057963435 -0.7713674382 0.6363636364
+-0.4196269939 -0.9031327273 -0.0909090909
+-0.0549037538 0.6084965838 -0.7916549030
+ 0.9945865685 0.0503298619 -0.0909090909
+ 0.7129031247 -0.2946361436 0.6363636364
+ 0.1589149180 0.8528028654 -0.4974669050
+-0.7186994682 -0.6396021491 -0.2727272727
+-0.7280781490 0.6084965838 0.3156487232
+ 0.0584860911 0.8216973001 0.5669152707
+-0.7771855594 -0.6084965838 0.1603574566
+-0.2781011065 -0.8216973001 -0.4974669050
+ 0.9057504287 -0.3449660055 0.2462003575
+ 0.5633668875 -0.6899320110 -0.4545454545
+-0.1495362372 0.9845681546 -0.0909090909
+-0.0700787782 -0.9845681546 0.1603574566
+-0.8508466748 0.2635305783 -0.4545454545
+-0.1870509604 0.1317652891 -0.9734730848
+-0.6486206900 -0.5078368599 0.5669152707
+-0.8566430183 0.5078368599 -0.0909090909
+ 0.4312196809 -0.6396021491 -0.6363636364
+ 0.7771855594 0.6084965838 -0.1603574566
+ 0.2781011065 0.8216973001 0.4974669050
+ 0.7280781490 -0.6084965838 -0.3156487232
+-0.0584860911 -0.8216973001 -0.5669152707
+-0.5995132797 -0.3449660055 0.7222065373
+-0.7222818055 -0.6899320110 -0.0479876405
+ 0.0700787782 0.9845681546 -0.1603574566
+ 0.1495362372 -0.9845681546 0.0909090909
+ 0.4348020182 0.2635305783 -0.8611032686
+-0.4066659758 0.1317652891 -0.9040247191
+ 0.8566430183 -0.5078368599 0.0909090909
+ 0.6486206900 0.5078368599 -0.5669152707
+-0.9361004773 -0.0814354272 -0.3421756384
+-0.3575585655 -0.5581667218 -0.7487334525
+-0.2874797873 0.9534625892 0.0909090909
+ 0.4196269939 0.9031327273 0.0909090909
+-0.2874797873 -0.9534625892 0.0909090909
+-0.9945865685 -0.0503298619 0.0909090909
+ 0.9151291095 -0.2132007164 -0.3421756384
+ 0.5446095259 -0.4264014327 0.7222065373
+ 0.4348020182 -0.2635305783 -0.8611032686
+-0.0057963435 0.7713674382 -0.6363636364
+-0.4160446566 -0.8528028654 -0.3156487232
+-0.6276493222 -0.2132007164 -0.7487334525
+-0.7222818055 0.6899320110 -0.0479876405
+ 0.0303500487 -0.4264014327 -0.9040247191
+-0.1589149180 -0.8528028654 0.4974669050
+-0.7129031247 0.2946361436 -0.6363636364
+ 0.5691632311 -0.0814354272 -0.8181818182
+-0.1379435501 -0.5581667218 -0.8181818182
+ 0.2874797873 0.9534625892 -0.0909090909
+-0.2910621246 0.9031327273 0.3156487232
+ 0.2874797873 -0.9534625892 -0.0909090909
+ 0.8660216992 -0.0503298619 -0.4974669050
+-0.9454791582 -0.2132007164 0.2462003575
+-0.0303500487 -0.4264014327 0.9040247191
+-0.8508466748 -0.2635305783 -0.4545454545
+-0.3611409028 0.7713674382 -0.5239938202
+ 0.1589149180 -0.8528028654 -0.4974669050
+ 0.0830397963 -0.2132007164 -0.9734730848
+ 0.5633668875 0.6899320110 -0.4545454545
+-0.5446095259 -0.4264014327 -0.7222065373
+ 0.4160446566 -0.8528028654 0.3156487232
+ 0.2174010091 0.2946361436 -0.9305516343
+-0.5749595746 0.0000000000 -0.8181818182
+-0.0000000000 0.0000000000 -1.0000000000
+ 0.0692731120 0.0542373073 0.2190608145
+-0.0577275933 0.0856238581 0.2190608145
+ 0.0692731120 0.9732489895 0.2190608145
+ 0.1731827800 0.0856238581 0.1460405430
+-0.3199055857 -0.6015009550 0.7320225525
+-0.1650061983 0.0877578066 0.1442207056
+ 0.6826243091 -0.6015009550 0.4149947635
+ 0.2179261468 0.0877578066 0.0231268655
+ 0.1389438731 -0.0529184545 0.1911695527
+-0.1966714664 0.1385423126 0.0278912618
+-0.0037665860 -0.0529184545 0.2362985623
+ 0.1769493660 0.1385423126 -0.0902580193
+-0.2309103733 -0.0000000000 0.0730202715
+ 0.9231499720 0.3717480345 0.0979669745
+ 0.1611457400 -0.1419951139 0.0979669745
+-0.9231499720 -0.3717480345 -0.0979669745
+-0.1611457400 0.1419951139 -0.0979669745
+ 0.2309103733 -0.0000000000 -0.0730202715
+-0.6989774726 0.3717480345 0.6109287125
+-0.0755194646 -0.1419951139 0.1728070835
+ 0.6989774726 -0.3717480345 -0.6109287125
+ 0.0755194646 0.1419951139 -0.1728070835
+-0.6826243091 0.6015009550 -0.4149947635
+-0.2179261468 -0.0877578066 -0.0231268655
+ 0.0516331291 0.1712477161 0.1632782908
+ 0.0873107439 -0.2241661707 0.0278912618
+-0.1450383372 -0.0327054035 0.1911695527
+-0.0516331291 0.1712477161 -0.1632782908
+ 0.3199055857 0.6015009550 -0.7320225525
+ 0.1650061983 -0.0877578066 -0.1442207056
+-0.0553997152 -0.2241661707 0.0730202715
+ 0.2285824951 -0.0327054035 0.0730202715
+-0.0896386221 0.1914607671 0.1181492812
+-0.1412717512 -0.1914607671 -0.0451290097
+ 0.1966714664 -0.1385423126 -0.0278912618
+ 0.0163531634 0.2297529205 0.0517132434
+-0.0163531634 -0.2297529205 -0.0517132434
+-0.1389438731 0.0529184545 -0.1911695527
+ 0.2934456114 0.2297529205 0.9279565015
+-0.2934456114 -0.2297529205 -0.9279565015
+ 0.1412717512 0.1914607671 0.0451290097
+ 0.0896386221 -0.1914607671 -0.1181492812
+-0.1769493660 -0.1385423126 0.0902580193
+ 0.0037665860 0.0529184545 -0.2362985623
+-0.1731827800 -0.0856238581 -0.1460405430
+-0.0692731120 -0.9732489895 -0.2190608145
+ 0.0553997152 0.2241661707 -0.0730202715
+-0.0692731120 -0.0542373073 -0.2190608145
+-0.2285824951 0.0327054035 -0.0730202715
+ 0.0577275933 -0.0856238581 -0.2190608145
+-0.0873107439 0.2241661707 -0.0278912618
+ 0.1450383372 0.0327054035 -0.1911695527
+ 0.0516331291 -0.1712477161 0.1632782908
+-0.0516331291 -0.1712477161 -0.1632782908
+10 0 2 7 13 25 33 18 10 4 1 3
+4 0 3 6 2
+10 0 1 5 11 21 37 29 16 8 3
+4 1 4 9 5
+10 2 6 12 23 40 64 44 26 14 7
+10 3 8 15 28 46 61 39 22 12 6 3
+10 4 10 19 34 55 77 51 31 17 9
+10 5 9 17 30 50 74 57 36 20 11 3
+4 7 14 24 13
+4 8 16 27 15
+4 10 18 32 19
+4 11 20 35 21
+4 12 22 38 23
+10 13 24 41 66 94 117 95 67 42 25
+10 14 26 43 58 84 116 93 65 41 24 3
+10 15 27 45 70 99 112 81 54 47 28
+10 16 29 48 72 101 111 98 69 45 27 3
+4 17 31 49 30
+10 18 33 53 80 111 101 110 79 52 32
+10 19 32 52 78 109 100 71 47 54 34 3
+10 20 36 58 43 68 96 115 83 56 35
+10 21 35 56 82 114 95 117 85 59 37 3
+10 22 39 62 89 114 82 113 87 60 38
+10 23 38 60 86 108 79 110 91 63 40 3
+4 25 42 53 33
+4 26 44 68 43
+4 28 47 71 46
+4 29 37 59 48
+10 30 49 73 103 97 69 98 105 75 50
+10 31 51 76 107 94 66 92 102 73 49 3
+4 34 54 81 55
+4 36 57 84 58
+4 39 61 88 62
+4 40 63 90 64
+4 41 65 92 66
+10 42 67 89 62 88 104 75 105 80 53 3
+10 44 64 90 106 77 55 81 112 96 68 3
+4 45 69 97 70
+10 46 71 100 116 84 57 74 104 88 61
+10 48 59 85 107 76 106 90 63 91 72
+4 50 75 104 74
+4 51 77 106 76
+4 52 79 108 78
+4 56 83 113 82
+4 60 87 118 86
+10 65 93 109 78 108 86 118 119 102 92
+4 67 95 114 89
+10 70 97 103 119 118 87 113 83 115 99 3
+4 72 91 110 101
+4 73 102 119 103
+4 80 105 98 111
+4 85 117 94 107
+4 93 116 100 109
+4 96 112 99 115
+3 2 0 1
+3 2 3 0
+3 0 4 1
+3 1 5 2
+3 3 6 0
+3 2 7 3
+3 4 5 1
+3 0 8 4
+3 5 9 2
+3 7 6 3
+3 6 10 0
+3 2 11 7
+3 4 12 5
+3 0 13 8
+3 8 14 4
+3 5 15 9
+3 9 16 2
+3 7 17 6
+3 10 18 0
+3 6 19 10
+3 11 20 7
+3 2 21 11
+3 12 22 5
+3 4 23 12
+3 13 14 8
+3 0 24 13
+3 14 25 4
+3 15 16 9
+3 5 26 15
+3 16 27 2
+3 7 28 17
+3 17 29 6
+3 19 18 10
+3 18 24 0
+3 6 30 19
+3 21 20 11
+3 20 31 7
+3 27 21 2
+3 23 22 12
+3 22 32 5
+3 4 33 23
+3 13 34 14
+3 24 35 13
+3 14 20 25
+3 25 36 4
+3 15 37 16
+3 5 38 26
+3 26 19 15
+3 16 39 27
+3 28 29 17
+3 7 40 28
+3 29 41 6
+3 19 42 18
+3 18 35 24
+3 30 15 19
+3 6 36 30
+3 21 43 20
+3 31 38 7
+3 14 31 20
+3 39 21 27
+3 23 44 22
+3 32 38 5
+3 22 35 32
+3 33 39 23
+3 36 33 4
+3 34 45 14
+3 13 29 34
+3 35 46 13
+3 20 36 25
+3 37 28 16
+3 15 47 37
+3 38 19 26
+3 16 48 39
+3 28 49 29
+3 38 40 7
+3 40 35 28
+3 29 39 41
+3 41 36 6
+3 19 45 42
+3 42 23 18
+3 18 50 35
+3 36 15 30
+3 21 22 43
+3 43 47 20
+3 14 38 31
+3 39 51 21
+3 23 45 44
+3 44 47 22
+3 35 38 32
+3 22 46 35
+3 36 39 33
+3 48 23 39
+3 29 45 34
+3 45 52 14
+3 13 51 29
+3 46 21 13
+3 20 53 36
+3 47 28 37
+3 28 50 16
+3 15 53 47
+3 38 52 19
+3 16 18 48
+3 49 45 29
+3 47 49 28
+3 38 40 35
+3 35 28 50
+3 39 41 36
+3 29 39 51
+3 45 42 23
+3 19 45 52
+3 23 18 48
+3 18 50 16
+3 36 15 53
+3 22 43 47
+3 21 22 46
+3 47 20 53
+3 14 38 52
+3 51 21 13
+3 45 47 44
+3 49 45 47
+inverted snub dodecadodecahedron
+medial inverted pentagonal hexecontahedron
+|5/3 2 5
+(3.5/3.3.3.5)
+icosahedral group
+A5
+12{5}+60{3}+12{5/3}
+64 60 150 84 60 9 0 0 -6 3 5 120 5 0 -1
+ 0.0000000000 0.0000000000 1.0000000000
+ 0.9505389400 0.0000000000 0.3106054144
+ 0.2252718768 0.9234591805 0.3106054144
+ 0.8112598353 0.4953602287 0.3106054144
+-0.2889844000 0.9055453015 0.3106054144
+-0.9482348826 -0.0661429059 0.3106054144
+ 0.5897694300 -0.0661429059 -0.8048584567
+ 0.3850026607 0.9055453015 -0.1782152018
+ 0.5573198493 0.4377082809 -0.7055537162
+-0.4709954327 0.1594257169 0.8676097874
+ 0.6720341587 -0.0753689321 0.7366747000
+-0.2761142752 0.6173097225 0.7366747000
+ 0.2950721213 -0.4002320578 0.8676097874
+ 0.8005020002 -0.5722201408 -0.1782152018
+-0.9797305684 0.0914732487 -0.1782152018
+-0.4850646484 -0.1093871277 0.8676097874
+-0.0776254431 0.4911492110 0.8676097874
+-0.4470814740 0.8765600364 -0.1782152018
+-0.5837373293 -0.1070214698 -0.8048584567
+-0.0305345625 0.8765600364 -0.4803229570
+-0.4885089715 0.3978663999 -0.7765702239
+ 0.6822034907 0.1918133228 0.7055537162
+ 0.9068404918 -0.1219494938 -0.4034459610
+ 0.6280254238 0.6350267068 0.4498056789
+ 0.9074753675 -0.4197944019 0.0161591306
+ 0.0662694728 -0.6265357487 -0.7765702239
+-0.5692643226 -0.7985238317 0.1956982912
+ 0.4568451653 -0.5417438957 0.7055537162
+-0.1299819960 -0.8836172995 0.4498056789
+ 0.5895721585 0.8070147898 -0.0336422200
+-0.5234589817 0.7504812130 -0.4034459610
+ 0.4007400217 -0.8959359724 -0.1915885392
+ 0.9945763348 0.0855188418 0.0591983266
+-0.0076279270 -0.7569762005 0.6533979236
+-0.3063909428 -0.8218360221 -0.4803229570
+-0.4897789665 -0.5772241483 0.6533979236
+-0.4053104966 -0.9140362596 0.0161591306
+ 0.1584253171 0.8200264597 0.5499618390
+-0.8270506245 0.5611198317 -0.0336422200
+-0.7034190217 -0.4502706470 0.5499618390
+-0.1409472501 0.0818639196 -0.9866266626
+-0.9653847065 -0.1769920905 -0.1915885392
+-0.8809267432 0.4308947110 0.1956982912
+ 0.8861844855 0.1438774958 -0.4404274331
+-0.1051400207 -0.1847560597 -0.9771441933
+ 0.6358781390 0.5897865144 -0.4978060464
+ 0.2874702454 -0.4819231848 -0.8277142635
+-0.7311680197 -0.6296283954 -0.2626050469
+ 0.3681846210 -0.8724307068 0.3214105579
+ 0.1681444855 0.7640334636 -0.6228806455
+-0.5294657581 0.7850867877 0.3214105579
+-0.0773062511 -0.9216496181 -0.3802442964
+ 0.3662906510 0.0161043166 -0.9303611180
+ 0.6023558347 -0.7546105427 0.2602506049
+ 0.4177101363 -0.7946961169 -0.4404274331
+ 0.2460872708 0.1028921402 0.9637708559
+-0.8447900947 0.0442149038 0.5332679797
+-0.7081172394 -0.5007585401 -0.4978060464
+-0.2634083151 0.5441095536 -0.7965932797
+-0.7705003202 -0.0094229209 -0.6373699594
+ 0.0347733835 0.0273103460 0.0479456261
+ 0.0221937153 0.0303790744 0.0479456261
+ 0.0154457535 0.0414303258 0.0479456261
+-0.0365894750 0.0248244539 0.0479456261
+ 0.0347733835 -0.9982444734 0.0479456261
+ 0.0569390737 0.0248244539 -0.0198875498
+ 0.0531075573 0.0287610955 -0.0081620442
+ 0.0512555391 0.0402551137 -0.0024943533
+-0.7983984023 0.3985080838 -0.4513881903
+ 0.0126076932 0.0297962381 0.0566308796
+ 0.0245528255 0.0210696106 0.0566308796
+ 0.0563926334 -0.0141094994 0.0295739612
+ 0.1529062285 0.4101421715 -0.8991123870
+-0.0518662103 0.0262507772 0.0295739612
+-0.0407008533 0.0276138549 0.0359881617
+-0.0435607236 0.0384924725 0.0295739612
+-0.0585284569 0.0208021960 -0.0198875498
+-0.0007246349 0.0208021960 -0.0618107580
+ 0.0093187938 0.0249959101 -0.0547959559
+ 0.0143807266 0.0365909393 -0.0520396399
+-0.6678347106 0.4530983827 0.5905071167
+ 0.0583803788 0.0288467118 0.0036639936
+ 0.0618929964 0.0193100395 -0.0070855930
+ 0.0452796477 -0.0179993596 -0.0433543864
+-0.0172538804 -0.0349221758 0.0523122501
+-0.0093187938 -0.0249959101 0.0547959559
+ 0.0021014290 -0.0236461716 0.0607475829
+ 0.6678347106 -0.4530983827 -0.5905071167
+ 0.0291449034 0.0398939600 0.0425778443
+-0.0062105643 0.0643176201 0.0088599601
+-0.8714085158 -0.4719227321 0.1339258511
+ 0.0499914832 -0.0358036921 0.0217433552
+ 0.0486579924 -0.0242868764 0.0275096281
+ 0.0436238866 -0.0336369212 0.0349190536
+ 0.0143872332 -0.0636145476 -0.0001520171
+-0.0525204118 -0.0386705249 -0.0001520171
+-0.0531075573 -0.0287610955 0.0081620442
+-0.0553064338 -0.0275614572 0.0208660182
+ 0.7983984023 -0.3985080838 0.4513881903
+-0.0341191820 0.0376109561 0.0409282746
+-0.0475577418 0.0178034772 0.0409282746
+-0.0095878575 -0.0148125719 0.0627892265
+ 0.8714085158 0.4719227321 -0.1339258511
+-0.0459405885 0.0231100357 -0.0401150201
+-0.0486579924 0.0242868764 -0.0275096281
+-0.0442189464 0.0355015672 -0.0322203316
+ 0.3641627194 0.4984711306 0.7867096324
+ 0.0221955507 0.0247144114 -0.0561282608
+ 0.0128599239 0.0149564314 -0.0621671439
+-0.0275690461 -0.0211064978 -0.0552113186
+ 0.0578830028 -0.0237350817 0.0184399064
+-0.3641627194 -0.4984711306 -0.7867096324
+ 0.0503647635 0.0377692216 -0.0170500075
+ 0.0078874982 0.0645938774 0.0043868710
+-0.1529062285 -0.4101421715 0.8991123870
+ 0.0353840547 -0.0391955450 -0.0382819042
+ 0.0407008533 -0.0276138549 -0.0359881617
+ 0.0459818845 -0.0365909393 -0.0282948002
+ 0.0029384979 -0.0644614796 -0.0094820427
+ 0.0021192465 -0.0608375115 0.0029220223
+ 0.0090286636 -0.0631393379 0.0136284081
+-0.0215500966 -0.0217815257 0.0575759041
+-0.0497697037 -0.0396338675 0.0143512855
+-0.0060124429 0.0631762251 -0.0150479691
+-0.0021192465 0.0608375115 -0.0029220223
+ 0.0080099440 0.0638884564 -0.0103890418
+ 0.0002152729 0.0341730572 -0.0555516163
+ 0.0349500485 -0.0277053167 -0.0475892403
+ 0.0520976973 -0.0234909763 -0.0314297666
+-0.0347733835 0.9982444734 -0.0479456261
+ 0.0475800150 -0.0202291728 0.0397586343
+-0.0094957793 -0.0645097026 -0.0014678904
+-0.0057318499 -0.0636925741 0.0128151536
+-0.0614790292 -0.0191369547 0.0103890418
+-0.0597571729 -0.0260027361 -0.0026008184
+-0.0262717496 -0.0415627235 -0.0428504544
+-0.0148012004 0.0634414628 -0.0031514317
+-0.0026364338 -0.0360745903 0.0542724553
+-0.0134385598 -0.0397018775 -0.0499699139
+-0.0221937153 -0.0303790744 -0.0479456261
+-0.0350048704 -0.0300701469 -0.0460898207
+-0.0519986769 0.0340752438 -0.0197190674
+-0.0547843524 0.0140253247 -0.0324929418
+-0.0142403331 -0.0270592347 -0.0576093481
+3 0 2 1
+5 0 3 11 10 2 3
+3 0 4 3
+3 0 5 4
+5 0 1 6 18 5
+3 1 7 6
+5 1 8 23 22 7 3
+3 1 2 8
+5 2 9 26 25 8
+3 2 10 9
+3 3 12 11
+3 3 13 12
+5 3 4 14 34 13
+3 4 15 14
+5 4 5 16 38 15 3
+3 5 17 16
+3 5 18 17
+3 6 19 18
+5 6 20 45 44 19 3
+3 6 7 20
+5 7 21 33 47 20
+3 7 22 21
+3 8 24 23
+3 8 25 24
+3 9 27 26
+5 9 28 55 39 27 3
+3 9 10 28
+5 10 29 58 57 28
+3 10 11 29
+3 11 30 29
+5 11 12 31 44 30
+3 12 32 31
+5 12 13 21 48 32 3
+3 13 33 21
+3 13 34 33
+3 14 35 34
+5 14 36 56 57 35 3
+3 14 15 36
+5 15 37 45 46 36
+3 15 38 37
+3 16 39 38
+3 16 27 39
+5 16 17 40 54 27
+3 17 41 40
+5 17 18 42 58 41 3
+3 18 19 42
+5 19 43 53 35 42
+3 19 44 43
+3 20 46 45
+3 20 47 46
+3 21 22 48
+5 22 49 38 39 48
+3 22 23 49
+3 23 50 49
+5 23 24 51 41 50
+3 24 52 51
+5 24 25 43 31 52 3
+3 25 53 43
+3 25 26 53
+5 26 54 33 34 53 3
+3 26 27 54
+3 28 56 55
+3 28 57 56
+3 29 50 58
+5 29 30 37 49 50 3
+3 30 45 37
+3 30 44 45
+3 31 43 44
+3 31 32 52
+5 32 55 56 59 52
+3 32 48 55
+3 33 54 47
+3 34 35 53
+3 35 57 42
+3 36 59 56
+3 36 46 59
+3 37 38 49
+3 39 55 48
+3 40 47 54
+5 40 51 59 46 47 3
+3 40 41 51
+3 41 58 50
+3 42 57 58
+3 51 52 59
+5 4 0 1 2 3
+5 4 5 6 7 0
+5 7 8 9 1 0
+5 1 10 11 12 2
+5 12 13 14 3 2
+5 14 15 16 4 3
+5 4 17 18 19 5
+5 19 20 21 6 5
+5 6 22 23 8 7
+5 8 24 25 26 9
+5 26 27 28 1 9
+5 28 29 30 10 1
+5 30 31 32 11 10
+5 32 33 34 12 11
+5 12 35 36 37 13
+5 37 38 39 14 13
+5 14 40 41 42 15
+5 42 43 44 16 15
+5 44 45 17 4 16
+5 45 46 47 18 17
+5 18 48 49 20 19
+5 20 33 32 50 21
+5 50 51 52 6 21
+5 52 53 54 22 6
+5 54 55 56 23 22
+5 56 57 58 8 23
+5 58 59 60 24 8
+5 60 42 41 25 24
+5 25 61 62 27 26
+5 27 63 64 29 28
+5 64 65 66 30 29
+5 30 67 56 68 31
+5 68 69 70 32 31
+5 20 71 59 34 33
+5 59 72 35 12 34
+5 72 46 73 36 35
+5 36 74 75 38 37
+5 38 65 64 76 39
+5 76 51 40 14 39
+5 51 77 25 41 40
+5 42 78 79 80 43
+5 80 54 81 44 43
+5 44 82 73 46 45
+5 46 57 56 67 47
+5 66 18 47 67 30
+5 38 48 18 66 65
+5 75 79 49 48 38
+5 78 71 20 49 79
+5 70 77 51 50 32
+5 64 53 52 51 76
+5 63 81 54 53 64
+5 79 83 55 54 80
+5 83 69 68 56 55
+5 57 58 59 72 46
+5 59 60 42 78 71
+5 69 61 25 77 70
+5 69 74 36 62 61
+5 82 27 62 36 73
+5 27 63 81 44 82
+5 74 75 79 83 69
+great dodecicosidodecahedron
+great dodecacronic hexecontahedron
+5/2 3|5/3
+(10/3.5/2.10/3.3)
+icosahedral group
+A5
+12{10/3}+20{3}+12{5/2}
+65 60 120 44 60 10 0 0 -16 3 4 120 5 0 -1
+ 0.0000000000 0.0000000000 1.0000000000
+ 0.9996324920 0.0000000000 0.0271086873
+-0.3453645319 0.9380770007 0.0271086873
+-0.9468654869 0.3204853643 0.0271086873
+ 0.0263835025 -0.9992842588 0.0271086873
+ 0.0364611038 0.9380770007 -0.3445027268
+ 0.0527670051 0.3204853643 -0.9457826254
+-0.7334184677 -0.2592781062 0.6283885859
+-0.3189810294 -0.0612072581 -0.9457826254
+ 0.8677149793 0.3583135302 -0.3445027268
+-0.3352869307 -0.8768697425 -0.3445027268
+ 0.2398305218 0.7400061526 0.6283885859
+-0.9367878857 -0.0612072581 -0.3445027268
+ 0.6480396600 -0.2592781062 -0.7161141409
+-0.3678987333 0.3583135302 0.8580570704
+ 0.6216561575 0.7400061526 0.2567771718
+-0.4672044434 -0.5185562123 -0.7161141409
+ 0.4796610435 -0.8390415766 0.2567771718
+-0.7233408665 -0.6409707286 0.2567771718
+ 0.4633551422 -0.2214499403 0.8580570704
+ 0.8514090780 -0.4573489542 0.2567771718
+ 0.2336022217 -0.4573489542 0.8580570704
+ 0.5060445461 0.4807280465 -0.7161141409
+ 0.2762916255 -0.6409707286 -0.7161141409
+-0.7031856640 -0.5185562123 -0.4864456563
+ 0.2436798229 -0.8390415766 0.4864456563
+ 0.8451807779 -0.2214499403 0.4864456563
+-0.7295691665 0.4807280465 0.4864456563
+-0.2436798229 0.8390415766 -0.4864456563
+ 0.7031856640 0.5185562123 0.4864456563
+-0.4998162460 0.7166270604 0.4864456563
+ 0.7295691665 -0.4807280465 -0.4864456563
+-0.4998162460 -0.7166270604 0.4864456563
+ 0.4998162460 -0.7166270604 -0.4864456563
+-0.8451807779 0.2214499403 -0.4864456563
+ 0.4998162460 0.7166270604 -0.4864456563
+-0.4796610435 0.8390415766 -0.2567771718
+ 0.4672044434 0.5185562123 0.7161141409
+-0.5060445461 -0.4807280465 0.7161141409
+-0.4633551422 0.2214499403 -0.8580570704
+-0.6480396600 0.2592781062 0.7161141409
+ 0.3678987333 -0.3583135302 -0.8580570704
+-0.2336022217 0.4573489542 -0.8580570704
+-0.6216561575 -0.7400061526 -0.2567771718
+-0.2762916255 0.6409707286 0.7161141409
+ 0.7233408665 0.6409707286 -0.2567771718
+-0.8514090780 0.4573489542 -0.2567771718
+ 0.7334184677 0.2592781062 -0.6283885859
+-0.8677149793 -0.3583135302 0.3445027268
+-0.2398305218 -0.7400061526 -0.6283885859
+-0.0364611038 -0.9380770007 0.3445027268
+ 0.9367878857 0.0612072581 0.3445027268
+ 0.3352869307 0.8768697425 0.3445027268
+-0.0527670051 -0.3204853643 0.9457826254
+ 0.3189810294 0.0612072581 0.9457826254
+ 0.3453645319 -0.9380770007 -0.0271086873
+ 0.9468654869 -0.3204853643 -0.0271086873
+-0.9996324920 0.0000000000 -0.0271086873
+-0.0263835025 0.9992842588 -0.0271086873
+ 0.0000000000 0.0000000000 -1.0000000000
+ 0.4931762648 0.7071067812 0.5067318540
+-0.3915763668 0.3813742685 0.5067318540
+-0.6938439517 -0.5116672736 0.5067318540
+ 0.4931762648 -0.4803270912 0.5067318540
+ 0.5253548247 -0.5116672736 -0.6798521231
+ 0.5171607473 0.3813742685 -0.3776956239
+ 0.0977538074 0.5937169362 -0.6071725516
+-0.9541739697 0.1954395076 -0.2266173744
+-0.2205551306 0.9486832981 -0.2266173744
+-0.5909300722 -0.1133898450 -0.6071725516
+-0.3675918843 -0.5270462767 -0.3776956239
+-0.2006676869 0.1954395076 -0.9599666027
+-0.6095993882 0.5937169362 0.0812582313
+-0.3465455537 -0.7771855594 0.0812582313
+ 0.2006676869 -0.1954395076 0.9599666027
+ 0.7111992862 -0.1456720081 0.1689106180
+ 0.1643920883 -0.7071067812 0.1689106180
+ 0.7677683711 0.3669372463 0.0812582313
+ 0.9541739697 -0.1954395076 0.2266173744
+ 0.0906227633 -0.7771855594 -0.3442153914
+ 0.1495688629 -0.1456720081 0.7155168599
+ 0.0604151755 0.3669372463 0.7696890141
+-0.1495688629 0.1456720081 -0.7155168599
+ 0.2205551306 -0.9486832981 0.2266173744
+-0.3652148696 -0.0700787782 0.7696890141
+ 0.7793066430 -0.0700787782 -0.3442153914
+-0.7111992862 0.1456720081 -0.1689106180
+-0.0906227633 0.7771855594 0.3442153914
+ 0.6938439517 0.5116672736 -0.5067318540
+-0.1643920883 0.7071067812 -0.1689106180
+-0.0604151755 -0.3669372463 -0.7696890141
+-0.7793066430 0.0700787782 0.3442153914
+-0.4931762648 -0.7071067812 -0.5067318540
+ 0.3652148696 0.0700787782 -0.7696890141
+-0.5253548247 0.5116672736 0.6798521231
+ 0.3465455537 0.7771855594 -0.0812582313
+-0.7677683711 -0.3669372463 -0.0812582313
+-0.5171607473 -0.3813742685 0.3776956239
+ 0.6095993882 -0.5937169362 -0.0812582313
+ 0.3675918843 0.5270462767 0.3776956239
+ 0.3915763668 -0.3813742685 -0.5067318540
+-0.0977538074 -0.5937169362 0.6071725516
+ 0.5909300722 0.1133898450 0.6071725516
+-0.4931762648 0.4803270912 -0.5067318540
+10 0 2 9 19 30 35 26 14 5 1 3
+5 0 3 11 7 2 2
+10 0 4 12 14 25 24 27 21 10 3 3
+3 0 1 4
+10 1 6 10 20 22 16 17 9 8 4 3
+5 1 5 13 15 6 2
+3 2 8 9
+10 2 7 16 28 40 43 42 30 18 8 3
+10 3 6 15 27 39 45 44 34 22 11 3
+3 3 10 6
+5 4 8 18 23 12 2
+10 5 12 23 35 46 49 47 36 24 13 3
+3 5 14 12
+3 7 17 16
+10 7 11 20 32 44 51 50 40 29 17 3
+5 9 17 29 31 19 2
+5 10 21 33 32 20 2
+3 11 22 20
+10 13 25 37 47 55 54 45 33 21 15 3
+3 13 24 25
+5 14 26 38 37 25 2
+3 15 21 27
+5 16 22 34 41 28 2
+10 18 19 31 43 53 56 49 38 26 23 3
+3 18 30 19
+3 23 26 35
+5 24 36 48 39 27 2
+3 28 29 40
+10 28 41 51 58 59 56 52 42 31 29 3
+5 30 42 52 46 35 2
+3 31 42 43
+3 32 34 44
+10 32 33 39 48 55 59 57 50 41 34 3
+3 33 45 39
+10 36 37 38 46 52 53 57 58 54 48 3
+3 36 47 37
+3 38 49 46
+5 40 50 57 53 43 2
+3 41 50 51
+5 44 45 54 58 51 2
+5 47 49 56 59 55 2
+3 48 54 55
+3 52 56 53
+3 57 59 58
+4 3 0 1 2
+4 3 4 5 0
+4 0 6 7 1
+4 1 8 9 2
+4 2 10 4 3
+4 5 11 12 0
+4 4 9 8 5
+4 7 13 14 1
+4 6 4 10 7
+4 0 15 4 6
+4 4 16 2 9
+4 14 17 8 1
+4 2 12 11 10
+4 5 18 19 11
+4 2 20 0 12
+4 8 21 18 5
+4 7 22 4 13
+4 15 14 13 4
+4 10 23 24 7
+4 0 24 23 15
+4 4 17 14 16
+4 16 18 21 2
+4 22 8 17 4
+4 11 25 23 10
+4 19 2 26 11
+4 18 20 2 19
+4 20 23 25 0
+4 8 26 2 21
+4 7 27 28 22
+4 15 28 27 14
+4 0 29 7 24
+4 23 30 28 15
+4 14 31 32 16
+4 32 33 18 16
+4 22 32 31 8
+4 11 29 0 25
+4 26 34 35 11
+4 18 35 34 20
+4 34 36 23 20
+4 8 33 32 26
+4 7 37 14 27
+4 28 38 32 22
+4 29 28 30 7
+4 23 37 7 30
+4 14 39 8 31
+4 39 18 33 8
+4 11 36 34 29
+4 18 40 11 35
+4 32 41 34 26
+4 40 23 36 11
+4 37 32 38 14
+4 28 39 14 38
+4 34 42 28 29
+4 23 42 34 37
+4 39 34 41 18
+4 32 40 18 41
+4 40 28 42 23
+4 34 43 32 37
+4 28 43 34 39
+4 32 40 28 43
+small dodecahemicosahedron
+small dodecahemicosacron
+5/3 5/2|3
+(6.5/3.6.5/2)
+icosahedral group
+A5
+10{6}+6{5/2}+6{5/3}
+66 30 60 22 30 0 1 1 -8 3 4 120 5 1 -1
+ 0.0000000000 0.0000000000 1.0000000000
+ 0.8660254038 0.0000000000 0.5000000000
+-0.8660254038 0.0000000000 0.5000000000
+-0.6454972244 0.5773502692 0.5000000000
+ 0.6454972244 -0.5773502692 0.5000000000
+ 0.8660254038 0.0000000000 -0.5000000000
+ 0.7557613141 0.5773502692 -0.3090169944
+ 0.1102640897 -0.5773502692 0.8090169944
+-0.1102640897 0.5773502692 0.8090169944
+-0.7557613141 -0.5773502692 -0.3090169944
+-0.8660254038 0.0000000000 -0.5000000000
+-0.6454972244 0.5773502692 -0.5000000000
+-0.1784110449 0.9341723590 -0.3090169944
+-0.4670861795 -0.3568220898 0.8090169944
+ 0.4670861795 0.3568220898 0.8090169944
+ 0.1784110449 -0.9341723590 -0.3090169944
+ 0.6454972244 -0.5773502692 -0.5000000000
+ 0.7557613141 0.5773502692 0.3090169944
+ 0.1102640897 -0.5773502692 -0.8090169944
+ 0.0000000000 -0.0000000000 -1.0000000000
+-0.1102640897 0.5773502692 -0.8090169944
+ 0.9341723590 -0.3568220898 0.0000000000
+-0.3568220898 -0.9341723590 0.0000000000
+-0.7557613141 -0.5773502692 0.3090169944
+ 0.3568220898 0.9341723590 0.0000000000
+-0.9341723590 0.3568220898 0.0000000000
+-0.1784110449 0.9341723590 0.3090169944
+-0.4670861795 -0.3568220898 -0.8090169944
+ 0.4670861795 0.3568220898 -0.8090169944
+ 0.1784110449 -0.9341723590 0.3090169944
+ 0.0000000000 1.0000000000 0.0000000000
+-0.4911234732 0.1875924741 0.8506508084
+-0.6666666667 -0.7453559925 0.0000000000
+ 0.4911234732 -0.1875924741 0.8506508084
+ 0.3333333333 -0.7453559925 -0.5773502692
+ 0.9822469464 0.1875924741 0.0000000000
+-0.9822469464 -0.1875924741 0.0000000000
+ 0.3333333333 -0.7453559925 0.5773502692
+ 0.7453559925 0.3333333333 0.5773502692
+-0.6070619982 0.7946544723 0.0000000000
+ 0.6070619982 -0.7946544723 0.0000000000
+ 0.7453559925 0.3333333333 -0.5773502692
+ 0.4911234732 -0.1875924741 -0.8506508084
+ 0.3035309991 0.7946544723 -0.5257311121
+ 0.1273220038 0.3333333333 0.9341723590
+-0.8726779962 0.3333333333 0.3568220898
+-0.3035309991 -0.7946544723 0.5257311121
+ 0.3035309991 0.7946544723 0.5257311121
+-0.8726779962 0.3333333333 -0.3568220898
+ 0.1273220038 0.3333333333 -0.9341723590
+-0.3035309991 -0.7946544723 -0.5257311121
+-0.4911234732 0.1875924741 -0.8506508084
+6 0 1 5 19 10 2
+5 0 2 8 13 3 3
+6 0 3 11 19 16 4
+5 0 1 7 14 4 2
+6 1 7 23 10 20 6
+5 1 6 21 17 5 3
+5 2 10 23 25 9 2
+6 2 9 18 5 17 8
+6 3 13 29 16 28 12
+5 3 12 25 26 11 2
+5 4 16 29 21 15 3
+6 4 15 27 11 26 14
+5 5 18 28 16 19 2
+5 6 20 24 28 12 2
+6 6 12 25 23 29 21
+6 7 14 24 20 27 22
+5 7 22 13 29 23 3
+5 8 17 26 14 24 2
+6 8 24 28 18 22 13
+6 9 25 26 17 21 15
+5 9 15 27 22 18 3
+5 10 19 11 27 20 3
+4 3 0 1 2
+4 3 4 5 0
+4 6 0 1 7
+4 1 8 9 2
+4 10 2 3 11
+4 5 7 12 0
+4 13 4 5 14
+4 3 15 16 4
+4 17 7 1 18
+4 6 19 20 7
+4 21 0 6 4
+4 9 11 21 2
+4 13 8 9 14
+4 16 18 1 8
+4 17 11 3 15
+4 10 19 20 11
+4 12 2 10 8
+4 5 19 17 7
+4 20 18 12 7
+4 12 0 21 2
+4 21 15 13 4
+4 10 14 5 19
+4 20 15 16 18
+4 16 14 6 4
+4 13 18 17 15
+4 9 19 6 14
+4 9 11 17 19
+4 21 11 20 15
+4 13 8 12 18
+4 16 8 10 14
+great dodecicosahedron
+great dodecicosacron
+5/3 5/2 3|
+(6.10/3.6/5.10/7)
+icosahedral group
+A5
+10{6}+6{10/3}+6{10/7}+10{6/5}
+67 60 120 32 60 0 0 1 -28 4 4 120 5 0 1
+ 0.0000000000 0.0000000000 1.0000000000
+ 0.7913673487 0.0000000000 0.6113409191
+-0.6820030709 0.4014151117 0.6113409191
+-0.4944105968 -0.6179162098 0.6113409191
+ 0.1126514014 0.7833083316 0.6113409191
+ 0.9007316265 0.4014151117 -0.1659772426
+ 0.7860486710 -0.6179162098 -0.0175226837
+ 0.4149268310 0.7833083316 0.4628863603
+-0.7549125894 -0.4645892808 0.4628863603
+-0.5726387930 0.8028302234 -0.1659772426
+-0.8761697921 -0.4525240881 -0.1659772426
+-0.0086058013 -0.9998094297 -0.0175226837
+-0.8708511144 0.1653921218 0.4628863603
+ 0.8343963552 0.2991971590 0.4628863603
+-0.2691077939 0.9487004534 -0.1659772426
+ 0.8278221080 -0.4645892808 -0.3144318014
+ 0.2187285557 0.8028302234 -0.5546363234
+ 0.4042894756 -0.4525240881 -0.7948408455
+ 0.8987000724 0.1653921218 -0.4061817646
+-0.1437874830 0.2991971590 0.9432954043
+ 0.0331676357 0.9487004534 -0.3144318014
+-0.0331676357 -0.9487004534 0.3144318014
+-0.6906088722 -0.5983943180 -0.4061817646
+-0.0278489580 -0.3307842435 0.9432954043
+-0.5779574707 0.1849140136 -0.7948408455
+ 0.1544248384 0.9366352607 0.3144318014
+-0.1544248384 -0.9366352607 -0.3144318014
+-0.7635183907 0.3307842435 -0.5546363234
+ 0.1007584765 -0.5983943180 -0.7948408455
+-0.7614868366 0.5668072335 -0.3144318014
+ 0.7614868366 -0.5668072335 0.3144318014
+ 0.2756820411 -0.1849140136 0.9432954043
+ 0.2166970016 0.5668072335 -0.7948408455
+-0.8278221080 0.4645892808 0.3144318014
+ 0.2691077939 -0.9487004534 0.1659772426
+ 0.7635183907 -0.3307842435 0.5546363234
+-0.2756820411 0.1849140136 -0.9432954043
+ 0.0278489580 0.3307842435 -0.9432954043
+-0.2166970016 -0.5668072335 0.7948408455
+ 0.5779574707 -0.1849140136 0.7948408455
+ 0.7549125894 0.4645892808 -0.4628863603
+-0.4149268310 -0.7833083316 -0.4628863603
+-0.4042894756 0.4525240881 0.7948408455
+ 0.1437874830 -0.2991971590 -0.9432954043
+ 0.8761697921 0.4525240881 0.1659772426
+ 0.5726387930 -0.8028302234 0.1659772426
+-0.2187285557 -0.8028302234 0.5546363234
+-0.8343963552 -0.2991971590 -0.4628863603
+ 0.8708511144 -0.1653921218 -0.4628863603
+-0.1007584765 0.5983943180 0.7948408455
+-0.9007316265 -0.4014151117 0.1659772426
+-0.1126514014 -0.7833083316 -0.6113409191
+-0.8987000724 -0.1653921218 0.4061817646
+ 0.6906088722 0.5983943180 0.4061817646
+ 0.6820030709 -0.4014151117 -0.6113409191
+-0.7913673487 0.0000000000 -0.6113409191
+-0.7860486710 0.6179162098 0.0175226837
+ 0.4944105968 0.6179162098 -0.6113409191
+ 0.0086058013 0.9998094297 0.0175226837
+ 0.0000000000 0.0000000000 -1.0000000000
+ 0.2317571228 0.8506508084 0.4718917654
+-0.3015891505 -0.0555029103 0.4718917654
+-0.8089973662 0.3504874081 0.4718917654
+ 0.2317571228 0.2008114159 0.4718917654
+ 0.8680129287 0.3504874081 -0.3517273552
+ 0.5578135237 -0.0555029103 0.0498189392
+-0.2259811885 0.4702282018 0.2110364131
+ 0.0842182165 -0.1752437040 0.9809163757
+-0.8159632084 -0.4587939735 -0.3517273552
+-0.3051588742 -0.4702282018 0.0498189392
+ 0.7247791497 -0.1752437040 0.6663218655
+ 0.3051588742 0.4702282018 -0.0498189392
+ 0.2259811885 -0.4702282018 -0.2110364131
+ 0.2204861533 -0.4587939735 -0.8607519655
+ 0.0772523743 -0.9845250856 0.1572972551
+-0.1828226219 0.3804226065 -0.3722538870
+ 0.3159753393 0.6754071043 -0.6663218655
+-0.3159753393 -0.6754071043 0.6663218655
+-0.5578135237 0.0555029103 -0.0498189392
+ 0.7204740224 -0.6754071043 0.1572972551
+-0.7247791497 0.1752437040 -0.6663218655
+-0.7204740224 0.6754071043 -0.1572972551
+ 0.3015891505 0.0555029103 -0.4718917654
+-0.0842182165 0.1752437040 -0.9809163757
+ 0.1828226219 -0.3804226065 0.3722538870
+-0.8680129287 -0.3504874081 0.3517273552
+-0.2317571228 -0.2008114159 -0.4718917654
+-0.0772523743 0.9845250856 -0.1572972551
+ 0.8159632084 0.4587939735 0.3517273552
+ 0.8089973662 -0.3504874081 -0.4718917654
+-0.2204861533 0.4587939735 0.8607519655
+-0.2317571228 -0.8506508084 -0.4718917654
+6 0 2 9 16 5 1
+10 0 3 12 19 38 52 42 23 8 2 3
+6 0 4 14 27 10 3 5
+10 0 1 7 19 39 53 49 31 13 4 7
+6 1 6 17 37 20 7 5
+10 1 5 15 35 44 48 30 13 18 6 3
+10 2 4 14 33 49 58 56 42 25 9 7
+6 2 8 21 30 13 4 5
+6 3 11 28 36 29 12
+10 3 10 26 46 50 41 21 8 22 11 7
+6 5 7 19 38 34 15 5
+10 5 16 25 44 57 58 53 40 20 7 7
+10 6 11 28 15 34 51 54 45 26 17 7
+6 6 18 32 24 22 11
+6 8 23 35 15 28 22
+10 9 24 32 14 27 37 20 29 36 16 3
+6 9 25 44 48 43 24 5
+6 10 12 19 39 45 26
+10 10 27 33 50 55 56 52 47 29 12 3
+6 13 31 46 26 17 18 5
+6 14 33 50 41 43 32
+6 16 36 47 52 42 25 5
+10 17 18 32 43 48 57 59 54 40 37 3
+6 20 29 47 51 54 40
+10 21 23 35 34 38 39 45 46 31 30 3
+6 21 41 55 56 42 23
+10 22 28 36 47 51 59 55 41 43 24 3
+6 27 37 40 53 49 33
+6 30 48 57 58 49 31 5
+6 34 35 44 57 59 51
+6 38 39 53 58 56 52 5
+6 45 46 50 55 59 54 5
+4 3 0 1 2
+4 3 4 5 0
+4 0 6 7 1
+4 1 8 9 2
+4 2 6 7 3
+4 5 10 11 0
+4 4 12 13 5
+4 3 10 11 4
+4 7 9 14 1
+4 0 15 16 6
+4 9 17 18 2
+4 8 12 13 9
+4 1 17 18 8
+4 7 5 19 3
+4 2 15 20 6
+4 5 14 12 10
+4 11 21 15 0
+4 4 22 19 12
+4 13 22 19 5
+4 3 17 1 10
+4 11 23 15 4
+4 7 24 25 9
+4 13 26 14 9
+4 14 24 25 1
+4 15 13 26 16
+4 16 11 21 6
+4 9 19 12 17
+4 18 27 15 2
+4 8 26 14 12
+4 18 23 15 8
+4 24 28 5 7
+4 19 24 28 3
+4 22 20 15 13
+4 20 18 27 6
+4 12 29 24 10
+4 5 29 24 14
+4 21 26 8 15
+4 27 22 4 15
+4 1 30 24 10
+4 3 30 24 17
+4 11 27 22 23
+4 25 26 20 9
+4 25 6 21 1
+4 22 16 26 20
+4 16 5 29 11
+4 12 31 24 17
+4 9 31 24 19
+4 18 21 26 23
+4 28 22 16 5
+4 28 6 27 3
+4 31 18 20 9
+4 12 23 26 29
+4 18 30 1 21
+4 11 30 3 27
+4 22 31 12 23
+4 25 18 31 26
+4 30 6 25 18
+4 29 22 28 11
+4 28 6 30 11
+4 26 29 22 31
+great snub dodecicosidodecahedron
+great hexagonal hexecontahedron
+|5/3 5/2 3
+(3.5/3.3.5/2.3.3)
+icosahedral group
+A5
+80{3}+12{5/2}+12{5/3}
+68 60 180 104 60 10 0 0 -16 3 6 120 5 0 -1
+ 0.0000000000 0.0000000000 1.0000000000
+ 1.0000000000 0.0000000000 0.0000000000
+ 0.0000000000 1.0000000000 0.0000000000
+ 0.7861513778 0.6180339887 0.0000000000
+-0.6180339887 0.7861513778 0.0000000000
+-1.0000000000 -0.0000000000 0.0000000000
+ 0.0000000000 -1.0000000000 0.0000000000
+ 0.0000000000 -0.0000000000 -1.0000000000
+ 0.0000000000 -0.7861513778 -0.6180339887
+ 0.0000000000 0.6180339887 -0.7861513778
+ 0.6180339887 0.0000000000 -0.7861513778
+-0.7861513778 0.0000000000 -0.6180339887
+-0.6180339887 -0.0000000000 0.7861513778
+ 0.7861513778 -0.0000000000 0.6180339887
+-0.4858682718 0.6180339887 0.6180339887
+ 0.3819660113 -0.4858682718 0.7861513778
+ 0.6180339887 -0.7861513778 0.0000000000
+-0.7861513778 -0.6180339887 -0.0000000000
+-0.4858682718 -0.3819660113 -0.7861513778
+-0.6180339887 -0.4858682718 0.6180339887
+-0.0000000000 0.7861513778 0.6180339887
+ 0.0000000000 -0.6180339887 0.7861513778
+ 0.6180339887 0.4858682718 -0.6180339887
+ 0.7861513778 -0.3819660113 0.4858682718
+-0.7861513778 0.4858682718 0.3819660113
+ 0.6180339887 0.6180339887 0.4858682718
+ 0.4858682718 -0.7861513778 0.3819660113
+-0.6180339887 -0.6180339887 -0.4858682718
+-0.4858682718 0.7861513778 -0.3819660113
+ 0.3819660113 0.7861513778 -0.4858682718
+ 0.4858682718 -0.6180339887 -0.6180339887
+-0.3819660113 -0.7861513778 0.4858682718
+-0.3819660113 0.4858682718 -0.7861513778
+-0.3177508827 -0.8678342830 -0.3819660113
+ 0.8678342830 -0.1039022605 -0.4858682718
+ 0.4858682718 0.3819660113 0.7861513778
+-0.8678342830 0.1039022605 0.4858682718
+-0.1039022605 0.9183170948 -0.3819660113
+-0.7861513778 0.3819660113 -0.4858682718
+ 0.7861513778 -0.4858682718 -0.3819660113
+-0.3819660113 0.3177508827 0.8678342830
+-0.4858682718 -0.8678342830 0.1039022605
+ 0.4858682718 0.8678342830 -0.1039022605
+-0.3819660113 0.1039022605 -0.9183170948
+ 0.8678342830 0.3819660113 -0.3177508827
+ 0.1039022605 0.4858682718 0.8678342830
+-0.8678342830 -0.3819660113 0.3177508827
+-0.1039022605 -0.4858682718 -0.8678342830
+-0.9183170948 0.3819660113 -0.1039022605
+ 0.9183170948 -0.3819660113 0.1039022605
+ 0.3177508827 0.8678342830 0.3819660113
+-0.2360679775 -0.3177508827 0.9183170948
+ 0.1039022605 -0.9183170948 0.3819660113
+ 0.9183170948 0.2360679775 0.3177508827
+ 0.3819660113 -0.3177508827 -0.8678342830
+ 0.3819660113 -0.1039022605 0.9183170948
+ 0.3177508827 -0.9183170948 -0.2360679775
+-0.3177508827 0.9183170948 0.2360679775
+ 0.2360679775 0.3177508827 -0.9183170948
+-0.9183170948 -0.2360679775 -0.3177508827
+ 0.5773502692 0.5773502692 0.5773502692
+ 0.2805161775 0.5773502692 0.5773502692
+ 0.0970626198 0.8107067993 0.5773502692
+-0.5773502692 0.2805161775 0.5773502692
+-0.5773502692 -0.5773502692 0.5773502692
+ 0.5773502692 -0.5773502692 0.5773502692
+ 0.5773502692 -0.5773502692 -0.5773502692
+ 0.5773502692 -0.2805161775 -0.5773502692
+ 0.5773502692 -0.0970626198 -0.8107067993
+ 0.5773502692 0.5773502692 -0.2805161775
+-0.0970626198 0.5773502692 -0.8107067993
+-0.8107067993 0.5773502692 0.0970626198
+ 0.0970626198 0.5773502692 0.8107067993
+ 0.3938967115 0.4331280021 0.8107067993
+ 0.8107067993 -0.0970626198 0.2805161775
+ 0.8107067993 -0.0970626198 -0.5773502692
+ 0.0970626198 0.8107067993 -0.5773502692
+-0.8107067993 0.0970626198 -0.5773502692
+-0.8107067993 0.0970626198 -0.2805161775
+-0.9941603570 -0.0471596473 -0.0970626198
+-0.5773502692 0.8107067993 -0.0970626198
+-0.5773502692 -0.0970626198 -0.8107067993
+-0.5773502692 -0.8107067993 0.0970626198
+-0.5773502692 -0.5773502692 0.2805161775
+-0.8107067993 -0.5773502692 0.0970626198
+-0.2805161775 -0.5773502692 -0.5773502692
+ 0.8107067993 -0.3938967115 -0.4331280021
+ 0.2805161775 -0.8107067993 0.0970626198
+-0.2805161775 0.8107067993 -0.0970626198
+-0.0970626198 0.9941603570 0.0471596473
+ 0.9941603570 -0.0970626198 0.0471596473
+ 0.2805161775 -0.8107067993 -0.5138727076
+-0.2805161775 0.0970626198 -0.9549290665
+-0.0970626198 0.2805161775 -0.8107067993
+ 0.0471596473 0.0970626198 -0.9941603570
+-0.4331280021 -0.8107067993 0.3938967115
+ 0.0970626198 -0.2805161775 0.8107067993
+ 0.5138727076 -0.8107067993 0.2805161775
+ 0.9549290665 0.0970626198 -0.2805161775
+ 0.3938967115 0.8107067993 0.4331280021
+-0.2805161775 0.8107067993 -0.0970626198
+-0.9549290665 0.2805161775 -0.0970626198
+-0.5138727076 -0.2805161775 0.8107067993
+ 0.0471596473 -0.9941603570 0.0970626198
+ 0.2805161775 -0.8107067993 0.0970626198
+ 0.5381189786 -0.8415485325 -0.0471596473
+ 0.2805161775 -0.5138727076 0.8107067993
+-0.2805161775 -0.9549290665 -0.0970626198
+ 0.4331280021 -0.3938967115 -0.8107067993
+-0.8415485325 0.3696504405 -0.3938967115
+-0.0970626198 0.2805161775 -0.8107067993
+ 0.0970626198 -0.2805161775 0.8107067993
+ 0.0970626198 -0.0471596473 0.9941603570
+ 0.8107067993 0.5138727076 0.2805161775
+-0.0970626198 0.9549290665 -0.2805161775
+ 0.8107067993 -0.2805161775 0.5138727076
+-0.0970626198 0.2805161775 0.9549290665
+-0.8107067993 -0.4331280021 0.3938967115
+-0.0471596473 -0.5381189786 0.8415485325
+-0.3938967115 0.8415485325 -0.3696504405
+-0.8107067993 0.0970626198 -0.2805161775
+ 0.8107067993 -0.0970626198 0.2805161775
+ 0.8415485325 0.0471596473 0.5381189786
+-0.7215725363 0.5138727076 0.4639697352
+ 0.2805161775 0.9549290665 0.0970626198
+ 0.1605401813 0.3938967115 -0.9050260940
+-0.3696504405 0.3938967115 -0.8415485325
+-0.6907308032 0.0471596473 0.7215725363
+-0.8107067993 -0.5138727076 -0.2805161775
+ 0.2496744444 -0.9549290665 -0.1605401813
+ 0.4639697352 0.7215725363 -0.5138727076
+ 0.0970626198 -0.2805161775 -0.9549290665
+-0.9050260940 -0.1605401813 -0.3938967115
+ 0.2104431538 -0.9050260940 0.3696504405
+-0.5773502692 -0.5773502692 0.2805161775
+ 0.5773502692 0.5773502692 -0.2805161775
+ 0.7215725363 0.6907308032 -0.0471596473
+-0.2805161775 0.8107067993 0.5138727076
+-0.1605401813 -0.2496744444 0.9549290665
+ 0.6907308032 0.4830309745 -0.5381189786
+-0.5138727076 -0.4639697352 -0.7215725363
+-0.9549290665 -0.0970626198 0.2805161775
+-0.3938967115 0.9050260940 0.1605401813
+-0.0471596473 -0.7215725363 -0.6907308032
+ 0.5138727076 0.2805161775 -0.8107067993
+ 0.9549290665 0.1605401813 0.2496744444
+ 0.3696504405 -0.2104431538 0.9050260940
+ 0.2805161775 0.5773502692 0.5773502692
+-0.2805161775 -0.5773502692 -0.5773502692
+-0.5381189786 -0.6907308032 -0.4830309745
+ 0.9050260940 -0.3696504405 0.2104431538
+ 0.5773502692 -0.2805161775 -0.5773502692
+-0.5773502692 0.2805161775 0.5773502692
+-0.0970626198 -0.8107067993 0.5773502692
+-0.4639697352 0.2496744444 0.8499380899
+-0.4830309745 0.5381189786 0.6907308032
+ 0.8499380899 0.4639697352 -0.2496744444
+ 0.5773502692 0.0970626198 0.8107067993
+-0.8499380899 0.2104431538 0.4830309745
+-0.2496744444 -0.8499380899 -0.4639697352
+ 0.8107067993 -0.5773502692 -0.0970626198
+ 0.4830309745 0.8499380899 -0.2104431538
+-0.2104431538 -0.4830309745 -0.8499380899
+-0.5773502692 0.5773502692 -0.5773502692
+3 0 2 1
+5 0 3 14 13 2 3
+3 0 4 3
+5 0 5 20 19 4 2
+3 0 6 5
+3 0 1 6
+3 1 7 6
+5 1 8 22 16 7 3
+3 1 9 8
+5 1 2 10 25 9 2
+3 2 11 10
+3 2 12 11
+3 2 13 12
+3 3 15 14
+5 3 16 35 34 15 2
+3 3 7 16
+3 3 4 7
+3 4 17 7
+5 4 18 36 32 17 3
+3 4 19 18
+3 5 9 20
+3 5 8 9
+3 5 21 8
+5 5 6 12 27 21 3
+3 6 11 12
+5 6 7 17 30 11 2
+3 8 23 22
+5 8 21 39 41 23 2
+5 9 24 42 38 20 3
+3 9 25 24
+3 10 26 25
+3 10 27 26
+3 10 28 27
+5 10 11 29 47 28 3
+3 11 30 29
+3 12 26 27
+5 12 13 31 45 26 2
+3 13 30 31
+3 13 29 30
+3 13 14 29
+5 14 32 50 48 29 2
+3 14 17 32
+3 14 15 17
+3 15 30 17
+5 15 33 49 31 30 3
+3 15 34 33
+3 16 19 35
+3 16 18 19
+3 16 22 18
+3 18 37 36
+5 18 22 38 54 37 2
+5 19 23 40 52 35 3
+3 19 20 23
+3 20 22 23
+3 20 38 22
+3 21 25 39
+3 21 24 25
+3 21 27 24
+3 23 41 40
+3 24 43 42
+5 24 27 28 46 43 2
+5 25 26 44 55 39 3
+3 26 45 44
+3 28 45 46
+3 28 44 45
+3 28 47 44
+3 29 48 47
+3 31 48 45
+3 31 47 48
+3 31 49 47
+3 32 34 50
+3 32 33 34
+3 32 36 33
+3 33 51 49
+5 33 36 52 59 51 2
+5 34 37 53 58 50 3
+3 34 35 37
+3 35 36 37
+3 35 52 36
+3 37 54 53
+3 38 41 54
+3 38 40 41
+3 38 42 40
+3 39 43 41
+3 39 42 43
+3 39 55 42
+3 40 53 52
+5 40 42 55 57 53 2
+5 41 43 56 59 54 3
+3 43 46 56
+3 44 56 55
+5 44 47 49 58 56 2
+5 45 48 51 57 46 3
+3 46 55 56
+3 46 57 55
+3 48 50 51
+3 49 50 58
+3 49 51 50
+3 51 59 57
+3 52 54 59
+3 52 53 54
+3 53 57 58
+3 56 58 59
+3 57 59 58
+6 5 0 1 2 3 4
+6 5 6 7 8 9 0
+6 9 10 11 12 1 0
+6 1 13 14 15 16 2
+6 16 17 18 19 3 2
+6 3 20 21 22 23 4
+6 23 24 25 6 5 4
+6 25 17 16 15 7 6
+6 7 26 27 22 21 8
+6 20 28 29 9 8 21
+6 9 30 31 32 33 10
+6 33 34 25 24 11 10
+6 23 35 36 12 11 24
+6 36 37 38 39 1 12
+6 39 40 41 42 13 1
+6 42 43 44 45 14 13
+6 14 46 47 48 7 15
+6 25 43 42 41 18 17
+6 18 49 50 48 47 19
+6 46 51 52 3 19 47
+6 52 53 54 28 20 3
+6 27 55 56 57 23 22
+6 50 54 53 26 7 48
+6 51 58 27 26 53 52
+6 28 59 60 57 56 29
+6 55 61 30 9 29 56
+6 61 62 36 35 31 30
+6 60 32 31 35 23 57
+6 60 63 64 65 33 32
+6 33 66 40 39 38 34
+6 37 44 43 25 34 38
+6 36 67 68 69 44 37
+6 40 70 71 72 18 41
+6 44 73 74 72 71 45
+6 70 75 76 14 45 71
+6 76 77 78 51 46 14
+6 74 78 77 49 18 72
+6 75 79 50 49 77 76
+6 50 80 81 82 28 54
+6 27 83 84 85 61 55
+6 51 86 87 82 81 58
+6 80 88 83 27 58 81
+6 87 85 84 59 28 82
+6 88 89 60 59 84 83
+6 61 90 91 65 64 62
+6 63 92 67 36 62 64
+6 89 93 94 92 63 60
+6 91 69 68 66 33 65
+6 92 95 40 66 68 67
+6 91 96 97 73 44 69
+6 95 97 96 75 70 40
+6 92 98 74 73 97 95
+6 74 99 100 86 51 78
+6 75 101 87 86 100 79
+6 99 88 80 50 79 100
+6 87 94 93 90 61 85
+6 88 102 91 90 93 89
+6 101 103 98 92 94 87
+6 102 103 101 75 96 91
+6 98 74 99 88 102 103
+great dodecahemicosahedron
+great dodecahemicosacron
+5/4 5|3
+(6.5/4.6.5)
+icosahedral group
+A5
+10{6}+6{5}+6{5/4}
+69 30 60 22 30 0 1 1 -8 3 4 120 5 1 -1
+ 0.0000000000 0.0000000000 1.0000000000
+ 0.8660254038 0.0000000000 0.5000000000
+-0.8660254038 0.0000000000 0.5000000000
+ 0.6454972244 0.5773502692 0.5000000000
+-0.6454972244 -0.5773502692 0.5000000000
+ 0.8660254038 0.0000000000 -0.5000000000
+ 0.1102640897 0.5773502692 0.8090169944
+ 0.7557613141 -0.5773502692 -0.3090169944
+-0.7557613141 0.5773502692 -0.3090169944
+-0.1102640897 -0.5773502692 0.8090169944
+-0.8660254038 -0.0000000000 -0.5000000000
+ 0.6454972244 0.5773502692 -0.5000000000
+ 0.4670861795 -0.3568220898 0.8090169944
+ 0.1784110449 0.9341723590 -0.3090169944
+-0.1784110449 -0.9341723590 -0.3090169944
+-0.4670861795 0.3568220898 0.8090169944
+-0.6454972244 -0.5773502692 -0.5000000000
+ 0.1102640897 0.5773502692 -0.8090169944
+ 0.7557613141 -0.5773502692 0.3090169944
+ 0.0000000000 -0.0000000000 -1.0000000000
+-0.7557613141 0.5773502692 0.3090169944
+-0.3568220898 0.9341723590 -0.0000000000
+ 0.9341723590 0.3568220898 -0.0000000000
+-0.1102640897 -0.5773502692 -0.8090169944
+-0.9341723590 -0.3568220898 -0.0000000000
+ 0.3568220898 -0.9341723590 -0.0000000000
+ 0.4670861795 -0.3568220898 -0.8090169944
+ 0.1784110449 0.9341723590 0.3090169944
+-0.1784110449 -0.9341723590 0.3090169944
+-0.4670861795 0.3568220898 -0.8090169944
+ 0.0000000000 1.0000000000 0.0000000000
+-0.3035309991 0.7946544723 0.5257311121
+-0.6666666667 0.7453559925 -0.0000000000
+ 0.3035309991 -0.7946544723 0.5257311121
+ 0.3333333333 0.7453559925 -0.5773502692
+ 0.6070619982 0.7946544723 0.0000000000
+-0.6070619982 -0.7946544723 0.0000000000
+ 0.3333333333 0.7453559925 0.5773502692
+-0.7453559925 0.3333333333 0.5773502692
+ 0.9822469464 -0.1875924741 0.0000000000
+-0.9822469464 0.1875924741 -0.0000000000
+-0.7453559925 0.3333333333 -0.5773502692
+ 0.3035309991 -0.7946544723 -0.5257311121
+-0.4911234732 -0.1875924741 0.8506508084
+ 0.8726779962 0.3333333333 -0.3568220898
+-0.1273220038 0.3333333333 -0.9341723590
+ 0.4911234732 0.1875924741 -0.8506508084
+-0.4911234732 -0.1875924741 -0.8506508084
+-0.1273220038 0.3333333333 0.9341723590
+ 0.8726779962 0.3333333333 0.3568220898
+ 0.4911234732 0.1875924741 0.8506508084
+-0.3035309991 0.7946544723 -0.5257311121
+6 0 1 5 19 10 2
+5 0 2 8 13 3 4
+6 0 3 11 19 16 4
+5 0 1 7 14 4
+6 1 7 23 10 20 6
+5 1 6 21 17 5 4
+5 2 10 23 25 9
+6 2 9 18 5 17 8
+6 3 13 29 16 28 12
+5 3 12 25 26 11
+5 4 16 29 21 15 4
+6 4 15 27 11 26 14
+5 5 18 28 16 19
+5 6 20 24 28 12
+6 6 12 25 23 29 21
+6 7 14 24 20 27 22
+5 7 22 13 29 23 4
+5 8 17 26 14 24
+6 8 24 28 18 22 13
+6 9 25 26 17 21 15
+5 9 15 27 22 18 4
+5 10 19 11 27 20 4
+4 3 0 1 2
+4 3 4 5 0
+4 6 0 1 7
+4 1 8 9 2
+4 10 2 3 11
+4 5 7 12 0
+4 13 4 5 14
+4 3 15 16 4
+4 17 7 1 18
+4 6 19 20 7
+4 21 0 6 4
+4 9 11 21 2
+4 13 8 9 14
+4 16 18 1 8
+4 17 11 3 15
+4 10 19 20 11
+4 12 2 10 8
+4 5 19 17 7
+4 20 18 12 7
+4 12 0 21 2
+4 21 15 13 4
+4 10 14 5 19
+4 20 15 16 18
+4 16 14 6 4
+4 13 18 17 15
+4 9 19 6 14
+4 9 11 17 19
+4 21 11 20 15
+4 13 8 12 18
+4 16 8 10 14
+great stellated truncated dodecahedron
+great triakisicosahedron
+2 3|5/3
+(10/3.10/3.3)
+icosahedral group
+A5
+12{10/3}+20{3}
+70 60 90 32 60 13 0 0 2 2 3 120 5 0 -1
+ 0.0000000000 0.0000000000 1.0000000000
+ 0.9876921901 0.0000000000 -0.1564101584
+-0.6303417987 0.7603979742 -0.1564101584
+-0.1831282032 -0.9705668053 -0.1564101584
+-0.2530769525 0.7603979742 -0.5981195340
+-0.4238973457 -0.6801206241 -0.5981195340
+ 0.7469230475 0.2904461812 -0.5981195340
+-0.7002905480 0.3896744429 -0.5981195340
+-0.6570598434 -0.6801206241 -0.3251281267
+-0.4739316403 0.2904461812 0.8312820317
+ 0.0788547642 -0.5502291431 0.8312820317
+ 0.5260683597 -0.1795056119 0.8312820317
+-0.1975384380 0.5195659239 0.8312820317
+ 0.7901537521 0.5195659239 -0.3251281267
+ 0.8333844566 -0.5502291431 -0.0521367195
+ 0.9033332059 -0.1795056119 0.3895726561
+-0.4383075806 0.8100121051 0.3895726561
+ 0.9389572656 0.3400603121 -0.0521367195
+-0.5082563299 -0.8596262360 -0.0521367195
+-0.7147007828 0.5808923624 0.3895726561
+ 0.0089060149 -0.9209526744 0.3895726561
+ 0.3861708611 -0.9209526744 -0.0521367195
+ 0.3162221118 0.8100121051 -0.4938460950
+ 0.0953674240 0.3400603121 0.9355554706
+-0.1309914837 -0.8596262360 -0.4938460950
+ 0.2729914073 0.5808923624 -0.7668375023
+-0.6214357837 -0.1605547002 -0.7668375023
+-0.0953674240 -0.3400603121 -0.9355554706
+ 0.3518461715 0.0306632192 -0.9355554706
+ 0.8690085163 -0.0306632192 -0.4938460950
+-0.3518461715 -0.0306632192 0.9355554706
+-0.8545982815 -0.1605547002 -0.4938460950
+-0.9389572656 -0.3400603121 0.0521367195
+-0.8690085163 0.0306632192 0.4938460950
+-0.8333844566 0.5502291431 0.0521367195
+-0.3162221118 -0.8100121051 0.4938460950
+ 0.8545982815 0.1605547002 0.4938460950
+-0.3861708611 0.9209526744 0.0521367195
+ 0.1309914837 0.8596262360 0.4938460950
+ 0.5082563299 0.8596262360 0.0521367195
+-0.0788547642 0.5502291431 -0.8312820317
+ 0.4383075806 -0.8100121051 -0.3895726561
+ 0.6214357837 0.1605547002 0.7668375023
+-0.0089060149 0.9209526744 -0.3895726561
+ 0.6570598434 0.6801206241 0.3251281267
+-0.7901537521 -0.5195659239 0.3251281267
+-0.9033332059 0.1795056119 -0.3895726561
+-0.2729914073 -0.5808923624 0.7668375023
+ 0.7147007828 -0.5808923624 -0.3895726561
+-0.5260683597 0.1795056119 -0.8312820317
+ 0.4238973457 0.6801206241 0.5981195340
+ 0.1975384380 -0.5195659239 -0.8312820317
+ 0.4739316403 -0.2904461812 -0.8312820317
+ 0.2530769525 -0.7603979742 0.5981195340
+ 0.7002905480 -0.3896744429 0.5981195340
+-0.7469230475 -0.2904461812 0.5981195340
+ 0.6303417987 -0.7603979742 0.1564101584
+-0.9876921901 -0.0000000000 0.1564101584
+ 0.1831282032 0.9705668053 0.1564101584
+-0.0000000000 0.0000000000 -1.0000000000
+ 0.3997648726 0.8506508084 0.3414399638
+-0.9100220386 -0.2351141009 0.3414399638
+ 0.3997648726 -0.4822469333 0.3414399638
+ 0.1949008944 -0.2351141009 -0.9522263391
+-0.1526965938 0.1842019375 -0.6720927788
+-0.6877040871 0.1842019375 -0.0456950952
+ 0.6307125431 -0.7608452130 -0.1526965938
+-0.0535007493 0.7099330497 -0.0456950952
+-0.0521673844 -0.7608452130 0.6468331514
+ 0.2879392144 0.2980449957 0.5807025884
+-0.3462641233 -0.2276861164 0.5807025884
+ 0.7573254447 -0.0898055953 0.6468331514
+ 0.6185920295 0.2980449957 0.1935675295
+ 0.5193961850 -0.2276861164 -0.4328301541
+ 0.0521673844 0.7608452130 -0.6468331514
+-0.7573254447 0.0898055953 -0.6468331514
+ 0.1274369665 -0.5526058126 -0.4328301541
+-0.4075705268 -0.5526058126 0.1935675295
+-0.6307125431 0.7608452130 0.1526965938
+-0.6185920295 -0.2980449957 -0.1935675295
+ 0.4075705268 0.5526058126 -0.1935675295
+-0.2879392144 -0.2980449957 -0.5807025884
+-0.1274369665 0.5526058126 0.4328301541
+-0.1949008944 0.2351141009 0.9522263391
+-0.5193961850 0.2276861164 0.4328301541
+ 0.3462641233 0.2276861164 -0.5807025884
+ 0.9100220386 0.2351141009 -0.3414399638
+ 0.6877040871 -0.1842019375 0.0456950952
+ 0.0535007493 -0.7099330497 0.0456950952
+-0.3997648726 -0.8506508084 -0.3414399638
+ 0.1526965938 -0.1842019375 0.6720927788
+-0.3997648726 0.4822469333 -0.3414399638
+10 0 2 6 11 19 25 15 9 4 1 3
+10 0 3 7 12 20 26 16 10 5 2 3
+3 0 1 3
+10 1 4 8 14 22 31 21 13 7 3 3
+3 2 5 6
+3 4 9 8
+10 5 10 17 27 35 36 28 18 11 6 3
+3 7 13 12
+10 8 9 15 24 33 42 41 32 23 14 3
+3 10 16 17
+3 11 18 19
+10 12 13 21 30 39 48 47 38 29 20 3
+3 14 23 22
+3 15 25 24
+10 16 26 29 38 46 52 44 34 27 17 3
+10 18 28 37 45 51 43 33 24 25 19 3
+3 20 29 26
+3 21 31 30
+10 22 23 32 40 50 55 49 39 30 31 3
+3 27 34 35
+3 28 36 37
+3 32 41 40
+3 33 43 42
+10 34 44 53 57 58 54 45 37 36 35 3
+3 38 47 46
+3 39 49 48
+10 40 41 42 43 51 54 58 59 56 50 3
+3 44 52 53
+3 45 54 51
+10 46 47 48 49 55 56 59 57 53 52 3
+3 50 56 55
+3 57 59 58
+3 2 0 1
+3 2 3 0
+3 0 4 1
+3 1 3 2
+3 3 5 0
+3 4 6 1
+3 0 6 4
+3 1 7 3
+3 3 8 5
+3 8 0 5
+3 6 9 1
+3 0 10 6
+3 1 11 7
+3 11 3 7
+3 3 12 8
+3 8 13 0
+3 9 14 1
+3 6 14 9
+3 10 15 6
+3 0 15 10
+3 1 16 11
+3 11 17 3
+3 3 18 12
+3 18 8 12
+3 8 15 13
+3 13 0 15
+3 14 16 1
+3 6 19 14
+3 15 20 6
+3 14 11 16
+3 11 18 17
+3 17 3 18
+3 18 21 8
+3 8 22 15
+3 19 23 14
+3 6 23 19
+3 20 23 6
+3 15 23 20
+3 14 24 11
+3 11 25 18
+3 18 26 21
+3 26 8 21
+3 26 22 8
+3 26 15 22
+3 23 27 14
+3 15 28 23
+3 14 29 24
+3 29 11 24
+3 29 25 11
+3 29 18 25
+3 18 30 26
+3 26 28 15
+3 27 29 14
+3 23 29 27
+3 26 23 28
+3 29 30 18
+3 29 26 30
+3 23 31 29
+3 26 31 23
+3 29 26 31
+great rhombicosidodecahedron
+great deltoidal hexecontahedron
+5/3 3|2
+(4.5/3.4.3)
+icosahedral group
+A5
+30{4}+20{3}+12{5/3}
+71 60 120 62 60 13 0 0 2 3 4 120 5 0 -1
+ 0.0000000000 0.0000000000 1.0000000000
+ 0.9996324920 0.0000000000 0.0271086873
+-0.9468654869 0.3204853643 0.0271086873
+-0.3453645319 0.9380770007 0.0271086873
+ 0.0263835025 -0.9992842588 0.0271086873
+ 0.0527670051 0.3204853643 -0.9457826254
+ 0.0364611038 0.9380770007 -0.3445027268
+ 0.2398305218 0.7400061526 0.6283885859
+-0.3352869307 -0.8768697425 -0.3445027268
+-0.3189810294 -0.0612072581 -0.9457826254
+ 0.8677149793 0.3583135302 -0.3445027268
+-0.7334184677 -0.2592781062 0.6283885859
+-0.9367878857 -0.0612072581 -0.3445027268
+ 0.6216561575 0.7400061526 0.2567771718
+-0.3678987333 0.3583135302 0.8580570704
+ 0.6480396600 -0.2592781062 -0.7161141409
+ 0.8514090780 -0.4573489542 0.2567771718
+ 0.5060445461 0.4807280465 -0.7161141409
+ 0.2336022217 -0.4573489542 0.8580570704
+-0.7233408665 -0.6409707286 0.2567771718
+ 0.4796610435 -0.8390415766 0.2567771718
+ 0.4633551422 -0.2214499403 0.8580570704
+-0.4672044434 -0.5185562123 -0.7161141409
+ 0.2762916255 -0.6409707286 -0.7161141409
+-0.7295691665 0.4807280465 0.4864456563
+ 0.2436798229 -0.8390415766 0.4864456563
+ 0.8451807779 -0.2214499403 0.4864456563
+-0.7031856640 -0.5185562123 -0.4864456563
+-0.4998162460 -0.7166270604 0.4864456563
+-0.8451807779 0.2214499403 -0.4864456563
+ 0.4998162460 -0.7166270604 -0.4864456563
+-0.4998162460 0.7166270604 0.4864456563
+ 0.7031856640 0.5185562123 0.4864456563
+ 0.7295691665 -0.4807280465 -0.4864456563
+-0.2436798229 0.8390415766 -0.4864456563
+ 0.4998162460 0.7166270604 -0.4864456563
+-0.4633551422 0.2214499403 -0.8580570704
+ 0.4672044434 0.5185562123 0.7161141409
+-0.5060445461 -0.4807280465 0.7161141409
+-0.4796610435 0.8390415766 -0.2567771718
+-0.2762916255 0.6409707286 0.7161141409
+ 0.3678987333 -0.3583135302 -0.8580570704
+ 0.7233408665 0.6409707286 -0.2567771718
+-0.2336022217 0.4573489542 -0.8580570704
+-0.6480396600 0.2592781062 0.7161141409
+-0.6216561575 -0.7400061526 -0.2567771718
+-0.8514090780 0.4573489542 -0.2567771718
+-0.8677149793 -0.3583135302 0.3445027268
+ 0.7334184677 0.2592781062 -0.6283885859
+-0.2398305218 -0.7400061526 -0.6283885859
+ 0.9367878857 0.0612072581 0.3445027268
+-0.0364611038 -0.9380770007 0.3445027268
+ 0.3189810294 0.0612072581 0.9457826254
+ 0.3352869307 0.8768697425 0.3445027268
+-0.0527670051 -0.3204853643 0.9457826254
+ 0.3453645319 -0.9380770007 -0.0271086873
+ 0.9468654869 -0.3204853643 -0.0271086873
+-0.0263835025 0.9992842588 -0.0271086873
+-0.9996324920 -0.0000000000 -0.0271086873
+ 0.0000000000 -0.0000000000 -1.0000000000
+ 0.1602426822 0.9732489895 0.1646471601
+-0.1272308741 0.1239160115 0.1646471601
+-0.9686806297 -0.1858740172 0.1646471601
+ 0.1602426822 -0.1560677326 0.1646471601
+ 0.1908463112 -0.1858740172 -0.9638612635
+ 0.1680357129 0.1239160115 -0.1227207474
+-0.1920048196 -0.0368425940 -0.1972823210
+-0.2898817352 -0.4156269378 0.8621037224
+ 0.4078312422 0.3007504775 0.8621037224
+ 0.0317621374 0.1929103266 -0.1972823210
+-0.1194378434 -0.1712477161 -0.1227207474
+ 0.8696452057 -0.4156269378 -0.2664047011
+-0.1980708480 0.1929103266 0.0264023998
+ 0.8507311228 0.3007504775 0.4310518612
+ 0.2494630659 0.1192251386 0.0264023998
+-0.6904884406 0.6724985120 -0.2664047011
+ 0.0534142274 -0.2297529205 0.0548823867
+ 0.4384348713 -0.8583725292 -0.2664047011
+ 0.2310826560 -0.0473317046 0.0548823867
+-0.1125994760 -0.2525228959 0.0264023998
+-0.2781921891 -0.8583725292 0.4310518612
+-0.2475885600 0.6724985120 -0.6974565623
+ 0.0196300805 0.1192251386 0.2500871207
+ 0.0485978695 -0.0473317046 0.2324855208
+ 0.0294451207 -0.2525228959 -0.1118423604
+ 0.0189140829 -0.7163774153 -0.6974565623
+-0.0485978695 0.0473317046 -0.2324855208
+-0.6977129774 -0.7163774153 0.0000000000
+-0.1186655045 -0.0227699753 0.2500871207
+-0.6787988945 0.2297529205 -0.6974565623
+ 0.7166270604 0.0000000000 -0.6974565623
+ 0.6977129774 0.7163774153 0.0000000000
+ 0.2532120777 -0.0227699753 -0.1118423604
+-0.2310826560 0.0473317046 -0.0548823867
+-0.7166270604 -0.0000000000 0.6974565623
+-0.0189140829 0.7163774153 0.6974565623
+ 0.6787988945 -0.2297529205 0.6974565623
+-0.2532120777 0.0227699753 0.1118423604
+ 0.2781921891 0.8583725292 -0.4310518612
+ 0.1186655045 0.0227699753 -0.2500871207
+-0.0534142274 0.2297529205 -0.0548823867
+-0.0294451207 0.2525228959 0.1118423604
+ 0.2475885600 -0.6724985120 0.6974565623
+-0.0196300805 -0.1192251386 -0.2500871207
+-0.8507311228 -0.3007504775 -0.4310518612
+-0.4384348713 0.8583725292 0.2664047011
+ 0.6904884406 -0.6724985120 0.2664047011
+ 0.1125994760 0.2525228959 -0.0264023998
+-0.2494630659 -0.1192251386 -0.0264023998
+-0.4078312422 -0.3007504775 -0.8621037224
+ 0.1194378434 0.1712477161 0.1227207474
+ 0.1980708480 -0.1929103266 -0.0264023998
+-0.8696452057 0.4156269378 0.2664047011
+-0.1680357129 -0.1239160115 0.1227207474
+ 0.2898817352 0.4156269378 -0.8621037224
+-0.0317621374 -0.1929103266 0.1972823210
+ 0.1272308741 -0.1239160115 -0.1646471601
+-0.1908463112 0.1858740172 0.9638612635
+ 0.9686806297 0.1858740172 -0.1646471601
+ 0.1920048196 0.0368425940 0.1972823210
+-0.1602426822 -0.9732489895 -0.1646471601
+-0.1602426822 0.1560677326 -0.1646471601
+4 0 2 5 1
+5 0 3 11 7 2 3
+4 0 4 9 3
+3 0 1 4
+4 1 6 12 4
+5 1 5 13 15 6 3
+3 2 8 5
+4 2 7 16 8
+4 3 10 20 11
+3 3 9 10
+5 4 12 23 19 9 3
+4 5 8 18 13
+3 6 14 12
+4 6 15 25 14
+3 7 17 16
+4 7 11 22 17
+5 8 16 28 30 18 3
+4 9 19 21 10
+5 10 21 33 32 20 3
+3 11 20 22
+4 12 14 26 23
+4 13 24 27 15
+3 13 18 24
+5 14 25 37 38 26 3
+3 15 27 25
+4 16 17 29 28
+5 17 22 34 41 29 3
+4 18 30 36 24
+3 19 31 21
+4 19 23 35 31
+4 20 32 34 22
+4 21 31 43 33
+3 23 26 35
+5 24 36 47 39 27 3
+4 25 27 39 37
+4 26 38 46 35
+4 28 40 42 30
+3 28 29 40
+4 29 41 50 40
+3 30 42 36
+5 31 35 46 53 43 3
+3 32 44 34
+4 32 33 45 44
+3 33 43 45
+4 34 44 51 41
+4 36 42 52 47
+4 37 48 49 38
+3 37 39 48
+3 38 49 46
+4 39 47 55 48
+5 40 50 57 52 42 3
+3 41 51 50
+4 43 53 54 45
+5 44 45 54 58 51 3
+4 46 49 56 53
+3 47 52 55
+5 48 55 59 56 49 3
+4 50 51 58 57
+4 52 57 59 55
+3 53 56 54
+4 54 56 59 58
+3 57 58 59
+4 3 0 1 2
+4 3 4 5 0
+4 0 6 7 1
+4 1 8 9 2
+4 2 10 4 3
+4 5 11 6 0
+4 4 12 13 5
+4 7 14 15 1
+4 11 16 7 6
+4 9 17 10 2
+4 8 18 17 9
+4 15 19 8 1
+4 10 20 12 4
+4 5 21 22 11
+4 20 23 13 12
+4 13 24 21 5
+4 16 25 14 7
+4 25 26 15 14
+4 22 27 16 11
+4 17 28 29 10
+4 19 30 18 8
+4 18 31 28 17
+4 26 30 19 15
+4 29 32 20 10
+4 21 33 27 22
+4 23 34 24 13
+4 32 35 23 20
+4 34 33 21 24
+4 16 36 37 25
+4 37 38 26 25
+4 27 39 36 16
+4 31 40 29 28
+4 30 41 42 18
+4 42 43 31 18
+4 26 44 41 30
+4 40 35 32 29
+4 33 45 39 27
+4 23 46 47 34
+4 35 48 46 23
+4 47 49 33 34
+4 36 50 38 37
+4 38 51 44 26
+4 45 50 36 39
+4 43 52 40 31
+4 44 53 42 41
+4 53 52 43 42
+4 40 54 48 35
+4 49 55 45 33
+4 46 56 49 47
+4 54 56 46 48
+4 50 57 51 38
+4 57 53 44 51
+4 55 58 50 45
+4 52 59 54 40
+4 53 60 59 52
+4 56 58 55 49
+4 60 56 54 59
+4 58 61 57 50
+4 61 60 53 57
+4 56 58 61 60
+great truncated icosidodecahedron
+great disdyakistriacontahedron
+5/3 2 3|
+(10/3.4.6)
+icosahedral group
+A5
+20{6}+30{4}+12{10/3}
+72 120 180 62 120 13 0 0 2 3 3 120 5 0 -1
+ 0.0000000000 0.0000000000 1.0000000000
+ 0.8541299615 0.0000000000 0.5200596205
+ 0.0775955677 0.8505979773 0.5200596205
+-0.8315867367 -0.1949397099 0.5200596205
+ 0.4038441822 0.8505979773 0.3367387081
+ 0.8766731863 -0.1949397099 -0.4398211385
+-0.7539911690 0.6556582674 0.0401192410
+ 0.8837688310 0.3248995166 0.3367387081
+-0.8090435119 -0.3898794199 -0.4398211385
+ 0.4263874070 0.6556582674 -0.6231420509
+-0.1719938631 0.3248995166 0.9299776423
+ 0.0450864496 -0.3898794199 -0.9197615180
+-0.7794046424 -0.0649799033 -0.6231420509
+ 0.3079307858 -0.2007989442 0.9299776423
+ 0.8583553576 -0.3957386541 -0.3265225838
+-0.7453804233 0.5811979239 -0.3265225838
+-0.1269074134 -0.0649799033 -0.9897838757
+ 0.6341794002 -0.2007989442 0.7466567299
+-0.7252886834 -0.3957386541 0.5633358175
+ 0.1087495382 0.5811979239 -0.8064629633
+-0.8412938197 -0.4701989976 0.2667163504
+ 0.0267686209 -0.5906783641 -0.8064629633
+ 0.2825173124 -0.9214371149 0.2667163504
+-0.1423549936 0.6497990331 0.7466567299
+-0.8072696007 0.1759788297 0.5633358175
+ 0.6653333707 -0.4701989976 -0.5798658539
+-0.7027454586 -0.5906783641 -0.3965449415
+ 0.0808845798 -0.9214371149 0.3800149051
+ 0.7117749679 0.6497990331 0.2667163504
+ 0.9009903223 0.1759788297 -0.3965449415
+-0.0351205564 -0.9958974583 0.0833954380
+-0.7776307312 0.5008783463 0.3800149051
+-0.1931819403 -0.7914773082 -0.5798658539
+-0.6180542463 0.7797588398 -0.0999254744
+-0.8326830741 -0.5446593410 -0.0999254744
+-0.0150288165 -0.2292402645 0.9732538393
+ 0.0894953255 -0.9958974583 0.0133730803
+ 0.7289964592 0.5008783463 -0.4665672992
+-0.3948146729 -0.7914773082 -0.4665672992
+ 0.2360757152 0.7797588398 -0.5798658539
+ 0.3476955019 -0.5446593410 -0.7631867663
+ 0.8391011449 -0.2292402645 0.4933134598
+ 0.8347157954 -0.5505185752 0.0133730803
+-0.7550875064 0.3059386363 -0.5798658539
+ 0.0922056206 0.9462572293 0.3099925474
+ 0.6766544115 -0.3460984252 -0.6498882116
+-0.6434677197 0.0591206691 -0.7631867663
+-0.0404422899 -0.9498784352 0.3099925474
+-0.4226796312 -0.5505185752 0.7199105693
+-0.1025902774 0.3059386363 -0.9465076787
+ 0.2168215026 0.9462572293 0.2399701898
+-0.9069896296 -0.3460984252 0.2399701898
+-0.3172191052 0.0591206691 -0.9465076787
+ 0.2858063246 -0.9498784352 0.1266716350
+ 0.3590165427 -0.4205587686 -0.8332091240
+ 0.8983788839 0.4205587686 0.1266716350
+ 0.1147488454 0.7513175194 -0.6498882116
+ 0.2263686321 0.5044995522 -0.8332091240
+ 0.6147652341 -0.7513175194 0.2399701898
+ 0.8293940619 -0.5044995522 0.2399701898
+-0.8983788839 -0.4205587686 -0.1266716350
+-0.3590165427 0.4205587686 0.8332091240
+-0.6147652341 0.7513175194 -0.2399701898
+-0.8293940619 0.5044995522 -0.2399701898
+-0.1147488454 -0.7513175194 0.6498882116
+-0.2263686321 -0.5044995522 0.8332091240
+ 0.4226796312 0.5505185752 -0.7199105693
+-0.2168215026 -0.9462572293 -0.2399701898
+ 0.9069896296 0.3460984252 -0.2399701898
+-0.2858063246 0.9498784352 -0.1266716350
+ 0.1025902774 -0.3059386363 0.9465076787
+ 0.3172191052 -0.0591206691 0.9465076787
+-0.8347157954 0.5505185752 -0.0133730803
+-0.0922056206 -0.9462572293 -0.3099925474
+-0.6766544115 0.3460984252 0.6498882116
+ 0.0404422899 0.9498784352 -0.3099925474
+ 0.7550875064 -0.3059386363 0.5798658539
+ 0.6434677197 -0.0591206691 0.7631867663
+-0.0894953255 0.9958974583 -0.0133730803
+-0.7289964592 -0.5008783463 0.4665672992
+ 0.3948146729 0.7914773082 0.4665672992
+-0.8391011449 0.2292402645 -0.4933134598
+-0.3476955019 0.5446593410 0.7631867663
+-0.2360757152 -0.7797588398 0.5798658539
+ 0.0351205564 0.9958974583 -0.0833954380
+ 0.7776307312 -0.5008783463 -0.3800149051
+ 0.1931819403 0.7914773082 0.5798658539
+ 0.0150288165 0.2292402645 -0.9732538393
+ 0.8326830741 0.5446593410 0.0999254744
+ 0.6180542463 -0.7797588398 0.0999254744
+ 0.7027454586 0.5906783641 0.3965449415
+-0.6653333707 0.4701989976 0.5798658539
+-0.0808845798 0.9214371149 -0.3800149051
+-0.9009903223 -0.1759788297 0.3965449415
+-0.7117749679 -0.6497990331 -0.2667163504
+-0.0267686209 0.5906783641 0.8064629633
+ 0.8412938197 0.4701989976 -0.2667163504
+-0.2825173124 0.9214371149 -0.2667163504
+ 0.8072696007 -0.1759788297 -0.5633358175
+ 0.1423549936 -0.6497990331 -0.7466567299
+ 0.1269074134 0.0649799033 0.9897838757
+ 0.7252886834 0.3957386541 -0.5633358175
+-0.6341794002 0.2007989442 -0.7466567299
+-0.1087495382 -0.5811979239 0.8064629633
+ 0.7794046424 0.0649799033 0.6231420509
+-0.8583553576 0.3957386541 0.3265225838
+-0.3079307858 0.2007989442 -0.9299776423
+ 0.7453804233 -0.5811979239 0.3265225838
+-0.4263874070 -0.6556582674 0.6231420509
+ 0.1719938631 -0.3248995166 -0.9299776423
+-0.0450864496 0.3898794199 0.9197615180
+ 0.7539911690 -0.6556582674 -0.0401192410
+-0.8837688310 -0.3248995166 -0.3367387081
+ 0.8090435119 0.3898794199 0.4398211385
+-0.8766731863 0.1949397099 0.4398211385
+-0.4038441822 -0.8505979773 -0.3367387081
+ 0.8315867367 0.1949397099 -0.5200596205
+-0.0775955677 -0.8505979773 -0.5200596205
+-0.8541299615 0.0000000000 -0.5200596205
+-0.0000000000 0.0000000000 -1.0000000000
+ 0.1125484940 0.1027486297 0.2002978807
+-0.1451976151 0.1262614479 0.2002978807
+ 0.1125484940 -0.9732489895 0.2002978807
+ 0.2465918377 0.1262614479 -0.0198507936
+ 0.2605224485 0.6488326596 -0.7149435178
+-0.2508908076 0.0175515613 -0.0094567831
+-0.7461418850 0.6488326596 -0.1492932256
+ 0.1224008564 0.0175515613 -0.2192114469
+ 0.2245940980 -0.1148764603 0.1162085697
+-0.1348570368 0.0368425940 -0.2399994678
+-0.0175451002 -0.1148764603 0.2522679329
+-0.1568547765 -0.2042953142 -0.1039401045
+-0.8375948183 -0.3536689320 0.4163570665
+ 0.1014417091 -0.2122013592 -0.0895759354
+ 0.2339533531 0.8785855802 0.4163570665
+-0.0072045220 -0.2042953142 -0.1880294155
+ 0.7912222885 -0.3536689320 -0.4988843319
+-0.1292652270 -0.2122013592 0.0400595761
+ 0.1425004198 -0.1239160115 0.9820073587
+ 0.0180479902 0.2752928712 0.0321192587
+-0.1632456053 -0.1490314232 0.1681786220
+ 0.7646531932 -0.1239160115 0.6324162524
+ 0.2285438474 -0.1490314232 -0.0519700523
+-0.1276525148 0.2411379082 -0.0519700523
+ 0.0063908288 -0.0552638910 -0.2721187265
+-0.0953526143 0.1595466752 -0.1696950876
+ 0.1854901192 -0.4956640459 -0.8484754382
+ 0.0953526143 -0.1595466752 0.1696950876
+ 0.0219977397 0.2411379082 -0.1360593633
+-0.2357483694 -0.0552638910 -0.1360593633
+-0.8211742143 -0.4956640459 -0.2828251461
+ 0.2421391982 0.0000000000 -0.1360593633
+ 0.1292652270 0.2122013592 -0.0400595761
+ 0.8211742143 0.4956640459 0.2828251461
+-0.2421391982 0.0000000000 0.1360593633
+-0.1014417091 0.2122013592 0.0895759354
+-0.1854901192 0.4956640459 0.8484754382
+-0.7646531932 0.1239160115 -0.6324162524
+-0.0219977397 -0.2411379082 0.1360593633
+ 0.2357483694 0.0552638910 0.1360593633
+-0.1425004198 0.1239160115 -0.9820073587
+ 0.1276525148 -0.2411379082 0.0519700523
+-0.0063908288 0.0552638910 0.2721187265
+-0.2285438474 0.1490314232 0.0519700523
+-0.1224008564 -0.0175515613 0.2192114469
+-0.7912222885 0.3536689320 0.4988843319
+ 0.1632456053 0.1490314232 -0.1681786220
+ 0.2508908076 -0.0175515613 0.0094567831
+ 0.8375948183 0.3536689320 -0.4163570665
+ 0.0072045220 0.2042953142 0.1880294155
+-0.2339533531 -0.8785855802 -0.4163570665
+-0.0180479902 -0.2752928712 -0.0321192587
+ 0.1568547765 0.2042953142 0.1039401045
+ 0.7461418850 -0.6488326596 0.1492932256
+ 0.0175451002 0.1148764603 -0.2522679329
+-0.1125484940 -0.1027486297 -0.2002978807
+-0.2605224485 -0.6488326596 0.7149435178
+-0.2245940980 0.1148764603 -0.1162085697
+ 0.1348570368 -0.0368425940 0.2399994678
+-0.2465918377 -0.1262614479 0.0198507936
+-0.1125484940 0.9732489895 -0.2002978807
+ 0.1451976151 -0.1262614479 -0.2002978807
+10 0 2 7 13 23 28 17 10 4 1 3
+4 0 3 6 2
+6 0 1 5 11 8 3
+4 1 4 9 5
+6 2 6 12 21 14 7
+10 3 8 15 24 34 43 31 20 12 6 3
+6 4 10 18 26 16 9
+10 5 9 16 25 37 49 40 29 19 11 3
+4 7 14 22 13
+4 8 11 19 15
+4 10 17 27 18
+4 12 20 30 21
+6 13 22 32 46 33 23
+10 14 21 30 42 54 67 58 45 32 22 3
+6 15 19 29 41 35 24
+4 16 26 36 25
+6 17 28 39 52 38 27
+10 18 27 38 51 64 73 60 48 36 26 3
+6 20 31 44 55 42 30
+4 23 33 39 28
+4 24 35 47 34
+6 25 36 48 61 50 37
+4 29 40 53 41
+4 31 43 56 44
+4 32 45 57 46
+10 33 46 57 69 81 87 75 63 52 39 3
+6 34 47 59 68 56 43
+10 35 41 53 65 77 89 83 71 59 47 3
+4 37 50 62 49
+4 38 52 63 51
+6 40 49 62 74 65 53
+4 42 55 66 54
+10 44 56 68 80 92 101 90 78 66 55 3
+6 45 58 70 82 69 57
+4 48 60 72 61
+10 50 61 72 84 95 105 97 86 74 62 3
+6 51 63 75 88 76 64
+6 54 66 78 91 79 67
+4 58 67 79 70
+4 59 71 80 68
+6 60 73 85 96 84 72
+4 64 76 85 73
+4 65 74 86 77
+4 69 82 93 81
+10 70 79 91 100 108 114 110 103 93 82 3
+6 71 83 94 102 92 80
+4 75 87 98 88
+10 76 88 98 107 113 116 111 104 96 85 3
+6 77 86 97 106 99 89
+4 78 90 100 91
+6 81 93 103 107 98 87
+4 83 89 99 94
+4 84 96 104 95
+6 90 101 109 115 108 100
+4 92 102 109 101
+10 94 99 106 112 117 119 118 115 109 102 3
+6 95 104 111 117 112 105
+4 97 105 112 106
+4 103 110 113 107
+4 108 115 118 114
+6 110 114 118 119 116 113
+4 111 116 119 117
+3 2 0 1
+3 2 3 0
+3 0 4 1
+3 1 5 2
+3 3 6 0
+3 2 7 3
+3 4 5 1
+3 0 8 4
+3 5 9 2
+3 7 6 3
+3 6 10 0
+3 9 7 2
+3 4 11 5
+3 0 12 8
+3 8 13 4
+3 5 14 9
+3 7 15 6
+3 10 16 0
+3 6 17 10
+3 14 7 9
+3 11 18 5
+3 13 11 4
+3 12 13 8
+3 0 19 12
+3 5 20 14
+3 7 21 15
+3 15 17 6
+3 17 16 10
+3 16 19 0
+3 14 22 7
+3 13 18 11
+3 18 23 5
+3 12 24 13
+3 19 25 12
+3 5 26 20
+3 20 27 14
+3 21 17 15
+3 7 28 21
+3 17 29 16
+3 16 25 19
+3 22 30 7
+3 27 22 14
+3 13 31 18
+3 23 26 5
+3 18 32 23
+3 24 33 13
+3 25 24 12
+3 26 27 20
+3 21 34 17
+3 30 28 7
+3 28 35 21
+3 17 36 29
+3 29 25 16
+3 27 30 22
+3 13 37 31
+3 31 32 18
+3 32 26 23
+3 25 33 24
+3 33 38 13
+3 26 39 27
+3 34 40 17
+3 35 34 21
+3 30 35 28
+3 36 25 29
+3 17 41 36
+3 27 42 30
+3 37 32 31
+3 38 37 13
+3 32 39 26
+3 25 43 33
+3 33 44 38
+3 39 45 27
+3 35 40 34
+3 40 41 17
+3 42 35 30
+3 36 46 25
+3 41 47 36
+3 27 48 42
+3 37 49 32
+3 44 37 38
+3 32 45 39
+3 25 50 43
+3 43 44 33
+3 45 51 27
+3 35 52 40
+3 40 47 41
+3 48 35 42
+3 46 50 25
+3 47 46 36
+3 51 48 27
+3 49 53 32
+3 44 49 37
+3 32 54 45
+3 50 44 43
+3 45 55 51
+3 35 56 52
+3 52 47 40
+3 48 57 35
+3 47 50 46
+3 55 48 51
+3 44 53 49
+3 53 54 32
+3 54 55 45
+3 50 58 44
+3 56 47 52
+3 57 56 35
+3 55 57 48
+3 47 58 50
+3 44 59 53
+3 53 55 54
+3 58 60 44
+3 56 61 47
+3 55 56 57
+3 47 60 58
+3 60 59 44
+3 59 55 53
+3 61 60 47
+3 55 61 56
+3 60 55 59
+3 61 60 55
+great inverted snub icosidodecahedron
+great inverted pentagonal hexecontahedron
+|5/3 2 3
+(3.5/3.3.3.3)
+icosahedral group
+A5
+80{3}+12{5/3}
+73 60 150 92 60 13 0 0 2 2 5 120 5 0 -1
+ 0.0000000000 0.0000000000 1.0000000000
+ 0.9794318115 0.0000000000 -0.2017754361
+-0.2475810566 0.9476234979 -0.2017754361
+ 0.6794635566 0.7054189880 -0.2017754361
+-0.8542645893 0.4790810838 -0.2017754361
+-0.2475810566 -0.9476234979 -0.2017754361
+-0.3699948910 0.4790810838 -0.7959805875
+-0.3699948910 -0.4790810838 -0.7959805875
+-0.6672097581 -0.2368765739 0.7062015487
+ 0.8324770646 0.1197554578 0.5409626302
+-0.6675126287 0.5116505870 0.5409626302
+ 0.4660769426 -0.5329649671 0.7062015487
+ 0.0883725112 -0.5988365416 -0.7959805875
+-0.2922587145 -0.6448753495 0.7062015487
+-0.6672097581 0.2368765739 0.7062015487
+ 0.7719508391 0.5856635302 0.2471641790
+ 0.4639966765 -0.7751694770 -0.4287416077
+ 0.4639966765 0.7751694770 -0.4287416077
+ 0.7719508391 -0.5856635302 0.2471641790
+ 0.1640284216 -0.8884116786 -0.4287416077
+ 0.1634158680 0.6254788577 -0.7629360738
+-0.5776256146 -0.6946432777 -0.4287416077
+ 0.7239072399 0.1089797474 -0.6812354385
+ 0.9573414162 0.1496906193 0.2471641790
+-0.4246121066 0.8491824202 0.3139964587
+-0.5949197891 -0.2529802202 -0.7629360738
+ 0.3170419295 -0.8949249348 0.3139964587
+-0.2548514500 -0.3832743477 0.8877789775
+-0.8776864208 -0.0000000000 -0.4792353772
+-0.2548514500 0.3832743477 0.8877789775
+-0.7254217428 -0.6728494848 -0.1450409111
+ 0.2582173913 -0.1829926907 0.9485976249
+-0.9980199890 0.0131730113 0.0615026278
+-0.5400311657 0.8290533603 -0.1450409111
+ 0.4846651202 0.2204107171 0.8464743570
+-0.0709753758 -0.9955801941 0.0615026278
+ 0.0229317766 0.1398845177 -0.9899022453
+ 0.8076938496 0.3434590203 -0.4792353772
+ 0.0262977179 0.5317796470 0.8464743570
+ 0.9516406439 -0.2960883932 -0.0819252605
+ 0.1085698247 0.9689378780 0.2221980688
+-0.2763633567 0.7320613041 -0.6226632655
+ 0.7613145044 -0.4132095093 -0.4996580098
+ 0.2099866077 0.9742658140 -0.0819252605
+ 0.1401812208 -0.3162174531 -0.9382727469
+-0.6959163498 -0.6395474135 0.3266183398
+-0.9330524663 0.2829153818 0.2221980688
+ 0.5310965183 0.7818292322 0.3266183398
+-0.7386751889 0.4524387678 -0.4996580098
+-0.4475438832 -0.8410410515 0.3038987040
+-0.2811491679 0.0431081729 -0.9586953796
+-0.8643913313 -0.2155621938 0.4542692670
+ 0.4802495600 0.5116505870 0.7124423043
+ 0.8209889390 -0.3458563213 0.4542692670
+-0.2034129914 0.8143987354 0.5434867567
+ 0.1802813051 -0.6781774208 0.7124423043
+ 0.5734078824 -0.3353176516 -0.7475061691
+ 0.4705702928 -0.8817519234 0.0328198885
+ 0.3836942965 0.4026708396 -0.8310444524
+-0.9121320599 -0.2694460771 -0.3088914320
+ 0.5471106816 0.7084162097 0.4458882998
+ 0.1585623966 0.6069020586 0.4458882998
+-0.1306762499 0.8854983579 0.4458882998
+-0.8237082743 -0.3502689009 0.4458882998
+ 0.5471106816 -0.7084162097 0.4458882998
+ 0.2705130889 -0.3502689009 -0.8967353934
+ 0.3101487853 -0.0000000000 -0.7043410035
+ 0.2705130889 0.3502689009 -0.8967353934
+-0.9604690280 0.1731867527 -0.2179577823
+-0.0615354041 0.6208598148 0.7815027091
+ 0.3573599567 0.5114170284 0.7815027091
+ 0.9224380568 -0.3187513710 -0.2179577823
+-0.0646114894 0.4378252958 -0.8967353934
+-0.7910432524 -0.5716161107 -0.2179577823
+-0.7056730782 -0.3000763028 0.0653317492
+-0.9604690280 -0.1731867527 -0.2179577823
+-0.1982961578 0.9730547528 0.1176566270
+ 0.6473614019 0.2164780859 -0.7307943990
+ 0.6473614019 -0.2164780859 -0.7307943990
+-0.1982961578 -0.9730547528 0.1176566270
+-0.0527175450 -0.6819118559 0.3528535099
+ 0.2461720631 -0.7517075429 0.6118292942
+ 0.8671240119 -0.1070352996 -0.4864559514
+ 0.2454877182 0.9396111859 0.2384671877
+-0.8086646931 0.3307899962 -0.4864559514
+-0.5824039347 -0.5352294570 0.6118292942
+ 0.4577817420 -0.8362546538 -0.3018510074
+ 0.5750948931 -0.4964545016 -0.1228304115
+ 0.5632615562 -0.8178589961 0.1176566270
+ 0.1797689355 0.2646385431 0.9474437035
+-0.9806571218 -0.0363866537 0.1923216597
+-0.7065204582 -0.6810588971 0.1923216597
+ 0.3153129089 -0.0541128280 0.9474437035
+ 0.4814093527 -0.1213684016 0.5880503928
+ 0.7334393435 -0.4281941574 0.5279360691
+-0.4997822658 -0.8660194532 -0.0150994524
+ 0.0376080229 -0.0000000000 -0.9992925681
+-0.4997822658 0.8660194532 -0.0150994524
+ 0.7334393435 0.4281941574 0.5279360691
+-0.1557358302 -0.6543033817 0.7400225914
+-0.4304322977 -0.7911034807 0.4346070868
+-0.5013032036 -0.1867132865 -0.8448865289
+-0.4814093527 0.1213684016 -0.5880503928
+-0.2943558888 0.1819512721 -0.9382155111
+ 0.4997822658 0.8660194532 0.0150994524
+ 0.8504349518 -0.4980243781 0.1695054916
+ 0.6797650274 -0.5277891775 -0.5092721195
+ 0.4153963271 0.8513025630 -0.3205149570
+ 0.0527175450 0.6819118559 -0.3528535099
+-0.1583640613 0.7024638389 -0.6938770635
+ 0.3960752728 -0.6013809101 -0.6938770635
+ 0.8604797042 -0.0147168902 0.5092721195
+ 0.6020633561 0.2164780859 0.7685420962
+-0.7654892092 0.4378252958 0.4715244224
+-0.5750948931 0.4964545016 0.1228304115
+-0.9394255243 0.3307899962 0.0897644851
+-0.1797689355 -0.2646385431 -0.9474437035
+ 0.2198683340 -0.9487067242 0.2271859747
+ 0.9191528491 0.2826295391 0.2743694290
+-0.3960752728 0.6013809101 0.6938770635
+-0.4843157361 0.5017858901 -0.7166932316
+-0.8191635253 -0.0947258962 -0.5656837662
+-0.5616372200 0.3064419676 0.7685420962
+-0.3101487853 -0.0000000000 0.7043410035
+-0.3882607088 -0.3679950751 0.8448865289
+-0.7334393435 -0.4281941574 -0.5279360691
+-0.2833476244 0.9005462671 -0.3297431494
+ 0.0712557971 0.9925336575 -0.0989926775
+-0.8671240119 0.1070352996 0.4864559514
+ 0.3965077344 -0.4525421860 0.7987410009
+ 0.1666692405 -0.8178589961 -0.5507522372
+ 0.5824039347 0.5352294570 -0.6118292942
+-0.7752096022 0.5954285393 -0.2109856093
+-0.4937747326 0.7686152920 0.4067149449
+ 0.7215564288 0.6208598148 -0.3064137896
+ 0.7056730782 0.3000763028 -0.0653317492
+ 0.8755232855 0.2333858350 -0.4230721316
+ 0.1982961578 -0.9730547528 -0.1176566270
+-0.0585650429 -0.1278384441 0.9900643757
+-0.1657176196 0.2889865716 0.9428809214
+ 0.9604690280 -0.1731867527 0.2179577823
+ 0.2734834501 0.6720295560 -0.6881737269
+-0.4581201091 -0.5411818279 -0.7051582764
+-0.1585623966 -0.6069020586 -0.4458882998
+-0.5045884113 -0.7880941967 -0.3525593176
+ 0.0646114894 -0.4378252958 0.8967353934
+ 0.9976445893 0.0243480286 -0.0641283625
+ 0.7485209820 0.6512940977 0.1246288001
+-0.5471106816 0.7084162097 -0.4458882998
+-0.6991764131 -0.0995950201 0.7079782309
+-0.1184473574 -0.9590900905 -0.2571311373
+-0.0432600651 -0.5595774856 -0.8276482371
+3 0 2 1
+5 0 3 10 9 2 3
+3 0 4 3
+3 0 5 4
+3 0 1 5
+3 1 6 5
+5 1 7 17 16 6 3
+3 1 2 7
+3 2 8 7
+3 2 9 8
+3 3 11 10
+3 3 12 11
+3 3 4 12
+3 4 13 12
+5 4 5 14 25 13 3
+3 5 6 14
+3 6 15 14
+3 6 16 15
+3 7 18 17
+3 7 8 18
+5 8 19 31 30 18 3
+3 8 9 19
+3 9 20 19
+3 9 10 20
+3 10 21 20
+3 10 11 21
+3 11 22 21
+5 11 12 23 35 22 3
+3 12 13 23
+3 13 24 23
+3 13 25 24
+3 14 26 25
+3 14 15 26
+5 15 27 39 38 26 3
+3 15 16 27
+3 16 28 27
+3 16 17 28
+3 17 29 28
+3 17 18 29
+3 18 30 29
+3 19 32 31
+3 19 20 32
+5 20 21 33 44 32 3
+3 21 22 33
+3 22 34 33
+3 22 35 34
+3 23 36 35
+3 23 24 36
+5 24 37 48 47 36 3
+3 24 25 37
+3 25 26 37
+3 26 38 37
+3 27 40 39
+3 27 28 40
+5 28 29 41 51 40 3
+3 29 30 41
+3 30 42 41
+3 30 31 42
+3 31 43 42
+3 31 32 43
+3 32 44 43
+3 33 45 44
+3 33 34 45
+5 34 46 55 54 45 3
+3 34 35 46
+3 35 36 46
+3 36 47 46
+3 37 38 48
+3 38 49 48
+3 38 39 49
+3 39 50 49
+3 39 40 50
+3 40 51 50
+3 41 52 51
+3 41 42 52
+5 42 43 53 58 52 3
+3 43 44 53
+3 44 45 53
+3 45 54 53
+3 46 47 55
+3 47 56 55
+3 47 48 56
+3 48 49 56
+5 49 50 57 59 56 3
+3 50 51 57
+3 51 52 57
+3 52 58 57
+3 53 54 58
+3 54 59 58
+3 54 55 59
+3 55 56 59
+3 57 58 59
+5 4 0 1 2 3
+5 4 5 6 7 0
+5 7 8 9 1 0
+5 1 10 11 12 2
+5 12 13 14 3 2
+5 14 15 5 4 3
+5 15 16 17 6 5
+5 6 18 19 8 7
+5 19 20 21 9 8
+5 21 22 23 1 9
+5 23 24 25 10 1
+5 25 26 27 11 10
+5 27 28 13 12 11
+5 28 29 30 14 13
+5 14 31 32 16 15
+5 32 33 34 17 16
+5 34 35 36 6 17
+5 36 37 38 18 6
+5 38 39 20 19 18
+5 20 40 41 22 21
+5 41 42 24 23 22
+5 42 43 26 25 24
+5 43 44 45 27 26
+5 27 46 47 29 28
+5 47 48 49 30 29
+5 49 50 31 14 30
+5 50 51 33 32 31
+5 33 52 53 35 34
+5 53 54 37 36 35
+5 54 55 39 38 37
+5 55 56 57 20 39
+5 57 58 59 40 20
+5 59 60 42 41 40
+5 42 61 62 44 43
+5 62 63 64 45 44
+5 64 65 46 27 45
+5 65 66 48 47 46
+5 48 67 51 50 49
+5 67 68 69 33 51
+5 69 70 71 52 33
+5 71 72 54 53 52
+5 54 73 74 56 55
+5 74 75 58 57 56
+5 75 76 60 59 58
+5 76 77 61 42 60
+5 77 78 63 62 61
+5 63 79 66 65 64
+5 79 80 81 48 66
+5 81 82 68 67 48
+5 82 83 70 69 68
+5 83 84 72 71 70
+5 84 85 73 54 72
+5 85 86 75 74 73
+5 75 87 78 77 76
+5 87 88 89 63 78
+5 89 90 80 79 63
+5 90 83 82 81 80
+5 83 91 86 85 84
+5 91 88 87 75 86
+5 88 89 90 83 91
+great dodecahemidodecahedron
+great dodecahemidodecacron
+5/3 5/2|5/3
+(10/3.5/3.10/3.5/2)
+icosahedral group
+A5
+6{10/3}+6{5/2}+6{5/3}
+74 30 60 18 30 0 1 1 -12 3 4 120 5 1 -1
+ 0.0000000000 0.0000000000 1.0000000000
+ 0.9510565163 0.0000000000 -0.3090169944
+-0.9510565163 0.0000000000 -0.3090169944
+-0.4253254042 0.8506508084 -0.3090169944
+ 0.4253254042 -0.8506508084 -0.3090169944
+-0.5877852523 -0.0000000000 -0.8090169944
+-0.1624598481 -0.8506508084 0.5000000000
+ 0.1624598481 0.8506508084 0.5000000000
+ 0.5877852523 -0.0000000000 -0.8090169944
+ 0.2628655561 -0.5257311121 -0.8090169944
+-0.6881909602 -0.5257311121 0.5000000000
+ 0.6881909602 0.5257311121 0.5000000000
+-0.2628655561 0.5257311121 -0.8090169944
+ 0.5257311121 0.8506508084 -0.0000000000
+-0.5877852523 -0.0000000000 0.8090169944
+-0.8506508084 0.5257311121 -0.0000000000
+ 0.8506508084 -0.5257311121 0.0000000000
+ 0.5877852523 0.0000000000 0.8090169944
+-0.5257311121 -0.8506508084 -0.0000000000
+ 0.2628655561 -0.5257311121 0.8090169944
+-0.2628655561 0.5257311121 0.8090169944
+ 0.9510565163 0.0000000000 0.3090169944
+-0.1624598481 -0.8506508084 -0.5000000000
+ 0.6881909602 0.5257311121 -0.5000000000
+ 0.1624598481 0.8506508084 -0.5000000000
+-0.6881909602 -0.5257311121 -0.5000000000
+-0.9510565163 -0.0000000000 0.3090169944
+-0.4253254042 0.8506508084 0.3090169944
+ 0.4253254042 -0.8506508084 0.3090169944
+ 0.0000000000 -0.0000000000 -1.0000000000
+ 0.0000000000 1.0000000000 0.0000000000
+-0.7236067977 0.4472135955 0.5257311121
+-0.8944271910 -0.4472135955 0.0000000000
+ 0.7236067977 -0.4472135955 0.5257311121
+-0.2763932023 -0.4472135955 -0.8506508084
+ 0.2763932023 0.4472135955 -0.8506508084
+-0.2763932023 -0.4472135955 -0.8506508084
+-0.2763932023 -0.4472135955 0.8506508084
+ 0.7236067977 -0.4472135955 -0.5257311121
+-0.8944271910 -0.4472135955 -0.0000000000
+ 0.8944271910 0.4472135955 -0.0000000000
+-0.7236067977 0.4472135955 -0.5257311121
+ 0.0000000000 -1.0000000000 -0.0000000000
+-0.0000000000 1.0000000000 -0.0000000000
+ 0.2763932023 0.4472135955 0.8506508084
+-0.2763932023 -0.4472135955 0.8506508084
+ 0.7236067977 -0.4472135955 -0.5257311121
+-0.7236067977 0.4472135955 -0.5257311121
+10 0 1 5 14 21 29 26 17 8 2 3
+5 0 2 7 10 3 3
+10 0 3 9 19 27 29 28 20 12 4 3
+5 0 1 6 11 4 2
+10 1 6 15 23 28 26 24 16 10 3 3
+5 1 3 9 13 5 3
+5 2 8 18 12 4 2
+10 2 4 11 15 22 21 27 25 16 7 3
+10 5 13 19 25 24 17 18 12 11 6 3
+5 5 6 15 22 14 2
+5 7 16 24 17 8 2
+10 7 8 18 20 23 22 14 13 9 10 3
+5 9 10 16 25 19 3
+5 11 15 23 20 12 3
+5 13 14 21 27 19 2
+5 17 26 28 20 18 2
+5 21 22 23 28 29 2
+5 24 26 29 27 25 3
+4 3 0 1 2
+4 3 4 5 0
+4 6 0 1 7
+4 1 4 5 2
+4 6 2 3 7
+4 5 8 9 0
+4 3 8 9 4
+4 10 7 1 11
+4 10 0 6 11
+4 5 11 12 2
+4 12 4 1 11
+4 13 7 3 8
+4 13 2 6 8
+4 14 11 5 8
+4 9 11 14 0
+4 9 7 13 4
+4 12 7 10 4
+4 15 0 10 8
+4 15 11 6 8
+4 12 8 14 2
+4 15 2 13 11
+4 14 7 16 0
+4 16 11 9 7
+4 16 4 13 11
+4 17 4 10 8
+4 17 7 12 8
+4 17 0 15 4
+4 17 2 14 7
+4 16 2 15 4
+4 16 0 17 2
+great icosihemidodecahedron
+great icosihemidodecacron
+3/2 3|5/3
+(10/3.3/2.10/3.3)
+icosahedral group
+A5
+6{10/3}+10{3}+10{3/2}
+75 30 60 26 30 0 1 1 -4 3 4 120 5 1 -1
+ 0.0000000000 0.0000000000 1.0000000000
+ 0.9510565163 0.0000000000 -0.3090169944
+-0.9510565163 0.0000000000 -0.3090169944
+ 0.4253254042 0.8506508084 -0.3090169944
+-0.4253254042 -0.8506508084 -0.3090169944
+-0.5877852523 0.0000000000 -0.8090169944
+-0.1624598481 0.8506508084 0.5000000000
+ 0.1624598481 -0.8506508084 0.5000000000
+ 0.5877852523 -0.0000000000 -0.8090169944
+-0.2628655561 -0.5257311121 -0.8090169944
+ 0.6881909602 -0.5257311121 0.5000000000
+-0.6881909602 0.5257311121 0.5000000000
+ 0.2628655561 0.5257311121 -0.8090169944
+ 0.5257311121 -0.8506508084 -0.0000000000
+-0.5877852523 -0.0000000000 0.8090169944
+-0.8506508084 -0.5257311121 -0.0000000000
+ 0.8506508084 0.5257311121 0.0000000000
+ 0.5877852523 0.0000000000 0.8090169944
+-0.5257311121 0.8506508084 -0.0000000000
+-0.2628655561 -0.5257311121 0.8090169944
+ 0.2628655561 0.5257311121 0.8090169944
+ 0.9510565163 0.0000000000 0.3090169944
+-0.1624598481 0.8506508084 -0.5000000000
+ 0.6881909602 -0.5257311121 -0.5000000000
+-0.6881909602 0.5257311121 -0.5000000000
+ 0.1624598481 -0.8506508084 -0.5000000000
+-0.9510565163 -0.0000000000 0.3090169944
+ 0.4253254042 0.8506508084 0.3090169944
+-0.4253254042 -0.8506508084 0.3090169944
+ 0.0000000000 -0.0000000000 -1.0000000000
+ 0.0000000000 1.0000000000 0.0000000000
+-0.4911234732 0.7946544723 0.3568220898
+-0.8944271910 0.4472135955 0.0000000000
+ 0.4911234732 -0.7946544723 0.3568220898
+-0.2763932023 0.4472135955 -0.8506508084
+ 0.1875924741 0.7946544723 -0.5773502692
+-0.1875924741 -0.7946544723 -0.5773502692
+-0.2763932023 0.4472135955 0.8506508084
+ 0.7946544723 -0.1875924741 -0.5773502692
+-0.7946544723 0.1875924741 -0.5773502692
+ 0.7236067977 0.4472135955 -0.5257311121
+-0.6070619982 -0.7946544723 -0.0000000000
+-0.3035309991 -0.1875924741 0.9341723590
+ 0.7236067977 0.4472135955 0.5257311121
+ 0.3035309991 0.1875924741 0.9341723590
+ 0.6070619982 0.7946544723 -0.0000000000
+-0.9822469464 -0.1875924741 -0.0000000000
+ 0.9822469464 0.1875924741 -0.0000000000
+ 0.1875924741 0.7946544723 0.5773502692
+-0.3035309991 -0.1875924741 -0.9341723590
+ 0.3035309991 0.1875924741 -0.9341723590
+-0.1875924741 -0.7946544723 0.5773502692
+ 0.7946544723 -0.1875924741 0.5773502692
+-0.7946544723 0.1875924741 0.5773502692
+ 0.4911234732 -0.7946544723 -0.3568220898
+-0.4911234732 0.7946544723 -0.3568220898
+10 0 1 5 14 21 29 26 17 8 2 3
+3 0 2 3 2
+10 0 3 9 19 27 29 28 20 12 4 3
+3 0 1 4
+10 1 4 11 16 25 26 27 23 15 6 3
+3 1 6 5 2
+3 2 8 7
+10 2 7 16 24 28 21 22 15 10 3 3
+3 3 10 9
+3 4 12 11 2
+10 5 6 10 9 18 17 25 24 20 13 3
+3 5 13 14
+3 6 15 10
+10 7 8 18 19 23 22 14 13 12 11 3
+3 7 11 16 2
+3 8 17 18 2
+3 9 18 19 2
+3 12 20 13
+3 14 22 21 2
+3 15 23 22 2
+3 16 25 24
+3 17 26 25
+3 19 23 27
+3 20 28 24 2
+3 21 28 29
+3 26 29 27 2
+4 3 0 1 2
+4 3 4 5 0
+4 6 0 1 7
+4 8 7 1 2
+4 9 2 3 4
+4 5 10 11 0
+4 12 4 5 10
+4 6 13 14 7
+4 15 0 6 13
+4 8 10 16 2
+4 12 7 8 10
+4 9 13 14 4
+4 17 2 9 13
+4 17 10 11 13
+4 18 13 11 0
+4 19 4 12 7
+4 20 4 14 7
+4 21 0 15 10
+4 16 13 15 10
+4 22 13 16 2
+4 23 2 17 10
+4 18 7 24 0
+4 19 13 18 7
+4 22 4 19 13
+4 20 10 23 7
+4 21 4 20 10
+4 25 0 21 4
+4 25 2 22 4
+4 24 2 23 7
+4 24 0 25 2
+small retrosnub icosicosidodecahedron
+small hexagrammic hexecontahedron
+|3/2 3/2 5/2
+(3.3/2.3.3/2.3.5/2)
+icosahedral group
+A5
+60{3}+12{5/2}+40{3/2}
+76 60 180 112 60 38 0 0 -8 3 6 120 5 0 -1
+ 0.0000000000 0.0000000000 1.0000000000
+ 0.8757465433 0.0000000000 -0.4827711589
+-0.8174044834 -0.3142959094 -0.4827711589
+ 0.6501517764 0.5867151573 -0.4827711589
+-0.3962731062 -0.7809607118 -0.4827711589
+ 0.0895951656 0.8711513729 -0.4827711589
+ 0.2290203992 -0.8452701727 -0.4827711589
+-0.3122207301 -0.8452701727 0.4336318148
+-0.3795312117 0.8711513729 0.3115306484
+-0.6140944004 -0.7809607118 -0.1139668111
+-0.1089106471 0.5867151573 0.8024361627
+ 0.8534618594 -0.5085414639 -0.1139668111
+ 0.3122207301 -0.5085414639 0.8024361627
+-0.9791144009 0.1683643544 -0.1139668111
+ 0.3018736703 -0.9010110667 0.3115306484
+ 0.9485998144 -0.0557408940 0.3115306484
+-0.4185577901 0.9010110667 -0.1139668111
+ 0.5724942349 -0.1683643544 0.8024361627
+ 0.7140366257 -0.6907700508 -0.1139668111
+-0.5947789188 -0.0483139995 0.8024361627
+ 0.5931883546 0.7969561732 -0.1139668111
+-0.9400878225 0.1385046605 0.3115306484
+ 0.7342041525 0.5224056964 0.4336318148
+-0.1810253991 0.1385046605 -0.9736766732
+ 0.1865681885 0.7969561732 0.5745025405
+ 0.4155885877 -0.0483139995 -0.9082686184
+ 0.2449102485 -0.6907700508 0.6803349963
+ 0.9791144009 -0.1683643544 0.1139668111
+-0.3018736703 0.9010110667 -0.3115306484
+ 0.7307785202 -0.0557408940 0.6803349963
+ 0.4185577901 -0.9010110667 0.1139668111
+-0.5724942349 0.1683643544 -0.8024361627
+-0.4155885877 0.0483139995 0.9082686184
+-0.2449102485 0.6907700508 -0.6803349963
+-0.7204314604 -0.3884911091 0.5745025405
+ 0.1553150829 -0.3884911091 -0.9082686184
+-0.7140366257 0.6907700508 0.1139668111
+ 0.5947789188 0.0483139995 -0.8024361627
+ 0.3795312117 -0.8711513729 -0.3115306484
+ 0.6140944004 0.7809607118 0.1139668111
+-0.7307785202 0.0557408940 -0.6803349963
+-0.5931883546 -0.7969561732 0.1139668111
+ 0.9400878225 -0.1385046605 -0.3115306484
+ 0.1089106471 -0.5867151573 -0.8024361627
+-0.8534618594 0.5085414639 0.1139668111
+-0.1553150829 0.3884911091 0.9082686184
+-0.3122207301 0.5085414639 -0.8024361627
+-0.9485998144 0.0557408940 -0.3115306484
+ 0.7204314604 0.3884911091 -0.5745025405
+-0.6501517764 -0.5867151573 0.4827711589
+ 0.1810253991 -0.1385046605 0.9736766732
+-0.1865681885 -0.7969561732 -0.5745025405
+ 0.3962731062 0.7809607118 0.4827711589
+-0.0895951656 -0.8711513729 0.4827711589
+ 0.3122207301 0.8452701727 -0.4336318148
+-0.2290203992 0.8452701727 0.4827711589
+-0.8757465433 0.0000000000 0.4827711589
+-0.7342041525 -0.5224056964 -0.4336318148
+ 0.8174044834 0.3142959094 0.4827711589
+-0.0000000000 -0.0000000000 -1.0000000000
+ 0.1814588279 -0.9775412010 0.1071722635
+-0.5201989819 0.8472940016 0.1071722635
+ 0.7896280312 -0.6041536876 0.1071722635
+-0.9538473568 0.2805161775 0.1071722635
+ 0.9909764414 0.0804971962 0.1071722635
+ 0.1814588279 -0.1388362820 0.1071722635
+ 0.5722705843 0.0804971962 0.8161045152
+-0.3666342546 0.2805161775 -0.8870682034
+ 0.4750653790 -0.6041536876 0.6397743410
+-0.1572813261 0.8472940016 -0.5073021381
+-0.2265924308 -0.7344008871 0.6397743410
+-0.0257718743 -0.2505849906 -0.0152212496
+ 0.4508878772 -0.7344008871 -0.5073021381
+-0.0520716024 0.7667968054 0.6397743410
+-0.0842536226 -0.4538847096 -0.8870682034
+ 0.1572813261 -0.1203377912 -0.1564292618
+ 0.4160557770 0.2000189813 -0.8870682034
+-0.7537294122 -0.1502689781 0.6397743410
+ 0.8267571157 -0.2431403140 -0.5073021381
+ 0.2351248029 0.0904066044 -0.0152212496
+ 0.6495862074 0.4107633769 0.6397743410
+-0.8589391359 -0.0697717819 -0.5073021381
+ 0.7073653437 -0.3005379561 0.6397743410
+-0.3666342546 0.2805161775 -0.8870682034
+ 0.0719611847 -0.5734064947 0.8161045152
+ 0.7494414927 -0.5734064947 -0.3309719638
+-0.9538473568 0.2805161775 0.1071722635
+ 0.9017757544 -0.3005379561 0.3106081546
+-0.8589391359 -0.0697717819 -0.5073021381
+ 0.8738816538 0.4107633769 0.2600082756
+ 0.1001815169 0.0904066044 0.2132581137
+-0.0451336029 -0.2431403140 0.9689405274
+ 0.1964013458 -0.1502689781 -0.9689405274
+-0.5759871832 0.2000189813 0.7926103532
+-0.0610614972 -0.1203377912 0.2132581137
+-0.8175221318 -0.4538847096 0.3544661259
+ 0.5351414998 0.7667968054 -0.3544661259
+-0.4187058571 -0.9077694191 -0.0252999395
+ 0.6001646849 0.7170468022 0.3544661259
+-0.3479751379 -0.6415295512 -0.6836323123
+-0.7666809950 -0.6415295512 0.0252999395
+ 0.6001646849 0.7170468022 0.3544661259
+-0.2242954464 -0.9077694191 -0.3544661259
+-0.1001815169 -0.0904066044 -0.2132581137
+ 0.0451336029 0.2431403140 -0.9689405274
+-0.1964013458 0.1502689781 0.9689405274
+ 0.5759871832 -0.2000189813 -0.7926103532
+-0.7537294122 -0.1502689781 0.6397743410
+ 0.9561443412 0.1071476454 -0.2725938019
+ 0.1466267277 -0.9508907518 -0.2725938019
+-0.0520716024 0.7667968054 0.6397743410
+ 0.3436872184 -0.5036347128 -0.7926103532
+-0.1964013458 0.1502689781 0.9689405274
+-0.2228758320 -0.1071476454 -0.9689405274
+ 0.0610614972 0.1203377912 -0.2132581137
+ 0.8175221318 0.4538847096 -0.3544661259
+-0.5351414998 -0.7667968054 0.3544661259
+ 0.4187058571 0.9077694191 0.0252999395
+ 0.5282035002 0.5036347128 -0.6836323123
+-0.5351414998 -0.7667968054 0.3544661259
+ 0.7666809950 0.6415295512 -0.0252999395
+-0.6001646849 -0.7170468022 -0.3544661259
+ 0.2242954464 0.9077694191 0.3544661259
+-0.3436872184 0.5036347128 0.7926103532
+ 0.1964013458 -0.1502689781 -0.9689405274
+ 0.2228758320 0.1071476454 0.9689405274
+-0.1679359245 -0.9508907518 0.2600082756
+-0.1572813261 0.8472940016 -0.5073021381
+ 0.5259065158 -0.7917985292 0.3106081546
+-0.5201989819 0.8472940016 0.1071722635
+-0.6001646849 -0.7170468022 -0.3544661259
+ 0.3479751379 0.6415295512 0.6836323123
+ 0.0520716024 -0.7667968054 -0.6397743410
+ 0.0520716024 -0.7667968054 -0.6397743410
+ 0.0842536226 0.4538847096 0.8870682034
+-0.1572813261 0.1203377912 0.1564292618
+-0.9561443412 -0.1071476454 0.2725938019
+ 0.7537294122 0.1502689781 -0.6397743410
+-0.5282035002 -0.5036347128 0.6836323123
+ 0.5351414998 0.7667968054 -0.3544661259
+-0.4160557770 -0.2000189813 0.8870682034
+ 0.7537294122 0.1502689781 -0.6397743410
+-0.8267571157 0.2431403140 0.5073021381
+-0.2351248029 -0.0904066044 0.0152212496
+-0.9017757544 0.3005379561 -0.3106081546
+ 0.8589391359 0.0697717819 0.5073021381
+-0.8738816538 -0.4107633769 -0.2600082756
+-0.6495862074 -0.4107633769 -0.6397743410
+ 0.8589391359 0.0697717819 0.5073021381
+-0.7073653437 0.3005379561 -0.6397743410
+-0.5722705843 -0.0804971962 -0.8161045152
+ 0.3666342546 -0.2805161775 0.8870682034
+-0.4750653790 0.6041536876 -0.6397743410
+ 0.1679359245 0.9508907518 -0.2600082756
+ 0.3666342546 -0.2805161775 0.8870682034
+-0.0719611847 0.5734064947 -0.8161045152
+ 0.1572813261 -0.8472940016 0.5073021381
+ 0.1572813261 -0.8472940016 0.5073021381
+ 0.2265924308 0.7344008871 -0.6397743410
+ 0.0257718743 0.2505849906 0.0152212496
+-0.5259065158 0.7917985292 -0.3106081546
+-0.4508878772 0.7344008871 0.5073021381
+-0.1466267277 0.9508907518 0.2725938019
+ 0.5201989819 -0.8472940016 -0.1071722635
+ 0.5201989819 -0.8472940016 -0.1071722635
+-0.7896280312 0.6041536876 -0.1071722635
+-0.7494414927 0.5734064947 0.3309719638
+ 0.9538473568 -0.2805161775 -0.1071722635
+ 0.9538473568 -0.2805161775 -0.1071722635
+-0.9909764414 -0.0804971962 -0.1071722635
+-0.1814588279 0.1388362820 -0.1071722635
+-0.1814588279 0.9775412010 -0.1071722635
+3 0 2 1
+3 0 3 2 2
+3 0 4 3
+3 0 5 4 2
+3 0 6 5
+5 0 1 7 22 6 2
+3 1 8 7
+3 1 9 8 2
+3 1 10 9
+3 1 2 10 2
+3 2 11 10
+5 2 12 35 34 11 2
+3 2 3 12
+3 3 13 12 2
+3 3 14 13
+5 3 4 15 23 14 2
+3 4 16 15
+3 4 17 16 2
+3 4 5 17
+5 5 18 24 25 17 2
+3 5 19 18
+3 5 6 19 2
+3 6 20 19
+3 6 21 20 2
+3 6 22 21
+3 7 23 22
+3 7 24 23 2
+3 7 25 24
+3 7 8 25 2
+3 8 26 25
+5 8 27 19 20 26 2
+3 8 9 27
+3 9 28 27 2
+3 9 29 28
+5 9 10 30 21 29 2
+3 10 31 30
+3 10 11 31 2
+3 11 32 31
+3 11 33 32 2
+3 11 34 33
+3 12 36 35
+3 12 37 36 2
+3 12 13 37
+5 13 38 33 41 37 2
+3 13 39 38
+3 13 14 39 2
+3 14 40 39
+3 14 24 40 2
+3 14 23 24
+3 15 34 23
+3 15 33 34 2
+3 15 41 33
+3 15 16 41 2
+3 16 42 41
+5 16 43 39 40 42 2
+3 16 17 43
+3 17 44 43 2
+3 17 25 44
+3 18 40 24
+3 18 45 40 2
+3 18 46 45
+3 18 19 46 2
+3 19 27 46
+3 20 47 26
+3 20 30 47 2
+3 20 21 30
+3 21 35 29
+3 21 22 35 2
+3 22 34 35
+3 22 23 34 2
+3 25 26 44 2
+3 26 48 44
+3 26 47 48 2
+3 27 49 46 2
+3 27 28 49
+5 28 50 47 52 49 2
+3 28 51 50
+3 28 29 51 2
+3 29 36 51
+3 29 35 36 2
+3 30 52 47
+3 30 31 52 2
+3 31 53 52
+5 31 32 51 36 53 2
+3 32 54 51
+3 32 38 54 2
+3 32 33 38
+3 36 37 53
+3 37 55 53 2
+3 37 41 55
+3 38 56 54
+3 38 39 56 2
+3 39 43 56
+3 40 45 42
+3 41 42 55 2
+3 42 57 55
+3 42 45 57 2
+3 43 58 56 2
+3 43 44 58
+5 44 48 45 46 58 2
+3 45 48 57
+3 46 49 58
+3 47 50 48
+3 48 50 57 2
+3 49 59 58 2
+3 49 52 59
+3 50 54 57
+3 50 51 54 2
+3 52 53 59 2
+3 53 55 59
+5 54 56 59 55 57 2
+3 56 58 59
+6 5 0 1 2 3 4
+6 5 6 7 8 9 0
+6 9 10 11 12 1 0
+6 12 13 14 15 2 1
+6 15 16 17 18 3 2
+6 18 19 20 21 4 3
+6 21 22 23 24 5 4
+6 5 25 26 27 28 6
+6 28 29 30 31 7 6
+6 31 32 33 34 8 7
+6 34 35 36 10 9 8
+6 36 37 38 39 11 10
+6 11 40 41 42 13 12
+6 42 43 44 45 14 13
+6 45 46 47 48 15 14
+6 15 49 50 51 52 16
+6 52 53 54 55 17 16
+6 55 56 57 19 18 17
+6 19 58 59 60 61 20
+6 61 62 30 22 21 20
+6 30 63 64 65 23 22
+6 65 34 66 67 24 23
+6 67 68 69 25 5 24
+6 69 49 15 48 26 25
+6 47 58 19 27 26 48
+6 57 70 29 28 27 19
+6 70 71 72 63 30 29
+6 62 73 74 32 31 30
+6 74 75 76 77 33 32
+6 77 78 79 66 34 33
+6 64 80 81 35 34 65
+6 81 82 83 37 36 35
+6 83 84 85 86 38 37
+6 86 43 51 50 39 38
+6 68 11 39 50 49 69
+6 79 40 11 68 67 66
+6 78 83 87 41 40 79
+6 87 88 89 43 42 41
+6 85 90 91 44 43 86
+6 91 92 54 46 45 44
+6 54 93 59 58 47 46
+6 89 94 53 52 51 43
+6 94 95 96 93 54 53
+6 92 97 98 56 55 54
+6 98 99 71 70 57 56
+6 96 100 99 60 59 93
+6 99 101 73 62 61 60
+6 72 102 75 80 64 63
+6 100 103 102 72 71 99
+6 101 104 105 75 74 73
+6 103 106 107 76 75 102
+6 107 84 83 78 77 76
+6 105 108 82 81 80 75
+6 108 109 88 87 83 82
+6 106 110 90 85 84 107
+6 109 110 95 94 89 88
+6 110 111 97 92 91 90
+6 95 96 100 103 106 110
+6 111 104 101 99 98 97
+6 104 105 108 109 110 111
+great rhombidodecahedron
+great rhombidodecacron
+3/2 5/3 2|
+(4.10/3.4/3.10/7)
+icosahedral group
+A5
+15{4}+6{10/3}+6{10/7}+15{4/3}
+77 60 120 42 60 0 0 1 -18 4 4 120 5 0 2
+ 0.0000000000 0.0000000000 1.0000000000
+ 0.9996324920 0.0000000000 0.0271086873
+-0.9468654869 0.3204853643 0.0271086873
+ 0.0263835025 -0.9992842588 0.0271086873
+-0.3453645319 0.9380770007 0.0271086873
+ 0.0527670051 0.3204853643 -0.9457826254
+ 0.0364611038 0.9380770007 -0.3445027268
+-0.3352869307 -0.8768697425 -0.3445027268
+ 0.2398305218 0.7400061526 0.6283885859
+-0.3189810294 -0.0612072581 -0.9457826254
+-0.9367878857 -0.0612072581 -0.3445027268
+ 0.8677149793 0.3583135302 -0.3445027268
+-0.7334184677 -0.2592781062 0.6283885859
+ 0.6216561575 0.7400061526 0.2567771718
+-0.3678987333 0.3583135302 0.8580570704
+ 0.6480396600 -0.2592781062 -0.7161141409
+ 0.8514090780 -0.4573489542 0.2567771718
+ 0.2336022217 -0.4573489542 0.8580570704
+ 0.5060445461 0.4807280465 -0.7161141409
+-0.7233408665 -0.6409707286 0.2567771718
+ 0.2762916255 -0.6409707286 -0.7161141409
+ 0.4796610435 -0.8390415766 0.2567771718
+ 0.4633551422 -0.2214499403 0.8580570704
+-0.4672044434 -0.5185562123 -0.7161141409
+-0.7295691665 0.4807280465 0.4864456563
+ 0.2436798229 -0.8390415766 0.4864456563
+ 0.8451807779 -0.2214499403 0.4864456563
+-0.7031856640 -0.5185562123 -0.4864456563
+-0.4998162460 -0.7166270604 0.4864456563
+ 0.4998162460 -0.7166270604 -0.4864456563
+-0.8451807779 0.2214499403 -0.4864456563
+-0.4998162460 0.7166270604 0.4864456563
+ 0.4998162460 0.7166270604 -0.4864456563
+ 0.7031856640 0.5185562123 0.4864456563
+ 0.7295691665 -0.4807280465 -0.4864456563
+-0.2436798229 0.8390415766 -0.4864456563
+-0.4633551422 0.2214499403 -0.8580570704
+ 0.4672044434 0.5185562123 0.7161141409
+-0.5060445461 -0.4807280465 0.7161141409
+-0.4796610435 0.8390415766 -0.2567771718
+-0.2762916255 0.6409707286 0.7161141409
+ 0.7233408665 0.6409707286 -0.2567771718
+ 0.3678987333 -0.3583135302 -0.8580570704
+-0.2336022217 0.4573489542 -0.8580570704
+-0.8514090780 0.4573489542 -0.2567771718
+-0.6480396600 0.2592781062 0.7161141409
+-0.6216561575 -0.7400061526 -0.2567771718
+-0.8677149793 -0.3583135302 0.3445027268
+ 0.7334184677 0.2592781062 -0.6283885859
+-0.2398305218 -0.7400061526 -0.6283885859
+ 0.9367878857 0.0612072581 0.3445027268
+ 0.3189810294 0.0612072581 0.9457826254
+-0.0364611038 -0.9380770007 0.3445027268
+ 0.3352869307 0.8768697425 0.3445027268
+-0.0527670051 -0.3204853643 0.9457826254
+ 0.3453645319 -0.9380770007 -0.0271086873
+ 0.9468654869 -0.3204853643 -0.0271086873
+-0.0263835025 0.9992842588 -0.0271086873
+-0.9996324920 0.0000000000 -0.0271086873
+ 0.0000000000 0.0000000000 -1.0000000000
+ 0.1602426822 0.9732489895 0.1646471601
+-0.2254435660 -0.1662507751 0.1646471601
+-0.9686806297 -0.1858740172 0.1646471601
+ 0.1602426822 0.2297529205 0.1646471601
+ 0.1908463112 -0.1858740172 -0.9638612635
+ 0.1706981301 -0.1662507751 -0.2208973453
+-0.0716627060 0.3082458890 -0.0736324484
+-0.2898817352 -0.4156269378 0.8621037224
+-0.3100299164 0.0635021454 -0.0736324484
+ 0.4078312422 0.3007504775 0.8621037224
+ 0.8696452057 -0.4156269378 -0.2664047011
+ 0.8507311228 0.3007504775 0.4310518612
+-0.0652008839 0.0635021454 -0.3119120569
+-0.6904884406 0.6724985120 -0.2664047011
+ 0.0652008839 -0.0635021454 0.3119120569
+ 0.4384348713 -0.8583725292 -0.2664047011
+-0.2781921891 -0.8583725292 0.4310518612
+ 0.3100299164 -0.0635021454 0.0736324484
+-0.2475885600 0.6724985120 -0.6974565623
+ 0.0189140829 -0.7163774153 -0.6974565623
+-0.6977129774 -0.7163774153 -0.0000000000
+ 0.0716627060 -0.3082458890 0.0736324484
+-0.6787988945 0.2297529205 -0.6974565623
+ 0.7166270604 0.0000000000 -0.6974565623
+ 0.6977129774 0.7163774153 -0.0000000000
+-0.7166270604 0.0000000000 0.6974565623
+-0.0189140829 0.7163774153 0.6974565623
+ 0.6787988945 -0.2297529205 0.6974565623
+-0.1602426822 -0.2297529205 -0.1646471601
+ 0.2781921891 0.8583725292 -0.4310518612
+ 0.2475885600 -0.6724985120 0.6974565623
+ 0.2254435660 0.1662507751 -0.1646471601
+-0.8507311228 -0.3007504775 -0.4310518612
+-0.4384348713 0.8583725292 0.2664047011
+-0.1706981301 0.1662507751 0.2208973453
+ 0.6904884406 -0.6724985120 0.2664047011
+-0.4078312422 -0.3007504775 -0.8621037224
+-0.8696452057 0.4156269378 0.2664047011
+ 0.2898817352 0.4156269378 -0.8621037224
+-0.1908463112 0.1858740172 0.9638612635
+ 0.9686806297 0.1858740172 -0.1646471601
+-0.1602426822 -0.9732489895 -0.1646471601
+4 0 2 5 1
+10 0 3 10 14 25 27 24 17 7 2 3
+4 0 4 9 3 3
+10 0 1 6 14 26 32 31 22 11 4 7
+4 1 3 10 6 3
+10 1 5 7 16 18 23 21 11 9 3 3
+10 2 8 18 30 40 41 36 24 13 5 7
+4 2 7 16 8 3
+10 4 12 23 35 45 46 43 31 19 9 3
+4 4 11 21 12
+4 5 13 17 7 3
+4 6 15 25 14
+10 6 10 20 32 44 49 48 39 27 15 3
+4 8 12 23 18
+10 8 16 28 40 50 52 45 33 21 12 3
+4 9 19 22 11
+4 10 20 26 14 3
+10 13 15 25 37 48 55 51 41 29 17 3
+4 13 24 27 15
+4 16 18 30 28
+4 17 24 36 29 3
+10 19 20 26 38 49 56 54 46 34 22 7
+4 19 31 32 20 3
+4 21 23 35 33 3
+4 22 31 43 34
+4 25 37 39 27 3
+4 26 38 44 32
+4 28 29 41 40 3
+10 28 30 42 52 58 59 55 47 36 29 7
+4 30 42 50 40
+4 33 34 46 45
+10 33 35 42 50 57 59 56 53 43 34 3
+4 35 42 52 45 3
+4 36 41 51 47
+10 37 38 44 53 54 58 57 51 47 39 3
+4 37 48 49 38
+4 39 48 55 47 3
+4 43 46 54 53 3
+4 44 49 56 53
+4 50 57 58 52 3
+4 51 57 59 55
+4 54 58 59 56 3
+4 3 0 1 2
+4 3 4 5 0
+4 0 6 7 1
+4 1 4 5 2
+4 2 8 9 3
+4 5 10 6 0
+4 3 11 12 4
+4 7 5 10 1
+4 6 13 14 7
+4 5 15 8 2
+4 1 16 12 4
+4 9 5 15 3
+4 8 13 14 9
+4 10 17 18 6
+4 3 16 1 11
+4 11 17 18 12
+4 14 19 5 7
+4 17 20 1 10
+4 6 19 5 13
+4 15 21 22 8
+4 16 21 22 12
+4 14 23 5 9
+4 21 24 3 15
+4 8 23 5 13
+4 18 1 20 6
+4 1 25 17 11
+4 3 26 21 16
+4 25 12 18 1
+4 14 27 28 19
+4 17 27 28 20
+4 6 29 28 19
+4 22 3 24 8
+4 26 12 22 3
+4 14 30 31 23
+4 21 30 31 24
+4 8 32 31 23
+4 28 33 6 20
+4 25 34 35 17
+4 26 34 35 21
+4 34 36 12 25
+4 14 29 6 27
+4 17 33 6 27
+4 29 31 32 28
+4 31 37 8 24
+4 34 38 12 26
+4 14 32 8 30
+4 21 37 8 30
+4 28 36 34 33
+4 35 12 36 17
+4 38 21 35 12
+4 14 39 31 29
+4 17 40 34 33
+4 39 28 32 14
+4 31 38 34 37
+4 21 41 34 37
+4 28 40 17 36
+4 31 41 21 38
+4 39 34 40 31
+4 41 28 39 34
+4 28 40 31 41
+great retrosnub icosidodecahedron
+great pentagrammic hexecontahedron
+|3/2 5/3 2
+(3.3/2.3.5/3.3)
+icosahedral group
+A5
+60{3}+12{5/3}+20{3/2}
+78 60 150 92 60 37 0 0 2 3 5 120 5 0 -1
+ 0.0000000000 0.0000000000 1.0000000000
+ 0.8737818460 0.0000000000 -0.4863180910
+-0.8272355164 -0.2813825063 -0.4863180910
+ 0.6925555704 0.5327865392 -0.4863180910
+-0.4840908004 -0.7274275300 -0.4863180910
+-0.8272355164 0.2813825063 -0.4863180910
+-0.0881336164 -0.5327865392 0.8416477703
+-0.6603580332 0.7274275300 -0.1864844676
+ 0.3909285122 0.9013314827 -0.1864844676
+ 0.2550110996 -0.4760234971 0.8416477703
+-0.3947197174 0.3685449435 0.8416477703
+ 0.9714370516 0.1467433071 -0.1864844676
+-0.5280509481 0.7309574441 0.4322770073
+ 0.0271688654 -0.9013314827 0.4322770073
+ 0.8594330536 0.4760234971 -0.1864844676
+ 0.5434572030 -0.3685449435 -0.7542074602
+ 0.3094806701 -0.1467433071 0.9395148305
+ 0.1209150724 -0.7309574441 -0.6716254612
+-0.2457391435 -0.2385878386 0.9395148305
+-0.3958253444 -0.5239211808 -0.7542074602
+-0.1243023628 0.9920238341 0.0209197322
+ 0.9269841826 -0.3745166086 0.0209197322
+-0.6079004419 -0.2482501956 -0.7542074602
+-0.3554430809 -0.9344637933 0.0209197322
+ 0.7014236118 0.2385878386 -0.6716254612
+-0.8515098127 0.5239211808 0.0209197322
+-0.0421712056 -0.9920238341 -0.1187867923
+ 0.4690884602 0.3745166086 0.7998083060
+-0.9546457693 0.2482501956 -0.1643876381
+-0.1545791184 0.9344637933 -0.3207533555
+ 0.6370715704 -0.5866558879 -0.4999746827
+ 0.7298299438 -0.4103101843 0.5468032605
+-0.7507169498 -0.5775303855 -0.3207533555
+-0.2094526036 0.8106391313 0.5468032605
+ 0.6206411698 -0.6903443834 0.3717918378
+ 0.2121565789 0.4199725414 -0.8823903051
+-0.1270493712 0.5866558879 0.7998083060
+ 0.8327162674 0.4103101843 0.3717918378
+-0.6453556930 0.5775303855 -0.4999746827
+ 0.3759261720 -0.8106391313 -0.4489362004
+ 0.6266939873 0.6903443834 0.3614958903
+-0.6678410472 -0.4199725414 0.6145009358
+ 0.2128398940 0.9715469400 0.1039024685
+-0.9414323712 -0.3088032958 0.1354459853
+ 0.1638510745 0.8784128377 -0.4489362004
+-0.1706686884 0.0204768941 -0.9851156763
+-0.6425523214 0.4577282099 0.6145009358
+ 0.1942959817 -0.9715469400 0.1354459853
+-0.3394853505 0.3088032958 -0.8884763482
+-0.3125885602 -0.8784128377 0.3614958903
+-0.9437754648 -0.0204768941 0.3299523735
+ 0.2244549438 -0.4577282099 -0.8602934756
+ 0.7424891904 -0.6682227370 0.0467779432
+-0.7746867276 -0.0891832664 0.6260246154
+ 0.9191603379 -0.2151178849 0.3299523735
+ 0.4019596432 0.6682227370 0.6260246154
+ 0.1702647736 0.0891832664 -0.9813542948
+ 0.7353106948 0.2151178849 0.6426838084
+-0.1028863235 0.5557051842 -0.8249885773
+-0.7708955225 -0.5557051842 0.3113066683
+ 0.1624562657 -0.9820828321 0.0955053542
+-0.4700607175 0.8774517931 0.0955053542
+ 0.7275849321 -0.6793370989 0.0955053542
+-0.1940488224 -0.0660053188 0.0955053542
+ 0.1624562657 0.9820828321 0.0955053542
+-0.1451481861 -0.8774517931 -0.4571765031
+ 0.4372885599 0.6793370989 0.5893045235
+-0.0109186081 0.0660053188 -0.2160023198
+-0.6327600026 0.5023295310 0.5893045235
+ 0.4199804802 -0.7839681379 -0.4571765031
+ 0.1451481861 0.1116632412 0.1326508383
+-0.6500680822 0.6069605700 -0.4571765031
+ 0.3232856579 -0.7404097257 0.5893045235
+-0.1420677659 0.5244844560 -0.8394836540
+ 0.2072009579 -0.5023295310 -0.8394836540
+-0.1952284234 0.7839681379 0.5893045235
+ 0.1864960831 -0.1116632412 0.0623173475
+-0.7156123975 -0.6069605700 -0.3456844847
+ 0.6721432584 0.7404097257 -0.0041083120
+-0.8026157016 -0.5244844560 0.2841198533
+ 0.9287592421 -0.2380801948 0.2841198533
+-0.8747711150 0.4845189553 -0.0041083120
+ 0.8729502462 -0.3441803374 -0.3456844847
+-0.9253114997 -0.0276453741 0.3781988390
+-0.2639851185 -0.8872865915 0.3781988390
+-0.1088354609 0.9320177463 -0.3456844847
+ 0.0900414998 -0.1398813892 -0.1531621544
+ 0.3069392403 -0.1981146941 0.9308806963
+-0.6354632109 0.1224416147 -0.7623611733
+ 0.6999311915 0.2380801948 0.6733603404
+-0.4290067871 -0.4845189553 -0.7623611733
+ 0.1224786701 0.3441803374 0.9308806963
+-0.1195324424 0.0276453741 -0.9924453277
+ 0.2020825408 0.8872865915 -0.4145903415
+-0.3549814808 -0.9320177463 0.0730141688
+-0.0900414998 0.1398813892 0.1531621544
+ 0.9626567586 0.1981146941 -0.1845061871
+-0.9751746089 -0.1224416147 -0.1845061871
+ 0.8263177513 0.3812005018 0.4145903415
+-0.0231391970 -0.2214684501 0.0393601759
+ 0.7319039452 0.2017076057 -0.6508691550
+-0.5067407650 0.0146004527 0.8619748395
+ 0.1813680862 0.1395273955 -0.9734668578
+-0.1158237709 -0.4935425313 0.8619748395
+ 0.3826352213 0.6557130703 -0.6508691550
+-0.6865649131 -0.4465908350 0.5737466742
+-0.9435278101 0.2518694250 -0.2152139965
+ 0.7641147853 -0.3812005018 0.5203986667
+ 0.0231391970 0.2214684501 -0.0393601759
+-0.2127795223 -0.2017076057 0.9560538252
+ 0.5067407650 -0.0146004527 -0.8619748395
+-0.7623950866 -0.1395273955 0.6318906850
+ 0.6968507713 0.4935425313 -0.5203986667
+-0.3826352213 -0.6557130703 0.6508691550
+ 0.1674404903 0.4465908350 -0.8789313445
+-0.6469047265 -0.2518694250 -0.7197750118
+ 0.6354632109 -0.1224416147 0.7623611733
+-0.3194267921 0.2655619217 -0.9096391539
+-0.1666620447 0.5559875283 0.8143105251
+ 0.4989740095 -0.3819252966 -0.7779190226
+-0.1864960831 0.1116632412 -0.0623173475
+ 0.8394638530 0.4913219899 -0.2321705015
+-0.6721432584 -0.7404097257 0.0041083120
+ 0.6639956781 0.6539122663 0.3626409897
+-0.8240367351 -0.3275425045 -0.4622546559
+ 0.9751746089 0.1224416147 0.1845061871
+-0.9501692068 -0.2655619217 0.1632646447
+ 0.6304789864 -0.5559875283 -0.5416402091
+-0.4370714318 0.3819252966 0.8143105251
+-0.1451481861 -0.1116632412 -0.1326508383
+ 0.2053800891 -0.4913219899 0.8464169902
+-0.3232856579 0.7404097257 -0.5893045235
+ 0.6397822240 -0.6539122663 0.4038284955
+-0.8046536985 0.3275425045 -0.4952255378
+ 0.1940488224 0.0660053188 -0.0955053542
+ 0.0485023878 -0.0191231611 0.9986399867
+-0.1224786701 -0.3441803374 -0.9308806963
+ 0.4594979286 0.4223387451 0.7813396432
+-0.0914262111 -0.9906050450 -0.1017000132
+ 0.3697500488 0.9182285161 -0.1419200256
+ 0.0109186081 -0.0660053188 0.2160023198
+ 0.8961810797 0.0191231611 -0.4432761860
+-0.8729502462 0.3441803374 0.3456844847
+ 0.9061825512 -0.4223387451 0.0215213446
+-0.1333258458 0.9906050450 -0.0304280072
+ 0.0558089959 -0.9182285161 0.3920991561
+-0.4714704631 -0.7039773520 -0.5311605127
+ 0.1451481861 0.8774517931 0.4571765031
+ 0.1583802720 -0.7508056718 -0.6412538753
+-0.6934030289 0.7039773520 -0.1536493650
+ 0.4700607175 -0.8774517931 -0.0955053542
+-0.4832928034 0.7508056718 0.4502431669
+3 0 2 1
+3 0 3 2 2
+3 0 4 3
+5 0 5 13 12 4 3
+3 0 1 5
+3 1 6 5 2
+3 1 7 6
+5 1 2 8 17 7 3
+3 2 9 8
+3 2 3 9
+5 3 10 21 20 9 3
+3 3 4 10
+3 4 11 10 2
+3 4 12 11
+3 5 14 13
+3 5 6 14
+5 6 15 27 26 14 3
+3 6 7 15
+3 7 16 15 2
+3 7 17 16
+3 8 18 17
+3 8 19 18
+3 8 9 19 2
+3 9 20 19
+3 10 22 21
+3 10 11 22
+5 11 23 35 34 22 3
+3 11 12 23
+3 12 24 23 2
+3 12 13 24
+3 13 25 24
+3 13 14 25 2
+3 14 26 25
+3 15 28 27
+3 15 16 28
+5 16 29 41 40 28 3
+3 16 17 29
+3 17 18 29 2
+3 18 30 29
+5 18 19 31 43 30 3
+3 19 20 31
+3 20 32 31 2
+3 20 21 32
+3 21 33 32
+3 21 22 33 2
+3 22 34 33
+3 23 36 35
+3 23 24 36
+5 24 25 37 48 36 3
+3 25 26 37
+3 26 38 37 2
+3 26 27 38
+3 27 39 38
+3 27 28 39 2
+3 28 40 39
+3 29 30 41
+3 30 42 41 2
+3 30 43 42
+3 31 44 43
+3 31 32 44
+5 32 33 45 53 44 3
+3 33 34 45
+3 34 46 45 2
+3 34 35 46
+3 35 47 46
+3 35 36 47 2
+3 36 48 47
+3 37 49 48
+3 37 38 49
+5 38 39 50 56 49 3
+3 39 40 50
+3 40 51 50 2
+3 40 41 51
+3 41 42 51
+5 42 52 58 57 51 3
+3 42 43 52
+3 43 44 52 2
+3 44 53 52
+3 45 54 53
+3 45 46 54
+5 46 47 55 59 54 3
+3 47 48 55
+3 48 49 55 2
+3 49 56 55
+3 50 57 56
+3 50 51 57
+3 52 53 58
+3 53 54 58 2
+3 54 59 58
+3 55 56 59
+3 56 57 59 2
+3 57 58 59
+5 4 0 1 2 3
+5 4 5 6 7 0
+5 7 8 9 1 0
+5 9 10 11 2 1
+5 11 12 13 3 2
+5 3 14 15 5 4
+5 15 16 17 6 5
+5 17 18 19 7 6
+5 7 20 21 22 8
+5 22 23 10 9 8
+5 10 24 25 12 11
+5 25 26 27 13 12
+5 27 28 29 3 13
+5 29 30 31 14 3
+5 31 32 16 15 14
+5 16 33 34 18 17
+5 34 35 36 19 18
+5 36 37 20 7 19
+5 37 38 39 21 20
+5 39 40 23 22 21
+5 40 41 42 10 23
+5 42 43 44 24 10
+5 44 45 26 25 24
+5 26 46 47 28 27
+5 47 48 30 29 28
+5 48 49 32 31 30
+5 49 50 51 16 32
+5 51 52 53 33 16
+5 53 54 35 34 33
+5 35 55 38 37 36
+5 55 56 57 39 38
+5 39 58 59 41 40
+5 59 60 43 42 41
+5 60 61 45 44 43
+5 61 62 63 26 45
+5 63 64 65 46 26
+5 65 66 48 47 46
+5 48 67 68 50 49
+5 68 69 52 51 50
+5 69 70 54 53 52
+5 70 71 72 35 54
+5 72 73 56 55 35
+5 73 74 75 57 56
+5 75 76 58 39 57
+5 76 77 60 59 58
+5 60 78 79 62 61
+5 79 80 64 63 62
+5 80 81 66 65 64
+5 81 82 67 48 66
+5 82 83 69 68 67
+5 69 84 85 71 70
+5 85 74 73 72 71
+5 74 86 77 76 75
+5 86 87 78 60 77
+5 87 88 80 79 78
+5 80 89 83 82 81
+5 89 90 84 69 83
+5 90 91 74 85 84
+5 91 88 87 86 74
+5 88 80 89 90 91
+great dirhombicosidodecahedron
+great dirhombicosidodecacron
+|3/2 5/3 3 5/2
+(4.5/3.4.3.4.5/2.4.3/2)
+icosahedral group
+A5
+60{4}+20{3}+12{5/2}+12{5/3}+20{3/2}
+79 60 240 124 60 0 1 0 -56 5 8 120 5 1 -1
+ 0.0000000000 0.0000000000 1.0000000000
+ 1.0000000000 0.0000000000 0.0000000000
+-1.0000000000 0.0000000000 0.0000000000
+-0.6180339887 0.7861513778 0.0000000000
+ 0.6180339887 -0.7861513778 0.0000000000
+ 0.7861513778 0.6180339887 0.0000000000
+-0.7861513778 -0.6180339887 0.0000000000
+ 0.0000000000 -1.0000000000 0.0000000000
+-0.0000000000 1.0000000000 0.0000000000
+-0.0000000000 -0.6180339887 0.7861513778
+ 0.0000000000 0.6180339887 -0.7861513778
+-0.0000000000 0.7861513778 0.6180339887
+ 0.0000000000 -0.7861513778 -0.6180339887
+ 0.0000000000 -0.0000000000 -1.0000000000
+-0.6180339887 -0.4858682718 0.6180339887
+ 0.6180339887 0.4858682718 -0.6180339887
+-0.4858682718 -0.3819660113 -0.7861513778
+ 0.4858682718 0.3819660113 0.7861513778
+-0.3819660113 0.4858682718 0.7861513778
+ 0.3819660113 -0.4858682718 -0.7861513778
+ 0.4858682718 -0.6180339887 0.6180339887
+-0.4858682718 0.6180339887 -0.6180339887
+-0.7861513778 -0.0000000000 0.6180339887
+ 0.7861513778 -0.0000000000 -0.6180339887
+-0.6180339887 -0.0000000000 -0.7861513778
+ 0.6180339887 -0.0000000000 0.7861513778
+ 0.6180339887 -0.6180339887 -0.4858682718
+-0.6180339887 0.6180339887 0.4858682718
+-0.7861513778 -0.4858682718 -0.3819660113
+ 0.7861513778 0.4858682718 0.3819660113
+ 0.7861513778 -0.3819660113 0.4858682718
+-0.7861513778 0.3819660113 -0.4858682718
+-0.8678342830 0.3177508827 0.3819660113
+ 0.8678342830 -0.3177508827 -0.3819660113
+ 0.1039022605 0.8678342830 -0.4858682718
+-0.1039022605 -0.8678342830 0.4858682718
+-0.9183170948 -0.1039022605 -0.3819660113
+ 0.9183170948 0.1039022605 0.3819660113
+ 0.3819660113 0.7861513778 0.4858682718
+-0.3819660113 -0.7861513778 -0.4858682718
+-0.4858682718 -0.7861513778 0.3819660113
+ 0.4858682718 0.7861513778 -0.3819660113
+ 0.3819660113 -0.8678342830 0.3177508827
+-0.3819660113 0.8678342830 -0.3177508827
+-0.4858682718 0.1039022605 0.8678342830
+ 0.4858682718 -0.1039022605 -0.8678342830
+-0.3819660113 -0.9183170948 -0.1039022605
+ 0.3819660113 0.9183170948 0.1039022605
+ 0.3177508827 -0.2360679775 0.9183170948
+-0.3177508827 0.2360679775 -0.9183170948
+-0.2360679775 0.9183170948 0.3177508827
+ 0.2360679775 -0.9183170948 -0.3177508827
+-0.3177508827 -0.3819660113 0.8678342830
+ 0.3177508827 0.3819660113 -0.8678342830
+-0.8678342830 0.4858682718 -0.1039022605
+ 0.8678342830 -0.4858682718 0.1039022605
+ 0.1039022605 0.3819660113 0.9183170948
+-0.1039022605 -0.3819660113 -0.9183170948
+ 0.9183170948 0.3177508827 -0.2360679775
+-0.9183170948 -0.3177508827 0.2360679775
+ 0.0000000000 1.0000000000 0.0000000000
+-0.5773502692 0.2805161775 0.5773502692
+-0.7861513778 -0.6180339887 -0.0000000000
+ 0.8107067993 -0.0970626198 0.5773502692
+-0.6180339887 0.7861513778 0.0000000000
+-0.2805161775 -0.5773502692 0.5773502692
+ 1.0000000000 0.0000000000 0.0000000000
+ 0.5773502692 0.5773502692 0.5773502692
+ 0.0000000000 0.0000000000 1.0000000000
+ 0.5773502692 -0.5773502692 0.2805161775
+ 0.0000000000 -0.7861513778 -0.6180339887
+ 0.5773502692 0.8107067993 -0.0970626198
+-0.0000000000 -0.6180339887 0.7861513778
+ 0.5773502692 -0.2805161775 -0.5773502692
+-0.5773502692 -0.5773502692 -0.5773502692
+-0.5773502692 0.5773502692 -0.2805161775
+-0.5773502692 -0.8107067993 0.0970626198
+ 0.4858682718 0.3819660113 0.7861513778
+-0.2805161775 0.5138727076 -0.8107067993
+-0.6180339887 -0.4858682718 0.6180339887
+ 0.0970626198 0.8107067993 0.2805161775
+ 0.0000000000 -0.0000000000 -1.0000000000
+-0.8107067993 0.0970626198 -0.5773502692
+ 0.2805161775 -0.5138727076 0.8107067993
+-0.0970626198 -0.8107067993 -0.2805161775
+ 0.4858682718 -0.6180339887 0.6180339887
+ 0.9549290665 -0.2805161775 -0.0970626198
+ 0.3819660113 -0.4858682718 -0.7861513778
+ 0.2805161775 0.5773502692 -0.5773502692
+-0.9549290665 0.2805161775 0.0970626198
+-0.6180339887 -0.0000000000 -0.7861513778
+ 0.0970626198 -0.5773502692 -0.8107067993
+ 0.7861513778 -0.0000000000 -0.6180339887
+-0.0970626198 0.5773502692 0.8107067993
+ 0.7861513778 0.4858682718 0.3819660113
+-0.8107067993 -0.2805161775 0.5138727076
+ 0.6180339887 -0.6180339887 -0.4858682718
+ 0.2805161775 0.0970626198 0.8107067993
+-1.0000000000 0.0000000000 -0.0000000000
+ 0.8107067993 0.2805161775 -0.5138727076
+-0.2805161775 -0.0970626198 -0.8107067993
+ 0.6180339887 0.4858682718 -0.6180339887
+-0.0970626198 0.9549290665 -0.2805161775
+-0.7861513778 0.3819660113 -0.4858682718
+ 0.0970626198 -0.9549290665 0.2805161775
+-0.0000000000 0.7861513778 0.6180339887
+-0.8107067993 -0.2805161775 -0.0970626198
+ 0.6180339887 -0.7861513778 -0.0000000000
+ 0.8107067993 0.2805161775 0.0970626198
+ 0.1039022605 0.8678342830 -0.4858682718
+ 0.2805161775 0.0970626198 -0.9549290665
+ 0.8678342830 -0.3177508827 -0.3819660113
+-0.2805161775 -0.0970626198 0.9549290665
+-0.9183170948 -0.1039022605 -0.3819660113
+-0.8107067993 -0.2805161775 0.5138727076
+-0.1039022605 -0.8678342830 0.4858682718
+ 0.2805161775 0.0970626198 0.8107067993
+ 0.7861513778 0.6180339887 0.0000000000
+ 0.8107067993 0.2805161775 -0.5138727076
+-0.2805161775 -0.0970626198 -0.8107067993
+-0.7861513778 -0.0000000000 0.6180339887
+ 0.5138727076 -0.8107067993 -0.2805161775
+ 0.3819660113 0.7861513778 0.4858682718
+-0.5138727076 0.8107067993 0.2805161775
+-0.4858682718 0.6180339887 -0.6180339887
+-0.8107067993 -0.2805161775 -0.0970626198
+ 0.0000000000 -1.0000000000 0.0000000000
+ 0.8107067993 0.2805161775 0.0970626198
+-0.6180339887 0.6180339887 0.4858682718
+ 0.2805161775 0.0970626198 -0.9549290665
+-0.4858682718 -0.7861513778 0.3819660113
+-0.2805161775 -0.0970626198 0.9549290665
+ 0.6180339887 0.0000000000 0.7861513778
+-0.0970626198 -0.8107067993 -0.2805161775
+ 0.0000000000 0.6180339887 -0.7861513778
+ 0.0970626198 0.8107067993 0.2805161775
+-0.4858682718 0.1039022605 0.8678342830
+-0.9549290665 0.2805161775 0.0970626198
+-0.3819660113 0.8678342830 -0.3177508827
+ 0.9549290665 -0.2805161775 -0.0970626198
+-0.3819660113 -0.9183170948 -0.1039022605
+ 0.5138727076 -0.8107067993 -0.2805161775
+ 0.4858682718 -0.1039022605 -0.8678342830
+-0.5138727076 0.8107067993 0.2805161775
+ 0.3177508827 -0.2360679775 0.9183170948
+-0.0970626198 0.5773502692 0.8107067993
+ 0.3819660113 0.9183170948 0.1039022605
+-0.5773502692 0.5773502692 -0.2805161775
+-0.4858682718 -0.3819660113 -0.7861513778
+ 0.0970626198 -0.5773502692 -0.8107067993
+ 0.5773502692 -0.5773502692 0.2805161775
+-0.3819660113 0.4858682718 0.7861513778
+ 0.3177508827 0.3819660113 -0.8678342830
+-0.5773502692 -0.8107067993 0.0970626198
+-0.2360679775 0.9183170948 0.3177508827
+ 0.5773502692 0.8107067993 -0.0970626198
+ 0.8678342830 -0.4858682718 0.1039022605
+-0.0970626198 0.9549290665 -0.2805161775
+-0.3177508827 -0.3819660113 0.8678342830
+ 0.0970626198 -0.9549290665 0.2805161775
+-0.1039022605 -0.3819660113 -0.9183170948
+ 0.2805161775 -0.5138727076 0.8107067993
+-0.8678342830 0.4858682718 -0.1039022605
+-0.2805161775 0.5138727076 -0.8107067993
+ 0.9183170948 0.3177508827 -0.2360679775
+ 0.8107067993 -0.0970626198 0.5773502692
+ 0.1039022605 0.3819660113 0.9183170948
+-0.2805161775 -0.5773502692 0.5773502692
+-0.7861513778 -0.4858682718 -0.3819660113
+-0.8107067993 0.0970626198 -0.5773502692
+ 0.2805161775 0.5773502692 -0.5773502692
+ 0.7861513778 -0.3819660113 0.4858682718
+-0.8678342830 0.3177508827 0.3819660113
+ 0.2360679775 -0.9183170948 -0.3177508827
+ 0.5773502692 0.5773502692 0.5773502692
+-0.9183170948 -0.3177508827 0.2360679775
+-0.5773502692 -0.5773502692 -0.5773502692
+-0.3177508827 0.2360679775 -0.9183170948
+-0.5773502692 0.2805161775 0.5773502692
+ 0.9183170948 0.1039022605 0.3819660113
+ 0.5773502692 -0.2805161775 -0.5773502692
+-0.3819660113 -0.7861513778 -0.4858682718
+ 0.4858682718 0.7861513778 -0.3819660113
+ 0.3819660113 -0.8678342830 0.3177508827
+4 0 1 13 2
+5 0 2 11 14 3 3
+4 0 3 13 4
+3 0 4 5
+4 0 5 13 6
+5 0 6 20 22 7 2
+4 0 7 13 8
+3 0 1 8 2
+4 1 8 2 7
+5 1 7 25 26 9 3
+4 1 9 2 10
+3 1 10 11
+4 1 11 2 12
+5 1 12 15 4 13 2
+3 2 13 7
+5 2 8 24 27 10 2
+3 2 9 12 2
+4 3 14 4 15
+3 3 15 16
+4 3 16 4 17
+5 3 17 34 18 5 2
+4 3 5 4 6
+3 3 6 13 2
+3 4 14 17 2
+5 4 16 35 19 6 3
+4 5 18 6 19
+3 5 19 20 2
+4 5 20 6 21
+5 5 21 23 8 13 3
+3 6 18 21
+4 7 22 8 23
+3 7 23 24 2
+4 7 24 8 25
+3 8 22 25
+4 9 26 10 27
+3 9 27 28
+4 9 28 10 29
+5 9 29 44 30 11 2
+4 9 11 10 12
+3 10 26 29 2
+5 10 28 45 31 12 3
+4 11 30 12 31
+3 11 31 15 2
+4 11 15 12 14
+3 12 30 14
+4 14 30 15 31
+5 14 31 46 32 16 2
+4 14 16 15 17
+5 15 30 47 33 17 3
+4 16 32 17 33
+3 16 33 34 2
+4 16 34 17 35
+3 17 32 35
+4 18 34 19 35
+3 18 35 36 2
+4 18 36 19 37
+5 18 37 52 38 20 3
+4 18 20 19 21
+3 19 34 37
+5 19 36 53 39 21 2
+4 20 38 21 39
+3 20 39 23
+4 20 23 21 22
+3 21 38 22 2
+4 22 38 23 39
+5 22 39 54 40 24 3
+4 22 24 23 25
+5 23 38 55 41 25 2
+4 24 40 25 41
+3 24 41 26
+4 24 26 25 27
+3 25 40 27 2
+4 26 41 27 40
+5 26 40 57 42 28 2
+4 26 28 27 29
+5 27 41 56 43 29 3
+4 28 42 29 43
+3 28 43 44 2
+4 28 44 29 45
+3 29 42 45
+4 30 44 31 45
+3 30 45 46 2
+4 30 46 31 47
+3 31 44 47
+4 32 46 33 47
+3 32 47 48 2
+4 32 48 33 49
+5 32 49 50 36 34 3
+4 32 34 33 35
+3 33 46 49
+5 33 48 51 37 35 2
+4 34 36 35 37
+4 36 50 37 51
+3 36 51 52
+4 36 52 37 53
+3 37 50 53 2
+4 38 52 39 53
+3 38 53 54
+4 38 54 39 55
+3 39 52 55 2
+4 40 54 41 55
+3 40 55 56
+4 40 56 41 57
+3 41 54 57 2
+4 42 57 43 56
+3 42 56 58 2
+4 42 58 43 59
+5 42 59 48 46 44 3
+4 42 44 43 45
+3 43 57 59
+5 43 58 49 47 45 2
+4 44 46 45 47
+4 46 48 47 49
+4 48 59 49 58
+3 48 58 50
+4 48 50 49 51
+3 49 59 51 2
+4 50 58 51 59
+5 50 59 56 54 52 2
+4 50 52 51 53
+5 51 58 57 55 53 3
+4 52 54 53 55
+4 54 56 55 57
+4 56 59 57 58
+8 7 0 1 2 3 4 5 6
+8 7 8 9 10 11 12 13 0
+8 14 0 1 12 16 10 15 8
+8 1 17 18 19 20 21 22 2
+8 13 2 3 21 24 19 23 17
+8 20 25 26 27 28 4 3 21
+8 22 4 5 27 29 25 24 21
+8 5 30 31 32 9 8 14 6
+8 28 6 7 8 15 32 33 30
+8 9 34 35 36 37 38 16 10
+8 15 34 39 36 40 38 11 10
+8 37 41 42 43 1 12 11 38
+8 40 41 44 43 13 12 16 38
+8 13 0 14 6 28 4 22 2
+8 44 45 46 47 23 17 1 43
+8 42 45 48 47 18 17 13 43
+8 46 49 50 51 24 19 18 47
+8 48 49 52 51 20 19 23 47
+8 20 53 54 55 56 57 29 25
+8 24 53 58 55 59 57 26 25
+8 56 60 61 62 5 27 26 57
+8 59 60 63 62 28 27 29 57
+8 63 64 65 66 33 30 5 62
+8 61 64 67 66 31 30 28 62
+8 65 68 69 70 15 32 31 66
+8 67 68 71 70 9 32 33 66
+8 69 72 73 74 39 34 9 70
+8 71 72 75 74 35 34 15 70
+8 73 76 77 78 40 36 35 74
+8 75 76 79 78 37 36 39 74
+8 37 80 81 82 48 45 44 41
+8 40 80 83 82 46 45 42 41
+8 46 84 85 86 87 88 52 49
+8 48 84 89 86 90 88 50 49
+8 87 91 58 53 20 51 50 88
+8 90 91 54 53 24 51 52 88
+8 87 92 93 94 59 55 54 91
+8 90 92 95 94 56 55 58 91
+8 56 96 97 98 67 64 63 60
+8 59 96 99 98 65 64 61 60
+8 65 100 101 102 73 72 71 68
+8 67 100 103 102 75 72 69 68
+8 73 104 105 106 107 108 79 76
+8 75 104 109 106 110 108 77 76
+8 107 111 83 80 37 78 77 108
+8 110 111 81 80 40 78 79 108
+8 107 112 89 84 46 82 81 111
+8 110 112 85 84 48 82 83 111
+8 107 113 114 115 90 86 85 112
+8 110 113 116 115 87 86 89 112
+8 114 117 118 119 95 92 87 115
+8 116 117 120 119 93 92 90 115
+8 118 121 99 96 56 94 93 119
+8 120 121 97 96 59 94 95 119
+8 118 122 103 100 65 98 97 121
+8 120 122 101 100 67 98 99 121
+8 118 123 105 104 75 102 101 122
+8 120 123 109 104 73 102 103 122
+8 105 106 110 113 114 117 120 123
+8 107 106 109 123 118 117 116 113
--- /dev/null
+++ b/lib/print/defprinter
@@ -1,0 +1,1 @@
+printer0
--- /dev/null
+++ b/lib/print/dj895.map
@@ -1,0 +1,729 @@
+255 110 110 108
+71 252 188 4
+34 253 187 6
+19 253 181 4
+12 254 168 4
+8 254 154 3
+6 254 140 3
+3 253 128 2
+0 255 112 0
+59 193 46 252
+85 249 15 39
+47 253 133 10
+24 253 164 7
+13 253 165 3
+8 254 158 3
+4 253 149 1
+1 253 141 0
+0 255 131 0
+11 175 65 253
+39 227 28 225
+54 253 21 45
+31 252 92 18
+16 253 128 8
+6 254 138 3
+1 252 140 0
+0 255 138 0
+0 247 133 0
+2 167 52 253
+11 194 48 251
+28 243 20 166
+23 237 40 56
+11 242 75 29
+4 250 91 13
+0 245 100 0
+0 231 112 0
+0 230 119 0
+0 164 39 254
+1 177 40 253
+8 225 28 239
+11 231 21 128
+3 228 48 59
+0 228 59 30
+0 229 61 8
+0 210 73 0
+0 205 90 0
+0 162 23 254
+0 168 24 253
+2 203 20 252
+0 222 24 193
+0 226 33 105
+0 223 37 43
+0 218 38 18
+0 208 40 0
+0 196 59 0
+0 164 11 255
+0 166 13 253
+0 188 10 253
+0 200 10 217
+0 204 9 135
+0 224 10 66
+0 221 20 26
+0 219 24 7
+0 203 34 0
+0 170 0 255
+0 163 0 251
+0 177 0 255
+0 184 0 228
+0 184 2 166
+0 205 0 100
+0 220 0 44
+0 233 12 18
+0 221 15 0
+0 183 0 255
+0 172 0 255
+0 173 0 255
+0 175 0 235
+0 173 0 191
+0 188 0 136
+0 209 0 81
+0 231 0 37
+0 255 0 0
+88 11 252 203
+56 94 251 31
+30 206 250 12
+18 250 241 7
+12 254 213 2
+8 254 194 2
+5 253 179 0
+1 253 167 0
+0 232 142 0
+27 112 124 253
+81 110 118 108
+46 244 188 13
+23 253 183 6
+12 254 173 3
+6 254 160 3
+2 253 149 0
+0 255 137 0
+0 246 121 0
+0 118 84 252
+31 175 67 242
+45 199 61 80
+25 233 120 31
+13 250 137 7
+4 253 139 1
+0 255 136 0
+0 247 131 0
+0 237 120 0
+0 120 52 253
+6 172 58 252
+14 212 59 203
+13 206 66 85
+4 219 96 48
+0 232 100 18
+0 225 99 0
+0 218 108 0
+0 218 112 0
+0 132 36 254
+0 164 39 254
+5 194 31 240
+0 201 51 152
+1 204 58 74
+0 197 59 31
+0 196 56 3
+0 191 72 0
+0 197 89 0
+0 136 21 255
+0 154 17 253
+0 186 12 248
+0 179 15 172
+0 182 19 92
+0 184 29 41
+0 179 32 15
+0 174 39 0
+0 176 57 0
+0 136 7 253
+0 147 0 251
+0 163 0 235
+0 160 0 181
+0 166 0 120
+0 179 3 61
+0 178 11 22
+0 174 16 4
+0 169 33 0
+0 138 0 255
+0 136 0 226
+0 139 0 206
+0 141 0 179
+0 145 0 141
+0 156 0 90
+0 171 0 45
+0 176 0 10
+0 176 13 0
+0 146 0 255
+0 135 0 206
+0 136 0 196
+0 137 0 180
+0 140 0 156
+0 147 0 118
+0 163 0 73
+0 181 0 35
+0 190 0 0
+46 8 247 246
+42 26 253 103
+28 77 253 30
+18 175 253 10
+11 243 254 2
+8 253 215 3
+2 252 217 0
+0 246 195 0
+0 214 165 0
+10 70 169 253
+52 39 215 183
+38 120 243 33
+15 223 246 14
+6 251 220 5
+3 253 198 0
+0 255 180 0
+0 248 163 0
+0 226 140 0
+0 80 94 253
+14 108 130 246
+23 134 143 132
+7 200 186 74
+6 234 158 13
+0 245 144 0
+0 240 136 0
+0 237 127 0
+0 222 115 0
+0 84 57 253
+0 116 74 253
+10 146 79 206
+3 179 119 129
+0 176 108 52
+0 198 99 11
+0 205 100 0
+0 208 106 0
+0 208 104 0
+0 92 36 255
+0 118 40 254
+2 156 42 234
+0 149 48 143
+0 157 58 71
+0 159 58 29
+0 170 58 3
+0 176 73 0
+0 185 86 0
+0 101 23 255
+0 121 19 254
+0 145 14 234
+0 142 18 161
+0 147 26 97
+0 147 28 43
+0 148 30 15
+0 152 39 0
+0 162 58 0
+0 107 7 255
+0 117 0 255
+0 127 0 219
+0 130 0 166
+0 130 0 110
+0 141 3 59
+0 144 8 24
+0 142 13 2
+0 148 31 0
+0 114 0 255
+0 107 0 223
+0 113 0 186
+0 118 0 161
+0 121 0 128
+0 127 0 85
+0 138 0 45
+0 142 0 11
+0 144 10 0
+0 119 0 255
+0 107 0 205
+0 113 0 176
+0 118 0 159
+0 119 0 137
+0 121 0 107
+0 131 0 69
+0 146 0 35
+0 147 0 0
+8 38 229 253
+28 14 254 170
+22 32 253 69
+13 67 253 30
+9 150 254 7
+0 216 250 0
+0 228 235 0
+0 216 209 0
+0 196 182 0
+4 44 183 254
+28 20 238 231
+29 32 248 81
+13 92 249 24
+1 175 243 2
+0 215 226 0
+0 225 209 0
+0 221 189 0
+0 207 166 0
+0 49 117 254
+5 67 163 251
+7 90 198 182
+7 108 194 68
+0 161 181 16
+0 195 165 0
+0 211 158 0
+0 215 147 0
+0 209 135 0
+0 60 66 254
+0 76 89 253
+3 95 114 210
+0 118 126 116
+0 124 117 48
+0 157 105 10
+0 181 106 0
+0 195 107 0
+0 196 105 0
+0 66 40 255
+0 76 45 253
+0 102 57 235
+0 103 60 147
+0 109 64 75
+0 120 65 30
+0 138 63 3
+0 157 75 0
+0 172 84 0
+0 73 26 254
+0 82 24 254
+0 101 23 240
+0 104 25 160
+0 103 30 97
+0 110 33 46
+0 115 33 15
+0 129 43 0
+0 145 60 0
+0 77 9 253
+0 81 0 251
+0 95 0 229
+0 98 0 161
+0 99 5 109
+0 104 8 61
+0 107 12 24
+0 109 12 0
+0 127 33 0
+0 85 0 255
+0 83 0 232
+0 87 0 193
+0 97 0 156
+0 101 0 122
+0 101 0 83
+0 106 0 43
+0 110 0 11
+0 114 10 0
+0 92 0 248
+0 84 0 209
+0 90 0 179
+0 99 0 153
+0 103 0 130
+0 102 0 101
+0 106 0 67
+0 116 0 34
+0 116 0 0
+5 29 224 254
+16 14 254 212
+16 19 253 112
+8 34 253 55
+3 55 253 26
+0 120 246 0
+0 174 232 0
+0 186 214 0
+0 175 193 0
+2 30 192 253
+5 34 243 247
+16 18 250 135
+6 36 250 53
+2 67 250 12
+0 127 230 0
+0 174 218 0
+0 191 209 0
+0 185 189 0
+0 36 138 255
+2 40 179 253
+0 58 215 202
+2 57 206 92
+0 77 202 26
+0 125 185 0
+0 170 187 0
+0 188 179 0
+0 190 162 0
+0 38 79 255
+0 45 101 254
+0 59 132 213
+0 56 128 118
+0 74 130 47
+0 106 121 8
+0 143 124 0
+0 169 128 0
+0 181 123 0
+0 44 44 254
+0 51 55 254
+1 60 67 223
+0 63 68 144
+0 70 74 71
+0 84 73 29
+0 106 70 2
+0 137 80 0
+0 159 86 0
+0 52 28 254
+0 56 30 254
+0 64 32 228
+0 66 33 161
+0 71 37 98
+0 75 40 48
+0 84 39 13
+0 102 49 0
+0 125 63 0
+0 58 11 253
+0 61 7 253
+0 65 7 231
+0 69 9 169
+0 73 10 112
+0 75 13 63
+0 80 15 25
+0 85 17 2
+0 104 36 0
+0 63 0 255
+0 62 0 236
+0 64 0 201
+0 70 0 161
+0 77 0 122
+0 79 0 82
+0 81 0 43
+0 84 0 11
+0 92 11 0
+0 68 0 243
+0 64 0 206
+0 67 0 180
+0 75 0 157
+0 85 0 130
+0 87 0 99
+0 87 0 69
+0 91 0 35
+0 93 0 0
+3 20 220 254
+0 28 253 240
+1 24 254 165
+3 23 254 80
+0 26 254 35
+0 33 252 8
+0 92 238 0
+0 140 217 0
+0 153 197 0
+1 20 198 254
+0 24 246 251
+0 23 252 182
+0 23 250 81
+0 24 250 19
+0 42 235 0
+0 99 221 0
+0 149 214 0
+0 163 199 0
+0 24 153 254
+1 22 190 251
+0 23 204 192
+0 26 202 100
+0 32 206 32
+0 48 195 0
+0 106 196 0
+0 151 197 0
+0 167 187 0
+0 26 93 255
+0 28 114 254
+0 29 135 205
+0 28 135 121
+0 33 141 53
+0 50 140 9
+0 98 146 0
+0 138 156 0
+0 158 150 0
+0 28 55 254
+0 32 62 254
+0 35 73 216
+0 35 78 141
+0 40 84 79
+0 50 84 27
+0 75 83 0
+0 113 98 0
+0 138 103 0
+0 34 34 255
+0 35 35 254
+0 37 40 222
+0 36 39 152
+0 42 45 94
+0 43 47 45
+0 58 47 14
+0 82 55 0
+0 110 68 0
+0 37 15 253
+0 39 14 253
+0 41 15 221
+0 43 14 163
+0 46 16 111
+0 50 19 62
+0 53 20 26
+0 61 23 2
+0 83 41 0
+0 44 0 255
+0 44 0 238
+0 44 0 200
+0 46 0 162
+0 51 0 123
+0 55 0 78
+0 55 0 41
+0 57 0 10
+0 70 13 0
+0 52 0 225
+0 48 0 196
+0 48 0 174
+0 53 0 153
+0 60 0 130
+0 67 0 99
+0 68 0 68
+0 70 0 36
+0 71 0 0
+1 12 217 253
+0 11 249 247
+0 9 253 188
+0 10 253 98
+0 12 254 43
+0 11 254 11
+0 19 247 0
+0 69 223 0
+0 115 204 0
+1 11 200 253
+1 6 239 251
+0 2 242 191
+0 4 239 95
+0 7 240 30
+0 12 235 0
+0 33 223 0
+0 80 214 0
+0 123 204 0
+0 13 163 253
+0 5 193 248
+0 5 193 183
+0 7 195 109
+0 10 199 43
+0 13 197 3
+0 40 198 0
+0 88 201 0
+0 130 195 0
+0 14 108 253
+0 11 126 251
+0 8 137 191
+0 10 138 122
+0 13 144 60
+0 15 150 15
+0 41 160 0
+0 90 169 0
+0 130 171 0
+0 17 64 253
+0 17 70 253
+0 14 76 207
+0 16 84 139
+0 17 91 79
+0 22 95 31
+0 36 99 0
+0 82 120 0
+0 116 130 0
+0 21 38 255
+0 20 39 253
+0 20 42 211
+0 19 46 151
+0 22 53 96
+0 24 55 48
+0 34 56 12
+0 62 68 0
+0 94 83 0
+0 22 22 255
+0 24 21 252
+0 21 19 208
+0 23 20 157
+0 22 23 106
+0 25 25 58
+0 29 31 30
+0 39 29 0
+0 68 47 0
+0 24 0 250
+0 25 0 242
+0 26 0 203
+0 27 0 160
+0 28 0 117
+0 31 2 74
+0 33 4 39
+0 35 6 11
+0 52 18 0
+0 35 0 214
+0 33 0 188
+0 34 0 168
+0 35 0 147
+0 38 0 124
+0 43 0 95
+0 47 0 64
+0 48 0 34
+0 50 0 0
+0 0 212 250
+0 0 243 251
+0 0 251 208
+0 0 249 125
+0 0 248 56
+0 3 253 23
+0 1 253 1
+0 13 244 0
+0 57 217 0
+0 0 198 255
+0 0 215 235
+0 0 215 187
+0 0 218 121
+0 0 221 53
+0 0 225 14
+0 8 221 0
+0 23 215 0
+0 62 209 0
+0 0 165 255
+0 0 179 228
+0 0 178 175
+0 0 182 125
+0 0 189 61
+0 0 192 16
+0 10 194 0
+0 30 200 0
+0 70 201 0
+0 0 116 250
+0 0 128 232
+0 0 138 177
+0 0 140 127
+0 0 145 72
+0 0 149 24
+0 9 158 0
+0 35 176 0
+0 78 183 0
+0 3 72 253
+0 0 73 243
+0 0 83 191
+0 0 90 134
+0 0 94 81
+0 2 100 36
+0 4 108 4
+0 36 133 0
+0 78 146 0
+0 6 42 253
+0 5 43 249
+0 4 47 204
+0 4 52 148
+0 4 58 97
+0 6 62 50
+0 8 65 13
+0 33 83 0
+0 70 102 0
+0 10 22 255
+0 11 23 247
+0 8 22 201
+0 7 25 154
+0 8 29 107
+0 9 32 61
+0 12 36 28
+0 22 39 0
+0 54 60 0
+0 11 7 255
+0 12 6 243
+0 10 4 200
+0 12 5 159
+0 11 7 117
+0 11 8 73
+0 14 10 38
+0 22 22 22
+0 36 26 0
+0 18 0 230
+0 18 0 198
+0 19 0 171
+0 19 0 145
+0 22 0 120
+0 22 0 91
+0 24 0 60
+0 25 0 31
+0 28 0 0
+0 0 229 255
+0 0 240 255
+0 0 242 218
+0 0 241 155
+0 0 239 88
+0 0 242 45
+0 0 246 19
+0 0 251 5
+0 0 255 0
+0 0 195 251
+0 0 193 214
+0 0 196 182
+0 0 203 142
+0 0 208 84
+0 0 212 40
+0 0 216 14
+0 0 219 0
+0 0 220 0
+0 0 163 239
+0 0 168 209
+0 0 170 172
+0 0 175 137
+0 0 180 88
+0 0 185 42
+0 0 189 14
+0 0 195 0
+0 0 200 0
+0 0 122 226
+0 0 131 204
+0 0 140 171
+0 0 145 136
+0 0 148 94
+0 0 154 49
+0 0 158 15
+0 0 168 0
+0 5 181 0
+0 0 82 224
+0 0 86 202
+0 0 96 172
+0 0 106 136
+0 0 109 98
+0 0 113 57
+0 0 119 20
+0 0 132 0
+0 11 155 0
+0 0 51 233
+0 0 53 205
+0 0 58 176
+0 0 66 143
+0 0 72 105
+0 0 76 64
+0 0 79 28
+0 0 88 0
+0 12 115 0
+0 0 28 248
+0 0 29 220
+0 0 32 179
+0 0 35 144
+0 0 39 112
+0 0 44 72
+0 0 48 35
+0 0 52 6
+0 10 73 0
+0 0 9 255
+0 0 0 236
+0 0 7 194
+0 0 8 156
+0 0 10 118
+0 0 15 77
+0 0 17 41
+0 0 19 13
+0 0 35 0
+0 0 0 255
+0 0 0 218
+0 0 0 187
+0 0 0 158
+0 0 0 124
+0 0 0 90
+0 0 0 55
+0 0 0 25
+0 0 0 0
--- /dev/null
+++ b/lib/print/dj970.map
@@ -1,0 +1,732 @@
+255 48 48 58
+57 254 183 16
+35 255 185 23
+23 255 180 22
+16 254 175 20
+10 254 173 21
+1 255 179 29
+0 255 169 18
+0 255 153 0
+60 213 12 255
+69 255 46 46
+37 255 141 33
+22 255 163 26
+14 255 165 20
+4 255 173 26
+0 255 172 24
+0 255 163 12
+0 255 150 0
+31 209 29 255
+43 255 17 206
+30 255 61 61
+17 255 122 45
+8 254 139 25
+0 255 152 20
+0 255 147 0
+0 250 144 0
+0 243 141 0
+10 204 42 255
+18 233 27 255
+28 255 25 177
+14 255 71 71
+6 254 101 45
+0 250 113 17
+0 229 113 0
+0 222 119 0
+0 221 123 0
+3 205 31 255
+2 220 34 255
+15 254 20 227
+14 255 26 148
+5 242 68 71
+0 240 77 34
+0 220 81 0
+0 203 91 0
+0 199 99 0
+2 209 16 255
+2 215 18 255
+1 241 26 255
+0 255 30 210
+4 239 32 127
+2 231 50 52
+0 226 53 18
+0 204 63 0
+0 192 77 0
+1 214 7 255
+1 215 10 255
+1 229 9 255
+0 250 7 237
+0 241 19 175
+0 231 27 102
+0 243 30 33
+0 224 35 6
+0 193 54 0
+0 214 0 250
+0 216 3 255
+0 224 0 255
+0 231 0 239
+0 229 0 194
+0 223 14 138
+0 235 12 78
+0 248 9 13
+0 210 29 0
+0 217 0 255
+0 215 0 255
+0 218 0 255
+0 220 0 242
+0 215 0 209
+0 199 0 153
+0 197 0 100
+0 226 0 54
+0 245 0 0
+71 0 247 247
+55 98 255 36
+35 221 245 26
+24 255 213 18
+17 255 192 18
+11 255 185 21
+2 254 187 29
+0 255 177 19
+0 255 161 0
+67 72 53 255
+86 119 117 120
+40 230 186 39
+20 255 185 20
+6 254 187 25
+0 254 185 23
+0 255 170 7
+0 240 156 0
+0 228 144 0
+25 162 49 255
+51 201 39 222
+41 191 90 108
+16 220 133 58
+0 244 156 29
+0 244 149 0
+0 234 144 0
+0 225 140 0
+0 220 135 0
+7 180 50 255
+16 208 37 255
+21 216 58 190
+16 197 86 104
+5 206 106 57
+0 214 110 16
+0 209 111 0
+0 208 118 0
+0 208 120 0
+4 185 32 255
+3 204 30 255
+3 237 43 240
+4 206 58 157
+0 196 77 92
+0 192 78 42
+0 189 75 0
+0 186 87 0
+0 189 97 0
+1 195 16 255
+0 207 10 255
+0 227 10 246
+0 206 27 186
+0 188 42 119
+0 185 52 64
+0 182 51 23
+0 176 56 0
+0 173 72 0
+0 200 5 255
+0 200 0 241
+0 202 0 226
+0 194 0 189
+0 185 17 141
+0 178 25 89
+0 179 31 39
+0 177 31 7
+0 171 48 0
+0 200 0 255
+0 182 0 216
+0 181 0 205
+0 180 0 188
+0 175 0 156
+0 173 8 113
+0 175 13 67
+0 181 14 20
+0 177 25 0
+0 196 0 246
+0 178 0 210
+0 175 0 201
+0 173 0 189
+0 173 0 169
+0 171 0 134
+0 168 0 89
+0 182 0 45
+0 193 0 0
+42 12 242 255
+41 38 255 116
+22 108 255 48
+20 181 255 21
+3 241 247 31
+0 254 222 25
+0 254 202 20
+0 255 188 8
+0 249 174 0
+40 46 140 255
+59 66 189 173
+29 130 211 70
+3 206 235 34
+0 234 212 8
+0 235 192 0
+0 234 178 0
+0 226 165 0
+0 217 151 0
+20 91 76 255
+45 104 78 215
+17 151 150 149
+0 191 175 95
+0 199 159 24
+0 205 150 0
+0 207 148 0
+0 205 142 0
+0 202 135 0
+8 141 54 255
+12 157 56 255
+15 169 86 193
+1 181 119 133
+0 178 117 67
+0 183 111 15
+0 189 114 0
+0 193 120 0
+0 193 120 0
+4 164 37 255
+4 175 36 255
+6 188 47 222
+0 176 70 158
+0 169 79 95
+0 166 79 42
+0 167 76 0
+0 173 89 0
+0 179 99 0
+1 176 19 255
+0 185 12 255
+0 197 16 231
+0 173 29 171
+0 163 39 115
+0 158 49 63
+0 157 49 22
+0 156 54 0
+0 158 70 0
+0 180 5 255
+0 176 0 237
+0 172 0 206
+0 163 0 170
+0 157 12 131
+0 152 20 84
+0 153 26 38
+0 151 28 7
+0 149 45 0
+0 178 0 248
+0 161 0 211
+0 156 0 190
+0 155 0 171
+0 153 0 142
+0 147 0 102
+0 149 8 60
+0 152 11 18
+0 149 21 0
+0 173 0 235
+0 156 0 202
+0 148 0 181
+0 147 0 167
+0 146 0 146
+0 146 0 122
+0 147 0 86
+0 152 0 41
+0 157 0 0
+21 26 232 255
+28 25 255 175
+17 58 255 92
+7 98 255 54
+0 162 255 19
+0 206 237 0
+0 226 215 0
+0 231 199 0
+0 229 184 0
+17 46 182 255
+31 36 232 226
+20 71 220 113
+6 111 233 42
+0 151 218 0
+0 189 204 0
+0 204 190 0
+0 207 175 0
+0 204 162 0
+14 67 117 255
+26 64 139 239
+4 115 183 179
+1 126 183 98
+0 141 170 21
+0 167 163 0
+0 185 160 0
+0 190 152 0
+0 188 142 0
+6 88 74 255
+12 94 73 255
+22 107 97 186
+0 132 131 129
+0 138 126 67
+0 148 119 13
+0 162 122 0
+0 173 125 0
+0 175 122 0
+1 125 46 255
+2 135 47 255
+7 138 56 214
+0 136 78 157
+0 135 84 97
+0 136 83 42
+0 142 82 0
+0 155 94 0
+0 162 101 0
+0 148 25 255
+0 155 22 255
+0 157 25 226
+0 141 34 167
+0 133 43 115
+0 132 50 65
+0 133 51 22
+0 136 57 0
+0 144 74 0
+0 154 7 255
+0 150 0 239
+0 144 0 206
+0 138 0 166
+0 134 14 127
+0 130 20 84
+0 130 26 38
+0 129 29 6
+0 131 44 0
+0 153 0 242
+0 139 0 209
+0 134 0 189
+0 134 0 163
+0 132 0 133
+0 127 0 99
+0 127 5 57
+0 129 9 17
+0 127 19 0
+0 150 0 226
+0 135 0 199
+0 130 0 179
+0 129 0 157
+0 128 0 137
+0 127 0 115
+0 126 0 83
+0 126 0 41
+0 128 0 0
+3 36 226 255
+18 18 255 208
+11 32 255 131
+0 65 255 76
+0 68 255 21
+0 125 241 0
+0 168 222 0
+0 196 210 0
+0 205 195 0
+5 38 193 255
+10 36 243 245
+10 35 234 145
+4 62 223 69
+0 79 219 9
+0 121 209 0
+0 160 202 0
+0 181 189 0
+0 187 174 0
+6 47 148 255
+8 49 171 249
+0 74 192 189
+0 76 183 106
+0 84 181 35
+0 112 175 0
+0 148 173 0
+0 168 166 0
+0 172 154 0
+3 66 100 255
+9 67 109 249
+7 77 126 194
+0 88 137 138
+0 92 138 69
+0 106 130 11
+0 133 133 0
+0 151 136 0
+0 157 131 0
+0 77 61 255
+0 91 67 255
+0 91 74 213
+0 99 93 162
+0 98 97 95
+0 105 92 42
+0 115 90 0
+0 131 101 0
+0 142 106 0
+0 103 28 255
+0 111 27 255
+0 113 34 222
+0 106 42 168
+0 102 50 117
+0 104 56 68
+0 107 55 22
+0 114 62 0
+0 126 77 0
+0 125 7 255
+0 122 0 244
+0 119 0 214
+0 112 10 171
+0 108 17 125
+0 105 23 84
+0 105 28 40
+0 106 30 6
+0 112 46 0
+0 130 0 239
+0 118 0 210
+0 114 0 191
+0 112 0 165
+0 110 0 129
+0 106 0 94
+0 100 0 52
+0 105 9 17
+0 106 18 0
+0 128 0 217
+0 118 0 197
+0 114 0 180
+0 112 0 158
+0 112 0 133
+0 108 0 108
+0 105 0 79
+0 104 0 41
+0 104 0 0
+2 22 221 255
+2 29 255 235
+0 30 255 174
+0 29 255 89
+0 34 254 23
+0 43 246 0
+0 101 230 0
+0 143 218 0
+0 173 209 0
+2 22 199 255
+1 25 235 249
+0 24 238 179
+0 29 222 89
+0 39 216 27
+0 57 209 0
+0 102 206 0
+0 134 199 0
+0 159 188 0
+2 30 166 255
+2 29 186 251
+0 33 186 185
+0 35 179 110
+0 45 179 49
+0 52 175 0
+0 96 180 0
+0 127 177 0
+0 148 168 0
+0 43 119 255
+0 43 130 255
+0 45 139 199
+0 47 140 136
+0 51 141 76
+0 57 140 18
+0 89 144 0
+0 120 148 0
+0 136 143 0
+0 53 76 255
+0 57 82 250
+0 57 90 203
+0 58 96 152
+0 60 101 101
+0 66 102 44
+0 78 98 0
+0 107 109 0
+0 123 113 0
+0 53 38 255
+0 64 39 255
+0 68 45 215
+0 69 54 167
+0 69 62 121
+0 68 68 66
+0 78 64 22
+0 90 69 0
+0 105 80 0
+0 81 12 255
+0 85 9 255
+0 84 12 217
+0 81 19 170
+0 78 24 127
+0 78 29 86
+0 79 33 42
+0 80 33 5
+0 90 48 0
+0 101 0 242
+0 94 0 213
+0 89 0 191
+0 86 0 164
+0 83 0 129
+0 79 0 91
+0 80 5 56
+0 81 11 19
+0 83 19 0
+0 108 0 212
+0 98 0 194
+0 94 0 177
+0 92 0 156
+0 90 0 131
+0 87 0 102
+0 83 0 73
+0 80 0 40
+0 81 0 0
+1 11 216 255
+0 15 249 246
+0 11 255 191
+0 11 255 111
+0 12 255 36
+0 14 247 0
+0 28 238 0
+0 82 226 0
+0 124 218 0
+0 10 201 255
+0 3 226 249
+0 0 220 183
+0 0 212 105
+0 11 210 40
+0 15 201 0
+0 41 202 0
+0 84 203 0
+0 118 200 0
+0 16 173 255
+0 7 184 248
+0 0 176 179
+0 8 175 117
+0 13 174 55
+0 20 173 9
+0 42 177 0
+0 81 182 0
+0 111 180 0
+0 21 128 255
+0 16 136 250
+0 15 137 192
+0 16 139 133
+0 19 140 80
+0 25 144 28
+0 39 146 0
+0 76 154 0
+0 106 155 0
+0 29 86 255
+0 27 89 245
+0 26 95 197
+0 26 100 148
+0 28 105 100
+0 30 107 48
+0 37 109 6
+0 69 118 0
+0 97 122 0
+0 35 48 255
+1 37 50 239
+0 36 56 198
+0 34 62 156
+0 35 67 114
+0 37 72 73
+0 42 74 23
+0 60 78 0
+0 83 86 0
+0 37 23 255
+0 44 20 249
+0 44 24 210
+0 44 27 168
+0 44 33 128
+0 44 38 90
+0 40 40 39
+0 53 41 6
+0 67 51 0
+0 60 0 251
+0 57 0 228
+0 55 0 197
+0 53 0 165
+0 50 0 127
+0 53 7 95
+0 53 10 58
+0 55 13 20
+0 59 21 0
+0 78 0 217
+0 74 0 194
+0 71 0 174
+0 69 0 153
+0 67 0 130
+0 63 0 100
+0 59 0 69
+0 56 0 38
+0 58 0 0
+0 4 213 255
+0 0 241 250
+0 0 255 214
+0 0 255 143
+0 0 250 68
+0 0 249 15
+0 4 244 0
+0 17 238 0
+0 66 229 0
+0 0 199 255
+0 0 201 226
+0 0 200 186
+0 0 202 132
+0 0 202 69
+0 0 201 20
+0 7 198 0
+0 25 199 0
+0 66 204 0
+0 0 171 255
+0 0 171 226
+0 0 168 177
+0 0 171 131
+0 0 172 78
+0 0 171 25
+0 7 170 0
+0 28 176 0
+0 65 183 0
+0 3 132 255
+0 0 133 232
+0 0 134 183
+0 0 136 134
+0 0 139 89
+0 0 138 36
+0 7 142 0
+0 29 152 0
+0 64 161 0
+0 9 93 255
+0 5 93 235
+0 0 93 188
+0 0 99 142
+0 0 104 97
+0 0 108 53
+0 8 114 11
+0 26 120 0
+0 59 128 0
+0 19 58 255
+0 16 57 228
+0 12 60 190
+0 9 66 151
+0 10 72 112
+0 11 77 71
+0 12 80 27
+0 22 85 0
+0 52 93 0
+0 26 30 255
+0 25 30 227
+0 19 30 193
+0 17 33 156
+0 16 38 121
+0 16 43 84
+0 17 48 45
+0 21 50 6
+0 43 58 0
+0 22 11 255
+0 22 6 233
+0 21 7 200
+0 21 7 166
+0 22 11 131
+0 23 13 96
+0 23 16 60
+0 20 20 19
+0 35 26 0
+0 37 0 240
+0 36 0 201
+0 34 0 178
+0 36 0 154
+0 37 0 130
+0 35 0 101
+0 32 0 70
+0 31 0 38
+0 34 0 0
+0 0 222 255
+0 0 237 255
+0 0 255 233
+0 0 255 178
+0 0 249 112
+0 0 255 61
+0 0 255 25
+0 0 255 6
+0 0 255 0
+0 0 197 255
+0 0 186 210
+0 0 191 188
+0 0 197 155
+0 0 200 106
+0 0 203 59
+0 0 205 27
+0 0 206 9
+0 0 208 0
+0 0 169 242
+0 0 160 204
+0 0 161 174
+0 0 167 144
+0 0 171 106
+0 0 173 60
+0 0 174 26
+0 0 175 6
+0 0 177 0
+0 0 132 226
+0 0 132 205
+0 0 134 176
+0 0 139 141
+0 0 143 108
+0 0 144 67
+0 0 145 26
+0 0 147 0
+0 0 152 0
+0 0 98 222
+0 0 99 201
+0 0 103 177
+0 0 109 144
+0 0 115 111
+0 0 116 74
+0 0 118 32
+0 0 120 0
+0 0 126 0
+0 0 62 243
+0 0 63 208
+0 0 68 176
+0 0 73 143
+0 0 81 113
+0 0 84 78
+0 0 86 41
+0 0 90 9
+0 0 97 0
+0 0 25 244
+0 0 28 213
+0 0 33 187
+0 0 39 146
+0 0 45 116
+0 0 51 84
+0 0 54 48
+0 0 58 14
+0 0 66 0
+0 0 0 242
+0 0 0 207
+0 0 2 191
+0 0 7 160
+0 0 11 123
+0 0 18 92
+0 0 22 56
+0 0 25 23
+0 0 33 0
+0 0 0 255
+0 0 0 212
+0 0 0 185
+0 0 0 157
+0 0 0 130
+0 0 0 106
+0 0 0 71
+0 0 0 37
+0 0 0 0
+0 0 0 0
+0 0 0 0
+0 0 0 0
--- /dev/null
+++ b/lib/print/paper.cfg
@@ -1,0 +1,8 @@
+A4=
+ hpcode=26
+ width_inches=8.3
+ height_inches=11.7
+A5=
+ hpcode=25
+ width_inches=4.15
+ height_inches=5.85
--- /dev/null
+++ b/lib/print/pmode.cfg
@@ -1,0 +1,7 @@
+HPnormal=
+ desc=300x300 dpi
+ resx=300
+ resy=300
+ blackdepth=1
+ coldepth=1
+ blackresmult=1
--- /dev/null
+++ b/lib/print/popt.cfg
@@ -1,0 +1,10 @@
+printer0=
+ duplex=0
+ orientation=1
+ paper=A4
+ mode=HPnormal
+testprinter=
+ duplex=0
+ orientation=1
+ paper=A4
+ mode=HPnormal
--- /dev/null
+++ b/lib/print/printer.cfg
@@ -1,0 +1,6 @@
+printer0=
+ ptype=HP Deskjet 970
+ device=/dev/lpt1data
+testprinter=
+ ptype=HP Deskjet 970
+ device=/tmp/printer.out
--- /dev/null
+++ b/lib/print/ptype.cfg
@@ -1,0 +1,4 @@
+HP Deskjet 970=
+ driver=hp_driver.dis
+ hpmapfile=dj970
+ modes=HPnormal
--- /dev/null
+++ b/lib/proto/FreeBSD
@@ -1,0 +1,19 @@
+FreeBSD
+ 386
+ bin
+ emu.new 0775 inferno inferno /FreeBSD/386/bin/emu
+ asm
+ iar
+ data2c
+ data2s
+ ksize
+ kstrip
+ limbo
+ mk
+ mkext
+ ndate
+ inm
+ iyacc
+ include
+ +
+ lib
--- /dev/null
+++ b/lib/proto/Hp
@@ -1,0 +1,46 @@
+Hp
+ s800
+ bin
+ emu.new 0775 inferno inferno /Linux/386/bin/emu
+ 0a
+ 0c
+ 0l
+ 5a
+ 5c
+ 5cv
+ 5coff
+ 5l
+ 8a
+ 8c
+ 8l
+ acid
+ asm
+ data2c
+ iar
+ data2s
+ ka
+ kc
+ kl
+ ksize
+ kstrip
+
+ limbo
+ mk
+ mkppcimage
+ mkext
+ ms2
+ ndate
+ inm
+ qa
+ qc
+ ql
+ sqz
+ srclist
+ tc
+ va
+ vc
+ vl
+ iyacc
+ include
+ +
+ lib
--- /dev/null
+++ b/lib/proto/Irix
@@ -1,0 +1,54 @@
+Irix
+ mips
+ bin
+ emu.new 0775 inferno inferno /Irix/mips/bin/emu
+ 0a
+ 0c
+ 0l
+ 1a
+ 1c
+ 1l
+ 2a
+ 2c
+ 2l
+ 5a
+ 5c
+ 5cv
+ 5coff
+ 5l
+ 8a
+ 8c
+ 8l
+ acid
+ asm
+ awk
+ data2c
+ data2s
+ ftl
+ iar
+ ka
+ kc
+ kl
+ ksize
+ kstrip
+
+ limbo
+ mk
+ mkppcimage
+ mkext
+ ms2
+ ndate
+ inm
+ qa
+ qc
+ ql
+ sqz
+ srclist
+ tc
+ va
+ vc
+ vl
+ iyacc
+ include
+ +
+ lib
--- /dev/null
+++ b/lib/proto/Linux
@@ -1,0 +1,40 @@
+Linux
+ 386
+ bin
+ emu.new 0775 inferno inferno /Linux/386/bin/emu
+ asm
+ iar
+ data2c
+ data2s
+ ksize
+ kstrip
+ limbo
+ mk
+ mkext
+ ndate
+ iyacc
+ include
+ +
+ lib
+ arm
+ bin
+ include
+ +
+ lib
+ power
+ bin
+ emu.new 0775 inferno inferno /Linux/power/bin/emu
+ data2c
+ mk
+ limbo
+ mkext
+ ndate
+ iyacc
+ include
+ +
+ lib
+ spim
+ bin
+ include
+ +
+ lib
--- /dev/null
+++ b/lib/proto/MacOSX
@@ -1,0 +1,47 @@
+MacOSX
+ README
+ power
+ bin
+ emu.new 0775 inferno inferno /MacOSX/power/bin/emu
+ asm
+ iar
+ data2c
+ data2s
+ ksize
+ kstrip
+
+ limbo
+ mk
+ mkext
+ ms2
+ ndate
+ inm
+ sqz
+ srclist
+ iyacc
+ include
+ +
+ lib
+ tcshrc
+ 386
+ bin
+ emu.new 0775 inferno inferno /MacOSX/386/bin/emu
+ asm
+ iar
+ data2c
+ data2s
+ ksize
+ kstrip
+
+ limbo
+ mk
+ mkext
+ ms2
+ ndate
+ inm
+ sqz
+ srclist
+ iyacc
+ include
+ +
+ lib
--- /dev/null
+++ b/lib/proto/NetBSD
@@ -1,0 +1,19 @@
+NetBSD
+ 386
+ bin
+ emu.new 0775 inferno inferno /NetBSD/386/bin/emu
+ asm
+ iar
+ data2c
+ data2s
+ ksize
+ kstrip
+ limbo
+ mk
+ mkext
+ ndate
+ inm
+ iyacc
+ include
+ +
+ lib
--- /dev/null
+++ b/lib/proto/Nt
@@ -1,0 +1,63 @@
+Nt
+ 386
+ bin
+ emu.new 0775 inferno inferno /Nt/386/bin/emu.exe
+ ie.exe
+ 0a.exe
+ 0c.exe
+ 0l.exe
+ 5a.exe
+ 5c.exe
+ 5cv.exe
+ 5coff.exe
+ 5l.exe
+ 8a.exe
+ 8c.exe
+ 8l.exe
+ acid.exe
+ asm.exe
+ awk.exe
+ iar.exe
+ c2l.exe
+ cp.exe
+ data2c.exe
+ data2s.exe
+ echo.exe
+ format.exe
+ gzip.exe
+ infdb.exe
+ inm.exe
+ ka.exe
+ kc.exe
+ kl.exe
+ ksize.exe
+ kstrip.exe
+ limbo.exe
+ mk.exe
+ mkdir.exe
+ mkppcimage.exe
+ mkext.exe
+ ms2.exe
+ mv.exe
+ ndate.exe
+ ntsrv.exe
+ ntsrv4.exe
+ odbc.exe
+ qa.exe
+ qc.exe
+ ql.exe
+ rcsh.exe
+ rm.exe
+ sed.exe
+ sqz.exe
+ srclist.exe
+ tc.exe
+ test.exe
+ tr.exe
+ va.exe
+ vc.exe
+ vl.exe
+ iyacc.exe
+ include
+ +
+ lib
--- /dev/null
+++ b/lib/proto/Plan9
@@ -1,0 +1,36 @@
+Plan9
+ 386
+ bin
+ emu.new 775 inferno inferno /Plan9/386/bin/emu
+ 5a
+ 5c
+ 5l
+ asm
+ data2c
+ data2s
+ iar
+ limbo
+ inm
+ include
+ lib9.h
+ u.h
+ lib
+ mips
+ bin
+ include
+ lib9.h
+ u.h
+ lib
+ sparc
+ bin
+ include
+ lib9.h
+ os.h
+ u.h
+ lib
+ power
+ bin
+ include
+ lib9.h
+ u.h
+ lib
--- /dev/null
+++ b/lib/proto/Solaris
@@ -1,0 +1,46 @@
+Solaris
+ sparc
+ bin
+ emu.new 0775 inferno inferno /Solaris/sparc/bin/emu
+ 0a
+ 0c
+ 0l
+ 5a
+ 5c
+ 5cv
+ 5coff
+ 5l
+ 8a
+ 8c
+ 8l
+ acid
+ asm
+ iar
+ data2c
+ data2s
+ ka
+ kc
+ kl
+ ksize
+ kstrip
+
+ limbo
+ mk
+ mkppcimage
+ mkext
+ ms2
+ ndate
+ inm
+ qa
+ qc
+ ql
+ sqz
+ srclist
+ tc
+ va
+ vc
+ vl
+ iyacc
+ include
+ +
+ lib
--- /dev/null
+++ b/lib/proto/inferno
@@ -1,0 +1,2443 @@
+CHANGES
+LICENCE
+NOTICE
+FreeBSD
+ 386
+ bin
+ include
+ lib
+Hp
+ s800
+ bin
+ include
+ lib
+Irix
+ mips
+ bin
+ include
+ lib
+Linux
+ 386
+ bin
+ include
+ lib
+ arm
+ bin
+ include
+ lib
+ power
+ bin
+ include
+ lib
+ spim
+ bin
+ include
+ lib
+MacOSX
+ 386
+ bin
+ include
+ lib
+ power
+ bin
+ include
+ lib
+Nt
+ 386
+ bin
+ include
+ lib
+Plan9
+ 386
+ bin
+ include
+ lib
+ sparc
+ bin
+ include
+ lib
+ mips
+ bin
+ include
+ lib
+ power
+ bin
+ include
+ lib
+Solaris
+ sparc
+ bin
+ include
+ lib
+include
+ NOTICE
+ a.out.h
+ cursor.h
+ draw.h
+ drawif.h
+ dynld.h
+ fcall.h
+ freetype.h
+ freetype
+ +
+ interp.h
+ isa.h
+ kernel.h
+ keyboard.h
+ libsec.h
+ mathi.h
+ memdraw.h
+ memlayer.h
+ mp.h
+ pool.h
+ pooldefs.h
+ prefab.h
+ raise.h
+ rdbg.h
+ styx.h
+ tk.h
+ version.h
+ vm.h
+acme
+ +
+appl
+ NOTICE
+ acme
+ acme
+ acid
+ guide
+ mkfile
+ readme
+ src
+ Acid.b
+ Acid0.b
+ mkfile
+ bin
+ guide
+ mkfile
+ readme
+ src
+ adiff.b
+ agrep.b
+ awd.b
+ cd.b
+ mkfile
+ new.b
+ spout.b
+ win.b
+ winm.b
+ edit
+ guide
+ mkfile
+ readme
+ src
+ a.b
+ c.b
+ d.b
+ e.b
+ findfile.b
+ g.b
+ i.b
+ input.b
+ mkfile
+ p.b
+ pipe.b
+ x.b
+ xxx.b
+ guide
+ mkbox.b
+ mkfile
+ readme
+ src
+ Mail.b
+ Mailp.b
+ Mailpop3.b
+ mashfile
+ mkfile
+ mkfile
+ acme.b
+ acme.m
+ buff.b
+ buff.m
+ col.b
+ col.m
+ common.m
+ dat.b
+ dat.m
+ disk.b
+ disk.m
+ ecmd.b
+ ecmd.m
+ edit.b
+ edit.m
+ elog.b
+ elog.m
+ exec.b
+ exec.m
+ file.b
+ file.m
+ frame.b
+ frame.m
+ fsys.b
+ fsys.m
+ graph.b
+ graph.m
+ gui.b
+ gui.m
+ look.b
+ look.m
+ mkfile
+ regx.b
+ regx.m
+ row.b
+ row.m
+ scrl.b
+ scrl.m
+ styxaux.b
+ styxaux.m
+ text.b
+ text.m
+ time.b
+ time.m
+ util.b
+ util.m
+ wind.b
+ wind.m
+ xfid.b
+ xfid.m
+ alphabet
+ abc
+ abc.b
+ autoconvert.b
+ autodeclare.b
+ declare.b
+ declares.b
+ define.b
+ eval.b
+ import.b
+ mkfile
+ newtypeset.b
+ rewrite.b
+ type.b
+ typeset.b
+ undeclare.b
+ alphabet.b
+ alphabet.shmod.b
+ auxi
+ endpoints.b
+ endpointsrv.b
+ fsfilter.b
+ mkfile
+ rexecsrv.b
+ eval.b
+ extvalues.b
+ fs
+ and.b
+ bundle.b
+ bundle.m
+ chstat.b
+ compose.b
+ depth.b
+ entries.b
+ exec.b
+ filter.b
+ ls.b
+ match.b
+ merge.b
+ mergewrite.b
+ mkext.b
+ mkfile
+ mode.b
+ newer.b
+ not.b
+ or.b
+ path.b
+ pipe.b
+ print.b
+ proto.b
+ query.b
+ run.b
+ select.b
+ setroot.b
+ size.b
+ unbundle.b
+ unbundle.m
+ walk.b
+ write.b
+ grid
+ farm.b
+ line2rec.b
+ local.b
+ mkfile
+ remote.b
+ rexec.b
+ main
+ auth.b
+ cat.b
+ create.b
+ dial.b
+ echo.b
+ export.b
+ fd.b
+ filter.b
+ genfilter.b
+ mkfile
+ mount.b
+ par.b
+ parse.b
+ pretty.b
+ print.b
+ read.b
+ readall.b
+ rewrite.b
+ rw.b
+ seq.b
+ unparse.b
+ w2fd.b
+ wait.b
+ mkfile
+ proxy.b
+ reports.b
+ typesets
+ abc.b
+ abctypes.b
+ fs.b
+ fstypes.b
+ grid.b
+ gridtypes.b
+ mkfile
+ declare.sh
+ fsdecl.sh
+ getendpoint.sh
+ mkendpoint.sh
+ rexecsrv.sh
+ setup
+ newtypesets
+ alphabet.proto
+ charon
+ build.b
+ build.m
+ charon.b
+ charon.m
+ chutils.b
+ chutils.m
+ common.m
+ cookiesrv.b
+ cookiesrv.m
+ ctype.b
+ ctype.m
+ date.b
+ date.m
+ event.b
+ event.m
+ file.b
+ ftp.b
+ gui.b
+ gui.m
+ http.b
+ img.b
+ img.m
+ jscript.b
+ layout.b
+ layout.m
+ lex.b
+ lex.m
+ mkfile
+ paginate.b
+ paginate.m
+ rgb.inc
+ script.m
+ transport.m
+ url.b
+ url.m
+ xxx.inc
+ ycbcr.inc
+ cmd
+ 9win.b
+ 9660srv.b
+ 9export.b
+ 9srvfs.b
+ B.b
+ ar.b
+ archfs.b
+ auplay.b
+ auth
+ aescbc.b
+ changelogin.b
+ countersigner.b
+ convpasswd.b
+ createsignerkey.b
+ dsagen.b
+ factotum
+ authio.m
+ mkfile
+ factotum.b
+ feedkey.b
+ proto
+ infauth.b
+ keyreps.b
+ keyreps.m
+ mkfile
+ p9any.b
+ pass.b
+ rpc.b
+ getpk.b
+ keyfs.b
+ keysrv.b
+ logind.b
+ mkauthinfo.b
+ mkfile
+ passwd.b
+ rsagen.b
+ secstore.b
+ signer.b
+ verify.b
+ auxi
+ cpuslave.b
+ digest.b
+ fpgaload.b
+ mangaload.b
+ mkfile
+ pcmcia.b
+ rdbgsrv.b
+ rstyxd.b
+ avr
+ burn.b
+ mkfile
+ basename.b
+ bind.b
+ bit2gif.b
+ broke.b
+ bytes.b
+ cal.b
+ calc.b
+ cat.b
+ cd.b
+ cddb.b
+ chgrp.b
+ chmod.b
+ cleanname.b
+ cmp.b
+ comm.b
+ cook.b
+ cp.b
+ cprof.b
+ cpu.b
+ crypt.b
+ date.b
+ dbfs.b
+ dbm
+ delete.b
+ fetch.b
+ keys.b
+ list.b
+ mkfile
+ store.b
+ dd.b
+ dial.b
+ diff.b
+ disdep.b
+ disdump.b
+ disk
+ format.b
+ ftl.b
+ kfs.b
+ kfscmd.b
+ mbr.b
+ mkext.b
+ mkfile
+ mkfs.b
+ prep
+ calc.tab.b
+ calc.tab.m
+ calc.y
+ fdisk.b
+ mkfile
+ pedit.b
+ pedit.m
+ prep.b
+ dossrv.b
+ du.b
+ echo.b
+ ed.b
+ emuinit.b
+ env.b
+ export.b
+ fc.b
+ fcp.b
+ fmt.b
+ fone.b
+ fortune.b
+ freq.b
+ fs.b
+ fs
+ and.b
+ bundle.b
+ chstat.b
+ compose.b
+ depth.b
+ entries.b
+ eval.b
+ exec.b
+ filter.b
+ ls.b
+ match.b
+ merge.b
+ mergewrite.b
+ mkfile
+ mode.b
+ not.b
+ or.b
+ path.b
+ pipe.b
+ print.b
+ proto.b
+ query.b
+ readfile.b
+ run.b
+ select.b
+ setroot.b
+ size.b
+ template.b
+ unbundle.b
+ void.b
+ walk.b
+ write.b
+ ftest.b
+ ftpfs.b
+ getauthinfo.b
+ getfile.b
+ gettar.b
+ gif2bit.b
+ grep.b
+ gunzip.b
+ gzip.b
+ idea.b
+ import.b
+ install
+ NOTICE
+ applylog.b
+ arch.b
+ arch.m
+ archfs.b
+ archfs.m
+ ckproto.b
+ create.b
+ eproto.b
+ info.b
+ inst.b
+ install.b
+ log.b
+ logs.b
+ logs.m
+ mergelog.b
+ mkfile
+ mkproto.b
+ proto.b
+ proto.m
+ proto2list.b
+ protocaller.m
+ updatelog.b
+ wdiff.b
+ wfind.b
+ wrap.b
+ wrap.m
+ wrap2list.b
+ iostats.b
+ ip
+ bootpd.b
+ dhcp.b
+ mkfile
+ nppp
+ mkfile
+ modem.b
+ modem.m
+ pppchat.b
+ ppplink.b
+ ppptest.b
+ script.b
+ script.m
+ ping.b
+ ppp
+ mkfile
+ modem.b
+ modem.m
+ pppclient.b
+ pppclient.m
+ pppdial.b
+ pppgui.b
+ pppgui.m
+ ppptest.b
+ script.b
+ script.m
+ rip.b
+ sntp.b
+ tftpd.b
+ virgild.b
+ irtest.b
+ itest.b
+ itreplay.b
+ kill.b
+ lego
+ clock.b
+ clockface.b
+ firmdl.b
+ link.b
+ mkfile
+ rcxsend.b
+ rcxsend.m
+ send.b
+ timers.b
+ timers.m
+ limbo
+ arg.m
+ asm.b
+ com.b
+ decls.b
+ dis.b
+ disoptab.m
+ ecom.b
+ gen.b
+ isa.m
+ lex.b
+ limbo.b
+ limbo.m
+ limbo.y
+ mkfile
+ nodes.b
+ opname.m
+ optim.b
+ sbl.b
+ stubs.b
+ typecheck.b
+ types.b
+ listen.b
+ lockfs.b
+ logfile.b
+ look.b
+ ls.b
+ lstar.b
+ m4.b
+ man2html.b
+ man2txt.b
+ manufacture.b
+ mash
+ builtins.b
+ depends.b
+ dump.b
+ exec.b
+ expr.b
+ eyacc.b
+ eyaccpar
+ history.b
+ lex.b
+ make.b
+ mash.b
+ mash.m
+ mash.y
+ mashfile
+ mashlib.b
+ mashparse.b
+ mashparse.m
+ misc.b
+ mkfile
+ serve.b
+ symb.b
+ tk.b
+ xeq.b
+ mc.b
+ md5sum.b
+ mdb.b
+ memfs.b
+ metamorph.b
+ mk
+ ar.m
+ mk.b
+ mkbinds
+ mkconfig
+ mkfile
+ mksubdirs
+ mkdir.b
+ mkfile
+ mntgen.b
+ mount.b
+ mouse.b
+ mpc
+ mkfile
+ qconfig.b
+ qflash.b
+ mprof.b
+ mv.b
+ ndb
+ mkfile
+ cs.b
+ csquery.b
+ dns.b
+ dnsquery.b
+ mkhash.b
+ query.b
+ registry.b
+ regquery.b
+ netkey.b
+ netstat.b
+ newer.b
+ ns.b
+ nsbuild.b
+ os.b
+ p.b
+ palm
+ connex.b
+ desklink.b
+ desklink.m
+ mkfile
+ palmsrv.b
+ pause.b
+ plumb.b
+ plumber.b
+ prof.b
+ promptstring.b
+ ps.b
+ puttar.b
+ pwd.b
+ ramfile.b
+ randpass.b
+ raw2iaf.b
+ rawdbfs.b
+ rcmd.b
+ rdp.b
+ read.b
+ rioimport.b
+ rm.b
+ runas.b
+ sed.b
+ sendmail.b
+ sh
+ arg.b
+ csv.b
+ doc
+ History
+ echo.b
+ expr.b
+ file2chan.b
+ mload.b
+ mkfile
+ mpexpr.b
+ regex.b
+ sexprs.b
+ sh.b
+ sh.y
+ std.b
+ string.b
+ test.b
+ tk.b
+ sha1sum.b
+ sleep.b
+ sort.b
+ spki
+ mkfile
+ verify.b
+ src.b
+ stack.b
+ stackv.b
+ stream.b
+ strings.b
+ styxchat.b
+ styxlisten.b
+ styxmon.b
+ sum.b
+ tail.b
+ tarfs.b
+ tclsh.b
+ tcs.b
+ tee.b
+ telnet.b
+ test.b
+ time.b
+ timestamp.b
+ tkcmd.b
+ tokenize.b
+ touch.b
+ touchcal.b
+ tr.b
+ trfs.b
+ tsort.b
+ unicode.b
+ units.b
+ units.y
+ uniq.b
+ unmount.b
+ usb
+ usbd.b
+ mkfile
+ uuencode.b
+ uudecode.b
+ vacfs.b
+ vacget.b
+ vacput.b
+ wav2iaf.b
+ wc.b
+ webgrab.b
+ wish.b
+ wmimport.b
+ wmexport.b
+ xargs.b
+ xd.b
+ xmount.b
+ yacc.b
+ zeros.b
+ collab
+ clients
+ chat.b
+ poll.b
+ poller.b
+ whiteboard.b
+ collabsrv.b
+ connect.b
+ lib
+ messages.b
+ messages.m
+ mkfile
+ proxy.b
+ proxy.m
+ runcollab
+ servers
+ chatsrv.b
+ memfssrv.b
+ mpx.b
+ wbsrv.b
+ service.m
+ srvmgr.b
+ srvmgr.m
+ demo
+ camera
+ camera.b
+ camload.bit
+ camproc.bit
+ mkfile
+ runcam.sh
+ runcamlocal.sh
+ tkinterface.b
+ chat
+ chat.b
+ chatclient.sh
+ chatsrv.b
+ mkfile
+ cpupool
+ mkfile
+ regpoll.b
+ runrstyx.sh
+ lego
+ clockface.b
+ clockreg.sh
+ firmdl.b
+ legolink.b
+ mkfile
+ rcxsend.b
+ rcxsend.m
+ styx.srec
+ timers.b
+ timers.m
+ mkfile
+ ns
+ mkfile
+ ns.b
+ runns.sh
+ odbc
+ mkfile
+ odbcmnt.b
+ runodbc.sh
+ spree
+ mkfile
+ spreeclient.sh
+ whiteboard
+ mkfile
+ runwb.sh
+ wbsrv.b
+ whiteboard.b
+ ebook
+ checkxml.b
+ cssfont.b
+ cssfont.m
+ cssparser.b
+ cssparser.m
+ dtd
+ *
+ ebook.b
+ mimeimage.b
+ mimeimage.m
+ mkfile
+ oebpackage.b
+ oebpackage.m
+ reader.b
+ reader.m
+ strcache.m
+ strmap.b
+ strmap.m
+ stylesheet.b
+ stylesheet.m
+ table.b
+ table.m
+ tst.txt
+ understandingoeb.opf
+ units.b
+ units.m
+ grid
+ README
+ demo
+ block.b
+ blur.b
+ mkfile
+ lib
+ announce.b
+ browser.b
+ browser.m
+ fbrowse.b
+ mkfile
+ pathreader.m
+ srvbrowse.b
+ mkfile
+ blurdemo.b
+ cpupool.b
+ find.b
+ jpg2bit.b
+ query.b
+ readjpg.b
+ register.b
+ reglisten.b
+ regstyxlisten.b
+ remotelogon.b
+ usercreatesrv.b
+ lib
+ NOTICE
+ arg.b
+ asn1.b
+ attrdb.b
+ attrhash.b
+ auth.b
+ auth9.b
+ bloomfilter.b
+ bufio.b
+ cfg.b
+ cfgfile.b
+ chanfill.b
+ complete.b
+ convcs
+ 8bit_stob.b
+ big5_btos.b
+ big5_stob.b
+ convcs.b
+ cp_btos.b
+ cp_stob.b
+ cp932_btos.b
+ euc-jp_btos.b
+ gb2312_btos.b
+ genbig5.b
+ gencp.b
+ gencp932.b
+ gengb2312.b
+ genjisx0201kana.b
+ genjisx0208-1997.b
+ genjisx0212.b
+ ibm437.b
+ ibm850.b
+ ibm866.b
+ iso8859-1.b
+ iso8859-10.b
+ iso8859-15.b
+ iso8859-2.b
+ iso8859-3.b
+ iso8859-4.b
+ iso8859-5.b
+ iso8859-6.b
+ iso8859-7.b
+ iso8859-8.b
+ iso8859-9.b
+ koi8-r.b
+ mkdata
+ mkfile
+ utf8_btos.b
+ utf8_stob.b
+ utf16_btos.b
+ utf16_stob.b
+ windows-1250.b
+ windows-1251.b
+ windows-1252.b
+ crc.b
+ crypt
+ mkfile
+ pkcs.b
+ ssl3.b
+ sslsession.b
+ x509.b
+ csv.b
+ daytime.b
+ db.b
+ dbm.b
+ dbsrv.b
+ debug.b
+ deflate.b
+ devpointer.b
+ dhcpclient.b
+ dial.b
+ dialog.b
+ dict.b
+ dis.b
+ diskblocks.b
+ disks.b
+ dividers.b
+ ecmascript
+ builtin.b
+ date.b
+ ecmascript.b
+ exec.b
+ mkfile
+ obj.b
+ pprint.b
+ regexp.b
+ uri.b
+ encoding
+ base16.b
+ base32.b
+ base32a.b
+ base64.b
+ mkfile
+ env.b
+ ether.b
+ exception.b
+ factotum.b
+ filepat.b
+ format.b
+ fsfilter.b
+ fslib.b
+ fsproto.b
+ gamer.b
+ hash.b
+ html.b
+ ida
+ NOTICE
+ ida.b
+ idatab.b
+ idatest.b
+ mkfile
+ mktab.b
+ idatab.dis
+ imageremap.b
+ inflate.b
+ ip.b
+ ipattr.b
+ ir.b
+ irmpath.b
+ irsage.b
+ irsim.b
+ itslib.b
+ json.b
+ keyset.b
+ libc.b
+ libc0.b
+ lists.b
+ lock.b
+ login.b
+ man.b
+ memfs.b
+ mkfile
+ mpeg.b
+ msgio.b
+ nametree.b
+ names.b
+ newns.b
+ palm.b
+ palmdb.b
+ palmfile.b
+ parseman.b
+ plumbing.b
+ plumbing.m
+ plumbmsg.b
+ pop3.b
+ popup.b
+ powerman.b
+ hp_driver.b
+ mkfile
+ print.b
+ scaler.b
+ scaler.m
+ profile.b
+ pslib.b
+ quicktime.b
+ rand.b
+ random.b
+ readdir.b
+ readgif.b
+ readjpg.b
+ readpicfile.b
+ readpng.b
+ readxbitmap.b
+ regex.b
+ regexutils.b
+ registries.b
+ rfc822.b
+ riff.b
+ secstore.b
+ scoretable.b
+ scsiio.b
+ selectfile.b
+ sets.b
+ sets32.b
+ sexprs.b
+ slip.b
+ smtp.b
+ sort.b
+ spki
+ mkfile
+ spki.b
+ verifier.b
+ strokes
+ buildstrokes.b
+ mkfile
+ readstrokes.b
+ strokes.b
+ writestrokes.b
+ styxconv
+ mkfile
+ ostyx.b
+ ostyx.m
+ osys.m
+ styxconv.b
+ styxpersist.b
+ ssl.b
+ string.b
+ strinttab.b
+ styx.b
+ styxflush.b
+ styxlib.b
+ styxservers.b
+ tables.b
+ tabs.b
+ tcl.m
+ tcl_calc.b
+ tcl_core.b
+ tcl_inthash.b
+ tcl_io.b
+ tcl_list.b
+ tcl_modhash.b
+ tcl_stack.b
+ tcl_strhash.b
+ tcl_string.b
+ tcl_symhash.b
+ tcl_tk.b
+ tcl_utils.b
+ tftp.b
+ timers.b
+ titlebar.b
+ tkclient.b
+ translate.b
+ ubfa.b
+ url.b
+ usb
+ mkfile
+ usb.b
+ usbmass.b
+ usbmct.b
+ usbmouse.b
+ utils.m
+ vac.b
+ venti.b
+ virgil.b
+ volume.b
+ w3c
+ css.b
+ mkfile
+ uris.b
+ xpointers.b
+ wait.b
+ watchvars.b
+ winplace.b
+ wmclient.b
+ wmlib.b
+ wmsrv.b
+ workdir.b
+ writegif.b
+ xml.b
+ math
+ ack.b
+ crackerbarrel.b
+ doc.txt
+ factor.b
+ ffts.b
+ fibonacci.b
+ fit.b
+ genprimes.b
+ geodesy.b
+ gr.b
+ graph0.b
+ hist0.b
+ linalg.b
+ linbench.b
+ mersenne.b
+ mkfile
+ parts.b
+ perms.b
+ pi.b
+ polyfill.b
+ polyhedra.b
+ powers.b
+ primes.b
+ sieve.b
+ mkfile
+# mux
+# audioctl.b
+# comics.b
+# connect4.b
+# email.b
+# emio.b
+# fnn.b
+# gamed.b
+# games.b
+# mkfile
+# movie.b
+# mux.b
+# news.b
+# news.m
+# othello.b
+# paper.m
+# pizza.b
+# popmail.b
+# readlnw.b
+# readnews.b
+# rec-pb.b
+# register.b
+# rmux.b
+# rmuxslave.b
+# tv.b
+# tvlist.b
+# web.b
+ spree
+ archives.b
+ gather.m
+ join.m
+ join.b
+ joinsession.b
+ joinsession.m
+ mkfile
+ spree.b
+ spree.m
+ clients
+ bounce.b
+ cards.b
+ chat.b
+ gather.b
+ lobby.b
+ othello.b
+ engines
+ afghan.b
+ bounce.b
+ canfield.b
+ chat.b
+ debug.b
+ freecell.b
+ gather.b
+ hearts.b
+ liars.b
+ liars.y
+ lobby.b
+ othello.b
+ racingdemon.b
+ snap.b
+ spider.b
+ spit.b
+ whist.b
+ lib
+ allow.b
+ allow.m
+ base64.b
+ base64.m
+ cardlib.b
+ cardlib.m
+ commandline.b
+ commandline.m
+ objstore.b
+ objstore.m
+ testsets.b
+ tricks.b
+ tricks.m
+ other
+ tst.b
+ tstboing.b
+ tstlines.sh
+ tstwin.b
+ svc
+ auth.sh
+ httpd
+ alarms.b
+ alarms.m
+ cache.b
+ cache.m
+ cgiparse.b
+ cgiparse.m
+ contents.b
+ contents.m
+ date.b
+ date.m
+ echo.b
+ httpd.b
+ httpd.m
+ httpd.debug
+ httpd.log
+ httpd.rewrite
+ httpd.suff
+ imagemap.b
+ mkfile
+ parser.b
+ parser.m
+ redirect.b
+ redirect.m
+ stats.b
+ mkfile
+ net.sh
+ registry.sh
+ rstyx.sh
+ styx.sh
+ webget
+ date.b
+ date.m
+ file.b
+ ftp.b
+ http.b
+ image2enc.b
+ image2enc.m
+ message.b
+ message.m
+ mkfile
+ transport.m
+ webget.b
+ webget.log
+ wgutils.b
+ wgutils.m
+ tiny
+ mkfile
+ rm.b
+ sh.b
+ wm
+ about.b
+ avi.b
+ bounce.b
+ brutus
+ excerpt.b
+ image.b
+ mkfile
+ mod.b
+ table.b
+ brutus.b
+ c4.b
+ calendar.b
+ clock.b
+ coffee.b
+ collide.b
+ colors.b
+ cprof.b
+ date.b
+ deb.b
+ debdata.b
+ debsrc.b
+ dir.b
+ drawmux
+ dmview.b
+ dmwm.b
+ drawmux.b
+ drawmux.m
+ drawoffs.m
+ mkfile
+ edit.b
+ filename.b
+ ftree
+ cptree.b
+ cptree.m
+ ftree.b
+ items.b
+ items.m
+ mkfile
+ wmsetup
+ getauthinfo.b
+ hebrew.m
+ keyboard.b
+ logon.b
+ logwindow.b
+ man.b
+ mand.b
+ mash.b
+ memory.b
+ minitel
+ README
+ event.b
+ event.m
+ keyb.b
+ miniterm.b
+ miniterm.m
+ mkfile
+ modem.b
+ screen.b
+ socket.b
+ swkeyb.b
+ swkeyb.m
+ mkfile
+ mpeg.b
+ mpeg
+ c0.tab
+ c0.vlc
+ c1.tab
+ c1.vlc
+ c2.tab
+ c2.vlc
+ c3.tab
+ c3.vlc
+ c4.tab
+ c4.vlc
+ c5.tab
+ c5.vlc
+ c6.tab
+ c6.vlc
+ c7.tab
+ c7.vlc
+ cbp.tab
+ cbp.vlc
+ cdc.tab
+ cdc.vlc
+ closest.m
+ decode.b
+ decode4.b
+ fixidct.b
+ fltidct.b
+ mai.tab
+ mai.vlc
+ makergbvmap.b
+ maketables
+ mbb.tab
+ mbb.vlc
+ mbi.tab
+ mbi.vlc
+ mbp.tab
+ mbp.vlc
+ mkfile
+ motion.tab
+ motion.vlc
+ mpeg.b
+ mpegio.b
+ mpegio.m
+ refidct.b
+ remap.b
+ remap1.b
+ remap2.b
+ remap24.b
+ remap4.b
+ remap8.b
+ rgbvmap.m
+ rl0f.tab
+ rl0f.vlc
+ rl0n.tab
+ rl0n.vlc
+ scidct.b
+ vlc.b
+ ydc.tab
+ ydc.vlc
+ mprof.b
+ pen.b
+ polyhedra.b
+ prof.b
+ qt.b
+ readmail.b
+ remotelogon.b
+ reversi.b
+ rmtdir.b
+ rt.b
+ sam.b
+ samstub.b
+ samstub.m
+ samterm.m
+ samtk.b
+ samtk.m
+ sendmail.b
+ sh.b
+ smenu.b
+ smenu.m
+ snake.b
+ stopwatch.b
+ sweeper.b
+ task.b
+ telnet.b
+ tetris.b
+ toolbar.b
+ unibrowse.b
+ view.b
+ vt.b
+ wish.b
+ wm.b
+ wmdeb.m
+ wmplay.b
+chan
+dev
+dis
+ 9660srv.dis
+ 9export.dis
+ 9srvfs.dis
+ 9win.dis
+ ar.dis
+ archfs.dis
+ B.dis
+ acme
+ +
+ acme.dis
+ alphabet
+ +
+ auhdr.dis
+ auplay.dis
+ auth
+ +
+ auxi
+ +
+ avr
+ +
+ basename.dis
+ bind.dis
+ broke.dis
+ bytes.dis
+ cal.dis
+ calc.dis
+ cat.dis
+ cd.dis
+ cddb.dis
+ charon
+ +
+ charon.dis
+ chgrp.dis
+ chmod.dis
+ cleanname.dis
+ cmp.dis
+ collab
+ +
+ comm.dis
+ cook.dis
+ cp.dis
+ cprof.dis
+ cpu.dis
+ crypt.dis
+ date.dis
+ dbfs.dis
+ dbm
+ +
+ dd.dis
+ demo
+ +
+ dial.dis
+ diff.dis
+ disdep.dis
+ disdump.dis
+ disk
+ +
+ dossrv.dis
+ du.dis
+ ebook
+ *
+ echo.dis
+ ed.dis
+ emuinit.dis
+ env.dis
+ export.dis
+ fc.dis
+ fcp.dis
+ fmt.dis
+ fone.dis
+ fortune.dis
+ freq.dis
+ fs.dis
+ fs
+ +
+ ftest.dis
+ ftpfs.dis
+ getauthinfo.dis
+ gettar.dis
+ grep.dis
+ grid
+ *
+ demo
+ *
+ lib
+ +
+ gunzip.dis
+ gzip.dis
+ idea.dis
+ import.dis
+ install
+ +
+ iostats.dis
+ ip
+ +
+ itest.dis
+ itreplay.dis
+ kill.dis
+ lc
+ lego
+ +
+ lib
+ arg.dis
+ asn1.dis
+ attrdb.dis
+ attrhash.dis
+ auth.dis
+ auth9.dis
+ bloomfilter.dis
+ bufio.dis
+ cfg.dis
+ cfgfile.dis
+ chanfill.dis
+ complete.dis
+ convcs
+ +
+ crc.dis
+ crypt
+ +
+ csv.dis
+ daytime.dis
+ db.dis
+ dbm.dis
+ dbsrv.dis
+ debug.dis
+ deflate.dis
+ devpointer.dis
+ dhcpclient.dis
+ dial.dis
+ dialog.dis
+ dict.dis
+ dis.dis
+ diskblocks.dis
+ disks.dis
+ dividers.dis
+ drawmux.dis
+ ecmascript.dis
+ encoding
+ +
+ env.dis
+ ether.dis
+ exception.dis
+ factotum.dis
+ filepat.dis
+ format.dis
+ fsfilter.dis
+ fslib.dis
+ fsproto.dis
+ ftree
+ +
+ gamer.dis
+ hash.dis
+ html.dis
+ ida
+ +
+ imageremap.dis
+ inflate.dis
+ ip.dis
+ ipattr.dis
+ ir.dis
+ irsage.dis
+ irsim.dis
+ itslib.dis
+ json.dis
+ keyset.dis
+ libc.dis
+ libc0.dis
+ lists.dis
+ lock.dis
+ login.dis
+ man.dis
+ mash
+ +
+ mashlib.dis
+ mashparse.dis
+ memfs.dis
+ mpeg.dis
+ msgio.dis
+ nametree.dis
+ names.dis
+ newns.dis
+ palm.dis
+ palmdb.dis
+ palmfile.dis
+ parseman.dis
+ plumbing.dis
+ plumbmsg.dis
+ pop3.dis
+ popup.dis
+ powerman.dis
+ +
+ profile.dis
+ pslib.dis
+ quicktime.dis
+ rand.dis
+ random.dis
+ readdir.dis
+ readgif.dis
+ readjpg.dis
+ readpicfile.dis
+ readpng.dis
+ readxbitmap.dis
+ regex.dis
+ regexutils.dis
+ registries.dis
+ rfc822.dis
+ riff.dis
+ secstore.dis
+ scoretable.dis
+ scsiio.dis
+ selectfile.dis
+ sets.dis
+ sets32.dis
+ sexprs.dis
+ slip.dis
+ smtp.dis
+ sort.dis
+ spki
+ *
+ ssl.dis
+ string.dis
+ strinttab.dis
+ strokes
+ +
+ styx.dis
+ styxconv
+ +
+ styxflush.dis
+ styxlib.dis
+ styxpersist.dis
+ styxservers.dis
+ tables.dis
+ tabs.dis
+ tcl_calc.dis
+ tcl_core.dis
+ tcl_inthash.dis
+ tcl_io.dis
+ tcl_list.dis
+ tcl_modhash.dis
+ tcl_stack.dis
+ tcl_strhash.dis
+ tcl_string.dis
+ tcl_symhash.dis
+ tcl_tk.dis
+ tcl_utils.dis
+ tftp.dis
+ timers.dis
+ titlebar.dis
+ tkclient.dis
+ translate.dis
+ ubfa.dis
+ url.dis
+ usb
+ usb.dis
+ usbmass.dis
+ usbmct.dis
+ usbmouse.dis
+ vac.dis
+ venti.dis
+ virgil.dis
+ volume.dis
+ w3c
+ +
+ wait.dis
+ watchvars.dis
+ winplace.dis
+ wmclient.dis
+ wmlib.dis
+ wmsrv.dis
+ workdir.dis
+ writegif.dis
+ xml.dis
+ limbo.dis
+ listen.dis
+ lockfs.dis
+ logfile.dis
+ look.dis
+ lookman
+ ls.dis
+ lstar.dis
+ m4.dis
+ man
+ man2html.dis
+ man2txt.dis
+ mash.dis
+ math
+ +
+ mc.dis
+ md5sum.dis
+ mdb.dis
+ memfs.dis
+ metamorph.dis
+ mk.dis
+ mkdir.dis
+ mntgen.dis
+ mount.dis
+ mouse.dis
+ mpc
+ +
+ mpeg
+ +
+ mprof.dis
+# mux
+# +
+ mv.dis
+ ndb
+ +
+ netkey.dis
+ netstat.dis
+ newer.dis
+ ns.dis
+ nsbuild.dis
+ os.dis
+ p.dis
+ palm
+ +
+ pause.dis
+ plumb.dis
+ plumber.dis
+ prof.dis
+ ps.dis
+ puttar.dis
+ pwd.dis
+ ramfile.dis
+ randpass.dis
+ raw2iaf.dis
+ rawdbfs.dis
+ rcmd.dis
+ rdp.dis
+ read.dis
+ rioimport.dis
+ rm.dis
+ runas.dis
+ sed.dis
+ sendmail.dis
+ sh
+ +
+ sh.dis
+ sha1sum.dis
+ shutdown
+ sleep.dis
+ sort.dis
+ spki
+ +
+ spree
+ +
+ src.dis
+ stack.dis
+ stream.dis
+ strings.dis
+ styxchat.dis
+ styxlisten.dis
+ styxmon.dis
+ sum.dis
+ svc
+ +
+ tail.dis
+ tarfs.dis
+ tclsh.dis
+ tcs.dis
+ tee.dis
+ telnet.dis
+ test.dis
+ time.dis
+ timestamp.dis
+ tiny
+ +
+ tkcmd.dis
+ tokenize.dis
+ touch.dis
+ touchcal.dis
+ tr.dis
+ trfs.dis
+ tsort.dis
+ unicode.dis
+ uniq.dis
+ unmount.dis
+ usb
+ usbd.dis
+ uudecode.dis
+ uuencode.dis
+ vacfs.dis
+ vacget.dis
+ vacput.dis
+ wav2iaf.dis
+ wc.dis
+ webgrab.dis
+ wish.dis
+ wm
+ about.dis
+ avi.dis
+ bounce.dis
+ brutus
+ *
+ brutus.dis
+ c4.dis
+ calendar.dis
+ chat.dis
+ clock.dis
+ coffee.dis
+ collide.dis
+ colors.dis
+ cprof.dis
+ date.dis
+ deb.dis
+ debdata.dis
+ debsrc.dis
+ dir.dis
+ dmview.dis
+ dmwm.dis
+ edit.dis
+ filename.dis
+ ftree.dis
+ getauthinfo.dis
+ keyboard.dis
+ logon.dis
+ logwindow.dis
+ man.dis
+ mand.dis
+ mash.dis
+ memory.dis
+ minitel
+ *
+ mpeg.dis
+ mprof.dis
+ pen.dis
+ polyhedra.dis
+ prof.dis
+ qt.dis
+ readmail.dis
+ remotelogon.dis
+ reversi.dis
+ rmtdir.dis
+ rt.dis
+ sendmail.dis
+ sh.dis
+ smenu.dis
+ snake.dis
+ stopwatch.dis
+ sweeper.dis
+ task.dis
+ telnet.dis
+ tetris.dis
+ toolbar.dis
+ unibrowse.dis
+ view.dis
+ vt.dis
+ wish.dis
+ wm.dis
+ wmplay.dis
+ wmimport.dis
+ wmexport.dis
+ xargs.dis
+ xd.dis
+ xmount.dis
+ yacc.dis
+ zeros.dis
+doc
+ 20010618.ms
+ 20010618.pdf
+ 20011003.ms
+ 20011003.pdf
+ 20020628.ms
+ 20020628.pdf
+ changes.ms
+ changes.pdf
+ acid.ms
+ acid.pdf
+ acidpaper.ms
+ acidpaper.pdf
+ acidtut.ms
+ acidtut.pdf
+ acme
+ acme.ms
+ acme.pdf
+ asm.ms
+ asm.pdf
+ backmatter.pdf
+ bltj.ms
+ bltj.pdf
+ compiler.ms
+ compiler.pdf
+ descent
+ descent.ms
+ descent.pdf
+ dev.ms
+ dev.pdf
+ dis.ms
+ dis.pdf
+ ebookimp.ms
+ ebookimp.pdf
+ fonts
+ fonts.pal
+ mkfile
+ frontmatter.pdf
+ gridinstall.ms
+ gridinstall.pdf
+ hotchips.ms
+ hotchips.pdf
+ install.ms
+ install.pdf
+ lprof.ms
+ lprof.pdf
+ limbo
+ limbo.rc
+ synsum
+ limbo.ms
+ limbo.pdf
+ addendum.ms
+ addendum.pdf
+ mkfile
+ lego.ms
+ lego.pdf
+ limbotk
+ tk.ms
+ tk.pdf
+ manhow.pdf
+ mk.ms
+ mk.pdf
+ perform
+ perform.ms
+ perform.pdf
+ port.ms
+ port.pdf
+ realinferno
+ real.ms
+ real.pdf
+ sh.ms
+ sh.pdf
+ styx.ms
+ styx.pdf
+env
+fonts
+ LICENCE
+ big5
+ +
+ charon
+ +
+ chinese
+ +
+ gb
+ +
+ jis
+ +
+ lucida
+ +
+ lucidasans
+ +
+ lucm
+ +
+ minitel
+ +
+ misc
+ +
+ pelm
+ +
+ psrename
+icons
+ +
+keydb
+ countersigned
+ keys 600 inferno inferno /keydb/keys.dist
+ signed
+lib
+ acid
+ +
+ convcs
+ +
+ ebook
+ +
+ ebooks
+ +
+ emptydirs
+ games
+ +
+ keyboard
+ legal
+ *
+ lego
+ *
+ mashinit
+ mimetype
+ mk
+ *
+ ndb
+ common
+ dns 664 inferno inferno /lib/ndb/dns.dist
+ inferno
+ local 664 inferno inferno /lib/ndb/local.dist
+ registry 664 inferno inferno /lib/ndb/registry.dist
+ services
+ polyhedra
+ polyhedra.all
+ *
+ proto
+ FreeBSD
+ Hp
+ Irix
+ Linux
+ MacOSX
+ Nt
+ Plan9
+ Solaris
+ inferno
+ src
+ utils
+ scsicodes
+ scores
+ +
+ sexp
+ sh
+ +
+ strokes
+ +
+ tbsetup
+ unicode
+ unidata
+ +
+ units
+ usbdb
+ video.specs
+ wmcharon
+ wmsetup
+ wmsetup.grid
+ words
+ yaccpar
+locale
+ NOTICE
+ Australia_ACT
+ Australia_Broken-Hill
+ Australia_LHI
+ Australia_NSW
+ Australia_North
+ Australia_Queensland
+ Australia_South
+ Australia_Sturt
+ Australia_Tasmania
+ Australia_Victoria
+ Australia_West
+ Australia_Yancowinna
+ Brazil_Acre
+ Brazil_DeNoronha
+ Brazil_East
+ Brazil_West
+ CET
+ CST.CDT
+ Canada_Atlantic
+ Canada_Central
+ Canada_East-Saskatchewan
+ Canada_Eastern
+ Canada_Mountain
+ Canada_Newfoundland
+ Canada_Pacific
+ Canada_Yukon
+ Chile_Continental
+ Chile_EasterIsland
+ Cuba
+ EET
+ EST.EDT
+ Egypt
+ GB-Eire
+ GMT
+ HST
+ Hongkong
+ Iceland
+ Iran
+ Israel
+ Jamaica
+ Japan
+ Libya
+ MET
+ MST.MDT
+ Mexico_BajaNorte
+ Mexico_BajaSur
+ Mexico_General
+ NZ
+ NZ_CHAT
+ Navajo
+ PRC
+ PST.PDT
+ Poland
+ README
+ ROC
+ ROK
+ Singapore
+ Turkey
+ US_Alaska
+ US_Arizona
+ US_Central
+ US_East-Indiana
+ US_Eastern
+ US_Hawaii
+ US_Michigan
+ US_Mountain
+ US_Pacific
+ US_Yukon
+ W-SU
+ WET
+ en_US
+ dict
+ calendar
+ location
+ location
+ timezone
+man
+ 1
+ +
+ 2
+ +
+ 3
+ +
+ 4
+ +
+ 5
+ +
+ 6
+ +
+ 7
+ +
+ 8
+ +
+ 9
+ +
+ 10
+ +
+ index
+mkconfig
+mkfiles
+ *
+mnt
+ *
+ spki
+ keys
+module
+ NOTICE
+ alphabet.m
+ alphabet
+ +
+ arg.m
+ asn1.m
+ attrdb.m
+ auth9.m
+ bench.m
+ bloomfilter.m
+ brutus.m
+ brutusext.m
+ bufio.m
+ bundle.m
+ cci.m
+ cfg.m
+ cfgfile.m
+ complete.m
+ convcs.m
+ crc.m
+ css.m
+ csv.m
+ cvsimages.m
+ daytime.m
+ db.m
+ dbm.m
+ debug.m
+ devpointer.m
+ dhcp.m
+ dial.m
+ dialog.m
+ dict.m
+ dis.m
+ diskblocks.m
+ disks.m
+ dividers.m
+ draw.m
+ ecmascript.m
+ emio.m
+ encoding.m
+ env.m
+ ether.m
+ exception.m
+ factotum.m
+ ffts.m
+ filepat.m
+ filter.m
+ format.m
+ freetype.m
+ fslib.m
+ fsproto.m
+ gamer.m
+ gr.m
+ grid
+ announce.m
+ browse.m
+ browser.m
+ demo
+ exproc.m
+ block.m
+ fbrowse.m
+ pathreader.m
+ readjpg.m
+ regpoll.m
+ srvbrowse.m
+ hash.m
+ html.m
+ ida.m
+ imagefile.m
+ inflate.m
+ ip.m
+ ipattr.m
+ ir.m
+ itslib.m
+ json.m
+ keyboard.m
+ keyring.m
+ keyset.m
+ libc.m
+ libc0.m
+ linalg.m
+ lists.m
+ loader.m
+ lock.m
+ man.m
+ math.m
+ math
+ *
+ memfs.m
+ mpeg.m
+ msgio.m
+ multistyx.m
+ muxclient.m
+ names.m
+ newns.m
+ palm.m
+ palmfile.m
+ pkcs.m
+ plumbmsg.m
+ pop3.m
+ popup.m
+ powerman.m
+ prefab.m
+ print.m
+ profile.m
+ pslib.m
+ quicktime.m
+ rand.m
+ readdir.m
+ regex.m
+ regexutils.m
+ registries.m
+ rfc822.m
+ riff.m
+ runt.m
+ scoretable.m
+ scsiio.m
+ secstore.m
+ security.m
+ selectfile.m
+ sets.m
+ sets32.m
+ sexprs.m
+ sh.m
+ smtp.m
+ sort.m
+ spki.m
+ strokes.m
+ srv.m
+ srvrunt.b
+ ssl3.m
+ sslsession.m
+ string.m
+ strinttab.m
+ styx.m
+ styxconv.m
+ styxflush.m
+ styxlib.m
+ styxpersist.m
+ styxservers.m
+ sys.m
+ tables.m
+ tabs.m
+ tcllib.m
+ tftp.m
+ timers.m
+ titlebar.m
+ tk.m
+ tkclient.m
+ translate.m
+ ubfa.m
+ unbundle.m
+ uris.m
+ url.m
+ usb.m
+ vac.m
+ venti.m
+ volume.m
+ wait.m
+ watchvars.m
+ webget.m
+ winplace.m
+ wmclient.m
+ wmlib.m
+ wmsrv.m
+ workdir.m
+ x509.m
+ xml.m
+ xpointers.m
+n
+ cd
+ client
+ chan
+ dev
+ disk
+ dist
+ dump
+ ftp
+ kfs
+ local
+ rdbg
+ registry
+ remote
+net
+net.alt
+nvfs
+prof
+prog
+services
+ httpd
+ httpd.rewrite
+ httpd.suff
+ logs
+ ppp
+ webget
+ help.html
+ inferno.gif
+ start.html
+ vnlogo.gif
+src
+sys
+#mux
+# basic
+# +
+# comics
+# +
+# namespace
+# namespace.init
+# news
+# +
+# pizza
+# +
+# price
+# rec-pb
+# +
+# tvlist
+# +
+tmp
+usr
+ inferno
+ charon
+ keyring
+ lib
+ plumbing
+ namespace
+wrap
--- /dev/null
+++ b/lib/proto/os
@@ -1,0 +1,1000 @@
+Inferno
+ 386
+ bin
+ include
+ *
+ lib
+ arm
+ bin
+ include
+ *
+ lib
+ mips
+ bin
+ include
+ *
+ lib
+ power
+ bin
+ include
+ *
+ lib
+ sparc
+ bin
+ include
+ *
+ lib
+ spim
+ bin
+ include
+ *
+ lib
+ thumb
+ bin
+ include
+ *
+ lib
+include
+ flate.h
+ kern.h
+ logfs.h
+ nandecc.h
+ nandfs.h
+ trace.h
+lib
+ proto
+ os
+libkern
+ NOTICE
+ abort.c
+ abs.c
+ atol.c
+ charstod.c
+ cistrcmp.c
+ cistrncmp.c
+ cistrstr.c
+ cleanname.c
+ convD2M.c
+ convM2D.c
+ convM2S.c
+ convS2M.c
+ div-arm.s
+ dofmt.c
+ exp.c
+ fcallfmt.c
+ floor.c
+ fmt.c
+ fmtdef.h
+ fmtprint.c
+ fmtquote.c
+ fmtstr.c
+ fmtvprint.c
+ frexp-386.c
+ frexp-68000.c
+ frexp-arm.c
+ frexp-mips.c
+ frexp-power.c
+ frexp-sparc.c
+ frexp-spim.c
+ frexp-thumb.c
+ getfcr-386.s
+ getfcr-68000.s
+ getfcr-arm.s
+ getfcr-mips.s
+ getfcr-power.s
+ getfcr-sparc.s
+ getfcr-spim.s
+ getfcr-thumb.s
+ getfields.c
+ log.c
+ memccpy-power.s
+ memccpy.c
+ memchr.c
+ memcmp-power.s
+ memcmp.c
+ memmove.c
+ memmove-386.s
+ memmove-68000.s
+ memmove-arm.s
+ memmove-mips.s
+ memmove-power.s
+ memmove-spim.s
+ memmove-sparc.s
+ memmove-thumb.s
+ memset-386.s
+ memset-68000.s
+ memset-arm.s
+ memset-mips.s
+ memset-power.s
+ memset-sparc.s
+ memset-spim.s
+ memset-thumb.s
+ memset.c
+ mkfile
+ mkfile-386
+ mkfile-68000
+ mkfile-arm
+ mkfile-mips
+ mkfile-power
+ mkfile-sparc
+ mkfile-spim
+ mkfile-thumb
+ muldiv-68000.s
+ nan-386.c
+ nan-68000.c
+ nan-arm.c
+ nan-mips.c
+ nan-power.c
+ nan-spim.c
+ nan-sparc.c
+ nan-thumb.c
+ netmkaddr.c
+ pow.c
+ pow10.c
+ qsort.c
+ rune.c
+ runestrlen.c
+ seprint.c
+ sin.c
+ smprint.c
+ snprint.c
+ sqrt.c
+ strcat.c
+ strchr-386.s
+ strchr-68000.s
+ strchr-arm.s
+ strchr-mips.c
+ strchr-mips.s
+ strchr-power.s
+ strchr-sparc.s
+ strchr-spim.c
+ strchr-thumb.s
+ strchr.c
+ strcmp-power.s
+ strcmp.c
+ strcpy.c
+ strdup.c
+ strecpy.c
+ strlen.c
+ strncmp-power.s
+ strncmp.c
+ strncpy.c
+ strrchr.c
+ strstr.c
+ strtod.c
+ strtol.c
+ strtoll.c
+ strtoul.c
+ strtoull.c
+ tokenize.c
+ toupper.c
+ u16.c
+ u32.c
+ u64.c
+ utfecpy.c
+ utflen.c
+ utfnlen.c
+ utfrrune.c
+ utfrune.c
+ vlop-386.s
+ vlop-arm.s
+ vlop-mips.s
+ vlop-power.s
+ vlop-sparc.s
+ vlop-spim.s
+ vlop-thumb.s
+ vlrt-386.c
+ vlrt-68000.c
+ vlrt-arm.c
+ vlrt-mips.c
+ vlrt-power.c
+ vlrt-sparc.c
+ vlrt-spim.c
+ vlrt-thumb.c
+ vseprint.c
+ vsmprint.c
+ vsnprint.c
+libnandfs
+ NOTICE
+ calcformat.c
+ correctauxilliary.c
+ ecc.c
+ eraseblock.c
+ extracttags.c
+ findfreeblock.c
+ formatblock.c
+ getblockstatus.c
+ hamming31_26.c
+ init.c
+ local.h
+ markblockbad.c
+ mkfile
+ open.c
+ readblock.c
+ readpage.c
+ readpageauxilliary.c
+ reformatblock.c
+ setget.c
+ updatepage.c
+ writeblock.c
+ writepageauxilliary.c
+liblogfs
+ NOTICE
+ boot.c
+ clunk.c
+ conv.c
+ create.c
+ dump.c
+ error.c
+ extentlist.c
+ fidmap.c
+ findfreeblock.c
+ flush.c
+ format.c
+ gn.c
+ group.c
+ groupset.c
+ is.c
+ local.h
+ log.c
+ map.c
+ mkfile
+ open.c
+ path.c
+ perm.c
+ read.c
+ remove.c
+ replace.c
+ replay.c
+ scan.c
+ srv.c
+ sweep.c
+ tagname.c
+ test.c
+ ust.c
+ walk.c
+ write.c
+ wstat.c
+os
+ NOTICE
+ README
+ boot
+ README
+ libflate
+ LICENCE
+ NOTICE
+ adler.c
+ crc.c
+ deflate.c
+ deflateblock.c
+ deflatezlib.c
+ deflatezlibblock.c
+ flateerr.c
+ inflate.c
+ inflateblock.c
+ inflatezlib.c
+ inflatezlibblock.c
+ mkfile
+ zlib.h
+ arm1110
+ Mk
+ dat.h
+ donprint.c
+ fns.h
+ il.s
+ imain.c
+ inflate.c
+ io.h
+ l.s
+ lib.h
+ map
+ mem.h
+ mkfile
+ print.c
+ uart.c
+ mpc
+ NOTICE
+ alarm.c
+ all.h
+ archfads.c
+ archfads.h
+ archpaq.c
+ archpaq.h
+ boot.h
+ bootp.c
+ clock.c
+ conf.c
+ console.c
+ cpm.c
+ crc32.c
+ dat.h
+ defont0.c
+ dload.c
+ donprint.c
+ dosboot.c
+ dosfs.h
+ devether.c
+ etherif.h
+ etherscc.c
+ fblt.c
+ flash.c
+ fns.h
+ gbitbltclip.c
+ gnot.h
+ i2c.c
+ initfads.c
+ initpaq.c
+ initrpcg.c
+ io.h
+ ip.h
+ l.s
+ lib.h
+ main.c
+ mem.c
+ mem.h
+ mkfile
+ ms2.c
+ plan9boot.c
+ qio.c
+ rmap.c
+ screen.c
+ sload.c
+ squeeze.h
+ trap.c
+ devuart.c
+ uartboot.c
+ ureg.h
+ zqs.c
+ pc
+ 8250.c
+ LICENCE
+ NOTICE
+ ahci.h
+ alarm.c
+ aoe.h
+ apm.c
+ bcom.c
+ boot.c
+ bootld.c
+ bootp.c
+ cga.c
+ cis.c
+ clock.c
+ conf.c
+ console.c
+ dat.h
+ devbios.c
+ devbios.h
+ devfloppy.c
+ devfloppy.h
+ devi82365.c
+ devpccard.c
+ devsd.c
+ dma.c
+ dosboot.c
+ dosfs.h
+ eipfmt.c
+ error.h
+ ether.c
+ ether2000.c
+ ether2114x.c
+ ether589.c
+ ether79c970.c
+ ether8003.c
+ ether8139.c
+ ether8169.c
+ ether82557.c
+ ether82563.c
+ ether83815.c
+ ether8390.c
+ ether8390.h
+ etherdp83820.c
+ etherec2t.c
+ etherelnk3.c
+ etherelnk3x.c
+ etherga620.c
+ etherga620fw.h
+ etherif.h
+ etherigbe.c
+ ethermii.c
+ ethermii.h
+ etherrhine.c
+ fns.h
+ fs.c
+ fs.h
+ getcallerpc.c
+ ilock.c
+ inflate.c
+ io.h
+ ip.h
+ kbd.c
+ kfs.h
+ kfsboot.c
+ l.s
+ lib.h
+ load.c
+ mbr.s
+ mem.h
+ memory.c
+ mkfile
+ noether.c
+ part.c
+ pbs.s
+ pbsdisk
+ pbsdisk.s
+ pbsdisklba
+ pbsdisklba.s
+ pbslba.s
+ pci.c
+ print.c
+ queue.c
+ sd.h
+ sd53c8xx.c
+ sd53c8xx.i
+ sdaoe.c
+ sdata.c
+ sdbios.c
+ sdiahci.c
+ sdmylex.c
+ sdscsi.c
+ trap.c
+ ureg.h
+ x16.h
+ puma
+ 8250.c
+ alarm.c
+ armv4.h
+ boot.h
+ bootp.c
+ cga.c
+ clock.c
+ conf.c
+ console.c
+ dat.h
+ div.s
+ donprint.c
+ dosboot.c
+ dosfs.h
+ ebsit.trap.c
+ ether.c
+ ether.h
+ ether8900.c
+ flash.c
+ fns.h
+ hard.c
+ io.h
+ ip.h
+ kbd.c
+ l.s
+ lib.h
+ main.c
+ mem.h
+ mkfile
+ outb.c
+ plan9boot.c
+ puma.c
+ puma.h
+ qio.c
+ rmap.c
+ squeeze.h
+ sum.c
+ trap.c
+ ureg.h
+ zqs.c
+ rpcg
+ NOTICE
+ alarm.c
+ all.h
+ archrpcg.c
+ archrpcg.h
+ boot.h
+ bootp.c
+ clock.c
+ conf.c
+ console.c
+ cpm.c
+ crc32.c
+ dat.h
+ defont0.c
+ devether.c
+ devuart.c
+ dload.c
+ donprint.c
+ dosboot.c
+ dosfs.h
+ etherif.h
+ etherscc.c
+ fblt.c
+ flash.c
+ fns.h
+ g.mx
+ gbitbltclip.c
+ gnot.h
+ i2c.c
+ initfads.c
+ initpaq.c
+ initrpcg.c
+ io.h
+ ip.h
+ l.s
+ lib.h
+ libg.h
+ main.c
+ mem.c
+ mem.h
+ mkfile
+ ms2.c
+ plan9boot.c
+ qbromrpcg
+ qio.c
+ rmap.c
+ screen.c
+ sload
+ sload.c
+ squeeze.h
+ trap.c
+ uartboot.c
+ ureg.h
+ zqs.c
+ cerf1110
+ Mk
+ NOTICE
+ README
+ archcerf.c
+ cerf
+ dat.h
+ devata.c
+ devcerf.c
+ ether8900.c
+ fns.h
+ io.h
+ main.c
+ mem.h
+ mkfile
+ cerf250
+ NOTICE
+ README
+ archcerf.c
+ cerf
+ dat.h
+# devata.c
+# devcerf.c
+ devpcf8563.c
+ ether91c111.c
+ fns.h
+ io.h
+ main.c
+ mem.h
+ mkfile
+ uart.h
+ cerf405
+ NOTICE
+ README
+ cerf
+ clock.c
+ compile.c
+ dat.h
+ devboot.c
+ devether.c
+ devrtc.c
+ devuart.c
+ etheremac.c
+ etherif.h
+ fns.h
+ fpi.h
+ fpipower.c
+ gpio.c
+ iic.c
+ inb.s
+ io.h
+ l.s
+ main.c
+ mal.c
+ mem.h
+ mkfile
+ mmu.c
+ nand.c
+ nofp.s
+ pci.c
+ physmem.h
+ powerbreak.c
+ rmap.c
+ tlb.s
+ trap.c
+ uart.c
+ uart.h
+ fads
+ NOTICE
+ archfads.c
+ archfads.h
+ dat.h
+ fads
+ fns.h
+ io.h
+ main.c
+ mem.h
+ mkfile
+ mmu.c
+ tlb.s
+ init
+ README
+ bootinit.b
+ cerf405.b
+ cerfinit.b
+ evalinit.b
+ geninit.b
+ i4e.b
+ init.b
+ ipaqinit.b
+ ipeinit.b
+ jsinit.b
+ mkfile
+ mpcinit.b
+ pcdemo.b
+ pcinit.b
+ reminit.b
+ rpcginit.b
+ soeinit.b
+ shell.b
+ srvinit.b
+ wminit.b
+ ip
+ *
+ ipaq1110
+ Mk
+ NOTICE
+ README
+ archipaq.c
+ dat.h
+ defont.c
+ devaudio.c
+ devipaq.c
+ etherwavelan.c
+ fns.h
+ inflate
+ io.h
+ ipaq
+ lcd.c
+ main.c
+ mem.h
+ mkfile
+ screen.c
+ screen.h
+ tstdraw.b
+ upd
+ ipengine
+ NOTICE
+ README
+ archipe.c
+ archipe.h
+ dat.h
+ devfpga.c
+ flash28f320b3b.c
+ fns.h
+ fpga
+ io.h
+ ipe
+ main.c
+ mem.h
+ mkfile
+ mmu.c
+ tlb.s
+ js
+ README
+ audio.h
+ clock.c
+ cs4231.h
+ dat.h
+ devcs4231.c
+ devrtc.c
+ fns.h
+ fsv.c
+ io.h
+ js
+ kbd.c
+ l.s
+ main.c
+ mem.h
+ mkfile
+ mmu.c
+ ns16552.h
+ iob.c
+ rom.c
+ rom.h
+ screen.c
+ screen.h
+ softcursor.h
+ superio.c
+ trap.c
+ ureg.h
+ ks32
+ Mk
+ NOTICE
+ archevaluator7t.c
+ armv7.h
+ clock.c
+ dat.h
+ devuart.c
+ download.ps
+ evaluator7t
+ fns.h
+ fpi.h
+ fpiarm.c
+ io.h
+ l.s
+ main.c
+ mem.h
+ mkfile
+ not.c
+ squirt
+ trap.c
+ mpc
+ 800io.h
+ NOTICE
+ clock.c
+ cpm.c
+ cpmtimer.c
+ devata.c
+ devbench.c
+ devboot.c
+ devether.c
+ devpcmcia.c
+ devrtc.c
+ devtouch.c
+ devuart.c
+# devusb.c
+# devusbc.c
+# devusbh.c
+# devvid.c
+ dsp.c
+ dsp.h
+ etherif.h
+ etherscc.c
+ faultpower.c
+ fp.s
+ fpi.h
+ fpipower.c
+ i2c.c
+ i2c_spi.srx
+ inb.s
+ kbd.c
+ l.s
+ nofp.s
+ pcmcia.h
+ pit.c
+ powerbreak.c
+ rmap.c
+ screen.c
+ screen.h
+ spi.c
+ trap.c
+ usb.h
+ pc
+ NOTICE
+ README
+ apbootstrap.h
+ apbootstrap.s
+ apic.c
+ apm.c
+ apmjump.s
+ archmp.c
+ audio.h
+ cga.c
+ cgamemscr.c
+ crystal.h
+ dat.h
+ devarch.c
+ devds1620.c
+ devether.c
+ devfloppy.c
+ devi82365.c
+ devlm78.c
+ devlpt.c
+ devmouse.c
+ devmpeg.c
+ devpccard.c
+ devpnp.c
+ devrtc.c
+ devtv.c
+ devusb.c
+ devvga.c
+ devzt5512.c
+ dma.c
+ ether2000.c
+ ether2114x.c
+ ether589.c
+ ether79c960.c
+ ether79c970.c
+ ether8003.c
+ ether8139.c
+ ether82543gc.c
+ ether82557.c
+ ether83815.c
+ ether8390.c
+ ether8390.h
+ etherec2t.c
+ etherelnk3.c
+ etherga620.c
+ etherga620fw.h
+ etherif.h
+ etherigbe.c
+ etherrhine.c
+ ethersmc.c
+ etherwavelan.c
+ flashif.h
+ flashzpc.c
+ floppy.h
+ fns.h
+ fpi.h
+ fpi387.c
+ fpsave.s
+ i8250.c
+ i8253.c
+ i8259.c
+ io.h
+ kbd.c
+ l.s
+ main.c
+ mem.h
+ memory.c
+ mkfile
+ mmu.c
+ mouse.c
+ mp.c
+ mp.h
+ pc
+ pc4e
+ pcdisk
+ pci.acid
+ pci.c
+ pcidb.acid
+ pcmciamodem.c
+ piix4smbus.c
+ pix
+ ps2mouse.c
+ ptclbsum386.s
+ screen.c
+ screen.h
+ sd53c8xx.c
+ sd53c8xx.i
+ sd53c8xx.n
+ sdata.c
+ sdmylex.c
+ sdscsi.c
+ trap.c
+ tv.h
+ uarti8250.c
+ uartisa.c
+ uartpci.c
+ usb.h
+ usbuhci.c
+ vga.c
+ vga.h
+ vga3dfx.c
+ vgaark2000pv.c
+ vgabt485.c
+ vgaclgd542x.c
+ vgaclgd546x.c
+ vgact65545.c
+ vgacyber938x.c
+ vgaet4000.c
+ vgahiqvideo.c
+ vgai81x.c
+ vgamach64xx.c
+ vgamga2164w.c
+ vgamga4xx.c
+ vganeomagic.c
+ vganvidia.c
+ vgargb524.c
+ vgas3.c
+ vgasavage.c
+ vgat2r4.c
+ vgatvp3020.c
+ vgatvp3026.c
+ vgavmware.c
+ vgax.c
+ wavelan.c
+ wavelan.h
+ x86break.c
+ zoran.h
+ port
+ *
+ pxa
+ NOTICE
+ clock.c
+ devether.c
+# devgpio.c
+# devpcmcia.c
+# devpower.c
+ devrtc.c
+ devuart.c
+# devuart0.c
+ dma.c
+ etherif.h
+ fpi.h
+ fpiarm.c
+ gpio.c
+# gscreen.c
+# gscreen.h
+ i2c.c
+ l.s
+ mmu.c
+ pxaio.h
+ sa1110break.c
+# softcursor.c
+# suspend.c
+ trap.c
+ omap
+ README
+ manga
+ Mk
+ archmanga.c
+ clock.c
+ dat.h
+# devesw.c
+ devether.c
+ devusb.c
+# esw.c
+# esw.h
+ eswnotes
+ ether8139.c
+ etherif.h
+ etherks8695.c
+ flashif.h
+ fns.h
+ fpi.h
+ fpiarm.c
+ gpio.c
+ inb.c
+ io.h
+ ioring.c
+ l.s
+ main.c
+ manga
+ mem.h
+ mkfile
+ mmu.c
+ pci.c
+ pinflate
+ trap.c
+ uartks8695.c
+ usb.h
+ usbuhci.c
+ rpcg
+ NOTICE
+ archrpcg.c
+ archrpcg.h
+ clock.c
+ dat.h
+ fns.h
+ io.h
+ main.c
+ mem.h
+ mkfile
+ mmu.c
+ rpcg
+ tlb.s
+ sa1110
+ clock.c
+ devether.c
+ devgpio.c
+ devpcmcia.c
+ devpower.c
+ devrtc.c
+ devuart.c
+ dma.c
+ etherif.h
+ fpi.h
+ fpiarm.c
+ gscreen.c
+ gscreen.h
+ i2c.h
+ i2cgpio.c
+ l.s
+ l3gpio.c
+ mmu.c
+ sa1110break.c
+ sa1110io.h
+ softcursor.c
+ suspend.c
+ trap.c
--- /dev/null
+++ b/lib/proto/src
@@ -1,0 +1,825 @@
+INSTALL
+include
+ styxserver.h
+asm
+ NOTICE
+ asm.h
+ asm.y
+ assem.c
+ lex.c
+ mkfile
+emu
+ NOTICE
+ mkfile
+ port
+ *
+ Plan9
+ asm-386.s
+ asm-mips.s
+ asm-power.s
+ asm-sparc.s
+ cmd.c
+ devfs.c
+ devsrv9.c
+ emu
+ emusig
+ mkfile
+ os.c
+ win.c
+ FreeBSD
+ +
+ Hp
+ +
+ Irix
+ +
+ Linux
+ +
+ MacOSX
+ +
+ Nt
+ +
+ Solaris
+ +
+ Unixware
+ +
+libdraw
+ NOTICE
+ alloc.c
+ allocimagemix.c
+ arith.c
+ bezier.c
+ border.c
+ buildfont.c
+ bytesperline.c
+ chan.c
+ cloadimage.c
+ computil.c
+ creadimage.c
+ defont.c
+ draw.c
+ drawrepl.c
+ ellipse.c
+ font.c
+ freesubfont.c
+ getdefont.c
+ getsubfont.c
+ init.c
+ line.c
+ loadimage.c
+ mkfile
+ mkfont.c
+ openfont.c
+ poly.c
+ readcolmap.c
+ readimage.c
+ readsubfont.c
+ rectclip.c
+ replclipr.c
+ rgb.c
+ string.c
+ stringbg.c
+ stringsubfont.c
+ stringwidth.c
+ subfont.c
+ subfontcache.c
+ subfontname.c
+ test.c
+ unloadimage.c
+ window.c
+ writecolmap.c
+ writeimage.c
+ writesubfont.c
+libdynld
+ NOTICE
+ dynld-386.c
+ dynld-68000.c
+ dynld-arm.c
+ dynld-mips.c
+ dynld-power.c
+ dynld-sparc.c
+ dynld-spim.c
+ dynld.c
+ dynloadfd.c
+ mkfile
+libfreetype
+ NOTICE
+ +
+ adler32.c
+ ahangles.c
+ ahangles.h
+ aherrors.h
+ ahglobal.c
+ ahglobal.h
+ ahglyph.c
+ ahglyph.h
+ ahhint.c
+ ahhint.h
+ ahloader.h
+ ahmodule.c
+ ahmodule.h
+ ahoptim.c
+ ahoptim.h
+ ahtypes.h
+ autohint.c
+ bdf.c
+ bdf.h
+ bdfdrivr.c
+ bdfdrivr.h
+ bdferror.h
+ bdflib.c
+ cff.c
+ cffcmap.c
+ cffcmap.h
+ cffdrivr.c
+ cffdrivr.h
+ cfferrs.h
+ cffgload.c
+ cffgload.h
+ cffload.c
+ cffload.h
+ cffobjs.c
+ cffobjs.h
+ cffparse.c
+ cffparse.h
+ cfftoken.h
+ ciderrs.h
+ cidgload.c
+ cidgload.h
+ cidload.c
+ cidload.h
+ cidobjs.c
+ cidobjs.h
+ cidparse.c
+ cidparse.h
+ cidriver.c
+ cidriver.h
+ cidtoken.h
+ fnterrs.h
+ freetype.c
+ ft2system.c
+ ftapi.c
+ ftbase.c
+ ftbbox.c
+ ftbdf.c
+ ftcache.c
+ ftcalc.c
+ ftccache.c
+ ftccmap.c
+ ftcerror.h
+ ftcglyph.c
+ ftcimage.c
+ ftcmanag.c
+ ftcsbits.c
+ ftdbgmem.c
+ ftdebug.c
+ ftexcept.c
+ ftgloadr.c
+ ftglyph.c
+ ftgrays.c
+ ftgrays.h
+ ftgzip.c
+ fthash.c
+ ftinit.c
+ ftlist.c
+ ftlru.c
+ ftmac.c
+ ftmm.c
+ ftnames.c
+ ftobject.c
+ ftobjs.c
+ ftoutln.c
+ ftpfr.c
+ ftraster.c
+ ftraster.h
+ ftrend1.c
+ ftrend1.h
+ ftsmerrs.h
+ ftsmooth.c
+ ftsmooth.h
+ ftstream.c
+ ftstroker.c
+ ftsynth.c
+ ftsysio.c
+ ftsysmem.c
+ ftsystem.c
+ ftsystem_inf.c
+ fttrigon.c
+ fttype1.c
+ ftutil.c
+ ftxf86.c
+ infblock.c
+ infblock.h
+ infcodes.c
+ infcodes.h
+ inffixed.h
+ inflate.c
+ inftrees.c
+ inftrees.h
+ infutil.c
+ infutil.h
+ mkfile
+ otlayout.h
+ otlbase.c
+ otlbase.h
+ otlcommn.c
+ otlcommn.h
+ otlconf.h
+ otlgdef.c
+ otlgdef.h
+ otlgpos.c
+ otlgpos.h
+ otlgsub.c
+ otlgsub.h
+ otljstf.c
+ otljstf.h
+ otlparse.c
+ otlparse.h
+ otltable.h
+ otltags.h
+ otlutils.h
+ pcf.c
+ pcf.h
+ pcfdriver.c
+ pcfdriver.h
+ pcferror.h
+ pcfread.c
+ pcfutil.c
+ pcfutil.h
+ pfr.c
+ pfrcmap.c
+ pfrcmap.h
+ pfrdrivr.c
+ pfrdrivr.h
+ pfrerror.h
+ pfrgload.c
+ pfrgload.h
+ pfrload.c
+ pfrload.h
+ pfrobjs.c
+ pfrobjs.h
+ pfrsbit.c
+ pfrsbit.h
+ pfrtypes.h
+ psaux.c
+ psauxerr.h
+ psauxmod.c
+ psauxmod.h
+ pshalgo.h
+ pshalgo1.c
+ pshalgo1.h
+ pshalgo2.c
+ pshalgo2.h
+ pshalgo3.c
+ pshalgo3.h
+ pshglob.c
+ pshglob.h
+ pshinter.c
+ pshmod.c
+ pshmod.h
+ pshrec.c
+ pshrec.h
+ psmodule.c
+ psmodule.h
+ psnamerr.h
+ psnames.c
+ psobjs.c
+ psobjs.h
+ pstables.h
+ raster.c
+ rasterrs.h
+ sfdriver.c
+ sfdriver.h
+ sferrors.h
+ sfnt.c
+ sfobjs.c
+ sfobjs.h
+ smooth.c
+ stddef.h
+ t1afm.c
+ t1afm.h
+ t1cmap.c
+ t1cmap.h
+ t1decode.c
+ t1decode.h
+ t1driver.c
+ t1driver.h
+ t1errors.h
+ t1gload.c
+ t1gload.h
+ t1load.c
+ t1load.h
+ t1objs.c
+ t1objs.h
+ t1parse.c
+ t1parse.h
+ t1tokens.h
+ t42drivr.c
+ t42drivr.h
+ t42error.h
+ t42objs.c
+ t42objs.h
+ t42parse.c
+ t42parse.h
+ test_bbox.c
+ test_trig.c
+ truetype.c
+ ttcmap.c
+ ttcmap.h
+ ttcmap0.c
+ ttcmap0.h
+ ttdriver.c
+ ttdriver.h
+ tterrors.h
+ ttgload.c
+ ttgload.h
+ ttinterp.c
+ ttinterp.h
+ ttload.c
+ ttload.h
+ ttobjs.c
+ ttobjs.h
+ ttpload.c
+ ttpload.h
+ ttpost.c
+ ttpost.h
+ ttsbit.c
+ ttsbit.h
+ type1.c
+ type1cid.c
+ type42.c
+ winfnt.c
+ winfnt.h
+ zconf.h
+ zlib.h
+ zutil.c
+ zutil.h
+libinterp
+ NOTICE
+ README
+ alt.c
+ comp-386.c
+ comp-68020.c
+ comp-arm.c
+ comp-mips.c
+ comp-power.c
+ comp-s800.c
+ comp-sparc.c
+ comp-spim.c
+ comp-thumb.c
+ conv.c
+ das-386.c
+ das-68000.c
+ das-68020.c
+ das-arm.c
+ das-mips.c
+ das-power.c
+ das-s800.c
+ das-sparc.c
+ das-stub.c
+ das-spim.c
+ das-thumb.c
+ dec.c
+ decgen.c
+ dlm-Inferno.c
+ dlm-Nt.c
+ dlm-Plan9.c
+ dlm-Posix.c
+ draw.c
+ drawmod.h
+ freetype.c
+ freetypemod.h
+ gc.c
+ geom.c
+ heap.c
+ heapaudit.c
+ ipint.c
+ keyring.c
+ keyring.h
+ link.c
+ load.c
+ loader.c
+ loadermod.h
+ math.c
+ mathmod.h
+ mkfile
+ mkoptab
+ optab.h
+ prefab.c
+ raise.c
+ readmod.c
+ runt.c
+ runt.h
+ sign.c
+ stack.c
+ string.c
+ sysmod.h
+ tab.h
+ tk.c
+ tkmod.h
+ validstk.c
+ xec.c
+libkeyring
+ NOTICE
+ dsaalg.c
+ egalg.c
+ keys.h
+ mkfile
+ rsaalg.c
+limbo
+ NOTICE
+ asm.c
+ com.c
+ decls.c
+ dis.c
+ dtocanon.c
+ ecom.c
+ fns.h
+ gen.c
+ lex.c
+ limbo.h
+ limbo.y
+ mkfile
+ nodes.c
+ optab.c
+ optim.c
+ runt.h
+ sbl.c
+ stubs.c
+ typecheck.c
+ types.c
+libmath
+ NOTICE
+ FPcontrol-FreeBSD.c
+ FPcontrol-Hp.c
+ FPcontrol-Inferno.c
+ FPcontrol-Irix.c
+ FPcontrol-Linux.c
+ FPcontrol-MacOSX.c
+ FPcontrol-Nt.c
+ FPcontrol-Plan9.c
+ FPcontrol-Solaris.c
+ FPcontrol-Unixware.c
+ bin
+ fdlibm-stubs
+ unif_dtoa
+ unif_fdlibm
+ blas.c
+ dtoa.c
+ fdim.c
+ fdlibm
+ *
+ g_fmt.c
+ gemm.c
+ gfltconv.c
+ mkfile
+ pow10.c
+libmemdraw
+ NOTICE
+ alloc.c
+ arc.c
+ cload.c
+ cmap.c
+ cread.c
+ defont.c
+ draw.c
+ drawtest.c
+ ellipse.c
+ fillpoly.c
+ hwdraw.c
+ icossin.c
+ icossin2.c
+ iprint.c
+ line.c
+ load.c
+ mkfile
+ mkfile-Inferno
+ mkfile-Irix
+ mkfile-Linux
+ mkfile-MacOSX
+ mkfile-Nt
+ mkfile-Plan9
+ mkfile-Solaris
+ mkfile-FreeBSD
+ mkfile-os
+ openmemsubfont.c
+ poly.c
+ read.c
+ string.c
+ subfont.c
+ unload.c
+ write.c
+libmemlayer
+ NOTICE
+ draw.c
+ lalloc-x11.c
+ lalloc.c
+ layerop.c
+ ldelete.c
+ lhide.c
+ line.c
+ load.c
+ lorigin.c
+ lreshape.c
+ lsetrefresh.c
+ ltofront.c
+ ltorear.c
+ mkfile
+ mkfile-FreeBSD
+ mkfile-Hp
+ mkfile-Inferno
+ mkfile-Irix
+ mkfile-Linux
+ mkfile-MacOSX
+ mkfile-NetBSD
+ mkfile-Nt
+ mkfile-Plan9
+ mkfile-Posix
+ mkfile-Solaris
+ mkfile-Unixware
+ mkfile-os
+ unload.c
+libmp
+ NOTICE
+ Inferno-386
+ mkfile
+ mpdigdiv.s
+ mpvecadd.s
+ mpvecdigmuladd.s
+ mpvecdigmulsub.s
+ mpvecsub.s
+ Inferno-amd64
+ mkfile
+ mpdigdiv.s
+ mpvecadd.s
+ mpvecdigmuladd.s
+ mpvecdigmulsub.s
+ mpvecsub.s
+ Inferno-mips
+ mkfile
+ mpdigdiv.s
+ mpvecadd.s
+ mpvecdigmuladd.s
+ mpvecdigmulsub.s
+ mpvecsub.s
+ Inferno-power
+ mkfile
+ mpvecadd.s
+ mpvecdigmuladd.s
+ mpvecdigmulsub.s
+ mpvecsub.s
+ Plan9-386
+ mkfile
+ mpdigdiv.s
+ mpvecadd.s
+ mpvecdigmuladd.s
+ mpvecdigmulsub.s
+ mpvecsub.s
+ Plan9-amd64
+ mkfile
+ mpdigdiv.s
+ mpvecadd.s
+ mpvecdigmuladd.s
+ mpvecdigmulsub.s
+ mpvecsub.s
+ Plan9-mips
+ mkfile
+ mpdigdiv.s
+ mpvecadd.s
+ mpvecdigmuladd.s
+ mpvecdigmulsub.s
+ mpvecsub.s
+ Plan9-power
+ mkfile
+ mpvecadd.s
+ mpvecdigmuladd.s
+ mpvecdigmulsub.s
+ mpvecsub.s
+ bigtest.c
+ mkfile
+ mtest.c
+ port
+ betomp.c
+ crt.c
+ crttest.c
+ dat.h
+ letomp.c
+ mkfile
+ mpadd.c
+ mpaux.c
+ mpcmp.c
+ mpdigdiv.c
+ mpdiv.c
+ mpeuclid.c
+ mpexp.c
+ mpextendedgcd.c
+ mpfactorial.c
+ mpfmt.c
+ mpinvert.c
+ mpleft.c
+ mpmod.c
+ mpmul.c
+ mprand.c
+ mpright.c
+ mpsub.c
+ mptobe.c
+ mptoi.c
+ mptole.c
+ mptoui.c
+ mptouv.c
+ mptov.c
+ mpvecadd.c
+ mpveccmp.c
+ mpvecdigmuladd.c
+ mpvecsub.c
+ os.h
+ reduce-nt
+ reduce-rc
+ reduce-sh
+ strtomp.c
+ test.c
+libprefab
+ NOTICE
+ box.c
+ compound.c
+ element.c
+ elistelement.c
+ iconbox.c
+ iconelement.c
+ mkfile
+ textbox.c
+ textelement.c
+libsec
+ NOTICE
+ Inferno-386
+ md5block.s
+ mkfile
+ sha1block.s
+ Inferno-mips
+ md5block.s
+ mkfile
+ sha1block.s
+ Plan9-386
+ md5block.s
+ mkfile
+ sha1block.s
+ Plan9-mips
+ md5block.s
+ mkfile
+ sha1block.s
+ mkfile
+ port
+ aes.c
+ blowfish.c
+ decodepem.c
+ des.c
+ des3CBC.c
+ des3ECB.c
+ desCBC.c
+ desECB.c
+ desmodes.c
+ dsaalloc.c
+ dsagen.c
+ dsaprimes.c
+ dsaprivtopub.c
+ dsasign.c
+ dsaverify.c
+ egalloc.c
+ egdecrypt.c
+ egencrypt.c
+ eggen.c
+ egprivtopub.c
+ egsign.c
+ egtest.c
+ egverify.c
+ fastrand.c
+ genprime.c
+ genrandom.c
+ gensafeprime.c
+ genstrongprime.c
+ hmac.c
+ hmactest.c
+ idea.c
+ md4.c
+ md4test.c
+ md5.c
+ md5block.c
+ md5pickle.c
+ mkfile
+ nfastrand.c
+ primetest.c
+ prng.c
+ probably_prime.c
+ rc4.c
+ reduce-nt
+ reduce-rc
+ reduce-sh
+ rsaalloc.c
+ rsadecrypt.c
+ rsaencrypt.c
+ rsafill.c
+ rsagen.c
+ rsaprivtopub.c
+ rsatest.c
+ sha1.c
+ sha1block.c
+ sha1pickle.c
+ smallprimes.c
+ smallprimetest.c
+libtk
+ NOTICE
+ buton.c
+ canvs.c
+ canvs.h
+ canvu.c
+ carcs.c
+ cbits.c
+ cimag.c
+ cline.c
+ colrs.c
+ coval.c
+ cpoly.c
+ crect.c
+ ctext.c
+ cwind.c
+ ebind.c
+ entry.c
+ extns.c
+ frame.c
+ frame.h
+ grids.c
+ image.c
+ label.c
+ label.h
+ listb.c
+ listb.h
+ mail.tk
+ menu.tk
+ menus.c
+ mkfile
+ mkfile-std
+ packr.c
+ panel.c
+ parse.c
+ radio.tk
+ scale.c
+ scrol.c
+ textu.c
+ textw.c
+ textw.h
+ tindx.c
+ tmark.c
+ ttags.c
+ twind.c
+ utils.c
+ windw.c
+ xdata.c
+man
+ lib
+ checkman.awk
+ colophon
+ lookman
+ +
+ man
+ notes
+ permind
+ preface
+ secindex
+ title
+ trademarks
+tools
+ NOTICE
+ db
+ infdb.c
+ mkfile
+ libstyx
+ Nt.c
+ Plan9.c
+ Posix.c
+ mkfile
+ styxaux.h
+ styxserver.c
+ mkfile
+ odbc
+ mkfile
+ mkfile-Linux
+ mkfile-MacOSX
+ mkfile-Nt
+ mkfile-Plan9
+ mkfile-Solaris
+ odbc.c
+ styxtest
+ mkfile
+ mkfile-FreeBSD
+ mkfile-Irix
+ mkfile-Linux
+ mkfile-MacOSX
+ mkfile-Nt
+ mkfile-Plan9
+ mkfile-Solaris
+ styxtest.c
+ styxtest0.c
+utils
+ ntsrv
+ domk
+ ntsrv.c
+ mkfile
--- /dev/null
+++ b/lib/proto/utils
@@ -1,0 +1,752 @@
+include
+ bio.h
+lib9
+ NOTICE
+ argv0.c
+ charstod.c
+ cistrcmp.c
+ cistrncmp.c
+ cistrstr.c
+ cleanname.c
+ convD2M.c
+ convM2D.c
+ convM2S.c
+ convS2M.c
+ create.c
+ dirstat-Nt.c
+ dirstat-posix.c
+ dirwstat.c
+ dofmt.c
+ dorfmt.c
+ errfmt.c
+ errstr-Nt.c
+ errstr-Plan9.c
+ errstr-posix.c
+ exits.c
+ fcallfmt.c
+ fltfmt.c
+ fmt.c
+ fmtdef.h
+ fmtfd.c
+ fmtlock.c
+ fmtprint.c
+ fmtquote.c
+ fmtrune.c
+ fmtstr.c
+ fmtvprint.c
+ fprint.c
+ getcallerpc-FreeBSD-386.S
+ getcallerpc-Hp-s800.s
+ getcallerpc-Irix-mips.s
+ getcallerpc-Linux-386.S
+ getcallerpc-Linux-arm.S
+ getcallerpc-Linux-spim.S
+ getcallerpc-MacOSX-power.s
+ getcallerpc-MacOSX-386.s
+ getcallerpc-Solaris-386.s
+ getcallerpc-Solaris-sparc.s
+ getcallerpc-Unixware-386.s
+ getfields.c
+ getuser-Nt.c
+ getuser-posix.c
+ getwd-Nt.c
+ getwd-posix.c
+ lock.c
+ lock-Hp-s800.s
+ lock-Irix-mips.s
+ lock-MacOSX-power.s
+ lock-Nt-386.c
+ lock-Solaris-386.s
+ lock-Solaris-sparc.s
+ lock-Unixware-386.s
+ mkfile
+ mkfile-Nt
+ mkfile-Plan9
+ mkfile-Posix
+ nulldir.c
+ pow10.c
+ print.c
+ qsort.c
+ readn.c
+ rerrstr.c
+ rune.c
+ runeseprint.c
+ runesmprint.c
+ runesnprint.c
+ runestrlen.c
+ runevseprint.c
+ sbrk-posix.c
+ seek.c
+ seprint.c
+ setbinmode-Nt.c
+ smprint.c
+ snprint.c
+ sprint.c
+ strdup.c
+ strecpy.c
+ strtoll.c
+ sysfatal.c
+ tokenize.c
+ u16.c
+ u32.c
+ u64.c
+ utfecpy.c
+ utflen.c
+ utfnlen.c
+ utfrrune.c
+ utfrune.c
+ vfprint.c
+ vseprint.c
+ vsmprint.c
+ vsnprint.c
+libbio
+ NOTICE
+ bbuffered.c
+ bfildes.c
+ bflush.c
+ bgetc.c
+ bgetd.c
+ bgetrune.c
+ binit.c
+ boffset.c
+ bprint.c
+ bputc.c
+ bputrune.c
+ brdline.c
+ bread.c
+ bseek.c
+ bwrite.c
+ mkfile
+mkfile
+makemk.sh
+utils
+ NOTICE
+ 0a
+ a.h
+ a.y
+ l.s
+ lex.c
+ mkfile
+ 0c
+ cgen.c
+ enam.c
+ gc.h
+ list.c
+ mkenam
+ mkfile
+ mul.c
+ peep.c
+ reg.c
+ sgen.c
+ swt.c
+ txt.c
+ v.out.h
+ 0l
+ Plan9.c
+ Nt.c
+ Posix.c
+ asm.c
+ enam.c
+ l.h
+ list.c
+ mkfile
+ noop.c
+ obj.c
+ optab.c
+ pass.c
+ sched.c
+ span.c
+ 1a
+ a.h
+ a.y
+ l.s
+ lex.c
+ mkfile
+ 1c
+ cgen.c
+ enam.c
+ gc.h
+ list.c
+ mkfile
+ mul.c
+ peep.c
+ reg.c
+ sgen.c
+ swt.c
+ txt.c
+ 1l
+ Plan9.c
+ Nt.c
+ Posix.c
+ asm.c
+ l.h
+ list.c
+ mkfile
+ obj.c
+ optab.c
+ pass.c
+ span.c
+ 2a
+ a.h
+ a.y
+ l.s
+ lex.c
+ mkfile
+ 2c
+ 2.out.h
+ Update
+ cgen.c
+ enam.c
+ gc.h
+ list.c
+ mkfile
+ mul.c
+ peep.c
+ reg.c
+ sgen.c
+ swt.c
+ txt.c
+ 2l
+ Plan9.c
+ Nt.c
+ Posix.c
+ asm.c
+ l.h
+ list.c
+ mkfile
+ obj.c
+ optab.c
+ pass.c
+ span.c
+ 5a
+ a.h
+ a.y
+ lex.c
+ mkfile
+ 5c
+ 5.out.h
+ cgen.c
+ enam.c
+ gc.h
+ list.c
+ mkenam
+ mkfile
+ mul.c
+ peep.c
+ reg.c
+ sgen.c
+ swt.c
+ txt.c
+ 5cv
+ 5cv.c
+ mkfile
+ 5coff
+ NOTICE
+ 5coff.c
+ auxi.c
+ auxi.h
+ coff.c
+ mkfile
+ readcoff.c
+ 5l
+ Plan9.c
+ Nt.c
+ Posix.c
+ asm.c
+ l.h
+ list.c
+ mkfile
+ noop.c
+ obj.c
+ optab.c
+ pass.c
+ span.c
+ thumb.c
+ 6c
+ 6.out.h
+ 8a
+ a.h
+ a.y
+ l.s
+ lex.c
+ mkfile
+ 8c
+ 8.out.h
+ cgen.c
+ cgen64.c
+ div.c
+ enam.c
+ gc.h
+ list.c
+ machcap.c
+ mkenam
+ mkfile
+ mul.c
+ peep.c
+ reg.c
+ sgen.c
+ swt.c
+ txt.c
+ 8l
+ Plan9.c
+ Nt.c
+ Posix.c
+ asm.c
+ l.h
+ list.c
+ mkfile
+ obj.c
+ optab.c
+ pass.c
+ span.c
+ acid
+ 386
+ B.sh
+ acid.h
+ arm
+ builtin.c
+ dbg.y
+ dot.c
+ exec.c
+ expr.c
+ lex.c
+ list.c
+ main.c
+ mips
+ mkfile
+ os-Plan9.c
+ os-Nt.c
+ os-Posix.c
+ port
+ print.c
+ proc.c
+ rdebug.c
+ sparc
+ util.c
+ iar
+ Plan9.c
+ Nt.c
+ Posix.c
+ ar.c
+ mkfile
+ awk
+ FIXES
+ NOTICE
+ README
+ awk.1
+ awk.h
+ awkgram.y
+ b.c
+ buildwin.bat
+ lex.c
+ lib.c
+ mac.code
+ main.c
+ makefile
+ maketab.c
+ missing95.c
+ mkfile
+ parse.c
+ proctab.c
+ proto.h
+ run.c
+ tran.c
+ ytab.c
+ ytab.h
+ ytabc.bak
+ ytabh.bak
+ c2l
+ Plan9.c
+ Nt.c
+ Posix.c
+ acid.c
+ bits.c
+ c2l.c
+ cc.h
+ cc.y
+ com.c
+ com64.c
+ dcl.c
+ dpchk.c
+ lex.c
+ lexbody
+ mac.c
+ macbody
+ mkfile
+ mpatof.c
+ out.c
+ scon.c
+ sub.c
+ cat
+ cat.c
+ mkfile
+ cc
+ Plan9.c
+ Nt.c
+ Posix.c
+ acid.c
+ bits.c
+ cc.h
+ cc.y
+ com.c
+ com64.c
+ dcl.c
+ dpchk.c
+ funct.c
+ lex.c
+ lexbody
+ mac.c
+ macbody
+ machcap.c
+ mkfile
+ mpatof.c
+ pickle.c
+ scon.c
+ sub.c
+ cp
+ cp.c
+ mkfile
+ cvbit
+ cvbit.c
+ mkfile
+ data2c
+ data2c.c
+ mkfile
+ data2s
+ data2s.c
+ mkfile
+ echo
+ echo.c
+ mkfile
+ format
+ Plan9.c
+ Nt.c
+ format.c
+ mkfile
+ ftl
+ ftl.c
+ mkfile
+ idea
+ NOTICE
+ idea.c
+ mkfile
+ include
+ a.out.h
+ ar.h
+ mach.h
+ regexp.h
+ ka
+ a.h
+ a.y
+ l.s
+ lex.c
+ mkfile
+ note
+ kc
+ cgen.c
+ enam.c
+ gc.h
+ k.out.h
+ list.c
+ mkenam
+ mkfile
+ mul.c
+ peep.c
+ reg.c
+ sgen.c
+ swt.c
+ txt.c
+ kl
+ Plan9.c
+ Nt.c
+ Posix.c
+ asm.c
+ foo.c
+ l.h
+ list.c
+ mkfile
+ noop.c
+ obj.c
+ optab.c
+ pass.c
+ sched.c
+ span.c
+ kprof
+ kprof.c
+ mkfile
+ ksize
+ ksize.c
+ mkfile
+ kstrip
+ kstrip.c
+ mkfile
+ lib
+ rcmain
+ yaccpar
+ libmach
+ NOTICE
+ 2.c
+ 2db.c
+ 2obj.c
+ 4.c
+ 4db.c
+ 5.c
+ 5db.c
+ 5obj.c
+ 6.c
+ 6obj.c
+ 8.c
+ 8db.c
+ 8obj.c
+ a.out.h
+ access.c
+ ar.h
+ bootexec.h
+ elf.h
+ executable.c
+ k.c
+ kdb.c
+ kobj.c
+ mach.h
+ machdata.c
+ map.c
+ mkfile
+ obj.c
+ obj.h
+ q.c
+ qdb.c
+ qobj.c
+ setmach.c
+ swap.c
+ sym.c
+ t.c
+ tdb.c
+ tobj.c
+ uregt.h
+ ureg2.h
+ ureg4.h
+ ureg5.h
+ ureg6.h
+ ureg8.h
+ uregk.h
+ uregq.h
+ uregv.h
+ v.c
+ vcodas.c
+ vdb.c
+ vobj.c
+ libregexp
+ NOTICE
+ mkfile
+ regaux.c
+ regcomp.c
+ regcomp.h
+ regerror.c
+ regexec.c
+ regsub.c
+ rregexec.c
+ rregsub.c
+ test.c
+ test2.c
+ md5sum
+ md5sum.c
+ mkfile
+ mkext
+ mkext.c
+ mkfile
+ mk
+ Plan9.c
+ Nt.c
+ Posix.c
+ README
+ arc.c
+ archive.c
+ bufblock.c
+ env.c
+ file.c
+ fns.h
+ graph.c
+ job.c
+ lex.c
+ main.c
+ match.c
+ mk.c
+ mk.h
+ mkfile
+ mkfile-Plan9
+ mkfile-Nt
+ mkfile-Posix
+ parse.c
+ rc.c
+ recipe.c
+ rule.c
+ run.c
+ sh.c
+ shprint.c
+ symtab.c
+ var.c
+ varsub.c
+ word.c
+ mkdir
+ mkdir.c
+ mkfile
+ mkfile
+ mkppcimage
+ mkfile
+ mkppcimage.c
+ ms2
+ mkfile
+ ms2.c
+ mv
+ mkfile
+ mv.c
+ na
+ mkfile
+ na.h
+ na.man
+ na.y
+ ndate
+ mkfile
+ ndate.c
+ nm
+ mkfile
+ nm.c
+ qa
+ Ins
+ a.h
+ a.y
+ branch
+ lex.c
+ mkfile
+ qc
+ cgen.c
+ enam.c
+ gc.h
+ list.c
+ mkenam
+ mkfile
+ mul.c
+ peep.c
+ q.out.h
+ reg.c
+ sgen.c
+ swt.c
+ txt.c
+ ql
+ Plan9.c
+ Ins
+ Notes
+ Nt.c
+ Posix.c
+ asm.c
+ asmout.c
+ cnam.c
+ l.h
+ list.c
+ mkcname
+ mkfile
+ noop.c
+ obj.c
+ optab.c
+ pass.c
+ sched.c
+ span.c
+ rcsh
+ Nt.c
+ code.c
+ exec.c
+ glob.c
+ here.c
+ io.c
+ lex.c
+ main.c
+ mkfile
+ pcmd.c
+ pfnc.c
+ rc.h
+ rcmain
+ rcpath
+ simple.c
+ syn.y
+ trap.c
+ tree.c
+ var.c
+ word.c
+ rm
+ mkfile
+ rm-Nt.c
+ sed
+ mkfile
+ sed.c
+ sqz
+ NOTICE
+ mkfile
+ squeeze.h
+ sqz.c
+ zqs.c
+ srclist
+ Plan9.c
+ Nt.c
+ Posix.c
+ mkfile
+ srclist.c
+ tc
+ 5.out.h
+ cgen.c
+ enam.c
+ gc.h
+ list.c
+ mkenam
+ mkfile
+ mul.c
+ peep.c
+ reg.c
+ sgen.c
+ swt.c
+ txt.c
+ test
+ mkfile
+ test-Nt.c
+ tr
+ mkfile
+ tr.c
+ va
+ a.h
+ a.y
+ l.s
+ lex.c
+ mkfile
+ note
+ vc
+ cgen.c
+ enam.c
+ gc.h
+ list.c
+ mkenam
+ mkfile
+ mul.c
+ peep.c
+ reg.c
+ sgen.c
+ swt.c
+ txt.c
+ v.out.h
+ vl
+ Plan9.c
+ Nt.c
+ Posix.c
+ asm.c
+ compat.c
+ l.h
+ list.c
+ mkfile
+ noop.c
+ obj.c
+ optab.c
+ pass.c
+ sched.c
+ span.c
+ iyacc
+ mkfile
+ yacc.c
+ yaccpar
--- /dev/null
+++ b/lib/scores/snake
@@ -1,0 +1,10 @@
+internet 194 12.442264511089631551711111423114516203162831133321313110111112321328244264119361518212319114745217111142231882541163110114371714171117163831151411351311582151911213357127133189101631195172031114161512112722711012143120321213111261811311961984731031203131419312115133113221919220271451433131103186515102139151181251531154132142316192031161515121131712181010156520206161111411121662919111131215113151174182718273114120672327412041735174141121311625422441125103120312531261621125617125451018116191162384221328102146131811412312115171027642541441411632226171112136201011210225623312193192431561531191228136573449315121032514185172820258165511214141144191131411018191411114201724519322918210131516611116315251184591314382013313116212211142419212171531167261511320417117916712125172151415252627225311813323118795151414151514181410161561531211313144410511911311311311311311315142218211241541119118106181345519541622113115282234201189164146171114616191155415727181101013162612114282817271010111451974814132206510231615164341415343499121113281271261151151925516311612011314111431133171342513110115117332181922213241152312029291281171164212111738315146231221222712571615151515151511761765313114951514141413154520325925141111617 30.30.1110000000000000000000000000001010000000000000000000000000001010000000000000000000000000001011111111111111111111100000001000000000000000000000100000001
\ No newline at end of file
+rog 155 0.51419612154514662414183619717141556151716173441104919419131812516145169419861971341461611518182117171011011179618114554112619211744216110816161201519191511651104431311261211392773549104856234183924717118145491718455621319113111163351819125712941911312116101979115211151179211519112111511071341851917511419110162461102316122248671022114111118619141221822711319191818119171818122151118824115110181727374210122916171716119611726111111111111111111163311116168292101919123161111111121122513136199531015251211011118113131717141101919111441218123151511311019110191148161291811411311211211521181141141141141141157161241518111112110111111113611243161121121111121186201136132719202011111247125132411611511921119117112110171711011687171272220112111110191121101954122341311111261016122612161511211211011011011011018121410316391812523251171171171171171131012113739185615311713120917191911532192510261221221211131161731361411411311311411411411716161202612312212111811611811614201025123121120120120119119141411411598162612612814251241221221221201221320120119317118117115116113212115111111101611812071521612231423124124126212812512312111911914201191201191161192111611954121131418462727201181171161186111620318114119261161151151141147431010201711611511612151126362261151151161912511611711911912225211151131121121121121131141197
\ No newline at end of file
+chris 148 12.2811622620451487146166102171284225239581758219171111071067214456267746492145118523135179141428612213116222203697114561812201111101910121115141445107557891397314528711075391620621101163201261111154619214126143161178111111899841372152413310494119571792011411039101317914162782061749855992124121731111121128314691791151923614114248163413716810720614114117161259941511411511791152410166212512421219416610111761021011111111426154310423202721012117101129617131983101711512051661891151015185514714614151455141111221231048191911141422282221116116117195232571520141511331466855188214241816455111181161225198414312111672631011171551461112141411781641512151154176153826462158185119121067722121115112110116425134481146191151151131131131151115822682521058132061171411319181201171151111123111138101321877910113787206392621311465171141141131131121131119721818118118119257651528811115115117119523202032226235151141161161171171161151199221324521118118117117118636661857417120118118119118114117105762111131111111111011052314611372018171419261419119119119120122212411411411411511711811911812012222619117117116116513694131131131212323116117115114111110110191919112185151215810262419171131131131121112194 30.30.000011111111111111111111000000000010000000000000000001000000000010000000000000000001000000000010000000000000000001000000000010000000000000000001111100102010000000000000000001111111100010000000000000000001111110100010000000000000000001111110100010000000000000000001111110100010000000000000000001111110100010000000000000000001111110100010000000000000000001111110100010000000000000000001111110100010000000000000000001111110100010000000
\ No newline at end of file
+chris 134
+rog 106
+chris 99 12.25152251095148514462610481411424875510126117189561052135811638815261311119269888912113488181011277823128186710114818201012581914114515991211513101011610111116315101912219231714151214121313131755649111242012292021122611211381311210124941315616164818418111021771816731041017124638919277208546611875815181103864131312661051341736412176349121662521822072254554101121423105122221121481411227117515123486142271451671924219820102319223156125517173142142126163517737423217126815510192223511101229281141141101111161522011518171149114610681144554127694211161161151166192661352141122931217115115115117121923262511218122211911911912118233121111111142312199102127119181181181181207795320222524221201114 30.30.000000000000010000000000000000000000000000011111111111100000000011111111111111111111100000000011111111111111111111111000000000000000000000000000001000000000000000000000000000001000000000000000000000000000001000000000000000000000000000001000000000000000000000000000001000000000000000000000000000001000000000000000000000000000001000000000000000002000000000001000000000000000000000000000001000000000000000000000000000001000000000000000000000000000001000000000000000000000000000001000000000000000000000000000001000000000000000000000000000001000000000000000000000000000001000000000000000000000000000001000000000000000000000000000001000000000000000000000000000001000000000000000000000000000001000000000000000000000000000001000000000000000000000000000001000000000000000000000000000001000000000000000000000000000001000000000111111131111111111111000000000000000010000000000000000000000000000010000000000000000
+rog 95 30.30.000000000000000000000000000000000000000000000000000000000000000000000000000000000000001100000000000000000000000000001311000000111111111111111111110001000000111111110000000000010001000000000000011100000000010001000000000000000111111111010001000000000001111111111111010001000000000000000000000000010001000000000000000000000000010011000000000000000000011111110010000000000000000000010000000010000000000000000000010000000010000000000000000000010000000010000000000000000000010000000010000000000000000000011111111110000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
+rog 90
+chris 86
+rog 85
--- /dev/null
+++ b/lib/scores/tetris
@@ -1,0 +1,10 @@
+rog 10294 619 61 1018459656
+chris 8198 488 48 966856907
+rog 7382 444 44 948217793
+rog 6717 398 39 1016489333
+chris 6662 400 40 949931938
+chris 5772 339 33 951416793
+rog 4543 265 26 1016041766
+rog 4503 267 26 950535599
+chris 4362 254 25 947854282
+rog 4331 255 25 1018374770
--- /dev/null
+++ b/lib/scores/x
@@ -1,0 +1,10 @@
+rog 155 51419612154514662414183619717141556151716173441104919419131812516145169419861971341461611518182117171011011179618114554112619211744216110816161201519191511651104431311261211392773549104856234183924717118145491718455621319113111163351819125712941911312116101979115211151179211519112111511071341851917511419110162461102316122248671022114111118619141221822711319191818119171818122151118824115110181727374210122916171716119611726111111111111111111163311116168292101919123161111111121122513136199531015251211011118113131717141101919111441218123151511311019110191148161291811411311211211521181141141141141141157161241518111112110111111113611243161121121111121186201136132719202011111247125132411611511921119117112110171711011687171272220112111110191121101954122341311111261016122612161511211211011011011011018121410316391812523251171171171171171131012113739185615311713120917191911532192510261221221211131161731361411411311311411411411716161202612312212111811611811614201025123121120120120119119141411411598162612612814251241221221221201221320120119317118117115116113212115111111101611812071521612231423124124126212812512312111911914201191201191161192111611954121131418462727201181171161186111620318114119261161151151141147431010201711611511612151126362261151151161912511611711911912225211151131121121121121131141197
\ No newline at end of file
+chris 134
+rog 106
+rog 95 30.30.000000000000000000000000000000000000000000000000000000000000000000000000000000000000001100000000000000000000000000001311000000111111111111111111110001000000111111110000000000010001000000000000011100000000010001000000000000000111111111010001000000000001111111111111010001000000000000000000000000010001000000000000000000000000010011000000000000000000011111110010000000000000000000010000000010000000000000000000010000000010000000000000000000010000000010000000000000000000010000000010000000000000000000011111111110000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
+rog 90
+chris 86 101171152141171718354961757517147113207317163165869862451311671385191241112152108273911994818824109111815391791921359101116218119782135455831711042814112420761010462121058622916111110812152839510631461491515201417112266822101131257101411179961091414616183208258439661661816755838291151710699217412293728181154578192454542123542843418116814146921810110114484141611711411610127136417611536882595752867661425117116121104541053836631531820113114116114111542102154472352021311761611653142185352336517514146141115110112110642939417107363159191918274711842491462162514113 30.30.000000000000000000000000000000001111110000000000000000000000001111110000000000000000000000111111111111111111111113111111000000000000000000000001000000000000000000000000000001111111000000000000000000000000000001000000000000000000000000000001000000000000000000000000000001000000000000000000000000000001000000000000000000000000000001000000000000000000000000000001000000000000000000000000000001000000000000000000000000000001000000000000000000000000000001000000000000000000000000000001000000000000000000000000000001000000000000000000000200000001000000000000000000000000000001000000000000000000001111111111000000000000000000001000000000000000000000000000001000000000000000000000000000001000000000000000000000000000001110000000000000000000000000000010000000000000000000000000000010000000000000000000000000000010000000000000000000000111111110000000000000000000000000000000000000000000000000000000000000000000
+rog 85 85227341327545131535331113163991152361774712132611316641816111571111398171821711719591564725184121041116121131215412617551257457121612255315112114771819839911152641681912351181145711015158472410117202031061618519619585154281341611419106110271124351114181222101711424714165514816121541928122010214611051719169592101919171111081724711071118181711471631221422115113715111191611146293176115172091443241151121111106675119111113113111114110118161108161311311311311311419114164131411018191919191104999211151167913111110111111151016111111111111110191344113517335 30.30.000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011111111111111111100000000000010000000000000000100000000000010000000000000000100000000000010000000000000000111100000000010000000000001111100100000000011111111111111000100100000000000000000000000000120100000000000000000000000000100100000000000000000000000000111300000000000000000000111111111100000000000000000000111111111110000000000000000000011111111110000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
+rog 84
+rog 83 5224106119351638185114114818172415519181018491038797106911013712111635212175181313361511362351252791125371162071021062719620116383178185371883415176166116719291012112418415152518616319434615161127110131735411010324144731127811341161131143174141131851128716419151851162105110125141102251862718717183429101941256162419207113811511514158196142081118196711911051161423239278101011258922111181611094194169181876113411811711611311311610526747163 30.30.000000001111111111111111100000000000000000000000000000100000000000000000000000000000100000000000000000000000000000100000000000000000000000000000100000000000000000000000000000100000000000000000000000000000100000000000000000000000001111100000000000000000000000001000000000000000000000000000001000000000000000000000000000001000000000000000000000000000001000000000000000000000000000001000000000000000000000000000001000000000000000000000000000001111111000000000000000000000000000001000000000000000000000000111111000000000000000000000000100000000000000000000000000000100000000000000000000000000000100000000000000000000000000000100000000000000000000000000000100000000000000000000000000000100000000000000000000000000000100000000000000000000000000000100000000000000000000000000000100000000000001111111111111111100000000000001113111111100000000000000000000001000000000000000000000000000001200000000000000000000
+rog 80 1161556116676121638116747174495110461029516151855113396511471865163915713514511276364181664729114789119821108111512418542116745219171132514113471711916341513135181912061999221339252186151418444815161125177110571820181978113411711411552011481451137141191111720715151723181222311619191101103592175811611117131721271461142251121192266142018110728121919191191845711621211111011385101916132124107110717118101733521146110118121101171511111011131411211612114113115202211911912381085117111101111111124111951261101651 30.30.000100000000000000000000000000000100000000000000000000000000000100000000000000000000000000000100000000000000000000000000000111111111111100000000000000000000000000000100000000000000000000000000000100000000000000000000000000000100000000000000000000000000000100000000000000200000000000000100000000000000000000000000001100000000000000000000000000001000000000000000000000000000001000000000000000000000000000001000000000000000000000000000001000000000000000000000000000001000000000000000000000000000001000000000000000000000000000001000000000000000000000000000001000000000000000000000000000001000000000000000100000000000001111111111111111100000000000000000000000000000100000000000000000000000000000100000000000000000000000000000111110000000000000000000000000130000000000000000000000000000010000000000000000000000000000010000000000000000000000000000011111111111100000000000000000000111111111100000000000000000
--- /dev/null
+++ b/lib/scsicodes
@@ -1,0 +1,487 @@
+# hget http://www.t10.org/lists/asc-num.htm |
+# grep '^[0-9]' |tr -d ' ' |tr A-Z a-z |
+# sed 's/(..)\/(..) .............. (.*)/\1\2 \3/' > scsicodes
+# (and then put this header back)
+0000 no additional sense information
+0001 filemark detected
+0002 end-of-partition/medium detected
+0003 setmark detected
+0004 beginning-of-partition/medium detected
+0005 end-of-data detected
+0006 i/o process terminated
+0011 audio play operation in progress
+0012 audio play operation paused
+0013 audio play operation successfully completed
+0014 audio play operation stopped due to error
+0015 no current audio status to return
+0016 operation in progress
+0017 cleaning requested
+0100 no index/sector signal
+0200 no seek complete
+0300 peripheral device write fault
+0301 no write current
+0302 excessive write errors
+0400 logical unit not ready, cause not reportable
+0401 logical unit is in process of becoming ready
+0402 logical unit not ready, initializing cmd. required
+0403 logical unit not ready, manual intervention required
+0404 logical unit not ready, format in progress
+0405 logical unit not ready, rebuild in progress
+0406 logical unit not ready, recalculation in progress
+0407 logical unit not ready, operation in progress
+0408 logical unit not ready, long write in progress
+0409 logical unit not ready, self-test in progress
+0410 auxiliary memory code 2 (99-148) [proposed]
+0500 logical unit does not respond to selection
+0600 no reference position found
+0700 multiple peripheral devices selected
+0800 logical unit communication failure
+0801 logical unit communication time-out
+0802 logical unit communication parity error
+0803 logical unit communication crc error (ultra-dma/32)
+0804 unreachable copy target
+0900 track following error
+0901 tracking servo failure
+0902 focus servo failure
+0903 spindle servo failure
+0904 head select fault
+0a00 error log overflow
+0b00 warning
+0b01 warning - specified temperature exceeded
+0b02 warning - enclosure degraded
+0c00 write error
+0c01 write error - recovered with auto reallocation
+0c02 write error - auto reallocation failed
+0c03 write error - recommend reassignment
+0c04 compression check miscompare error
+0c05 data expansion occurred during compression
+0c06 block not compressible
+0c07 write error - recovery needed
+0c08 write error - recovery failed
+0c09 write error - loss of streaming
+0c0a write error - padding blocks added
+0c0b auxiliary memory code 4 (99-148) [proposed]
+0d/00
+0e/00
+0f/00
+1000 id crc or ecc error
+1100 unrecovered read error
+1101 read retries exhausted
+1102 error too long to correct
+1103 multiple read errors
+1104 unrecovered read error - auto reallocate failed
+1105 l-ec uncorrectable error
+1106 circ unrecovered error
+1107 data re-synchronization error
+1108 incomplete block read
+1109 no gap found
+110a miscorrected error
+110b unrecovered read error - recommend reassignment
+110c unrecovered read error - recommend rewrite the data
+110d de-compression crc error
+110e cannot decompress using declared algorithm
+110f error reading upc/ean number
+1110 error reading isrc number
+1111 read error - loss of streaming
+1112 auxiliary memory code 3 (99-148) [proposed]
+1200 address mark not found for id field
+1300 address mark not found for data field
+1400 recorded entity not found
+1401 record not found
+1402 filemark or setmark not found
+1403 end-of-data not found
+1404 block sequence error
+1405 record not found - recommend reassignment
+1406 record not found - data auto-reallocated
+1500 random positioning error
+1501 mechanical positioning error
+1502 positioning error detected by read of medium
+1600 data synchronization mark error
+1601 data sync error - data rewritten
+1602 data sync error - recommend rewrite
+1603 data sync error - data auto-reallocated
+1604 data sync error - recommend reassignment
+1700 recovered data with no error correction applied
+1701 recovered data with retries
+1702 recovered data with positive head offset
+1703 recovered data with negative head offset
+1704 recovered data with retries and/or circ applied
+1705 recovered data using previous sector id
+1706 recovered data without ecc - data auto-reallocated
+1707 recovered data without ecc - recommend reassignment
+1708 recovered data without ecc - recommend rewrite
+1709 recovered data without ecc - data rewritten
+1800 recovered data with error correction applied
+1801 recovered data with error corr. & retries applied
+1802 recovered data - data auto-reallocated
+1803 recovered data with circ
+1804 recovered data with l-ec
+1805 recovered data - recommend reassignment
+1806 recovered data - recommend rewrite
+1807 recovered data with ecc - data rewritten
+1900 defect list error
+1901 defect list not available
+1902 defect list error in primary list
+1903 defect list error in grown list
+1a00 parameter list length error
+1b00 synchronous data transfer error
+1c00 defect list not found
+1c01 primary defect list not found
+1c02 grown defect list not found
+1d00 miscompare during verify operation
+1e00 recovered id with ecc correction
+1f00 partial defect list transfer
+2000 invalid command operation code
+2001 access controls code 1 (99-314) [proposed]
+2002 access controls code 2 (99-314) [proposed]
+2003 access controls code 3 (99-314) [proposed]
+2100 logical block address out of range
+2101 invalid element address
+2200 illegal function (use 20 00, 24 00, or 26 00)
+23/00
+2400 invalid field in cdb
+2401 cdb decryption error
+2500 logical unit not supported
+2600 invalid field in parameter list
+2601 parameter not supported
+2602 parameter value invalid
+2603 threshold parameters not supported
+2604 invalid release of persistent reservation
+2605 data decryption error
+2606 too many target descriptors
+2607 unsupported target descriptor type code
+2608 too many segment descriptors
+2609 unsupported segment descriptor type code
+260a unexpected inexact segment
+260b inline data length exceeded
+260c invalid operation for copy source or destination
+260d copy segment granularity violation
+2700 write protected
+2701 hardware write protected
+2702 logical unit software write protected
+2703 associated write protect
+2704 persistent write protect
+2705 permanent write protect
+2800 not ready to ready change, medium may have changed
+2801 import or export element accessed
+2900 power on, reset, or bus device reset occurred
+2901 power on occurred
+2902 scsi bus reset occurred
+2903 bus device reset function occurred
+2904 device internal reset
+2905 transceiver mode changed to single-ended
+2906 transceiver mode changed to lvd
+2a00 parameters changed
+2a01 mode parameters changed
+2a02 log parameters changed
+2a03 reservations preempted
+2a04 reservations released
+2a05 registrations preempted
+2b00 copy cannot execute since host cannot disconnect
+2c00 command sequence error
+2c01 too many windows specified
+2c02 invalid combination of windows specified
+2c03 current program area is not empty
+2c04 current program area is empty
+2c05 illegal power condition request
+2d00 overwrite error on update in place
+2e00 error detected by third party temporary initiator
+2e01 third party device failure
+2e02 copy target device not reachable
+2e03 incorrect copy target device type
+2e04 copy target device data underrun
+2e05 copy target device data overrun
+2f00 commands cleared by another initiator
+3000 incompatible medium installed
+3001 cannot read medium - unknown format
+3002 cannot read medium - incompatible format
+3003 cleaning cartridge installed
+3004 cannot write medium - unknown format
+3005 cannot write medium - incompatible format
+3006 cannot format medium - incompatible medium
+3007 cleaning failure
+3008 cannot write - application code mismatch
+3009 current session not fixated for append
+3100 medium format corrupted
+3101 format command failed
+3200 no defect spare location available
+3201 defect list update failure
+3300 tape length error
+3400 enclosure failure
+3500 enclosure services failure
+3501 unsupported enclosure function
+3502 enclosure services unavailable
+3503 enclosure services transfer failure
+3504 enclosure services transfer refused
+3600 ribbon, ink, or toner failure
+3700 rounded parameter
+3800 event status notification
+3802 esn - power management class event
+3804 esn - media class event
+3806 esn - device busy class event
+3900 saving parameters not supported
+3a00 medium not present
+3a01 medium not present - tray closed
+3a02 medium not present - tray open
+3a03 medium not present - loadable
+3a04 medium not present - medium auxiliary memory accessible
+3b00 sequential positioning error
+3b01 tape position error at beginning-of-medium
+3b02 tape position error at end-of-medium
+3b03 tape or electronic vertical forms unit not ready
+3b04 slew failure
+3b05 paper jam
+3b06 failed to sense top-of-form
+3b07 failed to sense bottom-of-form
+3b08 reposition error
+3b09 read past end of medium
+3b0a read past beginning of medium
+3b0b position past end of medium
+3b0c position past beginning of medium
+3b0d medium destination element full
+3b0e medium source element empty
+3b0f end of medium reached
+3b11 medium magazine not accessible
+3b12 medium magazine removed
+3b13 medium magazine inserted
+3b14 medium magazine locked
+3b15 medium magazine unlocked
+3b16 mechanical positioning or changer error
+3c/00
+3d00 invalid bits in identify message
+3e00 logical unit has not self-configured yet
+3e01 logical unit failure
+3e02 timeout on logical unit
+3e03 logical unit failed self-test
+3e04 logical unit unable to update self-test log
+3f00 target operating conditions have changed
+3f01 microcode has been changed
+3f02 changed operating definition
+3f03 inquiry data has changed
+3f04 component device attached
+3f05 device identifier changed
+3f06 redundancy group created or modified
+3f07 redundancy group deleted
+3f08 spare created or modified
+3f09 spare deleted
+3f0a volume set created or modified
+3f0b volume set deleted
+3f0c volume set deassigned
+3f0d volume set reassigned
+3f0e reported luns data has changed
+3f0f echo buffer overwritten
+3f10 medium loadable
+3f11 medium auxiliary memory accessible
+4000 ram failure (should use 40 nn)
+40nn diagnostic failure on component nn (80h-ffh)
+4100 data path failure (should use 40 nn)
+4200 power-on or self-test failure (should use 40 nn)
+4300 message error
+4400 internal target failure
+4500 select or reselect failure
+4600 unsuccessful soft reset
+4700 scsi parity error
+4701 data phase crc error detected
+4702 scsi parity error detected during st data phase
+4703 information unit crc error detected
+4704 asynchronous information protection error detected
+4800 initiator detected error message received
+4900 invalid message error
+4a00 command phase error
+4b00 data phase error
+4c00 logical unit failed self-configuration
+4dnn tagged overlapped commands (nn = queue tag)
+4e00 overlapped commands attempted
+4f/00
+5000 write append error
+5001 write append position error
+5002 position error related to timing
+5100 erase failure
+5200 cartridge fault
+5300 media load or eject failed
+5301 unload tape failure
+5302 medium removal prevented
+5400 scsi to host system interface failure
+5500 system resource failure
+5501 system buffer full
+5502 insufficient reservation resources
+5503 insufficient resources
+5504 insufficient registration resources
+5505 access controls code 4 (99-314) [proposed]
+5506 auxiliary memory code 1 (99-148) [proposed]
+56/00
+5700 unable to recover table-of-contents
+5800 generation does not exist
+5900 updated block read
+5a00 operator request or state change input
+5a01 operator medium removal request
+5a02 operator selected write protect
+5a03 operator selected write permit
+5b00 log exception
+5b01 threshold condition met
+5b02 log counter at maximum
+5b03 log list codes exhausted
+5c00 rpl status change
+5c01 spindles synchronized
+5c02 spindles not synchronized
+5d00 failure prediction threshold exceeded
+5d01 media failure prediction threshold exceeded
+5d02 logical unit failure prediction threshold exceeded
+5d10 hardware impending failure general hard drive failure
+5d11 hardware impending failure drive error rate too high
+5d12 hardware impending failure data error rate too high
+5d13 hardware impending failure seek error rate too high
+5d14 hardware impending failure too many block reassigns
+5d15 hardware impending failure access times too high
+5d16 hardware impending failure start unit times too high
+5d17 hardware impending failure channel parametrics
+5d18 hardware impending failure controller detected
+5d19 hardware impending failure throughput performance
+5d1a hardware impending failure seek time performance
+5d1b hardware impending failure spin-up retry count
+5d1c hardware impending failure drive calibration retry count
+5d20 controller impending failure general hard drive failure
+5d21 controller impending failure drive error rate too high
+5d22 controller impending failure data error rate too high
+5d23 controller impending failure seek error rate too high
+5d24 controller impending failure too many block reassigns
+5d25 controller impending failure access times too high
+5d26 controller impending failure start unit times too high
+5d27 controller impending failure channel parametrics
+5d28 controller impending failure controller detected
+5d29 controller impending failure throughput performance
+5d2a controller impending failure seek time performance
+5d2b controller impending failure spin-up retry count
+5d2c controller impending failure drive calibration retry count
+5d30 data channel impending failure general hard drive failure
+5d31 data channel impending failure drive error rate too high
+5d32 data channel impending failure data error rate too high
+5d33 data channel impending failure seek error rate too high
+5d34 data channel impending failure too many block reassigns
+5d35 data channel impending failure access times too high
+5d36 data channel impending failure start unit times too high
+5d37 data channel impending failure channel parametrics
+5d38 data channel impending failure controller detected
+5d39 data channel impending failure throughput performance
+5d3a data channel impending failure seek time performance
+5d3b data channel impending failure spin-up retry count
+5d3c data channel impending failure drive calibration retry count
+5d40 servo impending failure general hard drive failure
+5d41 servo impending failure drive error rate too high
+5d42 servo impending failure data error rate too high
+5d43 servo impending failure seek error rate too high
+5d44 servo impending failure too many block reassigns
+5d45 servo impending failure access times too high
+5d46 servo impending failure start unit times too high
+5d47 servo impending failure channel parametrics
+5d48 servo impending failure controller detected
+5d49 servo impending failure throughput performance
+5d4a servo impending failure seek time performance
+5d4b servo impending failure spin-up retry count
+5d4c servo impending failure drive calibration retry count
+5d50 spindle impending failure general hard drive failure
+5d51 spindle impending failure drive error rate too high
+5d52 spindle impending failure data error rate too high
+5d53 spindle impending failure seek error rate too high
+5d54 spindle impending failure too many block reassigns
+5d55 spindle impending failure access times too high
+5d56 spindle impending failure start unit times too high
+5d57 spindle impending failure channel parametrics
+5d58 spindle impending failure controller detected
+5d59 spindle impending failure throughput performance
+5d5a spindle impending failure seek time performance
+5d5b spindle impending failure spin-up retry count
+5d5c spindle impending failure drive calibration retry count
+5d60 firmware impending failure general hard drive failure
+5d61 firmware impending failure drive error rate too high
+5d62 firmware impending failure data error rate too high
+5d63 firmware impending failure seek error rate too high
+5d64 firmware impending failure too many block reassigns
+5d65 firmware impending failure access times too high
+5d66 firmware impending failure start unit times too high
+5d67 firmware impending failure channel parametrics
+5d68 firmware impending failure controller detected
+5d69 firmware impending failure throughput performance
+5d6a firmware impending failure seek time performance
+5d6b firmware impending failure spin-up retry count
+5d6c firmware impending failure drive calibration retry count
+5dff failure prediction threshold exceeded (false)
+5e00 low power condition on
+5e01 idle condition activated by timer
+5e02 standby condition activated by timer
+5e03 idle condition activated by command
+5e04 standby condition activated by command
+5e41 power state change to active
+5e42 power state change to idle
+5e43 power state change to standby
+5e45 power state change to sleep
+5e47 power state change to device control
+5f/00
+6000 lamp failure
+6100 video acquisition error
+6101 unable to acquire video
+6102 out of focus
+6200 scan head positioning error
+6300 end of user area encountered on this track
+6301 packet does not fit in available space
+6400 illegal mode for this track
+6401 invalid packet size
+6500 voltage fault
+6600 automatic document feeder cover up
+6601 automatic document feeder lift up
+6602 document jam in automatic document feeder
+6603 document miss feed automatic in document feeder
+6700 configuration failure
+6701 configuration of incapable logical units failed
+6702 add logical unit failed
+6703 modification of logical unit failed
+6704 exchange of logical unit failed
+6705 remove of logical unit failed
+6706 attachment of logical unit failed
+6707 creation of logical unit failed
+6708 assign failure occurred
+6709 multiply assigned logical unit
+6800 logical unit not configured
+6900 data loss on logical unit
+6901 multiple logical unit failures
+6902 parity/data mismatch
+6a00 informational, refer to log
+6b00 state change has occurred
+6b01 redundancy level got better
+6b02 redundancy level got worse
+6c00 rebuild failure occurred
+6d00 recalculate failure occurred
+6e00 command to logical unit failed
+6f00 copy protection key exchange failure - authentication failure
+6f01 copy protection key exchange failure - key not present
+6f02 copy protection key exchange failure - key not established
+6f03 read of scrambled sector without authentication
+6f04 media region code is mismatched to logical unit region
+6f05 drive region must be permanent/region reset count error
+70nn decompression exception short algorithm id of nn
+7100 decompression exception long algorithm id
+7200 session fixation error
+7201 session fixation error writing lead-in
+7202 session fixation error writing lead-out
+7203 session fixation error - incomplete track in session
+7204 empty or partially written reserved track
+7205 no more track reservations allowed
+7300 cd control error
+7301 power calibration area almost full
+7302 power calibration area is full
+7303 power calibration area error
+7304 program memory area update failure
+7305 program memory area is full
+7306 rma/pma is full
+74/00
+75/00
+76/00
+77/00
+78/00
+79/00
+7a/00
+7b/00
+7c/00
+7d/00
+7e/00
+7f/00
--- /dev/null
+++ b/lib/sexp
@@ -1,0 +1,699 @@
+Network Working Group R. Rivest
+Internet Draft May 4, 1997
+Expires November 4, 1997
+
+
+ S-Expressions
+ draft-rivest-sexp-00.txt
+
+
+Status of this Memo
+
+ Distribution of this memo is unlimited.
+
+ This document is an Internet-Draft. Internet Drafts are working
+ documents of the Internet Engineering Task Force (IETF), its Areas,
+ and its Working Groups. Note that other groups may also distribute
+ working documents as Internet Drafts.
+
+ Internet Drafts are draft documents valid for a maximum of six
+ months, and may be updated, replaced, or obsoleted by other documents
+ at any time. It is not appropriate to use Internet Drafts as
+ reference material, or to cite them other than as a ``working draft''
+ or ``work in progress.''
+
+ To learn the current status of any Internet-Draft, please check the
+ ``1id-abstracts.txt'' listing contained in the internet-drafts Shadow
+ Directories on: ftp.is.co.za (Africa), nic.nordu.net (Europe),
+ ds.internic.net (US East Coast), ftp.isi.edu (US West Coast),
+ or munnari.oz.au (Pacific Rim)
+
+
+Abstract
+
+This memo describes a data structure called "S-expressions" that are
+suitable for representing arbitrary complex data structures. We make
+precise the encodings of S-expressions: we give a "canonical form" for
+S-expressions, described two "transport" representations, and also
+describe an "advanced" format for display to people.
+
+
+
+1. Introduction
+
+S-expressions are data structures for representing complex data. They
+are either byte-strings ("octet-strings") or lists of simpler
+S-expressions. Here is a sample S-expression:
+
+ (snicker "abc" (#03# |YWJj|))
+
+It is a list of length three:
+
+ -- the octet-string "snicker"
+
+ -- the octet-string "abc"
+
+ -- a sub-list containing two elements:
+ - the hexadecimal constant #03#
+ - the base-64 constant |YWJj| (which is the same as "abc")
+
+This note gives a specific proposal for constructing and utilizing
+S-expressions. The proposal is independent of any particular application.
+
+Here are the design goals for S-expressions:
+
+ -- generality: S-expressions should be good at representing arbitrary
+ data.
+
+ -- readability: it should be easy for someone to examine and
+ understand the structure of an S-expression.
+
+ -- economy: S-expressions should represent data compactly.
+
+ -- tranportability: S-expressions should be easy to transport
+ over communication media (such as email) that are known to be
+ less than perfect.
+
+ -- flexibility: S-expressions should make it relatively simple to
+ modify and extend data structures.
+
+ -- canonicalization: it should be easy to produce a unique
+ "canonical" form of an S-expression, for digital signature purposes.
+
+ -- efficiency: S-expressions should admit in-memory representations
+ that allow efficient processing.
+
+
+Section 2 gives an introduction to S-expressions.
+Section 3 discusses the character sets used.
+Section 4 presents the various representations of octet-strings.
+Section 5 describes how to represent lists.
+Section 6 discusses how S-expressions are represented for various uses.
+Section 7 gives a BNF syntax for S-expressions.
+Section 8 talks about how S-expressions might be represented in memory.
+Section 9 briefly describes implementations for handling S-expressions.
+Section 10 discusses how applications might utilize S-expressions.
+Section 11 gives historical notes on S-expressions.
+Section 12 gives references.
+
+2. S-expressions -- informal introduction
+
+Informally, an S-expression is either:
+ -- an octet-string, or
+ -- a finite list of simpler S-expressions.
+
+An octet-string is a finite sequence of eight-bit octets. There may be
+many different but equivalent ways of representing an octet-string
+
+ abc -- as a token
+
+ "abc" -- as a quoted string
+
+ #616263# -- as a hexadecimal string
+
+ 3:abc -- as a length-prefixed "verbatim" encoding
+
+ {MzphYmM=} -- as a base-64 encoding of the verbatim encoding
+ (that is, an encoding of "3:abc")
+
+ |YWJj| -- as a base-64 encoding of the octet-string "abc"
+
+These encodings are all equivalent; they all denote the same octet string.
+
+We will give details of these encodings later on, and also describe how to
+give a "display type" to a byte string.
+
+A list is a finite sequence of zero or more simpler S-expressions. A list
+may be represented by using parentheses to surround the sequence of encodings
+of its elements, as in:
+
+ (abc (de #6667#) "ghi jkl")
+
+As we see, there is variability possible in the encoding of an
+S-expression. In some cases, it is desirable to standardize or
+restrict the encodings; in other cases it is desirable to have no
+restrictions. The following are the target cases we aim to handle:
+
+ -- a "transport" encoding for transporting the S-expression between
+ computers.
+
+ -- a "canonical" encoding, used when signing the S-expression.
+
+ -- an "advanced" encoding used for input/output to people.
+
+ -- an "in-memory" encoding used for processing the S-expression in
+ the computer.
+
+These need not be different; in this proposal the canonical encoding
+is the same as the transport encoding, for example. In this note we
+propose (related) encoding techniques for each of these uses.
+
+3. Character set
+
+We will be describing encodings of S-expressions. Except when giving
+"verbatim" encodings, the character set used is limited to the following
+characters in US-ASCII:
+ Alphabetic: A B ... Z a b ... z
+ numeric: 0 1 ... 9
+ whitespace: space, horizontal tab, vertical tab, form-feed
+ carriage-return, line-feed
+ The following graphics characters, which we call "pseudo-alphabetic":
+ - hyphen or minus
+ . period
+ / slash
+ _ underscore
+ : colon
+ * asterisk
+ + plus
+ = equal
+ The following graphics characters, which are "reserved punctuation":
+ ( left parenthesis
+ ) right parenthesis
+ [ left bracket
+ ] right bracket
+ { left brace
+ } right brace
+ | vertical bar
+ # number sign
+ " double quote
+ & ampersand
+ \ backslash
+ The following characters are unused and unavailable, except in
+ "verbatim" encodings:
+ ! exclamation point
+ % percent
+ ^ circumflex
+ ~ tilde
+ ; semicolon
+ ' apostrophe
+ , comma
+ < less than
+ > greater than
+ ? question mark
+
+
+4. Octet string representations
+
+This section describes in detail the ways in which an octet-string may
+be represented.
+
+We recall that an octet-string is any finite sequence of octets, and
+that the octet-string may have length zero.
+
+
+4.1 Verbatim representation
+
+A verbatim encoding of an octet string consists of four parts:
+
+ -- the length (number of octets) of the octet-string,
+ given in decimal most significant digit first, with
+ no leading zeros.
+
+ -- a colon ":"
+
+ -- the octet string itself, verbatim.
+
+There are no blanks or whitespace separating the parts. No "escape
+sequences" are interpreted in the octet string. This encoding is also
+called a "binary" or "raw" encoding.
+
+Here are some sample verbatim encodings:
+
+ 3:abc
+ 7:subject
+ 4:::::
+ 12:hello world!
+ 10:abcdefghij
+ 0:
+
+4.2 Quoted-string representation
+
+The quoted-string representation of an octet-string consists of:
+
+ -- an optional decimal length field
+
+ -- an initial double-quote (")
+
+ -- the octet string with "C" escape conventions (\n,etc)
+
+ -- a final double-quote (")
+
+The specified length is the length of the resulting string after any
+escape sequences have been handled. The string does not have any
+"terminating NULL" that C includes, and the length does not count such
+a character.
+
+The length is optional.
+
+The escape conventions within the quoted string are as follows (these follow
+the "C" programming language conventions, with an extension for
+ignoring line terminators of just LF or CRLF):
+ \b -- backspace
+ \t -- horizontal tab
+ \v -- vertical tab
+ \n -- new-line
+ \f -- form-feed
+ \r -- carriage-return
+ \" -- double-quote
+ \' -- single-quote
+ \\ -- back-slash
+ \ooo -- character with octal value ooo (all three digits
+ must be present)
+ \xhh -- character with hexadecimal value hh (both digits
+ must be present)
+ \<carriage-return> -- causes carriage-return to be ignored.
+ \<line-feed> -- causes linefeed to be ignored
+ \<carriage-return><line-feed> -- causes CRLF to be ignored.
+ \<line-feed><carriage-return> -- causes LFCR to be ignored.
+
+Here are some examples of quoted-string encodings:
+
+ "subject"
+ "hi there"
+ 7"subject"
+ 3"\n\n\n"
+ "This has\n two lines."
+ "This has\
+ one."
+ ""
+
+4.3 Token representation
+
+An octet string that meets the following conditions may be given
+directly as a "token".
+
+ -- it does not begin with a digit
+
+ -- it contains only characters that are
+ -- alphabetic (upper or lower case),
+ -- numeric, or
+ -- one of the eight "pseudo-alphabetic" punctuation marks:
+ - . / _ : * + =
+ (Note: upper and lower case are not equivalent.)
+ (Note: A token may begin with punctuation, including ":").
+
+Here are some examples of token representations:
+
+ subject
+ not-before
+ class-of-1997
+ //microsoft.com/names/smith
+ *
+
+
+4.4 Hexadecimal representation
+
+An octet-string may be represented with a hexadecimal encoding consisting of:
+
+ -- an (optional) decimal length of the octet string
+
+ -- a sharp-sign "#"
+
+ -- a hexadecimal encoding of the octet string, with each octet
+ represented with two hexadecimal digits, most significant
+ digit first.
+
+ -- a sharp-sign "#"
+
+There may be whitespace inserted in the midst of the hexadecimal
+encoding arbitrarily; it is ignored. It is an error to have
+characters other than whitespace and hexadecimal digits.
+
+Here are some examples of hexadecimal encodings:
+
+ #616263# -- represents "abc"
+ 3#616263# -- also represents "abc"
+ # 616
+ 263 # -- also represents "abc"
+
+
+4.5 Base-64 representation
+
+An octet-string may be represented in a base-64 coding consisting of:
+
+ -- an (optional) decimal length of the octet string
+
+ -- a vertical bar "|"
+
+ -- the rfc 1521 base-64 encoding of the octet string.
+
+ -- a final vertical bar "|"
+
+The base-64 encoding uses only the characters
+ A-Z a-z 0-9 + / =
+It produces four characters of output for each three octets of input.
+If the input has one or two left-over octets of input, it produces an
+output block of length four ending in two or one equals signs, respectively.
+Output routines compliant with this standard MUST output the equals signs
+as specified. Input routines MAY accept inputs where the equals signs are
+dropped.
+
+There may be whitespace inserted in the midst of the base-64 encoding
+arbitrarily; it is ignored. It is an error to have characters other
+than whitespace and base-64 characters.
+
+Here are some examples of base-64 encodings:
+
+ |YWJj| -- represents "abc"
+ | Y W
+ J j | -- also represents "abc"
+ 3|YWJj| -- also represents "abc"
+ |YWJjZA==| -- represents "abcd"
+ |YWJjZA| -- also represents "abcd"
+
+
+4.6 Display hint
+
+Any octet string may be preceded by a single "display hint".
+
+The purposes of the display hint is to provide information on how
+to display the octet string to a user. It has no other function.
+Many of the MIME types work here.
+
+A display-hint is an octet string surrounded by square brackets.
+There may be whitespace separating the octet string from the
+surrounding brackets. Any of the legal formats may be used for the
+octet string.
+
+Here are some examples of display-hints:
+
+ [image/gif]
+ [URI]
+ [charset=unicode-1-1]
+ [text/richtext]
+ [application/postscript]
+ [audio/basic]
+ ["http://abc.com/display-types/funky.html"]
+
+In applications an octet-string that is untyped may be considered to have
+a pre-specified "default" mime type. The mime type
+ "text/plain; charset=iso-8859-1"
+is the standard default.
+
+
+4.7 Equality of octet-strings
+
+Two octet strings are considered to be "equal" if and only if they
+have the same display hint and the same data octet strings.
+
+Note that octet-strings are "case-sensitive"; the octet-string "abc"
+is not equal to the octet-string "ABC".
+
+An untyped octet-string can be compared to another octet-string (typed
+or not) by considering it as a typed octet-string with the default
+mime-type.
+
+
+5. Lists
+
+Just as with octet-strings, there are several ways to represent an
+S-expression. Whitespace may be used to separate list elements, but
+they are only required to separate two octet strings when otherwise
+the two octet strings might be interpreted as one, as when one token
+follows another. Also, whitespace may follow the initial left
+parenthesis, or precede the final right parenthesis.
+
+Here are some examples of encodings of lists:
+
+ (a b c)
+
+ ( a ( b c ) ( ( d e ) ( e f ) ) )
+
+ (11:certificate(6:issuer3:bob)(7:subject5:alice))
+
+ ({3Rt=} "1997" murphy 3:{XC++})
+
+
+6. Representation types
+
+There are three "types" of representations:
+
+ -- canonical
+
+ -- basic transport
+
+ -- advanced transport
+
+The first two MUST be supported by any implementation; the last is
+optional.
+
+
+6.1 Canonical representation
+
+This canonical representation is used for digital signature purposes,
+transmission, etc. It is uniquely defined for each S-expression. It
+is not particularly readable, but that is not the point. It is
+intended to be very easy to parse, to be reasonably economical, and to
+be unique for any S-expression.
+
+The "canonical" form of an S-expression represents each octet-string
+in verbatim mode, and represents each list with no blanks separating
+elements from each other or from the surrounding parentheses.
+
+Here are some examples of canonical representations of S-expressions:
+
+ (6:issuer3:bob)
+
+ (4:icon[12:image/bitmap]9:xxxxxxxxx)
+
+ (7:subject(3:ref5:alice6:mother))
+
+
+6.2 Basic transport representation
+
+There are two forms of the "basic transport" representation:
+
+ -- the canonical representation
+
+ -- an rfc-2045 base-64 representation of the canonical representation,
+ surrounded by braces.
+
+The transport mechanism is intended to provide a universal means of
+representing S-expressions for transport from one machine to another.
+
+Here are some examples of an S-expression represented in basic
+transport mode:
+
+ (1:a1:b1:c)
+
+ {KDE6YTE6YjE6YykA}
+
+ (this is the same S-expression encoded in base-64)
+
+There is a difference between the brace notation for base-64 used here
+and the || notation for base-64'd octet-strings described above. Here
+the base-64 contents are converted to octets, and then re-scanned as
+if they were given originally as octets. With the || notation, the
+contents are just turned into an octet-string.
+
+
+6.3 Advanced transport representation
+
+The "advanced transport" representation is intended to provide more
+flexible and readable notations for documentation, design, debugging,
+and (in some cases) user interface.
+
+The advanced transport representation allows all of the representation
+forms described above, include quoted strings, base-64 and hexadecimal
+representation of strings, tokens, representations of strings with
+omitted lengths, and so on.
+
+
+7. BNF for syntax
+
+We give separate BNF's for canonical and advanced forms of S-expressions.
+We use the following notation:
+ <x>* means 0 or more occurrences of <x>
+ <x>+ means 1 or more occurrences of <x>
+ <x>? means 0 or 1 occurrences of <x>
+ parentheses are used for grouping, as in (<x> | <y>)*
+
+For canonical and basic transport:
+
+<sexpr> :: <string> | <list>
+<string> :: <display>? <simple-string> ;
+<simple-string> :: <raw> ;
+<display> :: "[" <simple-string> "]" ;
+<raw> :: <decimal> ":" <bytes> ;
+<decimal> :: <decimal-digit>+ ;
+ -- decimal numbers should have no unnecessary leading zeros
+<bytes> -- any string of bytes, of the indicated length
+<list> :: "(" <sexp>* ")" ;
+<decimal-digit> :: "0" | ... | "9" ;
+
+For advanced transport:
+
+<sexpr> :: <string> | <list>
+<string> :: <display>? <simple-string> ;
+<simple-string> :: <raw> | <token> | <base-64> | <hexadecimal> |
+ <quoted-string> ;
+<display> :: "[" <simple-string> "]" ;
+<raw> :: <decimal> ":" <bytes> ;
+<decimal> :: <decimal-digit>+ ;
+ -- decimal numbers should have no unnecessary leading zeros
+<bytes> -- any string of bytes, of the indicated length
+<token> :: <tokenchar>+ ;
+<base-64> :: <decimal>? "|" ( <base-64-char> | <whitespace> )* "|" ;
+<hexadecimal> :: "#" ( <hex-digit> | <white-space> )* "#" ;
+<quoted-string> :: <decimal>? <quoted-string-body>
+<quoted-string-body> :: "\"" <bytes> "\""
+<list> :: "(" ( <sexp> | <whitespace> )* ")" ;
+<whitespace> :: <whitespace-char>* ;
+<token-char> :: <alpha> | <decimal-digit> | <simple-punc> ;
+<alpha> :: <upper-case> | <lower-case> | <digit> ;
+<lower-case> :: "a" | ... | "z" ;
+<upper-case> :: "A" | ... | "Z" ;
+<decimal-digit> :: "0" | ... | "9" ;
+<hex-digit> :: <decimal-digit> | "A" | ... | "F" | "a" | ... | "f" ;
+<simple-punc> :: "-" | "." | "/" | "_" | ":" | "*" | "+" | "=" ;
+<whitespace-char> :: " " | "\t" | "\r" | "\n" ;
+<base-64-char> :: <alpha> | <decimal-digit> | "+" | "/" | "=" ;
+<null> :: "" ;
+
+8. In-memory representations
+
+For processing, the S-expression would typically be parsed and represented
+in memory in a more more amenable to efficient processing. We suggest
+two alternatives:
+
+ -- "list-structure"
+
+ -- "array-layout"
+
+We only sketch these here, as they are only suggestive. The code referenced
+below illustrates these styles in more detail.
+
+
+8.1. List-structure memory representation
+
+Here there are separate records for simple-strings, strings, and
+lists. An S-expression of the form ("abc" "de") would require two
+records for the simple strings, two for the strings, and two for the
+list elements. This is a fairly conventional representation, and
+details are omitted here.
+
+8.2 Array-layout memory representation
+
+Here each S-expression is represented as a contiguous array of bytes.
+The first byte codes the "type" of the S-expression:
+
+ 01 octet-string
+
+ 02 octet-string with display-hint
+
+ 03 beginning of list (and 00 is used for "end of list")
+
+Each of the three types is immediately followed by a k-byte integer
+indicating the size (in bytes) of the following representation. Here
+k is an integer that depends on the implementation, it might be
+anywhere from 2 to 8, but would be fixed for a given implementation;
+it determines the size of the objects that can be handled. The transport
+and canonical representations are independent of the choice of k made by
+the implementation.
+
+Although the length of lists are not given in the usual S-expression
+notations, it is easy to fill them in when parsing; when you reach a
+right-parenthesis you know how long the list representation was, and
+where to go back to fill in the missing length.
+
+
+8.2.1 Octet string
+
+This is represented as follows:
+
+ 01 <length> <octet-string>
+
+For example (here k = 2)
+
+ 01 0003 a b c
+
+8.2.2 Octet-string with display-hint
+
+This is represented as follows:
+
+ 02 <length>
+ 01 <length> <octet-string> /* for display-type */
+ 01 <length> <octet-string> /* for octet-string */
+
+For example, the S-expression
+
+ [gif] #61626364#
+
+would be represented as (with k = 2)
+
+ 02 000d
+ 01 0003 g i f
+ 01 0004 61 62 63 64
+
+8.2.3 List
+
+This is represented as
+
+ 03 <length> <item1> <item2> <item3> ... <itemn> 00
+
+For example, the list (abc [d]ef (g)) is represented in memory as (with k=2)
+
+ 03 001b
+ 01 0003 a b c
+ 02 0009
+ 01 0001 d
+ 01 0002 e f
+ 03 0005
+ 01 0001 g
+ 00
+ 00
+
+9. Code
+
+There is code available for reading and parsing the various
+S-expression formats proposed here.
+
+See http://theory.lcs.mit.edu/~rivest/sexp.html
+
+
+10. Utilization of S-expressions
+
+This note has described S-expressions in general form. Application writers
+may wish to restrict their use of S-expressions in various ways. Here are
+some possible restrictions that might be considered:
+
+ -- no display-hints
+ -- no lengths on hexadecimal, quoted-strings, or base-64 encodings
+ -- no empty lists
+ -- no empty octet-strings
+ -- no lists having another list as its first element
+ -- no base-64 or hexadecimal encodings
+ -- fixed limits on the size of octet-strings
+
+11. Historical note
+
+The S-expression technology described here was originally developed
+for ``SDSI'' (the Simple Distributed Security Infrastructure by
+Lampson and Rivest [SDSI]) in 1996, although the origins clearly date
+back to McCarthy's LISP programming language. It was further refined
+and improved during the merger of SDSI and SPKI [SPKI] during the
+first half of 1997. S-expressions are similar to, but more readable
+and flexible than, Bernstein's "net-strings" [BERN].
+
+12. References
+
+[SDSI] "A Simple Distributed Security Architecture", by
+ Butler Lampson, and Ronald L. Rivest
+ http://theory.lcs.mit.edu/~cis/sdsi.html
+
+[SPKI] <a href="http://www.clark.net/pub/cme/html/spki.html">SPKI--A
+ Simple Public Key Infrastructure</a>
+
+[BERN] Dan Bernstein's "net-strings"; Internet Draft
+ draft-bernstein-netstrings-02.txt
+
+Author's Address
+
+ Ronald L. Rivest
+ Room 324, 545 Technology Square
+ MIT Laboratory for Computer Science
+ Cambridge, MA 02139
+
+ rivest@theory.lcs.mit.edu
+
+
--- /dev/null
+++ b/lib/sh/owen
@@ -1,0 +1,121 @@
+load std sexprs
+
+# load a job. result is the new job id.
+subfn job {
+ {
+ id := "{read}
+ result=$id
+ or {echo load ${quote $*} >[1=0]} {
+ raise 'load failed'
+ }
+ } $* <> /n/remote/admin/clone
+}
+
+# load a job. print the new job id.
+fn job {
+ echo ${job $*}
+}
+
+# load a job, then start it.
+fn start {
+ id := ${job $*}
+ ctl $id start
+ echo $id
+}
+
+# send a control message to a job.
+fn ctl {
+ if {~ $#* 0 1} {
+ echo usage: ctl job-id request... >[1=2]
+ raise usage
+ }
+ (id args) := $*
+ echo ${quote $args} > /n/remote/admin/$id/ctl
+}
+
+# mount the scheduler name space
+fn mountsched {
+ configfile := $configfile # stop changes propagating out.
+ if{no $root}{
+ root=/grid/slave
+ }
+ opts := ()
+ fsopts := ()
+ schedaddr := ()
+ schedfsaddr := ()
+ readconfig {
+ if{~ $attr schedaddr}{
+ schedaddr=$val
+ }{~ $attr auth}{
+ if{~ $val 0}{
+ opts=($opts -A)
+ }
+ }{~ $attr keyfile}{
+ opts=($opts -k $val)
+ }{~ $attr schedfsaddr}{
+ schedfsaddr=$val
+ }{~ $attr fsauth}{
+ if{~ $val 0}{
+ fsopts=($fsopts -A)
+ }
+ }{~ $attr fskey fskeyfile}{ # first form is deprecated
+ fsopts=($opts -k $val)
+ }
+ }
+ if{no $schedaddr}{
+ ifs='
+ '
+ schedaddr=`{cat /grid/slave/schedaddr}
+ if{no $schedaddr}{
+ echo no scheduler address found >[1=2]
+ raise error
+ }
+ }
+ mount $opts $schedaddr /n/remote
+ no $schedfsaddr ||
+ mount $fsopts $schedfsaddr /n/gridfs
+}
+
+# print a format(2) file with the given format
+fn fmtcat {
+ if {! ~ $#* 2} {
+ echo usage: fmtread fmt file >[1=2]
+ raise usage
+ }
+ (fmt file) := $*
+ {echo $fmt >[1=0]; read -o 0; cat} <> $file
+}
+
+# readconfig command.
+# on entry $configfile is name of configuration file, or empty for default.
+# $root is default root directory.
+# run command for each entry in the config file, setting $attr and $val
+# to the attribute and the value in the entry.
+fn readconfig {
+ (cmd nil) := $*
+ if{no $configfile}{
+ if{ftest -f $root/config}{
+ configfile = $root/config
+ }
+ } {
+ if{! ~ $configfile '/*' './*'} {
+ configfile = $root/$configfile
+ }
+ if{! ftest -f $configfile}{
+ echo cannot find config file $configfile >[1=2]
+ raise 'config error'
+ }
+ }
+ if{! no $configfile} {
+ < $configfile getsexprs {
+ (attr sval) := ${els $sexp}
+ if{! ~ $#sval 1}{
+ echo bad config line $sexp >[1=2]
+ raise continue;
+ }
+ attr = ${text $attr}
+ val := ${text $sval}
+ $cmd
+ }
+ }
+}
--- /dev/null
+++ b/lib/sh/profile
@@ -1,0 +1,1 @@
+# emu sh initialisation here
--- /dev/null
+++ b/lib/sh/sched
@@ -1,0 +1,121 @@
+load std sexprs
+
+# load a job. result is the new job id.
+subfn job {
+ {
+ id := "{read}
+ result=$id
+ or {echo load ${quote $*} >[1=0]} {
+ raise 'load failed'
+ }
+ } $* <> /n/remote/admin/clone
+}
+
+# load a job. print the new job id.
+fn job {
+ echo ${job $*}
+}
+
+# load a job, then start it.
+fn start {
+ id := ${job $*}
+ ctl $id start
+ echo $id
+}
+
+# send a control message to a job.
+fn ctl {
+ if {~ $#* 0 1} {
+ echo usage: ctl job-id request... >[1=2]
+ raise usage
+ }
+ (id args) := $*
+ echo ${quote $args} > /n/remote/admin/$id/ctl
+}
+
+# mount the scheduler name space
+fn mountsched {
+ configfile := $configfile # stop changes propagating out.
+ if{no $root}{
+ root=/grid/slave
+ }
+ opts := ()
+ fsopts := ()
+ schedaddr := ()
+ schedfsaddr := ()
+ readconfig {
+ if{~ $attr schedaddr}{
+ schedaddr=$val
+ }{~ $attr auth}{
+ if{~ $val 0}{
+ opts=($opts -A)
+ }
+ }{~ $attr keyfile}{
+ opts=($opts -k $val)
+ }{~ $attr schedfsaddr}{
+ schedfsaddr=$val
+ }{~ $attr fsauth}{
+ if{~ $val 0}{
+ fsopts=($fsopts -A)
+ }
+ }{~ $attr fskey fskeyfile}{ # first form is deprecated
+ fsopts=($opts -k $val)
+ }
+ }
+ if{no $schedaddr}{
+ ifs='
+ '
+ schedaddr=`{cat /grid/slave/schedaddr}
+ if{no $schedaddr}{
+ echo no scheduler address found >[1=2]
+ raise error
+ }
+ }
+ mount $opts $schedaddr /n/remote
+ no $schedfsaddr ||
+ mount $fsopts $schedfsaddr /n/gridfs
+}
+
+# print a format(2) file with the given format
+fn fmtcat {
+ if {! ~ $#* 2} {
+ echo usage: fmtread fmt file >[1=2]
+ raise usage
+ }
+ (fmt file) := $*
+ {echo $fmt >[1=0]; read -o 0; cat} <> $file
+}
+
+# readconfig command.
+# on entry $configfile is name of configuration file, or empty for default.
+# $root is default root directory.
+# run command for each entry in the config file, setting $attr and $val
+# to the attribute and the value in the entry.
+fn readconfig {
+ (cmd nil) := $*
+ if{no $configfile}{
+ if{ftest -f $root/config}{
+ configfile = $root/config
+ }
+ } {
+ if{! ~ $configfile '/*' './*'} {
+ configfile = $root/$configfile
+ }
+ if{! ftest -f $configfile}{
+ echo cannot find config file $configfile >[1=2]
+ raise 'config error'
+ }
+ }
+ if{! no $configfile} {
+ < $configfile getsexprs {
+ (attr sval) := ${els $sexp}
+ if{! ~ $#sval 1}{
+ echo bad config line $sexp >[1=2]
+ raise continue;
+ }
+ attr = ${text $attr}
+ val := ${text $sval}
+ $cmd
+ }
+ }
+}
--- /dev/null
+++ b/lib/sh/srv
@@ -1,0 +1,24 @@
+# shell functions for starting inferno services
+load std
+
+fn srv {
+ if {! ftest -f /net/cs} {
+ srv.cs
+ }
+ srv.styx
+}
+
+fn srv.cs {
+ ndb/dns -r
+ ndb/cs
+}
+
+fn srv.styx {
+ listen tcp!*!styx {export /&}
+}
+
+fn srv.auth {
+ listen -A tcp!*!inflogin auth/logind
+ listen -A tcp!*!infsigner auth/signer
+ # listen -A tcp!*!infcsigner auth/countersigner
+}
--- /dev/null
+++ b/lib/sh/win
@@ -1,0 +1,42 @@
+load tk std
+
+fn x {
+ or {tk $wid $*} {
+ echo error on tk cmd $"*':' $status >[1=2]
+ }
+}
+
+subfn x {
+ result = ${tk $wid $*}
+ if {~ $result '!*'} {
+ echo error on tk cmd $"*':' $result >[1=2]
+ }
+}
+
+fn tkwin {
+ if {! ~ $#* 2} {
+ echo usage: tkwin name {command} >[1=2]
+ raise usage
+ }
+ wid := ${tk window $1}
+ while {} {
+ tk winctl $wid ${recv $wid}
+ } &
+ $2
+}
+
+# more for interactive use
+fn tkmkwin {
+ if {! ~ $#* 1} {
+ echo usage: tkmkwin name >[1=2]
+ raise usage
+ }
+ wid = ${tk window $1}
+ while {} {
+ tk winctl $wid ${recv $wid}
+ } &
+}
+
+fn onscreen {
+ tk onscreen $wid $1
+}
binary files /dev/null b/lib/strokes/digits.bit differ
--- /dev/null
+++ b/lib/strokes/digits.cl
@@ -1,0 +1,89 @@
+20
+4 0
+28 111 162 110 161 109 160 108 160 107 160 105 162 102 163 100 166 98 170 97 175 97 180 97 187 100 192 105 196 111 198 118 197 126 194 133 189 138 183 142 177 142 170 139 165 134 161 127 159 120 159 113 160 108 162 104 166
+27 40 155 39 154 38 154 37 153 35 153 32 155 30 157 28 160 27 164 26 169 27 176 29 182 32 188 36 192 40 194 45 193 50 190 54 184 58 178 61 171 62 164 60 158 56 154 50 152 44 153 37 155 32 159
+29 102 43 103 43 102 43 101 43 99 45 97 47 95 50 94 55 93 60 94 65 95 68 97 73 101 76 106 77 112 77 117 75 122 73 126 69 128 64 128 59 127 53 124 48 120 43 114 40 109 39 104 39 100 41 98 43 97 46
+26 28 39 27 38 27 39 26 40 24 41 22 44 21 48 20 52 19 58 20 64 22 69 25 73 29 76 34 77 38 75 43 72 47 68 50 63 51 57 51 51 49 46 46 41 42 38 37 37 32 37 29 39
+8 1
+43 158 35 158 36 157 37 157 40 156 42 156 44 156 47 155 50 155 53 154 55 154 58 153 60 153 62 153 64 153 66 153 69 153 71 153 73 153 74 153 76 153 77 153 79 153 80 153 82 153 80 153 82 153 84 153 86 153 88 153 89 153 91 153 93 154 95 154 97 154 98 154 99 154 100 154 101 154 102 154 103 154 104 154 105 154 106
+60 46 31 46 32 45 33 45 34 45 36 44 38 44 39 43 41 43 44 42 46 42 48 42 49 42 51 42 54 42 55 42 57 42 59 42 60 42 62 42 63 42 64 42 65 42 66 42 67 42 69 42 71 42 73 42 74 42 73 42 74 42 76 42 77 42 78 42 79 42 80 42 81 42 82 42 83 41 83 41 84 41 85 41 86 41 88 41 89 41 90 41 91 41 92 40 92 40 93 40 94 40 95 40 96 40 97 40 98 40 99 40 100 40 101 40 102 40 103 40 102
+20 112 25 112 26 112 28 112 30 113 33 113 37 113 41 113 45 113 52 113 56 113 60 113 63 113 67 112 70 112 74 112 77 112 78 111 79 111 80 111 81
+30 52 28 52 29 52 31 52 33 52 35 52 37 53 40 53 43 53 45 53 48 53 50 53 53 53 55 53 58 53 60 53 62 53 64 53 65 53 67 53 68 53 69 53 70 53 71 53 72 53 73 52 73 52 74 52 75 51 75 51 76
+15 117 153 117 152 117 153 117 156 117 160 117 166 117 172 117 180 117 186 117 191 117 195 118 197 118 198 119 198 119 197
+14 35 150 36 149 37 149 37 151 37 155 37 160 36 167 36 175 36 182 36 189 37 193 38 196 38 197 39 196
+11 109 34 109 35 110 37 110 42 111 48 111 56 111 64 111 72 112 78 112 81 112 82
+13 26 30 26 32 27 36 27 41 27 48 27 56 27 63 27 69 27 74 27 78 28 79 28 80 28 81
+4 2
+28 100 163 99 162 100 162 102 161 105 161 110 160 116 160 121 160 126 162 129 165 129 170 127 176 123 183 118 189 113 194 108 198 105 200 104 201 103 201 105 201 107 201 110 200 114 200 119 199 125 199 130 199 134 198 138 198
+30 27 161 26 160 26 159 27 159 28 158 30 157 33 157 37 157 39 158 42 161 43 165 43 171 42 179 39 186 35 193 30 199 26 202 23 204 21 204 21 202 22 200 25 198 29 196 33 195 38 196 43 197 48 198 52 200 54 201 56 202
+33 96 39 96 38 96 37 96 36 97 35 99 33 101 32 104 31 106 31 109 31 112 33 113 37 115 42 115 48 115 55 114 62 112 68 109 73 106 77 102 80 100 81 96 82 94 81 94 80 95 79 98 78 102 76 108 76 114 75 119 76 124 76 127 77 129 77
+25 19 37 18 36 19 35 20 33 23 32 26 31 30 31 34 32 37 34 38 38 37 44 35 51 31 58 26 65 21 71 17 75 15 78 14 78 16 78 19 76 23 76 28 75 32 75 36 75 40 75
+4 3
+36 84 161 85 160 86 159 88 158 91 157 95 156 100 156 104 156 109 157 112 159 113 163 113 167 110 173 107 177 104 180 102 183 101 184 100 184 101 184 103 183 105 182 108 182 110 182 113 183 115 185 116 187 116 191 115 195 113 199 109 202 105 204 100 206 95 206 91 205 88 204 85 202
+38 18 163 18 164 19 163 20 163 22 162 24 162 28 161 31 161 35 162 38 163 40 164 41 167 41 169 40 172 38 175 36 177 34 179 32 180 31 180 32 180 33 180 35 180 37 180 40 181 43 182 45 184 47 188 47 191 47 195 44 199 41 202 38 204 35 204 32 203 30 201 28 199 25 197 23 197
+36 93 34 92 34 93 33 94 31 97 29 101 28 105 27 110 27 113 27 115 30 116 33 115 37 112 42 109 47 106 51 103 54 102 55 101 55 102 54 104 53 107 52 110 52 113 54 115 56 117 59 118 63 118 67 116 71 113 74 109 77 104 78 100 79 95 79 92 77 90 76 88 74
+36 12 29 13 28 14 27 15 26 18 24 20 23 24 22 27 22 30 22 33 24 34 27 35 30 34 34 31 38 29 42 27 45 25 46 24 47 25 46 27 45 29 45 31 45 34 45 36 48 38 52 39 57 40 62 39 67 37 71 34 74 31 76 27 77 24 76 20 75 18 73 16 71
+4 4
+26 107 158 107 157 108 158 108 160 109 163 109 167 109 172 108 176 107 181 106 185 106 188 106 190 106 191 108 191 110 191 112 190 116 189 120 188 124 187 130 186 136 185 141 185 147 185 151 185 154 184 155 184
+24 22 159 23 160 23 161 23 162 24 164 24 167 25 170 25 173 24 176 24 179 24 181 24 182 25 183 26 183 27 183 29 183 32 182 35 182 40 181 45 180 51 179 56 179 60 178 63 177
+20 104 26 105 26 105 27 106 29 106 34 106 39 106 45 106 50 105 54 105 57 106 59 108 59 110 58 114 58 118 57 123 57 127 56 131 56 135 57 137 57
+22 19 24 20 24 20 25 21 27 21 31 21 35 21 41 20 47 19 53 18 58 18 62 18 64 19 66 22 66 26 66 31 66 36 65 42 65 46 65 49 65 52 66 53 66
+4 6
+33 114 148 114 147 113 147 113 148 111 149 110 152 108 155 106 158 104 163 103 168 103 173 103 178 105 182 107 187 111 190 115 193 119 194 123 195 128 194 132 192 135 188 139 186 140 183 141 180 140 178 138 176 134 175 129 174 123 174 118 175 113 176 109 178 107 180
+35 47 154 47 153 47 152 47 151 47 150 46 149 45 147 43 146 41 146 38 147 35 149 33 152 30 157 28 163 28 169 28 177 29 184 31 190 33 195 36 197 38 198 41 198 44 196 46 194 48 190 49 187 49 184 48 181 47 179 45 178 42 178 39 179 35 180 30 183 26 186
+41 127 30 127 31 127 30 128 30 128 29 128 28 128 26 127 25 126 23 125 21 123 19 121 18 119 16 117 16 115 16 113 17 110 19 108 22 106 26 103 32 102 38 100 44 100 52 100 59 101 65 103 70 106 74 110 76 114 77 119 76 123 74 126 72 127 68 127 65 125 62 121 61 117 60 113 62 109 64 106 67 105 70
+30 29 16 28 16 27 17 26 20 24 23 23 28 22 35 21 42 21 50 22 57 23 63 26 67 29 69 32 70 35 69 39 68 42 66 44 64 46 61 47 59 46 56 45 53 43 51 39 49 35 49 30 49 26 51 23 53 21 56 21 60
+4 7
+26 98 161 97 161 97 160 98 160 99 160 102 160 107 159 112 159 118 158 124 158 130 157 134 157 135 157 136 158 135 159 134 162 133 164 131 169 127 176 124 184 120 192 116 199 114 204 113 207 113 208 113 207
+27 27 152 26 153 25 153 26 153 28 153 30 154 34 154 38 154 43 154 48 155 52 156 55 156 57 157 58 158 58 157 58 158 57 159 56 161 55 163 53 168 51 175 47 183 44 192 41 201 39 207 38 211 38 213
+27 102 40 102 41 104 41 106 41 110 40 115 39 120 39 125 38 129 38 132 38 134 38 135 39 136 39 136 40 136 41 136 42 135 43 134 46 133 51 130 57 127 65 125 74 122 81 120 87 119 91 118 94 118 95
+28 27 36 26 37 25 37 24 37 23 37 24 37 25 36 28 36 32 36 38 36 44 35 51 34 57 34 61 33 64 33 65 34 65 37 63 40 61 45 58 51 55 58 52 66 50 72 48 77 47 81 46 82 46 83 45 83
+4 8
+43 123 152 124 151 125 151 125 150 125 149 124 148 123 148 121 148 117 149 113 152 109 155 106 158 104 162 104 165 105 168 108 170 112 171 116 173 121 174 125 176 128 179 129 182 129 186 127 189 124 193 119 196 114 197 110 196 108 194 106 190 107 186 109 182 113 177 116 174 121 171 124 168 127 165 129 162 129 159 128 157 126 155 123 154 122 153
+46 43 146 43 145 43 144 42 143 42 142 41 141 39 140 37 140 33 141 30 142 26 144 23 147 22 150 21 153 22 156 24 159 27 162 29 164 32 165 36 167 39 169 42 171 45 173 47 176 48 179 48 183 47 186 45 188 41 190 37 191 32 191 28 190 24 187 22 184 23 180 25 175 28 170 32 166 37 162 41 159 44 156 45 154 45 152 44 150 42 149 40 149
+44 120 34 120 33 120 32 120 31 120 30 118 29 117 27 114 26 111 26 108 27 105 29 102 32 100 35 100 40 100 44 102 47 105 50 109 51 113 53 117 54 121 56 124 58 126 61 127 65 127 69 126 72 124 75 120 77 116 79 110 80 106 80 101 79 99 77 98 75 99 70 103 65 108 59 113 53 117 47 121 43 123 39 124 36 123 35 122 34
+41 38 23 38 22 37 21 35 20 33 20 30 21 26 22 23 24 20 26 19 29 18 32 18 35 20 38 23 40 26 41 30 43 34 44 37 45 41 47 43 49 44 53 44 57 44 61 42 65 40 68 37 70 34 70 30 69 28 67 26 64 26 61 27 56 29 51 32 45 36 39 39 34 41 31 42 27 43 23 42 20 40 19
+4 9
+34 127 159 127 158 126 157 126 156 125 156 123 155 121 154 118 153 114 153 110 154 107 156 104 159 102 163 102 168 103 172 105 175 108 177 112 176 116 175 119 172 121 170 123 167 124 165 124 164 125 164 125 166 126 169 126 173 127 179 128 192 129 198 130 202 130 204 131 204
+40 53 158 53 157 53 155 53 154 52 153 51 152 49 150 47 149 44 149 41 150 38 151 34 154 32 157 30 161 31 165 33 168 36 170 40 171 45 171 48 169 52 168 54 166 55 163 56 162 56 160 56 159 56 160 57 163 57 167 58 173 59 180 60 188 60 195 59 201 58 206 56 210 54 211 53 211 51 211 50 210
+42 127 36 128 36 128 35 128 34 128 33 127 32 125 31 123 30 120 30 115 30 111 31 107 32 104 34 102 36 102 40 103 43 106 46 110 49 113 50 118 50 123 49 127 46 131 44 133 41 135 40 136 39 136 38 136 39 135 40 135 42 135 46 135 52 134 58 133 65 133 72 132 78 131 82 130 84 129 85 127 85 126 85 125 85
+40 50 34 50 33 50 32 50 31 49 31 47 30 46 29 43 29 40 28 36 29 32 30 28 31 26 33 24 36 24 40 25 44 28 47 32 49 36 50 41 49 45 47 49 43 52 40 54 37 55 35 55 34 55 33 55 35 55 38 55 42 56 48 57 54 58 62 58 70 58 76 57 81 57 84 56 85 55 85 55 83
+4 B
+12 143 155 142 155 141 155 139 155 135 155 130 155 124 156 116 156 108 157 100 158 95 158 90 158
+11 58 154 57 154 55 154 53 153 49 153 44 153 39 153 33 154 28 154 24 155 21 157
+10 142 60 141 59 139 59 136 58 132 58 126 58 119 58 110 59 102 60 96 62
+12 66 61 67 61 66 61 64 61 61 60 55 60 49 60 41 60 32 61 26 62 21 63 18 64
+4 N
+11 102 209 104 208 106 206 109 203 113 199 118 194 123 188 128 182 132 177 136 173 138 171
+14 22 206 22 205 23 203 25 199 28 195 32 190 36 184 41 178 46 173 50 169 54 165 56 163 59 161 60 160
+11 97 92 97 91 98 90 100 86 103 82 108 75 114 67 122 58 129 49 134 42 138 37
+13 27 66 27 67 26 67 27 65 28 63 31 59 34 54 38 49 43 43 47 38 50 34 52 32 52 33
+2 A
+13 13 59 14 59 17 60 21 60 31 60 38 60 48 60 55 60 59 61 63 61 64 61 65 61 64 61
+14 48 106 49 106 51 106 55 106 59 107 63 107 70 108 80 108 87 108 91 108 95 108 97 108 98 108 97 108
+2 S
+19 52 111 52 110 52 107 51 105 51 103 50 101 50 99 49 96 49 93 48 89 48 87 48 84 48 82 48 81 48 80 48 79 48 78 48 77 47 77
+22 102 140 102 139 102 137 103 134 103 131 103 128 104 125 104 121 104 118 105 115 106 112 107 109 108 106 108 103 109 101 109 99 109 97 110 95 110 93 110 92 110 91 110 92
+2 R
+24 75 27 75 28 74 30 72 32 69 35 67 37 64 41 61 44 58 48 55 52 52 55 49 58 47 61 45 63 43 64 42 65 41 65 40 66 40 65 41 65 42 65 43 64 44 64 45 63
+21 158 29 158 30 156 32 154 35 151 38 147 42 143 46 136 53 133 57 129 64 126 68 123 71 121 74 120 76 119 77 119 78 118 78 118 79 117 79 116 79 116 80
+2 P
+26 92 64 90 64 88 65 84 64 80 64 70 63 60 63 50 62 43 62 36 62 32 62 28 62 26 62 26 63 27 63 29 63 32 63 35 63 39 63 49 63 56 63 66 63 73 62 77 62 79 61 80 61
+28 206 64 205 64 202 64 199 64 195 64 188 64 181 64 178 64 174 65 171 65 167 66 160 67 157 68 154 68 152 68 151 68 152 68 153 68 154 67 156 67 160 67 164 66 171 65 178 65 185 65 192 64 194 64 196 64
+2 U
+46 20 79 21 79 22 79 24 79 27 79 34 80 41 81 51 81 61 82 68 82 72 82 74 82 77 82 78 82 79 82 80 82 82 82 84 81 86 81 88 81 89 81 91 81 92 81 91 80 90 79 89 78 88 76 88 74 87 72 87 70 87 67 87 65 87 64 87 63 87 62 87 61 87 60 87 59 87 58 87 57 87 56 87 55 87 54 86 54 86 53 86 52
+41 84 168 85 167 86 167 88 167 92 167 96 168 103 169 110 170 114 170 110 170 114 170 118 171 128 171 135 170 142 170 152 169 159 169 166 169 169 168 171 168 172 168 173 168 173 167 172 167 172 166 171 165 171 164 170 162 169 160 169 158 169 156 169 153 169 151 169 147 169 145 169 142 170 139 170 137 170 136 170 135 170 134
+2 V
+64 38 107 39 107 39 106 40 105 41 103 42 101 44 98 45 95 46 91 46 88 47 85 48 82 48 80 48 78 48 77 48 75 48 74 48 73 47 72 46 72 45 72 44 72 44 73 43 73 42 73 42 74 42 75 42 76 42 77 41 78 41 79 42 80 42 82 42 84 42 86 43 88 44 89 45 90 45 91 46 91 47 91 48 90 50 89 53 87 56 85 59 84 62 82 66 80 68 79 70 77 72 75 73 73 74 72 76 70 76 69 77 67 78 66 78 65 79 65 79 64 80 63 81 62 81 61 82 61
+65 88 138 89 137 90 136 92 135 93 133 95 131 97 130 99 128 102 125 104 123 106 121 107 119 108 117 108 115 108 113 108 112 108 111 108 110 108 109 107 109 106 109 105 109 104 109 103 109 102 109 100 108 99 108 99 109 98 110 98 111 98 112 98 113 98 114 98 116 99 117 99 119 99 120 99 122 99 123 100 124 101 124 102 124 103 123 104 121 106 120 109 117 111 115 114 111 117 107 120 103 122 100 124 96 126 93 127 89 129 86 127 89 129 86 130 83 131 81 132 79 133 78 133 77 133 78 132 78 132 79
+2 W
+69 107 30 107 31 106 32 106 35 104 37 103 39 102 42 100 45 98 48 96 51 93 55 96 51 93 55 91 59 88 62 86 65 83 67 80 69 78 70 76 71 75 71 74 71 73 71 72 70 71 69 70 67 69 66 69 65 68 64 67 63 67 62 67 61 67 60 67 59 68 59 69 58 70 57 72 56 73 56 74 56 75 56 75 57 76 57 77 58 78 59 80 60 81 61 81 63 82 65 82 67 82 68 82 70 82 72 81 74 80 76 78 78 77 79 74 81 72 83 70 85 68 86 66 87 64 89 62 90 60 91 57 93 55 94 53 95 52 95
+70 201 44 201 45 200 47 200 50 198 57 196 64 195 71 194 78 193 85 192 89 190 92 189 94 187 96 185 98 184 99 182 100 181 101 180 101 179 101 177 101 176 101 175 100 173 99 172 99 171 98 170 97 169 96 169 95 169 94 168 93 169 91 169 90 169 89 170 88 170 87 171 87 172 86 173 85 174 85 175 84 176 84 177 84 178 85 179 86 179 87 180 88 181 90 182 92 182 94 182 96 182 99 181 101 180 104 180 107 178 109 177 111 175 113 173 114 171 115 168 115 165 116 161 117 158 117 154 118 152 119 150 119 149 120 148 120 149 121 150 121
+2 X
+34 130 88 128 89 126 89 123 89 119 90 116 91 109 91 102 91 95 92 91 92 84 93 82 93 81 93 80 93 79 93 78 93 79 92 79 91 79 89 79 86 78 83 78 79 77 77 76 74 75 71 74 69 74 68 74 67 74 66 73 66 73 65 73 64 72 64 72 63
+34 218 155 217 155 216 155 214 155 212 155 209 155 205 155 198 155 188 155 181 155 174 156 170 156 168 156 166 156 166 157 165 157 165 155 164 153 164 152 164 150 163 148 163 145 162 143 162 141 162 139 161 138 161 137 161 136 161 135 162 135 162 134 162 133 162 132 163 132
+4 5
+60 89 34 88 34 87 34 86 34 84 34 81 34 77 33 73 33 69 33 64 33 60 33 56 34 53 34 50 35 48 36 47 38 46 40 46 42 46 45 47 47 48 50 49 53 50 56 50 59 50 62 50 65 50 67 49 68 49 69 49 70 50 70 51 69 52 68 54 67 56 66 59 66 62 66 66 67 69 69 72 72 75 75 77 78 79 81 81 84 81 88 82 91 81 94 80 97 78 99 76 101 73 103 69 105 64 107 59 108 53 108 47 108 41 106 36 102 32 99 29 97
+59 195 69 194 69 193 69 191 68 190 67 187 67 183 66 180 66 176 66 172 65 168 65 165 65 163 65 160 65 159 65 158 66 158 68 157 70 157 72 157 75 158 79 158 82 159 87 160 90 161 93 162 96 162 97 162 98 162 99 163 98 164 97 166 97 167 96 170 96 173 97 175 98 179 99 181 102 183 105 186 108 188 112 190 117 191 120 192 124 192 127 191 129 189 131 186 133 181 135 176 136 170 137 163 138 156 138 150 138 145 136 140 134 137 132 134 128 131 124
+52 81 32 80 32 78 31 76 31 74 31 71 31 67 30 64 30 60 30 56 31 53 31 51 32 49 33 48 34 48 36 48 39 48 42 49 46 51 50 52 54 53 58 54 62 55 65 54 67 55 68 56 67 58 67 60 67 62 67 64 67 67 68 70 70 72 72 75 75 76 78 78 81 78 84 78 86 77 88 75 90 72 91 69 93 64 94 59 94 53 94 48 93 43 92 38 90 34 89 31 88 29 87 28 87
+54 189 68 189 69 187 69 185 68 183 68 179 67 174 67 170 67 164 68 160 69 156 70 154 71 153 72 152 73 152 74 153 76 154 79 155 82 155 85 156 89 156 92 155 95 155 97 154 98 154 99 154 100 155 100 156 101 157 100 159 100 162 101 165 101 169 103 172 105 175 108 178 112 180 116 182 120 183 123 183 127 182 130 181 133 178 136 174 139 168 141 162 143 154 145 146 146 139 145 133 143 128 141 125 139 123 137 122 135
--- /dev/null
+++ b/lib/strokes/digits.clx
@@ -1,0 +1,20 @@
+0 7 34 9 2 85 77 116 105 73 101 28 63 1 19 19
+1 3 52 0 55 64 55 128
+2 7 2 15 43 1 75 33 56 87 3 127 53 123 107 126
+3 9 14 13 47 0 80 10 77 35 56 59 91 74 86 113 53 128 19 114
+4 5 0 2 6 62 9 121 58 119 108 114
+6 7 69 1 15 23 2 79 48 127 107 101 58 81 4 103
+7 5 4 3 54 2 105 5 79 66 51 128
+8 11 73 12 71 4 63 1 20 31 62 66 85 84 84 110 58 128 30 118 52 66 77 14
+9 7 78 16 46 1 17 27 48 50 86 29 90 78 81 128
+B 3 108 61 54 59 0 70
+N 3 0 128 50 64 108 0
+A 3 0 62 54 65 108 66
+S 3 57 128 53 64 57 0
+R 5 107 0 59 58 9 119 4 124 1 128
+P 5 108 65 54 64 0 67 44 65 88 62
+U 5 0 83 53 87 106 84 105 63 105 41
+V 5 0 128 35 79 18 60 63 62 108 0
+W 5 107 0 84 63 37 68 57 101 1 128
+X 5 108 84 70 88 32 90 7 75 0 37
+5 7 108 5 76 2 45 7 57 60 98 101 53 128 0 109
binary files /dev/null b/lib/strokes/letters.bit differ
--- /dev/null
+++ b/lib/strokes/letters.cl
@@ -1,0 +1,365 @@
+36
+11 a
+36 33 84 33 83 34 83 35 81 36 78 38 75 40 71 43 66 46 61 49 56 51 52 53 48 55 46 56 44 57 43 57 42 58 42 58 41 58 40 59 40 60 42 61 45 62 50 64 56 66 61 68 67 70 73 71 76 73 80 74 82 74 83 75 85 75 86 76 87 76 86 76 85
+28 172 78 172 79 173 78 174 75 176 72 179 67 182 62 185 55 188 49 191 45 194 41 195 38 196 37 196 38 197 40 199 43 201 48 203 55 206 61 208 67 210 72 212 76 213 79 215 80 215 82 216 82 216 83 215 82
+32 35 179 35 180 35 179 36 176 37 174 38 170 41 165 44 160 46 154 49 149 52 144 54 140 56 136 56 134 57 133 57 132 57 133 58 135 59 137 61 141 63 147 65 154 68 160 70 166 71 171 73 174 74 176 75 177 75 178 75 179 76 179 76 180
+28 145 188 146 187 147 185 150 182 153 178 158 172 164 166 170 159 177 153 182 148 186 144 189 142 191 141 192 142 192 144 192 147 193 152 194 159 195 166 197 173 198 179 199 184 200 187 201 189 201 190 202 190 202 191 202 190
+26 230 176 231 176 232 175 233 172 234 169 237 164 240 159 243 153 246 148 249 144 251 141 252 139 253 139 253 140 254 141 255 143 256 147 258 153 260 159 262 166 264 172 265 176 267 180 268 182 269 183 269 184
+28 251 96 252 95 252 94 253 91 254 86 257 79 260 72 264 63 269 55 273 48 276 42 278 40 279 39 280 40 281 42 282 45 285 52 287 60 290 69 294 79 297 89 300 96 301 102 303 105 303 107 304 108 304 109 304 108
+25 54 93 54 94 54 93 55 91 55 88 56 85 58 81 60 76 63 71 66 66 68 61 70 57 72 53 73 51 74 50 74 49 75 50 76 53 78 56 80 62 82 68 84 74 86 78 87 82 88 83
+28 130 148 130 146 131 144 132 141 135 137 137 131 140 124 143 117 146 111 148 106 149 103 150 102 150 101 151 103 152 106 153 111 155 118 157 125 158 132 160 139 161 143 162 146 163 148 163 149 164 149 164 150 165 150 165 149
+32 204 159 203 159 203 158 204 156 205 152 208 147 211 139 216 130 220 121 224 113 227 107 230 103 231 101 231 100 232 100 233 102 234 105 236 110 239 118 242 127 245 136 247 145 250 153 252 159 255 166 256 170 257 174 258 176 258 177 258 178 258 177 258 176
+52 44 100 45 100 46 99 47 98 48 97 48 95 49 93 50 91 52 89 53 86 54 84 56 81 57 78 58 75 60 72 61 69 62 66 63 63 64 61 66 59 67 57 67 55 68 54 68 53 68 52 69 53 70 55 71 58 72 61 74 65 75 68 77 72 78 75 80 78 82 81 80 78 82 81 83 84 84 86 85 87 86 89 87 90 87 91 88 91 88 92 88 93 88 94 89 94 89 95 89 96 90 96 90 97
+65 170 98 170 97 170 96 170 95 171 93 171 91 172 88 172 86 173 83 174 80 175 78 176 76 178 73 179 71 180 69 182 66 183 64 184 62 185 61 186 59 186 58 187 57 188 55 189 54 190 52 190 50 191 49 191 48 192 48 192 47 192 46 192 47 193 48 194 51 195 54 196 56 198 59 199 62 200 64 201 66 202 69 203 71 204 73 205 75 205 77 206 78 207 80 208 82 209 84 211 86 213 89 215 91 213 89 215 91 217 93 218 95 219 97 220 98 221 100 221 101 222 101 222 102 222 103 222 104 223 104
+9 b
+49 225 123 225 125 225 129 225 134 226 140 226 147 226 154 226 159 226 162 225 162 225 161 224 157 223 152 222 146 221 138 220 132 221 126 223 120 226 117 230 115 234 115 237 118 239 122 239 127 238 132 235 137 232 141 229 143 227 144 225 143 224 142 225 140 226 139 228 138 232 137 235 138 239 139 243 141 246 144 248 147 249 150 248 154 245 156 241 159 236 160 230 162 225 162 221 161 218 160
+52 65 132 66 133 66 136 68 140 69 145 69 152 70 159 69 167 68 172 66 176 65 178 63 177 62 174 62 168 61 161 62 153 64 145 68 137 72 131 75 126 79 123 83 123 86 124 88 127 88 132 87 138 85 143 82 148 79 151 76 153 73 154 71 154 70 153 70 152 72 151 74 150 77 149 81 149 85 149 89 150 92 152 94 156 94 159 93 163 90 166 87 170 82 173 77 175 72 176 68 176 64 174 63 172
+51 123 41 123 40 124 40 124 42 125 44 126 49 127 54 128 61 128 67 128 72 128 76 127 77 127 76 126 73 125 68 124 62 123 55 123 49 123 44 124 39 127 36 131 35 135 34 139 35 143 37 145 40 145 44 144 48 142 52 139 55 136 57 133 58 132 59 131 58 133 57 135 55 138 54 142 53 146 53 150 54 153 56 156 59 157 63 158 66 156 69 153 72 149 73 143 75 138 76 133 76 129 76
+49 239 156 239 158 240 161 240 166 241 171 241 177 240 182 240 187 239 190 239 191 238 191 238 188 237 183 236 177 236 168 236 159 237 150 238 145 241 139 245 135 250 134 254 136 257 140 258 145 258 149 255 155 252 160 248 164 245 167 242 169 241 169 241 168 243 167 246 165 250 164 255 163 260 164 264 167 266 170 267 173 267 177 266 180 263 183 258 186 253 188 250 190 244 190 238 190 234 189
+56 172 80 172 81 172 84 172 89 172 97 173 105 172 113 172 119 172 124 172 126 172 125 172 121 172 116 172 110 172 102 171 95 171 88 171 83 172 79 174 76 176 73 179 72 182 72 185 73 187 75 189 79 189 83 189 86 187 90 185 94 183 96 181 98 179 98 177 99 177 98 177 97 178 96 179 95 182 94 186 93 189 93 194 94 198 96 201 99 203 104 204 108 203 112 202 116 199 119 195 121 191 122 187 122 182 122 178 120 175 119 172 117
+51 64 56 64 58 64 60 65 65 64 71 64 77 64 83 64 89 63 91 63 88 62 84 62 78 61 73 60 67 61 62 62 57 64 52 68 49 72 46 76 45 79 46 81 49 82 53 82 57 81 61 79 65 76 68 74 70 72 70 71 70 71 69 72 68 74 67 77 66 81 66 84 66 88 68 91 69 93 71 95 73 95 75 94 77 91 79 88 82 83 84 78 86 74 87 71 87 68 87 67 85 67 84
+60 205 151 206 155 206 161 206 167 207 175 207 181 207 187 207 191 206 193 206 194 205 192 205 190 204 186 202 181 201 175 201 169 200 162 200 157 201 151 202 146 203 142 206 138 209 135 212 134 216 134 219 136 223 138 225 141 226 145 226 149 224 153 222 158 218 162 215 165 211 168 209 169 207 169 209 167 212 166 215 165 219 164 224 164 228 165 232 166 235 168 237 170 238 173 239 176 238 179 237 182 235 185 234 187 231 189 227 192 222 194 216 195 210 196 205 195 199 194 195 193
+58 160 68 161 71 161 74 162 79 163 85 164 90 164 96 164 101 164 103 163 104 163 103 162 101 162 97 161 92 161 86 160 80 160 74 160 69 161 66 162 62 164 60 166 58 169 57 172 57 174 59 175 61 177 64 177 68 176 72 174 76 171 79 168 80 165 81 163 81 162 81 162 80 163 79 165 78 167 77 170 77 174 77 178 77 181 78 184 79 187 81 188 83 189 85 190 88 189 91 187 93 184 96 180 98 176 100 171 102 167 103 163 102 160 101 158 100
+57 42 46 43 49 43 52 44 56 44 61 45 66 45 70 44 73 44 76 43 77 42 74 42 71 41 67 40 62 40 58 40 53 41 49 42 45 44 42 46 39 49 37 51 36 54 35 57 36 59 38 60 40 61 44 60 48 58 51 56 55 53 58 50 59 48 60 47 60 47 59 49 58 51 57 54 56 57 56 61 56 65 57 69 58 72 59 73 60 74 63 75 65 74 67 73 70 71 72 68 74 64 76 61 77 57 78 53 78 50 78 47 77 45 76
+9 c
+37 108 124 108 125 109 125 109 126 109 127 108 126 108 124 107 122 105 120 104 118 101 115 99 114 96 113 93 113 90 114 87 117 84 120 81 123 79 128 77 133 76 139 76 144 76 150 77 155 79 160 81 164 83 168 87 170 91 172 96 171 102 170 108 168 114 166 119 163 123 161 125 159 126 158
+38 202 89 202 90 202 91 202 90 202 89 202 88 202 86 201 85 201 83 200 82 199 81 197 81 195 81 193 81 191 82 188 83 186 85 184 87 182 91 180 95 179 99 178 103 178 108 179 113 180 117 182 120 184 123 187 125 191 126 194 126 198 126 201 124 204 123 207 122 208 120 210 119 210 118 211 117
+36 81 56 82 56 82 55 82 54 81 54 81 53 80 53 80 52 79 51 78 50 76 49 75 49 74 49 72 50 70 51 68 53 65 55 63 58 62 60 62 62 61 64 62 67 62 70 63 72 64 75 65 77 68 78 70 79 73 80 76 79 79 79 82 77 84 76 87 75 88 74 89 73
+41 127 144 128 144 127 144 127 143 126 142 125 141 124 140 122 138 120 137 118 137 116 136 113 136 110 136 106 138 103 139 100 142 97 146 94 150 92 156 90 162 89 170 88 177 87 184 88 190 89 196 90 202 93 206 96 210 100 213 105 214 111 214 119 213 126 210 134 207 141 203 147 200 151 197 154 195 156 194 156 193 157 193
+36 185 56 185 57 185 58 185 57 185 56 185 55 185 53 184 52 183 51 182 50 181 49 179 48 177 48 175 47 172 49 170 51 167 53 164 56 162 60 160 65 159 69 158 74 158 79 159 83 160 87 163 92 167 95 170 96 175 96 181 95 187 93 193 90 198 86 201 84 203 82 204 81
+36 70 35 71 35 70 35 70 34 69 34 68 33 67 32 64 31 62 30 59 29 57 28 54 27 51 28 49 29 46 31 44 33 41 35 39 38 37 41 35 45 35 49 34 54 35 58 36 61 39 65 42 67 46 69 50 71 55 72 60 72 65 71 71 69 75 68 79 66 82 65 83 64
+30 131 130 131 129 130 128 129 126 128 124 126 122 124 120 121 119 118 119 116 119 113 120 111 121 108 123 106 127 104 130 102 135 101 140 100 146 99 151 100 155 101 159 103 162 106 164 111 166 116 166 123 165 128 163 133 160 136 158 138 156
+33 194 43 194 44 194 45 194 44 194 43 194 42 193 41 192 39 191 38 190 37 188 36 186 35 184 35 182 35 180 36 177 38 175 40 173 43 172 47 171 51 170 56 170 61 170 65 171 69 173 73 175 75 179 76 183 77 187 77 192 76 196 75 200 74 202 73
+38 65 42 65 41 65 40 64 40 63 39 61 38 59 37 58 36 56 36 54 35 53 36 51 36 49 37 47 38 44 39 42 41 40 43 38 45 36 48 35 51 35 55 34 58 35 61 35 64 36 67 37 70 39 73 41 75 43 76 46 77 50 78 53 79 57 79 61 78 64 77 69 76 73 74 75 73
+9 d
+45 259 144 259 145 259 147 259 150 260 155 261 160 261 166 262 171 262 175 262 178 262 179 262 177 262 175 261 171 260 166 259 161 258 156 257 152 257 148 258 145 259 142 260 139 262 136 264 135 267 134 271 133 274 134 279 136 283 139 286 141 289 145 291 150 292 155 291 160 290 165 288 170 285 174 281 176 277 177 273 178 269 178 266 177 263 176 260 176 258 176
+44 172 93 173 94 173 95 173 98 174 101 174 105 175 111 175 117 175 122 174 127 174 130 173 132 173 133 173 132 173 129 173 125 173 120 173 115 173 110 172 105 172 101 172 97 173 93 174 90 176 88 178 86 181 86 184 86 188 88 191 91 195 94 197 99 199 103 200 108 200 113 199 117 197 121 195 124 192 126 188 127 184 128 181 128 177 127 175 126
+51 49 44 49 45 50 48 50 52 51 58 52 64 53 71 53 77 53 82 53 85 52 89 52 92 52 94 52 96 51 96 51 95 51 93 50 91 49 87 49 83 48 78 47 73 46 67 46 62 46 56 46 51 47 46 49 42 51 39 55 36 58 35 63 35 68 35 73 36 77 39 81 42 84 46 86 52 88 57 88 63 87 69 86 74 84 78 82 81 78 83 74 85 69 87 63 88 59 88 55 89 52 88
+40 85 130 85 131 85 133 86 136 86 140 87 146 87 150 87 156 86 160 86 164 85 164 85 163 85 160 84 155 83 150 82 144 82 139 82 134 82 130 82 127 84 125 86 124 89 124 93 125 97 127 101 130 105 134 108 139 111 144 112 149 112 153 111 158 109 161 106 165 101 167 96 169 89 171 82 172 75 173 70 173
+44 154 52 154 53 154 55 154 58 155 62 156 67 157 72 157 78 157 82 157 86 156 88 156 89 156 88 155 86 154 83 153 79 152 74 151 69 150 65 150 60 149 56 150 53 150 50 152 48 154 46 157 46 161 46 165 47 169 49 172 51 175 55 177 59 177 62 177 67 176 70 174 74 172 77 169 79 166 81 163 82 160 83 157 84 155 84 153 83
+41 37 43 37 44 38 45 38 48 39 52 39 56 40 60 40 64 40 67 40 69 39 69 39 67 38 65 38 62 37 59 36 55 35 51 35 48 35 45 37 42 38 40 40 38 43 36 45 36 48 37 51 38 54 41 57 43 60 47 62 52 63 56 64 59 63 62 62 64 59 65 55 67 51 68 46 69 42 70 40 70 39 71
+39 222 105 223 106 223 108 223 112 223 118 224 125 224 132 224 140 223 146 223 150 222 152 221 149 220 144 219 138 218 130 217 123 215 117 214 112 214 108 214 104 216 102 218 100 222 99 226 99 231 102 235 106 238 112 240 119 240 126 239 133 237 139 234 145 231 149 228 152 225 154 222 156 219 156 217 155 216 154
+44 141 54 142 55 142 57 142 59 142 63 142 68 142 73 143 78 143 83 142 86 142 89 142 91 142 92 142 91 141 89 141 85 140 80 139 74 139 69 139 64 140 59 141 56 142 53 144 51 147 49 151 49 155 50 159 51 164 54 168 57 171 62 174 67 176 71 176 76 175 80 173 83 171 85 166 88 160 90 154 92 149 93 144 94 141 94 139 94
+44 32 33 32 34 32 35 32 38 32 42 33 47 33 53 34 58 34 62 34 65 34 66 34 67 33 65 33 63 32 60 31 56 30 52 29 48 29 44 30 40 32 37 33 35 35 32 38 29 41 29 44 29 47 31 50 34 52 38 55 42 56 47 57 52 58 56 58 59 56 62 54 64 51 66 48 67 44 68 41 69 38 70 37 70 35 70 35 71
+9 e
+56 279 119 279 118 278 117 277 116 277 115 276 114 275 114 273 113 271 113 269 113 266 114 263 116 259 118 255 121 253 124 251 128 250 133 251 137 252 142 254 146 256 149 258 150 261 152 263 152 265 152 267 151 269 150 270 150 270 149 271 149 270 149 268 148 267 148 265 149 263 149 261 150 259 151 257 152 254 154 252 155 250 157 248 160 247 162 247 165 248 169 251 172 254 174 258 176 263 177 268 176 273 175 278 174 283 172 286 170 289 168 290 167
+54 167 80 167 79 167 78 166 78 165 77 163 76 161 75 159 75 155 75 152 76 149 77 147 79 144 82 143 87 142 93 142 100 144 106 146 112 149 115 153 117 156 116 159 115 162 113 164 112 165 110 166 108 165 107 163 105 161 105 159 104 155 104 152 104 149 105 146 106 143 107 140 109 137 110 136 112 134 115 134 118 134 122 134 126 135 131 136 134 139 138 142 140 145 143 149 143 154 143 159 142 164 140 168 137 171 135 173 134
+47 62 46 63 47 62 48 62 47 61 45 60 44 59 42 57 42 55 41 53 42 50 43 48 44 45 47 43 51 41 56 40 60 40 64 41 69 43 72 46 74 49 75 52 75 55 75 58 74 60 73 61 72 61 71 60 71 59 70 56 70 53 71 50 72 46 74 43 76 41 78 39 81 38 85 38 90 38 94 40 99 43 102 47 105 51 106 57 106 61 105 66 103 70 100
+53 263 145 263 144 263 143 262 143 262 142 260 141 259 140 256 140 253 140 250 141 247 143 244 145 242 148 241 150 239 154 239 158 240 162 241 165 243 168 246 169 250 170 253 170 256 170 258 169 259 169 260 169 260 168 260 169 259 169 258 169 257 170 255 170 253 171 250 172 247 173 243 175 240 176 237 178 234 180 233 182 232 183 232 186 233 188 235 190 237 193 240 195 244 197 249 198 254 198 259 197 263 196 267 195 269 193
+43 183 79 183 78 182 77 181 76 180 75 178 74 174 74 170 74 167 75 163 77 160 80 159 84 158 89 158 95 159 100 161 105 164 108 167 110 169 110 172 109 174 108 175 107 176 104 175 102 174 101 172 101 169 101 166 102 162 104 158 107 155 110 152 114 151 118 150 122 150 126 152 130 154 133 157 135 162 136 167 136 172 135 177 133 182 131
+39 75 75 75 74 74 73 73 72 71 71 69 69 64 69 60 70 55 70 51 72 47 75 45 79 43 83 43 88 44 93 46 98 48 101 51 102 54 102 56 101 57 99 58 98 58 97 57 97 54 98 51 100 47 103 43 107 39 111 36 115 35 119 34 124 36 128 39 131 43 134 49 135 55 134 61 133 66 130
+52 256 63 256 64 257 64 256 63 256 62 255 61 254 59 252 57 250 55 248 54 245 54 242 56 239 58 236 62 233 67 231 72 230 77 231 81 232 85 234 88 237 89 241 90 244 89 247 88 249 86 250 84 251 83 250 81 249 80 247 79 245 79 242 79 240 79 237 79 234 80 231 82 228 84 226 87 224 90 223 94 222 98 222 103 223 107 225 111 227 115 231 118 236 119 241 120 247 119 252 117 257 114 261 112
+54 160 42 160 41 159 40 158 39 157 39 155 38 154 37 152 36 150 35 149 35 148 35 146 36 144 37 142 40 140 43 138 47 137 51 137 55 138 58 139 62 141 65 143 66 145 67 146 68 148 67 149 66 150 65 151 63 152 61 152 60 151 59 149 58 147 59 144 59 141 60 137 61 134 63 130 64 127 66 126 67 124 69 123 71 123 73 124 75 126 78 128 80 132 82 136 84 141 85 146 86 152 85 157 84 161 83 164 81
+60 71 39 71 38 71 37 71 35 70 34 70 33 69 32 68 31 66 31 64 30 62 30 60 29 57 30 54 31 51 32 48 35 46 38 44 41 43 44 42 47 41 51 42 55 43 58 44 60 47 62 49 63 51 63 54 63 56 63 58 62 59 62 59 61 60 61 59 60 58 60 56 61 54 61 52 62 50 63 48 63 46 64 44 66 42 67 41 69 40 72 39 74 38 77 38 80 38 83 38 86 39 90 40 93 42 95 45 98 47 99 52 99 57 98 62 96 66 95 71 92
+9 f
+23 288 93 287 93 287 92 285 92 283 92 278 92 273 93 266 95 260 98 254 100 249 102 246 104 245 106 245 109 245 113 246 120 247 128 247 138 247 149 247 159 247 169 246 176 246 180
+29 199 89 199 88 198 88 196 87 193 85 189 83 185 81 180 79 175 77 171 75 168 74 165 73 164 73 163 73 162 73 163 74 163 76 163 80 163 85 163 93 163 102 162 113 161 123 160 132 160 138 159 143 159 145 158 146 158 145
+24 80 58 80 59 80 58 79 57 77 56 75 55 70 55 65 54 59 55 55 56 50 57 47 59 46 61 47 64 48 68 49 75 50 85 50 95 50 106 50 115 49 122 49 125 48 127 48 128
+28 269 62 268 62 267 62 266 61 264 61 261 61 257 61 252 61 246 62 240 62 235 62 231 63 228 63 226 63 225 64 225 65 225 66 226 68 227 72 227 77 228 83 228 89 228 95 227 100 227 105 226 107 225 108 225 107
+29 175 50 174 49 173 49 171 49 167 48 163 48 158 47 153 48 148 48 144 48 141 49 139 49 138 50 137 52 137 53 138 56 138 60 138 65 139 70 139 76 139 83 138 89 138 95 137 100 137 104 137 107 137 109 137 110 137 111
+24 72 40 71 40 68 40 65 40 61 40 57 39 53 39 49 39 46 39 44 39 43 40 42 40 42 41 42 42 42 44 43 48 43 53 43 58 44 64 44 70 44 75 44 78 44 80 44 82
+26 318 111 317 110 316 110 314 109 311 109 307 108 302 108 295 108 289 109 284 109 279 110 276 111 274 112 274 113 273 115 274 118 275 123 276 130 277 140 277 150 277 160 277 170 276 178 276 183 276 187 275 188
+29 238 52 238 51 237 51 236 51 234 50 232 49 228 49 223 48 217 48 212 48 206 49 202 50 198 51 196 52 195 54 196 57 196 61 197 67 198 75 199 84 199 94 199 103 199 111 198 117 198 120 198 122 197 122 197 121 197 120
+27 85 42 85 41 84 41 82 41 80 41 76 41 71 40 65 40 59 39 54 39 49 39 46 40 44 41 43 42 43 43 44 45 45 49 46 54 47 61 48 69 48 76 49 84 49 90 49 94 49 97 49 98 49 99
+9 g
+37 270 90 270 89 270 88 269 86 267 85 265 85 263 86 260 88 257 92 254 97 252 104 252 111 252 117 254 123 257 126 261 128 264 128 269 127 272 126 274 124 276 122 276 119 275 117 273 115 270 113 267 111 264 111 262 110 261 110 260 110 262 110 264 110 266 110 270 109 273 109 276 108 278 107
+48 182 55 182 56 181 54 181 53 180 51 178 49 175 48 173 46 169 46 165 47 162 49 158 52 154 57 152 63 150 69 148 77 147 85 147 92 149 99 152 104 156 107 162 109 167 110 173 109 179 107 183 104 186 101 187 97 188 93 187 88 185 85 183 81 180 79 176 77 173 77 169 77 166 77 163 78 162 78 161 79 163 79 166 79 169 79 174 78 179 78 183 77 187 76 189 75
+37 77 46 76 45 76 44 74 42 72 41 70 40 67 40 64 41 61 43 59 47 58 51 58 56 58 60 60 65 62 69 65 72 69 73 73 74 76 73 78 72 80 70 81 68 80 66 79 64 77 62 75 61 72 60 70 60 68 60 68 61 70 61 72 62 74 61 77 61 79 61 81 60 82 60
+50 174 145 174 144 174 143 173 143 172 141 170 140 169 139 166 138 163 137 160 137 157 138 154 140 151 143 148 147 146 153 145 159 146 165 147 171 150 176 154 179 158 182 162 182 167 181 171 180 174 177 177 174 178 171 179 168 179 166 178 163 176 161 173 160 170 159 168 158 165 159 163 159 161 160 160 160 161 160 162 160 164 160 166 160 170 159 174 158 178 157 181 156 184 155 185 155 186 155 185 155
+49 213 59 213 58 213 57 212 56 211 56 210 54 208 53 207 52 204 51 201 52 199 53 196 56 193 61 190 66 188 72 187 79 187 85 190 92 193 97 197 101 202 104 207 105 212 104 215 102 218 99 220 96 221 91 220 87 219 83 217 81 214 78 212 77 208 76 205 75 202 75 200 75 198 76 197 76 197 77 198 78 200 79 203 79 207 79 212 79 216 79 221 77 224 76 227 76 229 75
+41 90 51 90 50 90 49 89 48 87 47 85 46 83 46 81 46 79 46 76 48 74 50 72 54 71 58 70 62 71 67 72 71 73 75 76 79 79 82 82 85 86 86 90 86 94 85 97 83 99 80 100 78 100 75 98 72 96 71 92 70 89 70 86 70 84 71 83 72 83 73 85 73 87 73 91 73 94 72 97 72 100 71
+57 304 116 304 115 305 116 305 115 304 115 304 114 303 112 302 110 300 108 298 106 295 106 292 106 288 107 284 109 279 112 276 116 272 121 270 126 268 133 267 140 267 146 268 152 270 158 272 162 276 165 280 167 285 168 290 167 295 165 299 163 303 160 305 157 307 155 307 153 307 151 306 150 305 148 302 146 300 145 297 144 294 143 292 144 289 144 287 144 285 144 284 145 285 145 286 145 288 145 291 144 295 144 300 143 304 142 308 141 311 140 313 140 314 139
+51 201 92 200 92 200 91 200 90 199 89 198 88 197 87 195 87 193 87 191 88 188 90 186 92 183 95 181 99 179 104 178 110 177 117 178 123 179 128 181 132 184 135 187 137 191 137 195 136 199 134 201 132 203 130 204 127 204 125 203 124 201 122 199 121 196 121 194 121 192 121 190 121 189 122 188 122 189 122 190 122 192 122 194 122 197 121 200 121 203 120 205 120 206 119 207 119 208 119 208 118 207 118
+60 73 51 74 51 74 52 74 51 73 51 73 50 72 49 71 47 69 46 67 45 64 44 61 44 58 45 55 46 53 48 50 51 49 54 48 57 47 61 47 65 47 69 48 73 49 77 51 81 53 85 56 88 59 90 62 91 66 92 70 91 73 90 77 89 79 87 81 85 82 83 83 81 83 79 83 77 82 75 80 74 78 73 76 72 74 72 71 72 69 72 67 72 64 72 63 72 62 72 63 72 64 72 67 72 69 71 72 71 75 70 77 70 80 69 81 69 83 68 84 68
+9 h
+40 254 104 254 103 254 102 254 103 255 106 256 112 256 120 257 129 257 140 257 150 257 158 256 163 256 166 255 167 255 168 256 167 256 164 256 161 257 158 258 153 260 149 263 144 266 141 270 138 273 136 277 135 280 135 284 135 286 136 288 138 289 141 291 145 291 150 291 156 291 161 290 165 290 168 290 170 289 170 290 169
+31 155 61 154 60 155 61 155 64 156 70 157 79 158 89 158 97 158 108 158 117 157 122 157 125 157 126 157 125 157 123 158 119 160 115 163 110 167 105 171 101 175 99 178 99 182 100 184 103 186 107 188 111 189 116 189 119 190 122 190 124 189 125
+40 44 39 44 37 44 36 44 37 44 40 44 44 44 51 43 59 43 68 42 76 42 83 41 88 41 91 41 93 41 94 41 93 41 92 41 91 41 88 41 85 42 81 43 77 45 73 47 70 50 67 53 64 56 62 59 60 62 59 65 58 68 59 69 60 71 63 72 67 74 71 74 76 75 81 75 85 75 89 75 91
+36 247 106 246 102 245 100 245 99 245 100 245 101 246 105 247 112 248 122 250 135 251 147 252 159 251 168 251 174 251 177 251 178 251 176 252 174 253 171 255 168 258 165 261 162 265 161 270 160 273 161 276 162 279 164 280 166 282 167 282 169 282 171 283 173 283 174 283 176 283 177 283 176
+38 148 67 147 67 147 66 147 65 148 66 148 67 148 69 149 73 149 80 149 90 149 102 148 113 147 123 146 131 146 135 145 136 146 136 146 135 147 132 148 126 150 119 153 112 156 104 159 98 164 93 168 90 171 89 174 89 177 91 179 95 180 100 182 106 182 112 183 118 183 123 184 128 184 131 184 133
+25 44 58 43 58 43 59 44 61 44 65 45 71 45 78 45 87 45 95 45 101 45 105 45 107 45 106 46 102 47 98 49 95 51 91 53 89 56 89 58 89 60 91 62 93 63 97 64 100 64 103
+34 120 121 120 120 120 122 120 126 120 132 120 139 120 148 120 157 119 166 119 174 118 179 118 183 118 185 118 184 118 182 118 179 118 175 119 172 121 166 124 162 127 158 131 155 135 153 138 153 141 153 143 155 145 158 147 162 148 167 148 171 148 175 148 178 148 180 148 181
+37 176 30 176 29 176 28 176 29 176 32 177 36 177 43 177 52 177 61 177 70 176 79 176 84 175 88 175 90 175 89 175 88 175 85 176 81 178 76 180 71 183 67 186 63 190 61 195 60 199 59 203 60 206 61 209 62 211 65 212 68 212 72 212 77 212 81 211 86 211 89 211 92 211 94
+27 35 27 34 26 34 27 35 30 35 35 36 42 37 51 37 60 37 68 37 75 37 79 37 81 37 82 37 81 38 79 40 76 42 72 46 68 50 64 54 62 58 62 62 62 65 65 68 68 69 71 70 74 70 76
+9 i
+12 172 131 173 131 174 134 175 140 176 148 177 159 179 171 180 183 181 193 182 200 182 204 182 205
+8 77 121 78 124 79 129 80 137 81 145 82 155 83 162 83 168
+10 282 83 282 82 283 85 284 90 284 97 285 107 286 117 286 125 286 132 286 135
+14 221 66 222 64 223 63 223 64 222 69 220 77 218 89 215 102 212 115 209 128 208 136 207 141 207 143 207 142
+17 128 57 128 53 128 49 127 47 127 48 128 51 129 58 130 68 133 81 135 95 137 108 139 119 141 126 142 129 143 131 142 131 142 129
+11 47 46 46 45 46 46 46 49 45 55 45 63 45 73 45 83 45 91 45 98 45 102
+17 197 95 198 92 198 91 198 92 198 95 199 101 199 109 199 119 199 131 199 141 198 150 198 158 198 163 198 167 198 170 198 172 198 173
+11 117 32 118 32 118 33 118 36 119 40 119 46 119 53 120 59 120 64 120 68 120 71
+12 39 27 39 26 39 29 38 34 38 40 38 47 38 54 38 60 38 64 38 67 38 69 39 69
+9 j
+26 284 68 285 67 285 66 285 67 286 70 286 75 287 83 288 93 288 105 288 116 288 126 287 135 287 141 286 145 285 147 285 149 284 149 283 149 280 149 276 148 270 147 263 146 254 145 247 142 240 139 236 136
+25 207 54 208 52 208 51 208 52 209 55 209 60 209 66 210 74 210 82 210 90 210 97 210 102 209 105 208 107 205 108 201 107 195 105 189 104 182 101 176 100 170 99 166 98 164 98 161 98 160 99
+22 99 37 99 36 99 37 99 38 100 41 100 46 100 52 101 59 101 66 101 72 101 75 101 78 100 79 99 78 98 77 95 76 92 75 87 75 83 75 79 75 77 76 75 77
+29 297 92 297 89 298 88 298 89 298 91 299 95 299 102 300 111 301 123 302 136 302 148 303 160 304 170 304 177 304 183 304 188 303 192 302 194 301 195 299 196 296 196 292 195 288 195 283 194 277 193 271 193 266 192 262 192 260 192
+21 204 44 204 43 204 44 204 47 205 52 205 60 206 69 206 80 206 91 205 101 204 110 202 116 200 120 195 122 190 122 184 119 177 116 172 113 168 110 165 107 164 105
+21 92 28 93 30 93 34 94 39 95 47 95 55 96 64 96 73 95 80 95 86 95 90 94 93 93 95 91 96 89 96 85 95 81 93 77 90 73 87 69 84 65 83
+24 253 95 254 94 254 92 254 93 254 95 254 100 254 107 254 115 254 125 255 134 255 143 256 150 256 156 256 159 255 162 253 164 250 165 245 165 239 166 232 166 225 166 220 166 216 165 214 165
+21 198 37 197 38 197 40 198 44 198 49 198 56 198 62 199 68 199 73 198 76 198 78 197 79 195 79 193 79 189 78 184 78 178 78 173 78 168 78 163 77 161 76
+27 72 34 72 33 72 34 72 35 73 37 73 41 74 46 74 52 74 58 74 65 74 70 74 74 75 78 75 80 75 82 74 82 74 83 73 83 72 83 70 84 67 84 62 85 57 85 53 85 48 85 45 84 42 85
+9 k
+29 122 132 123 131 124 130 124 131 124 132 123 136 121 140 118 146 113 154 106 161 99 168 91 174 83 178 76 180 70 182 64 182 62 180 62 179 64 177 70 175 77 174 85 174 94 174 102 177 110 180 115 183 118 186 122 189 124 191
+35 217 51 217 52 217 53 217 55 216 58 216 62 214 66 211 72 207 78 201 84 194 90 186 95 179 99 172 101 167 103 164 104 163 104 162 105 163 105 163 104 164 104 165 104 167 103 170 103 173 103 177 103 185 106 191 110 196 115 202 121 208 128 213 137 218 146 221 154 224 160
+25 102 41 102 40 102 41 102 42 101 44 100 46 97 49 94 53 89 56 84 60 79 63 74 65 70 66 67 67 65 67 68 66 70 65 74 65 78 66 83 68 87 70 91 73 94 76 96 78 98 80
+28 110 130 110 131 111 133 111 137 110 142 108 148 105 154 101 159 95 163 88 165 81 166 75 166 70 166 65 164 63 163 63 161 66 160 71 159 78 159 86 159 94 160 102 163 110 166 116 170 121 174 124 177 127 178 128 179
+24 204 73 205 73 205 75 205 79 203 84 200 91 196 99 191 107 185 113 180 116 174 118 170 118 167 117 165 114 166 111 168 108 173 106 179 105 186 105 194 107 200 109 206 111 210 113 212 114
+24 92 54 93 54 93 55 93 56 92 59 90 62 87 67 83 71 78 76 73 81 68 84 62 85 59 85 57 83 57 81 58 78 61 76 65 74 71 73 77 73 82 74 88 75 93 77 97 79
+38 206 115 207 115 208 115 208 117 208 120 207 125 206 131 203 139 200 146 196 153 190 158 186 160 180 162 172 163 165 162 159 161 154 159 152 158 152 156 155 154 159 153 165 151 172 151 179 151 186 152 193 155 199 158 204 162 209 166 213 172 217 177 220 182 223 187 225 190 226 193 227 194 228 195 228 194
+29 204 53 204 52 204 54 203 56 202 60 200 64 196 69 192 73 187 76 182 78 177 78 173 78 170 77 167 76 167 74 167 72 169 71 171 70 176 70 181 71 187 73 192 76 197 80 201 83 204 87 206 90 207 92 208 94 209 95
+29 74 35 74 36 74 38 74 41 73 46 71 51 69 57 64 61 60 66 55 69 51 70 47 71 44 70 42 69 41 68 40 67 41 66 43 66 47 65 51 65 56 65 62 66 68 68 73 70 76 72 79 73 80 74 81 75 82 76
+9 l
+28 152 142 152 141 153 143 154 147 156 153 158 161 160 171 162 181 163 190 164 196 165 201 165 203 165 204 165 205 166 205 168 205 172 204 177 204 183 204 190 204 197 204 204 204 208 204 211 205 213 205 214 204 215 204 214 203
+24 189 53 189 54 190 56 190 60 191 65 191 71 190 78 190 84 189 89 188 92 188 93 187 94 187 93 188 94 189 94 192 95 196 96 202 98 208 98 216 98 222 98 228 98 232 98 235 97
+28 69 48 69 45 70 43 70 42 70 43 71 47 70 53 70 62 69 73 67 86 64 97 62 107 60 115 59 120 59 123 58 124 59 124 60 125 63 125 67 125 73 124 79 124 88 122 96 121 104 120 110 118 115 118 117 118
+21 85 152 85 151 85 153 85 157 86 163 85 171 85 179 85 187 84 193 84 197 85 199 86 199 89 199 92 199 96 198 101 197 106 196 111 196 116 195 119 195 122 195
+23 170 81 170 78 170 77 170 78 170 82 169 88 168 97 167 108 165 120 164 130 162 138 162 144 162 147 163 149 165 150 169 151 175 151 183 152 192 154 201 156 211 158 219 160 226 162
+23 42 48 43 47 43 46 43 47 43 49 44 54 43 61 43 70 42 82 41 93 40 103 38 111 38 116 38 119 39 119 42 119 47 118 52 116 58 115 65 114 71 113 76 112 79 111
+26 233 78 233 77 233 78 233 81 234 87 235 95 235 105 235 116 234 127 234 134 234 140 233 144 233 146 233 147 234 147 235 146 237 146 241 146 246 145 253 144 260 144 267 143 272 142 277 142 279 143 280 143
+26 134 58 134 56 134 55 134 56 135 59 135 64 135 70 134 77 134 85 133 93 132 100 131 105 130 109 130 110 130 111 131 111 132 110 135 110 139 109 144 109 150 109 156 109 162 109 166 109 169 109 171 110
+24 27 41 27 40 27 41 27 42 27 45 27 49 27 55 27 61 27 68 27 75 26 80 26 84 26 87 26 88 26 89 27 89 30 89 33 89 37 88 42 87 47 86 52 86 56 86 59 86
+9 m
+42 266 164 267 165 267 164 267 161 267 157 267 153 268 144 270 135 272 126 274 118 277 112 279 109 281 109 283 111 286 116 288 122 289 131 291 139 291 147 292 153 291 157 291 156 291 152 291 146 292 140 293 133 294 128 296 123 298 120 300 118 303 118 305 120 308 123 311 128 313 135 315 143 316 151 316 158 316 163 315 166 315 168 315 169
+37 184 146 183 147 183 146 183 145 183 143 183 142 184 138 185 134 186 130 188 127 189 125 191 124 192 124 193 126 194 130 195 133 197 138 198 141 198 144 199 145 200 143 201 140 203 137 205 133 208 129 210 126 211 124 212 124 213 124 213 126 214 129 215 133 217 138 218 142 219 146 219 148 220 149
+48 64 124 63 125 63 126 62 127 62 126 61 125 62 121 62 115 64 107 65 98 68 90 71 83 72 78 74 75 75 75 75 77 76 81 78 87 80 95 82 103 84 110 85 115 86 118 87 119 87 118 87 115 88 109 89 103 91 95 94 88 96 82 98 78 100 77 101 76 102 75 102 76 103 77 104 80 105 85 106 92 107 100 107 107 108 114 109 119 109 122 110 123 110 125 110 126
+43 271 175 271 177 271 180 271 182 271 183 271 181 271 178 271 173 271 166 273 158 275 151 277 145 280 141 282 140 284 141 286 144 287 147 288 153 289 159 289 165 290 169 290 171 290 170 291 167 292 162 294 155 296 148 299 141 302 136 305 132 308 130 311 130 313 132 315 136 317 141 318 147 319 153 320 157 321 160 321 163 321 165 321 166 321 167
+37 191 128 191 130 191 131 191 132 191 131 191 129 191 126 192 120 193 114 195 107 198 100 200 95 203 93 205 93 207 96 209 101 210 108 211 114 212 120 212 124 212 127 213 125 214 121 215 115 217 109 220 102 222 97 224 93 226 92 228 94 230 98 231 105 233 113 235 121 236 129 237 134 237 137
+46 54 104 54 107 55 109 55 110 54 108 53 104 53 98 52 90 52 82 53 74 56 67 59 62 62 58 67 57 70 57 74 60 76 64 78 70 80 77 81 85 81 92 81 98 81 102 81 103 80 102 81 97 81 92 83 85 85 78 87 71 90 67 93 64 95 61 98 60 100 59 103 60 105 61 107 65 109 70 111 77 112 86 113 94 113 102 113 107 114 111 114 112
+35 74 202 74 203 74 204 74 203 74 201 74 198 75 195 76 191 78 187 80 184 82 181 84 181 86 181 87 184 89 187 89 191 90 195 90 198 90 200 91 201 91 200 93 198 95 195 97 191 100 187 103 184 105 182 107 182 109 183 110 187 112 192 113 197 114 202 115 206 115 209
+48 163 118 163 119 163 120 163 119 163 118 163 114 162 108 162 100 164 91 166 83 168 76 171 71 174 69 178 69 181 71 184 74 186 78 188 84 189 92 189 99 189 104 188 109 188 112 187 112 188 111 188 107 189 102 190 96 192 89 194 83 196 78 198 75 199 73 202 72 204 72 206 72 208 72 211 74 213 76 215 80 216 85 217 93 218 100 219 107 219 113 219 117 219 118 219 117
+47 32 81 32 82 32 81 32 79 32 76 32 71 33 66 34 60 35 54 36 49 37 45 38 42 38 41 39 40 40 40 40 41 42 43 43 47 45 53 47 59 49 64 51 69 52 72 53 74 54 75 54 74 54 73 55 70 56 66 58 61 60 57 63 52 67 48 69 44 71 42 72 41 73 41 74 41 74 43 75 47 75 52 76 58 78 64 78 69 79 73 80 75 81 76
+9 n
+34 126 204 126 203 126 201 126 199 127 196 128 191 129 185 131 179 133 173 134 169 135 166 136 165 136 166 137 167 138 170 140 174 144 180 147 186 151 192 155 197 158 200 160 202 162 203 163 202 164 199 164 194 164 187 164 178 165 169 165 161 166 154 166 149 167 146 167 144
+35 211 142 211 143 211 142 211 140 210 137 210 131 210 124 211 116 211 108 212 101 212 97 212 94 213 93 214 96 216 100 219 106 222 113 226 122 230 130 234 136 236 140 238 142 239 142 239 141 240 139 240 135 240 130 241 122 241 112 241 102 241 93 241 84 241 78 240 75 240 74
+37 95 131 95 132 95 133 94 132 93 130 92 126 92 120 92 111 93 103 95 94 98 86 101 81 104 78 106 76 108 77 109 79 112 83 114 88 117 94 120 101 122 108 124 113 126 118 127 121 129 124 129 126 130 126 130 125 131 120 133 113 135 103 137 93 138 84 139 77 140 73 141 72 141 71
+34 237 190 237 189 237 188 237 185 238 180 240 174 242 166 244 157 247 149 249 143 251 138 252 136 253 135 254 137 256 141 258 147 261 155 265 165 269 175 272 183 275 189 277 193 279 194 280 194 281 192 281 188 282 181 284 172 285 160 286 149 286 140 286 132 286 127 286 124
+34 177 117 176 117 175 116 174 114 173 111 172 105 171 99 171 91 170 84 170 79 170 75 170 73 170 72 171 72 173 75 177 80 181 87 187 95 192 103 196 111 199 116 201 119 202 120 202 119 202 115 203 110 203 103 204 95 204 86 205 79 205 73 206 68 206 65 206 64
+34 54 116 54 115 53 113 53 110 53 106 53 99 53 92 55 85 56 78 58 73 60 69 62 67 63 66 64 65 67 66 68 68 70 70 72 74 74 79 76 85 78 91 79 98 81 103 81 107 82 110 82 108 83 105 84 99 85 92 86 84 87 77 88 72 89 69 90 66
+39 231 160 230 160 229 159 228 157 227 153 227 149 227 141 227 130 228 119 228 109 229 99 230 93 230 90 231 89 232 90 234 95 237 101 241 109 247 119 253 130 258 139 264 146 268 151 271 155 274 157 275 157 276 157 277 155 277 152 277 147 278 140 278 131 278 121 278 110 278 100 278 91 277 84 276 79 276 77
+37 148 137 147 138 147 139 146 139 146 138 146 136 145 132 144 128 144 122 144 116 143 110 143 106 143 103 143 102 144 101 144 102 146 104 147 108 150 112 154 118 158 124 161 129 164 133 167 135 168 137 169 137 170 137 170 136 170 134 170 132 170 128 170 124 170 118 170 112 170 107 170 102 170 99
+36 37 111 37 112 37 111 36 109 36 106 37 101 37 94 37 85 37 77 38 70 38 64 39 61 39 59 39 58 40 60 41 62 44 66 47 73 51 82 55 90 59 98 62 103 64 107 66 108 68 107 68 106 69 104 70 100 71 96 72 90 72 84 72 78 72 72 72 67 72 63 71 61
+9 o
+26 268 136 267 135 266 134 265 133 263 133 261 134 258 136 255 138 251 143 249 148 247 154 248 161 250 166 254 171 259 174 264 175 269 174 273 172 277 169 279 164 280 159 280 153 279 147 277 142 274 138 270 136
+31 170 68 170 66 169 64 168 62 166 62 163 62 159 65 155 70 151 77 147 87 146 97 147 108 151 117 156 125 163 129 170 130 178 129 185 125 191 119 194 111 197 101 197 91 196 82 193 74 189 68 183 65 176 63 169 64 162 65 157 68 153 70
+26 79 51 77 51 76 52 74 54 72 57 70 60 69 65 69 71 70 76 73 81 77 84 81 87 85 87 88 86 91 83 93 79 94 74 94 68 93 63 91 59 88 55 84 53 81 52 78 51 76 52 76 54
+25 271 158 270 158 267 159 265 160 262 164 260 169 258 176 257 183 258 190 260 196 263 200 268 202 274 201 279 198 285 194 289 189 291 183 292 176 290 170 287 164 283 160 277 157 271 157 265 158 261 159
+26 175 87 174 86 172 86 170 87 167 89 164 93 161 100 159 108 158 117 160 125 163 131 169 135 176 137 183 137 189 134 195 130 200 124 202 117 203 109 203 101 200 93 195 87 188 84 181 84 173 85 166 88
+29 62 68 61 67 60 66 58 66 56 68 53 71 51 76 49 83 48 92 49 101 52 109 56 115 62 119 68 120 74 119 79 116 83 111 85 105 87 97 87 89 86 81 83 74 79 70 74 67 67 67 60 68 55 71 51 75 50 78
+33 264 90 265 87 265 85 263 83 261 83 257 83 253 85 247 89 241 96 236 106 231 118 228 131 228 144 230 154 235 162 243 168 251 170 260 168 270 163 279 155 286 145 291 135 293 127 294 115 291 104 286 95 279 88 271 84 261 84 253 86 244 89 239 94 235 98
+24 157 117 157 116 155 116 154 117 152 120 149 124 147 130 145 136 144 143 145 149 148 153 151 155 156 155 160 154 165 150 168 146 170 140 171 135 170 129 169 125 166 121 162 119 158 119 154 120
+25 71 63 69 62 65 63 62 67 58 72 55 81 54 91 53 102 55 112 59 120 64 124 71 125 77 122 82 118 86 111 88 103 89 94 88 85 87 77 84 71 79 66 75 65 70 64 67 65 63 66
+9 p
+39 262 144 262 143 262 144 263 146 264 150 265 155 266 161 267 167 267 173 267 177 267 180 266 181 265 180 264 177 263 172 262 166 261 159 260 151 260 145 261 139 263 135 267 131 272 128 277 126 283 125 288 127 292 129 296 134 298 138 298 143 297 147 295 152 291 155 287 157 281 158 273 159 265 160 258 160 252 159
+36 195 93 195 92 196 94 196 97 197 102 198 108 198 115 199 123 199 131 198 136 198 140 197 142 196 139 195 133 194 126 193 117 192 109 192 101 192 94 194 89 196 85 199 83 203 83 207 84 211 86 215 90 217 95 219 100 218 106 217 111 214 115 210 119 205 121 200 122 196 122 193 121
+36 85 78 86 80 86 84 87 89 89 95 90 103 91 110 92 117 92 122 91 125 91 127 90 126 89 124 88 121 87 114 86 105 85 96 85 88 86 80 87 75 90 72 94 70 97 69 102 69 106 71 110 74 113 78 113 82 112 86 110 89 106 92 102 95 97 98 93 99 89 101 86 101
+35 248 100 248 103 249 106 250 112 251 121 252 130 253 141 254 150 254 158 255 163 254 167 253 166 251 163 249 157 247 148 244 137 242 126 241 113 242 103 244 94 248 86 253 82 259 80 266 80 273 83 279 89 284 96 287 103 286 111 284 118 279 124 273 128 266 131 259 133 254 132
+32 148 129 149 130 150 133 151 137 152 143 153 150 154 157 154 162 154 166 154 169 153 169 152 167 151 163 150 158 148 151 147 142 147 134 148 127 149 122 153 119 156 117 160 117 164 119 167 122 169 126 170 130 169 134 166 138 162 141 158 143 152 144 148 145
+32 57 79 57 80 58 84 58 89 60 95 61 103 62 110 62 117 61 121 60 123 58 122 56 118 54 111 52 103 51 93 51 83 53 74 56 68 61 63 67 61 73 61 79 63 83 66 86 70 87 75 85 81 81 86 76 91 71 95 64 97 61 98 58 98
+37 209 121 209 122 210 124 211 128 211 133 213 140 214 148 214 155 215 161 215 166 214 169 214 171 212 171 211 169 210 164 209 157 208 147 207 137 208 126 210 116 212 108 215 100 220 95 224 93 228 92 234 93 239 97 243 102 245 108 246 114 244 121 240 126 235 129 229 131 223 132 217 132 212 132
+38 131 58 131 57 131 58 132 59 133 62 134 66 135 71 136 77 136 83 136 89 136 93 136 95 135 95 134 93 134 88 132 83 131 76 130 69 130 63 130 57 132 52 135 48 138 45 141 43 145 42 149 42 154 45 157 48 159 52 161 57 160 61 159 65 156 68 153 70 148 71 144 71 140 71 136 71
+37 37 62 37 61 38 60 38 61 38 63 38 66 39 71 40 77 40 84 40 89 40 94 40 97 40 99 39 97 39 94 38 89 37 82 36 75 36 68 37 61 38 56 40 51 42 47 46 44 49 43 53 42 56 43 59 46 61 50 62 54 61 59 59 63 55 66 51 69 46 71 42 72 40 71
+9 q
+44 277 138 277 139 277 138 276 138 275 137 273 136 271 136 268 137 264 139 259 142 254 148 251 155 248 162 248 170 250 177 254 183 260 187 266 188 272 187 278 184 284 180 288 174 291 167 292 159 291 153 289 147 285 143 280 140 275 139 271 138 267 138 264 138 263 139 264 139 266 140 271 140 276 140 283 139 289 137 295 136 300 134 303 133 306 132 307 132
+39 170 81 170 79 169 78 167 78 164 80 161 84 158 90 156 99 155 108 155 118 157 126 161 132 167 136 173 137 180 135 186 133 191 128 194 122 196 113 196 104 195 95 191 88 186 82 180 79 175 77 170 77 166 79 165 82 167 86 170 89 176 92 183 94 191 93 200 91 209 88 217 85 224 82 228 80 231 79
+38 67 65 67 64 67 63 65 63 63 64 60 65 56 69 52 74 48 82 45 92 44 104 44 115 46 125 50 132 55 136 61 136 66 134 73 130 77 124 79 115 81 105 81 95 80 85 78 76 75 71 71 68 65 67 61 68 57 70 55 73 54 76 56 79 59 82 64 83 72 84 77 82 84 80 88 77
+36 236 157 236 156 235 156 234 157 233 159 232 162 230 165 229 170 228 175 229 179 230 183 233 186 237 188 241 189 244 189 248 188 250 185 252 181 252 177 252 171 252 166 250 161 247 158 244 155 241 155 237 155 234 156 231 157 230 159 231 160 233 160 238 160 244 159 251 157 257 154 263 152
+43 174 84 174 83 174 81 173 80 172 79 170 78 168 77 164 77 160 78 156 81 151 84 147 90 144 96 142 104 142 112 143 118 145 123 149 127 154 128 160 128 166 126 171 121 176 115 179 108 181 99 182 91 181 84 179 78 176 74 172 71 167 70 163 71 158 72 155 74 154 76 154 78 156 79 160 80 165 80 170 79 176 77 181 76 184 75
+38 62 54 60 52 58 51 56 51 54 52 51 54 49 56 47 60 46 66 45 73 46 81 47 90 50 96 54 101 59 104 62 104 68 101 73 97 77 90 79 82 79 74 78 68 75 62 72 58 67 55 62 53 58 53 55 53 53 54 52 56 54 58 57 60 62 62 69 63 75 63 82 62 87 60 92 59
+52 244 122 243 120 242 118 241 117 239 116 236 117 232 119 228 123 224 130 220 138 217 147 216 156 217 166 220 174 225 181 232 185 239 187 246 187 254 184 260 179 267 174 272 168 275 161 278 154 279 148 278 142 276 136 272 130 267 126 262 122 255 119 249 116 243 115 238 114 234 114 232 114 231 115 231 116 232 117 233 118 234 119 235 120 236 120 237 120 240 119 244 118 250 116 258 113 266 110 274 107 280 105 284 103
+40 165 67 165 66 164 65 162 66 159 67 157 68 154 72 152 76 151 82 151 89 152 95 155 100 158 103 162 104 166 103 170 100 173 96 175 90 176 85 175 80 174 75 172 71 170 69 167 67 164 66 162 65 160 64 158 64 157 63 156 63 157 63 159 64 162 63 166 63 171 62 177 61 187 59 191 59 193 59 195 58
+49 47 45 47 44 46 44 45 43 44 43 42 43 40 44 38 46 35 50 34 54 33 60 33 66 34 71 37 77 40 81 45 84 50 86 55 85 61 84 65 81 69 77 71 73 72 68 72 63 71 58 68 54 64 50 61 47 58 45 54 43 51 42 49 42 47 42 45 42 44 42 44 43 43 43 43 42 43 43 44 43 46 44 49 44 54 43 59 42 67 41 74 40 80 39 85 38 88 37
+9 r
+41 244 138 244 140 244 142 245 147 245 152 246 158 246 163 246 167 246 170 245 168 244 164 243 159 241 152 240 144 240 137 242 131 244 127 248 123 252 121 257 121 260 123 261 127 261 132 259 138 255 144 252 149 249 152 246 154 246 155 247 154 250 154 254 154 260 155 266 156 273 159 279 162 284 165 288 168 291 170 292 171 291 170
+38 145 85 146 83 147 85 149 89 150 96 151 104 152 112 152 119 152 123 151 121 150 115 150 107 149 99 150 90 152 84 155 79 160 76 165 76 169 78 172 81 174 85 174 91 173 97 170 102 168 106 165 109 163 110 162 111 164 112 167 113 171 115 176 117 183 119 190 122 195 124 200 125 203 125 204 125
+38 51 64 52 63 52 64 53 66 53 70 54 76 54 82 54 88 53 94 53 98 52 100 51 99 51 96 50 90 50 83 51 74 53 66 56 60 59 56 63 54 67 54 70 56 71 59 71 63 70 67 68 72 64 76 63 79 63 82 64 85 68 87 73 90 78 92 84 94 89 96 94 98 98 100 102 100
+51 244 137 245 138 246 139 247 143 248 149 249 158 250 167 251 176 251 184 251 187 251 190 250 191 248 187 247 182 245 175 243 167 242 158 241 151 242 144 243 138 245 133 249 129 253 126 258 124 264 124 269 125 273 128 276 133 276 140 274 146 270 153 265 159 260 163 256 164 251 166 247 165 246 164 246 163 250 161 255 161 261 162 268 164 275 168 282 173 287 177 291 182 295 187 297 189 298 191 299 192 299 191
+51 162 51 162 53 163 57 164 62 166 70 167 78 168 87 169 95 169 101 169 106 169 109 168 110 167 109 166 106 164 103 162 98 160 91 157 85 156 78 154 71 154 65 154 59 156 54 159 49 162 45 166 43 170 41 175 41 179 43 182 45 184 50 184 55 182 60 179 66 175 70 170 73 167 75 165 76 164 77 166 77 170 77 176 78 183 80 188 82 196 86 203 89 208 93 212 95 214 96 214 97 213 96
+48 49 50 49 51 50 54 51 58 52 63 53 69 54 76 53 83 53 88 52 93 51 95 50 94 49 91 48 86 46 81 44 74 42 67 41 61 41 56 41 51 43 47 46 43 50 41 55 39 59 38 64 39 68 40 70 43 70 48 69 53 65 58 62 63 59 66 56 68 55 69 54 70 55 70 58 71 62 72 68 74 74 76 80 79 85 82 90 85 93 88 94 89 95 90 95 89
+39 200 156 201 159 202 163 203 168 203 175 204 181 204 186 203 190 203 191 202 190 202 186 201 181 200 175 199 168 199 162 199 157 200 153 203 150 205 149 208 149 211 150 213 152 215 154 215 158 214 161 212 164 209 167 208 169 206 170 205 171 206 172 207 173 210 174 215 176 220 178 226 179 233 181 238 182 243 183
+41 146 58 146 59 146 62 146 66 146 72 147 80 147 87 147 95 146 100 146 103 146 102 146 99 145 95 144 88 143 81 142 74 141 67 141 61 143 56 147 53 152 50 157 48 163 49 167 51 170 54 171 59 169 64 166 69 162 73 158 76 155 77 153 78 153 79 155 80 159 81 169 85 176 89 183 93 188 97 193 99 196 100
+40 26 51 26 50 26 52 26 56 27 60 28 66 28 73 29 79 29 83 28 86 28 87 27 85 26 81 24 75 24 68 23 61 24 54 26 48 30 43 35 41 40 40 45 40 49 43 50 46 50 52 48 58 43 63 39 68 35 71 32 74 31 75 32 75 35 76 39 77 45 78 51 81 57 84 61 87 64 89 67 90
+9 s
+39 262 141 262 140 263 139 263 138 263 137 262 135 261 133 258 132 254 131 250 130 245 130 241 132 237 134 234 137 233 141 232 144 234 150 236 155 240 159 244 163 249 166 254 168 258 170 261 173 263 175 263 178 263 182 260 185 257 188 251 190 245 191 238 192 231 191 224 189 219 186 215 182 213 179 212 175 212 173
+31 194 65 194 64 193 63 192 62 189 61 186 61 181 63 176 65 172 68 169 72 168 76 169 79 172 82 177 86 182 89 187 93 191 97 193 101 193 104 192 108 188 110 184 112 178 113 171 113 165 112 160 111 155 109 153 107 152 106 152 104 154 102
+30 84 56 84 54 83 53 82 52 80 51 77 52 74 54 70 57 65 60 64 63 62 66 63 69 65 72 70 74 75 76 79 78 82 80 84 83 85 86 84 89 82 92 79 94 74 96 69 98 62 99 57 99 52 99 49 98 48 97 48 95
+34 270 96 271 94 271 92 270 89 268 87 264 84 260 82 254 81 248 81 242 83 237 87 233 92 232 98 233 102 235 107 240 114 246 121 253 127 260 133 265 138 269 142 271 147 271 151 269 156 266 160 261 163 255 166 248 167 243 167 237 165 231 163 227 160 224 157 223 154
+33 174 84 174 83 174 82 173 81 171 79 169 78 166 77 161 77 157 78 152 80 148 83 146 86 146 90 147 94 151 99 156 103 161 107 167 111 172 115 175 118 177 121 177 124 176 127 174 130 170 133 166 135 160 136 157 136 151 135 145 134 140 131 136 129 133 127
+27 80 50 80 49 80 47 79 46 76 46 73 47 69 49 63 52 58 57 55 61 53 66 55 70 58 74 63 76 70 79 75 82 79 86 82 91 82 96 79 100 75 105 70 108 62 110 56 111 51 111 48 110 46 107
+42 302 74 301 74 300 74 299 72 298 71 296 68 294 66 292 63 289 62 284 62 280 63 275 66 270 70 266 75 264 82 263 90 264 97 266 104 269 109 274 112 279 114 284 115 289 117 293 119 297 122 300 125 301 129 302 135 302 139 300 144 297 148 293 152 288 155 282 157 275 158 268 158 261 157 255 154 250 150 246 147 244 144 242 141
+37 190 95 190 94 189 93 188 91 186 90 184 89 181 89 178 90 176 92 174 95 172 99 172 102 172 106 173 109 174 112 176 114 178 115 180 116 182 117 184 117 186 118 188 119 190 121 192 123 193 125 193 127 193 130 192 132 190 134 188 136 184 137 181 138 177 139 173 139 170 138 167 137 165 136
+41 71 42 70 42 69 41 67 41 64 40 60 40 57 40 53 42 50 44 48 46 46 49 45 52 46 56 47 58 48 60 51 62 53 63 56 63 60 63 63 63 67 64 70 65 73 66 75 68 77 70 78 73 79 74 79 77 79 79 78 82 77 84 75 86 72 88 68 89 63 90 59 91 55 91 51 90 48 89 45 88 42 86
+9 t
+28 240 78 240 79 242 79 245 80 250 81 257 81 264 81 272 81 279 81 285 81 289 81 292 80 293 80 293 81 292 82 292 85 291 90 290 98 288 108 286 118 284 129 281 138 279 146 277 151 276 155 275 157 275 158 274 158
+27 147 52 145 52 145 51 144 51 144 52 146 53 150 53 155 53 162 53 169 52 175 51 180 50 184 50 186 50 187 50 187 51 186 52 186 56 187 61 187 69 188 79 189 90 190 100 191 110 192 116 193 121 193 123
+24 38 38 36 38 36 37 39 37 42 37 47 37 53 37 60 37 66 37 71 37 74 38 75 38 75 40 75 42 75 46 74 52 74 59 73 69 73 79 72 88 71 95 70 100 69 102 69 101
+29 268 93 266 93 265 92 264 92 263 91 264 91 266 90 271 90 278 89 286 88 294 87 302 86 308 86 312 86 314 87 315 87 315 89 315 92 315 98 314 105 314 115 314 126 314 136 315 145 315 152 315 157 316 160 316 162 315 161
+30 171 77 170 77 169 77 170 77 171 77 175 76 180 76 186 76 192 75 198 75 203 75 206 75 209 76 210 76 211 78 211 81 210 85 210 92 210 102 210 113 210 125 210 136 210 146 210 155 210 163 210 168 211 173 211 175 211 177 210 177
+27 57 65 56 65 56 64 58 64 61 65 67 64 72 64 78 63 84 63 89 63 92 63 94 63 94 64 94 65 94 68 93 71 93 76 92 85 92 94 92 104 92 112 92 120 92 124 92 126 92 127 92 126 92 125
+24 258 80 257 80 256 80 258 79 261 79 266 77 271 76 278 74 283 73 286 72 289 72 291 71 292 71 292 72 292 73 292 75 292 80 293 87 293 96 294 105 295 113 295 119 295 123 295 125
+27 159 50 157 49 157 50 159 50 163 52 168 54 175 56 183 59 190 62 197 64 201 65 204 66 206 67 207 67 207 68 207 69 206 72 205 77 203 84 201 94 198 104 195 112 193 119 193 124 192 126 193 125 193 124
+25 21 41 22 41 24 42 28 41 34 40 40 40 48 39 56 38 61 38 67 38 69 38 71 39 70 41 70 43 68 47 67 53 64 61 62 70 61 78 59 87 58 93 58 98 58 101 58 100 59 97
+9 u
+24 229 142 230 140 230 138 231 138 231 140 231 142 231 147 232 154 233 162 235 170 237 178 240 184 244 188 249 189 253 188 257 186 261 181 263 175 265 167 266 159 266 152 266 145 266 141 265 139
+22 154 93 154 91 154 90 155 92 155 96 157 102 158 110 160 119 162 128 164 135 167 140 170 142 174 142 178 140 181 136 184 131 186 123 187 114 188 105 188 97 188 91 187 89
+21 60 58 60 59 60 61 60 64 60 69 61 75 62 82 63 90 66 96 70 103 73 106 77 108 81 107 84 104 87 99 90 93 92 85 93 78 93 72 93 66 92 62
+24 220 119 220 117 220 118 220 120 220 124 220 130 221 137 222 145 224 153 227 160 231 165 236 168 242 168 248 166 253 162 258 157 261 149 263 141 265 133 265 127 265 121 264 117 264 114 263 112
+21 142 50 141 49 142 52 142 54 143 59 144 65 147 73 150 81 154 87 160 91 165 93 170 93 175 91 178 87 180 82 182 76 182 71 182 66 181 62 180 60 180 59
+20 44 40 44 41 43 45 43 50 43 57 45 65 47 73 50 81 54 87 59 91 65 92 71 90 74 87 77 82 79 77 80 72 80 67 79 63 79 59 79 57
+21 224 125 225 127 225 130 226 135 227 141 228 148 230 155 233 161 236 165 240 168 243 168 247 166 250 163 252 158 254 151 255 144 256 136 257 129 257 124 257 121 257 119
+23 133 67 133 66 133 65 133 66 133 69 134 73 135 80 136 88 138 98 141 106 145 112 150 116 156 116 159 115 164 110 168 102 171 94 173 85 173 77 173 70 172 66 171 63 170 60
+21 30 53 30 54 30 56 30 60 31 64 33 70 35 76 39 82 42 86 46 88 50 88 54 86 57 83 59 78 61 74 61 68 61 63 60 58 59 54 58 50 57 47
+9 v
+31 250 157 249 156 250 156 250 157 252 160 254 165 257 171 260 179 263 186 266 192 267 196 269 198 270 198 272 195 274 191 276 184 278 176 281 168 283 162 284 157 285 155 286 154 287 154 289 154 292 155 296 155 301 155 305 155 308 154 311 154 313 153
+32 164 114 163 112 163 110 163 109 163 111 165 114 167 120 170 127 173 136 175 144 178 151 181 156 184 158 187 158 190 155 193 150 196 143 199 135 201 127 202 120 202 114 203 111 203 109 203 108 204 108 206 108 209 109 213 109 218 109 222 108 226 106 229 105
+31 60 66 61 65 61 64 61 65 62 66 64 68 67 74 70 81 74 90 77 99 81 107 84 113 86 117 88 117 90 114 92 108 94 101 95 92 95 84 95 77 95 71 94 68 94 65 94 64 96 63 98 62 102 60 107 59 112 58 117 56 120 55
+34 259 150 258 150 258 151 259 151 260 152 261 155 262 158 264 164 267 170 269 177 271 183 274 188 277 190 281 190 284 187 288 182 291 175 292 169 293 162 294 157 293 153 293 150 292 149 292 148 293 148 294 148 297 148 301 147 306 146 311 144 316 143 319 141 322 141 324 141
+33 168 101 168 98 168 97 168 96 168 97 169 100 170 104 173 111 175 118 178 126 181 132 183 137 185 140 186 141 187 140 188 136 189 131 191 122 192 113 193 105 194 98 194 94 195 92 195 91 196 91 198 91 200 91 204 91 208 91 212 90 215 89 218 89 219 89
+32 57 58 57 57 57 56 58 57 58 58 60 62 62 68 64 76 66 86 69 95 71 102 74 106 76 107 79 105 81 100 83 93 85 86 86 78 87 72 87 67 87 63 87 62 86 61 87 61 87 62 89 62 91 62 95 62 99 62 104 61 107 61 110 60
+31 80 155 80 153 79 152 80 153 81 155 83 160 86 167 90 174 94 181 98 187 102 191 105 192 108 192 111 190 113 185 115 179 116 172 116 165 115 159 115 155 114 153 114 152 114 151 116 151 119 151 124 151 128 151 134 150 138 150 142 149 145 149
+30 160 93 161 91 162 91 164 94 166 99 168 105 171 112 174 120 177 127 180 132 183 135 185 136 187 135 189 131 190 126 191 118 192 110 192 102 191 96 191 91 191 88 192 86 194 86 197 85 202 84 207 84 212 83 217 82 221 82 223 82
+29 48 58 48 57 47 56 47 55 48 57 49 59 51 64 54 71 58 79 61 88 63 95 66 100 68 102 70 101 72 97 73 91 74 84 75 76 76 69 76 63 76 59 75 57 76 56 77 56 79 56 81 56 85 56 89 56 93 55
+9 w
+41 257 148 257 147 257 146 257 147 257 149 257 154 257 161 257 170 258 179 259 187 260 193 262 196 264 197 267 195 269 192 272 187 273 182 275 176 276 170 277 166 278 163 278 162 278 163 279 165 281 168 283 173 286 177 289 182 291 186 294 188 296 188 299 187 300 184 301 178 303 172 304 163 304 154 304 146 304 139 303 133 302 130
+43 159 64 158 61 158 60 158 61 159 65 161 70 163 79 167 90 171 101 176 113 179 122 183 128 185 131 186 130 188 125 189 117 191 107 194 96 196 85 198 78 199 74 200 72 200 70 200 71 201 72 202 76 204 83 206 92 208 101 211 111 213 119 216 125 218 128 219 129 221 126 223 121 225 112 227 102 229 90 231 79 232 69 232 62 233 57
+39 37 63 37 61 37 59 36 58 37 61 38 65 38 72 40 80 42 89 44 96 46 101 48 102 50 100 52 96 54 91 56 85 58 79 59 76 60 73 60 72 60 71 61 72 62 74 64 77 67 82 70 87 72 92 75 96 76 98 77 99 79 98 80 95 81 90 82 84 83 76 84 68 84 62 84 58 83 55
+37 249 123 249 122 249 123 249 124 249 128 248 132 248 139 249 146 250 153 252 159 254 162 257 164 259 163 261 161 263 158 265 154 266 150 266 147 267 146 267 145 268 146 269 149 270 152 272 157 275 161 278 165 282 167 286 166 290 163 294 159 296 153 298 146 299 140 298 135 298 130 297 128 296 126
+35 159 100 159 98 159 97 158 99 158 103 158 108 158 115 158 123 159 129 161 134 164 136 167 137 171 136 174 134 177 131 179 127 180 125 181 122 181 121 182 122 182 123 183 125 184 129 186 131 189 133 191 135 194 135 196 133 199 131 200 128 202 123 202 117 202 111 201 106 200 101
+44 35 49 35 47 35 46 34 47 34 48 33 52 32 57 31 64 31 72 31 79 32 88 35 96 38 102 43 105 48 106 54 103 58 99 62 93 65 87 67 81 68 76 68 73 68 71 68 70 68 71 69 73 70 75 71 79 73 84 75 90 77 94 80 98 84 101 87 102 91 101 95 99 98 95 101 89 104 82 104 74 104 66 102 59 99 53 96 48
+43 229 129 229 127 229 124 230 122 230 121 230 123 230 126 230 132 230 141 230 150 231 160 232 168 234 174 237 177 241 177 245 176 249 172 253 167 256 161 258 156 259 150 260 146 260 144 261 143 261 144 262 146 263 149 264 153 266 158 269 163 270 167 273 170 275 171 277 169 280 166 282 161 284 154 286 146 286 137 286 129 285 122 284 116 282 111
+37 129 69 128 68 127 67 126 69 126 73 126 78 126 86 126 94 128 103 129 109 130 114 133 116 135 115 138 112 140 107 142 102 144 96 145 92 145 90 146 90 148 92 150 97 153 102 157 108 160 113 163 117 167 119 169 118 171 115 173 109 174 101 175 93 175 85 175 80 174 74 173 71 172 69
+34 33 39 33 37 32 37 32 39 32 43 32 50 33 57 33 65 34 72 35 77 37 79 38 80 40 78 42 76 45 72 46 68 48 65 49 64 51 64 53 67 55 70 59 73 62 76 65 77 69 78 71 76 73 74 75 70 75 64 76 59 76 53 75 48 74 44 73 41
+9 x
+37 259 144 258 143 257 142 256 141 255 140 256 141 258 143 261 146 265 150 270 155 276 160 283 165 289 168 295 171 300 172 304 172 308 172 310 170 311 168 311 165 309 163 307 161 304 160 300 161 296 161 291 163 286 166 281 169 276 174 271 178 267 183 264 188 262 191 261 193 261 194 260 195 259 195
+33 181 87 180 85 180 84 179 84 180 85 180 87 182 91 185 95 188 100 193 106 199 111 205 115 211 116 217 116 222 115 226 113 228 111 229 108 229 107 227 106 224 106 220 107 215 109 208 112 202 115 194 119 187 123 181 128 175 132 171 135 169 138 168 140 168 142
+30 54 48 53 47 52 47 52 48 54 51 56 56 60 61 65 67 72 74 77 79 83 83 89 85 93 86 97 85 99 83 100 81 100 79 99 76 97 75 94 74 90 74 85 75 79 78 73 82 67 87 61 91 57 95 54 99 53 101 53 103
+37 227 154 227 153 227 154 227 155 228 157 230 160 233 164 237 169 241 174 246 178 251 181 255 183 258 184 261 184 262 183 263 183 263 181 263 180 263 178 262 177 261 176 260 175 258 175 255 176 251 177 247 178 242 180 238 182 233 185 229 187 226 189 224 190 223 190 222 191 221 191 220 191 218 192
+37 162 72 161 71 162 72 163 75 165 79 168 84 172 90 177 97 183 103 189 108 195 110 201 111 206 110 212 107 216 103 220 99 222 95 223 92 223 89 222 88 220 86 216 86 213 85 208 85 203 86 198 87 192 89 187 92 181 96 175 100 169 106 163 113 157 119 152 125 147 129 144 131 143 132
+32 46 52 45 51 45 50 46 52 48 55 51 59 56 65 61 71 66 76 72 80 77 83 81 83 85 83 87 82 89 80 89 78 89 76 89 74 88 73 87 72 85 71 83 71 81 72 78 73 73 75 69 77 63 81 59 85 55 89 53 93 52 95 52 97
+34 213 130 212 130 211 130 212 131 214 134 216 139 219 144 224 151 229 157 235 161 241 164 247 166 253 166 258 164 261 162 264 159 266 157 266 154 266 152 264 151 261 151 258 151 252 153 246 155 239 159 232 162 224 166 217 170 211 174 206 177 202 180 200 182 198 184 197 186
+35 141 59 140 59 140 60 140 61 142 63 144 66 147 70 152 76 157 81 162 86 168 89 173 91 177 92 181 91 184 90 186 89 187 89 187 88 186 88 185 87 184 87 183 86 182 87 181 87 180 88 178 88 176 89 170 91 164 94 155 99 146 103 138 108 132 112 127 116 126 118
+32 33 49 33 50 33 51 34 53 35 56 38 60 40 64 44 69 49 73 54 75 59 77 63 78 67 78 70 78 72 76 72 75 73 74 72 72 71 71 69 70 65 70 61 70 57 71 51 73 45 76 41 79 34 85 28 91 24 96 21 101 20 104 21 104
+9 y
+48 251 107 251 106 250 106 249 108 247 110 246 114 244 119 243 124 244 130 245 134 248 138 252 139 257 138 262 135 267 131 271 126 273 121 276 118 277 115 277 113 277 115 277 117 278 122 279 128 280 136 281 145 282 154 283 162 283 169 282 174 280 177 277 179 273 179 267 178 261 176 256 173 251 169 248 166 247 162 249 159 254 155 261 151 270 148 280 145 290 142 297 141 302 142 304 142
+38 140 59 140 58 139 60 138 62 137 66 136 72 135 79 135 85 136 90 139 91 143 90 148 87 152 82 157 77 160 72 162 69 164 68 165 70 165 75 166 83 167 93 168 104 168 115 167 124 164 131 160 135 155 137 149 137 144 136 140 133 138 128 138 123 141 118 146 113 154 108 162 103 171 100 178 99
+40 22 48 22 47 21 47 22 49 22 53 24 57 26 62 29 66 32 69 35 69 38 67 42 64 44 59 47 55 48 50 49 46 49 44 49 43 50 45 52 50 54 56 58 65 63 75 68 86 71 96 73 105 73 111 72 116 69 118 63 119 57 118 51 115 45 111 40 107 39 101 40 94 43 88 49 81 56 75 63 69
+40 262 126 262 124 262 123 262 122 262 123 262 126 262 130 262 135 263 140 265 145 266 148 269 149 271 148 274 145 277 142 279 138 281 135 282 133 283 133 284 135 284 140 286 146 288 154 289 163 291 171 291 178 289 183 287 185 283 186 278 185 274 182 269 180 267 177 266 174 268 170 271 166 277 161 284 157 291 154 297 151
+45 158 75 157 74 156 74 155 76 154 81 153 87 153 96 154 106 156 114 159 120 163 123 168 122 174 117 179 111 183 103 186 95 189 88 190 82 191 79 192 77 192 78 193 82 194 89 195 99 197 111 198 124 200 137 200 150 199 161 196 171 192 179 185 186 177 189 169 190 161 188 156 183 153 176 154 167 159 159 166 152 175 146 185 141 194 138 203 136 209 136
+37 56 59 56 56 56 54 56 53 56 56 56 59 56 64 57 69 59 74 62 77 65 78 69 77 72 74 74 71 76 67 78 63 79 59 79 58 81 59 82 63 85 69 87 77 89 87 90 97 90 107 88 115 85 120 80 124 75 125 70 124 65 122 63 117 63 112 65 106 70 100 75 95 81 91
+41 254 107 254 106 254 105 253 105 253 106 252 108 252 112 252 118 252 124 253 130 255 134 258 136 262 136 267 133 272 129 276 125 279 121 281 118 283 116 284 117 285 121 285 126 285 134 286 143 286 153 285 162 282 171 278 178 273 183 265 186 257 186 250 184 245 180 243 175 244 168 250 162 258 157 269 153 279 150 289 150 296 150
+45 153 62 153 61 152 62 151 63 149 65 147 69 144 75 142 81 141 87 141 93 142 98 145 100 150 100 155 97 161 93 167 88 172 83 175 79 177 76 178 74 179 73 179 74 179 76 179 81 178 87 178 95 177 104 175 113 172 121 168 128 164 134 159 137 153 139 148 139 144 138 142 136 142 132 145 127 150 122 158 118 167 114 177 111 185 110 192 110 196 111
+47 32 37 32 35 31 35 30 37 29 39 28 43 27 48 27 52 28 59 30 65 32 69 36 71 41 71 45 69 50 65 53 60 56 55 57 51 59 47 59 44 59 43 59 42 60 43 60 46 61 50 62 56 63 64 65 74 67 83 68 92 69 101 69 109 67 115 64 119 60 121 56 121 51 119 47 116 43 111 41 105 41 99 42 93 46 88 52 83 58 79 64 76 71 75
+11 z
+109 193 53 194 53 197 53 200 52 204 52 208 52 215 52 222 52 232 52 239 52 242 52 244 52 245 51 246 51 247 51 248 51 249 50 249 51 248 53 247 55 246 57 244 60 241 63 239 67 236 70 234 73 232 76 230 79 228 81 227 83 225 85 224 87 223 89 222 90 221 90 220 91 220 92 219 92 218 93 217 95 215 96 213 97 212 99 210 100 209 101 208 102 207 103 206 104 206 105 204 106 203 107 202 108 201 109 201 110 200 111 199 111 199 112 198 112 198 113 197 113 196 114 195 114 194 115 193 115 194 115 193 115 194 115 195 115 198 115 201 115 205 115 209 115 213 115 216 115 217 115 218 115 219 115 221 115 223 114 225 114 227 114 228 114 230 114 230 113 232 113 233 113 234 113 236 114 238 114 240 114 242 114 244 114 245 114 246 114 247 114 248 114 249 114 250 114 251 114 252 114 253 114 254 113 255 113 256 113 257 113 258 113 259 113 260 113 260 112
+134 22 47 22 46 23 46 24 46 26 46 28 45 32 45 36 45 40 45 47 45 54 45 58 46 61 46 64 46 65 46 67 46 68 46 69 46 70 46 72 46 74 46 76 45 79 45 81 45 83 45 84 45 85 45 86 45 87 45 88 45 89 45 88 46 86 47 85 49 84 51 82 53 81 54 80 56 78 58 76 59 75 61 73 63 71 65 70 66 70 68 69 69 68 70 68 71 67 72 68 71 67 72 66 73 65 74 64 75 62 76 61 77 60 78 60 79 59 79 58 80 57 81 56 82 55 83 54 84 54 85 53 85 52 86 52 87 51 87 50 88 50 89 49 90 49 91 48 91 48 92 47 93 46 94 44 96 44 97 43 98 42 99 41 100 40 101 39 102 38 103 37 103 37 104 36 104 36 105 35 106 34 107 34 108 33 108 32 109 31 111 30 111 30 112 31 111 33 111 36 111 40 111 44 110 47 110 50 110 51 110 52 110 53 110 54 110 55 109 57 109 59 109 62 109 64 109 65 109 67 109 69 109 71 109 73 109 76 109 78 109 79 109 80 108 81 108 82 108 83 108 84 108 85 107 86 107 87 107 89 107 91 107 94 107 95 107 96 107
+31 249 136 250 135 252 135 256 134 261 132 267 131 274 130 280 129 284 130 287 132 288 135 287 139 284 145 280 152 274 159 268 167 261 174 255 180 252 183 248 187 247 189 248 190 251 190 258 190 266 189 275 189 285 189 292 189 298 189 302 190 304 190
+27 168 78 167 78 166 78 168 77 170 76 174 75 179 75 184 74 189 74 193 75 195 77 196 82 195 87 192 95 189 103 185 111 181 117 179 121 177 124 177 126 178 126 181 126 186 126 191 126 197 125 202 125 207 125
+30 56 61 55 61 54 62 53 62 55 61 58 60 63 59 69 58 75 57 80 56 84 57 87 60 87 65 86 71 83 77 80 82 76 90 71 97 66 103 63 108 61 111 62 113 65 113 71 113 76 112 83 112 89 112 95 111 99 111 102 111
+34 220 73 218 73 220 72 224 71 230 70 238 69 245 68 253 67 259 68 263 70 266 73 266 78 265 86 263 96 258 108 253 121 247 134 240 145 233 156 226 163 221 169 218 173 216 175 218 173 222 170 225 168 233 166 242 163 252 162 261 162 270 163 277 164 282 166 285 167
+31 140 103 139 103 139 102 141 102 142 102 145 101 149 100 154 99 158 97 162 97 165 97 167 98 167 101 167 106 165 112 161 118 157 124 153 131 148 136 144 139 142 142 140 144 140 145 141 145 144 144 148 144 153 143 159 142 165 142 170 141 175 141
+26 53 50 51 50 50 50 51 49 53 49 55 49 59 49 63 49 68 50 71 52 72 56 73 60 71 65 69 70 64 74 61 78 58 80 57 81 56 82 56 83 58 82 62 82 65 82 71 81 74 81 77 80
+36 249 144 247 143 246 143 247 142 248 142 252 141 257 141 263 140 269 140 276 139 280 140 284 141 285 143 284 146 282 151 278 157 272 164 266 172 259 180 252 188 246 194 241 199 238 203 236 205 235 205 240 204 245 202 252 199 261 197 270 195 278 194 286 194 292 195 296 197 298 198 299 200
+35 173 58 175 58 178 58 182 58 187 58 193 58 198 59 203 59 206 59 208 60 209 62 208 65 207 68 204 74 200 80 195 88 189 96 183 104 178 110 174 115 172 118 170 119 170 120 172 119 174 118 177 117 181 116 187 114 194 113 202 112 210 111 217 110 224 110 229 110 233 111
+34 33 54 31 53 30 53 29 52 30 52 31 52 33 52 37 52 41 52 46 52 50 52 54 53 56 54 57 57 57 60 56 65 54 71 50 76 46 82 41 88 36 93 32 97 30 100 29 102 30 103 32 102 37 100 43 99 50 97 57 97 64 97 71 98 76 98 78 99
+9 A
+15 239 59 237 61 236 61 239 62 245 61 253 60 264 59 275 57 286 55 296 54 302 53 307 53 308 53 308 54 307 55
+12 133 129 130 129 129 129 133 129 139 128 149 128 160 127 171 127 181 126 189 126 194 125 196 125
+11 60 51 63 52 69 51 79 51 91 51 105 51 119 51 133 51 144 52 153 53 158 53
+18 175 189 173 189 172 189 175 189 180 188 188 187 198 186 209 184 221 182 234 180 245 178 255 177 263 176 269 175 272 174 274 174 275 175 274 175
+23 131 120 132 120 135 120 138 120 144 120 151 120 160 120 171 120 184 120 198 119 212 120 227 120 242 120 255 121 267 121 277 121 285 120 290 120 294 120 295 120 295 121 294 121 293 122
+14 55 77 55 78 56 78 60 77 65 77 73 77 80 77 88 77 94 76 99 76 103 75 104 75 105 75 104 75
+17 180 151 179 151 181 151 184 152 190 153 197 155 206 158 215 161 225 163 233 166 241 168 247 169 251 169 253 169 254 170 255 170 254 170
+16 146 104 145 104 146 104 147 104 151 104 158 104 166 103 175 103 186 102 197 100 207 99 216 97 223 97 229 96 231 96 233 96
+16 23 61 22 61 22 62 23 62 25 62 28 62 34 62 41 62 50 61 59 61 70 61 79 61 87 61 92 61 96 62 98 62
+9 B
+14 288 170 287 170 285 170 281 169 276 169 269 169 260 168 249 168 240 168 231 169 224 169 219 169 217 169 216 169
+11 234 116 232 117 229 118 224 120 218 122 210 125 202 126 194 128 187 129 182 129 179 130
+13 193 92 192 92 191 91 188 90 185 89 179 87 172 85 164 83 156 81 148 80 142 78 138 77 137 76
+11 297 167 296 167 293 167 289 167 284 166 277 166 270 166 264 165 260 165 257 165 256 164
+16 202 122 203 122 201 122 198 121 192 121 184 121 174 122 162 122 149 123 136 124 124 124 116 125 109 124 106 124 105 124 106 124
+12 126 77 125 76 122 76 118 75 113 74 107 73 100 73 94 73 88 73 84 73 81 74 79 74
+15 321 78 320 78 318 78 315 79 310 79 304 79 297 80 289 81 280 81 272 81 265 82 260 82 257 82 256 81 257 79
+16 216 128 215 128 214 128 211 128 207 127 201 126 193 126 184 125 174 125 163 124 154 124 145 123 139 123 136 122 133 122 132 121
+15 123 74 122 74 121 75 118 75 115 74 110 74 103 73 96 73 88 73 80 74 74 74 69 75 67 75 66 75 67 74
+9 N
+14 253 182 251 183 250 184 249 184 250 182 254 179 258 175 265 170 272 163 280 158 287 153 292 150 296 148 297 146
+11 185 147 185 146 185 144 187 140 190 134 194 126 199 115 205 104 212 93 217 84 221 78
+10 75 135 75 134 76 132 77 130 79 125 83 119 88 111 94 102 100 93 106 85
+10 192 172 192 171 194 169 198 165 203 160 209 153 217 146 225 139 232 132 238 126
+10 124 135 126 134 130 130 136 125 144 119 153 112 158 108 166 103 172 99 177 96
+10 49 93 47 95 46 97 47 94 50 90 54 84 59 77 67 69 73 62 78 57
+14 174 161 174 160 175 158 178 153 182 148 188 140 195 131 203 121 210 111 215 103 219 97 221 94 222 92 222 93
+11 94 120 96 118 100 113 106 106 114 99 124 89 135 80 146 72 155 66 162 61 167 58
+12 29 98 29 97 31 95 35 90 40 84 46 77 52 69 58 62 64 57 69 53 71 51 73 50
+9 P
+23 146 162 144 162 140 162 135 161 128 161 120 161 110 161 100 161 90 162 84 162 76 162 70 162 65 162 63 162 64 162 66 163 71 163 76 163 84 163 94 162 104 161 114 162 124 163
+20 243 111 244 111 243 111 242 110 238 110 234 109 227 109 220 109 211 110 202 111 194 112 187 114 183 115 181 116 183 116 187 116 194 116 203 115 213 115 222 114
+18 147 71 146 71 144 70 140 69 135 69 129 68 121 68 112 69 105 70 98 70 94 71 92 71 94 72 98 72 105 72 113 72 122 71 130 70
+21 288 147 289 147 287 147 284 147 279 147 273 149 264 151 255 154 246 157 239 159 233 161 230 162 229 162 230 162 233 162 240 161 249 160 261 157 273 155 285 152 294 150
+21 219 126 219 125 217 125 214 125 210 124 204 123 197 123 190 122 182 122 174 121 168 121 163 121 160 121 159 122 160 122 163 123 169 123 177 123 186 123 195 123 203 122
+19 137 92 136 92 134 91 130 89 126 87 121 85 114 82 107 80 101 79 96 78 92 77 90 78 91 79 94 80 98 82 104 84 111 86 118 88 123 89
+25 301 155 300 155 299 154 297 154 294 154 288 154 283 154 276 154 270 155 266 155 263 156 262 156 261 156 262 156 263 156 265 156 269 156 274 156 282 156 292 155 303 155 314 154 323 153 329 153 334 153
+24 234 117 233 117 232 117 229 116 225 115 219 115 211 116 201 117 191 118 182 119 174 120 167 121 163 121 160 122 159 122 160 122 164 121 170 120 179 119 189 118 200 117 210 117 218 118 224 118
+20 110 82 111 82 110 82 108 81 104 80 100 79 93 79 86 79 80 79 74 80 70 80 68 81 68 82 71 82 75 82 81 82 89 81 96 80 103 80 108 79
+9 R
+12 292 99 293 99 293 100 292 102 288 105 283 111 275 118 265 127 253 138 243 147 234 155 228 160
+10 227 79 229 78 230 78 229 79 226 81 222 85 217 90 210 97 202 105 195 112
+9 137 79 138 78 137 78 135 80 132 84 128 90 123 97 118 105 113 113
+13 285 79 284 80 282 82 278 85 272 91 264 98 255 107 245 116 235 126 225 134 217 140 211 144 207 147
+10 197 61 197 60 197 61 195 64 191 68 186 77 179 88 172 99 166 110 161 118
+13 123 54 123 55 121 56 118 58 114 62 109 66 103 71 97 76 92 80 89 83 87 85 86 85 87 84
+16 229 72 230 72 230 71 230 72 229 73 227 77 223 83 218 94 210 107 201 120 192 134 185 145 179 153 176 158 174 161 173 162
+14 142 94 143 94 142 94 142 95 139 97 136 100 132 105 126 111 120 117 114 123 110 127 107 129 105 130 105 129
+10 84 38 83 39 81 41 78 46 73 53 67 61 60 69 55 76 50 81 48 84
+9 S
+14 255 169 256 170 257 170 257 167 257 163 256 157 255 148 253 134 252 118 250 103 249 89 248 78 247 70 246 67
+12 213 161 213 162 212 160 211 158 210 153 209 147 208 139 207 131 206 124 205 119 205 115 205 113
+13 140 136 140 137 140 136 140 135 139 133 138 128 137 120 136 110 134 99 131 88 129 79 127 72 126 68
+12 239 158 240 160 240 161 240 158 241 153 241 145 242 134 243 120 244 108 245 98 245 90 246 85
+9 154 144 153 141 153 137 153 130 154 120 154 109 155 99 157 90 157 84
+10 82 124 82 125 82 123 82 119 82 112 83 103 83 93 84 84 85 76 85 72
+14 210 134 210 135 210 134 209 133 209 132 209 129 210 125 210 121 211 116 211 111 212 108 212 105 213 103 213 102
+16 142 121 142 122 142 121 142 119 142 116 142 109 142 100 143 89 143 76 144 64 144 53 144 46 144 40 144 36 144 34 145 33
+11 62 117 63 118 63 117 63 114 63 109 63 102 63 93 64 83 65 73 67 65 68 61
+9 U
+26 238 155 237 155 239 155 243 155 249 156 256 156 264 156 272 157 279 157 285 157 290 157 293 158 296 158 297 158 298 159 299 159 299 158 298 157 298 155 297 152 297 148 296 142 296 136 296 130 296 125 296 122
+27 125 140 122 140 120 140 121 140 124 140 128 140 135 141 144 142 153 142 162 143 171 144 179 145 185 145 189 145 191 145 193 146 193 145 192 143 192 140 191 136 191 130 191 124 191 116 192 110 194 103 195 99 195 95
+22 72 74 71 75 73 75 76 75 82 75 89 75 98 74 106 74 114 74 120 74 124 73 127 73 128 73 129 72 128 71 128 68 128 64 128 60 128 55 128 51 128 49 127 47
+29 212 183 211 183 211 184 212 184 216 184 221 184 229 184 240 184 251 184 262 184 274 184 284 184 293 183 300 183 306 183 310 182 312 183 313 183 314 183 313 182 313 180 312 178 310 174 309 169 307 163 306 157 306 152 306 148 306 146
+24 156 142 156 141 157 141 161 140 166 140 174 140 182 140 191 141 199 141 207 142 214 142 219 142 222 141 225 141 226 140 227 139 227 137 227 133 227 129 226 123 226 115 225 107 224 99 223 93
+24 47 99 46 100 46 101 48 101 52 101 58 101 65 101 75 102 83 102 90 103 96 104 100 105 103 105 104 105 104 103 103 101 102 98 102 94 101 90 100 85 100 80 100 76 100 73 100 72
+30 210 183 208 183 209 183 211 183 216 182 223 182 233 182 243 182 254 182 265 182 274 182 281 182 286 182 290 182 292 182 293 182 292 182 292 181 291 179 290 177 288 174 287 169 286 164 286 160 285 156 285 154 284 152 284 151 284 150 284 149
+27 159 120 157 121 154 122 155 121 159 121 165 120 173 119 183 118 193 118 202 118 211 118 218 118 223 118 227 118 229 118 231 118 231 119 231 118 230 116 229 113 228 108 226 101 224 93 222 86 219 80 217 76 215 73
+28 31 85 30 85 31 86 35 86 40 86 47 87 55 87 63 88 72 89 79 90 85 91 90 91 94 92 98 92 100 92 101 92 102 92 102 91 101 90 101 89 99 86 97 81 95 76 94 71 92 65 91 61 91 58 90 56
+9 V
+34 158 185 157 185 156 184 157 184 158 184 161 184 165 183 169 182 175 179 179 176 185 171 189 166 193 161 194 156 195 152 194 149 192 148 190 147 188 148 186 149 184 151 184 153 185 156 188 158 192 160 197 159 204 158 212 154 220 148 229 142 237 136 244 130 248 124 251 119
+37 104 168 105 168 106 167 107 166 110 164 113 161 117 157 120 152 123 146 125 142 126 137 126 134 125 132 124 131 123 131 122 131 121 132 120 133 119 135 118 137 118 139 119 142 120 144 123 146 127 147 131 148 135 146 139 144 143 140 146 136 148 129 151 121 152 112 154 102 155 94 155 88 155 84
+31 46 135 45 135 45 136 46 135 48 134 51 132 54 128 57 124 60 118 63 112 64 106 64 101 63 98 61 98 58 99 57 102 56 107 56 111 58 114 61 116 65 116 70 114 74 110 78 106 81 100 83 95 85 91 88 87 90 84 92 82 93 80
+38 174 186 173 184 173 183 173 182 173 181 175 181 177 181 181 180 186 177 191 174 196 170 200 166 204 161 206 157 207 153 206 150 205 148 204 147 202 146 200 147 199 147 198 148 198 150 199 151 202 153 206 153 211 153 216 151 222 148 228 143 234 137 239 129 244 121 247 113 249 110 250 104 251 101 250 101
+32 99 170 98 170 97 171 98 170 100 170 102 169 104 168 108 166 112 162 115 157 118 152 120 146 121 142 120 138 118 136 116 136 113 136 111 138 110 141 110 143 112 146 115 147 119 147 124 146 129 142 135 138 140 133 144 128 149 123 152 118 154 114 156 111
+30 39 127 38 127 37 128 38 128 39 127 41 126 43 124 46 121 49 117 52 111 54 105 56 99 55 95 54 92 52 91 50 92 48 93 47 96 47 100 48 102 51 105 56 106 61 104 69 100 76 94 82 88 87 81 91 76 94 72 96 70
+36 178 189 178 188 179 188 180 189 182 189 186 189 190 187 194 184 199 180 204 175 207 169 210 164 212 159 212 156 211 153 210 152 209 152 208 153 207 154 206 155 206 157 206 158 206 160 208 162 211 164 214 164 218 164 225 163 233 160 242 155 251 148 260 141 267 133 272 128 276 124 277 122
+40 98 162 98 159 98 158 98 157 98 156 98 157 100 157 102 158 105 158 110 158 116 158 122 156 129 153 134 149 139 144 141 139 142 135 142 130 141 127 140 126 138 125 136 125 135 125 133 126 133 128 133 130 135 131 139 131 144 130 150 127 156 122 163 115 169 106 174 97 179 87 182 78 184 70 186 65 186 61 186 59
+32 35 109 34 110 34 111 36 111 39 110 43 107 48 103 53 98 56 92 59 85 61 79 60 75 59 71 56 69 54 68 51 69 49 72 48 76 48 80 50 84 54 87 58 87 65 84 72 80 78 74 84 68 89 62 93 56 96 52 98 49 100 47 101 46
+9 W
+36 308 133 307 132 308 132 308 133 309 135 310 138 310 142 310 148 309 153 307 159 304 163 300 167 295 169 291 169 286 169 282 167 279 166 278 165 278 164 279 163 281 163 284 164 287 166 290 168 291 170 292 173 291 177 287 180 281 184 274 187 266 190 257 193 250 194 244 195 240 196 237 197
+37 234 68 234 67 235 67 236 68 236 69 236 72 237 76 237 81 236 88 235 95 232 102 228 109 223 115 218 119 213 121 209 122 205 120 203 118 202 116 202 115 203 113 206 113 209 114 211 115 214 118 216 123 217 128 215 134 211 140 206 145 199 150 191 153 183 156 174 157 167 157 160 156 156 156
+34 136 48 137 48 138 50 139 53 140 56 140 61 140 66 138 72 135 77 130 82 125 86 121 87 117 87 114 86 113 84 112 82 113 81 116 80 118 80 121 82 124 84 125 88 125 94 123 100 119 106 113 113 106 118 99 122 91 125 84 126 78 126 74 126 72 126 71 125
+37 282 80 282 79 283 80 284 80 285 82 288 85 290 90 292 96 294 102 294 109 294 115 291 121 288 125 284 127 280 129 276 129 273 129 271 128 269 128 268 127 269 126 272 126 275 127 278 128 282 131 285 134 287 139 287 143 286 148 283 152 279 156 274 158 268 161 263 163 260 164 257 164 256 164
+36 209 72 210 73 210 74 211 77 211 82 211 87 210 94 209 100 207 105 203 109 199 112 194 113 190 113 186 112 183 111 182 109 182 108 183 106 185 105 188 105 191 106 194 108 196 112 196 115 196 120 194 125 190 129 184 133 178 137 170 140 162 142 155 143 149 142 143 141 140 140 137 139
+34 98 61 98 62 99 63 100 65 101 68 103 72 103 77 103 83 102 88 99 93 95 97 90 99 86 100 83 99 80 97 79 95 79 93 80 91 83 91 85 91 87 92 90 95 91 99 91 103 89 109 84 114 78 120 71 125 63 128 55 130 48 131 43 131 39 130 37 129
+42 291 76 292 76 292 77 293 77 294 79 295 81 296 83 296 89 296 95 295 102 294 109 291 116 288 120 284 123 280 125 276 125 272 124 269 122 266 120 264 118 263 116 263 113 264 111 266 110 269 110 274 110 279 112 284 116 288 121 290 126 290 131 287 137 281 142 274 148 264 154 253 159 242 163 233 166 225 168 218 169 214 169 212 168
+36 212 63 212 62 212 63 212 64 213 65 214 68 216 72 217 77 218 80 218 85 217 90 214 95 211 98 205 101 200 103 194 103 189 103 186 102 184 101 184 100 186 98 189 97 193 97 197 99 201 102 204 106 205 111 203 117 200 122 193 128 185 133 176 138 167 142 159 144 153 146 149 146
+34 93 57 93 56 93 55 93 56 93 58 95 61 96 65 96 70 97 76 96 82 95 87 92 92 89 96 85 98 80 98 76 96 73 94 71 92 71 89 72 88 75 88 79 88 81 90 85 93 87 99 88 105 87 113 84 120 80 127 74 132 68 137 61 140 57 141 54 141
+9 X
+26 335 197 335 198 336 198 335 198 334 198 332 198 328 198 323 199 316 199 308 200 300 201 293 203 286 203 282 204 279 205 277 205 276 206 276 205 276 204 276 201 276 197 277 191 277 184 277 180 278 174 278 171
+23 234 160 234 161 234 160 232 160 229 159 225 159 218 158 211 158 202 158 193 160 185 161 178 162 173 163 170 164 168 164 168 163 167 161 167 158 167 154 167 149 168 144 168 139 169 137
+25 152 107 152 108 151 108 150 107 148 107 145 106 140 107 134 106 127 107 119 108 111 108 105 108 99 109 96 109 94 109 93 109 93 110 93 109 93 108 93 106 94 102 95 97 96 91 97 86 97 83
+25 307 74 306 74 305 74 302 73 298 73 295 72 290 72 282 72 273 71 257 72 249 72 244 72 241 72 240 72 239 72 238 72 238 71 238 70 238 68 237 65 237 61 237 55 237 51 237 47 237 46
+24 260 156 258 156 256 155 253 155 249 154 243 154 237 154 230 154 223 155 217 155 213 156 209 156 208 157 207 157 207 156 207 155 207 154 208 151 208 148 209 143 209 138 208 134 208 131 207 130
+24 134 109 133 109 133 110 131 109 129 109 126 109 121 108 115 108 108 108 100 108 93 109 88 109 83 109 80 110 79 111 78 111 79 111 79 109 80 107 81 102 82 97 83 91 84 86 84 83
+25 262 180 262 179 261 179 260 179 257 179 253 179 249 179 243 180 236 180 228 180 220 179 212 178 203 177 196 177 190 177 185 177 182 177 180 177 178 177 178 175 179 172 180 168 181 162 182 155 183 149
+24 265 97 263 97 261 98 257 98 253 98 247 98 239 98 232 98 225 99 219 99 215 100 212 101 211 102 210 102 210 101 210 100 209 98 208 94 208 88 207 82 206 76 206 70 205 67 205 65
+22 113 98 112 97 111 97 109 96 105 97 101 98 96 99 89 100 83 101 77 102 72 101 68 101 65 101 63 101 62 101 63 99 63 96 63 92 64 87 64 82 64 77 64 75
--- /dev/null
+++ b/lib/strokes/letters.clx
@@ -1,0 +1,36 @@
+a 5 0 117 27 60 61 6 86 64 108 123
+b 13 10 28 16 75 14 123 3 67 18 11 42 0 65 11 63 45 33 69 71 62 105 89 62 124 7 123
+c 5 78 23 19 17 0 81 43 126 108 105
+d 9 9 16 16 67 16 119 3 28 87 22 107 64 92 106 50 124 8 128
+e 9 95 13 67 1 37 13 28 55 68 65 23 71 20 120 61 127 103 115
+f 5 107 5 56 0 4 6 5 67 1 129
+g 11 82 18 26 10 0 69 7 99 33 124 70 124 100 96 78 76 50 76 77 74 108 69
+h 7 13 0 16 57 14 115 37 85 72 74 92 100 95 128
+i 3 50 0 56 64 58 129
+j 5 100 3 106 58 107 113 55 124 0 117
+k 5 92 0 66 66 3 93 54 88 105 128
+l 5 3 0 5 62 4 124 55 125 107 123
+m 9 0 114 4 60 24 9 41 51 48 95 59 52 83 8 102 63 108 121
+n 7 7 129 4 76 16 23 55 68 92 115 104 59 107 0
+o 7 50 4 0 74 66 124 103 88 104 43 72 8 27 12
+p 9 7 36 21 82 21 128 2 45 72 3 106 29 87 63 49 76 11 78
+q 9 41 14 1 60 23 122 55 115 74 83 72 39 36 11 68 16 108 3
+r 9 5 30 12 76 12 122 0 57 35 5 50 41 28 82 67 100 108 124
+s 7 103 13 65 2 32 33 70 67 107 101 57 128 2 111
+t 5 4 2 53 0 103 4 101 66 97 128
+u 5 0 5 12 71 57 124 104 74 105 7
+v 5 0 24 17 72 39 119 60 48 108 10
+w 9 1 14 3 69 19 123 39 99 52 70 67 95 89 119 108 64 103 5
+x 5 15 0 50 58 107 66 52 73 2 129
+y 11 10 0 4 23 15 47 44 40 73 19 85 59 87 99 58 127 20 112 56 77 104 64
+z 7 0 8 36 2 73 8 53 67 10 126 58 125 108 124
+A 3 0 66 51 63 108 61
+B 3 108 69 54 62 0 63
+N 3 0 129 48 63 108 0
+P 5 108 69 53 53 1 71 45 69 91 62
+R 3 108 0 57 63 1 128
+S 3 51 128 52 64 59 0
+U 5 0 98 53 100 106 100 106 63 103 26
+V 5 0 128 35 93 30 66 77 57 108 0
+W 5 100 0 105 47 65 62 64 110 0 128
+X 5 108 93 56 92 3 93 2 63 2 33
binary files /dev/null b/lib/strokes/punc.bit differ
--- /dev/null
+++ b/lib/strokes/punc.cl
@@ -1,0 +1,156 @@
+33
+4 !
+13 109 187 109 186 109 185 110 183 110 179 110 175 110 169 110 162 111 155 111 148 111 143 111 139 112 136
+14 37 182 37 183 36 183 36 181 36 179 36 175 36 170 36 163 35 156 35 150 35 144 35 139 36 136 36 135
+12 110 87 110 86 111 84 111 82 112 78 112 73 113 66 113 59 113 51 113 44 113 39 113 35
+15 36 89 37 89 37 88 36 86 36 83 36 79 36 74 35 67 35 59 35 52 35 46 35 42 35 39 35 38 35 37
+4 #
+44 95 125 95 124 95 123 95 125 96 128 97 133 97 139 98 145 99 150 99 154 100 156 101 155 102 152 104 148 107 143 109 137 113 132 116 127 118 123 120 120 122 117 123 116 123 115 124 115 124 116 123 117 124 119 124 121 124 124 124 129 125 134 126 139 127 144 128 148 128 152 129 156 129 159 129 162 130 163 130 165 130 164 130 163 130 160 130 156
+38 24 112 24 111 24 112 25 115 25 119 26 125 27 133 27 141 28 148 28 153 28 156 29 157 29 156 30 153 31 149 32 144 34 138 36 132 38 127 40 123 43 119 44 116 46 115 47 114 48 114 48 115 49 117 49 120 50 124 51 129 52 134 53 140 54 145 55 150 55 153 56 155 55 153 55 151
+40 92 28 92 27 92 28 92 29 92 31 93 35 93 40 93 47 93 53 93 59 93 62 94 64 95 63 97 61 99 57 101 52 104 46 107 40 111 35 113 31 116 27 118 25 120 23 120 22 121 21 121 22 121 24 121 27 122 32 122 37 122 43 123 48 124 53 125 57 125 60 126 62 126 63 127 64 126 63 126 62
+40 19 27 19 29 19 33 19 38 20 44 20 49 20 55 20 61 20 65 20 67 20 68 21 66 22 63 23 59 25 54 27 50 29 45 32 39 34 35 37 31 39 27 41 25 42 23 43 23 43 24 43 25 43 28 43 31 44 35 44 41 45 47 46 53 46 58 47 62 47 65 48 66 48 65 48 64 48 63 48 62
+4 $
+42 123 123 123 122 123 121 122 120 122 119 121 119 119 118 118 119 115 119 112 120 110 121 108 122 107 123 106 125 106 128 107 130 108 131 109 133 111 134 114 135 117 136 119 137 122 137 124 138 126 139 127 140 128 142 129 143 128 145 128 147 126 149 125 151 122 153 120 154 116 154 113 154 109 153 106 152 103 150 100 149 99 148 99 147
+38 55 117 55 116 55 115 54 114 52 114 50 114 47 115 44 115 41 117 39 118 37 120 36 122 36 124 37 125 39 127 41 128 43 129 46 130 49 131 52 132 56 133 58 134 60 135 62 137 63 139 63 142 63 144 62 146 60 147 58 148 56 149 52 150 48 150 44 150 40 149 37 149 34 148 33 147
+37 117 33 117 32 117 31 116 30 115 29 113 28 112 28 109 29 106 29 104 30 102 32 100 34 100 36 99 39 100 41 101 42 102 44 105 45 107 45 110 46 113 47 116 47 118 49 119 50 120 53 121 55 120 58 119 60 118 63 116 65 113 66 109 67 105 68 102 68 98 68 96 67 95 65
+43 43 29 44 28 44 27 44 26 43 26 43 25 41 25 39 24 37 24 35 25 32 26 30 28 28 30 26 32 25 35 24 37 25 39 25 40 27 41 29 42 31 42 33 42 36 43 39 43 41 44 44 46 46 47 48 49 49 51 50 54 50 56 49 59 48 61 46 63 44 65 41 66 37 67 34 67 31 66 28 65 26 64 25 62 25 60
+4 %
+56 26 164 25 164 26 163 27 162 28 162 30 162 32 164 35 168 37 173 40 180 41 187 42 195 41 200 40 204 38 206 37 207 36 206 35 203 35 200 35 196 37 192 40 187 43 184 47 180 51 177 55 175 58 174 61 174 63 175 65 176 66 179 68 183 69 186 70 191 71 195 70 199 70 202 69 204 67 206 66 207 64 207 64 206 63 204 63 201 63 197 65 192 67 187 70 182 73 177 77 173 80 170 84 169 87 170 89 172 91 174 92 177
+57 96 114 95 114 96 114 96 113 97 113 99 114 101 116 102 119 104 123 105 128 105 134 105 139 103 143 102 146 101 146 100 145 100 143 99 140 99 136 99 133 100 131 101 129 103 127 105 124 109 122 112 120 115 118 117 116 118 116 119 115 120 116 121 117 122 119 123 121 124 124 125 128 125 131 126 135 126 139 125 141 124 143 123 145 122 145 121 144 120 142 121 139 122 136 123 132 125 128 127 124 130 121 133 118 137 116 140 114 143 113 145 113 146 113
+52 25 90 26 90 27 90 29 90 31 93 33 97 35 102 37 108 38 114 38 120 38 124 37 126 36 126 35 125 33 122 33 119 32 115 32 112 33 109 35 106 38 103 42 100 45 98 49 96 52 95 55 94 56 94 57 96 58 97 59 100 59 103 60 106 61 109 61 113 61 116 61 119 60 121 59 122 58 122 57 121 56 119 56 116 56 113 57 110 59 107 60 104 64 101 67 97 71 95 74 93 76 92 78 92
+56 23 30 24 30 25 32 27 35 28 38 30 43 31 48 31 53 31 56 31 59 30 61 29 60 28 59 27 57 27 54 27 51 27 48 28 45 30 43 32 41 34 38 37 37 39 35 41 33 44 32 45 32 47 31 47 32 48 33 50 34 51 35 52 37 53 39 54 42 55 45 56 48 56 51 55 54 54 57 53 60 52 62 51 62 50 61 50 59 50 55 51 51 52 46 54 42 56 38 59 36 62 34 64 32 67 32 69 32 71 33 72 34
+4 &
+41 126 139 126 138 126 137 125 136 123 136 121 135 117 135 112 136 108 137 104 139 101 142 99 144 99 147 101 150 104 153 108 155 112 158 117 162 121 165 124 169 127 172 128 176 128 180 126 182 123 183 119 184 114 183 109 182 104 180 101 177 99 174 100 169 103 165 107 160 113 154 118 150 122 145 125 142 126 139 125 136 123 135
+42 51 138 51 137 51 136 50 136 49 135 48 134 46 134 43 135 39 137 36 138 33 141 32 144 32 146 33 148 35 151 38 152 42 154 46 157 50 159 53 163 55 166 56 169 55 172 53 175 49 177 46 178 42 178 39 176 37 173 36 170 36 166 38 161 41 157 44 153 48 150 52 146 54 142 55 140 55 137 53 136 51 135 48 135
+40 113 44 112 44 112 43 111 43 109 42 107 42 104 43 101 44 98 46 95 48 93 50 93 53 93 56 95 58 97 61 101 63 105 65 109 67 112 69 115 72 117 75 117 77 116 80 113 82 110 84 107 84 103 84 100 83 98 80 97 77 97 73 98 69 101 66 104 61 108 57 111 53 114 49 115 45 115 43 113 43
+40 45 40 45 39 44 39 44 38 43 37 41 36 38 37 35 37 32 39 29 41 27 43 25 46 24 49 25 51 26 53 29 55 31 56 35 58 38 60 41 62 43 65 45 68 45 71 44 75 42 78 39 79 35 80 33 79 31 77 30 74 30 70 32 65 35 61 39 56 43 53 46 49 48 46 48 43 47 41 45 41
+4 '
+12 110 132 111 134 111 137 111 141 110 147 110 154 110 161 110 166 110 171 110 174 111 175 111 176
+14 37 128 37 127 37 128 37 131 36 135 36 142 36 151 35 160 35 167 35 173 36 176 36 177 36 176 37 175
+12 109 34 110 36 110 38 110 42 111 47 111 53 111 60 111 66 111 71 111 74 111 76 111 77
+14 33 33 33 34 34 36 34 39 34 43 33 48 33 54 33 59 32 65 32 69 32 72 32 74 33 75 33 76
+4 +
+28 133 117 134 116 134 117 134 118 133 120 132 124 131 128 128 132 125 137 121 142 117 145 112 146 108 146 104 146 101 144 99 142 98 140 98 138 100 136 104 135 109 135 115 135 121 137 127 138 131 140 135 141 137 142 138 142
+28 59 115 59 114 58 114 58 115 58 116 56 118 55 122 52 126 49 130 45 135 40 139 35 142 30 144 26 145 22 144 20 144 20 142 21 140 23 138 28 137 32 137 38 137 43 139 48 142 51 144 54 147 56 148 58 149
+24 122 31 122 32 121 34 120 36 119 40 116 45 114 49 110 53 106 55 102 57 99 57 95 56 93 54 92 52 92 50 94 49 97 48 101 48 106 49 111 50 115 52 118 54 121 56 122 57
+26 47 29 48 29 47 31 47 33 45 36 43 39 40 44 36 48 32 52 28 55 24 58 20 59 17 59 16 58 15 57 16 55 18 54 21 53 25 53 30 53 34 54 39 56 43 58 46 59 49 61 51 61
+4 ,
+11 128 139 127 139 126 140 125 142 122 145 118 149 115 154 111 159 107 164 105 167 104 169
+13 54 136 54 137 54 138 54 140 53 143 52 147 51 151 49 155 46 159 43 162 40 163 38 165 37 165
+9 114 50 114 51 112 53 109 55 104 58 100 62 95 66 92 69 90 71
+11 47 45 47 46 47 47 46 49 46 52 44 56 42 60 39 65 36 69 33 71 30 74
+4 /
+10 94 185 95 183 96 180 98 175 101 169 105 162 109 155 113 149 116 145 118 143
+12 41 181 40 182 41 179 43 176 45 171 49 165 53 159 58 152 60 148 63 144 65 141 66 140
+11 98 78 98 77 99 76 100 73 102 70 106 65 109 60 113 54 117 50 120 46 122 44
+11 31 72 31 73 31 72 32 70 34 66 37 62 40 57 44 51 48 46 51 43 53 40
+4 <
+29 127 178 127 177 126 177 125 176 124 176 123 175 122 174 119 172 116 169 113 166 109 163 105 159 102 156 100 154 98 153 98 152 98 151 99 151 100 151 102 150 105 149 108 147 113 144 117 141 123 138 127 135 131 133 133 132 135 132
+23 60 173 59 172 57 171 56 169 54 168 51 166 47 163 43 160 40 157 37 155 35 154 34 153 35 154 36 154 37 153 40 152 43 151 47 148 51 146 54 144 58 141 61 140 64 139
+26 126 88 126 89 125 88 124 87 123 86 120 84 116 82 112 80 107 78 102 76 98 74 95 74 94 74 95 74 96 74 98 73 100 72 103 70 107 68 112 65 118 62 123 59 128 57 131 55 133 54 134 54
+24 50 85 49 84 48 83 47 82 45 80 42 77 38 74 33 71 28 69 24 67 21 65 19 64 20 63 22 62 26 62 30 61 36 60 42 59 49 57 55 55 60 53 63 52 65 51 66 51
+4 =
+34 97 132 97 131 98 131 100 131 103 131 107 131 112 130 118 130 123 129 126 128 128 129 129 130 129 131 127 134 125 137 122 142 118 147 115 153 111 159 108 165 105 170 103 174 101 176 101 177 101 178 103 177 106 176 110 175 115 174 121 173 126 173 131 173 134 173 136 173
+32 26 128 26 127 28 127 30 127 33 127 37 127 41 127 45 126 48 126 50 126 51 126 50 128 49 131 48 134 45 138 42 144 38 150 35 156 31 162 28 168 26 172 25 175 25 176 27 176 31 175 35 174 39 173 44 173 48 173 52 173 54 173 56 173
+31 102 36 101 36 102 35 104 35 107 34 111 34 115 33 120 32 125 32 128 32 130 33 131 34 130 37 128 40 126 45 122 49 119 54 115 59 111 64 109 67 107 70 107 72 108 73 109 73 113 72 118 71 123 70 128 69 133 69 137 69 140 69
+31 23 35 22 35 23 35 25 34 28 33 33 32 38 31 43 30 47 30 50 30 51 31 52 32 51 35 49 38 46 43 43 48 40 53 37 58 34 63 32 66 31 68 31 70 32 70 35 70 38 70 43 69 47 68 52 68 56 68 59 68 61 68
+4 @
+30 116 130 116 129 116 128 116 127 114 128 112 128 111 129 108 131 104 135 102 139 100 144 100 149 101 154 103 159 106 163 110 165 115 166 119 164 124 160 128 156 131 150 132 145 132 140 131 136 127 132 123 130 118 129 114 129 111 130 109 132
+31 51 124 51 123 50 122 50 121 49 120 48 119 45 119 42 120 39 122 36 125 33 129 30 135 29 139 29 145 30 150 33 155 37 158 41 160 46 160 52 159 56 156 60 151 63 146 64 141 64 135 63 131 60 127 56 125 52 124 49 123 46 124
+29 115 46 115 45 114 45 112 45 110 46 107 48 104 50 101 54 99 58 98 63 98 67 99 72 102 75 106 77 110 78 116 78 121 76 126 73 129 69 132 64 134 59 134 54 132 49 129 46 125 43 121 42 117 42 113 44 110 46
+30 39 40 39 39 38 39 37 39 35 40 32 41 29 42 27 45 24 48 23 52 23 57 25 61 27 66 30 69 34 71 39 71 44 70 49 67 53 63 57 58 60 54 61 50 61 46 60 42 56 40 52 38 47 38 43 38 38 40 35 42
+4 ^
+26 94 185 93 185 93 183 94 181 95 176 97 170 99 164 101 157 103 151 105 146 106 142 108 140 109 140 110 141 111 143 113 146 116 151 118 158 121 166 124 174 126 180 128 185 129 189 130 190 131 191 131 192
+21 26 165 27 162 28 158 29 154 31 149 33 143 36 138 39 134 41 130 43 127 45 126 47 127 48 129 49 132 51 137 53 144 55 150 57 156 59 160 61 164 62 166
+24 92 81 91 82 92 81 92 79 94 76 96 71 99 66 102 60 105 54 108 49 111 45 112 42 114 41 115 41 116 44 118 47 119 53 121 59 122 66 124 72 125 78 127 81 128 84 129 85
+23 22 75 21 75 22 73 23 71 24 67 27 62 29 55 33 49 36 44 39 39 41 36 43 33 45 33 46 34 46 36 47 40 49 45 51 51 53 57 54 63 56 67 58 70 59 73
+4 |
+21 89 170 89 169 88 169 88 167 88 163 88 158 89 152 89 145 89 139 89 134 89 132 88 135 88 140 87 147 87 155 87 162 87 168 87 173 87 176 87 177 86 176
+24 36 178 36 177 36 176 35 173 35 169 34 164 34 157 33 153 33 146 33 139 33 135 33 132 33 131 34 134 34 138 35 144 35 152 35 160 35 167 35 173 35 176 35 178 36 177 36 176
+21 87 82 87 81 87 79 87 74 88 69 88 62 89 55 90 48 90 42 90 38 90 37 90 40 90 44 90 51 91 59 92 66 92 73 93 79 93 83 93 85 93 84
+24 31 88 31 87 31 86 31 84 31 81 31 77 31 72 31 65 31 60 31 53 31 46 30 42 30 40 30 43 30 47 31 53 32 60 33 66 34 72 35 77 36 80 36 81 35 81 35 79
+4 ~
+40 123 121 123 120 122 120 122 122 122 126 122 131 122 137 122 144 122 152 122 159 121 166 121 170 120 174 120 175 119 175 119 173 118 169 117 164 116 158 115 151 113 144 111 137 108 132 106 128 103 125 101 124 99 125 97 125 96 126 95 128 95 130 95 133 95 138 95 144 94 150 93 157 92 163 92 167 91 170 90 171
+41 60 117 61 117 61 118 60 120 60 123 60 128 59 135 58 143 56 152 55 159 54 165 54 169 53 171 53 170 53 167 52 164 50 159 48 153 45 146 42 139 40 133 37 128 35 125 34 123 33 123 32 123 32 124 32 126 32 128 32 132 31 136 31 142 30 149 29 155 27 162 26 168 24 173 23 176 22 179 22 180 22 179
+39 121 25 120 25 120 26 120 27 120 29 119 33 118 37 117 43 116 49 115 55 114 60 113 63 113 65 112 64 112 62 111 59 110 55 108 49 105 43 103 38 101 33 98 29 97 26 95 25 94 26 93 27 93 28 92 30 92 32 92 35 92 38 92 44 91 49 91 55 90 61 90 65 89 69 89 70 88 70
+37 47 23 47 24 47 27 47 30 47 34 47 40 47 46 47 52 46 57 46 62 46 65 45 67 44 66 43 64 41 61 39 58 38 55 35 50 32 45 30 39 29 35 28 30 26 28 26 26 25 25 25 27 24 28 23 30 22 34 22 39 21 44 20 51 20 57 20 63 20 67 21 70 21 72
+4 ?
+29 29 38 28 38 27 38 27 37 27 36 28 35 29 33 32 31 36 29 40 28 45 27 49 27 53 28 56 31 57 34 57 37 56 41 54 45 51 49 48 53 44 57 42 61 39 65 38 68 38 71 38 73 38 76 38 77 39 77
+30 95 36 94 36 93 36 93 35 93 34 94 32 95 30 96 28 99 26 102 25 106 25 110 26 113 28 115 30 116 33 116 36 114 40 113 44 111 48 109 51 107 54 106 57 106 59 107 62 107 66 107 69 108 71 108 73 108 74 108 75
+26 35 134 34 133 33 132 33 130 34 129 35 127 38 125 42 124 46 123 50 122 54 122 57 123 59 125 59 128 59 131 58 135 56 139 53 142 51 146 50 150 49 153 49 157 49 159 49 162 49 163 49 165
+31 99 139 99 140 99 139 99 138 99 137 99 135 99 132 100 130 101 127 104 125 107 123 110 122 114 122 118 122 120 124 122 127 123 130 122 134 121 138 119 142 117 146 115 150 114 153 113 157 112 160 112 163 112 166 112 168 113 170 113 171 114 172
+4 >
+26 25 92 25 93 26 92 28 90 31 87 34 84 38 81 43 77 47 75 51 72 54 70 55 69 56 69 56 68 55 68 54 67 51 66 49 64 45 62 40 60 35 59 29 57 25 55 21 55 20 55 21 55
+25 96 100 95 101 96 100 98 99 101 97 105 94 110 92 113 90 118 87 122 85 125 83 127 82 127 81 126 80 125 80 124 80 123 80 120 79 117 77 113 75 109 73 103 71 99 68 95 65 92 64
+30 32 184 31 184 32 184 33 182 36 180 40 177 46 174 52 170 59 166 66 163 71 161 74 160 75 159 74 159 73 160 72 160 70 160 69 160 67 160 66 158 63 156 59 154 56 152 51 149 47 147 42 146 39 145 36 145 35 146 36 147
+28 108 197 107 198 108 198 109 198 112 196 116 194 121 191 126 187 132 184 136 182 139 180 141 180 142 179 141 180 141 181 140 181 139 181 138 181 137 180 135 178 133 176 130 174 126 170 122 167 117 163 114 159 110 157 108 156
+4 )
+16 27 28 28 29 29 30 32 32 35 35 38 41 41 48 42 56 42 63 41 69 39 74 37 77 35 79 33 81 32 81 31 81
+14 91 28 91 29 93 30 96 32 99 35 103 39 105 46 106 54 105 61 104 68 101 74 99 78 96 80 94 82
+17 34 124 33 124 34 124 36 125 39 127 42 131 46 137 49 144 51 151 52 158 51 165 50 170 48 173 46 175 44 176 42 177 41 177
+18 98 128 97 127 97 128 98 129 101 132 104 135 108 140 111 146 113 152 114 157 114 164 112 170 108 176 105 180 101 184 98 186 96 187 94 188
+8 (
+117 159 21 158 22 158 23 157 24 156 24 156 25 156 26 155 26 155 27 154 27 154 28 153 28 153 29 153 30 152 30 152 31 151 32 151 33 150 33 150 34 150 35 149 36 148 37 148 38 147 39 147 40 146 41 146 42 146 43 145 44 145 45 144 46 144 47 144 48 144 49 144 50 143 50 143 51 143 52 143 51 143 52 143 53 142 53 142 54 142 55 142 56 142 57 142 58 141 59 141 60 141 61 141 62 141 63 141 64 140 64 140 65 140 66 140 67 140 68 140 69 140 70 140 71 140 72 140 73 140 74 140 75 140 76 140 77 141 78 141 79 141 80 141 81 141 82 142 83 142 84 142 85 142 86 143 86 143 87 143 88 144 89 144 90 144 91 145 92 145 93 145 94 146 94 146 95 146 96 147 96 147 97 148 97 148 98 149 99 149 100 150 100 150 101 151 101 151 102 152 103 152 104 153 104 153 105 153 106 154 106 154 107 155 107 156 107 156 108 157 108 157 109 158 109 158 110 159 110 159 111 160 111 160 112
+101 63 19 63 20 62 20 62 21 62 22 61 22 61 23 60 23 60 24 60 25 59 25 59 26 58 26 58 27 58 28 57 28 57 29 57 30 56 30 56 31 56 32 55 32 55 33 55 34 54 34 54 35 54 36 53 37 53 38 52 38 52 39 52 40 52 41 51 41 51 42 51 43 51 44 51 45 51 46 51 47 50 47 50 48 50 49 50 50 50 51 50 52 50 53 50 54 50 55 50 56 50 57 50 58 50 59 50 60 50 61 50 62 50 63 50 64 50 65 50 66 50 67 50 68 50 69 50 70 50 71 50 72 50 73 50 74 51 74 51 75 51 76 52 77 52 78 52 79 53 80 54 81 54 82 55 82 55 83 56 84 57 85 57 86 58 86 58 87 59 88 60 89 60 90 61 90 61 91 63 92 64 93 65 93 65 94 66 94 67 94 68 94 68 95 69 95 70 95 70 96 71 96
+15 39 27 38 27 38 26 36 27 35 27 33 29 30 32 28 38 26 45 25 53 26 60 27 67 28 72 31 75 32 77
+13 113 27 112 27 110 28 108 30 105 34 102 40 99 48 98 57 97 66 98 73 99 77 101 80 103 81
+16 46 124 45 123 44 123 43 123 41 125 38 127 35 131 32 137 29 144 27 152 27 160 28 166 30 172 33 176 35 177 37 178
+17 113 128 113 127 112 127 111 127 109 128 107 131 104 136 101 142 99 150 98 159 98 166 98 173 100 177 102 180 105 182 106 183 107 183
+40 50 24 50 25 49 26 49 27 49 28 49 29 49 30 49 32 47 33 47 35 45 37 45 40 44 42 43 45 43 47 43 50 43 52 43 54 43 55 43 57 43 59 43 60 43 61 44 63 43 61 44 63 45 64 45 65 47 66 47 67 48 68 49 69 50 69 51 70 52 71 53 71 53 72 54 72 55 72 55 73
+40 140 25 139 27 138 28 137 29 135 31 134 33 133 34 132 36 131 37 129 39 128 41 126 44 124 46 122 49 121 51 119 53 118 55 117 58 116 60 115 63 115 65 115 68 115 71 115 73 116 75 117 78 118 80 119 82 121 83 122 85 124 87 125 89 127 90 128 91 129 92 130 92 131 93 132 93 133 93 133 94
+4 .
+21 133 137 133 138 132 138 130 139 126 139 122 139 116 139 109 139 103 140 98 141 94 142 91 143 92 143 95 142 100 141 107 140 115 139 124 138 131 138 137 138 140 138
+21 61 137 61 136 60 135 58 135 55 134 51 134 46 134 41 136 36 137 32 139 29 140 29 141 30 140 34 140 40 139 46 138 53 138 59 138 65 138 68 137 70 138
+19 126 50 125 50 124 50 122 51 119 51 115 51 111 51 105 52 99 52 95 53 92 53 91 53 92 54 96 54 101 53 106 53 112 52 116 52 120 52
+18 56 54 54 54 53 54 50 54 46 54 41 55 37 55 33 56 30 56 29 56 30 57 32 57 35 57 39 57 43 57 47 57 50 57 52 57
+4 -
+12 87 151 88 151 91 151 96 151 103 150 111 150 118 150 124 149 129 149 132 150 134 150 133 151
+12 23 131 22 131 23 131 25 131 29 130 34 129 41 129 49 129 57 129 65 130 70 130 74 131
+12 108 62 107 62 105 62 107 62 111 62 116 62 123 62 131 61 139 61 146 61 151 60 153 60
+14 27 60 25 60 24 60 23 60 25 59 27 59 33 59 40 58 47 58 56 57 63 57 70 57 74 57 76 57
+4 T
+68 39 103 39 102 39 101 39 100 39 99 39 100 39 99 39 98 38 97 38 95 38 94 38 92 38 91 37 89 37 88 37 87 37 85 37 84 37 83 37 81 37 80 37 79 37 78 37 77 37 75 37 74 37 73 37 72 37 71 37 70 37 69 37 68 37 67 37 66 37 65 37 64 37 63 38 62 38 61 38 60 38 59 38 58 38 57 38 56 38 55 38 54 38 53 39 53 40 53 42 53 44 53 46 53 49 53 51 54 53 54 55 54 57 54 59 54 61 54 62 54 63 54 64 54 65 53 66 53 67 53 68 53 69 53 70 53
+45 112 99 112 98 112 97 112 95 112 93 112 91 112 87 111 84 111 81 111 77 110 74 111 77 110 74 110 72 110 69 110 68 110 66 110 65 110 63 110 62 110 61 110 59 110 58 110 56 110 55 110 54 110 53 111 53 114 54 116 54 120 55 123 55 125 55 128 55 130 55 132 55 133 55 134 55 136 55 137 55 138 55 139 55 140 55 141 55 142 55
+57 32 191 32 190 33 189 33 187 33 185 33 183 34 181 34 179 34 177 34 175 34 173 34 170 34 169 34 167 34 165 34 164 34 163 34 162 34 160 34 159 34 158 34 157 34 156 35 156 35 155 35 154 35 153 35 152 35 151 36 151 36 150 36 149 36 148 37 147 37 146 37 145 38 145 38 144 39 144 41 144 43 145 46 145 50 145 54 145 58 145 61 145 64 145 65 145 66 145 67 145 68 145 69 145 70 145 71 145 72 144 73 144 74 144
+51 108 190 108 189 108 187 107 185 107 183 107 181 107 179 107 177 107 175 107 173 107 171 107 173 107 171 107 169 107 167 107 165 108 163 108 161 108 159 108 158 108 156 108 155 108 154 108 153 108 152 108 151 108 150 109 149 109 148 109 147 109 146 109 145 109 144 109 143 110 143 110 142 110 141 110 140 110 139 111 138 112 138 114 138 117 138 121 138 125 138 129 139 133 139 137 139 140 139 142 139 143 139
+4 _
+69 17 55 18 55 19 55 20 55 22 55 23 55 26 55 28 55 31 55 34 56 37 56 40 57 43 57 46 57 48 58 50 58 52 58 53 58 54 58 55 57 56 57 57 57 58 57 59 57 60 57 61 57 63 57 65 57 67 56 69 56 71 56 71 57 70 57 69 57 67 57 64 57 62 57 58 57 56 57 54 57 52 57 50 57 49 57 48 57 47 57 46 57 45 57 44 58 42 58 41 58 40 58 41 58 40 58 39 58 38 58 37 58 36 58 35 58 34 58 32 58 31 58 31 59 30 59 29 59 28 59 27 59 26 59 25 59 24 59
+44 98 78 99 78 101 78 104 78 107 78 110 78 114 78 121 78 125 78 128 78 131 78 133 78 135 78 137 78 138 78 139 78 138 78 137 78 136 78 134 78 131 78 129 78 126 78 124 79 122 79 120 79 117 79 115 78 113 78 111 78 110 78 108 78 108 79 107 79 106 79 105 79 104 79 103 79 102 79 101 79 100 79 99 79 98 79 97 79
+26 21 124 22 124 24 124 28 125 32 125 39 125 46 126 59 126 69 126 76 127 80 127 83 127 84 127 85 127 85 128 84 128 80 128 76 128 66 128 59 127 52 127 45 126 41 125 38 125 35 124 34 124
+36 86 165 86 164 87 164 89 164 91 164 93 163 96 163 99 164 102 164 106 164 109 163 106 164 109 163 112 164 116 164 120 164 123 164 125 164 126 164 126 165 125 165 123 165 122 165 120 165 118 165 116 165 114 165 112 165 109 165 102 164 95 163 88 163 84 162 82 162 80 162 81 162
+2 *
+57 35 128 35 129 38 131 41 134 44 137 46 139 49 141 51 143 53 145 56 147 60 148 63 149 66 150 69 150 73 149 76 147 79 146 81 143 83 141 85 139 86 137 87 135 87 134 87 133 86 133 86 132 85 132 83 132 82 133 79 133 76 134 73 135 69 135 67 136 63 137 61 138 59 139 58 139 57 140 55 141 54 142 53 143 51 145 50 146 49 147 48 148 47 149 46 150 45 152 43 153 41 155 39 157 38 158 37 159 36 160 35 161 34 162
+56 26 38 26 39 26 40 26 41 26 43 27 46 27 49 28 52 29 55 30 57 31 60 33 63 35 66 37 68 39 70 43 71 47 72 51 73 58 73 65 73 68 73 71 72 73 71 75 69 76 68 77 66 77 65 78 65 78 64 77 63 76 63 75 62 75 63 73 63 71 63 68 64 65 65 62 65 59 66 56 67 53 68 51 69 48 70 46 71 45 72 43 73 41 74 40 75 39 76 38 77 37 78 35 79 34 81 33 81 33 82 33 83
+2 `
+33 90 187 90 186 90 185 89 185 89 184 89 183 88 181 87 180 86 178 85 175 83 172 82 169 80 165 77 161 75 157 73 154 71 151 70 148 69 147 68 145 67 145 66 145 67 145 67 148 69 151 72 155 75 162 78 169 81 176 83 180 84 183 85 184 85 185
+37 69 103 69 102 69 101 68 101 67 99 67 98 66 96 65 94 65 92 64 90 62 87 61 84 60 81 59 78 59 75 58 73 58 70 57 68 57 67 57 66 57 67 58 68 59 70 60 72 62 76 64 79 66 83 68 86 69 89 70 92 71 94 72 96 73 98 74 99 75 100 75 101 76 102
+2 ;
+40 113 53 113 54 113 56 111 59 109 63 107 66 105 70 103 73 101 77 99 81 97 84 95 86 93 88 92 90 91 91 89 93 88 94 88 95 87 95 87 94 88 93 89 92 90 90 92 88 93 85 95 82 97 79 99 75 101 72 103 69 104 66 105 64 105 63 106 62 107 61 108 60 109 58 111 57 112 55 113 54
+34 71 32 71 33 71 34 69 36 67 39 64 42 61 46 57 50 53 54 50 58 48 61 47 64 46 66 45 68 46 67 47 67 47 66 48 64 49 62 50 59 52 57 54 54 56 51 59 47 61 45 64 42 67 39 71 37 78 34 82 32 86 30 89 28 91 27 93 25
+2 :
+32 100 31 101 32 101 34 102 37 102 40 103 44 104 48 104 55 105 59 106 63 106 66 107 68 107 70 107 71 108 72 108 73 107 73 107 72 107 71 107 69 108 67 108 65 108 62 108 59 108 56 108 52 108 48 109 45 109 42 108 40 108 39 107 39
+35 36 26 36 27 36 28 36 30 37 33 37 37 38 41 38 48 38 55 38 59 39 63 39 66 39 69 39 72 38 73 38 74 39 73 39 72 39 69 40 65 41 61 41 57 42 50 42 46 43 39 43 35 43 32 43 29 43 27 43 26 43 27 43 26 43 25 43 26 43 27
+3 F
+12 184 33 183 32 183 31 185 33 187 36 189 41 192 47 195 55 198 62 200 67 203 72 205 74
+14 112 34 111 33 112 33 113 34 114 38 117 43 120 50 122 57 125 64 128 69 129 72 131 74 132 75 132 74
+13 43 37 42 37 42 39 44 41 47 45 49 50 53 56 56 61 59 67 62 70 63 73 64 74 65 74
+3 G
+41 219 44 219 43 218 42 217 41 216 40 215 40 214 39 212 39 211 40 209 41 206 42 203 44 201 47 198 50 196 54 195 58 195 63 196 66 199 69 201 71 205 72 208 72 211 72 212 71 213 71 213 70 211 71 209 71 206 73 202 75 199 77 196 80 194 83 194 87 194 91 196 94 199 96 203 98 207 98 211 98 215 97
+40 145 43 145 42 145 40 144 39 142 38 139 38 136 39 132 41 128 44 124 47 121 51 120 54 119 58 120 61 122 64 124 65 127 66 129 66 131 65 133 64 134 63 134 62 133 61 132 61 130 62 128 63 125 65 122 67 119 70 117 73 116 76 117 80 118 83 121 86 124 87 129 88 134 87 138 86 142 85 145 84
+43 62 44 62 43 63 43 63 42 63 41 62 40 61 38 60 37 58 37 55 37 52 39 49 41 46 43 44 47 42 51 41 56 41 61 42 65 44 68 46 71 48 72 50 72 52 71 53 70 54 69 53 68 53 67 51 67 50 67 48 68 45 70 43 72 41 74 38 80 38 84 39 87 41 90 44 93 48 94 52 94 56 93 60 91 63 90
+3 H
+41 215 55 214 55 213 54 214 53 215 51 217 50 219 48 223 46 227 45 230 45 234 47 236 50 238 54 237 59 235 63 232 67 228 70 225 73 223 74 222 75 221 75 222 75 223 74 226 74 228 74 231 75 234 76 237 79 239 82 240 85 240 89 239 92 237 95 233 97 230 99 224 100 219 101 213 101 208 100 204 98 201 96
+40 135 54 134 54 133 54 134 53 135 52 137 50 140 49 144 48 148 49 152 50 155 53 157 56 157 60 156 64 154 68 151 71 149 73 146 75 144 76 143 77 143 76 144 76 146 75 148 75 150 76 153 77 155 78 157 80 158 83 159 85 158 88 157 90 154 93 152 94 148 95 144 96 139 96 135 96 131 95 128 94
+41 52 52 52 51 51 51 52 50 52 49 53 47 55 45 57 44 60 43 64 44 68 45 72 48 74 50 75 54 74 56 73 59 71 62 68 64 66 66 65 67 65 68 66 68 67 68 69 67 71 68 72 69 74 71 76 74 78 77 79 81 79 84 78 87 75 89 72 91 67 93 62 94 55 94 50 94 45 93 42 91 41 90
+3 I
+50 223 96 224 96 224 97 223 98 222 99 221 101 219 102 216 104 214 106 210 106 207 106 203 104 199 103 195 101 192 98 189 96 187 93 186 90 186 87 188 85 190 84 194 83 198 82 202 82 205 83 208 83 210 84 211 84 211 85 210 85 209 85 207 85 204 85 200 84 196 84 190 83 185 83 180 82 177 81 174 79 174 76 176 73 180 70 185 67 191 63 197 61 202 59 207 59 210 59 211 60
+50 152 94 152 95 151 96 149 98 147 99 144 100 139 102 134 104 128 105 122 105 118 104 114 102 112 100 111 97 111 94 113 91 115 88 118 85 121 83 125 82 128 81 131 81 133 82 135 83 136 84 136 85 136 86 135 86 134 87 133 86 131 86 128 85 124 84 121 82 117 80 113 79 109 76 106 74 103 72 102 70 103 69 105 67 109 64 114 62 121 60 128 57 134 56 139 56 142 56 145 57
+47 64 95 64 96 64 97 63 97 62 99 60 100 57 101 54 101 50 102 46 101 42 100 38 98 35 96 32 92 31 89 31 86 32 83 35 80 37 79 41 78 46 77 50 77 54 78 56 79 57 79 58 80 57 80 56 80 54 80 51 79 47 78 44 77 39 75 36 73 32 70 30 67 29 64 29 61 30 57 34 54 39 51 44 50 50 49 56 49 61 51 65 52 67 54
+3 J
+52 208 104 207 104 206 104 206 105 207 106 209 107 212 108 216 109 221 109 226 109 231 108 235 106 239 104 241 101 243 98 243 95 242 92 239 90 235 88 231 87 227 87 223 88 220 88 218 89 217 89 217 90 218 90 220 90 222 90 225 90 227 89 231 88 234 87 237 86 239 84 242 82 243 79 245 76 245 72 244 68 241 64 238 60 233 58 226 56 219 56 213 58 207 60 204 63 202 67 202 70 203 72 206 74
+48 126 101 124 100 123 100 122 100 121 101 122 101 123 102 125 103 128 104 132 104 138 103 143 101 148 99 153 96 156 93 157 89 158 87 157 84 155 82 151 80 149 79 145 79 142 79 139 79 137 79 135 79 136 79 137 79 140 78 144 78 147 77 152 75 156 73 159 71 161 69 163 66 163 64 163 60 161 56 158 53 154 50 151 49 145 48 139 48 133 49 128 51 124 53 122 55
+49 42 95 41 96 40 97 41 98 42 100 43 101 46 102 49 103 53 103 58 103 62 102 67 100 71 97 73 94 75 90 75 87 75 84 73 82 71 80 68 78 65 78 63 77 60 77 58 78 57 78 56 78 56 79 57 79 58 79 60 78 63 77 66 76 70 75 73 72 75 71 77 68 78 65 77 62 76 59 73 56 70 54 66 52 61 51 56 50 52 51 47 51 45 52 44 52 44 53
+3 K
+35 200 146 199 145 199 144 198 142 198 140 197 136 197 131 197 127 197 122 197 117 197 114 197 112 198 112 199 114 201 117 203 121 206 126 209 131 213 137 217 141 220 144 224 145 227 146 229 145 230 144 231 143 231 141 232 138 231 135 231 130 230 124 230 118 229 112 228 108 227 104
+35 137 85 137 84 137 82 137 80 136 77 136 73 136 67 135 61 135 54 135 49 135 44 135 42 136 41 137 43 139 46 141 50 144 56 147 63 151 69 155 75 158 80 161 82 164 83 166 84 167 82 169 80 170 76 171 71 171 65 171 57 171 49 171 42 171 36 170 32 170 30
+37 44 83 44 84 43 83 43 81 43 78 42 74 42 69 41 63 41 57 40 52 39 48 39 45 39 44 40 45 41 47 43 51 46 55 50 60 53 66 57 70 60 73 63 75 65 77 66 77 67 77 68 76 69 74 69 73 69 69 69 65 68 59 68 53 67 46 67 39 67 34 67 31 67 29
--- /dev/null
+++ b/lib/strokes/punc.clx
@@ -1,0 +1,33 @@
+! 3 54 128 53 64 55 0
+# 7 0 12 6 61 14 110 43 62 83 14 97 64 108 116
+$ 7 85 14 50 3 15 33 69 62 104 103 56 127 3 116
+% 9 0 30 20 63 15 96 20 61 55 41 69 69 64 97 70 59 108 38
+& 9 82 9 48 4 20 30 58 67 89 111 47 126 33 85 67 47 81 7
+' 3 53 0 54 64 54 128
++ 5 105 12 69 86 1 102 50 86 108 116
+, 3 108 0 63 70 0 128
+/ 3 10 128 49 64 98 0
+< 5 83 128 43 92 2 60 53 30 107 0
+= 7 0 10 41 3 83 3 51 64 14 126 60 121 108 120
+@ 7 54 10 0 67 55 122 96 89 107 46 82 8 39 11
+^ 5 0 122 21 60 59 2 85 62 108 126
+| 5 54 128 52 64 51 1 53 63 58 126
+~ 7 101 0 96 57 87 115 61 62 31 12 15 70 7 129
+? 5 18 34 44 2 88 9 69 69 57 128
+> 5 6 128 54 93 103 60 55 27 3 0
+) 3 34 0 75 64 44 128
+( 3 76 0 35 65 64 128
+. 5 108 57 54 58 0 70 52 68 106 65
+- 3 0 67 54 63 108 63
+T 5 3 128 1 72 4 15 51 2 108 1
+_ 5 0 62 54 63 108 64 58 65 8 64
+* 5 0 14 43 80 108 58 58 66 9 114
+` 5 79 128 51 64 25 1 55 61 83 121
+; 5 83 13 45 71 3 124 45 60 108 3
+: 5 40 0 51 65 58 127 65 71 67 12
+F 3 19 0 54 64 90 128
+G 9 91 13 89 6 81 1 28 33 55 73 36 78 20 109 51 128 88 122
+H 9 35 19 54 0 82 5 93 36 67 66 100 91 78 124 43 128 8 120
+I 9 108 104 60 126 18 92 44 69 77 71 38 66 0 39 44 7 94 3
+J 9 8 115 51 126 92 95 75 75 50 72 95 51 84 8 45 1 7 18
+K 7 12 128 4 80 4 33 44 84 96 119 105 60 100 0
--- /dev/null
+++ b/lib/tbsetup
@@ -1,0 +1,22 @@
+#
+# This file defines the format of the toolbar
+#
+#The entries are 2 ":" separated fields
+#<Button Label/Bitmap>:<application path>
+!EXEC=/dis/plumber.dis -w
+!EXEC=/dis/svc/cs/cs.dis
+!EXEC=/dis/dbfs.dis -e /data/vmails /mnt/vmail
+!EXEC=/dis/dbfs.dis -e /data/incalls /mnt/incall
+!EXEC=/dis/wm/sword/answerphone.dis
+!EXEC=/dis/wm/sword/vmail_led.dis /mnt/vmail /cvt/cons/0/ctl
+!NELEMS=7
+!HEIGHT=44
+phone:Virtual Phonepad:/dis/wm/sword/phonepad.dis
+www:HTML Browser:/dis/charon.dis
+mail:Mail:/dis/wm/mailtool.dis
+config:Configuration:/dis/wm/sword/config.dis
+addr:PIM:/dis/wm/sword/addrbook.dis
+shell:Shell:/dis/wm/sh.dis
+sds:SDS:/sds/dis/sdc.dis
+calls:Call History:/dis/wm/sword/callhist.dis
+vmails:Voice Mail:/dis/wm/sword/vmail.dis
--- /dev/null
+++ b/lib/unicode
@@ -1,0 +1,6588 @@
+0000 null
+0001 start of heading
+0002 start of text
+0003 end of text
+0004 end of transmission
+0005 enquiry
+0006 acknowledge
+0007 bell
+0008 backspace
+0009 horizontal tabulation
+000a line feed
+000b vertical tabulation
+000c form feed
+000d carriage return
+000e shift out
+000f shift in
+0010 data link escape
+0011 device control one
+0012 device control two
+0013 device control three
+0014 device control four
+0015 negative acknowledge
+0016 synchronous idle
+0017 end of transmission block
+0018 cancel
+0019 end of medium
+001a substitute
+001b escape
+001c file separator
+001d group separator
+001e record separator
+001f unit separator
+0020 space
+0021 exclamation mark
+0022 quotation mark
+0023 number sign
+0024 dollar sign
+0025 percent sign
+0026 ampersand
+0027 apostrophe
+0028 left parenthesis
+0029 right parenthesis
+002a asterisk
+002b plus sign
+002c comma
+002d hyphen-minus
+002e full stop
+002f solidus
+0030 digit zero
+0031 digit one
+0032 digit two
+0033 digit three
+0034 digit four
+0035 digit five
+0036 digit six
+0037 digit seven
+0038 digit eight
+0039 digit nine
+003a colon
+003b semicolon
+003c less-than sign
+003d equals sign
+003e greater-than sign
+003f question mark
+0040 commercial at
+0041 latin capital letter a
+0042 latin capital letter b
+0043 latin capital letter c
+0044 latin capital letter d
+0045 latin capital letter e
+0046 latin capital letter f
+0047 latin capital letter g
+0048 latin capital letter h
+0049 latin capital letter i
+004a latin capital letter j
+004b latin capital letter k
+004c latin capital letter l
+004d latin capital letter m
+004e latin capital letter n
+004f latin capital letter o
+0050 latin capital letter p
+0051 latin capital letter q
+0052 latin capital letter r
+0053 latin capital letter s
+0054 latin capital letter t
+0055 latin capital letter u
+0056 latin capital letter v
+0057 latin capital letter w
+0058 latin capital letter x
+0059 latin capital letter y
+005a latin capital letter z
+005b left square bracket
+005c reverse solidus
+005d right square bracket
+005e circumflex accent
+005f low line
+0060 grave accent
+0061 latin small letter a;0041
+0062 latin small letter b;0042
+0063 latin small letter c;0043
+0064 latin small letter d;0044
+0065 latin small letter e;0045
+0066 latin small letter f;0046
+0067 latin small letter g;0047
+0068 latin small letter h;0048
+0069 latin small letter i;0049
+006a latin small letter j;004a
+006b latin small letter k;004b
+006c latin small letter l;004c
+006d latin small letter m;004d
+006e latin small letter n;004e
+006f latin small letter o;004f
+0070 latin small letter p;0050
+0071 latin small letter q;0051
+0072 latin small letter r;0052
+0073 latin small letter s;0053
+0074 latin small letter t;0054
+0075 latin small letter u;0055
+0076 latin small letter v;0056
+0077 latin small letter w;0057
+0078 latin small letter x;0058
+0079 latin small letter y;0059
+007a latin small letter z;005a
+007b left curly bracket
+007c vertical line
+007d right curly bracket
+007e tilde
+007f <control>
+0080 <control>
+0081 <control>
+0082 <control>
+0083 <control>
+0084 <control>
+0085 <control>
+0086 <control>
+0087 <control>
+0088 <control>
+0089 <control>
+008a <control>
+008b <control>
+008c <control>
+008d <control>
+008e <control>
+008f <control>
+0090 <control>
+0091 <control>
+0092 <control>
+0093 <control>
+0094 <control>
+0095 <control>
+0096 <control>
+0097 <control>
+0098 <control>
+0099 <control>
+009a <control>
+009b <control>
+009c <control>
+009d <control>
+009e <control>
+009f <control>
+00a0 no-break space
+00a1 inverted exclamation mark
+00a2 cent sign
+00a3 pound sign
+00a4 currency sign
+00a5 yen sign
+00a6 broken bar
+00a7 section sign
+00a8 diaeresis
+00a9 copyright sign
+00aa feminine ordinal indicator
+00ab left-pointing double angle quotation mark
+00ac not sign
+00ad soft hyphen
+00ae registered sign
+00af macron
+00b0 degree sign
+00b1 plus-minus sign
+00b2 superscript two
+00b3 superscript three
+00b4 acute accent
+00b5 micro sign
+00b6 pilcrow sign
+00b7 middle dot
+00b8 cedilla
+00b9 superscript one
+00ba masculine ordinal indicator
+00bb right-pointing double angle quotation mark
+00bc vulgar fraction one quarter
+00bd vulgar fraction one half
+00be vulgar fraction three quarters
+00bf inverted question mark
+00c0 latin capital letter a with grave
+00c1 latin capital letter a with acute
+00c2 latin capital letter a with circumflex
+00c3 latin capital letter a with tilde
+00c4 latin capital letter a with diaeresis
+00c5 latin capital letter a with ring above
+00c6 latin capital letter ae
+00c7 latin capital letter c with cedilla
+00c8 latin capital letter e with grave
+00c9 latin capital letter e with acute
+00ca latin capital letter e with circumflex
+00cb latin capital letter e with diaeresis
+00cc latin capital letter i with grave
+00cd latin capital letter i with acute
+00ce latin capital letter i with circumflex
+00cf latin capital letter i with diaeresis
+00d0 latin capital letter eth
+00d1 latin capital letter n with tilde
+00d2 latin capital letter o with grave
+00d3 latin capital letter o with acute
+00d4 latin capital letter o with circumflex
+00d5 latin capital letter o with tilde
+00d6 latin capital letter o with diaeresis
+00d7 multiplication sign
+00d8 latin capital letter o with stroke
+00d9 latin capital letter u with grave
+00da latin capital letter u with acute
+00db latin capital letter u with circumflex
+00dc latin capital letter u with diaeresis
+00dd latin capital letter y with acute
+00de latin capital letter thorn
+00df latin small letter sharp s
+00e0 latin small letter a with grave;00c0
+00e1 latin small letter a with acute;00c1
+00e2 latin small letter a with circumflex;00c2
+00e3 latin small letter a with tilde;00c3
+00e4 latin small letter a with diaeresis;00c4
+00e5 latin small letter a with ring above;00c5
+00e6 latin small letter ae;00c6
+00e7 latin small letter c with cedilla;00c7
+00e8 latin small letter e with grave;00c8
+00e9 latin small letter e with acute;00c9
+00ea latin small letter e with circumflex;00ca
+00eb latin small letter e with diaeresis;00cb
+00ec latin small letter i with grave;00cc
+00ed latin small letter i with acute;00cd
+00ee latin small letter i with circumflex;00ce
+00ef latin small letter i with diaeresis;00cf
+00f0 latin small letter eth;00d0
+00f1 latin small letter n with tilde;00d1
+00f2 latin small letter o with grave;00d2
+00f3 latin small letter o with acute;00d3
+00f4 latin small letter o with circumflex;00d4
+00f5 latin small letter o with tilde;00d5
+00f6 latin small letter o with diaeresis;00d6
+00f7 division sign
+00f8 latin small letter o with stroke;00d8
+00f9 latin small letter u with grave;00d9
+00fa latin small letter u with acute;00da
+00fb latin small letter u with circumflex;00db
+00fc latin small letter u with diaeresis;00dc
+00fd latin small letter y with acute;00dd
+00fe latin small letter thorn;00de
+00ff latin small letter y with diaeresis;0178
+0100 latin capital letter a with macron
+0101 latin small letter a with macron;0100
+0102 latin capital letter a with breve
+0103 latin small letter a with breve;0102
+0104 latin capital letter a with ogonek
+0105 latin small letter a with ogonek;0104
+0106 latin capital letter c with acute
+0107 latin small letter c with acute;0106
+0108 latin capital letter c with circumflex
+0109 latin small letter c with circumflex;0108
+010a latin capital letter c with dot above
+010b latin small letter c with dot above;010a
+010c latin capital letter c with caron
+010d latin small letter c with caron;010c
+010e latin capital letter d with caron
+010f latin small letter d with caron;010e
+0110 latin capital letter d with stroke
+0111 latin small letter d with stroke;0110
+0112 latin capital letter e with macron
+0113 latin small letter e with macron;0112
+0114 latin capital letter e with breve
+0115 latin small letter e with breve;0114
+0116 latin capital letter e with dot above
+0117 latin small letter e with dot above;0116
+0118 latin capital letter e with ogonek
+0119 latin small letter e with ogonek;0118
+011a latin capital letter e with caron
+011b latin small letter e with caron;011a
+011c latin capital letter g with circumflex
+011d latin small letter g with circumflex;011c
+011e latin capital letter g with breve
+011f latin small letter g with breve;011e
+0120 latin capital letter g with dot above
+0121 latin small letter g with dot above;0120
+0122 latin capital letter g with cedilla
+0123 latin small letter g with cedilla;0122
+0124 latin capital letter h with circumflex
+0125 latin small letter h with circumflex;0124
+0126 latin capital letter h with stroke
+0127 latin small letter h with stroke;0126
+0128 latin capital letter i with tilde
+0129 latin small letter i with tilde;0128
+012a latin capital letter i with macron
+012b latin small letter i with macron;012a
+012c latin capital letter i with breve
+012d latin small letter i with breve;012c
+012e latin capital letter i with ogonek
+012f latin small letter i with ogonek;012e
+0130 latin capital letter i with dot above
+0131 latin small letter dotless i;0049
+0132 latin capital ligature ij
+0133 latin small ligature ij;0132
+0134 latin capital letter j with circumflex
+0135 latin small letter j with circumflex;0134
+0136 latin capital letter k with cedilla
+0137 latin small letter k with cedilla;0136
+0138 latin small letter kra
+0139 latin capital letter l with acute
+013a latin small letter l with acute;0139
+013b latin capital letter l with cedilla
+013c latin small letter l with cedilla;013b
+013d latin capital letter l with caron
+013e latin small letter l with caron;013d
+013f latin capital letter l with middle dot
+0140 latin small letter l with middle dot;013f
+0141 latin capital letter l with stroke
+0142 latin small letter l with stroke;0141
+0143 latin capital letter n with acute
+0144 latin small letter n with acute;0143
+0145 latin capital letter n with cedilla
+0146 latin small letter n with cedilla;0145
+0147 latin capital letter n with caron
+0148 latin small letter n with caron;0147
+0149 latin small letter n preceded by apostrophe
+014a latin capital letter eng
+014b latin small letter eng;014a
+014c latin capital letter o with macron
+014d latin small letter o with macron;014c
+014e latin capital letter o with breve
+014f latin small letter o with breve;014e
+0150 latin capital letter o with double acute
+0151 latin small letter o with double acute;0150
+0152 latin capital ligature oe
+0153 latin small ligature oe;0152
+0154 latin capital letter r with acute
+0155 latin small letter r with acute;0154
+0156 latin capital letter r with cedilla
+0157 latin small letter r with cedilla;0156
+0158 latin capital letter r with caron
+0159 latin small letter r with caron;0158
+015a latin capital letter s with acute
+015b latin small letter s with acute;015a
+015c latin capital letter s with circumflex
+015d latin small letter s with circumflex;015c
+015e latin capital letter s with cedilla
+015f latin small letter s with cedilla;015e
+0160 latin capital letter s with caron
+0161 latin small letter s with caron;0160
+0162 latin capital letter t with cedilla
+0163 latin small letter t with cedilla;0162
+0164 latin capital letter t with caron
+0165 latin small letter t with caron;0164
+0166 latin capital letter t with stroke
+0167 latin small letter t with stroke;0166
+0168 latin capital letter u with tilde
+0169 latin small letter u with tilde;0168
+016a latin capital letter u with macron
+016b latin small letter u with macron;016a
+016c latin capital letter u with breve
+016d latin small letter u with breve;016c
+016e latin capital letter u with ring above
+016f latin small letter u with ring above;016e
+0170 latin capital letter u with double acute
+0171 latin small letter u with double acute;0170
+0172 latin capital letter u with ogonek
+0173 latin small letter u with ogonek;0172
+0174 latin capital letter w with circumflex
+0175 latin small letter w with circumflex;0174
+0176 latin capital letter y with circumflex
+0177 latin small letter y with circumflex;0176
+0178 latin capital letter y with diaeresis
+0179 latin capital letter z with acute
+017a latin small letter z with acute;0179
+017b latin capital letter z with dot above
+017c latin small letter z with dot above;017b
+017d latin capital letter z with caron
+017e latin small letter z with caron;017d
+017f latin small letter long s;0053
+0180 latin small letter b with stroke
+0181 latin capital letter b with hook
+0182 latin capital letter b with topbar
+0183 latin small letter b with topbar;0182
+0184 latin capital letter tone six
+0185 latin small letter tone six;0184
+0186 latin capital letter open o
+0187 latin capital letter c with hook
+0188 latin small letter c with hook;0187
+0189 latin capital letter african d
+018a latin capital letter d with hook
+018b latin capital letter d with topbar
+018c latin small letter d with topbar;018b
+018d latin small letter turned delta
+018e latin capital letter reversed e
+018f latin capital letter schwa
+0190 latin capital letter open e
+0191 latin capital letter f with hook
+0192 latin small letter f with hook;0191
+0193 latin capital letter g with hook
+0194 latin capital letter gamma
+0195 latin small letter hv
+0196 latin capital letter iota
+0197 latin capital letter i with stroke
+0198 latin capital letter k with hook
+0199 latin small letter k with hook;0198
+019a latin small letter l with bar
+019b latin small letter lambda with stroke
+019c latin capital letter turned m
+019d latin capital letter n with left hook
+019e latin small letter n with long right leg
+019f latin capital letter o with middle tilde
+01a0 latin capital letter o with horn
+01a1 latin small letter o with horn;01a0
+01a2 latin capital letter oi
+01a3 latin small letter oi;01a2
+01a4 latin capital letter p with hook
+01a5 latin small letter p with hook;01a4
+01a6 latin letter yr
+01a7 latin capital letter tone two
+01a8 latin small letter tone two;01a7
+01a9 latin capital letter esh
+01aa latin letter reversed esh loop
+01ab latin small letter t with palatal hook
+01ac latin capital letter t with hook
+01ad latin small letter t with hook;01ac
+01ae latin capital letter t with retroflex hook
+01af latin capital letter u with horn
+01b0 latin small letter u with horn;01af
+01b1 latin capital letter upsilon
+01b2 latin capital letter v with hook
+01b3 latin capital letter y with hook
+01b4 latin small letter y with hook;01b3
+01b5 latin capital letter z with stroke
+01b6 latin small letter z with stroke;01b5
+01b7 latin capital letter ezh
+01b8 latin capital letter ezh reversed
+01b9 latin small letter ezh reversed;01b8
+01ba latin small letter ezh with tail
+01bb latin letter two with stroke
+01bc latin capital letter tone five
+01bd latin small letter tone five;01bc
+01be latin letter inverted glottal stop with stroke
+01bf latin letter wynn
+01c0 latin letter dental click
+01c1 latin letter lateral click
+01c2 latin letter alveolar click
+01c3 latin letter retroflex click
+01c4 latin capital letter dz with caron;01c5
+01c5 latin capital letter d with small letter z with caron
+01c6 latin small letter dz with caron;01c5
+01c7 latin capital letter lj;01c8
+01c8 latin capital letter l with small letter j
+01c9 latin small letter lj;01c8
+01ca latin capital letter nj;01cb
+01cb latin capital letter n with small letter j
+01cc latin small letter nj;01cb
+01cd latin capital letter a with caron
+01ce latin small letter a with caron;01cd
+01cf latin capital letter i with caron
+01d0 latin small letter i with caron;01cf
+01d1 latin capital letter o with caron
+01d2 latin small letter o with caron;01d1
+01d3 latin capital letter u with caron
+01d4 latin small letter u with caron;01d3
+01d5 latin capital letter u with diaeresis and macron
+01d6 latin small letter u with diaeresis and macron;01d5
+01d7 latin capital letter u with diaeresis and acute
+01d8 latin small letter u with diaeresis and acute;01d7
+01d9 latin capital letter u with diaeresis and caron
+01da latin small letter u with diaeresis and caron;01d9
+01db latin capital letter u with diaeresis and grave
+01dc latin small letter u with diaeresis and grave;01db
+01dd latin small letter turned e
+01de latin capital letter a with diaeresis and macron
+01df latin small letter a with diaeresis and macron;01de
+01e0 latin capital letter a with dot above and macron
+01e1 latin small letter a with dot above and macron;01e0
+01e2 latin capital letter ae with macron
+01e3 latin small letter ae with macron;01e2
+01e4 latin capital letter g with stroke
+01e5 latin small letter g with stroke;01e4
+01e6 latin capital letter g with caron
+01e7 latin small letter g with caron;01e6
+01e8 latin capital letter k with caron
+01e9 latin small letter k with caron;01e8
+01ea latin capital letter o with ogonek
+01eb latin small letter o with ogonek;01ea
+01ec latin capital letter o with ogonek and macron
+01ed latin small letter o with ogonek and macron;01ec
+01ee latin capital letter ezh with caron
+01ef latin small letter ezh with caron;01ee
+01f0 latin small letter j with caron
+01f1 latin capital letter dz;01f2
+01f2 latin capital letter d with small letter z
+01f3 latin small letter dz;01f2
+01f4 latin capital letter g with acute
+01f5 latin small letter g with acute;01f4
+01fa latin capital letter a with ring above and acute
+01fb latin small letter a with ring above and acute;01fa
+01fc latin capital letter ae with acute
+01fd latin small letter ae with acute;01fc
+01fe latin capital letter o with stroke and acute
+01ff latin small letter o with stroke and acute;01fe
+0200 latin capital letter a with double grave
+0201 latin small letter a with double grave;0200
+0202 latin capital letter a with inverted breve
+0203 latin small letter a with inverted breve;0202
+0204 latin capital letter e with double grave
+0205 latin small letter e with double grave;0204
+0206 latin capital letter e with inverted breve
+0207 latin small letter e with inverted breve;0206
+0208 latin capital letter i with double grave
+0209 latin small letter i with double grave;0208
+020a latin capital letter i with inverted breve
+020b latin small letter i with inverted breve;020a
+020c latin capital letter o with double grave
+020d latin small letter o with double grave;020c
+020e latin capital letter o with inverted breve
+020f latin small letter o with inverted breve;020e
+0210 latin capital letter r with double grave
+0211 latin small letter r with double grave;0210
+0212 latin capital letter r with inverted breve
+0213 latin small letter r with inverted breve;0212
+0214 latin capital letter u with double grave
+0215 latin small letter u with double grave;0214
+0216 latin capital letter u with inverted breve
+0217 latin small letter u with inverted breve;0216
+0250 latin small letter turned a
+0251 latin small letter alpha
+0252 latin small letter turned alpha
+0253 latin small letter b with hook;0181
+0254 latin small letter open o;0186
+0255 latin small letter c with curl
+0256 latin small letter d with tail;0189
+0257 latin small letter d with hook;018a
+0258 latin small letter reversed e;018e
+0259 latin small letter schwa;018f
+025a latin small letter schwa with hook
+025b latin small letter open e;0190
+025c latin small letter reversed open e
+025d latin small letter reversed open e with hook
+025e latin small letter closed reversed open e
+025f latin small letter dotless j with stroke
+0260 latin small letter g with hook;0193
+0261 latin small letter script g
+0262 latin letter small capital g
+0263 latin small letter gamma;0194
+0264 latin small letter rams horn
+0265 latin small letter turned h
+0266 latin small letter h with hook
+0267 latin small letter heng with hook
+0268 latin small letter i with stroke;0197
+0269 latin small letter iota;0196
+026a latin letter small capital i
+026b latin small letter l with middle tilde
+026c latin small letter l with belt
+026d latin small letter l with retroflex hook
+026e latin small letter lezh
+026f latin small letter turned m;019c
+0270 latin small letter turned m with long leg
+0271 latin small letter m with hook
+0272 latin small letter n with left hook;019d
+0273 latin small letter n with retroflex hook
+0274 latin letter small capital n
+0275 latin small letter barred o
+0276 latin letter small capital oe
+0277 latin small letter closed omega
+0278 latin small letter phi
+0279 latin small letter turned r
+027a latin small letter turned r with long leg
+027b latin small letter turned r with hook
+027c latin small letter r with long leg
+027d latin small letter r with tail
+027e latin small letter r with fishhook
+027f latin small letter reversed r with fishhook
+0280 latin letter small capital r
+0281 latin letter small capital inverted r
+0282 latin small letter s with hook
+0283 latin small letter esh;01a9
+0284 latin small letter dotless j with stroke and hook
+0285 latin small letter squat reversed esh
+0286 latin small letter esh with curl
+0287 latin small letter turned t
+0288 latin small letter t with retroflex hook;01ae
+0289 latin small letter u bar
+028a latin small letter upsilon;01b1
+028b latin small letter v with hook;01b2
+028c latin small letter turned v
+028d latin small letter turned w
+028e latin small letter turned y
+028f latin letter small capital y
+0290 latin small letter z with retroflex hook
+0291 latin small letter z with curl
+0292 latin small letter ezh;01b7
+0293 latin small letter ezh with curl
+0294 latin letter glottal stop
+0295 latin letter pharyngeal voiced fricative
+0296 latin letter inverted glottal stop
+0297 latin letter stretched c
+0298 latin letter bilabial click
+0299 latin letter small capital b
+029a latin small letter closed open e
+029b latin letter small capital g with hook
+029c latin letter small capital h
+029d latin small letter j with crossed-tail
+029e latin small letter turned k
+029f latin letter small capital l
+02a0 latin small letter q with hook
+02a1 latin letter glottal stop with stroke
+02a2 latin letter reversed glottal stop with stroke
+02a3 latin small letter dz digraph
+02a4 latin small letter dezh digraph
+02a5 latin small letter dz digraph with curl
+02a6 latin small letter ts digraph
+02a7 latin small letter tesh digraph
+02a8 latin small letter tc digraph with curl
+02b0 modifier letter small h
+02b1 modifier letter small h with hook
+02b2 modifier letter small j
+02b3 modifier letter small r
+02b4 modifier letter small turned r
+02b5 modifier letter small turned r with hook
+02b6 modifier letter small capital inverted r
+02b7 modifier letter small w
+02b8 modifier letter small y
+02b9 modifier letter prime
+02ba modifier letter double prime
+02bb modifier letter turned comma
+02bc modifier letter apostrophe
+02bd modifier letter reversed comma
+02be modifier letter right half ring
+02bf modifier letter left half ring
+02c0 modifier letter glottal stop
+02c1 modifier letter reversed glottal stop
+02c2 modifier letter left arrowhead
+02c3 modifier letter right arrowhead
+02c4 modifier letter up arrowhead
+02c5 modifier letter down arrowhead
+02c6 modifier letter circumflex accent
+02c7 caron
+02c8 modifier letter vertical line
+02c9 modifier letter macron
+02ca modifier letter acute accent
+02cb modifier letter grave accent
+02cc modifier letter low vertical line
+02cd modifier letter low macron
+02ce modifier letter low grave accent
+02cf modifier letter low acute accent
+02d0 modifier letter triangular colon
+02d1 modifier letter half triangular colon
+02d2 modifier letter centred right half ring
+02d3 modifier letter centred left half ring
+02d4 modifier letter up tack
+02d5 modifier letter down tack
+02d6 modifier letter plus sign
+02d7 modifier letter minus sign
+02d8 breve
+02d9 dot above
+02da ring above
+02db ogonek
+02dc small tilde
+02dd double acute accent
+02de modifier letter rhotic hook
+02e0 modifier letter small gamma
+02e1 modifier letter small l
+02e2 modifier letter small s
+02e3 modifier letter small x
+02e4 modifier letter small reversed glottal stop
+02e5 modifier letter extra-high tone bar
+02e6 modifier letter high tone bar
+02e7 modifier letter mid tone bar
+02e8 modifier letter low tone bar
+02e9 modifier letter extra-low tone bar
+0300 combining grave accent
+0301 combining acute accent
+0302 combining circumflex accent
+0303 combining tilde
+0304 combining macron
+0305 combining overline
+0306 combining breve
+0307 combining dot above
+0308 combining diaeresis
+0309 combining hook above
+030a combining ring above
+030b combining double acute accent
+030c combining caron
+030d combining vertical line above
+030e combining double vertical line above
+030f combining double grave accent
+0310 combining candrabindu
+0311 combining inverted breve
+0312 combining turned comma above
+0313 combining comma above
+0314 combining reversed comma above
+0315 combining comma above right
+0316 combining grave accent below
+0317 combining acute accent below
+0318 combining left tack below
+0319 combining right tack below
+031a combining left angle above
+031b combining horn
+031c combining left half ring below
+031d combining up tack below
+031e combining down tack below
+031f combining plus sign below
+0320 combining minus sign below
+0321 combining palatalized hook below
+0322 combining retroflex hook below
+0323 combining dot below
+0324 combining diaeresis below
+0325 combining ring below
+0326 combining comma below
+0327 combining cedilla
+0328 combining ogonek
+0329 combining vertical line below
+032a combining bridge below
+032b combining inverted double arch below
+032c combining caron below
+032d combining circumflex accent below
+032e combining breve below
+032f combining inverted breve below
+0330 combining tilde below
+0331 combining macron below
+0332 combining low line
+0333 combining double low line
+0334 combining tilde overlay
+0335 combining short stroke overlay
+0336 combining long stroke overlay
+0337 combining short solidus overlay
+0338 combining long solidus overlay
+0339 combining right half ring below
+033a combining inverted bridge below
+033b combining square below
+033c combining seagull below
+033d combining x above
+033e combining vertical tilde
+033f combining double overline
+0340 combining grave tone mark
+0341 combining acute tone mark
+0342 combining greek perispomeni
+0343 combining greek koronis
+0344 combining greek dialytika tonos
+0345 combining greek ypogegrammeni
+0360 combining double tilde
+0361 combining double inverted breve
+0374 greek numeral sign
+0375 greek lower numeral sign
+037a greek ypogegrammeni
+037e greek question mark
+0384 greek tonos
+0385 greek dialytika tonos
+0386 greek capital letter alpha with tonos
+0387 greek ano teleia
+0388 greek capital letter epsilon with tonos
+0389 greek capital letter eta with tonos
+038a greek capital letter iota with tonos
+038c greek capital letter omicron with tonos
+038e greek capital letter upsilon with tonos
+038f greek capital letter omega with tonos
+0390 greek small letter iota with dialytika and tonos
+0391 greek capital letter alpha
+0392 greek capital letter beta
+0393 greek capital letter gamma
+0394 greek capital letter delta
+0395 greek capital letter epsilon
+0396 greek capital letter zeta
+0397 greek capital letter eta
+0398 greek capital letter theta
+0399 greek capital letter iota
+039a greek capital letter kappa
+039b greek capital letter lamda
+039c greek capital letter mu
+039d greek capital letter nu
+039e greek capital letter xi
+039f greek capital letter omicron
+03a0 greek capital letter pi
+03a1 greek capital letter rho
+03a3 greek capital letter sigma
+03a4 greek capital letter tau
+03a5 greek capital letter upsilon
+03a6 greek capital letter phi
+03a7 greek capital letter chi
+03a8 greek capital letter psi
+03a9 greek capital letter omega
+03aa greek capital letter iota with dialytika
+03ab greek capital letter upsilon with dialytika
+03ac greek small letter alpha with tonos;0386
+03ad greek small letter epsilon with tonos;0388
+03ae greek small letter eta with tonos;0389
+03af greek small letter iota with tonos;038a
+03b0 greek small letter upsilon with dialytika and tonos
+03b1 greek small letter alpha;0391
+03b2 greek small letter beta;0392
+03b3 greek small letter gamma;0393
+03b4 greek small letter delta;0394
+03b5 greek small letter epsilon;0395
+03b6 greek small letter zeta;0396
+03b7 greek small letter eta;0397
+03b8 greek small letter theta;0398
+03b9 greek small letter iota;0399
+03ba greek small letter kappa;039a
+03bb greek small letter lamda;039b
+03bc greek small letter mu;039c
+03bd greek small letter nu;039d
+03be greek small letter xi;039e
+03bf greek small letter omicron;039f
+03c0 greek small letter pi;03a0
+03c1 greek small letter rho;03a1
+03c2 greek small letter final sigma
+03c3 greek small letter sigma;03a3
+03c4 greek small letter tau;03a4
+03c5 greek small letter upsilon;03a5
+03c6 greek small letter phi;03a6
+03c7 greek small letter chi;03a7
+03c8 greek small letter psi;03a8
+03c9 greek small letter omega;03a9
+03ca greek small letter iota with dialytika;03aa
+03cb greek small letter upsilon with dialytika;03ab
+03cc greek small letter omicron with tonos;038c
+03cd greek small letter upsilon with tonos;038e
+03ce greek small letter omega with tonos;038f
+03d0 greek beta symbol
+03d1 greek theta symbol
+03d2 greek upsilon with hook symbol
+03d3 greek upsilon with acute and hook symbol
+03d4 greek upsilon with diaeresis and hook symbol
+03d5 greek phi symbol
+03d6 greek pi symbol
+03da greek letter stigma
+03dc greek letter digamma
+03de greek letter koppa
+03e0 greek letter sampi
+03e2 coptic capital letter shei
+03e3 coptic small letter shei;03e2
+03e4 coptic capital letter fei
+03e5 coptic small letter fei;03e4
+03e6 coptic capital letter khei
+03e7 coptic small letter khei;03e6
+03e8 coptic capital letter hori
+03e9 coptic small letter hori;03e8
+03ea coptic capital letter gangia
+03eb coptic small letter gangia;03ea
+03ec coptic capital letter shima
+03ed coptic small letter shima;03ec
+03ee coptic capital letter dei
+03ef coptic small letter dei;03ee
+03f0 greek kappa symbol
+03f1 greek rho symbol
+03f2 greek lunate sigma symbol
+03f3 greek letter yot
+0401 cyrillic capital letter io
+0402 cyrillic capital letter dje
+0403 cyrillic capital letter gje
+0404 cyrillic capital letter ukrainian ie
+0405 cyrillic capital letter dze
+0406 cyrillic capital letter byelorussian-ukrainian i
+0407 cyrillic capital letter yi
+0408 cyrillic capital letter je
+0409 cyrillic capital letter lje
+040a cyrillic capital letter nje
+040b cyrillic capital letter tshe
+040c cyrillic capital letter kje
+040e cyrillic capital letter short u
+040f cyrillic capital letter dzhe
+0410 cyrillic capital letter a
+0411 cyrillic capital letter be
+0412 cyrillic capital letter ve
+0413 cyrillic capital letter ghe
+0414 cyrillic capital letter de
+0415 cyrillic capital letter ie
+0416 cyrillic capital letter zhe
+0417 cyrillic capital letter ze
+0418 cyrillic capital letter i
+0419 cyrillic capital letter short i
+041a cyrillic capital letter ka
+041b cyrillic capital letter el
+041c cyrillic capital letter em
+041d cyrillic capital letter en
+041e cyrillic capital letter o
+041f cyrillic capital letter pe
+0420 cyrillic capital letter er
+0421 cyrillic capital letter es
+0422 cyrillic capital letter te
+0423 cyrillic capital letter u
+0424 cyrillic capital letter ef
+0425 cyrillic capital letter ha
+0426 cyrillic capital letter tse
+0427 cyrillic capital letter che
+0428 cyrillic capital letter sha
+0429 cyrillic capital letter shcha
+042a cyrillic capital letter hard sign
+042b cyrillic capital letter yeru
+042c cyrillic capital letter soft sign
+042d cyrillic capital letter e
+042e cyrillic capital letter yu
+042f cyrillic capital letter ya
+0430 cyrillic small letter a;0410
+0431 cyrillic small letter be;0411
+0432 cyrillic small letter ve;0412
+0433 cyrillic small letter ghe;0413
+0434 cyrillic small letter de;0414
+0435 cyrillic small letter ie;0415
+0436 cyrillic small letter zhe;0416
+0437 cyrillic small letter ze;0417
+0438 cyrillic small letter i;0418
+0439 cyrillic small letter short i;0419
+043a cyrillic small letter ka;041a
+043b cyrillic small letter el;041b
+043c cyrillic small letter em;041c
+043d cyrillic small letter en;041d
+043e cyrillic small letter o;041e
+043f cyrillic small letter pe;041f
+0440 cyrillic small letter er;0420
+0441 cyrillic small letter es;0421
+0442 cyrillic small letter te;0422
+0443 cyrillic small letter u;0423
+0444 cyrillic small letter ef;0424
+0445 cyrillic small letter ha;0425
+0446 cyrillic small letter tse;0426
+0447 cyrillic small letter che;0427
+0448 cyrillic small letter sha;0428
+0449 cyrillic small letter shcha;0429
+044a cyrillic small letter hard sign;042a
+044b cyrillic small letter yeru;042b
+044c cyrillic small letter soft sign;042c
+044d cyrillic small letter e;042d
+044e cyrillic small letter yu;042e
+044f cyrillic small letter ya;042f
+0451 cyrillic small letter io;0401
+0452 cyrillic small letter dje;0402
+0453 cyrillic small letter gje;0403
+0454 cyrillic small letter ukrainian ie;0404
+0455 cyrillic small letter dze;0405
+0456 cyrillic small letter byelorussian-ukrainian i;0406
+0457 cyrillic small letter yi;0407
+0458 cyrillic small letter je;0408
+0459 cyrillic small letter lje;0409
+045a cyrillic small letter nje;040a
+045b cyrillic small letter tshe;040b
+045c cyrillic small letter kje;040c
+045e cyrillic small letter short u;040e
+045f cyrillic small letter dzhe;040f
+0460 cyrillic capital letter omega
+0461 cyrillic small letter omega;0460
+0462 cyrillic capital letter yat
+0463 cyrillic small letter yat;0462
+0464 cyrillic capital letter iotified e
+0465 cyrillic small letter iotified e;0464
+0466 cyrillic capital letter little yus
+0467 cyrillic small letter little yus;0466
+0468 cyrillic capital letter iotified little yus
+0469 cyrillic small letter iotified little yus;0468
+046a cyrillic capital letter big yus
+046b cyrillic small letter big yus;046a
+046c cyrillic capital letter iotified big yus
+046d cyrillic small letter iotified big yus;046c
+046e cyrillic capital letter ksi
+046f cyrillic small letter ksi;046e
+0470 cyrillic capital letter psi
+0471 cyrillic small letter psi;0470
+0472 cyrillic capital letter fita
+0473 cyrillic small letter fita;0472
+0474 cyrillic capital letter izhitsa
+0475 cyrillic small letter izhitsa;0474
+0476 cyrillic capital letter izhitsa with double grave accent
+0477 cyrillic small letter izhitsa with double grave accent;0476
+0478 cyrillic capital letter uk
+0479 cyrillic small letter uk;0478
+047a cyrillic capital letter round omega
+047b cyrillic small letter round omega;047a
+047c cyrillic capital letter omega with titlo
+047d cyrillic small letter omega with titlo;047c
+047e cyrillic capital letter ot
+047f cyrillic small letter ot;047e
+0480 cyrillic capital letter koppa
+0481 cyrillic small letter koppa;0480
+0482 cyrillic thousands sign
+0483 combining cyrillic titlo
+0484 combining cyrillic palatalization
+0485 combining cyrillic dasia pneumata
+0486 combining cyrillic psili pneumata
+0490 cyrillic capital letter ghe with upturn
+0491 cyrillic small letter ghe with upturn;0490
+0492 cyrillic capital letter ghe with stroke
+0493 cyrillic small letter ghe with stroke;0492
+0494 cyrillic capital letter ghe with middle hook
+0495 cyrillic small letter ghe with middle hook;0494
+0496 cyrillic capital letter zhe with descender
+0497 cyrillic small letter zhe with descender;0496
+0498 cyrillic capital letter ze with descender
+0499 cyrillic small letter ze with descender;0498
+049a cyrillic capital letter ka with descender
+049b cyrillic small letter ka with descender;049a
+049c cyrillic capital letter ka with vertical stroke
+049d cyrillic small letter ka with vertical stroke;049c
+049e cyrillic capital letter ka with stroke
+049f cyrillic small letter ka with stroke;049e
+04a0 cyrillic capital letter bashkir ka
+04a1 cyrillic small letter bashkir ka;04a0
+04a2 cyrillic capital letter en with descender
+04a3 cyrillic small letter en with descender;04a2
+04a4 cyrillic capital ligature en ghe
+04a5 cyrillic small ligature en ghe;04a4
+04a6 cyrillic capital letter pe with middle hook
+04a7 cyrillic small letter pe with middle hook;04a6
+04a8 cyrillic capital letter abkhasian ha
+04a9 cyrillic small letter abkhasian ha;04a8
+04aa cyrillic capital letter es with descender
+04ab cyrillic small letter es with descender;04aa
+04ac cyrillic capital letter te with descender
+04ad cyrillic small letter te with descender;04ac
+04ae cyrillic capital letter straight u
+04af cyrillic small letter straight u;04ae
+04b0 cyrillic capital letter straight u with stroke
+04b1 cyrillic small letter straight u with stroke;04b0
+04b2 cyrillic capital letter ha with descender
+04b3 cyrillic small letter ha with descender;04b2
+04b4 cyrillic capital ligature te tse
+04b5 cyrillic small ligature te tse;04b4
+04b6 cyrillic capital letter che with descender
+04b7 cyrillic small letter che with descender;04b6
+04b8 cyrillic capital letter che with vertical stroke
+04b9 cyrillic small letter che with vertical stroke;04b8
+04ba cyrillic capital letter shha
+04bb cyrillic small letter shha;04ba
+04bc cyrillic capital letter abkhasian che
+04bd cyrillic small letter abkhasian che;04bc
+04be cyrillic capital letter abkhasian che with descender
+04bf cyrillic small letter abkhasian che with descender;04be
+04c0 cyrillic letter palochka
+04c1 cyrillic capital letter zhe with breve
+04c2 cyrillic small letter zhe with breve;04c1
+04c3 cyrillic capital letter ka with hook
+04c4 cyrillic small letter ka with hook;04c3
+04c7 cyrillic capital letter en with hook
+04c8 cyrillic small letter en with hook;04c7
+04cb cyrillic capital letter khakassian che
+04cc cyrillic small letter khakassian che;04cb
+04d0 cyrillic capital letter a with breve
+04d1 cyrillic small letter a with breve;04d0
+04d2 cyrillic capital letter a with diaeresis
+04d3 cyrillic small letter a with diaeresis;04d2
+04d4 cyrillic capital ligature a ie
+04d5 cyrillic small ligature a ie;04d4
+04d6 cyrillic capital letter ie with breve
+04d7 cyrillic small letter ie with breve;04d6
+04d8 cyrillic capital letter schwa
+04d9 cyrillic small letter schwa;04d8
+04da cyrillic capital letter schwa with diaeresis
+04db cyrillic small letter schwa with diaeresis;04da
+04dc cyrillic capital letter zhe with diaeresis
+04dd cyrillic small letter zhe with diaeresis;04dc
+04de cyrillic capital letter ze with diaeresis
+04df cyrillic small letter ze with diaeresis;04de
+04e0 cyrillic capital letter abkhasian dze
+04e1 cyrillic small letter abkhasian dze;04e0
+04e2 cyrillic capital letter i with macron
+04e3 cyrillic small letter i with macron;04e2
+04e4 cyrillic capital letter i with diaeresis
+04e5 cyrillic small letter i with diaeresis;04e4
+04e6 cyrillic capital letter o with diaeresis
+04e7 cyrillic small letter o with diaeresis;04e6
+04e8 cyrillic capital letter barred o
+04e9 cyrillic small letter barred o;04e8
+04ea cyrillic capital letter barred o with diaeresis
+04eb cyrillic small letter barred o with diaeresis;04ea
+04ee cyrillic capital letter u with macron
+04ef cyrillic small letter u with macron;04ee
+04f0 cyrillic capital letter u with diaeresis
+04f1 cyrillic small letter u with diaeresis;04f0
+04f2 cyrillic capital letter u with double acute
+04f3 cyrillic small letter u with double acute;04f2
+04f4 cyrillic capital letter che with diaeresis
+04f5 cyrillic small letter che with diaeresis;04f4
+04f8 cyrillic capital letter yeru with diaeresis
+04f9 cyrillic small letter yeru with diaeresis;04f8
+0531 armenian capital letter ayb
+0532 armenian capital letter ben
+0533 armenian capital letter gim
+0534 armenian capital letter da
+0535 armenian capital letter ech
+0536 armenian capital letter za
+0537 armenian capital letter eh
+0538 armenian capital letter et
+0539 armenian capital letter to
+053a armenian capital letter zhe
+053b armenian capital letter ini
+053c armenian capital letter liwn
+053d armenian capital letter xeh
+053e armenian capital letter ca
+053f armenian capital letter ken
+0540 armenian capital letter ho
+0541 armenian capital letter ja
+0542 armenian capital letter ghad
+0543 armenian capital letter cheh
+0544 armenian capital letter men
+0545 armenian capital letter yi
+0546 armenian capital letter now
+0547 armenian capital letter sha
+0548 armenian capital letter vo
+0549 armenian capital letter cha
+054a armenian capital letter peh
+054b armenian capital letter jheh
+054c armenian capital letter ra
+054d armenian capital letter seh
+054e armenian capital letter vew
+054f armenian capital letter tiwn
+0550 armenian capital letter reh
+0551 armenian capital letter co
+0552 armenian capital letter yiwn
+0553 armenian capital letter piwr
+0554 armenian capital letter keh
+0555 armenian capital letter oh
+0556 armenian capital letter feh
+0559 armenian modifier letter left half ring
+055a armenian apostrophe
+055b armenian emphasis mark
+055c armenian exclamation mark
+055d armenian comma
+055e armenian question mark
+055f armenian abbreviation mark
+0561 armenian small letter ayb;0531
+0562 armenian small letter ben;0532
+0563 armenian small letter gim;0533
+0564 armenian small letter da;0534
+0565 armenian small letter ech;0535
+0566 armenian small letter za;0536
+0567 armenian small letter eh;0537
+0568 armenian small letter et;0538
+0569 armenian small letter to;0539
+056a armenian small letter zhe;053a
+056b armenian small letter ini;053b
+056c armenian small letter liwn;053c
+056d armenian small letter xeh;053d
+056e armenian small letter ca;053e
+056f armenian small letter ken;053f
+0570 armenian small letter ho;0540
+0571 armenian small letter ja;0541
+0572 armenian small letter ghad;0542
+0573 armenian small letter cheh;0543
+0574 armenian small letter men;0544
+0575 armenian small letter yi;0545
+0576 armenian small letter now;0546
+0577 armenian small letter sha;0547
+0578 armenian small letter vo;0548
+0579 armenian small letter cha;0549
+057a armenian small letter peh;054a
+057b armenian small letter jheh;054b
+057c armenian small letter ra;054c
+057d armenian small letter seh;054d
+057e armenian small letter vew;054e
+057f armenian small letter tiwn;054f
+0580 armenian small letter reh;0550
+0581 armenian small letter co;0551
+0582 armenian small letter yiwn;0552
+0583 armenian small letter piwr;0553
+0584 armenian small letter keh;0554
+0585 armenian small letter oh;0555
+0586 armenian small letter feh;0556
+0587 armenian small ligature ech yiwn
+0589 armenian full stop
+0591 hebrew accent etnahta
+0592 hebrew accent segol
+0593 hebrew accent shalshelet
+0594 hebrew accent zaqef qatan
+0595 hebrew accent zaqef gadol
+0596 hebrew accent tipeha
+0597 hebrew accent revia
+0598 hebrew accent zarqa
+0599 hebrew accent pashta
+059a hebrew accent yetiv
+059b hebrew accent tevir
+059c hebrew accent geresh
+059d hebrew accent geresh muqdam
+059e hebrew accent gershayim
+059f hebrew accent qarney para
+05a0 hebrew accent telisha gedola
+05a1 hebrew accent pazer
+05a3 hebrew accent munah
+05a4 hebrew accent mahapakh
+05a5 hebrew accent merkha
+05a6 hebrew accent merkha kefula
+05a7 hebrew accent darga
+05a8 hebrew accent qadma
+05a9 hebrew accent telisha qetana
+05aa hebrew accent yerah ben yomo
+05ab hebrew accent ole
+05ac hebrew accent iluy
+05ad hebrew accent dehi
+05ae hebrew accent zinor
+05af hebrew mark masora circle
+05b0 hebrew point sheva
+05b1 hebrew point hataf segol
+05b2 hebrew point hataf patah
+05b3 hebrew point hataf qamats
+05b4 hebrew point hiriq
+05b5 hebrew point tsere
+05b6 hebrew point segol
+05b7 hebrew point patah
+05b8 hebrew point qamats
+05b9 hebrew point holam
+05bb hebrew point qubuts
+05bc hebrew point dagesh or mapiq
+05bd hebrew point meteg
+05be hebrew punctuation maqaf
+05bf hebrew point rafe
+05c0 hebrew punctuation paseq
+05c1 hebrew point shin dot
+05c2 hebrew point sin dot
+05c3 hebrew punctuation sof pasuq
+05c4 hebrew mark upper dot
+05d0 hebrew letter alef
+05d1 hebrew letter bet
+05d2 hebrew letter gimel
+05d3 hebrew letter dalet
+05d4 hebrew letter he
+05d5 hebrew letter vav
+05d6 hebrew letter zayin
+05d7 hebrew letter het
+05d8 hebrew letter tet
+05d9 hebrew letter yod
+05da hebrew letter final kaf
+05db hebrew letter kaf
+05dc hebrew letter lamed
+05dd hebrew letter final mem
+05de hebrew letter mem
+05df hebrew letter final nun
+05e0 hebrew letter nun
+05e1 hebrew letter samekh
+05e2 hebrew letter ayin
+05e3 hebrew letter final pe
+05e4 hebrew letter pe
+05e5 hebrew letter final tsadi
+05e6 hebrew letter tsadi
+05e7 hebrew letter qof
+05e8 hebrew letter resh
+05e9 hebrew letter shin
+05ea hebrew letter tav
+05f0 hebrew ligature yiddish double vav
+05f1 hebrew ligature yiddish vav yod
+05f2 hebrew ligature yiddish double yod
+05f3 hebrew punctuation geresh
+05f4 hebrew punctuation gershayim
+060c arabic comma
+061b arabic semicolon
+061f arabic question mark
+0621 arabic letter hamza
+0622 arabic letter alef with madda above
+0623 arabic letter alef with hamza above
+0624 arabic letter waw with hamza above
+0625 arabic letter alef with hamza below
+0626 arabic letter yeh with hamza above
+0627 arabic letter alef
+0628 arabic letter beh
+0629 arabic letter teh marbuta
+062a arabic letter teh
+062b arabic letter theh
+062c arabic letter jeem
+062d arabic letter hah
+062e arabic letter khah
+062f arabic letter dal
+0630 arabic letter thal
+0631 arabic letter reh
+0632 arabic letter zain
+0633 arabic letter seen
+0634 arabic letter sheen
+0635 arabic letter sad
+0636 arabic letter dad
+0637 arabic letter tah
+0638 arabic letter zah
+0639 arabic letter ain
+063a arabic letter ghain
+0640 arabic tatweel
+0641 arabic letter feh
+0642 arabic letter qaf
+0643 arabic letter kaf
+0644 arabic letter lam
+0645 arabic letter meem
+0646 arabic letter noon
+0647 arabic letter heh
+0648 arabic letter waw
+0649 arabic letter alef maksura
+064a arabic letter yeh
+064b arabic fathatan
+064c arabic dammatan
+064d arabic kasratan
+064e arabic fatha
+064f arabic damma
+0650 arabic kasra
+0651 arabic shadda
+0652 arabic sukun
+0660 arabic-indic digit zero
+0661 arabic-indic digit one
+0662 arabic-indic digit two
+0663 arabic-indic digit three
+0664 arabic-indic digit four
+0665 arabic-indic digit five
+0666 arabic-indic digit six
+0667 arabic-indic digit seven
+0668 arabic-indic digit eight
+0669 arabic-indic digit nine
+066a arabic percent sign
+066b arabic decimal separator
+066c arabic thousands separator
+066d arabic five pointed star
+0670 arabic letter superscript alef
+0671 arabic letter alef wasla
+0672 arabic letter alef with wavy hamza above
+0673 arabic letter alef with wavy hamza below
+0674 arabic letter high hamza
+0675 arabic letter high hamza alef
+0676 arabic letter high hamza waw
+0677 arabic letter u with hamza above
+0678 arabic letter high hamza yeh
+0679 arabic letter tteh
+067a arabic letter tteheh
+067b arabic letter beeh
+067c arabic letter teh with ring
+067d arabic letter teh with three dots above downwards
+067e arabic letter peh
+067f arabic letter teheh
+0680 arabic letter beheh
+0681 arabic letter hah with hamza above
+0682 arabic letter hah with two dots vertical above
+0683 arabic letter nyeh
+0684 arabic letter dyeh
+0685 arabic letter hah with three dots above
+0686 arabic letter tcheh
+0687 arabic letter tcheheh
+0688 arabic letter ddal
+0689 arabic letter dal with ring
+068a arabic letter dal with dot below
+068b arabic letter dal with dot below and small tah
+068c arabic letter dahal
+068d arabic letter ddahal
+068e arabic letter dul
+068f arabic letter dal with three dots above downwards
+0690 arabic letter dal with four dots above
+0691 arabic letter rreh
+0692 arabic letter reh with small v
+0693 arabic letter reh with ring
+0694 arabic letter reh with dot below
+0695 arabic letter reh with small v below
+0696 arabic letter reh with dot below and dot above
+0697 arabic letter reh with two dots above
+0698 arabic letter jeh
+0699 arabic letter reh with four dots above
+069a arabic letter seen with dot below and dot above
+069b arabic letter seen with three dots below
+069c arabic letter seen with three dots below and three dots above
+069d arabic letter sad with two dots below
+069e arabic letter sad with three dots above
+069f arabic letter tah with three dots above
+06a0 arabic letter ain with three dots above
+06a1 arabic letter dotless feh
+06a2 arabic letter feh with dot moved below
+06a3 arabic letter feh with dot below
+06a4 arabic letter veh
+06a5 arabic letter feh with three dots below
+06a6 arabic letter peheh
+06a7 arabic letter qaf with dot above
+06a8 arabic letter qaf with three dots above
+06a9 arabic letter keheh
+06aa arabic letter swash kaf
+06ab arabic letter kaf with ring
+06ac arabic letter kaf with dot above
+06ad arabic letter ng
+06ae arabic letter kaf with three dots below
+06af arabic letter gaf
+06b0 arabic letter gaf with ring
+06b1 arabic letter ngoeh
+06b2 arabic letter gaf with two dots below
+06b3 arabic letter gueh
+06b4 arabic letter gaf with three dots above
+06b5 arabic letter lam with small v
+06b6 arabic letter lam with dot above
+06b7 arabic letter lam with three dots above
+06ba arabic letter noon ghunna
+06bb arabic letter rnoon
+06bc arabic letter noon with ring
+06bd arabic letter noon with three dots above
+06be arabic letter heh doachashmee
+06c0 arabic letter heh with yeh above
+06c1 arabic letter heh goal
+06c2 arabic letter heh goal with hamza above
+06c3 arabic letter teh marbuta goal
+06c4 arabic letter waw with ring
+06c5 arabic letter kirghiz oe
+06c6 arabic letter oe
+06c7 arabic letter u
+06c8 arabic letter yu
+06c9 arabic letter kirghiz yu
+06ca arabic letter waw with two dots above
+06cb arabic letter ve
+06cc arabic letter farsi yeh
+06cd arabic letter yeh with tail
+06ce arabic letter yeh with small v
+06d0 arabic letter e
+06d1 arabic letter yeh with three dots below
+06d2 arabic letter yeh barree
+06d3 arabic letter yeh barree with hamza above
+06d4 arabic full stop
+06d5 arabic letter ae
+06d6 arabic small high ligature sad with lam with alef maksura
+06d7 arabic small high ligature qaf with lam with alef maksura
+06d8 arabic small high meem initial form
+06d9 arabic small high lam alef
+06da arabic small high jeem
+06db arabic small high three dots
+06dc arabic small high seen
+06dd arabic end of ayah
+06de arabic start of rub el hizb
+06df arabic small high rounded zero
+06e0 arabic small high upright rectangular zero
+06e1 arabic small high dotless head of khah
+06e2 arabic small high meem isolated form
+06e3 arabic small low seen
+06e4 arabic small high madda
+06e5 arabic small waw
+06e6 arabic small yeh
+06e7 arabic small high yeh
+06e8 arabic small high noon
+06e9 arabic place of sajdah
+06ea arabic empty centre low stop
+06eb arabic empty centre high stop
+06ec arabic rounded high stop with filled centre
+06ed arabic small low meem
+06f0 extended arabic-indic digit zero
+06f1 extended arabic-indic digit one
+06f2 extended arabic-indic digit two
+06f3 extended arabic-indic digit three
+06f4 extended arabic-indic digit four
+06f5 extended arabic-indic digit five
+06f6 extended arabic-indic digit six
+06f7 extended arabic-indic digit seven
+06f8 extended arabic-indic digit eight
+06f9 extended arabic-indic digit nine
+0901 devanagari sign candrabindu
+0902 devanagari sign anusvara
+0903 devanagari sign visarga
+0905 devanagari letter a
+0906 devanagari letter aa
+0907 devanagari letter i
+0908 devanagari letter ii
+0909 devanagari letter u
+090a devanagari letter uu
+090b devanagari letter vocalic r
+090c devanagari letter vocalic l
+090d devanagari letter candra e
+090e devanagari letter short e
+090f devanagari letter e
+0910 devanagari letter ai
+0911 devanagari letter candra o
+0912 devanagari letter short o
+0913 devanagari letter o
+0914 devanagari letter au
+0915 devanagari letter ka
+0916 devanagari letter kha
+0917 devanagari letter ga
+0918 devanagari letter gha
+0919 devanagari letter nga
+091a devanagari letter ca
+091b devanagari letter cha
+091c devanagari letter ja
+091d devanagari letter jha
+091e devanagari letter nya
+091f devanagari letter tta
+0920 devanagari letter ttha
+0921 devanagari letter dda
+0922 devanagari letter ddha
+0923 devanagari letter nna
+0924 devanagari letter ta
+0925 devanagari letter tha
+0926 devanagari letter da
+0927 devanagari letter dha
+0928 devanagari letter na
+0929 devanagari letter nnna
+092a devanagari letter pa
+092b devanagari letter pha
+092c devanagari letter ba
+092d devanagari letter bha
+092e devanagari letter ma
+092f devanagari letter ya
+0930 devanagari letter ra
+0931 devanagari letter rra
+0932 devanagari letter la
+0933 devanagari letter lla
+0934 devanagari letter llla
+0935 devanagari letter va
+0936 devanagari letter sha
+0937 devanagari letter ssa
+0938 devanagari letter sa
+0939 devanagari letter ha
+093c devanagari sign nukta
+093d devanagari sign avagraha
+093e devanagari vowel sign aa
+093f devanagari vowel sign i
+0940 devanagari vowel sign ii
+0941 devanagari vowel sign u
+0942 devanagari vowel sign uu
+0943 devanagari vowel sign vocalic r
+0944 devanagari vowel sign vocalic rr
+0945 devanagari vowel sign candra e
+0946 devanagari vowel sign short e
+0947 devanagari vowel sign e
+0948 devanagari vowel sign ai
+0949 devanagari vowel sign candra o
+094a devanagari vowel sign short o
+094b devanagari vowel sign o
+094c devanagari vowel sign au
+094d devanagari sign virama
+0950 devanagari om
+0951 devanagari stress sign udatta
+0952 devanagari stress sign anudatta
+0953 devanagari grave accent
+0954 devanagari acute accent
+0958 devanagari letter qa
+0959 devanagari letter khha
+095a devanagari letter ghha
+095b devanagari letter za
+095c devanagari letter dddha
+095d devanagari letter rha
+095e devanagari letter fa
+095f devanagari letter yya
+0960 devanagari letter vocalic rr
+0961 devanagari letter vocalic ll
+0962 devanagari vowel sign vocalic l
+0963 devanagari vowel sign vocalic ll
+0964 devanagari danda
+0965 devanagari double danda
+0966 devanagari digit zero
+0967 devanagari digit one
+0968 devanagari digit two
+0969 devanagari digit three
+096a devanagari digit four
+096b devanagari digit five
+096c devanagari digit six
+096d devanagari digit seven
+096e devanagari digit eight
+096f devanagari digit nine
+0970 devanagari abbreviation sign
+0981 bengali sign candrabindu
+0982 bengali sign anusvara
+0983 bengali sign visarga
+0985 bengali letter a
+0986 bengali letter aa
+0987 bengali letter i
+0988 bengali letter ii
+0989 bengali letter u
+098a bengali letter uu
+098b bengali letter vocalic r
+098c bengali letter vocalic l
+098f bengali letter e
+0990 bengali letter ai
+0993 bengali letter o
+0994 bengali letter au
+0995 bengali letter ka
+0996 bengali letter kha
+0997 bengali letter ga
+0998 bengali letter gha
+0999 bengali letter nga
+099a bengali letter ca
+099b bengali letter cha
+099c bengali letter ja
+099d bengali letter jha
+099e bengali letter nya
+099f bengali letter tta
+09a0 bengali letter ttha
+09a1 bengali letter dda
+09a2 bengali letter ddha
+09a3 bengali letter nna
+09a4 bengali letter ta
+09a5 bengali letter tha
+09a6 bengali letter da
+09a7 bengali letter dha
+09a8 bengali letter na
+09aa bengali letter pa
+09ab bengali letter pha
+09ac bengali letter ba
+09ad bengali letter bha
+09ae bengali letter ma
+09af bengali letter ya
+09b0 bengali letter ra
+09b2 bengali letter la
+09b6 bengali letter sha
+09b7 bengali letter ssa
+09b8 bengali letter sa
+09b9 bengali letter ha
+09bc bengali sign nukta
+09be bengali vowel sign aa
+09bf bengali vowel sign i
+09c0 bengali vowel sign ii
+09c1 bengali vowel sign u
+09c2 bengali vowel sign uu
+09c3 bengali vowel sign vocalic r
+09c4 bengali vowel sign vocalic rr
+09c7 bengali vowel sign e
+09c8 bengali vowel sign ai
+09cb bengali vowel sign o
+09cc bengali vowel sign au
+09cd bengali sign virama
+09d7 bengali au length mark
+09dc bengali letter rra
+09dd bengali letter rha
+09df bengali letter yya
+09e0 bengali letter vocalic rr
+09e1 bengali letter vocalic ll
+09e2 bengali vowel sign vocalic l
+09e3 bengali vowel sign vocalic ll
+09e6 bengali digit zero
+09e7 bengali digit one
+09e8 bengali digit two
+09e9 bengali digit three
+09ea bengali digit four
+09eb bengali digit five
+09ec bengali digit six
+09ed bengali digit seven
+09ee bengali digit eight
+09ef bengali digit nine
+09f0 bengali letter ra with middle diagonal
+09f1 bengali letter ra with lower diagonal
+09f2 bengali rupee mark
+09f3 bengali rupee sign
+09f4 bengali currency numerator one
+09f5 bengali currency numerator two
+09f6 bengali currency numerator three
+09f7 bengali currency numerator four
+09f8 bengali currency numerator one less than the denominator
+09f9 bengali currency denominator sixteen
+09fa bengali isshar
+0a02 gurmukhi sign bindi
+0a05 gurmukhi letter a
+0a06 gurmukhi letter aa
+0a07 gurmukhi letter i
+0a08 gurmukhi letter ii
+0a09 gurmukhi letter u
+0a0a gurmukhi letter uu
+0a0f gurmukhi letter ee
+0a10 gurmukhi letter ai
+0a13 gurmukhi letter oo
+0a14 gurmukhi letter au
+0a15 gurmukhi letter ka
+0a16 gurmukhi letter kha
+0a17 gurmukhi letter ga
+0a18 gurmukhi letter gha
+0a19 gurmukhi letter nga
+0a1a gurmukhi letter ca
+0a1b gurmukhi letter cha
+0a1c gurmukhi letter ja
+0a1d gurmukhi letter jha
+0a1e gurmukhi letter nya
+0a1f gurmukhi letter tta
+0a20 gurmukhi letter ttha
+0a21 gurmukhi letter dda
+0a22 gurmukhi letter ddha
+0a23 gurmukhi letter nna
+0a24 gurmukhi letter ta
+0a25 gurmukhi letter tha
+0a26 gurmukhi letter da
+0a27 gurmukhi letter dha
+0a28 gurmukhi letter na
+0a2a gurmukhi letter pa
+0a2b gurmukhi letter pha
+0a2c gurmukhi letter ba
+0a2d gurmukhi letter bha
+0a2e gurmukhi letter ma
+0a2f gurmukhi letter ya
+0a30 gurmukhi letter ra
+0a32 gurmukhi letter la
+0a33 gurmukhi letter lla
+0a35 gurmukhi letter va
+0a36 gurmukhi letter sha
+0a38 gurmukhi letter sa
+0a39 gurmukhi letter ha
+0a3c gurmukhi sign nukta
+0a3e gurmukhi vowel sign aa
+0a3f gurmukhi vowel sign i
+0a40 gurmukhi vowel sign ii
+0a41 gurmukhi vowel sign u
+0a42 gurmukhi vowel sign uu
+0a47 gurmukhi vowel sign ee
+0a48 gurmukhi vowel sign ai
+0a4b gurmukhi vowel sign oo
+0a4c gurmukhi vowel sign au
+0a4d gurmukhi sign virama
+0a59 gurmukhi letter khha
+0a5a gurmukhi letter ghha
+0a5b gurmukhi letter za
+0a5c gurmukhi letter rra
+0a5e gurmukhi letter fa
+0a66 gurmukhi digit zero
+0a67 gurmukhi digit one
+0a68 gurmukhi digit two
+0a69 gurmukhi digit three
+0a6a gurmukhi digit four
+0a6b gurmukhi digit five
+0a6c gurmukhi digit six
+0a6d gurmukhi digit seven
+0a6e gurmukhi digit eight
+0a6f gurmukhi digit nine
+0a70 gurmukhi tippi
+0a71 gurmukhi addak
+0a72 gurmukhi iri
+0a73 gurmukhi ura
+0a74 gurmukhi ek onkar
+0a81 gujarati sign candrabindu
+0a82 gujarati sign anusvara
+0a83 gujarati sign visarga
+0a85 gujarati letter a
+0a86 gujarati letter aa
+0a87 gujarati letter i
+0a88 gujarati letter ii
+0a89 gujarati letter u
+0a8a gujarati letter uu
+0a8b gujarati letter vocalic r
+0a8d gujarati vowel candra e
+0a8f gujarati letter e
+0a90 gujarati letter ai
+0a91 gujarati vowel candra o
+0a93 gujarati letter o
+0a94 gujarati letter au
+0a95 gujarati letter ka
+0a96 gujarati letter kha
+0a97 gujarati letter ga
+0a98 gujarati letter gha
+0a99 gujarati letter nga
+0a9a gujarati letter ca
+0a9b gujarati letter cha
+0a9c gujarati letter ja
+0a9d gujarati letter jha
+0a9e gujarati letter nya
+0a9f gujarati letter tta
+0aa0 gujarati letter ttha
+0aa1 gujarati letter dda
+0aa2 gujarati letter ddha
+0aa3 gujarati letter nna
+0aa4 gujarati letter ta
+0aa5 gujarati letter tha
+0aa6 gujarati letter da
+0aa7 gujarati letter dha
+0aa8 gujarati letter na
+0aaa gujarati letter pa
+0aab gujarati letter pha
+0aac gujarati letter ba
+0aad gujarati letter bha
+0aae gujarati letter ma
+0aaf gujarati letter ya
+0ab0 gujarati letter ra
+0ab2 gujarati letter la
+0ab3 gujarati letter lla
+0ab5 gujarati letter va
+0ab6 gujarati letter sha
+0ab7 gujarati letter ssa
+0ab8 gujarati letter sa
+0ab9 gujarati letter ha
+0abc gujarati sign nukta
+0abd gujarati sign avagraha
+0abe gujarati vowel sign aa
+0abf gujarati vowel sign i
+0ac0 gujarati vowel sign ii
+0ac1 gujarati vowel sign u
+0ac2 gujarati vowel sign uu
+0ac3 gujarati vowel sign vocalic r
+0ac4 gujarati vowel sign vocalic rr
+0ac5 gujarati vowel sign candra e
+0ac7 gujarati vowel sign e
+0ac8 gujarati vowel sign ai
+0ac9 gujarati vowel sign candra o
+0acb gujarati vowel sign o
+0acc gujarati vowel sign au
+0acd gujarati sign virama
+0ad0 gujarati om
+0ae0 gujarati letter vocalic rr
+0ae6 gujarati digit zero
+0ae7 gujarati digit one
+0ae8 gujarati digit two
+0ae9 gujarati digit three
+0aea gujarati digit four
+0aeb gujarati digit five
+0aec gujarati digit six
+0aed gujarati digit seven
+0aee gujarati digit eight
+0aef gujarati digit nine
+0b01 oriya sign candrabindu
+0b02 oriya sign anusvara
+0b03 oriya sign visarga
+0b05 oriya letter a
+0b06 oriya letter aa
+0b07 oriya letter i
+0b08 oriya letter ii
+0b09 oriya letter u
+0b0a oriya letter uu
+0b0b oriya letter vocalic r
+0b0c oriya letter vocalic l
+0b0f oriya letter e
+0b10 oriya letter ai
+0b13 oriya letter o
+0b14 oriya letter au
+0b15 oriya letter ka
+0b16 oriya letter kha
+0b17 oriya letter ga
+0b18 oriya letter gha
+0b19 oriya letter nga
+0b1a oriya letter ca
+0b1b oriya letter cha
+0b1c oriya letter ja
+0b1d oriya letter jha
+0b1e oriya letter nya
+0b1f oriya letter tta
+0b20 oriya letter ttha
+0b21 oriya letter dda
+0b22 oriya letter ddha
+0b23 oriya letter nna
+0b24 oriya letter ta
+0b25 oriya letter tha
+0b26 oriya letter da
+0b27 oriya letter dha
+0b28 oriya letter na
+0b2a oriya letter pa
+0b2b oriya letter pha
+0b2c oriya letter ba
+0b2d oriya letter bha
+0b2e oriya letter ma
+0b2f oriya letter ya
+0b30 oriya letter ra
+0b32 oriya letter la
+0b33 oriya letter lla
+0b36 oriya letter sha
+0b37 oriya letter ssa
+0b38 oriya letter sa
+0b39 oriya letter ha
+0b3c oriya sign nukta
+0b3d oriya sign avagraha
+0b3e oriya vowel sign aa
+0b3f oriya vowel sign i
+0b40 oriya vowel sign ii
+0b41 oriya vowel sign u
+0b42 oriya vowel sign uu
+0b43 oriya vowel sign vocalic r
+0b47 oriya vowel sign e
+0b48 oriya vowel sign ai
+0b4b oriya vowel sign o
+0b4c oriya vowel sign au
+0b4d oriya sign virama
+0b56 oriya ai length mark
+0b57 oriya au length mark
+0b5c oriya letter rra
+0b5d oriya letter rha
+0b5f oriya letter yya
+0b60 oriya letter vocalic rr
+0b61 oriya letter vocalic ll
+0b66 oriya digit zero
+0b67 oriya digit one
+0b68 oriya digit two
+0b69 oriya digit three
+0b6a oriya digit four
+0b6b oriya digit five
+0b6c oriya digit six
+0b6d oriya digit seven
+0b6e oriya digit eight
+0b6f oriya digit nine
+0b70 oriya isshar
+0b82 tamil sign anusvara
+0b83 tamil sign visarga
+0b85 tamil letter a
+0b86 tamil letter aa
+0b87 tamil letter i
+0b88 tamil letter ii
+0b89 tamil letter u
+0b8a tamil letter uu
+0b8e tamil letter e
+0b8f tamil letter ee
+0b90 tamil letter ai
+0b92 tamil letter o
+0b93 tamil letter oo
+0b94 tamil letter au
+0b95 tamil letter ka
+0b99 tamil letter nga
+0b9a tamil letter ca
+0b9c tamil letter ja
+0b9e tamil letter nya
+0b9f tamil letter tta
+0ba3 tamil letter nna
+0ba4 tamil letter ta
+0ba8 tamil letter na
+0ba9 tamil letter nnna
+0baa tamil letter pa
+0bae tamil letter ma
+0baf tamil letter ya
+0bb0 tamil letter ra
+0bb1 tamil letter rra
+0bb2 tamil letter la
+0bb3 tamil letter lla
+0bb4 tamil letter llla
+0bb5 tamil letter va
+0bb7 tamil letter ssa
+0bb8 tamil letter sa
+0bb9 tamil letter ha
+0bbe tamil vowel sign aa
+0bbf tamil vowel sign i
+0bc0 tamil vowel sign ii
+0bc1 tamil vowel sign u
+0bc2 tamil vowel sign uu
+0bc6 tamil vowel sign e
+0bc7 tamil vowel sign ee
+0bc8 tamil vowel sign ai
+0bca tamil vowel sign o
+0bcb tamil vowel sign oo
+0bcc tamil vowel sign au
+0bcd tamil sign virama
+0bd7 tamil au length mark
+0be7 tamil digit one
+0be8 tamil digit two
+0be9 tamil digit three
+0bea tamil digit four
+0beb tamil digit five
+0bec tamil digit six
+0bed tamil digit seven
+0bee tamil digit eight
+0bef tamil digit nine
+0bf0 tamil number ten
+0bf1 tamil number one hundred
+0bf2 tamil number one thousand
+0c01 telugu sign candrabindu
+0c02 telugu sign anusvara
+0c03 telugu sign visarga
+0c05 telugu letter a
+0c06 telugu letter aa
+0c07 telugu letter i
+0c08 telugu letter ii
+0c09 telugu letter u
+0c0a telugu letter uu
+0c0b telugu letter vocalic r
+0c0c telugu letter vocalic l
+0c0e telugu letter e
+0c0f telugu letter ee
+0c10 telugu letter ai
+0c12 telugu letter o
+0c13 telugu letter oo
+0c14 telugu letter au
+0c15 telugu letter ka
+0c16 telugu letter kha
+0c17 telugu letter ga
+0c18 telugu letter gha
+0c19 telugu letter nga
+0c1a telugu letter ca
+0c1b telugu letter cha
+0c1c telugu letter ja
+0c1d telugu letter jha
+0c1e telugu letter nya
+0c1f telugu letter tta
+0c20 telugu letter ttha
+0c21 telugu letter dda
+0c22 telugu letter ddha
+0c23 telugu letter nna
+0c24 telugu letter ta
+0c25 telugu letter tha
+0c26 telugu letter da
+0c27 telugu letter dha
+0c28 telugu letter na
+0c2a telugu letter pa
+0c2b telugu letter pha
+0c2c telugu letter ba
+0c2d telugu letter bha
+0c2e telugu letter ma
+0c2f telugu letter ya
+0c30 telugu letter ra
+0c31 telugu letter rra
+0c32 telugu letter la
+0c33 telugu letter lla
+0c35 telugu letter va
+0c36 telugu letter sha
+0c37 telugu letter ssa
+0c38 telugu letter sa
+0c39 telugu letter ha
+0c3e telugu vowel sign aa
+0c3f telugu vowel sign i
+0c40 telugu vowel sign ii
+0c41 telugu vowel sign u
+0c42 telugu vowel sign uu
+0c43 telugu vowel sign vocalic r
+0c44 telugu vowel sign vocalic rr
+0c46 telugu vowel sign e
+0c47 telugu vowel sign ee
+0c48 telugu vowel sign ai
+0c4a telugu vowel sign o
+0c4b telugu vowel sign oo
+0c4c telugu vowel sign au
+0c4d telugu sign virama
+0c55 telugu length mark
+0c56 telugu ai length mark
+0c60 telugu letter vocalic rr
+0c61 telugu letter vocalic ll
+0c66 telugu digit zero
+0c67 telugu digit one
+0c68 telugu digit two
+0c69 telugu digit three
+0c6a telugu digit four
+0c6b telugu digit five
+0c6c telugu digit six
+0c6d telugu digit seven
+0c6e telugu digit eight
+0c6f telugu digit nine
+0c82 kannada sign anusvara
+0c83 kannada sign visarga
+0c85 kannada letter a
+0c86 kannada letter aa
+0c87 kannada letter i
+0c88 kannada letter ii
+0c89 kannada letter u
+0c8a kannada letter uu
+0c8b kannada letter vocalic r
+0c8c kannada letter vocalic l
+0c8e kannada letter e
+0c8f kannada letter ee
+0c90 kannada letter ai
+0c92 kannada letter o
+0c93 kannada letter oo
+0c94 kannada letter au
+0c95 kannada letter ka
+0c96 kannada letter kha
+0c97 kannada letter ga
+0c98 kannada letter gha
+0c99 kannada letter nga
+0c9a kannada letter ca
+0c9b kannada letter cha
+0c9c kannada letter ja
+0c9d kannada letter jha
+0c9e kannada letter nya
+0c9f kannada letter tta
+0ca0 kannada letter ttha
+0ca1 kannada letter dda
+0ca2 kannada letter ddha
+0ca3 kannada letter nna
+0ca4 kannada letter ta
+0ca5 kannada letter tha
+0ca6 kannada letter da
+0ca7 kannada letter dha
+0ca8 kannada letter na
+0caa kannada letter pa
+0cab kannada letter pha
+0cac kannada letter ba
+0cad kannada letter bha
+0cae kannada letter ma
+0caf kannada letter ya
+0cb0 kannada letter ra
+0cb1 kannada letter rra
+0cb2 kannada letter la
+0cb3 kannada letter lla
+0cb5 kannada letter va
+0cb6 kannada letter sha
+0cb7 kannada letter ssa
+0cb8 kannada letter sa
+0cb9 kannada letter ha
+0cbe kannada vowel sign aa
+0cbf kannada vowel sign i
+0cc0 kannada vowel sign ii
+0cc1 kannada vowel sign u
+0cc2 kannada vowel sign uu
+0cc3 kannada vowel sign vocalic r
+0cc4 kannada vowel sign vocalic rr
+0cc6 kannada vowel sign e
+0cc7 kannada vowel sign ee
+0cc8 kannada vowel sign ai
+0cca kannada vowel sign o
+0ccb kannada vowel sign oo
+0ccc kannada vowel sign au
+0ccd kannada sign virama
+0cd5 kannada length mark
+0cd6 kannada ai length mark
+0cde kannada letter fa
+0ce0 kannada letter vocalic rr
+0ce1 kannada letter vocalic ll
+0ce6 kannada digit zero
+0ce7 kannada digit one
+0ce8 kannada digit two
+0ce9 kannada digit three
+0cea kannada digit four
+0ceb kannada digit five
+0cec kannada digit six
+0ced kannada digit seven
+0cee kannada digit eight
+0cef kannada digit nine
+0d02 malayalam sign anusvara
+0d03 malayalam sign visarga
+0d05 malayalam letter a
+0d06 malayalam letter aa
+0d07 malayalam letter i
+0d08 malayalam letter ii
+0d09 malayalam letter u
+0d0a malayalam letter uu
+0d0b malayalam letter vocalic r
+0d0c malayalam letter vocalic l
+0d0e malayalam letter e
+0d0f malayalam letter ee
+0d10 malayalam letter ai
+0d12 malayalam letter o
+0d13 malayalam letter oo
+0d14 malayalam letter au
+0d15 malayalam letter ka
+0d16 malayalam letter kha
+0d17 malayalam letter ga
+0d18 malayalam letter gha
+0d19 malayalam letter nga
+0d1a malayalam letter ca
+0d1b malayalam letter cha
+0d1c malayalam letter ja
+0d1d malayalam letter jha
+0d1e malayalam letter nya
+0d1f malayalam letter tta
+0d20 malayalam letter ttha
+0d21 malayalam letter dda
+0d22 malayalam letter ddha
+0d23 malayalam letter nna
+0d24 malayalam letter ta
+0d25 malayalam letter tha
+0d26 malayalam letter da
+0d27 malayalam letter dha
+0d28 malayalam letter na
+0d2a malayalam letter pa
+0d2b malayalam letter pha
+0d2c malayalam letter ba
+0d2d malayalam letter bha
+0d2e malayalam letter ma
+0d2f malayalam letter ya
+0d30 malayalam letter ra
+0d31 malayalam letter rra
+0d32 malayalam letter la
+0d33 malayalam letter lla
+0d34 malayalam letter llla
+0d35 malayalam letter va
+0d36 malayalam letter sha
+0d37 malayalam letter ssa
+0d38 malayalam letter sa
+0d39 malayalam letter ha
+0d3e malayalam vowel sign aa
+0d3f malayalam vowel sign i
+0d40 malayalam vowel sign ii
+0d41 malayalam vowel sign u
+0d42 malayalam vowel sign uu
+0d43 malayalam vowel sign vocalic r
+0d46 malayalam vowel sign e
+0d47 malayalam vowel sign ee
+0d48 malayalam vowel sign ai
+0d4a malayalam vowel sign o
+0d4b malayalam vowel sign oo
+0d4c malayalam vowel sign au
+0d4d malayalam sign virama
+0d57 malayalam au length mark
+0d60 malayalam letter vocalic rr
+0d61 malayalam letter vocalic ll
+0d66 malayalam digit zero
+0d67 malayalam digit one
+0d68 malayalam digit two
+0d69 malayalam digit three
+0d6a malayalam digit four
+0d6b malayalam digit five
+0d6c malayalam digit six
+0d6d malayalam digit seven
+0d6e malayalam digit eight
+0d6f malayalam digit nine
+0e01 thai character ko kai
+0e02 thai character kho khai
+0e03 thai character kho khuat
+0e04 thai character kho khwai
+0e05 thai character kho khon
+0e06 thai character kho rakhang
+0e07 thai character ngo ngu
+0e08 thai character cho chan
+0e09 thai character cho ching
+0e0a thai character cho chang
+0e0b thai character so so
+0e0c thai character cho choe
+0e0d thai character yo ying
+0e0e thai character do chada
+0e0f thai character to patak
+0e10 thai character tho than
+0e11 thai character tho nangmontho
+0e12 thai character tho phuthao
+0e13 thai character no nen
+0e14 thai character do dek
+0e15 thai character to tao
+0e16 thai character tho thung
+0e17 thai character tho thahan
+0e18 thai character tho thong
+0e19 thai character no nu
+0e1a thai character bo baimai
+0e1b thai character po pla
+0e1c thai character pho phung
+0e1d thai character fo fa
+0e1e thai character pho phan
+0e1f thai character fo fan
+0e20 thai character pho samphao
+0e21 thai character mo ma
+0e22 thai character yo yak
+0e23 thai character ro rua
+0e24 thai character ru
+0e25 thai character lo ling
+0e26 thai character lu
+0e27 thai character wo waen
+0e28 thai character so sala
+0e29 thai character so rusi
+0e2a thai character so sua
+0e2b thai character ho hip
+0e2c thai character lo chula
+0e2d thai character o ang
+0e2e thai character ho nokhuk
+0e2f thai character paiyannoi
+0e30 thai character sara a
+0e31 thai character mai han-akat
+0e32 thai character sara aa
+0e33 thai character sara am
+0e34 thai character sara i
+0e35 thai character sara ii
+0e36 thai character sara ue
+0e37 thai character sara uee
+0e38 thai character sara u
+0e39 thai character sara uu
+0e3a thai character phinthu
+0e3f thai currency symbol baht
+0e40 thai character sara e
+0e41 thai character sara ae
+0e42 thai character sara o
+0e43 thai character sara ai maimuan
+0e44 thai character sara ai maimalai
+0e45 thai character lakkhangyao
+0e46 thai character maiyamok
+0e47 thai character maitaikhu
+0e48 thai character mai ek
+0e49 thai character mai tho
+0e4a thai character mai tri
+0e4b thai character mai chattawa
+0e4c thai character thanthakhat
+0e4d thai character nikhahit
+0e4e thai character yamakkan
+0e4f thai character fongman
+0e50 thai digit zero
+0e51 thai digit one
+0e52 thai digit two
+0e53 thai digit three
+0e54 thai digit four
+0e55 thai digit five
+0e56 thai digit six
+0e57 thai digit seven
+0e58 thai digit eight
+0e59 thai digit nine
+0e5a thai character angkhankhu
+0e5b thai character khomut
+0e81 lao letter ko
+0e82 lao letter kho sung
+0e84 lao letter kho tam
+0e87 lao letter ngo
+0e88 lao letter co
+0e8a lao letter so tam
+0e8d lao letter nyo
+0e94 lao letter do
+0e95 lao letter to
+0e96 lao letter tho sung
+0e97 lao letter tho tam
+0e99 lao letter no
+0e9a lao letter bo
+0e9b lao letter po
+0e9c lao letter pho sung
+0e9d lao letter fo tam
+0e9e lao letter pho tam
+0e9f lao letter fo sung
+0ea1 lao letter mo
+0ea2 lao letter yo
+0ea3 lao letter lo ling
+0ea5 lao letter lo loot
+0ea7 lao letter wo
+0eaa lao letter so sung
+0eab lao letter ho sung
+0ead lao letter o
+0eae lao letter ho tam
+0eaf lao ellipsis
+0eb0 lao vowel sign a
+0eb1 lao vowel sign mai kan
+0eb2 lao vowel sign aa
+0eb3 lao vowel sign am
+0eb4 lao vowel sign i
+0eb5 lao vowel sign ii
+0eb6 lao vowel sign y
+0eb7 lao vowel sign yy
+0eb8 lao vowel sign u
+0eb9 lao vowel sign uu
+0ebb lao vowel sign mai kon
+0ebc lao semivowel sign lo
+0ebd lao semivowel sign nyo
+0ec0 lao vowel sign e
+0ec1 lao vowel sign ei
+0ec2 lao vowel sign o
+0ec3 lao vowel sign ay
+0ec4 lao vowel sign ai
+0ec6 lao ko la
+0ec8 lao tone mai ek
+0ec9 lao tone mai tho
+0eca lao tone mai ti
+0ecb lao tone mai catawa
+0ecc lao cancellation mark
+0ecd lao niggahita
+0ed0 lao digit zero
+0ed1 lao digit one
+0ed2 lao digit two
+0ed3 lao digit three
+0ed4 lao digit four
+0ed5 lao digit five
+0ed6 lao digit six
+0ed7 lao digit seven
+0ed8 lao digit eight
+0ed9 lao digit nine
+0edc lao ho no
+0edd lao ho mo
+0f00 tibetan syllable om
+0f01 tibetan mark gter yig mgo truncated a
+0f02 tibetan mark gter yig mgo -um rnam bcad ma
+0f03 tibetan mark gter yig mgo -um gter tsheg ma
+0f04 tibetan mark initial yig mgo mdun ma
+0f05 tibetan mark closing yig mgo sgab ma
+0f06 tibetan mark caret yig mgo phur shad ma
+0f07 tibetan mark yig mgo tsheg shad ma
+0f08 tibetan mark sbrul shad
+0f09 tibetan mark bskur yig mgo
+0f0a tibetan mark bka- shog yig mgo
+0f0b tibetan mark intersyllabic tsheg
+0f0c tibetan mark delimiter tsheg bstar
+0f0d tibetan mark shad
+0f0e tibetan mark nyis shad
+0f0f tibetan mark tsheg shad
+0f10 tibetan mark nyis tsheg shad
+0f11 tibetan mark rin chen spungs shad
+0f12 tibetan mark rgya gram shad
+0f13 tibetan mark caret -dzud rtags me long can
+0f14 tibetan mark gter tsheg
+0f15 tibetan logotype sign chad rtags
+0f16 tibetan logotype sign lhag rtags
+0f17 tibetan astrological sign sgra gcan -char rtags
+0f18 tibetan astrological sign -khyud pa
+0f19 tibetan astrological sign sdong tshugs
+0f1a tibetan sign rdel dkar gcig
+0f1b tibetan sign rdel dkar gnyis
+0f1c tibetan sign rdel dkar gsum
+0f1d tibetan sign rdel nag gcig
+0f1e tibetan sign rdel nag gnyis
+0f1f tibetan sign rdel dkar rdel nag
+0f20 tibetan digit zero
+0f21 tibetan digit one
+0f22 tibetan digit two
+0f23 tibetan digit three
+0f24 tibetan digit four
+0f25 tibetan digit five
+0f26 tibetan digit six
+0f27 tibetan digit seven
+0f28 tibetan digit eight
+0f29 tibetan digit nine
+0f2a tibetan digit half one
+0f2b tibetan digit half two
+0f2c tibetan digit half three
+0f2d tibetan digit half four
+0f2e tibetan digit half five
+0f2f tibetan digit half six
+0f30 tibetan digit half seven
+0f31 tibetan digit half eight
+0f32 tibetan digit half nine
+0f33 tibetan digit half zero
+0f34 tibetan mark bsdus rtags
+0f35 tibetan mark ngas bzung nyi zla
+0f36 tibetan mark caret -dzud rtags bzhi mig can
+0f37 tibetan mark ngas bzung sgor rtags
+0f38 tibetan mark che mgo
+0f39 tibetan mark tsa -phru
+0f3a tibetan mark gug rtags gyon
+0f3b tibetan mark gug rtags gyas
+0f3c tibetan mark ang khang gyon
+0f3d tibetan mark ang khang gyas
+0f3e tibetan sign yar tshes
+0f3f tibetan sign mar tshes
+0f40 tibetan letter ka
+0f41 tibetan letter kha
+0f42 tibetan letter ga
+0f43 tibetan letter gha
+0f44 tibetan letter nga
+0f45 tibetan letter ca
+0f46 tibetan letter cha
+0f47 tibetan letter ja
+0f49 tibetan letter nya
+0f4a tibetan letter tta
+0f4b tibetan letter ttha
+0f4c tibetan letter dda
+0f4d tibetan letter ddha
+0f4e tibetan letter nna
+0f4f tibetan letter ta
+0f50 tibetan letter tha
+0f51 tibetan letter da
+0f52 tibetan letter dha
+0f53 tibetan letter na
+0f54 tibetan letter pa
+0f55 tibetan letter pha
+0f56 tibetan letter ba
+0f57 tibetan letter bha
+0f58 tibetan letter ma
+0f59 tibetan letter tsa
+0f5a tibetan letter tsha
+0f5b tibetan letter dza
+0f5c tibetan letter dzha
+0f5d tibetan letter wa
+0f5e tibetan letter zha
+0f5f tibetan letter za
+0f60 tibetan letter -a
+0f61 tibetan letter ya
+0f62 tibetan letter ra
+0f63 tibetan letter la
+0f64 tibetan letter sha
+0f65 tibetan letter ssa
+0f66 tibetan letter sa
+0f67 tibetan letter ha
+0f68 tibetan letter a
+0f69 tibetan letter kssa
+0f71 tibetan vowel sign aa
+0f72 tibetan vowel sign i
+0f73 tibetan vowel sign ii
+0f74 tibetan vowel sign u
+0f75 tibetan vowel sign uu
+0f76 tibetan vowel sign vocalic r
+0f77 tibetan vowel sign vocalic rr
+0f78 tibetan vowel sign vocalic l
+0f79 tibetan vowel sign vocalic ll
+0f7a tibetan vowel sign e
+0f7b tibetan vowel sign ee
+0f7c tibetan vowel sign o
+0f7d tibetan vowel sign oo
+0f7e tibetan sign rjes su nga ro
+0f7f tibetan sign rnam bcad
+0f80 tibetan vowel sign reversed i
+0f81 tibetan vowel sign reversed ii
+0f82 tibetan sign nyi zla naa da
+0f83 tibetan sign sna ldan
+0f84 tibetan mark halanta
+0f85 tibetan mark paluta
+0f86 tibetan sign lci rtags
+0f87 tibetan sign yang rtags
+0f88 tibetan sign lce tsa can
+0f89 tibetan sign mchu can
+0f8a tibetan sign gru can rgyings
+0f8b tibetan sign gru med rgyings
+0f90 tibetan subjoined letter ka
+0f91 tibetan subjoined letter kha
+0f92 tibetan subjoined letter ga
+0f93 tibetan subjoined letter gha
+0f94 tibetan subjoined letter nga
+0f95 tibetan subjoined letter ca
+0f97 tibetan subjoined letter ja
+0f99 tibetan subjoined letter nya
+0f9a tibetan subjoined letter tta
+0f9b tibetan subjoined letter ttha
+0f9c tibetan subjoined letter dda
+0f9d tibetan subjoined letter ddha
+0f9e tibetan subjoined letter nna
+0f9f tibetan subjoined letter ta
+0fa0 tibetan subjoined letter tha
+0fa1 tibetan subjoined letter da
+0fa2 tibetan subjoined letter dha
+0fa3 tibetan subjoined letter na
+0fa4 tibetan subjoined letter pa
+0fa5 tibetan subjoined letter pha
+0fa6 tibetan subjoined letter ba
+0fa7 tibetan subjoined letter bha
+0fa8 tibetan subjoined letter ma
+0fa9 tibetan subjoined letter tsa
+0faa tibetan subjoined letter tsha
+0fab tibetan subjoined letter dza
+0fac tibetan subjoined letter dzha
+0fad tibetan subjoined letter wa
+0fb1 tibetan subjoined letter ya
+0fb2 tibetan subjoined letter ra
+0fb3 tibetan subjoined letter la
+0fb4 tibetan subjoined letter sha
+0fb5 tibetan subjoined letter ssa
+0fb6 tibetan subjoined letter sa
+0fb7 tibetan subjoined letter ha
+0fb9 tibetan subjoined letter kssa
+10a0 georgian capital letter an
+10a1 georgian capital letter ban
+10a2 georgian capital letter gan
+10a3 georgian capital letter don
+10a4 georgian capital letter en
+10a5 georgian capital letter vin
+10a6 georgian capital letter zen
+10a7 georgian capital letter tan
+10a8 georgian capital letter in
+10a9 georgian capital letter kan
+10aa georgian capital letter las
+10ab georgian capital letter man
+10ac georgian capital letter nar
+10ad georgian capital letter on
+10ae georgian capital letter par
+10af georgian capital letter zhar
+10b0 georgian capital letter rae
+10b1 georgian capital letter san
+10b2 georgian capital letter tar
+10b3 georgian capital letter un
+10b4 georgian capital letter phar
+10b5 georgian capital letter khar
+10b6 georgian capital letter ghan
+10b7 georgian capital letter qar
+10b8 georgian capital letter shin
+10b9 georgian capital letter chin
+10ba georgian capital letter can
+10bb georgian capital letter jil
+10bc georgian capital letter cil
+10bd georgian capital letter char
+10be georgian capital letter xan
+10bf georgian capital letter jhan
+10c0 georgian capital letter hae
+10c1 georgian capital letter he
+10c2 georgian capital letter hie
+10c3 georgian capital letter we
+10c4 georgian capital letter har
+10c5 georgian capital letter hoe
+10d0 georgian letter an
+10d1 georgian letter ban
+10d2 georgian letter gan
+10d3 georgian letter don
+10d4 georgian letter en
+10d5 georgian letter vin
+10d6 georgian letter zen
+10d7 georgian letter tan
+10d8 georgian letter in
+10d9 georgian letter kan
+10da georgian letter las
+10db georgian letter man
+10dc georgian letter nar
+10dd georgian letter on
+10de georgian letter par
+10df georgian letter zhar
+10e0 georgian letter rae
+10e1 georgian letter san
+10e2 georgian letter tar
+10e3 georgian letter un
+10e4 georgian letter phar
+10e5 georgian letter khar
+10e6 georgian letter ghan
+10e7 georgian letter qar
+10e8 georgian letter shin
+10e9 georgian letter chin
+10ea georgian letter can
+10eb georgian letter jil
+10ec georgian letter cil
+10ed georgian letter char
+10ee georgian letter xan
+10ef georgian letter jhan
+10f0 georgian letter hae
+10f1 georgian letter he
+10f2 georgian letter hie
+10f3 georgian letter we
+10f4 georgian letter har
+10f5 georgian letter hoe
+10f6 georgian letter fi
+10fb georgian paragraph separator
+1100 hangul choseong kiyeok
+1101 hangul choseong ssangkiyeok
+1102 hangul choseong nieun
+1103 hangul choseong tikeut
+1104 hangul choseong ssangtikeut
+1105 hangul choseong rieul
+1106 hangul choseong mieum
+1107 hangul choseong pieup
+1108 hangul choseong ssangpieup
+1109 hangul choseong sios
+110a hangul choseong ssangsios
+110b hangul choseong ieung
+110c hangul choseong cieuc
+110d hangul choseong ssangcieuc
+110e hangul choseong chieuch
+110f hangul choseong khieukh
+1110 hangul choseong thieuth
+1111 hangul choseong phieuph
+1112 hangul choseong hieuh
+1113 hangul choseong nieun-kiyeok
+1114 hangul choseong ssangnieun
+1115 hangul choseong nieun-tikeut
+1116 hangul choseong nieun-pieup
+1117 hangul choseong tikeut-kiyeok
+1118 hangul choseong rieul-nieun
+1119 hangul choseong ssangrieul
+111a hangul choseong rieul-hieuh
+111b hangul choseong kapyeounrieul
+111c hangul choseong mieum-pieup
+111d hangul choseong kapyeounmieum
+111e hangul choseong pieup-kiyeok
+111f hangul choseong pieup-nieun
+1120 hangul choseong pieup-tikeut
+1121 hangul choseong pieup-sios
+1122 hangul choseong pieup-sios-kiyeok
+1123 hangul choseong pieup-sios-tikeut
+1124 hangul choseong pieup-sios-pieup
+1125 hangul choseong pieup-ssangsios
+1126 hangul choseong pieup-sios-cieuc
+1127 hangul choseong pieup-cieuc
+1128 hangul choseong pieup-chieuch
+1129 hangul choseong pieup-thieuth
+112a hangul choseong pieup-phieuph
+112b hangul choseong kapyeounpieup
+112c hangul choseong kapyeounssangpieup
+112d hangul choseong sios-kiyeok
+112e hangul choseong sios-nieun
+112f hangul choseong sios-tikeut
+1130 hangul choseong sios-rieul
+1131 hangul choseong sios-mieum
+1132 hangul choseong sios-pieup
+1133 hangul choseong sios-pieup-kiyeok
+1134 hangul choseong sios-ssangsios
+1135 hangul choseong sios-ieung
+1136 hangul choseong sios-cieuc
+1137 hangul choseong sios-chieuch
+1138 hangul choseong sios-khieukh
+1139 hangul choseong sios-thieuth
+113a hangul choseong sios-phieuph
+113b hangul choseong sios-hieuh
+113c hangul choseong chitueumsios
+113d hangul choseong chitueumssangsios
+113e hangul choseong ceongchieumsios
+113f hangul choseong ceongchieumssangsios
+1140 hangul choseong pansios
+1141 hangul choseong ieung-kiyeok
+1142 hangul choseong ieung-tikeut
+1143 hangul choseong ieung-mieum
+1144 hangul choseong ieung-pieup
+1145 hangul choseong ieung-sios
+1146 hangul choseong ieung-pansios
+1147 hangul choseong ssangieung
+1148 hangul choseong ieung-cieuc
+1149 hangul choseong ieung-chieuch
+114a hangul choseong ieung-thieuth
+114b hangul choseong ieung-phieuph
+114c hangul choseong yesieung
+114d hangul choseong cieuc-ieung
+114e hangul choseong chitueumcieuc
+114f hangul choseong chitueumssangcieuc
+1150 hangul choseong ceongchieumcieuc
+1151 hangul choseong ceongchieumssangcieuc
+1152 hangul choseong chieuch-khieukh
+1153 hangul choseong chieuch-hieuh
+1154 hangul choseong chitueumchieuch
+1155 hangul choseong ceongchieumchieuch
+1156 hangul choseong phieuph-pieup
+1157 hangul choseong kapyeounphieuph
+1158 hangul choseong ssanghieuh
+1159 hangul choseong yeorinhieuh
+115f hangul choseong filler
+1160 hangul jungseong filler
+1161 hangul jungseong a
+1162 hangul jungseong ae
+1163 hangul jungseong ya
+1164 hangul jungseong yae
+1165 hangul jungseong eo
+1166 hangul jungseong e
+1167 hangul jungseong yeo
+1168 hangul jungseong ye
+1169 hangul jungseong o
+116a hangul jungseong wa
+116b hangul jungseong wae
+116c hangul jungseong oe
+116d hangul jungseong yo
+116e hangul jungseong u
+116f hangul jungseong weo
+1170 hangul jungseong we
+1171 hangul jungseong wi
+1172 hangul jungseong yu
+1173 hangul jungseong eu
+1174 hangul jungseong yi
+1175 hangul jungseong i
+1176 hangul jungseong a-o
+1177 hangul jungseong a-u
+1178 hangul jungseong ya-o
+1179 hangul jungseong ya-yo
+117a hangul jungseong eo-o
+117b hangul jungseong eo-u
+117c hangul jungseong eo-eu
+117d hangul jungseong yeo-o
+117e hangul jungseong yeo-u
+117f hangul jungseong o-eo
+1180 hangul jungseong o-e
+1181 hangul jungseong o-ye
+1182 hangul jungseong o-o
+1183 hangul jungseong o-u
+1184 hangul jungseong yo-ya
+1185 hangul jungseong yo-yae
+1186 hangul jungseong yo-yeo
+1187 hangul jungseong yo-o
+1188 hangul jungseong yo-i
+1189 hangul jungseong u-a
+118a hangul jungseong u-ae
+118b hangul jungseong u-eo-eu
+118c hangul jungseong u-ye
+118d hangul jungseong u-u
+118e hangul jungseong yu-a
+118f hangul jungseong yu-eo
+1190 hangul jungseong yu-e
+1191 hangul jungseong yu-yeo
+1192 hangul jungseong yu-ye
+1193 hangul jungseong yu-u
+1194 hangul jungseong yu-i
+1195 hangul jungseong eu-u
+1196 hangul jungseong eu-eu
+1197 hangul jungseong yi-u
+1198 hangul jungseong i-a
+1199 hangul jungseong i-ya
+119a hangul jungseong i-o
+119b hangul jungseong i-u
+119c hangul jungseong i-eu
+119d hangul jungseong i-araea
+119e hangul jungseong araea
+119f hangul jungseong araea-eo
+11a0 hangul jungseong araea-u
+11a1 hangul jungseong araea-i
+11a2 hangul jungseong ssangaraea
+11a8 hangul jongseong kiyeok
+11a9 hangul jongseong ssangkiyeok
+11aa hangul jongseong kiyeok-sios
+11ab hangul jongseong nieun
+11ac hangul jongseong nieun-cieuc
+11ad hangul jongseong nieun-hieuh
+11ae hangul jongseong tikeut
+11af hangul jongseong rieul
+11b0 hangul jongseong rieul-kiyeok
+11b1 hangul jongseong rieul-mieum
+11b2 hangul jongseong rieul-pieup
+11b3 hangul jongseong rieul-sios
+11b4 hangul jongseong rieul-thieuth
+11b5 hangul jongseong rieul-phieuph
+11b6 hangul jongseong rieul-hieuh
+11b7 hangul jongseong mieum
+11b8 hangul jongseong pieup
+11b9 hangul jongseong pieup-sios
+11ba hangul jongseong sios
+11bb hangul jongseong ssangsios
+11bc hangul jongseong ieung
+11bd hangul jongseong cieuc
+11be hangul jongseong chieuch
+11bf hangul jongseong khieukh
+11c0 hangul jongseong thieuth
+11c1 hangul jongseong phieuph
+11c2 hangul jongseong hieuh
+11c3 hangul jongseong kiyeok-rieul
+11c4 hangul jongseong kiyeok-sios-kiyeok
+11c5 hangul jongseong nieun-kiyeok
+11c6 hangul jongseong nieun-tikeut
+11c7 hangul jongseong nieun-sios
+11c8 hangul jongseong nieun-pansios
+11c9 hangul jongseong nieun-thieuth
+11ca hangul jongseong tikeut-kiyeok
+11cb hangul jongseong tikeut-rieul
+11cc hangul jongseong rieul-kiyeok-sios
+11cd hangul jongseong rieul-nieun
+11ce hangul jongseong rieul-tikeut
+11cf hangul jongseong rieul-tikeut-hieuh
+11d0 hangul jongseong ssangrieul
+11d1 hangul jongseong rieul-mieum-kiyeok
+11d2 hangul jongseong rieul-mieum-sios
+11d3 hangul jongseong rieul-pieup-sios
+11d4 hangul jongseong rieul-pieup-hieuh
+11d5 hangul jongseong rieul-kapyeounpieup
+11d6 hangul jongseong rieul-ssangsios
+11d7 hangul jongseong rieul-pansios
+11d8 hangul jongseong rieul-khieukh
+11d9 hangul jongseong rieul-yeorinhieuh
+11da hangul jongseong mieum-kiyeok
+11db hangul jongseong mieum-rieul
+11dc hangul jongseong mieum-pieup
+11dd hangul jongseong mieum-sios
+11de hangul jongseong mieum-ssangsios
+11df hangul jongseong mieum-pansios
+11e0 hangul jongseong mieum-chieuch
+11e1 hangul jongseong mieum-hieuh
+11e2 hangul jongseong kapyeounmieum
+11e3 hangul jongseong pieup-rieul
+11e4 hangul jongseong pieup-phieuph
+11e5 hangul jongseong pieup-hieuh
+11e6 hangul jongseong kapyeounpieup
+11e7 hangul jongseong sios-kiyeok
+11e8 hangul jongseong sios-tikeut
+11e9 hangul jongseong sios-rieul
+11ea hangul jongseong sios-pieup
+11eb hangul jongseong pansios
+11ec hangul jongseong ieung-kiyeok
+11ed hangul jongseong ieung-ssangkiyeok
+11ee hangul jongseong ssangieung
+11ef hangul jongseong ieung-khieukh
+11f0 hangul jongseong yesieung
+11f1 hangul jongseong yesieung-sios
+11f2 hangul jongseong yesieung-pansios
+11f3 hangul jongseong phieuph-pieup
+11f4 hangul jongseong kapyeounphieuph
+11f5 hangul jongseong hieuh-nieun
+11f6 hangul jongseong hieuh-rieul
+11f7 hangul jongseong hieuh-mieum
+11f8 hangul jongseong hieuh-pieup
+11f9 hangul jongseong yeorinhieuh
+1e00 latin capital letter a with ring below
+1e01 latin small letter a with ring below;1e00
+1e02 latin capital letter b with dot above
+1e03 latin small letter b with dot above;1e02
+1e04 latin capital letter b with dot below
+1e05 latin small letter b with dot below;1e04
+1e06 latin capital letter b with line below
+1e07 latin small letter b with line below;1e06
+1e08 latin capital letter c with cedilla and acute
+1e09 latin small letter c with cedilla and acute;1e08
+1e0a latin capital letter d with dot above
+1e0b latin small letter d with dot above;1e0a
+1e0c latin capital letter d with dot below
+1e0d latin small letter d with dot below;1e0c
+1e0e latin capital letter d with line below
+1e0f latin small letter d with line below;1e0e
+1e10 latin capital letter d with cedilla
+1e11 latin small letter d with cedilla;1e10
+1e12 latin capital letter d with circumflex below
+1e13 latin small letter d with circumflex below;1e12
+1e14 latin capital letter e with macron and grave
+1e15 latin small letter e with macron and grave;1e14
+1e16 latin capital letter e with macron and acute
+1e17 latin small letter e with macron and acute;1e16
+1e18 latin capital letter e with circumflex below
+1e19 latin small letter e with circumflex below;1e18
+1e1a latin capital letter e with tilde below
+1e1b latin small letter e with tilde below;1e1a
+1e1c latin capital letter e with cedilla and breve
+1e1d latin small letter e with cedilla and breve;1e1c
+1e1e latin capital letter f with dot above
+1e1f latin small letter f with dot above;1e1e
+1e20 latin capital letter g with macron
+1e21 latin small letter g with macron;1e20
+1e22 latin capital letter h with dot above
+1e23 latin small letter h with dot above;1e22
+1e24 latin capital letter h with dot below
+1e25 latin small letter h with dot below;1e24
+1e26 latin capital letter h with diaeresis
+1e27 latin small letter h with diaeresis;1e26
+1e28 latin capital letter h with cedilla
+1e29 latin small letter h with cedilla;1e28
+1e2a latin capital letter h with breve below
+1e2b latin small letter h with breve below;1e2a
+1e2c latin capital letter i with tilde below
+1e2d latin small letter i with tilde below;1e2c
+1e2e latin capital letter i with diaeresis and acute
+1e2f latin small letter i with diaeresis and acute;1e2e
+1e30 latin capital letter k with acute
+1e31 latin small letter k with acute;1e30
+1e32 latin capital letter k with dot below
+1e33 latin small letter k with dot below;1e32
+1e34 latin capital letter k with line below
+1e35 latin small letter k with line below;1e34
+1e36 latin capital letter l with dot below
+1e37 latin small letter l with dot below;1e36
+1e38 latin capital letter l with dot below and macron
+1e39 latin small letter l with dot below and macron;1e38
+1e3a latin capital letter l with line below
+1e3b latin small letter l with line below;1e3a
+1e3c latin capital letter l with circumflex below
+1e3d latin small letter l with circumflex below;1e3c
+1e3e latin capital letter m with acute
+1e3f latin small letter m with acute;1e3e
+1e40 latin capital letter m with dot above
+1e41 latin small letter m with dot above;1e40
+1e42 latin capital letter m with dot below
+1e43 latin small letter m with dot below;1e42
+1e44 latin capital letter n with dot above
+1e45 latin small letter n with dot above;1e44
+1e46 latin capital letter n with dot below
+1e47 latin small letter n with dot below;1e46
+1e48 latin capital letter n with line below
+1e49 latin small letter n with line below;1e48
+1e4a latin capital letter n with circumflex below
+1e4b latin small letter n with circumflex below;1e4a
+1e4c latin capital letter o with tilde and acute
+1e4d latin small letter o with tilde and acute;1e4c
+1e4e latin capital letter o with tilde and diaeresis
+1e4f latin small letter o with tilde and diaeresis;1e4e
+1e50 latin capital letter o with macron and grave
+1e51 latin small letter o with macron and grave;1e50
+1e52 latin capital letter o with macron and acute
+1e53 latin small letter o with macron and acute;1e52
+1e54 latin capital letter p with acute
+1e55 latin small letter p with acute;1e54
+1e56 latin capital letter p with dot above
+1e57 latin small letter p with dot above;1e56
+1e58 latin capital letter r with dot above
+1e59 latin small letter r with dot above;1e58
+1e5a latin capital letter r with dot below
+1e5b latin small letter r with dot below;1e5a
+1e5c latin capital letter r with dot below and macron
+1e5d latin small letter r with dot below and macron;1e5c
+1e5e latin capital letter r with line below
+1e5f latin small letter r with line below;1e5e
+1e60 latin capital letter s with dot above
+1e61 latin small letter s with dot above;1e60
+1e62 latin capital letter s with dot below
+1e63 latin small letter s with dot below;1e62
+1e64 latin capital letter s with acute and dot above
+1e65 latin small letter s with acute and dot above;1e64
+1e66 latin capital letter s with caron and dot above
+1e67 latin small letter s with caron and dot above;1e66
+1e68 latin capital letter s with dot below and dot above
+1e69 latin small letter s with dot below and dot above;1e68
+1e6a latin capital letter t with dot above
+1e6b latin small letter t with dot above;1e6a
+1e6c latin capital letter t with dot below
+1e6d latin small letter t with dot below;1e6c
+1e6e latin capital letter t with line below
+1e6f latin small letter t with line below;1e6e
+1e70 latin capital letter t with circumflex below
+1e71 latin small letter t with circumflex below;1e70
+1e72 latin capital letter u with diaeresis below
+1e73 latin small letter u with diaeresis below;1e72
+1e74 latin capital letter u with tilde below
+1e75 latin small letter u with tilde below;1e74
+1e76 latin capital letter u with circumflex below
+1e77 latin small letter u with circumflex below;1e76
+1e78 latin capital letter u with tilde and acute
+1e79 latin small letter u with tilde and acute;1e78
+1e7a latin capital letter u with macron and diaeresis
+1e7b latin small letter u with macron and diaeresis;1e7a
+1e7c latin capital letter v with tilde
+1e7d latin small letter v with tilde;1e7c
+1e7e latin capital letter v with dot below
+1e7f latin small letter v with dot below;1e7e
+1e80 latin capital letter w with grave
+1e81 latin small letter w with grave;1e80
+1e82 latin capital letter w with acute
+1e83 latin small letter w with acute;1e82
+1e84 latin capital letter w with diaeresis
+1e85 latin small letter w with diaeresis;1e84
+1e86 latin capital letter w with dot above
+1e87 latin small letter w with dot above;1e86
+1e88 latin capital letter w with dot below
+1e89 latin small letter w with dot below;1e88
+1e8a latin capital letter x with dot above
+1e8b latin small letter x with dot above;1e8a
+1e8c latin capital letter x with diaeresis
+1e8d latin small letter x with diaeresis;1e8c
+1e8e latin capital letter y with dot above
+1e8f latin small letter y with dot above;1e8e
+1e90 latin capital letter z with circumflex
+1e91 latin small letter z with circumflex;1e90
+1e92 latin capital letter z with dot below
+1e93 latin small letter z with dot below;1e92
+1e94 latin capital letter z with line below
+1e95 latin small letter z with line below;1e94
+1e96 latin small letter h with line below
+1e97 latin small letter t with diaeresis
+1e98 latin small letter w with ring above
+1e99 latin small letter y with ring above
+1e9a latin small letter a with right half ring
+1e9b latin small letter long s with dot above
+1ea0 latin capital letter a with dot below
+1ea1 latin small letter a with dot below;1ea0
+1ea2 latin capital letter a with hook above
+1ea3 latin small letter a with hook above;1ea2
+1ea4 latin capital letter a with circumflex and acute
+1ea5 latin small letter a with circumflex and acute;1ea4
+1ea6 latin capital letter a with circumflex and grave
+1ea7 latin small letter a with circumflex and grave;1ea6
+1ea8 latin capital letter a with circumflex and hook above
+1ea9 latin small letter a with circumflex and hook above;1ea8
+1eaa latin capital letter a with circumflex and tilde
+1eab latin small letter a with circumflex and tilde;1eaa
+1eac latin capital letter a with circumflex and dot below
+1ead latin small letter a with circumflex and dot below;1eac
+1eae latin capital letter a with breve and acute
+1eaf latin small letter a with breve and acute;1eae
+1eb0 latin capital letter a with breve and grave
+1eb1 latin small letter a with breve and grave;1eb0
+1eb2 latin capital letter a with breve and hook above
+1eb3 latin small letter a with breve and hook above;1eb2
+1eb4 latin capital letter a with breve and tilde
+1eb5 latin small letter a with breve and tilde;1eb4
+1eb6 latin capital letter a with breve and dot below
+1eb7 latin small letter a with breve and dot below;1eb6
+1eb8 latin capital letter e with dot below
+1eb9 latin small letter e with dot below;1eb8
+1eba latin capital letter e with hook above
+1ebb latin small letter e with hook above;1eba
+1ebc latin capital letter e with tilde
+1ebd latin small letter e with tilde;1ebc
+1ebe latin capital letter e with circumflex and acute
+1ebf latin small letter e with circumflex and acute;1ebe
+1ec0 latin capital letter e with circumflex and grave
+1ec1 latin small letter e with circumflex and grave;1ec0
+1ec2 latin capital letter e with circumflex and hook above
+1ec3 latin small letter e with circumflex and hook above;1ec2
+1ec4 latin capital letter e with circumflex and tilde
+1ec5 latin small letter e with circumflex and tilde;1ec4
+1ec6 latin capital letter e with circumflex and dot below
+1ec7 latin small letter e with circumflex and dot below;1ec6
+1ec8 latin capital letter i with hook above
+1ec9 latin small letter i with hook above;1ec8
+1eca latin capital letter i with dot below
+1ecb latin small letter i with dot below;1eca
+1ecc latin capital letter o with dot below
+1ecd latin small letter o with dot below;1ecc
+1ece latin capital letter o with hook above
+1ecf latin small letter o with hook above;1ece
+1ed0 latin capital letter o with circumflex and acute
+1ed1 latin small letter o with circumflex and acute;1ed0
+1ed2 latin capital letter o with circumflex and grave
+1ed3 latin small letter o with circumflex and grave;1ed2
+1ed4 latin capital letter o with circumflex and hook above
+1ed5 latin small letter o with circumflex and hook above;1ed4
+1ed6 latin capital letter o with circumflex and tilde
+1ed7 latin small letter o with circumflex and tilde;1ed6
+1ed8 latin capital letter o with circumflex and dot below
+1ed9 latin small letter o with circumflex and dot below;1ed8
+1eda latin capital letter o with horn and acute
+1edb latin small letter o with horn and acute;1eda
+1edc latin capital letter o with horn and grave
+1edd latin small letter o with horn and grave;1edc
+1ede latin capital letter o with horn and hook above
+1edf latin small letter o with horn and hook above;1ede
+1ee0 latin capital letter o with horn and tilde
+1ee1 latin small letter o with horn and tilde;1ee0
+1ee2 latin capital letter o with horn and dot below
+1ee3 latin small letter o with horn and dot below;1ee2
+1ee4 latin capital letter u with dot below
+1ee5 latin small letter u with dot below;1ee4
+1ee6 latin capital letter u with hook above
+1ee7 latin small letter u with hook above;1ee6
+1ee8 latin capital letter u with horn and acute
+1ee9 latin small letter u with horn and acute;1ee8
+1eea latin capital letter u with horn and grave
+1eeb latin small letter u with horn and grave;1eea
+1eec latin capital letter u with horn and hook above
+1eed latin small letter u with horn and hook above;1eec
+1eee latin capital letter u with horn and tilde
+1eef latin small letter u with horn and tilde;1eee
+1ef0 latin capital letter u with horn and dot below
+1ef1 latin small letter u with horn and dot below;1ef0
+1ef2 latin capital letter y with grave
+1ef3 latin small letter y with grave;1ef2
+1ef4 latin capital letter y with dot below
+1ef5 latin small letter y with dot below;1ef4
+1ef6 latin capital letter y with hook above
+1ef7 latin small letter y with hook above;1ef6
+1ef8 latin capital letter y with tilde
+1ef9 latin small letter y with tilde;1ef8
+1f00 greek small letter alpha with psili;1f08
+1f01 greek small letter alpha with dasia;1f09
+1f02 greek small letter alpha with psili and varia;1f0a
+1f03 greek small letter alpha with dasia and varia;1f0b
+1f04 greek small letter alpha with psili and oxia;1f0c
+1f05 greek small letter alpha with dasia and oxia;1f0d
+1f06 greek small letter alpha with psili and perispomeni;1f0e
+1f07 greek small letter alpha with dasia and perispomeni;1f0f
+1f08 greek capital letter alpha with psili
+1f09 greek capital letter alpha with dasia
+1f0a greek capital letter alpha with psili and varia
+1f0b greek capital letter alpha with dasia and varia
+1f0c greek capital letter alpha with psili and oxia
+1f0d greek capital letter alpha with dasia and oxia
+1f0e greek capital letter alpha with psili and perispomeni
+1f0f greek capital letter alpha with dasia and perispomeni
+1f10 greek small letter epsilon with psili;1f18
+1f11 greek small letter epsilon with dasia;1f19
+1f12 greek small letter epsilon with psili and varia;1f1a
+1f13 greek small letter epsilon with dasia and varia;1f1b
+1f14 greek small letter epsilon with psili and oxia;1f1c
+1f15 greek small letter epsilon with dasia and oxia;1f1d
+1f18 greek capital letter epsilon with psili
+1f19 greek capital letter epsilon with dasia
+1f1a greek capital letter epsilon with psili and varia
+1f1b greek capital letter epsilon with dasia and varia
+1f1c greek capital letter epsilon with psili and oxia
+1f1d greek capital letter epsilon with dasia and oxia
+1f20 greek small letter eta with psili;1f28
+1f21 greek small letter eta with dasia;1f29
+1f22 greek small letter eta with psili and varia;1f2a
+1f23 greek small letter eta with dasia and varia;1f2b
+1f24 greek small letter eta with psili and oxia;1f2c
+1f25 greek small letter eta with dasia and oxia;1f2d
+1f26 greek small letter eta with psili and perispomeni;1f2e
+1f27 greek small letter eta with dasia and perispomeni;1f2f
+1f28 greek capital letter eta with psili
+1f29 greek capital letter eta with dasia
+1f2a greek capital letter eta with psili and varia
+1f2b greek capital letter eta with dasia and varia
+1f2c greek capital letter eta with psili and oxia
+1f2d greek capital letter eta with dasia and oxia
+1f2e greek capital letter eta with psili and perispomeni
+1f2f greek capital letter eta with dasia and perispomeni
+1f30 greek small letter iota with psili;1f38
+1f31 greek small letter iota with dasia;1f39
+1f32 greek small letter iota with psili and varia;1f3a
+1f33 greek small letter iota with dasia and varia;1f3b
+1f34 greek small letter iota with psili and oxia;1f3c
+1f35 greek small letter iota with dasia and oxia;1f3d
+1f36 greek small letter iota with psili and perispomeni;1f3e
+1f37 greek small letter iota with dasia and perispomeni;1f3f
+1f38 greek capital letter iota with psili
+1f39 greek capital letter iota with dasia
+1f3a greek capital letter iota with psili and varia
+1f3b greek capital letter iota with dasia and varia
+1f3c greek capital letter iota with psili and oxia
+1f3d greek capital letter iota with dasia and oxia
+1f3e greek capital letter iota with psili and perispomeni
+1f3f greek capital letter iota with dasia and perispomeni
+1f40 greek small letter omicron with psili;1f48
+1f41 greek small letter omicron with dasia;1f49
+1f42 greek small letter omicron with psili and varia;1f4a
+1f43 greek small letter omicron with dasia and varia;1f4b
+1f44 greek small letter omicron with psili and oxia;1f4c
+1f45 greek small letter omicron with dasia and oxia;1f4d
+1f48 greek capital letter omicron with psili
+1f49 greek capital letter omicron with dasia
+1f4a greek capital letter omicron with psili and varia
+1f4b greek capital letter omicron with dasia and varia
+1f4c greek capital letter omicron with psili and oxia
+1f4d greek capital letter omicron with dasia and oxia
+1f50 greek small letter upsilon with psili
+1f51 greek small letter upsilon with dasia;1f59
+1f52 greek small letter upsilon with psili and varia
+1f53 greek small letter upsilon with dasia and varia;1f5b
+1f54 greek small letter upsilon with psili and oxia
+1f55 greek small letter upsilon with dasia and oxia;1f5d
+1f56 greek small letter upsilon with psili and perispomeni
+1f57 greek small letter upsilon with dasia and perispomeni;1f5f
+1f59 greek capital letter upsilon with dasia
+1f5b greek capital letter upsilon with dasia and varia
+1f5d greek capital letter upsilon with dasia and oxia
+1f5f greek capital letter upsilon with dasia and perispomeni
+1f60 greek small letter omega with psili;1f68
+1f61 greek small letter omega with dasia;1f69
+1f62 greek small letter omega with psili and varia;1f6a
+1f63 greek small letter omega with dasia and varia;1f6b
+1f64 greek small letter omega with psili and oxia;1f6c
+1f65 greek small letter omega with dasia and oxia;1f6d
+1f66 greek small letter omega with psili and perispomeni;1f6e
+1f67 greek small letter omega with dasia and perispomeni;1f6f
+1f68 greek capital letter omega with psili
+1f69 greek capital letter omega with dasia
+1f6a greek capital letter omega with psili and varia
+1f6b greek capital letter omega with dasia and varia
+1f6c greek capital letter omega with psili and oxia
+1f6d greek capital letter omega with dasia and oxia
+1f6e greek capital letter omega with psili and perispomeni
+1f6f greek capital letter omega with dasia and perispomeni
+1f70 greek small letter alpha with varia;1fba
+1f71 greek small letter alpha with oxia;1fbb
+1f72 greek small letter epsilon with varia;1fc8
+1f73 greek small letter epsilon with oxia;1fc9
+1f74 greek small letter eta with varia;1fca
+1f75 greek small letter eta with oxia;1fcb
+1f76 greek small letter iota with varia;1fda
+1f77 greek small letter iota with oxia;1fdb
+1f78 greek small letter omicron with varia;1ff8
+1f79 greek small letter omicron with oxia;1ff9
+1f7a greek small letter upsilon with varia;1fea
+1f7b greek small letter upsilon with oxia;1feb
+1f7c greek small letter omega with varia;1ffa
+1f7d greek small letter omega with oxia;1ffb
+1f80 greek small letter alpha with psili and ypogegrammeni;1f88
+1f81 greek small letter alpha with dasia and ypogegrammeni;1f89
+1f82 greek small letter alpha with psili and varia and ypogegrammeni;1f8a
+1f83 greek small letter alpha with dasia and varia and ypogegrammeni;1f8b
+1f84 greek small letter alpha with psili and oxia and ypogegrammeni;1f8c
+1f85 greek small letter alpha with dasia and oxia and ypogegrammeni;1f8d
+1f86 greek small letter alpha with psili and perispomeni and ypogegrammeni;1f8e
+1f87 greek small letter alpha with dasia and perispomeni and ypogegrammeni;1f8f
+1f88 greek capital letter alpha with psili and prosgegrammeni
+1f89 greek capital letter alpha with dasia and prosgegrammeni
+1f8a greek capital letter alpha with psili and varia and prosgegrammeni
+1f8b greek capital letter alpha with dasia and varia and prosgegrammeni
+1f8c greek capital letter alpha with psili and oxia and prosgegrammeni
+1f8d greek capital letter alpha with dasia and oxia and prosgegrammeni
+1f8e greek capital letter alpha with psili and perispomeni and prosgegrammeni
+1f8f greek capital letter alpha with dasia and perispomeni and prosgegrammeni
+1f90 greek small letter eta with psili and ypogegrammeni;1f98
+1f91 greek small letter eta with dasia and ypogegrammeni;1f99
+1f92 greek small letter eta with psili and varia and ypogegrammeni;1f9a
+1f93 greek small letter eta with dasia and varia and ypogegrammeni;1f9b
+1f94 greek small letter eta with psili and oxia and ypogegrammeni;1f9c
+1f95 greek small letter eta with dasia and oxia and ypogegrammeni;1f9d
+1f96 greek small letter eta with psili and perispomeni and ypogegrammeni;1f9e
+1f97 greek small letter eta with dasia and perispomeni and ypogegrammeni;1f9f
+1f98 greek capital letter eta with psili and prosgegrammeni
+1f99 greek capital letter eta with dasia and prosgegrammeni
+1f9a greek capital letter eta with psili and varia and prosgegrammeni
+1f9b greek capital letter eta with dasia and varia and prosgegrammeni
+1f9c greek capital letter eta with psili and oxia and prosgegrammeni
+1f9d greek capital letter eta with dasia and oxia and prosgegrammeni
+1f9e greek capital letter eta with psili and perispomeni and prosgegrammeni
+1f9f greek capital letter eta with dasia and perispomeni and prosgegrammeni
+1fa0 greek small letter omega with psili and ypogegrammeni;1fa8
+1fa1 greek small letter omega with dasia and ypogegrammeni;1fa9
+1fa2 greek small letter omega with psili and varia and ypogegrammeni;1faa
+1fa3 greek small letter omega with dasia and varia and ypogegrammeni;1fab
+1fa4 greek small letter omega with psili and oxia and ypogegrammeni;1fac
+1fa5 greek small letter omega with dasia and oxia and ypogegrammeni;1fad
+1fa6 greek small letter omega with psili and perispomeni and ypogegrammeni;1fae
+1fa7 greek small letter omega with dasia and perispomeni and ypogegrammeni;1faf
+1fa8 greek capital letter omega with psili and prosgegrammeni
+1fa9 greek capital letter omega with dasia and prosgegrammeni
+1faa greek capital letter omega with psili and varia and prosgegrammeni
+1fab greek capital letter omega with dasia and varia and prosgegrammeni
+1fac greek capital letter omega with psili and oxia and prosgegrammeni
+1fad greek capital letter omega with dasia and oxia and prosgegrammeni
+1fae greek capital letter omega with psili and perispomeni and prosgegrammeni
+1faf greek capital letter omega with dasia and perispomeni and prosgegrammeni
+1fb0 greek small letter alpha with vrachy;1fb8
+1fb1 greek small letter alpha with macron;1fb9
+1fb2 greek small letter alpha with varia and ypogegrammeni
+1fb3 greek small letter alpha with ypogegrammeni;1fbc
+1fb4 greek small letter alpha with oxia and ypogegrammeni
+1fb6 greek small letter alpha with perispomeni
+1fb7 greek small letter alpha with perispomeni and ypogegrammeni
+1fb8 greek capital letter alpha with vrachy
+1fb9 greek capital letter alpha with macron
+1fba greek capital letter alpha with varia
+1fbb greek capital letter alpha with oxia
+1fbc greek capital letter alpha with prosgegrammeni
+1fbd greek koronis
+1fbe greek prosgegrammeni
+1fbf greek psili
+1fc0 greek perispomeni
+1fc1 greek dialytika and perispomeni
+1fc2 greek small letter eta with varia and ypogegrammeni
+1fc3 greek small letter eta with ypogegrammeni;1fcc
+1fc4 greek small letter eta with oxia and ypogegrammeni
+1fc6 greek small letter eta with perispomeni
+1fc7 greek small letter eta with perispomeni and ypogegrammeni
+1fc8 greek capital letter epsilon with varia
+1fc9 greek capital letter epsilon with oxia
+1fca greek capital letter eta with varia
+1fcb greek capital letter eta with oxia
+1fcc greek capital letter eta with prosgegrammeni
+1fcd greek psili and varia
+1fce greek psili and oxia
+1fcf greek psili and perispomeni
+1fd0 greek small letter iota with vrachy;1fd8
+1fd1 greek small letter iota with macron;1fd9
+1fd2 greek small letter iota with dialytika and varia
+1fd3 greek small letter iota with dialytika and oxia
+1fd6 greek small letter iota with perispomeni
+1fd7 greek small letter iota with dialytika and perispomeni
+1fd8 greek capital letter iota with vrachy
+1fd9 greek capital letter iota with macron
+1fda greek capital letter iota with varia
+1fdb greek capital letter iota with oxia
+1fdd greek dasia and varia
+1fde greek dasia and oxia
+1fdf greek dasia and perispomeni
+1fe0 greek small letter upsilon with vrachy;1fe8
+1fe1 greek small letter upsilon with macron;1fe9
+1fe2 greek small letter upsilon with dialytika and varia
+1fe3 greek small letter upsilon with dialytika and oxia
+1fe4 greek small letter rho with psili
+1fe5 greek small letter rho with dasia;1fec
+1fe6 greek small letter upsilon with perispomeni
+1fe7 greek small letter upsilon with dialytika and perispomeni
+1fe8 greek capital letter upsilon with vrachy
+1fe9 greek capital letter upsilon with macron
+1fea greek capital letter upsilon with varia
+1feb greek capital letter upsilon with oxia
+1fec greek capital letter rho with dasia
+1fed greek dialytika and varia
+1fee greek dialytika and oxia
+1fef greek varia
+1ff2 greek small letter omega with varia and ypogegrammeni
+1ff3 greek small letter omega with ypogegrammeni;1ffc
+1ff4 greek small letter omega with oxia and ypogegrammeni
+1ff6 greek small letter omega with perispomeni
+1ff7 greek small letter omega with perispomeni and ypogegrammeni
+1ff8 greek capital letter omicron with varia
+1ff9 greek capital letter omicron with oxia
+1ffa greek capital letter omega with varia
+1ffb greek capital letter omega with oxia
+1ffc greek capital letter omega with prosgegrammeni
+1ffd greek oxia
+1ffe greek dasia
+2000 en quad
+2001 em quad
+2002 en space
+2003 em space
+2004 three-per-em space
+2005 four-per-em space
+2006 six-per-em space
+2007 figure space
+2008 punctuation space
+2009 thin space
+200a hair space
+200b zero width space
+200c zero width non-joiner
+200d zero width joiner
+200e left-to-right mark
+200f right-to-left mark
+2010 hyphen
+2011 non-breaking hyphen
+2012 figure dash
+2013 en dash
+2014 em dash
+2015 horizontal bar
+2016 double vertical line
+2017 double low line
+2018 left single quotation mark
+2019 right single quotation mark
+201a single low-9 quotation mark
+201b single high-reversed-9 quotation mark
+201c left double quotation mark
+201d right double quotation mark
+201e double low-9 quotation mark
+201f double high-reversed-9 quotation mark
+2020 dagger
+2021 double dagger
+2022 bullet
+2023 triangular bullet
+2024 one dot leader
+2025 two dot leader
+2026 horizontal ellipsis
+2027 hyphenation point
+2028 line separator
+2029 paragraph separator
+202a left-to-right embedding
+202b right-to-left embedding
+202c pop directional formatting
+202d left-to-right override
+202e right-to-left override
+2030 per mille sign
+2031 per ten thousand sign
+2032 prime
+2033 double prime
+2034 triple prime
+2035 reversed prime
+2036 reversed double prime
+2037 reversed triple prime
+2038 caret
+2039 single left-pointing angle quotation mark
+203a single right-pointing angle quotation mark
+203b reference mark
+203c double exclamation mark
+203d interrobang
+203e overline
+203f undertie
+2040 character tie
+2041 caret insertion point
+2042 asterism
+2043 hyphen bullet
+2044 fraction slash
+2045 left square bracket with quill
+2046 right square bracket with quill
+206a inhibit symmetric swapping
+206b activate symmetric swapping
+206c inhibit arabic form shaping
+206d activate arabic form shaping
+206e national digit shapes
+206f nominal digit shapes
+2070 superscript zero
+2074 superscript four
+2075 superscript five
+2076 superscript six
+2077 superscript seven
+2078 superscript eight
+2079 superscript nine
+207a superscript plus sign
+207b superscript minus
+207c superscript equals sign
+207d superscript left parenthesis
+207e superscript right parenthesis
+207f superscript latin small letter n
+2080 subscript zero
+2081 subscript one
+2082 subscript two
+2083 subscript three
+2084 subscript four
+2085 subscript five
+2086 subscript six
+2087 subscript seven
+2088 subscript eight
+2089 subscript nine
+208a subscript plus sign
+208b subscript minus
+208c subscript equals sign
+208d subscript left parenthesis
+208e subscript right parenthesis
+20a0 euro-currency sign
+20a1 colon sign
+20a2 cruzeiro sign
+20a3 french franc sign
+20a4 lira sign
+20a5 mill sign
+20a6 naira sign
+20a7 peseta sign
+20a8 rupee sign
+20a9 won sign
+20aa new sheqel sign
+20ab dong sign
+20d0 combining left harpoon above
+20d1 combining right harpoon above
+20d2 combining long vertical line overlay
+20d3 combining short vertical line overlay
+20d4 combining anticlockwise arrow above
+20d5 combining clockwise arrow above
+20d6 combining left arrow above
+20d7 combining right arrow above
+20d8 combining ring overlay
+20d9 combining clockwise ring overlay
+20da combining anticlockwise ring overlay
+20db combining three dots above
+20dc combining four dots above
+20dd combining enclosing circle
+20de combining enclosing square
+20df combining enclosing diamond
+20e0 combining enclosing circle backslash
+20e1 combining left right arrow above
+2100 account of
+2101 addressed to the subject
+2102 double-struck capital c
+2103 degree celsius
+2104 centre line symbol
+2105 care of
+2106 cada una
+2107 euler constant
+2108 scruple
+2109 degree fahrenheit
+210a script small g
+210b script capital h
+210c black-letter capital h
+210d double-struck capital h
+210e planck constant
+210f planck constant over two pi
+2110 script capital i
+2111 black-letter capital i
+2112 script capital l
+2113 script small l
+2114 l b bar symbol
+2115 double-struck capital n
+2116 numero sign
+2117 sound recording copyright
+2118 script capital p
+2119 double-struck capital p
+211a double-struck capital q
+211b script capital r
+211c black-letter capital r
+211d double-struck capital r
+211e prescription take
+211f response
+2120 service mark
+2121 telephone sign
+2122 trade mark sign
+2123 versicle
+2124 double-struck capital z
+2125 ounce sign
+2126 ohm sign
+2127 inverted ohm sign
+2128 black-letter capital z
+2129 turned greek small letter iota
+212a kelvin sign
+212b angstrom sign
+212c script capital b
+212d black-letter capital c
+212e estimated symbol
+212f script small e
+2130 script capital e
+2131 script capital f
+2132 turned capital f
+2133 script capital m
+2134 script small o
+2135 alef symbol
+2136 bet symbol
+2137 gimel symbol
+2138 dalet symbol
+2153 vulgar fraction one third
+2154 vulgar fraction two thirds
+2155 vulgar fraction one fifth
+2156 vulgar fraction two fifths
+2157 vulgar fraction three fifths
+2158 vulgar fraction four fifths
+2159 vulgar fraction one sixth
+215a vulgar fraction five sixths
+215b vulgar fraction one eighth
+215c vulgar fraction three eighths
+215d vulgar fraction five eighths
+215e vulgar fraction seven eighths
+215f fraction numerator one
+2160 roman numeral one
+2161 roman numeral two
+2162 roman numeral three
+2163 roman numeral four
+2164 roman numeral five
+2165 roman numeral six
+2166 roman numeral seven
+2167 roman numeral eight
+2168 roman numeral nine
+2169 roman numeral ten
+216a roman numeral eleven
+216b roman numeral twelve
+216c roman numeral fifty
+216d roman numeral one hundred
+216e roman numeral five hundred
+216f roman numeral one thousand
+2170 small roman numeral one;2160
+2171 small roman numeral two;2161
+2172 small roman numeral three;2162
+2173 small roman numeral four;2163
+2174 small roman numeral five;2164
+2175 small roman numeral six;2165
+2176 small roman numeral seven;2166
+2177 small roman numeral eight;2167
+2178 small roman numeral nine;2168
+2179 small roman numeral ten;2169
+217a small roman numeral eleven;216a
+217b small roman numeral twelve;216b
+217c small roman numeral fifty;216c
+217d small roman numeral one hundred;216d
+217e small roman numeral five hundred;216e
+217f small roman numeral one thousand;216f
+2180 roman numeral one thousand c d
+2181 roman numeral five thousand
+2182 roman numeral ten thousand
+2190 leftwards arrow
+2191 upwards arrow
+2192 rightwards arrow
+2193 downwards arrow
+2194 left right arrow
+2195 up down arrow
+2196 north west arrow
+2197 north east arrow
+2198 south east arrow
+2199 south west arrow
+219a leftwards arrow with stroke
+219b rightwards arrow with stroke
+219c leftwards wave arrow
+219d rightwards wave arrow
+219e leftwards two headed arrow
+219f upwards two headed arrow
+21a0 rightwards two headed arrow
+21a1 downwards two headed arrow
+21a2 leftwards arrow with tail
+21a3 rightwards arrow with tail
+21a4 leftwards arrow from bar
+21a5 upwards arrow from bar
+21a6 rightwards arrow from bar
+21a7 downwards arrow from bar
+21a8 up down arrow with base
+21a9 leftwards arrow with hook
+21aa rightwards arrow with hook
+21ab leftwards arrow with loop
+21ac rightwards arrow with loop
+21ad left right wave arrow
+21ae left right arrow with stroke
+21af downwards zigzag arrow
+21b0 upwards arrow with tip leftwards
+21b1 upwards arrow with tip rightwards
+21b2 downwards arrow with tip leftwards
+21b3 downwards arrow with tip rightwards
+21b4 rightwards arrow with corner downwards
+21b5 downwards arrow with corner leftwards
+21b6 anticlockwise top semicircle arrow
+21b7 clockwise top semicircle arrow
+21b8 north west arrow to long bar
+21b9 leftwards arrow to bar over rightwards arrow to bar
+21ba anticlockwise open circle arrow
+21bb clockwise open circle arrow
+21bc leftwards harpoon with barb upwards
+21bd leftwards harpoon with barb downwards
+21be upwards harpoon with barb rightwards
+21bf upwards harpoon with barb leftwards
+21c0 rightwards harpoon with barb upwards
+21c1 rightwards harpoon with barb downwards
+21c2 downwards harpoon with barb rightwards
+21c3 downwards harpoon with barb leftwards
+21c4 rightwards arrow over leftwards arrow
+21c5 upwards arrow leftwards of downwards arrow
+21c6 leftwards arrow over rightwards arrow
+21c7 leftwards paired arrows
+21c8 upwards paired arrows
+21c9 rightwards paired arrows
+21ca downwards paired arrows
+21cb leftwards harpoon over rightwards harpoon
+21cc rightwards harpoon over leftwards harpoon
+21cd leftwards double arrow with stroke
+21ce left right double arrow with stroke
+21cf rightwards double arrow with stroke
+21d0 leftwards double arrow
+21d1 upwards double arrow
+21d2 rightwards double arrow
+21d3 downwards double arrow
+21d4 left right double arrow
+21d5 up down double arrow
+21d6 north west double arrow
+21d7 north east double arrow
+21d8 south east double arrow
+21d9 south west double arrow
+21da leftwards triple arrow
+21db rightwards triple arrow
+21dc leftwards squiggle arrow
+21dd rightwards squiggle arrow
+21de upwards arrow with double stroke
+21df downwards arrow with double stroke
+21e0 leftwards dashed arrow
+21e1 upwards dashed arrow
+21e2 rightwards dashed arrow
+21e3 downwards dashed arrow
+21e4 leftwards arrow to bar
+21e5 rightwards arrow to bar
+21e6 leftwards white arrow
+21e7 upwards white arrow
+21e8 rightwards white arrow
+21e9 downwards white arrow
+21ea upwards white arrow from bar
+2200 for all
+2201 complement
+2202 partial differential
+2203 there exists
+2204 there does not exist
+2205 empty set
+2206 increment
+2207 nabla
+2208 element of
+2209 not an element of
+220a small element of
+220b contains as member
+220c does not contain as member
+220d small contains as member
+220e end of proof
+220f n-ary product
+2210 n-ary coproduct
+2211 n-ary summation
+2212 minus sign
+2213 minus-or-plus sign
+2214 dot plus
+2215 division slash
+2216 set minus
+2217 asterisk operator
+2218 ring operator
+2219 bullet operator
+221a square root
+221b cube root
+221c fourth root
+221d proportional to
+221e infinity
+221f right angle
+2220 angle
+2221 measured angle
+2222 spherical angle
+2223 divides
+2224 does not divide
+2225 parallel to
+2226 not parallel to
+2227 logical and
+2228 logical or
+2229 intersection
+222a union
+222b integral
+222c double integral
+222d triple integral
+222e contour integral
+222f surface integral
+2230 volume integral
+2231 clockwise integral
+2232 clockwise contour integral
+2233 anticlockwise contour integral
+2234 therefore
+2235 because
+2236 ratio
+2237 proportion
+2238 dot minus
+2239 excess
+223a geometric proportion
+223b homothetic
+223c tilde operator
+223d reversed tilde
+223e inverted lazy s
+223f sine wave
+2240 wreath product
+2241 not tilde
+2242 minus tilde
+2243 asymptotically equal to
+2244 not asymptotically equal to
+2245 approximately equal to
+2246 approximately but not actually equal to
+2247 neither approximately nor actually equal to
+2248 almost equal to
+2249 not almost equal to
+224a almost equal or equal to
+224b triple tilde
+224c all equal to
+224d equivalent to
+224e geometrically equivalent to
+224f difference between
+2250 approaches the limit
+2251 geometrically equal to
+2252 approximately equal to or the image of
+2253 image of or approximately equal to
+2254 colon equals
+2255 equals colon
+2256 ring in equal to
+2257 ring equal to
+2258 corresponds to
+2259 estimates
+225a equiangular to
+225b star equals
+225c delta equal to
+225d equal to by definition
+225e measured by
+225f questioned equal to
+2260 not equal to
+2261 identical to
+2262 not identical to
+2263 strictly equivalent to
+2264 less-than or equal to
+2265 greater-than or equal to
+2266 less-than over equal to
+2267 greater-than over equal to
+2268 less-than but not equal to
+2269 greater-than but not equal to
+226a much less-than
+226b much greater-than
+226c between
+226d not equivalent to
+226e not less-than
+226f not greater-than
+2270 neither less-than nor equal to
+2271 neither greater-than nor equal to
+2272 less-than or equivalent to
+2273 greater-than or equivalent to
+2274 neither less-than nor equivalent to
+2275 neither greater-than nor equivalent to
+2276 less-than or greater-than
+2277 greater-than or less-than
+2278 neither less-than nor greater-than
+2279 neither greater-than nor less-than
+227a precedes
+227b succeeds
+227c precedes or equal to
+227d succeeds or equal to
+227e precedes or equivalent to
+227f succeeds or equivalent to
+2280 does not precede
+2281 does not succeed
+2282 subset of
+2283 superset of
+2284 not a subset of
+2285 not a superset of
+2286 subset of or equal to
+2287 superset of or equal to
+2288 neither a subset of nor equal to
+2289 neither a superset of nor equal to
+228a subset of with not equal to
+228b superset of with not equal to
+228c multiset
+228d multiset multiplication
+228e multiset union
+228f square image of
+2290 square original of
+2291 square image of or equal to
+2292 square original of or equal to
+2293 square cap
+2294 square cup
+2295 circled plus
+2296 circled minus
+2297 circled times
+2298 circled division slash
+2299 circled dot operator
+229a circled ring operator
+229b circled asterisk operator
+229c circled equals
+229d circled dash
+229e squared plus
+229f squared minus
+22a0 squared times
+22a1 squared dot operator
+22a2 right tack
+22a3 left tack
+22a4 down tack
+22a5 up tack
+22a6 assertion
+22a7 models
+22a8 true
+22a9 forces
+22aa triple vertical bar right turnstile
+22ab double vertical bar double right turnstile
+22ac does not prove
+22ad not true
+22ae does not force
+22af negated double vertical bar double right turnstile
+22b0 precedes under relation
+22b1 succeeds under relation
+22b2 normal subgroup of
+22b3 contains as normal subgroup
+22b4 normal subgroup of or equal to
+22b5 contains as normal subgroup or equal to
+22b6 original of
+22b7 image of
+22b8 multimap
+22b9 hermitian conjugate matrix
+22ba intercalate
+22bb xor
+22bc nand
+22bd nor
+22be right angle with arc
+22bf right triangle
+22c0 n-ary logical and
+22c1 n-ary logical or
+22c2 n-ary intersection
+22c3 n-ary union
+22c4 diamond operator
+22c5 dot operator
+22c6 star operator
+22c7 division times
+22c8 bowtie
+22c9 left normal factor semidirect product
+22ca right normal factor semidirect product
+22cb left semidirect product
+22cc right semidirect product
+22cd reversed tilde equals
+22ce curly logical or
+22cf curly logical and
+22d0 double subset
+22d1 double superset
+22d2 double intersection
+22d3 double union
+22d4 pitchfork
+22d5 equal and parallel to
+22d6 less-than with dot
+22d7 greater-than with dot
+22d8 very much less-than
+22d9 very much greater-than
+22da less-than equal to or greater-than
+22db greater-than equal to or less-than
+22dc equal to or less-than
+22dd equal to or greater-than
+22de equal to or precedes
+22df equal to or succeeds
+22e0 does not precede or equal
+22e1 does not succeed or equal
+22e2 not square image of or equal to
+22e3 not square original of or equal to
+22e4 square image of or not equal to
+22e5 square original of or not equal to
+22e6 less-than but not equivalent to
+22e7 greater-than but not equivalent to
+22e8 precedes but not equivalent to
+22e9 succeeds but not equivalent to
+22ea not normal subgroup of
+22eb does not contain as normal subgroup
+22ec not normal subgroup of or equal to
+22ed does not contain as normal subgroup or equal
+22ee vertical ellipsis
+22ef midline horizontal ellipsis
+22f0 up right diagonal ellipsis
+22f1 down right diagonal ellipsis
+2300 diameter sign
+2302 house
+2303 up arrowhead
+2304 down arrowhead
+2305 projective
+2306 perspective
+2307 wavy line
+2308 left ceiling
+2309 right ceiling
+230a left floor
+230b right floor
+230c bottom right crop
+230d bottom left crop
+230e top right crop
+230f top left crop
+2310 reversed not sign
+2311 square lozenge
+2312 arc
+2313 segment
+2314 sector
+2315 telephone recorder
+2316 position indicator
+2317 viewdata square
+2318 place of interest sign
+2319 turned not sign
+231a watch
+231b hourglass
+231c top left corner
+231d top right corner
+231e bottom left corner
+231f bottom right corner
+2320 top half integral
+2321 bottom half integral
+2322 frown
+2323 smile
+2324 up arrowhead between two horizontal bars
+2325 option key
+2326 erase to the right
+2327 x in a rectangle box
+2328 keyboard
+2329 left-pointing angle bracket
+232a right-pointing angle bracket
+232b erase to the left
+232c benzene ring
+232d cylindricity
+232e all around-profile
+232f symmetry
+2330 total runout
+2331 dimension origin
+2332 conical taper
+2333 slope
+2334 counterbore
+2335 countersink
+2336 apl functional symbol i-beam
+2337 apl functional symbol squish quad
+2338 apl functional symbol quad equal
+2339 apl functional symbol quad divide
+233a apl functional symbol quad diamond
+233b apl functional symbol quad jot
+233c apl functional symbol quad circle
+233d apl functional symbol circle stile
+233e apl functional symbol circle jot
+233f apl functional symbol slash bar
+2340 apl functional symbol backslash bar
+2341 apl functional symbol quad slash
+2342 apl functional symbol quad backslash
+2343 apl functional symbol quad less-than
+2344 apl functional symbol quad greater-than
+2345 apl functional symbol leftwards vane
+2346 apl functional symbol rightwards vane
+2347 apl functional symbol quad leftwards arrow
+2348 apl functional symbol quad rightwards arrow
+2349 apl functional symbol circle backslash
+234a apl functional symbol down tack underbar
+234b apl functional symbol delta stile
+234c apl functional symbol quad down caret
+234d apl functional symbol quad delta
+234e apl functional symbol down tack jot
+234f apl functional symbol upwards vane
+2350 apl functional symbol quad upwards arrow
+2351 apl functional symbol up tack overbar
+2352 apl functional symbol del stile
+2353 apl functional symbol quad up caret
+2354 apl functional symbol quad del
+2355 apl functional symbol up tack jot
+2356 apl functional symbol downwards vane
+2357 apl functional symbol quad downwards arrow
+2358 apl functional symbol quote underbar
+2359 apl functional symbol delta underbar
+235a apl functional symbol diamond underbar
+235b apl functional symbol jot underbar
+235c apl functional symbol circle underbar
+235d apl functional symbol up shoe jot
+235e apl functional symbol quote quad
+235f apl functional symbol circle star
+2360 apl functional symbol quad colon
+2361 apl functional symbol up tack diaeresis
+2362 apl functional symbol del diaeresis
+2363 apl functional symbol star diaeresis
+2364 apl functional symbol jot diaeresis
+2365 apl functional symbol circle diaeresis
+2366 apl functional symbol down shoe stile
+2367 apl functional symbol left shoe stile
+2368 apl functional symbol tilde diaeresis
+2369 apl functional symbol greater-than diaeresis
+236a apl functional symbol comma bar
+236b apl functional symbol del tilde
+236c apl functional symbol zilde
+236d apl functional symbol stile tilde
+236e apl functional symbol semicolon underbar
+236f apl functional symbol quad not equal
+2370 apl functional symbol quad question
+2371 apl functional symbol down caret tilde
+2372 apl functional symbol up caret tilde
+2373 apl functional symbol iota
+2374 apl functional symbol rho
+2375 apl functional symbol omega
+2376 apl functional symbol alpha underbar
+2377 apl functional symbol epsilon underbar
+2378 apl functional symbol iota underbar
+2379 apl functional symbol omega underbar
+237a apl functional symbol alpha
+2400 symbol for null
+2401 symbol for start of heading
+2402 symbol for start of text
+2403 symbol for end of text
+2404 symbol for end of transmission
+2405 symbol for enquiry
+2406 symbol for acknowledge
+2407 symbol for bell
+2408 symbol for backspace
+2409 symbol for horizontal tabulation
+240a symbol for line feed
+240b symbol for vertical tabulation
+240c symbol for form feed
+240d symbol for carriage return
+240e symbol for shift out
+240f symbol for shift in
+2410 symbol for data link escape
+2411 symbol for device control one
+2412 symbol for device control two
+2413 symbol for device control three
+2414 symbol for device control four
+2415 symbol for negative acknowledge
+2416 symbol for synchronous idle
+2417 symbol for end of transmission block
+2418 symbol for cancel
+2419 symbol for end of medium
+241a symbol for substitute
+241b symbol for escape
+241c symbol for file separator
+241d symbol for group separator
+241e symbol for record separator
+241f symbol for unit separator
+2420 symbol for space
+2421 symbol for delete
+2422 blank symbol
+2423 open box
+2424 symbol for newline
+2440 ocr hook
+2441 ocr chair
+2442 ocr fork
+2443 ocr inverted fork
+2444 ocr belt buckle
+2445 ocr bow tie
+2446 ocr branch bank identification
+2447 ocr amount of check
+2448 ocr dash
+2449 ocr customer account number
+244a ocr double backslash
+2460 circled digit one
+2461 circled digit two
+2462 circled digit three
+2463 circled digit four
+2464 circled digit five
+2465 circled digit six
+2466 circled digit seven
+2467 circled digit eight
+2468 circled digit nine
+2469 circled number ten
+246a circled number eleven
+246b circled number twelve
+246c circled number thirteen
+246d circled number fourteen
+246e circled number fifteen
+246f circled number sixteen
+2470 circled number seventeen
+2471 circled number eighteen
+2472 circled number nineteen
+2473 circled number twenty
+2474 parenthesized digit one
+2475 parenthesized digit two
+2476 parenthesized digit three
+2477 parenthesized digit four
+2478 parenthesized digit five
+2479 parenthesized digit six
+247a parenthesized digit seven
+247b parenthesized digit eight
+247c parenthesized digit nine
+247d parenthesized number ten
+247e parenthesized number eleven
+247f parenthesized number twelve
+2480 parenthesized number thirteen
+2481 parenthesized number fourteen
+2482 parenthesized number fifteen
+2483 parenthesized number sixteen
+2484 parenthesized number seventeen
+2485 parenthesized number eighteen
+2486 parenthesized number nineteen
+2487 parenthesized number twenty
+2488 digit one full stop
+2489 digit two full stop
+248a digit three full stop
+248b digit four full stop
+248c digit five full stop
+248d digit six full stop
+248e digit seven full stop
+248f digit eight full stop
+2490 digit nine full stop
+2491 number ten full stop
+2492 number eleven full stop
+2493 number twelve full stop
+2494 number thirteen full stop
+2495 number fourteen full stop
+2496 number fifteen full stop
+2497 number sixteen full stop
+2498 number seventeen full stop
+2499 number eighteen full stop
+249a number nineteen full stop
+249b number twenty full stop
+249c parenthesized latin small letter a
+249d parenthesized latin small letter b
+249e parenthesized latin small letter c
+249f parenthesized latin small letter d
+24a0 parenthesized latin small letter e
+24a1 parenthesized latin small letter f
+24a2 parenthesized latin small letter g
+24a3 parenthesized latin small letter h
+24a4 parenthesized latin small letter i
+24a5 parenthesized latin small letter j
+24a6 parenthesized latin small letter k
+24a7 parenthesized latin small letter l
+24a8 parenthesized latin small letter m
+24a9 parenthesized latin small letter n
+24aa parenthesized latin small letter o
+24ab parenthesized latin small letter p
+24ac parenthesized latin small letter q
+24ad parenthesized latin small letter r
+24ae parenthesized latin small letter s
+24af parenthesized latin small letter t
+24b0 parenthesized latin small letter u
+24b1 parenthesized latin small letter v
+24b2 parenthesized latin small letter w
+24b3 parenthesized latin small letter x
+24b4 parenthesized latin small letter y
+24b5 parenthesized latin small letter z
+24b6 circled latin capital letter a
+24b7 circled latin capital letter b
+24b8 circled latin capital letter c
+24b9 circled latin capital letter d
+24ba circled latin capital letter e
+24bb circled latin capital letter f
+24bc circled latin capital letter g
+24bd circled latin capital letter h
+24be circled latin capital letter i
+24bf circled latin capital letter j
+24c0 circled latin capital letter k
+24c1 circled latin capital letter l
+24c2 circled latin capital letter m
+24c3 circled latin capital letter n
+24c4 circled latin capital letter o
+24c5 circled latin capital letter p
+24c6 circled latin capital letter q
+24c7 circled latin capital letter r
+24c8 circled latin capital letter s
+24c9 circled latin capital letter t
+24ca circled latin capital letter u
+24cb circled latin capital letter v
+24cc circled latin capital letter w
+24cd circled latin capital letter x
+24ce circled latin capital letter y
+24cf circled latin capital letter z
+24d0 circled latin small letter a;24b6
+24d1 circled latin small letter b;24b7
+24d2 circled latin small letter c;24b8
+24d3 circled latin small letter d;24b9
+24d4 circled latin small letter e;24ba
+24d5 circled latin small letter f;24bb
+24d6 circled latin small letter g;24bc
+24d7 circled latin small letter h;24bd
+24d8 circled latin small letter i;24be
+24d9 circled latin small letter j;24bf
+24da circled latin small letter k;24c0
+24db circled latin small letter l;24c1
+24dc circled latin small letter m;24c2
+24dd circled latin small letter n;24c3
+24de circled latin small letter o;24c4
+24df circled latin small letter p;24c5
+24e0 circled latin small letter q;24c6
+24e1 circled latin small letter r;24c7
+24e2 circled latin small letter s;24c8
+24e3 circled latin small letter t;24c9
+24e4 circled latin small letter u;24ca
+24e5 circled latin small letter v;24cb
+24e6 circled latin small letter w;24cc
+24e7 circled latin small letter x;24cd
+24e8 circled latin small letter y;24ce
+24e9 circled latin small letter z;24cf
+24ea circled digit zero
+2500 box drawings light horizontal
+2501 box drawings heavy horizontal
+2502 box drawings light vertical
+2503 box drawings heavy vertical
+2504 box drawings light triple dash horizontal
+2505 box drawings heavy triple dash horizontal
+2506 box drawings light triple dash vertical
+2507 box drawings heavy triple dash vertical
+2508 box drawings light quadruple dash horizontal
+2509 box drawings heavy quadruple dash horizontal
+250a box drawings light quadruple dash vertical
+250b box drawings heavy quadruple dash vertical
+250c box drawings light down and right
+250d box drawings down light and right heavy
+250e box drawings down heavy and right light
+250f box drawings heavy down and right
+2510 box drawings light down and left
+2511 box drawings down light and left heavy
+2512 box drawings down heavy and left light
+2513 box drawings heavy down and left
+2514 box drawings light up and right
+2515 box drawings up light and right heavy
+2516 box drawings up heavy and right light
+2517 box drawings heavy up and right
+2518 box drawings light up and left
+2519 box drawings up light and left heavy
+251a box drawings up heavy and left light
+251b box drawings heavy up and left
+251c box drawings light vertical and right
+251d box drawings vertical light and right heavy
+251e box drawings up heavy and right down light
+251f box drawings down heavy and right up light
+2520 box drawings vertical heavy and right light
+2521 box drawings down light and right up heavy
+2522 box drawings up light and right down heavy
+2523 box drawings heavy vertical and right
+2524 box drawings light vertical and left
+2525 box drawings vertical light and left heavy
+2526 box drawings up heavy and left down light
+2527 box drawings down heavy and left up light
+2528 box drawings vertical heavy and left light
+2529 box drawings down light and left up heavy
+252a box drawings up light and left down heavy
+252b box drawings heavy vertical and left
+252c box drawings light down and horizontal
+252d box drawings left heavy and right down light
+252e box drawings right heavy and left down light
+252f box drawings down light and horizontal heavy
+2530 box drawings down heavy and horizontal light
+2531 box drawings right light and left down heavy
+2532 box drawings left light and right down heavy
+2533 box drawings heavy down and horizontal
+2534 box drawings light up and horizontal
+2535 box drawings left heavy and right up light
+2536 box drawings right heavy and left up light
+2537 box drawings up light and horizontal heavy
+2538 box drawings up heavy and horizontal light
+2539 box drawings right light and left up heavy
+253a box drawings left light and right up heavy
+253b box drawings heavy up and horizontal
+253c box drawings light vertical and horizontal
+253d box drawings left heavy and right vertical light
+253e box drawings right heavy and left vertical light
+253f box drawings vertical light and horizontal heavy
+2540 box drawings up heavy and down horizontal light
+2541 box drawings down heavy and up horizontal light
+2542 box drawings vertical heavy and horizontal light
+2543 box drawings left up heavy and right down light
+2544 box drawings right up heavy and left down light
+2545 box drawings left down heavy and right up light
+2546 box drawings right down heavy and left up light
+2547 box drawings down light and up horizontal heavy
+2548 box drawings up light and down horizontal heavy
+2549 box drawings right light and left vertical heavy
+254a box drawings left light and right vertical heavy
+254b box drawings heavy vertical and horizontal
+254c box drawings light double dash horizontal
+254d box drawings heavy double dash horizontal
+254e box drawings light double dash vertical
+254f box drawings heavy double dash vertical
+2550 box drawings double horizontal
+2551 box drawings double vertical
+2552 box drawings down single and right double
+2553 box drawings down double and right single
+2554 box drawings double down and right
+2555 box drawings down single and left double
+2556 box drawings down double and left single
+2557 box drawings double down and left
+2558 box drawings up single and right double
+2559 box drawings up double and right single
+255a box drawings double up and right
+255b box drawings up single and left double
+255c box drawings up double and left single
+255d box drawings double up and left
+255e box drawings vertical single and right double
+255f box drawings vertical double and right single
+2560 box drawings double vertical and right
+2561 box drawings vertical single and left double
+2562 box drawings vertical double and left single
+2563 box drawings double vertical and left
+2564 box drawings down single and horizontal double
+2565 box drawings down double and horizontal single
+2566 box drawings double down and horizontal
+2567 box drawings up single and horizontal double
+2568 box drawings up double and horizontal single
+2569 box drawings double up and horizontal
+256a box drawings vertical single and horizontal double
+256b box drawings vertical double and horizontal single
+256c box drawings double vertical and horizontal
+256d box drawings light arc down and right
+256e box drawings light arc down and left
+256f box drawings light arc up and left
+2570 box drawings light arc up and right
+2571 box drawings light diagonal upper right to lower left
+2572 box drawings light diagonal upper left to lower right
+2573 box drawings light diagonal cross
+2574 box drawings light left
+2575 box drawings light up
+2576 box drawings light right
+2577 box drawings light down
+2578 box drawings heavy left
+2579 box drawings heavy up
+257a box drawings heavy right
+257b box drawings heavy down
+257c box drawings light left and heavy right
+257d box drawings light up and heavy down
+257e box drawings heavy left and light right
+257f box drawings heavy up and light down
+2580 upper half block
+2581 lower one eighth block
+2582 lower one quarter block
+2583 lower three eighths block
+2584 lower half block
+2585 lower five eighths block
+2586 lower three quarters block
+2587 lower seven eighths block
+2588 full block
+2589 left seven eighths block
+258a left three quarters block
+258b left five eighths block
+258c left half block
+258d left three eighths block
+258e left one quarter block
+258f left one eighth block
+2590 right half block
+2591 light shade
+2592 medium shade
+2593 dark shade
+2594 upper one eighth block
+2595 right one eighth block
+25a0 black square
+25a1 white square
+25a2 white square with rounded corners
+25a3 white square containing black small square
+25a4 square with horizontal fill
+25a5 square with vertical fill
+25a6 square with orthogonal crosshatch fill
+25a7 square with upper left to lower right fill
+25a8 square with upper right to lower left fill
+25a9 square with diagonal crosshatch fill
+25aa black small square
+25ab white small square
+25ac black rectangle
+25ad white rectangle
+25ae black vertical rectangle
+25af white vertical rectangle
+25b0 black parallelogram
+25b1 white parallelogram
+25b2 black up-pointing triangle
+25b3 white up-pointing triangle
+25b4 black up-pointing small triangle
+25b5 white up-pointing small triangle
+25b6 black right-pointing triangle
+25b7 white right-pointing triangle
+25b8 black right-pointing small triangle
+25b9 white right-pointing small triangle
+25ba black right-pointing pointer
+25bb white right-pointing pointer
+25bc black down-pointing triangle
+25bd white down-pointing triangle
+25be black down-pointing small triangle
+25bf white down-pointing small triangle
+25c0 black left-pointing triangle
+25c1 white left-pointing triangle
+25c2 black left-pointing small triangle
+25c3 white left-pointing small triangle
+25c4 black left-pointing pointer
+25c5 white left-pointing pointer
+25c6 black diamond
+25c7 white diamond
+25c8 white diamond containing black small diamond
+25c9 fisheye
+25ca lozenge
+25cb white circle
+25cc dotted circle
+25cd circle with vertical fill
+25ce bullseye
+25cf black circle
+25d0 circle with left half black
+25d1 circle with right half black
+25d2 circle with lower half black
+25d3 circle with upper half black
+25d4 circle with upper right quadrant black
+25d5 circle with all but upper left quadrant black
+25d6 left half black circle
+25d7 right half black circle
+25d8 inverse bullet
+25d9 inverse white circle
+25da upper half inverse white circle
+25db lower half inverse white circle
+25dc upper left quadrant circular arc
+25dd upper right quadrant circular arc
+25de lower right quadrant circular arc
+25df lower left quadrant circular arc
+25e0 upper half circle
+25e1 lower half circle
+25e2 black lower right triangle
+25e3 black lower left triangle
+25e4 black upper left triangle
+25e5 black upper right triangle
+25e6 white bullet
+25e7 square with left half black
+25e8 square with right half black
+25e9 square with upper left diagonal half black
+25ea square with lower right diagonal half black
+25eb white square with vertical bisecting line
+25ec white up-pointing triangle with dot
+25ed up-pointing triangle with left half black
+25ee up-pointing triangle with right half black
+25ef large circle
+2600 black sun with rays
+2601 cloud
+2602 umbrella
+2603 snowman
+2604 comet
+2605 black star
+2606 white star
+2607 lightning
+2608 thunderstorm
+2609 sun
+260a ascending node
+260b descending node
+260c conjunction
+260d opposition
+260e black telephone
+260f white telephone
+2610 ballot box
+2611 ballot box with check
+2612 ballot box with x
+2613 saltire
+261a black left pointing index
+261b black right pointing index
+261c white left pointing index
+261d white up pointing index
+261e white right pointing index
+261f white down pointing index
+2620 skull and crossbones
+2621 caution sign
+2622 radioactive sign
+2623 biohazard sign
+2624 caduceus
+2625 ankh
+2626 orthodox cross
+2627 chi rho
+2628 cross of lorraine
+2629 cross of jerusalem
+262a star and crescent
+262b farsi symbol
+262c adi shakti
+262d hammer and sickle
+262e peace symbol
+262f yin yang
+2630 trigram for heaven
+2631 trigram for lake
+2632 trigram for fire
+2633 trigram for thunder
+2634 trigram for wind
+2635 trigram for water
+2636 trigram for mountain
+2637 trigram for earth
+2638 wheel of dharma
+2639 white frowning face
+263a white smiling face
+263b black smiling face
+263c white sun with rays
+263d first quarter moon
+263e last quarter moon
+263f mercury
+2640 female sign
+2641 earth
+2642 male sign
+2643 jupiter
+2644 saturn
+2645 uranus
+2646 neptune
+2647 pluto
+2648 aries
+2649 taurus
+264a gemini
+264b cancer
+264c leo
+264d virgo
+264e libra
+264f scorpius
+2650 sagittarius
+2651 capricorn
+2652 aquarius
+2653 pisces
+2654 white chess king
+2655 white chess queen
+2656 white chess rook
+2657 white chess bishop
+2658 white chess knight
+2659 white chess pawn
+265a black chess king
+265b black chess queen
+265c black chess rook
+265d black chess bishop
+265e black chess knight
+265f black chess pawn
+2660 black spade suit
+2661 white heart suit
+2662 white diamond suit
+2663 black club suit
+2664 white spade suit
+2665 black heart suit
+2666 black diamond suit
+2667 white club suit
+2668 hot springs
+2669 quarter note
+266a eighth note
+266b beamed eighth notes
+266c beamed sixteenth notes
+266d music flat sign
+266e music natural sign
+266f music sharp sign
+2701 upper blade scissors
+2702 black scissors
+2703 lower blade scissors
+2704 white scissors
+2706 telephone location sign
+2707 tape drive
+2708 airplane
+2709 envelope
+270c victory hand
+270d writing hand
+270e lower right pencil
+270f pencil
+2710 upper right pencil
+2711 white nib
+2712 black nib
+2713 check mark
+2714 heavy check mark
+2715 multiplication x
+2716 heavy multiplication x
+2717 ballot x
+2718 heavy ballot x
+2719 outlined greek cross
+271a heavy greek cross
+271b open centre cross
+271c heavy open centre cross
+271d latin cross
+271e shadowed white latin cross
+271f outlined latin cross
+2720 maltese cross
+2721 star of david
+2722 four teardrop-spoked asterisk
+2723 four balloon-spoked asterisk
+2724 heavy four balloon-spoked asterisk
+2725 four club-spoked asterisk
+2726 black four pointed star
+2727 white four pointed star
+2729 stress outlined white star
+272a circled white star
+272b open centre black star
+272c black centre white star
+272d outlined black star
+272e heavy outlined black star
+272f pinwheel star
+2730 shadowed white star
+2731 heavy asterisk
+2732 open centre asterisk
+2733 eight spoked asterisk
+2734 eight pointed black star
+2735 eight pointed pinwheel star
+2736 six pointed black star
+2737 eight pointed rectilinear black star
+2738 heavy eight pointed rectilinear black star
+2739 twelve pointed black star
+273a sixteen pointed asterisk
+273b teardrop-spoked asterisk
+273c open centre teardrop-spoked asterisk
+273d heavy teardrop-spoked asterisk
+273e six petalled black and white florette
+273f black florette
+2740 white florette
+2741 eight petalled outlined black florette
+2742 circled open centre eight pointed star
+2743 heavy teardrop-spoked pinwheel asterisk
+2744 snowflake
+2745 tight trifoliate snowflake
+2746 heavy chevron snowflake
+2747 sparkle
+2748 heavy sparkle
+2749 balloon-spoked asterisk
+274a eight teardrop-spoked propeller asterisk
+274b heavy eight teardrop-spoked propeller asterisk
+274d shadowed white circle
+274f lower right drop-shadowed white square
+2750 upper right drop-shadowed white square
+2751 lower right shadowed white square
+2752 upper right shadowed white square
+2756 black diamond minus white x
+2758 light vertical bar
+2759 medium vertical bar
+275a heavy vertical bar
+275b heavy single turned comma quotation mark ornament
+275c heavy single comma quotation mark ornament
+275d heavy double turned comma quotation mark ornament
+275e heavy double comma quotation mark ornament
+2761 curved stem paragraph sign ornament
+2762 heavy exclamation mark ornament
+2763 heavy heart exclamation mark ornament
+2764 heavy black heart
+2765 rotated heavy black heart bullet
+2766 floral heart
+2767 rotated floral heart bullet
+2776 dingbat negative circled digit one
+2777 dingbat negative circled digit two
+2778 dingbat negative circled digit three
+2779 dingbat negative circled digit four
+277a dingbat negative circled digit five
+277b dingbat negative circled digit six
+277c dingbat negative circled digit seven
+277d dingbat negative circled digit eight
+277e dingbat negative circled digit nine
+277f dingbat negative circled number ten
+2780 dingbat circled sans-serif digit one
+2781 dingbat circled sans-serif digit two
+2782 dingbat circled sans-serif digit three
+2783 dingbat circled sans-serif digit four
+2784 dingbat circled sans-serif digit five
+2785 dingbat circled sans-serif digit six
+2786 dingbat circled sans-serif digit seven
+2787 dingbat circled sans-serif digit eight
+2788 dingbat circled sans-serif digit nine
+2789 dingbat circled sans-serif number ten
+278a dingbat negative circled sans-serif digit one
+278b dingbat negative circled sans-serif digit two
+278c dingbat negative circled sans-serif digit three
+278d dingbat negative circled sans-serif digit four
+278e dingbat negative circled sans-serif digit five
+278f dingbat negative circled sans-serif digit six
+2790 dingbat negative circled sans-serif digit seven
+2791 dingbat negative circled sans-serif digit eight
+2792 dingbat negative circled sans-serif digit nine
+2793 dingbat negative circled sans-serif number ten
+2794 heavy wide-headed rightwards arrow
+2798 heavy south east arrow
+2799 heavy rightwards arrow
+279a heavy north east arrow
+279b drafting point rightwards arrow
+279c heavy round-tipped rightwards arrow
+279d triangle-headed rightwards arrow
+279e heavy triangle-headed rightwards arrow
+279f dashed triangle-headed rightwards arrow
+27a0 heavy dashed triangle-headed rightwards arrow
+27a1 black rightwards arrow
+27a2 three-d top-lighted rightwards arrowhead
+27a3 three-d bottom-lighted rightwards arrowhead
+27a4 black rightwards arrowhead
+27a5 heavy black curved downwards and rightwards arrow
+27a6 heavy black curved upwards and rightwards arrow
+27a7 squat black rightwards arrow
+27a8 heavy concave-pointed black rightwards arrow
+27a9 right-shaded white rightwards arrow
+27aa left-shaded white rightwards arrow
+27ab back-tilted shadowed white rightwards arrow
+27ac front-tilted shadowed white rightwards arrow
+27ad heavy lower right-shadowed white rightwards arrow
+27ae heavy upper right-shadowed white rightwards arrow
+27af notched lower right-shadowed white rightwards arrow
+27b1 notched upper right-shadowed white rightwards arrow
+27b2 circled heavy white rightwards arrow
+27b3 white-feathered rightwards arrow
+27b4 black-feathered south east arrow
+27b5 black-feathered rightwards arrow
+27b6 black-feathered north east arrow
+27b7 heavy black-feathered south east arrow
+27b8 heavy black-feathered rightwards arrow
+27b9 heavy black-feathered north east arrow
+27ba teardrop-barbed rightwards arrow
+27bb heavy teardrop-shanked rightwards arrow
+27bc wedge-tailed rightwards arrow
+27bd heavy wedge-tailed rightwards arrow
+27be open-outlined rightwards arrow
+3000 ideographic space
+3001 ideographic comma
+3002 ideographic full stop
+3003 ditto mark
+3004 japanese industrial standard symbol
+3005 ideographic iteration mark
+3006 ideographic closing mark
+3007 ideographic number zero
+3008 left angle bracket
+3009 right angle bracket
+300a left double angle bracket
+300b right double angle bracket
+300c left corner bracket
+300d right corner bracket
+300e left white corner bracket
+300f right white corner bracket
+3010 left black lenticular bracket
+3011 right black lenticular bracket
+3012 postal mark
+3013 geta mark
+3014 left tortoise shell bracket
+3015 right tortoise shell bracket
+3016 left white lenticular bracket
+3017 right white lenticular bracket
+3018 left white tortoise shell bracket
+3019 right white tortoise shell bracket
+301a left white square bracket
+301b right white square bracket
+301c wave dash
+301d reversed double prime quotation mark
+301e double prime quotation mark
+301f low double prime quotation mark
+3020 postal mark face
+3021 hangzhou numeral one
+3022 hangzhou numeral two
+3023 hangzhou numeral three
+3024 hangzhou numeral four
+3025 hangzhou numeral five
+3026 hangzhou numeral six
+3027 hangzhou numeral seven
+3028 hangzhou numeral eight
+3029 hangzhou numeral nine
+302a ideographic level tone mark
+302b ideographic rising tone mark
+302c ideographic departing tone mark
+302d ideographic entering tone mark
+302e hangul single dot tone mark
+302f hangul double dot tone mark
+3030 wavy dash
+3031 vertical kana repeat mark
+3032 vertical kana repeat with voiced sound mark
+3033 vertical kana repeat mark upper half
+3034 vertical kana repeat with voiced sound mark upper half
+3035 vertical kana repeat mark lower half
+3036 circled postal mark
+3037 ideographic telegraph line feed separator symbol
+303f ideographic half fill space
+3041 hiragana letter small a
+3042 hiragana letter a
+3043 hiragana letter small i
+3044 hiragana letter i
+3045 hiragana letter small u
+3046 hiragana letter u
+3047 hiragana letter small e
+3048 hiragana letter e
+3049 hiragana letter small o
+304a hiragana letter o
+304b hiragana letter ka
+304c hiragana letter ga
+304d hiragana letter ki
+304e hiragana letter gi
+304f hiragana letter ku
+3050 hiragana letter gu
+3051 hiragana letter ke
+3052 hiragana letter ge
+3053 hiragana letter ko
+3054 hiragana letter go
+3055 hiragana letter sa
+3056 hiragana letter za
+3057 hiragana letter si
+3058 hiragana letter zi
+3059 hiragana letter su
+305a hiragana letter zu
+305b hiragana letter se
+305c hiragana letter ze
+305d hiragana letter so
+305e hiragana letter zo
+305f hiragana letter ta
+3060 hiragana letter da
+3061 hiragana letter ti
+3062 hiragana letter di
+3063 hiragana letter small tu
+3064 hiragana letter tu
+3065 hiragana letter du
+3066 hiragana letter te
+3067 hiragana letter de
+3068 hiragana letter to
+3069 hiragana letter do
+306a hiragana letter na
+306b hiragana letter ni
+306c hiragana letter nu
+306d hiragana letter ne
+306e hiragana letter no
+306f hiragana letter ha
+3070 hiragana letter ba
+3071 hiragana letter pa
+3072 hiragana letter hi
+3073 hiragana letter bi
+3074 hiragana letter pi
+3075 hiragana letter hu
+3076 hiragana letter bu
+3077 hiragana letter pu
+3078 hiragana letter he
+3079 hiragana letter be
+307a hiragana letter pe
+307b hiragana letter ho
+307c hiragana letter bo
+307d hiragana letter po
+307e hiragana letter ma
+307f hiragana letter mi
+3080 hiragana letter mu
+3081 hiragana letter me
+3082 hiragana letter mo
+3083 hiragana letter small ya
+3084 hiragana letter ya
+3085 hiragana letter small yu
+3086 hiragana letter yu
+3087 hiragana letter small yo
+3088 hiragana letter yo
+3089 hiragana letter ra
+308a hiragana letter ri
+308b hiragana letter ru
+308c hiragana letter re
+308d hiragana letter ro
+308e hiragana letter small wa
+308f hiragana letter wa
+3090 hiragana letter wi
+3091 hiragana letter we
+3092 hiragana letter wo
+3093 hiragana letter n
+3094 hiragana letter vu
+3099 combining katakana-hiragana voiced sound mark
+309a combining katakana-hiragana semi-voiced sound mark
+309b katakana-hiragana voiced sound mark
+309c katakana-hiragana semi-voiced sound mark
+309d hiragana iteration mark
+309e hiragana voiced iteration mark
+30a1 katakana letter small a
+30a2 katakana letter a
+30a3 katakana letter small i
+30a4 katakana letter i
+30a5 katakana letter small u
+30a6 katakana letter u
+30a7 katakana letter small e
+30a8 katakana letter e
+30a9 katakana letter small o
+30aa katakana letter o
+30ab katakana letter ka
+30ac katakana letter ga
+30ad katakana letter ki
+30ae katakana letter gi
+30af katakana letter ku
+30b0 katakana letter gu
+30b1 katakana letter ke
+30b2 katakana letter ge
+30b3 katakana letter ko
+30b4 katakana letter go
+30b5 katakana letter sa
+30b6 katakana letter za
+30b7 katakana letter si
+30b8 katakana letter zi
+30b9 katakana letter su
+30ba katakana letter zu
+30bb katakana letter se
+30bc katakana letter ze
+30bd katakana letter so
+30be katakana letter zo
+30bf katakana letter ta
+30c0 katakana letter da
+30c1 katakana letter ti
+30c2 katakana letter di
+30c3 katakana letter small tu
+30c4 katakana letter tu
+30c5 katakana letter du
+30c6 katakana letter te
+30c7 katakana letter de
+30c8 katakana letter to
+30c9 katakana letter do
+30ca katakana letter na
+30cb katakana letter ni
+30cc katakana letter nu
+30cd katakana letter ne
+30ce katakana letter no
+30cf katakana letter ha
+30d0 katakana letter ba
+30d1 katakana letter pa
+30d2 katakana letter hi
+30d3 katakana letter bi
+30d4 katakana letter pi
+30d5 katakana letter hu
+30d6 katakana letter bu
+30d7 katakana letter pu
+30d8 katakana letter he
+30d9 katakana letter be
+30da katakana letter pe
+30db katakana letter ho
+30dc katakana letter bo
+30dd katakana letter po
+30de katakana letter ma
+30df katakana letter mi
+30e0 katakana letter mu
+30e1 katakana letter me
+30e2 katakana letter mo
+30e3 katakana letter small ya
+30e4 katakana letter ya
+30e5 katakana letter small yu
+30e6 katakana letter yu
+30e7 katakana letter small yo
+30e8 katakana letter yo
+30e9 katakana letter ra
+30ea katakana letter ri
+30eb katakana letter ru
+30ec katakana letter re
+30ed katakana letter ro
+30ee katakana letter small wa
+30ef katakana letter wa
+30f0 katakana letter wi
+30f1 katakana letter we
+30f2 katakana letter wo
+30f3 katakana letter n
+30f4 katakana letter vu
+30f5 katakana letter small ka
+30f6 katakana letter small ke
+30f7 katakana letter va
+30f8 katakana letter vi
+30f9 katakana letter ve
+30fa katakana letter vo
+30fb katakana middle dot
+30fc katakana-hiragana prolonged sound mark
+30fd katakana iteration mark
+30fe katakana voiced iteration mark
+3105 bopomofo letter b
+3106 bopomofo letter p
+3107 bopomofo letter m
+3108 bopomofo letter f
+3109 bopomofo letter d
+310a bopomofo letter t
+310b bopomofo letter n
+310c bopomofo letter l
+310d bopomofo letter g
+310e bopomofo letter k
+310f bopomofo letter h
+3110 bopomofo letter j
+3111 bopomofo letter q
+3112 bopomofo letter x
+3113 bopomofo letter zh
+3114 bopomofo letter ch
+3115 bopomofo letter sh
+3116 bopomofo letter r
+3117 bopomofo letter z
+3118 bopomofo letter c
+3119 bopomofo letter s
+311a bopomofo letter a
+311b bopomofo letter o
+311c bopomofo letter e
+311d bopomofo letter eh
+311e bopomofo letter ai
+311f bopomofo letter ei
+3120 bopomofo letter au
+3121 bopomofo letter ou
+3122 bopomofo letter an
+3123 bopomofo letter en
+3124 bopomofo letter ang
+3125 bopomofo letter eng
+3126 bopomofo letter er
+3127 bopomofo letter i
+3128 bopomofo letter u
+3129 bopomofo letter iu
+312a bopomofo letter v
+312b bopomofo letter ng
+312c bopomofo letter gn
+3131 hangul letter kiyeok
+3132 hangul letter ssangkiyeok
+3133 hangul letter kiyeok-sios
+3134 hangul letter nieun
+3135 hangul letter nieun-cieuc
+3136 hangul letter nieun-hieuh
+3137 hangul letter tikeut
+3138 hangul letter ssangtikeut
+3139 hangul letter rieul
+313a hangul letter rieul-kiyeok
+313b hangul letter rieul-mieum
+313c hangul letter rieul-pieup
+313d hangul letter rieul-sios
+313e hangul letter rieul-thieuth
+313f hangul letter rieul-phieuph
+3140 hangul letter rieul-hieuh
+3141 hangul letter mieum
+3142 hangul letter pieup
+3143 hangul letter ssangpieup
+3144 hangul letter pieup-sios
+3145 hangul letter sios
+3146 hangul letter ssangsios
+3147 hangul letter ieung
+3148 hangul letter cieuc
+3149 hangul letter ssangcieuc
+314a hangul letter chieuch
+314b hangul letter khieukh
+314c hangul letter thieuth
+314d hangul letter phieuph
+314e hangul letter hieuh
+314f hangul letter a
+3150 hangul letter ae
+3151 hangul letter ya
+3152 hangul letter yae
+3153 hangul letter eo
+3154 hangul letter e
+3155 hangul letter yeo
+3156 hangul letter ye
+3157 hangul letter o
+3158 hangul letter wa
+3159 hangul letter wae
+315a hangul letter oe
+315b hangul letter yo
+315c hangul letter u
+315d hangul letter weo
+315e hangul letter we
+315f hangul letter wi
+3160 hangul letter yu
+3161 hangul letter eu
+3162 hangul letter yi
+3163 hangul letter i
+3164 hangul filler
+3165 hangul letter ssangnieun
+3166 hangul letter nieun-tikeut
+3167 hangul letter nieun-sios
+3168 hangul letter nieun-pansios
+3169 hangul letter rieul-kiyeok-sios
+316a hangul letter rieul-tikeut
+316b hangul letter rieul-pieup-sios
+316c hangul letter rieul-pansios
+316d hangul letter rieul-yeorinhieuh
+316e hangul letter mieum-pieup
+316f hangul letter mieum-sios
+3170 hangul letter mieum-pansios
+3171 hangul letter kapyeounmieum
+3172 hangul letter pieup-kiyeok
+3173 hangul letter pieup-tikeut
+3174 hangul letter pieup-sios-kiyeok
+3175 hangul letter pieup-sios-tikeut
+3176 hangul letter pieup-cieuc
+3177 hangul letter pieup-thieuth
+3178 hangul letter kapyeounpieup
+3179 hangul letter kapyeounssangpieup
+317a hangul letter sios-kiyeok
+317b hangul letter sios-nieun
+317c hangul letter sios-tikeut
+317d hangul letter sios-pieup
+317e hangul letter sios-cieuc
+317f hangul letter pansios
+3180 hangul letter ssangieung
+3181 hangul letter yesieung
+3182 hangul letter yesieung-sios
+3183 hangul letter yesieung-pansios
+3184 hangul letter kapyeounphieuph
+3185 hangul letter ssanghieuh
+3186 hangul letter yeorinhieuh
+3187 hangul letter yo-ya
+3188 hangul letter yo-yae
+3189 hangul letter yo-i
+318a hangul letter yu-yeo
+318b hangul letter yu-ye
+318c hangul letter yu-i
+318d hangul letter araea
+318e hangul letter araeae
+3190 ideographic annotation linking mark
+3191 ideographic annotation reverse mark
+3192 ideographic annotation one mark
+3193 ideographic annotation two mark
+3194 ideographic annotation three mark
+3195 ideographic annotation four mark
+3196 ideographic annotation top mark
+3197 ideographic annotation middle mark
+3198 ideographic annotation bottom mark
+3199 ideographic annotation first mark
+319a ideographic annotation second mark
+319b ideographic annotation third mark
+319c ideographic annotation fourth mark
+319d ideographic annotation heaven mark
+319e ideographic annotation earth mark
+319f ideographic annotation man mark
+3200 parenthesized hangul kiyeok
+3201 parenthesized hangul nieun
+3202 parenthesized hangul tikeut
+3203 parenthesized hangul rieul
+3204 parenthesized hangul mieum
+3205 parenthesized hangul pieup
+3206 parenthesized hangul sios
+3207 parenthesized hangul ieung
+3208 parenthesized hangul cieuc
+3209 parenthesized hangul chieuch
+320a parenthesized hangul khieukh
+320b parenthesized hangul thieuth
+320c parenthesized hangul phieuph
+320d parenthesized hangul hieuh
+320e parenthesized hangul kiyeok a
+320f parenthesized hangul nieun a
+3210 parenthesized hangul tikeut a
+3211 parenthesized hangul rieul a
+3212 parenthesized hangul mieum a
+3213 parenthesized hangul pieup a
+3214 parenthesized hangul sios a
+3215 parenthesized hangul ieung a
+3216 parenthesized hangul cieuc a
+3217 parenthesized hangul chieuch a
+3218 parenthesized hangul khieukh a
+3219 parenthesized hangul thieuth a
+321a parenthesized hangul phieuph a
+321b parenthesized hangul hieuh a
+321c parenthesized hangul cieuc u
+3220 parenthesized ideograph one
+3221 parenthesized ideograph two
+3222 parenthesized ideograph three
+3223 parenthesized ideograph four
+3224 parenthesized ideograph five
+3225 parenthesized ideograph six
+3226 parenthesized ideograph seven
+3227 parenthesized ideograph eight
+3228 parenthesized ideograph nine
+3229 parenthesized ideograph ten
+322a parenthesized ideograph moon
+322b parenthesized ideograph fire
+322c parenthesized ideograph water
+322d parenthesized ideograph wood
+322e parenthesized ideograph metal
+322f parenthesized ideograph earth
+3230 parenthesized ideograph sun
+3231 parenthesized ideograph stock
+3232 parenthesized ideograph have
+3233 parenthesized ideograph society
+3234 parenthesized ideograph name
+3235 parenthesized ideograph special
+3236 parenthesized ideograph financial
+3237 parenthesized ideograph congratulation
+3238 parenthesized ideograph labor
+3239 parenthesized ideograph represent
+323a parenthesized ideograph call
+323b parenthesized ideograph study
+323c parenthesized ideograph supervise
+323d parenthesized ideograph enterprise
+323e parenthesized ideograph resource
+323f parenthesized ideograph alliance
+3240 parenthesized ideograph festival
+3241 parenthesized ideograph rest
+3242 parenthesized ideograph self
+3243 parenthesized ideograph reach
+3260 circled hangul kiyeok
+3261 circled hangul nieun
+3262 circled hangul tikeut
+3263 circled hangul rieul
+3264 circled hangul mieum
+3265 circled hangul pieup
+3266 circled hangul sios
+3267 circled hangul ieung
+3268 circled hangul cieuc
+3269 circled hangul chieuch
+326a circled hangul khieukh
+326b circled hangul thieuth
+326c circled hangul phieuph
+326d circled hangul hieuh
+326e circled hangul kiyeok a
+326f circled hangul nieun a
+3270 circled hangul tikeut a
+3271 circled hangul rieul a
+3272 circled hangul mieum a
+3273 circled hangul pieup a
+3274 circled hangul sios a
+3275 circled hangul ieung a
+3276 circled hangul cieuc a
+3277 circled hangul chieuch a
+3278 circled hangul khieukh a
+3279 circled hangul thieuth a
+327a circled hangul phieuph a
+327b circled hangul hieuh a
+327f korean standard symbol
+3280 circled ideograph one
+3281 circled ideograph two
+3282 circled ideograph three
+3283 circled ideograph four
+3284 circled ideograph five
+3285 circled ideograph six
+3286 circled ideograph seven
+3287 circled ideograph eight
+3288 circled ideograph nine
+3289 circled ideograph ten
+328a circled ideograph moon
+328b circled ideograph fire
+328c circled ideograph water
+328d circled ideograph wood
+328e circled ideograph metal
+328f circled ideograph earth
+3290 circled ideograph sun
+3291 circled ideograph stock
+3292 circled ideograph have
+3293 circled ideograph society
+3294 circled ideograph name
+3295 circled ideograph special
+3296 circled ideograph financial
+3297 circled ideograph congratulation
+3298 circled ideograph labor
+3299 circled ideograph secret
+329a circled ideograph male
+329b circled ideograph female
+329c circled ideograph suitable
+329d circled ideograph excellent
+329e circled ideograph print
+329f circled ideograph attention
+32a0 circled ideograph item
+32a1 circled ideograph rest
+32a2 circled ideograph copy
+32a3 circled ideograph correct
+32a4 circled ideograph high
+32a5 circled ideograph centre
+32a6 circled ideograph low
+32a7 circled ideograph left
+32a8 circled ideograph right
+32a9 circled ideograph medicine
+32aa circled ideograph religion
+32ab circled ideograph study
+32ac circled ideograph supervise
+32ad circled ideograph enterprise
+32ae circled ideograph resource
+32af circled ideograph alliance
+32b0 circled ideograph night
+32c0 ideographic telegraph symbol for january
+32c1 ideographic telegraph symbol for february
+32c2 ideographic telegraph symbol for march
+32c3 ideographic telegraph symbol for april
+32c4 ideographic telegraph symbol for may
+32c5 ideographic telegraph symbol for june
+32c6 ideographic telegraph symbol for july
+32c7 ideographic telegraph symbol for august
+32c8 ideographic telegraph symbol for september
+32c9 ideographic telegraph symbol for october
+32ca ideographic telegraph symbol for november
+32cb ideographic telegraph symbol for december
+32d0 circled katakana a
+32d1 circled katakana i
+32d2 circled katakana u
+32d3 circled katakana e
+32d4 circled katakana o
+32d5 circled katakana ka
+32d6 circled katakana ki
+32d7 circled katakana ku
+32d8 circled katakana ke
+32d9 circled katakana ko
+32da circled katakana sa
+32db circled katakana si
+32dc circled katakana su
+32dd circled katakana se
+32de circled katakana so
+32df circled katakana ta
+32e0 circled katakana ti
+32e1 circled katakana tu
+32e2 circled katakana te
+32e3 circled katakana to
+32e4 circled katakana na
+32e5 circled katakana ni
+32e6 circled katakana nu
+32e7 circled katakana ne
+32e8 circled katakana no
+32e9 circled katakana ha
+32ea circled katakana hi
+32eb circled katakana hu
+32ec circled katakana he
+32ed circled katakana ho
+32ee circled katakana ma
+32ef circled katakana mi
+32f0 circled katakana mu
+32f1 circled katakana me
+32f2 circled katakana mo
+32f3 circled katakana ya
+32f4 circled katakana yu
+32f5 circled katakana yo
+32f6 circled katakana ra
+32f7 circled katakana ri
+32f8 circled katakana ru
+32f9 circled katakana re
+32fa circled katakana ro
+32fb circled katakana wa
+32fc circled katakana wi
+32fd circled katakana we
+32fe circled katakana wo
+3300 square apaato
+3301 square aruhua
+3302 square anpea
+3303 square aaru
+3304 square iningu
+3305 square inti
+3306 square uon
+3307 square esukuudo
+3308 square eekaa
+3309 square onsu
+330a square oomu
+330b square kairi
+330c square karatto
+330d square karorii
+330e square garon
+330f square ganma
+3310 square giga
+3311 square ginii
+3312 square kyurii
+3313 square girudaa
+3314 square kiro
+3315 square kiroguramu
+3316 square kiromeetoru
+3317 square kirowatto
+3318 square guramu
+3319 square guramuton
+331a square kuruzeiro
+331b square kuroone
+331c square keesu
+331d square koruna
+331e square koopo
+331f square saikuru
+3320 square santiimu
+3321 square siringu
+3322 square senti
+3323 square sento
+3324 square daasu
+3325 square desi
+3326 square doru
+3327 square ton
+3328 square nano
+3329 square notto
+332a square haitu
+332b square paasento
+332c square paatu
+332d square baareru
+332e square piasutoru
+332f square pikuru
+3330 square piko
+3331 square biru
+3332 square huaraddo
+3333 square huiito
+3334 square bussyeru
+3335 square huran
+3336 square hekutaaru
+3337 square peso
+3338 square penihi
+3339 square herutu
+333a square pensu
+333b square peezi
+333c square beeta
+333d square pointo
+333e square boruto
+333f square hon
+3340 square pondo
+3341 square hooru
+3342 square hoon
+3343 square maikuro
+3344 square mairu
+3345 square mahha
+3346 square maruku
+3347 square mansyon
+3348 square mikuron
+3349 square miri
+334a square miribaaru
+334b square mega
+334c square megaton
+334d square meetoru
+334e square yaado
+334f square yaaru
+3350 square yuan
+3351 square rittoru
+3352 square rira
+3353 square rupii
+3354 square ruuburu
+3355 square remu
+3356 square rentogen
+3357 square watto
+3358 ideographic telegraph symbol for hour zero
+3359 ideographic telegraph symbol for hour one
+335a ideographic telegraph symbol for hour two
+335b ideographic telegraph symbol for hour three
+335c ideographic telegraph symbol for hour four
+335d ideographic telegraph symbol for hour five
+335e ideographic telegraph symbol for hour six
+335f ideographic telegraph symbol for hour seven
+3360 ideographic telegraph symbol for hour eight
+3361 ideographic telegraph symbol for hour nine
+3362 ideographic telegraph symbol for hour ten
+3363 ideographic telegraph symbol for hour eleven
+3364 ideographic telegraph symbol for hour twelve
+3365 ideographic telegraph symbol for hour thirteen
+3366 ideographic telegraph symbol for hour fourteen
+3367 ideographic telegraph symbol for hour fifteen
+3368 ideographic telegraph symbol for hour sixteen
+3369 ideographic telegraph symbol for hour seventeen
+336a ideographic telegraph symbol for hour eighteen
+336b ideographic telegraph symbol for hour nineteen
+336c ideographic telegraph symbol for hour twenty
+336d ideographic telegraph symbol for hour twenty-one
+336e ideographic telegraph symbol for hour twenty-two
+336f ideographic telegraph symbol for hour twenty-three
+3370 ideographic telegraph symbol for hour twenty-four
+3371 square hpa
+3372 square da
+3373 square au
+3374 square bar
+3375 square ov
+3376 square pc
+337b square era name heisei
+337c square era name syouwa
+337d square era name taisyou
+337e square era name meizi
+337f square corporation
+3380 square pa amps
+3381 square na
+3382 square mu a
+3383 square ma
+3384 square ka
+3385 square kb
+3386 square mb
+3387 square gb
+3388 square cal
+3389 square kcal
+338a square pf
+338b square nf
+338c square mu f
+338d square mu g
+338e square mg
+338f square kg
+3390 square hz
+3391 square khz
+3392 square mhz
+3393 square ghz
+3394 square thz
+3395 square mu l
+3396 square ml
+3397 square dl
+3398 square kl
+3399 square fm
+339a square nm
+339b square mu m
+339c square mm
+339d square cm
+339e square km
+339f square mm squared
+33a0 square cm squared
+33a1 square m squared
+33a2 square km squared
+33a3 square mm cubed
+33a4 square cm cubed
+33a5 square m cubed
+33a6 square km cubed
+33a7 square m over s
+33a8 square m over s squared
+33a9 square pa
+33aa square kpa
+33ab square mpa
+33ac square gpa
+33ad square rad
+33ae square rad over s
+33af square rad over s squared
+33b0 square ps
+33b1 square ns
+33b2 square mu s
+33b3 square ms
+33b4 square pv
+33b5 square nv
+33b6 square mu v
+33b7 square mv
+33b8 square kv
+33b9 square mv mega
+33ba square pw
+33bb square nw
+33bc square mu w
+33bd square mw
+33be square kw
+33bf square mw mega
+33c0 square k ohm
+33c1 square m ohm
+33c2 square am
+33c3 square bq
+33c4 square cc
+33c5 square cd
+33c6 square c over kg
+33c7 square co
+33c8 square db
+33c9 square gy
+33ca square ha
+33cb square hp
+33cc square in
+33cd square kk
+33ce square km capital
+33cf square kt
+33d0 square lm
+33d1 square ln
+33d2 square log
+33d3 square lx
+33d4 square mb small
+33d5 square mil
+33d6 square mol
+33d7 square ph
+33d8 square pm
+33d9 square ppm
+33da square pr
+33db square sr
+33dc square sv
+33dd square wb
+33e0 ideographic telegraph symbol for day one
+33e1 ideographic telegraph symbol for day two
+33e2 ideographic telegraph symbol for day three
+33e3 ideographic telegraph symbol for day four
+33e4 ideographic telegraph symbol for day five
+33e5 ideographic telegraph symbol for day six
+33e6 ideographic telegraph symbol for day seven
+33e7 ideographic telegraph symbol for day eight
+33e8 ideographic telegraph symbol for day nine
+33e9 ideographic telegraph symbol for day ten
+33ea ideographic telegraph symbol for day eleven
+33eb ideographic telegraph symbol for day twelve
+33ec ideographic telegraph symbol for day thirteen
+33ed ideographic telegraph symbol for day fourteen
+33ee ideographic telegraph symbol for day fifteen
+33ef ideographic telegraph symbol for day sixteen
+33f0 ideographic telegraph symbol for day seventeen
+33f1 ideographic telegraph symbol for day eighteen
+33f2 ideographic telegraph symbol for day nineteen
+33f3 ideographic telegraph symbol for day twenty
+33f4 ideographic telegraph symbol for day twenty-one
+33f5 ideographic telegraph symbol for day twenty-two
+33f6 ideographic telegraph symbol for day twenty-three
+33f7 ideographic telegraph symbol for day twenty-four
+33f8 ideographic telegraph symbol for day twenty-five
+33f9 ideographic telegraph symbol for day twenty-six
+33fa ideographic telegraph symbol for day twenty-seven
+33fb ideographic telegraph symbol for day twenty-eight
+33fc ideographic telegraph symbol for day twenty-nine
+33fd ideographic telegraph symbol for day thirty
+33fe ideographic telegraph symbol for day thirty-one
+4e00 <cjk ideograph, first>
+9fa5 <cjk ideograph, last>
+ac00 <hangul syllable, first>
+d7a3 <hangul syllable, last>
+d800 <unassigned high surrogate, first>
+db7f <unassigned high surrogate, last>
+db80 <private use high surrogate, first>
+dbff <private use high surrogate, last>
+dc00 <low surrogate, first>
+dfff <low surrogate, last>
+e000 <private use, first>
+f8ff <private use, last>
+f900 <cjk compatibility ideograph, first>
+fa2d <cjk compatibility ideograph, last>
+fb00 latin small ligature ff
+fb01 latin small ligature fi
+fb02 latin small ligature fl
+fb03 latin small ligature ffi
+fb04 latin small ligature ffl
+fb05 latin small ligature long s t
+fb06 latin small ligature st
+fb13 armenian small ligature men now
+fb14 armenian small ligature men ech
+fb15 armenian small ligature men ini
+fb16 armenian small ligature vew now
+fb17 armenian small ligature men xeh
+fb1e hebrew point judeo-spanish varika
+fb1f hebrew ligature yiddish yod yod patah
+fb20 hebrew letter alternative ayin
+fb21 hebrew letter wide alef
+fb22 hebrew letter wide dalet
+fb23 hebrew letter wide he
+fb24 hebrew letter wide kaf
+fb25 hebrew letter wide lamed
+fb26 hebrew letter wide final mem
+fb27 hebrew letter wide resh
+fb28 hebrew letter wide tav
+fb29 hebrew letter alternative plus sign
+fb2a hebrew letter shin with shin dot
+fb2b hebrew letter shin with sin dot
+fb2c hebrew letter shin with dagesh and shin dot
+fb2d hebrew letter shin with dagesh and sin dot
+fb2e hebrew letter alef with patah
+fb2f hebrew letter alef with qamats
+fb30 hebrew letter alef with mapiq
+fb31 hebrew letter bet with dagesh
+fb32 hebrew letter gimel with dagesh
+fb33 hebrew letter dalet with dagesh
+fb34 hebrew letter he with mapiq
+fb35 hebrew letter vav with dagesh
+fb36 hebrew letter zayin with dagesh
+fb38 hebrew letter tet with dagesh
+fb39 hebrew letter yod with dagesh
+fb3a hebrew letter final kaf with dagesh
+fb3b hebrew letter kaf with dagesh
+fb3c hebrew letter lamed with dagesh
+fb3e hebrew letter mem with dagesh
+fb40 hebrew letter nun with dagesh
+fb41 hebrew letter samekh with dagesh
+fb43 hebrew letter final pe with dagesh
+fb44 hebrew letter pe with dagesh
+fb46 hebrew letter tsadi with dagesh
+fb47 hebrew letter qof with dagesh
+fb48 hebrew letter resh with dagesh
+fb49 hebrew letter shin with dagesh
+fb4a hebrew letter tav with dagesh
+fb4b hebrew letter vav with holam
+fb4c hebrew letter bet with rafe
+fb4d hebrew letter kaf with rafe
+fb4e hebrew letter pe with rafe
+fb4f hebrew ligature alef lamed
+fb50 arabic letter alef wasla isolated form
+fb51 arabic letter alef wasla final form
+fb52 arabic letter beeh isolated form
+fb53 arabic letter beeh final form
+fb54 arabic letter beeh initial form
+fb55 arabic letter beeh medial form
+fb56 arabic letter peh isolated form
+fb57 arabic letter peh final form
+fb58 arabic letter peh initial form
+fb59 arabic letter peh medial form
+fb5a arabic letter beheh isolated form
+fb5b arabic letter beheh final form
+fb5c arabic letter beheh initial form
+fb5d arabic letter beheh medial form
+fb5e arabic letter tteheh isolated form
+fb5f arabic letter tteheh final form
+fb60 arabic letter tteheh initial form
+fb61 arabic letter tteheh medial form
+fb62 arabic letter teheh isolated form
+fb63 arabic letter teheh final form
+fb64 arabic letter teheh initial form
+fb65 arabic letter teheh medial form
+fb66 arabic letter tteh isolated form
+fb67 arabic letter tteh final form
+fb68 arabic letter tteh initial form
+fb69 arabic letter tteh medial form
+fb6a arabic letter veh isolated form
+fb6b arabic letter veh final form
+fb6c arabic letter veh initial form
+fb6d arabic letter veh medial form
+fb6e arabic letter peheh isolated form
+fb6f arabic letter peheh final form
+fb70 arabic letter peheh initial form
+fb71 arabic letter peheh medial form
+fb72 arabic letter dyeh isolated form
+fb73 arabic letter dyeh final form
+fb74 arabic letter dyeh initial form
+fb75 arabic letter dyeh medial form
+fb76 arabic letter nyeh isolated form
+fb77 arabic letter nyeh final form
+fb78 arabic letter nyeh initial form
+fb79 arabic letter nyeh medial form
+fb7a arabic letter tcheh isolated form
+fb7b arabic letter tcheh final form
+fb7c arabic letter tcheh initial form
+fb7d arabic letter tcheh medial form
+fb7e arabic letter tcheheh isolated form
+fb7f arabic letter tcheheh final form
+fb80 arabic letter tcheheh initial form
+fb81 arabic letter tcheheh medial form
+fb82 arabic letter ddahal isolated form
+fb83 arabic letter ddahal final form
+fb84 arabic letter dahal isolated form
+fb85 arabic letter dahal final form
+fb86 arabic letter dul isolated form
+fb87 arabic letter dul final form
+fb88 arabic letter ddal isolated form
+fb89 arabic letter ddal final form
+fb8a arabic letter jeh isolated form
+fb8b arabic letter jeh final form
+fb8c arabic letter rreh isolated form
+fb8d arabic letter rreh final form
+fb8e arabic letter keheh isolated form
+fb8f arabic letter keheh final form
+fb90 arabic letter keheh initial form
+fb91 arabic letter keheh medial form
+fb92 arabic letter gaf isolated form
+fb93 arabic letter gaf final form
+fb94 arabic letter gaf initial form
+fb95 arabic letter gaf medial form
+fb96 arabic letter gueh isolated form
+fb97 arabic letter gueh final form
+fb98 arabic letter gueh initial form
+fb99 arabic letter gueh medial form
+fb9a arabic letter ngoeh isolated form
+fb9b arabic letter ngoeh final form
+fb9c arabic letter ngoeh initial form
+fb9d arabic letter ngoeh medial form
+fb9e arabic letter noon ghunna isolated form
+fb9f arabic letter noon ghunna final form
+fba0 arabic letter rnoon isolated form
+fba1 arabic letter rnoon final form
+fba2 arabic letter rnoon initial form
+fba3 arabic letter rnoon medial form
+fba4 arabic letter heh with yeh above isolated form
+fba5 arabic letter heh with yeh above final form
+fba6 arabic letter heh goal isolated form
+fba7 arabic letter heh goal final form
+fba8 arabic letter heh goal initial form
+fba9 arabic letter heh goal medial form
+fbaa arabic letter heh doachashmee isolated form
+fbab arabic letter heh doachashmee final form
+fbac arabic letter heh doachashmee initial form
+fbad arabic letter heh doachashmee medial form
+fbae arabic letter yeh barree isolated form
+fbaf arabic letter yeh barree final form
+fbb0 arabic letter yeh barree with hamza above isolated form
+fbb1 arabic letter yeh barree with hamza above final form
+fbd3 arabic letter ng isolated form
+fbd4 arabic letter ng final form
+fbd5 arabic letter ng initial form
+fbd6 arabic letter ng medial form
+fbd7 arabic letter u isolated form
+fbd8 arabic letter u final form
+fbd9 arabic letter oe isolated form
+fbda arabic letter oe final form
+fbdb arabic letter yu isolated form
+fbdc arabic letter yu final form
+fbdd arabic letter u with hamza above isolated form
+fbde arabic letter ve isolated form
+fbdf arabic letter ve final form
+fbe0 arabic letter kirghiz oe isolated form
+fbe1 arabic letter kirghiz oe final form
+fbe2 arabic letter kirghiz yu isolated form
+fbe3 arabic letter kirghiz yu final form
+fbe4 arabic letter e isolated form
+fbe5 arabic letter e final form
+fbe6 arabic letter e initial form
+fbe7 arabic letter e medial form
+fbe8 arabic letter uighur kazakh kirghiz alef maksura initial form
+fbe9 arabic letter uighur kazakh kirghiz alef maksura medial form
+fbea arabic ligature yeh with hamza above with alef isolated form
+fbeb arabic ligature yeh with hamza above with alef final form
+fbec arabic ligature yeh with hamza above with ae isolated form
+fbed arabic ligature yeh with hamza above with ae final form
+fbee arabic ligature yeh with hamza above with waw isolated form
+fbef arabic ligature yeh with hamza above with waw final form
+fbf0 arabic ligature yeh with hamza above with u isolated form
+fbf1 arabic ligature yeh with hamza above with u final form
+fbf2 arabic ligature yeh with hamza above with oe isolated form
+fbf3 arabic ligature yeh with hamza above with oe final form
+fbf4 arabic ligature yeh with hamza above with yu isolated form
+fbf5 arabic ligature yeh with hamza above with yu final form
+fbf6 arabic ligature yeh with hamza above with e isolated form
+fbf7 arabic ligature yeh with hamza above with e final form
+fbf8 arabic ligature yeh with hamza above with e initial form
+fbf9 arabic ligature uighur kirghiz yeh with hamza above with alef maksura isolated form
+fbfa arabic ligature uighur kirghiz yeh with hamza above with alef maksura final form
+fbfb arabic ligature uighur kirghiz yeh with hamza above with alef maksura initial form
+fbfc arabic letter farsi yeh isolated form
+fbfd arabic letter farsi yeh final form
+fbfe arabic letter farsi yeh initial form
+fbff arabic letter farsi yeh medial form
+fc00 arabic ligature yeh with hamza above with jeem isolated form
+fc01 arabic ligature yeh with hamza above with hah isolated form
+fc02 arabic ligature yeh with hamza above with meem isolated form
+fc03 arabic ligature yeh with hamza above with alef maksura isolated form
+fc04 arabic ligature yeh with hamza above with yeh isolated form
+fc05 arabic ligature beh with jeem isolated form
+fc06 arabic ligature beh with hah isolated form
+fc07 arabic ligature beh with khah isolated form
+fc08 arabic ligature beh with meem isolated form
+fc09 arabic ligature beh with alef maksura isolated form
+fc0a arabic ligature beh with yeh isolated form
+fc0b arabic ligature teh with jeem isolated form
+fc0c arabic ligature teh with hah isolated form
+fc0d arabic ligature teh with khah isolated form
+fc0e arabic ligature teh with meem isolated form
+fc0f arabic ligature teh with alef maksura isolated form
+fc10 arabic ligature teh with yeh isolated form
+fc11 arabic ligature theh with jeem isolated form
+fc12 arabic ligature theh with meem isolated form
+fc13 arabic ligature theh with alef maksura isolated form
+fc14 arabic ligature theh with yeh isolated form
+fc15 arabic ligature jeem with hah isolated form
+fc16 arabic ligature jeem with meem isolated form
+fc17 arabic ligature hah with jeem isolated form
+fc18 arabic ligature hah with meem isolated form
+fc19 arabic ligature khah with jeem isolated form
+fc1a arabic ligature khah with hah isolated form
+fc1b arabic ligature khah with meem isolated form
+fc1c arabic ligature seen with jeem isolated form
+fc1d arabic ligature seen with hah isolated form
+fc1e arabic ligature seen with khah isolated form
+fc1f arabic ligature seen with meem isolated form
+fc20 arabic ligature sad with hah isolated form
+fc21 arabic ligature sad with meem isolated form
+fc22 arabic ligature dad with jeem isolated form
+fc23 arabic ligature dad with hah isolated form
+fc24 arabic ligature dad with khah isolated form
+fc25 arabic ligature dad with meem isolated form
+fc26 arabic ligature tah with hah isolated form
+fc27 arabic ligature tah with meem isolated form
+fc28 arabic ligature zah with meem isolated form
+fc29 arabic ligature ain with jeem isolated form
+fc2a arabic ligature ain with meem isolated form
+fc2b arabic ligature ghain with jeem isolated form
+fc2c arabic ligature ghain with meem isolated form
+fc2d arabic ligature feh with jeem isolated form
+fc2e arabic ligature feh with hah isolated form
+fc2f arabic ligature feh with khah isolated form
+fc30 arabic ligature feh with meem isolated form
+fc31 arabic ligature feh with alef maksura isolated form
+fc32 arabic ligature feh with yeh isolated form
+fc33 arabic ligature qaf with hah isolated form
+fc34 arabic ligature qaf with meem isolated form
+fc35 arabic ligature qaf with alef maksura isolated form
+fc36 arabic ligature qaf with yeh isolated form
+fc37 arabic ligature kaf with alef isolated form
+fc38 arabic ligature kaf with jeem isolated form
+fc39 arabic ligature kaf with hah isolated form
+fc3a arabic ligature kaf with khah isolated form
+fc3b arabic ligature kaf with lam isolated form
+fc3c arabic ligature kaf with meem isolated form
+fc3d arabic ligature kaf with alef maksura isolated form
+fc3e arabic ligature kaf with yeh isolated form
+fc3f arabic ligature lam with jeem isolated form
+fc40 arabic ligature lam with hah isolated form
+fc41 arabic ligature lam with khah isolated form
+fc42 arabic ligature lam with meem isolated form
+fc43 arabic ligature lam with alef maksura isolated form
+fc44 arabic ligature lam with yeh isolated form
+fc45 arabic ligature meem with jeem isolated form
+fc46 arabic ligature meem with hah isolated form
+fc47 arabic ligature meem with khah isolated form
+fc48 arabic ligature meem with meem isolated form
+fc49 arabic ligature meem with alef maksura isolated form
+fc4a arabic ligature meem with yeh isolated form
+fc4b arabic ligature noon with jeem isolated form
+fc4c arabic ligature noon with hah isolated form
+fc4d arabic ligature noon with khah isolated form
+fc4e arabic ligature noon with meem isolated form
+fc4f arabic ligature noon with alef maksura isolated form
+fc50 arabic ligature noon with yeh isolated form
+fc51 arabic ligature heh with jeem isolated form
+fc52 arabic ligature heh with meem isolated form
+fc53 arabic ligature heh with alef maksura isolated form
+fc54 arabic ligature heh with yeh isolated form
+fc55 arabic ligature yeh with jeem isolated form
+fc56 arabic ligature yeh with hah isolated form
+fc57 arabic ligature yeh with khah isolated form
+fc58 arabic ligature yeh with meem isolated form
+fc59 arabic ligature yeh with alef maksura isolated form
+fc5a arabic ligature yeh with yeh isolated form
+fc5b arabic ligature thal with superscript alef isolated form
+fc5c arabic ligature reh with superscript alef isolated form
+fc5d arabic ligature alef maksura with superscript alef isolated form
+fc5e arabic ligature shadda with dammatan isolated form
+fc5f arabic ligature shadda with kasratan isolated form
+fc60 arabic ligature shadda with fatha isolated form
+fc61 arabic ligature shadda with damma isolated form
+fc62 arabic ligature shadda with kasra isolated form
+fc63 arabic ligature shadda with superscript alef isolated form
+fc64 arabic ligature yeh with hamza above with reh final form
+fc65 arabic ligature yeh with hamza above with zain final form
+fc66 arabic ligature yeh with hamza above with meem final form
+fc67 arabic ligature yeh with hamza above with noon final form
+fc68 arabic ligature yeh with hamza above with alef maksura final form
+fc69 arabic ligature yeh with hamza above with yeh final form
+fc6a arabic ligature beh with reh final form
+fc6b arabic ligature beh with zain final form
+fc6c arabic ligature beh with meem final form
+fc6d arabic ligature beh with noon final form
+fc6e arabic ligature beh with alef maksura final form
+fc6f arabic ligature beh with yeh final form
+fc70 arabic ligature teh with reh final form
+fc71 arabic ligature teh with zain final form
+fc72 arabic ligature teh with meem final form
+fc73 arabic ligature teh with noon final form
+fc74 arabic ligature teh with alef maksura final form
+fc75 arabic ligature teh with yeh final form
+fc76 arabic ligature theh with reh final form
+fc77 arabic ligature theh with zain final form
+fc78 arabic ligature theh with meem final form
+fc79 arabic ligature theh with noon final form
+fc7a arabic ligature theh with alef maksura final form
+fc7b arabic ligature theh with yeh final form
+fc7c arabic ligature feh with alef maksura final form
+fc7d arabic ligature feh with yeh final form
+fc7e arabic ligature qaf with alef maksura final form
+fc7f arabic ligature qaf with yeh final form
+fc80 arabic ligature kaf with alef final form
+fc81 arabic ligature kaf with lam final form
+fc82 arabic ligature kaf with meem final form
+fc83 arabic ligature kaf with alef maksura final form
+fc84 arabic ligature kaf with yeh final form
+fc85 arabic ligature lam with meem final form
+fc86 arabic ligature lam with alef maksura final form
+fc87 arabic ligature lam with yeh final form
+fc88 arabic ligature meem with alef final form
+fc89 arabic ligature meem with meem final form
+fc8a arabic ligature noon with reh final form
+fc8b arabic ligature noon with zain final form
+fc8c arabic ligature noon with meem final form
+fc8d arabic ligature noon with noon final form
+fc8e arabic ligature noon with alef maksura final form
+fc8f arabic ligature noon with yeh final form
+fc90 arabic ligature alef maksura with superscript alef final form
+fc91 arabic ligature yeh with reh final form
+fc92 arabic ligature yeh with zain final form
+fc93 arabic ligature yeh with meem final form
+fc94 arabic ligature yeh with noon final form
+fc95 arabic ligature yeh with alef maksura final form
+fc96 arabic ligature yeh with yeh final form
+fc97 arabic ligature yeh with hamza above with jeem initial form
+fc98 arabic ligature yeh with hamza above with hah initial form
+fc99 arabic ligature yeh with hamza above with khah initial form
+fc9a arabic ligature yeh with hamza above with meem initial form
+fc9b arabic ligature yeh with hamza above with heh initial form
+fc9c arabic ligature beh with jeem initial form
+fc9d arabic ligature beh with hah initial form
+fc9e arabic ligature beh with khah initial form
+fc9f arabic ligature beh with meem initial form
+fca0 arabic ligature beh with heh initial form
+fca1 arabic ligature teh with jeem initial form
+fca2 arabic ligature teh with hah initial form
+fca3 arabic ligature teh with khah initial form
+fca4 arabic ligature teh with meem initial form
+fca5 arabic ligature teh with heh initial form
+fca6 arabic ligature theh with meem initial form
+fca7 arabic ligature jeem with hah initial form
+fca8 arabic ligature jeem with meem initial form
+fca9 arabic ligature hah with jeem initial form
+fcaa arabic ligature hah with meem initial form
+fcab arabic ligature khah with jeem initial form
+fcac arabic ligature khah with meem initial form
+fcad arabic ligature seen with jeem initial form
+fcae arabic ligature seen with hah initial form
+fcaf arabic ligature seen with khah initial form
+fcb0 arabic ligature seen with meem initial form
+fcb1 arabic ligature sad with hah initial form
+fcb2 arabic ligature sad with khah initial form
+fcb3 arabic ligature sad with meem initial form
+fcb4 arabic ligature dad with jeem initial form
+fcb5 arabic ligature dad with hah initial form
+fcb6 arabic ligature dad with khah initial form
+fcb7 arabic ligature dad with meem initial form
+fcb8 arabic ligature tah with hah initial form
+fcb9 arabic ligature zah with meem initial form
+fcba arabic ligature ain with jeem initial form
+fcbb arabic ligature ain with meem initial form
+fcbc arabic ligature ghain with jeem initial form
+fcbd arabic ligature ghain with meem initial form
+fcbe arabic ligature feh with jeem initial form
+fcbf arabic ligature feh with hah initial form
+fcc0 arabic ligature feh with khah initial form
+fcc1 arabic ligature feh with meem initial form
+fcc2 arabic ligature qaf with hah initial form
+fcc3 arabic ligature qaf with meem initial form
+fcc4 arabic ligature kaf with jeem initial form
+fcc5 arabic ligature kaf with hah initial form
+fcc6 arabic ligature kaf with khah initial form
+fcc7 arabic ligature kaf with lam initial form
+fcc8 arabic ligature kaf with meem initial form
+fcc9 arabic ligature lam with jeem initial form
+fcca arabic ligature lam with hah initial form
+fccb arabic ligature lam with khah initial form
+fccc arabic ligature lam with meem initial form
+fccd arabic ligature lam with heh initial form
+fcce arabic ligature meem with jeem initial form
+fccf arabic ligature meem with hah initial form
+fcd0 arabic ligature meem with khah initial form
+fcd1 arabic ligature meem with meem initial form
+fcd2 arabic ligature noon with jeem initial form
+fcd3 arabic ligature noon with hah initial form
+fcd4 arabic ligature noon with khah initial form
+fcd5 arabic ligature noon with meem initial form
+fcd6 arabic ligature noon with heh initial form
+fcd7 arabic ligature heh with jeem initial form
+fcd8 arabic ligature heh with meem initial form
+fcd9 arabic ligature heh with superscript alef initial form
+fcda arabic ligature yeh with jeem initial form
+fcdb arabic ligature yeh with hah initial form
+fcdc arabic ligature yeh with khah initial form
+fcdd arabic ligature yeh with meem initial form
+fcde arabic ligature yeh with heh initial form
+fcdf arabic ligature yeh with hamza above with meem medial form
+fce0 arabic ligature yeh with hamza above with heh medial form
+fce1 arabic ligature beh with meem medial form
+fce2 arabic ligature beh with heh medial form
+fce3 arabic ligature teh with meem medial form
+fce4 arabic ligature teh with heh medial form
+fce5 arabic ligature theh with meem medial form
+fce6 arabic ligature theh with heh medial form
+fce7 arabic ligature seen with meem medial form
+fce8 arabic ligature seen with heh medial form
+fce9 arabic ligature sheen with meem medial form
+fcea arabic ligature sheen with heh medial form
+fceb arabic ligature kaf with lam medial form
+fcec arabic ligature kaf with meem medial form
+fced arabic ligature lam with meem medial form
+fcee arabic ligature noon with meem medial form
+fcef arabic ligature noon with heh medial form
+fcf0 arabic ligature yeh with meem medial form
+fcf1 arabic ligature yeh with heh medial form
+fcf2 arabic ligature shadda with fatha medial form
+fcf3 arabic ligature shadda with damma medial form
+fcf4 arabic ligature shadda with kasra medial form
+fcf5 arabic ligature tah with alef maksura isolated form
+fcf6 arabic ligature tah with yeh isolated form
+fcf7 arabic ligature ain with alef maksura isolated form
+fcf8 arabic ligature ain with yeh isolated form
+fcf9 arabic ligature ghain with alef maksura isolated form
+fcfa arabic ligature ghain with yeh isolated form
+fcfb arabic ligature seen with alef maksura isolated form
+fcfc arabic ligature seen with yeh isolated form
+fcfd arabic ligature sheen with alef maksura isolated form
+fcfe arabic ligature sheen with yeh isolated form
+fcff arabic ligature hah with alef maksura isolated form
+fd00 arabic ligature hah with yeh isolated form
+fd01 arabic ligature jeem with alef maksura isolated form
+fd02 arabic ligature jeem with yeh isolated form
+fd03 arabic ligature khah with alef maksura isolated form
+fd04 arabic ligature khah with yeh isolated form
+fd05 arabic ligature sad with alef maksura isolated form
+fd06 arabic ligature sad with yeh isolated form
+fd07 arabic ligature dad with alef maksura isolated form
+fd08 arabic ligature dad with yeh isolated form
+fd09 arabic ligature sheen with jeem isolated form
+fd0a arabic ligature sheen with hah isolated form
+fd0b arabic ligature sheen with khah isolated form
+fd0c arabic ligature sheen with meem isolated form
+fd0d arabic ligature sheen with reh isolated form
+fd0e arabic ligature seen with reh isolated form
+fd0f arabic ligature sad with reh isolated form
+fd10 arabic ligature dad with reh isolated form
+fd11 arabic ligature tah with alef maksura final form
+fd12 arabic ligature tah with yeh final form
+fd13 arabic ligature ain with alef maksura final form
+fd14 arabic ligature ain with yeh final form
+fd15 arabic ligature ghain with alef maksura final form
+fd16 arabic ligature ghain with yeh final form
+fd17 arabic ligature seen with alef maksura final form
+fd18 arabic ligature seen with yeh final form
+fd19 arabic ligature sheen with alef maksura final form
+fd1a arabic ligature sheen with yeh final form
+fd1b arabic ligature hah with alef maksura final form
+fd1c arabic ligature hah with yeh final form
+fd1d arabic ligature jeem with alef maksura final form
+fd1e arabic ligature jeem with yeh final form
+fd1f arabic ligature khah with alef maksura final form
+fd20 arabic ligature khah with yeh final form
+fd21 arabic ligature sad with alef maksura final form
+fd22 arabic ligature sad with yeh final form
+fd23 arabic ligature dad with alef maksura final form
+fd24 arabic ligature dad with yeh final form
+fd25 arabic ligature sheen with jeem final form
+fd26 arabic ligature sheen with hah final form
+fd27 arabic ligature sheen with khah final form
+fd28 arabic ligature sheen with meem final form
+fd29 arabic ligature sheen with reh final form
+fd2a arabic ligature seen with reh final form
+fd2b arabic ligature sad with reh final form
+fd2c arabic ligature dad with reh final form
+fd2d arabic ligature sheen with jeem initial form
+fd2e arabic ligature sheen with hah initial form
+fd2f arabic ligature sheen with khah initial form
+fd30 arabic ligature sheen with meem initial form
+fd31 arabic ligature seen with heh initial form
+fd32 arabic ligature sheen with heh initial form
+fd33 arabic ligature tah with meem initial form
+fd34 arabic ligature seen with jeem medial form
+fd35 arabic ligature seen with hah medial form
+fd36 arabic ligature seen with khah medial form
+fd37 arabic ligature sheen with jeem medial form
+fd38 arabic ligature sheen with hah medial form
+fd39 arabic ligature sheen with khah medial form
+fd3a arabic ligature tah with meem medial form
+fd3b arabic ligature zah with meem medial form
+fd3c arabic ligature alef with fathatan final form
+fd3d arabic ligature alef with fathatan isolated form
+fd3e ornate left parenthesis
+fd3f ornate right parenthesis
+fd50 arabic ligature teh with jeem with meem initial form
+fd51 arabic ligature teh with hah with jeem final form
+fd52 arabic ligature teh with hah with jeem initial form
+fd53 arabic ligature teh with hah with meem initial form
+fd54 arabic ligature teh with khah with meem initial form
+fd55 arabic ligature teh with meem with jeem initial form
+fd56 arabic ligature teh with meem with hah initial form
+fd57 arabic ligature teh with meem with khah initial form
+fd58 arabic ligature jeem with meem with hah final form
+fd59 arabic ligature jeem with meem with hah initial form
+fd5a arabic ligature hah with meem with yeh final form
+fd5b arabic ligature hah with meem with alef maksura final form
+fd5c arabic ligature seen with hah with jeem initial form
+fd5d arabic ligature seen with jeem with hah initial form
+fd5e arabic ligature seen with jeem with alef maksura final form
+fd5f arabic ligature seen with meem with hah final form
+fd60 arabic ligature seen with meem with hah initial form
+fd61 arabic ligature seen with meem with jeem initial form
+fd62 arabic ligature seen with meem with meem final form
+fd63 arabic ligature seen with meem with meem initial form
+fd64 arabic ligature sad with hah with hah final form
+fd65 arabic ligature sad with hah with hah initial form
+fd66 arabic ligature sad with meem with meem final form
+fd67 arabic ligature sheen with hah with meem final form
+fd68 arabic ligature sheen with hah with meem initial form
+fd69 arabic ligature sheen with jeem with yeh final form
+fd6a arabic ligature sheen with meem with khah final form
+fd6b arabic ligature sheen with meem with khah initial form
+fd6c arabic ligature sheen with meem with meem final form
+fd6d arabic ligature sheen with meem with meem initial form
+fd6e arabic ligature dad with hah with alef maksura final form
+fd6f arabic ligature dad with khah with meem final form
+fd70 arabic ligature dad with khah with meem initial form
+fd71 arabic ligature tah with meem with hah final form
+fd72 arabic ligature tah with meem with hah initial form
+fd73 arabic ligature tah with meem with meem initial form
+fd74 arabic ligature tah with meem with yeh final form
+fd75 arabic ligature ain with jeem with meem final form
+fd76 arabic ligature ain with meem with meem final form
+fd77 arabic ligature ain with meem with meem initial form
+fd78 arabic ligature ain with meem with alef maksura final form
+fd79 arabic ligature ghain with meem with meem final form
+fd7a arabic ligature ghain with meem with yeh final form
+fd7b arabic ligature ghain with meem with alef maksura final form
+fd7c arabic ligature feh with khah with meem final form
+fd7d arabic ligature feh with khah with meem initial form
+fd7e arabic ligature qaf with meem with hah final form
+fd7f arabic ligature qaf with meem with meem final form
+fd80 arabic ligature lam with hah with meem final form
+fd81 arabic ligature lam with hah with yeh final form
+fd82 arabic ligature lam with hah with alef maksura final form
+fd83 arabic ligature lam with jeem with jeem initial form
+fd84 arabic ligature lam with jeem with jeem final form
+fd85 arabic ligature lam with khah with meem final form
+fd86 arabic ligature lam with khah with meem initial form
+fd87 arabic ligature lam with meem with hah final form
+fd88 arabic ligature lam with meem with hah initial form
+fd89 arabic ligature meem with hah with jeem initial form
+fd8a arabic ligature meem with hah with meem initial form
+fd8b arabic ligature meem with hah with yeh final form
+fd8c arabic ligature meem with jeem with hah initial form
+fd8d arabic ligature meem with jeem with meem initial form
+fd8e arabic ligature meem with khah with jeem initial form
+fd8f arabic ligature meem with khah with meem initial form
+fd92 arabic ligature meem with jeem with khah initial form
+fd93 arabic ligature heh with meem with jeem initial form
+fd94 arabic ligature heh with meem with meem initial form
+fd95 arabic ligature noon with hah with meem initial form
+fd96 arabic ligature noon with hah with alef maksura final form
+fd97 arabic ligature noon with jeem with meem final form
+fd98 arabic ligature noon with jeem with meem initial form
+fd99 arabic ligature noon with jeem with alef maksura final form
+fd9a arabic ligature noon with meem with yeh final form
+fd9b arabic ligature noon with meem with alef maksura final form
+fd9c arabic ligature yeh with meem with meem final form
+fd9d arabic ligature yeh with meem with meem initial form
+fd9e arabic ligature beh with khah with yeh final form
+fd9f arabic ligature teh with jeem with yeh final form
+fda0 arabic ligature teh with jeem with alef maksura final form
+fda1 arabic ligature teh with khah with yeh final form
+fda2 arabic ligature teh with khah with alef maksura final form
+fda3 arabic ligature teh with meem with yeh final form
+fda4 arabic ligature teh with meem with alef maksura final form
+fda5 arabic ligature jeem with meem with yeh final form
+fda6 arabic ligature jeem with hah with alef maksura final form
+fda7 arabic ligature jeem with meem with alef maksura final form
+fda8 arabic ligature seen with khah with alef maksura final form
+fda9 arabic ligature sad with hah with yeh final form
+fdaa arabic ligature sheen with hah with yeh final form
+fdab arabic ligature dad with hah with yeh final form
+fdac arabic ligature lam with jeem with yeh final form
+fdad arabic ligature lam with meem with yeh final form
+fdae arabic ligature yeh with hah with yeh final form
+fdaf arabic ligature yeh with jeem with yeh final form
+fdb0 arabic ligature yeh with meem with yeh final form
+fdb1 arabic ligature meem with meem with yeh final form
+fdb2 arabic ligature qaf with meem with yeh final form
+fdb3 arabic ligature noon with hah with yeh final form
+fdb4 arabic ligature qaf with meem with hah initial form
+fdb5 arabic ligature lam with hah with meem initial form
+fdb6 arabic ligature ain with meem with yeh final form
+fdb7 arabic ligature kaf with meem with yeh final form
+fdb8 arabic ligature noon with jeem with hah initial form
+fdb9 arabic ligature meem with khah with yeh final form
+fdba arabic ligature lam with jeem with meem initial form
+fdbb arabic ligature kaf with meem with meem final form
+fdbc arabic ligature lam with jeem with meem final form
+fdbd arabic ligature noon with jeem with hah final form
+fdbe arabic ligature jeem with hah with yeh final form
+fdbf arabic ligature hah with jeem with yeh final form
+fdc0 arabic ligature meem with jeem with yeh final form
+fdc1 arabic ligature feh with meem with yeh final form
+fdc2 arabic ligature beh with hah with yeh final form
+fdc3 arabic ligature kaf with meem with meem initial form
+fdc4 arabic ligature ain with jeem with meem initial form
+fdc5 arabic ligature sad with meem with meem initial form
+fdc6 arabic ligature seen with khah with yeh final form
+fdc7 arabic ligature noon with jeem with yeh final form
+fdf0 arabic ligature salla used as koranic stop sign isolated form
+fdf1 arabic ligature qala used as koranic stop sign isolated form
+fdf2 arabic ligature allah isolated form
+fdf3 arabic ligature akbar isolated form
+fdf4 arabic ligature mohammad isolated form
+fdf5 arabic ligature salam isolated form
+fdf6 arabic ligature rasoul isolated form
+fdf7 arabic ligature alayhe isolated form
+fdf8 arabic ligature wasallam isolated form
+fdf9 arabic ligature salla isolated form
+fdfa arabic ligature sallallahou alayhe wasallam
+fdfb arabic ligature jallajalalouhou
+fe20 combining ligature left half
+fe21 combining ligature right half
+fe22 combining double tilde left half
+fe23 combining double tilde right half
+fe30 presentation form for vertical two dot leader
+fe31 presentation form for vertical em dash
+fe32 presentation form for vertical en dash
+fe33 presentation form for vertical low line
+fe34 presentation form for vertical wavy low line
+fe35 presentation form for vertical left parenthesis
+fe36 presentation form for vertical right parenthesis
+fe37 presentation form for vertical left curly bracket
+fe38 presentation form for vertical right curly bracket
+fe39 presentation form for vertical left tortoise shell bracket
+fe3a presentation form for vertical right tortoise shell bracket
+fe3b presentation form for vertical left black lenticular bracket
+fe3c presentation form for vertical right black lenticular bracket
+fe3d presentation form for vertical left double angle bracket
+fe3e presentation form for vertical right double angle bracket
+fe3f presentation form for vertical left angle bracket
+fe40 presentation form for vertical right angle bracket
+fe41 presentation form for vertical left corner bracket
+fe42 presentation form for vertical right corner bracket
+fe43 presentation form for vertical left white corner bracket
+fe44 presentation form for vertical right white corner bracket
+fe49 dashed overline
+fe4a centreline overline
+fe4b wavy overline
+fe4c double wavy overline
+fe4d dashed low line
+fe4e centreline low line
+fe4f wavy low line
+fe50 small comma
+fe51 small ideographic comma
+fe52 small full stop
+fe54 small semicolon
+fe55 small colon
+fe56 small question mark
+fe57 small exclamation mark
+fe58 small em dash
+fe59 small left parenthesis
+fe5a small right parenthesis
+fe5b small left curly bracket
+fe5c small right curly bracket
+fe5d small left tortoise shell bracket
+fe5e small right tortoise shell bracket
+fe5f small number sign
+fe60 small ampersand
+fe61 small asterisk
+fe62 small plus sign
+fe63 small hyphen-minus
+fe64 small less-than sign
+fe65 small greater-than sign
+fe66 small equals sign
+fe68 small reverse solidus
+fe69 small dollar sign
+fe6a small percent sign
+fe6b small commercial at
+fe70 arabic fathatan isolated form
+fe71 arabic tatweel with fathatan above
+fe72 arabic dammatan isolated form
+fe74 arabic kasratan isolated form
+fe76 arabic fatha isolated form
+fe77 arabic fatha medial form
+fe78 arabic damma isolated form
+fe79 arabic damma medial form
+fe7a arabic kasra isolated form
+fe7b arabic kasra medial form
+fe7c arabic shadda isolated form
+fe7d arabic shadda medial form
+fe7e arabic sukun isolated form
+fe7f arabic sukun medial form
+fe80 arabic letter hamza isolated form
+fe81 arabic letter alef with madda above isolated form
+fe82 arabic letter alef with madda above final form
+fe83 arabic letter alef with hamza above isolated form
+fe84 arabic letter alef with hamza above final form
+fe85 arabic letter waw with hamza above isolated form
+fe86 arabic letter waw with hamza above final form
+fe87 arabic letter alef with hamza below isolated form
+fe88 arabic letter alef with hamza below final form
+fe89 arabic letter yeh with hamza above isolated form
+fe8a arabic letter yeh with hamza above final form
+fe8b arabic letter yeh with hamza above initial form
+fe8c arabic letter yeh with hamza above medial form
+fe8d arabic letter alef isolated form
+fe8e arabic letter alef final form
+fe8f arabic letter beh isolated form
+fe90 arabic letter beh final form
+fe91 arabic letter beh initial form
+fe92 arabic letter beh medial form
+fe93 arabic letter teh marbuta isolated form
+fe94 arabic letter teh marbuta final form
+fe95 arabic letter teh isolated form
+fe96 arabic letter teh final form
+fe97 arabic letter teh initial form
+fe98 arabic letter teh medial form
+fe99 arabic letter theh isolated form
+fe9a arabic letter theh final form
+fe9b arabic letter theh initial form
+fe9c arabic letter theh medial form
+fe9d arabic letter jeem isolated form
+fe9e arabic letter jeem final form
+fe9f arabic letter jeem initial form
+fea0 arabic letter jeem medial form
+fea1 arabic letter hah isolated form
+fea2 arabic letter hah final form
+fea3 arabic letter hah initial form
+fea4 arabic letter hah medial form
+fea5 arabic letter khah isolated form
+fea6 arabic letter khah final form
+fea7 arabic letter khah initial form
+fea8 arabic letter khah medial form
+fea9 arabic letter dal isolated form
+feaa arabic letter dal final form
+feab arabic letter thal isolated form
+feac arabic letter thal final form
+fead arabic letter reh isolated form
+feae arabic letter reh final form
+feaf arabic letter zain isolated form
+feb0 arabic letter zain final form
+feb1 arabic letter seen isolated form
+feb2 arabic letter seen final form
+feb3 arabic letter seen initial form
+feb4 arabic letter seen medial form
+feb5 arabic letter sheen isolated form
+feb6 arabic letter sheen final form
+feb7 arabic letter sheen initial form
+feb8 arabic letter sheen medial form
+feb9 arabic letter sad isolated form
+feba arabic letter sad final form
+febb arabic letter sad initial form
+febc arabic letter sad medial form
+febd arabic letter dad isolated form
+febe arabic letter dad final form
+febf arabic letter dad initial form
+fec0 arabic letter dad medial form
+fec1 arabic letter tah isolated form
+fec2 arabic letter tah final form
+fec3 arabic letter tah initial form
+fec4 arabic letter tah medial form
+fec5 arabic letter zah isolated form
+fec6 arabic letter zah final form
+fec7 arabic letter zah initial form
+fec8 arabic letter zah medial form
+fec9 arabic letter ain isolated form
+feca arabic letter ain final form
+fecb arabic letter ain initial form
+fecc arabic letter ain medial form
+fecd arabic letter ghain isolated form
+fece arabic letter ghain final form
+fecf arabic letter ghain initial form
+fed0 arabic letter ghain medial form
+fed1 arabic letter feh isolated form
+fed2 arabic letter feh final form
+fed3 arabic letter feh initial form
+fed4 arabic letter feh medial form
+fed5 arabic letter qaf isolated form
+fed6 arabic letter qaf final form
+fed7 arabic letter qaf initial form
+fed8 arabic letter qaf medial form
+fed9 arabic letter kaf isolated form
+feda arabic letter kaf final form
+fedb arabic letter kaf initial form
+fedc arabic letter kaf medial form
+fedd arabic letter lam isolated form
+fede arabic letter lam final form
+fedf arabic letter lam initial form
+fee0 arabic letter lam medial form
+fee1 arabic letter meem isolated form
+fee2 arabic letter meem final form
+fee3 arabic letter meem initial form
+fee4 arabic letter meem medial form
+fee5 arabic letter noon isolated form
+fee6 arabic letter noon final form
+fee7 arabic letter noon initial form
+fee8 arabic letter noon medial form
+fee9 arabic letter heh isolated form
+feea arabic letter heh final form
+feeb arabic letter heh initial form
+feec arabic letter heh medial form
+feed arabic letter waw isolated form
+feee arabic letter waw final form
+feef arabic letter alef maksura isolated form
+fef0 arabic letter alef maksura final form
+fef1 arabic letter yeh isolated form
+fef2 arabic letter yeh final form
+fef3 arabic letter yeh initial form
+fef4 arabic letter yeh medial form
+fef5 arabic ligature lam with alef with madda above isolated form
+fef6 arabic ligature lam with alef with madda above final form
+fef7 arabic ligature lam with alef with hamza above isolated form
+fef8 arabic ligature lam with alef with hamza above final form
+fef9 arabic ligature lam with alef with hamza below isolated form
+fefa arabic ligature lam with alef with hamza below final form
+fefb arabic ligature lam with alef isolated form
+fefc arabic ligature lam with alef final form
+feff zero width no-break space
+ff01 fullwidth exclamation mark
+ff02 fullwidth quotation mark
+ff03 fullwidth number sign
+ff04 fullwidth dollar sign
+ff05 fullwidth percent sign
+ff06 fullwidth ampersand
+ff07 fullwidth apostrophe
+ff08 fullwidth left parenthesis
+ff09 fullwidth right parenthesis
+ff0a fullwidth asterisk
+ff0b fullwidth plus sign
+ff0c fullwidth comma
+ff0d fullwidth hyphen-minus
+ff0e fullwidth full stop
+ff0f fullwidth solidus
+ff10 fullwidth digit zero
+ff11 fullwidth digit one
+ff12 fullwidth digit two
+ff13 fullwidth digit three
+ff14 fullwidth digit four
+ff15 fullwidth digit five
+ff16 fullwidth digit six
+ff17 fullwidth digit seven
+ff18 fullwidth digit eight
+ff19 fullwidth digit nine
+ff1a fullwidth colon
+ff1b fullwidth semicolon
+ff1c fullwidth less-than sign
+ff1d fullwidth equals sign
+ff1e fullwidth greater-than sign
+ff1f fullwidth question mark
+ff20 fullwidth commercial at
+ff21 fullwidth latin capital letter a
+ff22 fullwidth latin capital letter b
+ff23 fullwidth latin capital letter c
+ff24 fullwidth latin capital letter d
+ff25 fullwidth latin capital letter e
+ff26 fullwidth latin capital letter f
+ff27 fullwidth latin capital letter g
+ff28 fullwidth latin capital letter h
+ff29 fullwidth latin capital letter i
+ff2a fullwidth latin capital letter j
+ff2b fullwidth latin capital letter k
+ff2c fullwidth latin capital letter l
+ff2d fullwidth latin capital letter m
+ff2e fullwidth latin capital letter n
+ff2f fullwidth latin capital letter o
+ff30 fullwidth latin capital letter p
+ff31 fullwidth latin capital letter q
+ff32 fullwidth latin capital letter r
+ff33 fullwidth latin capital letter s
+ff34 fullwidth latin capital letter t
+ff35 fullwidth latin capital letter u
+ff36 fullwidth latin capital letter v
+ff37 fullwidth latin capital letter w
+ff38 fullwidth latin capital letter x
+ff39 fullwidth latin capital letter y
+ff3a fullwidth latin capital letter z
+ff3b fullwidth left square bracket
+ff3c fullwidth reverse solidus
+ff3d fullwidth right square bracket
+ff3e fullwidth circumflex accent
+ff3f fullwidth low line
+ff40 fullwidth grave accent
+ff41 fullwidth latin small letter a;ff21
+ff42 fullwidth latin small letter b;ff22
+ff43 fullwidth latin small letter c;ff23
+ff44 fullwidth latin small letter d;ff24
+ff45 fullwidth latin small letter e;ff25
+ff46 fullwidth latin small letter f;ff26
+ff47 fullwidth latin small letter g;ff27
+ff48 fullwidth latin small letter h;ff28
+ff49 fullwidth latin small letter i;ff29
+ff4a fullwidth latin small letter j;ff2a
+ff4b fullwidth latin small letter k;ff2b
+ff4c fullwidth latin small letter l;ff2c
+ff4d fullwidth latin small letter m;ff2d
+ff4e fullwidth latin small letter n;ff2e
+ff4f fullwidth latin small letter o;ff2f
+ff50 fullwidth latin small letter p;ff30
+ff51 fullwidth latin small letter q;ff31
+ff52 fullwidth latin small letter r;ff32
+ff53 fullwidth latin small letter s;ff33
+ff54 fullwidth latin small letter t;ff34
+ff55 fullwidth latin small letter u;ff35
+ff56 fullwidth latin small letter v;ff36
+ff57 fullwidth latin small letter w;ff37
+ff58 fullwidth latin small letter x;ff38
+ff59 fullwidth latin small letter y;ff39
+ff5a fullwidth latin small letter z;ff3a
+ff5b fullwidth left curly bracket
+ff5c fullwidth vertical line
+ff5d fullwidth right curly bracket
+ff5e fullwidth tilde
+ff61 halfwidth ideographic full stop
+ff62 halfwidth left corner bracket
+ff63 halfwidth right corner bracket
+ff64 halfwidth ideographic comma
+ff65 halfwidth katakana middle dot
+ff66 halfwidth katakana letter wo
+ff67 halfwidth katakana letter small a
+ff68 halfwidth katakana letter small i
+ff69 halfwidth katakana letter small u
+ff6a halfwidth katakana letter small e
+ff6b halfwidth katakana letter small o
+ff6c halfwidth katakana letter small ya
+ff6d halfwidth katakana letter small yu
+ff6e halfwidth katakana letter small yo
+ff6f halfwidth katakana letter small tu
+ff70 halfwidth katakana-hiragana prolonged sound mark
+ff71 halfwidth katakana letter a
+ff72 halfwidth katakana letter i
+ff73 halfwidth katakana letter u
+ff74 halfwidth katakana letter e
+ff75 halfwidth katakana letter o
+ff76 halfwidth katakana letter ka
+ff77 halfwidth katakana letter ki
+ff78 halfwidth katakana letter ku
+ff79 halfwidth katakana letter ke
+ff7a halfwidth katakana letter ko
+ff7b halfwidth katakana letter sa
+ff7c halfwidth katakana letter si
+ff7d halfwidth katakana letter su
+ff7e halfwidth katakana letter se
+ff7f halfwidth katakana letter so
+ff80 halfwidth katakana letter ta
+ff81 halfwidth katakana letter ti
+ff82 halfwidth katakana letter tu
+ff83 halfwidth katakana letter te
+ff84 halfwidth katakana letter to
+ff85 halfwidth katakana letter na
+ff86 halfwidth katakana letter ni
+ff87 halfwidth katakana letter nu
+ff88 halfwidth katakana letter ne
+ff89 halfwidth katakana letter no
+ff8a halfwidth katakana letter ha
+ff8b halfwidth katakana letter hi
+ff8c halfwidth katakana letter hu
+ff8d halfwidth katakana letter he
+ff8e halfwidth katakana letter ho
+ff8f halfwidth katakana letter ma
+ff90 halfwidth katakana letter mi
+ff91 halfwidth katakana letter mu
+ff92 halfwidth katakana letter me
+ff93 halfwidth katakana letter mo
+ff94 halfwidth katakana letter ya
+ff95 halfwidth katakana letter yu
+ff96 halfwidth katakana letter yo
+ff97 halfwidth katakana letter ra
+ff98 halfwidth katakana letter ri
+ff99 halfwidth katakana letter ru
+ff9a halfwidth katakana letter re
+ff9b halfwidth katakana letter ro
+ff9c halfwidth katakana letter wa
+ff9d halfwidth katakana letter n
+ff9e halfwidth katakana voiced sound mark
+ff9f halfwidth katakana semi-voiced sound mark
+ffa0 halfwidth hangul filler
+ffa1 halfwidth hangul letter kiyeok
+ffa2 halfwidth hangul letter ssangkiyeok
+ffa3 halfwidth hangul letter kiyeok-sios
+ffa4 halfwidth hangul letter nieun
+ffa5 halfwidth hangul letter nieun-cieuc
+ffa6 halfwidth hangul letter nieun-hieuh
+ffa7 halfwidth hangul letter tikeut
+ffa8 halfwidth hangul letter ssangtikeut
+ffa9 halfwidth hangul letter rieul
+ffaa halfwidth hangul letter rieul-kiyeok
+ffab halfwidth hangul letter rieul-mieum
+ffac halfwidth hangul letter rieul-pieup
+ffad halfwidth hangul letter rieul-sios
+ffae halfwidth hangul letter rieul-thieuth
+ffaf halfwidth hangul letter rieul-phieuph
+ffb0 halfwidth hangul letter rieul-hieuh
+ffb1 halfwidth hangul letter mieum
+ffb2 halfwidth hangul letter pieup
+ffb3 halfwidth hangul letter ssangpieup
+ffb4 halfwidth hangul letter pieup-sios
+ffb5 halfwidth hangul letter sios
+ffb6 halfwidth hangul letter ssangsios
+ffb7 halfwidth hangul letter ieung
+ffb8 halfwidth hangul letter cieuc
+ffb9 halfwidth hangul letter ssangcieuc
+ffba halfwidth hangul letter chieuch
+ffbb halfwidth hangul letter khieukh
+ffbc halfwidth hangul letter thieuth
+ffbd halfwidth hangul letter phieuph
+ffbe halfwidth hangul letter hieuh
+ffc2 halfwidth hangul letter a
+ffc3 halfwidth hangul letter ae
+ffc4 halfwidth hangul letter ya
+ffc5 halfwidth hangul letter yae
+ffc6 halfwidth hangul letter eo
+ffc7 halfwidth hangul letter e
+ffca halfwidth hangul letter yeo
+ffcb halfwidth hangul letter ye
+ffcc halfwidth hangul letter o
+ffcd halfwidth hangul letter wa
+ffce halfwidth hangul letter wae
+ffcf halfwidth hangul letter oe
+ffd2 halfwidth hangul letter yo
+ffd3 halfwidth hangul letter u
+ffd4 halfwidth hangul letter weo
+ffd5 halfwidth hangul letter we
+ffd6 halfwidth hangul letter wi
+ffd7 halfwidth hangul letter yu
+ffda halfwidth hangul letter eu
+ffdb halfwidth hangul letter yi
+ffdc halfwidth hangul letter i
+ffe0 fullwidth cent sign
+ffe1 fullwidth pound sign
+ffe2 fullwidth not sign
+ffe3 fullwidth macron
+ffe4 fullwidth broken bar
+ffe5 fullwidth yen sign
+ffe6 fullwidth won sign
+ffe8 halfwidth forms light vertical
+ffe9 halfwidth leftwards arrow
+ffea halfwidth upwards arrow
+ffeb halfwidth rightwards arrow
+ffec halfwidth downwards arrow
+ffed halfwidth black square
+ffee halfwidth white circle
+fffd replacement character
--- /dev/null
+++ b/lib/unidata/blocks.txt
@@ -1,0 +1,172 @@
+# Blocks-4.1.0.txt
+# Date: 2005-1-31, 16:50 [KW]
+#
+# Unicode Character Database
+# Copyright (c) 1991-2005 Unicode, Inc.
+# For terms of use, see http://www.unicode.org/terms_of_use.html
+# For documentation, see UCD.html
+#
+# Note: The casing of block names is not normative.
+# For example, "Basic Latin" and "BASIC LATIN" are equivalent.
+#
+# Format:
+# Start Code..End Code; Block Name
+
+# ================================================
+
+# Note: When comparing block names, casing, whitespace, hyphens,
+# and underbars are ignored.
+# For example, "Latin Extended-A" and "latin extended a" are equivalent.
+# For more information on the comparison of property values,
+# see UCD.html.
+#
+# All code points not explicitly listed for Block
+# have the value No_Block.
+
+# Property: Block
+
+0000..007F; Basic Latin
+0080..00FF; Latin-1 Supplement
+0100..017F; Latin Extended-A
+0180..024F; Latin Extended-B
+0250..02AF; IPA Extensions
+02B0..02FF; Spacing Modifier Letters
+0300..036F; Combining Diacritical Marks
+0370..03FF; Greek and Coptic
+0400..04FF; Cyrillic
+0500..052F; Cyrillic Supplement
+0530..058F; Armenian
+0590..05FF; Hebrew
+0600..06FF; Arabic
+0700..074F; Syriac
+0750..077F; Arabic Supplement
+0780..07BF; Thaana
+0900..097F; Devanagari
+0980..09FF; Bengali
+0A00..0A7F; Gurmukhi
+0A80..0AFF; Gujarati
+0B00..0B7F; Oriya
+0B80..0BFF; Tamil
+0C00..0C7F; Telugu
+0C80..0CFF; Kannada
+0D00..0D7F; Malayalam
+0D80..0DFF; Sinhala
+0E00..0E7F; Thai
+0E80..0EFF; Lao
+0F00..0FFF; Tibetan
+1000..109F; Myanmar
+10A0..10FF; Georgian
+1100..11FF; Hangul Jamo
+1200..137F; Ethiopic
+1380..139F; Ethiopic Supplement
+13A0..13FF; Cherokee
+1400..167F; Unified Canadian Aboriginal Syllabics
+1680..169F; Ogham
+16A0..16FF; Runic
+1700..171F; Tagalog
+1720..173F; Hanunoo
+1740..175F; Buhid
+1760..177F; Tagbanwa
+1780..17FF; Khmer
+1800..18AF; Mongolian
+1900..194F; Limbu
+1950..197F; Tai Le
+1980..19DF; New Tai Lue
+19E0..19FF; Khmer Symbols
+1A00..1A1F; Buginese
+1D00..1D7F; Phonetic Extensions
+1D80..1DBF; Phonetic Extensions Supplement
+1DC0..1DFF; Combining Diacritical Marks Supplement
+1E00..1EFF; Latin Extended Additional
+1F00..1FFF; Greek Extended
+2000..206F; General Punctuation
+2070..209F; Superscripts and Subscripts
+20A0..20CF; Currency Symbols
+20D0..20FF; Combining Diacritical Marks for Symbols
+2100..214F; Letterlike Symbols
+2150..218F; Number Forms
+2190..21FF; Arrows
+2200..22FF; Mathematical Operators
+2300..23FF; Miscellaneous Technical
+2400..243F; Control Pictures
+2440..245F; Optical Character Recognition
+2460..24FF; Enclosed Alphanumerics
+2500..257F; Box Drawing
+2580..259F; Block Elements
+25A0..25FF; Geometric Shapes
+2600..26FF; Miscellaneous Symbols
+2700..27BF; Dingbats
+27C0..27EF; Miscellaneous Mathematical Symbols-A
+27F0..27FF; Supplemental Arrows-A
+2800..28FF; Braille Patterns
+2900..297F; Supplemental Arrows-B
+2980..29FF; Miscellaneous Mathematical Symbols-B
+2A00..2AFF; Supplemental Mathematical Operators
+2B00..2BFF; Miscellaneous Symbols and Arrows
+2C00..2C5F; Glagolitic
+2C80..2CFF; Coptic
+2D00..2D2F; Georgian Supplement
+2D30..2D7F; Tifinagh
+2D80..2DDF; Ethiopic Extended
+2E00..2E7F; Supplemental Punctuation
+2E80..2EFF; CJK Radicals Supplement
+2F00..2FDF; Kangxi Radicals
+2FF0..2FFF; Ideographic Description Characters
+3000..303F; CJK Symbols and Punctuation
+3040..309F; Hiragana
+30A0..30FF; Katakana
+3100..312F; Bopomofo
+3130..318F; Hangul Compatibility Jamo
+3190..319F; Kanbun
+31A0..31BF; Bopomofo Extended
+31C0..31EF; CJK Strokes
+31F0..31FF; Katakana Phonetic Extensions
+3200..32FF; Enclosed CJK Letters and Months
+3300..33FF; CJK Compatibility
+3400..4DBF; CJK Unified Ideographs Extension A
+4DC0..4DFF; Yijing Hexagram Symbols
+4E00..9FFF; CJK Unified Ideographs
+A000..A48F; Yi Syllables
+A490..A4CF; Yi Radicals
+A700..A71F; Modifier Tone Letters
+A800..A82F; Syloti Nagri
+AC00..D7AF; Hangul Syllables
+D800..DB7F; High Surrogates
+DB80..DBFF; High Private Use Surrogates
+DC00..DFFF; Low Surrogates
+E000..F8FF; Private Use Area
+F900..FAFF; CJK Compatibility Ideographs
+FB00..FB4F; Alphabetic Presentation Forms
+FB50..FDFF; Arabic Presentation Forms-A
+FE00..FE0F; Variation Selectors
+FE10..FE1F; Vertical Forms
+FE20..FE2F; Combining Half Marks
+FE30..FE4F; CJK Compatibility Forms
+FE50..FE6F; Small Form Variants
+FE70..FEFF; Arabic Presentation Forms-B
+FF00..FFEF; Halfwidth and Fullwidth Forms
+FFF0..FFFF; Specials
+10000..1007F; Linear B Syllabary
+10080..100FF; Linear B Ideograms
+10100..1013F; Aegean Numbers
+10140..1018F; Ancient Greek Numbers
+10300..1032F; Old Italic
+10330..1034F; Gothic
+10380..1039F; Ugaritic
+103A0..103DF; Old Persian
+10400..1044F; Deseret
+10450..1047F; Shavian
+10480..104AF; Osmanya
+10800..1083F; Cypriot Syllabary
+10A00..10A5F; Kharoshthi
+1D000..1D0FF; Byzantine Musical Symbols
+1D100..1D1FF; Musical Symbols
+1D200..1D24F; Ancient Greek Musical Notation
+1D300..1D35F; Tai Xuan Jing Symbols
+1D400..1D7FF; Mathematical Alphanumeric Symbols
+20000..2A6DF; CJK Unified Ideographs Extension B
+2F800..2FA1F; CJK Compatibility Ideographs Supplement
+E0000..E007F; Tags
+E0100..E01EF; Variation Selectors Supplement
+F0000..FFFFF; Supplementary Private Use Area-A
+100000..10FFFF; Supplementary Private Use Area-B
--- /dev/null
+++ b/lib/unidata/index2.txt
@@ -1,0 +1,4307 @@
+8859-1 (Latin-1), Based on ISO 00A0
+8859-2, -3, -4, -9 (European Latin), Based on ISO 0100
+8859-5 (Cyrillic), Based on ISO 0400
+8859-6 (Arabic), Based on ISO 0600
+8859-7 (Greek), Based on ISO 0370
+8859-8 (Hebrew), Based on ISO 05D0
+A, COMBINING LATIN SMALL LETTER 0363
+a, latin small letter script 0251
+A, LATIN SMALL LETTER TURNED 0250
+ABBREVIATION MARK, ARMENIAN 055F
+ABBREVIATION MARK, SYRIAC 070F
+ABBREVIATION SIGN, DEVANAGARI 0970
+Abbreviations, Squared Latin 3371
+Aboriginal Syllabics, Unified Canadian 1400
+above, cedilla 0312
+ABOVE, COMBINING ALMOST EQUAL TO 034C
+ABOVE, COMBINING BRIDGE 0346
+ABOVE, COMBINING CLOCKWISE ARROW 20D5
+ABOVE, COMBINING COMMA 0313
+ABOVE, COMBINING DOT 0307
+ABOVE, COMBINING DOUBLE VERTICAL LINE 030E
+ABOVE, COMBINING FOUR DOTS 20DC
+ABOVE, COMBINING HOMOTHETIC 034B
+ABOVE, COMBINING HOOK 0309
+ABOVE, COMBINING LEFT ANGLE 031A
+ABOVE, COMBINING LEFT ARROW 20D6
+ABOVE, COMBINING LEFT HARPOON 20D0
+ABOVE, COMBINING LEFT RIGHT ARROW 20E1
+ABOVE, COMBINING NOT TILDE 034A
+ABOVE, COMBINING REVERSED COMMA 0314
+ABOVE, COMBINING RING 030A
+ABOVE, COMBINING THREE DOTS 20DB
+ABOVE, COMBINING TURNED COMMA 0312
+ABOVE, COMBINING VERTICAL LINE 030D
+ABOVE, COMBINING WIDE BRIDGE 20E9
+ABOVE, COMBINING X 033D
+ABOVE, DOT 02D9
+above, double dot 0308
+ABOVE, RING 02DA
+above, vee 030C
+ABOVE RIGHT, COMBINING COMMA 0315
+absolute continuity 2AA1
+ACCENT, ACUTE 00B4
+ACCENT, ALMOST EQUAL TO WITH CIRCUMFLEX 2A6F
+ACCENT, CIRCLED MULTIPLICATION SIGN WITH CIRCUMFLEX 2A36
+ACCENT, CIRCUMFLEX 005E
+ACCENT, COMBINING ACUTE 0301
+ACCENT, COMBINING CIRCUMFLEX 0302
+ACCENT, COMBINING DOUBLE ACUTE 030B
+ACCENT, COMBINING DOUBLE GRAVE 030F
+ACCENT, COMBINING GRAVE 0300
+ACCENT, DOUBLE ACUTE 02DD
+ACCENT, GRAVE 0060
+ACCENT, MODIFIER LETTER ACUTE 02CA
+ACCENT, MODIFIER LETTER CIRCUMFLEX 02C6
+ACCENT, MODIFIER LETTER CROSS 02DF
+ACCENT, MODIFIER LETTER GRAVE 02CB
+ACCENT, MODIFIER LETTER LOW ACUTE 02CF
+ACCENT, MODIFIER LETTER LOW GRAVE 02CE
+accent, swedish grave 02DF
+ACCENT ABOVE, PLUS SIGN WITH CIRCUMFLEX 2A23
+ACCENT BELOW, COMBINING ACUTE 0317
+ACCENT BELOW, COMBINING CIRCUMFLEX 032D
+ACCENT BELOW, COMBINING GRAVE 0316
+ACCOUNT OF 2100
+acknowledge 0006
+acknowledge, graphic for negative 237B
+acknowledge, negative 0015
+ACKNOWLEDGE, SYMBOL FOR 2406
+ACKNOWLEDGE, SYMBOL FOR NEGATIVE 2415
+ACTIVATE ARABIC FORM SHAPING 206D
+ACTIVATE SYMMETRIC SWAPPING 206B
+actuarial bend 20E7
+acute, spacing 00B4
+ACUTE ACCENT 00B4
+ACUTE ACCENT, COMBINING 0301
+ACUTE ACCENT, COMBINING DOUBLE 030B
+ACUTE ACCENT, DEVANAGARI 0954
+ACUTE ACCENT, DOUBLE 02DD
+ACUTE ACCENT, MODIFIER LETTER 02CA
+ACUTE ACCENT, MODIFIER LETTER LOW 02CF
+ACUTE ACCENT BELOW, COMBINING 0317
+ACUTE ANGLE 299F
+ACUTE TONE MARK, COMBINING 0341
+ADDRESSED TO THE SUBJECT 2101
+Addu dialect, consonant for 0780
+AE, LATIN SMALL LETTER 00E6
+Aegean Numbers 10100
+AEGEAN CHECK MARK 10102
+AEGEAN WORD SEPARATOR DOT 10101
+AEGEAN WORD SEPARATOR LINE 10100
+Ainu, Phonetic Extensions For 31F0
+AIRPLANE 2708
+aldus leaf 2766
+ALEF SYMBOL 2135
+ALL, FOR 2200
+ALL AROUND-PROFILE 232E
+ALL EQUAL TO 224C
+ALMOST EQUAL TO 2248
+ALMOST EQUAL TO, PRECEDES ABOVE 2AB7
+ALMOST EQUAL TO, PRECEDES ABOVE NOT 2AB9
+ALMOST EQUAL TO, SUBSET OF ABOVE 2AC9
+ALMOST EQUAL TO, SUCCEEDS ABOVE 2AB8
+ALMOST EQUAL TO, SUCCEEDS ABOVE NOT 2ABA
+ALMOST EQUAL TO, SUPERSET OF ABOVE 2ACA
+ALMOST EQUAL TO ABOVE, COMBINING 034C
+ALMOST EQUAL TO WITH CIRCUMFLEX ACCENT 2A6F
+ALPHA, LATIN SMALL LETTER 0251
+ALPHA, LATIN SMALL LETTER TURNED 0252
+Alphabetic Presentation Forms FB00
+Alphanumerics, Enclosed 2460
+alternating current 223F
+ALTERNATION MARK, PART 303D
+ALTERNATIVE KEY SYMBOL 2387
+ALVEOLAR CLICK, LATIN LETTER 01C2
+always (modal operator) 25FB
+always (modal operator), was 27E4
+always be (modal operator), will 27E5
+AMALGAMATION OR COPRODUCT 2A3F
+AMPERSAND 0026
+AMPERSAND, TURNED 214B
+AND, CURLY LOGICAL 22CF
+AND, LOGICAL 2227
+AND, N-ARY LOGICAL 22C0
+andrew's, cross st. 2613
+Ands and Ors, Logical 2A51
+ANGLE 2220
+ANGLE, ACUTE 299F
+ANGLE, MEASURED 2221
+ANGLE, RIGHT 221F
+ANGLE, SPHERICAL 2222
+ANGLE, TURNED 29A2
+ANGLE ABOVE, COMBINING LEFT 031A
+angle arc 2222
+ANGLE BELOW, COMBINING LEFT 0349
+ANGLE BRACKET, LEFT 3008
+ANGLE BRACKET, LEFT DOUBLE 300A
+ANGLE BRACKET, LEFT-POINTING 2329
+ANGLE BRACKET, MATHEMATICAL LEFT 27E8
+ANGLE BRACKET, MATHEMATICAL LEFT DOUBLE 27EA
+ANGLE BRACKET, RIGHT-POINTING 232A
+ANGLE OPENING LEFT, SPHERICAL 29A0
+ANGLE OPENING UP, SPHERICAL 29A1
+ANGLE QUOTATION MARK, LEFT-POINTING DOUBLE 00AB
+ANGLE QUOTATION MARK, RIGHT-POINTING DOUBLE 00BB
+ANGLE QUOTATION MARK, SINGLE LEFT-POINTING 2039
+ANGLE QUOTATION MARK, SINGLE RIGHT-POINTING 203A
+Angle Quotation Marks, Ornamental 276E
+ANGLE WITH ARC, RIGHT 22BE
+ANGLE WITH DOWNWARDS ZIGZAG ARROW, RIGHT 237C
+angled dash 00AC
+Angles and Measured Angles 299B
+ANGSTROM SIGN 212B
+ANKH 2625
+Annotation, Interlinear FFF9
+Annotation, Kanbun Ideographic 3190
+Annotation Signs, Koranic 06D6
+ANNUITY SYMBOL, COMBINING 20E7
+ano teleia 00B7
+ANTICLOCKWISE INTEGRATION 2A11
+ANTICLOCKWISE-ROTATED DIVISION SIGN, CIRCLED 29BC
+ANTIRESTRICTION, Z NOTATION DOMAIN 2A64
+ANTIRESTRICTION, Z NOTATION RANGE 2A65
+APL 2336
+APL Functional Symbols 2336
+apl jot 2218
+apl overbar 00AF
+apl quote 0022
+apl stile 2223
+apl tilde 223C
+apl upstile 2308
+APOSTROPHE 0027
+apostrophe 02BC
+apostrophe 2019
+APOSTROPHE, ARMENIAN 055A
+APOSTROPHE, MODIFIER LETTER 02BC
+APOSTROPHE, MODIFIER LETTER DOUBLE 02EE
+apostrophe-quote 0027
+APPLICATION, FUNCTION 2061
+application program command 009F
+APPROACHES THE LIMIT 2250
+APPROXIMATE, GREATER-THAN AND NOT 2A8A
+APPROXIMATE, GREATER-THAN OR 2A86
+APPROXIMATE, LESS-THAN AND NOT 2A89
+APPROXIMATE, LESS-THAN OR 2A85
+APPROXIMATELY EQUAL OR EQUAL TO 2A70
+APPROXIMATELY EQUAL TO 2245
+approximately equal to 2257
+AQUARIUS 2652
+Arabic 0600
+Arabic, Extended 0671
+ARABIC COMMA 060C
+ARABIC DECIMAL SEPARATOR 066B
+ARABIC END OF AYAH 06DD
+ARABIC FIVE POINTED STAR 066D
+ARABIC FOOTNOTE MARKER 0602
+ARABIC FORM SHAPING, ACTIVATE 206D
+ARABIC FORM SHAPING, INHIBIT 206C
+ARABIC FULL STOP 06D4
+Arabic Honorifics 0610
+ARABIC LETTER DOTLESS BEH 066E
+ARABIC LETTER DOTLESS QAF 066F
+Arabic Letters 0627
+ARABIC NUMBER SIGN 0600
+ARABIC PERCENT SIGN 066A
+Arabic Points 064B
+Arabic Presentation Forms-A FB50
+Arabic Presentation Forms-B FE70
+ARABIC QUESTION MARK 061F
+ARABIC SEMICOLON 061B
+ARABIC SIGN SAFHA 0603
+ARABIC SIGN SANAH 0601
+Arabic Poetic Marks 0610
+Arabic Subtending Marks 0600
+ARABIC TAIL FRAGMENT FE73
+ARABIC THOUSANDS SEPARATOR 066C
+Arabic-Indic Digits 0660
+Arabic-Indic Digits for Persian and Urdu, Eastern 06F0
+ARC 2312
+arc, angle 2222
+ARC, RIGHT ANGLE WITH 22BE
+ARCH BELOW, COMBINING INVERTED DOUBLE 032B
+Arcs 25DC
+area, end of guarded 0097
+area, end of selected 0087
+area, start of guarded 0096
+area, start of selected 0086
+ARIES 2648
+Armenian 0530
+ARMENIAN ABBREVIATION MARK 055F
+ARMENIAN APOSTROPHE 055A
+Armenian Capital Letters 0531
+ARMENIAN COMMA 055D
+ARMENIAN EMPHASIS MARK 055B
+ARMENIAN EXCLAMATION MARK 055C
+ARMENIAN FULL STOP 0589
+ARMENIAN HYPHEN 058A
+Armenian Ligatures FB13
+ARMENIAN QUESTION MARK 055E
+Armenian Small Letters 0561
+ARROW, BLACK CIRCLE WITH DOWN 29ED
+ARROW, BLACK DIAMOND WITH DOWN 29EA
+arrow, colon right 29F4
+ARROW, ELECTRIC 2301
+ARROW, RIGHT ANGLE WITH DOWNWARDS ZIGZAG 237C
+ARROW, WHITE CIRCLE WITH DOWN 29EC
+ARROW ABOVE, COMBINING CLOCKWISE 20D5
+ARROW ABOVE, COMBINING LEFT 20D6
+ARROW ABOVE, COMBINING LEFT RIGHT 20E1
+ARROW BELOW, COMBINING DOUBLE RIGHTWARDS 0362
+ARROW BELOW, COMBINING LEFT RIGHT 034D
+ARROW BELOW, COMBINING UPWARDS 034E
+Arrow Dingbats 2794
+ARROW OVERLAY, COMBINING LEFTWARDS 20EA
+ARROW THROUGH CIRCLE, UP 29BD
+ARROW WITH HOOK, INTEGRAL WITH LEFTWARDS 2A17
+ARROWHEAD, UP 2303
+Arrowheads, Modifier Letter 02C2
+Arrows 2190
+Arrows, Long 27F5
+Arrows, Other White and Black 2B00
+arrows extension 23AF
+Arrows-A, Supplemental 27F0
+Arrows-B, Supplemental 2900
+ASCENDING NODE 260A
+ASCII 0020
+ASCII C0 Control Codes 0000
+ASCII Digits 0030
+ASCII Variants, Fullwidth FF01
+ash 00E6
+ASSERTION 22A6
+ASTERISK 002A
+ASTERISK, EQUALS WITH 2A6E
+ASTERISK, LOW 204E
+ASTERISK, SQUARED 29C6
+Asterisk Dingbats 2722
+ASTERISK OPERATOR 2217
+ASTERISK OPERATOR, CIRCLED 229B
+ASTERISKS ALIGNED VERTICALLY, TWO 2051
+Asterisks and Snowflakes, Stars, 2721
+ASTERISM 2042
+Astrological Symbols 263D
+asymptotic to 2248
+ASYMPTOTICALLY EQUAL TO 2243
+AT, COMMERCIAL 0040
+AVERAGE WITH SLASH, INTEGRAL 2A0F
+AYAH, ARABIC END OF 06DD
+B, LATIN LETTER SMALL CAPITAL 0299
+B, SCRIPT CAPITAL 212C
+baby gamma, latin small letter 0264
+backslash 005C
+BACKSLASH, COMBINING ENCLOSING CIRCLE 20E0
+backspace 0008
+BACKSPACE, SYMBOL FOR 2408
+backward difference 2207
+bag bracket, z notation left 27E6
+BAG MEMBERSHIP, Z NOTATION 22FF
+bag subtraction, z notation 2A41
+BAHT, THAI CURRENCY SYMBOL 0E3F
+BALLOT BOX 2610
+BALLOT BOX WITH CHECK 2611
+BALLOT BOX WITH X 2612
+BALLOT X 2717
+BALLOT X, HEAVY 2718
+bang 0021
+bar, broken vertical 00A6
+BAR, CIRCLED VERTICAL 29B6
+BAR, HORIZONTAL 2015
+BAR, N-ARY WHITE VERTICAL 2AFF
+bar, vertical 007C
+BAR, WHITE VERTICAL 2AFE
+BAR BINARY RELATION, TRIPLE VERTICAL 2AF4
+BAR DELIMITER, TRIPLE VERTICAL 2980
+Bar Dingbats, Vertical 2758
+BAR OPERATOR, LARGE TRIPLE VERTICAL 2AFC
+Bar Symbols, Error 29EE
+BAR WITH DOUBLE VERTICAL STROKE, TRIPLE HORIZONTAL 2A68
+BAR WITH HORIZONTAL STROKE, TRIPLE VERTICAL 2AF5
+BAR WITH TRIPLE VERTICAL STROKE, TRIPLE HORIZONTAL 2A69
+barred o, latin capital letter 019F
+BARRED O, LATIN SMALL LETTER 0275
+Basic Latin, C0 Controls and 0000
+Basic Russian Alphabet 0410
+BEAMED EIGHTH NOTES 266B
+BEAMED SIXTEENTH NOTES 266C
+BECAUSE 2235
+beginning of line 2310
+bell 0007
+BELL, SYMBOL FOR 2407
+BELL SYMBOL 237E
+BELOW, COMBINING ACUTE ACCENT 0317
+BELOW, COMBINING BREVE 032E
+BELOW, COMBINING BRIDGE 032A
+BELOW, COMBINING CARON 032C
+BELOW, COMBINING CIRCUMFLEX ACCENT 032D
+BELOW, COMBINING COMMA 0326
+BELOW, COMBINING DIAERESIS 0324
+BELOW, COMBINING DOT 0323
+BELOW, COMBINING DOUBLE RIGHTWARDS ARROW 0362
+BELOW, COMBINING DOUBLE VERTICAL LINE 0348
+BELOW, COMBINING EQUALS SIGN 0347
+BELOW, COMBINING GRAVE ACCENT 0316
+BELOW, COMBINING INVERTED BREVE 032F
+BELOW, COMBINING INVERTED BRIDGE 033A
+BELOW, COMBINING INVERTED DOUBLE ARCH 032B
+BELOW, COMBINING LEFT ANGLE 0349
+BELOW, COMBINING LEFT HALF RING 031C
+BELOW, COMBINING LEFT RIGHT ARROW 034D
+BELOW, COMBINING LEFT TACK 0318
+BELOW, COMBINING MACRON 0331
+BELOW, COMBINING MINUS SIGN 0320
+BELOW, COMBINING PALATALIZED HOOK 0321
+BELOW, COMBINING PLUS SIGN 031F
+BELOW, COMBINING RETROFLEX HOOK 0322
+BELOW, COMBINING RIGHT HALF RING 0339
+BELOW, COMBINING RING 0325
+BELOW, COMBINING SEAGULL 033C
+BELOW, COMBINING SQUARE 033B
+BELOW, COMBINING TILDE 0330
+BELOW, COMBINING UP TACK 031D
+BELOW, COMBINING UPWARDS ARROW 034E
+BELOW, COMBINING VERTICAL LINE 0329
+below, greek non-spacing iota 0345
+bend, actuarial 20E7
+Bengali 0980
+Bengali Currency Signs 09F2
+Bengali Digits 09E6
+Bengali Letters 0985
+BENGALI RUPEE MARK 09F2
+BENGALI RUPEE SIGN 09F3
+BENZENE RING 232C
+bernoulli function 212C
+BET SYMBOL 2136
+Betty BOOP 263A
+BETWEEN 226C
+BEVERAGE, HOT 2615
+BIDENTAL PERCUSSIVE, LATIN LETTER 02AD
+Bidirectional Formatting Controls 202A
+Big 5, Duplicates from FA0C
+BIG REVERSE SOLIDUS 29F9
+BIG SOLIDUS 29F8
+bijection, z notation 2917
+bijective mapping 2916
+BILABIAL CLICK, LATIN LETTER 0298
+BILABIAL PERCUSSIVE, LATIN LETTER 02AC
+BINARY RELATION, TRIPLE SOLIDUS 2AFB
+BINARY RELATION, TRIPLE VERTICAL BAR 2AF4
+BIOHAZARD SIGN 2623
+BLACK, BOWTIE WITH LEFT HALF 29D1
+BLACK, BOWTIE WITH RIGHT HALF 29D2
+BLACK, DOWN-POINTING TRIANGLE WITH LEFT HALF 29E8
+BLACK, DOWN-POINTING TRIANGLE WITH RIGHT HALF 29E9
+BLACK, TIMES WITH LEFT HALF 29D4
+BLACK, TIMES WITH RIGHT HALF 29D5
+BLACK BOWTIE 29D3
+BLACK CIRCLE WITH DOWN ARROW 29ED
+BLACK CIRCLE WITH TWO WHITE DOTS 2689
+BLACK CIRCLE WITH WHITE DOT RIGHT 2688
+Black Circled Numbers, White On 24EB
+BLACK DIAMOND WITH DOWN ARROW 29EA
+BLACK FLAG 2691
+BLACK HOURGLASS 29D7
+BLACK LEFT POINTING INDEX 261A
+BLACK LEFTWARDS BULLET 204C
+BLACK LENTICULAR BRACKET, LEFT 3010
+BLACK LOZENGE 29EB
+BLACK MEDIUM SMALL SQUARE 25FE
+BLACK MEDIUM SQUARE 25FC
+BLACK NIB 2712
+BLACK PARALLELOGRAM 25B0
+BLACK SCISSORS 2702
+BLACK SHOGI PIECE 2617
+black small circle 2022
+BLACK SMILING FACE 263B
+BLACK STAR 2605
+BLACK SUN WITH RAYS 2600
+BLACK TELEPHONE 260E
+BLACK TRIANGLE, PLUS SIGN WITH 2A28
+BLACK UNIVERSAL RECYCLING SYMBOL 267B
+BLACK-LETTER CAPITAL C 212D
+BLACK-LETTER CAPITAL H 210C
+BLACK-LETTER CAPITAL I 2111
+BLACK-LETTER CAPITAL R 211C
+BLACK-LETTER CAPITAL Z 2128
+BLANK SYMBOL 2422
+block, end of transmission 0017
+BLOCK, SYMBOL FOR END OF TRANSMISSION 2417
+Block Elements 2580
+bom FEFF
+Bopomofo, Chinese 3100
+Bopomofo Extended for Minnan and Hakka, Chinese 31A0
+BOWTIE 22C8
+bowtie, large 2A1D
+Bowtie Symbols 29D1
+BOX, BALLOT 2610
+BOX, OPEN 2423
+BOX, SHOULDERED OPEN 237D
+BOX, X IN A RECTANGLE 2327
+Box Drawing 2500
+BOX LINE, LEFT VERTICAL 23B8
+BOX LINE, RIGHT VERTICAL 23B9
+BOX OPERATOR, SQUARE LEFT OPEN 2ACD
+BOX OPERATOR, SQUARE RIGHT OPEN 2ACE
+BOX WITH CHECK, BALLOT 2611
+BOX WITH X, BALLOT 2612
+bra 27E6
+brace, closing 007D
+brace, opening 007B
+bracket, z notation left bag 27E6
+bracket, closing curly 007D
+bracket, closing square 005D
+BRACKET, LEFT ANGLE 3008
+BRACKET, LEFT BLACK LENTICULAR 3010
+BRACKET, LEFT CORNER 300C
+BRACKET, LEFT CURLY 007B
+BRACKET, LEFT DOUBLE ANGLE 300A
+BRACKET, LEFT SQUARE 005B
+BRACKET, LEFT TORTOISE SHELL 3014
+BRACKET, LEFT WHITE CORNER 300E
+BRACKET, LEFT WHITE LENTICULAR 3016
+BRACKET, LEFT WHITE SQUARE 301A
+BRACKET, LEFT WHITE TORTOISE SHELL 3018
+BRACKET, LEFT-POINTING ANGLE 2329
+bracket, opening curly 007B
+bracket, opening square 005B
+BRACKET, RIGHT CURLY 007D
+BRACKET, RIGHT SQUARE 005D
+Bracket Pieces 239B
+Bracket Pieces 23B0
+BRACKET WITH QUILL, LEFT SQUARE 2045
+Brackets 2983
+Brackets, CJK Angle 3008
+Brackets, Corner 2308
+Brackets, CJK Corner 300C
+Brackets, CJK 3010
+Brackets, CJK 3014
+Brackets, Fullwidth FF5F
+Brackets, Mathematical 27E6
+Brackets, Ornamental 2768
+Brackets, Ornamental 2770
+Brackets, Vertical 23B4
+Braille Patterns 2800
+brazilian currency 20A2
+break here, no 0083
+break permitted here 0082
+breathing, rough 0314
+breathing, smooth 0313
+BREVE 02D8
+BREVE, COMBINING 0306
+BREVE, COMBINING DOUBLE INVERTED 0361
+BREVE, COMBINING INVERTED 0311
+BREVE BELOW, COMBINING 032E
+BREVE BELOW, COMBINING INVERTED 032F
+BRIDGE ABOVE, COMBINING 0346
+BRIDGE ABOVE, COMBINING WIDE 20E9
+BRIDGE BELOW, COMBINING 032A
+BRIDGE BELOW, COMBINING INVERTED 033A
+broken vertical bar 00A6
+Buhid 1740
+BULLET 2022
+BULLET, BLACK LEFTWARDS 204C
+BULLET, HYPHEN 2043
+BULLET, REVERSED ROTATED FLORAL HEART 2619
+bullet, tainome (japanese, a kind of) 25C9
+BULLET, TRIANGULAR 2023
+BULLET, WHITE 25E6
+BULLET OPERATOR 2219
+BULLSEYE 25CE
+bullseye, latin letter 0298
+BUMPY ABOVE, EQUALS SIGN WITH 2AAE
+BY, MEASURED 225E
+by definition, equal to 225C
+BY DEFINITION, EQUAL TO 225D
+byte order mark FEFF
+C, BLACK-LETTER CAPITAL 212D
+C, COMBINING LATIN SMALL LETTER 0368
+C, DOUBLE-STRUCK CAPITAL 2102
+C, LATIN LETTER STRETCHED 0297
+C0 Controls and Basic Latin 0000
+C1 Controls and Latin-1 Supplement 0080
+CADA UNA 2106
+CADUCEUS 2624
+Canadian Aboriginal Syllabics, Unified 1400
+cancel 0018
+CANCEL, SYMBOL FOR 2418
+cancel character 0094
+CANCER 264B
+CANDRABINDU, COMBINING 0310
+Cantillation Marks, Hebrew 0591
+cap 2229
+CAP, SQUARE 2293
+Capital Letters, Armenian 0531
+Capital Letters, Cyrillic 0401
+Capital Letters, Georgian 10A0
+Capital Letters, Greek 0391
+Capital Letters, Latin 0041
+CAPRICORN 2651
+caps lock 21EA
+caps lock 21EC
+Card Suits, Playing 2660
+cardinal (countable), first transfinite 2135
+cardinal (functions of a real variable), third transfinite 2137
+cardinal (the continuum), second transfinite 2136
+CARE OF 2105
+caret 028C
+CARET 2038
+CARET INSERTION POINT 2041
+CARON 02C7
+CARON, COMBINING 030C
+CARON BELOW, COMBINING 032C
+carriage return 000D
+carriage return 21B5
+CARRIAGE RETURN, SYMBOL FOR 240D
+CAUTION SIGN 2621
+CEDILLA 00B8
+CEDILLA, COMBINING 0327
+cedilla, spacing 00B8
+cedilla above 0312
+CEILING, LEFT 2308
+CELSIUS, DEGREE 2103
+CENT SIGN 00A2
+centigrade, degrees 2103
+CENTRE LINE SYMBOL 2104
+CENTRED LEFT HALF RING, MODIFIER LETTER 02D3
+CENTRELINE LOW LINE FE4E
+CENTRELINE OVERLINE FE4A
+cgj 034F
+character introducer, single 009A
+character tabulation set 0088
+character tabulation with justification 0089
+CHARACTER TIE 2040
+Chart Components, Form and 2500
+CHECK, BALLOT BOX WITH 2611
+CHECK MARK 2713
+CHECK MARK, AEGEAN 10102
+CHECK MARK, HEAVY 2714
+CHECK MARK, NOT 237B
+Cherokee 13A0
+Chess Pieces 2654
+Chess Symbols, Japanese 2616
+chevrons 00AB
+CHI RHO 2627
+Chinese Bopomofo 3100
+Chinese Bopomofo Extended for Minnan and Hakka 31A0
+choice, dijkstra 2AFE
+choice, n-ary dijkstra 2AFF
+CIRCLE, BLACK 25CF
+circle, black small 2022
+CIRCLE, COMBINING ENCLOSING 20DD
+CIRCLE, DOTTED 25CC
+circle, jis composition 20DD
+CIRCLE, LARGE 25EF
+CIRCLE, MULTIPLICATION SIGN IN DOUBLE 2A37
+CIRCLE, MULTIPLICATION SIGN IN LEFT HALF 2A34
+CIRCLE, MULTIPLICATION SIGN IN RIGHT HALF 2A35
+CIRCLE, PLUS SIGN IN LEFT HALF 2A2D
+CIRCLE, PLUS SIGN IN RIGHT HALF 2A2E
+CIRCLE, SQUARED SMALL 29C7
+CIRCLE ABOVE, PLUS SIGN WITH SMALL 2A22
+CIRCLE ABOVE, UP TACK WITH 27DF
+CIRCLE ABOVE, VERTICAL LINE WITH 2AEF
+CIRCLE BACKSLASH, COMBINING ENCLOSING 20E0
+CIRCLE BELOW, DOWN TACK WITH 2AF1
+CIRCLE BELOW, VERTICAL LINE WITH 2AF0
+CIRCLE DIVIDED BY HORIZONTAL BAR AND TOP HALF DIVIDED BY VERTICAL BAR 29BA
+CIRCLE INSIDE, GREATER-THAN WITH 2A7A
+CIRCLE INSIDE, LESS-THAN WITH 2A79
+Circle Symbols 29B5
+CIRCLE WITH DOT RIGHT, WHITE 2686
+CIRCLE WITH DOWN ARROW, BLACK 29ED
+CIRCLE WITH DOWN ARROW, WHITE 29EC
+CIRCLE WITH TWO DOTS, WHITE 2687
+CIRCLE WITH TWO WHITE DOTS, BLACK 2689
+CIRCLE WITH WHITE DOT RIGHT, BLACK 2688
+CIRCLED ASTERISK OPERATOR 229B
+CIRCLED DASH 229D
+CIRCLED DIGIT ZERO 24EA
+Circled Digits, Dingbat 2776
+CIRCLED DIVISION SIGN 2A38
+CIRCLED DIVISION SLASH 2298
+CIRCLED DOT OPERATOR 2299
+CIRCLED DOT OPERATOR, N-ARY 2A00
+CIRCLED EQUALS 229C
+Circled Ideographs 3280
+Circled Inverse Numbers 2776
+Circled Japanese Katakana 32D0
+Circled Korean Hangul Elements 3260
+Circled Korean Hangul Syllables 326E
+Circled Latin Letters 24B6
+CIRCLED MINUS 2296
+CIRCLED MULTIPLICATION SIGN WITH CIRCUMFLEX ACCENT 2A36
+Circled Numbers 2460
+Circled Numbers 3251
+Circled Numbers 32B1
+Circled Numbers, Double 24F5
+Circled Numbers, White On Black 24EB
+CIRCLED PLUS 2295
+CIRCLED PLUS OPERATOR, N-ARY 2A01
+CIRCLED POSTAL MARK 3036
+CIRCLED RING OPERATOR 229A
+CIRCLED TIMES 2297
+CIRCLED TIMES OPERATOR, N-ARY 2A02
+Circles 25CB
+CIRCULATION FUNCTION 2A10
+circumflex, spacing 005E
+CIRCUMFLEX ACCENT 005E
+CIRCUMFLEX ACCENT, ALMOST EQUAL TO WITH 2A6F
+CIRCUMFLEX ACCENT, CIRCLED MULTIPLICATION SIGN WITH 2A36
+CIRCUMFLEX ACCENT, COMBINING 0302
+CIRCUMFLEX ACCENT, MODIFIER LETTER 02C6
+CIRCUMFLEX ACCENT ABOVE, PLUS SIGN WITH 2A23
+CIRCUMFLEX ACCENT BELOW, COMBINING 032D
+CJK Compatibility 3300
+CJK Compatibility Forms FE30
+CJK Compatibility Ideographs F900
+CJK Compatibility Ideographs, IBM FA0E
+CJK Ideographs Area 3400
+CJK Letters and Ideographs, Enclosed 3200
+CJK Phonetics and Symbols Area 2E00
+CJK Radicals Supplement 2E80
+CJK Symbols and Punctuation 3000
+CJK Unified Ideographs 4E00
+CJK Unified Ideographs Extension A 3400
+clear key 2327
+CLEAR SCREEN SYMBOL 239A
+clear weather 2600
+CLICK, LATIN LETTER ALVEOLAR 01C2
+CLICK, LATIN LETTER BILABIAL 0298
+CLICK, LATIN LETTER DENTAL 01C0
+CLICK, LATIN LETTER LATERAL 01C1
+CLICK, LATIN LETTER RETROFLEX 01C3
+CLOCKWISE ARROW ABOVE, COMBINING 20D5
+CLOCKWISE CONTOUR INTEGRAL 2232
+CLOCKWISE INTEGRAL 2231
+CLOCKWISE RING OVERLAY, COMBINING 20D9
+clone 2104
+Clones of Diacritics, Spacing 02D8
+CLOSE UP 2050
+closed epsilon, latin small letter 029A
+CLOSED INTERSECTION WITH SERIFS 2A4D
+CLOSED OMEGA, LATIN SMALL LETTER 0277
+CLOSED OPEN E, LATIN SMALL LETTER 029A
+closed reversed epsilon, latin small letter 025E
+CLOSED REVERSED OPEN E, LATIN SMALL LETTER 025E
+CLOSED SUBSET 2ACF
+CLOSED SUBSET OR EQUAL TO 2AD1
+CLOSED SUPERSET 2AD0
+CLOSED SUPERSET OR EQUAL TO 2AD2
+CLOSED UNION WITH SERIFS 2A4C
+CLOSED UNION WITH SERIFS AND SMASH PRODUCT 2A50
+closing brace 007D
+closing curly bracket 007D
+CLOSING MARK, IDEOGRAPHIC 3006
+closing parenthesis 0029
+closing square bracket 005D
+CLOUD 2601
+cloudy weather 2601
+Codes, Process Internal FDD0
+coffee 2615
+COLON 003A
+COLON, ETHIOPIC 1365
+COLON, MODIFIER LETTER HALF TRIANGULAR 02D1
+COLON, MODIFIER LETTER TRIANGULAR 02D0
+COLON, MONGOLIAN 1804
+COLON, Z NOTATION TYPE 2982
+COLON EQUAL, DOUBLE 2A74
+COLON EQUALS 2254
+COLON OPERATOR, TRIPLE 2AF6
+colon right arrow 29F4
+COLON SIGN 20A1
+COMBINING ACUTE ACCENT 0301
+COMBINING ACUTE ACCENT BELOW 0317
+COMBINING ACUTE TONE MARK 0341
+COMBINING ALMOST EQUAL TO ABOVE 034C
+Combining Alphabet, Korean Hangul Jamo 1100
+COMBINING ANNUITY SYMBOL 20E7
+COMBINING BREVE 0306
+COMBINING BREVE BELOW 032E
+COMBINING BRIDGE ABOVE 0346
+COMBINING BRIDGE BELOW 032A
+COMBINING CANDRABINDU 0310
+COMBINING CARON 030C
+COMBINING CARON BELOW 032C
+COMBINING CEDILLA 0327
+Combining Characters, Cyrillic 0483
+COMBINING CIRCUMFLEX ACCENT 0302
+COMBINING CIRCUMFLEX ACCENT BELOW 032D
+COMBINING CLOCKWISE ARROW ABOVE 20D5
+COMBINING CLOCKWISE RING OVERLAY 20D9
+COMBINING COMMA ABOVE 0313
+COMBINING COMMA ABOVE RIGHT 0315
+COMBINING COMMA BELOW 0326
+Combining Diacritical Marks 0300
+Combining Diacritical Marks for Symbols 20D0
+COMBINING DIAERESIS 0308
+COMBINING DIAERESIS BELOW 0324
+COMBINING DOT ABOVE 0307
+COMBINING DOT BELOW 0323
+COMBINING DOUBLE ACUTE ACCENT 030B
+COMBINING DOUBLE GRAVE ACCENT 030F
+COMBINING DOUBLE INVERTED BREVE 0361
+COMBINING DOUBLE LOW LINE 0333
+COMBINING DOUBLE OVERLINE 033F
+COMBINING DOUBLE RIGHTWARDS ARROW BELOW 0362
+COMBINING DOUBLE TILDE 0360
+COMBINING DOUBLE TILDE LEFT HALF FE22
+COMBINING DOUBLE VERTICAL LINE ABOVE 030E
+COMBINING DOUBLE VERTICAL LINE BELOW 0348
+COMBINING DOUBLE VERTICAL STROKE OVERLAY 20E6
+COMBINING DOWN TACK BELOW 031E
+COMBINING ENCLOSING CIRCLE 20DD
+COMBINING ENCLOSING CIRCLE BACKSLASH 20E0
+COMBINING ENCLOSING DIAMOND 20DF
+COMBINING ENCLOSING KEYCAP 20E3
+COMBINING ENCLOSING SCREEN 20E2
+COMBINING ENCLOSING SQUARE 20DE
+COMBINING ENCLOSING UPWARD POINTING TRIANGLE 20E4
+COMBINING EQUALS SIGN BELOW 0347
+COMBINING FOUR DOTS ABOVE 20DC
+COMBINING GRAPHEME JOINER 034F
+COMBINING GRAVE ACCENT 0300
+COMBINING GRAVE ACCENT BELOW 0316
+COMBINING GRAVE TONE MARK 0340
+COMBINING GREEK DIALYTIKA TONOS 0344
+COMBINING GREEK KORONIS 0343
+COMBINING GREEK PERISPOMENI 0342
+COMBINING GREEK YPOGEGRAMMENI 0345
+combining hacek 030C
+Combining Half Marks FE20
+COMBINING HOMOTHETIC ABOVE 034B
+COMBINING HOOK ABOVE 0309
+COMBINING HORN 031B
+COMBINING INVERTED BREVE 0311
+COMBINING INVERTED BREVE BELOW 032F
+COMBINING INVERTED BRIDGE BELOW 033A
+COMBINING INVERTED DOUBLE ARCH BELOW 032B
+COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK 3099
+Combining Latin Small Letters 0363
+COMBINING LEFT ANGLE ABOVE 031A
+COMBINING LEFT ANGLE BELOW 0349
+COMBINING LEFT ARROW ABOVE 20D6
+COMBINING LEFT HALF RING BELOW 031C
+COMBINING LEFT HARPOON ABOVE 20D0
+COMBINING LEFT RIGHT ARROW ABOVE 20E1
+COMBINING LEFT RIGHT ARROW BELOW 034D
+COMBINING LEFT TACK BELOW 0318
+COMBINING LEFTWARDS ARROW OVERLAY 20EA
+COMBINING LIGATURE LEFT HALF FE20
+COMBINING LONG SOLIDUS OVERLAY 0338
+COMBINING LONG STROKE OVERLAY 0336
+COMBINING LONG VERTICAL LINE OVERLAY 20D2
+COMBINING LOW LINE 0332
+COMBINING MACRON 0304
+COMBINING MACRON BELOW 0331
+COMBINING MINUS SIGN BELOW 0320
+COMBINING NOT TILDE ABOVE 034A
+COMBINING OGONEK 0328
+COMBINING OVERLINE 0305
+COMBINING PALATALIZED HOOK BELOW 0321
+COMBINING PLUS SIGN BELOW 031F
+COMBINING RETROFLEX HOOK BELOW 0322
+COMBINING REVERSE SOLIDUS OVERLAY 20E5
+COMBINING REVERSED COMMA ABOVE 0314
+COMBINING RIGHT HALF RING BELOW 0339
+COMBINING RING ABOVE 030A
+COMBINING RING BELOW 0325
+COMBINING RING OVERLAY 20D8
+COMBINING SEAGULL BELOW 033C
+COMBINING SHORT SOLIDUS OVERLAY 0337
+COMBINING SHORT STROKE OVERLAY 0335
+COMBINING SHORT VERTICAL LINE OVERLAY 20D3
+COMBINING SQUARE BELOW 033B
+COMBINING THREE DOTS ABOVE 20DB
+COMBINING TILDE 0303
+COMBINING TILDE BELOW 0330
+COMBINING TILDE OVERLAY 0334
+COMBINING TRIPLE UNDERDOT 20E8
+COMBINING TURNED COMMA ABOVE 0312
+COMBINING UP TACK BELOW 031D
+COMBINING UPWARDS ARROW BELOW 034E
+COMBINING VERTICAL LINE ABOVE 030D
+COMBINING VERTICAL LINE BELOW 0329
+COMBINING VERTICAL TILDE 033E
+COMBINING WIDE BRIDGE ABOVE 20E9
+COMBINING X ABOVE 033D
+COMET 2604
+COMMA 002C
+COMMA, ARABIC 060C
+COMMA, ARMENIAN 055D
+COMMA, ETHIOPIC 1363
+comma, georgian 00B7
+COMMA, IDEOGRAPHIC 3001
+comma, invisible 2063
+COMMA, MODIFIER LETTER REVERSED 02BD
+COMMA, MODIFIER LETTER TURNED 02BB
+COMMA, MONGOLIAN 1802
+COMMA ABOVE, COMBINING 0313
+COMMA ABOVE, COMBINING REVERSED 0314
+COMMA ABOVE, COMBINING TURNED 0312
+COMMA ABOVE, MINUS SIGN WITH 2A29
+COMMA ABOVE RIGHT, COMBINING 0315
+COMMA BELOW, COMBINING 0326
+comma quotation mark, double 201D
+comma quotation mark, double reversed 201F
+comma quotation mark, double turned 201C
+comma quotation mark, low double 201E
+comma quotation mark, low single 201A
+comma quotation mark, single 2019
+comma quotation mark, single reversed 201B
+comma quotation mark, single turned 2018
+command, application program 009F
+command, operating system 009D
+command key 2318
+COMMERCIAL AT 0040
+COMMERCIAL MINUS SIGN 2052
+compass 263C
+Compatibility, CJK 3300
+Compatibility and Specials Area F900
+Compatibility Forms, CJK FE30
+Compatibility Ideographs, CJK F900
+Compatibility Ideographs, IBM CJK FA0E
+Compatibility Jamo, Korean Hangul 3130
+COMPLEMENT 2201
+complex numbers, the set of 2102
+component, radial 27DF
+Components, Form and Chart 2500
+composite function 2218
+COMPOSITION, Z NOTATION RELATIONAL 2A3E
+COMPOSITION, Z NOTATION SCHEMA 2A1F
+composition circle, jis 20DD
+COMPOSITION SYMBOL 2384
+concatenation, z notation sequence 2040
+CONCAVE-SIDED DIAMOND, WHITE 27E1
+CONCAVE-SIDED DIAMOND WITH LEFTWARDS TICK, WHITE 27E2
+CONCAVE-SIDED DIAMOND WITH RIGHTWARDS TICK, WHITE 27E3
+conductance 2127
+CONGRUENT WITH DOT ABOVE 2A6D
+CONICAL TAPER 2332
+CONJUGATE MATRIX, HERMITIAN 22B9
+conjunction 2227
+CONJUNCTION 260C
+CONSECUTIVE EQUALS SIGNS, THREE 2A76
+CONSECUTIVE EQUALS SIGNS, TWO 2A75
+consonant for Addu dialect 0780
+CONTAINS AS MEMBER 220B
+CONTAINS AS MEMBER, SMALL 220D
+CONTAINS AS NORMAL SUBGROUP 22B3
+CONTAINS WITH LONG HORIZONTAL STROKE 22FA
+CONTAINS WITH OVERBAR 22FD
+CONTAINS WITH OVERBAR, SMALL 22FE
+CONTAINS WITH VERTICAL BAR AT END OF HORIZONTAL STROKE 22FB
+CONTAINS WITH VERTICAL BAR AT END OF HORIZONTAL STROKE, SMALL 22FC
+continuity, absolute 2AA1
+CONTINUOUS UNDERLINE SYMBOL 2381
+continuum, second transfinite cardinal 2136
+CONTOUR INTEGRAL 222E
+CONTOUR INTEGRAL, CLOCKWISE 2232
+CONTOURED OUTLINE, SQUARE WITH 29E0
+contraction operator 20E9
+control, graphic for 2388
+Control, Syriac Format 070F
+Control Code Graphics 25F0
+Control Codes, ASCII C0 0000
+Control Codes, C1 0080
+Control Codes, Graphic Pictures for 2400
+Control Codes, Graphics for 237B
+control sequence introducer 009B
+control string, device 0090
+Controls, Bidirectional Formatting 202A
+Controls, Mongolian Format 180B
+Controls and Basic Latin, C0 0000
+Controls and Latin-1 Supplement, C1 0080
+COPRODUCT, AMALGAMATION OR 2A3F
+COPRODUCT, N-ARY 2210
+Coptic, Greek and 0370
+Coptic-unique Letters 03E2
+COPYRIGHT, SOUND RECORDING 2117
+COPYRIGHT SIGN 00A9
+CORNER, TOP LEFT 231C
+CORNER BRACKET, LEFT 300C
+CORNER BRACKET, LEFT WHITE 300E
+Corner brackets 2308
+Corner brackets, CJK 300C
+CORNER WITH DOT, LOWER RIGHT 27D3
+CORNER WITH DOT, UPPER LEFT 27D4
+corners, Quine 231C
+CORPORATION, SQUARE 337F
+CORRESPONDS TO 2258
+corresponds to 2259
+costa rican currency 20A1
+countable, first transfinite cardinal 2135
+COUNTERBORE 2334
+COUNTERSINK 2335
+cr 000D
+CRESCENT, STAR AND 262A
+Croatian, Additions for Slovenian and 0200
+Croatian Digraphs Matching Serbian Cyrillic Letters 01C4
+CROP, TOP LEFT 230F
+CROSS, EAST SYRIAC 2671
+CROSS, LATIN 271D
+cross, long 2020
+CROSS, MALTESE 2720
+CROSS, ORTHODOX 2626
+cross, st. andrew's 2613
+CROSS, WEST SYRIAC 2670
+CROSS ACCENT, MODIFIER LETTER 02DF
+Cross Dingbats 2719
+CROSS OF JERUSALEM 2629
+CROSS OF LORRAINE 2628
+CROSS PRODUCT, VECTOR OR 2A2F
+cross ratio 211E
+CROSSBONES, SKULL AND 2620
+crosshatch 0023
+CRUZEIRO SIGN 20A2
+CUBE ROOT 221B
+cubed 00B3
+cup 222A
+CUP, SQUARE 2294
+curly bracket, closing 007D
+CURLY BRACKET, LEFT 007B
+curly bracket, opening 007B
+CURLY BRACKET, RIGHT 007D
+CURLY LOGICAL AND 22CF
+CURLY LOGICAL OR 22CE
+currency, brazilian 20A2
+currency, costa rican 20A1
+currency, el salvadorian 20A1
+currency, euro european 20AC
+currency, french 20A3
+currency, greek 20AF
+currency, hebrew 20AA
+currency, indian 20A8
+currency, iranian FDFC
+currency, israeli 20AA
+currency, italian 20A4
+currency, korean 20A9
+currency, laotian 20AD
+currency, mongolian 20AE
+currency, nigerian 20A6
+currency, phillipine 20B1
+currency, spanish 20A7
+currency, turkish 20A4
+currency, vietnamese 20AB
+CURRENCY SIGN 00A4
+Currency Signs, Bengali 09F2
+currency symbol, florin 0192
+CURRENCY SYMBOL BAHT, THAI 0E3F
+Currency Symbols 20A0
+current, alternating 223F
+CURRENT SYMBOL FORM TWO, DIRECT 2393
+cycle 223C
+CYLINDRICITY 232D
+Cypriot Syllabary 10800
+Cyrillic 0400
+Cyrillic, Extended 048C
+Cyrillic Capital Letters 0401
+Cyrillic Combining Characters 0483
+Cyrillic Extensions 0450
+Cyrillic Historic Letters 0460
+Cyrillic Komi Letters 0500
+Cyrillic Small Letters 0430
+Cyrillic Supplementary 0500
+D, COMBINING LATIN SMALL LETTER 0369
+D, DOUBLE-STRUCK ITALIC CAPITAL 2145
+D, DOUBLE-STRUCK ITALIC SMALL 2146
+D, LATIN CAPITAL LETTER AFRICAN 0189
+d retroflex hook, latin small letter 0256
+D WITH TAIL, LATIN SMALL LETTER 0256
+DAGGER 2020
+DAGGER, DOUBLE 2021
+d'alembertian 29E0
+DALET SYMBOL 2138
+DANDA, DEVANAGARI 0964
+DANDA, DEVANAGARI DOUBLE 0965
+dash, angled 00AC
+DASH, CIRCLED 229D
+DASH, EM 2014
+DASH, EN 2013
+DASH, FIGURE 2012
+dash, long 2015
+dash, quotation 2015
+DASH, SWUNG 2053
+DASH, WAVE 301C
+DASH, WAVY 3030
+DASHED LOW LINE FE4D
+DASHED OVERLINE FE49
+Dashes 2010
+dasia 0314
+data link escape 0010
+DATA LINK ESCAPE, SYMBOL FOR 2410
+Database Theory Operators 27D5
+DAVID, STAR OF 2721
+Days, Telegraph Symbols for 33E0
+DAY SIGN, TAMIL 0BF3
+decimal point 002E
+decimal separator 002C
+DECIMAL SEPARATOR, ARABIC 066B
+DECIMAL SEPARATOR KEY SYMBOL 2396
+deergh viram 0965
+definition, equal to by 225C
+DEFINITION, EQUAL TO BY 225D
+DEGREE CELSIUS 2103
+DEGREE FAHRENHEIT 2109
+DEGREE SIGN 00B0
+degrees centigrade 2103
+degrees kelvin 212A
+del 2207
+delete 007F
+DELETE, SYMBOL FOR 2421
+delete, undoable 2425
+DELETE FORM TWO, SYMBOL FOR 2425
+delete to the left key 232B
+delete to the right key 2326
+DELIMITER, TRIPLE VERTICAL BAR 2980
+DELTA, LATIN SMALL LETTER TURNED 018D
+DELTA EQUAL TO 225C
+DENTAL CLICK, LATIN LETTER 01C0
+Dentistry Notation Symbols 23BE
+depth symbol 21A7
+derivative 0307
+derivative, double 0308
+derivative, fourth 20DC
+derivative, third 20DB
+DESCENDING NODE 260B
+Description Characters, Ideographic 2FF0
+Devanagari 0900
+DEVANAGARI DANDA 0964
+Devanagari Digits 0966
+DEVANAGARI DOUBLE DANDA 0965
+Devanagari Letters 0905
+DEVANAGARI OM 0950
+device control four 0014
+DEVICE CONTROL FOUR, SYMBOL FOR 2414
+device control one 0011
+DEVICE CONTROL ONE, SYMBOL FOR 2411
+device control string 0090
+device control three 0013
+DEVICE CONTROL THREE, SYMBOL FOR 2413
+device control two 0012
+DEVICE CONTROL TWO, SYMBOL FOR 2412
+DHARMA, WHEEL OF 2638
+Diacritic-vowel Combinations, Pinyin 01CD
+Diacritical Marks, Combining 0300
+Diacritical Marks for Symbols, Combining 20D0
+Diacritics, Double 0360
+Diacritics, Enclosing 20DD
+Diacritics, Medieval Superscript Letter 0363
+Diacritics, Overstruck 0334
+Diacritics, Spacing Clones of 02D8
+Diacritics for Greek 0342
+Diacritics for IPA 0346
+DIAERESIS 00A8
+DIAERESIS, COMBINING 0308
+diaeresis, greek capital letter upsilon hook 03D4
+diaeresis, spacing 00A8
+DIAERESIS AND HOOK SYMBOL, GREEK UPSILON WITH 03D4
+DIAERESIS BELOW, COMBINING 0324
+DIAGONAL ELLIPSIS, UP RIGHT 22F0
+DIAGONAL SLASH, SQUARED FALLING 29C5
+DIAGONAL SLASH, SQUARED RISING 29C4
+dialytika 0308
+DIALYTIKA TONOS, COMBINING GREEK 0344
+DIAMETER SIGN 2300
+diameter symbol 2205
+DIAMOND, COMBINING ENCLOSING 20DF
+DIAMOND, WHITE CONCAVE-SIDED 27E1
+DIAMOND OPERATOR 22C4
+DIAMOND WITH CENTRED DOT, WHITE 27D0
+DIAMOND WITH DOWN ARROW, BLACK 29EA
+DIAMOND WITH LEFTWARDS TICK, WHITE CONCAVE-SIDED 27E2
+DIAMOND WITH RIGHTWARDS TICK, WHITE CONCAVE-SIDED 27E3
+Diamonds 25C6
+Dice 2680
+diesis 2021
+difference, backward 2207
+difference, forward 2206
+difference, sum or positive 2A26
+difference, symmetric 2238
+difference, symmetric 2296
+difference between 223C
+DIFFERENCE BETWEEN 224F
+difference or sum, positive 2A24
+DIFFERENTIAL, PARTIAL 2202
+DIGIT SHAPES, NATIONAL 206E
+DIGIT SHAPES, NOMINAL 206F
+Digits, Arabic-Indic 0660
+Digits, ASCII 0030
+Digits, Bengali 09E6
+Digits, Devanagari 0966
+Digits, Dingbat Circled 2776
+Digits, Ethiopic 1369
+Digits, Gujarati 0AE6
+Digits, Gurmukhi 0A66
+Digits, Kannada 0CE6
+Digits, Khmer 17E0
+Digits, Lao 0ED0
+Digits, Malayalam 0D66
+Digits, Mongolian 1810
+Digits, Myanmar 1040
+Digits, Oriya 0B66
+Digits, Osmanya 104A0
+Digits, Subscript 2080
+Digits, Superscript 2070
+Digits, Tamil 0BE7
+Digits, Telugu 0C66
+Digits, Thai 0E50
+Digits, Tibetan 0F20
+Digits for Persian and Urdu, Eastern Arabic-Indic 06F0
+DIGRAPH KOTO, KATAKANA 30FF
+DIGRAPH YORI, HIRAGANA 309F
+Digraphs, Phonetic 02A3
+Digraphs, Yiddish 05F0
+Digraphs Matching Serbian Cyrillic Letters, Croatian 01C4
+Digram Symbols, Yijing Monogram and 268A
+Digram Symbols, Tai Xuan Jing 1D301
+dijkstra choice 2AFE
+dijkstra choice, n-ary 2AFF
+DIMENSION ORIGIN 2331
+Dingbat Circled Digits 2776
+Dingbats 2700
+Dingbats, Arrow 2794
+Dingbats, Asterisk 2722
+Dingbats, Cross 2719
+Dingbats, Drop-Shadowed 274D
+Dingbats, Hazard 2620
+Dingbats, Heart 2763
+Dingbats, Miscellaneous 2600
+Dingbats, Music 2669
+Dingbats, Pencil 270E
+Dingbats, Pointing Index Finger 261A
+Dingbats, Quotation Mark 275B
+Dingbats, Scissors 2701
+Dingbats, Snowflake 2744
+Dingbats, Star 2726
+Dingbats, Vertical Bar 2758
+Dingbats, Warning 2620
+Dingbats, Weather 2600
+Dingbats, Zapf 2700
+Dingbats Series 100, ITC Zapf 2700
+DIRECT CURRENT SYMBOL FORM TWO 2393
+direct product 2299
+direct sum 2295
+DIRECTIONAL FORMATTING, POP 202C
+Directional Formatting Controls 202A
+DISCONTINUOUS UNDERLINE SYMBOL 2382
+discretionary hyphen 00AD
+disjunction 2228
+DITTO MARK 3003
+DIVIDED BY HORIZONTAL BAR AND TOP HALF DIVIDED BY VERTICAL BAR, CIRCLE 29BA
+DIVIDED BY HORIZONTAL RULE, LOZENGE 27E0
+DIVIDED BY VERTICAL BAR, CIRCLE DIVIDED BY HORIZONTAL BAR AND TOP HALF 29BA
+DIVIDES 2223
+Divination Lore, Khmer Symbols for 17F0
+DIVISION SIGN 00F7
+DIVISION SIGN, CIRCLED 2A38
+DIVISION SIGN, CIRCLED ANTICLOCKWISE-ROTATED 29BC
+Division Sign Operators, Multiplication and 2A2F
+DIVISION SLASH 2215
+DIVISION SLASH, CIRCLED 2298
+DIVISION TIMES 22C7
+DOES NOT DIVIDE WITH REVERSED NEGATION SLASH 2AEE
+does not yield 22A3
+DOLLAR SIGN 0024
+DOMAIN ANTIRESTRICTION, Z NOTATION 2A64
+DONG SIGN 20AB
+dot 002E
+DOT, AEGEAN LINE SEPARATOR 10101
+dot, greek middle 00B7
+DOT, KATAKANA MIDDLE 30FB
+DOT, MIDDLE 00B7
+DOT, SESAME FE45
+DOT, WHITE SESAME FE46
+DOT ABOVE 02D9
+DOT ABOVE, COMBINING 0307
+dot above, double 0308
+DOT ABOVE, LATIN CAPITAL LETTER I WITH 0130
+DOT BELOW, COMBINING 0323
+DOT MINUS 2238
+DOT OPERATOR 22C5
+DOT OPERATOR, CIRCLED 2299
+DOT OPERATOR, N-ARY CIRCLED 2A00
+DOT OPERATOR, SQUARED 22A1
+DOT PLUS 2214
+DOTLESS BEH, ARABIC LETTER 066E
+DOTLESS I, LATIN SMALL LETTER 0131
+DOTLESS QAF, ARABIC LETTER 066F
+DOTS ABOVE, COMBINING FOUR 20DC
+DOTS ABOVE, COMBINING THREE 20DB
+DOTTED CIRCLE 25CC
+DOTTED FENCE 2999
+DOUBLE ACUTE ACCENT 02DD
+DOUBLE ACUTE ACCENT, COMBINING 030B
+DOUBLE ANGLE BRACKET, LEFT 300A
+DOUBLE ANGLE QUOTATION MARK, LEFT-POINTING 00AB
+DOUBLE ANGLE QUOTATION MARK, RIGHT-POINTING 00BB
+DOUBLE APOSTROPHE, MODIFIER LETTER 02EE
+DOUBLE ARCH BELOW, COMBINING INVERTED 032B
+double bar, latin letter pipe 01C2
+DOUBLE CIRCLE, MULTIPLICATION SIGN IN 2A37
+Double Circled Numbers 24F5
+DOUBLE COLON EQUAL 2A74
+double comma quotation mark 201D
+double comma quotation mark, low 201E
+DOUBLE DAGGER 2021
+DOUBLE DANDA, DEVANAGARI 0965
+double derivative 0308
+Double Diacritics 0360
+double dot above 0308
+DOUBLE DOWN TACK 2AEA
+DOUBLE EXCLAMATION MARK 203C
+DOUBLE GRAVE ACCENT, COMBINING 030F
+DOUBLE HIGH-REVERSED-9 QUOTATION MARK 201F
+DOUBLE HYPHEN, KATAKANA-HIRAGANA 30A0
+DOUBLE INTEGRAL 222C
+DOUBLE INTERSECTION 22D2
+DOUBLE INVERTED BREVE, COMBINING 0361
+DOUBLE LEFT TURNSTILE, DOUBLE VERTICAL BAR 2AE5
+DOUBLE LEFT TURNSTILE, VERTICAL BAR 2AE4
+DOUBLE LOGICAL AND 2A53
+DOUBLE LOGICAL OR 2A54
+DOUBLE LOW LINE 2017
+DOUBLE LOW LINE, COMBINING 0333
+DOUBLE LOW-9 QUOTATION MARK 201E
+DOUBLE NESTED GREATER-THAN 2AA2
+DOUBLE NESTED LESS-THAN 2AA1
+DOUBLE NESTED LESS-THAN WITH UNDERBAR 2AA3
+double obelisk 2021
+DOUBLE OVERBAR, LOGICAL AND WITH 2A5E
+DOUBLE OVERBAR, LOGICAL OR WITH 2A62
+DOUBLE OVERLINE, COMBINING 033F
+double pipe 01C1
+DOUBLE PLUS 29FA
+DOUBLE PRECEDES 2ABB
+DOUBLE PRIME 2033
+DOUBLE PRIME, MODIFIER LETTER 02BA
+DOUBLE PRIME, REVERSED 2036
+DOUBLE PRIME QUOTATION MARK 301E
+DOUBLE PRIME QUOTATION MARK, LOW 301F
+DOUBLE PRIME QUOTATION MARK, REVERSED 301D
+DOUBLE PUNCTUATION, PHILIPPINE 1736
+Double punctuation for vertical text 2047
+DOUBLE QUESTION MARK 2047
+DOUBLE QUOTATION MARK, LEFT 201C
+DOUBLE QUOTATION MARK, RIGHT 201D
+double reversed comma quotation mark 201F
+DOUBLE RIGHTWARDS ARROW BELOW, COMBINING 0362
+DOUBLE SOLIDUS OPERATOR 2AFD
+DOUBLE SQUARE INTERSECTION 2A4E
+DOUBLE SQUARE UNION 2A4F
+DOUBLE STROKE, INTEGRAL WITH 2A0E
+DOUBLE STROKE NOT SIGN 2AEC
+DOUBLE STROKE NOT SIGN, REVERSED 2AED
+DOUBLE SUBSET 22D0
+DOUBLE SUCCEEDS 2ABC
+DOUBLE SUPERSET 22D1
+DOUBLE TILDE, COMBINING 0360
+DOUBLE TILDE LEFT HALF, COMBINING FE22
+double turned comma quotation mark 201C
+DOUBLE TURNSTILE, LEFT AND RIGHT 27DA
+DOUBLE UNDERBAR, LOGICAL AND WITH 2A60
+DOUBLE UNDERBAR, LOGICAL OR WITH 2A63
+double underline 0333
+double underscore 0333
+double underscore, spacing 2017
+DOUBLE UNION 22D3
+DOUBLE UP TACK 2AEB
+DOUBLE VERTICAL, LONG DASH FROM LEFT MEMBER OF 2AE6
+DOUBLE VERTICAL BAR DOUBLE LEFT TURNSTILE 2AE5
+DOUBLE VERTICAL BAR LEFT TURNSTILE 2AE3
+DOUBLE VERTICAL LINE 2016
+DOUBLE VERTICAL LINE ABOVE, COMBINING 030E
+DOUBLE VERTICAL LINE BELOW, COMBINING 0348
+DOUBLE VERTICAL STROKE, RIGHTWARDS ARROW WITH TAIL WITH 2915
+DOUBLE VERTICAL STROKE, TRIPLE HORIZONTAL BAR WITH 2A68
+DOUBLE VERTICAL STROKE OVERLAY, COMBINING 20E6
+DOUBLE WAVY OVERLINE FE4C
+DOUBLE WIGGLY FENCE, LEFT 29DA
+DOUBLE WIGGLY FENCE, RIGHT 29DB
+double-barred pipe 01C2
+DOUBLE-ENDED MULTIMAP 29DF
+DOUBLE-STRUCK CAPITAL C 2102
+DOUBLE-STRUCK CAPITAL H 210D
+DOUBLE-STRUCK CAPITAL N 2115
+DOUBLE-STRUCK CAPITAL P 2119
+DOUBLE-STRUCK CAPITAL Q 211A
+DOUBLE-STRUCK CAPITAL R 211D
+DOUBLE-STRUCK CAPITAL Z 2124
+Double-struck Greek Letters 213D
+Double-Struck Italic Mathematical Symbols 2145
+DOUBLE-STRUCK N-ARY SUMMATION 2140
+down, page 21DF
+DOWN TACK 22A4
+DOWN TACK BELOW, COMBINING 031E
+DOWN-POINTING TRIANGLE WITH LEFT HALF BLACK 29E8
+DOWN-POINTING TRIANGLE WITH RIGHT HALF BLACK 29E9
+DRACHMA SIGN 20AF
+Drafting Symbols 232D
+dram 0292
+drop 264F
+Duplicates from Big 5 FA0C
+E, COMBINING LATIN SMALL LETTER 0364
+E, DOUBLE-STRUCK ITALIC SMALL 2147
+E, LATIN CAPITAL LETTER OPEN 0190
+E, LATIN CAPITAL LETTER REVERSED 018E
+e, latin capital letter turned 018E
+E, LATIN SMALL LETTER CLOSED OPEN 029A
+E, LATIN SMALL LETTER CLOSED REVERSED OPEN 025E
+E, LATIN SMALL LETTER OPEN 025B
+E, LATIN SMALL LETTER REVERSED 0258
+E, LATIN SMALL LETTER REVERSED OPEN 025C
+E, LATIN SMALL LETTER TURNED 01DD
+E, SCRIPT CAPITAL 2130
+E, SCRIPT SMALL 212F
+EARTH 2641
+Eastern Arabic-Indic Digits for Persian and Urdu 06F0
+ecu 20A0
+EIGHTH NOTE 266A
+EIGHTH NOTES, BEAMED 266B
+Eighths, Fractions 215B
+EJECT SYMBOL 23CF
+EK ONKAR, GURMUKHI 0A74
+el salvadorian currency 20A1
+ELECTRIC ARROW 2301
+electro-magnetic force, emf 2130
+electrolysis 21AF
+Electrotechnical Symbols from IR 181 238D
+element, unique 2129
+ELEMENT OF 2208
+ELEMENT OF, NOT AN 2209
+ELEMENT OF, SMALL 220A
+ELEMENT OF OPENING DOWNWARDS 2AD9
+ELEMENT OF OPENING UPWARDS 27D2
+ELEMENT OF WITH DOT ABOVE 22F5
+ELEMENT OF WITH LONG HORIZONTAL STROKE 22F2
+ELEMENT OF WITH OVERBAR 22F6
+ELEMENT OF WITH OVERBAR, SMALL 22F7
+ELEMENT OF WITH TWO HORIZONTAL STROKES 22F9
+ELEMENT OF WITH UNDERBAR 22F8
+ELEMENT OF WITH VERTICAL BAR AT END OF HORIZONTAL STROKE 22F3
+ELEMENT OF WITH VERTICAL BAR AT END OF HORIZONTAL STROKE, SMALL 22F4
+ell, mathematical symbol 2113
+ELLIPSIS, HORIZONTAL 2026
+ELLIPSIS, MIDLINE HORIZONTAL 22EF
+ELLIPSIS, UP RIGHT DIAGONAL 22F0
+ELLIPSIS, VERTICAL 22EE
+elliptic function, weierstrass 2118
+EM DASH 2014
+EM QUAD 2001
+EM SPACE 2003
+EMBEDDING, LEFT-TO-RIGHT 202A
+EMBEDDING, RIGHT-TO-LEFT 202B
+emf 2130
+EMPHASIS MARK, ARMENIAN 055B
+Emphasis Marks, Sidelining FE45
+EMPHASIS SYMBOL 2383
+EMPTY SET 2205
+Empty Sets 29B0
+EN DASH 2013
+EN QUAD 2000
+EN SPACE 2002
+Enclosed Alphanumerics 2460
+Enclosed CJK Letters and Ideographs 3200
+ENCLOSING CIRCLE, COMBINING 20DD
+ENCLOSING CIRCLE BACKSLASH, COMBINING 20E0
+Enclosing Diacritics 20DD
+ENCLOSING DIAMOND, COMBINING 20DF
+ENCLOSING KEYCAP, COMBINING 20E3
+ENCLOSING SCREEN, COMBINING 20E2
+ENCLOSING SQUARE, COMBINING 20DE
+ENCLOSING UPWARD POINTING TRIANGLE, COMBINING 20E4
+end 21F2
+end of guarded area 0097
+end of medium 0019
+end of medium, graphic for 237F
+END OF MEDIUM, SYMBOL FOR 2419
+END OF PROOF 220E
+end of selected area 0087
+end of text 0003
+END OF TEXT, SYMBOL FOR 2403
+end of transmission 0004
+end of transmission, graphic for 2301
+END OF TRANSMISSION, SYMBOL FOR 2404
+end of transmission block 0017
+END OF TRANSMISSION BLOCK, SYMBOL FOR 2417
+ENG, LATIN SMALL LETTER 014B
+enotikon, greek 203F
+enquiry 0005
+ENQUIRY, SYMBOL FOR 2405
+enter key 2324
+ENTER SYMBOL 2386
+ENVELOPE 2709
+epsilon, latin capital letter 0190
+epsilon, latin small letter 025B
+epsilon, latin small letter closed 029A
+epsilon, latin small letter closed reversed 025E
+epsilon, reversed straight 03F6
+epsilon, reversed straight 220D
+epsilon, straight 03F5
+epsilon, straight 220A
+EPSILON SYMBOL, GREEK LUNATE 03F5
+EPSILON SYMBOL, GREEK REVERSED LUNATE 03F6
+EQUAL, DOUBLE COLON 2A74
+EQUAL, GREATER-THAN ABOVE LESS-THAN ABOVE DOUBLE-LINE 2A92
+EQUAL, GREATER-THAN ABOVE SIMILAR OR 2A8E
+EQUAL, GREATER-THAN ABOVE SLANTED EQUAL ABOVE LESS-THAN ABOVE SLANTED 2A94
+EQUAL, GREATER-THAN CLOSED BY CURVE ABOVE SLANTED 2AA9
+EQUAL, LESS-THAN ABOVE GREATER-THAN ABOVE DOUBLE-LINE 2A91
+EQUAL, LESS-THAN ABOVE SIMILAR OR 2A8D
+EQUAL, LESS-THAN ABOVE SLANTED EQUAL ABOVE GREATER-THAN ABOVE SLANTED 2A93
+EQUAL, LESS-THAN CLOSED BY CURVE ABOVE SLANTED 2AA8
+EQUAL ABOVE GREATER-THAN, LESS-THAN ABOVE DOUBLE-LINE 2A8B
+EQUAL ABOVE GREATER-THAN ABOVE SLANTED EQUAL, LESS-THAN ABOVE SLANTED 2A93
+EQUAL ABOVE LESS-THAN, GREATER-THAN ABOVE DOUBLE-LINE 2A8C
+EQUAL ABOVE LESS-THAN ABOVE SLANTED EQUAL, GREATER-THAN ABOVE SLANTED 2A94
+EQUAL OR EQUAL TO, APPROXIMATELY 2A70
+EQUAL TO, ALL 224C
+EQUAL TO, ALMOST 2248
+EQUAL TO, APPROXIMATELY 2245
+equal to, approximately 2257
+EQUAL TO, APPROXIMATELY EQUAL OR 2A70
+EQUAL TO, ASYMPTOTICALLY 2243
+EQUAL TO, CLOSED SUBSET OR 2AD1
+EQUAL TO, CLOSED SUPERSET OR 2AD2
+EQUAL TO, DELTA 225C
+EQUAL TO, DOUBLE-LINE SLANTED GREATER-THAN OR 2AFA
+EQUAL TO, DOUBLE-LINE SLANTED LESS-THAN OR 2AF9
+EQUAL TO, GEOMETRICALLY 2251
+EQUAL TO, GREATER-THAN AND SINGLE-LINE NOT 2A88
+EQUAL TO, GREATER-THAN OR 2265
+EQUAL TO, GREATER-THAN OR SLANTED 2A7E
+EQUAL TO, LARGER THAN OR 2AAD
+EQUAL TO, LESS-THAN AND SINGLE-LINE NOT 2A87
+EQUAL TO, LESS-THAN OR 2264
+EQUAL TO, LESS-THAN OR SLANTED 2A7D
+EQUAL TO, NOT 2260
+EQUAL TO, PRECEDES ABOVE ALMOST 2AB7
+EQUAL TO, PRECEDES ABOVE NOT 2AB5
+EQUAL TO, PRECEDES ABOVE NOT ALMOST 2AB9
+EQUAL TO, PRECEDES ABOVE SINGLE-LINE NOT 2AB1
+EQUAL TO, QUESTIONED 225F
+EQUAL TO, RING 2257
+EQUAL TO, RING IN 2256
+EQUAL TO, SMALLER THAN OR 2AAC
+EQUAL TO, SUBSET OF ABOVE ALMOST 2AC9
+EQUAL TO, SUBSET OF ABOVE NOT 2ACB
+EQUAL TO, SUCCEEDS ABOVE ALMOST 2AB8
+EQUAL TO, SUCCEEDS ABOVE NOT 2AB6
+EQUAL TO, SUCCEEDS ABOVE NOT ALMOST 2ABA
+EQUAL TO, SUCCEEDS ABOVE SINGLE-LINE NOT 2AB2
+EQUAL TO, SUPERSET OF ABOVE ALMOST 2ACA
+EQUAL TO, SUPERSET OF ABOVE NOT 2ACC
+EQUAL TO ABOVE, COMBINING ALMOST 034C
+equal to by definition 225C
+EQUAL TO BY DEFINITION 225D
+EQUAL TO OR GREATER-THAN, DOUBLE-LINE 2A9A
+EQUAL TO OR GREATER-THAN, DOUBLE-LINE SLANTED 2A9C
+EQUAL TO OR GREATER-THAN, SLANTED 2A96
+EQUAL TO OR GREATER-THAN WITH DOT INSIDE, SLANTED 2A98
+EQUAL TO OR LESS-THAN, DOUBLE-LINE 2A99
+EQUAL TO OR LESS-THAN, DOUBLE-LINE SLANTED 2A9B
+EQUAL TO OR LESS-THAN, SLANTED 2A95
+EQUAL TO OR LESS-THAN WITH DOT INSIDE, SLANTED 2A97
+EQUAL TO WITH CIRCUMFLEX ACCENT, ALMOST 2A6F
+EQUAL TO WITH DOT ABOVE, GREATER-THAN OR SLANTED 2A82
+EQUAL TO WITH DOT ABOVE, LESS-THAN OR SLANTED 2A81
+EQUAL TO WITH DOT ABOVE, SUBSET OF OR 2AC3
+EQUAL TO WITH DOT ABOVE, SUPERSET OF OR 2AC4
+EQUAL TO WITH DOT ABOVE LEFT, GREATER-THAN OR SLANTED 2A84
+EQUAL TO WITH DOT ABOVE RIGHT, LESS-THAN OR SLANTED 2A83
+EQUAL TO WITH DOT INSIDE, GREATER-THAN OR SLANTED 2A80
+EQUAL TO WITH DOT INSIDE, LESS-THAN OR SLANTED 2A7F
+EQUALS, CIRCLED 229C
+EQUALS, REVERSED TILDE 22CD
+EQUALS, STAR 225B
+EQUALS COLON 2255
+EQUALS SIGN 003D
+EQUALS SIGN, PLUS SIGN ABOVE 2A72
+EQUALS SIGN, PRECEDES ABOVE 2AB3
+EQUALS SIGN, PRECEDES ABOVE SINGLE-LINE 2AAF
+EQUALS SIGN, SIMILAR ABOVE GREATER-THAN ABOVE 2AA0
+EQUALS SIGN, SIMILAR ABOVE LESS-THAN ABOVE 2A9F
+EQUALS SIGN, SUBSCRIPT 208C
+EQUALS SIGN, SUBSET OF ABOVE 2AC5
+EQUALS SIGN, SUCCEEDS ABOVE 2AB4
+EQUALS SIGN, SUCCEEDS ABOVE SINGLE-LINE 2AB0
+EQUALS SIGN, SUPERSCRIPT 207C
+EQUALS SIGN, SUPERSET OF ABOVE 2AC6
+EQUALS SIGN ABOVE PLUS SIGN 2A71
+EQUALS SIGN ABOVE TILDE OPERATOR 2A73
+EQUALS SIGN AND SLANTED PARALLEL 29E3
+EQUALS SIGN AND SLANTED PARALLEL WITH TILDE ABOVE 29E4
+EQUALS SIGN BELOW, COMBINING 0347
+EQUALS SIGN WITH BUMPY ABOVE 2AAE
+EQUALS SIGN WITH DOT BELOW 2A66
+EQUALS SIGN WITH TWO DOTS ABOVE AND TWO DOTS BELOW 2A77
+EQUALS SIGNS, THREE CONSECUTIVE 2A76
+EQUALS SIGNS, TWO CONSECUTIVE 2A75
+EQUALS WITH ASTERISK 2A6E
+equiangular 225C
+EQUIANGULAR TO 225A
+equivalent, tautological 29E6
+EQUIVALENT TO 224D
+EQUIVALENT TO, GEOMETRICALLY 224E
+EQUIVALENT TO, STRICTLY 2263
+EQUIVALENT WITH FOUR DOTS ABOVE 2A78
+Era Names, Japanese 337B
+ERASE TO THE LEFT 232B
+ERASE TO THE RIGHT 2326
+error 212F
+Error Bar Symbols 29EE
+escape 001B
+escape, data link 0010
+ESCAPE, SYMBOL FOR 241B
+ESCAPE, SYMBOL FOR DATA LINK 2410
+escudo 0024
+ESH, LATIN CAPITAL LETTER 01A9
+ESH, LATIN SMALL LETTER 0283
+ESH, LATIN SMALL LETTER SQUAT REVERSED 0285
+ESH LOOP, LATIN LETTER REVERSED 01AA
+ESTIMATED SYMBOL 212E
+ESTIMATES 2259
+eszett 00DF
+ET, TIRONIAN SIGN 204A
+ETH, LATIN SMALL LETTER 00F0
+ethel 0153
+Ethiopic 1200
+ETHIOPIC COLON 1365
+ETHIOPIC COMMA 1363
+Ethiopic Digits 1369
+ETHIOPIC FULL STOP 1362
+ETHIOPIC QUESTION MARK 1367
+ETHIOPIC SEMICOLON 1364
+ETHIOPIC WORDSPACE 1361
+EULER CONSTANT 2107
+EURO SIGN 20AC
+European Latin 0100
+european paragraph sign 00A7
+european section sign 00B6
+EXCESS 2239
+EXCLAMATION MARK 0021
+EXCLAMATION MARK, ARMENIAN 055C
+EXCLAMATION MARK, DOUBLE 203C
+EXCLAMATION MARK, INVERTED 00A1
+exclamation mark, latin letter 01C3
+EXCLAMATION MARK, QUESTION 2048
+EXCLAMATION MARK ORNAMENT, HEAVY 2762
+EXCLAMATION QUESTION MARK 2049
+EXISTS, THERE 2203
+Extended Additional, Latin 1E00
+Extended Arabic 0671
+Extended Cyrillic 048C
+Extended for Minnan and Hakka, Chinese Bopomofo 31A0
+Extended Greek 1F00
+Extended-A, Latin 0100
+Extended-B, Latin 0180
+extension, arrows 23AF
+EXTENSION, HORIZONTAL LINE 23AF
+EXTENSION, INTEGRAL 23AE
+EXTENSION, VERTICAL LINE 23D0
+Extension A, CJK Unified Ideographs 3400
+Extensions, Cyrillic 0450
+Extensions, IPA 0250
+Extensions, Katakana Phonetic 31F0
+Extensions, Special Characters 23AE
+Extensions for Sanskrit and Tibetan, Mongolian 1880
+Extensions for Vietnamese, Latin 1EA0
+EZH, LATIN CAPITAL LETTER 01B7
+EZH, LATIN SMALL LETTER 0292
+EZH REVERSED, LATIN SMALL LETTER 01B9
+F, SCRIPT CAPITAL 2131
+F, TURNED CAPITAL 2132
+F WITH HOOK, LATIN SMALL LETTER 0192
+FACE, BLACK SMILING 263B
+FACE, POSTAL MARK 3020
+FACE, WHITE FROWNING 2639
+FACE, WHITE SMILING 263A
+FACSIMILE SIGN 213B
+factorial 0021
+FAHRENHEIT, DEGREE 2109
+FALLING DIAGONAL SLASH, SQUARED 29C5
+FALLING DOTS, MINUS SIGN WITH 2A2B
+feet 2032
+FEMALE SIGN 2640
+FEMININE ORDINAL INDICATOR 00AA
+FENCE, DOTTED 2999
+FENCE, LEFT DOUBLE WIGGLY 29DA
+FENCE, LEFT WIGGLY 29D8
+FENCE, RIGHT DOUBLE WIGGLY 29DB
+FENCE, RIGHT WIGGLY 29D9
+Fences 2999
+Fences 29D8
+Fifths, Fractions 2155
+FIGURE DASH 2012
+FIGURE SPACE 2007
+file separator 001C
+FILE SEPARATOR, SYMBOL FOR 241C
+Finger Dingbats, Pointing Index 261A
+finite function, z notation 20E6
+finite function, z notation 21FB
+finite injection, z notation 2915
+FINITE PART INTEGRAL 2A0D
+finite relation, z notation 21FC
+finite surjection, z notation 2901
+finite surjective injection, z notation 2918
+FIRST QUARTER MOON 263D
+first transfinite cardinal (countable) 2135
+Fish Tails 297C
+FISHEYE 25C9
+fist 261E
+FIVE, LATIN SMALL LETTER TONE 01BD
+FIVE POINTED STAR, ARABIC 066D
+FLAG, BLACK 2691
+FLAT SIGN, MUSIC 266D
+FLOOR, LEFT 230A
+FLORAL HEART BULLET, REVERSED ROTATED 2619
+florin currency symbol 0192
+folder 0192
+FOOT, SQUARE 23CD
+FOONOTE MARKER, ARABIC 0602
+FOR ALL 2200
+FORCES 22A9
+FORKING 2ADC
+Forks 2AD9
+Form and Chart Components 2500
+form feed 000C
+form feed 21A1
+FORM FEED, SYMBOL FOR 240C
+Format Control, Syriac 070F
+Format Controls, Mongolian 180B
+FORMATTING, POP DIRECTIONAL 202C
+Formatting Characters 200C
+Formatting Characters 2028
+Formatting Controls, Bidirectional 202A
+forward difference 2206
+FOUR DOTS ABOVE, COMBINING 20DC
+FOUR-PER-EM SPACE 2005
+fourier transform 2131
+fourth derivative 20DC
+FOURTH ROOT 221C
+fourth transfinite cardinal 2138
+Fourths, Fractions 00BC
+FRACTION NUMERATOR ONE 215F
+FRACTION ONE HALF, VULGAR 00BD
+FRACTION ONE QUARTER, VULGAR 00BC
+FRACTION SLASH 2044
+FRACTION THREE QUARTERS, VULGAR 00BE
+Fractions 2153
+FRAGMENT, ARABIC TAIL FE73
+framus, white 29D6
+FRANC SIGN, FRENCH 20A3
+FRICATIVE, LATIN LETTER PHARYNGEAL VOICED 0295
+FROWN 2322
+FROWNING FACE, WHITE 2639
+FULL BLOCK 2588
+FULL OUTER JOIN 27D7
+FULL STOP 002E
+FULL STOP, ARABIC 06D4
+FULL STOP, ARMENIAN 0589
+FULL STOP, ETHIOPIC 1362
+full stop, georgian 0589
+FULL STOP, IDEOGRAPHIC 3002
+FULL STOP, MONGOLIAN 1803
+Fullwidth ASCII Variants FF01
+Fullwidth Brackets FF5F
+Fullwidth Forms, Halfwidth and FF00
+Fullwidth Symbol Variants FFE0
+FUNCTION, CIRCULATION 2A10
+function, gamma 0393
+function, z notation finite 20E6
+function, z notation finite 21FB
+function, z notation partial 21F8
+FUNCTION APPLICATION 2061
+function symbol 0192
+fvs 180B
+G, LATIN LETTER SMALL CAPITAL 0262
+G, LATIN SMALL LETTER SCRIPT 0261
+G, SCRIPT SMALL 210A
+G, TURNED SANS-SERIF CAPITAL 2141
+game 2141
+GAMMA, DOUBLE-STRUCK CAPITAL 213E
+GAMMA, DOUBLE-STRUCK SMALL 213D
+GAMMA, LATIN CAPITAL LETTER 0194
+GAMMA, LATIN SMALL LETTER 0263
+gamma, latin small letter baby 0264
+GAMMA, MODIFIER LETTER SMALL 02E0
+gamma function 0393
+GB 2312 (Chinese), Based on 3100
+GEMINI 264A
+General Punctuation 2000
+General Scripts Area 0000
+GENERIC MATERIALS, RECYCLING SYMBOL FOR 267A
+Generic punctuation for Philippine scripts 1735
+GEOMETRIC PROPORTION 223A
+Geometric Shapes 25A0
+GEOMETRICALLY EQUAL TO 2251
+GEOMETRICALLY EQUIVALENT TO 224E
+Georgian 10A0
+Georgian Capital Letters 10A0
+georgian comma 00B7
+georgian full stop 0589
+GEORGIAN PARAGRAPH SEPARATOR 10FB
+Georgian Small Letters 10D0
+german mark 2133
+GERMAN PENNY SIGN 20B0
+GETA MARK 3013
+GIMEL SYMBOL 2137
+GLEICH STARK 29E6
+glottal stop 02BC
+GLOTTAL STOP, LATIN LETTER 0294
+GLOTTAL STOP, LATIN LETTER INVERTED 0296
+glottal stop, latin letter reversed 0295
+GLOTTAL STOP, MODIFIER LETTER 02C0
+GLOTTAL STOP, MODIFIER LETTER REVERSED 02C1
+GLOTTAL STOP, MODIFIER LETTER SMALL REVERSED 02E4
+Go Markers 2686
+Golden Number Runes 16EE
+GRAPHEME JOINER, COMBINING 034F
+Graphic Characters, Terminal 23B7
+Graphic Characters, Terminal 2596
+Graphic Pictures for Control Codes 2400
+Graphics, Control Code 25F0
+Graphics, Scan Lines For Terminal 23BA
+Graphics for Control Codes 237B
+grave, spacing 0060
+GRAVE ACCENT 0060
+GRAVE ACCENT, COMBINING 0300
+GRAVE ACCENT, COMBINING DOUBLE 030F
+GRAVE ACCENT, DEVANAGARI 0953
+GRAVE ACCENT, MODIFIER LETTER 02CB
+GRAVE ACCENT, MODIFIER LETTER LOW 02CE
+grave accent, swedish 02DF
+GRAVE ACCENT BELOW, COMBINING 0316
+GRAVE TONE MARK, COMBINING 0340
+GREATER-THAN, CIRCLED 29C1
+GREATER-THAN, DOUBLE NESTED 2AA2
+GREATER-THAN, DOUBLE-LINE EQUAL TO OR 2A9A
+GREATER-THAN, DOUBLE-LINE SLANTED EQUAL TO OR 2A9C
+GREATER-THAN, LESS-THAN ABOVE DOUBLE-LINE EQUAL ABOVE 2A8B
+GREATER-THAN, LESS-THAN ABOVE SIMILAR ABOVE 2A8F
+GREATER-THAN, MUCH 226B
+GREATER-THAN, SIMILAR OR 2A9E
+GREATER-THAN, SLANTED EQUAL TO OR 2A96
+GREATER-THAN, TRIPLE NESTED 2AF8
+GREATER-THAN, VERY MUCH 22D9
+GREATER-THAN ABOVE DOUBLE-LINE EQUAL, LESS-THAN ABOVE 2A91
+GREATER-THAN ABOVE DOUBLE-LINE EQUAL ABOVE LESS-THAN 2A8C
+GREATER-THAN ABOVE EQUALS SIGN, SIMILAR ABOVE 2AA0
+GREATER-THAN ABOVE LESS-THAN ABOVE DOUBLE-LINE EQUAL 2A92
+GREATER-THAN ABOVE SIMILAR ABOVE LESS-THAN 2A90
+GREATER-THAN ABOVE SIMILAR OR EQUAL 2A8E
+GREATER-THAN ABOVE SLANTED EQUAL, LESS-THAN ABOVE SLANTED EQUAL ABOVE 2A93
+GREATER-THAN ABOVE SLANTED EQUAL ABOVE LESS-THAN ABOVE SLANTED EQUAL 2A94
+GREATER-THAN AND NOT APPROXIMATE 2A8A
+GREATER-THAN AND SINGLE-LINE NOT EQUAL TO 2A88
+GREATER-THAN BESIDE LESS-THAN 2AA5
+GREATER-THAN CLOSED BY CURVE 2AA7
+GREATER-THAN CLOSED BY CURVE ABOVE SLANTED EQUAL 2AA9
+GREATER-THAN OR APPROXIMATE 2A86
+GREATER-THAN OR EQUAL TO 2265
+GREATER-THAN OR EQUAL TO, DOUBLE-LINE SLANTED 2AFA
+GREATER-THAN OR SLANTED EQUAL TO 2A7E
+GREATER-THAN OR SLANTED EQUAL TO WITH DOT ABOVE 2A82
+GREATER-THAN OR SLANTED EQUAL TO WITH DOT ABOVE LEFT 2A84
+GREATER-THAN OR SLANTED EQUAL TO WITH DOT INSIDE 2A80
+GREATER-THAN OVERLAPPING LESS-THAN 2AA4
+GREATER-THAN SIGN 003E
+GREATER-THAN WITH CIRCLE INSIDE 2A7A
+GREATER-THAN WITH DOT INSIDE, SLANTED EQUAL TO OR 2A98
+GREATER-THAN WITH QUESTION MARK ABOVE 2A7C
+Greek, Diacritics for 0342
+Greek, Extended 1F00
+Greek and Coptic 0370
+Greek Capital Letters 0391
+greek currency 20AF
+GREEK DIALYTIKA TONOS, COMBINING 0344
+greek enotikon 203F
+GREEK KORONIS, COMBINING 0343
+greek middle dot 00B7
+greek non-spacing iota below 0345
+GREEK PERISPOMENI, COMBINING 0342
+GREEK QUESTION MARK 037E
+GREEK SMALL LETTER IOTA, TURNED 2129
+Greek Small Letters 03B1
+Greek Symbols 03D0
+GREEK YPOGEGRAMMENI, COMBINING 0345
+group lock 21F0
+group separator 001D
+GROUP SEPARATOR, SYMBOL FOR 241D
+guarded area, end of 0097
+guarded area, start of 0096
+gui icons 231A
+guillemet, left pointing 00AB
+guillemet, left pointing single 2039
+guillemet, right pointing 00BB
+guillemet, right pointing single 203A
+Gujarati 0A80
+Gujarati Digits 0AE6
+Gujarati Letters 0A85
+GUJARATI RUPEE SIGN 0AF1
+Gurmukhi 0A00
+Gurmukhi Digits 0A66
+Gurmukhi Letters 0A05
+H, BLACK-LETTER CAPITAL 210C
+H, COMBINING LATIN SMALL LETTER 036A
+H, DOUBLE-STRUCK CAPITAL 210D
+H, LATIN LETTER SMALL CAPITAL 029C
+H, LATIN SMALL LETTER TURNED 0265
+H, MODIFIER LETTER SMALL 02B0
+H, SCRIPT CAPITAL 210B
+hacek, combining 030C
+hacek, modifier letter 02C7
+HAIR SPACE 200A
+Hakka, Chinese Bopomofo Extended for Minnan and 31A0
+halant, bengali 09CD
+halant, devanagari 094D
+HALF, COMBINING DOUBLE TILDE LEFT FE22
+HALF, COMBINING LIGATURE LEFT FE20
+HALF, VULGAR FRACTION ONE 00BD
+HALF CIRCLE, MULTIPLICATION SIGN IN LEFT 2A34
+HALF CIRCLE, MULTIPLICATION SIGN IN RIGHT 2A35
+HALF CIRCLE, PLUS SIGN IN LEFT 2A2D
+HALF CIRCLE, PLUS SIGN IN RIGHT 2A2E
+HALF FILL SPACE, IDEOGRAPHIC 303F
+HALF INTEGRAL, TOP 2320
+Half Marks, Combining FE20
+HALF RING, MODIFIER LETTER CENTRED LEFT 02D3
+HALF RING, MODIFIER LETTER LEFT 02BF
+HALF RING BELOW, COMBINING LEFT 031C
+HALF RING BELOW, COMBINING RIGHT 0339
+HALF TRIANGULAR COLON, MODIFIER LETTER 02D1
+Halfwidth and Fullwidth Forms FF00
+Halfwidth Japanese Katakana Variants FF61
+Halfwidth Korean Hangul Variants FFA0
+hamiltonian function 210B
+HAMMER AND SICKLE 262D
+Han Ideographs 4E00
+HAND, VICTORY 270C
+HAND, WRITING 270D
+Hand Symbols, Pointing 261A
+Hangul, Based on KS C 5601 (Korean) 3130
+HANGUL CHOSEONG FILLER 115F
+Hangul Compatibility Jamo, Korean 3130
+Hangul Elements, Circled Korean 3260
+Hangul Elements, Parenthesized Korean 3200
+HANGUL FILLER 3164
+Hangul Jamo Combining Alphabet, Korean 1100
+HANGUL JUNGSEONG FILLER 1160
+Hangul Syllables, Circled Korean 326E
+Hangul Syllables, Parenthesized Korean 320E
+Hangul Syllables Area, Korean AC00
+Hangul Variants, Halfwidth Korean FFA0
+Hangzhou-style Numerals 3021
+Hanunoo 1720
+HANUNOO SIGN PAMUDPOD 1734
+Hanun�o-specific punctuation 1734
+HARPOON ABOVE, COMBINING LEFT 20D0
+hasant 09CD
+hash 0023
+hat 0302
+hat 2229
+have a nice day! 263A
+Hazard Dingbats 2620
+heading, start of 0001
+HEADING, SYMBOL FOR START OF 2401
+Heart Ornaments 2763
+HEAVY BALLOT X 2718
+HEAVY CHECK MARK 2714
+HEAVY MULTIPLICATION X 2716
+Hebrew 0590
+Hebrew Cantillation Marks 0591
+hebrew currency 20AA
+Hebrew Letters 05D0
+Hebrew Points 05B0
+Hebrew Presentation Forms FB1D
+HELM SYMBOL 2388
+HERMITIAN CONJUGATE MATRIX 22B9
+Hexagram Symbols, Yijing 4DC0
+hiding, z notation schema 29F9
+High Surrogates D800
+HIGH VOLTAGE SIGN 26A1
+HIGH-REVERSED-9 QUOTATION MARK, DOUBLE 201F
+HIGH-REVERSED-9 QUOTATION MARK, SINGLE 201B
+higher rank than 227B
+hilbert space 210C
+Hiragana, Based on JIS X 0208 (Japanese) 3040
+HIRAGANA DIGRAPH YORI 309F
+HIRAGANA ITERATION MARK 309D
+histogram marker 25AE
+Historic Letters, Cyrillic 0460
+home 21B8
+home 21F1
+HOMOTHETIC 223B
+HOMOTHETIC ABOVE, COMBINING 034B
+Honorific Signs, Arabic 0610
+HOOK, MODIFIER LETTER RHOTIC 02DE
+hook, nasal 0328
+HOOK ABOVE, COMBINING 0309
+HOOK BELOW, COMBINING PALATALIZED 0321
+HOOK BELOW, COMBINING RETROFLEX 0322
+HORIZONTAL BAR 2015
+HORIZONTAL BAR, CIRCLE WITH 29B5
+HORIZONTAL BAR WITH DOUBLE VERTICAL STROKE, TRIPLE 2A68
+HORIZONTAL BAR WITH TRIPLE VERTICAL STROKE, TRIPLE 2A69
+HORIZONTAL ELLIPSIS 2026
+HORIZONTAL ELLIPSIS, MIDLINE 22EF
+HORIZONTAL LINE EXTENSION 23AF
+HORIZONTAL RULE, LOZENGE DIVIDED BY 27E0
+horizontal tabulation 0009
+HORIZONTAL TABULATION, SYMBOL FOR 2409
+HORN, COMBINING 031B
+HORN, LATIN SMALL LETTER RAMS 0264
+HOT BEVERAGE 2615
+HOT SPRINGS 2668
+HOURGLASS 231B
+HOURGLASS, BLACK 29D7
+HOURGLASS, WHITE 29D6
+Hours, Telegraph Symbols for 3358
+HOUSE 2302
+HV, LATIN SMALL LETTER 0195
+HWAIR, LATIN CAPITAL LETTER 01F6
+HYPHEN 2010
+HYPHEN, ARMENIAN 058A
+hyphen, discretionary 00AD
+HYPHEN, KATAKANA-HIRAGANA DOUBLE 30A0
+HYPHEN, NON-BREAKING 2011
+HYPHEN, SOFT 00AD
+HYPHEN BULLET 2043
+hyphen or minus sign 002D
+HYPHEN-MINUS 002D
+HYPHENATION POINT 2027
+hyphus 002D
+HYSTERESIS SYMBOL 238E
+I, BLACK-LETTER CAPITAL 2111
+I, COMBINING LATIN SMALL LETTER 0365
+I, DOUBLE-STRUCK ITALIC SMALL 2148
+I, LATIN LETTER SMALL CAPITAL 026A
+I, LATIN SMALL LETTER DOTLESS 0131
+I, SCRIPT CAPITAL 2110
+I, SUPERSCRIPT LATIN SMALL LETTER 2071
+I WITH DOT ABOVE, LATIN CAPITAL LETTER 0130
+IBM CJK Compatibility Ideographs FA0E
+icons, gui 231A
+identical and parallel to 2A68
+IDENTICAL TO 2261
+IDENTICAL TO AND SLANTED PARALLEL 29E5
+IDENTICAL WITH DOT ABOVE 2A67
+Ideographic Annotation, Japanese Kanbun 3190
+IDEOGRAPHIC CLOSING MARK 3006
+IDEOGRAPHIC COMMA 3001
+Ideographic Description Characters 2FF0
+IDEOGRAPHIC FULL STOP 3002
+IDEOGRAPHIC HALF FILL SPACE 303F
+IDEOGRAPHIC ITERATION MARK 3005
+IDEOGRAPHIC ITERATION MARK, VERTICAL 303B
+IDEOGRAPHIC NUMBER ZERO 3007
+IDEOGRAPHIC SPACE 3000
+Ideographic Tone Marks 302A
+Ideographs, Circled 3280
+Ideographs, CJK Compatibility F900
+Ideographs, CJK Unified 4E00
+Ideographs, Enclosed CJK Letters and 3200
+Ideographs, Han 4E00
+Ideographs, IBM CJK Compatibility FA0E
+Ideographs, Parenthesized 3220
+Ideographs Area, CJK 3400
+Ideographs Extension A, CJK Unified 3400
+IDLE, SYMBOL FOR SYNCHRONOUS 2416
+idle, synchronous 0016
+IJ, LATIN SMALL LIGATURE 0133
+IMAGE OF 22B7
+IMAGE OF, SQUARE 228F
+imaginary part 2111
+implies 22A2
+inches 2033
+included in set 2282
+includes in set 2283
+INCOMPLETE INFINITY 29DC
+incorporated, japanese 337F
+INCREASES AS 29E1
+INCREMENT 2206
+independence 2AEB
+independent 2ADD
+independent, not 2ADC
+index 0084
+Index Finger Dingbats, Pointing 261A
+indian currency 20A8
+inferior order to, of 2134
+INFINITY 221E
+INFINITY, INCOMPLETE 29DC
+INFINITY, TIE OVER 29DD
+INFINITY NEGATED WITH VERTICAL BAR 29DE
+INFORMATION SOURCE 2139
+INHIBIT ARABIC FORM SHAPING 206C
+INHIBIT SYMMETRIC SWAPPING 206A
+injection, z notation finite 2915
+injection, z notation finite surjective 2918
+injection, z notation partial 2914
+injection, z notation surjective 2917
+INSERTION POINT, CARET 2041
+INSERTION SYMBOL 2380
+integers, the set of 2124
+INTEGRAL 222B
+INTEGRAL, CLOCKWISE 2231
+INTEGRAL, CLOCKWISE CONTOUR 2232
+INTEGRAL, CONTOUR 222E
+INTEGRAL, DOUBLE 222C
+integral, riemann 211B
+INTEGRAL, SURFACE 222F
+INTEGRAL, TOP HALF 2320
+INTEGRAL, TRIPLE 222D
+INTEGRAL, VOLUME 2230
+Integrals, Summations and 2A0A
+INTERCALATE 22BA
+INTERIOR PRODUCT 2A3C
+INTERIOR PRODUCT, RIGHTHAND 2A3D
+interleave 2AF4
+Interlinear Annotation FFF9
+Internal Codes, Process FDD0
+International Phonetic Alphabet 0250
+INTERROBANG 203D
+INTERSECTION 2229
+INTERSECTION, DOUBLE 22D2
+INTERSECTION, INTEGRAL WITH 2A19
+INTERSECTION, N-ARY 22C2
+intersection, proper 22D4
+INTERSECTION, TRANSVERSAL 2ADB
+INTERSECTION OPERATOR, N-ARY SQUARE 2A05
+INTERSECTION WITH DOT 2A40
+Intersections and Unions 2A40
+introducer, control sequence 009B
+introducer, single character 009A
+Inverse Numbers, Circled 2776
+INVERTED BREVE, COMBINING 0311
+INVERTED BREVE, COMBINING DOUBLE 0361
+INVERTED BREVE BELOW, COMBINING 032F
+INVERTED BRIDGE BELOW, COMBINING 033A
+INVERTED DOUBLE ARCH BELOW, COMBINING 032B
+INVERTED EXCLAMATION MARK 00A1
+INVERTED GLOTTAL STOP, LATIN LETTER 0296
+INVERTED LAZY S 223E
+INVERTED OHM SIGN 2127
+INVERTED QUESTION MARK 00BF
+INVERTED R, LATIN LETTER SMALL CAPITAL 0281
+INVERTED R, MODIFIER LETTER SMALL CAPITAL 02B6
+INVERTED UNDERTIE 2054
+Invisible Operators 2063
+IOTA, LATIN CAPITAL LETTER 0196
+IOTA, LATIN SMALL LETTER 0269
+IOTA, TURNED GREEK SMALL LETTER 2129
+iota below, greek non-spacing 0345
+IPA, Diacritics for 0346
+IPA Extensions 0250
+IR 181, Electrotechnical Symbols from 238D
+iran, symbol of 262B
+irish punt 00A3
+ISCII 1988 (Devanagari), Based on 0901
+ISO 8859-1 (Latin-1), Based on 00A0
+ISO 8859-2, -3, -4, -9 (European Latin), Based on 0100
+ISO 8859-5 (Cyrillic), Based on 0400
+ISO 8859-6 (Arabic), Based on 0600
+ISO 8859-7 (Greek), Based on 0370
+ISO 8859-8 (Hebrew), Based on 05D0
+ISO 9995-7, Keyboard Symbols from 2380
+ISO 9995-7, Keyboard Symbols from 2396
+israeli currency 20AA
+italian currency 20A4
+Italic Mathematical Symbols, Double-Struck 2145
+ITC Zapf Dingbats Series 100 2700
+ITERATION MARK, HIRAGANA 309D
+ITERATION MARK, IDEOGRAPHIC 3005
+ITERATION MARK, KATAKANA 30FD
+ITERATION MARK, VERTICAL IDEOGRAPHIC 303B
+ivy leaf 2767
+J, DOUBLE-STRUCK ITALIC SMALL 2149
+J, MODIFIER LETTER SMALL 02B2
+jack 2749
+Jamo, Korean Hangul Compatibility 3130
+Jamo Combining Alphabet, Korean Hangul 1100
+Japanese Chess Symbols 2616
+Japanese Era Names 337B
+Japanese Hiragana 3040
+japanese incorporated 337F
+JAPANESE INDUSTRIAL STANDARD SYMBOL 3004
+Japanese Kanbun (Ideographic Annotation) 3190
+Japanese Katakana 30A0
+Japanese Katakana, Circled 32D0
+Japanese Katakana Variants, Halfwidth FF61
+Japanese Katakana Words, Squared 3300
+japanese kome 203B
+JERUSALEM, CROSS OF 2629
+jis composition circle 20DD
+JIS X 0208, Based on 3040
+JIS X 0213 Compatibility Ideographs FA30
+JOIN 2A1D
+JOIN, FULL OUTER 27D7
+JOIN, LEFT OUTER 27D5
+JOIN, RIGHT OUTER 27D6
+JOINER, COMBINING GRAPHEME 034F
+JOINER, WORD 2060
+JOINER, ZERO WIDTH 200D
+jot, apl 2218
+JUPITER 2643
+justification, character tabulation with 0089
+K, LATIN SMALL LETTER TURNED 029E
+kabusiki-gaisya 337F
+Kana Repeat Marks 3031
+Kanbun (Ideographic Annotation), Japanese 3190
+Kangxi Radicals 2F00
+Kannada 0C80
+Kannada Digits 0CE6
+Kannada Letters 0C85
+Katakana, Circled Japanese 32D0
+Katakana, Japanese 30A0
+KATAKANA DIGRAPH KOTO 30FF
+KATAKANA ITERATION MARK 30FD
+KATAKANA MIDDLE DOT 30FB
+Katakana Phonetic Extensions 31F0
+Katakana Variants, Halfwidth Japanese FF61
+Katakana Words, Squared Japanese 3300
+KATAKANA-HIRAGANA DOUBLE HYPHEN 30A0
+KATAKANA-HIRAGANA PROLONGED SOUND MARK 30FC
+KATAKANA-HIRAGANA VOICED SOUND MARK 309B
+KATAKANA-HIRAGANA VOICED SOUND MARK, COMBINING 3099
+KELVIN SIGN 212A
+ket 27E7
+key, clear 2327
+key, command 2318
+key, delete to the left 232B
+key, delete to the right 2326
+key, enter 2324
+KEY, OPTION 2325
+KEY SYMBOL, ALTERNATIVE 2387
+KEY SYMBOL, DECIMAL SEPARATOR 2396
+KEYBOARD 2328
+Keyboard Symbols 2324
+Keyboard Symbols from ISO 9995-7 2380
+Keyboard Symbols from ISO 9995-7 2396
+Keyboard and UI Symbols 23CE
+KEYCAP, COMBINING ENCLOSING 20E3
+Khmer 1780
+Khmer Digits 17E0
+Khmer Lunar Date Symbols 19E0
+Khmer Symbols 19E0
+Khmer Symbols for Divination Lore 17F0
+KIP SIGN 20AD
+kome, japanese 203B
+Komi Letters, Cyrillic 0500
+Koranic Annotation Signs 06D6
+korean currency 20A9
+Korean Hangul Compatibility Jamo 3130
+Korean Hangul Elements, Circled 3260
+Korean Hangul Elements, Parenthesized 3200
+Korean Hangul Jamo Combining Alphabet 1100
+Korean Hangul Syllables, Circled 326E
+Korean Hangul Syllables, Parenthesized 320E
+Korean Hangul Syllables Area AC00
+Korean Hangul Variants, Halfwidth FFA0
+KOREAN STANDARD SYMBOL 327F
+KORONIS, COMBINING GREEK 0343
+KOTO, KATAKANA DIGRAPH 30FF
+KRA, LATIN SMALL LETTER 0138
+KS C 5601 (Korean Hangul), Based on 3130
+L, LATIN LETTER SMALL CAPITAL 029F
+L, MODIFIER LETTER SMALL 02E1
+L, REVERSED SANS-SERIF CAPITAL 2143
+L, SCRIPT CAPITAL 2112
+L, SCRIPT SMALL 2113
+L, TURNED SANS-SERIF CAPITAL 2142
+L B BAR SYMBOL 2114
+L WITH MIDDLE DOT, LATIN SMALL LETTER 0140
+L WITH MIDDLE TILDE, LATIN SMALL LETTER 026B
+lambda bar, latin letter 019B
+Lao 0E80
+Lao Digits 0ED0
+Lao Letters 0E81
+laotian currency 20AD
+laplace operator 2206
+laplace operator 2207
+laplace symbol 2112
+LARGE AND, SLOPING 2A58
+large bowtie 2A1D
+LARGE DOWN TACK 27D9
+LARGE LEFT TRIANGLE OPERATOR 2A1E
+LARGE OR, SLOPING 2A57
+LARGE TRIPLE VERTICAL BAR OPERATOR 2AFC
+LARGE UP TACK 27D8
+LARGER THAN 2AAB
+LARGER THAN OR EQUAL TO 2AAD
+LAST QUARTER MOON 263E
+LATERAL CLICK, LATIN LETTER 01C1
+Latin, Based on ISO 8859-2, -3, -4, -9 (European) 0100
+Latin, C0 Controls and Basic 0000
+Latin, European 0100
+Latin Abbreviations, Squared 3371
+LATIN CAPITAL LETTER N WITH LONG RIGHT LEG 0220
+Latin Capital Letters 0041
+LATIN CROSS 271D
+Latin Extended Additional 1E00
+Latin Extended-A 0100
+Latin Extended-B 0180
+Latin Extensions for Vietnamese 1EA0
+Latin Letters, Circled 24B6
+Latin Letters, Parenthesized 249C
+Latin Letters, Phonetic Modifiers Derived from 02B0
+Latin Ligatures FB00
+Latin Small Letters 0061
+Latin Small Letters, Combining 0363
+Latin-1, ISO 8859-1 aka 00A0
+Latin-1 Supplement, C1 Controls and 0080
+lazy s 223D
+LAZY S, INVERTED 223E
+LEADER, ONE DOT 2024
+leader, three dot 2026
+LEADER, TWO DOT 2025
+leaf, aldus 2766
+leaf, ivy 2767
+LEFT-TO-RIGHT EMBEDDING 202A
+LEFT-TO-RIGHT MARK 200E
+LEFT-TO-RIGHT OVERRIDE 202D
+leftward tab 21E4
+LEG, LATIN CAPITAL LETTER N WITH LONG RIGHT 0220
+LENTICULAR BRACKET, LEFT BLACK 3010
+LENTICULAR BRACKET, LEFT WHITE 3016
+LEO 264C
+LESS-THAN, CIRCLED 29C0
+LESS-THAN, DOUBLE NESTED 2AA1
+LESS-THAN, DOUBLE-LINE EQUAL TO OR 2A99
+LESS-THAN, DOUBLE-LINE SLANTED EQUAL TO OR 2A9B
+LESS-THAN, GREATER-THAN ABOVE DOUBLE-LINE EQUAL ABOVE 2A8C
+LESS-THAN, GREATER-THAN ABOVE SIMILAR ABOVE 2A90
+LESS-THAN, GREATER-THAN BESIDE 2AA5
+LESS-THAN, GREATER-THAN OVERLAPPING 2AA4
+LESS-THAN, MUCH 226A
+LESS-THAN, SIMILAR OR 2A9D
+LESS-THAN, SLANTED EQUAL TO OR 2A95
+LESS-THAN, TRIPLE NESTED 2AF7
+LESS-THAN, VERY MUCH 22D8
+LESS-THAN ABOVE DOUBLE-LINE EQUAL, GREATER-THAN ABOVE 2A92
+LESS-THAN ABOVE DOUBLE-LINE EQUAL ABOVE GREATER-THAN 2A8B
+LESS-THAN ABOVE EQUALS SIGN, SIMILAR ABOVE 2A9F
+LESS-THAN ABOVE GREATER-THAN ABOVE DOUBLE-LINE EQUAL 2A91
+LESS-THAN ABOVE SIMILAR ABOVE GREATER-THAN 2A8F
+LESS-THAN ABOVE SIMILAR OR EQUAL 2A8D
+LESS-THAN ABOVE SLANTED EQUAL, GREATER-THAN ABOVE SLANTED EQUAL ABOVE 2A94
+LESS-THAN ABOVE SLANTED EQUAL ABOVE GREATER-THAN ABOVE SLANTED EQUAL 2A93
+LESS-THAN AND NOT APPROXIMATE 2A89
+LESS-THAN AND SINGLE-LINE NOT EQUAL TO 2A87
+LESS-THAN CLOSED BY CURVE 2AA6
+LESS-THAN CLOSED BY CURVE ABOVE SLANTED EQUAL 2AA8
+LESS-THAN OR APPROXIMATE 2A85
+LESS-THAN OR EQUAL TO 2264
+LESS-THAN OR EQUAL TO, DOUBLE-LINE SLANTED 2AF9
+LESS-THAN OR SLANTED EQUAL TO 2A7D
+LESS-THAN OR SLANTED EQUAL TO WITH DOT ABOVE 2A81
+LESS-THAN OR SLANTED EQUAL TO WITH DOT ABOVE RIGHT 2A83
+LESS-THAN OR SLANTED EQUAL TO WITH DOT INSIDE 2A7F
+LESS-THAN SIGN 003C
+LESS-THAN WITH CIRCLE INSIDE 2A79
+LESS-THAN WITH DOT INSIDE, SLANTED EQUAL TO OR 2A97
+LESS-THAN WITH QUESTION MARK ABOVE 2A7B
+LESS-THAN WITH UNDERBAR, DOUBLE NESTED 2AA3
+Letterlike Symbols 2100
+level 2 lock 21EB
+level 3 lock 21EF
+level 3 select 21EE
+LEZH, LATIN SMALL LETTER 026E
+lf 000A
+LIABILITY SIGN, LIMITED 32CF
+LIBRA 264E
+ligature ae, latin small 00E6
+LIGATURE IJ, LATIN SMALL 0133
+LIGATURE LEFT HALF, COMBINING FE20
+LIGATURE OE, LATIN SMALL 0153
+ligature tie 0361
+Ligatures, Armenian FB13
+Ligatures, Latin FB00
+LIGHTNING 2607
+LIMIT, APPROACHES THE 2250
+Limbu 1900
+Limbu Digits 1946
+LIMITED LIABILITY SIGN 32CF
+LINE, AEGEAN WORD SEPARATOR 10100
+line, beginning of 2310
+LINE, CENTRELINE LOW FE4E
+LINE, COMBINING DOUBLE LOW 0333
+LINE, COMBINING LOW 0332
+LINE, DASHED LOW FE4D
+LINE, DOUBLE LOW 2017
+LINE, DOUBLE VERTICAL 2016
+LINE, LOW 005F
+LINE, MODIFIER LETTER LOW VERTICAL 02CC
+LINE, MODIFIER LETTER VERTICAL 02C8
+line, new 21B5
+line, next 0085
+LINE, VERTICAL 007C
+LINE, WAVY 2307
+LINE, WAVY LOW FE4F
+LINE ABOVE, COMBINING DOUBLE VERTICAL 030E
+LINE ABOVE, COMBINING VERTICAL 030D
+LINE BELOW, COMBINING DOUBLE VERTICAL 0348
+LINE BELOW, COMBINING VERTICAL 0329
+line down, partial 008B
+line feed 000A
+line feed 21B4
+line feed, reverse 008D
+LINE FEED, SYMBOL FOR 240A
+line marker 2319
+LINE OVERLAY, COMBINING LONG VERTICAL 20D2
+LINE OVERLAY, COMBINING SHORT VERTICAL 20D3
+LINE SEPARATOR 2028
+LINE SYMBOL, CENTRE 2104
+line tabulation set 008A
+line up, partial 008C
+LINE WITH MIDDLE DOT, VERTICAL 237F
+Linear B Ideograms 10080
+Linear B Syllabary 10000
+Lines For Terminal Graphics, Scan 23BA
+Lira, Italian 00A3
+LIRA SIGN 20A4
+liter 2113
+Livonian, Additions for 022A
+LOCATION SIGN, TELEPHONE 2706
+lock, caps 21EA
+lock, caps 21EC
+lock, group 21F0
+lock, level 2 21EB
+lock, level 3 21EF
+lock, numerics 21ED
+Logic Operators, Modal 27E0
+LOGICAL AND 2227
+LOGICAL AND, CURLY 22CF
+LOGICAL AND, INTERSECTION WITH 2A44
+LOGICAL AND, N-ARY 22C0
+LOGICAL AND OPERATOR, TWO 2A07
+Logical Ands and Ors 2A51
+LOGICAL OR 2228
+LOGICAL OR, CURLY 22CE
+LOGICAL OR, N-ARY 22C1
+LOGICAL OR, UNION WITH 2A45
+LOGICAL OR OPERATOR, TWO 2A08
+long 0304
+Long Arrows 27F5
+long cross 2020
+long dash 2015
+LONG DASH FROM LEFT MEMBER OF DOUBLE VERTICAL 2AE6
+LONG HORIZONTAL STROKE, CONTAINS WITH 22FA
+LONG HORIZONTAL STROKE, ELEMENT OF WITH 22F2
+LONG LEFT TACK 27DE
+LONG RIGHT LEG, LATIN CAPITAL LETTER N WITH 0220
+LONG RIGHT TACK 27DD
+LONG S, LATIN SMALL LETTER 017F
+long slash overlay 0338
+LONG SOLIDUS OVERLAY, COMBINING 0338
+LONG STROKE OVERLAY, COMBINING 0336
+LONG VERTICAL LINE OVERLAY, COMBINING 20D2
+LORRAINE, CROSS OF 2628
+LOW ACUTE ACCENT, MODIFIER LETTER 02CF
+LOW ASTERISK 204E
+low double comma quotation mark 201E
+LOW DOUBLE PRIME QUOTATION MARK 301F
+LOW GRAVE ACCENT, MODIFIER LETTER 02CE
+LOW LINE 005F
+LOW LINE, CENTRELINE FE4E
+LOW LINE, COMBINING 0332
+LOW LINE, COMBINING DOUBLE 0333
+LOW LINE, DASHED FE4D
+LOW LINE, DOUBLE 2017
+LOW LINE, WAVY FE4F
+LOW MACRON, MODIFIER LETTER 02CD
+low single comma quotation mark 201A
+Low Surrogates DC00
+LOW VERTICAL LINE, MODIFIER LETTER 02CC
+LOW-9 QUOTATION MARK, DOUBLE 201E
+LOW-9 QUOTATION MARK, SINGLE 201A
+lower rank than 227A
+LOZENGE 25CA
+LOZENGE, BLACK 29EB
+LOZENGE, SQUARE 2311
+LOZENGE DIVIDED BY HORIZONTAL RULE 27E0
+lre 202A
+lrm 200E
+lro 202D
+M, COMBINING LATIN SMALL LETTER 036B
+M, LATIN CAPITAL LETTER TURNED 019C
+M, LATIN SMALL LETTER TURNED 026F
+M, SCRIPT CAPITAL 2133
+m-matrix 2133
+MACRON 00AF
+MACRON, COMBINING 0304
+MACRON, MODIFIER LETTER 02C9
+MACRON, MODIFIER LETTER LOW 02CD
+macron, spacing 00AF
+MACRON BELOW, COMBINING 0331
+Malayalam 0D00
+Malayalam Digits 0D66
+Malayalam Letters 0D05
+MALE SIGN 2642
+MALTESE CROSS 2720
+Manchu Letters, Mongolian 1873
+Map Markers 2690
+mapping, bijective 2916
+maps from 27FB
+maps from 2906
+maps to 27FC
+maps to 2905
+maps to 2907
+mark, german 2133
+marker, histogram 25AE
+Markers, Go 2686
+Markers, Map 2690
+mars 2642
+MASCULINE ORDINAL INDICATOR 00BA
+MASU MARK 303C
+MATERIALS, RECYCLING SYMBOL FOR GENERIC 267A
+Mathematical Brackets 27E6
+Mathematical Operators 2200
+Mathematical Operators, Supplemental 2A00
+MATHEMATICAL SPACE, MEDIUM 205F
+Mathematical Symbols, Double-Struck Italic 2145
+Mathematical Symbols-A, Miscellaneous 27C0
+Mathematical Symbols-B, Miscellaneous 2980
+MATRIX, HERMITIAN CONJUGATE 22B9
+MEASURED ANGLE 2221
+Measured Angles, Angles and 299B
+MEASURED BY 225E
+Medieval Superscript Letter Diacritics 0363
+medium, end of 0019
+MEDIUM, SYMBOL FOR END OF 2419
+MEDIUM MATHEMATICAL SPACE 205F
+MEDIUM SMALL SQUARE, BLACK 25FE
+MEDIUM SMALL SQUARE, WHITE 25FD
+MEDIUM SQUARE, BLACK 25FC
+MEDIUM SQUARE, WHITE 25FB
+MEMBER, CONTAINS AS 220B
+MEMBER, SMALL CONTAINS AS 220D
+MEMBER OF DOUBLE VERTICAL, LONG DASH FROM LEFT 2AE6
+MEMBERSHIP, Z NOTATION BAG 22FF
+MERCURY 263F
+merge 2A07
+message, privacy 009E
+message waiting 0095
+mho 2127
+MICRO SIGN 00B5
+mid space 2005
+MIDDLE DOT 00B7
+middle dot, greek 00B7
+MIDDLE DOT, KATAKANA 30FB
+MIDDLE DOT, LATIN SMALL LETTER L WITH 0140
+MIDDLE DOT, VERTICAL LINE WITH 237F
+MIDDLE TILDE, LATIN CAPITAL LETTER O WITH 019F
+MIDDLE TILDE, LATIN SMALL LETTER L WITH 026B
+MIDLINE HORIZONTAL ELLIPSIS 22EF
+midpoint 00B7
+MILL SIGN 20A5
+MILLE SIGN, PER 2030
+milreis 0024
+minim 264F
+minim (alternate glyph) 264D
+Minnan and Hakka, Chinese Bopomofo Extended for 31A0
+MINUS, CIRCLED 2296
+MINUS, DOT 2238
+MINUS, SET 2216
+MINUS, SQUARED 229F
+MINUS, SUBSCRIPT 208B
+MINUS, SUPERSCRIPT 207B
+MINUS SIGN 2212
+MINUS SIGN, COMMERCIAL 2052
+minus sign, hyphen or 002D
+MINUS SIGN, MODIFIER LETTER 02D7
+MINUS SIGN, UNION WITH 2A41
+MINUS SIGN BELOW, COMBINING 0320
+MINUS SIGN IN TRIANGLE 2A3A
+Minus Sign Operators, Plus and 2A22
+MINUS SIMILAR, SIMILAR 2A6C
+MINUS TILDE 2242
+MINUS-OR-PLUS SIGN 2213
+minutes 2032
+MINY 29FF
+Miscellaneous Mathematical Symbols-A 27C0
+Miscellaneous Mathematical Symbols-B 2980
+Miscellaneous Symbols 2600
+Miscellaneous Symbols and Arrows 2B00
+Miscellaneous Technical 2300
+MISRA, ARABIC SIGN 060F
+mmsp 205F
+Modal Logic Operators 27E0
+MODELS 22A7
+Modifier Letters, Spacing 02B0
+MODULO TWO SUM 2A0A
+Mongolian 1800
+MONGOLIAN COLON 1804
+MONGOLIAN COMMA 1802
+mongolian currency 20AE
+Mongolian Digits 1810
+Mongolian Extensions for Sanskrit and Tibetan 1880
+Mongolian Format Controls 180B
+MONGOLIAN FULL STOP 1803
+Mongolian Manchu Letters 1873
+Mongolian Sibe Letters 185D
+Mongolian Todo Letters 1843
+Monogram and Digram Symbols, Yijing 268C
+Monogram Symbol, Tai Xuan Jing 1D300
+MONOSTABLE SYMBOL 238D
+MONTH SIGN, TAMIL 0BF4
+Months, Enclosed CJK Letters and 3200
+Months, Telegraph Symbols for 32C0
+MOON, FIRST QUARTER 263D
+MOON, LAST QUARTER 263E
+most positive 223E
+MUCH GREATER-THAN 226B
+MUCH GREATER-THAN, VERY 22D9
+MUCH LESS-THAN 226A
+MUCH LESS-THAN, VERY 22D8
+MULTIMAP 22B8
+MULTIMAP, DOUBLE-ENDED 29DF
+MULTIMAP, LEFT 27DC
+MULTIPLICATION, MULTISET 228D
+Multiplication and Division Sign Operators 2A2F
+MULTIPLICATION SIGN 00D7
+MULTIPLICATION SIGN BELOW, SUBSET WITH 2AC1
+MULTIPLICATION SIGN BELOW, SUPERSET WITH 2AC2
+MULTIPLICATION X 2715
+MULTIPLICATION X, HEAVY 2716
+MULTISET 228C
+MULTISET MULTIPLICATION 228D
+MULTISET UNION 228E
+MUSIC FLAT SIGN 266D
+MUSIC NATURAL SIGN 266E
+MUSIC SHARP SIGN 266F
+Musical Symbols 2669
+mutton 2003
+mutton quad 2001
+mvs 180E
+Myanmar 1000
+Myanmar Digits 1040
+N, DOUBLE-STRUCK CAPITAL 2115
+N, LATIN LETTER SMALL CAPITAL 0274
+N WITH LONG RIGHT LEG, LATIN CAPITAL LETTER 0220
+N-ARY COPRODUCT 2210
+n-ary dijkstra choice 2AFF
+N-ARY INTERSECTION 22C2
+N-ARY LOGICAL AND 22C0
+N-ARY LOGICAL OR 22C1
+N-ary Operators 2A00
+N-ARY PRODUCT 220F
+N-ARY SUMMATION 2211
+N-ARY SUMMATION, DOUBLE-STRUCK 2140
+N-ARY UNION 22C3
+N-ARY WHITE VERTICAL BAR 2AFF
+NABLA 2207
+NAIRA SIGN 20A6
+NAND 22BC
+nang 0323
+NARROW NO-BREAK SPACE 202F
+nasal hook 0328
+NATIONAL DIGIT SHAPES 206E
+natural number 2115
+NATURAL SIGN, MUSIC 266E
+nbsp 0080
+necessarily satisfies 2AF1
+NEGATED WITH VERTICAL BAR, INFINITY 29DE
+negation 20D3
+NEGATION SLASH, DOES NOT DIVIDE WITH REVERSED 2AEE
+negative acknowledge 0015
+negative acknowledge, graphic for 237B
+NEGATIVE ACKNOWLEDGE, SYMBOL FOR 2415
+NEPTUNE 2646
+never (modal operator) 27E1
+never (modal operator), was 27E2
+never be (modal operator), will 27E3
+new line 21B5
+NEW SHEQEL SIGN 20AA
+NEWLINE, SYMBOL FOR 2424
+next line 0085
+NEXT PAGE 2398
+NIB, BLACK 2712
+nigerian currency 20A6
+nim-addition 2A27
+nnbsp 202F
+no break here 0083
+no break space, graphic for 237D
+NO-BREAK SPACE 00A0
+NO-BREAK SPACE, NARROW 202F
+NO-BREAK SPACE, ZERO WIDTH FEFF
+NODE, ASCENDING 260A
+NODE, DESCENDING 260B
+NOMINAL DIGIT SHAPES 206F
+NON-BREAKING HYPHEN 2011
+non-breaking space 00A0
+NON-JOINER, ZERO WIDTH 200C
+non-theorem 22A3
+Noncharacters FDD0
+Noncharacters FFFE
+Noncharacters 1FFFE
+Noncharacters 2FFFE
+Noncharacters 3FFFE
+Noncharacters 4FFFE
+Noncharacters 5FFFE
+Noncharacters 6FFFE
+Noncharacters 7FFFE
+Noncharacters 8FFFE
+Noncharacters 9FFFE
+Noncharacters AFFFE
+Noncharacters BFFFE
+Noncharacters CFFFE
+Noncharacters DFFFE
+Noncharacters EFFFE
+Noncharacters FFFFE
+Noncharacters 10FFFE
+NONFORKING 2ADD
+NOR 22BD
+NORMAL SUBGROUP, CONTAINS AS 22B3
+NORMAL SUBGROUP OF 22B2
+not 223C
+Not a Character FFFE
+Not a Character FFFF
+NOT ALMOST EQUAL TO, PRECEDES ABOVE 2AB9
+NOT ALMOST EQUAL TO, SUCCEEDS ABOVE 2ABA
+NOT AN ELEMENT OF 2209
+NOT APPROXIMATE, GREATER-THAN AND 2A8A
+NOT APPROXIMATE, LESS-THAN AND 2A89
+NOT CHECK MARK 237B
+NOT DIVIDE WITH REVERSED NEGATION SLASH, DOES 2AEE
+NOT EQUAL TO 2260
+NOT EQUAL TO, GREATER-THAN AND SINGLE-LINE 2A88
+NOT EQUAL TO, LESS-THAN AND SINGLE-LINE 2A87
+NOT EQUAL TO, PRECEDES ABOVE 2AB5
+NOT EQUAL TO, PRECEDES ABOVE SINGLE-LINE 2AB1
+NOT EQUAL TO, SUBSET OF ABOVE 2ACB
+NOT EQUAL TO, SUCCEEDS ABOVE 2AB6
+NOT EQUAL TO, SUCCEEDS ABOVE SINGLE-LINE 2AB2
+NOT EQUAL TO, SUPERSET OF ABOVE 2ACC
+not independent 2ADC
+NOT SIGN 00AC
+NOT SIGN, DOUBLE STROKE 2AEC
+NOT SIGN, REVERSED 2310
+NOT SIGN, REVERSED DOUBLE STROKE 2AED
+NOT SIGN, TURNED 2319
+NOT TILDE ABOVE, COMBINING 034A
+not yield, does 22A3
+NOTE, EIGHTH 266A
+NOTE, QUARTER 2669
+NOTES, BEAMED EIGHTH 266B
+NOTES, BEAMED SIXTEENTH 266C
+null 0000
+NULL, SYMBOL FOR 2400
+null set 2205
+number, natural 2115
+Number Forms 2150
+Number Runes, Golden 16EE
+NUMBER SIGN 0023
+NUBMER SIGN, ARABIC 0600
+NUMBER SIGN, TAMIl 0BFA
+number symbol, real 210A
+NUMBER ZERO, IDEOGRAPHIC 3007
+Numbers, Aegean 10100
+Numbers, Circled 2460
+Numbers, Circled 3251
+Numbers, Circled 32B1
+Numbers, Circled Inverse 2776
+Numbers, Double Circled 24F5
+Numbers, Parenthesized 2474
+numbers, the set of complex 2102
+numbers, the set of rational 211A
+numbers, the set of real 211D
+Numbers, White On Black Circled 24EB
+Numbers Period 2488
+Numerals, Hangzhou-style 3021
+Numerals, Old Italic 10320
+Numerals, Roman 2160
+NUMERATOR ONE, FRACTION 215F
+numerics lock 21ED
+NUMERO SIGN 2116
+nut 2002
+O, COMBINING LATIN SMALL LETTER 0366
+o, latin capital letter barred 019F
+O, LATIN CAPITAL LETTER OPEN 0186
+O, LATIN SMALL LETTER BARRED 0275
+O, LATIN SMALL LETTER OPEN 0254
+O, SCRIPT SMALL 2134
+o bar 019F
+o bar 0275
+o e, latin small letter 0153
+O WITH MIDDLE TILDE, LATIN CAPITAL LETTER 019F
+obelisk 2020
+obelisk, double 2021
+OBJECT REPLACEMENT CHARACTER FFFC
+OCR, Optical Character Recognition 2440
+octothorpe 0023
+OE, LATIN LETTER SMALL CAPITAL 0276
+OE, LATIN SMALL LIGATURE 0153
+Ogham 1680
+OGHAM SPACE MARK 1680
+OGONEK 02DB
+OGONEK, COMBINING 0328
+OHM SIGN 2126
+OHM SIGN, INVERTED 2127
+OI, LATIN SMALL LETTER 01A3
+OM, DEVANAGARI 0950
+OMEGA, LATIN SMALL LETTER CLOSED 0277
+ONE, FRACTION NUMERATOR 215F
+ONE, SUPERSCRIPT 00B9
+ONE DOT LEADER 2024
+ONE HALF, VULGAR FRACTION 00BD
+ONE QUARTER, VULGAR FRACTION 00BC
+OPEN BOX 2423
+OPEN BOX, SHOULDERED 237D
+OPEN E, LATIN CAPITAL LETTER 0190
+OPEN E, LATIN SMALL LETTER 025B
+OPEN E, LATIN SMALL LETTER CLOSED 029A
+OPEN E, LATIN SMALL LETTER CLOSED REVERSED 025E
+OPEN E, LATIN SMALL LETTER REVERSED 025C
+OPEN O, LATIN CAPITAL LETTER 0186
+OPEN O, LATIN SMALL LETTER 0254
+opening brace 007B
+opening curly bracket 007B
+opening parenthesis 0028
+opening square bracket 005B
+operating system command 009D
+OPERATOR, ASTERISK 2217
+OPERATOR, BULLET 2219
+OPERATOR, CIRCLED ASTERISK 229B
+OPERATOR, CIRCLED DOT 2299
+OPERATOR, CIRCLED RING 229A
+OPERATOR, DIAMOND 22C4
+OPERATOR, DOT 22C5
+OPERATOR, RING 2218
+OPERATOR, SQUARED DOT 22A1
+OPERATOR, STAR 22C6
+OPERATOR, TILDE 223C
+Operators, Database Theory 27D5
+Operators, Invisible 2063
+Operators, Mathematical 2200
+Operators, Modal Logic 27E0
+Operators, Multiplication and Division Sign 2A2F
+Operators, N-Ary 2A00
+Operators, Plus and Minus Sign 2A22
+Operators, Relational 2A66
+Operators, Specialized plus sign 29FA
+Operators, Supplemental Mathematical 2A00
+Operators, Vertical Line 2AEE
+OPPOSITION 260D
+Optical Character Recognition (OCR) 2440
+OPTION KEY 2325
+OR, CURLY LOGICAL 22CE
+OR, DOUBLE LOGICAL 2A54
+OR, LOGICAL 2228
+OR, N-ARY LOGICAL 22C1
+OR, SLOPING LARGE 2A57
+OR, TWO INTERSECTING LOGICAL 2A56
+OR, UNION WITH LOGICAL 2A45
+OR OPERATOR, TWO LOGICAL 2A08
+OR WITH DOT ABOVE, LOGICAL 2A52
+OR WITH DOUBLE OVERBAR, LOGICAL 2A62
+OR WITH DOUBLE UNDERBAR, LOGICAL 2A63
+OR WITH HORIZONTAL DASH, LOGICAL 2A5D
+OR WITH MIDDLE STEM, LOGICAL 2A5B
+order 2134
+ORDINAL INDICATOR, FEMININE 00AA
+ORDINAL INDICATOR, MASCULINE 00BA
+ordinarily satisfies 2AE2
+ORIGIN, DIMENSION 2331
+ORIGINAL OF 22B6
+ORIGINAL OF, SQUARE 2290
+Oriya 0B00
+Oriya Digits 0B66
+Oriya Letters 0B05
+Ornamental Angle Quotation Marks 276E
+Ornamental Brackets 2768
+Ornamental Brackets 2770
+Ornaments, Heart 2763
+Ornaments, Punctuation 275B
+ORNATE LEFT PARENTHESIS FD3E
+ors, logical ands and 2A51
+ORTHODOX CROSS 2626
+orthogonal to 22A5
+Osmanya 10480
+Osmanya Digits 104A0
+OU, LATIN SMALL LETTER 0223
+OUNCE SIGN 2125
+OUTER JOIN, FULL 27D7
+OUTER JOIN, LEFT 27D5
+OUTER JOIN, RIGHT 27D6
+OUTLINE, SQUARE WITH CONTOURED 29E0
+OVER INFINITY, TIE 29DD
+OVER TOP SQUARE BRACKET, BOTTOM SQUARE BRACKET 23B6
+overbar, apl 00AF
+OVERLAPPING LESS-THAN, GREATER-THAN 2AA4
+OVERLAPPING LOGICAL AND, LOGICAL OR 2A59
+OVERLAY, COMBINING CLOCKWISE RING 20D9
+OVERLAY, COMBINING DOUBLE VERTICAL STROKE 20E6
+OVERLAY, COMBINING LEFTWARDS ARROW 20EA
+OVERLAY, COMBINING LONG SOLIDUS 0338
+OVERLAY, COMBINING LONG STROKE 0336
+OVERLAY, COMBINING LONG VERTICAL LINE 20D2
+OVERLAY, COMBINING REVERSE SOLIDUS 20E5
+OVERLAY, COMBINING RING 20D8
+OVERLAY, COMBINING SHORT SOLIDUS 0337
+OVERLAY, COMBINING SHORT STROKE 0335
+OVERLAY, COMBINING SHORT VERTICAL LINE 20D3
+OVERLAY, COMBINING TILDE 0334
+overlay, long slash 0338
+overlay, short slash 0337
+overline 00AF
+OVERLINE 203E
+OVERLINE, CENTRELINE FE4A
+OVERLINE, COMBINING 0305
+OVERLINE, COMBINING DOUBLE 033F
+OVERLINE, DASHED FE49
+OVERLINE, DOUBLE WAVY FE4C
+OVERLINE, WAVY FE4B
+OVERRIDE, LEFT-TO-RIGHT 202D
+OVERRIDE, RIGHT-TO-LEFT 202E
+overscore 0305
+overscore, spacing 203E
+Overscores and Underscores FE49
+Overstruck Diacritics 0334
+oxia 0301
+P, DOUBLE-STRUCK CAPITAL 2119
+P, SCRIPT CAPITAL 2118
+PAGE, NEXT 2398
+PAGE, PREVIOUS 2397
+page down 21DF
+page up 21DE
+PALATALIZED HOOK BELOW, COMBINING 0321
+PAMUDPOD, HANUNOO SIGN 1734
+PAPER SYMBOL, PARTIALLY-RECYCLED 267D
+PAPER SYMBOL, RECYCLED 267C
+PARAGRAPH SEPARATOR 2029
+PARAGRAPH SEPARATOR, GEORGIAN 10FB
+paragraph separator, urdu 203B
+paragraph sign 00B6
+paragraph sign, european 00A7
+PARAGRAPH SIGN ORNAMENT, CURVED STEM 2761
+PARALLEL, CIRCLED 29B7
+PARALLEL, EQUALS SIGN AND SLANTED 29E3
+PARALLEL, IDENTICAL TO AND SLANTED 29E5
+PARALLEL TO 2225
+parallel to, identical and 2A68
+PARALLEL WITH HORIZONTAL STROKE 2AF2
+PARALLEL WITH TILDE ABOVE, EQUALS SIGN AND SLANTED 29E4
+PARALLEL WITH TILDE OPERATOR 2AF3
+PARALLELOGRAM, BLACK 25B0
+parenthesis, closing 0029
+PARENTHESIS, LEFT 0028
+parenthesis, opening 0028
+PARENTHESIS, ORNATE LEFT FD3E
+PARENTHESIS, RIGHT 0029
+PARENTHESIS, SUBSCRIPT LEFT 208D
+PARENTHESIS, SUPERSCRIPT LEFT 207D
+Parenthesized Ideographs 3220
+Parenthesized Korean Hangul Elements 3200
+Parenthesized Korean Hangul Syllables 320E
+Parenthesized Latin Letters 249C
+Parenthesized Numbers 2474
+PART ALTERNATION MARK 303D
+PART INTEGRAL, FINITE 2A0D
+parted rule 00A6
+PARTIAL DIFFERENTIAL 2202
+partial function, z notation 21F8
+partial injection, z notation 2914
+partial line down 008B
+partial line up 008C
+partial relation, z notation 21F9
+partial surjection, z notation 2900
+PARTIALLY-RECYCLED PAPER SYMBOL 267D
+PARTNERSHIP SIGN 3250
+Parts, Summation Sign 23B2
+pdf 202C
+PEACE SYMBOL 262E
+PENCIL, UPPER RIGHT 2710
+Pencil Dingbats 270E
+PENNY SIGN, GERMAN 20B0
+per 2118
+PER MILLE SIGN 2030
+PER TEN THOUSAND SIGN 2031
+PERCENT SIGN 0025
+PERCENT SIGN, ARABIC 066A
+PERCUSSIVE, LATIN LETTER BIDENTAL 02AD
+PERCUSSIVE, LATIN LETTER BILABIAL 02AC
+period 002E
+PERISPOMENI, COMBINING GREEK 0342
+perpendicular 22A5
+PERPENDICULAR, CIRCLED 29B9
+PERPENDICULAR WITH S 2AE1
+Persian and Urdu, Eastern Arabic-Indic Digits for 06F0
+PERSPECTIVE 2306
+PESETA SIGN 20A7
+PESO SIGN 20B1
+PHARYNGEAL VOICED FRICATIVE, LATIN LETTER 0295
+PHI, LATIN SMALL LETTER 0278
+Philippine Scripts, Generic Punctuation For 1735
+Phonetic Alphabet, International 0250
+Phonetic Extensions 1D00
+Phonetic Extensions, Katakana 31F0
+Phonetic Extensions, non-IPA 1D00
+Phonetic Extensions for Ainu 31F0
+Phonetic Modifiers Derived from Latin Letters 02B0
+Phonetics and Symbols Area, CJK 2E00
+phonorecord sign 2117
+PI, DOUBLE-STRUCK CAPITAL 213F
+pi, mathematical constant 03C0
+Pictures for Control Codes, Graphic 2400
+Pieces, Bracket 239B
+Pieces, Bracket 23B0
+PILCROW SIGN 00B6
+PILCROW SIGN, REVERSED 204B
+Pinyin Diacritic-vowel Combinations 01CD
+pipe 01C0
+pipe, double 01C1
+pipe, double-barred 01C2
+PIPING, Z NOTATION SCHEMA 2A20
+PISCES 2653
+PITCHFORK 22D4
+PITCHFORK WITH TEE TOP 2ADA
+PLACE OF INTEREST SIGN 2318
+plaintiff 226C
+PLANCK CONSTANT 210E
+PLANCK CONSTANT OVER TWO PI 210F
+Planet Symbols 263F
+Playing Card Suits 2660
+PLUS, CIRCLED 2295
+PLUS, DOT 2214
+PLUS, DOUBLE 29FA
+PLUS, N-ARY UNION OPERATOR WITH 2A04
+PLUS, SQUARED 229E
+PLUS, TRIPLE 29FB
+Plus and Minus Sign Operators 2A22
+PLUS OPERATOR, N-ARY CIRCLED 2A01
+PLUS SIGN 002B
+PLUS SIGN, EQUALS SIGN ABOVE 2A71
+PLUS SIGN, MODIFIER LETTER 02D6
+PLUS SIGN, SUBSCRIPT 208A
+PLUS SIGN, SUPERSCRIPT 207A
+PLUS SIGN ABOVE EQUALS SIGN 2A72
+PLUS SIGN BELOW, COMBINING 031F
+PLUS SIGN BELOW, SUBSET WITH 2ABF
+PLUS SIGN BELOW, SUPERSET WITH 2AC0
+PLUS SIGN IN LEFT HALF CIRCLE 2A2D
+PLUS SIGN IN RIGHT HALF CIRCLE 2A2E
+PLUS SIGN IN TRIANGLE 2A39
+Plus Sign Operators, Specialized 29FA
+PLUS-MINUS SIGN 00B1
+PLUTO 2647
+POETIC VERSE SIGN, ARABIC 060E
+POINT OPERATOR, INTEGRAL AROUND A 2A15
+Pointers 25BA
+Points, Arabic 064B
+Points, Hebrew 05B0
+poison 2620
+Political Symbols, Religious and 2626
+POP DIRECTIONAL FORMATTING 202C
+POSITION INDICATOR 2316
+positive, most 223E
+positive difference, sum or 2A26
+positive difference or sum 2A24
+POSTAL MARK 3012
+POSTAL MARK, CIRCLED 3036
+POSTAL MARK FACE 3020
+pound sign 0023
+POUND SIGN 00A3
+pound sterling 00A3
+pounds 2114
+power set 2118
+PRECEDES 227A
+PRECEDES, DOUBLE 2ABB
+PRECEDES ABOVE ALMOST EQUAL TO 2AB7
+PRECEDES ABOVE EQUALS SIGN 2AB3
+PRECEDES ABOVE NOT ALMOST EQUAL TO 2AB9
+PRECEDES ABOVE NOT EQUAL TO 2AB5
+PRECEDES ABOVE SINGLE-LINE EQUALS SIGN 2AAF
+PRECEDES ABOVE SINGLE-LINE NOT EQUAL TO 2AB1
+PRECEDES UNDER RELATION 22B0
+PRESCRIPTION TAKE 211E
+Presentation Forms, Alphabetic FB00
+Presentation Forms, Hebrew FB1D
+Presentation Forms-A, Arabic FB50
+Presentation Forms-B, Arabic FE70
+PREVIOUS PAGE 2397
+PRIME 2032
+PRIME, DOUBLE 2033
+PRIME, MODIFIER LETTER 02B9
+PRIME, MODIFIER LETTER DOUBLE 02BA
+PRIME, QUADRUPLE 2057
+PRIME, REVERSED 2035
+PRIME, REVERSED DOUBLE 2036
+PRIME, REVERSED TRIPLE 2037
+PRIME, TRIPLE 2034
+PRIME QUOTATION MARK, DOUBLE 301E
+PRIME QUOTATION MARK, LOW DOUBLE 301F
+PRIME QUOTATION MARK, REVERSED DOUBLE 301D
+PRINT SCREEN SYMBOL 2399
+privacy message 009E
+Private Use Area E000
+Private Use Area-A, Supplementary F0000
+Private Use Area-B, Supplementary 100000
+private use one 0091
+private use two 0092
+PRODUCT, CLOSED UNION WITH SERIFS AND SMASH 2A50
+product, direct 2299
+PRODUCT, INTERIOR 2A3C
+PRODUCT, LEFT SEMIDIRECT 22CB
+PRODUCT, N-ARY 220F
+PRODUCT, RIGHTHAND INTERIOR 2A3D
+PRODUCT, SHUFFLE 29E2
+PRODUCT, SMASH 2A33
+product, tensor 2297
+PRODUCT, VECTOR OR CROSS 2A2F
+PRODUCT, WREATH 2240
+PRODUCT WITH BOTTOM CLOSED, SEMIDIRECT 2A32
+PROFILE, ALL AROUND- 232E
+prohibition 20E0
+PROJECTION, Z NOTATION SCHEMA 2A21
+PROJECTIVE 2305
+PROOF, END OF 220E
+PROPERTY LINE 214A
+PROPORTION 2237
+PROPORTION, GEOMETRIC 223A
+PROPORTIONAL TO 221D
+proportional to, varies with 223C
+proves 22A2
+psili 0313
+published 2117
+pullback 27D3
+Punctuation, CJK Symbols and 3000
+Punctuation, General 2000
+Punctuation, Hanun�o-Specific 1734
+Punctuation, Katakana 30A0
+PUNCTUATION, PHILIPPINE DOUBLE 1736
+PUNCTUATION, PHILIPPINE SINGLE 1735
+Punctuation For Philippine Scripts, Generic 1735
+Punctuation For Vertical Text, Double 2047
+Punctuation Ornaments 275B
+PUNCTUATION SPACE 2008
+punt, irish 00A3
+purna viram 0964
+pushout 27D4
+Q, DOUBLE-STRUCK CAPITAL 211A
+Q, ROTATED CAPITAL 213A
+QAF, ARABIC LETTER DOTLESS 066F
+qed 220E
+QUAD, EM 2001
+QUAD, EN 2000
+quad, mutton 2001
+Quadrants 2596
+quadrature 25A1
+QUADRUPLE INTEGRAL OPERATOR 2A0C
+QUADRUPLE PRIME 2057
+quantic 226C
+QUARTER MOON, FIRST 263D
+QUARTER MOON, LAST 263E
+QUARTER NOTE 2669
+Quarters, Fractions 00BC
+QUATERNION INTEGRAL OPERATOR 2A16
+QUESTION EXCLAMATION MARK 2048
+QUESTION MARK 003F
+QUESTION MARK, ARABIC 061F
+QUESTION MARK, ARMENIAN 055E
+QUESTION MARK, DOUBLE 2047
+QUESTION MARK, ETHIOPIC 1367
+QUESTION MARK, EXCLAMATION 2049
+QUESTION MARK, GREEK 037E
+QUESTION MARK, INVERTED 00BF
+QUESTION MARK ABOVE, GREATER-THAN WITH 2A7C
+QUESTION MARK ABOVE, LESS-THAN WITH 2A7B
+QUESTIONED EQUAL TO 225F
+QUILL, LEFT SQUARE BRACKET WITH 2045
+Quine Corners 231C
+quotation dash 2015
+QUOTATION MARK 0022
+quotation mark, double comma 201D
+QUOTATION MARK, DOUBLE HIGH-REVERSED-9 201F
+QUOTATION MARK, DOUBLE LOW-9 201E
+QUOTATION MARK, DOUBLE PRIME 301E
+quotation mark, double reversed comma 201F
+quotation mark, double turned comma 201C
+QUOTATION MARK, LEFT DOUBLE 201C
+QUOTATION MARK, LEFT SINGLE 2018
+QUOTATION MARK, LEFT-POINTING DOUBLE ANGLE 00AB
+quotation mark, low double comma 201E
+QUOTATION MARK, LOW DOUBLE PRIME 301F
+quotation mark, low single comma 201A
+QUOTATION MARK, REVERSED DOUBLE PRIME 301D
+QUOTATION MARK, RIGHT DOUBLE 201D
+QUOTATION MARK, RIGHT SINGLE 2019
+QUOTATION MARK, RIGHT-POINTING DOUBLE ANGLE 00BB
+quotation mark, single comma 2019
+QUOTATION MARK, SINGLE HIGH-REVERSED-9 201B
+QUOTATION MARK, SINGLE LEFT-POINTING ANGLE 2039
+QUOTATION MARK, SINGLE LOW-9 201A
+quotation mark, single reversed comma 201B
+QUOTATION MARK, SINGLE RIGHT-POINTING ANGLE 203A
+quotation mark, single turned comma 2018
+Quotation Mark Ornaments 275B
+Quotation Marks, Ornamental Angle 276E
+quote, apl 0022
+R, BLACK-LETTER CAPITAL 211C
+R, COMBINING LATIN SMALL LETTER 036C
+R, DOUBLE-STRUCK CAPITAL 211D
+R, LATIN LETTER SMALL CAPITAL 0280
+R, LATIN LETTER SMALL CAPITAL INVERTED 0281
+R, LATIN SMALL LETTER TURNED 0279
+R, MODIFIER LETTER SMALL 02B3
+R, MODIFIER LETTER SMALL CAPITAL INVERTED 02B6
+R, MODIFIER LETTER SMALL TURNED 02B4
+R, SCRIPT CAPITAL 211B
+radial component 27DF
+radical sign 221A
+Radicals, Kangxi 2F00
+Radicals, Yi A490
+Radicals Supplement, CJK 2E80
+RADIOACTIVE SIGN 2622
+RAIN DROPS, UMBRELLA WITH 2614
+rainy weather 2602
+RAMS HORN, LATIN SMALL LETTER 0264
+RANGE ANTIRESTRICTION, Z NOTATION 2A65
+RATIO 2236
+ratio, cross 211E
+rational numbers, the set of 211A
+real number symbol 210A
+real numbers, the set of 211D
+real part 211C
+recipe 211E
+record separator 001E
+RECORD SEPARATOR, SYMBOL FOR 241E
+RECORDER, TELEPHONE 2315
+RECORDING COPYRIGHT, SOUND 2117
+Rectangles 25AC
+RECTANGULAR PATH AROUND POLE, LINE INTEGRATION WITH 2A12
+RECYCLED PAPER SYMBOL 267C
+RECYCLING SYMBOL, BLACK UNIVERSAL 267B
+RECYCLING SYMBOL, UNIVERSAL 2672
+RECYCLING SYMBOL FOR GENERIC MATERIALS 267A
+Recycling Symbols 2672
+Recycling Symbols For Plastics 2673
+reduces to 22A6
+reducible 22A2
+REFERENCE MARK 203B
+registered trade mark sign 00AE
+RELATION, TRIPLE SOLIDUS BINARY 2AFB
+RELATION, TRIPLE VERTICAL BAR BINARY 2AF4
+relation, z notation finite 21FC
+relation, z notation partial 21F9
+RELATIONAL COMPOSITION, Z NOTATION 2A3E
+Relational Operators 2A66
+Relations 29E3
+Relations 2AF7
+Relations, Subset and superset 2ABD
+Religious and Political Symbols 2626
+Repeat Marks, Kana 3031
+REPLACEMENT CHARACTER FFFD
+REPLACEMENT CHARACTER, OBJECT FFFC
+resistance 2126
+RESPONSE 211F
+results in 22A8
+RETROFLEX CLICK, LATIN LETTER 01C3
+retroflex hook, latin small letter d 0256
+RETROFLEX HOOK BELOW, COMBINING 0322
+return, carriage 000D
+return, carriage 21B5
+RETURN, SYMBOL FOR CARRIAGE 240D
+RETURN SYMBOL 23CE
+reverse line feed 008D
+REVERSE SOLIDUS 005C
+REVERSE SOLIDUS, BIG 29F9
+REVERSE SOLIDUS, CIRCLED 29B8
+REVERSE SOLIDUS OPERATOR 29F5
+REVERSE SOLIDUS OVERLAY, COMBINING 20E5
+REVERSE SOLIDUS WITH HORIZONTAL STROKE 29F7
+reverse turnstile 22A3
+REVERSED, LATIN SMALL LETTER EZH 01B9
+REVERSED COMMA, MODIFIER LETTER 02BD
+REVERSED COMMA ABOVE, COMBINING 0314
+reversed comma quotation mark, double 201F
+reversed comma quotation mark, single 201B
+REVERSED DOUBLE PRIME 2036
+REVERSED DOUBLE PRIME QUOTATION MARK 301D
+REVERSED DOUBLE STROKE NOT SIGN 2AED
+REVERSED E, LATIN CAPITAL LETTER 018E
+REVERSED E, LATIN SMALL LETTER 0258
+reversed epsilon, latin small letter closed 025E
+REVERSED ESH, LATIN SMALL LETTER SQUAT 0285
+REVERSED ESH LOOP, LATIN LETTER 01AA
+reversed glottal stop, latin letter 0295
+REVERSED GLOTTAL STOP, MODIFIER LETTER 02C1
+REVERSED GLOTTAL STOP, MODIFIER LETTER SMALL 02E4
+REVERSED NEGATION SLASH, DOES NOT DIVIDE WITH 2AEE
+REVERSED NOT SIGN 2310
+REVERSED OPEN E, LATIN SMALL LETTER 025C
+REVERSED OPEN E, LATIN SMALL LETTER CLOSED 025E
+REVERSED PILCROW SIGN 204B
+REVERSED PRIME 2035
+REVERSED SANS-SERIF CAPITAL L 2143
+REVERSED SEMICOLON 204F
+reversed straight epsilon 220D
+REVERSED TILDE 223D
+REVERSED TILDE EQUALS 22CD
+REVERSED TRIPLE PRIME 2037
+RHOTIC HOOK, MODIFIER LETTER 02DE
+riemann integral 211B
+RIGHT ANGLE 221F
+RIGHT ANGLE WITH ARC 22BE
+RIGHT TRIANGLE 22BF
+RIGHT-TO-LEFT EMBEDDING 202B
+RIGHT-TO-LEFT MARK 200F
+RIGHT-TO-LEFT OVERRIDE 202E
+RIGHTHAND INTERIOR PRODUCT 2A3D
+RING, BENZENE 232C
+RING, MODIFIER LETTER CENTRED LEFT HALF 02D3
+RING, MODIFIER LETTER LEFT HALF 02BF
+RING ABOVE 02DA
+RING ABOVE, COMBINING 030A
+RING BELOW, COMBINING 0325
+RING BELOW, COMBINING LEFT HALF 031C
+RING BELOW, COMBINING RIGHT HALF 0339
+RING EQUAL TO 2257
+RING IN EQUAL TO 2256
+RING OPERATOR 2218
+RING OPERATOR, CIRCLED 229A
+RING OVERLAY, COMBINING 20D8
+RING OVERLAY, COMBINING CLOCKWISE 20D9
+RISING DIAGONAL SLASH, SQUARED 29C4
+RISING DOTS, MINUS SIGN WITH 2A2C
+RISING DOTS, TILDE OPERATOR WITH 2A6B
+rle 202B
+rlm 200F
+rlo 202E
+Roman Numerals 2160
+Romanian, Additions for 0218
+ROOT, CUBE 221B
+ROOT, FOURTH 221C
+ROOT, SQUARE 221A
+ROTATED CAPITAL Q 213A
+rotation 20D5
+rough breathing 0314
+RULE, LOZENGE DIVIDED BY HORIZONTAL 27E0
+rule, parted 00A6
+RULE-DELAYED 29F4
+Runes, Golden Number 16EE
+Runic 16A0
+RUNOUT, TOTAL 2330
+RUPEE MARK, BENGALI 09F2
+RUPEE SIGN 20A8
+RUPEE SIGN, BENGALI 09F3
+RUPEE SIGN, GUJARATI 0AF1
+RUPEE SIGN, TAMIL 0BF9
+Russian Alphabet, Basic 0410
+S, INVERTED LAZY 223E
+S, LATIN SMALL LETTER LONG 017F
+S, LATIN SMALL LETTER SHARP 00DF
+s, lazy 223D
+S, MODIFIER LETTER SMALL 02E2
+S, PERPENDICULAR WITH 2AE1
+S IN TRIANGLE 29CC
+SAFHA, ARABIC SIGN 0603
+SAGITTARIUS 2650
+SALTIRE 2613
+sam 070F
+SANAH, ARABIC SIGN 0601
+SANS-SERIF CAPITAL G, TURNED 2141
+SANS-SERIF CAPITAL L, REVERSED 2143
+SANS-SERIF CAPITAL L, TURNED 2142
+SANS-SERIF CAPITAL Y, TURNED 2144
+Sanskrit and Tibetan, Mongolian Extensions for 1880
+satisfies 22A8
+satisfies, necessarily 2AF1
+satisfies, ordinarily 2AE2
+SATURN 2644
+SCHEMA COMPOSITION, Z NOTATION 2A1F
+schema hiding, z notation 29F9
+SCHEMA PIPING, Z NOTATION 2A20
+SCHEMA PROJECTION, Z NOTATION 2A21
+SCHWA, LATIN CAPITAL LETTER 018F
+SCHWA, LATIN SMALL LETTER 0259
+Scissors Dingbats 2701
+SCORPIUS 264F
+SCREEN, COMBINING ENCLOSING 20E2
+script a, latin small letter 0251
+SCRIPT CAPITAL B 212C
+SCRIPT CAPITAL E 2130
+SCRIPT CAPITAL F 2131
+SCRIPT CAPITAL H 210B
+SCRIPT CAPITAL I 2110
+SCRIPT CAPITAL L 2112
+SCRIPT CAPITAL M 2133
+SCRIPT CAPITAL P 2118
+SCRIPT CAPITAL R 211B
+script f, latin small letter 0192
+SCRIPT G, LATIN SMALL LETTER 0261
+SCRIPT SMALL E 212F
+SCRIPT SMALL G 210A
+SCRIPT SMALL L 2113
+SCRIPT SMALL O 2134
+script v, latin capital letter 01B2
+script v, latin small letter 028B
+Scripts Area, General 0000
+scrolling 21F3
+SCRUPLE 2108
+SEAGULL BELOW, COMBINING 033C
+second transfinite cardinal (the continuum) 2136
+seconds 2033
+SECTION SIGN 00A7
+section sign, european 00B6
+SECTOR 2314
+SEGMENT 2313
+selected area, end of 0087
+selected area, start of 0086
+Selectors, Variation FE00
+SEMICIRCULAR PATH AROUND POLE, LINE INTEGRATION WITH 2A13
+SEMICOLON 003B
+SEMICOLON, ARABIC 061B
+SEMICOLON, ETHIOPIC 1364
+SEMICOLON, REVERSED 204F
+SEMIDIRECT PRODUCT, LEFT 22CB
+SEMIDIRECT PRODUCT WITH BOTTOM CLOSED 2A32
+SEPARATOR DOT, AEGEAN WORD 10101
+SEPARATOR LINE, AEGEAN WORD 10100
+SEPARATOR, ARABIC DECIMAL 066B
+SEPARATOR, ARABIC THOUSANDS 066C
+separator, decimal 002C
+separator, devanagari phrase 0964
+separator, file 001C
+SEPARATOR, GEORGIAN PARAGRAPH 10FB
+separator, group 001D
+SEPARATOR, INVISIBLE 2063
+SEPARATOR, LINE 2028
+SEPARATOR, PARAGRAPH 2029
+separator, record 001E
+SEPARATOR, SYMBOL FOR FILE 241C
+SEPARATOR, SYMBOL FOR GROUP 241D
+SEPARATOR, SYMBOL FOR RECORD 241E
+SEPARATOR, SYMBOL FOR UNIT 241F
+separator, unit 001F
+separator, urdu paragraph 203B
+SEPARATOR KEY SYMBOL, DECIMAL 2396
+sequence concatenation, z notation 2040
+sequence introducer, control 009B
+Serbian Cyrillic Letters, Croatian Digraphs Matching 01C4
+SERIFS, CLOSED INTERSECTION WITH 2A4D
+SERIFS, CLOSED UNION WITH 2A4C
+SERIFS AND SMASH PRODUCT, CLOSED UNION WITH 2A50
+SERIFS AT BOTTOM, TRIANGLE WITH 29CD
+SERVICE MARK 2120
+SESAME DOT FE45
+SESAME DOT, WHITE FE46
+SET, EMPTY 2205
+set, included in 2282
+set, includes in 2283
+set, null 2205
+set, power 2118
+SET MINUS 2216
+set of complex numbers, the 2102
+set of integers, the 2124
+set of rational numbers, the 211A
+set of real numbers, the 211D
+set transmit state 0093
+Sets, Empty 29B0
+sextile 2736
+Shade Characters 2591
+shamrock 2663
+Shapes, Geometric 25A0
+SHARP S, LATIN SMALL LETTER 00DF
+SHARP SIGN, MUSIC 266F
+Shavian 10450
+SHEQEL SIGN, NEW 20AA
+shift 21E7
+shift in 000F
+SHIFT IN, SYMBOL FOR 240F
+shift out 000E
+SHIFT OUT, SYMBOL FOR 240E
+shilling 002F
+SHOGI PIECE, BLACK 2617
+SHOGI PIECE, WHITE 2616
+short 0306
+SHORT DOWN TACK 2ADF
+SHORT DOWN TACK, SHORT UP TACK ABOVE 2AE9
+SHORT DOWN TACK WITH OVERBAR 2AE7
+SHORT I WITH TAIL, CYRILLIC CAPITAL LETTER 048A
+SHORT I WITH TAIL, CYRILLIC SMALL LETTER 048B
+SHORT LEFT TACK 2ADE
+short slash overlay 0337
+SHORT SOLIDUS OVERLAY, COMBINING 0337
+SHORT STROKE OVERLAY, COMBINING 0335
+SHORT UP TACK 2AE0
+SHORT UP TACK ABOVE SHORT DOWN TACK 2AE9
+SHORT UP TACK WITH UNDERBAR 2AE8
+SHORT VERTICAL LINE OVERLAY, COMBINING 20D3
+SHOULDERED OPEN BOX 237D
+SHUFFLE PRODUCT 29E2
+shy 00AD
+Sibe Letters, Mongolian 185D
+Sidelining Emphasis Marks FE45
+SIMILAR, SIMILAR MINUS 2A6C
+SIMILAR ABOVE GREATER-THAN, LESS-THAN ABOVE 2A8F
+SIMILAR ABOVE GREATER-THAN ABOVE EQUALS SIGN 2AA0
+SIMILAR ABOVE LESS-THAN, GREATER-THAN ABOVE 2A90
+SIMILAR ABOVE LESS-THAN ABOVE EQUALS SIGN 2A9F
+SIMILAR MINUS SIMILAR 2A6C
+SIMILAR OR EQUAL, GREATER-THAN ABOVE 2A8E
+SIMILAR OR EQUAL, LESS-THAN ABOVE 2A8D
+SIMILAR OR GREATER-THAN 2A9E
+SIMILAR OR LESS-THAN 2A9D
+similar to 223C
+SINE WAVE 223F
+single character introducer 009A
+single comma quotation mark 2019
+single comma quotation mark, low 201A
+single guillemet, left pointing 2039
+single guillemet, right pointing 203A
+SINGLE HIGH-REVERSED-9 QUOTATION MARK 201B
+SINGLE LEFT-POINTING ANGLE QUOTATION MARK 2039
+SINGLE LOW-9 QUOTATION MARK 201A
+SINGLE PUNCTUATION, PHILIPPINE 1735
+SINGLE QUOTATION MARK, LEFT 2018
+SINGLE QUOTATION MARK, RIGHT 2019
+single reversed comma quotation mark 201B
+SINGLE RIGHT-POINTING ANGLE QUOTATION MARK 203A
+single shift three 008F
+single shift two 008E
+single turned comma quotation mark 2018
+Sinhala 0D80
+SIX-PER-EM SPACE 2006
+SIXTEENTH NOTES, BEAMED 266C
+Sixths, Fractions 2159
+SKULL AND CROSSBONES 2620
+slash 002F
+SLASH, CIRCLED DIVISION 2298
+SLASH, DIVISION 2215
+SLASH, DOES NOT DIVIDE WITH REVERSED NEGATION 2AEE
+SLASH, FRACTION 2044
+SLASH, INTEGRAL AVERAGE WITH 2A0F
+SLASH, SQUARED FALLING DIAGONAL 29C5
+SLASH, SQUARED RISING DIAGONAL 29C4
+slash overlay, long 0338
+slash overlay, short 0337
+SLOPE 2333
+SLOPING LARGE AND 2A58
+SLOPING LARGE OR 2A57
+Slovenian and Croatian, Additions for 0200
+SMALL CAPITAL B, LATIN LETTER 0299
+SMALL CAPITAL G, LATIN LETTER 0262
+SMALL CAPITAL H, LATIN LETTER 029C
+SMALL CAPITAL I, LATIN LETTER 026A
+SMALL CAPITAL INVERTED R, LATIN LETTER 0281
+SMALL CAPITAL INVERTED R, MODIFIER LETTER 02B6
+SMALL CAPITAL L, LATIN LETTER 029F
+SMALL CAPITAL N, LATIN LETTER 0274
+SMALL CAPITAL OE, LATIN LETTER 0276
+SMALL CAPITAL R, LATIN LETTER 0280
+SMALL CAPITAL Y, LATIN LETTER 028F
+small circle, black 2022
+SMALL CIRCLE, SQUARED 29C7
+SMALL CIRCLE ABOVE, PLUS SIGN WITH 2A22
+SMALL CIRCLE TO THE RIGHT, CIRCLE WITH 29C2
+SMALL CONTAINS AS MEMBER 220D
+SMALL CONTAINS WITH OVERBAR 22FE
+SMALL CONTAINS WITH VERTICAL BAR AT END OF HORIZONTAL STROKE 22FC
+SMALL D, DOUBLE-STRUCK ITALIC 2146
+SMALL E, DOUBLE-STRUCK ITALIC 2147
+SMALL ELEMENT OF 220A
+SMALL ELEMENT OF WITH OVERBAR 22F7
+SMALL ELEMENT OF WITH VERTICAL BAR AT END OF HORIZONTAL STROKE 22F4
+Small Form Variants FE50
+SMALL GAMMA, DOUBLE-STRUCK 213D
+SMALL I, DOUBLE-STRUCK ITALIC 2148
+SMALL J, DOUBLE-STRUCK ITALIC 2149
+Small Letters, Armenian 0561
+Small Letters, Combining Latin 0363
+Small Letters, Cyrillic 0430
+Small Letters, Georgian 10D0
+Small Letters, Greek 03B1
+Small Letters, Latin 0061
+SMALL SQUARE, BLACK MEDIUM 25FE
+SMALL SQUARE, WHITE MEDIUM 25FD
+SMALL VEE WITH UNDERBAR 2A61
+SMALLER THAN 2AAA
+SMALLER THAN OR EQUAL TO 2AAC
+SMASH PRODUCT 2A33
+SMASH PRODUCT, CLOSED UNION WITH SERIFS AND 2A50
+SMILE 2323
+SMILING FACE, BLACK 263B
+SMILING FACE, WHITE 263A
+smooth breathing 0313
+Snowflake Dingbats 2744
+Snowflakes, Stars, Asterisks and 2721
+SNOWMAN 2603
+snowy weather 2603
+SOFT HYPHEN 00AD
+SOFTWARE-FUNCTION SYMBOL 2394
+solid 2588
+SOLIDUS 002F
+solidus 2044
+SOLIDUS, BIG 29F8
+SOLIDUS, BIG REVERSE 29F9
+SOLIDUS, CIRCLED REVERSE 29B8
+SOLIDUS, REVERSE 005C
+SOLIDUS BINARY RELATION, TRIPLE 2AFB
+SOLIDUS OPERATOR, DOUBLE 2AFD
+SOLIDUS OPERATOR, REVERSE 29F5
+SOLIDUS OVERLAY, COMBINING LONG 0338
+SOLIDUS OVERLAY, COMBINING REVERSE 20E5
+SOLIDUS OVERLAY, COMBINING SHORT 0337
+SOLIDUS WITH HORIZONTAL STROKE, REVERSE 29F7
+SOLIDUS WITH OVERBAR 29F6
+SOUND RECORDING COPYRIGHT 2117
+SOURCE, INFORMATION 2139
+SPACE 0020
+SPACE, EM 2003
+SPACE, EN 2002
+SPACE, FIGURE 2007
+SPACE, FOUR-PER-EM 2005
+space, graphic for 2422
+space, graphic for 2423
+space, graphic for no break 237D
+SPACE, HAIR 200A
+SPACE, IDEOGRAPHIC 3000
+SPACE, MEDIUM MATHEMATICAL 205F
+space, mid 2005
+SPACE, NARROW NO-BREAK 202F
+SPACE, NO-BREAK 00A0
+SPACE, PUNCTUATION 2008
+SPACE, SIX-PER-EM 2006
+SPACE, SYMBOL FOR 2420
+space, thick 2004
+SPACE, THIN 2009
+SPACE, THREE-PER-EM 2004
+SPACE, ZERO WIDTH 200B
+SPACE, ZERO WIDTH NO-BREAK FEFF
+SPACE MARK, OGHAM 1680
+Spaces 2000
+spacing acute 00B4
+spacing cedilla 00B8
+spacing circumflex 005E
+Spacing Clones of Diacritics 02D8
+spacing diaeresis 00A8
+spacing double underscore 2017
+spacing grave 0060
+spacing macron 00AF
+Spacing Modifier Letters 02B0
+spacing overscore 203E
+spacing underscore 005F
+spanish currency 20A7
+Special character extensions 23AE
+Specialized plus sign operators 29FA
+Specials FFF0
+Specials Area, Compatibility and F900
+SPHERICAL ANGLE 2222
+SPHERICAL ANGLE OPENING LEFT 29A0
+SPHERICAL ANGLE OPENING UP 29A1
+SPOT, Z NOTATION 2981
+SQUARE, BLACK MEDIUM 25FC
+SQUARE, BLACK MEDIUM SMALL 25FE
+SQUARE, COMBINING ENCLOSING 20DE
+SQUARE, VIEWDATA 2317
+SQUARE, WHITE MEDIUM 25FB
+SQUARE, WHITE MEDIUM SMALL 25FD
+SQUARE BELOW, COMBINING 033B
+square bracket, closing 005D
+SQUARE BRACKET, LEFT 005B
+SQUARE BRACKET, LEFT WHITE 301A
+square bracket, opening 005B
+SQUARE BRACKET, RIGHT 005D
+SQUARE BRACKET WITH QUILL, LEFT 2045
+SQUARE CAP 2293
+SQUARE CORPORATION 337F
+SQUARE CUP 2294
+SQUARE FOOT 23CD
+SQUARE IMAGE OF 228F
+SQUARE INTERSECTION, DOUBLE 2A4E
+SQUARE INTERSECTION OPERATOR, N-ARY 2A05
+SQUARE LEFT OPEN BOX OPERATOR 2ACD
+SQUARE LOZENGE 2311
+SQUARE ORIGINAL OF 2290
+SQUARE RIGHT OPEN BOX OPERATOR 2ACE
+SQUARE ROOT 221A
+Square Symbols 29C4
+SQUARE UNION, DOUBLE 2A4F
+SQUARE UNION OPERATOR, N-ARY 2A06
+SQUARE WITH CONTOURED OUTLINE 29E0
+SQUARE WITH LEFTWARDS TICK, WHITE 27E4
+SQUARE WITH RIGHTWARDS TICK, WHITE 27E5
+squared 00B2
+SQUARED DOT OPERATOR 22A1
+Squared Japanese Katakana Words 3300
+Squared Latin Abbreviations 3371
+SQUARED MINUS 229F
+SQUARED PLUS 229E
+SQUARED TIMES 22A0
+Squares 25A0
+SQUAT REVERSED ESH, LATIN SMALL LETTER 0285
+st. andrew's cross 2613
+star 002A
+STAR, ARABIC FIVE POINTED 066D
+STAR, BLACK 2605
+STAR AND CRESCENT 262A
+Star Dingbats 2726
+STAR EQUALS 225B
+STAR OF DAVID 2721
+STAR OPERATOR 22C6
+starburst 273A
+STARK, GLEICH 29E6
+Stars, Asterisks and Snowflakes 2721
+start of guarded area 0096
+start of heading 0001
+START OF HEADING, SYMBOL FOR 2401
+start of selected area 0086
+start of string 0098
+start of text 0002
+START OF TEXT, SYMBOL FOR 2402
+statement is true 22A8
+sterling, pound 00A3
+stile, apl 2223
+straight epsilon 220A
+straight epsilon, reversed 220D
+stress mark 0301
+STRETCHED C, LATIN LETTER 0297
+STRICTLY EQUIVALENT TO 2263
+string, device control 0090
+string, start of 0098
+string terminator 009C
+STROKE OVERLAY, COMBINING LONG 0336
+STROKE OVERLAY, COMBINING SHORT 0335
+SUBGROUP, CONTAINS AS NORMAL 22B3
+SUBGROUP OF, NORMAL 22B2
+subscript, iota 0345
+Subscript Digits 2080
+SUBSCRIPT EQUALS SIGN 208C
+SUBSCRIPT LEFT PARENTHESIS 208D
+SUBSCRIPT MINUS 208B
+SUBSCRIPT PLUS SIGN 208A
+SUBSCRIPT TWO, PLUS SIGN WITH 2A27
+Subscripts 2080
+SUBSET, DOUBLE 22D0
+Subset and Superset Relations 2ABD
+SUBSET OF 2282
+substitute 001A
+SUBSTITUTE, SYMBOL FOR 241A
+SUBSTITUTE FORM TWO, SYMBOL FOR 2426
+Subtending Marks, Arabic 0600
+subtraction, z notation bag 2A41
+SUCCEEDS 227B
+SUCCEEDS, DOUBLE 2ABC
+SUCCEEDS ABOVE ALMOST EQUAL TO 2AB8
+SUCCEEDS ABOVE EQUALS SIGN 2AB4
+SUCCEEDS ABOVE NOT ALMOST EQUAL TO 2ABA
+SUCCEEDS ABOVE NOT EQUAL TO 2AB6
+SUCCEEDS ABOVE SINGLE-LINE EQUALS SIGN 2AB0
+SUCCEEDS ABOVE SINGLE-LINE NOT EQUAL TO 2AB2
+SUCCEEDS UNDER RELATION 22B1
+such that 220B
+such that 2223
+Suits, Playing Card 2660
+sum, direct 2295
+SUM, MODULO TWO 2A0A
+sum, positive difference or 2A24
+sum or positive difference 2A26
+SUMMATION, DOUBLE-STRUCK N-ARY 2140
+SUMMATION, N-ARY 2211
+SUMMATION BOTTOM 23B3
+Summation Sign Parts 23B2
+SUMMATION TOP 23B2
+Summations and Integrals 2A0A
+SUN 2609
+SUN WITH RAYS, BLACK 2600
+SUPERIMPOSED X, CIRCLE WITH 29BB
+SUPERSCRIPT ALEF, ARABIC LETTER 0670
+Superscript Digits 2070
+SUPERSCRIPT EQUALS SIGN 207C
+SUPERSCRIPT LATIN SMALL LETTER I 2071
+SUPERSCRIPT LEFT PARENTHESIS 207D
+Superscript Letter Diacritics, Medieval 0363
+SUPERSCRIPT MINUS 207B
+SUPERSCRIPT ONE 00B9
+SUPERSCRIPT PLUS SIGN 207A
+SUPERSCRIPT THREE 00B3
+SUPERSCRIPT TWO 00B2
+SUPERSCRIPT ZERO 2070
+Superscripts 2070
+Superscripts and Subscripts 2070
+SUPERSET, DOUBLE 22D1
+SUPERSET OF 2283
+Superset Relations, Subset and 2ABD
+Supplemental Arrows-A 27F0
+Supplemental Arrows-B 2900
+Supplemental Mathematical Operators 2A00
+Supplementary, Cyrillic 0500
+Supplementary Private Use Area-A F0000
+Supplementary Private Use Area-B 100000
+SURFACE INTEGRAL 222F
+surjection, z notation finite 2901
+surjection, z notation partial 2900
+surjective injection, z notation 2917
+surjective injection, z notation finite 2918
+Surrogates, High D800
+Surrogates, Low DC00
+Surrogates Area D800
+swedish grave accent 02DF
+SWUNG DASH 2053
+Syllabics, Unified Canadian Aboriginal 1400
+Syllables, Yi A000
+Syllables Area, Korean Hangul AC00
+Symbol Variants, Fullwidth FFE0
+Symbols, Bowtie 29D1
+Symbols, Circle 29B5
+Symbols, Combining Diacritical Marks for 20D0
+Symbols, Dentistry Notation 23BE
+Symbols, Double-Struck Italic Mathematical 2145
+Symbols, Error Bar 29EE
+Symbols, Greek 03D0
+Symbols, Japanese Chess 2616
+Symbols, Letterlike 2100
+Symbols, Miscellaneous 2600
+Symbols, Recycling 2672
+Symbols, Square 29C4
+Symbols, Triangle 29CA
+Symbols and Arrows, Miscellaneous 2B00
+Symbols and Punctuation, CJK 3000
+Symbols Area 2000
+Symbols Area, CJK Phonetics and 2E00
+Symbols for Control Codes, Graphic 2400
+Symbols For Plastics, Recycling 2673
+Symbols-A, Miscellaneous Mathematical 27C0
+Symbols-B, Miscellaneous Mathematical 2980
+symmetric difference 2238
+symmetric difference 2296
+SYMMETRIC SWAPPING, ACTIVATE 206B
+SYMMETRIC SWAPPING, INHIBIT 206A
+SYMMETRY 232F
+synchronous idle 0016
+SYNCHRONOUS IDLE, SYMBOL FOR 2416
+Syriac 0700
+SYRIAC ABBREVIATION MARK 070F
+SYRIAC CROSS, EAST 2671
+SYRIAC CROSS, WEST 2670
+Syriac Format Control 070F
+T, COMBINING LATIN SMALL LETTER 036D
+T, LATIN SMALL LETTER TURNED 0287
+tab 0009
+tab, leftward 21E4
+tab, rightward 21E5
+tab, symbol for 2409
+tab with shift tab 21B9
+tabulation, horizontal 0009
+TABULATION, SYMBOL FOR HORIZONTAL 2409
+TABULATION, SYMBOL FOR VERTICAL 240B
+tabulation, vertical 000B
+tabulation set, character 0088
+tabulation set, line 008A
+tabulation with justification, character 0089
+TACK, LEFT 22A3
+TACK, MODIFIER LETTER UP 02D4
+TACK, RIGHT 22A2
+TACK, UP 22A5
+TACK BELOW, COMBINING LEFT 0318
+TACK BELOW, COMBINING UP 031D
+Tacks and Turnstiles 27D8
+Tacks and Turnstiles 2ADE
+Tagalog 1700
+TAGALOG SIGN VIRAMA 1714
+Tagbanwa 1760
+Tai Le 1950
+Tai Xuan Jing Symbols 1D300
+TAIL FRAGMENT, ARABIC FE73
+Tails, Fish 297C
+tainome (japanese, a kind of bullet) 25C9
+TAKE, PRESCRIPTION 211E
+Tamil 0B80
+Tamil Digits 0BE7
+Tamil Letters 0B85
+TAMIL RUPEE SIGN 0BF9
+TAMIL NUMBER SIGN 0BFA
+Tamil Symbols 0BF3
+TAPE DRIVE 2707
+TAPER, CONICAL 2332
+TAURUS 2649
+tautological equivalent 29E6
+tautology 22A8
+tea 2615
+Technical, Miscellaneous 2300
+TEE TOP, PITCHFORK WITH 2ADA
+Telegraph Symbols for Days 33E0
+Telegraph Symbols for Hours 3358
+Telegraph Symbols for Months 32C0
+TELEPHONE, BLACK 260E
+TELEPHONE LOCATION SIGN 2706
+TELEPHONE RECORDER 2315
+TELEPHONE SIGN 2121
+Telugu 0C00
+Telugu Digits 0C66
+Telugu Letters 0C05
+TEN THOUSAND SIGN, PER 2031
+tensor 20E1
+tensor product 2297
+Terminal graphic characters 23B7
+Terminal Graphic Characters 2596
+Terminal Graphics, Scan Lines For 23BA
+terminator, string 009C
+Tetragram Symbols, Tai Xuan Jing 1D306
+text, end of 0003
+text, start of 0002
+TEXT, SYMBOL FOR END OF 2403
+TEXT, SYMBOL FOR START OF 2402
+Thaana 0780
+Thai 0E00
+THAI CURRENCY SYMBOL BAHT 0E3F
+Thai Digits 0E50
+Thai Letters 0E01
+THERE EXISTS 2203
+THEREFORE 2234
+THERMODYNAMIC 29E7
+thick space 2004
+THIN SPACE 2009
+third derivative 20DB
+third transfinite cardinal (functions of a real variable) 2137
+Thirds, Fractions 2153
+THORN, LATIN CAPITAL LETTER 00DE
+THORN, LATIN SMALL LETTER 00FE
+THOUSANDS SEPARATOR, ARABIC 066C
+THOUSANDS SIGN, CYRILLIC 0482
+THREE, SUPERSCRIPT 00B3
+three dot leader 2026
+THREE DOTS ABOVE, COMBINING 20DB
+THREE QUARTERS, VULGAR FRACTION 00BE
+THREE-PER-EM SPACE 2004
+THUNDERSTORM 2608
+Tibetan 0F00
+Tibetan, Mongolian Extensions for Sanskrit and 1880
+Tibetan Digits 0F20
+Tibetan Letters 0F40
+TICK, WHITE CONCAVE-SIDED DIAMOND WITH LEFTWARDS 27E2
+TICK, WHITE CONCAVE-SIDED DIAMOND WITH RIGHTWARDS 27E3
+TICK, WHITE SQUARE WITH LEFTWARDS 27E4
+TICK, WHITE SQUARE WITH RIGHTWARDS 27E5
+TIE, CHARACTER 2040
+tie, ligature 0361
+TIE OVER INFINITY 29DD
+TILDE 007E
+tilde, apl 223C
+TILDE, COMBINING 0303
+TILDE, COMBINING DOUBLE 0360
+TILDE, COMBINING VERTICAL 033E
+TILDE, MINUS 2242
+TILDE, REVERSED 223D
+TILDE, SMALL 02DC
+TILDE, TRIPLE 224B
+TILDE ABOVE, COMBINING NOT 034A
+TILDE BELOW, COMBINING 0330
+TILDE EQUALS, REVERSED 22CD
+TILDE LEFT HALF, COMBINING DOUBLE FE22
+TILDE OPERATOR 223C
+TILDE OPERATOR, EQUALS SIGN ABOVE 2A73
+TILDE OPERATOR, PARALLEL WITH 2AF3
+TILDE OPERATOR, SUBSET OF ABOVE 2AC7
+TILDE OPERATOR, SUPERSET OF ABOVE 2AC8
+TILDE OPERATOR WITH DOT ABOVE 2A6A
+TILDE OPERATOR WITH RISING DOTS 2A6B
+TILDE OVERLAY, COMBINING 0334
+TIMES, CIRCLED 2297
+TIMES, DIVISION 22C7
+TIMES, INVISIBLE 2062
+TIMES, SQUARED 22A0
+TIMES OPERATOR, N-ARY 2A09
+TIMES OPERATOR, N-ARY CIRCLED 2A02
+TIMES SIGN, INTEGRAL WITH 2A18
+TIMES WITH LEFT HALF BLACK 29D4
+TIMES WITH RIGHT HALF BLACK 29D5
+TINY 29FE
+TIRONIAN SIGN ET 204A
+TIS 620-2529 (Thai), Based on 0E01
+Todo Letters, Mongolian 1843
+Tone Bar Letters 02E5
+TONE FIVE, LATIN SMALL LETTER 01BD
+TONE MARK, COMBINING ACUTE 0341
+TONE MARK, COMBINING GRAVE 0340
+Tone Marks, Ideographic 302A
+Tone Marks, Vietnamese 0340
+TONE SIX, LATIN SMALL LETTER 0185
+TONE TWO, LATIN SMALL LETTER 01A8
+tonos 0301
+TONOS, COMBINING GREEK DIALYTIKA 0344
+TOP HALF INTEGRAL 2320
+TOP LEFT CORNER 231C
+TOP LEFT CROP 230F
+TORTOISE SHELL BRACKET, LEFT 3014
+TORTOISE SHELL BRACKET, LEFT WHITE 3018
+TOTAL RUNOUT 2330
+TRADE MARK SIGN 2122
+trade mark sign, registered 00AE
+transfinite cardinal, fourth 2138
+transfinite cardinal (countable), first 2135
+transfinite cardinal (functions of a real variable), third 2137
+transfinite cardinal (the continuum), second 2136
+transmission, end of 0004
+transmission, graphic for end of 2301
+TRANSMISSION, SYMBOL FOR END OF 2404
+transmission block, end of 0017
+TRANSMISSION BLOCK, SYMBOL FOR END OF 2417
+transmit state, set 0093
+TRANSVERSAL INTERSECTION 2ADB
+TRIANGLE, COMBINING ENCLOSING UPWARD POINTING 20E4
+TRIANGLE, LOWER LEFT 25FA
+TRIANGLE, LOWER RIGHT 25FF
+TRIANGLE, MINUS SIGN IN 2A3A
+TRIANGLE, MULTIPLICATION SIGN IN 2A3B
+TRIANGLE, PLUS SIGN IN 2A39
+TRIANGLE, PLUS SIGN WITH BLACK 2A28
+TRIANGLE, RIGHT 22BF
+TRIANGLE, UPPER LEFT 25F8
+TRIANGLE, UPPER RIGHT 25F9
+TRIANGLE, VERTICAL BAR BESIDE RIGHT 29D0
+TRIANGLE OPERATOR, LARGE LEFT 2A1E
+Triangle symbols 29CA
+TRIANGLE WITH LEFT HALF BLACK, DOWN-POINTING 29E8
+TRIANGLE WITH RIGHT HALF BLACK, DOWN-POINTING 29E9
+Triangles 25B2
+TRIANGULAR BULLET 2023
+TRIANGULAR COLON, MODIFIER LETTER 02D0
+TRIANGULAR COLON, MODIFIER LETTER HALF 02D1
+Trigram Symbols, Yijing 2630
+trine 25B3
+TRIPLE COLON OPERATOR 2AF6
+TRIPLE HORIZONTAL BAR WITH DOUBLE VERTICAL STROKE 2A68
+TRIPLE HORIZONTAL BAR WITH TRIPLE VERTICAL STROKE 2A69
+TRIPLE INTEGRAL 222D
+TRIPLE NESTED GREATER-THAN 2AF8
+TRIPLE NESTED LESS-THAN 2AF7
+TRIPLE PLUS 29FB
+TRIPLE PRIME 2034
+TRIPLE PRIME, REVERSED 2037
+TRIPLE RIGHT TURNSTILE, VERTICAL BAR 2AE2
+TRIPLE SOLIDUS BINARY RELATION 2AFB
+TRIPLE TILDE 224B
+TRIPLE UNDERDOT, COMBINING 20E8
+TRIPLE VERTICAL BAR BINARY RELATION 2AF4
+TRIPLE VERTICAL BAR DELIMITER 2980
+TRIPLE VERTICAL BAR OPERATOR, LARGE 2AFC
+TRIPLE VERTICAL BAR WITH HORIZONTAL STROKE 2AF5
+TRIPLE VERTICAL STROKE, TRIPLE HORIZONTAL BAR WITH 2A69
+TRUE 22A8
+TUGRIK SIGN 20AE
+turbofan 274B
+turkish currency 20A4
+TURNED A, LATIN SMALL LETTER 0250
+TURNED ALPHA, LATIN SMALL LETTER 0252
+TURNED AMPERSAND 214B
+TURNED ANGLE 29A2
+TURNED CAPITAL F 2132
+TURNED COMMA, MODIFIER LETTER 02BB
+TURNED COMMA ABOVE, COMBINING 0312
+turned comma quotation mark, double 201C
+turned comma quotation mark, single 2018
+TURNED DELTA, LATIN SMALL LETTER 018D
+turned e, latin capital letter 018E
+TURNED E, LATIN SMALL LETTER 01DD
+TURNED GREEK SMALL LETTER IOTA 2129
+TURNED H, LATIN SMALL LETTER 0265
+TURNED K, LATIN SMALL LETTER 029E
+TURNED M, LATIN CAPITAL LETTER 019C
+TURNED M, LATIN SMALL LETTER 026F
+TURNED NOT SIGN 2319
+turned question mark 00BF
+TURNED R, LATIN SMALL LETTER 0279
+TURNED R, MODIFIER LETTER SMALL 02B4
+TURNED SANS-SERIF CAPITAL G 2141
+TURNED SANS-SERIF CAPITAL L 2142
+TURNED SANS-SERIF CAPITAL Y 2144
+TURNED T, LATIN SMALL LETTER 0287
+TURNED V, LATIN SMALL LETTER 028C
+TURNED W, LATIN SMALL LETTER 028D
+TURNED Y, LATIN SMALL LETTER 028E
+turnstile 22A2
+turnstile, reverse 22A3
+Turnstiles, Tacks and 27D8
+Turnstiles, Tacks and 2ADE
+TWO, SUPERSCRIPT 00B2
+TWO DOT LEADER 2025
+TWO-HEADED ARROW FROM BAR, RIGHTWARDS 2905
+TWO-HEADED ARROW WITH TAIL, RIGHTWARDS 2916
+TWO-HEADED ARROW WITH TAIL WITH VERTICAL STROKE, RIGHTWARDS 2917
+TYPE COLON, Z NOTATION 2982
+U, COMBINING LATIN SMALL LETTER 0367
+Ugaritic 10380
+UMBRELLA 2602
+UMBRELLA WITH RAIN DROPS 2614
+umlaut 0308
+UNASPIRATED, MODIFIER LETTER 02ED
+UNDERDOT, COMBINING TRIPLE 20E8
+underline 0332
+underline, double 0333
+UNDERLINE SYMBOL, CONTINUOUS 2381
+UNDERLINE SYMBOL, DISCONTINUOUS 2382
+underscore 0332
+underscore, double 0333
+underscore, spacing 005F
+underscore, spacing double 2017
+Underscores, Overscores and FE49
+UNDERTIE 203F
+UNDERTIE, INVERTED 2054
+UNDO SYMBOL 238C
+undoable delete 2425
+UNION 222A
+UNION, DOUBLE 22D3
+UNION, DOUBLE SQUARE 2A4F
+UNION, INTEGRAL WITH 2A1A
+UNION, INTERSECTION ABOVE 2A47
+UNION, INTERSECTION ABOVE BAR ABOVE 2A49
+UNION, MULTISET 228E
+UNION, N-ARY 22C3
+UNION, UNION BESIDE AND JOINED WITH 2A4A
+UNION ABOVE BAR ABOVE INTERSECTION 2A48
+UNION ABOVE INTERSECTION 2A46
+UNION BESIDE AND JOINED WITH UNION 2A4A
+UNION OPERATOR, N-ARY SQUARE 2A06
+UNION OPERATOR WITH DOT, N-ARY 2A03
+UNION OPERATOR WITH PLUS, N-ARY 2A04
+UNION WITH LOGICAL OR 2A45
+UNION WITH MINUS SIGN 2A41
+UNION WITH OVERBAR 2A42
+UNION WITH SERIFS, CLOSED 2A4C
+UNION WITH SERIFS AND SMASH PRODUCT, CLOSED 2A50
+Unions, Intersections and 2A40
+unique element 2129
+unit separator 001F
+UNIT SEPARATOR, SYMBOL FOR 241F
+UNIVERSAL RECYCLING SYMBOL 2672
+UNIVERSAL RECYCLING SYMBOL, BLACK 267B
+up, page 21DE
+UP ARROWHEAD 2303
+UP ARROWHEAD BETWEEN TWO HORIZONTAL BARS 2324
+UP RIGHT DIAGONAL ELLIPSIS 22F0
+UP TACK 22A5
+UP TACK, MODIFIER LETTER 02D4
+UP TACK BELOW, COMBINING 031D
+UPA Modifiers 02EF
+UPPER BLADE SCISSORS 2701
+UPPER RIGHT PENCIL 2710
+UPSILON, LATIN CAPITAL LETTER 01B1
+UPSILON, LATIN SMALL LETTER 028A
+upstile, apl 2308
+UPWARDS ARROW BELOW, COMBINING 034E
+URANUS 2645
+Urdu, Eastern Arabic-Indic Digits for Persian and 06F0
+urdu paragraph separator 203B
+V, COMBINING LATIN SMALL LETTER 036E
+v, latin capital letter script 01B2
+v, latin small letter script 028B
+V, LATIN SMALL LETTER TURNED 028C
+V WITH HOOK, LATIN CAPITAL LETTER 01B2
+valentine 2665
+valid 22A8
+varia 0300
+Variation Selectors FE00
+Variation Selectors Supplement E0100
+varies with (proportional to) 223C
+vector 20D0
+vector 20D6
+VECTOR OR CROSS PRODUCT 2A2F
+vector pointing into page 2295
+vector pointing into page 2297
+vector pointing out of page 2299
+vee 2228
+vee above 030C
+VEE WITH UNDERBAR, SMALL 2A61
+venus 2640
+VERSICLE 2123
+VERTICAL, LONG DASH FROM LEFT MEMBER OF DOUBLE 2AE6
+vertical bar 007C
+vertical bar, broken 00A6
+VERTICAL BAR, CIRCLED 29B6
+VERTICAL BAR, N-ARY WHITE 2AFF
+VERTICAL BAR, WHITE 2AFE
+VERTICAL BAR BINARY RELATION, TRIPLE 2AF4
+VERTICAL BAR DELIMITER, TRIPLE 2980
+Vertical Bar Dingbats 2758
+VERTICAL BAR OPERATOR, LARGE TRIPLE 2AFC
+VERTICAL BAR WITH HORIZONTAL STROKE, TRIPLE 2AF5
+vertical bowtie 29D6
+VERTICAL BOX LINE, LEFT 23B8
+VERTICAL BOX LINE, RIGHT 23B9
+Vertical brackets 23B4
+VERTICAL ELLIPSIS 22EE
+VERTICAL IDEOGRAPHIC ITERATION MARK 303B
+VERTICAL KANA REPEAT MARK 3031
+VERTICAL LINE 007C
+VERTICAL LINE, DOUBLE 2016
+VERTICAL LINE, MODIFIER LETTER 02C8
+VERTICAL LINE, MODIFIER LETTER LOW 02CC
+VERTICAL LINE ABOVE, COMBINING 030D
+VERTICAL LINE ABOVE, COMBINING DOUBLE 030E
+VERTICAL LINE BELOW, COMBINING 0329
+VERTICAL LINE BELOW, COMBINING DOUBLE 0348
+VERTICAL LINE EXTENSION 23D0
+Vertical Line Operators 2AEE
+VERTICAL LINE OVERLAY, COMBINING LONG 20D2
+VERTICAL LINE OVERLAY, COMBINING SHORT 20D3
+VERTICAL LINE WITH CIRCLE ABOVE 2AEF
+VERTICAL LINE WITH CIRCLE BELOW 2AF0
+VERTICAL LINE WITH MIDDLE DOT 237F
+VERTICAL STROKE OVERLAY, COMBINING DOUBLE 20E6
+vertical tabulation 000B
+VERTICAL TABULATION, SYMBOL FOR 240B
+Vertical Text, Double Punctuation For 2047
+VERTICAL TILDE, COMBINING 033E
+Vertical Variants, Glyphs for FE30
+VERTICAL ZIGZAG LINE 299A
+VERY MUCH GREATER-THAN 22D9
+VERY MUCH LESS-THAN 22D8
+VICTORY HAND 270C
+Vietnamese, Latin Extensions for 1EA0
+vietnamese currency 20AB
+Vietnamese Tone Marks 0340
+VIEWDATA SQUARE 2317
+vinculum 0305
+viram, deergh 0965
+viram, purna 0964
+VIRAMA, BENGALI SIGN 09CD
+VIRAMA, DEVANAGARI SIGN 094D
+VIRAMA, GUJARATI SIGN 0ACD
+VIRAMA, GURMUKHI SIGN 0A4D
+VIRAMA, KANNADA SIGN 0CCD
+VIRAMA, MALAYALAM SIGN 0D4D
+VIRAMA, ORIYA SIGN 0B4D
+VIRAMA, TAGALOG SIGN 1714
+VIRAMA, TAMIL SIGN 0BCD
+VIRAMA, TELUGU SIGN 0C4D
+VIRGO 264D
+virgule 002F
+VOICED FRICATIVE, LATIN LETTER PHARYNGEAL 0295
+VOICED SOUND MARK, COMBINING KATAKANA-HIRAGANA 3099
+VOICED SOUND MARK, KATAKANA-HIRAGANA 309B
+VOICING, MODIFIER LETTER 02EC
+VOLUME INTEGRAL 2230
+VOLTAGE SIGN, HIGH 26A1
+vrachy 0306
+VS1 FE00
+W, LATIN SMALL LETTER TURNED 028D
+W, MODIFIER LETTER SMALL 02B7
+WARNING SIGN 26A0
+Warning Signs 2620
+Warning Signs 26A0
+WATCH 231A
+WAVE, SINE 223F
+WAVE DASH 301C
+WAVY DASH 3030
+WAVY LINE 2307
+WAVY LOW LINE FE4F
+WAVY OVERLINE FE4B
+WAVY OVERLINE, DOUBLE FE4C
+Weather and Astrological Symbols 2600
+wedge 028C
+wedge 2227
+weierstrass elliptic function 2118
+WHEEL OF DHARMA 2638
+WHITE BULLET, CIRCLED 29BE
+WHITE CIRCLE WITH DOT RIGHT 2686
+WHITE CIRCLE WITH DOWN ARROW 29EC
+WHITE CIRCLE WITH TWO DOTS 2687
+WHITE CONCAVE-SIDED DIAMOND 27E1
+WHITE CONCAVE-SIDED DIAMOND WITH LEFTWARDS TICK 27E2
+WHITE CONCAVE-SIDED DIAMOND WITH RIGHTWARDS TICK 27E3
+WHITE DIAMOND WITH CENTRED DOT 27D0
+WHITE DOT RIGHT, BLACK CIRCLE WITH 2688
+WHITE DOTS, BLACK CIRCLE WITH TWO 2689
+WHITE FLAG 2690
+white framus 29D6
+WHITE HOURGLASS 29D6
+WHITE MEDIUM SMALL SQUARE 25FD
+WHITE MEDIUM SQUARE 25FB
+White On Black Circled Numbers 24EB
+WHITE SESAME DOT FE46
+WHITE SHOGI PIECE 2616
+WHITE SQUARE WITH LEFTWARDS TICK 27E4
+WHITE SQUARE WITH RIGHTWARDS TICK 27E5
+WHITE VERTICAL BAR 2AFE
+WHITE VERTICAL BAR, N-ARY 2AFF
+WIDE BRIDGE ABOVE, COMBINING 20E9
+WIGGLY FENCE, LEFT 29D8
+WIGGLY FENCE, LEFT DOUBLE 29DA
+WIGGLY FENCE, RIGHT 29D9
+WIGGLY FENCE, RIGHT DOUBLE 29DB
+wj 2060
+WON SIGN 20A9
+WORD DIVIDER, UGARITIC 1039F
+WORD JOINER 2060
+Word Separators, Aegean 10100
+Words, Squared Japanese Katakana 3300
+WORDSPACE, ETHIOPIC 1361
+WREATH PRODUCT 2240
+WRITING HAND 270D
+WYNN, LATIN CAPITAL LETTER 01F7
+WYNN, LATIN LETTER 01BF
+X, BALLOT 2717
+X, BALLOT BOX WITH 2612
+X, CIRCLE WITH SUPERIMPOSED 29BB
+X, COMBINING LATIN SMALL LETTER 036F
+X, HEAVY BALLOT 2718
+X, HEAVY MULTIPLICATION 2716
+X, MODIFIER LETTER SMALL 02E3
+X, MULTIPLICATION 2715
+X ABOVE, COMBINING 033D
+X IN A RECTANGLE BOX 2327
+XOR 22BB
+Y, LATIN LETTER SMALL CAPITAL 028F
+Y, LATIN SMALL LETTER TURNED 028E
+Y, MODIFIER LETTER SMALL 02B8
+Y, TURNED SANS-SERIF CAPITAL 2144
+YANG, YIN 262F
+YEN SIGN 00A5
+Yi Radicals A490
+Yi Syllables A000
+Yiddish Digraphs 05F0
+yields 22A2
+Yijing Monogram and Digram Symbols 268A
+Yijing Hexagram Symbols 4DC0
+Yijing Trigram Symbols 2630
+YIN YANG 262F
+yogh, latin capital letter 01B7
+YOGH, LATIN SMALL LETTER 021D
+yogh, latin small letter 0292
+YPOGEGRAMMENI, COMBINING GREEK 0345
+YR, LATIN LETTER 01A6
+yuan sign 00A5
+Z, BLACK-LETTER CAPITAL 2128
+Z, DOUBLE-STRUCK CAPITAL 2124
+Z NOTATION BAG MEMBERSHIP 22FF
+z notation bag subtraction 2A41
+z notation bijection 2917
+Z Notation Binding Brackets 2989
+Z NOTATION DOMAIN ANTIRESTRICTION 2A64
+z notation finite function 20E6
+z notation finite function 21FB
+z notation finite injection 2915
+z notation finite relation 21FC
+z notation finite surjection 2901
+z notation finite surjective injection 2918
+Z Notation Image Brackets 2987
+z notation left bag bracket 27E6
+z notation partial function 21F8
+z notation partial injection 2914
+z notation partial relation 21F9
+z notation partial surjection 2900
+Z NOTATION RANGE ANTIRESTRICTION 2A65
+Z NOTATION RELATIONAL COMPOSITION 2A3E
+Z NOTATION SCHEMA COMPOSITION 2A1F
+z notation schema hiding 29F9
+Z NOTATION SCHEMA PIPING 2A20
+Z NOTATION SCHEMA PROJECTION 2A21
+z notations sequence concatenation 2040
+Z NOTATION SPOT 2981
+z notation surjective injection 2917
+Z NOTATION TYPE COLON 2982
+Zapf Dingbats Series 100, ITC 2700
+ZERO, CIRCLED DIGIT 24EA
+ZERO, IDEOGRAPHIC NUMBER 3007
+ZERO, SUPERSCRIPT 2070
+ZERO WIDTH JOINER 200D
+ZERO WIDTH NO-BREAK SPACE FEFF
+ZERO WIDTH NON-JOINER 200C
+ZERO WIDTH SPACE 200B
+ZIGZAG ARROW, RIGHT ANGLE WITH DOWNWARDS 237C
+ZIGZAG LINE, VERTICAL 299A
+Zodiacal Symbols 2648
+zwj 200D
+zwnbsp FEFF
+zwnj 200C
+zwsp 200B
+
--- /dev/null
+++ b/lib/unidata/unidata2.txt
@@ -1,0 +1,16351 @@
+0000;<control>;Cc;0;BN;;;;;N;NULL;;;;
+0001;<control>;Cc;0;BN;;;;;N;START OF HEADING;;;;
+0002;<control>;Cc;0;BN;;;;;N;START OF TEXT;;;;
+0003;<control>;Cc;0;BN;;;;;N;END OF TEXT;;;;
+0004;<control>;Cc;0;BN;;;;;N;END OF TRANSMISSION;;;;
+0005;<control>;Cc;0;BN;;;;;N;ENQUIRY;;;;
+0006;<control>;Cc;0;BN;;;;;N;ACKNOWLEDGE;;;;
+0007;<control>;Cc;0;BN;;;;;N;BELL;;;;
+0008;<control>;Cc;0;BN;;;;;N;BACKSPACE;;;;
+0009;<control>;Cc;0;S;;;;;N;CHARACTER TABULATION;;;;
+000A;<control>;Cc;0;B;;;;;N;LINE FEED (LF);;;;
+000B;<control>;Cc;0;S;;;;;N;LINE TABULATION;;;;
+000C;<control>;Cc;0;WS;;;;;N;FORM FEED (FF);;;;
+000D;<control>;Cc;0;B;;;;;N;CARRIAGE RETURN (CR);;;;
+000E;<control>;Cc;0;BN;;;;;N;SHIFT OUT;;;;
+000F;<control>;Cc;0;BN;;;;;N;SHIFT IN;;;;
+0010;<control>;Cc;0;BN;;;;;N;DATA LINK ESCAPE;;;;
+0011;<control>;Cc;0;BN;;;;;N;DEVICE CONTROL ONE;;;;
+0012;<control>;Cc;0;BN;;;;;N;DEVICE CONTROL TWO;;;;
+0013;<control>;Cc;0;BN;;;;;N;DEVICE CONTROL THREE;;;;
+0014;<control>;Cc;0;BN;;;;;N;DEVICE CONTROL FOUR;;;;
+0015;<control>;Cc;0;BN;;;;;N;NEGATIVE ACKNOWLEDGE;;;;
+0016;<control>;Cc;0;BN;;;;;N;SYNCHRONOUS IDLE;;;;
+0017;<control>;Cc;0;BN;;;;;N;END OF TRANSMISSION BLOCK;;;;
+0018;<control>;Cc;0;BN;;;;;N;CANCEL;;;;
+0019;<control>;Cc;0;BN;;;;;N;END OF MEDIUM;;;;
+001A;<control>;Cc;0;BN;;;;;N;SUBSTITUTE;;;;
+001B;<control>;Cc;0;BN;;;;;N;ESCAPE;;;;
+001C;<control>;Cc;0;B;;;;;N;INFORMATION SEPARATOR FOUR;;;;
+001D;<control>;Cc;0;B;;;;;N;INFORMATION SEPARATOR THREE;;;;
+001E;<control>;Cc;0;B;;;;;N;INFORMATION SEPARATOR TWO;;;;
+001F;<control>;Cc;0;S;;;;;N;INFORMATION SEPARATOR ONE;;;;
+0020;SPACE;Zs;0;WS;;;;;N;;;;;
+0021;EXCLAMATION MARK;Po;0;ON;;;;;N;;;;;
+0022;QUOTATION MARK;Po;0;ON;;;;;N;;;;;
+0023;NUMBER SIGN;Po;0;ET;;;;;N;;;;;
+0024;DOLLAR SIGN;Sc;0;ET;;;;;N;;;;;
+0025;PERCENT SIGN;Po;0;ET;;;;;N;;;;;
+0026;AMPERSAND;Po;0;ON;;;;;N;;;;;
+0027;APOSTROPHE;Po;0;ON;;;;;N;APOSTROPHE-QUOTE;;;;
+0028;LEFT PARENTHESIS;Ps;0;ON;;;;;Y;OPENING PARENTHESIS;;;;
+0029;RIGHT PARENTHESIS;Pe;0;ON;;;;;Y;CLOSING PARENTHESIS;;;;
+002A;ASTERISK;Po;0;ON;;;;;N;;;;;
+002B;PLUS SIGN;Sm;0;ES;;;;;N;;;;;
+002C;COMMA;Po;0;CS;;;;;N;;;;;
+002D;HYPHEN-MINUS;Pd;0;ES;;;;;N;;;;;
+002E;FULL STOP;Po;0;CS;;;;;N;PERIOD;;;;
+002F;SOLIDUS;Po;0;CS;;;;;N;SLASH;;;;
+0030;DIGIT ZERO;Nd;0;EN;;0;0;0;N;;;;;
+0031;DIGIT ONE;Nd;0;EN;;1;1;1;N;;;;;
+0032;DIGIT TWO;Nd;0;EN;;2;2;2;N;;;;;
+0033;DIGIT THREE;Nd;0;EN;;3;3;3;N;;;;;
+0034;DIGIT FOUR;Nd;0;EN;;4;4;4;N;;;;;
+0035;DIGIT FIVE;Nd;0;EN;;5;5;5;N;;;;;
+0036;DIGIT SIX;Nd;0;EN;;6;6;6;N;;;;;
+0037;DIGIT SEVEN;Nd;0;EN;;7;7;7;N;;;;;
+0038;DIGIT EIGHT;Nd;0;EN;;8;8;8;N;;;;;
+0039;DIGIT NINE;Nd;0;EN;;9;9;9;N;;;;;
+003A;COLON;Po;0;CS;;;;;N;;;;;
+003B;SEMICOLON;Po;0;ON;;;;;N;;;;;
+003C;LESS-THAN SIGN;Sm;0;ON;;;;;Y;;;;;
+003D;EQUALS SIGN;Sm;0;ON;;;;;N;;;;;
+003E;GREATER-THAN SIGN;Sm;0;ON;;;;;Y;;;;;
+003F;QUESTION MARK;Po;0;ON;;;;;N;;;;;
+0040;COMMERCIAL AT;Po;0;ON;;;;;N;;;;;
+0041;LATIN CAPITAL LETTER A;Lu;0;L;;;;;N;;;;0061;
+0042;LATIN CAPITAL LETTER B;Lu;0;L;;;;;N;;;;0062;
+0043;LATIN CAPITAL LETTER C;Lu;0;L;;;;;N;;;;0063;
+0044;LATIN CAPITAL LETTER D;Lu;0;L;;;;;N;;;;0064;
+0045;LATIN CAPITAL LETTER E;Lu;0;L;;;;;N;;;;0065;
+0046;LATIN CAPITAL LETTER F;Lu;0;L;;;;;N;;;;0066;
+0047;LATIN CAPITAL LETTER G;Lu;0;L;;;;;N;;;;0067;
+0048;LATIN CAPITAL LETTER H;Lu;0;L;;;;;N;;;;0068;
+0049;LATIN CAPITAL LETTER I;Lu;0;L;;;;;N;;;;0069;
+004A;LATIN CAPITAL LETTER J;Lu;0;L;;;;;N;;;;006A;
+004B;LATIN CAPITAL LETTER K;Lu;0;L;;;;;N;;;;006B;
+004C;LATIN CAPITAL LETTER L;Lu;0;L;;;;;N;;;;006C;
+004D;LATIN CAPITAL LETTER M;Lu;0;L;;;;;N;;;;006D;
+004E;LATIN CAPITAL LETTER N;Lu;0;L;;;;;N;;;;006E;
+004F;LATIN CAPITAL LETTER O;Lu;0;L;;;;;N;;;;006F;
+0050;LATIN CAPITAL LETTER P;Lu;0;L;;;;;N;;;;0070;
+0051;LATIN CAPITAL LETTER Q;Lu;0;L;;;;;N;;;;0071;
+0052;LATIN CAPITAL LETTER R;Lu;0;L;;;;;N;;;;0072;
+0053;LATIN CAPITAL LETTER S;Lu;0;L;;;;;N;;;;0073;
+0054;LATIN CAPITAL LETTER T;Lu;0;L;;;;;N;;;;0074;
+0055;LATIN CAPITAL LETTER U;Lu;0;L;;;;;N;;;;0075;
+0056;LATIN CAPITAL LETTER V;Lu;0;L;;;;;N;;;;0076;
+0057;LATIN CAPITAL LETTER W;Lu;0;L;;;;;N;;;;0077;
+0058;LATIN CAPITAL LETTER X;Lu;0;L;;;;;N;;;;0078;
+0059;LATIN CAPITAL LETTER Y;Lu;0;L;;;;;N;;;;0079;
+005A;LATIN CAPITAL LETTER Z;Lu;0;L;;;;;N;;;;007A;
+005B;LEFT SQUARE BRACKET;Ps;0;ON;;;;;Y;OPENING SQUARE BRACKET;;;;
+005C;REVERSE SOLIDUS;Po;0;ON;;;;;N;BACKSLASH;;;;
+005D;RIGHT SQUARE BRACKET;Pe;0;ON;;;;;Y;CLOSING SQUARE BRACKET;;;;
+005E;CIRCUMFLEX ACCENT;Sk;0;ON;;;;;N;SPACING CIRCUMFLEX;;;;
+005F;LOW LINE;Pc;0;ON;;;;;N;SPACING UNDERSCORE;;;;
+0060;GRAVE ACCENT;Sk;0;ON;;;;;N;SPACING GRAVE;;;;
+0061;LATIN SMALL LETTER A;Ll;0;L;;;;;N;;;0041;;0041
+0062;LATIN SMALL LETTER B;Ll;0;L;;;;;N;;;0042;;0042
+0063;LATIN SMALL LETTER C;Ll;0;L;;;;;N;;;0043;;0043
+0064;LATIN SMALL LETTER D;Ll;0;L;;;;;N;;;0044;;0044
+0065;LATIN SMALL LETTER E;Ll;0;L;;;;;N;;;0045;;0045
+0066;LATIN SMALL LETTER F;Ll;0;L;;;;;N;;;0046;;0046
+0067;LATIN SMALL LETTER G;Ll;0;L;;;;;N;;;0047;;0047
+0068;LATIN SMALL LETTER H;Ll;0;L;;;;;N;;;0048;;0048
+0069;LATIN SMALL LETTER I;Ll;0;L;;;;;N;;;0049;;0049
+006A;LATIN SMALL LETTER J;Ll;0;L;;;;;N;;;004A;;004A
+006B;LATIN SMALL LETTER K;Ll;0;L;;;;;N;;;004B;;004B
+006C;LATIN SMALL LETTER L;Ll;0;L;;;;;N;;;004C;;004C
+006D;LATIN SMALL LETTER M;Ll;0;L;;;;;N;;;004D;;004D
+006E;LATIN SMALL LETTER N;Ll;0;L;;;;;N;;;004E;;004E
+006F;LATIN SMALL LETTER O;Ll;0;L;;;;;N;;;004F;;004F
+0070;LATIN SMALL LETTER P;Ll;0;L;;;;;N;;;0050;;0050
+0071;LATIN SMALL LETTER Q;Ll;0;L;;;;;N;;;0051;;0051
+0072;LATIN SMALL LETTER R;Ll;0;L;;;;;N;;;0052;;0052
+0073;LATIN SMALL LETTER S;Ll;0;L;;;;;N;;;0053;;0053
+0074;LATIN SMALL LETTER T;Ll;0;L;;;;;N;;;0054;;0054
+0075;LATIN SMALL LETTER U;Ll;0;L;;;;;N;;;0055;;0055
+0076;LATIN SMALL LETTER V;Ll;0;L;;;;;N;;;0056;;0056
+0077;LATIN SMALL LETTER W;Ll;0;L;;;;;N;;;0057;;0057
+0078;LATIN SMALL LETTER X;Ll;0;L;;;;;N;;;0058;;0058
+0079;LATIN SMALL LETTER Y;Ll;0;L;;;;;N;;;0059;;0059
+007A;LATIN SMALL LETTER Z;Ll;0;L;;;;;N;;;005A;;005A
+007B;LEFT CURLY BRACKET;Ps;0;ON;;;;;Y;OPENING CURLY BRACKET;;;;
+007C;VERTICAL LINE;Sm;0;ON;;;;;N;VERTICAL BAR;;;;
+007D;RIGHT CURLY BRACKET;Pe;0;ON;;;;;Y;CLOSING CURLY BRACKET;;;;
+007E;TILDE;Sm;0;ON;;;;;N;;;;;
+007F;<control>;Cc;0;BN;;;;;N;DELETE;;;;
+0080;<control>;Cc;0;BN;;;;;N;;;;;
+0081;<control>;Cc;0;BN;;;;;N;;;;;
+0082;<control>;Cc;0;BN;;;;;N;BREAK PERMITTED HERE;;;;
+0083;<control>;Cc;0;BN;;;;;N;NO BREAK HERE;;;;
+0084;<control>;Cc;0;BN;;;;;N;;;;;
+0085;<control>;Cc;0;B;;;;;N;NEXT LINE (NEL);;;;
+0086;<control>;Cc;0;BN;;;;;N;START OF SELECTED AREA;;;;
+0087;<control>;Cc;0;BN;;;;;N;END OF SELECTED AREA;;;;
+0088;<control>;Cc;0;BN;;;;;N;CHARACTER TABULATION SET;;;;
+0089;<control>;Cc;0;BN;;;;;N;CHARACTER TABULATION WITH JUSTIFICATION;;;;
+008A;<control>;Cc;0;BN;;;;;N;LINE TABULATION SET;;;;
+008B;<control>;Cc;0;BN;;;;;N;PARTIAL LINE FORWARD;;;;
+008C;<control>;Cc;0;BN;;;;;N;PARTIAL LINE BACKWARD;;;;
+008D;<control>;Cc;0;BN;;;;;N;REVERSE LINE FEED;;;;
+008E;<control>;Cc;0;BN;;;;;N;SINGLE SHIFT TWO;;;;
+008F;<control>;Cc;0;BN;;;;;N;SINGLE SHIFT THREE;;;;
+0090;<control>;Cc;0;BN;;;;;N;DEVICE CONTROL STRING;;;;
+0091;<control>;Cc;0;BN;;;;;N;PRIVATE USE ONE;;;;
+0092;<control>;Cc;0;BN;;;;;N;PRIVATE USE TWO;;;;
+0093;<control>;Cc;0;BN;;;;;N;SET TRANSMIT STATE;;;;
+0094;<control>;Cc;0;BN;;;;;N;CANCEL CHARACTER;;;;
+0095;<control>;Cc;0;BN;;;;;N;MESSAGE WAITING;;;;
+0096;<control>;Cc;0;BN;;;;;N;START OF GUARDED AREA;;;;
+0097;<control>;Cc;0;BN;;;;;N;END OF GUARDED AREA;;;;
+0098;<control>;Cc;0;BN;;;;;N;START OF STRING;;;;
+0099;<control>;Cc;0;BN;;;;;N;;;;;
+009A;<control>;Cc;0;BN;;;;;N;SINGLE CHARACTER INTRODUCER;;;;
+009B;<control>;Cc;0;BN;;;;;N;CONTROL SEQUENCE INTRODUCER;;;;
+009C;<control>;Cc;0;BN;;;;;N;STRING TERMINATOR;;;;
+009D;<control>;Cc;0;BN;;;;;N;OPERATING SYSTEM COMMAND;;;;
+009E;<control>;Cc;0;BN;;;;;N;PRIVACY MESSAGE;;;;
+009F;<control>;Cc;0;BN;;;;;N;APPLICATION PROGRAM COMMAND;;;;
+00A0;NO-BREAK SPACE;Zs;0;CS;<noBreak> 0020;;;;N;NON-BREAKING SPACE;;;;
+00A1;INVERTED EXCLAMATION MARK;Po;0;ON;;;;;N;;;;;
+00A2;CENT SIGN;Sc;0;ET;;;;;N;;;;;
+00A3;POUND SIGN;Sc;0;ET;;;;;N;;;;;
+00A4;CURRENCY SIGN;Sc;0;ET;;;;;N;;;;;
+00A5;YEN SIGN;Sc;0;ET;;;;;N;;;;;
+00A6;BROKEN BAR;So;0;ON;;;;;N;BROKEN VERTICAL BAR;;;;
+00A7;SECTION SIGN;So;0;ON;;;;;N;;;;;
+00A8;DIAERESIS;Sk;0;ON;<compat> 0020 0308;;;;N;SPACING DIAERESIS;;;;
+00A9;COPYRIGHT SIGN;So;0;ON;;;;;N;;;;;
+00AA;FEMININE ORDINAL INDICATOR;Ll;0;L;<super> 0061;;;;N;;;;;
+00AB;LEFT-POINTING DOUBLE ANGLE QUOTATION MARK;Pi;0;ON;;;;;Y;LEFT POINTING GUILLEMET;*;;;
+00AC;NOT SIGN;Sm;0;ON;;;;;N;;;;;
+00AD;SOFT HYPHEN;Cf;0;BN;;;;;N;;;;;
+00AE;REGISTERED SIGN;So;0;ON;;;;;N;REGISTERED TRADE MARK SIGN;;;;
+00AF;MACRON;Sk;0;ON;<compat> 0020 0304;;;;N;SPACING MACRON;;;;
+00B0;DEGREE SIGN;So;0;ET;;;;;N;;;;;
+00B1;PLUS-MINUS SIGN;Sm;0;ET;;;;;N;PLUS-OR-MINUS SIGN;;;;
+00B2;SUPERSCRIPT TWO;No;0;EN;<super> 0032;;2;2;N;SUPERSCRIPT DIGIT TWO;;;;
+00B3;SUPERSCRIPT THREE;No;0;EN;<super> 0033;;3;3;N;SUPERSCRIPT DIGIT THREE;;;;
+00B4;ACUTE ACCENT;Sk;0;ON;<compat> 0020 0301;;;;N;SPACING ACUTE;;;;
+00B5;MICRO SIGN;Ll;0;L;<compat> 03BC;;;;N;;;039C;;039C
+00B6;PILCROW SIGN;So;0;ON;;;;;N;PARAGRAPH SIGN;;;;
+00B7;MIDDLE DOT;Po;0;ON;;;;;N;;;;;
+00B8;CEDILLA;Sk;0;ON;<compat> 0020 0327;;;;N;SPACING CEDILLA;;;;
+00B9;SUPERSCRIPT ONE;No;0;EN;<super> 0031;;1;1;N;SUPERSCRIPT DIGIT ONE;;;;
+00BA;MASCULINE ORDINAL INDICATOR;Ll;0;L;<super> 006F;;;;N;;;;;
+00BB;RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK;Pf;0;ON;;;;;Y;RIGHT POINTING GUILLEMET;*;;;
+00BC;VULGAR FRACTION ONE QUARTER;No;0;ON;<fraction> 0031 2044 0034;;;1/4;N;FRACTION ONE QUARTER;;;;
+00BD;VULGAR FRACTION ONE HALF;No;0;ON;<fraction> 0031 2044 0032;;;1/2;N;FRACTION ONE HALF;;;;
+00BE;VULGAR FRACTION THREE QUARTERS;No;0;ON;<fraction> 0033 2044 0034;;;3/4;N;FRACTION THREE QUARTERS;;;;
+00BF;INVERTED QUESTION MARK;Po;0;ON;;;;;N;;;;;
+00C0;LATIN CAPITAL LETTER A WITH GRAVE;Lu;0;L;0041 0300;;;;N;LATIN CAPITAL LETTER A GRAVE;;;00E0;
+00C1;LATIN CAPITAL LETTER A WITH ACUTE;Lu;0;L;0041 0301;;;;N;LATIN CAPITAL LETTER A ACUTE;;;00E1;
+00C2;LATIN CAPITAL LETTER A WITH CIRCUMFLEX;Lu;0;L;0041 0302;;;;N;LATIN CAPITAL LETTER A CIRCUMFLEX;;;00E2;
+00C3;LATIN CAPITAL LETTER A WITH TILDE;Lu;0;L;0041 0303;;;;N;LATIN CAPITAL LETTER A TILDE;;;00E3;
+00C4;LATIN CAPITAL LETTER A WITH DIAERESIS;Lu;0;L;0041 0308;;;;N;LATIN CAPITAL LETTER A DIAERESIS;;;00E4;
+00C5;LATIN CAPITAL LETTER A WITH RING ABOVE;Lu;0;L;0041 030A;;;;N;LATIN CAPITAL LETTER A RING;;;00E5;
+00C6;LATIN CAPITAL LETTER AE;Lu;0;L;;;;;N;LATIN CAPITAL LETTER A E;ash *;;00E6;
+00C7;LATIN CAPITAL LETTER C WITH CEDILLA;Lu;0;L;0043 0327;;;;N;LATIN CAPITAL LETTER C CEDILLA;;;00E7;
+00C8;LATIN CAPITAL LETTER E WITH GRAVE;Lu;0;L;0045 0300;;;;N;LATIN CAPITAL LETTER E GRAVE;;;00E8;
+00C9;LATIN CAPITAL LETTER E WITH ACUTE;Lu;0;L;0045 0301;;;;N;LATIN CAPITAL LETTER E ACUTE;;;00E9;
+00CA;LATIN CAPITAL LETTER E WITH CIRCUMFLEX;Lu;0;L;0045 0302;;;;N;LATIN CAPITAL LETTER E CIRCUMFLEX;;;00EA;
+00CB;LATIN CAPITAL LETTER E WITH DIAERESIS;Lu;0;L;0045 0308;;;;N;LATIN CAPITAL LETTER E DIAERESIS;;;00EB;
+00CC;LATIN CAPITAL LETTER I WITH GRAVE;Lu;0;L;0049 0300;;;;N;LATIN CAPITAL LETTER I GRAVE;;;00EC;
+00CD;LATIN CAPITAL LETTER I WITH ACUTE;Lu;0;L;0049 0301;;;;N;LATIN CAPITAL LETTER I ACUTE;;;00ED;
+00CE;LATIN CAPITAL LETTER I WITH CIRCUMFLEX;Lu;0;L;0049 0302;;;;N;LATIN CAPITAL LETTER I CIRCUMFLEX;;;00EE;
+00CF;LATIN CAPITAL LETTER I WITH DIAERESIS;Lu;0;L;0049 0308;;;;N;LATIN CAPITAL LETTER I DIAERESIS;;;00EF;
+00D0;LATIN CAPITAL LETTER ETH;Lu;0;L;;;;;N;;Icelandic;;00F0;
+00D1;LATIN CAPITAL LETTER N WITH TILDE;Lu;0;L;004E 0303;;;;N;LATIN CAPITAL LETTER N TILDE;;;00F1;
+00D2;LATIN CAPITAL LETTER O WITH GRAVE;Lu;0;L;004F 0300;;;;N;LATIN CAPITAL LETTER O GRAVE;;;00F2;
+00D3;LATIN CAPITAL LETTER O WITH ACUTE;Lu;0;L;004F 0301;;;;N;LATIN CAPITAL LETTER O ACUTE;;;00F3;
+00D4;LATIN CAPITAL LETTER O WITH CIRCUMFLEX;Lu;0;L;004F 0302;;;;N;LATIN CAPITAL LETTER O CIRCUMFLEX;;;00F4;
+00D5;LATIN CAPITAL LETTER O WITH TILDE;Lu;0;L;004F 0303;;;;N;LATIN CAPITAL LETTER O TILDE;;;00F5;
+00D6;LATIN CAPITAL LETTER O WITH DIAERESIS;Lu;0;L;004F 0308;;;;N;LATIN CAPITAL LETTER O DIAERESIS;;;00F6;
+00D7;MULTIPLICATION SIGN;Sm;0;ON;;;;;N;;;;;
+00D8;LATIN CAPITAL LETTER O WITH STROKE;Lu;0;L;;;;;N;LATIN CAPITAL LETTER O SLASH;;;00F8;
+00D9;LATIN CAPITAL LETTER U WITH GRAVE;Lu;0;L;0055 0300;;;;N;LATIN CAPITAL LETTER U GRAVE;;;00F9;
+00DA;LATIN CAPITAL LETTER U WITH ACUTE;Lu;0;L;0055 0301;;;;N;LATIN CAPITAL LETTER U ACUTE;;;00FA;
+00DB;LATIN CAPITAL LETTER U WITH CIRCUMFLEX;Lu;0;L;0055 0302;;;;N;LATIN CAPITAL LETTER U CIRCUMFLEX;;;00FB;
+00DC;LATIN CAPITAL LETTER U WITH DIAERESIS;Lu;0;L;0055 0308;;;;N;LATIN CAPITAL LETTER U DIAERESIS;;;00FC;
+00DD;LATIN CAPITAL LETTER Y WITH ACUTE;Lu;0;L;0059 0301;;;;N;LATIN CAPITAL LETTER Y ACUTE;;;00FD;
+00DE;LATIN CAPITAL LETTER THORN;Lu;0;L;;;;;N;;Icelandic;;00FE;
+00DF;LATIN SMALL LETTER SHARP S;Ll;0;L;;;;;N;;German;;;
+00E0;LATIN SMALL LETTER A WITH GRAVE;Ll;0;L;0061 0300;;;;N;LATIN SMALL LETTER A GRAVE;;00C0;;00C0
+00E1;LATIN SMALL LETTER A WITH ACUTE;Ll;0;L;0061 0301;;;;N;LATIN SMALL LETTER A ACUTE;;00C1;;00C1
+00E2;LATIN SMALL LETTER A WITH CIRCUMFLEX;Ll;0;L;0061 0302;;;;N;LATIN SMALL LETTER A CIRCUMFLEX;;00C2;;00C2
+00E3;LATIN SMALL LETTER A WITH TILDE;Ll;0;L;0061 0303;;;;N;LATIN SMALL LETTER A TILDE;;00C3;;00C3
+00E4;LATIN SMALL LETTER A WITH DIAERESIS;Ll;0;L;0061 0308;;;;N;LATIN SMALL LETTER A DIAERESIS;;00C4;;00C4
+00E5;LATIN SMALL LETTER A WITH RING ABOVE;Ll;0;L;0061 030A;;;;N;LATIN SMALL LETTER A RING;;00C5;;00C5
+00E6;LATIN SMALL LETTER AE;Ll;0;L;;;;;N;LATIN SMALL LETTER A E;ash *;00C6;;00C6
+00E7;LATIN SMALL LETTER C WITH CEDILLA;Ll;0;L;0063 0327;;;;N;LATIN SMALL LETTER C CEDILLA;;00C7;;00C7
+00E8;LATIN SMALL LETTER E WITH GRAVE;Ll;0;L;0065 0300;;;;N;LATIN SMALL LETTER E GRAVE;;00C8;;00C8
+00E9;LATIN SMALL LETTER E WITH ACUTE;Ll;0;L;0065 0301;;;;N;LATIN SMALL LETTER E ACUTE;;00C9;;00C9
+00EA;LATIN SMALL LETTER E WITH CIRCUMFLEX;Ll;0;L;0065 0302;;;;N;LATIN SMALL LETTER E CIRCUMFLEX;;00CA;;00CA
+00EB;LATIN SMALL LETTER E WITH DIAERESIS;Ll;0;L;0065 0308;;;;N;LATIN SMALL LETTER E DIAERESIS;;00CB;;00CB
+00EC;LATIN SMALL LETTER I WITH GRAVE;Ll;0;L;0069 0300;;;;N;LATIN SMALL LETTER I GRAVE;;00CC;;00CC
+00ED;LATIN SMALL LETTER I WITH ACUTE;Ll;0;L;0069 0301;;;;N;LATIN SMALL LETTER I ACUTE;;00CD;;00CD
+00EE;LATIN SMALL LETTER I WITH CIRCUMFLEX;Ll;0;L;0069 0302;;;;N;LATIN SMALL LETTER I CIRCUMFLEX;;00CE;;00CE
+00EF;LATIN SMALL LETTER I WITH DIAERESIS;Ll;0;L;0069 0308;;;;N;LATIN SMALL LETTER I DIAERESIS;;00CF;;00CF
+00F0;LATIN SMALL LETTER ETH;Ll;0;L;;;;;N;;Icelandic;00D0;;00D0
+00F1;LATIN SMALL LETTER N WITH TILDE;Ll;0;L;006E 0303;;;;N;LATIN SMALL LETTER N TILDE;;00D1;;00D1
+00F2;LATIN SMALL LETTER O WITH GRAVE;Ll;0;L;006F 0300;;;;N;LATIN SMALL LETTER O GRAVE;;00D2;;00D2
+00F3;LATIN SMALL LETTER O WITH ACUTE;Ll;0;L;006F 0301;;;;N;LATIN SMALL LETTER O ACUTE;;00D3;;00D3
+00F4;LATIN SMALL LETTER O WITH CIRCUMFLEX;Ll;0;L;006F 0302;;;;N;LATIN SMALL LETTER O CIRCUMFLEX;;00D4;;00D4
+00F5;LATIN SMALL LETTER O WITH TILDE;Ll;0;L;006F 0303;;;;N;LATIN SMALL LETTER O TILDE;;00D5;;00D5
+00F6;LATIN SMALL LETTER O WITH DIAERESIS;Ll;0;L;006F 0308;;;;N;LATIN SMALL LETTER O DIAERESIS;;00D6;;00D6
+00F7;DIVISION SIGN;Sm;0;ON;;;;;N;;;;;
+00F8;LATIN SMALL LETTER O WITH STROKE;Ll;0;L;;;;;N;LATIN SMALL LETTER O SLASH;;00D8;;00D8
+00F9;LATIN SMALL LETTER U WITH GRAVE;Ll;0;L;0075 0300;;;;N;LATIN SMALL LETTER U GRAVE;;00D9;;00D9
+00FA;LATIN SMALL LETTER U WITH ACUTE;Ll;0;L;0075 0301;;;;N;LATIN SMALL LETTER U ACUTE;;00DA;;00DA
+00FB;LATIN SMALL LETTER U WITH CIRCUMFLEX;Ll;0;L;0075 0302;;;;N;LATIN SMALL LETTER U CIRCUMFLEX;;00DB;;00DB
+00FC;LATIN SMALL LETTER U WITH DIAERESIS;Ll;0;L;0075 0308;;;;N;LATIN SMALL LETTER U DIAERESIS;;00DC;;00DC
+00FD;LATIN SMALL LETTER Y WITH ACUTE;Ll;0;L;0079 0301;;;;N;LATIN SMALL LETTER Y ACUTE;;00DD;;00DD
+00FE;LATIN SMALL LETTER THORN;Ll;0;L;;;;;N;;Icelandic;00DE;;00DE
+00FF;LATIN SMALL LETTER Y WITH DIAERESIS;Ll;0;L;0079 0308;;;;N;LATIN SMALL LETTER Y DIAERESIS;;0178;;0178
+0100;LATIN CAPITAL LETTER A WITH MACRON;Lu;0;L;0041 0304;;;;N;LATIN CAPITAL LETTER A MACRON;;;0101;
+0101;LATIN SMALL LETTER A WITH MACRON;Ll;0;L;0061 0304;;;;N;LATIN SMALL LETTER A MACRON;;0100;;0100
+0102;LATIN CAPITAL LETTER A WITH BREVE;Lu;0;L;0041 0306;;;;N;LATIN CAPITAL LETTER A BREVE;;;0103;
+0103;LATIN SMALL LETTER A WITH BREVE;Ll;0;L;0061 0306;;;;N;LATIN SMALL LETTER A BREVE;;0102;;0102
+0104;LATIN CAPITAL LETTER A WITH OGONEK;Lu;0;L;0041 0328;;;;N;LATIN CAPITAL LETTER A OGONEK;;;0105;
+0105;LATIN SMALL LETTER A WITH OGONEK;Ll;0;L;0061 0328;;;;N;LATIN SMALL LETTER A OGONEK;;0104;;0104
+0106;LATIN CAPITAL LETTER C WITH ACUTE;Lu;0;L;0043 0301;;;;N;LATIN CAPITAL LETTER C ACUTE;;;0107;
+0107;LATIN SMALL LETTER C WITH ACUTE;Ll;0;L;0063 0301;;;;N;LATIN SMALL LETTER C ACUTE;;0106;;0106
+0108;LATIN CAPITAL LETTER C WITH CIRCUMFLEX;Lu;0;L;0043 0302;;;;N;LATIN CAPITAL LETTER C CIRCUMFLEX;;;0109;
+0109;LATIN SMALL LETTER C WITH CIRCUMFLEX;Ll;0;L;0063 0302;;;;N;LATIN SMALL LETTER C CIRCUMFLEX;;0108;;0108
+010A;LATIN CAPITAL LETTER C WITH DOT ABOVE;Lu;0;L;0043 0307;;;;N;LATIN CAPITAL LETTER C DOT;;;010B;
+010B;LATIN SMALL LETTER C WITH DOT ABOVE;Ll;0;L;0063 0307;;;;N;LATIN SMALL LETTER C DOT;;010A;;010A
+010C;LATIN CAPITAL LETTER C WITH CARON;Lu;0;L;0043 030C;;;;N;LATIN CAPITAL LETTER C HACEK;;;010D;
+010D;LATIN SMALL LETTER C WITH CARON;Ll;0;L;0063 030C;;;;N;LATIN SMALL LETTER C HACEK;;010C;;010C
+010E;LATIN CAPITAL LETTER D WITH CARON;Lu;0;L;0044 030C;;;;N;LATIN CAPITAL LETTER D HACEK;;;010F;
+010F;LATIN SMALL LETTER D WITH CARON;Ll;0;L;0064 030C;;;;N;LATIN SMALL LETTER D HACEK;;010E;;010E
+0110;LATIN CAPITAL LETTER D WITH STROKE;Lu;0;L;;;;;N;LATIN CAPITAL LETTER D BAR;;;0111;
+0111;LATIN SMALL LETTER D WITH STROKE;Ll;0;L;;;;;N;LATIN SMALL LETTER D BAR;;0110;;0110
+0112;LATIN CAPITAL LETTER E WITH MACRON;Lu;0;L;0045 0304;;;;N;LATIN CAPITAL LETTER E MACRON;;;0113;
+0113;LATIN SMALL LETTER E WITH MACRON;Ll;0;L;0065 0304;;;;N;LATIN SMALL LETTER E MACRON;;0112;;0112
+0114;LATIN CAPITAL LETTER E WITH BREVE;Lu;0;L;0045 0306;;;;N;LATIN CAPITAL LETTER E BREVE;;;0115;
+0115;LATIN SMALL LETTER E WITH BREVE;Ll;0;L;0065 0306;;;;N;LATIN SMALL LETTER E BREVE;;0114;;0114
+0116;LATIN CAPITAL LETTER E WITH DOT ABOVE;Lu;0;L;0045 0307;;;;N;LATIN CAPITAL LETTER E DOT;;;0117;
+0117;LATIN SMALL LETTER E WITH DOT ABOVE;Ll;0;L;0065 0307;;;;N;LATIN SMALL LETTER E DOT;;0116;;0116
+0118;LATIN CAPITAL LETTER E WITH OGONEK;Lu;0;L;0045 0328;;;;N;LATIN CAPITAL LETTER E OGONEK;;;0119;
+0119;LATIN SMALL LETTER E WITH OGONEK;Ll;0;L;0065 0328;;;;N;LATIN SMALL LETTER E OGONEK;;0118;;0118
+011A;LATIN CAPITAL LETTER E WITH CARON;Lu;0;L;0045 030C;;;;N;LATIN CAPITAL LETTER E HACEK;;;011B;
+011B;LATIN SMALL LETTER E WITH CARON;Ll;0;L;0065 030C;;;;N;LATIN SMALL LETTER E HACEK;;011A;;011A
+011C;LATIN CAPITAL LETTER G WITH CIRCUMFLEX;Lu;0;L;0047 0302;;;;N;LATIN CAPITAL LETTER G CIRCUMFLEX;;;011D;
+011D;LATIN SMALL LETTER G WITH CIRCUMFLEX;Ll;0;L;0067 0302;;;;N;LATIN SMALL LETTER G CIRCUMFLEX;;011C;;011C
+011E;LATIN CAPITAL LETTER G WITH BREVE;Lu;0;L;0047 0306;;;;N;LATIN CAPITAL LETTER G BREVE;;;011F;
+011F;LATIN SMALL LETTER G WITH BREVE;Ll;0;L;0067 0306;;;;N;LATIN SMALL LETTER G BREVE;;011E;;011E
+0120;LATIN CAPITAL LETTER G WITH DOT ABOVE;Lu;0;L;0047 0307;;;;N;LATIN CAPITAL LETTER G DOT;;;0121;
+0121;LATIN SMALL LETTER G WITH DOT ABOVE;Ll;0;L;0067 0307;;;;N;LATIN SMALL LETTER G DOT;;0120;;0120
+0122;LATIN CAPITAL LETTER G WITH CEDILLA;Lu;0;L;0047 0327;;;;N;LATIN CAPITAL LETTER G CEDILLA;;;0123;
+0123;LATIN SMALL LETTER G WITH CEDILLA;Ll;0;L;0067 0327;;;;N;LATIN SMALL LETTER G CEDILLA;;0122;;0122
+0124;LATIN CAPITAL LETTER H WITH CIRCUMFLEX;Lu;0;L;0048 0302;;;;N;LATIN CAPITAL LETTER H CIRCUMFLEX;;;0125;
+0125;LATIN SMALL LETTER H WITH CIRCUMFLEX;Ll;0;L;0068 0302;;;;N;LATIN SMALL LETTER H CIRCUMFLEX;;0124;;0124
+0126;LATIN CAPITAL LETTER H WITH STROKE;Lu;0;L;;;;;N;LATIN CAPITAL LETTER H BAR;;;0127;
+0127;LATIN SMALL LETTER H WITH STROKE;Ll;0;L;;;;;N;LATIN SMALL LETTER H BAR;;0126;;0126
+0128;LATIN CAPITAL LETTER I WITH TILDE;Lu;0;L;0049 0303;;;;N;LATIN CAPITAL LETTER I TILDE;;;0129;
+0129;LATIN SMALL LETTER I WITH TILDE;Ll;0;L;0069 0303;;;;N;LATIN SMALL LETTER I TILDE;;0128;;0128
+012A;LATIN CAPITAL LETTER I WITH MACRON;Lu;0;L;0049 0304;;;;N;LATIN CAPITAL LETTER I MACRON;;;012B;
+012B;LATIN SMALL LETTER I WITH MACRON;Ll;0;L;0069 0304;;;;N;LATIN SMALL LETTER I MACRON;;012A;;012A
+012C;LATIN CAPITAL LETTER I WITH BREVE;Lu;0;L;0049 0306;;;;N;LATIN CAPITAL LETTER I BREVE;;;012D;
+012D;LATIN SMALL LETTER I WITH BREVE;Ll;0;L;0069 0306;;;;N;LATIN SMALL LETTER I BREVE;;012C;;012C
+012E;LATIN CAPITAL LETTER I WITH OGONEK;Lu;0;L;0049 0328;;;;N;LATIN CAPITAL LETTER I OGONEK;;;012F;
+012F;LATIN SMALL LETTER I WITH OGONEK;Ll;0;L;0069 0328;;;;N;LATIN SMALL LETTER I OGONEK;;012E;;012E
+0130;LATIN CAPITAL LETTER I WITH DOT ABOVE;Lu;0;L;0049 0307;;;;N;LATIN CAPITAL LETTER I DOT;;;0069;
+0131;LATIN SMALL LETTER DOTLESS I;Ll;0;L;;;;;N;;;0049;;0049
+0132;LATIN CAPITAL LIGATURE IJ;Lu;0;L;<compat> 0049 004A;;;;N;LATIN CAPITAL LETTER I J;;;0133;
+0133;LATIN SMALL LIGATURE IJ;Ll;0;L;<compat> 0069 006A;;;;N;LATIN SMALL LETTER I J;;0132;;0132
+0134;LATIN CAPITAL LETTER J WITH CIRCUMFLEX;Lu;0;L;004A 0302;;;;N;LATIN CAPITAL LETTER J CIRCUMFLEX;;;0135;
+0135;LATIN SMALL LETTER J WITH CIRCUMFLEX;Ll;0;L;006A 0302;;;;N;LATIN SMALL LETTER J CIRCUMFLEX;;0134;;0134
+0136;LATIN CAPITAL LETTER K WITH CEDILLA;Lu;0;L;004B 0327;;;;N;LATIN CAPITAL LETTER K CEDILLA;;;0137;
+0137;LATIN SMALL LETTER K WITH CEDILLA;Ll;0;L;006B 0327;;;;N;LATIN SMALL LETTER K CEDILLA;;0136;;0136
+0138;LATIN SMALL LETTER KRA;Ll;0;L;;;;;N;;Greenlandic;;;
+0139;LATIN CAPITAL LETTER L WITH ACUTE;Lu;0;L;004C 0301;;;;N;LATIN CAPITAL LETTER L ACUTE;;;013A;
+013A;LATIN SMALL LETTER L WITH ACUTE;Ll;0;L;006C 0301;;;;N;LATIN SMALL LETTER L ACUTE;;0139;;0139
+013B;LATIN CAPITAL LETTER L WITH CEDILLA;Lu;0;L;004C 0327;;;;N;LATIN CAPITAL LETTER L CEDILLA;;;013C;
+013C;LATIN SMALL LETTER L WITH CEDILLA;Ll;0;L;006C 0327;;;;N;LATIN SMALL LETTER L CEDILLA;;013B;;013B
+013D;LATIN CAPITAL LETTER L WITH CARON;Lu;0;L;004C 030C;;;;N;LATIN CAPITAL LETTER L HACEK;;;013E;
+013E;LATIN SMALL LETTER L WITH CARON;Ll;0;L;006C 030C;;;;N;LATIN SMALL LETTER L HACEK;;013D;;013D
+013F;LATIN CAPITAL LETTER L WITH MIDDLE DOT;Lu;0;L;<compat> 004C 00B7;;;;N;;;;0140;
+0140;LATIN SMALL LETTER L WITH MIDDLE DOT;Ll;0;L;<compat> 006C 00B7;;;;N;;;013F;;013F
+0141;LATIN CAPITAL LETTER L WITH STROKE;Lu;0;L;;;;;N;LATIN CAPITAL LETTER L SLASH;;;0142;
+0142;LATIN SMALL LETTER L WITH STROKE;Ll;0;L;;;;;N;LATIN SMALL LETTER L SLASH;;0141;;0141
+0143;LATIN CAPITAL LETTER N WITH ACUTE;Lu;0;L;004E 0301;;;;N;LATIN CAPITAL LETTER N ACUTE;;;0144;
+0144;LATIN SMALL LETTER N WITH ACUTE;Ll;0;L;006E 0301;;;;N;LATIN SMALL LETTER N ACUTE;;0143;;0143
+0145;LATIN CAPITAL LETTER N WITH CEDILLA;Lu;0;L;004E 0327;;;;N;LATIN CAPITAL LETTER N CEDILLA;;;0146;
+0146;LATIN SMALL LETTER N WITH CEDILLA;Ll;0;L;006E 0327;;;;N;LATIN SMALL LETTER N CEDILLA;;0145;;0145
+0147;LATIN CAPITAL LETTER N WITH CARON;Lu;0;L;004E 030C;;;;N;LATIN CAPITAL LETTER N HACEK;;;0148;
+0148;LATIN SMALL LETTER N WITH CARON;Ll;0;L;006E 030C;;;;N;LATIN SMALL LETTER N HACEK;;0147;;0147
+0149;LATIN SMALL LETTER N PRECEDED BY APOSTROPHE;Ll;0;L;<compat> 02BC 006E;;;;N;LATIN SMALL LETTER APOSTROPHE N;;;;
+014A;LATIN CAPITAL LETTER ENG;Lu;0;L;;;;;N;;Sami;;014B;
+014B;LATIN SMALL LETTER ENG;Ll;0;L;;;;;N;;Sami;014A;;014A
+014C;LATIN CAPITAL LETTER O WITH MACRON;Lu;0;L;004F 0304;;;;N;LATIN CAPITAL LETTER O MACRON;;;014D;
+014D;LATIN SMALL LETTER O WITH MACRON;Ll;0;L;006F 0304;;;;N;LATIN SMALL LETTER O MACRON;;014C;;014C
+014E;LATIN CAPITAL LETTER O WITH BREVE;Lu;0;L;004F 0306;;;;N;LATIN CAPITAL LETTER O BREVE;;;014F;
+014F;LATIN SMALL LETTER O WITH BREVE;Ll;0;L;006F 0306;;;;N;LATIN SMALL LETTER O BREVE;;014E;;014E
+0150;LATIN CAPITAL LETTER O WITH DOUBLE ACUTE;Lu;0;L;004F 030B;;;;N;LATIN CAPITAL LETTER O DOUBLE ACUTE;;;0151;
+0151;LATIN SMALL LETTER O WITH DOUBLE ACUTE;Ll;0;L;006F 030B;;;;N;LATIN SMALL LETTER O DOUBLE ACUTE;;0150;;0150
+0152;LATIN CAPITAL LIGATURE OE;Lu;0;L;;;;;N;LATIN CAPITAL LETTER O E;;;0153;
+0153;LATIN SMALL LIGATURE OE;Ll;0;L;;;;;N;LATIN SMALL LETTER O E;;0152;;0152
+0154;LATIN CAPITAL LETTER R WITH ACUTE;Lu;0;L;0052 0301;;;;N;LATIN CAPITAL LETTER R ACUTE;;;0155;
+0155;LATIN SMALL LETTER R WITH ACUTE;Ll;0;L;0072 0301;;;;N;LATIN SMALL LETTER R ACUTE;;0154;;0154
+0156;LATIN CAPITAL LETTER R WITH CEDILLA;Lu;0;L;0052 0327;;;;N;LATIN CAPITAL LETTER R CEDILLA;;;0157;
+0157;LATIN SMALL LETTER R WITH CEDILLA;Ll;0;L;0072 0327;;;;N;LATIN SMALL LETTER R CEDILLA;;0156;;0156
+0158;LATIN CAPITAL LETTER R WITH CARON;Lu;0;L;0052 030C;;;;N;LATIN CAPITAL LETTER R HACEK;;;0159;
+0159;LATIN SMALL LETTER R WITH CARON;Ll;0;L;0072 030C;;;;N;LATIN SMALL LETTER R HACEK;;0158;;0158
+015A;LATIN CAPITAL LETTER S WITH ACUTE;Lu;0;L;0053 0301;;;;N;LATIN CAPITAL LETTER S ACUTE;;;015B;
+015B;LATIN SMALL LETTER S WITH ACUTE;Ll;0;L;0073 0301;;;;N;LATIN SMALL LETTER S ACUTE;;015A;;015A
+015C;LATIN CAPITAL LETTER S WITH CIRCUMFLEX;Lu;0;L;0053 0302;;;;N;LATIN CAPITAL LETTER S CIRCUMFLEX;;;015D;
+015D;LATIN SMALL LETTER S WITH CIRCUMFLEX;Ll;0;L;0073 0302;;;;N;LATIN SMALL LETTER S CIRCUMFLEX;;015C;;015C
+015E;LATIN CAPITAL LETTER S WITH CEDILLA;Lu;0;L;0053 0327;;;;N;LATIN CAPITAL LETTER S CEDILLA;*;;015F;
+015F;LATIN SMALL LETTER S WITH CEDILLA;Ll;0;L;0073 0327;;;;N;LATIN SMALL LETTER S CEDILLA;*;015E;;015E
+0160;LATIN CAPITAL LETTER S WITH CARON;Lu;0;L;0053 030C;;;;N;LATIN CAPITAL LETTER S HACEK;;;0161;
+0161;LATIN SMALL LETTER S WITH CARON;Ll;0;L;0073 030C;;;;N;LATIN SMALL LETTER S HACEK;;0160;;0160
+0162;LATIN CAPITAL LETTER T WITH CEDILLA;Lu;0;L;0054 0327;;;;N;LATIN CAPITAL LETTER T CEDILLA;*;;0163;
+0163;LATIN SMALL LETTER T WITH CEDILLA;Ll;0;L;0074 0327;;;;N;LATIN SMALL LETTER T CEDILLA;*;0162;;0162
+0164;LATIN CAPITAL LETTER T WITH CARON;Lu;0;L;0054 030C;;;;N;LATIN CAPITAL LETTER T HACEK;;;0165;
+0165;LATIN SMALL LETTER T WITH CARON;Ll;0;L;0074 030C;;;;N;LATIN SMALL LETTER T HACEK;;0164;;0164
+0166;LATIN CAPITAL LETTER T WITH STROKE;Lu;0;L;;;;;N;LATIN CAPITAL LETTER T BAR;;;0167;
+0167;LATIN SMALL LETTER T WITH STROKE;Ll;0;L;;;;;N;LATIN SMALL LETTER T BAR;;0166;;0166
+0168;LATIN CAPITAL LETTER U WITH TILDE;Lu;0;L;0055 0303;;;;N;LATIN CAPITAL LETTER U TILDE;;;0169;
+0169;LATIN SMALL LETTER U WITH TILDE;Ll;0;L;0075 0303;;;;N;LATIN SMALL LETTER U TILDE;;0168;;0168
+016A;LATIN CAPITAL LETTER U WITH MACRON;Lu;0;L;0055 0304;;;;N;LATIN CAPITAL LETTER U MACRON;;;016B;
+016B;LATIN SMALL LETTER U WITH MACRON;Ll;0;L;0075 0304;;;;N;LATIN SMALL LETTER U MACRON;;016A;;016A
+016C;LATIN CAPITAL LETTER U WITH BREVE;Lu;0;L;0055 0306;;;;N;LATIN CAPITAL LETTER U BREVE;;;016D;
+016D;LATIN SMALL LETTER U WITH BREVE;Ll;0;L;0075 0306;;;;N;LATIN SMALL LETTER U BREVE;;016C;;016C
+016E;LATIN CAPITAL LETTER U WITH RING ABOVE;Lu;0;L;0055 030A;;;;N;LATIN CAPITAL LETTER U RING;;;016F;
+016F;LATIN SMALL LETTER U WITH RING ABOVE;Ll;0;L;0075 030A;;;;N;LATIN SMALL LETTER U RING;;016E;;016E
+0170;LATIN CAPITAL LETTER U WITH DOUBLE ACUTE;Lu;0;L;0055 030B;;;;N;LATIN CAPITAL LETTER U DOUBLE ACUTE;;;0171;
+0171;LATIN SMALL LETTER U WITH DOUBLE ACUTE;Ll;0;L;0075 030B;;;;N;LATIN SMALL LETTER U DOUBLE ACUTE;;0170;;0170
+0172;LATIN CAPITAL LETTER U WITH OGONEK;Lu;0;L;0055 0328;;;;N;LATIN CAPITAL LETTER U OGONEK;;;0173;
+0173;LATIN SMALL LETTER U WITH OGONEK;Ll;0;L;0075 0328;;;;N;LATIN SMALL LETTER U OGONEK;;0172;;0172
+0174;LATIN CAPITAL LETTER W WITH CIRCUMFLEX;Lu;0;L;0057 0302;;;;N;LATIN CAPITAL LETTER W CIRCUMFLEX;;;0175;
+0175;LATIN SMALL LETTER W WITH CIRCUMFLEX;Ll;0;L;0077 0302;;;;N;LATIN SMALL LETTER W CIRCUMFLEX;;0174;;0174
+0176;LATIN CAPITAL LETTER Y WITH CIRCUMFLEX;Lu;0;L;0059 0302;;;;N;LATIN CAPITAL LETTER Y CIRCUMFLEX;;;0177;
+0177;LATIN SMALL LETTER Y WITH CIRCUMFLEX;Ll;0;L;0079 0302;;;;N;LATIN SMALL LETTER Y CIRCUMFLEX;;0176;;0176
+0178;LATIN CAPITAL LETTER Y WITH DIAERESIS;Lu;0;L;0059 0308;;;;N;LATIN CAPITAL LETTER Y DIAERESIS;;;00FF;
+0179;LATIN CAPITAL LETTER Z WITH ACUTE;Lu;0;L;005A 0301;;;;N;LATIN CAPITAL LETTER Z ACUTE;;;017A;
+017A;LATIN SMALL LETTER Z WITH ACUTE;Ll;0;L;007A 0301;;;;N;LATIN SMALL LETTER Z ACUTE;;0179;;0179
+017B;LATIN CAPITAL LETTER Z WITH DOT ABOVE;Lu;0;L;005A 0307;;;;N;LATIN CAPITAL LETTER Z DOT;;;017C;
+017C;LATIN SMALL LETTER Z WITH DOT ABOVE;Ll;0;L;007A 0307;;;;N;LATIN SMALL LETTER Z DOT;;017B;;017B
+017D;LATIN CAPITAL LETTER Z WITH CARON;Lu;0;L;005A 030C;;;;N;LATIN CAPITAL LETTER Z HACEK;;;017E;
+017E;LATIN SMALL LETTER Z WITH CARON;Ll;0;L;007A 030C;;;;N;LATIN SMALL LETTER Z HACEK;;017D;;017D
+017F;LATIN SMALL LETTER LONG S;Ll;0;L;<compat> 0073;;;;N;;;0053;;0053
+0180;LATIN SMALL LETTER B WITH STROKE;Ll;0;L;;;;;N;LATIN SMALL LETTER B BAR;;;;
+0181;LATIN CAPITAL LETTER B WITH HOOK;Lu;0;L;;;;;N;LATIN CAPITAL LETTER B HOOK;;;0253;
+0182;LATIN CAPITAL LETTER B WITH TOPBAR;Lu;0;L;;;;;N;LATIN CAPITAL LETTER B TOPBAR;;;0183;
+0183;LATIN SMALL LETTER B WITH TOPBAR;Ll;0;L;;;;;N;LATIN SMALL LETTER B TOPBAR;;0182;;0182
+0184;LATIN CAPITAL LETTER TONE SIX;Lu;0;L;;;;;N;;;;0185;
+0185;LATIN SMALL LETTER TONE SIX;Ll;0;L;;;;;N;;;0184;;0184
+0186;LATIN CAPITAL LETTER OPEN O;Lu;0;L;;;;;N;;;;0254;
+0187;LATIN CAPITAL LETTER C WITH HOOK;Lu;0;L;;;;;N;LATIN CAPITAL LETTER C HOOK;;;0188;
+0188;LATIN SMALL LETTER C WITH HOOK;Ll;0;L;;;;;N;LATIN SMALL LETTER C HOOK;;0187;;0187
+0189;LATIN CAPITAL LETTER AFRICAN D;Lu;0;L;;;;;N;;*;;0256;
+018A;LATIN CAPITAL LETTER D WITH HOOK;Lu;0;L;;;;;N;LATIN CAPITAL LETTER D HOOK;;;0257;
+018B;LATIN CAPITAL LETTER D WITH TOPBAR;Lu;0;L;;;;;N;LATIN CAPITAL LETTER D TOPBAR;;;018C;
+018C;LATIN SMALL LETTER D WITH TOPBAR;Ll;0;L;;;;;N;LATIN SMALL LETTER D TOPBAR;;018B;;018B
+018D;LATIN SMALL LETTER TURNED DELTA;Ll;0;L;;;;;N;;;;;
+018E;LATIN CAPITAL LETTER REVERSED E;Lu;0;L;;;;;N;LATIN CAPITAL LETTER TURNED E;;;01DD;
+018F;LATIN CAPITAL LETTER SCHWA;Lu;0;L;;;;;N;;;;0259;
+0190;LATIN CAPITAL LETTER OPEN E;Lu;0;L;;;;;N;LATIN CAPITAL LETTER EPSILON;;;025B;
+0191;LATIN CAPITAL LETTER F WITH HOOK;Lu;0;L;;;;;N;LATIN CAPITAL LETTER F HOOK;;;0192;
+0192;LATIN SMALL LETTER F WITH HOOK;Ll;0;L;;;;;N;LATIN SMALL LETTER SCRIPT F;;0191;;0191
+0193;LATIN CAPITAL LETTER G WITH HOOK;Lu;0;L;;;;;N;LATIN CAPITAL LETTER G HOOK;;;0260;
+0194;LATIN CAPITAL LETTER GAMMA;Lu;0;L;;;;;N;;;;0263;
+0195;LATIN SMALL LETTER HV;Ll;0;L;;;;;N;LATIN SMALL LETTER H V;hwair;01F6;;01F6
+0196;LATIN CAPITAL LETTER IOTA;Lu;0;L;;;;;N;;;;0269;
+0197;LATIN CAPITAL LETTER I WITH STROKE;Lu;0;L;;;;;N;LATIN CAPITAL LETTER BARRED I;;;0268;
+0198;LATIN CAPITAL LETTER K WITH HOOK;Lu;0;L;;;;;N;LATIN CAPITAL LETTER K HOOK;;;0199;
+0199;LATIN SMALL LETTER K WITH HOOK;Ll;0;L;;;;;N;LATIN SMALL LETTER K HOOK;;0198;;0198
+019A;LATIN SMALL LETTER L WITH BAR;Ll;0;L;;;;;N;LATIN SMALL LETTER BARRED L;;023D;;023D
+019B;LATIN SMALL LETTER LAMBDA WITH STROKE;Ll;0;L;;;;;N;LATIN SMALL LETTER BARRED LAMBDA;;;;
+019C;LATIN CAPITAL LETTER TURNED M;Lu;0;L;;;;;N;;;;026F;
+019D;LATIN CAPITAL LETTER N WITH LEFT HOOK;Lu;0;L;;;;;N;LATIN CAPITAL LETTER N HOOK;;;0272;
+019E;LATIN SMALL LETTER N WITH LONG RIGHT LEG;Ll;0;L;;;;;N;;;0220;;0220
+019F;LATIN CAPITAL LETTER O WITH MIDDLE TILDE;Lu;0;L;;;;;N;LATIN CAPITAL LETTER BARRED O;*;;0275;
+01A0;LATIN CAPITAL LETTER O WITH HORN;Lu;0;L;004F 031B;;;;N;LATIN CAPITAL LETTER O HORN;;;01A1;
+01A1;LATIN SMALL LETTER O WITH HORN;Ll;0;L;006F 031B;;;;N;LATIN SMALL LETTER O HORN;;01A0;;01A0
+01A2;LATIN CAPITAL LETTER OI;Lu;0;L;;;;;N;LATIN CAPITAL LETTER O I;gha;;01A3;
+01A3;LATIN SMALL LETTER OI;Ll;0;L;;;;;N;LATIN SMALL LETTER O I;gha;01A2;;01A2
+01A4;LATIN CAPITAL LETTER P WITH HOOK;Lu;0;L;;;;;N;LATIN CAPITAL LETTER P HOOK;;;01A5;
+01A5;LATIN SMALL LETTER P WITH HOOK;Ll;0;L;;;;;N;LATIN SMALL LETTER P HOOK;;01A4;;01A4
+01A6;LATIN LETTER YR;Lu;0;L;;;;;N;LATIN LETTER Y R;*;;0280;
+01A7;LATIN CAPITAL LETTER TONE TWO;Lu;0;L;;;;;N;;;;01A8;
+01A8;LATIN SMALL LETTER TONE TWO;Ll;0;L;;;;;N;;;01A7;;01A7
+01A9;LATIN CAPITAL LETTER ESH;Lu;0;L;;;;;N;;;;0283;
+01AA;LATIN LETTER REVERSED ESH LOOP;Ll;0;L;;;;;N;;;;;
+01AB;LATIN SMALL LETTER T WITH PALATAL HOOK;Ll;0;L;;;;;N;LATIN SMALL LETTER T PALATAL HOOK;;;;
+01AC;LATIN CAPITAL LETTER T WITH HOOK;Lu;0;L;;;;;N;LATIN CAPITAL LETTER T HOOK;;;01AD;
+01AD;LATIN SMALL LETTER T WITH HOOK;Ll;0;L;;;;;N;LATIN SMALL LETTER T HOOK;;01AC;;01AC
+01AE;LATIN CAPITAL LETTER T WITH RETROFLEX HOOK;Lu;0;L;;;;;N;LATIN CAPITAL LETTER T RETROFLEX HOOK;;;0288;
+01AF;LATIN CAPITAL LETTER U WITH HORN;Lu;0;L;0055 031B;;;;N;LATIN CAPITAL LETTER U HORN;;;01B0;
+01B0;LATIN SMALL LETTER U WITH HORN;Ll;0;L;0075 031B;;;;N;LATIN SMALL LETTER U HORN;;01AF;;01AF
+01B1;LATIN CAPITAL LETTER UPSILON;Lu;0;L;;;;;N;;;;028A;
+01B2;LATIN CAPITAL LETTER V WITH HOOK;Lu;0;L;;;;;N;LATIN CAPITAL LETTER SCRIPT V;;;028B;
+01B3;LATIN CAPITAL LETTER Y WITH HOOK;Lu;0;L;;;;;N;LATIN CAPITAL LETTER Y HOOK;;;01B4;
+01B4;LATIN SMALL LETTER Y WITH HOOK;Ll;0;L;;;;;N;LATIN SMALL LETTER Y HOOK;;01B3;;01B3
+01B5;LATIN CAPITAL LETTER Z WITH STROKE;Lu;0;L;;;;;N;LATIN CAPITAL LETTER Z BAR;;;01B6;
+01B6;LATIN SMALL LETTER Z WITH STROKE;Ll;0;L;;;;;N;LATIN SMALL LETTER Z BAR;;01B5;;01B5
+01B7;LATIN CAPITAL LETTER EZH;Lu;0;L;;;;;N;LATIN CAPITAL LETTER YOGH;;;0292;
+01B8;LATIN CAPITAL LETTER EZH REVERSED;Lu;0;L;;;;;N;LATIN CAPITAL LETTER REVERSED YOGH;;;01B9;
+01B9;LATIN SMALL LETTER EZH REVERSED;Ll;0;L;;;;;N;LATIN SMALL LETTER REVERSED YOGH;;01B8;;01B8
+01BA;LATIN SMALL LETTER EZH WITH TAIL;Ll;0;L;;;;;N;LATIN SMALL LETTER YOGH WITH TAIL;;;;
+01BB;LATIN LETTER TWO WITH STROKE;Lo;0;L;;;;;N;LATIN LETTER TWO BAR;;;;
+01BC;LATIN CAPITAL LETTER TONE FIVE;Lu;0;L;;;;;N;;;;01BD;
+01BD;LATIN SMALL LETTER TONE FIVE;Ll;0;L;;;;;N;;;01BC;;01BC
+01BE;LATIN LETTER INVERTED GLOTTAL STOP WITH STROKE;Ll;0;L;;;;;N;LATIN LETTER INVERTED GLOTTAL STOP BAR;;;;
+01BF;LATIN LETTER WYNN;Ll;0;L;;;;;N;;;01F7;;01F7
+01C0;LATIN LETTER DENTAL CLICK;Lo;0;L;;;;;N;LATIN LETTER PIPE;;;;
+01C1;LATIN LETTER LATERAL CLICK;Lo;0;L;;;;;N;LATIN LETTER DOUBLE PIPE;;;;
+01C2;LATIN LETTER ALVEOLAR CLICK;Lo;0;L;;;;;N;LATIN LETTER PIPE DOUBLE BAR;;;;
+01C3;LATIN LETTER RETROFLEX CLICK;Lo;0;L;;;;;N;LATIN LETTER EXCLAMATION MARK;;;;
+01C4;LATIN CAPITAL LETTER DZ WITH CARON;Lu;0;L;<compat> 0044 017D;;;;N;LATIN CAPITAL LETTER D Z HACEK;;;01C6;01C5
+01C5;LATIN CAPITAL LETTER D WITH SMALL LETTER Z WITH CARON;Lt;0;L;<compat> 0044 017E;;;;N;LATIN LETTER CAPITAL D SMALL Z HACEK;;01C4;01C6;01C5
+01C6;LATIN SMALL LETTER DZ WITH CARON;Ll;0;L;<compat> 0064 017E;;;;N;LATIN SMALL LETTER D Z HACEK;;01C4;;01C5
+01C7;LATIN CAPITAL LETTER LJ;Lu;0;L;<compat> 004C 004A;;;;N;LATIN CAPITAL LETTER L J;;;01C9;01C8
+01C8;LATIN CAPITAL LETTER L WITH SMALL LETTER J;Lt;0;L;<compat> 004C 006A;;;;N;LATIN LETTER CAPITAL L SMALL J;;01C7;01C9;01C8
+01C9;LATIN SMALL LETTER LJ;Ll;0;L;<compat> 006C 006A;;;;N;LATIN SMALL LETTER L J;;01C7;;01C8
+01CA;LATIN CAPITAL LETTER NJ;Lu;0;L;<compat> 004E 004A;;;;N;LATIN CAPITAL LETTER N J;;;01CC;01CB
+01CB;LATIN CAPITAL LETTER N WITH SMALL LETTER J;Lt;0;L;<compat> 004E 006A;;;;N;LATIN LETTER CAPITAL N SMALL J;;01CA;01CC;01CB
+01CC;LATIN SMALL LETTER NJ;Ll;0;L;<compat> 006E 006A;;;;N;LATIN SMALL LETTER N J;;01CA;;01CB
+01CD;LATIN CAPITAL LETTER A WITH CARON;Lu;0;L;0041 030C;;;;N;LATIN CAPITAL LETTER A HACEK;;;01CE;
+01CE;LATIN SMALL LETTER A WITH CARON;Ll;0;L;0061 030C;;;;N;LATIN SMALL LETTER A HACEK;;01CD;;01CD
+01CF;LATIN CAPITAL LETTER I WITH CARON;Lu;0;L;0049 030C;;;;N;LATIN CAPITAL LETTER I HACEK;;;01D0;
+01D0;LATIN SMALL LETTER I WITH CARON;Ll;0;L;0069 030C;;;;N;LATIN SMALL LETTER I HACEK;;01CF;;01CF
+01D1;LATIN CAPITAL LETTER O WITH CARON;Lu;0;L;004F 030C;;;;N;LATIN CAPITAL LETTER O HACEK;;;01D2;
+01D2;LATIN SMALL LETTER O WITH CARON;Ll;0;L;006F 030C;;;;N;LATIN SMALL LETTER O HACEK;;01D1;;01D1
+01D3;LATIN CAPITAL LETTER U WITH CARON;Lu;0;L;0055 030C;;;;N;LATIN CAPITAL LETTER U HACEK;;;01D4;
+01D4;LATIN SMALL LETTER U WITH CARON;Ll;0;L;0075 030C;;;;N;LATIN SMALL LETTER U HACEK;;01D3;;01D3
+01D5;LATIN CAPITAL LETTER U WITH DIAERESIS AND MACRON;Lu;0;L;00DC 0304;;;;N;LATIN CAPITAL LETTER U DIAERESIS MACRON;;;01D6;
+01D6;LATIN SMALL LETTER U WITH DIAERESIS AND MACRON;Ll;0;L;00FC 0304;;;;N;LATIN SMALL LETTER U DIAERESIS MACRON;;01D5;;01D5
+01D7;LATIN CAPITAL LETTER U WITH DIAERESIS AND ACUTE;Lu;0;L;00DC 0301;;;;N;LATIN CAPITAL LETTER U DIAERESIS ACUTE;;;01D8;
+01D8;LATIN SMALL LETTER U WITH DIAERESIS AND ACUTE;Ll;0;L;00FC 0301;;;;N;LATIN SMALL LETTER U DIAERESIS ACUTE;;01D7;;01D7
+01D9;LATIN CAPITAL LETTER U WITH DIAERESIS AND CARON;Lu;0;L;00DC 030C;;;;N;LATIN CAPITAL LETTER U DIAERESIS HACEK;;;01DA;
+01DA;LATIN SMALL LETTER U WITH DIAERESIS AND CARON;Ll;0;L;00FC 030C;;;;N;LATIN SMALL LETTER U DIAERESIS HACEK;;01D9;;01D9
+01DB;LATIN CAPITAL LETTER U WITH DIAERESIS AND GRAVE;Lu;0;L;00DC 0300;;;;N;LATIN CAPITAL LETTER U DIAERESIS GRAVE;;;01DC;
+01DC;LATIN SMALL LETTER U WITH DIAERESIS AND GRAVE;Ll;0;L;00FC 0300;;;;N;LATIN SMALL LETTER U DIAERESIS GRAVE;;01DB;;01DB
+01DD;LATIN SMALL LETTER TURNED E;Ll;0;L;;;;;N;;;018E;;018E
+01DE;LATIN CAPITAL LETTER A WITH DIAERESIS AND MACRON;Lu;0;L;00C4 0304;;;;N;LATIN CAPITAL LETTER A DIAERESIS MACRON;;;01DF;
+01DF;LATIN SMALL LETTER A WITH DIAERESIS AND MACRON;Ll;0;L;00E4 0304;;;;N;LATIN SMALL LETTER A DIAERESIS MACRON;;01DE;;01DE
+01E0;LATIN CAPITAL LETTER A WITH DOT ABOVE AND MACRON;Lu;0;L;0226 0304;;;;N;LATIN CAPITAL LETTER A DOT MACRON;;;01E1;
+01E1;LATIN SMALL LETTER A WITH DOT ABOVE AND MACRON;Ll;0;L;0227 0304;;;;N;LATIN SMALL LETTER A DOT MACRON;;01E0;;01E0
+01E2;LATIN CAPITAL LETTER AE WITH MACRON;Lu;0;L;00C6 0304;;;;N;LATIN CAPITAL LETTER A E MACRON;ash *;;01E3;
+01E3;LATIN SMALL LETTER AE WITH MACRON;Ll;0;L;00E6 0304;;;;N;LATIN SMALL LETTER A E MACRON;ash *;01E2;;01E2
+01E4;LATIN CAPITAL LETTER G WITH STROKE;Lu;0;L;;;;;N;LATIN CAPITAL LETTER G BAR;;;01E5;
+01E5;LATIN SMALL LETTER G WITH STROKE;Ll;0;L;;;;;N;LATIN SMALL LETTER G BAR;;01E4;;01E4
+01E6;LATIN CAPITAL LETTER G WITH CARON;Lu;0;L;0047 030C;;;;N;LATIN CAPITAL LETTER G HACEK;;;01E7;
+01E7;LATIN SMALL LETTER G WITH CARON;Ll;0;L;0067 030C;;;;N;LATIN SMALL LETTER G HACEK;;01E6;;01E6
+01E8;LATIN CAPITAL LETTER K WITH CARON;Lu;0;L;004B 030C;;;;N;LATIN CAPITAL LETTER K HACEK;;;01E9;
+01E9;LATIN SMALL LETTER K WITH CARON;Ll;0;L;006B 030C;;;;N;LATIN SMALL LETTER K HACEK;;01E8;;01E8
+01EA;LATIN CAPITAL LETTER O WITH OGONEK;Lu;0;L;004F 0328;;;;N;LATIN CAPITAL LETTER O OGONEK;;;01EB;
+01EB;LATIN SMALL LETTER O WITH OGONEK;Ll;0;L;006F 0328;;;;N;LATIN SMALL LETTER O OGONEK;;01EA;;01EA
+01EC;LATIN CAPITAL LETTER O WITH OGONEK AND MACRON;Lu;0;L;01EA 0304;;;;N;LATIN CAPITAL LETTER O OGONEK MACRON;;;01ED;
+01ED;LATIN SMALL LETTER O WITH OGONEK AND MACRON;Ll;0;L;01EB 0304;;;;N;LATIN SMALL LETTER O OGONEK MACRON;;01EC;;01EC
+01EE;LATIN CAPITAL LETTER EZH WITH CARON;Lu;0;L;01B7 030C;;;;N;LATIN CAPITAL LETTER YOGH HACEK;;;01EF;
+01EF;LATIN SMALL LETTER EZH WITH CARON;Ll;0;L;0292 030C;;;;N;LATIN SMALL LETTER YOGH HACEK;;01EE;;01EE
+01F0;LATIN SMALL LETTER J WITH CARON;Ll;0;L;006A 030C;;;;N;LATIN SMALL LETTER J HACEK;;;;
+01F1;LATIN CAPITAL LETTER DZ;Lu;0;L;<compat> 0044 005A;;;;N;;;;01F3;01F2
+01F2;LATIN CAPITAL LETTER D WITH SMALL LETTER Z;Lt;0;L;<compat> 0044 007A;;;;N;;;01F1;01F3;01F2
+01F3;LATIN SMALL LETTER DZ;Ll;0;L;<compat> 0064 007A;;;;N;;;01F1;;01F2
+01F4;LATIN CAPITAL LETTER G WITH ACUTE;Lu;0;L;0047 0301;;;;N;;;;01F5;
+01F5;LATIN SMALL LETTER G WITH ACUTE;Ll;0;L;0067 0301;;;;N;;;01F4;;01F4
+01F6;LATIN CAPITAL LETTER HWAIR;Lu;0;L;;;;;N;;;;0195;
+01F7;LATIN CAPITAL LETTER WYNN;Lu;0;L;;;;;N;;;;01BF;
+01F8;LATIN CAPITAL LETTER N WITH GRAVE;Lu;0;L;004E 0300;;;;N;;;;01F9;
+01F9;LATIN SMALL LETTER N WITH GRAVE;Ll;0;L;006E 0300;;;;N;;;01F8;;01F8
+01FA;LATIN CAPITAL LETTER A WITH RING ABOVE AND ACUTE;Lu;0;L;00C5 0301;;;;N;;;;01FB;
+01FB;LATIN SMALL LETTER A WITH RING ABOVE AND ACUTE;Ll;0;L;00E5 0301;;;;N;;;01FA;;01FA
+01FC;LATIN CAPITAL LETTER AE WITH ACUTE;Lu;0;L;00C6 0301;;;;N;;ash *;;01FD;
+01FD;LATIN SMALL LETTER AE WITH ACUTE;Ll;0;L;00E6 0301;;;;N;;ash *;01FC;;01FC
+01FE;LATIN CAPITAL LETTER O WITH STROKE AND ACUTE;Lu;0;L;00D8 0301;;;;N;;;;01FF;
+01FF;LATIN SMALL LETTER O WITH STROKE AND ACUTE;Ll;0;L;00F8 0301;;;;N;;;01FE;;01FE
+0200;LATIN CAPITAL LETTER A WITH DOUBLE GRAVE;Lu;0;L;0041 030F;;;;N;;;;0201;
+0201;LATIN SMALL LETTER A WITH DOUBLE GRAVE;Ll;0;L;0061 030F;;;;N;;;0200;;0200
+0202;LATIN CAPITAL LETTER A WITH INVERTED BREVE;Lu;0;L;0041 0311;;;;N;;;;0203;
+0203;LATIN SMALL LETTER A WITH INVERTED BREVE;Ll;0;L;0061 0311;;;;N;;;0202;;0202
+0204;LATIN CAPITAL LETTER E WITH DOUBLE GRAVE;Lu;0;L;0045 030F;;;;N;;;;0205;
+0205;LATIN SMALL LETTER E WITH DOUBLE GRAVE;Ll;0;L;0065 030F;;;;N;;;0204;;0204
+0206;LATIN CAPITAL LETTER E WITH INVERTED BREVE;Lu;0;L;0045 0311;;;;N;;;;0207;
+0207;LATIN SMALL LETTER E WITH INVERTED BREVE;Ll;0;L;0065 0311;;;;N;;;0206;;0206
+0208;LATIN CAPITAL LETTER I WITH DOUBLE GRAVE;Lu;0;L;0049 030F;;;;N;;;;0209;
+0209;LATIN SMALL LETTER I WITH DOUBLE GRAVE;Ll;0;L;0069 030F;;;;N;;;0208;;0208
+020A;LATIN CAPITAL LETTER I WITH INVERTED BREVE;Lu;0;L;0049 0311;;;;N;;;;020B;
+020B;LATIN SMALL LETTER I WITH INVERTED BREVE;Ll;0;L;0069 0311;;;;N;;;020A;;020A
+020C;LATIN CAPITAL LETTER O WITH DOUBLE GRAVE;Lu;0;L;004F 030F;;;;N;;;;020D;
+020D;LATIN SMALL LETTER O WITH DOUBLE GRAVE;Ll;0;L;006F 030F;;;;N;;;020C;;020C
+020E;LATIN CAPITAL LETTER O WITH INVERTED BREVE;Lu;0;L;004F 0311;;;;N;;;;020F;
+020F;LATIN SMALL LETTER O WITH INVERTED BREVE;Ll;0;L;006F 0311;;;;N;;;020E;;020E
+0210;LATIN CAPITAL LETTER R WITH DOUBLE GRAVE;Lu;0;L;0052 030F;;;;N;;;;0211;
+0211;LATIN SMALL LETTER R WITH DOUBLE GRAVE;Ll;0;L;0072 030F;;;;N;;;0210;;0210
+0212;LATIN CAPITAL LETTER R WITH INVERTED BREVE;Lu;0;L;0052 0311;;;;N;;;;0213;
+0213;LATIN SMALL LETTER R WITH INVERTED BREVE;Ll;0;L;0072 0311;;;;N;;;0212;;0212
+0214;LATIN CAPITAL LETTER U WITH DOUBLE GRAVE;Lu;0;L;0055 030F;;;;N;;;;0215;
+0215;LATIN SMALL LETTER U WITH DOUBLE GRAVE;Ll;0;L;0075 030F;;;;N;;;0214;;0214
+0216;LATIN CAPITAL LETTER U WITH INVERTED BREVE;Lu;0;L;0055 0311;;;;N;;;;0217;
+0217;LATIN SMALL LETTER U WITH INVERTED BREVE;Ll;0;L;0075 0311;;;;N;;;0216;;0216
+0218;LATIN CAPITAL LETTER S WITH COMMA BELOW;Lu;0;L;0053 0326;;;;N;;*;;0219;
+0219;LATIN SMALL LETTER S WITH COMMA BELOW;Ll;0;L;0073 0326;;;;N;;*;0218;;0218
+021A;LATIN CAPITAL LETTER T WITH COMMA BELOW;Lu;0;L;0054 0326;;;;N;;*;;021B;
+021B;LATIN SMALL LETTER T WITH COMMA BELOW;Ll;0;L;0074 0326;;;;N;;*;021A;;021A
+021C;LATIN CAPITAL LETTER YOGH;Lu;0;L;;;;;N;;;;021D;
+021D;LATIN SMALL LETTER YOGH;Ll;0;L;;;;;N;;;021C;;021C
+021E;LATIN CAPITAL LETTER H WITH CARON;Lu;0;L;0048 030C;;;;N;;;;021F;
+021F;LATIN SMALL LETTER H WITH CARON;Ll;0;L;0068 030C;;;;N;;;021E;;021E
+0220;LATIN CAPITAL LETTER N WITH LONG RIGHT LEG;Lu;0;L;;;;;N;;;;019E;
+0221;LATIN SMALL LETTER D WITH CURL;Ll;0;L;;;;;N;;;;;
+0222;LATIN CAPITAL LETTER OU;Lu;0;L;;;;;N;;;;0223;
+0223;LATIN SMALL LETTER OU;Ll;0;L;;;;;N;;;0222;;0222
+0224;LATIN CAPITAL LETTER Z WITH HOOK;Lu;0;L;;;;;N;;;;0225;
+0225;LATIN SMALL LETTER Z WITH HOOK;Ll;0;L;;;;;N;;;0224;;0224
+0226;LATIN CAPITAL LETTER A WITH DOT ABOVE;Lu;0;L;0041 0307;;;;N;;;;0227;
+0227;LATIN SMALL LETTER A WITH DOT ABOVE;Ll;0;L;0061 0307;;;;N;;;0226;;0226
+0228;LATIN CAPITAL LETTER E WITH CEDILLA;Lu;0;L;0045 0327;;;;N;;;;0229;
+0229;LATIN SMALL LETTER E WITH CEDILLA;Ll;0;L;0065 0327;;;;N;;;0228;;0228
+022A;LATIN CAPITAL LETTER O WITH DIAERESIS AND MACRON;Lu;0;L;00D6 0304;;;;N;;;;022B;
+022B;LATIN SMALL LETTER O WITH DIAERESIS AND MACRON;Ll;0;L;00F6 0304;;;;N;;;022A;;022A
+022C;LATIN CAPITAL LETTER O WITH TILDE AND MACRON;Lu;0;L;00D5 0304;;;;N;;;;022D;
+022D;LATIN SMALL LETTER O WITH TILDE AND MACRON;Ll;0;L;00F5 0304;;;;N;;;022C;;022C
+022E;LATIN CAPITAL LETTER O WITH DOT ABOVE;Lu;0;L;004F 0307;;;;N;;;;022F;
+022F;LATIN SMALL LETTER O WITH DOT ABOVE;Ll;0;L;006F 0307;;;;N;;;022E;;022E
+0230;LATIN CAPITAL LETTER O WITH DOT ABOVE AND MACRON;Lu;0;L;022E 0304;;;;N;;;;0231;
+0231;LATIN SMALL LETTER O WITH DOT ABOVE AND MACRON;Ll;0;L;022F 0304;;;;N;;;0230;;0230
+0232;LATIN CAPITAL LETTER Y WITH MACRON;Lu;0;L;0059 0304;;;;N;;;;0233;
+0233;LATIN SMALL LETTER Y WITH MACRON;Ll;0;L;0079 0304;;;;N;;;0232;;0232
+0234;LATIN SMALL LETTER L WITH CURL;Ll;0;L;;;;;N;;;;;
+0235;LATIN SMALL LETTER N WITH CURL;Ll;0;L;;;;;N;;;;;
+0236;LATIN SMALL LETTER T WITH CURL;Ll;0;L;;;;;N;;;;;
+0237;LATIN SMALL LETTER DOTLESS J;Ll;0;L;;;;;N;;;;;
+0238;LATIN SMALL LETTER DB DIGRAPH;Ll;0;L;;;;;N;;;;;
+0239;LATIN SMALL LETTER QP DIGRAPH;Ll;0;L;;;;;N;;;;;
+023A;LATIN CAPITAL LETTER A WITH STROKE;Lu;0;L;;;;;N;;;;;
+023B;LATIN CAPITAL LETTER C WITH STROKE;Lu;0;L;;;;;N;;;;023C;
+023C;LATIN SMALL LETTER C WITH STROKE;Ll;0;L;;;;;N;;;023B;;023B
+023D;LATIN CAPITAL LETTER L WITH BAR;Lu;0;L;;;;;N;;;;019A;
+023E;LATIN CAPITAL LETTER T WITH DIAGONAL STROKE;Lu;0;L;;;;;N;;;;;
+023F;LATIN SMALL LETTER S WITH SWASH TAIL;Ll;0;L;;;;;N;;;;;
+0240;LATIN SMALL LETTER Z WITH SWASH TAIL;Ll;0;L;;;;;N;;;;;
+0241;LATIN CAPITAL LETTER GLOTTAL STOP;Lu;0;L;;;;;N;;;;0294;
+0250;LATIN SMALL LETTER TURNED A;Ll;0;L;;;;;N;;;;;
+0251;LATIN SMALL LETTER ALPHA;Ll;0;L;;;;;N;LATIN SMALL LETTER SCRIPT A;;;;
+0252;LATIN SMALL LETTER TURNED ALPHA;Ll;0;L;;;;;N;LATIN SMALL LETTER TURNED SCRIPT A;;;;
+0253;LATIN SMALL LETTER B WITH HOOK;Ll;0;L;;;;;N;LATIN SMALL LETTER B HOOK;;0181;;0181
+0254;LATIN SMALL LETTER OPEN O;Ll;0;L;;;;;N;;;0186;;0186
+0255;LATIN SMALL LETTER C WITH CURL;Ll;0;L;;;;;N;LATIN SMALL LETTER C CURL;;;;
+0256;LATIN SMALL LETTER D WITH TAIL;Ll;0;L;;;;;N;LATIN SMALL LETTER D RETROFLEX HOOK;;0189;;0189
+0257;LATIN SMALL LETTER D WITH HOOK;Ll;0;L;;;;;N;LATIN SMALL LETTER D HOOK;;018A;;018A
+0258;LATIN SMALL LETTER REVERSED E;Ll;0;L;;;;;N;;;;;
+0259;LATIN SMALL LETTER SCHWA;Ll;0;L;;;;;N;;;018F;;018F
+025A;LATIN SMALL LETTER SCHWA WITH HOOK;Ll;0;L;;;;;N;LATIN SMALL LETTER SCHWA HOOK;;;;
+025B;LATIN SMALL LETTER OPEN E;Ll;0;L;;;;;N;LATIN SMALL LETTER EPSILON;;0190;;0190
+025C;LATIN SMALL LETTER REVERSED OPEN E;Ll;0;L;;;;;N;LATIN SMALL LETTER REVERSED EPSILON;;;;
+025D;LATIN SMALL LETTER REVERSED OPEN E WITH HOOK;Ll;0;L;;;;;N;LATIN SMALL LETTER REVERSED EPSILON HOOK;;;;
+025E;LATIN SMALL LETTER CLOSED REVERSED OPEN E;Ll;0;L;;;;;N;LATIN SMALL LETTER CLOSED REVERSED EPSILON;;;;
+025F;LATIN SMALL LETTER DOTLESS J WITH STROKE;Ll;0;L;;;;;N;LATIN SMALL LETTER DOTLESS J BAR;;;;
+0260;LATIN SMALL LETTER G WITH HOOK;Ll;0;L;;;;;N;LATIN SMALL LETTER G HOOK;;0193;;0193
+0261;LATIN SMALL LETTER SCRIPT G;Ll;0;L;;;;;N;;;;;
+0262;LATIN LETTER SMALL CAPITAL G;Ll;0;L;;;;;N;;;;;
+0263;LATIN SMALL LETTER GAMMA;Ll;0;L;;;;;N;;;0194;;0194
+0264;LATIN SMALL LETTER RAMS HORN;Ll;0;L;;;;;N;LATIN SMALL LETTER BABY GAMMA;;;;
+0265;LATIN SMALL LETTER TURNED H;Ll;0;L;;;;;N;;;;;
+0266;LATIN SMALL LETTER H WITH HOOK;Ll;0;L;;;;;N;LATIN SMALL LETTER H HOOK;;;;
+0267;LATIN SMALL LETTER HENG WITH HOOK;Ll;0;L;;;;;N;LATIN SMALL LETTER HENG HOOK;;;;
+0268;LATIN SMALL LETTER I WITH STROKE;Ll;0;L;;;;;N;LATIN SMALL LETTER BARRED I;;0197;;0197
+0269;LATIN SMALL LETTER IOTA;Ll;0;L;;;;;N;;;0196;;0196
+026A;LATIN LETTER SMALL CAPITAL I;Ll;0;L;;;;;N;;;;;
+026B;LATIN SMALL LETTER L WITH MIDDLE TILDE;Ll;0;L;;;;;N;;;;;
+026C;LATIN SMALL LETTER L WITH BELT;Ll;0;L;;;;;N;LATIN SMALL LETTER L BELT;;;;
+026D;LATIN SMALL LETTER L WITH RETROFLEX HOOK;Ll;0;L;;;;;N;LATIN SMALL LETTER L RETROFLEX HOOK;;;;
+026E;LATIN SMALL LETTER LEZH;Ll;0;L;;;;;N;LATIN SMALL LETTER L YOGH;;;;
+026F;LATIN SMALL LETTER TURNED M;Ll;0;L;;;;;N;;;019C;;019C
+0270;LATIN SMALL LETTER TURNED M WITH LONG LEG;Ll;0;L;;;;;N;;;;;
+0271;LATIN SMALL LETTER M WITH HOOK;Ll;0;L;;;;;N;LATIN SMALL LETTER M HOOK;;;;
+0272;LATIN SMALL LETTER N WITH LEFT HOOK;Ll;0;L;;;;;N;LATIN SMALL LETTER N HOOK;;019D;;019D
+0273;LATIN SMALL LETTER N WITH RETROFLEX HOOK;Ll;0;L;;;;;N;LATIN SMALL LETTER N RETROFLEX HOOK;;;;
+0274;LATIN LETTER SMALL CAPITAL N;Ll;0;L;;;;;N;;;;;
+0275;LATIN SMALL LETTER BARRED O;Ll;0;L;;;;;N;;;019F;;019F
+0276;LATIN LETTER SMALL CAPITAL OE;Ll;0;L;;;;;N;LATIN LETTER SMALL CAPITAL O E;;;;
+0277;LATIN SMALL LETTER CLOSED OMEGA;Ll;0;L;;;;;N;;;;;
+0278;LATIN SMALL LETTER PHI;Ll;0;L;;;;;N;;;;;
+0279;LATIN SMALL LETTER TURNED R;Ll;0;L;;;;;N;;;;;
+027A;LATIN SMALL LETTER TURNED R WITH LONG LEG;Ll;0;L;;;;;N;;;;;
+027B;LATIN SMALL LETTER TURNED R WITH HOOK;Ll;0;L;;;;;N;LATIN SMALL LETTER TURNED R HOOK;;;;
+027C;LATIN SMALL LETTER R WITH LONG LEG;Ll;0;L;;;;;N;;;;;
+027D;LATIN SMALL LETTER R WITH TAIL;Ll;0;L;;;;;N;LATIN SMALL LETTER R HOOK;;;;
+027E;LATIN SMALL LETTER R WITH FISHHOOK;Ll;0;L;;;;;N;LATIN SMALL LETTER FISHHOOK R;;;;
+027F;LATIN SMALL LETTER REVERSED R WITH FISHHOOK;Ll;0;L;;;;;N;LATIN SMALL LETTER REVERSED FISHHOOK R;;;;
+0280;LATIN LETTER SMALL CAPITAL R;Ll;0;L;;;;;N;;*;01A6;;01A6
+0281;LATIN LETTER SMALL CAPITAL INVERTED R;Ll;0;L;;;;;N;;;;;
+0282;LATIN SMALL LETTER S WITH HOOK;Ll;0;L;;;;;N;LATIN SMALL LETTER S HOOK;;;;
+0283;LATIN SMALL LETTER ESH;Ll;0;L;;;;;N;;;01A9;;01A9
+0284;LATIN SMALL LETTER DOTLESS J WITH STROKE AND HOOK;Ll;0;L;;;;;N;LATIN SMALL LETTER DOTLESS J BAR HOOK;;;;
+0285;LATIN SMALL LETTER SQUAT REVERSED ESH;Ll;0;L;;;;;N;;;;;
+0286;LATIN SMALL LETTER ESH WITH CURL;Ll;0;L;;;;;N;LATIN SMALL LETTER ESH CURL;;;;
+0287;LATIN SMALL LETTER TURNED T;Ll;0;L;;;;;N;;;;;
+0288;LATIN SMALL LETTER T WITH RETROFLEX HOOK;Ll;0;L;;;;;N;LATIN SMALL LETTER T RETROFLEX HOOK;;01AE;;01AE
+0289;LATIN SMALL LETTER U BAR;Ll;0;L;;;;;N;;;;;
+028A;LATIN SMALL LETTER UPSILON;Ll;0;L;;;;;N;;;01B1;;01B1
+028B;LATIN SMALL LETTER V WITH HOOK;Ll;0;L;;;;;N;LATIN SMALL LETTER SCRIPT V;;01B2;;01B2
+028C;LATIN SMALL LETTER TURNED V;Ll;0;L;;;;;N;;;;;
+028D;LATIN SMALL LETTER TURNED W;Ll;0;L;;;;;N;;;;;
+028E;LATIN SMALL LETTER TURNED Y;Ll;0;L;;;;;N;;;;;
+028F;LATIN LETTER SMALL CAPITAL Y;Ll;0;L;;;;;N;;;;;
+0290;LATIN SMALL LETTER Z WITH RETROFLEX HOOK;Ll;0;L;;;;;N;LATIN SMALL LETTER Z RETROFLEX HOOK;;;;
+0291;LATIN SMALL LETTER Z WITH CURL;Ll;0;L;;;;;N;LATIN SMALL LETTER Z CURL;;;;
+0292;LATIN SMALL LETTER EZH;Ll;0;L;;;;;N;LATIN SMALL LETTER YOGH;;01B7;;01B7
+0293;LATIN SMALL LETTER EZH WITH CURL;Ll;0;L;;;;;N;LATIN SMALL LETTER YOGH CURL;;;;
+0294;LATIN LETTER GLOTTAL STOP;Ll;0;L;;;;;N;;;0241;;0241
+0295;LATIN LETTER PHARYNGEAL VOICED FRICATIVE;Ll;0;L;;;;;N;LATIN LETTER REVERSED GLOTTAL STOP;;;;
+0296;LATIN LETTER INVERTED GLOTTAL STOP;Ll;0;L;;;;;N;;;;;
+0297;LATIN LETTER STRETCHED C;Ll;0;L;;;;;N;;;;;
+0298;LATIN LETTER BILABIAL CLICK;Ll;0;L;;;;;N;LATIN LETTER BULLSEYE;;;;
+0299;LATIN LETTER SMALL CAPITAL B;Ll;0;L;;;;;N;;;;;
+029A;LATIN SMALL LETTER CLOSED OPEN E;Ll;0;L;;;;;N;LATIN SMALL LETTER CLOSED EPSILON;;;;
+029B;LATIN LETTER SMALL CAPITAL G WITH HOOK;Ll;0;L;;;;;N;LATIN LETTER SMALL CAPITAL G HOOK;;;;
+029C;LATIN LETTER SMALL CAPITAL H;Ll;0;L;;;;;N;;;;;
+029D;LATIN SMALL LETTER J WITH CROSSED-TAIL;Ll;0;L;;;;;N;LATIN SMALL LETTER CROSSED-TAIL J;;;;
+029E;LATIN SMALL LETTER TURNED K;Ll;0;L;;;;;N;;;;;
+029F;LATIN LETTER SMALL CAPITAL L;Ll;0;L;;;;;N;;;;;
+02A0;LATIN SMALL LETTER Q WITH HOOK;Ll;0;L;;;;;N;LATIN SMALL LETTER Q HOOK;;;;
+02A1;LATIN LETTER GLOTTAL STOP WITH STROKE;Ll;0;L;;;;;N;LATIN LETTER GLOTTAL STOP BAR;;;;
+02A2;LATIN LETTER REVERSED GLOTTAL STOP WITH STROKE;Ll;0;L;;;;;N;LATIN LETTER REVERSED GLOTTAL STOP BAR;;;;
+02A3;LATIN SMALL LETTER DZ DIGRAPH;Ll;0;L;;;;;N;LATIN SMALL LETTER D Z;;;;
+02A4;LATIN SMALL LETTER DEZH DIGRAPH;Ll;0;L;;;;;N;LATIN SMALL LETTER D YOGH;;;;
+02A5;LATIN SMALL LETTER DZ DIGRAPH WITH CURL;Ll;0;L;;;;;N;LATIN SMALL LETTER D Z CURL;;;;
+02A6;LATIN SMALL LETTER TS DIGRAPH;Ll;0;L;;;;;N;LATIN SMALL LETTER T S;;;;
+02A7;LATIN SMALL LETTER TESH DIGRAPH;Ll;0;L;;;;;N;LATIN SMALL LETTER T ESH;;;;
+02A8;LATIN SMALL LETTER TC DIGRAPH WITH CURL;Ll;0;L;;;;;N;LATIN SMALL LETTER T C CURL;;;;
+02A9;LATIN SMALL LETTER FENG DIGRAPH;Ll;0;L;;;;;N;;;;;
+02AA;LATIN SMALL LETTER LS DIGRAPH;Ll;0;L;;;;;N;;;;;
+02AB;LATIN SMALL LETTER LZ DIGRAPH;Ll;0;L;;;;;N;;;;;
+02AC;LATIN LETTER BILABIAL PERCUSSIVE;Ll;0;L;;;;;N;;;;;
+02AD;LATIN LETTER BIDENTAL PERCUSSIVE;Ll;0;L;;;;;N;;;;;
+02AE;LATIN SMALL LETTER TURNED H WITH FISHHOOK;Ll;0;L;;;;;N;;;;;
+02AF;LATIN SMALL LETTER TURNED H WITH FISHHOOK AND TAIL;Ll;0;L;;;;;N;;;;;
+02B0;MODIFIER LETTER SMALL H;Lm;0;L;<super> 0068;;;;N;;;;;
+02B1;MODIFIER LETTER SMALL H WITH HOOK;Lm;0;L;<super> 0266;;;;N;MODIFIER LETTER SMALL H HOOK;;;;
+02B2;MODIFIER LETTER SMALL J;Lm;0;L;<super> 006A;;;;N;;;;;
+02B3;MODIFIER LETTER SMALL R;Lm;0;L;<super> 0072;;;;N;;;;;
+02B4;MODIFIER LETTER SMALL TURNED R;Lm;0;L;<super> 0279;;;;N;;;;;
+02B5;MODIFIER LETTER SMALL TURNED R WITH HOOK;Lm;0;L;<super> 027B;;;;N;MODIFIER LETTER SMALL TURNED R HOOK;;;;
+02B6;MODIFIER LETTER SMALL CAPITAL INVERTED R;Lm;0;L;<super> 0281;;;;N;;;;;
+02B7;MODIFIER LETTER SMALL W;Lm;0;L;<super> 0077;;;;N;;;;;
+02B8;MODIFIER LETTER SMALL Y;Lm;0;L;<super> 0079;;;;N;;;;;
+02B9;MODIFIER LETTER PRIME;Lm;0;ON;;;;;N;;;;;
+02BA;MODIFIER LETTER DOUBLE PRIME;Lm;0;ON;;;;;N;;;;;
+02BB;MODIFIER LETTER TURNED COMMA;Lm;0;L;;;;;N;;;;;
+02BC;MODIFIER LETTER APOSTROPHE;Lm;0;L;;;;;N;;;;;
+02BD;MODIFIER LETTER REVERSED COMMA;Lm;0;L;;;;;N;;;;;
+02BE;MODIFIER LETTER RIGHT HALF RING;Lm;0;L;;;;;N;;;;;
+02BF;MODIFIER LETTER LEFT HALF RING;Lm;0;L;;;;;N;;;;;
+02C0;MODIFIER LETTER GLOTTAL STOP;Lm;0;L;;;;;N;;;;;
+02C1;MODIFIER LETTER REVERSED GLOTTAL STOP;Lm;0;L;;;;;N;;;;;
+02C2;MODIFIER LETTER LEFT ARROWHEAD;Sk;0;ON;;;;;N;;;;;
+02C3;MODIFIER LETTER RIGHT ARROWHEAD;Sk;0;ON;;;;;N;;;;;
+02C4;MODIFIER LETTER UP ARROWHEAD;Sk;0;ON;;;;;N;;;;;
+02C5;MODIFIER LETTER DOWN ARROWHEAD;Sk;0;ON;;;;;N;;;;;
+02C6;MODIFIER LETTER CIRCUMFLEX ACCENT;Lm;0;ON;;;;;N;MODIFIER LETTER CIRCUMFLEX;;;;
+02C7;CARON;Lm;0;ON;;;;;N;MODIFIER LETTER HACEK;Mandarin Chinese third tone;;;
+02C8;MODIFIER LETTER VERTICAL LINE;Lm;0;ON;;;;;N;;;;;
+02C9;MODIFIER LETTER MACRON;Lm;0;ON;;;;;N;;Mandarin Chinese first tone;;;
+02CA;MODIFIER LETTER ACUTE ACCENT;Lm;0;ON;;;;;N;MODIFIER LETTER ACUTE;Mandarin Chinese second tone;;;
+02CB;MODIFIER LETTER GRAVE ACCENT;Lm;0;ON;;;;;N;MODIFIER LETTER GRAVE;Mandarin Chinese fourth tone;;;
+02CC;MODIFIER LETTER LOW VERTICAL LINE;Lm;0;ON;;;;;N;;;;;
+02CD;MODIFIER LETTER LOW MACRON;Lm;0;ON;;;;;N;;;;;
+02CE;MODIFIER LETTER LOW GRAVE ACCENT;Lm;0;ON;;;;;N;MODIFIER LETTER LOW GRAVE;;;;
+02CF;MODIFIER LETTER LOW ACUTE ACCENT;Lm;0;ON;;;;;N;MODIFIER LETTER LOW ACUTE;;;;
+02D0;MODIFIER LETTER TRIANGULAR COLON;Lm;0;L;;;;;N;;;;;
+02D1;MODIFIER LETTER HALF TRIANGULAR COLON;Lm;0;L;;;;;N;;;;;
+02D2;MODIFIER LETTER CENTRED RIGHT HALF RING;Sk;0;ON;;;;;N;MODIFIER LETTER CENTERED RIGHT HALF RING;;;;
+02D3;MODIFIER LETTER CENTRED LEFT HALF RING;Sk;0;ON;;;;;N;MODIFIER LETTER CENTERED LEFT HALF RING;;;;
+02D4;MODIFIER LETTER UP TACK;Sk;0;ON;;;;;N;;;;;
+02D5;MODIFIER LETTER DOWN TACK;Sk;0;ON;;;;;N;;;;;
+02D6;MODIFIER LETTER PLUS SIGN;Sk;0;ON;;;;;N;;;;;
+02D7;MODIFIER LETTER MINUS SIGN;Sk;0;ON;;;;;N;;;;;
+02D8;BREVE;Sk;0;ON;<compat> 0020 0306;;;;N;SPACING BREVE;;;;
+02D9;DOT ABOVE;Sk;0;ON;<compat> 0020 0307;;;;N;SPACING DOT ABOVE;Mandarin Chinese light tone;;;
+02DA;RING ABOVE;Sk;0;ON;<compat> 0020 030A;;;;N;SPACING RING ABOVE;;;;
+02DB;OGONEK;Sk;0;ON;<compat> 0020 0328;;;;N;SPACING OGONEK;;;;
+02DC;SMALL TILDE;Sk;0;ON;<compat> 0020 0303;;;;N;SPACING TILDE;;;;
+02DD;DOUBLE ACUTE ACCENT;Sk;0;ON;<compat> 0020 030B;;;;N;SPACING DOUBLE ACUTE;;;;
+02DE;MODIFIER LETTER RHOTIC HOOK;Sk;0;ON;;;;;N;;;;;
+02DF;MODIFIER LETTER CROSS ACCENT;Sk;0;ON;;;;;N;;;;;
+02E0;MODIFIER LETTER SMALL GAMMA;Lm;0;L;<super> 0263;;;;N;;;;;
+02E1;MODIFIER LETTER SMALL L;Lm;0;L;<super> 006C;;;;N;;;;;
+02E2;MODIFIER LETTER SMALL S;Lm;0;L;<super> 0073;;;;N;;;;;
+02E3;MODIFIER LETTER SMALL X;Lm;0;L;<super> 0078;;;;N;;;;;
+02E4;MODIFIER LETTER SMALL REVERSED GLOTTAL STOP;Lm;0;L;<super> 0295;;;;N;;;;;
+02E5;MODIFIER LETTER EXTRA-HIGH TONE BAR;Sk;0;ON;;;;;N;;;;;
+02E6;MODIFIER LETTER HIGH TONE BAR;Sk;0;ON;;;;;N;;;;;
+02E7;MODIFIER LETTER MID TONE BAR;Sk;0;ON;;;;;N;;;;;
+02E8;MODIFIER LETTER LOW TONE BAR;Sk;0;ON;;;;;N;;;;;
+02E9;MODIFIER LETTER EXTRA-LOW TONE BAR;Sk;0;ON;;;;;N;;;;;
+02EA;MODIFIER LETTER YIN DEPARTING TONE MARK;Sk;0;ON;;;;;N;;;;;
+02EB;MODIFIER LETTER YANG DEPARTING TONE MARK;Sk;0;ON;;;;;N;;;;;
+02EC;MODIFIER LETTER VOICING;Sk;0;ON;;;;;N;;;;;
+02ED;MODIFIER LETTER UNASPIRATED;Sk;0;ON;;;;;N;;;;;
+02EE;MODIFIER LETTER DOUBLE APOSTROPHE;Lm;0;L;;;;;N;;;;;
+02EF;MODIFIER LETTER LOW DOWN ARROWHEAD;Sk;0;ON;;;;;N;;;;;
+02F0;MODIFIER LETTER LOW UP ARROWHEAD;Sk;0;ON;;;;;N;;;;;
+02F1;MODIFIER LETTER LOW LEFT ARROWHEAD;Sk;0;ON;;;;;N;;;;;
+02F2;MODIFIER LETTER LOW RIGHT ARROWHEAD;Sk;0;ON;;;;;N;;;;;
+02F3;MODIFIER LETTER LOW RING;Sk;0;ON;;;;;N;;;;;
+02F4;MODIFIER LETTER MIDDLE GRAVE ACCENT;Sk;0;ON;;;;;N;;;;;
+02F5;MODIFIER LETTER MIDDLE DOUBLE GRAVE ACCENT;Sk;0;ON;;;;;N;;;;;
+02F6;MODIFIER LETTER MIDDLE DOUBLE ACUTE ACCENT;Sk;0;ON;;;;;N;;;;;
+02F7;MODIFIER LETTER LOW TILDE;Sk;0;ON;;;;;N;;;;;
+02F8;MODIFIER LETTER RAISED COLON;Sk;0;ON;;;;;N;;;;;
+02F9;MODIFIER LETTER BEGIN HIGH TONE;Sk;0;ON;;;;;N;;;;;
+02FA;MODIFIER LETTER END HIGH TONE;Sk;0;ON;;;;;N;;;;;
+02FB;MODIFIER LETTER BEGIN LOW TONE;Sk;0;ON;;;;;N;;;;;
+02FC;MODIFIER LETTER END LOW TONE;Sk;0;ON;;;;;N;;;;;
+02FD;MODIFIER LETTER SHELF;Sk;0;ON;;;;;N;;;;;
+02FE;MODIFIER LETTER OPEN SHELF;Sk;0;ON;;;;;N;;;;;
+02FF;MODIFIER LETTER LOW LEFT ARROW;Sk;0;ON;;;;;N;;;;;
+0300;COMBINING GRAVE ACCENT;Mn;230;NSM;;;;;N;NON-SPACING GRAVE;Varia;;;
+0301;COMBINING ACUTE ACCENT;Mn;230;NSM;;;;;N;NON-SPACING ACUTE;Oxia, Tonos;;;
+0302;COMBINING CIRCUMFLEX ACCENT;Mn;230;NSM;;;;;N;NON-SPACING CIRCUMFLEX;;;;
+0303;COMBINING TILDE;Mn;230;NSM;;;;;N;NON-SPACING TILDE;;;;
+0304;COMBINING MACRON;Mn;230;NSM;;;;;N;NON-SPACING MACRON;;;;
+0305;COMBINING OVERLINE;Mn;230;NSM;;;;;N;NON-SPACING OVERSCORE;;;;
+0306;COMBINING BREVE;Mn;230;NSM;;;;;N;NON-SPACING BREVE;Vrachy;;;
+0307;COMBINING DOT ABOVE;Mn;230;NSM;;;;;N;NON-SPACING DOT ABOVE;;;;
+0308;COMBINING DIAERESIS;Mn;230;NSM;;;;;N;NON-SPACING DIAERESIS;Dialytika;;;
+0309;COMBINING HOOK ABOVE;Mn;230;NSM;;;;;N;NON-SPACING HOOK ABOVE;;;;
+030A;COMBINING RING ABOVE;Mn;230;NSM;;;;;N;NON-SPACING RING ABOVE;;;;
+030B;COMBINING DOUBLE ACUTE ACCENT;Mn;230;NSM;;;;;N;NON-SPACING DOUBLE ACUTE;;;;
+030C;COMBINING CARON;Mn;230;NSM;;;;;N;NON-SPACING HACEK;;;;
+030D;COMBINING VERTICAL LINE ABOVE;Mn;230;NSM;;;;;N;NON-SPACING VERTICAL LINE ABOVE;;;;
+030E;COMBINING DOUBLE VERTICAL LINE ABOVE;Mn;230;NSM;;;;;N;NON-SPACING DOUBLE VERTICAL LINE ABOVE;;;;
+030F;COMBINING DOUBLE GRAVE ACCENT;Mn;230;NSM;;;;;N;NON-SPACING DOUBLE GRAVE;;;;
+0310;COMBINING CANDRABINDU;Mn;230;NSM;;;;;N;NON-SPACING CANDRABINDU;;;;
+0311;COMBINING INVERTED BREVE;Mn;230;NSM;;;;;N;NON-SPACING INVERTED BREVE;;;;
+0312;COMBINING TURNED COMMA ABOVE;Mn;230;NSM;;;;;N;NON-SPACING TURNED COMMA ABOVE;;;;
+0313;COMBINING COMMA ABOVE;Mn;230;NSM;;;;;N;NON-SPACING COMMA ABOVE;Psili;;;
+0314;COMBINING REVERSED COMMA ABOVE;Mn;230;NSM;;;;;N;NON-SPACING REVERSED COMMA ABOVE;Dasia;;;
+0315;COMBINING COMMA ABOVE RIGHT;Mn;232;NSM;;;;;N;NON-SPACING COMMA ABOVE RIGHT;;;;
+0316;COMBINING GRAVE ACCENT BELOW;Mn;220;NSM;;;;;N;NON-SPACING GRAVE BELOW;;;;
+0317;COMBINING ACUTE ACCENT BELOW;Mn;220;NSM;;;;;N;NON-SPACING ACUTE BELOW;;;;
+0318;COMBINING LEFT TACK BELOW;Mn;220;NSM;;;;;N;NON-SPACING LEFT TACK BELOW;;;;
+0319;COMBINING RIGHT TACK BELOW;Mn;220;NSM;;;;;N;NON-SPACING RIGHT TACK BELOW;;;;
+031A;COMBINING LEFT ANGLE ABOVE;Mn;232;NSM;;;;;N;NON-SPACING LEFT ANGLE ABOVE;;;;
+031B;COMBINING HORN;Mn;216;NSM;;;;;N;NON-SPACING HORN;;;;
+031C;COMBINING LEFT HALF RING BELOW;Mn;220;NSM;;;;;N;NON-SPACING LEFT HALF RING BELOW;;;;
+031D;COMBINING UP TACK BELOW;Mn;220;NSM;;;;;N;NON-SPACING UP TACK BELOW;;;;
+031E;COMBINING DOWN TACK BELOW;Mn;220;NSM;;;;;N;NON-SPACING DOWN TACK BELOW;;;;
+031F;COMBINING PLUS SIGN BELOW;Mn;220;NSM;;;;;N;NON-SPACING PLUS SIGN BELOW;;;;
+0320;COMBINING MINUS SIGN BELOW;Mn;220;NSM;;;;;N;NON-SPACING MINUS SIGN BELOW;;;;
+0321;COMBINING PALATALIZED HOOK BELOW;Mn;202;NSM;;;;;N;NON-SPACING PALATALIZED HOOK BELOW;;;;
+0322;COMBINING RETROFLEX HOOK BELOW;Mn;202;NSM;;;;;N;NON-SPACING RETROFLEX HOOK BELOW;;;;
+0323;COMBINING DOT BELOW;Mn;220;NSM;;;;;N;NON-SPACING DOT BELOW;;;;
+0324;COMBINING DIAERESIS BELOW;Mn;220;NSM;;;;;N;NON-SPACING DOUBLE DOT BELOW;;;;
+0325;COMBINING RING BELOW;Mn;220;NSM;;;;;N;NON-SPACING RING BELOW;;;;
+0326;COMBINING COMMA BELOW;Mn;220;NSM;;;;;N;NON-SPACING COMMA BELOW;;;;
+0327;COMBINING CEDILLA;Mn;202;NSM;;;;;N;NON-SPACING CEDILLA;;;;
+0328;COMBINING OGONEK;Mn;202;NSM;;;;;N;NON-SPACING OGONEK;;;;
+0329;COMBINING VERTICAL LINE BELOW;Mn;220;NSM;;;;;N;NON-SPACING VERTICAL LINE BELOW;;;;
+032A;COMBINING BRIDGE BELOW;Mn;220;NSM;;;;;N;NON-SPACING BRIDGE BELOW;;;;
+032B;COMBINING INVERTED DOUBLE ARCH BELOW;Mn;220;NSM;;;;;N;NON-SPACING INVERTED DOUBLE ARCH BELOW;;;;
+032C;COMBINING CARON BELOW;Mn;220;NSM;;;;;N;NON-SPACING HACEK BELOW;;;;
+032D;COMBINING CIRCUMFLEX ACCENT BELOW;Mn;220;NSM;;;;;N;NON-SPACING CIRCUMFLEX BELOW;;;;
+032E;COMBINING BREVE BELOW;Mn;220;NSM;;;;;N;NON-SPACING BREVE BELOW;;;;
+032F;COMBINING INVERTED BREVE BELOW;Mn;220;NSM;;;;;N;NON-SPACING INVERTED BREVE BELOW;;;;
+0330;COMBINING TILDE BELOW;Mn;220;NSM;;;;;N;NON-SPACING TILDE BELOW;;;;
+0331;COMBINING MACRON BELOW;Mn;220;NSM;;;;;N;NON-SPACING MACRON BELOW;;;;
+0332;COMBINING LOW LINE;Mn;220;NSM;;;;;N;NON-SPACING UNDERSCORE;;;;
+0333;COMBINING DOUBLE LOW LINE;Mn;220;NSM;;;;;N;NON-SPACING DOUBLE UNDERSCORE;;;;
+0334;COMBINING TILDE OVERLAY;Mn;1;NSM;;;;;N;NON-SPACING TILDE OVERLAY;;;;
+0335;COMBINING SHORT STROKE OVERLAY;Mn;1;NSM;;;;;N;NON-SPACING SHORT BAR OVERLAY;;;;
+0336;COMBINING LONG STROKE OVERLAY;Mn;1;NSM;;;;;N;NON-SPACING LONG BAR OVERLAY;;;;
+0337;COMBINING SHORT SOLIDUS OVERLAY;Mn;1;NSM;;;;;N;NON-SPACING SHORT SLASH OVERLAY;;;;
+0338;COMBINING LONG SOLIDUS OVERLAY;Mn;1;NSM;;;;;N;NON-SPACING LONG SLASH OVERLAY;;;;
+0339;COMBINING RIGHT HALF RING BELOW;Mn;220;NSM;;;;;N;NON-SPACING RIGHT HALF RING BELOW;;;;
+033A;COMBINING INVERTED BRIDGE BELOW;Mn;220;NSM;;;;;N;NON-SPACING INVERTED BRIDGE BELOW;;;;
+033B;COMBINING SQUARE BELOW;Mn;220;NSM;;;;;N;NON-SPACING SQUARE BELOW;;;;
+033C;COMBINING SEAGULL BELOW;Mn;220;NSM;;;;;N;NON-SPACING SEAGULL BELOW;;;;
+033D;COMBINING X ABOVE;Mn;230;NSM;;;;;N;NON-SPACING X ABOVE;;;;
+033E;COMBINING VERTICAL TILDE;Mn;230;NSM;;;;;N;NON-SPACING VERTICAL TILDE;;;;
+033F;COMBINING DOUBLE OVERLINE;Mn;230;NSM;;;;;N;NON-SPACING DOUBLE OVERSCORE;;;;
+0340;COMBINING GRAVE TONE MARK;Mn;230;NSM;0300;;;;N;NON-SPACING GRAVE TONE MARK;Vietnamese;;;
+0341;COMBINING ACUTE TONE MARK;Mn;230;NSM;0301;;;;N;NON-SPACING ACUTE TONE MARK;Vietnamese;;;
+0342;COMBINING GREEK PERISPOMENI;Mn;230;NSM;;;;;N;;;;;
+0343;COMBINING GREEK KORONIS;Mn;230;NSM;0313;;;;N;;;;;
+0344;COMBINING GREEK DIALYTIKA TONOS;Mn;230;NSM;0308 0301;;;;N;GREEK NON-SPACING DIAERESIS TONOS;;;;
+0345;COMBINING GREEK YPOGEGRAMMENI;Mn;240;NSM;;;;;N;GREEK NON-SPACING IOTA BELOW;;0399;;0399
+0346;COMBINING BRIDGE ABOVE;Mn;230;NSM;;;;;N;;;;;
+0347;COMBINING EQUALS SIGN BELOW;Mn;220;NSM;;;;;N;;;;;
+0348;COMBINING DOUBLE VERTICAL LINE BELOW;Mn;220;NSM;;;;;N;;;;;
+0349;COMBINING LEFT ANGLE BELOW;Mn;220;NSM;;;;;N;;;;;
+034A;COMBINING NOT TILDE ABOVE;Mn;230;NSM;;;;;N;;;;;
+034B;COMBINING HOMOTHETIC ABOVE;Mn;230;NSM;;;;;N;;;;;
+034C;COMBINING ALMOST EQUAL TO ABOVE;Mn;230;NSM;;;;;N;;;;;
+034D;COMBINING LEFT RIGHT ARROW BELOW;Mn;220;NSM;;;;;N;;;;;
+034E;COMBINING UPWARDS ARROW BELOW;Mn;220;NSM;;;;;N;;;;;
+034F;COMBINING GRAPHEME JOINER;Mn;0;NSM;;;;;N;;;;;
+0350;COMBINING RIGHT ARROWHEAD ABOVE;Mn;230;NSM;;;;;N;;;;;
+0351;COMBINING LEFT HALF RING ABOVE;Mn;230;NSM;;;;;N;;;;;
+0352;COMBINING FERMATA;Mn;230;NSM;;;;;N;;;;;
+0353;COMBINING X BELOW;Mn;220;NSM;;;;;N;;;;;
+0354;COMBINING LEFT ARROWHEAD BELOW;Mn;220;NSM;;;;;N;;;;;
+0355;COMBINING RIGHT ARROWHEAD BELOW;Mn;220;NSM;;;;;N;;;;;
+0356;COMBINING RIGHT ARROWHEAD AND UP ARROWHEAD BELOW;Mn;220;NSM;;;;;N;;;;;
+0357;COMBINING RIGHT HALF RING ABOVE;Mn;230;NSM;;;;;N;;;;;
+0358;COMBINING DOT ABOVE RIGHT;Mn;232;NSM;;;;;N;;;;;
+0359;COMBINING ASTERISK BELOW;Mn;220;NSM;;;;;N;;;;;
+035A;COMBINING DOUBLE RING BELOW;Mn;220;NSM;;;;;N;;;;;
+035B;COMBINING ZIGZAG ABOVE;Mn;230;NSM;;;;;N;;;;;
+035C;COMBINING DOUBLE BREVE BELOW;Mn;233;NSM;;;;;N;;;;;
+035D;COMBINING DOUBLE BREVE;Mn;234;NSM;;;;;N;;;;;
+035E;COMBINING DOUBLE MACRON;Mn;234;NSM;;;;;N;;;;;
+035F;COMBINING DOUBLE MACRON BELOW;Mn;233;NSM;;;;;N;;;;;
+0360;COMBINING DOUBLE TILDE;Mn;234;NSM;;;;;N;;;;;
+0361;COMBINING DOUBLE INVERTED BREVE;Mn;234;NSM;;;;;N;;;;;
+0362;COMBINING DOUBLE RIGHTWARDS ARROW BELOW;Mn;233;NSM;;;;;N;;;;;
+0363;COMBINING LATIN SMALL LETTER A;Mn;230;NSM;;;;;N;;;;;
+0364;COMBINING LATIN SMALL LETTER E;Mn;230;NSM;;;;;N;;;;;
+0365;COMBINING LATIN SMALL LETTER I;Mn;230;NSM;;;;;N;;;;;
+0366;COMBINING LATIN SMALL LETTER O;Mn;230;NSM;;;;;N;;;;;
+0367;COMBINING LATIN SMALL LETTER U;Mn;230;NSM;;;;;N;;;;;
+0368;COMBINING LATIN SMALL LETTER C;Mn;230;NSM;;;;;N;;;;;
+0369;COMBINING LATIN SMALL LETTER D;Mn;230;NSM;;;;;N;;;;;
+036A;COMBINING LATIN SMALL LETTER H;Mn;230;NSM;;;;;N;;;;;
+036B;COMBINING LATIN SMALL LETTER M;Mn;230;NSM;;;;;N;;;;;
+036C;COMBINING LATIN SMALL LETTER R;Mn;230;NSM;;;;;N;;;;;
+036D;COMBINING LATIN SMALL LETTER T;Mn;230;NSM;;;;;N;;;;;
+036E;COMBINING LATIN SMALL LETTER V;Mn;230;NSM;;;;;N;;;;;
+036F;COMBINING LATIN SMALL LETTER X;Mn;230;NSM;;;;;N;;;;;
+0374;GREEK NUMERAL SIGN;Sk;0;ON;02B9;;;;N;GREEK UPPER NUMERAL SIGN;Dexia keraia;;;
+0375;GREEK LOWER NUMERAL SIGN;Sk;0;ON;;;;;N;;Aristeri keraia;;;
+037A;GREEK YPOGEGRAMMENI;Lm;0;L;<compat> 0020 0345;;;;N;GREEK SPACING IOTA BELOW;;;;
+037E;GREEK QUESTION MARK;Po;0;ON;003B;;;;N;;Erotimatiko;;;
+0384;GREEK TONOS;Sk;0;ON;<compat> 0020 0301;;;;N;GREEK SPACING TONOS;;;;
+0385;GREEK DIALYTIKA TONOS;Sk;0;ON;00A8 0301;;;;N;GREEK SPACING DIAERESIS TONOS;;;;
+0386;GREEK CAPITAL LETTER ALPHA WITH TONOS;Lu;0;L;0391 0301;;;;N;GREEK CAPITAL LETTER ALPHA TONOS;;;03AC;
+0387;GREEK ANO TELEIA;Po;0;ON;00B7;;;;N;;;;;
+0388;GREEK CAPITAL LETTER EPSILON WITH TONOS;Lu;0;L;0395 0301;;;;N;GREEK CAPITAL LETTER EPSILON TONOS;;;03AD;
+0389;GREEK CAPITAL LETTER ETA WITH TONOS;Lu;0;L;0397 0301;;;;N;GREEK CAPITAL LETTER ETA TONOS;;;03AE;
+038A;GREEK CAPITAL LETTER IOTA WITH TONOS;Lu;0;L;0399 0301;;;;N;GREEK CAPITAL LETTER IOTA TONOS;;;03AF;
+038C;GREEK CAPITAL LETTER OMICRON WITH TONOS;Lu;0;L;039F 0301;;;;N;GREEK CAPITAL LETTER OMICRON TONOS;;;03CC;
+038E;GREEK CAPITAL LETTER UPSILON WITH TONOS;Lu;0;L;03A5 0301;;;;N;GREEK CAPITAL LETTER UPSILON TONOS;;;03CD;
+038F;GREEK CAPITAL LETTER OMEGA WITH TONOS;Lu;0;L;03A9 0301;;;;N;GREEK CAPITAL LETTER OMEGA TONOS;;;03CE;
+0390;GREEK SMALL LETTER IOTA WITH DIALYTIKA AND TONOS;Ll;0;L;03CA 0301;;;;N;GREEK SMALL LETTER IOTA DIAERESIS TONOS;;;;
+0391;GREEK CAPITAL LETTER ALPHA;Lu;0;L;;;;;N;;;;03B1;
+0392;GREEK CAPITAL LETTER BETA;Lu;0;L;;;;;N;;;;03B2;
+0393;GREEK CAPITAL LETTER GAMMA;Lu;0;L;;;;;N;;;;03B3;
+0394;GREEK CAPITAL LETTER DELTA;Lu;0;L;;;;;N;;;;03B4;
+0395;GREEK CAPITAL LETTER EPSILON;Lu;0;L;;;;;N;;;;03B5;
+0396;GREEK CAPITAL LETTER ZETA;Lu;0;L;;;;;N;;;;03B6;
+0397;GREEK CAPITAL LETTER ETA;Lu;0;L;;;;;N;;;;03B7;
+0398;GREEK CAPITAL LETTER THETA;Lu;0;L;;;;;N;;;;03B8;
+0399;GREEK CAPITAL LETTER IOTA;Lu;0;L;;;;;N;;;;03B9;
+039A;GREEK CAPITAL LETTER KAPPA;Lu;0;L;;;;;N;;;;03BA;
+039B;GREEK CAPITAL LETTER LAMDA;Lu;0;L;;;;;N;GREEK CAPITAL LETTER LAMBDA;;;03BB;
+039C;GREEK CAPITAL LETTER MU;Lu;0;L;;;;;N;;;;03BC;
+039D;GREEK CAPITAL LETTER NU;Lu;0;L;;;;;N;;;;03BD;
+039E;GREEK CAPITAL LETTER XI;Lu;0;L;;;;;N;;;;03BE;
+039F;GREEK CAPITAL LETTER OMICRON;Lu;0;L;;;;;N;;;;03BF;
+03A0;GREEK CAPITAL LETTER PI;Lu;0;L;;;;;N;;;;03C0;
+03A1;GREEK CAPITAL LETTER RHO;Lu;0;L;;;;;N;;;;03C1;
+03A3;GREEK CAPITAL LETTER SIGMA;Lu;0;L;;;;;N;;;;03C3;
+03A4;GREEK CAPITAL LETTER TAU;Lu;0;L;;;;;N;;;;03C4;
+03A5;GREEK CAPITAL LETTER UPSILON;Lu;0;L;;;;;N;;;;03C5;
+03A6;GREEK CAPITAL LETTER PHI;Lu;0;L;;;;;N;;;;03C6;
+03A7;GREEK CAPITAL LETTER CHI;Lu;0;L;;;;;N;;;;03C7;
+03A8;GREEK CAPITAL LETTER PSI;Lu;0;L;;;;;N;;;;03C8;
+03A9;GREEK CAPITAL LETTER OMEGA;Lu;0;L;;;;;N;;;;03C9;
+03AA;GREEK CAPITAL LETTER IOTA WITH DIALYTIKA;Lu;0;L;0399 0308;;;;N;GREEK CAPITAL LETTER IOTA DIAERESIS;;;03CA;
+03AB;GREEK CAPITAL LETTER UPSILON WITH DIALYTIKA;Lu;0;L;03A5 0308;;;;N;GREEK CAPITAL LETTER UPSILON DIAERESIS;;;03CB;
+03AC;GREEK SMALL LETTER ALPHA WITH TONOS;Ll;0;L;03B1 0301;;;;N;GREEK SMALL LETTER ALPHA TONOS;;0386;;0386
+03AD;GREEK SMALL LETTER EPSILON WITH TONOS;Ll;0;L;03B5 0301;;;;N;GREEK SMALL LETTER EPSILON TONOS;;0388;;0388
+03AE;GREEK SMALL LETTER ETA WITH TONOS;Ll;0;L;03B7 0301;;;;N;GREEK SMALL LETTER ETA TONOS;;0389;;0389
+03AF;GREEK SMALL LETTER IOTA WITH TONOS;Ll;0;L;03B9 0301;;;;N;GREEK SMALL LETTER IOTA TONOS;;038A;;038A
+03B0;GREEK SMALL LETTER UPSILON WITH DIALYTIKA AND TONOS;Ll;0;L;03CB 0301;;;;N;GREEK SMALL LETTER UPSILON DIAERESIS TONOS;;;;
+03B1;GREEK SMALL LETTER ALPHA;Ll;0;L;;;;;N;;;0391;;0391
+03B2;GREEK SMALL LETTER BETA;Ll;0;L;;;;;N;;;0392;;0392
+03B3;GREEK SMALL LETTER GAMMA;Ll;0;L;;;;;N;;;0393;;0393
+03B4;GREEK SMALL LETTER DELTA;Ll;0;L;;;;;N;;;0394;;0394
+03B5;GREEK SMALL LETTER EPSILON;Ll;0;L;;;;;N;;;0395;;0395
+03B6;GREEK SMALL LETTER ZETA;Ll;0;L;;;;;N;;;0396;;0396
+03B7;GREEK SMALL LETTER ETA;Ll;0;L;;;;;N;;;0397;;0397
+03B8;GREEK SMALL LETTER THETA;Ll;0;L;;;;;N;;;0398;;0398
+03B9;GREEK SMALL LETTER IOTA;Ll;0;L;;;;;N;;;0399;;0399
+03BA;GREEK SMALL LETTER KAPPA;Ll;0;L;;;;;N;;;039A;;039A
+03BB;GREEK SMALL LETTER LAMDA;Ll;0;L;;;;;N;GREEK SMALL LETTER LAMBDA;;039B;;039B
+03BC;GREEK SMALL LETTER MU;Ll;0;L;;;;;N;;;039C;;039C
+03BD;GREEK SMALL LETTER NU;Ll;0;L;;;;;N;;;039D;;039D
+03BE;GREEK SMALL LETTER XI;Ll;0;L;;;;;N;;;039E;;039E
+03BF;GREEK SMALL LETTER OMICRON;Ll;0;L;;;;;N;;;039F;;039F
+03C0;GREEK SMALL LETTER PI;Ll;0;L;;;;;N;;;03A0;;03A0
+03C1;GREEK SMALL LETTER RHO;Ll;0;L;;;;;N;;;03A1;;03A1
+03C2;GREEK SMALL LETTER FINAL SIGMA;Ll;0;L;;;;;N;;;03A3;;03A3
+03C3;GREEK SMALL LETTER SIGMA;Ll;0;L;;;;;N;;;03A3;;03A3
+03C4;GREEK SMALL LETTER TAU;Ll;0;L;;;;;N;;;03A4;;03A4
+03C5;GREEK SMALL LETTER UPSILON;Ll;0;L;;;;;N;;;03A5;;03A5
+03C6;GREEK SMALL LETTER PHI;Ll;0;L;;;;;N;;;03A6;;03A6
+03C7;GREEK SMALL LETTER CHI;Ll;0;L;;;;;N;;;03A7;;03A7
+03C8;GREEK SMALL LETTER PSI;Ll;0;L;;;;;N;;;03A8;;03A8
+03C9;GREEK SMALL LETTER OMEGA;Ll;0;L;;;;;N;;;03A9;;03A9
+03CA;GREEK SMALL LETTER IOTA WITH DIALYTIKA;Ll;0;L;03B9 0308;;;;N;GREEK SMALL LETTER IOTA DIAERESIS;;03AA;;03AA
+03CB;GREEK SMALL LETTER UPSILON WITH DIALYTIKA;Ll;0;L;03C5 0308;;;;N;GREEK SMALL LETTER UPSILON DIAERESIS;;03AB;;03AB
+03CC;GREEK SMALL LETTER OMICRON WITH TONOS;Ll;0;L;03BF 0301;;;;N;GREEK SMALL LETTER OMICRON TONOS;;038C;;038C
+03CD;GREEK SMALL LETTER UPSILON WITH TONOS;Ll;0;L;03C5 0301;;;;N;GREEK SMALL LETTER UPSILON TONOS;;038E;;038E
+03CE;GREEK SMALL LETTER OMEGA WITH TONOS;Ll;0;L;03C9 0301;;;;N;GREEK SMALL LETTER OMEGA TONOS;;038F;;038F
+03D0;GREEK BETA SYMBOL;Ll;0;L;<compat> 03B2;;;;N;GREEK SMALL LETTER CURLED BETA;;0392;;0392
+03D1;GREEK THETA SYMBOL;Ll;0;L;<compat> 03B8;;;;N;GREEK SMALL LETTER SCRIPT THETA;;0398;;0398
+03D2;GREEK UPSILON WITH HOOK SYMBOL;Lu;0;L;<compat> 03A5;;;;N;GREEK CAPITAL LETTER UPSILON HOOK;;;;
+03D3;GREEK UPSILON WITH ACUTE AND HOOK SYMBOL;Lu;0;L;03D2 0301;;;;N;GREEK CAPITAL LETTER UPSILON HOOK TONOS;;;;
+03D4;GREEK UPSILON WITH DIAERESIS AND HOOK SYMBOL;Lu;0;L;03D2 0308;;;;N;GREEK CAPITAL LETTER UPSILON HOOK DIAERESIS;;;;
+03D5;GREEK PHI SYMBOL;Ll;0;L;<compat> 03C6;;;;N;GREEK SMALL LETTER SCRIPT PHI;;03A6;;03A6
+03D6;GREEK PI SYMBOL;Ll;0;L;<compat> 03C0;;;;N;GREEK SMALL LETTER OMEGA PI;;03A0;;03A0
+03D7;GREEK KAI SYMBOL;Ll;0;L;;;;;N;;;;;
+03D8;GREEK LETTER ARCHAIC KOPPA;Lu;0;L;;;;;N;;*;;03D9;
+03D9;GREEK SMALL LETTER ARCHAIC KOPPA;Ll;0;L;;;;;N;;*;03D8;;03D8
+03DA;GREEK LETTER STIGMA;Lu;0;L;;;;;N;GREEK CAPITAL LETTER STIGMA;;;03DB;
+03DB;GREEK SMALL LETTER STIGMA;Ll;0;L;;;;;N;;;03DA;;03DA
+03DC;GREEK LETTER DIGAMMA;Lu;0;L;;;;;N;GREEK CAPITAL LETTER DIGAMMA;;;03DD;
+03DD;GREEK SMALL LETTER DIGAMMA;Ll;0;L;;;;;N;;;03DC;;03DC
+03DE;GREEK LETTER KOPPA;Lu;0;L;;;;;N;GREEK CAPITAL LETTER KOPPA;;;03DF;
+03DF;GREEK SMALL LETTER KOPPA;Ll;0;L;;;;;N;;;03DE;;03DE
+03E0;GREEK LETTER SAMPI;Lu;0;L;;;;;N;GREEK CAPITAL LETTER SAMPI;;;03E1;
+03E1;GREEK SMALL LETTER SAMPI;Ll;0;L;;;;;N;;;03E0;;03E0
+03E2;COPTIC CAPITAL LETTER SHEI;Lu;0;L;;;;;N;GREEK CAPITAL LETTER SHEI;;;03E3;
+03E3;COPTIC SMALL LETTER SHEI;Ll;0;L;;;;;N;GREEK SMALL LETTER SHEI;;03E2;;03E2
+03E4;COPTIC CAPITAL LETTER FEI;Lu;0;L;;;;;N;GREEK CAPITAL LETTER FEI;;;03E5;
+03E5;COPTIC SMALL LETTER FEI;Ll;0;L;;;;;N;GREEK SMALL LETTER FEI;;03E4;;03E4
+03E6;COPTIC CAPITAL LETTER KHEI;Lu;0;L;;;;;N;GREEK CAPITAL LETTER KHEI;;;03E7;
+03E7;COPTIC SMALL LETTER KHEI;Ll;0;L;;;;;N;GREEK SMALL LETTER KHEI;;03E6;;03E6
+03E8;COPTIC CAPITAL LETTER HORI;Lu;0;L;;;;;N;GREEK CAPITAL LETTER HORI;;;03E9;
+03E9;COPTIC SMALL LETTER HORI;Ll;0;L;;;;;N;GREEK SMALL LETTER HORI;;03E8;;03E8
+03EA;COPTIC CAPITAL LETTER GANGIA;Lu;0;L;;;;;N;GREEK CAPITAL LETTER GANGIA;;;03EB;
+03EB;COPTIC SMALL LETTER GANGIA;Ll;0;L;;;;;N;GREEK SMALL LETTER GANGIA;;03EA;;03EA
+03EC;COPTIC CAPITAL LETTER SHIMA;Lu;0;L;;;;;N;GREEK CAPITAL LETTER SHIMA;;;03ED;
+03ED;COPTIC SMALL LETTER SHIMA;Ll;0;L;;;;;N;GREEK SMALL LETTER SHIMA;;03EC;;03EC
+03EE;COPTIC CAPITAL LETTER DEI;Lu;0;L;;;;;N;GREEK CAPITAL LETTER DEI;;;03EF;
+03EF;COPTIC SMALL LETTER DEI;Ll;0;L;;;;;N;GREEK SMALL LETTER DEI;;03EE;;03EE
+03F0;GREEK KAPPA SYMBOL;Ll;0;L;<compat> 03BA;;;;N;GREEK SMALL LETTER SCRIPT KAPPA;;039A;;039A
+03F1;GREEK RHO SYMBOL;Ll;0;L;<compat> 03C1;;;;N;GREEK SMALL LETTER TAILED RHO;;03A1;;03A1
+03F2;GREEK LUNATE SIGMA SYMBOL;Ll;0;L;<compat> 03C2;;;;N;GREEK SMALL LETTER LUNATE SIGMA;;03F9;;03F9
+03F3;GREEK LETTER YOT;Ll;0;L;;;;;N;;;;;
+03F4;GREEK CAPITAL THETA SYMBOL;Lu;0;L;<compat> 0398;;;;N;;;;03B8;
+03F5;GREEK LUNATE EPSILON SYMBOL;Ll;0;L;<compat> 03B5;;;;N;;;0395;;0395
+03F6;GREEK REVERSED LUNATE EPSILON SYMBOL;Sm;0;ON;;;;;N;;;;;
+03F7;GREEK CAPITAL LETTER SHO;Lu;0;L;;;;;N;;;;03F8;
+03F8;GREEK SMALL LETTER SHO;Ll;0;L;;;;;N;;;03F7;;03F7
+03F9;GREEK CAPITAL LUNATE SIGMA SYMBOL;Lu;0;L;<compat> 03A3;;;;N;;;;03F2;
+03FA;GREEK CAPITAL LETTER SAN;Lu;0;L;;;;;N;;;;03FB;
+03FB;GREEK SMALL LETTER SAN;Ll;0;L;;;;;N;;;03FA;;03FA
+03FC;GREEK RHO WITH STROKE SYMBOL;Ll;0;L;;;;;N;;;;;
+03FD;GREEK CAPITAL REVERSED LUNATE SIGMA SYMBOL;Lu;0;L;;;;;N;;;;;
+03FE;GREEK CAPITAL DOTTED LUNATE SIGMA SYMBOL;Lu;0;L;;;;;N;;;;;
+03FF;GREEK CAPITAL REVERSED DOTTED LUNATE SIGMA SYMBOL;Lu;0;L;;;;;N;;;;;
+0400;CYRILLIC CAPITAL LETTER IE WITH GRAVE;Lu;0;L;0415 0300;;;;N;;;;0450;
+0401;CYRILLIC CAPITAL LETTER IO;Lu;0;L;0415 0308;;;;N;;;;0451;
+0402;CYRILLIC CAPITAL LETTER DJE;Lu;0;L;;;;;N;;Serbocroatian;;0452;
+0403;CYRILLIC CAPITAL LETTER GJE;Lu;0;L;0413 0301;;;;N;;;;0453;
+0404;CYRILLIC CAPITAL LETTER UKRAINIAN IE;Lu;0;L;;;;;N;CYRILLIC CAPITAL LETTER E;;;0454;
+0405;CYRILLIC CAPITAL LETTER DZE;Lu;0;L;;;;;N;;;;0455;
+0406;CYRILLIC CAPITAL LETTER BYELORUSSIAN-UKRAINIAN I;Lu;0;L;;;;;N;CYRILLIC CAPITAL LETTER I;;;0456;
+0407;CYRILLIC CAPITAL LETTER YI;Lu;0;L;0406 0308;;;;N;;Ukrainian;;0457;
+0408;CYRILLIC CAPITAL LETTER JE;Lu;0;L;;;;;N;;;;0458;
+0409;CYRILLIC CAPITAL LETTER LJE;Lu;0;L;;;;;N;;;;0459;
+040A;CYRILLIC CAPITAL LETTER NJE;Lu;0;L;;;;;N;;;;045A;
+040B;CYRILLIC CAPITAL LETTER TSHE;Lu;0;L;;;;;N;;Serbocroatian;;045B;
+040C;CYRILLIC CAPITAL LETTER KJE;Lu;0;L;041A 0301;;;;N;;;;045C;
+040D;CYRILLIC CAPITAL LETTER I WITH GRAVE;Lu;0;L;0418 0300;;;;N;;;;045D;
+040E;CYRILLIC CAPITAL LETTER SHORT U;Lu;0;L;0423 0306;;;;N;;Byelorussian;;045E;
+040F;CYRILLIC CAPITAL LETTER DZHE;Lu;0;L;;;;;N;;;;045F;
+0410;CYRILLIC CAPITAL LETTER A;Lu;0;L;;;;;N;;;;0430;
+0411;CYRILLIC CAPITAL LETTER BE;Lu;0;L;;;;;N;;;;0431;
+0412;CYRILLIC CAPITAL LETTER VE;Lu;0;L;;;;;N;;;;0432;
+0413;CYRILLIC CAPITAL LETTER GHE;Lu;0;L;;;;;N;CYRILLIC CAPITAL LETTER GE;;;0433;
+0414;CYRILLIC CAPITAL LETTER DE;Lu;0;L;;;;;N;;;;0434;
+0415;CYRILLIC CAPITAL LETTER IE;Lu;0;L;;;;;N;;;;0435;
+0416;CYRILLIC CAPITAL LETTER ZHE;Lu;0;L;;;;;N;;;;0436;
+0417;CYRILLIC CAPITAL LETTER ZE;Lu;0;L;;;;;N;;;;0437;
+0418;CYRILLIC CAPITAL LETTER I;Lu;0;L;;;;;N;CYRILLIC CAPITAL LETTER II;;;0438;
+0419;CYRILLIC CAPITAL LETTER SHORT I;Lu;0;L;0418 0306;;;;N;CYRILLIC CAPITAL LETTER SHORT II;;;0439;
+041A;CYRILLIC CAPITAL LETTER KA;Lu;0;L;;;;;N;;;;043A;
+041B;CYRILLIC CAPITAL LETTER EL;Lu;0;L;;;;;N;;;;043B;
+041C;CYRILLIC CAPITAL LETTER EM;Lu;0;L;;;;;N;;;;043C;
+041D;CYRILLIC CAPITAL LETTER EN;Lu;0;L;;;;;N;;;;043D;
+041E;CYRILLIC CAPITAL LETTER O;Lu;0;L;;;;;N;;;;043E;
+041F;CYRILLIC CAPITAL LETTER PE;Lu;0;L;;;;;N;;;;043F;
+0420;CYRILLIC CAPITAL LETTER ER;Lu;0;L;;;;;N;;;;0440;
+0421;CYRILLIC CAPITAL LETTER ES;Lu;0;L;;;;;N;;;;0441;
+0422;CYRILLIC CAPITAL LETTER TE;Lu;0;L;;;;;N;;;;0442;
+0423;CYRILLIC CAPITAL LETTER U;Lu;0;L;;;;;N;;;;0443;
+0424;CYRILLIC CAPITAL LETTER EF;Lu;0;L;;;;;N;;;;0444;
+0425;CYRILLIC CAPITAL LETTER HA;Lu;0;L;;;;;N;CYRILLIC CAPITAL LETTER KHA;;;0445;
+0426;CYRILLIC CAPITAL LETTER TSE;Lu;0;L;;;;;N;;;;0446;
+0427;CYRILLIC CAPITAL LETTER CHE;Lu;0;L;;;;;N;;;;0447;
+0428;CYRILLIC CAPITAL LETTER SHA;Lu;0;L;;;;;N;;;;0448;
+0429;CYRILLIC CAPITAL LETTER SHCHA;Lu;0;L;;;;;N;;;;0449;
+042A;CYRILLIC CAPITAL LETTER HARD SIGN;Lu;0;L;;;;;N;;;;044A;
+042B;CYRILLIC CAPITAL LETTER YERU;Lu;0;L;;;;;N;CYRILLIC CAPITAL LETTER YERI;;;044B;
+042C;CYRILLIC CAPITAL LETTER SOFT SIGN;Lu;0;L;;;;;N;;;;044C;
+042D;CYRILLIC CAPITAL LETTER E;Lu;0;L;;;;;N;CYRILLIC CAPITAL LETTER REVERSED E;;;044D;
+042E;CYRILLIC CAPITAL LETTER YU;Lu;0;L;;;;;N;CYRILLIC CAPITAL LETTER IU;;;044E;
+042F;CYRILLIC CAPITAL LETTER YA;Lu;0;L;;;;;N;CYRILLIC CAPITAL LETTER IA;;;044F;
+0430;CYRILLIC SMALL LETTER A;Ll;0;L;;;;;N;;;0410;;0410
+0431;CYRILLIC SMALL LETTER BE;Ll;0;L;;;;;N;;;0411;;0411
+0432;CYRILLIC SMALL LETTER VE;Ll;0;L;;;;;N;;;0412;;0412
+0433;CYRILLIC SMALL LETTER GHE;Ll;0;L;;;;;N;CYRILLIC SMALL LETTER GE;;0413;;0413
+0434;CYRILLIC SMALL LETTER DE;Ll;0;L;;;;;N;;;0414;;0414
+0435;CYRILLIC SMALL LETTER IE;Ll;0;L;;;;;N;;;0415;;0415
+0436;CYRILLIC SMALL LETTER ZHE;Ll;0;L;;;;;N;;;0416;;0416
+0437;CYRILLIC SMALL LETTER ZE;Ll;0;L;;;;;N;;;0417;;0417
+0438;CYRILLIC SMALL LETTER I;Ll;0;L;;;;;N;CYRILLIC SMALL LETTER II;;0418;;0418
+0439;CYRILLIC SMALL LETTER SHORT I;Ll;0;L;0438 0306;;;;N;CYRILLIC SMALL LETTER SHORT II;;0419;;0419
+043A;CYRILLIC SMALL LETTER KA;Ll;0;L;;;;;N;;;041A;;041A
+043B;CYRILLIC SMALL LETTER EL;Ll;0;L;;;;;N;;;041B;;041B
+043C;CYRILLIC SMALL LETTER EM;Ll;0;L;;;;;N;;;041C;;041C
+043D;CYRILLIC SMALL LETTER EN;Ll;0;L;;;;;N;;;041D;;041D
+043E;CYRILLIC SMALL LETTER O;Ll;0;L;;;;;N;;;041E;;041E
+043F;CYRILLIC SMALL LETTER PE;Ll;0;L;;;;;N;;;041F;;041F
+0440;CYRILLIC SMALL LETTER ER;Ll;0;L;;;;;N;;;0420;;0420
+0441;CYRILLIC SMALL LETTER ES;Ll;0;L;;;;;N;;;0421;;0421
+0442;CYRILLIC SMALL LETTER TE;Ll;0;L;;;;;N;;;0422;;0422
+0443;CYRILLIC SMALL LETTER U;Ll;0;L;;;;;N;;;0423;;0423
+0444;CYRILLIC SMALL LETTER EF;Ll;0;L;;;;;N;;;0424;;0424
+0445;CYRILLIC SMALL LETTER HA;Ll;0;L;;;;;N;CYRILLIC SMALL LETTER KHA;;0425;;0425
+0446;CYRILLIC SMALL LETTER TSE;Ll;0;L;;;;;N;;;0426;;0426
+0447;CYRILLIC SMALL LETTER CHE;Ll;0;L;;;;;N;;;0427;;0427
+0448;CYRILLIC SMALL LETTER SHA;Ll;0;L;;;;;N;;;0428;;0428
+0449;CYRILLIC SMALL LETTER SHCHA;Ll;0;L;;;;;N;;;0429;;0429
+044A;CYRILLIC SMALL LETTER HARD SIGN;Ll;0;L;;;;;N;;;042A;;042A
+044B;CYRILLIC SMALL LETTER YERU;Ll;0;L;;;;;N;CYRILLIC SMALL LETTER YERI;;042B;;042B
+044C;CYRILLIC SMALL LETTER SOFT SIGN;Ll;0;L;;;;;N;;;042C;;042C
+044D;CYRILLIC SMALL LETTER E;Ll;0;L;;;;;N;CYRILLIC SMALL LETTER REVERSED E;;042D;;042D
+044E;CYRILLIC SMALL LETTER YU;Ll;0;L;;;;;N;CYRILLIC SMALL LETTER IU;;042E;;042E
+044F;CYRILLIC SMALL LETTER YA;Ll;0;L;;;;;N;CYRILLIC SMALL LETTER IA;;042F;;042F
+0450;CYRILLIC SMALL LETTER IE WITH GRAVE;Ll;0;L;0435 0300;;;;N;;;0400;;0400
+0451;CYRILLIC SMALL LETTER IO;Ll;0;L;0435 0308;;;;N;;;0401;;0401
+0452;CYRILLIC SMALL LETTER DJE;Ll;0;L;;;;;N;;Serbocroatian;0402;;0402
+0453;CYRILLIC SMALL LETTER GJE;Ll;0;L;0433 0301;;;;N;;;0403;;0403
+0454;CYRILLIC SMALL LETTER UKRAINIAN IE;Ll;0;L;;;;;N;CYRILLIC SMALL LETTER E;;0404;;0404
+0455;CYRILLIC SMALL LETTER DZE;Ll;0;L;;;;;N;;;0405;;0405
+0456;CYRILLIC SMALL LETTER BYELORUSSIAN-UKRAINIAN I;Ll;0;L;;;;;N;CYRILLIC SMALL LETTER I;;0406;;0406
+0457;CYRILLIC SMALL LETTER YI;Ll;0;L;0456 0308;;;;N;;Ukrainian;0407;;0407
+0458;CYRILLIC SMALL LETTER JE;Ll;0;L;;;;;N;;;0408;;0408
+0459;CYRILLIC SMALL LETTER LJE;Ll;0;L;;;;;N;;;0409;;0409
+045A;CYRILLIC SMALL LETTER NJE;Ll;0;L;;;;;N;;;040A;;040A
+045B;CYRILLIC SMALL LETTER TSHE;Ll;0;L;;;;;N;;Serbocroatian;040B;;040B
+045C;CYRILLIC SMALL LETTER KJE;Ll;0;L;043A 0301;;;;N;;;040C;;040C
+045D;CYRILLIC SMALL LETTER I WITH GRAVE;Ll;0;L;0438 0300;;;;N;;;040D;;040D
+045E;CYRILLIC SMALL LETTER SHORT U;Ll;0;L;0443 0306;;;;N;;Byelorussian;040E;;040E
+045F;CYRILLIC SMALL LETTER DZHE;Ll;0;L;;;;;N;;;040F;;040F
+0460;CYRILLIC CAPITAL LETTER OMEGA;Lu;0;L;;;;;N;;;;0461;
+0461;CYRILLIC SMALL LETTER OMEGA;Ll;0;L;;;;;N;;;0460;;0460
+0462;CYRILLIC CAPITAL LETTER YAT;Lu;0;L;;;;;N;;;;0463;
+0463;CYRILLIC SMALL LETTER YAT;Ll;0;L;;;;;N;;;0462;;0462
+0464;CYRILLIC CAPITAL LETTER IOTIFIED E;Lu;0;L;;;;;N;;;;0465;
+0465;CYRILLIC SMALL LETTER IOTIFIED E;Ll;0;L;;;;;N;;;0464;;0464
+0466;CYRILLIC CAPITAL LETTER LITTLE YUS;Lu;0;L;;;;;N;;;;0467;
+0467;CYRILLIC SMALL LETTER LITTLE YUS;Ll;0;L;;;;;N;;;0466;;0466
+0468;CYRILLIC CAPITAL LETTER IOTIFIED LITTLE YUS;Lu;0;L;;;;;N;;;;0469;
+0469;CYRILLIC SMALL LETTER IOTIFIED LITTLE YUS;Ll;0;L;;;;;N;;;0468;;0468
+046A;CYRILLIC CAPITAL LETTER BIG YUS;Lu;0;L;;;;;N;;;;046B;
+046B;CYRILLIC SMALL LETTER BIG YUS;Ll;0;L;;;;;N;;;046A;;046A
+046C;CYRILLIC CAPITAL LETTER IOTIFIED BIG YUS;Lu;0;L;;;;;N;;;;046D;
+046D;CYRILLIC SMALL LETTER IOTIFIED BIG YUS;Ll;0;L;;;;;N;;;046C;;046C
+046E;CYRILLIC CAPITAL LETTER KSI;Lu;0;L;;;;;N;;;;046F;
+046F;CYRILLIC SMALL LETTER KSI;Ll;0;L;;;;;N;;;046E;;046E
+0470;CYRILLIC CAPITAL LETTER PSI;Lu;0;L;;;;;N;;;;0471;
+0471;CYRILLIC SMALL LETTER PSI;Ll;0;L;;;;;N;;;0470;;0470
+0472;CYRILLIC CAPITAL LETTER FITA;Lu;0;L;;;;;N;;;;0473;
+0473;CYRILLIC SMALL LETTER FITA;Ll;0;L;;;;;N;;;0472;;0472
+0474;CYRILLIC CAPITAL LETTER IZHITSA;Lu;0;L;;;;;N;;;;0475;
+0475;CYRILLIC SMALL LETTER IZHITSA;Ll;0;L;;;;;N;;;0474;;0474
+0476;CYRILLIC CAPITAL LETTER IZHITSA WITH DOUBLE GRAVE ACCENT;Lu;0;L;0474 030F;;;;N;CYRILLIC CAPITAL LETTER IZHITSA DOUBLE GRAVE;;;0477;
+0477;CYRILLIC SMALL LETTER IZHITSA WITH DOUBLE GRAVE ACCENT;Ll;0;L;0475 030F;;;;N;CYRILLIC SMALL LETTER IZHITSA DOUBLE GRAVE;;0476;;0476
+0478;CYRILLIC CAPITAL LETTER UK;Lu;0;L;;;;;N;CYRILLIC CAPITAL LETTER UK DIGRAPH;;;0479;
+0479;CYRILLIC SMALL LETTER UK;Ll;0;L;;;;;N;CYRILLIC SMALL LETTER UK DIGRAPH;;0478;;0478
+047A;CYRILLIC CAPITAL LETTER ROUND OMEGA;Lu;0;L;;;;;N;;;;047B;
+047B;CYRILLIC SMALL LETTER ROUND OMEGA;Ll;0;L;;;;;N;;;047A;;047A
+047C;CYRILLIC CAPITAL LETTER OMEGA WITH TITLO;Lu;0;L;;;;;N;CYRILLIC CAPITAL LETTER OMEGA TITLO;;;047D;
+047D;CYRILLIC SMALL LETTER OMEGA WITH TITLO;Ll;0;L;;;;;N;CYRILLIC SMALL LETTER OMEGA TITLO;;047C;;047C
+047E;CYRILLIC CAPITAL LETTER OT;Lu;0;L;;;;;N;;;;047F;
+047F;CYRILLIC SMALL LETTER OT;Ll;0;L;;;;;N;;;047E;;047E
+0480;CYRILLIC CAPITAL LETTER KOPPA;Lu;0;L;;;;;N;;;;0481;
+0481;CYRILLIC SMALL LETTER KOPPA;Ll;0;L;;;;;N;;;0480;;0480
+0482;CYRILLIC THOUSANDS SIGN;So;0;L;;;;;N;;;;;
+0483;COMBINING CYRILLIC TITLO;Mn;230;NSM;;;;;N;CYRILLIC NON-SPACING TITLO;;;;
+0484;COMBINING CYRILLIC PALATALIZATION;Mn;230;NSM;;;;;N;CYRILLIC NON-SPACING PALATALIZATION;;;;
+0485;COMBINING CYRILLIC DASIA PNEUMATA;Mn;230;NSM;;;;;N;CYRILLIC NON-SPACING DASIA PNEUMATA;;;;
+0486;COMBINING CYRILLIC PSILI PNEUMATA;Mn;230;NSM;;;;;N;CYRILLIC NON-SPACING PSILI PNEUMATA;;;;
+0488;COMBINING CYRILLIC HUNDRED THOUSANDS SIGN;Me;0;NSM;;;;;N;;;;;
+0489;COMBINING CYRILLIC MILLIONS SIGN;Me;0;NSM;;;;;N;;;;;
+048A;CYRILLIC CAPITAL LETTER SHORT I WITH TAIL;Lu;0;L;;;;;N;;;;048B;
+048B;CYRILLIC SMALL LETTER SHORT I WITH TAIL;Ll;0;L;;;;;N;;;048A;;048A
+048C;CYRILLIC CAPITAL LETTER SEMISOFT SIGN;Lu;0;L;;;;;N;;;;048D;
+048D;CYRILLIC SMALL LETTER SEMISOFT SIGN;Ll;0;L;;;;;N;;;048C;;048C
+048E;CYRILLIC CAPITAL LETTER ER WITH TICK;Lu;0;L;;;;;N;;;;048F;
+048F;CYRILLIC SMALL LETTER ER WITH TICK;Ll;0;L;;;;;N;;;048E;;048E
+0490;CYRILLIC CAPITAL LETTER GHE WITH UPTURN;Lu;0;L;;;;;N;CYRILLIC CAPITAL LETTER GE WITH UPTURN;;;0491;
+0491;CYRILLIC SMALL LETTER GHE WITH UPTURN;Ll;0;L;;;;;N;CYRILLIC SMALL LETTER GE WITH UPTURN;;0490;;0490
+0492;CYRILLIC CAPITAL LETTER GHE WITH STROKE;Lu;0;L;;;;;N;CYRILLIC CAPITAL LETTER GE BAR;;;0493;
+0493;CYRILLIC SMALL LETTER GHE WITH STROKE;Ll;0;L;;;;;N;CYRILLIC SMALL LETTER GE BAR;;0492;;0492
+0494;CYRILLIC CAPITAL LETTER GHE WITH MIDDLE HOOK;Lu;0;L;;;;;N;CYRILLIC CAPITAL LETTER GE HOOK;;;0495;
+0495;CYRILLIC SMALL LETTER GHE WITH MIDDLE HOOK;Ll;0;L;;;;;N;CYRILLIC SMALL LETTER GE HOOK;;0494;;0494
+0496;CYRILLIC CAPITAL LETTER ZHE WITH DESCENDER;Lu;0;L;;;;;N;CYRILLIC CAPITAL LETTER ZHE WITH RIGHT DESCENDER;;;0497;
+0497;CYRILLIC SMALL LETTER ZHE WITH DESCENDER;Ll;0;L;;;;;N;CYRILLIC SMALL LETTER ZHE WITH RIGHT DESCENDER;;0496;;0496
+0498;CYRILLIC CAPITAL LETTER ZE WITH DESCENDER;Lu;0;L;;;;;N;CYRILLIC CAPITAL LETTER ZE CEDILLA;;;0499;
+0499;CYRILLIC SMALL LETTER ZE WITH DESCENDER;Ll;0;L;;;;;N;CYRILLIC SMALL LETTER ZE CEDILLA;;0498;;0498
+049A;CYRILLIC CAPITAL LETTER KA WITH DESCENDER;Lu;0;L;;;;;N;CYRILLIC CAPITAL LETTER KA WITH RIGHT DESCENDER;;;049B;
+049B;CYRILLIC SMALL LETTER KA WITH DESCENDER;Ll;0;L;;;;;N;CYRILLIC SMALL LETTER KA WITH RIGHT DESCENDER;;049A;;049A
+049C;CYRILLIC CAPITAL LETTER KA WITH VERTICAL STROKE;Lu;0;L;;;;;N;CYRILLIC CAPITAL LETTER KA VERTICAL BAR;;;049D;
+049D;CYRILLIC SMALL LETTER KA WITH VERTICAL STROKE;Ll;0;L;;;;;N;CYRILLIC SMALL LETTER KA VERTICAL BAR;;049C;;049C
+049E;CYRILLIC CAPITAL LETTER KA WITH STROKE;Lu;0;L;;;;;N;CYRILLIC CAPITAL LETTER KA BAR;;;049F;
+049F;CYRILLIC SMALL LETTER KA WITH STROKE;Ll;0;L;;;;;N;CYRILLIC SMALL LETTER KA BAR;;049E;;049E
+04A0;CYRILLIC CAPITAL LETTER BASHKIR KA;Lu;0;L;;;;;N;CYRILLIC CAPITAL LETTER REVERSED GE KA;;;04A1;
+04A1;CYRILLIC SMALL LETTER BASHKIR KA;Ll;0;L;;;;;N;CYRILLIC SMALL LETTER REVERSED GE KA;;04A0;;04A0
+04A2;CYRILLIC CAPITAL LETTER EN WITH DESCENDER;Lu;0;L;;;;;N;CYRILLIC CAPITAL LETTER EN WITH RIGHT DESCENDER;;;04A3;
+04A3;CYRILLIC SMALL LETTER EN WITH DESCENDER;Ll;0;L;;;;;N;CYRILLIC SMALL LETTER EN WITH RIGHT DESCENDER;;04A2;;04A2
+04A4;CYRILLIC CAPITAL LIGATURE EN GHE;Lu;0;L;;;;;N;CYRILLIC CAPITAL LETTER EN GE;;;04A5;
+04A5;CYRILLIC SMALL LIGATURE EN GHE;Ll;0;L;;;;;N;CYRILLIC SMALL LETTER EN GE;;04A4;;04A4
+04A6;CYRILLIC CAPITAL LETTER PE WITH MIDDLE HOOK;Lu;0;L;;;;;N;CYRILLIC CAPITAL LETTER PE HOOK;Abkhasian;;04A7;
+04A7;CYRILLIC SMALL LETTER PE WITH MIDDLE HOOK;Ll;0;L;;;;;N;CYRILLIC SMALL LETTER PE HOOK;Abkhasian;04A6;;04A6
+04A8;CYRILLIC CAPITAL LETTER ABKHASIAN HA;Lu;0;L;;;;;N;CYRILLIC CAPITAL LETTER O HOOK;;;04A9;
+04A9;CYRILLIC SMALL LETTER ABKHASIAN HA;Ll;0;L;;;;;N;CYRILLIC SMALL LETTER O HOOK;;04A8;;04A8
+04AA;CYRILLIC CAPITAL LETTER ES WITH DESCENDER;Lu;0;L;;;;;N;CYRILLIC CAPITAL LETTER ES CEDILLA;;;04AB;
+04AB;CYRILLIC SMALL LETTER ES WITH DESCENDER;Ll;0;L;;;;;N;CYRILLIC SMALL LETTER ES CEDILLA;;04AA;;04AA
+04AC;CYRILLIC CAPITAL LETTER TE WITH DESCENDER;Lu;0;L;;;;;N;CYRILLIC CAPITAL LETTER TE WITH RIGHT DESCENDER;;;04AD;
+04AD;CYRILLIC SMALL LETTER TE WITH DESCENDER;Ll;0;L;;;;;N;CYRILLIC SMALL LETTER TE WITH RIGHT DESCENDER;;04AC;;04AC
+04AE;CYRILLIC CAPITAL LETTER STRAIGHT U;Lu;0;L;;;;;N;;;;04AF;
+04AF;CYRILLIC SMALL LETTER STRAIGHT U;Ll;0;L;;;;;N;;;04AE;;04AE
+04B0;CYRILLIC CAPITAL LETTER STRAIGHT U WITH STROKE;Lu;0;L;;;;;N;CYRILLIC CAPITAL LETTER STRAIGHT U BAR;;;04B1;
+04B1;CYRILLIC SMALL LETTER STRAIGHT U WITH STROKE;Ll;0;L;;;;;N;CYRILLIC SMALL LETTER STRAIGHT U BAR;;04B0;;04B0
+04B2;CYRILLIC CAPITAL LETTER HA WITH DESCENDER;Lu;0;L;;;;;N;CYRILLIC CAPITAL LETTER KHA WITH RIGHT DESCENDER;;;04B3;
+04B3;CYRILLIC SMALL LETTER HA WITH DESCENDER;Ll;0;L;;;;;N;CYRILLIC SMALL LETTER KHA WITH RIGHT DESCENDER;;04B2;;04B2
+04B4;CYRILLIC CAPITAL LIGATURE TE TSE;Lu;0;L;;;;;N;CYRILLIC CAPITAL LETTER TE TSE;Abkhasian;;04B5;
+04B5;CYRILLIC SMALL LIGATURE TE TSE;Ll;0;L;;;;;N;CYRILLIC SMALL LETTER TE TSE;Abkhasian;04B4;;04B4
+04B6;CYRILLIC CAPITAL LETTER CHE WITH DESCENDER;Lu;0;L;;;;;N;CYRILLIC CAPITAL LETTER CHE WITH RIGHT DESCENDER;;;04B7;
+04B7;CYRILLIC SMALL LETTER CHE WITH DESCENDER;Ll;0;L;;;;;N;CYRILLIC SMALL LETTER CHE WITH RIGHT DESCENDER;;04B6;;04B6
+04B8;CYRILLIC CAPITAL LETTER CHE WITH VERTICAL STROKE;Lu;0;L;;;;;N;CYRILLIC CAPITAL LETTER CHE VERTICAL BAR;;;04B9;
+04B9;CYRILLIC SMALL LETTER CHE WITH VERTICAL STROKE;Ll;0;L;;;;;N;CYRILLIC SMALL LETTER CHE VERTICAL BAR;;04B8;;04B8
+04BA;CYRILLIC CAPITAL LETTER SHHA;Lu;0;L;;;;;N;CYRILLIC CAPITAL LETTER H;;;04BB;
+04BB;CYRILLIC SMALL LETTER SHHA;Ll;0;L;;;;;N;CYRILLIC SMALL LETTER H;;04BA;;04BA
+04BC;CYRILLIC CAPITAL LETTER ABKHASIAN CHE;Lu;0;L;;;;;N;CYRILLIC CAPITAL LETTER IE HOOK;;;04BD;
+04BD;CYRILLIC SMALL LETTER ABKHASIAN CHE;Ll;0;L;;;;;N;CYRILLIC SMALL LETTER IE HOOK;;04BC;;04BC
+04BE;CYRILLIC CAPITAL LETTER ABKHASIAN CHE WITH DESCENDER;Lu;0;L;;;;;N;CYRILLIC CAPITAL LETTER IE HOOK OGONEK;;;04BF;
+04BF;CYRILLIC SMALL LETTER ABKHASIAN CHE WITH DESCENDER;Ll;0;L;;;;;N;CYRILLIC SMALL LETTER IE HOOK OGONEK;;04BE;;04BE
+04C0;CYRILLIC LETTER PALOCHKA;Lu;0;L;;;;;N;CYRILLIC LETTER I;;;;
+04C1;CYRILLIC CAPITAL LETTER ZHE WITH BREVE;Lu;0;L;0416 0306;;;;N;CYRILLIC CAPITAL LETTER SHORT ZHE;;;04C2;
+04C2;CYRILLIC SMALL LETTER ZHE WITH BREVE;Ll;0;L;0436 0306;;;;N;CYRILLIC SMALL LETTER SHORT ZHE;;04C1;;04C1
+04C3;CYRILLIC CAPITAL LETTER KA WITH HOOK;Lu;0;L;;;;;N;CYRILLIC CAPITAL LETTER KA HOOK;;;04C4;
+04C4;CYRILLIC SMALL LETTER KA WITH HOOK;Ll;0;L;;;;;N;CYRILLIC SMALL LETTER KA HOOK;;04C3;;04C3
+04C5;CYRILLIC CAPITAL LETTER EL WITH TAIL;Lu;0;L;;;;;N;;;;04C6;
+04C6;CYRILLIC SMALL LETTER EL WITH TAIL;Ll;0;L;;;;;N;;;04C5;;04C5
+04C7;CYRILLIC CAPITAL LETTER EN WITH HOOK;Lu;0;L;;;;;N;CYRILLIC CAPITAL LETTER EN HOOK;;;04C8;
+04C8;CYRILLIC SMALL LETTER EN WITH HOOK;Ll;0;L;;;;;N;CYRILLIC SMALL LETTER EN HOOK;;04C7;;04C7
+04C9;CYRILLIC CAPITAL LETTER EN WITH TAIL;Lu;0;L;;;;;N;;;;04CA;
+04CA;CYRILLIC SMALL LETTER EN WITH TAIL;Ll;0;L;;;;;N;;;04C9;;04C9
+04CB;CYRILLIC CAPITAL LETTER KHAKASSIAN CHE;Lu;0;L;;;;;N;CYRILLIC CAPITAL LETTER CHE WITH LEFT DESCENDER;;;04CC;
+04CC;CYRILLIC SMALL LETTER KHAKASSIAN CHE;Ll;0;L;;;;;N;CYRILLIC SMALL LETTER CHE WITH LEFT DESCENDER;;04CB;;04CB
+04CD;CYRILLIC CAPITAL LETTER EM WITH TAIL;Lu;0;L;;;;;N;;;;04CE;
+04CE;CYRILLIC SMALL LETTER EM WITH TAIL;Ll;0;L;;;;;N;;;04CD;;04CD
+04D0;CYRILLIC CAPITAL LETTER A WITH BREVE;Lu;0;L;0410 0306;;;;N;;;;04D1;
+04D1;CYRILLIC SMALL LETTER A WITH BREVE;Ll;0;L;0430 0306;;;;N;;;04D0;;04D0
+04D2;CYRILLIC CAPITAL LETTER A WITH DIAERESIS;Lu;0;L;0410 0308;;;;N;;;;04D3;
+04D3;CYRILLIC SMALL LETTER A WITH DIAERESIS;Ll;0;L;0430 0308;;;;N;;;04D2;;04D2
+04D4;CYRILLIC CAPITAL LIGATURE A IE;Lu;0;L;;;;;N;;;;04D5;
+04D5;CYRILLIC SMALL LIGATURE A IE;Ll;0;L;;;;;N;;;04D4;;04D4
+04D6;CYRILLIC CAPITAL LETTER IE WITH BREVE;Lu;0;L;0415 0306;;;;N;;;;04D7;
+04D7;CYRILLIC SMALL LETTER IE WITH BREVE;Ll;0;L;0435 0306;;;;N;;;04D6;;04D6
+04D8;CYRILLIC CAPITAL LETTER SCHWA;Lu;0;L;;;;;N;;;;04D9;
+04D9;CYRILLIC SMALL LETTER SCHWA;Ll;0;L;;;;;N;;;04D8;;04D8
+04DA;CYRILLIC CAPITAL LETTER SCHWA WITH DIAERESIS;Lu;0;L;04D8 0308;;;;N;;;;04DB;
+04DB;CYRILLIC SMALL LETTER SCHWA WITH DIAERESIS;Ll;0;L;04D9 0308;;;;N;;;04DA;;04DA
+04DC;CYRILLIC CAPITAL LETTER ZHE WITH DIAERESIS;Lu;0;L;0416 0308;;;;N;;;;04DD;
+04DD;CYRILLIC SMALL LETTER ZHE WITH DIAERESIS;Ll;0;L;0436 0308;;;;N;;;04DC;;04DC
+04DE;CYRILLIC CAPITAL LETTER ZE WITH DIAERESIS;Lu;0;L;0417 0308;;;;N;;;;04DF;
+04DF;CYRILLIC SMALL LETTER ZE WITH DIAERESIS;Ll;0;L;0437 0308;;;;N;;;04DE;;04DE
+04E0;CYRILLIC CAPITAL LETTER ABKHASIAN DZE;Lu;0;L;;;;;N;;;;04E1;
+04E1;CYRILLIC SMALL LETTER ABKHASIAN DZE;Ll;0;L;;;;;N;;;04E0;;04E0
+04E2;CYRILLIC CAPITAL LETTER I WITH MACRON;Lu;0;L;0418 0304;;;;N;;;;04E3;
+04E3;CYRILLIC SMALL LETTER I WITH MACRON;Ll;0;L;0438 0304;;;;N;;;04E2;;04E2
+04E4;CYRILLIC CAPITAL LETTER I WITH DIAERESIS;Lu;0;L;0418 0308;;;;N;;;;04E5;
+04E5;CYRILLIC SMALL LETTER I WITH DIAERESIS;Ll;0;L;0438 0308;;;;N;;;04E4;;04E4
+04E6;CYRILLIC CAPITAL LETTER O WITH DIAERESIS;Lu;0;L;041E 0308;;;;N;;;;04E7;
+04E7;CYRILLIC SMALL LETTER O WITH DIAERESIS;Ll;0;L;043E 0308;;;;N;;;04E6;;04E6
+04E8;CYRILLIC CAPITAL LETTER BARRED O;Lu;0;L;;;;;N;;;;04E9;
+04E9;CYRILLIC SMALL LETTER BARRED O;Ll;0;L;;;;;N;;;04E8;;04E8
+04EA;CYRILLIC CAPITAL LETTER BARRED O WITH DIAERESIS;Lu;0;L;04E8 0308;;;;N;;;;04EB;
+04EB;CYRILLIC SMALL LETTER BARRED O WITH DIAERESIS;Ll;0;L;04E9 0308;;;;N;;;04EA;;04EA
+04EC;CYRILLIC CAPITAL LETTER E WITH DIAERESIS;Lu;0;L;042D 0308;;;;N;;;;04ED;
+04ED;CYRILLIC SMALL LETTER E WITH DIAERESIS;Ll;0;L;044D 0308;;;;N;;;04EC;;04EC
+04EE;CYRILLIC CAPITAL LETTER U WITH MACRON;Lu;0;L;0423 0304;;;;N;;;;04EF;
+04EF;CYRILLIC SMALL LETTER U WITH MACRON;Ll;0;L;0443 0304;;;;N;;;04EE;;04EE
+04F0;CYRILLIC CAPITAL LETTER U WITH DIAERESIS;Lu;0;L;0423 0308;;;;N;;;;04F1;
+04F1;CYRILLIC SMALL LETTER U WITH DIAERESIS;Ll;0;L;0443 0308;;;;N;;;04F0;;04F0
+04F2;CYRILLIC CAPITAL LETTER U WITH DOUBLE ACUTE;Lu;0;L;0423 030B;;;;N;;;;04F3;
+04F3;CYRILLIC SMALL LETTER U WITH DOUBLE ACUTE;Ll;0;L;0443 030B;;;;N;;;04F2;;04F2
+04F4;CYRILLIC CAPITAL LETTER CHE WITH DIAERESIS;Lu;0;L;0427 0308;;;;N;;;;04F5;
+04F5;CYRILLIC SMALL LETTER CHE WITH DIAERESIS;Ll;0;L;0447 0308;;;;N;;;04F4;;04F4
+04F6;CYRILLIC CAPITAL LETTER GHE WITH DESCENDER;Lu;0;L;;;;;N;;;;04F7;
+04F7;CYRILLIC SMALL LETTER GHE WITH DESCENDER;Ll;0;L;;;;;N;;;04F6;;04F6
+04F8;CYRILLIC CAPITAL LETTER YERU WITH DIAERESIS;Lu;0;L;042B 0308;;;;N;;;;04F9;
+04F9;CYRILLIC SMALL LETTER YERU WITH DIAERESIS;Ll;0;L;044B 0308;;;;N;;;04F8;;04F8
+0500;CYRILLIC CAPITAL LETTER KOMI DE;Lu;0;L;;;;;N;;;;0501;
+0501;CYRILLIC SMALL LETTER KOMI DE;Ll;0;L;;;;;N;;;0500;;0500
+0502;CYRILLIC CAPITAL LETTER KOMI DJE;Lu;0;L;;;;;N;;;;0503;
+0503;CYRILLIC SMALL LETTER KOMI DJE;Ll;0;L;;;;;N;;;0502;;0502
+0504;CYRILLIC CAPITAL LETTER KOMI ZJE;Lu;0;L;;;;;N;;;;0505;
+0505;CYRILLIC SMALL LETTER KOMI ZJE;Ll;0;L;;;;;N;;;0504;;0504
+0506;CYRILLIC CAPITAL LETTER KOMI DZJE;Lu;0;L;;;;;N;;;;0507;
+0507;CYRILLIC SMALL LETTER KOMI DZJE;Ll;0;L;;;;;N;;;0506;;0506
+0508;CYRILLIC CAPITAL LETTER KOMI LJE;Lu;0;L;;;;;N;;;;0509;
+0509;CYRILLIC SMALL LETTER KOMI LJE;Ll;0;L;;;;;N;;;0508;;0508
+050A;CYRILLIC CAPITAL LETTER KOMI NJE;Lu;0;L;;;;;N;;;;050B;
+050B;CYRILLIC SMALL LETTER KOMI NJE;Ll;0;L;;;;;N;;;050A;;050A
+050C;CYRILLIC CAPITAL LETTER KOMI SJE;Lu;0;L;;;;;N;;;;050D;
+050D;CYRILLIC SMALL LETTER KOMI SJE;Ll;0;L;;;;;N;;;050C;;050C
+050E;CYRILLIC CAPITAL LETTER KOMI TJE;Lu;0;L;;;;;N;;;;050F;
+050F;CYRILLIC SMALL LETTER KOMI TJE;Ll;0;L;;;;;N;;;050E;;050E
+0531;ARMENIAN CAPITAL LETTER AYB;Lu;0;L;;;;;N;;;;0561;
+0532;ARMENIAN CAPITAL LETTER BEN;Lu;0;L;;;;;N;;;;0562;
+0533;ARMENIAN CAPITAL LETTER GIM;Lu;0;L;;;;;N;;;;0563;
+0534;ARMENIAN CAPITAL LETTER DA;Lu;0;L;;;;;N;;;;0564;
+0535;ARMENIAN CAPITAL LETTER ECH;Lu;0;L;;;;;N;;;;0565;
+0536;ARMENIAN CAPITAL LETTER ZA;Lu;0;L;;;;;N;;;;0566;
+0537;ARMENIAN CAPITAL LETTER EH;Lu;0;L;;;;;N;;;;0567;
+0538;ARMENIAN CAPITAL LETTER ET;Lu;0;L;;;;;N;;;;0568;
+0539;ARMENIAN CAPITAL LETTER TO;Lu;0;L;;;;;N;;;;0569;
+053A;ARMENIAN CAPITAL LETTER ZHE;Lu;0;L;;;;;N;;;;056A;
+053B;ARMENIAN CAPITAL LETTER INI;Lu;0;L;;;;;N;;;;056B;
+053C;ARMENIAN CAPITAL LETTER LIWN;Lu;0;L;;;;;N;;;;056C;
+053D;ARMENIAN CAPITAL LETTER XEH;Lu;0;L;;;;;N;;;;056D;
+053E;ARMENIAN CAPITAL LETTER CA;Lu;0;L;;;;;N;;;;056E;
+053F;ARMENIAN CAPITAL LETTER KEN;Lu;0;L;;;;;N;;;;056F;
+0540;ARMENIAN CAPITAL LETTER HO;Lu;0;L;;;;;N;;;;0570;
+0541;ARMENIAN CAPITAL LETTER JA;Lu;0;L;;;;;N;;;;0571;
+0542;ARMENIAN CAPITAL LETTER GHAD;Lu;0;L;;;;;N;ARMENIAN CAPITAL LETTER LAD;;;0572;
+0543;ARMENIAN CAPITAL LETTER CHEH;Lu;0;L;;;;;N;;;;0573;
+0544;ARMENIAN CAPITAL LETTER MEN;Lu;0;L;;;;;N;;;;0574;
+0545;ARMENIAN CAPITAL LETTER YI;Lu;0;L;;;;;N;;;;0575;
+0546;ARMENIAN CAPITAL LETTER NOW;Lu;0;L;;;;;N;;;;0576;
+0547;ARMENIAN CAPITAL LETTER SHA;Lu;0;L;;;;;N;;;;0577;
+0548;ARMENIAN CAPITAL LETTER VO;Lu;0;L;;;;;N;;;;0578;
+0549;ARMENIAN CAPITAL LETTER CHA;Lu;0;L;;;;;N;;;;0579;
+054A;ARMENIAN CAPITAL LETTER PEH;Lu;0;L;;;;;N;;;;057A;
+054B;ARMENIAN CAPITAL LETTER JHEH;Lu;0;L;;;;;N;;;;057B;
+054C;ARMENIAN CAPITAL LETTER RA;Lu;0;L;;;;;N;;;;057C;
+054D;ARMENIAN CAPITAL LETTER SEH;Lu;0;L;;;;;N;;;;057D;
+054E;ARMENIAN CAPITAL LETTER VEW;Lu;0;L;;;;;N;;;;057E;
+054F;ARMENIAN CAPITAL LETTER TIWN;Lu;0;L;;;;;N;;;;057F;
+0550;ARMENIAN CAPITAL LETTER REH;Lu;0;L;;;;;N;;;;0580;
+0551;ARMENIAN CAPITAL LETTER CO;Lu;0;L;;;;;N;;;;0581;
+0552;ARMENIAN CAPITAL LETTER YIWN;Lu;0;L;;;;;N;;;;0582;
+0553;ARMENIAN CAPITAL LETTER PIWR;Lu;0;L;;;;;N;;;;0583;
+0554;ARMENIAN CAPITAL LETTER KEH;Lu;0;L;;;;;N;;;;0584;
+0555;ARMENIAN CAPITAL LETTER OH;Lu;0;L;;;;;N;;;;0585;
+0556;ARMENIAN CAPITAL LETTER FEH;Lu;0;L;;;;;N;;;;0586;
+0559;ARMENIAN MODIFIER LETTER LEFT HALF RING;Lm;0;L;;;;;N;;;;;
+055A;ARMENIAN APOSTROPHE;Po;0;L;;;;;N;ARMENIAN MODIFIER LETTER RIGHT HALF RING;;;;
+055B;ARMENIAN EMPHASIS MARK;Po;0;L;;;;;N;;;;;
+055C;ARMENIAN EXCLAMATION MARK;Po;0;L;;;;;N;;;;;
+055D;ARMENIAN COMMA;Po;0;L;;;;;N;;;;;
+055E;ARMENIAN QUESTION MARK;Po;0;L;;;;;N;;;;;
+055F;ARMENIAN ABBREVIATION MARK;Po;0;L;;;;;N;;;;;
+0561;ARMENIAN SMALL LETTER AYB;Ll;0;L;;;;;N;;;0531;;0531
+0562;ARMENIAN SMALL LETTER BEN;Ll;0;L;;;;;N;;;0532;;0532
+0563;ARMENIAN SMALL LETTER GIM;Ll;0;L;;;;;N;;;0533;;0533
+0564;ARMENIAN SMALL LETTER DA;Ll;0;L;;;;;N;;;0534;;0534
+0565;ARMENIAN SMALL LETTER ECH;Ll;0;L;;;;;N;;;0535;;0535
+0566;ARMENIAN SMALL LETTER ZA;Ll;0;L;;;;;N;;;0536;;0536
+0567;ARMENIAN SMALL LETTER EH;Ll;0;L;;;;;N;;;0537;;0537
+0568;ARMENIAN SMALL LETTER ET;Ll;0;L;;;;;N;;;0538;;0538
+0569;ARMENIAN SMALL LETTER TO;Ll;0;L;;;;;N;;;0539;;0539
+056A;ARMENIAN SMALL LETTER ZHE;Ll;0;L;;;;;N;;;053A;;053A
+056B;ARMENIAN SMALL LETTER INI;Ll;0;L;;;;;N;;;053B;;053B
+056C;ARMENIAN SMALL LETTER LIWN;Ll;0;L;;;;;N;;;053C;;053C
+056D;ARMENIAN SMALL LETTER XEH;Ll;0;L;;;;;N;;;053D;;053D
+056E;ARMENIAN SMALL LETTER CA;Ll;0;L;;;;;N;;;053E;;053E
+056F;ARMENIAN SMALL LETTER KEN;Ll;0;L;;;;;N;;;053F;;053F
+0570;ARMENIAN SMALL LETTER HO;Ll;0;L;;;;;N;;;0540;;0540
+0571;ARMENIAN SMALL LETTER JA;Ll;0;L;;;;;N;;;0541;;0541
+0572;ARMENIAN SMALL LETTER GHAD;Ll;0;L;;;;;N;ARMENIAN SMALL LETTER LAD;;0542;;0542
+0573;ARMENIAN SMALL LETTER CHEH;Ll;0;L;;;;;N;;;0543;;0543
+0574;ARMENIAN SMALL LETTER MEN;Ll;0;L;;;;;N;;;0544;;0544
+0575;ARMENIAN SMALL LETTER YI;Ll;0;L;;;;;N;;;0545;;0545
+0576;ARMENIAN SMALL LETTER NOW;Ll;0;L;;;;;N;;;0546;;0546
+0577;ARMENIAN SMALL LETTER SHA;Ll;0;L;;;;;N;;;0547;;0547
+0578;ARMENIAN SMALL LETTER VO;Ll;0;L;;;;;N;;;0548;;0548
+0579;ARMENIAN SMALL LETTER CHA;Ll;0;L;;;;;N;;;0549;;0549
+057A;ARMENIAN SMALL LETTER PEH;Ll;0;L;;;;;N;;;054A;;054A
+057B;ARMENIAN SMALL LETTER JHEH;Ll;0;L;;;;;N;;;054B;;054B
+057C;ARMENIAN SMALL LETTER RA;Ll;0;L;;;;;N;;;054C;;054C
+057D;ARMENIAN SMALL LETTER SEH;Ll;0;L;;;;;N;;;054D;;054D
+057E;ARMENIAN SMALL LETTER VEW;Ll;0;L;;;;;N;;;054E;;054E
+057F;ARMENIAN SMALL LETTER TIWN;Ll;0;L;;;;;N;;;054F;;054F
+0580;ARMENIAN SMALL LETTER REH;Ll;0;L;;;;;N;;;0550;;0550
+0581;ARMENIAN SMALL LETTER CO;Ll;0;L;;;;;N;;;0551;;0551
+0582;ARMENIAN SMALL LETTER YIWN;Ll;0;L;;;;;N;;;0552;;0552
+0583;ARMENIAN SMALL LETTER PIWR;Ll;0;L;;;;;N;;;0553;;0553
+0584;ARMENIAN SMALL LETTER KEH;Ll;0;L;;;;;N;;;0554;;0554
+0585;ARMENIAN SMALL LETTER OH;Ll;0;L;;;;;N;;;0555;;0555
+0586;ARMENIAN SMALL LETTER FEH;Ll;0;L;;;;;N;;;0556;;0556
+0587;ARMENIAN SMALL LIGATURE ECH YIWN;Ll;0;L;<compat> 0565 0582;;;;N;;;;;
+0589;ARMENIAN FULL STOP;Po;0;L;;;;;N;ARMENIAN PERIOD;;;;
+058A;ARMENIAN HYPHEN;Pd;0;ON;;;;;N;;;;;
+0591;HEBREW ACCENT ETNAHTA;Mn;220;NSM;;;;;N;;;;;
+0592;HEBREW ACCENT SEGOL;Mn;230;NSM;;;;;N;;;;;
+0593;HEBREW ACCENT SHALSHELET;Mn;230;NSM;;;;;N;;;;;
+0594;HEBREW ACCENT ZAQEF QATAN;Mn;230;NSM;;;;;N;;;;;
+0595;HEBREW ACCENT ZAQEF GADOL;Mn;230;NSM;;;;;N;;;;;
+0596;HEBREW ACCENT TIPEHA;Mn;220;NSM;;;;;N;;*;;;
+0597;HEBREW ACCENT REVIA;Mn;230;NSM;;;;;N;;;;;
+0598;HEBREW ACCENT ZARQA;Mn;230;NSM;;;;;N;;*;;;
+0599;HEBREW ACCENT PASHTA;Mn;230;NSM;;;;;N;;;;;
+059A;HEBREW ACCENT YETIV;Mn;222;NSM;;;;;N;;;;;
+059B;HEBREW ACCENT TEVIR;Mn;220;NSM;;;;;N;;;;;
+059C;HEBREW ACCENT GERESH;Mn;230;NSM;;;;;N;;;;;
+059D;HEBREW ACCENT GERESH MUQDAM;Mn;230;NSM;;;;;N;;;;;
+059E;HEBREW ACCENT GERSHAYIM;Mn;230;NSM;;;;;N;;;;;
+059F;HEBREW ACCENT QARNEY PARA;Mn;230;NSM;;;;;N;;;;;
+05A0;HEBREW ACCENT TELISHA GEDOLA;Mn;230;NSM;;;;;N;;;;;
+05A1;HEBREW ACCENT PAZER;Mn;230;NSM;;;;;N;;;;;
+05A2;HEBREW ACCENT ATNAH HAFUKH;Mn;220;NSM;;;;;N;;;;;
+05A3;HEBREW ACCENT MUNAH;Mn;220;NSM;;;;;N;;;;;
+05A4;HEBREW ACCENT MAHAPAKH;Mn;220;NSM;;;;;N;;;;;
+05A5;HEBREW ACCENT MERKHA;Mn;220;NSM;;;;;N;;*;;;
+05A6;HEBREW ACCENT MERKHA KEFULA;Mn;220;NSM;;;;;N;;;;;
+05A7;HEBREW ACCENT DARGA;Mn;220;NSM;;;;;N;;;;;
+05A8;HEBREW ACCENT QADMA;Mn;230;NSM;;;;;N;;*;;;
+05A9;HEBREW ACCENT TELISHA QETANA;Mn;230;NSM;;;;;N;;;;;
+05AA;HEBREW ACCENT YERAH BEN YOMO;Mn;220;NSM;;;;;N;;*;;;
+05AB;HEBREW ACCENT OLE;Mn;230;NSM;;;;;N;;;;;
+05AC;HEBREW ACCENT ILUY;Mn;230;NSM;;;;;N;;;;;
+05AD;HEBREW ACCENT DEHI;Mn;222;NSM;;;;;N;;;;;
+05AE;HEBREW ACCENT ZINOR;Mn;228;NSM;;;;;N;;;;;
+05AF;HEBREW MARK MASORA CIRCLE;Mn;230;NSM;;;;;N;;;;;
+05B0;HEBREW POINT SHEVA;Mn;10;NSM;;;;;N;;;;;
+05B1;HEBREW POINT HATAF SEGOL;Mn;11;NSM;;;;;N;;;;;
+05B2;HEBREW POINT HATAF PATAH;Mn;12;NSM;;;;;N;;;;;
+05B3;HEBREW POINT HATAF QAMATS;Mn;13;NSM;;;;;N;;;;;
+05B4;HEBREW POINT HIRIQ;Mn;14;NSM;;;;;N;;;;;
+05B5;HEBREW POINT TSERE;Mn;15;NSM;;;;;N;;;;;
+05B6;HEBREW POINT SEGOL;Mn;16;NSM;;;;;N;;;;;
+05B7;HEBREW POINT PATAH;Mn;17;NSM;;;;;N;;;;;
+05B8;HEBREW POINT QAMATS;Mn;18;NSM;;;;;N;;;;;
+05B9;HEBREW POINT HOLAM;Mn;19;NSM;;;;;N;;;;;
+05BB;HEBREW POINT QUBUTS;Mn;20;NSM;;;;;N;;;;;
+05BC;HEBREW POINT DAGESH OR MAPIQ;Mn;21;NSM;;;;;N;HEBREW POINT DAGESH;or shuruq;;;
+05BD;HEBREW POINT METEG;Mn;22;NSM;;;;;N;;*;;;
+05BE;HEBREW PUNCTUATION MAQAF;Po;0;R;;;;;N;;;;;
+05BF;HEBREW POINT RAFE;Mn;23;NSM;;;;;N;;;;;
+05C0;HEBREW PUNCTUATION PASEQ;Po;0;R;;;;;N;HEBREW POINT PASEQ;*;;;
+05C1;HEBREW POINT SHIN DOT;Mn;24;NSM;;;;;N;;;;;
+05C2;HEBREW POINT SIN DOT;Mn;25;NSM;;;;;N;;;;;
+05C3;HEBREW PUNCTUATION SOF PASUQ;Po;0;R;;;;;N;;*;;;
+05C4;HEBREW MARK UPPER DOT;Mn;230;NSM;;;;;N;;;;;
+05C5;HEBREW MARK LOWER DOT;Mn;220;NSM;;;;;N;;;;;
+05C6;HEBREW PUNCTUATION NUN HAFUKHA;Po;0;R;;;;;N;;;;;
+05C7;HEBREW POINT QAMATS QATAN;Mn;18;NSM;;;;;N;;;;;
+05D0;HEBREW LETTER ALEF;Lo;0;R;;;;;N;;;;;
+05D1;HEBREW LETTER BET;Lo;0;R;;;;;N;;;;;
+05D2;HEBREW LETTER GIMEL;Lo;0;R;;;;;N;;;;;
+05D3;HEBREW LETTER DALET;Lo;0;R;;;;;N;;;;;
+05D4;HEBREW LETTER HE;Lo;0;R;;;;;N;;;;;
+05D5;HEBREW LETTER VAV;Lo;0;R;;;;;N;;;;;
+05D6;HEBREW LETTER ZAYIN;Lo;0;R;;;;;N;;;;;
+05D7;HEBREW LETTER HET;Lo;0;R;;;;;N;;;;;
+05D8;HEBREW LETTER TET;Lo;0;R;;;;;N;;;;;
+05D9;HEBREW LETTER YOD;Lo;0;R;;;;;N;;;;;
+05DA;HEBREW LETTER FINAL KAF;Lo;0;R;;;;;N;;;;;
+05DB;HEBREW LETTER KAF;Lo;0;R;;;;;N;;;;;
+05DC;HEBREW LETTER LAMED;Lo;0;R;;;;;N;;;;;
+05DD;HEBREW LETTER FINAL MEM;Lo;0;R;;;;;N;;;;;
+05DE;HEBREW LETTER MEM;Lo;0;R;;;;;N;;;;;
+05DF;HEBREW LETTER FINAL NUN;Lo;0;R;;;;;N;;;;;
+05E0;HEBREW LETTER NUN;Lo;0;R;;;;;N;;;;;
+05E1;HEBREW LETTER SAMEKH;Lo;0;R;;;;;N;;;;;
+05E2;HEBREW LETTER AYIN;Lo;0;R;;;;;N;;;;;
+05E3;HEBREW LETTER FINAL PE;Lo;0;R;;;;;N;;;;;
+05E4;HEBREW LETTER PE;Lo;0;R;;;;;N;;;;;
+05E5;HEBREW LETTER FINAL TSADI;Lo;0;R;;;;;N;;;;;
+05E6;HEBREW LETTER TSADI;Lo;0;R;;;;;N;;;;;
+05E7;HEBREW LETTER QOF;Lo;0;R;;;;;N;;;;;
+05E8;HEBREW LETTER RESH;Lo;0;R;;;;;N;;;;;
+05E9;HEBREW LETTER SHIN;Lo;0;R;;;;;N;;;;;
+05EA;HEBREW LETTER TAV;Lo;0;R;;;;;N;;;;;
+05F0;HEBREW LIGATURE YIDDISH DOUBLE VAV;Lo;0;R;;;;;N;HEBREW LETTER DOUBLE VAV;;;;
+05F1;HEBREW LIGATURE YIDDISH VAV YOD;Lo;0;R;;;;;N;HEBREW LETTER VAV YOD;;;;
+05F2;HEBREW LIGATURE YIDDISH DOUBLE YOD;Lo;0;R;;;;;N;HEBREW LETTER DOUBLE YOD;;;;
+05F3;HEBREW PUNCTUATION GERESH;Po;0;R;;;;;N;;;;;
+05F4;HEBREW PUNCTUATION GERSHAYIM;Po;0;R;;;;;N;;;;;
+0600;ARABIC NUMBER SIGN;Cf;0;AL;;;;;N;;;;;
+0601;ARABIC SIGN SANAH;Cf;0;AL;;;;;N;;;;;
+0602;ARABIC FOOTNOTE MARKER;Cf;0;AL;;;;;N;;;;;
+0603;ARABIC SIGN SAFHA;Cf;0;AL;;;;;N;;;;;
+060B;AFGHANI SIGN;Sc;0;AL;;;;;N;;;;;
+060C;ARABIC COMMA;Po;0;CS;;;;;N;;;;;
+060D;ARABIC DATE SEPARATOR;Po;0;AL;;;;;N;;;;;
+060E;ARABIC POETIC VERSE SIGN;So;0;ON;;;;;N;;;;;
+060F;ARABIC SIGN MISRA;So;0;ON;;;;;N;;;;;
+0610;ARABIC SIGN SALLALLAHOU ALAYHE WASSALLAM;Mn;230;NSM;;;;;N;;;;;
+0611;ARABIC SIGN ALAYHE ASSALLAM;Mn;230;NSM;;;;;N;;;;;
+0612;ARABIC SIGN RAHMATULLAH ALAYHE;Mn;230;NSM;;;;;N;;;;;
+0613;ARABIC SIGN RADI ALLAHOU ANHU;Mn;230;NSM;;;;;N;;;;;
+0614;ARABIC SIGN TAKHALLUS;Mn;230;NSM;;;;;N;;;;;
+0615;ARABIC SMALL HIGH TAH;Mn;230;NSM;;;;;N;;;;;
+061B;ARABIC SEMICOLON;Po;0;AL;;;;;N;;;;;
+061E;ARABIC TRIPLE DOT PUNCTUATION MARK;Po;0;AL;;;;;N;;;;;
+061F;ARABIC QUESTION MARK;Po;0;AL;;;;;N;;;;;
+0621;ARABIC LETTER HAMZA;Lo;0;AL;;;;;N;ARABIC LETTER HAMZAH;;;;
+0622;ARABIC LETTER ALEF WITH MADDA ABOVE;Lo;0;AL;0627 0653;;;;N;ARABIC LETTER MADDAH ON ALEF;;;;
+0623;ARABIC LETTER ALEF WITH HAMZA ABOVE;Lo;0;AL;0627 0654;;;;N;ARABIC LETTER HAMZAH ON ALEF;;;;
+0624;ARABIC LETTER WAW WITH HAMZA ABOVE;Lo;0;AL;0648 0654;;;;N;ARABIC LETTER HAMZAH ON WAW;;;;
+0625;ARABIC LETTER ALEF WITH HAMZA BELOW;Lo;0;AL;0627 0655;;;;N;ARABIC LETTER HAMZAH UNDER ALEF;;;;
+0626;ARABIC LETTER YEH WITH HAMZA ABOVE;Lo;0;AL;064A 0654;;;;N;ARABIC LETTER HAMZAH ON YA;;;;
+0627;ARABIC LETTER ALEF;Lo;0;AL;;;;;N;;;;;
+0628;ARABIC LETTER BEH;Lo;0;AL;;;;;N;ARABIC LETTER BAA;;;;
+0629;ARABIC LETTER TEH MARBUTA;Lo;0;AL;;;;;N;ARABIC LETTER TAA MARBUTAH;;;;
+062A;ARABIC LETTER TEH;Lo;0;AL;;;;;N;ARABIC LETTER TAA;;;;
+062B;ARABIC LETTER THEH;Lo;0;AL;;;;;N;ARABIC LETTER THAA;;;;
+062C;ARABIC LETTER JEEM;Lo;0;AL;;;;;N;;;;;
+062D;ARABIC LETTER HAH;Lo;0;AL;;;;;N;ARABIC LETTER HAA;;;;
+062E;ARABIC LETTER KHAH;Lo;0;AL;;;;;N;ARABIC LETTER KHAA;;;;
+062F;ARABIC LETTER DAL;Lo;0;AL;;;;;N;;;;;
+0630;ARABIC LETTER THAL;Lo;0;AL;;;;;N;;;;;
+0631;ARABIC LETTER REH;Lo;0;AL;;;;;N;ARABIC LETTER RA;;;;
+0632;ARABIC LETTER ZAIN;Lo;0;AL;;;;;N;;;;;
+0633;ARABIC LETTER SEEN;Lo;0;AL;;;;;N;;;;;
+0634;ARABIC LETTER SHEEN;Lo;0;AL;;;;;N;;;;;
+0635;ARABIC LETTER SAD;Lo;0;AL;;;;;N;;;;;
+0636;ARABIC LETTER DAD;Lo;0;AL;;;;;N;;;;;
+0637;ARABIC LETTER TAH;Lo;0;AL;;;;;N;;;;;
+0638;ARABIC LETTER ZAH;Lo;0;AL;;;;;N;ARABIC LETTER DHAH;;;;
+0639;ARABIC LETTER AIN;Lo;0;AL;;;;;N;;;;;
+063A;ARABIC LETTER GHAIN;Lo;0;AL;;;;;N;;;;;
+0640;ARABIC TATWEEL;Lm;0;AL;;;;;N;;;;;
+0641;ARABIC LETTER FEH;Lo;0;AL;;;;;N;ARABIC LETTER FA;;;;
+0642;ARABIC LETTER QAF;Lo;0;AL;;;;;N;;;;;
+0643;ARABIC LETTER KAF;Lo;0;AL;;;;;N;ARABIC LETTER CAF;;;;
+0644;ARABIC LETTER LAM;Lo;0;AL;;;;;N;;;;;
+0645;ARABIC LETTER MEEM;Lo;0;AL;;;;;N;;;;;
+0646;ARABIC LETTER NOON;Lo;0;AL;;;;;N;;;;;
+0647;ARABIC LETTER HEH;Lo;0;AL;;;;;N;ARABIC LETTER HA;;;;
+0648;ARABIC LETTER WAW;Lo;0;AL;;;;;N;;;;;
+0649;ARABIC LETTER ALEF MAKSURA;Lo;0;AL;;;;;N;ARABIC LETTER ALEF MAQSURAH;;;;
+064A;ARABIC LETTER YEH;Lo;0;AL;;;;;N;ARABIC LETTER YA;;;;
+064B;ARABIC FATHATAN;Mn;27;NSM;;;;;N;;;;;
+064C;ARABIC DAMMATAN;Mn;28;NSM;;;;;N;;;;;
+064D;ARABIC KASRATAN;Mn;29;NSM;;;;;N;;;;;
+064E;ARABIC FATHA;Mn;30;NSM;;;;;N;ARABIC FATHAH;;;;
+064F;ARABIC DAMMA;Mn;31;NSM;;;;;N;ARABIC DAMMAH;;;;
+0650;ARABIC KASRA;Mn;32;NSM;;;;;N;ARABIC KASRAH;;;;
+0651;ARABIC SHADDA;Mn;33;NSM;;;;;N;ARABIC SHADDAH;;;;
+0652;ARABIC SUKUN;Mn;34;NSM;;;;;N;;;;;
+0653;ARABIC MADDAH ABOVE;Mn;230;NSM;;;;;N;;;;;
+0654;ARABIC HAMZA ABOVE;Mn;230;NSM;;;;;N;;;;;
+0655;ARABIC HAMZA BELOW;Mn;220;NSM;;;;;N;;;;;
+0656;ARABIC SUBSCRIPT ALEF;Mn;220;NSM;;;;;N;;;;;
+0657;ARABIC INVERTED DAMMA;Mn;230;NSM;;;;;N;;;;;
+0658;ARABIC MARK NOON GHUNNA;Mn;230;NSM;;;;;N;;;;;
+0659;ARABIC ZWARAKAY;Mn;230;NSM;;;;;N;;;;;
+065A;ARABIC VOWEL SIGN SMALL V ABOVE;Mn;230;NSM;;;;;N;;;;;
+065B;ARABIC VOWEL SIGN INVERTED SMALL V ABOVE;Mn;230;NSM;;;;;N;;;;;
+065C;ARABIC VOWEL SIGN DOT BELOW;Mn;220;NSM;;;;;N;;;;;
+065D;ARABIC REVERSED DAMMA;Mn;230;NSM;;;;;N;;;;;
+065E;ARABIC FATHA WITH TWO DOTS;Mn;230;NSM;;;;;N;;;;;
+0660;ARABIC-INDIC DIGIT ZERO;Nd;0;AN;;0;0;0;N;;;;;
+0661;ARABIC-INDIC DIGIT ONE;Nd;0;AN;;1;1;1;N;;;;;
+0662;ARABIC-INDIC DIGIT TWO;Nd;0;AN;;2;2;2;N;;;;;
+0663;ARABIC-INDIC DIGIT THREE;Nd;0;AN;;3;3;3;N;;;;;
+0664;ARABIC-INDIC DIGIT FOUR;Nd;0;AN;;4;4;4;N;;;;;
+0665;ARABIC-INDIC DIGIT FIVE;Nd;0;AN;;5;5;5;N;;;;;
+0666;ARABIC-INDIC DIGIT SIX;Nd;0;AN;;6;6;6;N;;;;;
+0667;ARABIC-INDIC DIGIT SEVEN;Nd;0;AN;;7;7;7;N;;;;;
+0668;ARABIC-INDIC DIGIT EIGHT;Nd;0;AN;;8;8;8;N;;;;;
+0669;ARABIC-INDIC DIGIT NINE;Nd;0;AN;;9;9;9;N;;;;;
+066A;ARABIC PERCENT SIGN;Po;0;ET;;;;;N;;;;;
+066B;ARABIC DECIMAL SEPARATOR;Po;0;AN;;;;;N;;;;;
+066C;ARABIC THOUSANDS SEPARATOR;Po;0;AN;;;;;N;;;;;
+066D;ARABIC FIVE POINTED STAR;Po;0;AL;;;;;N;;;;;
+066E;ARABIC LETTER DOTLESS BEH;Lo;0;AL;;;;;N;;;;;
+066F;ARABIC LETTER DOTLESS QAF;Lo;0;AL;;;;;N;;;;;
+0670;ARABIC LETTER SUPERSCRIPT ALEF;Mn;35;NSM;;;;;N;ARABIC ALEF ABOVE;;;;
+0671;ARABIC LETTER ALEF WASLA;Lo;0;AL;;;;;N;ARABIC LETTER HAMZAT WASL ON ALEF;;;;
+0672;ARABIC LETTER ALEF WITH WAVY HAMZA ABOVE;Lo;0;AL;;;;;N;ARABIC LETTER WAVY HAMZAH ON ALEF;;;;
+0673;ARABIC LETTER ALEF WITH WAVY HAMZA BELOW;Lo;0;AL;;;;;N;ARABIC LETTER WAVY HAMZAH UNDER ALEF;;;;
+0674;ARABIC LETTER HIGH HAMZA;Lo;0;AL;;;;;N;ARABIC LETTER HIGH HAMZAH;;;;
+0675;ARABIC LETTER HIGH HAMZA ALEF;Lo;0;AL;<compat> 0627 0674;;;;N;ARABIC LETTER HIGH HAMZAH ALEF;;;;
+0676;ARABIC LETTER HIGH HAMZA WAW;Lo;0;AL;<compat> 0648 0674;;;;N;ARABIC LETTER HIGH HAMZAH WAW;;;;
+0677;ARABIC LETTER U WITH HAMZA ABOVE;Lo;0;AL;<compat> 06C7 0674;;;;N;ARABIC LETTER HIGH HAMZAH WAW WITH DAMMAH;;;;
+0678;ARABIC LETTER HIGH HAMZA YEH;Lo;0;AL;<compat> 064A 0674;;;;N;ARABIC LETTER HIGH HAMZAH YA;;;;
+0679;ARABIC LETTER TTEH;Lo;0;AL;;;;;N;ARABIC LETTER TAA WITH SMALL TAH;;;;
+067A;ARABIC LETTER TTEHEH;Lo;0;AL;;;;;N;ARABIC LETTER TAA WITH TWO DOTS VERTICAL ABOVE;;;;
+067B;ARABIC LETTER BEEH;Lo;0;AL;;;;;N;ARABIC LETTER BAA WITH TWO DOTS VERTICAL BELOW;;;;
+067C;ARABIC LETTER TEH WITH RING;Lo;0;AL;;;;;N;ARABIC LETTER TAA WITH RING;;;;
+067D;ARABIC LETTER TEH WITH THREE DOTS ABOVE DOWNWARDS;Lo;0;AL;;;;;N;ARABIC LETTER TAA WITH THREE DOTS ABOVE DOWNWARD;;;;
+067E;ARABIC LETTER PEH;Lo;0;AL;;;;;N;ARABIC LETTER TAA WITH THREE DOTS BELOW;;;;
+067F;ARABIC LETTER TEHEH;Lo;0;AL;;;;;N;ARABIC LETTER TAA WITH FOUR DOTS ABOVE;;;;
+0680;ARABIC LETTER BEHEH;Lo;0;AL;;;;;N;ARABIC LETTER BAA WITH FOUR DOTS BELOW;;;;
+0681;ARABIC LETTER HAH WITH HAMZA ABOVE;Lo;0;AL;;;;;N;ARABIC LETTER HAMZAH ON HAA;;;;
+0682;ARABIC LETTER HAH WITH TWO DOTS VERTICAL ABOVE;Lo;0;AL;;;;;N;ARABIC LETTER HAA WITH TWO DOTS VERTICAL ABOVE;;;;
+0683;ARABIC LETTER NYEH;Lo;0;AL;;;;;N;ARABIC LETTER HAA WITH MIDDLE TWO DOTS;;;;
+0684;ARABIC LETTER DYEH;Lo;0;AL;;;;;N;ARABIC LETTER HAA WITH MIDDLE TWO DOTS VERTICAL;;;;
+0685;ARABIC LETTER HAH WITH THREE DOTS ABOVE;Lo;0;AL;;;;;N;ARABIC LETTER HAA WITH THREE DOTS ABOVE;;;;
+0686;ARABIC LETTER TCHEH;Lo;0;AL;;;;;N;ARABIC LETTER HAA WITH MIDDLE THREE DOTS DOWNWARD;;;;
+0687;ARABIC LETTER TCHEHEH;Lo;0;AL;;;;;N;ARABIC LETTER HAA WITH MIDDLE FOUR DOTS;;;;
+0688;ARABIC LETTER DDAL;Lo;0;AL;;;;;N;ARABIC LETTER DAL WITH SMALL TAH;;;;
+0689;ARABIC LETTER DAL WITH RING;Lo;0;AL;;;;;N;;;;;
+068A;ARABIC LETTER DAL WITH DOT BELOW;Lo;0;AL;;;;;N;;;;;
+068B;ARABIC LETTER DAL WITH DOT BELOW AND SMALL TAH;Lo;0;AL;;;;;N;;;;;
+068C;ARABIC LETTER DAHAL;Lo;0;AL;;;;;N;ARABIC LETTER DAL WITH TWO DOTS ABOVE;;;;
+068D;ARABIC LETTER DDAHAL;Lo;0;AL;;;;;N;ARABIC LETTER DAL WITH TWO DOTS BELOW;;;;
+068E;ARABIC LETTER DUL;Lo;0;AL;;;;;N;ARABIC LETTER DAL WITH THREE DOTS ABOVE;;;;
+068F;ARABIC LETTER DAL WITH THREE DOTS ABOVE DOWNWARDS;Lo;0;AL;;;;;N;ARABIC LETTER DAL WITH THREE DOTS ABOVE DOWNWARD;;;;
+0690;ARABIC LETTER DAL WITH FOUR DOTS ABOVE;Lo;0;AL;;;;;N;;;;;
+0691;ARABIC LETTER RREH;Lo;0;AL;;;;;N;ARABIC LETTER RA WITH SMALL TAH;;;;
+0692;ARABIC LETTER REH WITH SMALL V;Lo;0;AL;;;;;N;ARABIC LETTER RA WITH SMALL V;;;;
+0693;ARABIC LETTER REH WITH RING;Lo;0;AL;;;;;N;ARABIC LETTER RA WITH RING;;;;
+0694;ARABIC LETTER REH WITH DOT BELOW;Lo;0;AL;;;;;N;ARABIC LETTER RA WITH DOT BELOW;;;;
+0695;ARABIC LETTER REH WITH SMALL V BELOW;Lo;0;AL;;;;;N;ARABIC LETTER RA WITH SMALL V BELOW;;;;
+0696;ARABIC LETTER REH WITH DOT BELOW AND DOT ABOVE;Lo;0;AL;;;;;N;ARABIC LETTER RA WITH DOT BELOW AND DOT ABOVE;;;;
+0697;ARABIC LETTER REH WITH TWO DOTS ABOVE;Lo;0;AL;;;;;N;ARABIC LETTER RA WITH TWO DOTS ABOVE;;;;
+0698;ARABIC LETTER JEH;Lo;0;AL;;;;;N;ARABIC LETTER RA WITH THREE DOTS ABOVE;;;;
+0699;ARABIC LETTER REH WITH FOUR DOTS ABOVE;Lo;0;AL;;;;;N;ARABIC LETTER RA WITH FOUR DOTS ABOVE;;;;
+069A;ARABIC LETTER SEEN WITH DOT BELOW AND DOT ABOVE;Lo;0;AL;;;;;N;;;;;
+069B;ARABIC LETTER SEEN WITH THREE DOTS BELOW;Lo;0;AL;;;;;N;;;;;
+069C;ARABIC LETTER SEEN WITH THREE DOTS BELOW AND THREE DOTS ABOVE;Lo;0;AL;;;;;N;;;;;
+069D;ARABIC LETTER SAD WITH TWO DOTS BELOW;Lo;0;AL;;;;;N;;;;;
+069E;ARABIC LETTER SAD WITH THREE DOTS ABOVE;Lo;0;AL;;;;;N;;;;;
+069F;ARABIC LETTER TAH WITH THREE DOTS ABOVE;Lo;0;AL;;;;;N;;;;;
+06A0;ARABIC LETTER AIN WITH THREE DOTS ABOVE;Lo;0;AL;;;;;N;;;;;
+06A1;ARABIC LETTER DOTLESS FEH;Lo;0;AL;;;;;N;ARABIC LETTER DOTLESS FA;;;;
+06A2;ARABIC LETTER FEH WITH DOT MOVED BELOW;Lo;0;AL;;;;;N;ARABIC LETTER FA WITH DOT MOVED BELOW;;;;
+06A3;ARABIC LETTER FEH WITH DOT BELOW;Lo;0;AL;;;;;N;ARABIC LETTER FA WITH DOT BELOW;;;;
+06A4;ARABIC LETTER VEH;Lo;0;AL;;;;;N;ARABIC LETTER FA WITH THREE DOTS ABOVE;;;;
+06A5;ARABIC LETTER FEH WITH THREE DOTS BELOW;Lo;0;AL;;;;;N;ARABIC LETTER FA WITH THREE DOTS BELOW;;;;
+06A6;ARABIC LETTER PEHEH;Lo;0;AL;;;;;N;ARABIC LETTER FA WITH FOUR DOTS ABOVE;;;;
+06A7;ARABIC LETTER QAF WITH DOT ABOVE;Lo;0;AL;;;;;N;;;;;
+06A8;ARABIC LETTER QAF WITH THREE DOTS ABOVE;Lo;0;AL;;;;;N;;;;;
+06A9;ARABIC LETTER KEHEH;Lo;0;AL;;;;;N;ARABIC LETTER OPEN CAF;;;;
+06AA;ARABIC LETTER SWASH KAF;Lo;0;AL;;;;;N;ARABIC LETTER SWASH CAF;;;;
+06AB;ARABIC LETTER KAF WITH RING;Lo;0;AL;;;;;N;ARABIC LETTER CAF WITH RING;;;;
+06AC;ARABIC LETTER KAF WITH DOT ABOVE;Lo;0;AL;;;;;N;ARABIC LETTER CAF WITH DOT ABOVE;;;;
+06AD;ARABIC LETTER NG;Lo;0;AL;;;;;N;ARABIC LETTER CAF WITH THREE DOTS ABOVE;;;;
+06AE;ARABIC LETTER KAF WITH THREE DOTS BELOW;Lo;0;AL;;;;;N;ARABIC LETTER CAF WITH THREE DOTS BELOW;;;;
+06AF;ARABIC LETTER GAF;Lo;0;AL;;;;;N;;*;;;
+06B0;ARABIC LETTER GAF WITH RING;Lo;0;AL;;;;;N;;;;;
+06B1;ARABIC LETTER NGOEH;Lo;0;AL;;;;;N;ARABIC LETTER GAF WITH TWO DOTS ABOVE;;;;
+06B2;ARABIC LETTER GAF WITH TWO DOTS BELOW;Lo;0;AL;;;;;N;;;;;
+06B3;ARABIC LETTER GUEH;Lo;0;AL;;;;;N;ARABIC LETTER GAF WITH TWO DOTS VERTICAL BELOW;;;;
+06B4;ARABIC LETTER GAF WITH THREE DOTS ABOVE;Lo;0;AL;;;;;N;;;;;
+06B5;ARABIC LETTER LAM WITH SMALL V;Lo;0;AL;;;;;N;;;;;
+06B6;ARABIC LETTER LAM WITH DOT ABOVE;Lo;0;AL;;;;;N;;;;;
+06B7;ARABIC LETTER LAM WITH THREE DOTS ABOVE;Lo;0;AL;;;;;N;;;;;
+06B8;ARABIC LETTER LAM WITH THREE DOTS BELOW;Lo;0;AL;;;;;N;;;;;
+06B9;ARABIC LETTER NOON WITH DOT BELOW;Lo;0;AL;;;;;N;;;;;
+06BA;ARABIC LETTER NOON GHUNNA;Lo;0;AL;;;;;N;ARABIC LETTER DOTLESS NOON;;;;
+06BB;ARABIC LETTER RNOON;Lo;0;AL;;;;;N;ARABIC LETTER DOTLESS NOON WITH SMALL TAH;;;;
+06BC;ARABIC LETTER NOON WITH RING;Lo;0;AL;;;;;N;;;;;
+06BD;ARABIC LETTER NOON WITH THREE DOTS ABOVE;Lo;0;AL;;;;;N;;;;;
+06BE;ARABIC LETTER HEH DOACHASHMEE;Lo;0;AL;;;;;N;ARABIC LETTER KNOTTED HA;;;;
+06BF;ARABIC LETTER TCHEH WITH DOT ABOVE;Lo;0;AL;;;;;N;;;;;
+06C0;ARABIC LETTER HEH WITH YEH ABOVE;Lo;0;AL;06D5 0654;;;;N;ARABIC LETTER HAMZAH ON HA;;;;
+06C1;ARABIC LETTER HEH GOAL;Lo;0;AL;;;;;N;ARABIC LETTER HA GOAL;;;;
+06C2;ARABIC LETTER HEH GOAL WITH HAMZA ABOVE;Lo;0;AL;06C1 0654;;;;N;ARABIC LETTER HAMZAH ON HA GOAL;;;;
+06C3;ARABIC LETTER TEH MARBUTA GOAL;Lo;0;AL;;;;;N;ARABIC LETTER TAA MARBUTAH GOAL;;;;
+06C4;ARABIC LETTER WAW WITH RING;Lo;0;AL;;;;;N;;;;;
+06C5;ARABIC LETTER KIRGHIZ OE;Lo;0;AL;;;;;N;ARABIC LETTER WAW WITH BAR;;;;
+06C6;ARABIC LETTER OE;Lo;0;AL;;;;;N;ARABIC LETTER WAW WITH SMALL V;;;;
+06C7;ARABIC LETTER U;Lo;0;AL;;;;;N;ARABIC LETTER WAW WITH DAMMAH;;;;
+06C8;ARABIC LETTER YU;Lo;0;AL;;;;;N;ARABIC LETTER WAW WITH ALEF ABOVE;;;;
+06C9;ARABIC LETTER KIRGHIZ YU;Lo;0;AL;;;;;N;ARABIC LETTER WAW WITH INVERTED SMALL V;;;;
+06CA;ARABIC LETTER WAW WITH TWO DOTS ABOVE;Lo;0;AL;;;;;N;;;;;
+06CB;ARABIC LETTER VE;Lo;0;AL;;;;;N;ARABIC LETTER WAW WITH THREE DOTS ABOVE;;;;
+06CC;ARABIC LETTER FARSI YEH;Lo;0;AL;;;;;N;ARABIC LETTER DOTLESS YA;;;;
+06CD;ARABIC LETTER YEH WITH TAIL;Lo;0;AL;;;;;N;ARABIC LETTER YA WITH TAIL;;;;
+06CE;ARABIC LETTER YEH WITH SMALL V;Lo;0;AL;;;;;N;ARABIC LETTER YA WITH SMALL V;;;;
+06CF;ARABIC LETTER WAW WITH DOT ABOVE;Lo;0;AL;;;;;N;;;;;
+06D0;ARABIC LETTER E;Lo;0;AL;;;;;N;ARABIC LETTER YA WITH TWO DOTS VERTICAL BELOW;*;;;
+06D1;ARABIC LETTER YEH WITH THREE DOTS BELOW;Lo;0;AL;;;;;N;ARABIC LETTER YA WITH THREE DOTS BELOW;;;;
+06D2;ARABIC LETTER YEH BARREE;Lo;0;AL;;;;;N;ARABIC LETTER YA BARREE;;;;
+06D3;ARABIC LETTER YEH BARREE WITH HAMZA ABOVE;Lo;0;AL;06D2 0654;;;;N;ARABIC LETTER HAMZAH ON YA BARREE;;;;
+06D4;ARABIC FULL STOP;Po;0;AL;;;;;N;ARABIC PERIOD;;;;
+06D5;ARABIC LETTER AE;Lo;0;AL;;;;;N;;;;;
+06D6;ARABIC SMALL HIGH LIGATURE SAD WITH LAM WITH ALEF MAKSURA;Mn;230;NSM;;;;;N;;;;;
+06D7;ARABIC SMALL HIGH LIGATURE QAF WITH LAM WITH ALEF MAKSURA;Mn;230;NSM;;;;;N;;;;;
+06D8;ARABIC SMALL HIGH MEEM INITIAL FORM;Mn;230;NSM;;;;;N;;;;;
+06D9;ARABIC SMALL HIGH LAM ALEF;Mn;230;NSM;;;;;N;;;;;
+06DA;ARABIC SMALL HIGH JEEM;Mn;230;NSM;;;;;N;;;;;
+06DB;ARABIC SMALL HIGH THREE DOTS;Mn;230;NSM;;;;;N;;;;;
+06DC;ARABIC SMALL HIGH SEEN;Mn;230;NSM;;;;;N;;;;;
+06DD;ARABIC END OF AYAH;Cf;0;AL;;;;;N;;;;;
+06DE;ARABIC START OF RUB EL HIZB;Me;0;NSM;;;;;N;;;;;
+06DF;ARABIC SMALL HIGH ROUNDED ZERO;Mn;230;NSM;;;;;N;;;;;
+06E0;ARABIC SMALL HIGH UPRIGHT RECTANGULAR ZERO;Mn;230;NSM;;;;;N;;;;;
+06E1;ARABIC SMALL HIGH DOTLESS HEAD OF KHAH;Mn;230;NSM;;;;;N;;;;;
+06E2;ARABIC SMALL HIGH MEEM ISOLATED FORM;Mn;230;NSM;;;;;N;;;;;
+06E3;ARABIC SMALL LOW SEEN;Mn;220;NSM;;;;;N;;;;;
+06E4;ARABIC SMALL HIGH MADDA;Mn;230;NSM;;;;;N;;;;;
+06E5;ARABIC SMALL WAW;Lm;0;AL;;;;;N;;;;;
+06E6;ARABIC SMALL YEH;Lm;0;AL;;;;;N;;;;;
+06E7;ARABIC SMALL HIGH YEH;Mn;230;NSM;;;;;N;;;;;
+06E8;ARABIC SMALL HIGH NOON;Mn;230;NSM;;;;;N;;;;;
+06E9;ARABIC PLACE OF SAJDAH;So;0;ON;;;;;N;;;;;
+06EA;ARABIC EMPTY CENTRE LOW STOP;Mn;220;NSM;;;;;N;;;;;
+06EB;ARABIC EMPTY CENTRE HIGH STOP;Mn;230;NSM;;;;;N;;;;;
+06EC;ARABIC ROUNDED HIGH STOP WITH FILLED CENTRE;Mn;230;NSM;;;;;N;;;;;
+06ED;ARABIC SMALL LOW MEEM;Mn;220;NSM;;;;;N;;;;;
+06EE;ARABIC LETTER DAL WITH INVERTED V;Lo;0;AL;;;;;N;;;;;
+06EF;ARABIC LETTER REH WITH INVERTED V;Lo;0;AL;;;;;N;;;;;
+06F0;EXTENDED ARABIC-INDIC DIGIT ZERO;Nd;0;EN;;0;0;0;N;EASTERN ARABIC-INDIC DIGIT ZERO;;;;
+06F1;EXTENDED ARABIC-INDIC DIGIT ONE;Nd;0;EN;;1;1;1;N;EASTERN ARABIC-INDIC DIGIT ONE;;;;
+06F2;EXTENDED ARABIC-INDIC DIGIT TWO;Nd;0;EN;;2;2;2;N;EASTERN ARABIC-INDIC DIGIT TWO;;;;
+06F3;EXTENDED ARABIC-INDIC DIGIT THREE;Nd;0;EN;;3;3;3;N;EASTERN ARABIC-INDIC DIGIT THREE;;;;
+06F4;EXTENDED ARABIC-INDIC DIGIT FOUR;Nd;0;EN;;4;4;4;N;EASTERN ARABIC-INDIC DIGIT FOUR;;;;
+06F5;EXTENDED ARABIC-INDIC DIGIT FIVE;Nd;0;EN;;5;5;5;N;EASTERN ARABIC-INDIC DIGIT FIVE;;;;
+06F6;EXTENDED ARABIC-INDIC DIGIT SIX;Nd;0;EN;;6;6;6;N;EASTERN ARABIC-INDIC DIGIT SIX;;;;
+06F7;EXTENDED ARABIC-INDIC DIGIT SEVEN;Nd;0;EN;;7;7;7;N;EASTERN ARABIC-INDIC DIGIT SEVEN;;;;
+06F8;EXTENDED ARABIC-INDIC DIGIT EIGHT;Nd;0;EN;;8;8;8;N;EASTERN ARABIC-INDIC DIGIT EIGHT;;;;
+06F9;EXTENDED ARABIC-INDIC DIGIT NINE;Nd;0;EN;;9;9;9;N;EASTERN ARABIC-INDIC DIGIT NINE;;;;
+06FA;ARABIC LETTER SHEEN WITH DOT BELOW;Lo;0;AL;;;;;N;;;;;
+06FB;ARABIC LETTER DAD WITH DOT BELOW;Lo;0;AL;;;;;N;;;;;
+06FC;ARABIC LETTER GHAIN WITH DOT BELOW;Lo;0;AL;;;;;N;;;;;
+06FD;ARABIC SIGN SINDHI AMPERSAND;So;0;AL;;;;;N;;;;;
+06FE;ARABIC SIGN SINDHI POSTPOSITION MEN;So;0;AL;;;;;N;;;;;
+06FF;ARABIC LETTER HEH WITH INVERTED V;Lo;0;AL;;;;;N;;;;;
+0700;SYRIAC END OF PARAGRAPH;Po;0;AL;;;;;N;;;;;
+0701;SYRIAC SUPRALINEAR FULL STOP;Po;0;AL;;;;;N;;;;;
+0702;SYRIAC SUBLINEAR FULL STOP;Po;0;AL;;;;;N;;;;;
+0703;SYRIAC SUPRALINEAR COLON;Po;0;AL;;;;;N;;;;;
+0704;SYRIAC SUBLINEAR COLON;Po;0;AL;;;;;N;;;;;
+0705;SYRIAC HORIZONTAL COLON;Po;0;AL;;;;;N;;;;;
+0706;SYRIAC COLON SKEWED LEFT;Po;0;AL;;;;;N;;;;;
+0707;SYRIAC COLON SKEWED RIGHT;Po;0;AL;;;;;N;;;;;
+0708;SYRIAC SUPRALINEAR COLON SKEWED LEFT;Po;0;AL;;;;;N;;;;;
+0709;SYRIAC SUBLINEAR COLON SKEWED RIGHT;Po;0;AL;;;;;N;;;;;
+070A;SYRIAC CONTRACTION;Po;0;AL;;;;;N;;;;;
+070B;SYRIAC HARKLEAN OBELUS;Po;0;AL;;;;;N;;;;;
+070C;SYRIAC HARKLEAN METOBELUS;Po;0;AL;;;;;N;;;;;
+070D;SYRIAC HARKLEAN ASTERISCUS;Po;0;AL;;;;;N;;;;;
+070F;SYRIAC ABBREVIATION MARK;Cf;0;BN;;;;;N;;;;;
+0710;SYRIAC LETTER ALAPH;Lo;0;AL;;;;;N;;;;;
+0711;SYRIAC LETTER SUPERSCRIPT ALAPH;Mn;36;NSM;;;;;N;;;;;
+0712;SYRIAC LETTER BETH;Lo;0;AL;;;;;N;;;;;
+0713;SYRIAC LETTER GAMAL;Lo;0;AL;;;;;N;;;;;
+0714;SYRIAC LETTER GAMAL GARSHUNI;Lo;0;AL;;;;;N;;;;;
+0715;SYRIAC LETTER DALATH;Lo;0;AL;;;;;N;;;;;
+0716;SYRIAC LETTER DOTLESS DALATH RISH;Lo;0;AL;;;;;N;;;;;
+0717;SYRIAC LETTER HE;Lo;0;AL;;;;;N;;;;;
+0718;SYRIAC LETTER WAW;Lo;0;AL;;;;;N;;;;;
+0719;SYRIAC LETTER ZAIN;Lo;0;AL;;;;;N;;;;;
+071A;SYRIAC LETTER HETH;Lo;0;AL;;;;;N;;;;;
+071B;SYRIAC LETTER TETH;Lo;0;AL;;;;;N;;;;;
+071C;SYRIAC LETTER TETH GARSHUNI;Lo;0;AL;;;;;N;;;;;
+071D;SYRIAC LETTER YUDH;Lo;0;AL;;;;;N;;;;;
+071E;SYRIAC LETTER YUDH HE;Lo;0;AL;;;;;N;;;;;
+071F;SYRIAC LETTER KAPH;Lo;0;AL;;;;;N;;;;;
+0720;SYRIAC LETTER LAMADH;Lo;0;AL;;;;;N;;;;;
+0721;SYRIAC LETTER MIM;Lo;0;AL;;;;;N;;;;;
+0722;SYRIAC LETTER NUN;Lo;0;AL;;;;;N;;;;;
+0723;SYRIAC LETTER SEMKATH;Lo;0;AL;;;;;N;;;;;
+0724;SYRIAC LETTER FINAL SEMKATH;Lo;0;AL;;;;;N;;;;;
+0725;SYRIAC LETTER E;Lo;0;AL;;;;;N;;;;;
+0726;SYRIAC LETTER PE;Lo;0;AL;;;;;N;;;;;
+0727;SYRIAC LETTER REVERSED PE;Lo;0;AL;;;;;N;;;;;
+0728;SYRIAC LETTER SADHE;Lo;0;AL;;;;;N;;;;;
+0729;SYRIAC LETTER QAPH;Lo;0;AL;;;;;N;;;;;
+072A;SYRIAC LETTER RISH;Lo;0;AL;;;;;N;;;;;
+072B;SYRIAC LETTER SHIN;Lo;0;AL;;;;;N;;;;;
+072C;SYRIAC LETTER TAW;Lo;0;AL;;;;;N;;;;;
+072D;SYRIAC LETTER PERSIAN BHETH;Lo;0;AL;;;;;N;;;;;
+072E;SYRIAC LETTER PERSIAN GHAMAL;Lo;0;AL;;;;;N;;;;;
+072F;SYRIAC LETTER PERSIAN DHALATH;Lo;0;AL;;;;;N;;;;;
+0730;SYRIAC PTHAHA ABOVE;Mn;230;NSM;;;;;N;;;;;
+0731;SYRIAC PTHAHA BELOW;Mn;220;NSM;;;;;N;;;;;
+0732;SYRIAC PTHAHA DOTTED;Mn;230;NSM;;;;;N;;;;;
+0733;SYRIAC ZQAPHA ABOVE;Mn;230;NSM;;;;;N;;;;;
+0734;SYRIAC ZQAPHA BELOW;Mn;220;NSM;;;;;N;;;;;
+0735;SYRIAC ZQAPHA DOTTED;Mn;230;NSM;;;;;N;;;;;
+0736;SYRIAC RBASA ABOVE;Mn;230;NSM;;;;;N;;;;;
+0737;SYRIAC RBASA BELOW;Mn;220;NSM;;;;;N;;;;;
+0738;SYRIAC DOTTED ZLAMA HORIZONTAL;Mn;220;NSM;;;;;N;;;;;
+0739;SYRIAC DOTTED ZLAMA ANGULAR;Mn;220;NSM;;;;;N;;;;;
+073A;SYRIAC HBASA ABOVE;Mn;230;NSM;;;;;N;;;;;
+073B;SYRIAC HBASA BELOW;Mn;220;NSM;;;;;N;;;;;
+073C;SYRIAC HBASA-ESASA DOTTED;Mn;220;NSM;;;;;N;;;;;
+073D;SYRIAC ESASA ABOVE;Mn;230;NSM;;;;;N;;;;;
+073E;SYRIAC ESASA BELOW;Mn;220;NSM;;;;;N;;;;;
+073F;SYRIAC RWAHA;Mn;230;NSM;;;;;N;;;;;
+0740;SYRIAC FEMININE DOT;Mn;230;NSM;;;;;N;;;;;
+0741;SYRIAC QUSHSHAYA;Mn;230;NSM;;;;;N;;;;;
+0742;SYRIAC RUKKAKHA;Mn;220;NSM;;;;;N;;;;;
+0743;SYRIAC TWO VERTICAL DOTS ABOVE;Mn;230;NSM;;;;;N;;;;;
+0744;SYRIAC TWO VERTICAL DOTS BELOW;Mn;220;NSM;;;;;N;;;;;
+0745;SYRIAC THREE DOTS ABOVE;Mn;230;NSM;;;;;N;;;;;
+0746;SYRIAC THREE DOTS BELOW;Mn;220;NSM;;;;;N;;;;;
+0747;SYRIAC OBLIQUE LINE ABOVE;Mn;230;NSM;;;;;N;;;;;
+0748;SYRIAC OBLIQUE LINE BELOW;Mn;220;NSM;;;;;N;;;;;
+0749;SYRIAC MUSIC;Mn;230;NSM;;;;;N;;;;;
+074A;SYRIAC BARREKH;Mn;230;NSM;;;;;N;;;;;
+074D;SYRIAC LETTER SOGDIAN ZHAIN;Lo;0;AL;;;;;N;;;;;
+074E;SYRIAC LETTER SOGDIAN KHAPH;Lo;0;AL;;;;;N;;;;;
+074F;SYRIAC LETTER SOGDIAN FE;Lo;0;AL;;;;;N;;;;;
+0750;ARABIC LETTER BEH WITH THREE DOTS HORIZONTALLY BELOW;Lo;0;AL;;;;;N;;;;;
+0751;ARABIC LETTER BEH WITH DOT BELOW AND THREE DOTS ABOVE;Lo;0;AL;;;;;N;;;;;
+0752;ARABIC LETTER BEH WITH THREE DOTS POINTING UPWARDS BELOW;Lo;0;AL;;;;;N;;;;;
+0753;ARABIC LETTER BEH WITH THREE DOTS POINTING UPWARDS BELOW AND TWO DOTS ABOVE;Lo;0;AL;;;;;N;;;;;
+0754;ARABIC LETTER BEH WITH TWO DOTS BELOW AND DOT ABOVE;Lo;0;AL;;;;;N;;;;;
+0755;ARABIC LETTER BEH WITH INVERTED SMALL V BELOW;Lo;0;AL;;;;;N;;;;;
+0756;ARABIC LETTER BEH WITH SMALL V;Lo;0;AL;;;;;N;;;;;
+0757;ARABIC LETTER HAH WITH TWO DOTS ABOVE;Lo;0;AL;;;;;N;;;;;
+0758;ARABIC LETTER HAH WITH THREE DOTS POINTING UPWARDS BELOW;Lo;0;AL;;;;;N;;;;;
+0759;ARABIC LETTER DAL WITH TWO DOTS VERTICALLY BELOW AND SMALL TAH;Lo;0;AL;;;;;N;;;;;
+075A;ARABIC LETTER DAL WITH INVERTED SMALL V BELOW;Lo;0;AL;;;;;N;;;;;
+075B;ARABIC LETTER REH WITH STROKE;Lo;0;AL;;;;;N;;;;;
+075C;ARABIC LETTER SEEN WITH FOUR DOTS ABOVE;Lo;0;AL;;;;;N;;;;;
+075D;ARABIC LETTER AIN WITH TWO DOTS ABOVE;Lo;0;AL;;;;;N;;;;;
+075E;ARABIC LETTER AIN WITH THREE DOTS POINTING DOWNWARDS ABOVE;Lo;0;AL;;;;;N;;;;;
+075F;ARABIC LETTER AIN WITH TWO DOTS VERTICALLY ABOVE;Lo;0;AL;;;;;N;;;;;
+0760;ARABIC LETTER FEH WITH TWO DOTS BELOW;Lo;0;AL;;;;;N;;;;;
+0761;ARABIC LETTER FEH WITH THREE DOTS POINTING UPWARDS BELOW;Lo;0;AL;;;;;N;;;;;
+0762;ARABIC LETTER KEHEH WITH DOT ABOVE;Lo;0;AL;;;;;N;;;;;
+0763;ARABIC LETTER KEHEH WITH THREE DOTS ABOVE;Lo;0;AL;;;;;N;;;;;
+0764;ARABIC LETTER KEHEH WITH THREE DOTS POINTING UPWARDS BELOW;Lo;0;AL;;;;;N;;;;;
+0765;ARABIC LETTER MEEM WITH DOT ABOVE;Lo;0;AL;;;;;N;;;;;
+0766;ARABIC LETTER MEEM WITH DOT BELOW;Lo;0;AL;;;;;N;;;;;
+0767;ARABIC LETTER NOON WITH TWO DOTS BELOW;Lo;0;AL;;;;;N;;;;;
+0768;ARABIC LETTER NOON WITH SMALL TAH;Lo;0;AL;;;;;N;;;;;
+0769;ARABIC LETTER NOON WITH SMALL V;Lo;0;AL;;;;;N;;;;;
+076A;ARABIC LETTER LAM WITH BAR;Lo;0;AL;;;;;N;;;;;
+076B;ARABIC LETTER REH WITH TWO DOTS VERTICALLY ABOVE;Lo;0;AL;;;;;N;;;;;
+076C;ARABIC LETTER REH WITH HAMZA ABOVE;Lo;0;AL;;;;;N;;;;;
+076D;ARABIC LETTER SEEN WITH TWO DOTS VERTICALLY ABOVE;Lo;0;AL;;;;;N;;;;;
+0780;THAANA LETTER HAA;Lo;0;AL;;;;;N;;;;;
+0781;THAANA LETTER SHAVIYANI;Lo;0;AL;;;;;N;;;;;
+0782;THAANA LETTER NOONU;Lo;0;AL;;;;;N;;;;;
+0783;THAANA LETTER RAA;Lo;0;AL;;;;;N;;;;;
+0784;THAANA LETTER BAA;Lo;0;AL;;;;;N;;;;;
+0785;THAANA LETTER LHAVIYANI;Lo;0;AL;;;;;N;;;;;
+0786;THAANA LETTER KAAFU;Lo;0;AL;;;;;N;;;;;
+0787;THAANA LETTER ALIFU;Lo;0;AL;;;;;N;;;;;
+0788;THAANA LETTER VAAVU;Lo;0;AL;;;;;N;;;;;
+0789;THAANA LETTER MEEMU;Lo;0;AL;;;;;N;;;;;
+078A;THAANA LETTER FAAFU;Lo;0;AL;;;;;N;;;;;
+078B;THAANA LETTER DHAALU;Lo;0;AL;;;;;N;;;;;
+078C;THAANA LETTER THAA;Lo;0;AL;;;;;N;;;;;
+078D;THAANA LETTER LAAMU;Lo;0;AL;;;;;N;;;;;
+078E;THAANA LETTER GAAFU;Lo;0;AL;;;;;N;;;;;
+078F;THAANA LETTER GNAVIYANI;Lo;0;AL;;;;;N;;;;;
+0790;THAANA LETTER SEENU;Lo;0;AL;;;;;N;;;;;
+0791;THAANA LETTER DAVIYANI;Lo;0;AL;;;;;N;;;;;
+0792;THAANA LETTER ZAVIYANI;Lo;0;AL;;;;;N;;;;;
+0793;THAANA LETTER TAVIYANI;Lo;0;AL;;;;;N;;;;;
+0794;THAANA LETTER YAA;Lo;0;AL;;;;;N;;;;;
+0795;THAANA LETTER PAVIYANI;Lo;0;AL;;;;;N;;;;;
+0796;THAANA LETTER JAVIYANI;Lo;0;AL;;;;;N;;;;;
+0797;THAANA LETTER CHAVIYANI;Lo;0;AL;;;;;N;;;;;
+0798;THAANA LETTER TTAA;Lo;0;AL;;;;;N;;;;;
+0799;THAANA LETTER HHAA;Lo;0;AL;;;;;N;;;;;
+079A;THAANA LETTER KHAA;Lo;0;AL;;;;;N;;;;;
+079B;THAANA LETTER THAALU;Lo;0;AL;;;;;N;;;;;
+079C;THAANA LETTER ZAA;Lo;0;AL;;;;;N;;;;;
+079D;THAANA LETTER SHEENU;Lo;0;AL;;;;;N;;;;;
+079E;THAANA LETTER SAADHU;Lo;0;AL;;;;;N;;;;;
+079F;THAANA LETTER DAADHU;Lo;0;AL;;;;;N;;;;;
+07A0;THAANA LETTER TO;Lo;0;AL;;;;;N;;;;;
+07A1;THAANA LETTER ZO;Lo;0;AL;;;;;N;;;;;
+07A2;THAANA LETTER AINU;Lo;0;AL;;;;;N;;;;;
+07A3;THAANA LETTER GHAINU;Lo;0;AL;;;;;N;;;;;
+07A4;THAANA LETTER QAAFU;Lo;0;AL;;;;;N;;;;;
+07A5;THAANA LETTER WAAVU;Lo;0;AL;;;;;N;;;;;
+07A6;THAANA ABAFILI;Mn;0;NSM;;;;;N;;;;;
+07A7;THAANA AABAAFILI;Mn;0;NSM;;;;;N;;;;;
+07A8;THAANA IBIFILI;Mn;0;NSM;;;;;N;;;;;
+07A9;THAANA EEBEEFILI;Mn;0;NSM;;;;;N;;;;;
+07AA;THAANA UBUFILI;Mn;0;NSM;;;;;N;;;;;
+07AB;THAANA OOBOOFILI;Mn;0;NSM;;;;;N;;;;;
+07AC;THAANA EBEFILI;Mn;0;NSM;;;;;N;;;;;
+07AD;THAANA EYBEYFILI;Mn;0;NSM;;;;;N;;;;;
+07AE;THAANA OBOFILI;Mn;0;NSM;;;;;N;;;;;
+07AF;THAANA OABOAFILI;Mn;0;NSM;;;;;N;;;;;
+07B0;THAANA SUKUN;Mn;0;NSM;;;;;N;;;;;
+07B1;THAANA LETTER NAA;Lo;0;AL;;;;;N;;;;;
+0901;DEVANAGARI SIGN CANDRABINDU;Mn;0;NSM;;;;;N;;;;;
+0902;DEVANAGARI SIGN ANUSVARA;Mn;0;NSM;;;;;N;;;;;
+0903;DEVANAGARI SIGN VISARGA;Mc;0;L;;;;;N;;;;;
+0904;DEVANAGARI LETTER SHORT A;Lo;0;L;;;;;N;;;;;
+0905;DEVANAGARI LETTER A;Lo;0;L;;;;;N;;;;;
+0906;DEVANAGARI LETTER AA;Lo;0;L;;;;;N;;;;;
+0907;DEVANAGARI LETTER I;Lo;0;L;;;;;N;;;;;
+0908;DEVANAGARI LETTER II;Lo;0;L;;;;;N;;;;;
+0909;DEVANAGARI LETTER U;Lo;0;L;;;;;N;;;;;
+090A;DEVANAGARI LETTER UU;Lo;0;L;;;;;N;;;;;
+090B;DEVANAGARI LETTER VOCALIC R;Lo;0;L;;;;;N;;;;;
+090C;DEVANAGARI LETTER VOCALIC L;Lo;0;L;;;;;N;;;;;
+090D;DEVANAGARI LETTER CANDRA E;Lo;0;L;;;;;N;;;;;
+090E;DEVANAGARI LETTER SHORT E;Lo;0;L;;;;;N;;;;;
+090F;DEVANAGARI LETTER E;Lo;0;L;;;;;N;;;;;
+0910;DEVANAGARI LETTER AI;Lo;0;L;;;;;N;;;;;
+0911;DEVANAGARI LETTER CANDRA O;Lo;0;L;;;;;N;;;;;
+0912;DEVANAGARI LETTER SHORT O;Lo;0;L;;;;;N;;;;;
+0913;DEVANAGARI LETTER O;Lo;0;L;;;;;N;;;;;
+0914;DEVANAGARI LETTER AU;Lo;0;L;;;;;N;;;;;
+0915;DEVANAGARI LETTER KA;Lo;0;L;;;;;N;;;;;
+0916;DEVANAGARI LETTER KHA;Lo;0;L;;;;;N;;;;;
+0917;DEVANAGARI LETTER GA;Lo;0;L;;;;;N;;;;;
+0918;DEVANAGARI LETTER GHA;Lo;0;L;;;;;N;;;;;
+0919;DEVANAGARI LETTER NGA;Lo;0;L;;;;;N;;;;;
+091A;DEVANAGARI LETTER CA;Lo;0;L;;;;;N;;;;;
+091B;DEVANAGARI LETTER CHA;Lo;0;L;;;;;N;;;;;
+091C;DEVANAGARI LETTER JA;Lo;0;L;;;;;N;;;;;
+091D;DEVANAGARI LETTER JHA;Lo;0;L;;;;;N;;;;;
+091E;DEVANAGARI LETTER NYA;Lo;0;L;;;;;N;;;;;
+091F;DEVANAGARI LETTER TTA;Lo;0;L;;;;;N;;;;;
+0920;DEVANAGARI LETTER TTHA;Lo;0;L;;;;;N;;;;;
+0921;DEVANAGARI LETTER DDA;Lo;0;L;;;;;N;;;;;
+0922;DEVANAGARI LETTER DDHA;Lo;0;L;;;;;N;;;;;
+0923;DEVANAGARI LETTER NNA;Lo;0;L;;;;;N;;;;;
+0924;DEVANAGARI LETTER TA;Lo;0;L;;;;;N;;;;;
+0925;DEVANAGARI LETTER THA;Lo;0;L;;;;;N;;;;;
+0926;DEVANAGARI LETTER DA;Lo;0;L;;;;;N;;;;;
+0927;DEVANAGARI LETTER DHA;Lo;0;L;;;;;N;;;;;
+0928;DEVANAGARI LETTER NA;Lo;0;L;;;;;N;;;;;
+0929;DEVANAGARI LETTER NNNA;Lo;0;L;0928 093C;;;;N;;;;;
+092A;DEVANAGARI LETTER PA;Lo;0;L;;;;;N;;;;;
+092B;DEVANAGARI LETTER PHA;Lo;0;L;;;;;N;;;;;
+092C;DEVANAGARI LETTER BA;Lo;0;L;;;;;N;;;;;
+092D;DEVANAGARI LETTER BHA;Lo;0;L;;;;;N;;;;;
+092E;DEVANAGARI LETTER MA;Lo;0;L;;;;;N;;;;;
+092F;DEVANAGARI LETTER YA;Lo;0;L;;;;;N;;;;;
+0930;DEVANAGARI LETTER RA;Lo;0;L;;;;;N;;;;;
+0931;DEVANAGARI LETTER RRA;Lo;0;L;0930 093C;;;;N;;;;;
+0932;DEVANAGARI LETTER LA;Lo;0;L;;;;;N;;;;;
+0933;DEVANAGARI LETTER LLA;Lo;0;L;;;;;N;;;;;
+0934;DEVANAGARI LETTER LLLA;Lo;0;L;0933 093C;;;;N;;;;;
+0935;DEVANAGARI LETTER VA;Lo;0;L;;;;;N;;;;;
+0936;DEVANAGARI LETTER SHA;Lo;0;L;;;;;N;;;;;
+0937;DEVANAGARI LETTER SSA;Lo;0;L;;;;;N;;;;;
+0938;DEVANAGARI LETTER SA;Lo;0;L;;;;;N;;;;;
+0939;DEVANAGARI LETTER HA;Lo;0;L;;;;;N;;;;;
+093C;DEVANAGARI SIGN NUKTA;Mn;7;NSM;;;;;N;;;;;
+093D;DEVANAGARI SIGN AVAGRAHA;Lo;0;L;;;;;N;;;;;
+093E;DEVANAGARI VOWEL SIGN AA;Mc;0;L;;;;;N;;;;;
+093F;DEVANAGARI VOWEL SIGN I;Mc;0;L;;;;;N;;;;;
+0940;DEVANAGARI VOWEL SIGN II;Mc;0;L;;;;;N;;;;;
+0941;DEVANAGARI VOWEL SIGN U;Mn;0;NSM;;;;;N;;;;;
+0942;DEVANAGARI VOWEL SIGN UU;Mn;0;NSM;;;;;N;;;;;
+0943;DEVANAGARI VOWEL SIGN VOCALIC R;Mn;0;NSM;;;;;N;;;;;
+0944;DEVANAGARI VOWEL SIGN VOCALIC RR;Mn;0;NSM;;;;;N;;;;;
+0945;DEVANAGARI VOWEL SIGN CANDRA E;Mn;0;NSM;;;;;N;;;;;
+0946;DEVANAGARI VOWEL SIGN SHORT E;Mn;0;NSM;;;;;N;;;;;
+0947;DEVANAGARI VOWEL SIGN E;Mn;0;NSM;;;;;N;;;;;
+0948;DEVANAGARI VOWEL SIGN AI;Mn;0;NSM;;;;;N;;;;;
+0949;DEVANAGARI VOWEL SIGN CANDRA O;Mc;0;L;;;;;N;;;;;
+094A;DEVANAGARI VOWEL SIGN SHORT O;Mc;0;L;;;;;N;;;;;
+094B;DEVANAGARI VOWEL SIGN O;Mc;0;L;;;;;N;;;;;
+094C;DEVANAGARI VOWEL SIGN AU;Mc;0;L;;;;;N;;;;;
+094D;DEVANAGARI SIGN VIRAMA;Mn;9;NSM;;;;;N;;;;;
+0950;DEVANAGARI OM;Lo;0;L;;;;;N;;;;;
+0951;DEVANAGARI STRESS SIGN UDATTA;Mn;230;NSM;;;;;N;;;;;
+0952;DEVANAGARI STRESS SIGN ANUDATTA;Mn;220;NSM;;;;;N;;;;;
+0953;DEVANAGARI GRAVE ACCENT;Mn;230;NSM;;;;;N;;;;;
+0954;DEVANAGARI ACUTE ACCENT;Mn;230;NSM;;;;;N;;;;;
+0958;DEVANAGARI LETTER QA;Lo;0;L;0915 093C;;;;N;;;;;
+0959;DEVANAGARI LETTER KHHA;Lo;0;L;0916 093C;;;;N;;;;;
+095A;DEVANAGARI LETTER GHHA;Lo;0;L;0917 093C;;;;N;;;;;
+095B;DEVANAGARI LETTER ZA;Lo;0;L;091C 093C;;;;N;;;;;
+095C;DEVANAGARI LETTER DDDHA;Lo;0;L;0921 093C;;;;N;;;;;
+095D;DEVANAGARI LETTER RHA;Lo;0;L;0922 093C;;;;N;;;;;
+095E;DEVANAGARI LETTER FA;Lo;0;L;092B 093C;;;;N;;;;;
+095F;DEVANAGARI LETTER YYA;Lo;0;L;092F 093C;;;;N;;;;;
+0960;DEVANAGARI LETTER VOCALIC RR;Lo;0;L;;;;;N;;;;;
+0961;DEVANAGARI LETTER VOCALIC LL;Lo;0;L;;;;;N;;;;;
+0962;DEVANAGARI VOWEL SIGN VOCALIC L;Mn;0;NSM;;;;;N;;;;;
+0963;DEVANAGARI VOWEL SIGN VOCALIC LL;Mn;0;NSM;;;;;N;;;;;
+0964;DEVANAGARI DANDA;Po;0;L;;;;;N;;;;;
+0965;DEVANAGARI DOUBLE DANDA;Po;0;L;;;;;N;;;;;
+0966;DEVANAGARI DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;;
+0967;DEVANAGARI DIGIT ONE;Nd;0;L;;1;1;1;N;;;;;
+0968;DEVANAGARI DIGIT TWO;Nd;0;L;;2;2;2;N;;;;;
+0969;DEVANAGARI DIGIT THREE;Nd;0;L;;3;3;3;N;;;;;
+096A;DEVANAGARI DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;;
+096B;DEVANAGARI DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;;
+096C;DEVANAGARI DIGIT SIX;Nd;0;L;;6;6;6;N;;;;;
+096D;DEVANAGARI DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;;
+096E;DEVANAGARI DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;;
+096F;DEVANAGARI DIGIT NINE;Nd;0;L;;9;9;9;N;;;;;
+0970;DEVANAGARI ABBREVIATION SIGN;Po;0;L;;;;;N;;;;;
+097D;DEVANAGARI LETTER GLOTTAL STOP;Lo;0;L;;;;;N;;;;;
+0981;BENGALI SIGN CANDRABINDU;Mn;0;NSM;;;;;N;;;;;
+0982;BENGALI SIGN ANUSVARA;Mc;0;L;;;;;N;;;;;
+0983;BENGALI SIGN VISARGA;Mc;0;L;;;;;N;;;;;
+0985;BENGALI LETTER A;Lo;0;L;;;;;N;;;;;
+0986;BENGALI LETTER AA;Lo;0;L;;;;;N;;;;;
+0987;BENGALI LETTER I;Lo;0;L;;;;;N;;;;;
+0988;BENGALI LETTER II;Lo;0;L;;;;;N;;;;;
+0989;BENGALI LETTER U;Lo;0;L;;;;;N;;;;;
+098A;BENGALI LETTER UU;Lo;0;L;;;;;N;;;;;
+098B;BENGALI LETTER VOCALIC R;Lo;0;L;;;;;N;;;;;
+098C;BENGALI LETTER VOCALIC L;Lo;0;L;;;;;N;;;;;
+098F;BENGALI LETTER E;Lo;0;L;;;;;N;;;;;
+0990;BENGALI LETTER AI;Lo;0;L;;;;;N;;;;;
+0993;BENGALI LETTER O;Lo;0;L;;;;;N;;;;;
+0994;BENGALI LETTER AU;Lo;0;L;;;;;N;;;;;
+0995;BENGALI LETTER KA;Lo;0;L;;;;;N;;;;;
+0996;BENGALI LETTER KHA;Lo;0;L;;;;;N;;;;;
+0997;BENGALI LETTER GA;Lo;0;L;;;;;N;;;;;
+0998;BENGALI LETTER GHA;Lo;0;L;;;;;N;;;;;
+0999;BENGALI LETTER NGA;Lo;0;L;;;;;N;;;;;
+099A;BENGALI LETTER CA;Lo;0;L;;;;;N;;;;;
+099B;BENGALI LETTER CHA;Lo;0;L;;;;;N;;;;;
+099C;BENGALI LETTER JA;Lo;0;L;;;;;N;;;;;
+099D;BENGALI LETTER JHA;Lo;0;L;;;;;N;;;;;
+099E;BENGALI LETTER NYA;Lo;0;L;;;;;N;;;;;
+099F;BENGALI LETTER TTA;Lo;0;L;;;;;N;;;;;
+09A0;BENGALI LETTER TTHA;Lo;0;L;;;;;N;;;;;
+09A1;BENGALI LETTER DDA;Lo;0;L;;;;;N;;;;;
+09A2;BENGALI LETTER DDHA;Lo;0;L;;;;;N;;;;;
+09A3;BENGALI LETTER NNA;Lo;0;L;;;;;N;;;;;
+09A4;BENGALI LETTER TA;Lo;0;L;;;;;N;;;;;
+09A5;BENGALI LETTER THA;Lo;0;L;;;;;N;;;;;
+09A6;BENGALI LETTER DA;Lo;0;L;;;;;N;;;;;
+09A7;BENGALI LETTER DHA;Lo;0;L;;;;;N;;;;;
+09A8;BENGALI LETTER NA;Lo;0;L;;;;;N;;;;;
+09AA;BENGALI LETTER PA;Lo;0;L;;;;;N;;;;;
+09AB;BENGALI LETTER PHA;Lo;0;L;;;;;N;;;;;
+09AC;BENGALI LETTER BA;Lo;0;L;;;;;N;;;;;
+09AD;BENGALI LETTER BHA;Lo;0;L;;;;;N;;;;;
+09AE;BENGALI LETTER MA;Lo;0;L;;;;;N;;;;;
+09AF;BENGALI LETTER YA;Lo;0;L;;;;;N;;;;;
+09B0;BENGALI LETTER RA;Lo;0;L;;;;;N;;;;;
+09B2;BENGALI LETTER LA;Lo;0;L;;;;;N;;;;;
+09B6;BENGALI LETTER SHA;Lo;0;L;;;;;N;;;;;
+09B7;BENGALI LETTER SSA;Lo;0;L;;;;;N;;;;;
+09B8;BENGALI LETTER SA;Lo;0;L;;;;;N;;;;;
+09B9;BENGALI LETTER HA;Lo;0;L;;;;;N;;;;;
+09BC;BENGALI SIGN NUKTA;Mn;7;NSM;;;;;N;;;;;
+09BD;BENGALI SIGN AVAGRAHA;Lo;0;L;;;;;N;;;;;
+09BE;BENGALI VOWEL SIGN AA;Mc;0;L;;;;;N;;;;;
+09BF;BENGALI VOWEL SIGN I;Mc;0;L;;;;;N;;;;;
+09C0;BENGALI VOWEL SIGN II;Mc;0;L;;;;;N;;;;;
+09C1;BENGALI VOWEL SIGN U;Mn;0;NSM;;;;;N;;;;;
+09C2;BENGALI VOWEL SIGN UU;Mn;0;NSM;;;;;N;;;;;
+09C3;BENGALI VOWEL SIGN VOCALIC R;Mn;0;NSM;;;;;N;;;;;
+09C4;BENGALI VOWEL SIGN VOCALIC RR;Mn;0;NSM;;;;;N;;;;;
+09C7;BENGALI VOWEL SIGN E;Mc;0;L;;;;;N;;;;;
+09C8;BENGALI VOWEL SIGN AI;Mc;0;L;;;;;N;;;;;
+09CB;BENGALI VOWEL SIGN O;Mc;0;L;09C7 09BE;;;;N;;;;;
+09CC;BENGALI VOWEL SIGN AU;Mc;0;L;09C7 09D7;;;;N;;;;;
+09CD;BENGALI SIGN VIRAMA;Mn;9;NSM;;;;;N;;;;;
+09CE;BENGALI LETTER KHANDA TA;Lo;0;L;;;;;N;;;;;
+09D7;BENGALI AU LENGTH MARK;Mc;0;L;;;;;N;;;;;
+09DC;BENGALI LETTER RRA;Lo;0;L;09A1 09BC;;;;N;;;;;
+09DD;BENGALI LETTER RHA;Lo;0;L;09A2 09BC;;;;N;;;;;
+09DF;BENGALI LETTER YYA;Lo;0;L;09AF 09BC;;;;N;;;;;
+09E0;BENGALI LETTER VOCALIC RR;Lo;0;L;;;;;N;;;;;
+09E1;BENGALI LETTER VOCALIC LL;Lo;0;L;;;;;N;;;;;
+09E2;BENGALI VOWEL SIGN VOCALIC L;Mn;0;NSM;;;;;N;;;;;
+09E3;BENGALI VOWEL SIGN VOCALIC LL;Mn;0;NSM;;;;;N;;;;;
+09E6;BENGALI DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;;
+09E7;BENGALI DIGIT ONE;Nd;0;L;;1;1;1;N;;;;;
+09E8;BENGALI DIGIT TWO;Nd;0;L;;2;2;2;N;;;;;
+09E9;BENGALI DIGIT THREE;Nd;0;L;;3;3;3;N;;;;;
+09EA;BENGALI DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;;
+09EB;BENGALI DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;;
+09EC;BENGALI DIGIT SIX;Nd;0;L;;6;6;6;N;;;;;
+09ED;BENGALI DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;;
+09EE;BENGALI DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;;
+09EF;BENGALI DIGIT NINE;Nd;0;L;;9;9;9;N;;;;;
+09F0;BENGALI LETTER RA WITH MIDDLE DIAGONAL;Lo;0;L;;;;;N;;Assamese;;;
+09F1;BENGALI LETTER RA WITH LOWER DIAGONAL;Lo;0;L;;;;;N;BENGALI LETTER VA WITH LOWER DIAGONAL;Assamese;;;
+09F2;BENGALI RUPEE MARK;Sc;0;ET;;;;;N;;;;;
+09F3;BENGALI RUPEE SIGN;Sc;0;ET;;;;;N;;;;;
+09F4;BENGALI CURRENCY NUMERATOR ONE;No;0;L;;;;1;N;;;;;
+09F5;BENGALI CURRENCY NUMERATOR TWO;No;0;L;;;;2;N;;;;;
+09F6;BENGALI CURRENCY NUMERATOR THREE;No;0;L;;;;3;N;;;;;
+09F7;BENGALI CURRENCY NUMERATOR FOUR;No;0;L;;;;4;N;;;;;
+09F8;BENGALI CURRENCY NUMERATOR ONE LESS THAN THE DENOMINATOR;No;0;L;;;;;N;;;;;
+09F9;BENGALI CURRENCY DENOMINATOR SIXTEEN;No;0;L;;;;16;N;;;;;
+09FA;BENGALI ISSHAR;So;0;L;;;;;N;;;;;
+0A01;GURMUKHI SIGN ADAK BINDI;Mn;0;NSM;;;;;N;;;;;
+0A02;GURMUKHI SIGN BINDI;Mn;0;NSM;;;;;N;;;;;
+0A03;GURMUKHI SIGN VISARGA;Mc;0;L;;;;;N;;;;;
+0A05;GURMUKHI LETTER A;Lo;0;L;;;;;N;;;;;
+0A06;GURMUKHI LETTER AA;Lo;0;L;;;;;N;;;;;
+0A07;GURMUKHI LETTER I;Lo;0;L;;;;;N;;;;;
+0A08;GURMUKHI LETTER II;Lo;0;L;;;;;N;;;;;
+0A09;GURMUKHI LETTER U;Lo;0;L;;;;;N;;;;;
+0A0A;GURMUKHI LETTER UU;Lo;0;L;;;;;N;;;;;
+0A0F;GURMUKHI LETTER EE;Lo;0;L;;;;;N;;;;;
+0A10;GURMUKHI LETTER AI;Lo;0;L;;;;;N;;;;;
+0A13;GURMUKHI LETTER OO;Lo;0;L;;;;;N;;;;;
+0A14;GURMUKHI LETTER AU;Lo;0;L;;;;;N;;;;;
+0A15;GURMUKHI LETTER KA;Lo;0;L;;;;;N;;;;;
+0A16;GURMUKHI LETTER KHA;Lo;0;L;;;;;N;;;;;
+0A17;GURMUKHI LETTER GA;Lo;0;L;;;;;N;;;;;
+0A18;GURMUKHI LETTER GHA;Lo;0;L;;;;;N;;;;;
+0A19;GURMUKHI LETTER NGA;Lo;0;L;;;;;N;;;;;
+0A1A;GURMUKHI LETTER CA;Lo;0;L;;;;;N;;;;;
+0A1B;GURMUKHI LETTER CHA;Lo;0;L;;;;;N;;;;;
+0A1C;GURMUKHI LETTER JA;Lo;0;L;;;;;N;;;;;
+0A1D;GURMUKHI LETTER JHA;Lo;0;L;;;;;N;;;;;
+0A1E;GURMUKHI LETTER NYA;Lo;0;L;;;;;N;;;;;
+0A1F;GURMUKHI LETTER TTA;Lo;0;L;;;;;N;;;;;
+0A20;GURMUKHI LETTER TTHA;Lo;0;L;;;;;N;;;;;
+0A21;GURMUKHI LETTER DDA;Lo;0;L;;;;;N;;;;;
+0A22;GURMUKHI LETTER DDHA;Lo;0;L;;;;;N;;;;;
+0A23;GURMUKHI LETTER NNA;Lo;0;L;;;;;N;;;;;
+0A24;GURMUKHI LETTER TA;Lo;0;L;;;;;N;;;;;
+0A25;GURMUKHI LETTER THA;Lo;0;L;;;;;N;;;;;
+0A26;GURMUKHI LETTER DA;Lo;0;L;;;;;N;;;;;
+0A27;GURMUKHI LETTER DHA;Lo;0;L;;;;;N;;;;;
+0A28;GURMUKHI LETTER NA;Lo;0;L;;;;;N;;;;;
+0A2A;GURMUKHI LETTER PA;Lo;0;L;;;;;N;;;;;
+0A2B;GURMUKHI LETTER PHA;Lo;0;L;;;;;N;;;;;
+0A2C;GURMUKHI LETTER BA;Lo;0;L;;;;;N;;;;;
+0A2D;GURMUKHI LETTER BHA;Lo;0;L;;;;;N;;;;;
+0A2E;GURMUKHI LETTER MA;Lo;0;L;;;;;N;;;;;
+0A2F;GURMUKHI LETTER YA;Lo;0;L;;;;;N;;;;;
+0A30;GURMUKHI LETTER RA;Lo;0;L;;;;;N;;;;;
+0A32;GURMUKHI LETTER LA;Lo;0;L;;;;;N;;;;;
+0A33;GURMUKHI LETTER LLA;Lo;0;L;0A32 0A3C;;;;N;;;;;
+0A35;GURMUKHI LETTER VA;Lo;0;L;;;;;N;;;;;
+0A36;GURMUKHI LETTER SHA;Lo;0;L;0A38 0A3C;;;;N;;;;;
+0A38;GURMUKHI LETTER SA;Lo;0;L;;;;;N;;;;;
+0A39;GURMUKHI LETTER HA;Lo;0;L;;;;;N;;;;;
+0A3C;GURMUKHI SIGN NUKTA;Mn;7;NSM;;;;;N;;;;;
+0A3E;GURMUKHI VOWEL SIGN AA;Mc;0;L;;;;;N;;;;;
+0A3F;GURMUKHI VOWEL SIGN I;Mc;0;L;;;;;N;;;;;
+0A40;GURMUKHI VOWEL SIGN II;Mc;0;L;;;;;N;;;;;
+0A41;GURMUKHI VOWEL SIGN U;Mn;0;NSM;;;;;N;;;;;
+0A42;GURMUKHI VOWEL SIGN UU;Mn;0;NSM;;;;;N;;;;;
+0A47;GURMUKHI VOWEL SIGN EE;Mn;0;NSM;;;;;N;;;;;
+0A48;GURMUKHI VOWEL SIGN AI;Mn;0;NSM;;;;;N;;;;;
+0A4B;GURMUKHI VOWEL SIGN OO;Mn;0;NSM;;;;;N;;;;;
+0A4C;GURMUKHI VOWEL SIGN AU;Mn;0;NSM;;;;;N;;;;;
+0A4D;GURMUKHI SIGN VIRAMA;Mn;9;NSM;;;;;N;;;;;
+0A59;GURMUKHI LETTER KHHA;Lo;0;L;0A16 0A3C;;;;N;;;;;
+0A5A;GURMUKHI LETTER GHHA;Lo;0;L;0A17 0A3C;;;;N;;;;;
+0A5B;GURMUKHI LETTER ZA;Lo;0;L;0A1C 0A3C;;;;N;;;;;
+0A5C;GURMUKHI LETTER RRA;Lo;0;L;;;;;N;;;;;
+0A5E;GURMUKHI LETTER FA;Lo;0;L;0A2B 0A3C;;;;N;;;;;
+0A66;GURMUKHI DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;;
+0A67;GURMUKHI DIGIT ONE;Nd;0;L;;1;1;1;N;;;;;
+0A68;GURMUKHI DIGIT TWO;Nd;0;L;;2;2;2;N;;;;;
+0A69;GURMUKHI DIGIT THREE;Nd;0;L;;3;3;3;N;;;;;
+0A6A;GURMUKHI DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;;
+0A6B;GURMUKHI DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;;
+0A6C;GURMUKHI DIGIT SIX;Nd;0;L;;6;6;6;N;;;;;
+0A6D;GURMUKHI DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;;
+0A6E;GURMUKHI DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;;
+0A6F;GURMUKHI DIGIT NINE;Nd;0;L;;9;9;9;N;;;;;
+0A70;GURMUKHI TIPPI;Mn;0;NSM;;;;;N;;;;;
+0A71;GURMUKHI ADDAK;Mn;0;NSM;;;;;N;;;;;
+0A72;GURMUKHI IRI;Lo;0;L;;;;;N;;;;;
+0A73;GURMUKHI URA;Lo;0;L;;;;;N;;;;;
+0A74;GURMUKHI EK ONKAR;Lo;0;L;;;;;N;;;;;
+0A81;GUJARATI SIGN CANDRABINDU;Mn;0;NSM;;;;;N;;;;;
+0A82;GUJARATI SIGN ANUSVARA;Mn;0;NSM;;;;;N;;;;;
+0A83;GUJARATI SIGN VISARGA;Mc;0;L;;;;;N;;;;;
+0A85;GUJARATI LETTER A;Lo;0;L;;;;;N;;;;;
+0A86;GUJARATI LETTER AA;Lo;0;L;;;;;N;;;;;
+0A87;GUJARATI LETTER I;Lo;0;L;;;;;N;;;;;
+0A88;GUJARATI LETTER II;Lo;0;L;;;;;N;;;;;
+0A89;GUJARATI LETTER U;Lo;0;L;;;;;N;;;;;
+0A8A;GUJARATI LETTER UU;Lo;0;L;;;;;N;;;;;
+0A8B;GUJARATI LETTER VOCALIC R;Lo;0;L;;;;;N;;;;;
+0A8C;GUJARATI LETTER VOCALIC L;Lo;0;L;;;;;N;;;;;
+0A8D;GUJARATI VOWEL CANDRA E;Lo;0;L;;;;;N;;;;;
+0A8F;GUJARATI LETTER E;Lo;0;L;;;;;N;;;;;
+0A90;GUJARATI LETTER AI;Lo;0;L;;;;;N;;;;;
+0A91;GUJARATI VOWEL CANDRA O;Lo;0;L;;;;;N;;;;;
+0A93;GUJARATI LETTER O;Lo;0;L;;;;;N;;;;;
+0A94;GUJARATI LETTER AU;Lo;0;L;;;;;N;;;;;
+0A95;GUJARATI LETTER KA;Lo;0;L;;;;;N;;;;;
+0A96;GUJARATI LETTER KHA;Lo;0;L;;;;;N;;;;;
+0A97;GUJARATI LETTER GA;Lo;0;L;;;;;N;;;;;
+0A98;GUJARATI LETTER GHA;Lo;0;L;;;;;N;;;;;
+0A99;GUJARATI LETTER NGA;Lo;0;L;;;;;N;;;;;
+0A9A;GUJARATI LETTER CA;Lo;0;L;;;;;N;;;;;
+0A9B;GUJARATI LETTER CHA;Lo;0;L;;;;;N;;;;;
+0A9C;GUJARATI LETTER JA;Lo;0;L;;;;;N;;;;;
+0A9D;GUJARATI LETTER JHA;Lo;0;L;;;;;N;;;;;
+0A9E;GUJARATI LETTER NYA;Lo;0;L;;;;;N;;;;;
+0A9F;GUJARATI LETTER TTA;Lo;0;L;;;;;N;;;;;
+0AA0;GUJARATI LETTER TTHA;Lo;0;L;;;;;N;;;;;
+0AA1;GUJARATI LETTER DDA;Lo;0;L;;;;;N;;;;;
+0AA2;GUJARATI LETTER DDHA;Lo;0;L;;;;;N;;;;;
+0AA3;GUJARATI LETTER NNA;Lo;0;L;;;;;N;;;;;
+0AA4;GUJARATI LETTER TA;Lo;0;L;;;;;N;;;;;
+0AA5;GUJARATI LETTER THA;Lo;0;L;;;;;N;;;;;
+0AA6;GUJARATI LETTER DA;Lo;0;L;;;;;N;;;;;
+0AA7;GUJARATI LETTER DHA;Lo;0;L;;;;;N;;;;;
+0AA8;GUJARATI LETTER NA;Lo;0;L;;;;;N;;;;;
+0AAA;GUJARATI LETTER PA;Lo;0;L;;;;;N;;;;;
+0AAB;GUJARATI LETTER PHA;Lo;0;L;;;;;N;;;;;
+0AAC;GUJARATI LETTER BA;Lo;0;L;;;;;N;;;;;
+0AAD;GUJARATI LETTER BHA;Lo;0;L;;;;;N;;;;;
+0AAE;GUJARATI LETTER MA;Lo;0;L;;;;;N;;;;;
+0AAF;GUJARATI LETTER YA;Lo;0;L;;;;;N;;;;;
+0AB0;GUJARATI LETTER RA;Lo;0;L;;;;;N;;;;;
+0AB2;GUJARATI LETTER LA;Lo;0;L;;;;;N;;;;;
+0AB3;GUJARATI LETTER LLA;Lo;0;L;;;;;N;;;;;
+0AB5;GUJARATI LETTER VA;Lo;0;L;;;;;N;;;;;
+0AB6;GUJARATI LETTER SHA;Lo;0;L;;;;;N;;;;;
+0AB7;GUJARATI LETTER SSA;Lo;0;L;;;;;N;;;;;
+0AB8;GUJARATI LETTER SA;Lo;0;L;;;;;N;;;;;
+0AB9;GUJARATI LETTER HA;Lo;0;L;;;;;N;;;;;
+0ABC;GUJARATI SIGN NUKTA;Mn;7;NSM;;;;;N;;;;;
+0ABD;GUJARATI SIGN AVAGRAHA;Lo;0;L;;;;;N;;;;;
+0ABE;GUJARATI VOWEL SIGN AA;Mc;0;L;;;;;N;;;;;
+0ABF;GUJARATI VOWEL SIGN I;Mc;0;L;;;;;N;;;;;
+0AC0;GUJARATI VOWEL SIGN II;Mc;0;L;;;;;N;;;;;
+0AC1;GUJARATI VOWEL SIGN U;Mn;0;NSM;;;;;N;;;;;
+0AC2;GUJARATI VOWEL SIGN UU;Mn;0;NSM;;;;;N;;;;;
+0AC3;GUJARATI VOWEL SIGN VOCALIC R;Mn;0;NSM;;;;;N;;;;;
+0AC4;GUJARATI VOWEL SIGN VOCALIC RR;Mn;0;NSM;;;;;N;;;;;
+0AC5;GUJARATI VOWEL SIGN CANDRA E;Mn;0;NSM;;;;;N;;;;;
+0AC7;GUJARATI VOWEL SIGN E;Mn;0;NSM;;;;;N;;;;;
+0AC8;GUJARATI VOWEL SIGN AI;Mn;0;NSM;;;;;N;;;;;
+0AC9;GUJARATI VOWEL SIGN CANDRA O;Mc;0;L;;;;;N;;;;;
+0ACB;GUJARATI VOWEL SIGN O;Mc;0;L;;;;;N;;;;;
+0ACC;GUJARATI VOWEL SIGN AU;Mc;0;L;;;;;N;;;;;
+0ACD;GUJARATI SIGN VIRAMA;Mn;9;NSM;;;;;N;;;;;
+0AD0;GUJARATI OM;Lo;0;L;;;;;N;;;;;
+0AE0;GUJARATI LETTER VOCALIC RR;Lo;0;L;;;;;N;;;;;
+0AE1;GUJARATI LETTER VOCALIC LL;Lo;0;L;;;;;N;;;;;
+0AE2;GUJARATI VOWEL SIGN VOCALIC L;Mn;0;NSM;;;;;N;;;;;
+0AE3;GUJARATI VOWEL SIGN VOCALIC LL;Mn;0;NSM;;;;;N;;;;;
+0AE6;GUJARATI DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;;
+0AE7;GUJARATI DIGIT ONE;Nd;0;L;;1;1;1;N;;;;;
+0AE8;GUJARATI DIGIT TWO;Nd;0;L;;2;2;2;N;;;;;
+0AE9;GUJARATI DIGIT THREE;Nd;0;L;;3;3;3;N;;;;;
+0AEA;GUJARATI DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;;
+0AEB;GUJARATI DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;;
+0AEC;GUJARATI DIGIT SIX;Nd;0;L;;6;6;6;N;;;;;
+0AED;GUJARATI DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;;
+0AEE;GUJARATI DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;;
+0AEF;GUJARATI DIGIT NINE;Nd;0;L;;9;9;9;N;;;;;
+0AF1;GUJARATI RUPEE SIGN;Sc;0;ET;;;;;N;;;;;
+0B01;ORIYA SIGN CANDRABINDU;Mn;0;NSM;;;;;N;;;;;
+0B02;ORIYA SIGN ANUSVARA;Mc;0;L;;;;;N;;;;;
+0B03;ORIYA SIGN VISARGA;Mc;0;L;;;;;N;;;;;
+0B05;ORIYA LETTER A;Lo;0;L;;;;;N;;;;;
+0B06;ORIYA LETTER AA;Lo;0;L;;;;;N;;;;;
+0B07;ORIYA LETTER I;Lo;0;L;;;;;N;;;;;
+0B08;ORIYA LETTER II;Lo;0;L;;;;;N;;;;;
+0B09;ORIYA LETTER U;Lo;0;L;;;;;N;;;;;
+0B0A;ORIYA LETTER UU;Lo;0;L;;;;;N;;;;;
+0B0B;ORIYA LETTER VOCALIC R;Lo;0;L;;;;;N;;;;;
+0B0C;ORIYA LETTER VOCALIC L;Lo;0;L;;;;;N;;;;;
+0B0F;ORIYA LETTER E;Lo;0;L;;;;;N;;;;;
+0B10;ORIYA LETTER AI;Lo;0;L;;;;;N;;;;;
+0B13;ORIYA LETTER O;Lo;0;L;;;;;N;;;;;
+0B14;ORIYA LETTER AU;Lo;0;L;;;;;N;;;;;
+0B15;ORIYA LETTER KA;Lo;0;L;;;;;N;;;;;
+0B16;ORIYA LETTER KHA;Lo;0;L;;;;;N;;;;;
+0B17;ORIYA LETTER GA;Lo;0;L;;;;;N;;;;;
+0B18;ORIYA LETTER GHA;Lo;0;L;;;;;N;;;;;
+0B19;ORIYA LETTER NGA;Lo;0;L;;;;;N;;;;;
+0B1A;ORIYA LETTER CA;Lo;0;L;;;;;N;;;;;
+0B1B;ORIYA LETTER CHA;Lo;0;L;;;;;N;;;;;
+0B1C;ORIYA LETTER JA;Lo;0;L;;;;;N;;;;;
+0B1D;ORIYA LETTER JHA;Lo;0;L;;;;;N;;;;;
+0B1E;ORIYA LETTER NYA;Lo;0;L;;;;;N;;;;;
+0B1F;ORIYA LETTER TTA;Lo;0;L;;;;;N;;;;;
+0B20;ORIYA LETTER TTHA;Lo;0;L;;;;;N;;;;;
+0B21;ORIYA LETTER DDA;Lo;0;L;;;;;N;;;;;
+0B22;ORIYA LETTER DDHA;Lo;0;L;;;;;N;;;;;
+0B23;ORIYA LETTER NNA;Lo;0;L;;;;;N;;;;;
+0B24;ORIYA LETTER TA;Lo;0;L;;;;;N;;;;;
+0B25;ORIYA LETTER THA;Lo;0;L;;;;;N;;;;;
+0B26;ORIYA LETTER DA;Lo;0;L;;;;;N;;;;;
+0B27;ORIYA LETTER DHA;Lo;0;L;;;;;N;;;;;
+0B28;ORIYA LETTER NA;Lo;0;L;;;;;N;;;;;
+0B2A;ORIYA LETTER PA;Lo;0;L;;;;;N;;;;;
+0B2B;ORIYA LETTER PHA;Lo;0;L;;;;;N;;;;;
+0B2C;ORIYA LETTER BA;Lo;0;L;;;;;N;;;;;
+0B2D;ORIYA LETTER BHA;Lo;0;L;;;;;N;;;;;
+0B2E;ORIYA LETTER MA;Lo;0;L;;;;;N;;;;;
+0B2F;ORIYA LETTER YA;Lo;0;L;;;;;N;;;;;
+0B30;ORIYA LETTER RA;Lo;0;L;;;;;N;;;;;
+0B32;ORIYA LETTER LA;Lo;0;L;;;;;N;;;;;
+0B33;ORIYA LETTER LLA;Lo;0;L;;;;;N;;;;;
+0B35;ORIYA LETTER VA;Lo;0;L;;;;;N;;;;;
+0B36;ORIYA LETTER SHA;Lo;0;L;;;;;N;;;;;
+0B37;ORIYA LETTER SSA;Lo;0;L;;;;;N;;;;;
+0B38;ORIYA LETTER SA;Lo;0;L;;;;;N;;;;;
+0B39;ORIYA LETTER HA;Lo;0;L;;;;;N;;;;;
+0B3C;ORIYA SIGN NUKTA;Mn;7;NSM;;;;;N;;;;;
+0B3D;ORIYA SIGN AVAGRAHA;Lo;0;L;;;;;N;;;;;
+0B3E;ORIYA VOWEL SIGN AA;Mc;0;L;;;;;N;;;;;
+0B3F;ORIYA VOWEL SIGN I;Mn;0;NSM;;;;;N;;;;;
+0B40;ORIYA VOWEL SIGN II;Mc;0;L;;;;;N;;;;;
+0B41;ORIYA VOWEL SIGN U;Mn;0;NSM;;;;;N;;;;;
+0B42;ORIYA VOWEL SIGN UU;Mn;0;NSM;;;;;N;;;;;
+0B43;ORIYA VOWEL SIGN VOCALIC R;Mn;0;NSM;;;;;N;;;;;
+0B47;ORIYA VOWEL SIGN E;Mc;0;L;;;;;N;;;;;
+0B48;ORIYA VOWEL SIGN AI;Mc;0;L;0B47 0B56;;;;N;;;;;
+0B4B;ORIYA VOWEL SIGN O;Mc;0;L;0B47 0B3E;;;;N;;;;;
+0B4C;ORIYA VOWEL SIGN AU;Mc;0;L;0B47 0B57;;;;N;;;;;
+0B4D;ORIYA SIGN VIRAMA;Mn;9;NSM;;;;;N;;;;;
+0B56;ORIYA AI LENGTH MARK;Mn;0;NSM;;;;;N;;;;;
+0B57;ORIYA AU LENGTH MARK;Mc;0;L;;;;;N;;;;;
+0B5C;ORIYA LETTER RRA;Lo;0;L;0B21 0B3C;;;;N;;;;;
+0B5D;ORIYA LETTER RHA;Lo;0;L;0B22 0B3C;;;;N;;;;;
+0B5F;ORIYA LETTER YYA;Lo;0;L;;;;;N;;;;;
+0B60;ORIYA LETTER VOCALIC RR;Lo;0;L;;;;;N;;;;;
+0B61;ORIYA LETTER VOCALIC LL;Lo;0;L;;;;;N;;;;;
+0B66;ORIYA DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;;
+0B67;ORIYA DIGIT ONE;Nd;0;L;;1;1;1;N;;;;;
+0B68;ORIYA DIGIT TWO;Nd;0;L;;2;2;2;N;;;;;
+0B69;ORIYA DIGIT THREE;Nd;0;L;;3;3;3;N;;;;;
+0B6A;ORIYA DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;;
+0B6B;ORIYA DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;;
+0B6C;ORIYA DIGIT SIX;Nd;0;L;;6;6;6;N;;;;;
+0B6D;ORIYA DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;;
+0B6E;ORIYA DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;;
+0B6F;ORIYA DIGIT NINE;Nd;0;L;;9;9;9;N;;;;;
+0B70;ORIYA ISSHAR;So;0;L;;;;;N;;;;;
+0B71;ORIYA LETTER WA;Lo;0;L;;;;;N;;;;;
+0B82;TAMIL SIGN ANUSVARA;Mn;0;NSM;;;;;N;;;;;
+0B83;TAMIL SIGN VISARGA;Lo;0;L;;;;;N;;;;;
+0B85;TAMIL LETTER A;Lo;0;L;;;;;N;;;;;
+0B86;TAMIL LETTER AA;Lo;0;L;;;;;N;;;;;
+0B87;TAMIL LETTER I;Lo;0;L;;;;;N;;;;;
+0B88;TAMIL LETTER II;Lo;0;L;;;;;N;;;;;
+0B89;TAMIL LETTER U;Lo;0;L;;;;;N;;;;;
+0B8A;TAMIL LETTER UU;Lo;0;L;;;;;N;;;;;
+0B8E;TAMIL LETTER E;Lo;0;L;;;;;N;;;;;
+0B8F;TAMIL LETTER EE;Lo;0;L;;;;;N;;;;;
+0B90;TAMIL LETTER AI;Lo;0;L;;;;;N;;;;;
+0B92;TAMIL LETTER O;Lo;0;L;;;;;N;;;;;
+0B93;TAMIL LETTER OO;Lo;0;L;;;;;N;;;;;
+0B94;TAMIL LETTER AU;Lo;0;L;0B92 0BD7;;;;N;;;;;
+0B95;TAMIL LETTER KA;Lo;0;L;;;;;N;;;;;
+0B99;TAMIL LETTER NGA;Lo;0;L;;;;;N;;;;;
+0B9A;TAMIL LETTER CA;Lo;0;L;;;;;N;;;;;
+0B9C;TAMIL LETTER JA;Lo;0;L;;;;;N;;;;;
+0B9E;TAMIL LETTER NYA;Lo;0;L;;;;;N;;;;;
+0B9F;TAMIL LETTER TTA;Lo;0;L;;;;;N;;;;;
+0BA3;TAMIL LETTER NNA;Lo;0;L;;;;;N;;;;;
+0BA4;TAMIL LETTER TA;Lo;0;L;;;;;N;;;;;
+0BA8;TAMIL LETTER NA;Lo;0;L;;;;;N;;;;;
+0BA9;TAMIL LETTER NNNA;Lo;0;L;;;;;N;;;;;
+0BAA;TAMIL LETTER PA;Lo;0;L;;;;;N;;;;;
+0BAE;TAMIL LETTER MA;Lo;0;L;;;;;N;;;;;
+0BAF;TAMIL LETTER YA;Lo;0;L;;;;;N;;;;;
+0BB0;TAMIL LETTER RA;Lo;0;L;;;;;N;;;;;
+0BB1;TAMIL LETTER RRA;Lo;0;L;;;;;N;;;;;
+0BB2;TAMIL LETTER LA;Lo;0;L;;;;;N;;;;;
+0BB3;TAMIL LETTER LLA;Lo;0;L;;;;;N;;;;;
+0BB4;TAMIL LETTER LLLA;Lo;0;L;;;;;N;;;;;
+0BB5;TAMIL LETTER VA;Lo;0;L;;;;;N;;;;;
+0BB6;TAMIL LETTER SHA;Lo;0;L;;;;;N;;;;;
+0BB7;TAMIL LETTER SSA;Lo;0;L;;;;;N;;;;;
+0BB8;TAMIL LETTER SA;Lo;0;L;;;;;N;;;;;
+0BB9;TAMIL LETTER HA;Lo;0;L;;;;;N;;;;;
+0BBE;TAMIL VOWEL SIGN AA;Mc;0;L;;;;;N;;;;;
+0BBF;TAMIL VOWEL SIGN I;Mc;0;L;;;;;N;;;;;
+0BC0;TAMIL VOWEL SIGN II;Mn;0;NSM;;;;;N;;;;;
+0BC1;TAMIL VOWEL SIGN U;Mc;0;L;;;;;N;;;;;
+0BC2;TAMIL VOWEL SIGN UU;Mc;0;L;;;;;N;;;;;
+0BC6;TAMIL VOWEL SIGN E;Mc;0;L;;;;;N;;;;;
+0BC7;TAMIL VOWEL SIGN EE;Mc;0;L;;;;;N;;;;;
+0BC8;TAMIL VOWEL SIGN AI;Mc;0;L;;;;;N;;;;;
+0BCA;TAMIL VOWEL SIGN O;Mc;0;L;0BC6 0BBE;;;;N;;;;;
+0BCB;TAMIL VOWEL SIGN OO;Mc;0;L;0BC7 0BBE;;;;N;;;;;
+0BCC;TAMIL VOWEL SIGN AU;Mc;0;L;0BC6 0BD7;;;;N;;;;;
+0BCD;TAMIL SIGN VIRAMA;Mn;9;NSM;;;;;N;;;;;
+0BD7;TAMIL AU LENGTH MARK;Mc;0;L;;;;;N;;;;;
+0BE6;TAMIL DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;;
+0BE7;TAMIL DIGIT ONE;Nd;0;L;;1;1;1;N;;;;;
+0BE8;TAMIL DIGIT TWO;Nd;0;L;;2;2;2;N;;;;;
+0BE9;TAMIL DIGIT THREE;Nd;0;L;;3;3;3;N;;;;;
+0BEA;TAMIL DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;;
+0BEB;TAMIL DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;;
+0BEC;TAMIL DIGIT SIX;Nd;0;L;;6;6;6;N;;;;;
+0BED;TAMIL DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;;
+0BEE;TAMIL DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;;
+0BEF;TAMIL DIGIT NINE;Nd;0;L;;9;9;9;N;;;;;
+0BF0;TAMIL NUMBER TEN;No;0;L;;;;10;N;;;;;
+0BF1;TAMIL NUMBER ONE HUNDRED;No;0;L;;;;100;N;;;;;
+0BF2;TAMIL NUMBER ONE THOUSAND;No;0;L;;;;1000;N;;;;;
+0BF3;TAMIL DAY SIGN;So;0;ON;;;;;N;;Naal;;;
+0BF4;TAMIL MONTH SIGN;So;0;ON;;;;;N;;Maatham;;;
+0BF5;TAMIL YEAR SIGN;So;0;ON;;;;;N;;Varudam;;;
+0BF6;TAMIL DEBIT SIGN;So;0;ON;;;;;N;;Patru;;;
+0BF7;TAMIL CREDIT SIGN;So;0;ON;;;;;N;;Varavu;;;
+0BF8;TAMIL AS ABOVE SIGN;So;0;ON;;;;;N;;Merpadi;;;
+0BF9;TAMIL RUPEE SIGN;Sc;0;ET;;;;;N;;Rupai;;;
+0BFA;TAMIL NUMBER SIGN;So;0;ON;;;;;N;;Enn;;;
+0C01;TELUGU SIGN CANDRABINDU;Mc;0;L;;;;;N;;;;;
+0C02;TELUGU SIGN ANUSVARA;Mc;0;L;;;;;N;;;;;
+0C03;TELUGU SIGN VISARGA;Mc;0;L;;;;;N;;;;;
+0C05;TELUGU LETTER A;Lo;0;L;;;;;N;;;;;
+0C06;TELUGU LETTER AA;Lo;0;L;;;;;N;;;;;
+0C07;TELUGU LETTER I;Lo;0;L;;;;;N;;;;;
+0C08;TELUGU LETTER II;Lo;0;L;;;;;N;;;;;
+0C09;TELUGU LETTER U;Lo;0;L;;;;;N;;;;;
+0C0A;TELUGU LETTER UU;Lo;0;L;;;;;N;;;;;
+0C0B;TELUGU LETTER VOCALIC R;Lo;0;L;;;;;N;;;;;
+0C0C;TELUGU LETTER VOCALIC L;Lo;0;L;;;;;N;;;;;
+0C0E;TELUGU LETTER E;Lo;0;L;;;;;N;;;;;
+0C0F;TELUGU LETTER EE;Lo;0;L;;;;;N;;;;;
+0C10;TELUGU LETTER AI;Lo;0;L;;;;;N;;;;;
+0C12;TELUGU LETTER O;Lo;0;L;;;;;N;;;;;
+0C13;TELUGU LETTER OO;Lo;0;L;;;;;N;;;;;
+0C14;TELUGU LETTER AU;Lo;0;L;;;;;N;;;;;
+0C15;TELUGU LETTER KA;Lo;0;L;;;;;N;;;;;
+0C16;TELUGU LETTER KHA;Lo;0;L;;;;;N;;;;;
+0C17;TELUGU LETTER GA;Lo;0;L;;;;;N;;;;;
+0C18;TELUGU LETTER GHA;Lo;0;L;;;;;N;;;;;
+0C19;TELUGU LETTER NGA;Lo;0;L;;;;;N;;;;;
+0C1A;TELUGU LETTER CA;Lo;0;L;;;;;N;;;;;
+0C1B;TELUGU LETTER CHA;Lo;0;L;;;;;N;;;;;
+0C1C;TELUGU LETTER JA;Lo;0;L;;;;;N;;;;;
+0C1D;TELUGU LETTER JHA;Lo;0;L;;;;;N;;;;;
+0C1E;TELUGU LETTER NYA;Lo;0;L;;;;;N;;;;;
+0C1F;TELUGU LETTER TTA;Lo;0;L;;;;;N;;;;;
+0C20;TELUGU LETTER TTHA;Lo;0;L;;;;;N;;;;;
+0C21;TELUGU LETTER DDA;Lo;0;L;;;;;N;;;;;
+0C22;TELUGU LETTER DDHA;Lo;0;L;;;;;N;;;;;
+0C23;TELUGU LETTER NNA;Lo;0;L;;;;;N;;;;;
+0C24;TELUGU LETTER TA;Lo;0;L;;;;;N;;;;;
+0C25;TELUGU LETTER THA;Lo;0;L;;;;;N;;;;;
+0C26;TELUGU LETTER DA;Lo;0;L;;;;;N;;;;;
+0C27;TELUGU LETTER DHA;Lo;0;L;;;;;N;;;;;
+0C28;TELUGU LETTER NA;Lo;0;L;;;;;N;;;;;
+0C2A;TELUGU LETTER PA;Lo;0;L;;;;;N;;;;;
+0C2B;TELUGU LETTER PHA;Lo;0;L;;;;;N;;;;;
+0C2C;TELUGU LETTER BA;Lo;0;L;;;;;N;;;;;
+0C2D;TELUGU LETTER BHA;Lo;0;L;;;;;N;;;;;
+0C2E;TELUGU LETTER MA;Lo;0;L;;;;;N;;;;;
+0C2F;TELUGU LETTER YA;Lo;0;L;;;;;N;;;;;
+0C30;TELUGU LETTER RA;Lo;0;L;;;;;N;;;;;
+0C31;TELUGU LETTER RRA;Lo;0;L;;;;;N;;;;;
+0C32;TELUGU LETTER LA;Lo;0;L;;;;;N;;;;;
+0C33;TELUGU LETTER LLA;Lo;0;L;;;;;N;;;;;
+0C35;TELUGU LETTER VA;Lo;0;L;;;;;N;;;;;
+0C36;TELUGU LETTER SHA;Lo;0;L;;;;;N;;;;;
+0C37;TELUGU LETTER SSA;Lo;0;L;;;;;N;;;;;
+0C38;TELUGU LETTER SA;Lo;0;L;;;;;N;;;;;
+0C39;TELUGU LETTER HA;Lo;0;L;;;;;N;;;;;
+0C3E;TELUGU VOWEL SIGN AA;Mn;0;NSM;;;;;N;;;;;
+0C3F;TELUGU VOWEL SIGN I;Mn;0;NSM;;;;;N;;;;;
+0C40;TELUGU VOWEL SIGN II;Mn;0;NSM;;;;;N;;;;;
+0C41;TELUGU VOWEL SIGN U;Mc;0;L;;;;;N;;;;;
+0C42;TELUGU VOWEL SIGN UU;Mc;0;L;;;;;N;;;;;
+0C43;TELUGU VOWEL SIGN VOCALIC R;Mc;0;L;;;;;N;;;;;
+0C44;TELUGU VOWEL SIGN VOCALIC RR;Mc;0;L;;;;;N;;;;;
+0C46;TELUGU VOWEL SIGN E;Mn;0;NSM;;;;;N;;;;;
+0C47;TELUGU VOWEL SIGN EE;Mn;0;NSM;;;;;N;;;;;
+0C48;TELUGU VOWEL SIGN AI;Mn;0;NSM;0C46 0C56;;;;N;;;;;
+0C4A;TELUGU VOWEL SIGN O;Mn;0;NSM;;;;;N;;;;;
+0C4B;TELUGU VOWEL SIGN OO;Mn;0;NSM;;;;;N;;;;;
+0C4C;TELUGU VOWEL SIGN AU;Mn;0;NSM;;;;;N;;;;;
+0C4D;TELUGU SIGN VIRAMA;Mn;9;NSM;;;;;N;;;;;
+0C55;TELUGU LENGTH MARK;Mn;84;NSM;;;;;N;;;;;
+0C56;TELUGU AI LENGTH MARK;Mn;91;NSM;;;;;N;;;;;
+0C60;TELUGU LETTER VOCALIC RR;Lo;0;L;;;;;N;;;;;
+0C61;TELUGU LETTER VOCALIC LL;Lo;0;L;;;;;N;;;;;
+0C66;TELUGU DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;;
+0C67;TELUGU DIGIT ONE;Nd;0;L;;1;1;1;N;;;;;
+0C68;TELUGU DIGIT TWO;Nd;0;L;;2;2;2;N;;;;;
+0C69;TELUGU DIGIT THREE;Nd;0;L;;3;3;3;N;;;;;
+0C6A;TELUGU DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;;
+0C6B;TELUGU DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;;
+0C6C;TELUGU DIGIT SIX;Nd;0;L;;6;6;6;N;;;;;
+0C6D;TELUGU DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;;
+0C6E;TELUGU DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;;
+0C6F;TELUGU DIGIT NINE;Nd;0;L;;9;9;9;N;;;;;
+0C82;KANNADA SIGN ANUSVARA;Mc;0;L;;;;;N;;;;;
+0C83;KANNADA SIGN VISARGA;Mc;0;L;;;;;N;;;;;
+0C85;KANNADA LETTER A;Lo;0;L;;;;;N;;;;;
+0C86;KANNADA LETTER AA;Lo;0;L;;;;;N;;;;;
+0C87;KANNADA LETTER I;Lo;0;L;;;;;N;;;;;
+0C88;KANNADA LETTER II;Lo;0;L;;;;;N;;;;;
+0C89;KANNADA LETTER U;Lo;0;L;;;;;N;;;;;
+0C8A;KANNADA LETTER UU;Lo;0;L;;;;;N;;;;;
+0C8B;KANNADA LETTER VOCALIC R;Lo;0;L;;;;;N;;;;;
+0C8C;KANNADA LETTER VOCALIC L;Lo;0;L;;;;;N;;;;;
+0C8E;KANNADA LETTER E;Lo;0;L;;;;;N;;;;;
+0C8F;KANNADA LETTER EE;Lo;0;L;;;;;N;;;;;
+0C90;KANNADA LETTER AI;Lo;0;L;;;;;N;;;;;
+0C92;KANNADA LETTER O;Lo;0;L;;;;;N;;;;;
+0C93;KANNADA LETTER OO;Lo;0;L;;;;;N;;;;;
+0C94;KANNADA LETTER AU;Lo;0;L;;;;;N;;;;;
+0C95;KANNADA LETTER KA;Lo;0;L;;;;;N;;;;;
+0C96;KANNADA LETTER KHA;Lo;0;L;;;;;N;;;;;
+0C97;KANNADA LETTER GA;Lo;0;L;;;;;N;;;;;
+0C98;KANNADA LETTER GHA;Lo;0;L;;;;;N;;;;;
+0C99;KANNADA LETTER NGA;Lo;0;L;;;;;N;;;;;
+0C9A;KANNADA LETTER CA;Lo;0;L;;;;;N;;;;;
+0C9B;KANNADA LETTER CHA;Lo;0;L;;;;;N;;;;;
+0C9C;KANNADA LETTER JA;Lo;0;L;;;;;N;;;;;
+0C9D;KANNADA LETTER JHA;Lo;0;L;;;;;N;;;;;
+0C9E;KANNADA LETTER NYA;Lo;0;L;;;;;N;;;;;
+0C9F;KANNADA LETTER TTA;Lo;0;L;;;;;N;;;;;
+0CA0;KANNADA LETTER TTHA;Lo;0;L;;;;;N;;;;;
+0CA1;KANNADA LETTER DDA;Lo;0;L;;;;;N;;;;;
+0CA2;KANNADA LETTER DDHA;Lo;0;L;;;;;N;;;;;
+0CA3;KANNADA LETTER NNA;Lo;0;L;;;;;N;;;;;
+0CA4;KANNADA LETTER TA;Lo;0;L;;;;;N;;;;;
+0CA5;KANNADA LETTER THA;Lo;0;L;;;;;N;;;;;
+0CA6;KANNADA LETTER DA;Lo;0;L;;;;;N;;;;;
+0CA7;KANNADA LETTER DHA;Lo;0;L;;;;;N;;;;;
+0CA8;KANNADA LETTER NA;Lo;0;L;;;;;N;;;;;
+0CAA;KANNADA LETTER PA;Lo;0;L;;;;;N;;;;;
+0CAB;KANNADA LETTER PHA;Lo;0;L;;;;;N;;;;;
+0CAC;KANNADA LETTER BA;Lo;0;L;;;;;N;;;;;
+0CAD;KANNADA LETTER BHA;Lo;0;L;;;;;N;;;;;
+0CAE;KANNADA LETTER MA;Lo;0;L;;;;;N;;;;;
+0CAF;KANNADA LETTER YA;Lo;0;L;;;;;N;;;;;
+0CB0;KANNADA LETTER RA;Lo;0;L;;;;;N;;;;;
+0CB1;KANNADA LETTER RRA;Lo;0;L;;;;;N;;;;;
+0CB2;KANNADA LETTER LA;Lo;0;L;;;;;N;;;;;
+0CB3;KANNADA LETTER LLA;Lo;0;L;;;;;N;;;;;
+0CB5;KANNADA LETTER VA;Lo;0;L;;;;;N;;;;;
+0CB6;KANNADA LETTER SHA;Lo;0;L;;;;;N;;;;;
+0CB7;KANNADA LETTER SSA;Lo;0;L;;;;;N;;;;;
+0CB8;KANNADA LETTER SA;Lo;0;L;;;;;N;;;;;
+0CB9;KANNADA LETTER HA;Lo;0;L;;;;;N;;;;;
+0CBC;KANNADA SIGN NUKTA;Mn;7;NSM;;;;;N;;;;;
+0CBD;KANNADA SIGN AVAGRAHA;Lo;0;L;;;;;N;;;;;
+0CBE;KANNADA VOWEL SIGN AA;Mc;0;L;;;;;N;;;;;
+0CBF;KANNADA VOWEL SIGN I;Mn;0;L;;;;;N;;;;;
+0CC0;KANNADA VOWEL SIGN II;Mc;0;L;0CBF 0CD5;;;;N;;;;;
+0CC1;KANNADA VOWEL SIGN U;Mc;0;L;;;;;N;;;;;
+0CC2;KANNADA VOWEL SIGN UU;Mc;0;L;;;;;N;;;;;
+0CC3;KANNADA VOWEL SIGN VOCALIC R;Mc;0;L;;;;;N;;;;;
+0CC4;KANNADA VOWEL SIGN VOCALIC RR;Mc;0;L;;;;;N;;;;;
+0CC6;KANNADA VOWEL SIGN E;Mn;0;L;;;;;N;;;;;
+0CC7;KANNADA VOWEL SIGN EE;Mc;0;L;0CC6 0CD5;;;;N;;;;;
+0CC8;KANNADA VOWEL SIGN AI;Mc;0;L;0CC6 0CD6;;;;N;;;;;
+0CCA;KANNADA VOWEL SIGN O;Mc;0;L;0CC6 0CC2;;;;N;;;;;
+0CCB;KANNADA VOWEL SIGN OO;Mc;0;L;0CCA 0CD5;;;;N;;;;;
+0CCC;KANNADA VOWEL SIGN AU;Mn;0;NSM;;;;;N;;;;;
+0CCD;KANNADA SIGN VIRAMA;Mn;9;NSM;;;;;N;;;;;
+0CD5;KANNADA LENGTH MARK;Mc;0;L;;;;;N;;;;;
+0CD6;KANNADA AI LENGTH MARK;Mc;0;L;;;;;N;;;;;
+0CDE;KANNADA LETTER FA;Lo;0;L;;;;;N;;;;;
+0CE0;KANNADA LETTER VOCALIC RR;Lo;0;L;;;;;N;;;;;
+0CE1;KANNADA LETTER VOCALIC LL;Lo;0;L;;;;;N;;;;;
+0CE6;KANNADA DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;;
+0CE7;KANNADA DIGIT ONE;Nd;0;L;;1;1;1;N;;;;;
+0CE8;KANNADA DIGIT TWO;Nd;0;L;;2;2;2;N;;;;;
+0CE9;KANNADA DIGIT THREE;Nd;0;L;;3;3;3;N;;;;;
+0CEA;KANNADA DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;;
+0CEB;KANNADA DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;;
+0CEC;KANNADA DIGIT SIX;Nd;0;L;;6;6;6;N;;;;;
+0CED;KANNADA DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;;
+0CEE;KANNADA DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;;
+0CEF;KANNADA DIGIT NINE;Nd;0;L;;9;9;9;N;;;;;
+0D02;MALAYALAM SIGN ANUSVARA;Mc;0;L;;;;;N;;;;;
+0D03;MALAYALAM SIGN VISARGA;Mc;0;L;;;;;N;;;;;
+0D05;MALAYALAM LETTER A;Lo;0;L;;;;;N;;;;;
+0D06;MALAYALAM LETTER AA;Lo;0;L;;;;;N;;;;;
+0D07;MALAYALAM LETTER I;Lo;0;L;;;;;N;;;;;
+0D08;MALAYALAM LETTER II;Lo;0;L;;;;;N;;;;;
+0D09;MALAYALAM LETTER U;Lo;0;L;;;;;N;;;;;
+0D0A;MALAYALAM LETTER UU;Lo;0;L;;;;;N;;;;;
+0D0B;MALAYALAM LETTER VOCALIC R;Lo;0;L;;;;;N;;;;;
+0D0C;MALAYALAM LETTER VOCALIC L;Lo;0;L;;;;;N;;;;;
+0D0E;MALAYALAM LETTER E;Lo;0;L;;;;;N;;;;;
+0D0F;MALAYALAM LETTER EE;Lo;0;L;;;;;N;;;;;
+0D10;MALAYALAM LETTER AI;Lo;0;L;;;;;N;;;;;
+0D12;MALAYALAM LETTER O;Lo;0;L;;;;;N;;;;;
+0D13;MALAYALAM LETTER OO;Lo;0;L;;;;;N;;;;;
+0D14;MALAYALAM LETTER AU;Lo;0;L;;;;;N;;;;;
+0D15;MALAYALAM LETTER KA;Lo;0;L;;;;;N;;;;;
+0D16;MALAYALAM LETTER KHA;Lo;0;L;;;;;N;;;;;
+0D17;MALAYALAM LETTER GA;Lo;0;L;;;;;N;;;;;
+0D18;MALAYALAM LETTER GHA;Lo;0;L;;;;;N;;;;;
+0D19;MALAYALAM LETTER NGA;Lo;0;L;;;;;N;;;;;
+0D1A;MALAYALAM LETTER CA;Lo;0;L;;;;;N;;;;;
+0D1B;MALAYALAM LETTER CHA;Lo;0;L;;;;;N;;;;;
+0D1C;MALAYALAM LETTER JA;Lo;0;L;;;;;N;;;;;
+0D1D;MALAYALAM LETTER JHA;Lo;0;L;;;;;N;;;;;
+0D1E;MALAYALAM LETTER NYA;Lo;0;L;;;;;N;;;;;
+0D1F;MALAYALAM LETTER TTA;Lo;0;L;;;;;N;;;;;
+0D20;MALAYALAM LETTER TTHA;Lo;0;L;;;;;N;;;;;
+0D21;MALAYALAM LETTER DDA;Lo;0;L;;;;;N;;;;;
+0D22;MALAYALAM LETTER DDHA;Lo;0;L;;;;;N;;;;;
+0D23;MALAYALAM LETTER NNA;Lo;0;L;;;;;N;;;;;
+0D24;MALAYALAM LETTER TA;Lo;0;L;;;;;N;;;;;
+0D25;MALAYALAM LETTER THA;Lo;0;L;;;;;N;;;;;
+0D26;MALAYALAM LETTER DA;Lo;0;L;;;;;N;;;;;
+0D27;MALAYALAM LETTER DHA;Lo;0;L;;;;;N;;;;;
+0D28;MALAYALAM LETTER NA;Lo;0;L;;;;;N;;;;;
+0D2A;MALAYALAM LETTER PA;Lo;0;L;;;;;N;;;;;
+0D2B;MALAYALAM LETTER PHA;Lo;0;L;;;;;N;;;;;
+0D2C;MALAYALAM LETTER BA;Lo;0;L;;;;;N;;;;;
+0D2D;MALAYALAM LETTER BHA;Lo;0;L;;;;;N;;;;;
+0D2E;MALAYALAM LETTER MA;Lo;0;L;;;;;N;;;;;
+0D2F;MALAYALAM LETTER YA;Lo;0;L;;;;;N;;;;;
+0D30;MALAYALAM LETTER RA;Lo;0;L;;;;;N;;;;;
+0D31;MALAYALAM LETTER RRA;Lo;0;L;;;;;N;;;;;
+0D32;MALAYALAM LETTER LA;Lo;0;L;;;;;N;;;;;
+0D33;MALAYALAM LETTER LLA;Lo;0;L;;;;;N;;;;;
+0D34;MALAYALAM LETTER LLLA;Lo;0;L;;;;;N;;;;;
+0D35;MALAYALAM LETTER VA;Lo;0;L;;;;;N;;;;;
+0D36;MALAYALAM LETTER SHA;Lo;0;L;;;;;N;;;;;
+0D37;MALAYALAM LETTER SSA;Lo;0;L;;;;;N;;;;;
+0D38;MALAYALAM LETTER SA;Lo;0;L;;;;;N;;;;;
+0D39;MALAYALAM LETTER HA;Lo;0;L;;;;;N;;;;;
+0D3E;MALAYALAM VOWEL SIGN AA;Mc;0;L;;;;;N;;;;;
+0D3F;MALAYALAM VOWEL SIGN I;Mc;0;L;;;;;N;;;;;
+0D40;MALAYALAM VOWEL SIGN II;Mc;0;L;;;;;N;;;;;
+0D41;MALAYALAM VOWEL SIGN U;Mn;0;NSM;;;;;N;;;;;
+0D42;MALAYALAM VOWEL SIGN UU;Mn;0;NSM;;;;;N;;;;;
+0D43;MALAYALAM VOWEL SIGN VOCALIC R;Mn;0;NSM;;;;;N;;;;;
+0D46;MALAYALAM VOWEL SIGN E;Mc;0;L;;;;;N;;;;;
+0D47;MALAYALAM VOWEL SIGN EE;Mc;0;L;;;;;N;;;;;
+0D48;MALAYALAM VOWEL SIGN AI;Mc;0;L;;;;;N;;;;;
+0D4A;MALAYALAM VOWEL SIGN O;Mc;0;L;0D46 0D3E;;;;N;;;;;
+0D4B;MALAYALAM VOWEL SIGN OO;Mc;0;L;0D47 0D3E;;;;N;;;;;
+0D4C;MALAYALAM VOWEL SIGN AU;Mc;0;L;0D46 0D57;;;;N;;;;;
+0D4D;MALAYALAM SIGN VIRAMA;Mn;9;NSM;;;;;N;;;;;
+0D57;MALAYALAM AU LENGTH MARK;Mc;0;L;;;;;N;;;;;
+0D60;MALAYALAM LETTER VOCALIC RR;Lo;0;L;;;;;N;;;;;
+0D61;MALAYALAM LETTER VOCALIC LL;Lo;0;L;;;;;N;;;;;
+0D66;MALAYALAM DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;;
+0D67;MALAYALAM DIGIT ONE;Nd;0;L;;1;1;1;N;;;;;
+0D68;MALAYALAM DIGIT TWO;Nd;0;L;;2;2;2;N;;;;;
+0D69;MALAYALAM DIGIT THREE;Nd;0;L;;3;3;3;N;;;;;
+0D6A;MALAYALAM DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;;
+0D6B;MALAYALAM DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;;
+0D6C;MALAYALAM DIGIT SIX;Nd;0;L;;6;6;6;N;;;;;
+0D6D;MALAYALAM DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;;
+0D6E;MALAYALAM DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;;
+0D6F;MALAYALAM DIGIT NINE;Nd;0;L;;9;9;9;N;;;;;
+0D82;SINHALA SIGN ANUSVARAYA;Mc;0;L;;;;;N;;;;;
+0D83;SINHALA SIGN VISARGAYA;Mc;0;L;;;;;N;;;;;
+0D85;SINHALA LETTER AYANNA;Lo;0;L;;;;;N;;;;;
+0D86;SINHALA LETTER AAYANNA;Lo;0;L;;;;;N;;;;;
+0D87;SINHALA LETTER AEYANNA;Lo;0;L;;;;;N;;;;;
+0D88;SINHALA LETTER AEEYANNA;Lo;0;L;;;;;N;;;;;
+0D89;SINHALA LETTER IYANNA;Lo;0;L;;;;;N;;;;;
+0D8A;SINHALA LETTER IIYANNA;Lo;0;L;;;;;N;;;;;
+0D8B;SINHALA LETTER UYANNA;Lo;0;L;;;;;N;;;;;
+0D8C;SINHALA LETTER UUYANNA;Lo;0;L;;;;;N;;;;;
+0D8D;SINHALA LETTER IRUYANNA;Lo;0;L;;;;;N;;;;;
+0D8E;SINHALA LETTER IRUUYANNA;Lo;0;L;;;;;N;;;;;
+0D8F;SINHALA LETTER ILUYANNA;Lo;0;L;;;;;N;;;;;
+0D90;SINHALA LETTER ILUUYANNA;Lo;0;L;;;;;N;;;;;
+0D91;SINHALA LETTER EYANNA;Lo;0;L;;;;;N;;;;;
+0D92;SINHALA LETTER EEYANNA;Lo;0;L;;;;;N;;;;;
+0D93;SINHALA LETTER AIYANNA;Lo;0;L;;;;;N;;;;;
+0D94;SINHALA LETTER OYANNA;Lo;0;L;;;;;N;;;;;
+0D95;SINHALA LETTER OOYANNA;Lo;0;L;;;;;N;;;;;
+0D96;SINHALA LETTER AUYANNA;Lo;0;L;;;;;N;;;;;
+0D9A;SINHALA LETTER ALPAPRAANA KAYANNA;Lo;0;L;;;;;N;;;;;
+0D9B;SINHALA LETTER MAHAAPRAANA KAYANNA;Lo;0;L;;;;;N;;;;;
+0D9C;SINHALA LETTER ALPAPRAANA GAYANNA;Lo;0;L;;;;;N;;;;;
+0D9D;SINHALA LETTER MAHAAPRAANA GAYANNA;Lo;0;L;;;;;N;;;;;
+0D9E;SINHALA LETTER KANTAJA NAASIKYAYA;Lo;0;L;;;;;N;;;;;
+0D9F;SINHALA LETTER SANYAKA GAYANNA;Lo;0;L;;;;;N;;;;;
+0DA0;SINHALA LETTER ALPAPRAANA CAYANNA;Lo;0;L;;;;;N;;;;;
+0DA1;SINHALA LETTER MAHAAPRAANA CAYANNA;Lo;0;L;;;;;N;;;;;
+0DA2;SINHALA LETTER ALPAPRAANA JAYANNA;Lo;0;L;;;;;N;;;;;
+0DA3;SINHALA LETTER MAHAAPRAANA JAYANNA;Lo;0;L;;;;;N;;;;;
+0DA4;SINHALA LETTER TAALUJA NAASIKYAYA;Lo;0;L;;;;;N;;;;;
+0DA5;SINHALA LETTER TAALUJA SANYOOGA NAAKSIKYAYA;Lo;0;L;;;;;N;;;;;
+0DA6;SINHALA LETTER SANYAKA JAYANNA;Lo;0;L;;;;;N;;;;;
+0DA7;SINHALA LETTER ALPAPRAANA TTAYANNA;Lo;0;L;;;;;N;;;;;
+0DA8;SINHALA LETTER MAHAAPRAANA TTAYANNA;Lo;0;L;;;;;N;;;;;
+0DA9;SINHALA LETTER ALPAPRAANA DDAYANNA;Lo;0;L;;;;;N;;;;;
+0DAA;SINHALA LETTER MAHAAPRAANA DDAYANNA;Lo;0;L;;;;;N;;;;;
+0DAB;SINHALA LETTER MUURDHAJA NAYANNA;Lo;0;L;;;;;N;;;;;
+0DAC;SINHALA LETTER SANYAKA DDAYANNA;Lo;0;L;;;;;N;;;;;
+0DAD;SINHALA LETTER ALPAPRAANA TAYANNA;Lo;0;L;;;;;N;;;;;
+0DAE;SINHALA LETTER MAHAAPRAANA TAYANNA;Lo;0;L;;;;;N;;;;;
+0DAF;SINHALA LETTER ALPAPRAANA DAYANNA;Lo;0;L;;;;;N;;;;;
+0DB0;SINHALA LETTER MAHAAPRAANA DAYANNA;Lo;0;L;;;;;N;;;;;
+0DB1;SINHALA LETTER DANTAJA NAYANNA;Lo;0;L;;;;;N;;;;;
+0DB3;SINHALA LETTER SANYAKA DAYANNA;Lo;0;L;;;;;N;;;;;
+0DB4;SINHALA LETTER ALPAPRAANA PAYANNA;Lo;0;L;;;;;N;;;;;
+0DB5;SINHALA LETTER MAHAAPRAANA PAYANNA;Lo;0;L;;;;;N;;;;;
+0DB6;SINHALA LETTER ALPAPRAANA BAYANNA;Lo;0;L;;;;;N;;;;;
+0DB7;SINHALA LETTER MAHAAPRAANA BAYANNA;Lo;0;L;;;;;N;;;;;
+0DB8;SINHALA LETTER MAYANNA;Lo;0;L;;;;;N;;;;;
+0DB9;SINHALA LETTER AMBA BAYANNA;Lo;0;L;;;;;N;;;;;
+0DBA;SINHALA LETTER YAYANNA;Lo;0;L;;;;;N;;;;;
+0DBB;SINHALA LETTER RAYANNA;Lo;0;L;;;;;N;;;;;
+0DBD;SINHALA LETTER DANTAJA LAYANNA;Lo;0;L;;;;;N;;;;;
+0DC0;SINHALA LETTER VAYANNA;Lo;0;L;;;;;N;;;;;
+0DC1;SINHALA LETTER TAALUJA SAYANNA;Lo;0;L;;;;;N;;;;;
+0DC2;SINHALA LETTER MUURDHAJA SAYANNA;Lo;0;L;;;;;N;;;;;
+0DC3;SINHALA LETTER DANTAJA SAYANNA;Lo;0;L;;;;;N;;;;;
+0DC4;SINHALA LETTER HAYANNA;Lo;0;L;;;;;N;;;;;
+0DC5;SINHALA LETTER MUURDHAJA LAYANNA;Lo;0;L;;;;;N;;;;;
+0DC6;SINHALA LETTER FAYANNA;Lo;0;L;;;;;N;;;;;
+0DCA;SINHALA SIGN AL-LAKUNA;Mn;9;NSM;;;;;N;;;;;
+0DCF;SINHALA VOWEL SIGN AELA-PILLA;Mc;0;L;;;;;N;;;;;
+0DD0;SINHALA VOWEL SIGN KETTI AEDA-PILLA;Mc;0;L;;;;;N;;;;;
+0DD1;SINHALA VOWEL SIGN DIGA AEDA-PILLA;Mc;0;L;;;;;N;;;;;
+0DD2;SINHALA VOWEL SIGN KETTI IS-PILLA;Mn;0;NSM;;;;;N;;;;;
+0DD3;SINHALA VOWEL SIGN DIGA IS-PILLA;Mn;0;NSM;;;;;N;;;;;
+0DD4;SINHALA VOWEL SIGN KETTI PAA-PILLA;Mn;0;NSM;;;;;N;;;;;
+0DD6;SINHALA VOWEL SIGN DIGA PAA-PILLA;Mn;0;NSM;;;;;N;;;;;
+0DD8;SINHALA VOWEL SIGN GAETTA-PILLA;Mc;0;L;;;;;N;;;;;
+0DD9;SINHALA VOWEL SIGN KOMBUVA;Mc;0;L;;;;;N;;;;;
+0DDA;SINHALA VOWEL SIGN DIGA KOMBUVA;Mc;0;L;0DD9 0DCA;;;;N;;;;;
+0DDB;SINHALA VOWEL SIGN KOMBU DEKA;Mc;0;L;;;;;N;;;;;
+0DDC;SINHALA VOWEL SIGN KOMBUVA HAA AELA-PILLA;Mc;0;L;0DD9 0DCF;;;;N;;;;;
+0DDD;SINHALA VOWEL SIGN KOMBUVA HAA DIGA AELA-PILLA;Mc;0;L;0DDC 0DCA;;;;N;;;;;
+0DDE;SINHALA VOWEL SIGN KOMBUVA HAA GAYANUKITTA;Mc;0;L;0DD9 0DDF;;;;N;;;;;
+0DDF;SINHALA VOWEL SIGN GAYANUKITTA;Mc;0;L;;;;;N;;;;;
+0DF2;SINHALA VOWEL SIGN DIGA GAETTA-PILLA;Mc;0;L;;;;;N;;;;;
+0DF3;SINHALA VOWEL SIGN DIGA GAYANUKITTA;Mc;0;L;;;;;N;;;;;
+0DF4;SINHALA PUNCTUATION KUNDDALIYA;Po;0;L;;;;;N;;;;;
+0E01;THAI CHARACTER KO KAI;Lo;0;L;;;;;N;THAI LETTER KO KAI;;;;
+0E02;THAI CHARACTER KHO KHAI;Lo;0;L;;;;;N;THAI LETTER KHO KHAI;;;;
+0E03;THAI CHARACTER KHO KHUAT;Lo;0;L;;;;;N;THAI LETTER KHO KHUAT;;;;
+0E04;THAI CHARACTER KHO KHWAI;Lo;0;L;;;;;N;THAI LETTER KHO KHWAI;;;;
+0E05;THAI CHARACTER KHO KHON;Lo;0;L;;;;;N;THAI LETTER KHO KHON;;;;
+0E06;THAI CHARACTER KHO RAKHANG;Lo;0;L;;;;;N;THAI LETTER KHO RAKHANG;;;;
+0E07;THAI CHARACTER NGO NGU;Lo;0;L;;;;;N;THAI LETTER NGO NGU;;;;
+0E08;THAI CHARACTER CHO CHAN;Lo;0;L;;;;;N;THAI LETTER CHO CHAN;;;;
+0E09;THAI CHARACTER CHO CHING;Lo;0;L;;;;;N;THAI LETTER CHO CHING;;;;
+0E0A;THAI CHARACTER CHO CHANG;Lo;0;L;;;;;N;THAI LETTER CHO CHANG;;;;
+0E0B;THAI CHARACTER SO SO;Lo;0;L;;;;;N;THAI LETTER SO SO;;;;
+0E0C;THAI CHARACTER CHO CHOE;Lo;0;L;;;;;N;THAI LETTER CHO CHOE;;;;
+0E0D;THAI CHARACTER YO YING;Lo;0;L;;;;;N;THAI LETTER YO YING;;;;
+0E0E;THAI CHARACTER DO CHADA;Lo;0;L;;;;;N;THAI LETTER DO CHADA;;;;
+0E0F;THAI CHARACTER TO PATAK;Lo;0;L;;;;;N;THAI LETTER TO PATAK;;;;
+0E10;THAI CHARACTER THO THAN;Lo;0;L;;;;;N;THAI LETTER THO THAN;;;;
+0E11;THAI CHARACTER THO NANGMONTHO;Lo;0;L;;;;;N;THAI LETTER THO NANGMONTHO;;;;
+0E12;THAI CHARACTER THO PHUTHAO;Lo;0;L;;;;;N;THAI LETTER THO PHUTHAO;;;;
+0E13;THAI CHARACTER NO NEN;Lo;0;L;;;;;N;THAI LETTER NO NEN;;;;
+0E14;THAI CHARACTER DO DEK;Lo;0;L;;;;;N;THAI LETTER DO DEK;;;;
+0E15;THAI CHARACTER TO TAO;Lo;0;L;;;;;N;THAI LETTER TO TAO;;;;
+0E16;THAI CHARACTER THO THUNG;Lo;0;L;;;;;N;THAI LETTER THO THUNG;;;;
+0E17;THAI CHARACTER THO THAHAN;Lo;0;L;;;;;N;THAI LETTER THO THAHAN;;;;
+0E18;THAI CHARACTER THO THONG;Lo;0;L;;;;;N;THAI LETTER THO THONG;;;;
+0E19;THAI CHARACTER NO NU;Lo;0;L;;;;;N;THAI LETTER NO NU;;;;
+0E1A;THAI CHARACTER BO BAIMAI;Lo;0;L;;;;;N;THAI LETTER BO BAIMAI;;;;
+0E1B;THAI CHARACTER PO PLA;Lo;0;L;;;;;N;THAI LETTER PO PLA;;;;
+0E1C;THAI CHARACTER PHO PHUNG;Lo;0;L;;;;;N;THAI LETTER PHO PHUNG;;;;
+0E1D;THAI CHARACTER FO FA;Lo;0;L;;;;;N;THAI LETTER FO FA;;;;
+0E1E;THAI CHARACTER PHO PHAN;Lo;0;L;;;;;N;THAI LETTER PHO PHAN;;;;
+0E1F;THAI CHARACTER FO FAN;Lo;0;L;;;;;N;THAI LETTER FO FAN;;;;
+0E20;THAI CHARACTER PHO SAMPHAO;Lo;0;L;;;;;N;THAI LETTER PHO SAMPHAO;;;;
+0E21;THAI CHARACTER MO MA;Lo;0;L;;;;;N;THAI LETTER MO MA;;;;
+0E22;THAI CHARACTER YO YAK;Lo;0;L;;;;;N;THAI LETTER YO YAK;;;;
+0E23;THAI CHARACTER RO RUA;Lo;0;L;;;;;N;THAI LETTER RO RUA;;;;
+0E24;THAI CHARACTER RU;Lo;0;L;;;;;N;THAI LETTER RU;;;;
+0E25;THAI CHARACTER LO LING;Lo;0;L;;;;;N;THAI LETTER LO LING;;;;
+0E26;THAI CHARACTER LU;Lo;0;L;;;;;N;THAI LETTER LU;;;;
+0E27;THAI CHARACTER WO WAEN;Lo;0;L;;;;;N;THAI LETTER WO WAEN;;;;
+0E28;THAI CHARACTER SO SALA;Lo;0;L;;;;;N;THAI LETTER SO SALA;;;;
+0E29;THAI CHARACTER SO RUSI;Lo;0;L;;;;;N;THAI LETTER SO RUSI;;;;
+0E2A;THAI CHARACTER SO SUA;Lo;0;L;;;;;N;THAI LETTER SO SUA;;;;
+0E2B;THAI CHARACTER HO HIP;Lo;0;L;;;;;N;THAI LETTER HO HIP;;;;
+0E2C;THAI CHARACTER LO CHULA;Lo;0;L;;;;;N;THAI LETTER LO CHULA;;;;
+0E2D;THAI CHARACTER O ANG;Lo;0;L;;;;;N;THAI LETTER O ANG;;;;
+0E2E;THAI CHARACTER HO NOKHUK;Lo;0;L;;;;;N;THAI LETTER HO NOK HUK;;;;
+0E2F;THAI CHARACTER PAIYANNOI;Lo;0;L;;;;;N;THAI PAI YAN NOI;paiyan noi;;;
+0E30;THAI CHARACTER SARA A;Lo;0;L;;;;;N;THAI VOWEL SIGN SARA A;;;;
+0E31;THAI CHARACTER MAI HAN-AKAT;Mn;0;NSM;;;;;N;THAI VOWEL SIGN MAI HAN-AKAT;;;;
+0E32;THAI CHARACTER SARA AA;Lo;0;L;;;;;N;THAI VOWEL SIGN SARA AA;;;;
+0E33;THAI CHARACTER SARA AM;Lo;0;L;<compat> 0E4D 0E32;;;;N;THAI VOWEL SIGN SARA AM;;;;
+0E34;THAI CHARACTER SARA I;Mn;0;NSM;;;;;N;THAI VOWEL SIGN SARA I;;;;
+0E35;THAI CHARACTER SARA II;Mn;0;NSM;;;;;N;THAI VOWEL SIGN SARA II;;;;
+0E36;THAI CHARACTER SARA UE;Mn;0;NSM;;;;;N;THAI VOWEL SIGN SARA UE;;;;
+0E37;THAI CHARACTER SARA UEE;Mn;0;NSM;;;;;N;THAI VOWEL SIGN SARA UEE;sara uue;;;
+0E38;THAI CHARACTER SARA U;Mn;103;NSM;;;;;N;THAI VOWEL SIGN SARA U;;;;
+0E39;THAI CHARACTER SARA UU;Mn;103;NSM;;;;;N;THAI VOWEL SIGN SARA UU;;;;
+0E3A;THAI CHARACTER PHINTHU;Mn;9;NSM;;;;;N;THAI VOWEL SIGN PHINTHU;;;;
+0E3F;THAI CURRENCY SYMBOL BAHT;Sc;0;ET;;;;;N;THAI BAHT SIGN;;;;
+0E40;THAI CHARACTER SARA E;Lo;0;L;;;;;N;THAI VOWEL SIGN SARA E;;;;
+0E41;THAI CHARACTER SARA AE;Lo;0;L;;;;;N;THAI VOWEL SIGN SARA AE;;;;
+0E42;THAI CHARACTER SARA O;Lo;0;L;;;;;N;THAI VOWEL SIGN SARA O;;;;
+0E43;THAI CHARACTER SARA AI MAIMUAN;Lo;0;L;;;;;N;THAI VOWEL SIGN SARA MAI MUAN;sara ai mai muan;;;
+0E44;THAI CHARACTER SARA AI MAIMALAI;Lo;0;L;;;;;N;THAI VOWEL SIGN SARA MAI MALAI;sara ai mai malai;;;
+0E45;THAI CHARACTER LAKKHANGYAO;Lo;0;L;;;;;N;THAI LAK KHANG YAO;lakkhang yao;;;
+0E46;THAI CHARACTER MAIYAMOK;Lm;0;L;;;;;N;THAI MAI YAMOK;mai yamok;;;
+0E47;THAI CHARACTER MAITAIKHU;Mn;0;NSM;;;;;N;THAI VOWEL SIGN MAI TAI KHU;mai taikhu;;;
+0E48;THAI CHARACTER MAI EK;Mn;107;NSM;;;;;N;THAI TONE MAI EK;;;;
+0E49;THAI CHARACTER MAI THO;Mn;107;NSM;;;;;N;THAI TONE MAI THO;;;;
+0E4A;THAI CHARACTER MAI TRI;Mn;107;NSM;;;;;N;THAI TONE MAI TRI;;;;
+0E4B;THAI CHARACTER MAI CHATTAWA;Mn;107;NSM;;;;;N;THAI TONE MAI CHATTAWA;;;;
+0E4C;THAI CHARACTER THANTHAKHAT;Mn;0;NSM;;;;;N;THAI THANTHAKHAT;;;;
+0E4D;THAI CHARACTER NIKHAHIT;Mn;0;NSM;;;;;N;THAI NIKKHAHIT;nikkhahit;;;
+0E4E;THAI CHARACTER YAMAKKAN;Mn;0;NSM;;;;;N;THAI YAMAKKAN;;;;
+0E4F;THAI CHARACTER FONGMAN;Po;0;L;;;;;N;THAI FONGMAN;;;;
+0E50;THAI DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;;
+0E51;THAI DIGIT ONE;Nd;0;L;;1;1;1;N;;;;;
+0E52;THAI DIGIT TWO;Nd;0;L;;2;2;2;N;;;;;
+0E53;THAI DIGIT THREE;Nd;0;L;;3;3;3;N;;;;;
+0E54;THAI DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;;
+0E55;THAI DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;;
+0E56;THAI DIGIT SIX;Nd;0;L;;6;6;6;N;;;;;
+0E57;THAI DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;;
+0E58;THAI DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;;
+0E59;THAI DIGIT NINE;Nd;0;L;;9;9;9;N;;;;;
+0E5A;THAI CHARACTER ANGKHANKHU;Po;0;L;;;;;N;THAI ANGKHANKHU;;;;
+0E5B;THAI CHARACTER KHOMUT;Po;0;L;;;;;N;THAI KHOMUT;;;;
+0E81;LAO LETTER KO;Lo;0;L;;;;;N;;;;;
+0E82;LAO LETTER KHO SUNG;Lo;0;L;;;;;N;;;;;
+0E84;LAO LETTER KHO TAM;Lo;0;L;;;;;N;;;;;
+0E87;LAO LETTER NGO;Lo;0;L;;;;;N;;;;;
+0E88;LAO LETTER CO;Lo;0;L;;;;;N;;;;;
+0E8A;LAO LETTER SO TAM;Lo;0;L;;;;;N;;;;;
+0E8D;LAO LETTER NYO;Lo;0;L;;;;;N;;;;;
+0E94;LAO LETTER DO;Lo;0;L;;;;;N;;;;;
+0E95;LAO LETTER TO;Lo;0;L;;;;;N;;;;;
+0E96;LAO LETTER THO SUNG;Lo;0;L;;;;;N;;;;;
+0E97;LAO LETTER THO TAM;Lo;0;L;;;;;N;;;;;
+0E99;LAO LETTER NO;Lo;0;L;;;;;N;;;;;
+0E9A;LAO LETTER BO;Lo;0;L;;;;;N;;;;;
+0E9B;LAO LETTER PO;Lo;0;L;;;;;N;;;;;
+0E9C;LAO LETTER PHO SUNG;Lo;0;L;;;;;N;;;;;
+0E9D;LAO LETTER FO TAM;Lo;0;L;;;;;N;;;;;
+0E9E;LAO LETTER PHO TAM;Lo;0;L;;;;;N;;;;;
+0E9F;LAO LETTER FO SUNG;Lo;0;L;;;;;N;;;;;
+0EA1;LAO LETTER MO;Lo;0;L;;;;;N;;;;;
+0EA2;LAO LETTER YO;Lo;0;L;;;;;N;;;;;
+0EA3;LAO LETTER LO LING;Lo;0;L;;;;;N;;;;;
+0EA5;LAO LETTER LO LOOT;Lo;0;L;;;;;N;;;;;
+0EA7;LAO LETTER WO;Lo;0;L;;;;;N;;;;;
+0EAA;LAO LETTER SO SUNG;Lo;0;L;;;;;N;;;;;
+0EAB;LAO LETTER HO SUNG;Lo;0;L;;;;;N;;;;;
+0EAD;LAO LETTER O;Lo;0;L;;;;;N;;;;;
+0EAE;LAO LETTER HO TAM;Lo;0;L;;;;;N;;;;;
+0EAF;LAO ELLIPSIS;Lo;0;L;;;;;N;;;;;
+0EB0;LAO VOWEL SIGN A;Lo;0;L;;;;;N;;;;;
+0EB1;LAO VOWEL SIGN MAI KAN;Mn;0;NSM;;;;;N;;;;;
+0EB2;LAO VOWEL SIGN AA;Lo;0;L;;;;;N;;;;;
+0EB3;LAO VOWEL SIGN AM;Lo;0;L;<compat> 0ECD 0EB2;;;;N;;;;;
+0EB4;LAO VOWEL SIGN I;Mn;0;NSM;;;;;N;;;;;
+0EB5;LAO VOWEL SIGN II;Mn;0;NSM;;;;;N;;;;;
+0EB6;LAO VOWEL SIGN Y;Mn;0;NSM;;;;;N;;;;;
+0EB7;LAO VOWEL SIGN YY;Mn;0;NSM;;;;;N;;;;;
+0EB8;LAO VOWEL SIGN U;Mn;118;NSM;;;;;N;;;;;
+0EB9;LAO VOWEL SIGN UU;Mn;118;NSM;;;;;N;;;;;
+0EBB;LAO VOWEL SIGN MAI KON;Mn;0;NSM;;;;;N;;;;;
+0EBC;LAO SEMIVOWEL SIGN LO;Mn;0;NSM;;;;;N;;;;;
+0EBD;LAO SEMIVOWEL SIGN NYO;Lo;0;L;;;;;N;;;;;
+0EC0;LAO VOWEL SIGN E;Lo;0;L;;;;;N;;;;;
+0EC1;LAO VOWEL SIGN EI;Lo;0;L;;;;;N;;;;;
+0EC2;LAO VOWEL SIGN O;Lo;0;L;;;;;N;;;;;
+0EC3;LAO VOWEL SIGN AY;Lo;0;L;;;;;N;;;;;
+0EC4;LAO VOWEL SIGN AI;Lo;0;L;;;;;N;;;;;
+0EC6;LAO KO LA;Lm;0;L;;;;;N;;;;;
+0EC8;LAO TONE MAI EK;Mn;122;NSM;;;;;N;;;;;
+0EC9;LAO TONE MAI THO;Mn;122;NSM;;;;;N;;;;;
+0ECA;LAO TONE MAI TI;Mn;122;NSM;;;;;N;;;;;
+0ECB;LAO TONE MAI CATAWA;Mn;122;NSM;;;;;N;;;;;
+0ECC;LAO CANCELLATION MARK;Mn;0;NSM;;;;;N;;;;;
+0ECD;LAO NIGGAHITA;Mn;0;NSM;;;;;N;;;;;
+0ED0;LAO DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;;
+0ED1;LAO DIGIT ONE;Nd;0;L;;1;1;1;N;;;;;
+0ED2;LAO DIGIT TWO;Nd;0;L;;2;2;2;N;;;;;
+0ED3;LAO DIGIT THREE;Nd;0;L;;3;3;3;N;;;;;
+0ED4;LAO DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;;
+0ED5;LAO DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;;
+0ED6;LAO DIGIT SIX;Nd;0;L;;6;6;6;N;;;;;
+0ED7;LAO DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;;
+0ED8;LAO DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;;
+0ED9;LAO DIGIT NINE;Nd;0;L;;9;9;9;N;;;;;
+0EDC;LAO HO NO;Lo;0;L;<compat> 0EAB 0E99;;;;N;;;;;
+0EDD;LAO HO MO;Lo;0;L;<compat> 0EAB 0EA1;;;;N;;;;;
+0F00;TIBETAN SYLLABLE OM;Lo;0;L;;;;;N;;;;;
+0F01;TIBETAN MARK GTER YIG MGO TRUNCATED A;So;0;L;;;;;N;;ter yik go a thung;;;
+0F02;TIBETAN MARK GTER YIG MGO -UM RNAM BCAD MA;So;0;L;;;;;N;;ter yik go wum nam chey ma;;;
+0F03;TIBETAN MARK GTER YIG MGO -UM GTER TSHEG MA;So;0;L;;;;;N;;ter yik go wum ter tsek ma;;;
+0F04;TIBETAN MARK INITIAL YIG MGO MDUN MA;Po;0;L;;;;;N;TIBETAN SINGLE ORNAMENT;yik go dun ma;;;
+0F05;TIBETAN MARK CLOSING YIG MGO SGAB MA;Po;0;L;;;;;N;;yik go kab ma;;;
+0F06;TIBETAN MARK CARET YIG MGO PHUR SHAD MA;Po;0;L;;;;;N;;yik go pur shey ma;;;
+0F07;TIBETAN MARK YIG MGO TSHEG SHAD MA;Po;0;L;;;;;N;;yik go tsek shey ma;;;
+0F08;TIBETAN MARK SBRUL SHAD;Po;0;L;;;;;N;TIBETAN RGYANSHAD;drul shey;;;
+0F09;TIBETAN MARK BSKUR YIG MGO;Po;0;L;;;;;N;;kur yik go;;;
+0F0A;TIBETAN MARK BKA- SHOG YIG MGO;Po;0;L;;;;;N;;ka sho yik go;;;
+0F0B;TIBETAN MARK INTERSYLLABIC TSHEG;Po;0;L;;;;;N;TIBETAN TSEG;tsek;;;
+0F0C;TIBETAN MARK DELIMITER TSHEG BSTAR;Po;0;L;<noBreak> 0F0B;;;;N;;tsek tar;;;
+0F0D;TIBETAN MARK SHAD;Po;0;L;;;;;N;TIBETAN SHAD;shey;;;
+0F0E;TIBETAN MARK NYIS SHAD;Po;0;L;;;;;N;TIBETAN DOUBLE SHAD;nyi shey;;;
+0F0F;TIBETAN MARK TSHEG SHAD;Po;0;L;;;;;N;;tsek shey;;;
+0F10;TIBETAN MARK NYIS TSHEG SHAD;Po;0;L;;;;;N;;nyi tsek shey;;;
+0F11;TIBETAN MARK RIN CHEN SPUNGS SHAD;Po;0;L;;;;;N;TIBETAN RINCHANPHUNGSHAD;rinchen pung shey;;;
+0F12;TIBETAN MARK RGYA GRAM SHAD;Po;0;L;;;;;N;;gya tram shey;;;
+0F13;TIBETAN MARK CARET -DZUD RTAGS ME LONG CAN;So;0;L;;;;;N;;dzu ta me long chen;;;
+0F14;TIBETAN MARK GTER TSHEG;So;0;L;;;;;N;TIBETAN COMMA;ter tsek;;;
+0F15;TIBETAN LOGOTYPE SIGN CHAD RTAGS;So;0;L;;;;;N;;che ta;;;
+0F16;TIBETAN LOGOTYPE SIGN LHAG RTAGS;So;0;L;;;;;N;;hlak ta;;;
+0F17;TIBETAN ASTROLOGICAL SIGN SGRA GCAN -CHAR RTAGS;So;0;L;;;;;N;;trachen char ta;;;
+0F18;TIBETAN ASTROLOGICAL SIGN -KHYUD PA;Mn;220;NSM;;;;;N;;kyu pa;;;
+0F19;TIBETAN ASTROLOGICAL SIGN SDONG TSHUGS;Mn;220;NSM;;;;;N;;dong tsu;;;
+0F1A;TIBETAN SIGN RDEL DKAR GCIG;So;0;L;;;;;N;;deka chig;;;
+0F1B;TIBETAN SIGN RDEL DKAR GNYIS;So;0;L;;;;;N;;deka nyi;;;
+0F1C;TIBETAN SIGN RDEL DKAR GSUM;So;0;L;;;;;N;;deka sum;;;
+0F1D;TIBETAN SIGN RDEL NAG GCIG;So;0;L;;;;;N;;dena chig;;;
+0F1E;TIBETAN SIGN RDEL NAG GNYIS;So;0;L;;;;;N;;dena nyi;;;
+0F1F;TIBETAN SIGN RDEL DKAR RDEL NAG;So;0;L;;;;;N;;deka dena;;;
+0F20;TIBETAN DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;;
+0F21;TIBETAN DIGIT ONE;Nd;0;L;;1;1;1;N;;;;;
+0F22;TIBETAN DIGIT TWO;Nd;0;L;;2;2;2;N;;;;;
+0F23;TIBETAN DIGIT THREE;Nd;0;L;;3;3;3;N;;;;;
+0F24;TIBETAN DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;;
+0F25;TIBETAN DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;;
+0F26;TIBETAN DIGIT SIX;Nd;0;L;;6;6;6;N;;;;;
+0F27;TIBETAN DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;;
+0F28;TIBETAN DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;;
+0F29;TIBETAN DIGIT NINE;Nd;0;L;;9;9;9;N;;;;;
+0F2A;TIBETAN DIGIT HALF ONE;No;0;L;;;;1/2;N;;;;;
+0F2B;TIBETAN DIGIT HALF TWO;No;0;L;;;;3/2;N;;;;;
+0F2C;TIBETAN DIGIT HALF THREE;No;0;L;;;;5/2;N;;;;;
+0F2D;TIBETAN DIGIT HALF FOUR;No;0;L;;;;7/2;N;;;;;
+0F2E;TIBETAN DIGIT HALF FIVE;No;0;L;;;;9/2;N;;;;;
+0F2F;TIBETAN DIGIT HALF SIX;No;0;L;;;;11/2;N;;;;;
+0F30;TIBETAN DIGIT HALF SEVEN;No;0;L;;;;13/2;N;;;;;
+0F31;TIBETAN DIGIT HALF EIGHT;No;0;L;;;;15/2;N;;;;;
+0F32;TIBETAN DIGIT HALF NINE;No;0;L;;;;17/2;N;;;;;
+0F33;TIBETAN DIGIT HALF ZERO;No;0;L;;;;-1/2;N;;;;;
+0F34;TIBETAN MARK BSDUS RTAGS;So;0;L;;;;;N;;du ta;;;
+0F35;TIBETAN MARK NGAS BZUNG NYI ZLA;Mn;220;NSM;;;;;N;TIBETAN HONORIFIC UNDER RING;nge zung nyi da;;;
+0F36;TIBETAN MARK CARET -DZUD RTAGS BZHI MIG CAN;So;0;L;;;;;N;;dzu ta shi mig chen;;;
+0F37;TIBETAN MARK NGAS BZUNG SGOR RTAGS;Mn;220;NSM;;;;;N;TIBETAN UNDER RING;nge zung gor ta;;;
+0F38;TIBETAN MARK CHE MGO;So;0;L;;;;;N;;che go;;;
+0F39;TIBETAN MARK TSA -PHRU;Mn;216;NSM;;;;;N;TIBETAN LENITION MARK;tsa tru;;;
+0F3A;TIBETAN MARK GUG RTAGS GYON;Ps;0;ON;;;;;N;;gug ta yun;;;
+0F3B;TIBETAN MARK GUG RTAGS GYAS;Pe;0;ON;;;;;N;;gug ta ye;;;
+0F3C;TIBETAN MARK ANG KHANG GYON;Ps;0;ON;;;;;N;TIBETAN LEFT BRACE;ang kang yun;;;
+0F3D;TIBETAN MARK ANG KHANG GYAS;Pe;0;ON;;;;;N;TIBETAN RIGHT BRACE;ang kang ye;;;
+0F3E;TIBETAN SIGN YAR TSHES;Mc;0;L;;;;;N;;yar tse;;;
+0F3F;TIBETAN SIGN MAR TSHES;Mc;0;L;;;;;N;;mar tse;;;
+0F40;TIBETAN LETTER KA;Lo;0;L;;;;;N;;;;;
+0F41;TIBETAN LETTER KHA;Lo;0;L;;;;;N;;;;;
+0F42;TIBETAN LETTER GA;Lo;0;L;;;;;N;;;;;
+0F43;TIBETAN LETTER GHA;Lo;0;L;0F42 0FB7;;;;N;;;;;
+0F44;TIBETAN LETTER NGA;Lo;0;L;;;;;N;;;;;
+0F45;TIBETAN LETTER CA;Lo;0;L;;;;;N;;;;;
+0F46;TIBETAN LETTER CHA;Lo;0;L;;;;;N;;;;;
+0F47;TIBETAN LETTER JA;Lo;0;L;;;;;N;;;;;
+0F49;TIBETAN LETTER NYA;Lo;0;L;;;;;N;;;;;
+0F4A;TIBETAN LETTER TTA;Lo;0;L;;;;;N;TIBETAN LETTER REVERSED TA;;;;
+0F4B;TIBETAN LETTER TTHA;Lo;0;L;;;;;N;TIBETAN LETTER REVERSED THA;;;;
+0F4C;TIBETAN LETTER DDA;Lo;0;L;;;;;N;TIBETAN LETTER REVERSED DA;;;;
+0F4D;TIBETAN LETTER DDHA;Lo;0;L;0F4C 0FB7;;;;N;;;;;
+0F4E;TIBETAN LETTER NNA;Lo;0;L;;;;;N;TIBETAN LETTER REVERSED NA;;;;
+0F4F;TIBETAN LETTER TA;Lo;0;L;;;;;N;;;;;
+0F50;TIBETAN LETTER THA;Lo;0;L;;;;;N;;;;;
+0F51;TIBETAN LETTER DA;Lo;0;L;;;;;N;;;;;
+0F52;TIBETAN LETTER DHA;Lo;0;L;0F51 0FB7;;;;N;;;;;
+0F53;TIBETAN LETTER NA;Lo;0;L;;;;;N;;;;;
+0F54;TIBETAN LETTER PA;Lo;0;L;;;;;N;;;;;
+0F55;TIBETAN LETTER PHA;Lo;0;L;;;;;N;;;;;
+0F56;TIBETAN LETTER BA;Lo;0;L;;;;;N;;;;;
+0F57;TIBETAN LETTER BHA;Lo;0;L;0F56 0FB7;;;;N;;;;;
+0F58;TIBETAN LETTER MA;Lo;0;L;;;;;N;;;;;
+0F59;TIBETAN LETTER TSA;Lo;0;L;;;;;N;;;;;
+0F5A;TIBETAN LETTER TSHA;Lo;0;L;;;;;N;;;;;
+0F5B;TIBETAN LETTER DZA;Lo;0;L;;;;;N;;;;;
+0F5C;TIBETAN LETTER DZHA;Lo;0;L;0F5B 0FB7;;;;N;;;;;
+0F5D;TIBETAN LETTER WA;Lo;0;L;;;;;N;;;;;
+0F5E;TIBETAN LETTER ZHA;Lo;0;L;;;;;N;;;;;
+0F5F;TIBETAN LETTER ZA;Lo;0;L;;;;;N;;;;;
+0F60;TIBETAN LETTER -A;Lo;0;L;;;;;N;TIBETAN LETTER AA;;;;
+0F61;TIBETAN LETTER YA;Lo;0;L;;;;;N;;;;;
+0F62;TIBETAN LETTER RA;Lo;0;L;;;;;N;;*;;;
+0F63;TIBETAN LETTER LA;Lo;0;L;;;;;N;;;;;
+0F64;TIBETAN LETTER SHA;Lo;0;L;;;;;N;;;;;
+0F65;TIBETAN LETTER SSA;Lo;0;L;;;;;N;TIBETAN LETTER REVERSED SHA;;;;
+0F66;TIBETAN LETTER SA;Lo;0;L;;;;;N;;;;;
+0F67;TIBETAN LETTER HA;Lo;0;L;;;;;N;;;;;
+0F68;TIBETAN LETTER A;Lo;0;L;;;;;N;;;;;
+0F69;TIBETAN LETTER KSSA;Lo;0;L;0F40 0FB5;;;;N;;;;;
+0F6A;TIBETAN LETTER FIXED-FORM RA;Lo;0;L;;;;;N;;*;;;
+0F71;TIBETAN VOWEL SIGN AA;Mn;129;NSM;;;;;N;;;;;
+0F72;TIBETAN VOWEL SIGN I;Mn;130;NSM;;;;;N;;;;;
+0F73;TIBETAN VOWEL SIGN II;Mn;0;NSM;0F71 0F72;;;;N;;;;;
+0F74;TIBETAN VOWEL SIGN U;Mn;132;NSM;;;;;N;;;;;
+0F75;TIBETAN VOWEL SIGN UU;Mn;0;NSM;0F71 0F74;;;;N;;;;;
+0F76;TIBETAN VOWEL SIGN VOCALIC R;Mn;0;NSM;0FB2 0F80;;;;N;;;;;
+0F77;TIBETAN VOWEL SIGN VOCALIC RR;Mn;0;NSM;<compat> 0FB2 0F81;;;;N;;;;;
+0F78;TIBETAN VOWEL SIGN VOCALIC L;Mn;0;NSM;0FB3 0F80;;;;N;;;;;
+0F79;TIBETAN VOWEL SIGN VOCALIC LL;Mn;0;NSM;<compat> 0FB3 0F81;;;;N;;;;;
+0F7A;TIBETAN VOWEL SIGN E;Mn;130;NSM;;;;;N;;;;;
+0F7B;TIBETAN VOWEL SIGN EE;Mn;130;NSM;;;;;N;TIBETAN VOWEL SIGN AI;;;;
+0F7C;TIBETAN VOWEL SIGN O;Mn;130;NSM;;;;;N;;;;;
+0F7D;TIBETAN VOWEL SIGN OO;Mn;130;NSM;;;;;N;TIBETAN VOWEL SIGN AU;;;;
+0F7E;TIBETAN SIGN RJES SU NGA RO;Mn;0;NSM;;;;;N;TIBETAN ANUSVARA;je su nga ro;;;
+0F7F;TIBETAN SIGN RNAM BCAD;Mc;0;L;;;;;N;TIBETAN VISARGA;nam chey;;;
+0F80;TIBETAN VOWEL SIGN REVERSED I;Mn;130;NSM;;;;;N;TIBETAN VOWEL SIGN SHORT I;;;;
+0F81;TIBETAN VOWEL SIGN REVERSED II;Mn;0;NSM;0F71 0F80;;;;N;;;;;
+0F82;TIBETAN SIGN NYI ZLA NAA DA;Mn;230;NSM;;;;;N;TIBETAN CANDRABINDU WITH ORNAMENT;nyi da na da;;;
+0F83;TIBETAN SIGN SNA LDAN;Mn;230;NSM;;;;;N;TIBETAN CANDRABINDU;nan de;;;
+0F84;TIBETAN MARK HALANTA;Mn;9;NSM;;;;;N;TIBETAN VIRAMA;;;;
+0F85;TIBETAN MARK PALUTA;Po;0;L;;;;;N;TIBETAN CHUCHENYIGE;;;;
+0F86;TIBETAN SIGN LCI RTAGS;Mn;230;NSM;;;;;N;;ji ta;;;
+0F87;TIBETAN SIGN YANG RTAGS;Mn;230;NSM;;;;;N;;yang ta;;;
+0F88;TIBETAN SIGN LCE TSA CAN;Lo;0;L;;;;;N;;che tsa chen;;;
+0F89;TIBETAN SIGN MCHU CAN;Lo;0;L;;;;;N;;chu chen;;;
+0F8A;TIBETAN SIGN GRU CAN RGYINGS;Lo;0;L;;;;;N;;tru chen ging;;;
+0F8B;TIBETAN SIGN GRU MED RGYINGS;Lo;0;L;;;;;N;;tru me ging;;;
+0F90;TIBETAN SUBJOINED LETTER KA;Mn;0;NSM;;;;;N;;;;;
+0F91;TIBETAN SUBJOINED LETTER KHA;Mn;0;NSM;;;;;N;;;;;
+0F92;TIBETAN SUBJOINED LETTER GA;Mn;0;NSM;;;;;N;;;;;
+0F93;TIBETAN SUBJOINED LETTER GHA;Mn;0;NSM;0F92 0FB7;;;;N;;;;;
+0F94;TIBETAN SUBJOINED LETTER NGA;Mn;0;NSM;;;;;N;;;;;
+0F95;TIBETAN SUBJOINED LETTER CA;Mn;0;NSM;;;;;N;;;;;
+0F96;TIBETAN SUBJOINED LETTER CHA;Mn;0;NSM;;;;;N;;;;;
+0F97;TIBETAN SUBJOINED LETTER JA;Mn;0;NSM;;;;;N;;;;;
+0F99;TIBETAN SUBJOINED LETTER NYA;Mn;0;NSM;;;;;N;;;;;
+0F9A;TIBETAN SUBJOINED LETTER TTA;Mn;0;NSM;;;;;N;;;;;
+0F9B;TIBETAN SUBJOINED LETTER TTHA;Mn;0;NSM;;;;;N;;;;;
+0F9C;TIBETAN SUBJOINED LETTER DDA;Mn;0;NSM;;;;;N;;;;;
+0F9D;TIBETAN SUBJOINED LETTER DDHA;Mn;0;NSM;0F9C 0FB7;;;;N;;;;;
+0F9E;TIBETAN SUBJOINED LETTER NNA;Mn;0;NSM;;;;;N;;;;;
+0F9F;TIBETAN SUBJOINED LETTER TA;Mn;0;NSM;;;;;N;;;;;
+0FA0;TIBETAN SUBJOINED LETTER THA;Mn;0;NSM;;;;;N;;;;;
+0FA1;TIBETAN SUBJOINED LETTER DA;Mn;0;NSM;;;;;N;;;;;
+0FA2;TIBETAN SUBJOINED LETTER DHA;Mn;0;NSM;0FA1 0FB7;;;;N;;;;;
+0FA3;TIBETAN SUBJOINED LETTER NA;Mn;0;NSM;;;;;N;;;;;
+0FA4;TIBETAN SUBJOINED LETTER PA;Mn;0;NSM;;;;;N;;;;;
+0FA5;TIBETAN SUBJOINED LETTER PHA;Mn;0;NSM;;;;;N;;;;;
+0FA6;TIBETAN SUBJOINED LETTER BA;Mn;0;NSM;;;;;N;;;;;
+0FA7;TIBETAN SUBJOINED LETTER BHA;Mn;0;NSM;0FA6 0FB7;;;;N;;;;;
+0FA8;TIBETAN SUBJOINED LETTER MA;Mn;0;NSM;;;;;N;;;;;
+0FA9;TIBETAN SUBJOINED LETTER TSA;Mn;0;NSM;;;;;N;;;;;
+0FAA;TIBETAN SUBJOINED LETTER TSHA;Mn;0;NSM;;;;;N;;;;;
+0FAB;TIBETAN SUBJOINED LETTER DZA;Mn;0;NSM;;;;;N;;;;;
+0FAC;TIBETAN SUBJOINED LETTER DZHA;Mn;0;NSM;0FAB 0FB7;;;;N;;;;;
+0FAD;TIBETAN SUBJOINED LETTER WA;Mn;0;NSM;;;;;N;;*;;;
+0FAE;TIBETAN SUBJOINED LETTER ZHA;Mn;0;NSM;;;;;N;;;;;
+0FAF;TIBETAN SUBJOINED LETTER ZA;Mn;0;NSM;;;;;N;;;;;
+0FB0;TIBETAN SUBJOINED LETTER -A;Mn;0;NSM;;;;;N;;;;;
+0FB1;TIBETAN SUBJOINED LETTER YA;Mn;0;NSM;;;;;N;;*;;;
+0FB2;TIBETAN SUBJOINED LETTER RA;Mn;0;NSM;;;;;N;;*;;;
+0FB3;TIBETAN SUBJOINED LETTER LA;Mn;0;NSM;;;;;N;;;;;
+0FB4;TIBETAN SUBJOINED LETTER SHA;Mn;0;NSM;;;;;N;;;;;
+0FB5;TIBETAN SUBJOINED LETTER SSA;Mn;0;NSM;;;;;N;;;;;
+0FB6;TIBETAN SUBJOINED LETTER SA;Mn;0;NSM;;;;;N;;;;;
+0FB7;TIBETAN SUBJOINED LETTER HA;Mn;0;NSM;;;;;N;;;;;
+0FB8;TIBETAN SUBJOINED LETTER A;Mn;0;NSM;;;;;N;;;;;
+0FB9;TIBETAN SUBJOINED LETTER KSSA;Mn;0;NSM;0F90 0FB5;;;;N;;;;;
+0FBA;TIBETAN SUBJOINED LETTER FIXED-FORM WA;Mn;0;NSM;;;;;N;;*;;;
+0FBB;TIBETAN SUBJOINED LETTER FIXED-FORM YA;Mn;0;NSM;;;;;N;;*;;;
+0FBC;TIBETAN SUBJOINED LETTER FIXED-FORM RA;Mn;0;NSM;;;;;N;;*;;;
+0FBE;TIBETAN KU RU KHA;So;0;L;;;;;N;;kuruka;;;
+0FBF;TIBETAN KU RU KHA BZHI MIG CAN;So;0;L;;;;;N;;kuruka shi mik chen;;;
+0FC0;TIBETAN CANTILLATION SIGN HEAVY BEAT;So;0;L;;;;;N;;;;;
+0FC1;TIBETAN CANTILLATION SIGN LIGHT BEAT;So;0;L;;;;;N;;;;;
+0FC2;TIBETAN CANTILLATION SIGN CANG TE-U;So;0;L;;;;;N;;chang tyu;;;
+0FC3;TIBETAN CANTILLATION SIGN SBUB -CHAL;So;0;L;;;;;N;;bub chey;;;
+0FC4;TIBETAN SYMBOL DRIL BU;So;0;L;;;;;N;;drilbu;;;
+0FC5;TIBETAN SYMBOL RDO RJE;So;0;L;;;;;N;;dorje;;;
+0FC6;TIBETAN SYMBOL PADMA GDAN;Mn;220;NSM;;;;;N;;pema den;;;
+0FC7;TIBETAN SYMBOL RDO RJE RGYA GRAM;So;0;L;;;;;N;;dorje gya dram;;;
+0FC8;TIBETAN SYMBOL PHUR PA;So;0;L;;;;;N;;phurba;;;
+0FC9;TIBETAN SYMBOL NOR BU;So;0;L;;;;;N;;norbu;;;
+0FCA;TIBETAN SYMBOL NOR BU NYIS -KHYIL;So;0;L;;;;;N;;norbu nyi khyi;;;
+0FCB;TIBETAN SYMBOL NOR BU GSUM -KHYIL;So;0;L;;;;;N;;norbu sum khyi;;;
+0FCC;TIBETAN SYMBOL NOR BU BZHI -KHYIL;So;0;L;;;;;N;;norbu shi khyi;;;
+0FCF;TIBETAN SIGN RDEL NAG GSUM;So;0;L;;;;;N;;dena sum;;;
+0FD0;TIBETAN MARK BSKA- SHOG GI MGO RGYAN;Po;0;L;;;;;N;;ka shog gi go gyen;;;
+0FD1;TIBETAN MARK MNYAM YIG GI MGO RGYAN;Po;0;L;;;;;N;;nyam yig gi go gyen;;;
+1000;MYANMAR LETTER KA;Lo;0;L;;;;;N;;;;;
+1001;MYANMAR LETTER KHA;Lo;0;L;;;;;N;;;;;
+1002;MYANMAR LETTER GA;Lo;0;L;;;;;N;;;;;
+1003;MYANMAR LETTER GHA;Lo;0;L;;;;;N;;;;;
+1004;MYANMAR LETTER NGA;Lo;0;L;;;;;N;;;;;
+1005;MYANMAR LETTER CA;Lo;0;L;;;;;N;;;;;
+1006;MYANMAR LETTER CHA;Lo;0;L;;;;;N;;;;;
+1007;MYANMAR LETTER JA;Lo;0;L;;;;;N;;;;;
+1008;MYANMAR LETTER JHA;Lo;0;L;;;;;N;;;;;
+1009;MYANMAR LETTER NYA;Lo;0;L;;;;;N;;;;;
+100A;MYANMAR LETTER NNYA;Lo;0;L;;;;;N;;;;;
+100B;MYANMAR LETTER TTA;Lo;0;L;;;;;N;;;;;
+100C;MYANMAR LETTER TTHA;Lo;0;L;;;;;N;;;;;
+100D;MYANMAR LETTER DDA;Lo;0;L;;;;;N;;;;;
+100E;MYANMAR LETTER DDHA;Lo;0;L;;;;;N;;;;;
+100F;MYANMAR LETTER NNA;Lo;0;L;;;;;N;;;;;
+1010;MYANMAR LETTER TA;Lo;0;L;;;;;N;;;;;
+1011;MYANMAR LETTER THA;Lo;0;L;;;;;N;;;;;
+1012;MYANMAR LETTER DA;Lo;0;L;;;;;N;;;;;
+1013;MYANMAR LETTER DHA;Lo;0;L;;;;;N;;;;;
+1014;MYANMAR LETTER NA;Lo;0;L;;;;;N;;;;;
+1015;MYANMAR LETTER PA;Lo;0;L;;;;;N;;;;;
+1016;MYANMAR LETTER PHA;Lo;0;L;;;;;N;;;;;
+1017;MYANMAR LETTER BA;Lo;0;L;;;;;N;;;;;
+1018;MYANMAR LETTER BHA;Lo;0;L;;;;;N;;;;;
+1019;MYANMAR LETTER MA;Lo;0;L;;;;;N;;;;;
+101A;MYANMAR LETTER YA;Lo;0;L;;;;;N;;;;;
+101B;MYANMAR LETTER RA;Lo;0;L;;;;;N;;;;;
+101C;MYANMAR LETTER LA;Lo;0;L;;;;;N;;;;;
+101D;MYANMAR LETTER WA;Lo;0;L;;;;;N;;;;;
+101E;MYANMAR LETTER SA;Lo;0;L;;;;;N;;;;;
+101F;MYANMAR LETTER HA;Lo;0;L;;;;;N;;;;;
+1020;MYANMAR LETTER LLA;Lo;0;L;;;;;N;;;;;
+1021;MYANMAR LETTER A;Lo;0;L;;;;;N;;;;;
+1023;MYANMAR LETTER I;Lo;0;L;;;;;N;;;;;
+1024;MYANMAR LETTER II;Lo;0;L;;;;;N;;;;;
+1025;MYANMAR LETTER U;Lo;0;L;;;;;N;;;;;
+1026;MYANMAR LETTER UU;Lo;0;L;1025 102E;;;;N;;;;;
+1027;MYANMAR LETTER E;Lo;0;L;;;;;N;;;;;
+1029;MYANMAR LETTER O;Lo;0;L;;;;;N;;;;;
+102A;MYANMAR LETTER AU;Lo;0;L;;;;;N;;;;;
+102C;MYANMAR VOWEL SIGN AA;Mc;0;L;;;;;N;;;;;
+102D;MYANMAR VOWEL SIGN I;Mn;0;NSM;;;;;N;;;;;
+102E;MYANMAR VOWEL SIGN II;Mn;0;NSM;;;;;N;;;;;
+102F;MYANMAR VOWEL SIGN U;Mn;0;NSM;;;;;N;;;;;
+1030;MYANMAR VOWEL SIGN UU;Mn;0;NSM;;;;;N;;;;;
+1031;MYANMAR VOWEL SIGN E;Mc;0;L;;;;;N;;;;;
+1032;MYANMAR VOWEL SIGN AI;Mn;0;NSM;;;;;N;;;;;
+1036;MYANMAR SIGN ANUSVARA;Mn;0;NSM;;;;;N;;;;;
+1037;MYANMAR SIGN DOT BELOW;Mn;7;NSM;;;;;N;;;;;
+1038;MYANMAR SIGN VISARGA;Mc;0;L;;;;;N;;;;;
+1039;MYANMAR SIGN VIRAMA;Mn;9;NSM;;;;;N;;;;;
+1040;MYANMAR DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;;
+1041;MYANMAR DIGIT ONE;Nd;0;L;;1;1;1;N;;;;;
+1042;MYANMAR DIGIT TWO;Nd;0;L;;2;2;2;N;;;;;
+1043;MYANMAR DIGIT THREE;Nd;0;L;;3;3;3;N;;;;;
+1044;MYANMAR DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;;
+1045;MYANMAR DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;;
+1046;MYANMAR DIGIT SIX;Nd;0;L;;6;6;6;N;;;;;
+1047;MYANMAR DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;;
+1048;MYANMAR DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;;
+1049;MYANMAR DIGIT NINE;Nd;0;L;;9;9;9;N;;;;;
+104A;MYANMAR SIGN LITTLE SECTION;Po;0;L;;;;;N;;;;;
+104B;MYANMAR SIGN SECTION;Po;0;L;;;;;N;;;;;
+104C;MYANMAR SYMBOL LOCATIVE;Po;0;L;;;;;N;;;;;
+104D;MYANMAR SYMBOL COMPLETED;Po;0;L;;;;;N;;;;;
+104E;MYANMAR SYMBOL AFOREMENTIONED;Po;0;L;;;;;N;;;;;
+104F;MYANMAR SYMBOL GENITIVE;Po;0;L;;;;;N;;;;;
+1050;MYANMAR LETTER SHA;Lo;0;L;;;;;N;;;;;
+1051;MYANMAR LETTER SSA;Lo;0;L;;;;;N;;;;;
+1052;MYANMAR LETTER VOCALIC R;Lo;0;L;;;;;N;;;;;
+1053;MYANMAR LETTER VOCALIC RR;Lo;0;L;;;;;N;;;;;
+1054;MYANMAR LETTER VOCALIC L;Lo;0;L;;;;;N;;;;;
+1055;MYANMAR LETTER VOCALIC LL;Lo;0;L;;;;;N;;;;;
+1056;MYANMAR VOWEL SIGN VOCALIC R;Mc;0;L;;;;;N;;;;;
+1057;MYANMAR VOWEL SIGN VOCALIC RR;Mc;0;L;;;;;N;;;;;
+1058;MYANMAR VOWEL SIGN VOCALIC L;Mn;0;NSM;;;;;N;;;;;
+1059;MYANMAR VOWEL SIGN VOCALIC LL;Mn;0;NSM;;;;;N;;;;;
+10A0;GEORGIAN CAPITAL LETTER AN;Lu;0;L;;;;;N;;Khutsuri;;2D00;
+10A1;GEORGIAN CAPITAL LETTER BAN;Lu;0;L;;;;;N;;Khutsuri;;2D01;
+10A2;GEORGIAN CAPITAL LETTER GAN;Lu;0;L;;;;;N;;Khutsuri;;2D02;
+10A3;GEORGIAN CAPITAL LETTER DON;Lu;0;L;;;;;N;;Khutsuri;;2D03;
+10A4;GEORGIAN CAPITAL LETTER EN;Lu;0;L;;;;;N;;Khutsuri;;2D04;
+10A5;GEORGIAN CAPITAL LETTER VIN;Lu;0;L;;;;;N;;Khutsuri;;2D05;
+10A6;GEORGIAN CAPITAL LETTER ZEN;Lu;0;L;;;;;N;;Khutsuri;;2D06;
+10A7;GEORGIAN CAPITAL LETTER TAN;Lu;0;L;;;;;N;;Khutsuri;;2D07;
+10A8;GEORGIAN CAPITAL LETTER IN;Lu;0;L;;;;;N;;Khutsuri;;2D08;
+10A9;GEORGIAN CAPITAL LETTER KAN;Lu;0;L;;;;;N;;Khutsuri;;2D09;
+10AA;GEORGIAN CAPITAL LETTER LAS;Lu;0;L;;;;;N;;Khutsuri;;2D0A;
+10AB;GEORGIAN CAPITAL LETTER MAN;Lu;0;L;;;;;N;;Khutsuri;;2D0B;
+10AC;GEORGIAN CAPITAL LETTER NAR;Lu;0;L;;;;;N;;Khutsuri;;2D0C;
+10AD;GEORGIAN CAPITAL LETTER ON;Lu;0;L;;;;;N;;Khutsuri;;2D0D;
+10AE;GEORGIAN CAPITAL LETTER PAR;Lu;0;L;;;;;N;;Khutsuri;;2D0E;
+10AF;GEORGIAN CAPITAL LETTER ZHAR;Lu;0;L;;;;;N;;Khutsuri;;2D0F;
+10B0;GEORGIAN CAPITAL LETTER RAE;Lu;0;L;;;;;N;;Khutsuri;;2D10;
+10B1;GEORGIAN CAPITAL LETTER SAN;Lu;0;L;;;;;N;;Khutsuri;;2D11;
+10B2;GEORGIAN CAPITAL LETTER TAR;Lu;0;L;;;;;N;;Khutsuri;;2D12;
+10B3;GEORGIAN CAPITAL LETTER UN;Lu;0;L;;;;;N;;Khutsuri;;2D13;
+10B4;GEORGIAN CAPITAL LETTER PHAR;Lu;0;L;;;;;N;;Khutsuri;;2D14;
+10B5;GEORGIAN CAPITAL LETTER KHAR;Lu;0;L;;;;;N;;Khutsuri;;2D15;
+10B6;GEORGIAN CAPITAL LETTER GHAN;Lu;0;L;;;;;N;;Khutsuri;;2D16;
+10B7;GEORGIAN CAPITAL LETTER QAR;Lu;0;L;;;;;N;;Khutsuri;;2D17;
+10B8;GEORGIAN CAPITAL LETTER SHIN;Lu;0;L;;;;;N;;Khutsuri;;2D18;
+10B9;GEORGIAN CAPITAL LETTER CHIN;Lu;0;L;;;;;N;;Khutsuri;;2D19;
+10BA;GEORGIAN CAPITAL LETTER CAN;Lu;0;L;;;;;N;;Khutsuri;;2D1A;
+10BB;GEORGIAN CAPITAL LETTER JIL;Lu;0;L;;;;;N;;Khutsuri;;2D1B;
+10BC;GEORGIAN CAPITAL LETTER CIL;Lu;0;L;;;;;N;;Khutsuri;;2D1C;
+10BD;GEORGIAN CAPITAL LETTER CHAR;Lu;0;L;;;;;N;;Khutsuri;;2D1D;
+10BE;GEORGIAN CAPITAL LETTER XAN;Lu;0;L;;;;;N;;Khutsuri;;2D1E;
+10BF;GEORGIAN CAPITAL LETTER JHAN;Lu;0;L;;;;;N;;Khutsuri;;2D1F;
+10C0;GEORGIAN CAPITAL LETTER HAE;Lu;0;L;;;;;N;;Khutsuri;;2D20;
+10C1;GEORGIAN CAPITAL LETTER HE;Lu;0;L;;;;;N;;Khutsuri;;2D21;
+10C2;GEORGIAN CAPITAL LETTER HIE;Lu;0;L;;;;;N;;Khutsuri;;2D22;
+10C3;GEORGIAN CAPITAL LETTER WE;Lu;0;L;;;;;N;;Khutsuri;;2D23;
+10C4;GEORGIAN CAPITAL LETTER HAR;Lu;0;L;;;;;N;;Khutsuri;;2D24;
+10C5;GEORGIAN CAPITAL LETTER HOE;Lu;0;L;;;;;N;;Khutsuri;;2D25;
+10D0;GEORGIAN LETTER AN;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER AN;;;;
+10D1;GEORGIAN LETTER BAN;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER BAN;;;;
+10D2;GEORGIAN LETTER GAN;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER GAN;;;;
+10D3;GEORGIAN LETTER DON;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER DON;;;;
+10D4;GEORGIAN LETTER EN;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER EN;;;;
+10D5;GEORGIAN LETTER VIN;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER VIN;;;;
+10D6;GEORGIAN LETTER ZEN;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER ZEN;;;;
+10D7;GEORGIAN LETTER TAN;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER TAN;;;;
+10D8;GEORGIAN LETTER IN;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER IN;;;;
+10D9;GEORGIAN LETTER KAN;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER KAN;;;;
+10DA;GEORGIAN LETTER LAS;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER LAS;;;;
+10DB;GEORGIAN LETTER MAN;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER MAN;;;;
+10DC;GEORGIAN LETTER NAR;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER NAR;;;;
+10DD;GEORGIAN LETTER ON;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER ON;;;;
+10DE;GEORGIAN LETTER PAR;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER PAR;;;;
+10DF;GEORGIAN LETTER ZHAR;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER ZHAR;;;;
+10E0;GEORGIAN LETTER RAE;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER RAE;;;;
+10E1;GEORGIAN LETTER SAN;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER SAN;;;;
+10E2;GEORGIAN LETTER TAR;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER TAR;;;;
+10E3;GEORGIAN LETTER UN;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER UN;;;;
+10E4;GEORGIAN LETTER PHAR;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER PHAR;;;;
+10E5;GEORGIAN LETTER KHAR;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER KHAR;;;;
+10E6;GEORGIAN LETTER GHAN;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER GHAN;;;;
+10E7;GEORGIAN LETTER QAR;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER QAR;;;;
+10E8;GEORGIAN LETTER SHIN;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER SHIN;;;;
+10E9;GEORGIAN LETTER CHIN;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER CHIN;;;;
+10EA;GEORGIAN LETTER CAN;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER CAN;;;;
+10EB;GEORGIAN LETTER JIL;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER JIL;;;;
+10EC;GEORGIAN LETTER CIL;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER CIL;;;;
+10ED;GEORGIAN LETTER CHAR;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER CHAR;;;;
+10EE;GEORGIAN LETTER XAN;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER XAN;;;;
+10EF;GEORGIAN LETTER JHAN;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER JHAN;;;;
+10F0;GEORGIAN LETTER HAE;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER HAE;;;;
+10F1;GEORGIAN LETTER HE;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER HE;;;;
+10F2;GEORGIAN LETTER HIE;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER HIE;;;;
+10F3;GEORGIAN LETTER WE;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER WE;;;;
+10F4;GEORGIAN LETTER HAR;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER HAR;;;;
+10F5;GEORGIAN LETTER HOE;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER HOE;;;;
+10F6;GEORGIAN LETTER FI;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER FI;;;;
+10F7;GEORGIAN LETTER YN;Lo;0;L;;;;;N;;;;;
+10F8;GEORGIAN LETTER ELIFI;Lo;0;L;;;;;N;;;;;
+10F9;GEORGIAN LETTER TURNED GAN;Lo;0;L;;;;;N;;;;;
+10FA;GEORGIAN LETTER AIN;Lo;0;L;;;;;N;;;;;
+10FB;GEORGIAN PARAGRAPH SEPARATOR;Po;0;L;;;;;N;;;;;
+10FC;MODIFIER LETTER GEORGIAN NAR;Lm;0;L;<super> 10DC;;;;N;;;;;
+1100;HANGUL CHOSEONG KIYEOK;Lo;0;L;;;;;N;;g *;;;
+1101;HANGUL CHOSEONG SSANGKIYEOK;Lo;0;L;;;;;N;;gg *;;;
+1102;HANGUL CHOSEONG NIEUN;Lo;0;L;;;;;N;;n *;;;
+1103;HANGUL CHOSEONG TIKEUT;Lo;0;L;;;;;N;;d *;;;
+1104;HANGUL CHOSEONG SSANGTIKEUT;Lo;0;L;;;;;N;;dd *;;;
+1105;HANGUL CHOSEONG RIEUL;Lo;0;L;;;;;N;;r *;;;
+1106;HANGUL CHOSEONG MIEUM;Lo;0;L;;;;;N;;m *;;;
+1107;HANGUL CHOSEONG PIEUP;Lo;0;L;;;;;N;;b *;;;
+1108;HANGUL CHOSEONG SSANGPIEUP;Lo;0;L;;;;;N;;bb *;;;
+1109;HANGUL CHOSEONG SIOS;Lo;0;L;;;;;N;;s *;;;
+110A;HANGUL CHOSEONG SSANGSIOS;Lo;0;L;;;;;N;;ss *;;;
+110B;HANGUL CHOSEONG IEUNG;Lo;0;L;;;;;N;;;;;
+110C;HANGUL CHOSEONG CIEUC;Lo;0;L;;;;;N;;j *;;;
+110D;HANGUL CHOSEONG SSANGCIEUC;Lo;0;L;;;;;N;;jj *;;;
+110E;HANGUL CHOSEONG CHIEUCH;Lo;0;L;;;;;N;;c *;;;
+110F;HANGUL CHOSEONG KHIEUKH;Lo;0;L;;;;;N;;k *;;;
+1110;HANGUL CHOSEONG THIEUTH;Lo;0;L;;;;;N;;t *;;;
+1111;HANGUL CHOSEONG PHIEUPH;Lo;0;L;;;;;N;;p *;;;
+1112;HANGUL CHOSEONG HIEUH;Lo;0;L;;;;;N;;h *;;;
+1113;HANGUL CHOSEONG NIEUN-KIYEOK;Lo;0;L;;;;;N;;;;;
+1114;HANGUL CHOSEONG SSANGNIEUN;Lo;0;L;;;;;N;;;;;
+1115;HANGUL CHOSEONG NIEUN-TIKEUT;Lo;0;L;;;;;N;;;;;
+1116;HANGUL CHOSEONG NIEUN-PIEUP;Lo;0;L;;;;;N;;;;;
+1117;HANGUL CHOSEONG TIKEUT-KIYEOK;Lo;0;L;;;;;N;;;;;
+1118;HANGUL CHOSEONG RIEUL-NIEUN;Lo;0;L;;;;;N;;;;;
+1119;HANGUL CHOSEONG SSANGRIEUL;Lo;0;L;;;;;N;;;;;
+111A;HANGUL CHOSEONG RIEUL-HIEUH;Lo;0;L;;;;;N;;;;;
+111B;HANGUL CHOSEONG KAPYEOUNRIEUL;Lo;0;L;;;;;N;;;;;
+111C;HANGUL CHOSEONG MIEUM-PIEUP;Lo;0;L;;;;;N;;;;;
+111D;HANGUL CHOSEONG KAPYEOUNMIEUM;Lo;0;L;;;;;N;;;;;
+111E;HANGUL CHOSEONG PIEUP-KIYEOK;Lo;0;L;;;;;N;;;;;
+111F;HANGUL CHOSEONG PIEUP-NIEUN;Lo;0;L;;;;;N;;;;;
+1120;HANGUL CHOSEONG PIEUP-TIKEUT;Lo;0;L;;;;;N;;;;;
+1121;HANGUL CHOSEONG PIEUP-SIOS;Lo;0;L;;;;;N;;;;;
+1122;HANGUL CHOSEONG PIEUP-SIOS-KIYEOK;Lo;0;L;;;;;N;;;;;
+1123;HANGUL CHOSEONG PIEUP-SIOS-TIKEUT;Lo;0;L;;;;;N;;;;;
+1124;HANGUL CHOSEONG PIEUP-SIOS-PIEUP;Lo;0;L;;;;;N;;;;;
+1125;HANGUL CHOSEONG PIEUP-SSANGSIOS;Lo;0;L;;;;;N;;;;;
+1126;HANGUL CHOSEONG PIEUP-SIOS-CIEUC;Lo;0;L;;;;;N;;;;;
+1127;HANGUL CHOSEONG PIEUP-CIEUC;Lo;0;L;;;;;N;;;;;
+1128;HANGUL CHOSEONG PIEUP-CHIEUCH;Lo;0;L;;;;;N;;;;;
+1129;HANGUL CHOSEONG PIEUP-THIEUTH;Lo;0;L;;;;;N;;;;;
+112A;HANGUL CHOSEONG PIEUP-PHIEUPH;Lo;0;L;;;;;N;;;;;
+112B;HANGUL CHOSEONG KAPYEOUNPIEUP;Lo;0;L;;;;;N;;;;;
+112C;HANGUL CHOSEONG KAPYEOUNSSANGPIEUP;Lo;0;L;;;;;N;;;;;
+112D;HANGUL CHOSEONG SIOS-KIYEOK;Lo;0;L;;;;;N;;;;;
+112E;HANGUL CHOSEONG SIOS-NIEUN;Lo;0;L;;;;;N;;;;;
+112F;HANGUL CHOSEONG SIOS-TIKEUT;Lo;0;L;;;;;N;;;;;
+1130;HANGUL CHOSEONG SIOS-RIEUL;Lo;0;L;;;;;N;;;;;
+1131;HANGUL CHOSEONG SIOS-MIEUM;Lo;0;L;;;;;N;;;;;
+1132;HANGUL CHOSEONG SIOS-PIEUP;Lo;0;L;;;;;N;;;;;
+1133;HANGUL CHOSEONG SIOS-PIEUP-KIYEOK;Lo;0;L;;;;;N;;;;;
+1134;HANGUL CHOSEONG SIOS-SSANGSIOS;Lo;0;L;;;;;N;;;;;
+1135;HANGUL CHOSEONG SIOS-IEUNG;Lo;0;L;;;;;N;;;;;
+1136;HANGUL CHOSEONG SIOS-CIEUC;Lo;0;L;;;;;N;;;;;
+1137;HANGUL CHOSEONG SIOS-CHIEUCH;Lo;0;L;;;;;N;;;;;
+1138;HANGUL CHOSEONG SIOS-KHIEUKH;Lo;0;L;;;;;N;;;;;
+1139;HANGUL CHOSEONG SIOS-THIEUTH;Lo;0;L;;;;;N;;;;;
+113A;HANGUL CHOSEONG SIOS-PHIEUPH;Lo;0;L;;;;;N;;;;;
+113B;HANGUL CHOSEONG SIOS-HIEUH;Lo;0;L;;;;;N;;;;;
+113C;HANGUL CHOSEONG CHITUEUMSIOS;Lo;0;L;;;;;N;;;;;
+113D;HANGUL CHOSEONG CHITUEUMSSANGSIOS;Lo;0;L;;;;;N;;;;;
+113E;HANGUL CHOSEONG CEONGCHIEUMSIOS;Lo;0;L;;;;;N;;;;;
+113F;HANGUL CHOSEONG CEONGCHIEUMSSANGSIOS;Lo;0;L;;;;;N;;;;;
+1140;HANGUL CHOSEONG PANSIOS;Lo;0;L;;;;;N;;;;;
+1141;HANGUL CHOSEONG IEUNG-KIYEOK;Lo;0;L;;;;;N;;;;;
+1142;HANGUL CHOSEONG IEUNG-TIKEUT;Lo;0;L;;;;;N;;;;;
+1143;HANGUL CHOSEONG IEUNG-MIEUM;Lo;0;L;;;;;N;;;;;
+1144;HANGUL CHOSEONG IEUNG-PIEUP;Lo;0;L;;;;;N;;;;;
+1145;HANGUL CHOSEONG IEUNG-SIOS;Lo;0;L;;;;;N;;;;;
+1146;HANGUL CHOSEONG IEUNG-PANSIOS;Lo;0;L;;;;;N;;;;;
+1147;HANGUL CHOSEONG SSANGIEUNG;Lo;0;L;;;;;N;;;;;
+1148;HANGUL CHOSEONG IEUNG-CIEUC;Lo;0;L;;;;;N;;;;;
+1149;HANGUL CHOSEONG IEUNG-CHIEUCH;Lo;0;L;;;;;N;;;;;
+114A;HANGUL CHOSEONG IEUNG-THIEUTH;Lo;0;L;;;;;N;;;;;
+114B;HANGUL CHOSEONG IEUNG-PHIEUPH;Lo;0;L;;;;;N;;;;;
+114C;HANGUL CHOSEONG YESIEUNG;Lo;0;L;;;;;N;;;;;
+114D;HANGUL CHOSEONG CIEUC-IEUNG;Lo;0;L;;;;;N;;;;;
+114E;HANGUL CHOSEONG CHITUEUMCIEUC;Lo;0;L;;;;;N;;;;;
+114F;HANGUL CHOSEONG CHITUEUMSSANGCIEUC;Lo;0;L;;;;;N;;;;;
+1150;HANGUL CHOSEONG CEONGCHIEUMCIEUC;Lo;0;L;;;;;N;;;;;
+1151;HANGUL CHOSEONG CEONGCHIEUMSSANGCIEUC;Lo;0;L;;;;;N;;;;;
+1152;HANGUL CHOSEONG CHIEUCH-KHIEUKH;Lo;0;L;;;;;N;;;;;
+1153;HANGUL CHOSEONG CHIEUCH-HIEUH;Lo;0;L;;;;;N;;;;;
+1154;HANGUL CHOSEONG CHITUEUMCHIEUCH;Lo;0;L;;;;;N;;;;;
+1155;HANGUL CHOSEONG CEONGCHIEUMCHIEUCH;Lo;0;L;;;;;N;;;;;
+1156;HANGUL CHOSEONG PHIEUPH-PIEUP;Lo;0;L;;;;;N;;;;;
+1157;HANGUL CHOSEONG KAPYEOUNPHIEUPH;Lo;0;L;;;;;N;;;;;
+1158;HANGUL CHOSEONG SSANGHIEUH;Lo;0;L;;;;;N;;;;;
+1159;HANGUL CHOSEONG YEORINHIEUH;Lo;0;L;;;;;N;;;;;
+115F;HANGUL CHOSEONG FILLER;Lo;0;L;;;;;N;;;;;
+1160;HANGUL JUNGSEONG FILLER;Lo;0;L;;;;;N;;;;;
+1161;HANGUL JUNGSEONG A;Lo;0;L;;;;;N;;;;;
+1162;HANGUL JUNGSEONG AE;Lo;0;L;;;;;N;;;;;
+1163;HANGUL JUNGSEONG YA;Lo;0;L;;;;;N;;;;;
+1164;HANGUL JUNGSEONG YAE;Lo;0;L;;;;;N;;;;;
+1165;HANGUL JUNGSEONG EO;Lo;0;L;;;;;N;;;;;
+1166;HANGUL JUNGSEONG E;Lo;0;L;;;;;N;;;;;
+1167;HANGUL JUNGSEONG YEO;Lo;0;L;;;;;N;;;;;
+1168;HANGUL JUNGSEONG YE;Lo;0;L;;;;;N;;;;;
+1169;HANGUL JUNGSEONG O;Lo;0;L;;;;;N;;;;;
+116A;HANGUL JUNGSEONG WA;Lo;0;L;;;;;N;;;;;
+116B;HANGUL JUNGSEONG WAE;Lo;0;L;;;;;N;;;;;
+116C;HANGUL JUNGSEONG OE;Lo;0;L;;;;;N;;;;;
+116D;HANGUL JUNGSEONG YO;Lo;0;L;;;;;N;;;;;
+116E;HANGUL JUNGSEONG U;Lo;0;L;;;;;N;;;;;
+116F;HANGUL JUNGSEONG WEO;Lo;0;L;;;;;N;;;;;
+1170;HANGUL JUNGSEONG WE;Lo;0;L;;;;;N;;;;;
+1171;HANGUL JUNGSEONG WI;Lo;0;L;;;;;N;;;;;
+1172;HANGUL JUNGSEONG YU;Lo;0;L;;;;;N;;;;;
+1173;HANGUL JUNGSEONG EU;Lo;0;L;;;;;N;;;;;
+1174;HANGUL JUNGSEONG YI;Lo;0;L;;;;;N;;;;;
+1175;HANGUL JUNGSEONG I;Lo;0;L;;;;;N;;;;;
+1176;HANGUL JUNGSEONG A-O;Lo;0;L;;;;;N;;;;;
+1177;HANGUL JUNGSEONG A-U;Lo;0;L;;;;;N;;;;;
+1178;HANGUL JUNGSEONG YA-O;Lo;0;L;;;;;N;;;;;
+1179;HANGUL JUNGSEONG YA-YO;Lo;0;L;;;;;N;;;;;
+117A;HANGUL JUNGSEONG EO-O;Lo;0;L;;;;;N;;;;;
+117B;HANGUL JUNGSEONG EO-U;Lo;0;L;;;;;N;;;;;
+117C;HANGUL JUNGSEONG EO-EU;Lo;0;L;;;;;N;;;;;
+117D;HANGUL JUNGSEONG YEO-O;Lo;0;L;;;;;N;;;;;
+117E;HANGUL JUNGSEONG YEO-U;Lo;0;L;;;;;N;;;;;
+117F;HANGUL JUNGSEONG O-EO;Lo;0;L;;;;;N;;;;;
+1180;HANGUL JUNGSEONG O-E;Lo;0;L;;;;;N;;;;;
+1181;HANGUL JUNGSEONG O-YE;Lo;0;L;;;;;N;;;;;
+1182;HANGUL JUNGSEONG O-O;Lo;0;L;;;;;N;;;;;
+1183;HANGUL JUNGSEONG O-U;Lo;0;L;;;;;N;;;;;
+1184;HANGUL JUNGSEONG YO-YA;Lo;0;L;;;;;N;;;;;
+1185;HANGUL JUNGSEONG YO-YAE;Lo;0;L;;;;;N;;;;;
+1186;HANGUL JUNGSEONG YO-YEO;Lo;0;L;;;;;N;;;;;
+1187;HANGUL JUNGSEONG YO-O;Lo;0;L;;;;;N;;;;;
+1188;HANGUL JUNGSEONG YO-I;Lo;0;L;;;;;N;;;;;
+1189;HANGUL JUNGSEONG U-A;Lo;0;L;;;;;N;;;;;
+118A;HANGUL JUNGSEONG U-AE;Lo;0;L;;;;;N;;;;;
+118B;HANGUL JUNGSEONG U-EO-EU;Lo;0;L;;;;;N;;;;;
+118C;HANGUL JUNGSEONG U-YE;Lo;0;L;;;;;N;;;;;
+118D;HANGUL JUNGSEONG U-U;Lo;0;L;;;;;N;;;;;
+118E;HANGUL JUNGSEONG YU-A;Lo;0;L;;;;;N;;;;;
+118F;HANGUL JUNGSEONG YU-EO;Lo;0;L;;;;;N;;;;;
+1190;HANGUL JUNGSEONG YU-E;Lo;0;L;;;;;N;;;;;
+1191;HANGUL JUNGSEONG YU-YEO;Lo;0;L;;;;;N;;;;;
+1192;HANGUL JUNGSEONG YU-YE;Lo;0;L;;;;;N;;;;;
+1193;HANGUL JUNGSEONG YU-U;Lo;0;L;;;;;N;;;;;
+1194;HANGUL JUNGSEONG YU-I;Lo;0;L;;;;;N;;;;;
+1195;HANGUL JUNGSEONG EU-U;Lo;0;L;;;;;N;;;;;
+1196;HANGUL JUNGSEONG EU-EU;Lo;0;L;;;;;N;;;;;
+1197;HANGUL JUNGSEONG YI-U;Lo;0;L;;;;;N;;;;;
+1198;HANGUL JUNGSEONG I-A;Lo;0;L;;;;;N;;;;;
+1199;HANGUL JUNGSEONG I-YA;Lo;0;L;;;;;N;;;;;
+119A;HANGUL JUNGSEONG I-O;Lo;0;L;;;;;N;;;;;
+119B;HANGUL JUNGSEONG I-U;Lo;0;L;;;;;N;;;;;
+119C;HANGUL JUNGSEONG I-EU;Lo;0;L;;;;;N;;;;;
+119D;HANGUL JUNGSEONG I-ARAEA;Lo;0;L;;;;;N;;;;;
+119E;HANGUL JUNGSEONG ARAEA;Lo;0;L;;;;;N;;;;;
+119F;HANGUL JUNGSEONG ARAEA-EO;Lo;0;L;;;;;N;;;;;
+11A0;HANGUL JUNGSEONG ARAEA-U;Lo;0;L;;;;;N;;;;;
+11A1;HANGUL JUNGSEONG ARAEA-I;Lo;0;L;;;;;N;;;;;
+11A2;HANGUL JUNGSEONG SSANGARAEA;Lo;0;L;;;;;N;;;;;
+11A8;HANGUL JONGSEONG KIYEOK;Lo;0;L;;;;;N;;g *;;;
+11A9;HANGUL JONGSEONG SSANGKIYEOK;Lo;0;L;;;;;N;;gg *;;;
+11AA;HANGUL JONGSEONG KIYEOK-SIOS;Lo;0;L;;;;;N;;gs *;;;
+11AB;HANGUL JONGSEONG NIEUN;Lo;0;L;;;;;N;;n *;;;
+11AC;HANGUL JONGSEONG NIEUN-CIEUC;Lo;0;L;;;;;N;;nj *;;;
+11AD;HANGUL JONGSEONG NIEUN-HIEUH;Lo;0;L;;;;;N;;nh *;;;
+11AE;HANGUL JONGSEONG TIKEUT;Lo;0;L;;;;;N;;d *;;;
+11AF;HANGUL JONGSEONG RIEUL;Lo;0;L;;;;;N;;l *;;;
+11B0;HANGUL JONGSEONG RIEUL-KIYEOK;Lo;0;L;;;;;N;;lg *;;;
+11B1;HANGUL JONGSEONG RIEUL-MIEUM;Lo;0;L;;;;;N;;lm *;;;
+11B2;HANGUL JONGSEONG RIEUL-PIEUP;Lo;0;L;;;;;N;;lb *;;;
+11B3;HANGUL JONGSEONG RIEUL-SIOS;Lo;0;L;;;;;N;;ls *;;;
+11B4;HANGUL JONGSEONG RIEUL-THIEUTH;Lo;0;L;;;;;N;;lt *;;;
+11B5;HANGUL JONGSEONG RIEUL-PHIEUPH;Lo;0;L;;;;;N;;lp *;;;
+11B6;HANGUL JONGSEONG RIEUL-HIEUH;Lo;0;L;;;;;N;;lh *;;;
+11B7;HANGUL JONGSEONG MIEUM;Lo;0;L;;;;;N;;m *;;;
+11B8;HANGUL JONGSEONG PIEUP;Lo;0;L;;;;;N;;b *;;;
+11B9;HANGUL JONGSEONG PIEUP-SIOS;Lo;0;L;;;;;N;;bs *;;;
+11BA;HANGUL JONGSEONG SIOS;Lo;0;L;;;;;N;;s *;;;
+11BB;HANGUL JONGSEONG SSANGSIOS;Lo;0;L;;;;;N;;ss *;;;
+11BC;HANGUL JONGSEONG IEUNG;Lo;0;L;;;;;N;;ng *;;;
+11BD;HANGUL JONGSEONG CIEUC;Lo;0;L;;;;;N;;j *;;;
+11BE;HANGUL JONGSEONG CHIEUCH;Lo;0;L;;;;;N;;c *;;;
+11BF;HANGUL JONGSEONG KHIEUKH;Lo;0;L;;;;;N;;k *;;;
+11C0;HANGUL JONGSEONG THIEUTH;Lo;0;L;;;;;N;;t *;;;
+11C1;HANGUL JONGSEONG PHIEUPH;Lo;0;L;;;;;N;;p *;;;
+11C2;HANGUL JONGSEONG HIEUH;Lo;0;L;;;;;N;;h *;;;
+11C3;HANGUL JONGSEONG KIYEOK-RIEUL;Lo;0;L;;;;;N;;;;;
+11C4;HANGUL JONGSEONG KIYEOK-SIOS-KIYEOK;Lo;0;L;;;;;N;;;;;
+11C5;HANGUL JONGSEONG NIEUN-KIYEOK;Lo;0;L;;;;;N;;;;;
+11C6;HANGUL JONGSEONG NIEUN-TIKEUT;Lo;0;L;;;;;N;;;;;
+11C7;HANGUL JONGSEONG NIEUN-SIOS;Lo;0;L;;;;;N;;;;;
+11C8;HANGUL JONGSEONG NIEUN-PANSIOS;Lo;0;L;;;;;N;;;;;
+11C9;HANGUL JONGSEONG NIEUN-THIEUTH;Lo;0;L;;;;;N;;;;;
+11CA;HANGUL JONGSEONG TIKEUT-KIYEOK;Lo;0;L;;;;;N;;;;;
+11CB;HANGUL JONGSEONG TIKEUT-RIEUL;Lo;0;L;;;;;N;;;;;
+11CC;HANGUL JONGSEONG RIEUL-KIYEOK-SIOS;Lo;0;L;;;;;N;;;;;
+11CD;HANGUL JONGSEONG RIEUL-NIEUN;Lo;0;L;;;;;N;;;;;
+11CE;HANGUL JONGSEONG RIEUL-TIKEUT;Lo;0;L;;;;;N;;;;;
+11CF;HANGUL JONGSEONG RIEUL-TIKEUT-HIEUH;Lo;0;L;;;;;N;;;;;
+11D0;HANGUL JONGSEONG SSANGRIEUL;Lo;0;L;;;;;N;;;;;
+11D1;HANGUL JONGSEONG RIEUL-MIEUM-KIYEOK;Lo;0;L;;;;;N;;;;;
+11D2;HANGUL JONGSEONG RIEUL-MIEUM-SIOS;Lo;0;L;;;;;N;;;;;
+11D3;HANGUL JONGSEONG RIEUL-PIEUP-SIOS;Lo;0;L;;;;;N;;;;;
+11D4;HANGUL JONGSEONG RIEUL-PIEUP-HIEUH;Lo;0;L;;;;;N;;;;;
+11D5;HANGUL JONGSEONG RIEUL-KAPYEOUNPIEUP;Lo;0;L;;;;;N;;;;;
+11D6;HANGUL JONGSEONG RIEUL-SSANGSIOS;Lo;0;L;;;;;N;;;;;
+11D7;HANGUL JONGSEONG RIEUL-PANSIOS;Lo;0;L;;;;;N;;;;;
+11D8;HANGUL JONGSEONG RIEUL-KHIEUKH;Lo;0;L;;;;;N;;;;;
+11D9;HANGUL JONGSEONG RIEUL-YEORINHIEUH;Lo;0;L;;;;;N;;;;;
+11DA;HANGUL JONGSEONG MIEUM-KIYEOK;Lo;0;L;;;;;N;;;;;
+11DB;HANGUL JONGSEONG MIEUM-RIEUL;Lo;0;L;;;;;N;;;;;
+11DC;HANGUL JONGSEONG MIEUM-PIEUP;Lo;0;L;;;;;N;;;;;
+11DD;HANGUL JONGSEONG MIEUM-SIOS;Lo;0;L;;;;;N;;;;;
+11DE;HANGUL JONGSEONG MIEUM-SSANGSIOS;Lo;0;L;;;;;N;;;;;
+11DF;HANGUL JONGSEONG MIEUM-PANSIOS;Lo;0;L;;;;;N;;;;;
+11E0;HANGUL JONGSEONG MIEUM-CHIEUCH;Lo;0;L;;;;;N;;;;;
+11E1;HANGUL JONGSEONG MIEUM-HIEUH;Lo;0;L;;;;;N;;;;;
+11E2;HANGUL JONGSEONG KAPYEOUNMIEUM;Lo;0;L;;;;;N;;;;;
+11E3;HANGUL JONGSEONG PIEUP-RIEUL;Lo;0;L;;;;;N;;;;;
+11E4;HANGUL JONGSEONG PIEUP-PHIEUPH;Lo;0;L;;;;;N;;;;;
+11E5;HANGUL JONGSEONG PIEUP-HIEUH;Lo;0;L;;;;;N;;;;;
+11E6;HANGUL JONGSEONG KAPYEOUNPIEUP;Lo;0;L;;;;;N;;;;;
+11E7;HANGUL JONGSEONG SIOS-KIYEOK;Lo;0;L;;;;;N;;;;;
+11E8;HANGUL JONGSEONG SIOS-TIKEUT;Lo;0;L;;;;;N;;;;;
+11E9;HANGUL JONGSEONG SIOS-RIEUL;Lo;0;L;;;;;N;;;;;
+11EA;HANGUL JONGSEONG SIOS-PIEUP;Lo;0;L;;;;;N;;;;;
+11EB;HANGUL JONGSEONG PANSIOS;Lo;0;L;;;;;N;;;;;
+11EC;HANGUL JONGSEONG IEUNG-KIYEOK;Lo;0;L;;;;;N;;;;;
+11ED;HANGUL JONGSEONG IEUNG-SSANGKIYEOK;Lo;0;L;;;;;N;;;;;
+11EE;HANGUL JONGSEONG SSANGIEUNG;Lo;0;L;;;;;N;;;;;
+11EF;HANGUL JONGSEONG IEUNG-KHIEUKH;Lo;0;L;;;;;N;;;;;
+11F0;HANGUL JONGSEONG YESIEUNG;Lo;0;L;;;;;N;;;;;
+11F1;HANGUL JONGSEONG YESIEUNG-SIOS;Lo;0;L;;;;;N;;;;;
+11F2;HANGUL JONGSEONG YESIEUNG-PANSIOS;Lo;0;L;;;;;N;;;;;
+11F3;HANGUL JONGSEONG PHIEUPH-PIEUP;Lo;0;L;;;;;N;;;;;
+11F4;HANGUL JONGSEONG KAPYEOUNPHIEUPH;Lo;0;L;;;;;N;;;;;
+11F5;HANGUL JONGSEONG HIEUH-NIEUN;Lo;0;L;;;;;N;;;;;
+11F6;HANGUL JONGSEONG HIEUH-RIEUL;Lo;0;L;;;;;N;;;;;
+11F7;HANGUL JONGSEONG HIEUH-MIEUM;Lo;0;L;;;;;N;;;;;
+11F8;HANGUL JONGSEONG HIEUH-PIEUP;Lo;0;L;;;;;N;;;;;
+11F9;HANGUL JONGSEONG YEORINHIEUH;Lo;0;L;;;;;N;;;;;
+1200;ETHIOPIC SYLLABLE HA;Lo;0;L;;;;;N;;;;;
+1201;ETHIOPIC SYLLABLE HU;Lo;0;L;;;;;N;;;;;
+1202;ETHIOPIC SYLLABLE HI;Lo;0;L;;;;;N;;;;;
+1203;ETHIOPIC SYLLABLE HAA;Lo;0;L;;;;;N;;;;;
+1204;ETHIOPIC SYLLABLE HEE;Lo;0;L;;;;;N;;;;;
+1205;ETHIOPIC SYLLABLE HE;Lo;0;L;;;;;N;;;;;
+1206;ETHIOPIC SYLLABLE HO;Lo;0;L;;;;;N;;;;;
+1207;ETHIOPIC SYLLABLE HOA;Lo;0;L;;;;;N;;;;;
+1208;ETHIOPIC SYLLABLE LA;Lo;0;L;;;;;N;;;;;
+1209;ETHIOPIC SYLLABLE LU;Lo;0;L;;;;;N;;;;;
+120A;ETHIOPIC SYLLABLE LI;Lo;0;L;;;;;N;;;;;
+120B;ETHIOPIC SYLLABLE LAA;Lo;0;L;;;;;N;;;;;
+120C;ETHIOPIC SYLLABLE LEE;Lo;0;L;;;;;N;;;;;
+120D;ETHIOPIC SYLLABLE LE;Lo;0;L;;;;;N;;;;;
+120E;ETHIOPIC SYLLABLE LO;Lo;0;L;;;;;N;;;;;
+120F;ETHIOPIC SYLLABLE LWA;Lo;0;L;;;;;N;;;;;
+1210;ETHIOPIC SYLLABLE HHA;Lo;0;L;;;;;N;;;;;
+1211;ETHIOPIC SYLLABLE HHU;Lo;0;L;;;;;N;;;;;
+1212;ETHIOPIC SYLLABLE HHI;Lo;0;L;;;;;N;;;;;
+1213;ETHIOPIC SYLLABLE HHAA;Lo;0;L;;;;;N;;;;;
+1214;ETHIOPIC SYLLABLE HHEE;Lo;0;L;;;;;N;;;;;
+1215;ETHIOPIC SYLLABLE HHE;Lo;0;L;;;;;N;;;;;
+1216;ETHIOPIC SYLLABLE HHO;Lo;0;L;;;;;N;;;;;
+1217;ETHIOPIC SYLLABLE HHWA;Lo;0;L;;;;;N;;;;;
+1218;ETHIOPIC SYLLABLE MA;Lo;0;L;;;;;N;;;;;
+1219;ETHIOPIC SYLLABLE MU;Lo;0;L;;;;;N;;;;;
+121A;ETHIOPIC SYLLABLE MI;Lo;0;L;;;;;N;;;;;
+121B;ETHIOPIC SYLLABLE MAA;Lo;0;L;;;;;N;;;;;
+121C;ETHIOPIC SYLLABLE MEE;Lo;0;L;;;;;N;;;;;
+121D;ETHIOPIC SYLLABLE ME;Lo;0;L;;;;;N;;;;;
+121E;ETHIOPIC SYLLABLE MO;Lo;0;L;;;;;N;;;;;
+121F;ETHIOPIC SYLLABLE MWA;Lo;0;L;;;;;N;;;;;
+1220;ETHIOPIC SYLLABLE SZA;Lo;0;L;;;;;N;;;;;
+1221;ETHIOPIC SYLLABLE SZU;Lo;0;L;;;;;N;;;;;
+1222;ETHIOPIC SYLLABLE SZI;Lo;0;L;;;;;N;;;;;
+1223;ETHIOPIC SYLLABLE SZAA;Lo;0;L;;;;;N;;;;;
+1224;ETHIOPIC SYLLABLE SZEE;Lo;0;L;;;;;N;;;;;
+1225;ETHIOPIC SYLLABLE SZE;Lo;0;L;;;;;N;;;;;
+1226;ETHIOPIC SYLLABLE SZO;Lo;0;L;;;;;N;;;;;
+1227;ETHIOPIC SYLLABLE SZWA;Lo;0;L;;;;;N;;;;;
+1228;ETHIOPIC SYLLABLE RA;Lo;0;L;;;;;N;;;;;
+1229;ETHIOPIC SYLLABLE RU;Lo;0;L;;;;;N;;;;;
+122A;ETHIOPIC SYLLABLE RI;Lo;0;L;;;;;N;;;;;
+122B;ETHIOPIC SYLLABLE RAA;Lo;0;L;;;;;N;;;;;
+122C;ETHIOPIC SYLLABLE REE;Lo;0;L;;;;;N;;;;;
+122D;ETHIOPIC SYLLABLE RE;Lo;0;L;;;;;N;;;;;
+122E;ETHIOPIC SYLLABLE RO;Lo;0;L;;;;;N;;;;;
+122F;ETHIOPIC SYLLABLE RWA;Lo;0;L;;;;;N;;;;;
+1230;ETHIOPIC SYLLABLE SA;Lo;0;L;;;;;N;;;;;
+1231;ETHIOPIC SYLLABLE SU;Lo;0;L;;;;;N;;;;;
+1232;ETHIOPIC SYLLABLE SI;Lo;0;L;;;;;N;;;;;
+1233;ETHIOPIC SYLLABLE SAA;Lo;0;L;;;;;N;;;;;
+1234;ETHIOPIC SYLLABLE SEE;Lo;0;L;;;;;N;;;;;
+1235;ETHIOPIC SYLLABLE SE;Lo;0;L;;;;;N;;;;;
+1236;ETHIOPIC SYLLABLE SO;Lo;0;L;;;;;N;;;;;
+1237;ETHIOPIC SYLLABLE SWA;Lo;0;L;;;;;N;;;;;
+1238;ETHIOPIC SYLLABLE SHA;Lo;0;L;;;;;N;;;;;
+1239;ETHIOPIC SYLLABLE SHU;Lo;0;L;;;;;N;;;;;
+123A;ETHIOPIC SYLLABLE SHI;Lo;0;L;;;;;N;;;;;
+123B;ETHIOPIC SYLLABLE SHAA;Lo;0;L;;;;;N;;;;;
+123C;ETHIOPIC SYLLABLE SHEE;Lo;0;L;;;;;N;;;;;
+123D;ETHIOPIC SYLLABLE SHE;Lo;0;L;;;;;N;;;;;
+123E;ETHIOPIC SYLLABLE SHO;Lo;0;L;;;;;N;;;;;
+123F;ETHIOPIC SYLLABLE SHWA;Lo;0;L;;;;;N;;;;;
+1240;ETHIOPIC SYLLABLE QA;Lo;0;L;;;;;N;;;;;
+1241;ETHIOPIC SYLLABLE QU;Lo;0;L;;;;;N;;;;;
+1242;ETHIOPIC SYLLABLE QI;Lo;0;L;;;;;N;;;;;
+1243;ETHIOPIC SYLLABLE QAA;Lo;0;L;;;;;N;;;;;
+1244;ETHIOPIC SYLLABLE QEE;Lo;0;L;;;;;N;;;;;
+1245;ETHIOPIC SYLLABLE QE;Lo;0;L;;;;;N;;;;;
+1246;ETHIOPIC SYLLABLE QO;Lo;0;L;;;;;N;;;;;
+1247;ETHIOPIC SYLLABLE QOA;Lo;0;L;;;;;N;;;;;
+1248;ETHIOPIC SYLLABLE QWA;Lo;0;L;;;;;N;;;;;
+124A;ETHIOPIC SYLLABLE QWI;Lo;0;L;;;;;N;;;;;
+124B;ETHIOPIC SYLLABLE QWAA;Lo;0;L;;;;;N;;;;;
+124C;ETHIOPIC SYLLABLE QWEE;Lo;0;L;;;;;N;;;;;
+124D;ETHIOPIC SYLLABLE QWE;Lo;0;L;;;;;N;;;;;
+1250;ETHIOPIC SYLLABLE QHA;Lo;0;L;;;;;N;;;;;
+1251;ETHIOPIC SYLLABLE QHU;Lo;0;L;;;;;N;;;;;
+1252;ETHIOPIC SYLLABLE QHI;Lo;0;L;;;;;N;;;;;
+1253;ETHIOPIC SYLLABLE QHAA;Lo;0;L;;;;;N;;;;;
+1254;ETHIOPIC SYLLABLE QHEE;Lo;0;L;;;;;N;;;;;
+1255;ETHIOPIC SYLLABLE QHE;Lo;0;L;;;;;N;;;;;
+1256;ETHIOPIC SYLLABLE QHO;Lo;0;L;;;;;N;;;;;
+1258;ETHIOPIC SYLLABLE QHWA;Lo;0;L;;;;;N;;;;;
+125A;ETHIOPIC SYLLABLE QHWI;Lo;0;L;;;;;N;;;;;
+125B;ETHIOPIC SYLLABLE QHWAA;Lo;0;L;;;;;N;;;;;
+125C;ETHIOPIC SYLLABLE QHWEE;Lo;0;L;;;;;N;;;;;
+125D;ETHIOPIC SYLLABLE QHWE;Lo;0;L;;;;;N;;;;;
+1260;ETHIOPIC SYLLABLE BA;Lo;0;L;;;;;N;;;;;
+1261;ETHIOPIC SYLLABLE BU;Lo;0;L;;;;;N;;;;;
+1262;ETHIOPIC SYLLABLE BI;Lo;0;L;;;;;N;;;;;
+1263;ETHIOPIC SYLLABLE BAA;Lo;0;L;;;;;N;;;;;
+1264;ETHIOPIC SYLLABLE BEE;Lo;0;L;;;;;N;;;;;
+1265;ETHIOPIC SYLLABLE BE;Lo;0;L;;;;;N;;;;;
+1266;ETHIOPIC SYLLABLE BO;Lo;0;L;;;;;N;;;;;
+1267;ETHIOPIC SYLLABLE BWA;Lo;0;L;;;;;N;;;;;
+1268;ETHIOPIC SYLLABLE VA;Lo;0;L;;;;;N;;;;;
+1269;ETHIOPIC SYLLABLE VU;Lo;0;L;;;;;N;;;;;
+126A;ETHIOPIC SYLLABLE VI;Lo;0;L;;;;;N;;;;;
+126B;ETHIOPIC SYLLABLE VAA;Lo;0;L;;;;;N;;;;;
+126C;ETHIOPIC SYLLABLE VEE;Lo;0;L;;;;;N;;;;;
+126D;ETHIOPIC SYLLABLE VE;Lo;0;L;;;;;N;;;;;
+126E;ETHIOPIC SYLLABLE VO;Lo;0;L;;;;;N;;;;;
+126F;ETHIOPIC SYLLABLE VWA;Lo;0;L;;;;;N;;;;;
+1270;ETHIOPIC SYLLABLE TA;Lo;0;L;;;;;N;;;;;
+1271;ETHIOPIC SYLLABLE TU;Lo;0;L;;;;;N;;;;;
+1272;ETHIOPIC SYLLABLE TI;Lo;0;L;;;;;N;;;;;
+1273;ETHIOPIC SYLLABLE TAA;Lo;0;L;;;;;N;;;;;
+1274;ETHIOPIC SYLLABLE TEE;Lo;0;L;;;;;N;;;;;
+1275;ETHIOPIC SYLLABLE TE;Lo;0;L;;;;;N;;;;;
+1276;ETHIOPIC SYLLABLE TO;Lo;0;L;;;;;N;;;;;
+1277;ETHIOPIC SYLLABLE TWA;Lo;0;L;;;;;N;;;;;
+1278;ETHIOPIC SYLLABLE CA;Lo;0;L;;;;;N;;;;;
+1279;ETHIOPIC SYLLABLE CU;Lo;0;L;;;;;N;;;;;
+127A;ETHIOPIC SYLLABLE CI;Lo;0;L;;;;;N;;;;;
+127B;ETHIOPIC SYLLABLE CAA;Lo;0;L;;;;;N;;;;;
+127C;ETHIOPIC SYLLABLE CEE;Lo;0;L;;;;;N;;;;;
+127D;ETHIOPIC SYLLABLE CE;Lo;0;L;;;;;N;;;;;
+127E;ETHIOPIC SYLLABLE CO;Lo;0;L;;;;;N;;;;;
+127F;ETHIOPIC SYLLABLE CWA;Lo;0;L;;;;;N;;;;;
+1280;ETHIOPIC SYLLABLE XA;Lo;0;L;;;;;N;;;;;
+1281;ETHIOPIC SYLLABLE XU;Lo;0;L;;;;;N;;;;;
+1282;ETHIOPIC SYLLABLE XI;Lo;0;L;;;;;N;;;;;
+1283;ETHIOPIC SYLLABLE XAA;Lo;0;L;;;;;N;;;;;
+1284;ETHIOPIC SYLLABLE XEE;Lo;0;L;;;;;N;;;;;
+1285;ETHIOPIC SYLLABLE XE;Lo;0;L;;;;;N;;;;;
+1286;ETHIOPIC SYLLABLE XO;Lo;0;L;;;;;N;;;;;
+1287;ETHIOPIC SYLLABLE XOA;Lo;0;L;;;;;N;;;;;
+1288;ETHIOPIC SYLLABLE XWA;Lo;0;L;;;;;N;;;;;
+128A;ETHIOPIC SYLLABLE XWI;Lo;0;L;;;;;N;;;;;
+128B;ETHIOPIC SYLLABLE XWAA;Lo;0;L;;;;;N;;;;;
+128C;ETHIOPIC SYLLABLE XWEE;Lo;0;L;;;;;N;;;;;
+128D;ETHIOPIC SYLLABLE XWE;Lo;0;L;;;;;N;;;;;
+1290;ETHIOPIC SYLLABLE NA;Lo;0;L;;;;;N;;;;;
+1291;ETHIOPIC SYLLABLE NU;Lo;0;L;;;;;N;;;;;
+1292;ETHIOPIC SYLLABLE NI;Lo;0;L;;;;;N;;;;;
+1293;ETHIOPIC SYLLABLE NAA;Lo;0;L;;;;;N;;;;;
+1294;ETHIOPIC SYLLABLE NEE;Lo;0;L;;;;;N;;;;;
+1295;ETHIOPIC SYLLABLE NE;Lo;0;L;;;;;N;;;;;
+1296;ETHIOPIC SYLLABLE NO;Lo;0;L;;;;;N;;;;;
+1297;ETHIOPIC SYLLABLE NWA;Lo;0;L;;;;;N;;;;;
+1298;ETHIOPIC SYLLABLE NYA;Lo;0;L;;;;;N;;;;;
+1299;ETHIOPIC SYLLABLE NYU;Lo;0;L;;;;;N;;;;;
+129A;ETHIOPIC SYLLABLE NYI;Lo;0;L;;;;;N;;;;;
+129B;ETHIOPIC SYLLABLE NYAA;Lo;0;L;;;;;N;;;;;
+129C;ETHIOPIC SYLLABLE NYEE;Lo;0;L;;;;;N;;;;;
+129D;ETHIOPIC SYLLABLE NYE;Lo;0;L;;;;;N;;;;;
+129E;ETHIOPIC SYLLABLE NYO;Lo;0;L;;;;;N;;;;;
+129F;ETHIOPIC SYLLABLE NYWA;Lo;0;L;;;;;N;;;;;
+12A0;ETHIOPIC SYLLABLE GLOTTAL A;Lo;0;L;;;;;N;;;;;
+12A1;ETHIOPIC SYLLABLE GLOTTAL U;Lo;0;L;;;;;N;;;;;
+12A2;ETHIOPIC SYLLABLE GLOTTAL I;Lo;0;L;;;;;N;;;;;
+12A3;ETHIOPIC SYLLABLE GLOTTAL AA;Lo;0;L;;;;;N;;;;;
+12A4;ETHIOPIC SYLLABLE GLOTTAL EE;Lo;0;L;;;;;N;;;;;
+12A5;ETHIOPIC SYLLABLE GLOTTAL E;Lo;0;L;;;;;N;;;;;
+12A6;ETHIOPIC SYLLABLE GLOTTAL O;Lo;0;L;;;;;N;;;;;
+12A7;ETHIOPIC SYLLABLE GLOTTAL WA;Lo;0;L;;;;;N;;;;;
+12A8;ETHIOPIC SYLLABLE KA;Lo;0;L;;;;;N;;;;;
+12A9;ETHIOPIC SYLLABLE KU;Lo;0;L;;;;;N;;;;;
+12AA;ETHIOPIC SYLLABLE KI;Lo;0;L;;;;;N;;;;;
+12AB;ETHIOPIC SYLLABLE KAA;Lo;0;L;;;;;N;;;;;
+12AC;ETHIOPIC SYLLABLE KEE;Lo;0;L;;;;;N;;;;;
+12AD;ETHIOPIC SYLLABLE KE;Lo;0;L;;;;;N;;;;;
+12AE;ETHIOPIC SYLLABLE KO;Lo;0;L;;;;;N;;;;;
+12AF;ETHIOPIC SYLLABLE KOA;Lo;0;L;;;;;N;;;;;
+12B0;ETHIOPIC SYLLABLE KWA;Lo;0;L;;;;;N;;;;;
+12B2;ETHIOPIC SYLLABLE KWI;Lo;0;L;;;;;N;;;;;
+12B3;ETHIOPIC SYLLABLE KWAA;Lo;0;L;;;;;N;;;;;
+12B4;ETHIOPIC SYLLABLE KWEE;Lo;0;L;;;;;N;;;;;
+12B5;ETHIOPIC SYLLABLE KWE;Lo;0;L;;;;;N;;;;;
+12B8;ETHIOPIC SYLLABLE KXA;Lo;0;L;;;;;N;;;;;
+12B9;ETHIOPIC SYLLABLE KXU;Lo;0;L;;;;;N;;;;;
+12BA;ETHIOPIC SYLLABLE KXI;Lo;0;L;;;;;N;;;;;
+12BB;ETHIOPIC SYLLABLE KXAA;Lo;0;L;;;;;N;;;;;
+12BC;ETHIOPIC SYLLABLE KXEE;Lo;0;L;;;;;N;;;;;
+12BD;ETHIOPIC SYLLABLE KXE;Lo;0;L;;;;;N;;;;;
+12BE;ETHIOPIC SYLLABLE KXO;Lo;0;L;;;;;N;;;;;
+12C0;ETHIOPIC SYLLABLE KXWA;Lo;0;L;;;;;N;;;;;
+12C2;ETHIOPIC SYLLABLE KXWI;Lo;0;L;;;;;N;;;;;
+12C3;ETHIOPIC SYLLABLE KXWAA;Lo;0;L;;;;;N;;;;;
+12C4;ETHIOPIC SYLLABLE KXWEE;Lo;0;L;;;;;N;;;;;
+12C5;ETHIOPIC SYLLABLE KXWE;Lo;0;L;;;;;N;;;;;
+12C8;ETHIOPIC SYLLABLE WA;Lo;0;L;;;;;N;;;;;
+12C9;ETHIOPIC SYLLABLE WU;Lo;0;L;;;;;N;;;;;
+12CA;ETHIOPIC SYLLABLE WI;Lo;0;L;;;;;N;;;;;
+12CB;ETHIOPIC SYLLABLE WAA;Lo;0;L;;;;;N;;;;;
+12CC;ETHIOPIC SYLLABLE WEE;Lo;0;L;;;;;N;;;;;
+12CD;ETHIOPIC SYLLABLE WE;Lo;0;L;;;;;N;;;;;
+12CE;ETHIOPIC SYLLABLE WO;Lo;0;L;;;;;N;;;;;
+12CF;ETHIOPIC SYLLABLE WOA;Lo;0;L;;;;;N;;;;;
+12D0;ETHIOPIC SYLLABLE PHARYNGEAL A;Lo;0;L;;;;;N;;;;;
+12D1;ETHIOPIC SYLLABLE PHARYNGEAL U;Lo;0;L;;;;;N;;;;;
+12D2;ETHIOPIC SYLLABLE PHARYNGEAL I;Lo;0;L;;;;;N;;;;;
+12D3;ETHIOPIC SYLLABLE PHARYNGEAL AA;Lo;0;L;;;;;N;;;;;
+12D4;ETHIOPIC SYLLABLE PHARYNGEAL EE;Lo;0;L;;;;;N;;;;;
+12D5;ETHIOPIC SYLLABLE PHARYNGEAL E;Lo;0;L;;;;;N;;;;;
+12D6;ETHIOPIC SYLLABLE PHARYNGEAL O;Lo;0;L;;;;;N;;;;;
+12D8;ETHIOPIC SYLLABLE ZA;Lo;0;L;;;;;N;;;;;
+12D9;ETHIOPIC SYLLABLE ZU;Lo;0;L;;;;;N;;;;;
+12DA;ETHIOPIC SYLLABLE ZI;Lo;0;L;;;;;N;;;;;
+12DB;ETHIOPIC SYLLABLE ZAA;Lo;0;L;;;;;N;;;;;
+12DC;ETHIOPIC SYLLABLE ZEE;Lo;0;L;;;;;N;;;;;
+12DD;ETHIOPIC SYLLABLE ZE;Lo;0;L;;;;;N;;;;;
+12DE;ETHIOPIC SYLLABLE ZO;Lo;0;L;;;;;N;;;;;
+12DF;ETHIOPIC SYLLABLE ZWA;Lo;0;L;;;;;N;;;;;
+12E0;ETHIOPIC SYLLABLE ZHA;Lo;0;L;;;;;N;;;;;
+12E1;ETHIOPIC SYLLABLE ZHU;Lo;0;L;;;;;N;;;;;
+12E2;ETHIOPIC SYLLABLE ZHI;Lo;0;L;;;;;N;;;;;
+12E3;ETHIOPIC SYLLABLE ZHAA;Lo;0;L;;;;;N;;;;;
+12E4;ETHIOPIC SYLLABLE ZHEE;Lo;0;L;;;;;N;;;;;
+12E5;ETHIOPIC SYLLABLE ZHE;Lo;0;L;;;;;N;;;;;
+12E6;ETHIOPIC SYLLABLE ZHO;Lo;0;L;;;;;N;;;;;
+12E7;ETHIOPIC SYLLABLE ZHWA;Lo;0;L;;;;;N;;;;;
+12E8;ETHIOPIC SYLLABLE YA;Lo;0;L;;;;;N;;;;;
+12E9;ETHIOPIC SYLLABLE YU;Lo;0;L;;;;;N;;;;;
+12EA;ETHIOPIC SYLLABLE YI;Lo;0;L;;;;;N;;;;;
+12EB;ETHIOPIC SYLLABLE YAA;Lo;0;L;;;;;N;;;;;
+12EC;ETHIOPIC SYLLABLE YEE;Lo;0;L;;;;;N;;;;;
+12ED;ETHIOPIC SYLLABLE YE;Lo;0;L;;;;;N;;;;;
+12EE;ETHIOPIC SYLLABLE YO;Lo;0;L;;;;;N;;;;;
+12EF;ETHIOPIC SYLLABLE YOA;Lo;0;L;;;;;N;;;;;
+12F0;ETHIOPIC SYLLABLE DA;Lo;0;L;;;;;N;;;;;
+12F1;ETHIOPIC SYLLABLE DU;Lo;0;L;;;;;N;;;;;
+12F2;ETHIOPIC SYLLABLE DI;Lo;0;L;;;;;N;;;;;
+12F3;ETHIOPIC SYLLABLE DAA;Lo;0;L;;;;;N;;;;;
+12F4;ETHIOPIC SYLLABLE DEE;Lo;0;L;;;;;N;;;;;
+12F5;ETHIOPIC SYLLABLE DE;Lo;0;L;;;;;N;;;;;
+12F6;ETHIOPIC SYLLABLE DO;Lo;0;L;;;;;N;;;;;
+12F7;ETHIOPIC SYLLABLE DWA;Lo;0;L;;;;;N;;;;;
+12F8;ETHIOPIC SYLLABLE DDA;Lo;0;L;;;;;N;;;;;
+12F9;ETHIOPIC SYLLABLE DDU;Lo;0;L;;;;;N;;;;;
+12FA;ETHIOPIC SYLLABLE DDI;Lo;0;L;;;;;N;;;;;
+12FB;ETHIOPIC SYLLABLE DDAA;Lo;0;L;;;;;N;;;;;
+12FC;ETHIOPIC SYLLABLE DDEE;Lo;0;L;;;;;N;;;;;
+12FD;ETHIOPIC SYLLABLE DDE;Lo;0;L;;;;;N;;;;;
+12FE;ETHIOPIC SYLLABLE DDO;Lo;0;L;;;;;N;;;;;
+12FF;ETHIOPIC SYLLABLE DDWA;Lo;0;L;;;;;N;;;;;
+1300;ETHIOPIC SYLLABLE JA;Lo;0;L;;;;;N;;;;;
+1301;ETHIOPIC SYLLABLE JU;Lo;0;L;;;;;N;;;;;
+1302;ETHIOPIC SYLLABLE JI;Lo;0;L;;;;;N;;;;;
+1303;ETHIOPIC SYLLABLE JAA;Lo;0;L;;;;;N;;;;;
+1304;ETHIOPIC SYLLABLE JEE;Lo;0;L;;;;;N;;;;;
+1305;ETHIOPIC SYLLABLE JE;Lo;0;L;;;;;N;;;;;
+1306;ETHIOPIC SYLLABLE JO;Lo;0;L;;;;;N;;;;;
+1307;ETHIOPIC SYLLABLE JWA;Lo;0;L;;;;;N;;;;;
+1308;ETHIOPIC SYLLABLE GA;Lo;0;L;;;;;N;;;;;
+1309;ETHIOPIC SYLLABLE GU;Lo;0;L;;;;;N;;;;;
+130A;ETHIOPIC SYLLABLE GI;Lo;0;L;;;;;N;;;;;
+130B;ETHIOPIC SYLLABLE GAA;Lo;0;L;;;;;N;;;;;
+130C;ETHIOPIC SYLLABLE GEE;Lo;0;L;;;;;N;;;;;
+130D;ETHIOPIC SYLLABLE GE;Lo;0;L;;;;;N;;;;;
+130E;ETHIOPIC SYLLABLE GO;Lo;0;L;;;;;N;;;;;
+130F;ETHIOPIC SYLLABLE GOA;Lo;0;L;;;;;N;;;;;
+1310;ETHIOPIC SYLLABLE GWA;Lo;0;L;;;;;N;;;;;
+1312;ETHIOPIC SYLLABLE GWI;Lo;0;L;;;;;N;;;;;
+1313;ETHIOPIC SYLLABLE GWAA;Lo;0;L;;;;;N;;;;;
+1314;ETHIOPIC SYLLABLE GWEE;Lo;0;L;;;;;N;;;;;
+1315;ETHIOPIC SYLLABLE GWE;Lo;0;L;;;;;N;;;;;
+1318;ETHIOPIC SYLLABLE GGA;Lo;0;L;;;;;N;;;;;
+1319;ETHIOPIC SYLLABLE GGU;Lo;0;L;;;;;N;;;;;
+131A;ETHIOPIC SYLLABLE GGI;Lo;0;L;;;;;N;;;;;
+131B;ETHIOPIC SYLLABLE GGAA;Lo;0;L;;;;;N;;;;;
+131C;ETHIOPIC SYLLABLE GGEE;Lo;0;L;;;;;N;;;;;
+131D;ETHIOPIC SYLLABLE GGE;Lo;0;L;;;;;N;;;;;
+131E;ETHIOPIC SYLLABLE GGO;Lo;0;L;;;;;N;;;;;
+131F;ETHIOPIC SYLLABLE GGWAA;Lo;0;L;;;;;N;;;;;
+1320;ETHIOPIC SYLLABLE THA;Lo;0;L;;;;;N;;;;;
+1321;ETHIOPIC SYLLABLE THU;Lo;0;L;;;;;N;;;;;
+1322;ETHIOPIC SYLLABLE THI;Lo;0;L;;;;;N;;;;;
+1323;ETHIOPIC SYLLABLE THAA;Lo;0;L;;;;;N;;;;;
+1324;ETHIOPIC SYLLABLE THEE;Lo;0;L;;;;;N;;;;;
+1325;ETHIOPIC SYLLABLE THE;Lo;0;L;;;;;N;;;;;
+1326;ETHIOPIC SYLLABLE THO;Lo;0;L;;;;;N;;;;;
+1327;ETHIOPIC SYLLABLE THWA;Lo;0;L;;;;;N;;;;;
+1328;ETHIOPIC SYLLABLE CHA;Lo;0;L;;;;;N;;;;;
+1329;ETHIOPIC SYLLABLE CHU;Lo;0;L;;;;;N;;;;;
+132A;ETHIOPIC SYLLABLE CHI;Lo;0;L;;;;;N;;;;;
+132B;ETHIOPIC SYLLABLE CHAA;Lo;0;L;;;;;N;;;;;
+132C;ETHIOPIC SYLLABLE CHEE;Lo;0;L;;;;;N;;;;;
+132D;ETHIOPIC SYLLABLE CHE;Lo;0;L;;;;;N;;;;;
+132E;ETHIOPIC SYLLABLE CHO;Lo;0;L;;;;;N;;;;;
+132F;ETHIOPIC SYLLABLE CHWA;Lo;0;L;;;;;N;;;;;
+1330;ETHIOPIC SYLLABLE PHA;Lo;0;L;;;;;N;;;;;
+1331;ETHIOPIC SYLLABLE PHU;Lo;0;L;;;;;N;;;;;
+1332;ETHIOPIC SYLLABLE PHI;Lo;0;L;;;;;N;;;;;
+1333;ETHIOPIC SYLLABLE PHAA;Lo;0;L;;;;;N;;;;;
+1334;ETHIOPIC SYLLABLE PHEE;Lo;0;L;;;;;N;;;;;
+1335;ETHIOPIC SYLLABLE PHE;Lo;0;L;;;;;N;;;;;
+1336;ETHIOPIC SYLLABLE PHO;Lo;0;L;;;;;N;;;;;
+1337;ETHIOPIC SYLLABLE PHWA;Lo;0;L;;;;;N;;;;;
+1338;ETHIOPIC SYLLABLE TSA;Lo;0;L;;;;;N;;;;;
+1339;ETHIOPIC SYLLABLE TSU;Lo;0;L;;;;;N;;;;;
+133A;ETHIOPIC SYLLABLE TSI;Lo;0;L;;;;;N;;;;;
+133B;ETHIOPIC SYLLABLE TSAA;Lo;0;L;;;;;N;;;;;
+133C;ETHIOPIC SYLLABLE TSEE;Lo;0;L;;;;;N;;;;;
+133D;ETHIOPIC SYLLABLE TSE;Lo;0;L;;;;;N;;;;;
+133E;ETHIOPIC SYLLABLE TSO;Lo;0;L;;;;;N;;;;;
+133F;ETHIOPIC SYLLABLE TSWA;Lo;0;L;;;;;N;;;;;
+1340;ETHIOPIC SYLLABLE TZA;Lo;0;L;;;;;N;;;;;
+1341;ETHIOPIC SYLLABLE TZU;Lo;0;L;;;;;N;;;;;
+1342;ETHIOPIC SYLLABLE TZI;Lo;0;L;;;;;N;;;;;
+1343;ETHIOPIC SYLLABLE TZAA;Lo;0;L;;;;;N;;;;;
+1344;ETHIOPIC SYLLABLE TZEE;Lo;0;L;;;;;N;;;;;
+1345;ETHIOPIC SYLLABLE TZE;Lo;0;L;;;;;N;;;;;
+1346;ETHIOPIC SYLLABLE TZO;Lo;0;L;;;;;N;;;;;
+1347;ETHIOPIC SYLLABLE TZOA;Lo;0;L;;;;;N;;;;;
+1348;ETHIOPIC SYLLABLE FA;Lo;0;L;;;;;N;;;;;
+1349;ETHIOPIC SYLLABLE FU;Lo;0;L;;;;;N;;;;;
+134A;ETHIOPIC SYLLABLE FI;Lo;0;L;;;;;N;;;;;
+134B;ETHIOPIC SYLLABLE FAA;Lo;0;L;;;;;N;;;;;
+134C;ETHIOPIC SYLLABLE FEE;Lo;0;L;;;;;N;;;;;
+134D;ETHIOPIC SYLLABLE FE;Lo;0;L;;;;;N;;;;;
+134E;ETHIOPIC SYLLABLE FO;Lo;0;L;;;;;N;;;;;
+134F;ETHIOPIC SYLLABLE FWA;Lo;0;L;;;;;N;;;;;
+1350;ETHIOPIC SYLLABLE PA;Lo;0;L;;;;;N;;;;;
+1351;ETHIOPIC SYLLABLE PU;Lo;0;L;;;;;N;;;;;
+1352;ETHIOPIC SYLLABLE PI;Lo;0;L;;;;;N;;;;;
+1353;ETHIOPIC SYLLABLE PAA;Lo;0;L;;;;;N;;;;;
+1354;ETHIOPIC SYLLABLE PEE;Lo;0;L;;;;;N;;;;;
+1355;ETHIOPIC SYLLABLE PE;Lo;0;L;;;;;N;;;;;
+1356;ETHIOPIC SYLLABLE PO;Lo;0;L;;;;;N;;;;;
+1357;ETHIOPIC SYLLABLE PWA;Lo;0;L;;;;;N;;;;;
+1358;ETHIOPIC SYLLABLE RYA;Lo;0;L;;;;;N;;;;;
+1359;ETHIOPIC SYLLABLE MYA;Lo;0;L;;;;;N;;;;;
+135A;ETHIOPIC SYLLABLE FYA;Lo;0;L;;;;;N;;;;;
+135F;ETHIOPIC COMBINING GEMINATION MARK;Mn;230;NSM;;;;;N;;;;;
+1360;ETHIOPIC SECTION MARK;So;0;L;;;;;N;;;;;
+1361;ETHIOPIC WORDSPACE;Po;0;L;;;;;N;;;;;
+1362;ETHIOPIC FULL STOP;Po;0;L;;;;;N;;;;;
+1363;ETHIOPIC COMMA;Po;0;L;;;;;N;;;;;
+1364;ETHIOPIC SEMICOLON;Po;0;L;;;;;N;;;;;
+1365;ETHIOPIC COLON;Po;0;L;;;;;N;;;;;
+1366;ETHIOPIC PREFACE COLON;Po;0;L;;;;;N;;;;;
+1367;ETHIOPIC QUESTION MARK;Po;0;L;;;;;N;;;;;
+1368;ETHIOPIC PARAGRAPH SEPARATOR;Po;0;L;;;;;N;;;;;
+1369;ETHIOPIC DIGIT ONE;No;0;L;;;1;1;N;;;;;
+136A;ETHIOPIC DIGIT TWO;No;0;L;;;2;2;N;;;;;
+136B;ETHIOPIC DIGIT THREE;No;0;L;;;3;3;N;;;;;
+136C;ETHIOPIC DIGIT FOUR;No;0;L;;;4;4;N;;;;;
+136D;ETHIOPIC DIGIT FIVE;No;0;L;;;5;5;N;;;;;
+136E;ETHIOPIC DIGIT SIX;No;0;L;;;6;6;N;;;;;
+136F;ETHIOPIC DIGIT SEVEN;No;0;L;;;7;7;N;;;;;
+1370;ETHIOPIC DIGIT EIGHT;No;0;L;;;8;8;N;;;;;
+1371;ETHIOPIC DIGIT NINE;No;0;L;;;9;9;N;;;;;
+1372;ETHIOPIC NUMBER TEN;No;0;L;;;;10;N;;;;;
+1373;ETHIOPIC NUMBER TWENTY;No;0;L;;;;20;N;;;;;
+1374;ETHIOPIC NUMBER THIRTY;No;0;L;;;;30;N;;;;;
+1375;ETHIOPIC NUMBER FORTY;No;0;L;;;;40;N;;;;;
+1376;ETHIOPIC NUMBER FIFTY;No;0;L;;;;50;N;;;;;
+1377;ETHIOPIC NUMBER SIXTY;No;0;L;;;;60;N;;;;;
+1378;ETHIOPIC NUMBER SEVENTY;No;0;L;;;;70;N;;;;;
+1379;ETHIOPIC NUMBER EIGHTY;No;0;L;;;;80;N;;;;;
+137A;ETHIOPIC NUMBER NINETY;No;0;L;;;;90;N;;;;;
+137B;ETHIOPIC NUMBER HUNDRED;No;0;L;;;;100;N;;;;;
+137C;ETHIOPIC NUMBER TEN THOUSAND;No;0;L;;;;10000;N;;;;;
+1380;ETHIOPIC SYLLABLE SEBATBEIT MWA;Lo;0;L;;;;;N;;;;;
+1381;ETHIOPIC SYLLABLE MWI;Lo;0;L;;;;;N;;;;;
+1382;ETHIOPIC SYLLABLE MWEE;Lo;0;L;;;;;N;;;;;
+1383;ETHIOPIC SYLLABLE MWE;Lo;0;L;;;;;N;;;;;
+1384;ETHIOPIC SYLLABLE SEBATBEIT BWA;Lo;0;L;;;;;N;;;;;
+1385;ETHIOPIC SYLLABLE BWI;Lo;0;L;;;;;N;;;;;
+1386;ETHIOPIC SYLLABLE BWEE;Lo;0;L;;;;;N;;;;;
+1387;ETHIOPIC SYLLABLE BWE;Lo;0;L;;;;;N;;;;;
+1388;ETHIOPIC SYLLABLE SEBATBEIT FWA;Lo;0;L;;;;;N;;;;;
+1389;ETHIOPIC SYLLABLE FWI;Lo;0;L;;;;;N;;;;;
+138A;ETHIOPIC SYLLABLE FWEE;Lo;0;L;;;;;N;;;;;
+138B;ETHIOPIC SYLLABLE FWE;Lo;0;L;;;;;N;;;;;
+138C;ETHIOPIC SYLLABLE SEBATBEIT PWA;Lo;0;L;;;;;N;;;;;
+138D;ETHIOPIC SYLLABLE PWI;Lo;0;L;;;;;N;;;;;
+138E;ETHIOPIC SYLLABLE PWEE;Lo;0;L;;;;;N;;;;;
+138F;ETHIOPIC SYLLABLE PWE;Lo;0;L;;;;;N;;;;;
+1390;ETHIOPIC TONAL MARK YIZET;So;0;ON;;;;;N;;;;;
+1391;ETHIOPIC TONAL MARK DERET;So;0;ON;;;;;N;;;;;
+1392;ETHIOPIC TONAL MARK RIKRIK;So;0;ON;;;;;N;;;;;
+1393;ETHIOPIC TONAL MARK SHORT RIKRIK;So;0;ON;;;;;N;;;;;
+1394;ETHIOPIC TONAL MARK DIFAT;So;0;ON;;;;;N;;;;;
+1395;ETHIOPIC TONAL MARK KENAT;So;0;ON;;;;;N;;;;;
+1396;ETHIOPIC TONAL MARK CHIRET;So;0;ON;;;;;N;;;;;
+1397;ETHIOPIC TONAL MARK HIDET;So;0;ON;;;;;N;;;;;
+1398;ETHIOPIC TONAL MARK DERET-HIDET;So;0;ON;;;;;N;;;;;
+1399;ETHIOPIC TONAL MARK KURT;So;0;ON;;;;;N;;;;;
+13A0;CHEROKEE LETTER A;Lo;0;L;;;;;N;;;;;
+13A1;CHEROKEE LETTER E;Lo;0;L;;;;;N;;;;;
+13A2;CHEROKEE LETTER I;Lo;0;L;;;;;N;;;;;
+13A3;CHEROKEE LETTER O;Lo;0;L;;;;;N;;;;;
+13A4;CHEROKEE LETTER U;Lo;0;L;;;;;N;;;;;
+13A5;CHEROKEE LETTER V;Lo;0;L;;;;;N;;;;;
+13A6;CHEROKEE LETTER GA;Lo;0;L;;;;;N;;;;;
+13A7;CHEROKEE LETTER KA;Lo;0;L;;;;;N;;;;;
+13A8;CHEROKEE LETTER GE;Lo;0;L;;;;;N;;;;;
+13A9;CHEROKEE LETTER GI;Lo;0;L;;;;;N;;;;;
+13AA;CHEROKEE LETTER GO;Lo;0;L;;;;;N;;;;;
+13AB;CHEROKEE LETTER GU;Lo;0;L;;;;;N;;;;;
+13AC;CHEROKEE LETTER GV;Lo;0;L;;;;;N;;;;;
+13AD;CHEROKEE LETTER HA;Lo;0;L;;;;;N;;;;;
+13AE;CHEROKEE LETTER HE;Lo;0;L;;;;;N;;;;;
+13AF;CHEROKEE LETTER HI;Lo;0;L;;;;;N;;;;;
+13B0;CHEROKEE LETTER HO;Lo;0;L;;;;;N;;;;;
+13B1;CHEROKEE LETTER HU;Lo;0;L;;;;;N;;;;;
+13B2;CHEROKEE LETTER HV;Lo;0;L;;;;;N;;;;;
+13B3;CHEROKEE LETTER LA;Lo;0;L;;;;;N;;;;;
+13B4;CHEROKEE LETTER LE;Lo;0;L;;;;;N;;;;;
+13B5;CHEROKEE LETTER LI;Lo;0;L;;;;;N;;;;;
+13B6;CHEROKEE LETTER LO;Lo;0;L;;;;;N;;;;;
+13B7;CHEROKEE LETTER LU;Lo;0;L;;;;;N;;;;;
+13B8;CHEROKEE LETTER LV;Lo;0;L;;;;;N;;;;;
+13B9;CHEROKEE LETTER MA;Lo;0;L;;;;;N;;;;;
+13BA;CHEROKEE LETTER ME;Lo;0;L;;;;;N;;;;;
+13BB;CHEROKEE LETTER MI;Lo;0;L;;;;;N;;;;;
+13BC;CHEROKEE LETTER MO;Lo;0;L;;;;;N;;;;;
+13BD;CHEROKEE LETTER MU;Lo;0;L;;;;;N;;;;;
+13BE;CHEROKEE LETTER NA;Lo;0;L;;;;;N;;;;;
+13BF;CHEROKEE LETTER HNA;Lo;0;L;;;;;N;;;;;
+13C0;CHEROKEE LETTER NAH;Lo;0;L;;;;;N;;;;;
+13C1;CHEROKEE LETTER NE;Lo;0;L;;;;;N;;;;;
+13C2;CHEROKEE LETTER NI;Lo;0;L;;;;;N;;;;;
+13C3;CHEROKEE LETTER NO;Lo;0;L;;;;;N;;;;;
+13C4;CHEROKEE LETTER NU;Lo;0;L;;;;;N;;;;;
+13C5;CHEROKEE LETTER NV;Lo;0;L;;;;;N;;;;;
+13C6;CHEROKEE LETTER QUA;Lo;0;L;;;;;N;;;;;
+13C7;CHEROKEE LETTER QUE;Lo;0;L;;;;;N;;;;;
+13C8;CHEROKEE LETTER QUI;Lo;0;L;;;;;N;;;;;
+13C9;CHEROKEE LETTER QUO;Lo;0;L;;;;;N;;;;;
+13CA;CHEROKEE LETTER QUU;Lo;0;L;;;;;N;;;;;
+13CB;CHEROKEE LETTER QUV;Lo;0;L;;;;;N;;;;;
+13CC;CHEROKEE LETTER SA;Lo;0;L;;;;;N;;;;;
+13CD;CHEROKEE LETTER S;Lo;0;L;;;;;N;;;;;
+13CE;CHEROKEE LETTER SE;Lo;0;L;;;;;N;;;;;
+13CF;CHEROKEE LETTER SI;Lo;0;L;;;;;N;;;;;
+13D0;CHEROKEE LETTER SO;Lo;0;L;;;;;N;;;;;
+13D1;CHEROKEE LETTER SU;Lo;0;L;;;;;N;;;;;
+13D2;CHEROKEE LETTER SV;Lo;0;L;;;;;N;;;;;
+13D3;CHEROKEE LETTER DA;Lo;0;L;;;;;N;;;;;
+13D4;CHEROKEE LETTER TA;Lo;0;L;;;;;N;;;;;
+13D5;CHEROKEE LETTER DE;Lo;0;L;;;;;N;;;;;
+13D6;CHEROKEE LETTER TE;Lo;0;L;;;;;N;;;;;
+13D7;CHEROKEE LETTER DI;Lo;0;L;;;;;N;;;;;
+13D8;CHEROKEE LETTER TI;Lo;0;L;;;;;N;;;;;
+13D9;CHEROKEE LETTER DO;Lo;0;L;;;;;N;;;;;
+13DA;CHEROKEE LETTER DU;Lo;0;L;;;;;N;;;;;
+13DB;CHEROKEE LETTER DV;Lo;0;L;;;;;N;;;;;
+13DC;CHEROKEE LETTER DLA;Lo;0;L;;;;;N;;;;;
+13DD;CHEROKEE LETTER TLA;Lo;0;L;;;;;N;;;;;
+13DE;CHEROKEE LETTER TLE;Lo;0;L;;;;;N;;;;;
+13DF;CHEROKEE LETTER TLI;Lo;0;L;;;;;N;;;;;
+13E0;CHEROKEE LETTER TLO;Lo;0;L;;;;;N;;;;;
+13E1;CHEROKEE LETTER TLU;Lo;0;L;;;;;N;;;;;
+13E2;CHEROKEE LETTER TLV;Lo;0;L;;;;;N;;;;;
+13E3;CHEROKEE LETTER TSA;Lo;0;L;;;;;N;;;;;
+13E4;CHEROKEE LETTER TSE;Lo;0;L;;;;;N;;;;;
+13E5;CHEROKEE LETTER TSI;Lo;0;L;;;;;N;;;;;
+13E6;CHEROKEE LETTER TSO;Lo;0;L;;;;;N;;;;;
+13E7;CHEROKEE LETTER TSU;Lo;0;L;;;;;N;;;;;
+13E8;CHEROKEE LETTER TSV;Lo;0;L;;;;;N;;;;;
+13E9;CHEROKEE LETTER WA;Lo;0;L;;;;;N;;;;;
+13EA;CHEROKEE LETTER WE;Lo;0;L;;;;;N;;;;;
+13EB;CHEROKEE LETTER WI;Lo;0;L;;;;;N;;;;;
+13EC;CHEROKEE LETTER WO;Lo;0;L;;;;;N;;;;;
+13ED;CHEROKEE LETTER WU;Lo;0;L;;;;;N;;;;;
+13EE;CHEROKEE LETTER WV;Lo;0;L;;;;;N;;;;;
+13EF;CHEROKEE LETTER YA;Lo;0;L;;;;;N;;;;;
+13F0;CHEROKEE LETTER YE;Lo;0;L;;;;;N;;;;;
+13F1;CHEROKEE LETTER YI;Lo;0;L;;;;;N;;;;;
+13F2;CHEROKEE LETTER YO;Lo;0;L;;;;;N;;;;;
+13F3;CHEROKEE LETTER YU;Lo;0;L;;;;;N;;;;;
+13F4;CHEROKEE LETTER YV;Lo;0;L;;;;;N;;;;;
+1401;CANADIAN SYLLABICS E;Lo;0;L;;;;;N;;;;;
+1402;CANADIAN SYLLABICS AAI;Lo;0;L;;;;;N;;;;;
+1403;CANADIAN SYLLABICS I;Lo;0;L;;;;;N;;;;;
+1404;CANADIAN SYLLABICS II;Lo;0;L;;;;;N;;;;;
+1405;CANADIAN SYLLABICS O;Lo;0;L;;;;;N;;;;;
+1406;CANADIAN SYLLABICS OO;Lo;0;L;;;;;N;;;;;
+1407;CANADIAN SYLLABICS Y-CREE OO;Lo;0;L;;;;;N;;;;;
+1408;CANADIAN SYLLABICS CARRIER EE;Lo;0;L;;;;;N;;;;;
+1409;CANADIAN SYLLABICS CARRIER I;Lo;0;L;;;;;N;;;;;
+140A;CANADIAN SYLLABICS A;Lo;0;L;;;;;N;;;;;
+140B;CANADIAN SYLLABICS AA;Lo;0;L;;;;;N;;;;;
+140C;CANADIAN SYLLABICS WE;Lo;0;L;;;;;N;;;;;
+140D;CANADIAN SYLLABICS WEST-CREE WE;Lo;0;L;;;;;N;;;;;
+140E;CANADIAN SYLLABICS WI;Lo;0;L;;;;;N;;;;;
+140F;CANADIAN SYLLABICS WEST-CREE WI;Lo;0;L;;;;;N;;;;;
+1410;CANADIAN SYLLABICS WII;Lo;0;L;;;;;N;;;;;
+1411;CANADIAN SYLLABICS WEST-CREE WII;Lo;0;L;;;;;N;;;;;
+1412;CANADIAN SYLLABICS WO;Lo;0;L;;;;;N;;;;;
+1413;CANADIAN SYLLABICS WEST-CREE WO;Lo;0;L;;;;;N;;;;;
+1414;CANADIAN SYLLABICS WOO;Lo;0;L;;;;;N;;;;;
+1415;CANADIAN SYLLABICS WEST-CREE WOO;Lo;0;L;;;;;N;;;;;
+1416;CANADIAN SYLLABICS NASKAPI WOO;Lo;0;L;;;;;N;;;;;
+1417;CANADIAN SYLLABICS WA;Lo;0;L;;;;;N;;;;;
+1418;CANADIAN SYLLABICS WEST-CREE WA;Lo;0;L;;;;;N;;;;;
+1419;CANADIAN SYLLABICS WAA;Lo;0;L;;;;;N;;;;;
+141A;CANADIAN SYLLABICS WEST-CREE WAA;Lo;0;L;;;;;N;;;;;
+141B;CANADIAN SYLLABICS NASKAPI WAA;Lo;0;L;;;;;N;;;;;
+141C;CANADIAN SYLLABICS AI;Lo;0;L;;;;;N;;;;;
+141D;CANADIAN SYLLABICS Y-CREE W;Lo;0;L;;;;;N;;;;;
+141E;CANADIAN SYLLABICS GLOTTAL STOP;Lo;0;L;;;;;N;;;;;
+141F;CANADIAN SYLLABICS FINAL ACUTE;Lo;0;L;;;;;N;;;;;
+1420;CANADIAN SYLLABICS FINAL GRAVE;Lo;0;L;;;;;N;;;;;
+1421;CANADIAN SYLLABICS FINAL BOTTOM HALF RING;Lo;0;L;;;;;N;;;;;
+1422;CANADIAN SYLLABICS FINAL TOP HALF RING;Lo;0;L;;;;;N;;;;;
+1423;CANADIAN SYLLABICS FINAL RIGHT HALF RING;Lo;0;L;;;;;N;;;;;
+1424;CANADIAN SYLLABICS FINAL RING;Lo;0;L;;;;;N;;;;;
+1425;CANADIAN SYLLABICS FINAL DOUBLE ACUTE;Lo;0;L;;;;;N;;;;;
+1426;CANADIAN SYLLABICS FINAL DOUBLE SHORT VERTICAL STROKES;Lo;0;L;;;;;N;;;;;
+1427;CANADIAN SYLLABICS FINAL MIDDLE DOT;Lo;0;L;;;;;N;;;;;
+1428;CANADIAN SYLLABICS FINAL SHORT HORIZONTAL STROKE;Lo;0;L;;;;;N;;;;;
+1429;CANADIAN SYLLABICS FINAL PLUS;Lo;0;L;;;;;N;;;;;
+142A;CANADIAN SYLLABICS FINAL DOWN TACK;Lo;0;L;;;;;N;;;;;
+142B;CANADIAN SYLLABICS EN;Lo;0;L;;;;;N;;;;;
+142C;CANADIAN SYLLABICS IN;Lo;0;L;;;;;N;;;;;
+142D;CANADIAN SYLLABICS ON;Lo;0;L;;;;;N;;;;;
+142E;CANADIAN SYLLABICS AN;Lo;0;L;;;;;N;;;;;
+142F;CANADIAN SYLLABICS PE;Lo;0;L;;;;;N;;;;;
+1430;CANADIAN SYLLABICS PAAI;Lo;0;L;;;;;N;;;;;
+1431;CANADIAN SYLLABICS PI;Lo;0;L;;;;;N;;;;;
+1432;CANADIAN SYLLABICS PII;Lo;0;L;;;;;N;;;;;
+1433;CANADIAN SYLLABICS PO;Lo;0;L;;;;;N;;;;;
+1434;CANADIAN SYLLABICS POO;Lo;0;L;;;;;N;;;;;
+1435;CANADIAN SYLLABICS Y-CREE POO;Lo;0;L;;;;;N;;;;;
+1436;CANADIAN SYLLABICS CARRIER HEE;Lo;0;L;;;;;N;;;;;
+1437;CANADIAN SYLLABICS CARRIER HI;Lo;0;L;;;;;N;;;;;
+1438;CANADIAN SYLLABICS PA;Lo;0;L;;;;;N;;;;;
+1439;CANADIAN SYLLABICS PAA;Lo;0;L;;;;;N;;;;;
+143A;CANADIAN SYLLABICS PWE;Lo;0;L;;;;;N;;;;;
+143B;CANADIAN SYLLABICS WEST-CREE PWE;Lo;0;L;;;;;N;;;;;
+143C;CANADIAN SYLLABICS PWI;Lo;0;L;;;;;N;;;;;
+143D;CANADIAN SYLLABICS WEST-CREE PWI;Lo;0;L;;;;;N;;;;;
+143E;CANADIAN SYLLABICS PWII;Lo;0;L;;;;;N;;;;;
+143F;CANADIAN SYLLABICS WEST-CREE PWII;Lo;0;L;;;;;N;;;;;
+1440;CANADIAN SYLLABICS PWO;Lo;0;L;;;;;N;;;;;
+1441;CANADIAN SYLLABICS WEST-CREE PWO;Lo;0;L;;;;;N;;;;;
+1442;CANADIAN SYLLABICS PWOO;Lo;0;L;;;;;N;;;;;
+1443;CANADIAN SYLLABICS WEST-CREE PWOO;Lo;0;L;;;;;N;;;;;
+1444;CANADIAN SYLLABICS PWA;Lo;0;L;;;;;N;;;;;
+1445;CANADIAN SYLLABICS WEST-CREE PWA;Lo;0;L;;;;;N;;;;;
+1446;CANADIAN SYLLABICS PWAA;Lo;0;L;;;;;N;;;;;
+1447;CANADIAN SYLLABICS WEST-CREE PWAA;Lo;0;L;;;;;N;;;;;
+1448;CANADIAN SYLLABICS Y-CREE PWAA;Lo;0;L;;;;;N;;;;;
+1449;CANADIAN SYLLABICS P;Lo;0;L;;;;;N;;;;;
+144A;CANADIAN SYLLABICS WEST-CREE P;Lo;0;L;;;;;N;;;;;
+144B;CANADIAN SYLLABICS CARRIER H;Lo;0;L;;;;;N;;;;;
+144C;CANADIAN SYLLABICS TE;Lo;0;L;;;;;N;;;;;
+144D;CANADIAN SYLLABICS TAAI;Lo;0;L;;;;;N;;;;;
+144E;CANADIAN SYLLABICS TI;Lo;0;L;;;;;N;;;;;
+144F;CANADIAN SYLLABICS TII;Lo;0;L;;;;;N;;;;;
+1450;CANADIAN SYLLABICS TO;Lo;0;L;;;;;N;;;;;
+1451;CANADIAN SYLLABICS TOO;Lo;0;L;;;;;N;;;;;
+1452;CANADIAN SYLLABICS Y-CREE TOO;Lo;0;L;;;;;N;;;;;
+1453;CANADIAN SYLLABICS CARRIER DEE;Lo;0;L;;;;;N;;;;;
+1454;CANADIAN SYLLABICS CARRIER DI;Lo;0;L;;;;;N;;;;;
+1455;CANADIAN SYLLABICS TA;Lo;0;L;;;;;N;;;;;
+1456;CANADIAN SYLLABICS TAA;Lo;0;L;;;;;N;;;;;
+1457;CANADIAN SYLLABICS TWE;Lo;0;L;;;;;N;;;;;
+1458;CANADIAN SYLLABICS WEST-CREE TWE;Lo;0;L;;;;;N;;;;;
+1459;CANADIAN SYLLABICS TWI;Lo;0;L;;;;;N;;;;;
+145A;CANADIAN SYLLABICS WEST-CREE TWI;Lo;0;L;;;;;N;;;;;
+145B;CANADIAN SYLLABICS TWII;Lo;0;L;;;;;N;;;;;
+145C;CANADIAN SYLLABICS WEST-CREE TWII;Lo;0;L;;;;;N;;;;;
+145D;CANADIAN SYLLABICS TWO;Lo;0;L;;;;;N;;;;;
+145E;CANADIAN SYLLABICS WEST-CREE TWO;Lo;0;L;;;;;N;;;;;
+145F;CANADIAN SYLLABICS TWOO;Lo;0;L;;;;;N;;;;;
+1460;CANADIAN SYLLABICS WEST-CREE TWOO;Lo;0;L;;;;;N;;;;;
+1461;CANADIAN SYLLABICS TWA;Lo;0;L;;;;;N;;;;;
+1462;CANADIAN SYLLABICS WEST-CREE TWA;Lo;0;L;;;;;N;;;;;
+1463;CANADIAN SYLLABICS TWAA;Lo;0;L;;;;;N;;;;;
+1464;CANADIAN SYLLABICS WEST-CREE TWAA;Lo;0;L;;;;;N;;;;;
+1465;CANADIAN SYLLABICS NASKAPI TWAA;Lo;0;L;;;;;N;;;;;
+1466;CANADIAN SYLLABICS T;Lo;0;L;;;;;N;;;;;
+1467;CANADIAN SYLLABICS TTE;Lo;0;L;;;;;N;;;;;
+1468;CANADIAN SYLLABICS TTI;Lo;0;L;;;;;N;;;;;
+1469;CANADIAN SYLLABICS TTO;Lo;0;L;;;;;N;;;;;
+146A;CANADIAN SYLLABICS TTA;Lo;0;L;;;;;N;;;;;
+146B;CANADIAN SYLLABICS KE;Lo;0;L;;;;;N;;;;;
+146C;CANADIAN SYLLABICS KAAI;Lo;0;L;;;;;N;;;;;
+146D;CANADIAN SYLLABICS KI;Lo;0;L;;;;;N;;;;;
+146E;CANADIAN SYLLABICS KII;Lo;0;L;;;;;N;;;;;
+146F;CANADIAN SYLLABICS KO;Lo;0;L;;;;;N;;;;;
+1470;CANADIAN SYLLABICS KOO;Lo;0;L;;;;;N;;;;;
+1471;CANADIAN SYLLABICS Y-CREE KOO;Lo;0;L;;;;;N;;;;;
+1472;CANADIAN SYLLABICS KA;Lo;0;L;;;;;N;;;;;
+1473;CANADIAN SYLLABICS KAA;Lo;0;L;;;;;N;;;;;
+1474;CANADIAN SYLLABICS KWE;Lo;0;L;;;;;N;;;;;
+1475;CANADIAN SYLLABICS WEST-CREE KWE;Lo;0;L;;;;;N;;;;;
+1476;CANADIAN SYLLABICS KWI;Lo;0;L;;;;;N;;;;;
+1477;CANADIAN SYLLABICS WEST-CREE KWI;Lo;0;L;;;;;N;;;;;
+1478;CANADIAN SYLLABICS KWII;Lo;0;L;;;;;N;;;;;
+1479;CANADIAN SYLLABICS WEST-CREE KWII;Lo;0;L;;;;;N;;;;;
+147A;CANADIAN SYLLABICS KWO;Lo;0;L;;;;;N;;;;;
+147B;CANADIAN SYLLABICS WEST-CREE KWO;Lo;0;L;;;;;N;;;;;
+147C;CANADIAN SYLLABICS KWOO;Lo;0;L;;;;;N;;;;;
+147D;CANADIAN SYLLABICS WEST-CREE KWOO;Lo;0;L;;;;;N;;;;;
+147E;CANADIAN SYLLABICS KWA;Lo;0;L;;;;;N;;;;;
+147F;CANADIAN SYLLABICS WEST-CREE KWA;Lo;0;L;;;;;N;;;;;
+1480;CANADIAN SYLLABICS KWAA;Lo;0;L;;;;;N;;;;;
+1481;CANADIAN SYLLABICS WEST-CREE KWAA;Lo;0;L;;;;;N;;;;;
+1482;CANADIAN SYLLABICS NASKAPI KWAA;Lo;0;L;;;;;N;;;;;
+1483;CANADIAN SYLLABICS K;Lo;0;L;;;;;N;;;;;
+1484;CANADIAN SYLLABICS KW;Lo;0;L;;;;;N;;;;;
+1485;CANADIAN SYLLABICS SOUTH-SLAVEY KEH;Lo;0;L;;;;;N;;;;;
+1486;CANADIAN SYLLABICS SOUTH-SLAVEY KIH;Lo;0;L;;;;;N;;;;;
+1487;CANADIAN SYLLABICS SOUTH-SLAVEY KOH;Lo;0;L;;;;;N;;;;;
+1488;CANADIAN SYLLABICS SOUTH-SLAVEY KAH;Lo;0;L;;;;;N;;;;;
+1489;CANADIAN SYLLABICS CE;Lo;0;L;;;;;N;;;;;
+148A;CANADIAN SYLLABICS CAAI;Lo;0;L;;;;;N;;;;;
+148B;CANADIAN SYLLABICS CI;Lo;0;L;;;;;N;;;;;
+148C;CANADIAN SYLLABICS CII;Lo;0;L;;;;;N;;;;;
+148D;CANADIAN SYLLABICS CO;Lo;0;L;;;;;N;;;;;
+148E;CANADIAN SYLLABICS COO;Lo;0;L;;;;;N;;;;;
+148F;CANADIAN SYLLABICS Y-CREE COO;Lo;0;L;;;;;N;;;;;
+1490;CANADIAN SYLLABICS CA;Lo;0;L;;;;;N;;;;;
+1491;CANADIAN SYLLABICS CAA;Lo;0;L;;;;;N;;;;;
+1492;CANADIAN SYLLABICS CWE;Lo;0;L;;;;;N;;;;;
+1493;CANADIAN SYLLABICS WEST-CREE CWE;Lo;0;L;;;;;N;;;;;
+1494;CANADIAN SYLLABICS CWI;Lo;0;L;;;;;N;;;;;
+1495;CANADIAN SYLLABICS WEST-CREE CWI;Lo;0;L;;;;;N;;;;;
+1496;CANADIAN SYLLABICS CWII;Lo;0;L;;;;;N;;;;;
+1497;CANADIAN SYLLABICS WEST-CREE CWII;Lo;0;L;;;;;N;;;;;
+1498;CANADIAN SYLLABICS CWO;Lo;0;L;;;;;N;;;;;
+1499;CANADIAN SYLLABICS WEST-CREE CWO;Lo;0;L;;;;;N;;;;;
+149A;CANADIAN SYLLABICS CWOO;Lo;0;L;;;;;N;;;;;
+149B;CANADIAN SYLLABICS WEST-CREE CWOO;Lo;0;L;;;;;N;;;;;
+149C;CANADIAN SYLLABICS CWA;Lo;0;L;;;;;N;;;;;
+149D;CANADIAN SYLLABICS WEST-CREE CWA;Lo;0;L;;;;;N;;;;;
+149E;CANADIAN SYLLABICS CWAA;Lo;0;L;;;;;N;;;;;
+149F;CANADIAN SYLLABICS WEST-CREE CWAA;Lo;0;L;;;;;N;;;;;
+14A0;CANADIAN SYLLABICS NASKAPI CWAA;Lo;0;L;;;;;N;;;;;
+14A1;CANADIAN SYLLABICS C;Lo;0;L;;;;;N;;;;;
+14A2;CANADIAN SYLLABICS SAYISI TH;Lo;0;L;;;;;N;;;;;
+14A3;CANADIAN SYLLABICS ME;Lo;0;L;;;;;N;;;;;
+14A4;CANADIAN SYLLABICS MAAI;Lo;0;L;;;;;N;;;;;
+14A5;CANADIAN SYLLABICS MI;Lo;0;L;;;;;N;;;;;
+14A6;CANADIAN SYLLABICS MII;Lo;0;L;;;;;N;;;;;
+14A7;CANADIAN SYLLABICS MO;Lo;0;L;;;;;N;;;;;
+14A8;CANADIAN SYLLABICS MOO;Lo;0;L;;;;;N;;;;;
+14A9;CANADIAN SYLLABICS Y-CREE MOO;Lo;0;L;;;;;N;;;;;
+14AA;CANADIAN SYLLABICS MA;Lo;0;L;;;;;N;;;;;
+14AB;CANADIAN SYLLABICS MAA;Lo;0;L;;;;;N;;;;;
+14AC;CANADIAN SYLLABICS MWE;Lo;0;L;;;;;N;;;;;
+14AD;CANADIAN SYLLABICS WEST-CREE MWE;Lo;0;L;;;;;N;;;;;
+14AE;CANADIAN SYLLABICS MWI;Lo;0;L;;;;;N;;;;;
+14AF;CANADIAN SYLLABICS WEST-CREE MWI;Lo;0;L;;;;;N;;;;;
+14B0;CANADIAN SYLLABICS MWII;Lo;0;L;;;;;N;;;;;
+14B1;CANADIAN SYLLABICS WEST-CREE MWII;Lo;0;L;;;;;N;;;;;
+14B2;CANADIAN SYLLABICS MWO;Lo;0;L;;;;;N;;;;;
+14B3;CANADIAN SYLLABICS WEST-CREE MWO;Lo;0;L;;;;;N;;;;;
+14B4;CANADIAN SYLLABICS MWOO;Lo;0;L;;;;;N;;;;;
+14B5;CANADIAN SYLLABICS WEST-CREE MWOO;Lo;0;L;;;;;N;;;;;
+14B6;CANADIAN SYLLABICS MWA;Lo;0;L;;;;;N;;;;;
+14B7;CANADIAN SYLLABICS WEST-CREE MWA;Lo;0;L;;;;;N;;;;;
+14B8;CANADIAN SYLLABICS MWAA;Lo;0;L;;;;;N;;;;;
+14B9;CANADIAN SYLLABICS WEST-CREE MWAA;Lo;0;L;;;;;N;;;;;
+14BA;CANADIAN SYLLABICS NASKAPI MWAA;Lo;0;L;;;;;N;;;;;
+14BB;CANADIAN SYLLABICS M;Lo;0;L;;;;;N;;;;;
+14BC;CANADIAN SYLLABICS WEST-CREE M;Lo;0;L;;;;;N;;;;;
+14BD;CANADIAN SYLLABICS MH;Lo;0;L;;;;;N;;;;;
+14BE;CANADIAN SYLLABICS ATHAPASCAN M;Lo;0;L;;;;;N;;;;;
+14BF;CANADIAN SYLLABICS SAYISI M;Lo;0;L;;;;;N;;;;;
+14C0;CANADIAN SYLLABICS NE;Lo;0;L;;;;;N;;;;;
+14C1;CANADIAN SYLLABICS NAAI;Lo;0;L;;;;;N;;;;;
+14C2;CANADIAN SYLLABICS NI;Lo;0;L;;;;;N;;;;;
+14C3;CANADIAN SYLLABICS NII;Lo;0;L;;;;;N;;;;;
+14C4;CANADIAN SYLLABICS NO;Lo;0;L;;;;;N;;;;;
+14C5;CANADIAN SYLLABICS NOO;Lo;0;L;;;;;N;;;;;
+14C6;CANADIAN SYLLABICS Y-CREE NOO;Lo;0;L;;;;;N;;;;;
+14C7;CANADIAN SYLLABICS NA;Lo;0;L;;;;;N;;;;;
+14C8;CANADIAN SYLLABICS NAA;Lo;0;L;;;;;N;;;;;
+14C9;CANADIAN SYLLABICS NWE;Lo;0;L;;;;;N;;;;;
+14CA;CANADIAN SYLLABICS WEST-CREE NWE;Lo;0;L;;;;;N;;;;;
+14CB;CANADIAN SYLLABICS NWA;Lo;0;L;;;;;N;;;;;
+14CC;CANADIAN SYLLABICS WEST-CREE NWA;Lo;0;L;;;;;N;;;;;
+14CD;CANADIAN SYLLABICS NWAA;Lo;0;L;;;;;N;;;;;
+14CE;CANADIAN SYLLABICS WEST-CREE NWAA;Lo;0;L;;;;;N;;;;;
+14CF;CANADIAN SYLLABICS NASKAPI NWAA;Lo;0;L;;;;;N;;;;;
+14D0;CANADIAN SYLLABICS N;Lo;0;L;;;;;N;;;;;
+14D1;CANADIAN SYLLABICS CARRIER NG;Lo;0;L;;;;;N;;;;;
+14D2;CANADIAN SYLLABICS NH;Lo;0;L;;;;;N;;;;;
+14D3;CANADIAN SYLLABICS LE;Lo;0;L;;;;;N;;;;;
+14D4;CANADIAN SYLLABICS LAAI;Lo;0;L;;;;;N;;;;;
+14D5;CANADIAN SYLLABICS LI;Lo;0;L;;;;;N;;;;;
+14D6;CANADIAN SYLLABICS LII;Lo;0;L;;;;;N;;;;;
+14D7;CANADIAN SYLLABICS LO;Lo;0;L;;;;;N;;;;;
+14D8;CANADIAN SYLLABICS LOO;Lo;0;L;;;;;N;;;;;
+14D9;CANADIAN SYLLABICS Y-CREE LOO;Lo;0;L;;;;;N;;;;;
+14DA;CANADIAN SYLLABICS LA;Lo;0;L;;;;;N;;;;;
+14DB;CANADIAN SYLLABICS LAA;Lo;0;L;;;;;N;;;;;
+14DC;CANADIAN SYLLABICS LWE;Lo;0;L;;;;;N;;;;;
+14DD;CANADIAN SYLLABICS WEST-CREE LWE;Lo;0;L;;;;;N;;;;;
+14DE;CANADIAN SYLLABICS LWI;Lo;0;L;;;;;N;;;;;
+14DF;CANADIAN SYLLABICS WEST-CREE LWI;Lo;0;L;;;;;N;;;;;
+14E0;CANADIAN SYLLABICS LWII;Lo;0;L;;;;;N;;;;;
+14E1;CANADIAN SYLLABICS WEST-CREE LWII;Lo;0;L;;;;;N;;;;;
+14E2;CANADIAN SYLLABICS LWO;Lo;0;L;;;;;N;;;;;
+14E3;CANADIAN SYLLABICS WEST-CREE LWO;Lo;0;L;;;;;N;;;;;
+14E4;CANADIAN SYLLABICS LWOO;Lo;0;L;;;;;N;;;;;
+14E5;CANADIAN SYLLABICS WEST-CREE LWOO;Lo;0;L;;;;;N;;;;;
+14E6;CANADIAN SYLLABICS LWA;Lo;0;L;;;;;N;;;;;
+14E7;CANADIAN SYLLABICS WEST-CREE LWA;Lo;0;L;;;;;N;;;;;
+14E8;CANADIAN SYLLABICS LWAA;Lo;0;L;;;;;N;;;;;
+14E9;CANADIAN SYLLABICS WEST-CREE LWAA;Lo;0;L;;;;;N;;;;;
+14EA;CANADIAN SYLLABICS L;Lo;0;L;;;;;N;;;;;
+14EB;CANADIAN SYLLABICS WEST-CREE L;Lo;0;L;;;;;N;;;;;
+14EC;CANADIAN SYLLABICS MEDIAL L;Lo;0;L;;;;;N;;;;;
+14ED;CANADIAN SYLLABICS SE;Lo;0;L;;;;;N;;;;;
+14EE;CANADIAN SYLLABICS SAAI;Lo;0;L;;;;;N;;;;;
+14EF;CANADIAN SYLLABICS SI;Lo;0;L;;;;;N;;;;;
+14F0;CANADIAN SYLLABICS SII;Lo;0;L;;;;;N;;;;;
+14F1;CANADIAN SYLLABICS SO;Lo;0;L;;;;;N;;;;;
+14F2;CANADIAN SYLLABICS SOO;Lo;0;L;;;;;N;;;;;
+14F3;CANADIAN SYLLABICS Y-CREE SOO;Lo;0;L;;;;;N;;;;;
+14F4;CANADIAN SYLLABICS SA;Lo;0;L;;;;;N;;;;;
+14F5;CANADIAN SYLLABICS SAA;Lo;0;L;;;;;N;;;;;
+14F6;CANADIAN SYLLABICS SWE;Lo;0;L;;;;;N;;;;;
+14F7;CANADIAN SYLLABICS WEST-CREE SWE;Lo;0;L;;;;;N;;;;;
+14F8;CANADIAN SYLLABICS SWI;Lo;0;L;;;;;N;;;;;
+14F9;CANADIAN SYLLABICS WEST-CREE SWI;Lo;0;L;;;;;N;;;;;
+14FA;CANADIAN SYLLABICS SWII;Lo;0;L;;;;;N;;;;;
+14FB;CANADIAN SYLLABICS WEST-CREE SWII;Lo;0;L;;;;;N;;;;;
+14FC;CANADIAN SYLLABICS SWO;Lo;0;L;;;;;N;;;;;
+14FD;CANADIAN SYLLABICS WEST-CREE SWO;Lo;0;L;;;;;N;;;;;
+14FE;CANADIAN SYLLABICS SWOO;Lo;0;L;;;;;N;;;;;
+14FF;CANADIAN SYLLABICS WEST-CREE SWOO;Lo;0;L;;;;;N;;;;;
+1500;CANADIAN SYLLABICS SWA;Lo;0;L;;;;;N;;;;;
+1501;CANADIAN SYLLABICS WEST-CREE SWA;Lo;0;L;;;;;N;;;;;
+1502;CANADIAN SYLLABICS SWAA;Lo;0;L;;;;;N;;;;;
+1503;CANADIAN SYLLABICS WEST-CREE SWAA;Lo;0;L;;;;;N;;;;;
+1504;CANADIAN SYLLABICS NASKAPI SWAA;Lo;0;L;;;;;N;;;;;
+1505;CANADIAN SYLLABICS S;Lo;0;L;;;;;N;;;;;
+1506;CANADIAN SYLLABICS ATHAPASCAN S;Lo;0;L;;;;;N;;;;;
+1507;CANADIAN SYLLABICS SW;Lo;0;L;;;;;N;;;;;
+1508;CANADIAN SYLLABICS BLACKFOOT S;Lo;0;L;;;;;N;;;;;
+1509;CANADIAN SYLLABICS MOOSE-CREE SK;Lo;0;L;;;;;N;;;;;
+150A;CANADIAN SYLLABICS NASKAPI SKW;Lo;0;L;;;;;N;;;;;
+150B;CANADIAN SYLLABICS NASKAPI S-W;Lo;0;L;;;;;N;;;;;
+150C;CANADIAN SYLLABICS NASKAPI SPWA;Lo;0;L;;;;;N;;;;;
+150D;CANADIAN SYLLABICS NASKAPI STWA;Lo;0;L;;;;;N;;;;;
+150E;CANADIAN SYLLABICS NASKAPI SKWA;Lo;0;L;;;;;N;;;;;
+150F;CANADIAN SYLLABICS NASKAPI SCWA;Lo;0;L;;;;;N;;;;;
+1510;CANADIAN SYLLABICS SHE;Lo;0;L;;;;;N;;;;;
+1511;CANADIAN SYLLABICS SHI;Lo;0;L;;;;;N;;;;;
+1512;CANADIAN SYLLABICS SHII;Lo;0;L;;;;;N;;;;;
+1513;CANADIAN SYLLABICS SHO;Lo;0;L;;;;;N;;;;;
+1514;CANADIAN SYLLABICS SHOO;Lo;0;L;;;;;N;;;;;
+1515;CANADIAN SYLLABICS SHA;Lo;0;L;;;;;N;;;;;
+1516;CANADIAN SYLLABICS SHAA;Lo;0;L;;;;;N;;;;;
+1517;CANADIAN SYLLABICS SHWE;Lo;0;L;;;;;N;;;;;
+1518;CANADIAN SYLLABICS WEST-CREE SHWE;Lo;0;L;;;;;N;;;;;
+1519;CANADIAN SYLLABICS SHWI;Lo;0;L;;;;;N;;;;;
+151A;CANADIAN SYLLABICS WEST-CREE SHWI;Lo;0;L;;;;;N;;;;;
+151B;CANADIAN SYLLABICS SHWII;Lo;0;L;;;;;N;;;;;
+151C;CANADIAN SYLLABICS WEST-CREE SHWII;Lo;0;L;;;;;N;;;;;
+151D;CANADIAN SYLLABICS SHWO;Lo;0;L;;;;;N;;;;;
+151E;CANADIAN SYLLABICS WEST-CREE SHWO;Lo;0;L;;;;;N;;;;;
+151F;CANADIAN SYLLABICS SHWOO;Lo;0;L;;;;;N;;;;;
+1520;CANADIAN SYLLABICS WEST-CREE SHWOO;Lo;0;L;;;;;N;;;;;
+1521;CANADIAN SYLLABICS SHWA;Lo;0;L;;;;;N;;;;;
+1522;CANADIAN SYLLABICS WEST-CREE SHWA;Lo;0;L;;;;;N;;;;;
+1523;CANADIAN SYLLABICS SHWAA;Lo;0;L;;;;;N;;;;;
+1524;CANADIAN SYLLABICS WEST-CREE SHWAA;Lo;0;L;;;;;N;;;;;
+1525;CANADIAN SYLLABICS SH;Lo;0;L;;;;;N;;;;;
+1526;CANADIAN SYLLABICS YE;Lo;0;L;;;;;N;;;;;
+1527;CANADIAN SYLLABICS YAAI;Lo;0;L;;;;;N;;;;;
+1528;CANADIAN SYLLABICS YI;Lo;0;L;;;;;N;;;;;
+1529;CANADIAN SYLLABICS YII;Lo;0;L;;;;;N;;;;;
+152A;CANADIAN SYLLABICS YO;Lo;0;L;;;;;N;;;;;
+152B;CANADIAN SYLLABICS YOO;Lo;0;L;;;;;N;;;;;
+152C;CANADIAN SYLLABICS Y-CREE YOO;Lo;0;L;;;;;N;;;;;
+152D;CANADIAN SYLLABICS YA;Lo;0;L;;;;;N;;;;;
+152E;CANADIAN SYLLABICS YAA;Lo;0;L;;;;;N;;;;;
+152F;CANADIAN SYLLABICS YWE;Lo;0;L;;;;;N;;;;;
+1530;CANADIAN SYLLABICS WEST-CREE YWE;Lo;0;L;;;;;N;;;;;
+1531;CANADIAN SYLLABICS YWI;Lo;0;L;;;;;N;;;;;
+1532;CANADIAN SYLLABICS WEST-CREE YWI;Lo;0;L;;;;;N;;;;;
+1533;CANADIAN SYLLABICS YWII;Lo;0;L;;;;;N;;;;;
+1534;CANADIAN SYLLABICS WEST-CREE YWII;Lo;0;L;;;;;N;;;;;
+1535;CANADIAN SYLLABICS YWO;Lo;0;L;;;;;N;;;;;
+1536;CANADIAN SYLLABICS WEST-CREE YWO;Lo;0;L;;;;;N;;;;;
+1537;CANADIAN SYLLABICS YWOO;Lo;0;L;;;;;N;;;;;
+1538;CANADIAN SYLLABICS WEST-CREE YWOO;Lo;0;L;;;;;N;;;;;
+1539;CANADIAN SYLLABICS YWA;Lo;0;L;;;;;N;;;;;
+153A;CANADIAN SYLLABICS WEST-CREE YWA;Lo;0;L;;;;;N;;;;;
+153B;CANADIAN SYLLABICS YWAA;Lo;0;L;;;;;N;;;;;
+153C;CANADIAN SYLLABICS WEST-CREE YWAA;Lo;0;L;;;;;N;;;;;
+153D;CANADIAN SYLLABICS NASKAPI YWAA;Lo;0;L;;;;;N;;;;;
+153E;CANADIAN SYLLABICS Y;Lo;0;L;;;;;N;;;;;
+153F;CANADIAN SYLLABICS BIBLE-CREE Y;Lo;0;L;;;;;N;;;;;
+1540;CANADIAN SYLLABICS WEST-CREE Y;Lo;0;L;;;;;N;;;;;
+1541;CANADIAN SYLLABICS SAYISI YI;Lo;0;L;;;;;N;;;;;
+1542;CANADIAN SYLLABICS RE;Lo;0;L;;;;;N;;;;;
+1543;CANADIAN SYLLABICS R-CREE RE;Lo;0;L;;;;;N;;;;;
+1544;CANADIAN SYLLABICS WEST-CREE LE;Lo;0;L;;;;;N;;;;;
+1545;CANADIAN SYLLABICS RAAI;Lo;0;L;;;;;N;;;;;
+1546;CANADIAN SYLLABICS RI;Lo;0;L;;;;;N;;;;;
+1547;CANADIAN SYLLABICS RII;Lo;0;L;;;;;N;;;;;
+1548;CANADIAN SYLLABICS RO;Lo;0;L;;;;;N;;;;;
+1549;CANADIAN SYLLABICS ROO;Lo;0;L;;;;;N;;;;;
+154A;CANADIAN SYLLABICS WEST-CREE LO;Lo;0;L;;;;;N;;;;;
+154B;CANADIAN SYLLABICS RA;Lo;0;L;;;;;N;;;;;
+154C;CANADIAN SYLLABICS RAA;Lo;0;L;;;;;N;;;;;
+154D;CANADIAN SYLLABICS WEST-CREE LA;Lo;0;L;;;;;N;;;;;
+154E;CANADIAN SYLLABICS RWAA;Lo;0;L;;;;;N;;;;;
+154F;CANADIAN SYLLABICS WEST-CREE RWAA;Lo;0;L;;;;;N;;;;;
+1550;CANADIAN SYLLABICS R;Lo;0;L;;;;;N;;;;;
+1551;CANADIAN SYLLABICS WEST-CREE R;Lo;0;L;;;;;N;;;;;
+1552;CANADIAN SYLLABICS MEDIAL R;Lo;0;L;;;;;N;;;;;
+1553;CANADIAN SYLLABICS FE;Lo;0;L;;;;;N;;;;;
+1554;CANADIAN SYLLABICS FAAI;Lo;0;L;;;;;N;;;;;
+1555;CANADIAN SYLLABICS FI;Lo;0;L;;;;;N;;;;;
+1556;CANADIAN SYLLABICS FII;Lo;0;L;;;;;N;;;;;
+1557;CANADIAN SYLLABICS FO;Lo;0;L;;;;;N;;;;;
+1558;CANADIAN SYLLABICS FOO;Lo;0;L;;;;;N;;;;;
+1559;CANADIAN SYLLABICS FA;Lo;0;L;;;;;N;;;;;
+155A;CANADIAN SYLLABICS FAA;Lo;0;L;;;;;N;;;;;
+155B;CANADIAN SYLLABICS FWAA;Lo;0;L;;;;;N;;;;;
+155C;CANADIAN SYLLABICS WEST-CREE FWAA;Lo;0;L;;;;;N;;;;;
+155D;CANADIAN SYLLABICS F;Lo;0;L;;;;;N;;;;;
+155E;CANADIAN SYLLABICS THE;Lo;0;L;;;;;N;;;;;
+155F;CANADIAN SYLLABICS N-CREE THE;Lo;0;L;;;;;N;;;;;
+1560;CANADIAN SYLLABICS THI;Lo;0;L;;;;;N;;;;;
+1561;CANADIAN SYLLABICS N-CREE THI;Lo;0;L;;;;;N;;;;;
+1562;CANADIAN SYLLABICS THII;Lo;0;L;;;;;N;;;;;
+1563;CANADIAN SYLLABICS N-CREE THII;Lo;0;L;;;;;N;;;;;
+1564;CANADIAN SYLLABICS THO;Lo;0;L;;;;;N;;;;;
+1565;CANADIAN SYLLABICS THOO;Lo;0;L;;;;;N;;;;;
+1566;CANADIAN SYLLABICS THA;Lo;0;L;;;;;N;;;;;
+1567;CANADIAN SYLLABICS THAA;Lo;0;L;;;;;N;;;;;
+1568;CANADIAN SYLLABICS THWAA;Lo;0;L;;;;;N;;;;;
+1569;CANADIAN SYLLABICS WEST-CREE THWAA;Lo;0;L;;;;;N;;;;;
+156A;CANADIAN SYLLABICS TH;Lo;0;L;;;;;N;;;;;
+156B;CANADIAN SYLLABICS TTHE;Lo;0;L;;;;;N;;;;;
+156C;CANADIAN SYLLABICS TTHI;Lo;0;L;;;;;N;;;;;
+156D;CANADIAN SYLLABICS TTHO;Lo;0;L;;;;;N;;;;;
+156E;CANADIAN SYLLABICS TTHA;Lo;0;L;;;;;N;;;;;
+156F;CANADIAN SYLLABICS TTH;Lo;0;L;;;;;N;;;;;
+1570;CANADIAN SYLLABICS TYE;Lo;0;L;;;;;N;;;;;
+1571;CANADIAN SYLLABICS TYI;Lo;0;L;;;;;N;;;;;
+1572;CANADIAN SYLLABICS TYO;Lo;0;L;;;;;N;;;;;
+1573;CANADIAN SYLLABICS TYA;Lo;0;L;;;;;N;;;;;
+1574;CANADIAN SYLLABICS NUNAVIK HE;Lo;0;L;;;;;N;;;;;
+1575;CANADIAN SYLLABICS NUNAVIK HI;Lo;0;L;;;;;N;;;;;
+1576;CANADIAN SYLLABICS NUNAVIK HII;Lo;0;L;;;;;N;;;;;
+1577;CANADIAN SYLLABICS NUNAVIK HO;Lo;0;L;;;;;N;;;;;
+1578;CANADIAN SYLLABICS NUNAVIK HOO;Lo;0;L;;;;;N;;;;;
+1579;CANADIAN SYLLABICS NUNAVIK HA;Lo;0;L;;;;;N;;;;;
+157A;CANADIAN SYLLABICS NUNAVIK HAA;Lo;0;L;;;;;N;;;;;
+157B;CANADIAN SYLLABICS NUNAVIK H;Lo;0;L;;;;;N;;;;;
+157C;CANADIAN SYLLABICS NUNAVUT H;Lo;0;L;;;;;N;;;;;
+157D;CANADIAN SYLLABICS HK;Lo;0;L;;;;;N;;;;;
+157E;CANADIAN SYLLABICS QAAI;Lo;0;L;;;;;N;;;;;
+157F;CANADIAN SYLLABICS QI;Lo;0;L;;;;;N;;;;;
+1580;CANADIAN SYLLABICS QII;Lo;0;L;;;;;N;;;;;
+1581;CANADIAN SYLLABICS QO;Lo;0;L;;;;;N;;;;;
+1582;CANADIAN SYLLABICS QOO;Lo;0;L;;;;;N;;;;;
+1583;CANADIAN SYLLABICS QA;Lo;0;L;;;;;N;;;;;
+1584;CANADIAN SYLLABICS QAA;Lo;0;L;;;;;N;;;;;
+1585;CANADIAN SYLLABICS Q;Lo;0;L;;;;;N;;;;;
+1586;CANADIAN SYLLABICS TLHE;Lo;0;L;;;;;N;;;;;
+1587;CANADIAN SYLLABICS TLHI;Lo;0;L;;;;;N;;;;;
+1588;CANADIAN SYLLABICS TLHO;Lo;0;L;;;;;N;;;;;
+1589;CANADIAN SYLLABICS TLHA;Lo;0;L;;;;;N;;;;;
+158A;CANADIAN SYLLABICS WEST-CREE RE;Lo;0;L;;;;;N;;;;;
+158B;CANADIAN SYLLABICS WEST-CREE RI;Lo;0;L;;;;;N;;;;;
+158C;CANADIAN SYLLABICS WEST-CREE RO;Lo;0;L;;;;;N;;;;;
+158D;CANADIAN SYLLABICS WEST-CREE RA;Lo;0;L;;;;;N;;;;;
+158E;CANADIAN SYLLABICS NGAAI;Lo;0;L;;;;;N;;;;;
+158F;CANADIAN SYLLABICS NGI;Lo;0;L;;;;;N;;;;;
+1590;CANADIAN SYLLABICS NGII;Lo;0;L;;;;;N;;;;;
+1591;CANADIAN SYLLABICS NGO;Lo;0;L;;;;;N;;;;;
+1592;CANADIAN SYLLABICS NGOO;Lo;0;L;;;;;N;;;;;
+1593;CANADIAN SYLLABICS NGA;Lo;0;L;;;;;N;;;;;
+1594;CANADIAN SYLLABICS NGAA;Lo;0;L;;;;;N;;;;;
+1595;CANADIAN SYLLABICS NG;Lo;0;L;;;;;N;;;;;
+1596;CANADIAN SYLLABICS NNG;Lo;0;L;;;;;N;;;;;
+1597;CANADIAN SYLLABICS SAYISI SHE;Lo;0;L;;;;;N;;;;;
+1598;CANADIAN SYLLABICS SAYISI SHI;Lo;0;L;;;;;N;;;;;
+1599;CANADIAN SYLLABICS SAYISI SHO;Lo;0;L;;;;;N;;;;;
+159A;CANADIAN SYLLABICS SAYISI SHA;Lo;0;L;;;;;N;;;;;
+159B;CANADIAN SYLLABICS WOODS-CREE THE;Lo;0;L;;;;;N;;;;;
+159C;CANADIAN SYLLABICS WOODS-CREE THI;Lo;0;L;;;;;N;;;;;
+159D;CANADIAN SYLLABICS WOODS-CREE THO;Lo;0;L;;;;;N;;;;;
+159E;CANADIAN SYLLABICS WOODS-CREE THA;Lo;0;L;;;;;N;;;;;
+159F;CANADIAN SYLLABICS WOODS-CREE TH;Lo;0;L;;;;;N;;;;;
+15A0;CANADIAN SYLLABICS LHI;Lo;0;L;;;;;N;;;;;
+15A1;CANADIAN SYLLABICS LHII;Lo;0;L;;;;;N;;;;;
+15A2;CANADIAN SYLLABICS LHO;Lo;0;L;;;;;N;;;;;
+15A3;CANADIAN SYLLABICS LHOO;Lo;0;L;;;;;N;;;;;
+15A4;CANADIAN SYLLABICS LHA;Lo;0;L;;;;;N;;;;;
+15A5;CANADIAN SYLLABICS LHAA;Lo;0;L;;;;;N;;;;;
+15A6;CANADIAN SYLLABICS LH;Lo;0;L;;;;;N;;;;;
+15A7;CANADIAN SYLLABICS TH-CREE THE;Lo;0;L;;;;;N;;;;;
+15A8;CANADIAN SYLLABICS TH-CREE THI;Lo;0;L;;;;;N;;;;;
+15A9;CANADIAN SYLLABICS TH-CREE THII;Lo;0;L;;;;;N;;;;;
+15AA;CANADIAN SYLLABICS TH-CREE THO;Lo;0;L;;;;;N;;;;;
+15AB;CANADIAN SYLLABICS TH-CREE THOO;Lo;0;L;;;;;N;;;;;
+15AC;CANADIAN SYLLABICS TH-CREE THA;Lo;0;L;;;;;N;;;;;
+15AD;CANADIAN SYLLABICS TH-CREE THAA;Lo;0;L;;;;;N;;;;;
+15AE;CANADIAN SYLLABICS TH-CREE TH;Lo;0;L;;;;;N;;;;;
+15AF;CANADIAN SYLLABICS AIVILIK B;Lo;0;L;;;;;N;;;;;
+15B0;CANADIAN SYLLABICS BLACKFOOT E;Lo;0;L;;;;;N;;;;;
+15B1;CANADIAN SYLLABICS BLACKFOOT I;Lo;0;L;;;;;N;;;;;
+15B2;CANADIAN SYLLABICS BLACKFOOT O;Lo;0;L;;;;;N;;;;;
+15B3;CANADIAN SYLLABICS BLACKFOOT A;Lo;0;L;;;;;N;;;;;
+15B4;CANADIAN SYLLABICS BLACKFOOT WE;Lo;0;L;;;;;N;;;;;
+15B5;CANADIAN SYLLABICS BLACKFOOT WI;Lo;0;L;;;;;N;;;;;
+15B6;CANADIAN SYLLABICS BLACKFOOT WO;Lo;0;L;;;;;N;;;;;
+15B7;CANADIAN SYLLABICS BLACKFOOT WA;Lo;0;L;;;;;N;;;;;
+15B8;CANADIAN SYLLABICS BLACKFOOT NE;Lo;0;L;;;;;N;;;;;
+15B9;CANADIAN SYLLABICS BLACKFOOT NI;Lo;0;L;;;;;N;;;;;
+15BA;CANADIAN SYLLABICS BLACKFOOT NO;Lo;0;L;;;;;N;;;;;
+15BB;CANADIAN SYLLABICS BLACKFOOT NA;Lo;0;L;;;;;N;;;;;
+15BC;CANADIAN SYLLABICS BLACKFOOT KE;Lo;0;L;;;;;N;;;;;
+15BD;CANADIAN SYLLABICS BLACKFOOT KI;Lo;0;L;;;;;N;;;;;
+15BE;CANADIAN SYLLABICS BLACKFOOT KO;Lo;0;L;;;;;N;;;;;
+15BF;CANADIAN SYLLABICS BLACKFOOT KA;Lo;0;L;;;;;N;;;;;
+15C0;CANADIAN SYLLABICS SAYISI HE;Lo;0;L;;;;;N;;;;;
+15C1;CANADIAN SYLLABICS SAYISI HI;Lo;0;L;;;;;N;;;;;
+15C2;CANADIAN SYLLABICS SAYISI HO;Lo;0;L;;;;;N;;;;;
+15C3;CANADIAN SYLLABICS SAYISI HA;Lo;0;L;;;;;N;;;;;
+15C4;CANADIAN SYLLABICS CARRIER GHU;Lo;0;L;;;;;N;;;;;
+15C5;CANADIAN SYLLABICS CARRIER GHO;Lo;0;L;;;;;N;;;;;
+15C6;CANADIAN SYLLABICS CARRIER GHE;Lo;0;L;;;;;N;;;;;
+15C7;CANADIAN SYLLABICS CARRIER GHEE;Lo;0;L;;;;;N;;;;;
+15C8;CANADIAN SYLLABICS CARRIER GHI;Lo;0;L;;;;;N;;;;;
+15C9;CANADIAN SYLLABICS CARRIER GHA;Lo;0;L;;;;;N;;;;;
+15CA;CANADIAN SYLLABICS CARRIER RU;Lo;0;L;;;;;N;;;;;
+15CB;CANADIAN SYLLABICS CARRIER RO;Lo;0;L;;;;;N;;;;;
+15CC;CANADIAN SYLLABICS CARRIER RE;Lo;0;L;;;;;N;;;;;
+15CD;CANADIAN SYLLABICS CARRIER REE;Lo;0;L;;;;;N;;;;;
+15CE;CANADIAN SYLLABICS CARRIER RI;Lo;0;L;;;;;N;;;;;
+15CF;CANADIAN SYLLABICS CARRIER RA;Lo;0;L;;;;;N;;;;;
+15D0;CANADIAN SYLLABICS CARRIER WU;Lo;0;L;;;;;N;;;;;
+15D1;CANADIAN SYLLABICS CARRIER WO;Lo;0;L;;;;;N;;;;;
+15D2;CANADIAN SYLLABICS CARRIER WE;Lo;0;L;;;;;N;;;;;
+15D3;CANADIAN SYLLABICS CARRIER WEE;Lo;0;L;;;;;N;;;;;
+15D4;CANADIAN SYLLABICS CARRIER WI;Lo;0;L;;;;;N;;;;;
+15D5;CANADIAN SYLLABICS CARRIER WA;Lo;0;L;;;;;N;;;;;
+15D6;CANADIAN SYLLABICS CARRIER HWU;Lo;0;L;;;;;N;;;;;
+15D7;CANADIAN SYLLABICS CARRIER HWO;Lo;0;L;;;;;N;;;;;
+15D8;CANADIAN SYLLABICS CARRIER HWE;Lo;0;L;;;;;N;;;;;
+15D9;CANADIAN SYLLABICS CARRIER HWEE;Lo;0;L;;;;;N;;;;;
+15DA;CANADIAN SYLLABICS CARRIER HWI;Lo;0;L;;;;;N;;;;;
+15DB;CANADIAN SYLLABICS CARRIER HWA;Lo;0;L;;;;;N;;;;;
+15DC;CANADIAN SYLLABICS CARRIER THU;Lo;0;L;;;;;N;;;;;
+15DD;CANADIAN SYLLABICS CARRIER THO;Lo;0;L;;;;;N;;;;;
+15DE;CANADIAN SYLLABICS CARRIER THE;Lo;0;L;;;;;N;;;;;
+15DF;CANADIAN SYLLABICS CARRIER THEE;Lo;0;L;;;;;N;;;;;
+15E0;CANADIAN SYLLABICS CARRIER THI;Lo;0;L;;;;;N;;;;;
+15E1;CANADIAN SYLLABICS CARRIER THA;Lo;0;L;;;;;N;;;;;
+15E2;CANADIAN SYLLABICS CARRIER TTU;Lo;0;L;;;;;N;;;;;
+15E3;CANADIAN SYLLABICS CARRIER TTO;Lo;0;L;;;;;N;;;;;
+15E4;CANADIAN SYLLABICS CARRIER TTE;Lo;0;L;;;;;N;;;;;
+15E5;CANADIAN SYLLABICS CARRIER TTEE;Lo;0;L;;;;;N;;;;;
+15E6;CANADIAN SYLLABICS CARRIER TTI;Lo;0;L;;;;;N;;;;;
+15E7;CANADIAN SYLLABICS CARRIER TTA;Lo;0;L;;;;;N;;;;;
+15E8;CANADIAN SYLLABICS CARRIER PU;Lo;0;L;;;;;N;;;;;
+15E9;CANADIAN SYLLABICS CARRIER PO;Lo;0;L;;;;;N;;;;;
+15EA;CANADIAN SYLLABICS CARRIER PE;Lo;0;L;;;;;N;;;;;
+15EB;CANADIAN SYLLABICS CARRIER PEE;Lo;0;L;;;;;N;;;;;
+15EC;CANADIAN SYLLABICS CARRIER PI;Lo;0;L;;;;;N;;;;;
+15ED;CANADIAN SYLLABICS CARRIER PA;Lo;0;L;;;;;N;;;;;
+15EE;CANADIAN SYLLABICS CARRIER P;Lo;0;L;;;;;N;;;;;
+15EF;CANADIAN SYLLABICS CARRIER GU;Lo;0;L;;;;;N;;;;;
+15F0;CANADIAN SYLLABICS CARRIER GO;Lo;0;L;;;;;N;;;;;
+15F1;CANADIAN SYLLABICS CARRIER GE;Lo;0;L;;;;;N;;;;;
+15F2;CANADIAN SYLLABICS CARRIER GEE;Lo;0;L;;;;;N;;;;;
+15F3;CANADIAN SYLLABICS CARRIER GI;Lo;0;L;;;;;N;;;;;
+15F4;CANADIAN SYLLABICS CARRIER GA;Lo;0;L;;;;;N;;;;;
+15F5;CANADIAN SYLLABICS CARRIER KHU;Lo;0;L;;;;;N;;;;;
+15F6;CANADIAN SYLLABICS CARRIER KHO;Lo;0;L;;;;;N;;;;;
+15F7;CANADIAN SYLLABICS CARRIER KHE;Lo;0;L;;;;;N;;;;;
+15F8;CANADIAN SYLLABICS CARRIER KHEE;Lo;0;L;;;;;N;;;;;
+15F9;CANADIAN SYLLABICS CARRIER KHI;Lo;0;L;;;;;N;;;;;
+15FA;CANADIAN SYLLABICS CARRIER KHA;Lo;0;L;;;;;N;;;;;
+15FB;CANADIAN SYLLABICS CARRIER KKU;Lo;0;L;;;;;N;;;;;
+15FC;CANADIAN SYLLABICS CARRIER KKO;Lo;0;L;;;;;N;;;;;
+15FD;CANADIAN SYLLABICS CARRIER KKE;Lo;0;L;;;;;N;;;;;
+15FE;CANADIAN SYLLABICS CARRIER KKEE;Lo;0;L;;;;;N;;;;;
+15FF;CANADIAN SYLLABICS CARRIER KKI;Lo;0;L;;;;;N;;;;;
+1600;CANADIAN SYLLABICS CARRIER KKA;Lo;0;L;;;;;N;;;;;
+1601;CANADIAN SYLLABICS CARRIER KK;Lo;0;L;;;;;N;;;;;
+1602;CANADIAN SYLLABICS CARRIER NU;Lo;0;L;;;;;N;;;;;
+1603;CANADIAN SYLLABICS CARRIER NO;Lo;0;L;;;;;N;;;;;
+1604;CANADIAN SYLLABICS CARRIER NE;Lo;0;L;;;;;N;;;;;
+1605;CANADIAN SYLLABICS CARRIER NEE;Lo;0;L;;;;;N;;;;;
+1606;CANADIAN SYLLABICS CARRIER NI;Lo;0;L;;;;;N;;;;;
+1607;CANADIAN SYLLABICS CARRIER NA;Lo;0;L;;;;;N;;;;;
+1608;CANADIAN SYLLABICS CARRIER MU;Lo;0;L;;;;;N;;;;;
+1609;CANADIAN SYLLABICS CARRIER MO;Lo;0;L;;;;;N;;;;;
+160A;CANADIAN SYLLABICS CARRIER ME;Lo;0;L;;;;;N;;;;;
+160B;CANADIAN SYLLABICS CARRIER MEE;Lo;0;L;;;;;N;;;;;
+160C;CANADIAN SYLLABICS CARRIER MI;Lo;0;L;;;;;N;;;;;
+160D;CANADIAN SYLLABICS CARRIER MA;Lo;0;L;;;;;N;;;;;
+160E;CANADIAN SYLLABICS CARRIER YU;Lo;0;L;;;;;N;;;;;
+160F;CANADIAN SYLLABICS CARRIER YO;Lo;0;L;;;;;N;;;;;
+1610;CANADIAN SYLLABICS CARRIER YE;Lo;0;L;;;;;N;;;;;
+1611;CANADIAN SYLLABICS CARRIER YEE;Lo;0;L;;;;;N;;;;;
+1612;CANADIAN SYLLABICS CARRIER YI;Lo;0;L;;;;;N;;;;;
+1613;CANADIAN SYLLABICS CARRIER YA;Lo;0;L;;;;;N;;;;;
+1614;CANADIAN SYLLABICS CARRIER JU;Lo;0;L;;;;;N;;;;;
+1615;CANADIAN SYLLABICS SAYISI JU;Lo;0;L;;;;;N;;;;;
+1616;CANADIAN SYLLABICS CARRIER JO;Lo;0;L;;;;;N;;;;;
+1617;CANADIAN SYLLABICS CARRIER JE;Lo;0;L;;;;;N;;;;;
+1618;CANADIAN SYLLABICS CARRIER JEE;Lo;0;L;;;;;N;;;;;
+1619;CANADIAN SYLLABICS CARRIER JI;Lo;0;L;;;;;N;;;;;
+161A;CANADIAN SYLLABICS SAYISI JI;Lo;0;L;;;;;N;;;;;
+161B;CANADIAN SYLLABICS CARRIER JA;Lo;0;L;;;;;N;;;;;
+161C;CANADIAN SYLLABICS CARRIER JJU;Lo;0;L;;;;;N;;;;;
+161D;CANADIAN SYLLABICS CARRIER JJO;Lo;0;L;;;;;N;;;;;
+161E;CANADIAN SYLLABICS CARRIER JJE;Lo;0;L;;;;;N;;;;;
+161F;CANADIAN SYLLABICS CARRIER JJEE;Lo;0;L;;;;;N;;;;;
+1620;CANADIAN SYLLABICS CARRIER JJI;Lo;0;L;;;;;N;;;;;
+1621;CANADIAN SYLLABICS CARRIER JJA;Lo;0;L;;;;;N;;;;;
+1622;CANADIAN SYLLABICS CARRIER LU;Lo;0;L;;;;;N;;;;;
+1623;CANADIAN SYLLABICS CARRIER LO;Lo;0;L;;;;;N;;;;;
+1624;CANADIAN SYLLABICS CARRIER LE;Lo;0;L;;;;;N;;;;;
+1625;CANADIAN SYLLABICS CARRIER LEE;Lo;0;L;;;;;N;;;;;
+1626;CANADIAN SYLLABICS CARRIER LI;Lo;0;L;;;;;N;;;;;
+1627;CANADIAN SYLLABICS CARRIER LA;Lo;0;L;;;;;N;;;;;
+1628;CANADIAN SYLLABICS CARRIER DLU;Lo;0;L;;;;;N;;;;;
+1629;CANADIAN SYLLABICS CARRIER DLO;Lo;0;L;;;;;N;;;;;
+162A;CANADIAN SYLLABICS CARRIER DLE;Lo;0;L;;;;;N;;;;;
+162B;CANADIAN SYLLABICS CARRIER DLEE;Lo;0;L;;;;;N;;;;;
+162C;CANADIAN SYLLABICS CARRIER DLI;Lo;0;L;;;;;N;;;;;
+162D;CANADIAN SYLLABICS CARRIER DLA;Lo;0;L;;;;;N;;;;;
+162E;CANADIAN SYLLABICS CARRIER LHU;Lo;0;L;;;;;N;;;;;
+162F;CANADIAN SYLLABICS CARRIER LHO;Lo;0;L;;;;;N;;;;;
+1630;CANADIAN SYLLABICS CARRIER LHE;Lo;0;L;;;;;N;;;;;
+1631;CANADIAN SYLLABICS CARRIER LHEE;Lo;0;L;;;;;N;;;;;
+1632;CANADIAN SYLLABICS CARRIER LHI;Lo;0;L;;;;;N;;;;;
+1633;CANADIAN SYLLABICS CARRIER LHA;Lo;0;L;;;;;N;;;;;
+1634;CANADIAN SYLLABICS CARRIER TLHU;Lo;0;L;;;;;N;;;;;
+1635;CANADIAN SYLLABICS CARRIER TLHO;Lo;0;L;;;;;N;;;;;
+1636;CANADIAN SYLLABICS CARRIER TLHE;Lo;0;L;;;;;N;;;;;
+1637;CANADIAN SYLLABICS CARRIER TLHEE;Lo;0;L;;;;;N;;;;;
+1638;CANADIAN SYLLABICS CARRIER TLHI;Lo;0;L;;;;;N;;;;;
+1639;CANADIAN SYLLABICS CARRIER TLHA;Lo;0;L;;;;;N;;;;;
+163A;CANADIAN SYLLABICS CARRIER TLU;Lo;0;L;;;;;N;;;;;
+163B;CANADIAN SYLLABICS CARRIER TLO;Lo;0;L;;;;;N;;;;;
+163C;CANADIAN SYLLABICS CARRIER TLE;Lo;0;L;;;;;N;;;;;
+163D;CANADIAN SYLLABICS CARRIER TLEE;Lo;0;L;;;;;N;;;;;
+163E;CANADIAN SYLLABICS CARRIER TLI;Lo;0;L;;;;;N;;;;;
+163F;CANADIAN SYLLABICS CARRIER TLA;Lo;0;L;;;;;N;;;;;
+1640;CANADIAN SYLLABICS CARRIER ZU;Lo;0;L;;;;;N;;;;;
+1641;CANADIAN SYLLABICS CARRIER ZO;Lo;0;L;;;;;N;;;;;
+1642;CANADIAN SYLLABICS CARRIER ZE;Lo;0;L;;;;;N;;;;;
+1643;CANADIAN SYLLABICS CARRIER ZEE;Lo;0;L;;;;;N;;;;;
+1644;CANADIAN SYLLABICS CARRIER ZI;Lo;0;L;;;;;N;;;;;
+1645;CANADIAN SYLLABICS CARRIER ZA;Lo;0;L;;;;;N;;;;;
+1646;CANADIAN SYLLABICS CARRIER Z;Lo;0;L;;;;;N;;;;;
+1647;CANADIAN SYLLABICS CARRIER INITIAL Z;Lo;0;L;;;;;N;;;;;
+1648;CANADIAN SYLLABICS CARRIER DZU;Lo;0;L;;;;;N;;;;;
+1649;CANADIAN SYLLABICS CARRIER DZO;Lo;0;L;;;;;N;;;;;
+164A;CANADIAN SYLLABICS CARRIER DZE;Lo;0;L;;;;;N;;;;;
+164B;CANADIAN SYLLABICS CARRIER DZEE;Lo;0;L;;;;;N;;;;;
+164C;CANADIAN SYLLABICS CARRIER DZI;Lo;0;L;;;;;N;;;;;
+164D;CANADIAN SYLLABICS CARRIER DZA;Lo;0;L;;;;;N;;;;;
+164E;CANADIAN SYLLABICS CARRIER SU;Lo;0;L;;;;;N;;;;;
+164F;CANADIAN SYLLABICS CARRIER SO;Lo;0;L;;;;;N;;;;;
+1650;CANADIAN SYLLABICS CARRIER SE;Lo;0;L;;;;;N;;;;;
+1651;CANADIAN SYLLABICS CARRIER SEE;Lo;0;L;;;;;N;;;;;
+1652;CANADIAN SYLLABICS CARRIER SI;Lo;0;L;;;;;N;;;;;
+1653;CANADIAN SYLLABICS CARRIER SA;Lo;0;L;;;;;N;;;;;
+1654;CANADIAN SYLLABICS CARRIER SHU;Lo;0;L;;;;;N;;;;;
+1655;CANADIAN SYLLABICS CARRIER SHO;Lo;0;L;;;;;N;;;;;
+1656;CANADIAN SYLLABICS CARRIER SHE;Lo;0;L;;;;;N;;;;;
+1657;CANADIAN SYLLABICS CARRIER SHEE;Lo;0;L;;;;;N;;;;;
+1658;CANADIAN SYLLABICS CARRIER SHI;Lo;0;L;;;;;N;;;;;
+1659;CANADIAN SYLLABICS CARRIER SHA;Lo;0;L;;;;;N;;;;;
+165A;CANADIAN SYLLABICS CARRIER SH;Lo;0;L;;;;;N;;;;;
+165B;CANADIAN SYLLABICS CARRIER TSU;Lo;0;L;;;;;N;;;;;
+165C;CANADIAN SYLLABICS CARRIER TSO;Lo;0;L;;;;;N;;;;;
+165D;CANADIAN SYLLABICS CARRIER TSE;Lo;0;L;;;;;N;;;;;
+165E;CANADIAN SYLLABICS CARRIER TSEE;Lo;0;L;;;;;N;;;;;
+165F;CANADIAN SYLLABICS CARRIER TSI;Lo;0;L;;;;;N;;;;;
+1660;CANADIAN SYLLABICS CARRIER TSA;Lo;0;L;;;;;N;;;;;
+1661;CANADIAN SYLLABICS CARRIER CHU;Lo;0;L;;;;;N;;;;;
+1662;CANADIAN SYLLABICS CARRIER CHO;Lo;0;L;;;;;N;;;;;
+1663;CANADIAN SYLLABICS CARRIER CHE;Lo;0;L;;;;;N;;;;;
+1664;CANADIAN SYLLABICS CARRIER CHEE;Lo;0;L;;;;;N;;;;;
+1665;CANADIAN SYLLABICS CARRIER CHI;Lo;0;L;;;;;N;;;;;
+1666;CANADIAN SYLLABICS CARRIER CHA;Lo;0;L;;;;;N;;;;;
+1667;CANADIAN SYLLABICS CARRIER TTSU;Lo;0;L;;;;;N;;;;;
+1668;CANADIAN SYLLABICS CARRIER TTSO;Lo;0;L;;;;;N;;;;;
+1669;CANADIAN SYLLABICS CARRIER TTSE;Lo;0;L;;;;;N;;;;;
+166A;CANADIAN SYLLABICS CARRIER TTSEE;Lo;0;L;;;;;N;;;;;
+166B;CANADIAN SYLLABICS CARRIER TTSI;Lo;0;L;;;;;N;;;;;
+166C;CANADIAN SYLLABICS CARRIER TTSA;Lo;0;L;;;;;N;;;;;
+166D;CANADIAN SYLLABICS CHI SIGN;Po;0;L;;;;;N;;;;;
+166E;CANADIAN SYLLABICS FULL STOP;Po;0;L;;;;;N;;;;;
+166F;CANADIAN SYLLABICS QAI;Lo;0;L;;;;;N;;;;;
+1670;CANADIAN SYLLABICS NGAI;Lo;0;L;;;;;N;;;;;
+1671;CANADIAN SYLLABICS NNGI;Lo;0;L;;;;;N;;;;;
+1672;CANADIAN SYLLABICS NNGII;Lo;0;L;;;;;N;;;;;
+1673;CANADIAN SYLLABICS NNGO;Lo;0;L;;;;;N;;;;;
+1674;CANADIAN SYLLABICS NNGOO;Lo;0;L;;;;;N;;;;;
+1675;CANADIAN SYLLABICS NNGA;Lo;0;L;;;;;N;;;;;
+1676;CANADIAN SYLLABICS NNGAA;Lo;0;L;;;;;N;;;;;
+1680;OGHAM SPACE MARK;Zs;0;WS;;;;;N;;;;;
+1681;OGHAM LETTER BEITH;Lo;0;L;;;;;N;;;;;
+1682;OGHAM LETTER LUIS;Lo;0;L;;;;;N;;;;;
+1683;OGHAM LETTER FEARN;Lo;0;L;;;;;N;;;;;
+1684;OGHAM LETTER SAIL;Lo;0;L;;;;;N;;;;;
+1685;OGHAM LETTER NION;Lo;0;L;;;;;N;;;;;
+1686;OGHAM LETTER UATH;Lo;0;L;;;;;N;;;;;
+1687;OGHAM LETTER DAIR;Lo;0;L;;;;;N;;;;;
+1688;OGHAM LETTER TINNE;Lo;0;L;;;;;N;;;;;
+1689;OGHAM LETTER COLL;Lo;0;L;;;;;N;;;;;
+168A;OGHAM LETTER CEIRT;Lo;0;L;;;;;N;;;;;
+168B;OGHAM LETTER MUIN;Lo;0;L;;;;;N;;;;;
+168C;OGHAM LETTER GORT;Lo;0;L;;;;;N;;;;;
+168D;OGHAM LETTER NGEADAL;Lo;0;L;;;;;N;;;;;
+168E;OGHAM LETTER STRAIF;Lo;0;L;;;;;N;;;;;
+168F;OGHAM LETTER RUIS;Lo;0;L;;;;;N;;;;;
+1690;OGHAM LETTER AILM;Lo;0;L;;;;;N;;;;;
+1691;OGHAM LETTER ONN;Lo;0;L;;;;;N;;;;;
+1692;OGHAM LETTER UR;Lo;0;L;;;;;N;;;;;
+1693;OGHAM LETTER EADHADH;Lo;0;L;;;;;N;;;;;
+1694;OGHAM LETTER IODHADH;Lo;0;L;;;;;N;;;;;
+1695;OGHAM LETTER EABHADH;Lo;0;L;;;;;N;;;;;
+1696;OGHAM LETTER OR;Lo;0;L;;;;;N;;;;;
+1697;OGHAM LETTER UILLEANN;Lo;0;L;;;;;N;;;;;
+1698;OGHAM LETTER IFIN;Lo;0;L;;;;;N;;;;;
+1699;OGHAM LETTER EAMHANCHOLL;Lo;0;L;;;;;N;;;;;
+169A;OGHAM LETTER PEITH;Lo;0;L;;;;;N;;;;;
+169B;OGHAM FEATHER MARK;Ps;0;ON;;;;;N;;;;;
+169C;OGHAM REVERSED FEATHER MARK;Pe;0;ON;;;;;N;;;;;
+16A0;RUNIC LETTER FEHU FEOH FE F;Lo;0;L;;;;;N;;;;;
+16A1;RUNIC LETTER V;Lo;0;L;;;;;N;;;;;
+16A2;RUNIC LETTER URUZ UR U;Lo;0;L;;;;;N;;;;;
+16A3;RUNIC LETTER YR;Lo;0;L;;;;;N;;;;;
+16A4;RUNIC LETTER Y;Lo;0;L;;;;;N;;;;;
+16A5;RUNIC LETTER W;Lo;0;L;;;;;N;;;;;
+16A6;RUNIC LETTER THURISAZ THURS THORN;Lo;0;L;;;;;N;;;;;
+16A7;RUNIC LETTER ETH;Lo;0;L;;;;;N;;;;;
+16A8;RUNIC LETTER ANSUZ A;Lo;0;L;;;;;N;;;;;
+16A9;RUNIC LETTER OS O;Lo;0;L;;;;;N;;;;;
+16AA;RUNIC LETTER AC A;Lo;0;L;;;;;N;;;;;
+16AB;RUNIC LETTER AESC;Lo;0;L;;;;;N;;;;;
+16AC;RUNIC LETTER LONG-BRANCH-OSS O;Lo;0;L;;;;;N;;;;;
+16AD;RUNIC LETTER SHORT-TWIG-OSS O;Lo;0;L;;;;;N;;;;;
+16AE;RUNIC LETTER O;Lo;0;L;;;;;N;;;;;
+16AF;RUNIC LETTER OE;Lo;0;L;;;;;N;;;;;
+16B0;RUNIC LETTER ON;Lo;0;L;;;;;N;;;;;
+16B1;RUNIC LETTER RAIDO RAD REID R;Lo;0;L;;;;;N;;;;;
+16B2;RUNIC LETTER KAUNA;Lo;0;L;;;;;N;;;;;
+16B3;RUNIC LETTER CEN;Lo;0;L;;;;;N;;;;;
+16B4;RUNIC LETTER KAUN K;Lo;0;L;;;;;N;;;;;
+16B5;RUNIC LETTER G;Lo;0;L;;;;;N;;;;;
+16B6;RUNIC LETTER ENG;Lo;0;L;;;;;N;;;;;
+16B7;RUNIC LETTER GEBO GYFU G;Lo;0;L;;;;;N;;;;;
+16B8;RUNIC LETTER GAR;Lo;0;L;;;;;N;;;;;
+16B9;RUNIC LETTER WUNJO WYNN W;Lo;0;L;;;;;N;;;;;
+16BA;RUNIC LETTER HAGLAZ H;Lo;0;L;;;;;N;;;;;
+16BB;RUNIC LETTER HAEGL H;Lo;0;L;;;;;N;;;;;
+16BC;RUNIC LETTER LONG-BRANCH-HAGALL H;Lo;0;L;;;;;N;;;;;
+16BD;RUNIC LETTER SHORT-TWIG-HAGALL H;Lo;0;L;;;;;N;;;;;
+16BE;RUNIC LETTER NAUDIZ NYD NAUD N;Lo;0;L;;;;;N;;;;;
+16BF;RUNIC LETTER SHORT-TWIG-NAUD N;Lo;0;L;;;;;N;;;;;
+16C0;RUNIC LETTER DOTTED-N;Lo;0;L;;;;;N;;;;;
+16C1;RUNIC LETTER ISAZ IS ISS I;Lo;0;L;;;;;N;;;;;
+16C2;RUNIC LETTER E;Lo;0;L;;;;;N;;;;;
+16C3;RUNIC LETTER JERAN J;Lo;0;L;;;;;N;;;;;
+16C4;RUNIC LETTER GER;Lo;0;L;;;;;N;;;;;
+16C5;RUNIC LETTER LONG-BRANCH-AR AE;Lo;0;L;;;;;N;;;;;
+16C6;RUNIC LETTER SHORT-TWIG-AR A;Lo;0;L;;;;;N;;;;;
+16C7;RUNIC LETTER IWAZ EOH;Lo;0;L;;;;;N;;;;;
+16C8;RUNIC LETTER PERTHO PEORTH P;Lo;0;L;;;;;N;;;;;
+16C9;RUNIC LETTER ALGIZ EOLHX;Lo;0;L;;;;;N;;;;;
+16CA;RUNIC LETTER SOWILO S;Lo;0;L;;;;;N;;;;;
+16CB;RUNIC LETTER SIGEL LONG-BRANCH-SOL S;Lo;0;L;;;;;N;;;;;
+16CC;RUNIC LETTER SHORT-TWIG-SOL S;Lo;0;L;;;;;N;;;;;
+16CD;RUNIC LETTER C;Lo;0;L;;;;;N;;;;;
+16CE;RUNIC LETTER Z;Lo;0;L;;;;;N;;;;;
+16CF;RUNIC LETTER TIWAZ TIR TYR T;Lo;0;L;;;;;N;;;;;
+16D0;RUNIC LETTER SHORT-TWIG-TYR T;Lo;0;L;;;;;N;;;;;
+16D1;RUNIC LETTER D;Lo;0;L;;;;;N;;;;;
+16D2;RUNIC LETTER BERKANAN BEORC BJARKAN B;Lo;0;L;;;;;N;;;;;
+16D3;RUNIC LETTER SHORT-TWIG-BJARKAN B;Lo;0;L;;;;;N;;;;;
+16D4;RUNIC LETTER DOTTED-P;Lo;0;L;;;;;N;;;;;
+16D5;RUNIC LETTER OPEN-P;Lo;0;L;;;;;N;;;;;
+16D6;RUNIC LETTER EHWAZ EH E;Lo;0;L;;;;;N;;;;;
+16D7;RUNIC LETTER MANNAZ MAN M;Lo;0;L;;;;;N;;;;;
+16D8;RUNIC LETTER LONG-BRANCH-MADR M;Lo;0;L;;;;;N;;;;;
+16D9;RUNIC LETTER SHORT-TWIG-MADR M;Lo;0;L;;;;;N;;;;;
+16DA;RUNIC LETTER LAUKAZ LAGU LOGR L;Lo;0;L;;;;;N;;;;;
+16DB;RUNIC LETTER DOTTED-L;Lo;0;L;;;;;N;;;;;
+16DC;RUNIC LETTER INGWAZ;Lo;0;L;;;;;N;;;;;
+16DD;RUNIC LETTER ING;Lo;0;L;;;;;N;;;;;
+16DE;RUNIC LETTER DAGAZ DAEG D;Lo;0;L;;;;;N;;;;;
+16DF;RUNIC LETTER OTHALAN ETHEL O;Lo;0;L;;;;;N;;;;;
+16E0;RUNIC LETTER EAR;Lo;0;L;;;;;N;;;;;
+16E1;RUNIC LETTER IOR;Lo;0;L;;;;;N;;;;;
+16E2;RUNIC LETTER CWEORTH;Lo;0;L;;;;;N;;;;;
+16E3;RUNIC LETTER CALC;Lo;0;L;;;;;N;;;;;
+16E4;RUNIC LETTER CEALC;Lo;0;L;;;;;N;;;;;
+16E5;RUNIC LETTER STAN;Lo;0;L;;;;;N;;;;;
+16E6;RUNIC LETTER LONG-BRANCH-YR;Lo;0;L;;;;;N;;;;;
+16E7;RUNIC LETTER SHORT-TWIG-YR;Lo;0;L;;;;;N;;;;;
+16E8;RUNIC LETTER ICELANDIC-YR;Lo;0;L;;;;;N;;;;;
+16E9;RUNIC LETTER Q;Lo;0;L;;;;;N;;;;;
+16EA;RUNIC LETTER X;Lo;0;L;;;;;N;;;;;
+16EB;RUNIC SINGLE PUNCTUATION;Po;0;L;;;;;N;;;;;
+16EC;RUNIC MULTIPLE PUNCTUATION;Po;0;L;;;;;N;;;;;
+16ED;RUNIC CROSS PUNCTUATION;Po;0;L;;;;;N;;;;;
+16EE;RUNIC ARLAUG SYMBOL;Nl;0;L;;;;17;N;;golden number 17;;;
+16EF;RUNIC TVIMADUR SYMBOL;Nl;0;L;;;;18;N;;golden number 18;;;
+16F0;RUNIC BELGTHOR SYMBOL;Nl;0;L;;;;19;N;;golden number 19;;;
+1700;TAGALOG LETTER A;Lo;0;L;;;;;N;;;;;
+1701;TAGALOG LETTER I;Lo;0;L;;;;;N;;;;;
+1702;TAGALOG LETTER U;Lo;0;L;;;;;N;;;;;
+1703;TAGALOG LETTER KA;Lo;0;L;;;;;N;;;;;
+1704;TAGALOG LETTER GA;Lo;0;L;;;;;N;;;;;
+1705;TAGALOG LETTER NGA;Lo;0;L;;;;;N;;;;;
+1706;TAGALOG LETTER TA;Lo;0;L;;;;;N;;;;;
+1707;TAGALOG LETTER DA;Lo;0;L;;;;;N;;;;;
+1708;TAGALOG LETTER NA;Lo;0;L;;;;;N;;;;;
+1709;TAGALOG LETTER PA;Lo;0;L;;;;;N;;;;;
+170A;TAGALOG LETTER BA;Lo;0;L;;;;;N;;;;;
+170B;TAGALOG LETTER MA;Lo;0;L;;;;;N;;;;;
+170C;TAGALOG LETTER YA;Lo;0;L;;;;;N;;;;;
+170E;TAGALOG LETTER LA;Lo;0;L;;;;;N;;;;;
+170F;TAGALOG LETTER WA;Lo;0;L;;;;;N;;;;;
+1710;TAGALOG LETTER SA;Lo;0;L;;;;;N;;;;;
+1711;TAGALOG LETTER HA;Lo;0;L;;;;;N;;;;;
+1712;TAGALOG VOWEL SIGN I;Mn;0;NSM;;;;;N;;;;;
+1713;TAGALOG VOWEL SIGN U;Mn;0;NSM;;;;;N;;;;;
+1714;TAGALOG SIGN VIRAMA;Mn;9;NSM;;;;;N;;;;;
+1720;HANUNOO LETTER A;Lo;0;L;;;;;N;;;;;
+1721;HANUNOO LETTER I;Lo;0;L;;;;;N;;;;;
+1722;HANUNOO LETTER U;Lo;0;L;;;;;N;;;;;
+1723;HANUNOO LETTER KA;Lo;0;L;;;;;N;;;;;
+1724;HANUNOO LETTER GA;Lo;0;L;;;;;N;;;;;
+1725;HANUNOO LETTER NGA;Lo;0;L;;;;;N;;;;;
+1726;HANUNOO LETTER TA;Lo;0;L;;;;;N;;;;;
+1727;HANUNOO LETTER DA;Lo;0;L;;;;;N;;;;;
+1728;HANUNOO LETTER NA;Lo;0;L;;;;;N;;;;;
+1729;HANUNOO LETTER PA;Lo;0;L;;;;;N;;;;;
+172A;HANUNOO LETTER BA;Lo;0;L;;;;;N;;;;;
+172B;HANUNOO LETTER MA;Lo;0;L;;;;;N;;;;;
+172C;HANUNOO LETTER YA;Lo;0;L;;;;;N;;;;;
+172D;HANUNOO LETTER RA;Lo;0;L;;;;;N;;;;;
+172E;HANUNOO LETTER LA;Lo;0;L;;;;;N;;;;;
+172F;HANUNOO LETTER WA;Lo;0;L;;;;;N;;;;;
+1730;HANUNOO LETTER SA;Lo;0;L;;;;;N;;;;;
+1731;HANUNOO LETTER HA;Lo;0;L;;;;;N;;;;;
+1732;HANUNOO VOWEL SIGN I;Mn;0;NSM;;;;;N;;;;;
+1733;HANUNOO VOWEL SIGN U;Mn;0;NSM;;;;;N;;;;;
+1734;HANUNOO SIGN PAMUDPOD;Mn;9;NSM;;;;;N;;;;;
+1735;PHILIPPINE SINGLE PUNCTUATION;Po;0;L;;;;;N;;;;;
+1736;PHILIPPINE DOUBLE PUNCTUATION;Po;0;L;;;;;N;;;;;
+1740;BUHID LETTER A;Lo;0;L;;;;;N;;;;;
+1741;BUHID LETTER I;Lo;0;L;;;;;N;;;;;
+1742;BUHID LETTER U;Lo;0;L;;;;;N;;;;;
+1743;BUHID LETTER KA;Lo;0;L;;;;;N;;;;;
+1744;BUHID LETTER GA;Lo;0;L;;;;;N;;;;;
+1745;BUHID LETTER NGA;Lo;0;L;;;;;N;;;;;
+1746;BUHID LETTER TA;Lo;0;L;;;;;N;;;;;
+1747;BUHID LETTER DA;Lo;0;L;;;;;N;;;;;
+1748;BUHID LETTER NA;Lo;0;L;;;;;N;;;;;
+1749;BUHID LETTER PA;Lo;0;L;;;;;N;;;;;
+174A;BUHID LETTER BA;Lo;0;L;;;;;N;;;;;
+174B;BUHID LETTER MA;Lo;0;L;;;;;N;;;;;
+174C;BUHID LETTER YA;Lo;0;L;;;;;N;;;;;
+174D;BUHID LETTER RA;Lo;0;L;;;;;N;;;;;
+174E;BUHID LETTER LA;Lo;0;L;;;;;N;;;;;
+174F;BUHID LETTER WA;Lo;0;L;;;;;N;;;;;
+1750;BUHID LETTER SA;Lo;0;L;;;;;N;;;;;
+1751;BUHID LETTER HA;Lo;0;L;;;;;N;;;;;
+1752;BUHID VOWEL SIGN I;Mn;0;NSM;;;;;N;;;;;
+1753;BUHID VOWEL SIGN U;Mn;0;NSM;;;;;N;;;;;
+1760;TAGBANWA LETTER A;Lo;0;L;;;;;N;;;;;
+1761;TAGBANWA LETTER I;Lo;0;L;;;;;N;;;;;
+1762;TAGBANWA LETTER U;Lo;0;L;;;;;N;;;;;
+1763;TAGBANWA LETTER KA;Lo;0;L;;;;;N;;;;;
+1764;TAGBANWA LETTER GA;Lo;0;L;;;;;N;;;;;
+1765;TAGBANWA LETTER NGA;Lo;0;L;;;;;N;;;;;
+1766;TAGBANWA LETTER TA;Lo;0;L;;;;;N;;;;;
+1767;TAGBANWA LETTER DA;Lo;0;L;;;;;N;;;;;
+1768;TAGBANWA LETTER NA;Lo;0;L;;;;;N;;;;;
+1769;TAGBANWA LETTER PA;Lo;0;L;;;;;N;;;;;
+176A;TAGBANWA LETTER BA;Lo;0;L;;;;;N;;;;;
+176B;TAGBANWA LETTER MA;Lo;0;L;;;;;N;;;;;
+176C;TAGBANWA LETTER YA;Lo;0;L;;;;;N;;;;;
+176E;TAGBANWA LETTER LA;Lo;0;L;;;;;N;;;;;
+176F;TAGBANWA LETTER WA;Lo;0;L;;;;;N;;;;;
+1770;TAGBANWA LETTER SA;Lo;0;L;;;;;N;;;;;
+1772;TAGBANWA VOWEL SIGN I;Mn;0;NSM;;;;;N;;;;;
+1773;TAGBANWA VOWEL SIGN U;Mn;0;NSM;;;;;N;;;;;
+1780;KHMER LETTER KA;Lo;0;L;;;;;N;;;;;
+1781;KHMER LETTER KHA;Lo;0;L;;;;;N;;;;;
+1782;KHMER LETTER KO;Lo;0;L;;;;;N;;;;;
+1783;KHMER LETTER KHO;Lo;0;L;;;;;N;;;;;
+1784;KHMER LETTER NGO;Lo;0;L;;;;;N;;;;;
+1785;KHMER LETTER CA;Lo;0;L;;;;;N;;;;;
+1786;KHMER LETTER CHA;Lo;0;L;;;;;N;;;;;
+1787;KHMER LETTER CO;Lo;0;L;;;;;N;;;;;
+1788;KHMER LETTER CHO;Lo;0;L;;;;;N;;;;;
+1789;KHMER LETTER NYO;Lo;0;L;;;;;N;;;;;
+178A;KHMER LETTER DA;Lo;0;L;;;;;N;;;;;
+178B;KHMER LETTER TTHA;Lo;0;L;;;;;N;;;;;
+178C;KHMER LETTER DO;Lo;0;L;;;;;N;;;;;
+178D;KHMER LETTER TTHO;Lo;0;L;;;;;N;;;;;
+178E;KHMER LETTER NNO;Lo;0;L;;;;;N;;;;;
+178F;KHMER LETTER TA;Lo;0;L;;;;;N;;;;;
+1790;KHMER LETTER THA;Lo;0;L;;;;;N;;;;;
+1791;KHMER LETTER TO;Lo;0;L;;;;;N;;;;;
+1792;KHMER LETTER THO;Lo;0;L;;;;;N;;;;;
+1793;KHMER LETTER NO;Lo;0;L;;;;;N;;;;;
+1794;KHMER LETTER BA;Lo;0;L;;;;;N;;;;;
+1795;KHMER LETTER PHA;Lo;0;L;;;;;N;;;;;
+1796;KHMER LETTER PO;Lo;0;L;;;;;N;;;;;
+1797;KHMER LETTER PHO;Lo;0;L;;;;;N;;;;;
+1798;KHMER LETTER MO;Lo;0;L;;;;;N;;;;;
+1799;KHMER LETTER YO;Lo;0;L;;;;;N;;;;;
+179A;KHMER LETTER RO;Lo;0;L;;;;;N;;;;;
+179B;KHMER LETTER LO;Lo;0;L;;;;;N;;;;;
+179C;KHMER LETTER VO;Lo;0;L;;;;;N;;;;;
+179D;KHMER LETTER SHA;Lo;0;L;;;;;N;;;;;
+179E;KHMER LETTER SSO;Lo;0;L;;;;;N;;;;;
+179F;KHMER LETTER SA;Lo;0;L;;;;;N;;;;;
+17A0;KHMER LETTER HA;Lo;0;L;;;;;N;;;;;
+17A1;KHMER LETTER LA;Lo;0;L;;;;;N;;;;;
+17A2;KHMER LETTER QA;Lo;0;L;;;;;N;;;;;
+17A3;KHMER INDEPENDENT VOWEL QAQ;Lo;0;L;;;;;N;;*;;;
+17A4;KHMER INDEPENDENT VOWEL QAA;Lo;0;L;;;;;N;;*;;;
+17A5;KHMER INDEPENDENT VOWEL QI;Lo;0;L;;;;;N;;;;;
+17A6;KHMER INDEPENDENT VOWEL QII;Lo;0;L;;;;;N;;;;;
+17A7;KHMER INDEPENDENT VOWEL QU;Lo;0;L;;;;;N;;;;;
+17A8;KHMER INDEPENDENT VOWEL QUK;Lo;0;L;;;;;N;;;;;
+17A9;KHMER INDEPENDENT VOWEL QUU;Lo;0;L;;;;;N;;;;;
+17AA;KHMER INDEPENDENT VOWEL QUUV;Lo;0;L;;;;;N;;;;;
+17AB;KHMER INDEPENDENT VOWEL RY;Lo;0;L;;;;;N;;;;;
+17AC;KHMER INDEPENDENT VOWEL RYY;Lo;0;L;;;;;N;;;;;
+17AD;KHMER INDEPENDENT VOWEL LY;Lo;0;L;;;;;N;;;;;
+17AE;KHMER INDEPENDENT VOWEL LYY;Lo;0;L;;;;;N;;;;;
+17AF;KHMER INDEPENDENT VOWEL QE;Lo;0;L;;;;;N;;;;;
+17B0;KHMER INDEPENDENT VOWEL QAI;Lo;0;L;;;;;N;;;;;
+17B1;KHMER INDEPENDENT VOWEL QOO TYPE ONE;Lo;0;L;;;;;N;;;;;
+17B2;KHMER INDEPENDENT VOWEL QOO TYPE TWO;Lo;0;L;;;;;N;;;;;
+17B3;KHMER INDEPENDENT VOWEL QAU;Lo;0;L;;;;;N;;;;;
+17B4;KHMER VOWEL INHERENT AQ;Cf;0;L;;;;;N;;*;;;
+17B5;KHMER VOWEL INHERENT AA;Cf;0;L;;;;;N;;*;;;
+17B6;KHMER VOWEL SIGN AA;Mc;0;L;;;;;N;;;;;
+17B7;KHMER VOWEL SIGN I;Mn;0;NSM;;;;;N;;;;;
+17B8;KHMER VOWEL SIGN II;Mn;0;NSM;;;;;N;;;;;
+17B9;KHMER VOWEL SIGN Y;Mn;0;NSM;;;;;N;;;;;
+17BA;KHMER VOWEL SIGN YY;Mn;0;NSM;;;;;N;;;;;
+17BB;KHMER VOWEL SIGN U;Mn;0;NSM;;;;;N;;;;;
+17BC;KHMER VOWEL SIGN UU;Mn;0;NSM;;;;;N;;;;;
+17BD;KHMER VOWEL SIGN UA;Mn;0;NSM;;;;;N;;;;;
+17BE;KHMER VOWEL SIGN OE;Mc;0;L;;;;;N;;;;;
+17BF;KHMER VOWEL SIGN YA;Mc;0;L;;;;;N;;;;;
+17C0;KHMER VOWEL SIGN IE;Mc;0;L;;;;;N;;;;;
+17C1;KHMER VOWEL SIGN E;Mc;0;L;;;;;N;;;;;
+17C2;KHMER VOWEL SIGN AE;Mc;0;L;;;;;N;;;;;
+17C3;KHMER VOWEL SIGN AI;Mc;0;L;;;;;N;;;;;
+17C4;KHMER VOWEL SIGN OO;Mc;0;L;;;;;N;;;;;
+17C5;KHMER VOWEL SIGN AU;Mc;0;L;;;;;N;;;;;
+17C6;KHMER SIGN NIKAHIT;Mn;0;NSM;;;;;N;;;;;
+17C7;KHMER SIGN REAHMUK;Mc;0;L;;;;;N;;;;;
+17C8;KHMER SIGN YUUKALEAPINTU;Mc;0;L;;;;;N;;;;;
+17C9;KHMER SIGN MUUSIKATOAN;Mn;0;NSM;;;;;N;;;;;
+17CA;KHMER SIGN TRIISAP;Mn;0;NSM;;;;;N;;;;;
+17CB;KHMER SIGN BANTOC;Mn;0;NSM;;;;;N;;;;;
+17CC;KHMER SIGN ROBAT;Mn;0;NSM;;;;;N;;;;;
+17CD;KHMER SIGN TOANDAKHIAT;Mn;0;NSM;;;;;N;;;;;
+17CE;KHMER SIGN KAKABAT;Mn;0;NSM;;;;;N;;;;;
+17CF;KHMER SIGN AHSDA;Mn;0;NSM;;;;;N;;;;;
+17D0;KHMER SIGN SAMYOK SANNYA;Mn;0;NSM;;;;;N;;;;;
+17D1;KHMER SIGN VIRIAM;Mn;0;NSM;;;;;N;;;;;
+17D2;KHMER SIGN COENG;Mn;9;NSM;;;;;N;;;;;
+17D3;KHMER SIGN BATHAMASAT;Mn;0;NSM;;;;;N;;*;;;
+17D4;KHMER SIGN KHAN;Po;0;L;;;;;N;;;;;
+17D5;KHMER SIGN BARIYOOSAN;Po;0;L;;;;;N;;;;;
+17D6;KHMER SIGN CAMNUC PII KUUH;Po;0;L;;;;;N;;;;;
+17D7;KHMER SIGN LEK TOO;Lm;0;L;;;;;N;;;;;
+17D8;KHMER SIGN BEYYAL;Po;0;L;;;;;N;;*;;;
+17D9;KHMER SIGN PHNAEK MUAN;Po;0;L;;;;;N;;;;;
+17DA;KHMER SIGN KOOMUUT;Po;0;L;;;;;N;;;;;
+17DB;KHMER CURRENCY SYMBOL RIEL;Sc;0;ET;;;;;N;;;;;
+17DC;KHMER SIGN AVAKRAHASANYA;Lo;0;L;;;;;N;;;;;
+17DD;KHMER SIGN ATTHACAN;Mn;230;NSM;;;;;N;;;;;
+17E0;KHMER DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;;
+17E1;KHMER DIGIT ONE;Nd;0;L;;1;1;1;N;;;;;
+17E2;KHMER DIGIT TWO;Nd;0;L;;2;2;2;N;;;;;
+17E3;KHMER DIGIT THREE;Nd;0;L;;3;3;3;N;;;;;
+17E4;KHMER DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;;
+17E5;KHMER DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;;
+17E6;KHMER DIGIT SIX;Nd;0;L;;6;6;6;N;;;;;
+17E7;KHMER DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;;
+17E8;KHMER DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;;
+17E9;KHMER DIGIT NINE;Nd;0;L;;9;9;9;N;;;;;
+17F0;KHMER SYMBOL LEK ATTAK SON;No;0;ON;;;;0;N;;;;;
+17F1;KHMER SYMBOL LEK ATTAK MUOY;No;0;ON;;;;1;N;;;;;
+17F2;KHMER SYMBOL LEK ATTAK PII;No;0;ON;;;;2;N;;;;;
+17F3;KHMER SYMBOL LEK ATTAK BEI;No;0;ON;;;;3;N;;;;;
+17F4;KHMER SYMBOL LEK ATTAK BUON;No;0;ON;;;;4;N;;;;;
+17F5;KHMER SYMBOL LEK ATTAK PRAM;No;0;ON;;;;5;N;;;;;
+17F6;KHMER SYMBOL LEK ATTAK PRAM-MUOY;No;0;ON;;;;6;N;;;;;
+17F7;KHMER SYMBOL LEK ATTAK PRAM-PII;No;0;ON;;;;7;N;;;;;
+17F8;KHMER SYMBOL LEK ATTAK PRAM-BEI;No;0;ON;;;;8;N;;;;;
+17F9;KHMER SYMBOL LEK ATTAK PRAM-BUON;No;0;ON;;;;9;N;;;;;
+1800;MONGOLIAN BIRGA;Po;0;ON;;;;;N;;;;;
+1801;MONGOLIAN ELLIPSIS;Po;0;ON;;;;;N;;;;;
+1802;MONGOLIAN COMMA;Po;0;ON;;;;;N;;;;;
+1803;MONGOLIAN FULL STOP;Po;0;ON;;;;;N;;;;;
+1804;MONGOLIAN COLON;Po;0;ON;;;;;N;;;;;
+1805;MONGOLIAN FOUR DOTS;Po;0;ON;;;;;N;;;;;
+1806;MONGOLIAN TODO SOFT HYPHEN;Pd;0;ON;;;;;N;;;;;
+1807;MONGOLIAN SIBE SYLLABLE BOUNDARY MARKER;Po;0;ON;;;;;N;;;;;
+1808;MONGOLIAN MANCHU COMMA;Po;0;ON;;;;;N;;;;;
+1809;MONGOLIAN MANCHU FULL STOP;Po;0;ON;;;;;N;;;;;
+180A;MONGOLIAN NIRUGU;Po;0;ON;;;;;N;;;;;
+180B;MONGOLIAN FREE VARIATION SELECTOR ONE;Mn;0;NSM;;;;;N;;;;;
+180C;MONGOLIAN FREE VARIATION SELECTOR TWO;Mn;0;NSM;;;;;N;;;;;
+180D;MONGOLIAN FREE VARIATION SELECTOR THREE;Mn;0;NSM;;;;;N;;;;;
+180E;MONGOLIAN VOWEL SEPARATOR;Zs;0;WS;;;;;N;;;;;
+1810;MONGOLIAN DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;;
+1811;MONGOLIAN DIGIT ONE;Nd;0;L;;1;1;1;N;;;;;
+1812;MONGOLIAN DIGIT TWO;Nd;0;L;;2;2;2;N;;;;;
+1813;MONGOLIAN DIGIT THREE;Nd;0;L;;3;3;3;N;;;;;
+1814;MONGOLIAN DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;;
+1815;MONGOLIAN DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;;
+1816;MONGOLIAN DIGIT SIX;Nd;0;L;;6;6;6;N;;;;;
+1817;MONGOLIAN DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;;
+1818;MONGOLIAN DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;;
+1819;MONGOLIAN DIGIT NINE;Nd;0;L;;9;9;9;N;;;;;
+1820;MONGOLIAN LETTER A;Lo;0;L;;;;;N;;;;;
+1821;MONGOLIAN LETTER E;Lo;0;L;;;;;N;;;;;
+1822;MONGOLIAN LETTER I;Lo;0;L;;;;;N;;;;;
+1823;MONGOLIAN LETTER O;Lo;0;L;;;;;N;;;;;
+1824;MONGOLIAN LETTER U;Lo;0;L;;;;;N;;;;;
+1825;MONGOLIAN LETTER OE;Lo;0;L;;;;;N;;;;;
+1826;MONGOLIAN LETTER UE;Lo;0;L;;;;;N;;;;;
+1827;MONGOLIAN LETTER EE;Lo;0;L;;;;;N;;;;;
+1828;MONGOLIAN LETTER NA;Lo;0;L;;;;;N;;;;;
+1829;MONGOLIAN LETTER ANG;Lo;0;L;;;;;N;;;;;
+182A;MONGOLIAN LETTER BA;Lo;0;L;;;;;N;;;;;
+182B;MONGOLIAN LETTER PA;Lo;0;L;;;;;N;;;;;
+182C;MONGOLIAN LETTER QA;Lo;0;L;;;;;N;;;;;
+182D;MONGOLIAN LETTER GA;Lo;0;L;;;;;N;;;;;
+182E;MONGOLIAN LETTER MA;Lo;0;L;;;;;N;;;;;
+182F;MONGOLIAN LETTER LA;Lo;0;L;;;;;N;;;;;
+1830;MONGOLIAN LETTER SA;Lo;0;L;;;;;N;;;;;
+1831;MONGOLIAN LETTER SHA;Lo;0;L;;;;;N;;;;;
+1832;MONGOLIAN LETTER TA;Lo;0;L;;;;;N;;;;;
+1833;MONGOLIAN LETTER DA;Lo;0;L;;;;;N;;;;;
+1834;MONGOLIAN LETTER CHA;Lo;0;L;;;;;N;;;;;
+1835;MONGOLIAN LETTER JA;Lo;0;L;;;;;N;;;;;
+1836;MONGOLIAN LETTER YA;Lo;0;L;;;;;N;;;;;
+1837;MONGOLIAN LETTER RA;Lo;0;L;;;;;N;;;;;
+1838;MONGOLIAN LETTER WA;Lo;0;L;;;;;N;;;;;
+1839;MONGOLIAN LETTER FA;Lo;0;L;;;;;N;;;;;
+183A;MONGOLIAN LETTER KA;Lo;0;L;;;;;N;;;;;
+183B;MONGOLIAN LETTER KHA;Lo;0;L;;;;;N;;;;;
+183C;MONGOLIAN LETTER TSA;Lo;0;L;;;;;N;;;;;
+183D;MONGOLIAN LETTER ZA;Lo;0;L;;;;;N;;;;;
+183E;MONGOLIAN LETTER HAA;Lo;0;L;;;;;N;;;;;
+183F;MONGOLIAN LETTER ZRA;Lo;0;L;;;;;N;;;;;
+1840;MONGOLIAN LETTER LHA;Lo;0;L;;;;;N;;;;;
+1841;MONGOLIAN LETTER ZHI;Lo;0;L;;;;;N;;;;;
+1842;MONGOLIAN LETTER CHI;Lo;0;L;;;;;N;;;;;
+1843;MONGOLIAN LETTER TODO LONG VOWEL SIGN;Lm;0;L;;;;;N;;;;;
+1844;MONGOLIAN LETTER TODO E;Lo;0;L;;;;;N;;;;;
+1845;MONGOLIAN LETTER TODO I;Lo;0;L;;;;;N;;;;;
+1846;MONGOLIAN LETTER TODO O;Lo;0;L;;;;;N;;;;;
+1847;MONGOLIAN LETTER TODO U;Lo;0;L;;;;;N;;;;;
+1848;MONGOLIAN LETTER TODO OE;Lo;0;L;;;;;N;;;;;
+1849;MONGOLIAN LETTER TODO UE;Lo;0;L;;;;;N;;;;;
+184A;MONGOLIAN LETTER TODO ANG;Lo;0;L;;;;;N;;;;;
+184B;MONGOLIAN LETTER TODO BA;Lo;0;L;;;;;N;;;;;
+184C;MONGOLIAN LETTER TODO PA;Lo;0;L;;;;;N;;;;;
+184D;MONGOLIAN LETTER TODO QA;Lo;0;L;;;;;N;;;;;
+184E;MONGOLIAN LETTER TODO GA;Lo;0;L;;;;;N;;;;;
+184F;MONGOLIAN LETTER TODO MA;Lo;0;L;;;;;N;;;;;
+1850;MONGOLIAN LETTER TODO TA;Lo;0;L;;;;;N;;;;;
+1851;MONGOLIAN LETTER TODO DA;Lo;0;L;;;;;N;;;;;
+1852;MONGOLIAN LETTER TODO CHA;Lo;0;L;;;;;N;;;;;
+1853;MONGOLIAN LETTER TODO JA;Lo;0;L;;;;;N;;;;;
+1854;MONGOLIAN LETTER TODO TSA;Lo;0;L;;;;;N;;;;;
+1855;MONGOLIAN LETTER TODO YA;Lo;0;L;;;;;N;;;;;
+1856;MONGOLIAN LETTER TODO WA;Lo;0;L;;;;;N;;;;;
+1857;MONGOLIAN LETTER TODO KA;Lo;0;L;;;;;N;;;;;
+1858;MONGOLIAN LETTER TODO GAA;Lo;0;L;;;;;N;;;;;
+1859;MONGOLIAN LETTER TODO HAA;Lo;0;L;;;;;N;;;;;
+185A;MONGOLIAN LETTER TODO JIA;Lo;0;L;;;;;N;;;;;
+185B;MONGOLIAN LETTER TODO NIA;Lo;0;L;;;;;N;;;;;
+185C;MONGOLIAN LETTER TODO DZA;Lo;0;L;;;;;N;;;;;
+185D;MONGOLIAN LETTER SIBE E;Lo;0;L;;;;;N;;;;;
+185E;MONGOLIAN LETTER SIBE I;Lo;0;L;;;;;N;;;;;
+185F;MONGOLIAN LETTER SIBE IY;Lo;0;L;;;;;N;;;;;
+1860;MONGOLIAN LETTER SIBE UE;Lo;0;L;;;;;N;;;;;
+1861;MONGOLIAN LETTER SIBE U;Lo;0;L;;;;;N;;;;;
+1862;MONGOLIAN LETTER SIBE ANG;Lo;0;L;;;;;N;;;;;
+1863;MONGOLIAN LETTER SIBE KA;Lo;0;L;;;;;N;;;;;
+1864;MONGOLIAN LETTER SIBE GA;Lo;0;L;;;;;N;;;;;
+1865;MONGOLIAN LETTER SIBE HA;Lo;0;L;;;;;N;;;;;
+1866;MONGOLIAN LETTER SIBE PA;Lo;0;L;;;;;N;;;;;
+1867;MONGOLIAN LETTER SIBE SHA;Lo;0;L;;;;;N;;;;;
+1868;MONGOLIAN LETTER SIBE TA;Lo;0;L;;;;;N;;;;;
+1869;MONGOLIAN LETTER SIBE DA;Lo;0;L;;;;;N;;;;;
+186A;MONGOLIAN LETTER SIBE JA;Lo;0;L;;;;;N;;;;;
+186B;MONGOLIAN LETTER SIBE FA;Lo;0;L;;;;;N;;;;;
+186C;MONGOLIAN LETTER SIBE GAA;Lo;0;L;;;;;N;;;;;
+186D;MONGOLIAN LETTER SIBE HAA;Lo;0;L;;;;;N;;;;;
+186E;MONGOLIAN LETTER SIBE TSA;Lo;0;L;;;;;N;;;;;
+186F;MONGOLIAN LETTER SIBE ZA;Lo;0;L;;;;;N;;;;;
+1870;MONGOLIAN LETTER SIBE RAA;Lo;0;L;;;;;N;;;;;
+1871;MONGOLIAN LETTER SIBE CHA;Lo;0;L;;;;;N;;;;;
+1872;MONGOLIAN LETTER SIBE ZHA;Lo;0;L;;;;;N;;;;;
+1873;MONGOLIAN LETTER MANCHU I;Lo;0;L;;;;;N;;;;;
+1874;MONGOLIAN LETTER MANCHU KA;Lo;0;L;;;;;N;;;;;
+1875;MONGOLIAN LETTER MANCHU RA;Lo;0;L;;;;;N;;;;;
+1876;MONGOLIAN LETTER MANCHU FA;Lo;0;L;;;;;N;;;;;
+1877;MONGOLIAN LETTER MANCHU ZHA;Lo;0;L;;;;;N;;;;;
+1880;MONGOLIAN LETTER ALI GALI ANUSVARA ONE;Lo;0;L;;;;;N;;;;;
+1881;MONGOLIAN LETTER ALI GALI VISARGA ONE;Lo;0;L;;;;;N;;;;;
+1882;MONGOLIAN LETTER ALI GALI DAMARU;Lo;0;L;;;;;N;;;;;
+1883;MONGOLIAN LETTER ALI GALI UBADAMA;Lo;0;L;;;;;N;;;;;
+1884;MONGOLIAN LETTER ALI GALI INVERTED UBADAMA;Lo;0;L;;;;;N;;;;;
+1885;MONGOLIAN LETTER ALI GALI BALUDA;Lo;0;L;;;;;N;;;;;
+1886;MONGOLIAN LETTER ALI GALI THREE BALUDA;Lo;0;L;;;;;N;;;;;
+1887;MONGOLIAN LETTER ALI GALI A;Lo;0;L;;;;;N;;;;;
+1888;MONGOLIAN LETTER ALI GALI I;Lo;0;L;;;;;N;;;;;
+1889;MONGOLIAN LETTER ALI GALI KA;Lo;0;L;;;;;N;;;;;
+188A;MONGOLIAN LETTER ALI GALI NGA;Lo;0;L;;;;;N;;;;;
+188B;MONGOLIAN LETTER ALI GALI CA;Lo;0;L;;;;;N;;;;;
+188C;MONGOLIAN LETTER ALI GALI TTA;Lo;0;L;;;;;N;;;;;
+188D;MONGOLIAN LETTER ALI GALI TTHA;Lo;0;L;;;;;N;;;;;
+188E;MONGOLIAN LETTER ALI GALI DDA;Lo;0;L;;;;;N;;;;;
+188F;MONGOLIAN LETTER ALI GALI NNA;Lo;0;L;;;;;N;;;;;
+1890;MONGOLIAN LETTER ALI GALI TA;Lo;0;L;;;;;N;;;;;
+1891;MONGOLIAN LETTER ALI GALI DA;Lo;0;L;;;;;N;;;;;
+1892;MONGOLIAN LETTER ALI GALI PA;Lo;0;L;;;;;N;;;;;
+1893;MONGOLIAN LETTER ALI GALI PHA;Lo;0;L;;;;;N;;;;;
+1894;MONGOLIAN LETTER ALI GALI SSA;Lo;0;L;;;;;N;;;;;
+1895;MONGOLIAN LETTER ALI GALI ZHA;Lo;0;L;;;;;N;;;;;
+1896;MONGOLIAN LETTER ALI GALI ZA;Lo;0;L;;;;;N;;;;;
+1897;MONGOLIAN LETTER ALI GALI AH;Lo;0;L;;;;;N;;;;;
+1898;MONGOLIAN LETTER TODO ALI GALI TA;Lo;0;L;;;;;N;;;;;
+1899;MONGOLIAN LETTER TODO ALI GALI ZHA;Lo;0;L;;;;;N;;;;;
+189A;MONGOLIAN LETTER MANCHU ALI GALI GHA;Lo;0;L;;;;;N;;;;;
+189B;MONGOLIAN LETTER MANCHU ALI GALI NGA;Lo;0;L;;;;;N;;;;;
+189C;MONGOLIAN LETTER MANCHU ALI GALI CA;Lo;0;L;;;;;N;;;;;
+189D;MONGOLIAN LETTER MANCHU ALI GALI JHA;Lo;0;L;;;;;N;;;;;
+189E;MONGOLIAN LETTER MANCHU ALI GALI TTA;Lo;0;L;;;;;N;;;;;
+189F;MONGOLIAN LETTER MANCHU ALI GALI DDHA;Lo;0;L;;;;;N;;;;;
+18A0;MONGOLIAN LETTER MANCHU ALI GALI TA;Lo;0;L;;;;;N;;;;;
+18A1;MONGOLIAN LETTER MANCHU ALI GALI DHA;Lo;0;L;;;;;N;;;;;
+18A2;MONGOLIAN LETTER MANCHU ALI GALI SSA;Lo;0;L;;;;;N;;;;;
+18A3;MONGOLIAN LETTER MANCHU ALI GALI CYA;Lo;0;L;;;;;N;;;;;
+18A4;MONGOLIAN LETTER MANCHU ALI GALI ZHA;Lo;0;L;;;;;N;;;;;
+18A5;MONGOLIAN LETTER MANCHU ALI GALI ZA;Lo;0;L;;;;;N;;;;;
+18A6;MONGOLIAN LETTER ALI GALI HALF U;Lo;0;L;;;;;N;;;;;
+18A7;MONGOLIAN LETTER ALI GALI HALF YA;Lo;0;L;;;;;N;;;;;
+18A8;MONGOLIAN LETTER MANCHU ALI GALI BHA;Lo;0;L;;;;;N;;;;;
+18A9;MONGOLIAN LETTER ALI GALI DAGALGA;Mn;228;NSM;;;;;N;;;;;
+1900;LIMBU VOWEL-CARRIER LETTER;Lo;0;L;;;;;N;;;;;
+1901;LIMBU LETTER KA;Lo;0;L;;;;;N;;;;;
+1902;LIMBU LETTER KHA;Lo;0;L;;;;;N;;;;;
+1903;LIMBU LETTER GA;Lo;0;L;;;;;N;;;;;
+1904;LIMBU LETTER GHA;Lo;0;L;;;;;N;;;;;
+1905;LIMBU LETTER NGA;Lo;0;L;;;;;N;;;;;
+1906;LIMBU LETTER CA;Lo;0;L;;;;;N;;;;;
+1907;LIMBU LETTER CHA;Lo;0;L;;;;;N;;;;;
+1908;LIMBU LETTER JA;Lo;0;L;;;;;N;;;;;
+1909;LIMBU LETTER JHA;Lo;0;L;;;;;N;;;;;
+190A;LIMBU LETTER YAN;Lo;0;L;;;;;N;;;;;
+190B;LIMBU LETTER TA;Lo;0;L;;;;;N;;;;;
+190C;LIMBU LETTER THA;Lo;0;L;;;;;N;;;;;
+190D;LIMBU LETTER DA;Lo;0;L;;;;;N;;;;;
+190E;LIMBU LETTER DHA;Lo;0;L;;;;;N;;;;;
+190F;LIMBU LETTER NA;Lo;0;L;;;;;N;;;;;
+1910;LIMBU LETTER PA;Lo;0;L;;;;;N;;;;;
+1911;LIMBU LETTER PHA;Lo;0;L;;;;;N;;;;;
+1912;LIMBU LETTER BA;Lo;0;L;;;;;N;;;;;
+1913;LIMBU LETTER BHA;Lo;0;L;;;;;N;;;;;
+1914;LIMBU LETTER MA;Lo;0;L;;;;;N;;;;;
+1915;LIMBU LETTER YA;Lo;0;L;;;;;N;;;;;
+1916;LIMBU LETTER RA;Lo;0;L;;;;;N;;;;;
+1917;LIMBU LETTER LA;Lo;0;L;;;;;N;;;;;
+1918;LIMBU LETTER WA;Lo;0;L;;;;;N;;;;;
+1919;LIMBU LETTER SHA;Lo;0;L;;;;;N;;;;;
+191A;LIMBU LETTER SSA;Lo;0;L;;;;;N;;;;;
+191B;LIMBU LETTER SA;Lo;0;L;;;;;N;;;;;
+191C;LIMBU LETTER HA;Lo;0;L;;;;;N;;;;;
+1920;LIMBU VOWEL SIGN A;Mn;0;NSM;;;;;N;;;;;
+1921;LIMBU VOWEL SIGN I;Mn;0;NSM;;;;;N;;;;;
+1922;LIMBU VOWEL SIGN U;Mn;0;NSM;;;;;N;;;;;
+1923;LIMBU VOWEL SIGN EE;Mc;0;L;;;;;N;;;;;
+1924;LIMBU VOWEL SIGN AI;Mc;0;L;;;;;N;;;;;
+1925;LIMBU VOWEL SIGN OO;Mc;0;L;;;;;N;;;;;
+1926;LIMBU VOWEL SIGN AU;Mc;0;L;;;;;N;;;;;
+1927;LIMBU VOWEL SIGN E;Mn;0;NSM;;;;;N;;;;;
+1928;LIMBU VOWEL SIGN O;Mn;0;NSM;;;;;N;;;;;
+1929;LIMBU SUBJOINED LETTER YA;Mc;0;NSM;;;;;N;;;;;
+192A;LIMBU SUBJOINED LETTER RA;Mc;0;NSM;;;;;N;;;;;
+192B;LIMBU SUBJOINED LETTER WA;Mc;0;NSM;;;;;N;;;;;
+1930;LIMBU SMALL LETTER KA;Mc;0;L;;;;;N;;;;;
+1931;LIMBU SMALL LETTER NGA;Mc;0;L;;;;;N;;;;;
+1932;LIMBU SMALL LETTER ANUSVARA;Mn;0;NSM;;;;;N;;;;;
+1933;LIMBU SMALL LETTER TA;Mc;0;L;;;;;N;;;;;
+1934;LIMBU SMALL LETTER NA;Mc;0;L;;;;;N;;;;;
+1935;LIMBU SMALL LETTER PA;Mc;0;L;;;;;N;;;;;
+1936;LIMBU SMALL LETTER MA;Mc;0;L;;;;;N;;;;;
+1937;LIMBU SMALL LETTER RA;Mc;0;L;;;;;N;;;;;
+1938;LIMBU SMALL LETTER LA;Mc;0;L;;;;;N;;;;;
+1939;LIMBU SIGN MUKPHRENG;Mn;222;NSM;;;;;N;;;;;
+193A;LIMBU SIGN KEMPHRENG;Mn;230;NSM;;;;;N;;;;;
+193B;LIMBU SIGN SA-I;Mn;220;NSM;;;;;N;;;;;
+1940;LIMBU SIGN LOO;So;0;ON;;;;;N;;;;;
+1944;LIMBU EXCLAMATION MARK;Po;0;ON;;;;;N;;;;;
+1945;LIMBU QUESTION MARK;Po;0;ON;;;;;N;;;;;
+1946;LIMBU DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;;
+1947;LIMBU DIGIT ONE;Nd;0;L;;1;1;1;N;;;;;
+1948;LIMBU DIGIT TWO;Nd;0;L;;2;2;2;N;;;;;
+1949;LIMBU DIGIT THREE;Nd;0;L;;3;3;3;N;;;;;
+194A;LIMBU DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;;
+194B;LIMBU DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;;
+194C;LIMBU DIGIT SIX;Nd;0;L;;6;6;6;N;;;;;
+194D;LIMBU DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;;
+194E;LIMBU DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;;
+194F;LIMBU DIGIT NINE;Nd;0;L;;9;9;9;N;;;;;
+1950;TAI LE LETTER KA;Lo;0;L;;;;;N;;;;;
+1951;TAI LE LETTER XA;Lo;0;L;;;;;N;;;;;
+1952;TAI LE LETTER NGA;Lo;0;L;;;;;N;;;;;
+1953;TAI LE LETTER TSA;Lo;0;L;;;;;N;;;;;
+1954;TAI LE LETTER SA;Lo;0;L;;;;;N;;;;;
+1955;TAI LE LETTER YA;Lo;0;L;;;;;N;;;;;
+1956;TAI LE LETTER TA;Lo;0;L;;;;;N;;;;;
+1957;TAI LE LETTER THA;Lo;0;L;;;;;N;;;;;
+1958;TAI LE LETTER LA;Lo;0;L;;;;;N;;;;;
+1959;TAI LE LETTER PA;Lo;0;L;;;;;N;;;;;
+195A;TAI LE LETTER PHA;Lo;0;L;;;;;N;;;;;
+195B;TAI LE LETTER MA;Lo;0;L;;;;;N;;;;;
+195C;TAI LE LETTER FA;Lo;0;L;;;;;N;;;;;
+195D;TAI LE LETTER VA;Lo;0;L;;;;;N;;;;;
+195E;TAI LE LETTER HA;Lo;0;L;;;;;N;;;;;
+195F;TAI LE LETTER QA;Lo;0;L;;;;;N;;;;;
+1960;TAI LE LETTER KHA;Lo;0;L;;;;;N;;;;;
+1961;TAI LE LETTER TSHA;Lo;0;L;;;;;N;;;;;
+1962;TAI LE LETTER NA;Lo;0;L;;;;;N;;;;;
+1963;TAI LE LETTER A;Lo;0;L;;;;;N;;;;;
+1964;TAI LE LETTER I;Lo;0;L;;;;;N;;;;;
+1965;TAI LE LETTER EE;Lo;0;L;;;;;N;;;;;
+1966;TAI LE LETTER EH;Lo;0;L;;;;;N;;;;;
+1967;TAI LE LETTER U;Lo;0;L;;;;;N;;;;;
+1968;TAI LE LETTER OO;Lo;0;L;;;;;N;;;;;
+1969;TAI LE LETTER O;Lo;0;L;;;;;N;;;;;
+196A;TAI LE LETTER UE;Lo;0;L;;;;;N;;;;;
+196B;TAI LE LETTER E;Lo;0;L;;;;;N;;;;;
+196C;TAI LE LETTER AUE;Lo;0;L;;;;;N;;;;;
+196D;TAI LE LETTER AI;Lo;0;L;;;;;N;;;;;
+1970;TAI LE LETTER TONE-2;Lo;0;L;;;;;N;;;;;
+1971;TAI LE LETTER TONE-3;Lo;0;L;;;;;N;;;;;
+1972;TAI LE LETTER TONE-4;Lo;0;L;;;;;N;;;;;
+1973;TAI LE LETTER TONE-5;Lo;0;L;;;;;N;;;;;
+1974;TAI LE LETTER TONE-6;Lo;0;L;;;;;N;;;;;
+1980;NEW TAI LUE LETTER HIGH QA;Lo;0;L;;;;;N;;;;;
+1981;NEW TAI LUE LETTER LOW QA;Lo;0;L;;;;;N;;;;;
+1982;NEW TAI LUE LETTER HIGH KA;Lo;0;L;;;;;N;;;;;
+1983;NEW TAI LUE LETTER HIGH XA;Lo;0;L;;;;;N;;;;;
+1984;NEW TAI LUE LETTER HIGH NGA;Lo;0;L;;;;;N;;;;;
+1985;NEW TAI LUE LETTER LOW KA;Lo;0;L;;;;;N;;;;;
+1986;NEW TAI LUE LETTER LOW XA;Lo;0;L;;;;;N;;;;;
+1987;NEW TAI LUE LETTER LOW NGA;Lo;0;L;;;;;N;;;;;
+1988;NEW TAI LUE LETTER HIGH TSA;Lo;0;L;;;;;N;;;;;
+1989;NEW TAI LUE LETTER HIGH SA;Lo;0;L;;;;;N;;;;;
+198A;NEW TAI LUE LETTER HIGH YA;Lo;0;L;;;;;N;;;;;
+198B;NEW TAI LUE LETTER LOW TSA;Lo;0;L;;;;;N;;;;;
+198C;NEW TAI LUE LETTER LOW SA;Lo;0;L;;;;;N;;;;;
+198D;NEW TAI LUE LETTER LOW YA;Lo;0;L;;;;;N;;;;;
+198E;NEW TAI LUE LETTER HIGH TA;Lo;0;L;;;;;N;;;;;
+198F;NEW TAI LUE LETTER HIGH THA;Lo;0;L;;;;;N;;;;;
+1990;NEW TAI LUE LETTER HIGH NA;Lo;0;L;;;;;N;;;;;
+1991;NEW TAI LUE LETTER LOW TA;Lo;0;L;;;;;N;;;;;
+1992;NEW TAI LUE LETTER LOW THA;Lo;0;L;;;;;N;;;;;
+1993;NEW TAI LUE LETTER LOW NA;Lo;0;L;;;;;N;;;;;
+1994;NEW TAI LUE LETTER HIGH PA;Lo;0;L;;;;;N;;;;;
+1995;NEW TAI LUE LETTER HIGH PHA;Lo;0;L;;;;;N;;;;;
+1996;NEW TAI LUE LETTER HIGH MA;Lo;0;L;;;;;N;;;;;
+1997;NEW TAI LUE LETTER LOW PA;Lo;0;L;;;;;N;;;;;
+1998;NEW TAI LUE LETTER LOW PHA;Lo;0;L;;;;;N;;;;;
+1999;NEW TAI LUE LETTER LOW MA;Lo;0;L;;;;;N;;;;;
+199A;NEW TAI LUE LETTER HIGH FA;Lo;0;L;;;;;N;;;;;
+199B;NEW TAI LUE LETTER HIGH VA;Lo;0;L;;;;;N;;;;;
+199C;NEW TAI LUE LETTER HIGH LA;Lo;0;L;;;;;N;;;;;
+199D;NEW TAI LUE LETTER LOW FA;Lo;0;L;;;;;N;;;;;
+199E;NEW TAI LUE LETTER LOW VA;Lo;0;L;;;;;N;;;;;
+199F;NEW TAI LUE LETTER LOW LA;Lo;0;L;;;;;N;;;;;
+19A0;NEW TAI LUE LETTER HIGH HA;Lo;0;L;;;;;N;;;;;
+19A1;NEW TAI LUE LETTER HIGH DA;Lo;0;L;;;;;N;;;;;
+19A2;NEW TAI LUE LETTER HIGH BA;Lo;0;L;;;;;N;;;;;
+19A3;NEW TAI LUE LETTER LOW HA;Lo;0;L;;;;;N;;;;;
+19A4;NEW TAI LUE LETTER LOW DA;Lo;0;L;;;;;N;;;;;
+19A5;NEW TAI LUE LETTER LOW BA;Lo;0;L;;;;;N;;;;;
+19A6;NEW TAI LUE LETTER HIGH KVA;Lo;0;L;;;;;N;;;;;
+19A7;NEW TAI LUE LETTER HIGH XVA;Lo;0;L;;;;;N;;;;;
+19A8;NEW TAI LUE LETTER LOW KVA;Lo;0;L;;;;;N;;;;;
+19A9;NEW TAI LUE LETTER LOW XVA;Lo;0;L;;;;;N;;;;;
+19B0;NEW TAI LUE VOWEL SIGN VOWEL SHORTENER;Mc;0;L;;;;;N;;;;;
+19B1;NEW TAI LUE VOWEL SIGN AA;Mc;0;L;;;;;N;;;;;
+19B2;NEW TAI LUE VOWEL SIGN II;Mc;0;L;;;;;N;;;;;
+19B3;NEW TAI LUE VOWEL SIGN U;Mc;0;L;;;;;N;;;;;
+19B4;NEW TAI LUE VOWEL SIGN UU;Mc;0;L;;;;;N;;;;;
+19B5;NEW TAI LUE VOWEL SIGN E;Mc;0;L;;;;;N;;;;;
+19B6;NEW TAI LUE VOWEL SIGN AE;Mc;0;L;;;;;N;;;;;
+19B7;NEW TAI LUE VOWEL SIGN O;Mc;0;L;;;;;N;;;;;
+19B8;NEW TAI LUE VOWEL SIGN OA;Mc;0;L;;;;;N;;;;;
+19B9;NEW TAI LUE VOWEL SIGN UE;Mc;0;L;;;;;N;;;;;
+19BA;NEW TAI LUE VOWEL SIGN AY;Mc;0;L;;;;;N;;;;;
+19BB;NEW TAI LUE VOWEL SIGN AAY;Mc;0;L;;;;;N;;;;;
+19BC;NEW TAI LUE VOWEL SIGN UY;Mc;0;L;;;;;N;;;;;
+19BD;NEW TAI LUE VOWEL SIGN OY;Mc;0;L;;;;;N;;;;;
+19BE;NEW TAI LUE VOWEL SIGN OAY;Mc;0;L;;;;;N;;;;;
+19BF;NEW TAI LUE VOWEL SIGN UEY;Mc;0;L;;;;;N;;;;;
+19C0;NEW TAI LUE VOWEL SIGN IY;Mc;0;L;;;;;N;;;;;
+19C1;NEW TAI LUE LETTER FINAL V;Lo;0;L;;;;;N;;;;;
+19C2;NEW TAI LUE LETTER FINAL NG;Lo;0;L;;;;;N;;;;;
+19C3;NEW TAI LUE LETTER FINAL N;Lo;0;L;;;;;N;;;;;
+19C4;NEW TAI LUE LETTER FINAL M;Lo;0;L;;;;;N;;;;;
+19C5;NEW TAI LUE LETTER FINAL K;Lo;0;L;;;;;N;;;;;
+19C6;NEW TAI LUE LETTER FINAL D;Lo;0;L;;;;;N;;;;;
+19C7;NEW TAI LUE LETTER FINAL B;Lo;0;L;;;;;N;;;;;
+19C8;NEW TAI LUE TONE MARK-1;Mc;0;L;;;;;N;;;;;
+19C9;NEW TAI LUE TONE MARK-2;Mc;0;L;;;;;N;;;;;
+19D0;NEW TAI LUE DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;;
+19D1;NEW TAI LUE DIGIT ONE;Nd;0;L;;1;1;1;N;;;;;
+19D2;NEW TAI LUE DIGIT TWO;Nd;0;L;;2;2;2;N;;;;;
+19D3;NEW TAI LUE DIGIT THREE;Nd;0;L;;3;3;3;N;;;;;
+19D4;NEW TAI LUE DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;;
+19D5;NEW TAI LUE DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;;
+19D6;NEW TAI LUE DIGIT SIX;Nd;0;L;;6;6;6;N;;;;;
+19D7;NEW TAI LUE DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;;
+19D8;NEW TAI LUE DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;;
+19D9;NEW TAI LUE DIGIT NINE;Nd;0;L;;9;9;9;N;;;;;
+19DE;NEW TAI LUE SIGN LAE;Po;0;ON;;;;;N;;;;;
+19DF;NEW TAI LUE SIGN LAEV;Po;0;ON;;;;;N;;;;;
+19E0;KHMER SYMBOL PATHAMASAT;So;0;ON;;;;;N;;;;;
+19E1;KHMER SYMBOL MUOY KOET;So;0;ON;;;;;N;;;;;
+19E2;KHMER SYMBOL PII KOET;So;0;ON;;;;;N;;;;;
+19E3;KHMER SYMBOL BEI KOET;So;0;ON;;;;;N;;;;;
+19E4;KHMER SYMBOL BUON KOET;So;0;ON;;;;;N;;;;;
+19E5;KHMER SYMBOL PRAM KOET;So;0;ON;;;;;N;;;;;
+19E6;KHMER SYMBOL PRAM-MUOY KOET;So;0;ON;;;;;N;;;;;
+19E7;KHMER SYMBOL PRAM-PII KOET;So;0;ON;;;;;N;;;;;
+19E8;KHMER SYMBOL PRAM-BEI KOET;So;0;ON;;;;;N;;;;;
+19E9;KHMER SYMBOL PRAM-BUON KOET;So;0;ON;;;;;N;;;;;
+19EA;KHMER SYMBOL DAP KOET;So;0;ON;;;;;N;;;;;
+19EB;KHMER SYMBOL DAP-MUOY KOET;So;0;ON;;;;;N;;;;;
+19EC;KHMER SYMBOL DAP-PII KOET;So;0;ON;;;;;N;;;;;
+19ED;KHMER SYMBOL DAP-BEI KOET;So;0;ON;;;;;N;;;;;
+19EE;KHMER SYMBOL DAP-BUON KOET;So;0;ON;;;;;N;;;;;
+19EF;KHMER SYMBOL DAP-PRAM KOET;So;0;ON;;;;;N;;;;;
+19F0;KHMER SYMBOL TUTEYASAT;So;0;ON;;;;;N;;;;;
+19F1;KHMER SYMBOL MUOY ROC;So;0;ON;;;;;N;;;;;
+19F2;KHMER SYMBOL PII ROC;So;0;ON;;;;;N;;;;;
+19F3;KHMER SYMBOL BEI ROC;So;0;ON;;;;;N;;;;;
+19F4;KHMER SYMBOL BUON ROC;So;0;ON;;;;;N;;;;;
+19F5;KHMER SYMBOL PRAM ROC;So;0;ON;;;;;N;;;;;
+19F6;KHMER SYMBOL PRAM-MUOY ROC;So;0;ON;;;;;N;;;;;
+19F7;KHMER SYMBOL PRAM-PII ROC;So;0;ON;;;;;N;;;;;
+19F8;KHMER SYMBOL PRAM-BEI ROC;So;0;ON;;;;;N;;;;;
+19F9;KHMER SYMBOL PRAM-BUON ROC;So;0;ON;;;;;N;;;;;
+19FA;KHMER SYMBOL DAP ROC;So;0;ON;;;;;N;;;;;
+19FB;KHMER SYMBOL DAP-MUOY ROC;So;0;ON;;;;;N;;;;;
+19FC;KHMER SYMBOL DAP-PII ROC;So;0;ON;;;;;N;;;;;
+19FD;KHMER SYMBOL DAP-BEI ROC;So;0;ON;;;;;N;;;;;
+19FE;KHMER SYMBOL DAP-BUON ROC;So;0;ON;;;;;N;;;;;
+19FF;KHMER SYMBOL DAP-PRAM ROC;So;0;ON;;;;;N;;;;;
+1A00;BUGINESE LETTER KA;Lo;0;L;;;;;N;;;;;
+1A01;BUGINESE LETTER GA;Lo;0;L;;;;;N;;;;;
+1A02;BUGINESE LETTER NGA;Lo;0;L;;;;;N;;;;;
+1A03;BUGINESE LETTER NGKA;Lo;0;L;;;;;N;;;;;
+1A04;BUGINESE LETTER PA;Lo;0;L;;;;;N;;;;;
+1A05;BUGINESE LETTER BA;Lo;0;L;;;;;N;;;;;
+1A06;BUGINESE LETTER MA;Lo;0;L;;;;;N;;;;;
+1A07;BUGINESE LETTER MPA;Lo;0;L;;;;;N;;;;;
+1A08;BUGINESE LETTER TA;Lo;0;L;;;;;N;;;;;
+1A09;BUGINESE LETTER DA;Lo;0;L;;;;;N;;;;;
+1A0A;BUGINESE LETTER NA;Lo;0;L;;;;;N;;;;;
+1A0B;BUGINESE LETTER NRA;Lo;0;L;;;;;N;;;;;
+1A0C;BUGINESE LETTER CA;Lo;0;L;;;;;N;;;;;
+1A0D;BUGINESE LETTER JA;Lo;0;L;;;;;N;;;;;
+1A0E;BUGINESE LETTER NYA;Lo;0;L;;;;;N;;;;;
+1A0F;BUGINESE LETTER NYCA;Lo;0;L;;;;;N;;;;;
+1A10;BUGINESE LETTER YA;Lo;0;L;;;;;N;;;;;
+1A11;BUGINESE LETTER RA;Lo;0;L;;;;;N;;;;;
+1A12;BUGINESE LETTER LA;Lo;0;L;;;;;N;;;;;
+1A13;BUGINESE LETTER VA;Lo;0;L;;;;;N;;;;;
+1A14;BUGINESE LETTER SA;Lo;0;L;;;;;N;;;;;
+1A15;BUGINESE LETTER A;Lo;0;L;;;;;N;;;;;
+1A16;BUGINESE LETTER HA;Lo;0;L;;;;;N;;;;;
+1A17;BUGINESE VOWEL SIGN I;Mn;230;NSM;;;;;N;;;;;
+1A18;BUGINESE VOWEL SIGN U;Mn;220;NSM;;;;;N;;;;;
+1A19;BUGINESE VOWEL SIGN E;Mc;0;L;;;;;N;;;;;
+1A1A;BUGINESE VOWEL SIGN O;Mc;0;L;;;;;N;;;;;
+1A1B;BUGINESE VOWEL SIGN AE;Mc;0;L;;;;;N;;;;;
+1A1E;BUGINESE PALLAWA;Po;0;L;;;;;N;;;;;
+1A1F;BUGINESE END OF SECTION;Po;0;L;;;;;N;;;;;
+1D00;LATIN LETTER SMALL CAPITAL A;Ll;0;L;;;;;N;;;;;
+1D01;LATIN LETTER SMALL CAPITAL AE;Ll;0;L;;;;;N;;;;;
+1D02;LATIN SMALL LETTER TURNED AE;Ll;0;L;;;;;N;;;;;
+1D03;LATIN LETTER SMALL CAPITAL BARRED B;Ll;0;L;;;;;N;;;;;
+1D04;LATIN LETTER SMALL CAPITAL C;Ll;0;L;;;;;N;;;;;
+1D05;LATIN LETTER SMALL CAPITAL D;Ll;0;L;;;;;N;;;;;
+1D06;LATIN LETTER SMALL CAPITAL ETH;Ll;0;L;;;;;N;;;;;
+1D07;LATIN LETTER SMALL CAPITAL E;Ll;0;L;;;;;N;;;;;
+1D08;LATIN SMALL LETTER TURNED OPEN E;Ll;0;L;;;;;N;;;;;
+1D09;LATIN SMALL LETTER TURNED I;Ll;0;L;;;;;N;;;;;
+1D0A;LATIN LETTER SMALL CAPITAL J;Ll;0;L;;;;;N;;;;;
+1D0B;LATIN LETTER SMALL CAPITAL K;Ll;0;L;;;;;N;;;;;
+1D0C;LATIN LETTER SMALL CAPITAL L WITH STROKE;Ll;0;L;;;;;N;;;;;
+1D0D;LATIN LETTER SMALL CAPITAL M;Ll;0;L;;;;;N;;;;;
+1D0E;LATIN LETTER SMALL CAPITAL REVERSED N;Ll;0;L;;;;;N;;;;;
+1D0F;LATIN LETTER SMALL CAPITAL O;Ll;0;L;;;;;N;;;;;
+1D10;LATIN LETTER SMALL CAPITAL OPEN O;Ll;0;L;;;;;N;;;;;
+1D11;LATIN SMALL LETTER SIDEWAYS O;Ll;0;L;;;;;N;;;;;
+1D12;LATIN SMALL LETTER SIDEWAYS OPEN O;Ll;0;L;;;;;N;;;;;
+1D13;LATIN SMALL LETTER SIDEWAYS O WITH STROKE;Ll;0;L;;;;;N;;;;;
+1D14;LATIN SMALL LETTER TURNED OE;Ll;0;L;;;;;N;;;;;
+1D15;LATIN LETTER SMALL CAPITAL OU;Ll;0;L;;;;;N;;;;;
+1D16;LATIN SMALL LETTER TOP HALF O;Ll;0;L;;;;;N;;;;;
+1D17;LATIN SMALL LETTER BOTTOM HALF O;Ll;0;L;;;;;N;;;;;
+1D18;LATIN LETTER SMALL CAPITAL P;Ll;0;L;;;;;N;;;;;
+1D19;LATIN LETTER SMALL CAPITAL REVERSED R;Ll;0;L;;;;;N;;;;;
+1D1A;LATIN LETTER SMALL CAPITAL TURNED R;Ll;0;L;;;;;N;;;;;
+1D1B;LATIN LETTER SMALL CAPITAL T;Ll;0;L;;;;;N;;;;;
+1D1C;LATIN LETTER SMALL CAPITAL U;Ll;0;L;;;;;N;;;;;
+1D1D;LATIN SMALL LETTER SIDEWAYS U;Ll;0;L;;;;;N;;;;;
+1D1E;LATIN SMALL LETTER SIDEWAYS DIAERESIZED U;Ll;0;L;;;;;N;;;;;
+1D1F;LATIN SMALL LETTER SIDEWAYS TURNED M;Ll;0;L;;;;;N;;;;;
+1D20;LATIN LETTER SMALL CAPITAL V;Ll;0;L;;;;;N;;;;;
+1D21;LATIN LETTER SMALL CAPITAL W;Ll;0;L;;;;;N;;;;;
+1D22;LATIN LETTER SMALL CAPITAL Z;Ll;0;L;;;;;N;;;;;
+1D23;LATIN LETTER SMALL CAPITAL EZH;Ll;0;L;;;;;N;;;;;
+1D24;LATIN LETTER VOICED LARYNGEAL SPIRANT;Ll;0;L;;;;;N;;;;;
+1D25;LATIN LETTER AIN;Ll;0;L;;;;;N;;;;;
+1D26;GREEK LETTER SMALL CAPITAL GAMMA;Ll;0;L;;;;;N;;;;;
+1D27;GREEK LETTER SMALL CAPITAL LAMDA;Ll;0;L;;;;;N;;;;;
+1D28;GREEK LETTER SMALL CAPITAL PI;Ll;0;L;;;;;N;;;;;
+1D29;GREEK LETTER SMALL CAPITAL RHO;Ll;0;L;;;;;N;;;;;
+1D2A;GREEK LETTER SMALL CAPITAL PSI;Ll;0;L;;;;;N;;;;;
+1D2B;CYRILLIC LETTER SMALL CAPITAL EL;Ll;0;L;;;;;N;;;;;
+1D2C;MODIFIER LETTER CAPITAL A;Lm;0;L;<super> 0041;;;;N;;;;;
+1D2D;MODIFIER LETTER CAPITAL AE;Lm;0;L;<super> 00C6;;;;N;;;;;
+1D2E;MODIFIER LETTER CAPITAL B;Lm;0;L;<super> 0042;;;;N;;;;;
+1D2F;MODIFIER LETTER CAPITAL BARRED B;Lm;0;L;;;;;N;;;;;
+1D30;MODIFIER LETTER CAPITAL D;Lm;0;L;<super> 0044;;;;N;;;;;
+1D31;MODIFIER LETTER CAPITAL E;Lm;0;L;<super> 0045;;;;N;;;;;
+1D32;MODIFIER LETTER CAPITAL REVERSED E;Lm;0;L;<super> 018E;;;;N;;;;;
+1D33;MODIFIER LETTER CAPITAL G;Lm;0;L;<super> 0047;;;;N;;;;;
+1D34;MODIFIER LETTER CAPITAL H;Lm;0;L;<super> 0048;;;;N;;;;;
+1D35;MODIFIER LETTER CAPITAL I;Lm;0;L;<super> 0049;;;;N;;;;;
+1D36;MODIFIER LETTER CAPITAL J;Lm;0;L;<super> 004A;;;;N;;;;;
+1D37;MODIFIER LETTER CAPITAL K;Lm;0;L;<super> 004B;;;;N;;;;;
+1D38;MODIFIER LETTER CAPITAL L;Lm;0;L;<super> 004C;;;;N;;;;;
+1D39;MODIFIER LETTER CAPITAL M;Lm;0;L;<super> 004D;;;;N;;;;;
+1D3A;MODIFIER LETTER CAPITAL N;Lm;0;L;<super> 004E;;;;N;;;;;
+1D3B;MODIFIER LETTER CAPITAL REVERSED N;Lm;0;L;;;;;N;;;;;
+1D3C;MODIFIER LETTER CAPITAL O;Lm;0;L;<super> 004F;;;;N;;;;;
+1D3D;MODIFIER LETTER CAPITAL OU;Lm;0;L;<super> 0222;;;;N;;;;;
+1D3E;MODIFIER LETTER CAPITAL P;Lm;0;L;<super> 0050;;;;N;;;;;
+1D3F;MODIFIER LETTER CAPITAL R;Lm;0;L;<super> 0052;;;;N;;;;;
+1D40;MODIFIER LETTER CAPITAL T;Lm;0;L;<super> 0054;;;;N;;;;;
+1D41;MODIFIER LETTER CAPITAL U;Lm;0;L;<super> 0055;;;;N;;;;;
+1D42;MODIFIER LETTER CAPITAL W;Lm;0;L;<super> 0057;;;;N;;;;;
+1D43;MODIFIER LETTER SMALL A;Lm;0;L;<super> 0061;;;;N;;;;;
+1D44;MODIFIER LETTER SMALL TURNED A;Lm;0;L;<super> 0250;;;;N;;;;;
+1D45;MODIFIER LETTER SMALL ALPHA;Lm;0;L;<super> 0251;;;;N;;;;;
+1D46;MODIFIER LETTER SMALL TURNED AE;Lm;0;L;<super> 1D02;;;;N;;;;;
+1D47;MODIFIER LETTER SMALL B;Lm;0;L;<super> 0062;;;;N;;;;;
+1D48;MODIFIER LETTER SMALL D;Lm;0;L;<super> 0064;;;;N;;;;;
+1D49;MODIFIER LETTER SMALL E;Lm;0;L;<super> 0065;;;;N;;;;;
+1D4A;MODIFIER LETTER SMALL SCHWA;Lm;0;L;<super> 0259;;;;N;;;;;
+1D4B;MODIFIER LETTER SMALL OPEN E;Lm;0;L;<super> 025B;;;;N;;;;;
+1D4C;MODIFIER LETTER SMALL TURNED OPEN E;Lm;0;L;<super> 025C;;;;N;;;;;
+1D4D;MODIFIER LETTER SMALL G;Lm;0;L;<super> 0067;;;;N;;;;;
+1D4E;MODIFIER LETTER SMALL TURNED I;Lm;0;L;;;;;N;;;;;
+1D4F;MODIFIER LETTER SMALL K;Lm;0;L;<super> 006B;;;;N;;;;;
+1D50;MODIFIER LETTER SMALL M;Lm;0;L;<super> 006D;;;;N;;;;;
+1D51;MODIFIER LETTER SMALL ENG;Lm;0;L;<super> 014B;;;;N;;;;;
+1D52;MODIFIER LETTER SMALL O;Lm;0;L;<super> 006F;;;;N;;;;;
+1D53;MODIFIER LETTER SMALL OPEN O;Lm;0;L;<super> 0254;;;;N;;;;;
+1D54;MODIFIER LETTER SMALL TOP HALF O;Lm;0;L;<super> 1D16;;;;N;;;;;
+1D55;MODIFIER LETTER SMALL BOTTOM HALF O;Lm;0;L;<super> 1D17;;;;N;;;;;
+1D56;MODIFIER LETTER SMALL P;Lm;0;L;<super> 0070;;;;N;;;;;
+1D57;MODIFIER LETTER SMALL T;Lm;0;L;<super> 0074;;;;N;;;;;
+1D58;MODIFIER LETTER SMALL U;Lm;0;L;<super> 0075;;;;N;;;;;
+1D59;MODIFIER LETTER SMALL SIDEWAYS U;Lm;0;L;<super> 1D1D;;;;N;;;;;
+1D5A;MODIFIER LETTER SMALL TURNED M;Lm;0;L;<super> 026F;;;;N;;;;;
+1D5B;MODIFIER LETTER SMALL V;Lm;0;L;<super> 0076;;;;N;;;;;
+1D5C;MODIFIER LETTER SMALL AIN;Lm;0;L;<super> 1D25;;;;N;;;;;
+1D5D;MODIFIER LETTER SMALL BETA;Lm;0;L;<super> 03B2;;;;N;;;;;
+1D5E;MODIFIER LETTER SMALL GREEK GAMMA;Lm;0;L;<super> 03B3;;;;N;;;;;
+1D5F;MODIFIER LETTER SMALL DELTA;Lm;0;L;<super> 03B4;;;;N;;;;;
+1D60;MODIFIER LETTER SMALL GREEK PHI;Lm;0;L;<super> 03C6;;;;N;;;;;
+1D61;MODIFIER LETTER SMALL CHI;Lm;0;L;<super> 03C7;;;;N;;;;;
+1D62;LATIN SUBSCRIPT SMALL LETTER I;Ll;0;L;<sub> 0069;;;;N;;;;;
+1D63;LATIN SUBSCRIPT SMALL LETTER R;Ll;0;L;<sub> 0072;;;;N;;;;;
+1D64;LATIN SUBSCRIPT SMALL LETTER U;Ll;0;L;<sub> 0075;;;;N;;;;;
+1D65;LATIN SUBSCRIPT SMALL LETTER V;Ll;0;L;<sub> 0076;;;;N;;;;;
+1D66;GREEK SUBSCRIPT SMALL LETTER BETA;Ll;0;L;<sub> 03B2;;;;N;;;;;
+1D67;GREEK SUBSCRIPT SMALL LETTER GAMMA;Ll;0;L;<sub> 03B3;;;;N;;;;;
+1D68;GREEK SUBSCRIPT SMALL LETTER RHO;Ll;0;L;<sub> 03C1;;;;N;;;;;
+1D69;GREEK SUBSCRIPT SMALL LETTER PHI;Ll;0;L;<sub> 03C6;;;;N;;;;;
+1D6A;GREEK SUBSCRIPT SMALL LETTER CHI;Ll;0;L;<sub> 03C7;;;;N;;;;;
+1D6B;LATIN SMALL LETTER UE;Ll;0;L;;;;;N;;;;;
+1D6C;LATIN SMALL LETTER B WITH MIDDLE TILDE;Ll;0;L;;;;;N;;;;;
+1D6D;LATIN SMALL LETTER D WITH MIDDLE TILDE;Ll;0;L;;;;;N;;;;;
+1D6E;LATIN SMALL LETTER F WITH MIDDLE TILDE;Ll;0;L;;;;;N;;;;;
+1D6F;LATIN SMALL LETTER M WITH MIDDLE TILDE;Ll;0;L;;;;;N;;;;;
+1D70;LATIN SMALL LETTER N WITH MIDDLE TILDE;Ll;0;L;;;;;N;;;;;
+1D71;LATIN SMALL LETTER P WITH MIDDLE TILDE;Ll;0;L;;;;;N;;;;;
+1D72;LATIN SMALL LETTER R WITH MIDDLE TILDE;Ll;0;L;;;;;N;;;;;
+1D73;LATIN SMALL LETTER R WITH FISHHOOK AND MIDDLE TILDE;Ll;0;L;;;;;N;;;;;
+1D74;LATIN SMALL LETTER S WITH MIDDLE TILDE;Ll;0;L;;;;;N;;;;;
+1D75;LATIN SMALL LETTER T WITH MIDDLE TILDE;Ll;0;L;;;;;N;;;;;
+1D76;LATIN SMALL LETTER Z WITH MIDDLE TILDE;Ll;0;L;;;;;N;;;;;
+1D77;LATIN SMALL LETTER TURNED G;Ll;0;L;;;;;N;;;;;
+1D78;MODIFIER LETTER CYRILLIC EN;Lm;0;L;<super> 043D;;;;N;;;;;
+1D79;LATIN SMALL LETTER INSULAR G;Ll;0;L;;;;;N;;;;;
+1D7A;LATIN SMALL LETTER TH WITH STRIKETHROUGH;Ll;0;L;;;;;N;;;;;
+1D7B;LATIN SMALL CAPITAL LETTER I WITH STROKE;Ll;0;L;;;;;N;;;;;
+1D7C;LATIN SMALL LETTER IOTA WITH STROKE;Ll;0;L;;;;;N;;;;;
+1D7D;LATIN SMALL LETTER P WITH STROKE;Ll;0;L;;;;;N;;;;;
+1D7E;LATIN SMALL CAPITAL LETTER U WITH STROKE;Ll;0;L;;;;;N;;;;;
+1D7F;LATIN SMALL LETTER UPSILON WITH STROKE;Ll;0;L;;;;;N;;;;;
+1D80;LATIN SMALL LETTER B WITH PALATAL HOOK;Ll;0;L;;;;;N;;;;;
+1D81;LATIN SMALL LETTER D WITH PALATAL HOOK;Ll;0;L;;;;;N;;;;;
+1D82;LATIN SMALL LETTER F WITH PALATAL HOOK;Ll;0;L;;;;;N;;;;;
+1D83;LATIN SMALL LETTER G WITH PALATAL HOOK;Ll;0;L;;;;;N;;;;;
+1D84;LATIN SMALL LETTER K WITH PALATAL HOOK;Ll;0;L;;;;;N;;;;;
+1D85;LATIN SMALL LETTER L WITH PALATAL HOOK;Ll;0;L;;;;;N;;;;;
+1D86;LATIN SMALL LETTER M WITH PALATAL HOOK;Ll;0;L;;;;;N;;;;;
+1D87;LATIN SMALL LETTER N WITH PALATAL HOOK;Ll;0;L;;;;;N;;;;;
+1D88;LATIN SMALL LETTER P WITH PALATAL HOOK;Ll;0;L;;;;;N;;;;;
+1D89;LATIN SMALL LETTER R WITH PALATAL HOOK;Ll;0;L;;;;;N;;;;;
+1D8A;LATIN SMALL LETTER S WITH PALATAL HOOK;Ll;0;L;;;;;N;;;;;
+1D8B;LATIN SMALL LETTER ESH WITH PALATAL HOOK;Ll;0;L;;;;;N;;;;;
+1D8C;LATIN SMALL LETTER V WITH PALATAL HOOK;Ll;0;L;;;;;N;;;;;
+1D8D;LATIN SMALL LETTER X WITH PALATAL HOOK;Ll;0;L;;;;;N;;;;;
+1D8E;LATIN SMALL LETTER Z WITH PALATAL HOOK;Ll;0;L;;;;;N;;;;;
+1D8F;LATIN SMALL LETTER A WITH RETROFLEX HOOK;Ll;0;L;;;;;N;;;;;
+1D90;LATIN SMALL LETTER ALPHA WITH RETROFLEX HOOK;Ll;0;L;;;;;N;;;;;
+1D91;LATIN SMALL LETTER D WITH HOOK AND TAIL;Ll;0;L;;;;;N;;;;;
+1D92;LATIN SMALL LETTER E WITH RETROFLEX HOOK;Ll;0;L;;;;;N;;;;;
+1D93;LATIN SMALL LETTER OPEN E WITH RETROFLEX HOOK;Ll;0;L;;;;;N;;;;;
+1D94;LATIN SMALL LETTER REVERSED OPEN E WITH RETROFLEX HOOK;Ll;0;L;;;;;N;;;;;
+1D95;LATIN SMALL LETTER SCHWA WITH RETROFLEX HOOK;Ll;0;L;;;;;N;;;;;
+1D96;LATIN SMALL LETTER I WITH RETROFLEX HOOK;Ll;0;L;;;;;N;;;;;
+1D97;LATIN SMALL LETTER OPEN O WITH RETROFLEX HOOK;Ll;0;L;;;;;N;;;;;
+1D98;LATIN SMALL LETTER ESH WITH RETROFLEX HOOK;Ll;0;L;;;;;N;;;;;
+1D99;LATIN SMALL LETTER U WITH RETROFLEX HOOK;Ll;0;L;;;;;N;;;;;
+1D9A;LATIN SMALL LETTER EZH WITH RETROFLEX HOOK;Ll;0;L;;;;;N;;;;;
+1D9B;MODIFIER LETTER SMALL TURNED ALPHA;Lm;0;L;<super> 0252;;;;N;;;;;
+1D9C;MODIFIER LETTER SMALL C;Lm;0;L;<super> 0063;;;;N;;;;;
+1D9D;MODIFIER LETTER SMALL C WITH CURL;Lm;0;L;<super> 0255;;;;N;;;;;
+1D9E;MODIFIER LETTER SMALL ETH;Lm;0;L;<super> 00F0;;;;N;;;;;
+1D9F;MODIFIER LETTER SMALL REVERSED OPEN E;Lm;0;L;<super> 025C;;;;N;;;;;
+1DA0;MODIFIER LETTER SMALL F;Lm;0;L;<super> 0066;;;;N;;;;;
+1DA1;MODIFIER LETTER SMALL DOTLESS J WITH STROKE;Lm;0;L;<super> 025F;;;;N;;;;;
+1DA2;MODIFIER LETTER SMALL SCRIPT G;Lm;0;L;<super> 0261;;;;N;;;;;
+1DA3;MODIFIER LETTER SMALL TURNED H;Lm;0;L;<super> 0265;;;;N;;;;;
+1DA4;MODIFIER LETTER SMALL I WITH STROKE;Lm;0;L;<super> 0268;;;;N;;;;;
+1DA5;MODIFIER LETTER SMALL IOTA;Lm;0;L;<super> 0269;;;;N;;;;;
+1DA6;MODIFIER LETTER SMALL CAPITAL I;Lm;0;L;<super> 026A;;;;N;;;;;
+1DA7;MODIFIER LETTER SMALL CAPITAL I WITH STROKE;Lm;0;L;<super> 1D7B;;;;N;;;;;
+1DA8;MODIFIER LETTER SMALL J WITH CROSSED-TAIL;Lm;0;L;<super> 029D;;;;N;;;;;
+1DA9;MODIFIER LETTER SMALL L WITH RETROFLEX HOOK;Lm;0;L;<super> 026D;;;;N;;;;;
+1DAA;MODIFIER LETTER SMALL L WITH PALATAL HOOK;Lm;0;L;<super> 1D85;;;;N;;;;;
+1DAB;MODIFIER LETTER SMALL CAPITAL L;Lm;0;L;<super> 029F;;;;N;;;;;
+1DAC;MODIFIER LETTER SMALL M WITH HOOK;Lm;0;L;<super> 0271;;;;N;;;;;
+1DAD;MODIFIER LETTER SMALL TURNED M WITH LONG LEG;Lm;0;L;<super> 0270;;;;N;;;;;
+1DAE;MODIFIER LETTER SMALL N WITH LEFT HOOK;Lm;0;L;<super> 0272;;;;N;;;;;
+1DAF;MODIFIER LETTER SMALL N WITH RETROFLEX HOOK;Lm;0;L;<super> 0273;;;;N;;;;;
+1DB0;MODIFIER LETTER SMALL CAPITAL N;Lm;0;L;<super> 0274;;;;N;;;;;
+1DB1;MODIFIER LETTER SMALL BARRED O;Lm;0;L;<super> 0275;;;;N;;;;;
+1DB2;MODIFIER LETTER SMALL PHI;Lm;0;L;<super> 0278;;;;N;;;;;
+1DB3;MODIFIER LETTER SMALL S WITH HOOK;Lm;0;L;<super> 0282;;;;N;;;;;
+1DB4;MODIFIER LETTER SMALL ESH;Lm;0;L;<super> 0283;;;;N;;;;;
+1DB5;MODIFIER LETTER SMALL T WITH PALATAL HOOK;Lm;0;L;<super> 01AB;;;;N;;;;;
+1DB6;MODIFIER LETTER SMALL U BAR;Lm;0;L;<super> 0289;;;;N;;;;;
+1DB7;MODIFIER LETTER SMALL UPSILON;Lm;0;L;<super> 028A;;;;N;;;;;
+1DB8;MODIFIER LETTER SMALL CAPITAL U;Lm;0;L;<super> 1D1C;;;;N;;;;;
+1DB9;MODIFIER LETTER SMALL V WITH HOOK;Lm;0;L;<super> 028B;;;;N;;;;;
+1DBA;MODIFIER LETTER SMALL TURNED V;Lm;0;L;<super> 028C;;;;N;;;;;
+1DBB;MODIFIER LETTER SMALL Z;Lm;0;L;<super> 007A;;;;N;;;;;
+1DBC;MODIFIER LETTER SMALL Z WITH RETROFLEX HOOK;Lm;0;L;<super> 0290;;;;N;;;;;
+1DBD;MODIFIER LETTER SMALL Z WITH CURL;Lm;0;L;<super> 0291;;;;N;;;;;
+1DBE;MODIFIER LETTER SMALL EZH;Lm;0;L;<super> 0292;;;;N;;;;;
+1DBF;MODIFIER LETTER SMALL THETA;Lm;0;L;<super> 03B8;;;;N;;;;;
+1DC0;COMBINING DOTTED GRAVE ACCENT;Mn;230;NSM;;;;;N;;;;;
+1DC1;COMBINING DOTTED ACUTE ACCENT;Mn;230;NSM;;;;;N;;;;;
+1DC2;COMBINING SNAKE BELOW;Mn;220;NSM;;;;;N;;;;;
+1DC3;COMBINING SUSPENSION MARK;Mn;230;NSM;;;;;N;;;;;
+1E00;LATIN CAPITAL LETTER A WITH RING BELOW;Lu;0;L;0041 0325;;;;N;;;;1E01;
+1E01;LATIN SMALL LETTER A WITH RING BELOW;Ll;0;L;0061 0325;;;;N;;;1E00;;1E00
+1E02;LATIN CAPITAL LETTER B WITH DOT ABOVE;Lu;0;L;0042 0307;;;;N;;;;1E03;
+1E03;LATIN SMALL LETTER B WITH DOT ABOVE;Ll;0;L;0062 0307;;;;N;;;1E02;;1E02
+1E04;LATIN CAPITAL LETTER B WITH DOT BELOW;Lu;0;L;0042 0323;;;;N;;;;1E05;
+1E05;LATIN SMALL LETTER B WITH DOT BELOW;Ll;0;L;0062 0323;;;;N;;;1E04;;1E04
+1E06;LATIN CAPITAL LETTER B WITH LINE BELOW;Lu;0;L;0042 0331;;;;N;;;;1E07;
+1E07;LATIN SMALL LETTER B WITH LINE BELOW;Ll;0;L;0062 0331;;;;N;;;1E06;;1E06
+1E08;LATIN CAPITAL LETTER C WITH CEDILLA AND ACUTE;Lu;0;L;00C7 0301;;;;N;;;;1E09;
+1E09;LATIN SMALL LETTER C WITH CEDILLA AND ACUTE;Ll;0;L;00E7 0301;;;;N;;;1E08;;1E08
+1E0A;LATIN CAPITAL LETTER D WITH DOT ABOVE;Lu;0;L;0044 0307;;;;N;;;;1E0B;
+1E0B;LATIN SMALL LETTER D WITH DOT ABOVE;Ll;0;L;0064 0307;;;;N;;;1E0A;;1E0A
+1E0C;LATIN CAPITAL LETTER D WITH DOT BELOW;Lu;0;L;0044 0323;;;;N;;;;1E0D;
+1E0D;LATIN SMALL LETTER D WITH DOT BELOW;Ll;0;L;0064 0323;;;;N;;;1E0C;;1E0C
+1E0E;LATIN CAPITAL LETTER D WITH LINE BELOW;Lu;0;L;0044 0331;;;;N;;;;1E0F;
+1E0F;LATIN SMALL LETTER D WITH LINE BELOW;Ll;0;L;0064 0331;;;;N;;;1E0E;;1E0E
+1E10;LATIN CAPITAL LETTER D WITH CEDILLA;Lu;0;L;0044 0327;;;;N;;;;1E11;
+1E11;LATIN SMALL LETTER D WITH CEDILLA;Ll;0;L;0064 0327;;;;N;;;1E10;;1E10
+1E12;LATIN CAPITAL LETTER D WITH CIRCUMFLEX BELOW;Lu;0;L;0044 032D;;;;N;;;;1E13;
+1E13;LATIN SMALL LETTER D WITH CIRCUMFLEX BELOW;Ll;0;L;0064 032D;;;;N;;;1E12;;1E12
+1E14;LATIN CAPITAL LETTER E WITH MACRON AND GRAVE;Lu;0;L;0112 0300;;;;N;;;;1E15;
+1E15;LATIN SMALL LETTER E WITH MACRON AND GRAVE;Ll;0;L;0113 0300;;;;N;;;1E14;;1E14
+1E16;LATIN CAPITAL LETTER E WITH MACRON AND ACUTE;Lu;0;L;0112 0301;;;;N;;;;1E17;
+1E17;LATIN SMALL LETTER E WITH MACRON AND ACUTE;Ll;0;L;0113 0301;;;;N;;;1E16;;1E16
+1E18;LATIN CAPITAL LETTER E WITH CIRCUMFLEX BELOW;Lu;0;L;0045 032D;;;;N;;;;1E19;
+1E19;LATIN SMALL LETTER E WITH CIRCUMFLEX BELOW;Ll;0;L;0065 032D;;;;N;;;1E18;;1E18
+1E1A;LATIN CAPITAL LETTER E WITH TILDE BELOW;Lu;0;L;0045 0330;;;;N;;;;1E1B;
+1E1B;LATIN SMALL LETTER E WITH TILDE BELOW;Ll;0;L;0065 0330;;;;N;;;1E1A;;1E1A
+1E1C;LATIN CAPITAL LETTER E WITH CEDILLA AND BREVE;Lu;0;L;0228 0306;;;;N;;;;1E1D;
+1E1D;LATIN SMALL LETTER E WITH CEDILLA AND BREVE;Ll;0;L;0229 0306;;;;N;;;1E1C;;1E1C
+1E1E;LATIN CAPITAL LETTER F WITH DOT ABOVE;Lu;0;L;0046 0307;;;;N;;;;1E1F;
+1E1F;LATIN SMALL LETTER F WITH DOT ABOVE;Ll;0;L;0066 0307;;;;N;;;1E1E;;1E1E
+1E20;LATIN CAPITAL LETTER G WITH MACRON;Lu;0;L;0047 0304;;;;N;;;;1E21;
+1E21;LATIN SMALL LETTER G WITH MACRON;Ll;0;L;0067 0304;;;;N;;;1E20;;1E20
+1E22;LATIN CAPITAL LETTER H WITH DOT ABOVE;Lu;0;L;0048 0307;;;;N;;;;1E23;
+1E23;LATIN SMALL LETTER H WITH DOT ABOVE;Ll;0;L;0068 0307;;;;N;;;1E22;;1E22
+1E24;LATIN CAPITAL LETTER H WITH DOT BELOW;Lu;0;L;0048 0323;;;;N;;;;1E25;
+1E25;LATIN SMALL LETTER H WITH DOT BELOW;Ll;0;L;0068 0323;;;;N;;;1E24;;1E24
+1E26;LATIN CAPITAL LETTER H WITH DIAERESIS;Lu;0;L;0048 0308;;;;N;;;;1E27;
+1E27;LATIN SMALL LETTER H WITH DIAERESIS;Ll;0;L;0068 0308;;;;N;;;1E26;;1E26
+1E28;LATIN CAPITAL LETTER H WITH CEDILLA;Lu;0;L;0048 0327;;;;N;;;;1E29;
+1E29;LATIN SMALL LETTER H WITH CEDILLA;Ll;0;L;0068 0327;;;;N;;;1E28;;1E28
+1E2A;LATIN CAPITAL LETTER H WITH BREVE BELOW;Lu;0;L;0048 032E;;;;N;;;;1E2B;
+1E2B;LATIN SMALL LETTER H WITH BREVE BELOW;Ll;0;L;0068 032E;;;;N;;;1E2A;;1E2A
+1E2C;LATIN CAPITAL LETTER I WITH TILDE BELOW;Lu;0;L;0049 0330;;;;N;;;;1E2D;
+1E2D;LATIN SMALL LETTER I WITH TILDE BELOW;Ll;0;L;0069 0330;;;;N;;;1E2C;;1E2C
+1E2E;LATIN CAPITAL LETTER I WITH DIAERESIS AND ACUTE;Lu;0;L;00CF 0301;;;;N;;;;1E2F;
+1E2F;LATIN SMALL LETTER I WITH DIAERESIS AND ACUTE;Ll;0;L;00EF 0301;;;;N;;;1E2E;;1E2E
+1E30;LATIN CAPITAL LETTER K WITH ACUTE;Lu;0;L;004B 0301;;;;N;;;;1E31;
+1E31;LATIN SMALL LETTER K WITH ACUTE;Ll;0;L;006B 0301;;;;N;;;1E30;;1E30
+1E32;LATIN CAPITAL LETTER K WITH DOT BELOW;Lu;0;L;004B 0323;;;;N;;;;1E33;
+1E33;LATIN SMALL LETTER K WITH DOT BELOW;Ll;0;L;006B 0323;;;;N;;;1E32;;1E32
+1E34;LATIN CAPITAL LETTER K WITH LINE BELOW;Lu;0;L;004B 0331;;;;N;;;;1E35;
+1E35;LATIN SMALL LETTER K WITH LINE BELOW;Ll;0;L;006B 0331;;;;N;;;1E34;;1E34
+1E36;LATIN CAPITAL LETTER L WITH DOT BELOW;Lu;0;L;004C 0323;;;;N;;;;1E37;
+1E37;LATIN SMALL LETTER L WITH DOT BELOW;Ll;0;L;006C 0323;;;;N;;;1E36;;1E36
+1E38;LATIN CAPITAL LETTER L WITH DOT BELOW AND MACRON;Lu;0;L;1E36 0304;;;;N;;;;1E39;
+1E39;LATIN SMALL LETTER L WITH DOT BELOW AND MACRON;Ll;0;L;1E37 0304;;;;N;;;1E38;;1E38
+1E3A;LATIN CAPITAL LETTER L WITH LINE BELOW;Lu;0;L;004C 0331;;;;N;;;;1E3B;
+1E3B;LATIN SMALL LETTER L WITH LINE BELOW;Ll;0;L;006C 0331;;;;N;;;1E3A;;1E3A
+1E3C;LATIN CAPITAL LETTER L WITH CIRCUMFLEX BELOW;Lu;0;L;004C 032D;;;;N;;;;1E3D;
+1E3D;LATIN SMALL LETTER L WITH CIRCUMFLEX BELOW;Ll;0;L;006C 032D;;;;N;;;1E3C;;1E3C
+1E3E;LATIN CAPITAL LETTER M WITH ACUTE;Lu;0;L;004D 0301;;;;N;;;;1E3F;
+1E3F;LATIN SMALL LETTER M WITH ACUTE;Ll;0;L;006D 0301;;;;N;;;1E3E;;1E3E
+1E40;LATIN CAPITAL LETTER M WITH DOT ABOVE;Lu;0;L;004D 0307;;;;N;;;;1E41;
+1E41;LATIN SMALL LETTER M WITH DOT ABOVE;Ll;0;L;006D 0307;;;;N;;;1E40;;1E40
+1E42;LATIN CAPITAL LETTER M WITH DOT BELOW;Lu;0;L;004D 0323;;;;N;;;;1E43;
+1E43;LATIN SMALL LETTER M WITH DOT BELOW;Ll;0;L;006D 0323;;;;N;;;1E42;;1E42
+1E44;LATIN CAPITAL LETTER N WITH DOT ABOVE;Lu;0;L;004E 0307;;;;N;;;;1E45;
+1E45;LATIN SMALL LETTER N WITH DOT ABOVE;Ll;0;L;006E 0307;;;;N;;;1E44;;1E44
+1E46;LATIN CAPITAL LETTER N WITH DOT BELOW;Lu;0;L;004E 0323;;;;N;;;;1E47;
+1E47;LATIN SMALL LETTER N WITH DOT BELOW;Ll;0;L;006E 0323;;;;N;;;1E46;;1E46
+1E48;LATIN CAPITAL LETTER N WITH LINE BELOW;Lu;0;L;004E 0331;;;;N;;;;1E49;
+1E49;LATIN SMALL LETTER N WITH LINE BELOW;Ll;0;L;006E 0331;;;;N;;;1E48;;1E48
+1E4A;LATIN CAPITAL LETTER N WITH CIRCUMFLEX BELOW;Lu;0;L;004E 032D;;;;N;;;;1E4B;
+1E4B;LATIN SMALL LETTER N WITH CIRCUMFLEX BELOW;Ll;0;L;006E 032D;;;;N;;;1E4A;;1E4A
+1E4C;LATIN CAPITAL LETTER O WITH TILDE AND ACUTE;Lu;0;L;00D5 0301;;;;N;;;;1E4D;
+1E4D;LATIN SMALL LETTER O WITH TILDE AND ACUTE;Ll;0;L;00F5 0301;;;;N;;;1E4C;;1E4C
+1E4E;LATIN CAPITAL LETTER O WITH TILDE AND DIAERESIS;Lu;0;L;00D5 0308;;;;N;;;;1E4F;
+1E4F;LATIN SMALL LETTER O WITH TILDE AND DIAERESIS;Ll;0;L;00F5 0308;;;;N;;;1E4E;;1E4E
+1E50;LATIN CAPITAL LETTER O WITH MACRON AND GRAVE;Lu;0;L;014C 0300;;;;N;;;;1E51;
+1E51;LATIN SMALL LETTER O WITH MACRON AND GRAVE;Ll;0;L;014D 0300;;;;N;;;1E50;;1E50
+1E52;LATIN CAPITAL LETTER O WITH MACRON AND ACUTE;Lu;0;L;014C 0301;;;;N;;;;1E53;
+1E53;LATIN SMALL LETTER O WITH MACRON AND ACUTE;Ll;0;L;014D 0301;;;;N;;;1E52;;1E52
+1E54;LATIN CAPITAL LETTER P WITH ACUTE;Lu;0;L;0050 0301;;;;N;;;;1E55;
+1E55;LATIN SMALL LETTER P WITH ACUTE;Ll;0;L;0070 0301;;;;N;;;1E54;;1E54
+1E56;LATIN CAPITAL LETTER P WITH DOT ABOVE;Lu;0;L;0050 0307;;;;N;;;;1E57;
+1E57;LATIN SMALL LETTER P WITH DOT ABOVE;Ll;0;L;0070 0307;;;;N;;;1E56;;1E56
+1E58;LATIN CAPITAL LETTER R WITH DOT ABOVE;Lu;0;L;0052 0307;;;;N;;;;1E59;
+1E59;LATIN SMALL LETTER R WITH DOT ABOVE;Ll;0;L;0072 0307;;;;N;;;1E58;;1E58
+1E5A;LATIN CAPITAL LETTER R WITH DOT BELOW;Lu;0;L;0052 0323;;;;N;;;;1E5B;
+1E5B;LATIN SMALL LETTER R WITH DOT BELOW;Ll;0;L;0072 0323;;;;N;;;1E5A;;1E5A
+1E5C;LATIN CAPITAL LETTER R WITH DOT BELOW AND MACRON;Lu;0;L;1E5A 0304;;;;N;;;;1E5D;
+1E5D;LATIN SMALL LETTER R WITH DOT BELOW AND MACRON;Ll;0;L;1E5B 0304;;;;N;;;1E5C;;1E5C
+1E5E;LATIN CAPITAL LETTER R WITH LINE BELOW;Lu;0;L;0052 0331;;;;N;;;;1E5F;
+1E5F;LATIN SMALL LETTER R WITH LINE BELOW;Ll;0;L;0072 0331;;;;N;;;1E5E;;1E5E
+1E60;LATIN CAPITAL LETTER S WITH DOT ABOVE;Lu;0;L;0053 0307;;;;N;;;;1E61;
+1E61;LATIN SMALL LETTER S WITH DOT ABOVE;Ll;0;L;0073 0307;;;;N;;;1E60;;1E60
+1E62;LATIN CAPITAL LETTER S WITH DOT BELOW;Lu;0;L;0053 0323;;;;N;;;;1E63;
+1E63;LATIN SMALL LETTER S WITH DOT BELOW;Ll;0;L;0073 0323;;;;N;;;1E62;;1E62
+1E64;LATIN CAPITAL LETTER S WITH ACUTE AND DOT ABOVE;Lu;0;L;015A 0307;;;;N;;;;1E65;
+1E65;LATIN SMALL LETTER S WITH ACUTE AND DOT ABOVE;Ll;0;L;015B 0307;;;;N;;;1E64;;1E64
+1E66;LATIN CAPITAL LETTER S WITH CARON AND DOT ABOVE;Lu;0;L;0160 0307;;;;N;;;;1E67;
+1E67;LATIN SMALL LETTER S WITH CARON AND DOT ABOVE;Ll;0;L;0161 0307;;;;N;;;1E66;;1E66
+1E68;LATIN CAPITAL LETTER S WITH DOT BELOW AND DOT ABOVE;Lu;0;L;1E62 0307;;;;N;;;;1E69;
+1E69;LATIN SMALL LETTER S WITH DOT BELOW AND DOT ABOVE;Ll;0;L;1E63 0307;;;;N;;;1E68;;1E68
+1E6A;LATIN CAPITAL LETTER T WITH DOT ABOVE;Lu;0;L;0054 0307;;;;N;;;;1E6B;
+1E6B;LATIN SMALL LETTER T WITH DOT ABOVE;Ll;0;L;0074 0307;;;;N;;;1E6A;;1E6A
+1E6C;LATIN CAPITAL LETTER T WITH DOT BELOW;Lu;0;L;0054 0323;;;;N;;;;1E6D;
+1E6D;LATIN SMALL LETTER T WITH DOT BELOW;Ll;0;L;0074 0323;;;;N;;;1E6C;;1E6C
+1E6E;LATIN CAPITAL LETTER T WITH LINE BELOW;Lu;0;L;0054 0331;;;;N;;;;1E6F;
+1E6F;LATIN SMALL LETTER T WITH LINE BELOW;Ll;0;L;0074 0331;;;;N;;;1E6E;;1E6E
+1E70;LATIN CAPITAL LETTER T WITH CIRCUMFLEX BELOW;Lu;0;L;0054 032D;;;;N;;;;1E71;
+1E71;LATIN SMALL LETTER T WITH CIRCUMFLEX BELOW;Ll;0;L;0074 032D;;;;N;;;1E70;;1E70
+1E72;LATIN CAPITAL LETTER U WITH DIAERESIS BELOW;Lu;0;L;0055 0324;;;;N;;;;1E73;
+1E73;LATIN SMALL LETTER U WITH DIAERESIS BELOW;Ll;0;L;0075 0324;;;;N;;;1E72;;1E72
+1E74;LATIN CAPITAL LETTER U WITH TILDE BELOW;Lu;0;L;0055 0330;;;;N;;;;1E75;
+1E75;LATIN SMALL LETTER U WITH TILDE BELOW;Ll;0;L;0075 0330;;;;N;;;1E74;;1E74
+1E76;LATIN CAPITAL LETTER U WITH CIRCUMFLEX BELOW;Lu;0;L;0055 032D;;;;N;;;;1E77;
+1E77;LATIN SMALL LETTER U WITH CIRCUMFLEX BELOW;Ll;0;L;0075 032D;;;;N;;;1E76;;1E76
+1E78;LATIN CAPITAL LETTER U WITH TILDE AND ACUTE;Lu;0;L;0168 0301;;;;N;;;;1E79;
+1E79;LATIN SMALL LETTER U WITH TILDE AND ACUTE;Ll;0;L;0169 0301;;;;N;;;1E78;;1E78
+1E7A;LATIN CAPITAL LETTER U WITH MACRON AND DIAERESIS;Lu;0;L;016A 0308;;;;N;;;;1E7B;
+1E7B;LATIN SMALL LETTER U WITH MACRON AND DIAERESIS;Ll;0;L;016B 0308;;;;N;;;1E7A;;1E7A
+1E7C;LATIN CAPITAL LETTER V WITH TILDE;Lu;0;L;0056 0303;;;;N;;;;1E7D;
+1E7D;LATIN SMALL LETTER V WITH TILDE;Ll;0;L;0076 0303;;;;N;;;1E7C;;1E7C
+1E7E;LATIN CAPITAL LETTER V WITH DOT BELOW;Lu;0;L;0056 0323;;;;N;;;;1E7F;
+1E7F;LATIN SMALL LETTER V WITH DOT BELOW;Ll;0;L;0076 0323;;;;N;;;1E7E;;1E7E
+1E80;LATIN CAPITAL LETTER W WITH GRAVE;Lu;0;L;0057 0300;;;;N;;;;1E81;
+1E81;LATIN SMALL LETTER W WITH GRAVE;Ll;0;L;0077 0300;;;;N;;;1E80;;1E80
+1E82;LATIN CAPITAL LETTER W WITH ACUTE;Lu;0;L;0057 0301;;;;N;;;;1E83;
+1E83;LATIN SMALL LETTER W WITH ACUTE;Ll;0;L;0077 0301;;;;N;;;1E82;;1E82
+1E84;LATIN CAPITAL LETTER W WITH DIAERESIS;Lu;0;L;0057 0308;;;;N;;;;1E85;
+1E85;LATIN SMALL LETTER W WITH DIAERESIS;Ll;0;L;0077 0308;;;;N;;;1E84;;1E84
+1E86;LATIN CAPITAL LETTER W WITH DOT ABOVE;Lu;0;L;0057 0307;;;;N;;;;1E87;
+1E87;LATIN SMALL LETTER W WITH DOT ABOVE;Ll;0;L;0077 0307;;;;N;;;1E86;;1E86
+1E88;LATIN CAPITAL LETTER W WITH DOT BELOW;Lu;0;L;0057 0323;;;;N;;;;1E89;
+1E89;LATIN SMALL LETTER W WITH DOT BELOW;Ll;0;L;0077 0323;;;;N;;;1E88;;1E88
+1E8A;LATIN CAPITAL LETTER X WITH DOT ABOVE;Lu;0;L;0058 0307;;;;N;;;;1E8B;
+1E8B;LATIN SMALL LETTER X WITH DOT ABOVE;Ll;0;L;0078 0307;;;;N;;;1E8A;;1E8A
+1E8C;LATIN CAPITAL LETTER X WITH DIAERESIS;Lu;0;L;0058 0308;;;;N;;;;1E8D;
+1E8D;LATIN SMALL LETTER X WITH DIAERESIS;Ll;0;L;0078 0308;;;;N;;;1E8C;;1E8C
+1E8E;LATIN CAPITAL LETTER Y WITH DOT ABOVE;Lu;0;L;0059 0307;;;;N;;;;1E8F;
+1E8F;LATIN SMALL LETTER Y WITH DOT ABOVE;Ll;0;L;0079 0307;;;;N;;;1E8E;;1E8E
+1E90;LATIN CAPITAL LETTER Z WITH CIRCUMFLEX;Lu;0;L;005A 0302;;;;N;;;;1E91;
+1E91;LATIN SMALL LETTER Z WITH CIRCUMFLEX;Ll;0;L;007A 0302;;;;N;;;1E90;;1E90
+1E92;LATIN CAPITAL LETTER Z WITH DOT BELOW;Lu;0;L;005A 0323;;;;N;;;;1E93;
+1E93;LATIN SMALL LETTER Z WITH DOT BELOW;Ll;0;L;007A 0323;;;;N;;;1E92;;1E92
+1E94;LATIN CAPITAL LETTER Z WITH LINE BELOW;Lu;0;L;005A 0331;;;;N;;;;1E95;
+1E95;LATIN SMALL LETTER Z WITH LINE BELOW;Ll;0;L;007A 0331;;;;N;;;1E94;;1E94
+1E96;LATIN SMALL LETTER H WITH LINE BELOW;Ll;0;L;0068 0331;;;;N;;;;;
+1E97;LATIN SMALL LETTER T WITH DIAERESIS;Ll;0;L;0074 0308;;;;N;;;;;
+1E98;LATIN SMALL LETTER W WITH RING ABOVE;Ll;0;L;0077 030A;;;;N;;;;;
+1E99;LATIN SMALL LETTER Y WITH RING ABOVE;Ll;0;L;0079 030A;;;;N;;;;;
+1E9A;LATIN SMALL LETTER A WITH RIGHT HALF RING;Ll;0;L;<compat> 0061 02BE;;;;N;;;;;
+1E9B;LATIN SMALL LETTER LONG S WITH DOT ABOVE;Ll;0;L;017F 0307;;;;N;;;1E60;;1E60
+1EA0;LATIN CAPITAL LETTER A WITH DOT BELOW;Lu;0;L;0041 0323;;;;N;;;;1EA1;
+1EA1;LATIN SMALL LETTER A WITH DOT BELOW;Ll;0;L;0061 0323;;;;N;;;1EA0;;1EA0
+1EA2;LATIN CAPITAL LETTER A WITH HOOK ABOVE;Lu;0;L;0041 0309;;;;N;;;;1EA3;
+1EA3;LATIN SMALL LETTER A WITH HOOK ABOVE;Ll;0;L;0061 0309;;;;N;;;1EA2;;1EA2
+1EA4;LATIN CAPITAL LETTER A WITH CIRCUMFLEX AND ACUTE;Lu;0;L;00C2 0301;;;;N;;;;1EA5;
+1EA5;LATIN SMALL LETTER A WITH CIRCUMFLEX AND ACUTE;Ll;0;L;00E2 0301;;;;N;;;1EA4;;1EA4
+1EA6;LATIN CAPITAL LETTER A WITH CIRCUMFLEX AND GRAVE;Lu;0;L;00C2 0300;;;;N;;;;1EA7;
+1EA7;LATIN SMALL LETTER A WITH CIRCUMFLEX AND GRAVE;Ll;0;L;00E2 0300;;;;N;;;1EA6;;1EA6
+1EA8;LATIN CAPITAL LETTER A WITH CIRCUMFLEX AND HOOK ABOVE;Lu;0;L;00C2 0309;;;;N;;;;1EA9;
+1EA9;LATIN SMALL LETTER A WITH CIRCUMFLEX AND HOOK ABOVE;Ll;0;L;00E2 0309;;;;N;;;1EA8;;1EA8
+1EAA;LATIN CAPITAL LETTER A WITH CIRCUMFLEX AND TILDE;Lu;0;L;00C2 0303;;;;N;;;;1EAB;
+1EAB;LATIN SMALL LETTER A WITH CIRCUMFLEX AND TILDE;Ll;0;L;00E2 0303;;;;N;;;1EAA;;1EAA
+1EAC;LATIN CAPITAL LETTER A WITH CIRCUMFLEX AND DOT BELOW;Lu;0;L;1EA0 0302;;;;N;;;;1EAD;
+1EAD;LATIN SMALL LETTER A WITH CIRCUMFLEX AND DOT BELOW;Ll;0;L;1EA1 0302;;;;N;;;1EAC;;1EAC
+1EAE;LATIN CAPITAL LETTER A WITH BREVE AND ACUTE;Lu;0;L;0102 0301;;;;N;;;;1EAF;
+1EAF;LATIN SMALL LETTER A WITH BREVE AND ACUTE;Ll;0;L;0103 0301;;;;N;;;1EAE;;1EAE
+1EB0;LATIN CAPITAL LETTER A WITH BREVE AND GRAVE;Lu;0;L;0102 0300;;;;N;;;;1EB1;
+1EB1;LATIN SMALL LETTER A WITH BREVE AND GRAVE;Ll;0;L;0103 0300;;;;N;;;1EB0;;1EB0
+1EB2;LATIN CAPITAL LETTER A WITH BREVE AND HOOK ABOVE;Lu;0;L;0102 0309;;;;N;;;;1EB3;
+1EB3;LATIN SMALL LETTER A WITH BREVE AND HOOK ABOVE;Ll;0;L;0103 0309;;;;N;;;1EB2;;1EB2
+1EB4;LATIN CAPITAL LETTER A WITH BREVE AND TILDE;Lu;0;L;0102 0303;;;;N;;;;1EB5;
+1EB5;LATIN SMALL LETTER A WITH BREVE AND TILDE;Ll;0;L;0103 0303;;;;N;;;1EB4;;1EB4
+1EB6;LATIN CAPITAL LETTER A WITH BREVE AND DOT BELOW;Lu;0;L;1EA0 0306;;;;N;;;;1EB7;
+1EB7;LATIN SMALL LETTER A WITH BREVE AND DOT BELOW;Ll;0;L;1EA1 0306;;;;N;;;1EB6;;1EB6
+1EB8;LATIN CAPITAL LETTER E WITH DOT BELOW;Lu;0;L;0045 0323;;;;N;;;;1EB9;
+1EB9;LATIN SMALL LETTER E WITH DOT BELOW;Ll;0;L;0065 0323;;;;N;;;1EB8;;1EB8
+1EBA;LATIN CAPITAL LETTER E WITH HOOK ABOVE;Lu;0;L;0045 0309;;;;N;;;;1EBB;
+1EBB;LATIN SMALL LETTER E WITH HOOK ABOVE;Ll;0;L;0065 0309;;;;N;;;1EBA;;1EBA
+1EBC;LATIN CAPITAL LETTER E WITH TILDE;Lu;0;L;0045 0303;;;;N;;;;1EBD;
+1EBD;LATIN SMALL LETTER E WITH TILDE;Ll;0;L;0065 0303;;;;N;;;1EBC;;1EBC
+1EBE;LATIN CAPITAL LETTER E WITH CIRCUMFLEX AND ACUTE;Lu;0;L;00CA 0301;;;;N;;;;1EBF;
+1EBF;LATIN SMALL LETTER E WITH CIRCUMFLEX AND ACUTE;Ll;0;L;00EA 0301;;;;N;;;1EBE;;1EBE
+1EC0;LATIN CAPITAL LETTER E WITH CIRCUMFLEX AND GRAVE;Lu;0;L;00CA 0300;;;;N;;;;1EC1;
+1EC1;LATIN SMALL LETTER E WITH CIRCUMFLEX AND GRAVE;Ll;0;L;00EA 0300;;;;N;;;1EC0;;1EC0
+1EC2;LATIN CAPITAL LETTER E WITH CIRCUMFLEX AND HOOK ABOVE;Lu;0;L;00CA 0309;;;;N;;;;1EC3;
+1EC3;LATIN SMALL LETTER E WITH CIRCUMFLEX AND HOOK ABOVE;Ll;0;L;00EA 0309;;;;N;;;1EC2;;1EC2
+1EC4;LATIN CAPITAL LETTER E WITH CIRCUMFLEX AND TILDE;Lu;0;L;00CA 0303;;;;N;;;;1EC5;
+1EC5;LATIN SMALL LETTER E WITH CIRCUMFLEX AND TILDE;Ll;0;L;00EA 0303;;;;N;;;1EC4;;1EC4
+1EC6;LATIN CAPITAL LETTER E WITH CIRCUMFLEX AND DOT BELOW;Lu;0;L;1EB8 0302;;;;N;;;;1EC7;
+1EC7;LATIN SMALL LETTER E WITH CIRCUMFLEX AND DOT BELOW;Ll;0;L;1EB9 0302;;;;N;;;1EC6;;1EC6
+1EC8;LATIN CAPITAL LETTER I WITH HOOK ABOVE;Lu;0;L;0049 0309;;;;N;;;;1EC9;
+1EC9;LATIN SMALL LETTER I WITH HOOK ABOVE;Ll;0;L;0069 0309;;;;N;;;1EC8;;1EC8
+1ECA;LATIN CAPITAL LETTER I WITH DOT BELOW;Lu;0;L;0049 0323;;;;N;;;;1ECB;
+1ECB;LATIN SMALL LETTER I WITH DOT BELOW;Ll;0;L;0069 0323;;;;N;;;1ECA;;1ECA
+1ECC;LATIN CAPITAL LETTER O WITH DOT BELOW;Lu;0;L;004F 0323;;;;N;;;;1ECD;
+1ECD;LATIN SMALL LETTER O WITH DOT BELOW;Ll;0;L;006F 0323;;;;N;;;1ECC;;1ECC
+1ECE;LATIN CAPITAL LETTER O WITH HOOK ABOVE;Lu;0;L;004F 0309;;;;N;;;;1ECF;
+1ECF;LATIN SMALL LETTER O WITH HOOK ABOVE;Ll;0;L;006F 0309;;;;N;;;1ECE;;1ECE
+1ED0;LATIN CAPITAL LETTER O WITH CIRCUMFLEX AND ACUTE;Lu;0;L;00D4 0301;;;;N;;;;1ED1;
+1ED1;LATIN SMALL LETTER O WITH CIRCUMFLEX AND ACUTE;Ll;0;L;00F4 0301;;;;N;;;1ED0;;1ED0
+1ED2;LATIN CAPITAL LETTER O WITH CIRCUMFLEX AND GRAVE;Lu;0;L;00D4 0300;;;;N;;;;1ED3;
+1ED3;LATIN SMALL LETTER O WITH CIRCUMFLEX AND GRAVE;Ll;0;L;00F4 0300;;;;N;;;1ED2;;1ED2
+1ED4;LATIN CAPITAL LETTER O WITH CIRCUMFLEX AND HOOK ABOVE;Lu;0;L;00D4 0309;;;;N;;;;1ED5;
+1ED5;LATIN SMALL LETTER O WITH CIRCUMFLEX AND HOOK ABOVE;Ll;0;L;00F4 0309;;;;N;;;1ED4;;1ED4
+1ED6;LATIN CAPITAL LETTER O WITH CIRCUMFLEX AND TILDE;Lu;0;L;00D4 0303;;;;N;;;;1ED7;
+1ED7;LATIN SMALL LETTER O WITH CIRCUMFLEX AND TILDE;Ll;0;L;00F4 0303;;;;N;;;1ED6;;1ED6
+1ED8;LATIN CAPITAL LETTER O WITH CIRCUMFLEX AND DOT BELOW;Lu;0;L;1ECC 0302;;;;N;;;;1ED9;
+1ED9;LATIN SMALL LETTER O WITH CIRCUMFLEX AND DOT BELOW;Ll;0;L;1ECD 0302;;;;N;;;1ED8;;1ED8
+1EDA;LATIN CAPITAL LETTER O WITH HORN AND ACUTE;Lu;0;L;01A0 0301;;;;N;;;;1EDB;
+1EDB;LATIN SMALL LETTER O WITH HORN AND ACUTE;Ll;0;L;01A1 0301;;;;N;;;1EDA;;1EDA
+1EDC;LATIN CAPITAL LETTER O WITH HORN AND GRAVE;Lu;0;L;01A0 0300;;;;N;;;;1EDD;
+1EDD;LATIN SMALL LETTER O WITH HORN AND GRAVE;Ll;0;L;01A1 0300;;;;N;;;1EDC;;1EDC
+1EDE;LATIN CAPITAL LETTER O WITH HORN AND HOOK ABOVE;Lu;0;L;01A0 0309;;;;N;;;;1EDF;
+1EDF;LATIN SMALL LETTER O WITH HORN AND HOOK ABOVE;Ll;0;L;01A1 0309;;;;N;;;1EDE;;1EDE
+1EE0;LATIN CAPITAL LETTER O WITH HORN AND TILDE;Lu;0;L;01A0 0303;;;;N;;;;1EE1;
+1EE1;LATIN SMALL LETTER O WITH HORN AND TILDE;Ll;0;L;01A1 0303;;;;N;;;1EE0;;1EE0
+1EE2;LATIN CAPITAL LETTER O WITH HORN AND DOT BELOW;Lu;0;L;01A0 0323;;;;N;;;;1EE3;
+1EE3;LATIN SMALL LETTER O WITH HORN AND DOT BELOW;Ll;0;L;01A1 0323;;;;N;;;1EE2;;1EE2
+1EE4;LATIN CAPITAL LETTER U WITH DOT BELOW;Lu;0;L;0055 0323;;;;N;;;;1EE5;
+1EE5;LATIN SMALL LETTER U WITH DOT BELOW;Ll;0;L;0075 0323;;;;N;;;1EE4;;1EE4
+1EE6;LATIN CAPITAL LETTER U WITH HOOK ABOVE;Lu;0;L;0055 0309;;;;N;;;;1EE7;
+1EE7;LATIN SMALL LETTER U WITH HOOK ABOVE;Ll;0;L;0075 0309;;;;N;;;1EE6;;1EE6
+1EE8;LATIN CAPITAL LETTER U WITH HORN AND ACUTE;Lu;0;L;01AF 0301;;;;N;;;;1EE9;
+1EE9;LATIN SMALL LETTER U WITH HORN AND ACUTE;Ll;0;L;01B0 0301;;;;N;;;1EE8;;1EE8
+1EEA;LATIN CAPITAL LETTER U WITH HORN AND GRAVE;Lu;0;L;01AF 0300;;;;N;;;;1EEB;
+1EEB;LATIN SMALL LETTER U WITH HORN AND GRAVE;Ll;0;L;01B0 0300;;;;N;;;1EEA;;1EEA
+1EEC;LATIN CAPITAL LETTER U WITH HORN AND HOOK ABOVE;Lu;0;L;01AF 0309;;;;N;;;;1EED;
+1EED;LATIN SMALL LETTER U WITH HORN AND HOOK ABOVE;Ll;0;L;01B0 0309;;;;N;;;1EEC;;1EEC
+1EEE;LATIN CAPITAL LETTER U WITH HORN AND TILDE;Lu;0;L;01AF 0303;;;;N;;;;1EEF;
+1EEF;LATIN SMALL LETTER U WITH HORN AND TILDE;Ll;0;L;01B0 0303;;;;N;;;1EEE;;1EEE
+1EF0;LATIN CAPITAL LETTER U WITH HORN AND DOT BELOW;Lu;0;L;01AF 0323;;;;N;;;;1EF1;
+1EF1;LATIN SMALL LETTER U WITH HORN AND DOT BELOW;Ll;0;L;01B0 0323;;;;N;;;1EF0;;1EF0
+1EF2;LATIN CAPITAL LETTER Y WITH GRAVE;Lu;0;L;0059 0300;;;;N;;;;1EF3;
+1EF3;LATIN SMALL LETTER Y WITH GRAVE;Ll;0;L;0079 0300;;;;N;;;1EF2;;1EF2
+1EF4;LATIN CAPITAL LETTER Y WITH DOT BELOW;Lu;0;L;0059 0323;;;;N;;;;1EF5;
+1EF5;LATIN SMALL LETTER Y WITH DOT BELOW;Ll;0;L;0079 0323;;;;N;;;1EF4;;1EF4
+1EF6;LATIN CAPITAL LETTER Y WITH HOOK ABOVE;Lu;0;L;0059 0309;;;;N;;;;1EF7;
+1EF7;LATIN SMALL LETTER Y WITH HOOK ABOVE;Ll;0;L;0079 0309;;;;N;;;1EF6;;1EF6
+1EF8;LATIN CAPITAL LETTER Y WITH TILDE;Lu;0;L;0059 0303;;;;N;;;;1EF9;
+1EF9;LATIN SMALL LETTER Y WITH TILDE;Ll;0;L;0079 0303;;;;N;;;1EF8;;1EF8
+1F00;GREEK SMALL LETTER ALPHA WITH PSILI;Ll;0;L;03B1 0313;;;;N;;;1F08;;1F08
+1F01;GREEK SMALL LETTER ALPHA WITH DASIA;Ll;0;L;03B1 0314;;;;N;;;1F09;;1F09
+1F02;GREEK SMALL LETTER ALPHA WITH PSILI AND VARIA;Ll;0;L;1F00 0300;;;;N;;;1F0A;;1F0A
+1F03;GREEK SMALL LETTER ALPHA WITH DASIA AND VARIA;Ll;0;L;1F01 0300;;;;N;;;1F0B;;1F0B
+1F04;GREEK SMALL LETTER ALPHA WITH PSILI AND OXIA;Ll;0;L;1F00 0301;;;;N;;;1F0C;;1F0C
+1F05;GREEK SMALL LETTER ALPHA WITH DASIA AND OXIA;Ll;0;L;1F01 0301;;;;N;;;1F0D;;1F0D
+1F06;GREEK SMALL LETTER ALPHA WITH PSILI AND PERISPOMENI;Ll;0;L;1F00 0342;;;;N;;;1F0E;;1F0E
+1F07;GREEK SMALL LETTER ALPHA WITH DASIA AND PERISPOMENI;Ll;0;L;1F01 0342;;;;N;;;1F0F;;1F0F
+1F08;GREEK CAPITAL LETTER ALPHA WITH PSILI;Lu;0;L;0391 0313;;;;N;;;;1F00;
+1F09;GREEK CAPITAL LETTER ALPHA WITH DASIA;Lu;0;L;0391 0314;;;;N;;;;1F01;
+1F0A;GREEK CAPITAL LETTER ALPHA WITH PSILI AND VARIA;Lu;0;L;1F08 0300;;;;N;;;;1F02;
+1F0B;GREEK CAPITAL LETTER ALPHA WITH DASIA AND VARIA;Lu;0;L;1F09 0300;;;;N;;;;1F03;
+1F0C;GREEK CAPITAL LETTER ALPHA WITH PSILI AND OXIA;Lu;0;L;1F08 0301;;;;N;;;;1F04;
+1F0D;GREEK CAPITAL LETTER ALPHA WITH DASIA AND OXIA;Lu;0;L;1F09 0301;;;;N;;;;1F05;
+1F0E;GREEK CAPITAL LETTER ALPHA WITH PSILI AND PERISPOMENI;Lu;0;L;1F08 0342;;;;N;;;;1F06;
+1F0F;GREEK CAPITAL LETTER ALPHA WITH DASIA AND PERISPOMENI;Lu;0;L;1F09 0342;;;;N;;;;1F07;
+1F10;GREEK SMALL LETTER EPSILON WITH PSILI;Ll;0;L;03B5 0313;;;;N;;;1F18;;1F18
+1F11;GREEK SMALL LETTER EPSILON WITH DASIA;Ll;0;L;03B5 0314;;;;N;;;1F19;;1F19
+1F12;GREEK SMALL LETTER EPSILON WITH PSILI AND VARIA;Ll;0;L;1F10 0300;;;;N;;;1F1A;;1F1A
+1F13;GREEK SMALL LETTER EPSILON WITH DASIA AND VARIA;Ll;0;L;1F11 0300;;;;N;;;1F1B;;1F1B
+1F14;GREEK SMALL LETTER EPSILON WITH PSILI AND OXIA;Ll;0;L;1F10 0301;;;;N;;;1F1C;;1F1C
+1F15;GREEK SMALL LETTER EPSILON WITH DASIA AND OXIA;Ll;0;L;1F11 0301;;;;N;;;1F1D;;1F1D
+1F18;GREEK CAPITAL LETTER EPSILON WITH PSILI;Lu;0;L;0395 0313;;;;N;;;;1F10;
+1F19;GREEK CAPITAL LETTER EPSILON WITH DASIA;Lu;0;L;0395 0314;;;;N;;;;1F11;
+1F1A;GREEK CAPITAL LETTER EPSILON WITH PSILI AND VARIA;Lu;0;L;1F18 0300;;;;N;;;;1F12;
+1F1B;GREEK CAPITAL LETTER EPSILON WITH DASIA AND VARIA;Lu;0;L;1F19 0300;;;;N;;;;1F13;
+1F1C;GREEK CAPITAL LETTER EPSILON WITH PSILI AND OXIA;Lu;0;L;1F18 0301;;;;N;;;;1F14;
+1F1D;GREEK CAPITAL LETTER EPSILON WITH DASIA AND OXIA;Lu;0;L;1F19 0301;;;;N;;;;1F15;
+1F20;GREEK SMALL LETTER ETA WITH PSILI;Ll;0;L;03B7 0313;;;;N;;;1F28;;1F28
+1F21;GREEK SMALL LETTER ETA WITH DASIA;Ll;0;L;03B7 0314;;;;N;;;1F29;;1F29
+1F22;GREEK SMALL LETTER ETA WITH PSILI AND VARIA;Ll;0;L;1F20 0300;;;;N;;;1F2A;;1F2A
+1F23;GREEK SMALL LETTER ETA WITH DASIA AND VARIA;Ll;0;L;1F21 0300;;;;N;;;1F2B;;1F2B
+1F24;GREEK SMALL LETTER ETA WITH PSILI AND OXIA;Ll;0;L;1F20 0301;;;;N;;;1F2C;;1F2C
+1F25;GREEK SMALL LETTER ETA WITH DASIA AND OXIA;Ll;0;L;1F21 0301;;;;N;;;1F2D;;1F2D
+1F26;GREEK SMALL LETTER ETA WITH PSILI AND PERISPOMENI;Ll;0;L;1F20 0342;;;;N;;;1F2E;;1F2E
+1F27;GREEK SMALL LETTER ETA WITH DASIA AND PERISPOMENI;Ll;0;L;1F21 0342;;;;N;;;1F2F;;1F2F
+1F28;GREEK CAPITAL LETTER ETA WITH PSILI;Lu;0;L;0397 0313;;;;N;;;;1F20;
+1F29;GREEK CAPITAL LETTER ETA WITH DASIA;Lu;0;L;0397 0314;;;;N;;;;1F21;
+1F2A;GREEK CAPITAL LETTER ETA WITH PSILI AND VARIA;Lu;0;L;1F28 0300;;;;N;;;;1F22;
+1F2B;GREEK CAPITAL LETTER ETA WITH DASIA AND VARIA;Lu;0;L;1F29 0300;;;;N;;;;1F23;
+1F2C;GREEK CAPITAL LETTER ETA WITH PSILI AND OXIA;Lu;0;L;1F28 0301;;;;N;;;;1F24;
+1F2D;GREEK CAPITAL LETTER ETA WITH DASIA AND OXIA;Lu;0;L;1F29 0301;;;;N;;;;1F25;
+1F2E;GREEK CAPITAL LETTER ETA WITH PSILI AND PERISPOMENI;Lu;0;L;1F28 0342;;;;N;;;;1F26;
+1F2F;GREEK CAPITAL LETTER ETA WITH DASIA AND PERISPOMENI;Lu;0;L;1F29 0342;;;;N;;;;1F27;
+1F30;GREEK SMALL LETTER IOTA WITH PSILI;Ll;0;L;03B9 0313;;;;N;;;1F38;;1F38
+1F31;GREEK SMALL LETTER IOTA WITH DASIA;Ll;0;L;03B9 0314;;;;N;;;1F39;;1F39
+1F32;GREEK SMALL LETTER IOTA WITH PSILI AND VARIA;Ll;0;L;1F30 0300;;;;N;;;1F3A;;1F3A
+1F33;GREEK SMALL LETTER IOTA WITH DASIA AND VARIA;Ll;0;L;1F31 0300;;;;N;;;1F3B;;1F3B
+1F34;GREEK SMALL LETTER IOTA WITH PSILI AND OXIA;Ll;0;L;1F30 0301;;;;N;;;1F3C;;1F3C
+1F35;GREEK SMALL LETTER IOTA WITH DASIA AND OXIA;Ll;0;L;1F31 0301;;;;N;;;1F3D;;1F3D
+1F36;GREEK SMALL LETTER IOTA WITH PSILI AND PERISPOMENI;Ll;0;L;1F30 0342;;;;N;;;1F3E;;1F3E
+1F37;GREEK SMALL LETTER IOTA WITH DASIA AND PERISPOMENI;Ll;0;L;1F31 0342;;;;N;;;1F3F;;1F3F
+1F38;GREEK CAPITAL LETTER IOTA WITH PSILI;Lu;0;L;0399 0313;;;;N;;;;1F30;
+1F39;GREEK CAPITAL LETTER IOTA WITH DASIA;Lu;0;L;0399 0314;;;;N;;;;1F31;
+1F3A;GREEK CAPITAL LETTER IOTA WITH PSILI AND VARIA;Lu;0;L;1F38 0300;;;;N;;;;1F32;
+1F3B;GREEK CAPITAL LETTER IOTA WITH DASIA AND VARIA;Lu;0;L;1F39 0300;;;;N;;;;1F33;
+1F3C;GREEK CAPITAL LETTER IOTA WITH PSILI AND OXIA;Lu;0;L;1F38 0301;;;;N;;;;1F34;
+1F3D;GREEK CAPITAL LETTER IOTA WITH DASIA AND OXIA;Lu;0;L;1F39 0301;;;;N;;;;1F35;
+1F3E;GREEK CAPITAL LETTER IOTA WITH PSILI AND PERISPOMENI;Lu;0;L;1F38 0342;;;;N;;;;1F36;
+1F3F;GREEK CAPITAL LETTER IOTA WITH DASIA AND PERISPOMENI;Lu;0;L;1F39 0342;;;;N;;;;1F37;
+1F40;GREEK SMALL LETTER OMICRON WITH PSILI;Ll;0;L;03BF 0313;;;;N;;;1F48;;1F48
+1F41;GREEK SMALL LETTER OMICRON WITH DASIA;Ll;0;L;03BF 0314;;;;N;;;1F49;;1F49
+1F42;GREEK SMALL LETTER OMICRON WITH PSILI AND VARIA;Ll;0;L;1F40 0300;;;;N;;;1F4A;;1F4A
+1F43;GREEK SMALL LETTER OMICRON WITH DASIA AND VARIA;Ll;0;L;1F41 0300;;;;N;;;1F4B;;1F4B
+1F44;GREEK SMALL LETTER OMICRON WITH PSILI AND OXIA;Ll;0;L;1F40 0301;;;;N;;;1F4C;;1F4C
+1F45;GREEK SMALL LETTER OMICRON WITH DASIA AND OXIA;Ll;0;L;1F41 0301;;;;N;;;1F4D;;1F4D
+1F48;GREEK CAPITAL LETTER OMICRON WITH PSILI;Lu;0;L;039F 0313;;;;N;;;;1F40;
+1F49;GREEK CAPITAL LETTER OMICRON WITH DASIA;Lu;0;L;039F 0314;;;;N;;;;1F41;
+1F4A;GREEK CAPITAL LETTER OMICRON WITH PSILI AND VARIA;Lu;0;L;1F48 0300;;;;N;;;;1F42;
+1F4B;GREEK CAPITAL LETTER OMICRON WITH DASIA AND VARIA;Lu;0;L;1F49 0300;;;;N;;;;1F43;
+1F4C;GREEK CAPITAL LETTER OMICRON WITH PSILI AND OXIA;Lu;0;L;1F48 0301;;;;N;;;;1F44;
+1F4D;GREEK CAPITAL LETTER OMICRON WITH DASIA AND OXIA;Lu;0;L;1F49 0301;;;;N;;;;1F45;
+1F50;GREEK SMALL LETTER UPSILON WITH PSILI;Ll;0;L;03C5 0313;;;;N;;;;;
+1F51;GREEK SMALL LETTER UPSILON WITH DASIA;Ll;0;L;03C5 0314;;;;N;;;1F59;;1F59
+1F52;GREEK SMALL LETTER UPSILON WITH PSILI AND VARIA;Ll;0;L;1F50 0300;;;;N;;;;;
+1F53;GREEK SMALL LETTER UPSILON WITH DASIA AND VARIA;Ll;0;L;1F51 0300;;;;N;;;1F5B;;1F5B
+1F54;GREEK SMALL LETTER UPSILON WITH PSILI AND OXIA;Ll;0;L;1F50 0301;;;;N;;;;;
+1F55;GREEK SMALL LETTER UPSILON WITH DASIA AND OXIA;Ll;0;L;1F51 0301;;;;N;;;1F5D;;1F5D
+1F56;GREEK SMALL LETTER UPSILON WITH PSILI AND PERISPOMENI;Ll;0;L;1F50 0342;;;;N;;;;;
+1F57;GREEK SMALL LETTER UPSILON WITH DASIA AND PERISPOMENI;Ll;0;L;1F51 0342;;;;N;;;1F5F;;1F5F
+1F59;GREEK CAPITAL LETTER UPSILON WITH DASIA;Lu;0;L;03A5 0314;;;;N;;;;1F51;
+1F5B;GREEK CAPITAL LETTER UPSILON WITH DASIA AND VARIA;Lu;0;L;1F59 0300;;;;N;;;;1F53;
+1F5D;GREEK CAPITAL LETTER UPSILON WITH DASIA AND OXIA;Lu;0;L;1F59 0301;;;;N;;;;1F55;
+1F5F;GREEK CAPITAL LETTER UPSILON WITH DASIA AND PERISPOMENI;Lu;0;L;1F59 0342;;;;N;;;;1F57;
+1F60;GREEK SMALL LETTER OMEGA WITH PSILI;Ll;0;L;03C9 0313;;;;N;;;1F68;;1F68
+1F61;GREEK SMALL LETTER OMEGA WITH DASIA;Ll;0;L;03C9 0314;;;;N;;;1F69;;1F69
+1F62;GREEK SMALL LETTER OMEGA WITH PSILI AND VARIA;Ll;0;L;1F60 0300;;;;N;;;1F6A;;1F6A
+1F63;GREEK SMALL LETTER OMEGA WITH DASIA AND VARIA;Ll;0;L;1F61 0300;;;;N;;;1F6B;;1F6B
+1F64;GREEK SMALL LETTER OMEGA WITH PSILI AND OXIA;Ll;0;L;1F60 0301;;;;N;;;1F6C;;1F6C
+1F65;GREEK SMALL LETTER OMEGA WITH DASIA AND OXIA;Ll;0;L;1F61 0301;;;;N;;;1F6D;;1F6D
+1F66;GREEK SMALL LETTER OMEGA WITH PSILI AND PERISPOMENI;Ll;0;L;1F60 0342;;;;N;;;1F6E;;1F6E
+1F67;GREEK SMALL LETTER OMEGA WITH DASIA AND PERISPOMENI;Ll;0;L;1F61 0342;;;;N;;;1F6F;;1F6F
+1F68;GREEK CAPITAL LETTER OMEGA WITH PSILI;Lu;0;L;03A9 0313;;;;N;;;;1F60;
+1F69;GREEK CAPITAL LETTER OMEGA WITH DASIA;Lu;0;L;03A9 0314;;;;N;;;;1F61;
+1F6A;GREEK CAPITAL LETTER OMEGA WITH PSILI AND VARIA;Lu;0;L;1F68 0300;;;;N;;;;1F62;
+1F6B;GREEK CAPITAL LETTER OMEGA WITH DASIA AND VARIA;Lu;0;L;1F69 0300;;;;N;;;;1F63;
+1F6C;GREEK CAPITAL LETTER OMEGA WITH PSILI AND OXIA;Lu;0;L;1F68 0301;;;;N;;;;1F64;
+1F6D;GREEK CAPITAL LETTER OMEGA WITH DASIA AND OXIA;Lu;0;L;1F69 0301;;;;N;;;;1F65;
+1F6E;GREEK CAPITAL LETTER OMEGA WITH PSILI AND PERISPOMENI;Lu;0;L;1F68 0342;;;;N;;;;1F66;
+1F6F;GREEK CAPITAL LETTER OMEGA WITH DASIA AND PERISPOMENI;Lu;0;L;1F69 0342;;;;N;;;;1F67;
+1F70;GREEK SMALL LETTER ALPHA WITH VARIA;Ll;0;L;03B1 0300;;;;N;;;1FBA;;1FBA
+1F71;GREEK SMALL LETTER ALPHA WITH OXIA;Ll;0;L;03AC;;;;N;;;1FBB;;1FBB
+1F72;GREEK SMALL LETTER EPSILON WITH VARIA;Ll;0;L;03B5 0300;;;;N;;;1FC8;;1FC8
+1F73;GREEK SMALL LETTER EPSILON WITH OXIA;Ll;0;L;03AD;;;;N;;;1FC9;;1FC9
+1F74;GREEK SMALL LETTER ETA WITH VARIA;Ll;0;L;03B7 0300;;;;N;;;1FCA;;1FCA
+1F75;GREEK SMALL LETTER ETA WITH OXIA;Ll;0;L;03AE;;;;N;;;1FCB;;1FCB
+1F76;GREEK SMALL LETTER IOTA WITH VARIA;Ll;0;L;03B9 0300;;;;N;;;1FDA;;1FDA
+1F77;GREEK SMALL LETTER IOTA WITH OXIA;Ll;0;L;03AF;;;;N;;;1FDB;;1FDB
+1F78;GREEK SMALL LETTER OMICRON WITH VARIA;Ll;0;L;03BF 0300;;;;N;;;1FF8;;1FF8
+1F79;GREEK SMALL LETTER OMICRON WITH OXIA;Ll;0;L;03CC;;;;N;;;1FF9;;1FF9
+1F7A;GREEK SMALL LETTER UPSILON WITH VARIA;Ll;0;L;03C5 0300;;;;N;;;1FEA;;1FEA
+1F7B;GREEK SMALL LETTER UPSILON WITH OXIA;Ll;0;L;03CD;;;;N;;;1FEB;;1FEB
+1F7C;GREEK SMALL LETTER OMEGA WITH VARIA;Ll;0;L;03C9 0300;;;;N;;;1FFA;;1FFA
+1F7D;GREEK SMALL LETTER OMEGA WITH OXIA;Ll;0;L;03CE;;;;N;;;1FFB;;1FFB
+1F80;GREEK SMALL LETTER ALPHA WITH PSILI AND YPOGEGRAMMENI;Ll;0;L;1F00 0345;;;;N;;;1F88;;1F88
+1F81;GREEK SMALL LETTER ALPHA WITH DASIA AND YPOGEGRAMMENI;Ll;0;L;1F01 0345;;;;N;;;1F89;;1F89
+1F82;GREEK SMALL LETTER ALPHA WITH PSILI AND VARIA AND YPOGEGRAMMENI;Ll;0;L;1F02 0345;;;;N;;;1F8A;;1F8A
+1F83;GREEK SMALL LETTER ALPHA WITH DASIA AND VARIA AND YPOGEGRAMMENI;Ll;0;L;1F03 0345;;;;N;;;1F8B;;1F8B
+1F84;GREEK SMALL LETTER ALPHA WITH PSILI AND OXIA AND YPOGEGRAMMENI;Ll;0;L;1F04 0345;;;;N;;;1F8C;;1F8C
+1F85;GREEK SMALL LETTER ALPHA WITH DASIA AND OXIA AND YPOGEGRAMMENI;Ll;0;L;1F05 0345;;;;N;;;1F8D;;1F8D
+1F86;GREEK SMALL LETTER ALPHA WITH PSILI AND PERISPOMENI AND YPOGEGRAMMENI;Ll;0;L;1F06 0345;;;;N;;;1F8E;;1F8E
+1F87;GREEK SMALL LETTER ALPHA WITH DASIA AND PERISPOMENI AND YPOGEGRAMMENI;Ll;0;L;1F07 0345;;;;N;;;1F8F;;1F8F
+1F88;GREEK CAPITAL LETTER ALPHA WITH PSILI AND PROSGEGRAMMENI;Lt;0;L;1F08 0345;;;;N;;;;1F80;
+1F89;GREEK CAPITAL LETTER ALPHA WITH DASIA AND PROSGEGRAMMENI;Lt;0;L;1F09 0345;;;;N;;;;1F81;
+1F8A;GREEK CAPITAL LETTER ALPHA WITH PSILI AND VARIA AND PROSGEGRAMMENI;Lt;0;L;1F0A 0345;;;;N;;;;1F82;
+1F8B;GREEK CAPITAL LETTER ALPHA WITH DASIA AND VARIA AND PROSGEGRAMMENI;Lt;0;L;1F0B 0345;;;;N;;;;1F83;
+1F8C;GREEK CAPITAL LETTER ALPHA WITH PSILI AND OXIA AND PROSGEGRAMMENI;Lt;0;L;1F0C 0345;;;;N;;;;1F84;
+1F8D;GREEK CAPITAL LETTER ALPHA WITH DASIA AND OXIA AND PROSGEGRAMMENI;Lt;0;L;1F0D 0345;;;;N;;;;1F85;
+1F8E;GREEK CAPITAL LETTER ALPHA WITH PSILI AND PERISPOMENI AND PROSGEGRAMMENI;Lt;0;L;1F0E 0345;;;;N;;;;1F86;
+1F8F;GREEK CAPITAL LETTER ALPHA WITH DASIA AND PERISPOMENI AND PROSGEGRAMMENI;Lt;0;L;1F0F 0345;;;;N;;;;1F87;
+1F90;GREEK SMALL LETTER ETA WITH PSILI AND YPOGEGRAMMENI;Ll;0;L;1F20 0345;;;;N;;;1F98;;1F98
+1F91;GREEK SMALL LETTER ETA WITH DASIA AND YPOGEGRAMMENI;Ll;0;L;1F21 0345;;;;N;;;1F99;;1F99
+1F92;GREEK SMALL LETTER ETA WITH PSILI AND VARIA AND YPOGEGRAMMENI;Ll;0;L;1F22 0345;;;;N;;;1F9A;;1F9A
+1F93;GREEK SMALL LETTER ETA WITH DASIA AND VARIA AND YPOGEGRAMMENI;Ll;0;L;1F23 0345;;;;N;;;1F9B;;1F9B
+1F94;GREEK SMALL LETTER ETA WITH PSILI AND OXIA AND YPOGEGRAMMENI;Ll;0;L;1F24 0345;;;;N;;;1F9C;;1F9C
+1F95;GREEK SMALL LETTER ETA WITH DASIA AND OXIA AND YPOGEGRAMMENI;Ll;0;L;1F25 0345;;;;N;;;1F9D;;1F9D
+1F96;GREEK SMALL LETTER ETA WITH PSILI AND PERISPOMENI AND YPOGEGRAMMENI;Ll;0;L;1F26 0345;;;;N;;;1F9E;;1F9E
+1F97;GREEK SMALL LETTER ETA WITH DASIA AND PERISPOMENI AND YPOGEGRAMMENI;Ll;0;L;1F27 0345;;;;N;;;1F9F;;1F9F
+1F98;GREEK CAPITAL LETTER ETA WITH PSILI AND PROSGEGRAMMENI;Lt;0;L;1F28 0345;;;;N;;;;1F90;
+1F99;GREEK CAPITAL LETTER ETA WITH DASIA AND PROSGEGRAMMENI;Lt;0;L;1F29 0345;;;;N;;;;1F91;
+1F9A;GREEK CAPITAL LETTER ETA WITH PSILI AND VARIA AND PROSGEGRAMMENI;Lt;0;L;1F2A 0345;;;;N;;;;1F92;
+1F9B;GREEK CAPITAL LETTER ETA WITH DASIA AND VARIA AND PROSGEGRAMMENI;Lt;0;L;1F2B 0345;;;;N;;;;1F93;
+1F9C;GREEK CAPITAL LETTER ETA WITH PSILI AND OXIA AND PROSGEGRAMMENI;Lt;0;L;1F2C 0345;;;;N;;;;1F94;
+1F9D;GREEK CAPITAL LETTER ETA WITH DASIA AND OXIA AND PROSGEGRAMMENI;Lt;0;L;1F2D 0345;;;;N;;;;1F95;
+1F9E;GREEK CAPITAL LETTER ETA WITH PSILI AND PERISPOMENI AND PROSGEGRAMMENI;Lt;0;L;1F2E 0345;;;;N;;;;1F96;
+1F9F;GREEK CAPITAL LETTER ETA WITH DASIA AND PERISPOMENI AND PROSGEGRAMMENI;Lt;0;L;1F2F 0345;;;;N;;;;1F97;
+1FA0;GREEK SMALL LETTER OMEGA WITH PSILI AND YPOGEGRAMMENI;Ll;0;L;1F60 0345;;;;N;;;1FA8;;1FA8
+1FA1;GREEK SMALL LETTER OMEGA WITH DASIA AND YPOGEGRAMMENI;Ll;0;L;1F61 0345;;;;N;;;1FA9;;1FA9
+1FA2;GREEK SMALL LETTER OMEGA WITH PSILI AND VARIA AND YPOGEGRAMMENI;Ll;0;L;1F62 0345;;;;N;;;1FAA;;1FAA
+1FA3;GREEK SMALL LETTER OMEGA WITH DASIA AND VARIA AND YPOGEGRAMMENI;Ll;0;L;1F63 0345;;;;N;;;1FAB;;1FAB
+1FA4;GREEK SMALL LETTER OMEGA WITH PSILI AND OXIA AND YPOGEGRAMMENI;Ll;0;L;1F64 0345;;;;N;;;1FAC;;1FAC
+1FA5;GREEK SMALL LETTER OMEGA WITH DASIA AND OXIA AND YPOGEGRAMMENI;Ll;0;L;1F65 0345;;;;N;;;1FAD;;1FAD
+1FA6;GREEK SMALL LETTER OMEGA WITH PSILI AND PERISPOMENI AND YPOGEGRAMMENI;Ll;0;L;1F66 0345;;;;N;;;1FAE;;1FAE
+1FA7;GREEK SMALL LETTER OMEGA WITH DASIA AND PERISPOMENI AND YPOGEGRAMMENI;Ll;0;L;1F67 0345;;;;N;;;1FAF;;1FAF
+1FA8;GREEK CAPITAL LETTER OMEGA WITH PSILI AND PROSGEGRAMMENI;Lt;0;L;1F68 0345;;;;N;;;;1FA0;
+1FA9;GREEK CAPITAL LETTER OMEGA WITH DASIA AND PROSGEGRAMMENI;Lt;0;L;1F69 0345;;;;N;;;;1FA1;
+1FAA;GREEK CAPITAL LETTER OMEGA WITH PSILI AND VARIA AND PROSGEGRAMMENI;Lt;0;L;1F6A 0345;;;;N;;;;1FA2;
+1FAB;GREEK CAPITAL LETTER OMEGA WITH DASIA AND VARIA AND PROSGEGRAMMENI;Lt;0;L;1F6B 0345;;;;N;;;;1FA3;
+1FAC;GREEK CAPITAL LETTER OMEGA WITH PSILI AND OXIA AND PROSGEGRAMMENI;Lt;0;L;1F6C 0345;;;;N;;;;1FA4;
+1FAD;GREEK CAPITAL LETTER OMEGA WITH DASIA AND OXIA AND PROSGEGRAMMENI;Lt;0;L;1F6D 0345;;;;N;;;;1FA5;
+1FAE;GREEK CAPITAL LETTER OMEGA WITH PSILI AND PERISPOMENI AND PROSGEGRAMMENI;Lt;0;L;1F6E 0345;;;;N;;;;1FA6;
+1FAF;GREEK CAPITAL LETTER OMEGA WITH DASIA AND PERISPOMENI AND PROSGEGRAMMENI;Lt;0;L;1F6F 0345;;;;N;;;;1FA7;
+1FB0;GREEK SMALL LETTER ALPHA WITH VRACHY;Ll;0;L;03B1 0306;;;;N;;;1FB8;;1FB8
+1FB1;GREEK SMALL LETTER ALPHA WITH MACRON;Ll;0;L;03B1 0304;;;;N;;;1FB9;;1FB9
+1FB2;GREEK SMALL LETTER ALPHA WITH VARIA AND YPOGEGRAMMENI;Ll;0;L;1F70 0345;;;;N;;;;;
+1FB3;GREEK SMALL LETTER ALPHA WITH YPOGEGRAMMENI;Ll;0;L;03B1 0345;;;;N;;;1FBC;;1FBC
+1FB4;GREEK SMALL LETTER ALPHA WITH OXIA AND YPOGEGRAMMENI;Ll;0;L;03AC 0345;;;;N;;;;;
+1FB6;GREEK SMALL LETTER ALPHA WITH PERISPOMENI;Ll;0;L;03B1 0342;;;;N;;;;;
+1FB7;GREEK SMALL LETTER ALPHA WITH PERISPOMENI AND YPOGEGRAMMENI;Ll;0;L;1FB6 0345;;;;N;;;;;
+1FB8;GREEK CAPITAL LETTER ALPHA WITH VRACHY;Lu;0;L;0391 0306;;;;N;;;;1FB0;
+1FB9;GREEK CAPITAL LETTER ALPHA WITH MACRON;Lu;0;L;0391 0304;;;;N;;;;1FB1;
+1FBA;GREEK CAPITAL LETTER ALPHA WITH VARIA;Lu;0;L;0391 0300;;;;N;;;;1F70;
+1FBB;GREEK CAPITAL LETTER ALPHA WITH OXIA;Lu;0;L;0386;;;;N;;;;1F71;
+1FBC;GREEK CAPITAL LETTER ALPHA WITH PROSGEGRAMMENI;Lt;0;L;0391 0345;;;;N;;;;1FB3;
+1FBD;GREEK KORONIS;Sk;0;ON;<compat> 0020 0313;;;;N;;;;;
+1FBE;GREEK PROSGEGRAMMENI;Ll;0;L;03B9;;;;N;;;0399;;0399
+1FBF;GREEK PSILI;Sk;0;ON;<compat> 0020 0313;;;;N;;;;;
+1FC0;GREEK PERISPOMENI;Sk;0;ON;<compat> 0020 0342;;;;N;;;;;
+1FC1;GREEK DIALYTIKA AND PERISPOMENI;Sk;0;ON;00A8 0342;;;;N;;;;;
+1FC2;GREEK SMALL LETTER ETA WITH VARIA AND YPOGEGRAMMENI;Ll;0;L;1F74 0345;;;;N;;;;;
+1FC3;GREEK SMALL LETTER ETA WITH YPOGEGRAMMENI;Ll;0;L;03B7 0345;;;;N;;;1FCC;;1FCC
+1FC4;GREEK SMALL LETTER ETA WITH OXIA AND YPOGEGRAMMENI;Ll;0;L;03AE 0345;;;;N;;;;;
+1FC6;GREEK SMALL LETTER ETA WITH PERISPOMENI;Ll;0;L;03B7 0342;;;;N;;;;;
+1FC7;GREEK SMALL LETTER ETA WITH PERISPOMENI AND YPOGEGRAMMENI;Ll;0;L;1FC6 0345;;;;N;;;;;
+1FC8;GREEK CAPITAL LETTER EPSILON WITH VARIA;Lu;0;L;0395 0300;;;;N;;;;1F72;
+1FC9;GREEK CAPITAL LETTER EPSILON WITH OXIA;Lu;0;L;0388;;;;N;;;;1F73;
+1FCA;GREEK CAPITAL LETTER ETA WITH VARIA;Lu;0;L;0397 0300;;;;N;;;;1F74;
+1FCB;GREEK CAPITAL LETTER ETA WITH OXIA;Lu;0;L;0389;;;;N;;;;1F75;
+1FCC;GREEK CAPITAL LETTER ETA WITH PROSGEGRAMMENI;Lt;0;L;0397 0345;;;;N;;;;1FC3;
+1FCD;GREEK PSILI AND VARIA;Sk;0;ON;1FBF 0300;;;;N;;;;;
+1FCE;GREEK PSILI AND OXIA;Sk;0;ON;1FBF 0301;;;;N;;;;;
+1FCF;GREEK PSILI AND PERISPOMENI;Sk;0;ON;1FBF 0342;;;;N;;;;;
+1FD0;GREEK SMALL LETTER IOTA WITH VRACHY;Ll;0;L;03B9 0306;;;;N;;;1FD8;;1FD8
+1FD1;GREEK SMALL LETTER IOTA WITH MACRON;Ll;0;L;03B9 0304;;;;N;;;1FD9;;1FD9
+1FD2;GREEK SMALL LETTER IOTA WITH DIALYTIKA AND VARIA;Ll;0;L;03CA 0300;;;;N;;;;;
+1FD3;GREEK SMALL LETTER IOTA WITH DIALYTIKA AND OXIA;Ll;0;L;0390;;;;N;;;;;
+1FD6;GREEK SMALL LETTER IOTA WITH PERISPOMENI;Ll;0;L;03B9 0342;;;;N;;;;;
+1FD7;GREEK SMALL LETTER IOTA WITH DIALYTIKA AND PERISPOMENI;Ll;0;L;03CA 0342;;;;N;;;;;
+1FD8;GREEK CAPITAL LETTER IOTA WITH VRACHY;Lu;0;L;0399 0306;;;;N;;;;1FD0;
+1FD9;GREEK CAPITAL LETTER IOTA WITH MACRON;Lu;0;L;0399 0304;;;;N;;;;1FD1;
+1FDA;GREEK CAPITAL LETTER IOTA WITH VARIA;Lu;0;L;0399 0300;;;;N;;;;1F76;
+1FDB;GREEK CAPITAL LETTER IOTA WITH OXIA;Lu;0;L;038A;;;;N;;;;1F77;
+1FDD;GREEK DASIA AND VARIA;Sk;0;ON;1FFE 0300;;;;N;;;;;
+1FDE;GREEK DASIA AND OXIA;Sk;0;ON;1FFE 0301;;;;N;;;;;
+1FDF;GREEK DASIA AND PERISPOMENI;Sk;0;ON;1FFE 0342;;;;N;;;;;
+1FE0;GREEK SMALL LETTER UPSILON WITH VRACHY;Ll;0;L;03C5 0306;;;;N;;;1FE8;;1FE8
+1FE1;GREEK SMALL LETTER UPSILON WITH MACRON;Ll;0;L;03C5 0304;;;;N;;;1FE9;;1FE9
+1FE2;GREEK SMALL LETTER UPSILON WITH DIALYTIKA AND VARIA;Ll;0;L;03CB 0300;;;;N;;;;;
+1FE3;GREEK SMALL LETTER UPSILON WITH DIALYTIKA AND OXIA;Ll;0;L;03B0;;;;N;;;;;
+1FE4;GREEK SMALL LETTER RHO WITH PSILI;Ll;0;L;03C1 0313;;;;N;;;;;
+1FE5;GREEK SMALL LETTER RHO WITH DASIA;Ll;0;L;03C1 0314;;;;N;;;1FEC;;1FEC
+1FE6;GREEK SMALL LETTER UPSILON WITH PERISPOMENI;Ll;0;L;03C5 0342;;;;N;;;;;
+1FE7;GREEK SMALL LETTER UPSILON WITH DIALYTIKA AND PERISPOMENI;Ll;0;L;03CB 0342;;;;N;;;;;
+1FE8;GREEK CAPITAL LETTER UPSILON WITH VRACHY;Lu;0;L;03A5 0306;;;;N;;;;1FE0;
+1FE9;GREEK CAPITAL LETTER UPSILON WITH MACRON;Lu;0;L;03A5 0304;;;;N;;;;1FE1;
+1FEA;GREEK CAPITAL LETTER UPSILON WITH VARIA;Lu;0;L;03A5 0300;;;;N;;;;1F7A;
+1FEB;GREEK CAPITAL LETTER UPSILON WITH OXIA;Lu;0;L;038E;;;;N;;;;1F7B;
+1FEC;GREEK CAPITAL LETTER RHO WITH DASIA;Lu;0;L;03A1 0314;;;;N;;;;1FE5;
+1FED;GREEK DIALYTIKA AND VARIA;Sk;0;ON;00A8 0300;;;;N;;;;;
+1FEE;GREEK DIALYTIKA AND OXIA;Sk;0;ON;0385;;;;N;;;;;
+1FEF;GREEK VARIA;Sk;0;ON;0060;;;;N;;;;;
+1FF2;GREEK SMALL LETTER OMEGA WITH VARIA AND YPOGEGRAMMENI;Ll;0;L;1F7C 0345;;;;N;;;;;
+1FF3;GREEK SMALL LETTER OMEGA WITH YPOGEGRAMMENI;Ll;0;L;03C9 0345;;;;N;;;1FFC;;1FFC
+1FF4;GREEK SMALL LETTER OMEGA WITH OXIA AND YPOGEGRAMMENI;Ll;0;L;03CE 0345;;;;N;;;;;
+1FF6;GREEK SMALL LETTER OMEGA WITH PERISPOMENI;Ll;0;L;03C9 0342;;;;N;;;;;
+1FF7;GREEK SMALL LETTER OMEGA WITH PERISPOMENI AND YPOGEGRAMMENI;Ll;0;L;1FF6 0345;;;;N;;;;;
+1FF8;GREEK CAPITAL LETTER OMICRON WITH VARIA;Lu;0;L;039F 0300;;;;N;;;;1F78;
+1FF9;GREEK CAPITAL LETTER OMICRON WITH OXIA;Lu;0;L;038C;;;;N;;;;1F79;
+1FFA;GREEK CAPITAL LETTER OMEGA WITH VARIA;Lu;0;L;03A9 0300;;;;N;;;;1F7C;
+1FFB;GREEK CAPITAL LETTER OMEGA WITH OXIA;Lu;0;L;038F;;;;N;;;;1F7D;
+1FFC;GREEK CAPITAL LETTER OMEGA WITH PROSGEGRAMMENI;Lt;0;L;03A9 0345;;;;N;;;;1FF3;
+1FFD;GREEK OXIA;Sk;0;ON;00B4;;;;N;;;;;
+1FFE;GREEK DASIA;Sk;0;ON;<compat> 0020 0314;;;;N;;;;;
+2000;EN QUAD;Zs;0;WS;2002;;;;N;;;;;
+2001;EM QUAD;Zs;0;WS;2003;;;;N;;;;;
+2002;EN SPACE;Zs;0;WS;<compat> 0020;;;;N;;;;;
+2003;EM SPACE;Zs;0;WS;<compat> 0020;;;;N;;;;;
+2004;THREE-PER-EM SPACE;Zs;0;WS;<compat> 0020;;;;N;;;;;
+2005;FOUR-PER-EM SPACE;Zs;0;WS;<compat> 0020;;;;N;;;;;
+2006;SIX-PER-EM SPACE;Zs;0;WS;<compat> 0020;;;;N;;;;;
+2007;FIGURE SPACE;Zs;0;WS;<noBreak> 0020;;;;N;;;;;
+2008;PUNCTUATION SPACE;Zs;0;WS;<compat> 0020;;;;N;;;;;
+2009;THIN SPACE;Zs;0;WS;<compat> 0020;;;;N;;;;;
+200A;HAIR SPACE;Zs;0;WS;<compat> 0020;;;;N;;;;;
+200B;ZERO WIDTH SPACE;Cf;0;BN;;;;;N;;;;;
+200C;ZERO WIDTH NON-JOINER;Cf;0;BN;;;;;N;;;;;
+200D;ZERO WIDTH JOINER;Cf;0;BN;;;;;N;;;;;
+200E;LEFT-TO-RIGHT MARK;Cf;0;L;;;;;N;;;;;
+200F;RIGHT-TO-LEFT MARK;Cf;0;R;;;;;N;;;;;
+2010;HYPHEN;Pd;0;ON;;;;;N;;;;;
+2011;NON-BREAKING HYPHEN;Pd;0;ON;<noBreak> 2010;;;;N;;;;;
+2012;FIGURE DASH;Pd;0;ON;;;;;N;;;;;
+2013;EN DASH;Pd;0;ON;;;;;N;;;;;
+2014;EM DASH;Pd;0;ON;;;;;N;;;;;
+2015;HORIZONTAL BAR;Pd;0;ON;;;;;N;QUOTATION DASH;;;;
+2016;DOUBLE VERTICAL LINE;Po;0;ON;;;;;N;DOUBLE VERTICAL BAR;;;;
+2017;DOUBLE LOW LINE;Po;0;ON;<compat> 0020 0333;;;;N;SPACING DOUBLE UNDERSCORE;;;;
+2018;LEFT SINGLE QUOTATION MARK;Pi;0;ON;;;;;N;SINGLE TURNED COMMA QUOTATION MARK;;;;
+2019;RIGHT SINGLE QUOTATION MARK;Pf;0;ON;;;;;N;SINGLE COMMA QUOTATION MARK;;;;
+201A;SINGLE LOW-9 QUOTATION MARK;Ps;0;ON;;;;;N;LOW SINGLE COMMA QUOTATION MARK;;;;
+201B;SINGLE HIGH-REVERSED-9 QUOTATION MARK;Pi;0;ON;;;;;N;SINGLE REVERSED COMMA QUOTATION MARK;;;;
+201C;LEFT DOUBLE QUOTATION MARK;Pi;0;ON;;;;;N;DOUBLE TURNED COMMA QUOTATION MARK;;;;
+201D;RIGHT DOUBLE QUOTATION MARK;Pf;0;ON;;;;;N;DOUBLE COMMA QUOTATION MARK;;;;
+201E;DOUBLE LOW-9 QUOTATION MARK;Ps;0;ON;;;;;N;LOW DOUBLE COMMA QUOTATION MARK;;;;
+201F;DOUBLE HIGH-REVERSED-9 QUOTATION MARK;Pi;0;ON;;;;;N;DOUBLE REVERSED COMMA QUOTATION MARK;;;;
+2020;DAGGER;Po;0;ON;;;;;N;;;;;
+2021;DOUBLE DAGGER;Po;0;ON;;;;;N;;;;;
+2022;BULLET;Po;0;ON;;;;;N;;;;;
+2023;TRIANGULAR BULLET;Po;0;ON;;;;;N;;;;;
+2024;ONE DOT LEADER;Po;0;ON;<compat> 002E;;;;N;;;;;
+2025;TWO DOT LEADER;Po;0;ON;<compat> 002E 002E;;;;N;;;;;
+2026;HORIZONTAL ELLIPSIS;Po;0;ON;<compat> 002E 002E 002E;;;;N;;;;;
+2027;HYPHENATION POINT;Po;0;ON;;;;;N;;;;;
+2028;LINE SEPARATOR;Zl;0;WS;;;;;N;;;;;
+2029;PARAGRAPH SEPARATOR;Zp;0;B;;;;;N;;;;;
+202A;LEFT-TO-RIGHT EMBEDDING;Cf;0;LRE;;;;;N;;;;;
+202B;RIGHT-TO-LEFT EMBEDDING;Cf;0;RLE;;;;;N;;;;;
+202C;POP DIRECTIONAL FORMATTING;Cf;0;PDF;;;;;N;;;;;
+202D;LEFT-TO-RIGHT OVERRIDE;Cf;0;LRO;;;;;N;;;;;
+202E;RIGHT-TO-LEFT OVERRIDE;Cf;0;RLO;;;;;N;;;;;
+202F;NARROW NO-BREAK SPACE;Zs;0;CS;<noBreak> 0020;;;;N;;;;;
+2030;PER MILLE SIGN;Po;0;ET;;;;;N;;;;;
+2031;PER TEN THOUSAND SIGN;Po;0;ET;;;;;N;;;;;
+2032;PRIME;Po;0;ET;;;;;N;;;;;
+2033;DOUBLE PRIME;Po;0;ET;<compat> 2032 2032;;;;N;;;;;
+2034;TRIPLE PRIME;Po;0;ET;<compat> 2032 2032 2032;;;;N;;;;;
+2035;REVERSED PRIME;Po;0;ON;;;;;N;;;;;
+2036;REVERSED DOUBLE PRIME;Po;0;ON;<compat> 2035 2035;;;;N;;;;;
+2037;REVERSED TRIPLE PRIME;Po;0;ON;<compat> 2035 2035 2035;;;;N;;;;;
+2038;CARET;Po;0;ON;;;;;N;;;;;
+2039;SINGLE LEFT-POINTING ANGLE QUOTATION MARK;Pi;0;ON;;;;;Y;LEFT POINTING SINGLE GUILLEMET;;;;
+203A;SINGLE RIGHT-POINTING ANGLE QUOTATION MARK;Pf;0;ON;;;;;Y;RIGHT POINTING SINGLE GUILLEMET;;;;
+203B;REFERENCE MARK;Po;0;ON;;;;;N;;;;;
+203C;DOUBLE EXCLAMATION MARK;Po;0;ON;<compat> 0021 0021;;;;N;;;;;
+203D;INTERROBANG;Po;0;ON;;;;;N;;;;;
+203E;OVERLINE;Po;0;ON;<compat> 0020 0305;;;;N;SPACING OVERSCORE;;;;
+203F;UNDERTIE;Pc;0;ON;;;;;N;;Enotikon;;;
+2040;CHARACTER TIE;Pc;0;ON;;;;;N;;;;;
+2041;CARET INSERTION POINT;Po;0;ON;;;;;N;;;;;
+2042;ASTERISM;Po;0;ON;;;;;N;;;;;
+2043;HYPHEN BULLET;Po;0;ON;;;;;N;;;;;
+2044;FRACTION SLASH;Sm;0;CS;;;;;N;;;;;
+2045;LEFT SQUARE BRACKET WITH QUILL;Ps;0;ON;;;;;Y;;;;;
+2046;RIGHT SQUARE BRACKET WITH QUILL;Pe;0;ON;;;;;Y;;;;;
+2047;DOUBLE QUESTION MARK;Po;0;ON;<compat> 003F 003F;;;;N;;;;;
+2048;QUESTION EXCLAMATION MARK;Po;0;ON;<compat> 003F 0021;;;;N;;;;;
+2049;EXCLAMATION QUESTION MARK;Po;0;ON;<compat> 0021 003F;;;;N;;;;;
+204A;TIRONIAN SIGN ET;Po;0;ON;;;;;N;;;;;
+204B;REVERSED PILCROW SIGN;Po;0;ON;;;;;N;;;;;
+204C;BLACK LEFTWARDS BULLET;Po;0;ON;;;;;N;;;;;
+204D;BLACK RIGHTWARDS BULLET;Po;0;ON;;;;;N;;;;;
+204E;LOW ASTERISK;Po;0;ON;;;;;N;;;;;
+204F;REVERSED SEMICOLON;Po;0;ON;;;;;N;;;;;
+2050;CLOSE UP;Po;0;ON;;;;;N;;;;;
+2051;TWO ASTERISKS ALIGNED VERTICALLY;Po;0;ON;;;;;N;;;;;
+2052;COMMERCIAL MINUS SIGN;Sm;0;ON;;;;;N;;;;;
+2053;SWUNG DASH;Po;0;ON;;;;;N;;;;;
+2054;INVERTED UNDERTIE;Pc;0;ON;;;;;N;;;;;
+2055;FLOWER PUNCTUATION MARK;Po;0;ON;;;;;N;;;;;
+2056;THREE DOT PUNCTUATION;Po;0;ON;;;;;N;;;;;
+2057;QUADRUPLE PRIME;Po;0;ON;<compat> 2032 2032 2032 2032;;;;N;;;;;
+2058;FOUR DOT PUNCTUATION;Po;0;ON;;;;;N;;;;;
+2059;FIVE DOT PUNCTUATION;Po;0;ON;;;;;N;;;;;
+205A;TWO DOT PUNCTUATION;Po;0;ON;;;;;N;;;;;
+205B;FOUR DOT MARK;Po;0;ON;;;;;N;;;;;
+205C;DOTTED CROSS;Po;0;ON;;;;;N;;;;;
+205D;TRICOLON;Po;0;ON;;;;;N;;;;;
+205E;VERTICAL FOUR DOTS;Po;0;ON;;;;;N;;;;;
+205F;MEDIUM MATHEMATICAL SPACE;Zs;0;WS;<compat> 0020;;;;N;;;;;
+2060;WORD JOINER;Cf;0;BN;;;;;N;;;;;
+2061;FUNCTION APPLICATION;Cf;0;BN;;;;;N;;;;;
+2062;INVISIBLE TIMES;Cf;0;BN;;;;;N;;;;;
+2063;INVISIBLE SEPARATOR;Cf;0;BN;;;;;N;;;;;
+206A;INHIBIT SYMMETRIC SWAPPING;Cf;0;BN;;;;;N;;;;;
+206B;ACTIVATE SYMMETRIC SWAPPING;Cf;0;BN;;;;;N;;;;;
+206C;INHIBIT ARABIC FORM SHAPING;Cf;0;BN;;;;;N;;;;;
+206D;ACTIVATE ARABIC FORM SHAPING;Cf;0;BN;;;;;N;;;;;
+206E;NATIONAL DIGIT SHAPES;Cf;0;BN;;;;;N;;;;;
+206F;NOMINAL DIGIT SHAPES;Cf;0;BN;;;;;N;;;;;
+2070;SUPERSCRIPT ZERO;No;0;EN;<super> 0030;;0;0;N;SUPERSCRIPT DIGIT ZERO;;;;
+2071;SUPERSCRIPT LATIN SMALL LETTER I;Ll;0;L;<super> 0069;;;;N;;;;;
+2074;SUPERSCRIPT FOUR;No;0;EN;<super> 0034;;4;4;N;SUPERSCRIPT DIGIT FOUR;;;;
+2075;SUPERSCRIPT FIVE;No;0;EN;<super> 0035;;5;5;N;SUPERSCRIPT DIGIT FIVE;;;;
+2076;SUPERSCRIPT SIX;No;0;EN;<super> 0036;;6;6;N;SUPERSCRIPT DIGIT SIX;;;;
+2077;SUPERSCRIPT SEVEN;No;0;EN;<super> 0037;;7;7;N;SUPERSCRIPT DIGIT SEVEN;;;;
+2078;SUPERSCRIPT EIGHT;No;0;EN;<super> 0038;;8;8;N;SUPERSCRIPT DIGIT EIGHT;;;;
+2079;SUPERSCRIPT NINE;No;0;EN;<super> 0039;;9;9;N;SUPERSCRIPT DIGIT NINE;;;;
+207A;SUPERSCRIPT PLUS SIGN;Sm;0;ES;<super> 002B;;;;N;;;;;
+207B;SUPERSCRIPT MINUS;Sm;0;ES;<super> 2212;;;;N;SUPERSCRIPT HYPHEN-MINUS;;;;
+207C;SUPERSCRIPT EQUALS SIGN;Sm;0;ON;<super> 003D;;;;N;;;;;
+207D;SUPERSCRIPT LEFT PARENTHESIS;Ps;0;ON;<super> 0028;;;;Y;SUPERSCRIPT OPENING PARENTHESIS;;;;
+207E;SUPERSCRIPT RIGHT PARENTHESIS;Pe;0;ON;<super> 0029;;;;Y;SUPERSCRIPT CLOSING PARENTHESIS;;;;
+207F;SUPERSCRIPT LATIN SMALL LETTER N;Ll;0;L;<super> 006E;;;;N;;;;;
+2080;SUBSCRIPT ZERO;No;0;EN;<sub> 0030;;0;0;N;SUBSCRIPT DIGIT ZERO;;;;
+2081;SUBSCRIPT ONE;No;0;EN;<sub> 0031;;1;1;N;SUBSCRIPT DIGIT ONE;;;;
+2082;SUBSCRIPT TWO;No;0;EN;<sub> 0032;;2;2;N;SUBSCRIPT DIGIT TWO;;;;
+2083;SUBSCRIPT THREE;No;0;EN;<sub> 0033;;3;3;N;SUBSCRIPT DIGIT THREE;;;;
+2084;SUBSCRIPT FOUR;No;0;EN;<sub> 0034;;4;4;N;SUBSCRIPT DIGIT FOUR;;;;
+2085;SUBSCRIPT FIVE;No;0;EN;<sub> 0035;;5;5;N;SUBSCRIPT DIGIT FIVE;;;;
+2086;SUBSCRIPT SIX;No;0;EN;<sub> 0036;;6;6;N;SUBSCRIPT DIGIT SIX;;;;
+2087;SUBSCRIPT SEVEN;No;0;EN;<sub> 0037;;7;7;N;SUBSCRIPT DIGIT SEVEN;;;;
+2088;SUBSCRIPT EIGHT;No;0;EN;<sub> 0038;;8;8;N;SUBSCRIPT DIGIT EIGHT;;;;
+2089;SUBSCRIPT NINE;No;0;EN;<sub> 0039;;9;9;N;SUBSCRIPT DIGIT NINE;;;;
+208A;SUBSCRIPT PLUS SIGN;Sm;0;ES;<sub> 002B;;;;N;;;;;
+208B;SUBSCRIPT MINUS;Sm;0;ES;<sub> 2212;;;;N;SUBSCRIPT HYPHEN-MINUS;;;;
+208C;SUBSCRIPT EQUALS SIGN;Sm;0;ON;<sub> 003D;;;;N;;;;;
+208D;SUBSCRIPT LEFT PARENTHESIS;Ps;0;ON;<sub> 0028;;;;Y;SUBSCRIPT OPENING PARENTHESIS;;;;
+208E;SUBSCRIPT RIGHT PARENTHESIS;Pe;0;ON;<sub> 0029;;;;Y;SUBSCRIPT CLOSING PARENTHESIS;;;;
+2090;LATIN SUBSCRIPT SMALL LETTER A;Lm;0;L;<sub> 0061;;;;N;;;;;
+2091;LATIN SUBSCRIPT SMALL LETTER E;Lm;0;L;<sub> 0065;;;;N;;;;;
+2092;LATIN SUBSCRIPT SMALL LETTER O;Lm;0;L;<sub> 006F;;;;N;;;;;
+2093;LATIN SUBSCRIPT SMALL LETTER X;Lm;0;L;<sub> 0078;;;;N;;;;;
+2094;LATIN SUBSCRIPT SMALL LETTER SCHWA;Lm;0;L;<sub> 0259;;;;N;;;;;
+20A0;EURO-CURRENCY SIGN;Sc;0;ET;;;;;N;;;;;
+20A1;COLON SIGN;Sc;0;ET;;;;;N;;;;;
+20A2;CRUZEIRO SIGN;Sc;0;ET;;;;;N;;;;;
+20A3;FRENCH FRANC SIGN;Sc;0;ET;;;;;N;;;;;
+20A4;LIRA SIGN;Sc;0;ET;;;;;N;;;;;
+20A5;MILL SIGN;Sc;0;ET;;;;;N;;;;;
+20A6;NAIRA SIGN;Sc;0;ET;;;;;N;;;;;
+20A7;PESETA SIGN;Sc;0;ET;;;;;N;;;;;
+20A8;RUPEE SIGN;Sc;0;ET;<compat> 0052 0073;;;;N;;;;;
+20A9;WON SIGN;Sc;0;ET;;;;;N;;;;;
+20AA;NEW SHEQEL SIGN;Sc;0;ET;;;;;N;;;;;
+20AB;DONG SIGN;Sc;0;ET;;;;;N;;;;;
+20AC;EURO SIGN;Sc;0;ET;;;;;N;;;;;
+20AD;KIP SIGN;Sc;0;ET;;;;;N;;;;;
+20AE;TUGRIK SIGN;Sc;0;ET;;;;;N;;;;;
+20AF;DRACHMA SIGN;Sc;0;ET;;;;;N;;;;;
+20B0;GERMAN PENNY SIGN;Sc;0;ET;;;;;N;;;;;
+20B1;PESO SIGN;Sc;0;ET;;;;;N;;;;;
+20B2;GUARANI SIGN;Sc;0;ET;;;;;N;;;;;
+20B3;AUSTRAL SIGN;Sc;0;ET;;;;;N;;;;;
+20B4;HRYVNIA SIGN;Sc;0;ET;;;;;N;;;;;
+20B5;CEDI SIGN;Sc;0;ET;;;;;N;;;;;
+20D0;COMBINING LEFT HARPOON ABOVE;Mn;230;NSM;;;;;N;NON-SPACING LEFT HARPOON ABOVE;;;;
+20D1;COMBINING RIGHT HARPOON ABOVE;Mn;230;NSM;;;;;N;NON-SPACING RIGHT HARPOON ABOVE;;;;
+20D2;COMBINING LONG VERTICAL LINE OVERLAY;Mn;1;NSM;;;;;N;NON-SPACING LONG VERTICAL BAR OVERLAY;;;;
+20D3;COMBINING SHORT VERTICAL LINE OVERLAY;Mn;1;NSM;;;;;N;NON-SPACING SHORT VERTICAL BAR OVERLAY;;;;
+20D4;COMBINING ANTICLOCKWISE ARROW ABOVE;Mn;230;NSM;;;;;N;NON-SPACING ANTICLOCKWISE ARROW ABOVE;;;;
+20D5;COMBINING CLOCKWISE ARROW ABOVE;Mn;230;NSM;;;;;N;NON-SPACING CLOCKWISE ARROW ABOVE;;;;
+20D6;COMBINING LEFT ARROW ABOVE;Mn;230;NSM;;;;;N;NON-SPACING LEFT ARROW ABOVE;;;;
+20D7;COMBINING RIGHT ARROW ABOVE;Mn;230;NSM;;;;;N;NON-SPACING RIGHT ARROW ABOVE;;;;
+20D8;COMBINING RING OVERLAY;Mn;1;NSM;;;;;N;NON-SPACING RING OVERLAY;;;;
+20D9;COMBINING CLOCKWISE RING OVERLAY;Mn;1;NSM;;;;;N;NON-SPACING CLOCKWISE RING OVERLAY;;;;
+20DA;COMBINING ANTICLOCKWISE RING OVERLAY;Mn;1;NSM;;;;;N;NON-SPACING ANTICLOCKWISE RING OVERLAY;;;;
+20DB;COMBINING THREE DOTS ABOVE;Mn;230;NSM;;;;;N;NON-SPACING THREE DOTS ABOVE;;;;
+20DC;COMBINING FOUR DOTS ABOVE;Mn;230;NSM;;;;;N;NON-SPACING FOUR DOTS ABOVE;;;;
+20DD;COMBINING ENCLOSING CIRCLE;Me;0;NSM;;;;;N;ENCLOSING CIRCLE;;;;
+20DE;COMBINING ENCLOSING SQUARE;Me;0;NSM;;;;;N;ENCLOSING SQUARE;;;;
+20DF;COMBINING ENCLOSING DIAMOND;Me;0;NSM;;;;;N;ENCLOSING DIAMOND;;;;
+20E0;COMBINING ENCLOSING CIRCLE BACKSLASH;Me;0;NSM;;;;;N;ENCLOSING CIRCLE SLASH;;;;
+20E1;COMBINING LEFT RIGHT ARROW ABOVE;Mn;230;NSM;;;;;N;NON-SPACING LEFT RIGHT ARROW ABOVE;;;;
+20E2;COMBINING ENCLOSING SCREEN;Me;0;NSM;;;;;N;;;;;
+20E3;COMBINING ENCLOSING KEYCAP;Me;0;NSM;;;;;N;;;;;
+20E4;COMBINING ENCLOSING UPWARD POINTING TRIANGLE;Me;0;NSM;;;;;N;;;;;
+20E5;COMBINING REVERSE SOLIDUS OVERLAY;Mn;1;NSM;;;;;N;;;;;
+20E6;COMBINING DOUBLE VERTICAL STROKE OVERLAY;Mn;1;NSM;;;;;N;;;;;
+20E7;COMBINING ANNUITY SYMBOL;Mn;230;NSM;;;;;N;;;;;
+20E8;COMBINING TRIPLE UNDERDOT;Mn;220;NSM;;;;;N;;;;;
+20E9;COMBINING WIDE BRIDGE ABOVE;Mn;230;NSM;;;;;N;;;;;
+20EA;COMBINING LEFTWARDS ARROW OVERLAY;Mn;1;NSM;;;;;N;;;;;
+20EB;COMBINING LONG DOUBLE SOLIDUS OVERLAY;Mn;1;NSM;;;;;N;;;;;
+2100;ACCOUNT OF;So;0;ON;<compat> 0061 002F 0063;;;;N;;;;;
+2101;ADDRESSED TO THE SUBJECT;So;0;ON;<compat> 0061 002F 0073;;;;N;;;;;
+2102;DOUBLE-STRUCK CAPITAL C;Lu;0;L;<font> 0043;;;;N;DOUBLE-STRUCK C;;;;
+2103;DEGREE CELSIUS;So;0;ON;<compat> 00B0 0043;;;;N;DEGREES CENTIGRADE;;;;
+2104;CENTRE LINE SYMBOL;So;0;ON;;;;;N;C L SYMBOL;;;;
+2105;CARE OF;So;0;ON;<compat> 0063 002F 006F;;;;N;;;;;
+2106;CADA UNA;So;0;ON;<compat> 0063 002F 0075;;;;N;;;;;
+2107;EULER CONSTANT;Lu;0;L;<compat> 0190;;;;N;EULERS;;;;
+2108;SCRUPLE;So;0;ON;;;;;N;;;;;
+2109;DEGREE FAHRENHEIT;So;0;ON;<compat> 00B0 0046;;;;N;DEGREES FAHRENHEIT;;;;
+210A;SCRIPT SMALL G;Ll;0;L;<font> 0067;;;;N;;;;;
+210B;SCRIPT CAPITAL H;Lu;0;L;<font> 0048;;;;N;SCRIPT H;;;;
+210C;BLACK-LETTER CAPITAL H;Lu;0;L;<font> 0048;;;;N;BLACK-LETTER H;;;;
+210D;DOUBLE-STRUCK CAPITAL H;Lu;0;L;<font> 0048;;;;N;DOUBLE-STRUCK H;;;;
+210E;PLANCK CONSTANT;Ll;0;L;<font> 0068;;;;N;;;;;
+210F;PLANCK CONSTANT OVER TWO PI;Ll;0;L;<font> 0127;;;;N;PLANCK CONSTANT OVER 2 PI;;;;
+2110;SCRIPT CAPITAL I;Lu;0;L;<font> 0049;;;;N;SCRIPT I;;;;
+2111;BLACK-LETTER CAPITAL I;Lu;0;L;<font> 0049;;;;N;BLACK-LETTER I;;;;
+2112;SCRIPT CAPITAL L;Lu;0;L;<font> 004C;;;;N;SCRIPT L;;;;
+2113;SCRIPT SMALL L;Ll;0;L;<font> 006C;;;;N;;;;;
+2114;L B BAR SYMBOL;So;0;ON;;;;;N;;;;;
+2115;DOUBLE-STRUCK CAPITAL N;Lu;0;L;<font> 004E;;;;N;DOUBLE-STRUCK N;;;;
+2116;NUMERO SIGN;So;0;ON;<compat> 004E 006F;;;;N;NUMERO;;;;
+2117;SOUND RECORDING COPYRIGHT;So;0;ON;;;;;N;;;;;
+2118;SCRIPT CAPITAL P;So;0;ON;;;;;N;SCRIPT P;;;;
+2119;DOUBLE-STRUCK CAPITAL P;Lu;0;L;<font> 0050;;;;N;DOUBLE-STRUCK P;;;;
+211A;DOUBLE-STRUCK CAPITAL Q;Lu;0;L;<font> 0051;;;;N;DOUBLE-STRUCK Q;;;;
+211B;SCRIPT CAPITAL R;Lu;0;L;<font> 0052;;;;N;SCRIPT R;;;;
+211C;BLACK-LETTER CAPITAL R;Lu;0;L;<font> 0052;;;;N;BLACK-LETTER R;;;;
+211D;DOUBLE-STRUCK CAPITAL R;Lu;0;L;<font> 0052;;;;N;DOUBLE-STRUCK R;;;;
+211E;PRESCRIPTION TAKE;So;0;ON;;;;;N;;;;;
+211F;RESPONSE;So;0;ON;;;;;N;;;;;
+2120;SERVICE MARK;So;0;ON;<super> 0053 004D;;;;N;;;;;
+2121;TELEPHONE SIGN;So;0;ON;<compat> 0054 0045 004C;;;;N;T E L SYMBOL;;;;
+2122;TRADE MARK SIGN;So;0;ON;<super> 0054 004D;;;;N;TRADEMARK;;;;
+2123;VERSICLE;So;0;ON;;;;;N;;;;;
+2124;DOUBLE-STRUCK CAPITAL Z;Lu;0;L;<font> 005A;;;;N;DOUBLE-STRUCK Z;;;;
+2125;OUNCE SIGN;So;0;ON;;;;;N;OUNCE;;;;
+2126;OHM SIGN;Lu;0;L;03A9;;;;N;OHM;;;03C9;
+2127;INVERTED OHM SIGN;So;0;ON;;;;;N;MHO;;;;
+2128;BLACK-LETTER CAPITAL Z;Lu;0;L;<font> 005A;;;;N;BLACK-LETTER Z;;;;
+2129;TURNED GREEK SMALL LETTER IOTA;So;0;ON;;;;;N;;;;;
+212A;KELVIN SIGN;Lu;0;L;004B;;;;N;DEGREES KELVIN;;;006B;
+212B;ANGSTROM SIGN;Lu;0;L;00C5;;;;N;ANGSTROM UNIT;;;00E5;
+212C;SCRIPT CAPITAL B;Lu;0;L;<font> 0042;;;;N;SCRIPT B;;;;
+212D;BLACK-LETTER CAPITAL C;Lu;0;L;<font> 0043;;;;N;BLACK-LETTER C;;;;
+212E;ESTIMATED SYMBOL;So;0;ET;;;;;N;;;;;
+212F;SCRIPT SMALL E;Ll;0;L;<font> 0065;;;;N;;;;;
+2130;SCRIPT CAPITAL E;Lu;0;L;<font> 0045;;;;N;SCRIPT E;;;;
+2131;SCRIPT CAPITAL F;Lu;0;L;<font> 0046;;;;N;SCRIPT F;;;;
+2132;TURNED CAPITAL F;So;0;ON;;;;;N;TURNED F;;;;
+2133;SCRIPT CAPITAL M;Lu;0;L;<font> 004D;;;;N;SCRIPT M;;;;
+2134;SCRIPT SMALL O;Ll;0;L;<font> 006F;;;;N;;;;;
+2135;ALEF SYMBOL;Lo;0;L;<compat> 05D0;;;;N;FIRST TRANSFINITE CARDINAL;;;;
+2136;BET SYMBOL;Lo;0;L;<compat> 05D1;;;;N;SECOND TRANSFINITE CARDINAL;;;;
+2137;GIMEL SYMBOL;Lo;0;L;<compat> 05D2;;;;N;THIRD TRANSFINITE CARDINAL;;;;
+2138;DALET SYMBOL;Lo;0;L;<compat> 05D3;;;;N;FOURTH TRANSFINITE CARDINAL;;;;
+2139;INFORMATION SOURCE;Ll;0;L;<font> 0069;;;;N;;;;;
+213A;ROTATED CAPITAL Q;So;0;ON;;;;;N;;;;;
+213B;FACSIMILE SIGN;So;0;ON;<compat> 0046 0041 0058;;;;N;;;;;
+213C;DOUBLE-STRUCK SMALL PI;Ll;0;L;<font> 03C0;;;;N;;;;;
+213D;DOUBLE-STRUCK SMALL GAMMA;Ll;0;L;<font> 03B3;;;;N;;;;;
+213E;DOUBLE-STRUCK CAPITAL GAMMA;Lu;0;L;<font> 0393;;;;N;;;;;
+213F;DOUBLE-STRUCK CAPITAL PI;Lu;0;L;<font> 03A0;;;;N;;;;;
+2140;DOUBLE-STRUCK N-ARY SUMMATION;Sm;0;ON;<font> 2211;;;;Y;;;;;
+2141;TURNED SANS-SERIF CAPITAL G;Sm;0;ON;;;;;N;;;;;
+2142;TURNED SANS-SERIF CAPITAL L;Sm;0;ON;;;;;N;;;;;
+2143;REVERSED SANS-SERIF CAPITAL L;Sm;0;ON;;;;;N;;;;;
+2144;TURNED SANS-SERIF CAPITAL Y;Sm;0;ON;;;;;N;;;;;
+2145;DOUBLE-STRUCK ITALIC CAPITAL D;Lu;0;L;<font> 0044;;;;N;;;;;
+2146;DOUBLE-STRUCK ITALIC SMALL D;Ll;0;L;<font> 0064;;;;N;;;;;
+2147;DOUBLE-STRUCK ITALIC SMALL E;Ll;0;L;<font> 0065;;;;N;;;;;
+2148;DOUBLE-STRUCK ITALIC SMALL I;Ll;0;L;<font> 0069;;;;N;;;;;
+2149;DOUBLE-STRUCK ITALIC SMALL J;Ll;0;L;<font> 006A;;;;N;;;;;
+214A;PROPERTY LINE;So;0;ON;;;;;N;;;;;
+214B;TURNED AMPERSAND;Sm;0;ON;;;;;N;;;;;
+214C;PER SIGN;So;0;ON;;;;;N;;;;;
+2153;VULGAR FRACTION ONE THIRD;No;0;ON;<fraction> 0031 2044 0033;;;1/3;N;FRACTION ONE THIRD;;;;
+2154;VULGAR FRACTION TWO THIRDS;No;0;ON;<fraction> 0032 2044 0033;;;2/3;N;FRACTION TWO THIRDS;;;;
+2155;VULGAR FRACTION ONE FIFTH;No;0;ON;<fraction> 0031 2044 0035;;;1/5;N;FRACTION ONE FIFTH;;;;
+2156;VULGAR FRACTION TWO FIFTHS;No;0;ON;<fraction> 0032 2044 0035;;;2/5;N;FRACTION TWO FIFTHS;;;;
+2157;VULGAR FRACTION THREE FIFTHS;No;0;ON;<fraction> 0033 2044 0035;;;3/5;N;FRACTION THREE FIFTHS;;;;
+2158;VULGAR FRACTION FOUR FIFTHS;No;0;ON;<fraction> 0034 2044 0035;;;4/5;N;FRACTION FOUR FIFTHS;;;;
+2159;VULGAR FRACTION ONE SIXTH;No;0;ON;<fraction> 0031 2044 0036;;;1/6;N;FRACTION ONE SIXTH;;;;
+215A;VULGAR FRACTION FIVE SIXTHS;No;0;ON;<fraction> 0035 2044 0036;;;5/6;N;FRACTION FIVE SIXTHS;;;;
+215B;VULGAR FRACTION ONE EIGHTH;No;0;ON;<fraction> 0031 2044 0038;;;1/8;N;FRACTION ONE EIGHTH;;;;
+215C;VULGAR FRACTION THREE EIGHTHS;No;0;ON;<fraction> 0033 2044 0038;;;3/8;N;FRACTION THREE EIGHTHS;;;;
+215D;VULGAR FRACTION FIVE EIGHTHS;No;0;ON;<fraction> 0035 2044 0038;;;5/8;N;FRACTION FIVE EIGHTHS;;;;
+215E;VULGAR FRACTION SEVEN EIGHTHS;No;0;ON;<fraction> 0037 2044 0038;;;7/8;N;FRACTION SEVEN EIGHTHS;;;;
+215F;FRACTION NUMERATOR ONE;No;0;ON;<fraction> 0031 2044;;;1;N;;;;;
+2160;ROMAN NUMERAL ONE;Nl;0;L;<compat> 0049;;;1;N;;;;2170;
+2161;ROMAN NUMERAL TWO;Nl;0;L;<compat> 0049 0049;;;2;N;;;;2171;
+2162;ROMAN NUMERAL THREE;Nl;0;L;<compat> 0049 0049 0049;;;3;N;;;;2172;
+2163;ROMAN NUMERAL FOUR;Nl;0;L;<compat> 0049 0056;;;4;N;;;;2173;
+2164;ROMAN NUMERAL FIVE;Nl;0;L;<compat> 0056;;;5;N;;;;2174;
+2165;ROMAN NUMERAL SIX;Nl;0;L;<compat> 0056 0049;;;6;N;;;;2175;
+2166;ROMAN NUMERAL SEVEN;Nl;0;L;<compat> 0056 0049 0049;;;7;N;;;;2176;
+2167;ROMAN NUMERAL EIGHT;Nl;0;L;<compat> 0056 0049 0049 0049;;;8;N;;;;2177;
+2168;ROMAN NUMERAL NINE;Nl;0;L;<compat> 0049 0058;;;9;N;;;;2178;
+2169;ROMAN NUMERAL TEN;Nl;0;L;<compat> 0058;;;10;N;;;;2179;
+216A;ROMAN NUMERAL ELEVEN;Nl;0;L;<compat> 0058 0049;;;11;N;;;;217A;
+216B;ROMAN NUMERAL TWELVE;Nl;0;L;<compat> 0058 0049 0049;;;12;N;;;;217B;
+216C;ROMAN NUMERAL FIFTY;Nl;0;L;<compat> 004C;;;50;N;;;;217C;
+216D;ROMAN NUMERAL ONE HUNDRED;Nl;0;L;<compat> 0043;;;100;N;;;;217D;
+216E;ROMAN NUMERAL FIVE HUNDRED;Nl;0;L;<compat> 0044;;;500;N;;;;217E;
+216F;ROMAN NUMERAL ONE THOUSAND;Nl;0;L;<compat> 004D;;;1000;N;;;;217F;
+2170;SMALL ROMAN NUMERAL ONE;Nl;0;L;<compat> 0069;;;1;N;;;2160;;2160
+2171;SMALL ROMAN NUMERAL TWO;Nl;0;L;<compat> 0069 0069;;;2;N;;;2161;;2161
+2172;SMALL ROMAN NUMERAL THREE;Nl;0;L;<compat> 0069 0069 0069;;;3;N;;;2162;;2162
+2173;SMALL ROMAN NUMERAL FOUR;Nl;0;L;<compat> 0069 0076;;;4;N;;;2163;;2163
+2174;SMALL ROMAN NUMERAL FIVE;Nl;0;L;<compat> 0076;;;5;N;;;2164;;2164
+2175;SMALL ROMAN NUMERAL SIX;Nl;0;L;<compat> 0076 0069;;;6;N;;;2165;;2165
+2176;SMALL ROMAN NUMERAL SEVEN;Nl;0;L;<compat> 0076 0069 0069;;;7;N;;;2166;;2166
+2177;SMALL ROMAN NUMERAL EIGHT;Nl;0;L;<compat> 0076 0069 0069 0069;;;8;N;;;2167;;2167
+2178;SMALL ROMAN NUMERAL NINE;Nl;0;L;<compat> 0069 0078;;;9;N;;;2168;;2168
+2179;SMALL ROMAN NUMERAL TEN;Nl;0;L;<compat> 0078;;;10;N;;;2169;;2169
+217A;SMALL ROMAN NUMERAL ELEVEN;Nl;0;L;<compat> 0078 0069;;;11;N;;;216A;;216A
+217B;SMALL ROMAN NUMERAL TWELVE;Nl;0;L;<compat> 0078 0069 0069;;;12;N;;;216B;;216B
+217C;SMALL ROMAN NUMERAL FIFTY;Nl;0;L;<compat> 006C;;;50;N;;;216C;;216C
+217D;SMALL ROMAN NUMERAL ONE HUNDRED;Nl;0;L;<compat> 0063;;;100;N;;;216D;;216D
+217E;SMALL ROMAN NUMERAL FIVE HUNDRED;Nl;0;L;<compat> 0064;;;500;N;;;216E;;216E
+217F;SMALL ROMAN NUMERAL ONE THOUSAND;Nl;0;L;<compat> 006D;;;1000;N;;;216F;;216F
+2180;ROMAN NUMERAL ONE THOUSAND C D;Nl;0;L;;;;1000;N;;;;;
+2181;ROMAN NUMERAL FIVE THOUSAND;Nl;0;L;;;;5000;N;;;;;
+2182;ROMAN NUMERAL TEN THOUSAND;Nl;0;L;;;;10000;N;;;;;
+2183;ROMAN NUMERAL REVERSED ONE HUNDRED;Nl;0;L;;;;;N;;;;;
+2190;LEFTWARDS ARROW;Sm;0;ON;;;;;N;LEFT ARROW;;;;
+2191;UPWARDS ARROW;Sm;0;ON;;;;;N;UP ARROW;;;;
+2192;RIGHTWARDS ARROW;Sm;0;ON;;;;;N;RIGHT ARROW;;;;
+2193;DOWNWARDS ARROW;Sm;0;ON;;;;;N;DOWN ARROW;;;;
+2194;LEFT RIGHT ARROW;Sm;0;ON;;;;;N;;;;;
+2195;UP DOWN ARROW;So;0;ON;;;;;N;;;;;
+2196;NORTH WEST ARROW;So;0;ON;;;;;N;UPPER LEFT ARROW;;;;
+2197;NORTH EAST ARROW;So;0;ON;;;;;N;UPPER RIGHT ARROW;;;;
+2198;SOUTH EAST ARROW;So;0;ON;;;;;N;LOWER RIGHT ARROW;;;;
+2199;SOUTH WEST ARROW;So;0;ON;;;;;N;LOWER LEFT ARROW;;;;
+219A;LEFTWARDS ARROW WITH STROKE;Sm;0;ON;2190 0338;;;;N;LEFT ARROW WITH STROKE;;;;
+219B;RIGHTWARDS ARROW WITH STROKE;Sm;0;ON;2192 0338;;;;N;RIGHT ARROW WITH STROKE;;;;
+219C;LEFTWARDS WAVE ARROW;So;0;ON;;;;;N;LEFT WAVE ARROW;;;;
+219D;RIGHTWARDS WAVE ARROW;So;0;ON;;;;;N;RIGHT WAVE ARROW;;;;
+219E;LEFTWARDS TWO HEADED ARROW;So;0;ON;;;;;N;LEFT TWO HEADED ARROW;;;;
+219F;UPWARDS TWO HEADED ARROW;So;0;ON;;;;;N;UP TWO HEADED ARROW;;;;
+21A0;RIGHTWARDS TWO HEADED ARROW;Sm;0;ON;;;;;N;RIGHT TWO HEADED ARROW;;;;
+21A1;DOWNWARDS TWO HEADED ARROW;So;0;ON;;;;;N;DOWN TWO HEADED ARROW;;;;
+21A2;LEFTWARDS ARROW WITH TAIL;So;0;ON;;;;;N;LEFT ARROW WITH TAIL;;;;
+21A3;RIGHTWARDS ARROW WITH TAIL;Sm;0;ON;;;;;N;RIGHT ARROW WITH TAIL;;;;
+21A4;LEFTWARDS ARROW FROM BAR;So;0;ON;;;;;N;LEFT ARROW FROM BAR;;;;
+21A5;UPWARDS ARROW FROM BAR;So;0;ON;;;;;N;UP ARROW FROM BAR;;;;
+21A6;RIGHTWARDS ARROW FROM BAR;Sm;0;ON;;;;;N;RIGHT ARROW FROM BAR;;;;
+21A7;DOWNWARDS ARROW FROM BAR;So;0;ON;;;;;N;DOWN ARROW FROM BAR;;;;
+21A8;UP DOWN ARROW WITH BASE;So;0;ON;;;;;N;;;;;
+21A9;LEFTWARDS ARROW WITH HOOK;So;0;ON;;;;;N;LEFT ARROW WITH HOOK;;;;
+21AA;RIGHTWARDS ARROW WITH HOOK;So;0;ON;;;;;N;RIGHT ARROW WITH HOOK;;;;
+21AB;LEFTWARDS ARROW WITH LOOP;So;0;ON;;;;;N;LEFT ARROW WITH LOOP;;;;
+21AC;RIGHTWARDS ARROW WITH LOOP;So;0;ON;;;;;N;RIGHT ARROW WITH LOOP;;;;
+21AD;LEFT RIGHT WAVE ARROW;So;0;ON;;;;;N;;;;;
+21AE;LEFT RIGHT ARROW WITH STROKE;Sm;0;ON;2194 0338;;;;N;;;;;
+21AF;DOWNWARDS ZIGZAG ARROW;So;0;ON;;;;;N;DOWN ZIGZAG ARROW;;;;
+21B0;UPWARDS ARROW WITH TIP LEFTWARDS;So;0;ON;;;;;N;UP ARROW WITH TIP LEFT;;;;
+21B1;UPWARDS ARROW WITH TIP RIGHTWARDS;So;0;ON;;;;;N;UP ARROW WITH TIP RIGHT;;;;
+21B2;DOWNWARDS ARROW WITH TIP LEFTWARDS;So;0;ON;;;;;N;DOWN ARROW WITH TIP LEFT;;;;
+21B3;DOWNWARDS ARROW WITH TIP RIGHTWARDS;So;0;ON;;;;;N;DOWN ARROW WITH TIP RIGHT;;;;
+21B4;RIGHTWARDS ARROW WITH CORNER DOWNWARDS;So;0;ON;;;;;N;RIGHT ARROW WITH CORNER DOWN;;;;
+21B5;DOWNWARDS ARROW WITH CORNER LEFTWARDS;So;0;ON;;;;;N;DOWN ARROW WITH CORNER LEFT;;;;
+21B6;ANTICLOCKWISE TOP SEMICIRCLE ARROW;So;0;ON;;;;;N;;;;;
+21B7;CLOCKWISE TOP SEMICIRCLE ARROW;So;0;ON;;;;;N;;;;;
+21B8;NORTH WEST ARROW TO LONG BAR;So;0;ON;;;;;N;UPPER LEFT ARROW TO LONG BAR;;;;
+21B9;LEFTWARDS ARROW TO BAR OVER RIGHTWARDS ARROW TO BAR;So;0;ON;;;;;N;LEFT ARROW TO BAR OVER RIGHT ARROW TO BAR;;;;
+21BA;ANTICLOCKWISE OPEN CIRCLE ARROW;So;0;ON;;;;;N;;;;;
+21BB;CLOCKWISE OPEN CIRCLE ARROW;So;0;ON;;;;;N;;;;;
+21BC;LEFTWARDS HARPOON WITH BARB UPWARDS;So;0;ON;;;;;N;LEFT HARPOON WITH BARB UP;;;;
+21BD;LEFTWARDS HARPOON WITH BARB DOWNWARDS;So;0;ON;;;;;N;LEFT HARPOON WITH BARB DOWN;;;;
+21BE;UPWARDS HARPOON WITH BARB RIGHTWARDS;So;0;ON;;;;;N;UP HARPOON WITH BARB RIGHT;;;;
+21BF;UPWARDS HARPOON WITH BARB LEFTWARDS;So;0;ON;;;;;N;UP HARPOON WITH BARB LEFT;;;;
+21C0;RIGHTWARDS HARPOON WITH BARB UPWARDS;So;0;ON;;;;;N;RIGHT HARPOON WITH BARB UP;;;;
+21C1;RIGHTWARDS HARPOON WITH BARB DOWNWARDS;So;0;ON;;;;;N;RIGHT HARPOON WITH BARB DOWN;;;;
+21C2;DOWNWARDS HARPOON WITH BARB RIGHTWARDS;So;0;ON;;;;;N;DOWN HARPOON WITH BARB RIGHT;;;;
+21C3;DOWNWARDS HARPOON WITH BARB LEFTWARDS;So;0;ON;;;;;N;DOWN HARPOON WITH BARB LEFT;;;;
+21C4;RIGHTWARDS ARROW OVER LEFTWARDS ARROW;So;0;ON;;;;;N;RIGHT ARROW OVER LEFT ARROW;;;;
+21C5;UPWARDS ARROW LEFTWARDS OF DOWNWARDS ARROW;So;0;ON;;;;;N;UP ARROW LEFT OF DOWN ARROW;;;;
+21C6;LEFTWARDS ARROW OVER RIGHTWARDS ARROW;So;0;ON;;;;;N;LEFT ARROW OVER RIGHT ARROW;;;;
+21C7;LEFTWARDS PAIRED ARROWS;So;0;ON;;;;;N;LEFT PAIRED ARROWS;;;;
+21C8;UPWARDS PAIRED ARROWS;So;0;ON;;;;;N;UP PAIRED ARROWS;;;;
+21C9;RIGHTWARDS PAIRED ARROWS;So;0;ON;;;;;N;RIGHT PAIRED ARROWS;;;;
+21CA;DOWNWARDS PAIRED ARROWS;So;0;ON;;;;;N;DOWN PAIRED ARROWS;;;;
+21CB;LEFTWARDS HARPOON OVER RIGHTWARDS HARPOON;So;0;ON;;;;;N;LEFT HARPOON OVER RIGHT HARPOON;;;;
+21CC;RIGHTWARDS HARPOON OVER LEFTWARDS HARPOON;So;0;ON;;;;;N;RIGHT HARPOON OVER LEFT HARPOON;;;;
+21CD;LEFTWARDS DOUBLE ARROW WITH STROKE;So;0;ON;21D0 0338;;;;N;LEFT DOUBLE ARROW WITH STROKE;;;;
+21CE;LEFT RIGHT DOUBLE ARROW WITH STROKE;Sm;0;ON;21D4 0338;;;;N;;;;;
+21CF;RIGHTWARDS DOUBLE ARROW WITH STROKE;Sm;0;ON;21D2 0338;;;;N;RIGHT DOUBLE ARROW WITH STROKE;;;;
+21D0;LEFTWARDS DOUBLE ARROW;So;0;ON;;;;;N;LEFT DOUBLE ARROW;;;;
+21D1;UPWARDS DOUBLE ARROW;So;0;ON;;;;;N;UP DOUBLE ARROW;;;;
+21D2;RIGHTWARDS DOUBLE ARROW;Sm;0;ON;;;;;N;RIGHT DOUBLE ARROW;;;;
+21D3;DOWNWARDS DOUBLE ARROW;So;0;ON;;;;;N;DOWN DOUBLE ARROW;;;;
+21D4;LEFT RIGHT DOUBLE ARROW;Sm;0;ON;;;;;N;;;;;
+21D5;UP DOWN DOUBLE ARROW;So;0;ON;;;;;N;;;;;
+21D6;NORTH WEST DOUBLE ARROW;So;0;ON;;;;;N;UPPER LEFT DOUBLE ARROW;;;;
+21D7;NORTH EAST DOUBLE ARROW;So;0;ON;;;;;N;UPPER RIGHT DOUBLE ARROW;;;;
+21D8;SOUTH EAST DOUBLE ARROW;So;0;ON;;;;;N;LOWER RIGHT DOUBLE ARROW;;;;
+21D9;SOUTH WEST DOUBLE ARROW;So;0;ON;;;;;N;LOWER LEFT DOUBLE ARROW;;;;
+21DA;LEFTWARDS TRIPLE ARROW;So;0;ON;;;;;N;LEFT TRIPLE ARROW;;;;
+21DB;RIGHTWARDS TRIPLE ARROW;So;0;ON;;;;;N;RIGHT TRIPLE ARROW;;;;
+21DC;LEFTWARDS SQUIGGLE ARROW;So;0;ON;;;;;N;LEFT SQUIGGLE ARROW;;;;
+21DD;RIGHTWARDS SQUIGGLE ARROW;So;0;ON;;;;;N;RIGHT SQUIGGLE ARROW;;;;
+21DE;UPWARDS ARROW WITH DOUBLE STROKE;So;0;ON;;;;;N;UP ARROW WITH DOUBLE STROKE;;;;
+21DF;DOWNWARDS ARROW WITH DOUBLE STROKE;So;0;ON;;;;;N;DOWN ARROW WITH DOUBLE STROKE;;;;
+21E0;LEFTWARDS DASHED ARROW;So;0;ON;;;;;N;LEFT DASHED ARROW;;;;
+21E1;UPWARDS DASHED ARROW;So;0;ON;;;;;N;UP DASHED ARROW;;;;
+21E2;RIGHTWARDS DASHED ARROW;So;0;ON;;;;;N;RIGHT DASHED ARROW;;;;
+21E3;DOWNWARDS DASHED ARROW;So;0;ON;;;;;N;DOWN DASHED ARROW;;;;
+21E4;LEFTWARDS ARROW TO BAR;So;0;ON;;;;;N;LEFT ARROW TO BAR;;;;
+21E5;RIGHTWARDS ARROW TO BAR;So;0;ON;;;;;N;RIGHT ARROW TO BAR;;;;
+21E6;LEFTWARDS WHITE ARROW;So;0;ON;;;;;N;WHITE LEFT ARROW;;;;
+21E7;UPWARDS WHITE ARROW;So;0;ON;;;;;N;WHITE UP ARROW;;;;
+21E8;RIGHTWARDS WHITE ARROW;So;0;ON;;;;;N;WHITE RIGHT ARROW;;;;
+21E9;DOWNWARDS WHITE ARROW;So;0;ON;;;;;N;WHITE DOWN ARROW;;;;
+21EA;UPWARDS WHITE ARROW FROM BAR;So;0;ON;;;;;N;WHITE UP ARROW FROM BAR;;;;
+21EB;UPWARDS WHITE ARROW ON PEDESTAL;So;0;ON;;;;;N;;;;;
+21EC;UPWARDS WHITE ARROW ON PEDESTAL WITH HORIZONTAL BAR;So;0;ON;;;;;N;;;;;
+21ED;UPWARDS WHITE ARROW ON PEDESTAL WITH VERTICAL BAR;So;0;ON;;;;;N;;;;;
+21EE;UPWARDS WHITE DOUBLE ARROW;So;0;ON;;;;;N;;;;;
+21EF;UPWARDS WHITE DOUBLE ARROW ON PEDESTAL;So;0;ON;;;;;N;;;;;
+21F0;RIGHTWARDS WHITE ARROW FROM WALL;So;0;ON;;;;;N;;;;;
+21F1;NORTH WEST ARROW TO CORNER;So;0;ON;;;;;N;;;;;
+21F2;SOUTH EAST ARROW TO CORNER;So;0;ON;;;;;N;;;;;
+21F3;UP DOWN WHITE ARROW;So;0;ON;;;;;N;;;;;
+21F4;RIGHT ARROW WITH SMALL CIRCLE;Sm;0;ON;;;;;N;;;;;
+21F5;DOWNWARDS ARROW LEFTWARDS OF UPWARDS ARROW;Sm;0;ON;;;;;N;;;;;
+21F6;THREE RIGHTWARDS ARROWS;Sm;0;ON;;;;;N;;;;;
+21F7;LEFTWARDS ARROW WITH VERTICAL STROKE;Sm;0;ON;;;;;N;;;;;
+21F8;RIGHTWARDS ARROW WITH VERTICAL STROKE;Sm;0;ON;;;;;N;;;;;
+21F9;LEFT RIGHT ARROW WITH VERTICAL STROKE;Sm;0;ON;;;;;N;;;;;
+21FA;LEFTWARDS ARROW WITH DOUBLE VERTICAL STROKE;Sm;0;ON;;;;;N;;;;;
+21FB;RIGHTWARDS ARROW WITH DOUBLE VERTICAL STROKE;Sm;0;ON;;;;;N;;;;;
+21FC;LEFT RIGHT ARROW WITH DOUBLE VERTICAL STROKE;Sm;0;ON;;;;;N;;;;;
+21FD;LEFTWARDS OPEN-HEADED ARROW;Sm;0;ON;;;;;N;;;;;
+21FE;RIGHTWARDS OPEN-HEADED ARROW;Sm;0;ON;;;;;N;;;;;
+21FF;LEFT RIGHT OPEN-HEADED ARROW;Sm;0;ON;;;;;N;;;;;
+2200;FOR ALL;Sm;0;ON;;;;;N;;;;;
+2201;COMPLEMENT;Sm;0;ON;;;;;Y;;;;;
+2202;PARTIAL DIFFERENTIAL;Sm;0;ON;;;;;Y;;;;;
+2203;THERE EXISTS;Sm;0;ON;;;;;Y;;;;;
+2204;THERE DOES NOT EXIST;Sm;0;ON;2203 0338;;;;Y;;;;;
+2205;EMPTY SET;Sm;0;ON;;;;;N;;;;;
+2206;INCREMENT;Sm;0;ON;;;;;N;;;;;
+2207;NABLA;Sm;0;ON;;;;;N;;;;;
+2208;ELEMENT OF;Sm;0;ON;;;;;Y;;;;;
+2209;NOT AN ELEMENT OF;Sm;0;ON;2208 0338;;;;Y;;;;;
+220A;SMALL ELEMENT OF;Sm;0;ON;;;;;Y;;;;;
+220B;CONTAINS AS MEMBER;Sm;0;ON;;;;;Y;;;;;
+220C;DOES NOT CONTAIN AS MEMBER;Sm;0;ON;220B 0338;;;;Y;;;;;
+220D;SMALL CONTAINS AS MEMBER;Sm;0;ON;;;;;Y;;;;;
+220E;END OF PROOF;Sm;0;ON;;;;;N;;;;;
+220F;N-ARY PRODUCT;Sm;0;ON;;;;;N;;;;;
+2210;N-ARY COPRODUCT;Sm;0;ON;;;;;N;;;;;
+2211;N-ARY SUMMATION;Sm;0;ON;;;;;Y;;;;;
+2212;MINUS SIGN;Sm;0;ES;;;;;N;;;;;
+2213;MINUS-OR-PLUS SIGN;Sm;0;ET;;;;;N;;;;;
+2214;DOT PLUS;Sm;0;ON;;;;;N;;;;;
+2215;DIVISION SLASH;Sm;0;ON;;;;;Y;;;;;
+2216;SET MINUS;Sm;0;ON;;;;;Y;;;;;
+2217;ASTERISK OPERATOR;Sm;0;ON;;;;;N;;;;;
+2218;RING OPERATOR;Sm;0;ON;;;;;N;;;;;
+2219;BULLET OPERATOR;Sm;0;ON;;;;;N;;;;;
+221A;SQUARE ROOT;Sm;0;ON;;;;;Y;;;;;
+221B;CUBE ROOT;Sm;0;ON;;;;;Y;;;;;
+221C;FOURTH ROOT;Sm;0;ON;;;;;Y;;;;;
+221D;PROPORTIONAL TO;Sm;0;ON;;;;;Y;;;;;
+221E;INFINITY;Sm;0;ON;;;;;N;;;;;
+221F;RIGHT ANGLE;Sm;0;ON;;;;;Y;;;;;
+2220;ANGLE;Sm;0;ON;;;;;Y;;;;;
+2221;MEASURED ANGLE;Sm;0;ON;;;;;Y;;;;;
+2222;SPHERICAL ANGLE;Sm;0;ON;;;;;Y;;;;;
+2223;DIVIDES;Sm;0;ON;;;;;N;;;;;
+2224;DOES NOT DIVIDE;Sm;0;ON;2223 0338;;;;Y;;;;;
+2225;PARALLEL TO;Sm;0;ON;;;;;N;;;;;
+2226;NOT PARALLEL TO;Sm;0;ON;2225 0338;;;;Y;;;;;
+2227;LOGICAL AND;Sm;0;ON;;;;;N;;;;;
+2228;LOGICAL OR;Sm;0;ON;;;;;N;;;;;
+2229;INTERSECTION;Sm;0;ON;;;;;N;;;;;
+222A;UNION;Sm;0;ON;;;;;N;;;;;
+222B;INTEGRAL;Sm;0;ON;;;;;Y;;;;;
+222C;DOUBLE INTEGRAL;Sm;0;ON;<compat> 222B 222B;;;;Y;;;;;
+222D;TRIPLE INTEGRAL;Sm;0;ON;<compat> 222B 222B 222B;;;;Y;;;;;
+222E;CONTOUR INTEGRAL;Sm;0;ON;;;;;Y;;;;;
+222F;SURFACE INTEGRAL;Sm;0;ON;<compat> 222E 222E;;;;Y;;;;;
+2230;VOLUME INTEGRAL;Sm;0;ON;<compat> 222E 222E 222E;;;;Y;;;;;
+2231;CLOCKWISE INTEGRAL;Sm;0;ON;;;;;Y;;;;;
+2232;CLOCKWISE CONTOUR INTEGRAL;Sm;0;ON;;;;;Y;;;;;
+2233;ANTICLOCKWISE CONTOUR INTEGRAL;Sm;0;ON;;;;;Y;;;;;
+2234;THEREFORE;Sm;0;ON;;;;;N;;;;;
+2235;BECAUSE;Sm;0;ON;;;;;N;;;;;
+2236;RATIO;Sm;0;ON;;;;;N;;;;;
+2237;PROPORTION;Sm;0;ON;;;;;N;;;;;
+2238;DOT MINUS;Sm;0;ON;;;;;N;;;;;
+2239;EXCESS;Sm;0;ON;;;;;Y;;;;;
+223A;GEOMETRIC PROPORTION;Sm;0;ON;;;;;N;;;;;
+223B;HOMOTHETIC;Sm;0;ON;;;;;Y;;;;;
+223C;TILDE OPERATOR;Sm;0;ON;;;;;Y;;;;;
+223D;REVERSED TILDE;Sm;0;ON;;;;;Y;;lazy S;;;
+223E;INVERTED LAZY S;Sm;0;ON;;;;;Y;;;;;
+223F;SINE WAVE;Sm;0;ON;;;;;Y;;;;;
+2240;WREATH PRODUCT;Sm;0;ON;;;;;Y;;;;;
+2241;NOT TILDE;Sm;0;ON;223C 0338;;;;Y;;;;;
+2242;MINUS TILDE;Sm;0;ON;;;;;Y;;;;;
+2243;ASYMPTOTICALLY EQUAL TO;Sm;0;ON;;;;;Y;;;;;
+2244;NOT ASYMPTOTICALLY EQUAL TO;Sm;0;ON;2243 0338;;;;Y;;;;;
+2245;APPROXIMATELY EQUAL TO;Sm;0;ON;;;;;Y;;;;;
+2246;APPROXIMATELY BUT NOT ACTUALLY EQUAL TO;Sm;0;ON;;;;;Y;;;;;
+2247;NEITHER APPROXIMATELY NOR ACTUALLY EQUAL TO;Sm;0;ON;2245 0338;;;;Y;;;;;
+2248;ALMOST EQUAL TO;Sm;0;ON;;;;;Y;;;;;
+2249;NOT ALMOST EQUAL TO;Sm;0;ON;2248 0338;;;;Y;;;;;
+224A;ALMOST EQUAL OR EQUAL TO;Sm;0;ON;;;;;Y;;;;;
+224B;TRIPLE TILDE;Sm;0;ON;;;;;Y;;;;;
+224C;ALL EQUAL TO;Sm;0;ON;;;;;Y;;;;;
+224D;EQUIVALENT TO;Sm;0;ON;;;;;N;;;;;
+224E;GEOMETRICALLY EQUIVALENT TO;Sm;0;ON;;;;;N;;;;;
+224F;DIFFERENCE BETWEEN;Sm;0;ON;;;;;N;;;;;
+2250;APPROACHES THE LIMIT;Sm;0;ON;;;;;N;;;;;
+2251;GEOMETRICALLY EQUAL TO;Sm;0;ON;;;;;N;;;;;
+2252;APPROXIMATELY EQUAL TO OR THE IMAGE OF;Sm;0;ON;;;;;Y;;;;;
+2253;IMAGE OF OR APPROXIMATELY EQUAL TO;Sm;0;ON;;;;;Y;;;;;
+2254;COLON EQUALS;Sm;0;ON;;;;;Y;COLON EQUAL;;;;
+2255;EQUALS COLON;Sm;0;ON;;;;;Y;EQUAL COLON;;;;
+2256;RING IN EQUAL TO;Sm;0;ON;;;;;N;;;;;
+2257;RING EQUAL TO;Sm;0;ON;;;;;N;;;;;
+2258;CORRESPONDS TO;Sm;0;ON;;;;;N;;;;;
+2259;ESTIMATES;Sm;0;ON;;;;;N;;;;;
+225A;EQUIANGULAR TO;Sm;0;ON;;;;;N;;;;;
+225B;STAR EQUALS;Sm;0;ON;;;;;N;;;;;
+225C;DELTA EQUAL TO;Sm;0;ON;;;;;N;;;;;
+225D;EQUAL TO BY DEFINITION;Sm;0;ON;;;;;N;;;;;
+225E;MEASURED BY;Sm;0;ON;;;;;N;;;;;
+225F;QUESTIONED EQUAL TO;Sm;0;ON;;;;;Y;;;;;
+2260;NOT EQUAL TO;Sm;0;ON;003D 0338;;;;Y;;;;;
+2261;IDENTICAL TO;Sm;0;ON;;;;;N;;;;;
+2262;NOT IDENTICAL TO;Sm;0;ON;2261 0338;;;;Y;;;;;
+2263;STRICTLY EQUIVALENT TO;Sm;0;ON;;;;;N;;;;;
+2264;LESS-THAN OR EQUAL TO;Sm;0;ON;;;;;Y;LESS THAN OR EQUAL TO;;;;
+2265;GREATER-THAN OR EQUAL TO;Sm;0;ON;;;;;Y;GREATER THAN OR EQUAL TO;;;;
+2266;LESS-THAN OVER EQUAL TO;Sm;0;ON;;;;;Y;LESS THAN OVER EQUAL TO;;;;
+2267;GREATER-THAN OVER EQUAL TO;Sm;0;ON;;;;;Y;GREATER THAN OVER EQUAL TO;;;;
+2268;LESS-THAN BUT NOT EQUAL TO;Sm;0;ON;;;;;Y;LESS THAN BUT NOT EQUAL TO;;;;
+2269;GREATER-THAN BUT NOT EQUAL TO;Sm;0;ON;;;;;Y;GREATER THAN BUT NOT EQUAL TO;;;;
+226A;MUCH LESS-THAN;Sm;0;ON;;;;;Y;MUCH LESS THAN;;;;
+226B;MUCH GREATER-THAN;Sm;0;ON;;;;;Y;MUCH GREATER THAN;;;;
+226C;BETWEEN;Sm;0;ON;;;;;N;;;;;
+226D;NOT EQUIVALENT TO;Sm;0;ON;224D 0338;;;;N;;;;;
+226E;NOT LESS-THAN;Sm;0;ON;003C 0338;;;;Y;NOT LESS THAN;;;;
+226F;NOT GREATER-THAN;Sm;0;ON;003E 0338;;;;Y;NOT GREATER THAN;;;;
+2270;NEITHER LESS-THAN NOR EQUAL TO;Sm;0;ON;2264 0338;;;;Y;NEITHER LESS THAN NOR EQUAL TO;;;;
+2271;NEITHER GREATER-THAN NOR EQUAL TO;Sm;0;ON;2265 0338;;;;Y;NEITHER GREATER THAN NOR EQUAL TO;;;;
+2272;LESS-THAN OR EQUIVALENT TO;Sm;0;ON;;;;;Y;LESS THAN OR EQUIVALENT TO;;;;
+2273;GREATER-THAN OR EQUIVALENT TO;Sm;0;ON;;;;;Y;GREATER THAN OR EQUIVALENT TO;;;;
+2274;NEITHER LESS-THAN NOR EQUIVALENT TO;Sm;0;ON;2272 0338;;;;Y;NEITHER LESS THAN NOR EQUIVALENT TO;;;;
+2275;NEITHER GREATER-THAN NOR EQUIVALENT TO;Sm;0;ON;2273 0338;;;;Y;NEITHER GREATER THAN NOR EQUIVALENT TO;;;;
+2276;LESS-THAN OR GREATER-THAN;Sm;0;ON;;;;;Y;LESS THAN OR GREATER THAN;;;;
+2277;GREATER-THAN OR LESS-THAN;Sm;0;ON;;;;;Y;GREATER THAN OR LESS THAN;;;;
+2278;NEITHER LESS-THAN NOR GREATER-THAN;Sm;0;ON;2276 0338;;;;Y;NEITHER LESS THAN NOR GREATER THAN;;;;
+2279;NEITHER GREATER-THAN NOR LESS-THAN;Sm;0;ON;2277 0338;;;;Y;NEITHER GREATER THAN NOR LESS THAN;;;;
+227A;PRECEDES;Sm;0;ON;;;;;Y;;;;;
+227B;SUCCEEDS;Sm;0;ON;;;;;Y;;;;;
+227C;PRECEDES OR EQUAL TO;Sm;0;ON;;;;;Y;;;;;
+227D;SUCCEEDS OR EQUAL TO;Sm;0;ON;;;;;Y;;;;;
+227E;PRECEDES OR EQUIVALENT TO;Sm;0;ON;;;;;Y;;;;;
+227F;SUCCEEDS OR EQUIVALENT TO;Sm;0;ON;;;;;Y;;;;;
+2280;DOES NOT PRECEDE;Sm;0;ON;227A 0338;;;;Y;;;;;
+2281;DOES NOT SUCCEED;Sm;0;ON;227B 0338;;;;Y;;;;;
+2282;SUBSET OF;Sm;0;ON;;;;;Y;;;;;
+2283;SUPERSET OF;Sm;0;ON;;;;;Y;;;;;
+2284;NOT A SUBSET OF;Sm;0;ON;2282 0338;;;;Y;;;;;
+2285;NOT A SUPERSET OF;Sm;0;ON;2283 0338;;;;Y;;;;;
+2286;SUBSET OF OR EQUAL TO;Sm;0;ON;;;;;Y;;;;;
+2287;SUPERSET OF OR EQUAL TO;Sm;0;ON;;;;;Y;;;;;
+2288;NEITHER A SUBSET OF NOR EQUAL TO;Sm;0;ON;2286 0338;;;;Y;;;;;
+2289;NEITHER A SUPERSET OF NOR EQUAL TO;Sm;0;ON;2287 0338;;;;Y;;;;;
+228A;SUBSET OF WITH NOT EQUAL TO;Sm;0;ON;;;;;Y;SUBSET OF OR NOT EQUAL TO;;;;
+228B;SUPERSET OF WITH NOT EQUAL TO;Sm;0;ON;;;;;Y;SUPERSET OF OR NOT EQUAL TO;;;;
+228C;MULTISET;Sm;0;ON;;;;;Y;;;;;
+228D;MULTISET MULTIPLICATION;Sm;0;ON;;;;;N;;;;;
+228E;MULTISET UNION;Sm;0;ON;;;;;N;;;;;
+228F;SQUARE IMAGE OF;Sm;0;ON;;;;;Y;;;;;
+2290;SQUARE ORIGINAL OF;Sm;0;ON;;;;;Y;;;;;
+2291;SQUARE IMAGE OF OR EQUAL TO;Sm;0;ON;;;;;Y;;;;;
+2292;SQUARE ORIGINAL OF OR EQUAL TO;Sm;0;ON;;;;;Y;;;;;
+2293;SQUARE CAP;Sm;0;ON;;;;;N;;;;;
+2294;SQUARE CUP;Sm;0;ON;;;;;N;;;;;
+2295;CIRCLED PLUS;Sm;0;ON;;;;;N;;;;;
+2296;CIRCLED MINUS;Sm;0;ON;;;;;N;;;;;
+2297;CIRCLED TIMES;Sm;0;ON;;;;;N;;;;;
+2298;CIRCLED DIVISION SLASH;Sm;0;ON;;;;;Y;;;;;
+2299;CIRCLED DOT OPERATOR;Sm;0;ON;;;;;N;;;;;
+229A;CIRCLED RING OPERATOR;Sm;0;ON;;;;;N;;;;;
+229B;CIRCLED ASTERISK OPERATOR;Sm;0;ON;;;;;N;;;;;
+229C;CIRCLED EQUALS;Sm;0;ON;;;;;N;;;;;
+229D;CIRCLED DASH;Sm;0;ON;;;;;N;;;;;
+229E;SQUARED PLUS;Sm;0;ON;;;;;N;;;;;
+229F;SQUARED MINUS;Sm;0;ON;;;;;N;;;;;
+22A0;SQUARED TIMES;Sm;0;ON;;;;;N;;;;;
+22A1;SQUARED DOT OPERATOR;Sm;0;ON;;;;;N;;;;;
+22A2;RIGHT TACK;Sm;0;ON;;;;;Y;;;;;
+22A3;LEFT TACK;Sm;0;ON;;;;;Y;;;;;
+22A4;DOWN TACK;Sm;0;ON;;;;;N;;;;;
+22A5;UP TACK;Sm;0;ON;;;;;N;;;;;
+22A6;ASSERTION;Sm;0;ON;;;;;Y;;;;;
+22A7;MODELS;Sm;0;ON;;;;;Y;;;;;
+22A8;TRUE;Sm;0;ON;;;;;Y;;;;;
+22A9;FORCES;Sm;0;ON;;;;;Y;;;;;
+22AA;TRIPLE VERTICAL BAR RIGHT TURNSTILE;Sm;0;ON;;;;;Y;;;;;
+22AB;DOUBLE VERTICAL BAR DOUBLE RIGHT TURNSTILE;Sm;0;ON;;;;;Y;;;;;
+22AC;DOES NOT PROVE;Sm;0;ON;22A2 0338;;;;Y;;;;;
+22AD;NOT TRUE;Sm;0;ON;22A8 0338;;;;Y;;;;;
+22AE;DOES NOT FORCE;Sm;0;ON;22A9 0338;;;;Y;;;;;
+22AF;NEGATED DOUBLE VERTICAL BAR DOUBLE RIGHT TURNSTILE;Sm;0;ON;22AB 0338;;;;Y;;;;;
+22B0;PRECEDES UNDER RELATION;Sm;0;ON;;;;;Y;;;;;
+22B1;SUCCEEDS UNDER RELATION;Sm;0;ON;;;;;Y;;;;;
+22B2;NORMAL SUBGROUP OF;Sm;0;ON;;;;;Y;;;;;
+22B3;CONTAINS AS NORMAL SUBGROUP;Sm;0;ON;;;;;Y;;;;;
+22B4;NORMAL SUBGROUP OF OR EQUAL TO;Sm;0;ON;;;;;Y;;;;;
+22B5;CONTAINS AS NORMAL SUBGROUP OR EQUAL TO;Sm;0;ON;;;;;Y;;;;;
+22B6;ORIGINAL OF;Sm;0;ON;;;;;Y;;;;;
+22B7;IMAGE OF;Sm;0;ON;;;;;Y;;;;;
+22B8;MULTIMAP;Sm;0;ON;;;;;Y;;;;;
+22B9;HERMITIAN CONJUGATE MATRIX;Sm;0;ON;;;;;N;;;;;
+22BA;INTERCALATE;Sm;0;ON;;;;;N;;;;;
+22BB;XOR;Sm;0;ON;;;;;N;;;;;
+22BC;NAND;Sm;0;ON;;;;;N;;;;;
+22BD;NOR;Sm;0;ON;;;;;N;;;;;
+22BE;RIGHT ANGLE WITH ARC;Sm;0;ON;;;;;Y;;;;;
+22BF;RIGHT TRIANGLE;Sm;0;ON;;;;;Y;;;;;
+22C0;N-ARY LOGICAL AND;Sm;0;ON;;;;;N;;;;;
+22C1;N-ARY LOGICAL OR;Sm;0;ON;;;;;N;;;;;
+22C2;N-ARY INTERSECTION;Sm;0;ON;;;;;N;;;;;
+22C3;N-ARY UNION;Sm;0;ON;;;;;N;;;;;
+22C4;DIAMOND OPERATOR;Sm;0;ON;;;;;N;;;;;
+22C5;DOT OPERATOR;Sm;0;ON;;;;;N;;;;;
+22C6;STAR OPERATOR;Sm;0;ON;;;;;N;;;;;
+22C7;DIVISION TIMES;Sm;0;ON;;;;;N;;;;;
+22C8;BOWTIE;Sm;0;ON;;;;;N;;;;;
+22C9;LEFT NORMAL FACTOR SEMIDIRECT PRODUCT;Sm;0;ON;;;;;Y;;;;;
+22CA;RIGHT NORMAL FACTOR SEMIDIRECT PRODUCT;Sm;0;ON;;;;;Y;;;;;
+22CB;LEFT SEMIDIRECT PRODUCT;Sm;0;ON;;;;;Y;;;;;
+22CC;RIGHT SEMIDIRECT PRODUCT;Sm;0;ON;;;;;Y;;;;;
+22CD;REVERSED TILDE EQUALS;Sm;0;ON;;;;;Y;;;;;
+22CE;CURLY LOGICAL OR;Sm;0;ON;;;;;N;;;;;
+22CF;CURLY LOGICAL AND;Sm;0;ON;;;;;N;;;;;
+22D0;DOUBLE SUBSET;Sm;0;ON;;;;;Y;;;;;
+22D1;DOUBLE SUPERSET;Sm;0;ON;;;;;Y;;;;;
+22D2;DOUBLE INTERSECTION;Sm;0;ON;;;;;N;;;;;
+22D3;DOUBLE UNION;Sm;0;ON;;;;;N;;;;;
+22D4;PITCHFORK;Sm;0;ON;;;;;N;;;;;
+22D5;EQUAL AND PARALLEL TO;Sm;0;ON;;;;;N;;;;;
+22D6;LESS-THAN WITH DOT;Sm;0;ON;;;;;Y;LESS THAN WITH DOT;;;;
+22D7;GREATER-THAN WITH DOT;Sm;0;ON;;;;;Y;GREATER THAN WITH DOT;;;;
+22D8;VERY MUCH LESS-THAN;Sm;0;ON;;;;;Y;VERY MUCH LESS THAN;;;;
+22D9;VERY MUCH GREATER-THAN;Sm;0;ON;;;;;Y;VERY MUCH GREATER THAN;;;;
+22DA;LESS-THAN EQUAL TO OR GREATER-THAN;Sm;0;ON;;;;;Y;LESS THAN EQUAL TO OR GREATER THAN;;;;
+22DB;GREATER-THAN EQUAL TO OR LESS-THAN;Sm;0;ON;;;;;Y;GREATER THAN EQUAL TO OR LESS THAN;;;;
+22DC;EQUAL TO OR LESS-THAN;Sm;0;ON;;;;;Y;EQUAL TO OR LESS THAN;;;;
+22DD;EQUAL TO OR GREATER-THAN;Sm;0;ON;;;;;Y;EQUAL TO OR GREATER THAN;;;;
+22DE;EQUAL TO OR PRECEDES;Sm;0;ON;;;;;Y;;;;;
+22DF;EQUAL TO OR SUCCEEDS;Sm;0;ON;;;;;Y;;;;;
+22E0;DOES NOT PRECEDE OR EQUAL;Sm;0;ON;227C 0338;;;;Y;;;;;
+22E1;DOES NOT SUCCEED OR EQUAL;Sm;0;ON;227D 0338;;;;Y;;;;;
+22E2;NOT SQUARE IMAGE OF OR EQUAL TO;Sm;0;ON;2291 0338;;;;Y;;;;;
+22E3;NOT SQUARE ORIGINAL OF OR EQUAL TO;Sm;0;ON;2292 0338;;;;Y;;;;;
+22E4;SQUARE IMAGE OF OR NOT EQUAL TO;Sm;0;ON;;;;;Y;;;;;
+22E5;SQUARE ORIGINAL OF OR NOT EQUAL TO;Sm;0;ON;;;;;Y;;;;;
+22E6;LESS-THAN BUT NOT EQUIVALENT TO;Sm;0;ON;;;;;Y;LESS THAN BUT NOT EQUIVALENT TO;;;;
+22E7;GREATER-THAN BUT NOT EQUIVALENT TO;Sm;0;ON;;;;;Y;GREATER THAN BUT NOT EQUIVALENT TO;;;;
+22E8;PRECEDES BUT NOT EQUIVALENT TO;Sm;0;ON;;;;;Y;;;;;
+22E9;SUCCEEDS BUT NOT EQUIVALENT TO;Sm;0;ON;;;;;Y;;;;;
+22EA;NOT NORMAL SUBGROUP OF;Sm;0;ON;22B2 0338;;;;Y;;;;;
+22EB;DOES NOT CONTAIN AS NORMAL SUBGROUP;Sm;0;ON;22B3 0338;;;;Y;;;;;
+22EC;NOT NORMAL SUBGROUP OF OR EQUAL TO;Sm;0;ON;22B4 0338;;;;Y;;;;;
+22ED;DOES NOT CONTAIN AS NORMAL SUBGROUP OR EQUAL;Sm;0;ON;22B5 0338;;;;Y;;;;;
+22EE;VERTICAL ELLIPSIS;Sm;0;ON;;;;;N;;;;;
+22EF;MIDLINE HORIZONTAL ELLIPSIS;Sm;0;ON;;;;;N;;;;;
+22F0;UP RIGHT DIAGONAL ELLIPSIS;Sm;0;ON;;;;;Y;;;;;
+22F1;DOWN RIGHT DIAGONAL ELLIPSIS;Sm;0;ON;;;;;Y;;;;;
+22F2;ELEMENT OF WITH LONG HORIZONTAL STROKE;Sm;0;ON;;;;;Y;;;;;
+22F3;ELEMENT OF WITH VERTICAL BAR AT END OF HORIZONTAL STROKE;Sm;0;ON;;;;;Y;;;;;
+22F4;SMALL ELEMENT OF WITH VERTICAL BAR AT END OF HORIZONTAL STROKE;Sm;0;ON;;;;;Y;;;;;
+22F5;ELEMENT OF WITH DOT ABOVE;Sm;0;ON;;;;;Y;;;;;
+22F6;ELEMENT OF WITH OVERBAR;Sm;0;ON;;;;;Y;;;;;
+22F7;SMALL ELEMENT OF WITH OVERBAR;Sm;0;ON;;;;;Y;;;;;
+22F8;ELEMENT OF WITH UNDERBAR;Sm;0;ON;;;;;Y;;;;;
+22F9;ELEMENT OF WITH TWO HORIZONTAL STROKES;Sm;0;ON;;;;;Y;;;;;
+22FA;CONTAINS WITH LONG HORIZONTAL STROKE;Sm;0;ON;;;;;Y;;;;;
+22FB;CONTAINS WITH VERTICAL BAR AT END OF HORIZONTAL STROKE;Sm;0;ON;;;;;Y;;;;;
+22FC;SMALL CONTAINS WITH VERTICAL BAR AT END OF HORIZONTAL STROKE;Sm;0;ON;;;;;Y;;;;;
+22FD;CONTAINS WITH OVERBAR;Sm;0;ON;;;;;Y;;;;;
+22FE;SMALL CONTAINS WITH OVERBAR;Sm;0;ON;;;;;Y;;;;;
+22FF;Z NOTATION BAG MEMBERSHIP;Sm;0;ON;;;;;Y;;;;;
+2300;DIAMETER SIGN;So;0;ON;;;;;N;;;;;
+2301;ELECTRIC ARROW;So;0;ON;;;;;N;;;;;
+2302;HOUSE;So;0;ON;;;;;N;;;;;
+2303;UP ARROWHEAD;So;0;ON;;;;;N;;;;;
+2304;DOWN ARROWHEAD;So;0;ON;;;;;N;;;;;
+2305;PROJECTIVE;So;0;ON;;;;;N;;;;;
+2306;PERSPECTIVE;So;0;ON;;;;;N;;;;;
+2307;WAVY LINE;So;0;ON;;;;;N;;;;;
+2308;LEFT CEILING;Sm;0;ON;;;;;Y;;;;;
+2309;RIGHT CEILING;Sm;0;ON;;;;;Y;;;;;
+230A;LEFT FLOOR;Sm;0;ON;;;;;Y;;;;;
+230B;RIGHT FLOOR;Sm;0;ON;;;;;Y;;;;;
+230C;BOTTOM RIGHT CROP;So;0;ON;;;;;N;;;;;
+230D;BOTTOM LEFT CROP;So;0;ON;;;;;N;;;;;
+230E;TOP RIGHT CROP;So;0;ON;;;;;N;;;;;
+230F;TOP LEFT CROP;So;0;ON;;;;;N;;;;;
+2310;REVERSED NOT SIGN;So;0;ON;;;;;N;;;;;
+2311;SQUARE LOZENGE;So;0;ON;;;;;N;;;;;
+2312;ARC;So;0;ON;;;;;N;;;;;
+2313;SEGMENT;So;0;ON;;;;;N;;;;;
+2314;SECTOR;So;0;ON;;;;;N;;;;;
+2315;TELEPHONE RECORDER;So;0;ON;;;;;N;;;;;
+2316;POSITION INDICATOR;So;0;ON;;;;;N;;;;;
+2317;VIEWDATA SQUARE;So;0;ON;;;;;N;;;;;
+2318;PLACE OF INTEREST SIGN;So;0;ON;;;;;N;COMMAND KEY;;;;
+2319;TURNED NOT SIGN;So;0;ON;;;;;N;;;;;
+231A;WATCH;So;0;ON;;;;;N;;;;;
+231B;HOURGLASS;So;0;ON;;;;;N;;;;;
+231C;TOP LEFT CORNER;So;0;ON;;;;;N;;;;;
+231D;TOP RIGHT CORNER;So;0;ON;;;;;N;;;;;
+231E;BOTTOM LEFT CORNER;So;0;ON;;;;;N;;;;;
+231F;BOTTOM RIGHT CORNER;So;0;ON;;;;;N;;;;;
+2320;TOP HALF INTEGRAL;Sm;0;ON;;;;;Y;;;;;
+2321;BOTTOM HALF INTEGRAL;Sm;0;ON;;;;;Y;;;;;
+2322;FROWN;So;0;ON;;;;;N;;;;;
+2323;SMILE;So;0;ON;;;;;N;;;;;
+2324;UP ARROWHEAD BETWEEN TWO HORIZONTAL BARS;So;0;ON;;;;;N;ENTER KEY;;;;
+2325;OPTION KEY;So;0;ON;;;;;N;;;;;
+2326;ERASE TO THE RIGHT;So;0;ON;;;;;N;DELETE TO THE RIGHT KEY;;;;
+2327;X IN A RECTANGLE BOX;So;0;ON;;;;;N;CLEAR KEY;;;;
+2328;KEYBOARD;So;0;ON;;;;;N;;;;;
+2329;LEFT-POINTING ANGLE BRACKET;Ps;0;ON;3008;;;;Y;BRA;;;;
+232A;RIGHT-POINTING ANGLE BRACKET;Pe;0;ON;3009;;;;Y;KET;;;;
+232B;ERASE TO THE LEFT;So;0;ON;;;;;N;DELETE TO THE LEFT KEY;;;;
+232C;BENZENE RING;So;0;ON;;;;;N;;;;;
+232D;CYLINDRICITY;So;0;ON;;;;;N;;;;;
+232E;ALL AROUND-PROFILE;So;0;ON;;;;;N;;;;;
+232F;SYMMETRY;So;0;ON;;;;;N;;;;;
+2330;TOTAL RUNOUT;So;0;ON;;;;;N;;;;;
+2331;DIMENSION ORIGIN;So;0;ON;;;;;N;;;;;
+2332;CONICAL TAPER;So;0;ON;;;;;N;;;;;
+2333;SLOPE;So;0;ON;;;;;N;;;;;
+2334;COUNTERBORE;So;0;ON;;;;;N;;;;;
+2335;COUNTERSINK;So;0;ON;;;;;N;;;;;
+2336;APL FUNCTIONAL SYMBOL I-BEAM;So;0;L;;;;;N;;;;;
+2337;APL FUNCTIONAL SYMBOL SQUISH QUAD;So;0;L;;;;;N;;;;;
+2338;APL FUNCTIONAL SYMBOL QUAD EQUAL;So;0;L;;;;;N;;;;;
+2339;APL FUNCTIONAL SYMBOL QUAD DIVIDE;So;0;L;;;;;N;;;;;
+233A;APL FUNCTIONAL SYMBOL QUAD DIAMOND;So;0;L;;;;;N;;;;;
+233B;APL FUNCTIONAL SYMBOL QUAD JOT;So;0;L;;;;;N;;;;;
+233C;APL FUNCTIONAL SYMBOL QUAD CIRCLE;So;0;L;;;;;N;;;;;
+233D;APL FUNCTIONAL SYMBOL CIRCLE STILE;So;0;L;;;;;N;;;;;
+233E;APL FUNCTIONAL SYMBOL CIRCLE JOT;So;0;L;;;;;N;;;;;
+233F;APL FUNCTIONAL SYMBOL SLASH BAR;So;0;L;;;;;N;;;;;
+2340;APL FUNCTIONAL SYMBOL BACKSLASH BAR;So;0;L;;;;;N;;;;;
+2341;APL FUNCTIONAL SYMBOL QUAD SLASH;So;0;L;;;;;N;;;;;
+2342;APL FUNCTIONAL SYMBOL QUAD BACKSLASH;So;0;L;;;;;N;;;;;
+2343;APL FUNCTIONAL SYMBOL QUAD LESS-THAN;So;0;L;;;;;N;;;;;
+2344;APL FUNCTIONAL SYMBOL QUAD GREATER-THAN;So;0;L;;;;;N;;;;;
+2345;APL FUNCTIONAL SYMBOL LEFTWARDS VANE;So;0;L;;;;;N;;;;;
+2346;APL FUNCTIONAL SYMBOL RIGHTWARDS VANE;So;0;L;;;;;N;;;;;
+2347;APL FUNCTIONAL SYMBOL QUAD LEFTWARDS ARROW;So;0;L;;;;;N;;;;;
+2348;APL FUNCTIONAL SYMBOL QUAD RIGHTWARDS ARROW;So;0;L;;;;;N;;;;;
+2349;APL FUNCTIONAL SYMBOL CIRCLE BACKSLASH;So;0;L;;;;;N;;;;;
+234A;APL FUNCTIONAL SYMBOL DOWN TACK UNDERBAR;So;0;L;;;;;N;;*;;;
+234B;APL FUNCTIONAL SYMBOL DELTA STILE;So;0;L;;;;;N;;;;;
+234C;APL FUNCTIONAL SYMBOL QUAD DOWN CARET;So;0;L;;;;;N;;;;;
+234D;APL FUNCTIONAL SYMBOL QUAD DELTA;So;0;L;;;;;N;;;;;
+234E;APL FUNCTIONAL SYMBOL DOWN TACK JOT;So;0;L;;;;;N;;*;;;
+234F;APL FUNCTIONAL SYMBOL UPWARDS VANE;So;0;L;;;;;N;;;;;
+2350;APL FUNCTIONAL SYMBOL QUAD UPWARDS ARROW;So;0;L;;;;;N;;;;;
+2351;APL FUNCTIONAL SYMBOL UP TACK OVERBAR;So;0;L;;;;;N;;*;;;
+2352;APL FUNCTIONAL SYMBOL DEL STILE;So;0;L;;;;;N;;;;;
+2353;APL FUNCTIONAL SYMBOL QUAD UP CARET;So;0;L;;;;;N;;;;;
+2354;APL FUNCTIONAL SYMBOL QUAD DEL;So;0;L;;;;;N;;;;;
+2355;APL FUNCTIONAL SYMBOL UP TACK JOT;So;0;L;;;;;N;;*;;;
+2356;APL FUNCTIONAL SYMBOL DOWNWARDS VANE;So;0;L;;;;;N;;;;;
+2357;APL FUNCTIONAL SYMBOL QUAD DOWNWARDS ARROW;So;0;L;;;;;N;;;;;
+2358;APL FUNCTIONAL SYMBOL QUOTE UNDERBAR;So;0;L;;;;;N;;;;;
+2359;APL FUNCTIONAL SYMBOL DELTA UNDERBAR;So;0;L;;;;;N;;;;;
+235A;APL FUNCTIONAL SYMBOL DIAMOND UNDERBAR;So;0;L;;;;;N;;;;;
+235B;APL FUNCTIONAL SYMBOL JOT UNDERBAR;So;0;L;;;;;N;;;;;
+235C;APL FUNCTIONAL SYMBOL CIRCLE UNDERBAR;So;0;L;;;;;N;;;;;
+235D;APL FUNCTIONAL SYMBOL UP SHOE JOT;So;0;L;;;;;N;;;;;
+235E;APL FUNCTIONAL SYMBOL QUOTE QUAD;So;0;L;;;;;N;;;;;
+235F;APL FUNCTIONAL SYMBOL CIRCLE STAR;So;0;L;;;;;N;;;;;
+2360;APL FUNCTIONAL SYMBOL QUAD COLON;So;0;L;;;;;N;;;;;
+2361;APL FUNCTIONAL SYMBOL UP TACK DIAERESIS;So;0;L;;;;;N;;*;;;
+2362;APL FUNCTIONAL SYMBOL DEL DIAERESIS;So;0;L;;;;;N;;;;;
+2363;APL FUNCTIONAL SYMBOL STAR DIAERESIS;So;0;L;;;;;N;;;;;
+2364;APL FUNCTIONAL SYMBOL JOT DIAERESIS;So;0;L;;;;;N;;;;;
+2365;APL FUNCTIONAL SYMBOL CIRCLE DIAERESIS;So;0;L;;;;;N;;;;;
+2366;APL FUNCTIONAL SYMBOL DOWN SHOE STILE;So;0;L;;;;;N;;;;;
+2367;APL FUNCTIONAL SYMBOL LEFT SHOE STILE;So;0;L;;;;;N;;;;;
+2368;APL FUNCTIONAL SYMBOL TILDE DIAERESIS;So;0;L;;;;;N;;;;;
+2369;APL FUNCTIONAL SYMBOL GREATER-THAN DIAERESIS;So;0;L;;;;;N;;;;;
+236A;APL FUNCTIONAL SYMBOL COMMA BAR;So;0;L;;;;;N;;;;;
+236B;APL FUNCTIONAL SYMBOL DEL TILDE;So;0;L;;;;;N;;;;;
+236C;APL FUNCTIONAL SYMBOL ZILDE;So;0;L;;;;;N;;;;;
+236D;APL FUNCTIONAL SYMBOL STILE TILDE;So;0;L;;;;;N;;;;;
+236E;APL FUNCTIONAL SYMBOL SEMICOLON UNDERBAR;So;0;L;;;;;N;;;;;
+236F;APL FUNCTIONAL SYMBOL QUAD NOT EQUAL;So;0;L;;;;;N;;;;;
+2370;APL FUNCTIONAL SYMBOL QUAD QUESTION;So;0;L;;;;;N;;;;;
+2371;APL FUNCTIONAL SYMBOL DOWN CARET TILDE;So;0;L;;;;;N;;;;;
+2372;APL FUNCTIONAL SYMBOL UP CARET TILDE;So;0;L;;;;;N;;;;;
+2373;APL FUNCTIONAL SYMBOL IOTA;So;0;L;;;;;N;;;;;
+2374;APL FUNCTIONAL SYMBOL RHO;So;0;L;;;;;N;;;;;
+2375;APL FUNCTIONAL SYMBOL OMEGA;So;0;L;;;;;N;;;;;
+2376;APL FUNCTIONAL SYMBOL ALPHA UNDERBAR;So;0;L;;;;;N;;;;;
+2377;APL FUNCTIONAL SYMBOL EPSILON UNDERBAR;So;0;L;;;;;N;;;;;
+2378;APL FUNCTIONAL SYMBOL IOTA UNDERBAR;So;0;L;;;;;N;;;;;
+2379;APL FUNCTIONAL SYMBOL OMEGA UNDERBAR;So;0;L;;;;;N;;;;;
+237A;APL FUNCTIONAL SYMBOL ALPHA;So;0;L;;;;;N;;;;;
+237B;NOT CHECK MARK;So;0;ON;;;;;N;;;;;
+237C;RIGHT ANGLE WITH DOWNWARDS ZIGZAG ARROW;Sm;0;ON;;;;;N;;;;;
+237D;SHOULDERED OPEN BOX;So;0;ON;;;;;N;;;;;
+237E;BELL SYMBOL;So;0;ON;;;;;N;;;;;
+237F;VERTICAL LINE WITH MIDDLE DOT;So;0;ON;;;;;N;;;;;
+2380;INSERTION SYMBOL;So;0;ON;;;;;N;;;;;
+2381;CONTINUOUS UNDERLINE SYMBOL;So;0;ON;;;;;N;;;;;
+2382;DISCONTINUOUS UNDERLINE SYMBOL;So;0;ON;;;;;N;;;;;
+2383;EMPHASIS SYMBOL;So;0;ON;;;;;N;;;;;
+2384;COMPOSITION SYMBOL;So;0;ON;;;;;N;;;;;
+2385;WHITE SQUARE WITH CENTRE VERTICAL LINE;So;0;ON;;;;;N;;;;;
+2386;ENTER SYMBOL;So;0;ON;;;;;N;;;;;
+2387;ALTERNATIVE KEY SYMBOL;So;0;ON;;;;;N;;;;;
+2388;HELM SYMBOL;So;0;ON;;;;;N;;;;;
+2389;CIRCLED HORIZONTAL BAR WITH NOTCH;So;0;ON;;;;;N;;pause;;;
+238A;CIRCLED TRIANGLE DOWN;So;0;ON;;;;;N;;break;;;
+238B;BROKEN CIRCLE WITH NORTHWEST ARROW;So;0;ON;;;;;N;;escape;;;
+238C;UNDO SYMBOL;So;0;ON;;;;;N;;;;;
+238D;MONOSTABLE SYMBOL;So;0;ON;;;;;N;;;;;
+238E;HYSTERESIS SYMBOL;So;0;ON;;;;;N;;;;;
+238F;OPEN-CIRCUIT-OUTPUT H-TYPE SYMBOL;So;0;ON;;;;;N;;;;;
+2390;OPEN-CIRCUIT-OUTPUT L-TYPE SYMBOL;So;0;ON;;;;;N;;;;;
+2391;PASSIVE-PULL-DOWN-OUTPUT SYMBOL;So;0;ON;;;;;N;;;;;
+2392;PASSIVE-PULL-UP-OUTPUT SYMBOL;So;0;ON;;;;;N;;;;;
+2393;DIRECT CURRENT SYMBOL FORM TWO;So;0;ON;;;;;N;;;;;
+2394;SOFTWARE-FUNCTION SYMBOL;So;0;ON;;;;;N;;;;;
+2395;APL FUNCTIONAL SYMBOL QUAD;So;0;L;;;;;N;;;;;
+2396;DECIMAL SEPARATOR KEY SYMBOL;So;0;ON;;;;;N;;;;;
+2397;PREVIOUS PAGE;So;0;ON;;;;;N;;;;;
+2398;NEXT PAGE;So;0;ON;;;;;N;;;;;
+2399;PRINT SCREEN SYMBOL;So;0;ON;;;;;N;;;;;
+239A;CLEAR SCREEN SYMBOL;So;0;ON;;;;;N;;;;;
+239B;LEFT PARENTHESIS UPPER HOOK;Sm;0;ON;;;;;N;;;;;
+239C;LEFT PARENTHESIS EXTENSION;Sm;0;ON;;;;;N;;;;;
+239D;LEFT PARENTHESIS LOWER HOOK;Sm;0;ON;;;;;N;;;;;
+239E;RIGHT PARENTHESIS UPPER HOOK;Sm;0;ON;;;;;N;;;;;
+239F;RIGHT PARENTHESIS EXTENSION;Sm;0;ON;;;;;N;;;;;
+23A0;RIGHT PARENTHESIS LOWER HOOK;Sm;0;ON;;;;;N;;;;;
+23A1;LEFT SQUARE BRACKET UPPER CORNER;Sm;0;ON;;;;;N;;;;;
+23A2;LEFT SQUARE BRACKET EXTENSION;Sm;0;ON;;;;;N;;;;;
+23A3;LEFT SQUARE BRACKET LOWER CORNER;Sm;0;ON;;;;;N;;;;;
+23A4;RIGHT SQUARE BRACKET UPPER CORNER;Sm;0;ON;;;;;N;;;;;
+23A5;RIGHT SQUARE BRACKET EXTENSION;Sm;0;ON;;;;;N;;;;;
+23A6;RIGHT SQUARE BRACKET LOWER CORNER;Sm;0;ON;;;;;N;;;;;
+23A7;LEFT CURLY BRACKET UPPER HOOK;Sm;0;ON;;;;;N;;;;;
+23A8;LEFT CURLY BRACKET MIDDLE PIECE;Sm;0;ON;;;;;N;;;;;
+23A9;LEFT CURLY BRACKET LOWER HOOK;Sm;0;ON;;;;;N;;;;;
+23AA;CURLY BRACKET EXTENSION;Sm;0;ON;;;;;N;;;;;
+23AB;RIGHT CURLY BRACKET UPPER HOOK;Sm;0;ON;;;;;N;;;;;
+23AC;RIGHT CURLY BRACKET MIDDLE PIECE;Sm;0;ON;;;;;N;;;;;
+23AD;RIGHT CURLY BRACKET LOWER HOOK;Sm;0;ON;;;;;N;;;;;
+23AE;INTEGRAL EXTENSION;Sm;0;ON;;;;;N;;;;;
+23AF;HORIZONTAL LINE EXTENSION;Sm;0;ON;;;;;N;;;;;
+23B0;UPPER LEFT OR LOWER RIGHT CURLY BRACKET SECTION;Sm;0;ON;;;;;N;;;;;
+23B1;UPPER RIGHT OR LOWER LEFT CURLY BRACKET SECTION;Sm;0;ON;;;;;N;;;;;
+23B2;SUMMATION TOP;Sm;0;ON;;;;;N;;;;;
+23B3;SUMMATION BOTTOM;Sm;0;ON;;;;;N;;;;;
+23B4;TOP SQUARE BRACKET;Ps;0;ON;;;;;N;;;;;
+23B5;BOTTOM SQUARE BRACKET;Pe;0;ON;;;;;N;;;;;
+23B6;BOTTOM SQUARE BRACKET OVER TOP SQUARE BRACKET;Po;0;ON;;;;;N;;;;;
+23B7;RADICAL SYMBOL BOTTOM;So;0;ON;;;;;N;;;;;
+23B8;LEFT VERTICAL BOX LINE;So;0;ON;;;;;N;;;;;
+23B9;RIGHT VERTICAL BOX LINE;So;0;ON;;;;;N;;;;;
+23BA;HORIZONTAL SCAN LINE-1;So;0;ON;;;;;N;;;;;
+23BB;HORIZONTAL SCAN LINE-3;So;0;ON;;;;;N;;;;;
+23BC;HORIZONTAL SCAN LINE-7;So;0;ON;;;;;N;;;;;
+23BD;HORIZONTAL SCAN LINE-9;So;0;ON;;;;;N;;;;;
+23BE;DENTISTRY SYMBOL LIGHT VERTICAL AND TOP RIGHT;So;0;ON;;;;;N;;;;;
+23BF;DENTISTRY SYMBOL LIGHT VERTICAL AND BOTTOM RIGHT;So;0;ON;;;;;N;;;;;
+23C0;DENTISTRY SYMBOL LIGHT VERTICAL WITH CIRCLE;So;0;ON;;;;;N;;;;;
+23C1;DENTISTRY SYMBOL LIGHT DOWN AND HORIZONTAL WITH CIRCLE;So;0;ON;;;;;N;;;;;
+23C2;DENTISTRY SYMBOL LIGHT UP AND HORIZONTAL WITH CIRCLE;So;0;ON;;;;;N;;;;;
+23C3;DENTISTRY SYMBOL LIGHT VERTICAL WITH TRIANGLE;So;0;ON;;;;;N;;;;;
+23C4;DENTISTRY SYMBOL LIGHT DOWN AND HORIZONTAL WITH TRIANGLE;So;0;ON;;;;;N;;;;;
+23C5;DENTISTRY SYMBOL LIGHT UP AND HORIZONTAL WITH TRIANGLE;So;0;ON;;;;;N;;;;;
+23C6;DENTISTRY SYMBOL LIGHT VERTICAL AND WAVE;So;0;ON;;;;;N;;;;;
+23C7;DENTISTRY SYMBOL LIGHT DOWN AND HORIZONTAL WITH WAVE;So;0;ON;;;;;N;;;;;
+23C8;DENTISTRY SYMBOL LIGHT UP AND HORIZONTAL WITH WAVE;So;0;ON;;;;;N;;;;;
+23C9;DENTISTRY SYMBOL LIGHT DOWN AND HORIZONTAL;So;0;ON;;;;;N;;;;;
+23CA;DENTISTRY SYMBOL LIGHT UP AND HORIZONTAL;So;0;ON;;;;;N;;;;;
+23CB;DENTISTRY SYMBOL LIGHT VERTICAL AND TOP LEFT;So;0;ON;;;;;N;;;;;
+23CC;DENTISTRY SYMBOL LIGHT VERTICAL AND BOTTOM LEFT;So;0;ON;;;;;N;;;;;
+23CD;SQUARE FOOT;So;0;ON;;;;;N;;;;;
+23CE;RETURN SYMBOL;So;0;ON;;;;;N;;;;;
+23CF;EJECT SYMBOL;So;0;ON;;;;;N;;;;;
+23D0;VERTICAL LINE EXTENSION;So;0;ON;;;;;N;;;;;
+23D1;METRICAL BREVE;So;0;ON;;;;;N;;;;;
+23D2;METRICAL LONG OVER SHORT;So;0;ON;;;;;N;;;;;
+23D3;METRICAL SHORT OVER LONG;So;0;ON;;;;;N;;;;;
+23D4;METRICAL LONG OVER TWO SHORTS;So;0;ON;;;;;N;;;;;
+23D5;METRICAL TWO SHORTS OVER LONG;So;0;ON;;;;;N;;;;;
+23D6;METRICAL TWO SHORTS JOINED;So;0;ON;;;;;N;;;;;
+23D7;METRICAL TRISEME;So;0;ON;;;;;N;;;;;
+23D8;METRICAL TETRASEME;So;0;ON;;;;;N;;;;;
+23D9;METRICAL PENTASEME;So;0;ON;;;;;N;;;;;
+23DA;EARTH GROUND;So;0;ON;;;;;N;;;;;
+23DB;FUSE;So;0;ON;;;;;N;;;;;
+2400;SYMBOL FOR NULL;So;0;ON;;;;;N;GRAPHIC FOR NULL;;;;
+2401;SYMBOL FOR START OF HEADING;So;0;ON;;;;;N;GRAPHIC FOR START OF HEADING;;;;
+2402;SYMBOL FOR START OF TEXT;So;0;ON;;;;;N;GRAPHIC FOR START OF TEXT;;;;
+2403;SYMBOL FOR END OF TEXT;So;0;ON;;;;;N;GRAPHIC FOR END OF TEXT;;;;
+2404;SYMBOL FOR END OF TRANSMISSION;So;0;ON;;;;;N;GRAPHIC FOR END OF TRANSMISSION;;;;
+2405;SYMBOL FOR ENQUIRY;So;0;ON;;;;;N;GRAPHIC FOR ENQUIRY;;;;
+2406;SYMBOL FOR ACKNOWLEDGE;So;0;ON;;;;;N;GRAPHIC FOR ACKNOWLEDGE;;;;
+2407;SYMBOL FOR BELL;So;0;ON;;;;;N;GRAPHIC FOR BELL;;;;
+2408;SYMBOL FOR BACKSPACE;So;0;ON;;;;;N;GRAPHIC FOR BACKSPACE;;;;
+2409;SYMBOL FOR HORIZONTAL TABULATION;So;0;ON;;;;;N;GRAPHIC FOR HORIZONTAL TABULATION;;;;
+240A;SYMBOL FOR LINE FEED;So;0;ON;;;;;N;GRAPHIC FOR LINE FEED;;;;
+240B;SYMBOL FOR VERTICAL TABULATION;So;0;ON;;;;;N;GRAPHIC FOR VERTICAL TABULATION;;;;
+240C;SYMBOL FOR FORM FEED;So;0;ON;;;;;N;GRAPHIC FOR FORM FEED;;;;
+240D;SYMBOL FOR CARRIAGE RETURN;So;0;ON;;;;;N;GRAPHIC FOR CARRIAGE RETURN;;;;
+240E;SYMBOL FOR SHIFT OUT;So;0;ON;;;;;N;GRAPHIC FOR SHIFT OUT;;;;
+240F;SYMBOL FOR SHIFT IN;So;0;ON;;;;;N;GRAPHIC FOR SHIFT IN;;;;
+2410;SYMBOL FOR DATA LINK ESCAPE;So;0;ON;;;;;N;GRAPHIC FOR DATA LINK ESCAPE;;;;
+2411;SYMBOL FOR DEVICE CONTROL ONE;So;0;ON;;;;;N;GRAPHIC FOR DEVICE CONTROL ONE;;;;
+2412;SYMBOL FOR DEVICE CONTROL TWO;So;0;ON;;;;;N;GRAPHIC FOR DEVICE CONTROL TWO;;;;
+2413;SYMBOL FOR DEVICE CONTROL THREE;So;0;ON;;;;;N;GRAPHIC FOR DEVICE CONTROL THREE;;;;
+2414;SYMBOL FOR DEVICE CONTROL FOUR;So;0;ON;;;;;N;GRAPHIC FOR DEVICE CONTROL FOUR;;;;
+2415;SYMBOL FOR NEGATIVE ACKNOWLEDGE;So;0;ON;;;;;N;GRAPHIC FOR NEGATIVE ACKNOWLEDGE;;;;
+2416;SYMBOL FOR SYNCHRONOUS IDLE;So;0;ON;;;;;N;GRAPHIC FOR SYNCHRONOUS IDLE;;;;
+2417;SYMBOL FOR END OF TRANSMISSION BLOCK;So;0;ON;;;;;N;GRAPHIC FOR END OF TRANSMISSION BLOCK;;;;
+2418;SYMBOL FOR CANCEL;So;0;ON;;;;;N;GRAPHIC FOR CANCEL;;;;
+2419;SYMBOL FOR END OF MEDIUM;So;0;ON;;;;;N;GRAPHIC FOR END OF MEDIUM;;;;
+241A;SYMBOL FOR SUBSTITUTE;So;0;ON;;;;;N;GRAPHIC FOR SUBSTITUTE;;;;
+241B;SYMBOL FOR ESCAPE;So;0;ON;;;;;N;GRAPHIC FOR ESCAPE;;;;
+241C;SYMBOL FOR FILE SEPARATOR;So;0;ON;;;;;N;GRAPHIC FOR FILE SEPARATOR;;;;
+241D;SYMBOL FOR GROUP SEPARATOR;So;0;ON;;;;;N;GRAPHIC FOR GROUP SEPARATOR;;;;
+241E;SYMBOL FOR RECORD SEPARATOR;So;0;ON;;;;;N;GRAPHIC FOR RECORD SEPARATOR;;;;
+241F;SYMBOL FOR UNIT SEPARATOR;So;0;ON;;;;;N;GRAPHIC FOR UNIT SEPARATOR;;;;
+2420;SYMBOL FOR SPACE;So;0;ON;;;;;N;GRAPHIC FOR SPACE;;;;
+2421;SYMBOL FOR DELETE;So;0;ON;;;;;N;GRAPHIC FOR DELETE;;;;
+2422;BLANK SYMBOL;So;0;ON;;;;;N;BLANK;;;;
+2423;OPEN BOX;So;0;ON;;;;;N;;;;;
+2424;SYMBOL FOR NEWLINE;So;0;ON;;;;;N;GRAPHIC FOR NEWLINE;;;;
+2425;SYMBOL FOR DELETE FORM TWO;So;0;ON;;;;;N;;;;;
+2426;SYMBOL FOR SUBSTITUTE FORM TWO;So;0;ON;;;;;N;;;;;
+2440;OCR HOOK;So;0;ON;;;;;N;;;;;
+2441;OCR CHAIR;So;0;ON;;;;;N;;;;;
+2442;OCR FORK;So;0;ON;;;;;N;;;;;
+2443;OCR INVERTED FORK;So;0;ON;;;;;N;;;;;
+2444;OCR BELT BUCKLE;So;0;ON;;;;;N;;;;;
+2445;OCR BOW TIE;So;0;ON;;;;;N;;;;;
+2446;OCR BRANCH BANK IDENTIFICATION;So;0;ON;;;;;N;;;;;
+2447;OCR AMOUNT OF CHECK;So;0;ON;;;;;N;;;;;
+2448;OCR DASH;So;0;ON;;;;;N;;;;;
+2449;OCR CUSTOMER ACCOUNT NUMBER;So;0;ON;;;;;N;;;;;
+244A;OCR DOUBLE BACKSLASH;So;0;ON;;;;;N;;;;;
+2460;CIRCLED DIGIT ONE;No;0;ON;<circle> 0031;;1;1;N;;;;;
+2461;CIRCLED DIGIT TWO;No;0;ON;<circle> 0032;;2;2;N;;;;;
+2462;CIRCLED DIGIT THREE;No;0;ON;<circle> 0033;;3;3;N;;;;;
+2463;CIRCLED DIGIT FOUR;No;0;ON;<circle> 0034;;4;4;N;;;;;
+2464;CIRCLED DIGIT FIVE;No;0;ON;<circle> 0035;;5;5;N;;;;;
+2465;CIRCLED DIGIT SIX;No;0;ON;<circle> 0036;;6;6;N;;;;;
+2466;CIRCLED DIGIT SEVEN;No;0;ON;<circle> 0037;;7;7;N;;;;;
+2467;CIRCLED DIGIT EIGHT;No;0;ON;<circle> 0038;;8;8;N;;;;;
+2468;CIRCLED DIGIT NINE;No;0;ON;<circle> 0039;;9;9;N;;;;;
+2469;CIRCLED NUMBER TEN;No;0;ON;<circle> 0031 0030;;;10;N;;;;;
+246A;CIRCLED NUMBER ELEVEN;No;0;ON;<circle> 0031 0031;;;11;N;;;;;
+246B;CIRCLED NUMBER TWELVE;No;0;ON;<circle> 0031 0032;;;12;N;;;;;
+246C;CIRCLED NUMBER THIRTEEN;No;0;ON;<circle> 0031 0033;;;13;N;;;;;
+246D;CIRCLED NUMBER FOURTEEN;No;0;ON;<circle> 0031 0034;;;14;N;;;;;
+246E;CIRCLED NUMBER FIFTEEN;No;0;ON;<circle> 0031 0035;;;15;N;;;;;
+246F;CIRCLED NUMBER SIXTEEN;No;0;ON;<circle> 0031 0036;;;16;N;;;;;
+2470;CIRCLED NUMBER SEVENTEEN;No;0;ON;<circle> 0031 0037;;;17;N;;;;;
+2471;CIRCLED NUMBER EIGHTEEN;No;0;ON;<circle> 0031 0038;;;18;N;;;;;
+2472;CIRCLED NUMBER NINETEEN;No;0;ON;<circle> 0031 0039;;;19;N;;;;;
+2473;CIRCLED NUMBER TWENTY;No;0;ON;<circle> 0032 0030;;;20;N;;;;;
+2474;PARENTHESIZED DIGIT ONE;No;0;ON;<compat> 0028 0031 0029;;1;1;N;;;;;
+2475;PARENTHESIZED DIGIT TWO;No;0;ON;<compat> 0028 0032 0029;;2;2;N;;;;;
+2476;PARENTHESIZED DIGIT THREE;No;0;ON;<compat> 0028 0033 0029;;3;3;N;;;;;
+2477;PARENTHESIZED DIGIT FOUR;No;0;ON;<compat> 0028 0034 0029;;4;4;N;;;;;
+2478;PARENTHESIZED DIGIT FIVE;No;0;ON;<compat> 0028 0035 0029;;5;5;N;;;;;
+2479;PARENTHESIZED DIGIT SIX;No;0;ON;<compat> 0028 0036 0029;;6;6;N;;;;;
+247A;PARENTHESIZED DIGIT SEVEN;No;0;ON;<compat> 0028 0037 0029;;7;7;N;;;;;
+247B;PARENTHESIZED DIGIT EIGHT;No;0;ON;<compat> 0028 0038 0029;;8;8;N;;;;;
+247C;PARENTHESIZED DIGIT NINE;No;0;ON;<compat> 0028 0039 0029;;9;9;N;;;;;
+247D;PARENTHESIZED NUMBER TEN;No;0;ON;<compat> 0028 0031 0030 0029;;;10;N;;;;;
+247E;PARENTHESIZED NUMBER ELEVEN;No;0;ON;<compat> 0028 0031 0031 0029;;;11;N;;;;;
+247F;PARENTHESIZED NUMBER TWELVE;No;0;ON;<compat> 0028 0031 0032 0029;;;12;N;;;;;
+2480;PARENTHESIZED NUMBER THIRTEEN;No;0;ON;<compat> 0028 0031 0033 0029;;;13;N;;;;;
+2481;PARENTHESIZED NUMBER FOURTEEN;No;0;ON;<compat> 0028 0031 0034 0029;;;14;N;;;;;
+2482;PARENTHESIZED NUMBER FIFTEEN;No;0;ON;<compat> 0028 0031 0035 0029;;;15;N;;;;;
+2483;PARENTHESIZED NUMBER SIXTEEN;No;0;ON;<compat> 0028 0031 0036 0029;;;16;N;;;;;
+2484;PARENTHESIZED NUMBER SEVENTEEN;No;0;ON;<compat> 0028 0031 0037 0029;;;17;N;;;;;
+2485;PARENTHESIZED NUMBER EIGHTEEN;No;0;ON;<compat> 0028 0031 0038 0029;;;18;N;;;;;
+2486;PARENTHESIZED NUMBER NINETEEN;No;0;ON;<compat> 0028 0031 0039 0029;;;19;N;;;;;
+2487;PARENTHESIZED NUMBER TWENTY;No;0;ON;<compat> 0028 0032 0030 0029;;;20;N;;;;;
+2488;DIGIT ONE FULL STOP;No;0;EN;<compat> 0031 002E;;1;1;N;DIGIT ONE PERIOD;;;;
+2489;DIGIT TWO FULL STOP;No;0;EN;<compat> 0032 002E;;2;2;N;DIGIT TWO PERIOD;;;;
+248A;DIGIT THREE FULL STOP;No;0;EN;<compat> 0033 002E;;3;3;N;DIGIT THREE PERIOD;;;;
+248B;DIGIT FOUR FULL STOP;No;0;EN;<compat> 0034 002E;;4;4;N;DIGIT FOUR PERIOD;;;;
+248C;DIGIT FIVE FULL STOP;No;0;EN;<compat> 0035 002E;;5;5;N;DIGIT FIVE PERIOD;;;;
+248D;DIGIT SIX FULL STOP;No;0;EN;<compat> 0036 002E;;6;6;N;DIGIT SIX PERIOD;;;;
+248E;DIGIT SEVEN FULL STOP;No;0;EN;<compat> 0037 002E;;7;7;N;DIGIT SEVEN PERIOD;;;;
+248F;DIGIT EIGHT FULL STOP;No;0;EN;<compat> 0038 002E;;8;8;N;DIGIT EIGHT PERIOD;;;;
+2490;DIGIT NINE FULL STOP;No;0;EN;<compat> 0039 002E;;9;9;N;DIGIT NINE PERIOD;;;;
+2491;NUMBER TEN FULL STOP;No;0;EN;<compat> 0031 0030 002E;;;10;N;NUMBER TEN PERIOD;;;;
+2492;NUMBER ELEVEN FULL STOP;No;0;EN;<compat> 0031 0031 002E;;;11;N;NUMBER ELEVEN PERIOD;;;;
+2493;NUMBER TWELVE FULL STOP;No;0;EN;<compat> 0031 0032 002E;;;12;N;NUMBER TWELVE PERIOD;;;;
+2494;NUMBER THIRTEEN FULL STOP;No;0;EN;<compat> 0031 0033 002E;;;13;N;NUMBER THIRTEEN PERIOD;;;;
+2495;NUMBER FOURTEEN FULL STOP;No;0;EN;<compat> 0031 0034 002E;;;14;N;NUMBER FOURTEEN PERIOD;;;;
+2496;NUMBER FIFTEEN FULL STOP;No;0;EN;<compat> 0031 0035 002E;;;15;N;NUMBER FIFTEEN PERIOD;;;;
+2497;NUMBER SIXTEEN FULL STOP;No;0;EN;<compat> 0031 0036 002E;;;16;N;NUMBER SIXTEEN PERIOD;;;;
+2498;NUMBER SEVENTEEN FULL STOP;No;0;EN;<compat> 0031 0037 002E;;;17;N;NUMBER SEVENTEEN PERIOD;;;;
+2499;NUMBER EIGHTEEN FULL STOP;No;0;EN;<compat> 0031 0038 002E;;;18;N;NUMBER EIGHTEEN PERIOD;;;;
+249A;NUMBER NINETEEN FULL STOP;No;0;EN;<compat> 0031 0039 002E;;;19;N;NUMBER NINETEEN PERIOD;;;;
+249B;NUMBER TWENTY FULL STOP;No;0;EN;<compat> 0032 0030 002E;;;20;N;NUMBER TWENTY PERIOD;;;;
+249C;PARENTHESIZED LATIN SMALL LETTER A;So;0;L;<compat> 0028 0061 0029;;;;N;;;;;
+249D;PARENTHESIZED LATIN SMALL LETTER B;So;0;L;<compat> 0028 0062 0029;;;;N;;;;;
+249E;PARENTHESIZED LATIN SMALL LETTER C;So;0;L;<compat> 0028 0063 0029;;;;N;;;;;
+249F;PARENTHESIZED LATIN SMALL LETTER D;So;0;L;<compat> 0028 0064 0029;;;;N;;;;;
+24A0;PARENTHESIZED LATIN SMALL LETTER E;So;0;L;<compat> 0028 0065 0029;;;;N;;;;;
+24A1;PARENTHESIZED LATIN SMALL LETTER F;So;0;L;<compat> 0028 0066 0029;;;;N;;;;;
+24A2;PARENTHESIZED LATIN SMALL LETTER G;So;0;L;<compat> 0028 0067 0029;;;;N;;;;;
+24A3;PARENTHESIZED LATIN SMALL LETTER H;So;0;L;<compat> 0028 0068 0029;;;;N;;;;;
+24A4;PARENTHESIZED LATIN SMALL LETTER I;So;0;L;<compat> 0028 0069 0029;;;;N;;;;;
+24A5;PARENTHESIZED LATIN SMALL LETTER J;So;0;L;<compat> 0028 006A 0029;;;;N;;;;;
+24A6;PARENTHESIZED LATIN SMALL LETTER K;So;0;L;<compat> 0028 006B 0029;;;;N;;;;;
+24A7;PARENTHESIZED LATIN SMALL LETTER L;So;0;L;<compat> 0028 006C 0029;;;;N;;;;;
+24A8;PARENTHESIZED LATIN SMALL LETTER M;So;0;L;<compat> 0028 006D 0029;;;;N;;;;;
+24A9;PARENTHESIZED LATIN SMALL LETTER N;So;0;L;<compat> 0028 006E 0029;;;;N;;;;;
+24AA;PARENTHESIZED LATIN SMALL LETTER O;So;0;L;<compat> 0028 006F 0029;;;;N;;;;;
+24AB;PARENTHESIZED LATIN SMALL LETTER P;So;0;L;<compat> 0028 0070 0029;;;;N;;;;;
+24AC;PARENTHESIZED LATIN SMALL LETTER Q;So;0;L;<compat> 0028 0071 0029;;;;N;;;;;
+24AD;PARENTHESIZED LATIN SMALL LETTER R;So;0;L;<compat> 0028 0072 0029;;;;N;;;;;
+24AE;PARENTHESIZED LATIN SMALL LETTER S;So;0;L;<compat> 0028 0073 0029;;;;N;;;;;
+24AF;PARENTHESIZED LATIN SMALL LETTER T;So;0;L;<compat> 0028 0074 0029;;;;N;;;;;
+24B0;PARENTHESIZED LATIN SMALL LETTER U;So;0;L;<compat> 0028 0075 0029;;;;N;;;;;
+24B1;PARENTHESIZED LATIN SMALL LETTER V;So;0;L;<compat> 0028 0076 0029;;;;N;;;;;
+24B2;PARENTHESIZED LATIN SMALL LETTER W;So;0;L;<compat> 0028 0077 0029;;;;N;;;;;
+24B3;PARENTHESIZED LATIN SMALL LETTER X;So;0;L;<compat> 0028 0078 0029;;;;N;;;;;
+24B4;PARENTHESIZED LATIN SMALL LETTER Y;So;0;L;<compat> 0028 0079 0029;;;;N;;;;;
+24B5;PARENTHESIZED LATIN SMALL LETTER Z;So;0;L;<compat> 0028 007A 0029;;;;N;;;;;
+24B6;CIRCLED LATIN CAPITAL LETTER A;So;0;L;<circle> 0041;;;;N;;;;24D0;
+24B7;CIRCLED LATIN CAPITAL LETTER B;So;0;L;<circle> 0042;;;;N;;;;24D1;
+24B8;CIRCLED LATIN CAPITAL LETTER C;So;0;L;<circle> 0043;;;;N;;;;24D2;
+24B9;CIRCLED LATIN CAPITAL LETTER D;So;0;L;<circle> 0044;;;;N;;;;24D3;
+24BA;CIRCLED LATIN CAPITAL LETTER E;So;0;L;<circle> 0045;;;;N;;;;24D4;
+24BB;CIRCLED LATIN CAPITAL LETTER F;So;0;L;<circle> 0046;;;;N;;;;24D5;
+24BC;CIRCLED LATIN CAPITAL LETTER G;So;0;L;<circle> 0047;;;;N;;;;24D6;
+24BD;CIRCLED LATIN CAPITAL LETTER H;So;0;L;<circle> 0048;;;;N;;;;24D7;
+24BE;CIRCLED LATIN CAPITAL LETTER I;So;0;L;<circle> 0049;;;;N;;;;24D8;
+24BF;CIRCLED LATIN CAPITAL LETTER J;So;0;L;<circle> 004A;;;;N;;;;24D9;
+24C0;CIRCLED LATIN CAPITAL LETTER K;So;0;L;<circle> 004B;;;;N;;;;24DA;
+24C1;CIRCLED LATIN CAPITAL LETTER L;So;0;L;<circle> 004C;;;;N;;;;24DB;
+24C2;CIRCLED LATIN CAPITAL LETTER M;So;0;L;<circle> 004D;;;;N;;;;24DC;
+24C3;CIRCLED LATIN CAPITAL LETTER N;So;0;L;<circle> 004E;;;;N;;;;24DD;
+24C4;CIRCLED LATIN CAPITAL LETTER O;So;0;L;<circle> 004F;;;;N;;;;24DE;
+24C5;CIRCLED LATIN CAPITAL LETTER P;So;0;L;<circle> 0050;;;;N;;;;24DF;
+24C6;CIRCLED LATIN CAPITAL LETTER Q;So;0;L;<circle> 0051;;;;N;;;;24E0;
+24C7;CIRCLED LATIN CAPITAL LETTER R;So;0;L;<circle> 0052;;;;N;;;;24E1;
+24C8;CIRCLED LATIN CAPITAL LETTER S;So;0;L;<circle> 0053;;;;N;;;;24E2;
+24C9;CIRCLED LATIN CAPITAL LETTER T;So;0;L;<circle> 0054;;;;N;;;;24E3;
+24CA;CIRCLED LATIN CAPITAL LETTER U;So;0;L;<circle> 0055;;;;N;;;;24E4;
+24CB;CIRCLED LATIN CAPITAL LETTER V;So;0;L;<circle> 0056;;;;N;;;;24E5;
+24CC;CIRCLED LATIN CAPITAL LETTER W;So;0;L;<circle> 0057;;;;N;;;;24E6;
+24CD;CIRCLED LATIN CAPITAL LETTER X;So;0;L;<circle> 0058;;;;N;;;;24E7;
+24CE;CIRCLED LATIN CAPITAL LETTER Y;So;0;L;<circle> 0059;;;;N;;;;24E8;
+24CF;CIRCLED LATIN CAPITAL LETTER Z;So;0;L;<circle> 005A;;;;N;;;;24E9;
+24D0;CIRCLED LATIN SMALL LETTER A;So;0;L;<circle> 0061;;;;N;;;24B6;;24B6
+24D1;CIRCLED LATIN SMALL LETTER B;So;0;L;<circle> 0062;;;;N;;;24B7;;24B7
+24D2;CIRCLED LATIN SMALL LETTER C;So;0;L;<circle> 0063;;;;N;;;24B8;;24B8
+24D3;CIRCLED LATIN SMALL LETTER D;So;0;L;<circle> 0064;;;;N;;;24B9;;24B9
+24D4;CIRCLED LATIN SMALL LETTER E;So;0;L;<circle> 0065;;;;N;;;24BA;;24BA
+24D5;CIRCLED LATIN SMALL LETTER F;So;0;L;<circle> 0066;;;;N;;;24BB;;24BB
+24D6;CIRCLED LATIN SMALL LETTER G;So;0;L;<circle> 0067;;;;N;;;24BC;;24BC
+24D7;CIRCLED LATIN SMALL LETTER H;So;0;L;<circle> 0068;;;;N;;;24BD;;24BD
+24D8;CIRCLED LATIN SMALL LETTER I;So;0;L;<circle> 0069;;;;N;;;24BE;;24BE
+24D9;CIRCLED LATIN SMALL LETTER J;So;0;L;<circle> 006A;;;;N;;;24BF;;24BF
+24DA;CIRCLED LATIN SMALL LETTER K;So;0;L;<circle> 006B;;;;N;;;24C0;;24C0
+24DB;CIRCLED LATIN SMALL LETTER L;So;0;L;<circle> 006C;;;;N;;;24C1;;24C1
+24DC;CIRCLED LATIN SMALL LETTER M;So;0;L;<circle> 006D;;;;N;;;24C2;;24C2
+24DD;CIRCLED LATIN SMALL LETTER N;So;0;L;<circle> 006E;;;;N;;;24C3;;24C3
+24DE;CIRCLED LATIN SMALL LETTER O;So;0;L;<circle> 006F;;;;N;;;24C4;;24C4
+24DF;CIRCLED LATIN SMALL LETTER P;So;0;L;<circle> 0070;;;;N;;;24C5;;24C5
+24E0;CIRCLED LATIN SMALL LETTER Q;So;0;L;<circle> 0071;;;;N;;;24C6;;24C6
+24E1;CIRCLED LATIN SMALL LETTER R;So;0;L;<circle> 0072;;;;N;;;24C7;;24C7
+24E2;CIRCLED LATIN SMALL LETTER S;So;0;L;<circle> 0073;;;;N;;;24C8;;24C8
+24E3;CIRCLED LATIN SMALL LETTER T;So;0;L;<circle> 0074;;;;N;;;24C9;;24C9
+24E4;CIRCLED LATIN SMALL LETTER U;So;0;L;<circle> 0075;;;;N;;;24CA;;24CA
+24E5;CIRCLED LATIN SMALL LETTER V;So;0;L;<circle> 0076;;;;N;;;24CB;;24CB
+24E6;CIRCLED LATIN SMALL LETTER W;So;0;L;<circle> 0077;;;;N;;;24CC;;24CC
+24E7;CIRCLED LATIN SMALL LETTER X;So;0;L;<circle> 0078;;;;N;;;24CD;;24CD
+24E8;CIRCLED LATIN SMALL LETTER Y;So;0;L;<circle> 0079;;;;N;;;24CE;;24CE
+24E9;CIRCLED LATIN SMALL LETTER Z;So;0;L;<circle> 007A;;;;N;;;24CF;;24CF
+24EA;CIRCLED DIGIT ZERO;No;0;ON;<circle> 0030;;0;0;N;;;;;
+24EB;NEGATIVE CIRCLED NUMBER ELEVEN;No;0;ON;;;;11;N;;;;;
+24EC;NEGATIVE CIRCLED NUMBER TWELVE;No;0;ON;;;;12;N;;;;;
+24ED;NEGATIVE CIRCLED NUMBER THIRTEEN;No;0;ON;;;;13;N;;;;;
+24EE;NEGATIVE CIRCLED NUMBER FOURTEEN;No;0;ON;;;;14;N;;;;;
+24EF;NEGATIVE CIRCLED NUMBER FIFTEEN;No;0;ON;;;;15;N;;;;;
+24F0;NEGATIVE CIRCLED NUMBER SIXTEEN;No;0;ON;;;;16;N;;;;;
+24F1;NEGATIVE CIRCLED NUMBER SEVENTEEN;No;0;ON;;;;17;N;;;;;
+24F2;NEGATIVE CIRCLED NUMBER EIGHTEEN;No;0;ON;;;;18;N;;;;;
+24F3;NEGATIVE CIRCLED NUMBER NINETEEN;No;0;ON;;;;19;N;;;;;
+24F4;NEGATIVE CIRCLED NUMBER TWENTY;No;0;ON;;;;20;N;;;;;
+24F5;DOUBLE CIRCLED DIGIT ONE;No;0;ON;;;1;1;N;;;;;
+24F6;DOUBLE CIRCLED DIGIT TWO;No;0;ON;;;2;2;N;;;;;
+24F7;DOUBLE CIRCLED DIGIT THREE;No;0;ON;;;3;3;N;;;;;
+24F8;DOUBLE CIRCLED DIGIT FOUR;No;0;ON;;;4;4;N;;;;;
+24F9;DOUBLE CIRCLED DIGIT FIVE;No;0;ON;;;5;5;N;;;;;
+24FA;DOUBLE CIRCLED DIGIT SIX;No;0;ON;;;6;6;N;;;;;
+24FB;DOUBLE CIRCLED DIGIT SEVEN;No;0;ON;;;7;7;N;;;;;
+24FC;DOUBLE CIRCLED DIGIT EIGHT;No;0;ON;;;8;8;N;;;;;
+24FD;DOUBLE CIRCLED DIGIT NINE;No;0;ON;;;9;9;N;;;;;
+24FE;DOUBLE CIRCLED NUMBER TEN;No;0;ON;;;;10;N;;;;;
+24FF;NEGATIVE CIRCLED DIGIT ZERO;No;0;ON;;;0;0;N;;;;;
+2500;BOX DRAWINGS LIGHT HORIZONTAL;So;0;ON;;;;;N;FORMS LIGHT HORIZONTAL;;;;
+2501;BOX DRAWINGS HEAVY HORIZONTAL;So;0;ON;;;;;N;FORMS HEAVY HORIZONTAL;;;;
+2502;BOX DRAWINGS LIGHT VERTICAL;So;0;ON;;;;;N;FORMS LIGHT VERTICAL;;;;
+2503;BOX DRAWINGS HEAVY VERTICAL;So;0;ON;;;;;N;FORMS HEAVY VERTICAL;;;;
+2504;BOX DRAWINGS LIGHT TRIPLE DASH HORIZONTAL;So;0;ON;;;;;N;FORMS LIGHT TRIPLE DASH HORIZONTAL;;;;
+2505;BOX DRAWINGS HEAVY TRIPLE DASH HORIZONTAL;So;0;ON;;;;;N;FORMS HEAVY TRIPLE DASH HORIZONTAL;;;;
+2506;BOX DRAWINGS LIGHT TRIPLE DASH VERTICAL;So;0;ON;;;;;N;FORMS LIGHT TRIPLE DASH VERTICAL;;;;
+2507;BOX DRAWINGS HEAVY TRIPLE DASH VERTICAL;So;0;ON;;;;;N;FORMS HEAVY TRIPLE DASH VERTICAL;;;;
+2508;BOX DRAWINGS LIGHT QUADRUPLE DASH HORIZONTAL;So;0;ON;;;;;N;FORMS LIGHT QUADRUPLE DASH HORIZONTAL;;;;
+2509;BOX DRAWINGS HEAVY QUADRUPLE DASH HORIZONTAL;So;0;ON;;;;;N;FORMS HEAVY QUADRUPLE DASH HORIZONTAL;;;;
+250A;BOX DRAWINGS LIGHT QUADRUPLE DASH VERTICAL;So;0;ON;;;;;N;FORMS LIGHT QUADRUPLE DASH VERTICAL;;;;
+250B;BOX DRAWINGS HEAVY QUADRUPLE DASH VERTICAL;So;0;ON;;;;;N;FORMS HEAVY QUADRUPLE DASH VERTICAL;;;;
+250C;BOX DRAWINGS LIGHT DOWN AND RIGHT;So;0;ON;;;;;N;FORMS LIGHT DOWN AND RIGHT;;;;
+250D;BOX DRAWINGS DOWN LIGHT AND RIGHT HEAVY;So;0;ON;;;;;N;FORMS DOWN LIGHT AND RIGHT HEAVY;;;;
+250E;BOX DRAWINGS DOWN HEAVY AND RIGHT LIGHT;So;0;ON;;;;;N;FORMS DOWN HEAVY AND RIGHT LIGHT;;;;
+250F;BOX DRAWINGS HEAVY DOWN AND RIGHT;So;0;ON;;;;;N;FORMS HEAVY DOWN AND RIGHT;;;;
+2510;BOX DRAWINGS LIGHT DOWN AND LEFT;So;0;ON;;;;;N;FORMS LIGHT DOWN AND LEFT;;;;
+2511;BOX DRAWINGS DOWN LIGHT AND LEFT HEAVY;So;0;ON;;;;;N;FORMS DOWN LIGHT AND LEFT HEAVY;;;;
+2512;BOX DRAWINGS DOWN HEAVY AND LEFT LIGHT;So;0;ON;;;;;N;FORMS DOWN HEAVY AND LEFT LIGHT;;;;
+2513;BOX DRAWINGS HEAVY DOWN AND LEFT;So;0;ON;;;;;N;FORMS HEAVY DOWN AND LEFT;;;;
+2514;BOX DRAWINGS LIGHT UP AND RIGHT;So;0;ON;;;;;N;FORMS LIGHT UP AND RIGHT;;;;
+2515;BOX DRAWINGS UP LIGHT AND RIGHT HEAVY;So;0;ON;;;;;N;FORMS UP LIGHT AND RIGHT HEAVY;;;;
+2516;BOX DRAWINGS UP HEAVY AND RIGHT LIGHT;So;0;ON;;;;;N;FORMS UP HEAVY AND RIGHT LIGHT;;;;
+2517;BOX DRAWINGS HEAVY UP AND RIGHT;So;0;ON;;;;;N;FORMS HEAVY UP AND RIGHT;;;;
+2518;BOX DRAWINGS LIGHT UP AND LEFT;So;0;ON;;;;;N;FORMS LIGHT UP AND LEFT;;;;
+2519;BOX DRAWINGS UP LIGHT AND LEFT HEAVY;So;0;ON;;;;;N;FORMS UP LIGHT AND LEFT HEAVY;;;;
+251A;BOX DRAWINGS UP HEAVY AND LEFT LIGHT;So;0;ON;;;;;N;FORMS UP HEAVY AND LEFT LIGHT;;;;
+251B;BOX DRAWINGS HEAVY UP AND LEFT;So;0;ON;;;;;N;FORMS HEAVY UP AND LEFT;;;;
+251C;BOX DRAWINGS LIGHT VERTICAL AND RIGHT;So;0;ON;;;;;N;FORMS LIGHT VERTICAL AND RIGHT;;;;
+251D;BOX DRAWINGS VERTICAL LIGHT AND RIGHT HEAVY;So;0;ON;;;;;N;FORMS VERTICAL LIGHT AND RIGHT HEAVY;;;;
+251E;BOX DRAWINGS UP HEAVY AND RIGHT DOWN LIGHT;So;0;ON;;;;;N;FORMS UP HEAVY AND RIGHT DOWN LIGHT;;;;
+251F;BOX DRAWINGS DOWN HEAVY AND RIGHT UP LIGHT;So;0;ON;;;;;N;FORMS DOWN HEAVY AND RIGHT UP LIGHT;;;;
+2520;BOX DRAWINGS VERTICAL HEAVY AND RIGHT LIGHT;So;0;ON;;;;;N;FORMS VERTICAL HEAVY AND RIGHT LIGHT;;;;
+2521;BOX DRAWINGS DOWN LIGHT AND RIGHT UP HEAVY;So;0;ON;;;;;N;FORMS DOWN LIGHT AND RIGHT UP HEAVY;;;;
+2522;BOX DRAWINGS UP LIGHT AND RIGHT DOWN HEAVY;So;0;ON;;;;;N;FORMS UP LIGHT AND RIGHT DOWN HEAVY;;;;
+2523;BOX DRAWINGS HEAVY VERTICAL AND RIGHT;So;0;ON;;;;;N;FORMS HEAVY VERTICAL AND RIGHT;;;;
+2524;BOX DRAWINGS LIGHT VERTICAL AND LEFT;So;0;ON;;;;;N;FORMS LIGHT VERTICAL AND LEFT;;;;
+2525;BOX DRAWINGS VERTICAL LIGHT AND LEFT HEAVY;So;0;ON;;;;;N;FORMS VERTICAL LIGHT AND LEFT HEAVY;;;;
+2526;BOX DRAWINGS UP HEAVY AND LEFT DOWN LIGHT;So;0;ON;;;;;N;FORMS UP HEAVY AND LEFT DOWN LIGHT;;;;
+2527;BOX DRAWINGS DOWN HEAVY AND LEFT UP LIGHT;So;0;ON;;;;;N;FORMS DOWN HEAVY AND LEFT UP LIGHT;;;;
+2528;BOX DRAWINGS VERTICAL HEAVY AND LEFT LIGHT;So;0;ON;;;;;N;FORMS VERTICAL HEAVY AND LEFT LIGHT;;;;
+2529;BOX DRAWINGS DOWN LIGHT AND LEFT UP HEAVY;So;0;ON;;;;;N;FORMS DOWN LIGHT AND LEFT UP HEAVY;;;;
+252A;BOX DRAWINGS UP LIGHT AND LEFT DOWN HEAVY;So;0;ON;;;;;N;FORMS UP LIGHT AND LEFT DOWN HEAVY;;;;
+252B;BOX DRAWINGS HEAVY VERTICAL AND LEFT;So;0;ON;;;;;N;FORMS HEAVY VERTICAL AND LEFT;;;;
+252C;BOX DRAWINGS LIGHT DOWN AND HORIZONTAL;So;0;ON;;;;;N;FORMS LIGHT DOWN AND HORIZONTAL;;;;
+252D;BOX DRAWINGS LEFT HEAVY AND RIGHT DOWN LIGHT;So;0;ON;;;;;N;FORMS LEFT HEAVY AND RIGHT DOWN LIGHT;;;;
+252E;BOX DRAWINGS RIGHT HEAVY AND LEFT DOWN LIGHT;So;0;ON;;;;;N;FORMS RIGHT HEAVY AND LEFT DOWN LIGHT;;;;
+252F;BOX DRAWINGS DOWN LIGHT AND HORIZONTAL HEAVY;So;0;ON;;;;;N;FORMS DOWN LIGHT AND HORIZONTAL HEAVY;;;;
+2530;BOX DRAWINGS DOWN HEAVY AND HORIZONTAL LIGHT;So;0;ON;;;;;N;FORMS DOWN HEAVY AND HORIZONTAL LIGHT;;;;
+2531;BOX DRAWINGS RIGHT LIGHT AND LEFT DOWN HEAVY;So;0;ON;;;;;N;FORMS RIGHT LIGHT AND LEFT DOWN HEAVY;;;;
+2532;BOX DRAWINGS LEFT LIGHT AND RIGHT DOWN HEAVY;So;0;ON;;;;;N;FORMS LEFT LIGHT AND RIGHT DOWN HEAVY;;;;
+2533;BOX DRAWINGS HEAVY DOWN AND HORIZONTAL;So;0;ON;;;;;N;FORMS HEAVY DOWN AND HORIZONTAL;;;;
+2534;BOX DRAWINGS LIGHT UP AND HORIZONTAL;So;0;ON;;;;;N;FORMS LIGHT UP AND HORIZONTAL;;;;
+2535;BOX DRAWINGS LEFT HEAVY AND RIGHT UP LIGHT;So;0;ON;;;;;N;FORMS LEFT HEAVY AND RIGHT UP LIGHT;;;;
+2536;BOX DRAWINGS RIGHT HEAVY AND LEFT UP LIGHT;So;0;ON;;;;;N;FORMS RIGHT HEAVY AND LEFT UP LIGHT;;;;
+2537;BOX DRAWINGS UP LIGHT AND HORIZONTAL HEAVY;So;0;ON;;;;;N;FORMS UP LIGHT AND HORIZONTAL HEAVY;;;;
+2538;BOX DRAWINGS UP HEAVY AND HORIZONTAL LIGHT;So;0;ON;;;;;N;FORMS UP HEAVY AND HORIZONTAL LIGHT;;;;
+2539;BOX DRAWINGS RIGHT LIGHT AND LEFT UP HEAVY;So;0;ON;;;;;N;FORMS RIGHT LIGHT AND LEFT UP HEAVY;;;;
+253A;BOX DRAWINGS LEFT LIGHT AND RIGHT UP HEAVY;So;0;ON;;;;;N;FORMS LEFT LIGHT AND RIGHT UP HEAVY;;;;
+253B;BOX DRAWINGS HEAVY UP AND HORIZONTAL;So;0;ON;;;;;N;FORMS HEAVY UP AND HORIZONTAL;;;;
+253C;BOX DRAWINGS LIGHT VERTICAL AND HORIZONTAL;So;0;ON;;;;;N;FORMS LIGHT VERTICAL AND HORIZONTAL;;;;
+253D;BOX DRAWINGS LEFT HEAVY AND RIGHT VERTICAL LIGHT;So;0;ON;;;;;N;FORMS LEFT HEAVY AND RIGHT VERTICAL LIGHT;;;;
+253E;BOX DRAWINGS RIGHT HEAVY AND LEFT VERTICAL LIGHT;So;0;ON;;;;;N;FORMS RIGHT HEAVY AND LEFT VERTICAL LIGHT;;;;
+253F;BOX DRAWINGS VERTICAL LIGHT AND HORIZONTAL HEAVY;So;0;ON;;;;;N;FORMS VERTICAL LIGHT AND HORIZONTAL HEAVY;;;;
+2540;BOX DRAWINGS UP HEAVY AND DOWN HORIZONTAL LIGHT;So;0;ON;;;;;N;FORMS UP HEAVY AND DOWN HORIZONTAL LIGHT;;;;
+2541;BOX DRAWINGS DOWN HEAVY AND UP HORIZONTAL LIGHT;So;0;ON;;;;;N;FORMS DOWN HEAVY AND UP HORIZONTAL LIGHT;;;;
+2542;BOX DRAWINGS VERTICAL HEAVY AND HORIZONTAL LIGHT;So;0;ON;;;;;N;FORMS VERTICAL HEAVY AND HORIZONTAL LIGHT;;;;
+2543;BOX DRAWINGS LEFT UP HEAVY AND RIGHT DOWN LIGHT;So;0;ON;;;;;N;FORMS LEFT UP HEAVY AND RIGHT DOWN LIGHT;;;;
+2544;BOX DRAWINGS RIGHT UP HEAVY AND LEFT DOWN LIGHT;So;0;ON;;;;;N;FORMS RIGHT UP HEAVY AND LEFT DOWN LIGHT;;;;
+2545;BOX DRAWINGS LEFT DOWN HEAVY AND RIGHT UP LIGHT;So;0;ON;;;;;N;FORMS LEFT DOWN HEAVY AND RIGHT UP LIGHT;;;;
+2546;BOX DRAWINGS RIGHT DOWN HEAVY AND LEFT UP LIGHT;So;0;ON;;;;;N;FORMS RIGHT DOWN HEAVY AND LEFT UP LIGHT;;;;
+2547;BOX DRAWINGS DOWN LIGHT AND UP HORIZONTAL HEAVY;So;0;ON;;;;;N;FORMS DOWN LIGHT AND UP HORIZONTAL HEAVY;;;;
+2548;BOX DRAWINGS UP LIGHT AND DOWN HORIZONTAL HEAVY;So;0;ON;;;;;N;FORMS UP LIGHT AND DOWN HORIZONTAL HEAVY;;;;
+2549;BOX DRAWINGS RIGHT LIGHT AND LEFT VERTICAL HEAVY;So;0;ON;;;;;N;FORMS RIGHT LIGHT AND LEFT VERTICAL HEAVY;;;;
+254A;BOX DRAWINGS LEFT LIGHT AND RIGHT VERTICAL HEAVY;So;0;ON;;;;;N;FORMS LEFT LIGHT AND RIGHT VERTICAL HEAVY;;;;
+254B;BOX DRAWINGS HEAVY VERTICAL AND HORIZONTAL;So;0;ON;;;;;N;FORMS HEAVY VERTICAL AND HORIZONTAL;;;;
+254C;BOX DRAWINGS LIGHT DOUBLE DASH HORIZONTAL;So;0;ON;;;;;N;FORMS LIGHT DOUBLE DASH HORIZONTAL;;;;
+254D;BOX DRAWINGS HEAVY DOUBLE DASH HORIZONTAL;So;0;ON;;;;;N;FORMS HEAVY DOUBLE DASH HORIZONTAL;;;;
+254E;BOX DRAWINGS LIGHT DOUBLE DASH VERTICAL;So;0;ON;;;;;N;FORMS LIGHT DOUBLE DASH VERTICAL;;;;
+254F;BOX DRAWINGS HEAVY DOUBLE DASH VERTICAL;So;0;ON;;;;;N;FORMS HEAVY DOUBLE DASH VERTICAL;;;;
+2550;BOX DRAWINGS DOUBLE HORIZONTAL;So;0;ON;;;;;N;FORMS DOUBLE HORIZONTAL;;;;
+2551;BOX DRAWINGS DOUBLE VERTICAL;So;0;ON;;;;;N;FORMS DOUBLE VERTICAL;;;;
+2552;BOX DRAWINGS DOWN SINGLE AND RIGHT DOUBLE;So;0;ON;;;;;N;FORMS DOWN SINGLE AND RIGHT DOUBLE;;;;
+2553;BOX DRAWINGS DOWN DOUBLE AND RIGHT SINGLE;So;0;ON;;;;;N;FORMS DOWN DOUBLE AND RIGHT SINGLE;;;;
+2554;BOX DRAWINGS DOUBLE DOWN AND RIGHT;So;0;ON;;;;;N;FORMS DOUBLE DOWN AND RIGHT;;;;
+2555;BOX DRAWINGS DOWN SINGLE AND LEFT DOUBLE;So;0;ON;;;;;N;FORMS DOWN SINGLE AND LEFT DOUBLE;;;;
+2556;BOX DRAWINGS DOWN DOUBLE AND LEFT SINGLE;So;0;ON;;;;;N;FORMS DOWN DOUBLE AND LEFT SINGLE;;;;
+2557;BOX DRAWINGS DOUBLE DOWN AND LEFT;So;0;ON;;;;;N;FORMS DOUBLE DOWN AND LEFT;;;;
+2558;BOX DRAWINGS UP SINGLE AND RIGHT DOUBLE;So;0;ON;;;;;N;FORMS UP SINGLE AND RIGHT DOUBLE;;;;
+2559;BOX DRAWINGS UP DOUBLE AND RIGHT SINGLE;So;0;ON;;;;;N;FORMS UP DOUBLE AND RIGHT SINGLE;;;;
+255A;BOX DRAWINGS DOUBLE UP AND RIGHT;So;0;ON;;;;;N;FORMS DOUBLE UP AND RIGHT;;;;
+255B;BOX DRAWINGS UP SINGLE AND LEFT DOUBLE;So;0;ON;;;;;N;FORMS UP SINGLE AND LEFT DOUBLE;;;;
+255C;BOX DRAWINGS UP DOUBLE AND LEFT SINGLE;So;0;ON;;;;;N;FORMS UP DOUBLE AND LEFT SINGLE;;;;
+255D;BOX DRAWINGS DOUBLE UP AND LEFT;So;0;ON;;;;;N;FORMS DOUBLE UP AND LEFT;;;;
+255E;BOX DRAWINGS VERTICAL SINGLE AND RIGHT DOUBLE;So;0;ON;;;;;N;FORMS VERTICAL SINGLE AND RIGHT DOUBLE;;;;
+255F;BOX DRAWINGS VERTICAL DOUBLE AND RIGHT SINGLE;So;0;ON;;;;;N;FORMS VERTICAL DOUBLE AND RIGHT SINGLE;;;;
+2560;BOX DRAWINGS DOUBLE VERTICAL AND RIGHT;So;0;ON;;;;;N;FORMS DOUBLE VERTICAL AND RIGHT;;;;
+2561;BOX DRAWINGS VERTICAL SINGLE AND LEFT DOUBLE;So;0;ON;;;;;N;FORMS VERTICAL SINGLE AND LEFT DOUBLE;;;;
+2562;BOX DRAWINGS VERTICAL DOUBLE AND LEFT SINGLE;So;0;ON;;;;;N;FORMS VERTICAL DOUBLE AND LEFT SINGLE;;;;
+2563;BOX DRAWINGS DOUBLE VERTICAL AND LEFT;So;0;ON;;;;;N;FORMS DOUBLE VERTICAL AND LEFT;;;;
+2564;BOX DRAWINGS DOWN SINGLE AND HORIZONTAL DOUBLE;So;0;ON;;;;;N;FORMS DOWN SINGLE AND HORIZONTAL DOUBLE;;;;
+2565;BOX DRAWINGS DOWN DOUBLE AND HORIZONTAL SINGLE;So;0;ON;;;;;N;FORMS DOWN DOUBLE AND HORIZONTAL SINGLE;;;;
+2566;BOX DRAWINGS DOUBLE DOWN AND HORIZONTAL;So;0;ON;;;;;N;FORMS DOUBLE DOWN AND HORIZONTAL;;;;
+2567;BOX DRAWINGS UP SINGLE AND HORIZONTAL DOUBLE;So;0;ON;;;;;N;FORMS UP SINGLE AND HORIZONTAL DOUBLE;;;;
+2568;BOX DRAWINGS UP DOUBLE AND HORIZONTAL SINGLE;So;0;ON;;;;;N;FORMS UP DOUBLE AND HORIZONTAL SINGLE;;;;
+2569;BOX DRAWINGS DOUBLE UP AND HORIZONTAL;So;0;ON;;;;;N;FORMS DOUBLE UP AND HORIZONTAL;;;;
+256A;BOX DRAWINGS VERTICAL SINGLE AND HORIZONTAL DOUBLE;So;0;ON;;;;;N;FORMS VERTICAL SINGLE AND HORIZONTAL DOUBLE;;;;
+256B;BOX DRAWINGS VERTICAL DOUBLE AND HORIZONTAL SINGLE;So;0;ON;;;;;N;FORMS VERTICAL DOUBLE AND HORIZONTAL SINGLE;;;;
+256C;BOX DRAWINGS DOUBLE VERTICAL AND HORIZONTAL;So;0;ON;;;;;N;FORMS DOUBLE VERTICAL AND HORIZONTAL;;;;
+256D;BOX DRAWINGS LIGHT ARC DOWN AND RIGHT;So;0;ON;;;;;N;FORMS LIGHT ARC DOWN AND RIGHT;;;;
+256E;BOX DRAWINGS LIGHT ARC DOWN AND LEFT;So;0;ON;;;;;N;FORMS LIGHT ARC DOWN AND LEFT;;;;
+256F;BOX DRAWINGS LIGHT ARC UP AND LEFT;So;0;ON;;;;;N;FORMS LIGHT ARC UP AND LEFT;;;;
+2570;BOX DRAWINGS LIGHT ARC UP AND RIGHT;So;0;ON;;;;;N;FORMS LIGHT ARC UP AND RIGHT;;;;
+2571;BOX DRAWINGS LIGHT DIAGONAL UPPER RIGHT TO LOWER LEFT;So;0;ON;;;;;N;FORMS LIGHT DIAGONAL UPPER RIGHT TO LOWER LEFT;;;;
+2572;BOX DRAWINGS LIGHT DIAGONAL UPPER LEFT TO LOWER RIGHT;So;0;ON;;;;;N;FORMS LIGHT DIAGONAL UPPER LEFT TO LOWER RIGHT;;;;
+2573;BOX DRAWINGS LIGHT DIAGONAL CROSS;So;0;ON;;;;;N;FORMS LIGHT DIAGONAL CROSS;;;;
+2574;BOX DRAWINGS LIGHT LEFT;So;0;ON;;;;;N;FORMS LIGHT LEFT;;;;
+2575;BOX DRAWINGS LIGHT UP;So;0;ON;;;;;N;FORMS LIGHT UP;;;;
+2576;BOX DRAWINGS LIGHT RIGHT;So;0;ON;;;;;N;FORMS LIGHT RIGHT;;;;
+2577;BOX DRAWINGS LIGHT DOWN;So;0;ON;;;;;N;FORMS LIGHT DOWN;;;;
+2578;BOX DRAWINGS HEAVY LEFT;So;0;ON;;;;;N;FORMS HEAVY LEFT;;;;
+2579;BOX DRAWINGS HEAVY UP;So;0;ON;;;;;N;FORMS HEAVY UP;;;;
+257A;BOX DRAWINGS HEAVY RIGHT;So;0;ON;;;;;N;FORMS HEAVY RIGHT;;;;
+257B;BOX DRAWINGS HEAVY DOWN;So;0;ON;;;;;N;FORMS HEAVY DOWN;;;;
+257C;BOX DRAWINGS LIGHT LEFT AND HEAVY RIGHT;So;0;ON;;;;;N;FORMS LIGHT LEFT AND HEAVY RIGHT;;;;
+257D;BOX DRAWINGS LIGHT UP AND HEAVY DOWN;So;0;ON;;;;;N;FORMS LIGHT UP AND HEAVY DOWN;;;;
+257E;BOX DRAWINGS HEAVY LEFT AND LIGHT RIGHT;So;0;ON;;;;;N;FORMS HEAVY LEFT AND LIGHT RIGHT;;;;
+257F;BOX DRAWINGS HEAVY UP AND LIGHT DOWN;So;0;ON;;;;;N;FORMS HEAVY UP AND LIGHT DOWN;;;;
+2580;UPPER HALF BLOCK;So;0;ON;;;;;N;;;;;
+2581;LOWER ONE EIGHTH BLOCK;So;0;ON;;;;;N;;;;;
+2582;LOWER ONE QUARTER BLOCK;So;0;ON;;;;;N;;;;;
+2583;LOWER THREE EIGHTHS BLOCK;So;0;ON;;;;;N;;;;;
+2584;LOWER HALF BLOCK;So;0;ON;;;;;N;;;;;
+2585;LOWER FIVE EIGHTHS BLOCK;So;0;ON;;;;;N;;;;;
+2586;LOWER THREE QUARTERS BLOCK;So;0;ON;;;;;N;LOWER THREE QUARTER BLOCK;;;;
+2587;LOWER SEVEN EIGHTHS BLOCK;So;0;ON;;;;;N;;;;;
+2588;FULL BLOCK;So;0;ON;;;;;N;;;;;
+2589;LEFT SEVEN EIGHTHS BLOCK;So;0;ON;;;;;N;;;;;
+258A;LEFT THREE QUARTERS BLOCK;So;0;ON;;;;;N;LEFT THREE QUARTER BLOCK;;;;
+258B;LEFT FIVE EIGHTHS BLOCK;So;0;ON;;;;;N;;;;;
+258C;LEFT HALF BLOCK;So;0;ON;;;;;N;;;;;
+258D;LEFT THREE EIGHTHS BLOCK;So;0;ON;;;;;N;;;;;
+258E;LEFT ONE QUARTER BLOCK;So;0;ON;;;;;N;;;;;
+258F;LEFT ONE EIGHTH BLOCK;So;0;ON;;;;;N;;;;;
+2590;RIGHT HALF BLOCK;So;0;ON;;;;;N;;;;;
+2591;LIGHT SHADE;So;0;ON;;;;;N;;;;;
+2592;MEDIUM SHADE;So;0;ON;;;;;N;;;;;
+2593;DARK SHADE;So;0;ON;;;;;N;;;;;
+2594;UPPER ONE EIGHTH BLOCK;So;0;ON;;;;;N;;;;;
+2595;RIGHT ONE EIGHTH BLOCK;So;0;ON;;;;;N;;;;;
+2596;QUADRANT LOWER LEFT;So;0;ON;;;;;N;;;;;
+2597;QUADRANT LOWER RIGHT;So;0;ON;;;;;N;;;;;
+2598;QUADRANT UPPER LEFT;So;0;ON;;;;;N;;;;;
+2599;QUADRANT UPPER LEFT AND LOWER LEFT AND LOWER RIGHT;So;0;ON;;;;;N;;;;;
+259A;QUADRANT UPPER LEFT AND LOWER RIGHT;So;0;ON;;;;;N;;;;;
+259B;QUADRANT UPPER LEFT AND UPPER RIGHT AND LOWER LEFT;So;0;ON;;;;;N;;;;;
+259C;QUADRANT UPPER LEFT AND UPPER RIGHT AND LOWER RIGHT;So;0;ON;;;;;N;;;;;
+259D;QUADRANT UPPER RIGHT;So;0;ON;;;;;N;;;;;
+259E;QUADRANT UPPER RIGHT AND LOWER LEFT;So;0;ON;;;;;N;;;;;
+259F;QUADRANT UPPER RIGHT AND LOWER LEFT AND LOWER RIGHT;So;0;ON;;;;;N;;;;;
+25A0;BLACK SQUARE;So;0;ON;;;;;N;;;;;
+25A1;WHITE SQUARE;So;0;ON;;;;;N;;;;;
+25A2;WHITE SQUARE WITH ROUNDED CORNERS;So;0;ON;;;;;N;;;;;
+25A3;WHITE SQUARE CONTAINING BLACK SMALL SQUARE;So;0;ON;;;;;N;;;;;
+25A4;SQUARE WITH HORIZONTAL FILL;So;0;ON;;;;;N;;;;;
+25A5;SQUARE WITH VERTICAL FILL;So;0;ON;;;;;N;;;;;
+25A6;SQUARE WITH ORTHOGONAL CROSSHATCH FILL;So;0;ON;;;;;N;;;;;
+25A7;SQUARE WITH UPPER LEFT TO LOWER RIGHT FILL;So;0;ON;;;;;N;;;;;
+25A8;SQUARE WITH UPPER RIGHT TO LOWER LEFT FILL;So;0;ON;;;;;N;;;;;
+25A9;SQUARE WITH DIAGONAL CROSSHATCH FILL;So;0;ON;;;;;N;;;;;
+25AA;BLACK SMALL SQUARE;So;0;ON;;;;;N;;;;;
+25AB;WHITE SMALL SQUARE;So;0;ON;;;;;N;;;;;
+25AC;BLACK RECTANGLE;So;0;ON;;;;;N;;;;;
+25AD;WHITE RECTANGLE;So;0;ON;;;;;N;;;;;
+25AE;BLACK VERTICAL RECTANGLE;So;0;ON;;;;;N;;;;;
+25AF;WHITE VERTICAL RECTANGLE;So;0;ON;;;;;N;;;;;
+25B0;BLACK PARALLELOGRAM;So;0;ON;;;;;N;;;;;
+25B1;WHITE PARALLELOGRAM;So;0;ON;;;;;N;;;;;
+25B2;BLACK UP-POINTING TRIANGLE;So;0;ON;;;;;N;BLACK UP POINTING TRIANGLE;;;;
+25B3;WHITE UP-POINTING TRIANGLE;So;0;ON;;;;;N;WHITE UP POINTING TRIANGLE;;;;
+25B4;BLACK UP-POINTING SMALL TRIANGLE;So;0;ON;;;;;N;BLACK UP POINTING SMALL TRIANGLE;;;;
+25B5;WHITE UP-POINTING SMALL TRIANGLE;So;0;ON;;;;;N;WHITE UP POINTING SMALL TRIANGLE;;;;
+25B6;BLACK RIGHT-POINTING TRIANGLE;So;0;ON;;;;;N;BLACK RIGHT POINTING TRIANGLE;;;;
+25B7;WHITE RIGHT-POINTING TRIANGLE;Sm;0;ON;;;;;N;WHITE RIGHT POINTING TRIANGLE;;;;
+25B8;BLACK RIGHT-POINTING SMALL TRIANGLE;So;0;ON;;;;;N;BLACK RIGHT POINTING SMALL TRIANGLE;;;;
+25B9;WHITE RIGHT-POINTING SMALL TRIANGLE;So;0;ON;;;;;N;WHITE RIGHT POINTING SMALL TRIANGLE;;;;
+25BA;BLACK RIGHT-POINTING POINTER;So;0;ON;;;;;N;BLACK RIGHT POINTING POINTER;;;;
+25BB;WHITE RIGHT-POINTING POINTER;So;0;ON;;;;;N;WHITE RIGHT POINTING POINTER;;;;
+25BC;BLACK DOWN-POINTING TRIANGLE;So;0;ON;;;;;N;BLACK DOWN POINTING TRIANGLE;;;;
+25BD;WHITE DOWN-POINTING TRIANGLE;So;0;ON;;;;;N;WHITE DOWN POINTING TRIANGLE;;;;
+25BE;BLACK DOWN-POINTING SMALL TRIANGLE;So;0;ON;;;;;N;BLACK DOWN POINTING SMALL TRIANGLE;;;;
+25BF;WHITE DOWN-POINTING SMALL TRIANGLE;So;0;ON;;;;;N;WHITE DOWN POINTING SMALL TRIANGLE;;;;
+25C0;BLACK LEFT-POINTING TRIANGLE;So;0;ON;;;;;N;BLACK LEFT POINTING TRIANGLE;;;;
+25C1;WHITE LEFT-POINTING TRIANGLE;Sm;0;ON;;;;;N;WHITE LEFT POINTING TRIANGLE;;;;
+25C2;BLACK LEFT-POINTING SMALL TRIANGLE;So;0;ON;;;;;N;BLACK LEFT POINTING SMALL TRIANGLE;;;;
+25C3;WHITE LEFT-POINTING SMALL TRIANGLE;So;0;ON;;;;;N;WHITE LEFT POINTING SMALL TRIANGLE;;;;
+25C4;BLACK LEFT-POINTING POINTER;So;0;ON;;;;;N;BLACK LEFT POINTING POINTER;;;;
+25C5;WHITE LEFT-POINTING POINTER;So;0;ON;;;;;N;WHITE LEFT POINTING POINTER;;;;
+25C6;BLACK DIAMOND;So;0;ON;;;;;N;;;;;
+25C7;WHITE DIAMOND;So;0;ON;;;;;N;;;;;
+25C8;WHITE DIAMOND CONTAINING BLACK SMALL DIAMOND;So;0;ON;;;;;N;;;;;
+25C9;FISHEYE;So;0;ON;;;;;N;;;;;
+25CA;LOZENGE;So;0;ON;;;;;N;;;;;
+25CB;WHITE CIRCLE;So;0;ON;;;;;N;;;;;
+25CC;DOTTED CIRCLE;So;0;ON;;;;;N;;;;;
+25CD;CIRCLE WITH VERTICAL FILL;So;0;ON;;;;;N;;;;;
+25CE;BULLSEYE;So;0;ON;;;;;N;;;;;
+25CF;BLACK CIRCLE;So;0;ON;;;;;N;;;;;
+25D0;CIRCLE WITH LEFT HALF BLACK;So;0;ON;;;;;N;;;;;
+25D1;CIRCLE WITH RIGHT HALF BLACK;So;0;ON;;;;;N;;;;;
+25D2;CIRCLE WITH LOWER HALF BLACK;So;0;ON;;;;;N;;;;;
+25D3;CIRCLE WITH UPPER HALF BLACK;So;0;ON;;;;;N;;;;;
+25D4;CIRCLE WITH UPPER RIGHT QUADRANT BLACK;So;0;ON;;;;;N;;;;;
+25D5;CIRCLE WITH ALL BUT UPPER LEFT QUADRANT BLACK;So;0;ON;;;;;N;;;;;
+25D6;LEFT HALF BLACK CIRCLE;So;0;ON;;;;;N;;;;;
+25D7;RIGHT HALF BLACK CIRCLE;So;0;ON;;;;;N;;;;;
+25D8;INVERSE BULLET;So;0;ON;;;;;N;;;;;
+25D9;INVERSE WHITE CIRCLE;So;0;ON;;;;;N;;;;;
+25DA;UPPER HALF INVERSE WHITE CIRCLE;So;0;ON;;;;;N;;;;;
+25DB;LOWER HALF INVERSE WHITE CIRCLE;So;0;ON;;;;;N;;;;;
+25DC;UPPER LEFT QUADRANT CIRCULAR ARC;So;0;ON;;;;;N;;;;;
+25DD;UPPER RIGHT QUADRANT CIRCULAR ARC;So;0;ON;;;;;N;;;;;
+25DE;LOWER RIGHT QUADRANT CIRCULAR ARC;So;0;ON;;;;;N;;;;;
+25DF;LOWER LEFT QUADRANT CIRCULAR ARC;So;0;ON;;;;;N;;;;;
+25E0;UPPER HALF CIRCLE;So;0;ON;;;;;N;;;;;
+25E1;LOWER HALF CIRCLE;So;0;ON;;;;;N;;;;;
+25E2;BLACK LOWER RIGHT TRIANGLE;So;0;ON;;;;;N;;;;;
+25E3;BLACK LOWER LEFT TRIANGLE;So;0;ON;;;;;N;;;;;
+25E4;BLACK UPPER LEFT TRIANGLE;So;0;ON;;;;;N;;;;;
+25E5;BLACK UPPER RIGHT TRIANGLE;So;0;ON;;;;;N;;;;;
+25E6;WHITE BULLET;So;0;ON;;;;;N;;;;;
+25E7;SQUARE WITH LEFT HALF BLACK;So;0;ON;;;;;N;;;;;
+25E8;SQUARE WITH RIGHT HALF BLACK;So;0;ON;;;;;N;;;;;
+25E9;SQUARE WITH UPPER LEFT DIAGONAL HALF BLACK;So;0;ON;;;;;N;;;;;
+25EA;SQUARE WITH LOWER RIGHT DIAGONAL HALF BLACK;So;0;ON;;;;;N;;;;;
+25EB;WHITE SQUARE WITH VERTICAL BISECTING LINE;So;0;ON;;;;;N;;;;;
+25EC;WHITE UP-POINTING TRIANGLE WITH DOT;So;0;ON;;;;;N;WHITE UP POINTING TRIANGLE WITH DOT;;;;
+25ED;UP-POINTING TRIANGLE WITH LEFT HALF BLACK;So;0;ON;;;;;N;UP POINTING TRIANGLE WITH LEFT HALF BLACK;;;;
+25EE;UP-POINTING TRIANGLE WITH RIGHT HALF BLACK;So;0;ON;;;;;N;UP POINTING TRIANGLE WITH RIGHT HALF BLACK;;;;
+25EF;LARGE CIRCLE;So;0;ON;;;;;N;;;;;
+25F0;WHITE SQUARE WITH UPPER LEFT QUADRANT;So;0;ON;;;;;N;;;;;
+25F1;WHITE SQUARE WITH LOWER LEFT QUADRANT;So;0;ON;;;;;N;;;;;
+25F2;WHITE SQUARE WITH LOWER RIGHT QUADRANT;So;0;ON;;;;;N;;;;;
+25F3;WHITE SQUARE WITH UPPER RIGHT QUADRANT;So;0;ON;;;;;N;;;;;
+25F4;WHITE CIRCLE WITH UPPER LEFT QUADRANT;So;0;ON;;;;;N;;;;;
+25F5;WHITE CIRCLE WITH LOWER LEFT QUADRANT;So;0;ON;;;;;N;;;;;
+25F6;WHITE CIRCLE WITH LOWER RIGHT QUADRANT;So;0;ON;;;;;N;;;;;
+25F7;WHITE CIRCLE WITH UPPER RIGHT QUADRANT;So;0;ON;;;;;N;;;;;
+25F8;UPPER LEFT TRIANGLE;Sm;0;ON;;;;;N;;;;;
+25F9;UPPER RIGHT TRIANGLE;Sm;0;ON;;;;;N;;;;;
+25FA;LOWER LEFT TRIANGLE;Sm;0;ON;;;;;N;;;;;
+25FB;WHITE MEDIUM SQUARE;Sm;0;ON;;;;;N;;;;;
+25FC;BLACK MEDIUM SQUARE;Sm;0;ON;;;;;N;;;;;
+25FD;WHITE MEDIUM SMALL SQUARE;Sm;0;ON;;;;;N;;;;;
+25FE;BLACK MEDIUM SMALL SQUARE;Sm;0;ON;;;;;N;;;;;
+25FF;LOWER RIGHT TRIANGLE;Sm;0;ON;;;;;N;;;;;
+2600;BLACK SUN WITH RAYS;So;0;ON;;;;;N;;;;;
+2601;CLOUD;So;0;ON;;;;;N;;;;;
+2602;UMBRELLA;So;0;ON;;;;;N;;;;;
+2603;SNOWMAN;So;0;ON;;;;;N;;;;;
+2604;COMET;So;0;ON;;;;;N;;;;;
+2605;BLACK STAR;So;0;ON;;;;;N;;;;;
+2606;WHITE STAR;So;0;ON;;;;;N;;;;;
+2607;LIGHTNING;So;0;ON;;;;;N;;;;;
+2608;THUNDERSTORM;So;0;ON;;;;;N;;;;;
+2609;SUN;So;0;ON;;;;;N;;;;;
+260A;ASCENDING NODE;So;0;ON;;;;;N;;;;;
+260B;DESCENDING NODE;So;0;ON;;;;;N;;;;;
+260C;CONJUNCTION;So;0;ON;;;;;N;;;;;
+260D;OPPOSITION;So;0;ON;;;;;N;;;;;
+260E;BLACK TELEPHONE;So;0;ON;;;;;N;;;;;
+260F;WHITE TELEPHONE;So;0;ON;;;;;N;;;;;
+2610;BALLOT BOX;So;0;ON;;;;;N;;;;;
+2611;BALLOT BOX WITH CHECK;So;0;ON;;;;;N;;;;;
+2612;BALLOT BOX WITH X;So;0;ON;;;;;N;;;;;
+2613;SALTIRE;So;0;ON;;;;;N;;;;;
+2614;UMBRELLA WITH RAIN DROPS;So;0;ON;;;;;N;;;;;
+2615;HOT BEVERAGE;So;0;ON;;;;;N;;;;;
+2616;WHITE SHOGI PIECE;So;0;ON;;;;;N;;;;;
+2617;BLACK SHOGI PIECE;So;0;ON;;;;;N;;;;;
+2618;SHAMROCK;So;0;ON;;;;;N;;;;;
+2619;REVERSED ROTATED FLORAL HEART BULLET;So;0;ON;;;;;N;;;;;
+261A;BLACK LEFT POINTING INDEX;So;0;ON;;;;;N;;;;;
+261B;BLACK RIGHT POINTING INDEX;So;0;ON;;;;;N;;;;;
+261C;WHITE LEFT POINTING INDEX;So;0;ON;;;;;N;;;;;
+261D;WHITE UP POINTING INDEX;So;0;ON;;;;;N;;;;;
+261E;WHITE RIGHT POINTING INDEX;So;0;ON;;;;;N;;;;;
+261F;WHITE DOWN POINTING INDEX;So;0;ON;;;;;N;;;;;
+2620;SKULL AND CROSSBONES;So;0;ON;;;;;N;;;;;
+2621;CAUTION SIGN;So;0;ON;;;;;N;;;;;
+2622;RADIOACTIVE SIGN;So;0;ON;;;;;N;;;;;
+2623;BIOHAZARD SIGN;So;0;ON;;;;;N;;;;;
+2624;CADUCEUS;So;0;ON;;;;;N;;;;;
+2625;ANKH;So;0;ON;;;;;N;;;;;
+2626;ORTHODOX CROSS;So;0;ON;;;;;N;;;;;
+2627;CHI RHO;So;0;ON;;;;;N;;;;;
+2628;CROSS OF LORRAINE;So;0;ON;;;;;N;;;;;
+2629;CROSS OF JERUSALEM;So;0;ON;;;;;N;;;;;
+262A;STAR AND CRESCENT;So;0;ON;;;;;N;;;;;
+262B;FARSI SYMBOL;So;0;ON;;;;;N;SYMBOL OF IRAN;;;;
+262C;ADI SHAKTI;So;0;ON;;;;;N;;;;;
+262D;HAMMER AND SICKLE;So;0;ON;;;;;N;;;;;
+262E;PEACE SYMBOL;So;0;ON;;;;;N;;;;;
+262F;YIN YANG;So;0;ON;;;;;N;;;;;
+2630;TRIGRAM FOR HEAVEN;So;0;ON;;;;;N;;;;;
+2631;TRIGRAM FOR LAKE;So;0;ON;;;;;N;;;;;
+2632;TRIGRAM FOR FIRE;So;0;ON;;;;;N;;;;;
+2633;TRIGRAM FOR THUNDER;So;0;ON;;;;;N;;;;;
+2634;TRIGRAM FOR WIND;So;0;ON;;;;;N;;;;;
+2635;TRIGRAM FOR WATER;So;0;ON;;;;;N;;;;;
+2636;TRIGRAM FOR MOUNTAIN;So;0;ON;;;;;N;;;;;
+2637;TRIGRAM FOR EARTH;So;0;ON;;;;;N;;;;;
+2638;WHEEL OF DHARMA;So;0;ON;;;;;N;;;;;
+2639;WHITE FROWNING FACE;So;0;ON;;;;;N;;;;;
+263A;WHITE SMILING FACE;So;0;ON;;;;;N;;;;;
+263B;BLACK SMILING FACE;So;0;ON;;;;;N;;;;;
+263C;WHITE SUN WITH RAYS;So;0;ON;;;;;N;;;;;
+263D;FIRST QUARTER MOON;So;0;ON;;;;;N;;;;;
+263E;LAST QUARTER MOON;So;0;ON;;;;;N;;;;;
+263F;MERCURY;So;0;ON;;;;;N;;;;;
+2640;FEMALE SIGN;So;0;ON;;;;;N;;;;;
+2641;EARTH;So;0;ON;;;;;N;;;;;
+2642;MALE SIGN;So;0;ON;;;;;N;;;;;
+2643;JUPITER;So;0;ON;;;;;N;;;;;
+2644;SATURN;So;0;ON;;;;;N;;;;;
+2645;URANUS;So;0;ON;;;;;N;;;;;
+2646;NEPTUNE;So;0;ON;;;;;N;;;;;
+2647;PLUTO;So;0;ON;;;;;N;;;;;
+2648;ARIES;So;0;ON;;;;;N;;;;;
+2649;TAURUS;So;0;ON;;;;;N;;;;;
+264A;GEMINI;So;0;ON;;;;;N;;;;;
+264B;CANCER;So;0;ON;;;;;N;;;;;
+264C;LEO;So;0;ON;;;;;N;;;;;
+264D;VIRGO;So;0;ON;;;;;N;;;;;
+264E;LIBRA;So;0;ON;;;;;N;;;;;
+264F;SCORPIUS;So;0;ON;;;;;N;;;;;
+2650;SAGITTARIUS;So;0;ON;;;;;N;;;;;
+2651;CAPRICORN;So;0;ON;;;;;N;;;;;
+2652;AQUARIUS;So;0;ON;;;;;N;;;;;
+2653;PISCES;So;0;ON;;;;;N;;;;;
+2654;WHITE CHESS KING;So;0;ON;;;;;N;;;;;
+2655;WHITE CHESS QUEEN;So;0;ON;;;;;N;;;;;
+2656;WHITE CHESS ROOK;So;0;ON;;;;;N;;;;;
+2657;WHITE CHESS BISHOP;So;0;ON;;;;;N;;;;;
+2658;WHITE CHESS KNIGHT;So;0;ON;;;;;N;;;;;
+2659;WHITE CHESS PAWN;So;0;ON;;;;;N;;;;;
+265A;BLACK CHESS KING;So;0;ON;;;;;N;;;;;
+265B;BLACK CHESS QUEEN;So;0;ON;;;;;N;;;;;
+265C;BLACK CHESS ROOK;So;0;ON;;;;;N;;;;;
+265D;BLACK CHESS BISHOP;So;0;ON;;;;;N;;;;;
+265E;BLACK CHESS KNIGHT;So;0;ON;;;;;N;;;;;
+265F;BLACK CHESS PAWN;So;0;ON;;;;;N;;;;;
+2660;BLACK SPADE SUIT;So;0;ON;;;;;N;;;;;
+2661;WHITE HEART SUIT;So;0;ON;;;;;N;;;;;
+2662;WHITE DIAMOND SUIT;So;0;ON;;;;;N;;;;;
+2663;BLACK CLUB SUIT;So;0;ON;;;;;N;;;;;
+2664;WHITE SPADE SUIT;So;0;ON;;;;;N;;;;;
+2665;BLACK HEART SUIT;So;0;ON;;;;;N;;;;;
+2666;BLACK DIAMOND SUIT;So;0;ON;;;;;N;;;;;
+2667;WHITE CLUB SUIT;So;0;ON;;;;;N;;;;;
+2668;HOT SPRINGS;So;0;ON;;;;;N;;;;;
+2669;QUARTER NOTE;So;0;ON;;;;;N;;;;;
+266A;EIGHTH NOTE;So;0;ON;;;;;N;;;;;
+266B;BEAMED EIGHTH NOTES;So;0;ON;;;;;N;BARRED EIGHTH NOTES;;;;
+266C;BEAMED SIXTEENTH NOTES;So;0;ON;;;;;N;BARRED SIXTEENTH NOTES;;;;
+266D;MUSIC FLAT SIGN;So;0;ON;;;;;N;FLAT;;;;
+266E;MUSIC NATURAL SIGN;So;0;ON;;;;;N;NATURAL;;;;
+266F;MUSIC SHARP SIGN;Sm;0;ON;;;;;N;SHARP;;;;
+2670;WEST SYRIAC CROSS;So;0;ON;;;;;N;;;;;
+2671;EAST SYRIAC CROSS;So;0;ON;;;;;N;;;;;
+2672;UNIVERSAL RECYCLING SYMBOL;So;0;ON;;;;;N;;;;;
+2673;RECYCLING SYMBOL FOR TYPE-1 PLASTICS;So;0;ON;;;;;N;;pete;;;
+2674;RECYCLING SYMBOL FOR TYPE-2 PLASTICS;So;0;ON;;;;;N;;hdpe;;;
+2675;RECYCLING SYMBOL FOR TYPE-3 PLASTICS;So;0;ON;;;;;N;;pvc;;;
+2676;RECYCLING SYMBOL FOR TYPE-4 PLASTICS;So;0;ON;;;;;N;;ldpe;;;
+2677;RECYCLING SYMBOL FOR TYPE-5 PLASTICS;So;0;ON;;;;;N;;pp;;;
+2678;RECYCLING SYMBOL FOR TYPE-6 PLASTICS;So;0;ON;;;;;N;;ps;;;
+2679;RECYCLING SYMBOL FOR TYPE-7 PLASTICS;So;0;ON;;;;;N;;other;;;
+267A;RECYCLING SYMBOL FOR GENERIC MATERIALS;So;0;ON;;;;;N;;;;;
+267B;BLACK UNIVERSAL RECYCLING SYMBOL;So;0;ON;;;;;N;;;;;
+267C;RECYCLED PAPER SYMBOL;So;0;ON;;;;;N;;;;;
+267D;PARTIALLY-RECYCLED PAPER SYMBOL;So;0;ON;;;;;N;;;;;
+267E;PERMANENT PAPER SIGN;So;0;ON;;;;;N;;;;;
+267F;WHEELCHAIR SYMBOL;So;0;ON;;;;;N;;;;;
+2680;DIE FACE-1;So;0;ON;;;;;N;;;;;
+2681;DIE FACE-2;So;0;ON;;;;;N;;;;;
+2682;DIE FACE-3;So;0;ON;;;;;N;;;;;
+2683;DIE FACE-4;So;0;ON;;;;;N;;;;;
+2684;DIE FACE-5;So;0;ON;;;;;N;;;;;
+2685;DIE FACE-6;So;0;ON;;;;;N;;;;;
+2686;WHITE CIRCLE WITH DOT RIGHT;So;0;ON;;;;;N;;;;;
+2687;WHITE CIRCLE WITH TWO DOTS;So;0;ON;;;;;N;;;;;
+2688;BLACK CIRCLE WITH WHITE DOT RIGHT;So;0;ON;;;;;N;;;;;
+2689;BLACK CIRCLE WITH TWO WHITE DOTS;So;0;ON;;;;;N;;;;;
+268A;MONOGRAM FOR YANG;So;0;ON;;;;;N;;;;;
+268B;MONOGRAM FOR YIN;So;0;ON;;;;;N;;;;;
+268C;DIGRAM FOR GREATER YANG;So;0;ON;;;;;N;;;;;
+268D;DIGRAM FOR LESSER YIN;So;0;ON;;;;;N;;;;;
+268E;DIGRAM FOR LESSER YANG;So;0;ON;;;;;N;;;;;
+268F;DIGRAM FOR GREATER YIN;So;0;ON;;;;;N;;;;;
+2690;WHITE FLAG;So;0;ON;;;;;N;;;;;
+2691;BLACK FLAG;So;0;ON;;;;;N;;;;;
+2692;HAMMER AND PICK;So;0;ON;;;;;N;;;;;
+2693;ANCHOR;So;0;ON;;;;;N;;;;;
+2694;CROSSED SWORDS;So;0;ON;;;;;N;;;;;
+2695;STAFF OF AESCULAPIUS;So;0;ON;;;;;N;;;;;
+2696;SCALES;So;0;ON;;;;;N;;;;;
+2697;ALEMBIC;So;0;ON;;;;;N;;;;;
+2698;FLOWER;So;0;ON;;;;;N;;;;;
+2699;GEAR;So;0;ON;;;;;N;;;;;
+269A;STAFF OF HERMES;So;0;ON;;;;;N;;;;;
+269B;ATOM SYMBOL;So;0;ON;;;;;N;;;;;
+269C;FLEUR-DE-LIS;So;0;ON;;;;;N;;;;;
+26A0;WARNING SIGN;So;0;ON;;;;;N;;;;;
+26A1;HIGH VOLTAGE SIGN;So;0;ON;;;;;N;;;;;
+26A2;DOUBLED FEMALE SIGN;So;0;ON;;;;;N;;;;;
+26A3;DOUBLED MALE SIGN;So;0;ON;;;;;N;;;;;
+26A4;INTERLOCKED FEMALE AND MALE SIGN;So;0;ON;;;;;N;;;;;
+26A5;MALE AND FEMALE SIGN;So;0;ON;;;;;N;;;;;
+26A6;MALE WITH STROKE SIGN;So;0;ON;;;;;N;;;;;
+26A7;MALE WITH STROKE AND MALE AND FEMALE SIGN;So;0;ON;;;;;N;;;;;
+26A8;VERTICAL MALE WITH STROKE SIGN;So;0;ON;;;;;N;;;;;
+26A9;HORIZONTAL MALE WITH STROKE SIGN;So;0;ON;;;;;N;;;;;
+26AA;MEDIUM WHITE CIRCLE;So;0;ON;;;;;N;;;;;
+26AB;MEDIUM BLACK CIRCLE;So;0;ON;;;;;N;;;;;
+26AC;MEDIUM SMALL WHITE CIRCLE;So;0;L;;;;;N;;;;;
+26AD;MARRIAGE SYMBOL;So;0;ON;;;;;N;;;;;
+26AE;DIVORCE SYMBOL;So;0;ON;;;;;N;;;;;
+26AF;UNMARRIED PARTNERSHIP SYMBOL;So;0;ON;;;;;N;;;;;
+26B0;COFFIN;So;0;ON;;;;;N;;;;;
+26B1;FUNERAL URN;So;0;ON;;;;;N;;;;;
+2701;UPPER BLADE SCISSORS;So;0;ON;;;;;N;;;;;
+2702;BLACK SCISSORS;So;0;ON;;;;;N;;;;;
+2703;LOWER BLADE SCISSORS;So;0;ON;;;;;N;;;;;
+2704;WHITE SCISSORS;So;0;ON;;;;;N;;;;;
+2706;TELEPHONE LOCATION SIGN;So;0;ON;;;;;N;;;;;
+2707;TAPE DRIVE;So;0;ON;;;;;N;;;;;
+2708;AIRPLANE;So;0;ON;;;;;N;;;;;
+2709;ENVELOPE;So;0;ON;;;;;N;;;;;
+270C;VICTORY HAND;So;0;ON;;;;;N;;;;;
+270D;WRITING HAND;So;0;ON;;;;;N;;;;;
+270E;LOWER RIGHT PENCIL;So;0;ON;;;;;N;;;;;
+270F;PENCIL;So;0;ON;;;;;N;;;;;
+2710;UPPER RIGHT PENCIL;So;0;ON;;;;;N;;;;;
+2711;WHITE NIB;So;0;ON;;;;;N;;;;;
+2712;BLACK NIB;So;0;ON;;;;;N;;;;;
+2713;CHECK MARK;So;0;ON;;;;;N;;;;;
+2714;HEAVY CHECK MARK;So;0;ON;;;;;N;;;;;
+2715;MULTIPLICATION X;So;0;ON;;;;;N;;;;;
+2716;HEAVY MULTIPLICATION X;So;0;ON;;;;;N;;;;;
+2717;BALLOT X;So;0;ON;;;;;N;;;;;
+2718;HEAVY BALLOT X;So;0;ON;;;;;N;;;;;
+2719;OUTLINED GREEK CROSS;So;0;ON;;;;;N;;;;;
+271A;HEAVY GREEK CROSS;So;0;ON;;;;;N;;;;;
+271B;OPEN CENTRE CROSS;So;0;ON;;;;;N;OPEN CENTER CROSS;;;;
+271C;HEAVY OPEN CENTRE CROSS;So;0;ON;;;;;N;HEAVY OPEN CENTER CROSS;;;;
+271D;LATIN CROSS;So;0;ON;;;;;N;;;;;
+271E;SHADOWED WHITE LATIN CROSS;So;0;ON;;;;;N;;;;;
+271F;OUTLINED LATIN CROSS;So;0;ON;;;;;N;;;;;
+2720;MALTESE CROSS;So;0;ON;;;;;N;;;;;
+2721;STAR OF DAVID;So;0;ON;;;;;N;;;;;
+2722;FOUR TEARDROP-SPOKED ASTERISK;So;0;ON;;;;;N;;;;;
+2723;FOUR BALLOON-SPOKED ASTERISK;So;0;ON;;;;;N;;;;;
+2724;HEAVY FOUR BALLOON-SPOKED ASTERISK;So;0;ON;;;;;N;;;;;
+2725;FOUR CLUB-SPOKED ASTERISK;So;0;ON;;;;;N;;;;;
+2726;BLACK FOUR POINTED STAR;So;0;ON;;;;;N;;;;;
+2727;WHITE FOUR POINTED STAR;So;0;ON;;;;;N;;;;;
+2729;STRESS OUTLINED WHITE STAR;So;0;ON;;;;;N;;;;;
+272A;CIRCLED WHITE STAR;So;0;ON;;;;;N;;;;;
+272B;OPEN CENTRE BLACK STAR;So;0;ON;;;;;N;OPEN CENTER BLACK STAR;;;;
+272C;BLACK CENTRE WHITE STAR;So;0;ON;;;;;N;BLACK CENTER WHITE STAR;;;;
+272D;OUTLINED BLACK STAR;So;0;ON;;;;;N;;;;;
+272E;HEAVY OUTLINED BLACK STAR;So;0;ON;;;;;N;;;;;
+272F;PINWHEEL STAR;So;0;ON;;;;;N;;;;;
+2730;SHADOWED WHITE STAR;So;0;ON;;;;;N;;;;;
+2731;HEAVY ASTERISK;So;0;ON;;;;;N;;;;;
+2732;OPEN CENTRE ASTERISK;So;0;ON;;;;;N;OPEN CENTER ASTERISK;;;;
+2733;EIGHT SPOKED ASTERISK;So;0;ON;;;;;N;;;;;
+2734;EIGHT POINTED BLACK STAR;So;0;ON;;;;;N;;;;;
+2735;EIGHT POINTED PINWHEEL STAR;So;0;ON;;;;;N;;;;;
+2736;SIX POINTED BLACK STAR;So;0;ON;;;;;N;;;;;
+2737;EIGHT POINTED RECTILINEAR BLACK STAR;So;0;ON;;;;;N;;;;;
+2738;HEAVY EIGHT POINTED RECTILINEAR BLACK STAR;So;0;ON;;;;;N;;;;;
+2739;TWELVE POINTED BLACK STAR;So;0;ON;;;;;N;;;;;
+273A;SIXTEEN POINTED ASTERISK;So;0;ON;;;;;N;;;;;
+273B;TEARDROP-SPOKED ASTERISK;So;0;ON;;;;;N;;;;;
+273C;OPEN CENTRE TEARDROP-SPOKED ASTERISK;So;0;ON;;;;;N;OPEN CENTER TEARDROP-SPOKED ASTERISK;;;;
+273D;HEAVY TEARDROP-SPOKED ASTERISK;So;0;ON;;;;;N;;;;;
+273E;SIX PETALLED BLACK AND WHITE FLORETTE;So;0;ON;;;;;N;;;;;
+273F;BLACK FLORETTE;So;0;ON;;;;;N;;;;;
+2740;WHITE FLORETTE;So;0;ON;;;;;N;;;;;
+2741;EIGHT PETALLED OUTLINED BLACK FLORETTE;So;0;ON;;;;;N;;;;;
+2742;CIRCLED OPEN CENTRE EIGHT POINTED STAR;So;0;ON;;;;;N;CIRCLED OPEN CENTER EIGHT POINTED STAR;;;;
+2743;HEAVY TEARDROP-SPOKED PINWHEEL ASTERISK;So;0;ON;;;;;N;;;;;
+2744;SNOWFLAKE;So;0;ON;;;;;N;;;;;
+2745;TIGHT TRIFOLIATE SNOWFLAKE;So;0;ON;;;;;N;;;;;
+2746;HEAVY CHEVRON SNOWFLAKE;So;0;ON;;;;;N;;;;;
+2747;SPARKLE;So;0;ON;;;;;N;;;;;
+2748;HEAVY SPARKLE;So;0;ON;;;;;N;;;;;
+2749;BALLOON-SPOKED ASTERISK;So;0;ON;;;;;N;;;;;
+274A;EIGHT TEARDROP-SPOKED PROPELLER ASTERISK;So;0;ON;;;;;N;;;;;
+274B;HEAVY EIGHT TEARDROP-SPOKED PROPELLER ASTERISK;So;0;ON;;;;;N;;;;;
+274D;SHADOWED WHITE CIRCLE;So;0;ON;;;;;N;;;;;
+274F;LOWER RIGHT DROP-SHADOWED WHITE SQUARE;So;0;ON;;;;;N;;;;;
+2750;UPPER RIGHT DROP-SHADOWED WHITE SQUARE;So;0;ON;;;;;N;;;;;
+2751;LOWER RIGHT SHADOWED WHITE SQUARE;So;0;ON;;;;;N;;;;;
+2752;UPPER RIGHT SHADOWED WHITE SQUARE;So;0;ON;;;;;N;;;;;
+2756;BLACK DIAMOND MINUS WHITE X;So;0;ON;;;;;N;;;;;
+2758;LIGHT VERTICAL BAR;So;0;ON;;;;;N;;;;;
+2759;MEDIUM VERTICAL BAR;So;0;ON;;;;;N;;;;;
+275A;HEAVY VERTICAL BAR;So;0;ON;;;;;N;;;;;
+275B;HEAVY SINGLE TURNED COMMA QUOTATION MARK ORNAMENT;So;0;ON;;;;;N;;;;;
+275C;HEAVY SINGLE COMMA QUOTATION MARK ORNAMENT;So;0;ON;;;;;N;;;;;
+275D;HEAVY DOUBLE TURNED COMMA QUOTATION MARK ORNAMENT;So;0;ON;;;;;N;;;;;
+275E;HEAVY DOUBLE COMMA QUOTATION MARK ORNAMENT;So;0;ON;;;;;N;;;;;
+2761;CURVED STEM PARAGRAPH SIGN ORNAMENT;So;0;ON;;;;;N;;;;;
+2762;HEAVY EXCLAMATION MARK ORNAMENT;So;0;ON;;;;;N;;;;;
+2763;HEAVY HEART EXCLAMATION MARK ORNAMENT;So;0;ON;;;;;N;;;;;
+2764;HEAVY BLACK HEART;So;0;ON;;;;;N;;;;;
+2765;ROTATED HEAVY BLACK HEART BULLET;So;0;ON;;;;;N;;;;;
+2766;FLORAL HEART;So;0;ON;;;;;N;;;;;
+2767;ROTATED FLORAL HEART BULLET;So;0;ON;;;;;N;;;;;
+2768;MEDIUM LEFT PARENTHESIS ORNAMENT;Ps;0;ON;;;;;Y;;;;;
+2769;MEDIUM RIGHT PARENTHESIS ORNAMENT;Pe;0;ON;;;;;Y;;;;;
+276A;MEDIUM FLATTENED LEFT PARENTHESIS ORNAMENT;Ps;0;ON;;;;;Y;;;;;
+276B;MEDIUM FLATTENED RIGHT PARENTHESIS ORNAMENT;Pe;0;ON;;;;;Y;;;;;
+276C;MEDIUM LEFT-POINTING ANGLE BRACKET ORNAMENT;Ps;0;ON;;;;;Y;;;;;
+276D;MEDIUM RIGHT-POINTING ANGLE BRACKET ORNAMENT;Pe;0;ON;;;;;Y;;;;;
+276E;HEAVY LEFT-POINTING ANGLE QUOTATION MARK ORNAMENT;Ps;0;ON;;;;;Y;;;;;
+276F;HEAVY RIGHT-POINTING ANGLE QUOTATION MARK ORNAMENT;Pe;0;ON;;;;;Y;;;;;
+2770;HEAVY LEFT-POINTING ANGLE BRACKET ORNAMENT;Ps;0;ON;;;;;Y;;;;;
+2771;HEAVY RIGHT-POINTING ANGLE BRACKET ORNAMENT;Pe;0;ON;;;;;Y;;;;;
+2772;LIGHT LEFT TORTOISE SHELL BRACKET ORNAMENT;Ps;0;ON;;;;;Y;;;;;
+2773;LIGHT RIGHT TORTOISE SHELL BRACKET ORNAMENT;Pe;0;ON;;;;;Y;;;;;
+2774;MEDIUM LEFT CURLY BRACKET ORNAMENT;Ps;0;ON;;;;;Y;;;;;
+2775;MEDIUM RIGHT CURLY BRACKET ORNAMENT;Pe;0;ON;;;;;Y;;;;;
+2776;DINGBAT NEGATIVE CIRCLED DIGIT ONE;No;0;ON;;;1;1;N;INVERSE CIRCLED DIGIT ONE;;;;
+2777;DINGBAT NEGATIVE CIRCLED DIGIT TWO;No;0;ON;;;2;2;N;INVERSE CIRCLED DIGIT TWO;;;;
+2778;DINGBAT NEGATIVE CIRCLED DIGIT THREE;No;0;ON;;;3;3;N;INVERSE CIRCLED DIGIT THREE;;;;
+2779;DINGBAT NEGATIVE CIRCLED DIGIT FOUR;No;0;ON;;;4;4;N;INVERSE CIRCLED DIGIT FOUR;;;;
+277A;DINGBAT NEGATIVE CIRCLED DIGIT FIVE;No;0;ON;;;5;5;N;INVERSE CIRCLED DIGIT FIVE;;;;
+277B;DINGBAT NEGATIVE CIRCLED DIGIT SIX;No;0;ON;;;6;6;N;INVERSE CIRCLED DIGIT SIX;;;;
+277C;DINGBAT NEGATIVE CIRCLED DIGIT SEVEN;No;0;ON;;;7;7;N;INVERSE CIRCLED DIGIT SEVEN;;;;
+277D;DINGBAT NEGATIVE CIRCLED DIGIT EIGHT;No;0;ON;;;8;8;N;INVERSE CIRCLED DIGIT EIGHT;;;;
+277E;DINGBAT NEGATIVE CIRCLED DIGIT NINE;No;0;ON;;;9;9;N;INVERSE CIRCLED DIGIT NINE;;;;
+277F;DINGBAT NEGATIVE CIRCLED NUMBER TEN;No;0;ON;;;;10;N;INVERSE CIRCLED NUMBER TEN;;;;
+2780;DINGBAT CIRCLED SANS-SERIF DIGIT ONE;No;0;ON;;;1;1;N;CIRCLED SANS-SERIF DIGIT ONE;;;;
+2781;DINGBAT CIRCLED SANS-SERIF DIGIT TWO;No;0;ON;;;2;2;N;CIRCLED SANS-SERIF DIGIT TWO;;;;
+2782;DINGBAT CIRCLED SANS-SERIF DIGIT THREE;No;0;ON;;;3;3;N;CIRCLED SANS-SERIF DIGIT THREE;;;;
+2783;DINGBAT CIRCLED SANS-SERIF DIGIT FOUR;No;0;ON;;;4;4;N;CIRCLED SANS-SERIF DIGIT FOUR;;;;
+2784;DINGBAT CIRCLED SANS-SERIF DIGIT FIVE;No;0;ON;;;5;5;N;CIRCLED SANS-SERIF DIGIT FIVE;;;;
+2785;DINGBAT CIRCLED SANS-SERIF DIGIT SIX;No;0;ON;;;6;6;N;CIRCLED SANS-SERIF DIGIT SIX;;;;
+2786;DINGBAT CIRCLED SANS-SERIF DIGIT SEVEN;No;0;ON;;;7;7;N;CIRCLED SANS-SERIF DIGIT SEVEN;;;;
+2787;DINGBAT CIRCLED SANS-SERIF DIGIT EIGHT;No;0;ON;;;8;8;N;CIRCLED SANS-SERIF DIGIT EIGHT;;;;
+2788;DINGBAT CIRCLED SANS-SERIF DIGIT NINE;No;0;ON;;;9;9;N;CIRCLED SANS-SERIF DIGIT NINE;;;;
+2789;DINGBAT CIRCLED SANS-SERIF NUMBER TEN;No;0;ON;;;;10;N;CIRCLED SANS-SERIF NUMBER TEN;;;;
+278A;DINGBAT NEGATIVE CIRCLED SANS-SERIF DIGIT ONE;No;0;ON;;;1;1;N;INVERSE CIRCLED SANS-SERIF DIGIT ONE;;;;
+278B;DINGBAT NEGATIVE CIRCLED SANS-SERIF DIGIT TWO;No;0;ON;;;2;2;N;INVERSE CIRCLED SANS-SERIF DIGIT TWO;;;;
+278C;DINGBAT NEGATIVE CIRCLED SANS-SERIF DIGIT THREE;No;0;ON;;;3;3;N;INVERSE CIRCLED SANS-SERIF DIGIT THREE;;;;
+278D;DINGBAT NEGATIVE CIRCLED SANS-SERIF DIGIT FOUR;No;0;ON;;;4;4;N;INVERSE CIRCLED SANS-SERIF DIGIT FOUR;;;;
+278E;DINGBAT NEGATIVE CIRCLED SANS-SERIF DIGIT FIVE;No;0;ON;;;5;5;N;INVERSE CIRCLED SANS-SERIF DIGIT FIVE;;;;
+278F;DINGBAT NEGATIVE CIRCLED SANS-SERIF DIGIT SIX;No;0;ON;;;6;6;N;INVERSE CIRCLED SANS-SERIF DIGIT SIX;;;;
+2790;DINGBAT NEGATIVE CIRCLED SANS-SERIF DIGIT SEVEN;No;0;ON;;;7;7;N;INVERSE CIRCLED SANS-SERIF DIGIT SEVEN;;;;
+2791;DINGBAT NEGATIVE CIRCLED SANS-SERIF DIGIT EIGHT;No;0;ON;;;8;8;N;INVERSE CIRCLED SANS-SERIF DIGIT EIGHT;;;;
+2792;DINGBAT NEGATIVE CIRCLED SANS-SERIF DIGIT NINE;No;0;ON;;;9;9;N;INVERSE CIRCLED SANS-SERIF DIGIT NINE;;;;
+2793;DINGBAT NEGATIVE CIRCLED SANS-SERIF NUMBER TEN;No;0;ON;;;;10;N;INVERSE CIRCLED SANS-SERIF NUMBER TEN;;;;
+2794;HEAVY WIDE-HEADED RIGHTWARDS ARROW;So;0;ON;;;;;N;HEAVY WIDE-HEADED RIGHT ARROW;;;;
+2798;HEAVY SOUTH EAST ARROW;So;0;ON;;;;;N;HEAVY LOWER RIGHT ARROW;;;;
+2799;HEAVY RIGHTWARDS ARROW;So;0;ON;;;;;N;HEAVY RIGHT ARROW;;;;
+279A;HEAVY NORTH EAST ARROW;So;0;ON;;;;;N;HEAVY UPPER RIGHT ARROW;;;;
+279B;DRAFTING POINT RIGHTWARDS ARROW;So;0;ON;;;;;N;DRAFTING POINT RIGHT ARROW;;;;
+279C;HEAVY ROUND-TIPPED RIGHTWARDS ARROW;So;0;ON;;;;;N;HEAVY ROUND-TIPPED RIGHT ARROW;;;;
+279D;TRIANGLE-HEADED RIGHTWARDS ARROW;So;0;ON;;;;;N;TRIANGLE-HEADED RIGHT ARROW;;;;
+279E;HEAVY TRIANGLE-HEADED RIGHTWARDS ARROW;So;0;ON;;;;;N;HEAVY TRIANGLE-HEADED RIGHT ARROW;;;;
+279F;DASHED TRIANGLE-HEADED RIGHTWARDS ARROW;So;0;ON;;;;;N;DASHED TRIANGLE-HEADED RIGHT ARROW;;;;
+27A0;HEAVY DASHED TRIANGLE-HEADED RIGHTWARDS ARROW;So;0;ON;;;;;N;HEAVY DASHED TRIANGLE-HEADED RIGHT ARROW;;;;
+27A1;BLACK RIGHTWARDS ARROW;So;0;ON;;;;;N;BLACK RIGHT ARROW;;;;
+27A2;THREE-D TOP-LIGHTED RIGHTWARDS ARROWHEAD;So;0;ON;;;;;N;THREE-D TOP-LIGHTED RIGHT ARROWHEAD;;;;
+27A3;THREE-D BOTTOM-LIGHTED RIGHTWARDS ARROWHEAD;So;0;ON;;;;;N;THREE-D BOTTOM-LIGHTED RIGHT ARROWHEAD;;;;
+27A4;BLACK RIGHTWARDS ARROWHEAD;So;0;ON;;;;;N;BLACK RIGHT ARROWHEAD;;;;
+27A5;HEAVY BLACK CURVED DOWNWARDS AND RIGHTWARDS ARROW;So;0;ON;;;;;N;HEAVY BLACK CURVED DOWN AND RIGHT ARROW;;;;
+27A6;HEAVY BLACK CURVED UPWARDS AND RIGHTWARDS ARROW;So;0;ON;;;;;N;HEAVY BLACK CURVED UP AND RIGHT ARROW;;;;
+27A7;SQUAT BLACK RIGHTWARDS ARROW;So;0;ON;;;;;N;SQUAT BLACK RIGHT ARROW;;;;
+27A8;HEAVY CONCAVE-POINTED BLACK RIGHTWARDS ARROW;So;0;ON;;;;;N;HEAVY CONCAVE-POINTED BLACK RIGHT ARROW;;;;
+27A9;RIGHT-SHADED WHITE RIGHTWARDS ARROW;So;0;ON;;;;;N;RIGHT-SHADED WHITE RIGHT ARROW;;;;
+27AA;LEFT-SHADED WHITE RIGHTWARDS ARROW;So;0;ON;;;;;N;LEFT-SHADED WHITE RIGHT ARROW;;;;
+27AB;BACK-TILTED SHADOWED WHITE RIGHTWARDS ARROW;So;0;ON;;;;;N;BACK-TILTED SHADOWED WHITE RIGHT ARROW;;;;
+27AC;FRONT-TILTED SHADOWED WHITE RIGHTWARDS ARROW;So;0;ON;;;;;N;FRONT-TILTED SHADOWED WHITE RIGHT ARROW;;;;
+27AD;HEAVY LOWER RIGHT-SHADOWED WHITE RIGHTWARDS ARROW;So;0;ON;;;;;N;HEAVY LOWER RIGHT-SHADOWED WHITE RIGHT ARROW;;;;
+27AE;HEAVY UPPER RIGHT-SHADOWED WHITE RIGHTWARDS ARROW;So;0;ON;;;;;N;HEAVY UPPER RIGHT-SHADOWED WHITE RIGHT ARROW;;;;
+27AF;NOTCHED LOWER RIGHT-SHADOWED WHITE RIGHTWARDS ARROW;So;0;ON;;;;;N;NOTCHED LOWER RIGHT-SHADOWED WHITE RIGHT ARROW;;;;
+27B1;NOTCHED UPPER RIGHT-SHADOWED WHITE RIGHTWARDS ARROW;So;0;ON;;;;;N;NOTCHED UPPER RIGHT-SHADOWED WHITE RIGHT ARROW;;;;
+27B2;CIRCLED HEAVY WHITE RIGHTWARDS ARROW;So;0;ON;;;;;N;CIRCLED HEAVY WHITE RIGHT ARROW;;;;
+27B3;WHITE-FEATHERED RIGHTWARDS ARROW;So;0;ON;;;;;N;WHITE-FEATHERED RIGHT ARROW;;;;
+27B4;BLACK-FEATHERED SOUTH EAST ARROW;So;0;ON;;;;;N;BLACK-FEATHERED LOWER RIGHT ARROW;;;;
+27B5;BLACK-FEATHERED RIGHTWARDS ARROW;So;0;ON;;;;;N;BLACK-FEATHERED RIGHT ARROW;;;;
+27B6;BLACK-FEATHERED NORTH EAST ARROW;So;0;ON;;;;;N;BLACK-FEATHERED UPPER RIGHT ARROW;;;;
+27B7;HEAVY BLACK-FEATHERED SOUTH EAST ARROW;So;0;ON;;;;;N;HEAVY BLACK-FEATHERED LOWER RIGHT ARROW;;;;
+27B8;HEAVY BLACK-FEATHERED RIGHTWARDS ARROW;So;0;ON;;;;;N;HEAVY BLACK-FEATHERED RIGHT ARROW;;;;
+27B9;HEAVY BLACK-FEATHERED NORTH EAST ARROW;So;0;ON;;;;;N;HEAVY BLACK-FEATHERED UPPER RIGHT ARROW;;;;
+27BA;TEARDROP-BARBED RIGHTWARDS ARROW;So;0;ON;;;;;N;TEARDROP-BARBED RIGHT ARROW;;;;
+27BB;HEAVY TEARDROP-SHANKED RIGHTWARDS ARROW;So;0;ON;;;;;N;HEAVY TEARDROP-SHANKED RIGHT ARROW;;;;
+27BC;WEDGE-TAILED RIGHTWARDS ARROW;So;0;ON;;;;;N;WEDGE-TAILED RIGHT ARROW;;;;
+27BD;HEAVY WEDGE-TAILED RIGHTWARDS ARROW;So;0;ON;;;;;N;HEAVY WEDGE-TAILED RIGHT ARROW;;;;
+27BE;OPEN-OUTLINED RIGHTWARDS ARROW;So;0;ON;;;;;N;OPEN-OUTLINED RIGHT ARROW;;;;
+27C0;THREE DIMENSIONAL ANGLE;Sm;0;ON;;;;;Y;;;;;
+27C1;WHITE TRIANGLE CONTAINING SMALL WHITE TRIANGLE;Sm;0;ON;;;;;N;;;;;
+27C2;PERPENDICULAR;Sm;0;ON;;;;;N;;;;;
+27C3;OPEN SUBSET;Sm;0;ON;;;;;Y;;;;;
+27C4;OPEN SUPERSET;Sm;0;ON;;;;;Y;;;;;
+27C5;LEFT S-SHAPED BAG DELIMITER;Ps;0;ON;;;;;Y;;;;;
+27C6;RIGHT S-SHAPED BAG DELIMITER;Pe;0;ON;;;;;Y;;;;;
+27D0;WHITE DIAMOND WITH CENTRED DOT;Sm;0;ON;;;;;N;;;;;
+27D1;AND WITH DOT;Sm;0;ON;;;;;N;;;;;
+27D2;ELEMENT OF OPENING UPWARDS;Sm;0;ON;;;;;N;;;;;
+27D3;LOWER RIGHT CORNER WITH DOT;Sm;0;ON;;;;;Y;;;;;
+27D4;UPPER LEFT CORNER WITH DOT;Sm;0;ON;;;;;Y;;;;;
+27D5;LEFT OUTER JOIN;Sm;0;ON;;;;;Y;;;;;
+27D6;RIGHT OUTER JOIN;Sm;0;ON;;;;;Y;;;;;
+27D7;FULL OUTER JOIN;Sm;0;ON;;;;;N;;;;;
+27D8;LARGE UP TACK;Sm;0;ON;;;;;N;;;;;
+27D9;LARGE DOWN TACK;Sm;0;ON;;;;;N;;;;;
+27DA;LEFT AND RIGHT DOUBLE TURNSTILE;Sm;0;ON;;;;;N;;;;;
+27DB;LEFT AND RIGHT TACK;Sm;0;ON;;;;;N;;;;;
+27DC;LEFT MULTIMAP;Sm;0;ON;;;;;Y;;;;;
+27DD;LONG RIGHT TACK;Sm;0;ON;;;;;Y;;;;;
+27DE;LONG LEFT TACK;Sm;0;ON;;;;;Y;;;;;
+27DF;UP TACK WITH CIRCLE ABOVE;Sm;0;ON;;;;;N;;;;;
+27E0;LOZENGE DIVIDED BY HORIZONTAL RULE;Sm;0;ON;;;;;N;;;;;
+27E1;WHITE CONCAVE-SIDED DIAMOND;Sm;0;ON;;;;;N;;;;;
+27E2;WHITE CONCAVE-SIDED DIAMOND WITH LEFTWARDS TICK;Sm;0;ON;;;;;Y;;;;;
+27E3;WHITE CONCAVE-SIDED DIAMOND WITH RIGHTWARDS TICK;Sm;0;ON;;;;;Y;;;;;
+27E4;WHITE SQUARE WITH LEFTWARDS TICK;Sm;0;ON;;;;;Y;;;;;
+27E5;WHITE SQUARE WITH RIGHTWARDS TICK;Sm;0;ON;;;;;Y;;;;;
+27E6;MATHEMATICAL LEFT WHITE SQUARE BRACKET;Ps;0;ON;;;;;Y;;;;;
+27E7;MATHEMATICAL RIGHT WHITE SQUARE BRACKET;Pe;0;ON;;;;;Y;;;;;
+27E8;MATHEMATICAL LEFT ANGLE BRACKET;Ps;0;ON;;;;;Y;;;;;
+27E9;MATHEMATICAL RIGHT ANGLE BRACKET;Pe;0;ON;;;;;Y;;;;;
+27EA;MATHEMATICAL LEFT DOUBLE ANGLE BRACKET;Ps;0;ON;;;;;Y;;;;;
+27EB;MATHEMATICAL RIGHT DOUBLE ANGLE BRACKET;Pe;0;ON;;;;;Y;;;;;
+27F0;UPWARDS QUADRUPLE ARROW;Sm;0;ON;;;;;N;;;;;
+27F1;DOWNWARDS QUADRUPLE ARROW;Sm;0;ON;;;;;N;;;;;
+27F2;ANTICLOCKWISE GAPPED CIRCLE ARROW;Sm;0;ON;;;;;N;;;;;
+27F3;CLOCKWISE GAPPED CIRCLE ARROW;Sm;0;ON;;;;;N;;;;;
+27F4;RIGHT ARROW WITH CIRCLED PLUS;Sm;0;ON;;;;;N;;;;;
+27F5;LONG LEFTWARDS ARROW;Sm;0;ON;;;;;N;;;;;
+27F6;LONG RIGHTWARDS ARROW;Sm;0;ON;;;;;N;;;;;
+27F7;LONG LEFT RIGHT ARROW;Sm;0;ON;;;;;N;;;;;
+27F8;LONG LEFTWARDS DOUBLE ARROW;Sm;0;ON;;;;;N;;;;;
+27F9;LONG RIGHTWARDS DOUBLE ARROW;Sm;0;ON;;;;;N;;;;;
+27FA;LONG LEFT RIGHT DOUBLE ARROW;Sm;0;ON;;;;;N;;;;;
+27FB;LONG LEFTWARDS ARROW FROM BAR;Sm;0;ON;;;;;N;;;;;
+27FC;LONG RIGHTWARDS ARROW FROM BAR;Sm;0;ON;;;;;N;;;;;
+27FD;LONG LEFTWARDS DOUBLE ARROW FROM BAR;Sm;0;ON;;;;;N;;;;;
+27FE;LONG RIGHTWARDS DOUBLE ARROW FROM BAR;Sm;0;ON;;;;;N;;;;;
+27FF;LONG RIGHTWARDS SQUIGGLE ARROW;Sm;0;ON;;;;;N;;;;;
+2800;BRAILLE PATTERN BLANK;So;0;L;;;;;N;;;;;
+2801;BRAILLE PATTERN DOTS-1;So;0;L;;;;;N;;;;;
+2802;BRAILLE PATTERN DOTS-2;So;0;L;;;;;N;;;;;
+2803;BRAILLE PATTERN DOTS-12;So;0;L;;;;;N;;;;;
+2804;BRAILLE PATTERN DOTS-3;So;0;L;;;;;N;;;;;
+2805;BRAILLE PATTERN DOTS-13;So;0;L;;;;;N;;;;;
+2806;BRAILLE PATTERN DOTS-23;So;0;L;;;;;N;;;;;
+2807;BRAILLE PATTERN DOTS-123;So;0;L;;;;;N;;;;;
+2808;BRAILLE PATTERN DOTS-4;So;0;L;;;;;N;;;;;
+2809;BRAILLE PATTERN DOTS-14;So;0;L;;;;;N;;;;;
+280A;BRAILLE PATTERN DOTS-24;So;0;L;;;;;N;;;;;
+280B;BRAILLE PATTERN DOTS-124;So;0;L;;;;;N;;;;;
+280C;BRAILLE PATTERN DOTS-34;So;0;L;;;;;N;;;;;
+280D;BRAILLE PATTERN DOTS-134;So;0;L;;;;;N;;;;;
+280E;BRAILLE PATTERN DOTS-234;So;0;L;;;;;N;;;;;
+280F;BRAILLE PATTERN DOTS-1234;So;0;L;;;;;N;;;;;
+2810;BRAILLE PATTERN DOTS-5;So;0;L;;;;;N;;;;;
+2811;BRAILLE PATTERN DOTS-15;So;0;L;;;;;N;;;;;
+2812;BRAILLE PATTERN DOTS-25;So;0;L;;;;;N;;;;;
+2813;BRAILLE PATTERN DOTS-125;So;0;L;;;;;N;;;;;
+2814;BRAILLE PATTERN DOTS-35;So;0;L;;;;;N;;;;;
+2815;BRAILLE PATTERN DOTS-135;So;0;L;;;;;N;;;;;
+2816;BRAILLE PATTERN DOTS-235;So;0;L;;;;;N;;;;;
+2817;BRAILLE PATTERN DOTS-1235;So;0;L;;;;;N;;;;;
+2818;BRAILLE PATTERN DOTS-45;So;0;L;;;;;N;;;;;
+2819;BRAILLE PATTERN DOTS-145;So;0;L;;;;;N;;;;;
+281A;BRAILLE PATTERN DOTS-245;So;0;L;;;;;N;;;;;
+281B;BRAILLE PATTERN DOTS-1245;So;0;L;;;;;N;;;;;
+281C;BRAILLE PATTERN DOTS-345;So;0;L;;;;;N;;;;;
+281D;BRAILLE PATTERN DOTS-1345;So;0;L;;;;;N;;;;;
+281E;BRAILLE PATTERN DOTS-2345;So;0;L;;;;;N;;;;;
+281F;BRAILLE PATTERN DOTS-12345;So;0;L;;;;;N;;;;;
+2820;BRAILLE PATTERN DOTS-6;So;0;L;;;;;N;;;;;
+2821;BRAILLE PATTERN DOTS-16;So;0;L;;;;;N;;;;;
+2822;BRAILLE PATTERN DOTS-26;So;0;L;;;;;N;;;;;
+2823;BRAILLE PATTERN DOTS-126;So;0;L;;;;;N;;;;;
+2824;BRAILLE PATTERN DOTS-36;So;0;L;;;;;N;;;;;
+2825;BRAILLE PATTERN DOTS-136;So;0;L;;;;;N;;;;;
+2826;BRAILLE PATTERN DOTS-236;So;0;L;;;;;N;;;;;
+2827;BRAILLE PATTERN DOTS-1236;So;0;L;;;;;N;;;;;
+2828;BRAILLE PATTERN DOTS-46;So;0;L;;;;;N;;;;;
+2829;BRAILLE PATTERN DOTS-146;So;0;L;;;;;N;;;;;
+282A;BRAILLE PATTERN DOTS-246;So;0;L;;;;;N;;;;;
+282B;BRAILLE PATTERN DOTS-1246;So;0;L;;;;;N;;;;;
+282C;BRAILLE PATTERN DOTS-346;So;0;L;;;;;N;;;;;
+282D;BRAILLE PATTERN DOTS-1346;So;0;L;;;;;N;;;;;
+282E;BRAILLE PATTERN DOTS-2346;So;0;L;;;;;N;;;;;
+282F;BRAILLE PATTERN DOTS-12346;So;0;L;;;;;N;;;;;
+2830;BRAILLE PATTERN DOTS-56;So;0;L;;;;;N;;;;;
+2831;BRAILLE PATTERN DOTS-156;So;0;L;;;;;N;;;;;
+2832;BRAILLE PATTERN DOTS-256;So;0;L;;;;;N;;;;;
+2833;BRAILLE PATTERN DOTS-1256;So;0;L;;;;;N;;;;;
+2834;BRAILLE PATTERN DOTS-356;So;0;L;;;;;N;;;;;
+2835;BRAILLE PATTERN DOTS-1356;So;0;L;;;;;N;;;;;
+2836;BRAILLE PATTERN DOTS-2356;So;0;L;;;;;N;;;;;
+2837;BRAILLE PATTERN DOTS-12356;So;0;L;;;;;N;;;;;
+2838;BRAILLE PATTERN DOTS-456;So;0;L;;;;;N;;;;;
+2839;BRAILLE PATTERN DOTS-1456;So;0;L;;;;;N;;;;;
+283A;BRAILLE PATTERN DOTS-2456;So;0;L;;;;;N;;;;;
+283B;BRAILLE PATTERN DOTS-12456;So;0;L;;;;;N;;;;;
+283C;BRAILLE PATTERN DOTS-3456;So;0;L;;;;;N;;;;;
+283D;BRAILLE PATTERN DOTS-13456;So;0;L;;;;;N;;;;;
+283E;BRAILLE PATTERN DOTS-23456;So;0;L;;;;;N;;;;;
+283F;BRAILLE PATTERN DOTS-123456;So;0;L;;;;;N;;;;;
+2840;BRAILLE PATTERN DOTS-7;So;0;L;;;;;N;;;;;
+2841;BRAILLE PATTERN DOTS-17;So;0;L;;;;;N;;;;;
+2842;BRAILLE PATTERN DOTS-27;So;0;L;;;;;N;;;;;
+2843;BRAILLE PATTERN DOTS-127;So;0;L;;;;;N;;;;;
+2844;BRAILLE PATTERN DOTS-37;So;0;L;;;;;N;;;;;
+2845;BRAILLE PATTERN DOTS-137;So;0;L;;;;;N;;;;;
+2846;BRAILLE PATTERN DOTS-237;So;0;L;;;;;N;;;;;
+2847;BRAILLE PATTERN DOTS-1237;So;0;L;;;;;N;;;;;
+2848;BRAILLE PATTERN DOTS-47;So;0;L;;;;;N;;;;;
+2849;BRAILLE PATTERN DOTS-147;So;0;L;;;;;N;;;;;
+284A;BRAILLE PATTERN DOTS-247;So;0;L;;;;;N;;;;;
+284B;BRAILLE PATTERN DOTS-1247;So;0;L;;;;;N;;;;;
+284C;BRAILLE PATTERN DOTS-347;So;0;L;;;;;N;;;;;
+284D;BRAILLE PATTERN DOTS-1347;So;0;L;;;;;N;;;;;
+284E;BRAILLE PATTERN DOTS-2347;So;0;L;;;;;N;;;;;
+284F;BRAILLE PATTERN DOTS-12347;So;0;L;;;;;N;;;;;
+2850;BRAILLE PATTERN DOTS-57;So;0;L;;;;;N;;;;;
+2851;BRAILLE PATTERN DOTS-157;So;0;L;;;;;N;;;;;
+2852;BRAILLE PATTERN DOTS-257;So;0;L;;;;;N;;;;;
+2853;BRAILLE PATTERN DOTS-1257;So;0;L;;;;;N;;;;;
+2854;BRAILLE PATTERN DOTS-357;So;0;L;;;;;N;;;;;
+2855;BRAILLE PATTERN DOTS-1357;So;0;L;;;;;N;;;;;
+2856;BRAILLE PATTERN DOTS-2357;So;0;L;;;;;N;;;;;
+2857;BRAILLE PATTERN DOTS-12357;So;0;L;;;;;N;;;;;
+2858;BRAILLE PATTERN DOTS-457;So;0;L;;;;;N;;;;;
+2859;BRAILLE PATTERN DOTS-1457;So;0;L;;;;;N;;;;;
+285A;BRAILLE PATTERN DOTS-2457;So;0;L;;;;;N;;;;;
+285B;BRAILLE PATTERN DOTS-12457;So;0;L;;;;;N;;;;;
+285C;BRAILLE PATTERN DOTS-3457;So;0;L;;;;;N;;;;;
+285D;BRAILLE PATTERN DOTS-13457;So;0;L;;;;;N;;;;;
+285E;BRAILLE PATTERN DOTS-23457;So;0;L;;;;;N;;;;;
+285F;BRAILLE PATTERN DOTS-123457;So;0;L;;;;;N;;;;;
+2860;BRAILLE PATTERN DOTS-67;So;0;L;;;;;N;;;;;
+2861;BRAILLE PATTERN DOTS-167;So;0;L;;;;;N;;;;;
+2862;BRAILLE PATTERN DOTS-267;So;0;L;;;;;N;;;;;
+2863;BRAILLE PATTERN DOTS-1267;So;0;L;;;;;N;;;;;
+2864;BRAILLE PATTERN DOTS-367;So;0;L;;;;;N;;;;;
+2865;BRAILLE PATTERN DOTS-1367;So;0;L;;;;;N;;;;;
+2866;BRAILLE PATTERN DOTS-2367;So;0;L;;;;;N;;;;;
+2867;BRAILLE PATTERN DOTS-12367;So;0;L;;;;;N;;;;;
+2868;BRAILLE PATTERN DOTS-467;So;0;L;;;;;N;;;;;
+2869;BRAILLE PATTERN DOTS-1467;So;0;L;;;;;N;;;;;
+286A;BRAILLE PATTERN DOTS-2467;So;0;L;;;;;N;;;;;
+286B;BRAILLE PATTERN DOTS-12467;So;0;L;;;;;N;;;;;
+286C;BRAILLE PATTERN DOTS-3467;So;0;L;;;;;N;;;;;
+286D;BRAILLE PATTERN DOTS-13467;So;0;L;;;;;N;;;;;
+286E;BRAILLE PATTERN DOTS-23467;So;0;L;;;;;N;;;;;
+286F;BRAILLE PATTERN DOTS-123467;So;0;L;;;;;N;;;;;
+2870;BRAILLE PATTERN DOTS-567;So;0;L;;;;;N;;;;;
+2871;BRAILLE PATTERN DOTS-1567;So;0;L;;;;;N;;;;;
+2872;BRAILLE PATTERN DOTS-2567;So;0;L;;;;;N;;;;;
+2873;BRAILLE PATTERN DOTS-12567;So;0;L;;;;;N;;;;;
+2874;BRAILLE PATTERN DOTS-3567;So;0;L;;;;;N;;;;;
+2875;BRAILLE PATTERN DOTS-13567;So;0;L;;;;;N;;;;;
+2876;BRAILLE PATTERN DOTS-23567;So;0;L;;;;;N;;;;;
+2877;BRAILLE PATTERN DOTS-123567;So;0;L;;;;;N;;;;;
+2878;BRAILLE PATTERN DOTS-4567;So;0;L;;;;;N;;;;;
+2879;BRAILLE PATTERN DOTS-14567;So;0;L;;;;;N;;;;;
+287A;BRAILLE PATTERN DOTS-24567;So;0;L;;;;;N;;;;;
+287B;BRAILLE PATTERN DOTS-124567;So;0;L;;;;;N;;;;;
+287C;BRAILLE PATTERN DOTS-34567;So;0;L;;;;;N;;;;;
+287D;BRAILLE PATTERN DOTS-134567;So;0;L;;;;;N;;;;;
+287E;BRAILLE PATTERN DOTS-234567;So;0;L;;;;;N;;;;;
+287F;BRAILLE PATTERN DOTS-1234567;So;0;L;;;;;N;;;;;
+2880;BRAILLE PATTERN DOTS-8;So;0;L;;;;;N;;;;;
+2881;BRAILLE PATTERN DOTS-18;So;0;L;;;;;N;;;;;
+2882;BRAILLE PATTERN DOTS-28;So;0;L;;;;;N;;;;;
+2883;BRAILLE PATTERN DOTS-128;So;0;L;;;;;N;;;;;
+2884;BRAILLE PATTERN DOTS-38;So;0;L;;;;;N;;;;;
+2885;BRAILLE PATTERN DOTS-138;So;0;L;;;;;N;;;;;
+2886;BRAILLE PATTERN DOTS-238;So;0;L;;;;;N;;;;;
+2887;BRAILLE PATTERN DOTS-1238;So;0;L;;;;;N;;;;;
+2888;BRAILLE PATTERN DOTS-48;So;0;L;;;;;N;;;;;
+2889;BRAILLE PATTERN DOTS-148;So;0;L;;;;;N;;;;;
+288A;BRAILLE PATTERN DOTS-248;So;0;L;;;;;N;;;;;
+288B;BRAILLE PATTERN DOTS-1248;So;0;L;;;;;N;;;;;
+288C;BRAILLE PATTERN DOTS-348;So;0;L;;;;;N;;;;;
+288D;BRAILLE PATTERN DOTS-1348;So;0;L;;;;;N;;;;;
+288E;BRAILLE PATTERN DOTS-2348;So;0;L;;;;;N;;;;;
+288F;BRAILLE PATTERN DOTS-12348;So;0;L;;;;;N;;;;;
+2890;BRAILLE PATTERN DOTS-58;So;0;L;;;;;N;;;;;
+2891;BRAILLE PATTERN DOTS-158;So;0;L;;;;;N;;;;;
+2892;BRAILLE PATTERN DOTS-258;So;0;L;;;;;N;;;;;
+2893;BRAILLE PATTERN DOTS-1258;So;0;L;;;;;N;;;;;
+2894;BRAILLE PATTERN DOTS-358;So;0;L;;;;;N;;;;;
+2895;BRAILLE PATTERN DOTS-1358;So;0;L;;;;;N;;;;;
+2896;BRAILLE PATTERN DOTS-2358;So;0;L;;;;;N;;;;;
+2897;BRAILLE PATTERN DOTS-12358;So;0;L;;;;;N;;;;;
+2898;BRAILLE PATTERN DOTS-458;So;0;L;;;;;N;;;;;
+2899;BRAILLE PATTERN DOTS-1458;So;0;L;;;;;N;;;;;
+289A;BRAILLE PATTERN DOTS-2458;So;0;L;;;;;N;;;;;
+289B;BRAILLE PATTERN DOTS-12458;So;0;L;;;;;N;;;;;
+289C;BRAILLE PATTERN DOTS-3458;So;0;L;;;;;N;;;;;
+289D;BRAILLE PATTERN DOTS-13458;So;0;L;;;;;N;;;;;
+289E;BRAILLE PATTERN DOTS-23458;So;0;L;;;;;N;;;;;
+289F;BRAILLE PATTERN DOTS-123458;So;0;L;;;;;N;;;;;
+28A0;BRAILLE PATTERN DOTS-68;So;0;L;;;;;N;;;;;
+28A1;BRAILLE PATTERN DOTS-168;So;0;L;;;;;N;;;;;
+28A2;BRAILLE PATTERN DOTS-268;So;0;L;;;;;N;;;;;
+28A3;BRAILLE PATTERN DOTS-1268;So;0;L;;;;;N;;;;;
+28A4;BRAILLE PATTERN DOTS-368;So;0;L;;;;;N;;;;;
+28A5;BRAILLE PATTERN DOTS-1368;So;0;L;;;;;N;;;;;
+28A6;BRAILLE PATTERN DOTS-2368;So;0;L;;;;;N;;;;;
+28A7;BRAILLE PATTERN DOTS-12368;So;0;L;;;;;N;;;;;
+28A8;BRAILLE PATTERN DOTS-468;So;0;L;;;;;N;;;;;
+28A9;BRAILLE PATTERN DOTS-1468;So;0;L;;;;;N;;;;;
+28AA;BRAILLE PATTERN DOTS-2468;So;0;L;;;;;N;;;;;
+28AB;BRAILLE PATTERN DOTS-12468;So;0;L;;;;;N;;;;;
+28AC;BRAILLE PATTERN DOTS-3468;So;0;L;;;;;N;;;;;
+28AD;BRAILLE PATTERN DOTS-13468;So;0;L;;;;;N;;;;;
+28AE;BRAILLE PATTERN DOTS-23468;So;0;L;;;;;N;;;;;
+28AF;BRAILLE PATTERN DOTS-123468;So;0;L;;;;;N;;;;;
+28B0;BRAILLE PATTERN DOTS-568;So;0;L;;;;;N;;;;;
+28B1;BRAILLE PATTERN DOTS-1568;So;0;L;;;;;N;;;;;
+28B2;BRAILLE PATTERN DOTS-2568;So;0;L;;;;;N;;;;;
+28B3;BRAILLE PATTERN DOTS-12568;So;0;L;;;;;N;;;;;
+28B4;BRAILLE PATTERN DOTS-3568;So;0;L;;;;;N;;;;;
+28B5;BRAILLE PATTERN DOTS-13568;So;0;L;;;;;N;;;;;
+28B6;BRAILLE PATTERN DOTS-23568;So;0;L;;;;;N;;;;;
+28B7;BRAILLE PATTERN DOTS-123568;So;0;L;;;;;N;;;;;
+28B8;BRAILLE PATTERN DOTS-4568;So;0;L;;;;;N;;;;;
+28B9;BRAILLE PATTERN DOTS-14568;So;0;L;;;;;N;;;;;
+28BA;BRAILLE PATTERN DOTS-24568;So;0;L;;;;;N;;;;;
+28BB;BRAILLE PATTERN DOTS-124568;So;0;L;;;;;N;;;;;
+28BC;BRAILLE PATTERN DOTS-34568;So;0;L;;;;;N;;;;;
+28BD;BRAILLE PATTERN DOTS-134568;So;0;L;;;;;N;;;;;
+28BE;BRAILLE PATTERN DOTS-234568;So;0;L;;;;;N;;;;;
+28BF;BRAILLE PATTERN DOTS-1234568;So;0;L;;;;;N;;;;;
+28C0;BRAILLE PATTERN DOTS-78;So;0;L;;;;;N;;;;;
+28C1;BRAILLE PATTERN DOTS-178;So;0;L;;;;;N;;;;;
+28C2;BRAILLE PATTERN DOTS-278;So;0;L;;;;;N;;;;;
+28C3;BRAILLE PATTERN DOTS-1278;So;0;L;;;;;N;;;;;
+28C4;BRAILLE PATTERN DOTS-378;So;0;L;;;;;N;;;;;
+28C5;BRAILLE PATTERN DOTS-1378;So;0;L;;;;;N;;;;;
+28C6;BRAILLE PATTERN DOTS-2378;So;0;L;;;;;N;;;;;
+28C7;BRAILLE PATTERN DOTS-12378;So;0;L;;;;;N;;;;;
+28C8;BRAILLE PATTERN DOTS-478;So;0;L;;;;;N;;;;;
+28C9;BRAILLE PATTERN DOTS-1478;So;0;L;;;;;N;;;;;
+28CA;BRAILLE PATTERN DOTS-2478;So;0;L;;;;;N;;;;;
+28CB;BRAILLE PATTERN DOTS-12478;So;0;L;;;;;N;;;;;
+28CC;BRAILLE PATTERN DOTS-3478;So;0;L;;;;;N;;;;;
+28CD;BRAILLE PATTERN DOTS-13478;So;0;L;;;;;N;;;;;
+28CE;BRAILLE PATTERN DOTS-23478;So;0;L;;;;;N;;;;;
+28CF;BRAILLE PATTERN DOTS-123478;So;0;L;;;;;N;;;;;
+28D0;BRAILLE PATTERN DOTS-578;So;0;L;;;;;N;;;;;
+28D1;BRAILLE PATTERN DOTS-1578;So;0;L;;;;;N;;;;;
+28D2;BRAILLE PATTERN DOTS-2578;So;0;L;;;;;N;;;;;
+28D3;BRAILLE PATTERN DOTS-12578;So;0;L;;;;;N;;;;;
+28D4;BRAILLE PATTERN DOTS-3578;So;0;L;;;;;N;;;;;
+28D5;BRAILLE PATTERN DOTS-13578;So;0;L;;;;;N;;;;;
+28D6;BRAILLE PATTERN DOTS-23578;So;0;L;;;;;N;;;;;
+28D7;BRAILLE PATTERN DOTS-123578;So;0;L;;;;;N;;;;;
+28D8;BRAILLE PATTERN DOTS-4578;So;0;L;;;;;N;;;;;
+28D9;BRAILLE PATTERN DOTS-14578;So;0;L;;;;;N;;;;;
+28DA;BRAILLE PATTERN DOTS-24578;So;0;L;;;;;N;;;;;
+28DB;BRAILLE PATTERN DOTS-124578;So;0;L;;;;;N;;;;;
+28DC;BRAILLE PATTERN DOTS-34578;So;0;L;;;;;N;;;;;
+28DD;BRAILLE PATTERN DOTS-134578;So;0;L;;;;;N;;;;;
+28DE;BRAILLE PATTERN DOTS-234578;So;0;L;;;;;N;;;;;
+28DF;BRAILLE PATTERN DOTS-1234578;So;0;L;;;;;N;;;;;
+28E0;BRAILLE PATTERN DOTS-678;So;0;L;;;;;N;;;;;
+28E1;BRAILLE PATTERN DOTS-1678;So;0;L;;;;;N;;;;;
+28E2;BRAILLE PATTERN DOTS-2678;So;0;L;;;;;N;;;;;
+28E3;BRAILLE PATTERN DOTS-12678;So;0;L;;;;;N;;;;;
+28E4;BRAILLE PATTERN DOTS-3678;So;0;L;;;;;N;;;;;
+28E5;BRAILLE PATTERN DOTS-13678;So;0;L;;;;;N;;;;;
+28E6;BRAILLE PATTERN DOTS-23678;So;0;L;;;;;N;;;;;
+28E7;BRAILLE PATTERN DOTS-123678;So;0;L;;;;;N;;;;;
+28E8;BRAILLE PATTERN DOTS-4678;So;0;L;;;;;N;;;;;
+28E9;BRAILLE PATTERN DOTS-14678;So;0;L;;;;;N;;;;;
+28EA;BRAILLE PATTERN DOTS-24678;So;0;L;;;;;N;;;;;
+28EB;BRAILLE PATTERN DOTS-124678;So;0;L;;;;;N;;;;;
+28EC;BRAILLE PATTERN DOTS-34678;So;0;L;;;;;N;;;;;
+28ED;BRAILLE PATTERN DOTS-134678;So;0;L;;;;;N;;;;;
+28EE;BRAILLE PATTERN DOTS-234678;So;0;L;;;;;N;;;;;
+28EF;BRAILLE PATTERN DOTS-1234678;So;0;L;;;;;N;;;;;
+28F0;BRAILLE PATTERN DOTS-5678;So;0;L;;;;;N;;;;;
+28F1;BRAILLE PATTERN DOTS-15678;So;0;L;;;;;N;;;;;
+28F2;BRAILLE PATTERN DOTS-25678;So;0;L;;;;;N;;;;;
+28F3;BRAILLE PATTERN DOTS-125678;So;0;L;;;;;N;;;;;
+28F4;BRAILLE PATTERN DOTS-35678;So;0;L;;;;;N;;;;;
+28F5;BRAILLE PATTERN DOTS-135678;So;0;L;;;;;N;;;;;
+28F6;BRAILLE PATTERN DOTS-235678;So;0;L;;;;;N;;;;;
+28F7;BRAILLE PATTERN DOTS-1235678;So;0;L;;;;;N;;;;;
+28F8;BRAILLE PATTERN DOTS-45678;So;0;L;;;;;N;;;;;
+28F9;BRAILLE PATTERN DOTS-145678;So;0;L;;;;;N;;;;;
+28FA;BRAILLE PATTERN DOTS-245678;So;0;L;;;;;N;;;;;
+28FB;BRAILLE PATTERN DOTS-1245678;So;0;L;;;;;N;;;;;
+28FC;BRAILLE PATTERN DOTS-345678;So;0;L;;;;;N;;;;;
+28FD;BRAILLE PATTERN DOTS-1345678;So;0;L;;;;;N;;;;;
+28FE;BRAILLE PATTERN DOTS-2345678;So;0;L;;;;;N;;;;;
+28FF;BRAILLE PATTERN DOTS-12345678;So;0;L;;;;;N;;;;;
+2900;RIGHTWARDS TWO-HEADED ARROW WITH VERTICAL STROKE;Sm;0;ON;;;;;N;;;;;
+2901;RIGHTWARDS TWO-HEADED ARROW WITH DOUBLE VERTICAL STROKE;Sm;0;ON;;;;;N;;;;;
+2902;LEFTWARDS DOUBLE ARROW WITH VERTICAL STROKE;Sm;0;ON;;;;;N;;;;;
+2903;RIGHTWARDS DOUBLE ARROW WITH VERTICAL STROKE;Sm;0;ON;;;;;N;;;;;
+2904;LEFT RIGHT DOUBLE ARROW WITH VERTICAL STROKE;Sm;0;ON;;;;;N;;;;;
+2905;RIGHTWARDS TWO-HEADED ARROW FROM BAR;Sm;0;ON;;;;;N;;;;;
+2906;LEFTWARDS DOUBLE ARROW FROM BAR;Sm;0;ON;;;;;N;;;;;
+2907;RIGHTWARDS DOUBLE ARROW FROM BAR;Sm;0;ON;;;;;N;;;;;
+2908;DOWNWARDS ARROW WITH HORIZONTAL STROKE;Sm;0;ON;;;;;N;;;;;
+2909;UPWARDS ARROW WITH HORIZONTAL STROKE;Sm;0;ON;;;;;N;;;;;
+290A;UPWARDS TRIPLE ARROW;Sm;0;ON;;;;;N;;;;;
+290B;DOWNWARDS TRIPLE ARROW;Sm;0;ON;;;;;N;;;;;
+290C;LEFTWARDS DOUBLE DASH ARROW;Sm;0;ON;;;;;N;;;;;
+290D;RIGHTWARDS DOUBLE DASH ARROW;Sm;0;ON;;;;;N;;;;;
+290E;LEFTWARDS TRIPLE DASH ARROW;Sm;0;ON;;;;;N;;;;;
+290F;RIGHTWARDS TRIPLE DASH ARROW;Sm;0;ON;;;;;N;;;;;
+2910;RIGHTWARDS TWO-HEADED TRIPLE DASH ARROW;Sm;0;ON;;;;;N;;;;;
+2911;RIGHTWARDS ARROW WITH DOTTED STEM;Sm;0;ON;;;;;N;;;;;
+2912;UPWARDS ARROW TO BAR;Sm;0;ON;;;;;N;;;;;
+2913;DOWNWARDS ARROW TO BAR;Sm;0;ON;;;;;N;;;;;
+2914;RIGHTWARDS ARROW WITH TAIL WITH VERTICAL STROKE;Sm;0;ON;;;;;N;;;;;
+2915;RIGHTWARDS ARROW WITH TAIL WITH DOUBLE VERTICAL STROKE;Sm;0;ON;;;;;N;;;;;
+2916;RIGHTWARDS TWO-HEADED ARROW WITH TAIL;Sm;0;ON;;;;;N;;;;;
+2917;RIGHTWARDS TWO-HEADED ARROW WITH TAIL WITH VERTICAL STROKE;Sm;0;ON;;;;;N;;;;;
+2918;RIGHTWARDS TWO-HEADED ARROW WITH TAIL WITH DOUBLE VERTICAL STROKE;Sm;0;ON;;;;;N;;;;;
+2919;LEFTWARDS ARROW-TAIL;Sm;0;ON;;;;;N;;;;;
+291A;RIGHTWARDS ARROW-TAIL;Sm;0;ON;;;;;N;;;;;
+291B;LEFTWARDS DOUBLE ARROW-TAIL;Sm;0;ON;;;;;N;;;;;
+291C;RIGHTWARDS DOUBLE ARROW-TAIL;Sm;0;ON;;;;;N;;;;;
+291D;LEFTWARDS ARROW TO BLACK DIAMOND;Sm;0;ON;;;;;N;;;;;
+291E;RIGHTWARDS ARROW TO BLACK DIAMOND;Sm;0;ON;;;;;N;;;;;
+291F;LEFTWARDS ARROW FROM BAR TO BLACK DIAMOND;Sm;0;ON;;;;;N;;;;;
+2920;RIGHTWARDS ARROW FROM BAR TO BLACK DIAMOND;Sm;0;ON;;;;;N;;;;;
+2921;NORTH WEST AND SOUTH EAST ARROW;Sm;0;ON;;;;;N;;;;;
+2922;NORTH EAST AND SOUTH WEST ARROW;Sm;0;ON;;;;;N;;;;;
+2923;NORTH WEST ARROW WITH HOOK;Sm;0;ON;;;;;N;;;;;
+2924;NORTH EAST ARROW WITH HOOK;Sm;0;ON;;;;;N;;;;;
+2925;SOUTH EAST ARROW WITH HOOK;Sm;0;ON;;;;;N;;;;;
+2926;SOUTH WEST ARROW WITH HOOK;Sm;0;ON;;;;;N;;;;;
+2927;NORTH WEST ARROW AND NORTH EAST ARROW;Sm;0;ON;;;;;N;;;;;
+2928;NORTH EAST ARROW AND SOUTH EAST ARROW;Sm;0;ON;;;;;N;;;;;
+2929;SOUTH EAST ARROW AND SOUTH WEST ARROW;Sm;0;ON;;;;;N;;;;;
+292A;SOUTH WEST ARROW AND NORTH WEST ARROW;Sm;0;ON;;;;;N;;;;;
+292B;RISING DIAGONAL CROSSING FALLING DIAGONAL;Sm;0;ON;;;;;N;;;;;
+292C;FALLING DIAGONAL CROSSING RISING DIAGONAL;Sm;0;ON;;;;;N;;;;;
+292D;SOUTH EAST ARROW CROSSING NORTH EAST ARROW;Sm;0;ON;;;;;N;;;;;
+292E;NORTH EAST ARROW CROSSING SOUTH EAST ARROW;Sm;0;ON;;;;;N;;;;;
+292F;FALLING DIAGONAL CROSSING NORTH EAST ARROW;Sm;0;ON;;;;;N;;;;;
+2930;RISING DIAGONAL CROSSING SOUTH EAST ARROW;Sm;0;ON;;;;;N;;;;;
+2931;NORTH EAST ARROW CROSSING NORTH WEST ARROW;Sm;0;ON;;;;;N;;;;;
+2932;NORTH WEST ARROW CROSSING NORTH EAST ARROW;Sm;0;ON;;;;;N;;;;;
+2933;WAVE ARROW POINTING DIRECTLY RIGHT;Sm;0;ON;;;;;N;;;;;
+2934;ARROW POINTING RIGHTWARDS THEN CURVING UPWARDS;Sm;0;ON;;;;;N;;;;;
+2935;ARROW POINTING RIGHTWARDS THEN CURVING DOWNWARDS;Sm;0;ON;;;;;N;;;;;
+2936;ARROW POINTING DOWNWARDS THEN CURVING LEFTWARDS;Sm;0;ON;;;;;N;;;;;
+2937;ARROW POINTING DOWNWARDS THEN CURVING RIGHTWARDS;Sm;0;ON;;;;;N;;;;;
+2938;RIGHT-SIDE ARC CLOCKWISE ARROW;Sm;0;ON;;;;;N;;;;;
+2939;LEFT-SIDE ARC ANTICLOCKWISE ARROW;Sm;0;ON;;;;;N;;;;;
+293A;TOP ARC ANTICLOCKWISE ARROW;Sm;0;ON;;;;;N;;;;;
+293B;BOTTOM ARC ANTICLOCKWISE ARROW;Sm;0;ON;;;;;N;;;;;
+293C;TOP ARC CLOCKWISE ARROW WITH MINUS;Sm;0;ON;;;;;N;;;;;
+293D;TOP ARC ANTICLOCKWISE ARROW WITH PLUS;Sm;0;ON;;;;;N;;;;;
+293E;LOWER RIGHT SEMICIRCULAR CLOCKWISE ARROW;Sm;0;ON;;;;;N;;;;;
+293F;LOWER LEFT SEMICIRCULAR ANTICLOCKWISE ARROW;Sm;0;ON;;;;;N;;;;;
+2940;ANTICLOCKWISE CLOSED CIRCLE ARROW;Sm;0;ON;;;;;N;;;;;
+2941;CLOCKWISE CLOSED CIRCLE ARROW;Sm;0;ON;;;;;N;;;;;
+2942;RIGHTWARDS ARROW ABOVE SHORT LEFTWARDS ARROW;Sm;0;ON;;;;;N;;;;;
+2943;LEFTWARDS ARROW ABOVE SHORT RIGHTWARDS ARROW;Sm;0;ON;;;;;N;;;;;
+2944;SHORT RIGHTWARDS ARROW ABOVE LEFTWARDS ARROW;Sm;0;ON;;;;;N;;;;;
+2945;RIGHTWARDS ARROW WITH PLUS BELOW;Sm;0;ON;;;;;N;;;;;
+2946;LEFTWARDS ARROW WITH PLUS BELOW;Sm;0;ON;;;;;N;;;;;
+2947;RIGHTWARDS ARROW THROUGH X;Sm;0;ON;;;;;N;;;;;
+2948;LEFT RIGHT ARROW THROUGH SMALL CIRCLE;Sm;0;ON;;;;;N;;;;;
+2949;UPWARDS TWO-HEADED ARROW FROM SMALL CIRCLE;Sm;0;ON;;;;;N;;;;;
+294A;LEFT BARB UP RIGHT BARB DOWN HARPOON;Sm;0;ON;;;;;N;;;;;
+294B;LEFT BARB DOWN RIGHT BARB UP HARPOON;Sm;0;ON;;;;;N;;;;;
+294C;UP BARB RIGHT DOWN BARB LEFT HARPOON;Sm;0;ON;;;;;N;;;;;
+294D;UP BARB LEFT DOWN BARB RIGHT HARPOON;Sm;0;ON;;;;;N;;;;;
+294E;LEFT BARB UP RIGHT BARB UP HARPOON;Sm;0;ON;;;;;N;;;;;
+294F;UP BARB RIGHT DOWN BARB RIGHT HARPOON;Sm;0;ON;;;;;N;;;;;
+2950;LEFT BARB DOWN RIGHT BARB DOWN HARPOON;Sm;0;ON;;;;;N;;;;;
+2951;UP BARB LEFT DOWN BARB LEFT HARPOON;Sm;0;ON;;;;;N;;;;;
+2952;LEFTWARDS HARPOON WITH BARB UP TO BAR;Sm;0;ON;;;;;N;;;;;
+2953;RIGHTWARDS HARPOON WITH BARB UP TO BAR;Sm;0;ON;;;;;N;;;;;
+2954;UPWARDS HARPOON WITH BARB RIGHT TO BAR;Sm;0;ON;;;;;N;;;;;
+2955;DOWNWARDS HARPOON WITH BARB RIGHT TO BAR;Sm;0;ON;;;;;N;;;;;
+2956;LEFTWARDS HARPOON WITH BARB DOWN TO BAR;Sm;0;ON;;;;;N;;;;;
+2957;RIGHTWARDS HARPOON WITH BARB DOWN TO BAR;Sm;0;ON;;;;;N;;;;;
+2958;UPWARDS HARPOON WITH BARB LEFT TO BAR;Sm;0;ON;;;;;N;;;;;
+2959;DOWNWARDS HARPOON WITH BARB LEFT TO BAR;Sm;0;ON;;;;;N;;;;;
+295A;LEFTWARDS HARPOON WITH BARB UP FROM BAR;Sm;0;ON;;;;;N;;;;;
+295B;RIGHTWARDS HARPOON WITH BARB UP FROM BAR;Sm;0;ON;;;;;N;;;;;
+295C;UPWARDS HARPOON WITH BARB RIGHT FROM BAR;Sm;0;ON;;;;;N;;;;;
+295D;DOWNWARDS HARPOON WITH BARB RIGHT FROM BAR;Sm;0;ON;;;;;N;;;;;
+295E;LEFTWARDS HARPOON WITH BARB DOWN FROM BAR;Sm;0;ON;;;;;N;;;;;
+295F;RIGHTWARDS HARPOON WITH BARB DOWN FROM BAR;Sm;0;ON;;;;;N;;;;;
+2960;UPWARDS HARPOON WITH BARB LEFT FROM BAR;Sm;0;ON;;;;;N;;;;;
+2961;DOWNWARDS HARPOON WITH BARB LEFT FROM BAR;Sm;0;ON;;;;;N;;;;;
+2962;LEFTWARDS HARPOON WITH BARB UP ABOVE LEFTWARDS HARPOON WITH BARB DOWN;Sm;0;ON;;;;;N;;;;;
+2963;UPWARDS HARPOON WITH BARB LEFT BESIDE UPWARDS HARPOON WITH BARB RIGHT;Sm;0;ON;;;;;N;;;;;
+2964;RIGHTWARDS HARPOON WITH BARB UP ABOVE RIGHTWARDS HARPOON WITH BARB DOWN;Sm;0;ON;;;;;N;;;;;
+2965;DOWNWARDS HARPOON WITH BARB LEFT BESIDE DOWNWARDS HARPOON WITH BARB RIGHT;Sm;0;ON;;;;;N;;;;;
+2966;LEFTWARDS HARPOON WITH BARB UP ABOVE RIGHTWARDS HARPOON WITH BARB UP;Sm;0;ON;;;;;N;;;;;
+2967;LEFTWARDS HARPOON WITH BARB DOWN ABOVE RIGHTWARDS HARPOON WITH BARB DOWN;Sm;0;ON;;;;;N;;;;;
+2968;RIGHTWARDS HARPOON WITH BARB UP ABOVE LEFTWARDS HARPOON WITH BARB UP;Sm;0;ON;;;;;N;;;;;
+2969;RIGHTWARDS HARPOON WITH BARB DOWN ABOVE LEFTWARDS HARPOON WITH BARB DOWN;Sm;0;ON;;;;;N;;;;;
+296A;LEFTWARDS HARPOON WITH BARB UP ABOVE LONG DASH;Sm;0;ON;;;;;N;;;;;
+296B;LEFTWARDS HARPOON WITH BARB DOWN BELOW LONG DASH;Sm;0;ON;;;;;N;;;;;
+296C;RIGHTWARDS HARPOON WITH BARB UP ABOVE LONG DASH;Sm;0;ON;;;;;N;;;;;
+296D;RIGHTWARDS HARPOON WITH BARB DOWN BELOW LONG DASH;Sm;0;ON;;;;;N;;;;;
+296E;UPWARDS HARPOON WITH BARB LEFT BESIDE DOWNWARDS HARPOON WITH BARB RIGHT;Sm;0;ON;;;;;N;;;;;
+296F;DOWNWARDS HARPOON WITH BARB LEFT BESIDE UPWARDS HARPOON WITH BARB RIGHT;Sm;0;ON;;;;;N;;;;;
+2970;RIGHT DOUBLE ARROW WITH ROUNDED HEAD;Sm;0;ON;;;;;N;;;;;
+2971;EQUALS SIGN ABOVE RIGHTWARDS ARROW;Sm;0;ON;;;;;N;;;;;
+2972;TILDE OPERATOR ABOVE RIGHTWARDS ARROW;Sm;0;ON;;;;;N;;;;;
+2973;LEFTWARDS ARROW ABOVE TILDE OPERATOR;Sm;0;ON;;;;;N;;;;;
+2974;RIGHTWARDS ARROW ABOVE TILDE OPERATOR;Sm;0;ON;;;;;N;;;;;
+2975;RIGHTWARDS ARROW ABOVE ALMOST EQUAL TO;Sm;0;ON;;;;;N;;;;;
+2976;LESS-THAN ABOVE LEFTWARDS ARROW;Sm;0;ON;;;;;N;;;;;
+2977;LEFTWARDS ARROW THROUGH LESS-THAN;Sm;0;ON;;;;;N;;;;;
+2978;GREATER-THAN ABOVE RIGHTWARDS ARROW;Sm;0;ON;;;;;N;;;;;
+2979;SUBSET ABOVE RIGHTWARDS ARROW;Sm;0;ON;;;;;N;;;;;
+297A;LEFTWARDS ARROW THROUGH SUBSET;Sm;0;ON;;;;;N;;;;;
+297B;SUPERSET ABOVE LEFTWARDS ARROW;Sm;0;ON;;;;;N;;;;;
+297C;LEFT FISH TAIL;Sm;0;ON;;;;;N;;;;;
+297D;RIGHT FISH TAIL;Sm;0;ON;;;;;N;;;;;
+297E;UP FISH TAIL;Sm;0;ON;;;;;N;;;;;
+297F;DOWN FISH TAIL;Sm;0;ON;;;;;N;;;;;
+2980;TRIPLE VERTICAL BAR DELIMITER;Sm;0;ON;;;;;N;;;;;
+2981;Z NOTATION SPOT;Sm;0;ON;;;;;N;;;;;
+2982;Z NOTATION TYPE COLON;Sm;0;ON;;;;;N;;;;;
+2983;LEFT WHITE CURLY BRACKET;Ps;0;ON;;;;;Y;;;;;
+2984;RIGHT WHITE CURLY BRACKET;Pe;0;ON;;;;;Y;;;;;
+2985;LEFT WHITE PARENTHESIS;Ps;0;ON;;;;;Y;;;;;
+2986;RIGHT WHITE PARENTHESIS;Pe;0;ON;;;;;Y;;;;;
+2987;Z NOTATION LEFT IMAGE BRACKET;Ps;0;ON;;;;;Y;;;;;
+2988;Z NOTATION RIGHT IMAGE BRACKET;Pe;0;ON;;;;;Y;;;;;
+2989;Z NOTATION LEFT BINDING BRACKET;Ps;0;ON;;;;;Y;;;;;
+298A;Z NOTATION RIGHT BINDING BRACKET;Pe;0;ON;;;;;Y;;;;;
+298B;LEFT SQUARE BRACKET WITH UNDERBAR;Ps;0;ON;;;;;Y;;;;;
+298C;RIGHT SQUARE BRACKET WITH UNDERBAR;Pe;0;ON;;;;;Y;;;;;
+298D;LEFT SQUARE BRACKET WITH TICK IN TOP CORNER;Ps;0;ON;;;;;Y;;;;;
+298E;RIGHT SQUARE BRACKET WITH TICK IN BOTTOM CORNER;Pe;0;ON;;;;;Y;;;;;
+298F;LEFT SQUARE BRACKET WITH TICK IN BOTTOM CORNER;Ps;0;ON;;;;;Y;;;;;
+2990;RIGHT SQUARE BRACKET WITH TICK IN TOP CORNER;Pe;0;ON;;;;;Y;;;;;
+2991;LEFT ANGLE BRACKET WITH DOT;Ps;0;ON;;;;;Y;;;;;
+2992;RIGHT ANGLE BRACKET WITH DOT;Pe;0;ON;;;;;Y;;;;;
+2993;LEFT ARC LESS-THAN BRACKET;Ps;0;ON;;;;;Y;;;;;
+2994;RIGHT ARC GREATER-THAN BRACKET;Pe;0;ON;;;;;Y;;;;;
+2995;DOUBLE LEFT ARC GREATER-THAN BRACKET;Ps;0;ON;;;;;Y;;;;;
+2996;DOUBLE RIGHT ARC LESS-THAN BRACKET;Pe;0;ON;;;;;Y;;;;;
+2997;LEFT BLACK TORTOISE SHELL BRACKET;Ps;0;ON;;;;;Y;;;;;
+2998;RIGHT BLACK TORTOISE SHELL BRACKET;Pe;0;ON;;;;;Y;;;;;
+2999;DOTTED FENCE;Sm;0;ON;;;;;N;;;;;
+299A;VERTICAL ZIGZAG LINE;Sm;0;ON;;;;;N;;;;;
+299B;MEASURED ANGLE OPENING LEFT;Sm;0;ON;;;;;Y;;;;;
+299C;RIGHT ANGLE VARIANT WITH SQUARE;Sm;0;ON;;;;;Y;;;;;
+299D;MEASURED RIGHT ANGLE WITH DOT;Sm;0;ON;;;;;Y;;;;;
+299E;ANGLE WITH S INSIDE;Sm;0;ON;;;;;Y;;;;;
+299F;ACUTE ANGLE;Sm;0;ON;;;;;Y;;;;;
+29A0;SPHERICAL ANGLE OPENING LEFT;Sm;0;ON;;;;;Y;;;;;
+29A1;SPHERICAL ANGLE OPENING UP;Sm;0;ON;;;;;Y;;;;;
+29A2;TURNED ANGLE;Sm;0;ON;;;;;Y;;;;;
+29A3;REVERSED ANGLE;Sm;0;ON;;;;;Y;;;;;
+29A4;ANGLE WITH UNDERBAR;Sm;0;ON;;;;;Y;;;;;
+29A5;REVERSED ANGLE WITH UNDERBAR;Sm;0;ON;;;;;Y;;;;;
+29A6;OBLIQUE ANGLE OPENING UP;Sm;0;ON;;;;;Y;;;;;
+29A7;OBLIQUE ANGLE OPENING DOWN;Sm;0;ON;;;;;Y;;;;;
+29A8;MEASURED ANGLE WITH OPEN ARM ENDING IN ARROW POINTING UP AND RIGHT;Sm;0;ON;;;;;Y;;;;;
+29A9;MEASURED ANGLE WITH OPEN ARM ENDING IN ARROW POINTING UP AND LEFT;Sm;0;ON;;;;;Y;;;;;
+29AA;MEASURED ANGLE WITH OPEN ARM ENDING IN ARROW POINTING DOWN AND RIGHT;Sm;0;ON;;;;;Y;;;;;
+29AB;MEASURED ANGLE WITH OPEN ARM ENDING IN ARROW POINTING DOWN AND LEFT;Sm;0;ON;;;;;Y;;;;;
+29AC;MEASURED ANGLE WITH OPEN ARM ENDING IN ARROW POINTING RIGHT AND UP;Sm;0;ON;;;;;Y;;;;;
+29AD;MEASURED ANGLE WITH OPEN ARM ENDING IN ARROW POINTING LEFT AND UP;Sm;0;ON;;;;;Y;;;;;
+29AE;MEASURED ANGLE WITH OPEN ARM ENDING IN ARROW POINTING RIGHT AND DOWN;Sm;0;ON;;;;;Y;;;;;
+29AF;MEASURED ANGLE WITH OPEN ARM ENDING IN ARROW POINTING LEFT AND DOWN;Sm;0;ON;;;;;Y;;;;;
+29B0;REVERSED EMPTY SET;Sm;0;ON;;;;;N;;;;;
+29B1;EMPTY SET WITH OVERBAR;Sm;0;ON;;;;;N;;;;;
+29B2;EMPTY SET WITH SMALL CIRCLE ABOVE;Sm;0;ON;;;;;N;;;;;
+29B3;EMPTY SET WITH RIGHT ARROW ABOVE;Sm;0;ON;;;;;N;;;;;
+29B4;EMPTY SET WITH LEFT ARROW ABOVE;Sm;0;ON;;;;;N;;;;;
+29B5;CIRCLE WITH HORIZONTAL BAR;Sm;0;ON;;;;;N;;;;;
+29B6;CIRCLED VERTICAL BAR;Sm;0;ON;;;;;N;;;;;
+29B7;CIRCLED PARALLEL;Sm;0;ON;;;;;N;;;;;
+29B8;CIRCLED REVERSE SOLIDUS;Sm;0;ON;;;;;Y;;;;;
+29B9;CIRCLED PERPENDICULAR;Sm;0;ON;;;;;N;;;;;
+29BA;CIRCLE DIVIDED BY HORIZONTAL BAR AND TOP HALF DIVIDED BY VERTICAL BAR;Sm;0;ON;;;;;N;;;;;
+29BB;CIRCLE WITH SUPERIMPOSED X;Sm;0;ON;;;;;N;;;;;
+29BC;CIRCLED ANTICLOCKWISE-ROTATED DIVISION SIGN;Sm;0;ON;;;;;N;;;;;
+29BD;UP ARROW THROUGH CIRCLE;Sm;0;ON;;;;;N;;;;;
+29BE;CIRCLED WHITE BULLET;Sm;0;ON;;;;;N;;;;;
+29BF;CIRCLED BULLET;Sm;0;ON;;;;;N;;;;;
+29C0;CIRCLED LESS-THAN;Sm;0;ON;;;;;Y;;;;;
+29C1;CIRCLED GREATER-THAN;Sm;0;ON;;;;;Y;;;;;
+29C2;CIRCLE WITH SMALL CIRCLE TO THE RIGHT;Sm;0;ON;;;;;Y;;;;;
+29C3;CIRCLE WITH TWO HORIZONTAL STROKES TO THE RIGHT;Sm;0;ON;;;;;Y;;;;;
+29C4;SQUARED RISING DIAGONAL SLASH;Sm;0;ON;;;;;Y;;;;;
+29C5;SQUARED FALLING DIAGONAL SLASH;Sm;0;ON;;;;;Y;;;;;
+29C6;SQUARED ASTERISK;Sm;0;ON;;;;;N;;;;;
+29C7;SQUARED SMALL CIRCLE;Sm;0;ON;;;;;N;;;;;
+29C8;SQUARED SQUARE;Sm;0;ON;;;;;N;;;;;
+29C9;TWO JOINED SQUARES;Sm;0;ON;;;;;Y;;;;;
+29CA;TRIANGLE WITH DOT ABOVE;Sm;0;ON;;;;;N;;;;;
+29CB;TRIANGLE WITH UNDERBAR;Sm;0;ON;;;;;N;;;;;
+29CC;S IN TRIANGLE;Sm;0;ON;;;;;N;;;;;
+29CD;TRIANGLE WITH SERIFS AT BOTTOM;Sm;0;ON;;;;;N;;;;;
+29CE;RIGHT TRIANGLE ABOVE LEFT TRIANGLE;Sm;0;ON;;;;;Y;;;;;
+29CF;LEFT TRIANGLE BESIDE VERTICAL BAR;Sm;0;ON;;;;;Y;;;;;
+29D0;VERTICAL BAR BESIDE RIGHT TRIANGLE;Sm;0;ON;;;;;Y;;;;;
+29D1;BOWTIE WITH LEFT HALF BLACK;Sm;0;ON;;;;;Y;;;;;
+29D2;BOWTIE WITH RIGHT HALF BLACK;Sm;0;ON;;;;;Y;;;;;
+29D3;BLACK BOWTIE;Sm;0;ON;;;;;N;;;;;
+29D4;TIMES WITH LEFT HALF BLACK;Sm;0;ON;;;;;Y;;;;;
+29D5;TIMES WITH RIGHT HALF BLACK;Sm;0;ON;;;;;Y;;;;;
+29D6;WHITE HOURGLASS;Sm;0;ON;;;;;N;;;;;
+29D7;BLACK HOURGLASS;Sm;0;ON;;;;;N;;;;;
+29D8;LEFT WIGGLY FENCE;Ps;0;ON;;;;;Y;;;;;
+29D9;RIGHT WIGGLY FENCE;Pe;0;ON;;;;;Y;;;;;
+29DA;LEFT DOUBLE WIGGLY FENCE;Ps;0;ON;;;;;Y;;;;;
+29DB;RIGHT DOUBLE WIGGLY FENCE;Pe;0;ON;;;;;Y;;;;;
+29DC;INCOMPLETE INFINITY;Sm;0;ON;;;;;Y;;;;;
+29DD;TIE OVER INFINITY;Sm;0;ON;;;;;N;;;;;
+29DE;INFINITY NEGATED WITH VERTICAL BAR;Sm;0;ON;;;;;N;;;;;
+29DF;DOUBLE-ENDED MULTIMAP;Sm;0;ON;;;;;N;;;;;
+29E0;SQUARE WITH CONTOURED OUTLINE;Sm;0;ON;;;;;N;;;;;
+29E1;INCREASES AS;Sm;0;ON;;;;;Y;;;;;
+29E2;SHUFFLE PRODUCT;Sm;0;ON;;;;;N;;;;;
+29E3;EQUALS SIGN AND SLANTED PARALLEL;Sm;0;ON;;;;;Y;;;;;
+29E4;EQUALS SIGN AND SLANTED PARALLEL WITH TILDE ABOVE;Sm;0;ON;;;;;Y;;;;;
+29E5;IDENTICAL TO AND SLANTED PARALLEL;Sm;0;ON;;;;;Y;;;;;
+29E6;GLEICH STARK;Sm;0;ON;;;;;N;;;;;
+29E7;THERMODYNAMIC;Sm;0;ON;;;;;N;;;;;
+29E8;DOWN-POINTING TRIANGLE WITH LEFT HALF BLACK;Sm;0;ON;;;;;Y;;;;;
+29E9;DOWN-POINTING TRIANGLE WITH RIGHT HALF BLACK;Sm;0;ON;;;;;Y;;;;;
+29EA;BLACK DIAMOND WITH DOWN ARROW;Sm;0;ON;;;;;N;;;;;
+29EB;BLACK LOZENGE;Sm;0;ON;;;;;N;;;;;
+29EC;WHITE CIRCLE WITH DOWN ARROW;Sm;0;ON;;;;;N;;;;;
+29ED;BLACK CIRCLE WITH DOWN ARROW;Sm;0;ON;;;;;N;;;;;
+29EE;ERROR-BARRED WHITE SQUARE;Sm;0;ON;;;;;N;;;;;
+29EF;ERROR-BARRED BLACK SQUARE;Sm;0;ON;;;;;N;;;;;
+29F0;ERROR-BARRED WHITE DIAMOND;Sm;0;ON;;;;;N;;;;;
+29F1;ERROR-BARRED BLACK DIAMOND;Sm;0;ON;;;;;N;;;;;
+29F2;ERROR-BARRED WHITE CIRCLE;Sm;0;ON;;;;;N;;;;;
+29F3;ERROR-BARRED BLACK CIRCLE;Sm;0;ON;;;;;N;;;;;
+29F4;RULE-DELAYED;Sm;0;ON;;;;;Y;;;;;
+29F5;REVERSE SOLIDUS OPERATOR;Sm;0;ON;;;;;Y;;;;;
+29F6;SOLIDUS WITH OVERBAR;Sm;0;ON;;;;;Y;;;;;
+29F7;REVERSE SOLIDUS WITH HORIZONTAL STROKE;Sm;0;ON;;;;;Y;;;;;
+29F8;BIG SOLIDUS;Sm;0;ON;;;;;Y;;;;;
+29F9;BIG REVERSE SOLIDUS;Sm;0;ON;;;;;Y;;;;;
+29FA;DOUBLE PLUS;Sm;0;ON;;;;;N;;;;;
+29FB;TRIPLE PLUS;Sm;0;ON;;;;;N;;;;;
+29FC;LEFT-POINTING CURVED ANGLE BRACKET;Ps;0;ON;;;;;Y;;;;;
+29FD;RIGHT-POINTING CURVED ANGLE BRACKET;Pe;0;ON;;;;;Y;;;;;
+29FE;TINY;Sm;0;ON;;;;;N;;;;;
+29FF;MINY;Sm;0;ON;;;;;N;;;;;
+2A00;N-ARY CIRCLED DOT OPERATOR;Sm;0;ON;;;;;N;;;;;
+2A01;N-ARY CIRCLED PLUS OPERATOR;Sm;0;ON;;;;;N;;;;;
+2A02;N-ARY CIRCLED TIMES OPERATOR;Sm;0;ON;;;;;N;;;;;
+2A03;N-ARY UNION OPERATOR WITH DOT;Sm;0;ON;;;;;N;;;;;
+2A04;N-ARY UNION OPERATOR WITH PLUS;Sm;0;ON;;;;;N;;;;;
+2A05;N-ARY SQUARE INTERSECTION OPERATOR;Sm;0;ON;;;;;N;;;;;
+2A06;N-ARY SQUARE UNION OPERATOR;Sm;0;ON;;;;;N;;;;;
+2A07;TWO LOGICAL AND OPERATOR;Sm;0;ON;;;;;N;;;;;
+2A08;TWO LOGICAL OR OPERATOR;Sm;0;ON;;;;;N;;;;;
+2A09;N-ARY TIMES OPERATOR;Sm;0;ON;;;;;N;;;;;
+2A0A;MODULO TWO SUM;Sm;0;ON;;;;;Y;;;;;
+2A0B;SUMMATION WITH INTEGRAL;Sm;0;ON;;;;;Y;;;;;
+2A0C;QUADRUPLE INTEGRAL OPERATOR;Sm;0;ON;<compat> 222B 222B 222B 222B;;;;Y;;;;;
+2A0D;FINITE PART INTEGRAL;Sm;0;ON;;;;;Y;;;;;
+2A0E;INTEGRAL WITH DOUBLE STROKE;Sm;0;ON;;;;;Y;;;;;
+2A0F;INTEGRAL AVERAGE WITH SLASH;Sm;0;ON;;;;;Y;;;;;
+2A10;CIRCULATION FUNCTION;Sm;0;ON;;;;;Y;;;;;
+2A11;ANTICLOCKWISE INTEGRATION;Sm;0;ON;;;;;Y;;;;;
+2A12;LINE INTEGRATION WITH RECTANGULAR PATH AROUND POLE;Sm;0;ON;;;;;Y;;;;;
+2A13;LINE INTEGRATION WITH SEMICIRCULAR PATH AROUND POLE;Sm;0;ON;;;;;Y;;;;;
+2A14;LINE INTEGRATION NOT INCLUDING THE POLE;Sm;0;ON;;;;;Y;;;;;
+2A15;INTEGRAL AROUND A POINT OPERATOR;Sm;0;ON;;;;;Y;;;;;
+2A16;QUATERNION INTEGRAL OPERATOR;Sm;0;ON;;;;;Y;;;;;
+2A17;INTEGRAL WITH LEFTWARDS ARROW WITH HOOK;Sm;0;ON;;;;;Y;;;;;
+2A18;INTEGRAL WITH TIMES SIGN;Sm;0;ON;;;;;Y;;;;;
+2A19;INTEGRAL WITH INTERSECTION;Sm;0;ON;;;;;Y;;;;;
+2A1A;INTEGRAL WITH UNION;Sm;0;ON;;;;;Y;;;;;
+2A1B;INTEGRAL WITH OVERBAR;Sm;0;ON;;;;;Y;;;;;
+2A1C;INTEGRAL WITH UNDERBAR;Sm;0;ON;;;;;Y;;;;;
+2A1D;JOIN;Sm;0;ON;;;;;N;;;;;
+2A1E;LARGE LEFT TRIANGLE OPERATOR;Sm;0;ON;;;;;Y;;;;;
+2A1F;Z NOTATION SCHEMA COMPOSITION;Sm;0;ON;;;;;Y;;;;;
+2A20;Z NOTATION SCHEMA PIPING;Sm;0;ON;;;;;Y;;;;;
+2A21;Z NOTATION SCHEMA PROJECTION;Sm;0;ON;;;;;Y;;;;;
+2A22;PLUS SIGN WITH SMALL CIRCLE ABOVE;Sm;0;ON;;;;;N;;;;;
+2A23;PLUS SIGN WITH CIRCUMFLEX ACCENT ABOVE;Sm;0;ON;;;;;N;;;;;
+2A24;PLUS SIGN WITH TILDE ABOVE;Sm;0;ON;;;;;Y;;;;;
+2A25;PLUS SIGN WITH DOT BELOW;Sm;0;ON;;;;;N;;;;;
+2A26;PLUS SIGN WITH TILDE BELOW;Sm;0;ON;;;;;Y;;;;;
+2A27;PLUS SIGN WITH SUBSCRIPT TWO;Sm;0;ON;;;;;N;;;;;
+2A28;PLUS SIGN WITH BLACK TRIANGLE;Sm;0;ON;;;;;N;;;;;
+2A29;MINUS SIGN WITH COMMA ABOVE;Sm;0;ON;;;;;Y;;;;;
+2A2A;MINUS SIGN WITH DOT BELOW;Sm;0;ON;;;;;N;;;;;
+2A2B;MINUS SIGN WITH FALLING DOTS;Sm;0;ON;;;;;Y;;;;;
+2A2C;MINUS SIGN WITH RISING DOTS;Sm;0;ON;;;;;Y;;;;;
+2A2D;PLUS SIGN IN LEFT HALF CIRCLE;Sm;0;ON;;;;;Y;;;;;
+2A2E;PLUS SIGN IN RIGHT HALF CIRCLE;Sm;0;ON;;;;;Y;;;;;
+2A2F;VECTOR OR CROSS PRODUCT;Sm;0;ON;;;;;N;;;;;
+2A30;MULTIPLICATION SIGN WITH DOT ABOVE;Sm;0;ON;;;;;N;;;;;
+2A31;MULTIPLICATION SIGN WITH UNDERBAR;Sm;0;ON;;;;;N;;;;;
+2A32;SEMIDIRECT PRODUCT WITH BOTTOM CLOSED;Sm;0;ON;;;;;N;;;;;
+2A33;SMASH PRODUCT;Sm;0;ON;;;;;N;;;;;
+2A34;MULTIPLICATION SIGN IN LEFT HALF CIRCLE;Sm;0;ON;;;;;Y;;;;;
+2A35;MULTIPLICATION SIGN IN RIGHT HALF CIRCLE;Sm;0;ON;;;;;Y;;;;;
+2A36;CIRCLED MULTIPLICATION SIGN WITH CIRCUMFLEX ACCENT;Sm;0;ON;;;;;N;;;;;
+2A37;MULTIPLICATION SIGN IN DOUBLE CIRCLE;Sm;0;ON;;;;;N;;;;;
+2A38;CIRCLED DIVISION SIGN;Sm;0;ON;;;;;N;;;;;
+2A39;PLUS SIGN IN TRIANGLE;Sm;0;ON;;;;;N;;;;;
+2A3A;MINUS SIGN IN TRIANGLE;Sm;0;ON;;;;;N;;;;;
+2A3B;MULTIPLICATION SIGN IN TRIANGLE;Sm;0;ON;;;;;N;;;;;
+2A3C;INTERIOR PRODUCT;Sm;0;ON;;;;;Y;;;;;
+2A3D;RIGHTHAND INTERIOR PRODUCT;Sm;0;ON;;;;;Y;;;;;
+2A3E;Z NOTATION RELATIONAL COMPOSITION;Sm;0;ON;;;;;Y;;;;;
+2A3F;AMALGAMATION OR COPRODUCT;Sm;0;ON;;;;;N;;;;;
+2A40;INTERSECTION WITH DOT;Sm;0;ON;;;;;N;;;;;
+2A41;UNION WITH MINUS SIGN;Sm;0;ON;;;;;N;;;;;
+2A42;UNION WITH OVERBAR;Sm;0;ON;;;;;N;;;;;
+2A43;INTERSECTION WITH OVERBAR;Sm;0;ON;;;;;N;;;;;
+2A44;INTERSECTION WITH LOGICAL AND;Sm;0;ON;;;;;N;;;;;
+2A45;UNION WITH LOGICAL OR;Sm;0;ON;;;;;N;;;;;
+2A46;UNION ABOVE INTERSECTION;Sm;0;ON;;;;;N;;;;;
+2A47;INTERSECTION ABOVE UNION;Sm;0;ON;;;;;N;;;;;
+2A48;UNION ABOVE BAR ABOVE INTERSECTION;Sm;0;ON;;;;;N;;;;;
+2A49;INTERSECTION ABOVE BAR ABOVE UNION;Sm;0;ON;;;;;N;;;;;
+2A4A;UNION BESIDE AND JOINED WITH UNION;Sm;0;ON;;;;;N;;;;;
+2A4B;INTERSECTION BESIDE AND JOINED WITH INTERSECTION;Sm;0;ON;;;;;N;;;;;
+2A4C;CLOSED UNION WITH SERIFS;Sm;0;ON;;;;;N;;;;;
+2A4D;CLOSED INTERSECTION WITH SERIFS;Sm;0;ON;;;;;N;;;;;
+2A4E;DOUBLE SQUARE INTERSECTION;Sm;0;ON;;;;;N;;;;;
+2A4F;DOUBLE SQUARE UNION;Sm;0;ON;;;;;N;;;;;
+2A50;CLOSED UNION WITH SERIFS AND SMASH PRODUCT;Sm;0;ON;;;;;N;;;;;
+2A51;LOGICAL AND WITH DOT ABOVE;Sm;0;ON;;;;;N;;;;;
+2A52;LOGICAL OR WITH DOT ABOVE;Sm;0;ON;;;;;N;;;;;
+2A53;DOUBLE LOGICAL AND;Sm;0;ON;;;;;N;;;;;
+2A54;DOUBLE LOGICAL OR;Sm;0;ON;;;;;N;;;;;
+2A55;TWO INTERSECTING LOGICAL AND;Sm;0;ON;;;;;N;;;;;
+2A56;TWO INTERSECTING LOGICAL OR;Sm;0;ON;;;;;N;;;;;
+2A57;SLOPING LARGE OR;Sm;0;ON;;;;;Y;;;;;
+2A58;SLOPING LARGE AND;Sm;0;ON;;;;;Y;;;;;
+2A59;LOGICAL OR OVERLAPPING LOGICAL AND;Sm;0;ON;;;;;N;;;;;
+2A5A;LOGICAL AND WITH MIDDLE STEM;Sm;0;ON;;;;;N;;;;;
+2A5B;LOGICAL OR WITH MIDDLE STEM;Sm;0;ON;;;;;N;;;;;
+2A5C;LOGICAL AND WITH HORIZONTAL DASH;Sm;0;ON;;;;;N;;;;;
+2A5D;LOGICAL OR WITH HORIZONTAL DASH;Sm;0;ON;;;;;N;;;;;
+2A5E;LOGICAL AND WITH DOUBLE OVERBAR;Sm;0;ON;;;;;N;;;;;
+2A5F;LOGICAL AND WITH UNDERBAR;Sm;0;ON;;;;;N;;;;;
+2A60;LOGICAL AND WITH DOUBLE UNDERBAR;Sm;0;ON;;;;;N;;;;;
+2A61;SMALL VEE WITH UNDERBAR;Sm;0;ON;;;;;N;;;;;
+2A62;LOGICAL OR WITH DOUBLE OVERBAR;Sm;0;ON;;;;;N;;;;;
+2A63;LOGICAL OR WITH DOUBLE UNDERBAR;Sm;0;ON;;;;;N;;;;;
+2A64;Z NOTATION DOMAIN ANTIRESTRICTION;Sm;0;ON;;;;;Y;;;;;
+2A65;Z NOTATION RANGE ANTIRESTRICTION;Sm;0;ON;;;;;Y;;;;;
+2A66;EQUALS SIGN WITH DOT BELOW;Sm;0;ON;;;;;N;;;;;
+2A67;IDENTICAL WITH DOT ABOVE;Sm;0;ON;;;;;N;;;;;
+2A68;TRIPLE HORIZONTAL BAR WITH DOUBLE VERTICAL STROKE;Sm;0;ON;;;;;N;;;;;
+2A69;TRIPLE HORIZONTAL BAR WITH TRIPLE VERTICAL STROKE;Sm;0;ON;;;;;N;;;;;
+2A6A;TILDE OPERATOR WITH DOT ABOVE;Sm;0;ON;;;;;Y;;;;;
+2A6B;TILDE OPERATOR WITH RISING DOTS;Sm;0;ON;;;;;Y;;;;;
+2A6C;SIMILAR MINUS SIMILAR;Sm;0;ON;;;;;Y;;;;;
+2A6D;CONGRUENT WITH DOT ABOVE;Sm;0;ON;;;;;Y;;;;;
+2A6E;EQUALS WITH ASTERISK;Sm;0;ON;;;;;N;;;;;
+2A6F;ALMOST EQUAL TO WITH CIRCUMFLEX ACCENT;Sm;0;ON;;;;;Y;;;;;
+2A70;APPROXIMATELY EQUAL OR EQUAL TO;Sm;0;ON;;;;;Y;;;;;
+2A71;EQUALS SIGN ABOVE PLUS SIGN;Sm;0;ON;;;;;N;;;;;
+2A72;PLUS SIGN ABOVE EQUALS SIGN;Sm;0;ON;;;;;N;;;;;
+2A73;EQUALS SIGN ABOVE TILDE OPERATOR;Sm;0;ON;;;;;Y;;;;;
+2A74;DOUBLE COLON EQUAL;Sm;0;ON;<compat> 003A 003A 003D;;;;Y;;;;;
+2A75;TWO CONSECUTIVE EQUALS SIGNS;Sm;0;ON;<compat> 003D 003D;;;;N;;;;;
+2A76;THREE CONSECUTIVE EQUALS SIGNS;Sm;0;ON;<compat> 003D 003D 003D;;;;N;;;;;
+2A77;EQUALS SIGN WITH TWO DOTS ABOVE AND TWO DOTS BELOW;Sm;0;ON;;;;;N;;;;;
+2A78;EQUIVALENT WITH FOUR DOTS ABOVE;Sm;0;ON;;;;;N;;;;;
+2A79;LESS-THAN WITH CIRCLE INSIDE;Sm;0;ON;;;;;Y;;;;;
+2A7A;GREATER-THAN WITH CIRCLE INSIDE;Sm;0;ON;;;;;Y;;;;;
+2A7B;LESS-THAN WITH QUESTION MARK ABOVE;Sm;0;ON;;;;;Y;;;;;
+2A7C;GREATER-THAN WITH QUESTION MARK ABOVE;Sm;0;ON;;;;;Y;;;;;
+2A7D;LESS-THAN OR SLANTED EQUAL TO;Sm;0;ON;;;;;Y;;;;;
+2A7E;GREATER-THAN OR SLANTED EQUAL TO;Sm;0;ON;;;;;Y;;;;;
+2A7F;LESS-THAN OR SLANTED EQUAL TO WITH DOT INSIDE;Sm;0;ON;;;;;Y;;;;;
+2A80;GREATER-THAN OR SLANTED EQUAL TO WITH DOT INSIDE;Sm;0;ON;;;;;Y;;;;;
+2A81;LESS-THAN OR SLANTED EQUAL TO WITH DOT ABOVE;Sm;0;ON;;;;;Y;;;;;
+2A82;GREATER-THAN OR SLANTED EQUAL TO WITH DOT ABOVE;Sm;0;ON;;;;;Y;;;;;
+2A83;LESS-THAN OR SLANTED EQUAL TO WITH DOT ABOVE RIGHT;Sm;0;ON;;;;;Y;;;;;
+2A84;GREATER-THAN OR SLANTED EQUAL TO WITH DOT ABOVE LEFT;Sm;0;ON;;;;;Y;;;;;
+2A85;LESS-THAN OR APPROXIMATE;Sm;0;ON;;;;;Y;;;;;
+2A86;GREATER-THAN OR APPROXIMATE;Sm;0;ON;;;;;Y;;;;;
+2A87;LESS-THAN AND SINGLE-LINE NOT EQUAL TO;Sm;0;ON;;;;;Y;;;;;
+2A88;GREATER-THAN AND SINGLE-LINE NOT EQUAL TO;Sm;0;ON;;;;;Y;;;;;
+2A89;LESS-THAN AND NOT APPROXIMATE;Sm;0;ON;;;;;Y;;;;;
+2A8A;GREATER-THAN AND NOT APPROXIMATE;Sm;0;ON;;;;;Y;;;;;
+2A8B;LESS-THAN ABOVE DOUBLE-LINE EQUAL ABOVE GREATER-THAN;Sm;0;ON;;;;;Y;;;;;
+2A8C;GREATER-THAN ABOVE DOUBLE-LINE EQUAL ABOVE LESS-THAN;Sm;0;ON;;;;;Y;;;;;
+2A8D;LESS-THAN ABOVE SIMILAR OR EQUAL;Sm;0;ON;;;;;Y;;;;;
+2A8E;GREATER-THAN ABOVE SIMILAR OR EQUAL;Sm;0;ON;;;;;Y;;;;;
+2A8F;LESS-THAN ABOVE SIMILAR ABOVE GREATER-THAN;Sm;0;ON;;;;;Y;;;;;
+2A90;GREATER-THAN ABOVE SIMILAR ABOVE LESS-THAN;Sm;0;ON;;;;;Y;;;;;
+2A91;LESS-THAN ABOVE GREATER-THAN ABOVE DOUBLE-LINE EQUAL;Sm;0;ON;;;;;Y;;;;;
+2A92;GREATER-THAN ABOVE LESS-THAN ABOVE DOUBLE-LINE EQUAL;Sm;0;ON;;;;;Y;;;;;
+2A93;LESS-THAN ABOVE SLANTED EQUAL ABOVE GREATER-THAN ABOVE SLANTED EQUAL;Sm;0;ON;;;;;Y;;;;;
+2A94;GREATER-THAN ABOVE SLANTED EQUAL ABOVE LESS-THAN ABOVE SLANTED EQUAL;Sm;0;ON;;;;;Y;;;;;
+2A95;SLANTED EQUAL TO OR LESS-THAN;Sm;0;ON;;;;;Y;;;;;
+2A96;SLANTED EQUAL TO OR GREATER-THAN;Sm;0;ON;;;;;Y;;;;;
+2A97;SLANTED EQUAL TO OR LESS-THAN WITH DOT INSIDE;Sm;0;ON;;;;;Y;;;;;
+2A98;SLANTED EQUAL TO OR GREATER-THAN WITH DOT INSIDE;Sm;0;ON;;;;;Y;;;;;
+2A99;DOUBLE-LINE EQUAL TO OR LESS-THAN;Sm;0;ON;;;;;Y;;;;;
+2A9A;DOUBLE-LINE EQUAL TO OR GREATER-THAN;Sm;0;ON;;;;;Y;;;;;
+2A9B;DOUBLE-LINE SLANTED EQUAL TO OR LESS-THAN;Sm;0;ON;;;;;Y;;;;;
+2A9C;DOUBLE-LINE SLANTED EQUAL TO OR GREATER-THAN;Sm;0;ON;;;;;Y;;;;;
+2A9D;SIMILAR OR LESS-THAN;Sm;0;ON;;;;;Y;;;;;
+2A9E;SIMILAR OR GREATER-THAN;Sm;0;ON;;;;;Y;;;;;
+2A9F;SIMILAR ABOVE LESS-THAN ABOVE EQUALS SIGN;Sm;0;ON;;;;;Y;;;;;
+2AA0;SIMILAR ABOVE GREATER-THAN ABOVE EQUALS SIGN;Sm;0;ON;;;;;Y;;;;;
+2AA1;DOUBLE NESTED LESS-THAN;Sm;0;ON;;;;;Y;;;;;
+2AA2;DOUBLE NESTED GREATER-THAN;Sm;0;ON;;;;;Y;;;;;
+2AA3;DOUBLE NESTED LESS-THAN WITH UNDERBAR;Sm;0;ON;;;;;Y;;;;;
+2AA4;GREATER-THAN OVERLAPPING LESS-THAN;Sm;0;ON;;;;;N;;;;;
+2AA5;GREATER-THAN BESIDE LESS-THAN;Sm;0;ON;;;;;N;;;;;
+2AA6;LESS-THAN CLOSED BY CURVE;Sm;0;ON;;;;;Y;;;;;
+2AA7;GREATER-THAN CLOSED BY CURVE;Sm;0;ON;;;;;Y;;;;;
+2AA8;LESS-THAN CLOSED BY CURVE ABOVE SLANTED EQUAL;Sm;0;ON;;;;;Y;;;;;
+2AA9;GREATER-THAN CLOSED BY CURVE ABOVE SLANTED EQUAL;Sm;0;ON;;;;;Y;;;;;
+2AAA;SMALLER THAN;Sm;0;ON;;;;;Y;;;;;
+2AAB;LARGER THAN;Sm;0;ON;;;;;Y;;;;;
+2AAC;SMALLER THAN OR EQUAL TO;Sm;0;ON;;;;;Y;;;;;
+2AAD;LARGER THAN OR EQUAL TO;Sm;0;ON;;;;;Y;;;;;
+2AAE;EQUALS SIGN WITH BUMPY ABOVE;Sm;0;ON;;;;;N;;;;;
+2AAF;PRECEDES ABOVE SINGLE-LINE EQUALS SIGN;Sm;0;ON;;;;;Y;;;;;
+2AB0;SUCCEEDS ABOVE SINGLE-LINE EQUALS SIGN;Sm;0;ON;;;;;Y;;;;;
+2AB1;PRECEDES ABOVE SINGLE-LINE NOT EQUAL TO;Sm;0;ON;;;;;Y;;;;;
+2AB2;SUCCEEDS ABOVE SINGLE-LINE NOT EQUAL TO;Sm;0;ON;;;;;Y;;;;;
+2AB3;PRECEDES ABOVE EQUALS SIGN;Sm;0;ON;;;;;Y;;;;;
+2AB4;SUCCEEDS ABOVE EQUALS SIGN;Sm;0;ON;;;;;Y;;;;;
+2AB5;PRECEDES ABOVE NOT EQUAL TO;Sm;0;ON;;;;;Y;;;;;
+2AB6;SUCCEEDS ABOVE NOT EQUAL TO;Sm;0;ON;;;;;Y;;;;;
+2AB7;PRECEDES ABOVE ALMOST EQUAL TO;Sm;0;ON;;;;;Y;;;;;
+2AB8;SUCCEEDS ABOVE ALMOST EQUAL TO;Sm;0;ON;;;;;Y;;;;;
+2AB9;PRECEDES ABOVE NOT ALMOST EQUAL TO;Sm;0;ON;;;;;Y;;;;;
+2ABA;SUCCEEDS ABOVE NOT ALMOST EQUAL TO;Sm;0;ON;;;;;Y;;;;;
+2ABB;DOUBLE PRECEDES;Sm;0;ON;;;;;Y;;;;;
+2ABC;DOUBLE SUCCEEDS;Sm;0;ON;;;;;Y;;;;;
+2ABD;SUBSET WITH DOT;Sm;0;ON;;;;;Y;;;;;
+2ABE;SUPERSET WITH DOT;Sm;0;ON;;;;;Y;;;;;
+2ABF;SUBSET WITH PLUS SIGN BELOW;Sm;0;ON;;;;;Y;;;;;
+2AC0;SUPERSET WITH PLUS SIGN BELOW;Sm;0;ON;;;;;Y;;;;;
+2AC1;SUBSET WITH MULTIPLICATION SIGN BELOW;Sm;0;ON;;;;;Y;;;;;
+2AC2;SUPERSET WITH MULTIPLICATION SIGN BELOW;Sm;0;ON;;;;;Y;;;;;
+2AC3;SUBSET OF OR EQUAL TO WITH DOT ABOVE;Sm;0;ON;;;;;Y;;;;;
+2AC4;SUPERSET OF OR EQUAL TO WITH DOT ABOVE;Sm;0;ON;;;;;Y;;;;;
+2AC5;SUBSET OF ABOVE EQUALS SIGN;Sm;0;ON;;;;;Y;;;;;
+2AC6;SUPERSET OF ABOVE EQUALS SIGN;Sm;0;ON;;;;;Y;;;;;
+2AC7;SUBSET OF ABOVE TILDE OPERATOR;Sm;0;ON;;;;;Y;;;;;
+2AC8;SUPERSET OF ABOVE TILDE OPERATOR;Sm;0;ON;;;;;Y;;;;;
+2AC9;SUBSET OF ABOVE ALMOST EQUAL TO;Sm;0;ON;;;;;Y;;;;;
+2ACA;SUPERSET OF ABOVE ALMOST EQUAL TO;Sm;0;ON;;;;;Y;;;;;
+2ACB;SUBSET OF ABOVE NOT EQUAL TO;Sm;0;ON;;;;;Y;;;;;
+2ACC;SUPERSET OF ABOVE NOT EQUAL TO;Sm;0;ON;;;;;Y;;;;;
+2ACD;SQUARE LEFT OPEN BOX OPERATOR;Sm;0;ON;;;;;Y;;;;;
+2ACE;SQUARE RIGHT OPEN BOX OPERATOR;Sm;0;ON;;;;;Y;;;;;
+2ACF;CLOSED SUBSET;Sm;0;ON;;;;;Y;;;;;
+2AD0;CLOSED SUPERSET;Sm;0;ON;;;;;Y;;;;;
+2AD1;CLOSED SUBSET OR EQUAL TO;Sm;0;ON;;;;;Y;;;;;
+2AD2;CLOSED SUPERSET OR EQUAL TO;Sm;0;ON;;;;;Y;;;;;
+2AD3;SUBSET ABOVE SUPERSET;Sm;0;ON;;;;;Y;;;;;
+2AD4;SUPERSET ABOVE SUBSET;Sm;0;ON;;;;;Y;;;;;
+2AD5;SUBSET ABOVE SUBSET;Sm;0;ON;;;;;Y;;;;;
+2AD6;SUPERSET ABOVE SUPERSET;Sm;0;ON;;;;;Y;;;;;
+2AD7;SUPERSET BESIDE SUBSET;Sm;0;ON;;;;;N;;;;;
+2AD8;SUPERSET BESIDE AND JOINED BY DASH WITH SUBSET;Sm;0;ON;;;;;N;;;;;
+2AD9;ELEMENT OF OPENING DOWNWARDS;Sm;0;ON;;;;;N;;;;;
+2ADA;PITCHFORK WITH TEE TOP;Sm;0;ON;;;;;N;;;;;
+2ADB;TRANSVERSAL INTERSECTION;Sm;0;ON;;;;;N;;;;;
+2ADC;FORKING;Sm;0;ON;2ADD 0338;;;;Y;;not independent;;;
+2ADD;NONFORKING;Sm;0;ON;;;;;N;;independent;;;
+2ADE;SHORT LEFT TACK;Sm;0;ON;;;;;Y;;;;;
+2ADF;SHORT DOWN TACK;Sm;0;ON;;;;;N;;;;;
+2AE0;SHORT UP TACK;Sm;0;ON;;;;;N;;;;;
+2AE1;PERPENDICULAR WITH S;Sm;0;ON;;;;;N;;;;;
+2AE2;VERTICAL BAR TRIPLE RIGHT TURNSTILE;Sm;0;ON;;;;;Y;;;;;
+2AE3;DOUBLE VERTICAL BAR LEFT TURNSTILE;Sm;0;ON;;;;;Y;;;;;
+2AE4;VERTICAL BAR DOUBLE LEFT TURNSTILE;Sm;0;ON;;;;;Y;;;;;
+2AE5;DOUBLE VERTICAL BAR DOUBLE LEFT TURNSTILE;Sm;0;ON;;;;;Y;;;;;
+2AE6;LONG DASH FROM LEFT MEMBER OF DOUBLE VERTICAL;Sm;0;ON;;;;;Y;;;;;
+2AE7;SHORT DOWN TACK WITH OVERBAR;Sm;0;ON;;;;;N;;;;;
+2AE8;SHORT UP TACK WITH UNDERBAR;Sm;0;ON;;;;;N;;;;;
+2AE9;SHORT UP TACK ABOVE SHORT DOWN TACK;Sm;0;ON;;;;;N;;;;;
+2AEA;DOUBLE DOWN TACK;Sm;0;ON;;;;;N;;;;;
+2AEB;DOUBLE UP TACK;Sm;0;ON;;;;;N;;;;;
+2AEC;DOUBLE STROKE NOT SIGN;Sm;0;ON;;;;;Y;;;;;
+2AED;REVERSED DOUBLE STROKE NOT SIGN;Sm;0;ON;;;;;Y;;;;;
+2AEE;DOES NOT DIVIDE WITH REVERSED NEGATION SLASH;Sm;0;ON;;;;;Y;;;;;
+2AEF;VERTICAL LINE WITH CIRCLE ABOVE;Sm;0;ON;;;;;N;;;;;
+2AF0;VERTICAL LINE WITH CIRCLE BELOW;Sm;0;ON;;;;;N;;;;;
+2AF1;DOWN TACK WITH CIRCLE BELOW;Sm;0;ON;;;;;N;;;;;
+2AF2;PARALLEL WITH HORIZONTAL STROKE;Sm;0;ON;;;;;N;;;;;
+2AF3;PARALLEL WITH TILDE OPERATOR;Sm;0;ON;;;;;Y;;;;;
+2AF4;TRIPLE VERTICAL BAR BINARY RELATION;Sm;0;ON;;;;;N;;;;;
+2AF5;TRIPLE VERTICAL BAR WITH HORIZONTAL STROKE;Sm;0;ON;;;;;N;;;;;
+2AF6;TRIPLE COLON OPERATOR;Sm;0;ON;;;;;N;;;;;
+2AF7;TRIPLE NESTED LESS-THAN;Sm;0;ON;;;;;Y;;;;;
+2AF8;TRIPLE NESTED GREATER-THAN;Sm;0;ON;;;;;Y;;;;;
+2AF9;DOUBLE-LINE SLANTED LESS-THAN OR EQUAL TO;Sm;0;ON;;;;;Y;;;;;
+2AFA;DOUBLE-LINE SLANTED GREATER-THAN OR EQUAL TO;Sm;0;ON;;;;;Y;;;;;
+2AFB;TRIPLE SOLIDUS BINARY RELATION;Sm;0;ON;;;;;Y;;;;;
+2AFC;LARGE TRIPLE VERTICAL BAR OPERATOR;Sm;0;ON;;;;;N;;;;;
+2AFD;DOUBLE SOLIDUS OPERATOR;Sm;0;ON;;;;;Y;;;;;
+2AFE;WHITE VERTICAL BAR;Sm;0;ON;;;;;N;;;;;
+2AFF;N-ARY WHITE VERTICAL BAR;Sm;0;ON;;;;;N;;;;;
+2B00;NORTH EAST WHITE ARROW;So;0;ON;;;;;N;;;;;
+2B01;NORTH WEST WHITE ARROW;So;0;ON;;;;;N;;;;;
+2B02;SOUTH EAST WHITE ARROW;So;0;ON;;;;;N;;;;;
+2B03;SOUTH WEST WHITE ARROW;So;0;ON;;;;;N;;;;;
+2B04;LEFT RIGHT WHITE ARROW;So;0;ON;;;;;N;;;;;
+2B05;LEFTWARDS BLACK ARROW;So;0;ON;;;;;N;;;;;
+2B06;UPWARDS BLACK ARROW;So;0;ON;;;;;N;;;;;
+2B07;DOWNWARDS BLACK ARROW;So;0;ON;;;;;N;;;;;
+2B08;NORTH EAST BLACK ARROW;So;0;ON;;;;;N;;;;;
+2B09;NORTH WEST BLACK ARROW;So;0;ON;;;;;N;;;;;
+2B0A;SOUTH EAST BLACK ARROW;So;0;ON;;;;;N;;;;;
+2B0B;SOUTH WEST BLACK ARROW;So;0;ON;;;;;N;;;;;
+2B0C;LEFT RIGHT BLACK ARROW;So;0;ON;;;;;N;;;;;
+2B0D;UP DOWN BLACK ARROW;So;0;ON;;;;;N;;;;;
+2B0E;RIGHTWARDS ARROW WITH TIP DOWNWARDS;So;0;ON;;;;;N;;;;;
+2B0F;RIGHTWARDS ARROW WITH TIP UPWARDS;So;0;ON;;;;;N;;;;;
+2B10;LEFTWARDS ARROW WITH TIP DOWNWARDS;So;0;ON;;;;;N;;;;;
+2B11;LEFTWARDS ARROW WITH TIP UPWARDS;So;0;ON;;;;;N;;;;;
+2B12;SQUARE WITH TOP HALF BLACK;So;0;ON;;;;;N;;;;;
+2B13;SQUARE WITH BOTTOM HALF BLACK;So;0;ON;;;;;N;;;;;
+2C00;GLAGOLITIC CAPITAL LETTER AZU;Lu;0;L;;;;;N;;;;2C30;
+2C01;GLAGOLITIC CAPITAL LETTER BUKY;Lu;0;L;;;;;N;;;;2C31;
+2C02;GLAGOLITIC CAPITAL LETTER VEDE;Lu;0;L;;;;;N;;;;2C32;
+2C03;GLAGOLITIC CAPITAL LETTER GLAGOLI;Lu;0;L;;;;;N;;;;2C33;
+2C04;GLAGOLITIC CAPITAL LETTER DOBRO;Lu;0;L;;;;;N;;;;2C34;
+2C05;GLAGOLITIC CAPITAL LETTER YESTU;Lu;0;L;;;;;N;;;;2C35;
+2C06;GLAGOLITIC CAPITAL LETTER ZHIVETE;Lu;0;L;;;;;N;;;;2C36;
+2C07;GLAGOLITIC CAPITAL LETTER DZELO;Lu;0;L;;;;;N;;;;2C37;
+2C08;GLAGOLITIC CAPITAL LETTER ZEMLJA;Lu;0;L;;;;;N;;;;2C38;
+2C09;GLAGOLITIC CAPITAL LETTER IZHE;Lu;0;L;;;;;N;;;;2C39;
+2C0A;GLAGOLITIC CAPITAL LETTER INITIAL IZHE;Lu;0;L;;;;;N;;;;2C3A;
+2C0B;GLAGOLITIC CAPITAL LETTER I;Lu;0;L;;;;;N;;;;2C3B;
+2C0C;GLAGOLITIC CAPITAL LETTER DJERVI;Lu;0;L;;;;;N;;;;2C3C;
+2C0D;GLAGOLITIC CAPITAL LETTER KAKO;Lu;0;L;;;;;N;;;;2C3D;
+2C0E;GLAGOLITIC CAPITAL LETTER LJUDIJE;Lu;0;L;;;;;N;;;;2C3E;
+2C0F;GLAGOLITIC CAPITAL LETTER MYSLITE;Lu;0;L;;;;;N;;;;2C3F;
+2C10;GLAGOLITIC CAPITAL LETTER NASHI;Lu;0;L;;;;;N;;;;2C40;
+2C11;GLAGOLITIC CAPITAL LETTER ONU;Lu;0;L;;;;;N;;;;2C41;
+2C12;GLAGOLITIC CAPITAL LETTER POKOJI;Lu;0;L;;;;;N;;;;2C42;
+2C13;GLAGOLITIC CAPITAL LETTER RITSI;Lu;0;L;;;;;N;;;;2C43;
+2C14;GLAGOLITIC CAPITAL LETTER SLOVO;Lu;0;L;;;;;N;;;;2C44;
+2C15;GLAGOLITIC CAPITAL LETTER TVRIDO;Lu;0;L;;;;;N;;;;2C45;
+2C16;GLAGOLITIC CAPITAL LETTER UKU;Lu;0;L;;;;;N;;;;2C46;
+2C17;GLAGOLITIC CAPITAL LETTER FRITU;Lu;0;L;;;;;N;;;;2C47;
+2C18;GLAGOLITIC CAPITAL LETTER HERU;Lu;0;L;;;;;N;;;;2C48;
+2C19;GLAGOLITIC CAPITAL LETTER OTU;Lu;0;L;;;;;N;;;;2C49;
+2C1A;GLAGOLITIC CAPITAL LETTER PE;Lu;0;L;;;;;N;;;;2C4A;
+2C1B;GLAGOLITIC CAPITAL LETTER SHTA;Lu;0;L;;;;;N;;;;2C4B;
+2C1C;GLAGOLITIC CAPITAL LETTER TSI;Lu;0;L;;;;;N;;;;2C4C;
+2C1D;GLAGOLITIC CAPITAL LETTER CHRIVI;Lu;0;L;;;;;N;;;;2C4D;
+2C1E;GLAGOLITIC CAPITAL LETTER SHA;Lu;0;L;;;;;N;;;;2C4E;
+2C1F;GLAGOLITIC CAPITAL LETTER YERU;Lu;0;L;;;;;N;;;;2C4F;
+2C20;GLAGOLITIC CAPITAL LETTER YERI;Lu;0;L;;;;;N;;;;2C50;
+2C21;GLAGOLITIC CAPITAL LETTER YATI;Lu;0;L;;;;;N;;;;2C51;
+2C22;GLAGOLITIC CAPITAL LETTER SPIDERY HA;Lu;0;L;;;;;N;;;;2C52;
+2C23;GLAGOLITIC CAPITAL LETTER YU;Lu;0;L;;;;;N;;;;2C53;
+2C24;GLAGOLITIC CAPITAL LETTER SMALL YUS;Lu;0;L;;;;;N;;;;2C54;
+2C25;GLAGOLITIC CAPITAL LETTER SMALL YUS WITH TAIL;Lu;0;L;;;;;N;;;;2C55;
+2C26;GLAGOLITIC CAPITAL LETTER YO;Lu;0;L;;;;;N;;;;2C56;
+2C27;GLAGOLITIC CAPITAL LETTER IOTATED SMALL YUS;Lu;0;L;;;;;N;;;;2C57;
+2C28;GLAGOLITIC CAPITAL LETTER BIG YUS;Lu;0;L;;;;;N;;;;2C58;
+2C29;GLAGOLITIC CAPITAL LETTER IOTATED BIG YUS;Lu;0;L;;;;;N;;;;2C59;
+2C2A;GLAGOLITIC CAPITAL LETTER FITA;Lu;0;L;;;;;N;;;;2C5A;
+2C2B;GLAGOLITIC CAPITAL LETTER IZHITSA;Lu;0;L;;;;;N;;;;2C5B;
+2C2C;GLAGOLITIC CAPITAL LETTER SHTAPIC;Lu;0;L;;;;;N;;;;2C5C;
+2C2D;GLAGOLITIC CAPITAL LETTER TROKUTASTI A;Lu;0;L;;;;;N;;;;2C5D;
+2C2E;GLAGOLITIC CAPITAL LETTER LATINATE MYSLITE;Lu;0;L;;;;;N;;;;2C5E;
+2C30;GLAGOLITIC SMALL LETTER AZU;Ll;0;L;;;;;N;;;2C00;;2C00
+2C31;GLAGOLITIC SMALL LETTER BUKY;Ll;0;L;;;;;N;;;2C01;;2C01
+2C32;GLAGOLITIC SMALL LETTER VEDE;Ll;0;L;;;;;N;;;2C02;;2C02
+2C33;GLAGOLITIC SMALL LETTER GLAGOLI;Ll;0;L;;;;;N;;;2C03;;2C03
+2C34;GLAGOLITIC SMALL LETTER DOBRO;Ll;0;L;;;;;N;;;2C04;;2C04
+2C35;GLAGOLITIC SMALL LETTER YESTU;Ll;0;L;;;;;N;;;2C05;;2C05
+2C36;GLAGOLITIC SMALL LETTER ZHIVETE;Ll;0;L;;;;;N;;;2C06;;2C06
+2C37;GLAGOLITIC SMALL LETTER DZELO;Ll;0;L;;;;;N;;;2C07;;2C07
+2C38;GLAGOLITIC SMALL LETTER ZEMLJA;Ll;0;L;;;;;N;;;2C08;;2C08
+2C39;GLAGOLITIC SMALL LETTER IZHE;Ll;0;L;;;;;N;;;2C09;;2C09
+2C3A;GLAGOLITIC SMALL LETTER INITIAL IZHE;Ll;0;L;;;;;N;;;2C0A;;2C0A
+2C3B;GLAGOLITIC SMALL LETTER I;Ll;0;L;;;;;N;;;2C0B;;2C0B
+2C3C;GLAGOLITIC SMALL LETTER DJERVI;Ll;0;L;;;;;N;;;2C0C;;2C0C
+2C3D;GLAGOLITIC SMALL LETTER KAKO;Ll;0;L;;;;;N;;;2C0D;;2C0D
+2C3E;GLAGOLITIC SMALL LETTER LJUDIJE;Ll;0;L;;;;;N;;;2C0E;;2C0E
+2C3F;GLAGOLITIC SMALL LETTER MYSLITE;Ll;0;L;;;;;N;;;2C0F;;2C0F
+2C40;GLAGOLITIC SMALL LETTER NASHI;Ll;0;L;;;;;N;;;2C10;;2C10
+2C41;GLAGOLITIC SMALL LETTER ONU;Ll;0;L;;;;;N;;;2C11;;2C11
+2C42;GLAGOLITIC SMALL LETTER POKOJI;Ll;0;L;;;;;N;;;2C12;;2C12
+2C43;GLAGOLITIC SMALL LETTER RITSI;Ll;0;L;;;;;N;;;2C13;;2C13
+2C44;GLAGOLITIC SMALL LETTER SLOVO;Ll;0;L;;;;;N;;;2C14;;2C14
+2C45;GLAGOLITIC SMALL LETTER TVRIDO;Ll;0;L;;;;;N;;;2C15;;2C15
+2C46;GLAGOLITIC SMALL LETTER UKU;Ll;0;L;;;;;N;;;2C16;;2C16
+2C47;GLAGOLITIC SMALL LETTER FRITU;Ll;0;L;;;;;N;;;2C17;;2C17
+2C48;GLAGOLITIC SMALL LETTER HERU;Ll;0;L;;;;;N;;;2C18;;2C18
+2C49;GLAGOLITIC SMALL LETTER OTU;Ll;0;L;;;;;N;;;2C19;;2C19
+2C4A;GLAGOLITIC SMALL LETTER PE;Ll;0;L;;;;;N;;;2C1A;;2C1A
+2C4B;GLAGOLITIC SMALL LETTER SHTA;Ll;0;L;;;;;N;;;2C1B;;2C1B
+2C4C;GLAGOLITIC SMALL LETTER TSI;Ll;0;L;;;;;N;;;2C1C;;2C1C
+2C4D;GLAGOLITIC SMALL LETTER CHRIVI;Ll;0;L;;;;;N;;;2C1D;;2C1D
+2C4E;GLAGOLITIC SMALL LETTER SHA;Ll;0;L;;;;;N;;;2C1E;;2C1E
+2C4F;GLAGOLITIC SMALL LETTER YERU;Ll;0;L;;;;;N;;;2C1F;;2C1F
+2C50;GLAGOLITIC SMALL LETTER YERI;Ll;0;L;;;;;N;;;2C20;;2C20
+2C51;GLAGOLITIC SMALL LETTER YATI;Ll;0;L;;;;;N;;;2C21;;2C21
+2C52;GLAGOLITIC SMALL LETTER SPIDERY HA;Ll;0;L;;;;;N;;;2C22;;2C22
+2C53;GLAGOLITIC SMALL LETTER YU;Ll;0;L;;;;;N;;;2C23;;2C23
+2C54;GLAGOLITIC SMALL LETTER SMALL YUS;Ll;0;L;;;;;N;;;2C24;;2C24
+2C55;GLAGOLITIC SMALL LETTER SMALL YUS WITH TAIL;Ll;0;L;;;;;N;;;2C25;;2C25
+2C56;GLAGOLITIC SMALL LETTER YO;Ll;0;L;;;;;N;;;2C26;;2C26
+2C57;GLAGOLITIC SMALL LETTER IOTATED SMALL YUS;Ll;0;L;;;;;N;;;2C27;;2C27
+2C58;GLAGOLITIC SMALL LETTER BIG YUS;Ll;0;L;;;;;N;;;2C28;;2C28
+2C59;GLAGOLITIC SMALL LETTER IOTATED BIG YUS;Ll;0;L;;;;;N;;;2C29;;2C29
+2C5A;GLAGOLITIC SMALL LETTER FITA;Ll;0;L;;;;;N;;;2C2A;;2C2A
+2C5B;GLAGOLITIC SMALL LETTER IZHITSA;Ll;0;L;;;;;N;;;2C2B;;2C2B
+2C5C;GLAGOLITIC SMALL LETTER SHTAPIC;Ll;0;L;;;;;N;;;2C2C;;2C2C
+2C5D;GLAGOLITIC SMALL LETTER TROKUTASTI A;Ll;0;L;;;;;N;;;2C2D;;2C2D
+2C5E;GLAGOLITIC SMALL LETTER LATINATE MYSLITE;Ll;0;L;;;;;N;;;2C2E;;2C2E
+2C80;COPTIC CAPITAL LETTER ALFA;Lu;0;L;;;;;N;;;;2C81;
+2C81;COPTIC SMALL LETTER ALFA;Ll;0;L;;;;;N;;;2C80;;2C80
+2C82;COPTIC CAPITAL LETTER VIDA;Lu;0;L;;;;;N;;;;2C83;
+2C83;COPTIC SMALL LETTER VIDA;Ll;0;L;;;;;N;;;2C82;;2C82
+2C84;COPTIC CAPITAL LETTER GAMMA;Lu;0;L;;;;;N;;;;2C85;
+2C85;COPTIC SMALL LETTER GAMMA;Ll;0;L;;;;;N;;;2C84;;2C84
+2C86;COPTIC CAPITAL LETTER DALDA;Lu;0;L;;;;;N;;;;2C87;
+2C87;COPTIC SMALL LETTER DALDA;Ll;0;L;;;;;N;;;2C86;;2C86
+2C88;COPTIC CAPITAL LETTER EIE;Lu;0;L;;;;;N;;;;2C89;
+2C89;COPTIC SMALL LETTER EIE;Ll;0;L;;;;;N;;;2C88;;2C88
+2C8A;COPTIC CAPITAL LETTER SOU;Lu;0;L;;;;;N;;;;2C8B;
+2C8B;COPTIC SMALL LETTER SOU;Ll;0;L;;;;;N;;;2C8A;;2C8A
+2C8C;COPTIC CAPITAL LETTER ZATA;Lu;0;L;;;;;N;;;;2C8D;
+2C8D;COPTIC SMALL LETTER ZATA;Ll;0;L;;;;;N;;;2C8C;;2C8C
+2C8E;COPTIC CAPITAL LETTER HATE;Lu;0;L;;;;;N;;;;2C8F;
+2C8F;COPTIC SMALL LETTER HATE;Ll;0;L;;;;;N;;;2C8E;;2C8E
+2C90;COPTIC CAPITAL LETTER THETHE;Lu;0;L;;;;;N;;;;2C91;
+2C91;COPTIC SMALL LETTER THETHE;Ll;0;L;;;;;N;;;2C90;;2C90
+2C92;COPTIC CAPITAL LETTER IAUDA;Lu;0;L;;;;;N;;;;2C93;
+2C93;COPTIC SMALL LETTER IAUDA;Ll;0;L;;;;;N;;;2C92;;2C92
+2C94;COPTIC CAPITAL LETTER KAPA;Lu;0;L;;;;;N;;;;2C95;
+2C95;COPTIC SMALL LETTER KAPA;Ll;0;L;;;;;N;;;2C94;;2C94
+2C96;COPTIC CAPITAL LETTER LAULA;Lu;0;L;;;;;N;;;;2C97;
+2C97;COPTIC SMALL LETTER LAULA;Ll;0;L;;;;;N;;;2C96;;2C96
+2C98;COPTIC CAPITAL LETTER MI;Lu;0;L;;;;;N;;;;2C99;
+2C99;COPTIC SMALL LETTER MI;Ll;0;L;;;;;N;;;2C98;;2C98
+2C9A;COPTIC CAPITAL LETTER NI;Lu;0;L;;;;;N;;;;2C9B;
+2C9B;COPTIC SMALL LETTER NI;Ll;0;L;;;;;N;;;2C9A;;2C9A
+2C9C;COPTIC CAPITAL LETTER KSI;Lu;0;L;;;;;N;;;;2C9D;
+2C9D;COPTIC SMALL LETTER KSI;Ll;0;L;;;;;N;;;2C9C;;2C9C
+2C9E;COPTIC CAPITAL LETTER O;Lu;0;L;;;;;N;;;;2C9F;
+2C9F;COPTIC SMALL LETTER O;Ll;0;L;;;;;N;;;2C9E;;2C9E
+2CA0;COPTIC CAPITAL LETTER PI;Lu;0;L;;;;;N;;;;2CA1;
+2CA1;COPTIC SMALL LETTER PI;Ll;0;L;;;;;N;;;2CA0;;2CA0
+2CA2;COPTIC CAPITAL LETTER RO;Lu;0;L;;;;;N;;;;2CA3;
+2CA3;COPTIC SMALL LETTER RO;Ll;0;L;;;;;N;;;2CA2;;2CA2
+2CA4;COPTIC CAPITAL LETTER SIMA;Lu;0;L;;;;;N;;;;2CA5;
+2CA5;COPTIC SMALL LETTER SIMA;Ll;0;L;;;;;N;;;2CA4;;2CA4
+2CA6;COPTIC CAPITAL LETTER TAU;Lu;0;L;;;;;N;;;;2CA7;
+2CA7;COPTIC SMALL LETTER TAU;Ll;0;L;;;;;N;;;2CA6;;2CA6
+2CA8;COPTIC CAPITAL LETTER UA;Lu;0;L;;;;;N;;;;2CA9;
+2CA9;COPTIC SMALL LETTER UA;Ll;0;L;;;;;N;;;2CA8;;2CA8
+2CAA;COPTIC CAPITAL LETTER FI;Lu;0;L;;;;;N;;;;2CAB;
+2CAB;COPTIC SMALL LETTER FI;Ll;0;L;;;;;N;;;2CAA;;2CAA
+2CAC;COPTIC CAPITAL LETTER KHI;Lu;0;L;;;;;N;;;;2CAD;
+2CAD;COPTIC SMALL LETTER KHI;Ll;0;L;;;;;N;;;2CAC;;2CAC
+2CAE;COPTIC CAPITAL LETTER PSI;Lu;0;L;;;;;N;;;;2CAF;
+2CAF;COPTIC SMALL LETTER PSI;Ll;0;L;;;;;N;;;2CAE;;2CAE
+2CB0;COPTIC CAPITAL LETTER OOU;Lu;0;L;;;;;N;;;;2CB1;
+2CB1;COPTIC SMALL LETTER OOU;Ll;0;L;;;;;N;;;2CB0;;2CB0
+2CB2;COPTIC CAPITAL LETTER DIALECT-P ALEF;Lu;0;L;;;;;N;;;;2CB3;
+2CB3;COPTIC SMALL LETTER DIALECT-P ALEF;Ll;0;L;;;;;N;;;2CB2;;2CB2
+2CB4;COPTIC CAPITAL LETTER OLD COPTIC AIN;Lu;0;L;;;;;N;;;;2CB5;
+2CB5;COPTIC SMALL LETTER OLD COPTIC AIN;Ll;0;L;;;;;N;;;2CB4;;2CB4
+2CB6;COPTIC CAPITAL LETTER CRYPTOGRAMMIC EIE;Lu;0;L;;;;;N;;;;2CB7;
+2CB7;COPTIC SMALL LETTER CRYPTOGRAMMIC EIE;Ll;0;L;;;;;N;;;2CB6;;2CB6
+2CB8;COPTIC CAPITAL LETTER DIALECT-P KAPA;Lu;0;L;;;;;N;;;;2CB9;
+2CB9;COPTIC SMALL LETTER DIALECT-P KAPA;Ll;0;L;;;;;N;;;2CB8;;2CB8
+2CBA;COPTIC CAPITAL LETTER DIALECT-P NI;Lu;0;L;;;;;N;;;;2CBB;
+2CBB;COPTIC SMALL LETTER DIALECT-P NI;Ll;0;L;;;;;N;;;2CBA;;2CBA
+2CBC;COPTIC CAPITAL LETTER CRYPTOGRAMMIC NI;Lu;0;L;;;;;N;;;;2CBD;
+2CBD;COPTIC SMALL LETTER CRYPTOGRAMMIC NI;Ll;0;L;;;;;N;;;2CBC;;2CBC
+2CBE;COPTIC CAPITAL LETTER OLD COPTIC OOU;Lu;0;L;;;;;N;;;;2CBF;
+2CBF;COPTIC SMALL LETTER OLD COPTIC OOU;Ll;0;L;;;;;N;;;2CBE;;2CBE
+2CC0;COPTIC CAPITAL LETTER SAMPI;Lu;0;L;;;;;N;;;;2CC1;
+2CC1;COPTIC SMALL LETTER SAMPI;Ll;0;L;;;;;N;;;2CC0;;2CC0
+2CC2;COPTIC CAPITAL LETTER CROSSED SHEI;Lu;0;L;;;;;N;;;;2CC3;
+2CC3;COPTIC SMALL LETTER CROSSED SHEI;Ll;0;L;;;;;N;;;2CC2;;2CC2
+2CC4;COPTIC CAPITAL LETTER OLD COPTIC SHEI;Lu;0;L;;;;;N;;;;2CC5;
+2CC5;COPTIC SMALL LETTER OLD COPTIC SHEI;Ll;0;L;;;;;N;;;2CC4;;2CC4
+2CC6;COPTIC CAPITAL LETTER OLD COPTIC ESH;Lu;0;L;;;;;N;;;;2CC7;
+2CC7;COPTIC SMALL LETTER OLD COPTIC ESH;Ll;0;L;;;;;N;;;2CC6;;2CC6
+2CC8;COPTIC CAPITAL LETTER AKHMIMIC KHEI;Lu;0;L;;;;;N;;;;2CC9;
+2CC9;COPTIC SMALL LETTER AKHMIMIC KHEI;Ll;0;L;;;;;N;;;2CC8;;2CC8
+2CCA;COPTIC CAPITAL LETTER DIALECT-P HORI;Lu;0;L;;;;;N;;;;2CCB;
+2CCB;COPTIC SMALL LETTER DIALECT-P HORI;Ll;0;L;;;;;N;;;2CCA;;2CCA
+2CCC;COPTIC CAPITAL LETTER OLD COPTIC HORI;Lu;0;L;;;;;N;;;;2CCD;
+2CCD;COPTIC SMALL LETTER OLD COPTIC HORI;Ll;0;L;;;;;N;;;2CCC;;2CCC
+2CCE;COPTIC CAPITAL LETTER OLD COPTIC HA;Lu;0;L;;;;;N;;;;2CCF;
+2CCF;COPTIC SMALL LETTER OLD COPTIC HA;Ll;0;L;;;;;N;;;2CCE;;2CCE
+2CD0;COPTIC CAPITAL LETTER L-SHAPED HA;Lu;0;L;;;;;N;;;;2CD1;
+2CD1;COPTIC SMALL LETTER L-SHAPED HA;Ll;0;L;;;;;N;;;2CD0;;2CD0
+2CD2;COPTIC CAPITAL LETTER OLD COPTIC HEI;Lu;0;L;;;;;N;;;;2CD3;
+2CD3;COPTIC SMALL LETTER OLD COPTIC HEI;Ll;0;L;;;;;N;;;2CD2;;2CD2
+2CD4;COPTIC CAPITAL LETTER OLD COPTIC HAT;Lu;0;L;;;;;N;;;;2CD5;
+2CD5;COPTIC SMALL LETTER OLD COPTIC HAT;Ll;0;L;;;;;N;;;2CD4;;2CD4
+2CD6;COPTIC CAPITAL LETTER OLD COPTIC GANGIA;Lu;0;L;;;;;N;;;;2CD7;
+2CD7;COPTIC SMALL LETTER OLD COPTIC GANGIA;Ll;0;L;;;;;N;;;2CD6;;2CD6
+2CD8;COPTIC CAPITAL LETTER OLD COPTIC DJA;Lu;0;L;;;;;N;;;;2CD9;
+2CD9;COPTIC SMALL LETTER OLD COPTIC DJA;Ll;0;L;;;;;N;;;2CD8;;2CD8
+2CDA;COPTIC CAPITAL LETTER OLD COPTIC SHIMA;Lu;0;L;;;;;N;;;;2CDB;
+2CDB;COPTIC SMALL LETTER OLD COPTIC SHIMA;Ll;0;L;;;;;N;;;2CDA;;2CDA
+2CDC;COPTIC CAPITAL LETTER OLD NUBIAN SHIMA;Lu;0;L;;;;;N;;;;2CDD;
+2CDD;COPTIC SMALL LETTER OLD NUBIAN SHIMA;Ll;0;L;;;;;N;;;2CDC;;2CDC
+2CDE;COPTIC CAPITAL LETTER OLD NUBIAN NGI;Lu;0;L;;;;;N;;;;2CDF;
+2CDF;COPTIC SMALL LETTER OLD NUBIAN NGI;Ll;0;L;;;;;N;;;2CDE;;2CDE
+2CE0;COPTIC CAPITAL LETTER OLD NUBIAN NYI;Lu;0;L;;;;;N;;;;2CE1;
+2CE1;COPTIC SMALL LETTER OLD NUBIAN NYI;Ll;0;L;;;;;N;;;2CE0;;2CE0
+2CE2;COPTIC CAPITAL LETTER OLD NUBIAN WAU;Lu;0;L;;;;;N;;;;2CE3;
+2CE3;COPTIC SMALL LETTER OLD NUBIAN WAU;Ll;0;L;;;;;N;;;2CE2;;2CE2
+2CE4;COPTIC SYMBOL KAI;Ll;0;L;;;;;N;;;;;
+2CE5;COPTIC SYMBOL MI RO;So;0;ON;;;;;N;;;;;
+2CE6;COPTIC SYMBOL PI RO;So;0;ON;;;;;N;;;;;
+2CE7;COPTIC SYMBOL STAUROS;So;0;ON;;;;;N;;;;;
+2CE8;COPTIC SYMBOL TAU RO;So;0;ON;;;;;N;;;;;
+2CE9;COPTIC SYMBOL KHI RO;So;0;ON;;;;;N;;;;;
+2CEA;COPTIC SYMBOL SHIMA SIMA;So;0;ON;;;;;N;;;;;
+2CF9;COPTIC OLD NUBIAN FULL STOP;Po;0;ON;;;;;N;;;;;
+2CFA;COPTIC OLD NUBIAN DIRECT QUESTION MARK;Po;0;ON;;;;;N;;;;;
+2CFB;COPTIC OLD NUBIAN INDIRECT QUESTION MARK;Po;0;ON;;;;;N;;;;;
+2CFC;COPTIC OLD NUBIAN VERSE DIVIDER;Po;0;ON;;;;;N;;;;;
+2CFD;COPTIC FRACTION ONE HALF;No;0;ON;;;;1/2;N;;;;;
+2CFE;COPTIC FULL STOP;Po;0;ON;;;;;N;;;;;
+2CFF;COPTIC MORPHOLOGICAL DIVIDER;Po;0;ON;;;;;N;;;;;
+2D00;GEORGIAN SMALL LETTER AN;Ll;0;L;;;;;N;;Khutsuri;10A0;;10A0
+2D01;GEORGIAN SMALL LETTER BAN;Ll;0;L;;;;;N;;Khutsuri;10A1;;10A1
+2D02;GEORGIAN SMALL LETTER GAN;Ll;0;L;;;;;N;;Khutsuri;10A2;;10A2
+2D03;GEORGIAN SMALL LETTER DON;Ll;0;L;;;;;N;;Khutsuri;10A3;;10A3
+2D04;GEORGIAN SMALL LETTER EN;Ll;0;L;;;;;N;;Khutsuri;10A4;;10A4
+2D05;GEORGIAN SMALL LETTER VIN;Ll;0;L;;;;;N;;Khutsuri;10A5;;10A5
+2D06;GEORGIAN SMALL LETTER ZEN;Ll;0;L;;;;;N;;Khutsuri;10A6;;10A6
+2D07;GEORGIAN SMALL LETTER TAN;Ll;0;L;;;;;N;;Khutsuri;10A7;;10A7
+2D08;GEORGIAN SMALL LETTER IN;Ll;0;L;;;;;N;;Khutsuri;10A8;;10A8
+2D09;GEORGIAN SMALL LETTER KAN;Ll;0;L;;;;;N;;Khutsuri;10A9;;10A9
+2D0A;GEORGIAN SMALL LETTER LAS;Ll;0;L;;;;;N;;Khutsuri;10AA;;10AA
+2D0B;GEORGIAN SMALL LETTER MAN;Ll;0;L;;;;;N;;Khutsuri;10AB;;10AB
+2D0C;GEORGIAN SMALL LETTER NAR;Ll;0;L;;;;;N;;Khutsuri;10AC;;10AC
+2D0D;GEORGIAN SMALL LETTER ON;Ll;0;L;;;;;N;;Khutsuri;10AD;;10AD
+2D0E;GEORGIAN SMALL LETTER PAR;Ll;0;L;;;;;N;;Khutsuri;10AE;;10AE
+2D0F;GEORGIAN SMALL LETTER ZHAR;Ll;0;L;;;;;N;;Khutsuri;10AF;;10AF
+2D10;GEORGIAN SMALL LETTER RAE;Ll;0;L;;;;;N;;Khutsuri;10B0;;10B0
+2D11;GEORGIAN SMALL LETTER SAN;Ll;0;L;;;;;N;;Khutsuri;10B1;;10B1
+2D12;GEORGIAN SMALL LETTER TAR;Ll;0;L;;;;;N;;Khutsuri;10B2;;10B2
+2D13;GEORGIAN SMALL LETTER UN;Ll;0;L;;;;;N;;Khutsuri;10B3;;10B3
+2D14;GEORGIAN SMALL LETTER PHAR;Ll;0;L;;;;;N;;Khutsuri;10B4;;10B4
+2D15;GEORGIAN SMALL LETTER KHAR;Ll;0;L;;;;;N;;Khutsuri;10B5;;10B5
+2D16;GEORGIAN SMALL LETTER GHAN;Ll;0;L;;;;;N;;Khutsuri;10B6;;10B6
+2D17;GEORGIAN SMALL LETTER QAR;Ll;0;L;;;;;N;;Khutsuri;10B7;;10B7
+2D18;GEORGIAN SMALL LETTER SHIN;Ll;0;L;;;;;N;;Khutsuri;10B8;;10B8
+2D19;GEORGIAN SMALL LETTER CHIN;Ll;0;L;;;;;N;;Khutsuri;10B9;;10B9
+2D1A;GEORGIAN SMALL LETTER CAN;Ll;0;L;;;;;N;;Khutsuri;10BA;;10BA
+2D1B;GEORGIAN SMALL LETTER JIL;Ll;0;L;;;;;N;;Khutsuri;10BB;;10BB
+2D1C;GEORGIAN SMALL LETTER CIL;Ll;0;L;;;;;N;;Khutsuri;10BC;;10BC
+2D1D;GEORGIAN SMALL LETTER CHAR;Ll;0;L;;;;;N;;Khutsuri;10BD;;10BD
+2D1E;GEORGIAN SMALL LETTER XAN;Ll;0;L;;;;;N;;Khutsuri;10BE;;10BE
+2D1F;GEORGIAN SMALL LETTER JHAN;Ll;0;L;;;;;N;;Khutsuri;10BF;;10BF
+2D20;GEORGIAN SMALL LETTER HAE;Ll;0;L;;;;;N;;Khutsuri;10C0;;10C0
+2D21;GEORGIAN SMALL LETTER HE;Ll;0;L;;;;;N;;Khutsuri;10C1;;10C1
+2D22;GEORGIAN SMALL LETTER HIE;Ll;0;L;;;;;N;;Khutsuri;10C2;;10C2
+2D23;GEORGIAN SMALL LETTER WE;Ll;0;L;;;;;N;;Khutsuri;10C3;;10C3
+2D24;GEORGIAN SMALL LETTER HAR;Ll;0;L;;;;;N;;Khutsuri;10C4;;10C4
+2D25;GEORGIAN SMALL LETTER HOE;Ll;0;L;;;;;N;;Khutsuri;10C5;;10C5
+2D30;TIFINAGH LETTER YA;Lo;0;L;;;;;N;;;;;
+2D31;TIFINAGH LETTER YAB;Lo;0;L;;;;;N;;;;;
+2D32;TIFINAGH LETTER YABH;Lo;0;L;;;;;N;;;;;
+2D33;TIFINAGH LETTER YAG;Lo;0;L;;;;;N;;;;;
+2D34;TIFINAGH LETTER YAGHH;Lo;0;L;;;;;N;;;;;
+2D35;TIFINAGH LETTER BERBER ACADEMY YAJ;Lo;0;L;;;;;N;;;;;
+2D36;TIFINAGH LETTER YAJ;Lo;0;L;;;;;N;;;;;
+2D37;TIFINAGH LETTER YAD;Lo;0;L;;;;;N;;;;;
+2D38;TIFINAGH LETTER YADH;Lo;0;L;;;;;N;;;;;
+2D39;TIFINAGH LETTER YADD;Lo;0;L;;;;;N;;;;;
+2D3A;TIFINAGH LETTER YADDH;Lo;0;L;;;;;N;;;;;
+2D3B;TIFINAGH LETTER YEY;Lo;0;L;;;;;N;;;;;
+2D3C;TIFINAGH LETTER YAF;Lo;0;L;;;;;N;;;;;
+2D3D;TIFINAGH LETTER YAK;Lo;0;L;;;;;N;;;;;
+2D3E;TIFINAGH LETTER TUAREG YAK;Lo;0;L;;;;;N;;;;;
+2D3F;TIFINAGH LETTER YAKHH;Lo;0;L;;;;;N;;;;;
+2D40;TIFINAGH LETTER YAH;Lo;0;L;;;;;N;;Tuareg yab;;;
+2D41;TIFINAGH LETTER BERBER ACADEMY YAH;Lo;0;L;;;;;N;;;;;
+2D42;TIFINAGH LETTER TUAREG YAH;Lo;0;L;;;;;N;;;;;
+2D43;TIFINAGH LETTER YAHH;Lo;0;L;;;;;N;;;;;
+2D44;TIFINAGH LETTER YAA;Lo;0;L;;;;;N;;;;;
+2D45;TIFINAGH LETTER YAKH;Lo;0;L;;;;;N;;;;;
+2D46;TIFINAGH LETTER TUAREG YAKH;Lo;0;L;;;;;N;;;;;
+2D47;TIFINAGH LETTER YAQ;Lo;0;L;;;;;N;;;;;
+2D48;TIFINAGH LETTER TUAREG YAQ;Lo;0;L;;;;;N;;;;;
+2D49;TIFINAGH LETTER YI;Lo;0;L;;;;;N;;;;;
+2D4A;TIFINAGH LETTER YAZH;Lo;0;L;;;;;N;;;;;
+2D4B;TIFINAGH LETTER AHAGGAR YAZH;Lo;0;L;;;;;N;;;;;
+2D4C;TIFINAGH LETTER TUAREG YAZH;Lo;0;L;;;;;N;;;;;
+2D4D;TIFINAGH LETTER YAL;Lo;0;L;;;;;N;;;;;
+2D4E;TIFINAGH LETTER YAM;Lo;0;L;;;;;N;;;;;
+2D4F;TIFINAGH LETTER YAN;Lo;0;L;;;;;N;;;;;
+2D50;TIFINAGH LETTER TUAREG YAGN;Lo;0;L;;;;;N;;;;;
+2D51;TIFINAGH LETTER TUAREG YANG;Lo;0;L;;;;;N;;;;;
+2D52;TIFINAGH LETTER YAP;Lo;0;L;;;;;N;;;;;
+2D53;TIFINAGH LETTER YU;Lo;0;L;;;;;N;;Tuareg yaw;;;
+2D54;TIFINAGH LETTER YAR;Lo;0;L;;;;;N;;;;;
+2D55;TIFINAGH LETTER YARR;Lo;0;L;;;;;N;;;;;
+2D56;TIFINAGH LETTER YAGH;Lo;0;L;;;;;N;;;;;
+2D57;TIFINAGH LETTER TUAREG YAGH;Lo;0;L;;;;;N;;;;;
+2D58;TIFINAGH LETTER AYER YAGH;Lo;0;L;;;;;N;;Adrar yaj;;;
+2D59;TIFINAGH LETTER YAS;Lo;0;L;;;;;N;;;;;
+2D5A;TIFINAGH LETTER YASS;Lo;0;L;;;;;N;;;;;
+2D5B;TIFINAGH LETTER YASH;Lo;0;L;;;;;N;;;;;
+2D5C;TIFINAGH LETTER YAT;Lo;0;L;;;;;N;;;;;
+2D5D;TIFINAGH LETTER YATH;Lo;0;L;;;;;N;;;;;
+2D5E;TIFINAGH LETTER YACH;Lo;0;L;;;;;N;;;;;
+2D5F;TIFINAGH LETTER YATT;Lo;0;L;;;;;N;;;;;
+2D60;TIFINAGH LETTER YAV;Lo;0;L;;;;;N;;;;;
+2D61;TIFINAGH LETTER YAW;Lo;0;L;;;;;N;;;;;
+2D62;TIFINAGH LETTER YAY;Lo;0;L;;;;;N;;;;;
+2D63;TIFINAGH LETTER YAZ;Lo;0;L;;;;;N;;;;;
+2D64;TIFINAGH LETTER TAWELLEMET YAZ;Lo;0;L;;;;;N;;harpoon yaz;;;
+2D65;TIFINAGH LETTER YAZZ;Lo;0;L;;;;;N;;;;;
+2D6F;TIFINAGH MODIFIER LETTER LABIALIZATION MARK;Lm;0;L;<super> 2D61;;;;N;;tamatart;;;
+2D80;ETHIOPIC SYLLABLE LOA;Lo;0;L;;;;;N;;;;;
+2D81;ETHIOPIC SYLLABLE MOA;Lo;0;L;;;;;N;;;;;
+2D82;ETHIOPIC SYLLABLE ROA;Lo;0;L;;;;;N;;;;;
+2D83;ETHIOPIC SYLLABLE SOA;Lo;0;L;;;;;N;;;;;
+2D84;ETHIOPIC SYLLABLE SHOA;Lo;0;L;;;;;N;;;;;
+2D85;ETHIOPIC SYLLABLE BOA;Lo;0;L;;;;;N;;;;;
+2D86;ETHIOPIC SYLLABLE TOA;Lo;0;L;;;;;N;;;;;
+2D87;ETHIOPIC SYLLABLE COA;Lo;0;L;;;;;N;;;;;
+2D88;ETHIOPIC SYLLABLE NOA;Lo;0;L;;;;;N;;;;;
+2D89;ETHIOPIC SYLLABLE NYOA;Lo;0;L;;;;;N;;;;;
+2D8A;ETHIOPIC SYLLABLE GLOTTAL OA;Lo;0;L;;;;;N;;;;;
+2D8B;ETHIOPIC SYLLABLE ZOA;Lo;0;L;;;;;N;;;;;
+2D8C;ETHIOPIC SYLLABLE DOA;Lo;0;L;;;;;N;;;;;
+2D8D;ETHIOPIC SYLLABLE DDOA;Lo;0;L;;;;;N;;;;;
+2D8E;ETHIOPIC SYLLABLE JOA;Lo;0;L;;;;;N;;;;;
+2D8F;ETHIOPIC SYLLABLE THOA;Lo;0;L;;;;;N;;;;;
+2D90;ETHIOPIC SYLLABLE CHOA;Lo;0;L;;;;;N;;;;;
+2D91;ETHIOPIC SYLLABLE PHOA;Lo;0;L;;;;;N;;;;;
+2D92;ETHIOPIC SYLLABLE POA;Lo;0;L;;;;;N;;;;;
+2D93;ETHIOPIC SYLLABLE GGWA;Lo;0;L;;;;;N;;;;;
+2D94;ETHIOPIC SYLLABLE GGWI;Lo;0;L;;;;;N;;;;;
+2D95;ETHIOPIC SYLLABLE GGWEE;Lo;0;L;;;;;N;;;;;
+2D96;ETHIOPIC SYLLABLE GGWE;Lo;0;L;;;;;N;;;;;
+2DA0;ETHIOPIC SYLLABLE SSA;Lo;0;L;;;;;N;;;;;
+2DA1;ETHIOPIC SYLLABLE SSU;Lo;0;L;;;;;N;;;;;
+2DA2;ETHIOPIC SYLLABLE SSI;Lo;0;L;;;;;N;;;;;
+2DA3;ETHIOPIC SYLLABLE SSAA;Lo;0;L;;;;;N;;;;;
+2DA4;ETHIOPIC SYLLABLE SSEE;Lo;0;L;;;;;N;;;;;
+2DA5;ETHIOPIC SYLLABLE SSE;Lo;0;L;;;;;N;;;;;
+2DA6;ETHIOPIC SYLLABLE SSO;Lo;0;L;;;;;N;;;;;
+2DA8;ETHIOPIC SYLLABLE CCA;Lo;0;L;;;;;N;;;;;
+2DA9;ETHIOPIC SYLLABLE CCU;Lo;0;L;;;;;N;;;;;
+2DAA;ETHIOPIC SYLLABLE CCI;Lo;0;L;;;;;N;;;;;
+2DAB;ETHIOPIC SYLLABLE CCAA;Lo;0;L;;;;;N;;;;;
+2DAC;ETHIOPIC SYLLABLE CCEE;Lo;0;L;;;;;N;;;;;
+2DAD;ETHIOPIC SYLLABLE CCE;Lo;0;L;;;;;N;;;;;
+2DAE;ETHIOPIC SYLLABLE CCO;Lo;0;L;;;;;N;;;;;
+2DB0;ETHIOPIC SYLLABLE ZZA;Lo;0;L;;;;;N;;;;;
+2DB1;ETHIOPIC SYLLABLE ZZU;Lo;0;L;;;;;N;;;;;
+2DB2;ETHIOPIC SYLLABLE ZZI;Lo;0;L;;;;;N;;;;;
+2DB3;ETHIOPIC SYLLABLE ZZAA;Lo;0;L;;;;;N;;;;;
+2DB4;ETHIOPIC SYLLABLE ZZEE;Lo;0;L;;;;;N;;;;;
+2DB5;ETHIOPIC SYLLABLE ZZE;Lo;0;L;;;;;N;;;;;
+2DB6;ETHIOPIC SYLLABLE ZZO;Lo;0;L;;;;;N;;;;;
+2DB8;ETHIOPIC SYLLABLE CCHA;Lo;0;L;;;;;N;;;;;
+2DB9;ETHIOPIC SYLLABLE CCHU;Lo;0;L;;;;;N;;;;;
+2DBA;ETHIOPIC SYLLABLE CCHI;Lo;0;L;;;;;N;;;;;
+2DBB;ETHIOPIC SYLLABLE CCHAA;Lo;0;L;;;;;N;;;;;
+2DBC;ETHIOPIC SYLLABLE CCHEE;Lo;0;L;;;;;N;;;;;
+2DBD;ETHIOPIC SYLLABLE CCHE;Lo;0;L;;;;;N;;;;;
+2DBE;ETHIOPIC SYLLABLE CCHO;Lo;0;L;;;;;N;;;;;
+2DC0;ETHIOPIC SYLLABLE QYA;Lo;0;L;;;;;N;;;;;
+2DC1;ETHIOPIC SYLLABLE QYU;Lo;0;L;;;;;N;;;;;
+2DC2;ETHIOPIC SYLLABLE QYI;Lo;0;L;;;;;N;;;;;
+2DC3;ETHIOPIC SYLLABLE QYAA;Lo;0;L;;;;;N;;;;;
+2DC4;ETHIOPIC SYLLABLE QYEE;Lo;0;L;;;;;N;;;;;
+2DC5;ETHIOPIC SYLLABLE QYE;Lo;0;L;;;;;N;;;;;
+2DC6;ETHIOPIC SYLLABLE QYO;Lo;0;L;;;;;N;;;;;
+2DC8;ETHIOPIC SYLLABLE KYA;Lo;0;L;;;;;N;;;;;
+2DC9;ETHIOPIC SYLLABLE KYU;Lo;0;L;;;;;N;;;;;
+2DCA;ETHIOPIC SYLLABLE KYI;Lo;0;L;;;;;N;;;;;
+2DCB;ETHIOPIC SYLLABLE KYAA;Lo;0;L;;;;;N;;;;;
+2DCC;ETHIOPIC SYLLABLE KYEE;Lo;0;L;;;;;N;;;;;
+2DCD;ETHIOPIC SYLLABLE KYE;Lo;0;L;;;;;N;;;;;
+2DCE;ETHIOPIC SYLLABLE KYO;Lo;0;L;;;;;N;;;;;
+2DD0;ETHIOPIC SYLLABLE XYA;Lo;0;L;;;;;N;;;;;
+2DD1;ETHIOPIC SYLLABLE XYU;Lo;0;L;;;;;N;;;;;
+2DD2;ETHIOPIC SYLLABLE XYI;Lo;0;L;;;;;N;;;;;
+2DD3;ETHIOPIC SYLLABLE XYAA;Lo;0;L;;;;;N;;;;;
+2DD4;ETHIOPIC SYLLABLE XYEE;Lo;0;L;;;;;N;;;;;
+2DD5;ETHIOPIC SYLLABLE XYE;Lo;0;L;;;;;N;;;;;
+2DD6;ETHIOPIC SYLLABLE XYO;Lo;0;L;;;;;N;;;;;
+2DD8;ETHIOPIC SYLLABLE GYA;Lo;0;L;;;;;N;;;;;
+2DD9;ETHIOPIC SYLLABLE GYU;Lo;0;L;;;;;N;;;;;
+2DDA;ETHIOPIC SYLLABLE GYI;Lo;0;L;;;;;N;;;;;
+2DDB;ETHIOPIC SYLLABLE GYAA;Lo;0;L;;;;;N;;;;;
+2DDC;ETHIOPIC SYLLABLE GYEE;Lo;0;L;;;;;N;;;;;
+2DDD;ETHIOPIC SYLLABLE GYE;Lo;0;L;;;;;N;;;;;
+2DDE;ETHIOPIC SYLLABLE GYO;Lo;0;L;;;;;N;;;;;
+2E00;RIGHT ANGLE SUBSTITUTION MARKER;Po;0;ON;;;;;N;;;;;
+2E01;RIGHT ANGLE DOTTED SUBSTITUTION MARKER;Po;0;ON;;;;;N;;;;;
+2E02;LEFT SUBSTITUTION BRACKET;Pi;0;ON;;;;;Y;;;;;
+2E03;RIGHT SUBSTITUTION BRACKET;Pf;0;ON;;;;;Y;;;;;
+2E04;LEFT DOTTED SUBSTITUTION BRACKET;Pi;0;ON;;;;;Y;;;;;
+2E05;RIGHT DOTTED SUBSTITUTION BRACKET;Pf;0;ON;;;;;Y;;;;;
+2E06;RAISED INTERPOLATION MARKER;Po;0;ON;;;;;N;;;;;
+2E07;RAISED DOTTED INTERPOLATION MARKER;Po;0;ON;;;;;N;;;;;
+2E08;DOTTED TRANSPOSITION MARKER;Po;0;ON;;;;;N;;;;;
+2E09;LEFT TRANSPOSITION BRACKET;Pi;0;ON;;;;;Y;;;;;
+2E0A;RIGHT TRANSPOSITION BRACKET;Pf;0;ON;;;;;Y;;;;;
+2E0B;RAISED SQUARE;Po;0;ON;;;;;N;;;;;
+2E0C;LEFT RAISED OMISSION BRACKET;Pi;0;ON;;;;;Y;;;;;
+2E0D;RIGHT RAISED OMISSION BRACKET;Pf;0;ON;;;;;Y;;;;;
+2E0E;EDITORIAL CORONIS;Po;0;ON;;;;;N;;;;;
+2E0F;PARAGRAPHOS;Po;0;ON;;;;;N;;;;;
+2E10;FORKED PARAGRAPHOS;Po;0;ON;;;;;N;;;;;
+2E11;REVERSED FORKED PARAGRAPHOS;Po;0;ON;;;;;N;;;;;
+2E12;HYPODIASTOLE;Po;0;ON;;;;;N;;;;;
+2E13;DOTTED OBELOS;Po;0;ON;;;;;N;;;;;
+2E14;DOWNWARDS ANCORA;Po;0;ON;;;;;N;;;;;
+2E15;UPWARDS ANCORA;Po;0;ON;;;;;N;;;;;
+2E16;DOTTED RIGHT-POINTING ANGLE;Po;0;ON;;;;;N;;;;;
+2E17;DOUBLE OBLIQUE HYPHEN;Pd;0;ON;;;;;N;;;;;
+2E1C;LEFT LOW PARAPHRASE BRACKET;Pi;0;ON;;;;;Y;;;;;
+2E1D;RIGHT LOW PARAPHRASE BRACKET;Pf;0;ON;;;;;Y;;;;;
+2E80;CJK RADICAL REPEAT;So;0;ON;;;;;N;;;;;
+2E81;CJK RADICAL CLIFF;So;0;ON;;;;;N;;;;;
+2E82;CJK RADICAL SECOND ONE;So;0;ON;;;;;N;;;;;
+2E83;CJK RADICAL SECOND TWO;So;0;ON;;;;;N;;;;;
+2E84;CJK RADICAL SECOND THREE;So;0;ON;;;;;N;;;;;
+2E85;CJK RADICAL PERSON;So;0;ON;;;;;N;;;;;
+2E86;CJK RADICAL BOX;So;0;ON;;;;;N;;;;;
+2E87;CJK RADICAL TABLE;So;0;ON;;;;;N;;;;;
+2E88;CJK RADICAL KNIFE ONE;So;0;ON;;;;;N;;;;;
+2E89;CJK RADICAL KNIFE TWO;So;0;ON;;;;;N;;;;;
+2E8A;CJK RADICAL DIVINATION;So;0;ON;;;;;N;;;;;
+2E8B;CJK RADICAL SEAL;So;0;ON;;;;;N;;;;;
+2E8C;CJK RADICAL SMALL ONE;So;0;ON;;;;;N;;;;;
+2E8D;CJK RADICAL SMALL TWO;So;0;ON;;;;;N;;;;;
+2E8E;CJK RADICAL LAME ONE;So;0;ON;;;;;N;;;;;
+2E8F;CJK RADICAL LAME TWO;So;0;ON;;;;;N;;;;;
+2E90;CJK RADICAL LAME THREE;So;0;ON;;;;;N;;;;;
+2E91;CJK RADICAL LAME FOUR;So;0;ON;;;;;N;;;;;
+2E92;CJK RADICAL SNAKE;So;0;ON;;;;;N;;;;;
+2E93;CJK RADICAL THREAD;So;0;ON;;;;;N;;;;;
+2E94;CJK RADICAL SNOUT ONE;So;0;ON;;;;;N;;;;;
+2E95;CJK RADICAL SNOUT TWO;So;0;ON;;;;;N;;;;;
+2E96;CJK RADICAL HEART ONE;So;0;ON;;;;;N;;;;;
+2E97;CJK RADICAL HEART TWO;So;0;ON;;;;;N;;;;;
+2E98;CJK RADICAL HAND;So;0;ON;;;;;N;;;;;
+2E99;CJK RADICAL RAP;So;0;ON;;;;;N;;;;;
+2E9B;CJK RADICAL CHOKE;So;0;ON;;;;;N;;;;;
+2E9C;CJK RADICAL SUN;So;0;ON;;;;;N;;;;;
+2E9D;CJK RADICAL MOON;So;0;ON;;;;;N;;;;;
+2E9E;CJK RADICAL DEATH;So;0;ON;;;;;N;;;;;
+2E9F;CJK RADICAL MOTHER;So;0;ON;<compat> 6BCD;;;;N;;;;;
+2EA0;CJK RADICAL CIVILIAN;So;0;ON;;;;;N;;;;;
+2EA1;CJK RADICAL WATER ONE;So;0;ON;;;;;N;;;;;
+2EA2;CJK RADICAL WATER TWO;So;0;ON;;;;;N;;;;;
+2EA3;CJK RADICAL FIRE;So;0;ON;;;;;N;;;;;
+2EA4;CJK RADICAL PAW ONE;So;0;ON;;;;;N;;;;;
+2EA5;CJK RADICAL PAW TWO;So;0;ON;;;;;N;;;;;
+2EA6;CJK RADICAL SIMPLIFIED HALF TREE TRUNK;So;0;ON;;;;;N;;;;;
+2EA7;CJK RADICAL COW;So;0;ON;;;;;N;;;;;
+2EA8;CJK RADICAL DOG;So;0;ON;;;;;N;;;;;
+2EA9;CJK RADICAL JADE;So;0;ON;;;;;N;;;;;
+2EAA;CJK RADICAL BOLT OF CLOTH;So;0;ON;;;;;N;;;;;
+2EAB;CJK RADICAL EYE;So;0;ON;;;;;N;;;;;
+2EAC;CJK RADICAL SPIRIT ONE;So;0;ON;;;;;N;;;;;
+2EAD;CJK RADICAL SPIRIT TWO;So;0;ON;;;;;N;;;;;
+2EAE;CJK RADICAL BAMBOO;So;0;ON;;;;;N;;;;;
+2EAF;CJK RADICAL SILK;So;0;ON;;;;;N;;;;;
+2EB0;CJK RADICAL C-SIMPLIFIED SILK;So;0;ON;;;;;N;;;;;
+2EB1;CJK RADICAL NET ONE;So;0;ON;;;;;N;;;;;
+2EB2;CJK RADICAL NET TWO;So;0;ON;;;;;N;;;;;
+2EB3;CJK RADICAL NET THREE;So;0;ON;;;;;N;;;;;
+2EB4;CJK RADICAL NET FOUR;So;0;ON;;;;;N;;;;;
+2EB5;CJK RADICAL MESH;So;0;ON;;;;;N;;;;;
+2EB6;CJK RADICAL SHEEP;So;0;ON;;;;;N;;;;;
+2EB7;CJK RADICAL RAM;So;0;ON;;;;;N;;;;;
+2EB8;CJK RADICAL EWE;So;0;ON;;;;;N;;;;;
+2EB9;CJK RADICAL OLD;So;0;ON;;;;;N;;;;;
+2EBA;CJK RADICAL BRUSH ONE;So;0;ON;;;;;N;;;;;
+2EBB;CJK RADICAL BRUSH TWO;So;0;ON;;;;;N;;;;;
+2EBC;CJK RADICAL MEAT;So;0;ON;;;;;N;;;;;
+2EBD;CJK RADICAL MORTAR;So;0;ON;;;;;N;;;;;
+2EBE;CJK RADICAL GRASS ONE;So;0;ON;;;;;N;;;;;
+2EBF;CJK RADICAL GRASS TWO;So;0;ON;;;;;N;;;;;
+2EC0;CJK RADICAL GRASS THREE;So;0;ON;;;;;N;;;;;
+2EC1;CJK RADICAL TIGER;So;0;ON;;;;;N;;;;;
+2EC2;CJK RADICAL CLOTHES;So;0;ON;;;;;N;;;;;
+2EC3;CJK RADICAL WEST ONE;So;0;ON;;;;;N;;;;;
+2EC4;CJK RADICAL WEST TWO;So;0;ON;;;;;N;;;;;
+2EC5;CJK RADICAL C-SIMPLIFIED SEE;So;0;ON;;;;;N;;;;;
+2EC6;CJK RADICAL SIMPLIFIED HORN;So;0;ON;;;;;N;;;;;
+2EC7;CJK RADICAL HORN;So;0;ON;;;;;N;;;;;
+2EC8;CJK RADICAL C-SIMPLIFIED SPEECH;So;0;ON;;;;;N;;;;;
+2EC9;CJK RADICAL C-SIMPLIFIED SHELL;So;0;ON;;;;;N;;;;;
+2ECA;CJK RADICAL FOOT;So;0;ON;;;;;N;;;;;
+2ECB;CJK RADICAL C-SIMPLIFIED CART;So;0;ON;;;;;N;;;;;
+2ECC;CJK RADICAL SIMPLIFIED WALK;So;0;ON;;;;;N;;;;;
+2ECD;CJK RADICAL WALK ONE;So;0;ON;;;;;N;;;;;
+2ECE;CJK RADICAL WALK TWO;So;0;ON;;;;;N;;;;;
+2ECF;CJK RADICAL CITY;So;0;ON;;;;;N;;;;;
+2ED0;CJK RADICAL C-SIMPLIFIED GOLD;So;0;ON;;;;;N;;;;;
+2ED1;CJK RADICAL LONG ONE;So;0;ON;;;;;N;;;;;
+2ED2;CJK RADICAL LONG TWO;So;0;ON;;;;;N;;;;;
+2ED3;CJK RADICAL C-SIMPLIFIED LONG;So;0;ON;;;;;N;;;;;
+2ED4;CJK RADICAL C-SIMPLIFIED GATE;So;0;ON;;;;;N;;;;;
+2ED5;CJK RADICAL MOUND ONE;So;0;ON;;;;;N;;;;;
+2ED6;CJK RADICAL MOUND TWO;So;0;ON;;;;;N;;;;;
+2ED7;CJK RADICAL RAIN;So;0;ON;;;;;N;;;;;
+2ED8;CJK RADICAL BLUE;So;0;ON;;;;;N;;;;;
+2ED9;CJK RADICAL C-SIMPLIFIED TANNED LEATHER;So;0;ON;;;;;N;;;;;
+2EDA;CJK RADICAL C-SIMPLIFIED LEAF;So;0;ON;;;;;N;;;;;
+2EDB;CJK RADICAL C-SIMPLIFIED WIND;So;0;ON;;;;;N;;;;;
+2EDC;CJK RADICAL C-SIMPLIFIED FLY;So;0;ON;;;;;N;;;;;
+2EDD;CJK RADICAL EAT ONE;So;0;ON;;;;;N;;;;;
+2EDE;CJK RADICAL EAT TWO;So;0;ON;;;;;N;;;;;
+2EDF;CJK RADICAL EAT THREE;So;0;ON;;;;;N;;;;;
+2EE0;CJK RADICAL C-SIMPLIFIED EAT;So;0;ON;;;;;N;;;;;
+2EE1;CJK RADICAL HEAD;So;0;ON;;;;;N;;;;;
+2EE2;CJK RADICAL C-SIMPLIFIED HORSE;So;0;ON;;;;;N;;;;;
+2EE3;CJK RADICAL BONE;So;0;ON;;;;;N;;;;;
+2EE4;CJK RADICAL GHOST;So;0;ON;;;;;N;;;;;
+2EE5;CJK RADICAL C-SIMPLIFIED FISH;So;0;ON;;;;;N;;;;;
+2EE6;CJK RADICAL C-SIMPLIFIED BIRD;So;0;ON;;;;;N;;;;;
+2EE7;CJK RADICAL C-SIMPLIFIED SALT;So;0;ON;;;;;N;;;;;
+2EE8;CJK RADICAL SIMPLIFIED WHEAT;So;0;ON;;;;;N;;;;;
+2EE9;CJK RADICAL SIMPLIFIED YELLOW;So;0;ON;;;;;N;;;;;
+2EEA;CJK RADICAL C-SIMPLIFIED FROG;So;0;ON;;;;;N;;;;;
+2EEB;CJK RADICAL J-SIMPLIFIED EVEN;So;0;ON;;;;;N;;;;;
+2EEC;CJK RADICAL C-SIMPLIFIED EVEN;So;0;ON;;;;;N;;;;;
+2EED;CJK RADICAL J-SIMPLIFIED TOOTH;So;0;ON;;;;;N;;;;;
+2EEE;CJK RADICAL C-SIMPLIFIED TOOTH;So;0;ON;;;;;N;;;;;
+2EEF;CJK RADICAL J-SIMPLIFIED DRAGON;So;0;ON;;;;;N;;;;;
+2EF0;CJK RADICAL C-SIMPLIFIED DRAGON;So;0;ON;;;;;N;;;;;
+2EF1;CJK RADICAL TURTLE;So;0;ON;;;;;N;;;;;
+2EF2;CJK RADICAL J-SIMPLIFIED TURTLE;So;0;ON;;;;;N;;;;;
+2EF3;CJK RADICAL C-SIMPLIFIED TURTLE;So;0;ON;<compat> 9F9F;;;;N;;;;;
+2F00;KANGXI RADICAL ONE;So;0;ON;<compat> 4E00;;;;N;;;;;
+2F01;KANGXI RADICAL LINE;So;0;ON;<compat> 4E28;;;;N;;;;;
+2F02;KANGXI RADICAL DOT;So;0;ON;<compat> 4E36;;;;N;;;;;
+2F03;KANGXI RADICAL SLASH;So;0;ON;<compat> 4E3F;;;;N;;;;;
+2F04;KANGXI RADICAL SECOND;So;0;ON;<compat> 4E59;;;;N;;;;;
+2F05;KANGXI RADICAL HOOK;So;0;ON;<compat> 4E85;;;;N;;;;;
+2F06;KANGXI RADICAL TWO;So;0;ON;<compat> 4E8C;;;;N;;;;;
+2F07;KANGXI RADICAL LID;So;0;ON;<compat> 4EA0;;;;N;;;;;
+2F08;KANGXI RADICAL MAN;So;0;ON;<compat> 4EBA;;;;N;;;;;
+2F09;KANGXI RADICAL LEGS;So;0;ON;<compat> 513F;;;;N;;;;;
+2F0A;KANGXI RADICAL ENTER;So;0;ON;<compat> 5165;;;;N;;;;;
+2F0B;KANGXI RADICAL EIGHT;So;0;ON;<compat> 516B;;;;N;;;;;
+2F0C;KANGXI RADICAL DOWN BOX;So;0;ON;<compat> 5182;;;;N;;;;;
+2F0D;KANGXI RADICAL COVER;So;0;ON;<compat> 5196;;;;N;;;;;
+2F0E;KANGXI RADICAL ICE;So;0;ON;<compat> 51AB;;;;N;;;;;
+2F0F;KANGXI RADICAL TABLE;So;0;ON;<compat> 51E0;;;;N;;;;;
+2F10;KANGXI RADICAL OPEN BOX;So;0;ON;<compat> 51F5;;;;N;;;;;
+2F11;KANGXI RADICAL KNIFE;So;0;ON;<compat> 5200;;;;N;;;;;
+2F12;KANGXI RADICAL POWER;So;0;ON;<compat> 529B;;;;N;;;;;
+2F13;KANGXI RADICAL WRAP;So;0;ON;<compat> 52F9;;;;N;;;;;
+2F14;KANGXI RADICAL SPOON;So;0;ON;<compat> 5315;;;;N;;;;;
+2F15;KANGXI RADICAL RIGHT OPEN BOX;So;0;ON;<compat> 531A;;;;N;;;;;
+2F16;KANGXI RADICAL HIDING ENCLOSURE;So;0;ON;<compat> 5338;;;;N;;;;;
+2F17;KANGXI RADICAL TEN;So;0;ON;<compat> 5341;;;;N;;;;;
+2F18;KANGXI RADICAL DIVINATION;So;0;ON;<compat> 535C;;;;N;;;;;
+2F19;KANGXI RADICAL SEAL;So;0;ON;<compat> 5369;;;;N;;;;;
+2F1A;KANGXI RADICAL CLIFF;So;0;ON;<compat> 5382;;;;N;;;;;
+2F1B;KANGXI RADICAL PRIVATE;So;0;ON;<compat> 53B6;;;;N;;;;;
+2F1C;KANGXI RADICAL AGAIN;So;0;ON;<compat> 53C8;;;;N;;;;;
+2F1D;KANGXI RADICAL MOUTH;So;0;ON;<compat> 53E3;;;;N;;;;;
+2F1E;KANGXI RADICAL ENCLOSURE;So;0;ON;<compat> 56D7;;;;N;;;;;
+2F1F;KANGXI RADICAL EARTH;So;0;ON;<compat> 571F;;;;N;;;;;
+2F20;KANGXI RADICAL SCHOLAR;So;0;ON;<compat> 58EB;;;;N;;;;;
+2F21;KANGXI RADICAL GO;So;0;ON;<compat> 5902;;;;N;;;;;
+2F22;KANGXI RADICAL GO SLOWLY;So;0;ON;<compat> 590A;;;;N;;;;;
+2F23;KANGXI RADICAL EVENING;So;0;ON;<compat> 5915;;;;N;;;;;
+2F24;KANGXI RADICAL BIG;So;0;ON;<compat> 5927;;;;N;;;;;
+2F25;KANGXI RADICAL WOMAN;So;0;ON;<compat> 5973;;;;N;;;;;
+2F26;KANGXI RADICAL CHILD;So;0;ON;<compat> 5B50;;;;N;;;;;
+2F27;KANGXI RADICAL ROOF;So;0;ON;<compat> 5B80;;;;N;;;;;
+2F28;KANGXI RADICAL INCH;So;0;ON;<compat> 5BF8;;;;N;;;;;
+2F29;KANGXI RADICAL SMALL;So;0;ON;<compat> 5C0F;;;;N;;;;;
+2F2A;KANGXI RADICAL LAME;So;0;ON;<compat> 5C22;;;;N;;;;;
+2F2B;KANGXI RADICAL CORPSE;So;0;ON;<compat> 5C38;;;;N;;;;;
+2F2C;KANGXI RADICAL SPROUT;So;0;ON;<compat> 5C6E;;;;N;;;;;
+2F2D;KANGXI RADICAL MOUNTAIN;So;0;ON;<compat> 5C71;;;;N;;;;;
+2F2E;KANGXI RADICAL RIVER;So;0;ON;<compat> 5DDB;;;;N;;;;;
+2F2F;KANGXI RADICAL WORK;So;0;ON;<compat> 5DE5;;;;N;;;;;
+2F30;KANGXI RADICAL ONESELF;So;0;ON;<compat> 5DF1;;;;N;;;;;
+2F31;KANGXI RADICAL TURBAN;So;0;ON;<compat> 5DFE;;;;N;;;;;
+2F32;KANGXI RADICAL DRY;So;0;ON;<compat> 5E72;;;;N;;;;;
+2F33;KANGXI RADICAL SHORT THREAD;So;0;ON;<compat> 5E7A;;;;N;;;;;
+2F34;KANGXI RADICAL DOTTED CLIFF;So;0;ON;<compat> 5E7F;;;;N;;;;;
+2F35;KANGXI RADICAL LONG STRIDE;So;0;ON;<compat> 5EF4;;;;N;;;;;
+2F36;KANGXI RADICAL TWO HANDS;So;0;ON;<compat> 5EFE;;;;N;;;;;
+2F37;KANGXI RADICAL SHOOT;So;0;ON;<compat> 5F0B;;;;N;;;;;
+2F38;KANGXI RADICAL BOW;So;0;ON;<compat> 5F13;;;;N;;;;;
+2F39;KANGXI RADICAL SNOUT;So;0;ON;<compat> 5F50;;;;N;;;;;
+2F3A;KANGXI RADICAL BRISTLE;So;0;ON;<compat> 5F61;;;;N;;;;;
+2F3B;KANGXI RADICAL STEP;So;0;ON;<compat> 5F73;;;;N;;;;;
+2F3C;KANGXI RADICAL HEART;So;0;ON;<compat> 5FC3;;;;N;;;;;
+2F3D;KANGXI RADICAL HALBERD;So;0;ON;<compat> 6208;;;;N;;;;;
+2F3E;KANGXI RADICAL DOOR;So;0;ON;<compat> 6236;;;;N;;;;;
+2F3F;KANGXI RADICAL HAND;So;0;ON;<compat> 624B;;;;N;;;;;
+2F40;KANGXI RADICAL BRANCH;So;0;ON;<compat> 652F;;;;N;;;;;
+2F41;KANGXI RADICAL RAP;So;0;ON;<compat> 6534;;;;N;;;;;
+2F42;KANGXI RADICAL SCRIPT;So;0;ON;<compat> 6587;;;;N;;;;;
+2F43;KANGXI RADICAL DIPPER;So;0;ON;<compat> 6597;;;;N;;;;;
+2F44;KANGXI RADICAL AXE;So;0;ON;<compat> 65A4;;;;N;;;;;
+2F45;KANGXI RADICAL SQUARE;So;0;ON;<compat> 65B9;;;;N;;;;;
+2F46;KANGXI RADICAL NOT;So;0;ON;<compat> 65E0;;;;N;;;;;
+2F47;KANGXI RADICAL SUN;So;0;ON;<compat> 65E5;;;;N;;;;;
+2F48;KANGXI RADICAL SAY;So;0;ON;<compat> 66F0;;;;N;;;;;
+2F49;KANGXI RADICAL MOON;So;0;ON;<compat> 6708;;;;N;;;;;
+2F4A;KANGXI RADICAL TREE;So;0;ON;<compat> 6728;;;;N;;;;;
+2F4B;KANGXI RADICAL LACK;So;0;ON;<compat> 6B20;;;;N;;;;;
+2F4C;KANGXI RADICAL STOP;So;0;ON;<compat> 6B62;;;;N;;;;;
+2F4D;KANGXI RADICAL DEATH;So;0;ON;<compat> 6B79;;;;N;;;;;
+2F4E;KANGXI RADICAL WEAPON;So;0;ON;<compat> 6BB3;;;;N;;;;;
+2F4F;KANGXI RADICAL DO NOT;So;0;ON;<compat> 6BCB;;;;N;;;;;
+2F50;KANGXI RADICAL COMPARE;So;0;ON;<compat> 6BD4;;;;N;;;;;
+2F51;KANGXI RADICAL FUR;So;0;ON;<compat> 6BDB;;;;N;;;;;
+2F52;KANGXI RADICAL CLAN;So;0;ON;<compat> 6C0F;;;;N;;;;;
+2F53;KANGXI RADICAL STEAM;So;0;ON;<compat> 6C14;;;;N;;;;;
+2F54;KANGXI RADICAL WATER;So;0;ON;<compat> 6C34;;;;N;;;;;
+2F55;KANGXI RADICAL FIRE;So;0;ON;<compat> 706B;;;;N;;;;;
+2F56;KANGXI RADICAL CLAW;So;0;ON;<compat> 722A;;;;N;;;;;
+2F57;KANGXI RADICAL FATHER;So;0;ON;<compat> 7236;;;;N;;;;;
+2F58;KANGXI RADICAL DOUBLE X;So;0;ON;<compat> 723B;;;;N;;;;;
+2F59;KANGXI RADICAL HALF TREE TRUNK;So;0;ON;<compat> 723F;;;;N;;;;;
+2F5A;KANGXI RADICAL SLICE;So;0;ON;<compat> 7247;;;;N;;;;;
+2F5B;KANGXI RADICAL FANG;So;0;ON;<compat> 7259;;;;N;;;;;
+2F5C;KANGXI RADICAL COW;So;0;ON;<compat> 725B;;;;N;;;;;
+2F5D;KANGXI RADICAL DOG;So;0;ON;<compat> 72AC;;;;N;;;;;
+2F5E;KANGXI RADICAL PROFOUND;So;0;ON;<compat> 7384;;;;N;;;;;
+2F5F;KANGXI RADICAL JADE;So;0;ON;<compat> 7389;;;;N;;;;;
+2F60;KANGXI RADICAL MELON;So;0;ON;<compat> 74DC;;;;N;;;;;
+2F61;KANGXI RADICAL TILE;So;0;ON;<compat> 74E6;;;;N;;;;;
+2F62;KANGXI RADICAL SWEET;So;0;ON;<compat> 7518;;;;N;;;;;
+2F63;KANGXI RADICAL LIFE;So;0;ON;<compat> 751F;;;;N;;;;;
+2F64;KANGXI RADICAL USE;So;0;ON;<compat> 7528;;;;N;;;;;
+2F65;KANGXI RADICAL FIELD;So;0;ON;<compat> 7530;;;;N;;;;;
+2F66;KANGXI RADICAL BOLT OF CLOTH;So;0;ON;<compat> 758B;;;;N;;;;;
+2F67;KANGXI RADICAL SICKNESS;So;0;ON;<compat> 7592;;;;N;;;;;
+2F68;KANGXI RADICAL DOTTED TENT;So;0;ON;<compat> 7676;;;;N;;;;;
+2F69;KANGXI RADICAL WHITE;So;0;ON;<compat> 767D;;;;N;;;;;
+2F6A;KANGXI RADICAL SKIN;So;0;ON;<compat> 76AE;;;;N;;;;;
+2F6B;KANGXI RADICAL DISH;So;0;ON;<compat> 76BF;;;;N;;;;;
+2F6C;KANGXI RADICAL EYE;So;0;ON;<compat> 76EE;;;;N;;;;;
+2F6D;KANGXI RADICAL SPEAR;So;0;ON;<compat> 77DB;;;;N;;;;;
+2F6E;KANGXI RADICAL ARROW;So;0;ON;<compat> 77E2;;;;N;;;;;
+2F6F;KANGXI RADICAL STONE;So;0;ON;<compat> 77F3;;;;N;;;;;
+2F70;KANGXI RADICAL SPIRIT;So;0;ON;<compat> 793A;;;;N;;;;;
+2F71;KANGXI RADICAL TRACK;So;0;ON;<compat> 79B8;;;;N;;;;;
+2F72;KANGXI RADICAL GRAIN;So;0;ON;<compat> 79BE;;;;N;;;;;
+2F73;KANGXI RADICAL CAVE;So;0;ON;<compat> 7A74;;;;N;;;;;
+2F74;KANGXI RADICAL STAND;So;0;ON;<compat> 7ACB;;;;N;;;;;
+2F75;KANGXI RADICAL BAMBOO;So;0;ON;<compat> 7AF9;;;;N;;;;;
+2F76;KANGXI RADICAL RICE;So;0;ON;<compat> 7C73;;;;N;;;;;
+2F77;KANGXI RADICAL SILK;So;0;ON;<compat> 7CF8;;;;N;;;;;
+2F78;KANGXI RADICAL JAR;So;0;ON;<compat> 7F36;;;;N;;;;;
+2F79;KANGXI RADICAL NET;So;0;ON;<compat> 7F51;;;;N;;;;;
+2F7A;KANGXI RADICAL SHEEP;So;0;ON;<compat> 7F8A;;;;N;;;;;
+2F7B;KANGXI RADICAL FEATHER;So;0;ON;<compat> 7FBD;;;;N;;;;;
+2F7C;KANGXI RADICAL OLD;So;0;ON;<compat> 8001;;;;N;;;;;
+2F7D;KANGXI RADICAL AND;So;0;ON;<compat> 800C;;;;N;;;;;
+2F7E;KANGXI RADICAL PLOW;So;0;ON;<compat> 8012;;;;N;;;;;
+2F7F;KANGXI RADICAL EAR;So;0;ON;<compat> 8033;;;;N;;;;;
+2F80;KANGXI RADICAL BRUSH;So;0;ON;<compat> 807F;;;;N;;;;;
+2F81;KANGXI RADICAL MEAT;So;0;ON;<compat> 8089;;;;N;;;;;
+2F82;KANGXI RADICAL MINISTER;So;0;ON;<compat> 81E3;;;;N;;;;;
+2F83;KANGXI RADICAL SELF;So;0;ON;<compat> 81EA;;;;N;;;;;
+2F84;KANGXI RADICAL ARRIVE;So;0;ON;<compat> 81F3;;;;N;;;;;
+2F85;KANGXI RADICAL MORTAR;So;0;ON;<compat> 81FC;;;;N;;;;;
+2F86;KANGXI RADICAL TONGUE;So;0;ON;<compat> 820C;;;;N;;;;;
+2F87;KANGXI RADICAL OPPOSE;So;0;ON;<compat> 821B;;;;N;;;;;
+2F88;KANGXI RADICAL BOAT;So;0;ON;<compat> 821F;;;;N;;;;;
+2F89;KANGXI RADICAL STOPPING;So;0;ON;<compat> 826E;;;;N;;;;;
+2F8A;KANGXI RADICAL COLOR;So;0;ON;<compat> 8272;;;;N;;;;;
+2F8B;KANGXI RADICAL GRASS;So;0;ON;<compat> 8278;;;;N;;;;;
+2F8C;KANGXI RADICAL TIGER;So;0;ON;<compat> 864D;;;;N;;;;;
+2F8D;KANGXI RADICAL INSECT;So;0;ON;<compat> 866B;;;;N;;;;;
+2F8E;KANGXI RADICAL BLOOD;So;0;ON;<compat> 8840;;;;N;;;;;
+2F8F;KANGXI RADICAL WALK ENCLOSURE;So;0;ON;<compat> 884C;;;;N;;;;;
+2F90;KANGXI RADICAL CLOTHES;So;0;ON;<compat> 8863;;;;N;;;;;
+2F91;KANGXI RADICAL WEST;So;0;ON;<compat> 897E;;;;N;;;;;
+2F92;KANGXI RADICAL SEE;So;0;ON;<compat> 898B;;;;N;;;;;
+2F93;KANGXI RADICAL HORN;So;0;ON;<compat> 89D2;;;;N;;;;;
+2F94;KANGXI RADICAL SPEECH;So;0;ON;<compat> 8A00;;;;N;;;;;
+2F95;KANGXI RADICAL VALLEY;So;0;ON;<compat> 8C37;;;;N;;;;;
+2F96;KANGXI RADICAL BEAN;So;0;ON;<compat> 8C46;;;;N;;;;;
+2F97;KANGXI RADICAL PIG;So;0;ON;<compat> 8C55;;;;N;;;;;
+2F98;KANGXI RADICAL BADGER;So;0;ON;<compat> 8C78;;;;N;;;;;
+2F99;KANGXI RADICAL SHELL;So;0;ON;<compat> 8C9D;;;;N;;;;;
+2F9A;KANGXI RADICAL RED;So;0;ON;<compat> 8D64;;;;N;;;;;
+2F9B;KANGXI RADICAL RUN;So;0;ON;<compat> 8D70;;;;N;;;;;
+2F9C;KANGXI RADICAL FOOT;So;0;ON;<compat> 8DB3;;;;N;;;;;
+2F9D;KANGXI RADICAL BODY;So;0;ON;<compat> 8EAB;;;;N;;;;;
+2F9E;KANGXI RADICAL CART;So;0;ON;<compat> 8ECA;;;;N;;;;;
+2F9F;KANGXI RADICAL BITTER;So;0;ON;<compat> 8F9B;;;;N;;;;;
+2FA0;KANGXI RADICAL MORNING;So;0;ON;<compat> 8FB0;;;;N;;;;;
+2FA1;KANGXI RADICAL WALK;So;0;ON;<compat> 8FB5;;;;N;;;;;
+2FA2;KANGXI RADICAL CITY;So;0;ON;<compat> 9091;;;;N;;;;;
+2FA3;KANGXI RADICAL WINE;So;0;ON;<compat> 9149;;;;N;;;;;
+2FA4;KANGXI RADICAL DISTINGUISH;So;0;ON;<compat> 91C6;;;;N;;;;;
+2FA5;KANGXI RADICAL VILLAGE;So;0;ON;<compat> 91CC;;;;N;;;;;
+2FA6;KANGXI RADICAL GOLD;So;0;ON;<compat> 91D1;;;;N;;;;;
+2FA7;KANGXI RADICAL LONG;So;0;ON;<compat> 9577;;;;N;;;;;
+2FA8;KANGXI RADICAL GATE;So;0;ON;<compat> 9580;;;;N;;;;;
+2FA9;KANGXI RADICAL MOUND;So;0;ON;<compat> 961C;;;;N;;;;;
+2FAA;KANGXI RADICAL SLAVE;So;0;ON;<compat> 96B6;;;;N;;;;;
+2FAB;KANGXI RADICAL SHORT TAILED BIRD;So;0;ON;<compat> 96B9;;;;N;;;;;
+2FAC;KANGXI RADICAL RAIN;So;0;ON;<compat> 96E8;;;;N;;;;;
+2FAD;KANGXI RADICAL BLUE;So;0;ON;<compat> 9751;;;;N;;;;;
+2FAE;KANGXI RADICAL WRONG;So;0;ON;<compat> 975E;;;;N;;;;;
+2FAF;KANGXI RADICAL FACE;So;0;ON;<compat> 9762;;;;N;;;;;
+2FB0;KANGXI RADICAL LEATHER;So;0;ON;<compat> 9769;;;;N;;;;;
+2FB1;KANGXI RADICAL TANNED LEATHER;So;0;ON;<compat> 97CB;;;;N;;;;;
+2FB2;KANGXI RADICAL LEEK;So;0;ON;<compat> 97ED;;;;N;;;;;
+2FB3;KANGXI RADICAL SOUND;So;0;ON;<compat> 97F3;;;;N;;;;;
+2FB4;KANGXI RADICAL LEAF;So;0;ON;<compat> 9801;;;;N;;;;;
+2FB5;KANGXI RADICAL WIND;So;0;ON;<compat> 98A8;;;;N;;;;;
+2FB6;KANGXI RADICAL FLY;So;0;ON;<compat> 98DB;;;;N;;;;;
+2FB7;KANGXI RADICAL EAT;So;0;ON;<compat> 98DF;;;;N;;;;;
+2FB8;KANGXI RADICAL HEAD;So;0;ON;<compat> 9996;;;;N;;;;;
+2FB9;KANGXI RADICAL FRAGRANT;So;0;ON;<compat> 9999;;;;N;;;;;
+2FBA;KANGXI RADICAL HORSE;So;0;ON;<compat> 99AC;;;;N;;;;;
+2FBB;KANGXI RADICAL BONE;So;0;ON;<compat> 9AA8;;;;N;;;;;
+2FBC;KANGXI RADICAL TALL;So;0;ON;<compat> 9AD8;;;;N;;;;;
+2FBD;KANGXI RADICAL HAIR;So;0;ON;<compat> 9ADF;;;;N;;;;;
+2FBE;KANGXI RADICAL FIGHT;So;0;ON;<compat> 9B25;;;;N;;;;;
+2FBF;KANGXI RADICAL SACRIFICIAL WINE;So;0;ON;<compat> 9B2F;;;;N;;;;;
+2FC0;KANGXI RADICAL CAULDRON;So;0;ON;<compat> 9B32;;;;N;;;;;
+2FC1;KANGXI RADICAL GHOST;So;0;ON;<compat> 9B3C;;;;N;;;;;
+2FC2;KANGXI RADICAL FISH;So;0;ON;<compat> 9B5A;;;;N;;;;;
+2FC3;KANGXI RADICAL BIRD;So;0;ON;<compat> 9CE5;;;;N;;;;;
+2FC4;KANGXI RADICAL SALT;So;0;ON;<compat> 9E75;;;;N;;;;;
+2FC5;KANGXI RADICAL DEER;So;0;ON;<compat> 9E7F;;;;N;;;;;
+2FC6;KANGXI RADICAL WHEAT;So;0;ON;<compat> 9EA5;;;;N;;;;;
+2FC7;KANGXI RADICAL HEMP;So;0;ON;<compat> 9EBB;;;;N;;;;;
+2FC8;KANGXI RADICAL YELLOW;So;0;ON;<compat> 9EC3;;;;N;;;;;
+2FC9;KANGXI RADICAL MILLET;So;0;ON;<compat> 9ECD;;;;N;;;;;
+2FCA;KANGXI RADICAL BLACK;So;0;ON;<compat> 9ED1;;;;N;;;;;
+2FCB;KANGXI RADICAL EMBROIDERY;So;0;ON;<compat> 9EF9;;;;N;;;;;
+2FCC;KANGXI RADICAL FROG;So;0;ON;<compat> 9EFD;;;;N;;;;;
+2FCD;KANGXI RADICAL TRIPOD;So;0;ON;<compat> 9F0E;;;;N;;;;;
+2FCE;KANGXI RADICAL DRUM;So;0;ON;<compat> 9F13;;;;N;;;;;
+2FCF;KANGXI RADICAL RAT;So;0;ON;<compat> 9F20;;;;N;;;;;
+2FD0;KANGXI RADICAL NOSE;So;0;ON;<compat> 9F3B;;;;N;;;;;
+2FD1;KANGXI RADICAL EVEN;So;0;ON;<compat> 9F4A;;;;N;;;;;
+2FD2;KANGXI RADICAL TOOTH;So;0;ON;<compat> 9F52;;;;N;;;;;
+2FD3;KANGXI RADICAL DRAGON;So;0;ON;<compat> 9F8D;;;;N;;;;;
+2FD4;KANGXI RADICAL TURTLE;So;0;ON;<compat> 9F9C;;;;N;;;;;
+2FD5;KANGXI RADICAL FLUTE;So;0;ON;<compat> 9FA0;;;;N;;;;;
+2FF0;IDEOGRAPHIC DESCRIPTION CHARACTER LEFT TO RIGHT;So;0;ON;;;;;N;;;;;
+2FF1;IDEOGRAPHIC DESCRIPTION CHARACTER ABOVE TO BELOW;So;0;ON;;;;;N;;;;;
+2FF2;IDEOGRAPHIC DESCRIPTION CHARACTER LEFT TO MIDDLE AND RIGHT;So;0;ON;;;;;N;;;;;
+2FF3;IDEOGRAPHIC DESCRIPTION CHARACTER ABOVE TO MIDDLE AND BELOW;So;0;ON;;;;;N;;;;;
+2FF4;IDEOGRAPHIC DESCRIPTION CHARACTER FULL SURROUND;So;0;ON;;;;;N;;;;;
+2FF5;IDEOGRAPHIC DESCRIPTION CHARACTER SURROUND FROM ABOVE;So;0;ON;;;;;N;;;;;
+2FF6;IDEOGRAPHIC DESCRIPTION CHARACTER SURROUND FROM BELOW;So;0;ON;;;;;N;;;;;
+2FF7;IDEOGRAPHIC DESCRIPTION CHARACTER SURROUND FROM LEFT;So;0;ON;;;;;N;;;;;
+2FF8;IDEOGRAPHIC DESCRIPTION CHARACTER SURROUND FROM UPPER LEFT;So;0;ON;;;;;N;;;;;
+2FF9;IDEOGRAPHIC DESCRIPTION CHARACTER SURROUND FROM UPPER RIGHT;So;0;ON;;;;;N;;;;;
+2FFA;IDEOGRAPHIC DESCRIPTION CHARACTER SURROUND FROM LOWER LEFT;So;0;ON;;;;;N;;;;;
+2FFB;IDEOGRAPHIC DESCRIPTION CHARACTER OVERLAID;So;0;ON;;;;;N;;;;;
+3000;IDEOGRAPHIC SPACE;Zs;0;WS;<wide> 0020;;;;N;;;;;
+3001;IDEOGRAPHIC COMMA;Po;0;ON;;;;;N;;;;;
+3002;IDEOGRAPHIC FULL STOP;Po;0;ON;;;;;N;IDEOGRAPHIC PERIOD;;;;
+3003;DITTO MARK;Po;0;ON;;;;;N;;;;;
+3004;JAPANESE INDUSTRIAL STANDARD SYMBOL;So;0;ON;;;;;N;;;;;
+3005;IDEOGRAPHIC ITERATION MARK;Lm;0;L;;;;;N;;;;;
+3006;IDEOGRAPHIC CLOSING MARK;Lo;0;L;;;;;N;;;;;
+3007;IDEOGRAPHIC NUMBER ZERO;Nl;0;L;;;;0;N;;;;;
+3008;LEFT ANGLE BRACKET;Ps;0;ON;;;;;Y;OPENING ANGLE BRACKET;;;;
+3009;RIGHT ANGLE BRACKET;Pe;0;ON;;;;;Y;CLOSING ANGLE BRACKET;;;;
+300A;LEFT DOUBLE ANGLE BRACKET;Ps;0;ON;;;;;Y;OPENING DOUBLE ANGLE BRACKET;;;;
+300B;RIGHT DOUBLE ANGLE BRACKET;Pe;0;ON;;;;;Y;CLOSING DOUBLE ANGLE BRACKET;;;;
+300C;LEFT CORNER BRACKET;Ps;0;ON;;;;;Y;OPENING CORNER BRACKET;;;;
+300D;RIGHT CORNER BRACKET;Pe;0;ON;;;;;Y;CLOSING CORNER BRACKET;;;;
+300E;LEFT WHITE CORNER BRACKET;Ps;0;ON;;;;;Y;OPENING WHITE CORNER BRACKET;;;;
+300F;RIGHT WHITE CORNER BRACKET;Pe;0;ON;;;;;Y;CLOSING WHITE CORNER BRACKET;;;;
+3010;LEFT BLACK LENTICULAR BRACKET;Ps;0;ON;;;;;Y;OPENING BLACK LENTICULAR BRACKET;;;;
+3011;RIGHT BLACK LENTICULAR BRACKET;Pe;0;ON;;;;;Y;CLOSING BLACK LENTICULAR BRACKET;;;;
+3012;POSTAL MARK;So;0;ON;;;;;N;;;;;
+3013;GETA MARK;So;0;ON;;;;;N;;;;;
+3014;LEFT TORTOISE SHELL BRACKET;Ps;0;ON;;;;;Y;OPENING TORTOISE SHELL BRACKET;;;;
+3015;RIGHT TORTOISE SHELL BRACKET;Pe;0;ON;;;;;Y;CLOSING TORTOISE SHELL BRACKET;;;;
+3016;LEFT WHITE LENTICULAR BRACKET;Ps;0;ON;;;;;Y;OPENING WHITE LENTICULAR BRACKET;;;;
+3017;RIGHT WHITE LENTICULAR BRACKET;Pe;0;ON;;;;;Y;CLOSING WHITE LENTICULAR BRACKET;;;;
+3018;LEFT WHITE TORTOISE SHELL BRACKET;Ps;0;ON;;;;;Y;OPENING WHITE TORTOISE SHELL BRACKET;;;;
+3019;RIGHT WHITE TORTOISE SHELL BRACKET;Pe;0;ON;;;;;Y;CLOSING WHITE TORTOISE SHELL BRACKET;;;;
+301A;LEFT WHITE SQUARE BRACKET;Ps;0;ON;;;;;Y;OPENING WHITE SQUARE BRACKET;;;;
+301B;RIGHT WHITE SQUARE BRACKET;Pe;0;ON;;;;;Y;CLOSING WHITE SQUARE BRACKET;;;;
+301C;WAVE DASH;Pd;0;ON;;;;;N;;;;;
+301D;REVERSED DOUBLE PRIME QUOTATION MARK;Ps;0;ON;;;;;N;;;;;
+301E;DOUBLE PRIME QUOTATION MARK;Pe;0;ON;;;;;N;;;;;
+301F;LOW DOUBLE PRIME QUOTATION MARK;Pe;0;ON;;;;;N;;;;;
+3020;POSTAL MARK FACE;So;0;ON;;;;;N;;;;;
+3021;HANGZHOU NUMERAL ONE;Nl;0;L;;;;1;N;;;;;
+3022;HANGZHOU NUMERAL TWO;Nl;0;L;;;;2;N;;;;;
+3023;HANGZHOU NUMERAL THREE;Nl;0;L;;;;3;N;;;;;
+3024;HANGZHOU NUMERAL FOUR;Nl;0;L;;;;4;N;;;;;
+3025;HANGZHOU NUMERAL FIVE;Nl;0;L;;;;5;N;;;;;
+3026;HANGZHOU NUMERAL SIX;Nl;0;L;;;;6;N;;;;;
+3027;HANGZHOU NUMERAL SEVEN;Nl;0;L;;;;7;N;;;;;
+3028;HANGZHOU NUMERAL EIGHT;Nl;0;L;;;;8;N;;;;;
+3029;HANGZHOU NUMERAL NINE;Nl;0;L;;;;9;N;;;;;
+302A;IDEOGRAPHIC LEVEL TONE MARK;Mn;218;NSM;;;;;N;;;;;
+302B;IDEOGRAPHIC RISING TONE MARK;Mn;228;NSM;;;;;N;;;;;
+302C;IDEOGRAPHIC DEPARTING TONE MARK;Mn;232;NSM;;;;;N;;;;;
+302D;IDEOGRAPHIC ENTERING TONE MARK;Mn;222;NSM;;;;;N;;;;;
+302E;HANGUL SINGLE DOT TONE MARK;Mn;224;NSM;;;;;N;;;;;
+302F;HANGUL DOUBLE DOT TONE MARK;Mn;224;NSM;;;;;N;;;;;
+3030;WAVY DASH;Pd;0;ON;;;;;N;;;;;
+3031;VERTICAL KANA REPEAT MARK;Lm;0;L;;;;;N;;;;;
+3032;VERTICAL KANA REPEAT WITH VOICED SOUND MARK;Lm;0;L;;;;;N;;;;;
+3033;VERTICAL KANA REPEAT MARK UPPER HALF;Lm;0;L;;;;;N;;;;;
+3034;VERTICAL KANA REPEAT WITH VOICED SOUND MARK UPPER HALF;Lm;0;L;;;;;N;;;;;
+3035;VERTICAL KANA REPEAT MARK LOWER HALF;Lm;0;L;;;;;N;;;;;
+3036;CIRCLED POSTAL MARK;So;0;ON;<compat> 3012;;;;N;;;;;
+3037;IDEOGRAPHIC TELEGRAPH LINE FEED SEPARATOR SYMBOL;So;0;ON;;;;;N;;;;;
+3038;HANGZHOU NUMERAL TEN;Nl;0;L;<compat> 5341;;;10;N;;;;;
+3039;HANGZHOU NUMERAL TWENTY;Nl;0;L;<compat> 5344;;;20;N;;;;;
+303A;HANGZHOU NUMERAL THIRTY;Nl;0;L;<compat> 5345;;;30;N;;;;;
+303B;VERTICAL IDEOGRAPHIC ITERATION MARK;Lm;0;L;;;;;N;;;;;
+303C;MASU MARK;Lo;0;L;;;;;N;;;;;
+303D;PART ALTERNATION MARK;Po;0;ON;;;;;N;;;;;
+303E;IDEOGRAPHIC VARIATION INDICATOR;So;0;ON;;;;;N;;;;;
+303F;IDEOGRAPHIC HALF FILL SPACE;So;0;ON;;;;;N;;;;;
+3041;HIRAGANA LETTER SMALL A;Lo;0;L;;;;;N;;;;;
+3042;HIRAGANA LETTER A;Lo;0;L;;;;;N;;;;;
+3043;HIRAGANA LETTER SMALL I;Lo;0;L;;;;;N;;;;;
+3044;HIRAGANA LETTER I;Lo;0;L;;;;;N;;;;;
+3045;HIRAGANA LETTER SMALL U;Lo;0;L;;;;;N;;;;;
+3046;HIRAGANA LETTER U;Lo;0;L;;;;;N;;;;;
+3047;HIRAGANA LETTER SMALL E;Lo;0;L;;;;;N;;;;;
+3048;HIRAGANA LETTER E;Lo;0;L;;;;;N;;;;;
+3049;HIRAGANA LETTER SMALL O;Lo;0;L;;;;;N;;;;;
+304A;HIRAGANA LETTER O;Lo;0;L;;;;;N;;;;;
+304B;HIRAGANA LETTER KA;Lo;0;L;;;;;N;;;;;
+304C;HIRAGANA LETTER GA;Lo;0;L;304B 3099;;;;N;;;;;
+304D;HIRAGANA LETTER KI;Lo;0;L;;;;;N;;;;;
+304E;HIRAGANA LETTER GI;Lo;0;L;304D 3099;;;;N;;;;;
+304F;HIRAGANA LETTER KU;Lo;0;L;;;;;N;;;;;
+3050;HIRAGANA LETTER GU;Lo;0;L;304F 3099;;;;N;;;;;
+3051;HIRAGANA LETTER KE;Lo;0;L;;;;;N;;;;;
+3052;HIRAGANA LETTER GE;Lo;0;L;3051 3099;;;;N;;;;;
+3053;HIRAGANA LETTER KO;Lo;0;L;;;;;N;;;;;
+3054;HIRAGANA LETTER GO;Lo;0;L;3053 3099;;;;N;;;;;
+3055;HIRAGANA LETTER SA;Lo;0;L;;;;;N;;;;;
+3056;HIRAGANA LETTER ZA;Lo;0;L;3055 3099;;;;N;;;;;
+3057;HIRAGANA LETTER SI;Lo;0;L;;;;;N;;;;;
+3058;HIRAGANA LETTER ZI;Lo;0;L;3057 3099;;;;N;;;;;
+3059;HIRAGANA LETTER SU;Lo;0;L;;;;;N;;;;;
+305A;HIRAGANA LETTER ZU;Lo;0;L;3059 3099;;;;N;;;;;
+305B;HIRAGANA LETTER SE;Lo;0;L;;;;;N;;;;;
+305C;HIRAGANA LETTER ZE;Lo;0;L;305B 3099;;;;N;;;;;
+305D;HIRAGANA LETTER SO;Lo;0;L;;;;;N;;;;;
+305E;HIRAGANA LETTER ZO;Lo;0;L;305D 3099;;;;N;;;;;
+305F;HIRAGANA LETTER TA;Lo;0;L;;;;;N;;;;;
+3060;HIRAGANA LETTER DA;Lo;0;L;305F 3099;;;;N;;;;;
+3061;HIRAGANA LETTER TI;Lo;0;L;;;;;N;;;;;
+3062;HIRAGANA LETTER DI;Lo;0;L;3061 3099;;;;N;;;;;
+3063;HIRAGANA LETTER SMALL TU;Lo;0;L;;;;;N;;;;;
+3064;HIRAGANA LETTER TU;Lo;0;L;;;;;N;;;;;
+3065;HIRAGANA LETTER DU;Lo;0;L;3064 3099;;;;N;;;;;
+3066;HIRAGANA LETTER TE;Lo;0;L;;;;;N;;;;;
+3067;HIRAGANA LETTER DE;Lo;0;L;3066 3099;;;;N;;;;;
+3068;HIRAGANA LETTER TO;Lo;0;L;;;;;N;;;;;
+3069;HIRAGANA LETTER DO;Lo;0;L;3068 3099;;;;N;;;;;
+306A;HIRAGANA LETTER NA;Lo;0;L;;;;;N;;;;;
+306B;HIRAGANA LETTER NI;Lo;0;L;;;;;N;;;;;
+306C;HIRAGANA LETTER NU;Lo;0;L;;;;;N;;;;;
+306D;HIRAGANA LETTER NE;Lo;0;L;;;;;N;;;;;
+306E;HIRAGANA LETTER NO;Lo;0;L;;;;;N;;;;;
+306F;HIRAGANA LETTER HA;Lo;0;L;;;;;N;;;;;
+3070;HIRAGANA LETTER BA;Lo;0;L;306F 3099;;;;N;;;;;
+3071;HIRAGANA LETTER PA;Lo;0;L;306F 309A;;;;N;;;;;
+3072;HIRAGANA LETTER HI;Lo;0;L;;;;;N;;;;;
+3073;HIRAGANA LETTER BI;Lo;0;L;3072 3099;;;;N;;;;;
+3074;HIRAGANA LETTER PI;Lo;0;L;3072 309A;;;;N;;;;;
+3075;HIRAGANA LETTER HU;Lo;0;L;;;;;N;;;;;
+3076;HIRAGANA LETTER BU;Lo;0;L;3075 3099;;;;N;;;;;
+3077;HIRAGANA LETTER PU;Lo;0;L;3075 309A;;;;N;;;;;
+3078;HIRAGANA LETTER HE;Lo;0;L;;;;;N;;;;;
+3079;HIRAGANA LETTER BE;Lo;0;L;3078 3099;;;;N;;;;;
+307A;HIRAGANA LETTER PE;Lo;0;L;3078 309A;;;;N;;;;;
+307B;HIRAGANA LETTER HO;Lo;0;L;;;;;N;;;;;
+307C;HIRAGANA LETTER BO;Lo;0;L;307B 3099;;;;N;;;;;
+307D;HIRAGANA LETTER PO;Lo;0;L;307B 309A;;;;N;;;;;
+307E;HIRAGANA LETTER MA;Lo;0;L;;;;;N;;;;;
+307F;HIRAGANA LETTER MI;Lo;0;L;;;;;N;;;;;
+3080;HIRAGANA LETTER MU;Lo;0;L;;;;;N;;;;;
+3081;HIRAGANA LETTER ME;Lo;0;L;;;;;N;;;;;
+3082;HIRAGANA LETTER MO;Lo;0;L;;;;;N;;;;;
+3083;HIRAGANA LETTER SMALL YA;Lo;0;L;;;;;N;;;;;
+3084;HIRAGANA LETTER YA;Lo;0;L;;;;;N;;;;;
+3085;HIRAGANA LETTER SMALL YU;Lo;0;L;;;;;N;;;;;
+3086;HIRAGANA LETTER YU;Lo;0;L;;;;;N;;;;;
+3087;HIRAGANA LETTER SMALL YO;Lo;0;L;;;;;N;;;;;
+3088;HIRAGANA LETTER YO;Lo;0;L;;;;;N;;;;;
+3089;HIRAGANA LETTER RA;Lo;0;L;;;;;N;;;;;
+308A;HIRAGANA LETTER RI;Lo;0;L;;;;;N;;;;;
+308B;HIRAGANA LETTER RU;Lo;0;L;;;;;N;;;;;
+308C;HIRAGANA LETTER RE;Lo;0;L;;;;;N;;;;;
+308D;HIRAGANA LETTER RO;Lo;0;L;;;;;N;;;;;
+308E;HIRAGANA LETTER SMALL WA;Lo;0;L;;;;;N;;;;;
+308F;HIRAGANA LETTER WA;Lo;0;L;;;;;N;;;;;
+3090;HIRAGANA LETTER WI;Lo;0;L;;;;;N;;;;;
+3091;HIRAGANA LETTER WE;Lo;0;L;;;;;N;;;;;
+3092;HIRAGANA LETTER WO;Lo;0;L;;;;;N;;;;;
+3093;HIRAGANA LETTER N;Lo;0;L;;;;;N;;;;;
+3094;HIRAGANA LETTER VU;Lo;0;L;3046 3099;;;;N;;;;;
+3095;HIRAGANA LETTER SMALL KA;Lo;0;L;;;;;N;;;;;
+3096;HIRAGANA LETTER SMALL KE;Lo;0;L;;;;;N;;;;;
+3099;COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK;Mn;8;NSM;;;;;N;NON-SPACING KATAKANA-HIRAGANA VOICED SOUND MARK;;;;
+309A;COMBINING KATAKANA-HIRAGANA SEMI-VOICED SOUND MARK;Mn;8;NSM;;;;;N;NON-SPACING KATAKANA-HIRAGANA SEMI-VOICED SOUND MARK;;;;
+309B;KATAKANA-HIRAGANA VOICED SOUND MARK;Sk;0;ON;<compat> 0020 3099;;;;N;;;;;
+309C;KATAKANA-HIRAGANA SEMI-VOICED SOUND MARK;Sk;0;ON;<compat> 0020 309A;;;;N;;;;;
+309D;HIRAGANA ITERATION MARK;Lm;0;L;;;;;N;;;;;
+309E;HIRAGANA VOICED ITERATION MARK;Lm;0;L;309D 3099;;;;N;;;;;
+309F;HIRAGANA DIGRAPH YORI;Lo;0;L;<vertical> 3088 308A;;;;N;;;;;
+30A0;KATAKANA-HIRAGANA DOUBLE HYPHEN;Pd;0;ON;;;;;N;;;;;
+30A1;KATAKANA LETTER SMALL A;Lo;0;L;;;;;N;;;;;
+30A2;KATAKANA LETTER A;Lo;0;L;;;;;N;;;;;
+30A3;KATAKANA LETTER SMALL I;Lo;0;L;;;;;N;;;;;
+30A4;KATAKANA LETTER I;Lo;0;L;;;;;N;;;;;
+30A5;KATAKANA LETTER SMALL U;Lo;0;L;;;;;N;;;;;
+30A6;KATAKANA LETTER U;Lo;0;L;;;;;N;;;;;
+30A7;KATAKANA LETTER SMALL E;Lo;0;L;;;;;N;;;;;
+30A8;KATAKANA LETTER E;Lo;0;L;;;;;N;;;;;
+30A9;KATAKANA LETTER SMALL O;Lo;0;L;;;;;N;;;;;
+30AA;KATAKANA LETTER O;Lo;0;L;;;;;N;;;;;
+30AB;KATAKANA LETTER KA;Lo;0;L;;;;;N;;;;;
+30AC;KATAKANA LETTER GA;Lo;0;L;30AB 3099;;;;N;;;;;
+30AD;KATAKANA LETTER KI;Lo;0;L;;;;;N;;;;;
+30AE;KATAKANA LETTER GI;Lo;0;L;30AD 3099;;;;N;;;;;
+30AF;KATAKANA LETTER KU;Lo;0;L;;;;;N;;;;;
+30B0;KATAKANA LETTER GU;Lo;0;L;30AF 3099;;;;N;;;;;
+30B1;KATAKANA LETTER KE;Lo;0;L;;;;;N;;;;;
+30B2;KATAKANA LETTER GE;Lo;0;L;30B1 3099;;;;N;;;;;
+30B3;KATAKANA LETTER KO;Lo;0;L;;;;;N;;;;;
+30B4;KATAKANA LETTER GO;Lo;0;L;30B3 3099;;;;N;;;;;
+30B5;KATAKANA LETTER SA;Lo;0;L;;;;;N;;;;;
+30B6;KATAKANA LETTER ZA;Lo;0;L;30B5 3099;;;;N;;;;;
+30B7;KATAKANA LETTER SI;Lo;0;L;;;;;N;;;;;
+30B8;KATAKANA LETTER ZI;Lo;0;L;30B7 3099;;;;N;;;;;
+30B9;KATAKANA LETTER SU;Lo;0;L;;;;;N;;;;;
+30BA;KATAKANA LETTER ZU;Lo;0;L;30B9 3099;;;;N;;;;;
+30BB;KATAKANA LETTER SE;Lo;0;L;;;;;N;;;;;
+30BC;KATAKANA LETTER ZE;Lo;0;L;30BB 3099;;;;N;;;;;
+30BD;KATAKANA LETTER SO;Lo;0;L;;;;;N;;;;;
+30BE;KATAKANA LETTER ZO;Lo;0;L;30BD 3099;;;;N;;;;;
+30BF;KATAKANA LETTER TA;Lo;0;L;;;;;N;;;;;
+30C0;KATAKANA LETTER DA;Lo;0;L;30BF 3099;;;;N;;;;;
+30C1;KATAKANA LETTER TI;Lo;0;L;;;;;N;;;;;
+30C2;KATAKANA LETTER DI;Lo;0;L;30C1 3099;;;;N;;;;;
+30C3;KATAKANA LETTER SMALL TU;Lo;0;L;;;;;N;;;;;
+30C4;KATAKANA LETTER TU;Lo;0;L;;;;;N;;;;;
+30C5;KATAKANA LETTER DU;Lo;0;L;30C4 3099;;;;N;;;;;
+30C6;KATAKANA LETTER TE;Lo;0;L;;;;;N;;;;;
+30C7;KATAKANA LETTER DE;Lo;0;L;30C6 3099;;;;N;;;;;
+30C8;KATAKANA LETTER TO;Lo;0;L;;;;;N;;;;;
+30C9;KATAKANA LETTER DO;Lo;0;L;30C8 3099;;;;N;;;;;
+30CA;KATAKANA LETTER NA;Lo;0;L;;;;;N;;;;;
+30CB;KATAKANA LETTER NI;Lo;0;L;;;;;N;;;;;
+30CC;KATAKANA LETTER NU;Lo;0;L;;;;;N;;;;;
+30CD;KATAKANA LETTER NE;Lo;0;L;;;;;N;;;;;
+30CE;KATAKANA LETTER NO;Lo;0;L;;;;;N;;;;;
+30CF;KATAKANA LETTER HA;Lo;0;L;;;;;N;;;;;
+30D0;KATAKANA LETTER BA;Lo;0;L;30CF 3099;;;;N;;;;;
+30D1;KATAKANA LETTER PA;Lo;0;L;30CF 309A;;;;N;;;;;
+30D2;KATAKANA LETTER HI;Lo;0;L;;;;;N;;;;;
+30D3;KATAKANA LETTER BI;Lo;0;L;30D2 3099;;;;N;;;;;
+30D4;KATAKANA LETTER PI;Lo;0;L;30D2 309A;;;;N;;;;;
+30D5;KATAKANA LETTER HU;Lo;0;L;;;;;N;;;;;
+30D6;KATAKANA LETTER BU;Lo;0;L;30D5 3099;;;;N;;;;;
+30D7;KATAKANA LETTER PU;Lo;0;L;30D5 309A;;;;N;;;;;
+30D8;KATAKANA LETTER HE;Lo;0;L;;;;;N;;;;;
+30D9;KATAKANA LETTER BE;Lo;0;L;30D8 3099;;;;N;;;;;
+30DA;KATAKANA LETTER PE;Lo;0;L;30D8 309A;;;;N;;;;;
+30DB;KATAKANA LETTER HO;Lo;0;L;;;;;N;;;;;
+30DC;KATAKANA LETTER BO;Lo;0;L;30DB 3099;;;;N;;;;;
+30DD;KATAKANA LETTER PO;Lo;0;L;30DB 309A;;;;N;;;;;
+30DE;KATAKANA LETTER MA;Lo;0;L;;;;;N;;;;;
+30DF;KATAKANA LETTER MI;Lo;0;L;;;;;N;;;;;
+30E0;KATAKANA LETTER MU;Lo;0;L;;;;;N;;;;;
+30E1;KATAKANA LETTER ME;Lo;0;L;;;;;N;;;;;
+30E2;KATAKANA LETTER MO;Lo;0;L;;;;;N;;;;;
+30E3;KATAKANA LETTER SMALL YA;Lo;0;L;;;;;N;;;;;
+30E4;KATAKANA LETTER YA;Lo;0;L;;;;;N;;;;;
+30E5;KATAKANA LETTER SMALL YU;Lo;0;L;;;;;N;;;;;
+30E6;KATAKANA LETTER YU;Lo;0;L;;;;;N;;;;;
+30E7;KATAKANA LETTER SMALL YO;Lo;0;L;;;;;N;;;;;
+30E8;KATAKANA LETTER YO;Lo;0;L;;;;;N;;;;;
+30E9;KATAKANA LETTER RA;Lo;0;L;;;;;N;;;;;
+30EA;KATAKANA LETTER RI;Lo;0;L;;;;;N;;;;;
+30EB;KATAKANA LETTER RU;Lo;0;L;;;;;N;;;;;
+30EC;KATAKANA LETTER RE;Lo;0;L;;;;;N;;;;;
+30ED;KATAKANA LETTER RO;Lo;0;L;;;;;N;;;;;
+30EE;KATAKANA LETTER SMALL WA;Lo;0;L;;;;;N;;;;;
+30EF;KATAKANA LETTER WA;Lo;0;L;;;;;N;;;;;
+30F0;KATAKANA LETTER WI;Lo;0;L;;;;;N;;;;;
+30F1;KATAKANA LETTER WE;Lo;0;L;;;;;N;;;;;
+30F2;KATAKANA LETTER WO;Lo;0;L;;;;;N;;;;;
+30F3;KATAKANA LETTER N;Lo;0;L;;;;;N;;;;;
+30F4;KATAKANA LETTER VU;Lo;0;L;30A6 3099;;;;N;;;;;
+30F5;KATAKANA LETTER SMALL KA;Lo;0;L;;;;;N;;;;;
+30F6;KATAKANA LETTER SMALL KE;Lo;0;L;;;;;N;;;;;
+30F7;KATAKANA LETTER VA;Lo;0;L;30EF 3099;;;;N;;;;;
+30F8;KATAKANA LETTER VI;Lo;0;L;30F0 3099;;;;N;;;;;
+30F9;KATAKANA LETTER VE;Lo;0;L;30F1 3099;;;;N;;;;;
+30FA;KATAKANA LETTER VO;Lo;0;L;30F2 3099;;;;N;;;;;
+30FB;KATAKANA MIDDLE DOT;Po;0;ON;;;;;N;;;;;
+30FC;KATAKANA-HIRAGANA PROLONGED SOUND MARK;Lm;0;L;;;;;N;;;;;
+30FD;KATAKANA ITERATION MARK;Lm;0;L;;;;;N;;;;;
+30FE;KATAKANA VOICED ITERATION MARK;Lm;0;L;30FD 3099;;;;N;;;;;
+30FF;KATAKANA DIGRAPH KOTO;Lo;0;L;<vertical> 30B3 30C8;;;;N;;;;;
+3105;BOPOMOFO LETTER B;Lo;0;L;;;;;N;;;;;
+3106;BOPOMOFO LETTER P;Lo;0;L;;;;;N;;;;;
+3107;BOPOMOFO LETTER M;Lo;0;L;;;;;N;;;;;
+3108;BOPOMOFO LETTER F;Lo;0;L;;;;;N;;;;;
+3109;BOPOMOFO LETTER D;Lo;0;L;;;;;N;;;;;
+310A;BOPOMOFO LETTER T;Lo;0;L;;;;;N;;;;;
+310B;BOPOMOFO LETTER N;Lo;0;L;;;;;N;;;;;
+310C;BOPOMOFO LETTER L;Lo;0;L;;;;;N;;;;;
+310D;BOPOMOFO LETTER G;Lo;0;L;;;;;N;;;;;
+310E;BOPOMOFO LETTER K;Lo;0;L;;;;;N;;;;;
+310F;BOPOMOFO LETTER H;Lo;0;L;;;;;N;;;;;
+3110;BOPOMOFO LETTER J;Lo;0;L;;;;;N;;;;;
+3111;BOPOMOFO LETTER Q;Lo;0;L;;;;;N;;;;;
+3112;BOPOMOFO LETTER X;Lo;0;L;;;;;N;;;;;
+3113;BOPOMOFO LETTER ZH;Lo;0;L;;;;;N;;;;;
+3114;BOPOMOFO LETTER CH;Lo;0;L;;;;;N;;;;;
+3115;BOPOMOFO LETTER SH;Lo;0;L;;;;;N;;;;;
+3116;BOPOMOFO LETTER R;Lo;0;L;;;;;N;;;;;
+3117;BOPOMOFO LETTER Z;Lo;0;L;;;;;N;;;;;
+3118;BOPOMOFO LETTER C;Lo;0;L;;;;;N;;;;;
+3119;BOPOMOFO LETTER S;Lo;0;L;;;;;N;;;;;
+311A;BOPOMOFO LETTER A;Lo;0;L;;;;;N;;;;;
+311B;BOPOMOFO LETTER O;Lo;0;L;;;;;N;;;;;
+311C;BOPOMOFO LETTER E;Lo;0;L;;;;;N;;;;;
+311D;BOPOMOFO LETTER EH;Lo;0;L;;;;;N;;;;;
+311E;BOPOMOFO LETTER AI;Lo;0;L;;;;;N;;;;;
+311F;BOPOMOFO LETTER EI;Lo;0;L;;;;;N;;;;;
+3120;BOPOMOFO LETTER AU;Lo;0;L;;;;;N;;;;;
+3121;BOPOMOFO LETTER OU;Lo;0;L;;;;;N;;;;;
+3122;BOPOMOFO LETTER AN;Lo;0;L;;;;;N;;;;;
+3123;BOPOMOFO LETTER EN;Lo;0;L;;;;;N;;;;;
+3124;BOPOMOFO LETTER ANG;Lo;0;L;;;;;N;;;;;
+3125;BOPOMOFO LETTER ENG;Lo;0;L;;;;;N;;;;;
+3126;BOPOMOFO LETTER ER;Lo;0;L;;;;;N;;;;;
+3127;BOPOMOFO LETTER I;Lo;0;L;;;;;N;;;;;
+3128;BOPOMOFO LETTER U;Lo;0;L;;;;;N;;;;;
+3129;BOPOMOFO LETTER IU;Lo;0;L;;;;;N;;;;;
+312A;BOPOMOFO LETTER V;Lo;0;L;;;;;N;;;;;
+312B;BOPOMOFO LETTER NG;Lo;0;L;;;;;N;;;;;
+312C;BOPOMOFO LETTER GN;Lo;0;L;;;;;N;;;;;
+3131;HANGUL LETTER KIYEOK;Lo;0;L;<compat> 1100;;;;N;HANGUL LETTER GIYEOG;;;;
+3132;HANGUL LETTER SSANGKIYEOK;Lo;0;L;<compat> 1101;;;;N;HANGUL LETTER SSANG GIYEOG;;;;
+3133;HANGUL LETTER KIYEOK-SIOS;Lo;0;L;<compat> 11AA;;;;N;HANGUL LETTER GIYEOG SIOS;;;;
+3134;HANGUL LETTER NIEUN;Lo;0;L;<compat> 1102;;;;N;;;;;
+3135;HANGUL LETTER NIEUN-CIEUC;Lo;0;L;<compat> 11AC;;;;N;HANGUL LETTER NIEUN JIEUJ;;;;
+3136;HANGUL LETTER NIEUN-HIEUH;Lo;0;L;<compat> 11AD;;;;N;HANGUL LETTER NIEUN HIEUH;;;;
+3137;HANGUL LETTER TIKEUT;Lo;0;L;<compat> 1103;;;;N;HANGUL LETTER DIGEUD;;;;
+3138;HANGUL LETTER SSANGTIKEUT;Lo;0;L;<compat> 1104;;;;N;HANGUL LETTER SSANG DIGEUD;;;;
+3139;HANGUL LETTER RIEUL;Lo;0;L;<compat> 1105;;;;N;HANGUL LETTER LIEUL;;;;
+313A;HANGUL LETTER RIEUL-KIYEOK;Lo;0;L;<compat> 11B0;;;;N;HANGUL LETTER LIEUL GIYEOG;;;;
+313B;HANGUL LETTER RIEUL-MIEUM;Lo;0;L;<compat> 11B1;;;;N;HANGUL LETTER LIEUL MIEUM;;;;
+313C;HANGUL LETTER RIEUL-PIEUP;Lo;0;L;<compat> 11B2;;;;N;HANGUL LETTER LIEUL BIEUB;;;;
+313D;HANGUL LETTER RIEUL-SIOS;Lo;0;L;<compat> 11B3;;;;N;HANGUL LETTER LIEUL SIOS;;;;
+313E;HANGUL LETTER RIEUL-THIEUTH;Lo;0;L;<compat> 11B4;;;;N;HANGUL LETTER LIEUL TIEUT;;;;
+313F;HANGUL LETTER RIEUL-PHIEUPH;Lo;0;L;<compat> 11B5;;;;N;HANGUL LETTER LIEUL PIEUP;;;;
+3140;HANGUL LETTER RIEUL-HIEUH;Lo;0;L;<compat> 111A;;;;N;HANGUL LETTER LIEUL HIEUH;;;;
+3141;HANGUL LETTER MIEUM;Lo;0;L;<compat> 1106;;;;N;;;;;
+3142;HANGUL LETTER PIEUP;Lo;0;L;<compat> 1107;;;;N;HANGUL LETTER BIEUB;;;;
+3143;HANGUL LETTER SSANGPIEUP;Lo;0;L;<compat> 1108;;;;N;HANGUL LETTER SSANG BIEUB;;;;
+3144;HANGUL LETTER PIEUP-SIOS;Lo;0;L;<compat> 1121;;;;N;HANGUL LETTER BIEUB SIOS;;;;
+3145;HANGUL LETTER SIOS;Lo;0;L;<compat> 1109;;;;N;;;;;
+3146;HANGUL LETTER SSANGSIOS;Lo;0;L;<compat> 110A;;;;N;HANGUL LETTER SSANG SIOS;;;;
+3147;HANGUL LETTER IEUNG;Lo;0;L;<compat> 110B;;;;N;;;;;
+3148;HANGUL LETTER CIEUC;Lo;0;L;<compat> 110C;;;;N;HANGUL LETTER JIEUJ;;;;
+3149;HANGUL LETTER SSANGCIEUC;Lo;0;L;<compat> 110D;;;;N;HANGUL LETTER SSANG JIEUJ;;;;
+314A;HANGUL LETTER CHIEUCH;Lo;0;L;<compat> 110E;;;;N;HANGUL LETTER CIEUC;;;;
+314B;HANGUL LETTER KHIEUKH;Lo;0;L;<compat> 110F;;;;N;HANGUL LETTER KIYEOK;;;;
+314C;HANGUL LETTER THIEUTH;Lo;0;L;<compat> 1110;;;;N;HANGUL LETTER TIEUT;;;;
+314D;HANGUL LETTER PHIEUPH;Lo;0;L;<compat> 1111;;;;N;HANGUL LETTER PIEUP;;;;
+314E;HANGUL LETTER HIEUH;Lo;0;L;<compat> 1112;;;;N;;;;;
+314F;HANGUL LETTER A;Lo;0;L;<compat> 1161;;;;N;;;;;
+3150;HANGUL LETTER AE;Lo;0;L;<compat> 1162;;;;N;;;;;
+3151;HANGUL LETTER YA;Lo;0;L;<compat> 1163;;;;N;;;;;
+3152;HANGUL LETTER YAE;Lo;0;L;<compat> 1164;;;;N;;;;;
+3153;HANGUL LETTER EO;Lo;0;L;<compat> 1165;;;;N;;;;;
+3154;HANGUL LETTER E;Lo;0;L;<compat> 1166;;;;N;;;;;
+3155;HANGUL LETTER YEO;Lo;0;L;<compat> 1167;;;;N;;;;;
+3156;HANGUL LETTER YE;Lo;0;L;<compat> 1168;;;;N;;;;;
+3157;HANGUL LETTER O;Lo;0;L;<compat> 1169;;;;N;;;;;
+3158;HANGUL LETTER WA;Lo;0;L;<compat> 116A;;;;N;;;;;
+3159;HANGUL LETTER WAE;Lo;0;L;<compat> 116B;;;;N;;;;;
+315A;HANGUL LETTER OE;Lo;0;L;<compat> 116C;;;;N;;;;;
+315B;HANGUL LETTER YO;Lo;0;L;<compat> 116D;;;;N;;;;;
+315C;HANGUL LETTER U;Lo;0;L;<compat> 116E;;;;N;;;;;
+315D;HANGUL LETTER WEO;Lo;0;L;<compat> 116F;;;;N;;;;;
+315E;HANGUL LETTER WE;Lo;0;L;<compat> 1170;;;;N;;;;;
+315F;HANGUL LETTER WI;Lo;0;L;<compat> 1171;;;;N;;;;;
+3160;HANGUL LETTER YU;Lo;0;L;<compat> 1172;;;;N;;;;;
+3161;HANGUL LETTER EU;Lo;0;L;<compat> 1173;;;;N;;;;;
+3162;HANGUL LETTER YI;Lo;0;L;<compat> 1174;;;;N;;;;;
+3163;HANGUL LETTER I;Lo;0;L;<compat> 1175;;;;N;;;;;
+3164;HANGUL FILLER;Lo;0;L;<compat> 1160;;;;N;HANGUL CAE OM;;;;
+3165;HANGUL LETTER SSANGNIEUN;Lo;0;L;<compat> 1114;;;;N;HANGUL LETTER SSANG NIEUN;;;;
+3166;HANGUL LETTER NIEUN-TIKEUT;Lo;0;L;<compat> 1115;;;;N;HANGUL LETTER NIEUN DIGEUD;;;;
+3167;HANGUL LETTER NIEUN-SIOS;Lo;0;L;<compat> 11C7;;;;N;HANGUL LETTER NIEUN SIOS;;;;
+3168;HANGUL LETTER NIEUN-PANSIOS;Lo;0;L;<compat> 11C8;;;;N;HANGUL LETTER NIEUN BAN CHI EUM;;;;
+3169;HANGUL LETTER RIEUL-KIYEOK-SIOS;Lo;0;L;<compat> 11CC;;;;N;HANGUL LETTER LIEUL GIYEOG SIOS;;;;
+316A;HANGUL LETTER RIEUL-TIKEUT;Lo;0;L;<compat> 11CE;;;;N;HANGUL LETTER LIEUL DIGEUD;;;;
+316B;HANGUL LETTER RIEUL-PIEUP-SIOS;Lo;0;L;<compat> 11D3;;;;N;HANGUL LETTER LIEUL BIEUB SIOS;;;;
+316C;HANGUL LETTER RIEUL-PANSIOS;Lo;0;L;<compat> 11D7;;;;N;HANGUL LETTER LIEUL BAN CHI EUM;;;;
+316D;HANGUL LETTER RIEUL-YEORINHIEUH;Lo;0;L;<compat> 11D9;;;;N;HANGUL LETTER LIEUL YEOLIN HIEUH;;;;
+316E;HANGUL LETTER MIEUM-PIEUP;Lo;0;L;<compat> 111C;;;;N;HANGUL LETTER MIEUM BIEUB;;;;
+316F;HANGUL LETTER MIEUM-SIOS;Lo;0;L;<compat> 11DD;;;;N;HANGUL LETTER MIEUM SIOS;;;;
+3170;HANGUL LETTER MIEUM-PANSIOS;Lo;0;L;<compat> 11DF;;;;N;HANGUL LETTER BIEUB BAN CHI EUM;;;;
+3171;HANGUL LETTER KAPYEOUNMIEUM;Lo;0;L;<compat> 111D;;;;N;HANGUL LETTER MIEUM SUN GYEONG EUM;;;;
+3172;HANGUL LETTER PIEUP-KIYEOK;Lo;0;L;<compat> 111E;;;;N;HANGUL LETTER BIEUB GIYEOG;;;;
+3173;HANGUL LETTER PIEUP-TIKEUT;Lo;0;L;<compat> 1120;;;;N;HANGUL LETTER BIEUB DIGEUD;;;;
+3174;HANGUL LETTER PIEUP-SIOS-KIYEOK;Lo;0;L;<compat> 1122;;;;N;HANGUL LETTER BIEUB SIOS GIYEOG;;;;
+3175;HANGUL LETTER PIEUP-SIOS-TIKEUT;Lo;0;L;<compat> 1123;;;;N;HANGUL LETTER BIEUB SIOS DIGEUD;;;;
+3176;HANGUL LETTER PIEUP-CIEUC;Lo;0;L;<compat> 1127;;;;N;HANGUL LETTER BIEUB JIEUJ;;;;
+3177;HANGUL LETTER PIEUP-THIEUTH;Lo;0;L;<compat> 1129;;;;N;HANGUL LETTER BIEUB TIEUT;;;;
+3178;HANGUL LETTER KAPYEOUNPIEUP;Lo;0;L;<compat> 112B;;;;N;HANGUL LETTER BIEUB SUN GYEONG EUM;;;;
+3179;HANGUL LETTER KAPYEOUNSSANGPIEUP;Lo;0;L;<compat> 112C;;;;N;HANGUL LETTER SSANG BIEUB SUN GYEONG EUM;;;;
+317A;HANGUL LETTER SIOS-KIYEOK;Lo;0;L;<compat> 112D;;;;N;HANGUL LETTER SIOS GIYEOG;;;;
+317B;HANGUL LETTER SIOS-NIEUN;Lo;0;L;<compat> 112E;;;;N;HANGUL LETTER SIOS NIEUN;;;;
+317C;HANGUL LETTER SIOS-TIKEUT;Lo;0;L;<compat> 112F;;;;N;HANGUL LETTER SIOS DIGEUD;;;;
+317D;HANGUL LETTER SIOS-PIEUP;Lo;0;L;<compat> 1132;;;;N;HANGUL LETTER SIOS BIEUB;;;;
+317E;HANGUL LETTER SIOS-CIEUC;Lo;0;L;<compat> 1136;;;;N;HANGUL LETTER SIOS JIEUJ;;;;
+317F;HANGUL LETTER PANSIOS;Lo;0;L;<compat> 1140;;;;N;HANGUL LETTER BAN CHI EUM;;;;
+3180;HANGUL LETTER SSANGIEUNG;Lo;0;L;<compat> 1147;;;;N;HANGUL LETTER SSANG IEUNG;;;;
+3181;HANGUL LETTER YESIEUNG;Lo;0;L;<compat> 114C;;;;N;HANGUL LETTER NGIEUNG;;;;
+3182;HANGUL LETTER YESIEUNG-SIOS;Lo;0;L;<compat> 11F1;;;;N;HANGUL LETTER NGIEUNG SIOS;;;;
+3183;HANGUL LETTER YESIEUNG-PANSIOS;Lo;0;L;<compat> 11F2;;;;N;HANGUL LETTER NGIEUNG BAN CHI EUM;;;;
+3184;HANGUL LETTER KAPYEOUNPHIEUPH;Lo;0;L;<compat> 1157;;;;N;HANGUL LETTER PIEUP SUN GYEONG EUM;;;;
+3185;HANGUL LETTER SSANGHIEUH;Lo;0;L;<compat> 1158;;;;N;HANGUL LETTER SSANG HIEUH;;;;
+3186;HANGUL LETTER YEORINHIEUH;Lo;0;L;<compat> 1159;;;;N;HANGUL LETTER YEOLIN HIEUH;;;;
+3187;HANGUL LETTER YO-YA;Lo;0;L;<compat> 1184;;;;N;HANGUL LETTER YOYA;;;;
+3188;HANGUL LETTER YO-YAE;Lo;0;L;<compat> 1185;;;;N;HANGUL LETTER YOYAE;;;;
+3189;HANGUL LETTER YO-I;Lo;0;L;<compat> 1188;;;;N;HANGUL LETTER YOI;;;;
+318A;HANGUL LETTER YU-YEO;Lo;0;L;<compat> 1191;;;;N;HANGUL LETTER YUYEO;;;;
+318B;HANGUL LETTER YU-YE;Lo;0;L;<compat> 1192;;;;N;HANGUL LETTER YUYE;;;;
+318C;HANGUL LETTER YU-I;Lo;0;L;<compat> 1194;;;;N;HANGUL LETTER YUI;;;;
+318D;HANGUL LETTER ARAEA;Lo;0;L;<compat> 119E;;;;N;HANGUL LETTER ALAE A;;;;
+318E;HANGUL LETTER ARAEAE;Lo;0;L;<compat> 11A1;;;;N;HANGUL LETTER ALAE AE;;;;
+3190;IDEOGRAPHIC ANNOTATION LINKING MARK;So;0;L;;;;;N;KANBUN TATETEN;Kanbun Tateten;;;
+3191;IDEOGRAPHIC ANNOTATION REVERSE MARK;So;0;L;;;;;N;KAERITEN RE;Kaeriten;;;
+3192;IDEOGRAPHIC ANNOTATION ONE MARK;No;0;L;<super> 4E00;;;1;N;KAERITEN ITI;Kaeriten;;;
+3193;IDEOGRAPHIC ANNOTATION TWO MARK;No;0;L;<super> 4E8C;;;2;N;KAERITEN NI;Kaeriten;;;
+3194;IDEOGRAPHIC ANNOTATION THREE MARK;No;0;L;<super> 4E09;;;3;N;KAERITEN SAN;Kaeriten;;;
+3195;IDEOGRAPHIC ANNOTATION FOUR MARK;No;0;L;<super> 56DB;;;4;N;KAERITEN SI;Kaeriten;;;
+3196;IDEOGRAPHIC ANNOTATION TOP MARK;So;0;L;<super> 4E0A;;;;N;KAERITEN ZYOU;Kaeriten;;;
+3197;IDEOGRAPHIC ANNOTATION MIDDLE MARK;So;0;L;<super> 4E2D;;;;N;KAERITEN TYUU;Kaeriten;;;
+3198;IDEOGRAPHIC ANNOTATION BOTTOM MARK;So;0;L;<super> 4E0B;;;;N;KAERITEN GE;Kaeriten;;;
+3199;IDEOGRAPHIC ANNOTATION FIRST MARK;So;0;L;<super> 7532;;;;N;KAERITEN KOU;Kaeriten;;;
+319A;IDEOGRAPHIC ANNOTATION SECOND MARK;So;0;L;<super> 4E59;;;;N;KAERITEN OTU;Kaeriten;;;
+319B;IDEOGRAPHIC ANNOTATION THIRD MARK;So;0;L;<super> 4E19;;;;N;KAERITEN HEI;Kaeriten;;;
+319C;IDEOGRAPHIC ANNOTATION FOURTH MARK;So;0;L;<super> 4E01;;;;N;KAERITEN TEI;Kaeriten;;;
+319D;IDEOGRAPHIC ANNOTATION HEAVEN MARK;So;0;L;<super> 5929;;;;N;KAERITEN TEN;Kaeriten;;;
+319E;IDEOGRAPHIC ANNOTATION EARTH MARK;So;0;L;<super> 5730;;;;N;KAERITEN TI;Kaeriten;;;
+319F;IDEOGRAPHIC ANNOTATION MAN MARK;So;0;L;<super> 4EBA;;;;N;KAERITEN ZIN;Kaeriten;;;
+31A0;BOPOMOFO LETTER BU;Lo;0;L;;;;;N;;;;;
+31A1;BOPOMOFO LETTER ZI;Lo;0;L;;;;;N;;;;;
+31A2;BOPOMOFO LETTER JI;Lo;0;L;;;;;N;;;;;
+31A3;BOPOMOFO LETTER GU;Lo;0;L;;;;;N;;;;;
+31A4;BOPOMOFO LETTER EE;Lo;0;L;;;;;N;;;;;
+31A5;BOPOMOFO LETTER ENN;Lo;0;L;;;;;N;;;;;
+31A6;BOPOMOFO LETTER OO;Lo;0;L;;;;;N;;;;;
+31A7;BOPOMOFO LETTER ONN;Lo;0;L;;;;;N;;;;;
+31A8;BOPOMOFO LETTER IR;Lo;0;L;;;;;N;;;;;
+31A9;BOPOMOFO LETTER ANN;Lo;0;L;;;;;N;;;;;
+31AA;BOPOMOFO LETTER INN;Lo;0;L;;;;;N;;;;;
+31AB;BOPOMOFO LETTER UNN;Lo;0;L;;;;;N;;;;;
+31AC;BOPOMOFO LETTER IM;Lo;0;L;;;;;N;;;;;
+31AD;BOPOMOFO LETTER NGG;Lo;0;L;;;;;N;;;;;
+31AE;BOPOMOFO LETTER AINN;Lo;0;L;;;;;N;;;;;
+31AF;BOPOMOFO LETTER AUNN;Lo;0;L;;;;;N;;;;;
+31B0;BOPOMOFO LETTER AM;Lo;0;L;;;;;N;;;;;
+31B1;BOPOMOFO LETTER OM;Lo;0;L;;;;;N;;;;;
+31B2;BOPOMOFO LETTER ONG;Lo;0;L;;;;;N;;;;;
+31B3;BOPOMOFO LETTER INNN;Lo;0;L;;;;;N;;;;;
+31B4;BOPOMOFO FINAL LETTER P;Lo;0;L;;;;;N;;;;;
+31B5;BOPOMOFO FINAL LETTER T;Lo;0;L;;;;;N;;;;;
+31B6;BOPOMOFO FINAL LETTER K;Lo;0;L;;;;;N;;;;;
+31B7;BOPOMOFO FINAL LETTER H;Lo;0;L;;;;;N;;;;;
+31C0;CJK STROKE T;So;0;ON;;;;;N;;;;;
+31C1;CJK STROKE WG;So;0;ON;;;;;N;;;;;
+31C2;CJK STROKE XG;So;0;ON;;;;;N;;;;;
+31C3;CJK STROKE BXG;So;0;ON;;;;;N;;;;;
+31C4;CJK STROKE SW;So;0;ON;;;;;N;;;;;
+31C5;CJK STROKE HZZ;So;0;ON;;;;;N;;;;;
+31C6;CJK STROKE HZG;So;0;ON;;;;;N;;;;;
+31C7;CJK STROKE HP;So;0;ON;;;;;N;;;;;
+31C8;CJK STROKE HZWG;So;0;ON;;;;;N;;;;;
+31C9;CJK STROKE SZWG;So;0;ON;;;;;N;;;;;
+31CA;CJK STROKE HZT;So;0;ON;;;;;N;;;;;
+31CB;CJK STROKE HZZP;So;0;ON;;;;;N;;;;;
+31CC;CJK STROKE HPWG;So;0;ON;;;;;N;;;;;
+31CD;CJK STROKE HZW;So;0;ON;;;;;N;;;;;
+31CE;CJK STROKE HZZZ;So;0;ON;;;;;N;;;;;
+31CF;CJK STROKE N;So;0;ON;;;;;N;;;;;
+31F0;KATAKANA LETTER SMALL KU;Lo;0;L;;;;;N;;;;;
+31F1;KATAKANA LETTER SMALL SI;Lo;0;L;;;;;N;;;;;
+31F2;KATAKANA LETTER SMALL SU;Lo;0;L;;;;;N;;;;;
+31F3;KATAKANA LETTER SMALL TO;Lo;0;L;;;;;N;;;;;
+31F4;KATAKANA LETTER SMALL NU;Lo;0;L;;;;;N;;;;;
+31F5;KATAKANA LETTER SMALL HA;Lo;0;L;;;;;N;;;;;
+31F6;KATAKANA LETTER SMALL HI;Lo;0;L;;;;;N;;;;;
+31F7;KATAKANA LETTER SMALL HU;Lo;0;L;;;;;N;;;;;
+31F8;KATAKANA LETTER SMALL HE;Lo;0;L;;;;;N;;;;;
+31F9;KATAKANA LETTER SMALL HO;Lo;0;L;;;;;N;;;;;
+31FA;KATAKANA LETTER SMALL MU;Lo;0;L;;;;;N;;;;;
+31FB;KATAKANA LETTER SMALL RA;Lo;0;L;;;;;N;;;;;
+31FC;KATAKANA LETTER SMALL RI;Lo;0;L;;;;;N;;;;;
+31FD;KATAKANA LETTER SMALL RU;Lo;0;L;;;;;N;;;;;
+31FE;KATAKANA LETTER SMALL RE;Lo;0;L;;;;;N;;;;;
+31FF;KATAKANA LETTER SMALL RO;Lo;0;L;;;;;N;;;;;
+3200;PARENTHESIZED HANGUL KIYEOK;So;0;L;<compat> 0028 1100 0029;;;;N;PARENTHESIZED HANGUL GIYEOG;;;;
+3201;PARENTHESIZED HANGUL NIEUN;So;0;L;<compat> 0028 1102 0029;;;;N;;;;;
+3202;PARENTHESIZED HANGUL TIKEUT;So;0;L;<compat> 0028 1103 0029;;;;N;PARENTHESIZED HANGUL DIGEUD;;;;
+3203;PARENTHESIZED HANGUL RIEUL;So;0;L;<compat> 0028 1105 0029;;;;N;PARENTHESIZED HANGUL LIEUL;;;;
+3204;PARENTHESIZED HANGUL MIEUM;So;0;L;<compat> 0028 1106 0029;;;;N;;;;;
+3205;PARENTHESIZED HANGUL PIEUP;So;0;L;<compat> 0028 1107 0029;;;;N;PARENTHESIZED HANGUL BIEUB;;;;
+3206;PARENTHESIZED HANGUL SIOS;So;0;L;<compat> 0028 1109 0029;;;;N;;;;;
+3207;PARENTHESIZED HANGUL IEUNG;So;0;L;<compat> 0028 110B 0029;;;;N;;;;;
+3208;PARENTHESIZED HANGUL CIEUC;So;0;L;<compat> 0028 110C 0029;;;;N;PARENTHESIZED HANGUL JIEUJ;;;;
+3209;PARENTHESIZED HANGUL CHIEUCH;So;0;L;<compat> 0028 110E 0029;;;;N;PARENTHESIZED HANGUL CIEUC;;;;
+320A;PARENTHESIZED HANGUL KHIEUKH;So;0;L;<compat> 0028 110F 0029;;;;N;PARENTHESIZED HANGUL KIYEOK;;;;
+320B;PARENTHESIZED HANGUL THIEUTH;So;0;L;<compat> 0028 1110 0029;;;;N;PARENTHESIZED HANGUL TIEUT;;;;
+320C;PARENTHESIZED HANGUL PHIEUPH;So;0;L;<compat> 0028 1111 0029;;;;N;PARENTHESIZED HANGUL PIEUP;;;;
+320D;PARENTHESIZED HANGUL HIEUH;So;0;L;<compat> 0028 1112 0029;;;;N;;;;;
+320E;PARENTHESIZED HANGUL KIYEOK A;So;0;L;<compat> 0028 1100 1161 0029;;;;N;PARENTHESIZED HANGUL GA;;;;
+320F;PARENTHESIZED HANGUL NIEUN A;So;0;L;<compat> 0028 1102 1161 0029;;;;N;PARENTHESIZED HANGUL NA;;;;
+3210;PARENTHESIZED HANGUL TIKEUT A;So;0;L;<compat> 0028 1103 1161 0029;;;;N;PARENTHESIZED HANGUL DA;;;;
+3211;PARENTHESIZED HANGUL RIEUL A;So;0;L;<compat> 0028 1105 1161 0029;;;;N;PARENTHESIZED HANGUL LA;;;;
+3212;PARENTHESIZED HANGUL MIEUM A;So;0;L;<compat> 0028 1106 1161 0029;;;;N;PARENTHESIZED HANGUL MA;;;;
+3213;PARENTHESIZED HANGUL PIEUP A;So;0;L;<compat> 0028 1107 1161 0029;;;;N;PARENTHESIZED HANGUL BA;;;;
+3214;PARENTHESIZED HANGUL SIOS A;So;0;L;<compat> 0028 1109 1161 0029;;;;N;PARENTHESIZED HANGUL SA;;;;
+3215;PARENTHESIZED HANGUL IEUNG A;So;0;L;<compat> 0028 110B 1161 0029;;;;N;PARENTHESIZED HANGUL A;;;;
+3216;PARENTHESIZED HANGUL CIEUC A;So;0;L;<compat> 0028 110C 1161 0029;;;;N;PARENTHESIZED HANGUL JA;;;;
+3217;PARENTHESIZED HANGUL CHIEUCH A;So;0;L;<compat> 0028 110E 1161 0029;;;;N;PARENTHESIZED HANGUL CA;;;;
+3218;PARENTHESIZED HANGUL KHIEUKH A;So;0;L;<compat> 0028 110F 1161 0029;;;;N;PARENTHESIZED HANGUL KA;;;;
+3219;PARENTHESIZED HANGUL THIEUTH A;So;0;L;<compat> 0028 1110 1161 0029;;;;N;PARENTHESIZED HANGUL TA;;;;
+321A;PARENTHESIZED HANGUL PHIEUPH A;So;0;L;<compat> 0028 1111 1161 0029;;;;N;PARENTHESIZED HANGUL PA;;;;
+321B;PARENTHESIZED HANGUL HIEUH A;So;0;L;<compat> 0028 1112 1161 0029;;;;N;PARENTHESIZED HANGUL HA;;;;
+321C;PARENTHESIZED HANGUL CIEUC U;So;0;L;<compat> 0028 110C 116E 0029;;;;N;PARENTHESIZED HANGUL JU;;;;
+321D;PARENTHESIZED KOREAN CHARACTER OJEON;So;0;ON;<compat> 0028 110B 1169 110C 1165 11AB 0029;;;;N;;;;;
+321E;PARENTHESIZED KOREAN CHARACTER O HU;So;0;ON;<compat> 0028 110B 1169 1112 116E 0029;;;;N;;;;;
+3220;PARENTHESIZED IDEOGRAPH ONE;No;0;L;<compat> 0028 4E00 0029;;;1;N;;;;;
+3221;PARENTHESIZED IDEOGRAPH TWO;No;0;L;<compat> 0028 4E8C 0029;;;2;N;;;;;
+3222;PARENTHESIZED IDEOGRAPH THREE;No;0;L;<compat> 0028 4E09 0029;;;3;N;;;;;
+3223;PARENTHESIZED IDEOGRAPH FOUR;No;0;L;<compat> 0028 56DB 0029;;;4;N;;;;;
+3224;PARENTHESIZED IDEOGRAPH FIVE;No;0;L;<compat> 0028 4E94 0029;;;5;N;;;;;
+3225;PARENTHESIZED IDEOGRAPH SIX;No;0;L;<compat> 0028 516D 0029;;;6;N;;;;;
+3226;PARENTHESIZED IDEOGRAPH SEVEN;No;0;L;<compat> 0028 4E03 0029;;;7;N;;;;;
+3227;PARENTHESIZED IDEOGRAPH EIGHT;No;0;L;<compat> 0028 516B 0029;;;8;N;;;;;
+3228;PARENTHESIZED IDEOGRAPH NINE;No;0;L;<compat> 0028 4E5D 0029;;;9;N;;;;;
+3229;PARENTHESIZED IDEOGRAPH TEN;No;0;L;<compat> 0028 5341 0029;;;10;N;;;;;
+322A;PARENTHESIZED IDEOGRAPH MOON;So;0;L;<compat> 0028 6708 0029;;;;N;;;;;
+322B;PARENTHESIZED IDEOGRAPH FIRE;So;0;L;<compat> 0028 706B 0029;;;;N;;;;;
+322C;PARENTHESIZED IDEOGRAPH WATER;So;0;L;<compat> 0028 6C34 0029;;;;N;;;;;
+322D;PARENTHESIZED IDEOGRAPH WOOD;So;0;L;<compat> 0028 6728 0029;;;;N;;;;;
+322E;PARENTHESIZED IDEOGRAPH METAL;So;0;L;<compat> 0028 91D1 0029;;;;N;;;;;
+322F;PARENTHESIZED IDEOGRAPH EARTH;So;0;L;<compat> 0028 571F 0029;;;;N;;;;;
+3230;PARENTHESIZED IDEOGRAPH SUN;So;0;L;<compat> 0028 65E5 0029;;;;N;;;;;
+3231;PARENTHESIZED IDEOGRAPH STOCK;So;0;L;<compat> 0028 682A 0029;;;;N;;;;;
+3232;PARENTHESIZED IDEOGRAPH HAVE;So;0;L;<compat> 0028 6709 0029;;;;N;;;;;
+3233;PARENTHESIZED IDEOGRAPH SOCIETY;So;0;L;<compat> 0028 793E 0029;;;;N;;;;;
+3234;PARENTHESIZED IDEOGRAPH NAME;So;0;L;<compat> 0028 540D 0029;;;;N;;;;;
+3235;PARENTHESIZED IDEOGRAPH SPECIAL;So;0;L;<compat> 0028 7279 0029;;;;N;;;;;
+3236;PARENTHESIZED IDEOGRAPH FINANCIAL;So;0;L;<compat> 0028 8CA1 0029;;;;N;;;;;
+3237;PARENTHESIZED IDEOGRAPH CONGRATULATION;So;0;L;<compat> 0028 795D 0029;;;;N;;;;;
+3238;PARENTHESIZED IDEOGRAPH LABOR;So;0;L;<compat> 0028 52B4 0029;;;;N;;;;;
+3239;PARENTHESIZED IDEOGRAPH REPRESENT;So;0;L;<compat> 0028 4EE3 0029;;;;N;;;;;
+323A;PARENTHESIZED IDEOGRAPH CALL;So;0;L;<compat> 0028 547C 0029;;;;N;;;;;
+323B;PARENTHESIZED IDEOGRAPH STUDY;So;0;L;<compat> 0028 5B66 0029;;;;N;;;;;
+323C;PARENTHESIZED IDEOGRAPH SUPERVISE;So;0;L;<compat> 0028 76E3 0029;;;;N;;;;;
+323D;PARENTHESIZED IDEOGRAPH ENTERPRISE;So;0;L;<compat> 0028 4F01 0029;;;;N;;;;;
+323E;PARENTHESIZED IDEOGRAPH RESOURCE;So;0;L;<compat> 0028 8CC7 0029;;;;N;;;;;
+323F;PARENTHESIZED IDEOGRAPH ALLIANCE;So;0;L;<compat> 0028 5354 0029;;;;N;;;;;
+3240;PARENTHESIZED IDEOGRAPH FESTIVAL;So;0;L;<compat> 0028 796D 0029;;;;N;;;;;
+3241;PARENTHESIZED IDEOGRAPH REST;So;0;L;<compat> 0028 4F11 0029;;;;N;;;;;
+3242;PARENTHESIZED IDEOGRAPH SELF;So;0;L;<compat> 0028 81EA 0029;;;;N;;;;;
+3243;PARENTHESIZED IDEOGRAPH REACH;So;0;L;<compat> 0028 81F3 0029;;;;N;;;;;
+3250;PARTNERSHIP SIGN;So;0;ON;<square> 0050 0054 0045;;;;N;;;;;
+3251;CIRCLED NUMBER TWENTY ONE;No;0;ON;<circle> 0032 0031;;;21;N;;;;;
+3252;CIRCLED NUMBER TWENTY TWO;No;0;ON;<circle> 0032 0032;;;22;N;;;;;
+3253;CIRCLED NUMBER TWENTY THREE;No;0;ON;<circle> 0032 0033;;;23;N;;;;;
+3254;CIRCLED NUMBER TWENTY FOUR;No;0;ON;<circle> 0032 0034;;;24;N;;;;;
+3255;CIRCLED NUMBER TWENTY FIVE;No;0;ON;<circle> 0032 0035;;;25;N;;;;;
+3256;CIRCLED NUMBER TWENTY SIX;No;0;ON;<circle> 0032 0036;;;26;N;;;;;
+3257;CIRCLED NUMBER TWENTY SEVEN;No;0;ON;<circle> 0032 0037;;;27;N;;;;;
+3258;CIRCLED NUMBER TWENTY EIGHT;No;0;ON;<circle> 0032 0038;;;28;N;;;;;
+3259;CIRCLED NUMBER TWENTY NINE;No;0;ON;<circle> 0032 0039;;;29;N;;;;;
+325A;CIRCLED NUMBER THIRTY;No;0;ON;<circle> 0033 0030;;;30;N;;;;;
+325B;CIRCLED NUMBER THIRTY ONE;No;0;ON;<circle> 0033 0031;;;31;N;;;;;
+325C;CIRCLED NUMBER THIRTY TWO;No;0;ON;<circle> 0033 0032;;;32;N;;;;;
+325D;CIRCLED NUMBER THIRTY THREE;No;0;ON;<circle> 0033 0033;;;33;N;;;;;
+325E;CIRCLED NUMBER THIRTY FOUR;No;0;ON;<circle> 0033 0034;;;34;N;;;;;
+325F;CIRCLED NUMBER THIRTY FIVE;No;0;ON;<circle> 0033 0035;;;35;N;;;;;
+3260;CIRCLED HANGUL KIYEOK;So;0;L;<circle> 1100;;;;N;CIRCLED HANGUL GIYEOG;;;;
+3261;CIRCLED HANGUL NIEUN;So;0;L;<circle> 1102;;;;N;;;;;
+3262;CIRCLED HANGUL TIKEUT;So;0;L;<circle> 1103;;;;N;CIRCLED HANGUL DIGEUD;;;;
+3263;CIRCLED HANGUL RIEUL;So;0;L;<circle> 1105;;;;N;CIRCLED HANGUL LIEUL;;;;
+3264;CIRCLED HANGUL MIEUM;So;0;L;<circle> 1106;;;;N;;;;;
+3265;CIRCLED HANGUL PIEUP;So;0;L;<circle> 1107;;;;N;CIRCLED HANGUL BIEUB;;;;
+3266;CIRCLED HANGUL SIOS;So;0;L;<circle> 1109;;;;N;;;;;
+3267;CIRCLED HANGUL IEUNG;So;0;L;<circle> 110B;;;;N;;;;;
+3268;CIRCLED HANGUL CIEUC;So;0;L;<circle> 110C;;;;N;CIRCLED HANGUL JIEUJ;;;;
+3269;CIRCLED HANGUL CHIEUCH;So;0;L;<circle> 110E;;;;N;CIRCLED HANGUL CIEUC;;;;
+326A;CIRCLED HANGUL KHIEUKH;So;0;L;<circle> 110F;;;;N;CIRCLED HANGUL KIYEOK;;;;
+326B;CIRCLED HANGUL THIEUTH;So;0;L;<circle> 1110;;;;N;CIRCLED HANGUL TIEUT;;;;
+326C;CIRCLED HANGUL PHIEUPH;So;0;L;<circle> 1111;;;;N;CIRCLED HANGUL PIEUP;;;;
+326D;CIRCLED HANGUL HIEUH;So;0;L;<circle> 1112;;;;N;;;;;
+326E;CIRCLED HANGUL KIYEOK A;So;0;L;<circle> 1100 1161;;;;N;CIRCLED HANGUL GA;;;;
+326F;CIRCLED HANGUL NIEUN A;So;0;L;<circle> 1102 1161;;;;N;CIRCLED HANGUL NA;;;;
+3270;CIRCLED HANGUL TIKEUT A;So;0;L;<circle> 1103 1161;;;;N;CIRCLED HANGUL DA;;;;
+3271;CIRCLED HANGUL RIEUL A;So;0;L;<circle> 1105 1161;;;;N;CIRCLED HANGUL LA;;;;
+3272;CIRCLED HANGUL MIEUM A;So;0;L;<circle> 1106 1161;;;;N;CIRCLED HANGUL MA;;;;
+3273;CIRCLED HANGUL PIEUP A;So;0;L;<circle> 1107 1161;;;;N;CIRCLED HANGUL BA;;;;
+3274;CIRCLED HANGUL SIOS A;So;0;L;<circle> 1109 1161;;;;N;CIRCLED HANGUL SA;;;;
+3275;CIRCLED HANGUL IEUNG A;So;0;L;<circle> 110B 1161;;;;N;CIRCLED HANGUL A;;;;
+3276;CIRCLED HANGUL CIEUC A;So;0;L;<circle> 110C 1161;;;;N;CIRCLED HANGUL JA;;;;
+3277;CIRCLED HANGUL CHIEUCH A;So;0;L;<circle> 110E 1161;;;;N;CIRCLED HANGUL CA;;;;
+3278;CIRCLED HANGUL KHIEUKH A;So;0;L;<circle> 110F 1161;;;;N;CIRCLED HANGUL KA;;;;
+3279;CIRCLED HANGUL THIEUTH A;So;0;L;<circle> 1110 1161;;;;N;CIRCLED HANGUL TA;;;;
+327A;CIRCLED HANGUL PHIEUPH A;So;0;L;<circle> 1111 1161;;;;N;CIRCLED HANGUL PA;;;;
+327B;CIRCLED HANGUL HIEUH A;So;0;L;<circle> 1112 1161;;;;N;CIRCLED HANGUL HA;;;;
+327C;CIRCLED KOREAN CHARACTER CHAMKO;So;0;ON;<circle> 110E 1161 11B7 1100 1169;;;;N;;;;;
+327D;CIRCLED KOREAN CHARACTER JUEUI;So;0;ON;<circle> 110C 116E 110B 1174;;;;N;;;;;
+327E;CIRCLED HANGUL IEUNG U;So;0;ON;<circle> 110B 116E;;;;N;;;;;
+327F;KOREAN STANDARD SYMBOL;So;0;L;;;;;N;;;;;
+3280;CIRCLED IDEOGRAPH ONE;No;0;L;<circle> 4E00;;;1;N;;;;;
+3281;CIRCLED IDEOGRAPH TWO;No;0;L;<circle> 4E8C;;;2;N;;;;;
+3282;CIRCLED IDEOGRAPH THREE;No;0;L;<circle> 4E09;;;3;N;;;;;
+3283;CIRCLED IDEOGRAPH FOUR;No;0;L;<circle> 56DB;;;4;N;;;;;
+3284;CIRCLED IDEOGRAPH FIVE;No;0;L;<circle> 4E94;;;5;N;;;;;
+3285;CIRCLED IDEOGRAPH SIX;No;0;L;<circle> 516D;;;6;N;;;;;
+3286;CIRCLED IDEOGRAPH SEVEN;No;0;L;<circle> 4E03;;;7;N;;;;;
+3287;CIRCLED IDEOGRAPH EIGHT;No;0;L;<circle> 516B;;;8;N;;;;;
+3288;CIRCLED IDEOGRAPH NINE;No;0;L;<circle> 4E5D;;;9;N;;;;;
+3289;CIRCLED IDEOGRAPH TEN;No;0;L;<circle> 5341;;;10;N;;;;;
+328A;CIRCLED IDEOGRAPH MOON;So;0;L;<circle> 6708;;;;N;;;;;
+328B;CIRCLED IDEOGRAPH FIRE;So;0;L;<circle> 706B;;;;N;;;;;
+328C;CIRCLED IDEOGRAPH WATER;So;0;L;<circle> 6C34;;;;N;;;;;
+328D;CIRCLED IDEOGRAPH WOOD;So;0;L;<circle> 6728;;;;N;;;;;
+328E;CIRCLED IDEOGRAPH METAL;So;0;L;<circle> 91D1;;;;N;;;;;
+328F;CIRCLED IDEOGRAPH EARTH;So;0;L;<circle> 571F;;;;N;;;;;
+3290;CIRCLED IDEOGRAPH SUN;So;0;L;<circle> 65E5;;;;N;;;;;
+3291;CIRCLED IDEOGRAPH STOCK;So;0;L;<circle> 682A;;;;N;;;;;
+3292;CIRCLED IDEOGRAPH HAVE;So;0;L;<circle> 6709;;;;N;;;;;
+3293;CIRCLED IDEOGRAPH SOCIETY;So;0;L;<circle> 793E;;;;N;;;;;
+3294;CIRCLED IDEOGRAPH NAME;So;0;L;<circle> 540D;;;;N;;;;;
+3295;CIRCLED IDEOGRAPH SPECIAL;So;0;L;<circle> 7279;;;;N;;;;;
+3296;CIRCLED IDEOGRAPH FINANCIAL;So;0;L;<circle> 8CA1;;;;N;;;;;
+3297;CIRCLED IDEOGRAPH CONGRATULATION;So;0;L;<circle> 795D;;;;N;;;;;
+3298;CIRCLED IDEOGRAPH LABOR;So;0;L;<circle> 52B4;;;;N;;;;;
+3299;CIRCLED IDEOGRAPH SECRET;So;0;L;<circle> 79D8;;;;N;;;;;
+329A;CIRCLED IDEOGRAPH MALE;So;0;L;<circle> 7537;;;;N;;;;;
+329B;CIRCLED IDEOGRAPH FEMALE;So;0;L;<circle> 5973;;;;N;;;;;
+329C;CIRCLED IDEOGRAPH SUITABLE;So;0;L;<circle> 9069;;;;N;;;;;
+329D;CIRCLED IDEOGRAPH EXCELLENT;So;0;L;<circle> 512A;;;;N;;;;;
+329E;CIRCLED IDEOGRAPH PRINT;So;0;L;<circle> 5370;;;;N;;;;;
+329F;CIRCLED IDEOGRAPH ATTENTION;So;0;L;<circle> 6CE8;;;;N;;;;;
+32A0;CIRCLED IDEOGRAPH ITEM;So;0;L;<circle> 9805;;;;N;;;;;
+32A1;CIRCLED IDEOGRAPH REST;So;0;L;<circle> 4F11;;;;N;;;;;
+32A2;CIRCLED IDEOGRAPH COPY;So;0;L;<circle> 5199;;;;N;;;;;
+32A3;CIRCLED IDEOGRAPH CORRECT;So;0;L;<circle> 6B63;;;;N;;;;;
+32A4;CIRCLED IDEOGRAPH HIGH;So;0;L;<circle> 4E0A;;;;N;;;;;
+32A5;CIRCLED IDEOGRAPH CENTRE;So;0;L;<circle> 4E2D;;;;N;CIRCLED IDEOGRAPH CENTER;;;;
+32A6;CIRCLED IDEOGRAPH LOW;So;0;L;<circle> 4E0B;;;;N;;;;;
+32A7;CIRCLED IDEOGRAPH LEFT;So;0;L;<circle> 5DE6;;;;N;;;;;
+32A8;CIRCLED IDEOGRAPH RIGHT;So;0;L;<circle> 53F3;;;;N;;;;;
+32A9;CIRCLED IDEOGRAPH MEDICINE;So;0;L;<circle> 533B;;;;N;;;;;
+32AA;CIRCLED IDEOGRAPH RELIGION;So;0;L;<circle> 5B97;;;;N;;;;;
+32AB;CIRCLED IDEOGRAPH STUDY;So;0;L;<circle> 5B66;;;;N;;;;;
+32AC;CIRCLED IDEOGRAPH SUPERVISE;So;0;L;<circle> 76E3;;;;N;;;;;
+32AD;CIRCLED IDEOGRAPH ENTERPRISE;So;0;L;<circle> 4F01;;;;N;;;;;
+32AE;CIRCLED IDEOGRAPH RESOURCE;So;0;L;<circle> 8CC7;;;;N;;;;;
+32AF;CIRCLED IDEOGRAPH ALLIANCE;So;0;L;<circle> 5354;;;;N;;;;;
+32B0;CIRCLED IDEOGRAPH NIGHT;So;0;L;<circle> 591C;;;;N;;;;;
+32B1;CIRCLED NUMBER THIRTY SIX;No;0;ON;<circle> 0033 0036;;;36;N;;;;;
+32B2;CIRCLED NUMBER THIRTY SEVEN;No;0;ON;<circle> 0033 0037;;;37;N;;;;;
+32B3;CIRCLED NUMBER THIRTY EIGHT;No;0;ON;<circle> 0033 0038;;;38;N;;;;;
+32B4;CIRCLED NUMBER THIRTY NINE;No;0;ON;<circle> 0033 0039;;;39;N;;;;;
+32B5;CIRCLED NUMBER FORTY;No;0;ON;<circle> 0034 0030;;;40;N;;;;;
+32B6;CIRCLED NUMBER FORTY ONE;No;0;ON;<circle> 0034 0031;;;41;N;;;;;
+32B7;CIRCLED NUMBER FORTY TWO;No;0;ON;<circle> 0034 0032;;;42;N;;;;;
+32B8;CIRCLED NUMBER FORTY THREE;No;0;ON;<circle> 0034 0033;;;43;N;;;;;
+32B9;CIRCLED NUMBER FORTY FOUR;No;0;ON;<circle> 0034 0034;;;44;N;;;;;
+32BA;CIRCLED NUMBER FORTY FIVE;No;0;ON;<circle> 0034 0035;;;45;N;;;;;
+32BB;CIRCLED NUMBER FORTY SIX;No;0;ON;<circle> 0034 0036;;;46;N;;;;;
+32BC;CIRCLED NUMBER FORTY SEVEN;No;0;ON;<circle> 0034 0037;;;47;N;;;;;
+32BD;CIRCLED NUMBER FORTY EIGHT;No;0;ON;<circle> 0034 0038;;;48;N;;;;;
+32BE;CIRCLED NUMBER FORTY NINE;No;0;ON;<circle> 0034 0039;;;49;N;;;;;
+32BF;CIRCLED NUMBER FIFTY;No;0;ON;<circle> 0035 0030;;;50;N;;;;;
+32C0;IDEOGRAPHIC TELEGRAPH SYMBOL FOR JANUARY;So;0;L;<compat> 0031 6708;;;;N;;;;;
+32C1;IDEOGRAPHIC TELEGRAPH SYMBOL FOR FEBRUARY;So;0;L;<compat> 0032 6708;;;;N;;;;;
+32C2;IDEOGRAPHIC TELEGRAPH SYMBOL FOR MARCH;So;0;L;<compat> 0033 6708;;;;N;;;;;
+32C3;IDEOGRAPHIC TELEGRAPH SYMBOL FOR APRIL;So;0;L;<compat> 0034 6708;;;;N;;;;;
+32C4;IDEOGRAPHIC TELEGRAPH SYMBOL FOR MAY;So;0;L;<compat> 0035 6708;;;;N;;;;;
+32C5;IDEOGRAPHIC TELEGRAPH SYMBOL FOR JUNE;So;0;L;<compat> 0036 6708;;;;N;;;;;
+32C6;IDEOGRAPHIC TELEGRAPH SYMBOL FOR JULY;So;0;L;<compat> 0037 6708;;;;N;;;;;
+32C7;IDEOGRAPHIC TELEGRAPH SYMBOL FOR AUGUST;So;0;L;<compat> 0038 6708;;;;N;;;;;
+32C8;IDEOGRAPHIC TELEGRAPH SYMBOL FOR SEPTEMBER;So;0;L;<compat> 0039 6708;;;;N;;;;;
+32C9;IDEOGRAPHIC TELEGRAPH SYMBOL FOR OCTOBER;So;0;L;<compat> 0031 0030 6708;;;;N;;;;;
+32CA;IDEOGRAPHIC TELEGRAPH SYMBOL FOR NOVEMBER;So;0;L;<compat> 0031 0031 6708;;;;N;;;;;
+32CB;IDEOGRAPHIC TELEGRAPH SYMBOL FOR DECEMBER;So;0;L;<compat> 0031 0032 6708;;;;N;;;;;
+32CC;SQUARE HG;So;0;ON;<square> 0048 0067;;;;N;;;;;
+32CD;SQUARE ERG;So;0;ON;<square> 0065 0072 0067;;;;N;;;;;
+32CE;SQUARE EV;So;0;ON;<square> 0065 0056;;;;N;;;;;
+32CF;LIMITED LIABILITY SIGN;So;0;ON;<square> 004C 0054 0044;;;;N;;;;;
+32D0;CIRCLED KATAKANA A;So;0;L;<circle> 30A2;;;;N;;;;;
+32D1;CIRCLED KATAKANA I;So;0;L;<circle> 30A4;;;;N;;;;;
+32D2;CIRCLED KATAKANA U;So;0;L;<circle> 30A6;;;;N;;;;;
+32D3;CIRCLED KATAKANA E;So;0;L;<circle> 30A8;;;;N;;;;;
+32D4;CIRCLED KATAKANA O;So;0;L;<circle> 30AA;;;;N;;;;;
+32D5;CIRCLED KATAKANA KA;So;0;L;<circle> 30AB;;;;N;;;;;
+32D6;CIRCLED KATAKANA KI;So;0;L;<circle> 30AD;;;;N;;;;;
+32D7;CIRCLED KATAKANA KU;So;0;L;<circle> 30AF;;;;N;;;;;
+32D8;CIRCLED KATAKANA KE;So;0;L;<circle> 30B1;;;;N;;;;;
+32D9;CIRCLED KATAKANA KO;So;0;L;<circle> 30B3;;;;N;;;;;
+32DA;CIRCLED KATAKANA SA;So;0;L;<circle> 30B5;;;;N;;;;;
+32DB;CIRCLED KATAKANA SI;So;0;L;<circle> 30B7;;;;N;;;;;
+32DC;CIRCLED KATAKANA SU;So;0;L;<circle> 30B9;;;;N;;;;;
+32DD;CIRCLED KATAKANA SE;So;0;L;<circle> 30BB;;;;N;;;;;
+32DE;CIRCLED KATAKANA SO;So;0;L;<circle> 30BD;;;;N;;;;;
+32DF;CIRCLED KATAKANA TA;So;0;L;<circle> 30BF;;;;N;;;;;
+32E0;CIRCLED KATAKANA TI;So;0;L;<circle> 30C1;;;;N;;;;;
+32E1;CIRCLED KATAKANA TU;So;0;L;<circle> 30C4;;;;N;;;;;
+32E2;CIRCLED KATAKANA TE;So;0;L;<circle> 30C6;;;;N;;;;;
+32E3;CIRCLED KATAKANA TO;So;0;L;<circle> 30C8;;;;N;;;;;
+32E4;CIRCLED KATAKANA NA;So;0;L;<circle> 30CA;;;;N;;;;;
+32E5;CIRCLED KATAKANA NI;So;0;L;<circle> 30CB;;;;N;;;;;
+32E6;CIRCLED KATAKANA NU;So;0;L;<circle> 30CC;;;;N;;;;;
+32E7;CIRCLED KATAKANA NE;So;0;L;<circle> 30CD;;;;N;;;;;
+32E8;CIRCLED KATAKANA NO;So;0;L;<circle> 30CE;;;;N;;;;;
+32E9;CIRCLED KATAKANA HA;So;0;L;<circle> 30CF;;;;N;;;;;
+32EA;CIRCLED KATAKANA HI;So;0;L;<circle> 30D2;;;;N;;;;;
+32EB;CIRCLED KATAKANA HU;So;0;L;<circle> 30D5;;;;N;;;;;
+32EC;CIRCLED KATAKANA HE;So;0;L;<circle> 30D8;;;;N;;;;;
+32ED;CIRCLED KATAKANA HO;So;0;L;<circle> 30DB;;;;N;;;;;
+32EE;CIRCLED KATAKANA MA;So;0;L;<circle> 30DE;;;;N;;;;;
+32EF;CIRCLED KATAKANA MI;So;0;L;<circle> 30DF;;;;N;;;;;
+32F0;CIRCLED KATAKANA MU;So;0;L;<circle> 30E0;;;;N;;;;;
+32F1;CIRCLED KATAKANA ME;So;0;L;<circle> 30E1;;;;N;;;;;
+32F2;CIRCLED KATAKANA MO;So;0;L;<circle> 30E2;;;;N;;;;;
+32F3;CIRCLED KATAKANA YA;So;0;L;<circle> 30E4;;;;N;;;;;
+32F4;CIRCLED KATAKANA YU;So;0;L;<circle> 30E6;;;;N;;;;;
+32F5;CIRCLED KATAKANA YO;So;0;L;<circle> 30E8;;;;N;;;;;
+32F6;CIRCLED KATAKANA RA;So;0;L;<circle> 30E9;;;;N;;;;;
+32F7;CIRCLED KATAKANA RI;So;0;L;<circle> 30EA;;;;N;;;;;
+32F8;CIRCLED KATAKANA RU;So;0;L;<circle> 30EB;;;;N;;;;;
+32F9;CIRCLED KATAKANA RE;So;0;L;<circle> 30EC;;;;N;;;;;
+32FA;CIRCLED KATAKANA RO;So;0;L;<circle> 30ED;;;;N;;;;;
+32FB;CIRCLED KATAKANA WA;So;0;L;<circle> 30EF;;;;N;;;;;
+32FC;CIRCLED KATAKANA WI;So;0;L;<circle> 30F0;;;;N;;;;;
+32FD;CIRCLED KATAKANA WE;So;0;L;<circle> 30F1;;;;N;;;;;
+32FE;CIRCLED KATAKANA WO;So;0;L;<circle> 30F2;;;;N;;;;;
+3300;SQUARE APAATO;So;0;L;<square> 30A2 30D1 30FC 30C8;;;;N;SQUARED APAATO;;;;
+3301;SQUARE ARUHUA;So;0;L;<square> 30A2 30EB 30D5 30A1;;;;N;SQUARED ARUHUA;;;;
+3302;SQUARE ANPEA;So;0;L;<square> 30A2 30F3 30DA 30A2;;;;N;SQUARED ANPEA;;;;
+3303;SQUARE AARU;So;0;L;<square> 30A2 30FC 30EB;;;;N;SQUARED AARU;;;;
+3304;SQUARE ININGU;So;0;L;<square> 30A4 30CB 30F3 30B0;;;;N;SQUARED ININGU;;;;
+3305;SQUARE INTI;So;0;L;<square> 30A4 30F3 30C1;;;;N;SQUARED INTI;;;;
+3306;SQUARE UON;So;0;L;<square> 30A6 30A9 30F3;;;;N;SQUARED UON;;;;
+3307;SQUARE ESUKUUDO;So;0;L;<square> 30A8 30B9 30AF 30FC 30C9;;;;N;SQUARED ESUKUUDO;;;;
+3308;SQUARE EEKAA;So;0;L;<square> 30A8 30FC 30AB 30FC;;;;N;SQUARED EEKAA;;;;
+3309;SQUARE ONSU;So;0;L;<square> 30AA 30F3 30B9;;;;N;SQUARED ONSU;;;;
+330A;SQUARE OOMU;So;0;L;<square> 30AA 30FC 30E0;;;;N;SQUARED OOMU;;;;
+330B;SQUARE KAIRI;So;0;L;<square> 30AB 30A4 30EA;;;;N;SQUARED KAIRI;;;;
+330C;SQUARE KARATTO;So;0;L;<square> 30AB 30E9 30C3 30C8;;;;N;SQUARED KARATTO;;;;
+330D;SQUARE KARORII;So;0;L;<square> 30AB 30ED 30EA 30FC;;;;N;SQUARED KARORII;;;;
+330E;SQUARE GARON;So;0;L;<square> 30AC 30ED 30F3;;;;N;SQUARED GARON;;;;
+330F;SQUARE GANMA;So;0;L;<square> 30AC 30F3 30DE;;;;N;SQUARED GANMA;;;;
+3310;SQUARE GIGA;So;0;L;<square> 30AE 30AC;;;;N;SQUARED GIGA;;;;
+3311;SQUARE GINII;So;0;L;<square> 30AE 30CB 30FC;;;;N;SQUARED GINII;;;;
+3312;SQUARE KYURII;So;0;L;<square> 30AD 30E5 30EA 30FC;;;;N;SQUARED KYURII;;;;
+3313;SQUARE GIRUDAA;So;0;L;<square> 30AE 30EB 30C0 30FC;;;;N;SQUARED GIRUDAA;;;;
+3314;SQUARE KIRO;So;0;L;<square> 30AD 30ED;;;;N;SQUARED KIRO;;;;
+3315;SQUARE KIROGURAMU;So;0;L;<square> 30AD 30ED 30B0 30E9 30E0;;;;N;SQUARED KIROGURAMU;;;;
+3316;SQUARE KIROMEETORU;So;0;L;<square> 30AD 30ED 30E1 30FC 30C8 30EB;;;;N;SQUARED KIROMEETORU;;;;
+3317;SQUARE KIROWATTO;So;0;L;<square> 30AD 30ED 30EF 30C3 30C8;;;;N;SQUARED KIROWATTO;;;;
+3318;SQUARE GURAMU;So;0;L;<square> 30B0 30E9 30E0;;;;N;SQUARED GURAMU;;;;
+3319;SQUARE GURAMUTON;So;0;L;<square> 30B0 30E9 30E0 30C8 30F3;;;;N;SQUARED GURAMUTON;;;;
+331A;SQUARE KURUZEIRO;So;0;L;<square> 30AF 30EB 30BC 30A4 30ED;;;;N;SQUARED KURUZEIRO;;;;
+331B;SQUARE KUROONE;So;0;L;<square> 30AF 30ED 30FC 30CD;;;;N;SQUARED KUROONE;;;;
+331C;SQUARE KEESU;So;0;L;<square> 30B1 30FC 30B9;;;;N;SQUARED KEESU;;;;
+331D;SQUARE KORUNA;So;0;L;<square> 30B3 30EB 30CA;;;;N;SQUARED KORUNA;;;;
+331E;SQUARE KOOPO;So;0;L;<square> 30B3 30FC 30DD;;;;N;SQUARED KOOPO;;;;
+331F;SQUARE SAIKURU;So;0;L;<square> 30B5 30A4 30AF 30EB;;;;N;SQUARED SAIKURU;;;;
+3320;SQUARE SANTIIMU;So;0;L;<square> 30B5 30F3 30C1 30FC 30E0;;;;N;SQUARED SANTIIMU;;;;
+3321;SQUARE SIRINGU;So;0;L;<square> 30B7 30EA 30F3 30B0;;;;N;SQUARED SIRINGU;;;;
+3322;SQUARE SENTI;So;0;L;<square> 30BB 30F3 30C1;;;;N;SQUARED SENTI;;;;
+3323;SQUARE SENTO;So;0;L;<square> 30BB 30F3 30C8;;;;N;SQUARED SENTO;;;;
+3324;SQUARE DAASU;So;0;L;<square> 30C0 30FC 30B9;;;;N;SQUARED DAASU;;;;
+3325;SQUARE DESI;So;0;L;<square> 30C7 30B7;;;;N;SQUARED DESI;;;;
+3326;SQUARE DORU;So;0;L;<square> 30C9 30EB;;;;N;SQUARED DORU;;;;
+3327;SQUARE TON;So;0;L;<square> 30C8 30F3;;;;N;SQUARED TON;;;;
+3328;SQUARE NANO;So;0;L;<square> 30CA 30CE;;;;N;SQUARED NANO;;;;
+3329;SQUARE NOTTO;So;0;L;<square> 30CE 30C3 30C8;;;;N;SQUARED NOTTO;;;;
+332A;SQUARE HAITU;So;0;L;<square> 30CF 30A4 30C4;;;;N;SQUARED HAITU;;;;
+332B;SQUARE PAASENTO;So;0;L;<square> 30D1 30FC 30BB 30F3 30C8;;;;N;SQUARED PAASENTO;;;;
+332C;SQUARE PAATU;So;0;L;<square> 30D1 30FC 30C4;;;;N;SQUARED PAATU;;;;
+332D;SQUARE BAARERU;So;0;L;<square> 30D0 30FC 30EC 30EB;;;;N;SQUARED BAARERU;;;;
+332E;SQUARE PIASUTORU;So;0;L;<square> 30D4 30A2 30B9 30C8 30EB;;;;N;SQUARED PIASUTORU;;;;
+332F;SQUARE PIKURU;So;0;L;<square> 30D4 30AF 30EB;;;;N;SQUARED PIKURU;;;;
+3330;SQUARE PIKO;So;0;L;<square> 30D4 30B3;;;;N;SQUARED PIKO;;;;
+3331;SQUARE BIRU;So;0;L;<square> 30D3 30EB;;;;N;SQUARED BIRU;;;;
+3332;SQUARE HUARADDO;So;0;L;<square> 30D5 30A1 30E9 30C3 30C9;;;;N;SQUARED HUARADDO;;;;
+3333;SQUARE HUIITO;So;0;L;<square> 30D5 30A3 30FC 30C8;;;;N;SQUARED HUIITO;;;;
+3334;SQUARE BUSSYERU;So;0;L;<square> 30D6 30C3 30B7 30A7 30EB;;;;N;SQUARED BUSSYERU;;;;
+3335;SQUARE HURAN;So;0;L;<square> 30D5 30E9 30F3;;;;N;SQUARED HURAN;;;;
+3336;SQUARE HEKUTAARU;So;0;L;<square> 30D8 30AF 30BF 30FC 30EB;;;;N;SQUARED HEKUTAARU;;;;
+3337;SQUARE PESO;So;0;L;<square> 30DA 30BD;;;;N;SQUARED PESO;;;;
+3338;SQUARE PENIHI;So;0;L;<square> 30DA 30CB 30D2;;;;N;SQUARED PENIHI;;;;
+3339;SQUARE HERUTU;So;0;L;<square> 30D8 30EB 30C4;;;;N;SQUARED HERUTU;;;;
+333A;SQUARE PENSU;So;0;L;<square> 30DA 30F3 30B9;;;;N;SQUARED PENSU;;;;
+333B;SQUARE PEEZI;So;0;L;<square> 30DA 30FC 30B8;;;;N;SQUARED PEEZI;;;;
+333C;SQUARE BEETA;So;0;L;<square> 30D9 30FC 30BF;;;;N;SQUARED BEETA;;;;
+333D;SQUARE POINTO;So;0;L;<square> 30DD 30A4 30F3 30C8;;;;N;SQUARED POINTO;;;;
+333E;SQUARE BORUTO;So;0;L;<square> 30DC 30EB 30C8;;;;N;SQUARED BORUTO;;;;
+333F;SQUARE HON;So;0;L;<square> 30DB 30F3;;;;N;SQUARED HON;;;;
+3340;SQUARE PONDO;So;0;L;<square> 30DD 30F3 30C9;;;;N;SQUARED PONDO;;;;
+3341;SQUARE HOORU;So;0;L;<square> 30DB 30FC 30EB;;;;N;SQUARED HOORU;;;;
+3342;SQUARE HOON;So;0;L;<square> 30DB 30FC 30F3;;;;N;SQUARED HOON;;;;
+3343;SQUARE MAIKURO;So;0;L;<square> 30DE 30A4 30AF 30ED;;;;N;SQUARED MAIKURO;;;;
+3344;SQUARE MAIRU;So;0;L;<square> 30DE 30A4 30EB;;;;N;SQUARED MAIRU;;;;
+3345;SQUARE MAHHA;So;0;L;<square> 30DE 30C3 30CF;;;;N;SQUARED MAHHA;;;;
+3346;SQUARE MARUKU;So;0;L;<square> 30DE 30EB 30AF;;;;N;SQUARED MARUKU;;;;
+3347;SQUARE MANSYON;So;0;L;<square> 30DE 30F3 30B7 30E7 30F3;;;;N;SQUARED MANSYON;;;;
+3348;SQUARE MIKURON;So;0;L;<square> 30DF 30AF 30ED 30F3;;;;N;SQUARED MIKURON;;;;
+3349;SQUARE MIRI;So;0;L;<square> 30DF 30EA;;;;N;SQUARED MIRI;;;;
+334A;SQUARE MIRIBAARU;So;0;L;<square> 30DF 30EA 30D0 30FC 30EB;;;;N;SQUARED MIRIBAARU;;;;
+334B;SQUARE MEGA;So;0;L;<square> 30E1 30AC;;;;N;SQUARED MEGA;;;;
+334C;SQUARE MEGATON;So;0;L;<square> 30E1 30AC 30C8 30F3;;;;N;SQUARED MEGATON;;;;
+334D;SQUARE MEETORU;So;0;L;<square> 30E1 30FC 30C8 30EB;;;;N;SQUARED MEETORU;;;;
+334E;SQUARE YAADO;So;0;L;<square> 30E4 30FC 30C9;;;;N;SQUARED YAADO;;;;
+334F;SQUARE YAARU;So;0;L;<square> 30E4 30FC 30EB;;;;N;SQUARED YAARU;;;;
+3350;SQUARE YUAN;So;0;L;<square> 30E6 30A2 30F3;;;;N;SQUARED YUAN;;;;
+3351;SQUARE RITTORU;So;0;L;<square> 30EA 30C3 30C8 30EB;;;;N;SQUARED RITTORU;;;;
+3352;SQUARE RIRA;So;0;L;<square> 30EA 30E9;;;;N;SQUARED RIRA;;;;
+3353;SQUARE RUPII;So;0;L;<square> 30EB 30D4 30FC;;;;N;SQUARED RUPII;;;;
+3354;SQUARE RUUBURU;So;0;L;<square> 30EB 30FC 30D6 30EB;;;;N;SQUARED RUUBURU;;;;
+3355;SQUARE REMU;So;0;L;<square> 30EC 30E0;;;;N;SQUARED REMU;;;;
+3356;SQUARE RENTOGEN;So;0;L;<square> 30EC 30F3 30C8 30B2 30F3;;;;N;SQUARED RENTOGEN;;;;
+3357;SQUARE WATTO;So;0;L;<square> 30EF 30C3 30C8;;;;N;SQUARED WATTO;;;;
+3358;IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR ZERO;So;0;L;<compat> 0030 70B9;;;;N;;;;;
+3359;IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR ONE;So;0;L;<compat> 0031 70B9;;;;N;;;;;
+335A;IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR TWO;So;0;L;<compat> 0032 70B9;;;;N;;;;;
+335B;IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR THREE;So;0;L;<compat> 0033 70B9;;;;N;;;;;
+335C;IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR FOUR;So;0;L;<compat> 0034 70B9;;;;N;;;;;
+335D;IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR FIVE;So;0;L;<compat> 0035 70B9;;;;N;;;;;
+335E;IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR SIX;So;0;L;<compat> 0036 70B9;;;;N;;;;;
+335F;IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR SEVEN;So;0;L;<compat> 0037 70B9;;;;N;;;;;
+3360;IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR EIGHT;So;0;L;<compat> 0038 70B9;;;;N;;;;;
+3361;IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR NINE;So;0;L;<compat> 0039 70B9;;;;N;;;;;
+3362;IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR TEN;So;0;L;<compat> 0031 0030 70B9;;;;N;;;;;
+3363;IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR ELEVEN;So;0;L;<compat> 0031 0031 70B9;;;;N;;;;;
+3364;IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR TWELVE;So;0;L;<compat> 0031 0032 70B9;;;;N;;;;;
+3365;IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR THIRTEEN;So;0;L;<compat> 0031 0033 70B9;;;;N;;;;;
+3366;IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR FOURTEEN;So;0;L;<compat> 0031 0034 70B9;;;;N;;;;;
+3367;IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR FIFTEEN;So;0;L;<compat> 0031 0035 70B9;;;;N;;;;;
+3368;IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR SIXTEEN;So;0;L;<compat> 0031 0036 70B9;;;;N;;;;;
+3369;IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR SEVENTEEN;So;0;L;<compat> 0031 0037 70B9;;;;N;;;;;
+336A;IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR EIGHTEEN;So;0;L;<compat> 0031 0038 70B9;;;;N;;;;;
+336B;IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR NINETEEN;So;0;L;<compat> 0031 0039 70B9;;;;N;;;;;
+336C;IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR TWENTY;So;0;L;<compat> 0032 0030 70B9;;;;N;;;;;
+336D;IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR TWENTY-ONE;So;0;L;<compat> 0032 0031 70B9;;;;N;;;;;
+336E;IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR TWENTY-TWO;So;0;L;<compat> 0032 0032 70B9;;;;N;;;;;
+336F;IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR TWENTY-THREE;So;0;L;<compat> 0032 0033 70B9;;;;N;;;;;
+3370;IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR TWENTY-FOUR;So;0;L;<compat> 0032 0034 70B9;;;;N;;;;;
+3371;SQUARE HPA;So;0;L;<square> 0068 0050 0061;;;;N;;;;;
+3372;SQUARE DA;So;0;L;<square> 0064 0061;;;;N;;;;;
+3373;SQUARE AU;So;0;L;<square> 0041 0055;;;;N;;;;;
+3374;SQUARE BAR;So;0;L;<square> 0062 0061 0072;;;;N;;;;;
+3375;SQUARE OV;So;0;L;<square> 006F 0056;;;;N;;;;;
+3376;SQUARE PC;So;0;L;<square> 0070 0063;;;;N;;;;;
+3377;SQUARE DM;So;0;ON;<square> 0064 006D;;;;N;;;;;
+3378;SQUARE DM SQUARED;So;0;ON;<square> 0064 006D 00B2;;;;N;;;;;
+3379;SQUARE DM CUBED;So;0;ON;<square> 0064 006D 00B3;;;;N;;;;;
+337A;SQUARE IU;So;0;ON;<square> 0049 0055;;;;N;;;;;
+337B;SQUARE ERA NAME HEISEI;So;0;L;<square> 5E73 6210;;;;N;SQUARED TWO IDEOGRAPHS ERA NAME HEISEI;;;;
+337C;SQUARE ERA NAME SYOUWA;So;0;L;<square> 662D 548C;;;;N;SQUARED TWO IDEOGRAPHS ERA NAME SYOUWA;;;;
+337D;SQUARE ERA NAME TAISYOU;So;0;L;<square> 5927 6B63;;;;N;SQUARED TWO IDEOGRAPHS ERA NAME TAISYOU;;;;
+337E;SQUARE ERA NAME MEIZI;So;0;L;<square> 660E 6CBB;;;;N;SQUARED TWO IDEOGRAPHS ERA NAME MEIZI;;;;
+337F;SQUARE CORPORATION;So;0;L;<square> 682A 5F0F 4F1A 793E;;;;N;SQUARED FOUR IDEOGRAPHS CORPORATION;;;;
+3380;SQUARE PA AMPS;So;0;L;<square> 0070 0041;;;;N;SQUARED PA AMPS;;;;
+3381;SQUARE NA;So;0;L;<square> 006E 0041;;;;N;SQUARED NA;;;;
+3382;SQUARE MU A;So;0;L;<square> 03BC 0041;;;;N;SQUARED MU A;;;;
+3383;SQUARE MA;So;0;L;<square> 006D 0041;;;;N;SQUARED MA;;;;
+3384;SQUARE KA;So;0;L;<square> 006B 0041;;;;N;SQUARED KA;;;;
+3385;SQUARE KB;So;0;L;<square> 004B 0042;;;;N;SQUARED KB;;;;
+3386;SQUARE MB;So;0;L;<square> 004D 0042;;;;N;SQUARED MB;;;;
+3387;SQUARE GB;So;0;L;<square> 0047 0042;;;;N;SQUARED GB;;;;
+3388;SQUARE CAL;So;0;L;<square> 0063 0061 006C;;;;N;SQUARED CAL;;;;
+3389;SQUARE KCAL;So;0;L;<square> 006B 0063 0061 006C;;;;N;SQUARED KCAL;;;;
+338A;SQUARE PF;So;0;L;<square> 0070 0046;;;;N;SQUARED PF;;;;
+338B;SQUARE NF;So;0;L;<square> 006E 0046;;;;N;SQUARED NF;;;;
+338C;SQUARE MU F;So;0;L;<square> 03BC 0046;;;;N;SQUARED MU F;;;;
+338D;SQUARE MU G;So;0;L;<square> 03BC 0067;;;;N;SQUARED MU G;;;;
+338E;SQUARE MG;So;0;L;<square> 006D 0067;;;;N;SQUARED MG;;;;
+338F;SQUARE KG;So;0;L;<square> 006B 0067;;;;N;SQUARED KG;;;;
+3390;SQUARE HZ;So;0;L;<square> 0048 007A;;;;N;SQUARED HZ;;;;
+3391;SQUARE KHZ;So;0;L;<square> 006B 0048 007A;;;;N;SQUARED KHZ;;;;
+3392;SQUARE MHZ;So;0;L;<square> 004D 0048 007A;;;;N;SQUARED MHZ;;;;
+3393;SQUARE GHZ;So;0;L;<square> 0047 0048 007A;;;;N;SQUARED GHZ;;;;
+3394;SQUARE THZ;So;0;L;<square> 0054 0048 007A;;;;N;SQUARED THZ;;;;
+3395;SQUARE MU L;So;0;L;<square> 03BC 2113;;;;N;SQUARED MU L;;;;
+3396;SQUARE ML;So;0;L;<square> 006D 2113;;;;N;SQUARED ML;;;;
+3397;SQUARE DL;So;0;L;<square> 0064 2113;;;;N;SQUARED DL;;;;
+3398;SQUARE KL;So;0;L;<square> 006B 2113;;;;N;SQUARED KL;;;;
+3399;SQUARE FM;So;0;L;<square> 0066 006D;;;;N;SQUARED FM;;;;
+339A;SQUARE NM;So;0;L;<square> 006E 006D;;;;N;SQUARED NM;;;;
+339B;SQUARE MU M;So;0;L;<square> 03BC 006D;;;;N;SQUARED MU M;;;;
+339C;SQUARE MM;So;0;L;<square> 006D 006D;;;;N;SQUARED MM;;;;
+339D;SQUARE CM;So;0;L;<square> 0063 006D;;;;N;SQUARED CM;;;;
+339E;SQUARE KM;So;0;L;<square> 006B 006D;;;;N;SQUARED KM;;;;
+339F;SQUARE MM SQUARED;So;0;L;<square> 006D 006D 00B2;;;;N;SQUARED MM SQUARED;;;;
+33A0;SQUARE CM SQUARED;So;0;L;<square> 0063 006D 00B2;;;;N;SQUARED CM SQUARED;;;;
+33A1;SQUARE M SQUARED;So;0;L;<square> 006D 00B2;;;;N;SQUARED M SQUARED;;;;
+33A2;SQUARE KM SQUARED;So;0;L;<square> 006B 006D 00B2;;;;N;SQUARED KM SQUARED;;;;
+33A3;SQUARE MM CUBED;So;0;L;<square> 006D 006D 00B3;;;;N;SQUARED MM CUBED;;;;
+33A4;SQUARE CM CUBED;So;0;L;<square> 0063 006D 00B3;;;;N;SQUARED CM CUBED;;;;
+33A5;SQUARE M CUBED;So;0;L;<square> 006D 00B3;;;;N;SQUARED M CUBED;;;;
+33A6;SQUARE KM CUBED;So;0;L;<square> 006B 006D 00B3;;;;N;SQUARED KM CUBED;;;;
+33A7;SQUARE M OVER S;So;0;L;<square> 006D 2215 0073;;;;N;SQUARED M OVER S;;;;
+33A8;SQUARE M OVER S SQUARED;So;0;L;<square> 006D 2215 0073 00B2;;;;N;SQUARED M OVER S SQUARED;;;;
+33A9;SQUARE PA;So;0;L;<square> 0050 0061;;;;N;SQUARED PA;;;;
+33AA;SQUARE KPA;So;0;L;<square> 006B 0050 0061;;;;N;SQUARED KPA;;;;
+33AB;SQUARE MPA;So;0;L;<square> 004D 0050 0061;;;;N;SQUARED MPA;;;;
+33AC;SQUARE GPA;So;0;L;<square> 0047 0050 0061;;;;N;SQUARED GPA;;;;
+33AD;SQUARE RAD;So;0;L;<square> 0072 0061 0064;;;;N;SQUARED RAD;;;;
+33AE;SQUARE RAD OVER S;So;0;L;<square> 0072 0061 0064 2215 0073;;;;N;SQUARED RAD OVER S;;;;
+33AF;SQUARE RAD OVER S SQUARED;So;0;L;<square> 0072 0061 0064 2215 0073 00B2;;;;N;SQUARED RAD OVER S SQUARED;;;;
+33B0;SQUARE PS;So;0;L;<square> 0070 0073;;;;N;SQUARED PS;;;;
+33B1;SQUARE NS;So;0;L;<square> 006E 0073;;;;N;SQUARED NS;;;;
+33B2;SQUARE MU S;So;0;L;<square> 03BC 0073;;;;N;SQUARED MU S;;;;
+33B3;SQUARE MS;So;0;L;<square> 006D 0073;;;;N;SQUARED MS;;;;
+33B4;SQUARE PV;So;0;L;<square> 0070 0056;;;;N;SQUARED PV;;;;
+33B5;SQUARE NV;So;0;L;<square> 006E 0056;;;;N;SQUARED NV;;;;
+33B6;SQUARE MU V;So;0;L;<square> 03BC 0056;;;;N;SQUARED MU V;;;;
+33B7;SQUARE MV;So;0;L;<square> 006D 0056;;;;N;SQUARED MV;;;;
+33B8;SQUARE KV;So;0;L;<square> 006B 0056;;;;N;SQUARED KV;;;;
+33B9;SQUARE MV MEGA;So;0;L;<square> 004D 0056;;;;N;SQUARED MV MEGA;;;;
+33BA;SQUARE PW;So;0;L;<square> 0070 0057;;;;N;SQUARED PW;;;;
+33BB;SQUARE NW;So;0;L;<square> 006E 0057;;;;N;SQUARED NW;;;;
+33BC;SQUARE MU W;So;0;L;<square> 03BC 0057;;;;N;SQUARED MU W;;;;
+33BD;SQUARE MW;So;0;L;<square> 006D 0057;;;;N;SQUARED MW;;;;
+33BE;SQUARE KW;So;0;L;<square> 006B 0057;;;;N;SQUARED KW;;;;
+33BF;SQUARE MW MEGA;So;0;L;<square> 004D 0057;;;;N;SQUARED MW MEGA;;;;
+33C0;SQUARE K OHM;So;0;L;<square> 006B 03A9;;;;N;SQUARED K OHM;;;;
+33C1;SQUARE M OHM;So;0;L;<square> 004D 03A9;;;;N;SQUARED M OHM;;;;
+33C2;SQUARE AM;So;0;L;<square> 0061 002E 006D 002E;;;;N;SQUARED AM;;;;
+33C3;SQUARE BQ;So;0;L;<square> 0042 0071;;;;N;SQUARED BQ;;;;
+33C4;SQUARE CC;So;0;L;<square> 0063 0063;;;;N;SQUARED CC;;;;
+33C5;SQUARE CD;So;0;L;<square> 0063 0064;;;;N;SQUARED CD;;;;
+33C6;SQUARE C OVER KG;So;0;L;<square> 0043 2215 006B 0067;;;;N;SQUARED C OVER KG;;;;
+33C7;SQUARE CO;So;0;L;<square> 0043 006F 002E;;;;N;SQUARED CO;;;;
+33C8;SQUARE DB;So;0;L;<square> 0064 0042;;;;N;SQUARED DB;;;;
+33C9;SQUARE GY;So;0;L;<square> 0047 0079;;;;N;SQUARED GY;;;;
+33CA;SQUARE HA;So;0;L;<square> 0068 0061;;;;N;SQUARED HA;;;;
+33CB;SQUARE HP;So;0;L;<square> 0048 0050;;;;N;SQUARED HP;;;;
+33CC;SQUARE IN;So;0;L;<square> 0069 006E;;;;N;SQUARED IN;;;;
+33CD;SQUARE KK;So;0;L;<square> 004B 004B;;;;N;SQUARED KK;;;;
+33CE;SQUARE KM CAPITAL;So;0;L;<square> 004B 004D;;;;N;SQUARED KM CAPITAL;;;;
+33CF;SQUARE KT;So;0;L;<square> 006B 0074;;;;N;SQUARED KT;;;;
+33D0;SQUARE LM;So;0;L;<square> 006C 006D;;;;N;SQUARED LM;;;;
+33D1;SQUARE LN;So;0;L;<square> 006C 006E;;;;N;SQUARED LN;;;;
+33D2;SQUARE LOG;So;0;L;<square> 006C 006F 0067;;;;N;SQUARED LOG;;;;
+33D3;SQUARE LX;So;0;L;<square> 006C 0078;;;;N;SQUARED LX;;;;
+33D4;SQUARE MB SMALL;So;0;L;<square> 006D 0062;;;;N;SQUARED MB SMALL;;;;
+33D5;SQUARE MIL;So;0;L;<square> 006D 0069 006C;;;;N;SQUARED MIL;;;;
+33D6;SQUARE MOL;So;0;L;<square> 006D 006F 006C;;;;N;SQUARED MOL;;;;
+33D7;SQUARE PH;So;0;L;<square> 0050 0048;;;;N;SQUARED PH;;;;
+33D8;SQUARE PM;So;0;L;<square> 0070 002E 006D 002E;;;;N;SQUARED PM;;;;
+33D9;SQUARE PPM;So;0;L;<square> 0050 0050 004D;;;;N;SQUARED PPM;;;;
+33DA;SQUARE PR;So;0;L;<square> 0050 0052;;;;N;SQUARED PR;;;;
+33DB;SQUARE SR;So;0;L;<square> 0073 0072;;;;N;SQUARED SR;;;;
+33DC;SQUARE SV;So;0;L;<square> 0053 0076;;;;N;SQUARED SV;;;;
+33DD;SQUARE WB;So;0;L;<square> 0057 0062;;;;N;SQUARED WB;;;;
+33DE;SQUARE V OVER M;So;0;ON;<square> 0056 2215 006D;;;;N;;;;;
+33DF;SQUARE A OVER M;So;0;ON;<square> 0041 2215 006D;;;;N;;;;;
+33E0;IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY ONE;So;0;L;<compat> 0031 65E5;;;;N;;;;;
+33E1;IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY TWO;So;0;L;<compat> 0032 65E5;;;;N;;;;;
+33E2;IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY THREE;So;0;L;<compat> 0033 65E5;;;;N;;;;;
+33E3;IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY FOUR;So;0;L;<compat> 0034 65E5;;;;N;;;;;
+33E4;IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY FIVE;So;0;L;<compat> 0035 65E5;;;;N;;;;;
+33E5;IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY SIX;So;0;L;<compat> 0036 65E5;;;;N;;;;;
+33E6;IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY SEVEN;So;0;L;<compat> 0037 65E5;;;;N;;;;;
+33E7;IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY EIGHT;So;0;L;<compat> 0038 65E5;;;;N;;;;;
+33E8;IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY NINE;So;0;L;<compat> 0039 65E5;;;;N;;;;;
+33E9;IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY TEN;So;0;L;<compat> 0031 0030 65E5;;;;N;;;;;
+33EA;IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY ELEVEN;So;0;L;<compat> 0031 0031 65E5;;;;N;;;;;
+33EB;IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY TWELVE;So;0;L;<compat> 0031 0032 65E5;;;;N;;;;;
+33EC;IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY THIRTEEN;So;0;L;<compat> 0031 0033 65E5;;;;N;;;;;
+33ED;IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY FOURTEEN;So;0;L;<compat> 0031 0034 65E5;;;;N;;;;;
+33EE;IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY FIFTEEN;So;0;L;<compat> 0031 0035 65E5;;;;N;;;;;
+33EF;IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY SIXTEEN;So;0;L;<compat> 0031 0036 65E5;;;;N;;;;;
+33F0;IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY SEVENTEEN;So;0;L;<compat> 0031 0037 65E5;;;;N;;;;;
+33F1;IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY EIGHTEEN;So;0;L;<compat> 0031 0038 65E5;;;;N;;;;;
+33F2;IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY NINETEEN;So;0;L;<compat> 0031 0039 65E5;;;;N;;;;;
+33F3;IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY TWENTY;So;0;L;<compat> 0032 0030 65E5;;;;N;;;;;
+33F4;IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY TWENTY-ONE;So;0;L;<compat> 0032 0031 65E5;;;;N;;;;;
+33F5;IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY TWENTY-TWO;So;0;L;<compat> 0032 0032 65E5;;;;N;;;;;
+33F6;IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY TWENTY-THREE;So;0;L;<compat> 0032 0033 65E5;;;;N;;;;;
+33F7;IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY TWENTY-FOUR;So;0;L;<compat> 0032 0034 65E5;;;;N;;;;;
+33F8;IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY TWENTY-FIVE;So;0;L;<compat> 0032 0035 65E5;;;;N;;;;;
+33F9;IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY TWENTY-SIX;So;0;L;<compat> 0032 0036 65E5;;;;N;;;;;
+33FA;IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY TWENTY-SEVEN;So;0;L;<compat> 0032 0037 65E5;;;;N;;;;;
+33FB;IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY TWENTY-EIGHT;So;0;L;<compat> 0032 0038 65E5;;;;N;;;;;
+33FC;IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY TWENTY-NINE;So;0;L;<compat> 0032 0039 65E5;;;;N;;;;;
+33FD;IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY THIRTY;So;0;L;<compat> 0033 0030 65E5;;;;N;;;;;
+33FE;IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY THIRTY-ONE;So;0;L;<compat> 0033 0031 65E5;;;;N;;;;;
+33FF;SQUARE GAL;So;0;ON;<square> 0067 0061 006C;;;;N;;;;;
+3400;<CJK Ideograph Extension A, First>;Lo;0;L;;;;;N;;;;;
+4DB5;<CJK Ideograph Extension A, Last>;Lo;0;L;;;;;N;;;;;
+4DC0;HEXAGRAM FOR THE CREATIVE HEAVEN;So;0;ON;;;;;N;;;;;
+4DC1;HEXAGRAM FOR THE RECEPTIVE EARTH;So;0;ON;;;;;N;;;;;
+4DC2;HEXAGRAM FOR DIFFICULTY AT THE BEGINNING;So;0;ON;;;;;N;;;;;
+4DC3;HEXAGRAM FOR YOUTHFUL FOLLY;So;0;ON;;;;;N;;;;;
+4DC4;HEXAGRAM FOR WAITING;So;0;ON;;;;;N;;;;;
+4DC5;HEXAGRAM FOR CONFLICT;So;0;ON;;;;;N;;;;;
+4DC6;HEXAGRAM FOR THE ARMY;So;0;ON;;;;;N;;;;;
+4DC7;HEXAGRAM FOR HOLDING TOGETHER;So;0;ON;;;;;N;;;;;
+4DC8;HEXAGRAM FOR SMALL TAMING;So;0;ON;;;;;N;;;;;
+4DC9;HEXAGRAM FOR TREADING;So;0;ON;;;;;N;;;;;
+4DCA;HEXAGRAM FOR PEACE;So;0;ON;;;;;N;;;;;
+4DCB;HEXAGRAM FOR STANDSTILL;So;0;ON;;;;;N;;;;;
+4DCC;HEXAGRAM FOR FELLOWSHIP;So;0;ON;;;;;N;;;;;
+4DCD;HEXAGRAM FOR GREAT POSSESSION;So;0;ON;;;;;N;;;;;
+4DCE;HEXAGRAM FOR MODESTY;So;0;ON;;;;;N;;;;;
+4DCF;HEXAGRAM FOR ENTHUSIASM;So;0;ON;;;;;N;;;;;
+4DD0;HEXAGRAM FOR FOLLOWING;So;0;ON;;;;;N;;;;;
+4DD1;HEXAGRAM FOR WORK ON THE DECAYED;So;0;ON;;;;;N;;;;;
+4DD2;HEXAGRAM FOR APPROACH;So;0;ON;;;;;N;;;;;
+4DD3;HEXAGRAM FOR CONTEMPLATION;So;0;ON;;;;;N;;;;;
+4DD4;HEXAGRAM FOR BITING THROUGH;So;0;ON;;;;;N;;;;;
+4DD5;HEXAGRAM FOR GRACE;So;0;ON;;;;;N;;;;;
+4DD6;HEXAGRAM FOR SPLITTING APART;So;0;ON;;;;;N;;;;;
+4DD7;HEXAGRAM FOR RETURN;So;0;ON;;;;;N;;;;;
+4DD8;HEXAGRAM FOR INNOCENCE;So;0;ON;;;;;N;;;;;
+4DD9;HEXAGRAM FOR GREAT TAMING;So;0;ON;;;;;N;;;;;
+4DDA;HEXAGRAM FOR MOUTH CORNERS;So;0;ON;;;;;N;;;;;
+4DDB;HEXAGRAM FOR GREAT PREPONDERANCE;So;0;ON;;;;;N;;;;;
+4DDC;HEXAGRAM FOR THE ABYSMAL WATER;So;0;ON;;;;;N;;;;;
+4DDD;HEXAGRAM FOR THE CLINGING FIRE;So;0;ON;;;;;N;;;;;
+4DDE;HEXAGRAM FOR INFLUENCE;So;0;ON;;;;;N;;;;;
+4DDF;HEXAGRAM FOR DURATION;So;0;ON;;;;;N;;;;;
+4DE0;HEXAGRAM FOR RETREAT;So;0;ON;;;;;N;;;;;
+4DE1;HEXAGRAM FOR GREAT POWER;So;0;ON;;;;;N;;;;;
+4DE2;HEXAGRAM FOR PROGRESS;So;0;ON;;;;;N;;;;;
+4DE3;HEXAGRAM FOR DARKENING OF THE LIGHT;So;0;ON;;;;;N;;;;;
+4DE4;HEXAGRAM FOR THE FAMILY;So;0;ON;;;;;N;;;;;
+4DE5;HEXAGRAM FOR OPPOSITION;So;0;ON;;;;;N;;;;;
+4DE6;HEXAGRAM FOR OBSTRUCTION;So;0;ON;;;;;N;;;;;
+4DE7;HEXAGRAM FOR DELIVERANCE;So;0;ON;;;;;N;;;;;
+4DE8;HEXAGRAM FOR DECREASE;So;0;ON;;;;;N;;;;;
+4DE9;HEXAGRAM FOR INCREASE;So;0;ON;;;;;N;;;;;
+4DEA;HEXAGRAM FOR BREAKTHROUGH;So;0;ON;;;;;N;;;;;
+4DEB;HEXAGRAM FOR COMING TO MEET;So;0;ON;;;;;N;;;;;
+4DEC;HEXAGRAM FOR GATHERING TOGETHER;So;0;ON;;;;;N;;;;;
+4DED;HEXAGRAM FOR PUSHING UPWARD;So;0;ON;;;;;N;;;;;
+4DEE;HEXAGRAM FOR OPPRESSION;So;0;ON;;;;;N;;;;;
+4DEF;HEXAGRAM FOR THE WELL;So;0;ON;;;;;N;;;;;
+4DF0;HEXAGRAM FOR REVOLUTION;So;0;ON;;;;;N;;;;;
+4DF1;HEXAGRAM FOR THE CAULDRON;So;0;ON;;;;;N;;;;;
+4DF2;HEXAGRAM FOR THE AROUSING THUNDER;So;0;ON;;;;;N;;;;;
+4DF3;HEXAGRAM FOR THE KEEPING STILL MOUNTAIN;So;0;ON;;;;;N;;;;;
+4DF4;HEXAGRAM FOR DEVELOPMENT;So;0;ON;;;;;N;;;;;
+4DF5;HEXAGRAM FOR THE MARRYING MAIDEN;So;0;ON;;;;;N;;;;;
+4DF6;HEXAGRAM FOR ABUNDANCE;So;0;ON;;;;;N;;;;;
+4DF7;HEXAGRAM FOR THE WANDERER;So;0;ON;;;;;N;;;;;
+4DF8;HEXAGRAM FOR THE GENTLE WIND;So;0;ON;;;;;N;;;;;
+4DF9;HEXAGRAM FOR THE JOYOUS LAKE;So;0;ON;;;;;N;;;;;
+4DFA;HEXAGRAM FOR DISPERSION;So;0;ON;;;;;N;;;;;
+4DFB;HEXAGRAM FOR LIMITATION;So;0;ON;;;;;N;;;;;
+4DFC;HEXAGRAM FOR INNER TRUTH;So;0;ON;;;;;N;;;;;
+4DFD;HEXAGRAM FOR SMALL PREPONDERANCE;So;0;ON;;;;;N;;;;;
+4DFE;HEXAGRAM FOR AFTER COMPLETION;So;0;ON;;;;;N;;;;;
+4DFF;HEXAGRAM FOR BEFORE COMPLETION;So;0;ON;;;;;N;;;;;
+4E00;<CJK Ideograph, First>;Lo;0;L;;;;;N;;;;;
+9FBB;<CJK Ideograph, Last>;Lo;0;L;;;;;N;;;;;
+A000;YI SYLLABLE IT;Lo;0;L;;;;;N;;;;;
+A001;YI SYLLABLE IX;Lo;0;L;;;;;N;;;;;
+A002;YI SYLLABLE I;Lo;0;L;;;;;N;;;;;
+A003;YI SYLLABLE IP;Lo;0;L;;;;;N;;;;;
+A004;YI SYLLABLE IET;Lo;0;L;;;;;N;;;;;
+A005;YI SYLLABLE IEX;Lo;0;L;;;;;N;;;;;
+A006;YI SYLLABLE IE;Lo;0;L;;;;;N;;;;;
+A007;YI SYLLABLE IEP;Lo;0;L;;;;;N;;;;;
+A008;YI SYLLABLE AT;Lo;0;L;;;;;N;;;;;
+A009;YI SYLLABLE AX;Lo;0;L;;;;;N;;;;;
+A00A;YI SYLLABLE A;Lo;0;L;;;;;N;;;;;
+A00B;YI SYLLABLE AP;Lo;0;L;;;;;N;;;;;
+A00C;YI SYLLABLE UOX;Lo;0;L;;;;;N;;;;;
+A00D;YI SYLLABLE UO;Lo;0;L;;;;;N;;;;;
+A00E;YI SYLLABLE UOP;Lo;0;L;;;;;N;;;;;
+A00F;YI SYLLABLE OT;Lo;0;L;;;;;N;;;;;
+A010;YI SYLLABLE OX;Lo;0;L;;;;;N;;;;;
+A011;YI SYLLABLE O;Lo;0;L;;;;;N;;;;;
+A012;YI SYLLABLE OP;Lo;0;L;;;;;N;;;;;
+A013;YI SYLLABLE EX;Lo;0;L;;;;;N;;;;;
+A014;YI SYLLABLE E;Lo;0;L;;;;;N;;;;;
+A015;YI SYLLABLE WU;Lm;0;L;;;;;N;;;;;
+A016;YI SYLLABLE BIT;Lo;0;L;;;;;N;;;;;
+A017;YI SYLLABLE BIX;Lo;0;L;;;;;N;;;;;
+A018;YI SYLLABLE BI;Lo;0;L;;;;;N;;;;;
+A019;YI SYLLABLE BIP;Lo;0;L;;;;;N;;;;;
+A01A;YI SYLLABLE BIET;Lo;0;L;;;;;N;;;;;
+A01B;YI SYLLABLE BIEX;Lo;0;L;;;;;N;;;;;
+A01C;YI SYLLABLE BIE;Lo;0;L;;;;;N;;;;;
+A01D;YI SYLLABLE BIEP;Lo;0;L;;;;;N;;;;;
+A01E;YI SYLLABLE BAT;Lo;0;L;;;;;N;;;;;
+A01F;YI SYLLABLE BAX;Lo;0;L;;;;;N;;;;;
+A020;YI SYLLABLE BA;Lo;0;L;;;;;N;;;;;
+A021;YI SYLLABLE BAP;Lo;0;L;;;;;N;;;;;
+A022;YI SYLLABLE BUOX;Lo;0;L;;;;;N;;;;;
+A023;YI SYLLABLE BUO;Lo;0;L;;;;;N;;;;;
+A024;YI SYLLABLE BUOP;Lo;0;L;;;;;N;;;;;
+A025;YI SYLLABLE BOT;Lo;0;L;;;;;N;;;;;
+A026;YI SYLLABLE BOX;Lo;0;L;;;;;N;;;;;
+A027;YI SYLLABLE BO;Lo;0;L;;;;;N;;;;;
+A028;YI SYLLABLE BOP;Lo;0;L;;;;;N;;;;;
+A029;YI SYLLABLE BEX;Lo;0;L;;;;;N;;;;;
+A02A;YI SYLLABLE BE;Lo;0;L;;;;;N;;;;;
+A02B;YI SYLLABLE BEP;Lo;0;L;;;;;N;;;;;
+A02C;YI SYLLABLE BUT;Lo;0;L;;;;;N;;;;;
+A02D;YI SYLLABLE BUX;Lo;0;L;;;;;N;;;;;
+A02E;YI SYLLABLE BU;Lo;0;L;;;;;N;;;;;
+A02F;YI SYLLABLE BUP;Lo;0;L;;;;;N;;;;;
+A030;YI SYLLABLE BURX;Lo;0;L;;;;;N;;;;;
+A031;YI SYLLABLE BUR;Lo;0;L;;;;;N;;;;;
+A032;YI SYLLABLE BYT;Lo;0;L;;;;;N;;;;;
+A033;YI SYLLABLE BYX;Lo;0;L;;;;;N;;;;;
+A034;YI SYLLABLE BY;Lo;0;L;;;;;N;;;;;
+A035;YI SYLLABLE BYP;Lo;0;L;;;;;N;;;;;
+A036;YI SYLLABLE BYRX;Lo;0;L;;;;;N;;;;;
+A037;YI SYLLABLE BYR;Lo;0;L;;;;;N;;;;;
+A038;YI SYLLABLE PIT;Lo;0;L;;;;;N;;;;;
+A039;YI SYLLABLE PIX;Lo;0;L;;;;;N;;;;;
+A03A;YI SYLLABLE PI;Lo;0;L;;;;;N;;;;;
+A03B;YI SYLLABLE PIP;Lo;0;L;;;;;N;;;;;
+A03C;YI SYLLABLE PIEX;Lo;0;L;;;;;N;;;;;
+A03D;YI SYLLABLE PIE;Lo;0;L;;;;;N;;;;;
+A03E;YI SYLLABLE PIEP;Lo;0;L;;;;;N;;;;;
+A03F;YI SYLLABLE PAT;Lo;0;L;;;;;N;;;;;
+A040;YI SYLLABLE PAX;Lo;0;L;;;;;N;;;;;
+A041;YI SYLLABLE PA;Lo;0;L;;;;;N;;;;;
+A042;YI SYLLABLE PAP;Lo;0;L;;;;;N;;;;;
+A043;YI SYLLABLE PUOX;Lo;0;L;;;;;N;;;;;
+A044;YI SYLLABLE PUO;Lo;0;L;;;;;N;;;;;
+A045;YI SYLLABLE PUOP;Lo;0;L;;;;;N;;;;;
+A046;YI SYLLABLE POT;Lo;0;L;;;;;N;;;;;
+A047;YI SYLLABLE POX;Lo;0;L;;;;;N;;;;;
+A048;YI SYLLABLE PO;Lo;0;L;;;;;N;;;;;
+A049;YI SYLLABLE POP;Lo;0;L;;;;;N;;;;;
+A04A;YI SYLLABLE PUT;Lo;0;L;;;;;N;;;;;
+A04B;YI SYLLABLE PUX;Lo;0;L;;;;;N;;;;;
+A04C;YI SYLLABLE PU;Lo;0;L;;;;;N;;;;;
+A04D;YI SYLLABLE PUP;Lo;0;L;;;;;N;;;;;
+A04E;YI SYLLABLE PURX;Lo;0;L;;;;;N;;;;;
+A04F;YI SYLLABLE PUR;Lo;0;L;;;;;N;;;;;
+A050;YI SYLLABLE PYT;Lo;0;L;;;;;N;;;;;
+A051;YI SYLLABLE PYX;Lo;0;L;;;;;N;;;;;
+A052;YI SYLLABLE PY;Lo;0;L;;;;;N;;;;;
+A053;YI SYLLABLE PYP;Lo;0;L;;;;;N;;;;;
+A054;YI SYLLABLE PYRX;Lo;0;L;;;;;N;;;;;
+A055;YI SYLLABLE PYR;Lo;0;L;;;;;N;;;;;
+A056;YI SYLLABLE BBIT;Lo;0;L;;;;;N;;;;;
+A057;YI SYLLABLE BBIX;Lo;0;L;;;;;N;;;;;
+A058;YI SYLLABLE BBI;Lo;0;L;;;;;N;;;;;
+A059;YI SYLLABLE BBIP;Lo;0;L;;;;;N;;;;;
+A05A;YI SYLLABLE BBIET;Lo;0;L;;;;;N;;;;;
+A05B;YI SYLLABLE BBIEX;Lo;0;L;;;;;N;;;;;
+A05C;YI SYLLABLE BBIE;Lo;0;L;;;;;N;;;;;
+A05D;YI SYLLABLE BBIEP;Lo;0;L;;;;;N;;;;;
+A05E;YI SYLLABLE BBAT;Lo;0;L;;;;;N;;;;;
+A05F;YI SYLLABLE BBAX;Lo;0;L;;;;;N;;;;;
+A060;YI SYLLABLE BBA;Lo;0;L;;;;;N;;;;;
+A061;YI SYLLABLE BBAP;Lo;0;L;;;;;N;;;;;
+A062;YI SYLLABLE BBUOX;Lo;0;L;;;;;N;;;;;
+A063;YI SYLLABLE BBUO;Lo;0;L;;;;;N;;;;;
+A064;YI SYLLABLE BBUOP;Lo;0;L;;;;;N;;;;;
+A065;YI SYLLABLE BBOT;Lo;0;L;;;;;N;;;;;
+A066;YI SYLLABLE BBOX;Lo;0;L;;;;;N;;;;;
+A067;YI SYLLABLE BBO;Lo;0;L;;;;;N;;;;;
+A068;YI SYLLABLE BBOP;Lo;0;L;;;;;N;;;;;
+A069;YI SYLLABLE BBEX;Lo;0;L;;;;;N;;;;;
+A06A;YI SYLLABLE BBE;Lo;0;L;;;;;N;;;;;
+A06B;YI SYLLABLE BBEP;Lo;0;L;;;;;N;;;;;
+A06C;YI SYLLABLE BBUT;Lo;0;L;;;;;N;;;;;
+A06D;YI SYLLABLE BBUX;Lo;0;L;;;;;N;;;;;
+A06E;YI SYLLABLE BBU;Lo;0;L;;;;;N;;;;;
+A06F;YI SYLLABLE BBUP;Lo;0;L;;;;;N;;;;;
+A070;YI SYLLABLE BBURX;Lo;0;L;;;;;N;;;;;
+A071;YI SYLLABLE BBUR;Lo;0;L;;;;;N;;;;;
+A072;YI SYLLABLE BBYT;Lo;0;L;;;;;N;;;;;
+A073;YI SYLLABLE BBYX;Lo;0;L;;;;;N;;;;;
+A074;YI SYLLABLE BBY;Lo;0;L;;;;;N;;;;;
+A075;YI SYLLABLE BBYP;Lo;0;L;;;;;N;;;;;
+A076;YI SYLLABLE NBIT;Lo;0;L;;;;;N;;;;;
+A077;YI SYLLABLE NBIX;Lo;0;L;;;;;N;;;;;
+A078;YI SYLLABLE NBI;Lo;0;L;;;;;N;;;;;
+A079;YI SYLLABLE NBIP;Lo;0;L;;;;;N;;;;;
+A07A;YI SYLLABLE NBIEX;Lo;0;L;;;;;N;;;;;
+A07B;YI SYLLABLE NBIE;Lo;0;L;;;;;N;;;;;
+A07C;YI SYLLABLE NBIEP;Lo;0;L;;;;;N;;;;;
+A07D;YI SYLLABLE NBAT;Lo;0;L;;;;;N;;;;;
+A07E;YI SYLLABLE NBAX;Lo;0;L;;;;;N;;;;;
+A07F;YI SYLLABLE NBA;Lo;0;L;;;;;N;;;;;
+A080;YI SYLLABLE NBAP;Lo;0;L;;;;;N;;;;;
+A081;YI SYLLABLE NBOT;Lo;0;L;;;;;N;;;;;
+A082;YI SYLLABLE NBOX;Lo;0;L;;;;;N;;;;;
+A083;YI SYLLABLE NBO;Lo;0;L;;;;;N;;;;;
+A084;YI SYLLABLE NBOP;Lo;0;L;;;;;N;;;;;
+A085;YI SYLLABLE NBUT;Lo;0;L;;;;;N;;;;;
+A086;YI SYLLABLE NBUX;Lo;0;L;;;;;N;;;;;
+A087;YI SYLLABLE NBU;Lo;0;L;;;;;N;;;;;
+A088;YI SYLLABLE NBUP;Lo;0;L;;;;;N;;;;;
+A089;YI SYLLABLE NBURX;Lo;0;L;;;;;N;;;;;
+A08A;YI SYLLABLE NBUR;Lo;0;L;;;;;N;;;;;
+A08B;YI SYLLABLE NBYT;Lo;0;L;;;;;N;;;;;
+A08C;YI SYLLABLE NBYX;Lo;0;L;;;;;N;;;;;
+A08D;YI SYLLABLE NBY;Lo;0;L;;;;;N;;;;;
+A08E;YI SYLLABLE NBYP;Lo;0;L;;;;;N;;;;;
+A08F;YI SYLLABLE NBYRX;Lo;0;L;;;;;N;;;;;
+A090;YI SYLLABLE NBYR;Lo;0;L;;;;;N;;;;;
+A091;YI SYLLABLE HMIT;Lo;0;L;;;;;N;;;;;
+A092;YI SYLLABLE HMIX;Lo;0;L;;;;;N;;;;;
+A093;YI SYLLABLE HMI;Lo;0;L;;;;;N;;;;;
+A094;YI SYLLABLE HMIP;Lo;0;L;;;;;N;;;;;
+A095;YI SYLLABLE HMIEX;Lo;0;L;;;;;N;;;;;
+A096;YI SYLLABLE HMIE;Lo;0;L;;;;;N;;;;;
+A097;YI SYLLABLE HMIEP;Lo;0;L;;;;;N;;;;;
+A098;YI SYLLABLE HMAT;Lo;0;L;;;;;N;;;;;
+A099;YI SYLLABLE HMAX;Lo;0;L;;;;;N;;;;;
+A09A;YI SYLLABLE HMA;Lo;0;L;;;;;N;;;;;
+A09B;YI SYLLABLE HMAP;Lo;0;L;;;;;N;;;;;
+A09C;YI SYLLABLE HMUOX;Lo;0;L;;;;;N;;;;;
+A09D;YI SYLLABLE HMUO;Lo;0;L;;;;;N;;;;;
+A09E;YI SYLLABLE HMUOP;Lo;0;L;;;;;N;;;;;
+A09F;YI SYLLABLE HMOT;Lo;0;L;;;;;N;;;;;
+A0A0;YI SYLLABLE HMOX;Lo;0;L;;;;;N;;;;;
+A0A1;YI SYLLABLE HMO;Lo;0;L;;;;;N;;;;;
+A0A2;YI SYLLABLE HMOP;Lo;0;L;;;;;N;;;;;
+A0A3;YI SYLLABLE HMUT;Lo;0;L;;;;;N;;;;;
+A0A4;YI SYLLABLE HMUX;Lo;0;L;;;;;N;;;;;
+A0A5;YI SYLLABLE HMU;Lo;0;L;;;;;N;;;;;
+A0A6;YI SYLLABLE HMUP;Lo;0;L;;;;;N;;;;;
+A0A7;YI SYLLABLE HMURX;Lo;0;L;;;;;N;;;;;
+A0A8;YI SYLLABLE HMUR;Lo;0;L;;;;;N;;;;;
+A0A9;YI SYLLABLE HMYX;Lo;0;L;;;;;N;;;;;
+A0AA;YI SYLLABLE HMY;Lo;0;L;;;;;N;;;;;
+A0AB;YI SYLLABLE HMYP;Lo;0;L;;;;;N;;;;;
+A0AC;YI SYLLABLE HMYRX;Lo;0;L;;;;;N;;;;;
+A0AD;YI SYLLABLE HMYR;Lo;0;L;;;;;N;;;;;
+A0AE;YI SYLLABLE MIT;Lo;0;L;;;;;N;;;;;
+A0AF;YI SYLLABLE MIX;Lo;0;L;;;;;N;;;;;
+A0B0;YI SYLLABLE MI;Lo;0;L;;;;;N;;;;;
+A0B1;YI SYLLABLE MIP;Lo;0;L;;;;;N;;;;;
+A0B2;YI SYLLABLE MIEX;Lo;0;L;;;;;N;;;;;
+A0B3;YI SYLLABLE MIE;Lo;0;L;;;;;N;;;;;
+A0B4;YI SYLLABLE MIEP;Lo;0;L;;;;;N;;;;;
+A0B5;YI SYLLABLE MAT;Lo;0;L;;;;;N;;;;;
+A0B6;YI SYLLABLE MAX;Lo;0;L;;;;;N;;;;;
+A0B7;YI SYLLABLE MA;Lo;0;L;;;;;N;;;;;
+A0B8;YI SYLLABLE MAP;Lo;0;L;;;;;N;;;;;
+A0B9;YI SYLLABLE MUOT;Lo;0;L;;;;;N;;;;;
+A0BA;YI SYLLABLE MUOX;Lo;0;L;;;;;N;;;;;
+A0BB;YI SYLLABLE MUO;Lo;0;L;;;;;N;;;;;
+A0BC;YI SYLLABLE MUOP;Lo;0;L;;;;;N;;;;;
+A0BD;YI SYLLABLE MOT;Lo;0;L;;;;;N;;;;;
+A0BE;YI SYLLABLE MOX;Lo;0;L;;;;;N;;;;;
+A0BF;YI SYLLABLE MO;Lo;0;L;;;;;N;;;;;
+A0C0;YI SYLLABLE MOP;Lo;0;L;;;;;N;;;;;
+A0C1;YI SYLLABLE MEX;Lo;0;L;;;;;N;;;;;
+A0C2;YI SYLLABLE ME;Lo;0;L;;;;;N;;;;;
+A0C3;YI SYLLABLE MUT;Lo;0;L;;;;;N;;;;;
+A0C4;YI SYLLABLE MUX;Lo;0;L;;;;;N;;;;;
+A0C5;YI SYLLABLE MU;Lo;0;L;;;;;N;;;;;
+A0C6;YI SYLLABLE MUP;Lo;0;L;;;;;N;;;;;
+A0C7;YI SYLLABLE MURX;Lo;0;L;;;;;N;;;;;
+A0C8;YI SYLLABLE MUR;Lo;0;L;;;;;N;;;;;
+A0C9;YI SYLLABLE MYT;Lo;0;L;;;;;N;;;;;
+A0CA;YI SYLLABLE MYX;Lo;0;L;;;;;N;;;;;
+A0CB;YI SYLLABLE MY;Lo;0;L;;;;;N;;;;;
+A0CC;YI SYLLABLE MYP;Lo;0;L;;;;;N;;;;;
+A0CD;YI SYLLABLE FIT;Lo;0;L;;;;;N;;;;;
+A0CE;YI SYLLABLE FIX;Lo;0;L;;;;;N;;;;;
+A0CF;YI SYLLABLE FI;Lo;0;L;;;;;N;;;;;
+A0D0;YI SYLLABLE FIP;Lo;0;L;;;;;N;;;;;
+A0D1;YI SYLLABLE FAT;Lo;0;L;;;;;N;;;;;
+A0D2;YI SYLLABLE FAX;Lo;0;L;;;;;N;;;;;
+A0D3;YI SYLLABLE FA;Lo;0;L;;;;;N;;;;;
+A0D4;YI SYLLABLE FAP;Lo;0;L;;;;;N;;;;;
+A0D5;YI SYLLABLE FOX;Lo;0;L;;;;;N;;;;;
+A0D6;YI SYLLABLE FO;Lo;0;L;;;;;N;;;;;
+A0D7;YI SYLLABLE FOP;Lo;0;L;;;;;N;;;;;
+A0D8;YI SYLLABLE FUT;Lo;0;L;;;;;N;;;;;
+A0D9;YI SYLLABLE FUX;Lo;0;L;;;;;N;;;;;
+A0DA;YI SYLLABLE FU;Lo;0;L;;;;;N;;;;;
+A0DB;YI SYLLABLE FUP;Lo;0;L;;;;;N;;;;;
+A0DC;YI SYLLABLE FURX;Lo;0;L;;;;;N;;;;;
+A0DD;YI SYLLABLE FUR;Lo;0;L;;;;;N;;;;;
+A0DE;YI SYLLABLE FYT;Lo;0;L;;;;;N;;;;;
+A0DF;YI SYLLABLE FYX;Lo;0;L;;;;;N;;;;;
+A0E0;YI SYLLABLE FY;Lo;0;L;;;;;N;;;;;
+A0E1;YI SYLLABLE FYP;Lo;0;L;;;;;N;;;;;
+A0E2;YI SYLLABLE VIT;Lo;0;L;;;;;N;;;;;
+A0E3;YI SYLLABLE VIX;Lo;0;L;;;;;N;;;;;
+A0E4;YI SYLLABLE VI;Lo;0;L;;;;;N;;;;;
+A0E5;YI SYLLABLE VIP;Lo;0;L;;;;;N;;;;;
+A0E6;YI SYLLABLE VIET;Lo;0;L;;;;;N;;;;;
+A0E7;YI SYLLABLE VIEX;Lo;0;L;;;;;N;;;;;
+A0E8;YI SYLLABLE VIE;Lo;0;L;;;;;N;;;;;
+A0E9;YI SYLLABLE VIEP;Lo;0;L;;;;;N;;;;;
+A0EA;YI SYLLABLE VAT;Lo;0;L;;;;;N;;;;;
+A0EB;YI SYLLABLE VAX;Lo;0;L;;;;;N;;;;;
+A0EC;YI SYLLABLE VA;Lo;0;L;;;;;N;;;;;
+A0ED;YI SYLLABLE VAP;Lo;0;L;;;;;N;;;;;
+A0EE;YI SYLLABLE VOT;Lo;0;L;;;;;N;;;;;
+A0EF;YI SYLLABLE VOX;Lo;0;L;;;;;N;;;;;
+A0F0;YI SYLLABLE VO;Lo;0;L;;;;;N;;;;;
+A0F1;YI SYLLABLE VOP;Lo;0;L;;;;;N;;;;;
+A0F2;YI SYLLABLE VEX;Lo;0;L;;;;;N;;;;;
+A0F3;YI SYLLABLE VEP;Lo;0;L;;;;;N;;;;;
+A0F4;YI SYLLABLE VUT;Lo;0;L;;;;;N;;;;;
+A0F5;YI SYLLABLE VUX;Lo;0;L;;;;;N;;;;;
+A0F6;YI SYLLABLE VU;Lo;0;L;;;;;N;;;;;
+A0F7;YI SYLLABLE VUP;Lo;0;L;;;;;N;;;;;
+A0F8;YI SYLLABLE VURX;Lo;0;L;;;;;N;;;;;
+A0F9;YI SYLLABLE VUR;Lo;0;L;;;;;N;;;;;
+A0FA;YI SYLLABLE VYT;Lo;0;L;;;;;N;;;;;
+A0FB;YI SYLLABLE VYX;Lo;0;L;;;;;N;;;;;
+A0FC;YI SYLLABLE VY;Lo;0;L;;;;;N;;;;;
+A0FD;YI SYLLABLE VYP;Lo;0;L;;;;;N;;;;;
+A0FE;YI SYLLABLE VYRX;Lo;0;L;;;;;N;;;;;
+A0FF;YI SYLLABLE VYR;Lo;0;L;;;;;N;;;;;
+A100;YI SYLLABLE DIT;Lo;0;L;;;;;N;;;;;
+A101;YI SYLLABLE DIX;Lo;0;L;;;;;N;;;;;
+A102;YI SYLLABLE DI;Lo;0;L;;;;;N;;;;;
+A103;YI SYLLABLE DIP;Lo;0;L;;;;;N;;;;;
+A104;YI SYLLABLE DIEX;Lo;0;L;;;;;N;;;;;
+A105;YI SYLLABLE DIE;Lo;0;L;;;;;N;;;;;
+A106;YI SYLLABLE DIEP;Lo;0;L;;;;;N;;;;;
+A107;YI SYLLABLE DAT;Lo;0;L;;;;;N;;;;;
+A108;YI SYLLABLE DAX;Lo;0;L;;;;;N;;;;;
+A109;YI SYLLABLE DA;Lo;0;L;;;;;N;;;;;
+A10A;YI SYLLABLE DAP;Lo;0;L;;;;;N;;;;;
+A10B;YI SYLLABLE DUOX;Lo;0;L;;;;;N;;;;;
+A10C;YI SYLLABLE DUO;Lo;0;L;;;;;N;;;;;
+A10D;YI SYLLABLE DOT;Lo;0;L;;;;;N;;;;;
+A10E;YI SYLLABLE DOX;Lo;0;L;;;;;N;;;;;
+A10F;YI SYLLABLE DO;Lo;0;L;;;;;N;;;;;
+A110;YI SYLLABLE DOP;Lo;0;L;;;;;N;;;;;
+A111;YI SYLLABLE DEX;Lo;0;L;;;;;N;;;;;
+A112;YI SYLLABLE DE;Lo;0;L;;;;;N;;;;;
+A113;YI SYLLABLE DEP;Lo;0;L;;;;;N;;;;;
+A114;YI SYLLABLE DUT;Lo;0;L;;;;;N;;;;;
+A115;YI SYLLABLE DUX;Lo;0;L;;;;;N;;;;;
+A116;YI SYLLABLE DU;Lo;0;L;;;;;N;;;;;
+A117;YI SYLLABLE DUP;Lo;0;L;;;;;N;;;;;
+A118;YI SYLLABLE DURX;Lo;0;L;;;;;N;;;;;
+A119;YI SYLLABLE DUR;Lo;0;L;;;;;N;;;;;
+A11A;YI SYLLABLE TIT;Lo;0;L;;;;;N;;;;;
+A11B;YI SYLLABLE TIX;Lo;0;L;;;;;N;;;;;
+A11C;YI SYLLABLE TI;Lo;0;L;;;;;N;;;;;
+A11D;YI SYLLABLE TIP;Lo;0;L;;;;;N;;;;;
+A11E;YI SYLLABLE TIEX;Lo;0;L;;;;;N;;;;;
+A11F;YI SYLLABLE TIE;Lo;0;L;;;;;N;;;;;
+A120;YI SYLLABLE TIEP;Lo;0;L;;;;;N;;;;;
+A121;YI SYLLABLE TAT;Lo;0;L;;;;;N;;;;;
+A122;YI SYLLABLE TAX;Lo;0;L;;;;;N;;;;;
+A123;YI SYLLABLE TA;Lo;0;L;;;;;N;;;;;
+A124;YI SYLLABLE TAP;Lo;0;L;;;;;N;;;;;
+A125;YI SYLLABLE TUOT;Lo;0;L;;;;;N;;;;;
+A126;YI SYLLABLE TUOX;Lo;0;L;;;;;N;;;;;
+A127;YI SYLLABLE TUO;Lo;0;L;;;;;N;;;;;
+A128;YI SYLLABLE TUOP;Lo;0;L;;;;;N;;;;;
+A129;YI SYLLABLE TOT;Lo;0;L;;;;;N;;;;;
+A12A;YI SYLLABLE TOX;Lo;0;L;;;;;N;;;;;
+A12B;YI SYLLABLE TO;Lo;0;L;;;;;N;;;;;
+A12C;YI SYLLABLE TOP;Lo;0;L;;;;;N;;;;;
+A12D;YI SYLLABLE TEX;Lo;0;L;;;;;N;;;;;
+A12E;YI SYLLABLE TE;Lo;0;L;;;;;N;;;;;
+A12F;YI SYLLABLE TEP;Lo;0;L;;;;;N;;;;;
+A130;YI SYLLABLE TUT;Lo;0;L;;;;;N;;;;;
+A131;YI SYLLABLE TUX;Lo;0;L;;;;;N;;;;;
+A132;YI SYLLABLE TU;Lo;0;L;;;;;N;;;;;
+A133;YI SYLLABLE TUP;Lo;0;L;;;;;N;;;;;
+A134;YI SYLLABLE TURX;Lo;0;L;;;;;N;;;;;
+A135;YI SYLLABLE TUR;Lo;0;L;;;;;N;;;;;
+A136;YI SYLLABLE DDIT;Lo;0;L;;;;;N;;;;;
+A137;YI SYLLABLE DDIX;Lo;0;L;;;;;N;;;;;
+A138;YI SYLLABLE DDI;Lo;0;L;;;;;N;;;;;
+A139;YI SYLLABLE DDIP;Lo;0;L;;;;;N;;;;;
+A13A;YI SYLLABLE DDIEX;Lo;0;L;;;;;N;;;;;
+A13B;YI SYLLABLE DDIE;Lo;0;L;;;;;N;;;;;
+A13C;YI SYLLABLE DDIEP;Lo;0;L;;;;;N;;;;;
+A13D;YI SYLLABLE DDAT;Lo;0;L;;;;;N;;;;;
+A13E;YI SYLLABLE DDAX;Lo;0;L;;;;;N;;;;;
+A13F;YI SYLLABLE DDA;Lo;0;L;;;;;N;;;;;
+A140;YI SYLLABLE DDAP;Lo;0;L;;;;;N;;;;;
+A141;YI SYLLABLE DDUOX;Lo;0;L;;;;;N;;;;;
+A142;YI SYLLABLE DDUO;Lo;0;L;;;;;N;;;;;
+A143;YI SYLLABLE DDUOP;Lo;0;L;;;;;N;;;;;
+A144;YI SYLLABLE DDOT;Lo;0;L;;;;;N;;;;;
+A145;YI SYLLABLE DDOX;Lo;0;L;;;;;N;;;;;
+A146;YI SYLLABLE DDO;Lo;0;L;;;;;N;;;;;
+A147;YI SYLLABLE DDOP;Lo;0;L;;;;;N;;;;;
+A148;YI SYLLABLE DDEX;Lo;0;L;;;;;N;;;;;
+A149;YI SYLLABLE DDE;Lo;0;L;;;;;N;;;;;
+A14A;YI SYLLABLE DDEP;Lo;0;L;;;;;N;;;;;
+A14B;YI SYLLABLE DDUT;Lo;0;L;;;;;N;;;;;
+A14C;YI SYLLABLE DDUX;Lo;0;L;;;;;N;;;;;
+A14D;YI SYLLABLE DDU;Lo;0;L;;;;;N;;;;;
+A14E;YI SYLLABLE DDUP;Lo;0;L;;;;;N;;;;;
+A14F;YI SYLLABLE DDURX;Lo;0;L;;;;;N;;;;;
+A150;YI SYLLABLE DDUR;Lo;0;L;;;;;N;;;;;
+A151;YI SYLLABLE NDIT;Lo;0;L;;;;;N;;;;;
+A152;YI SYLLABLE NDIX;Lo;0;L;;;;;N;;;;;
+A153;YI SYLLABLE NDI;Lo;0;L;;;;;N;;;;;
+A154;YI SYLLABLE NDIP;Lo;0;L;;;;;N;;;;;
+A155;YI SYLLABLE NDIEX;Lo;0;L;;;;;N;;;;;
+A156;YI SYLLABLE NDIE;Lo;0;L;;;;;N;;;;;
+A157;YI SYLLABLE NDAT;Lo;0;L;;;;;N;;;;;
+A158;YI SYLLABLE NDAX;Lo;0;L;;;;;N;;;;;
+A159;YI SYLLABLE NDA;Lo;0;L;;;;;N;;;;;
+A15A;YI SYLLABLE NDAP;Lo;0;L;;;;;N;;;;;
+A15B;YI SYLLABLE NDOT;Lo;0;L;;;;;N;;;;;
+A15C;YI SYLLABLE NDOX;Lo;0;L;;;;;N;;;;;
+A15D;YI SYLLABLE NDO;Lo;0;L;;;;;N;;;;;
+A15E;YI SYLLABLE NDOP;Lo;0;L;;;;;N;;;;;
+A15F;YI SYLLABLE NDEX;Lo;0;L;;;;;N;;;;;
+A160;YI SYLLABLE NDE;Lo;0;L;;;;;N;;;;;
+A161;YI SYLLABLE NDEP;Lo;0;L;;;;;N;;;;;
+A162;YI SYLLABLE NDUT;Lo;0;L;;;;;N;;;;;
+A163;YI SYLLABLE NDUX;Lo;0;L;;;;;N;;;;;
+A164;YI SYLLABLE NDU;Lo;0;L;;;;;N;;;;;
+A165;YI SYLLABLE NDUP;Lo;0;L;;;;;N;;;;;
+A166;YI SYLLABLE NDURX;Lo;0;L;;;;;N;;;;;
+A167;YI SYLLABLE NDUR;Lo;0;L;;;;;N;;;;;
+A168;YI SYLLABLE HNIT;Lo;0;L;;;;;N;;;;;
+A169;YI SYLLABLE HNIX;Lo;0;L;;;;;N;;;;;
+A16A;YI SYLLABLE HNI;Lo;0;L;;;;;N;;;;;
+A16B;YI SYLLABLE HNIP;Lo;0;L;;;;;N;;;;;
+A16C;YI SYLLABLE HNIET;Lo;0;L;;;;;N;;;;;
+A16D;YI SYLLABLE HNIEX;Lo;0;L;;;;;N;;;;;
+A16E;YI SYLLABLE HNIE;Lo;0;L;;;;;N;;;;;
+A16F;YI SYLLABLE HNIEP;Lo;0;L;;;;;N;;;;;
+A170;YI SYLLABLE HNAT;Lo;0;L;;;;;N;;;;;
+A171;YI SYLLABLE HNAX;Lo;0;L;;;;;N;;;;;
+A172;YI SYLLABLE HNA;Lo;0;L;;;;;N;;;;;
+A173;YI SYLLABLE HNAP;Lo;0;L;;;;;N;;;;;
+A174;YI SYLLABLE HNUOX;Lo;0;L;;;;;N;;;;;
+A175;YI SYLLABLE HNUO;Lo;0;L;;;;;N;;;;;
+A176;YI SYLLABLE HNOT;Lo;0;L;;;;;N;;;;;
+A177;YI SYLLABLE HNOX;Lo;0;L;;;;;N;;;;;
+A178;YI SYLLABLE HNOP;Lo;0;L;;;;;N;;;;;
+A179;YI SYLLABLE HNEX;Lo;0;L;;;;;N;;;;;
+A17A;YI SYLLABLE HNE;Lo;0;L;;;;;N;;;;;
+A17B;YI SYLLABLE HNEP;Lo;0;L;;;;;N;;;;;
+A17C;YI SYLLABLE HNUT;Lo;0;L;;;;;N;;;;;
+A17D;YI SYLLABLE NIT;Lo;0;L;;;;;N;;;;;
+A17E;YI SYLLABLE NIX;Lo;0;L;;;;;N;;;;;
+A17F;YI SYLLABLE NI;Lo;0;L;;;;;N;;;;;
+A180;YI SYLLABLE NIP;Lo;0;L;;;;;N;;;;;
+A181;YI SYLLABLE NIEX;Lo;0;L;;;;;N;;;;;
+A182;YI SYLLABLE NIE;Lo;0;L;;;;;N;;;;;
+A183;YI SYLLABLE NIEP;Lo;0;L;;;;;N;;;;;
+A184;YI SYLLABLE NAX;Lo;0;L;;;;;N;;;;;
+A185;YI SYLLABLE NA;Lo;0;L;;;;;N;;;;;
+A186;YI SYLLABLE NAP;Lo;0;L;;;;;N;;;;;
+A187;YI SYLLABLE NUOX;Lo;0;L;;;;;N;;;;;
+A188;YI SYLLABLE NUO;Lo;0;L;;;;;N;;;;;
+A189;YI SYLLABLE NUOP;Lo;0;L;;;;;N;;;;;
+A18A;YI SYLLABLE NOT;Lo;0;L;;;;;N;;;;;
+A18B;YI SYLLABLE NOX;Lo;0;L;;;;;N;;;;;
+A18C;YI SYLLABLE NO;Lo;0;L;;;;;N;;;;;
+A18D;YI SYLLABLE NOP;Lo;0;L;;;;;N;;;;;
+A18E;YI SYLLABLE NEX;Lo;0;L;;;;;N;;;;;
+A18F;YI SYLLABLE NE;Lo;0;L;;;;;N;;;;;
+A190;YI SYLLABLE NEP;Lo;0;L;;;;;N;;;;;
+A191;YI SYLLABLE NUT;Lo;0;L;;;;;N;;;;;
+A192;YI SYLLABLE NUX;Lo;0;L;;;;;N;;;;;
+A193;YI SYLLABLE NU;Lo;0;L;;;;;N;;;;;
+A194;YI SYLLABLE NUP;Lo;0;L;;;;;N;;;;;
+A195;YI SYLLABLE NURX;Lo;0;L;;;;;N;;;;;
+A196;YI SYLLABLE NUR;Lo;0;L;;;;;N;;;;;
+A197;YI SYLLABLE HLIT;Lo;0;L;;;;;N;;;;;
+A198;YI SYLLABLE HLIX;Lo;0;L;;;;;N;;;;;
+A199;YI SYLLABLE HLI;Lo;0;L;;;;;N;;;;;
+A19A;YI SYLLABLE HLIP;Lo;0;L;;;;;N;;;;;
+A19B;YI SYLLABLE HLIEX;Lo;0;L;;;;;N;;;;;
+A19C;YI SYLLABLE HLIE;Lo;0;L;;;;;N;;;;;
+A19D;YI SYLLABLE HLIEP;Lo;0;L;;;;;N;;;;;
+A19E;YI SYLLABLE HLAT;Lo;0;L;;;;;N;;;;;
+A19F;YI SYLLABLE HLAX;Lo;0;L;;;;;N;;;;;
+A1A0;YI SYLLABLE HLA;Lo;0;L;;;;;N;;;;;
+A1A1;YI SYLLABLE HLAP;Lo;0;L;;;;;N;;;;;
+A1A2;YI SYLLABLE HLUOX;Lo;0;L;;;;;N;;;;;
+A1A3;YI SYLLABLE HLUO;Lo;0;L;;;;;N;;;;;
+A1A4;YI SYLLABLE HLUOP;Lo;0;L;;;;;N;;;;;
+A1A5;YI SYLLABLE HLOX;Lo;0;L;;;;;N;;;;;
+A1A6;YI SYLLABLE HLO;Lo;0;L;;;;;N;;;;;
+A1A7;YI SYLLABLE HLOP;Lo;0;L;;;;;N;;;;;
+A1A8;YI SYLLABLE HLEX;Lo;0;L;;;;;N;;;;;
+A1A9;YI SYLLABLE HLE;Lo;0;L;;;;;N;;;;;
+A1AA;YI SYLLABLE HLEP;Lo;0;L;;;;;N;;;;;
+A1AB;YI SYLLABLE HLUT;Lo;0;L;;;;;N;;;;;
+A1AC;YI SYLLABLE HLUX;Lo;0;L;;;;;N;;;;;
+A1AD;YI SYLLABLE HLU;Lo;0;L;;;;;N;;;;;
+A1AE;YI SYLLABLE HLUP;Lo;0;L;;;;;N;;;;;
+A1AF;YI SYLLABLE HLURX;Lo;0;L;;;;;N;;;;;
+A1B0;YI SYLLABLE HLUR;Lo;0;L;;;;;N;;;;;
+A1B1;YI SYLLABLE HLYT;Lo;0;L;;;;;N;;;;;
+A1B2;YI SYLLABLE HLYX;Lo;0;L;;;;;N;;;;;
+A1B3;YI SYLLABLE HLY;Lo;0;L;;;;;N;;;;;
+A1B4;YI SYLLABLE HLYP;Lo;0;L;;;;;N;;;;;
+A1B5;YI SYLLABLE HLYRX;Lo;0;L;;;;;N;;;;;
+A1B6;YI SYLLABLE HLYR;Lo;0;L;;;;;N;;;;;
+A1B7;YI SYLLABLE LIT;Lo;0;L;;;;;N;;;;;
+A1B8;YI SYLLABLE LIX;Lo;0;L;;;;;N;;;;;
+A1B9;YI SYLLABLE LI;Lo;0;L;;;;;N;;;;;
+A1BA;YI SYLLABLE LIP;Lo;0;L;;;;;N;;;;;
+A1BB;YI SYLLABLE LIET;Lo;0;L;;;;;N;;;;;
+A1BC;YI SYLLABLE LIEX;Lo;0;L;;;;;N;;;;;
+A1BD;YI SYLLABLE LIE;Lo;0;L;;;;;N;;;;;
+A1BE;YI SYLLABLE LIEP;Lo;0;L;;;;;N;;;;;
+A1BF;YI SYLLABLE LAT;Lo;0;L;;;;;N;;;;;
+A1C0;YI SYLLABLE LAX;Lo;0;L;;;;;N;;;;;
+A1C1;YI SYLLABLE LA;Lo;0;L;;;;;N;;;;;
+A1C2;YI SYLLABLE LAP;Lo;0;L;;;;;N;;;;;
+A1C3;YI SYLLABLE LUOT;Lo;0;L;;;;;N;;;;;
+A1C4;YI SYLLABLE LUOX;Lo;0;L;;;;;N;;;;;
+A1C5;YI SYLLABLE LUO;Lo;0;L;;;;;N;;;;;
+A1C6;YI SYLLABLE LUOP;Lo;0;L;;;;;N;;;;;
+A1C7;YI SYLLABLE LOT;Lo;0;L;;;;;N;;;;;
+A1C8;YI SYLLABLE LOX;Lo;0;L;;;;;N;;;;;
+A1C9;YI SYLLABLE LO;Lo;0;L;;;;;N;;;;;
+A1CA;YI SYLLABLE LOP;Lo;0;L;;;;;N;;;;;
+A1CB;YI SYLLABLE LEX;Lo;0;L;;;;;N;;;;;
+A1CC;YI SYLLABLE LE;Lo;0;L;;;;;N;;;;;
+A1CD;YI SYLLABLE LEP;Lo;0;L;;;;;N;;;;;
+A1CE;YI SYLLABLE LUT;Lo;0;L;;;;;N;;;;;
+A1CF;YI SYLLABLE LUX;Lo;0;L;;;;;N;;;;;
+A1D0;YI SYLLABLE LU;Lo;0;L;;;;;N;;;;;
+A1D1;YI SYLLABLE LUP;Lo;0;L;;;;;N;;;;;
+A1D2;YI SYLLABLE LURX;Lo;0;L;;;;;N;;;;;
+A1D3;YI SYLLABLE LUR;Lo;0;L;;;;;N;;;;;
+A1D4;YI SYLLABLE LYT;Lo;0;L;;;;;N;;;;;
+A1D5;YI SYLLABLE LYX;Lo;0;L;;;;;N;;;;;
+A1D6;YI SYLLABLE LY;Lo;0;L;;;;;N;;;;;
+A1D7;YI SYLLABLE LYP;Lo;0;L;;;;;N;;;;;
+A1D8;YI SYLLABLE LYRX;Lo;0;L;;;;;N;;;;;
+A1D9;YI SYLLABLE LYR;Lo;0;L;;;;;N;;;;;
+A1DA;YI SYLLABLE GIT;Lo;0;L;;;;;N;;;;;
+A1DB;YI SYLLABLE GIX;Lo;0;L;;;;;N;;;;;
+A1DC;YI SYLLABLE GI;Lo;0;L;;;;;N;;;;;
+A1DD;YI SYLLABLE GIP;Lo;0;L;;;;;N;;;;;
+A1DE;YI SYLLABLE GIET;Lo;0;L;;;;;N;;;;;
+A1DF;YI SYLLABLE GIEX;Lo;0;L;;;;;N;;;;;
+A1E0;YI SYLLABLE GIE;Lo;0;L;;;;;N;;;;;
+A1E1;YI SYLLABLE GIEP;Lo;0;L;;;;;N;;;;;
+A1E2;YI SYLLABLE GAT;Lo;0;L;;;;;N;;;;;
+A1E3;YI SYLLABLE GAX;Lo;0;L;;;;;N;;;;;
+A1E4;YI SYLLABLE GA;Lo;0;L;;;;;N;;;;;
+A1E5;YI SYLLABLE GAP;Lo;0;L;;;;;N;;;;;
+A1E6;YI SYLLABLE GUOT;Lo;0;L;;;;;N;;;;;
+A1E7;YI SYLLABLE GUOX;Lo;0;L;;;;;N;;;;;
+A1E8;YI SYLLABLE GUO;Lo;0;L;;;;;N;;;;;
+A1E9;YI SYLLABLE GUOP;Lo;0;L;;;;;N;;;;;
+A1EA;YI SYLLABLE GOT;Lo;0;L;;;;;N;;;;;
+A1EB;YI SYLLABLE GOX;Lo;0;L;;;;;N;;;;;
+A1EC;YI SYLLABLE GO;Lo;0;L;;;;;N;;;;;
+A1ED;YI SYLLABLE GOP;Lo;0;L;;;;;N;;;;;
+A1EE;YI SYLLABLE GET;Lo;0;L;;;;;N;;;;;
+A1EF;YI SYLLABLE GEX;Lo;0;L;;;;;N;;;;;
+A1F0;YI SYLLABLE GE;Lo;0;L;;;;;N;;;;;
+A1F1;YI SYLLABLE GEP;Lo;0;L;;;;;N;;;;;
+A1F2;YI SYLLABLE GUT;Lo;0;L;;;;;N;;;;;
+A1F3;YI SYLLABLE GUX;Lo;0;L;;;;;N;;;;;
+A1F4;YI SYLLABLE GU;Lo;0;L;;;;;N;;;;;
+A1F5;YI SYLLABLE GUP;Lo;0;L;;;;;N;;;;;
+A1F6;YI SYLLABLE GURX;Lo;0;L;;;;;N;;;;;
+A1F7;YI SYLLABLE GUR;Lo;0;L;;;;;N;;;;;
+A1F8;YI SYLLABLE KIT;Lo;0;L;;;;;N;;;;;
+A1F9;YI SYLLABLE KIX;Lo;0;L;;;;;N;;;;;
+A1FA;YI SYLLABLE KI;Lo;0;L;;;;;N;;;;;
+A1FB;YI SYLLABLE KIP;Lo;0;L;;;;;N;;;;;
+A1FC;YI SYLLABLE KIEX;Lo;0;L;;;;;N;;;;;
+A1FD;YI SYLLABLE KIE;Lo;0;L;;;;;N;;;;;
+A1FE;YI SYLLABLE KIEP;Lo;0;L;;;;;N;;;;;
+A1FF;YI SYLLABLE KAT;Lo;0;L;;;;;N;;;;;
+A200;YI SYLLABLE KAX;Lo;0;L;;;;;N;;;;;
+A201;YI SYLLABLE KA;Lo;0;L;;;;;N;;;;;
+A202;YI SYLLABLE KAP;Lo;0;L;;;;;N;;;;;
+A203;YI SYLLABLE KUOX;Lo;0;L;;;;;N;;;;;
+A204;YI SYLLABLE KUO;Lo;0;L;;;;;N;;;;;
+A205;YI SYLLABLE KUOP;Lo;0;L;;;;;N;;;;;
+A206;YI SYLLABLE KOT;Lo;0;L;;;;;N;;;;;
+A207;YI SYLLABLE KOX;Lo;0;L;;;;;N;;;;;
+A208;YI SYLLABLE KO;Lo;0;L;;;;;N;;;;;
+A209;YI SYLLABLE KOP;Lo;0;L;;;;;N;;;;;
+A20A;YI SYLLABLE KET;Lo;0;L;;;;;N;;;;;
+A20B;YI SYLLABLE KEX;Lo;0;L;;;;;N;;;;;
+A20C;YI SYLLABLE KE;Lo;0;L;;;;;N;;;;;
+A20D;YI SYLLABLE KEP;Lo;0;L;;;;;N;;;;;
+A20E;YI SYLLABLE KUT;Lo;0;L;;;;;N;;;;;
+A20F;YI SYLLABLE KUX;Lo;0;L;;;;;N;;;;;
+A210;YI SYLLABLE KU;Lo;0;L;;;;;N;;;;;
+A211;YI SYLLABLE KUP;Lo;0;L;;;;;N;;;;;
+A212;YI SYLLABLE KURX;Lo;0;L;;;;;N;;;;;
+A213;YI SYLLABLE KUR;Lo;0;L;;;;;N;;;;;
+A214;YI SYLLABLE GGIT;Lo;0;L;;;;;N;;;;;
+A215;YI SYLLABLE GGIX;Lo;0;L;;;;;N;;;;;
+A216;YI SYLLABLE GGI;Lo;0;L;;;;;N;;;;;
+A217;YI SYLLABLE GGIEX;Lo;0;L;;;;;N;;;;;
+A218;YI SYLLABLE GGIE;Lo;0;L;;;;;N;;;;;
+A219;YI SYLLABLE GGIEP;Lo;0;L;;;;;N;;;;;
+A21A;YI SYLLABLE GGAT;Lo;0;L;;;;;N;;;;;
+A21B;YI SYLLABLE GGAX;Lo;0;L;;;;;N;;;;;
+A21C;YI SYLLABLE GGA;Lo;0;L;;;;;N;;;;;
+A21D;YI SYLLABLE GGAP;Lo;0;L;;;;;N;;;;;
+A21E;YI SYLLABLE GGUOT;Lo;0;L;;;;;N;;;;;
+A21F;YI SYLLABLE GGUOX;Lo;0;L;;;;;N;;;;;
+A220;YI SYLLABLE GGUO;Lo;0;L;;;;;N;;;;;
+A221;YI SYLLABLE GGUOP;Lo;0;L;;;;;N;;;;;
+A222;YI SYLLABLE GGOT;Lo;0;L;;;;;N;;;;;
+A223;YI SYLLABLE GGOX;Lo;0;L;;;;;N;;;;;
+A224;YI SYLLABLE GGO;Lo;0;L;;;;;N;;;;;
+A225;YI SYLLABLE GGOP;Lo;0;L;;;;;N;;;;;
+A226;YI SYLLABLE GGET;Lo;0;L;;;;;N;;;;;
+A227;YI SYLLABLE GGEX;Lo;0;L;;;;;N;;;;;
+A228;YI SYLLABLE GGE;Lo;0;L;;;;;N;;;;;
+A229;YI SYLLABLE GGEP;Lo;0;L;;;;;N;;;;;
+A22A;YI SYLLABLE GGUT;Lo;0;L;;;;;N;;;;;
+A22B;YI SYLLABLE GGUX;Lo;0;L;;;;;N;;;;;
+A22C;YI SYLLABLE GGU;Lo;0;L;;;;;N;;;;;
+A22D;YI SYLLABLE GGUP;Lo;0;L;;;;;N;;;;;
+A22E;YI SYLLABLE GGURX;Lo;0;L;;;;;N;;;;;
+A22F;YI SYLLABLE GGUR;Lo;0;L;;;;;N;;;;;
+A230;YI SYLLABLE MGIEX;Lo;0;L;;;;;N;;;;;
+A231;YI SYLLABLE MGIE;Lo;0;L;;;;;N;;;;;
+A232;YI SYLLABLE MGAT;Lo;0;L;;;;;N;;;;;
+A233;YI SYLLABLE MGAX;Lo;0;L;;;;;N;;;;;
+A234;YI SYLLABLE MGA;Lo;0;L;;;;;N;;;;;
+A235;YI SYLLABLE MGAP;Lo;0;L;;;;;N;;;;;
+A236;YI SYLLABLE MGUOX;Lo;0;L;;;;;N;;;;;
+A237;YI SYLLABLE MGUO;Lo;0;L;;;;;N;;;;;
+A238;YI SYLLABLE MGUOP;Lo;0;L;;;;;N;;;;;
+A239;YI SYLLABLE MGOT;Lo;0;L;;;;;N;;;;;
+A23A;YI SYLLABLE MGOX;Lo;0;L;;;;;N;;;;;
+A23B;YI SYLLABLE MGO;Lo;0;L;;;;;N;;;;;
+A23C;YI SYLLABLE MGOP;Lo;0;L;;;;;N;;;;;
+A23D;YI SYLLABLE MGEX;Lo;0;L;;;;;N;;;;;
+A23E;YI SYLLABLE MGE;Lo;0;L;;;;;N;;;;;
+A23F;YI SYLLABLE MGEP;Lo;0;L;;;;;N;;;;;
+A240;YI SYLLABLE MGUT;Lo;0;L;;;;;N;;;;;
+A241;YI SYLLABLE MGUX;Lo;0;L;;;;;N;;;;;
+A242;YI SYLLABLE MGU;Lo;0;L;;;;;N;;;;;
+A243;YI SYLLABLE MGUP;Lo;0;L;;;;;N;;;;;
+A244;YI SYLLABLE MGURX;Lo;0;L;;;;;N;;;;;
+A245;YI SYLLABLE MGUR;Lo;0;L;;;;;N;;;;;
+A246;YI SYLLABLE HXIT;Lo;0;L;;;;;N;;;;;
+A247;YI SYLLABLE HXIX;Lo;0;L;;;;;N;;;;;
+A248;YI SYLLABLE HXI;Lo;0;L;;;;;N;;;;;
+A249;YI SYLLABLE HXIP;Lo;0;L;;;;;N;;;;;
+A24A;YI SYLLABLE HXIET;Lo;0;L;;;;;N;;;;;
+A24B;YI SYLLABLE HXIEX;Lo;0;L;;;;;N;;;;;
+A24C;YI SYLLABLE HXIE;Lo;0;L;;;;;N;;;;;
+A24D;YI SYLLABLE HXIEP;Lo;0;L;;;;;N;;;;;
+A24E;YI SYLLABLE HXAT;Lo;0;L;;;;;N;;;;;
+A24F;YI SYLLABLE HXAX;Lo;0;L;;;;;N;;;;;
+A250;YI SYLLABLE HXA;Lo;0;L;;;;;N;;;;;
+A251;YI SYLLABLE HXAP;Lo;0;L;;;;;N;;;;;
+A252;YI SYLLABLE HXUOT;Lo;0;L;;;;;N;;;;;
+A253;YI SYLLABLE HXUOX;Lo;0;L;;;;;N;;;;;
+A254;YI SYLLABLE HXUO;Lo;0;L;;;;;N;;;;;
+A255;YI SYLLABLE HXUOP;Lo;0;L;;;;;N;;;;;
+A256;YI SYLLABLE HXOT;Lo;0;L;;;;;N;;;;;
+A257;YI SYLLABLE HXOX;Lo;0;L;;;;;N;;;;;
+A258;YI SYLLABLE HXO;Lo;0;L;;;;;N;;;;;
+A259;YI SYLLABLE HXOP;Lo;0;L;;;;;N;;;;;
+A25A;YI SYLLABLE HXEX;Lo;0;L;;;;;N;;;;;
+A25B;YI SYLLABLE HXE;Lo;0;L;;;;;N;;;;;
+A25C;YI SYLLABLE HXEP;Lo;0;L;;;;;N;;;;;
+A25D;YI SYLLABLE NGIEX;Lo;0;L;;;;;N;;;;;
+A25E;YI SYLLABLE NGIE;Lo;0;L;;;;;N;;;;;
+A25F;YI SYLLABLE NGIEP;Lo;0;L;;;;;N;;;;;
+A260;YI SYLLABLE NGAT;Lo;0;L;;;;;N;;;;;
+A261;YI SYLLABLE NGAX;Lo;0;L;;;;;N;;;;;
+A262;YI SYLLABLE NGA;Lo;0;L;;;;;N;;;;;
+A263;YI SYLLABLE NGAP;Lo;0;L;;;;;N;;;;;
+A264;YI SYLLABLE NGUOT;Lo;0;L;;;;;N;;;;;
+A265;YI SYLLABLE NGUOX;Lo;0;L;;;;;N;;;;;
+A266;YI SYLLABLE NGUO;Lo;0;L;;;;;N;;;;;
+A267;YI SYLLABLE NGOT;Lo;0;L;;;;;N;;;;;
+A268;YI SYLLABLE NGOX;Lo;0;L;;;;;N;;;;;
+A269;YI SYLLABLE NGO;Lo;0;L;;;;;N;;;;;
+A26A;YI SYLLABLE NGOP;Lo;0;L;;;;;N;;;;;
+A26B;YI SYLLABLE NGEX;Lo;0;L;;;;;N;;;;;
+A26C;YI SYLLABLE NGE;Lo;0;L;;;;;N;;;;;
+A26D;YI SYLLABLE NGEP;Lo;0;L;;;;;N;;;;;
+A26E;YI SYLLABLE HIT;Lo;0;L;;;;;N;;;;;
+A26F;YI SYLLABLE HIEX;Lo;0;L;;;;;N;;;;;
+A270;YI SYLLABLE HIE;Lo;0;L;;;;;N;;;;;
+A271;YI SYLLABLE HAT;Lo;0;L;;;;;N;;;;;
+A272;YI SYLLABLE HAX;Lo;0;L;;;;;N;;;;;
+A273;YI SYLLABLE HA;Lo;0;L;;;;;N;;;;;
+A274;YI SYLLABLE HAP;Lo;0;L;;;;;N;;;;;
+A275;YI SYLLABLE HUOT;Lo;0;L;;;;;N;;;;;
+A276;YI SYLLABLE HUOX;Lo;0;L;;;;;N;;;;;
+A277;YI SYLLABLE HUO;Lo;0;L;;;;;N;;;;;
+A278;YI SYLLABLE HUOP;Lo;0;L;;;;;N;;;;;
+A279;YI SYLLABLE HOT;Lo;0;L;;;;;N;;;;;
+A27A;YI SYLLABLE HOX;Lo;0;L;;;;;N;;;;;
+A27B;YI SYLLABLE HO;Lo;0;L;;;;;N;;;;;
+A27C;YI SYLLABLE HOP;Lo;0;L;;;;;N;;;;;
+A27D;YI SYLLABLE HEX;Lo;0;L;;;;;N;;;;;
+A27E;YI SYLLABLE HE;Lo;0;L;;;;;N;;;;;
+A27F;YI SYLLABLE HEP;Lo;0;L;;;;;N;;;;;
+A280;YI SYLLABLE WAT;Lo;0;L;;;;;N;;;;;
+A281;YI SYLLABLE WAX;Lo;0;L;;;;;N;;;;;
+A282;YI SYLLABLE WA;Lo;0;L;;;;;N;;;;;
+A283;YI SYLLABLE WAP;Lo;0;L;;;;;N;;;;;
+A284;YI SYLLABLE WUOX;Lo;0;L;;;;;N;;;;;
+A285;YI SYLLABLE WUO;Lo;0;L;;;;;N;;;;;
+A286;YI SYLLABLE WUOP;Lo;0;L;;;;;N;;;;;
+A287;YI SYLLABLE WOX;Lo;0;L;;;;;N;;;;;
+A288;YI SYLLABLE WO;Lo;0;L;;;;;N;;;;;
+A289;YI SYLLABLE WOP;Lo;0;L;;;;;N;;;;;
+A28A;YI SYLLABLE WEX;Lo;0;L;;;;;N;;;;;
+A28B;YI SYLLABLE WE;Lo;0;L;;;;;N;;;;;
+A28C;YI SYLLABLE WEP;Lo;0;L;;;;;N;;;;;
+A28D;YI SYLLABLE ZIT;Lo;0;L;;;;;N;;;;;
+A28E;YI SYLLABLE ZIX;Lo;0;L;;;;;N;;;;;
+A28F;YI SYLLABLE ZI;Lo;0;L;;;;;N;;;;;
+A290;YI SYLLABLE ZIP;Lo;0;L;;;;;N;;;;;
+A291;YI SYLLABLE ZIEX;Lo;0;L;;;;;N;;;;;
+A292;YI SYLLABLE ZIE;Lo;0;L;;;;;N;;;;;
+A293;YI SYLLABLE ZIEP;Lo;0;L;;;;;N;;;;;
+A294;YI SYLLABLE ZAT;Lo;0;L;;;;;N;;;;;
+A295;YI SYLLABLE ZAX;Lo;0;L;;;;;N;;;;;
+A296;YI SYLLABLE ZA;Lo;0;L;;;;;N;;;;;
+A297;YI SYLLABLE ZAP;Lo;0;L;;;;;N;;;;;
+A298;YI SYLLABLE ZUOX;Lo;0;L;;;;;N;;;;;
+A299;YI SYLLABLE ZUO;Lo;0;L;;;;;N;;;;;
+A29A;YI SYLLABLE ZUOP;Lo;0;L;;;;;N;;;;;
+A29B;YI SYLLABLE ZOT;Lo;0;L;;;;;N;;;;;
+A29C;YI SYLLABLE ZOX;Lo;0;L;;;;;N;;;;;
+A29D;YI SYLLABLE ZO;Lo;0;L;;;;;N;;;;;
+A29E;YI SYLLABLE ZOP;Lo;0;L;;;;;N;;;;;
+A29F;YI SYLLABLE ZEX;Lo;0;L;;;;;N;;;;;
+A2A0;YI SYLLABLE ZE;Lo;0;L;;;;;N;;;;;
+A2A1;YI SYLLABLE ZEP;Lo;0;L;;;;;N;;;;;
+A2A2;YI SYLLABLE ZUT;Lo;0;L;;;;;N;;;;;
+A2A3;YI SYLLABLE ZUX;Lo;0;L;;;;;N;;;;;
+A2A4;YI SYLLABLE ZU;Lo;0;L;;;;;N;;;;;
+A2A5;YI SYLLABLE ZUP;Lo;0;L;;;;;N;;;;;
+A2A6;YI SYLLABLE ZURX;Lo;0;L;;;;;N;;;;;
+A2A7;YI SYLLABLE ZUR;Lo;0;L;;;;;N;;;;;
+A2A8;YI SYLLABLE ZYT;Lo;0;L;;;;;N;;;;;
+A2A9;YI SYLLABLE ZYX;Lo;0;L;;;;;N;;;;;
+A2AA;YI SYLLABLE ZY;Lo;0;L;;;;;N;;;;;
+A2AB;YI SYLLABLE ZYP;Lo;0;L;;;;;N;;;;;
+A2AC;YI SYLLABLE ZYRX;Lo;0;L;;;;;N;;;;;
+A2AD;YI SYLLABLE ZYR;Lo;0;L;;;;;N;;;;;
+A2AE;YI SYLLABLE CIT;Lo;0;L;;;;;N;;;;;
+A2AF;YI SYLLABLE CIX;Lo;0;L;;;;;N;;;;;
+A2B0;YI SYLLABLE CI;Lo;0;L;;;;;N;;;;;
+A2B1;YI SYLLABLE CIP;Lo;0;L;;;;;N;;;;;
+A2B2;YI SYLLABLE CIET;Lo;0;L;;;;;N;;;;;
+A2B3;YI SYLLABLE CIEX;Lo;0;L;;;;;N;;;;;
+A2B4;YI SYLLABLE CIE;Lo;0;L;;;;;N;;;;;
+A2B5;YI SYLLABLE CIEP;Lo;0;L;;;;;N;;;;;
+A2B6;YI SYLLABLE CAT;Lo;0;L;;;;;N;;;;;
+A2B7;YI SYLLABLE CAX;Lo;0;L;;;;;N;;;;;
+A2B8;YI SYLLABLE CA;Lo;0;L;;;;;N;;;;;
+A2B9;YI SYLLABLE CAP;Lo;0;L;;;;;N;;;;;
+A2BA;YI SYLLABLE CUOX;Lo;0;L;;;;;N;;;;;
+A2BB;YI SYLLABLE CUO;Lo;0;L;;;;;N;;;;;
+A2BC;YI SYLLABLE CUOP;Lo;0;L;;;;;N;;;;;
+A2BD;YI SYLLABLE COT;Lo;0;L;;;;;N;;;;;
+A2BE;YI SYLLABLE COX;Lo;0;L;;;;;N;;;;;
+A2BF;YI SYLLABLE CO;Lo;0;L;;;;;N;;;;;
+A2C0;YI SYLLABLE COP;Lo;0;L;;;;;N;;;;;
+A2C1;YI SYLLABLE CEX;Lo;0;L;;;;;N;;;;;
+A2C2;YI SYLLABLE CE;Lo;0;L;;;;;N;;;;;
+A2C3;YI SYLLABLE CEP;Lo;0;L;;;;;N;;;;;
+A2C4;YI SYLLABLE CUT;Lo;0;L;;;;;N;;;;;
+A2C5;YI SYLLABLE CUX;Lo;0;L;;;;;N;;;;;
+A2C6;YI SYLLABLE CU;Lo;0;L;;;;;N;;;;;
+A2C7;YI SYLLABLE CUP;Lo;0;L;;;;;N;;;;;
+A2C8;YI SYLLABLE CURX;Lo;0;L;;;;;N;;;;;
+A2C9;YI SYLLABLE CUR;Lo;0;L;;;;;N;;;;;
+A2CA;YI SYLLABLE CYT;Lo;0;L;;;;;N;;;;;
+A2CB;YI SYLLABLE CYX;Lo;0;L;;;;;N;;;;;
+A2CC;YI SYLLABLE CY;Lo;0;L;;;;;N;;;;;
+A2CD;YI SYLLABLE CYP;Lo;0;L;;;;;N;;;;;
+A2CE;YI SYLLABLE CYRX;Lo;0;L;;;;;N;;;;;
+A2CF;YI SYLLABLE CYR;Lo;0;L;;;;;N;;;;;
+A2D0;YI SYLLABLE ZZIT;Lo;0;L;;;;;N;;;;;
+A2D1;YI SYLLABLE ZZIX;Lo;0;L;;;;;N;;;;;
+A2D2;YI SYLLABLE ZZI;Lo;0;L;;;;;N;;;;;
+A2D3;YI SYLLABLE ZZIP;Lo;0;L;;;;;N;;;;;
+A2D4;YI SYLLABLE ZZIET;Lo;0;L;;;;;N;;;;;
+A2D5;YI SYLLABLE ZZIEX;Lo;0;L;;;;;N;;;;;
+A2D6;YI SYLLABLE ZZIE;Lo;0;L;;;;;N;;;;;
+A2D7;YI SYLLABLE ZZIEP;Lo;0;L;;;;;N;;;;;
+A2D8;YI SYLLABLE ZZAT;Lo;0;L;;;;;N;;;;;
+A2D9;YI SYLLABLE ZZAX;Lo;0;L;;;;;N;;;;;
+A2DA;YI SYLLABLE ZZA;Lo;0;L;;;;;N;;;;;
+A2DB;YI SYLLABLE ZZAP;Lo;0;L;;;;;N;;;;;
+A2DC;YI SYLLABLE ZZOX;Lo;0;L;;;;;N;;;;;
+A2DD;YI SYLLABLE ZZO;Lo;0;L;;;;;N;;;;;
+A2DE;YI SYLLABLE ZZOP;Lo;0;L;;;;;N;;;;;
+A2DF;YI SYLLABLE ZZEX;Lo;0;L;;;;;N;;;;;
+A2E0;YI SYLLABLE ZZE;Lo;0;L;;;;;N;;;;;
+A2E1;YI SYLLABLE ZZEP;Lo;0;L;;;;;N;;;;;
+A2E2;YI SYLLABLE ZZUX;Lo;0;L;;;;;N;;;;;
+A2E3;YI SYLLABLE ZZU;Lo;0;L;;;;;N;;;;;
+A2E4;YI SYLLABLE ZZUP;Lo;0;L;;;;;N;;;;;
+A2E5;YI SYLLABLE ZZURX;Lo;0;L;;;;;N;;;;;
+A2E6;YI SYLLABLE ZZUR;Lo;0;L;;;;;N;;;;;
+A2E7;YI SYLLABLE ZZYT;Lo;0;L;;;;;N;;;;;
+A2E8;YI SYLLABLE ZZYX;Lo;0;L;;;;;N;;;;;
+A2E9;YI SYLLABLE ZZY;Lo;0;L;;;;;N;;;;;
+A2EA;YI SYLLABLE ZZYP;Lo;0;L;;;;;N;;;;;
+A2EB;YI SYLLABLE ZZYRX;Lo;0;L;;;;;N;;;;;
+A2EC;YI SYLLABLE ZZYR;Lo;0;L;;;;;N;;;;;
+A2ED;YI SYLLABLE NZIT;Lo;0;L;;;;;N;;;;;
+A2EE;YI SYLLABLE NZIX;Lo;0;L;;;;;N;;;;;
+A2EF;YI SYLLABLE NZI;Lo;0;L;;;;;N;;;;;
+A2F0;YI SYLLABLE NZIP;Lo;0;L;;;;;N;;;;;
+A2F1;YI SYLLABLE NZIEX;Lo;0;L;;;;;N;;;;;
+A2F2;YI SYLLABLE NZIE;Lo;0;L;;;;;N;;;;;
+A2F3;YI SYLLABLE NZIEP;Lo;0;L;;;;;N;;;;;
+A2F4;YI SYLLABLE NZAT;Lo;0;L;;;;;N;;;;;
+A2F5;YI SYLLABLE NZAX;Lo;0;L;;;;;N;;;;;
+A2F6;YI SYLLABLE NZA;Lo;0;L;;;;;N;;;;;
+A2F7;YI SYLLABLE NZAP;Lo;0;L;;;;;N;;;;;
+A2F8;YI SYLLABLE NZUOX;Lo;0;L;;;;;N;;;;;
+A2F9;YI SYLLABLE NZUO;Lo;0;L;;;;;N;;;;;
+A2FA;YI SYLLABLE NZOX;Lo;0;L;;;;;N;;;;;
+A2FB;YI SYLLABLE NZOP;Lo;0;L;;;;;N;;;;;
+A2FC;YI SYLLABLE NZEX;Lo;0;L;;;;;N;;;;;
+A2FD;YI SYLLABLE NZE;Lo;0;L;;;;;N;;;;;
+A2FE;YI SYLLABLE NZUX;Lo;0;L;;;;;N;;;;;
+A2FF;YI SYLLABLE NZU;Lo;0;L;;;;;N;;;;;
+A300;YI SYLLABLE NZUP;Lo;0;L;;;;;N;;;;;
+A301;YI SYLLABLE NZURX;Lo;0;L;;;;;N;;;;;
+A302;YI SYLLABLE NZUR;Lo;0;L;;;;;N;;;;;
+A303;YI SYLLABLE NZYT;Lo;0;L;;;;;N;;;;;
+A304;YI SYLLABLE NZYX;Lo;0;L;;;;;N;;;;;
+A305;YI SYLLABLE NZY;Lo;0;L;;;;;N;;;;;
+A306;YI SYLLABLE NZYP;Lo;0;L;;;;;N;;;;;
+A307;YI SYLLABLE NZYRX;Lo;0;L;;;;;N;;;;;
+A308;YI SYLLABLE NZYR;Lo;0;L;;;;;N;;;;;
+A309;YI SYLLABLE SIT;Lo;0;L;;;;;N;;;;;
+A30A;YI SYLLABLE SIX;Lo;0;L;;;;;N;;;;;
+A30B;YI SYLLABLE SI;Lo;0;L;;;;;N;;;;;
+A30C;YI SYLLABLE SIP;Lo;0;L;;;;;N;;;;;
+A30D;YI SYLLABLE SIEX;Lo;0;L;;;;;N;;;;;
+A30E;YI SYLLABLE SIE;Lo;0;L;;;;;N;;;;;
+A30F;YI SYLLABLE SIEP;Lo;0;L;;;;;N;;;;;
+A310;YI SYLLABLE SAT;Lo;0;L;;;;;N;;;;;
+A311;YI SYLLABLE SAX;Lo;0;L;;;;;N;;;;;
+A312;YI SYLLABLE SA;Lo;0;L;;;;;N;;;;;
+A313;YI SYLLABLE SAP;Lo;0;L;;;;;N;;;;;
+A314;YI SYLLABLE SUOX;Lo;0;L;;;;;N;;;;;
+A315;YI SYLLABLE SUO;Lo;0;L;;;;;N;;;;;
+A316;YI SYLLABLE SUOP;Lo;0;L;;;;;N;;;;;
+A317;YI SYLLABLE SOT;Lo;0;L;;;;;N;;;;;
+A318;YI SYLLABLE SOX;Lo;0;L;;;;;N;;;;;
+A319;YI SYLLABLE SO;Lo;0;L;;;;;N;;;;;
+A31A;YI SYLLABLE SOP;Lo;0;L;;;;;N;;;;;
+A31B;YI SYLLABLE SEX;Lo;0;L;;;;;N;;;;;
+A31C;YI SYLLABLE SE;Lo;0;L;;;;;N;;;;;
+A31D;YI SYLLABLE SEP;Lo;0;L;;;;;N;;;;;
+A31E;YI SYLLABLE SUT;Lo;0;L;;;;;N;;;;;
+A31F;YI SYLLABLE SUX;Lo;0;L;;;;;N;;;;;
+A320;YI SYLLABLE SU;Lo;0;L;;;;;N;;;;;
+A321;YI SYLLABLE SUP;Lo;0;L;;;;;N;;;;;
+A322;YI SYLLABLE SURX;Lo;0;L;;;;;N;;;;;
+A323;YI SYLLABLE SUR;Lo;0;L;;;;;N;;;;;
+A324;YI SYLLABLE SYT;Lo;0;L;;;;;N;;;;;
+A325;YI SYLLABLE SYX;Lo;0;L;;;;;N;;;;;
+A326;YI SYLLABLE SY;Lo;0;L;;;;;N;;;;;
+A327;YI SYLLABLE SYP;Lo;0;L;;;;;N;;;;;
+A328;YI SYLLABLE SYRX;Lo;0;L;;;;;N;;;;;
+A329;YI SYLLABLE SYR;Lo;0;L;;;;;N;;;;;
+A32A;YI SYLLABLE SSIT;Lo;0;L;;;;;N;;;;;
+A32B;YI SYLLABLE SSIX;Lo;0;L;;;;;N;;;;;
+A32C;YI SYLLABLE SSI;Lo;0;L;;;;;N;;;;;
+A32D;YI SYLLABLE SSIP;Lo;0;L;;;;;N;;;;;
+A32E;YI SYLLABLE SSIEX;Lo;0;L;;;;;N;;;;;
+A32F;YI SYLLABLE SSIE;Lo;0;L;;;;;N;;;;;
+A330;YI SYLLABLE SSIEP;Lo;0;L;;;;;N;;;;;
+A331;YI SYLLABLE SSAT;Lo;0;L;;;;;N;;;;;
+A332;YI SYLLABLE SSAX;Lo;0;L;;;;;N;;;;;
+A333;YI SYLLABLE SSA;Lo;0;L;;;;;N;;;;;
+A334;YI SYLLABLE SSAP;Lo;0;L;;;;;N;;;;;
+A335;YI SYLLABLE SSOT;Lo;0;L;;;;;N;;;;;
+A336;YI SYLLABLE SSOX;Lo;0;L;;;;;N;;;;;
+A337;YI SYLLABLE SSO;Lo;0;L;;;;;N;;;;;
+A338;YI SYLLABLE SSOP;Lo;0;L;;;;;N;;;;;
+A339;YI SYLLABLE SSEX;Lo;0;L;;;;;N;;;;;
+A33A;YI SYLLABLE SSE;Lo;0;L;;;;;N;;;;;
+A33B;YI SYLLABLE SSEP;Lo;0;L;;;;;N;;;;;
+A33C;YI SYLLABLE SSUT;Lo;0;L;;;;;N;;;;;
+A33D;YI SYLLABLE SSUX;Lo;0;L;;;;;N;;;;;
+A33E;YI SYLLABLE SSU;Lo;0;L;;;;;N;;;;;
+A33F;YI SYLLABLE SSUP;Lo;0;L;;;;;N;;;;;
+A340;YI SYLLABLE SSYT;Lo;0;L;;;;;N;;;;;
+A341;YI SYLLABLE SSYX;Lo;0;L;;;;;N;;;;;
+A342;YI SYLLABLE SSY;Lo;0;L;;;;;N;;;;;
+A343;YI SYLLABLE SSYP;Lo;0;L;;;;;N;;;;;
+A344;YI SYLLABLE SSYRX;Lo;0;L;;;;;N;;;;;
+A345;YI SYLLABLE SSYR;Lo;0;L;;;;;N;;;;;
+A346;YI SYLLABLE ZHAT;Lo;0;L;;;;;N;;;;;
+A347;YI SYLLABLE ZHAX;Lo;0;L;;;;;N;;;;;
+A348;YI SYLLABLE ZHA;Lo;0;L;;;;;N;;;;;
+A349;YI SYLLABLE ZHAP;Lo;0;L;;;;;N;;;;;
+A34A;YI SYLLABLE ZHUOX;Lo;0;L;;;;;N;;;;;
+A34B;YI SYLLABLE ZHUO;Lo;0;L;;;;;N;;;;;
+A34C;YI SYLLABLE ZHUOP;Lo;0;L;;;;;N;;;;;
+A34D;YI SYLLABLE ZHOT;Lo;0;L;;;;;N;;;;;
+A34E;YI SYLLABLE ZHOX;Lo;0;L;;;;;N;;;;;
+A34F;YI SYLLABLE ZHO;Lo;0;L;;;;;N;;;;;
+A350;YI SYLLABLE ZHOP;Lo;0;L;;;;;N;;;;;
+A351;YI SYLLABLE ZHET;Lo;0;L;;;;;N;;;;;
+A352;YI SYLLABLE ZHEX;Lo;0;L;;;;;N;;;;;
+A353;YI SYLLABLE ZHE;Lo;0;L;;;;;N;;;;;
+A354;YI SYLLABLE ZHEP;Lo;0;L;;;;;N;;;;;
+A355;YI SYLLABLE ZHUT;Lo;0;L;;;;;N;;;;;
+A356;YI SYLLABLE ZHUX;Lo;0;L;;;;;N;;;;;
+A357;YI SYLLABLE ZHU;Lo;0;L;;;;;N;;;;;
+A358;YI SYLLABLE ZHUP;Lo;0;L;;;;;N;;;;;
+A359;YI SYLLABLE ZHURX;Lo;0;L;;;;;N;;;;;
+A35A;YI SYLLABLE ZHUR;Lo;0;L;;;;;N;;;;;
+A35B;YI SYLLABLE ZHYT;Lo;0;L;;;;;N;;;;;
+A35C;YI SYLLABLE ZHYX;Lo;0;L;;;;;N;;;;;
+A35D;YI SYLLABLE ZHY;Lo;0;L;;;;;N;;;;;
+A35E;YI SYLLABLE ZHYP;Lo;0;L;;;;;N;;;;;
+A35F;YI SYLLABLE ZHYRX;Lo;0;L;;;;;N;;;;;
+A360;YI SYLLABLE ZHYR;Lo;0;L;;;;;N;;;;;
+A361;YI SYLLABLE CHAT;Lo;0;L;;;;;N;;;;;
+A362;YI SYLLABLE CHAX;Lo;0;L;;;;;N;;;;;
+A363;YI SYLLABLE CHA;Lo;0;L;;;;;N;;;;;
+A364;YI SYLLABLE CHAP;Lo;0;L;;;;;N;;;;;
+A365;YI SYLLABLE CHUOT;Lo;0;L;;;;;N;;;;;
+A366;YI SYLLABLE CHUOX;Lo;0;L;;;;;N;;;;;
+A367;YI SYLLABLE CHUO;Lo;0;L;;;;;N;;;;;
+A368;YI SYLLABLE CHUOP;Lo;0;L;;;;;N;;;;;
+A369;YI SYLLABLE CHOT;Lo;0;L;;;;;N;;;;;
+A36A;YI SYLLABLE CHOX;Lo;0;L;;;;;N;;;;;
+A36B;YI SYLLABLE CHO;Lo;0;L;;;;;N;;;;;
+A36C;YI SYLLABLE CHOP;Lo;0;L;;;;;N;;;;;
+A36D;YI SYLLABLE CHET;Lo;0;L;;;;;N;;;;;
+A36E;YI SYLLABLE CHEX;Lo;0;L;;;;;N;;;;;
+A36F;YI SYLLABLE CHE;Lo;0;L;;;;;N;;;;;
+A370;YI SYLLABLE CHEP;Lo;0;L;;;;;N;;;;;
+A371;YI SYLLABLE CHUX;Lo;0;L;;;;;N;;;;;
+A372;YI SYLLABLE CHU;Lo;0;L;;;;;N;;;;;
+A373;YI SYLLABLE CHUP;Lo;0;L;;;;;N;;;;;
+A374;YI SYLLABLE CHURX;Lo;0;L;;;;;N;;;;;
+A375;YI SYLLABLE CHUR;Lo;0;L;;;;;N;;;;;
+A376;YI SYLLABLE CHYT;Lo;0;L;;;;;N;;;;;
+A377;YI SYLLABLE CHYX;Lo;0;L;;;;;N;;;;;
+A378;YI SYLLABLE CHY;Lo;0;L;;;;;N;;;;;
+A379;YI SYLLABLE CHYP;Lo;0;L;;;;;N;;;;;
+A37A;YI SYLLABLE CHYRX;Lo;0;L;;;;;N;;;;;
+A37B;YI SYLLABLE CHYR;Lo;0;L;;;;;N;;;;;
+A37C;YI SYLLABLE RRAX;Lo;0;L;;;;;N;;;;;
+A37D;YI SYLLABLE RRA;Lo;0;L;;;;;N;;;;;
+A37E;YI SYLLABLE RRUOX;Lo;0;L;;;;;N;;;;;
+A37F;YI SYLLABLE RRUO;Lo;0;L;;;;;N;;;;;
+A380;YI SYLLABLE RROT;Lo;0;L;;;;;N;;;;;
+A381;YI SYLLABLE RROX;Lo;0;L;;;;;N;;;;;
+A382;YI SYLLABLE RRO;Lo;0;L;;;;;N;;;;;
+A383;YI SYLLABLE RROP;Lo;0;L;;;;;N;;;;;
+A384;YI SYLLABLE RRET;Lo;0;L;;;;;N;;;;;
+A385;YI SYLLABLE RREX;Lo;0;L;;;;;N;;;;;
+A386;YI SYLLABLE RRE;Lo;0;L;;;;;N;;;;;
+A387;YI SYLLABLE RREP;Lo;0;L;;;;;N;;;;;
+A388;YI SYLLABLE RRUT;Lo;0;L;;;;;N;;;;;
+A389;YI SYLLABLE RRUX;Lo;0;L;;;;;N;;;;;
+A38A;YI SYLLABLE RRU;Lo;0;L;;;;;N;;;;;
+A38B;YI SYLLABLE RRUP;Lo;0;L;;;;;N;;;;;
+A38C;YI SYLLABLE RRURX;Lo;0;L;;;;;N;;;;;
+A38D;YI SYLLABLE RRUR;Lo;0;L;;;;;N;;;;;
+A38E;YI SYLLABLE RRYT;Lo;0;L;;;;;N;;;;;
+A38F;YI SYLLABLE RRYX;Lo;0;L;;;;;N;;;;;
+A390;YI SYLLABLE RRY;Lo;0;L;;;;;N;;;;;
+A391;YI SYLLABLE RRYP;Lo;0;L;;;;;N;;;;;
+A392;YI SYLLABLE RRYRX;Lo;0;L;;;;;N;;;;;
+A393;YI SYLLABLE RRYR;Lo;0;L;;;;;N;;;;;
+A394;YI SYLLABLE NRAT;Lo;0;L;;;;;N;;;;;
+A395;YI SYLLABLE NRAX;Lo;0;L;;;;;N;;;;;
+A396;YI SYLLABLE NRA;Lo;0;L;;;;;N;;;;;
+A397;YI SYLLABLE NRAP;Lo;0;L;;;;;N;;;;;
+A398;YI SYLLABLE NROX;Lo;0;L;;;;;N;;;;;
+A399;YI SYLLABLE NRO;Lo;0;L;;;;;N;;;;;
+A39A;YI SYLLABLE NROP;Lo;0;L;;;;;N;;;;;
+A39B;YI SYLLABLE NRET;Lo;0;L;;;;;N;;;;;
+A39C;YI SYLLABLE NREX;Lo;0;L;;;;;N;;;;;
+A39D;YI SYLLABLE NRE;Lo;0;L;;;;;N;;;;;
+A39E;YI SYLLABLE NREP;Lo;0;L;;;;;N;;;;;
+A39F;YI SYLLABLE NRUT;Lo;0;L;;;;;N;;;;;
+A3A0;YI SYLLABLE NRUX;Lo;0;L;;;;;N;;;;;
+A3A1;YI SYLLABLE NRU;Lo;0;L;;;;;N;;;;;
+A3A2;YI SYLLABLE NRUP;Lo;0;L;;;;;N;;;;;
+A3A3;YI SYLLABLE NRURX;Lo;0;L;;;;;N;;;;;
+A3A4;YI SYLLABLE NRUR;Lo;0;L;;;;;N;;;;;
+A3A5;YI SYLLABLE NRYT;Lo;0;L;;;;;N;;;;;
+A3A6;YI SYLLABLE NRYX;Lo;0;L;;;;;N;;;;;
+A3A7;YI SYLLABLE NRY;Lo;0;L;;;;;N;;;;;
+A3A8;YI SYLLABLE NRYP;Lo;0;L;;;;;N;;;;;
+A3A9;YI SYLLABLE NRYRX;Lo;0;L;;;;;N;;;;;
+A3AA;YI SYLLABLE NRYR;Lo;0;L;;;;;N;;;;;
+A3AB;YI SYLLABLE SHAT;Lo;0;L;;;;;N;;;;;
+A3AC;YI SYLLABLE SHAX;Lo;0;L;;;;;N;;;;;
+A3AD;YI SYLLABLE SHA;Lo;0;L;;;;;N;;;;;
+A3AE;YI SYLLABLE SHAP;Lo;0;L;;;;;N;;;;;
+A3AF;YI SYLLABLE SHUOX;Lo;0;L;;;;;N;;;;;
+A3B0;YI SYLLABLE SHUO;Lo;0;L;;;;;N;;;;;
+A3B1;YI SYLLABLE SHUOP;Lo;0;L;;;;;N;;;;;
+A3B2;YI SYLLABLE SHOT;Lo;0;L;;;;;N;;;;;
+A3B3;YI SYLLABLE SHOX;Lo;0;L;;;;;N;;;;;
+A3B4;YI SYLLABLE SHO;Lo;0;L;;;;;N;;;;;
+A3B5;YI SYLLABLE SHOP;Lo;0;L;;;;;N;;;;;
+A3B6;YI SYLLABLE SHET;Lo;0;L;;;;;N;;;;;
+A3B7;YI SYLLABLE SHEX;Lo;0;L;;;;;N;;;;;
+A3B8;YI SYLLABLE SHE;Lo;0;L;;;;;N;;;;;
+A3B9;YI SYLLABLE SHEP;Lo;0;L;;;;;N;;;;;
+A3BA;YI SYLLABLE SHUT;Lo;0;L;;;;;N;;;;;
+A3BB;YI SYLLABLE SHUX;Lo;0;L;;;;;N;;;;;
+A3BC;YI SYLLABLE SHU;Lo;0;L;;;;;N;;;;;
+A3BD;YI SYLLABLE SHUP;Lo;0;L;;;;;N;;;;;
+A3BE;YI SYLLABLE SHURX;Lo;0;L;;;;;N;;;;;
+A3BF;YI SYLLABLE SHUR;Lo;0;L;;;;;N;;;;;
+A3C0;YI SYLLABLE SHYT;Lo;0;L;;;;;N;;;;;
+A3C1;YI SYLLABLE SHYX;Lo;0;L;;;;;N;;;;;
+A3C2;YI SYLLABLE SHY;Lo;0;L;;;;;N;;;;;
+A3C3;YI SYLLABLE SHYP;Lo;0;L;;;;;N;;;;;
+A3C4;YI SYLLABLE SHYRX;Lo;0;L;;;;;N;;;;;
+A3C5;YI SYLLABLE SHYR;Lo;0;L;;;;;N;;;;;
+A3C6;YI SYLLABLE RAT;Lo;0;L;;;;;N;;;;;
+A3C7;YI SYLLABLE RAX;Lo;0;L;;;;;N;;;;;
+A3C8;YI SYLLABLE RA;Lo;0;L;;;;;N;;;;;
+A3C9;YI SYLLABLE RAP;Lo;0;L;;;;;N;;;;;
+A3CA;YI SYLLABLE RUOX;Lo;0;L;;;;;N;;;;;
+A3CB;YI SYLLABLE RUO;Lo;0;L;;;;;N;;;;;
+A3CC;YI SYLLABLE RUOP;Lo;0;L;;;;;N;;;;;
+A3CD;YI SYLLABLE ROT;Lo;0;L;;;;;N;;;;;
+A3CE;YI SYLLABLE ROX;Lo;0;L;;;;;N;;;;;
+A3CF;YI SYLLABLE RO;Lo;0;L;;;;;N;;;;;
+A3D0;YI SYLLABLE ROP;Lo;0;L;;;;;N;;;;;
+A3D1;YI SYLLABLE REX;Lo;0;L;;;;;N;;;;;
+A3D2;YI SYLLABLE RE;Lo;0;L;;;;;N;;;;;
+A3D3;YI SYLLABLE REP;Lo;0;L;;;;;N;;;;;
+A3D4;YI SYLLABLE RUT;Lo;0;L;;;;;N;;;;;
+A3D5;YI SYLLABLE RUX;Lo;0;L;;;;;N;;;;;
+A3D6;YI SYLLABLE RU;Lo;0;L;;;;;N;;;;;
+A3D7;YI SYLLABLE RUP;Lo;0;L;;;;;N;;;;;
+A3D8;YI SYLLABLE RURX;Lo;0;L;;;;;N;;;;;
+A3D9;YI SYLLABLE RUR;Lo;0;L;;;;;N;;;;;
+A3DA;YI SYLLABLE RYT;Lo;0;L;;;;;N;;;;;
+A3DB;YI SYLLABLE RYX;Lo;0;L;;;;;N;;;;;
+A3DC;YI SYLLABLE RY;Lo;0;L;;;;;N;;;;;
+A3DD;YI SYLLABLE RYP;Lo;0;L;;;;;N;;;;;
+A3DE;YI SYLLABLE RYRX;Lo;0;L;;;;;N;;;;;
+A3DF;YI SYLLABLE RYR;Lo;0;L;;;;;N;;;;;
+A3E0;YI SYLLABLE JIT;Lo;0;L;;;;;N;;;;;
+A3E1;YI SYLLABLE JIX;Lo;0;L;;;;;N;;;;;
+A3E2;YI SYLLABLE JI;Lo;0;L;;;;;N;;;;;
+A3E3;YI SYLLABLE JIP;Lo;0;L;;;;;N;;;;;
+A3E4;YI SYLLABLE JIET;Lo;0;L;;;;;N;;;;;
+A3E5;YI SYLLABLE JIEX;Lo;0;L;;;;;N;;;;;
+A3E6;YI SYLLABLE JIE;Lo;0;L;;;;;N;;;;;
+A3E7;YI SYLLABLE JIEP;Lo;0;L;;;;;N;;;;;
+A3E8;YI SYLLABLE JUOT;Lo;0;L;;;;;N;;;;;
+A3E9;YI SYLLABLE JUOX;Lo;0;L;;;;;N;;;;;
+A3EA;YI SYLLABLE JUO;Lo;0;L;;;;;N;;;;;
+A3EB;YI SYLLABLE JUOP;Lo;0;L;;;;;N;;;;;
+A3EC;YI SYLLABLE JOT;Lo;0;L;;;;;N;;;;;
+A3ED;YI SYLLABLE JOX;Lo;0;L;;;;;N;;;;;
+A3EE;YI SYLLABLE JO;Lo;0;L;;;;;N;;;;;
+A3EF;YI SYLLABLE JOP;Lo;0;L;;;;;N;;;;;
+A3F0;YI SYLLABLE JUT;Lo;0;L;;;;;N;;;;;
+A3F1;YI SYLLABLE JUX;Lo;0;L;;;;;N;;;;;
+A3F2;YI SYLLABLE JU;Lo;0;L;;;;;N;;;;;
+A3F3;YI SYLLABLE JUP;Lo;0;L;;;;;N;;;;;
+A3F4;YI SYLLABLE JURX;Lo;0;L;;;;;N;;;;;
+A3F5;YI SYLLABLE JUR;Lo;0;L;;;;;N;;;;;
+A3F6;YI SYLLABLE JYT;Lo;0;L;;;;;N;;;;;
+A3F7;YI SYLLABLE JYX;Lo;0;L;;;;;N;;;;;
+A3F8;YI SYLLABLE JY;Lo;0;L;;;;;N;;;;;
+A3F9;YI SYLLABLE JYP;Lo;0;L;;;;;N;;;;;
+A3FA;YI SYLLABLE JYRX;Lo;0;L;;;;;N;;;;;
+A3FB;YI SYLLABLE JYR;Lo;0;L;;;;;N;;;;;
+A3FC;YI SYLLABLE QIT;Lo;0;L;;;;;N;;;;;
+A3FD;YI SYLLABLE QIX;Lo;0;L;;;;;N;;;;;
+A3FE;YI SYLLABLE QI;Lo;0;L;;;;;N;;;;;
+A3FF;YI SYLLABLE QIP;Lo;0;L;;;;;N;;;;;
+A400;YI SYLLABLE QIET;Lo;0;L;;;;;N;;;;;
+A401;YI SYLLABLE QIEX;Lo;0;L;;;;;N;;;;;
+A402;YI SYLLABLE QIE;Lo;0;L;;;;;N;;;;;
+A403;YI SYLLABLE QIEP;Lo;0;L;;;;;N;;;;;
+A404;YI SYLLABLE QUOT;Lo;0;L;;;;;N;;;;;
+A405;YI SYLLABLE QUOX;Lo;0;L;;;;;N;;;;;
+A406;YI SYLLABLE QUO;Lo;0;L;;;;;N;;;;;
+A407;YI SYLLABLE QUOP;Lo;0;L;;;;;N;;;;;
+A408;YI SYLLABLE QOT;Lo;0;L;;;;;N;;;;;
+A409;YI SYLLABLE QOX;Lo;0;L;;;;;N;;;;;
+A40A;YI SYLLABLE QO;Lo;0;L;;;;;N;;;;;
+A40B;YI SYLLABLE QOP;Lo;0;L;;;;;N;;;;;
+A40C;YI SYLLABLE QUT;Lo;0;L;;;;;N;;;;;
+A40D;YI SYLLABLE QUX;Lo;0;L;;;;;N;;;;;
+A40E;YI SYLLABLE QU;Lo;0;L;;;;;N;;;;;
+A40F;YI SYLLABLE QUP;Lo;0;L;;;;;N;;;;;
+A410;YI SYLLABLE QURX;Lo;0;L;;;;;N;;;;;
+A411;YI SYLLABLE QUR;Lo;0;L;;;;;N;;;;;
+A412;YI SYLLABLE QYT;Lo;0;L;;;;;N;;;;;
+A413;YI SYLLABLE QYX;Lo;0;L;;;;;N;;;;;
+A414;YI SYLLABLE QY;Lo;0;L;;;;;N;;;;;
+A415;YI SYLLABLE QYP;Lo;0;L;;;;;N;;;;;
+A416;YI SYLLABLE QYRX;Lo;0;L;;;;;N;;;;;
+A417;YI SYLLABLE QYR;Lo;0;L;;;;;N;;;;;
+A418;YI SYLLABLE JJIT;Lo;0;L;;;;;N;;;;;
+A419;YI SYLLABLE JJIX;Lo;0;L;;;;;N;;;;;
+A41A;YI SYLLABLE JJI;Lo;0;L;;;;;N;;;;;
+A41B;YI SYLLABLE JJIP;Lo;0;L;;;;;N;;;;;
+A41C;YI SYLLABLE JJIET;Lo;0;L;;;;;N;;;;;
+A41D;YI SYLLABLE JJIEX;Lo;0;L;;;;;N;;;;;
+A41E;YI SYLLABLE JJIE;Lo;0;L;;;;;N;;;;;
+A41F;YI SYLLABLE JJIEP;Lo;0;L;;;;;N;;;;;
+A420;YI SYLLABLE JJUOX;Lo;0;L;;;;;N;;;;;
+A421;YI SYLLABLE JJUO;Lo;0;L;;;;;N;;;;;
+A422;YI SYLLABLE JJUOP;Lo;0;L;;;;;N;;;;;
+A423;YI SYLLABLE JJOT;Lo;0;L;;;;;N;;;;;
+A424;YI SYLLABLE JJOX;Lo;0;L;;;;;N;;;;;
+A425;YI SYLLABLE JJO;Lo;0;L;;;;;N;;;;;
+A426;YI SYLLABLE JJOP;Lo;0;L;;;;;N;;;;;
+A427;YI SYLLABLE JJUT;Lo;0;L;;;;;N;;;;;
+A428;YI SYLLABLE JJUX;Lo;0;L;;;;;N;;;;;
+A429;YI SYLLABLE JJU;Lo;0;L;;;;;N;;;;;
+A42A;YI SYLLABLE JJUP;Lo;0;L;;;;;N;;;;;
+A42B;YI SYLLABLE JJURX;Lo;0;L;;;;;N;;;;;
+A42C;YI SYLLABLE JJUR;Lo;0;L;;;;;N;;;;;
+A42D;YI SYLLABLE JJYT;Lo;0;L;;;;;N;;;;;
+A42E;YI SYLLABLE JJYX;Lo;0;L;;;;;N;;;;;
+A42F;YI SYLLABLE JJY;Lo;0;L;;;;;N;;;;;
+A430;YI SYLLABLE JJYP;Lo;0;L;;;;;N;;;;;
+A431;YI SYLLABLE NJIT;Lo;0;L;;;;;N;;;;;
+A432;YI SYLLABLE NJIX;Lo;0;L;;;;;N;;;;;
+A433;YI SYLLABLE NJI;Lo;0;L;;;;;N;;;;;
+A434;YI SYLLABLE NJIP;Lo;0;L;;;;;N;;;;;
+A435;YI SYLLABLE NJIET;Lo;0;L;;;;;N;;;;;
+A436;YI SYLLABLE NJIEX;Lo;0;L;;;;;N;;;;;
+A437;YI SYLLABLE NJIE;Lo;0;L;;;;;N;;;;;
+A438;YI SYLLABLE NJIEP;Lo;0;L;;;;;N;;;;;
+A439;YI SYLLABLE NJUOX;Lo;0;L;;;;;N;;;;;
+A43A;YI SYLLABLE NJUO;Lo;0;L;;;;;N;;;;;
+A43B;YI SYLLABLE NJOT;Lo;0;L;;;;;N;;;;;
+A43C;YI SYLLABLE NJOX;Lo;0;L;;;;;N;;;;;
+A43D;YI SYLLABLE NJO;Lo;0;L;;;;;N;;;;;
+A43E;YI SYLLABLE NJOP;Lo;0;L;;;;;N;;;;;
+A43F;YI SYLLABLE NJUX;Lo;0;L;;;;;N;;;;;
+A440;YI SYLLABLE NJU;Lo;0;L;;;;;N;;;;;
+A441;YI SYLLABLE NJUP;Lo;0;L;;;;;N;;;;;
+A442;YI SYLLABLE NJURX;Lo;0;L;;;;;N;;;;;
+A443;YI SYLLABLE NJUR;Lo;0;L;;;;;N;;;;;
+A444;YI SYLLABLE NJYT;Lo;0;L;;;;;N;;;;;
+A445;YI SYLLABLE NJYX;Lo;0;L;;;;;N;;;;;
+A446;YI SYLLABLE NJY;Lo;0;L;;;;;N;;;;;
+A447;YI SYLLABLE NJYP;Lo;0;L;;;;;N;;;;;
+A448;YI SYLLABLE NJYRX;Lo;0;L;;;;;N;;;;;
+A449;YI SYLLABLE NJYR;Lo;0;L;;;;;N;;;;;
+A44A;YI SYLLABLE NYIT;Lo;0;L;;;;;N;;;;;
+A44B;YI SYLLABLE NYIX;Lo;0;L;;;;;N;;;;;
+A44C;YI SYLLABLE NYI;Lo;0;L;;;;;N;;;;;
+A44D;YI SYLLABLE NYIP;Lo;0;L;;;;;N;;;;;
+A44E;YI SYLLABLE NYIET;Lo;0;L;;;;;N;;;;;
+A44F;YI SYLLABLE NYIEX;Lo;0;L;;;;;N;;;;;
+A450;YI SYLLABLE NYIE;Lo;0;L;;;;;N;;;;;
+A451;YI SYLLABLE NYIEP;Lo;0;L;;;;;N;;;;;
+A452;YI SYLLABLE NYUOX;Lo;0;L;;;;;N;;;;;
+A453;YI SYLLABLE NYUO;Lo;0;L;;;;;N;;;;;
+A454;YI SYLLABLE NYUOP;Lo;0;L;;;;;N;;;;;
+A455;YI SYLLABLE NYOT;Lo;0;L;;;;;N;;;;;
+A456;YI SYLLABLE NYOX;Lo;0;L;;;;;N;;;;;
+A457;YI SYLLABLE NYO;Lo;0;L;;;;;N;;;;;
+A458;YI SYLLABLE NYOP;Lo;0;L;;;;;N;;;;;
+A459;YI SYLLABLE NYUT;Lo;0;L;;;;;N;;;;;
+A45A;YI SYLLABLE NYUX;Lo;0;L;;;;;N;;;;;
+A45B;YI SYLLABLE NYU;Lo;0;L;;;;;N;;;;;
+A45C;YI SYLLABLE NYUP;Lo;0;L;;;;;N;;;;;
+A45D;YI SYLLABLE XIT;Lo;0;L;;;;;N;;;;;
+A45E;YI SYLLABLE XIX;Lo;0;L;;;;;N;;;;;
+A45F;YI SYLLABLE XI;Lo;0;L;;;;;N;;;;;
+A460;YI SYLLABLE XIP;Lo;0;L;;;;;N;;;;;
+A461;YI SYLLABLE XIET;Lo;0;L;;;;;N;;;;;
+A462;YI SYLLABLE XIEX;Lo;0;L;;;;;N;;;;;
+A463;YI SYLLABLE XIE;Lo;0;L;;;;;N;;;;;
+A464;YI SYLLABLE XIEP;Lo;0;L;;;;;N;;;;;
+A465;YI SYLLABLE XUOX;Lo;0;L;;;;;N;;;;;
+A466;YI SYLLABLE XUO;Lo;0;L;;;;;N;;;;;
+A467;YI SYLLABLE XOT;Lo;0;L;;;;;N;;;;;
+A468;YI SYLLABLE XOX;Lo;0;L;;;;;N;;;;;
+A469;YI SYLLABLE XO;Lo;0;L;;;;;N;;;;;
+A46A;YI SYLLABLE XOP;Lo;0;L;;;;;N;;;;;
+A46B;YI SYLLABLE XYT;Lo;0;L;;;;;N;;;;;
+A46C;YI SYLLABLE XYX;Lo;0;L;;;;;N;;;;;
+A46D;YI SYLLABLE XY;Lo;0;L;;;;;N;;;;;
+A46E;YI SYLLABLE XYP;Lo;0;L;;;;;N;;;;;
+A46F;YI SYLLABLE XYRX;Lo;0;L;;;;;N;;;;;
+A470;YI SYLLABLE XYR;Lo;0;L;;;;;N;;;;;
+A471;YI SYLLABLE YIT;Lo;0;L;;;;;N;;;;;
+A472;YI SYLLABLE YIX;Lo;0;L;;;;;N;;;;;
+A473;YI SYLLABLE YI;Lo;0;L;;;;;N;;;;;
+A474;YI SYLLABLE YIP;Lo;0;L;;;;;N;;;;;
+A475;YI SYLLABLE YIET;Lo;0;L;;;;;N;;;;;
+A476;YI SYLLABLE YIEX;Lo;0;L;;;;;N;;;;;
+A477;YI SYLLABLE YIE;Lo;0;L;;;;;N;;;;;
+A478;YI SYLLABLE YIEP;Lo;0;L;;;;;N;;;;;
+A479;YI SYLLABLE YUOT;Lo;0;L;;;;;N;;;;;
+A47A;YI SYLLABLE YUOX;Lo;0;L;;;;;N;;;;;
+A47B;YI SYLLABLE YUO;Lo;0;L;;;;;N;;;;;
+A47C;YI SYLLABLE YUOP;Lo;0;L;;;;;N;;;;;
+A47D;YI SYLLABLE YOT;Lo;0;L;;;;;N;;;;;
+A47E;YI SYLLABLE YOX;Lo;0;L;;;;;N;;;;;
+A47F;YI SYLLABLE YO;Lo;0;L;;;;;N;;;;;
+A480;YI SYLLABLE YOP;Lo;0;L;;;;;N;;;;;
+A481;YI SYLLABLE YUT;Lo;0;L;;;;;N;;;;;
+A482;YI SYLLABLE YUX;Lo;0;L;;;;;N;;;;;
+A483;YI SYLLABLE YU;Lo;0;L;;;;;N;;;;;
+A484;YI SYLLABLE YUP;Lo;0;L;;;;;N;;;;;
+A485;YI SYLLABLE YURX;Lo;0;L;;;;;N;;;;;
+A486;YI SYLLABLE YUR;Lo;0;L;;;;;N;;;;;
+A487;YI SYLLABLE YYT;Lo;0;L;;;;;N;;;;;
+A488;YI SYLLABLE YYX;Lo;0;L;;;;;N;;;;;
+A489;YI SYLLABLE YY;Lo;0;L;;;;;N;;;;;
+A48A;YI SYLLABLE YYP;Lo;0;L;;;;;N;;;;;
+A48B;YI SYLLABLE YYRX;Lo;0;L;;;;;N;;;;;
+A48C;YI SYLLABLE YYR;Lo;0;L;;;;;N;;;;;
+A490;YI RADICAL QOT;So;0;ON;;;;;N;;;;;
+A491;YI RADICAL LI;So;0;ON;;;;;N;;;;;
+A492;YI RADICAL KIT;So;0;ON;;;;;N;;;;;
+A493;YI RADICAL NYIP;So;0;ON;;;;;N;;;;;
+A494;YI RADICAL CYP;So;0;ON;;;;;N;;;;;
+A495;YI RADICAL SSI;So;0;ON;;;;;N;;;;;
+A496;YI RADICAL GGOP;So;0;ON;;;;;N;;;;;
+A497;YI RADICAL GEP;So;0;ON;;;;;N;;;;;
+A498;YI RADICAL MI;So;0;ON;;;;;N;;;;;
+A499;YI RADICAL HXIT;So;0;ON;;;;;N;;;;;
+A49A;YI RADICAL LYR;So;0;ON;;;;;N;;;;;
+A49B;YI RADICAL BBUT;So;0;ON;;;;;N;;;;;
+A49C;YI RADICAL MOP;So;0;ON;;;;;N;;;;;
+A49D;YI RADICAL YO;So;0;ON;;;;;N;;;;;
+A49E;YI RADICAL PUT;So;0;ON;;;;;N;;;;;
+A49F;YI RADICAL HXUO;So;0;ON;;;;;N;;;;;
+A4A0;YI RADICAL TAT;So;0;ON;;;;;N;;;;;
+A4A1;YI RADICAL GA;So;0;ON;;;;;N;;;;;
+A4A2;YI RADICAL ZUP;So;0;ON;;;;;N;;;;;
+A4A3;YI RADICAL CYT;So;0;ON;;;;;N;;;;;
+A4A4;YI RADICAL DDUR;So;0;ON;;;;;N;;;;;
+A4A5;YI RADICAL BUR;So;0;ON;;;;;N;;;;;
+A4A6;YI RADICAL GGUO;So;0;ON;;;;;N;;;;;
+A4A7;YI RADICAL NYOP;So;0;ON;;;;;N;;;;;
+A4A8;YI RADICAL TU;So;0;ON;;;;;N;;;;;
+A4A9;YI RADICAL OP;So;0;ON;;;;;N;;;;;
+A4AA;YI RADICAL JJUT;So;0;ON;;;;;N;;;;;
+A4AB;YI RADICAL ZOT;So;0;ON;;;;;N;;;;;
+A4AC;YI RADICAL PYT;So;0;ON;;;;;N;;;;;
+A4AD;YI RADICAL HMO;So;0;ON;;;;;N;;;;;
+A4AE;YI RADICAL YIT;So;0;ON;;;;;N;;;;;
+A4AF;YI RADICAL VUR;So;0;ON;;;;;N;;;;;
+A4B0;YI RADICAL SHY;So;0;ON;;;;;N;;;;;
+A4B1;YI RADICAL VEP;So;0;ON;;;;;N;;;;;
+A4B2;YI RADICAL ZA;So;0;ON;;;;;N;;;;;
+A4B3;YI RADICAL JO;So;0;ON;;;;;N;;;;;
+A4B4;YI RADICAL NZUP;So;0;ON;;;;;N;;;;;
+A4B5;YI RADICAL JJY;So;0;ON;;;;;N;;;;;
+A4B6;YI RADICAL GOT;So;0;ON;;;;;N;;;;;
+A4B7;YI RADICAL JJIE;So;0;ON;;;;;N;;;;;
+A4B8;YI RADICAL WO;So;0;ON;;;;;N;;;;;
+A4B9;YI RADICAL DU;So;0;ON;;;;;N;;;;;
+A4BA;YI RADICAL SHUR;So;0;ON;;;;;N;;;;;
+A4BB;YI RADICAL LIE;So;0;ON;;;;;N;;;;;
+A4BC;YI RADICAL CY;So;0;ON;;;;;N;;;;;
+A4BD;YI RADICAL CUOP;So;0;ON;;;;;N;;;;;
+A4BE;YI RADICAL CIP;So;0;ON;;;;;N;;;;;
+A4BF;YI RADICAL HXOP;So;0;ON;;;;;N;;;;;
+A4C0;YI RADICAL SHAT;So;0;ON;;;;;N;;;;;
+A4C1;YI RADICAL ZUR;So;0;ON;;;;;N;;;;;
+A4C2;YI RADICAL SHOP;So;0;ON;;;;;N;;;;;
+A4C3;YI RADICAL CHE;So;0;ON;;;;;N;;;;;
+A4C4;YI RADICAL ZZIET;So;0;ON;;;;;N;;;;;
+A4C5;YI RADICAL NBIE;So;0;ON;;;;;N;;;;;
+A4C6;YI RADICAL KE;So;0;ON;;;;;N;;;;;
+A700;MODIFIER LETTER CHINESE TONE YIN PING;Sk;0;ON;;;;;N;;;;;
+A701;MODIFIER LETTER CHINESE TONE YANG PING;Sk;0;ON;;;;;N;;;;;
+A702;MODIFIER LETTER CHINESE TONE YIN SHANG;Sk;0;ON;;;;;N;;;;;
+A703;MODIFIER LETTER CHINESE TONE YANG SHANG;Sk;0;ON;;;;;N;;;;;
+A704;MODIFIER LETTER CHINESE TONE YIN QU;Sk;0;ON;;;;;N;;;;;
+A705;MODIFIER LETTER CHINESE TONE YANG QU;Sk;0;ON;;;;;N;;;;;
+A706;MODIFIER LETTER CHINESE TONE YIN RU;Sk;0;ON;;;;;N;;;;;
+A707;MODIFIER LETTER CHINESE TONE YANG RU;Sk;0;ON;;;;;N;;;;;
+A708;MODIFIER LETTER EXTRA-HIGH DOTTED TONE BAR;Sk;0;ON;;;;;N;;;;;
+A709;MODIFIER LETTER HIGH DOTTED TONE BAR;Sk;0;ON;;;;;N;;;;;
+A70A;MODIFIER LETTER MID DOTTED TONE BAR;Sk;0;ON;;;;;N;;;;;
+A70B;MODIFIER LETTER LOW DOTTED TONE BAR;Sk;0;ON;;;;;N;;;;;
+A70C;MODIFIER LETTER EXTRA-LOW DOTTED TONE BAR;Sk;0;ON;;;;;N;;;;;
+A70D;MODIFIER LETTER EXTRA-HIGH DOTTED LEFT-STEM TONE BAR;Sk;0;ON;;;;;N;;;;;
+A70E;MODIFIER LETTER HIGH DOTTED LEFT-STEM TONE BAR;Sk;0;ON;;;;;N;;;;;
+A70F;MODIFIER LETTER MID DOTTED LEFT-STEM TONE BAR;Sk;0;ON;;;;;N;;;;;
+A710;MODIFIER LETTER LOW DOTTED LEFT-STEM TONE BAR;Sk;0;ON;;;;;N;;;;;
+A711;MODIFIER LETTER EXTRA-LOW DOTTED LEFT-STEM TONE BAR;Sk;0;ON;;;;;N;;;;;
+A712;MODIFIER LETTER EXTRA-HIGH LEFT-STEM TONE BAR;Sk;0;ON;;;;;N;;;;;
+A713;MODIFIER LETTER HIGH LEFT-STEM TONE BAR;Sk;0;ON;;;;;N;;;;;
+A714;MODIFIER LETTER MID LEFT-STEM TONE BAR;Sk;0;ON;;;;;N;;;;;
+A715;MODIFIER LETTER LOW LEFT-STEM TONE BAR;Sk;0;ON;;;;;N;;;;;
+A716;MODIFIER LETTER EXTRA-LOW LEFT-STEM TONE BAR;Sk;0;ON;;;;;N;;;;;
+A800;SYLOTI NAGRI LETTER A;Lo;0;L;;;;;N;;;;;
+A801;SYLOTI NAGRI LETTER I;Lo;0;L;;;;;N;;;;;
+A802;SYLOTI NAGRI SIGN DVISVARA;Mc;0;NSM;;;;;N;;;;;
+A803;SYLOTI NAGRI LETTER U;Lo;0;L;;;;;N;;;;;
+A804;SYLOTI NAGRI LETTER E;Lo;0;L;;;;;N;;;;;
+A805;SYLOTI NAGRI LETTER O;Lo;0;L;;;;;N;;;;;
+A806;SYLOTI NAGRI SIGN HASANTA;Mn;9;NSM;;;;;N;;;;;
+A807;SYLOTI NAGRI LETTER KO;Lo;0;L;;;;;N;;;;;
+A808;SYLOTI NAGRI LETTER KHO;Lo;0;L;;;;;N;;;;;
+A809;SYLOTI NAGRI LETTER GO;Lo;0;L;;;;;N;;;;;
+A80A;SYLOTI NAGRI LETTER GHO;Lo;0;L;;;;;N;;;;;
+A80B;SYLOTI NAGRI SIGN ANUSVARA;Mn;0;NSM;;;;;N;;;;;
+A80C;SYLOTI NAGRI LETTER CO;Lo;0;L;;;;;N;;;;;
+A80D;SYLOTI NAGRI LETTER CHO;Lo;0;L;;;;;N;;;;;
+A80E;SYLOTI NAGRI LETTER JO;Lo;0;L;;;;;N;;;;;
+A80F;SYLOTI NAGRI LETTER JHO;Lo;0;L;;;;;N;;;;;
+A810;SYLOTI NAGRI LETTER TTO;Lo;0;L;;;;;N;;;;;
+A811;SYLOTI NAGRI LETTER TTHO;Lo;0;L;;;;;N;;;;;
+A812;SYLOTI NAGRI LETTER DDO;Lo;0;L;;;;;N;;;;;
+A813;SYLOTI NAGRI LETTER DDHO;Lo;0;L;;;;;N;;;;;
+A814;SYLOTI NAGRI LETTER TO;Lo;0;L;;;;;N;;;;;
+A815;SYLOTI NAGRI LETTER THO;Lo;0;L;;;;;N;;;;;
+A816;SYLOTI NAGRI LETTER DO;Lo;0;L;;;;;N;;;;;
+A817;SYLOTI NAGRI LETTER DHO;Lo;0;L;;;;;N;;;;;
+A818;SYLOTI NAGRI LETTER NO;Lo;0;L;;;;;N;;;;;
+A819;SYLOTI NAGRI LETTER PO;Lo;0;L;;;;;N;;;;;
+A81A;SYLOTI NAGRI LETTER PHO;Lo;0;L;;;;;N;;;;;
+A81B;SYLOTI NAGRI LETTER BO;Lo;0;L;;;;;N;;;;;
+A81C;SYLOTI NAGRI LETTER BHO;Lo;0;L;;;;;N;;;;;
+A81D;SYLOTI NAGRI LETTER MO;Lo;0;L;;;;;N;;;;;
+A81E;SYLOTI NAGRI LETTER RO;Lo;0;L;;;;;N;;;;;
+A81F;SYLOTI NAGRI LETTER LO;Lo;0;L;;;;;N;;;;;
+A820;SYLOTI NAGRI LETTER RRO;Lo;0;L;;;;;N;;;;;
+A821;SYLOTI NAGRI LETTER SO;Lo;0;L;;;;;N;;;;;
+A822;SYLOTI NAGRI LETTER HO;Lo;0;L;;;;;N;;;;;
+A823;SYLOTI NAGRI VOWEL SIGN A;Mc;0;L;;;;;N;;;;;
+A824;SYLOTI NAGRI VOWEL SIGN I;Mc;0;L;;;;;N;;;;;
+A825;SYLOTI NAGRI VOWEL SIGN U;Mn;0;NSM;;;;;N;;;;;
+A826;SYLOTI NAGRI VOWEL SIGN E;Mn;0;NSM;;;;;N;;;;;
+A827;SYLOTI NAGRI VOWEL SIGN OO;Mc;0;L;;;;;N;;;;;
+A828;SYLOTI NAGRI POETRY MARK-1;So;0;ON;;;;;N;;;;;
+A829;SYLOTI NAGRI POETRY MARK-2;So;0;ON;;;;;N;;;;;
+A82A;SYLOTI NAGRI POETRY MARK-3;So;0;ON;;;;;N;;;;;
+A82B;SYLOTI NAGRI POETRY MARK-4;So;0;ON;;;;;N;;;;;
+AC00;<Hangul Syllable, First>;Lo;0;L;;;;;N;;;;;
+D7A3;<Hangul Syllable, Last>;Lo;0;L;;;;;N;;;;;
+D800;<Non Private Use High Surrogate, First>;Cs;0;L;;;;;N;;;;;
+DB7F;<Non Private Use High Surrogate, Last>;Cs;0;L;;;;;N;;;;;
+DB80;<Private Use High Surrogate, First>;Cs;0;L;;;;;N;;;;;
+DBFF;<Private Use High Surrogate, Last>;Cs;0;L;;;;;N;;;;;
+DC00;<Low Surrogate, First>;Cs;0;L;;;;;N;;;;;
+DFFF;<Low Surrogate, Last>;Cs;0;L;;;;;N;;;;;
+E000;<Private Use, First>;Co;0;L;;;;;N;;;;;
+F8FF;<Private Use, Last>;Co;0;L;;;;;N;;;;;
+F900;CJK COMPATIBILITY IDEOGRAPH-F900;Lo;0;L;8C48;;;;N;;;;;
+F901;CJK COMPATIBILITY IDEOGRAPH-F901;Lo;0;L;66F4;;;;N;;;;;
+F902;CJK COMPATIBILITY IDEOGRAPH-F902;Lo;0;L;8ECA;;;;N;;;;;
+F903;CJK COMPATIBILITY IDEOGRAPH-F903;Lo;0;L;8CC8;;;;N;;;;;
+F904;CJK COMPATIBILITY IDEOGRAPH-F904;Lo;0;L;6ED1;;;;N;;;;;
+F905;CJK COMPATIBILITY IDEOGRAPH-F905;Lo;0;L;4E32;;;;N;;;;;
+F906;CJK COMPATIBILITY IDEOGRAPH-F906;Lo;0;L;53E5;;;;N;;;;;
+F907;CJK COMPATIBILITY IDEOGRAPH-F907;Lo;0;L;9F9C;;;;N;;;;;
+F908;CJK COMPATIBILITY IDEOGRAPH-F908;Lo;0;L;9F9C;;;;N;;;;;
+F909;CJK COMPATIBILITY IDEOGRAPH-F909;Lo;0;L;5951;;;;N;;;;;
+F90A;CJK COMPATIBILITY IDEOGRAPH-F90A;Lo;0;L;91D1;;;;N;;;;;
+F90B;CJK COMPATIBILITY IDEOGRAPH-F90B;Lo;0;L;5587;;;;N;;;;;
+F90C;CJK COMPATIBILITY IDEOGRAPH-F90C;Lo;0;L;5948;;;;N;;;;;
+F90D;CJK COMPATIBILITY IDEOGRAPH-F90D;Lo;0;L;61F6;;;;N;;;;;
+F90E;CJK COMPATIBILITY IDEOGRAPH-F90E;Lo;0;L;7669;;;;N;;;;;
+F90F;CJK COMPATIBILITY IDEOGRAPH-F90F;Lo;0;L;7F85;;;;N;;;;;
+F910;CJK COMPATIBILITY IDEOGRAPH-F910;Lo;0;L;863F;;;;N;;;;;
+F911;CJK COMPATIBILITY IDEOGRAPH-F911;Lo;0;L;87BA;;;;N;;;;;
+F912;CJK COMPATIBILITY IDEOGRAPH-F912;Lo;0;L;88F8;;;;N;;;;;
+F913;CJK COMPATIBILITY IDEOGRAPH-F913;Lo;0;L;908F;;;;N;;;;;
+F914;CJK COMPATIBILITY IDEOGRAPH-F914;Lo;0;L;6A02;;;;N;;;;;
+F915;CJK COMPATIBILITY IDEOGRAPH-F915;Lo;0;L;6D1B;;;;N;;;;;
+F916;CJK COMPATIBILITY IDEOGRAPH-F916;Lo;0;L;70D9;;;;N;;;;;
+F917;CJK COMPATIBILITY IDEOGRAPH-F917;Lo;0;L;73DE;;;;N;;;;;
+F918;CJK COMPATIBILITY IDEOGRAPH-F918;Lo;0;L;843D;;;;N;;;;;
+F919;CJK COMPATIBILITY IDEOGRAPH-F919;Lo;0;L;916A;;;;N;;;;;
+F91A;CJK COMPATIBILITY IDEOGRAPH-F91A;Lo;0;L;99F1;;;;N;;;;;
+F91B;CJK COMPATIBILITY IDEOGRAPH-F91B;Lo;0;L;4E82;;;;N;;;;;
+F91C;CJK COMPATIBILITY IDEOGRAPH-F91C;Lo;0;L;5375;;;;N;;;;;
+F91D;CJK COMPATIBILITY IDEOGRAPH-F91D;Lo;0;L;6B04;;;;N;;;;;
+F91E;CJK COMPATIBILITY IDEOGRAPH-F91E;Lo;0;L;721B;;;;N;;;;;
+F91F;CJK COMPATIBILITY IDEOGRAPH-F91F;Lo;0;L;862D;;;;N;;;;;
+F920;CJK COMPATIBILITY IDEOGRAPH-F920;Lo;0;L;9E1E;;;;N;;;;;
+F921;CJK COMPATIBILITY IDEOGRAPH-F921;Lo;0;L;5D50;;;;N;;;;;
+F922;CJK COMPATIBILITY IDEOGRAPH-F922;Lo;0;L;6FEB;;;;N;;;;;
+F923;CJK COMPATIBILITY IDEOGRAPH-F923;Lo;0;L;85CD;;;;N;;;;;
+F924;CJK COMPATIBILITY IDEOGRAPH-F924;Lo;0;L;8964;;;;N;;;;;
+F925;CJK COMPATIBILITY IDEOGRAPH-F925;Lo;0;L;62C9;;;;N;;;;;
+F926;CJK COMPATIBILITY IDEOGRAPH-F926;Lo;0;L;81D8;;;;N;;;;;
+F927;CJK COMPATIBILITY IDEOGRAPH-F927;Lo;0;L;881F;;;;N;;;;;
+F928;CJK COMPATIBILITY IDEOGRAPH-F928;Lo;0;L;5ECA;;;;N;;;;;
+F929;CJK COMPATIBILITY IDEOGRAPH-F929;Lo;0;L;6717;;;;N;;;;;
+F92A;CJK COMPATIBILITY IDEOGRAPH-F92A;Lo;0;L;6D6A;;;;N;;;;;
+F92B;CJK COMPATIBILITY IDEOGRAPH-F92B;Lo;0;L;72FC;;;;N;;;;;
+F92C;CJK COMPATIBILITY IDEOGRAPH-F92C;Lo;0;L;90CE;;;;N;;;;;
+F92D;CJK COMPATIBILITY IDEOGRAPH-F92D;Lo;0;L;4F86;;;;N;;;;;
+F92E;CJK COMPATIBILITY IDEOGRAPH-F92E;Lo;0;L;51B7;;;;N;;;;;
+F92F;CJK COMPATIBILITY IDEOGRAPH-F92F;Lo;0;L;52DE;;;;N;;;;;
+F930;CJK COMPATIBILITY IDEOGRAPH-F930;Lo;0;L;64C4;;;;N;;;;;
+F931;CJK COMPATIBILITY IDEOGRAPH-F931;Lo;0;L;6AD3;;;;N;;;;;
+F932;CJK COMPATIBILITY IDEOGRAPH-F932;Lo;0;L;7210;;;;N;;;;;
+F933;CJK COMPATIBILITY IDEOGRAPH-F933;Lo;0;L;76E7;;;;N;;;;;
+F934;CJK COMPATIBILITY IDEOGRAPH-F934;Lo;0;L;8001;;;;N;;;;;
+F935;CJK COMPATIBILITY IDEOGRAPH-F935;Lo;0;L;8606;;;;N;;;;;
+F936;CJK COMPATIBILITY IDEOGRAPH-F936;Lo;0;L;865C;;;;N;;;;;
+F937;CJK COMPATIBILITY IDEOGRAPH-F937;Lo;0;L;8DEF;;;;N;;;;;
+F938;CJK COMPATIBILITY IDEOGRAPH-F938;Lo;0;L;9732;;;;N;;;;;
+F939;CJK COMPATIBILITY IDEOGRAPH-F939;Lo;0;L;9B6F;;;;N;;;;;
+F93A;CJK COMPATIBILITY IDEOGRAPH-F93A;Lo;0;L;9DFA;;;;N;;;;;
+F93B;CJK COMPATIBILITY IDEOGRAPH-F93B;Lo;0;L;788C;;;;N;;;;;
+F93C;CJK COMPATIBILITY IDEOGRAPH-F93C;Lo;0;L;797F;;;;N;;;;;
+F93D;CJK COMPATIBILITY IDEOGRAPH-F93D;Lo;0;L;7DA0;;;;N;;;;;
+F93E;CJK COMPATIBILITY IDEOGRAPH-F93E;Lo;0;L;83C9;;;;N;;;;;
+F93F;CJK COMPATIBILITY IDEOGRAPH-F93F;Lo;0;L;9304;;;;N;;;;;
+F940;CJK COMPATIBILITY IDEOGRAPH-F940;Lo;0;L;9E7F;;;;N;;;;;
+F941;CJK COMPATIBILITY IDEOGRAPH-F941;Lo;0;L;8AD6;;;;N;;;;;
+F942;CJK COMPATIBILITY IDEOGRAPH-F942;Lo;0;L;58DF;;;;N;;;;;
+F943;CJK COMPATIBILITY IDEOGRAPH-F943;Lo;0;L;5F04;;;;N;;;;;
+F944;CJK COMPATIBILITY IDEOGRAPH-F944;Lo;0;L;7C60;;;;N;;;;;
+F945;CJK COMPATIBILITY IDEOGRAPH-F945;Lo;0;L;807E;;;;N;;;;;
+F946;CJK COMPATIBILITY IDEOGRAPH-F946;Lo;0;L;7262;;;;N;;;;;
+F947;CJK COMPATIBILITY IDEOGRAPH-F947;Lo;0;L;78CA;;;;N;;;;;
+F948;CJK COMPATIBILITY IDEOGRAPH-F948;Lo;0;L;8CC2;;;;N;;;;;
+F949;CJK COMPATIBILITY IDEOGRAPH-F949;Lo;0;L;96F7;;;;N;;;;;
+F94A;CJK COMPATIBILITY IDEOGRAPH-F94A;Lo;0;L;58D8;;;;N;;;;;
+F94B;CJK COMPATIBILITY IDEOGRAPH-F94B;Lo;0;L;5C62;;;;N;;;;;
+F94C;CJK COMPATIBILITY IDEOGRAPH-F94C;Lo;0;L;6A13;;;;N;;;;;
+F94D;CJK COMPATIBILITY IDEOGRAPH-F94D;Lo;0;L;6DDA;;;;N;;;;;
+F94E;CJK COMPATIBILITY IDEOGRAPH-F94E;Lo;0;L;6F0F;;;;N;;;;;
+F94F;CJK COMPATIBILITY IDEOGRAPH-F94F;Lo;0;L;7D2F;;;;N;;;;;
+F950;CJK COMPATIBILITY IDEOGRAPH-F950;Lo;0;L;7E37;;;;N;;;;;
+F951;CJK COMPATIBILITY IDEOGRAPH-F951;Lo;0;L;964B;;;;N;;;;;
+F952;CJK COMPATIBILITY IDEOGRAPH-F952;Lo;0;L;52D2;;;;N;;;;;
+F953;CJK COMPATIBILITY IDEOGRAPH-F953;Lo;0;L;808B;;;;N;;;;;
+F954;CJK COMPATIBILITY IDEOGRAPH-F954;Lo;0;L;51DC;;;;N;;;;;
+F955;CJK COMPATIBILITY IDEOGRAPH-F955;Lo;0;L;51CC;;;;N;;;;;
+F956;CJK COMPATIBILITY IDEOGRAPH-F956;Lo;0;L;7A1C;;;;N;;;;;
+F957;CJK COMPATIBILITY IDEOGRAPH-F957;Lo;0;L;7DBE;;;;N;;;;;
+F958;CJK COMPATIBILITY IDEOGRAPH-F958;Lo;0;L;83F1;;;;N;;;;;
+F959;CJK COMPATIBILITY IDEOGRAPH-F959;Lo;0;L;9675;;;;N;;;;;
+F95A;CJK COMPATIBILITY IDEOGRAPH-F95A;Lo;0;L;8B80;;;;N;;;;;
+F95B;CJK COMPATIBILITY IDEOGRAPH-F95B;Lo;0;L;62CF;;;;N;;;;;
+F95C;CJK COMPATIBILITY IDEOGRAPH-F95C;Lo;0;L;6A02;;;;N;;;;;
+F95D;CJK COMPATIBILITY IDEOGRAPH-F95D;Lo;0;L;8AFE;;;;N;;;;;
+F95E;CJK COMPATIBILITY IDEOGRAPH-F95E;Lo;0;L;4E39;;;;N;;;;;
+F95F;CJK COMPATIBILITY IDEOGRAPH-F95F;Lo;0;L;5BE7;;;;N;;;;;
+F960;CJK COMPATIBILITY IDEOGRAPH-F960;Lo;0;L;6012;;;;N;;;;;
+F961;CJK COMPATIBILITY IDEOGRAPH-F961;Lo;0;L;7387;;;;N;;;;;
+F962;CJK COMPATIBILITY IDEOGRAPH-F962;Lo;0;L;7570;;;;N;;;;;
+F963;CJK COMPATIBILITY IDEOGRAPH-F963;Lo;0;L;5317;;;;N;;;;;
+F964;CJK COMPATIBILITY IDEOGRAPH-F964;Lo;0;L;78FB;;;;N;;;;;
+F965;CJK COMPATIBILITY IDEOGRAPH-F965;Lo;0;L;4FBF;;;;N;;;;;
+F966;CJK COMPATIBILITY IDEOGRAPH-F966;Lo;0;L;5FA9;;;;N;;;;;
+F967;CJK COMPATIBILITY IDEOGRAPH-F967;Lo;0;L;4E0D;;;;N;;;;;
+F968;CJK COMPATIBILITY IDEOGRAPH-F968;Lo;0;L;6CCC;;;;N;;;;;
+F969;CJK COMPATIBILITY IDEOGRAPH-F969;Lo;0;L;6578;;;;N;;;;;
+F96A;CJK COMPATIBILITY IDEOGRAPH-F96A;Lo;0;L;7D22;;;;N;;;;;
+F96B;CJK COMPATIBILITY IDEOGRAPH-F96B;Lo;0;L;53C3;;;;N;;;;;
+F96C;CJK COMPATIBILITY IDEOGRAPH-F96C;Lo;0;L;585E;;;;N;;;;;
+F96D;CJK COMPATIBILITY IDEOGRAPH-F96D;Lo;0;L;7701;;;;N;;;;;
+F96E;CJK COMPATIBILITY IDEOGRAPH-F96E;Lo;0;L;8449;;;;N;;;;;
+F96F;CJK COMPATIBILITY IDEOGRAPH-F96F;Lo;0;L;8AAA;;;;N;;;;;
+F970;CJK COMPATIBILITY IDEOGRAPH-F970;Lo;0;L;6BBA;;;;N;;;;;
+F971;CJK COMPATIBILITY IDEOGRAPH-F971;Lo;0;L;8FB0;;;;N;;;;;
+F972;CJK COMPATIBILITY IDEOGRAPH-F972;Lo;0;L;6C88;;;;N;;;;;
+F973;CJK COMPATIBILITY IDEOGRAPH-F973;Lo;0;L;62FE;;;;N;;;;;
+F974;CJK COMPATIBILITY IDEOGRAPH-F974;Lo;0;L;82E5;;;;N;;;;;
+F975;CJK COMPATIBILITY IDEOGRAPH-F975;Lo;0;L;63A0;;;;N;;;;;
+F976;CJK COMPATIBILITY IDEOGRAPH-F976;Lo;0;L;7565;;;;N;;;;;
+F977;CJK COMPATIBILITY IDEOGRAPH-F977;Lo;0;L;4EAE;;;;N;;;;;
+F978;CJK COMPATIBILITY IDEOGRAPH-F978;Lo;0;L;5169;;;;N;;;;;
+F979;CJK COMPATIBILITY IDEOGRAPH-F979;Lo;0;L;51C9;;;;N;;;;;
+F97A;CJK COMPATIBILITY IDEOGRAPH-F97A;Lo;0;L;6881;;;;N;;;;;
+F97B;CJK COMPATIBILITY IDEOGRAPH-F97B;Lo;0;L;7CE7;;;;N;;;;;
+F97C;CJK COMPATIBILITY IDEOGRAPH-F97C;Lo;0;L;826F;;;;N;;;;;
+F97D;CJK COMPATIBILITY IDEOGRAPH-F97D;Lo;0;L;8AD2;;;;N;;;;;
+F97E;CJK COMPATIBILITY IDEOGRAPH-F97E;Lo;0;L;91CF;;;;N;;;;;
+F97F;CJK COMPATIBILITY IDEOGRAPH-F97F;Lo;0;L;52F5;;;;N;;;;;
+F980;CJK COMPATIBILITY IDEOGRAPH-F980;Lo;0;L;5442;;;;N;;;;;
+F981;CJK COMPATIBILITY IDEOGRAPH-F981;Lo;0;L;5973;;;;N;;;;;
+F982;CJK COMPATIBILITY IDEOGRAPH-F982;Lo;0;L;5EEC;;;;N;;;;;
+F983;CJK COMPATIBILITY IDEOGRAPH-F983;Lo;0;L;65C5;;;;N;;;;;
+F984;CJK COMPATIBILITY IDEOGRAPH-F984;Lo;0;L;6FFE;;;;N;;;;;
+F985;CJK COMPATIBILITY IDEOGRAPH-F985;Lo;0;L;792A;;;;N;;;;;
+F986;CJK COMPATIBILITY IDEOGRAPH-F986;Lo;0;L;95AD;;;;N;;;;;
+F987;CJK COMPATIBILITY IDEOGRAPH-F987;Lo;0;L;9A6A;;;;N;;;;;
+F988;CJK COMPATIBILITY IDEOGRAPH-F988;Lo;0;L;9E97;;;;N;;;;;
+F989;CJK COMPATIBILITY IDEOGRAPH-F989;Lo;0;L;9ECE;;;;N;;;;;
+F98A;CJK COMPATIBILITY IDEOGRAPH-F98A;Lo;0;L;529B;;;;N;;;;;
+F98B;CJK COMPATIBILITY IDEOGRAPH-F98B;Lo;0;L;66C6;;;;N;;;;;
+F98C;CJK COMPATIBILITY IDEOGRAPH-F98C;Lo;0;L;6B77;;;;N;;;;;
+F98D;CJK COMPATIBILITY IDEOGRAPH-F98D;Lo;0;L;8F62;;;;N;;;;;
+F98E;CJK COMPATIBILITY IDEOGRAPH-F98E;Lo;0;L;5E74;;;;N;;;;;
+F98F;CJK COMPATIBILITY IDEOGRAPH-F98F;Lo;0;L;6190;;;;N;;;;;
+F990;CJK COMPATIBILITY IDEOGRAPH-F990;Lo;0;L;6200;;;;N;;;;;
+F991;CJK COMPATIBILITY IDEOGRAPH-F991;Lo;0;L;649A;;;;N;;;;;
+F992;CJK COMPATIBILITY IDEOGRAPH-F992;Lo;0;L;6F23;;;;N;;;;;
+F993;CJK COMPATIBILITY IDEOGRAPH-F993;Lo;0;L;7149;;;;N;;;;;
+F994;CJK COMPATIBILITY IDEOGRAPH-F994;Lo;0;L;7489;;;;N;;;;;
+F995;CJK COMPATIBILITY IDEOGRAPH-F995;Lo;0;L;79CA;;;;N;;;;;
+F996;CJK COMPATIBILITY IDEOGRAPH-F996;Lo;0;L;7DF4;;;;N;;;;;
+F997;CJK COMPATIBILITY IDEOGRAPH-F997;Lo;0;L;806F;;;;N;;;;;
+F998;CJK COMPATIBILITY IDEOGRAPH-F998;Lo;0;L;8F26;;;;N;;;;;
+F999;CJK COMPATIBILITY IDEOGRAPH-F999;Lo;0;L;84EE;;;;N;;;;;
+F99A;CJK COMPATIBILITY IDEOGRAPH-F99A;Lo;0;L;9023;;;;N;;;;;
+F99B;CJK COMPATIBILITY IDEOGRAPH-F99B;Lo;0;L;934A;;;;N;;;;;
+F99C;CJK COMPATIBILITY IDEOGRAPH-F99C;Lo;0;L;5217;;;;N;;;;;
+F99D;CJK COMPATIBILITY IDEOGRAPH-F99D;Lo;0;L;52A3;;;;N;;;;;
+F99E;CJK COMPATIBILITY IDEOGRAPH-F99E;Lo;0;L;54BD;;;;N;;;;;
+F99F;CJK COMPATIBILITY IDEOGRAPH-F99F;Lo;0;L;70C8;;;;N;;;;;
+F9A0;CJK COMPATIBILITY IDEOGRAPH-F9A0;Lo;0;L;88C2;;;;N;;;;;
+F9A1;CJK COMPATIBILITY IDEOGRAPH-F9A1;Lo;0;L;8AAA;;;;N;;;;;
+F9A2;CJK COMPATIBILITY IDEOGRAPH-F9A2;Lo;0;L;5EC9;;;;N;;;;;
+F9A3;CJK COMPATIBILITY IDEOGRAPH-F9A3;Lo;0;L;5FF5;;;;N;;;;;
+F9A4;CJK COMPATIBILITY IDEOGRAPH-F9A4;Lo;0;L;637B;;;;N;;;;;
+F9A5;CJK COMPATIBILITY IDEOGRAPH-F9A5;Lo;0;L;6BAE;;;;N;;;;;
+F9A6;CJK COMPATIBILITY IDEOGRAPH-F9A6;Lo;0;L;7C3E;;;;N;;;;;
+F9A7;CJK COMPATIBILITY IDEOGRAPH-F9A7;Lo;0;L;7375;;;;N;;;;;
+F9A8;CJK COMPATIBILITY IDEOGRAPH-F9A8;Lo;0;L;4EE4;;;;N;;;;;
+F9A9;CJK COMPATIBILITY IDEOGRAPH-F9A9;Lo;0;L;56F9;;;;N;;;;;
+F9AA;CJK COMPATIBILITY IDEOGRAPH-F9AA;Lo;0;L;5BE7;;;;N;;;;;
+F9AB;CJK COMPATIBILITY IDEOGRAPH-F9AB;Lo;0;L;5DBA;;;;N;;;;;
+F9AC;CJK COMPATIBILITY IDEOGRAPH-F9AC;Lo;0;L;601C;;;;N;;;;;
+F9AD;CJK COMPATIBILITY IDEOGRAPH-F9AD;Lo;0;L;73B2;;;;N;;;;;
+F9AE;CJK COMPATIBILITY IDEOGRAPH-F9AE;Lo;0;L;7469;;;;N;;;;;
+F9AF;CJK COMPATIBILITY IDEOGRAPH-F9AF;Lo;0;L;7F9A;;;;N;;;;;
+F9B0;CJK COMPATIBILITY IDEOGRAPH-F9B0;Lo;0;L;8046;;;;N;;;;;
+F9B1;CJK COMPATIBILITY IDEOGRAPH-F9B1;Lo;0;L;9234;;;;N;;;;;
+F9B2;CJK COMPATIBILITY IDEOGRAPH-F9B2;Lo;0;L;96F6;;;;N;;;;;
+F9B3;CJK COMPATIBILITY IDEOGRAPH-F9B3;Lo;0;L;9748;;;;N;;;;;
+F9B4;CJK COMPATIBILITY IDEOGRAPH-F9B4;Lo;0;L;9818;;;;N;;;;;
+F9B5;CJK COMPATIBILITY IDEOGRAPH-F9B5;Lo;0;L;4F8B;;;;N;;;;;
+F9B6;CJK COMPATIBILITY IDEOGRAPH-F9B6;Lo;0;L;79AE;;;;N;;;;;
+F9B7;CJK COMPATIBILITY IDEOGRAPH-F9B7;Lo;0;L;91B4;;;;N;;;;;
+F9B8;CJK COMPATIBILITY IDEOGRAPH-F9B8;Lo;0;L;96B8;;;;N;;;;;
+F9B9;CJK COMPATIBILITY IDEOGRAPH-F9B9;Lo;0;L;60E1;;;;N;;;;;
+F9BA;CJK COMPATIBILITY IDEOGRAPH-F9BA;Lo;0;L;4E86;;;;N;;;;;
+F9BB;CJK COMPATIBILITY IDEOGRAPH-F9BB;Lo;0;L;50DA;;;;N;;;;;
+F9BC;CJK COMPATIBILITY IDEOGRAPH-F9BC;Lo;0;L;5BEE;;;;N;;;;;
+F9BD;CJK COMPATIBILITY IDEOGRAPH-F9BD;Lo;0;L;5C3F;;;;N;;;;;
+F9BE;CJK COMPATIBILITY IDEOGRAPH-F9BE;Lo;0;L;6599;;;;N;;;;;
+F9BF;CJK COMPATIBILITY IDEOGRAPH-F9BF;Lo;0;L;6A02;;;;N;;;;;
+F9C0;CJK COMPATIBILITY IDEOGRAPH-F9C0;Lo;0;L;71CE;;;;N;;;;;
+F9C1;CJK COMPATIBILITY IDEOGRAPH-F9C1;Lo;0;L;7642;;;;N;;;;;
+F9C2;CJK COMPATIBILITY IDEOGRAPH-F9C2;Lo;0;L;84FC;;;;N;;;;;
+F9C3;CJK COMPATIBILITY IDEOGRAPH-F9C3;Lo;0;L;907C;;;;N;;;;;
+F9C4;CJK COMPATIBILITY IDEOGRAPH-F9C4;Lo;0;L;9F8D;;;;N;;;;;
+F9C5;CJK COMPATIBILITY IDEOGRAPH-F9C5;Lo;0;L;6688;;;;N;;;;;
+F9C6;CJK COMPATIBILITY IDEOGRAPH-F9C6;Lo;0;L;962E;;;;N;;;;;
+F9C7;CJK COMPATIBILITY IDEOGRAPH-F9C7;Lo;0;L;5289;;;;N;;;;;
+F9C8;CJK COMPATIBILITY IDEOGRAPH-F9C8;Lo;0;L;677B;;;;N;;;;;
+F9C9;CJK COMPATIBILITY IDEOGRAPH-F9C9;Lo;0;L;67F3;;;;N;;;;;
+F9CA;CJK COMPATIBILITY IDEOGRAPH-F9CA;Lo;0;L;6D41;;;;N;;;;;
+F9CB;CJK COMPATIBILITY IDEOGRAPH-F9CB;Lo;0;L;6E9C;;;;N;;;;;
+F9CC;CJK COMPATIBILITY IDEOGRAPH-F9CC;Lo;0;L;7409;;;;N;;;;;
+F9CD;CJK COMPATIBILITY IDEOGRAPH-F9CD;Lo;0;L;7559;;;;N;;;;;
+F9CE;CJK COMPATIBILITY IDEOGRAPH-F9CE;Lo;0;L;786B;;;;N;;;;;
+F9CF;CJK COMPATIBILITY IDEOGRAPH-F9CF;Lo;0;L;7D10;;;;N;;;;;
+F9D0;CJK COMPATIBILITY IDEOGRAPH-F9D0;Lo;0;L;985E;;;;N;;;;;
+F9D1;CJK COMPATIBILITY IDEOGRAPH-F9D1;Lo;0;L;516D;;;;N;;;;;
+F9D2;CJK COMPATIBILITY IDEOGRAPH-F9D2;Lo;0;L;622E;;;;N;;;;;
+F9D3;CJK COMPATIBILITY IDEOGRAPH-F9D3;Lo;0;L;9678;;;;N;;;;;
+F9D4;CJK COMPATIBILITY IDEOGRAPH-F9D4;Lo;0;L;502B;;;;N;;;;;
+F9D5;CJK COMPATIBILITY IDEOGRAPH-F9D5;Lo;0;L;5D19;;;;N;;;;;
+F9D6;CJK COMPATIBILITY IDEOGRAPH-F9D6;Lo;0;L;6DEA;;;;N;;;;;
+F9D7;CJK COMPATIBILITY IDEOGRAPH-F9D7;Lo;0;L;8F2A;;;;N;;;;;
+F9D8;CJK COMPATIBILITY IDEOGRAPH-F9D8;Lo;0;L;5F8B;;;;N;;;;;
+F9D9;CJK COMPATIBILITY IDEOGRAPH-F9D9;Lo;0;L;6144;;;;N;;;;;
+F9DA;CJK COMPATIBILITY IDEOGRAPH-F9DA;Lo;0;L;6817;;;;N;;;;;
+F9DB;CJK COMPATIBILITY IDEOGRAPH-F9DB;Lo;0;L;7387;;;;N;;;;;
+F9DC;CJK COMPATIBILITY IDEOGRAPH-F9DC;Lo;0;L;9686;;;;N;;;;;
+F9DD;CJK COMPATIBILITY IDEOGRAPH-F9DD;Lo;0;L;5229;;;;N;;;;;
+F9DE;CJK COMPATIBILITY IDEOGRAPH-F9DE;Lo;0;L;540F;;;;N;;;;;
+F9DF;CJK COMPATIBILITY IDEOGRAPH-F9DF;Lo;0;L;5C65;;;;N;;;;;
+F9E0;CJK COMPATIBILITY IDEOGRAPH-F9E0;Lo;0;L;6613;;;;N;;;;;
+F9E1;CJK COMPATIBILITY IDEOGRAPH-F9E1;Lo;0;L;674E;;;;N;;;;;
+F9E2;CJK COMPATIBILITY IDEOGRAPH-F9E2;Lo;0;L;68A8;;;;N;;;;;
+F9E3;CJK COMPATIBILITY IDEOGRAPH-F9E3;Lo;0;L;6CE5;;;;N;;;;;
+F9E4;CJK COMPATIBILITY IDEOGRAPH-F9E4;Lo;0;L;7406;;;;N;;;;;
+F9E5;CJK COMPATIBILITY IDEOGRAPH-F9E5;Lo;0;L;75E2;;;;N;;;;;
+F9E6;CJK COMPATIBILITY IDEOGRAPH-F9E6;Lo;0;L;7F79;;;;N;;;;;
+F9E7;CJK COMPATIBILITY IDEOGRAPH-F9E7;Lo;0;L;88CF;;;;N;;;;;
+F9E8;CJK COMPATIBILITY IDEOGRAPH-F9E8;Lo;0;L;88E1;;;;N;;;;;
+F9E9;CJK COMPATIBILITY IDEOGRAPH-F9E9;Lo;0;L;91CC;;;;N;;;;;
+F9EA;CJK COMPATIBILITY IDEOGRAPH-F9EA;Lo;0;L;96E2;;;;N;;;;;
+F9EB;CJK COMPATIBILITY IDEOGRAPH-F9EB;Lo;0;L;533F;;;;N;;;;;
+F9EC;CJK COMPATIBILITY IDEOGRAPH-F9EC;Lo;0;L;6EBA;;;;N;;;;;
+F9ED;CJK COMPATIBILITY IDEOGRAPH-F9ED;Lo;0;L;541D;;;;N;;;;;
+F9EE;CJK COMPATIBILITY IDEOGRAPH-F9EE;Lo;0;L;71D0;;;;N;;;;;
+F9EF;CJK COMPATIBILITY IDEOGRAPH-F9EF;Lo;0;L;7498;;;;N;;;;;
+F9F0;CJK COMPATIBILITY IDEOGRAPH-F9F0;Lo;0;L;85FA;;;;N;;;;;
+F9F1;CJK COMPATIBILITY IDEOGRAPH-F9F1;Lo;0;L;96A3;;;;N;;;;;
+F9F2;CJK COMPATIBILITY IDEOGRAPH-F9F2;Lo;0;L;9C57;;;;N;;;;;
+F9F3;CJK COMPATIBILITY IDEOGRAPH-F9F3;Lo;0;L;9E9F;;;;N;;;;;
+F9F4;CJK COMPATIBILITY IDEOGRAPH-F9F4;Lo;0;L;6797;;;;N;;;;;
+F9F5;CJK COMPATIBILITY IDEOGRAPH-F9F5;Lo;0;L;6DCB;;;;N;;;;;
+F9F6;CJK COMPATIBILITY IDEOGRAPH-F9F6;Lo;0;L;81E8;;;;N;;;;;
+F9F7;CJK COMPATIBILITY IDEOGRAPH-F9F7;Lo;0;L;7ACB;;;;N;;;;;
+F9F8;CJK COMPATIBILITY IDEOGRAPH-F9F8;Lo;0;L;7B20;;;;N;;;;;
+F9F9;CJK COMPATIBILITY IDEOGRAPH-F9F9;Lo;0;L;7C92;;;;N;;;;;
+F9FA;CJK COMPATIBILITY IDEOGRAPH-F9FA;Lo;0;L;72C0;;;;N;;;;;
+F9FB;CJK COMPATIBILITY IDEOGRAPH-F9FB;Lo;0;L;7099;;;;N;;;;;
+F9FC;CJK COMPATIBILITY IDEOGRAPH-F9FC;Lo;0;L;8B58;;;;N;;;;;
+F9FD;CJK COMPATIBILITY IDEOGRAPH-F9FD;Lo;0;L;4EC0;;;;N;;;;;
+F9FE;CJK COMPATIBILITY IDEOGRAPH-F9FE;Lo;0;L;8336;;;;N;;;;;
+F9FF;CJK COMPATIBILITY IDEOGRAPH-F9FF;Lo;0;L;523A;;;;N;;;;;
+FA00;CJK COMPATIBILITY IDEOGRAPH-FA00;Lo;0;L;5207;;;;N;;;;;
+FA01;CJK COMPATIBILITY IDEOGRAPH-FA01;Lo;0;L;5EA6;;;;N;;;;;
+FA02;CJK COMPATIBILITY IDEOGRAPH-FA02;Lo;0;L;62D3;;;;N;;;;;
+FA03;CJK COMPATIBILITY IDEOGRAPH-FA03;Lo;0;L;7CD6;;;;N;;;;;
+FA04;CJK COMPATIBILITY IDEOGRAPH-FA04;Lo;0;L;5B85;;;;N;;;;;
+FA05;CJK COMPATIBILITY IDEOGRAPH-FA05;Lo;0;L;6D1E;;;;N;;;;;
+FA06;CJK COMPATIBILITY IDEOGRAPH-FA06;Lo;0;L;66B4;;;;N;;;;;
+FA07;CJK COMPATIBILITY IDEOGRAPH-FA07;Lo;0;L;8F3B;;;;N;;;;;
+FA08;CJK COMPATIBILITY IDEOGRAPH-FA08;Lo;0;L;884C;;;;N;;;;;
+FA09;CJK COMPATIBILITY IDEOGRAPH-FA09;Lo;0;L;964D;;;;N;;;;;
+FA0A;CJK COMPATIBILITY IDEOGRAPH-FA0A;Lo;0;L;898B;;;;N;;;;;
+FA0B;CJK COMPATIBILITY IDEOGRAPH-FA0B;Lo;0;L;5ED3;;;;N;;;;;
+FA0C;CJK COMPATIBILITY IDEOGRAPH-FA0C;Lo;0;L;5140;;;;N;;;;;
+FA0D;CJK COMPATIBILITY IDEOGRAPH-FA0D;Lo;0;L;55C0;;;;N;;;;;
+FA0E;CJK COMPATIBILITY IDEOGRAPH-FA0E;Lo;0;L;;;;;N;;;;;
+FA0F;CJK COMPATIBILITY IDEOGRAPH-FA0F;Lo;0;L;;;;;N;;;;;
+FA10;CJK COMPATIBILITY IDEOGRAPH-FA10;Lo;0;L;585A;;;;N;;;;;
+FA11;CJK COMPATIBILITY IDEOGRAPH-FA11;Lo;0;L;;;;;N;;;;;
+FA12;CJK COMPATIBILITY IDEOGRAPH-FA12;Lo;0;L;6674;;;;N;;;;;
+FA13;CJK COMPATIBILITY IDEOGRAPH-FA13;Lo;0;L;;;;;N;;;;;
+FA14;CJK COMPATIBILITY IDEOGRAPH-FA14;Lo;0;L;;;;;N;;;;;
+FA15;CJK COMPATIBILITY IDEOGRAPH-FA15;Lo;0;L;51DE;;;;N;;;;;
+FA16;CJK COMPATIBILITY IDEOGRAPH-FA16;Lo;0;L;732A;;;;N;;;;;
+FA17;CJK COMPATIBILITY IDEOGRAPH-FA17;Lo;0;L;76CA;;;;N;;;;;
+FA18;CJK COMPATIBILITY IDEOGRAPH-FA18;Lo;0;L;793C;;;;N;;;;;
+FA19;CJK COMPATIBILITY IDEOGRAPH-FA19;Lo;0;L;795E;;;;N;;;;;
+FA1A;CJK COMPATIBILITY IDEOGRAPH-FA1A;Lo;0;L;7965;;;;N;;;;;
+FA1B;CJK COMPATIBILITY IDEOGRAPH-FA1B;Lo;0;L;798F;;;;N;;;;;
+FA1C;CJK COMPATIBILITY IDEOGRAPH-FA1C;Lo;0;L;9756;;;;N;;;;;
+FA1D;CJK COMPATIBILITY IDEOGRAPH-FA1D;Lo;0;L;7CBE;;;;N;;;;;
+FA1E;CJK COMPATIBILITY IDEOGRAPH-FA1E;Lo;0;L;7FBD;;;;N;;;;;
+FA1F;CJK COMPATIBILITY IDEOGRAPH-FA1F;Lo;0;L;;;;;N;;*;;;
+FA20;CJK COMPATIBILITY IDEOGRAPH-FA20;Lo;0;L;8612;;;;N;;;;;
+FA21;CJK COMPATIBILITY IDEOGRAPH-FA21;Lo;0;L;;;;;N;;;;;
+FA22;CJK COMPATIBILITY IDEOGRAPH-FA22;Lo;0;L;8AF8;;;;N;;;;;
+FA23;CJK COMPATIBILITY IDEOGRAPH-FA23;Lo;0;L;;;;;N;;*;;;
+FA24;CJK COMPATIBILITY IDEOGRAPH-FA24;Lo;0;L;;;;;N;;;;;
+FA25;CJK COMPATIBILITY IDEOGRAPH-FA25;Lo;0;L;9038;;;;N;;;;;
+FA26;CJK COMPATIBILITY IDEOGRAPH-FA26;Lo;0;L;90FD;;;;N;;;;;
+FA27;CJK COMPATIBILITY IDEOGRAPH-FA27;Lo;0;L;;;;;N;;;;;
+FA28;CJK COMPATIBILITY IDEOGRAPH-FA28;Lo;0;L;;;;;N;;;;;
+FA29;CJK COMPATIBILITY IDEOGRAPH-FA29;Lo;0;L;;;;;N;;;;;
+FA2A;CJK COMPATIBILITY IDEOGRAPH-FA2A;Lo;0;L;98EF;;;;N;;;;;
+FA2B;CJK COMPATIBILITY IDEOGRAPH-FA2B;Lo;0;L;98FC;;;;N;;;;;
+FA2C;CJK COMPATIBILITY IDEOGRAPH-FA2C;Lo;0;L;9928;;;;N;;;;;
+FA2D;CJK COMPATIBILITY IDEOGRAPH-FA2D;Lo;0;L;9DB4;;;;N;;;;;
+FA30;CJK COMPATIBILITY IDEOGRAPH-FA30;Lo;0;L;4FAE;;;;N;;;;;
+FA31;CJK COMPATIBILITY IDEOGRAPH-FA31;Lo;0;L;50E7;;;;N;;;;;
+FA32;CJK COMPATIBILITY IDEOGRAPH-FA32;Lo;0;L;514D;;;;N;;;;;
+FA33;CJK COMPATIBILITY IDEOGRAPH-FA33;Lo;0;L;52C9;;;;N;;;;;
+FA34;CJK COMPATIBILITY IDEOGRAPH-FA34;Lo;0;L;52E4;;;;N;;;;;
+FA35;CJK COMPATIBILITY IDEOGRAPH-FA35;Lo;0;L;5351;;;;N;;;;;
+FA36;CJK COMPATIBILITY IDEOGRAPH-FA36;Lo;0;L;559D;;;;N;;;;;
+FA37;CJK COMPATIBILITY IDEOGRAPH-FA37;Lo;0;L;5606;;;;N;;;;;
+FA38;CJK COMPATIBILITY IDEOGRAPH-FA38;Lo;0;L;5668;;;;N;;;;;
+FA39;CJK COMPATIBILITY IDEOGRAPH-FA39;Lo;0;L;5840;;;;N;;;;;
+FA3A;CJK COMPATIBILITY IDEOGRAPH-FA3A;Lo;0;L;58A8;;;;N;;;;;
+FA3B;CJK COMPATIBILITY IDEOGRAPH-FA3B;Lo;0;L;5C64;;;;N;;;;;
+FA3C;CJK COMPATIBILITY IDEOGRAPH-FA3C;Lo;0;L;5C6E;;;;N;;;;;
+FA3D;CJK COMPATIBILITY IDEOGRAPH-FA3D;Lo;0;L;6094;;;;N;;;;;
+FA3E;CJK COMPATIBILITY IDEOGRAPH-FA3E;Lo;0;L;6168;;;;N;;;;;
+FA3F;CJK COMPATIBILITY IDEOGRAPH-FA3F;Lo;0;L;618E;;;;N;;;;;
+FA40;CJK COMPATIBILITY IDEOGRAPH-FA40;Lo;0;L;61F2;;;;N;;;;;
+FA41;CJK COMPATIBILITY IDEOGRAPH-FA41;Lo;0;L;654F;;;;N;;;;;
+FA42;CJK COMPATIBILITY IDEOGRAPH-FA42;Lo;0;L;65E2;;;;N;;;;;
+FA43;CJK COMPATIBILITY IDEOGRAPH-FA43;Lo;0;L;6691;;;;N;;;;;
+FA44;CJK COMPATIBILITY IDEOGRAPH-FA44;Lo;0;L;6885;;;;N;;;;;
+FA45;CJK COMPATIBILITY IDEOGRAPH-FA45;Lo;0;L;6D77;;;;N;;;;;
+FA46;CJK COMPATIBILITY IDEOGRAPH-FA46;Lo;0;L;6E1A;;;;N;;;;;
+FA47;CJK COMPATIBILITY IDEOGRAPH-FA47;Lo;0;L;6F22;;;;N;;;;;
+FA48;CJK COMPATIBILITY IDEOGRAPH-FA48;Lo;0;L;716E;;;;N;;;;;
+FA49;CJK COMPATIBILITY IDEOGRAPH-FA49;Lo;0;L;722B;;;;N;;;;;
+FA4A;CJK COMPATIBILITY IDEOGRAPH-FA4A;Lo;0;L;7422;;;;N;;;;;
+FA4B;CJK COMPATIBILITY IDEOGRAPH-FA4B;Lo;0;L;7891;;;;N;;;;;
+FA4C;CJK COMPATIBILITY IDEOGRAPH-FA4C;Lo;0;L;793E;;;;N;;;;;
+FA4D;CJK COMPATIBILITY IDEOGRAPH-FA4D;Lo;0;L;7949;;;;N;;;;;
+FA4E;CJK COMPATIBILITY IDEOGRAPH-FA4E;Lo;0;L;7948;;;;N;;;;;
+FA4F;CJK COMPATIBILITY IDEOGRAPH-FA4F;Lo;0;L;7950;;;;N;;;;;
+FA50;CJK COMPATIBILITY IDEOGRAPH-FA50;Lo;0;L;7956;;;;N;;;;;
+FA51;CJK COMPATIBILITY IDEOGRAPH-FA51;Lo;0;L;795D;;;;N;;;;;
+FA52;CJK COMPATIBILITY IDEOGRAPH-FA52;Lo;0;L;798D;;;;N;;;;;
+FA53;CJK COMPATIBILITY IDEOGRAPH-FA53;Lo;0;L;798E;;;;N;;;;;
+FA54;CJK COMPATIBILITY IDEOGRAPH-FA54;Lo;0;L;7A40;;;;N;;;;;
+FA55;CJK COMPATIBILITY IDEOGRAPH-FA55;Lo;0;L;7A81;;;;N;;;;;
+FA56;CJK COMPATIBILITY IDEOGRAPH-FA56;Lo;0;L;7BC0;;;;N;;;;;
+FA57;CJK COMPATIBILITY IDEOGRAPH-FA57;Lo;0;L;7DF4;;;;N;;;;;
+FA58;CJK COMPATIBILITY IDEOGRAPH-FA58;Lo;0;L;7E09;;;;N;;;;;
+FA59;CJK COMPATIBILITY IDEOGRAPH-FA59;Lo;0;L;7E41;;;;N;;;;;
+FA5A;CJK COMPATIBILITY IDEOGRAPH-FA5A;Lo;0;L;7F72;;;;N;;;;;
+FA5B;CJK COMPATIBILITY IDEOGRAPH-FA5B;Lo;0;L;8005;;;;N;;;;;
+FA5C;CJK COMPATIBILITY IDEOGRAPH-FA5C;Lo;0;L;81ED;;;;N;;;;;
+FA5D;CJK COMPATIBILITY IDEOGRAPH-FA5D;Lo;0;L;8279;;;;N;;;;;
+FA5E;CJK COMPATIBILITY IDEOGRAPH-FA5E;Lo;0;L;8279;;;;N;;;;;
+FA5F;CJK COMPATIBILITY IDEOGRAPH-FA5F;Lo;0;L;8457;;;;N;;;;;
+FA60;CJK COMPATIBILITY IDEOGRAPH-FA60;Lo;0;L;8910;;;;N;;;;;
+FA61;CJK COMPATIBILITY IDEOGRAPH-FA61;Lo;0;L;8996;;;;N;;;;;
+FA62;CJK COMPATIBILITY IDEOGRAPH-FA62;Lo;0;L;8B01;;;;N;;;;;
+FA63;CJK COMPATIBILITY IDEOGRAPH-FA63;Lo;0;L;8B39;;;;N;;;;;
+FA64;CJK COMPATIBILITY IDEOGRAPH-FA64;Lo;0;L;8CD3;;;;N;;;;;
+FA65;CJK COMPATIBILITY IDEOGRAPH-FA65;Lo;0;L;8D08;;;;N;;;;;
+FA66;CJK COMPATIBILITY IDEOGRAPH-FA66;Lo;0;L;8FB6;;;;N;;;;;
+FA67;CJK COMPATIBILITY IDEOGRAPH-FA67;Lo;0;L;9038;;;;N;;;;;
+FA68;CJK COMPATIBILITY IDEOGRAPH-FA68;Lo;0;L;96E3;;;;N;;;;;
+FA69;CJK COMPATIBILITY IDEOGRAPH-FA69;Lo;0;L;97FF;;;;N;;;;;
+FA6A;CJK COMPATIBILITY IDEOGRAPH-FA6A;Lo;0;L;983B;;;;N;;;;;
+FA70;CJK COMPATIBILITY IDEOGRAPH-FA70;Lo;0;L;4E26;;;;N;;;;;
+FA71;CJK COMPATIBILITY IDEOGRAPH-FA71;Lo;0;L;51B5;;;;N;;;;;
+FA72;CJK COMPATIBILITY IDEOGRAPH-FA72;Lo;0;L;5168;;;;N;;;;;
+FA73;CJK COMPATIBILITY IDEOGRAPH-FA73;Lo;0;L;4F80;;;;N;;;;;
+FA74;CJK COMPATIBILITY IDEOGRAPH-FA74;Lo;0;L;5145;;;;N;;;;;
+FA75;CJK COMPATIBILITY IDEOGRAPH-FA75;Lo;0;L;5180;;;;N;;;;;
+FA76;CJK COMPATIBILITY IDEOGRAPH-FA76;Lo;0;L;52C7;;;;N;;;;;
+FA77;CJK COMPATIBILITY IDEOGRAPH-FA77;Lo;0;L;52FA;;;;N;;;;;
+FA78;CJK COMPATIBILITY IDEOGRAPH-FA78;Lo;0;L;559D;;;;N;;;;;
+FA79;CJK COMPATIBILITY IDEOGRAPH-FA79;Lo;0;L;5555;;;;N;;;;;
+FA7A;CJK COMPATIBILITY IDEOGRAPH-FA7A;Lo;0;L;5599;;;;N;;;;;
+FA7B;CJK COMPATIBILITY IDEOGRAPH-FA7B;Lo;0;L;55E2;;;;N;;;;;
+FA7C;CJK COMPATIBILITY IDEOGRAPH-FA7C;Lo;0;L;585A;;;;N;;;;;
+FA7D;CJK COMPATIBILITY IDEOGRAPH-FA7D;Lo;0;L;58B3;;;;N;;;;;
+FA7E;CJK COMPATIBILITY IDEOGRAPH-FA7E;Lo;0;L;5944;;;;N;;;;;
+FA7F;CJK COMPATIBILITY IDEOGRAPH-FA7F;Lo;0;L;5954;;;;N;;;;;
+FA80;CJK COMPATIBILITY IDEOGRAPH-FA80;Lo;0;L;5A62;;;;N;;;;;
+FA81;CJK COMPATIBILITY IDEOGRAPH-FA81;Lo;0;L;5B28;;;;N;;;;;
+FA82;CJK COMPATIBILITY IDEOGRAPH-FA82;Lo;0;L;5ED2;;;;N;;;;;
+FA83;CJK COMPATIBILITY IDEOGRAPH-FA83;Lo;0;L;5ED9;;;;N;;;;;
+FA84;CJK COMPATIBILITY IDEOGRAPH-FA84;Lo;0;L;5F69;;;;N;;;;;
+FA85;CJK COMPATIBILITY IDEOGRAPH-FA85;Lo;0;L;5FAD;;;;N;;;;;
+FA86;CJK COMPATIBILITY IDEOGRAPH-FA86;Lo;0;L;60D8;;;;N;;;;;
+FA87;CJK COMPATIBILITY IDEOGRAPH-FA87;Lo;0;L;614E;;;;N;;;;;
+FA88;CJK COMPATIBILITY IDEOGRAPH-FA88;Lo;0;L;6108;;;;N;;;;;
+FA89;CJK COMPATIBILITY IDEOGRAPH-FA89;Lo;0;L;618E;;;;N;;;;;
+FA8A;CJK COMPATIBILITY IDEOGRAPH-FA8A;Lo;0;L;6160;;;;N;;;;;
+FA8B;CJK COMPATIBILITY IDEOGRAPH-FA8B;Lo;0;L;61F2;;;;N;;;;;
+FA8C;CJK COMPATIBILITY IDEOGRAPH-FA8C;Lo;0;L;6234;;;;N;;;;;
+FA8D;CJK COMPATIBILITY IDEOGRAPH-FA8D;Lo;0;L;63C4;;;;N;;;;;
+FA8E;CJK COMPATIBILITY IDEOGRAPH-FA8E;Lo;0;L;641C;;;;N;;;;;
+FA8F;CJK COMPATIBILITY IDEOGRAPH-FA8F;Lo;0;L;6452;;;;N;;;;;
+FA90;CJK COMPATIBILITY IDEOGRAPH-FA90;Lo;0;L;6556;;;;N;;;;;
+FA91;CJK COMPATIBILITY IDEOGRAPH-FA91;Lo;0;L;6674;;;;N;;;;;
+FA92;CJK COMPATIBILITY IDEOGRAPH-FA92;Lo;0;L;6717;;;;N;;;;;
+FA93;CJK COMPATIBILITY IDEOGRAPH-FA93;Lo;0;L;671B;;;;N;;;;;
+FA94;CJK COMPATIBILITY IDEOGRAPH-FA94;Lo;0;L;6756;;;;N;;;;;
+FA95;CJK COMPATIBILITY IDEOGRAPH-FA95;Lo;0;L;6B79;;;;N;;;;;
+FA96;CJK COMPATIBILITY IDEOGRAPH-FA96;Lo;0;L;6BBA;;;;N;;;;;
+FA97;CJK COMPATIBILITY IDEOGRAPH-FA97;Lo;0;L;6D41;;;;N;;;;;
+FA98;CJK COMPATIBILITY IDEOGRAPH-FA98;Lo;0;L;6EDB;;;;N;;;;;
+FA99;CJK COMPATIBILITY IDEOGRAPH-FA99;Lo;0;L;6ECB;;;;N;;;;;
+FA9A;CJK COMPATIBILITY IDEOGRAPH-FA9A;Lo;0;L;6F22;;;;N;;;;;
+FA9B;CJK COMPATIBILITY IDEOGRAPH-FA9B;Lo;0;L;701E;;;;N;;;;;
+FA9C;CJK COMPATIBILITY IDEOGRAPH-FA9C;Lo;0;L;716E;;;;N;;;;;
+FA9D;CJK COMPATIBILITY IDEOGRAPH-FA9D;Lo;0;L;77A7;;;;N;;;;;
+FA9E;CJK COMPATIBILITY IDEOGRAPH-FA9E;Lo;0;L;7235;;;;N;;;;;
+FA9F;CJK COMPATIBILITY IDEOGRAPH-FA9F;Lo;0;L;72AF;;;;N;;;;;
+FAA0;CJK COMPATIBILITY IDEOGRAPH-FAA0;Lo;0;L;732A;;;;N;;;;;
+FAA1;CJK COMPATIBILITY IDEOGRAPH-FAA1;Lo;0;L;7471;;;;N;;;;;
+FAA2;CJK COMPATIBILITY IDEOGRAPH-FAA2;Lo;0;L;7506;;;;N;;;;;
+FAA3;CJK COMPATIBILITY IDEOGRAPH-FAA3;Lo;0;L;753B;;;;N;;;;;
+FAA4;CJK COMPATIBILITY IDEOGRAPH-FAA4;Lo;0;L;761D;;;;N;;;;;
+FAA5;CJK COMPATIBILITY IDEOGRAPH-FAA5;Lo;0;L;761F;;;;N;;;;;
+FAA6;CJK COMPATIBILITY IDEOGRAPH-FAA6;Lo;0;L;76CA;;;;N;;;;;
+FAA7;CJK COMPATIBILITY IDEOGRAPH-FAA7;Lo;0;L;76DB;;;;N;;;;;
+FAA8;CJK COMPATIBILITY IDEOGRAPH-FAA8;Lo;0;L;76F4;;;;N;;;;;
+FAA9;CJK COMPATIBILITY IDEOGRAPH-FAA9;Lo;0;L;774A;;;;N;;;;;
+FAAA;CJK COMPATIBILITY IDEOGRAPH-FAAA;Lo;0;L;7740;;;;N;;;;;
+FAAB;CJK COMPATIBILITY IDEOGRAPH-FAAB;Lo;0;L;78CC;;;;N;;;;;
+FAAC;CJK COMPATIBILITY IDEOGRAPH-FAAC;Lo;0;L;7AB1;;;;N;;;;;
+FAAD;CJK COMPATIBILITY IDEOGRAPH-FAAD;Lo;0;L;7BC0;;;;N;;;;;
+FAAE;CJK COMPATIBILITY IDEOGRAPH-FAAE;Lo;0;L;7C7B;;;;N;;;;;
+FAAF;CJK COMPATIBILITY IDEOGRAPH-FAAF;Lo;0;L;7D5B;;;;N;;;;;
+FAB0;CJK COMPATIBILITY IDEOGRAPH-FAB0;Lo;0;L;7DF4;;;;N;;;;;
+FAB1;CJK COMPATIBILITY IDEOGRAPH-FAB1;Lo;0;L;7F3E;;;;N;;;;;
+FAB2;CJK COMPATIBILITY IDEOGRAPH-FAB2;Lo;0;L;8005;;;;N;;;;;
+FAB3;CJK COMPATIBILITY IDEOGRAPH-FAB3;Lo;0;L;8352;;;;N;;;;;
+FAB4;CJK COMPATIBILITY IDEOGRAPH-FAB4;Lo;0;L;83EF;;;;N;;;;;
+FAB5;CJK COMPATIBILITY IDEOGRAPH-FAB5;Lo;0;L;8779;;;;N;;;;;
+FAB6;CJK COMPATIBILITY IDEOGRAPH-FAB6;Lo;0;L;8941;;;;N;;;;;
+FAB7;CJK COMPATIBILITY IDEOGRAPH-FAB7;Lo;0;L;8986;;;;N;;;;;
+FAB8;CJK COMPATIBILITY IDEOGRAPH-FAB8;Lo;0;L;8996;;;;N;;;;;
+FAB9;CJK COMPATIBILITY IDEOGRAPH-FAB9;Lo;0;L;8ABF;;;;N;;;;;
+FABA;CJK COMPATIBILITY IDEOGRAPH-FABA;Lo;0;L;8AF8;;;;N;;;;;
+FABB;CJK COMPATIBILITY IDEOGRAPH-FABB;Lo;0;L;8ACB;;;;N;;;;;
+FABC;CJK COMPATIBILITY IDEOGRAPH-FABC;Lo;0;L;8B01;;;;N;;;;;
+FABD;CJK COMPATIBILITY IDEOGRAPH-FABD;Lo;0;L;8AFE;;;;N;;;;;
+FABE;CJK COMPATIBILITY IDEOGRAPH-FABE;Lo;0;L;8AED;;;;N;;;;;
+FABF;CJK COMPATIBILITY IDEOGRAPH-FABF;Lo;0;L;8B39;;;;N;;;;;
+FAC0;CJK COMPATIBILITY IDEOGRAPH-FAC0;Lo;0;L;8B8A;;;;N;;;;;
+FAC1;CJK COMPATIBILITY IDEOGRAPH-FAC1;Lo;0;L;8D08;;;;N;;;;;
+FAC2;CJK COMPATIBILITY IDEOGRAPH-FAC2;Lo;0;L;8F38;;;;N;;;;;
+FAC3;CJK COMPATIBILITY IDEOGRAPH-FAC3;Lo;0;L;9072;;;;N;;;;;
+FAC4;CJK COMPATIBILITY IDEOGRAPH-FAC4;Lo;0;L;9199;;;;N;;;;;
+FAC5;CJK COMPATIBILITY IDEOGRAPH-FAC5;Lo;0;L;9276;;;;N;;;;;
+FAC6;CJK COMPATIBILITY IDEOGRAPH-FAC6;Lo;0;L;967C;;;;N;;;;;
+FAC7;CJK COMPATIBILITY IDEOGRAPH-FAC7;Lo;0;L;96E3;;;;N;;;;;
+FAC8;CJK COMPATIBILITY IDEOGRAPH-FAC8;Lo;0;L;9756;;;;N;;;;;
+FAC9;CJK COMPATIBILITY IDEOGRAPH-FAC9;Lo;0;L;97DB;;;;N;;;;;
+FACA;CJK COMPATIBILITY IDEOGRAPH-FACA;Lo;0;L;97FF;;;;N;;;;;
+FACB;CJK COMPATIBILITY IDEOGRAPH-FACB;Lo;0;L;980B;;;;N;;;;;
+FACC;CJK COMPATIBILITY IDEOGRAPH-FACC;Lo;0;L;983B;;;;N;;;;;
+FACD;CJK COMPATIBILITY IDEOGRAPH-FACD;Lo;0;L;9B12;;;;N;;;;;
+FACE;CJK COMPATIBILITY IDEOGRAPH-FACE;Lo;0;L;9F9C;;;;N;;;;;
+FACF;CJK COMPATIBILITY IDEOGRAPH-FACF;Lo;0;L;2284A;;;;N;;;;;
+FAD0;CJK COMPATIBILITY IDEOGRAPH-FAD0;Lo;0;L;22844;;;;N;;;;;
+FAD1;CJK COMPATIBILITY IDEOGRAPH-FAD1;Lo;0;L;233D5;;;;N;;;;;
+FAD2;CJK COMPATIBILITY IDEOGRAPH-FAD2;Lo;0;L;3B9D;;;;N;;;;;
+FAD3;CJK COMPATIBILITY IDEOGRAPH-FAD3;Lo;0;L;4018;;;;N;;;;;
+FAD4;CJK COMPATIBILITY IDEOGRAPH-FAD4;Lo;0;L;4039;;;;N;;;;;
+FAD5;CJK COMPATIBILITY IDEOGRAPH-FAD5;Lo;0;L;25249;;;;N;;;;;
+FAD6;CJK COMPATIBILITY IDEOGRAPH-FAD6;Lo;0;L;25CD0;;;;N;;;;;
+FAD7;CJK COMPATIBILITY IDEOGRAPH-FAD7;Lo;0;L;27ED3;;;;N;;;;;
+FAD8;CJK COMPATIBILITY IDEOGRAPH-FAD8;Lo;0;L;9F43;;;;N;;;;;
+FAD9;CJK COMPATIBILITY IDEOGRAPH-FAD9;Lo;0;L;9F8E;;;;N;;;;;
+FB00;LATIN SMALL LIGATURE FF;Ll;0;L;<compat> 0066 0066;;;;N;;;;;
+FB01;LATIN SMALL LIGATURE FI;Ll;0;L;<compat> 0066 0069;;;;N;;;;;
+FB02;LATIN SMALL LIGATURE FL;Ll;0;L;<compat> 0066 006C;;;;N;;;;;
+FB03;LATIN SMALL LIGATURE FFI;Ll;0;L;<compat> 0066 0066 0069;;;;N;;;;;
+FB04;LATIN SMALL LIGATURE FFL;Ll;0;L;<compat> 0066 0066 006C;;;;N;;;;;
+FB05;LATIN SMALL LIGATURE LONG S T;Ll;0;L;<compat> 017F 0074;;;;N;;;;;
+FB06;LATIN SMALL LIGATURE ST;Ll;0;L;<compat> 0073 0074;;;;N;;;;;
+FB13;ARMENIAN SMALL LIGATURE MEN NOW;Ll;0;L;<compat> 0574 0576;;;;N;;;;;
+FB14;ARMENIAN SMALL LIGATURE MEN ECH;Ll;0;L;<compat> 0574 0565;;;;N;;;;;
+FB15;ARMENIAN SMALL LIGATURE MEN INI;Ll;0;L;<compat> 0574 056B;;;;N;;;;;
+FB16;ARMENIAN SMALL LIGATURE VEW NOW;Ll;0;L;<compat> 057E 0576;;;;N;;;;;
+FB17;ARMENIAN SMALL LIGATURE MEN XEH;Ll;0;L;<compat> 0574 056D;;;;N;;;;;
+FB1D;HEBREW LETTER YOD WITH HIRIQ;Lo;0;R;05D9 05B4;;;;N;;;;;
+FB1E;HEBREW POINT JUDEO-SPANISH VARIKA;Mn;26;NSM;;;;;N;HEBREW POINT VARIKA;;;;
+FB1F;HEBREW LIGATURE YIDDISH YOD YOD PATAH;Lo;0;R;05F2 05B7;;;;N;;;;;
+FB20;HEBREW LETTER ALTERNATIVE AYIN;Lo;0;R;<font> 05E2;;;;N;;;;;
+FB21;HEBREW LETTER WIDE ALEF;Lo;0;R;<font> 05D0;;;;N;;;;;
+FB22;HEBREW LETTER WIDE DALET;Lo;0;R;<font> 05D3;;;;N;;;;;
+FB23;HEBREW LETTER WIDE HE;Lo;0;R;<font> 05D4;;;;N;;;;;
+FB24;HEBREW LETTER WIDE KAF;Lo;0;R;<font> 05DB;;;;N;;;;;
+FB25;HEBREW LETTER WIDE LAMED;Lo;0;R;<font> 05DC;;;;N;;;;;
+FB26;HEBREW LETTER WIDE FINAL MEM;Lo;0;R;<font> 05DD;;;;N;;;;;
+FB27;HEBREW LETTER WIDE RESH;Lo;0;R;<font> 05E8;;;;N;;;;;
+FB28;HEBREW LETTER WIDE TAV;Lo;0;R;<font> 05EA;;;;N;;;;;
+FB29;HEBREW LETTER ALTERNATIVE PLUS SIGN;Sm;0;ES;<font> 002B;;;;N;;;;;
+FB2A;HEBREW LETTER SHIN WITH SHIN DOT;Lo;0;R;05E9 05C1;;;;N;;;;;
+FB2B;HEBREW LETTER SHIN WITH SIN DOT;Lo;0;R;05E9 05C2;;;;N;;;;;
+FB2C;HEBREW LETTER SHIN WITH DAGESH AND SHIN DOT;Lo;0;R;FB49 05C1;;;;N;;;;;
+FB2D;HEBREW LETTER SHIN WITH DAGESH AND SIN DOT;Lo;0;R;FB49 05C2;;;;N;;;;;
+FB2E;HEBREW LETTER ALEF WITH PATAH;Lo;0;R;05D0 05B7;;;;N;;;;;
+FB2F;HEBREW LETTER ALEF WITH QAMATS;Lo;0;R;05D0 05B8;;;;N;;;;;
+FB30;HEBREW LETTER ALEF WITH MAPIQ;Lo;0;R;05D0 05BC;;;;N;;;;;
+FB31;HEBREW LETTER BET WITH DAGESH;Lo;0;R;05D1 05BC;;;;N;;;;;
+FB32;HEBREW LETTER GIMEL WITH DAGESH;Lo;0;R;05D2 05BC;;;;N;;;;;
+FB33;HEBREW LETTER DALET WITH DAGESH;Lo;0;R;05D3 05BC;;;;N;;;;;
+FB34;HEBREW LETTER HE WITH MAPIQ;Lo;0;R;05D4 05BC;;;;N;;;;;
+FB35;HEBREW LETTER VAV WITH DAGESH;Lo;0;R;05D5 05BC;;;;N;;;;;
+FB36;HEBREW LETTER ZAYIN WITH DAGESH;Lo;0;R;05D6 05BC;;;;N;;;;;
+FB38;HEBREW LETTER TET WITH DAGESH;Lo;0;R;05D8 05BC;;;;N;;;;;
+FB39;HEBREW LETTER YOD WITH DAGESH;Lo;0;R;05D9 05BC;;;;N;;;;;
+FB3A;HEBREW LETTER FINAL KAF WITH DAGESH;Lo;0;R;05DA 05BC;;;;N;;;;;
+FB3B;HEBREW LETTER KAF WITH DAGESH;Lo;0;R;05DB 05BC;;;;N;;;;;
+FB3C;HEBREW LETTER LAMED WITH DAGESH;Lo;0;R;05DC 05BC;;;;N;;;;;
+FB3E;HEBREW LETTER MEM WITH DAGESH;Lo;0;R;05DE 05BC;;;;N;;;;;
+FB40;HEBREW LETTER NUN WITH DAGESH;Lo;0;R;05E0 05BC;;;;N;;;;;
+FB41;HEBREW LETTER SAMEKH WITH DAGESH;Lo;0;R;05E1 05BC;;;;N;;;;;
+FB43;HEBREW LETTER FINAL PE WITH DAGESH;Lo;0;R;05E3 05BC;;;;N;;;;;
+FB44;HEBREW LETTER PE WITH DAGESH;Lo;0;R;05E4 05BC;;;;N;;;;;
+FB46;HEBREW LETTER TSADI WITH DAGESH;Lo;0;R;05E6 05BC;;;;N;;;;;
+FB47;HEBREW LETTER QOF WITH DAGESH;Lo;0;R;05E7 05BC;;;;N;;;;;
+FB48;HEBREW LETTER RESH WITH DAGESH;Lo;0;R;05E8 05BC;;;;N;;;;;
+FB49;HEBREW LETTER SHIN WITH DAGESH;Lo;0;R;05E9 05BC;;;;N;;;;;
+FB4A;HEBREW LETTER TAV WITH DAGESH;Lo;0;R;05EA 05BC;;;;N;;;;;
+FB4B;HEBREW LETTER VAV WITH HOLAM;Lo;0;R;05D5 05B9;;;;N;;;;;
+FB4C;HEBREW LETTER BET WITH RAFE;Lo;0;R;05D1 05BF;;;;N;;;;;
+FB4D;HEBREW LETTER KAF WITH RAFE;Lo;0;R;05DB 05BF;;;;N;;;;;
+FB4E;HEBREW LETTER PE WITH RAFE;Lo;0;R;05E4 05BF;;;;N;;;;;
+FB4F;HEBREW LIGATURE ALEF LAMED;Lo;0;R;<compat> 05D0 05DC;;;;N;;;;;
+FB50;ARABIC LETTER ALEF WASLA ISOLATED FORM;Lo;0;AL;<isolated> 0671;;;;N;;;;;
+FB51;ARABIC LETTER ALEF WASLA FINAL FORM;Lo;0;AL;<final> 0671;;;;N;;;;;
+FB52;ARABIC LETTER BEEH ISOLATED FORM;Lo;0;AL;<isolated> 067B;;;;N;;;;;
+FB53;ARABIC LETTER BEEH FINAL FORM;Lo;0;AL;<final> 067B;;;;N;;;;;
+FB54;ARABIC LETTER BEEH INITIAL FORM;Lo;0;AL;<initial> 067B;;;;N;;;;;
+FB55;ARABIC LETTER BEEH MEDIAL FORM;Lo;0;AL;<medial> 067B;;;;N;;;;;
+FB56;ARABIC LETTER PEH ISOLATED FORM;Lo;0;AL;<isolated> 067E;;;;N;;;;;
+FB57;ARABIC LETTER PEH FINAL FORM;Lo;0;AL;<final> 067E;;;;N;;;;;
+FB58;ARABIC LETTER PEH INITIAL FORM;Lo;0;AL;<initial> 067E;;;;N;;;;;
+FB59;ARABIC LETTER PEH MEDIAL FORM;Lo;0;AL;<medial> 067E;;;;N;;;;;
+FB5A;ARABIC LETTER BEHEH ISOLATED FORM;Lo;0;AL;<isolated> 0680;;;;N;;;;;
+FB5B;ARABIC LETTER BEHEH FINAL FORM;Lo;0;AL;<final> 0680;;;;N;;;;;
+FB5C;ARABIC LETTER BEHEH INITIAL FORM;Lo;0;AL;<initial> 0680;;;;N;;;;;
+FB5D;ARABIC LETTER BEHEH MEDIAL FORM;Lo;0;AL;<medial> 0680;;;;N;;;;;
+FB5E;ARABIC LETTER TTEHEH ISOLATED FORM;Lo;0;AL;<isolated> 067A;;;;N;;;;;
+FB5F;ARABIC LETTER TTEHEH FINAL FORM;Lo;0;AL;<final> 067A;;;;N;;;;;
+FB60;ARABIC LETTER TTEHEH INITIAL FORM;Lo;0;AL;<initial> 067A;;;;N;;;;;
+FB61;ARABIC LETTER TTEHEH MEDIAL FORM;Lo;0;AL;<medial> 067A;;;;N;;;;;
+FB62;ARABIC LETTER TEHEH ISOLATED FORM;Lo;0;AL;<isolated> 067F;;;;N;;;;;
+FB63;ARABIC LETTER TEHEH FINAL FORM;Lo;0;AL;<final> 067F;;;;N;;;;;
+FB64;ARABIC LETTER TEHEH INITIAL FORM;Lo;0;AL;<initial> 067F;;;;N;;;;;
+FB65;ARABIC LETTER TEHEH MEDIAL FORM;Lo;0;AL;<medial> 067F;;;;N;;;;;
+FB66;ARABIC LETTER TTEH ISOLATED FORM;Lo;0;AL;<isolated> 0679;;;;N;;;;;
+FB67;ARABIC LETTER TTEH FINAL FORM;Lo;0;AL;<final> 0679;;;;N;;;;;
+FB68;ARABIC LETTER TTEH INITIAL FORM;Lo;0;AL;<initial> 0679;;;;N;;;;;
+FB69;ARABIC LETTER TTEH MEDIAL FORM;Lo;0;AL;<medial> 0679;;;;N;;;;;
+FB6A;ARABIC LETTER VEH ISOLATED FORM;Lo;0;AL;<isolated> 06A4;;;;N;;;;;
+FB6B;ARABIC LETTER VEH FINAL FORM;Lo;0;AL;<final> 06A4;;;;N;;;;;
+FB6C;ARABIC LETTER VEH INITIAL FORM;Lo;0;AL;<initial> 06A4;;;;N;;;;;
+FB6D;ARABIC LETTER VEH MEDIAL FORM;Lo;0;AL;<medial> 06A4;;;;N;;;;;
+FB6E;ARABIC LETTER PEHEH ISOLATED FORM;Lo;0;AL;<isolated> 06A6;;;;N;;;;;
+FB6F;ARABIC LETTER PEHEH FINAL FORM;Lo;0;AL;<final> 06A6;;;;N;;;;;
+FB70;ARABIC LETTER PEHEH INITIAL FORM;Lo;0;AL;<initial> 06A6;;;;N;;;;;
+FB71;ARABIC LETTER PEHEH MEDIAL FORM;Lo;0;AL;<medial> 06A6;;;;N;;;;;
+FB72;ARABIC LETTER DYEH ISOLATED FORM;Lo;0;AL;<isolated> 0684;;;;N;;;;;
+FB73;ARABIC LETTER DYEH FINAL FORM;Lo;0;AL;<final> 0684;;;;N;;;;;
+FB74;ARABIC LETTER DYEH INITIAL FORM;Lo;0;AL;<initial> 0684;;;;N;;;;;
+FB75;ARABIC LETTER DYEH MEDIAL FORM;Lo;0;AL;<medial> 0684;;;;N;;;;;
+FB76;ARABIC LETTER NYEH ISOLATED FORM;Lo;0;AL;<isolated> 0683;;;;N;;;;;
+FB77;ARABIC LETTER NYEH FINAL FORM;Lo;0;AL;<final> 0683;;;;N;;;;;
+FB78;ARABIC LETTER NYEH INITIAL FORM;Lo;0;AL;<initial> 0683;;;;N;;;;;
+FB79;ARABIC LETTER NYEH MEDIAL FORM;Lo;0;AL;<medial> 0683;;;;N;;;;;
+FB7A;ARABIC LETTER TCHEH ISOLATED FORM;Lo;0;AL;<isolated> 0686;;;;N;;;;;
+FB7B;ARABIC LETTER TCHEH FINAL FORM;Lo;0;AL;<final> 0686;;;;N;;;;;
+FB7C;ARABIC LETTER TCHEH INITIAL FORM;Lo;0;AL;<initial> 0686;;;;N;;;;;
+FB7D;ARABIC LETTER TCHEH MEDIAL FORM;Lo;0;AL;<medial> 0686;;;;N;;;;;
+FB7E;ARABIC LETTER TCHEHEH ISOLATED FORM;Lo;0;AL;<isolated> 0687;;;;N;;;;;
+FB7F;ARABIC LETTER TCHEHEH FINAL FORM;Lo;0;AL;<final> 0687;;;;N;;;;;
+FB80;ARABIC LETTER TCHEHEH INITIAL FORM;Lo;0;AL;<initial> 0687;;;;N;;;;;
+FB81;ARABIC LETTER TCHEHEH MEDIAL FORM;Lo;0;AL;<medial> 0687;;;;N;;;;;
+FB82;ARABIC LETTER DDAHAL ISOLATED FORM;Lo;0;AL;<isolated> 068D;;;;N;;;;;
+FB83;ARABIC LETTER DDAHAL FINAL FORM;Lo;0;AL;<final> 068D;;;;N;;;;;
+FB84;ARABIC LETTER DAHAL ISOLATED FORM;Lo;0;AL;<isolated> 068C;;;;N;;;;;
+FB85;ARABIC LETTER DAHAL FINAL FORM;Lo;0;AL;<final> 068C;;;;N;;;;;
+FB86;ARABIC LETTER DUL ISOLATED FORM;Lo;0;AL;<isolated> 068E;;;;N;;;;;
+FB87;ARABIC LETTER DUL FINAL FORM;Lo;0;AL;<final> 068E;;;;N;;;;;
+FB88;ARABIC LETTER DDAL ISOLATED FORM;Lo;0;AL;<isolated> 0688;;;;N;;;;;
+FB89;ARABIC LETTER DDAL FINAL FORM;Lo;0;AL;<final> 0688;;;;N;;;;;
+FB8A;ARABIC LETTER JEH ISOLATED FORM;Lo;0;AL;<isolated> 0698;;;;N;;;;;
+FB8B;ARABIC LETTER JEH FINAL FORM;Lo;0;AL;<final> 0698;;;;N;;;;;
+FB8C;ARABIC LETTER RREH ISOLATED FORM;Lo;0;AL;<isolated> 0691;;;;N;;;;;
+FB8D;ARABIC LETTER RREH FINAL FORM;Lo;0;AL;<final> 0691;;;;N;;;;;
+FB8E;ARABIC LETTER KEHEH ISOLATED FORM;Lo;0;AL;<isolated> 06A9;;;;N;;;;;
+FB8F;ARABIC LETTER KEHEH FINAL FORM;Lo;0;AL;<final> 06A9;;;;N;;;;;
+FB90;ARABIC LETTER KEHEH INITIAL FORM;Lo;0;AL;<initial> 06A9;;;;N;;;;;
+FB91;ARABIC LETTER KEHEH MEDIAL FORM;Lo;0;AL;<medial> 06A9;;;;N;;;;;
+FB92;ARABIC LETTER GAF ISOLATED FORM;Lo;0;AL;<isolated> 06AF;;;;N;;;;;
+FB93;ARABIC LETTER GAF FINAL FORM;Lo;0;AL;<final> 06AF;;;;N;;;;;
+FB94;ARABIC LETTER GAF INITIAL FORM;Lo;0;AL;<initial> 06AF;;;;N;;;;;
+FB95;ARABIC LETTER GAF MEDIAL FORM;Lo;0;AL;<medial> 06AF;;;;N;;;;;
+FB96;ARABIC LETTER GUEH ISOLATED FORM;Lo;0;AL;<isolated> 06B3;;;;N;;;;;
+FB97;ARABIC LETTER GUEH FINAL FORM;Lo;0;AL;<final> 06B3;;;;N;;;;;
+FB98;ARABIC LETTER GUEH INITIAL FORM;Lo;0;AL;<initial> 06B3;;;;N;;;;;
+FB99;ARABIC LETTER GUEH MEDIAL FORM;Lo;0;AL;<medial> 06B3;;;;N;;;;;
+FB9A;ARABIC LETTER NGOEH ISOLATED FORM;Lo;0;AL;<isolated> 06B1;;;;N;;;;;
+FB9B;ARABIC LETTER NGOEH FINAL FORM;Lo;0;AL;<final> 06B1;;;;N;;;;;
+FB9C;ARABIC LETTER NGOEH INITIAL FORM;Lo;0;AL;<initial> 06B1;;;;N;;;;;
+FB9D;ARABIC LETTER NGOEH MEDIAL FORM;Lo;0;AL;<medial> 06B1;;;;N;;;;;
+FB9E;ARABIC LETTER NOON GHUNNA ISOLATED FORM;Lo;0;AL;<isolated> 06BA;;;;N;;;;;
+FB9F;ARABIC LETTER NOON GHUNNA FINAL FORM;Lo;0;AL;<final> 06BA;;;;N;;;;;
+FBA0;ARABIC LETTER RNOON ISOLATED FORM;Lo;0;AL;<isolated> 06BB;;;;N;;;;;
+FBA1;ARABIC LETTER RNOON FINAL FORM;Lo;0;AL;<final> 06BB;;;;N;;;;;
+FBA2;ARABIC LETTER RNOON INITIAL FORM;Lo;0;AL;<initial> 06BB;;;;N;;;;;
+FBA3;ARABIC LETTER RNOON MEDIAL FORM;Lo;0;AL;<medial> 06BB;;;;N;;;;;
+FBA4;ARABIC LETTER HEH WITH YEH ABOVE ISOLATED FORM;Lo;0;AL;<isolated> 06C0;;;;N;;;;;
+FBA5;ARABIC LETTER HEH WITH YEH ABOVE FINAL FORM;Lo;0;AL;<final> 06C0;;;;N;;;;;
+FBA6;ARABIC LETTER HEH GOAL ISOLATED FORM;Lo;0;AL;<isolated> 06C1;;;;N;;;;;
+FBA7;ARABIC LETTER HEH GOAL FINAL FORM;Lo;0;AL;<final> 06C1;;;;N;;;;;
+FBA8;ARABIC LETTER HEH GOAL INITIAL FORM;Lo;0;AL;<initial> 06C1;;;;N;;;;;
+FBA9;ARABIC LETTER HEH GOAL MEDIAL FORM;Lo;0;AL;<medial> 06C1;;;;N;;;;;
+FBAA;ARABIC LETTER HEH DOACHASHMEE ISOLATED FORM;Lo;0;AL;<isolated> 06BE;;;;N;;;;;
+FBAB;ARABIC LETTER HEH DOACHASHMEE FINAL FORM;Lo;0;AL;<final> 06BE;;;;N;;;;;
+FBAC;ARABIC LETTER HEH DOACHASHMEE INITIAL FORM;Lo;0;AL;<initial> 06BE;;;;N;;;;;
+FBAD;ARABIC LETTER HEH DOACHASHMEE MEDIAL FORM;Lo;0;AL;<medial> 06BE;;;;N;;;;;
+FBAE;ARABIC LETTER YEH BARREE ISOLATED FORM;Lo;0;AL;<isolated> 06D2;;;;N;;;;;
+FBAF;ARABIC LETTER YEH BARREE FINAL FORM;Lo;0;AL;<final> 06D2;;;;N;;;;;
+FBB0;ARABIC LETTER YEH BARREE WITH HAMZA ABOVE ISOLATED FORM;Lo;0;AL;<isolated> 06D3;;;;N;;;;;
+FBB1;ARABIC LETTER YEH BARREE WITH HAMZA ABOVE FINAL FORM;Lo;0;AL;<final> 06D3;;;;N;;;;;
+FBD3;ARABIC LETTER NG ISOLATED FORM;Lo;0;AL;<isolated> 06AD;;;;N;;;;;
+FBD4;ARABIC LETTER NG FINAL FORM;Lo;0;AL;<final> 06AD;;;;N;;;;;
+FBD5;ARABIC LETTER NG INITIAL FORM;Lo;0;AL;<initial> 06AD;;;;N;;;;;
+FBD6;ARABIC LETTER NG MEDIAL FORM;Lo;0;AL;<medial> 06AD;;;;N;;;;;
+FBD7;ARABIC LETTER U ISOLATED FORM;Lo;0;AL;<isolated> 06C7;;;;N;;;;;
+FBD8;ARABIC LETTER U FINAL FORM;Lo;0;AL;<final> 06C7;;;;N;;;;;
+FBD9;ARABIC LETTER OE ISOLATED FORM;Lo;0;AL;<isolated> 06C6;;;;N;;;;;
+FBDA;ARABIC LETTER OE FINAL FORM;Lo;0;AL;<final> 06C6;;;;N;;;;;
+FBDB;ARABIC LETTER YU ISOLATED FORM;Lo;0;AL;<isolated> 06C8;;;;N;;;;;
+FBDC;ARABIC LETTER YU FINAL FORM;Lo;0;AL;<final> 06C8;;;;N;;;;;
+FBDD;ARABIC LETTER U WITH HAMZA ABOVE ISOLATED FORM;Lo;0;AL;<isolated> 0677;;;;N;;;;;
+FBDE;ARABIC LETTER VE ISOLATED FORM;Lo;0;AL;<isolated> 06CB;;;;N;;;;;
+FBDF;ARABIC LETTER VE FINAL FORM;Lo;0;AL;<final> 06CB;;;;N;;;;;
+FBE0;ARABIC LETTER KIRGHIZ OE ISOLATED FORM;Lo;0;AL;<isolated> 06C5;;;;N;;;;;
+FBE1;ARABIC LETTER KIRGHIZ OE FINAL FORM;Lo;0;AL;<final> 06C5;;;;N;;;;;
+FBE2;ARABIC LETTER KIRGHIZ YU ISOLATED FORM;Lo;0;AL;<isolated> 06C9;;;;N;;;;;
+FBE3;ARABIC LETTER KIRGHIZ YU FINAL FORM;Lo;0;AL;<final> 06C9;;;;N;;;;;
+FBE4;ARABIC LETTER E ISOLATED FORM;Lo;0;AL;<isolated> 06D0;;;;N;;;;;
+FBE5;ARABIC LETTER E FINAL FORM;Lo;0;AL;<final> 06D0;;;;N;;;;;
+FBE6;ARABIC LETTER E INITIAL FORM;Lo;0;AL;<initial> 06D0;;;;N;;;;;
+FBE7;ARABIC LETTER E MEDIAL FORM;Lo;0;AL;<medial> 06D0;;;;N;;;;;
+FBE8;ARABIC LETTER UIGHUR KAZAKH KIRGHIZ ALEF MAKSURA INITIAL FORM;Lo;0;AL;<initial> 0649;;;;N;;;;;
+FBE9;ARABIC LETTER UIGHUR KAZAKH KIRGHIZ ALEF MAKSURA MEDIAL FORM;Lo;0;AL;<medial> 0649;;;;N;;;;;
+FBEA;ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH ALEF ISOLATED FORM;Lo;0;AL;<isolated> 0626 0627;;;;N;;;;;
+FBEB;ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH ALEF FINAL FORM;Lo;0;AL;<final> 0626 0627;;;;N;;;;;
+FBEC;ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH AE ISOLATED FORM;Lo;0;AL;<isolated> 0626 06D5;;;;N;;;;;
+FBED;ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH AE FINAL FORM;Lo;0;AL;<final> 0626 06D5;;;;N;;;;;
+FBEE;ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH WAW ISOLATED FORM;Lo;0;AL;<isolated> 0626 0648;;;;N;;;;;
+FBEF;ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH WAW FINAL FORM;Lo;0;AL;<final> 0626 0648;;;;N;;;;;
+FBF0;ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH U ISOLATED FORM;Lo;0;AL;<isolated> 0626 06C7;;;;N;;;;;
+FBF1;ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH U FINAL FORM;Lo;0;AL;<final> 0626 06C7;;;;N;;;;;
+FBF2;ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH OE ISOLATED FORM;Lo;0;AL;<isolated> 0626 06C6;;;;N;;;;;
+FBF3;ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH OE FINAL FORM;Lo;0;AL;<final> 0626 06C6;;;;N;;;;;
+FBF4;ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH YU ISOLATED FORM;Lo;0;AL;<isolated> 0626 06C8;;;;N;;;;;
+FBF5;ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH YU FINAL FORM;Lo;0;AL;<final> 0626 06C8;;;;N;;;;;
+FBF6;ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH E ISOLATED FORM;Lo;0;AL;<isolated> 0626 06D0;;;;N;;;;;
+FBF7;ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH E FINAL FORM;Lo;0;AL;<final> 0626 06D0;;;;N;;;;;
+FBF8;ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH E INITIAL FORM;Lo;0;AL;<initial> 0626 06D0;;;;N;;;;;
+FBF9;ARABIC LIGATURE UIGHUR KIRGHIZ YEH WITH HAMZA ABOVE WITH ALEF MAKSURA ISOLATED FORM;Lo;0;AL;<isolated> 0626 0649;;;;N;;;;;
+FBFA;ARABIC LIGATURE UIGHUR KIRGHIZ YEH WITH HAMZA ABOVE WITH ALEF MAKSURA FINAL FORM;Lo;0;AL;<final> 0626 0649;;;;N;;;;;
+FBFB;ARABIC LIGATURE UIGHUR KIRGHIZ YEH WITH HAMZA ABOVE WITH ALEF MAKSURA INITIAL FORM;Lo;0;AL;<initial> 0626 0649;;;;N;;;;;
+FBFC;ARABIC LETTER FARSI YEH ISOLATED FORM;Lo;0;AL;<isolated> 06CC;;;;N;;;;;
+FBFD;ARABIC LETTER FARSI YEH FINAL FORM;Lo;0;AL;<final> 06CC;;;;N;;;;;
+FBFE;ARABIC LETTER FARSI YEH INITIAL FORM;Lo;0;AL;<initial> 06CC;;;;N;;;;;
+FBFF;ARABIC LETTER FARSI YEH MEDIAL FORM;Lo;0;AL;<medial> 06CC;;;;N;;;;;
+FC00;ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH JEEM ISOLATED FORM;Lo;0;AL;<isolated> 0626 062C;;;;N;;;;;
+FC01;ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH HAH ISOLATED FORM;Lo;0;AL;<isolated> 0626 062D;;;;N;;;;;
+FC02;ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH MEEM ISOLATED FORM;Lo;0;AL;<isolated> 0626 0645;;;;N;;;;;
+FC03;ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH ALEF MAKSURA ISOLATED FORM;Lo;0;AL;<isolated> 0626 0649;;;;N;;;;;
+FC04;ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH YEH ISOLATED FORM;Lo;0;AL;<isolated> 0626 064A;;;;N;;;;;
+FC05;ARABIC LIGATURE BEH WITH JEEM ISOLATED FORM;Lo;0;AL;<isolated> 0628 062C;;;;N;;;;;
+FC06;ARABIC LIGATURE BEH WITH HAH ISOLATED FORM;Lo;0;AL;<isolated> 0628 062D;;;;N;;;;;
+FC07;ARABIC LIGATURE BEH WITH KHAH ISOLATED FORM;Lo;0;AL;<isolated> 0628 062E;;;;N;;;;;
+FC08;ARABIC LIGATURE BEH WITH MEEM ISOLATED FORM;Lo;0;AL;<isolated> 0628 0645;;;;N;;;;;
+FC09;ARABIC LIGATURE BEH WITH ALEF MAKSURA ISOLATED FORM;Lo;0;AL;<isolated> 0628 0649;;;;N;;;;;
+FC0A;ARABIC LIGATURE BEH WITH YEH ISOLATED FORM;Lo;0;AL;<isolated> 0628 064A;;;;N;;;;;
+FC0B;ARABIC LIGATURE TEH WITH JEEM ISOLATED FORM;Lo;0;AL;<isolated> 062A 062C;;;;N;;;;;
+FC0C;ARABIC LIGATURE TEH WITH HAH ISOLATED FORM;Lo;0;AL;<isolated> 062A 062D;;;;N;;;;;
+FC0D;ARABIC LIGATURE TEH WITH KHAH ISOLATED FORM;Lo;0;AL;<isolated> 062A 062E;;;;N;;;;;
+FC0E;ARABIC LIGATURE TEH WITH MEEM ISOLATED FORM;Lo;0;AL;<isolated> 062A 0645;;;;N;;;;;
+FC0F;ARABIC LIGATURE TEH WITH ALEF MAKSURA ISOLATED FORM;Lo;0;AL;<isolated> 062A 0649;;;;N;;;;;
+FC10;ARABIC LIGATURE TEH WITH YEH ISOLATED FORM;Lo;0;AL;<isolated> 062A 064A;;;;N;;;;;
+FC11;ARABIC LIGATURE THEH WITH JEEM ISOLATED FORM;Lo;0;AL;<isolated> 062B 062C;;;;N;;;;;
+FC12;ARABIC LIGATURE THEH WITH MEEM ISOLATED FORM;Lo;0;AL;<isolated> 062B 0645;;;;N;;;;;
+FC13;ARABIC LIGATURE THEH WITH ALEF MAKSURA ISOLATED FORM;Lo;0;AL;<isolated> 062B 0649;;;;N;;;;;
+FC14;ARABIC LIGATURE THEH WITH YEH ISOLATED FORM;Lo;0;AL;<isolated> 062B 064A;;;;N;;;;;
+FC15;ARABIC LIGATURE JEEM WITH HAH ISOLATED FORM;Lo;0;AL;<isolated> 062C 062D;;;;N;;;;;
+FC16;ARABIC LIGATURE JEEM WITH MEEM ISOLATED FORM;Lo;0;AL;<isolated> 062C 0645;;;;N;;;;;
+FC17;ARABIC LIGATURE HAH WITH JEEM ISOLATED FORM;Lo;0;AL;<isolated> 062D 062C;;;;N;;;;;
+FC18;ARABIC LIGATURE HAH WITH MEEM ISOLATED FORM;Lo;0;AL;<isolated> 062D 0645;;;;N;;;;;
+FC19;ARABIC LIGATURE KHAH WITH JEEM ISOLATED FORM;Lo;0;AL;<isolated> 062E 062C;;;;N;;;;;
+FC1A;ARABIC LIGATURE KHAH WITH HAH ISOLATED FORM;Lo;0;AL;<isolated> 062E 062D;;;;N;;;;;
+FC1B;ARABIC LIGATURE KHAH WITH MEEM ISOLATED FORM;Lo;0;AL;<isolated> 062E 0645;;;;N;;;;;
+FC1C;ARABIC LIGATURE SEEN WITH JEEM ISOLATED FORM;Lo;0;AL;<isolated> 0633 062C;;;;N;;;;;
+FC1D;ARABIC LIGATURE SEEN WITH HAH ISOLATED FORM;Lo;0;AL;<isolated> 0633 062D;;;;N;;;;;
+FC1E;ARABIC LIGATURE SEEN WITH KHAH ISOLATED FORM;Lo;0;AL;<isolated> 0633 062E;;;;N;;;;;
+FC1F;ARABIC LIGATURE SEEN WITH MEEM ISOLATED FORM;Lo;0;AL;<isolated> 0633 0645;;;;N;;;;;
+FC20;ARABIC LIGATURE SAD WITH HAH ISOLATED FORM;Lo;0;AL;<isolated> 0635 062D;;;;N;;;;;
+FC21;ARABIC LIGATURE SAD WITH MEEM ISOLATED FORM;Lo;0;AL;<isolated> 0635 0645;;;;N;;;;;
+FC22;ARABIC LIGATURE DAD WITH JEEM ISOLATED FORM;Lo;0;AL;<isolated> 0636 062C;;;;N;;;;;
+FC23;ARABIC LIGATURE DAD WITH HAH ISOLATED FORM;Lo;0;AL;<isolated> 0636 062D;;;;N;;;;;
+FC24;ARABIC LIGATURE DAD WITH KHAH ISOLATED FORM;Lo;0;AL;<isolated> 0636 062E;;;;N;;;;;
+FC25;ARABIC LIGATURE DAD WITH MEEM ISOLATED FORM;Lo;0;AL;<isolated> 0636 0645;;;;N;;;;;
+FC26;ARABIC LIGATURE TAH WITH HAH ISOLATED FORM;Lo;0;AL;<isolated> 0637 062D;;;;N;;;;;
+FC27;ARABIC LIGATURE TAH WITH MEEM ISOLATED FORM;Lo;0;AL;<isolated> 0637 0645;;;;N;;;;;
+FC28;ARABIC LIGATURE ZAH WITH MEEM ISOLATED FORM;Lo;0;AL;<isolated> 0638 0645;;;;N;;;;;
+FC29;ARABIC LIGATURE AIN WITH JEEM ISOLATED FORM;Lo;0;AL;<isolated> 0639 062C;;;;N;;;;;
+FC2A;ARABIC LIGATURE AIN WITH MEEM ISOLATED FORM;Lo;0;AL;<isolated> 0639 0645;;;;N;;;;;
+FC2B;ARABIC LIGATURE GHAIN WITH JEEM ISOLATED FORM;Lo;0;AL;<isolated> 063A 062C;;;;N;;;;;
+FC2C;ARABIC LIGATURE GHAIN WITH MEEM ISOLATED FORM;Lo;0;AL;<isolated> 063A 0645;;;;N;;;;;
+FC2D;ARABIC LIGATURE FEH WITH JEEM ISOLATED FORM;Lo;0;AL;<isolated> 0641 062C;;;;N;;;;;
+FC2E;ARABIC LIGATURE FEH WITH HAH ISOLATED FORM;Lo;0;AL;<isolated> 0641 062D;;;;N;;;;;
+FC2F;ARABIC LIGATURE FEH WITH KHAH ISOLATED FORM;Lo;0;AL;<isolated> 0641 062E;;;;N;;;;;
+FC30;ARABIC LIGATURE FEH WITH MEEM ISOLATED FORM;Lo;0;AL;<isolated> 0641 0645;;;;N;;;;;
+FC31;ARABIC LIGATURE FEH WITH ALEF MAKSURA ISOLATED FORM;Lo;0;AL;<isolated> 0641 0649;;;;N;;;;;
+FC32;ARABIC LIGATURE FEH WITH YEH ISOLATED FORM;Lo;0;AL;<isolated> 0641 064A;;;;N;;;;;
+FC33;ARABIC LIGATURE QAF WITH HAH ISOLATED FORM;Lo;0;AL;<isolated> 0642 062D;;;;N;;;;;
+FC34;ARABIC LIGATURE QAF WITH MEEM ISOLATED FORM;Lo;0;AL;<isolated> 0642 0645;;;;N;;;;;
+FC35;ARABIC LIGATURE QAF WITH ALEF MAKSURA ISOLATED FORM;Lo;0;AL;<isolated> 0642 0649;;;;N;;;;;
+FC36;ARABIC LIGATURE QAF WITH YEH ISOLATED FORM;Lo;0;AL;<isolated> 0642 064A;;;;N;;;;;
+FC37;ARABIC LIGATURE KAF WITH ALEF ISOLATED FORM;Lo;0;AL;<isolated> 0643 0627;;;;N;;;;;
+FC38;ARABIC LIGATURE KAF WITH JEEM ISOLATED FORM;Lo;0;AL;<isolated> 0643 062C;;;;N;;;;;
+FC39;ARABIC LIGATURE KAF WITH HAH ISOLATED FORM;Lo;0;AL;<isolated> 0643 062D;;;;N;;;;;
+FC3A;ARABIC LIGATURE KAF WITH KHAH ISOLATED FORM;Lo;0;AL;<isolated> 0643 062E;;;;N;;;;;
+FC3B;ARABIC LIGATURE KAF WITH LAM ISOLATED FORM;Lo;0;AL;<isolated> 0643 0644;;;;N;;;;;
+FC3C;ARABIC LIGATURE KAF WITH MEEM ISOLATED FORM;Lo;0;AL;<isolated> 0643 0645;;;;N;;;;;
+FC3D;ARABIC LIGATURE KAF WITH ALEF MAKSURA ISOLATED FORM;Lo;0;AL;<isolated> 0643 0649;;;;N;;;;;
+FC3E;ARABIC LIGATURE KAF WITH YEH ISOLATED FORM;Lo;0;AL;<isolated> 0643 064A;;;;N;;;;;
+FC3F;ARABIC LIGATURE LAM WITH JEEM ISOLATED FORM;Lo;0;AL;<isolated> 0644 062C;;;;N;;;;;
+FC40;ARABIC LIGATURE LAM WITH HAH ISOLATED FORM;Lo;0;AL;<isolated> 0644 062D;;;;N;;;;;
+FC41;ARABIC LIGATURE LAM WITH KHAH ISOLATED FORM;Lo;0;AL;<isolated> 0644 062E;;;;N;;;;;
+FC42;ARABIC LIGATURE LAM WITH MEEM ISOLATED FORM;Lo;0;AL;<isolated> 0644 0645;;;;N;;;;;
+FC43;ARABIC LIGATURE LAM WITH ALEF MAKSURA ISOLATED FORM;Lo;0;AL;<isolated> 0644 0649;;;;N;;;;;
+FC44;ARABIC LIGATURE LAM WITH YEH ISOLATED FORM;Lo;0;AL;<isolated> 0644 064A;;;;N;;;;;
+FC45;ARABIC LIGATURE MEEM WITH JEEM ISOLATED FORM;Lo;0;AL;<isolated> 0645 062C;;;;N;;;;;
+FC46;ARABIC LIGATURE MEEM WITH HAH ISOLATED FORM;Lo;0;AL;<isolated> 0645 062D;;;;N;;;;;
+FC47;ARABIC LIGATURE MEEM WITH KHAH ISOLATED FORM;Lo;0;AL;<isolated> 0645 062E;;;;N;;;;;
+FC48;ARABIC LIGATURE MEEM WITH MEEM ISOLATED FORM;Lo;0;AL;<isolated> 0645 0645;;;;N;;;;;
+FC49;ARABIC LIGATURE MEEM WITH ALEF MAKSURA ISOLATED FORM;Lo;0;AL;<isolated> 0645 0649;;;;N;;;;;
+FC4A;ARABIC LIGATURE MEEM WITH YEH ISOLATED FORM;Lo;0;AL;<isolated> 0645 064A;;;;N;;;;;
+FC4B;ARABIC LIGATURE NOON WITH JEEM ISOLATED FORM;Lo;0;AL;<isolated> 0646 062C;;;;N;;;;;
+FC4C;ARABIC LIGATURE NOON WITH HAH ISOLATED FORM;Lo;0;AL;<isolated> 0646 062D;;;;N;;;;;
+FC4D;ARABIC LIGATURE NOON WITH KHAH ISOLATED FORM;Lo;0;AL;<isolated> 0646 062E;;;;N;;;;;
+FC4E;ARABIC LIGATURE NOON WITH MEEM ISOLATED FORM;Lo;0;AL;<isolated> 0646 0645;;;;N;;;;;
+FC4F;ARABIC LIGATURE NOON WITH ALEF MAKSURA ISOLATED FORM;Lo;0;AL;<isolated> 0646 0649;;;;N;;;;;
+FC50;ARABIC LIGATURE NOON WITH YEH ISOLATED FORM;Lo;0;AL;<isolated> 0646 064A;;;;N;;;;;
+FC51;ARABIC LIGATURE HEH WITH JEEM ISOLATED FORM;Lo;0;AL;<isolated> 0647 062C;;;;N;;;;;
+FC52;ARABIC LIGATURE HEH WITH MEEM ISOLATED FORM;Lo;0;AL;<isolated> 0647 0645;;;;N;;;;;
+FC53;ARABIC LIGATURE HEH WITH ALEF MAKSURA ISOLATED FORM;Lo;0;AL;<isolated> 0647 0649;;;;N;;;;;
+FC54;ARABIC LIGATURE HEH WITH YEH ISOLATED FORM;Lo;0;AL;<isolated> 0647 064A;;;;N;;;;;
+FC55;ARABIC LIGATURE YEH WITH JEEM ISOLATED FORM;Lo;0;AL;<isolated> 064A 062C;;;;N;;;;;
+FC56;ARABIC LIGATURE YEH WITH HAH ISOLATED FORM;Lo;0;AL;<isolated> 064A 062D;;;;N;;;;;
+FC57;ARABIC LIGATURE YEH WITH KHAH ISOLATED FORM;Lo;0;AL;<isolated> 064A 062E;;;;N;;;;;
+FC58;ARABIC LIGATURE YEH WITH MEEM ISOLATED FORM;Lo;0;AL;<isolated> 064A 0645;;;;N;;;;;
+FC59;ARABIC LIGATURE YEH WITH ALEF MAKSURA ISOLATED FORM;Lo;0;AL;<isolated> 064A 0649;;;;N;;;;;
+FC5A;ARABIC LIGATURE YEH WITH YEH ISOLATED FORM;Lo;0;AL;<isolated> 064A 064A;;;;N;;;;;
+FC5B;ARABIC LIGATURE THAL WITH SUPERSCRIPT ALEF ISOLATED FORM;Lo;0;AL;<isolated> 0630 0670;;;;N;;;;;
+FC5C;ARABIC LIGATURE REH WITH SUPERSCRIPT ALEF ISOLATED FORM;Lo;0;AL;<isolated> 0631 0670;;;;N;;;;;
+FC5D;ARABIC LIGATURE ALEF MAKSURA WITH SUPERSCRIPT ALEF ISOLATED FORM;Lo;0;AL;<isolated> 0649 0670;;;;N;;;;;
+FC5E;ARABIC LIGATURE SHADDA WITH DAMMATAN ISOLATED FORM;Lo;0;AL;<isolated> 0020 064C 0651;;;;N;;;;;
+FC5F;ARABIC LIGATURE SHADDA WITH KASRATAN ISOLATED FORM;Lo;0;AL;<isolated> 0020 064D 0651;;;;N;;;;;
+FC60;ARABIC LIGATURE SHADDA WITH FATHA ISOLATED FORM;Lo;0;AL;<isolated> 0020 064E 0651;;;;N;;;;;
+FC61;ARABIC LIGATURE SHADDA WITH DAMMA ISOLATED FORM;Lo;0;AL;<isolated> 0020 064F 0651;;;;N;;;;;
+FC62;ARABIC LIGATURE SHADDA WITH KASRA ISOLATED FORM;Lo;0;AL;<isolated> 0020 0650 0651;;;;N;;;;;
+FC63;ARABIC LIGATURE SHADDA WITH SUPERSCRIPT ALEF ISOLATED FORM;Lo;0;AL;<isolated> 0020 0651 0670;;;;N;;;;;
+FC64;ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH REH FINAL FORM;Lo;0;AL;<final> 0626 0631;;;;N;;;;;
+FC65;ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH ZAIN FINAL FORM;Lo;0;AL;<final> 0626 0632;;;;N;;;;;
+FC66;ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH MEEM FINAL FORM;Lo;0;AL;<final> 0626 0645;;;;N;;;;;
+FC67;ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH NOON FINAL FORM;Lo;0;AL;<final> 0626 0646;;;;N;;;;;
+FC68;ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH ALEF MAKSURA FINAL FORM;Lo;0;AL;<final> 0626 0649;;;;N;;;;;
+FC69;ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH YEH FINAL FORM;Lo;0;AL;<final> 0626 064A;;;;N;;;;;
+FC6A;ARABIC LIGATURE BEH WITH REH FINAL FORM;Lo;0;AL;<final> 0628 0631;;;;N;;;;;
+FC6B;ARABIC LIGATURE BEH WITH ZAIN FINAL FORM;Lo;0;AL;<final> 0628 0632;;;;N;;;;;
+FC6C;ARABIC LIGATURE BEH WITH MEEM FINAL FORM;Lo;0;AL;<final> 0628 0645;;;;N;;;;;
+FC6D;ARABIC LIGATURE BEH WITH NOON FINAL FORM;Lo;0;AL;<final> 0628 0646;;;;N;;;;;
+FC6E;ARABIC LIGATURE BEH WITH ALEF MAKSURA FINAL FORM;Lo;0;AL;<final> 0628 0649;;;;N;;;;;
+FC6F;ARABIC LIGATURE BEH WITH YEH FINAL FORM;Lo;0;AL;<final> 0628 064A;;;;N;;;;;
+FC70;ARABIC LIGATURE TEH WITH REH FINAL FORM;Lo;0;AL;<final> 062A 0631;;;;N;;;;;
+FC71;ARABIC LIGATURE TEH WITH ZAIN FINAL FORM;Lo;0;AL;<final> 062A 0632;;;;N;;;;;
+FC72;ARABIC LIGATURE TEH WITH MEEM FINAL FORM;Lo;0;AL;<final> 062A 0645;;;;N;;;;;
+FC73;ARABIC LIGATURE TEH WITH NOON FINAL FORM;Lo;0;AL;<final> 062A 0646;;;;N;;;;;
+FC74;ARABIC LIGATURE TEH WITH ALEF MAKSURA FINAL FORM;Lo;0;AL;<final> 062A 0649;;;;N;;;;;
+FC75;ARABIC LIGATURE TEH WITH YEH FINAL FORM;Lo;0;AL;<final> 062A 064A;;;;N;;;;;
+FC76;ARABIC LIGATURE THEH WITH REH FINAL FORM;Lo;0;AL;<final> 062B 0631;;;;N;;;;;
+FC77;ARABIC LIGATURE THEH WITH ZAIN FINAL FORM;Lo;0;AL;<final> 062B 0632;;;;N;;;;;
+FC78;ARABIC LIGATURE THEH WITH MEEM FINAL FORM;Lo;0;AL;<final> 062B 0645;;;;N;;;;;
+FC79;ARABIC LIGATURE THEH WITH NOON FINAL FORM;Lo;0;AL;<final> 062B 0646;;;;N;;;;;
+FC7A;ARABIC LIGATURE THEH WITH ALEF MAKSURA FINAL FORM;Lo;0;AL;<final> 062B 0649;;;;N;;;;;
+FC7B;ARABIC LIGATURE THEH WITH YEH FINAL FORM;Lo;0;AL;<final> 062B 064A;;;;N;;;;;
+FC7C;ARABIC LIGATURE FEH WITH ALEF MAKSURA FINAL FORM;Lo;0;AL;<final> 0641 0649;;;;N;;;;;
+FC7D;ARABIC LIGATURE FEH WITH YEH FINAL FORM;Lo;0;AL;<final> 0641 064A;;;;N;;;;;
+FC7E;ARABIC LIGATURE QAF WITH ALEF MAKSURA FINAL FORM;Lo;0;AL;<final> 0642 0649;;;;N;;;;;
+FC7F;ARABIC LIGATURE QAF WITH YEH FINAL FORM;Lo;0;AL;<final> 0642 064A;;;;N;;;;;
+FC80;ARABIC LIGATURE KAF WITH ALEF FINAL FORM;Lo;0;AL;<final> 0643 0627;;;;N;;;;;
+FC81;ARABIC LIGATURE KAF WITH LAM FINAL FORM;Lo;0;AL;<final> 0643 0644;;;;N;;;;;
+FC82;ARABIC LIGATURE KAF WITH MEEM FINAL FORM;Lo;0;AL;<final> 0643 0645;;;;N;;;;;
+FC83;ARABIC LIGATURE KAF WITH ALEF MAKSURA FINAL FORM;Lo;0;AL;<final> 0643 0649;;;;N;;;;;
+FC84;ARABIC LIGATURE KAF WITH YEH FINAL FORM;Lo;0;AL;<final> 0643 064A;;;;N;;;;;
+FC85;ARABIC LIGATURE LAM WITH MEEM FINAL FORM;Lo;0;AL;<final> 0644 0645;;;;N;;;;;
+FC86;ARABIC LIGATURE LAM WITH ALEF MAKSURA FINAL FORM;Lo;0;AL;<final> 0644 0649;;;;N;;;;;
+FC87;ARABIC LIGATURE LAM WITH YEH FINAL FORM;Lo;0;AL;<final> 0644 064A;;;;N;;;;;
+FC88;ARABIC LIGATURE MEEM WITH ALEF FINAL FORM;Lo;0;AL;<final> 0645 0627;;;;N;;;;;
+FC89;ARABIC LIGATURE MEEM WITH MEEM FINAL FORM;Lo;0;AL;<final> 0645 0645;;;;N;;;;;
+FC8A;ARABIC LIGATURE NOON WITH REH FINAL FORM;Lo;0;AL;<final> 0646 0631;;;;N;;;;;
+FC8B;ARABIC LIGATURE NOON WITH ZAIN FINAL FORM;Lo;0;AL;<final> 0646 0632;;;;N;;;;;
+FC8C;ARABIC LIGATURE NOON WITH MEEM FINAL FORM;Lo;0;AL;<final> 0646 0645;;;;N;;;;;
+FC8D;ARABIC LIGATURE NOON WITH NOON FINAL FORM;Lo;0;AL;<final> 0646 0646;;;;N;;;;;
+FC8E;ARABIC LIGATURE NOON WITH ALEF MAKSURA FINAL FORM;Lo;0;AL;<final> 0646 0649;;;;N;;;;;
+FC8F;ARABIC LIGATURE NOON WITH YEH FINAL FORM;Lo;0;AL;<final> 0646 064A;;;;N;;;;;
+FC90;ARABIC LIGATURE ALEF MAKSURA WITH SUPERSCRIPT ALEF FINAL FORM;Lo;0;AL;<final> 0649 0670;;;;N;;;;;
+FC91;ARABIC LIGATURE YEH WITH REH FINAL FORM;Lo;0;AL;<final> 064A 0631;;;;N;;;;;
+FC92;ARABIC LIGATURE YEH WITH ZAIN FINAL FORM;Lo;0;AL;<final> 064A 0632;;;;N;;;;;
+FC93;ARABIC LIGATURE YEH WITH MEEM FINAL FORM;Lo;0;AL;<final> 064A 0645;;;;N;;;;;
+FC94;ARABIC LIGATURE YEH WITH NOON FINAL FORM;Lo;0;AL;<final> 064A 0646;;;;N;;;;;
+FC95;ARABIC LIGATURE YEH WITH ALEF MAKSURA FINAL FORM;Lo;0;AL;<final> 064A 0649;;;;N;;;;;
+FC96;ARABIC LIGATURE YEH WITH YEH FINAL FORM;Lo;0;AL;<final> 064A 064A;;;;N;;;;;
+FC97;ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH JEEM INITIAL FORM;Lo;0;AL;<initial> 0626 062C;;;;N;;;;;
+FC98;ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH HAH INITIAL FORM;Lo;0;AL;<initial> 0626 062D;;;;N;;;;;
+FC99;ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH KHAH INITIAL FORM;Lo;0;AL;<initial> 0626 062E;;;;N;;;;;
+FC9A;ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH MEEM INITIAL FORM;Lo;0;AL;<initial> 0626 0645;;;;N;;;;;
+FC9B;ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH HEH INITIAL FORM;Lo;0;AL;<initial> 0626 0647;;;;N;;;;;
+FC9C;ARABIC LIGATURE BEH WITH JEEM INITIAL FORM;Lo;0;AL;<initial> 0628 062C;;;;N;;;;;
+FC9D;ARABIC LIGATURE BEH WITH HAH INITIAL FORM;Lo;0;AL;<initial> 0628 062D;;;;N;;;;;
+FC9E;ARABIC LIGATURE BEH WITH KHAH INITIAL FORM;Lo;0;AL;<initial> 0628 062E;;;;N;;;;;
+FC9F;ARABIC LIGATURE BEH WITH MEEM INITIAL FORM;Lo;0;AL;<initial> 0628 0645;;;;N;;;;;
+FCA0;ARABIC LIGATURE BEH WITH HEH INITIAL FORM;Lo;0;AL;<initial> 0628 0647;;;;N;;;;;
+FCA1;ARABIC LIGATURE TEH WITH JEEM INITIAL FORM;Lo;0;AL;<initial> 062A 062C;;;;N;;;;;
+FCA2;ARABIC LIGATURE TEH WITH HAH INITIAL FORM;Lo;0;AL;<initial> 062A 062D;;;;N;;;;;
+FCA3;ARABIC LIGATURE TEH WITH KHAH INITIAL FORM;Lo;0;AL;<initial> 062A 062E;;;;N;;;;;
+FCA4;ARABIC LIGATURE TEH WITH MEEM INITIAL FORM;Lo;0;AL;<initial> 062A 0645;;;;N;;;;;
+FCA5;ARABIC LIGATURE TEH WITH HEH INITIAL FORM;Lo;0;AL;<initial> 062A 0647;;;;N;;;;;
+FCA6;ARABIC LIGATURE THEH WITH MEEM INITIAL FORM;Lo;0;AL;<initial> 062B 0645;;;;N;;;;;
+FCA7;ARABIC LIGATURE JEEM WITH HAH INITIAL FORM;Lo;0;AL;<initial> 062C 062D;;;;N;;;;;
+FCA8;ARABIC LIGATURE JEEM WITH MEEM INITIAL FORM;Lo;0;AL;<initial> 062C 0645;;;;N;;;;;
+FCA9;ARABIC LIGATURE HAH WITH JEEM INITIAL FORM;Lo;0;AL;<initial> 062D 062C;;;;N;;;;;
+FCAA;ARABIC LIGATURE HAH WITH MEEM INITIAL FORM;Lo;0;AL;<initial> 062D 0645;;;;N;;;;;
+FCAB;ARABIC LIGATURE KHAH WITH JEEM INITIAL FORM;Lo;0;AL;<initial> 062E 062C;;;;N;;;;;
+FCAC;ARABIC LIGATURE KHAH WITH MEEM INITIAL FORM;Lo;0;AL;<initial> 062E 0645;;;;N;;;;;
+FCAD;ARABIC LIGATURE SEEN WITH JEEM INITIAL FORM;Lo;0;AL;<initial> 0633 062C;;;;N;;;;;
+FCAE;ARABIC LIGATURE SEEN WITH HAH INITIAL FORM;Lo;0;AL;<initial> 0633 062D;;;;N;;;;;
+FCAF;ARABIC LIGATURE SEEN WITH KHAH INITIAL FORM;Lo;0;AL;<initial> 0633 062E;;;;N;;;;;
+FCB0;ARABIC LIGATURE SEEN WITH MEEM INITIAL FORM;Lo;0;AL;<initial> 0633 0645;;;;N;;;;;
+FCB1;ARABIC LIGATURE SAD WITH HAH INITIAL FORM;Lo;0;AL;<initial> 0635 062D;;;;N;;;;;
+FCB2;ARABIC LIGATURE SAD WITH KHAH INITIAL FORM;Lo;0;AL;<initial> 0635 062E;;;;N;;;;;
+FCB3;ARABIC LIGATURE SAD WITH MEEM INITIAL FORM;Lo;0;AL;<initial> 0635 0645;;;;N;;;;;
+FCB4;ARABIC LIGATURE DAD WITH JEEM INITIAL FORM;Lo;0;AL;<initial> 0636 062C;;;;N;;;;;
+FCB5;ARABIC LIGATURE DAD WITH HAH INITIAL FORM;Lo;0;AL;<initial> 0636 062D;;;;N;;;;;
+FCB6;ARABIC LIGATURE DAD WITH KHAH INITIAL FORM;Lo;0;AL;<initial> 0636 062E;;;;N;;;;;
+FCB7;ARABIC LIGATURE DAD WITH MEEM INITIAL FORM;Lo;0;AL;<initial> 0636 0645;;;;N;;;;;
+FCB8;ARABIC LIGATURE TAH WITH HAH INITIAL FORM;Lo;0;AL;<initial> 0637 062D;;;;N;;;;;
+FCB9;ARABIC LIGATURE ZAH WITH MEEM INITIAL FORM;Lo;0;AL;<initial> 0638 0645;;;;N;;;;;
+FCBA;ARABIC LIGATURE AIN WITH JEEM INITIAL FORM;Lo;0;AL;<initial> 0639 062C;;;;N;;;;;
+FCBB;ARABIC LIGATURE AIN WITH MEEM INITIAL FORM;Lo;0;AL;<initial> 0639 0645;;;;N;;;;;
+FCBC;ARABIC LIGATURE GHAIN WITH JEEM INITIAL FORM;Lo;0;AL;<initial> 063A 062C;;;;N;;;;;
+FCBD;ARABIC LIGATURE GHAIN WITH MEEM INITIAL FORM;Lo;0;AL;<initial> 063A 0645;;;;N;;;;;
+FCBE;ARABIC LIGATURE FEH WITH JEEM INITIAL FORM;Lo;0;AL;<initial> 0641 062C;;;;N;;;;;
+FCBF;ARABIC LIGATURE FEH WITH HAH INITIAL FORM;Lo;0;AL;<initial> 0641 062D;;;;N;;;;;
+FCC0;ARABIC LIGATURE FEH WITH KHAH INITIAL FORM;Lo;0;AL;<initial> 0641 062E;;;;N;;;;;
+FCC1;ARABIC LIGATURE FEH WITH MEEM INITIAL FORM;Lo;0;AL;<initial> 0641 0645;;;;N;;;;;
+FCC2;ARABIC LIGATURE QAF WITH HAH INITIAL FORM;Lo;0;AL;<initial> 0642 062D;;;;N;;;;;
+FCC3;ARABIC LIGATURE QAF WITH MEEM INITIAL FORM;Lo;0;AL;<initial> 0642 0645;;;;N;;;;;
+FCC4;ARABIC LIGATURE KAF WITH JEEM INITIAL FORM;Lo;0;AL;<initial> 0643 062C;;;;N;;;;;
+FCC5;ARABIC LIGATURE KAF WITH HAH INITIAL FORM;Lo;0;AL;<initial> 0643 062D;;;;N;;;;;
+FCC6;ARABIC LIGATURE KAF WITH KHAH INITIAL FORM;Lo;0;AL;<initial> 0643 062E;;;;N;;;;;
+FCC7;ARABIC LIGATURE KAF WITH LAM INITIAL FORM;Lo;0;AL;<initial> 0643 0644;;;;N;;;;;
+FCC8;ARABIC LIGATURE KAF WITH MEEM INITIAL FORM;Lo;0;AL;<initial> 0643 0645;;;;N;;;;;
+FCC9;ARABIC LIGATURE LAM WITH JEEM INITIAL FORM;Lo;0;AL;<initial> 0644 062C;;;;N;;;;;
+FCCA;ARABIC LIGATURE LAM WITH HAH INITIAL FORM;Lo;0;AL;<initial> 0644 062D;;;;N;;;;;
+FCCB;ARABIC LIGATURE LAM WITH KHAH INITIAL FORM;Lo;0;AL;<initial> 0644 062E;;;;N;;;;;
+FCCC;ARABIC LIGATURE LAM WITH MEEM INITIAL FORM;Lo;0;AL;<initial> 0644 0645;;;;N;;;;;
+FCCD;ARABIC LIGATURE LAM WITH HEH INITIAL FORM;Lo;0;AL;<initial> 0644 0647;;;;N;;;;;
+FCCE;ARABIC LIGATURE MEEM WITH JEEM INITIAL FORM;Lo;0;AL;<initial> 0645 062C;;;;N;;;;;
+FCCF;ARABIC LIGATURE MEEM WITH HAH INITIAL FORM;Lo;0;AL;<initial> 0645 062D;;;;N;;;;;
+FCD0;ARABIC LIGATURE MEEM WITH KHAH INITIAL FORM;Lo;0;AL;<initial> 0645 062E;;;;N;;;;;
+FCD1;ARABIC LIGATURE MEEM WITH MEEM INITIAL FORM;Lo;0;AL;<initial> 0645 0645;;;;N;;;;;
+FCD2;ARABIC LIGATURE NOON WITH JEEM INITIAL FORM;Lo;0;AL;<initial> 0646 062C;;;;N;;;;;
+FCD3;ARABIC LIGATURE NOON WITH HAH INITIAL FORM;Lo;0;AL;<initial> 0646 062D;;;;N;;;;;
+FCD4;ARABIC LIGATURE NOON WITH KHAH INITIAL FORM;Lo;0;AL;<initial> 0646 062E;;;;N;;;;;
+FCD5;ARABIC LIGATURE NOON WITH MEEM INITIAL FORM;Lo;0;AL;<initial> 0646 0645;;;;N;;;;;
+FCD6;ARABIC LIGATURE NOON WITH HEH INITIAL FORM;Lo;0;AL;<initial> 0646 0647;;;;N;;;;;
+FCD7;ARABIC LIGATURE HEH WITH JEEM INITIAL FORM;Lo;0;AL;<initial> 0647 062C;;;;N;;;;;
+FCD8;ARABIC LIGATURE HEH WITH MEEM INITIAL FORM;Lo;0;AL;<initial> 0647 0645;;;;N;;;;;
+FCD9;ARABIC LIGATURE HEH WITH SUPERSCRIPT ALEF INITIAL FORM;Lo;0;AL;<initial> 0647 0670;;;;N;;;;;
+FCDA;ARABIC LIGATURE YEH WITH JEEM INITIAL FORM;Lo;0;AL;<initial> 064A 062C;;;;N;;;;;
+FCDB;ARABIC LIGATURE YEH WITH HAH INITIAL FORM;Lo;0;AL;<initial> 064A 062D;;;;N;;;;;
+FCDC;ARABIC LIGATURE YEH WITH KHAH INITIAL FORM;Lo;0;AL;<initial> 064A 062E;;;;N;;;;;
+FCDD;ARABIC LIGATURE YEH WITH MEEM INITIAL FORM;Lo;0;AL;<initial> 064A 0645;;;;N;;;;;
+FCDE;ARABIC LIGATURE YEH WITH HEH INITIAL FORM;Lo;0;AL;<initial> 064A 0647;;;;N;;;;;
+FCDF;ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH MEEM MEDIAL FORM;Lo;0;AL;<medial> 0626 0645;;;;N;;;;;
+FCE0;ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH HEH MEDIAL FORM;Lo;0;AL;<medial> 0626 0647;;;;N;;;;;
+FCE1;ARABIC LIGATURE BEH WITH MEEM MEDIAL FORM;Lo;0;AL;<medial> 0628 0645;;;;N;;;;;
+FCE2;ARABIC LIGATURE BEH WITH HEH MEDIAL FORM;Lo;0;AL;<medial> 0628 0647;;;;N;;;;;
+FCE3;ARABIC LIGATURE TEH WITH MEEM MEDIAL FORM;Lo;0;AL;<medial> 062A 0645;;;;N;;;;;
+FCE4;ARABIC LIGATURE TEH WITH HEH MEDIAL FORM;Lo;0;AL;<medial> 062A 0647;;;;N;;;;;
+FCE5;ARABIC LIGATURE THEH WITH MEEM MEDIAL FORM;Lo;0;AL;<medial> 062B 0645;;;;N;;;;;
+FCE6;ARABIC LIGATURE THEH WITH HEH MEDIAL FORM;Lo;0;AL;<medial> 062B 0647;;;;N;;;;;
+FCE7;ARABIC LIGATURE SEEN WITH MEEM MEDIAL FORM;Lo;0;AL;<medial> 0633 0645;;;;N;;;;;
+FCE8;ARABIC LIGATURE SEEN WITH HEH MEDIAL FORM;Lo;0;AL;<medial> 0633 0647;;;;N;;;;;
+FCE9;ARABIC LIGATURE SHEEN WITH MEEM MEDIAL FORM;Lo;0;AL;<medial> 0634 0645;;;;N;;;;;
+FCEA;ARABIC LIGATURE SHEEN WITH HEH MEDIAL FORM;Lo;0;AL;<medial> 0634 0647;;;;N;;;;;
+FCEB;ARABIC LIGATURE KAF WITH LAM MEDIAL FORM;Lo;0;AL;<medial> 0643 0644;;;;N;;;;;
+FCEC;ARABIC LIGATURE KAF WITH MEEM MEDIAL FORM;Lo;0;AL;<medial> 0643 0645;;;;N;;;;;
+FCED;ARABIC LIGATURE LAM WITH MEEM MEDIAL FORM;Lo;0;AL;<medial> 0644 0645;;;;N;;;;;
+FCEE;ARABIC LIGATURE NOON WITH MEEM MEDIAL FORM;Lo;0;AL;<medial> 0646 0645;;;;N;;;;;
+FCEF;ARABIC LIGATURE NOON WITH HEH MEDIAL FORM;Lo;0;AL;<medial> 0646 0647;;;;N;;;;;
+FCF0;ARABIC LIGATURE YEH WITH MEEM MEDIAL FORM;Lo;0;AL;<medial> 064A 0645;;;;N;;;;;
+FCF1;ARABIC LIGATURE YEH WITH HEH MEDIAL FORM;Lo;0;AL;<medial> 064A 0647;;;;N;;;;;
+FCF2;ARABIC LIGATURE SHADDA WITH FATHA MEDIAL FORM;Lo;0;AL;<medial> 0640 064E 0651;;;;N;;;;;
+FCF3;ARABIC LIGATURE SHADDA WITH DAMMA MEDIAL FORM;Lo;0;AL;<medial> 0640 064F 0651;;;;N;;;;;
+FCF4;ARABIC LIGATURE SHADDA WITH KASRA MEDIAL FORM;Lo;0;AL;<medial> 0640 0650 0651;;;;N;;;;;
+FCF5;ARABIC LIGATURE TAH WITH ALEF MAKSURA ISOLATED FORM;Lo;0;AL;<isolated> 0637 0649;;;;N;;;;;
+FCF6;ARABIC LIGATURE TAH WITH YEH ISOLATED FORM;Lo;0;AL;<isolated> 0637 064A;;;;N;;;;;
+FCF7;ARABIC LIGATURE AIN WITH ALEF MAKSURA ISOLATED FORM;Lo;0;AL;<isolated> 0639 0649;;;;N;;;;;
+FCF8;ARABIC LIGATURE AIN WITH YEH ISOLATED FORM;Lo;0;AL;<isolated> 0639 064A;;;;N;;;;;
+FCF9;ARABIC LIGATURE GHAIN WITH ALEF MAKSURA ISOLATED FORM;Lo;0;AL;<isolated> 063A 0649;;;;N;;;;;
+FCFA;ARABIC LIGATURE GHAIN WITH YEH ISOLATED FORM;Lo;0;AL;<isolated> 063A 064A;;;;N;;;;;
+FCFB;ARABIC LIGATURE SEEN WITH ALEF MAKSURA ISOLATED FORM;Lo;0;AL;<isolated> 0633 0649;;;;N;;;;;
+FCFC;ARABIC LIGATURE SEEN WITH YEH ISOLATED FORM;Lo;0;AL;<isolated> 0633 064A;;;;N;;;;;
+FCFD;ARABIC LIGATURE SHEEN WITH ALEF MAKSURA ISOLATED FORM;Lo;0;AL;<isolated> 0634 0649;;;;N;;;;;
+FCFE;ARABIC LIGATURE SHEEN WITH YEH ISOLATED FORM;Lo;0;AL;<isolated> 0634 064A;;;;N;;;;;
+FCFF;ARABIC LIGATURE HAH WITH ALEF MAKSURA ISOLATED FORM;Lo;0;AL;<isolated> 062D 0649;;;;N;;;;;
+FD00;ARABIC LIGATURE HAH WITH YEH ISOLATED FORM;Lo;0;AL;<isolated> 062D 064A;;;;N;;;;;
+FD01;ARABIC LIGATURE JEEM WITH ALEF MAKSURA ISOLATED FORM;Lo;0;AL;<isolated> 062C 0649;;;;N;;;;;
+FD02;ARABIC LIGATURE JEEM WITH YEH ISOLATED FORM;Lo;0;AL;<isolated> 062C 064A;;;;N;;;;;
+FD03;ARABIC LIGATURE KHAH WITH ALEF MAKSURA ISOLATED FORM;Lo;0;AL;<isolated> 062E 0649;;;;N;;;;;
+FD04;ARABIC LIGATURE KHAH WITH YEH ISOLATED FORM;Lo;0;AL;<isolated> 062E 064A;;;;N;;;;;
+FD05;ARABIC LIGATURE SAD WITH ALEF MAKSURA ISOLATED FORM;Lo;0;AL;<isolated> 0635 0649;;;;N;;;;;
+FD06;ARABIC LIGATURE SAD WITH YEH ISOLATED FORM;Lo;0;AL;<isolated> 0635 064A;;;;N;;;;;
+FD07;ARABIC LIGATURE DAD WITH ALEF MAKSURA ISOLATED FORM;Lo;0;AL;<isolated> 0636 0649;;;;N;;;;;
+FD08;ARABIC LIGATURE DAD WITH YEH ISOLATED FORM;Lo;0;AL;<isolated> 0636 064A;;;;N;;;;;
+FD09;ARABIC LIGATURE SHEEN WITH JEEM ISOLATED FORM;Lo;0;AL;<isolated> 0634 062C;;;;N;;;;;
+FD0A;ARABIC LIGATURE SHEEN WITH HAH ISOLATED FORM;Lo;0;AL;<isolated> 0634 062D;;;;N;;;;;
+FD0B;ARABIC LIGATURE SHEEN WITH KHAH ISOLATED FORM;Lo;0;AL;<isolated> 0634 062E;;;;N;;;;;
+FD0C;ARABIC LIGATURE SHEEN WITH MEEM ISOLATED FORM;Lo;0;AL;<isolated> 0634 0645;;;;N;;;;;
+FD0D;ARABIC LIGATURE SHEEN WITH REH ISOLATED FORM;Lo;0;AL;<isolated> 0634 0631;;;;N;;;;;
+FD0E;ARABIC LIGATURE SEEN WITH REH ISOLATED FORM;Lo;0;AL;<isolated> 0633 0631;;;;N;;;;;
+FD0F;ARABIC LIGATURE SAD WITH REH ISOLATED FORM;Lo;0;AL;<isolated> 0635 0631;;;;N;;;;;
+FD10;ARABIC LIGATURE DAD WITH REH ISOLATED FORM;Lo;0;AL;<isolated> 0636 0631;;;;N;;;;;
+FD11;ARABIC LIGATURE TAH WITH ALEF MAKSURA FINAL FORM;Lo;0;AL;<final> 0637 0649;;;;N;;;;;
+FD12;ARABIC LIGATURE TAH WITH YEH FINAL FORM;Lo;0;AL;<final> 0637 064A;;;;N;;;;;
+FD13;ARABIC LIGATURE AIN WITH ALEF MAKSURA FINAL FORM;Lo;0;AL;<final> 0639 0649;;;;N;;;;;
+FD14;ARABIC LIGATURE AIN WITH YEH FINAL FORM;Lo;0;AL;<final> 0639 064A;;;;N;;;;;
+FD15;ARABIC LIGATURE GHAIN WITH ALEF MAKSURA FINAL FORM;Lo;0;AL;<final> 063A 0649;;;;N;;;;;
+FD16;ARABIC LIGATURE GHAIN WITH YEH FINAL FORM;Lo;0;AL;<final> 063A 064A;;;;N;;;;;
+FD17;ARABIC LIGATURE SEEN WITH ALEF MAKSURA FINAL FORM;Lo;0;AL;<final> 0633 0649;;;;N;;;;;
+FD18;ARABIC LIGATURE SEEN WITH YEH FINAL FORM;Lo;0;AL;<final> 0633 064A;;;;N;;;;;
+FD19;ARABIC LIGATURE SHEEN WITH ALEF MAKSURA FINAL FORM;Lo;0;AL;<final> 0634 0649;;;;N;;;;;
+FD1A;ARABIC LIGATURE SHEEN WITH YEH FINAL FORM;Lo;0;AL;<final> 0634 064A;;;;N;;;;;
+FD1B;ARABIC LIGATURE HAH WITH ALEF MAKSURA FINAL FORM;Lo;0;AL;<final> 062D 0649;;;;N;;;;;
+FD1C;ARABIC LIGATURE HAH WITH YEH FINAL FORM;Lo;0;AL;<final> 062D 064A;;;;N;;;;;
+FD1D;ARABIC LIGATURE JEEM WITH ALEF MAKSURA FINAL FORM;Lo;0;AL;<final> 062C 0649;;;;N;;;;;
+FD1E;ARABIC LIGATURE JEEM WITH YEH FINAL FORM;Lo;0;AL;<final> 062C 064A;;;;N;;;;;
+FD1F;ARABIC LIGATURE KHAH WITH ALEF MAKSURA FINAL FORM;Lo;0;AL;<final> 062E 0649;;;;N;;;;;
+FD20;ARABIC LIGATURE KHAH WITH YEH FINAL FORM;Lo;0;AL;<final> 062E 064A;;;;N;;;;;
+FD21;ARABIC LIGATURE SAD WITH ALEF MAKSURA FINAL FORM;Lo;0;AL;<final> 0635 0649;;;;N;;;;;
+FD22;ARABIC LIGATURE SAD WITH YEH FINAL FORM;Lo;0;AL;<final> 0635 064A;;;;N;;;;;
+FD23;ARABIC LIGATURE DAD WITH ALEF MAKSURA FINAL FORM;Lo;0;AL;<final> 0636 0649;;;;N;;;;;
+FD24;ARABIC LIGATURE DAD WITH YEH FINAL FORM;Lo;0;AL;<final> 0636 064A;;;;N;;;;;
+FD25;ARABIC LIGATURE SHEEN WITH JEEM FINAL FORM;Lo;0;AL;<final> 0634 062C;;;;N;;;;;
+FD26;ARABIC LIGATURE SHEEN WITH HAH FINAL FORM;Lo;0;AL;<final> 0634 062D;;;;N;;;;;
+FD27;ARABIC LIGATURE SHEEN WITH KHAH FINAL FORM;Lo;0;AL;<final> 0634 062E;;;;N;;;;;
+FD28;ARABIC LIGATURE SHEEN WITH MEEM FINAL FORM;Lo;0;AL;<final> 0634 0645;;;;N;;;;;
+FD29;ARABIC LIGATURE SHEEN WITH REH FINAL FORM;Lo;0;AL;<final> 0634 0631;;;;N;;;;;
+FD2A;ARABIC LIGATURE SEEN WITH REH FINAL FORM;Lo;0;AL;<final> 0633 0631;;;;N;;;;;
+FD2B;ARABIC LIGATURE SAD WITH REH FINAL FORM;Lo;0;AL;<final> 0635 0631;;;;N;;;;;
+FD2C;ARABIC LIGATURE DAD WITH REH FINAL FORM;Lo;0;AL;<final> 0636 0631;;;;N;;;;;
+FD2D;ARABIC LIGATURE SHEEN WITH JEEM INITIAL FORM;Lo;0;AL;<initial> 0634 062C;;;;N;;;;;
+FD2E;ARABIC LIGATURE SHEEN WITH HAH INITIAL FORM;Lo;0;AL;<initial> 0634 062D;;;;N;;;;;
+FD2F;ARABIC LIGATURE SHEEN WITH KHAH INITIAL FORM;Lo;0;AL;<initial> 0634 062E;;;;N;;;;;
+FD30;ARABIC LIGATURE SHEEN WITH MEEM INITIAL FORM;Lo;0;AL;<initial> 0634 0645;;;;N;;;;;
+FD31;ARABIC LIGATURE SEEN WITH HEH INITIAL FORM;Lo;0;AL;<initial> 0633 0647;;;;N;;;;;
+FD32;ARABIC LIGATURE SHEEN WITH HEH INITIAL FORM;Lo;0;AL;<initial> 0634 0647;;;;N;;;;;
+FD33;ARABIC LIGATURE TAH WITH MEEM INITIAL FORM;Lo;0;AL;<initial> 0637 0645;;;;N;;;;;
+FD34;ARABIC LIGATURE SEEN WITH JEEM MEDIAL FORM;Lo;0;AL;<medial> 0633 062C;;;;N;;;;;
+FD35;ARABIC LIGATURE SEEN WITH HAH MEDIAL FORM;Lo;0;AL;<medial> 0633 062D;;;;N;;;;;
+FD36;ARABIC LIGATURE SEEN WITH KHAH MEDIAL FORM;Lo;0;AL;<medial> 0633 062E;;;;N;;;;;
+FD37;ARABIC LIGATURE SHEEN WITH JEEM MEDIAL FORM;Lo;0;AL;<medial> 0634 062C;;;;N;;;;;
+FD38;ARABIC LIGATURE SHEEN WITH HAH MEDIAL FORM;Lo;0;AL;<medial> 0634 062D;;;;N;;;;;
+FD39;ARABIC LIGATURE SHEEN WITH KHAH MEDIAL FORM;Lo;0;AL;<medial> 0634 062E;;;;N;;;;;
+FD3A;ARABIC LIGATURE TAH WITH MEEM MEDIAL FORM;Lo;0;AL;<medial> 0637 0645;;;;N;;;;;
+FD3B;ARABIC LIGATURE ZAH WITH MEEM MEDIAL FORM;Lo;0;AL;<medial> 0638 0645;;;;N;;;;;
+FD3C;ARABIC LIGATURE ALEF WITH FATHATAN FINAL FORM;Lo;0;AL;<final> 0627 064B;;;;N;;;;;
+FD3D;ARABIC LIGATURE ALEF WITH FATHATAN ISOLATED FORM;Lo;0;AL;<isolated> 0627 064B;;;;N;;;;;
+FD3E;ORNATE LEFT PARENTHESIS;Ps;0;ON;;;;;N;;;;;
+FD3F;ORNATE RIGHT PARENTHESIS;Pe;0;ON;;;;;N;;;;;
+FD50;ARABIC LIGATURE TEH WITH JEEM WITH MEEM INITIAL FORM;Lo;0;AL;<initial> 062A 062C 0645;;;;N;;;;;
+FD51;ARABIC LIGATURE TEH WITH HAH WITH JEEM FINAL FORM;Lo;0;AL;<final> 062A 062D 062C;;;;N;;;;;
+FD52;ARABIC LIGATURE TEH WITH HAH WITH JEEM INITIAL FORM;Lo;0;AL;<initial> 062A 062D 062C;;;;N;;;;;
+FD53;ARABIC LIGATURE TEH WITH HAH WITH MEEM INITIAL FORM;Lo;0;AL;<initial> 062A 062D 0645;;;;N;;;;;
+FD54;ARABIC LIGATURE TEH WITH KHAH WITH MEEM INITIAL FORM;Lo;0;AL;<initial> 062A 062E 0645;;;;N;;;;;
+FD55;ARABIC LIGATURE TEH WITH MEEM WITH JEEM INITIAL FORM;Lo;0;AL;<initial> 062A 0645 062C;;;;N;;;;;
+FD56;ARABIC LIGATURE TEH WITH MEEM WITH HAH INITIAL FORM;Lo;0;AL;<initial> 062A 0645 062D;;;;N;;;;;
+FD57;ARABIC LIGATURE TEH WITH MEEM WITH KHAH INITIAL FORM;Lo;0;AL;<initial> 062A 0645 062E;;;;N;;;;;
+FD58;ARABIC LIGATURE JEEM WITH MEEM WITH HAH FINAL FORM;Lo;0;AL;<final> 062C 0645 062D;;;;N;;;;;
+FD59;ARABIC LIGATURE JEEM WITH MEEM WITH HAH INITIAL FORM;Lo;0;AL;<initial> 062C 0645 062D;;;;N;;;;;
+FD5A;ARABIC LIGATURE HAH WITH MEEM WITH YEH FINAL FORM;Lo;0;AL;<final> 062D 0645 064A;;;;N;;;;;
+FD5B;ARABIC LIGATURE HAH WITH MEEM WITH ALEF MAKSURA FINAL FORM;Lo;0;AL;<final> 062D 0645 0649;;;;N;;;;;
+FD5C;ARABIC LIGATURE SEEN WITH HAH WITH JEEM INITIAL FORM;Lo;0;AL;<initial> 0633 062D 062C;;;;N;;;;;
+FD5D;ARABIC LIGATURE SEEN WITH JEEM WITH HAH INITIAL FORM;Lo;0;AL;<initial> 0633 062C 062D;;;;N;;;;;
+FD5E;ARABIC LIGATURE SEEN WITH JEEM WITH ALEF MAKSURA FINAL FORM;Lo;0;AL;<final> 0633 062C 0649;;;;N;;;;;
+FD5F;ARABIC LIGATURE SEEN WITH MEEM WITH HAH FINAL FORM;Lo;0;AL;<final> 0633 0645 062D;;;;N;;;;;
+FD60;ARABIC LIGATURE SEEN WITH MEEM WITH HAH INITIAL FORM;Lo;0;AL;<initial> 0633 0645 062D;;;;N;;;;;
+FD61;ARABIC LIGATURE SEEN WITH MEEM WITH JEEM INITIAL FORM;Lo;0;AL;<initial> 0633 0645 062C;;;;N;;;;;
+FD62;ARABIC LIGATURE SEEN WITH MEEM WITH MEEM FINAL FORM;Lo;0;AL;<final> 0633 0645 0645;;;;N;;;;;
+FD63;ARABIC LIGATURE SEEN WITH MEEM WITH MEEM INITIAL FORM;Lo;0;AL;<initial> 0633 0645 0645;;;;N;;;;;
+FD64;ARABIC LIGATURE SAD WITH HAH WITH HAH FINAL FORM;Lo;0;AL;<final> 0635 062D 062D;;;;N;;;;;
+FD65;ARABIC LIGATURE SAD WITH HAH WITH HAH INITIAL FORM;Lo;0;AL;<initial> 0635 062D 062D;;;;N;;;;;
+FD66;ARABIC LIGATURE SAD WITH MEEM WITH MEEM FINAL FORM;Lo;0;AL;<final> 0635 0645 0645;;;;N;;;;;
+FD67;ARABIC LIGATURE SHEEN WITH HAH WITH MEEM FINAL FORM;Lo;0;AL;<final> 0634 062D 0645;;;;N;;;;;
+FD68;ARABIC LIGATURE SHEEN WITH HAH WITH MEEM INITIAL FORM;Lo;0;AL;<initial> 0634 062D 0645;;;;N;;;;;
+FD69;ARABIC LIGATURE SHEEN WITH JEEM WITH YEH FINAL FORM;Lo;0;AL;<final> 0634 062C 064A;;;;N;;;;;
+FD6A;ARABIC LIGATURE SHEEN WITH MEEM WITH KHAH FINAL FORM;Lo;0;AL;<final> 0634 0645 062E;;;;N;;;;;
+FD6B;ARABIC LIGATURE SHEEN WITH MEEM WITH KHAH INITIAL FORM;Lo;0;AL;<initial> 0634 0645 062E;;;;N;;;;;
+FD6C;ARABIC LIGATURE SHEEN WITH MEEM WITH MEEM FINAL FORM;Lo;0;AL;<final> 0634 0645 0645;;;;N;;;;;
+FD6D;ARABIC LIGATURE SHEEN WITH MEEM WITH MEEM INITIAL FORM;Lo;0;AL;<initial> 0634 0645 0645;;;;N;;;;;
+FD6E;ARABIC LIGATURE DAD WITH HAH WITH ALEF MAKSURA FINAL FORM;Lo;0;AL;<final> 0636 062D 0649;;;;N;;;;;
+FD6F;ARABIC LIGATURE DAD WITH KHAH WITH MEEM FINAL FORM;Lo;0;AL;<final> 0636 062E 0645;;;;N;;;;;
+FD70;ARABIC LIGATURE DAD WITH KHAH WITH MEEM INITIAL FORM;Lo;0;AL;<initial> 0636 062E 0645;;;;N;;;;;
+FD71;ARABIC LIGATURE TAH WITH MEEM WITH HAH FINAL FORM;Lo;0;AL;<final> 0637 0645 062D;;;;N;;;;;
+FD72;ARABIC LIGATURE TAH WITH MEEM WITH HAH INITIAL FORM;Lo;0;AL;<initial> 0637 0645 062D;;;;N;;;;;
+FD73;ARABIC LIGATURE TAH WITH MEEM WITH MEEM INITIAL FORM;Lo;0;AL;<initial> 0637 0645 0645;;;;N;;;;;
+FD74;ARABIC LIGATURE TAH WITH MEEM WITH YEH FINAL FORM;Lo;0;AL;<final> 0637 0645 064A;;;;N;;;;;
+FD75;ARABIC LIGATURE AIN WITH JEEM WITH MEEM FINAL FORM;Lo;0;AL;<final> 0639 062C 0645;;;;N;;;;;
+FD76;ARABIC LIGATURE AIN WITH MEEM WITH MEEM FINAL FORM;Lo;0;AL;<final> 0639 0645 0645;;;;N;;;;;
+FD77;ARABIC LIGATURE AIN WITH MEEM WITH MEEM INITIAL FORM;Lo;0;AL;<initial> 0639 0645 0645;;;;N;;;;;
+FD78;ARABIC LIGATURE AIN WITH MEEM WITH ALEF MAKSURA FINAL FORM;Lo;0;AL;<final> 0639 0645 0649;;;;N;;;;;
+FD79;ARABIC LIGATURE GHAIN WITH MEEM WITH MEEM FINAL FORM;Lo;0;AL;<final> 063A 0645 0645;;;;N;;;;;
+FD7A;ARABIC LIGATURE GHAIN WITH MEEM WITH YEH FINAL FORM;Lo;0;AL;<final> 063A 0645 064A;;;;N;;;;;
+FD7B;ARABIC LIGATURE GHAIN WITH MEEM WITH ALEF MAKSURA FINAL FORM;Lo;0;AL;<final> 063A 0645 0649;;;;N;;;;;
+FD7C;ARABIC LIGATURE FEH WITH KHAH WITH MEEM FINAL FORM;Lo;0;AL;<final> 0641 062E 0645;;;;N;;;;;
+FD7D;ARABIC LIGATURE FEH WITH KHAH WITH MEEM INITIAL FORM;Lo;0;AL;<initial> 0641 062E 0645;;;;N;;;;;
+FD7E;ARABIC LIGATURE QAF WITH MEEM WITH HAH FINAL FORM;Lo;0;AL;<final> 0642 0645 062D;;;;N;;;;;
+FD7F;ARABIC LIGATURE QAF WITH MEEM WITH MEEM FINAL FORM;Lo;0;AL;<final> 0642 0645 0645;;;;N;;;;;
+FD80;ARABIC LIGATURE LAM WITH HAH WITH MEEM FINAL FORM;Lo;0;AL;<final> 0644 062D 0645;;;;N;;;;;
+FD81;ARABIC LIGATURE LAM WITH HAH WITH YEH FINAL FORM;Lo;0;AL;<final> 0644 062D 064A;;;;N;;;;;
+FD82;ARABIC LIGATURE LAM WITH HAH WITH ALEF MAKSURA FINAL FORM;Lo;0;AL;<final> 0644 062D 0649;;;;N;;;;;
+FD83;ARABIC LIGATURE LAM WITH JEEM WITH JEEM INITIAL FORM;Lo;0;AL;<initial> 0644 062C 062C;;;;N;;;;;
+FD84;ARABIC LIGATURE LAM WITH JEEM WITH JEEM FINAL FORM;Lo;0;AL;<final> 0644 062C 062C;;;;N;;;;;
+FD85;ARABIC LIGATURE LAM WITH KHAH WITH MEEM FINAL FORM;Lo;0;AL;<final> 0644 062E 0645;;;;N;;;;;
+FD86;ARABIC LIGATURE LAM WITH KHAH WITH MEEM INITIAL FORM;Lo;0;AL;<initial> 0644 062E 0645;;;;N;;;;;
+FD87;ARABIC LIGATURE LAM WITH MEEM WITH HAH FINAL FORM;Lo;0;AL;<final> 0644 0645 062D;;;;N;;;;;
+FD88;ARABIC LIGATURE LAM WITH MEEM WITH HAH INITIAL FORM;Lo;0;AL;<initial> 0644 0645 062D;;;;N;;;;;
+FD89;ARABIC LIGATURE MEEM WITH HAH WITH JEEM INITIAL FORM;Lo;0;AL;<initial> 0645 062D 062C;;;;N;;;;;
+FD8A;ARABIC LIGATURE MEEM WITH HAH WITH MEEM INITIAL FORM;Lo;0;AL;<initial> 0645 062D 0645;;;;N;;;;;
+FD8B;ARABIC LIGATURE MEEM WITH HAH WITH YEH FINAL FORM;Lo;0;AL;<final> 0645 062D 064A;;;;N;;;;;
+FD8C;ARABIC LIGATURE MEEM WITH JEEM WITH HAH INITIAL FORM;Lo;0;AL;<initial> 0645 062C 062D;;;;N;;;;;
+FD8D;ARABIC LIGATURE MEEM WITH JEEM WITH MEEM INITIAL FORM;Lo;0;AL;<initial> 0645 062C 0645;;;;N;;;;;
+FD8E;ARABIC LIGATURE MEEM WITH KHAH WITH JEEM INITIAL FORM;Lo;0;AL;<initial> 0645 062E 062C;;;;N;;;;;
+FD8F;ARABIC LIGATURE MEEM WITH KHAH WITH MEEM INITIAL FORM;Lo;0;AL;<initial> 0645 062E 0645;;;;N;;;;;
+FD92;ARABIC LIGATURE MEEM WITH JEEM WITH KHAH INITIAL FORM;Lo;0;AL;<initial> 0645 062C 062E;;;;N;;;;;
+FD93;ARABIC LIGATURE HEH WITH MEEM WITH JEEM INITIAL FORM;Lo;0;AL;<initial> 0647 0645 062C;;;;N;;;;;
+FD94;ARABIC LIGATURE HEH WITH MEEM WITH MEEM INITIAL FORM;Lo;0;AL;<initial> 0647 0645 0645;;;;N;;;;;
+FD95;ARABIC LIGATURE NOON WITH HAH WITH MEEM INITIAL FORM;Lo;0;AL;<initial> 0646 062D 0645;;;;N;;;;;
+FD96;ARABIC LIGATURE NOON WITH HAH WITH ALEF MAKSURA FINAL FORM;Lo;0;AL;<final> 0646 062D 0649;;;;N;;;;;
+FD97;ARABIC LIGATURE NOON WITH JEEM WITH MEEM FINAL FORM;Lo;0;AL;<final> 0646 062C 0645;;;;N;;;;;
+FD98;ARABIC LIGATURE NOON WITH JEEM WITH MEEM INITIAL FORM;Lo;0;AL;<initial> 0646 062C 0645;;;;N;;;;;
+FD99;ARABIC LIGATURE NOON WITH JEEM WITH ALEF MAKSURA FINAL FORM;Lo;0;AL;<final> 0646 062C 0649;;;;N;;;;;
+FD9A;ARABIC LIGATURE NOON WITH MEEM WITH YEH FINAL FORM;Lo;0;AL;<final> 0646 0645 064A;;;;N;;;;;
+FD9B;ARABIC LIGATURE NOON WITH MEEM WITH ALEF MAKSURA FINAL FORM;Lo;0;AL;<final> 0646 0645 0649;;;;N;;;;;
+FD9C;ARABIC LIGATURE YEH WITH MEEM WITH MEEM FINAL FORM;Lo;0;AL;<final> 064A 0645 0645;;;;N;;;;;
+FD9D;ARABIC LIGATURE YEH WITH MEEM WITH MEEM INITIAL FORM;Lo;0;AL;<initial> 064A 0645 0645;;;;N;;;;;
+FD9E;ARABIC LIGATURE BEH WITH KHAH WITH YEH FINAL FORM;Lo;0;AL;<final> 0628 062E 064A;;;;N;;;;;
+FD9F;ARABIC LIGATURE TEH WITH JEEM WITH YEH FINAL FORM;Lo;0;AL;<final> 062A 062C 064A;;;;N;;;;;
+FDA0;ARABIC LIGATURE TEH WITH JEEM WITH ALEF MAKSURA FINAL FORM;Lo;0;AL;<final> 062A 062C 0649;;;;N;;;;;
+FDA1;ARABIC LIGATURE TEH WITH KHAH WITH YEH FINAL FORM;Lo;0;AL;<final> 062A 062E 064A;;;;N;;;;;
+FDA2;ARABIC LIGATURE TEH WITH KHAH WITH ALEF MAKSURA FINAL FORM;Lo;0;AL;<final> 062A 062E 0649;;;;N;;;;;
+FDA3;ARABIC LIGATURE TEH WITH MEEM WITH YEH FINAL FORM;Lo;0;AL;<final> 062A 0645 064A;;;;N;;;;;
+FDA4;ARABIC LIGATURE TEH WITH MEEM WITH ALEF MAKSURA FINAL FORM;Lo;0;AL;<final> 062A 0645 0649;;;;N;;;;;
+FDA5;ARABIC LIGATURE JEEM WITH MEEM WITH YEH FINAL FORM;Lo;0;AL;<final> 062C 0645 064A;;;;N;;;;;
+FDA6;ARABIC LIGATURE JEEM WITH HAH WITH ALEF MAKSURA FINAL FORM;Lo;0;AL;<final> 062C 062D 0649;;;;N;;;;;
+FDA7;ARABIC LIGATURE JEEM WITH MEEM WITH ALEF MAKSURA FINAL FORM;Lo;0;AL;<final> 062C 0645 0649;;;;N;;;;;
+FDA8;ARABIC LIGATURE SEEN WITH KHAH WITH ALEF MAKSURA FINAL FORM;Lo;0;AL;<final> 0633 062E 0649;;;;N;;;;;
+FDA9;ARABIC LIGATURE SAD WITH HAH WITH YEH FINAL FORM;Lo;0;AL;<final> 0635 062D 064A;;;;N;;;;;
+FDAA;ARABIC LIGATURE SHEEN WITH HAH WITH YEH FINAL FORM;Lo;0;AL;<final> 0634 062D 064A;;;;N;;;;;
+FDAB;ARABIC LIGATURE DAD WITH HAH WITH YEH FINAL FORM;Lo;0;AL;<final> 0636 062D 064A;;;;N;;;;;
+FDAC;ARABIC LIGATURE LAM WITH JEEM WITH YEH FINAL FORM;Lo;0;AL;<final> 0644 062C 064A;;;;N;;;;;
+FDAD;ARABIC LIGATURE LAM WITH MEEM WITH YEH FINAL FORM;Lo;0;AL;<final> 0644 0645 064A;;;;N;;;;;
+FDAE;ARABIC LIGATURE YEH WITH HAH WITH YEH FINAL FORM;Lo;0;AL;<final> 064A 062D 064A;;;;N;;;;;
+FDAF;ARABIC LIGATURE YEH WITH JEEM WITH YEH FINAL FORM;Lo;0;AL;<final> 064A 062C 064A;;;;N;;;;;
+FDB0;ARABIC LIGATURE YEH WITH MEEM WITH YEH FINAL FORM;Lo;0;AL;<final> 064A 0645 064A;;;;N;;;;;
+FDB1;ARABIC LIGATURE MEEM WITH MEEM WITH YEH FINAL FORM;Lo;0;AL;<final> 0645 0645 064A;;;;N;;;;;
+FDB2;ARABIC LIGATURE QAF WITH MEEM WITH YEH FINAL FORM;Lo;0;AL;<final> 0642 0645 064A;;;;N;;;;;
+FDB3;ARABIC LIGATURE NOON WITH HAH WITH YEH FINAL FORM;Lo;0;AL;<final> 0646 062D 064A;;;;N;;;;;
+FDB4;ARABIC LIGATURE QAF WITH MEEM WITH HAH INITIAL FORM;Lo;0;AL;<initial> 0642 0645 062D;;;;N;;;;;
+FDB5;ARABIC LIGATURE LAM WITH HAH WITH MEEM INITIAL FORM;Lo;0;AL;<initial> 0644 062D 0645;;;;N;;;;;
+FDB6;ARABIC LIGATURE AIN WITH MEEM WITH YEH FINAL FORM;Lo;0;AL;<final> 0639 0645 064A;;;;N;;;;;
+FDB7;ARABIC LIGATURE KAF WITH MEEM WITH YEH FINAL FORM;Lo;0;AL;<final> 0643 0645 064A;;;;N;;;;;
+FDB8;ARABIC LIGATURE NOON WITH JEEM WITH HAH INITIAL FORM;Lo;0;AL;<initial> 0646 062C 062D;;;;N;;;;;
+FDB9;ARABIC LIGATURE MEEM WITH KHAH WITH YEH FINAL FORM;Lo;0;AL;<final> 0645 062E 064A;;;;N;;;;;
+FDBA;ARABIC LIGATURE LAM WITH JEEM WITH MEEM INITIAL FORM;Lo;0;AL;<initial> 0644 062C 0645;;;;N;;;;;
+FDBB;ARABIC LIGATURE KAF WITH MEEM WITH MEEM FINAL FORM;Lo;0;AL;<final> 0643 0645 0645;;;;N;;;;;
+FDBC;ARABIC LIGATURE LAM WITH JEEM WITH MEEM FINAL FORM;Lo;0;AL;<final> 0644 062C 0645;;;;N;;;;;
+FDBD;ARABIC LIGATURE NOON WITH JEEM WITH HAH FINAL FORM;Lo;0;AL;<final> 0646 062C 062D;;;;N;;;;;
+FDBE;ARABIC LIGATURE JEEM WITH HAH WITH YEH FINAL FORM;Lo;0;AL;<final> 062C 062D 064A;;;;N;;;;;
+FDBF;ARABIC LIGATURE HAH WITH JEEM WITH YEH FINAL FORM;Lo;0;AL;<final> 062D 062C 064A;;;;N;;;;;
+FDC0;ARABIC LIGATURE MEEM WITH JEEM WITH YEH FINAL FORM;Lo;0;AL;<final> 0645 062C 064A;;;;N;;;;;
+FDC1;ARABIC LIGATURE FEH WITH MEEM WITH YEH FINAL FORM;Lo;0;AL;<final> 0641 0645 064A;;;;N;;;;;
+FDC2;ARABIC LIGATURE BEH WITH HAH WITH YEH FINAL FORM;Lo;0;AL;<final> 0628 062D 064A;;;;N;;;;;
+FDC3;ARABIC LIGATURE KAF WITH MEEM WITH MEEM INITIAL FORM;Lo;0;AL;<initial> 0643 0645 0645;;;;N;;;;;
+FDC4;ARABIC LIGATURE AIN WITH JEEM WITH MEEM INITIAL FORM;Lo;0;AL;<initial> 0639 062C 0645;;;;N;;;;;
+FDC5;ARABIC LIGATURE SAD WITH MEEM WITH MEEM INITIAL FORM;Lo;0;AL;<initial> 0635 0645 0645;;;;N;;;;;
+FDC6;ARABIC LIGATURE SEEN WITH KHAH WITH YEH FINAL FORM;Lo;0;AL;<final> 0633 062E 064A;;;;N;;;;;
+FDC7;ARABIC LIGATURE NOON WITH JEEM WITH YEH FINAL FORM;Lo;0;AL;<final> 0646 062C 064A;;;;N;;;;;
+FDF0;ARABIC LIGATURE SALLA USED AS KORANIC STOP SIGN ISOLATED FORM;Lo;0;AL;<isolated> 0635 0644 06D2;;;;N;;;;;
+FDF1;ARABIC LIGATURE QALA USED AS KORANIC STOP SIGN ISOLATED FORM;Lo;0;AL;<isolated> 0642 0644 06D2;;;;N;;;;;
+FDF2;ARABIC LIGATURE ALLAH ISOLATED FORM;Lo;0;AL;<isolated> 0627 0644 0644 0647;;;;N;;;;;
+FDF3;ARABIC LIGATURE AKBAR ISOLATED FORM;Lo;0;AL;<isolated> 0627 0643 0628 0631;;;;N;;;;;
+FDF4;ARABIC LIGATURE MOHAMMAD ISOLATED FORM;Lo;0;AL;<isolated> 0645 062D 0645 062F;;;;N;;;;;
+FDF5;ARABIC LIGATURE SALAM ISOLATED FORM;Lo;0;AL;<isolated> 0635 0644 0639 0645;;;;N;;;;;
+FDF6;ARABIC LIGATURE RASOUL ISOLATED FORM;Lo;0;AL;<isolated> 0631 0633 0648 0644;;;;N;;;;;
+FDF7;ARABIC LIGATURE ALAYHE ISOLATED FORM;Lo;0;AL;<isolated> 0639 0644 064A 0647;;;;N;;;;;
+FDF8;ARABIC LIGATURE WASALLAM ISOLATED FORM;Lo;0;AL;<isolated> 0648 0633 0644 0645;;;;N;;;;;
+FDF9;ARABIC LIGATURE SALLA ISOLATED FORM;Lo;0;AL;<isolated> 0635 0644 0649;;;;N;;;;;
+FDFA;ARABIC LIGATURE SALLALLAHOU ALAYHE WASALLAM;Lo;0;AL;<isolated> 0635 0644 0649 0020 0627 0644 0644 0647 0020 0639 0644 064A 0647 0020 0648 0633 0644 0645;;;;N;ARABIC LETTER SALLALLAHOU ALAYHE WASALLAM;;;;
+FDFB;ARABIC LIGATURE JALLAJALALOUHOU;Lo;0;AL;<isolated> 062C 0644 0020 062C 0644 0627 0644 0647;;;;N;ARABIC LETTER JALLAJALALOUHOU;;;;
+FDFC;RIAL SIGN;Sc;0;AL;<isolated> 0631 06CC 0627 0644;;;;N;;;;;
+FDFD;ARABIC LIGATURE BISMILLAH AR-RAHMAN AR-RAHEEM;So;0;ON;;;;;N;;;;;
+FE00;VARIATION SELECTOR-1;Mn;0;NSM;;;;;N;;;;;
+FE01;VARIATION SELECTOR-2;Mn;0;NSM;;;;;N;;;;;
+FE02;VARIATION SELECTOR-3;Mn;0;NSM;;;;;N;;;;;
+FE03;VARIATION SELECTOR-4;Mn;0;NSM;;;;;N;;;;;
+FE04;VARIATION SELECTOR-5;Mn;0;NSM;;;;;N;;;;;
+FE05;VARIATION SELECTOR-6;Mn;0;NSM;;;;;N;;;;;
+FE06;VARIATION SELECTOR-7;Mn;0;NSM;;;;;N;;;;;
+FE07;VARIATION SELECTOR-8;Mn;0;NSM;;;;;N;;;;;
+FE08;VARIATION SELECTOR-9;Mn;0;NSM;;;;;N;;;;;
+FE09;VARIATION SELECTOR-10;Mn;0;NSM;;;;;N;;;;;
+FE0A;VARIATION SELECTOR-11;Mn;0;NSM;;;;;N;;;;;
+FE0B;VARIATION SELECTOR-12;Mn;0;NSM;;;;;N;;;;;
+FE0C;VARIATION SELECTOR-13;Mn;0;NSM;;;;;N;;;;;
+FE0D;VARIATION SELECTOR-14;Mn;0;NSM;;;;;N;;;;;
+FE0E;VARIATION SELECTOR-15;Mn;0;NSM;;;;;N;;;;;
+FE0F;VARIATION SELECTOR-16;Mn;0;NSM;;;;;N;;;;;
+FE10;PRESENTATION FORM FOR VERTICAL COMMA;Po;0;ON;<vertical> 002C;;;;N;;;;;
+FE11;PRESENTATION FORM FOR VERTICAL IDEOGRAPHIC COMMA;Po;0;ON;<vertical> 3001;;;;N;;;;;
+FE12;PRESENTATION FORM FOR VERTICAL IDEOGRAPHIC FULL STOP;Po;0;ON;<vertical> 3002;;;;N;;;;;
+FE13;PRESENTATION FORM FOR VERTICAL COLON;Po;0;ON;<vertical> 003A;;;;N;;;;;
+FE14;PRESENTATION FORM FOR VERTICAL SEMICOLON;Po;0;ON;<vertical> 003B;;;;N;;;;;
+FE15;PRESENTATION FORM FOR VERTICAL EXCLAMATION MARK;Po;0;ON;<vertical> 0021;;;;N;;;;;
+FE16;PRESENTATION FORM FOR VERTICAL QUESTION MARK;Po;0;ON;<vertical> 003F;;;;N;;;;;
+FE17;PRESENTATION FORM FOR VERTICAL LEFT WHITE LENTICULAR BRACKET;Ps;0;ON;<vertical> 3016;;;;N;;;;;
+FE18;PRESENTATION FORM FOR VERTICAL RIGHT WHITE LENTICULAR BRAKCET;Pe;0;ON;<vertical> 3017;;;;N;;;;;
+FE19;PRESENTATION FORM FOR VERTICAL HORIZONTAL ELLIPSIS;Po;0;ON;<vertical> 2026;;;;N;;;;;
+FE20;COMBINING LIGATURE LEFT HALF;Mn;230;NSM;;;;;N;;;;;
+FE21;COMBINING LIGATURE RIGHT HALF;Mn;230;NSM;;;;;N;;;;;
+FE22;COMBINING DOUBLE TILDE LEFT HALF;Mn;230;NSM;;;;;N;;;;;
+FE23;COMBINING DOUBLE TILDE RIGHT HALF;Mn;230;NSM;;;;;N;;;;;
+FE30;PRESENTATION FORM FOR VERTICAL TWO DOT LEADER;Po;0;ON;<vertical> 2025;;;;N;GLYPH FOR VERTICAL TWO DOT LEADER;;;;
+FE31;PRESENTATION FORM FOR VERTICAL EM DASH;Pd;0;ON;<vertical> 2014;;;;N;GLYPH FOR VERTICAL EM DASH;;;;
+FE32;PRESENTATION FORM FOR VERTICAL EN DASH;Pd;0;ON;<vertical> 2013;;;;N;GLYPH FOR VERTICAL EN DASH;;;;
+FE33;PRESENTATION FORM FOR VERTICAL LOW LINE;Pc;0;ON;<vertical> 005F;;;;N;GLYPH FOR VERTICAL SPACING UNDERSCORE;;;;
+FE34;PRESENTATION FORM FOR VERTICAL WAVY LOW LINE;Pc;0;ON;<vertical> 005F;;;;N;GLYPH FOR VERTICAL SPACING WAVY UNDERSCORE;;;;
+FE35;PRESENTATION FORM FOR VERTICAL LEFT PARENTHESIS;Ps;0;ON;<vertical> 0028;;;;N;GLYPH FOR VERTICAL OPENING PARENTHESIS;;;;
+FE36;PRESENTATION FORM FOR VERTICAL RIGHT PARENTHESIS;Pe;0;ON;<vertical> 0029;;;;N;GLYPH FOR VERTICAL CLOSING PARENTHESIS;;;;
+FE37;PRESENTATION FORM FOR VERTICAL LEFT CURLY BRACKET;Ps;0;ON;<vertical> 007B;;;;N;GLYPH FOR VERTICAL OPENING CURLY BRACKET;;;;
+FE38;PRESENTATION FORM FOR VERTICAL RIGHT CURLY BRACKET;Pe;0;ON;<vertical> 007D;;;;N;GLYPH FOR VERTICAL CLOSING CURLY BRACKET;;;;
+FE39;PRESENTATION FORM FOR VERTICAL LEFT TORTOISE SHELL BRACKET;Ps;0;ON;<vertical> 3014;;;;N;GLYPH FOR VERTICAL OPENING TORTOISE SHELL BRACKET;;;;
+FE3A;PRESENTATION FORM FOR VERTICAL RIGHT TORTOISE SHELL BRACKET;Pe;0;ON;<vertical> 3015;;;;N;GLYPH FOR VERTICAL CLOSING TORTOISE SHELL BRACKET;;;;
+FE3B;PRESENTATION FORM FOR VERTICAL LEFT BLACK LENTICULAR BRACKET;Ps;0;ON;<vertical> 3010;;;;N;GLYPH FOR VERTICAL OPENING BLACK LENTICULAR BRACKET;;;;
+FE3C;PRESENTATION FORM FOR VERTICAL RIGHT BLACK LENTICULAR BRACKET;Pe;0;ON;<vertical> 3011;;;;N;GLYPH FOR VERTICAL CLOSING BLACK LENTICULAR BRACKET;;;;
+FE3D;PRESENTATION FORM FOR VERTICAL LEFT DOUBLE ANGLE BRACKET;Ps;0;ON;<vertical> 300A;;;;N;GLYPH FOR VERTICAL OPENING DOUBLE ANGLE BRACKET;;;;
+FE3E;PRESENTATION FORM FOR VERTICAL RIGHT DOUBLE ANGLE BRACKET;Pe;0;ON;<vertical> 300B;;;;N;GLYPH FOR VERTICAL CLOSING DOUBLE ANGLE BRACKET;;;;
+FE3F;PRESENTATION FORM FOR VERTICAL LEFT ANGLE BRACKET;Ps;0;ON;<vertical> 3008;;;;N;GLYPH FOR VERTICAL OPENING ANGLE BRACKET;;;;
+FE40;PRESENTATION FORM FOR VERTICAL RIGHT ANGLE BRACKET;Pe;0;ON;<vertical> 3009;;;;N;GLYPH FOR VERTICAL CLOSING ANGLE BRACKET;;;;
+FE41;PRESENTATION FORM FOR VERTICAL LEFT CORNER BRACKET;Ps;0;ON;<vertical> 300C;;;;N;GLYPH FOR VERTICAL OPENING CORNER BRACKET;;;;
+FE42;PRESENTATION FORM FOR VERTICAL RIGHT CORNER BRACKET;Pe;0;ON;<vertical> 300D;;;;N;GLYPH FOR VERTICAL CLOSING CORNER BRACKET;;;;
+FE43;PRESENTATION FORM FOR VERTICAL LEFT WHITE CORNER BRACKET;Ps;0;ON;<vertical> 300E;;;;N;GLYPH FOR VERTICAL OPENING WHITE CORNER BRACKET;;;;
+FE44;PRESENTATION FORM FOR VERTICAL RIGHT WHITE CORNER BRACKET;Pe;0;ON;<vertical> 300F;;;;N;GLYPH FOR VERTICAL CLOSING WHITE CORNER BRACKET;;;;
+FE45;SESAME DOT;Po;0;ON;;;;;N;;;;;
+FE46;WHITE SESAME DOT;Po;0;ON;;;;;N;;;;;
+FE47;PRESENTATION FORM FOR VERTICAL LEFT SQUARE BRACKET;Ps;0;ON;<vertical> 005B;;;;N;;;;;
+FE48;PRESENTATION FORM FOR VERTICAL RIGHT SQUARE BRACKET;Pe;0;ON;<vertical> 005D;;;;N;;;;;
+FE49;DASHED OVERLINE;Po;0;ON;<compat> 203E;;;;N;SPACING DASHED OVERSCORE;;;;
+FE4A;CENTRELINE OVERLINE;Po;0;ON;<compat> 203E;;;;N;SPACING CENTERLINE OVERSCORE;;;;
+FE4B;WAVY OVERLINE;Po;0;ON;<compat> 203E;;;;N;SPACING WAVY OVERSCORE;;;;
+FE4C;DOUBLE WAVY OVERLINE;Po;0;ON;<compat> 203E;;;;N;SPACING DOUBLE WAVY OVERSCORE;;;;
+FE4D;DASHED LOW LINE;Pc;0;ON;<compat> 005F;;;;N;SPACING DASHED UNDERSCORE;;;;
+FE4E;CENTRELINE LOW LINE;Pc;0;ON;<compat> 005F;;;;N;SPACING CENTERLINE UNDERSCORE;;;;
+FE4F;WAVY LOW LINE;Pc;0;ON;<compat> 005F;;;;N;SPACING WAVY UNDERSCORE;;;;
+FE50;SMALL COMMA;Po;0;CS;<small> 002C;;;;N;;;;;
+FE51;SMALL IDEOGRAPHIC COMMA;Po;0;ON;<small> 3001;;;;N;;;;;
+FE52;SMALL FULL STOP;Po;0;CS;<small> 002E;;;;N;SMALL PERIOD;;;;
+FE54;SMALL SEMICOLON;Po;0;ON;<small> 003B;;;;N;;;;;
+FE55;SMALL COLON;Po;0;CS;<small> 003A;;;;N;;;;;
+FE56;SMALL QUESTION MARK;Po;0;ON;<small> 003F;;;;N;;;;;
+FE57;SMALL EXCLAMATION MARK;Po;0;ON;<small> 0021;;;;N;;;;;
+FE58;SMALL EM DASH;Pd;0;ON;<small> 2014;;;;N;;;;;
+FE59;SMALL LEFT PARENTHESIS;Ps;0;ON;<small> 0028;;;;N;SMALL OPENING PARENTHESIS;;;;
+FE5A;SMALL RIGHT PARENTHESIS;Pe;0;ON;<small> 0029;;;;N;SMALL CLOSING PARENTHESIS;;;;
+FE5B;SMALL LEFT CURLY BRACKET;Ps;0;ON;<small> 007B;;;;N;SMALL OPENING CURLY BRACKET;;;;
+FE5C;SMALL RIGHT CURLY BRACKET;Pe;0;ON;<small> 007D;;;;N;SMALL CLOSING CURLY BRACKET;;;;
+FE5D;SMALL LEFT TORTOISE SHELL BRACKET;Ps;0;ON;<small> 3014;;;;N;SMALL OPENING TORTOISE SHELL BRACKET;;;;
+FE5E;SMALL RIGHT TORTOISE SHELL BRACKET;Pe;0;ON;<small> 3015;;;;N;SMALL CLOSING TORTOISE SHELL BRACKET;;;;
+FE5F;SMALL NUMBER SIGN;Po;0;ET;<small> 0023;;;;N;;;;;
+FE60;SMALL AMPERSAND;Po;0;ON;<small> 0026;;;;N;;;;;
+FE61;SMALL ASTERISK;Po;0;ON;<small> 002A;;;;N;;;;;
+FE62;SMALL PLUS SIGN;Sm;0;ES;<small> 002B;;;;N;;;;;
+FE63;SMALL HYPHEN-MINUS;Pd;0;ES;<small> 002D;;;;N;;;;;
+FE64;SMALL LESS-THAN SIGN;Sm;0;ON;<small> 003C;;;;N;;;;;
+FE65;SMALL GREATER-THAN SIGN;Sm;0;ON;<small> 003E;;;;N;;;;;
+FE66;SMALL EQUALS SIGN;Sm;0;ON;<small> 003D;;;;N;;;;;
+FE68;SMALL REVERSE SOLIDUS;Po;0;ON;<small> 005C;;;;N;SMALL BACKSLASH;;;;
+FE69;SMALL DOLLAR SIGN;Sc;0;ET;<small> 0024;;;;N;;;;;
+FE6A;SMALL PERCENT SIGN;Po;0;ET;<small> 0025;;;;N;;;;;
+FE6B;SMALL COMMERCIAL AT;Po;0;ON;<small> 0040;;;;N;;;;;
+FE70;ARABIC FATHATAN ISOLATED FORM;Lo;0;AL;<isolated> 0020 064B;;;;N;ARABIC SPACING FATHATAN;;;;
+FE71;ARABIC TATWEEL WITH FATHATAN ABOVE;Lo;0;AL;<medial> 0640 064B;;;;N;ARABIC FATHATAN ON TATWEEL;;;;
+FE72;ARABIC DAMMATAN ISOLATED FORM;Lo;0;AL;<isolated> 0020 064C;;;;N;ARABIC SPACING DAMMATAN;;;;
+FE73;ARABIC TAIL FRAGMENT;Lo;0;AL;;;;;N;;;;;
+FE74;ARABIC KASRATAN ISOLATED FORM;Lo;0;AL;<isolated> 0020 064D;;;;N;ARABIC SPACING KASRATAN;;;;
+FE76;ARABIC FATHA ISOLATED FORM;Lo;0;AL;<isolated> 0020 064E;;;;N;ARABIC SPACING FATHAH;;;;
+FE77;ARABIC FATHA MEDIAL FORM;Lo;0;AL;<medial> 0640 064E;;;;N;ARABIC FATHAH ON TATWEEL;;;;
+FE78;ARABIC DAMMA ISOLATED FORM;Lo;0;AL;<isolated> 0020 064F;;;;N;ARABIC SPACING DAMMAH;;;;
+FE79;ARABIC DAMMA MEDIAL FORM;Lo;0;AL;<medial> 0640 064F;;;;N;ARABIC DAMMAH ON TATWEEL;;;;
+FE7A;ARABIC KASRA ISOLATED FORM;Lo;0;AL;<isolated> 0020 0650;;;;N;ARABIC SPACING KASRAH;;;;
+FE7B;ARABIC KASRA MEDIAL FORM;Lo;0;AL;<medial> 0640 0650;;;;N;ARABIC KASRAH ON TATWEEL;;;;
+FE7C;ARABIC SHADDA ISOLATED FORM;Lo;0;AL;<isolated> 0020 0651;;;;N;ARABIC SPACING SHADDAH;;;;
+FE7D;ARABIC SHADDA MEDIAL FORM;Lo;0;AL;<medial> 0640 0651;;;;N;ARABIC SHADDAH ON TATWEEL;;;;
+FE7E;ARABIC SUKUN ISOLATED FORM;Lo;0;AL;<isolated> 0020 0652;;;;N;ARABIC SPACING SUKUN;;;;
+FE7F;ARABIC SUKUN MEDIAL FORM;Lo;0;AL;<medial> 0640 0652;;;;N;ARABIC SUKUN ON TATWEEL;;;;
+FE80;ARABIC LETTER HAMZA ISOLATED FORM;Lo;0;AL;<isolated> 0621;;;;N;GLYPH FOR ISOLATE ARABIC HAMZAH;;;;
+FE81;ARABIC LETTER ALEF WITH MADDA ABOVE ISOLATED FORM;Lo;0;AL;<isolated> 0622;;;;N;GLYPH FOR ISOLATE ARABIC MADDAH ON ALEF;;;;
+FE82;ARABIC LETTER ALEF WITH MADDA ABOVE FINAL FORM;Lo;0;AL;<final> 0622;;;;N;GLYPH FOR FINAL ARABIC MADDAH ON ALEF;;;;
+FE83;ARABIC LETTER ALEF WITH HAMZA ABOVE ISOLATED FORM;Lo;0;AL;<isolated> 0623;;;;N;GLYPH FOR ISOLATE ARABIC HAMZAH ON ALEF;;;;
+FE84;ARABIC LETTER ALEF WITH HAMZA ABOVE FINAL FORM;Lo;0;AL;<final> 0623;;;;N;GLYPH FOR FINAL ARABIC HAMZAH ON ALEF;;;;
+FE85;ARABIC LETTER WAW WITH HAMZA ABOVE ISOLATED FORM;Lo;0;AL;<isolated> 0624;;;;N;GLYPH FOR ISOLATE ARABIC HAMZAH ON WAW;;;;
+FE86;ARABIC LETTER WAW WITH HAMZA ABOVE FINAL FORM;Lo;0;AL;<final> 0624;;;;N;GLYPH FOR FINAL ARABIC HAMZAH ON WAW;;;;
+FE87;ARABIC LETTER ALEF WITH HAMZA BELOW ISOLATED FORM;Lo;0;AL;<isolated> 0625;;;;N;GLYPH FOR ISOLATE ARABIC HAMZAH UNDER ALEF;;;;
+FE88;ARABIC LETTER ALEF WITH HAMZA BELOW FINAL FORM;Lo;0;AL;<final> 0625;;;;N;GLYPH FOR FINAL ARABIC HAMZAH UNDER ALEF;;;;
+FE89;ARABIC LETTER YEH WITH HAMZA ABOVE ISOLATED FORM;Lo;0;AL;<isolated> 0626;;;;N;GLYPH FOR ISOLATE ARABIC HAMZAH ON YA;;;;
+FE8A;ARABIC LETTER YEH WITH HAMZA ABOVE FINAL FORM;Lo;0;AL;<final> 0626;;;;N;GLYPH FOR FINAL ARABIC HAMZAH ON YA;;;;
+FE8B;ARABIC LETTER YEH WITH HAMZA ABOVE INITIAL FORM;Lo;0;AL;<initial> 0626;;;;N;GLYPH FOR INITIAL ARABIC HAMZAH ON YA;;;;
+FE8C;ARABIC LETTER YEH WITH HAMZA ABOVE MEDIAL FORM;Lo;0;AL;<medial> 0626;;;;N;GLYPH FOR MEDIAL ARABIC HAMZAH ON YA;;;;
+FE8D;ARABIC LETTER ALEF ISOLATED FORM;Lo;0;AL;<isolated> 0627;;;;N;GLYPH FOR ISOLATE ARABIC ALEF;;;;
+FE8E;ARABIC LETTER ALEF FINAL FORM;Lo;0;AL;<final> 0627;;;;N;GLYPH FOR FINAL ARABIC ALEF;;;;
+FE8F;ARABIC LETTER BEH ISOLATED FORM;Lo;0;AL;<isolated> 0628;;;;N;GLYPH FOR ISOLATE ARABIC BAA;;;;
+FE90;ARABIC LETTER BEH FINAL FORM;Lo;0;AL;<final> 0628;;;;N;GLYPH FOR FINAL ARABIC BAA;;;;
+FE91;ARABIC LETTER BEH INITIAL FORM;Lo;0;AL;<initial> 0628;;;;N;GLYPH FOR INITIAL ARABIC BAA;;;;
+FE92;ARABIC LETTER BEH MEDIAL FORM;Lo;0;AL;<medial> 0628;;;;N;GLYPH FOR MEDIAL ARABIC BAA;;;;
+FE93;ARABIC LETTER TEH MARBUTA ISOLATED FORM;Lo;0;AL;<isolated> 0629;;;;N;GLYPH FOR ISOLATE ARABIC TAA MARBUTAH;;;;
+FE94;ARABIC LETTER TEH MARBUTA FINAL FORM;Lo;0;AL;<final> 0629;;;;N;GLYPH FOR FINAL ARABIC TAA MARBUTAH;;;;
+FE95;ARABIC LETTER TEH ISOLATED FORM;Lo;0;AL;<isolated> 062A;;;;N;GLYPH FOR ISOLATE ARABIC TAA;;;;
+FE96;ARABIC LETTER TEH FINAL FORM;Lo;0;AL;<final> 062A;;;;N;GLYPH FOR FINAL ARABIC TAA;;;;
+FE97;ARABIC LETTER TEH INITIAL FORM;Lo;0;AL;<initial> 062A;;;;N;GLYPH FOR INITIAL ARABIC TAA;;;;
+FE98;ARABIC LETTER TEH MEDIAL FORM;Lo;0;AL;<medial> 062A;;;;N;GLYPH FOR MEDIAL ARABIC TAA;;;;
+FE99;ARABIC LETTER THEH ISOLATED FORM;Lo;0;AL;<isolated> 062B;;;;N;GLYPH FOR ISOLATE ARABIC THAA;;;;
+FE9A;ARABIC LETTER THEH FINAL FORM;Lo;0;AL;<final> 062B;;;;N;GLYPH FOR FINAL ARABIC THAA;;;;
+FE9B;ARABIC LETTER THEH INITIAL FORM;Lo;0;AL;<initial> 062B;;;;N;GLYPH FOR INITIAL ARABIC THAA;;;;
+FE9C;ARABIC LETTER THEH MEDIAL FORM;Lo;0;AL;<medial> 062B;;;;N;GLYPH FOR MEDIAL ARABIC THAA;;;;
+FE9D;ARABIC LETTER JEEM ISOLATED FORM;Lo;0;AL;<isolated> 062C;;;;N;GLYPH FOR ISOLATE ARABIC JEEM;;;;
+FE9E;ARABIC LETTER JEEM FINAL FORM;Lo;0;AL;<final> 062C;;;;N;GLYPH FOR FINAL ARABIC JEEM;;;;
+FE9F;ARABIC LETTER JEEM INITIAL FORM;Lo;0;AL;<initial> 062C;;;;N;GLYPH FOR INITIAL ARABIC JEEM;;;;
+FEA0;ARABIC LETTER JEEM MEDIAL FORM;Lo;0;AL;<medial> 062C;;;;N;GLYPH FOR MEDIAL ARABIC JEEM;;;;
+FEA1;ARABIC LETTER HAH ISOLATED FORM;Lo;0;AL;<isolated> 062D;;;;N;GLYPH FOR ISOLATE ARABIC HAA;;;;
+FEA2;ARABIC LETTER HAH FINAL FORM;Lo;0;AL;<final> 062D;;;;N;GLYPH FOR FINAL ARABIC HAA;;;;
+FEA3;ARABIC LETTER HAH INITIAL FORM;Lo;0;AL;<initial> 062D;;;;N;GLYPH FOR INITIAL ARABIC HAA;;;;
+FEA4;ARABIC LETTER HAH MEDIAL FORM;Lo;0;AL;<medial> 062D;;;;N;GLYPH FOR MEDIAL ARABIC HAA;;;;
+FEA5;ARABIC LETTER KHAH ISOLATED FORM;Lo;0;AL;<isolated> 062E;;;;N;GLYPH FOR ISOLATE ARABIC KHAA;;;;
+FEA6;ARABIC LETTER KHAH FINAL FORM;Lo;0;AL;<final> 062E;;;;N;GLYPH FOR FINAL ARABIC KHAA;;;;
+FEA7;ARABIC LETTER KHAH INITIAL FORM;Lo;0;AL;<initial> 062E;;;;N;GLYPH FOR INITIAL ARABIC KHAA;;;;
+FEA8;ARABIC LETTER KHAH MEDIAL FORM;Lo;0;AL;<medial> 062E;;;;N;GLYPH FOR MEDIAL ARABIC KHAA;;;;
+FEA9;ARABIC LETTER DAL ISOLATED FORM;Lo;0;AL;<isolated> 062F;;;;N;GLYPH FOR ISOLATE ARABIC DAL;;;;
+FEAA;ARABIC LETTER DAL FINAL FORM;Lo;0;AL;<final> 062F;;;;N;GLYPH FOR FINAL ARABIC DAL;;;;
+FEAB;ARABIC LETTER THAL ISOLATED FORM;Lo;0;AL;<isolated> 0630;;;;N;GLYPH FOR ISOLATE ARABIC THAL;;;;
+FEAC;ARABIC LETTER THAL FINAL FORM;Lo;0;AL;<final> 0630;;;;N;GLYPH FOR FINAL ARABIC THAL;;;;
+FEAD;ARABIC LETTER REH ISOLATED FORM;Lo;0;AL;<isolated> 0631;;;;N;GLYPH FOR ISOLATE ARABIC RA;;;;
+FEAE;ARABIC LETTER REH FINAL FORM;Lo;0;AL;<final> 0631;;;;N;GLYPH FOR FINAL ARABIC RA;;;;
+FEAF;ARABIC LETTER ZAIN ISOLATED FORM;Lo;0;AL;<isolated> 0632;;;;N;GLYPH FOR ISOLATE ARABIC ZAIN;;;;
+FEB0;ARABIC LETTER ZAIN FINAL FORM;Lo;0;AL;<final> 0632;;;;N;GLYPH FOR FINAL ARABIC ZAIN;;;;
+FEB1;ARABIC LETTER SEEN ISOLATED FORM;Lo;0;AL;<isolated> 0633;;;;N;GLYPH FOR ISOLATE ARABIC SEEN;;;;
+FEB2;ARABIC LETTER SEEN FINAL FORM;Lo;0;AL;<final> 0633;;;;N;GLYPH FOR FINAL ARABIC SEEN;;;;
+FEB3;ARABIC LETTER SEEN INITIAL FORM;Lo;0;AL;<initial> 0633;;;;N;GLYPH FOR INITIAL ARABIC SEEN;;;;
+FEB4;ARABIC LETTER SEEN MEDIAL FORM;Lo;0;AL;<medial> 0633;;;;N;GLYPH FOR MEDIAL ARABIC SEEN;;;;
+FEB5;ARABIC LETTER SHEEN ISOLATED FORM;Lo;0;AL;<isolated> 0634;;;;N;GLYPH FOR ISOLATE ARABIC SHEEN;;;;
+FEB6;ARABIC LETTER SHEEN FINAL FORM;Lo;0;AL;<final> 0634;;;;N;GLYPH FOR FINAL ARABIC SHEEN;;;;
+FEB7;ARABIC LETTER SHEEN INITIAL FORM;Lo;0;AL;<initial> 0634;;;;N;GLYPH FOR INITIAL ARABIC SHEEN;;;;
+FEB8;ARABIC LETTER SHEEN MEDIAL FORM;Lo;0;AL;<medial> 0634;;;;N;GLYPH FOR MEDIAL ARABIC SHEEN;;;;
+FEB9;ARABIC LETTER SAD ISOLATED FORM;Lo;0;AL;<isolated> 0635;;;;N;GLYPH FOR ISOLATE ARABIC SAD;;;;
+FEBA;ARABIC LETTER SAD FINAL FORM;Lo;0;AL;<final> 0635;;;;N;GLYPH FOR FINAL ARABIC SAD;;;;
+FEBB;ARABIC LETTER SAD INITIAL FORM;Lo;0;AL;<initial> 0635;;;;N;GLYPH FOR INITIAL ARABIC SAD;;;;
+FEBC;ARABIC LETTER SAD MEDIAL FORM;Lo;0;AL;<medial> 0635;;;;N;GLYPH FOR MEDIAL ARABIC SAD;;;;
+FEBD;ARABIC LETTER DAD ISOLATED FORM;Lo;0;AL;<isolated> 0636;;;;N;GLYPH FOR ISOLATE ARABIC DAD;;;;
+FEBE;ARABIC LETTER DAD FINAL FORM;Lo;0;AL;<final> 0636;;;;N;GLYPH FOR FINAL ARABIC DAD;;;;
+FEBF;ARABIC LETTER DAD INITIAL FORM;Lo;0;AL;<initial> 0636;;;;N;GLYPH FOR INITIAL ARABIC DAD;;;;
+FEC0;ARABIC LETTER DAD MEDIAL FORM;Lo;0;AL;<medial> 0636;;;;N;GLYPH FOR MEDIAL ARABIC DAD;;;;
+FEC1;ARABIC LETTER TAH ISOLATED FORM;Lo;0;AL;<isolated> 0637;;;;N;GLYPH FOR ISOLATE ARABIC TAH;;;;
+FEC2;ARABIC LETTER TAH FINAL FORM;Lo;0;AL;<final> 0637;;;;N;GLYPH FOR FINAL ARABIC TAH;;;;
+FEC3;ARABIC LETTER TAH INITIAL FORM;Lo;0;AL;<initial> 0637;;;;N;GLYPH FOR INITIAL ARABIC TAH;;;;
+FEC4;ARABIC LETTER TAH MEDIAL FORM;Lo;0;AL;<medial> 0637;;;;N;GLYPH FOR MEDIAL ARABIC TAH;;;;
+FEC5;ARABIC LETTER ZAH ISOLATED FORM;Lo;0;AL;<isolated> 0638;;;;N;GLYPH FOR ISOLATE ARABIC DHAH;;;;
+FEC6;ARABIC LETTER ZAH FINAL FORM;Lo;0;AL;<final> 0638;;;;N;GLYPH FOR FINAL ARABIC DHAH;;;;
+FEC7;ARABIC LETTER ZAH INITIAL FORM;Lo;0;AL;<initial> 0638;;;;N;GLYPH FOR INITIAL ARABIC DHAH;;;;
+FEC8;ARABIC LETTER ZAH MEDIAL FORM;Lo;0;AL;<medial> 0638;;;;N;GLYPH FOR MEDIAL ARABIC DHAH;;;;
+FEC9;ARABIC LETTER AIN ISOLATED FORM;Lo;0;AL;<isolated> 0639;;;;N;GLYPH FOR ISOLATE ARABIC AIN;;;;
+FECA;ARABIC LETTER AIN FINAL FORM;Lo;0;AL;<final> 0639;;;;N;GLYPH FOR FINAL ARABIC AIN;;;;
+FECB;ARABIC LETTER AIN INITIAL FORM;Lo;0;AL;<initial> 0639;;;;N;GLYPH FOR INITIAL ARABIC AIN;;;;
+FECC;ARABIC LETTER AIN MEDIAL FORM;Lo;0;AL;<medial> 0639;;;;N;GLYPH FOR MEDIAL ARABIC AIN;;;;
+FECD;ARABIC LETTER GHAIN ISOLATED FORM;Lo;0;AL;<isolated> 063A;;;;N;GLYPH FOR ISOLATE ARABIC GHAIN;;;;
+FECE;ARABIC LETTER GHAIN FINAL FORM;Lo;0;AL;<final> 063A;;;;N;GLYPH FOR FINAL ARABIC GHAIN;;;;
+FECF;ARABIC LETTER GHAIN INITIAL FORM;Lo;0;AL;<initial> 063A;;;;N;GLYPH FOR INITIAL ARABIC GHAIN;;;;
+FED0;ARABIC LETTER GHAIN MEDIAL FORM;Lo;0;AL;<medial> 063A;;;;N;GLYPH FOR MEDIAL ARABIC GHAIN;;;;
+FED1;ARABIC LETTER FEH ISOLATED FORM;Lo;0;AL;<isolated> 0641;;;;N;GLYPH FOR ISOLATE ARABIC FA;;;;
+FED2;ARABIC LETTER FEH FINAL FORM;Lo;0;AL;<final> 0641;;;;N;GLYPH FOR FINAL ARABIC FA;;;;
+FED3;ARABIC LETTER FEH INITIAL FORM;Lo;0;AL;<initial> 0641;;;;N;GLYPH FOR INITIAL ARABIC FA;;;;
+FED4;ARABIC LETTER FEH MEDIAL FORM;Lo;0;AL;<medial> 0641;;;;N;GLYPH FOR MEDIAL ARABIC FA;;;;
+FED5;ARABIC LETTER QAF ISOLATED FORM;Lo;0;AL;<isolated> 0642;;;;N;GLYPH FOR ISOLATE ARABIC QAF;;;;
+FED6;ARABIC LETTER QAF FINAL FORM;Lo;0;AL;<final> 0642;;;;N;GLYPH FOR FINAL ARABIC QAF;;;;
+FED7;ARABIC LETTER QAF INITIAL FORM;Lo;0;AL;<initial> 0642;;;;N;GLYPH FOR INITIAL ARABIC QAF;;;;
+FED8;ARABIC LETTER QAF MEDIAL FORM;Lo;0;AL;<medial> 0642;;;;N;GLYPH FOR MEDIAL ARABIC QAF;;;;
+FED9;ARABIC LETTER KAF ISOLATED FORM;Lo;0;AL;<isolated> 0643;;;;N;GLYPH FOR ISOLATE ARABIC CAF;;;;
+FEDA;ARABIC LETTER KAF FINAL FORM;Lo;0;AL;<final> 0643;;;;N;GLYPH FOR FINAL ARABIC CAF;;;;
+FEDB;ARABIC LETTER KAF INITIAL FORM;Lo;0;AL;<initial> 0643;;;;N;GLYPH FOR INITIAL ARABIC CAF;;;;
+FEDC;ARABIC LETTER KAF MEDIAL FORM;Lo;0;AL;<medial> 0643;;;;N;GLYPH FOR MEDIAL ARABIC CAF;;;;
+FEDD;ARABIC LETTER LAM ISOLATED FORM;Lo;0;AL;<isolated> 0644;;;;N;GLYPH FOR ISOLATE ARABIC LAM;;;;
+FEDE;ARABIC LETTER LAM FINAL FORM;Lo;0;AL;<final> 0644;;;;N;GLYPH FOR FINAL ARABIC LAM;;;;
+FEDF;ARABIC LETTER LAM INITIAL FORM;Lo;0;AL;<initial> 0644;;;;N;GLYPH FOR INITIAL ARABIC LAM;;;;
+FEE0;ARABIC LETTER LAM MEDIAL FORM;Lo;0;AL;<medial> 0644;;;;N;GLYPH FOR MEDIAL ARABIC LAM;;;;
+FEE1;ARABIC LETTER MEEM ISOLATED FORM;Lo;0;AL;<isolated> 0645;;;;N;GLYPH FOR ISOLATE ARABIC MEEM;;;;
+FEE2;ARABIC LETTER MEEM FINAL FORM;Lo;0;AL;<final> 0645;;;;N;GLYPH FOR FINAL ARABIC MEEM;;;;
+FEE3;ARABIC LETTER MEEM INITIAL FORM;Lo;0;AL;<initial> 0645;;;;N;GLYPH FOR INITIAL ARABIC MEEM;;;;
+FEE4;ARABIC LETTER MEEM MEDIAL FORM;Lo;0;AL;<medial> 0645;;;;N;GLYPH FOR MEDIAL ARABIC MEEM;;;;
+FEE5;ARABIC LETTER NOON ISOLATED FORM;Lo;0;AL;<isolated> 0646;;;;N;GLYPH FOR ISOLATE ARABIC NOON;;;;
+FEE6;ARABIC LETTER NOON FINAL FORM;Lo;0;AL;<final> 0646;;;;N;GLYPH FOR FINAL ARABIC NOON;;;;
+FEE7;ARABIC LETTER NOON INITIAL FORM;Lo;0;AL;<initial> 0646;;;;N;GLYPH FOR INITIAL ARABIC NOON;;;;
+FEE8;ARABIC LETTER NOON MEDIAL FORM;Lo;0;AL;<medial> 0646;;;;N;GLYPH FOR MEDIAL ARABIC NOON;;;;
+FEE9;ARABIC LETTER HEH ISOLATED FORM;Lo;0;AL;<isolated> 0647;;;;N;GLYPH FOR ISOLATE ARABIC HA;;;;
+FEEA;ARABIC LETTER HEH FINAL FORM;Lo;0;AL;<final> 0647;;;;N;GLYPH FOR FINAL ARABIC HA;;;;
+FEEB;ARABIC LETTER HEH INITIAL FORM;Lo;0;AL;<initial> 0647;;;;N;GLYPH FOR INITIAL ARABIC HA;;;;
+FEEC;ARABIC LETTER HEH MEDIAL FORM;Lo;0;AL;<medial> 0647;;;;N;GLYPH FOR MEDIAL ARABIC HA;;;;
+FEED;ARABIC LETTER WAW ISOLATED FORM;Lo;0;AL;<isolated> 0648;;;;N;GLYPH FOR ISOLATE ARABIC WAW;;;;
+FEEE;ARABIC LETTER WAW FINAL FORM;Lo;0;AL;<final> 0648;;;;N;GLYPH FOR FINAL ARABIC WAW;;;;
+FEEF;ARABIC LETTER ALEF MAKSURA ISOLATED FORM;Lo;0;AL;<isolated> 0649;;;;N;GLYPH FOR ISOLATE ARABIC ALEF MAQSURAH;;;;
+FEF0;ARABIC LETTER ALEF MAKSURA FINAL FORM;Lo;0;AL;<final> 0649;;;;N;GLYPH FOR FINAL ARABIC ALEF MAQSURAH;;;;
+FEF1;ARABIC LETTER YEH ISOLATED FORM;Lo;0;AL;<isolated> 064A;;;;N;GLYPH FOR ISOLATE ARABIC YA;;;;
+FEF2;ARABIC LETTER YEH FINAL FORM;Lo;0;AL;<final> 064A;;;;N;GLYPH FOR FINAL ARABIC YA;;;;
+FEF3;ARABIC LETTER YEH INITIAL FORM;Lo;0;AL;<initial> 064A;;;;N;GLYPH FOR INITIAL ARABIC YA;;;;
+FEF4;ARABIC LETTER YEH MEDIAL FORM;Lo;0;AL;<medial> 064A;;;;N;GLYPH FOR MEDIAL ARABIC YA;;;;
+FEF5;ARABIC LIGATURE LAM WITH ALEF WITH MADDA ABOVE ISOLATED FORM;Lo;0;AL;<isolated> 0644 0622;;;;N;GLYPH FOR ISOLATE ARABIC MADDAH ON LIGATURE LAM ALEF;;;;
+FEF6;ARABIC LIGATURE LAM WITH ALEF WITH MADDA ABOVE FINAL FORM;Lo;0;AL;<final> 0644 0622;;;;N;GLYPH FOR FINAL ARABIC MADDAH ON LIGATURE LAM ALEF;;;;
+FEF7;ARABIC LIGATURE LAM WITH ALEF WITH HAMZA ABOVE ISOLATED FORM;Lo;0;AL;<isolated> 0644 0623;;;;N;GLYPH FOR ISOLATE ARABIC HAMZAH ON LIGATURE LAM ALEF;;;;
+FEF8;ARABIC LIGATURE LAM WITH ALEF WITH HAMZA ABOVE FINAL FORM;Lo;0;AL;<final> 0644 0623;;;;N;GLYPH FOR FINAL ARABIC HAMZAH ON LIGATURE LAM ALEF;;;;
+FEF9;ARABIC LIGATURE LAM WITH ALEF WITH HAMZA BELOW ISOLATED FORM;Lo;0;AL;<isolated> 0644 0625;;;;N;GLYPH FOR ISOLATE ARABIC HAMZAH UNDER LIGATURE LAM ALEF;;;;
+FEFA;ARABIC LIGATURE LAM WITH ALEF WITH HAMZA BELOW FINAL FORM;Lo;0;AL;<final> 0644 0625;;;;N;GLYPH FOR FINAL ARABIC HAMZAH UNDER LIGATURE LAM ALEF;;;;
+FEFB;ARABIC LIGATURE LAM WITH ALEF ISOLATED FORM;Lo;0;AL;<isolated> 0644 0627;;;;N;GLYPH FOR ISOLATE ARABIC LIGATURE LAM ALEF;;;;
+FEFC;ARABIC LIGATURE LAM WITH ALEF FINAL FORM;Lo;0;AL;<final> 0644 0627;;;;N;GLYPH FOR FINAL ARABIC LIGATURE LAM ALEF;;;;
+FEFF;ZERO WIDTH NO-BREAK SPACE;Cf;0;BN;;;;;N;BYTE ORDER MARK;;;;
+FF01;FULLWIDTH EXCLAMATION MARK;Po;0;ON;<wide> 0021;;;;N;;;;;
+FF02;FULLWIDTH QUOTATION MARK;Po;0;ON;<wide> 0022;;;;N;;;;;
+FF03;FULLWIDTH NUMBER SIGN;Po;0;ET;<wide> 0023;;;;N;;;;;
+FF04;FULLWIDTH DOLLAR SIGN;Sc;0;ET;<wide> 0024;;;;N;;;;;
+FF05;FULLWIDTH PERCENT SIGN;Po;0;ET;<wide> 0025;;;;N;;;;;
+FF06;FULLWIDTH AMPERSAND;Po;0;ON;<wide> 0026;;;;N;;;;;
+FF07;FULLWIDTH APOSTROPHE;Po;0;ON;<wide> 0027;;;;N;;;;;
+FF08;FULLWIDTH LEFT PARENTHESIS;Ps;0;ON;<wide> 0028;;;;Y;FULLWIDTH OPENING PARENTHESIS;;;;
+FF09;FULLWIDTH RIGHT PARENTHESIS;Pe;0;ON;<wide> 0029;;;;Y;FULLWIDTH CLOSING PARENTHESIS;;;;
+FF0A;FULLWIDTH ASTERISK;Po;0;ON;<wide> 002A;;;;N;;;;;
+FF0B;FULLWIDTH PLUS SIGN;Sm;0;ES;<wide> 002B;;;;N;;;;;
+FF0C;FULLWIDTH COMMA;Po;0;CS;<wide> 002C;;;;N;;;;;
+FF0D;FULLWIDTH HYPHEN-MINUS;Pd;0;ES;<wide> 002D;;;;N;;;;;
+FF0E;FULLWIDTH FULL STOP;Po;0;CS;<wide> 002E;;;;N;FULLWIDTH PERIOD;;;;
+FF0F;FULLWIDTH SOLIDUS;Po;0;CS;<wide> 002F;;;;N;FULLWIDTH SLASH;;;;
+FF10;FULLWIDTH DIGIT ZERO;Nd;0;EN;<wide> 0030;0;0;0;N;;;;;
+FF11;FULLWIDTH DIGIT ONE;Nd;0;EN;<wide> 0031;1;1;1;N;;;;;
+FF12;FULLWIDTH DIGIT TWO;Nd;0;EN;<wide> 0032;2;2;2;N;;;;;
+FF13;FULLWIDTH DIGIT THREE;Nd;0;EN;<wide> 0033;3;3;3;N;;;;;
+FF14;FULLWIDTH DIGIT FOUR;Nd;0;EN;<wide> 0034;4;4;4;N;;;;;
+FF15;FULLWIDTH DIGIT FIVE;Nd;0;EN;<wide> 0035;5;5;5;N;;;;;
+FF16;FULLWIDTH DIGIT SIX;Nd;0;EN;<wide> 0036;6;6;6;N;;;;;
+FF17;FULLWIDTH DIGIT SEVEN;Nd;0;EN;<wide> 0037;7;7;7;N;;;;;
+FF18;FULLWIDTH DIGIT EIGHT;Nd;0;EN;<wide> 0038;8;8;8;N;;;;;
+FF19;FULLWIDTH DIGIT NINE;Nd;0;EN;<wide> 0039;9;9;9;N;;;;;
+FF1A;FULLWIDTH COLON;Po;0;CS;<wide> 003A;;;;N;;;;;
+FF1B;FULLWIDTH SEMICOLON;Po;0;ON;<wide> 003B;;;;N;;;;;
+FF1C;FULLWIDTH LESS-THAN SIGN;Sm;0;ON;<wide> 003C;;;;Y;;;;;
+FF1D;FULLWIDTH EQUALS SIGN;Sm;0;ON;<wide> 003D;;;;N;;;;;
+FF1E;FULLWIDTH GREATER-THAN SIGN;Sm;0;ON;<wide> 003E;;;;Y;;;;;
+FF1F;FULLWIDTH QUESTION MARK;Po;0;ON;<wide> 003F;;;;N;;;;;
+FF20;FULLWIDTH COMMERCIAL AT;Po;0;ON;<wide> 0040;;;;N;;;;;
+FF21;FULLWIDTH LATIN CAPITAL LETTER A;Lu;0;L;<wide> 0041;;;;N;;;;FF41;
+FF22;FULLWIDTH LATIN CAPITAL LETTER B;Lu;0;L;<wide> 0042;;;;N;;;;FF42;
+FF23;FULLWIDTH LATIN CAPITAL LETTER C;Lu;0;L;<wide> 0043;;;;N;;;;FF43;
+FF24;FULLWIDTH LATIN CAPITAL LETTER D;Lu;0;L;<wide> 0044;;;;N;;;;FF44;
+FF25;FULLWIDTH LATIN CAPITAL LETTER E;Lu;0;L;<wide> 0045;;;;N;;;;FF45;
+FF26;FULLWIDTH LATIN CAPITAL LETTER F;Lu;0;L;<wide> 0046;;;;N;;;;FF46;
+FF27;FULLWIDTH LATIN CAPITAL LETTER G;Lu;0;L;<wide> 0047;;;;N;;;;FF47;
+FF28;FULLWIDTH LATIN CAPITAL LETTER H;Lu;0;L;<wide> 0048;;;;N;;;;FF48;
+FF29;FULLWIDTH LATIN CAPITAL LETTER I;Lu;0;L;<wide> 0049;;;;N;;;;FF49;
+FF2A;FULLWIDTH LATIN CAPITAL LETTER J;Lu;0;L;<wide> 004A;;;;N;;;;FF4A;
+FF2B;FULLWIDTH LATIN CAPITAL LETTER K;Lu;0;L;<wide> 004B;;;;N;;;;FF4B;
+FF2C;FULLWIDTH LATIN CAPITAL LETTER L;Lu;0;L;<wide> 004C;;;;N;;;;FF4C;
+FF2D;FULLWIDTH LATIN CAPITAL LETTER M;Lu;0;L;<wide> 004D;;;;N;;;;FF4D;
+FF2E;FULLWIDTH LATIN CAPITAL LETTER N;Lu;0;L;<wide> 004E;;;;N;;;;FF4E;
+FF2F;FULLWIDTH LATIN CAPITAL LETTER O;Lu;0;L;<wide> 004F;;;;N;;;;FF4F;
+FF30;FULLWIDTH LATIN CAPITAL LETTER P;Lu;0;L;<wide> 0050;;;;N;;;;FF50;
+FF31;FULLWIDTH LATIN CAPITAL LETTER Q;Lu;0;L;<wide> 0051;;;;N;;;;FF51;
+FF32;FULLWIDTH LATIN CAPITAL LETTER R;Lu;0;L;<wide> 0052;;;;N;;;;FF52;
+FF33;FULLWIDTH LATIN CAPITAL LETTER S;Lu;0;L;<wide> 0053;;;;N;;;;FF53;
+FF34;FULLWIDTH LATIN CAPITAL LETTER T;Lu;0;L;<wide> 0054;;;;N;;;;FF54;
+FF35;FULLWIDTH LATIN CAPITAL LETTER U;Lu;0;L;<wide> 0055;;;;N;;;;FF55;
+FF36;FULLWIDTH LATIN CAPITAL LETTER V;Lu;0;L;<wide> 0056;;;;N;;;;FF56;
+FF37;FULLWIDTH LATIN CAPITAL LETTER W;Lu;0;L;<wide> 0057;;;;N;;;;FF57;
+FF38;FULLWIDTH LATIN CAPITAL LETTER X;Lu;0;L;<wide> 0058;;;;N;;;;FF58;
+FF39;FULLWIDTH LATIN CAPITAL LETTER Y;Lu;0;L;<wide> 0059;;;;N;;;;FF59;
+FF3A;FULLWIDTH LATIN CAPITAL LETTER Z;Lu;0;L;<wide> 005A;;;;N;;;;FF5A;
+FF3B;FULLWIDTH LEFT SQUARE BRACKET;Ps;0;ON;<wide> 005B;;;;Y;FULLWIDTH OPENING SQUARE BRACKET;;;;
+FF3C;FULLWIDTH REVERSE SOLIDUS;Po;0;ON;<wide> 005C;;;;N;FULLWIDTH BACKSLASH;;;;
+FF3D;FULLWIDTH RIGHT SQUARE BRACKET;Pe;0;ON;<wide> 005D;;;;Y;FULLWIDTH CLOSING SQUARE BRACKET;;;;
+FF3E;FULLWIDTH CIRCUMFLEX ACCENT;Sk;0;ON;<wide> 005E;;;;N;FULLWIDTH SPACING CIRCUMFLEX;;;;
+FF3F;FULLWIDTH LOW LINE;Pc;0;ON;<wide> 005F;;;;N;FULLWIDTH SPACING UNDERSCORE;;;;
+FF40;FULLWIDTH GRAVE ACCENT;Sk;0;ON;<wide> 0060;;;;N;FULLWIDTH SPACING GRAVE;;;;
+FF41;FULLWIDTH LATIN SMALL LETTER A;Ll;0;L;<wide> 0061;;;;N;;;FF21;;FF21
+FF42;FULLWIDTH LATIN SMALL LETTER B;Ll;0;L;<wide> 0062;;;;N;;;FF22;;FF22
+FF43;FULLWIDTH LATIN SMALL LETTER C;Ll;0;L;<wide> 0063;;;;N;;;FF23;;FF23
+FF44;FULLWIDTH LATIN SMALL LETTER D;Ll;0;L;<wide> 0064;;;;N;;;FF24;;FF24
+FF45;FULLWIDTH LATIN SMALL LETTER E;Ll;0;L;<wide> 0065;;;;N;;;FF25;;FF25
+FF46;FULLWIDTH LATIN SMALL LETTER F;Ll;0;L;<wide> 0066;;;;N;;;FF26;;FF26
+FF47;FULLWIDTH LATIN SMALL LETTER G;Ll;0;L;<wide> 0067;;;;N;;;FF27;;FF27
+FF48;FULLWIDTH LATIN SMALL LETTER H;Ll;0;L;<wide> 0068;;;;N;;;FF28;;FF28
+FF49;FULLWIDTH LATIN SMALL LETTER I;Ll;0;L;<wide> 0069;;;;N;;;FF29;;FF29
+FF4A;FULLWIDTH LATIN SMALL LETTER J;Ll;0;L;<wide> 006A;;;;N;;;FF2A;;FF2A
+FF4B;FULLWIDTH LATIN SMALL LETTER K;Ll;0;L;<wide> 006B;;;;N;;;FF2B;;FF2B
+FF4C;FULLWIDTH LATIN SMALL LETTER L;Ll;0;L;<wide> 006C;;;;N;;;FF2C;;FF2C
+FF4D;FULLWIDTH LATIN SMALL LETTER M;Ll;0;L;<wide> 006D;;;;N;;;FF2D;;FF2D
+FF4E;FULLWIDTH LATIN SMALL LETTER N;Ll;0;L;<wide> 006E;;;;N;;;FF2E;;FF2E
+FF4F;FULLWIDTH LATIN SMALL LETTER O;Ll;0;L;<wide> 006F;;;;N;;;FF2F;;FF2F
+FF50;FULLWIDTH LATIN SMALL LETTER P;Ll;0;L;<wide> 0070;;;;N;;;FF30;;FF30
+FF51;FULLWIDTH LATIN SMALL LETTER Q;Ll;0;L;<wide> 0071;;;;N;;;FF31;;FF31
+FF52;FULLWIDTH LATIN SMALL LETTER R;Ll;0;L;<wide> 0072;;;;N;;;FF32;;FF32
+FF53;FULLWIDTH LATIN SMALL LETTER S;Ll;0;L;<wide> 0073;;;;N;;;FF33;;FF33
+FF54;FULLWIDTH LATIN SMALL LETTER T;Ll;0;L;<wide> 0074;;;;N;;;FF34;;FF34
+FF55;FULLWIDTH LATIN SMALL LETTER U;Ll;0;L;<wide> 0075;;;;N;;;FF35;;FF35
+FF56;FULLWIDTH LATIN SMALL LETTER V;Ll;0;L;<wide> 0076;;;;N;;;FF36;;FF36
+FF57;FULLWIDTH LATIN SMALL LETTER W;Ll;0;L;<wide> 0077;;;;N;;;FF37;;FF37
+FF58;FULLWIDTH LATIN SMALL LETTER X;Ll;0;L;<wide> 0078;;;;N;;;FF38;;FF38
+FF59;FULLWIDTH LATIN SMALL LETTER Y;Ll;0;L;<wide> 0079;;;;N;;;FF39;;FF39
+FF5A;FULLWIDTH LATIN SMALL LETTER Z;Ll;0;L;<wide> 007A;;;;N;;;FF3A;;FF3A
+FF5B;FULLWIDTH LEFT CURLY BRACKET;Ps;0;ON;<wide> 007B;;;;Y;FULLWIDTH OPENING CURLY BRACKET;;;;
+FF5C;FULLWIDTH VERTICAL LINE;Sm;0;ON;<wide> 007C;;;;N;FULLWIDTH VERTICAL BAR;;;;
+FF5D;FULLWIDTH RIGHT CURLY BRACKET;Pe;0;ON;<wide> 007D;;;;Y;FULLWIDTH CLOSING CURLY BRACKET;;;;
+FF5E;FULLWIDTH TILDE;Sm;0;ON;<wide> 007E;;;;N;FULLWIDTH SPACING TILDE;;;;
+FF5F;FULLWIDTH LEFT WHITE PARENTHESIS;Ps;0;ON;<wide> 2985;;;;Y;;*;;;
+FF60;FULLWIDTH RIGHT WHITE PARENTHESIS;Pe;0;ON;<wide> 2986;;;;Y;;*;;;
+FF61;HALFWIDTH IDEOGRAPHIC FULL STOP;Po;0;ON;<narrow> 3002;;;;N;HALFWIDTH IDEOGRAPHIC PERIOD;;;;
+FF62;HALFWIDTH LEFT CORNER BRACKET;Ps;0;ON;<narrow> 300C;;;;Y;HALFWIDTH OPENING CORNER BRACKET;;;;
+FF63;HALFWIDTH RIGHT CORNER BRACKET;Pe;0;ON;<narrow> 300D;;;;Y;HALFWIDTH CLOSING CORNER BRACKET;;;;
+FF64;HALFWIDTH IDEOGRAPHIC COMMA;Po;0;ON;<narrow> 3001;;;;N;;;;;
+FF65;HALFWIDTH KATAKANA MIDDLE DOT;Po;0;ON;<narrow> 30FB;;;;N;;;;;
+FF66;HALFWIDTH KATAKANA LETTER WO;Lo;0;L;<narrow> 30F2;;;;N;;;;;
+FF67;HALFWIDTH KATAKANA LETTER SMALL A;Lo;0;L;<narrow> 30A1;;;;N;;;;;
+FF68;HALFWIDTH KATAKANA LETTER SMALL I;Lo;0;L;<narrow> 30A3;;;;N;;;;;
+FF69;HALFWIDTH KATAKANA LETTER SMALL U;Lo;0;L;<narrow> 30A5;;;;N;;;;;
+FF6A;HALFWIDTH KATAKANA LETTER SMALL E;Lo;0;L;<narrow> 30A7;;;;N;;;;;
+FF6B;HALFWIDTH KATAKANA LETTER SMALL O;Lo;0;L;<narrow> 30A9;;;;N;;;;;
+FF6C;HALFWIDTH KATAKANA LETTER SMALL YA;Lo;0;L;<narrow> 30E3;;;;N;;;;;
+FF6D;HALFWIDTH KATAKANA LETTER SMALL YU;Lo;0;L;<narrow> 30E5;;;;N;;;;;
+FF6E;HALFWIDTH KATAKANA LETTER SMALL YO;Lo;0;L;<narrow> 30E7;;;;N;;;;;
+FF6F;HALFWIDTH KATAKANA LETTER SMALL TU;Lo;0;L;<narrow> 30C3;;;;N;;;;;
+FF70;HALFWIDTH KATAKANA-HIRAGANA PROLONGED SOUND MARK;Lm;0;L;<narrow> 30FC;;;;N;;;;;
+FF71;HALFWIDTH KATAKANA LETTER A;Lo;0;L;<narrow> 30A2;;;;N;;;;;
+FF72;HALFWIDTH KATAKANA LETTER I;Lo;0;L;<narrow> 30A4;;;;N;;;;;
+FF73;HALFWIDTH KATAKANA LETTER U;Lo;0;L;<narrow> 30A6;;;;N;;;;;
+FF74;HALFWIDTH KATAKANA LETTER E;Lo;0;L;<narrow> 30A8;;;;N;;;;;
+FF75;HALFWIDTH KATAKANA LETTER O;Lo;0;L;<narrow> 30AA;;;;N;;;;;
+FF76;HALFWIDTH KATAKANA LETTER KA;Lo;0;L;<narrow> 30AB;;;;N;;;;;
+FF77;HALFWIDTH KATAKANA LETTER KI;Lo;0;L;<narrow> 30AD;;;;N;;;;;
+FF78;HALFWIDTH KATAKANA LETTER KU;Lo;0;L;<narrow> 30AF;;;;N;;;;;
+FF79;HALFWIDTH KATAKANA LETTER KE;Lo;0;L;<narrow> 30B1;;;;N;;;;;
+FF7A;HALFWIDTH KATAKANA LETTER KO;Lo;0;L;<narrow> 30B3;;;;N;;;;;
+FF7B;HALFWIDTH KATAKANA LETTER SA;Lo;0;L;<narrow> 30B5;;;;N;;;;;
+FF7C;HALFWIDTH KATAKANA LETTER SI;Lo;0;L;<narrow> 30B7;;;;N;;;;;
+FF7D;HALFWIDTH KATAKANA LETTER SU;Lo;0;L;<narrow> 30B9;;;;N;;;;;
+FF7E;HALFWIDTH KATAKANA LETTER SE;Lo;0;L;<narrow> 30BB;;;;N;;;;;
+FF7F;HALFWIDTH KATAKANA LETTER SO;Lo;0;L;<narrow> 30BD;;;;N;;;;;
+FF80;HALFWIDTH KATAKANA LETTER TA;Lo;0;L;<narrow> 30BF;;;;N;;;;;
+FF81;HALFWIDTH KATAKANA LETTER TI;Lo;0;L;<narrow> 30C1;;;;N;;;;;
+FF82;HALFWIDTH KATAKANA LETTER TU;Lo;0;L;<narrow> 30C4;;;;N;;;;;
+FF83;HALFWIDTH KATAKANA LETTER TE;Lo;0;L;<narrow> 30C6;;;;N;;;;;
+FF84;HALFWIDTH KATAKANA LETTER TO;Lo;0;L;<narrow> 30C8;;;;N;;;;;
+FF85;HALFWIDTH KATAKANA LETTER NA;Lo;0;L;<narrow> 30CA;;;;N;;;;;
+FF86;HALFWIDTH KATAKANA LETTER NI;Lo;0;L;<narrow> 30CB;;;;N;;;;;
+FF87;HALFWIDTH KATAKANA LETTER NU;Lo;0;L;<narrow> 30CC;;;;N;;;;;
+FF88;HALFWIDTH KATAKANA LETTER NE;Lo;0;L;<narrow> 30CD;;;;N;;;;;
+FF89;HALFWIDTH KATAKANA LETTER NO;Lo;0;L;<narrow> 30CE;;;;N;;;;;
+FF8A;HALFWIDTH KATAKANA LETTER HA;Lo;0;L;<narrow> 30CF;;;;N;;;;;
+FF8B;HALFWIDTH KATAKANA LETTER HI;Lo;0;L;<narrow> 30D2;;;;N;;;;;
+FF8C;HALFWIDTH KATAKANA LETTER HU;Lo;0;L;<narrow> 30D5;;;;N;;;;;
+FF8D;HALFWIDTH KATAKANA LETTER HE;Lo;0;L;<narrow> 30D8;;;;N;;;;;
+FF8E;HALFWIDTH KATAKANA LETTER HO;Lo;0;L;<narrow> 30DB;;;;N;;;;;
+FF8F;HALFWIDTH KATAKANA LETTER MA;Lo;0;L;<narrow> 30DE;;;;N;;;;;
+FF90;HALFWIDTH KATAKANA LETTER MI;Lo;0;L;<narrow> 30DF;;;;N;;;;;
+FF91;HALFWIDTH KATAKANA LETTER MU;Lo;0;L;<narrow> 30E0;;;;N;;;;;
+FF92;HALFWIDTH KATAKANA LETTER ME;Lo;0;L;<narrow> 30E1;;;;N;;;;;
+FF93;HALFWIDTH KATAKANA LETTER MO;Lo;0;L;<narrow> 30E2;;;;N;;;;;
+FF94;HALFWIDTH KATAKANA LETTER YA;Lo;0;L;<narrow> 30E4;;;;N;;;;;
+FF95;HALFWIDTH KATAKANA LETTER YU;Lo;0;L;<narrow> 30E6;;;;N;;;;;
+FF96;HALFWIDTH KATAKANA LETTER YO;Lo;0;L;<narrow> 30E8;;;;N;;;;;
+FF97;HALFWIDTH KATAKANA LETTER RA;Lo;0;L;<narrow> 30E9;;;;N;;;;;
+FF98;HALFWIDTH KATAKANA LETTER RI;Lo;0;L;<narrow> 30EA;;;;N;;;;;
+FF99;HALFWIDTH KATAKANA LETTER RU;Lo;0;L;<narrow> 30EB;;;;N;;;;;
+FF9A;HALFWIDTH KATAKANA LETTER RE;Lo;0;L;<narrow> 30EC;;;;N;;;;;
+FF9B;HALFWIDTH KATAKANA LETTER RO;Lo;0;L;<narrow> 30ED;;;;N;;;;;
+FF9C;HALFWIDTH KATAKANA LETTER WA;Lo;0;L;<narrow> 30EF;;;;N;;;;;
+FF9D;HALFWIDTH KATAKANA LETTER N;Lo;0;L;<narrow> 30F3;;;;N;;;;;
+FF9E;HALFWIDTH KATAKANA VOICED SOUND MARK;Lm;0;L;<narrow> 3099;;;;N;;halfwidth katakana-hiragana voiced sound mark;;;
+FF9F;HALFWIDTH KATAKANA SEMI-VOICED SOUND MARK;Lm;0;L;<narrow> 309A;;;;N;;halfwidth katakana-hiragana semi-voiced sound mark;;;
+FFA0;HALFWIDTH HANGUL FILLER;Lo;0;L;<narrow> 3164;;;;N;HALFWIDTH HANGUL CAE OM;;;;
+FFA1;HALFWIDTH HANGUL LETTER KIYEOK;Lo;0;L;<narrow> 3131;;;;N;HALFWIDTH HANGUL LETTER GIYEOG;;;;
+FFA2;HALFWIDTH HANGUL LETTER SSANGKIYEOK;Lo;0;L;<narrow> 3132;;;;N;HALFWIDTH HANGUL LETTER SSANG GIYEOG;;;;
+FFA3;HALFWIDTH HANGUL LETTER KIYEOK-SIOS;Lo;0;L;<narrow> 3133;;;;N;HALFWIDTH HANGUL LETTER GIYEOG SIOS;;;;
+FFA4;HALFWIDTH HANGUL LETTER NIEUN;Lo;0;L;<narrow> 3134;;;;N;;;;;
+FFA5;HALFWIDTH HANGUL LETTER NIEUN-CIEUC;Lo;0;L;<narrow> 3135;;;;N;HALFWIDTH HANGUL LETTER NIEUN JIEUJ;;;;
+FFA6;HALFWIDTH HANGUL LETTER NIEUN-HIEUH;Lo;0;L;<narrow> 3136;;;;N;HALFWIDTH HANGUL LETTER NIEUN HIEUH;;;;
+FFA7;HALFWIDTH HANGUL LETTER TIKEUT;Lo;0;L;<narrow> 3137;;;;N;HALFWIDTH HANGUL LETTER DIGEUD;;;;
+FFA8;HALFWIDTH HANGUL LETTER SSANGTIKEUT;Lo;0;L;<narrow> 3138;;;;N;HALFWIDTH HANGUL LETTER SSANG DIGEUD;;;;
+FFA9;HALFWIDTH HANGUL LETTER RIEUL;Lo;0;L;<narrow> 3139;;;;N;HALFWIDTH HANGUL LETTER LIEUL;;;;
+FFAA;HALFWIDTH HANGUL LETTER RIEUL-KIYEOK;Lo;0;L;<narrow> 313A;;;;N;HALFWIDTH HANGUL LETTER LIEUL GIYEOG;;;;
+FFAB;HALFWIDTH HANGUL LETTER RIEUL-MIEUM;Lo;0;L;<narrow> 313B;;;;N;HALFWIDTH HANGUL LETTER LIEUL MIEUM;;;;
+FFAC;HALFWIDTH HANGUL LETTER RIEUL-PIEUP;Lo;0;L;<narrow> 313C;;;;N;HALFWIDTH HANGUL LETTER LIEUL BIEUB;;;;
+FFAD;HALFWIDTH HANGUL LETTER RIEUL-SIOS;Lo;0;L;<narrow> 313D;;;;N;HALFWIDTH HANGUL LETTER LIEUL SIOS;;;;
+FFAE;HALFWIDTH HANGUL LETTER RIEUL-THIEUTH;Lo;0;L;<narrow> 313E;;;;N;HALFWIDTH HANGUL LETTER LIEUL TIEUT;;;;
+FFAF;HALFWIDTH HANGUL LETTER RIEUL-PHIEUPH;Lo;0;L;<narrow> 313F;;;;N;HALFWIDTH HANGUL LETTER LIEUL PIEUP;;;;
+FFB0;HALFWIDTH HANGUL LETTER RIEUL-HIEUH;Lo;0;L;<narrow> 3140;;;;N;HALFWIDTH HANGUL LETTER LIEUL HIEUH;;;;
+FFB1;HALFWIDTH HANGUL LETTER MIEUM;Lo;0;L;<narrow> 3141;;;;N;;;;;
+FFB2;HALFWIDTH HANGUL LETTER PIEUP;Lo;0;L;<narrow> 3142;;;;N;HALFWIDTH HANGUL LETTER BIEUB;;;;
+FFB3;HALFWIDTH HANGUL LETTER SSANGPIEUP;Lo;0;L;<narrow> 3143;;;;N;HALFWIDTH HANGUL LETTER SSANG BIEUB;;;;
+FFB4;HALFWIDTH HANGUL LETTER PIEUP-SIOS;Lo;0;L;<narrow> 3144;;;;N;HALFWIDTH HANGUL LETTER BIEUB SIOS;;;;
+FFB5;HALFWIDTH HANGUL LETTER SIOS;Lo;0;L;<narrow> 3145;;;;N;;;;;
+FFB6;HALFWIDTH HANGUL LETTER SSANGSIOS;Lo;0;L;<narrow> 3146;;;;N;HALFWIDTH HANGUL LETTER SSANG SIOS;;;;
+FFB7;HALFWIDTH HANGUL LETTER IEUNG;Lo;0;L;<narrow> 3147;;;;N;;;;;
+FFB8;HALFWIDTH HANGUL LETTER CIEUC;Lo;0;L;<narrow> 3148;;;;N;HALFWIDTH HANGUL LETTER JIEUJ;;;;
+FFB9;HALFWIDTH HANGUL LETTER SSANGCIEUC;Lo;0;L;<narrow> 3149;;;;N;HALFWIDTH HANGUL LETTER SSANG JIEUJ;;;;
+FFBA;HALFWIDTH HANGUL LETTER CHIEUCH;Lo;0;L;<narrow> 314A;;;;N;HALFWIDTH HANGUL LETTER CIEUC;;;;
+FFBB;HALFWIDTH HANGUL LETTER KHIEUKH;Lo;0;L;<narrow> 314B;;;;N;HALFWIDTH HANGUL LETTER KIYEOK;;;;
+FFBC;HALFWIDTH HANGUL LETTER THIEUTH;Lo;0;L;<narrow> 314C;;;;N;HALFWIDTH HANGUL LETTER TIEUT;;;;
+FFBD;HALFWIDTH HANGUL LETTER PHIEUPH;Lo;0;L;<narrow> 314D;;;;N;HALFWIDTH HANGUL LETTER PIEUP;;;;
+FFBE;HALFWIDTH HANGUL LETTER HIEUH;Lo;0;L;<narrow> 314E;;;;N;;;;;
+FFC2;HALFWIDTH HANGUL LETTER A;Lo;0;L;<narrow> 314F;;;;N;;;;;
+FFC3;HALFWIDTH HANGUL LETTER AE;Lo;0;L;<narrow> 3150;;;;N;;;;;
+FFC4;HALFWIDTH HANGUL LETTER YA;Lo;0;L;<narrow> 3151;;;;N;;;;;
+FFC5;HALFWIDTH HANGUL LETTER YAE;Lo;0;L;<narrow> 3152;;;;N;;;;;
+FFC6;HALFWIDTH HANGUL LETTER EO;Lo;0;L;<narrow> 3153;;;;N;;;;;
+FFC7;HALFWIDTH HANGUL LETTER E;Lo;0;L;<narrow> 3154;;;;N;;;;;
+FFCA;HALFWIDTH HANGUL LETTER YEO;Lo;0;L;<narrow> 3155;;;;N;;;;;
+FFCB;HALFWIDTH HANGUL LETTER YE;Lo;0;L;<narrow> 3156;;;;N;;;;;
+FFCC;HALFWIDTH HANGUL LETTER O;Lo;0;L;<narrow> 3157;;;;N;;;;;
+FFCD;HALFWIDTH HANGUL LETTER WA;Lo;0;L;<narrow> 3158;;;;N;;;;;
+FFCE;HALFWIDTH HANGUL LETTER WAE;Lo;0;L;<narrow> 3159;;;;N;;;;;
+FFCF;HALFWIDTH HANGUL LETTER OE;Lo;0;L;<narrow> 315A;;;;N;;;;;
+FFD2;HALFWIDTH HANGUL LETTER YO;Lo;0;L;<narrow> 315B;;;;N;;;;;
+FFD3;HALFWIDTH HANGUL LETTER U;Lo;0;L;<narrow> 315C;;;;N;;;;;
+FFD4;HALFWIDTH HANGUL LETTER WEO;Lo;0;L;<narrow> 315D;;;;N;;;;;
+FFD5;HALFWIDTH HANGUL LETTER WE;Lo;0;L;<narrow> 315E;;;;N;;;;;
+FFD6;HALFWIDTH HANGUL LETTER WI;Lo;0;L;<narrow> 315F;;;;N;;;;;
+FFD7;HALFWIDTH HANGUL LETTER YU;Lo;0;L;<narrow> 3160;;;;N;;;;;
+FFDA;HALFWIDTH HANGUL LETTER EU;Lo;0;L;<narrow> 3161;;;;N;;;;;
+FFDB;HALFWIDTH HANGUL LETTER YI;Lo;0;L;<narrow> 3162;;;;N;;;;;
+FFDC;HALFWIDTH HANGUL LETTER I;Lo;0;L;<narrow> 3163;;;;N;;;;;
+FFE0;FULLWIDTH CENT SIGN;Sc;0;ET;<wide> 00A2;;;;N;;;;;
+FFE1;FULLWIDTH POUND SIGN;Sc;0;ET;<wide> 00A3;;;;N;;;;;
+FFE2;FULLWIDTH NOT SIGN;Sm;0;ON;<wide> 00AC;;;;N;;;;;
+FFE3;FULLWIDTH MACRON;Sk;0;ON;<wide> 00AF;;;;N;FULLWIDTH SPACING MACRON;*;;;
+FFE4;FULLWIDTH BROKEN BAR;So;0;ON;<wide> 00A6;;;;N;FULLWIDTH BROKEN VERTICAL BAR;;;;
+FFE5;FULLWIDTH YEN SIGN;Sc;0;ET;<wide> 00A5;;;;N;;;;;
+FFE6;FULLWIDTH WON SIGN;Sc;0;ET;<wide> 20A9;;;;N;;;;;
+FFE8;HALFWIDTH FORMS LIGHT VERTICAL;So;0;ON;<narrow> 2502;;;;N;;;;;
+FFE9;HALFWIDTH LEFTWARDS ARROW;Sm;0;ON;<narrow> 2190;;;;N;;;;;
+FFEA;HALFWIDTH UPWARDS ARROW;Sm;0;ON;<narrow> 2191;;;;N;;;;;
+FFEB;HALFWIDTH RIGHTWARDS ARROW;Sm;0;ON;<narrow> 2192;;;;N;;;;;
+FFEC;HALFWIDTH DOWNWARDS ARROW;Sm;0;ON;<narrow> 2193;;;;N;;;;;
+FFED;HALFWIDTH BLACK SQUARE;So;0;ON;<narrow> 25A0;;;;N;;;;;
+FFEE;HALFWIDTH WHITE CIRCLE;So;0;ON;<narrow> 25CB;;;;N;;;;;
+FFF9;INTERLINEAR ANNOTATION ANCHOR;Cf;0;ON;;;;;N;;;;;
+FFFA;INTERLINEAR ANNOTATION SEPARATOR;Cf;0;ON;;;;;N;;;;;
+FFFB;INTERLINEAR ANNOTATION TERMINATOR;Cf;0;ON;;;;;N;;;;;
+FFFC;OBJECT REPLACEMENT CHARACTER;So;0;ON;;;;;N;;;;;
+FFFD;REPLACEMENT CHARACTER;So;0;ON;;;;;N;;;;;
+10000;LINEAR B SYLLABLE B008 A;Lo;0;L;;;;;N;;;;;
+10001;LINEAR B SYLLABLE B038 E;Lo;0;L;;;;;N;;;;;
+10002;LINEAR B SYLLABLE B028 I;Lo;0;L;;;;;N;;;;;
+10003;LINEAR B SYLLABLE B061 O;Lo;0;L;;;;;N;;;;;
+10004;LINEAR B SYLLABLE B010 U;Lo;0;L;;;;;N;;;;;
+10005;LINEAR B SYLLABLE B001 DA;Lo;0;L;;;;;N;;;;;
+10006;LINEAR B SYLLABLE B045 DE;Lo;0;L;;;;;N;;;;;
+10007;LINEAR B SYLLABLE B007 DI;Lo;0;L;;;;;N;;;;;
+10008;LINEAR B SYLLABLE B014 DO;Lo;0;L;;;;;N;;;;;
+10009;LINEAR B SYLLABLE B051 DU;Lo;0;L;;;;;N;;;;;
+1000A;LINEAR B SYLLABLE B057 JA;Lo;0;L;;;;;N;;;;;
+1000B;LINEAR B SYLLABLE B046 JE;Lo;0;L;;;;;N;;;;;
+1000D;LINEAR B SYLLABLE B036 JO;Lo;0;L;;;;;N;;;;;
+1000E;LINEAR B SYLLABLE B065 JU;Lo;0;L;;;;;N;;;;;
+1000F;LINEAR B SYLLABLE B077 KA;Lo;0;L;;;;;N;;;;;
+10010;LINEAR B SYLLABLE B044 KE;Lo;0;L;;;;;N;;;;;
+10011;LINEAR B SYLLABLE B067 KI;Lo;0;L;;;;;N;;;;;
+10012;LINEAR B SYLLABLE B070 KO;Lo;0;L;;;;;N;;;;;
+10013;LINEAR B SYLLABLE B081 KU;Lo;0;L;;;;;N;;;;;
+10014;LINEAR B SYLLABLE B080 MA;Lo;0;L;;;;;N;;;;;
+10015;LINEAR B SYLLABLE B013 ME;Lo;0;L;;;;;N;;;;;
+10016;LINEAR B SYLLABLE B073 MI;Lo;0;L;;;;;N;;;;;
+10017;LINEAR B SYLLABLE B015 MO;Lo;0;L;;;;;N;;;;;
+10018;LINEAR B SYLLABLE B023 MU;Lo;0;L;;;;;N;;;;;
+10019;LINEAR B SYLLABLE B006 NA;Lo;0;L;;;;;N;;;;;
+1001A;LINEAR B SYLLABLE B024 NE;Lo;0;L;;;;;N;;;;;
+1001B;LINEAR B SYLLABLE B030 NI;Lo;0;L;;;;;N;;;;;
+1001C;LINEAR B SYLLABLE B052 NO;Lo;0;L;;;;;N;;;;;
+1001D;LINEAR B SYLLABLE B055 NU;Lo;0;L;;;;;N;;;;;
+1001E;LINEAR B SYLLABLE B003 PA;Lo;0;L;;;;;N;;;;;
+1001F;LINEAR B SYLLABLE B072 PE;Lo;0;L;;;;;N;;;;;
+10020;LINEAR B SYLLABLE B039 PI;Lo;0;L;;;;;N;;;;;
+10021;LINEAR B SYLLABLE B011 PO;Lo;0;L;;;;;N;;;;;
+10022;LINEAR B SYLLABLE B050 PU;Lo;0;L;;;;;N;;;;;
+10023;LINEAR B SYLLABLE B016 QA;Lo;0;L;;;;;N;;;;;
+10024;LINEAR B SYLLABLE B078 QE;Lo;0;L;;;;;N;;;;;
+10025;LINEAR B SYLLABLE B021 QI;Lo;0;L;;;;;N;;;;;
+10026;LINEAR B SYLLABLE B032 QO;Lo;0;L;;;;;N;;;;;
+10028;LINEAR B SYLLABLE B060 RA;Lo;0;L;;;;;N;;;;;
+10029;LINEAR B SYLLABLE B027 RE;Lo;0;L;;;;;N;;;;;
+1002A;LINEAR B SYLLABLE B053 RI;Lo;0;L;;;;;N;;;;;
+1002B;LINEAR B SYLLABLE B002 RO;Lo;0;L;;;;;N;;;;;
+1002C;LINEAR B SYLLABLE B026 RU;Lo;0;L;;;;;N;;;;;
+1002D;LINEAR B SYLLABLE B031 SA;Lo;0;L;;;;;N;;;;;
+1002E;LINEAR B SYLLABLE B009 SE;Lo;0;L;;;;;N;;;;;
+1002F;LINEAR B SYLLABLE B041 SI;Lo;0;L;;;;;N;;;;;
+10030;LINEAR B SYLLABLE B012 SO;Lo;0;L;;;;;N;;;;;
+10031;LINEAR B SYLLABLE B058 SU;Lo;0;L;;;;;N;;;;;
+10032;LINEAR B SYLLABLE B059 TA;Lo;0;L;;;;;N;;;;;
+10033;LINEAR B SYLLABLE B004 TE;Lo;0;L;;;;;N;;;;;
+10034;LINEAR B SYLLABLE B037 TI;Lo;0;L;;;;;N;;;;;
+10035;LINEAR B SYLLABLE B005 TO;Lo;0;L;;;;;N;;;;;
+10036;LINEAR B SYLLABLE B069 TU;Lo;0;L;;;;;N;;;;;
+10037;LINEAR B SYLLABLE B054 WA;Lo;0;L;;;;;N;;;;;
+10038;LINEAR B SYLLABLE B075 WE;Lo;0;L;;;;;N;;;;;
+10039;LINEAR B SYLLABLE B040 WI;Lo;0;L;;;;;N;;;;;
+1003A;LINEAR B SYLLABLE B042 WO;Lo;0;L;;;;;N;;;;;
+1003C;LINEAR B SYLLABLE B017 ZA;Lo;0;L;;;;;N;;;;;
+1003D;LINEAR B SYLLABLE B074 ZE;Lo;0;L;;;;;N;;;;;
+1003F;LINEAR B SYLLABLE B020 ZO;Lo;0;L;;;;;N;;;;;
+10040;LINEAR B SYLLABLE B025 A2;Lo;0;L;;;;;N;;;;;
+10041;LINEAR B SYLLABLE B043 A3;Lo;0;L;;;;;N;;;;;
+10042;LINEAR B SYLLABLE B085 AU;Lo;0;L;;;;;N;;;;;
+10043;LINEAR B SYLLABLE B071 DWE;Lo;0;L;;;;;N;;;;;
+10044;LINEAR B SYLLABLE B090 DWO;Lo;0;L;;;;;N;;;;;
+10045;LINEAR B SYLLABLE B048 NWA;Lo;0;L;;;;;N;;;;;
+10046;LINEAR B SYLLABLE B029 PU2;Lo;0;L;;;;;N;;;;;
+10047;LINEAR B SYLLABLE B062 PTE;Lo;0;L;;;;;N;;;;;
+10048;LINEAR B SYLLABLE B076 RA2;Lo;0;L;;;;;N;;;;;
+10049;LINEAR B SYLLABLE B033 RA3;Lo;0;L;;;;;N;;;;;
+1004A;LINEAR B SYLLABLE B068 RO2;Lo;0;L;;;;;N;;;;;
+1004B;LINEAR B SYLLABLE B066 TA2;Lo;0;L;;;;;N;;;;;
+1004C;LINEAR B SYLLABLE B087 TWE;Lo;0;L;;;;;N;;;;;
+1004D;LINEAR B SYLLABLE B091 TWO;Lo;0;L;;;;;N;;;;;
+10050;LINEAR B SYMBOL B018;Lo;0;L;;;;;N;;;;;
+10051;LINEAR B SYMBOL B019;Lo;0;L;;;;;N;;;;;
+10052;LINEAR B SYMBOL B022;Lo;0;L;;;;;N;;;;;
+10053;LINEAR B SYMBOL B034;Lo;0;L;;;;;N;;;;;
+10054;LINEAR B SYMBOL B047;Lo;0;L;;;;;N;;;;;
+10055;LINEAR B SYMBOL B049;Lo;0;L;;;;;N;;;;;
+10056;LINEAR B SYMBOL B056;Lo;0;L;;;;;N;;;;;
+10057;LINEAR B SYMBOL B063;Lo;0;L;;;;;N;;;;;
+10058;LINEAR B SYMBOL B064;Lo;0;L;;;;;N;;;;;
+10059;LINEAR B SYMBOL B079;Lo;0;L;;;;;N;;;;;
+1005A;LINEAR B SYMBOL B082;Lo;0;L;;;;;N;;;;;
+1005B;LINEAR B SYMBOL B083;Lo;0;L;;;;;N;;;;;
+1005C;LINEAR B SYMBOL B086;Lo;0;L;;;;;N;;;;;
+1005D;LINEAR B SYMBOL B089;Lo;0;L;;;;;N;;;;;
+10080;LINEAR B IDEOGRAM B100 MAN;Lo;0;L;;;;;N;;;;;
+10081;LINEAR B IDEOGRAM B102 WOMAN;Lo;0;L;;;;;N;;;;;
+10082;LINEAR B IDEOGRAM B104 DEER;Lo;0;L;;;;;N;;;;;
+10083;LINEAR B IDEOGRAM B105 EQUID;Lo;0;L;;;;;N;;;;;
+10084;LINEAR B IDEOGRAM B105F MARE;Lo;0;L;;;;;N;;;;;
+10085;LINEAR B IDEOGRAM B105M STALLION;Lo;0;L;;;;;N;;;;;
+10086;LINEAR B IDEOGRAM B106F EWE;Lo;0;L;;;;;N;;;;;
+10087;LINEAR B IDEOGRAM B106M RAM;Lo;0;L;;;;;N;;;;;
+10088;LINEAR B IDEOGRAM B107F SHE-GOAT;Lo;0;L;;;;;N;;;;;
+10089;LINEAR B IDEOGRAM B107M HE-GOAT;Lo;0;L;;;;;N;;;;;
+1008A;LINEAR B IDEOGRAM B108F SOW;Lo;0;L;;;;;N;;;;;
+1008B;LINEAR B IDEOGRAM B108M BOAR;Lo;0;L;;;;;N;;;;;
+1008C;LINEAR B IDEOGRAM B109F COW;Lo;0;L;;;;;N;;;;;
+1008D;LINEAR B IDEOGRAM B109M BULL;Lo;0;L;;;;;N;;;;;
+1008E;LINEAR B IDEOGRAM B120 WHEAT;Lo;0;L;;;;;N;;;;;
+1008F;LINEAR B IDEOGRAM B121 BARLEY;Lo;0;L;;;;;N;;;;;
+10090;LINEAR B IDEOGRAM B122 OLIVE;Lo;0;L;;;;;N;;;;;
+10091;LINEAR B IDEOGRAM B123 SPICE;Lo;0;L;;;;;N;;;;;
+10092;LINEAR B IDEOGRAM B125 CYPERUS;Lo;0;L;;;;;N;;;;;
+10093;LINEAR B MONOGRAM B127 KAPO;Lo;0;L;;;;;N;;;;;
+10094;LINEAR B MONOGRAM B128 KANAKO;Lo;0;L;;;;;N;;;;;
+10095;LINEAR B IDEOGRAM B130 OIL;Lo;0;L;;;;;N;;;;;
+10096;LINEAR B IDEOGRAM B131 WINE;Lo;0;L;;;;;N;;;;;
+10097;LINEAR B IDEOGRAM B132;Lo;0;L;;;;;N;;;;;
+10098;LINEAR B MONOGRAM B133 AREPA;Lo;0;L;;;;;N;;;;;
+10099;LINEAR B MONOGRAM B135 MERI;Lo;0;L;;;;;N;;;;;
+1009A;LINEAR B IDEOGRAM B140 BRONZE;Lo;0;L;;;;;N;;;;;
+1009B;LINEAR B IDEOGRAM B141 GOLD;Lo;0;L;;;;;N;;;;;
+1009C;LINEAR B IDEOGRAM B142;Lo;0;L;;;;;N;;;;;
+1009D;LINEAR B IDEOGRAM B145 WOOL;Lo;0;L;;;;;N;;;;;
+1009E;LINEAR B IDEOGRAM B146;Lo;0;L;;;;;N;;;;;
+1009F;LINEAR B IDEOGRAM B150;Lo;0;L;;;;;N;;;;;
+100A0;LINEAR B IDEOGRAM B151 HORN;Lo;0;L;;;;;N;;;;;
+100A1;LINEAR B IDEOGRAM B152;Lo;0;L;;;;;N;;;;;
+100A2;LINEAR B IDEOGRAM B153;Lo;0;L;;;;;N;;;;;
+100A3;LINEAR B IDEOGRAM B154;Lo;0;L;;;;;N;;;;;
+100A4;LINEAR B MONOGRAM B156 TURO2;Lo;0;L;;;;;N;;;;;
+100A5;LINEAR B IDEOGRAM B157;Lo;0;L;;;;;N;;;;;
+100A6;LINEAR B IDEOGRAM B158;Lo;0;L;;;;;N;;;;;
+100A7;LINEAR B IDEOGRAM B159 CLOTH;Lo;0;L;;;;;N;;;;;
+100A8;LINEAR B IDEOGRAM B160;Lo;0;L;;;;;N;;;;;
+100A9;LINEAR B IDEOGRAM B161;Lo;0;L;;;;;N;;;;;
+100AA;LINEAR B IDEOGRAM B162 GARMENT;Lo;0;L;;;;;N;;;;;
+100AB;LINEAR B IDEOGRAM B163 ARMOUR;Lo;0;L;;;;;N;;;;;
+100AC;LINEAR B IDEOGRAM B164;Lo;0;L;;;;;N;;;;;
+100AD;LINEAR B IDEOGRAM B165;Lo;0;L;;;;;N;;;;;
+100AE;LINEAR B IDEOGRAM B166;Lo;0;L;;;;;N;;;;;
+100AF;LINEAR B IDEOGRAM B167;Lo;0;L;;;;;N;;;;;
+100B0;LINEAR B IDEOGRAM B168;Lo;0;L;;;;;N;;;;;
+100B1;LINEAR B IDEOGRAM B169;Lo;0;L;;;;;N;;;;;
+100B2;LINEAR B IDEOGRAM B170;Lo;0;L;;;;;N;;;;;
+100B3;LINEAR B IDEOGRAM B171;Lo;0;L;;;;;N;;;;;
+100B4;LINEAR B IDEOGRAM B172;Lo;0;L;;;;;N;;;;;
+100B5;LINEAR B IDEOGRAM B173 MONTH;Lo;0;L;;;;;N;;;;;
+100B6;LINEAR B IDEOGRAM B174;Lo;0;L;;;;;N;;;;;
+100B7;LINEAR B IDEOGRAM B176 TREE;Lo;0;L;;;;;N;;;;;
+100B8;LINEAR B IDEOGRAM B177;Lo;0;L;;;;;N;;;;;
+100B9;LINEAR B IDEOGRAM B178;Lo;0;L;;;;;N;;;;;
+100BA;LINEAR B IDEOGRAM B179;Lo;0;L;;;;;N;;;;;
+100BB;LINEAR B IDEOGRAM B180;Lo;0;L;;;;;N;;;;;
+100BC;LINEAR B IDEOGRAM B181;Lo;0;L;;;;;N;;;;;
+100BD;LINEAR B IDEOGRAM B182;Lo;0;L;;;;;N;;;;;
+100BE;LINEAR B IDEOGRAM B183;Lo;0;L;;;;;N;;;;;
+100BF;LINEAR B IDEOGRAM B184;Lo;0;L;;;;;N;;;;;
+100C0;LINEAR B IDEOGRAM B185;Lo;0;L;;;;;N;;;;;
+100C1;LINEAR B IDEOGRAM B189;Lo;0;L;;;;;N;;;;;
+100C2;LINEAR B IDEOGRAM B190;Lo;0;L;;;;;N;;;;;
+100C3;LINEAR B IDEOGRAM B191 HELMET;Lo;0;L;;;;;N;;;;;
+100C4;LINEAR B IDEOGRAM B220 FOOTSTOOL;Lo;0;L;;;;;N;;;;;
+100C5;LINEAR B IDEOGRAM B225 BATHTUB;Lo;0;L;;;;;N;;;;;
+100C6;LINEAR B IDEOGRAM B230 SPEAR;Lo;0;L;;;;;N;;;;;
+100C7;LINEAR B IDEOGRAM B231 ARROW;Lo;0;L;;;;;N;;;;;
+100C8;LINEAR B IDEOGRAM B232;Lo;0;L;;;;;N;;;;;
+100C9;LINEAR B IDEOGRAM B233 SWORD;Lo;0;L;;;;;N;;pug;;;
+100CA;LINEAR B IDEOGRAM B234;Lo;0;L;;;;;N;;;;;
+100CB;LINEAR B IDEOGRAM B236;Lo;0;L;;;;;N;;gup;;;
+100CC;LINEAR B IDEOGRAM B240 WHEELED CHARIOT;Lo;0;L;;;;;N;;;;;
+100CD;LINEAR B IDEOGRAM B241 CHARIOT;Lo;0;L;;;;;N;;;;;
+100CE;LINEAR B IDEOGRAM B242 CHARIOT FRAME;Lo;0;L;;;;;N;;;;;
+100CF;LINEAR B IDEOGRAM B243 WHEEL;Lo;0;L;;;;;N;;;;;
+100D0;LINEAR B IDEOGRAM B245;Lo;0;L;;;;;N;;;;;
+100D1;LINEAR B IDEOGRAM B246;Lo;0;L;;;;;N;;;;;
+100D2;LINEAR B MONOGRAM B247 DIPTE;Lo;0;L;;;;;N;;;;;
+100D3;LINEAR B IDEOGRAM B248;Lo;0;L;;;;;N;;;;;
+100D4;LINEAR B IDEOGRAM B249;Lo;0;L;;;;;N;;;;;
+100D5;LINEAR B IDEOGRAM B251;Lo;0;L;;;;;N;;;;;
+100D6;LINEAR B IDEOGRAM B252;Lo;0;L;;;;;N;;;;;
+100D7;LINEAR B IDEOGRAM B253;Lo;0;L;;;;;N;;;;;
+100D8;LINEAR B IDEOGRAM B254 DART;Lo;0;L;;;;;N;;;;;
+100D9;LINEAR B IDEOGRAM B255;Lo;0;L;;;;;N;;;;;
+100DA;LINEAR B IDEOGRAM B256;Lo;0;L;;;;;N;;;;;
+100DB;LINEAR B IDEOGRAM B257;Lo;0;L;;;;;N;;;;;
+100DC;LINEAR B IDEOGRAM B258;Lo;0;L;;;;;N;;;;;
+100DD;LINEAR B IDEOGRAM B259;Lo;0;L;;;;;N;;;;;
+100DE;LINEAR B IDEOGRAM VESSEL B155;Lo;0;L;;;;;N;;;;;
+100DF;LINEAR B IDEOGRAM VESSEL B200;Lo;0;L;;;;;N;;;;;
+100E0;LINEAR B IDEOGRAM VESSEL B201;Lo;0;L;;;;;N;;;;;
+100E1;LINEAR B IDEOGRAM VESSEL B202;Lo;0;L;;;;;N;;;;;
+100E2;LINEAR B IDEOGRAM VESSEL B203;Lo;0;L;;;;;N;;;;;
+100E3;LINEAR B IDEOGRAM VESSEL B204;Lo;0;L;;;;;N;;;;;
+100E4;LINEAR B IDEOGRAM VESSEL B205;Lo;0;L;;;;;N;;;;;
+100E5;LINEAR B IDEOGRAM VESSEL B206;Lo;0;L;;;;;N;;;;;
+100E6;LINEAR B IDEOGRAM VESSEL B207;Lo;0;L;;;;;N;;;;;
+100E7;LINEAR B IDEOGRAM VESSEL B208;Lo;0;L;;;;;N;;;;;
+100E8;LINEAR B IDEOGRAM VESSEL B209;Lo;0;L;;;;;N;;;;;
+100E9;LINEAR B IDEOGRAM VESSEL B210;Lo;0;L;;;;;N;;;;;
+100EA;LINEAR B IDEOGRAM VESSEL B211;Lo;0;L;;;;;N;;;;;
+100EB;LINEAR B IDEOGRAM VESSEL B212;Lo;0;L;;;;;N;;;;;
+100EC;LINEAR B IDEOGRAM VESSEL B213;Lo;0;L;;;;;N;;;;;
+100ED;LINEAR B IDEOGRAM VESSEL B214;Lo;0;L;;;;;N;;;;;
+100EE;LINEAR B IDEOGRAM VESSEL B215;Lo;0;L;;;;;N;;;;;
+100EF;LINEAR B IDEOGRAM VESSEL B216;Lo;0;L;;;;;N;;;;;
+100F0;LINEAR B IDEOGRAM VESSEL B217;Lo;0;L;;;;;N;;;;;
+100F1;LINEAR B IDEOGRAM VESSEL B218;Lo;0;L;;;;;N;;;;;
+100F2;LINEAR B IDEOGRAM VESSEL B219;Lo;0;L;;;;;N;;;;;
+100F3;LINEAR B IDEOGRAM VESSEL B221;Lo;0;L;;;;;N;;;;;
+100F4;LINEAR B IDEOGRAM VESSEL B222;Lo;0;L;;;;;N;;;;;
+100F5;LINEAR B IDEOGRAM VESSEL B226;Lo;0;L;;;;;N;;;;;
+100F6;LINEAR B IDEOGRAM VESSEL B227;Lo;0;L;;;;;N;;;;;
+100F7;LINEAR B IDEOGRAM VESSEL B228;Lo;0;L;;;;;N;;;;;
+100F8;LINEAR B IDEOGRAM VESSEL B229;Lo;0;L;;;;;N;;;;;
+100F9;LINEAR B IDEOGRAM VESSEL B250;Lo;0;L;;;;;N;;;;;
+100FA;LINEAR B IDEOGRAM VESSEL B305;Lo;0;L;;;;;N;;;;;
+10100;AEGEAN WORD SEPARATOR LINE;Po;0;L;;;;;N;;;;;
+10101;AEGEAN WORD SEPARATOR DOT;Po;0;ON;;;;;N;;;;;
+10102;AEGEAN CHECK MARK;So;0;L;;;;;N;;;;;
+10107;AEGEAN NUMBER ONE;No;0;L;;;;1;N;;;;;
+10108;AEGEAN NUMBER TWO;No;0;L;;;;2;N;;;;;
+10109;AEGEAN NUMBER THREE;No;0;L;;;;3;N;;;;;
+1010A;AEGEAN NUMBER FOUR;No;0;L;;;;4;N;;;;;
+1010B;AEGEAN NUMBER FIVE;No;0;L;;;;5;N;;;;;
+1010C;AEGEAN NUMBER SIX;No;0;L;;;;6;N;;;;;
+1010D;AEGEAN NUMBER SEVEN;No;0;L;;;;7;N;;;;;
+1010E;AEGEAN NUMBER EIGHT;No;0;L;;;;8;N;;;;;
+1010F;AEGEAN NUMBER NINE;No;0;L;;;;9;N;;;;;
+10110;AEGEAN NUMBER TEN;No;0;L;;;;10;N;;;;;
+10111;AEGEAN NUMBER TWENTY;No;0;L;;;;20;N;;;;;
+10112;AEGEAN NUMBER THIRTY;No;0;L;;;;30;N;;;;;
+10113;AEGEAN NUMBER FORTY;No;0;L;;;;40;N;;;;;
+10114;AEGEAN NUMBER FIFTY;No;0;L;;;;50;N;;;;;
+10115;AEGEAN NUMBER SIXTY;No;0;L;;;;60;N;;;;;
+10116;AEGEAN NUMBER SEVENTY;No;0;L;;;;70;N;;;;;
+10117;AEGEAN NUMBER EIGHTY;No;0;L;;;;80;N;;;;;
+10118;AEGEAN NUMBER NINETY;No;0;L;;;;90;N;;;;;
+10119;AEGEAN NUMBER ONE HUNDRED;No;0;L;;;;100;N;;;;;
+1011A;AEGEAN NUMBER TWO HUNDRED;No;0;L;;;;200;N;;;;;
+1011B;AEGEAN NUMBER THREE HUNDRED;No;0;L;;;;300;N;;;;;
+1011C;AEGEAN NUMBER FOUR HUNDRED;No;0;L;;;;400;N;;;;;
+1011D;AEGEAN NUMBER FIVE HUNDRED;No;0;L;;;;500;N;;;;;
+1011E;AEGEAN NUMBER SIX HUNDRED;No;0;L;;;;600;N;;;;;
+1011F;AEGEAN NUMBER SEVEN HUNDRED;No;0;L;;;;700;N;;;;;
+10120;AEGEAN NUMBER EIGHT HUNDRED;No;0;L;;;;800;N;;;;;
+10121;AEGEAN NUMBER NINE HUNDRED;No;0;L;;;;900;N;;;;;
+10122;AEGEAN NUMBER ONE THOUSAND;No;0;L;;;;1000;N;;;;;
+10123;AEGEAN NUMBER TWO THOUSAND;No;0;L;;;;2000;N;;;;;
+10124;AEGEAN NUMBER THREE THOUSAND;No;0;L;;;;3000;N;;;;;
+10125;AEGEAN NUMBER FOUR THOUSAND;No;0;L;;;;4000;N;;;;;
+10126;AEGEAN NUMBER FIVE THOUSAND;No;0;L;;;;5000;N;;;;;
+10127;AEGEAN NUMBER SIX THOUSAND;No;0;L;;;;6000;N;;;;;
+10128;AEGEAN NUMBER SEVEN THOUSAND;No;0;L;;;;7000;N;;;;;
+10129;AEGEAN NUMBER EIGHT THOUSAND;No;0;L;;;;8000;N;;;;;
+1012A;AEGEAN NUMBER NINE THOUSAND;No;0;L;;;;9000;N;;;;;
+1012B;AEGEAN NUMBER TEN THOUSAND;No;0;L;;;;10000;N;;;;;
+1012C;AEGEAN NUMBER TWENTY THOUSAND;No;0;L;;;;20000;N;;;;;
+1012D;AEGEAN NUMBER THIRTY THOUSAND;No;0;L;;;;30000;N;;;;;
+1012E;AEGEAN NUMBER FORTY THOUSAND;No;0;L;;;;40000;N;;;;;
+1012F;AEGEAN NUMBER FIFTY THOUSAND;No;0;L;;;;50000;N;;;;;
+10130;AEGEAN NUMBER SIXTY THOUSAND;No;0;L;;;;60000;N;;;;;
+10131;AEGEAN NUMBER SEVENTY THOUSAND;No;0;L;;;;70000;N;;;;;
+10132;AEGEAN NUMBER EIGHTY THOUSAND;No;0;L;;;;80000;N;;;;;
+10133;AEGEAN NUMBER NINETY THOUSAND;No;0;L;;;;90000;N;;;;;
+10137;AEGEAN WEIGHT BASE UNIT;So;0;L;;;;;N;;;;;
+10138;AEGEAN WEIGHT FIRST SUBUNIT;So;0;L;;;;;N;;;;;
+10139;AEGEAN WEIGHT SECOND SUBUNIT;So;0;L;;;;;N;;;;;
+1013A;AEGEAN WEIGHT THIRD SUBUNIT;So;0;L;;;;;N;;;;;
+1013B;AEGEAN WEIGHT FOURTH SUBUNIT;So;0;L;;;;;N;;;;;
+1013C;AEGEAN DRY MEASURE FIRST SUBUNIT;So;0;L;;;;;N;;;;;
+1013D;AEGEAN LIQUID MEASURE FIRST SUBUNIT;So;0;L;;;;;N;;;;;
+1013E;AEGEAN MEASURE SECOND SUBUNIT;So;0;L;;;;;N;;;;;
+1013F;AEGEAN MEASURE THIRD SUBUNIT;So;0;L;;;;;N;;;;;
+10140;GREEK ACROPHONIC ATTIC ONE QUARTER;Nl;0;ON;;;;1/4;N;;;;;
+10141;GREEK ACROPHONIC ATTIC ONE HALF;Nl;0;ON;;;;1/2;N;;;;;
+10142;GREEK ACROPHONIC ATTIC ONE DRACHMA;Nl;0;ON;;;;1;N;;;;;
+10143;GREEK ACROPHONIC ATTIC FIVE;Nl;0;ON;;;;5;N;;;;;
+10144;GREEK ACROPHONIC ATTIC FIFTY;Nl;0;ON;;;;50;N;;;;;
+10145;GREEK ACROPHONIC ATTIC FIVE HUNDRED;Nl;0;ON;;;;500;N;;;;;
+10146;GREEK ACROPHONIC ATTIC FIVE THOUSAND;Nl;0;ON;;;;5000;N;;;;;
+10147;GREEK ACROPHONIC ATTIC FIFTY THOUSAND;Nl;0;ON;;;;50000;N;;;;;
+10148;GREEK ACROPHONIC ATTIC FIVE TALENTS;Nl;0;ON;;;;5;N;;;;;
+10149;GREEK ACROPHONIC ATTIC TEN TALENTS;Nl;0;ON;;;;10;N;;;;;
+1014A;GREEK ACROPHONIC ATTIC FIFTY TALENTS;Nl;0;ON;;;;50;N;;;;;
+1014B;GREEK ACROPHONIC ATTIC ONE HUNDRED TALENTS;Nl;0;ON;;;;100;N;;;;;
+1014C;GREEK ACROPHONIC ATTIC FIVE HUNDRED TALENTS;Nl;0;ON;;;;500;N;;;;;
+1014D;GREEK ACROPHONIC ATTIC ONE THOUSAND TALENTS;Nl;0;ON;;;;1000;N;;;;;
+1014E;GREEK ACROPHONIC ATTIC FIVE THOUSAND TALENTS;Nl;0;ON;;;;5000;N;;;;;
+1014F;GREEK ACROPHONIC ATTIC FIVE STATERS;Nl;0;ON;;;;5;N;;;;;
+10150;GREEK ACROPHONIC ATTIC TEN STATERS;Nl;0;ON;;;;10;N;;;;;
+10151;GREEK ACROPHONIC ATTIC FIFTY STATERS;Nl;0;ON;;;;50;N;;;;;
+10152;GREEK ACROPHONIC ATTIC ONE HUNDRED STATERS;Nl;0;ON;;;;100;N;;;;;
+10153;GREEK ACROPHONIC ATTIC FIVE HUNDRED STATERS;Nl;0;ON;;;;500;N;;;;;
+10154;GREEK ACROPHONIC ATTIC ONE THOUSAND STATERS;Nl;0;ON;;;;1000;N;;;;;
+10155;GREEK ACROPHONIC ATTIC TEN THOUSAND STATERS;Nl;0;ON;;;;10000;N;;;;;
+10156;GREEK ACROPHONIC ATTIC FIFTY THOUSAND STATERS;Nl;0;ON;;;;50000;N;;;;;
+10157;GREEK ACROPHONIC ATTIC TEN MNAS;Nl;0;ON;;;;10;N;;;;;
+10158;GREEK ACROPHONIC HERAEUM ONE PLETHRON;Nl;0;ON;;;;1;N;;;;;
+10159;GREEK ACROPHONIC THESPIAN ONE;Nl;0;ON;;;;1;N;;;;;
+1015A;GREEK ACROPHONIC HERMIONIAN ONE;Nl;0;ON;;;;1;N;;;;;
+1015B;GREEK ACROPHONIC EPIDAUREAN TWO;Nl;0;ON;;;;2;N;;;;;
+1015C;GREEK ACROPHONIC THESPIAN TWO;Nl;0;ON;;;;2;N;;;;;
+1015D;GREEK ACROPHONIC CYRENAIC TWO DRACHMAS;Nl;0;ON;;;;2;N;;;;;
+1015E;GREEK ACROPHONIC EPIDAUREAN TWO DRACHMAS;Nl;0;ON;;;;2;N;;;;;
+1015F;GREEK ACROPHONIC TROEZENIAN FIVE;Nl;0;ON;;;;5;N;;;;;
+10160;GREEK ACROPHONIC TROEZENIAN TEN;Nl;0;ON;;;;10;N;;;;;
+10161;GREEK ACROPHONIC TROEZENIAN TEN ALTERNATE FORM;Nl;0;ON;;;;10;N;;;;;
+10162;GREEK ACROPHONIC HERMIONIAN TEN;Nl;0;ON;;;;10;N;;;;;
+10163;GREEK ACROPHONIC MESSENIAN TEN;Nl;0;ON;;;;10;N;;;;;
+10164;GREEK ACROPHONIC THESPIAN TEN;Nl;0;ON;;;;10;N;;;;;
+10165;GREEK ACROPHONIC THESPIAN THIRTY;Nl;0;ON;;;;30;N;;;;;
+10166;GREEK ACROPHONIC TROEZENIAN FIFTY;Nl;0;ON;;;;50;N;;;;;
+10167;GREEK ACROPHONIC TROEZENIAN FIFTY ALTERNATE FORM;Nl;0;ON;;;;50;N;;;;;
+10168;GREEK ACROPHONIC HERMIONIAN FIFTY;Nl;0;ON;;;;50;N;;;;;
+10169;GREEK ACROPHONIC THESPIAN FIFTY;Nl;0;ON;;;;50;N;;;;;
+1016A;GREEK ACROPHONIC THESPIAN ONE HUNDRED;Nl;0;ON;;;;100;N;;;;;
+1016B;GREEK ACROPHONIC THESPIAN THREE HUNDRED;Nl;0;ON;;;;300;N;;;;;
+1016C;GREEK ACROPHONIC EPIDAUREAN FIVE HUNDRED;Nl;0;ON;;;;500;N;;;;;
+1016D;GREEK ACROPHONIC TROEZENIAN FIVE HUNDRED;Nl;0;ON;;;;500;N;;;;;
+1016E;GREEK ACROPHONIC THESPIAN FIVE HUNDRED;Nl;0;ON;;;;500;N;;;;;
+1016F;GREEK ACROPHONIC CARYSTIAN FIVE HUNDRED;Nl;0;ON;;;;500;N;;;;;
+10170;GREEK ACROPHONIC NAXIAN FIVE HUNDRED;Nl;0;ON;;;;500;N;;;;;
+10171;GREEK ACROPHONIC THESPIAN ONE THOUSAND;Nl;0;ON;;;;1000;N;;;;;
+10172;GREEK ACROPHONIC THESPIAN FIVE THOUSAND;Nl;0;ON;;;;5000;N;;;;;
+10173;GREEK ACROPHONIC DELPHIC FIVE MNAS;Nl;0;ON;;;;5;N;;;;;
+10174;GREEK ACROPHONIC STRATIAN FIFTY MNAS;Nl;0;ON;;;;50;N;;;;;
+10175;GREEK ONE HALF SIGN;No;0;ON;;;;1/2;N;;;;;
+10176;GREEK ONE HALF SIGN ALTERNATE FORM;No;0;ON;;;;1/2;N;;;;;
+10177;GREEK TWO THIRDS SIGN;No;0;ON;;;;2/3;N;;;;;
+10178;GREEK THREE QUARTERS SIGN;No;0;ON;;;;3/4;N;;;;;
+10179;GREEK YEAR SIGN;So;0;ON;;;;;N;;;;;
+1017A;GREEK TALENT SIGN;So;0;ON;;;;;N;;;;;
+1017B;GREEK DRACHMA SIGN;So;0;ON;;;;;N;;;;;
+1017C;GREEK OBOL SIGN;So;0;ON;;;;;N;;;;;
+1017D;GREEK TWO OBOLS SIGN;So;0;ON;;;;;N;;;;;
+1017E;GREEK THREE OBOLS SIGN;So;0;ON;;;;;N;;;;;
+1017F;GREEK FOUR OBOLS SIGN;So;0;ON;;;;;N;;;;;
+10180;GREEK FIVE OBOLS SIGN;So;0;ON;;;;;N;;;;;
+10181;GREEK METRETES SIGN;So;0;ON;;;;;N;;;;;
+10182;GREEK KYATHOS BASE SIGN;So;0;ON;;;;;N;;;;;
+10183;GREEK LITRA SIGN;So;0;ON;;;;;N;;;;;
+10184;GREEK OUNKIA SIGN;So;0;ON;;;;;N;;;;;
+10185;GREEK XESTES SIGN;So;0;ON;;;;;N;;;;;
+10186;GREEK ARTABE SIGN;So;0;ON;;;;;N;;;;;
+10187;GREEK AROURA SIGN;So;0;ON;;;;;N;;;;;
+10188;GREEK GRAMMA SIGN;So;0;ON;;;;;N;;;;;
+10189;GREEK TRYBLION BASE SIGN;So;0;ON;;;;;N;;;;;
+1018A;GREEK ZERO SIGN;No;0;ON;;;;0;N;;;;;
+10300;OLD ITALIC LETTER A;Lo;0;L;;;;;N;;;;;
+10301;OLD ITALIC LETTER BE;Lo;0;L;;;;;N;;;;;
+10302;OLD ITALIC LETTER KE;Lo;0;L;;;;;N;;;;;
+10303;OLD ITALIC LETTER DE;Lo;0;L;;;;;N;;;;;
+10304;OLD ITALIC LETTER E;Lo;0;L;;;;;N;;;;;
+10305;OLD ITALIC LETTER VE;Lo;0;L;;;;;N;;;;;
+10306;OLD ITALIC LETTER ZE;Lo;0;L;;;;;N;;;;;
+10307;OLD ITALIC LETTER HE;Lo;0;L;;;;;N;;;;;
+10308;OLD ITALIC LETTER THE;Lo;0;L;;;;;N;;;;;
+10309;OLD ITALIC LETTER I;Lo;0;L;;;;;N;;;;;
+1030A;OLD ITALIC LETTER KA;Lo;0;L;;;;;N;;;;;
+1030B;OLD ITALIC LETTER EL;Lo;0;L;;;;;N;;;;;
+1030C;OLD ITALIC LETTER EM;Lo;0;L;;;;;N;;;;;
+1030D;OLD ITALIC LETTER EN;Lo;0;L;;;;;N;;;;;
+1030E;OLD ITALIC LETTER ESH;Lo;0;L;;;;;N;;;;;
+1030F;OLD ITALIC LETTER O;Lo;0;L;;;;;N;;Faliscan;;;
+10310;OLD ITALIC LETTER PE;Lo;0;L;;;;;N;;;;;
+10311;OLD ITALIC LETTER SHE;Lo;0;L;;;;;N;;;;;
+10312;OLD ITALIC LETTER KU;Lo;0;L;;;;;N;;;;;
+10313;OLD ITALIC LETTER ER;Lo;0;L;;;;;N;;;;;
+10314;OLD ITALIC LETTER ES;Lo;0;L;;;;;N;;;;;
+10315;OLD ITALIC LETTER TE;Lo;0;L;;;;;N;;;;;
+10316;OLD ITALIC LETTER U;Lo;0;L;;;;;N;;;;;
+10317;OLD ITALIC LETTER EKS;Lo;0;L;;;;;N;;Faliscan;;;
+10318;OLD ITALIC LETTER PHE;Lo;0;L;;;;;N;;;;;
+10319;OLD ITALIC LETTER KHE;Lo;0;L;;;;;N;;;;;
+1031A;OLD ITALIC LETTER EF;Lo;0;L;;;;;N;;;;;
+1031B;OLD ITALIC LETTER ERS;Lo;0;L;;;;;N;;Umbrian;;;
+1031C;OLD ITALIC LETTER CHE;Lo;0;L;;;;;N;;Umbrian;;;
+1031D;OLD ITALIC LETTER II;Lo;0;L;;;;;N;;Oscan;;;
+1031E;OLD ITALIC LETTER UU;Lo;0;L;;;;;N;;Oscan;;;
+10320;OLD ITALIC NUMERAL ONE;No;0;L;;;;1;N;;;;;
+10321;OLD ITALIC NUMERAL FIVE;No;0;L;;;;5;N;;;;;
+10322;OLD ITALIC NUMERAL TEN;No;0;L;;;;10;N;;;;;
+10323;OLD ITALIC NUMERAL FIFTY;No;0;L;;;;50;N;;;;;
+10330;GOTHIC LETTER AHSA;Lo;0;L;;;;;N;;;;;
+10331;GOTHIC LETTER BAIRKAN;Lo;0;L;;;;;N;;;;;
+10332;GOTHIC LETTER GIBA;Lo;0;L;;;;;N;;;;;
+10333;GOTHIC LETTER DAGS;Lo;0;L;;;;;N;;;;;
+10334;GOTHIC LETTER AIHVUS;Lo;0;L;;;;;N;;;;;
+10335;GOTHIC LETTER QAIRTHRA;Lo;0;L;;;;;N;;;;;
+10336;GOTHIC LETTER IUJA;Lo;0;L;;;;;N;;;;;
+10337;GOTHIC LETTER HAGL;Lo;0;L;;;;;N;;;;;
+10338;GOTHIC LETTER THIUTH;Lo;0;L;;;;;N;;;;;
+10339;GOTHIC LETTER EIS;Lo;0;L;;;;;N;;;;;
+1033A;GOTHIC LETTER KUSMA;Lo;0;L;;;;;N;;;;;
+1033B;GOTHIC LETTER LAGUS;Lo;0;L;;;;;N;;;;;
+1033C;GOTHIC LETTER MANNA;Lo;0;L;;;;;N;;;;;
+1033D;GOTHIC LETTER NAUTHS;Lo;0;L;;;;;N;;;;;
+1033E;GOTHIC LETTER JER;Lo;0;L;;;;;N;;;;;
+1033F;GOTHIC LETTER URUS;Lo;0;L;;;;;N;;;;;
+10340;GOTHIC LETTER PAIRTHRA;Lo;0;L;;;;;N;;;;;
+10341;GOTHIC LETTER NINETY;Lo;0;L;;;;;N;;;;;
+10342;GOTHIC LETTER RAIDA;Lo;0;L;;;;;N;;;;;
+10343;GOTHIC LETTER SAUIL;Lo;0;L;;;;;N;;;;;
+10344;GOTHIC LETTER TEIWS;Lo;0;L;;;;;N;;;;;
+10345;GOTHIC LETTER WINJA;Lo;0;L;;;;;N;;;;;
+10346;GOTHIC LETTER FAIHU;Lo;0;L;;;;;N;;;;;
+10347;GOTHIC LETTER IGGWS;Lo;0;L;;;;;N;;;;;
+10348;GOTHIC LETTER HWAIR;Lo;0;L;;;;;N;;;;;
+10349;GOTHIC LETTER OTHAL;Lo;0;L;;;;;N;;;;;
+1034A;GOTHIC LETTER NINE HUNDRED;Nl;0;L;;;;900;N;;;;;
+10380;UGARITIC LETTER ALPA;Lo;0;L;;;;;N;;;;;
+10381;UGARITIC LETTER BETA;Lo;0;L;;;;;N;;;;;
+10382;UGARITIC LETTER GAMLA;Lo;0;L;;;;;N;;;;;
+10383;UGARITIC LETTER KHA;Lo;0;L;;;;;N;;;;;
+10384;UGARITIC LETTER DELTA;Lo;0;L;;;;;N;;;;;
+10385;UGARITIC LETTER HO;Lo;0;L;;;;;N;;;;;
+10386;UGARITIC LETTER WO;Lo;0;L;;;;;N;;;;;
+10387;UGARITIC LETTER ZETA;Lo;0;L;;;;;N;;;;;
+10388;UGARITIC LETTER HOTA;Lo;0;L;;;;;N;;;;;
+10389;UGARITIC LETTER TET;Lo;0;L;;;;;N;;;;;
+1038A;UGARITIC LETTER YOD;Lo;0;L;;;;;N;;;;;
+1038B;UGARITIC LETTER KAF;Lo;0;L;;;;;N;;;;;
+1038C;UGARITIC LETTER SHIN;Lo;0;L;;;;;N;;;;;
+1038D;UGARITIC LETTER LAMDA;Lo;0;L;;;;;N;;;;;
+1038E;UGARITIC LETTER MEM;Lo;0;L;;;;;N;;;;;
+1038F;UGARITIC LETTER DHAL;Lo;0;L;;;;;N;;;;;
+10390;UGARITIC LETTER NUN;Lo;0;L;;;;;N;;;;;
+10391;UGARITIC LETTER ZU;Lo;0;L;;;;;N;;;;;
+10392;UGARITIC LETTER SAMKA;Lo;0;L;;;;;N;;;;;
+10393;UGARITIC LETTER AIN;Lo;0;L;;;;;N;;;;;
+10394;UGARITIC LETTER PU;Lo;0;L;;;;;N;;;;;
+10395;UGARITIC LETTER SADE;Lo;0;L;;;;;N;;;;;
+10396;UGARITIC LETTER QOPA;Lo;0;L;;;;;N;;;;;
+10397;UGARITIC LETTER RASHA;Lo;0;L;;;;;N;;;;;
+10398;UGARITIC LETTER THANNA;Lo;0;L;;;;;N;;;;;
+10399;UGARITIC LETTER GHAIN;Lo;0;L;;;;;N;;;;;
+1039A;UGARITIC LETTER TO;Lo;0;L;;;;;N;;;;;
+1039B;UGARITIC LETTER I;Lo;0;L;;;;;N;;;;;
+1039C;UGARITIC LETTER U;Lo;0;L;;;;;N;;;;;
+1039D;UGARITIC LETTER SSU;Lo;0;L;;;;;N;;;;;
+1039F;UGARITIC WORD DIVIDER;Po;0;L;;;;;N;;;;;
+103A0;OLD PERSIAN SIGN A;Lo;0;L;;;;;N;;;;;
+103A1;OLD PERSIAN SIGN I;Lo;0;L;;;;;N;;;;;
+103A2;OLD PERSIAN SIGN U;Lo;0;L;;;;;N;;;;;
+103A3;OLD PERSIAN SIGN KA;Lo;0;L;;;;;N;;;;;
+103A4;OLD PERSIAN SIGN KU;Lo;0;L;;;;;N;;;;;
+103A5;OLD PERSIAN SIGN GA;Lo;0;L;;;;;N;;;;;
+103A6;OLD PERSIAN SIGN GU;Lo;0;L;;;;;N;;;;;
+103A7;OLD PERSIAN SIGN XA;Lo;0;L;;;;;N;;;;;
+103A8;OLD PERSIAN SIGN CA;Lo;0;L;;;;;N;;;;;
+103A9;OLD PERSIAN SIGN JA;Lo;0;L;;;;;N;;;;;
+103AA;OLD PERSIAN SIGN JI;Lo;0;L;;;;;N;;;;;
+103AB;OLD PERSIAN SIGN TA;Lo;0;L;;;;;N;;;;;
+103AC;OLD PERSIAN SIGN TU;Lo;0;L;;;;;N;;;;;
+103AD;OLD PERSIAN SIGN DA;Lo;0;L;;;;;N;;;;;
+103AE;OLD PERSIAN SIGN DI;Lo;0;L;;;;;N;;;;;
+103AF;OLD PERSIAN SIGN DU;Lo;0;L;;;;;N;;;;;
+103B0;OLD PERSIAN SIGN THA;Lo;0;L;;;;;N;;;;;
+103B1;OLD PERSIAN SIGN PA;Lo;0;L;;;;;N;;;;;
+103B2;OLD PERSIAN SIGN BA;Lo;0;L;;;;;N;;;;;
+103B3;OLD PERSIAN SIGN FA;Lo;0;L;;;;;N;;;;;
+103B4;OLD PERSIAN SIGN NA;Lo;0;L;;;;;N;;;;;
+103B5;OLD PERSIAN SIGN NU;Lo;0;L;;;;;N;;;;;
+103B6;OLD PERSIAN SIGN MA;Lo;0;L;;;;;N;;;;;
+103B7;OLD PERSIAN SIGN MI;Lo;0;L;;;;;N;;;;;
+103B8;OLD PERSIAN SIGN MU;Lo;0;L;;;;;N;;;;;
+103B9;OLD PERSIAN SIGN YA;Lo;0;L;;;;;N;;;;;
+103BA;OLD PERSIAN SIGN VA;Lo;0;L;;;;;N;;;;;
+103BB;OLD PERSIAN SIGN VI;Lo;0;L;;;;;N;;;;;
+103BC;OLD PERSIAN SIGN RA;Lo;0;L;;;;;N;;;;;
+103BD;OLD PERSIAN SIGN RU;Lo;0;L;;;;;N;;;;;
+103BE;OLD PERSIAN SIGN LA;Lo;0;L;;;;;N;;;;;
+103BF;OLD PERSIAN SIGN SA;Lo;0;L;;;;;N;;;;;
+103C0;OLD PERSIAN SIGN ZA;Lo;0;L;;;;;N;;;;;
+103C1;OLD PERSIAN SIGN SHA;Lo;0;L;;;;;N;;;;;
+103C2;OLD PERSIAN SIGN SSA;Lo;0;L;;;;;N;;;;;
+103C3;OLD PERSIAN SIGN HA;Lo;0;L;;;;;N;;;;;
+103C8;OLD PERSIAN SIGN AURAMAZDAA;Lo;0;L;;;;;N;;;;;
+103C9;OLD PERSIAN SIGN AURAMAZDAA-2;Lo;0;L;;;;;N;;;;;
+103CA;OLD PERSIAN SIGN AURAMAZDAAHA;Lo;0;L;;;;;N;;;;;
+103CB;OLD PERSIAN SIGN XSHAAYATHIYA;Lo;0;L;;;;;N;;;;;
+103CC;OLD PERSIAN SIGN DAHYAAUSH;Lo;0;L;;;;;N;;;;;
+103CD;OLD PERSIAN SIGN DAHYAAUSH-2;Lo;0;L;;;;;N;;;;;
+103CE;OLD PERSIAN SIGN BAGA;Lo;0;L;;;;;N;;;;;
+103CF;OLD PERSIAN SIGN BUUMISH;Lo;0;L;;;;;N;;;;;
+103D0;OLD PERSIAN WORD DIVIDER;So;0;L;;;;;N;;;;;
+103D1;OLD PERSIAN NUMBER ONE;Nl;0;ON;;;;1;N;;;;;
+103D2;OLD PERSIAN NUMBER TWO;Nl;0;ON;;;;2;N;;;;;
+103D3;OLD PERSIAN NUMBER TEN;Nl;0;ON;;;;10;N;;;;;
+103D4;OLD PERSIAN NUMBER TWENTY;Nl;0;ON;;;;20;N;;;;;
+103D5;OLD PERSIAN NUMBER HUNDRED;Nl;0;ON;;;;100;N;;;;;
+10400;DESERET CAPITAL LETTER LONG I;Lu;0;L;;;;;N;;;;10428;
+10401;DESERET CAPITAL LETTER LONG E;Lu;0;L;;;;;N;;;;10429;
+10402;DESERET CAPITAL LETTER LONG A;Lu;0;L;;;;;N;;;;1042A;
+10403;DESERET CAPITAL LETTER LONG AH;Lu;0;L;;;;;N;;;;1042B;
+10404;DESERET CAPITAL LETTER LONG O;Lu;0;L;;;;;N;;;;1042C;
+10405;DESERET CAPITAL LETTER LONG OO;Lu;0;L;;;;;N;;;;1042D;
+10406;DESERET CAPITAL LETTER SHORT I;Lu;0;L;;;;;N;;;;1042E;
+10407;DESERET CAPITAL LETTER SHORT E;Lu;0;L;;;;;N;;;;1042F;
+10408;DESERET CAPITAL LETTER SHORT A;Lu;0;L;;;;;N;;;;10430;
+10409;DESERET CAPITAL LETTER SHORT AH;Lu;0;L;;;;;N;;;;10431;
+1040A;DESERET CAPITAL LETTER SHORT O;Lu;0;L;;;;;N;;;;10432;
+1040B;DESERET CAPITAL LETTER SHORT OO;Lu;0;L;;;;;N;;;;10433;
+1040C;DESERET CAPITAL LETTER AY;Lu;0;L;;;;;N;;;;10434;
+1040D;DESERET CAPITAL LETTER OW;Lu;0;L;;;;;N;;;;10435;
+1040E;DESERET CAPITAL LETTER WU;Lu;0;L;;;;;N;;;;10436;
+1040F;DESERET CAPITAL LETTER YEE;Lu;0;L;;;;;N;;;;10437;
+10410;DESERET CAPITAL LETTER H;Lu;0;L;;;;;N;;;;10438;
+10411;DESERET CAPITAL LETTER PEE;Lu;0;L;;;;;N;;;;10439;
+10412;DESERET CAPITAL LETTER BEE;Lu;0;L;;;;;N;;;;1043A;
+10413;DESERET CAPITAL LETTER TEE;Lu;0;L;;;;;N;;;;1043B;
+10414;DESERET CAPITAL LETTER DEE;Lu;0;L;;;;;N;;;;1043C;
+10415;DESERET CAPITAL LETTER CHEE;Lu;0;L;;;;;N;;;;1043D;
+10416;DESERET CAPITAL LETTER JEE;Lu;0;L;;;;;N;;;;1043E;
+10417;DESERET CAPITAL LETTER KAY;Lu;0;L;;;;;N;;;;1043F;
+10418;DESERET CAPITAL LETTER GAY;Lu;0;L;;;;;N;;;;10440;
+10419;DESERET CAPITAL LETTER EF;Lu;0;L;;;;;N;;;;10441;
+1041A;DESERET CAPITAL LETTER VEE;Lu;0;L;;;;;N;;;;10442;
+1041B;DESERET CAPITAL LETTER ETH;Lu;0;L;;;;;N;;;;10443;
+1041C;DESERET CAPITAL LETTER THEE;Lu;0;L;;;;;N;;;;10444;
+1041D;DESERET CAPITAL LETTER ES;Lu;0;L;;;;;N;;;;10445;
+1041E;DESERET CAPITAL LETTER ZEE;Lu;0;L;;;;;N;;;;10446;
+1041F;DESERET CAPITAL LETTER ESH;Lu;0;L;;;;;N;;;;10447;
+10420;DESERET CAPITAL LETTER ZHEE;Lu;0;L;;;;;N;;;;10448;
+10421;DESERET CAPITAL LETTER ER;Lu;0;L;;;;;N;;;;10449;
+10422;DESERET CAPITAL LETTER EL;Lu;0;L;;;;;N;;;;1044A;
+10423;DESERET CAPITAL LETTER EM;Lu;0;L;;;;;N;;;;1044B;
+10424;DESERET CAPITAL LETTER EN;Lu;0;L;;;;;N;;;;1044C;
+10425;DESERET CAPITAL LETTER ENG;Lu;0;L;;;;;N;;;;1044D;
+10426;DESERET CAPITAL LETTER OI;Lu;0;L;;;;;N;;;;1044E;
+10427;DESERET CAPITAL LETTER EW;Lu;0;L;;;;;N;;;;1044F;
+10428;DESERET SMALL LETTER LONG I;Ll;0;L;;;;;N;;;10400;;10400
+10429;DESERET SMALL LETTER LONG E;Ll;0;L;;;;;N;;;10401;;10401
+1042A;DESERET SMALL LETTER LONG A;Ll;0;L;;;;;N;;;10402;;10402
+1042B;DESERET SMALL LETTER LONG AH;Ll;0;L;;;;;N;;;10403;;10403
+1042C;DESERET SMALL LETTER LONG O;Ll;0;L;;;;;N;;;10404;;10404
+1042D;DESERET SMALL LETTER LONG OO;Ll;0;L;;;;;N;;;10405;;10405
+1042E;DESERET SMALL LETTER SHORT I;Ll;0;L;;;;;N;;;10406;;10406
+1042F;DESERET SMALL LETTER SHORT E;Ll;0;L;;;;;N;;;10407;;10407
+10430;DESERET SMALL LETTER SHORT A;Ll;0;L;;;;;N;;;10408;;10408
+10431;DESERET SMALL LETTER SHORT AH;Ll;0;L;;;;;N;;;10409;;10409
+10432;DESERET SMALL LETTER SHORT O;Ll;0;L;;;;;N;;;1040A;;1040A
+10433;DESERET SMALL LETTER SHORT OO;Ll;0;L;;;;;N;;;1040B;;1040B
+10434;DESERET SMALL LETTER AY;Ll;0;L;;;;;N;;;1040C;;1040C
+10435;DESERET SMALL LETTER OW;Ll;0;L;;;;;N;;;1040D;;1040D
+10436;DESERET SMALL LETTER WU;Ll;0;L;;;;;N;;;1040E;;1040E
+10437;DESERET SMALL LETTER YEE;Ll;0;L;;;;;N;;;1040F;;1040F
+10438;DESERET SMALL LETTER H;Ll;0;L;;;;;N;;;10410;;10410
+10439;DESERET SMALL LETTER PEE;Ll;0;L;;;;;N;;;10411;;10411
+1043A;DESERET SMALL LETTER BEE;Ll;0;L;;;;;N;;;10412;;10412
+1043B;DESERET SMALL LETTER TEE;Ll;0;L;;;;;N;;;10413;;10413
+1043C;DESERET SMALL LETTER DEE;Ll;0;L;;;;;N;;;10414;;10414
+1043D;DESERET SMALL LETTER CHEE;Ll;0;L;;;;;N;;;10415;;10415
+1043E;DESERET SMALL LETTER JEE;Ll;0;L;;;;;N;;;10416;;10416
+1043F;DESERET SMALL LETTER KAY;Ll;0;L;;;;;N;;;10417;;10417
+10440;DESERET SMALL LETTER GAY;Ll;0;L;;;;;N;;;10418;;10418
+10441;DESERET SMALL LETTER EF;Ll;0;L;;;;;N;;;10419;;10419
+10442;DESERET SMALL LETTER VEE;Ll;0;L;;;;;N;;;1041A;;1041A
+10443;DESERET SMALL LETTER ETH;Ll;0;L;;;;;N;;;1041B;;1041B
+10444;DESERET SMALL LETTER THEE;Ll;0;L;;;;;N;;;1041C;;1041C
+10445;DESERET SMALL LETTER ES;Ll;0;L;;;;;N;;;1041D;;1041D
+10446;DESERET SMALL LETTER ZEE;Ll;0;L;;;;;N;;;1041E;;1041E
+10447;DESERET SMALL LETTER ESH;Ll;0;L;;;;;N;;;1041F;;1041F
+10448;DESERET SMALL LETTER ZHEE;Ll;0;L;;;;;N;;;10420;;10420
+10449;DESERET SMALL LETTER ER;Ll;0;L;;;;;N;;;10421;;10421
+1044A;DESERET SMALL LETTER EL;Ll;0;L;;;;;N;;;10422;;10422
+1044B;DESERET SMALL LETTER EM;Ll;0;L;;;;;N;;;10423;;10423
+1044C;DESERET SMALL LETTER EN;Ll;0;L;;;;;N;;;10424;;10424
+1044D;DESERET SMALL LETTER ENG;Ll;0;L;;;;;N;;;10425;;10425
+1044E;DESERET SMALL LETTER OI;Ll;0;L;;;;;N;;;10426;;10426
+1044F;DESERET SMALL LETTER EW;Ll;0;L;;;;;N;;;10427;;10427
+10450;SHAVIAN LETTER PEEP;Lo;0;L;;;;;N;;;;;
+10451;SHAVIAN LETTER TOT;Lo;0;L;;;;;N;;;;;
+10452;SHAVIAN LETTER KICK;Lo;0;L;;;;;N;;;;;
+10453;SHAVIAN LETTER FEE;Lo;0;L;;;;;N;;;;;
+10454;SHAVIAN LETTER THIGH;Lo;0;L;;;;;N;;;;;
+10455;SHAVIAN LETTER SO;Lo;0;L;;;;;N;;;;;
+10456;SHAVIAN LETTER SURE;Lo;0;L;;;;;N;;;;;
+10457;SHAVIAN LETTER CHURCH;Lo;0;L;;;;;N;;;;;
+10458;SHAVIAN LETTER YEA;Lo;0;L;;;;;N;;;;;
+10459;SHAVIAN LETTER HUNG;Lo;0;L;;;;;N;;;;;
+1045A;SHAVIAN LETTER BIB;Lo;0;L;;;;;N;;;;;
+1045B;SHAVIAN LETTER DEAD;Lo;0;L;;;;;N;;;;;
+1045C;SHAVIAN LETTER GAG;Lo;0;L;;;;;N;;;;;
+1045D;SHAVIAN LETTER VOW;Lo;0;L;;;;;N;;;;;
+1045E;SHAVIAN LETTER THEY;Lo;0;L;;;;;N;;;;;
+1045F;SHAVIAN LETTER ZOO;Lo;0;L;;;;;N;;;;;
+10460;SHAVIAN LETTER MEASURE;Lo;0;L;;;;;N;;;;;
+10461;SHAVIAN LETTER JUDGE;Lo;0;L;;;;;N;;;;;
+10462;SHAVIAN LETTER WOE;Lo;0;L;;;;;N;;;;;
+10463;SHAVIAN LETTER HA-HA;Lo;0;L;;;;;N;;;;;
+10464;SHAVIAN LETTER LOLL;Lo;0;L;;;;;N;;;;;
+10465;SHAVIAN LETTER MIME;Lo;0;L;;;;;N;;;;;
+10466;SHAVIAN LETTER IF;Lo;0;L;;;;;N;;;;;
+10467;SHAVIAN LETTER EGG;Lo;0;L;;;;;N;;;;;
+10468;SHAVIAN LETTER ASH;Lo;0;L;;;;;N;;;;;
+10469;SHAVIAN LETTER ADO;Lo;0;L;;;;;N;;;;;
+1046A;SHAVIAN LETTER ON;Lo;0;L;;;;;N;;;;;
+1046B;SHAVIAN LETTER WOOL;Lo;0;L;;;;;N;;;;;
+1046C;SHAVIAN LETTER OUT;Lo;0;L;;;;;N;;;;;
+1046D;SHAVIAN LETTER AH;Lo;0;L;;;;;N;;;;;
+1046E;SHAVIAN LETTER ROAR;Lo;0;L;;;;;N;;;;;
+1046F;SHAVIAN LETTER NUN;Lo;0;L;;;;;N;;;;;
+10470;SHAVIAN LETTER EAT;Lo;0;L;;;;;N;;;;;
+10471;SHAVIAN LETTER AGE;Lo;0;L;;;;;N;;;;;
+10472;SHAVIAN LETTER ICE;Lo;0;L;;;;;N;;;;;
+10473;SHAVIAN LETTER UP;Lo;0;L;;;;;N;;;;;
+10474;SHAVIAN LETTER OAK;Lo;0;L;;;;;N;;;;;
+10475;SHAVIAN LETTER OOZE;Lo;0;L;;;;;N;;;;;
+10476;SHAVIAN LETTER OIL;Lo;0;L;;;;;N;;;;;
+10477;SHAVIAN LETTER AWE;Lo;0;L;;;;;N;;;;;
+10478;SHAVIAN LETTER ARE;Lo;0;L;;;;;N;;;;;
+10479;SHAVIAN LETTER OR;Lo;0;L;;;;;N;;;;;
+1047A;SHAVIAN LETTER AIR;Lo;0;L;;;;;N;;;;;
+1047B;SHAVIAN LETTER ERR;Lo;0;L;;;;;N;;;;;
+1047C;SHAVIAN LETTER ARRAY;Lo;0;L;;;;;N;;;;;
+1047D;SHAVIAN LETTER EAR;Lo;0;L;;;;;N;;;;;
+1047E;SHAVIAN LETTER IAN;Lo;0;L;;;;;N;;;;;
+1047F;SHAVIAN LETTER YEW;Lo;0;L;;;;;N;;;;;
+10480;OSMANYA LETTER ALEF;Lo;0;L;;;;;N;;;;;
+10481;OSMANYA LETTER BA;Lo;0;L;;;;;N;;;;;
+10482;OSMANYA LETTER TA;Lo;0;L;;;;;N;;;;;
+10483;OSMANYA LETTER JA;Lo;0;L;;;;;N;;;;;
+10484;OSMANYA LETTER XA;Lo;0;L;;;;;N;;;;;
+10485;OSMANYA LETTER KHA;Lo;0;L;;;;;N;;;;;
+10486;OSMANYA LETTER DEEL;Lo;0;L;;;;;N;;;;;
+10487;OSMANYA LETTER RA;Lo;0;L;;;;;N;;;;;
+10488;OSMANYA LETTER SA;Lo;0;L;;;;;N;;;;;
+10489;OSMANYA LETTER SHIIN;Lo;0;L;;;;;N;;;;;
+1048A;OSMANYA LETTER DHA;Lo;0;L;;;;;N;;;;;
+1048B;OSMANYA LETTER CAYN;Lo;0;L;;;;;N;;;;;
+1048C;OSMANYA LETTER GA;Lo;0;L;;;;;N;;;;;
+1048D;OSMANYA LETTER FA;Lo;0;L;;;;;N;;;;;
+1048E;OSMANYA LETTER QAAF;Lo;0;L;;;;;N;;;;;
+1048F;OSMANYA LETTER KAAF;Lo;0;L;;;;;N;;;;;
+10490;OSMANYA LETTER LAAN;Lo;0;L;;;;;N;;;;;
+10491;OSMANYA LETTER MIIN;Lo;0;L;;;;;N;;;;;
+10492;OSMANYA LETTER NUUN;Lo;0;L;;;;;N;;;;;
+10493;OSMANYA LETTER WAW;Lo;0;L;;;;;N;;;;;
+10494;OSMANYA LETTER HA;Lo;0;L;;;;;N;;;;;
+10495;OSMANYA LETTER YA;Lo;0;L;;;;;N;;;;;
+10496;OSMANYA LETTER A;Lo;0;L;;;;;N;;;;;
+10497;OSMANYA LETTER E;Lo;0;L;;;;;N;;;;;
+10498;OSMANYA LETTER I;Lo;0;L;;;;;N;;;;;
+10499;OSMANYA LETTER O;Lo;0;L;;;;;N;;;;;
+1049A;OSMANYA LETTER U;Lo;0;L;;;;;N;;;;;
+1049B;OSMANYA LETTER AA;Lo;0;L;;;;;N;;;;;
+1049C;OSMANYA LETTER EE;Lo;0;L;;;;;N;;;;;
+1049D;OSMANYA LETTER OO;Lo;0;L;;;;;N;;;;;
+104A0;OSMANYA DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;;
+104A1;OSMANYA DIGIT ONE;Nd;0;L;;1;1;1;N;;;;;
+104A2;OSMANYA DIGIT TWO;Nd;0;L;;2;2;2;N;;;;;
+104A3;OSMANYA DIGIT THREE;Nd;0;L;;3;3;3;N;;;;;
+104A4;OSMANYA DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;;
+104A5;OSMANYA DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;;
+104A6;OSMANYA DIGIT SIX;Nd;0;L;;6;6;6;N;;;;;
+104A7;OSMANYA DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;;
+104A8;OSMANYA DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;;
+104A9;OSMANYA DIGIT NINE;Nd;0;L;;9;9;9;N;;;;;
+10800;CYPRIOT SYLLABLE A;Lo;0;R;;;;;N;;;;;
+10801;CYPRIOT SYLLABLE E;Lo;0;R;;;;;N;;;;;
+10802;CYPRIOT SYLLABLE I;Lo;0;R;;;;;N;;;;;
+10803;CYPRIOT SYLLABLE O;Lo;0;R;;;;;N;;;;;
+10804;CYPRIOT SYLLABLE U;Lo;0;R;;;;;N;;;;;
+10805;CYPRIOT SYLLABLE JA;Lo;0;R;;;;;N;;;;;
+10808;CYPRIOT SYLLABLE JO;Lo;0;R;;;;;N;;;;;
+1080A;CYPRIOT SYLLABLE KA;Lo;0;R;;;;;N;;;;;
+1080B;CYPRIOT SYLLABLE KE;Lo;0;R;;;;;N;;;;;
+1080C;CYPRIOT SYLLABLE KI;Lo;0;R;;;;;N;;;;;
+1080D;CYPRIOT SYLLABLE KO;Lo;0;R;;;;;N;;;;;
+1080E;CYPRIOT SYLLABLE KU;Lo;0;R;;;;;N;;;;;
+1080F;CYPRIOT SYLLABLE LA;Lo;0;R;;;;;N;;;;;
+10810;CYPRIOT SYLLABLE LE;Lo;0;R;;;;;N;;;;;
+10811;CYPRIOT SYLLABLE LI;Lo;0;R;;;;;N;;;;;
+10812;CYPRIOT SYLLABLE LO;Lo;0;R;;;;;N;;;;;
+10813;CYPRIOT SYLLABLE LU;Lo;0;R;;;;;N;;;;;
+10814;CYPRIOT SYLLABLE MA;Lo;0;R;;;;;N;;;;;
+10815;CYPRIOT SYLLABLE ME;Lo;0;R;;;;;N;;;;;
+10816;CYPRIOT SYLLABLE MI;Lo;0;R;;;;;N;;;;;
+10817;CYPRIOT SYLLABLE MO;Lo;0;R;;;;;N;;;;;
+10818;CYPRIOT SYLLABLE MU;Lo;0;R;;;;;N;;;;;
+10819;CYPRIOT SYLLABLE NA;Lo;0;R;;;;;N;;;;;
+1081A;CYPRIOT SYLLABLE NE;Lo;0;R;;;;;N;;;;;
+1081B;CYPRIOT SYLLABLE NI;Lo;0;R;;;;;N;;;;;
+1081C;CYPRIOT SYLLABLE NO;Lo;0;R;;;;;N;;;;;
+1081D;CYPRIOT SYLLABLE NU;Lo;0;R;;;;;N;;;;;
+1081E;CYPRIOT SYLLABLE PA;Lo;0;R;;;;;N;;;;;
+1081F;CYPRIOT SYLLABLE PE;Lo;0;R;;;;;N;;;;;
+10820;CYPRIOT SYLLABLE PI;Lo;0;R;;;;;N;;;;;
+10821;CYPRIOT SYLLABLE PO;Lo;0;R;;;;;N;;;;;
+10822;CYPRIOT SYLLABLE PU;Lo;0;R;;;;;N;;;;;
+10823;CYPRIOT SYLLABLE RA;Lo;0;R;;;;;N;;;;;
+10824;CYPRIOT SYLLABLE RE;Lo;0;R;;;;;N;;;;;
+10825;CYPRIOT SYLLABLE RI;Lo;0;R;;;;;N;;;;;
+10826;CYPRIOT SYLLABLE RO;Lo;0;R;;;;;N;;;;;
+10827;CYPRIOT SYLLABLE RU;Lo;0;R;;;;;N;;;;;
+10828;CYPRIOT SYLLABLE SA;Lo;0;R;;;;;N;;;;;
+10829;CYPRIOT SYLLABLE SE;Lo;0;R;;;;;N;;;;;
+1082A;CYPRIOT SYLLABLE SI;Lo;0;R;;;;;N;;;;;
+1082B;CYPRIOT SYLLABLE SO;Lo;0;R;;;;;N;;;;;
+1082C;CYPRIOT SYLLABLE SU;Lo;0;R;;;;;N;;;;;
+1082D;CYPRIOT SYLLABLE TA;Lo;0;R;;;;;N;;;;;
+1082E;CYPRIOT SYLLABLE TE;Lo;0;R;;;;;N;;;;;
+1082F;CYPRIOT SYLLABLE TI;Lo;0;R;;;;;N;;;;;
+10830;CYPRIOT SYLLABLE TO;Lo;0;R;;;;;N;;;;;
+10831;CYPRIOT SYLLABLE TU;Lo;0;R;;;;;N;;;;;
+10832;CYPRIOT SYLLABLE WA;Lo;0;R;;;;;N;;;;;
+10833;CYPRIOT SYLLABLE WE;Lo;0;R;;;;;N;;;;;
+10834;CYPRIOT SYLLABLE WI;Lo;0;R;;;;;N;;;;;
+10835;CYPRIOT SYLLABLE WO;Lo;0;R;;;;;N;;;;;
+10837;CYPRIOT SYLLABLE XA;Lo;0;R;;;;;N;;;;;
+10838;CYPRIOT SYLLABLE XE;Lo;0;R;;;;;N;;;;;
+1083C;CYPRIOT SYLLABLE ZA;Lo;0;R;;;;;N;;;;;
+1083F;CYPRIOT SYLLABLE ZO;Lo;0;R;;;;;N;;;;;
+10A00;KHAROSHTHI LETTER A;Lo;0;R;;;;;N;;;;;
+10A01;KHAROSHTHI VOWEL SIGN I;Mn;0;NSM;;;;;N;;;;;
+10A02;KHAROSHTHI VOWEL SIGN U;Mn;0;NSM;;;;;N;;;;;
+10A03;KHAROSHTHI VOWEL SIGN VOCALIC R;Mn;0;NSM;;;;;N;;;;;
+10A05;KHAROSHTHI VOWEL SIGN E;Mn;0;NSM;;;;;N;;;;;
+10A06;KHAROSHTHI VOWEL SIGN O;Mn;0;NSM;;;;;N;;;;;
+10A0C;KHAROSHTHI VOWEL LENGTH MARK;Mn;0;NSM;;;;;N;;;;;
+10A0D;KHAROSHTHI SIGN DOUBLE RING BELOW;Mn;220;NSM;;;;;N;;;;;
+10A0E;KHAROSHTHI SIGN ANUSVARA;Mn;0;NSM;;;;;N;;;;;
+10A0F;KHAROSHTHI SIGN VISARGA;Mn;230;NSM;;;;;N;;;;;
+10A10;KHAROSHTHI LETTER KA;Lo;0;R;;;;;N;;;;;
+10A11;KHAROSHTHI LETTER KHA;Lo;0;R;;;;;N;;;;;
+10A12;KHAROSHTHI LETTER GA;Lo;0;R;;;;;N;;;;;
+10A13;KHAROSHTHI LETTER GHA;Lo;0;R;;;;;N;;;;;
+10A15;KHAROSHTHI LETTER CA;Lo;0;R;;;;;N;;;;;
+10A16;KHAROSHTHI LETTER CHA;Lo;0;R;;;;;N;;;;;
+10A17;KHAROSHTHI LETTER JA;Lo;0;R;;;;;N;;;;;
+10A19;KHAROSHTHI LETTER NYA;Lo;0;R;;;;;N;;;;;
+10A1A;KHAROSHTHI LETTER TTA;Lo;0;R;;;;;N;;;;;
+10A1B;KHAROSHTHI LETTER TTHA;Lo;0;R;;;;;N;;;;;
+10A1C;KHAROSHTHI LETTER DDA;Lo;0;R;;;;;N;;;;;
+10A1D;KHAROSHTHI LETTER DDHA;Lo;0;R;;;;;N;;;;;
+10A1E;KHAROSHTHI LETTER NNA;Lo;0;R;;;;;N;;;;;
+10A1F;KHAROSHTHI LETTER TA;Lo;0;R;;;;;N;;;;;
+10A20;KHAROSHTHI LETTER THA;Lo;0;R;;;;;N;;;;;
+10A21;KHAROSHTHI LETTER DA;Lo;0;R;;;;;N;;;;;
+10A22;KHAROSHTHI LETTER DHA;Lo;0;R;;;;;N;;;;;
+10A23;KHAROSHTHI LETTER NA;Lo;0;R;;;;;N;;;;;
+10A24;KHAROSHTHI LETTER PA;Lo;0;R;;;;;N;;;;;
+10A25;KHAROSHTHI LETTER PHA;Lo;0;R;;;;;N;;;;;
+10A26;KHAROSHTHI LETTER BA;Lo;0;R;;;;;N;;;;;
+10A27;KHAROSHTHI LETTER BHA;Lo;0;R;;;;;N;;;;;
+10A28;KHAROSHTHI LETTER MA;Lo;0;R;;;;;N;;;;;
+10A29;KHAROSHTHI LETTER YA;Lo;0;R;;;;;N;;;;;
+10A2A;KHAROSHTHI LETTER RA;Lo;0;R;;;;;N;;;;;
+10A2B;KHAROSHTHI LETTER LA;Lo;0;R;;;;;N;;;;;
+10A2C;KHAROSHTHI LETTER VA;Lo;0;R;;;;;N;;;;;
+10A2D;KHAROSHTHI LETTER SHA;Lo;0;R;;;;;N;;;;;
+10A2E;KHAROSHTHI LETTER SSA;Lo;0;R;;;;;N;;;;;
+10A2F;KHAROSHTHI LETTER SA;Lo;0;R;;;;;N;;;;;
+10A30;KHAROSHTHI LETTER ZA;Lo;0;R;;;;;N;;;;;
+10A31;KHAROSHTHI LETTER HA;Lo;0;R;;;;;N;;;;;
+10A32;KHAROSHTHI LETTER KKA;Lo;0;R;;;;;N;;;;;
+10A33;KHAROSHTHI LETTER TTTHA;Lo;0;R;;;;;N;;;;;
+10A38;KHAROSHTHI SIGN BAR ABOVE;Mn;230;NSM;;;;;N;;;;;
+10A39;KHAROSHTHI SIGN CAUDA;Mn;1;NSM;;;;;N;;;;;
+10A3A;KHAROSHTHI SIGN DOT BELOW;Mn;220;NSM;;;;;N;;;;;
+10A3F;KHAROSHTHI VIRAMA;Mn;9;NSM;;;;;N;;;;;
+10A40;KHAROSHTHI DIGIT ONE;No;0;R;;;1;1;N;;;;;
+10A41;KHAROSHTHI DIGIT TWO;No;0;R;;;2;2;N;;;;;
+10A42;KHAROSHTHI DIGIT THREE;No;0;R;;;3;3;N;;;;;
+10A43;KHAROSHTHI DIGIT FOUR;No;0;R;;;4;4;N;;;;;
+10A44;KHAROSHTHI NUMBER TEN;No;0;R;;;;10;N;;;;;
+10A45;KHAROSHTHI NUMBER TWENTY;No;0;R;;;;20;N;;;;;
+10A46;KHAROSHTHI NUMBER ONE HUNDRED;No;0;R;;;;100;N;;;;;
+10A47;KHAROSHTHI NUMBER ONE THOUSAND;No;0;R;;;;1000;N;;;;;
+10A50;KHAROSHTHI PUNCTUATION DOT;Po;0;R;;;;;N;;;;;
+10A51;KHAROSHTHI PUNCTUATION SMALL CIRCLE;Po;0;R;;;;;N;;;;;
+10A52;KHAROSHTHI PUNCTUATION CIRCLE;Po;0;R;;;;;N;;;;;
+10A53;KHAROSHTHI PUNCTUATION CRESCENT BAR;Po;0;R;;;;;N;;;;;
+10A54;KHAROSHTHI PUNCTUATION MANGALAM;Po;0;R;;;;;N;;;;;
+10A55;KHAROSHTHI PUNCTUATION LOTUS;Po;0;R;;;;;N;;;;;
+10A56;KHAROSHTHI PUNCTUATION DANDA;Po;0;R;;;;;N;;;;;
+10A57;KHAROSHTHI PUNCTUATION DOUBLE DANDA;Po;0;R;;;;;N;;;;;
+10A58;KHAROSHTHI PUNCTUATION LINES;Po;0;R;;;;;N;;;;;
+1D000;BYZANTINE MUSICAL SYMBOL PSILI;So;0;L;;;;;N;;;;;
+1D001;BYZANTINE MUSICAL SYMBOL DASEIA;So;0;L;;;;;N;;;;;
+1D002;BYZANTINE MUSICAL SYMBOL PERISPOMENI;So;0;L;;;;;N;;;;;
+1D003;BYZANTINE MUSICAL SYMBOL OXEIA EKFONITIKON;So;0;L;;;;;N;;;;;
+1D004;BYZANTINE MUSICAL SYMBOL OXEIA DIPLI;So;0;L;;;;;N;;;;;
+1D005;BYZANTINE MUSICAL SYMBOL VAREIA EKFONITIKON;So;0;L;;;;;N;;;;;
+1D006;BYZANTINE MUSICAL SYMBOL VAREIA DIPLI;So;0;L;;;;;N;;;;;
+1D007;BYZANTINE MUSICAL SYMBOL KATHISTI;So;0;L;;;;;N;;;;;
+1D008;BYZANTINE MUSICAL SYMBOL SYRMATIKI;So;0;L;;;;;N;;;;;
+1D009;BYZANTINE MUSICAL SYMBOL PARAKLITIKI;So;0;L;;;;;N;;;;;
+1D00A;BYZANTINE MUSICAL SYMBOL YPOKRISIS;So;0;L;;;;;N;;;;;
+1D00B;BYZANTINE MUSICAL SYMBOL YPOKRISIS DIPLI;So;0;L;;;;;N;;;;;
+1D00C;BYZANTINE MUSICAL SYMBOL KREMASTI;So;0;L;;;;;N;;;;;
+1D00D;BYZANTINE MUSICAL SYMBOL APESO EKFONITIKON;So;0;L;;;;;N;;;;;
+1D00E;BYZANTINE MUSICAL SYMBOL EXO EKFONITIKON;So;0;L;;;;;N;;;;;
+1D00F;BYZANTINE MUSICAL SYMBOL TELEIA;So;0;L;;;;;N;;;;;
+1D010;BYZANTINE MUSICAL SYMBOL KENTIMATA;So;0;L;;;;;N;;;;;
+1D011;BYZANTINE MUSICAL SYMBOL APOSTROFOS;So;0;L;;;;;N;;;;;
+1D012;BYZANTINE MUSICAL SYMBOL APOSTROFOS DIPLI;So;0;L;;;;;N;;;;;
+1D013;BYZANTINE MUSICAL SYMBOL SYNEVMA;So;0;L;;;;;N;;;;;
+1D014;BYZANTINE MUSICAL SYMBOL THITA;So;0;L;;;;;N;;;;;
+1D015;BYZANTINE MUSICAL SYMBOL OLIGON ARCHAION;So;0;L;;;;;N;;;;;
+1D016;BYZANTINE MUSICAL SYMBOL GORGON ARCHAION;So;0;L;;;;;N;;;;;
+1D017;BYZANTINE MUSICAL SYMBOL PSILON;So;0;L;;;;;N;;;;;
+1D018;BYZANTINE MUSICAL SYMBOL CHAMILON;So;0;L;;;;;N;;;;;
+1D019;BYZANTINE MUSICAL SYMBOL VATHY;So;0;L;;;;;N;;;;;
+1D01A;BYZANTINE MUSICAL SYMBOL ISON ARCHAION;So;0;L;;;;;N;;;;;
+1D01B;BYZANTINE MUSICAL SYMBOL KENTIMA ARCHAION;So;0;L;;;;;N;;;;;
+1D01C;BYZANTINE MUSICAL SYMBOL KENTIMATA ARCHAION;So;0;L;;;;;N;;;;;
+1D01D;BYZANTINE MUSICAL SYMBOL SAXIMATA;So;0;L;;;;;N;;;;;
+1D01E;BYZANTINE MUSICAL SYMBOL PARICHON;So;0;L;;;;;N;;;;;
+1D01F;BYZANTINE MUSICAL SYMBOL STAVROS APODEXIA;So;0;L;;;;;N;;;;;
+1D020;BYZANTINE MUSICAL SYMBOL OXEIAI ARCHAION;So;0;L;;;;;N;;;;;
+1D021;BYZANTINE MUSICAL SYMBOL VAREIAI ARCHAION;So;0;L;;;;;N;;;;;
+1D022;BYZANTINE MUSICAL SYMBOL APODERMA ARCHAION;So;0;L;;;;;N;;;;;
+1D023;BYZANTINE MUSICAL SYMBOL APOTHEMA;So;0;L;;;;;N;;;;;
+1D024;BYZANTINE MUSICAL SYMBOL KLASMA;So;0;L;;;;;N;;;;;
+1D025;BYZANTINE MUSICAL SYMBOL REVMA;So;0;L;;;;;N;;;;;
+1D026;BYZANTINE MUSICAL SYMBOL PIASMA ARCHAION;So;0;L;;;;;N;;;;;
+1D027;BYZANTINE MUSICAL SYMBOL TINAGMA;So;0;L;;;;;N;;;;;
+1D028;BYZANTINE MUSICAL SYMBOL ANATRICHISMA;So;0;L;;;;;N;;;;;
+1D029;BYZANTINE MUSICAL SYMBOL SEISMA;So;0;L;;;;;N;;;;;
+1D02A;BYZANTINE MUSICAL SYMBOL SYNAGMA ARCHAION;So;0;L;;;;;N;;;;;
+1D02B;BYZANTINE MUSICAL SYMBOL SYNAGMA META STAVROU;So;0;L;;;;;N;;;;;
+1D02C;BYZANTINE MUSICAL SYMBOL OYRANISMA ARCHAION;So;0;L;;;;;N;;;;;
+1D02D;BYZANTINE MUSICAL SYMBOL THEMA;So;0;L;;;;;N;;;;;
+1D02E;BYZANTINE MUSICAL SYMBOL LEMOI;So;0;L;;;;;N;;;;;
+1D02F;BYZANTINE MUSICAL SYMBOL DYO;So;0;L;;;;;N;;;;;
+1D030;BYZANTINE MUSICAL SYMBOL TRIA;So;0;L;;;;;N;;;;;
+1D031;BYZANTINE MUSICAL SYMBOL TESSERA;So;0;L;;;;;N;;;;;
+1D032;BYZANTINE MUSICAL SYMBOL KRATIMATA;So;0;L;;;;;N;;;;;
+1D033;BYZANTINE MUSICAL SYMBOL APESO EXO NEO;So;0;L;;;;;N;;;;;
+1D034;BYZANTINE MUSICAL SYMBOL FTHORA ARCHAION;So;0;L;;;;;N;;;;;
+1D035;BYZANTINE MUSICAL SYMBOL IMIFTHORA;So;0;L;;;;;N;;;;;
+1D036;BYZANTINE MUSICAL SYMBOL TROMIKON ARCHAION;So;0;L;;;;;N;;;;;
+1D037;BYZANTINE MUSICAL SYMBOL KATAVA TROMIKON;So;0;L;;;;;N;;;;;
+1D038;BYZANTINE MUSICAL SYMBOL PELASTON;So;0;L;;;;;N;;;;;
+1D039;BYZANTINE MUSICAL SYMBOL PSIFISTON;So;0;L;;;;;N;;;;;
+1D03A;BYZANTINE MUSICAL SYMBOL KONTEVMA;So;0;L;;;;;N;;;;;
+1D03B;BYZANTINE MUSICAL SYMBOL CHOREVMA ARCHAION;So;0;L;;;;;N;;;;;
+1D03C;BYZANTINE MUSICAL SYMBOL RAPISMA;So;0;L;;;;;N;;;;;
+1D03D;BYZANTINE MUSICAL SYMBOL PARAKALESMA ARCHAION;So;0;L;;;;;N;;;;;
+1D03E;BYZANTINE MUSICAL SYMBOL PARAKLITIKI ARCHAION;So;0;L;;;;;N;;;;;
+1D03F;BYZANTINE MUSICAL SYMBOL ICHADIN;So;0;L;;;;;N;;;;;
+1D040;BYZANTINE MUSICAL SYMBOL NANA;So;0;L;;;;;N;;;;;
+1D041;BYZANTINE MUSICAL SYMBOL PETASMA;So;0;L;;;;;N;;;;;
+1D042;BYZANTINE MUSICAL SYMBOL KONTEVMA ALLO;So;0;L;;;;;N;;;;;
+1D043;BYZANTINE MUSICAL SYMBOL TROMIKON ALLO;So;0;L;;;;;N;;;;;
+1D044;BYZANTINE MUSICAL SYMBOL STRAGGISMATA;So;0;L;;;;;N;;;;;
+1D045;BYZANTINE MUSICAL SYMBOL GRONTHISMATA;So;0;L;;;;;N;;;;;
+1D046;BYZANTINE MUSICAL SYMBOL ISON NEO;So;0;L;;;;;N;;;;;
+1D047;BYZANTINE MUSICAL SYMBOL OLIGON NEO;So;0;L;;;;;N;;;;;
+1D048;BYZANTINE MUSICAL SYMBOL OXEIA NEO;So;0;L;;;;;N;;;;;
+1D049;BYZANTINE MUSICAL SYMBOL PETASTI;So;0;L;;;;;N;;;;;
+1D04A;BYZANTINE MUSICAL SYMBOL KOUFISMA;So;0;L;;;;;N;;;;;
+1D04B;BYZANTINE MUSICAL SYMBOL PETASTOKOUFISMA;So;0;L;;;;;N;;;;;
+1D04C;BYZANTINE MUSICAL SYMBOL KRATIMOKOUFISMA;So;0;L;;;;;N;;;;;
+1D04D;BYZANTINE MUSICAL SYMBOL PELASTON NEO;So;0;L;;;;;N;;;;;
+1D04E;BYZANTINE MUSICAL SYMBOL KENTIMATA NEO ANO;So;0;L;;;;;N;;;;;
+1D04F;BYZANTINE MUSICAL SYMBOL KENTIMA NEO ANO;So;0;L;;;;;N;;;;;
+1D050;BYZANTINE MUSICAL SYMBOL YPSILI;So;0;L;;;;;N;;;;;
+1D051;BYZANTINE MUSICAL SYMBOL APOSTROFOS NEO;So;0;L;;;;;N;;;;;
+1D052;BYZANTINE MUSICAL SYMBOL APOSTROFOI SYNDESMOS NEO;So;0;L;;;;;N;;;;;
+1D053;BYZANTINE MUSICAL SYMBOL YPORROI;So;0;L;;;;;N;;;;;
+1D054;BYZANTINE MUSICAL SYMBOL KRATIMOYPORROON;So;0;L;;;;;N;;;;;
+1D055;BYZANTINE MUSICAL SYMBOL ELAFRON;So;0;L;;;;;N;;;;;
+1D056;BYZANTINE MUSICAL SYMBOL CHAMILI;So;0;L;;;;;N;;;;;
+1D057;BYZANTINE MUSICAL SYMBOL MIKRON ISON;So;0;L;;;;;N;;;;;
+1D058;BYZANTINE MUSICAL SYMBOL VAREIA NEO;So;0;L;;;;;N;;;;;
+1D059;BYZANTINE MUSICAL SYMBOL PIASMA NEO;So;0;L;;;;;N;;;;;
+1D05A;BYZANTINE MUSICAL SYMBOL PSIFISTON NEO;So;0;L;;;;;N;;;;;
+1D05B;BYZANTINE MUSICAL SYMBOL OMALON;So;0;L;;;;;N;;;;;
+1D05C;BYZANTINE MUSICAL SYMBOL ANTIKENOMA;So;0;L;;;;;N;;;;;
+1D05D;BYZANTINE MUSICAL SYMBOL LYGISMA;So;0;L;;;;;N;;;;;
+1D05E;BYZANTINE MUSICAL SYMBOL PARAKLITIKI NEO;So;0;L;;;;;N;;;;;
+1D05F;BYZANTINE MUSICAL SYMBOL PARAKALESMA NEO;So;0;L;;;;;N;;;;;
+1D060;BYZANTINE MUSICAL SYMBOL ETERON PARAKALESMA;So;0;L;;;;;N;;;;;
+1D061;BYZANTINE MUSICAL SYMBOL KYLISMA;So;0;L;;;;;N;;;;;
+1D062;BYZANTINE MUSICAL SYMBOL ANTIKENOKYLISMA;So;0;L;;;;;N;;;;;
+1D063;BYZANTINE MUSICAL SYMBOL TROMIKON NEO;So;0;L;;;;;N;;;;;
+1D064;BYZANTINE MUSICAL SYMBOL EKSTREPTON;So;0;L;;;;;N;;;;;
+1D065;BYZANTINE MUSICAL SYMBOL SYNAGMA NEO;So;0;L;;;;;N;;;;;
+1D066;BYZANTINE MUSICAL SYMBOL SYRMA;So;0;L;;;;;N;;;;;
+1D067;BYZANTINE MUSICAL SYMBOL CHOREVMA NEO;So;0;L;;;;;N;;;;;
+1D068;BYZANTINE MUSICAL SYMBOL EPEGERMA;So;0;L;;;;;N;;;;;
+1D069;BYZANTINE MUSICAL SYMBOL SEISMA NEO;So;0;L;;;;;N;;;;;
+1D06A;BYZANTINE MUSICAL SYMBOL XIRON KLASMA;So;0;L;;;;;N;;;;;
+1D06B;BYZANTINE MUSICAL SYMBOL TROMIKOPSIFISTON;So;0;L;;;;;N;;;;;
+1D06C;BYZANTINE MUSICAL SYMBOL PSIFISTOLYGISMA;So;0;L;;;;;N;;;;;
+1D06D;BYZANTINE MUSICAL SYMBOL TROMIKOLYGISMA;So;0;L;;;;;N;;;;;
+1D06E;BYZANTINE MUSICAL SYMBOL TROMIKOPARAKALESMA;So;0;L;;;;;N;;;;;
+1D06F;BYZANTINE MUSICAL SYMBOL PSIFISTOPARAKALESMA;So;0;L;;;;;N;;;;;
+1D070;BYZANTINE MUSICAL SYMBOL TROMIKOSYNAGMA;So;0;L;;;;;N;;;;;
+1D071;BYZANTINE MUSICAL SYMBOL PSIFISTOSYNAGMA;So;0;L;;;;;N;;;;;
+1D072;BYZANTINE MUSICAL SYMBOL GORGOSYNTHETON;So;0;L;;;;;N;;;;;
+1D073;BYZANTINE MUSICAL SYMBOL ARGOSYNTHETON;So;0;L;;;;;N;;;;;
+1D074;BYZANTINE MUSICAL SYMBOL ETERON ARGOSYNTHETON;So;0;L;;;;;N;;;;;
+1D075;BYZANTINE MUSICAL SYMBOL OYRANISMA NEO;So;0;L;;;;;N;;;;;
+1D076;BYZANTINE MUSICAL SYMBOL THEMATISMOS ESO;So;0;L;;;;;N;;;;;
+1D077;BYZANTINE MUSICAL SYMBOL THEMATISMOS EXO;So;0;L;;;;;N;;;;;
+1D078;BYZANTINE MUSICAL SYMBOL THEMA APLOUN;So;0;L;;;;;N;;;;;
+1D079;BYZANTINE MUSICAL SYMBOL THES KAI APOTHES;So;0;L;;;;;N;;;;;
+1D07A;BYZANTINE MUSICAL SYMBOL KATAVASMA;So;0;L;;;;;N;;;;;
+1D07B;BYZANTINE MUSICAL SYMBOL ENDOFONON;So;0;L;;;;;N;;;;;
+1D07C;BYZANTINE MUSICAL SYMBOL YFEN KATO;So;0;L;;;;;N;;;;;
+1D07D;BYZANTINE MUSICAL SYMBOL YFEN ANO;So;0;L;;;;;N;;;;;
+1D07E;BYZANTINE MUSICAL SYMBOL STAVROS;So;0;L;;;;;N;;;;;
+1D07F;BYZANTINE MUSICAL SYMBOL KLASMA ANO;So;0;L;;;;;N;;;;;
+1D080;BYZANTINE MUSICAL SYMBOL DIPLI ARCHAION;So;0;L;;;;;N;;;;;
+1D081;BYZANTINE MUSICAL SYMBOL KRATIMA ARCHAION;So;0;L;;;;;N;;;;;
+1D082;BYZANTINE MUSICAL SYMBOL KRATIMA ALLO;So;0;L;;;;;N;;;;;
+1D083;BYZANTINE MUSICAL SYMBOL KRATIMA NEO;So;0;L;;;;;N;;;;;
+1D084;BYZANTINE MUSICAL SYMBOL APODERMA NEO;So;0;L;;;;;N;;;;;
+1D085;BYZANTINE MUSICAL SYMBOL APLI;So;0;L;;;;;N;;;;;
+1D086;BYZANTINE MUSICAL SYMBOL DIPLI;So;0;L;;;;;N;;;;;
+1D087;BYZANTINE MUSICAL SYMBOL TRIPLI;So;0;L;;;;;N;;;;;
+1D088;BYZANTINE MUSICAL SYMBOL TETRAPLI;So;0;L;;;;;N;;;;;
+1D089;BYZANTINE MUSICAL SYMBOL KORONIS;So;0;L;;;;;N;;;;;
+1D08A;BYZANTINE MUSICAL SYMBOL LEIMMA ENOS CHRONOU;So;0;L;;;;;N;;;;;
+1D08B;BYZANTINE MUSICAL SYMBOL LEIMMA DYO CHRONON;So;0;L;;;;;N;;;;;
+1D08C;BYZANTINE MUSICAL SYMBOL LEIMMA TRION CHRONON;So;0;L;;;;;N;;;;;
+1D08D;BYZANTINE MUSICAL SYMBOL LEIMMA TESSARON CHRONON;So;0;L;;;;;N;;;;;
+1D08E;BYZANTINE MUSICAL SYMBOL LEIMMA IMISEOS CHRONOU;So;0;L;;;;;N;;;;;
+1D08F;BYZANTINE MUSICAL SYMBOL GORGON NEO ANO;So;0;L;;;;;N;;;;;
+1D090;BYZANTINE MUSICAL SYMBOL GORGON PARESTIGMENON ARISTERA;So;0;L;;;;;N;;;;;
+1D091;BYZANTINE MUSICAL SYMBOL GORGON PARESTIGMENON DEXIA;So;0;L;;;;;N;;;;;
+1D092;BYZANTINE MUSICAL SYMBOL DIGORGON;So;0;L;;;;;N;;;;;
+1D093;BYZANTINE MUSICAL SYMBOL DIGORGON PARESTIGMENON ARISTERA KATO;So;0;L;;;;;N;;;;;
+1D094;BYZANTINE MUSICAL SYMBOL DIGORGON PARESTIGMENON ARISTERA ANO;So;0;L;;;;;N;;;;;
+1D095;BYZANTINE MUSICAL SYMBOL DIGORGON PARESTIGMENON DEXIA;So;0;L;;;;;N;;;;;
+1D096;BYZANTINE MUSICAL SYMBOL TRIGORGON;So;0;L;;;;;N;;;;;
+1D097;BYZANTINE MUSICAL SYMBOL ARGON;So;0;L;;;;;N;;;;;
+1D098;BYZANTINE MUSICAL SYMBOL IMIDIARGON;So;0;L;;;;;N;;;;;
+1D099;BYZANTINE MUSICAL SYMBOL DIARGON;So;0;L;;;;;N;;;;;
+1D09A;BYZANTINE MUSICAL SYMBOL AGOGI POLI ARGI;So;0;L;;;;;N;;;;;
+1D09B;BYZANTINE MUSICAL SYMBOL AGOGI ARGOTERI;So;0;L;;;;;N;;;;;
+1D09C;BYZANTINE MUSICAL SYMBOL AGOGI ARGI;So;0;L;;;;;N;;;;;
+1D09D;BYZANTINE MUSICAL SYMBOL AGOGI METRIA;So;0;L;;;;;N;;;;;
+1D09E;BYZANTINE MUSICAL SYMBOL AGOGI MESI;So;0;L;;;;;N;;;;;
+1D09F;BYZANTINE MUSICAL SYMBOL AGOGI GORGI;So;0;L;;;;;N;;;;;
+1D0A0;BYZANTINE MUSICAL SYMBOL AGOGI GORGOTERI;So;0;L;;;;;N;;;;;
+1D0A1;BYZANTINE MUSICAL SYMBOL AGOGI POLI GORGI;So;0;L;;;;;N;;;;;
+1D0A2;BYZANTINE MUSICAL SYMBOL MARTYRIA PROTOS ICHOS;So;0;L;;;;;N;;;;;
+1D0A3;BYZANTINE MUSICAL SYMBOL MARTYRIA ALLI PROTOS ICHOS;So;0;L;;;;;N;;;;;
+1D0A4;BYZANTINE MUSICAL SYMBOL MARTYRIA DEYTEROS ICHOS;So;0;L;;;;;N;;;;;
+1D0A5;BYZANTINE MUSICAL SYMBOL MARTYRIA ALLI DEYTEROS ICHOS;So;0;L;;;;;N;;;;;
+1D0A6;BYZANTINE MUSICAL SYMBOL MARTYRIA TRITOS ICHOS;So;0;L;;;;;N;;;;;
+1D0A7;BYZANTINE MUSICAL SYMBOL MARTYRIA TRIFONIAS;So;0;L;;;;;N;;;;;
+1D0A8;BYZANTINE MUSICAL SYMBOL MARTYRIA TETARTOS ICHOS;So;0;L;;;;;N;;;;;
+1D0A9;BYZANTINE MUSICAL SYMBOL MARTYRIA TETARTOS LEGETOS ICHOS;So;0;L;;;;;N;;;;;
+1D0AA;BYZANTINE MUSICAL SYMBOL MARTYRIA LEGETOS ICHOS;So;0;L;;;;;N;;;;;
+1D0AB;BYZANTINE MUSICAL SYMBOL MARTYRIA PLAGIOS ICHOS;So;0;L;;;;;N;;;;;
+1D0AC;BYZANTINE MUSICAL SYMBOL ISAKIA TELOUS ICHIMATOS;So;0;L;;;;;N;;;;;
+1D0AD;BYZANTINE MUSICAL SYMBOL APOSTROFOI TELOUS ICHIMATOS;So;0;L;;;;;N;;;;;
+1D0AE;BYZANTINE MUSICAL SYMBOL FANEROSIS TETRAFONIAS;So;0;L;;;;;N;;;;;
+1D0AF;BYZANTINE MUSICAL SYMBOL FANEROSIS MONOFONIAS;So;0;L;;;;;N;;;;;
+1D0B0;BYZANTINE MUSICAL SYMBOL FANEROSIS DIFONIAS;So;0;L;;;;;N;;;;;
+1D0B1;BYZANTINE MUSICAL SYMBOL MARTYRIA VARYS ICHOS;So;0;L;;;;;N;;;;;
+1D0B2;BYZANTINE MUSICAL SYMBOL MARTYRIA PROTOVARYS ICHOS;So;0;L;;;;;N;;;;;
+1D0B3;BYZANTINE MUSICAL SYMBOL MARTYRIA PLAGIOS TETARTOS ICHOS;So;0;L;;;;;N;;;;;
+1D0B4;BYZANTINE MUSICAL SYMBOL GORTHMIKON N APLOUN;So;0;L;;;;;N;;;;;
+1D0B5;BYZANTINE MUSICAL SYMBOL GORTHMIKON N DIPLOUN;So;0;L;;;;;N;;;;;
+1D0B6;BYZANTINE MUSICAL SYMBOL ENARXIS KAI FTHORA VOU;So;0;L;;;;;N;;;;;
+1D0B7;BYZANTINE MUSICAL SYMBOL IMIFONON;So;0;L;;;;;N;;;;;
+1D0B8;BYZANTINE MUSICAL SYMBOL IMIFTHORON;So;0;L;;;;;N;;;;;
+1D0B9;BYZANTINE MUSICAL SYMBOL FTHORA ARCHAION DEYTEROU ICHOU;So;0;L;;;;;N;;;;;
+1D0BA;BYZANTINE MUSICAL SYMBOL FTHORA DIATONIKI PA;So;0;L;;;;;N;;;;;
+1D0BB;BYZANTINE MUSICAL SYMBOL FTHORA DIATONIKI NANA;So;0;L;;;;;N;;;;;
+1D0BC;BYZANTINE MUSICAL SYMBOL FTHORA NAOS ICHOS;So;0;L;;;;;N;;;;;
+1D0BD;BYZANTINE MUSICAL SYMBOL FTHORA DIATONIKI DI;So;0;L;;;;;N;;;;;
+1D0BE;BYZANTINE MUSICAL SYMBOL FTHORA SKLIRON DIATONON DI;So;0;L;;;;;N;;;;;
+1D0BF;BYZANTINE MUSICAL SYMBOL FTHORA DIATONIKI KE;So;0;L;;;;;N;;;;;
+1D0C0;BYZANTINE MUSICAL SYMBOL FTHORA DIATONIKI ZO;So;0;L;;;;;N;;;;;
+1D0C1;BYZANTINE MUSICAL SYMBOL FTHORA DIATONIKI NI KATO;So;0;L;;;;;N;;;;;
+1D0C2;BYZANTINE MUSICAL SYMBOL FTHORA DIATONIKI NI ANO;So;0;L;;;;;N;;;;;
+1D0C3;BYZANTINE MUSICAL SYMBOL FTHORA MALAKON CHROMA DIFONIAS;So;0;L;;;;;N;;;;;
+1D0C4;BYZANTINE MUSICAL SYMBOL FTHORA MALAKON CHROMA MONOFONIAS;So;0;L;;;;;N;;;;;
+1D0C5;BYZANTINE MUSICAL SYMBOL FHTORA SKLIRON CHROMA VASIS;So;0;L;;;;;N;;;;;
+1D0C6;BYZANTINE MUSICAL SYMBOL FTHORA SKLIRON CHROMA SYNAFI;So;0;L;;;;;N;;;;;
+1D0C7;BYZANTINE MUSICAL SYMBOL FTHORA NENANO;So;0;L;;;;;N;;;;;
+1D0C8;BYZANTINE MUSICAL SYMBOL CHROA ZYGOS;So;0;L;;;;;N;;;;;
+1D0C9;BYZANTINE MUSICAL SYMBOL CHROA KLITON;So;0;L;;;;;N;;;;;
+1D0CA;BYZANTINE MUSICAL SYMBOL CHROA SPATHI;So;0;L;;;;;N;;;;;
+1D0CB;BYZANTINE MUSICAL SYMBOL FTHORA I YFESIS TETARTIMORION;So;0;L;;;;;N;;;;;
+1D0CC;BYZANTINE MUSICAL SYMBOL FTHORA ENARMONIOS ANTIFONIA;So;0;L;;;;;N;;;;;
+1D0CD;BYZANTINE MUSICAL SYMBOL YFESIS TRITIMORION;So;0;L;;;;;N;;;;;
+1D0CE;BYZANTINE MUSICAL SYMBOL DIESIS TRITIMORION;So;0;L;;;;;N;;;;;
+1D0CF;BYZANTINE MUSICAL SYMBOL DIESIS TETARTIMORION;So;0;L;;;;;N;;;;;
+1D0D0;BYZANTINE MUSICAL SYMBOL DIESIS APLI DYO DODEKATA;So;0;L;;;;;N;;;;;
+1D0D1;BYZANTINE MUSICAL SYMBOL DIESIS MONOGRAMMOS TESSERA DODEKATA;So;0;L;;;;;N;;;;;
+1D0D2;BYZANTINE MUSICAL SYMBOL DIESIS DIGRAMMOS EX DODEKATA;So;0;L;;;;;N;;;;;
+1D0D3;BYZANTINE MUSICAL SYMBOL DIESIS TRIGRAMMOS OKTO DODEKATA;So;0;L;;;;;N;;;;;
+1D0D4;BYZANTINE MUSICAL SYMBOL YFESIS APLI DYO DODEKATA;So;0;L;;;;;N;;;;;
+1D0D5;BYZANTINE MUSICAL SYMBOL YFESIS MONOGRAMMOS TESSERA DODEKATA;So;0;L;;;;;N;;;;;
+1D0D6;BYZANTINE MUSICAL SYMBOL YFESIS DIGRAMMOS EX DODEKATA;So;0;L;;;;;N;;;;;
+1D0D7;BYZANTINE MUSICAL SYMBOL YFESIS TRIGRAMMOS OKTO DODEKATA;So;0;L;;;;;N;;;;;
+1D0D8;BYZANTINE MUSICAL SYMBOL GENIKI DIESIS;So;0;L;;;;;N;;;;;
+1D0D9;BYZANTINE MUSICAL SYMBOL GENIKI YFESIS;So;0;L;;;;;N;;;;;
+1D0DA;BYZANTINE MUSICAL SYMBOL DIASTOLI APLI MIKRI;So;0;L;;;;;N;;;;;
+1D0DB;BYZANTINE MUSICAL SYMBOL DIASTOLI APLI MEGALI;So;0;L;;;;;N;;;;;
+1D0DC;BYZANTINE MUSICAL SYMBOL DIASTOLI DIPLI;So;0;L;;;;;N;;;;;
+1D0DD;BYZANTINE MUSICAL SYMBOL DIASTOLI THESEOS;So;0;L;;;;;N;;;;;
+1D0DE;BYZANTINE MUSICAL SYMBOL SIMANSIS THESEOS;So;0;L;;;;;N;;;;;
+1D0DF;BYZANTINE MUSICAL SYMBOL SIMANSIS THESEOS DISIMOU;So;0;L;;;;;N;;;;;
+1D0E0;BYZANTINE MUSICAL SYMBOL SIMANSIS THESEOS TRISIMOU;So;0;L;;;;;N;;;;;
+1D0E1;BYZANTINE MUSICAL SYMBOL SIMANSIS THESEOS TETRASIMOU;So;0;L;;;;;N;;;;;
+1D0E2;BYZANTINE MUSICAL SYMBOL SIMANSIS ARSEOS;So;0;L;;;;;N;;;;;
+1D0E3;BYZANTINE MUSICAL SYMBOL SIMANSIS ARSEOS DISIMOU;So;0;L;;;;;N;;;;;
+1D0E4;BYZANTINE MUSICAL SYMBOL SIMANSIS ARSEOS TRISIMOU;So;0;L;;;;;N;;;;;
+1D0E5;BYZANTINE MUSICAL SYMBOL SIMANSIS ARSEOS TETRASIMOU;So;0;L;;;;;N;;;;;
+1D0E6;BYZANTINE MUSICAL SYMBOL DIGRAMMA GG;So;0;L;;;;;N;;;;;
+1D0E7;BYZANTINE MUSICAL SYMBOL DIFTOGGOS OU;So;0;L;;;;;N;;;;;
+1D0E8;BYZANTINE MUSICAL SYMBOL STIGMA;So;0;L;;;;;N;;;;;
+1D0E9;BYZANTINE MUSICAL SYMBOL ARKTIKO PA;So;0;L;;;;;N;;;;;
+1D0EA;BYZANTINE MUSICAL SYMBOL ARKTIKO VOU;So;0;L;;;;;N;;;;;
+1D0EB;BYZANTINE MUSICAL SYMBOL ARKTIKO GA;So;0;L;;;;;N;;;;;
+1D0EC;BYZANTINE MUSICAL SYMBOL ARKTIKO DI;So;0;L;;;;;N;;;;;
+1D0ED;BYZANTINE MUSICAL SYMBOL ARKTIKO KE;So;0;L;;;;;N;;;;;
+1D0EE;BYZANTINE MUSICAL SYMBOL ARKTIKO ZO;So;0;L;;;;;N;;;;;
+1D0EF;BYZANTINE MUSICAL SYMBOL ARKTIKO NI;So;0;L;;;;;N;;;;;
+1D0F0;BYZANTINE MUSICAL SYMBOL KENTIMATA NEO MESO;So;0;L;;;;;N;;;;;
+1D0F1;BYZANTINE MUSICAL SYMBOL KENTIMA NEO MESO;So;0;L;;;;;N;;;;;
+1D0F2;BYZANTINE MUSICAL SYMBOL KENTIMATA NEO KATO;So;0;L;;;;;N;;;;;
+1D0F3;BYZANTINE MUSICAL SYMBOL KENTIMA NEO KATO;So;0;L;;;;;N;;;;;
+1D0F4;BYZANTINE MUSICAL SYMBOL KLASMA KATO;So;0;L;;;;;N;;;;;
+1D0F5;BYZANTINE MUSICAL SYMBOL GORGON NEO KATO;So;0;L;;;;;N;;;;;
+1D100;MUSICAL SYMBOL SINGLE BARLINE;So;0;L;;;;;N;;;;;
+1D101;MUSICAL SYMBOL DOUBLE BARLINE;So;0;L;;;;;N;;;;;
+1D102;MUSICAL SYMBOL FINAL BARLINE;So;0;L;;;;;N;;;;;
+1D103;MUSICAL SYMBOL REVERSE FINAL BARLINE;So;0;L;;;;;N;;;;;
+1D104;MUSICAL SYMBOL DASHED BARLINE;So;0;L;;;;;N;;;;;
+1D105;MUSICAL SYMBOL SHORT BARLINE;So;0;L;;;;;N;;;;;
+1D106;MUSICAL SYMBOL LEFT REPEAT SIGN;So;0;L;;;;;N;;;;;
+1D107;MUSICAL SYMBOL RIGHT REPEAT SIGN;So;0;L;;;;;N;;;;;
+1D108;MUSICAL SYMBOL REPEAT DOTS;So;0;L;;;;;N;;;;;
+1D109;MUSICAL SYMBOL DAL SEGNO;So;0;L;;;;;N;;;;;
+1D10A;MUSICAL SYMBOL DA CAPO;So;0;L;;;;;N;;;;;
+1D10B;MUSICAL SYMBOL SEGNO;So;0;L;;;;;N;;;;;
+1D10C;MUSICAL SYMBOL CODA;So;0;L;;;;;N;;;;;
+1D10D;MUSICAL SYMBOL REPEATED FIGURE-1;So;0;L;;;;;N;;;;;
+1D10E;MUSICAL SYMBOL REPEATED FIGURE-2;So;0;L;;;;;N;;;;;
+1D10F;MUSICAL SYMBOL REPEATED FIGURE-3;So;0;L;;;;;N;;;;;
+1D110;MUSICAL SYMBOL FERMATA;So;0;L;;;;;N;;;;;
+1D111;MUSICAL SYMBOL FERMATA BELOW;So;0;L;;;;;N;;;;;
+1D112;MUSICAL SYMBOL BREATH MARK;So;0;L;;;;;N;;;;;
+1D113;MUSICAL SYMBOL CAESURA;So;0;L;;;;;N;;;;;
+1D114;MUSICAL SYMBOL BRACE;So;0;L;;;;;N;;;;;
+1D115;MUSICAL SYMBOL BRACKET;So;0;L;;;;;N;;;;;
+1D116;MUSICAL SYMBOL ONE-LINE STAFF;So;0;L;;;;;N;;;;;
+1D117;MUSICAL SYMBOL TWO-LINE STAFF;So;0;L;;;;;N;;;;;
+1D118;MUSICAL SYMBOL THREE-LINE STAFF;So;0;L;;;;;N;;;;;
+1D119;MUSICAL SYMBOL FOUR-LINE STAFF;So;0;L;;;;;N;;;;;
+1D11A;MUSICAL SYMBOL FIVE-LINE STAFF;So;0;L;;;;;N;;;;;
+1D11B;MUSICAL SYMBOL SIX-LINE STAFF;So;0;L;;;;;N;;;;;
+1D11C;MUSICAL SYMBOL SIX-STRING FRETBOARD;So;0;L;;;;;N;;;;;
+1D11D;MUSICAL SYMBOL FOUR-STRING FRETBOARD;So;0;L;;;;;N;;;;;
+1D11E;MUSICAL SYMBOL G CLEF;So;0;L;;;;;N;;;;;
+1D11F;MUSICAL SYMBOL G CLEF OTTAVA ALTA;So;0;L;;;;;N;;;;;
+1D120;MUSICAL SYMBOL G CLEF OTTAVA BASSA;So;0;L;;;;;N;;;;;
+1D121;MUSICAL SYMBOL C CLEF;So;0;L;;;;;N;;;;;
+1D122;MUSICAL SYMBOL F CLEF;So;0;L;;;;;N;;;;;
+1D123;MUSICAL SYMBOL F CLEF OTTAVA ALTA;So;0;L;;;;;N;;;;;
+1D124;MUSICAL SYMBOL F CLEF OTTAVA BASSA;So;0;L;;;;;N;;;;;
+1D125;MUSICAL SYMBOL DRUM CLEF-1;So;0;L;;;;;N;;;;;
+1D126;MUSICAL SYMBOL DRUM CLEF-2;So;0;L;;;;;N;;;;;
+1D12A;MUSICAL SYMBOL DOUBLE SHARP;So;0;L;;;;;N;;;;;
+1D12B;MUSICAL SYMBOL DOUBLE FLAT;So;0;L;;;;;N;;;;;
+1D12C;MUSICAL SYMBOL FLAT UP;So;0;L;;;;;N;;;;;
+1D12D;MUSICAL SYMBOL FLAT DOWN;So;0;L;;;;;N;;;;;
+1D12E;MUSICAL SYMBOL NATURAL UP;So;0;L;;;;;N;;;;;
+1D12F;MUSICAL SYMBOL NATURAL DOWN;So;0;L;;;;;N;;;;;
+1D130;MUSICAL SYMBOL SHARP UP;So;0;L;;;;;N;;;;;
+1D131;MUSICAL SYMBOL SHARP DOWN;So;0;L;;;;;N;;;;;
+1D132;MUSICAL SYMBOL QUARTER TONE SHARP;So;0;L;;;;;N;;;;;
+1D133;MUSICAL SYMBOL QUARTER TONE FLAT;So;0;L;;;;;N;;;;;
+1D134;MUSICAL SYMBOL COMMON TIME;So;0;L;;;;;N;;;;;
+1D135;MUSICAL SYMBOL CUT TIME;So;0;L;;;;;N;;;;;
+1D136;MUSICAL SYMBOL OTTAVA ALTA;So;0;L;;;;;N;;;;;
+1D137;MUSICAL SYMBOL OTTAVA BASSA;So;0;L;;;;;N;;;;;
+1D138;MUSICAL SYMBOL QUINDICESIMA ALTA;So;0;L;;;;;N;;;;;
+1D139;MUSICAL SYMBOL QUINDICESIMA BASSA;So;0;L;;;;;N;;;;;
+1D13A;MUSICAL SYMBOL MULTI REST;So;0;L;;;;;N;;;;;
+1D13B;MUSICAL SYMBOL WHOLE REST;So;0;L;;;;;N;;;;;
+1D13C;MUSICAL SYMBOL HALF REST;So;0;L;;;;;N;;;;;
+1D13D;MUSICAL SYMBOL QUARTER REST;So;0;L;;;;;N;;;;;
+1D13E;MUSICAL SYMBOL EIGHTH REST;So;0;L;;;;;N;;;;;
+1D13F;MUSICAL SYMBOL SIXTEENTH REST;So;0;L;;;;;N;;;;;
+1D140;MUSICAL SYMBOL THIRTY-SECOND REST;So;0;L;;;;;N;;;;;
+1D141;MUSICAL SYMBOL SIXTY-FOURTH REST;So;0;L;;;;;N;;;;;
+1D142;MUSICAL SYMBOL ONE HUNDRED TWENTY-EIGHTH REST;So;0;L;;;;;N;;;;;
+1D143;MUSICAL SYMBOL X NOTEHEAD;So;0;L;;;;;N;;;;;
+1D144;MUSICAL SYMBOL PLUS NOTEHEAD;So;0;L;;;;;N;;;;;
+1D145;MUSICAL SYMBOL CIRCLE X NOTEHEAD;So;0;L;;;;;N;;;;;
+1D146;MUSICAL SYMBOL SQUARE NOTEHEAD WHITE;So;0;L;;;;;N;;;;;
+1D147;MUSICAL SYMBOL SQUARE NOTEHEAD BLACK;So;0;L;;;;;N;;;;;
+1D148;MUSICAL SYMBOL TRIANGLE NOTEHEAD UP WHITE;So;0;L;;;;;N;;;;;
+1D149;MUSICAL SYMBOL TRIANGLE NOTEHEAD UP BLACK;So;0;L;;;;;N;;;;;
+1D14A;MUSICAL SYMBOL TRIANGLE NOTEHEAD LEFT WHITE;So;0;L;;;;;N;;;;;
+1D14B;MUSICAL SYMBOL TRIANGLE NOTEHEAD LEFT BLACK;So;0;L;;;;;N;;;;;
+1D14C;MUSICAL SYMBOL TRIANGLE NOTEHEAD RIGHT WHITE;So;0;L;;;;;N;;;;;
+1D14D;MUSICAL SYMBOL TRIANGLE NOTEHEAD RIGHT BLACK;So;0;L;;;;;N;;;;;
+1D14E;MUSICAL SYMBOL TRIANGLE NOTEHEAD DOWN WHITE;So;0;L;;;;;N;;;;;
+1D14F;MUSICAL SYMBOL TRIANGLE NOTEHEAD DOWN BLACK;So;0;L;;;;;N;;;;;
+1D150;MUSICAL SYMBOL TRIANGLE NOTEHEAD UP RIGHT WHITE;So;0;L;;;;;N;;;;;
+1D151;MUSICAL SYMBOL TRIANGLE NOTEHEAD UP RIGHT BLACK;So;0;L;;;;;N;;;;;
+1D152;MUSICAL SYMBOL MOON NOTEHEAD WHITE;So;0;L;;;;;N;;;;;
+1D153;MUSICAL SYMBOL MOON NOTEHEAD BLACK;So;0;L;;;;;N;;;;;
+1D154;MUSICAL SYMBOL TRIANGLE-ROUND NOTEHEAD DOWN WHITE;So;0;L;;;;;N;;;;;
+1D155;MUSICAL SYMBOL TRIANGLE-ROUND NOTEHEAD DOWN BLACK;So;0;L;;;;;N;;;;;
+1D156;MUSICAL SYMBOL PARENTHESIS NOTEHEAD;So;0;L;;;;;N;;;;;
+1D157;MUSICAL SYMBOL VOID NOTEHEAD;So;0;L;;;;;N;;;;;
+1D158;MUSICAL SYMBOL NOTEHEAD BLACK;So;0;L;;;;;N;;;;;
+1D159;MUSICAL SYMBOL NULL NOTEHEAD;So;0;L;;;;;N;;;;;
+1D15A;MUSICAL SYMBOL CLUSTER NOTEHEAD WHITE;So;0;L;;;;;N;;;;;
+1D15B;MUSICAL SYMBOL CLUSTER NOTEHEAD BLACK;So;0;L;;;;;N;;;;;
+1D15C;MUSICAL SYMBOL BREVE;So;0;L;;;;;N;;;;;
+1D15D;MUSICAL SYMBOL WHOLE NOTE;So;0;L;;;;;N;;;;;
+1D15E;MUSICAL SYMBOL HALF NOTE;So;0;L;1D157 1D165;;;;N;;;;;
+1D15F;MUSICAL SYMBOL QUARTER NOTE;So;0;L;1D158 1D165;;;;N;;;;;
+1D160;MUSICAL SYMBOL EIGHTH NOTE;So;0;L;1D15F 1D16E;;;;N;;;;;
+1D161;MUSICAL SYMBOL SIXTEENTH NOTE;So;0;L;1D15F 1D16F;;;;N;;;;;
+1D162;MUSICAL SYMBOL THIRTY-SECOND NOTE;So;0;L;1D15F 1D170;;;;N;;;;;
+1D163;MUSICAL SYMBOL SIXTY-FOURTH NOTE;So;0;L;1D15F 1D171;;;;N;;;;;
+1D164;MUSICAL SYMBOL ONE HUNDRED TWENTY-EIGHTH NOTE;So;0;L;1D15F 1D172;;;;N;;;;;
+1D165;MUSICAL SYMBOL COMBINING STEM;Mc;216;L;;;;;N;;;;;
+1D166;MUSICAL SYMBOL COMBINING SPRECHGESANG STEM;Mc;216;L;;;;;N;;;;;
+1D167;MUSICAL SYMBOL COMBINING TREMOLO-1;Mn;1;NSM;;;;;N;;;;;
+1D168;MUSICAL SYMBOL COMBINING TREMOLO-2;Mn;1;NSM;;;;;N;;;;;
+1D169;MUSICAL SYMBOL COMBINING TREMOLO-3;Mn;1;NSM;;;;;N;;;;;
+1D16A;MUSICAL SYMBOL FINGERED TREMOLO-1;So;0;L;;;;;N;;;;;
+1D16B;MUSICAL SYMBOL FINGERED TREMOLO-2;So;0;L;;;;;N;;;;;
+1D16C;MUSICAL SYMBOL FINGERED TREMOLO-3;So;0;L;;;;;N;;;;;
+1D16D;MUSICAL SYMBOL COMBINING AUGMENTATION DOT;Mc;226;L;;;;;N;;;;;
+1D16E;MUSICAL SYMBOL COMBINING FLAG-1;Mc;216;L;;;;;N;;;;;
+1D16F;MUSICAL SYMBOL COMBINING FLAG-2;Mc;216;L;;;;;N;;;;;
+1D170;MUSICAL SYMBOL COMBINING FLAG-3;Mc;216;L;;;;;N;;;;;
+1D171;MUSICAL SYMBOL COMBINING FLAG-4;Mc;216;L;;;;;N;;;;;
+1D172;MUSICAL SYMBOL COMBINING FLAG-5;Mc;216;L;;;;;N;;;;;
+1D173;MUSICAL SYMBOL BEGIN BEAM;Cf;0;BN;;;;;N;;;;;
+1D174;MUSICAL SYMBOL END BEAM;Cf;0;BN;;;;;N;;;;;
+1D175;MUSICAL SYMBOL BEGIN TIE;Cf;0;BN;;;;;N;;;;;
+1D176;MUSICAL SYMBOL END TIE;Cf;0;BN;;;;;N;;;;;
+1D177;MUSICAL SYMBOL BEGIN SLUR;Cf;0;BN;;;;;N;;;;;
+1D178;MUSICAL SYMBOL END SLUR;Cf;0;BN;;;;;N;;;;;
+1D179;MUSICAL SYMBOL BEGIN PHRASE;Cf;0;BN;;;;;N;;;;;
+1D17A;MUSICAL SYMBOL END PHRASE;Cf;0;BN;;;;;N;;;;;
+1D17B;MUSICAL SYMBOL COMBINING ACCENT;Mn;220;NSM;;;;;N;;;;;
+1D17C;MUSICAL SYMBOL COMBINING STACCATO;Mn;220;NSM;;;;;N;;;;;
+1D17D;MUSICAL SYMBOL COMBINING TENUTO;Mn;220;NSM;;;;;N;;;;;
+1D17E;MUSICAL SYMBOL COMBINING STACCATISSIMO;Mn;220;NSM;;;;;N;;;;;
+1D17F;MUSICAL SYMBOL COMBINING MARCATO;Mn;220;NSM;;;;;N;;;;;
+1D180;MUSICAL SYMBOL COMBINING MARCATO-STACCATO;Mn;220;NSM;;;;;N;;;;;
+1D181;MUSICAL SYMBOL COMBINING ACCENT-STACCATO;Mn;220;NSM;;;;;N;;;;;
+1D182;MUSICAL SYMBOL COMBINING LOURE;Mn;220;NSM;;;;;N;;;;;
+1D183;MUSICAL SYMBOL ARPEGGIATO UP;So;0;L;;;;;N;;;;;
+1D184;MUSICAL SYMBOL ARPEGGIATO DOWN;So;0;L;;;;;N;;;;;
+1D185;MUSICAL SYMBOL COMBINING DOIT;Mn;230;NSM;;;;;N;;;;;
+1D186;MUSICAL SYMBOL COMBINING RIP;Mn;230;NSM;;;;;N;;;;;
+1D187;MUSICAL SYMBOL COMBINING FLIP;Mn;230;NSM;;;;;N;;;;;
+1D188;MUSICAL SYMBOL COMBINING SMEAR;Mn;230;NSM;;;;;N;;;;;
+1D189;MUSICAL SYMBOL COMBINING BEND;Mn;230;NSM;;;;;N;;;;;
+1D18A;MUSICAL SYMBOL COMBINING DOUBLE TONGUE;Mn;220;NSM;;;;;N;;;;;
+1D18B;MUSICAL SYMBOL COMBINING TRIPLE TONGUE;Mn;220;NSM;;;;;N;;;;;
+1D18C;MUSICAL SYMBOL RINFORZANDO;So;0;L;;;;;N;;;;;
+1D18D;MUSICAL SYMBOL SUBITO;So;0;L;;;;;N;;;;;
+1D18E;MUSICAL SYMBOL Z;So;0;L;;;;;N;;;;;
+1D18F;MUSICAL SYMBOL PIANO;So;0;L;;;;;N;;;;;
+1D190;MUSICAL SYMBOL MEZZO;So;0;L;;;;;N;;;;;
+1D191;MUSICAL SYMBOL FORTE;So;0;L;;;;;N;;;;;
+1D192;MUSICAL SYMBOL CRESCENDO;So;0;L;;;;;N;;;;;
+1D193;MUSICAL SYMBOL DECRESCENDO;So;0;L;;;;;N;;;;;
+1D194;MUSICAL SYMBOL GRACE NOTE SLASH;So;0;L;;;;;N;;;;;
+1D195;MUSICAL SYMBOL GRACE NOTE NO SLASH;So;0;L;;;;;N;;;;;
+1D196;MUSICAL SYMBOL TR;So;0;L;;;;;N;;;;;
+1D197;MUSICAL SYMBOL TURN;So;0;L;;;;;N;;;;;
+1D198;MUSICAL SYMBOL INVERTED TURN;So;0;L;;;;;N;;;;;
+1D199;MUSICAL SYMBOL TURN SLASH;So;0;L;;;;;N;;;;;
+1D19A;MUSICAL SYMBOL TURN UP;So;0;L;;;;;N;;;;;
+1D19B;MUSICAL SYMBOL ORNAMENT STROKE-1;So;0;L;;;;;N;;;;;
+1D19C;MUSICAL SYMBOL ORNAMENT STROKE-2;So;0;L;;;;;N;;;;;
+1D19D;MUSICAL SYMBOL ORNAMENT STROKE-3;So;0;L;;;;;N;;;;;
+1D19E;MUSICAL SYMBOL ORNAMENT STROKE-4;So;0;L;;;;;N;;;;;
+1D19F;MUSICAL SYMBOL ORNAMENT STROKE-5;So;0;L;;;;;N;;;;;
+1D1A0;MUSICAL SYMBOL ORNAMENT STROKE-6;So;0;L;;;;;N;;;;;
+1D1A1;MUSICAL SYMBOL ORNAMENT STROKE-7;So;0;L;;;;;N;;;;;
+1D1A2;MUSICAL SYMBOL ORNAMENT STROKE-8;So;0;L;;;;;N;;;;;
+1D1A3;MUSICAL SYMBOL ORNAMENT STROKE-9;So;0;L;;;;;N;;;;;
+1D1A4;MUSICAL SYMBOL ORNAMENT STROKE-10;So;0;L;;;;;N;;;;;
+1D1A5;MUSICAL SYMBOL ORNAMENT STROKE-11;So;0;L;;;;;N;;;;;
+1D1A6;MUSICAL SYMBOL HAUPTSTIMME;So;0;L;;;;;N;;;;;
+1D1A7;MUSICAL SYMBOL NEBENSTIMME;So;0;L;;;;;N;;;;;
+1D1A8;MUSICAL SYMBOL END OF STIMME;So;0;L;;;;;N;;;;;
+1D1A9;MUSICAL SYMBOL DEGREE SLASH;So;0;L;;;;;N;;;;;
+1D1AA;MUSICAL SYMBOL COMBINING DOWN BOW;Mn;230;NSM;;;;;N;;;;;
+1D1AB;MUSICAL SYMBOL COMBINING UP BOW;Mn;230;NSM;;;;;N;;;;;
+1D1AC;MUSICAL SYMBOL COMBINING HARMONIC;Mn;230;NSM;;;;;N;;;;;
+1D1AD;MUSICAL SYMBOL COMBINING SNAP PIZZICATO;Mn;230;NSM;;;;;N;;;;;
+1D1AE;MUSICAL SYMBOL PEDAL MARK;So;0;L;;;;;N;;;;;
+1D1AF;MUSICAL SYMBOL PEDAL UP MARK;So;0;L;;;;;N;;;;;
+1D1B0;MUSICAL SYMBOL HALF PEDAL MARK;So;0;L;;;;;N;;;;;
+1D1B1;MUSICAL SYMBOL GLISSANDO UP;So;0;L;;;;;N;;;;;
+1D1B2;MUSICAL SYMBOL GLISSANDO DOWN;So;0;L;;;;;N;;;;;
+1D1B3;MUSICAL SYMBOL WITH FINGERNAILS;So;0;L;;;;;N;;;;;
+1D1B4;MUSICAL SYMBOL DAMP;So;0;L;;;;;N;;;;;
+1D1B5;MUSICAL SYMBOL DAMP ALL;So;0;L;;;;;N;;;;;
+1D1B6;MUSICAL SYMBOL MAXIMA;So;0;L;;;;;N;;;;;
+1D1B7;MUSICAL SYMBOL LONGA;So;0;L;;;;;N;;;;;
+1D1B8;MUSICAL SYMBOL BREVIS;So;0;L;;;;;N;;;;;
+1D1B9;MUSICAL SYMBOL SEMIBREVIS WHITE;So;0;L;;;;;N;;;;;
+1D1BA;MUSICAL SYMBOL SEMIBREVIS BLACK;So;0;L;;;;;N;;;;;
+1D1BB;MUSICAL SYMBOL MINIMA;So;0;L;1D1B9 1D165;;;;N;;;;;
+1D1BC;MUSICAL SYMBOL MINIMA BLACK;So;0;L;1D1BA 1D165;;;;N;;;;;
+1D1BD;MUSICAL SYMBOL SEMIMINIMA WHITE;So;0;L;1D1BB 1D16E;;;;N;;;;;
+1D1BE;MUSICAL SYMBOL SEMIMINIMA BLACK;So;0;L;1D1BC 1D16E;;;;N;;;;;
+1D1BF;MUSICAL SYMBOL FUSA WHITE;So;0;L;1D1BB 1D16F;;;;N;;;;;
+1D1C0;MUSICAL SYMBOL FUSA BLACK;So;0;L;1D1BC 1D16F;;;;N;;;;;
+1D1C1;MUSICAL SYMBOL LONGA PERFECTA REST;So;0;L;;;;;N;;;;;
+1D1C2;MUSICAL SYMBOL LONGA IMPERFECTA REST;So;0;L;;;;;N;;;;;
+1D1C3;MUSICAL SYMBOL BREVIS REST;So;0;L;;;;;N;;;;;
+1D1C4;MUSICAL SYMBOL SEMIBREVIS REST;So;0;L;;;;;N;;;;;
+1D1C5;MUSICAL SYMBOL MINIMA REST;So;0;L;;;;;N;;;;;
+1D1C6;MUSICAL SYMBOL SEMIMINIMA REST;So;0;L;;;;;N;;;;;
+1D1C7;MUSICAL SYMBOL TEMPUS PERFECTUM CUM PROLATIONE PERFECTA;So;0;L;;;;;N;;;;;
+1D1C8;MUSICAL SYMBOL TEMPUS PERFECTUM CUM PROLATIONE IMPERFECTA;So;0;L;;;;;N;;;;;
+1D1C9;MUSICAL SYMBOL TEMPUS PERFECTUM CUM PROLATIONE PERFECTA DIMINUTION-1;So;0;L;;;;;N;;;;;
+1D1CA;MUSICAL SYMBOL TEMPUS IMPERFECTUM CUM PROLATIONE PERFECTA;So;0;L;;;;;N;;;;;
+1D1CB;MUSICAL SYMBOL TEMPUS IMPERFECTUM CUM PROLATIONE IMPERFECTA;So;0;L;;;;;N;;;;;
+1D1CC;MUSICAL SYMBOL TEMPUS IMPERFECTUM CUM PROLATIONE IMPERFECTA DIMINUTION-1;So;0;L;;;;;N;;;;;
+1D1CD;MUSICAL SYMBOL TEMPUS IMPERFECTUM CUM PROLATIONE IMPERFECTA DIMINUTION-2;So;0;L;;;;;N;;;;;
+1D1CE;MUSICAL SYMBOL TEMPUS IMPERFECTUM CUM PROLATIONE IMPERFECTA DIMINUTION-3;So;0;L;;;;;N;;;;;
+1D1CF;MUSICAL SYMBOL CROIX;So;0;L;;;;;N;;;;;
+1D1D0;MUSICAL SYMBOL GREGORIAN C CLEF;So;0;L;;;;;N;;;;;
+1D1D1;MUSICAL SYMBOL GREGORIAN F CLEF;So;0;L;;;;;N;;;;;
+1D1D2;MUSICAL SYMBOL SQUARE B;So;0;L;;;;;N;;;;;
+1D1D3;MUSICAL SYMBOL VIRGA;So;0;L;;;;;N;;;;;
+1D1D4;MUSICAL SYMBOL PODATUS;So;0;L;;;;;N;;;;;
+1D1D5;MUSICAL SYMBOL CLIVIS;So;0;L;;;;;N;;;;;
+1D1D6;MUSICAL SYMBOL SCANDICUS;So;0;L;;;;;N;;;;;
+1D1D7;MUSICAL SYMBOL CLIMACUS;So;0;L;;;;;N;;;;;
+1D1D8;MUSICAL SYMBOL TORCULUS;So;0;L;;;;;N;;;;;
+1D1D9;MUSICAL SYMBOL PORRECTUS;So;0;L;;;;;N;;;;;
+1D1DA;MUSICAL SYMBOL PORRECTUS FLEXUS;So;0;L;;;;;N;;;;;
+1D1DB;MUSICAL SYMBOL SCANDICUS FLEXUS;So;0;L;;;;;N;;;;;
+1D1DC;MUSICAL SYMBOL TORCULUS RESUPINUS;So;0;L;;;;;N;;;;;
+1D1DD;MUSICAL SYMBOL PES SUBPUNCTIS;So;0;L;;;;;N;;;;;
+1D200;GREEK VOCAL NOTATION SYMBOL-1;So;0;ON;;;;;N;;;;;
+1D201;GREEK VOCAL NOTATION SYMBOL-2;So;0;ON;;;;;N;;;;;
+1D202;GREEK VOCAL NOTATION SYMBOL-3;So;0;ON;;;;;N;;;;;
+1D203;GREEK VOCAL NOTATION SYMBOL-4;So;0;ON;;;;;N;;;;;
+1D204;GREEK VOCAL NOTATION SYMBOL-5;So;0;ON;;;;;N;;;;;
+1D205;GREEK VOCAL NOTATION SYMBOL-6;So;0;ON;;;;;N;;;;;
+1D206;GREEK VOCAL NOTATION SYMBOL-7;So;0;ON;;;;;N;;;;;
+1D207;GREEK VOCAL NOTATION SYMBOL-8;So;0;ON;;;;;N;;;;;
+1D208;GREEK VOCAL NOTATION SYMBOL-9;So;0;ON;;;;;N;;;;;
+1D209;GREEK VOCAL NOTATION SYMBOL-10;So;0;ON;;;;;N;;;;;
+1D20A;GREEK VOCAL NOTATION SYMBOL-11;So;0;ON;;;;;N;;;;;
+1D20B;GREEK VOCAL NOTATION SYMBOL-12;So;0;ON;;;;;N;;;;;
+1D20C;GREEK VOCAL NOTATION SYMBOL-13;So;0;ON;;;;;N;;;;;
+1D20D;GREEK VOCAL NOTATION SYMBOL-14;So;0;ON;;;;;N;;;;;
+1D20E;GREEK VOCAL NOTATION SYMBOL-15;So;0;ON;;;;;N;;;;;
+1D20F;GREEK VOCAL NOTATION SYMBOL-16;So;0;ON;;;;;N;;;;;
+1D210;GREEK VOCAL NOTATION SYMBOL-17;So;0;ON;;;;;N;;;;;
+1D211;GREEK VOCAL NOTATION SYMBOL-18;So;0;ON;;;;;N;;;;;
+1D212;GREEK VOCAL NOTATION SYMBOL-19;So;0;ON;;;;;N;;;;;
+1D213;GREEK VOCAL NOTATION SYMBOL-20;So;0;ON;;;;;N;;;;;
+1D214;GREEK VOCAL NOTATION SYMBOL-21;So;0;ON;;;;;N;;;;;
+1D215;GREEK VOCAL NOTATION SYMBOL-22;So;0;ON;;;;;N;;;;;
+1D216;GREEK VOCAL NOTATION SYMBOL-23;So;0;ON;;;;;N;;;;;
+1D217;GREEK VOCAL NOTATION SYMBOL-24;So;0;ON;;;;;N;;;;;
+1D218;GREEK VOCAL NOTATION SYMBOL-50;So;0;ON;;;;;N;;;;;
+1D219;GREEK VOCAL NOTATION SYMBOL-51;So;0;ON;;;;;N;;;;;
+1D21A;GREEK VOCAL NOTATION SYMBOL-52;So;0;ON;;;;;N;;;;;
+1D21B;GREEK VOCAL NOTATION SYMBOL-53;So;0;ON;;;;;N;;;;;
+1D21C;GREEK VOCAL NOTATION SYMBOL-54;So;0;ON;;;;;N;;;;;
+1D21D;GREEK INSTRUMENTAL NOTATION SYMBOL-1;So;0;ON;;;;;N;;;;;
+1D21E;GREEK INSTRUMENTAL NOTATION SYMBOL-2;So;0;ON;;;;;N;;;;;
+1D21F;GREEK INSTRUMENTAL NOTATION SYMBOL-4;So;0;ON;;;;;N;;;;;
+1D220;GREEK INSTRUMENTAL NOTATION SYMBOL-5;So;0;ON;;;;;N;;;;;
+1D221;GREEK INSTRUMENTAL NOTATION SYMBOL-7;So;0;ON;;;;;N;;;;;
+1D222;GREEK INSTRUMENTAL NOTATION SYMBOL-8;So;0;ON;;;;;N;;;;;
+1D223;GREEK INSTRUMENTAL NOTATION SYMBOL-11;So;0;ON;;;;;N;;;;;
+1D224;GREEK INSTRUMENTAL NOTATION SYMBOL-12;So;0;ON;;;;;N;;;;;
+1D225;GREEK INSTRUMENTAL NOTATION SYMBOL-13;So;0;ON;;;;;N;;;;;
+1D226;GREEK INSTRUMENTAL NOTATION SYMBOL-14;So;0;ON;;;;;N;;;;;
+1D227;GREEK INSTRUMENTAL NOTATION SYMBOL-17;So;0;ON;;;;;N;;;;;
+1D228;GREEK INSTRUMENTAL NOTATION SYMBOL-18;So;0;ON;;;;;N;;;;;
+1D229;GREEK INSTRUMENTAL NOTATION SYMBOL-19;So;0;ON;;;;;N;;;;;
+1D22A;GREEK INSTRUMENTAL NOTATION SYMBOL-23;So;0;ON;;;;;N;;;;;
+1D22B;GREEK INSTRUMENTAL NOTATION SYMBOL-24;So;0;ON;;;;;N;;;;;
+1D22C;GREEK INSTRUMENTAL NOTATION SYMBOL-25;So;0;ON;;;;;N;;;;;
+1D22D;GREEK INSTRUMENTAL NOTATION SYMBOL-26;So;0;ON;;;;;N;;;;;
+1D22E;GREEK INSTRUMENTAL NOTATION SYMBOL-27;So;0;ON;;;;;N;;;;;
+1D22F;GREEK INSTRUMENTAL NOTATION SYMBOL-29;So;0;ON;;;;;N;;;;;
+1D230;GREEK INSTRUMENTAL NOTATION SYMBOL-30;So;0;ON;;;;;N;;;;;
+1D231;GREEK INSTRUMENTAL NOTATION SYMBOL-32;So;0;ON;;;;;N;;;;;
+1D232;GREEK INSTRUMENTAL NOTATION SYMBOL-36;So;0;ON;;;;;N;;;;;
+1D233;GREEK INSTRUMENTAL NOTATION SYMBOL-37;So;0;ON;;;;;N;;;;;
+1D234;GREEK INSTRUMENTAL NOTATION SYMBOL-38;So;0;ON;;;;;N;;;;;
+1D235;GREEK INSTRUMENTAL NOTATION SYMBOL-39;So;0;ON;;;;;N;;;;;
+1D236;GREEK INSTRUMENTAL NOTATION SYMBOL-40;So;0;ON;;;;;N;;;;;
+1D237;GREEK INSTRUMENTAL NOTATION SYMBOL-42;So;0;ON;;;;;N;;;;;
+1D238;GREEK INSTRUMENTAL NOTATION SYMBOL-43;So;0;ON;;;;;N;;;;;
+1D239;GREEK INSTRUMENTAL NOTATION SYMBOL-45;So;0;ON;;;;;N;;;;;
+1D23A;GREEK INSTRUMENTAL NOTATION SYMBOL-47;So;0;ON;;;;;N;;;;;
+1D23B;GREEK INSTRUMENTAL NOTATION SYMBOL-48;So;0;ON;;;;;N;;;;;
+1D23C;GREEK INSTRUMENTAL NOTATION SYMBOL-49;So;0;ON;;;;;N;;;;;
+1D23D;GREEK INSTRUMENTAL NOTATION SYMBOL-50;So;0;ON;;;;;N;;;;;
+1D23E;GREEK INSTRUMENTAL NOTATION SYMBOL-51;So;0;ON;;;;;N;;;;;
+1D23F;GREEK INSTRUMENTAL NOTATION SYMBOL-52;So;0;ON;;;;;N;;;;;
+1D240;GREEK INSTRUMENTAL NOTATION SYMBOL-53;So;0;ON;;;;;N;;;;;
+1D241;GREEK INSTRUMENTAL NOTATION SYMBOL-54;So;0;ON;;;;;N;;;;;
+1D242;COMBINING GREEK MUSICAL TRISEME;Mn;230;NSM;;;;;N;;;;;
+1D243;COMBINING GREEK MUSICAL TETRASEME;Mn;230;NSM;;;;;N;;;;;
+1D244;COMBINING GREEK MUSICAL PENTASEME;Mn;230;NSM;;;;;N;;;;;
+1D245;GREEK MUSICAL LEIMMA;So;0;ON;;;;;N;;;;;
+1D300;MONOGRAM FOR EARTH;So;0;ON;;;;;N;;;;;
+1D301;DIGRAM FOR HEAVENLY EARTH;So;0;ON;;;;;N;;;;;
+1D302;DIGRAM FOR HUMAN EARTH;So;0;ON;;;;;N;;;;;
+1D303;DIGRAM FOR EARTHLY HEAVEN;So;0;ON;;;;;N;;;;;
+1D304;DIGRAM FOR EARTHLY HUMAN;So;0;ON;;;;;N;;;;;
+1D305;DIGRAM FOR EARTH;So;0;ON;;;;;N;;;;;
+1D306;TETRAGRAM FOR CENTRE;So;0;ON;;;;;N;;;;;
+1D307;TETRAGRAM FOR FULL CIRCLE;So;0;ON;;;;;N;;;;;
+1D308;TETRAGRAM FOR MIRED;So;0;ON;;;;;N;;;;;
+1D309;TETRAGRAM FOR BARRIER;So;0;ON;;;;;N;;;;;
+1D30A;TETRAGRAM FOR KEEPING SMALL;So;0;ON;;;;;N;;;;;
+1D30B;TETRAGRAM FOR CONTRARIETY;So;0;ON;;;;;N;;;;;
+1D30C;TETRAGRAM FOR ASCENT;So;0;ON;;;;;N;;;;;
+1D30D;TETRAGRAM FOR OPPOSITION;So;0;ON;;;;;N;;;;;
+1D30E;TETRAGRAM FOR BRANCHING OUT;So;0;ON;;;;;N;;;;;
+1D30F;TETRAGRAM FOR DEFECTIVENESS OR DISTORTION;So;0;ON;;;;;N;;;;;
+1D310;TETRAGRAM FOR DIVERGENCE;So;0;ON;;;;;N;;;;;
+1D311;TETRAGRAM FOR YOUTHFULNESS;So;0;ON;;;;;N;;;;;
+1D312;TETRAGRAM FOR INCREASE;So;0;ON;;;;;N;;;;;
+1D313;TETRAGRAM FOR PENETRATION;So;0;ON;;;;;N;;;;;
+1D314;TETRAGRAM FOR REACH;So;0;ON;;;;;N;;;;;
+1D315;TETRAGRAM FOR CONTACT;So;0;ON;;;;;N;;;;;
+1D316;TETRAGRAM FOR HOLDING BACK;So;0;ON;;;;;N;;;;;
+1D317;TETRAGRAM FOR WAITING;So;0;ON;;;;;N;;;;;
+1D318;TETRAGRAM FOR FOLLOWING;So;0;ON;;;;;N;;;;;
+1D319;TETRAGRAM FOR ADVANCE;So;0;ON;;;;;N;;;;;
+1D31A;TETRAGRAM FOR RELEASE;So;0;ON;;;;;N;;;;;
+1D31B;TETRAGRAM FOR RESISTANCE;So;0;ON;;;;;N;;;;;
+1D31C;TETRAGRAM FOR EASE;So;0;ON;;;;;N;;;;;
+1D31D;TETRAGRAM FOR JOY;So;0;ON;;;;;N;;;;;
+1D31E;TETRAGRAM FOR CONTENTION;So;0;ON;;;;;N;;;;;
+1D31F;TETRAGRAM FOR ENDEAVOUR;So;0;ON;;;;;N;;;;;
+1D320;TETRAGRAM FOR DUTIES;So;0;ON;;;;;N;;;;;
+1D321;TETRAGRAM FOR CHANGE;So;0;ON;;;;;N;;;;;
+1D322;TETRAGRAM FOR DECISIVENESS;So;0;ON;;;;;N;;;;;
+1D323;TETRAGRAM FOR BOLD RESOLUTION;So;0;ON;;;;;N;;;;;
+1D324;TETRAGRAM FOR PACKING;So;0;ON;;;;;N;;;;;
+1D325;TETRAGRAM FOR LEGION;So;0;ON;;;;;N;;;;;
+1D326;TETRAGRAM FOR CLOSENESS;So;0;ON;;;;;N;;;;;
+1D327;TETRAGRAM FOR KINSHIP;So;0;ON;;;;;N;;;;;
+1D328;TETRAGRAM FOR GATHERING;So;0;ON;;;;;N;;;;;
+1D329;TETRAGRAM FOR STRENGTH;So;0;ON;;;;;N;;;;;
+1D32A;TETRAGRAM FOR PURITY;So;0;ON;;;;;N;;;;;
+1D32B;TETRAGRAM FOR FULLNESS;So;0;ON;;;;;N;;;;;
+1D32C;TETRAGRAM FOR RESIDENCE;So;0;ON;;;;;N;;;;;
+1D32D;TETRAGRAM FOR LAW OR MODEL;So;0;ON;;;;;N;;;;;
+1D32E;TETRAGRAM FOR RESPONSE;So;0;ON;;;;;N;;;;;
+1D32F;TETRAGRAM FOR GOING TO MEET;So;0;ON;;;;;N;;;;;
+1D330;TETRAGRAM FOR ENCOUNTERS;So;0;ON;;;;;N;;;;;
+1D331;TETRAGRAM FOR STOVE;So;0;ON;;;;;N;;;;;
+1D332;TETRAGRAM FOR GREATNESS;So;0;ON;;;;;N;;;;;
+1D333;TETRAGRAM FOR ENLARGEMENT;So;0;ON;;;;;N;;;;;
+1D334;TETRAGRAM FOR PATTERN;So;0;ON;;;;;N;;;;;
+1D335;TETRAGRAM FOR RITUAL;So;0;ON;;;;;N;;;;;
+1D336;TETRAGRAM FOR FLIGHT;So;0;ON;;;;;N;;;;;
+1D337;TETRAGRAM FOR VASTNESS OR WASTING;So;0;ON;;;;;N;;;;;
+1D338;TETRAGRAM FOR CONSTANCY;So;0;ON;;;;;N;;;;;
+1D339;TETRAGRAM FOR MEASURE;So;0;ON;;;;;N;;;;;
+1D33A;TETRAGRAM FOR ETERNITY;So;0;ON;;;;;N;;;;;
+1D33B;TETRAGRAM FOR UNITY;So;0;ON;;;;;N;;;;;
+1D33C;TETRAGRAM FOR DIMINISHMENT;So;0;ON;;;;;N;;;;;
+1D33D;TETRAGRAM FOR CLOSED MOUTH;So;0;ON;;;;;N;;;;;
+1D33E;TETRAGRAM FOR GUARDEDNESS;So;0;ON;;;;;N;;;;;
+1D33F;TETRAGRAM FOR GATHERING IN;So;0;ON;;;;;N;;;;;
+1D340;TETRAGRAM FOR MASSING;So;0;ON;;;;;N;;;;;
+1D341;TETRAGRAM FOR ACCUMULATION;So;0;ON;;;;;N;;;;;
+1D342;TETRAGRAM FOR EMBELLISHMENT;So;0;ON;;;;;N;;;;;
+1D343;TETRAGRAM FOR DOUBT;So;0;ON;;;;;N;;;;;
+1D344;TETRAGRAM FOR WATCH;So;0;ON;;;;;N;;;;;
+1D345;TETRAGRAM FOR SINKING;So;0;ON;;;;;N;;;;;
+1D346;TETRAGRAM FOR INNER;So;0;ON;;;;;N;;;;;
+1D347;TETRAGRAM FOR DEPARTURE;So;0;ON;;;;;N;;;;;
+1D348;TETRAGRAM FOR DARKENING;So;0;ON;;;;;N;;;;;
+1D349;TETRAGRAM FOR DIMMING;So;0;ON;;;;;N;;;;;
+1D34A;TETRAGRAM FOR EXHAUSTION;So;0;ON;;;;;N;;;;;
+1D34B;TETRAGRAM FOR SEVERANCE;So;0;ON;;;;;N;;;;;
+1D34C;TETRAGRAM FOR STOPPAGE;So;0;ON;;;;;N;;;;;
+1D34D;TETRAGRAM FOR HARDNESS;So;0;ON;;;;;N;;;;;
+1D34E;TETRAGRAM FOR COMPLETION;So;0;ON;;;;;N;;;;;
+1D34F;TETRAGRAM FOR CLOSURE;So;0;ON;;;;;N;;;;;
+1D350;TETRAGRAM FOR FAILURE;So;0;ON;;;;;N;;;;;
+1D351;TETRAGRAM FOR AGGRAVATION;So;0;ON;;;;;N;;;;;
+1D352;TETRAGRAM FOR COMPLIANCE;So;0;ON;;;;;N;;;;;
+1D353;TETRAGRAM FOR ON THE VERGE;So;0;ON;;;;;N;;;;;
+1D354;TETRAGRAM FOR DIFFICULTIES;So;0;ON;;;;;N;;;;;
+1D355;TETRAGRAM FOR LABOURING;So;0;ON;;;;;N;;;;;
+1D356;TETRAGRAM FOR FOSTERING;So;0;ON;;;;;N;;;;;
+1D400;MATHEMATICAL BOLD CAPITAL A;Lu;0;L;<font> 0041;;;;N;;;;;
+1D401;MATHEMATICAL BOLD CAPITAL B;Lu;0;L;<font> 0042;;;;N;;;;;
+1D402;MATHEMATICAL BOLD CAPITAL C;Lu;0;L;<font> 0043;;;;N;;;;;
+1D403;MATHEMATICAL BOLD CAPITAL D;Lu;0;L;<font> 0044;;;;N;;;;;
+1D404;MATHEMATICAL BOLD CAPITAL E;Lu;0;L;<font> 0045;;;;N;;;;;
+1D405;MATHEMATICAL BOLD CAPITAL F;Lu;0;L;<font> 0046;;;;N;;;;;
+1D406;MATHEMATICAL BOLD CAPITAL G;Lu;0;L;<font> 0047;;;;N;;;;;
+1D407;MATHEMATICAL BOLD CAPITAL H;Lu;0;L;<font> 0048;;;;N;;;;;
+1D408;MATHEMATICAL BOLD CAPITAL I;Lu;0;L;<font> 0049;;;;N;;;;;
+1D409;MATHEMATICAL BOLD CAPITAL J;Lu;0;L;<font> 004A;;;;N;;;;;
+1D40A;MATHEMATICAL BOLD CAPITAL K;Lu;0;L;<font> 004B;;;;N;;;;;
+1D40B;MATHEMATICAL BOLD CAPITAL L;Lu;0;L;<font> 004C;;;;N;;;;;
+1D40C;MATHEMATICAL BOLD CAPITAL M;Lu;0;L;<font> 004D;;;;N;;;;;
+1D40D;MATHEMATICAL BOLD CAPITAL N;Lu;0;L;<font> 004E;;;;N;;;;;
+1D40E;MATHEMATICAL BOLD CAPITAL O;Lu;0;L;<font> 004F;;;;N;;;;;
+1D40F;MATHEMATICAL BOLD CAPITAL P;Lu;0;L;<font> 0050;;;;N;;;;;
+1D410;MATHEMATICAL BOLD CAPITAL Q;Lu;0;L;<font> 0051;;;;N;;;;;
+1D411;MATHEMATICAL BOLD CAPITAL R;Lu;0;L;<font> 0052;;;;N;;;;;
+1D412;MATHEMATICAL BOLD CAPITAL S;Lu;0;L;<font> 0053;;;;N;;;;;
+1D413;MATHEMATICAL BOLD CAPITAL T;Lu;0;L;<font> 0054;;;;N;;;;;
+1D414;MATHEMATICAL BOLD CAPITAL U;Lu;0;L;<font> 0055;;;;N;;;;;
+1D415;MATHEMATICAL BOLD CAPITAL V;Lu;0;L;<font> 0056;;;;N;;;;;
+1D416;MATHEMATICAL BOLD CAPITAL W;Lu;0;L;<font> 0057;;;;N;;;;;
+1D417;MATHEMATICAL BOLD CAPITAL X;Lu;0;L;<font> 0058;;;;N;;;;;
+1D418;MATHEMATICAL BOLD CAPITAL Y;Lu;0;L;<font> 0059;;;;N;;;;;
+1D419;MATHEMATICAL BOLD CAPITAL Z;Lu;0;L;<font> 005A;;;;N;;;;;
+1D41A;MATHEMATICAL BOLD SMALL A;Ll;0;L;<font> 0061;;;;N;;;;;
+1D41B;MATHEMATICAL BOLD SMALL B;Ll;0;L;<font> 0062;;;;N;;;;;
+1D41C;MATHEMATICAL BOLD SMALL C;Ll;0;L;<font> 0063;;;;N;;;;;
+1D41D;MATHEMATICAL BOLD SMALL D;Ll;0;L;<font> 0064;;;;N;;;;;
+1D41E;MATHEMATICAL BOLD SMALL E;Ll;0;L;<font> 0065;;;;N;;;;;
+1D41F;MATHEMATICAL BOLD SMALL F;Ll;0;L;<font> 0066;;;;N;;;;;
+1D420;MATHEMATICAL BOLD SMALL G;Ll;0;L;<font> 0067;;;;N;;;;;
+1D421;MATHEMATICAL BOLD SMALL H;Ll;0;L;<font> 0068;;;;N;;;;;
+1D422;MATHEMATICAL BOLD SMALL I;Ll;0;L;<font> 0069;;;;N;;;;;
+1D423;MATHEMATICAL BOLD SMALL J;Ll;0;L;<font> 006A;;;;N;;;;;
+1D424;MATHEMATICAL BOLD SMALL K;Ll;0;L;<font> 006B;;;;N;;;;;
+1D425;MATHEMATICAL BOLD SMALL L;Ll;0;L;<font> 006C;;;;N;;;;;
+1D426;MATHEMATICAL BOLD SMALL M;Ll;0;L;<font> 006D;;;;N;;;;;
+1D427;MATHEMATICAL BOLD SMALL N;Ll;0;L;<font> 006E;;;;N;;;;;
+1D428;MATHEMATICAL BOLD SMALL O;Ll;0;L;<font> 006F;;;;N;;;;;
+1D429;MATHEMATICAL BOLD SMALL P;Ll;0;L;<font> 0070;;;;N;;;;;
+1D42A;MATHEMATICAL BOLD SMALL Q;Ll;0;L;<font> 0071;;;;N;;;;;
+1D42B;MATHEMATICAL BOLD SMALL R;Ll;0;L;<font> 0072;;;;N;;;;;
+1D42C;MATHEMATICAL BOLD SMALL S;Ll;0;L;<font> 0073;;;;N;;;;;
+1D42D;MATHEMATICAL BOLD SMALL T;Ll;0;L;<font> 0074;;;;N;;;;;
+1D42E;MATHEMATICAL BOLD SMALL U;Ll;0;L;<font> 0075;;;;N;;;;;
+1D42F;MATHEMATICAL BOLD SMALL V;Ll;0;L;<font> 0076;;;;N;;;;;
+1D430;MATHEMATICAL BOLD SMALL W;Ll;0;L;<font> 0077;;;;N;;;;;
+1D431;MATHEMATICAL BOLD SMALL X;Ll;0;L;<font> 0078;;;;N;;;;;
+1D432;MATHEMATICAL BOLD SMALL Y;Ll;0;L;<font> 0079;;;;N;;;;;
+1D433;MATHEMATICAL BOLD SMALL Z;Ll;0;L;<font> 007A;;;;N;;;;;
+1D434;MATHEMATICAL ITALIC CAPITAL A;Lu;0;L;<font> 0041;;;;N;;;;;
+1D435;MATHEMATICAL ITALIC CAPITAL B;Lu;0;L;<font> 0042;;;;N;;;;;
+1D436;MATHEMATICAL ITALIC CAPITAL C;Lu;0;L;<font> 0043;;;;N;;;;;
+1D437;MATHEMATICAL ITALIC CAPITAL D;Lu;0;L;<font> 0044;;;;N;;;;;
+1D438;MATHEMATICAL ITALIC CAPITAL E;Lu;0;L;<font> 0045;;;;N;;;;;
+1D439;MATHEMATICAL ITALIC CAPITAL F;Lu;0;L;<font> 0046;;;;N;;;;;
+1D43A;MATHEMATICAL ITALIC CAPITAL G;Lu;0;L;<font> 0047;;;;N;;;;;
+1D43B;MATHEMATICAL ITALIC CAPITAL H;Lu;0;L;<font> 0048;;;;N;;;;;
+1D43C;MATHEMATICAL ITALIC CAPITAL I;Lu;0;L;<font> 0049;;;;N;;;;;
+1D43D;MATHEMATICAL ITALIC CAPITAL J;Lu;0;L;<font> 004A;;;;N;;;;;
+1D43E;MATHEMATICAL ITALIC CAPITAL K;Lu;0;L;<font> 004B;;;;N;;;;;
+1D43F;MATHEMATICAL ITALIC CAPITAL L;Lu;0;L;<font> 004C;;;;N;;;;;
+1D440;MATHEMATICAL ITALIC CAPITAL M;Lu;0;L;<font> 004D;;;;N;;;;;
+1D441;MATHEMATICAL ITALIC CAPITAL N;Lu;0;L;<font> 004E;;;;N;;;;;
+1D442;MATHEMATICAL ITALIC CAPITAL O;Lu;0;L;<font> 004F;;;;N;;;;;
+1D443;MATHEMATICAL ITALIC CAPITAL P;Lu;0;L;<font> 0050;;;;N;;;;;
+1D444;MATHEMATICAL ITALIC CAPITAL Q;Lu;0;L;<font> 0051;;;;N;;;;;
+1D445;MATHEMATICAL ITALIC CAPITAL R;Lu;0;L;<font> 0052;;;;N;;;;;
+1D446;MATHEMATICAL ITALIC CAPITAL S;Lu;0;L;<font> 0053;;;;N;;;;;
+1D447;MATHEMATICAL ITALIC CAPITAL T;Lu;0;L;<font> 0054;;;;N;;;;;
+1D448;MATHEMATICAL ITALIC CAPITAL U;Lu;0;L;<font> 0055;;;;N;;;;;
+1D449;MATHEMATICAL ITALIC CAPITAL V;Lu;0;L;<font> 0056;;;;N;;;;;
+1D44A;MATHEMATICAL ITALIC CAPITAL W;Lu;0;L;<font> 0057;;;;N;;;;;
+1D44B;MATHEMATICAL ITALIC CAPITAL X;Lu;0;L;<font> 0058;;;;N;;;;;
+1D44C;MATHEMATICAL ITALIC CAPITAL Y;Lu;0;L;<font> 0059;;;;N;;;;;
+1D44D;MATHEMATICAL ITALIC CAPITAL Z;Lu;0;L;<font> 005A;;;;N;;;;;
+1D44E;MATHEMATICAL ITALIC SMALL A;Ll;0;L;<font> 0061;;;;N;;;;;
+1D44F;MATHEMATICAL ITALIC SMALL B;Ll;0;L;<font> 0062;;;;N;;;;;
+1D450;MATHEMATICAL ITALIC SMALL C;Ll;0;L;<font> 0063;;;;N;;;;;
+1D451;MATHEMATICAL ITALIC SMALL D;Ll;0;L;<font> 0064;;;;N;;;;;
+1D452;MATHEMATICAL ITALIC SMALL E;Ll;0;L;<font> 0065;;;;N;;;;;
+1D453;MATHEMATICAL ITALIC SMALL F;Ll;0;L;<font> 0066;;;;N;;;;;
+1D454;MATHEMATICAL ITALIC SMALL G;Ll;0;L;<font> 0067;;;;N;;;;;
+1D456;MATHEMATICAL ITALIC SMALL I;Ll;0;L;<font> 0069;;;;N;;;;;
+1D457;MATHEMATICAL ITALIC SMALL J;Ll;0;L;<font> 006A;;;;N;;;;;
+1D458;MATHEMATICAL ITALIC SMALL K;Ll;0;L;<font> 006B;;;;N;;;;;
+1D459;MATHEMATICAL ITALIC SMALL L;Ll;0;L;<font> 006C;;;;N;;;;;
+1D45A;MATHEMATICAL ITALIC SMALL M;Ll;0;L;<font> 006D;;;;N;;;;;
+1D45B;MATHEMATICAL ITALIC SMALL N;Ll;0;L;<font> 006E;;;;N;;;;;
+1D45C;MATHEMATICAL ITALIC SMALL O;Ll;0;L;<font> 006F;;;;N;;;;;
+1D45D;MATHEMATICAL ITALIC SMALL P;Ll;0;L;<font> 0070;;;;N;;;;;
+1D45E;MATHEMATICAL ITALIC SMALL Q;Ll;0;L;<font> 0071;;;;N;;;;;
+1D45F;MATHEMATICAL ITALIC SMALL R;Ll;0;L;<font> 0072;;;;N;;;;;
+1D460;MATHEMATICAL ITALIC SMALL S;Ll;0;L;<font> 0073;;;;N;;;;;
+1D461;MATHEMATICAL ITALIC SMALL T;Ll;0;L;<font> 0074;;;;N;;;;;
+1D462;MATHEMATICAL ITALIC SMALL U;Ll;0;L;<font> 0075;;;;N;;;;;
+1D463;MATHEMATICAL ITALIC SMALL V;Ll;0;L;<font> 0076;;;;N;;;;;
+1D464;MATHEMATICAL ITALIC SMALL W;Ll;0;L;<font> 0077;;;;N;;;;;
+1D465;MATHEMATICAL ITALIC SMALL X;Ll;0;L;<font> 0078;;;;N;;;;;
+1D466;MATHEMATICAL ITALIC SMALL Y;Ll;0;L;<font> 0079;;;;N;;;;;
+1D467;MATHEMATICAL ITALIC SMALL Z;Ll;0;L;<font> 007A;;;;N;;;;;
+1D468;MATHEMATICAL BOLD ITALIC CAPITAL A;Lu;0;L;<font> 0041;;;;N;;;;;
+1D469;MATHEMATICAL BOLD ITALIC CAPITAL B;Lu;0;L;<font> 0042;;;;N;;;;;
+1D46A;MATHEMATICAL BOLD ITALIC CAPITAL C;Lu;0;L;<font> 0043;;;;N;;;;;
+1D46B;MATHEMATICAL BOLD ITALIC CAPITAL D;Lu;0;L;<font> 0044;;;;N;;;;;
+1D46C;MATHEMATICAL BOLD ITALIC CAPITAL E;Lu;0;L;<font> 0045;;;;N;;;;;
+1D46D;MATHEMATICAL BOLD ITALIC CAPITAL F;Lu;0;L;<font> 0046;;;;N;;;;;
+1D46E;MATHEMATICAL BOLD ITALIC CAPITAL G;Lu;0;L;<font> 0047;;;;N;;;;;
+1D46F;MATHEMATICAL BOLD ITALIC CAPITAL H;Lu;0;L;<font> 0048;;;;N;;;;;
+1D470;MATHEMATICAL BOLD ITALIC CAPITAL I;Lu;0;L;<font> 0049;;;;N;;;;;
+1D471;MATHEMATICAL BOLD ITALIC CAPITAL J;Lu;0;L;<font> 004A;;;;N;;;;;
+1D472;MATHEMATICAL BOLD ITALIC CAPITAL K;Lu;0;L;<font> 004B;;;;N;;;;;
+1D473;MATHEMATICAL BOLD ITALIC CAPITAL L;Lu;0;L;<font> 004C;;;;N;;;;;
+1D474;MATHEMATICAL BOLD ITALIC CAPITAL M;Lu;0;L;<font> 004D;;;;N;;;;;
+1D475;MATHEMATICAL BOLD ITALIC CAPITAL N;Lu;0;L;<font> 004E;;;;N;;;;;
+1D476;MATHEMATICAL BOLD ITALIC CAPITAL O;Lu;0;L;<font> 004F;;;;N;;;;;
+1D477;MATHEMATICAL BOLD ITALIC CAPITAL P;Lu;0;L;<font> 0050;;;;N;;;;;
+1D478;MATHEMATICAL BOLD ITALIC CAPITAL Q;Lu;0;L;<font> 0051;;;;N;;;;;
+1D479;MATHEMATICAL BOLD ITALIC CAPITAL R;Lu;0;L;<font> 0052;;;;N;;;;;
+1D47A;MATHEMATICAL BOLD ITALIC CAPITAL S;Lu;0;L;<font> 0053;;;;N;;;;;
+1D47B;MATHEMATICAL BOLD ITALIC CAPITAL T;Lu;0;L;<font> 0054;;;;N;;;;;
+1D47C;MATHEMATICAL BOLD ITALIC CAPITAL U;Lu;0;L;<font> 0055;;;;N;;;;;
+1D47D;MATHEMATICAL BOLD ITALIC CAPITAL V;Lu;0;L;<font> 0056;;;;N;;;;;
+1D47E;MATHEMATICAL BOLD ITALIC CAPITAL W;Lu;0;L;<font> 0057;;;;N;;;;;
+1D47F;MATHEMATICAL BOLD ITALIC CAPITAL X;Lu;0;L;<font> 0058;;;;N;;;;;
+1D480;MATHEMATICAL BOLD ITALIC CAPITAL Y;Lu;0;L;<font> 0059;;;;N;;;;;
+1D481;MATHEMATICAL BOLD ITALIC CAPITAL Z;Lu;0;L;<font> 005A;;;;N;;;;;
+1D482;MATHEMATICAL BOLD ITALIC SMALL A;Ll;0;L;<font> 0061;;;;N;;;;;
+1D483;MATHEMATICAL BOLD ITALIC SMALL B;Ll;0;L;<font> 0062;;;;N;;;;;
+1D484;MATHEMATICAL BOLD ITALIC SMALL C;Ll;0;L;<font> 0063;;;;N;;;;;
+1D485;MATHEMATICAL BOLD ITALIC SMALL D;Ll;0;L;<font> 0064;;;;N;;;;;
+1D486;MATHEMATICAL BOLD ITALIC SMALL E;Ll;0;L;<font> 0065;;;;N;;;;;
+1D487;MATHEMATICAL BOLD ITALIC SMALL F;Ll;0;L;<font> 0066;;;;N;;;;;
+1D488;MATHEMATICAL BOLD ITALIC SMALL G;Ll;0;L;<font> 0067;;;;N;;;;;
+1D489;MATHEMATICAL BOLD ITALIC SMALL H;Ll;0;L;<font> 0068;;;;N;;;;;
+1D48A;MATHEMATICAL BOLD ITALIC SMALL I;Ll;0;L;<font> 0069;;;;N;;;;;
+1D48B;MATHEMATICAL BOLD ITALIC SMALL J;Ll;0;L;<font> 006A;;;;N;;;;;
+1D48C;MATHEMATICAL BOLD ITALIC SMALL K;Ll;0;L;<font> 006B;;;;N;;;;;
+1D48D;MATHEMATICAL BOLD ITALIC SMALL L;Ll;0;L;<font> 006C;;;;N;;;;;
+1D48E;MATHEMATICAL BOLD ITALIC SMALL M;Ll;0;L;<font> 006D;;;;N;;;;;
+1D48F;MATHEMATICAL BOLD ITALIC SMALL N;Ll;0;L;<font> 006E;;;;N;;;;;
+1D490;MATHEMATICAL BOLD ITALIC SMALL O;Ll;0;L;<font> 006F;;;;N;;;;;
+1D491;MATHEMATICAL BOLD ITALIC SMALL P;Ll;0;L;<font> 0070;;;;N;;;;;
+1D492;MATHEMATICAL BOLD ITALIC SMALL Q;Ll;0;L;<font> 0071;;;;N;;;;;
+1D493;MATHEMATICAL BOLD ITALIC SMALL R;Ll;0;L;<font> 0072;;;;N;;;;;
+1D494;MATHEMATICAL BOLD ITALIC SMALL S;Ll;0;L;<font> 0073;;;;N;;;;;
+1D495;MATHEMATICAL BOLD ITALIC SMALL T;Ll;0;L;<font> 0074;;;;N;;;;;
+1D496;MATHEMATICAL BOLD ITALIC SMALL U;Ll;0;L;<font> 0075;;;;N;;;;;
+1D497;MATHEMATICAL BOLD ITALIC SMALL V;Ll;0;L;<font> 0076;;;;N;;;;;
+1D498;MATHEMATICAL BOLD ITALIC SMALL W;Ll;0;L;<font> 0077;;;;N;;;;;
+1D499;MATHEMATICAL BOLD ITALIC SMALL X;Ll;0;L;<font> 0078;;;;N;;;;;
+1D49A;MATHEMATICAL BOLD ITALIC SMALL Y;Ll;0;L;<font> 0079;;;;N;;;;;
+1D49B;MATHEMATICAL BOLD ITALIC SMALL Z;Ll;0;L;<font> 007A;;;;N;;;;;
+1D49C;MATHEMATICAL SCRIPT CAPITAL A;Lu;0;L;<font> 0041;;;;N;;;;;
+1D49E;MATHEMATICAL SCRIPT CAPITAL C;Lu;0;L;<font> 0043;;;;N;;;;;
+1D49F;MATHEMATICAL SCRIPT CAPITAL D;Lu;0;L;<font> 0044;;;;N;;;;;
+1D4A2;MATHEMATICAL SCRIPT CAPITAL G;Lu;0;L;<font> 0047;;;;N;;;;;
+1D4A5;MATHEMATICAL SCRIPT CAPITAL J;Lu;0;L;<font> 004A;;;;N;;;;;
+1D4A6;MATHEMATICAL SCRIPT CAPITAL K;Lu;0;L;<font> 004B;;;;N;;;;;
+1D4A9;MATHEMATICAL SCRIPT CAPITAL N;Lu;0;L;<font> 004E;;;;N;;;;;
+1D4AA;MATHEMATICAL SCRIPT CAPITAL O;Lu;0;L;<font> 004F;;;;N;;;;;
+1D4AB;MATHEMATICAL SCRIPT CAPITAL P;Lu;0;L;<font> 0050;;;;N;;;;;
+1D4AC;MATHEMATICAL SCRIPT CAPITAL Q;Lu;0;L;<font> 0051;;;;N;;;;;
+1D4AE;MATHEMATICAL SCRIPT CAPITAL S;Lu;0;L;<font> 0053;;;;N;;;;;
+1D4AF;MATHEMATICAL SCRIPT CAPITAL T;Lu;0;L;<font> 0054;;;;N;;;;;
+1D4B0;MATHEMATICAL SCRIPT CAPITAL U;Lu;0;L;<font> 0055;;;;N;;;;;
+1D4B1;MATHEMATICAL SCRIPT CAPITAL V;Lu;0;L;<font> 0056;;;;N;;;;;
+1D4B2;MATHEMATICAL SCRIPT CAPITAL W;Lu;0;L;<font> 0057;;;;N;;;;;
+1D4B3;MATHEMATICAL SCRIPT CAPITAL X;Lu;0;L;<font> 0058;;;;N;;;;;
+1D4B4;MATHEMATICAL SCRIPT CAPITAL Y;Lu;0;L;<font> 0059;;;;N;;;;;
+1D4B5;MATHEMATICAL SCRIPT CAPITAL Z;Lu;0;L;<font> 005A;;;;N;;;;;
+1D4B6;MATHEMATICAL SCRIPT SMALL A;Ll;0;L;<font> 0061;;;;N;;;;;
+1D4B7;MATHEMATICAL SCRIPT SMALL B;Ll;0;L;<font> 0062;;;;N;;;;;
+1D4B8;MATHEMATICAL SCRIPT SMALL C;Ll;0;L;<font> 0063;;;;N;;;;;
+1D4B9;MATHEMATICAL SCRIPT SMALL D;Ll;0;L;<font> 0064;;;;N;;;;;
+1D4BB;MATHEMATICAL SCRIPT SMALL F;Ll;0;L;<font> 0066;;;;N;;;;;
+1D4BD;MATHEMATICAL SCRIPT SMALL H;Ll;0;L;<font> 0068;;;;N;;;;;
+1D4BE;MATHEMATICAL SCRIPT SMALL I;Ll;0;L;<font> 0069;;;;N;;;;;
+1D4BF;MATHEMATICAL SCRIPT SMALL J;Ll;0;L;<font> 006A;;;;N;;;;;
+1D4C0;MATHEMATICAL SCRIPT SMALL K;Ll;0;L;<font> 006B;;;;N;;;;;
+1D4C1;MATHEMATICAL SCRIPT SMALL L;Ll;0;L;<font> 006C;;;;N;;;;;
+1D4C2;MATHEMATICAL SCRIPT SMALL M;Ll;0;L;<font> 006D;;;;N;;;;;
+1D4C3;MATHEMATICAL SCRIPT SMALL N;Ll;0;L;<font> 006E;;;;N;;;;;
+1D4C5;MATHEMATICAL SCRIPT SMALL P;Ll;0;L;<font> 0070;;;;N;;;;;
+1D4C6;MATHEMATICAL SCRIPT SMALL Q;Ll;0;L;<font> 0071;;;;N;;;;;
+1D4C7;MATHEMATICAL SCRIPT SMALL R;Ll;0;L;<font> 0072;;;;N;;;;;
+1D4C8;MATHEMATICAL SCRIPT SMALL S;Ll;0;L;<font> 0073;;;;N;;;;;
+1D4C9;MATHEMATICAL SCRIPT SMALL T;Ll;0;L;<font> 0074;;;;N;;;;;
+1D4CA;MATHEMATICAL SCRIPT SMALL U;Ll;0;L;<font> 0075;;;;N;;;;;
+1D4CB;MATHEMATICAL SCRIPT SMALL V;Ll;0;L;<font> 0076;;;;N;;;;;
+1D4CC;MATHEMATICAL SCRIPT SMALL W;Ll;0;L;<font> 0077;;;;N;;;;;
+1D4CD;MATHEMATICAL SCRIPT SMALL X;Ll;0;L;<font> 0078;;;;N;;;;;
+1D4CE;MATHEMATICAL SCRIPT SMALL Y;Ll;0;L;<font> 0079;;;;N;;;;;
+1D4CF;MATHEMATICAL SCRIPT SMALL Z;Ll;0;L;<font> 007A;;;;N;;;;;
+1D4D0;MATHEMATICAL BOLD SCRIPT CAPITAL A;Lu;0;L;<font> 0041;;;;N;;;;;
+1D4D1;MATHEMATICAL BOLD SCRIPT CAPITAL B;Lu;0;L;<font> 0042;;;;N;;;;;
+1D4D2;MATHEMATICAL BOLD SCRIPT CAPITAL C;Lu;0;L;<font> 0043;;;;N;;;;;
+1D4D3;MATHEMATICAL BOLD SCRIPT CAPITAL D;Lu;0;L;<font> 0044;;;;N;;;;;
+1D4D4;MATHEMATICAL BOLD SCRIPT CAPITAL E;Lu;0;L;<font> 0045;;;;N;;;;;
+1D4D5;MATHEMATICAL BOLD SCRIPT CAPITAL F;Lu;0;L;<font> 0046;;;;N;;;;;
+1D4D6;MATHEMATICAL BOLD SCRIPT CAPITAL G;Lu;0;L;<font> 0047;;;;N;;;;;
+1D4D7;MATHEMATICAL BOLD SCRIPT CAPITAL H;Lu;0;L;<font> 0048;;;;N;;;;;
+1D4D8;MATHEMATICAL BOLD SCRIPT CAPITAL I;Lu;0;L;<font> 0049;;;;N;;;;;
+1D4D9;MATHEMATICAL BOLD SCRIPT CAPITAL J;Lu;0;L;<font> 004A;;;;N;;;;;
+1D4DA;MATHEMATICAL BOLD SCRIPT CAPITAL K;Lu;0;L;<font> 004B;;;;N;;;;;
+1D4DB;MATHEMATICAL BOLD SCRIPT CAPITAL L;Lu;0;L;<font> 004C;;;;N;;;;;
+1D4DC;MATHEMATICAL BOLD SCRIPT CAPITAL M;Lu;0;L;<font> 004D;;;;N;;;;;
+1D4DD;MATHEMATICAL BOLD SCRIPT CAPITAL N;Lu;0;L;<font> 004E;;;;N;;;;;
+1D4DE;MATHEMATICAL BOLD SCRIPT CAPITAL O;Lu;0;L;<font> 004F;;;;N;;;;;
+1D4DF;MATHEMATICAL BOLD SCRIPT CAPITAL P;Lu;0;L;<font> 0050;;;;N;;;;;
+1D4E0;MATHEMATICAL BOLD SCRIPT CAPITAL Q;Lu;0;L;<font> 0051;;;;N;;;;;
+1D4E1;MATHEMATICAL BOLD SCRIPT CAPITAL R;Lu;0;L;<font> 0052;;;;N;;;;;
+1D4E2;MATHEMATICAL BOLD SCRIPT CAPITAL S;Lu;0;L;<font> 0053;;;;N;;;;;
+1D4E3;MATHEMATICAL BOLD SCRIPT CAPITAL T;Lu;0;L;<font> 0054;;;;N;;;;;
+1D4E4;MATHEMATICAL BOLD SCRIPT CAPITAL U;Lu;0;L;<font> 0055;;;;N;;;;;
+1D4E5;MATHEMATICAL BOLD SCRIPT CAPITAL V;Lu;0;L;<font> 0056;;;;N;;;;;
+1D4E6;MATHEMATICAL BOLD SCRIPT CAPITAL W;Lu;0;L;<font> 0057;;;;N;;;;;
+1D4E7;MATHEMATICAL BOLD SCRIPT CAPITAL X;Lu;0;L;<font> 0058;;;;N;;;;;
+1D4E8;MATHEMATICAL BOLD SCRIPT CAPITAL Y;Lu;0;L;<font> 0059;;;;N;;;;;
+1D4E9;MATHEMATICAL BOLD SCRIPT CAPITAL Z;Lu;0;L;<font> 005A;;;;N;;;;;
+1D4EA;MATHEMATICAL BOLD SCRIPT SMALL A;Ll;0;L;<font> 0061;;;;N;;;;;
+1D4EB;MATHEMATICAL BOLD SCRIPT SMALL B;Ll;0;L;<font> 0062;;;;N;;;;;
+1D4EC;MATHEMATICAL BOLD SCRIPT SMALL C;Ll;0;L;<font> 0063;;;;N;;;;;
+1D4ED;MATHEMATICAL BOLD SCRIPT SMALL D;Ll;0;L;<font> 0064;;;;N;;;;;
+1D4EE;MATHEMATICAL BOLD SCRIPT SMALL E;Ll;0;L;<font> 0065;;;;N;;;;;
+1D4EF;MATHEMATICAL BOLD SCRIPT SMALL F;Ll;0;L;<font> 0066;;;;N;;;;;
+1D4F0;MATHEMATICAL BOLD SCRIPT SMALL G;Ll;0;L;<font> 0067;;;;N;;;;;
+1D4F1;MATHEMATICAL BOLD SCRIPT SMALL H;Ll;0;L;<font> 0068;;;;N;;;;;
+1D4F2;MATHEMATICAL BOLD SCRIPT SMALL I;Ll;0;L;<font> 0069;;;;N;;;;;
+1D4F3;MATHEMATICAL BOLD SCRIPT SMALL J;Ll;0;L;<font> 006A;;;;N;;;;;
+1D4F4;MATHEMATICAL BOLD SCRIPT SMALL K;Ll;0;L;<font> 006B;;;;N;;;;;
+1D4F5;MATHEMATICAL BOLD SCRIPT SMALL L;Ll;0;L;<font> 006C;;;;N;;;;;
+1D4F6;MATHEMATICAL BOLD SCRIPT SMALL M;Ll;0;L;<font> 006D;;;;N;;;;;
+1D4F7;MATHEMATICAL BOLD SCRIPT SMALL N;Ll;0;L;<font> 006E;;;;N;;;;;
+1D4F8;MATHEMATICAL BOLD SCRIPT SMALL O;Ll;0;L;<font> 006F;;;;N;;;;;
+1D4F9;MATHEMATICAL BOLD SCRIPT SMALL P;Ll;0;L;<font> 0070;;;;N;;;;;
+1D4FA;MATHEMATICAL BOLD SCRIPT SMALL Q;Ll;0;L;<font> 0071;;;;N;;;;;
+1D4FB;MATHEMATICAL BOLD SCRIPT SMALL R;Ll;0;L;<font> 0072;;;;N;;;;;
+1D4FC;MATHEMATICAL BOLD SCRIPT SMALL S;Ll;0;L;<font> 0073;;;;N;;;;;
+1D4FD;MATHEMATICAL BOLD SCRIPT SMALL T;Ll;0;L;<font> 0074;;;;N;;;;;
+1D4FE;MATHEMATICAL BOLD SCRIPT SMALL U;Ll;0;L;<font> 0075;;;;N;;;;;
+1D4FF;MATHEMATICAL BOLD SCRIPT SMALL V;Ll;0;L;<font> 0076;;;;N;;;;;
+1D500;MATHEMATICAL BOLD SCRIPT SMALL W;Ll;0;L;<font> 0077;;;;N;;;;;
+1D501;MATHEMATICAL BOLD SCRIPT SMALL X;Ll;0;L;<font> 0078;;;;N;;;;;
+1D502;MATHEMATICAL BOLD SCRIPT SMALL Y;Ll;0;L;<font> 0079;;;;N;;;;;
+1D503;MATHEMATICAL BOLD SCRIPT SMALL Z;Ll;0;L;<font> 007A;;;;N;;;;;
+1D504;MATHEMATICAL FRAKTUR CAPITAL A;Lu;0;L;<font> 0041;;;;N;;;;;
+1D505;MATHEMATICAL FRAKTUR CAPITAL B;Lu;0;L;<font> 0042;;;;N;;;;;
+1D507;MATHEMATICAL FRAKTUR CAPITAL D;Lu;0;L;<font> 0044;;;;N;;;;;
+1D508;MATHEMATICAL FRAKTUR CAPITAL E;Lu;0;L;<font> 0045;;;;N;;;;;
+1D509;MATHEMATICAL FRAKTUR CAPITAL F;Lu;0;L;<font> 0046;;;;N;;;;;
+1D50A;MATHEMATICAL FRAKTUR CAPITAL G;Lu;0;L;<font> 0047;;;;N;;;;;
+1D50D;MATHEMATICAL FRAKTUR CAPITAL J;Lu;0;L;<font> 004A;;;;N;;;;;
+1D50E;MATHEMATICAL FRAKTUR CAPITAL K;Lu;0;L;<font> 004B;;;;N;;;;;
+1D50F;MATHEMATICAL FRAKTUR CAPITAL L;Lu;0;L;<font> 004C;;;;N;;;;;
+1D510;MATHEMATICAL FRAKTUR CAPITAL M;Lu;0;L;<font> 004D;;;;N;;;;;
+1D511;MATHEMATICAL FRAKTUR CAPITAL N;Lu;0;L;<font> 004E;;;;N;;;;;
+1D512;MATHEMATICAL FRAKTUR CAPITAL O;Lu;0;L;<font> 004F;;;;N;;;;;
+1D513;MATHEMATICAL FRAKTUR CAPITAL P;Lu;0;L;<font> 0050;;;;N;;;;;
+1D514;MATHEMATICAL FRAKTUR CAPITAL Q;Lu;0;L;<font> 0051;;;;N;;;;;
+1D516;MATHEMATICAL FRAKTUR CAPITAL S;Lu;0;L;<font> 0053;;;;N;;;;;
+1D517;MATHEMATICAL FRAKTUR CAPITAL T;Lu;0;L;<font> 0054;;;;N;;;;;
+1D518;MATHEMATICAL FRAKTUR CAPITAL U;Lu;0;L;<font> 0055;;;;N;;;;;
+1D519;MATHEMATICAL FRAKTUR CAPITAL V;Lu;0;L;<font> 0056;;;;N;;;;;
+1D51A;MATHEMATICAL FRAKTUR CAPITAL W;Lu;0;L;<font> 0057;;;;N;;;;;
+1D51B;MATHEMATICAL FRAKTUR CAPITAL X;Lu;0;L;<font> 0058;;;;N;;;;;
+1D51C;MATHEMATICAL FRAKTUR CAPITAL Y;Lu;0;L;<font> 0059;;;;N;;;;;
+1D51E;MATHEMATICAL FRAKTUR SMALL A;Ll;0;L;<font> 0061;;;;N;;;;;
+1D51F;MATHEMATICAL FRAKTUR SMALL B;Ll;0;L;<font> 0062;;;;N;;;;;
+1D520;MATHEMATICAL FRAKTUR SMALL C;Ll;0;L;<font> 0063;;;;N;;;;;
+1D521;MATHEMATICAL FRAKTUR SMALL D;Ll;0;L;<font> 0064;;;;N;;;;;
+1D522;MATHEMATICAL FRAKTUR SMALL E;Ll;0;L;<font> 0065;;;;N;;;;;
+1D523;MATHEMATICAL FRAKTUR SMALL F;Ll;0;L;<font> 0066;;;;N;;;;;
+1D524;MATHEMATICAL FRAKTUR SMALL G;Ll;0;L;<font> 0067;;;;N;;;;;
+1D525;MATHEMATICAL FRAKTUR SMALL H;Ll;0;L;<font> 0068;;;;N;;;;;
+1D526;MATHEMATICAL FRAKTUR SMALL I;Ll;0;L;<font> 0069;;;;N;;;;;
+1D527;MATHEMATICAL FRAKTUR SMALL J;Ll;0;L;<font> 006A;;;;N;;;;;
+1D528;MATHEMATICAL FRAKTUR SMALL K;Ll;0;L;<font> 006B;;;;N;;;;;
+1D529;MATHEMATICAL FRAKTUR SMALL L;Ll;0;L;<font> 006C;;;;N;;;;;
+1D52A;MATHEMATICAL FRAKTUR SMALL M;Ll;0;L;<font> 006D;;;;N;;;;;
+1D52B;MATHEMATICAL FRAKTUR SMALL N;Ll;0;L;<font> 006E;;;;N;;;;;
+1D52C;MATHEMATICAL FRAKTUR SMALL O;Ll;0;L;<font> 006F;;;;N;;;;;
+1D52D;MATHEMATICAL FRAKTUR SMALL P;Ll;0;L;<font> 0070;;;;N;;;;;
+1D52E;MATHEMATICAL FRAKTUR SMALL Q;Ll;0;L;<font> 0071;;;;N;;;;;
+1D52F;MATHEMATICAL FRAKTUR SMALL R;Ll;0;L;<font> 0072;;;;N;;;;;
+1D530;MATHEMATICAL FRAKTUR SMALL S;Ll;0;L;<font> 0073;;;;N;;;;;
+1D531;MATHEMATICAL FRAKTUR SMALL T;Ll;0;L;<font> 0074;;;;N;;;;;
+1D532;MATHEMATICAL FRAKTUR SMALL U;Ll;0;L;<font> 0075;;;;N;;;;;
+1D533;MATHEMATICAL FRAKTUR SMALL V;Ll;0;L;<font> 0076;;;;N;;;;;
+1D534;MATHEMATICAL FRAKTUR SMALL W;Ll;0;L;<font> 0077;;;;N;;;;;
+1D535;MATHEMATICAL FRAKTUR SMALL X;Ll;0;L;<font> 0078;;;;N;;;;;
+1D536;MATHEMATICAL FRAKTUR SMALL Y;Ll;0;L;<font> 0079;;;;N;;;;;
+1D537;MATHEMATICAL FRAKTUR SMALL Z;Ll;0;L;<font> 007A;;;;N;;;;;
+1D538;MATHEMATICAL DOUBLE-STRUCK CAPITAL A;Lu;0;L;<font> 0041;;;;N;;;;;
+1D539;MATHEMATICAL DOUBLE-STRUCK CAPITAL B;Lu;0;L;<font> 0042;;;;N;;;;;
+1D53B;MATHEMATICAL DOUBLE-STRUCK CAPITAL D;Lu;0;L;<font> 0044;;;;N;;;;;
+1D53C;MATHEMATICAL DOUBLE-STRUCK CAPITAL E;Lu;0;L;<font> 0045;;;;N;;;;;
+1D53D;MATHEMATICAL DOUBLE-STRUCK CAPITAL F;Lu;0;L;<font> 0046;;;;N;;;;;
+1D53E;MATHEMATICAL DOUBLE-STRUCK CAPITAL G;Lu;0;L;<font> 0047;;;;N;;;;;
+1D540;MATHEMATICAL DOUBLE-STRUCK CAPITAL I;Lu;0;L;<font> 0049;;;;N;;;;;
+1D541;MATHEMATICAL DOUBLE-STRUCK CAPITAL J;Lu;0;L;<font> 004A;;;;N;;;;;
+1D542;MATHEMATICAL DOUBLE-STRUCK CAPITAL K;Lu;0;L;<font> 004B;;;;N;;;;;
+1D543;MATHEMATICAL DOUBLE-STRUCK CAPITAL L;Lu;0;L;<font> 004C;;;;N;;;;;
+1D544;MATHEMATICAL DOUBLE-STRUCK CAPITAL M;Lu;0;L;<font> 004D;;;;N;;;;;
+1D546;MATHEMATICAL DOUBLE-STRUCK CAPITAL O;Lu;0;L;<font> 004F;;;;N;;;;;
+1D54A;MATHEMATICAL DOUBLE-STRUCK CAPITAL S;Lu;0;L;<font> 0053;;;;N;;;;;
+1D54B;MATHEMATICAL DOUBLE-STRUCK CAPITAL T;Lu;0;L;<font> 0054;;;;N;;;;;
+1D54C;MATHEMATICAL DOUBLE-STRUCK CAPITAL U;Lu;0;L;<font> 0055;;;;N;;;;;
+1D54D;MATHEMATICAL DOUBLE-STRUCK CAPITAL V;Lu;0;L;<font> 0056;;;;N;;;;;
+1D54E;MATHEMATICAL DOUBLE-STRUCK CAPITAL W;Lu;0;L;<font> 0057;;;;N;;;;;
+1D54F;MATHEMATICAL DOUBLE-STRUCK CAPITAL X;Lu;0;L;<font> 0058;;;;N;;;;;
+1D550;MATHEMATICAL DOUBLE-STRUCK CAPITAL Y;Lu;0;L;<font> 0059;;;;N;;;;;
+1D552;MATHEMATICAL DOUBLE-STRUCK SMALL A;Ll;0;L;<font> 0061;;;;N;;;;;
+1D553;MATHEMATICAL DOUBLE-STRUCK SMALL B;Ll;0;L;<font> 0062;;;;N;;;;;
+1D554;MATHEMATICAL DOUBLE-STRUCK SMALL C;Ll;0;L;<font> 0063;;;;N;;;;;
+1D555;MATHEMATICAL DOUBLE-STRUCK SMALL D;Ll;0;L;<font> 0064;;;;N;;;;;
+1D556;MATHEMATICAL DOUBLE-STRUCK SMALL E;Ll;0;L;<font> 0065;;;;N;;;;;
+1D557;MATHEMATICAL DOUBLE-STRUCK SMALL F;Ll;0;L;<font> 0066;;;;N;;;;;
+1D558;MATHEMATICAL DOUBLE-STRUCK SMALL G;Ll;0;L;<font> 0067;;;;N;;;;;
+1D559;MATHEMATICAL DOUBLE-STRUCK SMALL H;Ll;0;L;<font> 0068;;;;N;;;;;
+1D55A;MATHEMATICAL DOUBLE-STRUCK SMALL I;Ll;0;L;<font> 0069;;;;N;;;;;
+1D55B;MATHEMATICAL DOUBLE-STRUCK SMALL J;Ll;0;L;<font> 006A;;;;N;;;;;
+1D55C;MATHEMATICAL DOUBLE-STRUCK SMALL K;Ll;0;L;<font> 006B;;;;N;;;;;
+1D55D;MATHEMATICAL DOUBLE-STRUCK SMALL L;Ll;0;L;<font> 006C;;;;N;;;;;
+1D55E;MATHEMATICAL DOUBLE-STRUCK SMALL M;Ll;0;L;<font> 006D;;;;N;;;;;
+1D55F;MATHEMATICAL DOUBLE-STRUCK SMALL N;Ll;0;L;<font> 006E;;;;N;;;;;
+1D560;MATHEMATICAL DOUBLE-STRUCK SMALL O;Ll;0;L;<font> 006F;;;;N;;;;;
+1D561;MATHEMATICAL DOUBLE-STRUCK SMALL P;Ll;0;L;<font> 0070;;;;N;;;;;
+1D562;MATHEMATICAL DOUBLE-STRUCK SMALL Q;Ll;0;L;<font> 0071;;;;N;;;;;
+1D563;MATHEMATICAL DOUBLE-STRUCK SMALL R;Ll;0;L;<font> 0072;;;;N;;;;;
+1D564;MATHEMATICAL DOUBLE-STRUCK SMALL S;Ll;0;L;<font> 0073;;;;N;;;;;
+1D565;MATHEMATICAL DOUBLE-STRUCK SMALL T;Ll;0;L;<font> 0074;;;;N;;;;;
+1D566;MATHEMATICAL DOUBLE-STRUCK SMALL U;Ll;0;L;<font> 0075;;;;N;;;;;
+1D567;MATHEMATICAL DOUBLE-STRUCK SMALL V;Ll;0;L;<font> 0076;;;;N;;;;;
+1D568;MATHEMATICAL DOUBLE-STRUCK SMALL W;Ll;0;L;<font> 0077;;;;N;;;;;
+1D569;MATHEMATICAL DOUBLE-STRUCK SMALL X;Ll;0;L;<font> 0078;;;;N;;;;;
+1D56A;MATHEMATICAL DOUBLE-STRUCK SMALL Y;Ll;0;L;<font> 0079;;;;N;;;;;
+1D56B;MATHEMATICAL DOUBLE-STRUCK SMALL Z;Ll;0;L;<font> 007A;;;;N;;;;;
+1D56C;MATHEMATICAL BOLD FRAKTUR CAPITAL A;Lu;0;L;<font> 0041;;;;N;;;;;
+1D56D;MATHEMATICAL BOLD FRAKTUR CAPITAL B;Lu;0;L;<font> 0042;;;;N;;;;;
+1D56E;MATHEMATICAL BOLD FRAKTUR CAPITAL C;Lu;0;L;<font> 0043;;;;N;;;;;
+1D56F;MATHEMATICAL BOLD FRAKTUR CAPITAL D;Lu;0;L;<font> 0044;;;;N;;;;;
+1D570;MATHEMATICAL BOLD FRAKTUR CAPITAL E;Lu;0;L;<font> 0045;;;;N;;;;;
+1D571;MATHEMATICAL BOLD FRAKTUR CAPITAL F;Lu;0;L;<font> 0046;;;;N;;;;;
+1D572;MATHEMATICAL BOLD FRAKTUR CAPITAL G;Lu;0;L;<font> 0047;;;;N;;;;;
+1D573;MATHEMATICAL BOLD FRAKTUR CAPITAL H;Lu;0;L;<font> 0048;;;;N;;;;;
+1D574;MATHEMATICAL BOLD FRAKTUR CAPITAL I;Lu;0;L;<font> 0049;;;;N;;;;;
+1D575;MATHEMATICAL BOLD FRAKTUR CAPITAL J;Lu;0;L;<font> 004A;;;;N;;;;;
+1D576;MATHEMATICAL BOLD FRAKTUR CAPITAL K;Lu;0;L;<font> 004B;;;;N;;;;;
+1D577;MATHEMATICAL BOLD FRAKTUR CAPITAL L;Lu;0;L;<font> 004C;;;;N;;;;;
+1D578;MATHEMATICAL BOLD FRAKTUR CAPITAL M;Lu;0;L;<font> 004D;;;;N;;;;;
+1D579;MATHEMATICAL BOLD FRAKTUR CAPITAL N;Lu;0;L;<font> 004E;;;;N;;;;;
+1D57A;MATHEMATICAL BOLD FRAKTUR CAPITAL O;Lu;0;L;<font> 004F;;;;N;;;;;
+1D57B;MATHEMATICAL BOLD FRAKTUR CAPITAL P;Lu;0;L;<font> 0050;;;;N;;;;;
+1D57C;MATHEMATICAL BOLD FRAKTUR CAPITAL Q;Lu;0;L;<font> 0051;;;;N;;;;;
+1D57D;MATHEMATICAL BOLD FRAKTUR CAPITAL R;Lu;0;L;<font> 0052;;;;N;;;;;
+1D57E;MATHEMATICAL BOLD FRAKTUR CAPITAL S;Lu;0;L;<font> 0053;;;;N;;;;;
+1D57F;MATHEMATICAL BOLD FRAKTUR CAPITAL T;Lu;0;L;<font> 0054;;;;N;;;;;
+1D580;MATHEMATICAL BOLD FRAKTUR CAPITAL U;Lu;0;L;<font> 0055;;;;N;;;;;
+1D581;MATHEMATICAL BOLD FRAKTUR CAPITAL V;Lu;0;L;<font> 0056;;;;N;;;;;
+1D582;MATHEMATICAL BOLD FRAKTUR CAPITAL W;Lu;0;L;<font> 0057;;;;N;;;;;
+1D583;MATHEMATICAL BOLD FRAKTUR CAPITAL X;Lu;0;L;<font> 0058;;;;N;;;;;
+1D584;MATHEMATICAL BOLD FRAKTUR CAPITAL Y;Lu;0;L;<font> 0059;;;;N;;;;;
+1D585;MATHEMATICAL BOLD FRAKTUR CAPITAL Z;Lu;0;L;<font> 005A;;;;N;;;;;
+1D586;MATHEMATICAL BOLD FRAKTUR SMALL A;Ll;0;L;<font> 0061;;;;N;;;;;
+1D587;MATHEMATICAL BOLD FRAKTUR SMALL B;Ll;0;L;<font> 0062;;;;N;;;;;
+1D588;MATHEMATICAL BOLD FRAKTUR SMALL C;Ll;0;L;<font> 0063;;;;N;;;;;
+1D589;MATHEMATICAL BOLD FRAKTUR SMALL D;Ll;0;L;<font> 0064;;;;N;;;;;
+1D58A;MATHEMATICAL BOLD FRAKTUR SMALL E;Ll;0;L;<font> 0065;;;;N;;;;;
+1D58B;MATHEMATICAL BOLD FRAKTUR SMALL F;Ll;0;L;<font> 0066;;;;N;;;;;
+1D58C;MATHEMATICAL BOLD FRAKTUR SMALL G;Ll;0;L;<font> 0067;;;;N;;;;;
+1D58D;MATHEMATICAL BOLD FRAKTUR SMALL H;Ll;0;L;<font> 0068;;;;N;;;;;
+1D58E;MATHEMATICAL BOLD FRAKTUR SMALL I;Ll;0;L;<font> 0069;;;;N;;;;;
+1D58F;MATHEMATICAL BOLD FRAKTUR SMALL J;Ll;0;L;<font> 006A;;;;N;;;;;
+1D590;MATHEMATICAL BOLD FRAKTUR SMALL K;Ll;0;L;<font> 006B;;;;N;;;;;
+1D591;MATHEMATICAL BOLD FRAKTUR SMALL L;Ll;0;L;<font> 006C;;;;N;;;;;
+1D592;MATHEMATICAL BOLD FRAKTUR SMALL M;Ll;0;L;<font> 006D;;;;N;;;;;
+1D593;MATHEMATICAL BOLD FRAKTUR SMALL N;Ll;0;L;<font> 006E;;;;N;;;;;
+1D594;MATHEMATICAL BOLD FRAKTUR SMALL O;Ll;0;L;<font> 006F;;;;N;;;;;
+1D595;MATHEMATICAL BOLD FRAKTUR SMALL P;Ll;0;L;<font> 0070;;;;N;;;;;
+1D596;MATHEMATICAL BOLD FRAKTUR SMALL Q;Ll;0;L;<font> 0071;;;;N;;;;;
+1D597;MATHEMATICAL BOLD FRAKTUR SMALL R;Ll;0;L;<font> 0072;;;;N;;;;;
+1D598;MATHEMATICAL BOLD FRAKTUR SMALL S;Ll;0;L;<font> 0073;;;;N;;;;;
+1D599;MATHEMATICAL BOLD FRAKTUR SMALL T;Ll;0;L;<font> 0074;;;;N;;;;;
+1D59A;MATHEMATICAL BOLD FRAKTUR SMALL U;Ll;0;L;<font> 0075;;;;N;;;;;
+1D59B;MATHEMATICAL BOLD FRAKTUR SMALL V;Ll;0;L;<font> 0076;;;;N;;;;;
+1D59C;MATHEMATICAL BOLD FRAKTUR SMALL W;Ll;0;L;<font> 0077;;;;N;;;;;
+1D59D;MATHEMATICAL BOLD FRAKTUR SMALL X;Ll;0;L;<font> 0078;;;;N;;;;;
+1D59E;MATHEMATICAL BOLD FRAKTUR SMALL Y;Ll;0;L;<font> 0079;;;;N;;;;;
+1D59F;MATHEMATICAL BOLD FRAKTUR SMALL Z;Ll;0;L;<font> 007A;;;;N;;;;;
+1D5A0;MATHEMATICAL SANS-SERIF CAPITAL A;Lu;0;L;<font> 0041;;;;N;;;;;
+1D5A1;MATHEMATICAL SANS-SERIF CAPITAL B;Lu;0;L;<font> 0042;;;;N;;;;;
+1D5A2;MATHEMATICAL SANS-SERIF CAPITAL C;Lu;0;L;<font> 0043;;;;N;;;;;
+1D5A3;MATHEMATICAL SANS-SERIF CAPITAL D;Lu;0;L;<font> 0044;;;;N;;;;;
+1D5A4;MATHEMATICAL SANS-SERIF CAPITAL E;Lu;0;L;<font> 0045;;;;N;;;;;
+1D5A5;MATHEMATICAL SANS-SERIF CAPITAL F;Lu;0;L;<font> 0046;;;;N;;;;;
+1D5A6;MATHEMATICAL SANS-SERIF CAPITAL G;Lu;0;L;<font> 0047;;;;N;;;;;
+1D5A7;MATHEMATICAL SANS-SERIF CAPITAL H;Lu;0;L;<font> 0048;;;;N;;;;;
+1D5A8;MATHEMATICAL SANS-SERIF CAPITAL I;Lu;0;L;<font> 0049;;;;N;;;;;
+1D5A9;MATHEMATICAL SANS-SERIF CAPITAL J;Lu;0;L;<font> 004A;;;;N;;;;;
+1D5AA;MATHEMATICAL SANS-SERIF CAPITAL K;Lu;0;L;<font> 004B;;;;N;;;;;
+1D5AB;MATHEMATICAL SANS-SERIF CAPITAL L;Lu;0;L;<font> 004C;;;;N;;;;;
+1D5AC;MATHEMATICAL SANS-SERIF CAPITAL M;Lu;0;L;<font> 004D;;;;N;;;;;
+1D5AD;MATHEMATICAL SANS-SERIF CAPITAL N;Lu;0;L;<font> 004E;;;;N;;;;;
+1D5AE;MATHEMATICAL SANS-SERIF CAPITAL O;Lu;0;L;<font> 004F;;;;N;;;;;
+1D5AF;MATHEMATICAL SANS-SERIF CAPITAL P;Lu;0;L;<font> 0050;;;;N;;;;;
+1D5B0;MATHEMATICAL SANS-SERIF CAPITAL Q;Lu;0;L;<font> 0051;;;;N;;;;;
+1D5B1;MATHEMATICAL SANS-SERIF CAPITAL R;Lu;0;L;<font> 0052;;;;N;;;;;
+1D5B2;MATHEMATICAL SANS-SERIF CAPITAL S;Lu;0;L;<font> 0053;;;;N;;;;;
+1D5B3;MATHEMATICAL SANS-SERIF CAPITAL T;Lu;0;L;<font> 0054;;;;N;;;;;
+1D5B4;MATHEMATICAL SANS-SERIF CAPITAL U;Lu;0;L;<font> 0055;;;;N;;;;;
+1D5B5;MATHEMATICAL SANS-SERIF CAPITAL V;Lu;0;L;<font> 0056;;;;N;;;;;
+1D5B6;MATHEMATICAL SANS-SERIF CAPITAL W;Lu;0;L;<font> 0057;;;;N;;;;;
+1D5B7;MATHEMATICAL SANS-SERIF CAPITAL X;Lu;0;L;<font> 0058;;;;N;;;;;
+1D5B8;MATHEMATICAL SANS-SERIF CAPITAL Y;Lu;0;L;<font> 0059;;;;N;;;;;
+1D5B9;MATHEMATICAL SANS-SERIF CAPITAL Z;Lu;0;L;<font> 005A;;;;N;;;;;
+1D5BA;MATHEMATICAL SANS-SERIF SMALL A;Ll;0;L;<font> 0061;;;;N;;;;;
+1D5BB;MATHEMATICAL SANS-SERIF SMALL B;Ll;0;L;<font> 0062;;;;N;;;;;
+1D5BC;MATHEMATICAL SANS-SERIF SMALL C;Ll;0;L;<font> 0063;;;;N;;;;;
+1D5BD;MATHEMATICAL SANS-SERIF SMALL D;Ll;0;L;<font> 0064;;;;N;;;;;
+1D5BE;MATHEMATICAL SANS-SERIF SMALL E;Ll;0;L;<font> 0065;;;;N;;;;;
+1D5BF;MATHEMATICAL SANS-SERIF SMALL F;Ll;0;L;<font> 0066;;;;N;;;;;
+1D5C0;MATHEMATICAL SANS-SERIF SMALL G;Ll;0;L;<font> 0067;;;;N;;;;;
+1D5C1;MATHEMATICAL SANS-SERIF SMALL H;Ll;0;L;<font> 0068;;;;N;;;;;
+1D5C2;MATHEMATICAL SANS-SERIF SMALL I;Ll;0;L;<font> 0069;;;;N;;;;;
+1D5C3;MATHEMATICAL SANS-SERIF SMALL J;Ll;0;L;<font> 006A;;;;N;;;;;
+1D5C4;MATHEMATICAL SANS-SERIF SMALL K;Ll;0;L;<font> 006B;;;;N;;;;;
+1D5C5;MATHEMATICAL SANS-SERIF SMALL L;Ll;0;L;<font> 006C;;;;N;;;;;
+1D5C6;MATHEMATICAL SANS-SERIF SMALL M;Ll;0;L;<font> 006D;;;;N;;;;;
+1D5C7;MATHEMATICAL SANS-SERIF SMALL N;Ll;0;L;<font> 006E;;;;N;;;;;
+1D5C8;MATHEMATICAL SANS-SERIF SMALL O;Ll;0;L;<font> 006F;;;;N;;;;;
+1D5C9;MATHEMATICAL SANS-SERIF SMALL P;Ll;0;L;<font> 0070;;;;N;;;;;
+1D5CA;MATHEMATICAL SANS-SERIF SMALL Q;Ll;0;L;<font> 0071;;;;N;;;;;
+1D5CB;MATHEMATICAL SANS-SERIF SMALL R;Ll;0;L;<font> 0072;;;;N;;;;;
+1D5CC;MATHEMATICAL SANS-SERIF SMALL S;Ll;0;L;<font> 0073;;;;N;;;;;
+1D5CD;MATHEMATICAL SANS-SERIF SMALL T;Ll;0;L;<font> 0074;;;;N;;;;;
+1D5CE;MATHEMATICAL SANS-SERIF SMALL U;Ll;0;L;<font> 0075;;;;N;;;;;
+1D5CF;MATHEMATICAL SANS-SERIF SMALL V;Ll;0;L;<font> 0076;;;;N;;;;;
+1D5D0;MATHEMATICAL SANS-SERIF SMALL W;Ll;0;L;<font> 0077;;;;N;;;;;
+1D5D1;MATHEMATICAL SANS-SERIF SMALL X;Ll;0;L;<font> 0078;;;;N;;;;;
+1D5D2;MATHEMATICAL SANS-SERIF SMALL Y;Ll;0;L;<font> 0079;;;;N;;;;;
+1D5D3;MATHEMATICAL SANS-SERIF SMALL Z;Ll;0;L;<font> 007A;;;;N;;;;;
+1D5D4;MATHEMATICAL SANS-SERIF BOLD CAPITAL A;Lu;0;L;<font> 0041;;;;N;;;;;
+1D5D5;MATHEMATICAL SANS-SERIF BOLD CAPITAL B;Lu;0;L;<font> 0042;;;;N;;;;;
+1D5D6;MATHEMATICAL SANS-SERIF BOLD CAPITAL C;Lu;0;L;<font> 0043;;;;N;;;;;
+1D5D7;MATHEMATICAL SANS-SERIF BOLD CAPITAL D;Lu;0;L;<font> 0044;;;;N;;;;;
+1D5D8;MATHEMATICAL SANS-SERIF BOLD CAPITAL E;Lu;0;L;<font> 0045;;;;N;;;;;
+1D5D9;MATHEMATICAL SANS-SERIF BOLD CAPITAL F;Lu;0;L;<font> 0046;;;;N;;;;;
+1D5DA;MATHEMATICAL SANS-SERIF BOLD CAPITAL G;Lu;0;L;<font> 0047;;;;N;;;;;
+1D5DB;MATHEMATICAL SANS-SERIF BOLD CAPITAL H;Lu;0;L;<font> 0048;;;;N;;;;;
+1D5DC;MATHEMATICAL SANS-SERIF BOLD CAPITAL I;Lu;0;L;<font> 0049;;;;N;;;;;
+1D5DD;MATHEMATICAL SANS-SERIF BOLD CAPITAL J;Lu;0;L;<font> 004A;;;;N;;;;;
+1D5DE;MATHEMATICAL SANS-SERIF BOLD CAPITAL K;Lu;0;L;<font> 004B;;;;N;;;;;
+1D5DF;MATHEMATICAL SANS-SERIF BOLD CAPITAL L;Lu;0;L;<font> 004C;;;;N;;;;;
+1D5E0;MATHEMATICAL SANS-SERIF BOLD CAPITAL M;Lu;0;L;<font> 004D;;;;N;;;;;
+1D5E1;MATHEMATICAL SANS-SERIF BOLD CAPITAL N;Lu;0;L;<font> 004E;;;;N;;;;;
+1D5E2;MATHEMATICAL SANS-SERIF BOLD CAPITAL O;Lu;0;L;<font> 004F;;;;N;;;;;
+1D5E3;MATHEMATICAL SANS-SERIF BOLD CAPITAL P;Lu;0;L;<font> 0050;;;;N;;;;;
+1D5E4;MATHEMATICAL SANS-SERIF BOLD CAPITAL Q;Lu;0;L;<font> 0051;;;;N;;;;;
+1D5E5;MATHEMATICAL SANS-SERIF BOLD CAPITAL R;Lu;0;L;<font> 0052;;;;N;;;;;
+1D5E6;MATHEMATICAL SANS-SERIF BOLD CAPITAL S;Lu;0;L;<font> 0053;;;;N;;;;;
+1D5E7;MATHEMATICAL SANS-SERIF BOLD CAPITAL T;Lu;0;L;<font> 0054;;;;N;;;;;
+1D5E8;MATHEMATICAL SANS-SERIF BOLD CAPITAL U;Lu;0;L;<font> 0055;;;;N;;;;;
+1D5E9;MATHEMATICAL SANS-SERIF BOLD CAPITAL V;Lu;0;L;<font> 0056;;;;N;;;;;
+1D5EA;MATHEMATICAL SANS-SERIF BOLD CAPITAL W;Lu;0;L;<font> 0057;;;;N;;;;;
+1D5EB;MATHEMATICAL SANS-SERIF BOLD CAPITAL X;Lu;0;L;<font> 0058;;;;N;;;;;
+1D5EC;MATHEMATICAL SANS-SERIF BOLD CAPITAL Y;Lu;0;L;<font> 0059;;;;N;;;;;
+1D5ED;MATHEMATICAL SANS-SERIF BOLD CAPITAL Z;Lu;0;L;<font> 005A;;;;N;;;;;
+1D5EE;MATHEMATICAL SANS-SERIF BOLD SMALL A;Ll;0;L;<font> 0061;;;;N;;;;;
+1D5EF;MATHEMATICAL SANS-SERIF BOLD SMALL B;Ll;0;L;<font> 0062;;;;N;;;;;
+1D5F0;MATHEMATICAL SANS-SERIF BOLD SMALL C;Ll;0;L;<font> 0063;;;;N;;;;;
+1D5F1;MATHEMATICAL SANS-SERIF BOLD SMALL D;Ll;0;L;<font> 0064;;;;N;;;;;
+1D5F2;MATHEMATICAL SANS-SERIF BOLD SMALL E;Ll;0;L;<font> 0065;;;;N;;;;;
+1D5F3;MATHEMATICAL SANS-SERIF BOLD SMALL F;Ll;0;L;<font> 0066;;;;N;;;;;
+1D5F4;MATHEMATICAL SANS-SERIF BOLD SMALL G;Ll;0;L;<font> 0067;;;;N;;;;;
+1D5F5;MATHEMATICAL SANS-SERIF BOLD SMALL H;Ll;0;L;<font> 0068;;;;N;;;;;
+1D5F6;MATHEMATICAL SANS-SERIF BOLD SMALL I;Ll;0;L;<font> 0069;;;;N;;;;;
+1D5F7;MATHEMATICAL SANS-SERIF BOLD SMALL J;Ll;0;L;<font> 006A;;;;N;;;;;
+1D5F8;MATHEMATICAL SANS-SERIF BOLD SMALL K;Ll;0;L;<font> 006B;;;;N;;;;;
+1D5F9;MATHEMATICAL SANS-SERIF BOLD SMALL L;Ll;0;L;<font> 006C;;;;N;;;;;
+1D5FA;MATHEMATICAL SANS-SERIF BOLD SMALL M;Ll;0;L;<font> 006D;;;;N;;;;;
+1D5FB;MATHEMATICAL SANS-SERIF BOLD SMALL N;Ll;0;L;<font> 006E;;;;N;;;;;
+1D5FC;MATHEMATICAL SANS-SERIF BOLD SMALL O;Ll;0;L;<font> 006F;;;;N;;;;;
+1D5FD;MATHEMATICAL SANS-SERIF BOLD SMALL P;Ll;0;L;<font> 0070;;;;N;;;;;
+1D5FE;MATHEMATICAL SANS-SERIF BOLD SMALL Q;Ll;0;L;<font> 0071;;;;N;;;;;
+1D5FF;MATHEMATICAL SANS-SERIF BOLD SMALL R;Ll;0;L;<font> 0072;;;;N;;;;;
+1D600;MATHEMATICAL SANS-SERIF BOLD SMALL S;Ll;0;L;<font> 0073;;;;N;;;;;
+1D601;MATHEMATICAL SANS-SERIF BOLD SMALL T;Ll;0;L;<font> 0074;;;;N;;;;;
+1D602;MATHEMATICAL SANS-SERIF BOLD SMALL U;Ll;0;L;<font> 0075;;;;N;;;;;
+1D603;MATHEMATICAL SANS-SERIF BOLD SMALL V;Ll;0;L;<font> 0076;;;;N;;;;;
+1D604;MATHEMATICAL SANS-SERIF BOLD SMALL W;Ll;0;L;<font> 0077;;;;N;;;;;
+1D605;MATHEMATICAL SANS-SERIF BOLD SMALL X;Ll;0;L;<font> 0078;;;;N;;;;;
+1D606;MATHEMATICAL SANS-SERIF BOLD SMALL Y;Ll;0;L;<font> 0079;;;;N;;;;;
+1D607;MATHEMATICAL SANS-SERIF BOLD SMALL Z;Ll;0;L;<font> 007A;;;;N;;;;;
+1D608;MATHEMATICAL SANS-SERIF ITALIC CAPITAL A;Lu;0;L;<font> 0041;;;;N;;;;;
+1D609;MATHEMATICAL SANS-SERIF ITALIC CAPITAL B;Lu;0;L;<font> 0042;;;;N;;;;;
+1D60A;MATHEMATICAL SANS-SERIF ITALIC CAPITAL C;Lu;0;L;<font> 0043;;;;N;;;;;
+1D60B;MATHEMATICAL SANS-SERIF ITALIC CAPITAL D;Lu;0;L;<font> 0044;;;;N;;;;;
+1D60C;MATHEMATICAL SANS-SERIF ITALIC CAPITAL E;Lu;0;L;<font> 0045;;;;N;;;;;
+1D60D;MATHEMATICAL SANS-SERIF ITALIC CAPITAL F;Lu;0;L;<font> 0046;;;;N;;;;;
+1D60E;MATHEMATICAL SANS-SERIF ITALIC CAPITAL G;Lu;0;L;<font> 0047;;;;N;;;;;
+1D60F;MATHEMATICAL SANS-SERIF ITALIC CAPITAL H;Lu;0;L;<font> 0048;;;;N;;;;;
+1D610;MATHEMATICAL SANS-SERIF ITALIC CAPITAL I;Lu;0;L;<font> 0049;;;;N;;;;;
+1D611;MATHEMATICAL SANS-SERIF ITALIC CAPITAL J;Lu;0;L;<font> 004A;;;;N;;;;;
+1D612;MATHEMATICAL SANS-SERIF ITALIC CAPITAL K;Lu;0;L;<font> 004B;;;;N;;;;;
+1D613;MATHEMATICAL SANS-SERIF ITALIC CAPITAL L;Lu;0;L;<font> 004C;;;;N;;;;;
+1D614;MATHEMATICAL SANS-SERIF ITALIC CAPITAL M;Lu;0;L;<font> 004D;;;;N;;;;;
+1D615;MATHEMATICAL SANS-SERIF ITALIC CAPITAL N;Lu;0;L;<font> 004E;;;;N;;;;;
+1D616;MATHEMATICAL SANS-SERIF ITALIC CAPITAL O;Lu;0;L;<font> 004F;;;;N;;;;;
+1D617;MATHEMATICAL SANS-SERIF ITALIC CAPITAL P;Lu;0;L;<font> 0050;;;;N;;;;;
+1D618;MATHEMATICAL SANS-SERIF ITALIC CAPITAL Q;Lu;0;L;<font> 0051;;;;N;;;;;
+1D619;MATHEMATICAL SANS-SERIF ITALIC CAPITAL R;Lu;0;L;<font> 0052;;;;N;;;;;
+1D61A;MATHEMATICAL SANS-SERIF ITALIC CAPITAL S;Lu;0;L;<font> 0053;;;;N;;;;;
+1D61B;MATHEMATICAL SANS-SERIF ITALIC CAPITAL T;Lu;0;L;<font> 0054;;;;N;;;;;
+1D61C;MATHEMATICAL SANS-SERIF ITALIC CAPITAL U;Lu;0;L;<font> 0055;;;;N;;;;;
+1D61D;MATHEMATICAL SANS-SERIF ITALIC CAPITAL V;Lu;0;L;<font> 0056;;;;N;;;;;
+1D61E;MATHEMATICAL SANS-SERIF ITALIC CAPITAL W;Lu;0;L;<font> 0057;;;;N;;;;;
+1D61F;MATHEMATICAL SANS-SERIF ITALIC CAPITAL X;Lu;0;L;<font> 0058;;;;N;;;;;
+1D620;MATHEMATICAL SANS-SERIF ITALIC CAPITAL Y;Lu;0;L;<font> 0059;;;;N;;;;;
+1D621;MATHEMATICAL SANS-SERIF ITALIC CAPITAL Z;Lu;0;L;<font> 005A;;;;N;;;;;
+1D622;MATHEMATICAL SANS-SERIF ITALIC SMALL A;Ll;0;L;<font> 0061;;;;N;;;;;
+1D623;MATHEMATICAL SANS-SERIF ITALIC SMALL B;Ll;0;L;<font> 0062;;;;N;;;;;
+1D624;MATHEMATICAL SANS-SERIF ITALIC SMALL C;Ll;0;L;<font> 0063;;;;N;;;;;
+1D625;MATHEMATICAL SANS-SERIF ITALIC SMALL D;Ll;0;L;<font> 0064;;;;N;;;;;
+1D626;MATHEMATICAL SANS-SERIF ITALIC SMALL E;Ll;0;L;<font> 0065;;;;N;;;;;
+1D627;MATHEMATICAL SANS-SERIF ITALIC SMALL F;Ll;0;L;<font> 0066;;;;N;;;;;
+1D628;MATHEMATICAL SANS-SERIF ITALIC SMALL G;Ll;0;L;<font> 0067;;;;N;;;;;
+1D629;MATHEMATICAL SANS-SERIF ITALIC SMALL H;Ll;0;L;<font> 0068;;;;N;;;;;
+1D62A;MATHEMATICAL SANS-SERIF ITALIC SMALL I;Ll;0;L;<font> 0069;;;;N;;;;;
+1D62B;MATHEMATICAL SANS-SERIF ITALIC SMALL J;Ll;0;L;<font> 006A;;;;N;;;;;
+1D62C;MATHEMATICAL SANS-SERIF ITALIC SMALL K;Ll;0;L;<font> 006B;;;;N;;;;;
+1D62D;MATHEMATICAL SANS-SERIF ITALIC SMALL L;Ll;0;L;<font> 006C;;;;N;;;;;
+1D62E;MATHEMATICAL SANS-SERIF ITALIC SMALL M;Ll;0;L;<font> 006D;;;;N;;;;;
+1D62F;MATHEMATICAL SANS-SERIF ITALIC SMALL N;Ll;0;L;<font> 006E;;;;N;;;;;
+1D630;MATHEMATICAL SANS-SERIF ITALIC SMALL O;Ll;0;L;<font> 006F;;;;N;;;;;
+1D631;MATHEMATICAL SANS-SERIF ITALIC SMALL P;Ll;0;L;<font> 0070;;;;N;;;;;
+1D632;MATHEMATICAL SANS-SERIF ITALIC SMALL Q;Ll;0;L;<font> 0071;;;;N;;;;;
+1D633;MATHEMATICAL SANS-SERIF ITALIC SMALL R;Ll;0;L;<font> 0072;;;;N;;;;;
+1D634;MATHEMATICAL SANS-SERIF ITALIC SMALL S;Ll;0;L;<font> 0073;;;;N;;;;;
+1D635;MATHEMATICAL SANS-SERIF ITALIC SMALL T;Ll;0;L;<font> 0074;;;;N;;;;;
+1D636;MATHEMATICAL SANS-SERIF ITALIC SMALL U;Ll;0;L;<font> 0075;;;;N;;;;;
+1D637;MATHEMATICAL SANS-SERIF ITALIC SMALL V;Ll;0;L;<font> 0076;;;;N;;;;;
+1D638;MATHEMATICAL SANS-SERIF ITALIC SMALL W;Ll;0;L;<font> 0077;;;;N;;;;;
+1D639;MATHEMATICAL SANS-SERIF ITALIC SMALL X;Ll;0;L;<font> 0078;;;;N;;;;;
+1D63A;MATHEMATICAL SANS-SERIF ITALIC SMALL Y;Ll;0;L;<font> 0079;;;;N;;;;;
+1D63B;MATHEMATICAL SANS-SERIF ITALIC SMALL Z;Ll;0;L;<font> 007A;;;;N;;;;;
+1D63C;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL A;Lu;0;L;<font> 0041;;;;N;;;;;
+1D63D;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL B;Lu;0;L;<font> 0042;;;;N;;;;;
+1D63E;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL C;Lu;0;L;<font> 0043;;;;N;;;;;
+1D63F;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL D;Lu;0;L;<font> 0044;;;;N;;;;;
+1D640;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL E;Lu;0;L;<font> 0045;;;;N;;;;;
+1D641;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL F;Lu;0;L;<font> 0046;;;;N;;;;;
+1D642;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL G;Lu;0;L;<font> 0047;;;;N;;;;;
+1D643;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL H;Lu;0;L;<font> 0048;;;;N;;;;;
+1D644;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL I;Lu;0;L;<font> 0049;;;;N;;;;;
+1D645;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL J;Lu;0;L;<font> 004A;;;;N;;;;;
+1D646;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL K;Lu;0;L;<font> 004B;;;;N;;;;;
+1D647;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL L;Lu;0;L;<font> 004C;;;;N;;;;;
+1D648;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL M;Lu;0;L;<font> 004D;;;;N;;;;;
+1D649;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL N;Lu;0;L;<font> 004E;;;;N;;;;;
+1D64A;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL O;Lu;0;L;<font> 004F;;;;N;;;;;
+1D64B;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL P;Lu;0;L;<font> 0050;;;;N;;;;;
+1D64C;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL Q;Lu;0;L;<font> 0051;;;;N;;;;;
+1D64D;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL R;Lu;0;L;<font> 0052;;;;N;;;;;
+1D64E;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL S;Lu;0;L;<font> 0053;;;;N;;;;;
+1D64F;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL T;Lu;0;L;<font> 0054;;;;N;;;;;
+1D650;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL U;Lu;0;L;<font> 0055;;;;N;;;;;
+1D651;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL V;Lu;0;L;<font> 0056;;;;N;;;;;
+1D652;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL W;Lu;0;L;<font> 0057;;;;N;;;;;
+1D653;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL X;Lu;0;L;<font> 0058;;;;N;;;;;
+1D654;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL Y;Lu;0;L;<font> 0059;;;;N;;;;;
+1D655;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL Z;Lu;0;L;<font> 005A;;;;N;;;;;
+1D656;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL A;Ll;0;L;<font> 0061;;;;N;;;;;
+1D657;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL B;Ll;0;L;<font> 0062;;;;N;;;;;
+1D658;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL C;Ll;0;L;<font> 0063;;;;N;;;;;
+1D659;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL D;Ll;0;L;<font> 0064;;;;N;;;;;
+1D65A;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL E;Ll;0;L;<font> 0065;;;;N;;;;;
+1D65B;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL F;Ll;0;L;<font> 0066;;;;N;;;;;
+1D65C;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL G;Ll;0;L;<font> 0067;;;;N;;;;;
+1D65D;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL H;Ll;0;L;<font> 0068;;;;N;;;;;
+1D65E;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL I;Ll;0;L;<font> 0069;;;;N;;;;;
+1D65F;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL J;Ll;0;L;<font> 006A;;;;N;;;;;
+1D660;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL K;Ll;0;L;<font> 006B;;;;N;;;;;
+1D661;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL L;Ll;0;L;<font> 006C;;;;N;;;;;
+1D662;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL M;Ll;0;L;<font> 006D;;;;N;;;;;
+1D663;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL N;Ll;0;L;<font> 006E;;;;N;;;;;
+1D664;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL O;Ll;0;L;<font> 006F;;;;N;;;;;
+1D665;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL P;Ll;0;L;<font> 0070;;;;N;;;;;
+1D666;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL Q;Ll;0;L;<font> 0071;;;;N;;;;;
+1D667;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL R;Ll;0;L;<font> 0072;;;;N;;;;;
+1D668;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL S;Ll;0;L;<font> 0073;;;;N;;;;;
+1D669;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL T;Ll;0;L;<font> 0074;;;;N;;;;;
+1D66A;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL U;Ll;0;L;<font> 0075;;;;N;;;;;
+1D66B;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL V;Ll;0;L;<font> 0076;;;;N;;;;;
+1D66C;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL W;Ll;0;L;<font> 0077;;;;N;;;;;
+1D66D;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL X;Ll;0;L;<font> 0078;;;;N;;;;;
+1D66E;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL Y;Ll;0;L;<font> 0079;;;;N;;;;;
+1D66F;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL Z;Ll;0;L;<font> 007A;;;;N;;;;;
+1D670;MATHEMATICAL MONOSPACE CAPITAL A;Lu;0;L;<font> 0041;;;;N;;;;;
+1D671;MATHEMATICAL MONOSPACE CAPITAL B;Lu;0;L;<font> 0042;;;;N;;;;;
+1D672;MATHEMATICAL MONOSPACE CAPITAL C;Lu;0;L;<font> 0043;;;;N;;;;;
+1D673;MATHEMATICAL MONOSPACE CAPITAL D;Lu;0;L;<font> 0044;;;;N;;;;;
+1D674;MATHEMATICAL MONOSPACE CAPITAL E;Lu;0;L;<font> 0045;;;;N;;;;;
+1D675;MATHEMATICAL MONOSPACE CAPITAL F;Lu;0;L;<font> 0046;;;;N;;;;;
+1D676;MATHEMATICAL MONOSPACE CAPITAL G;Lu;0;L;<font> 0047;;;;N;;;;;
+1D677;MATHEMATICAL MONOSPACE CAPITAL H;Lu;0;L;<font> 0048;;;;N;;;;;
+1D678;MATHEMATICAL MONOSPACE CAPITAL I;Lu;0;L;<font> 0049;;;;N;;;;;
+1D679;MATHEMATICAL MONOSPACE CAPITAL J;Lu;0;L;<font> 004A;;;;N;;;;;
+1D67A;MATHEMATICAL MONOSPACE CAPITAL K;Lu;0;L;<font> 004B;;;;N;;;;;
+1D67B;MATHEMATICAL MONOSPACE CAPITAL L;Lu;0;L;<font> 004C;;;;N;;;;;
+1D67C;MATHEMATICAL MONOSPACE CAPITAL M;Lu;0;L;<font> 004D;;;;N;;;;;
+1D67D;MATHEMATICAL MONOSPACE CAPITAL N;Lu;0;L;<font> 004E;;;;N;;;;;
+1D67E;MATHEMATICAL MONOSPACE CAPITAL O;Lu;0;L;<font> 004F;;;;N;;;;;
+1D67F;MATHEMATICAL MONOSPACE CAPITAL P;Lu;0;L;<font> 0050;;;;N;;;;;
+1D680;MATHEMATICAL MONOSPACE CAPITAL Q;Lu;0;L;<font> 0051;;;;N;;;;;
+1D681;MATHEMATICAL MONOSPACE CAPITAL R;Lu;0;L;<font> 0052;;;;N;;;;;
+1D682;MATHEMATICAL MONOSPACE CAPITAL S;Lu;0;L;<font> 0053;;;;N;;;;;
+1D683;MATHEMATICAL MONOSPACE CAPITAL T;Lu;0;L;<font> 0054;;;;N;;;;;
+1D684;MATHEMATICAL MONOSPACE CAPITAL U;Lu;0;L;<font> 0055;;;;N;;;;;
+1D685;MATHEMATICAL MONOSPACE CAPITAL V;Lu;0;L;<font> 0056;;;;N;;;;;
+1D686;MATHEMATICAL MONOSPACE CAPITAL W;Lu;0;L;<font> 0057;;;;N;;;;;
+1D687;MATHEMATICAL MONOSPACE CAPITAL X;Lu;0;L;<font> 0058;;;;N;;;;;
+1D688;MATHEMATICAL MONOSPACE CAPITAL Y;Lu;0;L;<font> 0059;;;;N;;;;;
+1D689;MATHEMATICAL MONOSPACE CAPITAL Z;Lu;0;L;<font> 005A;;;;N;;;;;
+1D68A;MATHEMATICAL MONOSPACE SMALL A;Ll;0;L;<font> 0061;;;;N;;;;;
+1D68B;MATHEMATICAL MONOSPACE SMALL B;Ll;0;L;<font> 0062;;;;N;;;;;
+1D68C;MATHEMATICAL MONOSPACE SMALL C;Ll;0;L;<font> 0063;;;;N;;;;;
+1D68D;MATHEMATICAL MONOSPACE SMALL D;Ll;0;L;<font> 0064;;;;N;;;;;
+1D68E;MATHEMATICAL MONOSPACE SMALL E;Ll;0;L;<font> 0065;;;;N;;;;;
+1D68F;MATHEMATICAL MONOSPACE SMALL F;Ll;0;L;<font> 0066;;;;N;;;;;
+1D690;MATHEMATICAL MONOSPACE SMALL G;Ll;0;L;<font> 0067;;;;N;;;;;
+1D691;MATHEMATICAL MONOSPACE SMALL H;Ll;0;L;<font> 0068;;;;N;;;;;
+1D692;MATHEMATICAL MONOSPACE SMALL I;Ll;0;L;<font> 0069;;;;N;;;;;
+1D693;MATHEMATICAL MONOSPACE SMALL J;Ll;0;L;<font> 006A;;;;N;;;;;
+1D694;MATHEMATICAL MONOSPACE SMALL K;Ll;0;L;<font> 006B;;;;N;;;;;
+1D695;MATHEMATICAL MONOSPACE SMALL L;Ll;0;L;<font> 006C;;;;N;;;;;
+1D696;MATHEMATICAL MONOSPACE SMALL M;Ll;0;L;<font> 006D;;;;N;;;;;
+1D697;MATHEMATICAL MONOSPACE SMALL N;Ll;0;L;<font> 006E;;;;N;;;;;
+1D698;MATHEMATICAL MONOSPACE SMALL O;Ll;0;L;<font> 006F;;;;N;;;;;
+1D699;MATHEMATICAL MONOSPACE SMALL P;Ll;0;L;<font> 0070;;;;N;;;;;
+1D69A;MATHEMATICAL MONOSPACE SMALL Q;Ll;0;L;<font> 0071;;;;N;;;;;
+1D69B;MATHEMATICAL MONOSPACE SMALL R;Ll;0;L;<font> 0072;;;;N;;;;;
+1D69C;MATHEMATICAL MONOSPACE SMALL S;Ll;0;L;<font> 0073;;;;N;;;;;
+1D69D;MATHEMATICAL MONOSPACE SMALL T;Ll;0;L;<font> 0074;;;;N;;;;;
+1D69E;MATHEMATICAL MONOSPACE SMALL U;Ll;0;L;<font> 0075;;;;N;;;;;
+1D69F;MATHEMATICAL MONOSPACE SMALL V;Ll;0;L;<font> 0076;;;;N;;;;;
+1D6A0;MATHEMATICAL MONOSPACE SMALL W;Ll;0;L;<font> 0077;;;;N;;;;;
+1D6A1;MATHEMATICAL MONOSPACE SMALL X;Ll;0;L;<font> 0078;;;;N;;;;;
+1D6A2;MATHEMATICAL MONOSPACE SMALL Y;Ll;0;L;<font> 0079;;;;N;;;;;
+1D6A3;MATHEMATICAL MONOSPACE SMALL Z;Ll;0;L;<font> 007A;;;;N;;;;;
+1D6A4;MATHEMATICAL ITALIC SMALL DOTLESS I;Ll;0;L;<font> 0131;;;;N;;;;;
+1D6A5;MATHEMATICAL ITALIC SMALL DOTLESS J;Ll;0;L;<font> 0237;;;;N;;;;;
+1D6A8;MATHEMATICAL BOLD CAPITAL ALPHA;Lu;0;L;<font> 0391;;;;N;;;;;
+1D6A9;MATHEMATICAL BOLD CAPITAL BETA;Lu;0;L;<font> 0392;;;;N;;;;;
+1D6AA;MATHEMATICAL BOLD CAPITAL GAMMA;Lu;0;L;<font> 0393;;;;N;;;;;
+1D6AB;MATHEMATICAL BOLD CAPITAL DELTA;Lu;0;L;<font> 0394;;;;N;;;;;
+1D6AC;MATHEMATICAL BOLD CAPITAL EPSILON;Lu;0;L;<font> 0395;;;;N;;;;;
+1D6AD;MATHEMATICAL BOLD CAPITAL ZETA;Lu;0;L;<font> 0396;;;;N;;;;;
+1D6AE;MATHEMATICAL BOLD CAPITAL ETA;Lu;0;L;<font> 0397;;;;N;;;;;
+1D6AF;MATHEMATICAL BOLD CAPITAL THETA;Lu;0;L;<font> 0398;;;;N;;;;;
+1D6B0;MATHEMATICAL BOLD CAPITAL IOTA;Lu;0;L;<font> 0399;;;;N;;;;;
+1D6B1;MATHEMATICAL BOLD CAPITAL KAPPA;Lu;0;L;<font> 039A;;;;N;;;;;
+1D6B2;MATHEMATICAL BOLD CAPITAL LAMDA;Lu;0;L;<font> 039B;;;;N;;;;;
+1D6B3;MATHEMATICAL BOLD CAPITAL MU;Lu;0;L;<font> 039C;;;;N;;;;;
+1D6B4;MATHEMATICAL BOLD CAPITAL NU;Lu;0;L;<font> 039D;;;;N;;;;;
+1D6B5;MATHEMATICAL BOLD CAPITAL XI;Lu;0;L;<font> 039E;;;;N;;;;;
+1D6B6;MATHEMATICAL BOLD CAPITAL OMICRON;Lu;0;L;<font> 039F;;;;N;;;;;
+1D6B7;MATHEMATICAL BOLD CAPITAL PI;Lu;0;L;<font> 03A0;;;;N;;;;;
+1D6B8;MATHEMATICAL BOLD CAPITAL RHO;Lu;0;L;<font> 03A1;;;;N;;;;;
+1D6B9;MATHEMATICAL BOLD CAPITAL THETA SYMBOL;Lu;0;L;<font> 03F4;;;;N;;;;;
+1D6BA;MATHEMATICAL BOLD CAPITAL SIGMA;Lu;0;L;<font> 03A3;;;;N;;;;;
+1D6BB;MATHEMATICAL BOLD CAPITAL TAU;Lu;0;L;<font> 03A4;;;;N;;;;;
+1D6BC;MATHEMATICAL BOLD CAPITAL UPSILON;Lu;0;L;<font> 03A5;;;;N;;;;;
+1D6BD;MATHEMATICAL BOLD CAPITAL PHI;Lu;0;L;<font> 03A6;;;;N;;;;;
+1D6BE;MATHEMATICAL BOLD CAPITAL CHI;Lu;0;L;<font> 03A7;;;;N;;;;;
+1D6BF;MATHEMATICAL BOLD CAPITAL PSI;Lu;0;L;<font> 03A8;;;;N;;;;;
+1D6C0;MATHEMATICAL BOLD CAPITAL OMEGA;Lu;0;L;<font> 03A9;;;;N;;;;;
+1D6C1;MATHEMATICAL BOLD NABLA;Sm;0;L;<font> 2207;;;;N;;;;;
+1D6C2;MATHEMATICAL BOLD SMALL ALPHA;Ll;0;L;<font> 03B1;;;;N;;;;;
+1D6C3;MATHEMATICAL BOLD SMALL BETA;Ll;0;L;<font> 03B2;;;;N;;;;;
+1D6C4;MATHEMATICAL BOLD SMALL GAMMA;Ll;0;L;<font> 03B3;;;;N;;;;;
+1D6C5;MATHEMATICAL BOLD SMALL DELTA;Ll;0;L;<font> 03B4;;;;N;;;;;
+1D6C6;MATHEMATICAL BOLD SMALL EPSILON;Ll;0;L;<font> 03B5;;;;N;;;;;
+1D6C7;MATHEMATICAL BOLD SMALL ZETA;Ll;0;L;<font> 03B6;;;;N;;;;;
+1D6C8;MATHEMATICAL BOLD SMALL ETA;Ll;0;L;<font> 03B7;;;;N;;;;;
+1D6C9;MATHEMATICAL BOLD SMALL THETA;Ll;0;L;<font> 03B8;;;;N;;;;;
+1D6CA;MATHEMATICAL BOLD SMALL IOTA;Ll;0;L;<font> 03B9;;;;N;;;;;
+1D6CB;MATHEMATICAL BOLD SMALL KAPPA;Ll;0;L;<font> 03BA;;;;N;;;;;
+1D6CC;MATHEMATICAL BOLD SMALL LAMDA;Ll;0;L;<font> 03BB;;;;N;;;;;
+1D6CD;MATHEMATICAL BOLD SMALL MU;Ll;0;L;<font> 03BC;;;;N;;;;;
+1D6CE;MATHEMATICAL BOLD SMALL NU;Ll;0;L;<font> 03BD;;;;N;;;;;
+1D6CF;MATHEMATICAL BOLD SMALL XI;Ll;0;L;<font> 03BE;;;;N;;;;;
+1D6D0;MATHEMATICAL BOLD SMALL OMICRON;Ll;0;L;<font> 03BF;;;;N;;;;;
+1D6D1;MATHEMATICAL BOLD SMALL PI;Ll;0;L;<font> 03C0;;;;N;;;;;
+1D6D2;MATHEMATICAL BOLD SMALL RHO;Ll;0;L;<font> 03C1;;;;N;;;;;
+1D6D3;MATHEMATICAL BOLD SMALL FINAL SIGMA;Ll;0;L;<font> 03C2;;;;N;;;;;
+1D6D4;MATHEMATICAL BOLD SMALL SIGMA;Ll;0;L;<font> 03C3;;;;N;;;;;
+1D6D5;MATHEMATICAL BOLD SMALL TAU;Ll;0;L;<font> 03C4;;;;N;;;;;
+1D6D6;MATHEMATICAL BOLD SMALL UPSILON;Ll;0;L;<font> 03C5;;;;N;;;;;
+1D6D7;MATHEMATICAL BOLD SMALL PHI;Ll;0;L;<font> 03C6;;;;N;;;;;
+1D6D8;MATHEMATICAL BOLD SMALL CHI;Ll;0;L;<font> 03C7;;;;N;;;;;
+1D6D9;MATHEMATICAL BOLD SMALL PSI;Ll;0;L;<font> 03C8;;;;N;;;;;
+1D6DA;MATHEMATICAL BOLD SMALL OMEGA;Ll;0;L;<font> 03C9;;;;N;;;;;
+1D6DB;MATHEMATICAL BOLD PARTIAL DIFFERENTIAL;Sm;0;L;<font> 2202;;;;N;;;;;
+1D6DC;MATHEMATICAL BOLD EPSILON SYMBOL;Ll;0;L;<font> 03F5;;;;N;;;;;
+1D6DD;MATHEMATICAL BOLD THETA SYMBOL;Ll;0;L;<font> 03D1;;;;N;;;;;
+1D6DE;MATHEMATICAL BOLD KAPPA SYMBOL;Ll;0;L;<font> 03F0;;;;N;;;;;
+1D6DF;MATHEMATICAL BOLD PHI SYMBOL;Ll;0;L;<font> 03D5;;;;N;;;;;
+1D6E0;MATHEMATICAL BOLD RHO SYMBOL;Ll;0;L;<font> 03F1;;;;N;;;;;
+1D6E1;MATHEMATICAL BOLD PI SYMBOL;Ll;0;L;<font> 03D6;;;;N;;;;;
+1D6E2;MATHEMATICAL ITALIC CAPITAL ALPHA;Lu;0;L;<font> 0391;;;;N;;;;;
+1D6E3;MATHEMATICAL ITALIC CAPITAL BETA;Lu;0;L;<font> 0392;;;;N;;;;;
+1D6E4;MATHEMATICAL ITALIC CAPITAL GAMMA;Lu;0;L;<font> 0393;;;;N;;;;;
+1D6E5;MATHEMATICAL ITALIC CAPITAL DELTA;Lu;0;L;<font> 0394;;;;N;;;;;
+1D6E6;MATHEMATICAL ITALIC CAPITAL EPSILON;Lu;0;L;<font> 0395;;;;N;;;;;
+1D6E7;MATHEMATICAL ITALIC CAPITAL ZETA;Lu;0;L;<font> 0396;;;;N;;;;;
+1D6E8;MATHEMATICAL ITALIC CAPITAL ETA;Lu;0;L;<font> 0397;;;;N;;;;;
+1D6E9;MATHEMATICAL ITALIC CAPITAL THETA;Lu;0;L;<font> 0398;;;;N;;;;;
+1D6EA;MATHEMATICAL ITALIC CAPITAL IOTA;Lu;0;L;<font> 0399;;;;N;;;;;
+1D6EB;MATHEMATICAL ITALIC CAPITAL KAPPA;Lu;0;L;<font> 039A;;;;N;;;;;
+1D6EC;MATHEMATICAL ITALIC CAPITAL LAMDA;Lu;0;L;<font> 039B;;;;N;;;;;
+1D6ED;MATHEMATICAL ITALIC CAPITAL MU;Lu;0;L;<font> 039C;;;;N;;;;;
+1D6EE;MATHEMATICAL ITALIC CAPITAL NU;Lu;0;L;<font> 039D;;;;N;;;;;
+1D6EF;MATHEMATICAL ITALIC CAPITAL XI;Lu;0;L;<font> 039E;;;;N;;;;;
+1D6F0;MATHEMATICAL ITALIC CAPITAL OMICRON;Lu;0;L;<font> 039F;;;;N;;;;;
+1D6F1;MATHEMATICAL ITALIC CAPITAL PI;Lu;0;L;<font> 03A0;;;;N;;;;;
+1D6F2;MATHEMATICAL ITALIC CAPITAL RHO;Lu;0;L;<font> 03A1;;;;N;;;;;
+1D6F3;MATHEMATICAL ITALIC CAPITAL THETA SYMBOL;Lu;0;L;<font> 03F4;;;;N;;;;;
+1D6F4;MATHEMATICAL ITALIC CAPITAL SIGMA;Lu;0;L;<font> 03A3;;;;N;;;;;
+1D6F5;MATHEMATICAL ITALIC CAPITAL TAU;Lu;0;L;<font> 03A4;;;;N;;;;;
+1D6F6;MATHEMATICAL ITALIC CAPITAL UPSILON;Lu;0;L;<font> 03A5;;;;N;;;;;
+1D6F7;MATHEMATICAL ITALIC CAPITAL PHI;Lu;0;L;<font> 03A6;;;;N;;;;;
+1D6F8;MATHEMATICAL ITALIC CAPITAL CHI;Lu;0;L;<font> 03A7;;;;N;;;;;
+1D6F9;MATHEMATICAL ITALIC CAPITAL PSI;Lu;0;L;<font> 03A8;;;;N;;;;;
+1D6FA;MATHEMATICAL ITALIC CAPITAL OMEGA;Lu;0;L;<font> 03A9;;;;N;;;;;
+1D6FB;MATHEMATICAL ITALIC NABLA;Sm;0;L;<font> 2207;;;;N;;;;;
+1D6FC;MATHEMATICAL ITALIC SMALL ALPHA;Ll;0;L;<font> 03B1;;;;N;;;;;
+1D6FD;MATHEMATICAL ITALIC SMALL BETA;Ll;0;L;<font> 03B2;;;;N;;;;;
+1D6FE;MATHEMATICAL ITALIC SMALL GAMMA;Ll;0;L;<font> 03B3;;;;N;;;;;
+1D6FF;MATHEMATICAL ITALIC SMALL DELTA;Ll;0;L;<font> 03B4;;;;N;;;;;
+1D700;MATHEMATICAL ITALIC SMALL EPSILON;Ll;0;L;<font> 03B5;;;;N;;;;;
+1D701;MATHEMATICAL ITALIC SMALL ZETA;Ll;0;L;<font> 03B6;;;;N;;;;;
+1D702;MATHEMATICAL ITALIC SMALL ETA;Ll;0;L;<font> 03B7;;;;N;;;;;
+1D703;MATHEMATICAL ITALIC SMALL THETA;Ll;0;L;<font> 03B8;;;;N;;;;;
+1D704;MATHEMATICAL ITALIC SMALL IOTA;Ll;0;L;<font> 03B9;;;;N;;;;;
+1D705;MATHEMATICAL ITALIC SMALL KAPPA;Ll;0;L;<font> 03BA;;;;N;;;;;
+1D706;MATHEMATICAL ITALIC SMALL LAMDA;Ll;0;L;<font> 03BB;;;;N;;;;;
+1D707;MATHEMATICAL ITALIC SMALL MU;Ll;0;L;<font> 03BC;;;;N;;;;;
+1D708;MATHEMATICAL ITALIC SMALL NU;Ll;0;L;<font> 03BD;;;;N;;;;;
+1D709;MATHEMATICAL ITALIC SMALL XI;Ll;0;L;<font> 03BE;;;;N;;;;;
+1D70A;MATHEMATICAL ITALIC SMALL OMICRON;Ll;0;L;<font> 03BF;;;;N;;;;;
+1D70B;MATHEMATICAL ITALIC SMALL PI;Ll;0;L;<font> 03C0;;;;N;;;;;
+1D70C;MATHEMATICAL ITALIC SMALL RHO;Ll;0;L;<font> 03C1;;;;N;;;;;
+1D70D;MATHEMATICAL ITALIC SMALL FINAL SIGMA;Ll;0;L;<font> 03C2;;;;N;;;;;
+1D70E;MATHEMATICAL ITALIC SMALL SIGMA;Ll;0;L;<font> 03C3;;;;N;;;;;
+1D70F;MATHEMATICAL ITALIC SMALL TAU;Ll;0;L;<font> 03C4;;;;N;;;;;
+1D710;MATHEMATICAL ITALIC SMALL UPSILON;Ll;0;L;<font> 03C5;;;;N;;;;;
+1D711;MATHEMATICAL ITALIC SMALL PHI;Ll;0;L;<font> 03C6;;;;N;;;;;
+1D712;MATHEMATICAL ITALIC SMALL CHI;Ll;0;L;<font> 03C7;;;;N;;;;;
+1D713;MATHEMATICAL ITALIC SMALL PSI;Ll;0;L;<font> 03C8;;;;N;;;;;
+1D714;MATHEMATICAL ITALIC SMALL OMEGA;Ll;0;L;<font> 03C9;;;;N;;;;;
+1D715;MATHEMATICAL ITALIC PARTIAL DIFFERENTIAL;Sm;0;L;<font> 2202;;;;N;;;;;
+1D716;MATHEMATICAL ITALIC EPSILON SYMBOL;Ll;0;L;<font> 03F5;;;;N;;;;;
+1D717;MATHEMATICAL ITALIC THETA SYMBOL;Ll;0;L;<font> 03D1;;;;N;;;;;
+1D718;MATHEMATICAL ITALIC KAPPA SYMBOL;Ll;0;L;<font> 03F0;;;;N;;;;;
+1D719;MATHEMATICAL ITALIC PHI SYMBOL;Ll;0;L;<font> 03D5;;;;N;;;;;
+1D71A;MATHEMATICAL ITALIC RHO SYMBOL;Ll;0;L;<font> 03F1;;;;N;;;;;
+1D71B;MATHEMATICAL ITALIC PI SYMBOL;Ll;0;L;<font> 03D6;;;;N;;;;;
+1D71C;MATHEMATICAL BOLD ITALIC CAPITAL ALPHA;Lu;0;L;<font> 0391;;;;N;;;;;
+1D71D;MATHEMATICAL BOLD ITALIC CAPITAL BETA;Lu;0;L;<font> 0392;;;;N;;;;;
+1D71E;MATHEMATICAL BOLD ITALIC CAPITAL GAMMA;Lu;0;L;<font> 0393;;;;N;;;;;
+1D71F;MATHEMATICAL BOLD ITALIC CAPITAL DELTA;Lu;0;L;<font> 0394;;;;N;;;;;
+1D720;MATHEMATICAL BOLD ITALIC CAPITAL EPSILON;Lu;0;L;<font> 0395;;;;N;;;;;
+1D721;MATHEMATICAL BOLD ITALIC CAPITAL ZETA;Lu;0;L;<font> 0396;;;;N;;;;;
+1D722;MATHEMATICAL BOLD ITALIC CAPITAL ETA;Lu;0;L;<font> 0397;;;;N;;;;;
+1D723;MATHEMATICAL BOLD ITALIC CAPITAL THETA;Lu;0;L;<font> 0398;;;;N;;;;;
+1D724;MATHEMATICAL BOLD ITALIC CAPITAL IOTA;Lu;0;L;<font> 0399;;;;N;;;;;
+1D725;MATHEMATICAL BOLD ITALIC CAPITAL KAPPA;Lu;0;L;<font> 039A;;;;N;;;;;
+1D726;MATHEMATICAL BOLD ITALIC CAPITAL LAMDA;Lu;0;L;<font> 039B;;;;N;;;;;
+1D727;MATHEMATICAL BOLD ITALIC CAPITAL MU;Lu;0;L;<font> 039C;;;;N;;;;;
+1D728;MATHEMATICAL BOLD ITALIC CAPITAL NU;Lu;0;L;<font> 039D;;;;N;;;;;
+1D729;MATHEMATICAL BOLD ITALIC CAPITAL XI;Lu;0;L;<font> 039E;;;;N;;;;;
+1D72A;MATHEMATICAL BOLD ITALIC CAPITAL OMICRON;Lu;0;L;<font> 039F;;;;N;;;;;
+1D72B;MATHEMATICAL BOLD ITALIC CAPITAL PI;Lu;0;L;<font> 03A0;;;;N;;;;;
+1D72C;MATHEMATICAL BOLD ITALIC CAPITAL RHO;Lu;0;L;<font> 03A1;;;;N;;;;;
+1D72D;MATHEMATICAL BOLD ITALIC CAPITAL THETA SYMBOL;Lu;0;L;<font> 03F4;;;;N;;;;;
+1D72E;MATHEMATICAL BOLD ITALIC CAPITAL SIGMA;Lu;0;L;<font> 03A3;;;;N;;;;;
+1D72F;MATHEMATICAL BOLD ITALIC CAPITAL TAU;Lu;0;L;<font> 03A4;;;;N;;;;;
+1D730;MATHEMATICAL BOLD ITALIC CAPITAL UPSILON;Lu;0;L;<font> 03A5;;;;N;;;;;
+1D731;MATHEMATICAL BOLD ITALIC CAPITAL PHI;Lu;0;L;<font> 03A6;;;;N;;;;;
+1D732;MATHEMATICAL BOLD ITALIC CAPITAL CHI;Lu;0;L;<font> 03A7;;;;N;;;;;
+1D733;MATHEMATICAL BOLD ITALIC CAPITAL PSI;Lu;0;L;<font> 03A8;;;;N;;;;;
+1D734;MATHEMATICAL BOLD ITALIC CAPITAL OMEGA;Lu;0;L;<font> 03A9;;;;N;;;;;
+1D735;MATHEMATICAL BOLD ITALIC NABLA;Sm;0;L;<font> 2207;;;;N;;;;;
+1D736;MATHEMATICAL BOLD ITALIC SMALL ALPHA;Ll;0;L;<font> 03B1;;;;N;;;;;
+1D737;MATHEMATICAL BOLD ITALIC SMALL BETA;Ll;0;L;<font> 03B2;;;;N;;;;;
+1D738;MATHEMATICAL BOLD ITALIC SMALL GAMMA;Ll;0;L;<font> 03B3;;;;N;;;;;
+1D739;MATHEMATICAL BOLD ITALIC SMALL DELTA;Ll;0;L;<font> 03B4;;;;N;;;;;
+1D73A;MATHEMATICAL BOLD ITALIC SMALL EPSILON;Ll;0;L;<font> 03B5;;;;N;;;;;
+1D73B;MATHEMATICAL BOLD ITALIC SMALL ZETA;Ll;0;L;<font> 03B6;;;;N;;;;;
+1D73C;MATHEMATICAL BOLD ITALIC SMALL ETA;Ll;0;L;<font> 03B7;;;;N;;;;;
+1D73D;MATHEMATICAL BOLD ITALIC SMALL THETA;Ll;0;L;<font> 03B8;;;;N;;;;;
+1D73E;MATHEMATICAL BOLD ITALIC SMALL IOTA;Ll;0;L;<font> 03B9;;;;N;;;;;
+1D73F;MATHEMATICAL BOLD ITALIC SMALL KAPPA;Ll;0;L;<font> 03BA;;;;N;;;;;
+1D740;MATHEMATICAL BOLD ITALIC SMALL LAMDA;Ll;0;L;<font> 03BB;;;;N;;;;;
+1D741;MATHEMATICAL BOLD ITALIC SMALL MU;Ll;0;L;<font> 03BC;;;;N;;;;;
+1D742;MATHEMATICAL BOLD ITALIC SMALL NU;Ll;0;L;<font> 03BD;;;;N;;;;;
+1D743;MATHEMATICAL BOLD ITALIC SMALL XI;Ll;0;L;<font> 03BE;;;;N;;;;;
+1D744;MATHEMATICAL BOLD ITALIC SMALL OMICRON;Ll;0;L;<font> 03BF;;;;N;;;;;
+1D745;MATHEMATICAL BOLD ITALIC SMALL PI;Ll;0;L;<font> 03C0;;;;N;;;;;
+1D746;MATHEMATICAL BOLD ITALIC SMALL RHO;Ll;0;L;<font> 03C1;;;;N;;;;;
+1D747;MATHEMATICAL BOLD ITALIC SMALL FINAL SIGMA;Ll;0;L;<font> 03C2;;;;N;;;;;
+1D748;MATHEMATICAL BOLD ITALIC SMALL SIGMA;Ll;0;L;<font> 03C3;;;;N;;;;;
+1D749;MATHEMATICAL BOLD ITALIC SMALL TAU;Ll;0;L;<font> 03C4;;;;N;;;;;
+1D74A;MATHEMATICAL BOLD ITALIC SMALL UPSILON;Ll;0;L;<font> 03C5;;;;N;;;;;
+1D74B;MATHEMATICAL BOLD ITALIC SMALL PHI;Ll;0;L;<font> 03C6;;;;N;;;;;
+1D74C;MATHEMATICAL BOLD ITALIC SMALL CHI;Ll;0;L;<font> 03C7;;;;N;;;;;
+1D74D;MATHEMATICAL BOLD ITALIC SMALL PSI;Ll;0;L;<font> 03C8;;;;N;;;;;
+1D74E;MATHEMATICAL BOLD ITALIC SMALL OMEGA;Ll;0;L;<font> 03C9;;;;N;;;;;
+1D74F;MATHEMATICAL BOLD ITALIC PARTIAL DIFFERENTIAL;Sm;0;L;<font> 2202;;;;N;;;;;
+1D750;MATHEMATICAL BOLD ITALIC EPSILON SYMBOL;Ll;0;L;<font> 03F5;;;;N;;;;;
+1D751;MATHEMATICAL BOLD ITALIC THETA SYMBOL;Ll;0;L;<font> 03D1;;;;N;;;;;
+1D752;MATHEMATICAL BOLD ITALIC KAPPA SYMBOL;Ll;0;L;<font> 03F0;;;;N;;;;;
+1D753;MATHEMATICAL BOLD ITALIC PHI SYMBOL;Ll;0;L;<font> 03D5;;;;N;;;;;
+1D754;MATHEMATICAL BOLD ITALIC RHO SYMBOL;Ll;0;L;<font> 03F1;;;;N;;;;;
+1D755;MATHEMATICAL BOLD ITALIC PI SYMBOL;Ll;0;L;<font> 03D6;;;;N;;;;;
+1D756;MATHEMATICAL SANS-SERIF BOLD CAPITAL ALPHA;Lu;0;L;<font> 0391;;;;N;;;;;
+1D757;MATHEMATICAL SANS-SERIF BOLD CAPITAL BETA;Lu;0;L;<font> 0392;;;;N;;;;;
+1D758;MATHEMATICAL SANS-SERIF BOLD CAPITAL GAMMA;Lu;0;L;<font> 0393;;;;N;;;;;
+1D759;MATHEMATICAL SANS-SERIF BOLD CAPITAL DELTA;Lu;0;L;<font> 0394;;;;N;;;;;
+1D75A;MATHEMATICAL SANS-SERIF BOLD CAPITAL EPSILON;Lu;0;L;<font> 0395;;;;N;;;;;
+1D75B;MATHEMATICAL SANS-SERIF BOLD CAPITAL ZETA;Lu;0;L;<font> 0396;;;;N;;;;;
+1D75C;MATHEMATICAL SANS-SERIF BOLD CAPITAL ETA;Lu;0;L;<font> 0397;;;;N;;;;;
+1D75D;MATHEMATICAL SANS-SERIF BOLD CAPITAL THETA;Lu;0;L;<font> 0398;;;;N;;;;;
+1D75E;MATHEMATICAL SANS-SERIF BOLD CAPITAL IOTA;Lu;0;L;<font> 0399;;;;N;;;;;
+1D75F;MATHEMATICAL SANS-SERIF BOLD CAPITAL KAPPA;Lu;0;L;<font> 039A;;;;N;;;;;
+1D760;MATHEMATICAL SANS-SERIF BOLD CAPITAL LAMDA;Lu;0;L;<font> 039B;;;;N;;;;;
+1D761;MATHEMATICAL SANS-SERIF BOLD CAPITAL MU;Lu;0;L;<font> 039C;;;;N;;;;;
+1D762;MATHEMATICAL SANS-SERIF BOLD CAPITAL NU;Lu;0;L;<font> 039D;;;;N;;;;;
+1D763;MATHEMATICAL SANS-SERIF BOLD CAPITAL XI;Lu;0;L;<font> 039E;;;;N;;;;;
+1D764;MATHEMATICAL SANS-SERIF BOLD CAPITAL OMICRON;Lu;0;L;<font> 039F;;;;N;;;;;
+1D765;MATHEMATICAL SANS-SERIF BOLD CAPITAL PI;Lu;0;L;<font> 03A0;;;;N;;;;;
+1D766;MATHEMATICAL SANS-SERIF BOLD CAPITAL RHO;Lu;0;L;<font> 03A1;;;;N;;;;;
+1D767;MATHEMATICAL SANS-SERIF BOLD CAPITAL THETA SYMBOL;Lu;0;L;<font> 03F4;;;;N;;;;;
+1D768;MATHEMATICAL SANS-SERIF BOLD CAPITAL SIGMA;Lu;0;L;<font> 03A3;;;;N;;;;;
+1D769;MATHEMATICAL SANS-SERIF BOLD CAPITAL TAU;Lu;0;L;<font> 03A4;;;;N;;;;;
+1D76A;MATHEMATICAL SANS-SERIF BOLD CAPITAL UPSILON;Lu;0;L;<font> 03A5;;;;N;;;;;
+1D76B;MATHEMATICAL SANS-SERIF BOLD CAPITAL PHI;Lu;0;L;<font> 03A6;;;;N;;;;;
+1D76C;MATHEMATICAL SANS-SERIF BOLD CAPITAL CHI;Lu;0;L;<font> 03A7;;;;N;;;;;
+1D76D;MATHEMATICAL SANS-SERIF BOLD CAPITAL PSI;Lu;0;L;<font> 03A8;;;;N;;;;;
+1D76E;MATHEMATICAL SANS-SERIF BOLD CAPITAL OMEGA;Lu;0;L;<font> 03A9;;;;N;;;;;
+1D76F;MATHEMATICAL SANS-SERIF BOLD NABLA;Sm;0;L;<font> 2207;;;;N;;;;;
+1D770;MATHEMATICAL SANS-SERIF BOLD SMALL ALPHA;Ll;0;L;<font> 03B1;;;;N;;;;;
+1D771;MATHEMATICAL SANS-SERIF BOLD SMALL BETA;Ll;0;L;<font> 03B2;;;;N;;;;;
+1D772;MATHEMATICAL SANS-SERIF BOLD SMALL GAMMA;Ll;0;L;<font> 03B3;;;;N;;;;;
+1D773;MATHEMATICAL SANS-SERIF BOLD SMALL DELTA;Ll;0;L;<font> 03B4;;;;N;;;;;
+1D774;MATHEMATICAL SANS-SERIF BOLD SMALL EPSILON;Ll;0;L;<font> 03B5;;;;N;;;;;
+1D775;MATHEMATICAL SANS-SERIF BOLD SMALL ZETA;Ll;0;L;<font> 03B6;;;;N;;;;;
+1D776;MATHEMATICAL SANS-SERIF BOLD SMALL ETA;Ll;0;L;<font> 03B7;;;;N;;;;;
+1D777;MATHEMATICAL SANS-SERIF BOLD SMALL THETA;Ll;0;L;<font> 03B8;;;;N;;;;;
+1D778;MATHEMATICAL SANS-SERIF BOLD SMALL IOTA;Ll;0;L;<font> 03B9;;;;N;;;;;
+1D779;MATHEMATICAL SANS-SERIF BOLD SMALL KAPPA;Ll;0;L;<font> 03BA;;;;N;;;;;
+1D77A;MATHEMATICAL SANS-SERIF BOLD SMALL LAMDA;Ll;0;L;<font> 03BB;;;;N;;;;;
+1D77B;MATHEMATICAL SANS-SERIF BOLD SMALL MU;Ll;0;L;<font> 03BC;;;;N;;;;;
+1D77C;MATHEMATICAL SANS-SERIF BOLD SMALL NU;Ll;0;L;<font> 03BD;;;;N;;;;;
+1D77D;MATHEMATICAL SANS-SERIF BOLD SMALL XI;Ll;0;L;<font> 03BE;;;;N;;;;;
+1D77E;MATHEMATICAL SANS-SERIF BOLD SMALL OMICRON;Ll;0;L;<font> 03BF;;;;N;;;;;
+1D77F;MATHEMATICAL SANS-SERIF BOLD SMALL PI;Ll;0;L;<font> 03C0;;;;N;;;;;
+1D780;MATHEMATICAL SANS-SERIF BOLD SMALL RHO;Ll;0;L;<font> 03C1;;;;N;;;;;
+1D781;MATHEMATICAL SANS-SERIF BOLD SMALL FINAL SIGMA;Ll;0;L;<font> 03C2;;;;N;;;;;
+1D782;MATHEMATICAL SANS-SERIF BOLD SMALL SIGMA;Ll;0;L;<font> 03C3;;;;N;;;;;
+1D783;MATHEMATICAL SANS-SERIF BOLD SMALL TAU;Ll;0;L;<font> 03C4;;;;N;;;;;
+1D784;MATHEMATICAL SANS-SERIF BOLD SMALL UPSILON;Ll;0;L;<font> 03C5;;;;N;;;;;
+1D785;MATHEMATICAL SANS-SERIF BOLD SMALL PHI;Ll;0;L;<font> 03C6;;;;N;;;;;
+1D786;MATHEMATICAL SANS-SERIF BOLD SMALL CHI;Ll;0;L;<font> 03C7;;;;N;;;;;
+1D787;MATHEMATICAL SANS-SERIF BOLD SMALL PSI;Ll;0;L;<font> 03C8;;;;N;;;;;
+1D788;MATHEMATICAL SANS-SERIF BOLD SMALL OMEGA;Ll;0;L;<font> 03C9;;;;N;;;;;
+1D789;MATHEMATICAL SANS-SERIF BOLD PARTIAL DIFFERENTIAL;Sm;0;L;<font> 2202;;;;N;;;;;
+1D78A;MATHEMATICAL SANS-SERIF BOLD EPSILON SYMBOL;Ll;0;L;<font> 03F5;;;;N;;;;;
+1D78B;MATHEMATICAL SANS-SERIF BOLD THETA SYMBOL;Ll;0;L;<font> 03D1;;;;N;;;;;
+1D78C;MATHEMATICAL SANS-SERIF BOLD KAPPA SYMBOL;Ll;0;L;<font> 03F0;;;;N;;;;;
+1D78D;MATHEMATICAL SANS-SERIF BOLD PHI SYMBOL;Ll;0;L;<font> 03D5;;;;N;;;;;
+1D78E;MATHEMATICAL SANS-SERIF BOLD RHO SYMBOL;Ll;0;L;<font> 03F1;;;;N;;;;;
+1D78F;MATHEMATICAL SANS-SERIF BOLD PI SYMBOL;Ll;0;L;<font> 03D6;;;;N;;;;;
+1D790;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL ALPHA;Lu;0;L;<font> 0391;;;;N;;;;;
+1D791;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL BETA;Lu;0;L;<font> 0392;;;;N;;;;;
+1D792;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL GAMMA;Lu;0;L;<font> 0393;;;;N;;;;;
+1D793;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL DELTA;Lu;0;L;<font> 0394;;;;N;;;;;
+1D794;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL EPSILON;Lu;0;L;<font> 0395;;;;N;;;;;
+1D795;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL ZETA;Lu;0;L;<font> 0396;;;;N;;;;;
+1D796;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL ETA;Lu;0;L;<font> 0397;;;;N;;;;;
+1D797;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL THETA;Lu;0;L;<font> 0398;;;;N;;;;;
+1D798;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL IOTA;Lu;0;L;<font> 0399;;;;N;;;;;
+1D799;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL KAPPA;Lu;0;L;<font> 039A;;;;N;;;;;
+1D79A;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL LAMDA;Lu;0;L;<font> 039B;;;;N;;;;;
+1D79B;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL MU;Lu;0;L;<font> 039C;;;;N;;;;;
+1D79C;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL NU;Lu;0;L;<font> 039D;;;;N;;;;;
+1D79D;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL XI;Lu;0;L;<font> 039E;;;;N;;;;;
+1D79E;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL OMICRON;Lu;0;L;<font> 039F;;;;N;;;;;
+1D79F;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL PI;Lu;0;L;<font> 03A0;;;;N;;;;;
+1D7A0;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL RHO;Lu;0;L;<font> 03A1;;;;N;;;;;
+1D7A1;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL THETA SYMBOL;Lu;0;L;<font> 03F4;;;;N;;;;;
+1D7A2;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL SIGMA;Lu;0;L;<font> 03A3;;;;N;;;;;
+1D7A3;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL TAU;Lu;0;L;<font> 03A4;;;;N;;;;;
+1D7A4;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL UPSILON;Lu;0;L;<font> 03A5;;;;N;;;;;
+1D7A5;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL PHI;Lu;0;L;<font> 03A6;;;;N;;;;;
+1D7A6;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL CHI;Lu;0;L;<font> 03A7;;;;N;;;;;
+1D7A7;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL PSI;Lu;0;L;<font> 03A8;;;;N;;;;;
+1D7A8;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL OMEGA;Lu;0;L;<font> 03A9;;;;N;;;;;
+1D7A9;MATHEMATICAL SANS-SERIF BOLD ITALIC NABLA;Sm;0;L;<font> 2207;;;;N;;;;;
+1D7AA;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL ALPHA;Ll;0;L;<font> 03B1;;;;N;;;;;
+1D7AB;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL BETA;Ll;0;L;<font> 03B2;;;;N;;;;;
+1D7AC;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL GAMMA;Ll;0;L;<font> 03B3;;;;N;;;;;
+1D7AD;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL DELTA;Ll;0;L;<font> 03B4;;;;N;;;;;
+1D7AE;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL EPSILON;Ll;0;L;<font> 03B5;;;;N;;;;;
+1D7AF;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL ZETA;Ll;0;L;<font> 03B6;;;;N;;;;;
+1D7B0;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL ETA;Ll;0;L;<font> 03B7;;;;N;;;;;
+1D7B1;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL THETA;Ll;0;L;<font> 03B8;;;;N;;;;;
+1D7B2;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL IOTA;Ll;0;L;<font> 03B9;;;;N;;;;;
+1D7B3;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL KAPPA;Ll;0;L;<font> 03BA;;;;N;;;;;
+1D7B4;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL LAMDA;Ll;0;L;<font> 03BB;;;;N;;;;;
+1D7B5;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL MU;Ll;0;L;<font> 03BC;;;;N;;;;;
+1D7B6;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL NU;Ll;0;L;<font> 03BD;;;;N;;;;;
+1D7B7;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL XI;Ll;0;L;<font> 03BE;;;;N;;;;;
+1D7B8;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL OMICRON;Ll;0;L;<font> 03BF;;;;N;;;;;
+1D7B9;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL PI;Ll;0;L;<font> 03C0;;;;N;;;;;
+1D7BA;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL RHO;Ll;0;L;<font> 03C1;;;;N;;;;;
+1D7BB;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL FINAL SIGMA;Ll;0;L;<font> 03C2;;;;N;;;;;
+1D7BC;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL SIGMA;Ll;0;L;<font> 03C3;;;;N;;;;;
+1D7BD;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL TAU;Ll;0;L;<font> 03C4;;;;N;;;;;
+1D7BE;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL UPSILON;Ll;0;L;<font> 03C5;;;;N;;;;;
+1D7BF;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL PHI;Ll;0;L;<font> 03C6;;;;N;;;;;
+1D7C0;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL CHI;Ll;0;L;<font> 03C7;;;;N;;;;;
+1D7C1;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL PSI;Ll;0;L;<font> 03C8;;;;N;;;;;
+1D7C2;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL OMEGA;Ll;0;L;<font> 03C9;;;;N;;;;;
+1D7C3;MATHEMATICAL SANS-SERIF BOLD ITALIC PARTIAL DIFFERENTIAL;Sm;0;L;<font> 2202;;;;N;;;;;
+1D7C4;MATHEMATICAL SANS-SERIF BOLD ITALIC EPSILON SYMBOL;Ll;0;L;<font> 03F5;;;;N;;;;;
+1D7C5;MATHEMATICAL SANS-SERIF BOLD ITALIC THETA SYMBOL;Ll;0;L;<font> 03D1;;;;N;;;;;
+1D7C6;MATHEMATICAL SANS-SERIF BOLD ITALIC KAPPA SYMBOL;Ll;0;L;<font> 03F0;;;;N;;;;;
+1D7C7;MATHEMATICAL SANS-SERIF BOLD ITALIC PHI SYMBOL;Ll;0;L;<font> 03D5;;;;N;;;;;
+1D7C8;MATHEMATICAL SANS-SERIF BOLD ITALIC RHO SYMBOL;Ll;0;L;<font> 03F1;;;;N;;;;;
+1D7C9;MATHEMATICAL SANS-SERIF BOLD ITALIC PI SYMBOL;Ll;0;L;<font> 03D6;;;;N;;;;;
+1D7CE;MATHEMATICAL BOLD DIGIT ZERO;Nd;0;EN;<font> 0030;0;0;0;N;;;;;
+1D7CF;MATHEMATICAL BOLD DIGIT ONE;Nd;0;EN;<font> 0031;1;1;1;N;;;;;
+1D7D0;MATHEMATICAL BOLD DIGIT TWO;Nd;0;EN;<font> 0032;2;2;2;N;;;;;
+1D7D1;MATHEMATICAL BOLD DIGIT THREE;Nd;0;EN;<font> 0033;3;3;3;N;;;;;
+1D7D2;MATHEMATICAL BOLD DIGIT FOUR;Nd;0;EN;<font> 0034;4;4;4;N;;;;;
+1D7D3;MATHEMATICAL BOLD DIGIT FIVE;Nd;0;EN;<font> 0035;5;5;5;N;;;;;
+1D7D4;MATHEMATICAL BOLD DIGIT SIX;Nd;0;EN;<font> 0036;6;6;6;N;;;;;
+1D7D5;MATHEMATICAL BOLD DIGIT SEVEN;Nd;0;EN;<font> 0037;7;7;7;N;;;;;
+1D7D6;MATHEMATICAL BOLD DIGIT EIGHT;Nd;0;EN;<font> 0038;8;8;8;N;;;;;
+1D7D7;MATHEMATICAL BOLD DIGIT NINE;Nd;0;EN;<font> 0039;9;9;9;N;;;;;
+1D7D8;MATHEMATICAL DOUBLE-STRUCK DIGIT ZERO;Nd;0;EN;<font> 0030;0;0;0;N;;;;;
+1D7D9;MATHEMATICAL DOUBLE-STRUCK DIGIT ONE;Nd;0;EN;<font> 0031;1;1;1;N;;;;;
+1D7DA;MATHEMATICAL DOUBLE-STRUCK DIGIT TWO;Nd;0;EN;<font> 0032;2;2;2;N;;;;;
+1D7DB;MATHEMATICAL DOUBLE-STRUCK DIGIT THREE;Nd;0;EN;<font> 0033;3;3;3;N;;;;;
+1D7DC;MATHEMATICAL DOUBLE-STRUCK DIGIT FOUR;Nd;0;EN;<font> 0034;4;4;4;N;;;;;
+1D7DD;MATHEMATICAL DOUBLE-STRUCK DIGIT FIVE;Nd;0;EN;<font> 0035;5;5;5;N;;;;;
+1D7DE;MATHEMATICAL DOUBLE-STRUCK DIGIT SIX;Nd;0;EN;<font> 0036;6;6;6;N;;;;;
+1D7DF;MATHEMATICAL DOUBLE-STRUCK DIGIT SEVEN;Nd;0;EN;<font> 0037;7;7;7;N;;;;;
+1D7E0;MATHEMATICAL DOUBLE-STRUCK DIGIT EIGHT;Nd;0;EN;<font> 0038;8;8;8;N;;;;;
+1D7E1;MATHEMATICAL DOUBLE-STRUCK DIGIT NINE;Nd;0;EN;<font> 0039;9;9;9;N;;;;;
+1D7E2;MATHEMATICAL SANS-SERIF DIGIT ZERO;Nd;0;EN;<font> 0030;0;0;0;N;;;;;
+1D7E3;MATHEMATICAL SANS-SERIF DIGIT ONE;Nd;0;EN;<font> 0031;1;1;1;N;;;;;
+1D7E4;MATHEMATICAL SANS-SERIF DIGIT TWO;Nd;0;EN;<font> 0032;2;2;2;N;;;;;
+1D7E5;MATHEMATICAL SANS-SERIF DIGIT THREE;Nd;0;EN;<font> 0033;3;3;3;N;;;;;
+1D7E6;MATHEMATICAL SANS-SERIF DIGIT FOUR;Nd;0;EN;<font> 0034;4;4;4;N;;;;;
+1D7E7;MATHEMATICAL SANS-SERIF DIGIT FIVE;Nd;0;EN;<font> 0035;5;5;5;N;;;;;
+1D7E8;MATHEMATICAL SANS-SERIF DIGIT SIX;Nd;0;EN;<font> 0036;6;6;6;N;;;;;
+1D7E9;MATHEMATICAL SANS-SERIF DIGIT SEVEN;Nd;0;EN;<font> 0037;7;7;7;N;;;;;
+1D7EA;MATHEMATICAL SANS-SERIF DIGIT EIGHT;Nd;0;EN;<font> 0038;8;8;8;N;;;;;
+1D7EB;MATHEMATICAL SANS-SERIF DIGIT NINE;Nd;0;EN;<font> 0039;9;9;9;N;;;;;
+1D7EC;MATHEMATICAL SANS-SERIF BOLD DIGIT ZERO;Nd;0;EN;<font> 0030;0;0;0;N;;;;;
+1D7ED;MATHEMATICAL SANS-SERIF BOLD DIGIT ONE;Nd;0;EN;<font> 0031;1;1;1;N;;;;;
+1D7EE;MATHEMATICAL SANS-SERIF BOLD DIGIT TWO;Nd;0;EN;<font> 0032;2;2;2;N;;;;;
+1D7EF;MATHEMATICAL SANS-SERIF BOLD DIGIT THREE;Nd;0;EN;<font> 0033;3;3;3;N;;;;;
+1D7F0;MATHEMATICAL SANS-SERIF BOLD DIGIT FOUR;Nd;0;EN;<font> 0034;4;4;4;N;;;;;
+1D7F1;MATHEMATICAL SANS-SERIF BOLD DIGIT FIVE;Nd;0;EN;<font> 0035;5;5;5;N;;;;;
+1D7F2;MATHEMATICAL SANS-SERIF BOLD DIGIT SIX;Nd;0;EN;<font> 0036;6;6;6;N;;;;;
+1D7F3;MATHEMATICAL SANS-SERIF BOLD DIGIT SEVEN;Nd;0;EN;<font> 0037;7;7;7;N;;;;;
+1D7F4;MATHEMATICAL SANS-SERIF BOLD DIGIT EIGHT;Nd;0;EN;<font> 0038;8;8;8;N;;;;;
+1D7F5;MATHEMATICAL SANS-SERIF BOLD DIGIT NINE;Nd;0;EN;<font> 0039;9;9;9;N;;;;;
+1D7F6;MATHEMATICAL MONOSPACE DIGIT ZERO;Nd;0;EN;<font> 0030;0;0;0;N;;;;;
+1D7F7;MATHEMATICAL MONOSPACE DIGIT ONE;Nd;0;EN;<font> 0031;1;1;1;N;;;;;
+1D7F8;MATHEMATICAL MONOSPACE DIGIT TWO;Nd;0;EN;<font> 0032;2;2;2;N;;;;;
+1D7F9;MATHEMATICAL MONOSPACE DIGIT THREE;Nd;0;EN;<font> 0033;3;3;3;N;;;;;
+1D7FA;MATHEMATICAL MONOSPACE DIGIT FOUR;Nd;0;EN;<font> 0034;4;4;4;N;;;;;
+1D7FB;MATHEMATICAL MONOSPACE DIGIT FIVE;Nd;0;EN;<font> 0035;5;5;5;N;;;;;
+1D7FC;MATHEMATICAL MONOSPACE DIGIT SIX;Nd;0;EN;<font> 0036;6;6;6;N;;;;;
+1D7FD;MATHEMATICAL MONOSPACE DIGIT SEVEN;Nd;0;EN;<font> 0037;7;7;7;N;;;;;
+1D7FE;MATHEMATICAL MONOSPACE DIGIT EIGHT;Nd;0;EN;<font> 0038;8;8;8;N;;;;;
+1D7FF;MATHEMATICAL MONOSPACE DIGIT NINE;Nd;0;EN;<font> 0039;9;9;9;N;;;;;
+20000;<CJK Ideograph Extension B, First>;Lo;0;L;;;;;N;;;;;
+2A6D6;<CJK Ideograph Extension B, Last>;Lo;0;L;;;;;N;;;;;
+2F800;CJK COMPATIBILITY IDEOGRAPH-2F800;Lo;0;L;4E3D;;;;N;;;;;
+2F801;CJK COMPATIBILITY IDEOGRAPH-2F801;Lo;0;L;4E38;;;;N;;;;;
+2F802;CJK COMPATIBILITY IDEOGRAPH-2F802;Lo;0;L;4E41;;;;N;;;;;
+2F803;CJK COMPATIBILITY IDEOGRAPH-2F803;Lo;0;L;20122;;;;N;;;;;
+2F804;CJK COMPATIBILITY IDEOGRAPH-2F804;Lo;0;L;4F60;;;;N;;;;;
+2F805;CJK COMPATIBILITY IDEOGRAPH-2F805;Lo;0;L;4FAE;;;;N;;;;;
+2F806;CJK COMPATIBILITY IDEOGRAPH-2F806;Lo;0;L;4FBB;;;;N;;;;;
+2F807;CJK COMPATIBILITY IDEOGRAPH-2F807;Lo;0;L;5002;;;;N;;;;;
+2F808;CJK COMPATIBILITY IDEOGRAPH-2F808;Lo;0;L;507A;;;;N;;;;;
+2F809;CJK COMPATIBILITY IDEOGRAPH-2F809;Lo;0;L;5099;;;;N;;;;;
+2F80A;CJK COMPATIBILITY IDEOGRAPH-2F80A;Lo;0;L;50E7;;;;N;;;;;
+2F80B;CJK COMPATIBILITY IDEOGRAPH-2F80B;Lo;0;L;50CF;;;;N;;;;;
+2F80C;CJK COMPATIBILITY IDEOGRAPH-2F80C;Lo;0;L;349E;;;;N;;;;;
+2F80D;CJK COMPATIBILITY IDEOGRAPH-2F80D;Lo;0;L;2063A;;;;N;;;;;
+2F80E;CJK COMPATIBILITY IDEOGRAPH-2F80E;Lo;0;L;514D;;;;N;;;;;
+2F80F;CJK COMPATIBILITY IDEOGRAPH-2F80F;Lo;0;L;5154;;;;N;;;;;
+2F810;CJK COMPATIBILITY IDEOGRAPH-2F810;Lo;0;L;5164;;;;N;;;;;
+2F811;CJK COMPATIBILITY IDEOGRAPH-2F811;Lo;0;L;5177;;;;N;;;;;
+2F812;CJK COMPATIBILITY IDEOGRAPH-2F812;Lo;0;L;2051C;;;;N;;;;;
+2F813;CJK COMPATIBILITY IDEOGRAPH-2F813;Lo;0;L;34B9;;;;N;;;;;
+2F814;CJK COMPATIBILITY IDEOGRAPH-2F814;Lo;0;L;5167;;;;N;;;;;
+2F815;CJK COMPATIBILITY IDEOGRAPH-2F815;Lo;0;L;518D;;;;N;;;;;
+2F816;CJK COMPATIBILITY IDEOGRAPH-2F816;Lo;0;L;2054B;;;;N;;;;;
+2F817;CJK COMPATIBILITY IDEOGRAPH-2F817;Lo;0;L;5197;;;;N;;;;;
+2F818;CJK COMPATIBILITY IDEOGRAPH-2F818;Lo;0;L;51A4;;;;N;;;;;
+2F819;CJK COMPATIBILITY IDEOGRAPH-2F819;Lo;0;L;4ECC;;;;N;;;;;
+2F81A;CJK COMPATIBILITY IDEOGRAPH-2F81A;Lo;0;L;51AC;;;;N;;;;;
+2F81B;CJK COMPATIBILITY IDEOGRAPH-2F81B;Lo;0;L;51B5;;;;N;;;;;
+2F81C;CJK COMPATIBILITY IDEOGRAPH-2F81C;Lo;0;L;291DF;;;;N;;;;;
+2F81D;CJK COMPATIBILITY IDEOGRAPH-2F81D;Lo;0;L;51F5;;;;N;;;;;
+2F81E;CJK COMPATIBILITY IDEOGRAPH-2F81E;Lo;0;L;5203;;;;N;;;;;
+2F81F;CJK COMPATIBILITY IDEOGRAPH-2F81F;Lo;0;L;34DF;;;;N;;;;;
+2F820;CJK COMPATIBILITY IDEOGRAPH-2F820;Lo;0;L;523B;;;;N;;;;;
+2F821;CJK COMPATIBILITY IDEOGRAPH-2F821;Lo;0;L;5246;;;;N;;;;;
+2F822;CJK COMPATIBILITY IDEOGRAPH-2F822;Lo;0;L;5272;;;;N;;;;;
+2F823;CJK COMPATIBILITY IDEOGRAPH-2F823;Lo;0;L;5277;;;;N;;;;;
+2F824;CJK COMPATIBILITY IDEOGRAPH-2F824;Lo;0;L;3515;;;;N;;;;;
+2F825;CJK COMPATIBILITY IDEOGRAPH-2F825;Lo;0;L;52C7;;;;N;;;;;
+2F826;CJK COMPATIBILITY IDEOGRAPH-2F826;Lo;0;L;52C9;;;;N;;;;;
+2F827;CJK COMPATIBILITY IDEOGRAPH-2F827;Lo;0;L;52E4;;;;N;;;;;
+2F828;CJK COMPATIBILITY IDEOGRAPH-2F828;Lo;0;L;52FA;;;;N;;;;;
+2F829;CJK COMPATIBILITY IDEOGRAPH-2F829;Lo;0;L;5305;;;;N;;;;;
+2F82A;CJK COMPATIBILITY IDEOGRAPH-2F82A;Lo;0;L;5306;;;;N;;;;;
+2F82B;CJK COMPATIBILITY IDEOGRAPH-2F82B;Lo;0;L;5317;;;;N;;;;;
+2F82C;CJK COMPATIBILITY IDEOGRAPH-2F82C;Lo;0;L;5349;;;;N;;;;;
+2F82D;CJK COMPATIBILITY IDEOGRAPH-2F82D;Lo;0;L;5351;;;;N;;;;;
+2F82E;CJK COMPATIBILITY IDEOGRAPH-2F82E;Lo;0;L;535A;;;;N;;;;;
+2F82F;CJK COMPATIBILITY IDEOGRAPH-2F82F;Lo;0;L;5373;;;;N;;;;;
+2F830;CJK COMPATIBILITY IDEOGRAPH-2F830;Lo;0;L;537D;;;;N;;;;;
+2F831;CJK COMPATIBILITY IDEOGRAPH-2F831;Lo;0;L;537F;;;;N;;;;;
+2F832;CJK COMPATIBILITY IDEOGRAPH-2F832;Lo;0;L;537F;;;;N;;;;;
+2F833;CJK COMPATIBILITY IDEOGRAPH-2F833;Lo;0;L;537F;;;;N;;;;;
+2F834;CJK COMPATIBILITY IDEOGRAPH-2F834;Lo;0;L;20A2C;;;;N;;;;;
+2F835;CJK COMPATIBILITY IDEOGRAPH-2F835;Lo;0;L;7070;;;;N;;;;;
+2F836;CJK COMPATIBILITY IDEOGRAPH-2F836;Lo;0;L;53CA;;;;N;;;;;
+2F837;CJK COMPATIBILITY IDEOGRAPH-2F837;Lo;0;L;53DF;;;;N;;;;;
+2F838;CJK COMPATIBILITY IDEOGRAPH-2F838;Lo;0;L;20B63;;;;N;;;;;
+2F839;CJK COMPATIBILITY IDEOGRAPH-2F839;Lo;0;L;53EB;;;;N;;;;;
+2F83A;CJK COMPATIBILITY IDEOGRAPH-2F83A;Lo;0;L;53F1;;;;N;;;;;
+2F83B;CJK COMPATIBILITY IDEOGRAPH-2F83B;Lo;0;L;5406;;;;N;;;;;
+2F83C;CJK COMPATIBILITY IDEOGRAPH-2F83C;Lo;0;L;549E;;;;N;;;;;
+2F83D;CJK COMPATIBILITY IDEOGRAPH-2F83D;Lo;0;L;5438;;;;N;;;;;
+2F83E;CJK COMPATIBILITY IDEOGRAPH-2F83E;Lo;0;L;5448;;;;N;;;;;
+2F83F;CJK COMPATIBILITY IDEOGRAPH-2F83F;Lo;0;L;5468;;;;N;;;;;
+2F840;CJK COMPATIBILITY IDEOGRAPH-2F840;Lo;0;L;54A2;;;;N;;;;;
+2F841;CJK COMPATIBILITY IDEOGRAPH-2F841;Lo;0;L;54F6;;;;N;;;;;
+2F842;CJK COMPATIBILITY IDEOGRAPH-2F842;Lo;0;L;5510;;;;N;;;;;
+2F843;CJK COMPATIBILITY IDEOGRAPH-2F843;Lo;0;L;5553;;;;N;;;;;
+2F844;CJK COMPATIBILITY IDEOGRAPH-2F844;Lo;0;L;5563;;;;N;;;;;
+2F845;CJK COMPATIBILITY IDEOGRAPH-2F845;Lo;0;L;5584;;;;N;;;;;
+2F846;CJK COMPATIBILITY IDEOGRAPH-2F846;Lo;0;L;5584;;;;N;;;;;
+2F847;CJK COMPATIBILITY IDEOGRAPH-2F847;Lo;0;L;5599;;;;N;;;;;
+2F848;CJK COMPATIBILITY IDEOGRAPH-2F848;Lo;0;L;55AB;;;;N;;;;;
+2F849;CJK COMPATIBILITY IDEOGRAPH-2F849;Lo;0;L;55B3;;;;N;;;;;
+2F84A;CJK COMPATIBILITY IDEOGRAPH-2F84A;Lo;0;L;55C2;;;;N;;;;;
+2F84B;CJK COMPATIBILITY IDEOGRAPH-2F84B;Lo;0;L;5716;;;;N;;;;;
+2F84C;CJK COMPATIBILITY IDEOGRAPH-2F84C;Lo;0;L;5606;;;;N;;;;;
+2F84D;CJK COMPATIBILITY IDEOGRAPH-2F84D;Lo;0;L;5717;;;;N;;;;;
+2F84E;CJK COMPATIBILITY IDEOGRAPH-2F84E;Lo;0;L;5651;;;;N;;;;;
+2F84F;CJK COMPATIBILITY IDEOGRAPH-2F84F;Lo;0;L;5674;;;;N;;;;;
+2F850;CJK COMPATIBILITY IDEOGRAPH-2F850;Lo;0;L;5207;;;;N;;;;;
+2F851;CJK COMPATIBILITY IDEOGRAPH-2F851;Lo;0;L;58EE;;;;N;;;;;
+2F852;CJK COMPATIBILITY IDEOGRAPH-2F852;Lo;0;L;57CE;;;;N;;;;;
+2F853;CJK COMPATIBILITY IDEOGRAPH-2F853;Lo;0;L;57F4;;;;N;;;;;
+2F854;CJK COMPATIBILITY IDEOGRAPH-2F854;Lo;0;L;580D;;;;N;;;;;
+2F855;CJK COMPATIBILITY IDEOGRAPH-2F855;Lo;0;L;578B;;;;N;;;;;
+2F856;CJK COMPATIBILITY IDEOGRAPH-2F856;Lo;0;L;5832;;;;N;;;;;
+2F857;CJK COMPATIBILITY IDEOGRAPH-2F857;Lo;0;L;5831;;;;N;;;;;
+2F858;CJK COMPATIBILITY IDEOGRAPH-2F858;Lo;0;L;58AC;;;;N;;;;;
+2F859;CJK COMPATIBILITY IDEOGRAPH-2F859;Lo;0;L;214E4;;;;N;;;;;
+2F85A;CJK COMPATIBILITY IDEOGRAPH-2F85A;Lo;0;L;58F2;;;;N;;;;;
+2F85B;CJK COMPATIBILITY IDEOGRAPH-2F85B;Lo;0;L;58F7;;;;N;;;;;
+2F85C;CJK COMPATIBILITY IDEOGRAPH-2F85C;Lo;0;L;5906;;;;N;;;;;
+2F85D;CJK COMPATIBILITY IDEOGRAPH-2F85D;Lo;0;L;591A;;;;N;;;;;
+2F85E;CJK COMPATIBILITY IDEOGRAPH-2F85E;Lo;0;L;5922;;;;N;;;;;
+2F85F;CJK COMPATIBILITY IDEOGRAPH-2F85F;Lo;0;L;5962;;;;N;;;;;
+2F860;CJK COMPATIBILITY IDEOGRAPH-2F860;Lo;0;L;216A8;;;;N;;;;;
+2F861;CJK COMPATIBILITY IDEOGRAPH-2F861;Lo;0;L;216EA;;;;N;;;;;
+2F862;CJK COMPATIBILITY IDEOGRAPH-2F862;Lo;0;L;59EC;;;;N;;;;;
+2F863;CJK COMPATIBILITY IDEOGRAPH-2F863;Lo;0;L;5A1B;;;;N;;;;;
+2F864;CJK COMPATIBILITY IDEOGRAPH-2F864;Lo;0;L;5A27;;;;N;;;;;
+2F865;CJK COMPATIBILITY IDEOGRAPH-2F865;Lo;0;L;59D8;;;;N;;;;;
+2F866;CJK COMPATIBILITY IDEOGRAPH-2F866;Lo;0;L;5A66;;;;N;;;;;
+2F867;CJK COMPATIBILITY IDEOGRAPH-2F867;Lo;0;L;36EE;;;;N;;;;;
+2F868;CJK COMPATIBILITY IDEOGRAPH-2F868;Lo;0;L;36FC;;;;N;;;;;
+2F869;CJK COMPATIBILITY IDEOGRAPH-2F869;Lo;0;L;5B08;;;;N;;;;;
+2F86A;CJK COMPATIBILITY IDEOGRAPH-2F86A;Lo;0;L;5B3E;;;;N;;;;;
+2F86B;CJK COMPATIBILITY IDEOGRAPH-2F86B;Lo;0;L;5B3E;;;;N;;;;;
+2F86C;CJK COMPATIBILITY IDEOGRAPH-2F86C;Lo;0;L;219C8;;;;N;;;;;
+2F86D;CJK COMPATIBILITY IDEOGRAPH-2F86D;Lo;0;L;5BC3;;;;N;;;;;
+2F86E;CJK COMPATIBILITY IDEOGRAPH-2F86E;Lo;0;L;5BD8;;;;N;;;;;
+2F86F;CJK COMPATIBILITY IDEOGRAPH-2F86F;Lo;0;L;5BE7;;;;N;;;;;
+2F870;CJK COMPATIBILITY IDEOGRAPH-2F870;Lo;0;L;5BF3;;;;N;;;;;
+2F871;CJK COMPATIBILITY IDEOGRAPH-2F871;Lo;0;L;21B18;;;;N;;;;;
+2F872;CJK COMPATIBILITY IDEOGRAPH-2F872;Lo;0;L;5BFF;;;;N;;;;;
+2F873;CJK COMPATIBILITY IDEOGRAPH-2F873;Lo;0;L;5C06;;;;N;;;;;
+2F874;CJK COMPATIBILITY IDEOGRAPH-2F874;Lo;0;L;5F53;;;;N;;;;;
+2F875;CJK COMPATIBILITY IDEOGRAPH-2F875;Lo;0;L;5C22;;;;N;;;;;
+2F876;CJK COMPATIBILITY IDEOGRAPH-2F876;Lo;0;L;3781;;;;N;;;;;
+2F877;CJK COMPATIBILITY IDEOGRAPH-2F877;Lo;0;L;5C60;;;;N;;;;;
+2F878;CJK COMPATIBILITY IDEOGRAPH-2F878;Lo;0;L;5C6E;;;;N;;;;;
+2F879;CJK COMPATIBILITY IDEOGRAPH-2F879;Lo;0;L;5CC0;;;;N;;;;;
+2F87A;CJK COMPATIBILITY IDEOGRAPH-2F87A;Lo;0;L;5C8D;;;;N;;;;;
+2F87B;CJK COMPATIBILITY IDEOGRAPH-2F87B;Lo;0;L;21DE4;;;;N;;;;;
+2F87C;CJK COMPATIBILITY IDEOGRAPH-2F87C;Lo;0;L;5D43;;;;N;;;;;
+2F87D;CJK COMPATIBILITY IDEOGRAPH-2F87D;Lo;0;L;21DE6;;;;N;;;;;
+2F87E;CJK COMPATIBILITY IDEOGRAPH-2F87E;Lo;0;L;5D6E;;;;N;;;;;
+2F87F;CJK COMPATIBILITY IDEOGRAPH-2F87F;Lo;0;L;5D6B;;;;N;;;;;
+2F880;CJK COMPATIBILITY IDEOGRAPH-2F880;Lo;0;L;5D7C;;;;N;;;;;
+2F881;CJK COMPATIBILITY IDEOGRAPH-2F881;Lo;0;L;5DE1;;;;N;;;;;
+2F882;CJK COMPATIBILITY IDEOGRAPH-2F882;Lo;0;L;5DE2;;;;N;;;;;
+2F883;CJK COMPATIBILITY IDEOGRAPH-2F883;Lo;0;L;382F;;;;N;;;;;
+2F884;CJK COMPATIBILITY IDEOGRAPH-2F884;Lo;0;L;5DFD;;;;N;;;;;
+2F885;CJK COMPATIBILITY IDEOGRAPH-2F885;Lo;0;L;5E28;;;;N;;;;;
+2F886;CJK COMPATIBILITY IDEOGRAPH-2F886;Lo;0;L;5E3D;;;;N;;;;;
+2F887;CJK COMPATIBILITY IDEOGRAPH-2F887;Lo;0;L;5E69;;;;N;;;;;
+2F888;CJK COMPATIBILITY IDEOGRAPH-2F888;Lo;0;L;3862;;;;N;;;;;
+2F889;CJK COMPATIBILITY IDEOGRAPH-2F889;Lo;0;L;22183;;;;N;;;;;
+2F88A;CJK COMPATIBILITY IDEOGRAPH-2F88A;Lo;0;L;387C;;;;N;;;;;
+2F88B;CJK COMPATIBILITY IDEOGRAPH-2F88B;Lo;0;L;5EB0;;;;N;;;;;
+2F88C;CJK COMPATIBILITY IDEOGRAPH-2F88C;Lo;0;L;5EB3;;;;N;;;;;
+2F88D;CJK COMPATIBILITY IDEOGRAPH-2F88D;Lo;0;L;5EB6;;;;N;;;;;
+2F88E;CJK COMPATIBILITY IDEOGRAPH-2F88E;Lo;0;L;5ECA;;;;N;;;;;
+2F88F;CJK COMPATIBILITY IDEOGRAPH-2F88F;Lo;0;L;2A392;;;;N;;;;;
+2F890;CJK COMPATIBILITY IDEOGRAPH-2F890;Lo;0;L;5EFE;;;;N;;;;;
+2F891;CJK COMPATIBILITY IDEOGRAPH-2F891;Lo;0;L;22331;;;;N;;;;;
+2F892;CJK COMPATIBILITY IDEOGRAPH-2F892;Lo;0;L;22331;;;;N;;;;;
+2F893;CJK COMPATIBILITY IDEOGRAPH-2F893;Lo;0;L;8201;;;;N;;;;;
+2F894;CJK COMPATIBILITY IDEOGRAPH-2F894;Lo;0;L;5F22;;;;N;;;;;
+2F895;CJK COMPATIBILITY IDEOGRAPH-2F895;Lo;0;L;5F22;;;;N;;;;;
+2F896;CJK COMPATIBILITY IDEOGRAPH-2F896;Lo;0;L;38C7;;;;N;;;;;
+2F897;CJK COMPATIBILITY IDEOGRAPH-2F897;Lo;0;L;232B8;;;;N;;;;;
+2F898;CJK COMPATIBILITY IDEOGRAPH-2F898;Lo;0;L;261DA;;;;N;;;;;
+2F899;CJK COMPATIBILITY IDEOGRAPH-2F899;Lo;0;L;5F62;;;;N;;;;;
+2F89A;CJK COMPATIBILITY IDEOGRAPH-2F89A;Lo;0;L;5F6B;;;;N;;;;;
+2F89B;CJK COMPATIBILITY IDEOGRAPH-2F89B;Lo;0;L;38E3;;;;N;;;;;
+2F89C;CJK COMPATIBILITY IDEOGRAPH-2F89C;Lo;0;L;5F9A;;;;N;;;;;
+2F89D;CJK COMPATIBILITY IDEOGRAPH-2F89D;Lo;0;L;5FCD;;;;N;;;;;
+2F89E;CJK COMPATIBILITY IDEOGRAPH-2F89E;Lo;0;L;5FD7;;;;N;;;;;
+2F89F;CJK COMPATIBILITY IDEOGRAPH-2F89F;Lo;0;L;5FF9;;;;N;;;;;
+2F8A0;CJK COMPATIBILITY IDEOGRAPH-2F8A0;Lo;0;L;6081;;;;N;;;;;
+2F8A1;CJK COMPATIBILITY IDEOGRAPH-2F8A1;Lo;0;L;393A;;;;N;;;;;
+2F8A2;CJK COMPATIBILITY IDEOGRAPH-2F8A2;Lo;0;L;391C;;;;N;;;;;
+2F8A3;CJK COMPATIBILITY IDEOGRAPH-2F8A3;Lo;0;L;6094;;;;N;;;;;
+2F8A4;CJK COMPATIBILITY IDEOGRAPH-2F8A4;Lo;0;L;226D4;;;;N;;;;;
+2F8A5;CJK COMPATIBILITY IDEOGRAPH-2F8A5;Lo;0;L;60C7;;;;N;;;;;
+2F8A6;CJK COMPATIBILITY IDEOGRAPH-2F8A6;Lo;0;L;6148;;;;N;;;;;
+2F8A7;CJK COMPATIBILITY IDEOGRAPH-2F8A7;Lo;0;L;614C;;;;N;;;;;
+2F8A8;CJK COMPATIBILITY IDEOGRAPH-2F8A8;Lo;0;L;614E;;;;N;;;;;
+2F8A9;CJK COMPATIBILITY IDEOGRAPH-2F8A9;Lo;0;L;614C;;;;N;;;;;
+2F8AA;CJK COMPATIBILITY IDEOGRAPH-2F8AA;Lo;0;L;617A;;;;N;;;;;
+2F8AB;CJK COMPATIBILITY IDEOGRAPH-2F8AB;Lo;0;L;618E;;;;N;;;;;
+2F8AC;CJK COMPATIBILITY IDEOGRAPH-2F8AC;Lo;0;L;61B2;;;;N;;;;;
+2F8AD;CJK COMPATIBILITY IDEOGRAPH-2F8AD;Lo;0;L;61A4;;;;N;;;;;
+2F8AE;CJK COMPATIBILITY IDEOGRAPH-2F8AE;Lo;0;L;61AF;;;;N;;;;;
+2F8AF;CJK COMPATIBILITY IDEOGRAPH-2F8AF;Lo;0;L;61DE;;;;N;;;;;
+2F8B0;CJK COMPATIBILITY IDEOGRAPH-2F8B0;Lo;0;L;61F2;;;;N;;;;;
+2F8B1;CJK COMPATIBILITY IDEOGRAPH-2F8B1;Lo;0;L;61F6;;;;N;;;;;
+2F8B2;CJK COMPATIBILITY IDEOGRAPH-2F8B2;Lo;0;L;6210;;;;N;;;;;
+2F8B3;CJK COMPATIBILITY IDEOGRAPH-2F8B3;Lo;0;L;621B;;;;N;;;;;
+2F8B4;CJK COMPATIBILITY IDEOGRAPH-2F8B4;Lo;0;L;625D;;;;N;;;;;
+2F8B5;CJK COMPATIBILITY IDEOGRAPH-2F8B5;Lo;0;L;62B1;;;;N;;;;;
+2F8B6;CJK COMPATIBILITY IDEOGRAPH-2F8B6;Lo;0;L;62D4;;;;N;;;;;
+2F8B7;CJK COMPATIBILITY IDEOGRAPH-2F8B7;Lo;0;L;6350;;;;N;;;;;
+2F8B8;CJK COMPATIBILITY IDEOGRAPH-2F8B8;Lo;0;L;22B0C;;;;N;;;;;
+2F8B9;CJK COMPATIBILITY IDEOGRAPH-2F8B9;Lo;0;L;633D;;;;N;;;;;
+2F8BA;CJK COMPATIBILITY IDEOGRAPH-2F8BA;Lo;0;L;62FC;;;;N;;;;;
+2F8BB;CJK COMPATIBILITY IDEOGRAPH-2F8BB;Lo;0;L;6368;;;;N;;;;;
+2F8BC;CJK COMPATIBILITY IDEOGRAPH-2F8BC;Lo;0;L;6383;;;;N;;;;;
+2F8BD;CJK COMPATIBILITY IDEOGRAPH-2F8BD;Lo;0;L;63E4;;;;N;;;;;
+2F8BE;CJK COMPATIBILITY IDEOGRAPH-2F8BE;Lo;0;L;22BF1;;;;N;;;;;
+2F8BF;CJK COMPATIBILITY IDEOGRAPH-2F8BF;Lo;0;L;6422;;;;N;;;;;
+2F8C0;CJK COMPATIBILITY IDEOGRAPH-2F8C0;Lo;0;L;63C5;;;;N;;;;;
+2F8C1;CJK COMPATIBILITY IDEOGRAPH-2F8C1;Lo;0;L;63A9;;;;N;;;;;
+2F8C2;CJK COMPATIBILITY IDEOGRAPH-2F8C2;Lo;0;L;3A2E;;;;N;;;;;
+2F8C3;CJK COMPATIBILITY IDEOGRAPH-2F8C3;Lo;0;L;6469;;;;N;;;;;
+2F8C4;CJK COMPATIBILITY IDEOGRAPH-2F8C4;Lo;0;L;647E;;;;N;;;;;
+2F8C5;CJK COMPATIBILITY IDEOGRAPH-2F8C5;Lo;0;L;649D;;;;N;;;;;
+2F8C6;CJK COMPATIBILITY IDEOGRAPH-2F8C6;Lo;0;L;6477;;;;N;;;;;
+2F8C7;CJK COMPATIBILITY IDEOGRAPH-2F8C7;Lo;0;L;3A6C;;;;N;;;;;
+2F8C8;CJK COMPATIBILITY IDEOGRAPH-2F8C8;Lo;0;L;654F;;;;N;;;;;
+2F8C9;CJK COMPATIBILITY IDEOGRAPH-2F8C9;Lo;0;L;656C;;;;N;;;;;
+2F8CA;CJK COMPATIBILITY IDEOGRAPH-2F8CA;Lo;0;L;2300A;;;;N;;;;;
+2F8CB;CJK COMPATIBILITY IDEOGRAPH-2F8CB;Lo;0;L;65E3;;;;N;;;;;
+2F8CC;CJK COMPATIBILITY IDEOGRAPH-2F8CC;Lo;0;L;66F8;;;;N;;;;;
+2F8CD;CJK COMPATIBILITY IDEOGRAPH-2F8CD;Lo;0;L;6649;;;;N;;;;;
+2F8CE;CJK COMPATIBILITY IDEOGRAPH-2F8CE;Lo;0;L;3B19;;;;N;;;;;
+2F8CF;CJK COMPATIBILITY IDEOGRAPH-2F8CF;Lo;0;L;6691;;;;N;;;;;
+2F8D0;CJK COMPATIBILITY IDEOGRAPH-2F8D0;Lo;0;L;3B08;;;;N;;;;;
+2F8D1;CJK COMPATIBILITY IDEOGRAPH-2F8D1;Lo;0;L;3AE4;;;;N;;;;;
+2F8D2;CJK COMPATIBILITY IDEOGRAPH-2F8D2;Lo;0;L;5192;;;;N;;;;;
+2F8D3;CJK COMPATIBILITY IDEOGRAPH-2F8D3;Lo;0;L;5195;;;;N;;;;;
+2F8D4;CJK COMPATIBILITY IDEOGRAPH-2F8D4;Lo;0;L;6700;;;;N;;;;;
+2F8D5;CJK COMPATIBILITY IDEOGRAPH-2F8D5;Lo;0;L;669C;;;;N;;;;;
+2F8D6;CJK COMPATIBILITY IDEOGRAPH-2F8D6;Lo;0;L;80AD;;;;N;;;;;
+2F8D7;CJK COMPATIBILITY IDEOGRAPH-2F8D7;Lo;0;L;43D9;;;;N;;;;;
+2F8D8;CJK COMPATIBILITY IDEOGRAPH-2F8D8;Lo;0;L;6717;;;;N;;;;;
+2F8D9;CJK COMPATIBILITY IDEOGRAPH-2F8D9;Lo;0;L;671B;;;;N;;;;;
+2F8DA;CJK COMPATIBILITY IDEOGRAPH-2F8DA;Lo;0;L;6721;;;;N;;;;;
+2F8DB;CJK COMPATIBILITY IDEOGRAPH-2F8DB;Lo;0;L;675E;;;;N;;;;;
+2F8DC;CJK COMPATIBILITY IDEOGRAPH-2F8DC;Lo;0;L;6753;;;;N;;;;;
+2F8DD;CJK COMPATIBILITY IDEOGRAPH-2F8DD;Lo;0;L;233C3;;;;N;;;;;
+2F8DE;CJK COMPATIBILITY IDEOGRAPH-2F8DE;Lo;0;L;3B49;;;;N;;;;;
+2F8DF;CJK COMPATIBILITY IDEOGRAPH-2F8DF;Lo;0;L;67FA;;;;N;;;;;
+2F8E0;CJK COMPATIBILITY IDEOGRAPH-2F8E0;Lo;0;L;6785;;;;N;;;;;
+2F8E1;CJK COMPATIBILITY IDEOGRAPH-2F8E1;Lo;0;L;6852;;;;N;;;;;
+2F8E2;CJK COMPATIBILITY IDEOGRAPH-2F8E2;Lo;0;L;6885;;;;N;;;;;
+2F8E3;CJK COMPATIBILITY IDEOGRAPH-2F8E3;Lo;0;L;2346D;;;;N;;;;;
+2F8E4;CJK COMPATIBILITY IDEOGRAPH-2F8E4;Lo;0;L;688E;;;;N;;;;;
+2F8E5;CJK COMPATIBILITY IDEOGRAPH-2F8E5;Lo;0;L;681F;;;;N;;;;;
+2F8E6;CJK COMPATIBILITY IDEOGRAPH-2F8E6;Lo;0;L;6914;;;;N;;;;;
+2F8E7;CJK COMPATIBILITY IDEOGRAPH-2F8E7;Lo;0;L;3B9D;;;;N;;;;;
+2F8E8;CJK COMPATIBILITY IDEOGRAPH-2F8E8;Lo;0;L;6942;;;;N;;;;;
+2F8E9;CJK COMPATIBILITY IDEOGRAPH-2F8E9;Lo;0;L;69A3;;;;N;;;;;
+2F8EA;CJK COMPATIBILITY IDEOGRAPH-2F8EA;Lo;0;L;69EA;;;;N;;;;;
+2F8EB;CJK COMPATIBILITY IDEOGRAPH-2F8EB;Lo;0;L;6AA8;;;;N;;;;;
+2F8EC;CJK COMPATIBILITY IDEOGRAPH-2F8EC;Lo;0;L;236A3;;;;N;;;;;
+2F8ED;CJK COMPATIBILITY IDEOGRAPH-2F8ED;Lo;0;L;6ADB;;;;N;;;;;
+2F8EE;CJK COMPATIBILITY IDEOGRAPH-2F8EE;Lo;0;L;3C18;;;;N;;;;;
+2F8EF;CJK COMPATIBILITY IDEOGRAPH-2F8EF;Lo;0;L;6B21;;;;N;;;;;
+2F8F0;CJK COMPATIBILITY IDEOGRAPH-2F8F0;Lo;0;L;238A7;;;;N;;;;;
+2F8F1;CJK COMPATIBILITY IDEOGRAPH-2F8F1;Lo;0;L;6B54;;;;N;;;;;
+2F8F2;CJK COMPATIBILITY IDEOGRAPH-2F8F2;Lo;0;L;3C4E;;;;N;;;;;
+2F8F3;CJK COMPATIBILITY IDEOGRAPH-2F8F3;Lo;0;L;6B72;;;;N;;;;;
+2F8F4;CJK COMPATIBILITY IDEOGRAPH-2F8F4;Lo;0;L;6B9F;;;;N;;;;;
+2F8F5;CJK COMPATIBILITY IDEOGRAPH-2F8F5;Lo;0;L;6BBA;;;;N;;;;;
+2F8F6;CJK COMPATIBILITY IDEOGRAPH-2F8F6;Lo;0;L;6BBB;;;;N;;;;;
+2F8F7;CJK COMPATIBILITY IDEOGRAPH-2F8F7;Lo;0;L;23A8D;;;;N;;;;;
+2F8F8;CJK COMPATIBILITY IDEOGRAPH-2F8F8;Lo;0;L;21D0B;;;;N;;;;;
+2F8F9;CJK COMPATIBILITY IDEOGRAPH-2F8F9;Lo;0;L;23AFA;;;;N;;;;;
+2F8FA;CJK COMPATIBILITY IDEOGRAPH-2F8FA;Lo;0;L;6C4E;;;;N;;;;;
+2F8FB;CJK COMPATIBILITY IDEOGRAPH-2F8FB;Lo;0;L;23CBC;;;;N;;;;;
+2F8FC;CJK COMPATIBILITY IDEOGRAPH-2F8FC;Lo;0;L;6CBF;;;;N;;;;;
+2F8FD;CJK COMPATIBILITY IDEOGRAPH-2F8FD;Lo;0;L;6CCD;;;;N;;;;;
+2F8FE;CJK COMPATIBILITY IDEOGRAPH-2F8FE;Lo;0;L;6C67;;;;N;;;;;
+2F8FF;CJK COMPATIBILITY IDEOGRAPH-2F8FF;Lo;0;L;6D16;;;;N;;;;;
+2F900;CJK COMPATIBILITY IDEOGRAPH-2F900;Lo;0;L;6D3E;;;;N;;;;;
+2F901;CJK COMPATIBILITY IDEOGRAPH-2F901;Lo;0;L;6D77;;;;N;;;;;
+2F902;CJK COMPATIBILITY IDEOGRAPH-2F902;Lo;0;L;6D41;;;;N;;;;;
+2F903;CJK COMPATIBILITY IDEOGRAPH-2F903;Lo;0;L;6D69;;;;N;;;;;
+2F904;CJK COMPATIBILITY IDEOGRAPH-2F904;Lo;0;L;6D78;;;;N;;;;;
+2F905;CJK COMPATIBILITY IDEOGRAPH-2F905;Lo;0;L;6D85;;;;N;;;;;
+2F906;CJK COMPATIBILITY IDEOGRAPH-2F906;Lo;0;L;23D1E;;;;N;;;;;
+2F907;CJK COMPATIBILITY IDEOGRAPH-2F907;Lo;0;L;6D34;;;;N;;;;;
+2F908;CJK COMPATIBILITY IDEOGRAPH-2F908;Lo;0;L;6E2F;;;;N;;;;;
+2F909;CJK COMPATIBILITY IDEOGRAPH-2F909;Lo;0;L;6E6E;;;;N;;;;;
+2F90A;CJK COMPATIBILITY IDEOGRAPH-2F90A;Lo;0;L;3D33;;;;N;;;;;
+2F90B;CJK COMPATIBILITY IDEOGRAPH-2F90B;Lo;0;L;6ECB;;;;N;;;;;
+2F90C;CJK COMPATIBILITY IDEOGRAPH-2F90C;Lo;0;L;6EC7;;;;N;;;;;
+2F90D;CJK COMPATIBILITY IDEOGRAPH-2F90D;Lo;0;L;23ED1;;;;N;;;;;
+2F90E;CJK COMPATIBILITY IDEOGRAPH-2F90E;Lo;0;L;6DF9;;;;N;;;;;
+2F90F;CJK COMPATIBILITY IDEOGRAPH-2F90F;Lo;0;L;6F6E;;;;N;;;;;
+2F910;CJK COMPATIBILITY IDEOGRAPH-2F910;Lo;0;L;23F5E;;;;N;;;;;
+2F911;CJK COMPATIBILITY IDEOGRAPH-2F911;Lo;0;L;23F8E;;;;N;;;;;
+2F912;CJK COMPATIBILITY IDEOGRAPH-2F912;Lo;0;L;6FC6;;;;N;;;;;
+2F913;CJK COMPATIBILITY IDEOGRAPH-2F913;Lo;0;L;7039;;;;N;;;;;
+2F914;CJK COMPATIBILITY IDEOGRAPH-2F914;Lo;0;L;701E;;;;N;;;;;
+2F915;CJK COMPATIBILITY IDEOGRAPH-2F915;Lo;0;L;701B;;;;N;;;;;
+2F916;CJK COMPATIBILITY IDEOGRAPH-2F916;Lo;0;L;3D96;;;;N;;;;;
+2F917;CJK COMPATIBILITY IDEOGRAPH-2F917;Lo;0;L;704A;;;;N;;;;;
+2F918;CJK COMPATIBILITY IDEOGRAPH-2F918;Lo;0;L;707D;;;;N;;;;;
+2F919;CJK COMPATIBILITY IDEOGRAPH-2F919;Lo;0;L;7077;;;;N;;;;;
+2F91A;CJK COMPATIBILITY IDEOGRAPH-2F91A;Lo;0;L;70AD;;;;N;;;;;
+2F91B;CJK COMPATIBILITY IDEOGRAPH-2F91B;Lo;0;L;20525;;;;N;;;;;
+2F91C;CJK COMPATIBILITY IDEOGRAPH-2F91C;Lo;0;L;7145;;;;N;;;;;
+2F91D;CJK COMPATIBILITY IDEOGRAPH-2F91D;Lo;0;L;24263;;;;N;;;;;
+2F91E;CJK COMPATIBILITY IDEOGRAPH-2F91E;Lo;0;L;719C;;;;N;;;;;
+2F91F;CJK COMPATIBILITY IDEOGRAPH-2F91F;Lo;0;L;243AB;;;;N;;;;;
+2F920;CJK COMPATIBILITY IDEOGRAPH-2F920;Lo;0;L;7228;;;;N;;;;;
+2F921;CJK COMPATIBILITY IDEOGRAPH-2F921;Lo;0;L;7235;;;;N;;;;;
+2F922;CJK COMPATIBILITY IDEOGRAPH-2F922;Lo;0;L;7250;;;;N;;;;;
+2F923;CJK COMPATIBILITY IDEOGRAPH-2F923;Lo;0;L;24608;;;;N;;;;;
+2F924;CJK COMPATIBILITY IDEOGRAPH-2F924;Lo;0;L;7280;;;;N;;;;;
+2F925;CJK COMPATIBILITY IDEOGRAPH-2F925;Lo;0;L;7295;;;;N;;;;;
+2F926;CJK COMPATIBILITY IDEOGRAPH-2F926;Lo;0;L;24735;;;;N;;;;;
+2F927;CJK COMPATIBILITY IDEOGRAPH-2F927;Lo;0;L;24814;;;;N;;;;;
+2F928;CJK COMPATIBILITY IDEOGRAPH-2F928;Lo;0;L;737A;;;;N;;;;;
+2F929;CJK COMPATIBILITY IDEOGRAPH-2F929;Lo;0;L;738B;;;;N;;;;;
+2F92A;CJK COMPATIBILITY IDEOGRAPH-2F92A;Lo;0;L;3EAC;;;;N;;;;;
+2F92B;CJK COMPATIBILITY IDEOGRAPH-2F92B;Lo;0;L;73A5;;;;N;;;;;
+2F92C;CJK COMPATIBILITY IDEOGRAPH-2F92C;Lo;0;L;3EB8;;;;N;;;;;
+2F92D;CJK COMPATIBILITY IDEOGRAPH-2F92D;Lo;0;L;3EB8;;;;N;;;;;
+2F92E;CJK COMPATIBILITY IDEOGRAPH-2F92E;Lo;0;L;7447;;;;N;;;;;
+2F92F;CJK COMPATIBILITY IDEOGRAPH-2F92F;Lo;0;L;745C;;;;N;;;;;
+2F930;CJK COMPATIBILITY IDEOGRAPH-2F930;Lo;0;L;7471;;;;N;;;;;
+2F931;CJK COMPATIBILITY IDEOGRAPH-2F931;Lo;0;L;7485;;;;N;;;;;
+2F932;CJK COMPATIBILITY IDEOGRAPH-2F932;Lo;0;L;74CA;;;;N;;;;;
+2F933;CJK COMPATIBILITY IDEOGRAPH-2F933;Lo;0;L;3F1B;;;;N;;;;;
+2F934;CJK COMPATIBILITY IDEOGRAPH-2F934;Lo;0;L;7524;;;;N;;;;;
+2F935;CJK COMPATIBILITY IDEOGRAPH-2F935;Lo;0;L;24C36;;;;N;;;;;
+2F936;CJK COMPATIBILITY IDEOGRAPH-2F936;Lo;0;L;753E;;;;N;;;;;
+2F937;CJK COMPATIBILITY IDEOGRAPH-2F937;Lo;0;L;24C92;;;;N;;;;;
+2F938;CJK COMPATIBILITY IDEOGRAPH-2F938;Lo;0;L;7570;;;;N;;;;;
+2F939;CJK COMPATIBILITY IDEOGRAPH-2F939;Lo;0;L;2219F;;;;N;;;;;
+2F93A;CJK COMPATIBILITY IDEOGRAPH-2F93A;Lo;0;L;7610;;;;N;;;;;
+2F93B;CJK COMPATIBILITY IDEOGRAPH-2F93B;Lo;0;L;24FA1;;;;N;;;;;
+2F93C;CJK COMPATIBILITY IDEOGRAPH-2F93C;Lo;0;L;24FB8;;;;N;;;;;
+2F93D;CJK COMPATIBILITY IDEOGRAPH-2F93D;Lo;0;L;25044;;;;N;;;;;
+2F93E;CJK COMPATIBILITY IDEOGRAPH-2F93E;Lo;0;L;3FFC;;;;N;;;;;
+2F93F;CJK COMPATIBILITY IDEOGRAPH-2F93F;Lo;0;L;4008;;;;N;;;;;
+2F940;CJK COMPATIBILITY IDEOGRAPH-2F940;Lo;0;L;76F4;;;;N;;;;;
+2F941;CJK COMPATIBILITY IDEOGRAPH-2F941;Lo;0;L;250F3;;;;N;;;;;
+2F942;CJK COMPATIBILITY IDEOGRAPH-2F942;Lo;0;L;250F2;;;;N;;;;;
+2F943;CJK COMPATIBILITY IDEOGRAPH-2F943;Lo;0;L;25119;;;;N;;;;;
+2F944;CJK COMPATIBILITY IDEOGRAPH-2F944;Lo;0;L;25133;;;;N;;;;;
+2F945;CJK COMPATIBILITY IDEOGRAPH-2F945;Lo;0;L;771E;;;;N;;;;;
+2F946;CJK COMPATIBILITY IDEOGRAPH-2F946;Lo;0;L;771F;;;;N;;;;;
+2F947;CJK COMPATIBILITY IDEOGRAPH-2F947;Lo;0;L;771F;;;;N;;;;;
+2F948;CJK COMPATIBILITY IDEOGRAPH-2F948;Lo;0;L;774A;;;;N;;;;;
+2F949;CJK COMPATIBILITY IDEOGRAPH-2F949;Lo;0;L;4039;;;;N;;;;;
+2F94A;CJK COMPATIBILITY IDEOGRAPH-2F94A;Lo;0;L;778B;;;;N;;;;;
+2F94B;CJK COMPATIBILITY IDEOGRAPH-2F94B;Lo;0;L;4046;;;;N;;;;;
+2F94C;CJK COMPATIBILITY IDEOGRAPH-2F94C;Lo;0;L;4096;;;;N;;;;;
+2F94D;CJK COMPATIBILITY IDEOGRAPH-2F94D;Lo;0;L;2541D;;;;N;;;;;
+2F94E;CJK COMPATIBILITY IDEOGRAPH-2F94E;Lo;0;L;784E;;;;N;;;;;
+2F94F;CJK COMPATIBILITY IDEOGRAPH-2F94F;Lo;0;L;788C;;;;N;;;;;
+2F950;CJK COMPATIBILITY IDEOGRAPH-2F950;Lo;0;L;78CC;;;;N;;;;;
+2F951;CJK COMPATIBILITY IDEOGRAPH-2F951;Lo;0;L;40E3;;;;N;;;;;
+2F952;CJK COMPATIBILITY IDEOGRAPH-2F952;Lo;0;L;25626;;;;N;;;;;
+2F953;CJK COMPATIBILITY IDEOGRAPH-2F953;Lo;0;L;7956;;;;N;;;;;
+2F954;CJK COMPATIBILITY IDEOGRAPH-2F954;Lo;0;L;2569A;;;;N;;;;;
+2F955;CJK COMPATIBILITY IDEOGRAPH-2F955;Lo;0;L;256C5;;;;N;;;;;
+2F956;CJK COMPATIBILITY IDEOGRAPH-2F956;Lo;0;L;798F;;;;N;;;;;
+2F957;CJK COMPATIBILITY IDEOGRAPH-2F957;Lo;0;L;79EB;;;;N;;;;;
+2F958;CJK COMPATIBILITY IDEOGRAPH-2F958;Lo;0;L;412F;;;;N;;;;;
+2F959;CJK COMPATIBILITY IDEOGRAPH-2F959;Lo;0;L;7A40;;;;N;;;;;
+2F95A;CJK COMPATIBILITY IDEOGRAPH-2F95A;Lo;0;L;7A4A;;;;N;;;;;
+2F95B;CJK COMPATIBILITY IDEOGRAPH-2F95B;Lo;0;L;7A4F;;;;N;;;;;
+2F95C;CJK COMPATIBILITY IDEOGRAPH-2F95C;Lo;0;L;2597C;;;;N;;;;;
+2F95D;CJK COMPATIBILITY IDEOGRAPH-2F95D;Lo;0;L;25AA7;;;;N;;;;;
+2F95E;CJK COMPATIBILITY IDEOGRAPH-2F95E;Lo;0;L;25AA7;;;;N;;;;;
+2F95F;CJK COMPATIBILITY IDEOGRAPH-2F95F;Lo;0;L;7AEE;;;;N;;;;;
+2F960;CJK COMPATIBILITY IDEOGRAPH-2F960;Lo;0;L;4202;;;;N;;;;;
+2F961;CJK COMPATIBILITY IDEOGRAPH-2F961;Lo;0;L;25BAB;;;;N;;;;;
+2F962;CJK COMPATIBILITY IDEOGRAPH-2F962;Lo;0;L;7BC6;;;;N;;;;;
+2F963;CJK COMPATIBILITY IDEOGRAPH-2F963;Lo;0;L;7BC9;;;;N;;;;;
+2F964;CJK COMPATIBILITY IDEOGRAPH-2F964;Lo;0;L;4227;;;;N;;;;;
+2F965;CJK COMPATIBILITY IDEOGRAPH-2F965;Lo;0;L;25C80;;;;N;;;;;
+2F966;CJK COMPATIBILITY IDEOGRAPH-2F966;Lo;0;L;7CD2;;;;N;;;;;
+2F967;CJK COMPATIBILITY IDEOGRAPH-2F967;Lo;0;L;42A0;;;;N;;;;;
+2F968;CJK COMPATIBILITY IDEOGRAPH-2F968;Lo;0;L;7CE8;;;;N;;;;;
+2F969;CJK COMPATIBILITY IDEOGRAPH-2F969;Lo;0;L;7CE3;;;;N;;;;;
+2F96A;CJK COMPATIBILITY IDEOGRAPH-2F96A;Lo;0;L;7D00;;;;N;;;;;
+2F96B;CJK COMPATIBILITY IDEOGRAPH-2F96B;Lo;0;L;25F86;;;;N;;;;;
+2F96C;CJK COMPATIBILITY IDEOGRAPH-2F96C;Lo;0;L;7D63;;;;N;;;;;
+2F96D;CJK COMPATIBILITY IDEOGRAPH-2F96D;Lo;0;L;4301;;;;N;;;;;
+2F96E;CJK COMPATIBILITY IDEOGRAPH-2F96E;Lo;0;L;7DC7;;;;N;;;;;
+2F96F;CJK COMPATIBILITY IDEOGRAPH-2F96F;Lo;0;L;7E02;;;;N;;;;;
+2F970;CJK COMPATIBILITY IDEOGRAPH-2F970;Lo;0;L;7E45;;;;N;;;;;
+2F971;CJK COMPATIBILITY IDEOGRAPH-2F971;Lo;0;L;4334;;;;N;;;;;
+2F972;CJK COMPATIBILITY IDEOGRAPH-2F972;Lo;0;L;26228;;;;N;;;;;
+2F973;CJK COMPATIBILITY IDEOGRAPH-2F973;Lo;0;L;26247;;;;N;;;;;
+2F974;CJK COMPATIBILITY IDEOGRAPH-2F974;Lo;0;L;4359;;;;N;;;;;
+2F975;CJK COMPATIBILITY IDEOGRAPH-2F975;Lo;0;L;262D9;;;;N;;;;;
+2F976;CJK COMPATIBILITY IDEOGRAPH-2F976;Lo;0;L;7F7A;;;;N;;;;;
+2F977;CJK COMPATIBILITY IDEOGRAPH-2F977;Lo;0;L;2633E;;;;N;;;;;
+2F978;CJK COMPATIBILITY IDEOGRAPH-2F978;Lo;0;L;7F95;;;;N;;;;;
+2F979;CJK COMPATIBILITY IDEOGRAPH-2F979;Lo;0;L;7FFA;;;;N;;;;;
+2F97A;CJK COMPATIBILITY IDEOGRAPH-2F97A;Lo;0;L;8005;;;;N;;;;;
+2F97B;CJK COMPATIBILITY IDEOGRAPH-2F97B;Lo;0;L;264DA;;;;N;;;;;
+2F97C;CJK COMPATIBILITY IDEOGRAPH-2F97C;Lo;0;L;26523;;;;N;;;;;
+2F97D;CJK COMPATIBILITY IDEOGRAPH-2F97D;Lo;0;L;8060;;;;N;;;;;
+2F97E;CJK COMPATIBILITY IDEOGRAPH-2F97E;Lo;0;L;265A8;;;;N;;;;;
+2F97F;CJK COMPATIBILITY IDEOGRAPH-2F97F;Lo;0;L;8070;;;;N;;;;;
+2F980;CJK COMPATIBILITY IDEOGRAPH-2F980;Lo;0;L;2335F;;;;N;;;;;
+2F981;CJK COMPATIBILITY IDEOGRAPH-2F981;Lo;0;L;43D5;;;;N;;;;;
+2F982;CJK COMPATIBILITY IDEOGRAPH-2F982;Lo;0;L;80B2;;;;N;;;;;
+2F983;CJK COMPATIBILITY IDEOGRAPH-2F983;Lo;0;L;8103;;;;N;;;;;
+2F984;CJK COMPATIBILITY IDEOGRAPH-2F984;Lo;0;L;440B;;;;N;;;;;
+2F985;CJK COMPATIBILITY IDEOGRAPH-2F985;Lo;0;L;813E;;;;N;;;;;
+2F986;CJK COMPATIBILITY IDEOGRAPH-2F986;Lo;0;L;5AB5;;;;N;;;;;
+2F987;CJK COMPATIBILITY IDEOGRAPH-2F987;Lo;0;L;267A7;;;;N;;;;;
+2F988;CJK COMPATIBILITY IDEOGRAPH-2F988;Lo;0;L;267B5;;;;N;;;;;
+2F989;CJK COMPATIBILITY IDEOGRAPH-2F989;Lo;0;L;23393;;;;N;;;;;
+2F98A;CJK COMPATIBILITY IDEOGRAPH-2F98A;Lo;0;L;2339C;;;;N;;;;;
+2F98B;CJK COMPATIBILITY IDEOGRAPH-2F98B;Lo;0;L;8201;;;;N;;;;;
+2F98C;CJK COMPATIBILITY IDEOGRAPH-2F98C;Lo;0;L;8204;;;;N;;;;;
+2F98D;CJK COMPATIBILITY IDEOGRAPH-2F98D;Lo;0;L;8F9E;;;;N;;;;;
+2F98E;CJK COMPATIBILITY IDEOGRAPH-2F98E;Lo;0;L;446B;;;;N;;;;;
+2F98F;CJK COMPATIBILITY IDEOGRAPH-2F98F;Lo;0;L;8291;;;;N;;;;;
+2F990;CJK COMPATIBILITY IDEOGRAPH-2F990;Lo;0;L;828B;;;;N;;;;;
+2F991;CJK COMPATIBILITY IDEOGRAPH-2F991;Lo;0;L;829D;;;;N;;;;;
+2F992;CJK COMPATIBILITY IDEOGRAPH-2F992;Lo;0;L;52B3;;;;N;;;;;
+2F993;CJK COMPATIBILITY IDEOGRAPH-2F993;Lo;0;L;82B1;;;;N;;;;;
+2F994;CJK COMPATIBILITY IDEOGRAPH-2F994;Lo;0;L;82B3;;;;N;;;;;
+2F995;CJK COMPATIBILITY IDEOGRAPH-2F995;Lo;0;L;82BD;;;;N;;;;;
+2F996;CJK COMPATIBILITY IDEOGRAPH-2F996;Lo;0;L;82E6;;;;N;;;;;
+2F997;CJK COMPATIBILITY IDEOGRAPH-2F997;Lo;0;L;26B3C;;;;N;;;;;
+2F998;CJK COMPATIBILITY IDEOGRAPH-2F998;Lo;0;L;82E5;;;;N;;;;;
+2F999;CJK COMPATIBILITY IDEOGRAPH-2F999;Lo;0;L;831D;;;;N;;;;;
+2F99A;CJK COMPATIBILITY IDEOGRAPH-2F99A;Lo;0;L;8363;;;;N;;;;;
+2F99B;CJK COMPATIBILITY IDEOGRAPH-2F99B;Lo;0;L;83AD;;;;N;;;;;
+2F99C;CJK COMPATIBILITY IDEOGRAPH-2F99C;Lo;0;L;8323;;;;N;;;;;
+2F99D;CJK COMPATIBILITY IDEOGRAPH-2F99D;Lo;0;L;83BD;;;;N;;;;;
+2F99E;CJK COMPATIBILITY IDEOGRAPH-2F99E;Lo;0;L;83E7;;;;N;;;;;
+2F99F;CJK COMPATIBILITY IDEOGRAPH-2F99F;Lo;0;L;8457;;;;N;;;;;
+2F9A0;CJK COMPATIBILITY IDEOGRAPH-2F9A0;Lo;0;L;8353;;;;N;;;;;
+2F9A1;CJK COMPATIBILITY IDEOGRAPH-2F9A1;Lo;0;L;83CA;;;;N;;;;;
+2F9A2;CJK COMPATIBILITY IDEOGRAPH-2F9A2;Lo;0;L;83CC;;;;N;;;;;
+2F9A3;CJK COMPATIBILITY IDEOGRAPH-2F9A3;Lo;0;L;83DC;;;;N;;;;;
+2F9A4;CJK COMPATIBILITY IDEOGRAPH-2F9A4;Lo;0;L;26C36;;;;N;;;;;
+2F9A5;CJK COMPATIBILITY IDEOGRAPH-2F9A5;Lo;0;L;26D6B;;;;N;;;;;
+2F9A6;CJK COMPATIBILITY IDEOGRAPH-2F9A6;Lo;0;L;26CD5;;;;N;;;;;
+2F9A7;CJK COMPATIBILITY IDEOGRAPH-2F9A7;Lo;0;L;452B;;;;N;;;;;
+2F9A8;CJK COMPATIBILITY IDEOGRAPH-2F9A8;Lo;0;L;84F1;;;;N;;;;;
+2F9A9;CJK COMPATIBILITY IDEOGRAPH-2F9A9;Lo;0;L;84F3;;;;N;;;;;
+2F9AA;CJK COMPATIBILITY IDEOGRAPH-2F9AA;Lo;0;L;8516;;;;N;;;;;
+2F9AB;CJK COMPATIBILITY IDEOGRAPH-2F9AB;Lo;0;L;273CA;;;;N;;;;;
+2F9AC;CJK COMPATIBILITY IDEOGRAPH-2F9AC;Lo;0;L;8564;;;;N;;;;;
+2F9AD;CJK COMPATIBILITY IDEOGRAPH-2F9AD;Lo;0;L;26F2C;;;;N;;;;;
+2F9AE;CJK COMPATIBILITY IDEOGRAPH-2F9AE;Lo;0;L;455D;;;;N;;;;;
+2F9AF;CJK COMPATIBILITY IDEOGRAPH-2F9AF;Lo;0;L;4561;;;;N;;;;;
+2F9B0;CJK COMPATIBILITY IDEOGRAPH-2F9B0;Lo;0;L;26FB1;;;;N;;;;;
+2F9B1;CJK COMPATIBILITY IDEOGRAPH-2F9B1;Lo;0;L;270D2;;;;N;;;;;
+2F9B2;CJK COMPATIBILITY IDEOGRAPH-2F9B2;Lo;0;L;456B;;;;N;;;;;
+2F9B3;CJK COMPATIBILITY IDEOGRAPH-2F9B3;Lo;0;L;8650;;;;N;;;;;
+2F9B4;CJK COMPATIBILITY IDEOGRAPH-2F9B4;Lo;0;L;865C;;;;N;;;;;
+2F9B5;CJK COMPATIBILITY IDEOGRAPH-2F9B5;Lo;0;L;8667;;;;N;;;;;
+2F9B6;CJK COMPATIBILITY IDEOGRAPH-2F9B6;Lo;0;L;8669;;;;N;;;;;
+2F9B7;CJK COMPATIBILITY IDEOGRAPH-2F9B7;Lo;0;L;86A9;;;;N;;;;;
+2F9B8;CJK COMPATIBILITY IDEOGRAPH-2F9B8;Lo;0;L;8688;;;;N;;;;;
+2F9B9;CJK COMPATIBILITY IDEOGRAPH-2F9B9;Lo;0;L;870E;;;;N;;;;;
+2F9BA;CJK COMPATIBILITY IDEOGRAPH-2F9BA;Lo;0;L;86E2;;;;N;;;;;
+2F9BB;CJK COMPATIBILITY IDEOGRAPH-2F9BB;Lo;0;L;8779;;;;N;;;;;
+2F9BC;CJK COMPATIBILITY IDEOGRAPH-2F9BC;Lo;0;L;8728;;;;N;;;;;
+2F9BD;CJK COMPATIBILITY IDEOGRAPH-2F9BD;Lo;0;L;876B;;;;N;;;;;
+2F9BE;CJK COMPATIBILITY IDEOGRAPH-2F9BE;Lo;0;L;8786;;;;N;;;;;
+2F9BF;CJK COMPATIBILITY IDEOGRAPH-2F9BF;Lo;0;L;45D7;;;;N;;;;;
+2F9C0;CJK COMPATIBILITY IDEOGRAPH-2F9C0;Lo;0;L;87E1;;;;N;;;;;
+2F9C1;CJK COMPATIBILITY IDEOGRAPH-2F9C1;Lo;0;L;8801;;;;N;;;;;
+2F9C2;CJK COMPATIBILITY IDEOGRAPH-2F9C2;Lo;0;L;45F9;;;;N;;;;;
+2F9C3;CJK COMPATIBILITY IDEOGRAPH-2F9C3;Lo;0;L;8860;;;;N;;;;;
+2F9C4;CJK COMPATIBILITY IDEOGRAPH-2F9C4;Lo;0;L;8863;;;;N;;;;;
+2F9C5;CJK COMPATIBILITY IDEOGRAPH-2F9C5;Lo;0;L;27667;;;;N;;;;;
+2F9C6;CJK COMPATIBILITY IDEOGRAPH-2F9C6;Lo;0;L;88D7;;;;N;;;;;
+2F9C7;CJK COMPATIBILITY IDEOGRAPH-2F9C7;Lo;0;L;88DE;;;;N;;;;;
+2F9C8;CJK COMPATIBILITY IDEOGRAPH-2F9C8;Lo;0;L;4635;;;;N;;;;;
+2F9C9;CJK COMPATIBILITY IDEOGRAPH-2F9C9;Lo;0;L;88FA;;;;N;;;;;
+2F9CA;CJK COMPATIBILITY IDEOGRAPH-2F9CA;Lo;0;L;34BB;;;;N;;;;;
+2F9CB;CJK COMPATIBILITY IDEOGRAPH-2F9CB;Lo;0;L;278AE;;;;N;;;;;
+2F9CC;CJK COMPATIBILITY IDEOGRAPH-2F9CC;Lo;0;L;27966;;;;N;;;;;
+2F9CD;CJK COMPATIBILITY IDEOGRAPH-2F9CD;Lo;0;L;46BE;;;;N;;;;;
+2F9CE;CJK COMPATIBILITY IDEOGRAPH-2F9CE;Lo;0;L;46C7;;;;N;;;;;
+2F9CF;CJK COMPATIBILITY IDEOGRAPH-2F9CF;Lo;0;L;8AA0;;;;N;;;;;
+2F9D0;CJK COMPATIBILITY IDEOGRAPH-2F9D0;Lo;0;L;8AED;;;;N;;;;;
+2F9D1;CJK COMPATIBILITY IDEOGRAPH-2F9D1;Lo;0;L;8B8A;;;;N;;;;;
+2F9D2;CJK COMPATIBILITY IDEOGRAPH-2F9D2;Lo;0;L;8C55;;;;N;;;;;
+2F9D3;CJK COMPATIBILITY IDEOGRAPH-2F9D3;Lo;0;L;27CA8;;;;N;;;;;
+2F9D4;CJK COMPATIBILITY IDEOGRAPH-2F9D4;Lo;0;L;8CAB;;;;N;;;;;
+2F9D5;CJK COMPATIBILITY IDEOGRAPH-2F9D5;Lo;0;L;8CC1;;;;N;;;;;
+2F9D6;CJK COMPATIBILITY IDEOGRAPH-2F9D6;Lo;0;L;8D1B;;;;N;;;;;
+2F9D7;CJK COMPATIBILITY IDEOGRAPH-2F9D7;Lo;0;L;8D77;;;;N;;;;;
+2F9D8;CJK COMPATIBILITY IDEOGRAPH-2F9D8;Lo;0;L;27F2F;;;;N;;;;;
+2F9D9;CJK COMPATIBILITY IDEOGRAPH-2F9D9;Lo;0;L;20804;;;;N;;;;;
+2F9DA;CJK COMPATIBILITY IDEOGRAPH-2F9DA;Lo;0;L;8DCB;;;;N;;;;;
+2F9DB;CJK COMPATIBILITY IDEOGRAPH-2F9DB;Lo;0;L;8DBC;;;;N;;;;;
+2F9DC;CJK COMPATIBILITY IDEOGRAPH-2F9DC;Lo;0;L;8DF0;;;;N;;;;;
+2F9DD;CJK COMPATIBILITY IDEOGRAPH-2F9DD;Lo;0;L;208DE;;;;N;;;;;
+2F9DE;CJK COMPATIBILITY IDEOGRAPH-2F9DE;Lo;0;L;8ED4;;;;N;;;;;
+2F9DF;CJK COMPATIBILITY IDEOGRAPH-2F9DF;Lo;0;L;8F38;;;;N;;;;;
+2F9E0;CJK COMPATIBILITY IDEOGRAPH-2F9E0;Lo;0;L;285D2;;;;N;;;;;
+2F9E1;CJK COMPATIBILITY IDEOGRAPH-2F9E1;Lo;0;L;285ED;;;;N;;;;;
+2F9E2;CJK COMPATIBILITY IDEOGRAPH-2F9E2;Lo;0;L;9094;;;;N;;;;;
+2F9E3;CJK COMPATIBILITY IDEOGRAPH-2F9E3;Lo;0;L;90F1;;;;N;;;;;
+2F9E4;CJK COMPATIBILITY IDEOGRAPH-2F9E4;Lo;0;L;9111;;;;N;;;;;
+2F9E5;CJK COMPATIBILITY IDEOGRAPH-2F9E5;Lo;0;L;2872E;;;;N;;;;;
+2F9E6;CJK COMPATIBILITY IDEOGRAPH-2F9E6;Lo;0;L;911B;;;;N;;;;;
+2F9E7;CJK COMPATIBILITY IDEOGRAPH-2F9E7;Lo;0;L;9238;;;;N;;;;;
+2F9E8;CJK COMPATIBILITY IDEOGRAPH-2F9E8;Lo;0;L;92D7;;;;N;;;;;
+2F9E9;CJK COMPATIBILITY IDEOGRAPH-2F9E9;Lo;0;L;92D8;;;;N;;;;;
+2F9EA;CJK COMPATIBILITY IDEOGRAPH-2F9EA;Lo;0;L;927C;;;;N;;;;;
+2F9EB;CJK COMPATIBILITY IDEOGRAPH-2F9EB;Lo;0;L;93F9;;;;N;;;;;
+2F9EC;CJK COMPATIBILITY IDEOGRAPH-2F9EC;Lo;0;L;9415;;;;N;;;;;
+2F9ED;CJK COMPATIBILITY IDEOGRAPH-2F9ED;Lo;0;L;28BFA;;;;N;;;;;
+2F9EE;CJK COMPATIBILITY IDEOGRAPH-2F9EE;Lo;0;L;958B;;;;N;;;;;
+2F9EF;CJK COMPATIBILITY IDEOGRAPH-2F9EF;Lo;0;L;4995;;;;N;;;;;
+2F9F0;CJK COMPATIBILITY IDEOGRAPH-2F9F0;Lo;0;L;95B7;;;;N;;;;;
+2F9F1;CJK COMPATIBILITY IDEOGRAPH-2F9F1;Lo;0;L;28D77;;;;N;;;;;
+2F9F2;CJK COMPATIBILITY IDEOGRAPH-2F9F2;Lo;0;L;49E6;;;;N;;;;;
+2F9F3;CJK COMPATIBILITY IDEOGRAPH-2F9F3;Lo;0;L;96C3;;;;N;;;;;
+2F9F4;CJK COMPATIBILITY IDEOGRAPH-2F9F4;Lo;0;L;5DB2;;;;N;;;;;
+2F9F5;CJK COMPATIBILITY IDEOGRAPH-2F9F5;Lo;0;L;9723;;;;N;;;;;
+2F9F6;CJK COMPATIBILITY IDEOGRAPH-2F9F6;Lo;0;L;29145;;;;N;;;;;
+2F9F7;CJK COMPATIBILITY IDEOGRAPH-2F9F7;Lo;0;L;2921A;;;;N;;;;;
+2F9F8;CJK COMPATIBILITY IDEOGRAPH-2F9F8;Lo;0;L;4A6E;;;;N;;;;;
+2F9F9;CJK COMPATIBILITY IDEOGRAPH-2F9F9;Lo;0;L;4A76;;;;N;;;;;
+2F9FA;CJK COMPATIBILITY IDEOGRAPH-2F9FA;Lo;0;L;97E0;;;;N;;;;;
+2F9FB;CJK COMPATIBILITY IDEOGRAPH-2F9FB;Lo;0;L;2940A;;;;N;;;;;
+2F9FC;CJK COMPATIBILITY IDEOGRAPH-2F9FC;Lo;0;L;4AB2;;;;N;;;;;
+2F9FD;CJK COMPATIBILITY IDEOGRAPH-2F9FD;Lo;0;L;29496;;;;N;;;;;
+2F9FE;CJK COMPATIBILITY IDEOGRAPH-2F9FE;Lo;0;L;980B;;;;N;;;;;
+2F9FF;CJK COMPATIBILITY IDEOGRAPH-2F9FF;Lo;0;L;980B;;;;N;;;;;
+2FA00;CJK COMPATIBILITY IDEOGRAPH-2FA00;Lo;0;L;9829;;;;N;;;;;
+2FA01;CJK COMPATIBILITY IDEOGRAPH-2FA01;Lo;0;L;295B6;;;;N;;;;;
+2FA02;CJK COMPATIBILITY IDEOGRAPH-2FA02;Lo;0;L;98E2;;;;N;;;;;
+2FA03;CJK COMPATIBILITY IDEOGRAPH-2FA03;Lo;0;L;4B33;;;;N;;;;;
+2FA04;CJK COMPATIBILITY IDEOGRAPH-2FA04;Lo;0;L;9929;;;;N;;;;;
+2FA05;CJK COMPATIBILITY IDEOGRAPH-2FA05;Lo;0;L;99A7;;;;N;;;;;
+2FA06;CJK COMPATIBILITY IDEOGRAPH-2FA06;Lo;0;L;99C2;;;;N;;;;;
+2FA07;CJK COMPATIBILITY IDEOGRAPH-2FA07;Lo;0;L;99FE;;;;N;;;;;
+2FA08;CJK COMPATIBILITY IDEOGRAPH-2FA08;Lo;0;L;4BCE;;;;N;;;;;
+2FA09;CJK COMPATIBILITY IDEOGRAPH-2FA09;Lo;0;L;29B30;;;;N;;;;;
+2FA0A;CJK COMPATIBILITY IDEOGRAPH-2FA0A;Lo;0;L;9B12;;;;N;;;;;
+2FA0B;CJK COMPATIBILITY IDEOGRAPH-2FA0B;Lo;0;L;9C40;;;;N;;;;;
+2FA0C;CJK COMPATIBILITY IDEOGRAPH-2FA0C;Lo;0;L;9CFD;;;;N;;;;;
+2FA0D;CJK COMPATIBILITY IDEOGRAPH-2FA0D;Lo;0;L;4CCE;;;;N;;;;;
+2FA0E;CJK COMPATIBILITY IDEOGRAPH-2FA0E;Lo;0;L;4CED;;;;N;;;;;
+2FA0F;CJK COMPATIBILITY IDEOGRAPH-2FA0F;Lo;0;L;9D67;;;;N;;;;;
+2FA10;CJK COMPATIBILITY IDEOGRAPH-2FA10;Lo;0;L;2A0CE;;;;N;;;;;
+2FA11;CJK COMPATIBILITY IDEOGRAPH-2FA11;Lo;0;L;4CF8;;;;N;;;;;
+2FA12;CJK COMPATIBILITY IDEOGRAPH-2FA12;Lo;0;L;2A105;;;;N;;;;;
+2FA13;CJK COMPATIBILITY IDEOGRAPH-2FA13;Lo;0;L;2A20E;;;;N;;;;;
+2FA14;CJK COMPATIBILITY IDEOGRAPH-2FA14;Lo;0;L;2A291;;;;N;;;;;
+2FA15;CJK COMPATIBILITY IDEOGRAPH-2FA15;Lo;0;L;9EBB;;;;N;;;;;
+2FA16;CJK COMPATIBILITY IDEOGRAPH-2FA16;Lo;0;L;4D56;;;;N;;;;;
+2FA17;CJK COMPATIBILITY IDEOGRAPH-2FA17;Lo;0;L;9EF9;;;;N;;;;;
+2FA18;CJK COMPATIBILITY IDEOGRAPH-2FA18;Lo;0;L;9EFE;;;;N;;;;;
+2FA19;CJK COMPATIBILITY IDEOGRAPH-2FA19;Lo;0;L;9F05;;;;N;;;;;
+2FA1A;CJK COMPATIBILITY IDEOGRAPH-2FA1A;Lo;0;L;9F0F;;;;N;;;;;
+2FA1B;CJK COMPATIBILITY IDEOGRAPH-2FA1B;Lo;0;L;9F16;;;;N;;;;;
+2FA1C;CJK COMPATIBILITY IDEOGRAPH-2FA1C;Lo;0;L;9F3B;;;;N;;;;;
+2FA1D;CJK COMPATIBILITY IDEOGRAPH-2FA1D;Lo;0;L;2A600;;;;N;;;;;
+E0001;LANGUAGE TAG;Cf;0;BN;;;;;N;;;;;
+E0020;TAG SPACE;Cf;0;BN;;;;;N;;;;;
+E0021;TAG EXCLAMATION MARK;Cf;0;BN;;;;;N;;;;;
+E0022;TAG QUOTATION MARK;Cf;0;BN;;;;;N;;;;;
+E0023;TAG NUMBER SIGN;Cf;0;BN;;;;;N;;;;;
+E0024;TAG DOLLAR SIGN;Cf;0;BN;;;;;N;;;;;
+E0025;TAG PERCENT SIGN;Cf;0;BN;;;;;N;;;;;
+E0026;TAG AMPERSAND;Cf;0;BN;;;;;N;;;;;
+E0027;TAG APOSTROPHE;Cf;0;BN;;;;;N;;;;;
+E0028;TAG LEFT PARENTHESIS;Cf;0;BN;;;;;N;;;;;
+E0029;TAG RIGHT PARENTHESIS;Cf;0;BN;;;;;N;;;;;
+E002A;TAG ASTERISK;Cf;0;BN;;;;;N;;;;;
+E002B;TAG PLUS SIGN;Cf;0;BN;;;;;N;;;;;
+E002C;TAG COMMA;Cf;0;BN;;;;;N;;;;;
+E002D;TAG HYPHEN-MINUS;Cf;0;BN;;;;;N;;;;;
+E002E;TAG FULL STOP;Cf;0;BN;;;;;N;;;;;
+E002F;TAG SOLIDUS;Cf;0;BN;;;;;N;;;;;
+E0030;TAG DIGIT ZERO;Cf;0;BN;;;;;N;;;;;
+E0031;TAG DIGIT ONE;Cf;0;BN;;;;;N;;;;;
+E0032;TAG DIGIT TWO;Cf;0;BN;;;;;N;;;;;
+E0033;TAG DIGIT THREE;Cf;0;BN;;;;;N;;;;;
+E0034;TAG DIGIT FOUR;Cf;0;BN;;;;;N;;;;;
+E0035;TAG DIGIT FIVE;Cf;0;BN;;;;;N;;;;;
+E0036;TAG DIGIT SIX;Cf;0;BN;;;;;N;;;;;
+E0037;TAG DIGIT SEVEN;Cf;0;BN;;;;;N;;;;;
+E0038;TAG DIGIT EIGHT;Cf;0;BN;;;;;N;;;;;
+E0039;TAG DIGIT NINE;Cf;0;BN;;;;;N;;;;;
+E003A;TAG COLON;Cf;0;BN;;;;;N;;;;;
+E003B;TAG SEMICOLON;Cf;0;BN;;;;;N;;;;;
+E003C;TAG LESS-THAN SIGN;Cf;0;BN;;;;;N;;;;;
+E003D;TAG EQUALS SIGN;Cf;0;BN;;;;;N;;;;;
+E003E;TAG GREATER-THAN SIGN;Cf;0;BN;;;;;N;;;;;
+E003F;TAG QUESTION MARK;Cf;0;BN;;;;;N;;;;;
+E0040;TAG COMMERCIAL AT;Cf;0;BN;;;;;N;;;;;
+E0041;TAG LATIN CAPITAL LETTER A;Cf;0;BN;;;;;N;;;;;
+E0042;TAG LATIN CAPITAL LETTER B;Cf;0;BN;;;;;N;;;;;
+E0043;TAG LATIN CAPITAL LETTER C;Cf;0;BN;;;;;N;;;;;
+E0044;TAG LATIN CAPITAL LETTER D;Cf;0;BN;;;;;N;;;;;
+E0045;TAG LATIN CAPITAL LETTER E;Cf;0;BN;;;;;N;;;;;
+E0046;TAG LATIN CAPITAL LETTER F;Cf;0;BN;;;;;N;;;;;
+E0047;TAG LATIN CAPITAL LETTER G;Cf;0;BN;;;;;N;;;;;
+E0048;TAG LATIN CAPITAL LETTER H;Cf;0;BN;;;;;N;;;;;
+E0049;TAG LATIN CAPITAL LETTER I;Cf;0;BN;;;;;N;;;;;
+E004A;TAG LATIN CAPITAL LETTER J;Cf;0;BN;;;;;N;;;;;
+E004B;TAG LATIN CAPITAL LETTER K;Cf;0;BN;;;;;N;;;;;
+E004C;TAG LATIN CAPITAL LETTER L;Cf;0;BN;;;;;N;;;;;
+E004D;TAG LATIN CAPITAL LETTER M;Cf;0;BN;;;;;N;;;;;
+E004E;TAG LATIN CAPITAL LETTER N;Cf;0;BN;;;;;N;;;;;
+E004F;TAG LATIN CAPITAL LETTER O;Cf;0;BN;;;;;N;;;;;
+E0050;TAG LATIN CAPITAL LETTER P;Cf;0;BN;;;;;N;;;;;
+E0051;TAG LATIN CAPITAL LETTER Q;Cf;0;BN;;;;;N;;;;;
+E0052;TAG LATIN CAPITAL LETTER R;Cf;0;BN;;;;;N;;;;;
+E0053;TAG LATIN CAPITAL LETTER S;Cf;0;BN;;;;;N;;;;;
+E0054;TAG LATIN CAPITAL LETTER T;Cf;0;BN;;;;;N;;;;;
+E0055;TAG LATIN CAPITAL LETTER U;Cf;0;BN;;;;;N;;;;;
+E0056;TAG LATIN CAPITAL LETTER V;Cf;0;BN;;;;;N;;;;;
+E0057;TAG LATIN CAPITAL LETTER W;Cf;0;BN;;;;;N;;;;;
+E0058;TAG LATIN CAPITAL LETTER X;Cf;0;BN;;;;;N;;;;;
+E0059;TAG LATIN CAPITAL LETTER Y;Cf;0;BN;;;;;N;;;;;
+E005A;TAG LATIN CAPITAL LETTER Z;Cf;0;BN;;;;;N;;;;;
+E005B;TAG LEFT SQUARE BRACKET;Cf;0;BN;;;;;N;;;;;
+E005C;TAG REVERSE SOLIDUS;Cf;0;BN;;;;;N;;;;;
+E005D;TAG RIGHT SQUARE BRACKET;Cf;0;BN;;;;;N;;;;;
+E005E;TAG CIRCUMFLEX ACCENT;Cf;0;BN;;;;;N;;;;;
+E005F;TAG LOW LINE;Cf;0;BN;;;;;N;;;;;
+E0060;TAG GRAVE ACCENT;Cf;0;BN;;;;;N;;;;;
+E0061;TAG LATIN SMALL LETTER A;Cf;0;BN;;;;;N;;;;;
+E0062;TAG LATIN SMALL LETTER B;Cf;0;BN;;;;;N;;;;;
+E0063;TAG LATIN SMALL LETTER C;Cf;0;BN;;;;;N;;;;;
+E0064;TAG LATIN SMALL LETTER D;Cf;0;BN;;;;;N;;;;;
+E0065;TAG LATIN SMALL LETTER E;Cf;0;BN;;;;;N;;;;;
+E0066;TAG LATIN SMALL LETTER F;Cf;0;BN;;;;;N;;;;;
+E0067;TAG LATIN SMALL LETTER G;Cf;0;BN;;;;;N;;;;;
+E0068;TAG LATIN SMALL LETTER H;Cf;0;BN;;;;;N;;;;;
+E0069;TAG LATIN SMALL LETTER I;Cf;0;BN;;;;;N;;;;;
+E006A;TAG LATIN SMALL LETTER J;Cf;0;BN;;;;;N;;;;;
+E006B;TAG LATIN SMALL LETTER K;Cf;0;BN;;;;;N;;;;;
+E006C;TAG LATIN SMALL LETTER L;Cf;0;BN;;;;;N;;;;;
+E006D;TAG LATIN SMALL LETTER M;Cf;0;BN;;;;;N;;;;;
+E006E;TAG LATIN SMALL LETTER N;Cf;0;BN;;;;;N;;;;;
+E006F;TAG LATIN SMALL LETTER O;Cf;0;BN;;;;;N;;;;;
+E0070;TAG LATIN SMALL LETTER P;Cf;0;BN;;;;;N;;;;;
+E0071;TAG LATIN SMALL LETTER Q;Cf;0;BN;;;;;N;;;;;
+E0072;TAG LATIN SMALL LETTER R;Cf;0;BN;;;;;N;;;;;
+E0073;TAG LATIN SMALL LETTER S;Cf;0;BN;;;;;N;;;;;
+E0074;TAG LATIN SMALL LETTER T;Cf;0;BN;;;;;N;;;;;
+E0075;TAG LATIN SMALL LETTER U;Cf;0;BN;;;;;N;;;;;
+E0076;TAG LATIN SMALL LETTER V;Cf;0;BN;;;;;N;;;;;
+E0077;TAG LATIN SMALL LETTER W;Cf;0;BN;;;;;N;;;;;
+E0078;TAG LATIN SMALL LETTER X;Cf;0;BN;;;;;N;;;;;
+E0079;TAG LATIN SMALL LETTER Y;Cf;0;BN;;;;;N;;;;;
+E007A;TAG LATIN SMALL LETTER Z;Cf;0;BN;;;;;N;;;;;
+E007B;TAG LEFT CURLY BRACKET;Cf;0;BN;;;;;N;;;;;
+E007C;TAG VERTICAL LINE;Cf;0;BN;;;;;N;;;;;
+E007D;TAG RIGHT CURLY BRACKET;Cf;0;BN;;;;;N;;;;;
+E007E;TAG TILDE;Cf;0;BN;;;;;N;;;;;
+E007F;CANCEL TAG;Cf;0;BN;;;;;N;;;;;
+E0100;VARIATION SELECTOR-17;Mn;0;NSM;;;;;N;;;;;
+E0101;VARIATION SELECTOR-18;Mn;0;NSM;;;;;N;;;;;
+E0102;VARIATION SELECTOR-19;Mn;0;NSM;;;;;N;;;;;
+E0103;VARIATION SELECTOR-20;Mn;0;NSM;;;;;N;;;;;
+E0104;VARIATION SELECTOR-21;Mn;0;NSM;;;;;N;;;;;
+E0105;VARIATION SELECTOR-22;Mn;0;NSM;;;;;N;;;;;
+E0106;VARIATION SELECTOR-23;Mn;0;NSM;;;;;N;;;;;
+E0107;VARIATION SELECTOR-24;Mn;0;NSM;;;;;N;;;;;
+E0108;VARIATION SELECTOR-25;Mn;0;NSM;;;;;N;;;;;
+E0109;VARIATION SELECTOR-26;Mn;0;NSM;;;;;N;;;;;
+E010A;VARIATION SELECTOR-27;Mn;0;NSM;;;;;N;;;;;
+E010B;VARIATION SELECTOR-28;Mn;0;NSM;;;;;N;;;;;
+E010C;VARIATION SELECTOR-29;Mn;0;NSM;;;;;N;;;;;
+E010D;VARIATION SELECTOR-30;Mn;0;NSM;;;;;N;;;;;
+E010E;VARIATION SELECTOR-31;Mn;0;NSM;;;;;N;;;;;
+E010F;VARIATION SELECTOR-32;Mn;0;NSM;;;;;N;;;;;
+E0110;VARIATION SELECTOR-33;Mn;0;NSM;;;;;N;;;;;
+E0111;VARIATION SELECTOR-34;Mn;0;NSM;;;;;N;;;;;
+E0112;VARIATION SELECTOR-35;Mn;0;NSM;;;;;N;;;;;
+E0113;VARIATION SELECTOR-36;Mn;0;NSM;;;;;N;;;;;
+E0114;VARIATION SELECTOR-37;Mn;0;NSM;;;;;N;;;;;
+E0115;VARIATION SELECTOR-38;Mn;0;NSM;;;;;N;;;;;
+E0116;VARIATION SELECTOR-39;Mn;0;NSM;;;;;N;;;;;
+E0117;VARIATION SELECTOR-40;Mn;0;NSM;;;;;N;;;;;
+E0118;VARIATION SELECTOR-41;Mn;0;NSM;;;;;N;;;;;
+E0119;VARIATION SELECTOR-42;Mn;0;NSM;;;;;N;;;;;
+E011A;VARIATION SELECTOR-43;Mn;0;NSM;;;;;N;;;;;
+E011B;VARIATION SELECTOR-44;Mn;0;NSM;;;;;N;;;;;
+E011C;VARIATION SELECTOR-45;Mn;0;NSM;;;;;N;;;;;
+E011D;VARIATION SELECTOR-46;Mn;0;NSM;;;;;N;;;;;
+E011E;VARIATION SELECTOR-47;Mn;0;NSM;;;;;N;;;;;
+E011F;VARIATION SELECTOR-48;Mn;0;NSM;;;;;N;;;;;
+E0120;VARIATION SELECTOR-49;Mn;0;NSM;;;;;N;;;;;
+E0121;VARIATION SELECTOR-50;Mn;0;NSM;;;;;N;;;;;
+E0122;VARIATION SELECTOR-51;Mn;0;NSM;;;;;N;;;;;
+E0123;VARIATION SELECTOR-52;Mn;0;NSM;;;;;N;;;;;
+E0124;VARIATION SELECTOR-53;Mn;0;NSM;;;;;N;;;;;
+E0125;VARIATION SELECTOR-54;Mn;0;NSM;;;;;N;;;;;
+E0126;VARIATION SELECTOR-55;Mn;0;NSM;;;;;N;;;;;
+E0127;VARIATION SELECTOR-56;Mn;0;NSM;;;;;N;;;;;
+E0128;VARIATION SELECTOR-57;Mn;0;NSM;;;;;N;;;;;
+E0129;VARIATION SELECTOR-58;Mn;0;NSM;;;;;N;;;;;
+E012A;VARIATION SELECTOR-59;Mn;0;NSM;;;;;N;;;;;
+E012B;VARIATION SELECTOR-60;Mn;0;NSM;;;;;N;;;;;
+E012C;VARIATION SELECTOR-61;Mn;0;NSM;;;;;N;;;;;
+E012D;VARIATION SELECTOR-62;Mn;0;NSM;;;;;N;;;;;
+E012E;VARIATION SELECTOR-63;Mn;0;NSM;;;;;N;;;;;
+E012F;VARIATION SELECTOR-64;Mn;0;NSM;;;;;N;;;;;
+E0130;VARIATION SELECTOR-65;Mn;0;NSM;;;;;N;;;;;
+E0131;VARIATION SELECTOR-66;Mn;0;NSM;;;;;N;;;;;
+E0132;VARIATION SELECTOR-67;Mn;0;NSM;;;;;N;;;;;
+E0133;VARIATION SELECTOR-68;Mn;0;NSM;;;;;N;;;;;
+E0134;VARIATION SELECTOR-69;Mn;0;NSM;;;;;N;;;;;
+E0135;VARIATION SELECTOR-70;Mn;0;NSM;;;;;N;;;;;
+E0136;VARIATION SELECTOR-71;Mn;0;NSM;;;;;N;;;;;
+E0137;VARIATION SELECTOR-72;Mn;0;NSM;;;;;N;;;;;
+E0138;VARIATION SELECTOR-73;Mn;0;NSM;;;;;N;;;;;
+E0139;VARIATION SELECTOR-74;Mn;0;NSM;;;;;N;;;;;
+E013A;VARIATION SELECTOR-75;Mn;0;NSM;;;;;N;;;;;
+E013B;VARIATION SELECTOR-76;Mn;0;NSM;;;;;N;;;;;
+E013C;VARIATION SELECTOR-77;Mn;0;NSM;;;;;N;;;;;
+E013D;VARIATION SELECTOR-78;Mn;0;NSM;;;;;N;;;;;
+E013E;VARIATION SELECTOR-79;Mn;0;NSM;;;;;N;;;;;
+E013F;VARIATION SELECTOR-80;Mn;0;NSM;;;;;N;;;;;
+E0140;VARIATION SELECTOR-81;Mn;0;NSM;;;;;N;;;;;
+E0141;VARIATION SELECTOR-82;Mn;0;NSM;;;;;N;;;;;
+E0142;VARIATION SELECTOR-83;Mn;0;NSM;;;;;N;;;;;
+E0143;VARIATION SELECTOR-84;Mn;0;NSM;;;;;N;;;;;
+E0144;VARIATION SELECTOR-85;Mn;0;NSM;;;;;N;;;;;
+E0145;VARIATION SELECTOR-86;Mn;0;NSM;;;;;N;;;;;
+E0146;VARIATION SELECTOR-87;Mn;0;NSM;;;;;N;;;;;
+E0147;VARIATION SELECTOR-88;Mn;0;NSM;;;;;N;;;;;
+E0148;VARIATION SELECTOR-89;Mn;0;NSM;;;;;N;;;;;
+E0149;VARIATION SELECTOR-90;Mn;0;NSM;;;;;N;;;;;
+E014A;VARIATION SELECTOR-91;Mn;0;NSM;;;;;N;;;;;
+E014B;VARIATION SELECTOR-92;Mn;0;NSM;;;;;N;;;;;
+E014C;VARIATION SELECTOR-93;Mn;0;NSM;;;;;N;;;;;
+E014D;VARIATION SELECTOR-94;Mn;0;NSM;;;;;N;;;;;
+E014E;VARIATION SELECTOR-95;Mn;0;NSM;;;;;N;;;;;
+E014F;VARIATION SELECTOR-96;Mn;0;NSM;;;;;N;;;;;
+E0150;VARIATION SELECTOR-97;Mn;0;NSM;;;;;N;;;;;
+E0151;VARIATION SELECTOR-98;Mn;0;NSM;;;;;N;;;;;
+E0152;VARIATION SELECTOR-99;Mn;0;NSM;;;;;N;;;;;
+E0153;VARIATION SELECTOR-100;Mn;0;NSM;;;;;N;;;;;
+E0154;VARIATION SELECTOR-101;Mn;0;NSM;;;;;N;;;;;
+E0155;VARIATION SELECTOR-102;Mn;0;NSM;;;;;N;;;;;
+E0156;VARIATION SELECTOR-103;Mn;0;NSM;;;;;N;;;;;
+E0157;VARIATION SELECTOR-104;Mn;0;NSM;;;;;N;;;;;
+E0158;VARIATION SELECTOR-105;Mn;0;NSM;;;;;N;;;;;
+E0159;VARIATION SELECTOR-106;Mn;0;NSM;;;;;N;;;;;
+E015A;VARIATION SELECTOR-107;Mn;0;NSM;;;;;N;;;;;
+E015B;VARIATION SELECTOR-108;Mn;0;NSM;;;;;N;;;;;
+E015C;VARIATION SELECTOR-109;Mn;0;NSM;;;;;N;;;;;
+E015D;VARIATION SELECTOR-110;Mn;0;NSM;;;;;N;;;;;
+E015E;VARIATION SELECTOR-111;Mn;0;NSM;;;;;N;;;;;
+E015F;VARIATION SELECTOR-112;Mn;0;NSM;;;;;N;;;;;
+E0160;VARIATION SELECTOR-113;Mn;0;NSM;;;;;N;;;;;
+E0161;VARIATION SELECTOR-114;Mn;0;NSM;;;;;N;;;;;
+E0162;VARIATION SELECTOR-115;Mn;0;NSM;;;;;N;;;;;
+E0163;VARIATION SELECTOR-116;Mn;0;NSM;;;;;N;;;;;
+E0164;VARIATION SELECTOR-117;Mn;0;NSM;;;;;N;;;;;
+E0165;VARIATION SELECTOR-118;Mn;0;NSM;;;;;N;;;;;
+E0166;VARIATION SELECTOR-119;Mn;0;NSM;;;;;N;;;;;
+E0167;VARIATION SELECTOR-120;Mn;0;NSM;;;;;N;;;;;
+E0168;VARIATION SELECTOR-121;Mn;0;NSM;;;;;N;;;;;
+E0169;VARIATION SELECTOR-122;Mn;0;NSM;;;;;N;;;;;
+E016A;VARIATION SELECTOR-123;Mn;0;NSM;;;;;N;;;;;
+E016B;VARIATION SELECTOR-124;Mn;0;NSM;;;;;N;;;;;
+E016C;VARIATION SELECTOR-125;Mn;0;NSM;;;;;N;;;;;
+E016D;VARIATION SELECTOR-126;Mn;0;NSM;;;;;N;;;;;
+E016E;VARIATION SELECTOR-127;Mn;0;NSM;;;;;N;;;;;
+E016F;VARIATION SELECTOR-128;Mn;0;NSM;;;;;N;;;;;
+E0170;VARIATION SELECTOR-129;Mn;0;NSM;;;;;N;;;;;
+E0171;VARIATION SELECTOR-130;Mn;0;NSM;;;;;N;;;;;
+E0172;VARIATION SELECTOR-131;Mn;0;NSM;;;;;N;;;;;
+E0173;VARIATION SELECTOR-132;Mn;0;NSM;;;;;N;;;;;
+E0174;VARIATION SELECTOR-133;Mn;0;NSM;;;;;N;;;;;
+E0175;VARIATION SELECTOR-134;Mn;0;NSM;;;;;N;;;;;
+E0176;VARIATION SELECTOR-135;Mn;0;NSM;;;;;N;;;;;
+E0177;VARIATION SELECTOR-136;Mn;0;NSM;;;;;N;;;;;
+E0178;VARIATION SELECTOR-137;Mn;0;NSM;;;;;N;;;;;
+E0179;VARIATION SELECTOR-138;Mn;0;NSM;;;;;N;;;;;
+E017A;VARIATION SELECTOR-139;Mn;0;NSM;;;;;N;;;;;
+E017B;VARIATION SELECTOR-140;Mn;0;NSM;;;;;N;;;;;
+E017C;VARIATION SELECTOR-141;Mn;0;NSM;;;;;N;;;;;
+E017D;VARIATION SELECTOR-142;Mn;0;NSM;;;;;N;;;;;
+E017E;VARIATION SELECTOR-143;Mn;0;NSM;;;;;N;;;;;
+E017F;VARIATION SELECTOR-144;Mn;0;NSM;;;;;N;;;;;
+E0180;VARIATION SELECTOR-145;Mn;0;NSM;;;;;N;;;;;
+E0181;VARIATION SELECTOR-146;Mn;0;NSM;;;;;N;;;;;
+E0182;VARIATION SELECTOR-147;Mn;0;NSM;;;;;N;;;;;
+E0183;VARIATION SELECTOR-148;Mn;0;NSM;;;;;N;;;;;
+E0184;VARIATION SELECTOR-149;Mn;0;NSM;;;;;N;;;;;
+E0185;VARIATION SELECTOR-150;Mn;0;NSM;;;;;N;;;;;
+E0186;VARIATION SELECTOR-151;Mn;0;NSM;;;;;N;;;;;
+E0187;VARIATION SELECTOR-152;Mn;0;NSM;;;;;N;;;;;
+E0188;VARIATION SELECTOR-153;Mn;0;NSM;;;;;N;;;;;
+E0189;VARIATION SELECTOR-154;Mn;0;NSM;;;;;N;;;;;
+E018A;VARIATION SELECTOR-155;Mn;0;NSM;;;;;N;;;;;
+E018B;VARIATION SELECTOR-156;Mn;0;NSM;;;;;N;;;;;
+E018C;VARIATION SELECTOR-157;Mn;0;NSM;;;;;N;;;;;
+E018D;VARIATION SELECTOR-158;Mn;0;NSM;;;;;N;;;;;
+E018E;VARIATION SELECTOR-159;Mn;0;NSM;;;;;N;;;;;
+E018F;VARIATION SELECTOR-160;Mn;0;NSM;;;;;N;;;;;
+E0190;VARIATION SELECTOR-161;Mn;0;NSM;;;;;N;;;;;
+E0191;VARIATION SELECTOR-162;Mn;0;NSM;;;;;N;;;;;
+E0192;VARIATION SELECTOR-163;Mn;0;NSM;;;;;N;;;;;
+E0193;VARIATION SELECTOR-164;Mn;0;NSM;;;;;N;;;;;
+E0194;VARIATION SELECTOR-165;Mn;0;NSM;;;;;N;;;;;
+E0195;VARIATION SELECTOR-166;Mn;0;NSM;;;;;N;;;;;
+E0196;VARIATION SELECTOR-167;Mn;0;NSM;;;;;N;;;;;
+E0197;VARIATION SELECTOR-168;Mn;0;NSM;;;;;N;;;;;
+E0198;VARIATION SELECTOR-169;Mn;0;NSM;;;;;N;;;;;
+E0199;VARIATION SELECTOR-170;Mn;0;NSM;;;;;N;;;;;
+E019A;VARIATION SELECTOR-171;Mn;0;NSM;;;;;N;;;;;
+E019B;VARIATION SELECTOR-172;Mn;0;NSM;;;;;N;;;;;
+E019C;VARIATION SELECTOR-173;Mn;0;NSM;;;;;N;;;;;
+E019D;VARIATION SELECTOR-174;Mn;0;NSM;;;;;N;;;;;
+E019E;VARIATION SELECTOR-175;Mn;0;NSM;;;;;N;;;;;
+E019F;VARIATION SELECTOR-176;Mn;0;NSM;;;;;N;;;;;
+E01A0;VARIATION SELECTOR-177;Mn;0;NSM;;;;;N;;;;;
+E01A1;VARIATION SELECTOR-178;Mn;0;NSM;;;;;N;;;;;
+E01A2;VARIATION SELECTOR-179;Mn;0;NSM;;;;;N;;;;;
+E01A3;VARIATION SELECTOR-180;Mn;0;NSM;;;;;N;;;;;
+E01A4;VARIATION SELECTOR-181;Mn;0;NSM;;;;;N;;;;;
+E01A5;VARIATION SELECTOR-182;Mn;0;NSM;;;;;N;;;;;
+E01A6;VARIATION SELECTOR-183;Mn;0;NSM;;;;;N;;;;;
+E01A7;VARIATION SELECTOR-184;Mn;0;NSM;;;;;N;;;;;
+E01A8;VARIATION SELECTOR-185;Mn;0;NSM;;;;;N;;;;;
+E01A9;VARIATION SELECTOR-186;Mn;0;NSM;;;;;N;;;;;
+E01AA;VARIATION SELECTOR-187;Mn;0;NSM;;;;;N;;;;;
+E01AB;VARIATION SELECTOR-188;Mn;0;NSM;;;;;N;;;;;
+E01AC;VARIATION SELECTOR-189;Mn;0;NSM;;;;;N;;;;;
+E01AD;VARIATION SELECTOR-190;Mn;0;NSM;;;;;N;;;;;
+E01AE;VARIATION SELECTOR-191;Mn;0;NSM;;;;;N;;;;;
+E01AF;VARIATION SELECTOR-192;Mn;0;NSM;;;;;N;;;;;
+E01B0;VARIATION SELECTOR-193;Mn;0;NSM;;;;;N;;;;;
+E01B1;VARIATION SELECTOR-194;Mn;0;NSM;;;;;N;;;;;
+E01B2;VARIATION SELECTOR-195;Mn;0;NSM;;;;;N;;;;;
+E01B3;VARIATION SELECTOR-196;Mn;0;NSM;;;;;N;;;;;
+E01B4;VARIATION SELECTOR-197;Mn;0;NSM;;;;;N;;;;;
+E01B5;VARIATION SELECTOR-198;Mn;0;NSM;;;;;N;;;;;
+E01B6;VARIATION SELECTOR-199;Mn;0;NSM;;;;;N;;;;;
+E01B7;VARIATION SELECTOR-200;Mn;0;NSM;;;;;N;;;;;
+E01B8;VARIATION SELECTOR-201;Mn;0;NSM;;;;;N;;;;;
+E01B9;VARIATION SELECTOR-202;Mn;0;NSM;;;;;N;;;;;
+E01BA;VARIATION SELECTOR-203;Mn;0;NSM;;;;;N;;;;;
+E01BB;VARIATION SELECTOR-204;Mn;0;NSM;;;;;N;;;;;
+E01BC;VARIATION SELECTOR-205;Mn;0;NSM;;;;;N;;;;;
+E01BD;VARIATION SELECTOR-206;Mn;0;NSM;;;;;N;;;;;
+E01BE;VARIATION SELECTOR-207;Mn;0;NSM;;;;;N;;;;;
+E01BF;VARIATION SELECTOR-208;Mn;0;NSM;;;;;N;;;;;
+E01C0;VARIATION SELECTOR-209;Mn;0;NSM;;;;;N;;;;;
+E01C1;VARIATION SELECTOR-210;Mn;0;NSM;;;;;N;;;;;
+E01C2;VARIATION SELECTOR-211;Mn;0;NSM;;;;;N;;;;;
+E01C3;VARIATION SELECTOR-212;Mn;0;NSM;;;;;N;;;;;
+E01C4;VARIATION SELECTOR-213;Mn;0;NSM;;;;;N;;;;;
+E01C5;VARIATION SELECTOR-214;Mn;0;NSM;;;;;N;;;;;
+E01C6;VARIATION SELECTOR-215;Mn;0;NSM;;;;;N;;;;;
+E01C7;VARIATION SELECTOR-216;Mn;0;NSM;;;;;N;;;;;
+E01C8;VARIATION SELECTOR-217;Mn;0;NSM;;;;;N;;;;;
+E01C9;VARIATION SELECTOR-218;Mn;0;NSM;;;;;N;;;;;
+E01CA;VARIATION SELECTOR-219;Mn;0;NSM;;;;;N;;;;;
+E01CB;VARIATION SELECTOR-220;Mn;0;NSM;;;;;N;;;;;
+E01CC;VARIATION SELECTOR-221;Mn;0;NSM;;;;;N;;;;;
+E01CD;VARIATION SELECTOR-222;Mn;0;NSM;;;;;N;;;;;
+E01CE;VARIATION SELECTOR-223;Mn;0;NSM;;;;;N;;;;;
+E01CF;VARIATION SELECTOR-224;Mn;0;NSM;;;;;N;;;;;
+E01D0;VARIATION SELECTOR-225;Mn;0;NSM;;;;;N;;;;;
+E01D1;VARIATION SELECTOR-226;Mn;0;NSM;;;;;N;;;;;
+E01D2;VARIATION SELECTOR-227;Mn;0;NSM;;;;;N;;;;;
+E01D3;VARIATION SELECTOR-228;Mn;0;NSM;;;;;N;;;;;
+E01D4;VARIATION SELECTOR-229;Mn;0;NSM;;;;;N;;;;;
+E01D5;VARIATION SELECTOR-230;Mn;0;NSM;;;;;N;;;;;
+E01D6;VARIATION SELECTOR-231;Mn;0;NSM;;;;;N;;;;;
+E01D7;VARIATION SELECTOR-232;Mn;0;NSM;;;;;N;;;;;
+E01D8;VARIATION SELECTOR-233;Mn;0;NSM;;;;;N;;;;;
+E01D9;VARIATION SELECTOR-234;Mn;0;NSM;;;;;N;;;;;
+E01DA;VARIATION SELECTOR-235;Mn;0;NSM;;;;;N;;;;;
+E01DB;VARIATION SELECTOR-236;Mn;0;NSM;;;;;N;;;;;
+E01DC;VARIATION SELECTOR-237;Mn;0;NSM;;;;;N;;;;;
+E01DD;VARIATION SELECTOR-238;Mn;0;NSM;;;;;N;;;;;
+E01DE;VARIATION SELECTOR-239;Mn;0;NSM;;;;;N;;;;;
+E01DF;VARIATION SELECTOR-240;Mn;0;NSM;;;;;N;;;;;
+E01E0;VARIATION SELECTOR-241;Mn;0;NSM;;;;;N;;;;;
+E01E1;VARIATION SELECTOR-242;Mn;0;NSM;;;;;N;;;;;
+E01E2;VARIATION SELECTOR-243;Mn;0;NSM;;;;;N;;;;;
+E01E3;VARIATION SELECTOR-244;Mn;0;NSM;;;;;N;;;;;
+E01E4;VARIATION SELECTOR-245;Mn;0;NSM;;;;;N;;;;;
+E01E5;VARIATION SELECTOR-246;Mn;0;NSM;;;;;N;;;;;
+E01E6;VARIATION SELECTOR-247;Mn;0;NSM;;;;;N;;;;;
+E01E7;VARIATION SELECTOR-248;Mn;0;NSM;;;;;N;;;;;
+E01E8;VARIATION SELECTOR-249;Mn;0;NSM;;;;;N;;;;;
+E01E9;VARIATION SELECTOR-250;Mn;0;NSM;;;;;N;;;;;
+E01EA;VARIATION SELECTOR-251;Mn;0;NSM;;;;;N;;;;;
+E01EB;VARIATION SELECTOR-252;Mn;0;NSM;;;;;N;;;;;
+E01EC;VARIATION SELECTOR-253;Mn;0;NSM;;;;;N;;;;;
+E01ED;VARIATION SELECTOR-254;Mn;0;NSM;;;;;N;;;;;
+E01EE;VARIATION SELECTOR-255;Mn;0;NSM;;;;;N;;;;;
+E01EF;VARIATION SELECTOR-256;Mn;0;NSM;;;;;N;;;;;
+F0000;<Plane 15 Private Use, First>;Co;0;L;;;;;N;;;;;
+FFFFD;<Plane 15 Private Use, Last>;Co;0;L;;;;;N;;;;;
+100000;<Plane 16 Private Use, First>;Co;0;L;;;;;N;;;;;
+10FFFD;<Plane 16 Private Use, Last>;Co;0;L;;;;;N;;;;;
--- /dev/null
+++ b/lib/units
@@ -1,0 +1,597 @@
+/order of evaluation
+/ + -
+/ * /
+/ juxtaposition (meaning *)
+/ ¹ ² ³ ^
+/ | (meaning /)
+/ name number ()
+
+/dimensions
+m #
+kg #
+sec #
+coul #
+candela #
+$ #
+radian #
+bit #
+erlang #
+°K #
+°C #
+°F #
+
+/constants
+
+π 3.14159265358979323846
+pi π
+c 2.997925e+8 m/sec
+g 9.80665 m/sec²
+au 1.49597871e+11 m
+mole 6.022169e+23
+e 1.6021917e-19 coul
+energy c²
+force g
+mercury 1.33322e+5 kg/m²sec²
+hg mercury
+h 6.62620e-34 m²kg/sec
+ℏ h/2 π
+hbar ℏ
+nonillion 1e30
+octillion 1e27
+septillion 1e24
+sextillion 1e21
+pentillion 1e18
+quadrillion 1e15
+trillion 1e12
+billion 1e9
+million 1e6
+thousand 1e3
+hundred 1e2
+
+/dimensionless
+
+° 1|180 π radian
+degree °
+circle 2 π radian
+turn 2 π radian
+grad .9 °
+arcdeg 1 °
+arcmin 1|60 °
+arcsec 1|3600 °
+ccs 1|36 erlang
+
+steradian radian²
+sphere 4 π steradian
+sr steradian
+giga 1024 1024 1024
+
+/Time
+
+second sec
+s sec
+minute 60 sec
+min minute
+hour 60 min
+hr hour
+day 24 hr
+da day
+week 7 day
+year 365.24219879 day
+yr year
+month 1|12 year
+ms millisec
+us microsec
+
+/Mass
+
+gram millikg
+gm gram
+mg milligram
+metricton kilokg
+
+/Avoirdupois
+
+lb .45359237 kg
+lbf lb g
+pound lb
+ounce 1|16 lb
+oz ounce
+dram 1|16 oz
+dr dram
+grain 1|7000 lb
+gr grain
+shortton 2000 lb
+ton shortton
+longton 2240 lb
+
+/Apothecary
+
+scruple 20 grain
+apdram 60 grain
+apounce 480 grain
+troyounce apounce
+appound 5760 grain
+troypound appound
+
+/Length
+
+meter m
+cm centimeter
+mm millimeter
+km kilometer
+nm nanometer
+micron micrometer
+µ micrometer
+Å decinanometer
+angstrom Å
+
+inch 2.54 cm
+" inch
+in inch
+inches inch
+' 12"
+foot 12 in
+feet foot
+ft foot
+yard 3 ft
+yd yard
+rod 5.5 yd
+rd rod
+mile 5280 ft
+mi mile
+
+british 1200|3937 m/ft
+nmile 1852 m
+
+acre 4840 yd²
+
+cc cm³
+liter kilocc
+ml milliliter
+
+/US Liquid
+
+gallon 231 in³
+imperial 1.20095
+epa 0.8
+gal gallon
+quart 1|4 gal
+qt quart
+pint 1|2 qt
+pt pint
+
+floz 1|16 pt
+fldr 1|8 floz
+
+/US Dry
+
+dry 268.8025 in³/gallon
+peck 8 dry quart
+pk peck
+bushel 4 peck
+bu bushel
+
+/British
+
+brgallon 277.420 in³
+brquart 1|4 brgallon
+brpint 1|2 brquart
+brfloz 1|20 brpint
+brpeck 554.84 in³
+brbushel 4 brpeck
+
+/Energy Work
+
+newton kg m/sec²
+nt newton
+joule nt m
+cal 4.1868 joule
+
+/Electrical
+
+coulomb coul
+ampere coul/sec
+amp ampere
+watt joule/sec
+volt watt/amp
+Ω volt/amp
+ohm Ω
+mho 1/Ω
+farad coul/volt
+henry sec²/farad
+weber volt sec
+
+/Light
+
+cd candela
+lumen cd sr
+lux cd sr/m²
+
+/ MONEY DATE
+/ Fri Oct 27 15:52:13 EDT 2000
+
+/ MONEY START
+argentpeso 1 | .9998 $
+australiadollar 1 | 1.9175 $
+brazilreal 1 | 1.9300 $
+britainpound 1 | .6972 $
+canadadollar 1 | 1.5237 $
+chilepeso 1 | 576.45 $
+chinayuan 1 | 8.2782 $
+colombiapeso 1 | 2165.00 $
+czechrepkoruna 1 | 42.11 $
+denmarkkrone 1 | 9.0134 $
+dominicanpeso 1 | 16.00 $
+egyptpound 1 | 3.6750 $
+euro 1 | 1.08863 $
+hongkongdollar 1 | 7.7991 $
+hungaryforint 1 | 317.59 $
+indiarupee 1 | 46.600 $
+indnsiarupiah 1 | 9025.00 $
+israelshekel 1 | 4.1450 $
+japanyen 1 | 108.34 $
+jordandinar 1 | .71098 $
+lebanonpound 1 | 1514.00 $
+malaysiaringgit 1 | 3.7996 $
+mexicopeso 1 | 9.6850 $
+newzealanddollar 1 | 2.4938 $
+norwaykrone 1 | 9.5940 $
+pakistanrupee 1 | 57.75 $
+perunewsol 1 | 3.510 $
+philpinspeso 1 | 50.10 $
+polandzloty 1 | 4.70 $
+russiaruble 1 | 27.9200 $
+sdr 1 | .7841 $
+saudiarabriyal 1 | 3.7508 $
+singaporedollar 1 | 1.7546 $
+slovakrepkoruna 1 | 52.65 $
+southafricarand 1 | 7.6725 $
+southkoreawon 1 | 1137.20 $
+swedenkrona 1 | 10.2621 $
+switzerlndfranc 1 | 1.8195 $
+taiwandollar 1 | 32.09 $
+thailandbaht 1 | 43.58 $
+turkeylira 1 | 687860 $
+uaedirham 1 | 3.6728 $
+uruguaynewpeso 1 | 12.4180 $
+venezuelabolivar 1 | 693.2500 $
+/ MONEY END
+
+€ euro
+£ britainpound
+¥ japanyen
+dollar $
+
+bef 1 | 40.3399 €
+belgiumfranc bef
+dem 1 | 1.95583 €
+germanymark dem
+grd 1 | 340.750 €
+greecedrachma grd
+esp 1 | 166.386 €
+spainpeseta esp
+frf 1 | 6.55957 €
+francefranc frf
+iep 1 | .787564 €
+irelandpunt iep
+itl 1 | 1936.27 €
+italylira itl
+luf 1 | 40.3399 €
+luxembourgfranc luf
+nlg 1 | 2.20371 €
+netherlandsguilder nlg
+ats 1 | 13.7603 €
+austriaschilling ats
+pte 1 | 200.482 €
+portugalescudo pte
+fim 1 | 5.94573 €
+finlandmark fim
+
+baht thailandbaht
+bolivar venezuelabolivar
+brpound britainpound
+dinar jordandinar
+dirham uaedirham
+drachma greecedrachma
+escudo portugalescudo
+forint hungaryforint
+franc francefranc
+guilder netherlandsguilder
+krona swedenkrona
+lira italylira
+mark germanymark
+peseta spainpeseta
+peso mexicopeso
+punt irelandpunt
+rand southafricarand
+real brazilreal
+yuan chinayuan
+ringgit malaysiaringgit
+riyal saudiarabriyal
+ruble russiaruble
+rupee indiarupee
+rupiah indnsiarupiah
+shekel israelshekel
+sol perunewsol
+won southkoreawon
+yen japanyen
+zloty polandzloty
+
+usdollar dollar
+sterling britainpound | pound
+poundsterling britainpound
+
+/bits
+
+baud bit/sec
+byte 8 bit
+short 2 byte
+long 4 byte
+vlong 8 bytes
+frame 2352 byte
+
+/Australian liquid measure
+
+pony 7 brfloz
+midie 10 brfloz
+pot midie
+handle midie
+schooner 15 brfloz
+jug 40 brfloz
+resch midie
+alf midie
+tinny 13 brfloz
+stubby tinny
+twisty 250 ml
+longneck 2 tinny
+slab 24 tinny
+sixpack 6 tinny
+nip brfloz
+
+/wine
+winebottle 750 ml
+balthazar 16 winebottle
+jeroboam 4 winebottle
+magnum 2 winebottle
+mathusalem 8 winebottle
+methuselah 8 winebottle
+nebuchadnezzar 20 winebottle
+rehoboam 6 winebottle
+salmanazar 12 winebottle
+split 0.25 winebottle
+jigger 1.5 floz
+
+/Trivia
+
+% 1|100
+admiraltyknot 6080 ft/hr
+ε₀ (1e-9/36π) farad/m
+α (1/4π ε₀) e²/ℏ c
+alpha α
+apostilb cd/π m²
+are 1e+2 m²
+arpentcan 27.52 mi
+arpentlin 191.835 ft
+astronomicalunit au
+atmosphere 1.01325e+5 nt/m²
+atm atmosphere
+atomicmassunit 1.66044e-27 kg
+amu atomicmassunit
+bag 94 lb
+bakersdozen 13
+bar 1e+5 nt/m²
+barie 1e-1 nt/m²
+barleycorn 1|3 in
+barn 1e-28 m²
+barrel 42 gal
+barye 1e-1 nt/m²
+bev 1e+9 e volt
+biot 10 amp
+blondel cd/π m²
+boardfoot 144 in³
+bolt 40 yd
+bottommeasure 1|40 in
+britishthermalunit 1.05506e+3 joule
+btu britishthermalunit
+quad 1.0e+15 btu
+refrigeration 12000 btu/ton hour
+buck dollar
+cable 720 ft
+caliber 1e-2 in
+calorie cal
+carat 205 mg
+cent centidollar
+cental 100 lb
+centesimalminute 1e-2 grad
+centesimalsecond 1e-4 grad
+century 100 year
+cfs ft³/sec
+chain 66 ft
+circularinch 1|4 π in²
+circularmil 1e-6|4 π in²
+clusec 1e-8 mm hg m³/s
+coomb 4 bu
+cord 128 ft³
+cordfoot cord
+crith 9.06e-2 gm
+cubit 18 in
+cup 1|2 pt
+curie 3.7e+10/sec
+cusec ft³/sec
+dalton amu
+decade 10 yr
+degK °K
+degC °C
+degF °F
+dipotre 1/m
+displacementton 35 ft³
+doppelzentner 100 kg
+dozen 12
+drop .03 cm³
+dyne cm gm/sec²
+electronvolt e volt
+ell 45 in
+engineerschain 100 ft
+engineerslink 100|100 ft
+equivalentfootcandle lumen/π ft²
+equivalentlux lumen/π m²
+equivalentphot cd/π cm²
+erg cm²gm/sec²
+ev e volt
+faraday 9.652e+4 coul
+fathom 6 ft
+fermi 1e-15 m
+fifth 4|5 qt
+fin 5 dollar
+finger 7|8 in
+firkin 9 gal
+footcandle lumen/ft²
+footlambert cd/π ft²
+fortnight 14 da
+franklin 3.33564e-10 coul
+frigorie kilocal
+furlong 220 yd
+galileo 1e-2 m/sec²
+gamma 1e-9 weber/m²
+gauss 1e-4 weber/m²
+geodeticfoot british ft
+geographicalmile 1852 m
+gilbert 7.95775e-1 amp
+gill 1|4 pt
+gross 144
+gunterschain 22 yd
+hand 4 in
+hectare 1e+4 m²
+hefnercandle .92 cd
+hertz 1/sec
+hogshead 2 barrel
+hd hogshead
+homestead 1|4 mi²
+horsepower 550 ft lb g/sec
+hp horsepower
+hyl gm force sec²/m
+hz 1/sec
+imaginarycubicfoot 1.4 ft³
+karat 1|24
+kcal kilocal
+kcalorie kilocal
+kev 1e+3 e volt
+key kg
+khz 1e+3/sec
+kilderkin 18 gal
+knot nmile/hr
+kwh kilowatt hour
+lambert cd/π cm²
+langley cal/cm²
+last 80 bu
+league 3 mi
+lightyear c yr
+ly lightyear
+lightsecond c sec
+line 1|12 in
+link 66|100 ft
+longhundredweight 112 lb
+longquarter 28 lb
+lusec 1e-6 mm hg m³/s
+mach 331.46 m/sec
+marineleague 3 nmile
+maxwell 1e-8 weber
+metriccarat 200 mg
+mev 1e+6 e volt
+mgd megagal/day
+mh millihenry
+mhz 1e+6/sec
+mil 1e-3 in
+millenium 1000 year
+minersinch 1.5 ft³/min
+minim 1|60 fldr
+mo month
+mpg mile/gal
+mph mile/hr
+nail 1|16 yd
+nauticalmile nmile
+nit cd/m²
+noggin 1|8 qt
+nox 1e-3 lux
+ns nanosec
+oersted 2.5e+2 amp/m π
+oe oersted
+pace 36 in
+palm 3 in
+parasang 3.5 mi
+parsec au radian/arcsec
+pascal nt/m²
+pc parsec
+pennyweight 1|20 oz
+percent %
+perch rd
+pf picofarad
+phot lumen/cm²
+pica 1|6 in
+pieze 1e+3 nt/m²
+pipe 4 barrel
+point 1|72 in
+poise gm/cm sec
+pole rd
+poundal ft lb/sec²
+pdl poundal
+proof 1/200
+psi lb g/in²
+quarter 9 in
+quartersection 1|4 mi²
+quintal 100 kg
+quire 25
+rad 100 erg/gm
+ream 500
+registerton 100 ft³
+rhe 10 m²/nt sec
+rontgen 2.58e-4 curie/kg
+rood 1.21e+3 yd
+rope 20 ft
+rutherford 1e+6/sec
+rydberg 1.36054e+1 ev
+sabin 1 ft²
+sack 3 bu
+seam 8 bu
+section mi²
+shippington 40 ft³
+shorthundredweight 100 lb
+shortquarter 25 lb
+siemens 1/Ω
+σ 5.66956e-5 erg/cm² °K^4 sec
+sigma σ
+skein 120 yd
+skot 1e-3 apostilb
+slug lb g sec²/ft
+span 9 in
+spat 4 π sr
+spindle 14400 yd
+square 100 ft²
+squidge 1|972 inch
+catsquidge 1|432 inch
+stere m³
+sthene 1e+3 nt
+stilb cd/cm²
+stoke 1e-4 m²/sec
+stone 14 lb
+strike 2 bu
+surveyfoot british ft
+surveyorschain 66 ft
+surveyorslink 66|100 ft
+tablespoon 4 fldr
+teaspoon 4|3 fldr
+tesla weber/m²
+therm 1e+5 btu
+thermie 1e+6 cal
+timberfoot ft³
+tnt 4.6e+6 m²/sec²
+tonne 1e+6 gm
+torr mm hg
+township 36 mi²
+tun 8 barrel
+water .22491|2.54 kg/m²sec²
+wey 40 bu
+weymass 252 lb
+Xunit 1.00202e-13 m
+k 1.38047e-16 erg/°K
+foal 9223372036854775807
--- /dev/null
+++ b/lib/usbdb
@@ -1,0 +1,14 @@
+vendor 0x0711
+ product 0x0230
+ load /dis/lib/usb/usbmct.dis
+class 3
+ subclass 1
+ proto 1
+ load /dis/lib/usb/usbkbd.dis
+ proto 2
+ load /dis/lib/usb/usbmouse.dis
+
+class 8
+ subclass 6
+ proto 80
+ load /dis/lib/usb/usbmass.dis
--- /dev/null
+++ b/lib/wmcharon
@@ -1,0 +1,28 @@
+# /dis/sh script
+# wm defines "menu" and "delmenu" builtins
+load std
+prompt='% ' ''
+fn % {$*}
+autoload=std
+home=/usr/^"{cat /dev/user}
+
+if {! {~ wm ${loaded}}} {
+ echo wmsetup must run under wm >[1=2]
+ raise usage
+}
+
+fn wmrun {
+ args := $*
+ {
+ pctl newpgrp
+ fn wmrun
+ $args
+ } > /chan/wmstdout >[2] /chan/wmstderr &
+}
+
+fn cd {
+ builtin cd $*; echo cwd `{pwd} > /chan/shctl >[2] /dev/null
+}
+
+plumber >[2] /chan/wmstderr >/chan/wmstdout
+wmrun $*
--- /dev/null
+++ b/lib/wmsetup
@@ -1,0 +1,52 @@
+# /dis/sh script
+# wm defines "menu" and "delmenu" builtins
+load std
+prompt='% ' ''
+fn % {$*}
+autoload=std
+home=/usr/^"{cat /dev/user}
+
+if {! {~ wm ${loaded}}} {
+ echo wmsetup must run under wm >[1=2]
+ raise usage
+}
+
+fn wmrun {
+ args := $*
+ {
+ pctl newpgrp
+ fn wmrun
+ $args
+ } > /chan/wmstdout >[2] /chan/wmstderr &
+}
+
+fn cd {
+ builtin cd $*;
+ rescue 'bad redir' {} {
+ echo cwd `{pwd} > /chan/shctl
+ } >[2] /dev/null
+}
+
+plumber >/chan/wmstdout >[2=1]
+menu Shell {wmrun wm/sh}
+menu Acme {wmrun acme}
+menu Edit {wmrun wm/edit}
+menu Charon {wmrun charon}
+menu Manual {wmrun wm/man}
+menu Files {if {ftest -d $home} {wmrun wm/ftree $home} {wmrun wm/ftree /}}
+menu '' ''
+menu System 'Debugger' {wmrun wm/deb}
+menu System 'Module manager' {wmrun wm/rt}
+menu System 'Task manager' {wmrun wm/task}
+menu System 'Memory monitor' {wmrun wm/memory}
+menu System 'About' {wmrun wm/about}
+menu Misc 'Coffee' {wmrun wm/coffee}
+menu Misc 'Colours' {wmrun wm/colors}
+#menu Misc 'Winctl' {wmrun wm/winctl}
+menu Misc 'Clock' {wmrun wm/date}
+menu Games 'Tetris' {wmrun wm/tetris}
+menu Games 'Bounce' {wmrun wm/bounce}
+#menu Games 'Game client' {wmrun games/gameclient >/dev/null >[2=1]}
+#menu Games 'Game client (local)' {wmrun games/gameclient -l > /dev/null >[2=1]}
+
+if {ftest -f $home/lib/wmsetup} {run $home/lib/wmsetup} {}
--- /dev/null
+++ b/lib/wmsetup.grid
@@ -1,0 +1,54 @@
+# /dis/sh script
+# wm defines "menu" and "delmenu" builtins
+load std
+prompt='% ' ''
+fn % {$*}
+autoload=std
+home=/usr/^"{cat /dev/user}
+
+if {! {~ wm ${loaded}}} {
+ echo wmsetup must run under wm >[1=2]
+ raise usage
+}
+
+fn wmrun {
+ args := $*
+ {
+ pctl newpgrp
+ fn wmrun
+ $args
+ } > /chan/wmstdout >[2] /chan/wmstderr &
+}
+
+fn cd {
+ builtin cd $*;
+ rescue 'bad redir' {} {
+ echo cwd `{pwd} > /chan/shctl
+ } >[2] /dev/null
+}
+autoload=std sexprs
+run /lib/sh/sched
+bind -a /grid/scripts/Inferno /dis
+if{! ftest -f /net/cs}{
+ ndb/cs
+}
+mount -a {mntgen} /n
+
+plumber >/chan/wmstdout >[2=1]
+menu Shell {wmrun wm/sh}
+menu Acme {wmrun acme}
+menu Charon {wmrun charon}
+menu Manual {wmrun wm/man}
+menu Files {if {ftest -d $home} {wmrun wm/ftree $home} {wmrun wm/ftree /}}
+menu '' ''
+menu Grid 'Node monitor' {wmrun nodemonitor}
+menu Grid 'Job monitor' {wmrun jobmonitor}
+menu System 'Debugger' {wmrun wm/deb}
+menu System 'Task manager' {wmrun wm/task}
+menu System 'Memory monitor' {wmrun wm/memory}
+menu System 'About' {wmrun wm/about}
+menu Games 'Tetris' {wmrun wm/tetris}
+menu Games 'Bounce' {wmrun wm/bounce}
+
+# anything else
+if {ftest -f $home/lib/wmsetup} {run $home/lib/wmsetup} {}
--- /dev/null
+++ b/lib/words
@@ -1,0 +1,29758 @@
+AAA
+AAAS
+aardvark
+Aaron
+AARP
+AAU
+AAUP
+AAUW
+ABA
+Ababa
+aback
+abacus
+abaft
+abalone
+abandon
+abase
+abash
+abate
+abattoir
+abbe
+abbess
+abbey
+abbot
+Abbott
+abbreviate
+abc
+abcdefghijklmnopqrstuvwxyz
+abdicate
+abdomen
+abdominal
+abduct
+Abe
+abeam
+abed
+Abel
+Abelian
+Abelson
+Aberdeen
+Abernathy
+aberrant
+aberrate
+abet
+abettor
+abeyant
+abhor
+abhorrent
+abide
+Abidjan
+Abigail
+abject
+abjuration
+abjure
+ablate
+ablaut
+ablaze
+able
+abloom
+ablution
+ABM
+abnegate
+Abner
+abnormal
+aboard
+abode
+abolish
+abolition
+abolitionary
+abomasum
+abominable
+abominate
+aboriginal
+aborigine
+aborning
+abort
+abortifacient
+abound
+about
+above
+aboveboard
+aboveground
+abovementioned
+abracadabra
+abrade
+Abraham
+Abram
+Abramson
+abrasion
+abreact
+abreast
+abridge
+abridgment
+abroad
+abrogate
+abrupt
+Absalom
+abscess
+abscissa
+abscissae
+abscission
+abscond
+absent
+absentee
+absenteeism
+absentia
+absentminded
+absinthe
+absolute
+absolve
+absorb
+absorbent
+absorption
+abstain
+abstemious
+abstention
+abstinent
+abstract
+abstruse
+absurd
+absurdum
+abuilding
+abundant
+abuse
+abusive
+abut
+abysmal
+abyss
+abyssal
+Abyssinia
+AC
+acacia
+Acad.
+academe
+academia
+academic
+academician
+academy
+Acadia
+acanthus
+Acapulco
+accede
+accelerando
+accelerant
+accelerate
+accelerometer
+accent
+accentual
+accentuate
+accept
+acceptant
+acceptor
+access
+accessible
+accession
+accessorize
+accessory
+accident
+accidental
+accipiter
+acclaim
+acclamation
+acclimate
+acclimatize
+accolade
+accommodate
+accompaniment
+accompanist
+accompany
+accompli
+accomplice
+accomplish
+accord
+accordant
+accordion
+accost
+account
+accountant
+accouter
+Accra
+accredit
+accreditation
+accrete
+accretion
+accretionary
+accrual
+accrue
+acculturate
+accumulate
+accuracy
+accurate
+accursed
+accusation
+accusatory
+accuse
+accustom
+ace
+acentric
+acerb
+acerbic
+acetaldehyde
+acetate
+acetic
+acetify
+acetone
+acetyl
+acetylene
+ache
+achieve
+Achilles
+aching
+achondrite
+achromatic
+acid
+acidic
+acidify
+acidimeter
+acidulous
+Ackley
+acknowledge
+acknowledgeable
+acknowledgment
+ACLU
+ACM
+acme
+acne
+acolyte
+acorn
+acoustic
+acoustician
+acoustoelectric
+acoustooptic
+acquaint
+acquaintance
+acquiesce
+acquiescent
+acquire
+acquisition
+acquit
+acquittal
+acre
+acreage
+acrid
+acrimonious
+acrimony
+acrobat
+acrobatic
+acrolein
+acronym
+acrophobe
+acropolis
+across
+acrostic
+acrylate
+acrylic
+ACS
+act
+Actaeon
+actinic
+actinide
+actinium
+actinometer
+activate
+activism
+Acton
+actress
+actual
+actuarial
+actuary
+actuate
+acuity
+acumen
+acupuncture
+Acura
+acute
+acyclic
+acyl
+A.D.
+ad
+Ada
+adage
+adagio
+Adair
+Adam
+adamant
+adamantine
+Adams
+Adamson
+adapt
+adaptation
+adaptive
+adaptor
+add
+addend
+addenda
+addendum
+addict
+Addis
+Addison
+addition
+addle
+address
+addressee
+Addressograph
+adduce
+Adelaide
+Adele
+Adelia
+Adelphi
+Aden
+adenine
+adenoid
+adenoma
+adenosine
+adept
+adequacy
+adequate
+adhere
+adherent
+adhesion
+adiabatic
+Adidas
+adieu
+adipose
+Adirondack
+adjacent
+adjectival
+adjective
+adjoin
+adjoint
+adjourn
+adjudge
+adjudicate
+adjunct
+adjuration
+adjure
+adjust
+adjutant
+Adkins
+Adler
+administer
+administrable
+administrate
+administratrix
+admiral
+admiralty
+admiration
+admire
+admissible
+admission
+admit
+admittance
+admix
+admixture
+admonish
+admonition
+admonitory
+ado
+adobe
+adolescent
+Adolf
+Adolph
+Adolphus
+Adonis
+adopt
+adoration
+adore
+adorn
+adrenal
+adrenalin
+adrenaline
+Adrian
+Adriatic
+Adrienne
+adrift
+adroit
+adsorb
+adsorbate
+adsorbent
+adsorption
+adulate
+adult
+adulterant
+adulterate
+adulterer
+adulteress
+adulterous
+adultery
+adumbrate
+advance
+advantage
+advantageous
+advection
+advent
+adventitial
+adventitious
+adventure
+adventuresome
+adventuress
+adventurous
+adverb
+adverbial
+adversarial
+adversary
+adverse
+advert
+advertent
+advertise
+advice
+advise
+advisee
+advisor
+advisory
+advocacy
+advocate
+adz
+adze
+Aegean
+aegis
+Aeneas
+Aeneid
+aeolian
+Aeolus
+aerate
+aerial
+aerie
+Aerobacter
+aerobatic
+aerobic
+aerodynamic
+aeronautic
+aerosol
+aerospace
+Aeschylus
+Aesop
+afar
+affable
+affair
+affect
+affectation
+affectionate
+afferent
+affiance
+affidavit
+affiliate
+affine
+affinity
+affirm
+affirmation
+affix
+affixation
+afflatus
+afflict
+affluent
+afford
+afforest
+afforestation
+affray
+affright
+affront
+afghan
+Afghanistan
+aficionado
+afield
+afire
+AFL
+aflame
+afloat
+aflutter
+afoot
+aforementioned
+aforesaid
+aforethought
+afoul
+afraid
+afresh
+Africa
+Afrikaans
+Afrikaner
+afro
+aft
+afterbirth
+afterburner
+aftercare
+afterdeck
+aftereffect
+afterglow
+afterimage
+afterlife
+aftermarket
+aftermath
+aftermost
+afternoon
+aftershock
+aftertaste
+afterthought
+afterward
+afterworld
+again
+against
+Agamemnon
+agamic
+agape
+agar
+agaric
+agate
+Agatha
+agave
+age
+Agee
+agelong
+agenda
+agendum
+agent
+agglomerate
+agglutinate
+agglutinin
+aggrade
+aggrandize
+aggravate
+aggregate
+aggression
+aggressor
+aggrieve
+aghast
+agile
+agitate
+agitprop
+agleam
+agley
+aglitter
+aglow
+Agnes
+Agnew
+agnomen
+agnostic
+ago
+agog
+agon
+agone
+agony
+agora
+agoraphobe
+agouti
+agrarian
+agree
+agreeable
+agribusiness
+Agricola
+agricultural
+agriculture
+agrimony
+agronomist
+agronomy
+aground
+ague
+Aguilar
+Agway
+ah
+aha
+Ahab
+ahead
+ahem
+Ahmadabad
+ahoy
+aid
+Aida
+aide
+Aiken
+ail
+ailanthus
+Aileen
+aileron
+ailment
+aim
+ain't
+Ainu
+air
+airbag
+airborne
+airbrush
+Airbus
+aircraft
+airdrop
+Airedale
+Aires
+airfare
+airfield
+airflow
+airfoil
+airframe
+airhead
+airlift
+airline
+airlock
+airmail
+airmass
+airpark
+airplane
+airport
+airscrew
+airsick
+airspace
+airspeed
+airstream
+airstrip
+airtight
+airwave
+airway
+airworthy
+aisle
+Aitken
+ajar
+Ajax
+AK
+AK47
+Akers
+akido
+akimbo
+akin
+Akkadian
+Akron
+akvavit
+Al
+Alabama
+Alabamian
+alabaster
+alack
+alacrity
+Aladdin
+Alameda
+Alamo
+Alan
+alar
+alarm
+alas
+Alaska
+alb
+albacore
+Albania
+Albanian
+Albany
+albatross
+albedo
+albeit
+Alberich
+Albert
+Alberta
+Alberto
+albinism
+albino
+Albion
+Albrecht
+Albright
+album
+albumen
+albumin
+Albuquerque
+Alcestis
+alchemical
+alchemist
+alchemy
+Alcmena
+Alcoa
+alcohol
+alcoholic
+Alcott
+alcove
+Aldebaran
+aldehyde
+Alden
+alder
+Aldrich
+aldrin
+ale
+Alec
+Aleck
+alehouse
+alembic
+aleph
+alert
+Aleut
+Aleutian
+alewife
+Alex
+Alexander
+Alexandra
+Alexandria
+alexandrine
+Alexis
+alfalfa
+Alfonso
+Alfred
+Alfredo
+alfresco
+alga
+algae
+algal
+algebra
+algebraic
+Algenib
+Alger
+Algeria
+Algerian
+Algiers
+Algol
+Algonquin
+algorithm
+algorithmic
+Alhambra
+Ali
+alia
+alias
+alibi
+Alice
+Alicia
+alidade
+alien
+alienate
+alienee
+alienor
+alight
+align
+alike
+aliment
+alimentary
+alimentation
+alimony
+aliphatic
+aliquot
+Alison
+Alistair
+alive
+alizarin
+alkali
+alkaline
+alkaloid
+alkane
+alkene
+alkyd
+alkyl
+all
+Allah
+allay
+allegation
+allege
+Alleghenies
+Allegheny
+allegiant
+allegoric
+allegorist
+allegorize
+allegory
+Allegra
+allegretto
+allegro
+allele
+alleluia
+allemand
+Allen
+Allentown
+allergen
+allergenic
+allergic
+allergist
+allergy
+alleviate
+alley
+alleyway
+alliance
+alligator
+Allis
+Allison
+alliterate
+allocable
+allocate
+allophone
+allophonic
+allot
+allotrope
+allotropic
+allow
+allowance
+alloy
+allspice
+Allstate
+allude
+allure
+allusion
+alluvial
+alluvium
+ally
+allyl
+Allyn
+alma
+Almaden
+almagest
+almanac
+almighty
+almond
+almost
+alms
+almshouse
+alnico
+aloe
+aloft
+aloha
+alone
+along
+alongside
+Alonzo
+aloof
+aloud
+alp
+alpaca
+alpenstock
+Alpert
+alpha
+alphabet
+alphabetic
+alphameric
+alphanumeric
+Alpheratz
+Alphonse
+alphorn
+alpine
+already
+Alsace
+Alsatian
+also
+Alsop
+Altair
+altar
+altarpiece
+altazimuth
+alter
+alteration
+altercate
+altern
+alternate
+althea
+although
+altimeter
+altiplano
+altitude
+alto
+altocumulus
+altogether
+Alton
+altostratus
+altricial
+altruism
+altruist
+alum
+alumina
+aluminate
+aluminize
+aluminum
+alumna
+alumnae
+alumni
+alumnus
+alundum
+Alva
+Alvarez
+alveolar
+alveoli
+alveolus
+Alvin
+always
+alyssum
+Alzheimer
+A&M
+a.m.
+am
+AMA
+Amadeus
+amalgam
+amalgamate
+Amanda
+amanita
+amanuensis
+amaranth
+Amarillo
+amaryllis
+amass
+amateur
+amateurish
+amatory
+amaze
+amazon
+Amazonia
+Amazonian
+ambassador
+ambassadorial
+ambassadress
+amber
+ambergris
+ambiance
+ambidextrous
+ambient
+ambiguity
+ambiguous
+ambit
+ambition
+ambitious
+ambivalent
+amble
+ambrosia
+ambrosial
+ambulant
+ambulate
+ambuscade
+ambush
+ameer
+Amelia
+ameliorate
+amen
+amend
+amendatory
+Amerada
+America
+American
+Americana
+americanize
+americium
+Amerindian
+Ames
+Ameslan
+amethyst
+amethystine
+Amherst
+amiable
+amicable
+amicus
+amid
+amide
+amidships
+amidst
+amigo
+amine
+amino
+Amish
+amiss
+amity
+Amman
+Ammerman
+ammeter
+ammo
+ammonia
+ammonium
+ammunition
+amnesia
+amnesty
+amniocentesis
+amniotic
+Amoco
+amoeba
+amoebae
+amoebic
+amok
+among
+amongst
+amoral
+amorous
+amorphous
+amort
+Amos
+amount
+amour
+amperage
+ampere
+ampersand
+Ampex
+amphetamine
+amphibia
+amphibian
+amphibious
+amphibole
+amphibology
+amphitheater
+amphora
+ample
+amplify
+amplitude
+amply
+ampoule
+amputate
+amputee
+Amsterdam
+Amtrak
+amulet
+amuse
+Amy
+amygdaloid
+amyl
+amyloid
+an
+ana
+Anabaptist
+anabasis
+Anabel
+anabolic
+anachronism
+anachronistic
+anachronous
+anaconda
+anaerobic
+anaglyph
+anagram
+anagrammatic
+Anaheim
+anal
+analemma
+analeptic
+analgesia
+analgesic
+analog
+analogous
+analogue
+analogy
+analysand
+analyses
+analysis
+analyst
+analytic
+analyze
+anamorphic
+anapest
+anapestic
+anarch
+anarchic
+anarchs
+anarchy
+anastigmat
+anastigmatic
+anastomosis
+anastomotic
+anathema
+anathematize
+Anatole
+Anatolia
+Anatolian
+anatomic
+anatomist
+anatomize
+anatomy
+ancestor
+ancestral
+ancestress
+ancestry
+anchor
+anchorage
+anchorite
+anchovy
+ancient
+ancillary
+and
+andante
+andantino
+Andean
+Andersen
+Anderson
+Andes
+andesine
+andesite
+andiron
+Andorra
+Andover
+Andre
+Andrea
+Andrei
+Andrew
+Andrews
+Androcles
+androgen
+androgenic
+androgynous
+androgyny
+android
+Andromache
+Andromeda
+Andy
+anecdotal
+anecdote
+anechoic
+anemia
+anemic
+anemometer
+anemone
+anent
+aneroid
+anesthesia
+anesthesiology
+anesthetic
+anesthetist
+anesthetize
+aneurism
+aneurysm
+anew
+angel
+Angela
+Angeles
+angelfish
+angelic
+Angelica
+Angelina
+Angeline
+Angelo
+anger
+Angie
+angina
+angiogram
+angioplasty
+angiosperm
+angle
+angleworm
+Anglican
+anglicism
+anglicize
+Anglo
+anglophile
+anglophobe
+anglophobic
+anglophone
+Angola
+angora
+angry
+angst
+angstrom
+anguish
+angular
+angulate
+Angus
+anharmonic
+Anheuser
+anhydride
+anhydrite
+anhydrous
+ani
+aniline
+animadversion
+animadvert
+animal
+animate
+animism
+animist
+animosity
+animus
+anion
+anionic
+anise
+anisette
+anisotropic
+anisotropy
+Anita
+Ankara
+ankle
+anklebone
+anklet
+Ann
+Anna
+Annale
+Annalen
+annalist
+annals
+Annapolis
+Anne
+anneal
+Annette
+annex
+annexation
+Annie
+annihilate
+anniversary
+annotate
+announce
+annoy
+annoyance
+annual
+annuitant
+annuity
+annul
+annular
+annuli
+annulus
+annum
+annunciate
+anode
+anodic
+anodyne
+anoint
+anomalous
+anomaly
+anomie
+anon
+anonymity
+anonymous
+anopheles
+anorak
+anorexia
+anorexic
+anorthic
+anorthosite
+another
+anoxia
+anoxic
+Anselm
+Anselmo
+ANSI
+answer
+ant
+antacid
+Antaeus
+antagonism
+antagonist
+antagonistic
+antagonize
+antarctic
+Antarctica
+Antares
+ante
+anteater
+antebellum
+antecede
+antecedent
+antechamber
+antedate
+antediluvian
+anteing
+antelope
+antenna
+antennae
+antepenultimate
+anterior
+anteroom
+anthem
+anther
+anthill
+anthologize
+anthology
+Anthony
+anthracite
+anthracnose
+anthrax
+anthropic
+anthropocentric
+anthropogenic
+anthropoid
+anthropology
+anthropometric
+anthropomorphic
+anthropomorphism
+anthropomorphize
+anti
+antic
+antichrist
+anticipant
+anticipate
+anticline
+antidotal
+Antietam
+antigen
+antigenic
+Antigone
+Antigua
+antihistamine
+Antilles
+antimony
+antinomy
+Antioch
+antipasto
+antipathy
+antiperspirant
+antiphonal
+antipodal
+antipodean
+antipodes
+antiquarian
+antiquary
+antiquate
+antiquated
+antique
+antiquity
+antisemite
+antisemitic
+antisemitism
+antithetic
+antler
+Antoine
+Antoinette
+Anton
+Antonia
+Antonio
+Antony
+antonym
+antonymous
+antonymy
+Antwerp
+anus
+anvil
+anxiety
+anxious
+any
+anybody
+anybody'd
+anyhow
+anymore
+anyone
+anyplace
+anything
+anyway
+anywhere
+aorta
+aortic
+A&P
+AP
+apace
+apache
+apart
+apartheid
+apathetic
+apathy
+ape
+apercu
+aperiodic
+aperitif
+aperture
+apex
+aphasia
+aphasic
+aphelion
+aphid
+aphis
+aphorism
+aphorist
+aphrodisiac
+Aphrodite
+apiarist
+apiary
+apices
+apiculture
+apiece
+apish
+aplomb
+apnea
+apocalypse
+apocalyptic
+apocope
+apocrypha
+apocryphal
+apodictic
+apogee
+apolitical
+Apollo
+Apollonian
+apologetic
+apologia
+apologize
+apology
+apoplectic
+apoplexy
+apostasy
+apostate
+apostle
+apostolic
+apostrophe
+apostrophize
+apothecary
+apothegm
+apotheosis
+Appalachia
+appall
+appanage
+apparatchik
+apparatus
+apparel
+apparent
+apparition
+appeal
+appear
+appearance
+appease
+appellant
+appellate
+append
+appendage
+appendectomy
+appendices
+appendicitis
+appendix
+apperceive
+apperception
+appertain
+appetite
+appetize
+Appian
+applaud
+applause
+apple
+Appleby
+applejack
+Appleton
+appliance
+applicable
+applicant
+application
+applicator
+applique
+apply
+appoint
+appointee
+appointive
+apportion
+apposite
+apposition
+appraisal
+appraise
+appreciable
+appreciate
+apprehend
+apprehensible
+apprehension
+apprentice
+apprise
+approach
+approbation
+approbatory
+appropriable
+appropriate
+approval
+approve
+approximable
+approximant
+approximate
+appurtenant
+Apr
+Apr.
+apricot
+April
+apron
+apropos
+apse
+apsidal
+apsides
+apt
+aptitude
+aptly
+aptness
+aqua
+aquaculture
+aqualung
+aquamarine
+aquaplane
+aquarist
+aquarium
+Aquarius
+aquatic
+aqueduct
+aqueous
+aquifer
+Aquila
+aquiline
+Aquinas
+aquiver
+AR
+Arab
+arabesque
+Arabia
+Arabic
+arable
+Araby
+Arachne
+arachnid
+Aramaic
+Arapaho
+Arawak
+arbiter
+arbitrable
+arbitrage
+arbitrageur
+arbitrary
+arbitrate
+arbor
+arboreal
+arborescent
+arboretum
+arbutus
+arc
+arcade
+Arcadia
+arcana
+arcane
+arccos
+arccosine
+arch
+archaic
+archaism
+archangel
+archbishop
+archbishopric
+archdeacon
+archdiocese
+archduchess
+archduke
+archenemy
+archeology
+Archer
+archery
+archetypal
+archetype
+archetypical
+archfool
+Archibald
+Archie
+Archimedean
+Archimedes
+archipelago
+architect
+architectonic
+architectural
+architecture
+architrave
+archival
+archive
+archrival
+archway
+arcing
+arcsin
+arcsine
+arctan
+arctangent
+arctic
+Arcturus
+Arden
+ardent
+ardor
+arduous
+are
+area
+areal
+areaway
+areawide
+arena
+arenaceous
+aren't
+Arequipa
+Ares
+argent
+Argentina
+argentine
+Argentinian
+argillaceous
+Argive
+argon
+argonaut
+Argonne
+argosy
+argot
+argue
+argument
+argumentation
+argumentive
+Argus
+argyll
+Ariadne
+Arianism
+arid
+Ariel
+Aries
+arise
+arisen
+aristocracy
+aristocrat
+aristocratic
+Aristophanes
+Aristotelean
+Aristotelian
+Aristotle
+arithmetic
+arithmetician
+arithmeticize
+arithmetize
+Arizona
+ark
+Arkansan
+Arkansas
+Arlen
+Arlene
+Arlington
+Arlo
+arm
+armada
+armadillo
+Armageddon
+armament
+armamentaria
+armamentarium
+Armando
+Armata
+armature
+armchair
+Armco
+Armenia
+Armenian
+armhole
+armillaria
+armistice
+armlet
+armload
+armoire
+armor
+armorial
+armory
+Armour
+armpit
+armrest
+Armstrong
+army
+Arnold
+aroma
+aromatic
+arose
+around
+arousal
+arouse
+ARPA
+arpeggio
+arrack
+Arragon
+arraign
+arrange
+arrangeable
+arrant
+array
+arrear
+arrest
+Arrhenius
+arrhythmia
+arrival
+arrive
+arrogant
+arrogate
+arrow
+arrowhead
+arrowroot
+arroyo
+arsenal
+arsenate
+arsenic
+arsenide
+arsine
+arson
+art
+Artemis
+artemisia
+arterial
+arteriole
+arteriosclerosis
+arteriosclerotic
+artery
+artesian
+arthritic
+arthritis
+arthropod
+arthroscope
+Arthur
+Arthurian
+artichoke
+article
+articulate
+Artie
+artifact
+artifice
+artificial
+artillery
+artisan
+artistry
+Arturo
+artwork
+Aruba
+arugula
+arum
+Aryan
+aryl
+a's
+as
+ASA
+ASAP
+asbestos
+ascend
+ascendant
+ascendent
+ascension
+ascent
+ascertain
+ascetic
+asceticism
+ascorbic
+ascot
+ascribe
+ascription
+asepsis
+aseptic
+asexual
+ash
+ashamed
+Ashanti
+ashcan
+ashen
+Asher
+Asheville
+Ashland
+ashlar
+Ashley
+Ashmolean
+ashore
+ashram
+ashtray
+Asia
+Asiatic
+aside
+Asilomar
+Asimov
+asinine
+ask
+askance
+askew
+aslant
+asleep
+asocial
+asp
+asparagus
+aspect
+aspen
+asperity
+aspersion
+asphalt
+aspheric
+asphyxia
+asphyxiate
+aspic
+aspidistra
+aspirant
+aspirate
+aspire
+aspirin
+ass
+assai
+assail
+assailant
+Assam
+assassin
+assassinate
+assault
+assay
+assemblage
+assemble
+assembly
+assent
+assert
+assess
+assessor
+asset
+asseverate
+assiduity
+assiduous
+assign
+assignation
+assignee
+assimilable
+assimilate
+assist
+assistant
+associable
+associate
+assonant
+assort
+Asst.
+assuage
+assume
+assumption
+assurance
+assure
+assured
+Assyria
+Assyriology
+Astarte
+astatine
+aster
+asteria
+asterisk
+astern
+asteroid
+asthma
+asthmatic
+astigmat
+astigmatic
+astigmatism
+ASTM
+astonish
+Astor
+Astoria
+astound
+astraddle
+astral
+astray
+astride
+astringent
+astrodome
+astrolabe
+astrologer
+astrology
+astronaut
+astronautic
+astronomer
+astronomy
+astrophysical
+astrophysicist
+astrophysics
+Astroturf
+astute
+Asuncion
+asunder
+asylum
+asymmetry
+asymptomatic
+asymptote
+asymptotic
+asynchronism
+asynchronous
+asynchrony
+at
+Atalanta
+atavism
+atavistic
+Atchison
+ate
+atelier
+Athabascan
+atheism
+atheist
+Athena
+Athene
+Athenian
+Athens
+athirst
+athlete
+athletic
+athwart
+Atkins
+Atkinson
+Atlanta
+Atlantic
+Atlantica
+Atlantis
+atlas
+ATM
+atmosphere
+atmospheric
+atoll
+atom
+atomic
+atonal
+atone
+atop
+atremble
+Atreus
+atrium
+atrocious
+atrocity
+atrophic
+atrophy
+Atropos
+AT&T
+attach
+attache
+attack
+attain
+attainder
+attar
+attempt
+attend
+attendant
+attendee
+attention
+attenuate
+attest
+attestation
+attic
+Attica
+attire
+attitude
+attitudinal
+attitudinize
+Attn
+Attn.
+attorney
+attract
+attribute
+attrition
+attune
+Atwater
+Atwood
+atypic
+Auberge
+Aubrey
+auburn
+Auckland
+auction
+auctioneer
+audacious
+audacity
+audible
+audience
+audio
+audiology
+audiometer
+audiophile
+audiotape
+audiovisual
+audit
+audition
+auditor
+auditorium
+Audrey
+Audubon
+Auerbach
+Aug.
+Augean
+augend
+auger
+aught
+augment
+augmentation
+augur
+augury
+august
+Augusta
+Augustan
+Augustine
+Augustus
+auk
+aunt
+auntie
+aura
+aural
+aureomycin
+auric
+auricle
+auricular
+Auriga
+aurora
+auroral
+Auschwitz
+auspices
+auspicious
+Aussie
+austenite
+austere
+Austin
+austral
+Australasia
+Australia
+Australis
+Australopithecus
+Austria
+autarchy
+autarky
+authentic
+authenticate
+author
+authorial
+authoritarian
+authoritative
+autism
+autistic
+auto
+autobahn
+autochthonous
+autoclave
+autocracy
+autocrat
+autocratic
+autodidact
+autogen
+autogenic
+autogenous
+autogiro
+automata
+automate
+automatic
+automaton
+automorph
+automorphic
+autonomous
+autonomy
+autopsy
+autumn
+autumnal
+auxiliary
+auxin
+avail
+avalanche
+avalanching
+avarice
+avaricious
+avast
+avatar
+Ave.
+avenge
+avenue
+aver
+average
+averse
+aversion
+avert
+avertive
+Avery
+avian
+aviarist
+aviary
+aviate
+aviatrix
+aviculture
+avid
+avifauna
+avionic
+Avis
+Aviv
+avocado
+avocation
+avocet
+Avogadro
+avoid
+avoidance
+avoirdupois
+Avon
+avow
+avowal
+avuncular
+await
+awake
+awaken
+award
+awardee
+aware
+awash
+away
+awe
+aweigh
+awesome
+awestricken
+awestruck
+awful
+awhile
+awkward
+awl
+awn
+awoke
+awoken
+awry
+ax
+axe
+axial
+axil
+axillary
+axiology
+axiom
+axiomatic
+axiomatize
+axis
+axle
+axon
+ayatollah
+aye
+Ayers
+Aylesbury
+AZ
+azalea
+Azerbaijan
+azimuth
+azimuthal
+Azores
+Aztec
+Aztecan
+azure
+azurite
+babbitt
+babble
+Babcock
+babe
+Babel
+baboon
+babushka
+baby
+babyhood
+babyish
+Babylon
+Babylonian
+babysat
+babysit
+baccalaureate
+baccarat
+bacchanal
+bacchanalia
+bacchanalian
+Bacchus
+Bach
+bachelor
+bacilli
+bacillus
+back
+backache
+backbencher
+backbite
+backboard
+backbone
+backcross
+backdate
+backdrop
+backfield
+backfill
+backfire
+backgammon
+background
+backhand
+backhoe
+backlash
+backlog
+backorder
+backpack
+backplane
+backplate
+backrest
+backsaw
+backscatter
+backside
+backslap
+backslid
+backslide
+backspace
+backspin
+backstage
+backstay
+backstitch
+backstop
+backstretch
+backstroke
+backswept
+backtrack
+backup
+backward
+backwash
+backwater
+backwoods
+backyard
+bacon
+bacteria
+bacterial
+bacteriologic
+bacteriology
+bacteriophage
+bacterium
+bad
+bade
+Baden
+badge
+badinage
+badland
+badminton
+Baedeker
+Baffin
+baffle
+bag
+bagatelle
+bagel
+baggage
+baggy
+Baghdad
+Bagley
+bagpipe
+baguette
+bah
+Bahai
+Bahaism
+Bahama
+Bahrein
+bail
+Bailey
+bailiff
+bailiwick
+bailout
+Baird
+bait
+baize
+Baja
+bake
+Bakelite
+Bakersfield
+bakery
+Bakhtiari
+baklava
+baksheesh
+Baku
+balalaika
+balance
+Balboa
+balcony
+bald
+balderdash
+baldpate
+Baldwin
+baldy
+bale
+baleen
+baleful
+Balfour
+Bali
+Balinese
+balk
+Balkan
+balkanize
+ball
+ballad
+balladeer
+Ballard
+ballast
+ballerina
+ballet
+balletic
+balletomane
+ballfield
+balloon
+ballot
+ballpark
+ballroom
+ballyhoo
+balm
+baloney
+balsa
+balsam
+balsamic
+Baltic
+Baltimore
+Baltimorean
+baluster
+balustrade
+Balzac
+bam
+Bamako
+Bamberger
+Bambi
+bambino
+bamboo
+bamboozle
+ban
+banal
+banana
+Banbury
+band
+bandage
+bandanna
+bandgap
+bandicoot
+bandit
+banditry
+bandolier
+bandstand
+bandwagon
+bandwidth
+bandy
+bane
+bang
+bangkok
+Bangladesh
+bangle
+Bangor
+Bangui
+banish
+banister
+banjo
+bank
+bankroll
+bankrupt
+bankruptcy
+banns
+banquet
+banquette
+banshee
+bantam
+banter
+Bantu
+Bantus
+banyan
+banzai
+baobab
+baptism
+baptismal
+baptist
+Baptiste
+baptistery
+baptistry
+baptize
+bar
+barb
+Barbados
+Barbara
+barbarian
+barbaric
+barbarism
+barbarity
+barbarous
+barbecue
+barbell
+barber
+barberry
+Barbie
+barbital
+barbiturate
+Barbour
+Barcelona
+Barclay
+bard
+bare
+bareback
+barefaced
+barefoot
+bareheaded
+barfly
+bargain
+barge
+barhop
+baritone
+barium
+bark
+barkentine
+barley
+Barlow
+barmaid
+barn
+Barnabas
+barnacle
+Barnard
+Barnes
+Barnet
+Barnett
+Barney
+Barnhard
+barnstorm
+barnyard
+barograph
+barometer
+baron
+baroness
+baronet
+baronetage
+baronial
+barony
+baroque
+barque
+Barr
+barrack
+barracuda
+barrage
+barre
+barrel
+barren
+Barrett
+barrette
+barricade
+barrier
+Barrington
+barrio
+barrister
+Barron
+barroom
+barrow
+Barry
+Barrymore
+Barstow
+Bart
+bartend
+bartender
+barter
+Barth
+Bartholomew
+Bartlett
+Bartok
+Barton
+baryon
+basal
+basalt
+base
+baseball
+baseboard
+Basel
+baseline
+basement
+baseplate
+baserun
+bash
+bashaw
+basic
+basil
+basilar
+basilica
+basilisk
+basin
+basis
+bask
+basket
+basketball
+basketry
+basketwork
+basophilic
+Basque
+bass
+basset
+Bassett
+bassi
+bassinet
+basso
+bassoon
+basswood
+bastard
+bastardy
+baste
+bastille
+basting
+bastion
+bat
+Batavia
+batch
+Batchelder
+bate
+bateau
+Bateman
+bath
+bathe
+bathetic
+bathhouse
+bathos
+bathrobe
+bathroom
+bathtub
+Bathurst
+bathymetry
+batik
+Batman
+baton
+Bator
+batt
+battalion
+Battelle
+batten
+batterer
+battery
+battle
+battlefield
+battlefront
+battleground
+batwing
+bauble
+baud
+Baudelaire
+Bauer
+Bauhaus
+Bausch
+bauxite
+Bavaria
+bawd
+bawl
+Baxter
+bay
+bayberry
+Bayda
+Baylor
+bayonet
+Bayonne
+bayou
+Bayport
+Bayreuth
+bazaar
+bazooka
+BBC
+B.C.
+BC
+be
+beach
+beachcomb
+beachhead
+beacon
+bead
+beadle
+beadwork
+beagle
+beak
+beam
+bean
+beanbag
+beanie
+bear
+beard
+Beardsley
+bearish
+bearskin
+Beasley
+beast
+Beastie
+beat
+beaten
+beatific
+beatify
+beatitude
+beatnik
+Beatrice
+beau
+Beaujolais
+Beaumont
+Beauregard
+beauteous
+beautician
+beautify
+beauty
+beaux
+beaver
+bebop
+becalm
+became
+because
+Bechtel
+beck
+becket
+Beckman
+beckon
+Becky
+becloud
+become
+bed
+bedaub
+bedazzle
+bedbug
+bedclothes
+bedeck
+bedevil
+bedfast
+bedfellow
+Bedford
+bedim
+bedizen
+bedlam
+bedouin
+bedpan
+bedpost
+bedraggle
+bedridden
+bedrock
+bedroll
+bedroom
+bedside
+bedspread
+bedspring
+bedstead
+bedstraw
+bedtime
+bee
+Beebe
+beebread
+beech
+Beecham
+Beechcraft
+beechwood
+beef
+beefeater
+beefsteak
+beehive
+Beelzebub
+been
+beep
+beer
+beeswax
+beet
+Beethoven
+beetle
+befall
+befallen
+befell
+befit
+befog
+before
+beforehand
+beforetime
+befoul
+befriend
+befuddle
+beg
+began
+begat
+beget
+beggar
+beggary
+begin
+begone
+begonia
+begot
+begotten
+begrime
+begrudge
+beguile
+Begum
+begun
+behalf
+behave
+behavior
+behavioral
+behead
+beheld
+behemoth
+behest
+behind
+behindhand
+behold
+beholden
+behoove
+beige
+Beijing
+being
+Beirut
+bejeweled
+bel
+Bela
+belabor
+belated
+belay
+belch
+beleaguer
+Belfast
+belfry
+Belgian
+Belgium
+Belgrade
+belie
+belief
+belies
+believe
+belike
+Belinda
+belittle
+Belize
+bell
+Bella
+belladonna
+Bellamy
+Bellatrix
+bellboy
+belle
+bellflower
+bellhop
+bellicose
+belligerent
+Bellingham
+Bellini
+bellow
+bellum
+bellwether
+belly
+bellyache
+Belmont
+belong
+Belorussia
+beloved
+below
+Belshazzar
+belt
+Beltsville
+Beltway
+beluga
+belvedere
+belying
+bemadden
+bemoan
+bemuse
+Ben
+bench
+benchmark
+bend
+benday
+Bendix
+beneath
+Benedict
+Benedictine
+benediction
+benedictory
+benefaction
+benefactor
+benefactress
+benefice
+beneficent
+beneficial
+beneficiary
+benefit
+Benelux
+benevolent
+Bengal
+Bengali
+benight
+benign
+benignant
+benison
+Benjamin
+Bennett
+Bennie
+Bennington
+Benny
+Benson
+bent
+Bentham
+benthic
+Bentley
+Benton
+benumb
+Benz
+Benzedrine
+benzene
+benzoate
+benzoin
+benzyl
+Beowulf
+beplaster
+bequeath
+bequest
+berate
+Berea
+bereave
+bereft
+Berenices
+beret
+berg
+bergamot
+Bergen
+Berger
+Bergland
+Berglund
+Bergman
+Bergson
+Bergstrom
+beribbon
+beriberi
+Bering
+Berkeley
+berkelium
+Berkowitz
+Berkshire
+Berlin
+Berliner
+Berlioz
+Berlitz
+Berman
+Bermuda
+Bern
+Bernadette
+Bernadine
+Bernard
+Bernardino
+Bernardo
+berne
+Bernet
+Bernhard
+Bernice
+Bernie
+Berniece
+Bernini
+Bernoulli
+Bernstein
+berry
+berserk
+Bert
+berth
+Bertha
+Bertie
+Bertram
+Bertrand
+Berwick
+beryl
+beryllium
+beseech
+beseem
+beset
+beside
+besiege
+besmirch
+besot
+besought
+bespatter
+bespeak
+bespeckle
+bespectacled
+bespoke
+Bess
+Bessel
+Bessemer
+Bessie
+best
+bestial
+bestiary
+bestir
+bestow
+bestowal
+bestsell
+bestubble
+bet
+beta
+betake
+betaken
+betatron
+betel
+Betelgeuse
+Beth
+bethel
+Bethesda
+bethink
+Bethlehem
+bethought
+betide
+betimes
+betoken
+betony
+betook
+betray
+betrayal
+betrayer
+betroth
+betrothal
+Betsey
+Betsy
+Bette
+betterment
+bettor
+Betty
+between
+betwixt
+Beulah
+bevel
+beverage
+Beverly
+bevy
+bewail
+beware
+bewhisker
+bewilder
+bewitch
+bey
+beyond
+bezel
+Bhutan
+biannual
+bias
+biathlon
+biaxial
+bib
+bibb
+bible
+biblical
+bibliography
+bibliomania
+bibliophile
+bibulous
+bicameral
+bicarbonate
+bicentennial
+bicentric
+biceps
+bichromate
+bicker
+biconcave
+biconnected
+biconvex
+bicuspid
+bicycle
+bid
+biddable
+bidden
+biddy
+bide
+bidiagonal
+bidirectional
+biennial
+biennium
+bier
+bifacial
+bifocal
+bifold
+bifurcate
+big
+bigamist
+bigamous
+bigamy
+Bigelow
+biggie
+biggish
+Biggs
+bighead
+bighearted
+bighorn
+bight
+bigot
+bigotry
+bigwig
+biharmonic
+bijouterie
+bike
+bikini
+bilateral
+bilayer
+bile
+bilge
+bilharzia
+bilharziasis
+bilinear
+bilingual
+bilious
+bilk
+bill
+billabong
+billboard
+billet
+billfold
+billiard
+Billie
+Billiken
+billingsgate
+billion
+billionaire
+billionth
+billow
+billy
+Biltmore
+bimetal
+bimetallic
+bimetallism
+Bimini
+bimodal
+bimolecular
+bimonthly
+bin
+binary
+binaural
+bind
+bindery
+bindle
+binge
+Bingham
+Binghamton
+bingo
+binnacle
+binocular
+binomial
+binuclear
+biocide
+biography
+biology
+Biometrika
+biometry
+biopsy
+biota
+biotic
+bipartisan
+bipartite
+biped
+bipedal
+biphenyl
+biplane
+bipolar
+biquadratic
+biracial
+birch
+birchbark
+bird
+birdbath
+birdbrain
+birdhouse
+birdie
+birdseed
+birdshot
+birdwatch
+birefringent
+Birgit
+Birmingham
+birth
+birthday
+birthmark
+birthplace
+birthright
+birthstone
+biscuit
+bisect
+bisexual
+bishop
+bishopric
+Bismarck
+Bismark
+bismuth
+bison
+bisque
+Bissau
+bistable
+bistate
+bistro
+bit
+bitch
+bite
+bitt
+bitten
+bittern
+bitterroot
+bittersweet
+bitumen
+bituminous
+bitwise
+bivalent
+bivalve
+bivariate
+bivouac
+bivouacked
+bivouacking
+biweekly
+biz
+bizarre
+Bizet
+blab
+blabbermouth
+black
+blackamoor
+blackball
+blackberry
+blackbird
+blackboard
+blackbody
+Blackburn
+blacken
+blackface
+Blackfeet
+blackfly
+blackguard
+blackhead
+blackish
+blackjack
+blacklist
+blackmail
+Blackman
+blackout
+blacksmith
+blacksnake
+Blackstone
+blacktop
+Blackwell
+bladder
+bladdernut
+blade
+blah
+Blaine
+Blair
+Blake
+blame
+blameworthy
+blanc
+blanch
+Blanchard
+Blanche
+bland
+blandish
+blank
+Blankenship
+blanket
+blare
+blarney
+blaspheme
+blasphemous
+blasphemy
+blast
+blat
+blatant
+blather
+blatherskite
+Blatz
+blaze
+blazon
+bleach
+bleak
+bleary
+bleat
+bled
+bleed
+Bleeker
+blemish
+blench
+blend
+Blenheim
+bless
+blest
+Blevins
+blew
+blight
+blimp
+blimpish
+blind
+blindfold
+blink
+Blinn
+blintz
+blip
+bliss
+blister
+blithe
+blitz
+blitzkrieg
+blizzard
+bloat
+blob
+bloc
+Bloch
+block
+blockade
+blockage
+blockbust
+blockhead
+blockhouse
+bloke
+Blomberg
+Blomquist
+blond
+blonde
+blood
+bloodbath
+bloodhound
+bloodletting
+bloodroot
+bloodshed
+bloodshot
+bloodstain
+bloodstone
+bloodstream
+bloodsuck
+bloodthirsty
+bloody
+bloom
+Bloomfield
+Bloomington
+bloop
+blossom
+blot
+blotch
+blotchy
+blouse
+blow
+blowback
+blowfish
+blowgun
+blowhard
+blowhole
+blown
+blowout
+blowpipe
+blowsy
+blowtorch
+blowup
+blowzy
+blubber
+blubbery
+bludgeon
+blue
+blueback
+bluebeard
+bluebell
+blueberry
+bluebill
+bluebird
+bluebonnet
+bluebook
+bluebush
+bluefin
+bluefish
+bluegill
+bluegrass
+bluejacket
+bluepoint
+blueprint
+bluestocking
+bluet
+bluff
+bluish
+Blum
+Blumenthal
+blunder
+blunderbuss
+blunt
+blur
+blurb
+blurt
+blush
+bluster
+blustery
+blutwurst
+Blvd.
+Blythe
+BMW
+boa
+boar
+board
+boardinghouse
+boardroom
+boardwalk
+boast
+boat
+boathouse
+boatload
+boatswain
+boatyard
+bob
+Bobbie
+bobbin
+bobble
+bobby
+bobcat
+bobolink
+bobsled
+bobtail
+bobwhite
+Boca
+bocce
+boccie
+bock
+boddhisattva
+bode
+bodega
+bodhisattva
+bodice
+Bodleian
+body
+bodybuild
+bodyguard
+Boeing
+Boeotian
+bog
+bogey
+boggle
+Bogota
+bogus
+bogy
+Bohemia
+Bohr
+boil
+Bois
+Boise
+boisterous
+bola
+bold
+boldface
+bole
+bolero
+boletus
+bolivar
+Bolivia
+boll
+bollard
+bollix
+bolo
+Bologna
+bolometer
+Bolshevik
+Bolshevism
+Bolshevist
+Bolshoi
+bolster
+bolt
+Bolton
+Boltzmann
+bomb
+bombard
+bombardier
+bombast
+bombastic
+Bombay
+bombproof
+bombshell
+bombsight
+bon
+bona
+bonanza
+Bonaparte
+Bonaventure
+bonbon
+bond
+bondage
+bondholder
+bonds
+bone
+bonefish
+bonehead
+bonfire
+bong
+bongo
+Boniface
+bonito
+bonkers
+Bonn
+Bonner
+bonnet
+Bonneville
+Bonnie
+bonny
+bonsai
+bonus
+bonze
+boo
+boob
+boodle
+boogie
+book
+bookbind
+bookcase
+bookend
+bookie
+bookish
+booklet
+bookmark
+bookmobile
+bookplate
+booksell
+bookshelf
+bookshelves
+bookstore
+bookworm
+boolean
+boom
+boomerang
+boon
+boondock
+boondoggle
+Boone
+boor
+boorish
+boost
+boot
+bootblack
+Bootes
+booth
+bootie
+bootleg
+bootlick
+bootstrap
+booze
+bop
+borage
+borane
+borate
+borax
+Bordeaux
+bordello
+Borden
+border
+borderland
+borderline
+bore
+boreal
+borealis
+Boreas
+boredom
+Borg
+boric
+Boris
+born
+borne
+Borneo
+boron
+borosilicate
+borough
+Borroughs
+borrow
+borscht
+borzoi
+Bosch
+Bose
+bosh
+Bosnia
+bosom
+boson
+boss
+Boston
+bosun
+Boswell
+botanic
+botanist
+botanize
+botany
+botch
+botfly
+both
+botheration
+bothersome
+Botswana
+bottle
+bottleneck
+bottom
+bottommost
+botulin
+botulism
+Boucher
+boudoir
+bouffant
+bough
+bought
+bouillabaisse
+bouillon
+boulder
+bouldery
+boule
+boulevard
+boulevardier
+bounce
+bouncy
+bound
+boundary
+bounden
+bounteous
+bounty
+bouquet
+bourbon
+bourdon
+bourgeois
+bourgeoise
+bourgeoisie
+bourn
+bourse
+boustrophedon
+bout
+boutique
+boutonniere
+bovine
+bow
+Bowditch
+bowdlerize
+Bowdoin
+bowel
+Bowen
+bowery
+bowfin
+bowhead
+bowie
+bowl
+bowleg
+bowline
+bowsprit
+bowstring
+box
+boxcar
+boxwood
+boy
+boyar
+Boyce
+boycott
+Boyd
+Boyer
+boyfriend
+boyhood
+boyish
+Boyle
+Boylston
+boysenberry
+BP
+bra
+brace
+bracelet
+brachycephalic
+bracken
+bracket
+brackish
+bract
+brad
+Bradbury
+Bradford
+Bradley
+Bradshaw
+Brady
+brae
+brag
+Bragg
+braggart
+brahma
+Brahman
+Brahmaputra
+Brahmin
+Brahms
+Brahmsian
+braid
+braille
+brain
+Brainard
+brainchild
+brainchildren
+brainstorm
+brainwash
+braise
+brake
+bramble
+bran
+branch
+brand
+Brandeis
+Brandenburg
+brandish
+Brandon
+Brandt
+brandy
+brandywine
+Braniff
+brant
+brash
+Brasilia
+brass
+brassiere
+brat
+brattish
+bratwurst
+Braun
+bravado
+brave
+bravery
+bravo
+bravura
+brawl
+brawn
+bray
+braze
+brazen
+brazier
+Brazil
+Brazilian
+Brazzaville
+breach
+bread
+breadbasket
+breadboard
+breadfruit
+breadroot
+breadth
+breadwin
+break
+breakage
+breakaway
+breakdown
+breakfast
+breakneck
+breakout
+breakpoint
+breakthrough
+breakup
+breakwater
+bream
+breast
+breastplate
+breastwork
+breath
+breathalyzer
+breathe
+breathtaking
+breccia
+bred
+breech
+breechclout
+breeches
+breed
+breeze
+breezeway
+Bremen
+bremsstrahlung
+Brenda
+Brendan
+Brennan
+Brenner
+Brent
+Brest
+brethren
+Breton
+Brett
+breve
+brevet
+breviary
+brevity
+brew
+brewery
+Brewster
+Brian
+briar
+bribe
+bribery
+Brice
+brick
+brickbat
+bricklay
+brickwork
+brickyard
+bridal
+bride
+bridegroom
+bridesmaid
+bridge
+bridgeable
+bridgehead
+Bridgeport
+Bridget
+Bridgetown
+bridgework
+bridle
+Brie
+brief
+briefcase
+brier
+briery
+brig
+brigade
+brigadier
+brigand
+brigantine
+Briggs
+Brigham
+bright
+brighten
+Brighton
+brightwork
+Brigitte
+brilliant
+Brillouin
+brim
+brimstone
+Brindisi
+brindle
+brine
+bring
+brink
+brinkmanship
+brioche
+briquette
+Brisbane
+brisk
+brisket
+bristle
+bristly
+bristol
+Britain
+Britannic
+Britannica
+britches
+Briticism
+British
+Britisher
+Briton
+Britt
+Brittany
+Britten
+brittle
+broach
+broad
+broadcast
+broadcloth
+broaden
+broadloom
+broadsheet
+broadside
+Broadway
+brocade
+broccoli
+brochette
+brochure
+Brock
+Broglie
+brogue
+broil
+broke
+broken
+brokerage
+bromate
+bromeliad
+Bromfield
+bromide
+bromine
+Bromley
+bronchi
+bronchial
+bronchitis
+bronchus
+bronco
+brontosaurus
+Bronx
+bronze
+brooch
+brood
+brook
+Brooke
+Brookhaven
+Brookline
+Brooklyn
+brookside
+broom
+broomcorn
+broomstick
+broth
+brothel
+brother
+brougham
+brought
+brouhaha
+brow
+browbeat
+browbeaten
+brown
+Browne
+Brownell
+Brownian
+brownie
+brownish
+brownout
+brownstone
+browse
+Bruce
+brucellosis
+Bruckner
+Bruegel
+bruise
+bruit
+Brumidi
+brunch
+brunette
+Brunhilde
+Bruno
+Brunswick
+brunt
+brush
+brushfire
+brushwork
+brusque
+Brussels
+brutal
+brute
+brutish
+Bryan
+Bryant
+Bryce
+Bryn
+bryophyte
+b's
+BSA
+BTU
+bubble
+bubonic
+buccaneer
+Buchanan
+Bucharest
+Buchenwald
+Buchwald
+buck
+buckaroo
+buckboard
+bucket
+buckeye
+buckhorn
+Buckingham
+buckle
+Buckley
+Bucknell
+buckram
+buckshot
+buckskin
+buckthorn
+bucktooth
+buckwheat
+bucolic
+bud
+Budapest
+Budd
+Buddha
+Buddhism
+Buddhist
+buddy
+budge
+budget
+budgetary
+budgeteer
+budgie
+budgiregar
+Budweiser
+Buena
+Buenos
+buff
+buffalo
+buffet
+bufflehead
+buffoon
+buffoonery
+buffoonish
+bug
+bugaboo
+bugbear
+bugeyed
+buggery
+buggy
+bughouse
+bugle
+Buick
+build
+buildup
+built
+builtin
+Bujumbura
+bulb
+bulblet
+bulbous
+Bulgaria
+bulge
+bulimia
+bulimic
+bulk
+bulkhead
+bull
+bulldog
+bulldoze
+bullet
+bulletin
+bulletproof
+bullfight
+bullfinch
+bullfrog
+bullhead
+bullhide
+bullhorn
+bullion
+bullish
+bullock
+bullpen
+bullseye
+bullshit
+bullwhack
+bullwhip
+bully
+bullyboy
+bullyrag
+bulrush
+bulwark
+bum
+bumble
+bumblebee
+bump
+bumpkin
+bumptious
+bun
+bunch
+buncombe
+Bundestag
+bundle
+bung
+bungalow
+bungee
+bunghole
+bungle
+bunion
+bunk
+bunkhouse
+bunkmate
+bunkum
+bunny
+Bunsen
+bunt
+Bunyan
+buoy
+buoyant
+burble
+Burch
+burden
+burdensome
+burdock
+bureau
+bureaucracy
+bureaucrat
+bureaucratic
+buret
+burette
+burg
+burgee
+burgeon
+burgess
+burgher
+burglar
+burglarproof
+burglary
+burgle
+burgomaster
+Burgundian
+Burgundy
+burial
+buried
+burin
+Burke
+Burkina
+burl
+burlap
+burlesque
+burley
+Burlington
+burly
+Burma
+Burmese
+burn
+Burnett
+Burnham
+burnish
+burnoose
+burnout
+Burnside
+burnt
+burp
+burr
+burrito
+burro
+Burroughs
+burrow
+bursar
+bursitis
+burst
+Burt
+Burton
+Burtt
+Burundi
+bury
+bus
+busboy
+Busch
+buses
+bush
+bushel
+bushmaster
+Bushnell
+bushwhack
+business
+busload
+buss
+bust
+bustard
+bustle
+busy
+busybody
+busyness
+but
+butadiene
+butane
+butch
+butcher
+butchery
+butene
+buteo
+butler
+butt
+butte
+butterball
+buttercup
+butterfat
+Butterfield
+butterfinger
+butterfly
+buttermilk
+butternut
+butterscotch
+buttery
+buttock
+button
+buttonhole
+buttonhook
+buttonwood
+buttress
+Buttrick
+butyl
+butylene
+butyrate
+butyric
+buxom
+Buxtehude
+Buxton
+buy
+buyback
+buyer
+buyout
+buzz
+buzzard
+buzzer
+buzzing
+buzzsaw
+buzzword
+BWI
+by
+bye
+Byers
+bygone
+bylaw
+byline
+bypass
+bypath
+byplay
+byproduct
+Byrd
+Byrne
+byroad
+Byron
+Byronic
+bystander
+byte
+byway
+byword
+Byzantine
+Byzantium
+CA
+cab
+cabal
+cabala
+cabana
+cabaret
+cabbage
+cabby
+cabdriver
+cabin
+cabinet
+cabinetry
+cabinetwork
+cable
+cablegram
+caboodle
+caboose
+Cabot
+cabriole
+cabriolet
+cacao
+cacciatore
+cachalot
+cache
+cachet
+caching
+cacique
+cackle
+CACM
+cacophonist
+cacophonous
+cacophony
+cacti
+cactus
+cad
+cadastral
+cadaver
+cadaverous
+caddie
+caddish
+caddy
+cadent
+cadenza
+cadet
+cadge
+Cadillac
+cadmium
+cadre
+caduceus
+Cady
+Caesar
+caesura
+cafe
+cafeteria
+caffeinate
+caffeine
+caftan
+cage
+cagey
+Cahill
+cahoot
+caiman
+Cain
+Caine
+cairn
+Cairo
+caisson
+cajole
+cajolery
+Cajun
+cake
+cakewalk
+Cal
+calabash
+Calais
+calamine
+calamitous
+calamity
+calcareous
+calcify
+calcine
+calcite
+calcium
+calculable
+calculate
+calculi
+calculus
+Calcutta
+Calder
+caldera
+Caldwell
+Caleb
+calendar
+calendric
+calends
+calendula
+calf
+calfskin
+Calgary
+Calhoun
+caliber
+calibrate
+calico
+California
+californium
+caliper
+caliph
+caliphate
+calisthenic
+calk
+Calkins
+call
+calla
+Callaghan
+Callahan
+calligraph
+calligraphy
+calliope
+Callisto
+callous
+callow
+callus
+calm
+caloric
+calorie
+calorimeter
+Calumet
+calumniate
+calumny
+calvados
+calvary
+calve
+Calvert
+Calvin
+Calvinist
+calypso
+calyx
+cam
+camaraderie
+camber
+cambium
+Cambodia
+Cambrian
+cambric
+Cambridge
+camcorder
+Camden
+came
+camel
+camelback
+cameleer
+camellia
+camelopard
+Camelot
+Camembert
+cameo
+camera
+Cameron
+Cameroun
+Camilla
+Camille
+Camino
+camisole
+camouflage
+camp
+campaign
+campanile
+campanology
+Campbell
+campfire
+campground
+camphor
+campion
+camporee
+campsite
+campus
+camshaft
+can
+Canaan
+Canada
+Canadian
+canal
+canalize
+canape
+canard
+canary
+canasta
+Canaveral
+Canberra
+cancan
+cancel
+cancellate
+cancer
+cancerous
+Candace
+candela
+candelabra
+candid
+candidacy
+candidate
+Candide
+candle
+candlelight
+candlelit
+candlepower
+candlestick
+candor
+candy
+cane
+Canfield
+canine
+Canis
+canister
+canker
+cankerworm
+canna
+cannabis
+cannel
+cannery
+cannibal
+cannister
+cannon
+cannonade
+cannonball
+cannoneer
+cannot
+canoe
+canoeing
+canoeist
+Canoga
+canon
+canonic
+canopy
+canst
+can't
+cant
+cantabile
+Cantabrigian
+cantaloupe
+cantankerous
+cantata
+canteen
+Canterbury
+canticle
+cantilever
+cantle
+canto
+canton
+Cantonese
+cantor
+Cantrell
+canvas
+canvasback
+canvass
+canyon
+cap
+capacious
+capacitance
+capacitate
+capacitive
+capacitor
+capacity
+caparison
+cape
+capella
+caper
+Capetown
+capillarity
+capillary
+Capistrano
+capita
+capital
+capitate
+capitol
+Capitoline
+capitulate
+capo
+capon
+cappucino
+caprice
+capricious
+Capricorn
+capsize
+capstan
+capstone
+capsule
+captain
+captaincy
+caption
+captious
+captivate
+captor
+capture
+capuchin
+Caputo
+capybara
+car
+carabiner
+Caracas
+caracul
+carafe
+carageen
+caramel
+carapace
+carat
+caravan
+caravansary
+caravel
+caraway
+carbide
+carbine
+carbohydrate
+Carboloy
+carbon
+carbonaceous
+carbonate
+Carbondale
+Carbone
+carbonic
+carboniferous
+carbonyl
+carborundum
+carboxy
+carboxyl
+carboxylate
+carboy
+carbuncle
+carburet
+carburetion
+carburetor
+carcass
+carcinogen
+carcinogenic
+carcinoma
+card
+cardamom
+cardboard
+cardiac
+cardigan
+cardinal
+cardiograph
+cardiography
+cardioid
+cardiology
+cardiovascular
+care
+careen
+career
+carefree
+caress
+caret
+caretaker
+careworn
+Carey
+carfare
+Cargill
+cargo
+cargoes
+carhop
+Carib
+Caribbean
+caribou
+caricature
+caries
+carillon
+carioca
+Carl
+Carla
+Carleton
+Carlin
+Carlisle
+Carlo
+carload
+Carlson
+Carlton
+Carlyle
+Carmela
+Carmen
+Carmichael
+carmine
+carnage
+carnal
+carnation
+carne
+Carnegie
+carnelian
+carney
+carnival
+carnivore
+carnivorous
+carny
+carob
+carol
+Carole
+Carolina
+Caroline
+Carolingian
+Carolinian
+Carolyn
+carom
+carotene
+carotid
+carousal
+carouse
+carousel
+carp
+carpal
+Carpathia
+carpel
+carpenter
+carpentry
+carpet
+carpetbag
+carport
+Carr
+carrageen
+Carrara
+carrel
+carriage
+Carrie
+carrion
+Carroll
+carrot
+Carruthers
+carry
+carryall
+carryover
+carsick
+Carson
+cart
+cartage
+carte
+cartel
+Cartesian
+Carthage
+Carthaginian
+cartilage
+cartogram
+cartography
+carton
+cartoon
+cartouche
+cartridge
+cartwheel
+Caruso
+carve
+carven
+caryatid
+casaba
+Casanova
+casbah
+cascade
+cascara
+case
+casebook
+casein
+casework
+Casey
+cash
+cashew
+cashier
+cashmere
+casino
+cask
+casket
+Caspian
+Cassandra
+cassava
+casserole
+cassette
+Cassidy
+Cassiopeia
+Cassius
+cassock
+cassowary
+cast
+castanet
+castaway
+caste
+casteth
+castigate
+Castilian
+Castillo
+castle
+castoff
+castor
+castrate
+Castro
+casual
+casualty
+casuist
+casuistry
+cat
+catabolic
+catabolize
+cataclysm
+cataclysmic
+catacomb
+catafalque
+Catalan
+catalepsy
+cataleptic
+Catalina
+catalog
+catalogue
+catalpa
+catalysis
+catalyst
+catalytic
+catalyze
+catamaran
+catamount
+catapult
+cataract
+catarrh
+catastrophe
+catastrophic
+catatonia
+catatonic
+catbird
+catcall
+catch
+catchall
+catchup
+catchword
+catechism
+catechist
+catechize
+categoric
+categorize
+category
+catena
+catenary
+catenate
+cater
+caterpillar
+caterwaul
+catfish
+catgut
+catharsis
+cathartic
+cathedra
+cathedral
+Catherine
+Catherwood
+catheter
+cathode
+cathodic
+catholic
+Catholicism
+Cathy
+cation
+cationic
+catkin
+catnap
+catnip
+Catskill
+catsup
+cattail
+cattle
+catty
+CATV
+catwalk
+Caucasia
+Caucasus
+Cauchy
+caucus
+caudal
+caudillo
+caught
+cauldron
+cauliflower
+caulk
+causa
+causal
+causation
+cause
+causeway
+caustic
+cauterize
+caution
+cautionary
+cautious
+cavalcade
+cavalier
+cavalry
+cave
+caveat
+Cavendish
+cavern
+cavernous
+caviar
+cavil
+Caviness
+cavitate
+cavort
+caw
+cay
+cayenne
+Cayley
+cayman
+Cayuga
+CB
+CBC
+CBS
+CCC
+CCNY
+CD
+CDC
+cease
+Cecil
+Cecilia
+Cecily
+Cecropia
+cedar
+cede
+cedilla
+Cedric
+ceil
+celandine
+Celanese
+Celebes
+celebrant
+celebrate
+celebrity
+celeriac
+celerity
+celery
+celesta
+Celeste
+celestial
+Celia
+celibacy
+celibate
+cell
+cellar
+cello
+cellophane
+cellular
+celluloid
+cellulose
+Celsius
+Celt
+Celtic
+cement
+cemetery
+cenotaph
+cenote
+Cenozoic
+censer
+censor
+censorial
+censorious
+censure
+census
+cent
+centaur
+Centauri
+centenarian
+centenary
+centennial
+center
+centerboard
+centered
+centerfold
+centering
+centerline
+centerpiece
+centers
+centesimal
+centigrade
+centigram
+centiliter
+centime
+centimeter
+centipede
+central
+centrex
+centric
+centrifugal
+centrifugate
+centrifuge
+centripetal
+centrist
+centroid
+centum
+centurion
+century
+CEO
+cephalic
+cephalopod
+Cepheid
+Cepheus
+CEQ
+ceramic
+ceramist
+Cerberus
+cereal
+cerebellum
+cerebral
+cerebrate
+cerebrum
+ceremonial
+ceremonious
+ceremony
+Ceres
+cereus
+cerise
+cerium
+CERN
+certain
+certainty
+certificate
+certificatory
+certified
+certify
+certiorari
+certitude
+cerulean
+Cervantes
+cervical
+cervix
+cesarean
+cesium
+cessation
+cession
+Cessna
+cesspool
+cetacean
+cetera
+ceteris
+Cetus
+Ceylon
+Cezanne
+Chablis
+Chad
+chador
+Chadwick
+chafe
+chaff
+chaffer
+chaffinch
+chagrin
+chain
+chainsaw
+chair
+chairlady
+chaise
+chalcedony
+chalet
+chalice
+chalk
+chalkboard
+chalkline
+challenge
+Chalmers
+chamber
+chamberlain
+chambermaid
+chameleon
+chamfer
+chamois
+chamomile
+champ
+champagne
+champaign
+champion
+Champlain
+Chan
+chance
+chancel
+chancellery
+chancellor
+chancery
+chancy
+chandelier
+chandler
+chandlery
+Chaney
+Chang
+change
+changeable
+changeling
+changeover
+channel
+chanson
+chant
+chantey
+chanticleer
+Chantilly
+chantry
+chanty
+Chao
+chaos
+chaotic
+chap
+chaparral
+chapel
+chaperon
+chaperone
+chaplain
+chaplaincy
+Chaplin
+chapter
+char
+character
+characteristic
+charade
+charcoal
+chard
+charge
+chargeable
+charily
+chariot
+charioteer
+charisma
+charismatic
+charitable
+charity
+charlatan
+Charlene
+Charles
+Charleston
+Charley
+Charlie
+Charlotte
+Charlottesville
+charm
+charnel
+Charon
+chart
+Charta
+charter
+Chartres
+chartreuse
+chartroom
+chary
+Charybdis
+chase
+chasm
+chassis
+chaste
+chasten
+chastise
+chastity
+chasuble
+chat
+chateau
+chateaux
+Chatham
+Chattanooga
+chattel
+chatter
+Chaucer
+chauffer
+chauffeur
+Chauncey
+Chautauqua
+chauvinism
+chauvinist
+Chavez
+chaw
+cheap
+cheapen
+cheapskate
+cheat
+check
+checkbook
+checkerboard
+checklist
+checkmate
+checkout
+checkpoint
+checkroom
+checksum
+checkup
+cheddar
+cheek
+cheekbone
+cheer
+cheerlead
+cheery
+cheese
+cheeseburger
+cheesecake
+cheesecloth
+cheetah
+chef
+chelate
+Chelsea
+chemic
+chemise
+chemisorb
+chemisorption
+chemist
+chemistry
+chemoreception
+chemoreceptor
+chemotherapeutic
+chemotherapy
+chemurgy
+Chen
+Cheney
+chenille
+cherish
+Cherokee
+cheroot
+cherry
+chert
+cherub
+cherubic
+cherubim
+chervil
+Cheryl
+Chesapeake
+Cheshire
+chess
+chessboard
+chest
+Chester
+chesterfield
+Chesterton
+chestnut
+chevalier
+Chevrolet
+chevron
+Chevy
+chew
+Cheyenne
+chi
+Chiang
+chianti
+chiaroscuro
+chiasma
+chic
+Chicago
+Chicagoan
+chicanery
+Chicano
+chick
+chickadee
+chicken
+chicle
+chicory
+chide
+chief
+chiefdom
+chieftain
+chiffon
+chigger
+chignon
+Chihuahua
+chilblain
+child
+childbear
+childbirth
+Childers
+childish
+children
+Chile
+Chilean
+chili
+chilies
+chill
+chilly
+chime
+chimera
+chimeric
+Chimique
+chimney
+chimp
+chimpanzee
+chin
+china
+Chinaman
+Chinamen
+Chinatown
+chinch
+chinchilla
+chine
+Chinese
+Ching
+chink
+chino
+chinoiserie
+Chinook
+chintz
+chintzy
+chip
+chipboard
+chipmunk
+Chippendale
+Chippewa
+chiropodist
+chiropractic
+chiropractor
+chirp
+chisel
+Chisholm
+chit
+chitchat
+chitin
+chitinous
+chiton
+chivalric
+chivalrous
+chivalry
+chive
+chlorate
+chlordane
+chloric
+chloride
+chlorinate
+chlorine
+chloroform
+chlorophyl
+chlorophyll
+chock
+chocolate
+Choctaw
+choice
+choir
+choirboy
+choirmaster
+choke
+choler
+cholera
+choleric
+cholesterol
+cholinesterase
+chomp
+chondrite
+chondrule
+choose
+chop
+chophouse
+Chopin
+chopstick
+choral
+chorale
+chord
+chordal
+chordate
+chore
+choreograph
+choreography
+chorine
+chortle
+chorus
+chose
+chosen
+Chou
+chow
+chowder
+Chris
+Christ
+christen
+Christendom
+Christensen
+Christenson
+Christian
+Christiana
+Christianson
+Christie
+Christina
+Christine
+Christlike
+Christmas
+Christoffel
+Christophe
+Christopher
+Christy
+chromate
+chromatic
+chromatograph
+chromatography
+chrome
+chromic
+chromium
+chromosomal
+chromosome
+chromosphere
+chronic
+chronicle
+chronograph
+chronography
+chronology
+chronometer
+chrysalis
+chrysanthemum
+Chrysler
+chub
+chuck
+chuckle
+chuff
+chug
+chukker
+chum
+chump
+Chungking
+chunk
+church
+churchgo
+Churchill
+Churchillian
+churchyard
+churl
+churlish
+churn
+chute
+chutney
+CIA
+cicada
+Cicero
+Ciceronian
+cider
+cigar
+cigarette
+cilantro
+cilia
+ciliate
+cinch
+Cincinnati
+cinder
+Cinderella
+Cindy
+cinema
+cinematic
+cinematography
+Cinerama
+cinnabar
+cinnamon
+CIO
+cipher
+circa
+circadian
+Circe
+circle
+circlet
+circuit
+circuitous
+circuitry
+circulant
+circular
+circulate
+circumambient
+circumambulate
+circumcircle
+circumcise
+circumcision
+circumference
+circumferential
+circumflex
+circumfluent
+circumlocution
+circumlocutory
+circumnavigate
+circumpolar
+circumscribe
+circumscription
+circumspect
+circumsphere
+circumstance
+circumstantial
+circumvallate
+circumvent
+circus
+cirque
+cirrhosis
+cirrostratus
+cirrus
+CIS
+cistern
+cit.
+citadel
+citation
+cite
+Citicorp
+citify
+citizen
+citizeness
+citizenry
+citrate
+citric
+Citroen
+citron
+citrus
+city
+cityscape
+citywide
+civet
+civic
+civil
+civilian
+clack
+clad
+claim
+claimant
+Claire
+clairvoyant
+clam
+clambake
+clamber
+clamor
+clamorous
+clamp
+clamshell
+clan
+clandestine
+clang
+clangor
+clangorous
+clank
+clannish
+clans
+clap
+clapboard
+Clapeyron
+claptrap
+claque
+Clara
+Clare
+Claremont
+Clarence
+Clarendon
+claret
+clarify
+clarinet
+clarion
+clarity
+Clark
+Clarke
+clash
+clasp
+class
+classic
+classification
+classificatory
+classify
+classmate
+classroom
+clatter
+clattery
+Claude
+Claudia
+Claudio
+Claus
+clausal
+clause
+Clausen
+Clausius
+claustral
+claustrophobe
+clavichord
+clavicle
+clavier
+claw
+clay
+clayey
+claymore
+Clayton
+clean
+cleanse
+cleanup
+clear
+clearance
+clearheaded
+clearinghouse
+Clearwater
+cleat
+cleavage
+cleave
+clef
+cleft
+Clem
+clematis
+clement
+Clemson
+clench
+Cleo
+Cleopatra
+clepsydra
+clerestory
+clergy
+cleric
+clerisy
+clerk
+Cleveland
+clever
+cliche
+click
+client
+clientele
+cliff
+cliffhang
+Clifford
+Clifton
+climactic
+climate
+climatic
+climatology
+climax
+climb
+clime
+clinch
+cline
+cling
+clinic
+clinician
+clink
+Clint
+Clinton
+Clio
+clip
+clipboard
+clique
+clitoral
+clitoris
+Clive
+cloaca
+cloak
+cloakroom
+clobber
+clock
+clockwatcher
+clockwise
+clockwork
+clod
+cloddish
+clodhop
+clog
+cloisonne
+cloister
+clomp
+clonal
+clone
+clonic
+clop
+close
+closemouthed
+closet
+closeup
+closure
+clot
+cloth
+clothbound
+clothe
+clothes
+clotheshorse
+clothesline
+clothespin
+clothier
+Clotho
+cloture
+cloud
+cloudburst
+clout
+clove
+cloven
+cloverleaf
+clown
+clownish
+cloy
+club
+clubfoot
+clubhouse
+clubroom
+cluck
+clue
+clump
+clumsy
+clung
+clunk
+cluster
+clutch
+clutter
+Clyde
+Clytemnestra
+CNN
+Co.
+coach
+coachwork
+coact
+coadjutor
+coagulable
+coagulant
+coagulate
+coal
+coalesce
+coalescent
+coalition
+coaming
+coanchor
+coarse
+coarsen
+coarticulate
+coast
+coastal
+coastline
+coastwise
+coat
+Coates
+coati
+coattail
+coauthor
+coax
+coaxial
+cob
+cobalt
+Cobb
+cobble
+cobblestone
+Cobol
+cobra
+cobweb
+coca
+cocaine
+cocci
+coccidiosis
+coccus
+cochair
+cochineal
+cochlea
+cochlear
+Cochran
+Cochrane
+cock
+cockade
+cockamamie
+cockatiel
+cockatoo
+cockcrow
+cockerel
+cockeye
+cockfight
+cockle
+cocklebur
+cockleshell
+cockney
+cockpit
+cockroach
+cocksure
+cocktail
+coco
+cocoa
+cocoanut
+coconut
+cocoon
+cod
+coda
+Coddington
+coddle
+code
+codebreak
+codefendant
+codeine
+codeposit
+codetermine
+codeword
+codex
+codfish
+codger
+codices
+codicil
+codify
+codpiece
+Cody
+coed
+coeditor
+coeducation
+coefficient
+coelacanth
+coequal
+coerce
+coercible
+coercion
+coeval
+coexist
+coexistent
+coextensive
+cofactor
+coffee
+coffeecup
+coffeehouse
+coffeepot
+coffer
+cofferdam
+Coffey
+coffin
+Coffman
+cofound
+cog
+cogent
+cogitate
+cognac
+cognate
+cognition
+cognizable
+cognizant
+cognoscenti
+cohabit
+cohabitation
+Cohen
+cohere
+coherent
+cohesion
+Cohn
+cohort
+cohosh
+cohost
+coif
+coiffeur
+coiffure
+coil
+coin
+coinage
+coincide
+coincident
+coincidental
+coinsurance
+coinsure
+coinvent
+coinventor
+coital
+coitus
+coke
+col
+cola
+colander
+colatitude
+Colby
+cold
+cole
+Coleman
+coleoptera
+Coleridge
+coleslaw
+Colette
+coleus
+Colgate
+colic
+colicky
+coliform
+Colin
+coliseum
+colitis
+collaborate
+collage
+collagen
+collagenic
+collapse
+collapsible
+collar
+collarbone
+collard
+collate
+collateral
+colleague
+collect
+collectible
+colleen
+college
+collegial
+collegian
+collegiate
+collet
+collide
+collie
+colliery
+collimate
+collinear
+Collins
+collision
+collocate
+collodion
+colloid
+colloquia
+colloquial
+colloquium
+colloquy
+collude
+collusion
+cologne
+Colombia
+Colombo
+colon
+colonel
+colonial
+colonic
+colonist
+colonnade
+colony
+colophon
+color
+Colorado
+colorate
+coloratura
+colorcast
+colorfast
+colorimeter
+colossal
+Colosseum
+colossi
+Colossian
+Colossians
+colossus
+colostomy
+colostrum
+colt
+coltish
+coltsfoot
+Columbia
+columbine
+Columbus
+column
+columnar
+colza
+coma
+Comanche
+comatose
+comb
+combat
+combatant
+combative
+combination
+combinator
+combinatorial
+combinatoric
+combine
+combust
+combustible
+come
+comeback
+comedian
+comedic
+comedienne
+comedown
+comedy
+comestible
+comet
+cometary
+cometh
+comeuppance
+comfort
+comfrey
+comfy
+comic
+Cominform
+comma
+command
+commandant
+commandeer
+commando
+commemorate
+commend
+commendation
+commendatory
+commensurable
+commensurate
+comment
+commentary
+commentator
+commerce
+commercial
+commie
+commingle
+comminute
+commiserate
+commissar
+commissariat
+commissary
+commission
+commit
+committable
+committal
+committee
+commode
+commodious
+commodity
+commodore
+common
+commonality
+commonplace
+commonweal
+commonwealth
+commotion
+communal
+commune
+communicable
+communicant
+communicate
+communion
+communique
+communitarian
+commutate
+commute
+compact
+Compagnie
+companion
+companionway
+company
+comparative
+comparator
+compare
+comparison
+compartment
+compass
+compassion
+compassionate
+compatible
+compatriot
+compeer
+compel
+compellable
+compendia
+compendious
+compendium
+compensable
+compensate
+compete
+competent
+competition
+competitor
+compilation
+compile
+complacent
+complain
+complainant
+complaint
+complaisant
+compleat
+complement
+complementarity
+complementary
+complementation
+complete
+completion
+complex
+complexion
+compliant
+complicate
+complicity
+compliment
+complimentary
+compline
+comply
+component
+comport
+compose
+composit
+composite
+composition
+compositor
+compost
+composure
+compote
+compound
+comprehend
+comprehensible
+comprehension
+compress
+compressible
+compression
+compressor
+comprise
+compromise
+Compton
+comptroller
+compulsion
+compulsory
+compunction
+computation
+compute
+comrade
+Comstock
+con
+Conakry
+Conant
+concatenate
+concave
+conceal
+concede
+conceit
+conceive
+concentrate
+concentric
+concept
+conceptual
+concern
+concert
+concertgo
+concerti
+concertina
+concertino
+concertmaster
+concertmeister
+concerto
+concession
+concessionaire
+conch
+conchoidal
+conchology
+conchs
+concierge
+conciliate
+concise
+concision
+conclave
+conclude
+conclusion
+concoct
+concomitant
+concord
+concordant
+concordat
+Concorde
+concourse
+concrete
+concretion
+concubinage
+concubine
+concupiscent
+concur
+concurrent
+concussion
+condemn
+condemnate
+condensate
+condense
+condescend
+condescension
+condiment
+condition
+condo
+condolence
+condom
+condominium
+condone
+condor
+conduce
+conducive
+conduct
+conductance
+conduit
+cone
+coneflower
+conelrad
+Conestoga
+coney
+confab
+confabulate
+confect
+confectionary
+confectionery
+confederacy
+confederate
+confer
+conferee
+conference
+conferential
+conferral
+confess
+confession
+confessor
+confetti
+confidant
+confidante
+confide
+confident
+confidential
+configuration
+configure
+confine
+confirm
+confirmation
+confirmatory
+confiscable
+confiscate
+conflagration
+conflation
+conflict
+confluent
+confocal
+conform
+conformal
+conformant
+conformation
+confound
+confraternity
+confrere
+confront
+confrontation
+Confucian
+Confucianism
+Confucius
+confuse
+confusion
+confutation
+confute
+conga
+congeal
+congelation
+congener
+congeneric
+congenial
+congenital
+congeries
+congest
+congestion
+conglomerate
+Congo
+Congolese
+congratulate
+congregate
+congress
+congressional
+congruent
+congruential
+congruity
+congruous
+conic
+conifer
+coniferous
+conjectural
+conjecture
+conjoin
+conjoint
+conjugal
+conjugate
+conjunct
+conjunctivitis
+conjuncture
+conjure
+conk
+Conklin
+Conley
+conn
+connect
+Connecticut
+Conner
+Connie
+conniption
+connivance
+connive
+connoisseur
+Connolly
+Connor
+Connors
+connotation
+connote
+connubial
+conoid
+conquer
+conqueror
+conquest
+conquistador
+Conrad
+Conrail
+consanguine
+consanguineous
+conscience
+conscientious
+conscionable
+conscious
+conscript
+consecrate
+consecutive
+consensual
+consensus
+consent
+consequent
+consequential
+conservancy
+conservation
+conservatism
+conservator
+conserve
+consider
+considerate
+consign
+consignee
+consignor
+consist
+consistent
+consistory
+consolation
+console
+consolidate
+consomme
+consonant
+consonantal
+consort
+consortia
+consortium
+conspecific
+conspicuous
+conspiracy
+conspirator
+conspiratorial
+conspire
+constable
+constabulary
+Constance
+constant
+Constantine
+Constantinople
+constellate
+consternate
+constipate
+constituent
+constitute
+constrain
+constraint
+constrict
+construct
+constructible
+construe
+consul
+consular
+consulate
+consult
+consultant
+consultation
+consultive
+consume
+consummate
+consumption
+contact
+contagion
+contagious
+contain
+contaminant
+contaminate
+contemplate
+contemporaneity
+contemporaneous
+contemporary
+contempt
+contemptible
+contemptuous
+contend
+content
+contentious
+conterminous
+contest
+contestant
+context
+contextual
+contiguity
+contiguous
+continent
+continental
+contingent
+continua
+continual
+continuant
+continuation
+continue
+continuity
+continuo
+continuous
+continuum
+contort
+contour
+contraband
+contrabass
+contrabassoon
+contraception
+contract
+contractual
+contradict
+contradictor
+contradistinction
+contradistinguish
+contrail
+contraindicate
+contralateral
+contralto
+contraposition
+contrapositive
+contraption
+contrapuntal
+contrariety
+contrariwise
+contrary
+contrast
+contravariant
+contravene
+contravention
+contretemps
+contribute
+contributor
+contrite
+contrition
+contrivance
+contrive
+control
+controversial
+controversy
+controvert
+controvertible
+contumacious
+contumacy
+contumelious
+contumely
+contusion
+conundrum
+conurbation
+Convair
+convalesce
+convalescent
+convect
+convene
+convenient
+convent
+conventioneer
+converge
+convergent
+conversant
+conversation
+converse
+conversion
+convert
+convertible
+convex
+convey
+conveyance
+conveyor
+convict
+convince
+convivial
+convocation
+convoke
+convolute
+convolve
+convoy
+convulse
+convulsion
+Conway
+cony
+coo
+cook
+cookbook
+Cooke
+cookery
+cookie
+cookout
+cool
+coolant
+Cooley
+coolheaded
+Coolidge
+coolie
+coolish
+coon
+coonskin
+coop
+cooperage
+cooperate
+coordinate
+Coors
+coot
+cootie
+cop
+cope
+Copeland
+Copenhagen
+copepod
+Copernican
+Copernicus
+copilot
+copious
+coplanar
+copolymer
+copperas
+Copperfield
+copperhead
+coppery
+copra
+coprolite
+copse
+copter
+Coptic
+copula
+copulate
+copy
+copybook
+copycat
+copyreader
+copyright
+copywriter
+coquette
+coquettish
+Cora
+coracle
+coral
+coralline
+corbel
+Corbett
+Corcoran
+cord
+cordage
+cordial
+cordiform
+cordillera
+cordite
+cordon
+corduroy
+cordwood
+core
+coreligionist
+Corey
+coriander
+Corinne
+Corinth
+Corinthian
+Coriolanus
+Coriolis
+cork
+corkscrew
+cormorant
+corn
+cornbread
+cornea
+corneal
+Cornelia
+Cornelius
+Cornell
+cornerstone
+cornet
+cornfield
+cornflower
+cornice
+corniche
+Cornish
+cornmeal
+cornstalk
+cornstarch
+cornucopia
+Cornwall
+corolla
+corollary
+corona
+Coronado
+coronary
+coronate
+coroner
+coronet
+coroutine
+Corp.
+corpora
+corporal
+corporate
+corporeal
+corps
+corpse
+corpulent
+corpus
+corpuscle
+corpuscular
+corral
+correct
+correlate
+correspond
+correspondent
+corridor
+corrigenda
+corrigendum
+corrigible
+corroborate
+corroboree
+corrode
+corrodible
+corrosion
+corrugate
+corrupt
+corruptible
+corsage
+corsair
+corset
+Corsica
+cortege
+cortex
+cortical
+cortisone
+Cortland
+corundum
+coruscate
+corvette
+Corvus
+cos
+cosec
+cosecant
+coset
+Cosgrove
+cosh
+cosign
+cosignatory
+cosine
+cosmetic
+cosmetician
+cosmetology
+cosmic
+cosmography
+cosmology
+cosmonaut
+cosmopolitan
+cosmopolite
+cosmos
+cosponsor
+cossack
+cosset
+cost
+Costa
+costar
+Costello
+costume
+cosy
+cot
+cotangent
+coterie
+cotillion
+cotoneaster
+cotta
+cottage
+cotton
+cottonmouth
+cottonseed
+cottontail
+cottonwood
+Cottrell
+couch
+cougar
+cough
+could
+couldn't
+couloir
+coulomb
+Coulter
+council
+councillor
+counsel
+counselor
+count
+countdown
+countenance
+counterfeit
+countermand
+countervail
+countess
+countinghouse
+countrify
+country
+countryside
+countrywide
+county
+countywide
+coup
+coupe
+couple
+couplet
+coupon
+courage
+courageous
+courier
+course
+court
+courteous
+courtesan
+courtesy
+courthouse
+courtier
+Courtney
+courtroom
+courtyard
+couscous
+cousin
+couture
+couturier
+covalent
+covariant
+covary
+cove
+coven
+covenant
+cover
+coverage
+coverall
+coverlet
+covert
+coverup
+covet
+covetous
+cow
+Cowan
+coward
+cowardice
+cowbell
+cowbird
+cowboy
+cowcatcher
+cowgirl
+cowhand
+cowherd
+cowhide
+cowl
+cowlick
+coworker
+cowpea
+cowpoke
+cowpony
+cowpox
+cowpunch
+cowrie
+cowry
+cowslip
+cox
+coxcomb
+coxswain
+coy
+coyote
+coypu
+cozen
+cozy
+CPA
+CPI
+CPR
+crab
+crabapple
+crabgrass
+crabmeat
+crack
+crackbrain
+crackdown
+crackerjack
+crackle
+crackpot
+crackup
+cradle
+craft
+crafts
+craftspeople
+crag
+Craig
+cram
+Cramer
+cramp
+crampon
+cranberry
+Crandall
+crane
+cranelike
+Cranford
+crania
+cranial
+cranium
+crank
+crankcase
+crankshaft
+cranny
+Cranston
+crap
+crape
+crash
+crass
+crate
+cravat
+crave
+craven
+craw
+crawdad
+crawfish
+Crawford
+crawl
+crawlspace
+crayfish
+crayon
+craze
+creak
+cream
+creamery
+crease
+create
+creature
+creche
+credal
+credent
+credential
+credenza
+credible
+credit
+creditor
+credo
+credulity
+credulous
+creed
+creedal
+creek
+creekside
+creel
+creep
+creepage
+cremate
+crematorium
+crematory
+crenelate
+crenellate
+creole
+Creon
+creosote
+crepe
+crepitate
+crept
+crepuscular
+crescendo
+crescent
+cress
+Cressida
+crest
+crestfallen
+Crestview
+Cretaceous
+Cretan
+Crete
+cretin
+cretinous
+crevasse
+crevice
+crew
+crewcut
+crewel
+crib
+cribbage
+crick
+cricket
+cried
+crime
+Crimea
+criminal
+criminology
+crimp
+crimson
+cringe
+cringle
+crinkle
+crinkly
+crinoid
+crinoline
+cripple
+crises
+crisis
+crisp
+Crispin
+criss
+crisscross
+criteria
+criterion
+critic
+critique
+critter
+croak
+Croatia
+crochet
+crock
+crockery
+Crockett
+crocodile
+crocodilian
+crocus
+croft
+croissant
+Croix
+Cromwell
+crone
+crook
+crookneck
+croon
+crop
+cropland
+croquet
+croquette
+Crosby
+crosier
+cross
+crossarm
+crossbar
+crossbill
+crossbones
+crossbow
+crossbred
+crossbreed
+crosscurrent
+crosscut
+crosshatch
+crosslink
+crossover
+crosspatch
+crosspoint
+crossroad
+crossruff
+crosstalk
+crosstown
+crosstree
+crosswalk
+crossway
+crosswind
+crosswise
+crossword
+crotch
+crotchet
+crouch
+croup
+crouton
+crow
+crowbar
+crowd
+Crowe
+crowfoot
+Crowley
+crown
+crozier
+CRT
+crucial
+crucible
+crucifix
+crucifixion
+cruciform
+crucify
+crud
+crude
+cruel
+cruelty
+cruet
+Cruickshank
+cruise
+cruller
+crumb
+crumble
+crummy
+crump
+crumpet
+crumple
+crunch
+crupper
+crusade
+crush
+Crusoe
+crust
+crustacean
+crustal
+crutch
+crux
+Cruz
+cry
+cryogen
+cryogenic
+cryostat
+crypt
+cryptanalysis
+cryptanalyst
+cryptanalytic
+cryptanalyze
+cryptic
+crypto
+cryptograph
+cryptography
+cryptology
+crystal
+crystalline
+crystallite
+crystallize
+crystallography
+c's
+CSPAN
+CT
+cub
+Cuba
+cubbyhole
+cube
+cubic
+cubicle
+cubicly
+cubit
+cuboid
+cuckold
+cuckoldry
+cuckoo
+cucumber
+cud
+cuddle
+cuddlesome
+cuddly
+cudgel
+cue
+cuesta
+cuff
+cufflink
+cuirass
+cuisine
+Culbertson
+culex
+culinary
+cull
+cullet
+culm
+culminate
+culotte
+culpa
+culpable
+culprit
+cult
+cultivable
+cultivar
+cultivate
+cultural
+culture
+Culver
+culvert
+cumber
+Cumberland
+cumbersome
+cumin
+cummerbund
+Cummings
+Cummins
+cumquat
+cumulate
+cumulostratus
+cumulus
+Cunard
+cuneiform
+cunnilingus
+cunning
+Cunningham
+CUNY
+cup
+cupboard
+cupcake
+Cupid
+cupidity
+cupola
+cupric
+cuprous
+cur
+curacy
+curare
+curate
+curatorial
+curb
+curbside
+curbstone
+curd
+curdle
+cure
+curettage
+curette
+curfew
+curia
+curie
+curio
+curiosa
+curiosity
+curious
+curium
+curl
+curlew
+curlicue
+curmudgeon
+Curran
+currant
+current
+curricula
+curricular
+curriculum
+curry
+curse
+cursive
+cursor
+curt
+curtail
+curtain
+Curtis
+curtsey
+curtsy
+curvaceous
+curvacious
+curvature
+curve
+curvilinear
+Cushing
+cushion
+Cushman
+cushy
+cusp
+cuspidor
+cuss
+custard
+Custer
+custodial
+custodian
+custody
+custom
+customary
+customhouse
+cut
+cutaneous
+cutaway
+cutback
+cute
+cutesy
+cuticle
+cutlass
+cutler
+cutlery
+cutlet
+cutoff
+cutout
+cutpurse
+cutthroat
+cuttlebone
+cuttlefish
+cutup
+cutworm
+cyan
+Cyanamid
+cyanate
+cyanic
+cyanide
+cybernetic
+cybernetics
+cyberpunk
+cycad
+Cyclades
+cyclamen
+cycle
+cyclic
+cyclist
+cycloid
+cyclone
+cyclopean
+cyclops
+cyclorama
+cyclotron
+cygnet
+Cygnus
+cylinder
+cylindric
+cymbal
+cynic
+Cynthia
+cypress
+Cyprian
+Cypriot
+Cyprus
+Cyril
+Cyrillic
+Cyrus
+cyst
+cystic
+cytochemistry
+cytochrome
+cytogenetic
+cytology
+cytolysis
+cytoplasm
+cytoplasmic
+cytoplast
+cytosine
+czar
+czarina
+czarism
+czarist
+Czech
+Czechoslovakia
+Czechs
+dab
+dabble
+Dacca
+dacha
+dachshund
+Dacron
+dactyl
+dactylic
+dad
+dada
+Dadaism
+Dadaist
+daddy
+Dade
+dado
+dadoes
+Daedalus
+d'affaires
+daffodil
+daffy
+daft
+dageurreotype
+dagger
+daguerreotype
+Daguerrotype
+Dahl
+dahlia
+Dahomey
+Dailey
+daily
+Daimler
+dainty
+daiquiri
+dairy
+Dairylea
+dairymaid
+dais
+daisy
+Dakar
+Dakota
+dale
+Daley
+Dallas
+dalliance
+dally
+dalmatian
+Dalton
+Daly
+Dalzell
+dam
+damage
+Damascus
+damask
+dame
+damn
+damnation
+Damocles
+Damon
+damp
+dampen
+dampish
+damsel
+Dan
+Dana
+Danbury
+dance
+dandelion
+dander
+dandify
+dandle
+dandruff
+dandy
+Dane
+dang
+danger
+dangerous
+dangle
+Daniel
+Danielson
+Danish
+dank
+Danny
+danseuse
+Dante
+Danube
+Danubian
+Danzig
+Daphne
+dapper
+dapple
+Dar
+dare
+daredevil
+Darius
+Darjeeling
+dark
+darken
+darkish
+darkle
+darkroom
+Darlene
+darling
+darn
+Darrell
+Darren
+Darryl
+d'art
+dart
+Dartmouth
+Darwin
+Darwinian
+Daryl
+dash
+dashboard
+dastard
+data
+database
+date
+dateline
+Datsun
+datum
+daub
+Daugherty
+daughter
+daunt
+dauphin
+dauphine
+Dave
+davenport
+David
+Davidson
+Davies
+Davis
+Davison
+davit
+Davy
+dawdle
+dawn
+Dawson
+day
+daybed
+daybreak
+daydream
+daylight
+daytime
+Dayton
+Daytona
+daze
+dazzle
+DC
+DDT
+de
+deacon
+deaconess
+deactivate
+dead
+deadbeat
+deaden
+deadeye
+deadfall
+deadhead
+deadline
+deadlock
+deadpan
+deadweight
+deadwood
+deaf
+deafen
+deal
+deallocate
+dealt
+dean
+Deane
+deanery
+Deanna
+dear
+Dearborn
+dearie
+dearth
+deasil
+death
+deathbed
+deathward
+deathwatch
+debacle
+debar
+debark
+debarkation
+debase
+debate
+debauch
+debauchery
+Debbie
+Debby
+debenture
+debilitate
+debility
+debit
+deblur
+debonair
+Deborah
+Debra
+debrief
+debris
+debt
+debtor
+debug
+debunk
+Debussy
+debut
+debutant
+debutante
+Dec.
+decade
+decadent
+decaffeinate
+decagon
+decagonal
+decal
+decalcify
+decalogue
+decamp
+decant
+decapitate
+decapod
+decarbonate
+decarbonize
+decathlon
+Decatur
+decay
+Decca
+decease
+decedent
+deceit
+deceive
+decelerate
+December
+decennial
+decennium
+decent
+decentralize
+deception
+decertify
+decibel
+decide
+deciduous
+decile
+deciliter
+decimal
+decimate
+decimeter
+decipher
+decision
+decisional
+deck
+Decker
+deckhand
+deckhouse
+declaim
+declamation
+declamatory
+declaration
+declarator
+declare
+declassify
+declaw
+declension
+declinable
+declinate
+decline
+declivity
+decoct
+decode
+decollate
+decolletage
+decollimate
+decolonize
+decolorize
+decommission
+decommit
+decompile
+decompose
+decomposition
+decompress
+decompression
+decompressor
+decongestant
+deconstruct
+decontaminate
+decontrol
+deconvolution
+deconvolve
+decor
+decorate
+decorous
+decorticate
+decorum
+decouple
+decoy
+decrease
+decree
+decrement
+decrepit
+decrepitude
+decrescendo
+decriminalize
+decry
+decrypt
+dedicate
+dedifferentiate
+deduce
+deducible
+deduct
+deductible
+Dee
+deed
+deem
+deemphasize
+deep
+deepen
+deer
+Deere
+deerfly
+deerhound
+deerskin
+deerstalker
+deface
+defalcate
+defamation
+defamatory
+defame
+defang
+default
+defeat
+defecate
+defect
+defend
+defendant
+defenestrate
+defense
+defensible
+defensive
+defer
+deferent
+deferential
+deferral
+defiant
+deficient
+deficit
+defile
+define
+definiendum
+definiens
+definite
+definition
+deflate
+deflationary
+deflect
+deflower
+defocus
+defog
+defoliant
+defoliate
+deforest
+deforestation
+deform
+deformation
+defraud
+defray
+defrayal
+defrock
+defrost
+deft
+defunct
+defuse
+defy
+degas
+degauss
+degeneracy
+degenerate
+degradation
+degrade
+degrease
+degree
+degum
+dehiscent
+dehumanize
+dehumidify
+dehydrate
+dehydrogenate
+deice
+deify
+deign
+deinstitute
+deionize
+Deirdre
+deism
+deist
+deistic
+deity
+deja
+deject
+Del
+delaminate
+Delaney
+Delano
+Delaware
+delay
+Delbert
+Delco
+delectable
+delectate
+delegable
+delegacy
+delegate
+delete
+deleterious
+deletion
+delft
+Delgado
+Delhi
+deli
+Delia
+deliberate
+delicacy
+delicate
+delicatessen
+delicious
+delicti
+delight
+delightsome
+Delilah
+delimit
+delimitation
+delineament
+delineate
+delinquent
+deliquesce
+deliquescent
+delirious
+delirium
+delist
+deliver
+deliverance
+delivery
+dell
+Della
+Delmarva
+Delores
+delouse
+Delphi
+Delphic
+delphinium
+Delphinus
+delta
+deltoid
+delude
+deluge
+delusion
+delusory
+deluxe
+delve
+demagnetize
+demagnify
+demagogic
+demagogue
+demagoguery
+demagogy
+demand
+demarcate
+demark
+demarkation
+deme
+demean
+demeanor
+demented
+dementia
+demerit
+demigod
+demijohn
+demilitarize
+demimonde
+demineralize
+demiscible
+demise
+demission
+demit
+demitasse
+demiurge
+demo
+demobilize
+democracy
+democrat
+democratic
+demodulate
+demography
+demolish
+demolition
+demon
+demonetize
+demoniac
+demoniacal
+demonic
+demonology
+demonstrable
+demonstrate
+demoralize
+demote
+demotion
+demount
+demountable
+Dempsey
+demultiplex
+demur
+demure
+demurral
+demystify
+demythologize
+den
+denationalize
+denaturalize
+denature
+dendrite
+dendrochronology
+dendrology
+Deneb
+Denebola
+deniable
+denial
+denigrate
+denim
+Denise
+denitrify
+denizen
+Denmark
+Dennis
+Denny
+denominate
+denormalize
+denotation
+denote
+denouement
+denounce
+dense
+densitometer
+dent
+dental
+dentate
+dentistry
+dentition
+Denton
+dentrifice
+denture
+denuclearize
+denudation
+denude
+denumerable
+denunciation
+denunciatory
+Denver
+deny
+deodorant
+deodorize
+deoxidize
+deoxyribonucleic
+depart
+department
+departure
+depend
+dependent
+depersonalize
+depict
+depilate
+depilatory
+deplane
+deplete
+depletion
+deplore
+deploy
+depolarize
+depopulate
+deport
+deportation
+deportee
+depose
+deposit
+depositary
+deposition
+depositor
+depot
+deprave
+depravity
+deprecate
+depreciable
+depreciate
+depredate
+depress
+depressant
+depressible
+depression
+depressor
+depressurize
+deprivation
+deprive
+Dept.
+depth
+deputation
+depute
+deputy
+deracinate
+derail
+derange
+derate
+derby
+Derbyshire
+dereference
+deregulate
+Derek
+derelict
+deride
+derision
+derisory
+derivate
+derive
+dermatitis
+dermatology
+derogate
+derrick
+derriere
+dervish
+Des
+desalinate
+desalt
+descant
+Descartes
+descend
+descendant
+descendent
+descent
+describe
+description
+descriptor
+descry
+Desdemona
+desecrate
+desegregate
+desensitize
+desert
+desertify
+deserve
+desex
+deshabille
+desiccant
+desiccate
+desiderata
+desideratum
+design
+designate
+designee
+desire
+desirous
+desist
+desk
+desktop
+Desmond
+desolate
+desorption
+despair
+despatch
+desperado
+desperadoes
+desperate
+despicable
+despise
+despite
+despoil
+despoliation
+despond
+despondent
+despot
+despotic
+dessert
+destabilize
+desterilize
+destinate
+destine
+destiny
+destitute
+destroy
+destruct
+destructible
+desuetude
+desultory
+desynchronize
+detach
+detail
+detain
+detainee
+d'etat
+detect
+detent
+detente
+deter
+detergent
+deteriorate
+determinacy
+determinant
+determinate
+determine
+deterrent
+detest
+detestation
+dethrone
+detonable
+detonate
+detour
+detoxify
+detract
+d'etre
+detribalize
+detriment
+detrital
+detritus
+Detroit
+detune
+deuce
+deus
+deuterate
+deuterium
+deuteron
+Deuteronomy
+devaluate
+devalue
+devastate
+develop
+deviant
+deviate
+device
+devil
+devilish
+devilry
+deviltry
+devious
+devise
+devisee
+devitalize
+devitrify
+devoid
+devolution
+devolve
+Devon
+Devonshire
+devote
+devotee
+devotion
+devour
+devout
+dew
+dewar
+dewdrop
+Dewey
+Dewitt
+dewlap
+dexter
+dexterity
+dextral
+dextro
+dextrorotation
+dextrorotatory
+dextrose
+dextrous
+dey
+Dhabi
+dharma
+dhow
+diabase
+diabetes
+diabetic
+diabolic
+diabolism
+diabolist
+diachronic
+diacritical
+diadem
+diagnose
+diagnosis
+diagnostic
+diagnostician
+diagonal
+diagram
+diagrammatic
+dial
+dialect
+dialectic
+dialectician
+dialog
+dialogue
+dialyses
+dialysis
+dialytic
+dialyze
+diamagnetic
+diamagnetism
+diamegnetism
+diameter
+diametral
+diamine
+diamond
+diamondback
+Diana
+Diane
+diapason
+diaper
+diaphanous
+diaphoresis
+diaphragm
+diarist
+diarrhea
+diary
+diaspora
+diastolic
+diathermic
+diathermy
+diatom
+diatomaceous
+diatomic
+diatonic
+diatribe
+Diaz
+diazo
+dib
+dibasic
+dibble
+dibs
+dice
+dichloride
+dichotomize
+dichotomous
+dichotomy
+dick
+dickcissel
+dickens
+Dickensian
+Dickerson
+dickey
+Dickinson
+Dickson
+dicky
+dicot
+dicotyledon
+dicta
+dictate
+dictatorial
+diction
+dictionary
+dictum
+did
+didactic
+diddle
+didn't
+Dido
+didst
+die
+Diebold
+Diego
+diehard
+dieldrin
+dielectric
+diem
+dieresis
+diesel
+diet
+dietary
+dietetic
+diethylstilbestrol
+dietician
+dietitian
+Dietrich
+Dietz
+differ
+different
+differentiable
+differential
+differentiate
+difficult
+difficulty
+diffident
+diffract
+diffractometer
+diffuse
+diffusible
+diffusion
+difluoride
+dig
+digest
+digestible
+digestion
+digit
+digital
+digitalis
+digitate
+dignify
+dignitary
+dignity
+digram
+digraph
+digress
+digression
+dihedral
+dike
+dilapidate
+dilatant
+dilatation
+dilate
+dilemma
+dilettante
+dilettantish
+dilettantism
+diligent
+dill
+Dillon
+dilly
+dilogarithm
+diluent
+dilute
+dim
+dime
+dimension
+dimeric
+dimethyl
+diminish
+diminuendo
+diminution
+dimple
+dimply
+dimwit
+din
+Dinah
+dinar
+dine
+dinette
+ding
+dingbat
+dingdong
+dinghy
+dingo
+dingoes
+dinky
+dinnertime
+dinnerware
+dinosaur
+dinosaurian
+dint
+diocesan
+diocese
+diode
+Dionysiac
+Dionysian
+Dionysus
+Diophantine
+diopter
+diorama
+dioxide
+dioxin
+dip
+diphenyl
+diphtheria
+diphthong
+diploid
+diploidy
+diploma
+diplomacy
+diplomat
+diplomatic
+dipole
+dipsomania
+dipstick
+diptych
+Dirac
+dire
+direct
+directorate
+directorial
+directory
+directrices
+directrix
+dirge
+Dirichlet
+dirigible
+dirk
+dirt
+dirty
+Dis
+disambiguate
+disastrous
+disburse
+disc
+discern
+discernible
+disciple
+disciplinarian
+disciplinary
+discipline
+disco
+discography
+discoid
+discombobulate
+discomfit
+discomfiture
+discommode
+disconsolate
+discordant
+discotheque
+discovery
+discreet
+discrepant
+discrete
+discretion
+discretionary
+discriminable
+discriminant
+discriminate
+discus
+discuss
+discussant
+discussion
+disdain
+disembowel
+disgruntle
+dish
+dishcloth
+dishes
+dishevel
+dishrag
+dishwasher
+dishwater
+disinfectant
+disjunct
+disk
+dismal
+dismay
+dismissal
+Disney
+Disneyland
+disorganize
+disparage
+disparate
+disparity
+dispel
+dispensary
+dispensate
+dispense
+dispersal
+dispersant
+disperse
+dispersible
+dispersion
+dispirit
+disposal
+disputant
+disputation
+disputatious
+dispute
+disquietude
+disquisition
+disrupt
+dissemble
+disseminate
+dissension
+dissertation
+dissident
+dissipate
+dissociable
+dissociate
+dissonant
+dissuade
+dissuasion
+distaff
+distal
+distant
+distensible
+distention
+distill
+distillate
+distillery
+distills
+distinct
+distinguish
+distort
+distortion
+distraught
+distribution
+distributor
+district
+disturb
+disturbance
+disulfide
+disyllabic
+disyllable
+ditch
+dither
+ditto
+ditty
+Ditzel
+diuretic
+diurnal
+diva
+divalent
+divan
+dive
+diverge
+divergent
+diverse
+diversify
+diversion
+diversionary
+divert
+diverticulitis
+diverticulosis
+divertimento
+divertissement
+divest
+divestiture
+divide
+dividend
+divination
+divine
+divisible
+division
+divisional
+divisor
+divorce
+divorcee
+divot
+divulge
+divulgence
+divvy
+Dixie
+Dixieland
+Dixon
+dizzy
+DJ
+Djakarta
+djinn
+djinni
+Dmitry
+DNA
+Dnieper
+do
+DOA
+doable
+dobbin
+Dobbs
+dobson
+Doc
+docile
+dock
+docket
+dockhand
+dockside
+dockyard
+doctor
+doctoral
+doctorate
+doctrinaire
+doctrinal
+doctrine
+document
+documentary
+documentation
+DOD
+Dodd
+dodder
+dodecahedra
+dodecahedral
+dodecahedron
+dodge
+dodo
+dodoes
+Dodson
+doe
+doesn't
+doeth
+d'oeuvre
+doff
+dog
+dogcart
+dogcatcher
+doge
+dogface
+dogfight
+dogfish
+doggerel
+doggone
+doghouse
+dogleg
+dogma
+dogmatic
+dogmatism
+dogmatist
+dogmatize
+dogtooth
+dogtrot
+dogwood
+Doherty
+doily
+Dolan
+dolce
+doldrums
+dole
+dolichocephalic
+doll
+dollar
+dollop
+dolly
+dolomite
+dolor
+Dolores
+dolorous
+dolphin
+dolt
+doltish
+domain
+dome
+Domenico
+Domesday
+domestic
+domesticate
+domicile
+domiciliary
+dominant
+dominate
+domineer
+Domingo
+Dominic
+dominical
+Dominican
+Dominick
+dominion
+Dominique
+domino
+dominoes
+don
+Donahue
+Donald
+Donaldson
+donate
+done
+Doneck
+donkey
+Donna
+Donnelly
+Donner
+Donnie
+donnish
+donnybrook
+donor
+Donovan
+don't
+doodad
+doodle
+Dooley
+Doolittle
+doom
+doomsday
+door
+doorbell
+doorknob
+doormat
+doorstep
+doorway
+dooryard
+dopant
+dope
+dopester
+dopey
+dopier
+dopiest
+Doppler
+Dora
+Dorado
+Dorcas
+Dorchester
+Doreen
+Doria
+Doric
+Doris
+dorm
+dormant
+dormitory
+Dorothea
+Dorothy
+dorsal
+Dorset
+Dorsey
+dory
+dosage
+dose
+dosimeter
+dossier
+Dostoevsky
+dot
+dotage
+dotard
+dote
+doth
+Dottie
+double
+Doubleday
+doubleheader
+doublet
+doubleton
+doubloon
+doubt
+douce
+douche
+Doug
+dough
+doughboy
+Dougherty
+doughnut
+doughty
+Douglas
+Douglass
+dour
+douse
+dove
+dovecote
+dovekie
+dovetail
+dovish
+Dow
+dowager
+dowdy
+dowel
+dower
+dowitcher
+Dowling
+down
+downbeat
+downcast
+downdraft
+Downey
+downfall
+downfallen
+downgrade
+downhaul
+downhearted
+downhill
+Downing
+downplay
+downpour
+downrange
+downright
+downriver
+downside
+downsize
+downslope
+downspout
+downstage
+downstairs
+downstate
+downstream
+downstroke
+downswing
+downtime
+downtown
+downtrend
+downtrodden
+downturn
+downward
+downwind
+dowry
+dowse
+doxology
+doxy
+doyenne
+Doyle
+doze
+dozen
+dozenth
+Dr.
+drab
+drably
+drachma
+Draco
+draconian
+draft
+draftee
+drafts
+drag
+draggle
+draggly
+dragline
+dragnet
+dragon
+dragonfly
+dragonhead
+dragoon
+drain
+drainage
+drainpipe
+drake
+dram
+drama
+dramatic
+dramatist
+dramatize
+dramaturgic
+dramaturgy
+drank
+drape
+drapery
+drastic
+draw
+drawback
+drawbar
+drawbridge
+drawknife
+drawl
+drawn
+drawstring
+dray
+dread
+dreadnought
+dream
+dreamboat
+dreamland
+dreamlike
+dreamt
+dreamworld
+drear
+dreary
+dredge
+dreg
+drench
+dress
+dressage
+drew
+Drexel
+Dreyfuss
+drib
+dribble
+driblet
+dried
+drier
+drift
+driftwood
+drill
+drillmaster
+drink
+drip
+Driscoll
+drive
+drivel
+driven
+driveway
+drizzle
+drizzly
+drogue
+droll
+drollery
+drolly
+dromedary
+drone
+drool
+droop
+drop
+drophead
+dropkick
+droplet
+dropout
+dropsy
+drosophila
+dross
+drought
+drove
+drown
+drowse
+drub
+drudge
+drudgery
+drug
+druggist
+drugstore
+druid
+druidic
+drum
+drumbeat
+drumhead
+drumlin
+Drummond
+drumstick
+drunk
+drunkard
+drunken
+drunkometer
+Drury
+dry
+dryad
+Dryden
+drypoint
+drywall
+d's
+dual
+dualism
+Duane
+dub
+Dubhe
+dubiety
+dubious
+dubitable
+Dublin
+Dubliner
+ducal
+ducat
+duce
+duchess
+duchy
+duck
+duckbill
+duckling
+duckpin
+duckweed
+duct
+ductile
+ductwork
+dud
+dude
+dudgeon
+Dudley
+due
+duel
+dueness
+duenna
+duet
+duff
+duffel
+duffle
+Duffy
+dug
+Dugan
+dugong
+dugout
+duke
+dukedom
+dulcet
+dulcimer
+dull
+dullard
+dullish
+dully
+dulse
+Duluth
+duly
+Duma
+dumb
+dumbbell
+dumbfound
+dumbly
+dumbstruck
+dumbwaiter
+dumdum
+dumfound
+dummy
+dump
+dumpish
+dumpling
+dumpster
+Dumpty
+dun
+Dunbar
+Duncan
+dunce
+dunderhead
+dune
+Dunedin
+dung
+dungaree
+dungeon
+dunghill
+Dunham
+dunk
+Dunkirk
+Dunlap
+Dunlop
+Dunn
+dunnage
+duo
+duodecimal
+duodenal
+duodenum
+duopolist
+duopoly
+dupe
+duple
+duplex
+duplicable
+duplicate
+duplicity
+DuPont
+durable
+Durango
+duration
+Durer
+duress
+Durham
+during
+Durkee
+Durkin
+Durrell
+Durward
+Dusenberg
+Dusenbury
+dusk
+Dusseldorf
+dust
+dustbin
+dustpan
+dustup
+Dutch
+dutiable
+Dutton
+duty
+Dvorak
+dwarf
+dwarfish
+dwarves
+Dwayne
+dwell
+dwelt
+Dwight
+dwindle
+Dwyer
+dyad
+dyadic
+dye
+dyeing
+dyer
+dyestuff
+dying
+Dyke
+Dylan
+dynamic
+dynamism
+dynamite
+dynamo
+dynamometer
+dynast
+dynastic
+dynasty
+dyne
+Dynel
+dysentery
+dysfunction
+dysgenic
+dyslexia
+dyslexic
+dyspepsia
+dyspeptic
+dysplasia
+dysprosium
+dystrophy
+each
+Eagan
+eager
+eagle
+eaglet
+ear
+earache
+eardrum
+earl
+earlobe
+early
+earmark
+earmuff
+earn
+earnest
+earphone
+earring
+earshot
+earth
+earthbound
+earthen
+earthenware
+earthling
+earthmen
+earthmove
+earthquake
+earthshaking
+earthshine
+earthwork
+earthworm
+earwig
+ease
+easel
+east
+eastbound
+eastern
+easternmost
+Eastland
+Eastman
+eastmost
+eastward
+Eastwood
+easygoing
+eat
+eaten
+eatery
+Eaton
+eave
+eavesdrop
+ebb
+Eben
+ebony
+ebullient
+ebullition
+EC
+eccentric
+Eccles
+Ecclesiastes
+ecclesiastic
+ecdysiast
+ecdysis
+echelon
+echidna
+echinoderm
+echo
+echoes
+eclat
+eclectic
+eclipse
+ecliptic
+eclogue
+Ecole
+ecology
+econometric
+Econometrica
+economics
+economist
+economize
+economy
+ecosystem
+ecstasy
+ecstatic
+ectomorph
+ectomorphic
+ectoplasm
+ectothermic
+ecu
+Ecuador
+ecumenic
+ecumenical
+ecumenist
+eczema
+Ed
+Eddie
+eddy
+edelweiss
+edema
+edematous
+Eden
+edentate
+Edgar
+edge
+Edgerton
+edgeways
+edgewise
+edging
+edible
+edict
+edifice
+edify
+Edinburgh
+Edison
+edit
+Edith
+edition
+editor
+editorial
+Edmonds
+Edmondson
+Edmonton
+Edmund
+Edna
+EDT
+educable
+educate
+educe
+educible
+Edward
+Edwardian
+Edwards
+Edwin
+Edwina
+EEG
+eel
+eelgrass
+EEOC
+e'er
+eerie
+eerily
+eeriness
+efface
+effaceable
+effect
+effectual
+effectuate
+effeminacy
+effeminate
+effendi
+efferent
+effervesce
+effervescent
+effete
+efficacious
+efficacity
+efficacy
+efficient
+Effie
+effigy
+effloresce
+efflorescent
+effluent
+effluvia
+effluvium
+efflux
+effort
+effrontery
+effulgent
+effuse
+effusion
+eft
+EFTA
+e.g.
+egad
+egalitarian
+Egan
+egg
+egghead
+eggnog
+eggplant
+eggshell
+ego
+egocentric
+egomania
+egotism
+egotist
+egregious
+egress
+egret
+Egypt
+Egyptian
+Egyptology
+eh
+Ehrlich
+eider
+eiderdown
+eidetic
+Eiffel
+eigenfunction
+eigenstate
+eigenvalue
+eigenvector
+eight
+eighteen
+eighteenth
+eightfold
+eighth
+eightieth
+eighty
+Eileen
+Einstein
+Einsteinian
+einsteinium
+Eire
+Eisenhower
+Eisner
+either
+ejaculate
+eject
+ejecta
+eke
+Ekstrom
+Ektachrome
+elaborate
+Elaine
+elan
+elapse
+elastic
+elastomer
+elastomeric
+elate
+Elba
+Elbert
+elbow
+elder
+elderberry
+eldest
+Eldon
+Eleanor
+Eleazar
+elect
+electioneer
+electoral
+electorate
+Electra
+electress
+electret
+electric
+electrician
+electrify
+electro
+electrocute
+electrode
+electrography
+electrolysis
+electrolyte
+electrolytic
+electrolyze
+electron
+electronic
+electrophoresis
+electrophorus
+electrum
+eleemosynary
+elegant
+elegiac
+elegy
+element
+elementary
+Elena
+elephant
+elephantiasis
+elephantine
+elevate
+eleven
+eleventh
+elf
+elfin
+elfish
+Elgin
+Eli
+Elias
+elicit
+elide
+eligible
+Elijah
+eliminate
+Elinor
+Eliot
+Elisabeth
+Elisha
+elision
+elite
+elixir
+Elizabeth
+Elizabethan
+elk
+Elkhart
+elkhound
+Ella
+Ellen
+Elliott
+ellipse
+ellipsis
+ellipsoid
+ellipsometer
+elliptic
+Ellis
+Ellison
+Ellsworth
+Ellwood
+elm
+Elmer
+Elmhurst
+Elmira
+Elmsford
+elocution
+elocutionary
+Eloise
+elongate
+elope
+eloquent
+Elsa
+else
+Elsevier
+elsewhere
+Elsie
+Elsinore
+Elton
+eluate
+elucidate
+elude
+elusive
+elute
+elver
+elves
+Elvis
+elvish
+Ely
+Elysee
+elysian
+em
+emaciate
+emanate
+emancipate
+Emanuel
+emasculate
+embalm
+embank
+embarcadero
+embargo
+embargoes
+embark
+embarkation
+embarrass
+embassy
+embattle
+embayment
+embed
+embellish
+ember
+embezzle
+embitter
+emblazon
+emblem
+emblematic
+embodiment
+embody
+embolden
+embolism
+emboss
+embouchure
+embrace
+embraceable
+embrasure
+embrittle
+embrocate
+embroider
+embroidery
+embroil
+embryo
+embryology
+embryonic
+emcee
+emend
+emendable
+emendation
+emerald
+emerge
+emergent
+emeritus
+emersed
+emersion
+Emerson
+emery
+emetic
+emigrant
+emigrate
+emigre
+Emil
+Emile
+Emilio
+Emily
+eminent
+emir
+emirate
+emissary
+emission
+emissivity
+emit
+emittance
+Emma
+Emmanuel
+Emmett
+emollient
+emolument
+Emory
+emote
+emotion
+emotional
+empathetic
+empathic
+empathy
+emperor
+emphases
+emphasis
+emphasize
+emphatic
+emphysema
+emphysematous
+empire
+empiric
+emplace
+emplane
+employ
+employed
+employee
+employer
+employing
+emporia
+emporium
+empower
+empress
+emptor
+empty
+emu
+emulate
+emulsify
+emulsion
+en
+enable
+enact
+enamel
+enamelware
+enamor
+enantiomorph
+enantiomorphic
+encage
+encamp
+encapsulate
+encase
+encaustic
+encephalic
+encephalitis
+encephalograph
+encephalography
+enchain
+enchant
+enchantress
+enchilada
+encipher
+encircle
+enclave
+enclose
+enclosure
+encode
+encomia
+encomium
+encompass
+encore
+encounter
+encourage
+encroach
+encrust
+encrypt
+encumber
+encumbrance
+encyclical
+encyclopedia
+encyclopedic
+encyclopedist
+encyst
+end
+endanger
+endear
+endearment
+endeavor
+endemic
+endemism
+endgame
+Endicott
+endive
+endmost
+endocrine
+endogamous
+endogamy
+endogenous
+endomorph
+endomorphic
+endoplasm
+endorse
+endorsee
+endoskeleton
+endosperm
+endothelial
+endothermal
+endothermic
+endow
+endpaper
+endpoint
+endue
+endurance
+endure
+endways
+endwise
+ENE
+enema
+enemy
+energetic
+energize
+energy
+enervate
+enfant
+enfeeble
+Enfield
+enfilade
+enfold
+enforce
+enforceable
+enfranchise
+Eng.
+engage
+Engel
+engender
+engine
+engineer
+engirdle
+England
+Englander
+Engle
+Englewood
+English
+engorge
+engram
+engrave
+engross
+engulf
+enhance
+enharmonic
+Enid
+enigma
+enigmatic
+enjoin
+enjoinder
+enjoy
+enlarge
+enlargeable
+enlighten
+enlist
+enlistee
+enliven
+enmesh
+enmity
+ennoble
+ennui
+Enoch
+enormity
+enormous
+Enos
+enough
+enounce
+enplane
+enquire
+Enquirer
+enquiry
+enrage
+enrapt
+enrapture
+enrich
+Enrico
+enrobe
+enroll
+enrollee
+ensconce
+ensemble
+enshrine
+enshroud
+ensign
+ensilage
+enslave
+ensnare
+ensoul
+ensue
+ensuite
+ensure
+entablature
+entail
+entangle
+entendre
+entente
+enter
+enteric
+enterprise
+entertain
+enthalpy
+enthrall
+enthrone
+enthuse
+enthusiasm
+enthusiast
+enthusiastic
+entice
+entire
+entirety
+entitle
+entity
+entomb
+entomology
+entourage
+entrails
+entrain
+entrance
+entranceway
+entrant
+entrap
+entreat
+entreaty
+entree
+entrench
+entrepreneur
+entrepreneurial
+entropy
+entrust
+entry
+entryway
+entwine
+entwist
+enumerable
+enumerate
+enunciable
+enunciate
+envelop
+envelope
+enviable
+envious
+environ
+envisage
+envision
+envoi
+envoy
+envy
+enzymatic
+enzyme
+enzymology
+Eocene
+eohippus
+eon
+eosine
+EPA
+epaulet
+epaulette
+ephemera
+ephemeral
+ephemerides
+ephemeris
+Ephesian
+Ephesus
+Ephraim
+epic
+epicene
+epicenter
+epicure
+epicurean
+epicycle
+epicyclic
+epicycloid
+epidemic
+epidemiology
+epidermal
+epidermic
+epidermis
+epigenetic
+epiglottal
+epiglottis
+epigram
+epigrammatic
+epigraph
+epigraphy
+epilepsy
+epileptic
+epilogue
+epiphany
+epiphenomenal
+epiphenomenon
+epiphyseal
+epiphysis
+epiphyte
+epiphytic
+episcopacy
+episcopal
+Episcopalian
+episcopate
+episode
+episodic
+epistemic
+epistemology
+epistle
+epistolary
+epitaph
+epitaxial
+epitaxy
+epithelial
+epithelium
+epithet
+epitome
+epizootic
+epoch
+epochal
+epochs
+eponym
+eponymic
+eponymous
+eponymy
+epoxy
+epsilon
+Epsom
+Epstein
+equable
+equal
+equalitarian
+equanimity
+equate
+equatorial
+equerry
+equestrian
+equiangular
+equidistant
+equidistribute
+equilateral
+equilibrate
+equilibria
+equilibrium
+equine
+equinoctial
+equinox
+equip
+equipage
+equipoise
+equipotent
+equipotential
+equiprobable
+equitable
+equitation
+equity
+equivalent
+equivocal
+equivocate
+era
+eradicable
+eradicate
+erase
+Erasmus
+Erastus
+erasure
+Erato
+Eratosthenes
+erbium
+ERDA
+ere
+erect
+erectile
+eremite
+erg
+ergo
+ergodic
+ergonomic
+ergot
+Eric
+Erica
+Erich
+Erickson
+Ericsson
+Erie
+Erlenmeyer
+Erma
+ermine
+Ernest
+Ernestine
+Ernie
+Ernst
+erode
+erodible
+Eros
+erosible
+erosion
+erotic
+erotica
+err
+errancy
+errand
+errant
+errantry
+errata
+erratic
+erratum
+Errol
+erroneous
+error
+ersatz
+Erskine
+erstwhile
+erudite
+erudition
+erupt
+Ervin
+Erwin
+e's
+escadrille
+escalate
+escapade
+escape
+escapee
+escargot
+escarole
+escarpment
+eschatology
+escheat
+eschew
+escort
+escritoire
+escrow
+escudo
+escutcheon
+ESE
+esker
+Eskimo
+Esmark
+esophageal
+esophagi
+esophagus
+esoteric
+esoterica
+ESP
+espalier
+especial
+Esperanto
+espial
+espionage
+esplanade
+ESPN
+Esposito
+espousal
+espouse
+espresso
+esprit
+espy
+Esq.
+esquire
+essay
+Essen
+essence
+Essene
+essential
+Essex
+EST
+establish
+estate
+esteem
+Estella
+Estelle
+ester
+esterase
+Estes
+Esther
+esthete
+esthetic
+estimable
+estimate
+estival
+estivate
+Estonia
+estop
+estoppal
+estrange
+estrogen
+estrogenic
+estrus
+estuarine
+estuary
+et
+eta
+etc
+etcetera
+etch
+eternal
+eternity
+Ethan
+ethane
+ethanol
+Ethel
+ether
+ethereal
+ethic
+Ethiopia
+ethnic
+ethnocentric
+ethnography
+ethnology
+ethology
+ethos
+ethyl
+ethylene
+etiology
+etiquette
+Etruscan
+ETS
+etude
+etymology
+eucalypt
+eucalyptus
+Eucharist
+eucharistic
+Euclid
+euclidean
+Eugene
+Eugenia
+eugenic
+Euler
+Eulerian
+eulogize
+eulogy
+Eumenides
+Eunice
+eunuch
+eunuchs
+euphemism
+euphemist
+euphemize
+euphonic
+euphonious
+euphonium
+euphony
+euphoria
+euphoric
+Euphrates
+Eurasia
+eureka
+Euridyce
+Euripides
+Europa
+Europe
+European
+europium
+Eurydice
+eustatic
+eutectic
+Euterpe
+euthanasia
+eutrophic
+eutrophy
+Eva
+evacuate
+evacuee
+evade
+evaluable
+evaluate
+evanescent
+evangel
+evangelic
+Evans
+Evanston
+Evansville
+evaporate
+evasion
+eve
+Evelyn
+even
+evenhanded
+evensong
+event
+eventide
+eventual
+eventuate
+ever
+Eveready
+Everest
+Everett
+Everglades
+evergreen
+Everhart
+everlasting
+evermore
+evert
+every
+everybody
+everyday
+everyman
+everyone
+everything
+everywhere
+evict
+evictor
+evident
+evidential
+evidentiary
+evil
+evildoer
+evildoing
+evince
+eviscerate
+evocable
+evocation
+evoke
+evolute
+evolutionary
+evolve
+evzone
+ewe
+Ewing
+ex
+exacerbate
+exact
+exactitude
+exactor
+exaggerate
+exalt
+exaltation
+exam
+examination
+examine
+examinee
+example
+exarch
+exasperate
+excavate
+exceed
+excel
+excellent
+excelsior
+except
+excerpt
+excess
+excessive
+exchange
+exchangeable
+exchequer
+excise
+excision
+excitation
+excitatory
+excite
+exciton
+exclaim
+exclamation
+exclamatory
+exclude
+excludible
+exclusion
+exclusionary
+excommunicate
+excoriate
+excrement
+excrescent
+excreta
+excretal
+excrete
+excretion
+excretory
+excruciate
+exculpate
+excursion
+excursus
+excuse
+exec
+execrable
+execrate
+execute
+executor
+executrix
+exegesis
+exegete
+exegetic
+exemplar
+exemplify
+exempt
+exercise
+exert
+Exeter
+exeunt
+exfoliate
+exhalation
+exhale
+exhaust
+exhaustible
+exhaustion
+exhibit
+exhibition
+exhibitor
+exhilarate
+exhort
+exhortation
+exhortatory
+exhumation
+exhume
+exigent
+exiguous
+exile
+exist
+existent
+existential
+exit
+exodus
+exogamous
+exogamy
+exogenous
+exonerate
+exorable
+exorbitant
+exorcise
+exorcism
+exorcist
+exoskeletal
+exoskeleton
+exothermic
+exotic
+exotica
+expand
+expanse
+expansible
+expansion
+expansionary
+expatiate
+expatriate
+expect
+expectant
+expectation
+expectorant
+expectorate
+expedient
+expedite
+expedition
+expeditionary
+expeditious
+expeditor
+expel
+expend
+expenditure
+expense
+expensive
+experience
+experiential
+experiment
+experimentation
+expert
+expertise
+expiable
+expiate
+expiration
+expire
+expiry
+explain
+explanation
+explanatory
+expletive
+explicable
+explicate
+explicit
+explode
+exploit
+exploitation
+exploration
+exploratory
+explore
+explosion
+exponent
+exponential
+exponentiate
+export
+exportation
+expose
+exposit
+exposition
+expositor
+expostulate
+exposure
+expound
+express
+expressible
+expression
+expressway
+expropriate
+expulsion
+expunge
+expurgate
+exquisite
+exsert
+extant
+extemporaneous
+extempore
+extend
+extendible
+extensible
+extensile
+extension
+extensometer
+extensor
+extent
+extenuate
+exterior
+exterminate
+external
+extinct
+extinguish
+extirpate
+extol
+extoll
+extort
+extortionate
+extra
+extracellular
+extract
+extracurricular
+extraditable
+extradite
+extradition
+extralegal
+extralinguistic
+extramarital
+extramural
+extraneous
+extraordinary
+extrapolate
+extrasensory
+extraterrestrial
+extraterritorial
+extravagant
+extravaganza
+extrema
+extremal
+extreme
+extremis
+extremum
+extricable
+extricate
+extrinsic
+extroversion
+extrovert
+extrude
+extrusion
+exuberant
+exuberate
+exudation
+exude
+exult
+exultant
+exultation
+exurb
+exurbanite
+exurbia
+Exxon
+eye
+eyeball
+eyebolt
+eyebright
+eyebrow
+eyedrop
+eyeglass
+eyeing
+eyelash
+eyelet
+eyelid
+eyepiece
+eyeshade
+eyeshot
+eyesight
+eyesore
+eyestrain
+eyewash
+eyewitness
+eyrie
+Ezekiel
+Ezra
+FAA
+Faber
+Fabian
+fable
+fabric
+fabricate
+fabulist
+fabulous
+facade
+face
+facedown
+faceplate
+facet
+facetious
+facial
+facies
+facile
+facilitate
+facsimile
+fact
+factious
+factitious
+facto
+factoid
+factor
+factorial
+factory
+factotum
+factual
+facula
+facultative
+faculty
+fad
+faddish
+fade
+fadeaway
+fadeout
+faery
+Fafnir
+fag
+faggot
+Fahey
+Fahrenheit
+faience
+fail
+failsafe
+failsoft
+failure
+fain
+faint
+fainthearted
+fair
+Fairchild
+Fairfax
+Fairfield
+fairgoer
+fairground
+fairish
+fairlead
+Fairport
+fairway
+fairy
+fairyland
+faith
+fajita
+fake
+fakery
+fakir
+falcon
+falconry
+fall
+fallacious
+fallacy
+fallback
+fallen
+fallible
+falloff
+fallout
+fallow
+Falmouth
+false
+falsehood
+falsetto
+falsie
+falsify
+Falstaff
+falter
+fame
+familial
+familiar
+familiarly
+family
+famine
+famish
+famous
+fan
+fanatic
+fancy
+fandango
+fanfare
+fanfold
+fang
+fangled
+fanlight
+Fannie
+Fanny
+fanout
+fantail
+fantasia
+fantasist
+fantasize
+fantasm
+fantastic
+fantasy
+fantod
+far
+farad
+faraday
+faraway
+Farber
+farce
+farceur
+farcical
+fare
+farewell
+farfetched
+Fargo
+farina
+farinaceous
+Farkas
+Farley
+farm
+farmhand
+farmhouse
+Farmington
+farmland
+farmstead
+farmyard
+Farnsworth
+faro
+farrago
+Farrell
+farrier
+Farris
+farrow
+Farsi
+farsighted
+farther
+farthermost
+farthest
+farthing
+fascia
+fascicle
+fasciculate
+fascinate
+fascism
+fascist
+fashion
+Faso
+fast
+fasten
+fastidious
+fat
+fatal
+fate
+father
+fatherland
+fathom
+fatigue
+Fatima
+fatten
+fattish
+fatuity
+fatuous
+faucet
+Faulkner
+fault
+faultfind
+faun
+fauna
+faunal
+Faust
+Faustian
+Faustus
+favor
+favorable
+favorite
+fawn
+fax
+fay
+Faye
+Fayette
+Fayetteville
+faze
+FBI
+FCC
+FDA
+Fe
+fealty
+fear
+fearsome
+feasible
+feast
+feat
+feather
+featherbed
+featherbrain
+featherhead
+featherweight
+feathery
+feature
+Feb.
+febrile
+February
+fecal
+feces
+feckless
+fecund
+fed
+Fedders
+federal
+federate
+fedora
+fee
+feeble
+feebleminded
+feed
+feedback
+feedstock
+feel
+Feeney
+feet
+feign
+feint
+feisty
+Feldman
+feldspar
+feldspathic
+Felice
+Felicia
+felicitate
+felicitous
+felicity
+feline
+Felix
+fell
+fellah
+fellatio
+fellow
+felon
+felonious
+felony
+felt
+felucca
+female
+feminine
+feminism
+feminist
+feminize
+femur
+fen
+fence
+fencepost
+fend
+fenestrate
+fennel
+Fenton
+fenugreek
+feral
+Ferber
+Ferdinand
+Ferguson
+Fermat
+fermata
+ferment
+fermentation
+Fermi
+fermion
+fermium
+fern
+Fernando
+fernery
+ferocious
+ferocity
+Ferrell
+Ferrer
+ferret
+ferric
+ferris
+ferrite
+ferroelectric
+ferromagnet
+ferromagnetic
+ferromagnetism
+ferrous
+ferruginous
+ferrule
+ferry
+ferryboat
+fertile
+fervent
+fervid
+fervor
+fescue
+fest
+festal
+festival
+festive
+festoon
+festschrift
+feta
+fetal
+fetch
+fete
+fetid
+fetish
+fetlock
+fetter
+fettle
+fetus
+feud
+feudal
+feudatory
+fever
+feverish
+few
+fey
+fez
+fiance
+fiancee
+fiasco
+fiat
+fib
+fiber
+fiberboard
+Fiberglas
+Fibonacci
+fibrillar
+fibrillation
+fibrin
+fibrosis
+fibrous
+fibula
+FICA
+fiche
+fickle
+fiction
+fictioneer
+fictitious
+fid
+fiddle
+fiddlehead
+fiddlestick
+fide
+fidelity
+fidget
+fiducial
+fiduciary
+fie
+fief
+fiefdom
+field
+fieldstone
+fieldwork
+fiend
+fiendish
+fierce
+fiery
+fiesta
+fife
+FIFO
+fifteen
+fifteenth
+fifth
+fiftieth
+fifty
+fiftyish
+fig
+fight
+figural
+figurate
+figure
+figurehead
+figurine
+Fiji
+filament
+filamentary
+filamentous
+filar
+filbert
+filch
+file
+filet
+filial
+filibuster
+filigree
+Filipino
+fill
+fillet
+fillip
+filly
+film
+filmdom
+filmic
+filmstrip
+filter
+filth
+filtrate
+fin
+finagle
+final
+finale
+finance
+financial
+financier
+finch
+find
+fine
+finery
+finesse
+finessing
+finger
+fingerboard
+fingerling
+fingernail
+fingerprint
+fingertip
+finial
+finicky
+finis
+finish
+finitary
+finite
+finitude
+fink
+Finland
+Finley
+Finn
+Finnegan
+Finnish
+fir
+fire
+firearm
+fireball
+firebird
+fireboat
+firebox
+firebrand
+firebreak
+firebrick
+firebug
+fireclay
+firecracker
+firefight
+firefly
+fireguard
+firehouse
+firelight
+fireplace
+fireplug
+firepower
+fireproof
+fireside
+Firestone
+firetrap
+firewall
+firewood
+firework
+firm
+firmament
+first
+firstborn
+firsthand
+fiscal
+Fischbein
+Fischer
+fish
+fisher
+fishery
+fishhook
+fishmonger
+fishpond
+fishtail
+fishwife
+Fisk
+Fiske
+fissile
+fission
+fissure
+fist
+fisticuffs
+fit
+Fitch
+Fitchburg
+fitful
+fitment
+Fitzgerald
+Fitzpatrick
+Fitzroy
+five
+fivefold
+fix
+fixate
+fixture
+Fizeau
+fizz
+fizzle
+fjord
+FL
+flabbergast
+flabby
+flaccid
+flack
+flag
+flagella
+flagellant
+flagellar
+flagellate
+flagellum
+flageolet
+flagitious
+Flagler
+flagon
+flagpole
+flagrant
+flagstaff
+flagstone
+flail
+flair
+flak
+flake
+flam
+flambe
+flamboyant
+flame
+flamenco
+flameout
+flameproof
+flamethrower
+flamingo
+flammable
+Flanagan
+Flanders
+flange
+flank
+flannel
+flap
+flapjack
+flare
+flareup
+flash
+flashback
+flashbulb
+flashgun
+flashlight
+flashover
+flask
+flat
+flatbed
+flatcar
+flatfeet
+flatfish
+flatfoot
+flathead
+flatiron
+flatland
+flatten
+flatter
+flattery
+flatulent
+flatus
+flatware
+flatways
+flatwise
+flatwork
+flatworm
+flaunt
+flautist
+flavor
+flavorsome
+flaw
+flax
+flaxen
+flaxseed
+flay
+flea
+fleabane
+fleck
+flection
+fled
+fledge
+fledgling
+flee
+fleece
+fleet
+Fleming
+Flemish
+flense
+flesh
+fleshpot
+fleshy
+fletch
+Fletcher
+flew
+flex
+flexible
+flexural
+flexure
+flibbertigibbet
+flick
+flicker
+flier
+flight
+flimflam
+flimsy
+flinch
+fling
+flint
+flintlock
+flip
+flipflop
+flippant
+flirt
+flirtation
+flirtatious
+flit
+flitch
+flivver
+Flo
+float
+floc
+floccing
+flocculate
+flocculi
+flock
+floe
+flog
+flood
+floodgate
+floodlight
+floodlit
+floodplain
+floodwater
+floodway
+flooey
+floor
+floorboard
+floorwalker
+floozy
+flop
+flophouse
+floppy
+flora
+floral
+Florence
+Florentine
+Flores
+floret
+floriculture
+florid
+Florida
+Floridian
+florin
+florist
+floss
+flotation
+flotilla
+flotsam
+flounce
+flouncy
+flounder
+flour
+flourish
+flout
+flow
+flowchart
+flower
+flowerpot
+flowery
+flown
+flowstone
+Floyd
+flu
+flub
+fluctuant
+fluctuate
+flue
+fluency
+fluent
+fluff
+fluid
+fluke
+flume
+flummery
+flummox
+flung
+flunk
+fluoresce
+fluorescein
+fluorescent
+fluoridate
+fluoride
+fluorimeter
+fluorinate
+fluorine
+fluorite
+fluorocarbon
+fluorography
+fluoroscope
+fluoroscopic
+fluoroscopy
+fluorspar
+flurry
+flush
+fluster
+flute
+flutter
+fluttery
+fluvial
+flux
+fly
+flyby
+flycatcher
+flyer
+flyleaf
+Flynn
+flyover
+flypaper
+flyspeck
+flyway
+flyweight
+flywheel
+FM
+FMC
+foal
+foam
+fob
+focal
+foci
+focus
+fodder
+foe
+fog
+fogbound
+fogey
+foghorn
+fogy
+foible
+foil
+foist
+fold
+foldaway
+folderol
+foldout
+Foley
+foliage
+foliate
+folio
+folk
+folkish
+folklore
+folkloric
+folksong
+folksy
+folkway
+follicle
+follicular
+follow
+followeth
+folly
+Fomalhaut
+foment
+fond
+fondle
+fondue
+font
+Fontaine
+Fontainebleau
+food
+foodstuff
+foofaraw
+fool
+foolery
+foolhardy
+foolish
+foolproof
+foolscap
+foot
+footage
+football
+footboard
+footbridge
+footcandle
+Foote
+footfall
+footgear
+foothill
+foothold
+footlight
+footling
+footlocker
+footloose
+footnote
+footpad
+footpath
+footprint
+footrest
+footrope
+footsie
+footsore
+footstep
+footstool
+footway
+footwear
+footwork
+fop
+foppery
+foppish
+for
+forage
+foray
+forbade
+forbear
+forbearance
+Forbes
+forbid
+forbidden
+forbode
+forbore
+forborne
+force
+forceps
+forcible
+ford
+Fordham
+fore
+forearm
+forebears
+forebode
+forebrain
+forecast
+forecastle
+foreclose
+foreclosure
+foredeck
+foredoom
+foreface
+forefather
+forefeet
+forefinger
+forefoot
+forefront
+foregoing
+foregone
+foreground
+forehand
+forehead
+foreign
+forejudge
+foreknow
+foreknowledge
+foreknown
+forelady
+foreleg
+forelimb
+forelock
+foremast
+foremost
+foremother
+forename
+forenoon
+forensic
+foreordain
+foreordination
+forepart
+forepaw
+forepeak
+foreplay
+forequarter
+forerunner
+foresail
+foresaw
+foresee
+foreseeable
+foreseen
+foreseer
+foreshadow
+foreshore
+foreshorten
+foresight
+foreskin
+forest
+forestall
+forestation
+forestay
+forestry
+foreswear
+foresworn
+foretaste
+foretell
+forethought
+foretoken
+foretold
+foretop
+forever
+forevermore
+forewarn
+foreword
+forfeit
+forfeiture
+forfend
+forgather
+forgave
+forge
+forgeable
+forgery
+forget
+forgive
+forgiven
+forgo
+forgoes
+forgoing
+forgot
+forgotten
+fork
+forklift
+forlorn
+form
+formal
+formaldehyde
+formant
+format
+formate
+formfitting
+formic
+Formica
+formidable
+Formosa
+formula
+formulae
+formulaic
+formulary
+formulate
+fornicate
+Forrest
+forsake
+forsaken
+forsook
+forsooth
+forswear
+forsworn
+Forsythe
+forsythia
+fort
+forte
+Fortescue
+forth
+forthcome
+forthright
+forthwith
+fortieth
+fortify
+fortiori
+fortissimo
+fortitude
+fortnight
+Fortran
+fortress
+fortuitous
+fortuity
+fortunate
+fortune
+forty
+fortyish
+forum
+forward
+forwent
+Foss
+fossil
+fossiliferous
+foster
+Foucault
+fought
+foul
+foulard
+foulmouth
+found
+foundation
+foundling
+foundry
+fount
+fountain
+fountainhead
+four
+fourfold
+Fourier
+fourscore
+foursome
+foursquare
+fourteen
+fourteenth
+fourth
+fovea
+foveal
+fowl
+fox
+foxglove
+Foxhall
+foxhole
+foxhound
+foxtail
+foyer
+FPC
+fracas
+fractal
+fraction
+fractionate
+fractious
+fracture
+fragile
+fragment
+fragmentary
+fragmentation
+fragrant
+frail
+frailty
+frambesia
+frame
+framework
+Fran
+franc
+franca
+France
+Frances
+Francesca
+franchise
+Francine
+Francis
+Franciscan
+Francisco
+francium
+Franco
+Francois
+frangible
+frangipani
+frank
+Frankenstein
+Frankfort
+Frankfurt
+frankfurter
+Frankie
+franklin
+frantic
+Franz
+frappe
+Fraser
+fraternal
+fraternity
+fraternize
+fratricidal
+fratricide
+Frau
+fraud
+fraudulent
+fraught
+fray
+Frazier
+frazzle
+freak
+freakish
+freckle
+Fred
+Freda
+Freddie
+Freddy
+Frederic
+Frederick
+Fredericks
+Fredericksburg
+Fredericton
+Fredholm
+Fredrickson
+free
+freebase
+freebie
+freeboard
+freeboot
+freed
+freedom
+freehand
+freehearted
+freehold
+freeload
+Freemason
+freemasonry
+Freeport
+freestanding
+freestone
+freethink
+Freetown
+freeway
+freewheel
+freewill
+freeze
+freight
+French
+frenetic
+frenzy
+freon
+frequent
+fresco
+frescoes
+fresh
+freshen
+freshet
+freshwater
+Fresnel
+Fresno
+fret
+fretwork
+Freud
+Freudian
+Frey
+Fri.
+friable
+friar
+fricassee
+fricative
+Frick
+friction
+frictional
+Friday
+fridge
+fried
+Friedman
+Friedrich
+friend
+friendlily
+frieze
+frigate
+Frigga
+fright
+frighten
+frigid
+Frigidaire
+frijoles
+frill
+frilly
+fringe
+fringy
+frippery
+frisbee
+frisk
+fritillary
+fritter
+Fritz
+frivolity
+frivolous
+frizz
+frizzle
+frock
+frog
+frolic
+frolicked
+frolicking
+frolicsome
+from
+frond
+front
+frontage
+frontal
+frontier
+frontiers
+frontispiece
+frontlet
+frosh
+frost
+frostbite
+frostbitten
+froth
+froward
+frown
+frowsy
+frowzy
+froze
+frozen
+FRS
+fructify
+fructose
+Fruehauf
+frugal
+fruit
+fruitcake
+fruiterer
+fruition
+fruity
+frumpish
+frumpy
+frustrate
+frustum
+fry
+Frye
+f's
+FTC
+Fuchs
+fuchsia
+fuddle
+fudge
+fuel
+fugacity
+fugal
+fugitive
+fugue
+Fuji
+Fujitsu
+fulcrum
+fulfill
+fulgent
+full
+fullback
+Fullbright
+Fullerton
+fully
+fulminate
+fulsome
+Fulton
+fumarole
+fumble
+fume
+fumigant
+fumigate
+fun
+function
+functionary
+functor
+fund
+fundable
+fundamental
+fundraise
+funeral
+funerary
+funereal
+fungal
+fungi
+fungible
+fungicidal
+fungicide
+fungiform
+fungo
+fungoes
+fungoid
+fungus
+funicular
+funk
+funnel
+funny
+fur
+furbelow
+furbish
+furious
+furl
+furlong
+furlough
+Furman
+furnace
+furnish
+furniture
+furor
+furore
+furrier
+furrow
+further
+furtherance
+furthermore
+furthermost
+furthest
+furtive
+fury
+furze
+fuse
+fuselage
+fusible
+fusiform
+fusil
+fusileer
+fusillade
+fusion
+fuss
+fussbudget
+fustian
+fusty
+futile
+future
+fuze
+fuzz
+FY
+FYI
+GA
+gab
+gabardine
+gabble
+gabbro
+gaberdine
+Gaberones
+gabfest
+gabion
+gable
+Gabon
+Gabriel
+Gabrielle
+gad
+gadabout
+gadfly
+gadget
+gadgeteer
+gadgetry
+gadolinium
+gadwall
+Gaelic
+gaff
+gaffe
+gag
+gage
+gaggle
+gagster
+gagwriter
+gaiety
+Gail
+gaillardia
+gaily
+gain
+Gaines
+Gainesville
+gainsaid
+gainsay
+gait
+Gaithersburg
+gal
+gala
+galactic
+Galapagos
+Galatea
+Galatia
+galaxy
+Galbreath
+gale
+Galen
+galena
+Galilean
+Galilee
+Galileo
+gall
+Gallagher
+gallant
+gallantry
+galleon
+gallery
+galley
+Gallic
+gallinule
+gallium
+gallivant
+gallon
+gallonage
+gallop
+Galloway
+gallows
+gallstone
+Gallup
+gallus
+Galois
+galoot
+galore
+galosh
+Galt
+galumph
+galvanic
+galvanism
+galvanize
+galvanometer
+Galveston
+Galway
+gam
+gamba
+Gambia
+gambit
+gamble
+gambol
+gambrel
+game
+gamecock
+gamelan
+games
+gamete
+gamey
+gamin
+gamma
+gamut
+gander
+gang
+Ganges
+gangland
+ganglia
+gangling
+ganglion
+gangplank
+gangrene
+gangrenous
+gangster
+gangway
+gannet
+Gannett
+gantlet
+gantry
+Ganymede
+GAO
+gap
+gape
+gar
+garage
+garb
+garbage
+garble
+Garcia
+garden
+gardenia
+Gardner
+Garfield
+Gargantua
+gargantuan
+gargle
+gargoyle
+Garibaldi
+garish
+garland
+garlic
+garlicky
+garner
+garnet
+garnish
+garnishee
+garniture
+garret
+Garrett
+garrison
+Garrisonian
+garrulity
+garrulous
+Garry
+garter
+Garth
+Garvey
+Gary
+Garza
+gas
+gasbag
+Gascony
+gaseous
+gases
+gash
+gasholder
+gashouse
+gasify
+gasket
+gaslight
+gaslit
+gasohol
+gasoline
+gasp
+Gaspee
+Gaston
+gastric
+gastritis
+gastrointestinal
+gastronome
+gastronomy
+gastropod
+gasworks
+gat
+gate
+gatefold
+gatehouse
+gatepost
+gateway
+gather
+Gatlinburg
+gator
+Gatwick
+gauche
+gaucherie
+gaucho
+gaud
+gauge
+gaugeable
+Gauguin
+Gaul
+Gaulle
+gaunt
+gauntlet
+gaur
+gauss
+Gaussian
+gauze
+gave
+gavel
+Gavin
+gavotte
+gawk
+gawkish
+gay
+Gayle
+Gaylord
+gaze
+gazebo
+gazelle
+gazette
+gazetteer
+GDP
+GE
+gear
+gearbox
+gearshift
+gecko
+gedanken
+gee
+geese
+geest
+geezer
+gefilte
+Gegenschein
+Geiger
+Geigy
+geisha
+gel
+gelable
+gelatin
+gelatine
+gelatinous
+geld
+gelid
+gem
+Gemini
+Gemma
+gemology
+gemstone
+gendarme
+gender
+gene
+genealogy
+genera
+generable
+general
+generaled
+generalissimo
+generate
+generatrices
+generatrix
+generic
+generosity
+generous
+Genesco
+geneses
+genesis
+genetic
+Geneva
+Genevieve
+genial
+genie
+genii
+genital
+genitalia
+genitive
+genius
+Genoa
+genocidal
+genocide
+genome
+genomic
+genotype
+genotypical
+genre
+gent
+genteel
+gentian
+gentile
+gentility
+gentle
+gentlefolk
+gentleman
+gentrify
+gentry
+genuflect
+genuine
+genus
+geochronometry
+geode
+geodesic
+geodesy
+geodetic
+Geoffrey
+geography
+geoid
+geology
+geometrician
+geometrize
+geomorphology
+geophysicist
+George
+Georgetown
+Georgia
+geoscience
+geosynclinal
+geosyncline
+Gerald
+Geraldine
+geranium
+Gerard
+Gerber
+gerbil
+Gerhard
+Gerhardt
+geriatric
+germ
+German
+germane
+Germanic
+germanium
+Germantown
+Germany
+germicidal
+germicide
+germinal
+germinate
+gerontocracy
+gerontology
+Gerry
+gerrymander
+Gershwin
+Gertrude
+gerund
+gerundive
+gestalt
+gestapo
+gestation
+gesticulate
+gestural
+gesture
+gesundheit
+get
+getaway
+Gethsemane
+Getty
+Gettysburg
+getup
+gewgaw
+geyser
+Ghana
+ghastly
+Ghent
+gherkin
+ghetto
+ghost
+ghostwrite
+ghostwritten
+ghoul
+ghoulish
+GI
+Giacomo
+giant
+giantess
+gibber
+gibberish
+gibbet
+gibbon
+gibbous
+Gibbs
+gibe
+giblet
+Gibraltar
+Gibson
+giddap
+giddy
+Gideon
+Gifford
+gift
+gig
+gigantesque
+gigantic
+gigantism
+giggle
+giggly
+gigolo
+Gil
+gila
+gilbert
+Gilbertson
+Gilchrist
+gild
+Gilead
+Giles
+gill
+Gillespie
+Gillette
+Gilligan
+Gilmore
+gilt
+gimbal
+Gimbel
+gimcrack
+gimcrackery
+gimlet
+gimmick
+gimmickry
+gimpy
+gin
+Gina
+ginger
+gingerbread
+gingery
+gingham
+gingivitis
+gingko
+ginkgo
+ginmill
+Ginn
+Ginny
+Gino
+Ginsberg
+Ginsburg
+ginseng
+Giovanni
+Gipsy
+giraffe
+gird
+girdle
+girl
+girlfriend
+girlie
+girlish
+girly
+girth
+Gisela
+gist
+Giuliano
+Giuseppe
+give
+giveaway
+given
+giveth
+gizmo
+gizzard
+glace
+glacial
+glaciate
+glacier
+glaciology
+glacis
+glad
+gladden
+glade
+gladiator
+gladiatorial
+gladiolus
+gladsome
+Gladstone
+Gladys
+glamor
+glamorous
+glance
+gland
+glandular
+glare
+Glasgow
+glasnost
+glass
+glassblow
+glassine
+glassware
+glasswork
+Glaswegian
+glaucoma
+glaucous
+glaze
+glazier
+gleam
+glean
+Gleason
+glee
+glen
+Glenda
+Glendale
+Glenn
+glib
+glibly
+Glidden
+glide
+glimmer
+glimpse
+glint
+glissade
+glissando
+glisten
+glister
+glitch
+glitter
+glittery
+glitz
+gloaming
+gloat
+glob
+global
+globe
+globular
+globule
+globulin
+glockenspiel
+glom
+glomerular
+gloom
+Gloria
+Gloriana
+glorify
+glorious
+glory
+gloss
+glossary
+glossolalia
+glottal
+glottis
+Gloucester
+glove
+glow
+glowworm
+glucose
+glue
+gluey
+gluier
+glum
+glut
+glutamic
+gluten
+glutinous
+glutton
+gluttonous
+gluttony
+glyceride
+glycerin
+glycerinate
+glycerine
+glycerol
+glycol
+glycoprotein
+glyph
+GM
+GMT
+gnarl
+gnarly
+gnash
+gnat
+gnaw
+gneiss
+gnome
+gnomic
+gnomish
+gnomon
+gnomonic
+gnosis
+GNP
+gnu
+go
+Goa
+goad
+goal
+goalie
+goalpost
+goaltend
+goat
+goatee
+goatherd
+goatskin
+gob
+gobble
+gobbledegook
+gobbledygook
+goblet
+goblin
+god
+Goddard
+goddess
+godfather
+Godfrey
+godhead
+godmother
+godparent
+godsend
+godson
+Godwin
+godwit
+goer
+goes
+Goethe
+Goff
+goggle
+Gogh
+gogo
+going
+goiter
+gold
+Goldberg
+golden
+goldeneye
+goldenrod
+goldenseal
+goldfield
+goldfinch
+goldfish
+Goldman
+goldsmith
+Goldstein
+Goldstine
+Goldwater
+Goleta
+golf
+Goliath
+golly
+Gomez
+gonad
+gondola
+gondolier
+gone
+gong
+goniometer
+gonorrhea
+Gonzales
+Gonzalez
+goo
+goober
+good
+Goode
+Goodman
+Goodrich
+goodwill
+Goodwin
+goody
+Goodyear
+gooey
+goof
+googol
+googolplex
+gooier
+gooiest
+goon
+goose
+gooseberry
+gooseflesh
+gooseneck
+GOP
+gopher
+Gordian
+Gordon
+gore
+Goren
+gorge
+gorgeous
+gorgon
+Gorham
+gorilla
+Gorky
+Gorman
+gorse
+Gorton
+gosh
+goshawk
+gosling
+gospel
+gossamer
+gossip
+got
+Gotham
+Gothic
+gotta
+gotten
+Gottfried
+gouache
+gouge
+goulash
+Gould
+gourd
+gourmand
+gourmet
+gout
+govern
+governance
+governess
+governor
+gown
+goy
+goyim
+GPO
+GPS
+grab
+grace
+gracile
+gracious
+grackle
+grad
+gradate
+grade
+gradient
+gradual
+graduate
+Grady
+Graff
+graffiti
+graft
+graham
+grail
+grain
+gram
+grammar
+grammarian
+grammatic
+grampus
+granary
+grand
+grandam
+grandchild
+grandchildren
+granddaughter
+grandee
+grandeur
+grandfather
+grandiloquent
+grandiose
+grandma
+grandmother
+grandnephew
+grandniece
+grandpa
+grandparent
+grandsire
+grandson
+grandstand
+granduncle
+grange
+granite
+grannie
+granny
+granola
+grant
+grantee
+grantor
+grantsman
+granular
+granulate
+granule
+Granville
+grape
+grapefruit
+grapeshot
+grapevine
+graph
+grapheme
+graphic
+graphite
+graphology
+grapnel
+grapple
+grasp
+grass
+grasshopper
+grassland
+grata
+grate
+graticule
+gratify
+gratin
+gratis
+gratitude
+gratuitous
+gratuity
+grave
+gravel
+graven
+gravestone
+graveyard
+gravid
+gravimeter
+gravitate
+graviton
+gravure
+gravy
+gray
+graybeard
+grayish
+Grayson
+graywacke
+graze
+grease
+great
+greatcoat
+greathearted
+grebe
+Grecian
+Greece
+greed
+Greek
+green
+greenback
+greenbelt
+Greenberg
+Greenblatt
+Greenbriar
+greenbrier
+Greene
+greenery
+Greenfield
+greengrocer
+greengrocery
+greenhorn
+greenhouse
+greenie
+greenish
+Greenland
+greenmail
+greensand
+Greensboro
+greensward
+greenware
+Greenwich
+greenwood
+Greer
+greet
+Greg
+gregarious
+Gregg
+Gregorian
+Gregory
+gremlin
+grenade
+grenadier
+grenadine
+Grendel
+Grenoble
+Gresham
+Greta
+Gretchen
+grew
+grey
+greyhound
+greyish
+greylag
+grid
+griddle
+gridiron
+gridlock
+grief
+grievance
+grieve
+grievous
+griffin
+Griffith
+grill
+grille
+grillwork
+grim
+grimace
+Grimaldi
+grime
+Grimm
+grin
+grind
+grindstone
+gringo
+grip
+gripe
+grippe
+grisly
+grist
+gristle
+gristmill
+Griswold
+grit
+grizzle
+grizzly
+groan
+groat
+grocer
+grocery
+grog
+grogshop
+groin
+grommet
+groom
+groove
+groovy
+grope
+grosbeak
+gross
+Grosset
+Grosvenor
+grotesque
+Groton
+grotto
+grouch
+ground
+groundhog
+groundnut
+groundsel
+groundsheet
+groundskeeper
+groundskeeping
+groundwater
+groundwork
+group
+groupie
+grouse
+grout
+grove
+grovel
+Grover
+grow
+growl
+grown
+grownup
+growth
+grub
+grubstake
+grudge
+gruel
+gruesome
+gruff
+grumble
+Grumman
+grumpy
+grunge
+grunion
+grunt
+gryphon
+g's
+GSA
+GTE
+Guadalupe
+Guam
+guanaco
+guanidine
+guanine
+guano
+guarantee
+guarantor
+guaranty
+guard
+guardhouse
+Guardia
+guardian
+guardroom
+guards
+Guatemala
+guava
+gubernatorial
+gudgeon
+Guenther
+guerdon
+guerilla
+guernsey
+guerrilla
+guess
+guesstimate
+guesswork
+guest
+guff
+guffaw
+Guggenheim
+Guiana
+guidance
+guide
+guidebook
+guideline
+guidepost
+guignol
+guild
+guildhall
+guile
+Guilford
+guillemot
+guillotine
+guilt
+guinea
+Guinness
+guise
+guitar
+gulag
+gulch
+gulf
+gull
+Gullah
+gullet
+gullible
+Gulliver
+gully
+gulp
+gum
+gumbo
+gumdrop
+gumption
+gumshoe
+gun
+gunboat
+guncotton
+Gunderson
+gunfight
+gunfire
+gunflint
+gunk
+gunmetal
+gunnery
+gunny
+gunnysack
+gunplay
+gunpoint
+gunpowder
+gunrun
+gunshot
+gunsling
+gunsmith
+Gunther
+gunwale
+guppy
+gurdy
+gurgle
+Gurkha
+gurney
+guru
+Gus
+gush
+gusset
+gussy
+gust
+Gustafson
+gustatorial
+gustatory
+Gustav
+Gustave
+Gustavus
+gusto
+gut
+Gutenberg
+Guthrie
+Gutierrez
+gutsy
+guttersnipe
+guttural
+guy
+Guyana
+Guzman
+guzzle
+Gwen
+Gwendolyn
+Gwyn
+gybe
+gym
+gymnasium
+gymnast
+gymnastic
+gymnosperm
+gynecology
+gyp
+gypsum
+gypsy
+gyrate
+gyrfalcon
+gyro
+gyrocompass
+gyromagnetic
+gyroscope
+gyroscopic
+gyrostabilize
+ha
+Haag
+Haas
+Habakkuk
+habeas
+haberdasher
+haberdashery
+Haberman
+Habib
+habiliment
+habit
+habitant
+habitat
+habitation
+habitual
+habituate
+habitue
+hachure
+hacienda
+hack
+Hackett
+hackle
+hackmatack
+hackney
+hackneyed
+hacksaw
+hackwork
+had
+Hadamard
+Hadassah
+Haddad
+haddock
+Hades
+Hadley
+hadn't
+Hadrian
+hadron
+hafnium
+haft
+hag
+Hagen
+Hager
+Haggai
+haggard
+haggis
+haggle
+hagiography
+Hagstrom
+Hague
+Hahn
+Haifa
+haiku
+hail
+hailstone
+hailstorm
+Haines
+hair
+hairbreadth
+hairbrush
+haircut
+hairdo
+hairdress
+hairline
+hairpin
+hairsplit
+hairspring
+Haiti
+Haitian
+hajj
+hajji
+Hal
+halation
+halberd
+halcyon
+hale
+Haley
+half
+halfback
+halfhearted
+halfpenny
+halftone
+halfway
+halibut
+halide
+Halifax
+halite
+halitosis
+hall
+hallelujah
+Halley
+hallmark
+hallow
+Halloween
+hallucinate
+hallucinogen
+hallucinogenic
+hallway
+halo
+halocarbon
+halogen
+halogenate
+Halsey
+Halstead
+halt
+haltere
+halvah
+halve
+Halverson
+halyard
+ham
+Hamburg
+hamburger
+Hamilton
+hamlet
+Hamlin
+hammer
+hammerhead
+hammerlock
+hammock
+Hammond
+hamper
+Hampshire
+Hampshirite
+Hampton
+hamster
+hamstring
+Han
+Hancock
+hand
+handbag
+handball
+handbill
+handbook
+handcar
+handcart
+handclasp
+handcraft
+handcuff
+Handel
+handgrip
+handgun
+handhold
+handicap
+handicraft
+handicrafts
+handiwork
+handkerchief
+handle
+handleable
+handlebar
+handline
+handmade
+handmaiden
+handoff
+handout
+handpick
+handrail
+handsbreadth
+handset
+handshake
+handsome
+handspike
+handspring
+handstand
+handwork
+handwoven
+handwrite
+handwritten
+handy
+Haney
+Hanford
+hang
+hangable
+hangar
+hangdog
+hangnail
+hangout
+hangover
+hank
+Hankel
+hanker
+hanky
+Hanley
+Hanlon
+Hanna
+Hannah
+Hannibal
+Hanoi
+Hanover
+Hanoverian
+Hans
+Hansard
+Hansel
+Hansen
+hansom
+Hanson
+Hanukkah
+hap
+haphazard
+haploid
+happen
+happenstance
+happing
+Hapsburg
+harangue
+harass
+Harbin
+harbinger
+harbor
+Harcourt
+hard
+hardball
+hardboard
+hardboiled
+hardcover
+harden
+hardhat
+hardhead
+hardhearted
+Hardin
+Harding
+hardline
+hardpan
+hardscrabble
+hardship
+hardtack
+hardtop
+hardware
+hardwood
+hardworking
+hardy
+hare
+harebrained
+harelip
+harem
+haricot
+hark
+Harlan
+Harlem
+harlequin
+Harley
+harlot
+harlotry
+harm
+Harmon
+harmonic
+harmonica
+harmonious
+harmonist
+harmonium
+harmonize
+harmony
+harness
+Harold
+harp
+harpoon
+harpsichord
+harpy
+Harrell
+Harriet
+Harriman
+Harrington
+Harris
+Harrisburg
+Harrison
+harrow
+harry
+harsh
+harshen
+hart
+Hartford
+Hartley
+Hartman
+harum
+haruspex
+Harvard
+harvest
+Harvey
+hash
+Hashemite
+hashish
+hasn't
+hasp
+hassle
+hassock
+hast
+haste
+hasten
+Hastings
+hasty
+hat
+hatbox
+hatch
+hatchery
+hatchet
+hatchling
+hatchway
+hate
+Hatfield
+hath
+Hathaway
+hatred
+Hatteras
+Hattie
+haughty
+haul
+haulage
+haunch
+haunt
+hauteur
+Havana
+have
+haven
+haven't
+Havilland
+havoc
+haw
+Hawaii
+Hawaiian
+hawk
+Hawkins
+hawkish
+Hawley
+hawsehole
+hawser
+hawthorn
+Hawthorne
+hay
+haycock
+Hayden
+Haydn
+Hayes
+hayfield
+hayloft
+haymarket
+haymow
+Haynes
+hayrack
+hayride
+hayseed
+haystack
+Hayward
+haywire
+hazard
+hazardous
+haze
+hazel
+hazelnut
+HDTV
+he
+head
+headache
+headband
+headboard
+headcount
+headdress
+headfirst
+headgear
+headhunt
+headland
+headlight
+headline
+headlock
+headlong
+headmaster
+headmistress
+headmost
+headphone
+headpiece
+headquartered
+headquarters
+headrest
+headroom
+heads
+headsail
+headset
+headstand
+headstone
+headstrong
+headwaiter
+headwall
+headwater
+headway
+headwind
+headwork
+heal
+Healey
+health
+Healy
+heap
+hear
+heard
+hearken
+hearsay
+hearse
+Hearst
+heart
+heartache
+heartbeat
+heartbreak
+heartbroken
+heartburn
+hearten
+heartfelt
+hearth
+hearthstone
+heartland
+heartrending
+heartsick
+heartsore
+heartstring
+heartthrob
+heat
+heath
+heathen
+heathenish
+heather
+Heathkit
+Heathrow
+heatstroke
+heave
+heaven
+heavenward
+heavy
+heavyhearted
+heavyset
+heavyweight
+Hebe
+hebephrenic
+Hebert
+hebetude
+Hebraic
+Hebraism
+Hebraist
+Hebrew
+Hecate
+hecatomb
+heck
+heckle
+Heckman
+hectare
+hectic
+hectograph
+hector
+Hecuba
+he'd
+hedge
+hedgehog
+hedgehop
+hedgerow
+hedonism
+hedonist
+heebie
+heed
+heel
+heelpiece
+heft
+Hegelian
+hegemonic
+hegemony
+hegira
+Heidelberg
+Heidi
+heifer
+heigh
+height
+heighten
+Heine
+heinous
+Heinrich
+Heinz
+heir
+heiress
+heirloom
+Heisenberg
+heist
+held
+Helen
+Helena
+Helene
+Helga
+heliacal
+helical
+helices
+helicoid
+helicopter
+heliocentric
+heliograph
+heliostat
+heliotrope
+heliotropic
+heliport
+helium
+helix
+he'll
+hell
+hellbender
+hellcat
+hellebore
+Hellene
+Hellenic
+Hellenism
+Hellenist
+hellfire
+hellgrammite
+hellion
+hellish
+hello
+helm
+helmet
+Helmholtz
+helms
+Helmut
+helot
+helotry
+help
+helpmate
+helpmeet
+Helsinki
+helter
+helve
+hem
+hematite
+hematology
+hematoma
+heme
+hemicycle
+Hemingway
+hemiola
+hemiplegic
+hemisphere
+hemispheric
+hemline
+hemlock
+hemoglobin
+hemolysis
+hemolytic
+hemophilia
+hemophilic
+hemorrhage
+hemorrhagic
+hemorrhoid
+hemosiderin
+hemp
+Hempstead
+hen
+henbane
+hence
+henceforth
+henceforward
+henchman
+henchmen
+Henderson
+Hendrick
+Hendricks
+Hendrickson
+Hendrix
+henequen
+Henley
+henna
+hennery
+henpeck
+Henri
+Henrietta
+henry
+Hensley
+Henson
+hep
+hepatic
+hepatica
+hepatitis
+Hepburn
+heptagon
+heptagonal
+heptameter
+heptane
+her
+Hera
+Heraclitus
+herald
+heraldic
+heraldry
+herb
+herbaceous
+herbal
+herbarium
+Herbert
+herbicidal
+herbicide
+herbivore
+herbivorous
+Herculean
+Hercules
+herd
+herds
+here
+hereabout
+hereafter
+hereby
+hereditary
+heredity
+Hereford
+herein
+hereinabove
+hereinafter
+hereinbefore
+hereinbelow
+hereof
+hereon
+heresy
+heretic
+hereto
+heretofore
+hereunder
+hereunto
+hereupon
+herewith
+heritable
+heritage
+Herkimer
+Herman
+hermaphrodite
+hermeneutic
+Hermes
+hermetic
+hermit
+hermitage
+Hermite
+hermitian
+Hermosa
+Hernandez
+hernia
+hero
+Herodotus
+heroes
+heroic
+heroin
+heroine
+heroism
+heron
+heronry
+herpes
+herpetology
+Herr
+Herrera
+herringbone
+Herschel
+herself
+Hershel
+Hershey
+hertz
+Hertzog
+hesitant
+hesitate
+Hesperus
+Hess
+Hessian
+Hester
+heterocyclic
+heterodox
+heterodyne
+heterogamous
+heterogeneity
+heterogeneous
+heterologous
+heterology
+heteromorph
+heteromorphic
+heterosexual
+heterostructure
+heterotrophic
+heterozygous
+Hetman
+Hettie
+Hetty
+Heublein
+heuristic
+Heusen
+Heuser
+hew
+Hewett
+Hewitt
+Hewlett
+hewn
+hex
+hexad
+hexadecimal
+hexagon
+hexagonal
+hexagram
+hexameter
+hexane
+hey
+heyday
+hi
+Hiatt
+hiatus
+Hiawatha
+hibachi
+Hibbard
+hibernate
+Hibernia
+hibiscus
+hiccup
+hiccupped
+hiccupping
+hick
+Hickey
+Hickman
+hickory
+hid
+hidalgo
+hidden
+hide
+hideaway
+hidebound
+hideous
+hideout
+hie
+hierarch
+hierarchal
+hierarchic
+hierarchs
+hierarchy
+hieratic
+hieroglyph
+hieroglyphic
+Hieronymus
+hierophant
+hifalutin
+Higgins
+higgle
+higgledy
+high
+highball
+highboy
+highbrow
+highfalutin
+highhanded
+highland
+highlight
+highroad
+hightail
+highway
+hijack
+hijinks
+hike
+hilarious
+hilarity
+Hilbert
+Hilda
+Hildebrand
+Hildegard
+hill
+Hillary
+hillbilly
+Hillcrest
+Hillel
+hillock
+hillside
+hilltop
+hilly
+hilt
+Hilton
+hilum
+him
+Himalaya
+himself
+Hinayana
+hind
+hinder
+Hindi
+hindmost
+hindquarter
+hindrance
+hindsight
+Hindu
+Hinduism
+Hindustani
+Hines
+hinge
+Hinman
+hint
+hinterland
+Hinton
+hip
+hippie
+hippo
+hippocampus
+Hippocratic
+hippodrome
+hippopotamus
+hippy
+hipster
+Hiram
+hire
+hireling
+Hiroshi
+Hiroshima
+Hirsch
+hirsute
+his
+Hispanic
+hiss
+histamine
+histidine
+histochemistry
+histogram
+histology
+historian
+historic
+historiography
+history
+histrionic
+hit
+Hitachi
+hitch
+Hitchcock
+hitchhike
+hither
+hithermost
+hitherto
+hitherward
+Hitler
+Hitlerian
+Hittite
+HIV
+hive
+HMO
+ho
+hoagie
+Hoagland
+hoagy
+hoar
+hoard
+hoarfrost
+hoarse
+hoarsen
+hoax
+hob
+Hobart
+Hobbes
+Hobbesian
+hobble
+hobbledehoy
+Hobbs
+hobby
+hobbyhorse
+hobgoblin
+hobnail
+hobnob
+hobo
+hoboes
+Hoboken
+hoc
+hock
+hockey
+hocus
+hod
+Hodge
+hodgepodge
+Hodgkin
+hoe
+hoecake
+hoedown
+Hoff
+hog
+hogan
+hogback
+hoggish
+hogshead
+hogwash
+hoist
+Hokkaido
+hokum
+Holbrook
+Holcomb
+hold
+holden
+holdfast
+holdout
+holdover
+holdup
+hole
+holeable
+holey
+holiday
+Holland
+hollandaise
+holler
+Hollerith
+Hollingsworth
+Hollister
+hollow
+Holloway
+hollowware
+holly
+hollyhock
+Hollywood
+Holm
+Holman
+Holmdel
+Holmes
+holmium
+holocaust
+Holocene
+holograph
+holography
+holotype
+Holst
+Holstein
+holster
+Holt
+holy
+Holyoke
+holystone
+homage
+hombre
+homburg
+home
+homebody
+homebound
+homebred
+homebuild
+homecome
+homegrown
+homeland
+homemade
+homeomorph
+homeomorphic
+homeopath
+homeopathic
+homeopathy
+homeostasis
+homeostatic
+homeotypic
+homeown
+Homeric
+homeroom
+homesick
+homespun
+homestead
+homestretch
+hometown
+homeward
+homework
+homey
+homicidal
+homicide
+homier
+homiest
+homiletic
+homily
+hominess
+hominid
+hominoid
+hominy
+homo
+homoerotic
+homogenate
+homogeneity
+homogeneous
+homogenize
+homograph
+homolog
+homologize
+homologous
+homologue
+homology
+homomorph
+homomorphic
+homonym
+homonymic
+homonymous
+homonymy
+homophobe
+homophone
+homophonic
+homosexual
+homotopy
+homozygous
+homunculi
+homunculus
+honcho
+Honda
+Honduran
+Honduras
+hone
+honest
+honey
+honeybee
+honeycomb
+honeydew
+honeymoon
+honeysuckle
+Honeywell
+Hong
+honied
+honk
+honky
+Honolulu
+honor
+honoraria
+honorarium
+honorary
+honoree
+honorific
+honoris
+Honshu
+hooch
+hood
+hoodlum
+hoodoo
+hoodwink
+hooey
+hoof
+hoofmark
+hook
+hookah
+hookup
+hookworm
+hooligan
+hoop
+hoopla
+hooray
+hoosegow
+Hoosier
+hoot
+hootenanny
+Hoover
+hooves
+hop
+hope
+Hopi
+Hopkins
+Hopkinsian
+hopscotch
+Horace
+Horatio
+horde
+horehound
+horizon
+horizontal
+hormonal
+hormone
+horn
+hornbeam
+hornblende
+Hornblower
+hornbook
+Horne
+Horner
+hornet
+hornpipe
+hornswoggle
+horntail
+hornworm
+horology
+horoscope
+Horowitz
+horrendous
+horrible
+horrid
+horrific
+horrify
+horror
+hors
+horse
+horseback
+horsecar
+horsedom
+horseflesh
+horsefly
+horsehair
+horsehide
+horselaugh
+horseplay
+horsepower
+horseradish
+horseshoe
+horsetail
+horsewhip
+hortatory
+horticultural
+horticulture
+Horton
+Horus
+hosanna
+hose
+Hosea
+hosiery
+hospice
+hospitable
+hospital
+host
+hostage
+hostel
+hostelry
+hostess
+hostile
+hostler
+hot
+hotbed
+hotblood
+hotbox
+hotel
+hotelier
+hotfoot
+hothead
+hothouse
+hotline
+hotrod
+hotshot
+Houdaille
+Houdini
+hough
+Houghton
+hound
+hour
+hourglass
+house
+houseboat
+housebreak
+housebroken
+houseclean
+housecoat
+housefly
+household
+houselights
+housemaid
+housemother
+housetop
+houseware
+housewarming
+housewife
+housewives
+housework
+Houston
+Houyhnhnm
+hove
+hovel
+hover
+hovercraft
+how
+Howard
+howbeit
+how'd
+howdy
+Howe
+Howell
+however
+Howie
+howitzer
+howl
+how're
+howsoever
+howsomever
+hoy
+hoyden
+hoydenish
+hoyle
+Hoyt
+Hrothgar
+h's
+hub
+Hubbard
+Hubbell
+hubbub
+hubby
+hubcap
+Huber
+Hubert
+hubris
+huckleberry
+huckster
+huddle
+Hudson
+hue
+hued
+huff
+Huffman
+hug
+huge
+Huggins
+Hugh
+Hughes
+Hugo
+Huguenot
+huh
+hula
+hulk
+hull
+hullabaloo
+hum
+human
+humane
+humanitarian
+humankind
+humanoid
+humble
+Humboldt
+humbug
+humbuggery
+humdinger
+humdrum
+humerus
+humic
+humid
+humidify
+humidistat
+humidor
+humiliate
+humility
+Hummel
+hummingbird
+hummock
+humongous
+humor
+humoresque
+humorous
+hump
+humpback
+humph
+Humphrey
+humus
+Hun
+hunch
+hunchback
+hundred
+hundredfold
+hundredth
+hundredweight
+hung
+Hungarian
+Hungary
+hungry
+hunk
+hunt
+Huntington
+Huntley
+huntress
+hunts
+Huntsville
+Hurd
+hurdle
+hurdy
+hurl
+Hurley
+hurly
+Huron
+hurrah
+hurray
+hurricane
+hurry
+Hurst
+hurt
+hurtful
+hurtle
+Hurwitz
+husband
+husbandry
+hush
+husk
+hussar
+hussy
+hustings
+hustle
+Huston
+hut
+hutch
+Hutchins
+Hutchinson
+Hutchison
+Hutton
+Huxley
+Huxtable
+huzza
+huzzah
+hyacinth
+Hyades
+hyaline
+Hyannis
+Hyatt
+hybrid
+Hyde
+hydra
+hydrangea
+hydrant
+hydrate
+hydraulic
+hydrazine
+hydride
+hydro
+hydrocarbon
+hydrocarbonate
+hydrocephalic
+hydrochemistry
+hydrochloric
+hydrochloride
+hydrodynamic
+hydroelectric
+hydrofluoric
+hydrofoil
+hydroform
+hydrogen
+hydrogenate
+hydrography
+hydrology
+hydrolysis
+hydrolyze
+hydrometer
+hydrophilic
+hydrophobe
+hydrophone
+hydroplane
+hydroponic
+hydropower
+hydroscope
+hydrosphere
+hydrostatic
+hydrotherapy
+hydrothermal
+hydrous
+hydroxide
+hydroxy
+hydroxyl
+hydroxylate
+hyena
+hygiene
+hygienic
+hygrometer
+hygroscopic
+hying
+Hyman
+hymen
+hymeneal
+hymenoptera
+hymn
+hymnal
+hymnbook
+hype
+hyperbola
+hyperbolic
+hyperboloid
+hyperborean
+hypergolic
+hyperopia
+hyperopic
+hyphen
+hyphenate
+hypnosis
+hypnotic
+hypnotism
+hypnotist
+hypnotize
+hypoactive
+hypocaust
+hypocenter
+hypochondria
+hypocrisy
+hypocrite
+hypocritical
+hypocycloid
+hypodermic
+hypophyseal
+hypostatize
+hypotenuse
+hypothalamic
+hypothalamus
+hypothermia
+hypothermic
+hypotheses
+hypothesis
+hypothesize
+hypothetic
+hypothyroid
+hypoxia
+hypsometer
+hysterectomy
+hysteresis
+hysteria
+hysteric
+Hyundai
+IA
+iambic
+Ian
+iatrogenic
+Iberia
+ibex
+ibid.
+ibis
+IBM
+Ibn
+Icarus
+ICBM
+ICC
+ice
+iceberg
+iceboat
+icebox
+icebreaker
+icefall
+icehouse
+Iceland
+Icelandic
+ichneumon
+ichthyology
+ichthyosaur
+icicle
+icky
+icon
+iconic
+iconoclasm
+iconoclast
+iconoclastic
+iconography
+iconology
+iconoscope
+icosahedra
+icosahedral
+icosahedron
+I'd
+ID
+Ida
+Idaho
+idea
+ideal
+ideate
+idempotent
+identical
+identify
+identity
+ideograph
+ideography
+ideologue
+ideology
+ides
+idiocy
+idiom
+idiomatic
+idiosyncrasy
+idiosyncratic
+idiot
+idiotic
+idle
+idly
+idol
+idolater
+idolatrous
+idolatry
+idyll
+idyllic
+i.e.
+IEEE
+if
+Ifni
+igloo
+igneous
+ignite
+ignition
+ignoble
+ignominious
+ignominy
+ignoramus
+ignorant
+ignore
+iguana
+ii
+iii
+Ike
+IL
+ileitis
+ileum
+iliac
+Iliad
+ilk
+I'll
+ill
+illegal
+illegible
+illegitimacy
+illegitimate
+illiberal
+illicit
+illimitable
+Illinois
+illiquid
+illiteracy
+illiterate
+illness
+illogic
+illume
+illuminant
+illuminate
+illuminati
+illumine
+illusion
+illusionary
+illusory
+illustrate
+illustrious
+Ilona
+Ilyushin
+I'm
+image
+imagery
+imaginary
+imaginate
+imagine
+imbalance
+imbecile
+imbecilic
+imbibe
+Imbrium
+imbroglio
+imbrue
+imbue
+imitable
+imitate
+immanent
+immediacy
+immense
+immerse
+immersion
+imminent
+immolate
+immovable
+immune
+immunization
+immunology
+immure
+imp
+impact
+impair
+impartation
+impassable
+impasse
+impasto
+impatient
+impeach
+impecunious
+impedance
+impede
+impedimenta
+impel
+impend
+imperative
+imperial
+imperil
+imperious
+imperium
+impersonate
+impetigo
+impetuosity
+impetuous
+impetus
+impinge
+impish
+implement
+implementation
+implicant
+implicate
+implicit
+implode
+implore
+important
+importation
+importunate
+importune
+impost
+impoverish
+imprecate
+impregnable
+impregnate
+impresario
+impressible
+impression
+imprimatur
+imprint
+impromptu
+improvisation
+improvisatorial
+improvisatory
+improvise
+impudent
+impugn
+impulsion
+impulsive
+impunity
+imputation
+impute
+in
+inability
+inaction
+inadvisable
+inalienable
+inalterable
+inamorata
+inane
+inappeasable
+inapproachable
+inapt
+inarguable
+inartistic
+inasmuch
+inaugural
+inaugurate
+inboard
+inborn
+inbound
+inbred
+inbreed
+Inc.
+Inca
+incandescent
+incant
+incantation
+incapable
+incarcerate
+incarnate
+incendiary
+incense
+incentive
+inception
+inceptor
+incessant
+incest
+incestuous
+inch
+inchoate
+inchworm
+incident
+incidental
+incinerate
+incipient
+incise
+incision
+incisive
+incisor
+incivil
+inclination
+incline
+inclose
+include
+inclusion
+incognito
+income
+incommunicado
+incommutable
+incomparable
+incompetent
+incomplete
+incompletion
+incomprehension
+incomputable
+inconceivable
+inconclusive
+incondensable
+inconsiderable
+inconsolable
+incontestable
+incontrollable
+incorporable
+incorporate
+incorrect
+incorrigible
+increment
+incriminate
+incross
+incrustation
+incubate
+incubi
+incubus
+inculcate
+incumbent
+incunabula
+incur
+incursion
+indebted
+indecent
+indecipherable
+indecomposable
+indeed
+indefatigable
+indefeasible
+indefinable
+indelible
+indelicate
+indemnify
+indemnity
+indent
+indentation
+indenture
+indescribable
+indeterminable
+indeterminism
+index
+India
+Indian
+Indiana
+Indianapolis
+indicant
+indicate
+indices
+indicia
+indict
+Indies
+indigene
+indigenous
+indigent
+indigestible
+indignant
+indignation
+indigo
+indirect
+indiscoverable
+indispensable
+indispose
+indisposition
+indisputable
+indissoluble
+indistinct
+indistinguishable
+indium
+individual
+individualism
+individuate
+Indochina
+Indochinese
+indoctrinate
+indole
+indolent
+indomitable
+Indonesia
+indoor
+indrawn
+induce
+inducible
+inductance
+inductee
+indulge
+indulgent
+industrial
+industrialism
+industrious
+industry
+inebriate
+inebriety
+ineducable
+ineffable
+ineffective
+inelastic
+ineluctable
+inept
+ineptitude
+inequality
+inequivalent
+inerrant
+inert
+inertance
+inertia
+inertial
+inescapable
+inessential
+inevitable
+inexact
+inexcusable
+inexperience
+inexpert
+inexplainable
+inexpressible
+inextinguishable
+Inez
+infamy
+infancy
+infant
+infanta
+infanticide
+infantile
+infantry
+infarct
+infatuate
+infect
+infectible
+infectious
+infer
+inferable
+inference
+inferential
+inferior
+infernal
+inferno
+infest
+infestation
+infidel
+infield
+infight
+infima
+infimum
+infinitesimal
+infinitive
+infinitude
+infinitum
+infinity
+infirmary
+infix
+inflame
+inflammation
+inflammatory
+inflate
+inflationary
+inflect
+inflict
+inflorescent
+influential
+influenza
+influx
+info
+inform
+informatics
+information
+infra
+infract
+infrared
+infrasonic
+infrastructure
+infrequent
+infuriate
+ingenious
+ingenue
+ingenuity
+ingenuous
+Ingersoll
+ingest
+ingestible
+ingestion
+ingot
+Ingram
+ingrate
+ingratiate
+ingredient
+ingress
+Ingrid
+ingroup
+inhabit
+inhalant
+inhere
+inherent
+inherit
+inheritance
+inheritor
+inhibit
+inhibition
+inhibitor
+inholding
+inhomogeneity
+inhomogeneous
+inhuman
+inhume
+inimical
+iniquitous
+iniquity
+initial
+initiate
+inject
+Injun
+injure
+injurious
+injury
+ink
+inkblot
+inker
+inkling
+inkwell
+inland
+inlay
+inlet
+Inman
+inmate
+inmost
+inn
+innards
+innate
+inner
+innermost
+innersole
+innervate
+inning
+innocent
+innocuous
+innovate
+innuendo
+inoculant
+inoculate
+inoperative
+inordinate
+inpatient
+input
+inquire
+inquiry
+inquisition
+inquisitor
+inquisitorial
+inroad
+inrush
+inscription
+inseam
+insect
+insecticidal
+insecticide
+insectivore
+insecure
+inseminate
+insert
+inset
+inshore
+inside
+insidious
+insight
+insignia
+insincere
+insinuate
+insipid
+insist
+insistent
+insofar
+insolate
+insole
+insolent
+insolvable
+insomnia
+insomuch
+insouciant
+inspect
+inspiration
+inspirit
+instable
+installation
+instalment
+instant
+instantaneous
+instantiate
+instar
+instate
+instead
+instep
+instigate
+instill
+instinct
+instinctual
+institute
+instruct
+instructible
+instrument
+instrumentation
+insubordinate
+insufferable
+insulant
+insular
+insulate
+insulin
+insult
+insuperable
+insupportable
+insurance
+insure
+insurgent
+insurmountable
+insurrection
+intact
+intake
+integer
+integrable
+integral
+integrand
+integrate
+integrity
+intellect
+intellectual
+intelligent
+intelligentsia
+intelligible
+intend
+intendant
+intense
+intensify
+intensive
+intent
+intention
+inter
+intercalary
+intercalate
+intercept
+intercessor
+intercom
+interdict
+interest
+interfere
+interference
+interferometer
+interim
+interior
+interject
+interlude
+intermediacy
+intermediary
+intermit
+intermittent
+intermitting
+intern
+internal
+internecine
+Interpol
+interpolant
+interpolate
+interpret
+interpretation
+interpretive
+interpupillary
+interregnum
+interrogate
+interrogatory
+interrupt
+interruptible
+intersperse
+interspersion
+interstice
+interstitial
+interval
+intervale
+intervene
+intervenor
+intervention
+interviewee
+intestacy
+intestate
+intestinal
+intestine
+intimacy
+intimal
+intimate
+intimidate
+into
+intonate
+intoxicant
+intoxicate
+intractable
+intramolecular
+intransigent
+intransitive
+intrepid
+intricacy
+intricate
+intrigue
+intrinsic
+introduce
+introduction
+introductory
+introit
+introject
+intromission
+intromit
+introspect
+introversion
+introvert
+intrude
+intrusion
+intuit
+intuitable
+Inuit
+inundate
+inure
+invade
+invalid
+invasion
+invective
+inveigh
+inveigle
+invent
+inventor
+inventory
+Inverness
+inverse
+invert
+invertible
+invest
+investigate
+investiture
+investor
+inveterate
+inviable
+invidious
+invigorate
+inviolable
+inviolate
+invitation
+invite
+invitee
+invoice
+invoke
+involutionary
+involutory
+involve
+inward
+Io
+iodate
+iodic
+iodide
+iodine
+iodize
+iodoform
+iodous
+ion
+ionic
+ionize
+ionosphere
+ionospheric
+iota
+IOU
+Iowa
+ipecac
+ipsilateral
+ipso
+IQ
+IR
+Ira
+Iran
+Iranian
+Iraq
+Iraqi
+irascible
+irate
+ire
+Ireland
+Irene
+irenic
+irides
+iridescent
+iridium
+iris
+Irish
+irk
+irksome
+Irma
+iron
+ironbound
+ironclad
+ironic
+ironmaster
+ironmonger
+ironmongery
+ironside
+ironstone
+ironware
+ironwood
+ironwork
+irony
+Iroquois
+irrational
+Irrawaddy
+irreclaimable
+irrecoverable
+irredeemable
+irredentism
+irredentist
+irrefragable
+irremovable
+irreplaceable
+irreproducible
+irresolute
+irresolvable
+irrevocable
+irrigate
+irritable
+irritant
+irritate
+irrupt
+IRS
+Irvin
+Irvine
+Irving
+Irwin
+i's
+is
+Isaac
+Isaacson
+Isabel
+Isabella
+Isaiah
+ISBN
+isentropic
+Isfahan
+Ising
+isinglass
+Isis
+Islam
+Islamabad
+Islamic
+island
+isle
+islet
+ism
+isn't
+isochronal
+isochronism
+isochronous
+isoclinal
+isocline
+isogonic
+isolate
+Isolde
+isomer
+isomeric
+isomorph
+isomorphic
+isopleth
+isosceles
+isostasy
+isotherm
+isothermal
+isotope
+isotopic
+isotopy
+isotropic
+isotropy
+Israel
+Israeli
+Israelite
+ISSN
+issuant
+issue
+Istanbul
+isthmian
+isthmus
+it
+Italian
+italianate
+italic
+Italy
+itch
+it'd
+item
+iterate
+Ithaca
+itinerant
+itinerary
+it'll
+Ito
+itself
+IT&T
+ITT
+IUD
+iv
+Ivan
+Ivanhoe
+I've
+Iverson
+ivory
+ivy
+ix
+Izvestia
+jab
+jabber
+jabberwocky
+Jablonsky
+jacaranda
+jack
+jackal
+jackanapes
+jackass
+jackboot
+jackdaw
+jacket
+jackhammer
+Jackie
+jackknife
+jacklight
+Jackman
+jackpot
+jackrabbit
+Jackson
+Jacksonville
+jackstraw
+Jacky
+JACM
+Jacob
+Jacobean
+Jacobi
+Jacobian
+Jacobin
+Jacobs
+Jacobsen
+Jacobson
+Jacobus
+jacquard
+Jacqueline
+Jacques
+jacuzzi
+jade
+jaeger
+jag
+jaguar
+jail
+jailbird
+jailbreak
+jailhouse
+Jaime
+Jakarta
+Jake
+jalapeno
+jalopy
+jalousie
+jam
+Jamaica
+jamb
+jambalaya
+jamboree
+James
+Jamestown
+Jamie
+Jan
+Jane
+Janeiro
+Janet
+jangle
+Janice
+Janie
+Janis
+janissary
+janitor
+janitorial
+janizary
+Janos
+Jansenist
+January
+Janus
+Japan
+Japanese
+japanned
+jape
+japery
+jar
+jargon
+Jarvin
+Jarvis
+jasmine
+Jason
+jasper
+jaundice
+jaunt
+Java
+Javanese
+javelin
+jaw
+jawbone
+jawbreak
+jay
+jaybird
+Jaycee
+jaywalk
+jazz
+jealous
+jealousy
+jean
+Jeanette
+Jeanne
+Jeannie
+Jed
+jeebies
+jeep
+jeer
+Jeff
+Jefferson
+Jeffrey
+Jehovah
+jejune
+jejunum
+jelly
+jellyfish
+Jenkins
+Jennie
+Jennifer
+Jennings
+jenny
+Jensen
+jeopard
+jeopardy
+jerboa
+jeremiad
+Jeremiah
+Jeremy
+Jeres
+Jericho
+jerk
+jerkin
+jerkwater
+jeroboam
+Jerome
+jerry
+jersey
+Jerseyite
+Jerusalem
+jess
+Jesse
+Jessica
+Jessie
+jest
+Jesuit
+jesuitic
+jesuitism
+Jesus
+jet
+jetliner
+jetport
+jetsam
+jettison
+jetty
+jetway
+Jew
+jewel
+Jewell
+jewelry
+Jewess
+Jewett
+Jewish
+Jewry
+jezebel
+JFK
+jib
+jibe
+Jiddah
+jiffy
+jig
+jiggle
+jiggly
+jigsaw
+jihad
+Jill
+jilt
+Jim
+Jimenez
+Jimmie
+jimmy
+jingle
+jingly
+jingo
+jingoism
+jingoist
+jinks
+jinx
+jitney
+jitter
+jitterbug
+jittery
+jive
+J&J
+Jo
+Joan
+Joann
+Joanna
+Joanne
+Joaquin
+job
+jobholder
+Jocelyn
+jock
+jockey
+jockstrap
+jocose
+jocular
+jocund
+jodhpur
+Jodi
+Jody
+Joe
+Joel
+joey
+jog
+joggle
+Johann
+Johannes
+Johannesburg
+Johansen
+Johanson
+john
+Johnny
+johnnycake
+Johnson
+Johnston
+Johnstown
+join
+joinery
+joint
+joist
+joke
+Joliet
+Jolla
+jollity
+jolly
+jolt
+Jon
+Jonah
+Jonas
+Jonathan
+Jones
+jonquil
+Jordan
+Jordanian
+Jorge
+Jorgensen
+Jorgenson
+Jose
+Josef
+Joseph
+Josephine
+Josephson
+Josephus
+josh
+Joshua
+Josiah
+joss
+jostle
+jot
+joule
+jounce
+jouncy
+journal
+journalese
+journey
+joust
+Jovanovich
+Jove
+jovial
+Jovian
+jowl
+jowly
+joy
+Joyce
+joyous
+joyride
+joystick
+Jr.
+j's
+Juan
+Juanita
+jubilant
+jubilate
+jubilee
+Judah
+Judaic
+Judaism
+Judaist
+Judas
+Judd
+Jude
+judge
+judgment
+judicable
+judicatory
+judicature
+judicial
+judiciary
+judicious
+Judith
+judo
+Judson
+Judy
+jug
+jugate
+juggernaut
+juggle
+jugular
+juice
+Juilliard
+jujitsu
+juju
+jujube
+juke
+jukebox
+Jukes
+Jul.
+julep
+Jules
+Julia
+Julie
+julienne
+Juliet
+Julio
+Julius
+Julliard
+July
+jumble
+jumbo
+jump
+Jun.
+junco
+junction
+juncture
+June
+Juneau
+jungle
+jungly
+junior
+juniper
+junk
+junkerdom
+junket
+junketeer
+junkie
+Juno
+junta
+Jupiter
+Jura
+Jurassic
+jure
+juridic
+Juris
+jurisdiction
+jurisprudent
+jurisprudential
+jurist
+juror
+jury
+just
+justice
+justiciable
+justify
+Justine
+Justinian
+jut
+jute
+juvenal
+juvenile
+juxtapose
+juxtaposition
+Kaaba
+kabob
+Kabuki
+Kabul
+Kaddish
+kafir
+Kafka
+Kafkaesque
+Kahn
+kaiser
+Kajar
+Kalamazoo
+kale
+kaleidescope
+kaleidoscope
+kaleidoscopic
+kalends
+Kalmuk
+Kamchatka
+kamikaze
+Kampala
+kampong
+Kampuchea
+Kane
+kangaroo
+Kanji
+Kankakee
+Kansan
+Kansas
+Kant
+Kantian
+kaolin
+Kaplan
+kapok
+kappa
+kaput
+Karachi
+karakul
+Karamazov
+karate
+Karen
+Karl
+Karla
+karma
+Karol
+Karp
+karyotype
+Kashmir
+Kashmiri
+Kaskaskia
+Kate
+Katharine
+Katherine
+Kathleen
+Kathryn
+Kathy
+Katie
+Katmandu
+Katowice
+katydid
+Katz
+Kauffman
+Kaufman
+kava
+Kay
+kayak
+kayo
+Kazakhstan
+kazoo
+Keaton
+Keats
+kedge
+keel
+keelboat
+keelhaul
+keelson
+keen
+Keenan
+keep
+keepsake
+keg
+kegler
+Keith
+Keller
+Kelley
+Kellogg
+Kelly
+kelp
+Kelsey
+kelvin
+Kemp
+ken
+Kendall
+Kennan
+Kennecott
+Kennedy
+kennel
+Kenneth
+Kenney
+Kenny
+keno
+Kensington
+Kent
+Kenton
+Kentuckian
+Kentucky
+Kenya
+Kenyon
+kepi
+Kepler
+kept
+kerchief
+kerfuffle
+Kermit
+kern
+kernel
+kerosene
+Kerr
+kerry
+kerygma
+Kessler
+kestrel
+ketch
+ketchup
+ketone
+ketosis
+Kettering
+kettle
+kettledrum
+Kevin
+key
+keyboard
+keyed
+Keyes
+keyhole
+Keynes
+Keynesian
+keynote
+keypunch
+keystone
+keyway
+keyword
+khaki
+khan
+Khartoum
+khedive
+Khmer
+Khrushchev
+kibbutz
+kibbutzim
+kibitz
+kibitzing
+kibosh
+kick
+kickback
+kickoff
+kickshaw
+kid
+Kidd
+Kidde
+kiddie
+kidnap
+kidney
+Kieffer
+kielbasa
+Kiev
+Kiewit
+Kigali
+Kikuyu
+Kilgore
+kill
+killdeer
+killjoy
+kiln
+kilo
+kilohm
+kilt
+Kim
+Kimball
+Kimberly
+kimono
+kin
+kind
+kindergarten
+kindergartner
+kindhearted
+kindle
+kindred
+kine
+kinematic
+kinescope
+kinesic
+kinesthesis
+kinesthetic
+kinetic
+kinfolk
+king
+kingbird
+kingdom
+kingfish
+kingfisher
+kinglet
+kingpin
+Kingsbury
+Kingsley
+Kingston
+kink
+kinkajou
+Kinney
+kins
+Kinshasa
+Kinshasha
+kinship
+kiosk
+Kiowa
+Kipling
+kipper
+Kirby
+Kirchner
+Kirchoff
+Kirghiz
+Kirgizstan
+kirk
+Kirkland
+Kirkpatrick
+Kirov
+kirsch
+Kirsten
+kiss
+kissing
+kit
+Kitakyushu
+kitchen
+kitchenette
+kitchenware
+kite
+kith
+kitsch
+kitten
+kittenish
+kittiwake
+kittle
+kitty
+kiva
+Kiwanian
+Kiwanis
+kiwi
+Klan
+Klans
+klatch
+klatsch
+Klaus
+klaxon
+kleenex
+Klein
+kleptomania
+Kline
+Klux
+klystron
+km
+knack
+knap
+Knapp
+knapsack
+Knauer
+knave
+knavery
+knavish
+knead
+knee
+kneecap
+kneehole
+kneel
+knell
+knelt
+knew
+knick
+knickerbocker
+knickknack
+knife
+knifelike
+knight
+Knightsbridge
+knit
+knitwear
+knives
+knob
+knock
+knockdown
+knockout
+knoll
+knot
+knothole
+Knott
+knout
+know
+knoweth
+knowhow
+knowledge
+knowledgeable
+Knowles
+Knowlton
+known
+Knox
+Knoxville
+knuckle
+knuckleball
+knucklebone
+Knudsen
+Knudson
+knurl
+Knutsen
+Knutson
+koala
+Koch
+Kochab
+Kodachrome
+Kodak
+Kodiak
+Koenig
+Koenigsberg
+kohl
+kohlrabi
+kohlrabies
+kola
+kolkhoz
+Kong
+kook
+kooky
+kopeck
+Koppers
+Koran
+Korea
+kosher
+Kowalewski
+Kowalski
+kowtow
+kraal
+kraft
+Krakatoa
+Krakow
+Kramer
+krater
+Krause
+kraut
+Kremlin
+Kresge
+Krieger
+krill
+Kris
+Krishna
+Kristin
+Kristine
+krona
+Kronecker
+kroner
+Krueger
+Kruger
+Kruse
+krypton
+KS
+k's
+Ku
+kudos
+kudzu
+Kuhn
+kulak
+kumquat
+Kurd
+Kurdish
+Kurt
+kuru
+Kuwait
+Kuwaiti
+kvass
+kwashiorkor
+KY
+Kyle
+Kyoto
+kyrie
+Kyushu
+la
+lab
+Laban
+label
+labia
+labial
+labile
+lability
+labor
+laboratory
+laborious
+laborite
+Labour
+Labrador
+labyrinth
+labyrinthine
+lac
+laccolith
+lace
+lacerate
+Lacerta
+lacewing
+Lachesis
+lachrymal
+lachrymate
+lachrymose
+lack
+lackadaisic
+lackaday
+lackey
+lackluster
+laconic
+lacquer
+lacrosse
+lactase
+lactate
+lactic
+lactose
+lacuna
+lacunae
+lacustrine
+lad
+laddie
+laden
+ladle
+lady
+ladybird
+ladybug
+ladyfern
+ladyfinger
+Lafayette
+lag
+lager
+laggard
+lagniappe
+lagoon
+Lagos
+Lagrange
+Lagrangian
+Laguerre
+Lahore
+laic
+laid
+Laidlaw
+lain
+lair
+laird
+laissez
+laity
+lake
+lakefront
+Lakehurst
+lakeside
+Lally
+lam
+lama
+Lamar
+Lamarck
+Lamarckian
+lamasery
+lamb
+lambaste
+lambasting
+lambda
+lambert
+lame
+lamella
+lamellae
+lamellar
+lament
+lamentation
+lamina
+laminar
+laminate
+lamp
+lampblack
+lamplight
+lampoon
+lampoonery
+lamprey
+Lana
+Lancashire
+Lancaster
+lance
+lanceolate
+lancet
+land
+landau
+landfall
+landfill
+landform
+landhold
+Landis
+landlady
+landlocked
+landlord
+landlubber
+landmark
+landmass
+landowner
+Landry
+lands
+Landsat
+landscape
+landslide
+landward
+lane
+Lang
+Lange
+Langley
+Langmuir
+language
+languid
+languish
+languor
+languorous
+lank
+Lanka
+lanolin
+Lansing
+lantern
+lanthanide
+lanthanum
+lanyard
+Lao
+Laocoon
+Laos
+Laotian
+lap
+lapboard
+LAPD
+lapdog
+lapel
+lapidary
+Laplace
+Laplacian
+lappet
+lapse
+lapstrake
+lapwing
+Laramie
+larboard
+larcenist
+larcenous
+larceny
+larch
+lard
+Laredo
+lares
+large
+largemouth
+largess
+largesse
+larghetto
+largish
+largo
+lariat
+lark
+Larkin
+larkspur
+Larry
+Lars
+Larsen
+Larson
+larva
+larvae
+larval
+larvicide
+laryngeal
+larynges
+laryngitis
+laryngology
+laryngoscope
+laryngoscopic
+laryngoscopy
+larynx
+lasagna
+lascar
+lascivious
+lase
+lash
+lass
+lassie
+lassitude
+lasso
+last
+Laszlo
+latch
+latchkey
+latchstring
+late
+latecome
+lateen
+latent
+lateral
+Lateran
+laterite
+latex
+lath
+lathe
+lather
+Lathrop
+latifundium
+Latin
+Latinate
+latinize
+latish
+latitude
+latitudinal
+latitudinarian
+latitudinary
+latrine
+Latrobe
+latter
+lattice
+latticework
+latus
+Latvia
+laud
+laudanum
+laudatory
+Lauderdale
+Laue
+laugh
+laughingstock
+Laughlin
+laughter
+launch
+launder
+launderette
+laundress
+laundromat
+laundry
+Laura
+laureate
+laurel
+Lauren
+Laurence
+Laurent
+Laurentian
+Laurie
+Lausanne
+lava
+lavabo
+lavatory
+lave
+lavender
+Laverne
+lavish
+Lavoisier
+law
+lawbreak
+lawgive
+lawn
+Lawrence
+lawrencium
+Lawson
+lawsuit
+lawyer
+lax
+laxative
+lay
+layette
+layoff
+layout
+layover
+Layton
+layup
+Lazarus
+laze
+lazybones
+lea
+leach
+leachate
+lead
+leaden
+leadeth
+leadoff
+leads
+leaf
+leaflet
+league
+Leah
+leak
+leakage
+lean
+Leander
+Leanne
+leap
+leapfrog
+leapt
+Lear
+learn
+lease
+leasehold
+leash
+least
+leastwise
+leather
+leatherback
+leatherneck
+leatherwork
+leathery
+leave
+leaven
+Leavenworth
+Lebanese
+Lebanon
+lebensraum
+Lebesgue
+lecher
+lecherous
+lechery
+lecithin
+lectern
+lectionary
+lector
+lecture
+led
+lederhosen
+ledge
+lee
+leeboard
+leech
+leek
+leer
+leery
+leeward
+leeway
+left
+leftmost
+leftover
+leftward
+lefty
+leg
+legacy
+legal
+legalese
+legate
+legatee
+legato
+legend
+legendary
+Legendre
+legerdemain
+leghorn
+legible
+legion
+legionary
+legionnaire
+legislate
+legislature
+legit
+legitimacy
+legitimate
+legitimize
+Lego
+legume
+leguminous
+Lehigh
+Lehman
+Leigh
+Leighton
+Leila
+leisure
+leitmotif
+leitmotiv
+Leland
+lemma
+lemming
+lemon
+lemonade
+Lemuel
+lemur
+Len
+Lena
+lend
+lender
+length
+lengthen
+lengthways
+lengthwise
+lenient
+Lenin
+Leningrad
+Leninism
+Leninist
+lenity
+Lennox
+Lenny
+lens
+lent
+Lenten
+lenticular
+lentil
+lento
+Leo
+Leon
+Leona
+Leonard
+Leonardo
+Leone
+Leonid
+leonine
+leopard
+Leopold
+leotard
+leper
+lepidoptera
+leprechaun
+leprosy
+leprous
+lepton
+Leroy
+lesbian
+lesion
+Lesley
+Leslie
+Lesotho
+less
+lessee
+lessen
+lesson
+lessor
+lest
+Lester
+let
+letdown
+lethal
+lethargic
+lethargy
+Lethe
+Letitia
+letter
+letterhead
+letterpress
+Lettish
+lettuce
+letup
+leukemia
+leukemic
+leukocyte
+levee
+level
+levelheaded
+lever
+leverage
+Levi
+leviathan
+Levin
+Levine
+Levinson
+levitate
+Levite
+Leviticus
+Levitt
+levity
+levo
+levorotary
+levorotation
+levorotatory
+levy
+Lew
+lewd
+lewis
+lexical
+lexicography
+lexicon
+Lexington
+Leyden
+liable
+liaison
+liana
+liar
+lib
+libation
+Libby
+libel
+libelous
+liberal
+liberate
+Liberia
+libertarian
+libertine
+liberty
+libidinal
+libidinous
+libido
+librarian
+library
+librate
+librettist
+libretto
+Libreville
+Libya
+lice
+license
+licensee
+licensor
+licentious
+lichee
+lichen
+licit
+lick
+licorice
+lid
+lido
+lie
+Liechtenstein
+lied
+lief
+lien
+lieu
+lieutenant
+life
+lifeblood
+lifeboat
+lifeguard
+lifeline
+lifelong
+lifer
+lifesaver
+lifesaving
+lifespan
+lifestyle
+lifetime
+LIFO
+lift
+liftoff
+ligament
+ligamentary
+ligand
+ligate
+ligature
+Ligget
+Liggett
+light
+lighten
+lighterage
+lightface
+lightfast
+lighthearted
+lighthouse
+lightish
+lightning
+lightproof
+lightsome
+lightweight
+lignin
+lignite
+lignum
+like
+liken
+likewise
+Lila
+lilac
+Lilian
+Lilith
+Lillian
+Lillie
+lilliputian
+Lilly
+lilt
+lily
+Lima
+limb
+limbic
+limbo
+Limburger
+lime
+limelight
+limerick
+limestone
+limey
+limit
+limitation
+limn
+limnology
+limo
+limousine
+limp
+limpet
+limpid
+limpkin
+Lin
+linchpin
+Lincoln
+Lincolnesque
+Lind
+Linda
+lindane
+Lindberg
+Lindbergh
+linden
+Lindholm
+Lindquist
+Lindsay
+Lindsey
+Lindstrom
+line
+lineage
+lineal
+lineament
+linear
+lineation
+linebacker
+linen
+liner
+lineup
+linger
+lingerie
+lingo
+lingua
+lingual
+linguist
+liniment
+link
+linkage
+linkup
+Linnaean
+Linnean
+linoleum
+Linotype
+linseed
+lint
+lintel
+Linus
+lion
+Lionel
+lioness
+lionhearted
+lip
+lipid
+lipoma
+Lippincott
+lipread
+Lipschitz
+Lipscomb
+lipstick
+Lipton
+liquefaction
+liquefy
+liqueur
+liquid
+liquidate
+liquidus
+liquor
+lira
+Lisa
+Lisbon
+Lise
+lisle
+lisp
+Lissajous
+lissome
+list
+listen
+lit
+litany
+liter
+literacy
+literal
+literary
+literate
+literati
+literature
+lithe
+lithic
+lithium
+lithograph
+lithography
+lithology
+lithosphere
+lithospheric
+Lithuania
+litigant
+litigate
+litigious
+litmus
+litter
+litterbug
+little
+littleneck
+Littleton
+Litton
+littoral
+liturgic
+liturgy
+live
+livelong
+liven
+Livermore
+Liverpool
+liverwort
+liverwurst
+livery
+livestock
+liveth
+livid
+Livingston
+livre
+Liz
+lizard
+Lizzie
+llama
+Lloyd
+lo
+load
+loaf
+loam
+loan
+loath
+loathe
+loathsome
+loaves
+lob
+lobar
+lobate
+lobby
+lobe
+loblolly
+lobo
+lobotomize
+lobotomy
+lobscouse
+lobster
+lobular
+lobule
+local
+locale
+locate
+loci
+lock
+Locke
+locket
+Lockhart
+Lockheed
+Lockian
+lockjaw
+locknut
+lockout
+locksmith
+lockstep
+lockstitch
+lockup
+Lockwood
+loco
+locomotion
+locomotor
+locus
+locust
+locution
+locutor
+lode
+lodestone
+lodge
+lodgepole
+Lodowick
+Loeb
+l'oeil
+loess
+loft
+log
+Logan
+logarithm
+logarithmic
+logbook
+loge
+loggerhead
+loggia
+logic
+logician
+logistic
+logjam
+logo
+logorrhea
+logotype
+logroll
+logy
+Lohengrin
+loin
+loincloth
+Loire
+Lois
+loiter
+Loki
+Lola
+loll
+lollipop
+lolly
+lollygag
+lollypop
+Lomb
+London
+Londoner
+lone
+lonely
+lonesome
+long
+longboat
+longbow
+longevity
+Longfellow
+longhair
+longhand
+longhorn
+longhouse
+longish
+longitude
+longitudinal
+longleg
+longshoreman
+longshoremen
+longspur
+longstanding
+longtime
+longueur
+Lonnie
+look
+lookout
+lookup
+loom
+Loomis
+loon
+loop
+loophole
+loopy
+loose
+looseleaf
+loosen
+loosestrife
+loot
+lop
+lope
+Lopez
+lopsided
+loquacious
+loquacity
+loquat
+loran
+lord
+lordling
+lordosis
+lore
+Lorelei
+Loren
+Lorene
+Loretta
+lorgnette
+Lorinda
+loris
+Lorraine
+lorry
+Los
+lose
+loss
+lost
+lot
+lothario
+lotion
+Lotte
+lottery
+Lottie
+lotto
+lotus
+Lou
+loud
+loudmouth
+loudspeak
+Louis
+Louisa
+Louise
+Louisiana
+Louisville
+lounge
+Lounsbury
+loupe
+Lourdes
+louse
+lout
+loutish
+louver
+Louvre
+love
+lovebird
+Lovelace
+Loveland
+lovelorn
+lovely
+lovemaking
+lovesick
+loveth
+low
+lowborn
+lowboy
+lowbrow
+lowdown
+Lowe
+Lowell
+lower
+lowerclass
+lowermost
+Lowery
+lowland
+Lowry
+lox
+loxodrome
+loyal
+loyalty
+lozenge
+LP
+LPG
+l's
+LSI
+Ltd.
+LTV
+luau
+lubber
+Lubbock
+lube
+Lubell
+lubricant
+lubricate
+lubricious
+lubricity
+Lucas
+lucent
+Lucerne
+Lucia
+Lucian
+lucid
+Lucifer
+Lucille
+Lucinda
+Lucite
+Lucius
+luck
+lucrative
+lucre
+Lucretia
+Lucretius
+lucubrate
+Lucy
+Luddite
+ludicrous
+Ludlow
+Ludwig
+luff
+Lufthansa
+Luftwaffe
+lug
+luge
+luggage
+lugsail
+lugubrious
+Luis
+Luke
+lukewarm
+Lula
+lull
+lullaby
+lulu
+lumbago
+lumbar
+lumber
+lumberjack
+lumberyard
+lumen
+luminaire
+luminal
+luminance
+luminary
+luminesce
+luminescent
+luminiferous
+luminosity
+luminous
+lummox
+lump
+lumpen
+lumpish
+Lumpur
+luna
+lunacy
+lunar
+lunate
+lunatic
+lunch
+luncheon
+luncheonette
+lunchroom
+lunchtime
+Lund
+Lundberg
+Lundquist
+lune
+lunette
+lung
+lunge
+lungfish
+lunker
+lunkhead
+lupine
+Lura
+lurch
+lure
+lurid
+lurk
+Lusaka
+luscious
+lush
+lust
+luster
+lustrous
+lutanist
+lute
+luteal
+lutetium
+Luther
+Lutheran
+Lutz
+lux
+luxe
+Luxembourg
+luxuriant
+luxuriate
+luxurious
+luxury
+Luzon
+lyceum
+lycopodium
+Lydia
+lye
+lying
+Lykes
+Lyle
+Lyman
+Lyme
+lymph
+lymphatic
+lymphocyte
+lymphocytic
+lymphoma
+lynch
+Lynchburg
+Lynda
+Lynn
+Lynne
+lynx
+Lyon
+lyonnaise
+Lyons
+Lyra
+lyre
+lyrebird
+lyric
+lyricism
+lyse
+Lysenkoism
+lysergic
+lyses
+lysine
+lysis
+ma
+ma'am
+Mabel
+Mac
+macabre
+macadam
+macadamia
+macaque
+macaroni
+macaroon
+MacArthur
+Macassar
+macaw
+Macbeth
+MacDonald
+mace
+Macedon
+Macedonia
+macerate
+MacGregor
+Mach
+machete
+Machiavelli
+Machiavellian
+machicolate
+machination
+machine
+machinery
+machismo
+macho
+macintosh
+Mack
+MacKenzie
+mackerel
+Mackey
+Mackinac
+mackinaw
+mackintosh
+MacMillan
+Macon
+macrame
+macro
+macrocosm
+macroeconomic
+macromolecular
+macromolecule
+macron
+macrophage
+macroprocessor
+macroscopic
+macrostructure
+maculate
+Macy
+mad
+Madagascar
+madam
+Madame
+madcap
+madden
+maddish
+Maddox
+made
+Madeira
+Madeleine
+Madeline
+mademoiselle
+madhouse
+Madison
+Madonna
+madras
+Madrid
+madrigal
+Madsen
+Mae
+maelstrom
+maestoso
+maestro
+Mafia
+magazine
+magdalen
+Magdalene
+Magellan
+magenta
+Maggie
+maggot
+magi
+magic
+magician
+magisterial
+magistracy
+magistrate
+magma
+magmatic
+magna
+magnanimity
+magnanimous
+magnate
+magnesia
+magnesite
+magnesium
+magnet
+magnetic
+magnetite
+magneto
+magneton
+magnetron
+magnificat
+magnificent
+magnify
+magniloquent
+magnitude
+magnolia
+magnum
+Magnuson
+Magog
+magpie
+Magruder
+maguey
+Magyar
+maharaja
+maharajah
+maharani
+mahatma
+Mahayana
+Mahayanist
+mahogany
+Mahoney
+mahout
+maid
+maiden
+maidenhair
+maidenhead
+maidservant
+Maier
+mailbag
+mailbox
+maim
+main
+Maine
+mainland
+mainline
+mainmast
+mainsail
+mainsheet
+mainspring
+mainstay
+mainstream
+maintain
+maintenance
+maintop
+maitre
+maize
+majestic
+majesty
+major
+majorette
+majuscule
+make
+makeshift
+makeup
+Malabar
+Malachi
+malachite
+maladapt
+maladaptation
+maladaptive
+maladjust
+maladjustive
+maladminister
+maladministration
+maladroit
+malady
+Malagasy
+malaise
+malaprop
+malaria
+malarial
+malarkey
+malathion
+Malawi
+Malay
+Malaya
+Malaysia
+Malcolm
+malconduct
+malcontent
+Malden
+maldistribute
+Maldive
+male
+maledict
+maledictory
+malefaction
+malefactor
+maleficent
+malemute
+malevolent
+malfeasant
+malformation
+malformed
+malfunction
+malgre
+Mali
+malice
+malicious
+malign
+malignant
+malinger
+mall
+mallard
+malleable
+mallet
+Mallory
+mallow
+malnourished
+malnutrition
+malocclusion
+malodorous
+Malone
+Maloney
+malposed
+malpractice
+Malraux
+malt
+Malta
+Maltese
+Malthusian
+Malton
+maltose
+maltreat
+mama
+mamba
+mambo
+Mamie
+mamma
+mammal
+mammalian
+mammalogy
+mammary
+mammograph
+mammography
+mammon
+mammoth
+mammy
+man
+mana
+manacle
+manage
+manageable
+managerial
+Managua
+Manama
+manatee
+Manchester
+Manchu
+mandala
+mandamus
+mandarin
+mandate
+mandible
+mandolin
+mandrake
+mandrel
+mandrill
+Mandy
+mane
+maneuver
+Manfred
+manganese
+mange
+mangle
+mango
+mangrove
+manhandle
+Manhattan
+manhole
+manhunt
+mania
+maniacal
+manic
+manicotti
+manicure
+manifest
+manifestation
+manifesto
+manifold
+manikin
+manila
+manioc
+maniple
+manipulable
+manipulate
+Manitoba
+mankind
+Manley
+Mann
+manna
+mannequin
+mannerism
+mannikin
+mannish
+manometer
+manor
+manorial
+manpower
+manque
+manrope
+Mans
+mansard
+manse
+manservant
+Mansfield
+mansion
+manslaughter
+mantel
+mantic
+mantilla
+mantis
+mantissa
+mantle
+mantlepiece
+mantra
+mantrap
+manual
+Manuel
+manufactory
+manufacture
+manumission
+manumit
+manure
+manuscript
+Manville
+Manx
+many
+manzanita
+Mao
+Maori
+map
+maple
+mar
+marathon
+maraud
+maravedi
+marble
+Marc
+Marceau
+Marcel
+Marcella
+Marcello
+march
+marchioness
+Marcia
+Marco
+Marconi
+Marcus
+Marcy
+Mardi
+mare
+Margaret
+margarine
+margay
+marge
+Margery
+Margie
+margin
+marginal
+marginalia
+Margo
+Margot
+Marguerite
+maria
+mariachi
+Marian
+Marianne
+Marie
+Marietta
+marigold
+marijuana
+Marilyn
+marimba
+Marin
+marina
+marinade
+marinate
+marine
+Marino
+Mario
+Marion
+marionette
+marital
+maritime
+marjoram
+Marjorie
+Marjory
+mark
+markdown
+market
+marketeer
+marketplace
+Markham
+Markov
+Markovian
+marks
+markup
+marl
+Marlboro
+Marlborough
+Marlene
+marlin
+marline
+marlinspike
+Marlowe
+marly
+marmalade
+marmoset
+marmot
+maroon
+marque
+marquee
+marquess
+marquetry
+Marquette
+marquis
+marquise
+marriage
+marriageable
+married
+Marrietta
+Marriott
+marrow
+marrowbone
+marry
+Marseilles
+marsh
+Marsha
+marshal
+Marshall
+marshland
+marshmallow
+marsupial
+mart
+marten
+martensite
+Martha
+martial
+Martian
+martin
+martinet
+Martinez
+martingale
+martini
+Martinique
+Martinson
+Marty
+martyr
+martyrdom
+Marva
+marvel
+marvelous
+Marvin
+Marx
+Marxian
+Mary
+Maryann
+Maryland
+marzipan
+mascara
+mascot
+masculine
+maser
+Maseru
+mash
+mashie
+mask
+masochism
+masochist
+mason
+Masonic
+Masonite
+masonry
+masque
+masquerade
+mass
+Massachusetts
+massacre
+massacring
+massage
+masseur
+Massey
+massif
+massive
+mast
+mastectomy
+mastermind
+masterpiece
+masterwork
+mastery
+masthead
+mastic
+masticate
+mastiff
+mastitis
+mastodon
+mastoid
+mastoidectomy
+masturbate
+mat
+matador
+match
+matchbook
+matchbox
+matchlock
+matchstick
+mate
+Mateo
+mater
+material
+materiel
+maternal
+maternity
+matey
+math
+mathematic
+mathematician
+Mathematik
+Mathews
+Mathewson
+Mathias
+Mathieu
+Mathis
+Matilda
+matinal
+matinee
+matins
+Matisse
+matriarch
+matriarchal
+matriarchs
+matriarchy
+matrices
+matricide
+matriculate
+matrilineal
+matrimonial
+matrimony
+matrix
+matron
+Matson
+Matt
+matte
+Matthew
+Matthews
+Mattie
+mattock
+mattress
+Mattson
+maturate
+mature
+maudlin
+maul
+maunder
+Maureen
+Maurice
+Maurine
+Mauritania
+Mauritius
+mausoleum
+mauve
+maverick
+Mavis
+maw
+mawkish
+Mawr
+Max
+maxilla
+maxim
+maxima
+maximal
+Maximilian
+maximum
+Maxine
+maxwell
+Maxwellian
+may
+Maya
+mayapple
+maybe
+Mayer
+mayest
+Mayfair
+mayflower
+mayfly
+mayhap
+mayhem
+Maynard
+mayn't
+Mayo
+mayonnaise
+mayor
+mayoral
+mayoralty
+Mays
+mayst
+Mazda
+maze
+mazurka
+MBA
+Mbabane
+MC
+McAdams
+McAllister
+McBride
+McCabe
+McCall
+McCann
+McCarthy
+McCarty
+McCauley
+McClain
+McClellan
+McClure
+McCluskey
+McConnel
+McConnell
+McCormick
+McCoy
+McCracken
+McCullough
+McDaniel
+McDermott
+McDonald
+McDonnell
+McDougall
+McDowell
+McElroy
+McFadden
+McFarland
+McGee
+McGill
+McGinnis
+McGovern
+McGowan
+McGrath
+McGraw
+McGregor
+McGuire
+McHugh
+McIntosh
+McIntyre
+McKay
+McKee
+McKenna
+McKenzie
+McKeon
+McKesson
+McKinley
+McKinney
+McKnight
+McLaughlin
+McLean
+McLeod
+McMahon
+McMillan
+McMullen
+McNally
+McNamara
+McNaughton
+McNeil
+McPherson
+M.D.
+MD
+me
+mead
+Meade
+meadow
+meadowland
+meadowlark
+meadowsweet
+meager
+meal
+mealtime
+mealy
+mealybug
+mean
+meander
+meaning
+meant
+meantime
+meanwhile
+measle
+measly
+measure
+meat
+mecca
+mechanic
+mechanician
+mechanism
+mechanist
+mechanize
+mecum
+medal
+medallion
+meddle
+meddlesome
+Medea
+media
+medial
+median
+mediate
+mediatrix
+medic
+medicable
+Medicaid
+medicament
+Medicare
+medicate
+Medici
+medicinal
+medicine
+medico
+medieval
+mediocre
+mediocrity
+meditate
+Mediterranean
+medium
+medley
+medusa
+meek
+meet
+meetinghouse
+Meg
+megalith
+megalithic
+megalomania
+megalomanic
+megalopolis
+megalopolitan
+megohm
+Meier
+meiosis
+meiotic
+Meistersinger
+Mekong
+Mel
+melamine
+melancholia
+melancholic
+melancholy
+Melanesia
+melange
+melanic
+Melanie
+melanin
+melanism
+melanist
+melanoma
+Melbourne
+Melcher
+meld
+melee
+Melinda
+meliorate
+meliorism
+meliorist
+Melissa
+mellifluent
+mellifluous
+Mellon
+mellow
+melodeon
+melodic
+melodious
+melodrama
+melodramatic
+melody
+melon
+Melpomene
+melt
+meltdown
+meltwater
+Melville
+Melvin
+member
+membrane
+membranous
+memento
+memo
+memoir
+memorabilia
+memorable
+memoranda
+memorandum
+memorial
+memorium
+memorize
+memory
+Memphis
+men
+menace
+menage
+menagerie
+menarche
+mend
+mendacious
+mendacity
+mendelevium
+Mendelian
+Mendelssohn
+mendicant
+Menelaus
+menfolk
+menhaden
+menhir
+menial
+meningitis
+meniscus
+Menlo
+Mennonite
+menopause
+menorah
+Menshevik
+menstrual
+menstruate
+mensurable
+mensuration
+mental
+menthol
+mention
+mentor
+menu
+Menzies
+meow
+Mephistopheles
+mercantile
+mercaptan
+Mercator
+Mercedes
+mercenary
+mercer
+merchandise
+merchant
+mercilessly
+Merck
+mercurate
+mercurial
+mercuric
+mercurous
+mercury
+mercy
+mere
+Meredith
+meretricious
+merganser
+merge
+meridian
+meridional
+meringue
+merino
+merit
+meritorious
+Merle
+merlin
+mermaid
+merman
+Merriam
+Merrill
+Merrimack
+merriment
+Merritt
+merry
+merrymaker
+merrymaking
+Mervin
+mesa
+mescal
+mescaline
+mesdames
+mesenteric
+mesh
+mesmeric
+mesmerism
+mesmerize
+mesomorph
+mesomorphic
+meson
+Mesopotamia
+mesosphere
+Mesozoic
+mesquite
+mess
+message
+messenger
+messiah
+messianic
+messieurs
+Messrs.
+mestiza
+mestizo
+met
+metabolic
+metabolism
+metabolite
+metacarpal
+metal
+metallic
+metalliferous
+metallize
+metallography
+metalloid
+metallurgic
+metallurgist
+metallurgy
+metalware
+metalwork
+metamorphic
+metamorphism
+metamorphose
+metamorphosis
+metaphor
+metaphoric
+metastasize
+metatarsal
+Metcalf
+mete
+meteor
+meteoric
+meteorite
+meteoroid
+meteorology
+meter
+methacrylate
+methadone
+methane
+methanol
+methinks
+method
+methodic
+Methodism
+Methodist
+methodology
+methought
+Methuen
+Methuselah
+methyl
+methylate
+methylene
+meticulous
+metier
+metonymy
+metope
+metric
+metro
+metrology
+metronome
+metropolis
+metropolitan
+mettle
+mettlesome
+Metzler
+mew
+Mexican
+Mexico
+Meyer
+Meyers
+mezzanine
+mezzo
+MGM
+mho
+mi
+Miami
+miasma
+miasmal
+miasmic
+mica
+Micah
+mice
+Michael
+Michel
+Michelangelo
+Michele
+Michelin
+Michelle
+Michelson
+Michigan
+Mickelson
+mickey
+micro
+microbial
+microbic
+microcosm
+microfiche
+micrography
+micron
+Micronesia
+microscopy
+mid
+Midas
+middle
+middlebrow
+Middlebury
+Middlesex
+Middleton
+Middletown
+middleweight
+midge
+midriff
+midst
+midterm
+midwifery
+mien
+miff
+Mifflin
+might
+mightn't
+mignon
+migraine
+migrant
+migrate
+Miguel
+mikado
+mike
+mil
+milady
+Milan
+milch
+mild
+mildew
+Mildred
+mile
+mileage
+milepost
+milestone
+milieu
+militant
+militarism
+militarist
+militarize
+military
+militate
+militia
+milk
+milkmaid
+milkshake
+milksop
+milkweed
+mill
+Millard
+millenarian
+millenary
+millennia
+millennial
+millennium
+miller
+millet
+Millie
+Millikan
+milliner
+millinery
+million
+millionaire
+millions
+millionth
+millipede
+millpond
+millrace
+millstone
+millstream
+millwork
+millwright
+milo
+milord
+milt
+Milton
+Miltonic
+Milwaukee
+mime
+mimeo
+mimeograph
+mimesis
+mimetic
+Mimi
+mimic
+mimicked
+mimicking
+mimicry
+mimosa
+mina
+minaret
+minatory
+mince
+mincemeat
+mind
+Mindanao
+mindset
+mine
+minefield
+minelayer
+mineral
+mineralogy
+Minerva
+minestrone
+minesweep
+minesweeper
+Ming
+mingle
+mini
+miniature
+minim
+minima
+minimal
+minimax
+minimum
+minion
+minister
+ministerial
+ministration
+ministry
+miniver
+mink
+Minneapolis
+Minnesota
+Minnie
+minnow
+Minoan
+minor
+Minos
+Minotaur
+Minsky
+minstrel
+minstrelsy
+mint
+minuend
+minuet
+minus
+minuscule
+minute
+minutia
+minutiae
+minx
+Miocene
+Mira
+miracle
+miraculous
+mirage
+Miranda
+mire
+Mirfak
+Miriam
+mirror
+mirth
+MIRV
+miry
+misanthrope
+miscegenation
+miscellanea
+miscellaneous
+miscellany
+mischievous
+miscible
+miscreant
+miser
+miserable
+misericord
+misery
+mishmash
+misnomer
+misogamy
+misogynic
+misogynist
+misogynous
+misogyny
+misprision
+mispronunciation
+miss
+missal
+misshapen
+missile
+missileer
+missilery
+mission
+missionary
+Mississippi
+Mississippian
+Missoula
+Missouri
+Missy
+mist
+mistletoe
+mistral
+misutilize
+MIT
+Mitchell
+mite
+miter
+MITI
+miticide
+mitigate
+mitochondria
+mitosis
+mitral
+Mitsubishi
+mitt
+mitten
+mitzvah
+mix
+mixture
+mixup
+Mizar
+mizzen
+mizzenmast
+MN
+mnemonic
+MO
+moa
+moan
+moat
+mob
+Mobil
+mobile
+mobility
+mobocracy
+mobster
+moccasin
+mocha
+mock
+mockery
+mockingbird
+mockup
+modal
+mode
+model
+modem
+moderacy
+moderate
+moderato
+modern
+modest
+Modesto
+modesty
+modicum
+modify
+modish
+modular
+modulate
+module
+moduli
+modulo
+modulus
+modus
+Moe
+Moen
+Mogadiscio
+mogul
+mohair
+Mohammed
+Mohammedan
+Mohawk
+Mohican
+Mohr
+moiety
+Moines
+Moira
+moire
+Moiseyev
+moist
+moisten
+moisture
+Mojave
+mola
+molal
+molar
+molasses
+mold
+moldboard
+Moldova
+mole
+molecular
+molecule
+molehill
+moleskin
+molest
+molestation
+Moliere
+Moline
+moll
+mollify
+mollusc
+molluscan
+mollusk
+Molly
+mollycoddle
+Moloch
+molt
+molten
+molto
+Moluccas
+molybdate
+molybdenite
+molybdenum
+mom
+moment
+momenta
+momentary
+momentous
+momentum
+mommy
+Mon.
+Mona
+Monaco
+monad
+monadic
+monadnock
+monarch
+monarchial
+monarchic
+monarchs
+monarchy
+monasterial
+monastery
+monastic
+monatomic
+monaural
+Monday
+monel
+monetarism
+monetarist
+monetary
+money
+moneybags
+moneylender
+monger
+Mongol
+Mongolia
+mongolism
+Mongoloid
+mongoose
+mongrel
+Monica
+monicker
+monied
+monies
+moniker
+monism
+monist
+monitor
+monk
+monkey
+monkeyflower
+monkeyshine
+monkish
+Monmouth
+Monoceros
+monochromatic
+monochromator
+monocle
+monocotyledon
+monocular
+monogamous
+monogamy
+monogynous
+monogyny
+monolith
+monologist
+monologue
+monomer
+monomeric
+monomial
+Monongahela
+mononucleosis
+monophony
+monopoly
+monotheism
+monotheist
+monotonous
+monoxide
+Monroe
+Monrovia
+Mons
+Monsanto
+monsieur
+monsignor
+monsoon
+monster
+monstrosity
+monstrous
+Mont
+montage
+Montague
+Montana
+Montclair
+monte
+Montenegrin
+Monterey
+Monteverdi
+Montevideo
+Montgomery
+month
+Monticello
+Montmartre
+Montpelier
+Montrachet
+Montreal
+Monty
+monument
+moo
+mooch
+mood
+moon
+moonbeam
+Mooney
+moonlet
+moonlight
+moonlit
+moonrise
+moonscape
+moonset
+moonshine
+moonstone
+moonstruck
+moor
+moorage
+Moore
+Moorish
+moose
+moot
+mop
+mope
+moppet
+moraine
+moral
+morale
+Moran
+morass
+moratorium
+Moravia
+morbid
+mordant
+more
+morel
+Moreland
+moreover
+Moresby
+Morgan
+morganatic
+morgue
+Moriarty
+moribund
+Morley
+Mormon
+morn
+Moroccan
+morocco
+moron
+moronic
+morose
+morph
+morpheme
+morphemic
+morphine
+morphogenesis
+morphogenetic
+morphology
+morphophonemic
+Morrill
+morris
+Morrison
+Morrissey
+Morristown
+morrow
+Morse
+morsel
+mort
+mortal
+mortar
+mortarboard
+mortem
+mortgage
+mortgagee
+mortgagor
+mortician
+mortify
+Mortimer
+mortise
+Morton
+mortuary
+mosaic
+Moscow
+Moser
+Moses
+Moslem
+mosque
+mosquito
+mosquitoes
+moss
+mossback
+most
+mot
+mote
+motel
+motet
+moth
+mothball
+mother
+motherland
+motif
+motile
+motion
+motivate
+motley
+motoneuron
+motor
+motorboat
+motorcade
+motorcar
+motorcycle
+Motorola
+mottle
+motto
+mottoes
+Moulton
+mound
+mount
+mountain
+mountaineer
+mountainous
+mountainside
+mountaintop
+mountebank
+Mountie
+mourn
+mouse
+mousse
+moustache
+mouth
+mouthpiece
+mouthwash
+Mouton
+move
+movie
+mow
+mown
+moxie
+Moyer
+Mozambique
+Mozart
+mozzarella
+MPH
+Mr.
+Mrs.
+Ms.
+m's
+Mt.
+mu
+much
+mucilage
+mucilaginous
+muck
+muckrake
+mucosa
+mucous
+mucus
+mud
+Mudd
+muddle
+muddlehead
+muddy
+mudguard
+mudslide
+mudsling
+Mueller
+Muenster
+muezzin
+muff
+muffin
+muffle
+mufti
+mug
+mugwump
+Muir
+Mukden
+mukluk
+mulatto
+mulattoes
+mulberry
+mulch
+mulct
+mule
+mulish
+mull
+mullah
+mullein
+mullen
+mullet
+mulligan
+mulligatawny
+mullion
+multi
+multifarious
+multiformity
+multimedia
+multinomial
+multiphasic
+multiple
+multiplet
+multiplex
+multiplexor
+multipliable
+multiplicable
+multiplicand
+multiplication
+multiplicity
+multiply
+multitude
+multitudinous
+mum
+mumble
+mumbo
+Mumford
+mummify
+mummy
+mumps
+munch
+Muncie
+mundane
+mung
+Munich
+municipal
+munificent
+munition
+Munson
+muon
+Muong
+mural
+murder
+murderess
+murderous
+muriatic
+Muriel
+murine
+murk
+murmur
+murmurous
+Murphy
+Murray
+murre
+muscat
+muscatel
+muscle
+muscovite
+Muscovy
+muscular
+musculature
+muse
+musette
+museum
+mush
+mushroom
+music
+musicale
+musician
+musicology
+musk
+Muskegon
+muskellunge
+musket
+musketeer
+musketry
+muskmelon
+muskoxen
+muskrat
+Muslim
+muslin
+muss
+mussel
+must
+mustache
+mustachio
+mustang
+mustard
+mustn't
+mutagen
+mutagenic
+mutandis
+mutant
+mutate
+mutatis
+mute
+mutilate
+mutineer
+mutinous
+mutiny
+mutt
+mutter
+mutton
+mutual
+mutuel
+Muzak
+muzhik
+Muzo
+muzzle
+muzzy
+my
+Myanmar
+mycelium
+Mycenae
+Mycenaean
+mycology
+mycophagous
+myeline
+myeloid
+Myers
+mylar
+mynah
+Mynheer
+myocardial
+myocardium
+myoglobin
+myopia
+myopic
+myosin
+Myra
+myriad
+myrmidon
+Myrna
+Myron
+myrrh
+myrtle
+myself
+mysterious
+mystery
+mystic
+mystify
+mystique
+myth
+mythic
+mythologize
+mythology
+mythopoeic
+myxomatosis
+NAACP
+nab
+Nabisco
+nabla
+nabob
+nacelle
+nacho
+nacreous
+Nadia
+Nadine
+nadir
+nag
+Nagasaki
+Nagoya
+Nagy
+Nahum
+naiad
+nail
+Nair
+Nairobi
+naive
+naivete
+naked
+Nam
+name
+nameable
+nameplate
+namesake
+Namibia
+Nan
+Nancy
+Nanette
+Nanking
+nanny
+Nantucket
+Naomi
+nap
+napalm
+nape
+naphtha
+naphthalene
+napkin
+Naples
+napoleon
+Napoleonic
+Narbonne
+narcissism
+narcissist
+narcissus
+narcolepsy
+narcoleptic
+narcosis
+narcotic
+narcotize
+nares
+Narragansett
+narrate
+narrow
+narrowish
+narthex
+narwhal
+nary
+NASA
+nasal
+nascent
+Nash
+Nashua
+Nashville
+Nassau
+nasturtium
+nasty
+Nat
+natal
+Natalie
+natation
+natatorium
+natatory
+Natchez
+Nathan
+Nathaniel
+nation
+nationwide
+NATO
+natter
+natty
+natural
+nature
+naturopath
+naturopathy
+naught
+naughty
+nausea
+nauseate
+nauseous
+nauseum
+nautical
+nautilus
+Navajo
+naval
+nave
+navel
+navigable
+navigate
+navvy
+navy
+nay
+naysay
+Nazarene
+Nazareth
+nazi
+nazify
+Naziism
+Nazism
+N.B.
+NBA
+NBC
+NBS
+NC
+NCAA
+NCAR
+NCR
+ND
+Ndjamena
+NE
+Neal
+Neanderthal
+neap
+Neapolitan
+near
+nearby
+nearsighted
+neat
+neath
+Nebraska
+Nebuchadnezzar
+nebula
+nebulae
+nebular
+nebulize
+nebulosity
+nebulous
+necessary
+necessitate
+necessity
+neck
+neckerchief
+neckerchieves
+necklace
+neckline
+necktie
+necrology
+necromancer
+necromancy
+necromantic
+necrophagous
+necrophilia
+necropolis
+necropsy
+necrosis
+necrotic
+nectar
+nectarine
+Ned
+nee
+need
+Needham
+needle
+needlecraft
+needlepoint
+needlework
+needn't
+ne'er
+nefarious
+Neff
+negate
+neglect
+negligee
+negligent
+negligible
+negotiable
+negotiant
+negotiate
+Negress
+Negro
+Negroes
+negroid
+negrophile
+negrophobe
+Nehemiah
+Nehru
+neigh
+neighbor
+Neil
+neither
+Nell
+Nellie
+Nelsen
+nelson
+nematode
+nemeses
+nemesis
+Neocene
+neoclassic
+neoconservative
+neodymium
+neoliberal
+neolithic
+neologism
+neology
+neomycin
+neon
+neonatal
+neonate
+neonatology
+neoorthodox
+neoorthodoxy
+neophyte
+neoprene
+neotenic
+neoteny
+Nepal
+Nepali
+nepenthe
+nephew
+nepotism
+Neptune
+Neptunian
+neptunium
+nerd
+nereid
+Nero
+nerve
+nervous
+Ness
+nest
+nestle
+Nestor
+Nestorian
+net
+nether
+Netherlands
+netherworld
+nettle
+nettlesome
+network
+Neumann
+neural
+neuralgia
+neuralgic
+neurally
+neurasthenia
+neurasthenic
+neuritis
+neurology
+neuron
+neuronal
+neuroses
+neurosis
+neurotic
+neuter
+neutral
+neutrino
+neutron
+Neva
+Nevada
+never
+nevermore
+nevertheless
+Nevins
+new
+Newark
+Newbold
+newborn
+Newbury
+Newcastle
+newcomer
+newel
+Newell
+newfangled
+newfound
+Newfoundland
+newish
+newlywed
+Newman
+Newport
+news
+newsboy
+newsbreak
+newscast
+newsletter
+newsmonger
+newspaper
+newsprint
+newsreel
+newsroom
+newsstand
+Newsweek
+newsworthy
+newsy
+newt
+newton
+Newtonian
+next
+nexus
+NFL
+Nguyen
+NH
+NHL
+niacin
+Niagara
+Niamey
+nib
+nibble
+Nibelung
+niblick
+nibs
+Nicaragua
+nice
+Nicene
+nicety
+niche
+Nicholas
+Nicholls
+Nichols
+Nicholson
+nichrome
+nick
+nickel
+nickelodeon
+nickname
+Nicodemus
+Nicole
+Nicosia
+nicotine
+niece
+niello
+Nielsen
+Nielson
+Nietzsche
+nifty
+Niger
+Nigeria
+niggard
+niggardly
+nigger
+niggle
+nigh
+night
+nightcap
+nightclothes
+nightclub
+nightdress
+nightfall
+nightgown
+nighthawk
+nightingale
+nightjar
+nightlong
+nightmare
+nightmarish
+nightshade
+nightshirt
+nightstick
+nighttime
+nightwalker
+NIH
+nihilism
+nihilist
+Nike
+Nikkei
+Nikko
+Nikolai
+Nikon
+nil
+Nile
+nilpotent
+nim
+nimble
+nimbostratus
+nimbus
+NIMH
+Nimrod
+Nina
+nincompoop
+nine
+ninefold
+ninepence
+ninepin
+nineteen
+nineteenth
+ninetieth
+ninety
+Nineveh
+ninny
+ninth
+Niobe
+niobium
+nip
+nipple
+Nippon
+Nipponese
+nirvana
+nisei
+Nissan
+NIST
+nit
+nitpick
+nitrate
+nitric
+nitride
+nitrify
+nitrite
+nitrobenzene
+nitrocellulose
+nitrogen
+nitrogenous
+nitroglycerine
+nitrosamine
+nitrous
+nitty
+nitwit
+nix
+Nixon
+nizam
+NJ
+NM
+NNE
+NNW
+no
+NOAA
+Noah
+nob
+Nobel
+nobelium
+noble
+noblesse
+nobody
+nobody'd
+nocturnal
+nocturne
+nod
+nodal
+node
+nodular
+nodule
+Noel
+noetic
+nog
+noggin
+noise
+noisomely
+Nolan
+Noll
+nolo
+nomad
+nomadic
+nomenclature
+nomenklatura
+nominal
+nominate
+nominee
+nomograph
+nomography
+non
+nonagenarian
+nonagon
+nonce
+nonchalant
+noncom
+nondescript
+none
+nonesuch
+nonetheless
+nonfeasance
+nonpareil
+nonplus
+nonsensical
+noodle
+nook
+noon
+noonday
+noontide
+noontime
+noose
+nor
+Nora
+Norbert
+Nordhoff
+Nordic
+Nordstrom
+Noreen
+norepinephrine
+Norfolk
+noria
+norm
+Norma
+normal
+normalcy
+Norman
+Normandy
+normative
+Norris
+Norse
+north
+Northampton
+northbound
+northeast
+northeastern
+northeastward
+northerly
+northern
+northernmost
+northland
+northmost
+Northrop
+Northrup
+Northumberland
+northward
+northwest
+northwestern
+northwestward
+Norton
+Norwalk
+Norway
+Norwegian
+Norwich
+nose
+nosebag
+nosebleed
+nosedive
+nosegay
+nosepiece
+nosh
+nostalgia
+nostalgic
+Nostradamus
+Nostrand
+nostril
+nostrum
+not
+notarial
+notarize
+notary
+notate
+notch
+note
+notebook
+noteworthy
+nothing
+notice
+noticeable
+notify
+notion
+notoriety
+notorious
+Nottingham
+notwithstanding
+Nouakchott
+nougat
+noun
+nourish
+nouveau
+Nov.
+nova
+Novak
+novel
+novelette
+novella
+novelty
+November
+novena
+novice
+novitiate
+novo
+Novosibirsk
+now
+nowadays
+nowhere
+nowise
+noxious
+nozzle
+NRA
+NRC
+n's
+NSA
+NSF
+NTIS
+nu
+nuance
+nub
+nubbin
+nubble
+nubbly
+Nubia
+nubile
+nubility
+nucleant
+nuclear
+nucleate
+nuclei
+nucleic
+nucleoli
+nucleolus
+nucleon
+nucleonic
+nucleoplasm
+nucleoprotein
+nucleoside
+nucleotide
+nucleus
+nuclide
+nude
+nudge
+nugatory
+nugget
+nuisance
+nuisancy
+nuke
+null
+nullify
+numb
+number
+numbly
+numbskull
+numerable
+numeral
+numerate
+numeric
+Numerische
+numerology
+numerous
+numinous
+numismatic
+numismatist
+nun
+nuncio
+nunnery
+nuptial
+nurse
+nursemaid
+nursery
+nurserymaid
+nursling
+nurture
+nut
+nutant
+nutate
+nutcrack
+nuthatch
+nutmeg
+nutpick
+nutria
+nutrient
+nutriment
+nutrition
+nutritious
+nutshell
+nuzzle
+NV
+NW
+NWT
+NY
+N.Y.C.
+NYC
+nylon
+nymph
+nymphomania
+NYPD
+Nyquist
+NYSE
+NYU
+NZ
+oaf
+oafish
+Oahu
+oak
+oaken
+Oakland
+Oakley
+oakum
+oakwood
+oar
+oarlock
+oars
+oases
+oasis
+oat
+oath
+oatmeal
+Obadiah
+obbligato
+obduracy
+obdurate
+obedient
+obeisant
+obelisk
+Oberlin
+Oberon
+obese
+obey
+obfuscate
+obi
+obit
+obituary
+object
+objectify
+objectivity
+objet
+oblate
+obligate
+oblige
+obligee
+obligor
+oblique
+obliterate
+oblivion
+oblivious
+oblong
+obloquy
+obnoxious
+oboe
+oboist
+O'Brien
+obscene
+obscurant
+obscuration
+obscure
+obsequious
+obsequy
+observant
+observation
+observatory
+observe
+obsess
+obsession
+obsidian
+obsolesce
+obsolescent
+obsolete
+obstacle
+obstetric
+obstetrician
+obstinacy
+obstinate
+obstreperous
+obstruct
+obtain
+obtrude
+obtrusion
+obtuse
+obverse
+obviate
+obvious
+ocarina
+occasion
+occident
+occidental
+occipital
+occiput
+occlude
+occlusion
+occult
+occultation
+occupant
+occupation
+occupy
+occur
+occurrent
+ocean
+oceanarium
+oceangoing
+Oceania
+oceanic
+oceanography
+oceanside
+ocelli
+ocelot
+ocher
+o'clock
+O'Connell
+O'Connor
+Oct.
+octagon
+octagonal
+octahedra
+octahedral
+octahedron
+octal
+octameter
+octane
+octant
+octave
+Octavia
+octavo
+octennial
+octet
+octile
+octillion
+October
+octogenarian
+octopod
+octopus
+octoroon
+ocular
+oculist
+odd
+oddball
+oddment
+ode
+O'Dell
+Odessa
+odeum
+Odin
+odious
+odium
+Odom
+odometer
+O'Donnell
+odor
+odorant
+odoriferous
+odorous
+O'Dwyer
+Odysseus
+odyssey
+Oedipal
+Oedipus
+oenology
+o'er
+oersted
+oestrous
+oeuvre
+of
+off
+offal
+offbeat
+Offenbach
+offend
+offense
+offensive
+offer
+offertory
+offhand
+office
+officeholder
+officemate
+official
+officialdom
+officiate
+officio
+officious
+offload
+offprint
+offset
+offshoot
+offshore
+offspring
+offstage
+oft
+often
+oftentimes
+ofttimes
+Ogden
+ogee
+ogle
+ogre
+ogress
+oh
+O'Hare
+Ohio
+ohm
+ohmic
+ohmmeter
+oil
+oilcloth
+oilseed
+oilskin
+oilstone
+oily
+oink
+ointment
+OK
+okapi
+Okay
+OK'd
+Okinawa
+Oklahoma
+okra
+Olaf
+old
+olden
+Oldenburg
+oldie
+oldish
+Oldsmobile
+oldster
+oldy
+oleaginous
+oleander
+O'Leary
+olefin
+olefinic
+oleo
+oleomargarine
+olfaction
+olfactory
+Olga
+oligarch
+oligarchic
+oligarchs
+oligarchy
+Oligocene
+oligoclase
+oligopoly
+Olin
+olive
+Oliver
+Olivetti
+Olivia
+olivine
+Ollie
+Olsen
+Olson
+Olympia
+olympiad
+Olympic
+Olympus
+Omaha
+Oman
+omasum
+ombuds
+omega
+omelet
+omelette
+omen
+omicron
+ominous
+omission
+omit
+omnibus
+omnidirectional
+omnipotent
+omnipresent
+omnirange
+omniscient
+omnivore
+omnivorous
+on
+once
+oncology
+oncoming
+one
+Oneida
+O'Neil
+oneness
+onerous
+oneself
+onetime
+oneupmanship
+ongoing
+onion
+onionskin
+onlook
+only
+onomatopoeia
+onomatopoeic
+onomatopoetic
+Onondaga
+onrush
+onrushing
+onset
+onshore
+onslaught
+Ont.
+Ontario
+onto
+ontogenetic
+ontogeny
+ontology
+onus
+onward
+onyx
+oodles
+oolong
+oomph
+oops
+ooze
+op.
+opacity
+opal
+opalescent
+opaline
+opaque
+OPEC
+Opel
+open
+openhanded
+openhearted
+openmouthed
+openwork
+opera
+operable
+operago
+operand
+operant
+operate
+operatic
+operculum
+operetta
+Ophelia
+Ophiucus
+ophthalmic
+ophthalmology
+opiate
+opine
+opinion
+opinionated
+opium
+opossum
+Oppenheimer
+opponent
+opportune
+oppose
+opposite
+opposition
+oppress
+oppression
+oppressor
+opprobrious
+opprobrium
+opt
+optative
+optic
+optician
+optima
+optimal
+optimism
+optimist
+optimistic
+optimize
+optimum
+optoacoustic
+optoelectronic
+optoisolate
+optometrist
+optometry
+opulent
+opus
+opuscule
+or
+oracle
+oracular
+oral
+orange
+orangeade
+orangeroot
+orangery
+orangish
+orangutan
+orate
+oratorical
+oratorio
+oratory
+orb
+orbicular
+orbit
+orbital
+orchard
+orchestra
+orchestral
+orchestrate
+orchid
+orchis
+ordain
+ordeal
+order
+orderly
+ordinal
+ordinance
+ordinary
+ordinate
+ordnance
+Ordovician
+ordure
+ore
+oregano
+Oregon
+Oresteia
+Orestes
+organ
+organdy
+organic
+organismic
+organometallic
+orgasm
+orgiastic
+orgy
+orient
+oriental
+orientation
+orientations
+orienteer
+orifice
+origami
+origin
+original
+originate
+Orin
+Orinoco
+oriole
+Orion
+Orionid
+orison
+Orkney
+Orlando
+Orleans
+Orlon
+ormolu
+ornament
+ornamentation
+ornate
+ornately
+ornery
+ornithology
+orogenesis
+orogenic
+orogeny
+orography
+Orono
+orotund
+orphan
+orphanage
+Orpheus
+Orphic
+Orr
+orrery
+Ortega
+orthant
+orthicon
+ortho
+orthoclase
+orthodontic
+orthodontist
+orthodox
+orthodoxy
+orthogonal
+orthography
+orthonormal
+orthopedic
+orthophosphate
+orthorhombic
+orthotropic
+Ortiz
+Orville
+Orwell
+Orwellian
+oryx
+o's
+Osaka
+Osborn
+Osborne
+Oscar
+oscillate
+oscillograph
+oscillography
+oscilloscope
+osculate
+Osgood
+OSHA
+O'Shea
+Oshkosh
+osier
+Osiris
+Oslo
+osmium
+osmosis
+osmotic
+osprey
+osseous
+ossify
+ossuary
+ostensible
+ostensive
+ostentation
+ostentatious
+osteology
+osteomyelitis
+osteopath
+osteopathic
+osteoporosis
+ostracism
+ostracize
+ostracod
+Ostrander
+ostrich
+O'Sullivan
+Oswald
+Othello
+other
+otherness
+otherwise
+otherworld
+otherworldly
+otic
+otiose
+Otis
+Ott
+Ottawa
+otter
+Otto
+Ouagadougou
+ouch
+ought
+oughtn't
+Ouija
+ounce
+our
+ours
+ourselves
+oust
+out
+outermost
+outlandish
+outlaw
+outlawry
+outlier
+outpace
+outrageous
+outrance
+outshine
+outvote
+ouzel
+ouzo
+ova
+oval
+ovarian
+ovary
+ovate
+oven
+ovenbird
+over
+overhang
+overt
+overture
+Ovid
+oviduct
+oviform
+ovine
+oviparous
+ovipositor
+ovoid
+ovular
+ovulate
+ovum
+owe
+Owen
+Owens
+owing
+owl
+owlet
+owlish
+own
+ox
+oxalate
+oxalic
+oxbow
+Oxbridge
+oxcart
+oxen
+oxeye
+oxford
+oxidant
+oxidase
+oxidate
+oxide
+Oxnard
+oxtail
+oxygen
+oxygenate
+oxygenic
+oxymoron
+oxymoronic
+oyez
+oyster
+Ozark
+ozone
+pa
+Pablo
+Pabst
+PAC
+paca
+pace
+paceset
+pachyderm
+pachysandra
+pacific
+pacifism
+pacifist
+pacify
+pack
+package
+Packard
+packet
+packsack
+packsaddle
+pact
+pad
+paddle
+paddock
+paddy
+padlock
+padre
+paean
+pagan
+page
+pageant
+pageantry
+pageboy
+paginate
+pagoda
+paid
+pail
+pain
+Paine
+painstaking
+paint
+paintbrush
+pair
+pairwise
+paisley
+pajama
+Pakistan
+Pakistani
+pal
+palace
+paladin
+palanquin
+palatal
+palate
+palatial
+palatine
+palaver
+palazzi
+palazzo
+pale
+paleface
+paleobotany
+Paleocene
+paleography
+Paleolithic
+paleontology
+Paleozoic
+Palermo
+Palestine
+Palestinian
+palette
+palfrey
+palimpsest
+palindrome
+palindromic
+palisade
+pall
+palladia
+Palladian
+palladium
+Pallas
+pallbearer
+pallet
+palliate
+pallid
+pallor
+palm
+palmate
+palmetto
+palmistry
+Palmolive
+Palmyra
+Palo
+Palomar
+palomino
+palp
+palpable
+palpate
+palpitant
+palpitate
+palsy
+paltry
+Pam
+Pamela
+pampa
+pamper
+pamphlet
+pamphleteer
+pan
+panacea
+panache
+panama
+Panamanian
+panatela
+pancake
+Pancho
+panchromatic
+pancreas
+pancreatic
+panda
+Pandanus
+pandemic
+pandemonium
+pander
+Pandora
+pane
+panegyric
+panegyrist
+panel
+pang
+panhandle
+panic
+panicked
+panicking
+panicky
+panicle
+panjandrum
+panky
+pannier
+panoply
+panorama
+panoramic
+pansy
+pant
+pantaloon
+pantheism
+pantheist
+pantheon
+panther
+pantograph
+pantomime
+pantomimic
+pantry
+panty
+pantywaist
+panzer
+Paoli
+pap
+papa
+papacy
+papal
+papaw
+papaya
+paper
+paperback
+paperboard
+paperbound
+paperhang
+paperweight
+paperwork
+papery
+papillary
+papist
+papistry
+papoose
+Pappas
+pappy
+paprika
+Papua
+papyri
+papyrus
+par
+para
+parabola
+parabolic
+paraboloid
+parachute
+parade
+paradigm
+paradigmatic
+paradise
+paradisiac
+paradox
+paradoxic
+paraffin
+paragon
+Paraguay
+parakeet
+paralinguistic
+parallax
+parallel
+parallelepiped
+parallelism
+parallelogram
+paralytic
+paralyze
+Paramaribo
+paramecium
+parametrize
+paramour
+Paramus
+paranoia
+paranoid
+parapet
+paraphernalia
+paraplegia
+paraplegic
+parasite
+parasitology
+parasol
+parathion
+paraxial
+parboil
+parcel
+parch
+pardner
+pardon
+pare
+paregoric
+parent
+parentage
+parental
+parentheses
+parenthesis
+parenthesize
+parenthetic
+Pareto
+parfait
+pariah
+paribus
+parietal
+parimutuel
+Paris
+parish
+parishioner
+Parisian
+parity
+park
+parka
+Parke
+Parkinson
+parkinsonism
+parkland
+parkway
+parlance
+parlay
+parley
+parliament
+parliamentarian
+parliamentary
+parlor
+parlous
+Parmesan
+parochial
+parodist
+parody
+parole
+parolee
+paroxysm
+parquet
+Parr
+parricide
+Parrish
+parrot
+parry
+parse
+parsec
+Parsifal
+parsimonious
+parsimony
+parsley
+parsnip
+parson
+parsonage
+part
+partake
+parterre
+Parthenon
+partial
+participant
+participate
+participial
+participle
+particle
+particular
+particulate
+partisan
+partita
+partition
+partner
+partook
+partridge
+parturition
+party
+partygo
+parvenu
+Pasadena
+Pascal
+paseo
+pasha
+Paso
+pass
+passage
+passageway
+Passaic
+passbook
+passe
+passel
+passenger
+passerby
+passerine
+passeth
+passion
+passionate
+passivate
+passkey
+Passover
+passport
+password
+past
+pasta
+paste
+pasteboard
+pastel
+pasteup
+Pasteur
+pasteurize
+pastiche
+pastime
+pastor
+pastoral
+pastorale
+pastorate
+pastrami
+pastry
+pasturage
+pasture
+pat
+Patagonia
+patch
+patchwork
+pate
+Patel
+patent
+patentee
+paterfamilias
+paternal
+paternity
+paternoster
+Paterson
+path
+pathetic
+pathfind
+pathogen
+pathogenesis
+pathogenic
+pathology
+pathos
+pathway
+patient
+patina
+patio
+patois
+patriarch
+patriarchal
+patriarchate
+patriarchs
+patriarchy
+Patrice
+Patricia
+patrician
+patricidal
+patricide
+Patrick
+patrilineal
+patrimonial
+patrimony
+patriot
+patriotic
+patristic
+patrol
+patron
+patronage
+patroness
+patronymic
+patsy
+patter
+pattern
+Patterson
+Patti
+Patton
+patty
+paucity
+Paul
+Paula
+Paulette
+Pauli
+Pauline
+Paulo
+Paulsen
+Paulson
+Paulus
+paunch
+pauper
+pause
+pavane
+pave
+pavilion
+Pavlov
+Pavlovian
+paw
+pawl
+pawn
+pawnbroker
+pawnshop
+pawpaw
+Pawtucket
+pax
+pay
+payback
+paycheck
+payday
+payee
+payload
+paymaster
+Payne
+payoff
+payola
+payout
+payroll
+Paz
+PBS
+PDQ
+pea
+Peabody
+peace
+peaceable
+peacetime
+peach
+Peachtree
+peacock
+peafowl
+peahen
+peak
+peal
+Peale
+peanut
+pear
+Pearce
+pearl
+Pearson
+peasant
+peasantry
+Pease
+peashooter
+peat
+peavy
+pebble
+pecan
+peccable
+peccadillo
+peccadilloes
+peccary
+peck
+Pecos
+pectin
+pectoral
+peculate
+peculiar
+pecuniary
+pedagogic
+pedagogue
+pedagogy
+pedal
+pedant
+pedantic
+pedantry
+peddle
+pederast
+pedestal
+pedestrian
+pediatric
+pediatrician
+pedicab
+pedicure
+pedigree
+pediment
+pedlar
+pedometer
+Pedro
+pee
+peed
+peek
+peekaboo
+peel
+peen
+peep
+peephole
+peer
+peerage
+peeress
+peeve
+peevish
+peewee
+peg
+Pegasus
+pegboard
+Peggy
+pegmatite
+PEI
+pejorative
+Peking
+Pekingese
+pekoe
+pelagic
+Pelham
+pelican
+pellagra
+pellet
+pellucid
+pelt
+peltry
+pelvic
+pelvis
+Pembroke
+pemmican
+pen
+Pena
+penal
+penalty
+penance
+penates
+pence
+penchant
+pencil
+pendant
+pending
+pendulous
+pendulum
+Penelope
+peneplain
+peneplane
+penetrable
+penetrant
+penetrate
+penguin
+Penh
+penholder
+penicillin
+peninsula
+peninsular
+penis
+penitent
+penitential
+penitentiary
+penknife
+Penn
+penna
+pennant
+Pennington
+pennon
+Pennsylvania
+penny
+pennyroyal
+pennyweight
+penology
+Penrose
+Pensacola
+pension
+penstock
+pent
+pentad
+pentagon
+pentagonal
+pentagram
+pentameter
+pentane
+Pentateuch
+pentathlon
+Pentecost
+pentecostal
+penthouse
+penult
+penultimate
+penumbra
+penumbral
+penurious
+penury
+peon
+peonage
+peony
+people
+Peoria
+pep
+pepper
+peppercorn
+peppergrass
+peppermint
+pepperoni
+peppery
+Pepsi
+PepsiCo
+peptic
+peptide
+peptize
+per
+peradventure
+perambulate
+percale
+perceivable
+perceive
+percent
+percentage
+percentile
+percept
+perceptible
+perceptual
+perch
+perchance
+perchlorate
+Percival
+percolate
+percussion
+Percy
+perdition
+perdurable
+peregrinate
+peregrine
+peremptory
+perennial
+perestroika
+Perez
+perfect
+perfecta
+perfectible
+perfervid
+perfidious
+perfidy
+perforate
+perforce
+perform
+performance
+perfume
+perfumery
+perfunctory
+perfuse
+perfusion
+Pergamon
+pergola
+perhaps
+Periclean
+Pericles
+perigee
+perihelion
+peril
+Perilla
+perilous
+perimeter
+period
+periodic
+periodontic
+periodontist
+peripatetic
+peripheral
+periphery
+periphrastic
+periscope
+perish
+peristyle
+peritectic
+peritoneal
+periwig
+periwinkle
+perjure
+perjury
+perk
+Perkins
+Perle
+perlite
+permafrost
+permalloy
+permanent
+permeable
+permeance
+permeate
+Permian
+permissible
+permission
+permit
+permittivity
+permutation
+permute
+pernicious
+pernickety
+Pernod
+perorate
+peroxide
+perpendicular
+perpetrate
+perpetual
+perpetuate
+perpetuity
+perplex
+perquisite
+Perry
+persecute
+persecutor
+Perseid
+Persephone
+Perseus
+perseverance
+persevere
+Pershing
+Persia
+Persian
+persiflage
+persimmon
+persist
+persistent
+persnickety
+person
+persona
+personae
+personage
+personal
+personify
+personnel
+perspective
+perspicacious
+perspicacity
+perspicuity
+perspicuous
+perspiration
+perspire
+persuade
+persuasion
+pert
+pertain
+Perth
+pertinacious
+pertinacity
+pertinent
+perturb
+perturbation
+Peru
+perusal
+peruse
+Peruvian
+pervade
+pervasion
+perverse
+perversion
+pervert
+pervious
+peseta
+pesky
+peso
+pessimal
+pessimism
+pessimist
+pessimum
+pest
+pesticide
+pestiferous
+pestilent
+pestilential
+pestle
+pet
+petal
+petard
+Pete
+peter
+Petersburg
+Petersen
+Peterson
+petiole
+petit
+petite
+petition
+petrel
+petri
+petrifaction
+petrify
+petrochemical
+petroglyph
+petrography
+petrol
+petrolatum
+petroleum
+petrology
+petticoat
+pettifog
+pettifoggery
+pettish
+petulant
+petunia
+Peugeot
+pew
+pewter
+peyote
+pfennig
+Pfizer
+phaeton
+phage
+phagocyte
+phalange
+phalanx
+phalarope
+phallic
+phallus
+phantasm
+phantasy
+phantom
+pharaoh
+pharaonic
+pharisaic
+pharisee
+pharmaceutic
+pharmacist
+pharmacology
+pharmacopoeia
+pharmacy
+pharyngeal
+pharynx
+phase
+phasor
+PhD
+pheasant
+Phelps
+phenobarbital
+phenol
+phenolic
+phenomena
+phenomenal
+phenomenology
+phenomenon
+phenotype
+phenotypic
+phenyl
+pheromone
+phi
+phial
+Phil
+Philadelphia
+philander
+philanthropic
+philanthropist
+philanthropy
+philatelic
+philatelist
+philately
+Philemon
+philharmonic
+Philip
+Philippian
+philippic
+Philippine
+philistine
+Phillip
+Phillips
+philodendron
+philology
+Philomena
+philosopher
+philosophic
+philosophize
+philosophy
+philter
+Phipps
+phlebitis
+phlebotomist
+phlebotomy
+phlegm
+phlegmatic
+phloem
+phlogiston
+phlox
+phobia
+phobic
+phoebe
+Phoebus
+Phoenicia
+phoenix
+phon
+phone
+phoneme
+phonemic
+phonetic
+phonetician
+phonic
+phonograph
+phonology
+phonon
+phosgene
+phosphate
+phosphene
+phosphide
+phosphine
+phosphor
+phosphoresce
+phosphorescent
+phosphoric
+phosphorus
+phosphorylate
+photo
+photogenic
+photogrammetry
+photography
+photolysis
+photolytic
+photolyze
+photon
+photonic
+photostat
+photosynthesize
+phrasal
+phrase
+phraseology
+phrenology
+phthalate
+phthisis
+phyla
+phyletic
+Phyllis
+phyllotaxis
+phylogenetic
+phylogeny
+phylum
+physic
+physician
+Physik
+physiochemical
+physiognomy
+physiography
+physiology
+physiotherapist
+physiotherapy
+physique
+phytology
+phytoplankton
+phytotoxic
+phytotoxin
+pi
+pianissimo
+pianist
+piano
+pianoforte
+piaster
+piazza
+pica
+picador
+picalilli
+picaresque
+Picasso
+picayune
+Piccadilly
+piccolo
+pick
+pickaninny
+pickax
+pickaxe
+pickerel
+Pickering
+picket
+Pickett
+Pickford
+pickle
+Pickman
+pickoff
+pickpocket
+pickup
+picnic
+picnicked
+picnicker
+picnicking
+picogram
+Pict
+pictograph
+pictographic
+pictorial
+picture
+picturesque
+piddle
+pidgin
+pie
+piebald
+piece
+piecemeal
+piecewise
+piecework
+piedmont
+pier
+pierce
+Pierre
+Pierrot
+Pierson
+pieta
+pietism
+pietist
+pietistic
+piety
+piezoelectric
+piffle
+pig
+pigeon
+pigeonfoot
+pigeonhole
+piggish
+piggledy
+piggyback
+pigheaded
+piglet
+pigment
+pigmentary
+pigmentation
+pigmy
+pigpen
+pigroot
+pigskin
+pigstick
+pigsty
+pigtail
+pike
+pilaf
+pilaster
+Pilate
+pile
+pileate
+pileup
+pilfer
+pilferage
+pilgrim
+pilgrimage
+pill
+pillage
+pillar
+pillory
+pillow
+pillowcase
+Pillsbury
+pilot
+pimento
+pimiento
+pimp
+pimple
+pin
+pinafore
+pinata
+pinball
+pincer
+pinch
+pincushion
+pine
+pineal
+pineapple
+Pinehurst
+pinetum
+pinewood
+pinfeather
+ping
+pinhead
+pinhole
+pinion
+pink
+pinkeye
+pinkie
+pinkish
+pinko
+pinnace
+pinnacle
+pinnate
+pinochle
+pinpoint
+pinprick
+pinsetter
+Pinsky
+pinspotter
+pinstripe
+pint
+pintail
+pintle
+pinto
+pinup
+pinwheel
+pion
+pioneer
+pious
+pip
+pipe
+pipeline
+pipette
+pipsissewa
+piquant
+pique
+piracy
+Piraeus
+piranha
+pirate
+piratic
+pirogue
+pirouette
+pirouetted
+pirouetting
+Piscataway
+piscatory
+Pisces
+pisciculture
+piscine
+piss
+pissoir
+pistachio
+pistil
+pistol
+pistole
+pistoleer
+piston
+pit
+pita
+pitch
+pitchblende
+pitchfork
+pitchstone
+piteous
+pitfall
+pith
+pithead
+pithecanthropus
+pitiable
+pitilessly
+Pitney
+piton
+Pitt
+pittance
+Pittman
+Pitts
+Pittsburgh
+Pittsburgher
+Pittsfield
+Pittston
+pituitary
+pity
+Pius
+pivot
+pivotal
+pixel
+pixie
+pixilate
+pixy
+pizza
+pizzazz
+pizzeria
+pizzicato
+placable
+placard
+placate
+place
+placeable
+placebo
+placehold
+placenta
+placental
+placid
+placket
+plagiarism
+plagiarist
+plagiarize
+plagioclase
+plague
+plagued
+plaguey
+plaguily
+plaice
+plaid
+plain
+plainclothesman
+Plainfield
+plains
+plainsong
+plainspoken
+plaint
+plaintiff
+plaintive
+plait
+plan
+planar
+planarian
+Planck
+plane
+planeload
+planet
+planetaria
+planetarium
+planetary
+planetesimal
+planetoid
+plangent
+planimeter
+plank
+plankton
+planktonic
+planoconcave
+planoconvex
+plant
+plantain
+plantation
+plaque
+plasm
+plasma
+plasmon
+plaster
+plasterboard
+plasterwork
+plastic
+plastomer
+plastron
+plat
+plate
+plateau
+platelet
+platen
+platform
+platinic
+platinum
+platitude
+platitudinous
+Plato
+platonic
+Platonism
+Platonist
+platoon
+Platte
+platypus
+plaudit
+plausible
+play
+playa
+playact
+playback
+playbill
+playboy
+playgo
+playground
+playhouse
+playland
+playlet
+playmate
+playoff
+playpen
+playroom
+playsuit
+plaything
+playtime
+playwright
+playwriting
+plaza
+plea
+plead
+pleasant
+pleasantry
+please
+pleasure
+pleat
+plebe
+plebeian
+plebiscite
+plectrum
+pled
+pledge
+Pleiades
+Pleistocene
+plenary
+plenipotentiary
+plenish
+plenitude
+plenteous
+plenty
+plenum
+plesiosaur
+plethora
+pleura
+pleural
+pleurisy
+Plexiglas
+plexus
+pliable
+pliancy
+pliant
+pliers
+plight
+plimsoll
+plink
+plinth
+Pliny
+Pliocene
+plod
+plop
+plosion
+plot
+plover
+plow
+plowboy
+plowshare
+ploy
+pluck
+plug
+plugboard
+pluggable
+plum
+plumage
+plumb
+plumbago
+plumbate
+plumbic
+plume
+plummet
+plumose
+plump
+plumpish
+plunder
+plunge
+plunk
+pluperfect
+plural
+plus
+plush
+Plutarch
+Pluto
+plutocracy
+plutocrat
+plutocratic
+plutonian
+plutonic
+plutonium
+pluvial
+ply
+Plymouth
+plyscore
+plywood
+PM
+p.m.
+pneuma
+pneumatic
+pneumococcus
+pneumonia
+pneumonic
+Po
+poach
+pock
+pocketbook
+pockmark
+Pocono
+pocus
+pod
+podia
+podiatrist
+podiatry
+podium
+Podunk
+podzol
+Poe
+poem
+poesy
+poet
+poetaster
+poetess
+poetic
+poetress
+poetry
+pogo
+pogrom
+poi
+poignant
+Poincare
+poinsettia
+point
+pointillism
+pointillist
+pointwise
+poise
+poison
+poisonous
+Poisson
+poke
+pokerface
+pokey
+pol
+Poland
+polar
+polarimeter
+Polaris
+polariscope
+polariscopic
+polariton
+polarograph
+polarography
+Polaroid
+polaron
+polder
+pole
+polecat
+polemic
+police
+policy
+policyholder
+polio
+poliomyelitis
+polis
+polish
+politburo
+polite
+politesse
+politic
+politician
+politicker
+politicking
+politico
+politics
+polity
+Polk
+polka
+poll
+pollack
+Pollard
+pollen
+pollinate
+polliwog
+pollock
+pollster
+pollutant
+pollute
+Pollux
+Pollyanna
+polo
+polonaise
+polonium
+polopony
+poltergeist
+poltroon
+poly
+polyandry
+polyethylene
+polygamist
+polygamous
+polygamy
+polyglot
+polygon
+polygonal
+polygynous
+polyhedra
+polyhedral
+polyhedron
+Polyhymnia
+polymathic
+polymer
+polymerase
+polymeric
+polymorph
+polymorphic
+polymorphous
+Polynesia
+Polynices
+polynomial
+polyp
+Polyphemus
+polyphonous
+polyphony
+polyploid
+polypropylene
+polytechnic
+polytheism
+polytheist
+polytope
+polytypy
+pomade
+pomegranate
+pommel
+pomology
+Pomona
+pomp
+pompadour
+pompano
+Pompeii
+pompon
+pomposity
+pompous
+Ponce
+Ponchartrain
+poncho
+pond
+ponder
+ponderous
+pong
+poniard
+Pontiac
+pontifex
+pontiff
+pontific
+pontificate
+pontoon
+pony
+ponytail
+Ponzi
+pooch
+poodle
+pooh
+pool
+Poole
+poolroom
+poop
+poor
+poorhouse
+poorish
+pop
+popcorn
+pope
+popery
+popeye
+popgun
+popinjay
+popish
+poplar
+poplin
+popover
+poppet
+poppy
+poppycock
+popsicle
+populace
+popular
+populate
+populism
+populist
+populous
+porcelain
+porch
+porcine
+porcupine
+pore
+porgy
+pork
+porn
+porno
+pornography
+porosity
+porous
+porphyry
+porpoise
+porridge
+porringer
+Porsche
+port
+portage
+portal
+portamenti
+portamento
+portation
+portcullis
+Porte
+portend
+portent
+portentous
+porter
+porterage
+porterhouse
+portfolio
+porthole
+Portia
+portico
+portiere
+Portland
+portmanteau
+Porto
+portrait
+portraiture
+portray
+portrayal
+Portsmouth
+Portugal
+Portuguese
+portulaca
+posada
+pose
+Poseidon
+poseur
+posh
+posit
+position
+positron
+posse
+possess
+possession
+possessor
+possible
+possum
+post
+postage
+postal
+postbellum
+postcard
+postclassic
+postcondition
+postdate
+postdoc
+postdoctoral
+posterior
+posteriori
+posterity
+postern
+postfix
+postglacial
+postgraduate
+posthaste
+posthumous
+posthypnotic
+postilion
+postimpression
+postlude
+postmark
+postmaster
+postmillenarian
+postmistress
+postmodern
+postmortem
+postmultiply
+postnasal
+postnuptial
+postoperative
+postorder
+postpaid
+postpartum
+postpone
+postprandial
+postprocess
+postprocessor
+postscript
+postulant
+postulate
+postural
+posture
+postwar
+posy
+pot
+potable
+potash
+potassium
+potation
+potato
+potatoes
+potbelly
+potboil
+potent
+potentate
+potential
+potentiate
+potentiometer
+pothole
+pothook
+pothunter
+potion
+potlatch
+potluck
+Potomac
+potpourri
+potsherd
+potshot
+pottage
+potter
+pottery
+Potts
+pouch
+Poughkeepsie
+poultice
+poultry
+pounce
+pound
+poundage
+poundal
+pour
+pout
+poverty
+pow
+powder
+powderpuff
+powdery
+Powell
+power
+powerhouse
+powwow
+pox
+Poynting
+ppm
+PR
+practicable
+practical
+practice
+practitioner
+Prado
+pragmatic
+pragmatism
+pragmatist
+Prague
+prairie
+praise
+praiseworthy
+praline
+pram
+prance
+prank
+prankish
+prankster
+praseodymium
+prate
+pratfall
+Pratt
+prattle
+Pravda
+prawn
+praxes
+praxis
+pray
+prayer
+preach
+preachy
+preamble
+Precambrian
+precarious
+precaution
+precautionary
+precede
+precedent
+precept
+preceptive
+precess
+precession
+precinct
+precious
+precipice
+precipitable
+precipitate
+precipitous
+precis
+precise
+precision
+preclude
+preclusion
+precocial
+precocious
+precocity
+precursor
+predaceous
+predacious
+predecessor
+predicament
+predicate
+predict
+predilect
+predispose
+predisposition
+predominant
+predominate
+preemie
+preeminent
+preempt
+preen
+prefab
+prefabricate
+preface
+prefatory
+prefect
+prefecture
+prefer
+preferable
+preference
+preferential
+prefix
+pregnant
+prehensile
+prehension
+prehistoric
+prehominid
+prejudice
+prejudicial
+prelim
+preliminary
+prelude
+premature
+premed
+premeditate
+premier
+premiere
+premise
+premium
+premonition
+Prentice
+preoccupy
+prep
+preparation
+preparator
+prepare
+preponderant
+preponderate
+preposition
+preposterous
+preppy
+preprogram
+prerequisite
+prerogative
+presage
+presbyter
+presbyterial
+Presbyterian
+presbytery
+prescient
+Prescott
+prescribe
+prescript
+present
+presentation
+preservation
+preserve
+preside
+president
+presidential
+presidium
+press
+pressboard
+pressroom
+pressure
+prestidigitate
+prestige
+prestigious
+presto
+Preston
+presume
+presumed
+presuming
+presumption
+presumptuous
+presuppose
+presupposition
+pretend
+pretense
+pretenses
+pretension
+pretentious
+preterite
+preternatural
+pretext
+Pretoria
+prettify
+pretty
+pretzel
+prevail
+prevalent
+prevaricate
+prevent
+preview
+previous
+prexy
+prey
+Priam
+price
+prick
+prickle
+pride
+priest
+priestess
+Priestley
+prig
+priggish
+prim
+prima
+primacy
+primal
+primary
+primate
+prime
+primeval
+primitive
+primitivism
+primo
+primogeniture
+primordial
+primp
+primrose
+primus
+prince
+princedom
+princeling
+princess
+Princeton
+principal
+principia
+principle
+printery
+printout
+prior
+prioress
+priori
+prioritize
+priory
+Priscilla
+prism
+prismatic
+prismoid
+prison
+prissy
+pristine
+Pritchard
+prithee
+privacy
+private
+privateer
+privet
+privilege
+privity
+privy
+prix
+prize
+prizefight
+prizewin
+pro
+proactive
+probabilist
+probate
+probationary
+probe
+probity
+problem
+problematic
+proboscis
+procaine
+procedural
+procedure
+proceed
+process
+procession
+processor
+proclaim
+proclamation
+proclivity
+proconsul
+procrastinate
+procreate
+procrustean
+Procrustes
+Procter
+proctology
+proctor
+procurator
+procure
+procuress
+Procyon
+prod
+prodigal
+prodigious
+prodigy
+produce
+producible
+product
+productivity
+prof
+profanation
+profane
+profess
+profession
+professional
+professor
+professorial
+proffer
+proficient
+profile
+profit
+profiteer
+profligacy
+profligate
+profound
+profundity
+profuse
+profusion
+progenitor
+progeny
+progesterone
+prognosis
+prognosticate
+program
+programmatic
+progress
+progression
+prohibit
+prohibition
+prohibitory
+project
+projectile
+Prokofieff
+prolate
+prolegomena
+proletarian
+proletariat
+proliferate
+prolific
+prolix
+prologue
+prolong
+prolongate
+prolusion
+prom
+promenade
+Promethean
+Prometheus
+promethium
+prominent
+promiscuity
+promiscuous
+promise
+promissory
+promontory
+promote
+promotion
+prompt
+promptitude
+promulgate
+pronate
+prone
+prong
+pronghorn
+pronominal
+pronoun
+pronounce
+pronounceable
+pronto
+pronunciamento
+pronunciation
+proof
+proofread
+prop
+propagable
+propaganda
+propagandist
+propagandize
+propagate
+propane
+propel
+propellant
+propensity
+proper
+property
+propertyless
+prophecy
+prophesy
+prophet
+prophetess
+prophetic
+prophylactic
+prophylaxis
+propinquity
+propionate
+propitiable
+propitiate
+propitious
+proponent
+proportion
+proportionate
+propos
+proposal
+propose
+proposition
+propound
+proprietary
+proprietor
+proprietress
+propriety
+proprioception
+propulsion
+propyl
+propylene
+prorate
+prorogue
+prosaic
+proscenium
+prosciutto
+proscribe
+proscription
+prose
+prosecute
+prosecutor
+prosecutorial
+proselyte
+proselytize
+Proserpine
+prosodic
+prosodist
+prosody
+prosopopoeia
+prospect
+prospectus
+prosper
+prosperous
+prostate
+prostheses
+prosthesis
+prosthetic
+prostitute
+prostrate
+protactinium
+protagonist
+protean
+protease
+protect
+protectorate
+protectress
+protege
+protegee
+protein
+proteolysis
+proteolytic
+protest
+protestant
+protestation
+prothonotary
+protocol
+protolanguage
+proton
+protoplasm
+protoplasmic
+protoplast
+protoplastic
+prototype
+prototypic
+protozoa
+protozoan
+protozooic
+protozoon
+protract
+protractor
+protrude
+protrusion
+protuberant
+proud
+Proust
+prove
+proven
+provenance
+Provencal
+provender
+proverb
+proverbial
+provide
+provident
+providential
+province
+provincial
+provision
+provisional
+proviso
+provisory
+provocateur
+provocation
+provoke
+provolone
+provost
+prow
+prowess
+prowl
+proximal
+proximate
+proximity
+proxy
+prude
+prudent
+prudential
+prudery
+prudish
+Pruitt
+prune
+prurient
+Prussia
+pry
+P.S.
+p's
+psalm
+psalter
+psaltery
+pseudo
+pseudonym
+pseudonymous
+pshaw
+psi
+psoriasis
+psych
+psyche
+psychedelic
+psychiatric
+psychiatrist
+psychiatry
+psychic
+psycho
+psychoanalyze
+psychogenic
+psychokinesis
+psychology
+psychometry
+psychopath
+psychopathic
+psychoses
+psychosis
+psychotic
+PTA
+ptarmigan
+pterodactyl
+Ptolemaic
+Ptolemy
+ptomaine
+pub
+puberty
+pubescent
+pubic
+public
+publican
+publication
+publicly
+publish
+PUC
+Puccini
+puce
+puck
+puckish
+pudding
+puddle
+pudenda
+pudendum
+pudgy
+pueblo
+puerile
+Puerto
+puff
+puffball
+puffery
+puffin
+pug
+Pugh
+pugilism
+pugilist
+pugnacious
+pugnacity
+puissant
+puke
+pukka
+Pulaski
+pulchritude
+pule
+Pulitzer
+pull
+pullback
+pullet
+pulley
+Pullman
+pullout
+pullover
+pulmonary
+pulmonic
+pulp
+pulpit
+pulpwood
+pulsar
+pulsate
+pulsatile
+pulse
+pulverable
+pulverize
+puma
+pumice
+pummel
+pump
+pumpernickel
+pumpkin
+pumpkinseed
+pun
+punch
+punchboard
+puncheon
+punctate
+punctilio
+punctilious
+punctual
+punctuate
+puncture
+pundit
+punditry
+pungent
+Punic
+punish
+punitive
+punk
+punkah
+punster
+punt
+puny
+pup
+pupa
+pupae
+pupal
+pupate
+pupil
+pupillary
+puppet
+puppeteer
+puppetry
+puppy
+puppyish
+purblind
+Purcell
+purchase
+purdah
+Purdue
+pure
+purebred
+puree
+purgation
+purgatory
+purge
+purify
+Purina
+purine
+puritan
+puritanic
+purl
+purlieu
+purloin
+purple
+purplish
+purport
+purpose
+purposive
+purr
+purse
+purslane
+pursuant
+pursue
+pursuer
+pursuit
+pursuivant
+purulent
+purvey
+purveyance
+purveyor
+purview
+pus
+Pusan
+Pusey
+push
+pushball
+pushbutton
+pushcart
+pushover
+pushpin
+pusillanimity
+pusillanimous
+puss
+pussycat
+pussyfoot
+pustulant
+pustular
+pustulate
+pustule
+put
+putative
+Putnam
+putrefaction
+putrefy
+putrescent
+putrid
+putsch
+putt
+putter
+putty
+puzzle
+PVC
+Pygmalion
+pygmy
+Pyhrric
+Pyle
+pylon
+pyloric
+Pyongyang
+pyorrhea
+pyramid
+pyramidal
+pyre
+pyrethrin
+pyrethrum
+Pyrex
+pyridine
+pyrite
+pyroelectric
+pyrolysis
+pyrolytic
+pyrolyze
+pyromania
+pyrometer
+pyrophosphate
+pyrotechnic
+pyroxene
+pyrrhic
+Pythagoras
+Pythagorean
+Pythias
+python
+Q&A
+Qatar
+QED
+q's
+qua
+quack
+quackery
+quad
+quadrangle
+quadrangular
+quadrant
+quadratic
+quadrature
+quadrennial
+quadrennium
+quadric
+quadriceps
+quadrilateral
+quadrille
+quadrillion
+quadrillionth
+quadripartite
+quadriplegia
+quadriplegic
+quadrivium
+quadroon
+quadruped
+quadruple
+quadruplet
+quadruplicate
+quadrupole
+quaff
+quagmire
+quahog
+quail
+quaint
+quake
+Quakeress
+qualified
+qualify
+qualitative
+quality
+qualm
+qualmish
+quandary
+quanta
+Quantico
+quantify
+quantile
+quantitate
+quantitative
+quantity
+quantize
+quantum
+quarantine
+quark
+quarrel
+quarrelsome
+quarry
+quart
+quarterback
+quarterdeck
+quarterfinal
+quarterfinalist
+quartermaster
+quarternion
+quartet
+quartette
+quartic
+quartile
+quarto
+quartz
+quasar
+quash
+quasi
+quaternary
+quatrain
+quaver
+quay
+quayside
+Que.
+queasy
+queazy
+Quebec
+Quechua
+queen
+Queensland
+queer
+queerish
+quell
+quench
+Quentin
+querulous
+query
+quest
+question
+questionnaire
+quetzal
+queue
+Quezon
+quibble
+quiche
+quick
+quicken
+quickie
+quicklime
+quicksand
+quicksilver
+quickstep
+quid
+quiescent
+quiet
+quietude
+quietus
+quill
+quilt
+quince
+quinine
+Quinn
+quinquennial
+quint
+quintal
+quintessence
+quintessential
+quintet
+quintette
+quintic
+quintile
+quintillion
+quintuple
+quintuplet
+quintuplicate
+quip
+quire
+Quirinal
+quirk
+quirt
+quisling
+quit
+quite
+Quito
+quiver
+Quixote
+quixotic
+quiz
+quizzical
+quo
+quod
+quoin
+quoit
+quondam
+quonset
+quorum
+quota
+quotation
+quote
+quoth
+quotidian
+quotient
+Rabat
+rabbet
+rabbi
+rabbinate
+rabbinic
+rabbit
+rabbity
+rabble
+rabid
+rabies
+raccoon
+race
+racecourse
+racehorse
+racemic
+racetrack
+raceway
+Rachel
+Rachmaninoff
+racial
+rack
+racket
+racketeer
+raconteur
+racquet
+radar
+Radcliffe
+radial
+radian
+radiant
+radiate
+radical
+radices
+radii
+radio
+radiograph
+radiography
+radiolarian
+radiology
+radiosonde
+radish
+radium
+radius
+radix
+radome
+radon
+Rae
+Rafael
+Rafferty
+raffia
+raffish
+raffle
+raft
+rafts
+rag
+ragamuffin
+rage
+raggedy
+raglan
+ragout
+ragtag
+ragtime
+ragweed
+raid
+rail
+railbird
+railhead
+raillery
+railroad
+railway
+raiment
+rain
+rainbow
+raincoat
+raindrop
+rainfall
+rainproof
+rainspout
+rainstorm
+rainwear
+raise
+raisin
+raison
+raj
+rajah
+Rajiv
+rake
+rakehell
+rakish
+Raleigh
+rally
+Ralph
+Ralston
+ram
+Ramada
+Raman
+ramble
+rambunctious
+ramify
+Ramirez
+Ramo
+Ramon
+Ramona
+Ramos
+ramp
+rampage
+rampant
+rampart
+ramrod
+Ramsey
+ramshackle
+ran
+ranch
+rancho
+rancid
+rancor
+rancorous
+Rand
+Randall
+Randolph
+random
+randy
+rang
+range
+rangeland
+Rangoon
+Ranier
+rank
+Rankin
+Rankine
+rankle
+ransack
+ransom
+rant
+Rao
+Raoul
+rap
+rapacious
+rapacity
+rape
+Raphael
+rapid
+rapier
+rapine
+rappel
+rapport
+rapprochement
+rapscallion
+rapt
+raptor
+rapture
+rapturous
+rara
+rare
+rarebit
+rarefaction
+rarefy
+Raritan
+rasa
+rascal
+rash
+Rasmussen
+rasp
+raspberry
+raster
+Rastus
+rat
+rata
+ratatouille
+ratchet
+rate
+ratepayer
+rather
+rathskeller
+ratify
+ratio
+ratiocinate
+rationale
+rattail
+rattan
+rattle
+rattlesnake
+rattletrap
+rattly
+raucous
+Raul
+raunchy
+ravage
+rave
+ravel
+raven
+ravenous
+ravine
+ravioli
+ravish
+raw
+rawboned
+rawhide
+Rawlinson
+ray
+Rayleigh
+Raymond
+rayon
+Raytheon
+raze
+razor
+razorback
+razz
+razzle
+RBI
+RCA
+R&D
+re
+reach
+reactant
+reactionary
+read
+readout
+ready
+Reagan
+real
+realism
+realist
+reality
+realize
+realm
+realtor
+realty
+ream
+reap
+rear
+rearmost
+rearward
+reason
+reave
+reb
+rebarbative
+Rebecca
+rebel
+rebellion
+rebellious
+rebuke
+rebut
+rebuttal
+recalcitrant
+recantation
+recappable
+receipt
+receivable
+receive
+recension
+recent
+receptacle
+reception
+receptor
+recess
+recherche
+recidivism
+recidivist
+Recife
+recipe
+recipient
+reciprocal
+reciprocate
+reciprocity
+recital
+reck
+reckon
+reclamation
+recline
+recluse
+reclusive
+recognize
+recombinant
+recompense
+reconcile
+recondite
+reconnaissance
+reconnoiter
+recovery
+recreant
+recriminate
+recrudescent
+recruit
+rectal
+rectangle
+rectangular
+rectifier
+rectify
+rectilinear
+rectitude
+recto
+rector
+rectory
+rectum
+recumbent
+recuperate
+recur
+recurrent
+recursion
+recusant
+recuse
+red
+redact
+redbird
+redbud
+redcap
+redcoat
+redden
+reddish
+redemption
+redemptory
+redhead
+redivivus
+redleg
+Redmond
+redneck
+redolent
+redound
+redox
+redpoll
+redshank
+redskin
+redstart
+Redstone
+redtop
+reduce
+reducible
+redundant
+redwing
+redwood
+Reebok
+reed
+reedbuck
+reef
+reek
+reel
+reemit
+reenable
+Reese
+reeve
+ref
+refection
+refectory
+refer
+referable
+referee
+referenda
+referendum
+referent
+referential
+referral
+refinement
+refinery
+reflect
+reflectance
+reflectometer
+reflexive
+reformatory
+refract
+refractometer
+refractor
+refrain
+refrangible
+refrigerant
+refrigerate
+refuge
+refugee
+refulgent
+refusal
+refusenik
+refutation
+refute
+regalia
+regality
+regard
+regatta
+regelation
+regeneracy
+reggae
+regicide
+regime
+regimen
+regiment
+regimental
+regimentation
+Regina
+Reginald
+region
+regional
+Regis
+registrable
+registrant
+registrar
+registration
+registry
+regolith
+regress
+regression
+regressor
+regret
+regular
+regulate
+Regulus
+regurgitate
+rehabilitate
+rehearsal
+Reich
+Reid
+reify
+reign
+Reilly
+reimburse
+rein
+reindeer
+reinforce
+Reinhold
+reject
+rejoice
+rejoinder
+rejuvenate
+relatedly
+relaxant
+relaxation
+relayed
+relent
+relevant
+reliably
+reliant
+relic
+relict
+relief
+relies
+relieve
+religion
+religiosity
+religious
+relinquish
+reliquary
+relish
+reluctant
+remainder
+remand
+remanent
+Rembrandt
+remediable
+remedy
+remembrance
+Remington
+reminisce
+reminiscent
+remit
+remittal
+remittance
+remnant
+remonstrant
+remonstrate
+remorse
+remote
+removal
+remunerate
+Remus
+Rena
+renaissance
+renal
+Renault
+rend
+render
+rendezvous
+rendition
+Rene
+Renee
+renegade
+renege
+renewal
+rennet
+Renoir
+renounce
+renovate
+renown
+Rensselaer
+rent
+rental
+rentier
+renunciate
+rep
+repair
+reparable
+reparation
+repartee
+repatriate
+repeater
+repel
+repellent
+repentant
+repertoire
+repertory
+repetitious
+replete
+replica
+replicable
+replicate
+reportorial
+repository
+reprehensible
+repressable
+repressible
+repression
+repressor
+reprieve
+reprimand
+reprisal
+reprise
+reproach
+reptile
+reptilian
+republican
+repudiate
+repugnant
+repulsion
+reputation
+repute
+requiem
+require
+requisite
+requisition
+requital
+requite
+reredos
+rerouted
+rerouting
+rescind
+rescission
+rescue
+resemblant
+resemble
+resent
+reserpine
+reservation
+reservoir
+resident
+residential
+residua
+residual
+residuary
+residue
+residuum
+resignation
+resilient
+resinate
+resinous
+resist
+resistant
+resistible
+resistive
+resistor
+resonant
+resonate
+resorcinol
+respect
+respective
+respiration
+respirator
+resplendent
+respond
+respondent
+response
+responsible
+responsive
+rest
+restaurant
+restaurateur
+restitute
+restive
+restoration
+restraint
+restroom
+result
+resultant
+resume
+resumption
+resurgent
+resurrect
+resuscitate
+ret
+retain
+retaliate
+retard
+retardant
+retardation
+retch
+retention
+reticent
+reticle
+reticular
+reticulate
+reticule
+reticulum
+retina
+retinal
+retinue
+retiree
+retort
+retractile
+retribution
+retrieval
+retrieve
+retroaction
+retroactive
+retrofit
+retroflex
+retrograde
+retrogress
+retrogression
+retrorocket
+retrospect
+retrovirus
+retrovision
+Reub
+Reuben
+Reuters
+rev
+revanche
+revanchist
+reveille
+revel
+revelation
+revelatory
+revelry
+revenge
+revenue
+reverberant
+reverberate
+revere
+reverend
+reverent
+reverential
+reverie
+reversal
+reversible
+reversionary
+revert
+revertible
+revertive
+revile
+revilement
+revisal
+revise
+revival
+revive
+revoke
+revolt
+revolution
+revolutionary
+revolve
+revulsion
+Rex
+Reyes
+Reykjavik
+Reynolds
+RFP
+rhapsodic
+rhapsodize
+rhapsody
+Rhea
+Rhenish
+rhenium
+rheology
+rheostat
+rhesus
+rhetoric
+rhetorician
+rheum
+rheumatic
+rheumatism
+Rhine
+rhinestone
+rhino
+rhinoceros
+rhizome
+rho
+Rhoda
+Rhode
+Rhodes
+Rhodesia
+rhodium
+rhododendron
+rhomb
+rhombi
+rhombic
+rhombohedra
+rhombohedral
+rhombohedron
+rhomboid
+rhombus
+Rhonda
+rhubarb
+rhumb
+rhyme
+rhymester
+rhythm
+rhythmic
+RI
+rialto
+rib
+ribald
+ribaldry
+ribbon
+riboflavin
+ribonucleic
+ribosome
+Rica
+Ricardo
+Riccardo
+rice
+rich
+Richard
+Richards
+Richardson
+Richfield
+Richmond
+Richter
+rick
+rickets
+rickettsia
+rickettsiae
+rickety
+rickrack
+ricksha
+rickshaw
+Rico
+ricochet
+rid
+riddance
+ridden
+riddle
+ride
+ridge
+ridgepole
+Ridgway
+ridicule
+ridiculous
+Riemann
+Riesling
+rife
+riffle
+riffraff
+rifle
+riflery
+rift
+rig
+rigamarole
+Rigel
+Riggs
+right
+righteous
+rightmost
+rightward
+rigid
+rigidify
+rigor
+rigorous
+rile
+Riley
+rill
+rilly
+rim
+rime
+rimester
+rind
+Rinehart
+ring
+ringbolt
+ringleader
+ringlet
+ringmaster
+ringneck
+ringside
+ringtail
+ringtoss
+ringworm
+rink
+rinse
+Rio
+Riordan
+riot
+riotous
+rip
+riparian
+ripe
+ripen
+Ripley
+ripoff
+riposte
+ripple
+riprap
+ripsaw
+ripsnort
+riptide
+rise
+risen
+risible
+risk
+risque
+Rita
+ritardando
+Ritchie
+rite
+Ritter
+ritual
+Ritz
+ritzy
+rival
+rivalry
+riven
+river
+Rivera
+riverbank
+riverbed
+riverboat
+riverfront
+riverine
+riverside
+rivet
+Riviera
+rivulet
+Riyadh
+RNA
+roach
+road
+roadbed
+roadblock
+roadhouse
+roadrunner
+roadside
+roadstead
+roadster
+roadway
+roadwork
+roam
+roan
+roar
+roast
+rob
+robbery
+Robbins
+robe
+Roberson
+Robert
+Roberta
+Roberto
+Roberts
+Robertson
+robin
+Robinson
+robot
+robotic
+robust
+roc
+Rocco
+Rochester
+rock
+rockabye
+rockbound
+Rockefeller
+rocket
+rocketeer
+rocketry
+rockfish
+Rockford
+Rockies
+Rockland
+rockslide
+Rockwell
+rococo
+rod
+Rodale
+rode
+rodent
+rodeo
+Rodgers
+Rodney
+rodomontade
+Rodriguez
+roe
+roebuck
+roentgen
+roentgenography
+Roger
+Rogers
+Roget
+rogue
+roguish
+roil
+roily
+roister
+Roland
+role
+Rolf
+roll
+rollback
+rollick
+Rollins
+roly
+romaine
+roman
+romance
+Romanesque
+Romania
+romanize
+Romano
+romantic
+Rome
+Romeo
+Romero
+romp
+Romulus
+Ron
+Ronald
+rondeau
+rondo
+Ronnie
+rood
+roof
+rooftop
+rooftree
+rook
+rookery
+rookie
+room
+roomette
+roommate
+Roosevelt
+Rooseveltian
+roost
+root
+rootlet
+rootstock
+rope
+ropewalk
+Rorschach
+Rosa
+Rosalie
+rosary
+Roscoe
+rose
+roseate
+rosebud
+rosebush
+Roseland
+Rosemarie
+rosemary
+Rosen
+Rosenberg
+Rosenblum
+Rosenthal
+Rosenzweig
+roseola
+Rosetta
+rosette
+rosewater
+rosewood
+Rosicrucian
+Rosie
+rosin
+Ross
+roster
+rostrum
+rot
+Rotarian
+rotary
+rotate
+ROTC
+rote
+Roth
+rotifer
+rotisserie
+rotogravure
+rotor
+rototill
+rotten
+rottweiler
+rotund
+rotunda
+rouge
+rough
+roughage
+roughcast
+roughen
+roughhewn
+roughhouse
+roughish
+roughneck
+roughrider
+roughshod
+roulade
+roulette
+round
+roundabout
+roundhead
+roundhouse
+roundoff
+roundtable
+roundup
+roundworm
+rouse
+Rousseau
+roust
+roustabout
+rout
+route
+routine
+rove
+row
+rowboat
+rowdy
+Rowe
+rowel
+Rowena
+Rowland
+Rowley
+Roxanne
+Roy
+royal
+royalty
+Royce
+royster
+RPM
+RR
+r's
+RSVP
+Ruanda
+rub
+rubato
+rubberneck
+rubbery
+rubbish
+rubble
+rubdown
+rube
+rubella
+Ruben
+Rubicon
+rubicund
+rubidium
+ruble
+rubric
+ruby
+rucksack
+ruckus
+ruction
+rudder
+ruddy
+rude
+rudiment
+rudimentary
+Rudolf
+Rudolph
+Rudy
+Rudyard
+rue
+ruff
+ruffian
+ruffle
+rufous
+Rufus
+rug
+rugby
+ruggedize
+ruin
+ruination
+ruinous
+Ruiz
+rule
+rum
+rumble
+rumen
+Rumford
+ruminant
+ruminate
+rummage
+rummy
+rumor
+rumormonger
+rump
+rumple
+rumpus
+rumrun
+run
+runabout
+runaround
+runaway
+rundown
+rune
+rung
+Runge
+runic
+runneth
+Runnymede
+runoff
+runt
+runway
+Runyon
+rupee
+rupture
+rural
+ruse
+rush
+Rushmore
+rusk
+Russ
+Russell
+russet
+Russia
+russianize
+Russo
+rust
+rustic
+rusticate
+rustle
+rustproof
+rut
+rutabaga
+Rutgers
+Ruth
+ruthenium
+Rutherford
+ruthless
+rutile
+Rutland
+Rutledge
+RV
+Rwanda
+Ryan
+Rydberg
+Ryder
+rye
+Saab
+sabbath
+sabbatic
+Sabena
+saber
+Sabina
+Sabine
+sable
+sabotage
+saboteur
+sabra
+sac
+saccade
+saccadic
+saccharine
+sacerdotal
+sachem
+sachet
+sack
+sackcloth
+sacral
+sacrament
+Sacramento
+sacred
+sacrifice
+sacrificial
+sacrilege
+sacrilegious
+sacristan
+sacristy
+sacroiliac
+sacrosanct
+sacrum
+sad
+sadden
+saddle
+saddlebag
+saddlery
+sadhu
+Sadie
+sadism
+sadist
+Sadler
+sadomasochism
+sadomasochist
+safari
+safe
+safecrack
+safeguard
+safelight
+safety
+safflower
+saffron
+sag
+saga
+sagacious
+sagacity
+sage
+sagebrush
+Saginaw
+sagittal
+Sagittarius
+sago
+saguaro
+Sahara
+sahib
+said
+Saigon
+sail
+sailboard
+sailboat
+sailcloth
+sailfish
+sailor
+sailplane
+saint
+saith
+sake
+saki
+Sal
+salaam
+salacious
+salad
+salamander
+salami
+salaried
+salary
+Salazar
+sale
+Salem
+Salerno
+sales
+salesclerk
+salesgirl
+Salesian
+saleslady
+salespeople
+salesroom
+salient
+Salina
+saline
+Salisbury
+Salish
+saliva
+salivary
+salivate
+Salk
+Salle
+sallow
+sally
+salmon
+salmonella
+salon
+saloon
+salsify
+salt
+saltate
+saltbox
+saltbush
+saltcellar
+saltine
+saltpeter
+saltshaker
+saltwater
+saltworks
+salubrious
+salubrity
+salutary
+salutation
+salutatorian
+salutatory
+salute
+Salvador
+salvage
+salvageable
+salvation
+Salvatore
+salve
+salvo
+Sam
+Samantha
+Samaritan
+samarium
+samba
+same
+samizdat
+Sammy
+Samoa
+samovar
+sampan
+sample
+Sampson
+Samson
+Samuel
+Samuelson
+samurai
+San
+Sana
+sanatarium
+sanatoria
+sanatorium
+Sanborn
+Sanchez
+Sancho
+sanctify
+sanctimonious
+sanctimony
+sanction
+sanctity
+sanctuary
+sanctum
+sand
+sandal
+sandalwood
+sandbag
+sandbank
+sandbar
+sandblast
+sandbox
+Sandburg
+sanderling
+Sanderson
+sandglass
+sandhill
+Sandia
+sandlot
+sandpaper
+sandpile
+sandpiper
+Sandra
+sandstone
+sandstorm
+Sandusky
+sandwich
+sane
+Sanford
+sang
+sangaree
+sangfroid
+sanguinary
+sanguine
+sanguineous
+Sanhedrin
+sanitarian
+sanitarium
+sanitary
+sanitate
+sanitize
+sank
+sans
+Sanskrit
+Santa
+Santayana
+Santiago
+Santo
+Sao
+sap
+sapiens
+sapient
+sapling
+saponify
+sapphire
+saprophyte
+saprophytic
+sapsucker
+sapwood
+Sara
+Saracen
+Sarah
+Saran
+Sarasota
+Saratoga
+sarcasm
+sarcastic
+sarcoma
+sarcophagi
+sarcophagus
+sardine
+Sardinia
+sardonic
+sargasso
+sargassum
+sarge
+Sargent
+sari
+sarong
+sarsaparilla
+sartorial
+sash
+sashay
+Saskatchewan
+sass
+sassafras
+sassy
+sat
+satan
+satanic
+satchel
+sate
+satellite
+satiable
+satiate
+satiety
+satin
+satire
+satiric
+satisfaction
+satisfactory
+satisfy
+satrap
+saturable
+saturate
+Saturday
+Saturn
+saturnalia
+saturnalian
+saturnian
+saturnine
+satyr
+sauce
+saucepan
+Saud
+Saudi
+sauerbraten
+sauerkraut
+Saul
+Sault
+sauna
+Saunders
+saunter
+sauropod
+sausage
+saute
+sautee
+sauterne
+savage
+savagery
+savanna
+Savannah
+savant
+save
+savior
+Saviour
+Savonarola
+savor
+savory
+savoy
+Savoyard
+savvy
+saw
+sawbuck
+sawdust
+sawfish
+sawfly
+sawhorse
+sawmill
+sawtimber
+sawtooth
+sawyer
+sax
+saxifrage
+Saxon
+Saxony
+saxophone
+say
+SC
+scab
+scabbard
+scabious
+scabrous
+scads
+scaffold
+Scala
+scalar
+scalawag
+scald
+scale
+scalene
+scallion
+scallop
+scalp
+scalpel
+scaly
+scam
+scamp
+scan
+scandal
+scandalous
+Scandinavia
+scandium
+scansion
+scant
+scapegoat
+scapegrace
+scapula
+scapular
+scar
+scarab
+Scarborough
+scarce
+scare
+scarecrow
+scaremonger
+scarf
+scarface
+scarify
+scarless
+scarlet
+scarp
+Scarsdale
+scarum
+scarves
+scat
+scathe
+scathing
+scatology
+scatter
+scatterbrain
+scattergun
+scaup
+scavenge
+scenario
+scene
+scenery
+scenic
+scent
+scentless
+scepter
+Schaefer
+Schafer
+Schantz
+schedule
+schema
+schemata
+schematic
+schematize
+scheme
+Schenectady
+scherzo
+Schiller
+schism
+schismatic
+schist
+schistosomiasis
+schizoid
+schizophrenia
+schizophrenic
+schlemiel
+schlep
+Schlesinger
+schlieren
+Schlitz
+schlock
+Schloss
+schmaltz
+schmaltzy
+schmalz
+Schmidt
+Schmitt
+schmooze
+Schnabel
+schnapps
+schnauzer
+Schneider
+Schoenberg
+Schofield
+scholar
+scholastic
+scholium
+school
+schoolbag
+schoolbook
+schoolboy
+schoolchild
+schoolchildren
+schoolgirl
+schoolgirlish
+schoolhouse
+schoolmarm
+schoolmaster
+schoolmate
+schoolmistress
+schoolroom
+schoolteacher
+schoolwork
+schooner
+Schottky
+Schroeder
+Schroedinger
+Schubert
+Schultz
+Schulz
+Schumacher
+Schumann
+schuss
+Schuster
+Schuyler
+Schuylkill
+schwa
+Schwab
+Schwartz
+Schweitzer
+sciatic
+sciatica
+science
+scientific
+scientist
+scimitar
+scintilla
+scintillate
+scion
+scission
+scissor
+sclerosis
+sclerotic
+SCM
+scoff
+scofflaw
+scold
+scoliosis
+sconce
+scone
+scoop
+scoot
+scope
+scorch
+score
+scoreboard
+scorecard
+scoria
+scorn
+Scorpio
+scorpion
+scot
+scotch
+Scotia
+Scotland
+Scots
+Scott
+Scottish
+Scottsdale
+Scotty
+scoundrel
+scour
+scourge
+scout
+scoutmaster
+scow
+scowl
+scrabble
+scraggly
+scraggy
+scram
+scramble
+Scranton
+scrap
+scrapbook
+scrape
+scrapple
+scratch
+scrawl
+scrawly
+scrawny
+scream
+scree
+screech
+screed
+screen
+screenplay
+screenwriter
+screw
+screwball
+screwdriver
+screwworm
+scribble
+scribe
+Scribner
+scrim
+scrimmage
+scrimp
+scrimshaw
+scrip
+Scripps
+script
+scriptorium
+scriptural
+scripture
+scriptwriter
+scriven
+scrod
+scrofula
+scrofulous
+scrog
+scroll
+scrooge
+scrotum
+scrounge
+scrub
+scruff
+scrum
+scrumptious
+scrunch
+scruple
+scrupulosity
+scrupulous
+scrutable
+scrutinize
+scrutiny
+scuba
+scud
+scuff
+scuffle
+scull
+scullery
+scullion
+sculpin
+sculpt
+sculptor
+sculptress
+sculptural
+sculpture
+scum
+scurrility
+scurrilous
+scurry
+scurvy
+scuttle
+scuttlebutt
+scutum
+Scylla
+scythe
+Scythia
+SD
+SE
+sea
+seabag
+seabed
+seabird
+seaboard
+seaborne
+seacoast
+seafare
+seafood
+seafowl
+seafront
+seagoer
+seagoing
+Seagram
+seagull
+seahorse
+seal
+sealant
+sealskin
+seam
+seaman
+seamount
+seamstress
+Sean
+seance
+seaplane
+seaport
+seaquake
+sear
+search
+searchlight
+seascape
+seashell
+seashore
+seasick
+seaside
+season
+seasonal
+seat
+seatmate
+Seattle
+seawall
+seaward
+seaway
+seaweed
+seaworthy
+Sebastian
+sec
+secant
+secede
+secession
+seclude
+seclusion
+second
+secondary
+secondhand
+secondo
+secrecy
+secret
+secretarial
+secretariat
+secretary
+secrete
+secretion
+secretory
+sect
+sectarian
+sectary
+sector
+sectoral
+secular
+secure
+sedan
+sedate
+sedentary
+seder
+sedge
+sediment
+sedimentary
+sedimentation
+sedition
+seditious
+seduce
+seduction
+sedulous
+see
+seeable
+seed
+seedbed
+seedcake
+seedeat
+seedling
+seedpod
+seedsman
+seek
+seem
+seen
+seep
+seepage
+seer
+seersucker
+seesaw
+seethe
+seethed
+seething
+segment
+segmentary
+segmentation
+Segovia
+segregant
+segregate
+segue
+Segundo
+Seidel
+seigneur
+seigneurial
+seine
+seism
+seismic
+seismograph
+seismography
+seismology
+seismometer
+seize
+seizure
+seldom
+select
+Selectric
+Selena
+selenate
+selenite
+selenium
+selenography
+selenology
+self
+selfish
+Selfridge
+selfsame
+Selkirk
+sell
+sellout
+Selma
+selsyn
+seltzer
+selvage
+selves
+Selwyn
+semantic
+semaphore
+semblance
+semen
+semester
+semi
+seminal
+seminar
+seminarian
+seminary
+Seminole
+semiotic
+Semite
+semolina
+semper
+sempiternal
+senate
+senatorial
+send
+sender
+Seneca
+Senegal
+senescent
+senile
+senior
+senor
+senora
+senorita
+sensate
+sense
+sensible
+sensitive
+sensitize
+sensor
+sensorial
+sensorimotor
+sensual
+sensuous
+sent
+sentence
+sentential
+sententious
+sentient
+sentiment
+sentinel
+sentry
+Seoul
+sepal
+separable
+separate
+sepia
+Sepoy
+sepsis
+sept
+septa
+septate
+September
+septennial
+septet
+septic
+septillion
+septuagenarian
+septum
+septuplet
+sepulcher
+sepulchral
+sequel
+sequelae
+sequent
+sequential
+sequester
+sequestration
+sequin
+sequitur
+sequoia
+sera
+seraglio
+serape
+seraph
+seraphic
+seraphim
+Serb
+Serbia
+serenade
+serendipitous
+serendipity
+serene
+serf
+serfdom
+serge
+sergeant
+Sergei
+serial
+seriate
+seriatim
+series
+serif
+serigraph
+seriocomic
+serious
+sermon
+serology
+Serpens
+serpent
+serpentine
+serrate
+serried
+serum
+servant
+serve
+service
+serviceable
+serviette
+servile
+servitor
+servitude
+servo
+servomechanism
+servomotor
+sesame
+sesquicentennial
+sesquipedalian
+sessile
+session
+set
+setback
+Seth
+Seton
+setscrew
+settee
+settle
+setup
+seven
+sevenfold
+seventeen
+seventeenth
+seventh
+seventieth
+seventy
+sever
+severable
+several
+severalfold
+severalty
+severance
+severe
+Severn
+Seville
+sew
+sewage
+Seward
+sewerage
+sewn
+sex
+sexagesimal
+sexology
+Sextans
+sextant
+sextet
+sextillion
+sexton
+sextuple
+sextuplet
+sexual
+Seychelles
+Seymour
+sforzando
+shabby
+shack
+shackle
+shad
+shadbush
+shade
+shadow
+shadowbox
+Shafer
+Shaffer
+shaft
+shag
+shagbark
+shah
+shake
+shakeable
+shakedown
+shaken
+Shakespeare
+Shakespearean
+Shakespearian
+shako
+shaky
+shale
+shall
+shallot
+shallow
+shalom
+shalt
+sham
+shaman
+shamateur
+shamble
+shame
+shamefaced
+shampoo
+shamrock
+shamus
+Shane
+shanghai
+shanghaied
+shanghaier
+shanghaiing
+shank
+Shannon
+shan't
+Shantung
+shanty
+shantytown
+shape
+Shapiro
+shard
+share
+sharecrop
+sharehold
+shareholder
+shareown
+Shari
+shark
+sharkskin
+Sharon
+sharp
+Sharpe
+sharpen
+sharpshoot
+Shasta
+shatter
+shatterproof
+Shattuck
+shave
+shaven
+shaw
+shawl
+Shawn
+Shawnee
+shay
+she
+Shea
+sheaf
+shear
+Shearson
+sheath
+sheathe
+sheave
+shebang
+she'd
+shed
+Shedir
+Sheehan
+sheen
+sheep
+sheepfold
+sheepherding
+sheepish
+sheepshank
+sheepshead
+sheepshear
+sheepskin
+sheer
+sheet
+Sheffield
+sheik
+sheikdom
+sheikh
+Sheila
+shekel
+Shelby
+Sheldon
+shelf
+she'll
+shell
+shellac
+shellacked
+shellacking
+shellback
+Shelley
+shellfire
+shellfish
+shellproof
+Shelly
+shelter
+Shelton
+shelty
+shelve
+Shenandoah
+shenanigan
+Shepard
+shepherd
+Sheppard
+Sheraton
+sherbet
+Sheri
+Sheridan
+sheriff
+sherlock
+Sherman
+Sherri
+Sherrill
+sherry
+Sherwin
+Sherwood
+Sheryl
+Shetland
+Shia
+shibboleth
+shied
+shield
+shift
+shill
+shillelagh
+Shiloh
+shim
+shimmery
+shimmy
+shin
+shinbone
+shindig
+shine
+shingle
+shinny
+Shinto
+ship
+shipboard
+shipbuild
+shiplap
+Shipley
+shipmaster
+shipmate
+shipshape
+shipway
+shipworm
+shipwreck
+shipwright
+shipyard
+shire
+shirk
+Shirley
+shirr
+shirt
+shirttail
+shirtwaist
+shish
+shit
+shiv
+Shiva
+shivaree
+shiver
+shivery
+shoal
+shock
+Shockley
+shod
+shoddy
+shoe
+shoehorn
+shoelace
+shoestring
+shofar
+shogun
+shoji
+shone
+shoo
+shoofly
+shook
+shoot
+shootout
+shop
+shoplift
+shopown
+shoptalk
+shopworn
+shore
+shorebird
+shoreline
+shorn
+short
+shortage
+shortbread
+shortcake
+shortchange
+shortcoming
+shortcut
+shorten
+shortfall
+shorthand
+shortish
+shortsighted
+shortstop
+shot
+shotgun
+should
+shoulder
+shouldn't
+shouldst
+shout
+shove
+shovel
+show
+showboat
+showcase
+showdown
+showery
+shown
+showpiece
+showplace
+showroom
+shrank
+shrapnel
+shred
+Shreveport
+shrew
+shrewd
+shrewish
+shriek
+shrieve
+shrift
+shrike
+shrill
+shrilly
+shrimp
+shrine
+shrink
+shrinkage
+shrive
+shrivel
+shroud
+shrove
+shrub
+shrubbery
+shrug
+shrunk
+shrunken
+shtick
+Shu
+shuck
+shudder
+shuddery
+shuffle
+shuffleboard
+Shulman
+shun
+shunpike
+shunt
+shush
+shut
+shutdown
+shutoff
+shutout
+shutterbug
+shuttle
+shuttlecock
+shy
+Shylock
+shyly
+shyster
+sial
+SIAM
+Siamese
+Sian
+sib
+Siberia
+sibilant
+sibilate
+Sibley
+sibling
+sibyl
+sibylline
+sic
+Sicilian
+Sicily
+sick
+sickbed
+sicken
+sickish
+sickle
+sickroom
+side
+sidearm
+sideband
+sidebar
+sideboard
+sideburns
+sidecar
+sidehill
+sidekick
+sidelight
+sideline
+sidelobe
+sidelong
+sidereal
+sidesaddle
+sideshow
+sideslip
+sidesplitting
+sidestep
+sidestroke
+sideswipe
+sidetrack
+sidewalk
+sidewall
+sideway
+sidewinder
+sidewise
+sidle
+Sidney
+siege
+Siegel
+Siegfried
+Sieglinda
+Siegmund
+Siemens
+sienna
+sierra
+siesta
+sieve
+sift
+sigh
+sight
+sightsee
+sightseer
+sigma
+sigmoid
+Sigmund
+sign
+signal
+signatory
+signature
+signboard
+signet
+significant
+signify
+Signor
+Signora
+signpost
+Sikh
+Sikorsky
+silage
+silane
+Silas
+silent
+silhouette
+silhouetting
+silica
+silicate
+siliceous
+silicic
+silicide
+silicious
+silicon
+silicone
+silicosis
+silk
+silken
+silkworm
+sill
+silly
+silo
+silt
+siltation
+Silurian
+Silva
+silver
+silverfish
+Silverman
+silversmith
+silverware
+silvery
+silvicultural
+silviculture
+simian
+similar
+simile
+similitude
+simmer
+Simmons
+Simon
+simonize
+Simons
+Simonson
+simony
+simpatico
+simper
+simple
+simplectic
+simpleminded
+simpleton
+simplex
+simplicial
+simplicity
+simplify
+simplistic
+simply
+Simpson
+Sims
+simulacra
+simulacrum
+simulate
+simulcast
+simultaneity
+simultaneous
+sin
+Sinai
+since
+sincere
+Sinclair
+sine
+sinecure
+sinew
+sinfonia
+sing
+singable
+Singapore
+singe
+singeing
+Singh
+single
+singlehanded
+singlet
+singleton
+singletree
+singsong
+singular
+sinh
+sinister
+sinistral
+sink
+sinkhole
+sinter
+sinuous
+sinus
+sinusitis
+sinusoid
+Siobhan
+Sioux
+sip
+siphon
+sir
+sire
+siren
+Sirius
+sirloin
+sirocco
+Sis
+sisal
+siskin
+sissified
+sissy
+sister
+Sistine
+Sisyphean
+Sisyphian
+Sisyphus
+sit
+sitcom
+site
+situ
+situate
+situs
+six
+sixfold
+sixgun
+sixpence
+sixteen
+sixteenth
+sixth
+sixtieth
+sixty
+sixtyish
+size
+sizzle
+skat
+skate
+skateboard
+skedaddle
+skeet
+skein
+skeletal
+skeleton
+skelter
+skeptic
+sketch
+sketchbook
+sketchpad
+skew
+ski
+skid
+skied
+skiff
+skiing
+skill
+skillet
+skillful
+skim
+skimp
+skin
+skindive
+skinflint
+skinhead
+skink
+skip
+skipjack
+Skippy
+skirl
+skirmish
+skirt
+skit
+skittish
+skittle
+skivvy
+skoal
+skua
+skulduggery
+skulk
+skull
+skullcap
+skullduggery
+skunk
+sky
+skycap
+skydive
+Skye
+skyhook
+skyjack
+skylark
+skylight
+skyline
+skyrocket
+skysail
+skyscrape
+skyward
+skywave
+skyway
+skywrite
+S&L
+slab
+slack
+slacken
+slag
+slain
+slake
+slalom
+slam
+slander
+slanderous
+slang
+slant
+slantwise
+slap
+slapdash
+slaphappy
+slapstick
+slash
+slat
+slate
+slather
+slattern
+slaughter
+slaughterhouse
+Slav
+slave
+slavehold
+slavery
+Slavic
+slavish
+slaw
+slay
+sleaze
+sled
+sledge
+sledgehammer
+sleek
+sleep
+sleeplike
+sleepwalk
+sleepyhead
+sleet
+sleeve
+sleigh
+sleight
+slender
+slept
+sleuth
+slew
+slice
+slick
+slid
+slide
+slight
+slim
+slime
+sling
+slingshot
+slink
+slip
+slipcase
+slipcover
+slipknot
+slippage
+slippery
+slipshod
+slipstream
+slipup
+slit
+slither
+slithery
+sliver
+slivery
+slivovitz
+Sloan
+Sloane
+slob
+slobber
+Slocum
+sloe
+slog
+slogan
+sloganeer
+sloop
+slop
+slope
+slosh
+slot
+sloth
+slouch
+slough
+sloven
+slow
+slowdown
+slowish
+slowpoke
+sludge
+slug
+slugfest
+sluggard
+sluggish
+sluice
+sluiceway
+slum
+slumber
+slump
+slung
+slunk
+slur
+slurp
+slurry
+slush
+slushy
+slut
+sluttish
+sly
+smack
+small
+Smalley
+smallish
+smallpox
+smalltime
+smarmy
+smart
+smarten
+smash
+smashup
+smatter
+smear
+smell
+smelly
+smelt
+smidgen
+smile
+smirch
+smirk
+smite
+smith
+smithereens
+Smithfield
+Smithson
+Smithsonian
+smithy
+smitten
+smock
+smog
+smoke
+smokehouse
+smokeproof
+smokescreen
+smokestack
+smolder
+smooch
+smooth
+smoothbore
+smorgasbord
+smote
+smother
+Smucker
+smudge
+smug
+smuggle
+smut
+Smyrna
+Smythe
+snack
+snaffle
+snafu
+snag
+snail
+snake
+snakebird
+snakebite
+snakeroot
+snap
+snapback
+snapdragon
+snappish
+snapshot
+snare
+snark
+snarl
+snarly
+snatch
+snazzy
+sneak
+sneer
+sneeze
+snell
+snick
+snide
+sniff
+sniffle
+snifter
+snigger
+sniggle
+sniggly
+snip
+snipe
+sniperscope
+snippet
+snit
+snitch
+snivel
+snob
+snobbery
+snobbish
+snook
+snoop
+snoot
+snooze
+snore
+snorkel
+snort
+snotty
+snout
+snow
+snowball
+snowbird
+snowbound
+snowcapped
+snowdrift
+snowdrop
+snowfall
+snowfield
+snowflake
+snowmobile
+snowplow
+snowshed
+snowshoe
+snowslide
+snowstorm
+snowsuit
+snub
+snuff
+snuffbox
+snuffle
+snug
+snuggle
+snuggly
+Snyder
+so
+soak
+soap
+soapbox
+soapstone
+soapsud
+soar
+sob
+sober
+soberside
+sobriety
+sobriquet
+Soc.
+soccer
+sociable
+social
+socialite
+societal
+Societe
+society
+socioeconomic
+sociology
+sociometry
+sociopath
+sock
+socket
+sockeye
+Socrates
+Socratic
+sod
+soda
+sodden
+sodium
+Sodom
+sodomite
+sodomize
+sodomy
+sofa
+soffit
+Sofia
+soft
+softball
+soften
+softhead
+softhearted
+software
+softwood
+soggy
+soignee
+soil
+soilage
+soiree
+sojourn
+Sol
+solace
+solar
+solarium
+sold
+solder
+soldier
+soldiery
+sole
+solecism
+solemn
+solemnity
+solenoid
+solicit
+solicitation
+solicitor
+solicitous
+solicitude
+solid
+solidarity
+solidify
+solidus
+soliloquist
+soliloquize
+soliloquy
+solipsism
+solipsist
+solitaire
+solitary
+soliton
+solitude
+solo
+Solomon
+Solomonic
+Solon
+solstice
+soluble
+solute
+solvate
+solve
+solvent
+Somali
+Somalia
+somatic
+somber
+sombrero
+some
+somebody
+somebody'd
+someday
+somehow
+someone
+someplace
+Somers
+somersault
+Somerset
+Somerville
+something
+sometime
+somewhat
+somewhere
+sommelier
+Sommerfeld
+somnambulate
+somnambulist
+somnolent
+son
+sonar
+sonata
+sonatina
+song
+songbag
+songbird
+songbook
+songfest
+songwrite
+Sonia
+sonic
+sonnet
+sonneteer
+sonny
+sonogram
+Sonoma
+Sonora
+sonority
+sonorous
+Sony
+Sonya
+soon
+soot
+sooth
+soothe
+soothsay
+sop
+Sophia
+Sophie
+sophism
+sophist
+sophisticate
+sophistry
+Sophoclean
+Sophocles
+sophomore
+sophomoric
+soporific
+soprano
+sora
+sorb
+Sorbonne
+sorcerer
+sorceress
+sorcery
+sordid
+sore
+sorehead
+Sorensen
+Sorenson
+sorghum
+sorority
+sorption
+sorrel
+sorrow
+sorry
+sort
+sortie
+sostenuto
+sot
+Soto
+sottish
+sou
+souffle
+sought
+soul
+sound
+soundboard
+soundproof
+soup
+sour
+source
+sourdough
+sourpuss
+sourwood
+Sousa
+souse
+soutane
+south
+Southampton
+southbound
+southeast
+southeastern
+southeasternmost
+southeastward
+southern
+southernmost
+Southey
+southland
+southmost
+southpaw
+southward
+southwest
+southwestern
+southwesternmost
+southwestward
+souvenir
+sou'wester
+sovereign
+sovereignty
+soviet
+sovkhoz
+sow
+sowbelly
+sown
+sox
+soy
+soya
+soybean
+S&P
+spa
+space
+spacecraft
+spacesuit
+spacious
+spackle
+spade
+spadework
+spaghetti
+Spain
+spake
+spall
+spallation
+span
+spandrel
+spangle
+Spaniard
+spaniel
+Spanish
+spank
+spar
+spare
+spareribs
+sparge
+spark
+sparkle
+Sparkman
+sparkplug
+sparling
+sparrow
+sparse
+Sparta
+Spartan
+spasm
+spasmodic
+spastic
+spat
+spate
+spatial
+spatiotemporal
+spatterdock
+spatula
+Spaulding
+spavin
+spawn
+spay
+spayed
+speak
+speakeasy
+spear
+spearhead
+spearmint
+spec
+special
+specialty
+speciation
+specie
+species
+specific
+specify
+specimen
+specious
+speck
+speckle
+spectacle
+spectacular
+spectator
+specter
+spectra
+spectral
+spectrograph
+spectrography
+spectroheliograph
+spectrometer
+spectrophotometer
+spectroscope
+spectroscopy
+spectrum
+specular
+speculate
+speculum
+sped
+speech
+speechify
+speed
+speedboat
+speedometer
+speedster
+speedup
+speedway
+speedwell
+speleology
+spell
+spellbind
+spellbound
+spelunker
+spelunking
+Spence
+Spencer
+Spencerian
+spend
+spendthrift
+spent
+speramtozoon
+sperm
+spermatophyte
+spermatozoa
+spermicide
+Sperry
+spew
+sphagnum
+sphere
+spheric
+spheroid
+spherule
+sphincter
+sphinx
+sphygmometer
+Spica
+spice
+spicebush
+spicule
+spider
+spidery
+Spiegel
+spiel
+spiffy
+spigot
+spike
+spikenard
+spill
+spillage
+spillway
+spilt
+spin
+spinach
+spinal
+spindle
+spindly
+spine
+spinet
+spinnaker
+spinneret
+spinodal
+spinoff
+spinor
+spinster
+spiral
+spire
+spirit
+spiritual
+Spiro
+spirochete
+spit
+spitball
+spite
+spitfire
+spittle
+spittoon
+spitz
+splash
+splat
+splay
+splayed
+splayfoot
+spleen
+splendid
+splendiferous
+splendor
+splenetic
+splice
+spline
+splint
+splintery
+split
+splotch
+splurge
+splutter
+spoil
+spoilage
+spoilsman
+spoilsport
+Spokane
+spoke
+spoken
+spokes
+spokeshave
+spoliate
+spondaic
+sponge
+sponson
+sponsor
+spontaneity
+spontaneous
+spoof
+spook
+spool
+spoon
+spoonbill
+spoor
+sporadic
+spore
+sporran
+sport
+sportive
+sports
+sportscast
+sportsman
+sportswear
+sportswrite
+sportswriting
+spot
+spotlight
+spouse
+spout
+Sprague
+sprain
+sprang
+sprawl
+spray
+spread
+spree
+sprig
+sprightly
+spring
+springboard
+springe
+Springfield
+springhouse
+springtail
+springtime
+sprinkle
+sprint
+sprite
+sprocket
+Sproul
+sprout
+spruce
+sprue
+sprung
+spry
+spud
+spume
+spumoni
+spun
+spunk
+spur
+spurge
+spurious
+spurn
+spurt
+sputnik
+sputter
+sputum
+spy
+spyglass
+squab
+squabble
+squad
+squadron
+squalid
+squall
+squally
+squalor
+squamous
+squander
+square
+squarish
+squash
+squat
+squaw
+squawk
+squawroot
+squeak
+squeal
+squeamish
+squeegee
+squeeze
+squelch
+squib
+Squibb
+squid
+squiggle
+squiggly
+squill
+squint
+squire
+squirm
+squirrel
+squirt
+squish
+Sr.
+Sri
+s's
+SSE
+SST
+SSW
+St.
+stab
+stabile
+stable
+staccato
+Stacey
+stack
+Stacy
+stadia
+stadium
+staff
+Stafford
+stag
+stage
+stagecoach
+stagecraft
+stagehand
+stagestruck
+stagger
+stagnant
+stagnate
+Stahl
+staid
+stain
+stair
+staircase
+stairway
+stairwell
+stake
+stakehold
+stalactite
+stalag
+stalagmite
+stale
+stalemate
+Staley
+Stalin
+stalk
+stall
+stallion
+stalwart
+stamen
+Stamford
+stamina
+staminate
+stammer
+stamp
+stampede
+Stan
+stance
+stanch
+stanchion
+stand
+standard
+standby
+standbys
+standee
+standeth
+Standish
+standoff
+standoffish
+standout
+standpipe
+standpoint
+standstill
+standup
+Stanford
+Stanhope
+stank
+Stanley
+stannic
+stannous
+Stanton
+stanza
+staph
+staphylococcus
+staple
+Stapleton
+star
+starboard
+starch
+stardom
+stardust
+stare
+starfish
+stargaze
+stark
+Starkey
+starlet
+starlight
+starling
+starlit
+Starr
+start
+startle
+startup
+starvation
+starve
+starveling
+stash
+stasis
+state
+statecraft
+statehouse
+Staten
+stater
+stateroom
+states
+stateside
+statewide
+static
+stationarity
+stationary
+stationery
+stationmaster
+statistician
+Statler
+stator
+statuary
+statue
+statuesque
+statuette
+stature
+status
+statute
+statutory
+Stauffer
+staunch
+Staunton
+stave
+stay
+stayed
+staysail
+Ste.
+stead
+steadfast
+steady
+steak
+steal
+stealth
+steam
+steamboat
+steamroll
+stearate
+stearic
+Stearns
+steed
+steel
+Steele
+steelhead
+steelwork
+steely
+steelyard
+Steen
+steep
+steepen
+steeple
+steeplebush
+steeplechase
+steeplejack
+steer
+steerage
+steersman
+steeve
+Stefan
+stegosaurus
+stein
+Steinberg
+steinbok
+Steiner
+stela
+stele
+Stella
+stellar
+stellate
+stem
+stemware
+stench
+stencil
+steno
+stenography
+stenotype
+stentorian
+step
+stepbrother
+stepchild
+stepchildren
+stepdaughter
+stepfather
+Stephanie
+Stephen
+Stephens
+Stephenson
+stepladder
+stepmother
+steppe
+stepsister
+stepson
+stepwise
+steradian
+stere
+stereo
+stereography
+stereopsis
+stereopticon
+stereoscopy
+steric
+sterile
+sterling
+stern
+sternal
+sternmost
+Sterno
+sternpost
+sternum
+steroid
+stet
+stethoscope
+Stetson
+Steuben
+Steve
+stevedore
+Steven
+Stevens
+Stevenson
+stew
+steward
+stewardess
+Stewart
+stick
+stickle
+stickpin
+sticktight
+stickup
+stickwork
+sticky
+stiff
+stiffen
+stifle
+stigma
+stigmata
+stigmatic
+stigmatize
+stile
+stiletto
+still
+stillbirth
+stillborn
+stillwater
+stilt
+stimulant
+stimulate
+stimuli
+stimulus
+sting
+stink
+stinkbug
+stinkpot
+stint
+stipend
+stipple
+stipulate
+stir
+Stirling
+stirrup
+stitch
+stoat
+stochastic
+stock
+stockade
+stockbroker
+stockholder
+Stockholm
+stockpile
+stockpot
+stockroom
+Stockton
+stockyard
+stodgy
+stogy
+stoic
+stoichiometry
+stoke
+stole
+stolen
+stolid
+stolon
+stoma
+stomach
+stomachs
+stomp
+stone
+stonecrop
+stonecut
+Stonehenge
+stonemason
+stonewall
+stoneware
+stonework
+stood
+stooge
+stool
+stoolie
+stoop
+stop
+stopcock
+stopgap
+stoplight
+stopover
+stoppage
+stopwatch
+storage
+store
+storehouse
+storeown
+storeroom
+storewide
+Storey
+stork
+storm
+stormbound
+story
+storyboard
+storybook
+storytell
+stout
+stouthearted
+stove
+stovepipe
+stow
+stowage
+stowaway
+strabismic
+strabismus
+straddle
+strafe
+straggle
+straggly
+straight
+straightaway
+straightedge
+straighten
+straightforward
+straightway
+strain
+strait
+straiten
+straitjacket
+straitlaced
+strake
+strand
+strange
+strangle
+stranglehold
+strangulate
+strap
+straphanger
+strata
+stratagem
+strategic
+strategist
+strategy
+Stratford
+stratify
+stratigraphy
+stratocumulus
+stratosphere
+stratospheric
+Stratton
+stratum
+stratus
+Strauss
+straw
+strawberry
+strawflower
+stray
+streak
+stream
+streamlet
+streamline
+streamside
+street
+streetcar
+streetwalk
+strength
+strengthen
+strenuous
+strep
+streptococcus
+streptomycin
+stress
+stretch
+stretchy
+strew
+strewn
+striate
+stricken
+Strickland
+strict
+stricter
+stricture
+stride
+strident
+strife
+strike
+strikebound
+strikebreak
+strikeout
+string
+stringent
+strip
+stripe
+stripling
+striptease
+strive
+striven
+strobe
+stroboscope
+strode
+stroganoff
+stroke
+stroll
+Strom
+Stromberg
+strong
+strongbox
+stronghold
+strongish
+strongroom
+strontium
+strop
+strophe
+strove
+struck
+structural
+structure
+strudel
+struggle
+strum
+strumpet
+strung
+strut
+strychnine
+Stu
+Stuart
+stub
+stubble
+stubborn
+stucco
+stuck
+stud
+Studebaker
+student
+studio
+studious
+study
+stuff
+stultify
+stumble
+stumblebum
+stump
+stumpage
+stun
+stung
+stunk
+stunt
+stupefaction
+stupefy
+stupendous
+stupid
+stupor
+Sturbridge
+sturdy
+sturgeon
+Sturm
+stutter
+Stuttgart
+Stuyvesant
+sty
+stye
+Stygian
+style
+styli
+stylish
+stylites
+stylus
+stymie
+styptic
+styrene
+Styrofoam
+Styx
+suasion
+suave
+sub
+Subaru
+subdeb
+subdue
+subito
+subject
+subjectivity
+sublimate
+sublimer
+subliminal
+submersible
+submersion
+submit
+submittal
+suborn
+subpoena
+subpoenaed
+subrogation
+subservient
+subsidence
+subsidiary
+subsidy
+subsist
+subsistent
+substance
+substantial
+substantiate
+substantive
+substituent
+substitute
+substitutionary
+substrate
+subsume
+subsumed
+subsuming
+subsumption
+subterfuge
+subterranean
+subtext
+subtle
+subtlety
+subtly
+subtracter
+subtrahend
+suburb
+suburbia
+subvent
+subvert
+succeed
+success
+succession
+successor
+succinct
+succor
+succotash
+succubus
+succulent
+succumb
+such
+suck
+suckle
+suckling
+sucrose
+suction
+Sudan
+Sudanese
+sudden
+suds
+sudsy
+sue
+suede
+suet
+suey
+Suez
+suffer
+sufferance
+suffice
+sufficient
+suffix
+suffocate
+Suffolk
+suffragan
+suffrage
+suffragette
+suffuse
+suffusion
+sugar
+sugarcane
+sugarhouse
+sugarloaf
+sugarplum
+suggest
+suggestible
+suggestion
+suicidal
+suicide
+suit
+suitcase
+suite
+suitor
+sukiyaki
+sulfa
+sulfanilamide
+sulfate
+sulfide
+sulfite
+sulfonamide
+sulfur
+sulfuric
+sulfurous
+sulk
+sulky
+sullen
+Sullivan
+sully
+sultan
+sultanate
+sultry
+sum
+sumac
+Sumatra
+Sumerian
+summa
+summand
+summarily
+summarize
+summary
+summation
+summer
+summersault
+summertime
+summit
+summitry
+summon
+summons
+Sumner
+sump
+sumptuous
+Sumter
+sun
+sunbaked
+sunbath
+sunbathe
+sunbathing
+sunbeam
+sunbonnet
+sunbow
+sunburn
+sunburnt
+sunburst
+sundae
+Sunday
+sunder
+sundew
+sundial
+sundown
+sundry
+sunfish
+sunflower
+sung
+sunglasses
+sunk
+sunken
+sunlamp
+sunlight
+sunlit
+Sunni
+Sunnyvale
+sunrise
+sunscreen
+sunset
+sunshade
+sunshine
+sunspot
+sunstroke
+sunstruck
+sunsuit
+suntan
+sunup
+SUNY
+sup
+super
+superannuate
+superb
+superbly
+supercilious
+superficial
+superfluity
+superfluous
+superintendent
+superior
+superlunary
+supernatant
+supernovae
+supernumerary
+supersede
+superstar
+superstition
+superstitious
+supervene
+supervention
+supervise
+supervisory
+supine
+supplant
+supple
+supplely
+supplementary
+supplementation
+suppliant
+supplicant
+supplicate
+supply
+support
+supposal
+suppose
+supposition
+suppositious
+suppository
+suppress
+suppressant
+suppressible
+suppression
+suppressor
+suppurate
+supra
+supramolecular
+supranational
+suprema
+supremacist
+supremacy
+supreme
+supremum
+surcease
+surcharge
+surcoat
+surd
+sure
+surefire
+surefooted
+surety
+surf
+surface
+surfactant
+surfboard
+surfboat
+surfeit
+surge
+surgeon
+surgery
+surgical
+surly
+surmise
+surmount
+surname
+surpass
+surplice
+surplus
+surprint
+surprise
+surreal
+surrender
+surreptitious
+surrey
+surrogate
+surround
+surtax
+surtout
+surveillant
+survey
+surveyor
+survival
+survive
+survivor
+Sus
+Susan
+Susanna
+Susanne
+susceptance
+susceptible
+sushi
+Susie
+suspect
+suspend
+suspense
+suspension
+suspensor
+suspicion
+suspicious
+Sussex
+sustain
+sustenance
+Sutherland
+sutra
+Sutton
+suture
+Suzanne
+suzerain
+suzerainty
+Suzuki
+svelte
+Sven
+SW
+swab
+swaddle
+swag
+swage
+swagger
+Swahili
+swain
+swale
+swallow
+swallowtail
+swam
+swami
+swamp
+swampland
+swan
+swank
+swansdown
+Swanson
+swap
+sward
+swarm
+swart
+Swarthmore
+Swarthout
+swarthy
+swash
+swashbuckle
+swastika
+swat
+swatch
+swath
+swathe
+sway
+swayback
+Swaziland
+swear
+swearword
+sweat
+sweatband
+sweatshirt
+sweatshop
+Swede
+Sweden
+Swedish
+Sweeney
+sweep
+sweepstake
+sweet
+sweetbread
+sweeten
+sweetheart
+sweetie
+sweetish
+sweetmeat
+sweetshop
+swell
+swelter
+Swenson
+swept
+swerve
+swift
+swig
+swill
+swim
+swimsuit
+swindle
+swine
+swineherd
+swing
+swingable
+swinish
+swipe
+swirl
+swirly
+swish
+swiss
+switch
+switchback
+switchblade
+switchboard
+switchgear
+switchyard
+Switzer
+Switzerland
+swivel
+swizzle
+swollen
+swoon
+swoop
+swoosh
+sword
+swordfish
+swordplay
+swords
+swordtail
+swore
+sworn
+swum
+swung
+sybarite
+Sybil
+sycamore
+sycophant
+sycophantic
+Sydney
+Sykes
+syllabary
+syllabic
+syllabify
+syllable
+syllabus
+syllogism
+syllogistic
+sylph
+sylvan
+Sylvania
+Sylvester
+Sylvia
+sylviculture
+symbiont
+symbiosis
+symbiotic
+symbol
+symbolic
+symbology
+symmetrize
+symmetry
+sympathetic
+sympathize
+sympathy
+sympatric
+symphonic
+symphony
+symposia
+symposium
+symptom
+symptomatic
+synagogue
+synapse
+synaptic
+sync
+synch
+synchromesh
+synchronic
+synchronism
+synchronize
+synchronous
+synchrony
+synchrotron
+syncline
+syncopate
+syndic
+syndicate
+syndrome
+synecdoche
+synergetic
+synergism
+synergist
+synergistic
+synergy
+synod
+synodic
+synonym
+synonymous
+synonymy
+synopses
+synopsis
+synopsize
+synoptic
+syntactic
+syntax
+syntheses
+synthesis
+synthesize
+synthetic
+syphilis
+syphilitic
+Syracuse
+Syria
+syringa
+syringe
+syrinx
+syrup
+system
+systematic
+systematize
+systemic
+systemization
+systemwide
+systole
+systolic
+syzygy
+tab
+tabby
+tabernacle
+tablature
+table
+tableau
+tableaux
+tablecloth
+tableland
+tablespoon
+tablet
+tabletop
+tableware
+tabloid
+taboo
+tabu
+tabula
+tabular
+tabulate
+tachinid
+tachistoscope
+tachometer
+tacit
+taciturn
+Tacitus
+tack
+tackle
+taco
+Tacoma
+tact
+tactic
+tactician
+tactile
+taction
+tactual
+tad
+tadpole
+taffeta
+taffrail
+taffy
+Taft
+tag
+Tagalog
+tagalong
+Tahiti
+Tahitian
+Tahoe
+tail
+tailback
+tailcoat
+tailgate
+taillight
+tailor
+tailpiece
+tailpipe
+tailrace
+tailspin
+tailstock
+tailwind
+taint
+Taipei
+Taiwan
+Taiwanese
+Tajikistan
+take
+takedown
+taken
+takeoff
+takeout
+takeover
+taketh
+talc
+talcum
+tale
+talebear
+talent
+talisman
+talismanic
+talk
+talkative
+talkie
+tall
+Tallahassee
+tallish
+tallow
+tally
+tallyho
+Talmud
+talmudic
+talon
+talus
+tam
+tamale
+Tamara
+tamarack
+tamarind
+tamarisk
+tambour
+tambourine
+tame
+Tamil
+Tammany
+Tammy
+tamp
+Tampa
+tamper
+tampon
+tan
+tanager
+Tanaka
+Tananarive
+tanbark
+tandem
+tang
+tangelo
+tangent
+tangential
+tangerine
+tangible
+tangle
+tango
+tangy
+tanh
+tank
+tankard
+tannery
+tannest
+tannin
+tansy
+tantalize
+tantalum
+Tantalus
+tantamount
+tantrum
+Tanya
+Tanzania
+tao
+Taoist
+Taos
+tap
+tapa
+tape
+taper
+tapestry
+tapeworm
+tapioca
+tapir
+tapis
+tappet
+taproom
+taproot
+tapster
+tar
+tarantara
+tarantella
+tarantula
+Tarbell
+tardy
+target
+Tarheel
+tariff
+tarmac
+tarn
+tarnish
+tarp
+tarpaper
+tarpaulin
+tarpon
+tarragon
+tarry
+Tarrytown
+tart
+tartan
+tartar
+Tartary
+tartrate
+Tarzan
+task
+taskmaster
+taskmistress
+Tasmania
+Tass
+tassel
+taste
+tasting
+tasty
+tat
+Tate
+tater
+tattle
+tattler
+tattletale
+tattoo
+tau
+taught
+taunt
+Taurus
+taut
+tauten
+tautologous
+tautology
+tautonym
+tavern
+taverna
+tawdry
+tawny
+tax
+taxa
+taxation
+taxi
+taxicab
+taxidermic
+taxidermist
+taxidermy
+taxied
+taxiing
+taximeter
+taxiway
+taxon
+taxonomist
+taxonomy
+taxpay
+Taylor
+TB
+tea
+teacart
+teach
+teacup
+teahouse
+teak
+teakettle
+teakwood
+teal
+team
+teammate
+teamster
+teamwork
+teapot
+tear
+teardrop
+tearjerk
+tearoom
+tease
+teasel
+teaspoon
+teat
+teatime
+tech
+technetium
+technic
+technician
+technicolor
+technique
+technocracy
+technocrat
+technocratic
+technology
+tectonic
+tecum
+ted
+teddy
+tedious
+tedium
+tee
+teem
+teen
+teenage
+teensy
+teepee
+teeter
+teeterboard
+teeth
+teethe
+teetotal
+Teflon
+Tegucigalpa
+tegument
+Teheran
+Tehran
+tektite
+Tektronix
+telecom
+Teledyne
+Telefunken
+telegenic
+telegraphy
+telekinesis
+teleology
+telepathic
+telepathy
+telephone
+telephony
+telethon
+Telex
+tell
+telltale
+tellurium
+temblor
+temerity
+temper
+tempera
+temperance
+temperate
+temperature
+tempest
+tempestuous
+template
+temple
+Templeton
+tempo
+temporal
+temporary
+temporize
+tempt
+temptation
+temptress
+tempura
+ten
+tenable
+tenacious
+tenacity
+tenant
+tenantry
+tend
+tendency
+tendentious
+tender
+tenderfeet
+tenderfoot
+tenderhearted
+tenderloin
+tendinitis
+tendon
+tendril
+tenebrous
+tenement
+tenet
+tenfold
+Tenneco
+Tennessee
+Tenney
+tennis
+Tennyson
+tenon
+tenor
+tense
+tensile
+tension
+tensional
+tensor
+tenspot
+tent
+tentacle
+tentage
+tentative
+tenterhook
+tenth
+tenuous
+tenure
+tepee
+tepid
+tequila
+teratogen
+teratogenic
+teratology
+terbium
+tercel
+tercentenary
+teredo
+Terence
+Teresa
+tergiversate
+teriyaki
+term
+termagant
+terminable
+terminal
+terminate
+termini
+terminology
+terminus
+termite
+tern
+ternary
+terpene
+Terpsichore
+terpsichorean
+Terra
+terrace
+terrain
+terramycin
+terrapin
+terrarium
+terrazzo
+Terre
+Terrell
+Terrence
+terrestrial
+Terri
+terrible
+terrier
+terrific
+terrify
+territorial
+territory
+terror
+terry
+terse
+tertiary
+Tess
+tessellate
+tessera
+tesserae
+tessitura
+test
+testament
+testamentary
+testate
+testbed
+testes
+testicle
+testicular
+testify
+testimonial
+testimony
+testosterone
+tetanus
+tetched
+tetchy
+tete
+tether
+tetherball
+Teton
+tetrachloride
+tetracycline
+tetrad
+tetraethyl
+tetrafluoride
+tetrafluouride
+tetragonal
+tetragrammaton
+tetrahedra
+tetrahedral
+tetrahedron
+tetralogy
+tetraploid
+tetravalent
+tetrode
+Teutonic
+Texaco
+Texan
+Texas
+text
+textbook
+textile
+Textron
+textual
+textural
+texture
+TGV
+Thadeus
+Thai
+Thailand
+thalamus
+Thalia
+thallium
+thallophyte
+Thames
+than
+thane
+thank
+thanksgiving
+that
+thatch
+that'll
+thaumaturgic
+thaumaturgy
+thaw
+Thayer
+the
+Thea
+theater
+theatergoer
+theatergoing
+theatric
+Thebes
+thee
+theft
+their
+theirs
+theism
+theist
+Thelma
+them
+thematic
+theme
+themselves
+then
+thence
+thenceforth
+Theo
+theocracy
+theocratic
+theodolite
+Theodore
+theogony
+theologian
+theology
+theorem
+theoretic
+theoretician
+theorist
+theorize
+theory
+theosophy
+therapeutic
+therapist
+therapy
+there
+thereabouts
+thereafter
+thereat
+thereby
+there'd
+therefore
+therefrom
+therein
+there'll
+thereof
+thereon
+Theresa
+Therese
+thereto
+theretofore
+thereunder
+thereunto
+thereupon
+therewith
+therm
+thermal
+thermionic
+thermistor
+thermo
+Thermofax
+thermography
+thermophile
+thermophilic
+thermostat
+thesaurus
+these
+Theseus
+thesis
+thespian
+Thessalonian
+theta
+Thetis
+they
+they'd
+they'll
+they're
+they've
+thiamin
+thiamine
+thick
+thicken
+thicket
+thickheaded
+thickish
+thickset
+thief
+thieve
+thievery
+thievish
+thigh
+thimble
+Thimbu
+thin
+thine
+thing
+thingamajig
+think
+thinnish
+thiocyanate
+thiouracil
+third
+thirst
+thirteen
+thirteenth
+thirtieth
+thirty
+thirtyish
+this
+this'll
+thistle
+thistledown
+thither
+Thomas
+Thomistic
+Thompson
+Thomson
+thong
+Thor
+thorax
+Thoreau
+thorium
+thorn
+Thornton
+thorough
+thoroughbred
+thoroughfare
+thoroughgoing
+Thorpe
+Thorstein
+those
+thou
+though
+thought
+thousand
+thousandfold
+thousandth
+thraldom
+thrall
+thrash
+thread
+threadbare
+threat
+threaten
+three
+threefold
+threesome
+threnody
+thresh
+threshold
+threw
+thrice
+thrift
+thrill
+thrips
+thrive
+throat
+throb
+throes
+thrombosis
+thrombus
+throne
+throng
+throttle
+through
+throughout
+throughput
+throughway
+throve
+throw
+throwaway
+throwback
+thrown
+thrum
+thrush
+thrust
+Thruway
+Thu.
+Thuban
+thud
+thug
+thuggee
+thuggery
+thuggish
+Thule
+thulium
+thumb
+thumbnail
+thumbprint
+thumbscrew
+thumbtack
+thump
+thunder
+thunderbird
+thunderbolt
+thunderclap
+thundercloud
+thunderhead
+thunderous
+thundershower
+thunderstorm
+Thurman
+Thursday
+Thurston
+thus
+thwack
+thwart
+thy
+thyme
+thymine
+thyratron
+thyroid
+thyroidectomy
+thyroxine
+thyself
+ti
+tiara
+Tiber
+Tibet
+Tibetan
+tibia
+Tibor
+tic
+tick
+ticket
+tickle
+ticklish
+tidal
+tidbit
+tide
+tideland
+tidewater
+tidy
+tie
+tieback
+tiedown
+Tientsin
+tiff
+tiffany
+tiger
+tigerish
+tight
+tighten
+tightfisted
+tightrope
+tightwad
+tightwire
+tigress
+Tigris
+til
+tilde
+tile
+till
+tillage
+tilt
+tilth
+Tim
+timber
+timberland
+timberline
+timbre
+time
+timeout
+timepiece
+timesave
+timeserve
+timeshare
+timetable
+timeworn
+Timex
+timid
+Timon
+timorous
+timothy
+timpani
+timpanist
+tin
+Tina
+tincture
+tinder
+tinderbox
+tine
+tinfoil
+tinge
+tingle
+tinhorn
+tinker
+Tinkertoy
+tinkle
+tinkly
+tinplate
+tinsel
+tinsmith
+tint
+tintinnabulate
+tintype
+tinware
+Tioga
+tip
+tipoff
+Tipperary
+tipple
+tipster
+tipsy
+tiptoe
+tirade
+Tirana
+tire
+tiresome
+tissue
+tit
+titan
+titanate
+titanic
+titanium
+titer
+tithe
+tithing
+titian
+titillate
+title
+titmouse
+titrate
+tittle
+titular
+Titus
+TLC
+TN
+TNT
+to
+toad
+toadstool
+toady
+toast
+toastmaster
+toastmistress
+tobacco
+tobacconist
+Tobago
+Tobias
+toboggan
+Toby
+toccata
+tocsin
+today
+Todd
+toddle
+toddy
+toe
+toehold
+toeing
+toenail
+toffee
+tofu
+tog
+together
+toggery
+toggle
+Togo
+togs
+toil
+toilet
+toiletry
+toilette
+toilsome
+toilworn
+tokamak
+token
+Tokyo
+told
+Toledo
+tolerable
+tolerant
+tolerate
+toll
+tollbooth
+tollgate
+tollhouse
+Tolstoy
+toluene
+Tom
+tomahawk
+tomato
+tomatoes
+tomb
+tomboy
+tomboyish
+tombstone
+tomcat
+tome
+tomfoolery
+Tomlinson
+Tommie
+tommy
+tommyrot
+tomograph
+tomography
+tomorrow
+Tompkins
+ton
+tonal
+tone
+tong
+tongue
+Toni
+tonic
+tonight
+tonnage
+tonne
+tonneau
+tonsil
+tonsillectomy
+tonsillitis
+tonsorial
+tonsure
+Tonya
+too
+toodle
+took
+tool
+toolbox
+toolholder
+toolkit
+toolroom
+toolshed
+toolsmith
+toot
+tooth
+toothache
+toothbrush
+toothpaste
+toothpick
+toothsome
+tootle
+top
+topaz
+topcoat
+Topeka
+toper
+topflight
+topgallant
+topiary
+topic
+topkick
+topknot
+topmast
+topmost
+topnotch
+topo
+topocentric
+topography
+topology
+topple
+topsail
+topside
+topsoil
+topsy
+toque
+Torah
+torch
+torchbearer
+torchlight
+tore
+toreador
+tori
+torment
+torn
+tornado
+tornadoes
+toroid
+Toronto
+torpedo
+torpedoes
+torpid
+torpor
+torque
+torr
+Torrance
+torrent
+torrential
+Torres
+torrid
+torsion
+torso
+tort
+torte
+tortellini
+tortilla
+tortious
+tortoise
+tortoiseshell
+tortoni
+tortuous
+torture
+torus
+Tory
+Toshiba
+toss
+tot
+total
+totaled
+totaling
+totalitarian
+totalizator
+tote
+totem
+totemic
+toucan
+touch
+touchback
+touchdown
+touche
+touchhole
+touchstone
+tough
+toughen
+toughie
+toupee
+tour
+touristy
+tourmaline
+tournament
+tourney
+tourniquet
+tousle
+tout
+tow
+toward
+towboat
+towel
+towhead
+towhee
+towline
+town
+townhouse
+towns
+Townsend
+townsfolk
+townspeople
+towpath
+towrope
+toxic
+toxicology
+toxin
+toy
+Toyota
+trace
+traceable
+tracery
+Tracey
+trachea
+tracheal
+tracheotomy
+track
+trackage
+trackwalker
+tract
+Tracy
+trade
+trademark
+tradeoff
+trades
+tradespeople
+tradition
+traduce
+traffic
+trafficked
+trafficker
+trafficking
+tragedian
+tragedienne
+tragedy
+tragic
+tragicomedy
+tragicomic
+trail
+trailblaze
+trailside
+train
+trainee
+trainload
+traipse
+trait
+traitor
+traitorous
+trajectory
+tram
+tramcar
+trammel
+tramp
+trample
+trampoline
+tramway
+Tran
+trance
+tranquil
+tranquillity
+transact
+transalpine
+transatlantic
+transceiver
+transcend
+transcendent
+transcendental
+transconductance
+transcontinental
+transcribe
+transcript
+transducer
+transduction
+transect
+transept
+transfer
+transferable
+transferal
+transferee
+transference
+transferor
+transfiguration
+transfigure
+transfinite
+transfix
+transform
+transformation
+transfuse
+transfusion
+transgenic
+transgress
+transgression
+transgressor
+transient
+transistor
+transit
+Transite
+transition
+transitory
+translate
+transliterate
+translocate
+translucent
+transmigrate
+transmissible
+transmission
+transmit
+transmittable
+transmittal
+transmittance
+transmogrify
+transmutation
+transmute
+transoceanic
+transom
+transpacific
+transparent
+transpiration
+transpire
+transplant
+transplantation
+transpolar
+transpond
+transport
+transportation
+transpose
+transposition
+transship
+transubstantiate
+transuranium
+transversal
+transverse
+transvestite
+trap
+trapdoor
+trapeze
+trapezium
+trapezoid
+traprock
+trapshoot
+trash
+Trastevere
+trauma
+traumatic
+traumatize
+travail
+travel
+travelogue
+traversal
+traverse
+travertine
+travesty
+Travis
+travois
+trawl
+tray
+treacherous
+treachery
+treacle
+tread
+treadle
+treadmill
+treason
+treasonous
+treasure
+treasury
+treat
+treatise
+treaty
+treble
+tree
+treehopper
+treetop
+trefoil
+trek
+trellis
+tremble
+tremendous
+tremolo
+tremor
+tremulous
+trench
+trenchant
+trencherman
+trenchermen
+trend
+Trenton
+trepan
+trepidation
+trespass
+tress
+trestle
+Trevelyan
+Trevor
+triable
+triac
+triad
+trial
+triangle
+triangular
+triangulate
+Triangulum
+Trianon
+Triassic
+triathlon
+triatomic
+triaxial
+tribal
+tribe
+tribes
+tribulate
+tribunal
+tribune
+tributary
+tribute
+trice
+Trichinella
+trichloride
+trichloroethane
+trick
+trickery
+trickle
+trickster
+tricolor
+tricorn
+tricornered
+tricot
+tricycle
+trident
+tridiagonal
+tried
+triennial
+triennium
+trifecta
+trifle
+trifluouride
+trifocal
+trifurcate
+trig
+trigger
+trigonal
+trigonometric
+trigonometry
+trigram
+trigraph
+trihedral
+trilateral
+trilingual
+trill
+trillion
+trillionth
+trilobite
+trilogy
+trim
+trimer
+trimester
+trimotor
+Trinidad
+trinitarian
+trinity
+trinket
+trinomial
+trio
+triode
+trioxide
+trip
+tripartite
+tripe
+triplane
+triple
+triplet
+Triplett
+triplex
+triplicate
+triploid
+tripod
+tripoli
+triptych
+trireme
+trisect
+trisodium
+Tristan
+tristate
+trisyllable
+trite
+tritiate
+tritium
+triton
+tritone
+triumph
+triumphal
+triumphant
+triumvir
+triumvirate
+triune
+trivalent
+trivia
+trivial
+trivium
+trochaic
+trochee
+trod
+trodden
+troglodyte
+troglodytic
+trogon
+troika
+Trojan
+troll
+trolley
+trolleybus
+trollop
+trombone
+trompe
+troop
+trope
+trophic
+trophy
+tropic
+tropism
+tropopause
+troposphere
+tropospheric
+trot
+troth
+troubadour
+trouble
+troubleshoot
+troublesome
+trough
+trounce
+troupe
+trouser
+trousseau
+trout
+Troutman
+trove
+trowel
+troy
+truancy
+truant
+truantry
+truce
+truck
+truckle
+truckload
+truculent
+trudge
+Trudy
+true
+truffle
+truism
+truly
+Truman
+Trumbull
+trump
+trumpery
+trumpet
+truncate
+truncheon
+trundle
+trunk
+trunnion
+truss
+trust
+trustbust
+trustee
+trustworthy
+trusty
+truth
+TRW
+try
+tryout
+trypsin
+tsar
+tsarina
+tsetse
+tsunami
+TTL
+TTY
+tub
+tuba
+tubby
+tube
+tubercle
+tubercular
+tuberculin
+tuberculosis
+tuberculous
+tuberous
+tubular
+tubule
+tuck
+Tucson
+Tudor
+Tue.
+Tuesday
+tufa
+tuff
+tuffet
+tuft
+tug
+tugboat
+tuition
+Tulane
+tulip
+tulle
+Tulsa
+tum
+tumble
+tumbledown
+tumbleweed
+tumbrel
+tumbril
+tumescent
+tumid
+tummy
+tumor
+tumpline
+tumuli
+tumult
+tumultuous
+tumulus
+tun
+tuna
+tundra
+tune
+tung
+tungstate
+tungsten
+tunic
+Tunis
+Tunisia
+tunnel
+tuppence
+turban
+turbid
+turbinate
+turbine
+turbo
+turbocharge
+turbofan
+turbojet
+turboprop
+turbot
+turbulent
+tureen
+turf
+turgid
+Turin
+Turing
+turk
+turkey
+Turkish
+Turkmenistan
+turmeric
+turmoil
+turn
+turnabout
+turnaround
+turnbuckle
+turncoat
+turndown
+turnery
+turnip
+turnkey
+turnoff
+turnout
+turnover
+turnpike
+turnstile
+turnstone
+turntable
+turnup
+turpentine
+turpitude
+turquoise
+turret
+turtle
+turtleback
+turtledove
+turtleneck
+turvy
+Tuscaloosa
+Tuscan
+Tuscany
+Tuscarora
+tusk
+Tuskegee
+tussle
+tussock
+tut
+tutelage
+tutelary
+tutor
+tutorial
+tutti
+Tuttle
+tutu
+tux
+tuxedo
+tuyere
+TV
+TVA
+TWA
+twaddle
+twain
+twang
+tweak
+tweed
+tween
+tweet
+tweeze
+twelfth
+twelve
+twentieth
+twenty
+twentyish
+twerp
+twice
+twiddle
+twig
+twilight
+twill
+twin
+twine
+twinge
+twinkle
+twinkly
+twirl
+twirly
+twist
+twit
+twitch
+twixt
+two
+twofold
+Twombly
+twopenny
+twosome
+TWX
+TX
+Tyburn
+tycoon
+tying
+Tyler
+tympanist
+tympanum
+Tyndall
+type
+typecast
+typeface
+typescript
+typeset
+typewrite
+typewritten
+typhoid
+Typhon
+typhoon
+typhus
+typic
+typify
+typo
+typography
+typology
+tyrannic
+tyrannicide
+tyrannize
+tyrannosaurus
+tyrannous
+tyranny
+tyrant
+tyro
+tyrosine
+tyrranize
+Tyson
+UAL
+ubiquitous
+ubiquity
+UCLA
+udder
+Uganda
+ugh
+uglify
+ugly
+UHF
+UJA
+U.K.
+UK
+ukase
+Ukraine
+Ukrainian
+ukulele
+Ulan
+ulcer
+ulcerate
+ulcerous
+Ullman
+ulna
+ulster
+ulterior
+ultimacy
+ultimate
+ultimatum
+ultra
+ululate
+Ulysses
+umber
+umbilical
+umbilici
+umbilicus
+umbra
+umbrage
+umbrageous
+umbrella
+umiak
+umlaut
+umpire
+umpteen
+umpteenth
+U.N.
+UN
+unaided
+unanimity
+unanimous
+unarticulated
+unary
+unbeknown
+unbeknownst
+unbidden
+unborn
+uncanny
+unchristian
+uncial
+uncle
+uncompleted
+uncouth
+unction
+unctuous
+under
+underclassman
+underclassmen
+underlie
+underling
+underlying
+undulant
+undulate
+unending
+UNESCO
+unfertilized
+uniaxial
+unicameral
+unicellular
+unicorn
+unicycle
+unidimensional
+unidirectional
+uniform
+uniformitarian
+unify
+unilateral
+unimodal
+unimodular
+uninominal
+union
+uniplex
+unipolar
+uniprocessor
+unique
+Uniroyal
+unisex
+unisexual
+unison
+unit
+unitarian
+unitary
+unite
+unity
+Univac
+univalent
+univariate
+universal
+universe
+univocal
+Unix
+unkempt
+unlucky
+unmediated
+unmet
+unmoderated
+unperturbed
+unpolitical
+unportable
+unprovable
+unproved
+unruly
+unscented
+untainted
+until
+untilled
+unto
+untouchable
+unused
+unvented
+unwary
+unwieldy
+up
+upbeat
+upbraid
+upbring
+upchuck
+upcome
+update
+updraft
+upend
+upgrade
+upheaval
+upheave
+upheld
+uphill
+uphold
+upholster
+upholstery
+UPI
+upkeep
+upland
+uplift
+upload
+upmost
+upon
+upperclass
+uppercut
+uppermost
+uppity
+upraise
+uprear
+upright
+uprise
+uprisen
+upriver
+uproar
+uproarious
+uproot
+uprose
+upscale
+upset
+upshot
+upside
+upsilon
+upslope
+upstage
+upstairs
+upstand
+upstart
+upstate
+upstater
+upstream
+upstroke
+upsurge
+upsweep
+upswept
+upswing
+uptake
+upthrust
+uptilt
+uptime
+Upton
+uptown
+uptrend
+upturn
+upward
+upwell
+upwind
+uranium
+Uranus
+uranyl
+urban
+Urbana
+urbane
+urbanite
+urchin
+urea
+urethane
+urethra
+urge
+urgency
+urgent
+uric
+urinal
+urinalysis
+urinary
+urinate
+urine
+Uris
+urn
+urology
+Ursa
+ursine
+Ursula
+Ursuline
+Uruguay
+U.S.
+u's
+us
+U.S.A.
+USA
+USAF
+usage
+USC
+USC&GS
+USDA
+use
+useful
+USGS
+usher
+usherette
+USIA
+USMA
+USMC
+USN
+USNA
+USNR
+USPS
+USSR
+usual
+usurer
+usurious
+usurp
+usurpation
+usury
+UT
+Utah
+utensil
+uterine
+utero
+uterus
+Utica
+utile
+utilitarian
+utmost
+utopia
+utopian
+utter
+utterance
+uttermost
+uvula
+uxorial
+uxorious
+Uzbekistan
+Uzi
+VA
+vacant
+vacate
+vacationland
+vaccinate
+vaccine
+vaccinia
+vacillate
+vacua
+vacuity
+vacuo
+vacuolate
+vacuole
+vacuous
+vacuum
+Vaduz
+vagabond
+vagarious
+vagary
+vagina
+vaginal
+vagrant
+vague
+Vail
+vain
+vainglorious
+vainglory
+Valdez
+vale
+valediction
+valedictorian
+valedictory
+valent
+valentine
+Valerie
+Valery
+valet
+Valhalla
+valiant
+valid
+validate
+valise
+Valkyrie
+Valletta
+valley
+Valois
+valor
+valorous
+valuable
+valuate
+value
+valve
+vamoose
+vamp
+vampire
+van
+vanadium
+Vance
+Vancouver
+vandal
+Vandenberg
+Vanderbilt
+Vanderpoel
+vane
+Vanessa
+vanguard
+vanilla
+vanish
+vanity
+vanload
+vanquish
+vantage
+vapid
+vapor
+vaporous
+Vargas
+variable
+variac
+Varian
+variant
+variate
+varicolored
+varicose
+variegate
+varietal
+variety
+variorum
+various
+varistor
+Varitype
+varlet
+varmint
+varnish
+varsity
+vary
+vascular
+vase
+vasectomy
+Vaseline
+vasoconstrict
+vasodilate
+vasomotor
+Vasquez
+vassal
+vassalage
+Vassar
+vast
+vasty
+vat
+Vatican
+vaudeville
+vaudevillian
+Vaudois
+Vaughan
+Vaughn
+vault
+vaunt
+VCR
+veal
+vector
+vectorial
+Veda
+vee
+veep
+veer
+veery
+Vega
+vegetable
+vegetal
+vegetarian
+vegetate
+veggie
+vehement
+vehicle
+vehicular
+veil
+vein
+velar
+Velasquez
+Velcro
+veld
+veldt
+Vella
+vellum
+Velma
+velocipede
+velocity
+velour
+velvet
+velveteen
+venal
+venation
+vend
+vendetta
+vendible
+vendor
+veneer
+venerable
+venerate
+venereal
+venery
+Venetian
+Veneto
+Venezuela
+vengeance
+vengeful
+venial
+Venice
+venin
+venire
+venison
+venom
+venomous
+venous
+vent
+ventilate
+ventral
+ventricle
+ventricular
+ventriloquism
+ventriloquist
+ventriloquy
+venture
+venturesome
+venturi
+venturous
+venue
+Venus
+Venusian
+Vera
+veracious
+veracity
+veranda
+verandah
+verb
+verbal
+verbatim
+verbena
+verbiage
+verbose
+verbosity
+verdant
+Verde
+Verdi
+verdict
+verdure
+verge
+veridic
+verify
+verisimilitude
+veritable
+verity
+Verlag
+vermeil
+vermicelli
+vermicide
+vermiculite
+vermilion
+vermin
+verminous
+Vermont
+vermouth
+Vern
+Verna
+vernacular
+vernal
+Verne
+vernier
+Vernon
+Verona
+Veronica
+versa
+Versailles
+versant
+versatile
+verse
+versify
+version
+verso
+verst
+versus
+vertebra
+vertebrae
+vertebral
+vertebrate
+vertex
+vertical
+vertices
+vertiginous
+vertigo
+vertigoes
+verve
+very
+vesicle
+vesicular
+vesper
+vessel
+vest
+vestal
+vestibular
+vestibule
+vestige
+vestigial
+vestry
+vet
+vetch
+veteran
+veterinarian
+veterinary
+veto
+vetoes
+vex
+vexation
+vexatious
+VHF
+VHS
+vi
+via
+viable
+viaduct
+vial
+viand
+vibrant
+vibraphone
+vibrate
+vibrato
+viburnum
+Vic
+vicar
+vicarage
+vicarious
+vice
+viceregal
+viceroy
+Vichy
+vichyssoise
+vicinal
+vicinity
+vicious
+vicissitude
+Vicki
+Vickie
+Vicksburg
+Vicky
+victim
+victor
+Victoria
+Victorian
+victorious
+victory
+victual
+vicuna
+Vida
+vide
+video
+videoconference
+videotape
+vidicon
+vie
+Vienna
+Viennese
+Vientiane
+Viet
+Vietnam
+Vietnamese
+view
+viewpoint
+vigil
+vigilant
+vigilante
+vigilantism
+vigintillion
+vignette
+vignetting
+vigor
+vigorous
+vii
+viii
+Viking
+vile
+vilify
+villa
+village
+villain
+villainous
+villainy
+villein
+vim
+Vincent
+vincible
+vinculum
+vindicate
+vindictive
+vine
+vinegar
+vineyard
+viniculture
+vinous
+Vinson
+vintage
+vintner
+vinyl
+viol
+viola
+violate
+violent
+violet
+violin
+violist
+VIP
+viper
+virago
+viral
+vireo
+Virgil
+virgin
+virginal
+Virginia
+Virginian
+Virgo
+virgule
+virile
+virology
+virtual
+virtue
+virtuosi
+virtuosity
+virtuoso
+virtuous
+virulent
+virus
+vis
+visa
+visage
+viscera
+visceral
+viscid
+viscoelastic
+viscometer
+viscosimeter
+viscosity
+viscount
+viscous
+vise
+Vishnu
+visible
+Visigoth
+Visigothic
+vision
+visionary
+visit
+visitation
+visitor
+visor
+vista
+visual
+vita
+vitae
+vital
+vitamin
+vitiate
+viticulture
+Vito
+vitreous
+vitrify
+vitriol
+vitriolic
+vitro
+vituperate
+viva
+vivace
+vivacious
+vivacity
+Vivaldi
+Vivian
+vivid
+vivify
+viviparous
+vivisect
+vivo
+vixen
+viz.
+vizier
+Vladimir
+Vladivostok
+vocable
+vocabulary
+vocal
+vocalic
+vocate
+vociferate
+vociferous
+vocoder
+vodka
+Vogel
+vogue
+voguish
+voice
+voiceband
+void
+volatile
+volcanic
+volcanism
+volcano
+Volga
+volition
+Volkswagen
+volley
+volleyball
+volocanology
+Volstead
+volt
+Volta
+voltage
+voltaic
+Voltaire
+Volterra
+voltmeter
+voluble
+volume
+volumetric
+voluminous
+voluntarism
+voluntary
+volunteer
+voluptuary
+voluptuous
+volute
+Volvo
+vomit
+von
+voodoo
+voracious
+voracity
+vortex
+vortices
+vorticity
+Voss
+votary
+vote
+votive
+vouch
+vouchsafe
+Vought
+vow
+vowel
+voyage
+voyageur
+voyeur
+V.P.
+VP
+Vreeland
+v's
+vs
+vs.
+VT
+Vulcan
+vulcanize
+vulgar
+vulgarian
+vulgate
+vulnerable
+vulpine
+vulture
+vulva
+VW
+vying
+WA
+Waals
+Wabash
+WAC
+wacky
+Waco
+wad
+waddle
+wade
+wader
+wadi
+Wadsworth
+wafer
+waffle
+waft
+wag
+wage
+wager
+waggish
+waggle
+Wagner
+Wagnerian
+wagon
+wagoneer
+wagonload
+wah
+Wahl
+wahoo
+waif
+wail
+wainscot
+Wainwright
+waist
+waistband
+waistcoat
+waistline
+wait
+Waite
+waitress
+waive
+wake
+Wakefield
+waken
+wakeup
+Walcott
+Walden
+Waldo
+Waldorf
+Waldron
+wale
+Walgreen
+walk
+walkie
+walkout
+walkover
+walkway
+wall
+wallaby
+Wallace
+wallboard
+Waller
+wallet
+walleye
+Wallis
+wallop
+wallow
+wallpaper
+walnut
+Walpole
+walrus
+Walsh
+Walt
+Walter
+Walters
+Waltham
+Walton
+waltz
+waltzing
+wampum
+wan
+wand
+Wanda
+wander
+wanderlust
+wane
+Wang
+wangle
+want
+wanton
+wapiti
+Wappinger
+war
+warble
+ward
+warden
+wardrobe
+wardroom
+ware
+warehouse
+warfare
+warfarin
+warhead
+warhorse
+Waring
+warlock
+warlord
+warm
+warmhearted
+warmish
+warmonger
+warmth
+warmup
+warn
+warp
+warpath
+warplane
+warrant
+warranty
+warren
+warrior
+Warsaw
+wart
+warthog
+wartime
+Warwick
+was
+wash
+washbasin
+washboard
+washbowl
+Washburn
+washcloth
+washer
+Washington
+washout
+washrag
+washroom
+washstand
+washtub
+wasn't
+wasp
+waspish
+wassail
+Wasserman
+wast
+wastage
+waste
+wastebasket
+wasteland
+wastepaper
+wastewater
+wasting
+wastrel
+watch
+watchband
+watchcase
+watchdog
+watchtower
+watchword
+water
+waterbed
+waterborne
+Waterbury
+watercolor
+watercourse
+watercraft
+watercress
+waterfall
+waterfowl
+waterfront
+Watergate
+Waterhouse
+waterlily
+waterline
+waterlog
+waterloo
+watermark
+watermelon
+waterproof
+watershed
+waterside
+waterspout
+watertight
+Watertown
+waterway
+waterworks
+watery
+Watkins
+Watson
+watt
+wattage
+wattle
+wattmeter
+wave
+waveform
+wavefront
+waveguide
+wavelength
+wavelet
+wavenumber
+waver
+wax
+waxen
+waxwing
+waxwork
+way
+waybill
+wayfare
+waylaid
+waylay
+Wayne
+wayside
+wayward
+we
+weak
+weaken
+weakish
+weakling
+weal
+wealth
+wean
+weapon
+weaponry
+wear
+wearied
+wearisome
+weary
+weasel
+weather
+weatherbeaten
+weathercock
+weatherglass
+weatherproof
+weatherstrip
+weathertight
+weave
+web
+Webb
+weber
+Webster
+WECo
+we'd
+wed
+wedge
+wedlock
+Wednesday
+wee
+weed
+week
+weekday
+weekend
+weeklong
+ween
+weep
+weevil
+Wehr
+Wei
+Weierstrass
+weigh
+weight
+Weinberg
+Weinstein
+weir
+weird
+Weiss
+Welch
+welcome
+weld
+Weldon
+welfare
+welkin
+we'll
+well
+wellbeing
+wellborn
+Weller
+Welles
+Wellesley
+wellhead
+Wellington
+wellingtons
+wellspring
+welsh
+welt
+wen
+wench
+wend
+Wendell
+Wendy
+went
+wept
+we're
+were
+weren't
+werewolf
+werewolves
+Werner
+wert
+Werther
+Wesley
+Wesleyan
+west
+westbound
+Westchester
+westerly
+western
+westernmost
+Westfield
+Westinghouse
+Westminster
+westmost
+Weston
+westward
+wet
+wetback
+wetland
+we've
+Weyerhauser
+whack
+whale
+whaleboat
+whalebone
+Whalen
+wham
+whammy
+wharf
+wharfinger
+Wharton
+wharves
+what
+what'd
+whatever
+Whatley
+whatnot
+what're
+whatsoever
+wheat
+Wheaties
+Wheatstone
+whee
+wheedle
+wheel
+wheelbarrow
+wheelbase
+wheelchair
+wheelhorse
+wheelhouse
+wheelwright
+wheeze
+Whelan
+whelk
+Wheller
+whelm
+whelp
+when
+whence
+whenever
+whensoever
+where
+whereabout
+whereas
+whereat
+whereby
+where'd
+wherefore
+wherefrom
+wherein
+whereof
+whereon
+where're
+wheresoever
+whereunto
+whereupon
+wherever
+wherewith
+wherewithal
+wherry
+whet
+whether
+whetstone
+whey
+wheyey
+which
+whichever
+whiff
+whiffle
+whiffletree
+whig
+while
+whilom
+whim
+whimper
+whimsical
+whimsy
+whine
+whinny
+whip
+whipcord
+whiplash
+whippersnapper
+whippet
+Whipple
+whippoorwill
+whipsaw
+whir
+whirl
+whirligig
+whirlpool
+whirlwind
+whirlybird
+whirr
+whish
+whisk
+whiskery
+whiskey
+whisper
+whist
+whistle
+whistleable
+whistleblow
+whit
+Whitaker
+Whitcomb
+white
+whitecap
+whiteface
+whitefish
+Whitehall
+whitehead
+Whitehorse
+whiten
+whiteout
+whitetail
+whitewall
+whitewash
+whitey
+whither
+whitish
+Whitlock
+Whitman
+Whitney
+Whittaker
+Whittier
+whittle
+whiz
+whizbang
+who
+whoa
+who'd
+whodunit
+whoever
+whole
+wholehearted
+wholesale
+wholesome
+who'll
+wholly
+whom
+whomever
+whomp
+whomsoever
+whoop
+whoopee
+whoosh
+whop
+whore
+whorehouse
+whorl
+whose
+whosoever
+who've
+whup
+why
+WI
+Wichita
+wick
+wickerwork
+wicket
+wide
+widen
+widespread
+widgeon
+widget
+widish
+widow
+width
+widthwise
+wield
+wiener
+Wier
+wife
+wig
+Wiggins
+wiggle
+wiggly
+wigwag
+wigwam
+Wilbert
+Wilbur
+Wilcox
+wild
+wildcat
+wildebeest
+wilderment
+wildfire
+wildfowl
+wildlife
+wildwood
+wile
+Wiley
+Wilfred
+Wilhelm
+Wilhelmina
+Wilkerson
+Wilkes
+Wilkins
+Wilkinson
+will
+Willa
+Willard
+William
+Williams
+Williamsburg
+Williamson
+Willie
+Willis
+Willoughby
+willow
+willpower
+willy
+Wilma
+Wilmington
+Wilshire
+Wilson
+wilt
+wily
+wimp
+win
+wince
+winch
+Winchester
+wind
+windage
+windbag
+windblown
+windbreak
+windburn
+windfall
+windjammer
+windlass
+windmill
+window
+windowpane
+windowsill
+windpipe
+windproof
+windrow
+windscreen
+windshield
+Windsor
+windstorm
+windsurf
+windswept
+windup
+windward
+wine
+wineglass
+winegrower
+winemaster
+winepress
+winery
+wineshop
+wineskin
+Winfield
+wing
+wingback
+winglet
+wingspan
+wingspread
+wingtip
+Winifred
+wink
+winkle
+Winnetka
+Winnie
+Winnipeg
+winnow
+wino
+Winslow
+winsome
+Winston
+winter
+wintergreen
+wintertime
+wintery
+Winthrop
+wintry
+winy
+wipe
+wirable
+wire
+wirehair
+wiretap
+Wisconsin
+wisdom
+wise
+wiseacre
+wisecrack
+wisenheimer
+wish
+wishbone
+wisp
+wisteria
+wistful
+wit
+witch
+witchcraft
+with
+withal
+withdraw
+withdrawal
+withdrawn
+withdrew
+withe
+withheld
+withhold
+within
+without
+withstand
+withstood
+witness
+Witt
+witticism
+wive
+wizard
+wizardry
+wizen
+WNW
+woad
+wobble
+woe
+woebegone
+wok
+woke
+Wolcott
+wolf
+Wolfe
+Wolff
+Wolfgang
+wolfhound
+wolfish
+wolverine
+wolves
+woman
+womanish
+womankind
+womb
+wombat
+women
+womenfolk
+won
+wonder
+wonderland
+wonderwork
+wondrous
+Wong
+wonk
+won't
+wont
+woo
+wood
+Woodard
+woodbine
+Woodbury
+woodcarver
+woodchopper
+woodchuck
+woodcock
+woodcraft
+woodcut
+wooden
+woodenhead
+woodgrain
+woodhen
+woodland
+Woodlawn
+woodlot
+woodpecker
+woodpile
+Woodrow
+woodruff
+woods
+woodshed
+woodside
+Woodstock
+woodsy
+woodturner
+Woodward
+woodwind
+woodwork
+woof
+wool
+woolen
+woolgather
+Woolworth
+Wooster
+woozy
+Worcester
+word
+wordmonger
+wordplay
+wordsmith
+Wordsworth
+wore
+work
+workable
+workaday
+workaholic
+workbag
+workbasket
+workbench
+workbook
+workday
+workforce
+workhorse
+workhouse
+working
+workload
+workman
+workout
+workpiece
+workplace
+workroom
+worksheet
+workshop
+workspace
+workstation
+worktable
+workweek
+world
+worldwide
+worm
+wormhole
+wormwood
+worn
+worrisome
+worry
+worse
+worsen
+worship
+worst
+worth
+Worthington
+worthwhile
+worthy
+Wotan
+would
+wouldn't
+wouldst
+wound
+wove
+woven
+wow
+WPA
+wrack
+wraith
+wrangle
+wrap
+wraparound
+wrapup
+wrasse
+wrath
+wreak
+wreath
+wreathe
+wreck
+wreckage
+wren
+wrench
+wrest
+wrestle
+wretch
+wriggle
+wriggly
+wright
+Wrigley
+wring
+wrinkle
+wrinkly
+wrist
+wristband
+wristlet
+wristwatch
+writ
+write
+writeup
+writhe
+writhing
+written
+wrong
+wrongdoer
+wrongdoing
+wrongheaded
+Wronskian
+wrote
+wrought
+wrung
+wry
+w's
+WSW
+Wu
+Wuhan
+wunderkind
+wurst
+WV
+WWI
+WWII
+WY
+Wyandotte
+Wyatt
+Wyeth
+Wylie
+Wyman
+Wyner
+Wyoming
+Xavier
+x'd
+xebec
+xenolith
+xenon
+xenophobe
+xenophobic
+xeric
+xeriscape
+xerography
+Xerox
+Xerxes
+xi
+Xiao
+x'ing
+Xmas
+Xosa
+x's
+xylem
+xylene
+xylophone
+yacht
+yachts
+yack
+yackety
+yagi
+yah
+yahoo
+Yahweh
+yak
+Yakima
+Yale
+Yalta
+yam
+Yamaha
+yammer
+yang
+Yangtze
+yank
+Yankee
+Yankton
+Yaounde
+yap
+yapping
+Yaqui
+yard
+yardage
+yardarm
+yardbird
+yardmaster
+yardstick
+Yarmouth
+yarmulke
+yarn
+yarrow
+Yates
+yaw
+yawl
+yawn
+yawp
+yclept
+ye
+yea
+Yeager
+yeah
+year
+yearbook
+yearling
+yearn
+yeast
+Yeats
+yegg
+yell
+yellow
+yellowish
+Yellowknife
+yellowlegs
+Yellowstone
+yelp
+Yemen
+yen
+yeoman
+yeomanry
+Yerkes
+yes
+yeshiva
+yesterday
+yesteryear
+yet
+yeti
+yew
+Yiddish
+yield
+yin
+yip
+yippee
+yipping
+YMCA
+yodel
+Yoder
+yoga
+yogi
+yogurt
+yoke
+yokel
+Yokohama
+Yokuts
+Yolanda
+yolk
+yon
+yond
+Yonkers
+yore
+York
+Yorker
+Yorktown
+Yosemite
+Yost
+you
+you'd
+you'll
+young
+youngish
+youngster
+Youngstown
+your
+you're
+yours
+yourself
+yourselves
+youth
+you've
+yowl
+Ypsilanti
+y's
+ytterbium
+yttrium
+Yucatan
+yucca
+Yugoslav
+Yugoslavia
+yuh
+Yuki
+Yukon
+yule
+yuletide
+yummy
+yuppie
+Yves
+Yvette
+Yvonne
+YWCA
+zabaglione
+Zachary
+zag
+zaibatsu
+Zaire
+Zambia
+Zan
+zany
+Zanzibar
+zap
+zarzuela
+zeal
+Zealand
+Zealander
+zealot
+zealotry
+zealous
+zebra
+zebu
+Zechariah
+zed
+Zeiss
+zeitgeist
+Zelda
+Zellerbach
+Zen
+zenith
+Zeno
+zeolite
+Zephaniah
+zephyr
+zeppelin
+zero
+zeroth
+zest
+zeta
+Zeus
+Ziegler
+zig
+ziggurat
+zigzag
+zilch
+zillion
+Zimbabwe
+Zimmerman
+zinc
+zing
+zinnia
+Zion
+zip
+zircon
+zirconium
+zither
+zloty
+zlotys
+zodiac
+zodiacal
+Zoe
+Zomba
+zombie
+zonal
+zonate
+zone
+zonk
+zoo
+zoogeography
+zoology
+zoom
+zoomorph
+zoomorphic
+zoophyte
+Zoroaster
+zounds
+z's
+zucchini
+Zulu
+Zurich
+zwieback
+zygote
+zygotic
+zymurgy
--- /dev/null
+++ b/lib/yaccpar
@@ -1,0 +1,211 @@
+
+YYSys: module
+{
+ FD: adt
+ {
+ fd: int;
+ };
+ fildes: fn(fd: int): ref FD;
+ fprint: fn(fd: ref FD, s: string, *): int;
+};
+
+yysys: YYSys;
+yystderr: ref YYSys->FD;
+
+YYFLAG: con -1000;
+
+# parser for yacc output
+
+yytokname(yyc: int): string
+{
+ if(yyc > 0 && yyc <= len yytoknames && yytoknames[yyc-1] != nil)
+ return yytoknames[yyc-1];
+ return "<"+string yyc+">";
+}
+
+yystatname(yys: int): string
+{
+ if(yys >= 0 && yys < len yystates && yystates[yys] != nil)
+ return yystates[yys];
+ return "<"+string yys+">\n";
+}
+
+yylex1(yylex: ref YYLEX): int
+{
+ c : int;
+ yychar := yylex.lex();
+ if(yychar <= 0)
+ c = yytok1[0];
+ else if(yychar < len yytok1)
+ c = yytok1[yychar];
+ else if(yychar >= YYPRIVATE && yychar < YYPRIVATE+len yytok2)
+ c = yytok2[yychar-YYPRIVATE];
+ else{
+ n := len yytok3;
+ c = 0;
+ for(i := 0; i < n; i+=2) {
+ if(yytok3[i+0] == yychar) {
+ c = yytok3[i+1];
+ break;
+ }
+ }
+ if(c == 0)
+ c = yytok2[1]; # unknown char
+ }
+ if(yydebug >= 3)
+ yysys->fprint(yystderr, "lex %.4ux %s\n", yychar, yytokname(c));
+ return c;
+}
+
+YYS: adt
+{
+ yyv: YYSTYPE;
+ yys: int;
+};
+
+yyparse(yylex: ref YYLEX): int
+{
+ if(yydebug >= 1 && yysys == nil) {
+ yysys = load YYSys "$Sys";
+ yystderr = yysys->fildes(2);
+ }
+
+ yys := array[YYMAXDEPTH] of YYS;
+
+ yyval: YYSTYPE;
+ yystate := 0;
+ yychar := -1;
+ yynerrs := 0; # number of errors
+ yyerrflag := 0; # error recovery flag
+ yyp := -1;
+ yyn := 0;
+
+yystack:
+ for(;;){
+ # put a state and value onto the stack
+ if(yydebug >= 4)
+ yysys->fprint(yystderr, "char %s in %s", yytokname(yychar), yystatname(yystate));
+
+ yyp++;
+ if(yyp >= len yys)
+ yys = (array[len yys * 2] of YYS)[0:] = yys;
+ yys[yyp].yys = yystate;
+ yys[yyp].yyv = yyval;
+
+ for(;;){
+ yyn = yypact[yystate];
+ if(yyn > YYFLAG) { # simple state
+ if(yychar < 0)
+ yychar = yylex1(yylex);
+ yyn += yychar;
+ if(yyn >= 0 && yyn < YYLAST) {
+ yyn = yyact[yyn];
+ if(yychk[yyn] == yychar) { # valid shift
+ yychar = -1;
+ yyp++;
+ if(yyp >= len yys)
+ yys = (array[len yys * 2] of YYS)[0:] = yys;
+ yystate = yyn;
+ yys[yyp].yys = yystate;
+ yys[yyp].yyv = yylex.lval;
+ if(yyerrflag > 0)
+ yyerrflag--;
+ if(yydebug >= 4)
+ yysys->fprint(yystderr, "char %s in %s", yytokname(yychar), yystatname(yystate));
+ continue;
+ }
+ }
+ }
+
+ # default state action
+ yyn = yydef[yystate];
+ if(yyn == -2) {
+ if(yychar < 0)
+ yychar = yylex1(yylex);
+
+ # look through exception table
+ for(yyxi:=0;; yyxi+=2)
+ if(yyexca[yyxi] == -1 && yyexca[yyxi+1] == yystate)
+ break;
+ for(yyxi += 2;; yyxi += 2) {
+ yyn = yyexca[yyxi];
+ if(yyn < 0 || yyn == yychar)
+ break;
+ }
+ yyn = yyexca[yyxi+1];
+ if(yyn < 0){
+ yyn = 0;
+ break yystack;
+ }
+ }
+
+ if(yyn != 0)
+ break;
+
+ # error ... attempt to resume parsing
+ if(yyerrflag == 0) { # brand new error
+ yylex.error("syntax error");
+ yynerrs++;
+ if(yydebug >= 1) {
+ yysys->fprint(yystderr, "%s", yystatname(yystate));
+ yysys->fprint(yystderr, "saw %s\n", yytokname(yychar));
+ }
+ }
+
+ if(yyerrflag != 3) { # incompletely recovered error ... try again
+ yyerrflag = 3;
+
+ # find a state where "error" is a legal shift action
+ while(yyp >= 0) {
+ yyn = yypact[yys[yyp].yys] + YYERRCODE;
+ if(yyn >= 0 && yyn < YYLAST) {
+ yystate = yyact[yyn]; # simulate a shift of "error"
+ if(yychk[yystate] == YYERRCODE)
+ continue yystack;
+ }
+
+ # the current yyp has no shift onn "error", pop stack
+ if(yydebug >= 2)
+ yysys->fprint(yystderr, "error recovery pops state %d, uncovers %d\n",
+ yys[yyp].yys, yys[yyp-1].yys );
+ yyp--;
+ }
+ # there is no state on the stack with an error shift ... abort
+ yyn = 1;
+ break yystack;
+ }
+
+ # no shift yet; clobber input char
+ if(yydebug >= 2)
+ yysys->fprint(yystderr, "error recovery discards %s\n", yytokname(yychar));
+ if(yychar == YYEOFCODE) {
+ yyn = 1;
+ break yystack;
+ }
+ yychar = -1;
+ # try again in the same state
+ }
+
+ # reduction by production yyn
+ if(yydebug >= 2)
+ yysys->fprint(yystderr, "reduce %d in:\n\t%s", yyn, yystatname(yystate));
+
+ yypt := yyp;
+ yyp -= yyr2[yyn];
+# yyval = yys[yyp+1].yyv;
+ yym := yyn;
+
+ # consult goto table to find next state
+ yyn = yyr1[yyn];
+ yyg := yypgo[yyn];
+ yyj := yyg + yys[yyp].yys + 1;
+
+ if(yyj >= YYLAST || yychk[yystate=yyact[yyj]] != -yyn)
+ yystate = yyact[yyg];
+ case yym {
+ $A
+ }
+ }
+
+ return yyn;
+}
--- /dev/null
+++ b/lib9/NOTICE
@@ -1,0 +1,29 @@
+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-2007 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.
+
--- /dev/null
+++ b/lib9/argv0.c
@@ -1,0 +1,1 @@
+char* argv0 = 0;
--- /dev/null
+++ b/lib9/charstod.c
@@ -1,0 +1,80 @@
+#include "lib9.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.
+ */
+
+#define ADVANCE *s++ = c; if(s>=e) return NaN(); c = (*f)(vp)
+
+double
+charstod(int(*f)(void*), void *vp)
+{
+ char str[400], *s, *e, *start;
+ int c;
+
+ s = str;
+ e = str + sizeof str - 1;
+ c = (*f)(vp);
+ while(c == ' ' || c == '\t')
+ c = (*f)(vp);
+ if(c == '-' || c == '+'){
+ ADVANCE;
+ }
+ start = s;
+ while(c >= '0' && c <= '9'){
+ ADVANCE;
+ }
+ if(c == '.'){
+ ADVANCE;
+ while(c >= '0' && c <= '9'){
+ ADVANCE;
+ }
+ }
+ if(s > start && (c == 'e' || c == 'E')){
+ ADVANCE;
+ if(c == '-' || c == '+'){
+ ADVANCE;
+ }
+ while(c >= '0' && c <= '9'){
+ ADVANCE;
+ }
+ }else if(s == start && (c == 'i' || c == 'I')){
+ ADVANCE;
+ if(c != 'n' && c != 'N')
+ return NaN();
+ ADVANCE;
+ if(c != 'f' && c != 'F')
+ return NaN();
+ ADVANCE;
+ if(c != 'i' && c != 'I')
+ return NaN();
+ ADVANCE;
+ if(c != 'n' && c != 'N')
+ return NaN();
+ ADVANCE;
+ if(c != 'i' && c != 'I')
+ return NaN();
+ ADVANCE;
+ if(c != 't' && c != 'T')
+ return NaN();
+ ADVANCE;
+ if(c != 'y' && c != 'Y')
+ return NaN();
+ ADVANCE; /* so caller can back up uniformly */
+ USED(c);
+ }else if(s == str && (c == 'n' || c == 'N')){
+ ADVANCE;
+ if(c != 'a' && c != 'A')
+ return NaN();
+ ADVANCE;
+ if(c != 'n' && c != 'N')
+ return NaN();
+ ADVANCE; /* so caller can back up uniformly */
+ USED(c);
+ }
+ *s = 0;
+ return strtod(str, &s);
+}
--- /dev/null
+++ b/lib9/cistrcmp.c
@@ -1,0 +1,25 @@
+#include "lib9.h"
+
+int
+cistrcmp(char *s1, char *s2)
+{
+ int c1, c2;
+
+ while(*s1){
+ c1 = *(uchar*)s1++;
+ c2 = *(uchar*)s2++;
+
+ if(c1 == c2)
+ continue;
+
+ if(c1 >= 'A' && c1 <= 'Z')
+ c1 -= 'A' - 'a';
+
+ if(c2 >= 'A' && c2 <= 'Z')
+ c2 -= 'A' - 'a';
+
+ if(c1 != c2)
+ return c1 - c2;
+ }
+ return -*s2;
+}
--- /dev/null
+++ b/lib9/cistrncmp.c
@@ -1,0 +1,27 @@
+#include "lib9.h"
+
+int
+cistrncmp(char *s1, char *s2, int n)
+{
+ int c1, c2;
+
+ while(*s1 && n-- > 0){
+ c1 = *(uchar*)s1++;
+ c2 = *(uchar*)s2++;
+
+ if(c1 == c2)
+ continue;
+
+ if(c1 >= 'A' && c1 <= 'Z')
+ c1 -= 'A' - 'a';
+
+ if(c2 >= 'A' && c2 <= 'Z')
+ c2 -= 'A' - 'a';
+
+ if(c1 != c2)
+ return c1 - c2;
+ }
+ if(n <= 0)
+ return 0;
+ return -*s2;
+}
--- /dev/null
+++ b/lib9/cistrstr.c
@@ -1,0 +1,22 @@
+#include "lib9.h"
+
+char*
+cistrstr(char *s, char *sub)
+{
+ int c, csub, n;
+
+ csub = *sub;
+ if(csub == '\0')
+ return s;
+ if(csub >= 'A' && csub <= 'Z')
+ csub -= 'A' - 'a';
+ sub++;
+ n = strlen(sub);
+ for(; c = *s; s++){
+ if(c >= 'A' && c <= 'Z')
+ c -= 'A' - 'a';
+ if(c == csub && cistrncmp(s+1, sub, n) == 0)
+ return s;
+ }
+ return nil;
+}
--- /dev/null
+++ b/lib9/cleanname.c
@@ -1,0 +1,62 @@
+#include "lib9.h"
+
+/*
+ * In place, rewrite name to compress multiple /, eliminate ., and process ..
+ */
+#define SEP(x) ((x)=='/' || (x) == 0)
+char*
+cleanname(char *name)
+{
+ char *p, *q, *dotdot;
+ int rooted, erasedprefix;
+
+ rooted = name[0] == '/';
+ erasedprefix = 0;
+
+ /*
+ * invariants:
+ * p points at beginning of path element we're considering.
+ * q points just past the last path element we wrote (no slash).
+ * dotdot points just past the point where .. cannot backtrack
+ * any further (no slash).
+ */
+ p = q = dotdot = name+rooted;
+ while(*p) {
+ if(p[0] == '/') /* null element */
+ p++;
+ else if(p[0] == '.' && SEP(p[1])) {
+ if(p == name)
+ erasedprefix = 1;
+ p += 1; /* don't count the separator in case it is nul */
+ } else if(p[0] == '.' && p[1] == '.' && SEP(p[2])) {
+ p += 2;
+ if(q > dotdot) { /* can backtrack */
+ while(--q > dotdot && *q != '/')
+ ;
+ } else if(!rooted) { /* /.. is / but ./../ is .. */
+ if(q != name)
+ *q++ = '/';
+ *q++ = '.';
+ *q++ = '.';
+ dotdot = q;
+ }
+ if(q == name)
+ erasedprefix = 1; /* erased entire path via dotdot */
+ } else { /* real path element */
+ if(q != name+rooted)
+ *q++ = '/';
+ while((*q = *p) != '/' && *q != 0)
+ p++, q++;
+ }
+ }
+ if(q == name) /* empty string is really ``.'' */
+ *q++ = '.';
+ *q = '\0';
+ if(erasedprefix && name[0] == '#'){
+ /* this was not a #x device path originally - make it not one now */
+ memmove(name+2, name, strlen(name)+1);
+ name[0] = '.';
+ name[1] = '/';
+ }
+ return name;
+}
--- /dev/null
+++ b/lib9/convD2M.c
@@ -1,0 +1,94 @@
+#include "lib9.h"
+#include "fcall.h"
+
+uint
+sizeD2M(Dir *d)
+{
+ char *sv[4];
+ int i, ns;
+
+ sv[0] = d->name;
+ sv[1] = d->uid;
+ sv[2] = d->gid;
+ sv[3] = d->muid;
+
+ ns = 0;
+ for(i = 0; i < 4; i++)
+ if(sv[i])
+ ns += strlen(sv[i]);
+
+ return STATFIXLEN + ns;
+}
+
+uint
+convD2M(Dir *d, uchar *buf, uint nbuf)
+{
+ uchar *p, *ebuf;
+ char *sv[4];
+ int i, ns, nsv[4], ss;
+
+ if(nbuf < BIT16SZ)
+ return 0;
+
+ p = buf;
+ ebuf = buf + nbuf;
+
+ sv[0] = d->name;
+ sv[1] = d->uid;
+ sv[2] = d->gid;
+ sv[3] = d->muid;
+
+ ns = 0;
+ for(i = 0; i < 4; i++){
+ if(sv[i])
+ nsv[i] = strlen(sv[i]);
+ else
+ nsv[i] = 0;
+ ns += nsv[i];
+ }
+
+ ss = STATFIXLEN + ns;
+
+ /* set size befor erroring, so user can know how much is needed */
+ /* note that length excludes count field itself */
+ PBIT16(p, ss-BIT16SZ);
+ p += BIT16SZ;
+
+ if(ss > nbuf)
+ return BIT16SZ;
+
+ PBIT16(p, d->type);
+ p += BIT16SZ;
+ PBIT32(p, d->dev);
+ p += BIT32SZ;
+ PBIT8(p, d->qid.type);
+ p += BIT8SZ;
+ PBIT32(p, d->qid.vers);
+ p += BIT32SZ;
+ PBIT64(p, d->qid.path);
+ p += BIT64SZ;
+ PBIT32(p, d->mode);
+ p += BIT32SZ;
+ PBIT32(p, d->atime);
+ p += BIT32SZ;
+ PBIT32(p, d->mtime);
+ p += BIT32SZ;
+ PBIT64(p, d->length);
+ p += BIT64SZ;
+
+ for(i = 0; i < 4; i++){
+ ns = nsv[i];
+ if(p + ns + BIT16SZ > ebuf)
+ return 0;
+ PBIT16(p, ns);
+ p += BIT16SZ;
+ if(ns)
+ memmove(p, sv[i], ns);
+ p += ns;
+ }
+
+ if(ss != p - buf)
+ return 0;
+
+ return p - buf;
+}
--- /dev/null
+++ b/lib9/convM2D.c
@@ -1,0 +1,93 @@
+#include "lib9.h"
+#include "fcall.h"
+
+int
+statcheck(uchar *buf, uint nbuf)
+{
+ uchar *ebuf;
+ int i;
+
+ ebuf = buf + nbuf;
+
+ if(nbuf < STATFIXLEN || nbuf != BIT16SZ + GBIT16(buf))
+ return -1;
+
+ buf += STATFIXLEN - 4 * BIT16SZ;
+
+ for(i = 0; i < 4; i++){
+ if(buf + BIT16SZ > ebuf)
+ return -1;
+ buf += BIT16SZ + GBIT16(buf);
+ }
+
+ if(buf != ebuf)
+ return -1;
+
+ return 0;
+}
+
+static char nullstring[] = "";
+
+uint
+convM2D(uchar *buf, uint nbuf, Dir *d, char *strs)
+{
+ uchar *p, *ebuf;
+ char *sv[4];
+ int i, ns;
+
+ if(nbuf < STATFIXLEN)
+ return 0;
+
+ p = buf;
+ ebuf = buf + nbuf;
+
+ p += BIT16SZ; /* ignore size */
+ d->type = GBIT16(p);
+ p += BIT16SZ;
+ d->dev = GBIT32(p);
+ p += BIT32SZ;
+ d->qid.type = GBIT8(p);
+ p += BIT8SZ;
+ d->qid.vers = GBIT32(p);
+ p += BIT32SZ;
+ d->qid.path = GBIT64(p);
+ p += BIT64SZ;
+ d->mode = GBIT32(p);
+ p += BIT32SZ;
+ d->atime = GBIT32(p);
+ p += BIT32SZ;
+ d->mtime = GBIT32(p);
+ p += BIT32SZ;
+ d->length = GBIT64(p);
+ p += BIT64SZ;
+
+ for(i = 0; i < 4; i++){
+ if(p + BIT16SZ > ebuf)
+ return 0;
+ ns = GBIT16(p);
+ p += BIT16SZ;
+ if(p + ns > ebuf)
+ return 0;
+ if(strs){
+ sv[i] = strs;
+ memmove(strs, p, ns);
+ strs += ns;
+ *strs++ = '\0';
+ }
+ p += ns;
+ }
+
+ if(strs){
+ d->name = sv[0];
+ d->uid = sv[1];
+ d->gid = sv[2];
+ d->muid = sv[3];
+ }else{
+ d->name = nullstring;
+ d->uid = nullstring;
+ d->gid = nullstring;
+ d->muid = nullstring;
+ }
+
+ return p - buf;
+}
--- /dev/null
+++ b/lib9/convM2S.c
@@ -1,0 +1,314 @@
+#include "lib9.h"
+#include "fcall.h"
+
+static
+uchar*
+gstring(uchar *p, uchar *ep, char **s)
+{
+ uint n;
+
+ if(p+BIT16SZ > ep)
+ return nil;
+ n = GBIT16(p);
+ p += BIT16SZ - 1;
+ if(p+n+1 > ep)
+ return nil;
+ /* move it down, on top of count, to make room for '\0' */
+ memmove(p, p + 1, n);
+ p[n] = '\0';
+ *s = (char*)p;
+ p += n+1;
+ return p;
+}
+
+static
+uchar*
+gqid(uchar *p, uchar *ep, Qid *q)
+{
+ if(p+QIDSZ > ep)
+ return nil;
+ q->type = GBIT8(p);
+ p += BIT8SZ;
+ q->vers = GBIT32(p);
+ p += BIT32SZ;
+ q->path = GBIT64(p);
+ p += BIT64SZ;
+ return p;
+}
+
+/*
+ * no syntactic checks.
+ * three causes for error:
+ * 1. message size field is incorrect
+ * 2. input buffer too short for its own data (counts too long, etc.)
+ * 3. too many names or qids
+ * gqid() and gstring() return nil if they would reach beyond buffer.
+ * main switch statement checks range and also can fall through
+ * to test at end of routine.
+ */
+uint
+convM2S(uchar *ap, uint nap, Fcall *f)
+{
+ uchar *p, *ep;
+ uint i, size;
+
+ p = ap;
+ ep = p + nap;
+
+ if(p+BIT32SZ+BIT8SZ+BIT16SZ > ep)
+ return 0;
+ size = GBIT32(p);
+ p += BIT32SZ;
+
+ if(size < BIT32SZ+BIT8SZ+BIT16SZ)
+ return 0;
+
+ f->type = GBIT8(p);
+ p += BIT8SZ;
+ f->tag = GBIT16(p);
+ p += BIT16SZ;
+
+ switch(f->type)
+ {
+ default:
+ return 0;
+
+ case Tversion:
+ if(p+BIT32SZ > ep)
+ return 0;
+ f->msize = GBIT32(p);
+ p += BIT32SZ;
+ p = gstring(p, ep, &f->version);
+ break;
+
+ case Tflush:
+ if(p+BIT16SZ > ep)
+ return 0;
+ f->oldtag = GBIT16(p);
+ p += BIT16SZ;
+ break;
+
+ case Tauth:
+ if(p+BIT32SZ > ep)
+ return 0;
+ f->afid = GBIT32(p);
+ p += BIT32SZ;
+ p = gstring(p, ep, &f->uname);
+ if(p == nil)
+ break;
+ p = gstring(p, ep, &f->aname);
+ if(p == nil)
+ break;
+ break;
+
+ case Tattach:
+ if(p+BIT32SZ > ep)
+ return 0;
+ f->fid = GBIT32(p);
+ p += BIT32SZ;
+ if(p+BIT32SZ > ep)
+ return 0;
+ f->afid = GBIT32(p);
+ p += BIT32SZ;
+ p = gstring(p, ep, &f->uname);
+ if(p == nil)
+ break;
+ p = gstring(p, ep, &f->aname);
+ if(p == nil)
+ break;
+ break;
+
+ case Twalk:
+ if(p+BIT32SZ+BIT32SZ+BIT16SZ > ep)
+ return 0;
+ f->fid = GBIT32(p);
+ p += BIT32SZ;
+ f->newfid = GBIT32(p);
+ p += BIT32SZ;
+ f->nwname = GBIT16(p);
+ p += BIT16SZ;
+ if(f->nwname > MAXWELEM)
+ return 0;
+ for(i=0; i<f->nwname; i++){
+ p = gstring(p, ep, &f->wname[i]);
+ if(p == nil)
+ break;
+ }
+ break;
+
+ case Topen:
+ if(p+BIT32SZ+BIT8SZ > ep)
+ return 0;
+ f->fid = GBIT32(p);
+ p += BIT32SZ;
+ f->mode = GBIT8(p);
+ p += BIT8SZ;
+ break;
+
+ case Tcreate:
+ if(p+BIT32SZ > ep)
+ return 0;
+ f->fid = GBIT32(p);
+ p += BIT32SZ;
+ p = gstring(p, ep, &f->name);
+ if(p == nil)
+ break;
+ if(p+BIT32SZ+BIT8SZ > ep)
+ return 0;
+ f->perm = GBIT32(p);
+ p += BIT32SZ;
+ f->mode = GBIT8(p);
+ p += BIT8SZ;
+ break;
+
+ case Tread:
+ if(p+BIT32SZ+BIT64SZ+BIT32SZ > ep)
+ return 0;
+ f->fid = GBIT32(p);
+ p += BIT32SZ;
+ f->offset = GBIT64(p);
+ p += BIT64SZ;
+ f->count = GBIT32(p);
+ p += BIT32SZ;
+ break;
+
+ case Twrite:
+ if(p+BIT32SZ+BIT64SZ+BIT32SZ > ep)
+ return 0;
+ f->fid = GBIT32(p);
+ p += BIT32SZ;
+ f->offset = GBIT64(p);
+ p += BIT64SZ;
+ f->count = GBIT32(p);
+ p += BIT32SZ;
+ if(p+f->count > ep)
+ return 0;
+ f->data = (char*)p;
+ p += f->count;
+ break;
+
+ case Tclunk:
+ case Tremove:
+ if(p+BIT32SZ > ep)
+ return 0;
+ f->fid = GBIT32(p);
+ p += BIT32SZ;
+ break;
+
+ case Tstat:
+ if(p+BIT32SZ > ep)
+ return 0;
+ f->fid = GBIT32(p);
+ p += BIT32SZ;
+ break;
+
+ case Twstat:
+ if(p+BIT32SZ+BIT16SZ > ep)
+ return 0;
+ f->fid = GBIT32(p);
+ p += BIT32SZ;
+ f->nstat = GBIT16(p);
+ p += BIT16SZ;
+ if(p+f->nstat > ep)
+ return 0;
+ f->stat = p;
+ p += f->nstat;
+ break;
+
+/*
+ */
+ case Rversion:
+ if(p+BIT32SZ > ep)
+ return 0;
+ f->msize = GBIT32(p);
+ p += BIT32SZ;
+ p = gstring(p, ep, &f->version);
+ break;
+
+ case Rerror:
+ p = gstring(p, ep, &f->ename);
+ break;
+
+ case Rflush:
+ break;
+
+ case Rauth:
+ p = gqid(p, ep, &f->aqid);
+ if(p == nil)
+ break;
+ break;
+
+ case Rattach:
+ p = gqid(p, ep, &f->qid);
+ if(p == nil)
+ break;
+ break;
+
+ case Rwalk:
+ if(p+BIT16SZ > ep)
+ return 0;
+ f->nwqid = GBIT16(p);
+ p += BIT16SZ;
+ if(f->nwqid > MAXWELEM)
+ return 0;
+ for(i=0; i<f->nwqid; i++){
+ p = gqid(p, ep, &f->wqid[i]);
+ if(p == nil)
+ break;
+ }
+ break;
+
+ case Ropen:
+ case Rcreate:
+ p = gqid(p, ep, &f->qid);
+ if(p == nil)
+ break;
+ if(p+BIT32SZ > ep)
+ return 0;
+ f->iounit = GBIT32(p);
+ p += BIT32SZ;
+ break;
+
+ case Rread:
+ if(p+BIT32SZ > ep)
+ return 0;
+ f->count = GBIT32(p);
+ p += BIT32SZ;
+ if(p+f->count > ep)
+ return 0;
+ f->data = (char*)p;
+ p += f->count;
+ break;
+
+ case Rwrite:
+ if(p+BIT32SZ > ep)
+ return 0;
+ f->count = GBIT32(p);
+ p += BIT32SZ;
+ break;
+
+ case Rclunk:
+ case Rremove:
+ break;
+
+ case Rstat:
+ if(p+BIT16SZ > ep)
+ return 0;
+ f->nstat = GBIT16(p);
+ p += BIT16SZ;
+ if(p+f->nstat > ep)
+ return 0;
+ f->stat = p;
+ p += f->nstat;
+ break;
+
+ case Rwstat:
+ break;
+ }
+
+ if(p==nil || p>ep)
+ return 0;
+ if(ap+size == p)
+ return size;
+ return 0;
+}
--- /dev/null
+++ b/lib9/convS2M.c
@@ -1,0 +1,385 @@
+#include "lib9.h"
+#include "fcall.h"
+
+static
+uchar*
+pstring(uchar *p, char *s)
+{
+ uint n;
+
+ if(s == nil){
+ PBIT16(p, 0);
+ p += BIT16SZ;
+ return p;
+ }
+
+ n = strlen(s);
+ PBIT16(p, n);
+ p += BIT16SZ;
+ memmove(p, s, n);
+ p += n;
+ return p;
+}
+
+static
+uchar*
+pqid(uchar *p, Qid *q)
+{
+ PBIT8(p, q->type);
+ p += BIT8SZ;
+ PBIT32(p, q->vers);
+ p += BIT32SZ;
+ PBIT64(p, q->path);
+ p += BIT64SZ;
+ return p;
+}
+
+static
+uint
+stringsz(char *s)
+{
+ if(s == nil)
+ return BIT16SZ;
+
+ return BIT16SZ+strlen(s);
+}
+
+uint
+sizeS2M(Fcall *f)
+{
+ uint n;
+ int i;
+
+ n = 0;
+ n += BIT32SZ; /* size */
+ n += BIT8SZ; /* type */
+ n += BIT16SZ; /* tag */
+
+ switch(f->type)
+ {
+ default:
+ return 0;
+
+ case Tversion:
+ n += BIT32SZ;
+ n += stringsz(f->version);
+ break;
+
+ case Tflush:
+ n += BIT16SZ;
+ break;
+
+ case Tauth:
+ n += BIT32SZ;
+ n += stringsz(f->uname);
+ n += stringsz(f->aname);
+ break;
+
+ case Tattach:
+ n += BIT32SZ;
+ n += BIT32SZ;
+ n += stringsz(f->uname);
+ n += stringsz(f->aname);
+ break;
+
+ case Twalk:
+ n += BIT32SZ;
+ n += BIT32SZ;
+ n += BIT16SZ;
+ for(i=0; i<f->nwname; i++)
+ n += stringsz(f->wname[i]);
+ break;
+
+ case Topen:
+ n += BIT32SZ;
+ n += BIT8SZ;
+ break;
+
+ case Tcreate:
+ n += BIT32SZ;
+ n += stringsz(f->name);
+ n += BIT32SZ;
+ n += BIT8SZ;
+ break;
+
+ case Tread:
+ n += BIT32SZ;
+ n += BIT64SZ;
+ n += BIT32SZ;
+ break;
+
+ case Twrite:
+ n += BIT32SZ;
+ n += BIT64SZ;
+ n += BIT32SZ;
+ n += f->count;
+ break;
+
+ case Tclunk:
+ case Tremove:
+ n += BIT32SZ;
+ break;
+
+ case Tstat:
+ n += BIT32SZ;
+ break;
+
+ case Twstat:
+ n += BIT32SZ;
+ n += BIT16SZ;
+ n += f->nstat;
+ break;
+/*
+ */
+
+ case Rversion:
+ n += BIT32SZ;
+ n += stringsz(f->version);
+ break;
+
+ case Rerror:
+ n += stringsz(f->ename);
+ break;
+
+ case Rflush:
+ break;
+
+ case Rauth:
+ n += QIDSZ;
+ break;
+
+ case Rattach:
+ n += QIDSZ;
+ break;
+
+ case Rwalk:
+ n += BIT16SZ;
+ n += f->nwqid*QIDSZ;
+ break;
+
+ case Ropen:
+ case Rcreate:
+ n += QIDSZ;
+ n += BIT32SZ;
+ break;
+
+ case Rread:
+ n += BIT32SZ;
+ n += f->count;
+ break;
+
+ case Rwrite:
+ n += BIT32SZ;
+ break;
+
+ case Rclunk:
+ break;
+
+ case Rremove:
+ break;
+
+ case Rstat:
+ n += BIT16SZ;
+ n += f->nstat;
+ break;
+
+ case Rwstat:
+ break;
+ }
+ return n;
+}
+
+uint
+convS2M(Fcall *f, uchar *ap, uint nap)
+{
+ uchar *p;
+ uint i, size;
+
+ size = sizeS2M(f);
+ if(size == 0)
+ return 0;
+ if(size > nap)
+ return 0;
+
+ p = (uchar*)ap;
+
+ PBIT32(p, size);
+ p += BIT32SZ;
+ PBIT8(p, f->type);
+ p += BIT8SZ;
+ PBIT16(p, f->tag);
+ p += BIT16SZ;
+
+ switch(f->type)
+ {
+ default:
+ return 0;
+
+ case Tversion:
+ PBIT32(p, f->msize);
+ p += BIT32SZ;
+ p = pstring(p, f->version);
+ break;
+
+ case Tflush:
+ PBIT16(p, f->oldtag);
+ p += BIT16SZ;
+ break;
+
+ case Tauth:
+ PBIT32(p, f->afid);
+ p += BIT32SZ;
+ p = pstring(p, f->uname);
+ p = pstring(p, f->aname);
+ break;
+
+ case Tattach:
+ PBIT32(p, f->fid);
+ p += BIT32SZ;
+ PBIT32(p, f->afid);
+ p += BIT32SZ;
+ p = pstring(p, f->uname);
+ p = pstring(p, f->aname);
+ break;
+
+ case Twalk:
+ PBIT32(p, f->fid);
+ p += BIT32SZ;
+ PBIT32(p, f->newfid);
+ p += BIT32SZ;
+ PBIT16(p, f->nwname);
+ p += BIT16SZ;
+ if(f->nwname > MAXWELEM)
+ return 0;
+ for(i=0; i<f->nwname; i++)
+ p = pstring(p, f->wname[i]);
+ break;
+
+ case Topen:
+ PBIT32(p, f->fid);
+ p += BIT32SZ;
+ PBIT8(p, f->mode);
+ p += BIT8SZ;
+ break;
+
+ case Tcreate:
+ PBIT32(p, f->fid);
+ p += BIT32SZ;
+ p = pstring(p, f->name);
+ PBIT32(p, f->perm);
+ p += BIT32SZ;
+ PBIT8(p, f->mode);
+ p += BIT8SZ;
+ break;
+
+ case Tread:
+ PBIT32(p, f->fid);
+ p += BIT32SZ;
+ PBIT64(p, f->offset);
+ p += BIT64SZ;
+ PBIT32(p, f->count);
+ p += BIT32SZ;
+ break;
+
+ case Twrite:
+ PBIT32(p, f->fid);
+ p += BIT32SZ;
+ PBIT64(p, f->offset);
+ p += BIT64SZ;
+ PBIT32(p, f->count);
+ p += BIT32SZ;
+ memmove(p, f->data, f->count);
+ p += f->count;
+ break;
+
+ case Tclunk:
+ case Tremove:
+ PBIT32(p, f->fid);
+ p += BIT32SZ;
+ break;
+
+ case Tstat:
+ PBIT32(p, f->fid);
+ p += BIT32SZ;
+ break;
+
+ case Twstat:
+ PBIT32(p, f->fid);
+ p += BIT32SZ;
+ PBIT16(p, f->nstat);
+ p += BIT16SZ;
+ memmove(p, f->stat, f->nstat);
+ p += f->nstat;
+ break;
+/*
+ */
+
+ case Rversion:
+ PBIT32(p, f->msize);
+ p += BIT32SZ;
+ p = pstring(p, f->version);
+ break;
+
+ case Rerror:
+ p = pstring(p, f->ename);
+ break;
+
+ case Rflush:
+ break;
+
+ case Rauth:
+ p = pqid(p, &f->aqid);
+ break;
+
+ case Rattach:
+ p = pqid(p, &f->qid);
+ break;
+
+ case Rwalk:
+ PBIT16(p, f->nwqid);
+ p += BIT16SZ;
+ if(f->nwqid > MAXWELEM)
+ return 0;
+ for(i=0; i<f->nwqid; i++)
+ p = pqid(p, &f->wqid[i]);
+ break;
+
+ case Ropen:
+ case Rcreate:
+ p = pqid(p, &f->qid);
+ PBIT32(p, f->iounit);
+ p += BIT32SZ;
+ break;
+
+ case Rread:
+ PBIT32(p, f->count);
+ p += BIT32SZ;
+ memmove(p, f->data, f->count);
+ p += f->count;
+ break;
+
+ case Rwrite:
+ PBIT32(p, f->count);
+ p += BIT32SZ;
+ break;
+
+ case Rclunk:
+ break;
+
+ case Rremove:
+ break;
+
+ case Rstat:
+ PBIT16(p, f->nstat);
+ p += BIT16SZ;
+ memmove(p, f->stat, f->nstat);
+ p += f->nstat;
+ break;
+
+ case Rwstat:
+ break;
+ }
+ if(size != p-ap)
+ return 0;
+ return size;
+}
--- /dev/null
+++ b/lib9/create.c
@@ -1,0 +1,32 @@
+#include "lib9.h"
+#include <sys/types.h>
+#include <fcntl.h>
+
+int
+create(char *f, int mode, int perm)
+{
+ int m;
+
+ m = 0;
+ switch(mode & 3){
+ case OREAD:
+ case OEXEC:
+ m = O_RDONLY;
+ break;
+ case OWRITE:
+ m = O_WRONLY;
+ break;
+ case ORDWR:
+ m = O_RDWR;
+ break;
+ }
+ m |= O_CREAT|O_TRUNC;
+
+ if(perm & DMDIR){
+ if(mkdir(f, perm&0777) < 0)
+ return -1;
+ perm &= ~DMDIR;
+ m &= 3;
+ }
+ return open(f, m, perm);
+}
--- /dev/null
+++ b/lib9/dirstat-Nt.c
@@ -1,0 +1,64 @@
+#include "lib9.h"
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#define ISTYPE(s, t) (((s)->st_mode&S_IFMT) == t)
+
+static char nullstring[] = "";
+static char Enovmem[] = "out of memory";
+
+static Dir*
+statconv(struct stat *s, char *name)
+{
+ Dir *dir;
+
+#ifdef NO
+ extern char* GetNameFromID(int);
+
+ uid = GetNameFromID(s->st_uid), NAMELEN);
+ gid = GetNameFromID(s->st_gid), NAMELEN);
+#endif
+ dir = malloc(sizeof(Dir));
+ if(dir == nil){
+ werrstr(Enovmem);
+ return nil;
+ }
+ dir->name = name;
+ dir->uid = dir->gid = dir->muid = nullstring;
+ dir->qid.type = ISTYPE(s, _S_IFDIR)? QTDIR: QTFILE;
+ dir->qid.path = s->st_ino;
+ dir->qid.vers = s->st_mtime;
+ dir->mode = (dir->qid.type<<24)|(s->st_mode&0777);
+ dir->atime = s->st_atime;
+ dir->mtime = s->st_mtime;
+ dir->length = s->st_size;
+ dir->dev = s->st_dev;
+ dir->type = ISTYPE(s, _S_IFIFO)? '|': 'M';
+ return dir;
+}
+
+Dir*
+dirfstat(int fd)
+{
+ struct stat sbuf;
+
+ if(fstat(fd, &sbuf) < 0)
+ return nil;
+ return statconv(&sbuf, nullstring);
+}
+
+Dir*
+dirstat(char *f)
+{
+ struct stat sbuf;
+ char *p;
+
+ if(stat(f, &sbuf) < 0)
+ return nil;
+ p = strrchr(f, '/');
+ if(p)
+ p++;
+ else
+ p = nullstring;
+ return statconv(&sbuf, p);
+}
--- /dev/null
+++ b/lib9/dirstat-posix.c
@@ -1,0 +1,79 @@
+#include "lib9.h"
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <pwd.h>
+#include <grp.h>
+
+static char nullstring[] = "";
+static char Enovmem[] = "out of memory";
+
+static Dir*
+statconv(struct stat *s, char *name)
+{
+ struct passwd *p;
+ struct group *g;
+ Dir *dir;
+ int str;
+ char *n;
+
+ str = 0;
+ p = getpwuid(s->st_uid);
+ if(p)
+ str += strlen(p->pw_name)+1;
+ g = getgrgid(s->st_gid);
+ if(g)
+ str += strlen(g->gr_name)+1;
+ dir = malloc(sizeof(Dir)+str);
+ if(dir == nil){
+ werrstr(Enovmem);
+ return nil;
+ }
+ n = (char*)dir+sizeof(Dir);
+ dir->name = name;
+ dir->uid = dir->gid = dir->muid = nullstring;
+ if(p){
+ dir->uid = n;
+ strcpy(n, p->pw_name);
+ n += strlen(p->pw_name)+1;
+ }
+ if(g){
+ dir->gid = n;
+ strcpy(n, g->gr_name);
+ }
+ dir->qid.type = S_ISDIR(s->st_mode)? QTDIR: QTFILE;
+ dir->qid.path = s->st_ino;
+ dir->qid.vers = s->st_mtime;
+ dir->mode = (dir->qid.type<<24)|(s->st_mode&0777);
+ dir->atime = s->st_atime;
+ dir->mtime = s->st_mtime;
+ dir->length = s->st_size;
+ dir->dev = s->st_dev;
+ dir->type = S_ISFIFO(s->st_mode)? '|': 'M';
+ return dir;
+}
+
+Dir*
+dirfstat(int fd)
+{
+ struct stat sbuf;
+
+ if(fstat(fd, &sbuf) < 0)
+ return nil;
+ return statconv(&sbuf, nullstring);
+}
+
+Dir*
+dirstat(char *f)
+{
+ struct stat sbuf;
+ char *p;
+
+ if(stat(f, &sbuf) < 0)
+ return nil;
+ p = strrchr(f, '/');
+ if(p)
+ p++;
+ else
+ p = nullstring;
+ return statconv(&sbuf, p);
+}
--- /dev/null
+++ b/lib9/dirwstat.c
@@ -1,0 +1,15 @@
+#include "lib9.h"
+#include <sys/types.h>
+#include <sys/stat.h>
+
+int
+dirfwstat(int fd, Dir *d)
+{
+ return -1;
+}
+
+int
+dirwstat(char *name, Dir *d)
+{
+ return -1;
+}
--- /dev/null
+++ b/lib9/dofmt.c
@@ -1,0 +1,531 @@
+/*
+ * 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 "lib9.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 = f->to;
+ rs = 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 = f->to;
+ s = 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 = _fmtflush(f, t, n);
+ if(t != nil)
+ s = 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 = _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 = f->to;
+ s = 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 = f->to;
+ s = 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, void *vm, int n, int sz)
+{
+ Rune *rt, *rs, r;
+ char *t, *s, *m, *me;
+ ulong fl;
+ int nc, w;
+
+ m = 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 = f->to;
+ rs = f->stop;
+ for(nc = n; nc > 0; nc--){
+ r = *(uchar*)m;
+ if(r < Runeself)
+ m++;
+ else if((me - m) >= UTFmax || fullrune(m, me-m))
+ m += chartorune(&r, m);
+ else
+ break;
+ FMTRCHAR(f, rt, rs, r);
+ }
+ f->nfmt += rt - (Rune *)f->to;
+ f->to = rt;
+ if(m < me)
+ return -1;
+ if(fl & FmtLeft && _rfmtpad(f, w - n) < 0)
+ return -1;
+ }else{
+ if(!(fl & FmtLeft) && _fmtpad(f, w - n) < 0)
+ return -1;
+ t = f->to;
+ s = 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, void *vm, int n)
+{
+ Rune r, *m, *me, *rt, *rs;
+ char *t, *s;
+ ulong fl;
+ int w;
+
+ m = 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 = f->to;
+ rs = 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 = f->to;
+ s = 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, x, 1, 1);
+}
+
+/* fmt out one rune */
+int
+_runefmt(Fmt *f)
+{
+ Rune x[1];
+
+ x[0] = va_arg(f->args, int);
+ return _fmtrcpy(f, x, 1);
+}
+
+/* public helper routine: fmt out a null terminated string already in hand */
+int
+fmtstrcpy(Fmt *f, char *s)
+{
+ int p, i;
+ if(!s)
+ return _fmtcpy(f, "<nil>", 5, 5);
+ /* if precision is specified, make sure we don't wander off the end */
+ if(f->flags & FmtPrec){
+ p = f->prec;
+ for(i = 0; i < p; i++)
+ if(s[i] == 0)
+ break;
+ return _fmtcpy(f, s, utfnlen(s, i), i); /* BUG?: won't print a partial rune at end */
+ }
+
+ return _fmtcpy(f, s, utflen(s), strlen(s));
+}
+
+/* fmt out a null terminated utf string */
+int
+_strfmt(Fmt *f)
+{
+ char *s;
+
+ s = va_arg(f->args, char *);
+ return fmtstrcpy(f, s);
+}
+
+/* public helper routine: fmt out a null terminated rune string already in hand */
+int
+fmtrunestrcpy(Fmt *f, Rune *s)
+{
+ Rune *e;
+ int n, p;
+
+ if(!s)
+ return _fmtcpy(f, "<nil>", 5, 5);
+ /* if precision is specified, make sure we don't wander off the end */
+ if(f->flags & FmtPrec){
+ p = f->prec;
+ for(n = 0; n < p; n++)
+ if(s[n] == 0)
+ break;
+ }else{
+ for(e = s; *e; e++)
+ ;
+ n = e - s;
+ }
+ return _fmtrcpy(f, s, n);
+}
+
+/* fmt out a null terminated rune string */
+int
+_runesfmt(Fmt *f)
+{
+ Rune *s;
+
+ s = va_arg(f->args, Rune *);
+ return fmtrunestrcpy(f, s);
+}
+
+/* fmt a % */
+int
+_percentfmt(Fmt *f)
+{
+ Rune x[1];
+
+ x[0] = f->r;
+ f->prec = 1;
+ return _fmtrcpy(f, 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':
+ 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)){
+ 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':
+ 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, x, 3, 3);
+ return 0;
+}
--- /dev/null
+++ b/lib9/dorfmt.c
@@ -1,0 +1,58 @@
+/*
+ * 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 "lib9.h"
+#include "fmtdef.h"
+
+/* format the output into f->to and return the number of characters fmted */
+
+int
+dorfmt(Fmt *f, Rune *fmt)
+{
+ Rune *rt, *rs;
+ int r;
+ char *t, *s;
+ int nfmt;
+
+ nfmt = f->nfmt;
+ for(;;){
+ if(f->runes){
+ rt = f->to;
+ rs = f->stop;
+ while((r = *fmt++) && r != '%'){
+ FMTRCHAR(f, rt, rs, r);
+ }
+ f->nfmt += rt - (Rune *)f->to;
+ f->to = rt;
+ if(!r)
+ return f->nfmt - nfmt;
+ f->stop = rs;
+ }else{
+ t = f->to;
+ s = f->stop;
+ while((r = *fmt++) && r != '%'){
+ FMTRUNE(f, t, f->stop, r);
+ }
+ f->nfmt += t - (char *)f->to;
+ f->to = t;
+ if(!r)
+ return f->nfmt - nfmt;
+ f->stop = s;
+ }
+
+ fmt = _fmtdispatch(f, fmt, 1);
+ if(fmt == nil)
+ return -1;
+ }
+ return 0; /* not reached */
+}
--- /dev/null
+++ b/lib9/errfmt.c
@@ -1,0 +1,24 @@
+/*
+ * 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 "lib9.h"
+#include "fmtdef.h"
+
+int
+errfmt(Fmt *f)
+{
+ char buf[ERRMAX];
+
+ rerrstr(buf, sizeof buf);
+ return _fmtcpy(f, buf, utflen(buf), strlen(buf));
+}
--- /dev/null
+++ b/lib9/errstr-Nt.c
@@ -1,0 +1,65 @@
+#include "lib9.h"
+#include <Windows.h>
+
+static char errstring[ERRMAX];
+
+enum
+{
+ Magic = 0xffffff
+};
+
+static void
+winerror(int e, char *buf, uint nerr)
+{
+ int r;
+ char buf2[ERRMAX], *p, *q;
+
+ r = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
+ 0, e, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
+ buf2, sizeof(buf2), 0);
+
+ if(r == 0)
+ snprint(buf2, ERRMAX, "windows error %d", e);
+
+ q = buf2;
+ for(p = buf2; *p; p++) {
+ if(*p == '\r')
+ continue;
+ if(*p == '\n')
+ *q++ = ' ';
+ else
+ *q++ = *p;
+ }
+ *q = '\0';
+ utfecpy(buf, buf+nerr, buf2);
+}
+
+void
+werrstr(char *fmt, ...)
+{
+ va_list arg;
+
+ va_start(arg, fmt);
+ vseprint(errstring, errstring+sizeof(errstring), fmt, arg);
+ va_end(arg);
+ SetLastError(Magic);
+}
+
+int
+errstr(char *buf, uint nerr)
+{
+ DWORD le;
+
+ le = GetLastError();
+ if(le == Magic)
+ utfecpy(buf, buf+nerr, errstring);
+ else
+ winerror(le, buf, nerr);
+ return 1;
+}
+
+void
+oserrstr(char *buf, uint nerr)
+{
+ winerror(GetLastError(), buf, nerr);
+}
--- /dev/null
+++ b/lib9/errstr-Plan9.c
@@ -1,0 +1,8 @@
+#include "lib9.h"
+
+void
+oserrstr(char *buf, uint nerr)
+{
+ *buf = 0;
+ errstr(buf, nerr);
+}
--- /dev/null
+++ b/lib9/errstr-posix.c
@@ -1,0 +1,43 @@
+#include "lib9.h"
+
+#include <errno.h>
+
+static char errstring[ERRMAX];
+
+enum
+{
+ Magic = 0xffffff
+};
+
+void
+werrstr(char *fmt, ...)
+{
+ va_list arg;
+
+ va_start(arg, fmt);
+ vseprint(errstring, errstring+sizeof(errstring), fmt, arg);
+ va_end(arg);
+ errno = Magic;
+}
+
+void
+oserrstr(char *buf, uint nerr)
+{
+ char *s;
+
+ if(errno != EINTR)
+ s = strerror(errno);
+ else
+ s = "interrupted";
+ utfecpy(buf, buf+nerr, s);
+}
+
+int
+errstr(char *buf, uint nerr)
+{
+ if(errno == Magic)
+ utfecpy(buf, buf+nerr, errstring);
+ else
+ oserrstr(buf, nerr);
+ return 1;
+}
--- /dev/null
+++ b/lib9/exits.c
@@ -1,0 +1,17 @@
+#include "lib9.h"
+
+void
+exits(char *s)
+{
+ if(s == 0 || *s == 0)
+ exit(0);
+ exit(1);
+}
+
+void
+_exits(char *s)
+{
+ if(s == 0 || *s == 0)
+ _exit(0);
+ _exit(1);
+}
--- /dev/null
+++ b/lib9/fcallfmt.c
@@ -1,0 +1,246 @@
+/*
+ * 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 <lib9.h>
+#include "fcall.h"
+
+static uint dumpsome(char*, char*, char*, long);
+static void fdirconv(char*, char*, Dir*);
+static char *qidtype(char*, uchar);
+
+#define QIDFMT "(%.16llux %lud %s)"
+
+int
+fcallfmt(Fmt *fmt)
+{
+ Fcall *f;
+ int fid, type, tag, i;
+ char buf[512], tmp[200];
+ char *p, *e;
+ Dir *d;
+ Qid *q;
+
+ e = buf+sizeof(buf);
+ f = va_arg(fmt->args, Fcall*);
+ type = f->type;
+ fid = f->fid;
+ tag = f->tag;
+ switch(type){
+ case Tversion: /* 100 */
+ seprint(buf, e, "Tversion tag %ud msize %ud version '%s'", tag, f->msize, f->version);
+ break;
+ case Rversion:
+ seprint(buf, e, "Rversion tag %ud msize %ud version '%s'", tag, f->msize, f->version);
+ break;
+ case Tauth: /* 102 */
+ seprint(buf, e, "Tauth tag %ud afid %d uname %s aname %s", tag,
+ f->afid, f->uname, f->aname);
+ break;
+ case Rauth:
+ seprint(buf, e, "Rauth tag %ud qid " QIDFMT, tag,
+ f->aqid.path, f->aqid.vers, qidtype(tmp, f->aqid.type));
+ break;
+ case Tattach: /* 104 */
+ seprint(buf, e, "Tattach tag %ud fid %d afid %d uname %s aname %s", tag,
+ fid, f->afid, f->uname, f->aname);
+ break;
+ case Rattach:
+ seprint(buf, e, "Rattach tag %ud qid " QIDFMT, tag,
+ f->qid.path, f->qid.vers, qidtype(tmp, f->qid.type));
+ break;
+ case Rerror: /* 107; 106 (Terror) illegal */
+ seprint(buf, e, "Rerror tag %ud ename %s", tag, f->ename);
+ break;
+ case Tflush: /* 108 */
+ seprint(buf, e, "Tflush tag %ud oldtag %ud", tag, f->oldtag);
+ break;
+ case Rflush:
+ seprint(buf, e, "Rflush tag %ud", tag);
+ break;
+ case Twalk: /* 110 */
+ p = seprint(buf, e, "Twalk tag %ud fid %d newfid %d nwname %d ", tag, fid, f->newfid, f->nwname);
+ if(f->nwname <= MAXWELEM)
+ for(i=0; i<f->nwname; i++)
+ p = seprint(p, e, "%d:%s ", i, f->wname[i]);
+ break;
+ case Rwalk:
+ p = seprint(buf, e, "Rwalk tag %ud nwqid %ud ", tag, f->nwqid);
+ if(f->nwqid <= MAXWELEM)
+ for(i=0; i<f->nwqid; i++){
+ q = &f->wqid[i];
+ p = seprint(p, e, "%d:" QIDFMT " ", i,
+ q->path, q->vers, qidtype(tmp, q->type));
+ }
+ break;
+ case Topen: /* 112 */
+ seprint(buf, e, "Topen tag %ud fid %ud mode %d", tag, fid, f->mode);
+ break;
+ case Ropen:
+ seprint(buf, e, "Ropen tag %ud qid " QIDFMT " iounit %ud ", tag,
+ f->qid.path, f->qid.vers, qidtype(tmp, f->qid.type), f->iounit);
+ break;
+ case Tcreate: /* 114 */
+ seprint(buf, e, "Tcreate tag %ud fid %ud name %s perm %M mode %d", tag, fid, f->name, (ulong)f->perm, f->mode);
+ break;
+ case Rcreate:
+ seprint(buf, e, "Rcreate tag %ud qid " QIDFMT " iounit %ud ", tag,
+ f->qid.path, f->qid.vers, qidtype(tmp, f->qid.type), f->iounit);
+ break;
+ case Tread: /* 116 */
+ seprint(buf, e, "Tread tag %ud fid %d offset %lld count %ud",
+ tag, fid, f->offset, f->count);
+ break;
+ case Rread:
+ p = seprint(buf, e, "Rread tag %ud count %ud ", tag, f->count);
+ dumpsome(p, e, f->data, f->count);
+ break;
+ case Twrite: /* 118 */
+ p = seprint(buf, e, "Twrite tag %ud fid %d offset %lld count %ud ",
+ tag, fid, f->offset, f->count);
+ dumpsome(p, e, f->data, f->count);
+ break;
+ case Rwrite:
+ seprint(buf, e, "Rwrite tag %ud count %ud", tag, f->count);
+ break;
+ case Tclunk: /* 120 */
+ seprint(buf, e, "Tclunk tag %ud fid %ud", tag, fid);
+ break;
+ case Rclunk:
+ seprint(buf, e, "Rclunk tag %ud", tag);
+ break;
+ case Tremove: /* 122 */
+ seprint(buf, e, "Tremove tag %ud fid %ud", tag, fid);
+ break;
+ case Rremove:
+ seprint(buf, e, "Rremove tag %ud", tag);
+ break;
+ case Tstat: /* 124 */
+ seprint(buf, e, "Tstat tag %ud fid %ud", tag, fid);
+ break;
+ case Rstat:
+ p = seprint(buf, e, "Rstat tag %ud ", tag);
+ if(f->nstat > sizeof tmp)
+ seprint(p, e, " stat(%d bytes)", f->nstat);
+ else{
+ d = (Dir*)tmp;
+ convM2D(f->stat, f->nstat, d, (char*)(d+1));
+ seprint(p, e, " stat ");
+ fdirconv(p+6, e, d);
+ }
+ break;
+ case Twstat: /* 126 */
+ p = seprint(buf, e, "Twstat tag %ud fid %ud", tag, fid);
+ if(f->nstat > sizeof tmp)
+ seprint(p, e, " stat(%d bytes)", f->nstat);
+ else{
+ d = (Dir*)tmp;
+ convM2D(f->stat, f->nstat, d, (char*)(d+1));
+ seprint(p, e, " stat ");
+ fdirconv(p+6, e, d);
+ }
+ break;
+ case Rwstat:
+ seprint(buf, e, "Rwstat tag %ud", tag);
+ break;
+ default:
+ seprint(buf, e, "unknown type %d", type);
+ }
+ return fmtstrcpy(fmt, buf);
+}
+
+static char*
+qidtype(char *s, uchar t)
+{
+ char *p;
+
+ p = s;
+ if(t & QTDIR)
+ *p++ = 'd';
+ if(t & QTAPPEND)
+ *p++ = 'a';
+ if(t & QTEXCL)
+ *p++ = 'l';
+ if(t & QTAUTH)
+ *p++ = 'A';
+ *p = '\0';
+ return s;
+}
+
+int
+dirfmt(Fmt *fmt)
+{
+ char buf[160];
+
+ fdirconv(buf, buf+sizeof buf, va_arg(fmt->args, Dir*));
+ return fmtstrcpy(fmt, buf);
+}
+
+static void
+fdirconv(char *buf, char *e, Dir *d)
+{
+ char tmp[16];
+
+ seprint(buf, e, "'%s' '%s' '%s' '%s' "
+ "q " QIDFMT " m %#luo "
+ "at %ld mt %ld l %lld "
+ "t %d d %d",
+ d->name, d->uid, d->gid, d->muid,
+ d->qid.path, d->qid.vers, qidtype(tmp, d->qid.type), d->mode,
+ d->atime, d->mtime, d->length,
+ d->type, d->dev);
+}
+
+/*
+ * dump out count (or DUMPL, if count is bigger) bytes from
+ * buf to ans, as a string if they are all printable,
+ * else as a series of hex bytes
+ */
+#define DUMPL 64
+
+static uint
+dumpsome(char *ans, char *e, char *buf, long count)
+{
+ int i, printable;
+ char *p;
+
+ if(buf == nil){
+ seprint(ans, e, "<no data>");
+ return strlen(ans);
+ }
+ printable = 1;
+ if(count > DUMPL)
+ count = DUMPL;
+ for(i=0; i<count && printable; i++)
+ if((buf[i]<32 && buf[i] !='\n' && buf[i] !='\t') || (uchar)buf[i]>127)
+ printable = 0;
+ p = ans;
+ *p++ = '\'';
+ if(printable){
+ if(count > e-p-2)
+ count = e-p-2;
+ memmove(p, buf, count);
+ p += count;
+ }else{
+ if(2*count > e-p-2)
+ count = (e-p-2)/2;
+ for(i=0; i<count; i++){
+ if(i>0 && i%4==0)
+ *p++ = ' ';
+ sprint(p, "%2.2ux", buf[i]);
+ p += 2;
+ }
+ }
+ *p++ = '\'';
+ *p = 0;
+ return p - ans;
+}
--- /dev/null
+++ b/lib9/fltfmt.c
@@ -1,0 +1,324 @@
+/*
+ * 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 "lib9.h"
+#include <ctype.h>
+#include "fmtdef.h"
+
+enum
+{
+ FDIGIT = 30,
+ FDEFLT = 6,
+ NSIGNIF = 17,
+};
+
+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;
+}
+
+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);
+}
--- /dev/null
+++ b/lib9/fmt.c
@@ -1,0 +1,188 @@
+/*
+ * 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 "lib9.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,
+ 'S', _runesfmt,
+ 'X', _ifmt,
+ 'b', _ifmt,
+ 'c', _charfmt,
+ 'd', _ifmt,
+ 'h', _flagfmt,
+ 'l', _flagfmt,
+ 'n', _countfmt,
+ 'o', _ifmt,
+ 'p', _ifmt,
+ 'r', errfmt,
+ 's', _strfmt,
+ 'u', _flagfmt,
+ 'x', _ifmt,
+ 0, nil,
+};
+
+int (*doquote)(int);
+
+static Fmts
+fmtfmt(int c)
+{
+ Convfmt *p, *ep;
+
+ ep = &fmtalloc.fmt[fmtalloc.nfmt];
+ for(p=fmtalloc.fmt; p<ep; p++)
+ if(p->c == c)
+ return p->fmt;
+
+ /* is this a predefined format char? */
+ for(p=knownfmt; p->c; p++)
+ if(p->c == c){
+ /* no need to lock; fmtinstall is idempotent */
+ fmtinstall(p->c, p->fmt);
+ while(p->fmt == nil) /* loop until value is updated */
+ ;
+ return p->fmt;
+ }
+
+ return _badfmt;
+}
+
+int
+fmtinstall(int c, Fmts f)
+{
+ Convfmt *p, *ep;
+
+ if(c<=0 || c>=65536)
+ return -1;
+ if(!f)
+ f = _badfmt;
+
+ _fmtlock();
+
+ ep = &fmtalloc.fmt[fmtalloc.nfmt];
+ for(p=fmtalloc.fmt; p<ep; p++)
+ if(p->c == c)
+ break;
+
+ if(p == &fmtalloc.fmt[Maxfmt]){
+ _fmtunlock();
+ return -1;
+ }
+
+ p->fmt = f;
+ if(p == ep){ /* installing a new format character */
+ fmtalloc.nfmt++;
+ p->c = c;
+ }
+
+ _fmtunlock();
+ return 0;
+}
+
+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, 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){
+ i = -i;
+ f->flags |= FmtLeft;
+ }
+ goto numflag;
+ }
+ n = (*fmtfmt(r))(f);
+ if(n < 0)
+ return nil;
+ if(n == 0)
+ return fmt;
+ }
+}
--- /dev/null
+++ b/lib9/fmtdef.h
@@ -1,0 +1,102 @@
+/*
+ * 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 */
+};
+
+void *_fmtflush(Fmt*, void*, int);
+void *_fmtdispatch(Fmt*, void*, int);
+int _floatfmt(Fmt*, double);
+int _fmtpad(Fmt*, int);
+int _rfmtpad(Fmt*, int);
+int _fmtFdFlush(Fmt*);
+
+int _efgfmt(Fmt*);
+int _charfmt(Fmt*);
+int _countfmt(Fmt*);
+int _flagfmt(Fmt*);
+int _percentfmt(Fmt*);
+int _ifmt(Fmt*);
+int _runefmt(Fmt*);
+int _runesfmt(Fmt*);
+int _strfmt(Fmt*);
+int _badfmt(Fmt*);
+int _fmtcpy(Fmt*, void*, int, int);
+int _fmtrcpy(Fmt*, void*, int n);
+
+void _fmtlock(void);
+void _fmtunlock(void);
+
+#define FMTCHAR(f, t, s, c)\
+ do{\
+ if(t + 1 > (char*)s){\
+ t = _fmtflush(f, t, 1);\
+ if(t != nil)\
+ s = f->stop;\
+ else\
+ return -1;\
+ }\
+ *t++ = c;\
+ }while(0)
+
+#define FMTRCHAR(f, t, s, c)\
+ do{\
+ if(t + 1 > (Rune*)s){\
+ t = _fmtflush(f, t, sizeof(Rune));\
+ if(t != nil)\
+ s = f->stop;\
+ else\
+ return -1;\
+ }\
+ *t++ = c;\
+ }while(0)
+
+#define FMTRUNE(f, t, s, r)\
+ do{\
+ Rune _rune;\
+ int _runelen;\
+ if(t + UTFmax > (char*)s && t + (_runelen = runelen(r)) > (char*)s){\
+ t = _fmtflush(f, t, _runelen);\
+ if(t != nil)\
+ s = f->stop;\
+ else\
+ return -1;\
+ }\
+ if(r < Runeself)\
+ *t++ = r;\
+ else{\
+ _rune = r;\
+ t += runetochar(t, &_rune);\
+ }\
+ }while(0)
+
+#ifndef va_copy
+#define va_copy(a, b) ((a) = (b))
+#endif
--- /dev/null
+++ b/lib9/fmtfd.c
@@ -1,0 +1,43 @@
+/*
+ * 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 "lib9.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;
+}
--- /dev/null
+++ b/lib9/fmtlock.c
@@ -1,0 +1,24 @@
+/*
+ * 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 "lib9.h"
+
+void
+_fmtlock(void)
+{
+}
+
+void
+_fmtunlock(void)
+{
+}
--- /dev/null
+++ b/lib9/fmtprint.c
@@ -1,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 "lib9.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;
+}
+
--- /dev/null
+++ b/lib9/fmtquote.c
@@ -1,0 +1,259 @@
+/*
+ * 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 "lib9.h"
+#include "fmtdef.h"
+
+/*
+ * How many bytes of output UTF will be produced by quoting (if necessary) this string?
+ * How many runes? How much of the input will be consumed?
+ * The parameter q is filled in by _quotesetup.
+ * The string may be UTF or Runes (s or r).
+ * Return count does not include NUL.
+ * Terminate the scan at the first of:
+ * NUL in input
+ * count exceeded in input
+ * count exceeded on output
+ * *ninp is set to number of input bytes accepted.
+ * nin may be <0 initially, to avoid checking input by count.
+ */
+void
+_quotesetup(char *s, Rune *r, int nin, int nout, Quoteinfo *q, int sharp, int runesout)
+{
+ int w;
+ Rune c;
+
+ q->quoted = 0;
+ q->nbytesout = 0;
+ q->nrunesout = 0;
+ q->nbytesin = 0;
+ q->nrunesin = 0;
+ if(sharp || nin==0 || (s && *s=='\0') || (r && *r=='\0')){
+ if(nout < 2)
+ return;
+ q->quoted = 1;
+ q->nbytesout = 2;
+ q->nrunesout = 2;
+ }
+ for(; nin!=0; nin-=w){
+ if(s)
+ w = chartorune(&c, s);
+ else{
+ c = *r;
+ w = runelen(c);
+ }
+
+ if(c == '\0')
+ break;
+ if(runesout){
+ if(q->nrunesout+1 > nout)
+ break;
+ }else{
+ if(q->nbytesout+w > nout)
+ break;
+ }
+
+ if((c <= L' ') || (c == L'\'') || (doquote!=nil && doquote(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 = f->to;
+ s = f->stop;
+ rt = f->to;
+ rs = 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 = *rm++;
+ }
+ if(f->runes){
+ FMTRCHAR(f, rt, rs, r);
+ if(r == '\'')
+ FMTRCHAR(f, rt, rs, r);
+ }else{
+ FMTRUNE(f, t, s, r);
+ if(r == '\'')
+ FMTRUNE(f, t, s, r);
+ }
+ }
+
+ if(f->runes){
+ FMTRCHAR(f, rt, rs, '\'');
+ USED(rs);
+ f->nfmt += rt - (Rune *)f->to;
+ f->to = rt;
+ if(fl & FmtLeft && _rfmtpad(f, w - q->nrunesout) < 0)
+ return -1;
+ }else{
+ FMTRUNE(f, t, s, '\'');
+ USED(s);
+ f->nfmt += t - (char *)f->to;
+ f->to = t;
+ if(fl & FmtLeft && _fmtpad(f, w - q->nbytesout) < 0)
+ return -1;
+ }
+ return 0;
+}
+
+int
+_quotestrfmt(int runesin, Fmt *f)
+{
+ int outlen;
+ Rune *r;
+ char *s;
+ Quoteinfo q;
+
+ f->flags &= ~FmtPrec; /* ignored for %q %Q, so disable for %s %S in easy case */
+ if(runesin){
+ r = va_arg(f->args, Rune *);
+ s = nil;
+ }else{
+ s = va_arg(f->args, char *);
+ r = nil;
+ }
+ if(!s && !r)
+ return _fmtcpy(f, "<nil>", 5, 5);
+
+ if(f->flush)
+ outlen = 0x7FFFFFFF; /* if we can flush, no output limit */
+ else if(f->runes)
+ outlen = (Rune*)f->stop - (Rune*)f->to;
+ else
+ outlen = (char*)f->stop - (char*)f->to;
+
+ _quotesetup(s, r, -1, outlen, &q, f->flags&FmtSharp, f->runes);
+//print("bytes in %d bytes out %d runes in %d runesout %d\n", q.nbytesin, q.nbytesout, q.nrunesin, q.nrunesout);
+
+ if(runesin){
+ if(!q.quoted)
+ return _fmtrcpy(f, r, q.nrunesin);
+ return qstrfmt(nil, r, &q, f);
+ }
+
+ if(!q.quoted)
+ return _fmtcpy(f, s, q.nrunesin, q.nbytesin);
+ return qstrfmt(s, nil, &q, f);
+}
+
+int
+quotestrfmt(Fmt *f)
+{
+ return _quotestrfmt(0, f);
+}
+
+int
+quoterunestrfmt(Fmt *f)
+{
+ return _quotestrfmt(1, f);
+}
+
+void
+quotefmtinstall(void)
+{
+ fmtinstall('q', quotestrfmt);
+ fmtinstall('Q', quoterunestrfmt);
+}
+
+int
+_needsquotes(char *s, int *quotelenp)
+{
+ Quoteinfo q;
+
+ _quotesetup(s, nil, -1, 0x7FFFFFFF, &q, 0, 0);
+ *quotelenp = q.nbytesout;
+
+ return q.quoted;
+}
+
+int
+_runeneedsquotes(Rune *r, int *quotelenp)
+{
+ Quoteinfo q;
+
+ _quotesetup(nil, r, -1, 0x7FFFFFFF, &q, 0, 0);
+ *quotelenp = q.nrunesout;
+
+ return q.quoted;
+}
--- /dev/null
+++ b/lib9/fmtrune.c
@@ -1,0 +1,37 @@
+/*
+ * 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 "lib9.h"
+#include "fmtdef.h"
+
+int
+fmtrune(Fmt *f, int r)
+{
+ Rune *rt;
+ char *t;
+ int n;
+
+ if(f->runes){
+ rt = f->to;
+ FMTRCHAR(f, rt, f->stop, r);
+ f->to = rt;
+ n = 1;
+ }else{
+ t = f->to;
+ FMTRUNE(f, t, f->stop, r);
+ n = t - (char*)f->to;
+ f->to = t;
+ }
+ f->nfmt += n;
+ return 0;
+}
--- /dev/null
+++ b/lib9/fmtstr.c
@@ -1,0 +1,23 @@
+/*
+ * 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 "lib9.h"
+
+char*
+fmtstrflush(Fmt *f)
+{
+ if(f->start == nil)
+ return nil;
+ *(char*)f->to = '\0';
+ return f->start;
+}
--- /dev/null
+++ b/lib9/fmtvprint.c
@@ -1,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 "lib9.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;
+}
+
--- /dev/null
+++ b/lib9/fprint.c
@@ -1,0 +1,26 @@
+/*
+ * 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 "lib9.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;
+}
--- /dev/null
+++ b/lib9/getcallerpc-DragonFly-386.S
@@ -1,0 +1,8 @@
+ .file "getcallerpc-DragonFly-386.S"
+
+ .type getcallerpc,@function
+ .global getcallerpc
+getcallerpc:
+ movl 4(%esp), %eax
+ movl -4(%eax), %eax
+ ret
--- /dev/null
+++ b/lib9/getcallerpc-FreeBSD-386.S
@@ -1,0 +1,8 @@
+ .file "getcallerpc-FreeBSD-386.S"
+
+ .type getcallerpc,@function
+ .global getcallerpc
+getcallerpc:
+ movl 4(%esp), %eax
+ movl -4(%eax), %eax
+ ret
--- /dev/null
+++ b/lib9/getcallerpc-Irix-mips.s
@@ -1,0 +1,9 @@
+#include <sys/regdef.h>
+#include <sys/asm.h>
+
+LEAF(getcallerpc)
+ .set noreorder
+ lw v0, 28(sp)
+ j ra
+ .set reorder
+ END(getcallerpc)
--- /dev/null
+++ b/lib9/getcallerpc-Linux-386.S
@@ -1,0 +1,7 @@
+ .file "getcallerpc-Linux-386.S"
+ .type getcallerpc,@function
+ .global getcallerpc
+getcallerpc:
+ movl 4(%esp), %eax
+ movl -4(%eax), %eax
+ ret
--- /dev/null
+++ b/lib9/getcallerpc-Linux-arm.S
@@ -1,0 +1,1 @@
+/* getcallerpc for arm Linux is placed in lib9.h as inline function*/
--- /dev/null
+++ b/lib9/getcallerpc-Linux-power.c
@@ -1,0 +1,12 @@
+#include <lib9.h>
+
+ulong
+getcallerpc(void *x)
+{
+ulong *lp;
+
+ lp = x;
+
+ return lp[-1];
+}
+
--- /dev/null
+++ b/lib9/getcallerpc-Linux-spim.S
@@ -1,0 +1,10 @@
+#include <sys/regdef.h>
+#include <sys/asm.h>
+
+LEAF(getcallerpc)
+ .set noreorder
+ addiu t0,a0,-4
+ j ra
+ lw v0,0(t0)
+ .set reorder
+ END(getcallerpc)
--- /dev/null
+++ b/lib9/getcallerpc-MacOSX-386.s
@@ -1,0 +1,7 @@
+ .file "getcallerpc-MacOSX-386.s"
+ .text
+.globl _getcallerpc
+_getcallerpc:
+ movl 4(%esp), %eax
+ movl -4(%eax), %eax
+ ret
--- /dev/null
+++ b/lib9/getcallerpc-MacOSX-power.s
@@ -1,0 +1,19 @@
+/*
+ File: getcallerpc-Darwin-power.s
+
+ getcallerpc() is passed a pointer
+
+ Plan 9 asm:
+
+ TEXT getcallerpc(SB), $-4
+ MOVW 0(R1), R3
+ RETURN
+
+ */
+
+#import <architecture/ppc/asm_help.h>
+
+.text
+LABEL(_getcallerpc)
+ mflr r3
+ blr
--- /dev/null
+++ b/lib9/getcallerpc-NetBSD-386.S
@@ -1,0 +1,8 @@
+ .file "getcallerpc-NetBSD-386.S"
+
+ .type getcallerpc,@function
+ .global getcallerpc
+getcallerpc:
+ movl 4(%esp), %eax
+ movl -4(%eax), %eax
+ ret
--- /dev/null
+++ b/lib9/getcallerpc-OpenBSD-386.S
@@ -1,0 +1,8 @@
+ .file "getcallerpc-OpenBSD-386.S"
+
+ .type getcallerpc,@function
+ .global getcallerpc
+getcallerpc:
+ movl 4(%esp), %eax
+ movl -4(%eax), %eax
+ ret
--- /dev/null
+++ b/lib9/getcallerpc-Solaris-386.s
@@ -1,0 +1,9 @@
+ .align 4
+ .globl getcallerpc
+getcallerpc:
+ movl 4(%esp), %eax
+ movl -4(%eax), %eax
+ ret
+ .align 4
+ .type getcallerpc,@function
+ .size getcallerpc,.-getcallerpc
--- /dev/null
+++ b/lib9/getcallerpc-Solaris-sparc.s
@@ -1,0 +1,11 @@
+ .section ".text", #alloc, #execinstr
+ .align 8
+ .skip 16
+ .global getcallerpc
+ .type getcallerpc, #function
+getcallerpc: ! ignore argument
+ retl
+ add %i7,0,%o0
+
+ .size getcallerpc,(.-getcallerpc)
+
--- /dev/null
+++ b/lib9/getcallerpc-Unixware-386.s
@@ -1,0 +1,9 @@
+ .align 4
+ .globl getcallerpc
+getcallerpc:
+ movl 4(%esp), %eax
+ movl -4(%eax), %eax
+ ret
+ .align 4
+ .type getcallerpc,@function
+ .size getcallerpc,.-getcallerpc
--- /dev/null
+++ b/lib9/getfields.c
@@ -1,0 +1,35 @@
+#include "lib9.h"
+int
+getfields(char *str, char **args, int max, int mflag, char *set)
+{
+ Rune r;
+ int nr, intok, narg;
+
+ if(max <= 0)
+ return 0;
+
+ narg = 0;
+ args[narg] = str;
+ if(!mflag)
+ narg++;
+ intok = 0;
+ for(;; str += nr) {
+ nr = chartorune(&r, str);
+ if(r == 0)
+ break;
+ if(utfrune(set, r)) {
+ if(narg >= max)
+ break;
+ *str = 0;
+ intok = 0;
+ args[narg] = str + nr;
+ if(!mflag)
+ narg++;
+ } else {
+ if(!intok && mflag)
+ narg++;
+ intok = 1;
+ }
+ }
+ return narg;
+}
--- /dev/null
+++ b/lib9/getuser-Nt.c
@@ -1,0 +1,8 @@
+#include "lib9.h"
+
+char*
+getuser(void)
+{
+ /* could do better, but result isn't really used */
+ return "unknown";
+}
--- /dev/null
+++ b/lib9/getuser-posix.c
@@ -1,0 +1,22 @@
+#include "lib9.h"
+#include <pwd.h>
+
+char*
+getuser(void)
+{
+ struct passwd *p;
+
+ static char *user = 0;
+
+ if (!user) {
+ p = getpwuid(getuid());
+ if (p && p->pw_name) {
+ user = malloc(strlen(p->pw_name)+1);
+ if (user)
+ strcpy(user, p->pw_name);
+ }
+ }
+ if(!user)
+ user = "unknown";
+ return user;
+}
--- /dev/null
+++ b/lib9/getwd-Nt.c
@@ -1,0 +1,24 @@
+#include "lib9.h"
+#include <windows.h>
+
+
+char*
+getwd(char *buf, int size)
+{
+ int n;
+ char *p;
+
+ buf[0] = 0;
+
+ n = GetCurrentDirectory(size, buf);
+ if(n == 0) {
+ /*winerror();*/
+ return 0;
+ }
+
+ for(p=buf; *p; p++)
+ if(*p == '\\')
+ *p = '/';
+
+ return buf;
+}
--- /dev/null
+++ b/lib9/getwd-posix.c
@@ -1,0 +1,9 @@
+#include "lib9.h"
+#undef getwd
+#include <unistd.h>
+
+char *
+infgetwd(char *buf, int size)
+{
+ return getcwd(buf, size);
+}
--- /dev/null
+++ b/lib9/isnan-posix.c
@@ -1,0 +1,15 @@
+#include <lib9.h>
+
+int
+isNaN(double d)
+{
+ return isnan(d);
+}
+
+int
+isInf(double d, int sign)
+{
+ if(sign < 0)
+ return isinf(d) < 0;
+ return isinf(d);
+}
--- /dev/null
+++ b/lib9/lock-Irix-mips.s
@@ -1,0 +1,19 @@
+#include <sys/regdef.h>
+#include <sys/asm.h>
+
+/*
+ * lock from r4000 book
+ */
+LEAF(canlock)
+ .set noreorder
+1:
+ ll t0,0(a0) /* a0 is argument */
+ or t1, t0, 1
+ sc t1,0(a0)
+ beq t1,zero,1b
+ nop
+ j $31 /* lock held */
+ xor v0, t0, 1
+
+ .set reorder
+ END(canlock)
--- /dev/null
+++ b/lib9/lock-MacOSX-power.s
@@ -1,0 +1,16 @@
+#include <architecture/ppc/asm_help.h>
+
+LEAF(__tas)
+ sync
+ mr r4,r3
+ addi r5,0,0x1
+1:
+ lwarx r3,0,r4
+ cmpwi r3,0x0
+ bne- 2f
+ stwcx. r5,0,r4
+ bne- 1b /* Lost reservation, try again */
+2:
+ sync
+ blr
+END(__tas)
--- /dev/null
+++ b/lib9/lock-Nt-386.c
@@ -1,0 +1,15 @@
+#include "lib9.h"
+
+int
+_tas(int *la)
+{
+ int v;
+
+ _asm {
+ mov eax, la
+ mov ebx, 1
+ xchg ebx, [eax]
+ mov v, ebx
+ }
+ return v;
+}
--- /dev/null
+++ b/lib9/lock-Solaris-386.s
@@ -1,0 +1,56 @@
+ .section .bss
+ .align 4
+.L4_.bss:
+ .align 4
+Solaris_Asm_IntP: / Offset 0
+ .type Solaris_Asm_IntP,@object
+ .size Solaris_Asm_IntP,4
+ .set .,.+4
+Solaris_Asm_VoidP: / Offset 4
+ .type Solaris_Asm_VoidP,@object
+ .size Solaris_Asm_VoidP,4
+ .set .,.+4
+ .section .data
+ .align 4
+.L2_.data:
+ .align 4
+.L01: .string "canlock corrupted 0x%lux\n\000"
+ .set .,.+0x2
+ .section .text
+ .align 4
+.L1_.text:
+
+ .align 4
+ .align 4
+ .globl canlock
+canlock:
+ pushl %ebp
+ movl %esp,%ebp
+ pushl %esi
+ movl 8(%ebp),%eax
+ movl %eax,Solaris_Asm_IntP
+ movl $1, %ecx
+ xchg (%eax), %ecx
+ andl %ecx,%ecx
+ jne .L1
+ movl $1,%esi
+ jmp .L2
+ .align 4
+.L3:
+ subl %esi,%esi
+ jmp .L2
+ .align 4
+.L1:
+ cmpl $1,%ecx
+ je .L3
+ pushl %ecx
+ pushl $.L01
+ call print
+ addl $8,%esp
+.L2:
+ movl %esi,%eax
+ popl %esi
+ leave
+ ret
+ .type canlock,@function
+ .size canlock,.-canlock
--- /dev/null
+++ b/lib9/lock-Solaris-sparc.s
@@ -1,0 +1,20 @@
+
+ .section ".text", #alloc, #execinstr
+ .align 8
+ .skip 16
+ .global canlock
+ .type canlock,#function
+
+canlock:
+ or %g0,1,%o1
+ swap [%o0],%o1 ! o0 points to lock; key is first word
+ cmp %o1,1
+ bne .gotit
+ nop
+ retl ! key was 1
+ or %g0,0,%o0
+.gotit:
+ retl ! key was not 1
+ or %g0,1,%o0
+
+ .size canlock,(.-canlock)
--- /dev/null
+++ b/lib9/lock-Unixware-386.s
@@ -1,0 +1,56 @@
+ .section .bss
+ .align 4
+.L4_.bss:
+ .align 4
+Unixware_Asm_IntP: / Offset 0
+ .type Unixware_Asm_IntP,@object
+ .size Unixware_Asm_IntP,4
+ .set .,.+4
+Unixware_Asm_VoidP: / Offset 4
+ .type Unixware_Asm_VoidP,@object
+ .size Unixware_Asm_VoidP,4
+ .set .,.+4
+ .section .data
+ .align 4
+.L2_.data:
+ .align 4
+.L01: .string "canlock corrupted 0x%lux\n\000"
+ .set .,.+0x2
+ .section .text
+ .align 4
+.L1_.text:
+
+ .align 4
+ .align 4
+ .globl canlock
+canlock:
+ pushl %ebp
+ movl %esp,%ebp
+ pushl %esi
+ movl 8(%ebp),%eax
+ movl %eax,Unixware_Asm_IntP
+ movl $1, %ecx
+ xchg (%eax), %ecx
+ andl %ecx,%ecx
+ jne .L1
+ movl $1,%esi
+ jmp .L2
+ .align 4
+.L3:
+ subl %esi,%esi
+ jmp .L2
+ .align 4
+.L1:
+ cmpl $1,%ecx
+ je .L3
+ pushl %ecx
+ pushl $.L01
+ call print
+ addl $8,%esp
+.L2:
+ movl %esi,%eax
+ popl %esi
+ leave
+ ret
+ .type canlock,@function
+ .size canlock,.-canlock
--- /dev/null
+++ b/lib9/lock.c
@@ -1,0 +1,141 @@
+#include "dat.h"
+#include "fns.h"
+#include "error.h"
+
+void
+lock(Lock *l)
+{
+ int i;
+
+ if(_tas(&l->val) == 0)
+ return;
+ for(i=0; i<100; i++){
+ if(_tas(&l->val) == 0)
+ return;
+ osyield();
+ }
+ for(i=1;; i++){
+ if(_tas(&l->val) == 0)
+ return;
+ osmillisleep(i*10);
+ if(i > 100){
+ osyield();
+ i = 1;
+ }
+ }
+}
+
+int
+canlock(Lock *l)
+{
+ return _tas(&l->val) == 0;
+}
+
+void
+unlock(Lock *l)
+{
+ l->val = 0;
+}
+
+void
+qlock(QLock *q)
+{
+ Proc *p;
+
+ lock(&q->use);
+ if(!q->locked) {
+ q->locked = 1;
+ unlock(&q->use);
+ return;
+ }
+ p = q->tail;
+ if(p == 0)
+ q->head = up;
+ else
+ p->qnext = up;
+ q->tail = up;
+ up->qnext = 0;
+ unlock(&q->use);
+ osblock();
+}
+
+int
+canqlock(QLock *q)
+{
+ if(!canlock(&q->use))
+ return 0;
+ if(q->locked){
+ unlock(&q->use);
+ return 0;
+ }
+ q->locked = 1;
+ unlock(&q->use);
+ return 1;
+}
+
+void
+qunlock(QLock *q)
+{
+ Proc *p;
+
+ lock(&q->use);
+ p = q->head;
+ if(p) {
+ q->head = p->qnext;
+ if(q->head == 0)
+ q->tail = 0;
+ unlock(&q->use);
+ osready(p);
+ return;
+ }
+ q->locked = 0;
+ unlock(&q->use);
+}
+
+void
+rlock(RWlock *l)
+{
+ qlock(&l->x); /* wait here for writers and exclusion */
+ lock(&l->l);
+ l->readers++;
+ canqlock(&l->k); /* block writers if we are the first reader */
+ unlock(&l->l);
+ qunlock(&l->x);
+}
+
+/* same as rlock but punts if there are any writers waiting */
+int
+canrlock(RWlock *l)
+{
+ if (!canqlock(&l->x))
+ return 0;
+ lock(&l->l);
+ l->readers++;
+ canqlock(&l->k); /* block writers if we are the first reader */
+ unlock(&l->l);
+ qunlock(&l->x);
+ return 1;
+}
+
+void
+runlock(RWlock *l)
+{
+ lock(&l->l);
+ if(--l->readers == 0) /* last reader out allows writers */
+ qunlock(&l->k);
+ unlock(&l->l);
+}
+
+void
+wlock(RWlock *l)
+{
+ qlock(&l->x); /* wait here for writers and exclusion */
+ qlock(&l->k); /* wait here for last reader */
+}
+
+void
+wunlock(RWlock *l)
+{
+ qunlock(&l->k);
+ qunlock(&l->x);
+}
--- /dev/null
+++ b/lib9/mkfile
@@ -1,0 +1,92 @@
+<../mkconfig
+
+LIB=lib9.a
+
+#
+# files used by all models
+#
+COMMONFILES=\
+ convD2M.$O\
+ convM2D.$O\
+ convM2S.$O\
+ convS2M.$O\
+ fcallfmt.$O\
+ runestrchr.$O\
+ runestrlen.$O\
+ runetype.$O\
+ strtoll.$O\
+ strtoull.$O\
+ rune.$O\
+#
+# files used by most models. these are added to TARGFILES in some
+# model-specific mkfiles included below
+#
+IMPORTFILES=\
+ argv0.$O\
+ charstod.$O\
+ cistrcmp.$O\
+ cistrncmp.$O\
+ cistrstr.$O\
+ cleanname.$O\
+ create.$O\
+ dirwstat.$O\
+ dofmt.$O\
+ dorfmt.$O\
+ errfmt.$O\
+ exits.$O\
+ fmt.$O\
+ fmtfd.$O\
+ fmtlock.$O\
+ fmtprint.$O\
+ fmtquote.$O\
+ fmtrune.$O\
+ fmtstr.$O\
+ fmtvprint.$O\
+ fprint.$O\
+ getfields.$O\
+ nulldir.$O\
+ pow10.$O\
+ print.$O\
+ qsort.$O\
+ readn.$O\
+ rerrstr.$O\
+ runeseprint.$O\
+ runesmprint.$O\
+ runesnprint.$O\
+ runevseprint.$O\
+ seek.$O\
+ seprint.$O\
+ smprint.$O\
+ snprint.$O\
+ sprint.$O\
+ strdup.$O\
+ strecpy.$O\
+ sysfatal.$O\
+ tokenize.$O\
+ u16.$O\
+ u32.$O\
+ u64.$O\
+ utflen.$O\
+ utfnlen.$O\
+ utfrrune.$O\
+ utfrune.$O\
+ utfecpy.$O\
+ vfprint.$O\
+ vseprint.$O\
+ vsmprint.$O\
+ vsnprint.$O\
+
+<mkfile-$TARGMODEL
+
+OFILES=$COMMONFILES $TARGFILES
+
+HFILES=$ROOT/$SYSTARG/$OBJTYPE/include/lib9.h\
+ fmtdef.h\
+
+<$ROOT/mkfiles/mksyslib-$SHELLTYPE
+
+convD2M.$O: $ROOT/include/fcall.h
+convM2D.$O: $ROOT/include/fcall.h
+convM2S.$O: $ROOT/include/fcall.h
+convS2M.$O: $ROOT/include/fcall.h
+fcallfmt.$O: $ROOT/include/fcall.h
--- /dev/null
+++ b/lib9/mkfile-Nt
@@ -1,0 +1,10 @@
+TARGFILES=\
+ $IMPORTFILES\
+ dirstat-Nt.$O\
+ errstr-Nt.$O\
+ getuser-Nt.$O\
+ getwd-Nt.$O\
+ setbinmode-Nt.$O\
+ lock-Nt-386.$O\
+ pread-Nt.$O\
+ isnan-posix.$O\
--- /dev/null
+++ b/lib9/mkfile-Plan9
@@ -1,0 +1,2 @@
+TARGFILES=errstr-Plan9.$O\
+
--- /dev/null
+++ b/lib9/mkfile-Posix
@@ -1,0 +1,10 @@
+TARGFILES=\
+ $IMPORTFILES\
+ dirstat-posix.$O\
+ errstr-posix.$O\
+ getuser-posix.$O\
+ getcallerpc-$SYSTARG-$OBJTYPE.$O\
+ setfcr-$SYSTARG-$OBJTYPE.$O\
+ getwd-posix.$O\
+ sbrk-posix.$O\
+ isnan-posix.$O\
--- /dev/null
+++ b/lib9/nulldir.c
@@ -1,0 +1,8 @@
+#include "lib9.h"
+
+void
+nulldir(Dir *d)
+{
+ memset(d, ~0, sizeof(Dir));
+ d->name = d->uid = d->gid = d->muid = "";
+}
--- /dev/null
+++ b/lib9/pow10.c
@@ -1,0 +1,51 @@
+#ifdef LINUX_386
+#define _MATH_H
+#endif
+#include "lib9.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,
+ 1.0e70, 1.0e71, 1.0e72, 1.0e73, 1.0e74, 1.0e75, 1.0e76, 1.0e77, 1.0e78, 1.0e79,
+ 1.0e80, 1.0e81, 1.0e82, 1.0e83, 1.0e84, 1.0e85, 1.0e86, 1.0e87, 1.0e88, 1.0e89,
+ 1.0e90, 1.0e91, 1.0e92, 1.0e93, 1.0e94, 1.0e95, 1.0e96, 1.0e97, 1.0e98, 1.0e99,
+ 1.0e100,1.0e101,1.0e102,1.0e103,1.0e104,1.0e105,1.0e106,1.0e107,1.0e108,1.0e109,
+ 1.0e110,1.0e111,1.0e112,1.0e113,1.0e114,1.0e115,1.0e116,1.0e117,1.0e118,1.0e119,
+ 1.0e120,1.0e121,1.0e122,1.0e123,1.0e124,1.0e125,1.0e126,1.0e127,1.0e128,1.0e129,
+ 1.0e130,1.0e131,1.0e132,1.0e133,1.0e134,1.0e135,1.0e136,1.0e137,1.0e138,1.0e139,
+ 1.0e140,1.0e141,1.0e142,1.0e143,1.0e144,1.0e145,1.0e146,1.0e147,1.0e148,1.0e149,
+ 1.0e150,1.0e151,1.0e152,1.0e153,1.0e154,1.0e155,1.0e156,1.0e157,1.0e158,1.0e159,
+};
+
+double
+pow10(int n)
+{
+ int m;
+
+ if(n < 0) {
+ n = -n;
+ if(n < sizeof(tab)/sizeof(tab[0]))
+ return 1/tab[n];
+ m = n/2;
+ return 1/(pow10(m) * pow10(n-m));
+ }
+ if(n < sizeof(tab)/sizeof(tab[0]))
+ return tab[n];
+ m = n/2;
+ return pow10(m) * pow10(n-m);
+}
--- /dev/null
+++ b/lib9/pread-Nt.c
@@ -1,0 +1,9 @@
+#include "lib9.h"
+
+long
+pread(int fd, void *buf, long n, vlong offset)
+{
+ if(seek(fd, offset, 0) < 0)
+ return -1;
+ return read(fd, buf, n);
+}
--- /dev/null
+++ b/lib9/print.c
@@ -1,0 +1,26 @@
+/*
+ * 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 "lib9.h"
+
+int
+print(char *fmt, ...)
+{
+ int n;
+ va_list args;
+
+ va_start(args, fmt);
+ n = vfprint(1, fmt, args);
+ va_end(args);
+ return n;
+}
--- /dev/null
+++ b/lib9/qsort.c
@@ -1,0 +1,123 @@
+/*
+ * qsort -- simple quicksort
+ */
+
+#include "lib9.h"
+typedef
+struct
+{
+ int (*cmp)(void*, void*);
+ void (*swap)(char*, char*, long);
+ long es;
+} Sort;
+
+static void
+swapb(char *i, char *j, long es)
+{
+ char c;
+
+ do {
+ c = *i;
+ *i++ = *j;
+ *j++ = c;
+ es--;
+ } while(es != 0);
+
+}
+
+static void
+swapi(char *ii, char *ij, long es)
+{
+ long *i, *j, c;
+
+ i = (long*)ii;
+ j = (long*)ij;
+ do {
+ c = *i;
+ *i++ = *j;
+ *j++ = c;
+ es -= sizeof(long);
+ } while(es != 0);
+}
+
+static char*
+pivot(char *a, long n, Sort *p)
+{
+ long j;
+ char *pi, *pj, *pk;
+
+ j = n/6 * p->es;
+ pi = a + j; /* 1/6 */
+ j += j;
+ pj = pi + j; /* 1/2 */
+ pk = pj + j; /* 5/6 */
+ if(p->cmp(pi, pj) < 0) {
+ if(p->cmp(pi, pk) < 0) {
+ if(p->cmp(pj, pk) < 0)
+ return pj;
+ return pk;
+ }
+ return pi;
+ }
+ if(p->cmp(pj, pk) < 0) {
+ if(p->cmp(pi, pk) < 0)
+ return pi;
+ return pk;
+ }
+ return pj;
+}
+
+static void
+qsorts(char *a, long n, Sort *p)
+{
+ long j, es;
+ char *pi, *pj, *pn;
+
+ es = p->es;
+ while(n > 1) {
+ if(n > 10) {
+ pi = pivot(a, n, p);
+ } else
+ pi = a + (n>>1)*es;
+
+ p->swap(a, pi, es);
+ pi = a;
+ pn = a + n*es;
+ pj = pn;
+ for(;;) {
+ do
+ pi += es;
+ while(pi < pn && p->cmp(pi, a) < 0);
+ do
+ pj -= es;
+ while(pj > a && p->cmp(pj, a) > 0);
+ if(pj < pi)
+ break;
+ p->swap(pi, pj, es);
+ }
+ p->swap(a, pj, es);
+ j = (pj - a) / es;
+
+ n = n-j-1;
+ if(j >= n) {
+ qsorts(a, j, p);
+ a += (j+1)*es;
+ } else {
+ qsorts(a + (j+1)*es, n, p);
+ n = j;
+ }
+ }
+}
+
+void
+qsort(void *va, long n, long es, int (*cmp)(void*, void*))
+{
+ Sort s;
+
+ s.cmp = cmp;
+ s.es = es;
+ s.swap = swapi;
+ if(((uintptr)va | es) % sizeof(long))
+ s.swap = swapb;
+ qsorts((char*)va, n, &s);
+}
--- /dev/null
+++ b/lib9/readn.c
@@ -1,0 +1,21 @@
+#include "lib9.h"
+
+long
+readn(int f, void *av, long n)
+{
+ char *a;
+ long m, t;
+
+ a = av;
+ t = 0;
+ while(t < n){
+ m = read(f, a+t, n-t);
+ if(m <= 0){
+ if(t == 0)
+ return m;
+ break;
+ }
+ t += m;
+ }
+ return t;
+}
--- /dev/null
+++ b/lib9/rerrstr.c
@@ -1,0 +1,12 @@
+#include "lib9.h"
+
+void
+rerrstr(char *buf, uint nbuf)
+{
+ char tmp[ERRMAX];
+
+ tmp[0] = 0;
+ errstr(tmp, sizeof tmp);
+ utfecpy(buf, buf+nbuf, tmp);
+ errstr(tmp, sizeof tmp);
+}
--- /dev/null
+++ b/lib9/rune.c
@@ -1,0 +1,165 @@
+#include "lib9.h"
+
+#define Bit(i) (7-(i))
+/* N 0's preceded by i 1's, T(Bit(2)) is 1100 0000 */
+#define T(i) (((1 << (Bit(i)+1))-1) ^ 0xFF)
+/* 0000 0000 0000 0111 1111 1111 */
+#define RuneX(i) ((1 << (Bit(i) + ((i)-1)*Bitx))-1)
+
+enum
+{
+ Bitx = Bit(1),
+
+ Tx = T(1), /* 1000 0000 */
+ Rune1 = (1<<(Bit(0)+0*Bitx))-1, /* 0000 0000 0000 0000 0111 1111 */
+
+ Maskx = (1<<Bitx)-1, /* 0011 1111 */
+ Testx = Maskx ^ 0xFF, /* 1100 0000 */
+
+ SurrogateMin = 0xD800,
+ SurrogateMax = 0xDFFF,
+
+ Bad = Runeerror,
+};
+
+int
+chartorune(Rune *rune, char *str)
+{
+ int c[UTFmax], i;
+ Rune l;
+
+ /*
+ * N character sequence
+ * 00000-0007F => T1
+ * 00080-007FF => T2 Tx
+ * 00800-0FFFF => T3 Tx Tx
+ * 10000-10FFFF => T4 Tx Tx Tx
+ */
+
+ c[0] = *(uchar*)(str);
+ if(c[0] < Tx){
+ *rune = c[0];
+ return 1;
+ }
+ l = c[0];
+
+ for(i = 1; i < UTFmax; i++) {
+ c[i] = *(uchar*)(str+i);
+ c[i] ^= Tx;
+ if(c[i] & Testx)
+ goto bad;
+ l = (l << Bitx) | c[i];
+ if(c[0] < T(i + 2)) {
+ l &= RuneX(i + 1);
+ if(i == 1) {
+ if(c[0] < T(2) || l <= Rune1)
+ goto bad;
+ } else if(l <= RuneX(i) || l > Runemax)
+ goto bad;
+ if (i == 2 && SurrogateMin <= l && l <= SurrogateMax)
+ goto bad;
+ *rune = l;
+ return i + 1;
+ }
+ }
+
+ /*
+ * bad decoding
+ */
+bad:
+ *rune = Bad;
+ return 1;
+}
+
+int
+runetochar(char *str, Rune *rune)
+{
+ int i, j;
+ Rune c;
+
+ c = *rune;
+ if(c <= Rune1) {
+ str[0] = c;
+ return 1;
+ }
+
+ /*
+ * one character sequence
+ * 00000-0007F => 00-7F
+ * two character sequence
+ * 0080-07FF => T2 Tx
+ * three character sequence
+ * 0800-FFFF => T3 Tx Tx
+ * four character sequence (21-bit value)
+ * 10000-1FFFFF => T4 Tx Tx Tx
+ * If the Rune is out of range or a surrogate half,
+ * convert it to the error rune.
+ * Do this test when i==3 because the error rune encodes to three bytes.
+ * Doing it earlier would duplicate work, since an out of range
+ * Rune wouldn't have fit in one or two bytes.
+ */
+ for(i = 2; i < UTFmax + 1; i++){
+ if(i == 3){
+ if(c > Runemax)
+ c = Runeerror;
+ if(SurrogateMin <= c && c <= SurrogateMax)
+ c = Runeerror;
+ }
+ if (c <= RuneX(i) || i == UTFmax ) {
+ str[0] = T(i) | (c >> (i - 1)*Bitx);
+ for(j = 1; j < i; j++)
+ str[j] = Tx | ((c >> (i - j - 1)*Bitx) & Maskx);
+ return i;
+ }
+ }
+ return UTFmax;
+}
+
+int
+runelen(long c)
+{
+ Rune rune;
+ char str[10];
+
+ rune = c;
+ return runetochar(str, &rune);
+}
+
+int
+runenlen(Rune *r, int nrune)
+{
+ int nb, i;
+ Rune c;
+
+ nb = 0;
+ while(nrune--) {
+ c = *r++;
+ if(c <= Rune1){
+ nb++;
+ } else {
+ for(i = 2; i < UTFmax + 1; i++)
+ if(c <= RuneX(i) || i == UTFmax){
+ nb += i;
+ break;
+ }
+ }
+ }
+ return nb;
+}
+
+int
+fullrune(char *str, int n)
+{
+ int i;
+ Rune c;
+
+ if(n <= 0)
+ return 0;
+ c = *(uchar*)str;
+ if(c < Tx)
+ return 1;
+ for(i = 3; i < UTFmax + 1; i++)
+ if(c < T(i))
+ return n >= i - 1;
+ return n >= UTFmax;
+}
--- /dev/null
+++ b/lib9/runeseprint.c
@@ -1,0 +1,13 @@
+#include "lib9.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;
+}
--- /dev/null
+++ b/lib9/runesmprint.c
@@ -1,0 +1,13 @@
+#include "lib9.h"
+
+Rune*
+runesmprint(char *fmt, ...)
+{
+ va_list args;
+ Rune *p;
+
+ va_start(args, fmt);
+ p = runevsmprint(fmt, args);
+ va_end(args);
+ return p;
+}
--- /dev/null
+++ b/lib9/runesnprint.c
@@ -1,0 +1,14 @@
+#include "lib9.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;
+}
+
--- /dev/null
+++ b/lib9/runestrchr.c
@@ -1,0 +1,19 @@
+#include "lib9.h"
+
+Rune*
+runestrchr(Rune *s, Rune c)
+{
+ Rune c0 = c;
+ Rune c1;
+
+ if(c == 0) {
+ while(*s++)
+ ;
+ return s-1;
+ }
+
+ while(c1 = *s++)
+ if(c1 == c0)
+ return s-1;
+ return 0;
+}
--- /dev/null
+++ b/lib9/runestrlen.c
@@ -1,0 +1,13 @@
+#include "lib9.h"
+
+
+long
+runestrlen(Rune *s)
+{
+ int i;
+
+ i = 0;
+ while(*s++)
+ i++;
+ return i;
+}
--- /dev/null
+++ b/lib9/runetype.c
@@ -1,0 +1,5 @@
+#include "lib9.h"
+
+Rune*_runebsearch(Rune c, Rune *t, int n, int ne);
+
+#include "runetypebody-6.2.0.h"
--- /dev/null
+++ b/lib9/runetypebody-6.2.0.h
@@ -1,0 +1,1641 @@
+/* generated automatically by mkrunetype.c in Go from UnicodeData-6.2.0.txt
+ * with s/rbsearch/_runebsearch/g
+ */
+
+static Rune __isspacer[] = {
+ 0x0009, 0x000d,
+ 0x0020, 0x0020,
+ 0x0085, 0x0085,
+ 0x00a0, 0x00a0,
+ 0x1680, 0x1680,
+ 0x180e, 0x180e,
+ 0x2000, 0x200a,
+ 0x2028, 0x2029,
+ 0x202f, 0x202f,
+ 0x205f, 0x205f,
+ 0x3000, 0x3000,
+ 0xfeff, 0xfeff,
+};
+
+int
+isspacerune(Rune c)
+{
+ Rune *p;
+
+ p = _runebsearch(c, __isspacer, nelem(__isspacer)/2, 2);
+ if(p && c >= p[0] && c <= p[1])
+ return 1;
+ return 0;
+}
+
+static Rune __isdigitr[] = {
+ 0x0030, 0x0039,
+ 0x0660, 0x0669,
+ 0x06f0, 0x06f9,
+ 0x07c0, 0x07c9,
+ 0x0966, 0x096f,
+ 0x09e6, 0x09ef,
+ 0x0a66, 0x0a6f,
+ 0x0ae6, 0x0aef,
+ 0x0b66, 0x0b6f,
+ 0x0be6, 0x0bef,
+ 0x0c66, 0x0c6f,
+ 0x0ce6, 0x0cef,
+ 0x0d66, 0x0d6f,
+ 0x0e50, 0x0e59,
+ 0x0ed0, 0x0ed9,
+ 0x0f20, 0x0f29,
+ 0x1040, 0x1049,
+ 0x1090, 0x1099,
+ 0x17e0, 0x17e9,
+ 0x1810, 0x1819,
+ 0x1946, 0x194f,
+ 0x19d0, 0x19d9,
+ 0x1a80, 0x1a89,
+ 0x1a90, 0x1a99,
+ 0x1b50, 0x1b59,
+ 0x1bb0, 0x1bb9,
+ 0x1c40, 0x1c49,
+ 0x1c50, 0x1c59,
+ 0xa620, 0xa629,
+ 0xa8d0, 0xa8d9,
+ 0xa900, 0xa909,
+ 0xa9d0, 0xa9d9,
+ 0xaa50, 0xaa59,
+ 0xabf0, 0xabf9,
+ 0xff10, 0xff19,
+ 0x104a0, 0x104a9,
+ 0x11066, 0x1106f,
+ 0x110f0, 0x110f9,
+ 0x11136, 0x1113f,
+ 0x111d0, 0x111d9,
+ 0x116c0, 0x116c9,
+ 0x1d7ce, 0x1d7ff,
+};
+
+int
+isdigitrune(Rune c)
+{
+ Rune *p;
+
+ p = _runebsearch(c, __isdigitr, nelem(__isdigitr)/2, 2);
+ if(p && c >= p[0] && c <= p[1])
+ return 1;
+ return 0;
+}
+
+static Rune __isalphar[] = {
+ 0x0041, 0x005a,
+ 0x0061, 0x007a,
+ 0x00c0, 0x00d6,
+ 0x00d8, 0x00f6,
+ 0x00f8, 0x02c1,
+ 0x02c6, 0x02d1,
+ 0x02e0, 0x02e4,
+ 0x0370, 0x0374,
+ 0x0376, 0x0377,
+ 0x037a, 0x037d,
+ 0x0388, 0x038a,
+ 0x038e, 0x03a1,
+ 0x03a3, 0x03f5,
+ 0x03f7, 0x0481,
+ 0x048a, 0x0527,
+ 0x0531, 0x0556,
+ 0x0561, 0x0587,
+ 0x05d0, 0x05ea,
+ 0x05f0, 0x05f2,
+ 0x0620, 0x064a,
+ 0x066e, 0x066f,
+ 0x0671, 0x06d3,
+ 0x06e5, 0x06e6,
+ 0x06ee, 0x06ef,
+ 0x06fa, 0x06fc,
+ 0x0712, 0x072f,
+ 0x074d, 0x07a5,
+ 0x07ca, 0x07ea,
+ 0x07f4, 0x07f5,
+ 0x0800, 0x0815,
+ 0x0840, 0x0858,
+ 0x08a2, 0x08ac,
+ 0x0904, 0x0939,
+ 0x0958, 0x0961,
+ 0x0971, 0x0977,
+ 0x0979, 0x097f,
+ 0x0985, 0x098c,
+ 0x098f, 0x0990,
+ 0x0993, 0x09a8,
+ 0x09aa, 0x09b0,
+ 0x09b6, 0x09b9,
+ 0x09dc, 0x09dd,
+ 0x09df, 0x09e1,
+ 0x09f0, 0x09f1,
+ 0x0a05, 0x0a0a,
+ 0x0a0f, 0x0a10,
+ 0x0a13, 0x0a28,
+ 0x0a2a, 0x0a30,
+ 0x0a32, 0x0a33,
+ 0x0a35, 0x0a36,
+ 0x0a38, 0x0a39,
+ 0x0a59, 0x0a5c,
+ 0x0a72, 0x0a74,
+ 0x0a85, 0x0a8d,
+ 0x0a8f, 0x0a91,
+ 0x0a93, 0x0aa8,
+ 0x0aaa, 0x0ab0,
+ 0x0ab2, 0x0ab3,
+ 0x0ab5, 0x0ab9,
+ 0x0ae0, 0x0ae1,
+ 0x0b05, 0x0b0c,
+ 0x0b0f, 0x0b10,
+ 0x0b13, 0x0b28,
+ 0x0b2a, 0x0b30,
+ 0x0b32, 0x0b33,
+ 0x0b35, 0x0b39,
+ 0x0b5c, 0x0b5d,
+ 0x0b5f, 0x0b61,
+ 0x0b85, 0x0b8a,
+ 0x0b8e, 0x0b90,
+ 0x0b92, 0x0b95,
+ 0x0b99, 0x0b9a,
+ 0x0b9e, 0x0b9f,
+ 0x0ba3, 0x0ba4,
+ 0x0ba8, 0x0baa,
+ 0x0bae, 0x0bb9,
+ 0x0c05, 0x0c0c,
+ 0x0c0e, 0x0c10,
+ 0x0c12, 0x0c28,
+ 0x0c2a, 0x0c33,
+ 0x0c35, 0x0c39,
+ 0x0c58, 0x0c59,
+ 0x0c60, 0x0c61,
+ 0x0c85, 0x0c8c,
+ 0x0c8e, 0x0c90,
+ 0x0c92, 0x0ca8,
+ 0x0caa, 0x0cb3,
+ 0x0cb5, 0x0cb9,
+ 0x0ce0, 0x0ce1,
+ 0x0cf1, 0x0cf2,
+ 0x0d05, 0x0d0c,
+ 0x0d0e, 0x0d10,
+ 0x0d12, 0x0d3a,
+ 0x0d60, 0x0d61,
+ 0x0d7a, 0x0d7f,
+ 0x0d85, 0x0d96,
+ 0x0d9a, 0x0db1,
+ 0x0db3, 0x0dbb,
+ 0x0dc0, 0x0dc6,
+ 0x0e01, 0x0e30,
+ 0x0e32, 0x0e33,
+ 0x0e40, 0x0e46,
+ 0x0e81, 0x0e82,
+ 0x0e87, 0x0e88,
+ 0x0e94, 0x0e97,
+ 0x0e99, 0x0e9f,
+ 0x0ea1, 0x0ea3,
+ 0x0eaa, 0x0eab,
+ 0x0ead, 0x0eb0,
+ 0x0eb2, 0x0eb3,
+ 0x0ec0, 0x0ec4,
+ 0x0edc, 0x0edf,
+ 0x0f40, 0x0f47,
+ 0x0f49, 0x0f6c,
+ 0x0f88, 0x0f8c,
+ 0x1000, 0x102a,
+ 0x1050, 0x1055,
+ 0x105a, 0x105d,
+ 0x1065, 0x1066,
+ 0x106e, 0x1070,
+ 0x1075, 0x1081,
+ 0x10a0, 0x10c5,
+ 0x10d0, 0x10fa,
+ 0x10fc, 0x1248,
+ 0x124a, 0x124d,
+ 0x1250, 0x1256,
+ 0x125a, 0x125d,
+ 0x1260, 0x1288,
+ 0x128a, 0x128d,
+ 0x1290, 0x12b0,
+ 0x12b2, 0x12b5,
+ 0x12b8, 0x12be,
+ 0x12c2, 0x12c5,
+ 0x12c8, 0x12d6,
+ 0x12d8, 0x1310,
+ 0x1312, 0x1315,
+ 0x1318, 0x135a,
+ 0x1380, 0x138f,
+ 0x13a0, 0x13f4,
+ 0x1401, 0x166c,
+ 0x166f, 0x167f,
+ 0x1681, 0x169a,
+ 0x16a0, 0x16ea,
+ 0x1700, 0x170c,
+ 0x170e, 0x1711,
+ 0x1720, 0x1731,
+ 0x1740, 0x1751,
+ 0x1760, 0x176c,
+ 0x176e, 0x1770,
+ 0x1780, 0x17b3,
+ 0x1820, 0x1877,
+ 0x1880, 0x18a8,
+ 0x18b0, 0x18f5,
+ 0x1900, 0x191c,
+ 0x1950, 0x196d,
+ 0x1970, 0x1974,
+ 0x1980, 0x19ab,
+ 0x19c1, 0x19c7,
+ 0x1a00, 0x1a16,
+ 0x1a20, 0x1a54,
+ 0x1b05, 0x1b33,
+ 0x1b45, 0x1b4b,
+ 0x1b83, 0x1ba0,
+ 0x1bae, 0x1baf,
+ 0x1bba, 0x1be5,
+ 0x1c00, 0x1c23,
+ 0x1c4d, 0x1c4f,
+ 0x1c5a, 0x1c7d,
+ 0x1ce9, 0x1cec,
+ 0x1cee, 0x1cf1,
+ 0x1cf5, 0x1cf6,
+ 0x1d00, 0x1dbf,
+ 0x1e00, 0x1f15,
+ 0x1f18, 0x1f1d,
+ 0x1f20, 0x1f45,
+ 0x1f48, 0x1f4d,
+ 0x1f50, 0x1f57,
+ 0x1f5f, 0x1f7d,
+ 0x1f80, 0x1fb4,
+ 0x1fb6, 0x1fbc,
+ 0x1fc2, 0x1fc4,
+ 0x1fc6, 0x1fcc,
+ 0x1fd0, 0x1fd3,
+ 0x1fd6, 0x1fdb,
+ 0x1fe0, 0x1fec,
+ 0x1ff2, 0x1ff4,
+ 0x1ff6, 0x1ffc,
+ 0x2090, 0x209c,
+ 0x210a, 0x2113,
+ 0x2119, 0x211d,
+ 0x212a, 0x212d,
+ 0x212f, 0x2139,
+ 0x213c, 0x213f,
+ 0x2145, 0x2149,
+ 0x2183, 0x2184,
+ 0x2c00, 0x2c2e,
+ 0x2c30, 0x2c5e,
+ 0x2c60, 0x2ce4,
+ 0x2ceb, 0x2cee,
+ 0x2cf2, 0x2cf3,
+ 0x2d00, 0x2d25,
+ 0x2d30, 0x2d67,
+ 0x2d80, 0x2d96,
+ 0x2da0, 0x2da6,
+ 0x2da8, 0x2dae,
+ 0x2db0, 0x2db6,
+ 0x2db8, 0x2dbe,
+ 0x2dc0, 0x2dc6,
+ 0x2dc8, 0x2dce,
+ 0x2dd0, 0x2dd6,
+ 0x2dd8, 0x2dde,
+ 0x3005, 0x3006,
+ 0x3031, 0x3035,
+ 0x303b, 0x303c,
+ 0x3041, 0x3096,
+ 0x309d, 0x309f,
+ 0x30a1, 0x30fa,
+ 0x30fc, 0x30ff,
+ 0x3105, 0x312d,
+ 0x3131, 0x318e,
+ 0x31a0, 0x31ba,
+ 0x31f0, 0x31ff,
+ 0x3400, 0x4db5,
+ 0x4e00, 0x9fcc,
+ 0xa000, 0xa48c,
+ 0xa4d0, 0xa4fd,
+ 0xa500, 0xa60c,
+ 0xa610, 0xa61f,
+ 0xa62a, 0xa62b,
+ 0xa640, 0xa66e,
+ 0xa67f, 0xa697,
+ 0xa6a0, 0xa6e5,
+ 0xa717, 0xa71f,
+ 0xa722, 0xa788,
+ 0xa78b, 0xa78e,
+ 0xa790, 0xa793,
+ 0xa7a0, 0xa7aa,
+ 0xa7f8, 0xa801,
+ 0xa803, 0xa805,
+ 0xa807, 0xa80a,
+ 0xa80c, 0xa822,
+ 0xa840, 0xa873,
+ 0xa882, 0xa8b3,
+ 0xa8f2, 0xa8f7,
+ 0xa90a, 0xa925,
+ 0xa930, 0xa946,
+ 0xa960, 0xa97c,
+ 0xa984, 0xa9b2,
+ 0xaa00, 0xaa28,
+ 0xaa40, 0xaa42,
+ 0xaa44, 0xaa4b,
+ 0xaa60, 0xaa76,
+ 0xaa80, 0xaaaf,
+ 0xaab5, 0xaab6,
+ 0xaab9, 0xaabd,
+ 0xaadb, 0xaadd,
+ 0xaae0, 0xaaea,
+ 0xaaf2, 0xaaf4,
+ 0xab01, 0xab06,
+ 0xab09, 0xab0e,
+ 0xab11, 0xab16,
+ 0xab20, 0xab26,
+ 0xab28, 0xab2e,
+ 0xabc0, 0xabe2,
+ 0xac00, 0xd7a3,
+ 0xd7b0, 0xd7c6,
+ 0xd7cb, 0xd7fb,
+ 0xf900, 0xfa6d,
+ 0xfa70, 0xfad9,
+ 0xfb00, 0xfb06,
+ 0xfb13, 0xfb17,
+ 0xfb1f, 0xfb28,
+ 0xfb2a, 0xfb36,
+ 0xfb38, 0xfb3c,
+ 0xfb40, 0xfb41,
+ 0xfb43, 0xfb44,
+ 0xfb46, 0xfbb1,
+ 0xfbd3, 0xfd3d,
+ 0xfd50, 0xfd8f,
+ 0xfd92, 0xfdc7,
+ 0xfdf0, 0xfdfb,
+ 0xfe70, 0xfe74,
+ 0xfe76, 0xfefc,
+ 0xff21, 0xff3a,
+ 0xff41, 0xff5a,
+ 0xff66, 0xffbe,
+ 0xffc2, 0xffc7,
+ 0xffca, 0xffcf,
+ 0xffd2, 0xffd7,
+ 0xffda, 0xffdc,
+ 0x10000, 0x1000b,
+ 0x1000d, 0x10026,
+ 0x10028, 0x1003a,
+ 0x1003c, 0x1003d,
+ 0x1003f, 0x1004d,
+ 0x10050, 0x1005d,
+ 0x10080, 0x100fa,
+ 0x10280, 0x1029c,
+ 0x102a0, 0x102d0,
+ 0x10300, 0x1031e,
+ 0x10330, 0x10340,
+ 0x10342, 0x10349,
+ 0x10380, 0x1039d,
+ 0x103a0, 0x103c3,
+ 0x103c8, 0x103cf,
+ 0x10400, 0x1049d,
+ 0x10800, 0x10805,
+ 0x1080a, 0x10835,
+ 0x10837, 0x10838,
+ 0x1083f, 0x10855,
+ 0x10900, 0x10915,
+ 0x10920, 0x10939,
+ 0x10980, 0x109b7,
+ 0x109be, 0x109bf,
+ 0x10a10, 0x10a13,
+ 0x10a15, 0x10a17,
+ 0x10a19, 0x10a33,
+ 0x10a60, 0x10a7c,
+ 0x10b00, 0x10b35,
+ 0x10b40, 0x10b55,
+ 0x10b60, 0x10b72,
+ 0x10c00, 0x10c48,
+ 0x11003, 0x11037,
+ 0x11083, 0x110af,
+ 0x110d0, 0x110e8,
+ 0x11103, 0x11126,
+ 0x11183, 0x111b2,
+ 0x111c1, 0x111c4,
+ 0x11680, 0x116aa,
+ 0x12000, 0x1236e,
+ 0x13000, 0x1342e,
+ 0x16800, 0x16a38,
+ 0x16f00, 0x16f44,
+ 0x16f93, 0x16f9f,
+ 0x1b000, 0x1b001,
+ 0x1d400, 0x1d454,
+ 0x1d456, 0x1d49c,
+ 0x1d49e, 0x1d49f,
+ 0x1d4a5, 0x1d4a6,
+ 0x1d4a9, 0x1d4ac,
+ 0x1d4ae, 0x1d4b9,
+ 0x1d4bd, 0x1d4c3,
+ 0x1d4c5, 0x1d505,
+ 0x1d507, 0x1d50a,
+ 0x1d50d, 0x1d514,
+ 0x1d516, 0x1d51c,
+ 0x1d51e, 0x1d539,
+ 0x1d53b, 0x1d53e,
+ 0x1d540, 0x1d544,
+ 0x1d54a, 0x1d550,
+ 0x1d552, 0x1d6a5,
+ 0x1d6a8, 0x1d6c0,
+ 0x1d6c2, 0x1d6da,
+ 0x1d6dc, 0x1d6fa,
+ 0x1d6fc, 0x1d714,
+ 0x1d716, 0x1d734,
+ 0x1d736, 0x1d74e,
+ 0x1d750, 0x1d76e,
+ 0x1d770, 0x1d788,
+ 0x1d78a, 0x1d7a8,
+ 0x1d7aa, 0x1d7c2,
+ 0x1d7c4, 0x1d7cb,
+ 0x1ee00, 0x1ee03,
+ 0x1ee05, 0x1ee1f,
+ 0x1ee21, 0x1ee22,
+ 0x1ee29, 0x1ee32,
+ 0x1ee34, 0x1ee37,
+ 0x1ee4d, 0x1ee4f,
+ 0x1ee51, 0x1ee52,
+ 0x1ee61, 0x1ee62,
+ 0x1ee67, 0x1ee6a,
+ 0x1ee6c, 0x1ee72,
+ 0x1ee74, 0x1ee77,
+ 0x1ee79, 0x1ee7c,
+ 0x1ee80, 0x1ee89,
+ 0x1ee8b, 0x1ee9b,
+ 0x1eea1, 0x1eea3,
+ 0x1eea5, 0x1eea9,
+ 0x1eeab, 0x1eebb,
+ 0x20000, 0x2a6d6,
+ 0x2a700, 0x2b734,
+ 0x2b740, 0x2b81d,
+ 0x2f800, 0x2fa1d,
+};
+
+static Rune __isalphas[] = {
+ 0x00aa,
+ 0x00b5,
+ 0x00ba,
+ 0x02ec,
+ 0x02ee,
+ 0x0386,
+ 0x038c,
+ 0x0559,
+ 0x06d5,
+ 0x06ff,
+ 0x0710,
+ 0x07b1,
+ 0x07fa,
+ 0x081a,
+ 0x0824,
+ 0x0828,
+ 0x08a0,
+ 0x093d,
+ 0x0950,
+ 0x09b2,
+ 0x09bd,
+ 0x09ce,
+ 0x0a5e,
+ 0x0abd,
+ 0x0ad0,
+ 0x0b3d,
+ 0x0b71,
+ 0x0b83,
+ 0x0b9c,
+ 0x0bd0,
+ 0x0c3d,
+ 0x0cbd,
+ 0x0cde,
+ 0x0d3d,
+ 0x0d4e,
+ 0x0dbd,
+ 0x0e84,
+ 0x0e8a,
+ 0x0e8d,
+ 0x0ea5,
+ 0x0ea7,
+ 0x0ebd,
+ 0x0ec6,
+ 0x0f00,
+ 0x103f,
+ 0x1061,
+ 0x108e,
+ 0x10c7,
+ 0x10cd,
+ 0x1258,
+ 0x12c0,
+ 0x17d7,
+ 0x17dc,
+ 0x18aa,
+ 0x1aa7,
+ 0x1f59,
+ 0x1f5b,
+ 0x1f5d,
+ 0x1fbe,
+ 0x2071,
+ 0x207f,
+ 0x2102,
+ 0x2107,
+ 0x2115,
+ 0x2124,
+ 0x2126,
+ 0x2128,
+ 0x214e,
+ 0x2d27,
+ 0x2d2d,
+ 0x2d6f,
+ 0x2e2f,
+ 0xa8fb,
+ 0xa9cf,
+ 0xaa7a,
+ 0xaab1,
+ 0xaac0,
+ 0xaac2,
+ 0xfb1d,
+ 0xfb3e,
+ 0x10808,
+ 0x1083c,
+ 0x10a00,
+ 0x16f50,
+ 0x1d4a2,
+ 0x1d4bb,
+ 0x1d546,
+ 0x1ee24,
+ 0x1ee27,
+ 0x1ee39,
+ 0x1ee3b,
+ 0x1ee42,
+ 0x1ee47,
+ 0x1ee49,
+ 0x1ee4b,
+ 0x1ee54,
+ 0x1ee57,
+ 0x1ee59,
+ 0x1ee5b,
+ 0x1ee5d,
+ 0x1ee5f,
+ 0x1ee64,
+ 0x1ee7e,
+};
+
+int
+isalpharune(Rune c)
+{
+ Rune *p;
+
+ p = _runebsearch(c, __isalphar, nelem(__isalphar)/2, 2);
+ if(p && c >= p[0] && c <= p[1])
+ return 1;
+ p = _runebsearch(c, __isalphas, nelem(__isalphas), 1);
+ if(p && c == p[0])
+ return 1;
+ return 0;
+}
+
+static Rune __isupperr[] = {
+ 0x0041, 0x005a,
+ 0x00c0, 0x00d6,
+ 0x00d8, 0x00de,
+ 0x0178, 0x0179,
+ 0x0181, 0x0182,
+ 0x0186, 0x0187,
+ 0x0189, 0x018b,
+ 0x018e, 0x0191,
+ 0x0193, 0x0194,
+ 0x0196, 0x0198,
+ 0x019c, 0x019d,
+ 0x019f, 0x01a0,
+ 0x01a6, 0x01a7,
+ 0x01ae, 0x01af,
+ 0x01b1, 0x01b3,
+ 0x01b7, 0x01b8,
+ 0x01f6, 0x01f8,
+ 0x023a, 0x023b,
+ 0x023d, 0x023e,
+ 0x0243, 0x0246,
+ 0x0388, 0x038a,
+ 0x038e, 0x038f,
+ 0x0391, 0x03a1,
+ 0x03a3, 0x03ab,
+ 0x03d2, 0x03d4,
+ 0x03f9, 0x03fa,
+ 0x03fd, 0x042f,
+ 0x04c0, 0x04c1,
+ 0x0531, 0x0556,
+ 0x10a0, 0x10c5,
+ 0x1f08, 0x1f0f,
+ 0x1f18, 0x1f1d,
+ 0x1f28, 0x1f2f,
+ 0x1f38, 0x1f3f,
+ 0x1f48, 0x1f4d,
+ 0x1f68, 0x1f6f,
+ 0x1f88, 0x1f8f,
+ 0x1f98, 0x1f9f,
+ 0x1fa8, 0x1faf,
+ 0x1fb8, 0x1fbc,
+ 0x1fc8, 0x1fcc,
+ 0x1fd8, 0x1fdb,
+ 0x1fe8, 0x1fec,
+ 0x1ff8, 0x1ffc,
+ 0x210b, 0x210d,
+ 0x2110, 0x2112,
+ 0x2119, 0x211d,
+ 0x212a, 0x212d,
+ 0x2130, 0x2133,
+ 0x213e, 0x213f,
+ 0x2160, 0x216f,
+ 0x24b6, 0x24cf,
+ 0x2c00, 0x2c2e,
+ 0x2c62, 0x2c64,
+ 0x2c6d, 0x2c70,
+ 0x2c7e, 0x2c80,
+ 0xa77d, 0xa77e,
+ 0xff21, 0xff3a,
+ 0x10400, 0x10427,
+ 0x1d400, 0x1d419,
+ 0x1d434, 0x1d44d,
+ 0x1d468, 0x1d481,
+ 0x1d49e, 0x1d49f,
+ 0x1d4a5, 0x1d4a6,
+ 0x1d4a9, 0x1d4ac,
+ 0x1d4ae, 0x1d4b5,
+ 0x1d4d0, 0x1d4e9,
+ 0x1d504, 0x1d505,
+ 0x1d507, 0x1d50a,
+ 0x1d50d, 0x1d514,
+ 0x1d516, 0x1d51c,
+ 0x1d538, 0x1d539,
+ 0x1d53b, 0x1d53e,
+ 0x1d540, 0x1d544,
+ 0x1d54a, 0x1d550,
+ 0x1d56c, 0x1d585,
+ 0x1d5a0, 0x1d5b9,
+ 0x1d5d4, 0x1d5ed,
+ 0x1d608, 0x1d621,
+ 0x1d63c, 0x1d655,
+ 0x1d670, 0x1d689,
+ 0x1d6a8, 0x1d6c0,
+ 0x1d6e2, 0x1d6fa,
+ 0x1d71c, 0x1d734,
+ 0x1d756, 0x1d76e,
+ 0x1d790, 0x1d7a8,
+};
+
+static Rune __isupperp[] = {
+ 0x0100, 0x0136,
+ 0x0139, 0x0147,
+ 0x014a, 0x0176,
+ 0x017b, 0x017d,
+ 0x01a2, 0x01a4,
+ 0x01cd, 0x01db,
+ 0x01de, 0x01ee,
+ 0x01fa, 0x0232,
+ 0x0248, 0x024e,
+ 0x0370, 0x0372,
+ 0x03d8, 0x03ee,
+ 0x0460, 0x0480,
+ 0x048a, 0x04be,
+ 0x04c3, 0x04cd,
+ 0x04d0, 0x0526,
+ 0x1e00, 0x1e94,
+ 0x1e9e, 0x1efe,
+ 0x1f59, 0x1f5f,
+ 0x2124, 0x2128,
+ 0x2c67, 0x2c6b,
+ 0x2c82, 0x2ce2,
+ 0x2ceb, 0x2ced,
+ 0xa640, 0xa66c,
+ 0xa680, 0xa696,
+ 0xa722, 0xa72e,
+ 0xa732, 0xa76e,
+ 0xa779, 0xa77b,
+ 0xa780, 0xa786,
+ 0xa78b, 0xa78d,
+ 0xa790, 0xa792,
+ 0xa7a0, 0xa7aa,
+};
+
+static Rune __isuppers[] = {
+ 0x0184,
+ 0x01a9,
+ 0x01ac,
+ 0x01b5,
+ 0x01bc,
+ 0x01c4,
+ 0x01c7,
+ 0x01ca,
+ 0x01f1,
+ 0x01f4,
+ 0x0241,
+ 0x0376,
+ 0x0386,
+ 0x038c,
+ 0x03cf,
+ 0x03f4,
+ 0x03f7,
+ 0x10c7,
+ 0x10cd,
+ 0x2102,
+ 0x2107,
+ 0x2115,
+ 0x2145,
+ 0x2183,
+ 0x2c60,
+ 0x2c72,
+ 0x2c75,
+ 0x2cf2,
+ 0x1d49c,
+ 0x1d4a2,
+ 0x1d546,
+ 0x1d7ca,
+};
+
+int
+isupperrune(Rune c)
+{
+ Rune *p;
+
+ p = _runebsearch(c, __isupperr, nelem(__isupperr)/2, 2);
+ if(p && c >= p[0] && c <= p[1])
+ return 1;
+ p = _runebsearch(c, __isupperp, nelem(__isupperp)/2, 2);
+ if(p && c >= p[0] && c <= p[1] && !((c - p[0]) & 1))
+ return 1;
+ p = _runebsearch(c, __isuppers, nelem(__isuppers), 1);
+ if(p && c == p[0])
+ return 1;
+ return 0;
+}
+
+static Rune __islowerr[] = {
+ 0x0061, 0x007a,
+ 0x00df, 0x00f6,
+ 0x00f8, 0x00ff,
+ 0x0137, 0x0138,
+ 0x0148, 0x0149,
+ 0x017e, 0x0180,
+ 0x018c, 0x018d,
+ 0x0199, 0x019b,
+ 0x01aa, 0x01ab,
+ 0x01b9, 0x01ba,
+ 0x01bd, 0x01bf,
+ 0x01dc, 0x01dd,
+ 0x01ef, 0x01f0,
+ 0x0233, 0x0239,
+ 0x023f, 0x0240,
+ 0x024f, 0x0293,
+ 0x0295, 0x02af,
+ 0x037b, 0x037d,
+ 0x03ac, 0x03ce,
+ 0x03d0, 0x03d1,
+ 0x03d5, 0x03d7,
+ 0x03ef, 0x03f3,
+ 0x03fb, 0x03fc,
+ 0x0430, 0x045f,
+ 0x04ce, 0x04cf,
+ 0x0561, 0x0587,
+ 0x1d00, 0x1d2b,
+ 0x1d6b, 0x1d77,
+ 0x1d79, 0x1d9a,
+ 0x1e95, 0x1e9d,
+ 0x1eff, 0x1f07,
+ 0x1f10, 0x1f15,
+ 0x1f20, 0x1f27,
+ 0x1f30, 0x1f37,
+ 0x1f40, 0x1f45,
+ 0x1f50, 0x1f57,
+ 0x1f60, 0x1f67,
+ 0x1f70, 0x1f7d,
+ 0x1f80, 0x1f87,
+ 0x1f90, 0x1f97,
+ 0x1fa0, 0x1fa7,
+ 0x1fb0, 0x1fb4,
+ 0x1fb6, 0x1fb7,
+ 0x1fc2, 0x1fc4,
+ 0x1fc6, 0x1fc7,
+ 0x1fd0, 0x1fd3,
+ 0x1fd6, 0x1fd7,
+ 0x1fe0, 0x1fe7,
+ 0x1ff2, 0x1ff4,
+ 0x1ff6, 0x1ff7,
+ 0x210e, 0x210f,
+ 0x213c, 0x213d,
+ 0x2146, 0x2149,
+ 0x2170, 0x217f,
+ 0x24d0, 0x24e9,
+ 0x2c30, 0x2c5e,
+ 0x2c65, 0x2c66,
+ 0x2c73, 0x2c74,
+ 0x2c76, 0x2c7b,
+ 0x2ce3, 0x2ce4,
+ 0x2d00, 0x2d25,
+ 0xa72f, 0xa731,
+ 0xa771, 0xa778,
+ 0xfb00, 0xfb06,
+ 0xfb13, 0xfb17,
+ 0xff41, 0xff5a,
+ 0x10428, 0x1044f,
+ 0x1d41a, 0x1d433,
+ 0x1d44e, 0x1d454,
+ 0x1d456, 0x1d467,
+ 0x1d482, 0x1d49b,
+ 0x1d4b6, 0x1d4b9,
+ 0x1d4bd, 0x1d4c3,
+ 0x1d4c5, 0x1d4cf,
+ 0x1d4ea, 0x1d503,
+ 0x1d51e, 0x1d537,
+ 0x1d552, 0x1d56b,
+ 0x1d586, 0x1d59f,
+ 0x1d5ba, 0x1d5d3,
+ 0x1d5ee, 0x1d607,
+ 0x1d622, 0x1d63b,
+ 0x1d656, 0x1d66f,
+ 0x1d68a, 0x1d6a5,
+ 0x1d6c2, 0x1d6da,
+ 0x1d6dc, 0x1d6e1,
+ 0x1d6fc, 0x1d714,
+ 0x1d716, 0x1d71b,
+ 0x1d736, 0x1d74e,
+ 0x1d750, 0x1d755,
+ 0x1d770, 0x1d788,
+ 0x1d78a, 0x1d78f,
+ 0x1d7aa, 0x1d7c2,
+ 0x1d7c4, 0x1d7c9,
+};
+
+static Rune __islowerp[] = {
+ 0x0101, 0x0135,
+ 0x013a, 0x0146,
+ 0x014b, 0x0177,
+ 0x017a, 0x017c,
+ 0x0183, 0x0185,
+ 0x01a1, 0x01a5,
+ 0x01b4, 0x01b6,
+ 0x01cc, 0x01da,
+ 0x01df, 0x01ed,
+ 0x01f3, 0x01f5,
+ 0x01f9, 0x0231,
+ 0x0247, 0x024d,
+ 0x0371, 0x0373,
+ 0x03d9, 0x03ed,
+ 0x0461, 0x0481,
+ 0x048b, 0x04bf,
+ 0x04c2, 0x04cc,
+ 0x04d1, 0x0527,
+ 0x1e01, 0x1e93,
+ 0x1e9f, 0x1efd,
+ 0x2c68, 0x2c6c,
+ 0x2c81, 0x2ce1,
+ 0x2cec, 0x2cee,
+ 0xa641, 0xa66d,
+ 0xa681, 0xa697,
+ 0xa723, 0xa72d,
+ 0xa733, 0xa76f,
+ 0xa77a, 0xa77c,
+ 0xa77f, 0xa787,
+ 0xa78c, 0xa78e,
+ 0xa791, 0xa793,
+ 0xa7a1, 0xa7a9,
+};
+
+static Rune __islowers[] = {
+ 0x00b5,
+ 0x0188,
+ 0x0192,
+ 0x0195,
+ 0x019e,
+ 0x01a8,
+ 0x01ad,
+ 0x01b0,
+ 0x01c6,
+ 0x01c9,
+ 0x023c,
+ 0x0242,
+ 0x0377,
+ 0x0390,
+ 0x03f5,
+ 0x03f8,
+ 0x1fbe,
+ 0x210a,
+ 0x2113,
+ 0x212f,
+ 0x2134,
+ 0x2139,
+ 0x214e,
+ 0x2184,
+ 0x2c61,
+ 0x2c71,
+ 0x2cf3,
+ 0x2d27,
+ 0x2d2d,
+ 0xa7fa,
+ 0x1d4bb,
+ 0x1d7cb,
+};
+
+int
+islowerrune(Rune c)
+{
+ Rune *p;
+
+ p = _runebsearch(c, __islowerr, nelem(__islowerr)/2, 2);
+ if(p && c >= p[0] && c <= p[1])
+ return 1;
+ p = _runebsearch(c, __islowerp, nelem(__islowerp)/2, 2);
+ if(p && c >= p[0] && c <= p[1] && !((c - p[0]) & 1))
+ return 1;
+ p = _runebsearch(c, __islowers, nelem(__islowers), 1);
+ if(p && c == p[0])
+ return 1;
+ return 0;
+}
+
+static Rune __istitler[] = {
+ 0x0041, 0x005a,
+ 0x00c0, 0x00d6,
+ 0x00d8, 0x00de,
+ 0x0178, 0x0179,
+ 0x0181, 0x0182,
+ 0x0186, 0x0187,
+ 0x0189, 0x018b,
+ 0x018e, 0x0191,
+ 0x0193, 0x0194,
+ 0x0196, 0x0198,
+ 0x019c, 0x019d,
+ 0x019f, 0x01a0,
+ 0x01a6, 0x01a7,
+ 0x01ae, 0x01af,
+ 0x01b1, 0x01b3,
+ 0x01b7, 0x01b8,
+ 0x01f6, 0x01f8,
+ 0x023a, 0x023b,
+ 0x023d, 0x023e,
+ 0x0243, 0x0246,
+ 0x0388, 0x038a,
+ 0x038e, 0x038f,
+ 0x0391, 0x03a1,
+ 0x03a3, 0x03ab,
+ 0x03f9, 0x03fa,
+ 0x03fd, 0x042f,
+ 0x04c0, 0x04c1,
+ 0x0531, 0x0556,
+ 0x10a0, 0x10c5,
+ 0x1f08, 0x1f0f,
+ 0x1f18, 0x1f1d,
+ 0x1f28, 0x1f2f,
+ 0x1f38, 0x1f3f,
+ 0x1f48, 0x1f4d,
+ 0x1f68, 0x1f6f,
+ 0x1f88, 0x1f8f,
+ 0x1f98, 0x1f9f,
+ 0x1fa8, 0x1faf,
+ 0x1fb8, 0x1fbc,
+ 0x1fc8, 0x1fcc,
+ 0x1fd8, 0x1fdb,
+ 0x1fe8, 0x1fec,
+ 0x1ff8, 0x1ffc,
+ 0x2160, 0x216f,
+ 0x24b6, 0x24cf,
+ 0x2c00, 0x2c2e,
+ 0x2c62, 0x2c64,
+ 0x2c6d, 0x2c70,
+ 0x2c7e, 0x2c80,
+ 0xa77d, 0xa77e,
+ 0xff21, 0xff3a,
+ 0x10400, 0x10427,
+};
+
+static Rune __istitlep[] = {
+ 0x0100, 0x012e,
+ 0x0132, 0x0136,
+ 0x0139, 0x0147,
+ 0x014a, 0x0176,
+ 0x017b, 0x017d,
+ 0x01a2, 0x01a4,
+ 0x01cb, 0x01db,
+ 0x01de, 0x01ee,
+ 0x01f2, 0x01f4,
+ 0x01fa, 0x0232,
+ 0x0248, 0x024e,
+ 0x0370, 0x0372,
+ 0x03d8, 0x03ee,
+ 0x0460, 0x0480,
+ 0x048a, 0x04be,
+ 0x04c3, 0x04cd,
+ 0x04d0, 0x0526,
+ 0x1e00, 0x1e94,
+ 0x1ea0, 0x1efe,
+ 0x1f59, 0x1f5f,
+ 0x2c67, 0x2c6b,
+ 0x2c82, 0x2ce2,
+ 0x2ceb, 0x2ced,
+ 0xa640, 0xa66c,
+ 0xa680, 0xa696,
+ 0xa722, 0xa72e,
+ 0xa732, 0xa76e,
+ 0xa779, 0xa77b,
+ 0xa780, 0xa786,
+ 0xa78b, 0xa78d,
+ 0xa790, 0xa792,
+ 0xa7a0, 0xa7aa,
+};
+
+static Rune __istitles[] = {
+ 0x0184,
+ 0x01a9,
+ 0x01ac,
+ 0x01b5,
+ 0x01bc,
+ 0x01c5,
+ 0x01c8,
+ 0x0241,
+ 0x0376,
+ 0x0386,
+ 0x038c,
+ 0x03cf,
+ 0x03f7,
+ 0x10c7,
+ 0x10cd,
+ 0x2132,
+ 0x2183,
+ 0x2c60,
+ 0x2c72,
+ 0x2c75,
+ 0x2cf2,
+};
+
+int
+istitlerune(Rune c)
+{
+ Rune *p;
+
+ p = _runebsearch(c, __istitler, nelem(__istitler)/2, 2);
+ if(p && c >= p[0] && c <= p[1])
+ return 1;
+ p = _runebsearch(c, __istitlep, nelem(__istitlep)/2, 2);
+ if(p && c >= p[0] && c <= p[1] && !((c - p[0]) & 1))
+ return 1;
+ p = _runebsearch(c, __istitles, nelem(__istitles), 1);
+ if(p && c == p[0])
+ return 1;
+ return 0;
+}
+
+static Rune __toupperr[] = {
+ 0x0061, 0x007a, 1048544,
+ 0x00e0, 0x00f6, 1048544,
+ 0x00f8, 0x00fe, 1048544,
+ 0x023f, 0x0240, 1059391,
+ 0x0256, 0x0257, 1048371,
+ 0x028a, 0x028b, 1048359,
+ 0x037b, 0x037d, 1048706,
+ 0x03ad, 0x03af, 1048539,
+ 0x03b1, 0x03c1, 1048544,
+ 0x03c3, 0x03cb, 1048544,
+ 0x03cd, 0x03ce, 1048513,
+ 0x0430, 0x044f, 1048544,
+ 0x0450, 0x045f, 1048496,
+ 0x0561, 0x0586, 1048528,
+ 0x1f00, 0x1f07, 1048584,
+ 0x1f10, 0x1f15, 1048584,
+ 0x1f20, 0x1f27, 1048584,
+ 0x1f30, 0x1f37, 1048584,
+ 0x1f40, 0x1f45, 1048584,
+ 0x1f60, 0x1f67, 1048584,
+ 0x1f70, 0x1f71, 1048650,
+ 0x1f72, 0x1f75, 1048662,
+ 0x1f76, 0x1f77, 1048676,
+ 0x1f78, 0x1f79, 1048704,
+ 0x1f7a, 0x1f7b, 1048688,
+ 0x1f7c, 0x1f7d, 1048702,
+ 0x1f80, 0x1f87, 1048584,
+ 0x1f90, 0x1f97, 1048584,
+ 0x1fa0, 0x1fa7, 1048584,
+ 0x1fb0, 0x1fb1, 1048584,
+ 0x1fd0, 0x1fd1, 1048584,
+ 0x1fe0, 0x1fe1, 1048584,
+ 0x2170, 0x217f, 1048560,
+ 0x24d0, 0x24e9, 1048550,
+ 0x2c30, 0x2c5e, 1048528,
+ 0x2d00, 0x2d25, 1041312,
+ 0xff41, 0xff5a, 1048544,
+ 0x10428, 0x1044f, 1048536,
+};
+
+static Rune __toupperp[] = {
+ 0x0101, 0x012f, 1048575,
+ 0x0133, 0x0137, 1048575,
+ 0x013a, 0x0148, 1048575,
+ 0x014b, 0x0177, 1048575,
+ 0x017a, 0x017e, 1048575,
+ 0x0183, 0x0185, 1048575,
+ 0x01a1, 0x01a5, 1048575,
+ 0x01b4, 0x01b6, 1048575,
+ 0x01ce, 0x01dc, 1048575,
+ 0x01df, 0x01ef, 1048575,
+ 0x01f9, 0x021f, 1048575,
+ 0x0223, 0x0233, 1048575,
+ 0x0247, 0x024f, 1048575,
+ 0x0371, 0x0373, 1048575,
+ 0x03d9, 0x03ef, 1048575,
+ 0x0461, 0x0481, 1048575,
+ 0x048b, 0x04bf, 1048575,
+ 0x04c2, 0x04ce, 1048575,
+ 0x04d1, 0x0527, 1048575,
+ 0x1e01, 0x1e95, 1048575,
+ 0x1ea1, 0x1eff, 1048575,
+ 0x1f51, 0x1f57, 1048584,
+ 0x2c68, 0x2c6c, 1048575,
+ 0x2c81, 0x2ce3, 1048575,
+ 0x2cec, 0x2cee, 1048575,
+ 0xa641, 0xa66d, 1048575,
+ 0xa681, 0xa697, 1048575,
+ 0xa723, 0xa72f, 1048575,
+ 0xa733, 0xa76f, 1048575,
+ 0xa77a, 0xa77c, 1048575,
+ 0xa77f, 0xa787, 1048575,
+ 0xa791, 0xa793, 1048575,
+ 0xa7a1, 0xa7a9, 1048575,
+};
+
+static Rune __touppers[] = {
+ 0x00b5, 1049319,
+ 0x00ff, 1048697,
+ 0x0131, 1048344,
+ 0x017f, 1048276,
+ 0x0180, 1048771,
+ 0x0188, 1048575,
+ 0x018c, 1048575,
+ 0x0192, 1048575,
+ 0x0195, 1048673,
+ 0x0199, 1048575,
+ 0x019a, 1048739,
+ 0x019e, 1048706,
+ 0x01a8, 1048575,
+ 0x01ad, 1048575,
+ 0x01b0, 1048575,
+ 0x01b9, 1048575,
+ 0x01bd, 1048575,
+ 0x01bf, 1048632,
+ 0x01c5, 1048575,
+ 0x01c6, 1048574,
+ 0x01c8, 1048575,
+ 0x01c9, 1048574,
+ 0x01cb, 1048575,
+ 0x01cc, 1048574,
+ 0x01dd, 1048497,
+ 0x01f2, 1048575,
+ 0x01f3, 1048574,
+ 0x01f5, 1048575,
+ 0x023c, 1048575,
+ 0x0242, 1048575,
+ 0x0250, 1059359,
+ 0x0251, 1059356,
+ 0x0252, 1059358,
+ 0x0253, 1048366,
+ 0x0254, 1048370,
+ 0x0259, 1048374,
+ 0x025b, 1048373,
+ 0x0260, 1048371,
+ 0x0263, 1048369,
+ 0x0265, 1090856,
+ 0x0266, 1090884,
+ 0x0268, 1048367,
+ 0x0269, 1048365,
+ 0x026b, 1059319,
+ 0x026f, 1048365,
+ 0x0271, 1059325,
+ 0x0272, 1048363,
+ 0x0275, 1048362,
+ 0x027d, 1059303,
+ 0x0280, 1048358,
+ 0x0283, 1048358,
+ 0x0288, 1048358,
+ 0x0289, 1048507,
+ 0x028c, 1048505,
+ 0x0292, 1048357,
+ 0x0345, 1048660,
+ 0x0377, 1048575,
+ 0x03ac, 1048538,
+ 0x03c2, 1048545,
+ 0x03cc, 1048512,
+ 0x03d0, 1048514,
+ 0x03d1, 1048519,
+ 0x03d5, 1048529,
+ 0x03d6, 1048522,
+ 0x03d7, 1048568,
+ 0x03f0, 1048490,
+ 0x03f1, 1048496,
+ 0x03f2, 1048583,
+ 0x03f5, 1048480,
+ 0x03f8, 1048575,
+ 0x03fb, 1048575,
+ 0x04cf, 1048561,
+ 0x1d79, 1083908,
+ 0x1d7d, 1052390,
+ 0x1e9b, 1048517,
+ 0x1fb3, 1048585,
+ 0x1fbe, 1041371,
+ 0x1fc3, 1048585,
+ 0x1fe5, 1048583,
+ 0x1ff3, 1048585,
+ 0x214e, 1048548,
+ 0x2184, 1048575,
+ 0x2c61, 1048575,
+ 0x2c65, 1037781,
+ 0x2c66, 1037784,
+ 0x2c73, 1048575,
+ 0x2c76, 1048575,
+ 0x2cf3, 1048575,
+ 0x2d27, 1041312,
+ 0x2d2d, 1041312,
+ 0xa78c, 1048575,
+};
+
+Rune
+toupperrune(Rune c)
+{
+ Rune *p;
+
+ p = _runebsearch(c, __toupperr, nelem(__toupperr)/3, 3);
+ if(p && c >= p[0] && c <= p[1])
+ return c + p[2] - 1048576;
+ p = _runebsearch(c, __toupperp, nelem(__toupperp)/3, 3);
+ if(p && c >= p[0] && c <= p[1] && !((c - p[0]) & 1))
+ return c + p[2] - 1048576;
+ p = _runebsearch(c, __touppers, nelem(__touppers)/2, 2);
+ if(p && c == p[0])
+ return c + p[1] - 1048576;
+ return c;
+}
+
+static Rune __tolowerr[] = {
+ 0x0041, 0x005a, 1048608,
+ 0x00c0, 0x00d6, 1048608,
+ 0x00d8, 0x00de, 1048608,
+ 0x0189, 0x018a, 1048781,
+ 0x01b1, 0x01b2, 1048793,
+ 0x0388, 0x038a, 1048613,
+ 0x038e, 0x038f, 1048639,
+ 0x0391, 0x03a1, 1048608,
+ 0x03a3, 0x03ab, 1048608,
+ 0x03fd, 0x03ff, 1048446,
+ 0x0400, 0x040f, 1048656,
+ 0x0410, 0x042f, 1048608,
+ 0x0531, 0x0556, 1048624,
+ 0x10a0, 0x10c5, 1055840,
+ 0x1f08, 0x1f0f, 1048568,
+ 0x1f18, 0x1f1d, 1048568,
+ 0x1f28, 0x1f2f, 1048568,
+ 0x1f38, 0x1f3f, 1048568,
+ 0x1f48, 0x1f4d, 1048568,
+ 0x1f68, 0x1f6f, 1048568,
+ 0x1f88, 0x1f8f, 1048568,
+ 0x1f98, 0x1f9f, 1048568,
+ 0x1fa8, 0x1faf, 1048568,
+ 0x1fb8, 0x1fb9, 1048568,
+ 0x1fba, 0x1fbb, 1048502,
+ 0x1fc8, 0x1fcb, 1048490,
+ 0x1fd8, 0x1fd9, 1048568,
+ 0x1fda, 0x1fdb, 1048476,
+ 0x1fe8, 0x1fe9, 1048568,
+ 0x1fea, 0x1feb, 1048464,
+ 0x1ff8, 0x1ff9, 1048448,
+ 0x1ffa, 0x1ffb, 1048450,
+ 0x2160, 0x216f, 1048592,
+ 0x24b6, 0x24cf, 1048602,
+ 0x2c00, 0x2c2e, 1048624,
+ 0x2c7e, 0x2c7f, 1037761,
+ 0xff21, 0xff3a, 1048608,
+ 0x10400, 0x10427, 1048616,
+};
+
+static Rune __tolowerp[] = {
+ 0x0100, 0x012e, 1048577,
+ 0x0132, 0x0136, 1048577,
+ 0x0139, 0x0147, 1048577,
+ 0x014a, 0x0176, 1048577,
+ 0x017b, 0x017d, 1048577,
+ 0x01a2, 0x01a4, 1048577,
+ 0x01b3, 0x01b5, 1048577,
+ 0x01cd, 0x01db, 1048577,
+ 0x01de, 0x01ee, 1048577,
+ 0x01f8, 0x021e, 1048577,
+ 0x0222, 0x0232, 1048577,
+ 0x0248, 0x024e, 1048577,
+ 0x0370, 0x0372, 1048577,
+ 0x03d8, 0x03ee, 1048577,
+ 0x0460, 0x0480, 1048577,
+ 0x048a, 0x04be, 1048577,
+ 0x04c3, 0x04cd, 1048577,
+ 0x04d0, 0x0526, 1048577,
+ 0x1e00, 0x1e94, 1048577,
+ 0x1ea0, 0x1efe, 1048577,
+ 0x1f59, 0x1f5f, 1048568,
+ 0x2c67, 0x2c6b, 1048577,
+ 0x2c80, 0x2ce2, 1048577,
+ 0x2ceb, 0x2ced, 1048577,
+ 0xa640, 0xa66c, 1048577,
+ 0xa680, 0xa696, 1048577,
+ 0xa722, 0xa72e, 1048577,
+ 0xa732, 0xa76e, 1048577,
+ 0xa779, 0xa77b, 1048577,
+ 0xa780, 0xa786, 1048577,
+ 0xa790, 0xa792, 1048577,
+ 0xa7a0, 0xa7a8, 1048577,
+};
+
+static Rune __tolowers[] = {
+ 0x0130, 1048377,
+ 0x0178, 1048455,
+ 0x0179, 1048577,
+ 0x0181, 1048786,
+ 0x0182, 1048577,
+ 0x0184, 1048577,
+ 0x0186, 1048782,
+ 0x0187, 1048577,
+ 0x018b, 1048577,
+ 0x018e, 1048655,
+ 0x018f, 1048778,
+ 0x0190, 1048779,
+ 0x0191, 1048577,
+ 0x0193, 1048781,
+ 0x0194, 1048783,
+ 0x0196, 1048787,
+ 0x0197, 1048785,
+ 0x0198, 1048577,
+ 0x019c, 1048787,
+ 0x019d, 1048789,
+ 0x019f, 1048790,
+ 0x01a0, 1048577,
+ 0x01a6, 1048794,
+ 0x01a7, 1048577,
+ 0x01a9, 1048794,
+ 0x01ac, 1048577,
+ 0x01ae, 1048794,
+ 0x01af, 1048577,
+ 0x01b7, 1048795,
+ 0x01b8, 1048577,
+ 0x01bc, 1048577,
+ 0x01c4, 1048578,
+ 0x01c5, 1048577,
+ 0x01c7, 1048578,
+ 0x01c8, 1048577,
+ 0x01ca, 1048578,
+ 0x01cb, 1048577,
+ 0x01f1, 1048578,
+ 0x01f2, 1048577,
+ 0x01f4, 1048577,
+ 0x01f6, 1048479,
+ 0x01f7, 1048520,
+ 0x0220, 1048446,
+ 0x023a, 1059371,
+ 0x023b, 1048577,
+ 0x023d, 1048413,
+ 0x023e, 1059368,
+ 0x0241, 1048577,
+ 0x0243, 1048381,
+ 0x0244, 1048645,
+ 0x0245, 1048647,
+ 0x0246, 1048577,
+ 0x0376, 1048577,
+ 0x0386, 1048614,
+ 0x038c, 1048640,
+ 0x03cf, 1048584,
+ 0x03f4, 1048516,
+ 0x03f7, 1048577,
+ 0x03f9, 1048569,
+ 0x03fa, 1048577,
+ 0x04c0, 1048591,
+ 0x04c1, 1048577,
+ 0x10c7, 1055840,
+ 0x10cd, 1055840,
+ 0x1e9e, 1040961,
+ 0x1fbc, 1048567,
+ 0x1fcc, 1048567,
+ 0x1fec, 1048569,
+ 0x1ffc, 1048567,
+ 0x2126, 1041059,
+ 0x212a, 1040193,
+ 0x212b, 1040314,
+ 0x2132, 1048604,
+ 0x2183, 1048577,
+ 0x2c60, 1048577,
+ 0x2c62, 1037833,
+ 0x2c63, 1044762,
+ 0x2c64, 1037849,
+ 0x2c6d, 1037796,
+ 0x2c6e, 1037827,
+ 0x2c6f, 1037793,
+ 0x2c70, 1037794,
+ 0x2c72, 1048577,
+ 0x2c75, 1048577,
+ 0x2cf2, 1048577,
+ 0xa77d, 1013244,
+ 0xa77e, 1048577,
+ 0xa78b, 1048577,
+ 0xa78d, 1006296,
+ 0xa7aa, 1006268,
+};
+
+Rune
+tolowerrune(Rune c)
+{
+ Rune *p;
+
+ p = _runebsearch(c, __tolowerr, nelem(__tolowerr)/3, 3);
+ if(p && c >= p[0] && c <= p[1])
+ return c + p[2] - 1048576;
+ p = _runebsearch(c, __tolowerp, nelem(__tolowerp)/3, 3);
+ if(p && c >= p[0] && c <= p[1] && !((c - p[0]) & 1))
+ return c + p[2] - 1048576;
+ p = _runebsearch(c, __tolowers, nelem(__tolowers)/2, 2);
+ if(p && c == p[0])
+ return c + p[1] - 1048576;
+ return c;
+}
+
+static Rune __totitler[] = {
+ 0x0061, 0x007a, 1048544,
+ 0x00e0, 0x00f6, 1048544,
+ 0x00f8, 0x00fe, 1048544,
+ 0x023f, 0x0240, 1059391,
+ 0x0256, 0x0257, 1048371,
+ 0x028a, 0x028b, 1048359,
+ 0x037b, 0x037d, 1048706,
+ 0x03ad, 0x03af, 1048539,
+ 0x03b1, 0x03c1, 1048544,
+ 0x03c3, 0x03cb, 1048544,
+ 0x03cd, 0x03ce, 1048513,
+ 0x0430, 0x044f, 1048544,
+ 0x0450, 0x045f, 1048496,
+ 0x0561, 0x0586, 1048528,
+ 0x1f00, 0x1f07, 1048584,
+ 0x1f10, 0x1f15, 1048584,
+ 0x1f20, 0x1f27, 1048584,
+ 0x1f30, 0x1f37, 1048584,
+ 0x1f40, 0x1f45, 1048584,
+ 0x1f60, 0x1f67, 1048584,
+ 0x1f70, 0x1f71, 1048650,
+ 0x1f72, 0x1f75, 1048662,
+ 0x1f76, 0x1f77, 1048676,
+ 0x1f78, 0x1f79, 1048704,
+ 0x1f7a, 0x1f7b, 1048688,
+ 0x1f7c, 0x1f7d, 1048702,
+ 0x1f80, 0x1f87, 1048584,
+ 0x1f90, 0x1f97, 1048584,
+ 0x1fa0, 0x1fa7, 1048584,
+ 0x1fb0, 0x1fb1, 1048584,
+ 0x1fd0, 0x1fd1, 1048584,
+ 0x1fe0, 0x1fe1, 1048584,
+ 0x2170, 0x217f, 1048560,
+ 0x24d0, 0x24e9, 1048550,
+ 0x2c30, 0x2c5e, 1048528,
+ 0x2d00, 0x2d25, 1041312,
+ 0xff41, 0xff5a, 1048544,
+ 0x10428, 0x1044f, 1048536,
+};
+
+static Rune __totitlep[] = {
+ 0x0101, 0x012f, 1048575,
+ 0x0133, 0x0137, 1048575,
+ 0x013a, 0x0148, 1048575,
+ 0x014b, 0x0177, 1048575,
+ 0x017a, 0x017e, 1048575,
+ 0x0183, 0x0185, 1048575,
+ 0x01a1, 0x01a5, 1048575,
+ 0x01b4, 0x01b6, 1048575,
+ 0x01cc, 0x01dc, 1048575,
+ 0x01df, 0x01ef, 1048575,
+ 0x01f3, 0x01f5, 1048575,
+ 0x01f9, 0x021f, 1048575,
+ 0x0223, 0x0233, 1048575,
+ 0x0247, 0x024f, 1048575,
+ 0x0371, 0x0373, 1048575,
+ 0x03d9, 0x03ef, 1048575,
+ 0x0461, 0x0481, 1048575,
+ 0x048b, 0x04bf, 1048575,
+ 0x04c2, 0x04ce, 1048575,
+ 0x04d1, 0x0527, 1048575,
+ 0x1e01, 0x1e95, 1048575,
+ 0x1ea1, 0x1eff, 1048575,
+ 0x1f51, 0x1f57, 1048584,
+ 0x2c68, 0x2c6c, 1048575,
+ 0x2c81, 0x2ce3, 1048575,
+ 0x2cec, 0x2cee, 1048575,
+ 0xa641, 0xa66d, 1048575,
+ 0xa681, 0xa697, 1048575,
+ 0xa723, 0xa72f, 1048575,
+ 0xa733, 0xa76f, 1048575,
+ 0xa77a, 0xa77c, 1048575,
+ 0xa77f, 0xa787, 1048575,
+ 0xa791, 0xa793, 1048575,
+ 0xa7a1, 0xa7a9, 1048575,
+};
+
+static Rune __totitles[] = {
+ 0x00b5, 1049319,
+ 0x00ff, 1048697,
+ 0x0131, 1048344,
+ 0x017f, 1048276,
+ 0x0180, 1048771,
+ 0x0188, 1048575,
+ 0x018c, 1048575,
+ 0x0192, 1048575,
+ 0x0195, 1048673,
+ 0x0199, 1048575,
+ 0x019a, 1048739,
+ 0x019e, 1048706,
+ 0x01a8, 1048575,
+ 0x01ad, 1048575,
+ 0x01b0, 1048575,
+ 0x01b9, 1048575,
+ 0x01bd, 1048575,
+ 0x01bf, 1048632,
+ 0x01c4, 1048577,
+ 0x01c6, 1048575,
+ 0x01c7, 1048577,
+ 0x01c9, 1048575,
+ 0x01ca, 1048577,
+ 0x01dd, 1048497,
+ 0x01f1, 1048577,
+ 0x023c, 1048575,
+ 0x0242, 1048575,
+ 0x0250, 1059359,
+ 0x0251, 1059356,
+ 0x0252, 1059358,
+ 0x0253, 1048366,
+ 0x0254, 1048370,
+ 0x0259, 1048374,
+ 0x025b, 1048373,
+ 0x0260, 1048371,
+ 0x0263, 1048369,
+ 0x0265, 1090856,
+ 0x0266, 1090884,
+ 0x0268, 1048367,
+ 0x0269, 1048365,
+ 0x026b, 1059319,
+ 0x026f, 1048365,
+ 0x0271, 1059325,
+ 0x0272, 1048363,
+ 0x0275, 1048362,
+ 0x027d, 1059303,
+ 0x0280, 1048358,
+ 0x0283, 1048358,
+ 0x0288, 1048358,
+ 0x0289, 1048507,
+ 0x028c, 1048505,
+ 0x0292, 1048357,
+ 0x0345, 1048660,
+ 0x0377, 1048575,
+ 0x03ac, 1048538,
+ 0x03c2, 1048545,
+ 0x03cc, 1048512,
+ 0x03d0, 1048514,
+ 0x03d1, 1048519,
+ 0x03d5, 1048529,
+ 0x03d6, 1048522,
+ 0x03d7, 1048568,
+ 0x03f0, 1048490,
+ 0x03f1, 1048496,
+ 0x03f2, 1048583,
+ 0x03f5, 1048480,
+ 0x03f8, 1048575,
+ 0x03fb, 1048575,
+ 0x04cf, 1048561,
+ 0x1d79, 1083908,
+ 0x1d7d, 1052390,
+ 0x1e9b, 1048517,
+ 0x1fb3, 1048585,
+ 0x1fbe, 1041371,
+ 0x1fc3, 1048585,
+ 0x1fe5, 1048583,
+ 0x1ff3, 1048585,
+ 0x214e, 1048548,
+ 0x2184, 1048575,
+ 0x2c61, 1048575,
+ 0x2c65, 1037781,
+ 0x2c66, 1037784,
+ 0x2c73, 1048575,
+ 0x2c76, 1048575,
+ 0x2cf3, 1048575,
+ 0x2d27, 1041312,
+ 0x2d2d, 1041312,
+ 0xa78c, 1048575,
+};
+
+Rune
+totitlerune(Rune c)
+{
+ Rune *p;
+
+ p = _runebsearch(c, __totitler, nelem(__totitler)/3, 3);
+ if(p && c >= p[0] && c <= p[1])
+ return c + p[2] - 1048576;
+ p = _runebsearch(c, __totitlep, nelem(__totitlep)/3, 3);
+ if(p && c >= p[0] && c <= p[1] && !((c - p[0]) & 1))
+ return c + p[2] - 1048576;
+ p = _runebsearch(c, __totitles, nelem(__totitles)/2, 2);
+ if(p && c == p[0])
+ return c + p[1] - 1048576;
+ return c;
+}
+
--- /dev/null
+++ b/lib9/runevseprint.c
@@ -1,0 +1,24 @@
+#include "lib9.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 f.to;
+}
+
--- /dev/null
+++ b/lib9/sbrk-posix.c
@@ -1,0 +1,48 @@
+#ifdef __APPLE_CC__ /* look for a better way */
+#include "lib9.h"
+#undef _POSIX_C_SOURCE
+#undef getwd
+
+#include <unistd.h>
+#include <pthread.h>
+#include <time.h>
+#include <termios.h>
+#include <signal.h>
+#include <pwd.h>
+#include <sys/resource.h>
+#include <sys/time.h>
+
+#include <sys/socket.h>
+#include <sched.h>
+#include <errno.h>
+#include <sys/ucontext.h>
+
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include <mach/mach_init.h>
+
+#include <mach/task.h>
+
+#include <mach/vm_map.h>
+
+
+__typeof__(sbrk(0))
+sbrk(int size)
+{
+ void *brk;
+ kern_return_t err;
+
+ err = vm_allocate( (vm_map_t) mach_task_self(),
+ (vm_address_t *)&brk,
+ size,
+ VM_FLAGS_ANYWHERE);
+ if (err != KERN_SUCCESS)
+ brk = (void*)-1;
+
+ return brk;
+}
+#else
+/* dummy function for everyone else, in case its ar complains about empty files */
+void __fakesbrk(void){}
+#endif
--- /dev/null
+++ b/lib9/seek.c
@@ -1,0 +1,9 @@
+#include "lib9.h"
+#include <sys/types.h>
+#include <fcntl.h>
+
+vlong
+seek(int fd, vlong where, int from)
+{
+ return lseek(fd, where, from);
+}
--- /dev/null
+++ b/lib9/seprint.c
@@ -1,0 +1,26 @@
+/*
+ * 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 "lib9.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;
+}
--- /dev/null
+++ b/lib9/setbinmode-Nt.c
@@ -1,0 +1,9 @@
+#include "lib9.h"
+
+void
+setbinmode(void)
+{
+ _setmode(0, _O_BINARY);
+ _setmode(1, _O_BINARY);
+ _setmode(2, _O_BINARY);
+}
--- /dev/null
+++ b/lib9/setfcr-Linux-386.S
@@ -1,0 +1,34 @@
+
+#define FN(x) .type x,@function; .global x; x
+#define ENT subl $16, %esp
+#define RET addl $16, %esp; ret
+
+ .file "setfcr-Linux-386.S"
+FN(setfcr):
+ ENT
+ xorb $0x3f, %al
+ movl %eax, (%esp)
+ fwait
+ fldcw (%esp)
+ RET
+
+FN(getfcr):
+ ENT
+ fwait
+ fstcw (%esp)
+ movw (%esp), %ax
+ andl $0xffff, %eax
+ xorb $0x3f, %al
+ RET
+
+FN(getfsr):
+ ENT
+ fwait
+ fstsw (%esp)
+ movw (%esp), %ax
+ andl $0xffff, %eax
+ RET
+
+FN(setfsr):
+ fclex
+ ret
--- /dev/null
+++ b/lib9/setfcr-Linux-arm.S
@@ -1,0 +1,33 @@
+#define FN(x) .type x,%function; .global x; x
+#define ENT
+#define RET bx lr
+#ifdef USEVFP
+ .fpu vfp
+#define VMSR(f,r) vmsr f,r
+#define VMRS(r,f) vmrs r,f
+#else
+ .fpu softvfp
+#define VMSR(f,r)
+#define VMRS(r,f)
+#endif
+
+ .file "setfcr-Linux-arm.S"
+FN(setfcr):
+ ENT
+ VMSR(fpscr,r0)
+ RET
+
+FN(getfcr):
+ ENT
+ VMRS(r0, fpscr)
+ RET
+
+FN(getfsr):
+ ENT
+ VMRS(r0, fpscr)
+ RET
+
+FN(setfsr):
+ ENT
+ VMSR(fpscr, r0)
+ RET
--- /dev/null
+++ b/lib9/setfcr-Linux-power.S
@@ -1,0 +1,30 @@
+
+#define FN(x) .type x,@function; .global x; x
+
+FN(getfcr):
+ mffs %f0
+ stfdu %f0,-16(%r1)
+ lw %r3,-12(%r1)
+ blr
+
+FN(getfsr):
+ mffs %f0
+ stfdu %f0,-16(%r1)
+ lw %r3,-12(%r1)
+ blr
+
+FN(setfsr):
+ sync
+ stw %r3,-12(%r1)
+ lfd %f0,-16(%r1)
+ mtfsf 0xff, %f0
+ isync
+ blr
+
+FN(setfcr):
+ sync
+ stw %r3,-12(%r1)
+ lfd %f0,-16(%r1)
+ mtfsf 0xff, %f0
+ isync
+ blr
--- /dev/null
+++ b/lib9/setfcr-MacOSX-386.c
@@ -1,0 +1,56 @@
+/*
+ * Linux 386 fpu support
+ * Mimic Plan9 floating point support
+ */
+
+#include "lib9.h"
+
+void
+setfcr(ulong fcr)
+{
+ __asm__( "xorb $0x3f, %%al\n\t"
+ "pushw %%ax\n\t"
+ "fwait\n\t"
+ "fldcw (%%esp)\n\t"
+ "popw %%ax\n\t"
+ : /* no output */
+ : "al" (fcr)
+ );
+}
+
+ulong
+getfcr(void)
+{
+ ulong fcr = 0;
+
+ __asm__( "pushl %%eax\n\t"
+ "fwait\n\t"
+ "fstcw (%%esp)\n\t"
+ "popl %%eax\n\t"
+ "xorb $0x3f, %%al\n\t"
+ : "=a" (fcr)
+ : "eax" (fcr)
+ );
+ return fcr;
+}
+
+ulong
+getfsr(void)
+{
+ ulong fsr = -1;
+
+ __asm__( "fwait\n\t"
+ "fstsw (%%eax)\n\t"
+ "movl (%%eax), %%eax\n\t"
+ "andl $0xffff, %%eax\n\t"
+ : "=a" (fsr)
+ : "eax" (&fsr)
+ );
+ return fsr;
+}
+
+void
+setfsr(ulong fsr)
+{
+ __asm__("fclex\n\t");
+}
--- /dev/null
+++ b/lib9/setfcr-MacOSX-power.c
@@ -1,0 +1,37 @@
+/*
+ * MacOSX/Darwin ppc fpu support
+ * Mimic Plan9 floating point support
+ */
+
+#include "lib9.h"
+#include <architecture/ppc/fp_regs.h>
+
+ulong
+getfcr(void)
+{
+ ppc_fp_scr_t fpscr = get_fp_scr();
+ return ((ulong*)&fpscr)[1];
+}
+
+ulong
+getfsr(void)
+{
+ ppc_fp_scr_t fpscr = get_fp_scr();
+ return ((ulong*)&fpscr)[1];
+}
+
+void
+setfsr(ulong fsr)
+{
+ ppc_fp_scr_t fpscr = get_fp_scr();
+ (((ulong*)&fpscr)[1]) = fsr;
+ set_fp_scr(fpscr);
+}
+
+void
+setfcr(ulong fcr)
+{
+ ppc_fp_scr_t fpscr = get_fp_scr();
+ (((ulong*)&fpscr)[1]) = fcr;
+ set_fp_scr(fpscr);
+}
--- /dev/null
+++ b/lib9/setfcr-NetBSD-386.S
@@ -1,0 +1,34 @@
+
+#define FN(x) .type x,@function; .global x; x
+#define ENT subl $16, %esp
+#define RET addl $16, %esp; ret
+
+ .file "setfcr-Linux-386.S"
+FN(setfcr):
+ ENT
+ xorb $0x3f, %al
+ movl %eax, (%esp)
+ fwait
+ fldcw (%esp)
+ RET
+
+FN(getfcr):
+ ENT
+ fwait
+ fstcw (%esp)
+ movw (%esp), %ax
+ andl $0xffff, %eax
+ xorb $0x3f, %al
+ RET
+
+FN(getfsr):
+ ENT
+ fwait
+ fstsw (%esp)
+ movw (%esp), %ax
+ andl $0xffff, %eax
+ RET
+
+FN(setfsr):
+ fclex
+ ret
--- /dev/null
+++ b/lib9/setfcr-Solaris-sparc.c
@@ -1,0 +1,42 @@
+/* This code is a little awkward. If somebody who understands Solaris
+ better would tell me an idiomatic way to invoke equivalent
+ behavior, I'd be grateful. ehg@bell-labs.com */
+
+#include "lib9.h"
+
+ulong
+getfcr(void)
+{
+ ulong v;
+
+ asm(" st %fsr, [%fp-8]");
+ return v;
+}
+
+void
+setfcr(ulong v)
+{
+ ulong vv;
+
+ vv = (getfcr() & ~FPFCR) | (v & FPFCR);
+ asm(" ld [%fp-4], %fsr");
+}
+
+ulong
+getfsr(void)
+{
+ ulong v;
+
+ asm(" st %fsr, [%fp-8]");
+ return v;
+}
+
+void
+setfsr(ulong v)
+{
+ ulong vv;
+
+ vv = (getfsr() & ~FPFSR) | (v & FPFSR);
+ asm(" ld [%fp-4], %fsr");
+}
+
--- /dev/null
+++ b/lib9/smprint.c
@@ -1,0 +1,26 @@
+/*
+ * 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 "lib9.h"
+
+char*
+smprint(char *fmt, ...)
+{
+ va_list args;
+ char *p;
+
+ va_start(args, fmt);
+ p = vsmprint(fmt, args);
+ va_end(args);
+ return p;
+}
--- /dev/null
+++ b/lib9/snprint.c
@@ -1,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 "lib9.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;
+}
+
--- /dev/null
+++ b/lib9/sprint.c
@@ -1,0 +1,35 @@
+/*
+ * 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 "lib9.h"
+
+int
+sprint(char *buf, char *fmt, ...)
+{
+ int n;
+ uint len;
+ va_list args;
+
+ len = 1<<30; /* big number, but sprint is deprecated anyway */
+ /*
+ * the stack might be near the top of memory, so
+ * we must be sure not to overflow a 32-bit pointer.
+ */
+ if((uintptr)buf+len < (uintptr)buf)
+ len = -(uint)buf-1;
+
+ va_start(args, fmt);
+ n = vsnprint(buf, len, fmt, args);
+ va_end(args);
+ return n;
+}
--- /dev/null
+++ b/lib9/strdup.c
@@ -1,0 +1,12 @@
+#include "lib9.h"
+
+char*
+strdup(const char *s)
+{
+ char *os;
+
+ os = malloc(strlen(s) + 1);
+ if(os == 0)
+ return 0;
+ return strcpy(os, s);
+}
--- /dev/null
+++ b/lib9/strecpy.c
@@ -1,0 +1,16 @@
+#include "lib9.h"
+
+char*
+strecpy(char *to, char *e, char *from)
+{
+ if(to >= e)
+ return to;
+ to = memccpy(to, from, '\0', e - to);
+ if(to == nil){
+ to = e - 1;
+ *to = '\0';
+ }else{
+ to--;
+ }
+ return to;
+}
--- /dev/null
+++ b/lib9/strtoll.c
@@ -1,0 +1,81 @@
+#include "lib9.h"
+
+vlong
+strtoll(const char *nptr, char **endptr, int base)
+{
+ const char *p;
+ vlong n;
+ int c, v, neg, ndig;
+
+ p = nptr;
+ neg = 0;
+ n = 0;
+ ndig = 0;
+
+ /*
+ * White space
+ */
+ for(;;p++){
+ switch(*p){
+ case ' ':
+ case '\t':
+ case '\n':
+ case '\f':
+ case '\r':
+ case '\v':
+ continue;
+ }
+ break;
+ }
+
+ /*
+ * Sign
+ */
+ if(*p=='-' || *p=='+')
+ if(*p++ == '-')
+ neg = 1;
+
+ /*
+ * Base
+ */
+ if(base==0){
+ if(*p != '0')
+ base = 10;
+ else{
+ base = 8;
+ if(p[1]=='x' || p[1]=='X'){
+ p += 2;
+ base = 16;
+ }
+ }
+ }else if(base==16 && *p=='0'){
+ if(p[1]=='x' || p[1]=='X')
+ p += 2;
+ }else if(base<0 || 36<base)
+ goto Return;
+
+ /*
+ * Non-empty sequence of digits
+ */
+ for(;; p++,ndig++){
+ c = *p;
+ v = base;
+ if('0'<=c && c<='9')
+ v = c - '0';
+ else if('a'<=c && c<='z')
+ v = c - 'a' + 10;
+ else if('A'<=c && c<='Z')
+ v = c - 'A' + 10;
+ if(v >= base)
+ break;
+ n = n*base + v;
+ }
+ Return:
+ if(ndig == 0)
+ p = nptr;
+ if(endptr)
+ *endptr = (char*) p;
+ if(neg)
+ return -n;
+ return n;
+}
--- /dev/null
+++ b/lib9/strtoull.c
@@ -1,0 +1,96 @@
+#include "lib9.h"
+
+#define UVLONG_MAX ((uvlong)1<<63)
+
+uvlong
+strtoull(const char *nptr, char **endptr, int base)
+{
+ const char *p;
+ uvlong n, nn, m;
+ int c, ovfl, v, neg, ndig;
+
+ p = nptr;
+ neg = 0;
+ n = 0;
+ ndig = 0;
+ ovfl = 0;
+
+ /*
+ * White space
+ */
+ for(;; p++) {
+ switch(*p) {
+ case ' ':
+ case '\t':
+ case '\n':
+ case '\f':
+ case '\r':
+ case '\v':
+ continue;
+ }
+ break;
+ }
+
+ /*
+ * Sign
+ */
+ if(*p == '-' || *p == '+')
+ if(*p++ == '-')
+ neg = 1;
+
+ /*
+ * Base
+ */
+ if(base == 0) {
+ base = 10;
+ if(*p == '0') {
+ base = 8;
+ if(p[1] == 'x' || p[1] == 'X'){
+ p += 2;
+ base = 16;
+ }
+ }
+ } else
+ if(base == 16 && *p == '0') {
+ if(p[1] == 'x' || p[1] == 'X')
+ p += 2;
+ } else
+ if(base < 0 || 36 < base)
+ goto Return;
+
+ /*
+ * Non-empty sequence of digits
+ */
+ m = UVLONG_MAX/base;
+ for(;; p++,ndig++) {
+ c = *p;
+ v = base;
+ if('0' <= c && c <= '9')
+ v = c - '0';
+ else
+ if('a' <= c && c <= 'z')
+ v = c - 'a' + 10;
+ else
+ if('A' <= c && c <= 'Z')
+ v = c - 'A' + 10;
+ if(v >= base)
+ break;
+ if(n > m)
+ ovfl = 1;
+ nn = n*base + v;
+ if(nn < n)
+ ovfl = 1;
+ n = nn;
+ }
+
+Return:
+ if(ndig == 0)
+ p = nptr;
+ if(endptr)
+ *endptr = (char*)p;
+ if(ovfl)
+ return UVLONG_MAX;
+ if(neg)
+ return -n;
+ return n;
+}
--- /dev/null
+++ b/lib9/sysfatal.c
@@ -1,0 +1,28 @@
+#include "lib9.h"
+
+
+
+static void
+_sysfatalimpl(char *fmt, va_list arg)
+{
+ char buf[1024];
+
+ vseprint(buf, buf+sizeof(buf), fmt, arg);
+ if(argv0)
+ fprint(2, "%s: %s\n", argv0, buf);
+ else
+ fprint(2, "%s\n", buf);
+ exits(buf);
+}
+
+void (*_sysfatal)(char *fmt, va_list arg) = _sysfatalimpl;
+
+void
+sysfatal(char *fmt, ...)
+{
+ va_list arg;
+
+ va_start(arg, fmt);
+ (*_sysfatal)(fmt, arg);
+ va_end(arg);
+}
--- /dev/null
+++ b/lib9/tokenize.c
@@ -1,0 +1,106 @@
+#include "lib9.h"
+
+static char qsep[] = " \t\r\n";
+
+static char*
+qtoken(char *s, char *sep)
+{
+ int quoting;
+ char *t;
+
+ quoting = 0;
+ t = s; /* s is output string, t is input string */
+ while(*t!='\0' && (quoting || utfrune(sep, *t)==nil)){
+ if(*t != '\''){
+ *s++ = *t++;
+ continue;
+ }
+ /* *t is a quote */
+ if(!quoting){
+ quoting = 1;
+ t++;
+ continue;
+ }
+ /* quoting and we're on a quote */
+ if(t[1] != '\''){
+ /* end of quoted section; absorb closing quote */
+ t++;
+ quoting = 0;
+ continue;
+ }
+ /* doubled quote; fold one quote into two */
+ t++;
+ *s++ = *t++;
+ }
+ if(*s != '\0'){
+ *s = '\0';
+ if(t == s)
+ t++;
+ }
+ return t;
+}
+
+static char*
+etoken(char *t, char *sep)
+{
+ int quoting;
+
+ /* move to end of next token */
+ quoting = 0;
+ while(*t!='\0' && (quoting || utfrune(sep, *t)==nil)){
+ if(*t != '\''){
+ t++;
+ continue;
+ }
+ /* *t is a quote */
+ if(!quoting){
+ quoting = 1;
+ t++;
+ continue;
+ }
+ /* quoting and we're on a quote */
+ if(t[1] != '\''){
+ /* end of quoted section; absorb closing quote */
+ t++;
+ quoting = 0;
+ continue;
+ }
+ /* doubled quote; fold one quote into two */
+ t += 2;
+ }
+ return t;
+}
+
+int
+gettokens(char *s, char **args, int maxargs, char *sep)
+{
+ int nargs;
+
+ for(nargs=0; nargs<maxargs; nargs++){
+ while(*s!='\0' && utfrune(sep, *s)!=nil)
+ *s++ = '\0';
+ if(*s == '\0')
+ break;
+ args[nargs] = s;
+ s = etoken(s, sep);
+ }
+
+ return nargs;
+}
+
+int
+tokenize(char *s, char **args, int maxargs)
+{
+ int nargs;
+
+ for(nargs=0; nargs<maxargs; nargs++){
+ while(*s!='\0' && utfrune(qsep, *s)!=nil)
+ s++;
+ if(*s == '\0')
+ break;
+ args[nargs] = s;
+ s = qtoken(s, qsep);
+ }
+
+ return nargs;
+}
--- /dev/null
+++ b/lib9/u16.c
@@ -1,0 +1,52 @@
+#include <lib9.h>
+static char t16e[] = "0123456789ABCDEF";
+
+int
+dec16(uchar *out, int lim, char *in, int n)
+{
+ int c, w = 0, i = 0;
+ uchar *start = out;
+ uchar *eout = out + lim;
+
+ while(n-- > 0){
+ c = *in++;
+ if('0' <= c && c <= '9')
+ c = c - '0';
+ else if('a' <= c && c <= 'z')
+ c = c - 'a' + 10;
+ else if('A' <= c && c <= 'Z')
+ c = c - 'A' + 10;
+ else
+ continue;
+ w = (w<<4) + c;
+ i++;
+ if(i == 2){
+ if(out + 1 > eout)
+ goto exhausted;
+ *out++ = w;
+ w = 0;
+ i = 0;
+ }
+ }
+exhausted:
+ return out - start;
+}
+
+int
+enc16(char *out, int lim, uchar *in, int n)
+{
+ uint c;
+ char *eout = out + lim;
+ char *start = out;
+
+ while(n-- > 0){
+ c = *in++;
+ if(out + 2 >= eout)
+ goto exhausted;
+ *out++ = t16e[c>>4];
+ *out++ = t16e[c&0xf];
+ }
+exhausted:
+ *out = 0;
+ return out - start;
+}
--- /dev/null
+++ b/lib9/u32.c
@@ -1,0 +1,109 @@
+#include <lib9.h>
+
+int
+dec32(uchar *dest, int ndest, char *src, int nsrc)
+{
+ char *s, *tab;
+ uchar *start;
+ int i, u[8];
+
+ if(ndest+1 < (5*nsrc+7)/8)
+ return -1;
+ start = dest;
+ tab = "23456789abcdefghijkmnpqrstuvwxyz";
+ while(nsrc>=8){
+ for(i=0; i<8; i++){
+ s = strchr(tab,(int)src[i]);
+ u[i] = s ? s-tab : 0;
+ }
+ *dest++ = (u[0]<<3) | (0x7 & (u[1]>>2));
+ *dest++ = ((0x3 & u[1])<<6) | (u[2]<<1) | (0x1 & (u[3]>>4));
+ *dest++ = ((0xf & u[3])<<4) | (0xf & (u[4]>>1));
+ *dest++ = ((0x1 & u[4])<<7) | (u[5]<<2) | (0x3 & (u[6]>>3));
+ *dest++ = ((0x7 & u[6])<<5) | u[7];
+ src += 8;
+ nsrc -= 8;
+ }
+ if(nsrc > 0){
+ if(nsrc == 1 || nsrc == 3 || nsrc == 6)
+ return -1;
+ for(i=0; i<nsrc; i++){
+ s = strchr(tab,(int)src[i]);
+ u[i] = s ? s-tab : 0;
+ }
+ *dest++ = (u[0]<<3) | (0x7 & (u[1]>>2));
+ if(nsrc == 2)
+ goto out;
+ *dest++ = ((0x3 & u[1])<<6) | (u[2]<<1) | (0x1 & (u[3]>>4));
+ if(nsrc == 4)
+ goto out;
+ *dest++ = ((0xf & u[3])<<4) | (0xf & (u[4]>>1));
+ if(nsrc == 5)
+ goto out;
+ *dest++ = ((0x1 & u[4])<<7) | (u[5]<<2) | (0x3 & (u[6]>>3));
+ }
+out:
+ return dest-start;
+}
+
+int
+enc32(char *dest, int ndest, uchar *src, int nsrc)
+{
+ char *tab, *start;
+ int j;
+
+ if(ndest <= (8*nsrc+4)/5 )
+ return -1;
+ start = dest;
+ tab = "23456789abcdefghijkmnpqrstuvwxyz";
+ while(nsrc>=5){
+ j = (0x1f & (src[0]>>3));
+ *dest++ = tab[j];
+ j = (0x1c & (src[0]<<2)) | (0x03 & (src[1]>>6));
+ *dest++ = tab[j];
+ j = (0x1f & (src[1]>>1));
+ *dest++ = tab[j];
+ j = (0x10 & (src[1]<<4)) | (0x0f & (src[2]>>4));
+ *dest++ = tab[j];
+ j = (0x1e & (src[2]<<1)) | (0x01 & (src[3]>>7));
+ *dest++ = tab[j];
+ j = (0x1f & (src[3]>>2));
+ *dest++ = tab[j];
+ j = (0x18 & (src[3]<<3)) | (0x07 & (src[4]>>5));
+ *dest++ = tab[j];
+ j = (0x1f & (src[4]));
+ *dest++ = tab[j];
+ src += 5;
+ nsrc -= 5;
+ }
+ if(nsrc){
+ j = (0x1f & (src[0]>>3));
+ *dest++ = tab[j];
+ j = (0x1c & (src[0]<<2));
+ if(nsrc == 1)
+ goto out;
+ j |= (0x03 & (src[1]>>6));
+ *dest++ = tab[j];
+ j = (0x1f & (src[1]>>1));
+ if(nsrc == 2)
+ goto out;
+ *dest++ = tab[j];
+ j = (0x10 & (src[1]<<4));
+ if(nsrc == 3)
+ goto out;
+ j |= (0x0f & (src[2]>>4));
+ *dest++ = tab[j];
+ j = (0x1e & (src[2]<<1));
+ if(nsrc == 4)
+ goto out;
+ j |= (0x01 & (src[3]>>7));
+ *dest++ = tab[j];
+ j = (0x1f & (src[3]>>2));
+ *dest++ = tab[j];
+ j = (0x18 & (src[3]<<3));
+out:
+ *dest++ = tab[j];
+ }
+ *dest = 0;
+ return dest-start;
+}
--- /dev/null
+++ b/lib9/u64.c
@@ -1,0 +1,126 @@
+#include <lib9.h>
+
+enum {
+ INVAL= 255
+};
+
+static uchar t64d[256] = {
+ INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,
+ INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,
+ INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL, 62,INVAL,INVAL,INVAL, 63,
+ 52, 53, 54, 55, 56, 57, 58, 59, 60, 61,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,
+ INVAL, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
+ 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25,INVAL,INVAL,INVAL,INVAL,INVAL,
+ INVAL, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
+ 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51,INVAL,INVAL,INVAL,INVAL,INVAL,
+ INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,
+ INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,
+ INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,
+ INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,
+ INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,
+ INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,
+ INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,
+ INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL
+};
+static char t64e[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+
+int
+dec64(uchar *out, int lim, char *in, int n)
+{
+ ulong b24;
+ uchar *start = out;
+ uchar *e = out + lim;
+ int i, c;
+
+ b24 = 0;
+ i = 0;
+ while(n-- > 0){
+
+ c = t64d[*(uchar*)in++];
+ if(c == INVAL)
+ continue;
+ switch(i){
+ case 0:
+ b24 = c<<18;
+ break;
+ case 1:
+ b24 |= c<<12;
+ break;
+ case 2:
+ b24 |= c<<6;
+ break;
+ case 3:
+ if(out + 3 > e)
+ goto exhausted;
+
+ b24 |= c;
+ *out++ = b24>>16;
+ *out++ = b24>>8;
+ *out++ = b24;
+ i = -1;
+ break;
+ }
+ i++;
+ }
+ switch(i){
+ case 2:
+ if(out + 1 > e)
+ goto exhausted;
+ *out++ = b24>>16;
+ break;
+ case 3:
+ if(out + 2 > e)
+ goto exhausted;
+ *out++ = b24>>16;
+ *out++ = b24>>8;
+ break;
+ }
+exhausted:
+ return out - start;
+}
+
+int
+enc64(char *out, int lim, uchar *in, int n)
+{
+ int i;
+ ulong b24;
+ char *start = out;
+ char *e = out + lim;
+
+ for(i = n/3; i > 0; i--){
+ b24 = (*in++)<<16;
+ b24 |= (*in++)<<8;
+ b24 |= *in++;
+ if(out + 4 >= e)
+ goto exhausted;
+ *out++ = t64e[(b24>>18)];
+ *out++ = t64e[(b24>>12)&0x3f];
+ *out++ = t64e[(b24>>6)&0x3f];
+ *out++ = t64e[(b24)&0x3f];
+ }
+
+ switch(n%3){
+ case 2:
+ b24 = (*in++)<<16;
+ b24 |= (*in)<<8;
+ if(out + 4 >= e)
+ goto exhausted;
+ *out++ = t64e[(b24>>18)];
+ *out++ = t64e[(b24>>12)&0x3f];
+ *out++ = t64e[(b24>>6)&0x3f];
+ *out++ = '=';
+ break;
+ case 1:
+ b24 = (*in)<<16;
+ if(out + 4 >= e)
+ goto exhausted;
+ *out++ = t64e[(b24>>18)];
+ *out++ = t64e[(b24>>12)&0x3f];
+ *out++ = '=';
+ *out++ = '=';
+ break;
+ }
+exhausted:
+ *out = 0;
+ return out - start;
+}
--- /dev/null
+++ b/lib9/utfecpy.c
@@ -1,0 +1,20 @@
+#include "lib9.h"
+
+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;
+ while(end>to && (*--end&0xC0)==0x80)
+ ;
+ *end = '\0';
+ }else{
+ end--;
+ }
+ return end;
+}
--- /dev/null
+++ b/lib9/utflen.c
@@ -1,0 +1,21 @@
+#include "lib9.h"
+
+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++;
+ }
+}
--- /dev/null
+++ b/lib9/utfnlen.c
@@ -1,0 +1,25 @@
+#include "lib9.h"
+
+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;
+}
--- /dev/null
+++ b/lib9/utfrrune.c
@@ -1,0 +1,29 @@
+#include "lib9.h"
+
+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;
+ }
+}
--- /dev/null
+++ b/lib9/utfrune.c
@@ -1,0 +1,28 @@
+#include "lib9.h"
+
+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;
+ }
+}
--- /dev/null
+++ b/lib9/vfprint.c
@@ -1,0 +1,47 @@
+/*
+ * 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 "lib9.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;
+}
+
+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;
+}
--- /dev/null
+++ b/lib9/vseprint.c
@@ -1,0 +1,37 @@
+/*
+ * 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 "lib9.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 = nil;
+ f.farg = nil;
+ f.nfmt = 0;
+ va_copy(f.args, args);
+ dofmt(&f, fmt);
+ va_end(f.args);
+ *(char*)f.to = '\0';
+ return f.to;
+}
+
--- /dev/null
+++ b/lib9/vsmprint.c
@@ -1,0 +1,79 @@
+/*
+ * 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 "lib9.h"
+#include "fmtdef.h"
+
+static int
+fmtStrFlush(Fmt *f)
+{
+ char *s;
+ int n;
+
+ if(f->start == nil)
+ return 0;
+ n = (int)f->farg;
+ n += 256;
+ f->farg = (void*)n;
+ s = f->start;
+ f->start = realloc(s, n);
+ if(f->start == nil){
+ free(s);
+ f->to = nil;
+ f->stop = nil;
+ return 0;
+ }
+ f->to = (char*)f->start + ((char*)f->to - s);
+ f->stop = (char*)f->start + n - 1;
+ return 1;
+}
+
+int
+fmtstrinit(Fmt *f)
+{
+ int n;
+
+ memset(f, 0, sizeof(*f));
+ 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);
+ f.start = nil;
+ return nil;
+ }
+ return fmtstrflush(&f);
+}
--- /dev/null
+++ b/lib9/vsnprint.c
@@ -1,0 +1,36 @@
+/*
+ * 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 "lib9.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 = nil;
+ 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;
+}
--- /dev/null
+++ b/libbio/NOTICE
@@ -1,0 +1,29 @@
+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-2007 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.
+
--- /dev/null
+++ b/libbio/bbuffered.c
@@ -1,0 +1,20 @@
+#include "lib9.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;
+}
--- /dev/null
+++ b/libbio/bfildes.c
@@ -1,0 +1,9 @@
+#include "lib9.h"
+#include <bio.h>
+
+int
+Bfildes(Biobuf *bp)
+{
+
+ return bp->fid;
+}
--- /dev/null
+++ b/libbio/bflush.c
@@ -1,0 +1,33 @@
+#include "lib9.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;
+}
--- /dev/null
+++ b/libbio/bgetc.c
@@ -1,0 +1,53 @@
+#include "lib9.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;
+}
--- /dev/null
+++ b/libbio/bgetd.c
@@ -1,0 +1,36 @@
+#include "lib9.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 = charstod(Bgetdf, &b);
+ if(b.eof)
+ return -1;
+ Bungetc(bp);
+ *dp = d;
+ return 1;
+}
--- /dev/null
+++ b/libbio/bgetrune.c
@@ -1,0 +1,52 @@
+#include "lib9.h"
+#include <bio.h>
+
+long
+Bgetrune(Biobuf *bp)
+{
+ int c, i;
+ Rune rune;
+ char str[UTFmax];
+
+ c = Bgetc(bp);
+ if(c < Runeself) { /* one char */
+ bp->runesize = 1;
+ return c;
+ }
+ str[0] = c;
+ bp->runesize = 0;
+
+ for(i=1;;) {
+ c = Bgetc(bp);
+ if(c < 0)
+ return c;
+ if (i >= sizeof str)
+ return Runeerror;
+ str[i++] = c;
+
+ if(fullrune(str, i)) {
+ /* utf is long enough to be a rune, but could be bad. */
+ bp->runesize = chartorune(&rune, str);
+ if (rune == Runeerror)
+ bp->runesize = 0; /* push back nothing */
+ else
+ /* push back bytes unconsumed by chartorune */
+ for(; i > bp->runesize; i--)
+ Bungetc(bp);
+ 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;
+}
--- /dev/null
+++ b/libbio/binit.c
@@ -1,0 +1,144 @@
+#include "lib9.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<nelem(wbufs); i++) {
+ bp = wbufs[i];
+ if(bp != 0) {
+ wbufs[i] = 0;
+ Bflush(bp);
+ }
+ }
+}
+
+static
+void
+deinstall(Biobuf *bp)
+{
+ int i;
+
+ for(i=0; i<nelem(wbufs); i++)
+ if(wbufs[i] == bp)
+ wbufs[i] = 0;
+}
+
+static
+void
+install(Biobuf *bp)
+{
+ int i;
+
+ deinstall(bp);
+ for(i=0; i<nelem(wbufs); i++)
+ if(wbufs[i] == 0) {
+ wbufs[i] = bp;
+ break;
+ }
+ if(atexitflag == 0) {
+ atexitflag = 1;
+ atexit(batexit);
+ }
+}
+
+int
+Binits(Biobuf *bp, int f, int mode, uchar *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*
+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);
+ break;
+
+ case OWRITE:
+ f = create(name, mode, 0666);
+ break;
+ }
+ if(f < 0)
+ return 0;
+ bp = malloc(sizeof(Biobuf));
+ if(bp == nil)
+ return 0;
+ Binits(bp, f, mode, bp->b, sizeof(bp->b));
+ bp->flag = Bmagic;
+ return bp;
+}
+
+int
+Bterm(Biobuf *bp)
+{
+ int r;
+
+ deinstall(bp);
+ r = Bflush(bp);
+ if(bp->flag == Bmagic) {
+ bp->flag = 0;
+ close(bp->fid);
+ bp->fid = -1; /* prevent accidents */
+ free(bp);
+ }
+ /* otherwise opened with Binit(s) */
+ return r;
+}
--- /dev/null
+++ b/libbio/boffset.c
@@ -1,0 +1,25 @@
+#include "lib9.h"
+#include <bio.h>
+
+vlong
+Boffset(Biobuf *bp)
+{
+ vlong 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;
+}
--- /dev/null
+++ b/libbio/bprint.c
@@ -1,0 +1,14 @@
+#include "lib9.h"
+#include <bio.h>
+
+int
+Bprint(Biobuf *bp, char *fmt, ...)
+{
+ va_list arg;
+ int n;
+
+ va_start(arg, fmt);
+ n = Bvprint(bp, fmt, arg);
+ va_end(arg);
+ return n;
+}
--- /dev/null
+++ b/libbio/bputc.c
@@ -1,0 +1,20 @@
+#include "lib9.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;
+}
--- /dev/null
+++ b/libbio/bputrune.c
@@ -1,0 +1,22 @@
+#include "lib9.h"
+#include <bio.h>
+
+int
+Bputrune(Biobuf *bp, long c)
+{
+ Rune rune;
+ char str[UTFmax];
+ 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;
+}
--- /dev/null
+++ b/libbio/brdline.c
@@ -1,0 +1,94 @@
+#include "lib9.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 = (uchar*)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;
+}
--- /dev/null
+++ b/libbio/brdstr.c
@@ -1,0 +1,111 @@
+#include "lib9.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 = (uchar*)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;
+ }
+}
--- /dev/null
+++ b/libbio/bread.c
@@ -1,0 +1,47 @@
+#include "lib9.h"
+#include <bio.h>
+
+long
+Bread(Biobuf *bp, void *ap, long count)
+{
+ long c;
+ uchar *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;
+ if(count == c && bp->state == Binactive)
+ return -1;
+ return count-c;
+}
--- /dev/null
+++ b/libbio/bseek.c
@@ -1,0 +1,57 @@
+#include "lib9.h"
+#include <bio.h>
+
+vlong
+Bseek(Biobuf *bp, vlong offset, int base)
+{
+ vlong n, d;
+
+ 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) {
+ /*
+ * if d is too large for an int, icount may wrap,
+ * so we need to ensure that icount hasn't wrapped
+ * and points within the buffer's valid data.
+ */
+ d = n - Boffset(bp);
+ bp->icount += d;
+ if(d <= bp->bsize && bp->icount <= 0 &&
+ bp->ebuf - bp->gbuf >= -bp->icount)
+ return n;
+ }
+
+ /*
+ * reset the buffer
+ */
+ n = seek(bp->fid, n, base);
+ bp->icount = 0;
+ bp->gbuf = bp->ebuf;
+ break;
+
+ case Bwactive:
+ Bflush(bp);
+ n = seek(bp->fid, offset, base);
+ break;
+ }
+ bp->offset = n;
+ return n;
+}
--- /dev/null
+++ b/libbio/bvprint.c
@@ -1,0 +1,43 @@
+#include "lib9.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;
+#ifdef va_copy
+ va_copy(f.args, arg);
+#else
+ f.args = arg;
+#endif
+ n = dofmt(&f, fmt);
+#ifdef va_copy
+ va_end(f.args);
+#endif
+ bp->ocount = (char*)f.to - (char*)f.stop;
+ return n;
+}
--- /dev/null
+++ b/libbio/bwrite.c
@@ -1,0 +1,42 @@
+#include "lib9.h"
+#include <bio.h>
+
+long
+Bwrite(Biobuf *bp, void *ap, long count)
+{
+ long c;
+ uchar *p;
+ int i, n, oc;
+ char errbuf[ERRMAX];
+
+ 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) {
+ errstr(errbuf, sizeof errbuf);
+ if(strstr(errbuf, "interrupt") == nil)
+ bp->state = Binactive;
+ errstr(errbuf, sizeof errbuf);
+ 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;
+}
--- /dev/null
+++ b/libbio/mkfile
@@ -1,0 +1,25 @@
+<../mkconfig
+
+LIB=libbio.a
+OFILES=\
+ bbuffered.$O\
+ bfildes.$O\
+ bflush.$O\
+ bgetrune.$O\
+ bgetc.$O\
+ bgetd.$O\
+ binit.$O\
+ boffset.$O\
+ bprint.$O\
+ bputrune.$O\
+ bputc.$O\
+ brdline.$O\
+ brdstr.$O\
+ bread.$O\
+ bseek.$O\
+ bvprint.$O\
+ bwrite.$O\
+
+HFILES= $ROOT/include/bio.h
+
+<$ROOT/mkfiles/mksyslib-$SHELLTYPE
--- /dev/null
+++ b/libdraw/NOTICE
@@ -1,0 +1,31 @@
+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.
+ Portions Copyright © 1997-1999 Vita Nuova Limited
+ Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
+ Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
+
+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.
+
--- /dev/null
+++ b/libdraw/alloc.c
@@ -1,0 +1,237 @@
+#include "lib9.h"
+#include "draw.h"
+#include "kernel.h"
+
+Image*
+allocimage(Display *d, Rectangle r, ulong chan, int repl, ulong val)
+{
+ return _allocimage(nil, d, r, chan, repl, val, 0, 0);
+}
+
+Image*
+_allocimage(Image *ai, Display *d, Rectangle r, ulong chan, int repl, ulong val, int screenid, int refresh)
+{
+ uchar *a;
+ char *err;
+ Image *i;
+ Rectangle clipr;
+ int id;
+ int depth;
+
+ err = 0;
+ i = 0;
+
+ if(chan == 0){
+ kwerrstr("bad channel descriptor");
+ return nil;
+ }
+
+ depth = chantodepth(chan);
+ if(depth == 0){
+ err = "bad channel descriptor";
+ Error:
+ if(err)
+ kwerrstr("allocimage: %s", err);
+ else
+ kwerrstr("allocimage: %r");
+ free(i);
+ return 0;
+ }
+
+ /* flush pending data so we don't get error allocating the image */
+ flushimage(d, 0);
+ a = bufimage(d, 1+4+4+1+4+1+4*4+4*4+4);
+ if(a == 0)
+ goto Error;
+ d->imageid++;
+ id = d->imageid;
+ a[0] = 'b';
+ BPLONG(a+1, id);
+ BPLONG(a+5, screenid);
+ a[9] = refresh;
+ BPLONG(a+10, chan);
+ a[14] = repl;
+ BPLONG(a+15, r.min.x);
+ BPLONG(a+19, r.min.y);
+ BPLONG(a+23, r.max.x);
+ BPLONG(a+27, r.max.y);
+ if(repl)
+ /* huge but not infinite, so various offsets will leave it huge, not overflow */
+ clipr = Rect(-0x3FFFFFFF, -0x3FFFFFFF, 0x3FFFFFFF, 0x3FFFFFFF);
+ else
+ clipr = r;
+ BPLONG(a+31, clipr.min.x);
+ BPLONG(a+35, clipr.min.y);
+ BPLONG(a+39, clipr.max.x);
+ BPLONG(a+43, clipr.max.y);
+ BPLONG(a+47, val);
+ if(flushimage(d, 0) < 0)
+ goto Error;
+
+ if(ai)
+ i = ai;
+ else{
+ i = malloc(sizeof(Image));
+ if(i == nil){
+ a = bufimage(d, 1+4);
+ if(a){
+ a[0] = 'f';
+ BPLONG(a+1, id);
+ flushimage(d, 0);
+ }
+ goto Error;
+ }
+ }
+ i->display = d;
+ i->id = id;
+ i->depth = depth;
+ i->chan = chan;
+ i->r = r;
+ i->clipr = clipr;
+ i->repl = repl;
+ i->screen = 0;
+ i->next = 0;
+ return i;
+}
+
+Image*
+namedimage(Display *d, char *name)
+{
+ uchar *a;
+ char *err, buf[12*12+1];
+ Image *i;
+ int id, n;
+ ulong chan;
+
+ err = 0;
+ i = 0;
+
+ n = strlen(name);
+ if(n >= 256){
+ err = "name too long";
+ Error:
+ if(err)
+ kwerrstr("namedimage: %s", err);
+ else
+ kwerrstr("namedimage: %r");
+ if(i)
+ free(i);
+ return 0;
+ }
+ /* flush pending data so we don't get error allocating the image */
+ flushimage(d, 0);
+ a = bufimage(d, 1+4+1+n);
+ if(a == 0)
+ goto Error;
+ d->imageid++;
+ id = d->imageid;
+ a[0] = 'n';
+ BPLONG(a+1, id);
+ a[5] = n;
+ memmove(a+6, name, n);
+ if(flushimage(d, 0) < 0)
+ goto Error;
+
+ if(kchanio(d->ctlchan, buf, sizeof buf, OREAD) < 12*12)
+ goto Error;
+ buf[12*12] = '\0';
+
+ i = malloc(sizeof(Image));
+ if(i == nil){
+ Error1:
+ a = bufimage(d, 1+4);
+ if(a){
+ a[0] = 'f';
+ BPLONG(a+1, id);
+ flushimage(d, 0);
+ }
+ goto Error;
+ }
+ i->display = d;
+ i->id = id;
+ if((chan=strtochan(buf+2*12))==0){
+ kwerrstr("bad channel from devdraw");
+ goto Error1;
+ }
+ i->chan = chan;
+ i->depth = chantodepth(chan);
+ i->repl = atoi(buf+3*12);
+ i->r.min.x = atoi(buf+4*12);
+ i->r.min.y = atoi(buf+5*12);
+ i->r.max.x = atoi(buf+6*12);
+ i->r.max.y = atoi(buf+7*12);
+ i->clipr.min.x = atoi(buf+8*12);
+ i->clipr.min.y = atoi(buf+9*12);
+ i->clipr.max.x = atoi(buf+10*12);
+ i->clipr.max.y = atoi(buf+11*12);
+ i->screen = 0;
+ i->next = 0;
+ return i;
+}
+
+int
+nameimage(Image *i, char *name, int in)
+{
+ uchar *a;
+ int n;
+
+ n = strlen(name);
+ a = bufimage(i->display, 1+4+1+1+n);
+ if(a == 0)
+ return 0;
+ a[0] = 'N';
+ BPLONG(a+1, i->id);
+ a[5] = in;
+ a[6] = n;
+ memmove(a+7, name, n);
+ if(flushimage(i->display, 0) < 0)
+ return 0;
+ return 1;
+}
+
+int
+_freeimage1(Image *i)
+{
+ uchar *a;
+ Display *d;
+ Image *w;
+
+ if(i == 0)
+ return 0;
+ /* make sure no refresh events occur on this if we block in the write */
+ d = i->display;
+ /* flush pending data so we don't get error deleting the image */
+ flushimage(d, 0);
+ a = bufimage(d, 1+4);
+ if(a == 0)
+ return -1;
+ a[0] = 'f';
+ BPLONG(a+1, i->id);
+ if(i->screen){
+ w = d->windows;
+ if(w == i)
+ d->windows = i->next;
+ else
+ while(w){
+ if(w->next == i){
+ w->next = i->next;
+ break;
+ }
+ w = w->next;
+ }
+ }
+ if(flushimage(d, i->screen!=0) < 0)
+ return -1;
+
+ return 0;
+}
+
+int
+freeimage(Image *i)
+{
+ int ret;
+
+ ret = _freeimage1(i);
+ free(i);
+ return ret;
+}
--- /dev/null
+++ b/libdraw/allocimagemix.c
@@ -1,0 +1,42 @@
+#include "lib9.h"
+#include "draw.h"
+
+Image*
+allocimagemix(Display *d, ulong color1, ulong color3)
+{
+ Image *t, *b;
+ static Image *qmask;
+
+ if(qmask == nil)
+ qmask = allocimage(d, Rect(0,0,1,1), GREY8, 1, 0x3F3F3FFF);
+
+ if(d->depth <= 8){ /* create a 2×2 texture */
+ t = allocimage(d, Rect(0,0,1,1), d->chan, 0, color1);
+ if(t == nil)
+ return nil;
+
+ b = allocimage(d, Rect(0,0,2,2), d->chan, 1, color3);
+ if(b == nil){
+ freeimage(t);
+ return nil;
+ }
+
+ draw(b, Rect(0,0,1,1), t, nil, ZP);
+ freeimage(t);
+ return b;
+ }else{ /* use a solid color, blended using alpha */
+ t = allocimage(d, Rect(0,0,1,1), d->chan, 1, color1);
+ if(t == nil)
+ return nil;
+
+ b = allocimage(d, Rect(0,0,1,1), d->chan, 1, color3);
+ if(b == nil){
+ freeimage(t);
+ return nil;
+ }
+
+ draw(b, b->r, t, qmask, ZP);
+ freeimage(t);
+ return b;
+ }
+}
--- /dev/null
+++ b/libdraw/arith.c
@@ -1,0 +1,203 @@
+#include "lib9.h"
+#include "draw.h"
+
+Point
+Pt(int x, int y)
+{
+ Point p;
+
+ p.x = x;
+ p.y = y;
+ return p;
+}
+
+Rectangle
+Rect(int x, int y, int bx, int by)
+{
+ Rectangle r;
+
+ r.min.x = x;
+ r.min.y = y;
+ r.max.x = bx;
+ r.max.y = by;
+ return r;
+}
+
+Rectangle
+Rpt(Point min, Point max)
+{
+ Rectangle r;
+
+ r.min = min;
+ r.max = max;
+ return r;
+}
+
+Point
+addpt(Point a, Point b)
+{
+ a.x += b.x;
+ a.y += b.y;
+ return a;
+}
+
+Point
+subpt(Point a, Point b)
+{
+ a.x -= b.x;
+ a.y -= b.y;
+ return a;
+}
+
+Rectangle
+insetrect(Rectangle r, int n)
+{
+ r.min.x += n;
+ r.min.y += n;
+ r.max.x -= n;
+ r.max.y -= n;
+ return r;
+}
+
+Point
+divpt(Point a, int b)
+{
+ a.x /= b;
+ a.y /= b;
+ return a;
+}
+
+Point
+mulpt(Point a, int b)
+{
+ a.x *= b;
+ a.y *= b;
+ return a;
+}
+
+Rectangle
+rectsubpt(Rectangle r, Point p)
+{
+ r.min.x -= p.x;
+ r.min.y -= p.y;
+ r.max.x -= p.x;
+ r.max.y -= p.y;
+ return r;
+}
+
+Rectangle
+rectaddpt(Rectangle r, Point p)
+{
+ r.min.x += p.x;
+ r.min.y += p.y;
+ r.max.x += p.x;
+ r.max.y += p.y;
+ return r;
+}
+
+int
+eqpt(Point p, Point q)
+{
+ return p.x==q.x && p.y==q.y;
+}
+
+int
+eqrect(Rectangle r, Rectangle s)
+{
+ return r.min.x==s.min.x && r.max.x==s.max.x &&
+ r.min.y==s.min.y && r.max.y==s.max.y;
+}
+
+int
+rectXrect(Rectangle r, Rectangle s)
+{
+ return r.min.x<s.max.x && s.min.x<r.max.x &&
+ r.min.y<s.max.y && s.min.y<r.max.y;
+}
+
+int
+rectinrect(Rectangle r, Rectangle s)
+{
+ return s.min.x<=r.min.x && r.max.x<=s.max.x && s.min.y<=r.min.y && r.max.y<=s.max.y;
+}
+
+int
+ptinrect(Point p, Rectangle r)
+{
+ return p.x>=r.min.x && p.x<r.max.x &&
+ p.y>=r.min.y && p.y<r.max.y;
+}
+
+Rectangle
+canonrect(Rectangle r)
+{
+ int t;
+ if (r.max.x < r.min.x) {
+ t = r.min.x;
+ r.min.x = r.max.x;
+ r.max.x = t;
+ }
+ if (r.max.y < r.min.y) {
+ t = r.min.y;
+ r.min.y = r.max.y;
+ r.max.y = t;
+ }
+ return r;
+}
+
+void
+combinerect(Rectangle *r1, Rectangle r2)
+{
+ if(r1->min.x > r2.min.x)
+ r1->min.x = r2.min.x;
+ if(r1->min.y > r2.min.y)
+ r1->min.y = r2.min.y;
+ if(r1->max.x < r2.max.x)
+ r1->max.x = r2.max.x;
+ if(r1->max.y < r2.max.y)
+ r1->max.y = r2.max.y;
+}
+
+ulong
+drawld2chan[] = {
+ GREY1,
+ GREY2,
+ GREY4,
+ CMAP8,
+};
+
+ulong
+setalpha(ulong color, uchar alpha)
+{
+ int red, green, blue;
+
+ red = (color >> 3*8) & 0xFF;
+ green = (color >> 2*8) & 0xFF;
+ blue = (color >> 1*8) & 0xFF;
+ /* ignore incoming alpha */
+ red = (red * alpha)/255;
+ green = (green * alpha)/255;
+ blue = (blue * alpha)/255;
+ return (red<<3*8) | (green<<2*8) | (blue<<1*8) | (alpha<<0*8);
+}
+
+Point ZP;
+Rectangle ZR;
+int
+Rfmt(Fmt *f)
+{
+ Rectangle r;
+
+ r = va_arg(f->args, Rectangle);
+ return fmtprint(f, "%P %P", r.min, r.max);
+}
+
+int
+Pfmt(Fmt *f)
+{
+ Point p;
+
+ p = va_arg(f->args, Point);
+ return fmtprint(f, "[%d %d]", p.x, p.y);
+}
+
--- /dev/null
+++ b/libdraw/bezier.c
@@ -1,0 +1,243 @@
+#include "lib9.h"
+#include "draw.h"
+
+#define PINC 32 /* realloc granularity */
+
+typedef struct Plist Plist;
+struct Plist
+{
+ Point *p;
+ int np; /* -1 if malloc/realloc failed */
+};
+
+static void
+appendpt(Plist *l, Point p)
+{
+ if(l->np == -1)
+ return;
+ if(l->np == 0)
+ l->p = malloc(PINC*sizeof(Point));
+ else if(l->np%PINC == 0)
+ l->p = realloc(l->p, (l->np+PINC)*sizeof(Point));
+ if(l->p == 0){
+ l->np = -1;
+ return;
+ }
+ l->p[l->np++] = p;
+}
+
+static int
+normsq(Point p)
+{
+ return p.x*p.x+p.y*p.y;
+}
+
+static int
+psdist(Point p, Point a, Point b)
+{
+ int num, den;
+
+ p = subpt(p, a);
+ b = subpt(b, a);
+ num = p.x*b.x + p.y*b.y;
+ if(num <= 0)
+ return normsq(p);
+ den = normsq(b);
+ if(num >= den)
+ return normsq(subpt(b, p));
+ return normsq(subpt(divpt(mulpt(b, num), den), p));
+}
+
+/*
+ * Convert cubic Bezier curve control points to polyline
+ * vertices. Leaves the last vertex off, so you can continue
+ * with another curve.
+ */
+static void
+bpts1(Plist *l, Point p0, Point p1, Point p2, Point p3, int scale)
+{
+ Point p01, p12, p23, p012, p123, p0123;
+ Point tp0, tp1, tp2, tp3;
+ tp0=divpt(p0, scale);
+ tp1=divpt(p1, scale);
+ tp2=divpt(p2, scale);
+ tp3=divpt(p3, scale);
+ if(psdist(tp1, tp0, tp3)<=1 && psdist(tp2, tp0, tp3)<=1){
+ appendpt(l, tp0);
+ appendpt(l, tp1);
+ appendpt(l, tp2);
+ }
+ else{
+ /*
+ * if scale factor is getting too big for comfort,
+ * rescale now & concede the rounding error
+ */
+ if(scale>(1<<12)){
+ p0=tp0;
+ p1=tp1;
+ p2=tp2;
+ p3=tp3;
+ scale=1;
+ }
+ p01=addpt(p0, p1);
+ p12=addpt(p1, p2);
+ p23=addpt(p2, p3);
+ p012=addpt(p01, p12);
+ p123=addpt(p12, p23);
+ p0123=addpt(p012, p123);
+ bpts1(l, mulpt(p0, 8), mulpt(p01, 4), mulpt(p012, 2), p0123, scale*8);
+ bpts1(l, p0123, mulpt(p123, 2), mulpt(p23, 4), mulpt(p3, 8), scale*8);
+ }
+}
+
+static void
+bpts(Plist *l, Point p0, Point p1, Point p2, Point p3)
+{
+ bpts1(l, p0, p1, p2, p3, 1);
+}
+
+static void
+bezierpts(Plist *l, Point p0, Point p1, Point p2, Point p3)
+{
+ bpts(l, p0, p1, p2, p3);
+ appendpt(l, p3);
+}
+
+static void
+bezsplinepts(Plist *l, Point *pt, int npt)
+{
+ Point *p, *ep;
+ Point a, b, c, d;
+ int periodic;
+
+ if(npt<3)
+ return;
+ ep = &pt[npt-3];
+ periodic = eqpt(pt[0], ep[2]);
+ if(periodic){
+ a = divpt(addpt(ep[1], pt[0]), 2);
+ b = divpt(addpt(ep[1], mulpt(pt[0], 5)), 6);
+ c = divpt(addpt(mulpt(pt[0], 5), pt[1]), 6);
+ d = divpt(addpt(pt[0], pt[1]), 2);
+ bpts(l, a, b, c, d);
+ }
+ for(p=pt; p<=ep; p++){
+ if(p==pt && !periodic){
+ a = p[0];
+ b = divpt(addpt(p[0], mulpt(p[1], 2)), 3);
+ }
+ else{
+ a = divpt(addpt(p[0], p[1]), 2);
+ b = divpt(addpt(p[0], mulpt(p[1], 5)), 6);
+ }
+ if(p==ep && !periodic){
+ c = divpt(addpt(mulpt(p[1], 2), p[2]), 3);
+ d = p[2];
+ }
+ else{
+ c = divpt(addpt(mulpt(p[1], 5), p[2]), 6);
+ d = divpt(addpt(p[1], p[2]), 2);
+ }
+ bpts(l, a, b, c, d);
+ }
+ appendpt(l, d);
+}
+
+int
+getbezsplinepts(Point *pt, int npt, Point **pp)
+{
+ Plist l;
+ l.np = 0;
+ l.p = nil;
+ bezsplinepts(&l, pt, npt);
+ *pp = l.p;
+ return l.np;
+}
+
+int
+bezier(Image *dst, Point p0, Point p1, Point p2, Point p3, int end0, int end1, int radius, Image *src, Point sp)
+{
+ return bezierop(dst, p0, p1, p2, p3, end0, end1, radius, src, sp, SoverD);
+}
+
+int
+bezierop(Image *dst, Point p0, Point p1, Point p2, Point p3, int end0, int end1, int radius, Image *src, Point sp, Drawop op)
+{
+ Plist l;
+
+ l.np = 0;
+ bezierpts(&l, p0, p1, p2, p3);
+ if(l.np == -1)
+ return 0;
+ if(l.np != 0){
+ polyop(dst, l.p, l.np, end0, end1, radius, src, addpt(subpt(sp, p0), l.p[0]), op);
+ free(l.p);
+ }
+ return 1;
+}
+
+int
+bezspline(Image *dst, Point *pt, int npt, int end0, int end1, int radius, Image *src, Point sp)
+{
+ return bezsplineop(dst, pt, npt, end0, end1, radius, src, sp, SoverD);
+}
+
+int
+bezsplineop(Image *dst, Point *pt, int npt, int end0, int end1, int radius, Image *src, Point sp, Drawop op)
+{
+ Plist l;
+
+ l.np = 0;
+ bezsplinepts(&l, pt, npt);
+ if(l.np==-1)
+ return 0;
+ if(l.np != 0){
+ polyop(dst, l.p, l.np, end0, end1, radius, src, addpt(subpt(sp, pt[0]), l.p[0]), op);
+ free(l.p);
+ }
+ return 1;
+}
+
+int
+fillbezier(Image *dst, Point p0, Point p1, Point p2, Point p3, int w, Image *src, Point sp)
+{
+ return fillbezierop(dst, p0, p1, p2, p3, w, src, sp, SoverD);
+}
+
+int
+fillbezierop(Image *dst, Point p0, Point p1, Point p2, Point p3, int w, Image *src, Point sp, Drawop op)
+{
+ Plist l;
+
+ l.np = 0;
+ bezierpts(&l, p0, p1, p2, p3);
+ if(l.np == -1)
+ return 0;
+ if(l.np != 0){
+ fillpolyop(dst, l.p, l.np, w, src, addpt(subpt(sp, p0), l.p[0]), op);
+ free(l.p);
+ }
+ return 1;
+}
+
+int
+fillbezspline(Image *dst, Point *pt, int npt, int w, Image *src, Point sp)
+{
+ return fillbezsplineop(dst, pt, npt, w, src, sp, SoverD);
+}
+
+int
+fillbezsplineop(Image *dst, Point *pt, int npt, int w, Image *src, Point sp, Drawop op)
+{
+ Plist l;
+
+ l.np = 0;
+ bezsplinepts(&l, pt, npt);
+ if(l.np == -1)
+ return 0;
+ if(l.np > 0){
+ fillpolyop(dst, l.p, l.np, w, src, addpt(subpt(sp, pt[0]), l.p[0]), op);
+ free(l.p);
+ }
+ return 1;
+}
--- /dev/null
+++ b/libdraw/border.c
@@ -1,0 +1,26 @@
+#include "lib9.h"
+#include "draw.h"
+
+void
+borderop(Image *im, Rectangle r, int i, Image *color, Point sp, Drawop op)
+{
+ if(i < 0){
+ r = insetrect(r, i);
+ sp = addpt(sp, Pt(i,i));
+ i = -i;
+ }
+ drawop(im, Rect(r.min.x, r.min.y, r.max.x, r.min.y+i),
+ color, nil, sp, op);
+ drawop(im, Rect(r.min.x, r.max.y-i, r.max.x, r.max.y),
+ color, nil, Pt(sp.x, sp.y+Dy(r)-i), op);
+ drawop(im, Rect(r.min.x, r.min.y+i, r.min.x+i, r.max.y-i),
+ color, nil, Pt(sp.x, sp.y+i), op);
+ drawop(im, Rect(r.max.x-i, r.min.y+i, r.max.x, r.max.y-i),
+ color, nil, Pt(sp.x+Dx(r)-i, sp.y+i), op);
+}
+
+void
+border(Image *im, Rectangle r, int i, Image *color, Point sp)
+{
+ borderop(im, r, i, color, sp, SoverD);
+}
--- /dev/null
+++ b/libdraw/buildfont.c
@@ -1,0 +1,142 @@
+#include "lib9.h"
+#include "draw.h"
+#include "kernel.h"
+
+static char*
+skip(char *s)
+{
+ while(*s==' ' || *s=='\n' || *s=='\t')
+ s++;
+ return s;
+}
+
+Font*
+buildfont(Display *d, char *buf, char *name)
+{
+ Font *fnt;
+ Cachefont *c;
+ char *s, *t;
+ ulong min, max;
+ int offset;
+ char badform[] = "bad font format: number expected (char position %d)";
+
+ s = buf;
+ fnt = malloc(sizeof(Font));
+ if(fnt == 0)
+ return 0;
+ memset(fnt, 0, sizeof(Font));
+ fnt->display = d;
+ fnt->name = strdup(name);
+ fnt->ncache = NFCACHE+NFLOOK;
+ fnt->nsubf = NFSUBF;
+ fnt->cache = malloc(fnt->ncache * sizeof(fnt->cache[0]));
+ fnt->subf = malloc(fnt->nsubf * sizeof(fnt->subf[0]));
+ if(fnt->name==0 || fnt->cache==0 || fnt->subf==0){
+ Err2:
+ free(fnt->name);
+ free(fnt->cache);
+ free(fnt->subf);
+ free(fnt->sub);
+ free(fnt);
+ return 0;
+ }
+ fnt->height = strtol(s, &s, 0);
+ s = skip(s);
+ fnt->ascent = strtol(s, &s, 0);
+ s = skip(s);
+ if(fnt->height<=0 || fnt->ascent<=0){
+ kwerrstr("bad height or ascent in font file");
+ goto Err2;
+ }
+ fnt->width = 0;
+ fnt->nsub = 0;
+ fnt->sub = 0;
+
+ memset(fnt->subf, 0, fnt->nsubf * sizeof(fnt->subf[0]));
+ memset(fnt->cache, 0, fnt->ncache*sizeof(fnt->cache[0]));
+ fnt->age = 1;
+ do{
+ /* must be looking at a number now */
+ if(*s<'0' || '9'<*s){
+ kwerrstr(badform, s-buf);
+ goto Err3;
+ }
+ min = strtol(s, &s, 0);
+ s = skip(s);
+ /* must be looking at a number now */
+ if(*s<'0' || '9'<*s){
+ kwerrstr(badform, s-buf);
+ goto Err3;
+ }
+ max = strtol(s, &s, 0);
+ s = skip(s);
+ if(*s==0 || min>=Runemax || max>=Runemax || min>max){
+ kwerrstr("illegal subfont range");
+ Err3:
+ freefont(fnt);
+ return 0;
+ }
+ t = s;
+ offset = strtol(s, &t, 0);
+ if(t>s && (*t==' ' || *t=='\t' || *t=='\n'))
+ s = skip(t);
+ else
+ offset = 0;
+ fnt->sub = realloc(fnt->sub, (fnt->nsub+1)*sizeof(Cachefont*));
+ if(fnt->sub == 0){
+ /* realloc manual says fnt->sub may have been destroyed */
+ fnt->nsub = 0;
+ goto Err3;
+ }
+ c = malloc(sizeof(Cachefont));
+ if(c == 0)
+ goto Err3;
+ fnt->sub[fnt->nsub] = c;
+ c->min = min;
+ c->max = max;
+ c->offset = offset;
+ t = s;
+ while(*s && *s!=' ' && *s!='\n' && *s!='\t')
+ s++;
+ *s++ = 0;
+ c->subfontname = 0;
+ c->name = strdup(t);
+ if(c->name == 0){
+ free(c);
+ goto Err3;
+ }
+ s = skip(s);
+ fnt->nsub++;
+ }while(*s);
+ return fnt;
+}
+
+void
+freefont(Font *f)
+{
+ int i;
+ Cachefont *c;
+ Subfont *s;
+
+ if(f == 0)
+ return;
+
+ for(i=0; i<f->nsub; i++){
+ c = f->sub[i];
+ free(c->subfontname);
+ free(c->name);
+ free(c);
+ }
+ for(i=0; i<f->nsubf; i++){
+ s = f->subf[i].f;
+/* if(s && s!=display->defaultsubfont)*/ /* Plan 9 uses this */
+ if(s)
+ freesubfont(s);
+ }
+ freeimage(f->cacheimage);
+ free(f->name);
+ free(f->cache);
+ free(f->subf);
+ free(f->sub);
+ free(f);
+}
--- /dev/null
+++ b/libdraw/bytesperline.c
@@ -1,0 +1,30 @@
+#include "lib9.h"
+#include "draw.h"
+
+static
+int
+unitsperline(Rectangle r, int d, int bitsperunit)
+{
+ ulong l, t;
+
+ if(r.min.x >= 0){
+ l = (r.max.x*d+bitsperunit-1)/bitsperunit;
+ l -= (r.min.x*d)/bitsperunit;
+ }else{ /* make positive before divide */
+ t = (-r.min.x*d+bitsperunit-1)/bitsperunit;
+ l = t+(r.max.x*d+bitsperunit-1)/bitsperunit;
+ }
+ return l;
+}
+
+int
+wordsperline(Rectangle r, int d)
+{
+ return unitsperline(r, d, 8*sizeof(ulong));
+}
+
+int
+bytesperline(Rectangle r, int d)
+{
+ return unitsperline(r, d, 8);
+}
--- /dev/null
+++ b/libdraw/chan.c
@@ -1,0 +1,76 @@
+#include "lib9.h"
+#include "draw.h"
+
+static char channames[] = "rgbkamx";
+char*
+chantostr(char *buf, ulong cc)
+{
+ ulong c, rc;
+ char *p;
+
+ if(chantodepth(cc) == 0)
+ return nil;
+
+ /* reverse the channel descriptor so we can easily generate the string in the right order */
+ rc = 0;
+ for(c=cc; c; c>>=8){
+ rc <<= 8;
+ rc |= c&0xFF;
+ }
+
+ p = buf;
+ for(c=rc; c; c>>=8) {
+ *p++ = channames[TYPE(c)];
+ *p++ = '0'+NBITS(c);
+ }
+ *p = 0;
+
+ return buf;
+}
+
+/* avoid pulling in ctype when using with drawterm etc. */
+static int
+iswhitespace(char c)
+{
+ return c==' ' || c== '\t' || c=='\r' || c=='\n';
+}
+
+ulong
+strtochan(char *s)
+{
+ char *p, *q;
+ ulong c;
+ int t, n;
+
+ c = 0;
+ p=s;
+ while(*p && iswhitespace(*p))
+ p++;
+
+ while(*p && !iswhitespace(*p)){
+ if((q = strchr(channames, p[0])) == nil)
+ return 0;
+ t = q-channames;
+ if(p[1] < '0' || p[1] > '9')
+ return 0;
+ n = p[1]-'0';
+ c = (c<<8) | __DC(t, n);
+ p += 2;
+ }
+ return c;
+}
+
+int
+chantodepth(ulong c)
+{
+ int n;
+
+ for(n=0; c; c>>=8){
+ if(TYPE(c) >= NChan || NBITS(c) > 8 || NBITS(c) <= 0)
+ return 0;
+ n += NBITS(c);
+ }
+ if(n==0 || (n>8 && n%8) || (n<8 && 8%n))
+ return 0;
+ return n;
+}
--- /dev/null
+++ b/libdraw/cloadimage.c
@@ -1,0 +1,49 @@
+#include "lib9.h"
+#include "draw.h"
+#include "kernel.h"
+
+int
+cloadimage(Image *i, Rectangle r, uchar *data, int ndata)
+{
+ int m, nb, miny, maxy, ncblock;
+ uchar *a;
+
+ if(!rectinrect(r, i->r)){
+ werrstr("cloadimage: bad rectangle");
+ return -1;
+ }
+
+ miny = r.min.y;
+ m = 0;
+ ncblock = _compblocksize(r, i->depth);
+ while(miny != r.max.y){
+ maxy = atoi((char*)data+0*12);
+ nb = atoi((char*)data+1*12);
+ if(maxy<=miny || r.max.y<maxy){
+ werrstr("creadimage: bad maxy %d", maxy);
+ return -1;
+ }
+ data += 2*12;
+ ndata -= 2*12;
+ m += 2*12;
+ if(nb<=0 || ncblock<nb || nb>ndata){
+ werrstr("creadimage: bad count %d", nb);
+ return -1;
+ }
+ a = bufimage(i->display, 21+nb);
+ if(a == nil)
+ return -1;
+ a[0] = 'Y';
+ BPLONG(a+1, i->id);
+ BPLONG(a+5, r.min.x);
+ BPLONG(a+9, miny);
+ BPLONG(a+13, r.max.x);
+ BPLONG(a+17, maxy);
+ memmove(a+21, data, nb);
+ miny = maxy;
+ data += nb;
+ ndata += nb;
+ m += nb;
+ }
+ return m;
+}
--- /dev/null
+++ b/libdraw/computil.c
@@ -1,0 +1,37 @@
+#include "lib9.h"
+#include "draw.h"
+
+/*
+ * compressed data are sequences of byte codes.
+ * if the first byte b has the 0x80 bit set, the next (b^0x80)+1 bytes
+ * are data. otherwise, it's two bytes specifying a previous string to repeat.
+ */
+void
+_twiddlecompressed(uchar *buf, int n)
+{
+ uchar *ebuf;
+ int j, k, c;
+
+ ebuf = buf+n;
+ while(buf < ebuf){
+ c = *buf++;
+ if(c >= 128){
+ k = c-128+1;
+ for(j=0; j<k; j++, buf++)
+ *buf ^= 0xFF;
+ }else
+ buf++;
+ }
+}
+
+int
+_compblocksize(Rectangle r, int depth)
+{
+ int bpl;
+
+ bpl = bytesperline(r, depth);
+ bpl = 2*bpl; /* add plenty extra for blocking, etc. */
+ if(bpl < NCBLOCK)
+ return NCBLOCK;
+ return bpl;
+}
--- /dev/null
+++ b/libdraw/creadimage.c
@@ -1,0 +1,116 @@
+#include "lib9.h"
+#include "draw.h"
+#include "kernel.h"
+
+Image *
+creadimage(Display *d, int fd, int dolock)
+{
+ char hdr[5*12+1];
+ Rectangle r;
+ int m, nb, miny, maxy, new, ldepth, ncblock;
+ uchar *buf, *a;
+ Image *i;
+ ulong chan;
+ int font;
+
+ font = dolock&2;
+ dolock &= 1;
+ if(libreadn(fd, hdr, 5*12) != 5*12)
+ return nil;
+
+ /*
+ * distinguish new channel descriptor from old ldepth.
+ * channel descriptors have letters as well as numbers,
+ * while ldepths are a single digit formatted as %-11d.
+ */
+ new = 0;
+ for(m=0; m<10; m++){
+ if(hdr[m] != ' '){
+ new = 1;
+ break;
+ }
+ }
+ if(hdr[11] != ' '){
+ kwerrstr("creadimage: bad format");
+ return nil;
+ }
+ if(new){
+ hdr[11] = '\0';
+ if((chan = strtochan(hdr)) == 0){
+ kwerrstr("creadimage: bad channel string %s", hdr);
+ return nil;
+ }
+ }else{
+ ldepth = ((int)hdr[10])-'0';
+ if(ldepth<0 || ldepth>3){
+ kwerrstr("creadimage: bad ldepth %d", ldepth);
+ return nil;
+ }
+ chan = drawld2chan[ldepth];
+ }
+ r.min.x=atoi(hdr+1*12);
+ r.min.y=atoi(hdr+2*12);
+ r.max.x=atoi(hdr+3*12);
+ r.max.y=atoi(hdr+4*12);
+ if(r.min.x>r.max.x || r.min.y>r.max.y){
+ kwerrstr("creadimage: bad rectangle");
+ return nil;
+ }
+
+ if(dolock)
+ dolock = lockdisplay(d);
+ i = allocimage(d, r, chan, 0, 0);
+ if(dolock)
+ unlockdisplay(d);
+ if(i == nil)
+ return nil;
+ ncblock = _compblocksize(r, i->depth);
+ buf = malloc(ncblock);
+ if(buf == nil)
+ goto Errout;
+ miny = r.min.y;
+ while(miny != r.max.y){
+ if(libreadn(fd, hdr, 2*12) != 2*12){
+ Errout:
+ if(dolock)
+ lockdisplay(d);
+ Erroutlock:
+ freeimage(i);
+ if(dolock)
+ unlockdisplay(d);
+ free(buf);
+ return nil;
+ }
+ maxy = atoi(hdr+0*12);
+ nb = atoi(hdr+1*12);
+ if(maxy<=miny || r.max.y<maxy){
+ kwerrstr("creadimage: bad maxy %d", maxy);
+ goto Errout;
+ }
+ if(nb<=0 || ncblock<nb){
+ kwerrstr("creadimage: bad count %d", nb);
+ goto Errout;
+ }
+ if(libreadn(fd, buf, nb)!=nb)
+ goto Errout;
+ if(dolock)
+ lockdisplay(d);
+ a = bufimage(i->display, 21+nb);
+ if(a == nil)
+ goto Erroutlock;
+ a[0] = 'Y';
+ BPLONG(a+1, i->id);
+ BPLONG(a+5, r.min.x);
+ BPLONG(a+9, miny);
+ BPLONG(a+13, r.max.x);
+ BPLONG(a+17, maxy);
+ if(!font&&!new) /* old image: flip the data bits */
+ _twiddlecompressed(buf, nb);
+ memmove(a+21, buf, nb);
+ if(dolock)
+ unlockdisplay(d);
+ miny = maxy;
+ }
+ free(buf);
+ return i;
+}
--- /dev/null
+++ b/libdraw/defont.c
@@ -1,0 +1,401 @@
+#include "lib9.h"
+#include "draw.h"
+
+/*
+ * lucm/latin1.9, in uncompressed form
+ */
+uchar
+defontdata[] =
+{
+0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x30,0x20,0x20,0x20,0x20,0x20,
+0x20,0x20,0x20,0x20,0x20,0x20,0x30,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,
+0x20,0x20,0x30,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x32,0x33,0x30,0x34,0x20,
+0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x31,0x35,0x20,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xff,0xff,
+0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+0xff,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x30,0x06,0x06,0x03,0x42,0x40,0x00,0x00,0x00,0x18,0x03,0x03,
+0x02,0x43,0x00,0x60,0x60,0x48,0x00,0x0d,0x0c,0x01,0x81,0x80,0xd0,0x90,0x00,0x00,
+0x18,0x01,0x81,0x81,0x40,0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x7f,0x9c,0x1c,
+0x0e,0x07,0x01,0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xe0,0x70,
+0x38,0x1c,0x0e,0x04,0x81,0xc1,0xc0,0x70,0x00,0x1c,0x1c,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xaa,0x80,0xc0,0x63,0xe3,
+0xf1,0xf8,0xfe,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xfc,0x7f,0xff,0xff,0x1f,0x8f,
+0xc7,0xe3,0xf1,0xfb,0x7e,0x3e,0x3f,0x8f,0xff,0xe3,0xe3,0xff,0xff,0xff,0xff,0xff,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x0c,0x18,0x09,0x05,0x82,0x40,0xc0,0x00,0x00,0x06,0x0c,0x04,
+0x82,0x40,0xc1,0x80,0x90,0x48,0x00,0x16,0x03,0x06,0x02,0x41,0x60,0x90,0x00,0x00,
+0x06,0x06,0x02,0x41,0x41,0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x3e,0x7f,0xa0,0x10,
+0x08,0x04,0x02,0x40,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x90,0x48,
+0x24,0x12,0x09,0x06,0x82,0x01,0x00,0x90,0x00,0x20,0x10,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x04,0x80,0x00,0x40,0x00,0x00,0x38,0x06,0x18,0x00,0x00,0x00,0x00,0x00,
+0x00,0x06,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x07,0xc6,0x01,0xf0,0x00,0x00,0x0c,0x00,0x18,0x00,0x00,0x30,0x00,0x3c,
+0x00,0x60,0x06,0x01,0x8c,0x07,0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x01,0xe0,0xc3,0xc0,0x01,0x54,0x9c,0xc0,0x5f,0xef,
+0xf7,0xfb,0xfd,0xbf,0xff,0xff,0xff,0xff,0xff,0xff,0xfb,0x7f,0xff,0xff,0x6f,0xb7,
+0xdb,0xed,0xf6,0xf9,0x7d,0xfe,0xff,0x6f,0xff,0xdf,0xef,0xff,0xff,0xff,0xff,0xff,
+0xff,0x00,0x01,0x00,0x00,0x00,0x00,0x30,0x00,0x14,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x38,0x00,0x00,0x00,0x00,0x00,0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x20,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x78,0x30,0x06,0x06,0x06,0x82,0x80,0xc0,0x00,
+0x00,0x18,0x03,0x03,0x02,0x41,0x80,0x30,0x30,0x24,0x76,0x0d,0x0c,0x00,0xc0,0xc0,
+0xd0,0x50,0x00,0x00,0x18,0x01,0x81,0x81,0x40,0x30,0x00,0x28,0x0f,0x7f,0xbc,0x1c,
+0x0e,0x07,0x03,0xc0,0x10,0x70,0x24,0x10,0x09,0x07,0x03,0x80,0xe0,0x70,0x90,0x48,
+0x24,0x12,0x09,0x05,0x81,0x81,0xc0,0x80,0x70,0x18,0x1c,0x07,0x01,0xc1,0xc0,0x90,
+0x00,0x0c,0x04,0x84,0x83,0xe1,0xc0,0xe0,0x38,0x0c,0x0c,0x02,0x00,0x00,0x00,0x00,
+0x00,0x06,0x1c,0x06,0x0f,0x87,0xc0,0x63,0xf8,0x78,0xfe,0x3e,0x0e,0x00,0x00,0x00,
+0x00,0x00,0x00,0x7c,0x1c,0x0c,0x1f,0x03,0xc7,0xc3,0xf1,0xf8,0x3c,0x63,0x3f,0x0f,
+0x8c,0x66,0x06,0x19,0x84,0x78,0x7e,0x1e,0x1f,0x07,0xcf,0xf3,0x1b,0x0d,0x86,0x63,
+0x61,0x9f,0xc6,0x06,0x00,0x30,0x00,0x00,0x10,0x00,0x18,0x00,0x00,0x30,0x00,0x60,
+0x00,0x60,0x06,0x01,0x8c,0x00,0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x80,
+0x00,0x00,0x00,0x00,0x00,0x00,0x03,0x00,0xc0,0x60,0x00,0xaa,0xb6,0xc0,0x43,0xe3,
+0xf1,0xf8,0xfc,0x3f,0xef,0x8f,0xdb,0xef,0xf6,0xf8,0xfb,0xff,0x1f,0x8f,0x6f,0xb7,
+0xdb,0xed,0xf6,0xfa,0x7e,0x7e,0x3f,0x7f,0x8f,0xe7,0xe3,0xf8,0xfe,0x3e,0x3f,0x6f,
+0x00,0x00,0x01,0x01,0xc8,0x0b,0x0c,0x30,0x7c,0x14,0x0f,0x0f,0x00,0x00,0x00,0x00,
+0x78,0x00,0x1c,0x00,0x0f,0x07,0x81,0x80,0x00,0x7c,0x00,0x00,0x1c,0x0f,0x80,0x04,
+0x42,0x23,0x90,0x00,0x18,0x0c,0x06,0x03,0x01,0x80,0xc0,0x3c,0x3c,0x3f,0x1f,0x8f,
+0xc7,0xe7,0xe3,0xf1,0xf8,0xfc,0x7c,0x30,0x8f,0x07,0x83,0xc1,0xe0,0xf0,0x00,0x3d,
+0x31,0x98,0xcc,0x66,0x36,0x19,0x80,0xcc,0x0c,0x18,0x09,0x0b,0x02,0x81,0x20,0x00,
+0x00,0x06,0x0c,0x04,0x82,0x40,0x60,0xc0,0x48,0x24,0x18,0x16,0x03,0x03,0x01,0x21,
+0x60,0x50,0x00,0x00,0x06,0x06,0x02,0x41,0x40,0xc1,0x80,0x28,0x87,0x7f,0x84,0x10,
+0x08,0x04,0x02,0x40,0x38,0x48,0x24,0x10,0x09,0x04,0x04,0x81,0x00,0x80,0x90,0x48,
+0x24,0x12,0x09,0x04,0x80,0x41,0x00,0x80,0x40,0x04,0x10,0x04,0x02,0x01,0x20,0x90,
+0x00,0x0c,0x04,0x84,0x86,0x53,0x65,0xb0,0x08,0x18,0x06,0x0a,0x80,0x00,0x00,0x00,
+0x00,0x0c,0x36,0x0e,0x19,0xcc,0xe0,0xe3,0xf8,0xcc,0xfe,0x63,0x1b,0x00,0x00,0x00,
+0x00,0x00,0x00,0xc6,0x62,0x0c,0x19,0x86,0x66,0x63,0x01,0x80,0x66,0x63,0x0c,0x01,
+0x8c,0xc6,0x06,0x19,0xc4,0xcc,0x63,0x33,0x19,0x8c,0x61,0x83,0x1b,0x0d,0x86,0x63,
+0x61,0x80,0xc6,0x03,0x00,0x30,0x30,0x00,0x1c,0x00,0x18,0x00,0x00,0x30,0x00,0x60,
+0x00,0x60,0x00,0x00,0x0c,0x00,0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x80,
+0x00,0x00,0x00,0x00,0x00,0x00,0x03,0x00,0xc0,0x60,0x01,0x54,0x86,0xc0,0x7b,0xef,
+0xf7,0xfb,0xfd,0xbf,0xc7,0xb7,0xdb,0xef,0xf6,0xfb,0xfb,0x7e,0xff,0x7f,0x6f,0xb7,
+0xdb,0xed,0xf6,0xfb,0x7f,0xbe,0xff,0x7f,0xbf,0xfb,0xef,0xfb,0xfd,0xfe,0xdf,0x6f,
+0xff,0x00,0x07,0x83,0x24,0x13,0x0c,0x30,0xc6,0x00,0x10,0x81,0x80,0x00,0x00,0x00,
+0x84,0x00,0x22,0x00,0x01,0x80,0xc0,0x00,0x00,0xf4,0x00,0x00,0x2c,0x18,0xc0,0x0c,
+0x46,0x20,0x90,0x00,0x18,0x0c,0x06,0x03,0x01,0x80,0xc0,0x70,0x66,0x30,0x18,0x0c,
+0x06,0x01,0x80,0xc0,0x60,0x30,0x66,0x38,0x99,0x8c,0xc6,0x63,0x31,0x98,0x00,0x66,
+0x31,0x98,0xcc,0x66,0x36,0x19,0x80,0xcc,0x00,0x00,0x00,0x00,0x00,0x00,0xc0,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x6c,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x80,0x00,0xff,0x7f,0xb8,0x1c,
+0x0e,0x07,0x02,0x40,0x7c,0x70,0x3c,0x10,0x09,0x07,0x04,0x00,0xc0,0x60,0xe0,0x70,
+0x38,0x1c,0x0e,0x04,0x83,0x81,0xc0,0x70,0x70,0x38,0x1c,0x07,0x02,0xc1,0xc0,0x90,
+0x00,0x0c,0x00,0x04,0x86,0x43,0x69,0xb0,0x30,0x18,0x06,0x07,0x01,0x00,0x00,0x00,
+0x00,0x0c,0x63,0x16,0x00,0xc0,0x61,0x62,0x01,0x80,0x06,0x63,0x31,0x80,0x00,0x00,
+0x60,0x00,0xc0,0x06,0x43,0x16,0x19,0x8c,0x06,0x33,0x01,0x80,0xc0,0x63,0x0c,0x01,
+0x8c,0x86,0x07,0x39,0xc5,0x86,0x63,0x61,0x99,0x8c,0x01,0x83,0x1b,0x0d,0xb6,0x63,
+0x31,0x01,0x86,0x03,0x00,0x30,0x30,0x00,0x1c,0x3e,0x1b,0x03,0xc1,0xf0,0xf0,0x60,
+0x3e,0x6e,0x3e,0x0f,0x8c,0x60,0xc5,0xb1,0xb8,0x38,0x6c,0x0f,0x8c,0xc7,0xc1,0x83,
+0x19,0x8d,0x82,0x63,0x31,0x9f,0xc1,0x80,0xc0,0xc0,0x00,0xaa,0x86,0xc0,0x47,0xe3,
+0xf1,0xf8,0xfd,0xbf,0x83,0x8f,0xc3,0xef,0xf6,0xf8,0xfc,0xff,0x3f,0x9f,0x1f,0x8f,
+0xc7,0xe3,0xf1,0xfb,0x7c,0x7e,0x3f,0x8f,0x8f,0xc7,0xe3,0xf8,0xfd,0x3e,0x3f,0x6f,
+0x00,0x0c,0x0d,0x43,0x03,0xe1,0x88,0x30,0xc0,0x00,0x27,0x41,0x80,0x00,0x00,0x01,
+0x72,0x00,0x22,0x04,0x01,0x80,0xc0,0x03,0x18,0xf4,0x00,0x00,0x0c,0x18,0xc0,0x04,
+0x82,0x43,0x20,0x18,0x2c,0x16,0x0b,0x05,0x82,0xc1,0x60,0xb0,0xc0,0x30,0x18,0x0c,
+0x06,0x01,0x80,0xc0,0x60,0x30,0x63,0x38,0xb0,0xd8,0x6c,0x36,0x1b,0x0c,0x00,0xc7,
+0x31,0x98,0xcc,0x66,0x33,0x11,0xf8,0xc8,0x7c,0x3e,0x1f,0x0f,0x87,0xc3,0xe1,0xd8,
+0x3c,0x1e,0x0f,0x07,0x83,0xc7,0xc3,0xe1,0xf0,0xf8,0x06,0x37,0x07,0x03,0x81,0xc0,
+0xe0,0x70,0x10,0x1d,0x31,0x98,0xcc,0x66,0x33,0x19,0xb0,0xc6,0x8f,0x7f,0x87,0x03,
+0x81,0x80,0x90,0x30,0x6c,0x48,0x24,0x10,0x06,0x04,0x04,0x80,0x20,0x10,0x10,0x0e,
+0x07,0x03,0x81,0xc0,0x60,0x88,0x38,0x0c,0x40,0x09,0x03,0x84,0x02,0x41,0x40,0x90,
+0x00,0x0c,0x00,0x1f,0xe7,0x41,0xd1,0xa0,0x00,0x30,0x03,0x0a,0x81,0x00,0x00,0x00,
+0x00,0x18,0x63,0x06,0x00,0xc0,0xc2,0x62,0x01,0xb0,0x0c,0x72,0x31,0x86,0x03,0x00,
+0xc0,0x00,0x60,0x06,0x8f,0x16,0x19,0x0c,0x06,0x33,0x01,0x80,0xc0,0x63,0x0c,0x01,
+0x8d,0x06,0x07,0x39,0x65,0x86,0x63,0x61,0x99,0x0e,0x01,0x83,0x19,0x89,0xb6,0x32,
+0x33,0x03,0x06,0x01,0x80,0x30,0x78,0x00,0x00,0x03,0x1d,0x86,0x23,0x31,0x99,0xfc,
+0x66,0x77,0x06,0x01,0x8c,0x40,0xc6,0xd9,0xdc,0x6c,0x76,0x19,0x8d,0xcc,0x27,0xf3,
+0x19,0x8d,0x82,0x63,0x31,0x80,0xc0,0x80,0xc0,0x80,0x01,0x54,0x8c,0xc0,0x78,0xfc,
+0x7e,0x7f,0x6f,0xcf,0x93,0xb7,0xdb,0xef,0xf9,0xfb,0xff,0xff,0xdf,0xef,0xef,0xf1,
+0xf8,0xfc,0x7e,0x3f,0x9f,0x77,0xc7,0xf3,0xbf,0xf6,0xfc,0x7b,0xfd,0xbe,0xbf,0x6f,
+0xff,0x0c,0x19,0x03,0x03,0x61,0x98,0x30,0x78,0x00,0x28,0x4f,0x83,0x30,0x00,0x01,
+0x4a,0x00,0x1c,0x04,0x03,0x03,0x80,0x03,0x18,0xf4,0x00,0x00,0x0c,0x18,0xd9,0x84,
+0x82,0x40,0xa0,0x18,0x2c,0x16,0x0b,0x05,0x82,0xc1,0x60,0xb0,0xc0,0x30,0x18,0x0c,
+0x06,0x01,0x80,0xc0,0x60,0x30,0x63,0x2c,0xb0,0xd8,0x6c,0x36,0x1b,0x0c,0x64,0xcb,
+0x31,0x98,0xcc,0x66,0x33,0x31,0x8c,0xd8,0x06,0x03,0x01,0x80,0xc0,0x60,0x30,0x6c,
+0x62,0x33,0x19,0x8c,0xc6,0x60,0xc0,0x60,0x30,0x18,0x1e,0x3b,0x8d,0x86,0xc3,0x61,
+0xb0,0xd8,0x10,0x36,0x31,0x98,0xcc,0x66,0x33,0x19,0xd8,0xc6,0x0f,0x7f,0x82,0x01,
+0x02,0x40,0xd0,0x40,0x6c,0x70,0x24,0x1c,0x06,0x04,0x03,0x01,0xc0,0xe0,0x10,0x12,
+0x09,0x04,0x82,0x40,0x90,0x50,0x10,0x12,0x70,0x09,0x04,0x04,0x01,0xc1,0x20,0x60,
+0x00,0x0c,0x00,0x04,0x83,0xc0,0x20,0xcc,0x00,0x30,0x03,0x02,0x01,0x00,0x00,0x00,
+0x00,0x18,0x63,0x06,0x01,0x83,0x84,0x63,0xf1,0xd8,0x18,0x3c,0x31,0x86,0x03,0x01,
+0x83,0xf8,0x30,0x1c,0x9b,0x33,0x1e,0x0c,0x06,0x33,0xe1,0x80,0xc0,0x7f,0x0c,0x01,
+0x8f,0x06,0x07,0x79,0x65,0x86,0x66,0x61,0x9e,0x07,0x81,0x83,0x19,0x89,0xb6,0x1c,
+0x1a,0x03,0x06,0x01,0x80,0x30,0x48,0x00,0x00,0x03,0x18,0xcc,0x06,0x33,0x18,0x60,
+0xc6,0x63,0x06,0x01,0x8c,0x80,0xc6,0xd9,0x8c,0xc6,0x63,0x31,0x8e,0x4c,0x01,0x83,
+0x19,0x8d,0x92,0x32,0x31,0x81,0x87,0x00,0xc0,0x70,0xe4,0xaa,0x98,0xc0,0x7d,0xfe,
+0xfd,0xbf,0x2f,0xbf,0x93,0x8f,0xdb,0xe3,0xf9,0xfb,0xff,0x1e,0x3f,0x1f,0xef,0xed,
+0xf6,0xfb,0x7d,0xbf,0x6f,0xaf,0xef,0xed,0x8f,0xf6,0xfb,0xfb,0xfe,0x3e,0xdf,0x9f,
+0x00,0x00,0x19,0x0f,0xc6,0x30,0xd0,0x00,0xcc,0x00,0x28,0x59,0x86,0x67,0xf0,0x01,
+0x72,0x00,0x00,0x3f,0x86,0x00,0xc0,0x03,0x18,0xf4,0x00,0x00,0x0c,0x18,0xcc,0xc5,
+0x32,0x83,0x4c,0x00,0x66,0x33,0x19,0x8c,0xc6,0x63,0x31,0xbc,0xc0,0x3e,0x1f,0x0f,
+0x87,0xc1,0x80,0xc0,0x60,0x30,0xfb,0x2c,0xb0,0xd8,0x6c,0x36,0x1b,0x0c,0x38,0xcb,
+0x31,0x98,0xcc,0x66,0x31,0xa1,0x8c,0xcc,0x06,0x03,0x01,0x80,0xc0,0x60,0x30,0x6c,
+0xc0,0x63,0x31,0x98,0xcc,0x60,0xc0,0x60,0x30,0x18,0x37,0x31,0x98,0xcc,0x66,0x33,
+0x19,0x8c,0x00,0x67,0x31,0x98,0xcc,0x66,0x33,0x19,0x8c,0xc6,0x1f,0x7f,0x82,0x01,
+0x02,0x40,0xb0,0x40,0x6c,0x07,0x03,0x83,0x80,0xe0,0xe0,0x00,0x18,0x0e,0x10,0x10,
+0x08,0x04,0x02,0x00,0xf0,0x20,0x10,0x1e,0x08,0x89,0x03,0x00,0xe0,0x38,0x1c,0x0e,
+0x00,0x0c,0x00,0x04,0x81,0xe0,0x41,0x6c,0x00,0x30,0x03,0x00,0x0f,0xe0,0x03,0xf8,
+0x00,0x30,0x63,0x06,0x03,0x00,0xc7,0xf0,0x39,0x8c,0x30,0x3e,0x1b,0x80,0x00,0x03,
+0x00,0x00,0x18,0x30,0x9b,0x23,0x19,0x0c,0x06,0x33,0x01,0xf8,0xc6,0x63,0x0c,0x01,
+0x8d,0x86,0x05,0xd9,0x35,0x86,0x7c,0x61,0x9b,0x01,0xc1,0x83,0x19,0x99,0xb4,0x1c,
+0x0c,0x06,0x06,0x00,0xc0,0x30,0xcc,0x00,0x00,0x3f,0x18,0xcc,0x06,0x33,0xf8,0x60,
+0xc6,0x63,0x06,0x01,0x8f,0x00,0xc6,0xd9,0x8c,0xc6,0x63,0x31,0x8c,0x0f,0x81,0x83,
+0x18,0xd9,0xba,0x1c,0x1b,0x03,0x00,0x80,0xc0,0x81,0x75,0x54,0x98,0xc0,0x7d,0xfe,
+0xfd,0xbf,0x4f,0xbf,0x93,0xf8,0xfc,0x7c,0x7f,0x1f,0x1f,0x6f,0xe7,0xf1,0xef,0xef,
+0xf7,0xfb,0xfd,0xff,0x0f,0xdf,0xef,0xe1,0xf7,0x76,0xfc,0xff,0x1f,0xc7,0xe3,0xf1,
+0xff,0x08,0x19,0x03,0x06,0x31,0xf8,0x00,0xc6,0x00,0x28,0x5b,0x8c,0xc0,0x11,0xf1,
+0x4a,0x00,0x00,0x04,0x0c,0x00,0xc0,0x03,0x18,0x74,0x38,0x00,0x0c,0x18,0xc6,0x65,
+0x52,0xb8,0x54,0x18,0x46,0x23,0x11,0x88,0xc4,0x62,0x31,0x30,0xc0,0x30,0x18,0x0c,
+0x06,0x01,0x80,0xc0,0x60,0x30,0x63,0x26,0xb0,0xd8,0x6c,0x36,0x1b,0x0c,0x10,0xd3,
+0x31,0x98,0xcc,0x66,0x30,0xc1,0x8c,0xc6,0x7e,0x3f,0x1f,0x8f,0xc7,0xe3,0xf1,0xfc,
+0xc0,0x7f,0x3f,0x9f,0xcf,0xe0,0xc0,0x60,0x30,0x18,0x63,0x31,0x98,0xcc,0x66,0x33,
+0x19,0x8c,0xfe,0x6b,0x31,0x98,0xcc,0x66,0x31,0xb1,0x8c,0x6c,0x0e,0x7f,0x82,0x01,
+0x01,0x80,0x90,0x30,0xc6,0x08,0x01,0x02,0x00,0x40,0x80,0xe0,0x24,0x04,0x1c,0x10,
+0x08,0x04,0x02,0x00,0x90,0x20,0x10,0x12,0x0d,0x86,0x00,0x81,0x00,0x40,0x20,0x10,
+0x00,0x04,0x00,0x1f,0xe1,0x70,0xbb,0x28,0x00,0x30,0x03,0x00,0x01,0x00,0x00,0x00,
+0x00,0x30,0x63,0x06,0x06,0x00,0x67,0xf0,0x19,0x8c,0x30,0x67,0x0d,0x80,0x00,0x01,
+0x83,0xf8,0x30,0x30,0x9b,0x7f,0x19,0x8c,0x06,0x33,0x01,0x80,0xc6,0x63,0x0c,0x01,
+0x8c,0xc6,0x05,0xd9,0x35,0x86,0x60,0x61,0x99,0x80,0xe1,0x83,0x18,0xd0,0xdc,0x26,
+0x0c,0x0c,0x06,0x00,0xc0,0x30,0x84,0x00,0x00,0x63,0x18,0xcc,0x06,0x33,0x00,0x60,
+0xc6,0x63,0x06,0x01,0x8d,0x80,0xc6,0xd9,0x8c,0xc6,0x63,0x31,0x8c,0x03,0xe1,0x83,
+0x18,0xd9,0xba,0x1c,0x1b,0x06,0x01,0x80,0xc0,0xc1,0x38,0xaa,0x80,0xc0,0x7d,0xfe,
+0xfe,0x7f,0x6f,0xcf,0x39,0xf7,0xfe,0xfd,0xff,0xbf,0x7f,0x0f,0xdb,0xfb,0xe3,0xef,
+0xf7,0xfb,0xfd,0xff,0x6f,0xdf,0xef,0xed,0xf2,0x79,0xff,0x7e,0xff,0xbf,0xdf,0xef,
+0x00,0x0c,0x19,0x03,0x03,0x60,0x60,0x30,0x66,0x00,0x28,0x4d,0xc6,0x60,0x10,0x00,
+0x84,0x00,0x00,0x04,0x0f,0x87,0x80,0x03,0x18,0x14,0x38,0x00,0x3f,0x0f,0x8c,0xc2,
+0x90,0x84,0xa4,0x18,0xfe,0x7f,0x3f,0x9f,0xcf,0xe7,0xf1,0xf0,0xc0,0x30,0x18,0x0c,
+0x06,0x01,0x80,0xc0,0x60,0x30,0x63,0x26,0xb0,0xd8,0x6c,0x36,0x1b,0x0c,0x38,0xd3,
+0x31,0x98,0xcc,0x66,0x30,0xc1,0x98,0xc6,0xc6,0x63,0x31,0x98,0xcc,0x66,0x33,0x60,
+0xc0,0x60,0x30,0x18,0x0c,0x00,0xc0,0x60,0x30,0x18,0x63,0x31,0x98,0xcc,0x66,0x33,
+0x19,0x8c,0x00,0x6b,0x31,0x98,0xcc,0x66,0x31,0xb1,0x8c,0x6c,0x1c,0x7f,0x81,0x20,
+0x90,0x38,0x18,0x0b,0x83,0x06,0x01,0x03,0x80,0x40,0xe0,0x90,0x24,0x04,0x03,0x8e,
+0x86,0xc3,0x61,0x90,0x24,0x12,0x0e,0x04,0x8a,0x81,0xc7,0x70,0xc0,0x30,0x18,0x0c,
+0x00,0x00,0x00,0x04,0x81,0x31,0x6f,0x30,0x00,0x18,0x06,0x00,0x01,0x00,0x00,0x00,
+0x00,0x60,0x63,0x06,0x0c,0x00,0x60,0x60,0x19,0x8c,0x60,0x63,0x01,0x80,0x00,0x00,
+0xc0,0x00,0x60,0x00,0x4d,0xe1,0x99,0x8c,0x06,0x33,0x01,0x80,0xc6,0x63,0x0c,0x01,
+0x8c,0xc6,0x04,0x99,0x1d,0x86,0x60,0x61,0x99,0x80,0x61,0x83,0x18,0xd0,0xdc,0x63,
+0x0c,0x0c,0x06,0x00,0x60,0x30,0x84,0x00,0x00,0x63,0x18,0xcc,0x06,0x33,0x00,0x60,
+0x6e,0x63,0x06,0x01,0x8c,0xc0,0xc6,0xd9,0x8c,0xc6,0x63,0x31,0x8c,0x00,0x61,0x83,
+0x18,0xd0,0xcc,0x26,0x0e,0x0c,0x03,0x00,0xc0,0x60,0x01,0x54,0x98,0xc0,0x7e,0xdf,
+0x6f,0xc7,0xe7,0xf4,0x7c,0xf9,0xfe,0xfc,0x7f,0xbf,0x1f,0x5f,0xdb,0xfb,0xfc,0x71,
+0x79,0x3c,0x9e,0x6f,0xdb,0xed,0xf1,0xfb,0x75,0x7e,0x38,0x8f,0x3f,0xcf,0xe7,0xf3,
+0xff,0x0c,0x0d,0x03,0x03,0xe1,0xf8,0x30,0x3c,0x00,0x27,0x40,0x03,0x30,0x00,0x00,
+0x78,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0x18,0x14,0x00,0x00,0x00,0x00,0x19,0x82,
+0xf8,0x98,0xbe,0x70,0xc3,0x61,0xb0,0xd8,0x6c,0x36,0x1b,0x30,0xc0,0x30,0x18,0x0c,
+0x06,0x01,0x80,0xc0,0x60,0x30,0x63,0x23,0xb0,0xd8,0x6c,0x36,0x1b,0x0c,0x4c,0xe3,
+0x31,0x98,0xcc,0x66,0x30,0xc1,0xf0,0xc6,0xc6,0x63,0x31,0x98,0xcc,0x66,0x33,0x60,
+0xc0,0x60,0x30,0x18,0x0c,0x00,0xc0,0x60,0x30,0x18,0x63,0x31,0x98,0xcc,0x66,0x33,
+0x19,0x8c,0x10,0x73,0x31,0x98,0xcc,0x66,0x30,0xe1,0x8c,0x38,0x1c,0x7f,0x80,0xa0,
+0x50,0x10,0x24,0x0d,0xff,0x01,0x01,0x02,0x00,0x40,0x80,0xf0,0x24,0x04,0x02,0x01,
+0x81,0x20,0x10,0x30,0x28,0x1a,0x09,0x06,0x8a,0x81,0x20,0x90,0x20,0x08,0x04,0x02,
+0x00,0x0c,0x00,0x04,0x85,0x32,0x6f,0xb8,0x00,0x18,0x06,0x00,0x01,0x01,0xc0,0x00,
+0x70,0x60,0x36,0x06,0x1f,0xcc,0xe0,0x63,0x30,0xd8,0x60,0x63,0x33,0x06,0x03,0x00,
+0x60,0x00,0xc0,0x30,0x60,0x61,0x99,0x86,0x66,0x63,0x01,0x80,0x66,0x63,0x0c,0x03,
+0x0c,0x66,0x04,0x19,0x1c,0xcc,0x60,0x33,0x18,0xcc,0x61,0x81,0xb0,0x60,0xcc,0x63,
+0x0c,0x18,0x06,0x00,0x60,0x30,0x00,0x00,0x00,0x67,0x19,0x86,0x23,0x71,0x88,0x60,
+0x36,0x63,0x06,0x01,0x8c,0x60,0xc6,0xd9,0x8c,0x6c,0x66,0x1b,0x8c,0x08,0x61,0x83,
+0xb8,0x70,0xcc,0x63,0x0c,0x18,0x03,0x00,0xc0,0x60,0x00,0xaa,0x98,0xc0,0x7f,0x5f,
+0xaf,0xef,0xdb,0xf2,0x00,0xfe,0xfe,0xfd,0xff,0xbf,0x7f,0x6f,0xdb,0xfb,0xfd,0xfe,
+0x7e,0xdf,0xef,0xcf,0xd7,0xe5,0xf6,0xf9,0x75,0x7e,0xdf,0x6f,0xdf,0xf7,0xfb,0xfd,
+0x00,0x0c,0x07,0xc6,0x04,0x10,0x60,0x30,0x06,0x00,0x10,0x80,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x3f,0x80,0x00,0x00,0x03,0xb8,0x14,0x00,0x00,0x00,0x00,0x00,0x04,
+0x11,0x21,0x04,0xc0,0xc3,0x61,0xb0,0xd8,0x6c,0x36,0x1b,0x30,0x66,0x30,0x18,0x0c,
+0x06,0x01,0x80,0xc0,0x60,0x30,0x66,0x23,0x99,0x8c,0xc6,0x63,0x31,0x98,0x00,0x66,
+0x1b,0x0d,0x86,0xc3,0x60,0xc1,0x80,0xc6,0xce,0x67,0x33,0x99,0xcc,0xe6,0x73,0x74,
+0x62,0x31,0x18,0x8c,0x46,0x20,0xc0,0x60,0x30,0x18,0x36,0x31,0x8d,0x86,0xc3,0x61,
+0xb0,0xd8,0x10,0x36,0x3b,0x9d,0xce,0xe7,0x70,0xc1,0x98,0x30,0x00,0x7f,0x80,0xc0,
+0x60,0x10,0x24,0x0c,0x38,0x0e,0x01,0x02,0x00,0x40,0x80,0xa0,0x18,0x0e,0x03,0x00,
+0x80,0x40,0x60,0x50,0x30,0x16,0x0e,0x05,0x88,0x81,0xc0,0x81,0xc0,0x70,0x38,0x1c,
+0x00,0x0c,0x00,0x04,0x83,0xe0,0x39,0xcc,0x00,0x0c,0x0c,0x00,0x00,0x01,0xc0,0x00,
+0x70,0xc0,0x1c,0x06,0x1f,0xc7,0xc0,0x61,0xe0,0x70,0x60,0x3e,0x1e,0x06,0x03,0x00,
+0x00,0x00,0x00,0x30,0x1e,0x61,0x9f,0x03,0xc7,0xc3,0xf1,0x80,0x3e,0x63,0x3f,0x1e,
+0x0c,0x67,0xe4,0x19,0x0c,0x78,0x60,0x1e,0x18,0xc7,0xc1,0x80,0xe0,0x60,0xcc,0x63,
+0x0c,0x1f,0xc6,0x00,0x30,0x30,0x00,0x00,0x00,0x3b,0x9f,0x03,0xc1,0xb0,0xf0,0x60,
+0x06,0x63,0x06,0x01,0x8c,0x70,0xc6,0xd9,0x8c,0x38,0x7c,0x0d,0x8c,0x07,0xc0,0xf1,
+0xd8,0x60,0xcc,0x63,0x0c,0x1f,0xc3,0x00,0xc0,0x60,0x01,0x54,0x80,0xc0,0x7f,0x3f,
+0x9f,0xef,0xdb,0xf3,0xc7,0xf1,0xfe,0xfd,0xff,0xbf,0x7f,0xff,0xe7,0xf1,0xfc,0xff,
+0x7f,0xbf,0x9f,0xaf,0xcf,0xe9,0xf1,0xfa,0x77,0x7e,0x3f,0x7e,0x3f,0x8f,0xc7,0xe3,
+0xff,0x0c,0x01,0x0f,0xe8,0x08,0x60,0x30,0xc6,0x00,0x0f,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0xd8,0x14,0x00,0x00,0x00,0x00,0x00,0x04,
+0x11,0x3d,0x04,0xc0,0xc3,0x61,0xb0,0xd8,0x6c,0x36,0x1b,0x3c,0x3c,0x3f,0x1f,0x8f,
+0xc7,0xe7,0xe3,0xf1,0xf8,0xfc,0x7c,0x21,0x8f,0x07,0x83,0xc1,0xe0,0xf0,0x00,0xbc,
+0x0e,0x07,0x03,0x81,0xc0,0xc1,0x80,0xcc,0x77,0x3b,0x9d,0xce,0xe7,0x73,0xb9,0x98,
+0x3c,0x1e,0x0f,0x07,0x83,0xc0,0xc0,0x60,0x30,0x18,0x1c,0x31,0x87,0x03,0x81,0xc0,
+0xe0,0x70,0x00,0x5c,0x1d,0x8e,0xc7,0x63,0xb0,0xc1,0xf0,0x30,0x00,0x7f,0x81,0x40,
+0xa0,0x10,0x28,0x0a,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x90,0x00,0x00,0x02,0x00,
+0x80,0x80,0x10,0xf8,0x28,0x12,0x09,0x04,0x80,0x01,0x20,0x80,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x06,0x18,0x00,0x00,0x00,0x40,0x00,
+0x00,0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x07,0xc0,0x31,0xf0,0x01,0xff,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0xcc,0x00,0x00,0x01,0x80,0x00,0x00,0x00,0x00,0x00,0x60,0x01,0x80,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x18,0x00,0x01,0xe0,0xc3,0xc0,0x00,0x00,0xff,0xc0,0x7e,0xbf,
+0x5f,0xef,0xd7,0xf5,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfd,0xff,
+0x7f,0x7f,0xef,0x07,0xd7,0xed,0xf6,0xfb,0x7f,0xfe,0xdf,0x7f,0xff,0xff,0xff,0xff,
+0x00,0x0c,0x01,0x00,0x00,0x00,0x00,0x30,0x7c,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0x00,0x14,0x00,0x08,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0xc6,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x81,0x80,0x60,0x00,0x7f,0x81,0x20,
+0x90,0x10,0x1c,0x0a,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0x80,
+0x81,0xe0,0x60,0x10,0x24,0x12,0x0e,0x04,0x80,0x01,0xc0,0x70,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x80,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x78,0x00,0x00,0x1f,0x00,0x00,0x00,0x00,0x00,0x00,0x60,0x01,0x80,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x18,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x7f,0xfe,0xdf,
+0x6f,0xef,0xe3,0xf5,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfc,0x7f,
+0x7e,0x1f,0x9f,0xef,0xdb,0xed,0xf1,0xfb,0x7f,0xfe,0x3f,0x8f,0xff,0xff,0xff,0xff,
+0x00,0x0c,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x30,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x7c,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x30,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x81,0x80,0x60,0x20,0x20,0x20,0x20,
+0x20,0x20,0x20,0x20,0x32,0x35,0x36,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,
+0x20,0x31,0x35,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x31,0x33,0x20,
+0x00,0x00,0x01,0x0c,0x00,0x09,0x09,0x00,0x01,0x0f,0x00,0x09,0x12,0x00,0x01,0x0f,
+0x00,0x09,0x1b,0x00,0x01,0x0f,0x00,0x09,0x24,0x00,0x01,0x0f,0x00,0x09,0x2d,0x00,
+0x01,0x0f,0x00,0x09,0x36,0x00,0x01,0x0f,0x00,0x09,0x3f,0x00,0x03,0x0d,0x00,0x09,
+0x48,0x00,0x03,0x0d,0x00,0x09,0x51,0x00,0x03,0x0d,0x00,0x09,0x5a,0x00,0x03,0x0d,
+0x00,0x09,0x63,0x00,0x03,0x0d,0x00,0x09,0x6c,0x00,0x03,0x0d,0x00,0x09,0x75,0x00,
+0x03,0x0e,0x00,0x09,0x7e,0x00,0x03,0x0d,0x00,0x09,0x87,0x00,0x03,0x0d,0x00,0x09,
+0x90,0x00,0x01,0x0f,0x00,0x09,0x99,0x00,0x01,0x0f,0x00,0x09,0xa2,0x00,0x01,0x0f,
+0x00,0x09,0xab,0x00,0x01,0x0f,0x00,0x09,0xb4,0x00,0x01,0x0f,0x00,0x09,0xbd,0x00,
+0x01,0x0f,0x00,0x09,0xc6,0x00,0x01,0x0f,0x00,0x09,0xcf,0x00,0x01,0x0f,0x00,0x09,
+0xd8,0x00,0x01,0x0f,0x00,0x09,0xe1,0x00,0x03,0x0d,0x00,0x09,0xea,0x00,0x01,0x0f,
+0x00,0x09,0xf3,0x00,0x01,0x0f,0x00,0x09,0xfc,0x00,0x03,0x0d,0x00,0x09,0x05,0x01,
+0x03,0x0d,0x00,0x09,0x0e,0x01,0x03,0x0d,0x00,0x09,0x17,0x01,0x03,0x0d,0x00,0x09,
+0x20,0x01,0x00,0x00,0x00,0x09,0x29,0x01,0x03,0x0d,0x00,0x09,0x32,0x01,0x02,0x05,
+0x00,0x09,0x3b,0x01,0x03,0x0d,0x00,0x09,0x44,0x01,0x02,0x0e,0x00,0x09,0x4d,0x01,
+0x03,0x0d,0x00,0x09,0x56,0x01,0x03,0x0d,0x00,0x09,0x5f,0x01,0x02,0x06,0x00,0x09,
+0x68,0x01,0x02,0x0e,0x00,0x09,0x71,0x01,0x02,0x0e,0x00,0x09,0x7a,0x01,0x03,0x08,
+0x00,0x09,0x83,0x01,0x05,0x0c,0x00,0x09,0x8c,0x01,0x0b,0x0f,0x00,0x09,0x95,0x01,
+0x08,0x09,0x00,0x09,0x9e,0x01,0x0b,0x0d,0x00,0x09,0xa7,0x01,0x02,0x0e,0x00,0x09,
+0xb0,0x01,0x03,0x0d,0x00,0x09,0xb9,0x01,0x03,0x0d,0x00,0x09,0xc2,0x01,0x03,0x0d,
+0x00,0x09,0xcb,0x01,0x03,0x0d,0x00,0x09,0xd4,0x01,0x03,0x0d,0x00,0x09,0xdd,0x01,
+0x03,0x0d,0x00,0x09,0xe6,0x01,0x03,0x0d,0x00,0x09,0xef,0x01,0x03,0x0d,0x00,0x09,
+0xf8,0x01,0x03,0x0d,0x00,0x09,0x01,0x02,0x03,0x0d,0x00,0x09,0x0a,0x02,0x06,0x0d,
+0x00,0x09,0x13,0x02,0x06,0x0f,0x00,0x09,0x1c,0x02,0x05,0x0c,0x00,0x09,0x25,0x02,
+0x07,0x0a,0x00,0x09,0x2e,0x02,0x05,0x0c,0x00,0x09,0x37,0x02,0x03,0x0d,0x00,0x09,
+0x40,0x02,0x03,0x0d,0x00,0x09,0x49,0x02,0x03,0x0d,0x00,0x09,0x52,0x02,0x03,0x0d,
+0x00,0x09,0x5b,0x02,0x03,0x0d,0x00,0x09,0x64,0x02,0x03,0x0d,0x00,0x09,0x6d,0x02,
+0x03,0x0d,0x00,0x09,0x76,0x02,0x03,0x0d,0x00,0x09,0x7f,0x02,0x03,0x0d,0x00,0x09,
+0x88,0x02,0x03,0x0d,0x00,0x09,0x91,0x02,0x03,0x0d,0x00,0x09,0x9a,0x02,0x03,0x0d,
+0x00,0x09,0xa3,0x02,0x03,0x0d,0x00,0x09,0xac,0x02,0x03,0x0d,0x00,0x09,0xb5,0x02,
+0x03,0x0d,0x00,0x09,0xbe,0x02,0x03,0x0d,0x00,0x09,0xc7,0x02,0x03,0x0d,0x00,0x09,
+0xd0,0x02,0x03,0x0d,0x00,0x09,0xd9,0x02,0x03,0x0f,0x00,0x09,0xe2,0x02,0x03,0x0d,
+0x00,0x09,0xeb,0x02,0x03,0x0d,0x00,0x09,0xf4,0x02,0x03,0x0d,0x00,0x09,0xfd,0x02,
+0x03,0x0d,0x00,0x09,0x06,0x03,0x03,0x0d,0x00,0x09,0x0f,0x03,0x03,0x0d,0x00,0x09,
+0x18,0x03,0x03,0x0d,0x00,0x09,0x21,0x03,0x03,0x0d,0x00,0x09,0x2a,0x03,0x03,0x0d,
+0x00,0x09,0x33,0x03,0x02,0x0e,0x00,0x09,0x3c,0x03,0x02,0x0e,0x00,0x09,0x45,0x03,
+0x02,0x0e,0x00,0x09,0x4e,0x03,0x04,0x0b,0x00,0x09,0x57,0x03,0x0d,0x0e,0x00,0x09,
+0x60,0x03,0x02,0x06,0x00,0x09,0x69,0x03,0x05,0x0d,0x00,0x09,0x72,0x03,0x02,0x0d,
+0x00,0x09,0x7b,0x03,0x05,0x0d,0x00,0x09,0x84,0x03,0x02,0x0d,0x00,0x09,0x8d,0x03,
+0x05,0x0d,0x00,0x09,0x96,0x03,0x02,0x0d,0x00,0x09,0x9f,0x03,0x05,0x0f,0x00,0x09,
+0xa8,0x03,0x02,0x0d,0x00,0x09,0xb1,0x03,0x02,0x0d,0x00,0x09,0xba,0x03,0x02,0x0f,
+0x00,0x09,0xc3,0x03,0x02,0x0d,0x00,0x09,0xcc,0x03,0x02,0x0d,0x00,0x09,0xd5,0x03,
+0x05,0x0d,0x00,0x09,0xde,0x03,0x05,0x0d,0x00,0x09,0xe7,0x03,0x05,0x0d,0x00,0x09,
+0xf0,0x03,0x05,0x0f,0x00,0x09,0xf9,0x03,0x05,0x0f,0x00,0x09,0x02,0x04,0x05,0x0d,
+0x00,0x09,0x0b,0x04,0x05,0x0d,0x00,0x09,0x14,0x04,0x03,0x0d,0x00,0x09,0x1d,0x04,
+0x05,0x0d,0x00,0x09,0x26,0x04,0x05,0x0d,0x00,0x09,0x2f,0x04,0x05,0x0d,0x00,0x09,
+0x38,0x04,0x05,0x0d,0x00,0x09,0x41,0x04,0x05,0x0f,0x00,0x09,0x4a,0x04,0x05,0x0d,
+0x00,0x09,0x53,0x04,0x02,0x0e,0x00,0x09,0x5c,0x04,0x02,0x0e,0x00,0x09,0x65,0x04,
+0x02,0x0e,0x00,0x09,0x6e,0x04,0x07,0x0a,0x00,0x09,0x77,0x04,0x01,0x0d,0x00,0x09,
+0x80,0x04,0x00,0x0e,0x00,0x09,0x89,0x04,0x00,0x0f,0x00,0x09,0x92,0x04,0x00,0x0f,
+0x00,0x09,0x9b,0x04,0x00,0x0f,0x00,0x09,0xa4,0x04,0x00,0x0f,0x00,0x09,0xad,0x04,
+0x00,0x0f,0x00,0x09,0xb6,0x04,0x00,0x0f,0x00,0x09,0xbf,0x04,0x00,0x0f,0x00,0x09,
+0xc8,0x04,0x00,0x0f,0x00,0x09,0xd1,0x04,0x00,0x0f,0x00,0x09,0xda,0x04,0x00,0x0f,
+0x00,0x09,0xe3,0x04,0x00,0x0f,0x00,0x09,0xec,0x04,0x00,0x0f,0x00,0x09,0xf5,0x04,
+0x00,0x0f,0x00,0x09,0xfe,0x04,0x00,0x0f,0x00,0x09,0x07,0x05,0x00,0x0f,0x00,0x09,
+0x10,0x05,0x00,0x0f,0x00,0x09,0x19,0x05,0x00,0x0f,0x00,0x09,0x22,0x05,0x00,0x0f,
+0x00,0x09,0x2b,0x05,0x00,0x0f,0x00,0x09,0x34,0x05,0x00,0x0f,0x00,0x09,0x3d,0x05,
+0x00,0x0f,0x00,0x09,0x46,0x05,0x00,0x0f,0x00,0x09,0x4f,0x05,0x00,0x0f,0x00,0x09,
+0x58,0x05,0x00,0x0f,0x00,0x09,0x61,0x05,0x00,0x0f,0x00,0x09,0x6a,0x05,0x00,0x0f,
+0x00,0x09,0x73,0x05,0x00,0x0f,0x00,0x09,0x7c,0x05,0x00,0x0f,0x00,0x09,0x85,0x05,
+0x00,0x0f,0x00,0x09,0x8e,0x05,0x00,0x0f,0x00,0x09,0x97,0x05,0x00,0x0f,0x00,0x09,
+0xa0,0x05,0x00,0x0d,0x00,0x09,0xa9,0x05,0x05,0x0f,0x00,0x09,0xb2,0x05,0x02,0x0e,
+0x00,0x09,0xbb,0x05,0x03,0x0d,0x00,0x09,0xc4,0x05,0x03,0x0d,0x00,0x09,0xcd,0x05,
+0x03,0x0d,0x00,0x09,0xd6,0x05,0x02,0x0e,0x00,0x09,0xdf,0x05,0x03,0x0e,0x00,0x09,
+0xe8,0x05,0x02,0x04,0x00,0x09,0xf1,0x05,0x03,0x0d,0x00,0x09,0xfa,0x05,0x03,0x0a,
+0x00,0x09,0x03,0x06,0x06,0x0b,0x00,0x09,0x0c,0x06,0x07,0x0a,0x00,0x09,0x15,0x06,
+0x08,0x09,0x00,0x09,0x1e,0x06,0x03,0x0b,0x00,0x09,0x27,0x06,0x02,0x03,0x00,0x09,
+0x30,0x06,0x03,0x07,0x00,0x09,0x39,0x06,0x05,0x0c,0x00,0x09,0x42,0x06,0x03,0x0a,
+0x00,0x09,0x4b,0x06,0x03,0x0a,0x00,0x09,0x54,0x06,0x02,0x04,0x00,0x09,0x5d,0x06,
+0x05,0x0f,0x00,0x09,0x66,0x06,0x03,0x0e,0x00,0x09,0x6f,0x06,0x08,0x0a,0x00,0x09,
+0x78,0x06,0x0d,0x0f,0x00,0x09,0x81,0x06,0x03,0x0a,0x00,0x09,0x8a,0x06,0x03,0x0a,
+0x00,0x09,0x93,0x06,0x06,0x0b,0x00,0x09,0x9c,0x06,0x03,0x0d,0x00,0x09,0xa5,0x06,
+0x03,0x0d,0x00,0x09,0xae,0x06,0x03,0x0d,0x00,0x09,0xb7,0x06,0x05,0x0f,0x00,0x09,
+0xc0,0x06,0x00,0x0d,0x00,0x09,0xc9,0x06,0x00,0x0d,0x00,0x09,0xd2,0x06,0x00,0x0d,
+0x00,0x09,0xdb,0x06,0x00,0x0d,0x00,0x09,0xe4,0x06,0x00,0x0d,0x00,0x09,0xed,0x06,
+0x01,0x0d,0x00,0x09,0xf6,0x06,0x03,0x0d,0x00,0x09,0xff,0x06,0x03,0x0f,0x00,0x09,
+0x08,0x07,0x00,0x0d,0x00,0x09,0x11,0x07,0x00,0x0d,0x00,0x09,0x1a,0x07,0x00,0x0d,
+0x00,0x09,0x23,0x07,0x00,0x0d,0x00,0x09,0x2c,0x07,0x00,0x0d,0x00,0x09,0x35,0x07,
+0x00,0x0d,0x00,0x09,0x3e,0x07,0x00,0x0d,0x00,0x09,0x47,0x07,0x00,0x0d,0x00,0x09,
+0x50,0x07,0x03,0x0d,0x00,0x09,0x59,0x07,0x00,0x0d,0x00,0x09,0x62,0x07,0x00,0x0d,
+0x00,0x09,0x6b,0x07,0x00,0x0d,0x00,0x09,0x74,0x07,0x00,0x0d,0x00,0x09,0x7d,0x07,
+0x00,0x0d,0x00,0x09,0x86,0x07,0x00,0x0d,0x00,0x09,0x8f,0x07,0x06,0x0b,0x00,0x09,
+0x98,0x07,0x03,0x0d,0x00,0x09,0xa1,0x07,0x00,0x0d,0x00,0x09,0xaa,0x07,0x00,0x0d,
+0x00,0x09,0xb3,0x07,0x00,0x0d,0x00,0x09,0xbc,0x07,0x00,0x0d,0x00,0x09,0xc5,0x07,
+0x00,0x0d,0x00,0x09,0xce,0x07,0x03,0x0d,0x00,0x09,0xd7,0x07,0x02,0x0d,0x00,0x09,
+0xe0,0x07,0x02,0x0d,0x00,0x09,0xe9,0x07,0x02,0x0d,0x00,0x09,0xf2,0x07,0x02,0x0d,
+0x00,0x09,0xfb,0x07,0x02,0x0d,0x00,0x09,0x04,0x08,0x02,0x0d,0x00,0x09,0x0d,0x08,
+0x02,0x0d,0x00,0x09,0x16,0x08,0x05,0x0d,0x00,0x09,0x1f,0x08,0x05,0x0f,0x00,0x09,
+0x28,0x08,0x02,0x0d,0x00,0x09,0x31,0x08,0x02,0x0d,0x00,0x09,0x3a,0x08,0x02,0x0d,
+0x00,0x09,0x43,0x08,0x02,0x0d,0x00,0x09,0x4c,0x08,0x02,0x0d,0x00,0x09,0x55,0x08,
+0x02,0x0d,0x00,0x09,0x5e,0x08,0x02,0x0d,0x00,0x09,0x67,0x08,0x02,0x0d,0x00,0x09,
+0x70,0x08,0x02,0x0d,0x00,0x09,0x79,0x08,0x02,0x0d,0x00,0x09,0x82,0x08,0x02,0x0d,
+0x00,0x09,0x8b,0x08,0x02,0x0d,0x00,0x09,0x94,0x08,0x02,0x0d,0x00,0x09,0x9d,0x08,
+0x02,0x0d,0x00,0x09,0xa6,0x08,0x02,0x0d,0x00,0x09,0xaf,0x08,0x05,0x0c,0x00,0x09,
+0xb8,0x08,0x05,0x0d,0x00,0x09,0xc1,0x08,0x02,0x0d,0x00,0x09,0xca,0x08,0x02,0x0d,
+0x00,0x09,0xd3,0x08,0x02,0x0d,0x00,0x09,0xdc,0x08,0x02,0x0d,0x00,0x09,0xe5,0x08,
+0x02,0x0f,0x00,0x09,0xee,0x08,0x03,0x0f,0x00,0x09,0xf7,0x08,0x02,0x0f,0x00,0x09,
+0x00,0x09,0x00,0x00,0x00,0x00,
+};
+
+int sizeofdefont = sizeof defontdata;
+
+void
+_unpackinfo(Fontchar *fc, uchar *p, int n)
+{
+ int j;
+
+ for(j=0; j<=n; j++){
+ fc->x = p[0]|(p[1]<<8);
+ fc->top = p[2];
+ fc->bottom = p[3];
+ fc->left = p[4];
+ fc->width = p[5];
+ fc++;
+ p += 6;
+ }
+}
--- /dev/null
+++ b/libdraw/draw.c
@@ -1,0 +1,68 @@
+#include "lib9.h"
+#include "draw.h"
+
+void
+_setdrawop(Display *d, Drawop op)
+{
+ uchar *a;
+
+ if(op != SoverD){
+ a = bufimage(d, 1+1);
+ if(a == 0)
+ return;
+ a[0] = 'O';
+ a[1] = op;
+ }
+}
+
+static void
+draw1(Image *dst, Rectangle *r, Image *src, Point *p0, Image *mask, Point *p1, Drawop op)
+{
+ uchar *a;
+
+ _setdrawop(dst->display, op);
+
+ a = bufimage(dst->display, 1+4+4+4+4*4+2*4+2*4);
+ if(a == 0)
+ return;
+ if(src == nil)
+ src = dst->display->black;
+ if(mask == nil)
+ mask = dst->display->opaque;
+ a[0] = 'd';
+ BPLONG(a+1, dst->id);
+ BPLONG(a+5, src->id);
+ BPLONG(a+9, mask->id);
+ BPLONG(a+13, r->min.x);
+ BPLONG(a+17, r->min.y);
+ BPLONG(a+21, r->max.x);
+ BPLONG(a+25, r->max.y);
+ BPLONG(a+29, p0->x);
+ BPLONG(a+33, p0->y);
+ BPLONG(a+37, p1->x);
+ BPLONG(a+41, p1->y);
+}
+
+void
+draw(Image *dst, Rectangle r, Image *src, Image *mask, Point p1)
+{
+ draw1(dst, &r, src, &p1, mask, &p1, SoverD);
+}
+
+void
+drawop(Image *dst, Rectangle r, Image *src, Image *mask, Point p1, Drawop op)
+{
+ draw1(dst, &r, src, &p1, mask, &p1, op);
+}
+
+void
+gendraw(Image *dst, Rectangle r, Image *src, Point p0, Image *mask, Point p1)
+{
+ draw1(dst, &r, src, &p0, mask, &p1, SoverD);
+}
+
+void
+gendrawop(Image *dst, Rectangle r, Image *src, Point p0, Image *mask, Point p1, Drawop op)
+{
+ draw1(dst, &r, src, &p0, mask, &p1, op);
+}
--- /dev/null
+++ b/libdraw/drawrepl.c
@@ -1,0 +1,22 @@
+#include "lib9.h"
+#include "draw.h"
+
+int
+drawreplxy(int min, int max, int x)
+{
+ int sx;
+
+ sx = (x-min)%(max-min);
+ if(sx < 0)
+ sx += max-min;
+ return sx+min;
+}
+
+Point
+drawrepl(Rectangle r, Point p)
+{
+ p.x = drawreplxy(r.min.x, r.max.x, p.x);
+ p.y = drawreplxy(r.min.y, r.max.y, p.y);
+ return p;
+}
+
--- /dev/null
+++ b/libdraw/ellipse.c
@@ -1,0 +1,81 @@
+#include "lib9.h"
+#include "draw.h"
+
+static
+void
+doellipse(int cmd, Image *dst, Point *c, int xr, int yr, int thick, Image *src, Point *sp, int alpha, int phi, Drawop op)
+{
+ uchar *a;
+
+ _setdrawop(dst->display, op);
+
+ a = bufimage(dst->display, 1+4+4+2*4+4+4+4+2*4+2*4);
+ if(a == 0){
+ _drawprint(2, "image ellipse: %r\n");
+ return;
+ }
+ a[0] = cmd;
+ BPLONG(a+1, dst->id);
+ BPLONG(a+5, src->id);
+ BPLONG(a+9, c->x);
+ BPLONG(a+13, c->y);
+ BPLONG(a+17, xr);
+ BPLONG(a+21, yr);
+ BPLONG(a+25, thick);
+ BPLONG(a+29, sp->x);
+ BPLONG(a+33, sp->y);
+ BPLONG(a+37, alpha);
+ BPLONG(a+41, phi);
+}
+
+void
+ellipse(Image *dst, Point c, int a, int b, int thick, Image *src, Point sp)
+{
+ doellipse('e', dst, &c, a, b, thick, src, &sp, 0, 0, SoverD);
+}
+
+void
+ellipseop(Image *dst, Point c, int a, int b, int thick, Image *src, Point sp, Drawop op)
+{
+ doellipse('e', dst, &c, a, b, thick, src, &sp, 0, 0, op);
+}
+
+void
+fillellipse(Image *dst, Point c, int a, int b, Image *src, Point sp)
+{
+ doellipse('E', dst, &c, a, b, 0, src, &sp, 0, 0, SoverD);
+}
+
+void
+fillellipseop(Image *dst, Point c, int a, int b, Image *src, Point sp, Drawop op)
+{
+ doellipse('E', dst, &c, a, b, 0, src, &sp, 0, 0, op);
+}
+
+void
+arc(Image *dst, Point c, int a, int b, int thick, Image *src, Point sp, int alpha, int phi)
+{
+ alpha |= 1<<31;
+ doellipse('e', dst, &c, a, b, thick, src, &sp, alpha, phi, SoverD);
+}
+
+void
+arcop(Image *dst, Point c, int a, int b, int thick, Image *src, Point sp, int alpha, int phi, Drawop op)
+{
+ alpha |= 1<<31;
+ doellipse('e', dst, &c, a, b, thick, src, &sp, alpha, phi, op);
+}
+
+void
+fillarc(Image *dst, Point c, int a, int b, Image *src, Point sp, int alpha, int phi)
+{
+ alpha |= 1<<31;
+ doellipse('E', dst, &c, a, b, 0, src, &sp, alpha, phi, SoverD);
+}
+
+void
+fillarcop(Image *dst, Point c, int a, int b, Image *src, Point sp, int alpha, int phi, Drawop op)
+{
+ alpha |= 1<<31;
+ doellipse('E', dst, &c, a, b, 0, src, &sp, alpha, phi, op);
+}
--- /dev/null
+++ b/libdraw/font.c
@@ -1,0 +1,398 @@
+#include "lib9.h"
+#include "draw.h"
+
+static int fontresize(Font*, int, int, int);
+static int freeup(Font*);
+
+#define PJW 0 /* use NUL==pjw for invisible characters */
+
+int
+cachechars(Font *f, char **ss, Rune **rr, ushort *cp, int max, int *wp, char **subfontname)
+{
+ int i, th, sh, h, ld, w, rw, wid, nc;
+ char *sp;
+ Rune r, *rp, vr;
+ ulong a;
+ Cacheinfo *c, *tc, *ec;
+
+ if(ss){
+ sp = *ss;
+ rp = (Rune*) L"";
+ }else{
+ sp = "";
+ rp = *rr;
+ }
+ wid = 0;
+ *subfontname = 0;
+ for(i=0; (*sp || *rp) && i<max; sp+=w, rp+=rw){
+ if(ss){
+ r = *(uchar*)sp;
+ if(r < Runeself)
+ w = 1;
+ else{
+ w = chartorune(&vr, sp);
+ r = vr;
+ }
+ rw = 0;
+ }else{
+ r = *rp;
+ w = 0;
+ rw = 1;
+ }
+
+ sh = (17 * (uint)r) & (f->ncache-NFLOOK-1);
+ c = &f->cache[sh];
+ ec = c+NFLOOK;
+ h = sh;
+ while(c < ec){
+ if(c->value==r && c->age)
+ goto Found;
+ c++;
+ h++;
+ }
+
+ /*
+ * Not found; toss out oldest entry
+ */
+ a = ~0;
+ th = sh;
+ tc = &f->cache[th];
+ while(tc < ec){
+ if(tc->age < a){
+ a = tc->age;
+ h = th;
+ c = tc;
+ }
+ tc++;
+ th++;
+ }
+
+ if(a && (f->age-a)<500){ /* kicking out too recent; resize */
+ nc = 2*(f->ncache-NFLOOK) + NFLOOK;
+ if(nc <= MAXFCACHE){
+ if(i == 0)
+ fontresize(f, f->width, nc, f->maxdepth);
+ /* else flush first; retry will resize */
+ break;
+ }
+ }
+
+ if(c->age == f->age) /* flush pending string output */
+ break;
+
+ ld = loadchar(f, r, c, h, i, subfontname);
+ if(ld <= 0){
+ if(ld == 0)
+ continue;
+ break;
+ }
+ c = &f->cache[h]; /* may have reallocated f->cache */
+
+ Found:
+ wid += c->width;
+ c->age = f->age;
+ cp[i] = h;
+ i++;
+ }
+ if(ss)
+ *ss = sp;
+ else
+ *rr = rp;
+ *wp = wid;
+ return i;
+}
+
+void
+agefont(Font *f)
+{
+ Cacheinfo *c, *ec;
+ Cachesubf *s, *es;
+
+ f->age++;
+ if(f->age == 65536){
+ /*
+ * Renormalize ages
+ */
+ c = f->cache;
+ ec = c+f->ncache;
+ while(c < ec){
+ if(c->age){
+ c->age >>= 2;
+ c->age++;
+ }
+ c++;
+ }
+ s = f->subf;
+ es = s+f->nsubf;
+ while(s < es){
+ if(s->age){
+ if(s->age<SUBFAGE && s->cf->name != nil){
+ /* clean up */
+/* if(s->f != display->defaultsubfont) */ /* plan 9 uses this */
+ if(s->f)
+ freesubfont(s->f);
+ s->cf = nil;
+ s->f = nil;
+ s->age = 0;
+ }else{
+ s->age >>= 2;
+ s->age++;
+ }
+ }
+ s++;
+ }
+ f->age = (65536>>2) + 1;
+ }
+}
+
+static Subfont*
+cf2subfont(Cachefont *cf, Font *f)
+{
+ char *name;
+ Subfont *sf;
+ int depth;
+
+ name = cf->subfontname;
+ if(name == nil){
+ depth = 0;
+ if(f->display){
+ if(f->display->image)
+ depth = f->display->image->depth;
+ }
+ name = subfontname(cf->name, f->name, depth);
+ if(name == nil)
+ return nil;
+ cf->subfontname = name;
+ }
+ sf = lookupsubfont(f->display, name);
+ return sf;
+}
+
+/* return 1 if load succeeded, 0 if failed, -1 if must retry */
+int
+loadchar(Font *f, Rune r, Cacheinfo *c, int h, int noflush, char **subfontname)
+{
+ int i, oi, wid, top, bottom;
+ Rune pic;
+ Fontchar *fi;
+ Cachefont *cf;
+ Cachesubf *subf, *of;
+ uchar *b;
+
+ pic = r;
+ Again:
+ for(i=0; i<f->nsub; i++){
+ cf = f->sub[i];
+ if(cf->min<=pic && pic<=cf->max)
+ goto Found;
+ }
+ TryPJW:
+ if(pic != PJW){
+ pic = PJW;
+ goto Again;
+ }
+ return 0;
+
+ Found:
+ /*
+ * Choose exact or oldest
+ */
+ oi = 0;
+ subf = &f->subf[0];
+ for(i=0; i<f->nsubf; i++){
+ if(cf == subf->cf)
+ goto Found2;
+ if(subf->age < f->subf[oi].age)
+ oi = i;
+ subf++;
+ }
+ subf = &f->subf[oi];
+
+ if(subf->f){
+ if(f->age-subf->age>SUBFAGE || f->nsubf>MAXSUBF){
+ Toss:
+ /* ancient data; toss */
+ freesubfont(subf->f);
+ subf->cf = nil;
+ subf->f = nil;
+ subf->age = 0;
+ }else{ /* too recent; grow instead */
+ of = f->subf;
+ f->subf = malloc((f->nsubf+DSUBF)*sizeof *subf);
+ if(f->subf == nil){
+ f->subf = of;
+ goto Toss;
+ }
+ memmove(f->subf, of, (f->nsubf+DSUBF)*sizeof *subf);
+ memset(f->subf+f->nsubf, 0, DSUBF*sizeof *subf);
+ subf = &f->subf[f->nsubf];
+ f->nsubf += DSUBF;
+ free(of);
+ }
+ }
+ subf->age = 0;
+ subf->cf = nil;
+ subf->f = cf2subfont(cf, f);
+ if(subf->f == nil){
+ if(cf->subfontname == nil)
+ goto TryPJW;
+ *subfontname = cf->subfontname;
+ return -1;
+ }
+
+ subf->cf = cf;
+ if(subf->f->ascent > f->ascent){
+ /* should print something? this is a mistake in the font file */
+ /* must prevent c->top from going negative when loading cache */
+ Image *b;
+ int d, t;
+ d = subf->f->ascent - f->ascent;
+ b = subf->f->bits;
+ draw(b, b->r, b, nil, addpt(b->r.min, Pt(0, d)));
+ draw(b, Rect(b->r.min.x, b->r.max.y-d, b->r.max.x, b->r.max.y), f->display->black, nil, b->r.min);
+ for(i=0; i<subf->f->n; i++){
+ t = subf->f->info[i].top-d;
+ if(t < 0)
+ t = 0;
+ subf->f->info[i].top = t;
+ t = subf->f->info[i].bottom-d;
+ if(t < 0)
+ t = 0;
+ subf->f->info[i].bottom = t;
+ }
+ subf->f->ascent = f->ascent;
+ }
+
+ Found2:
+ subf->age = f->age;
+
+ pic += cf->offset;
+ if(pic-cf->min >= subf->f->n)
+ goto TryPJW;
+ fi = &subf->f->info[pic - cf->min];
+ if(fi->width == 0)
+ goto TryPJW;
+ wid = (fi+1)->x - fi->x;
+ if(f->width < wid || f->width == 0 || f->maxdepth < subf->f->bits->depth){
+ /*
+ * Flush, free, reload (easier than reformatting f->b)
+ */
+ if(noflush)
+ return -1;
+ if(f->width < wid)
+ f->width = wid;
+ if(f->maxdepth < subf->f->bits->depth)
+ f->maxdepth = subf->f->bits->depth;
+ i = fontresize(f, f->width, f->ncache, f->maxdepth);
+ if(i <= 0)
+ return i;
+ /* c is still valid as didn't reallocate f->cache */
+ }
+ c->value = r;
+ top = fi->top + (f->ascent-subf->f->ascent);
+ bottom = fi->bottom + (f->ascent-subf->f->ascent);
+ c->width = fi->width;
+ c->x = h*f->width;
+ c->left = fi->left;
+ flushimage(f->display, 0); /* flush any pending errors */
+ if (f->cacheimage == 0)
+ return 0;
+ b = bufimage(f->display, 37);
+ if(b == 0)
+ return 0;
+ b[0] = 'l';
+ BPLONG(b+1, f->cacheimage->id);
+ BPLONG(b+5, subf->f->bits->id);
+ BPSHORT(b+9, c-f->cache);
+ BPLONG(b+11, c->x);
+ BPLONG(b+15, top);
+ BPLONG(b+19, c->x+((fi+1)->x-fi->x));
+ BPLONG(b+23, bottom);
+ BPLONG(b+27, fi->x);
+ BPLONG(b+31, fi->top);
+ b[35] = fi->left;
+ b[36] = fi->width;
+ return 1;
+}
+
+/* release all subfonts, return number freed */
+static
+int
+freeup(Font *f)
+{
+ Cachesubf *s, *es;
+ int nf;
+
+ if(f->sub[0]->name == nil) /* font from mkfont; don't free */
+ return 0;
+ s = f->subf;
+ es = s+f->nsubf;
+ nf = 0;
+ while(s < es){
+ if(s->age){
+ freesubfont(s->f);
+ s->cf = nil;
+ s->f = nil;
+ s->age = 0;
+ nf++;
+ }
+ s++;
+ }
+ return nf;
+}
+
+/* return whether resize succeeded && f->cache is unchanged */
+static int
+fontresize(Font *f, int wid, int ncache, int depth)
+{
+ Cacheinfo *i;
+ int ret;
+ Image *new;
+ uchar *b;
+ Display *d;
+
+ ret = 0;
+ d = f->display;
+ if(depth <= 0)
+ depth = 1;
+
+ new = allocimage(d, Rect(0, 0, ncache*wid, f->height), CHAN1(CGrey, depth), 0, 0);
+ if(new == nil){
+ _drawprint(2, "font cache resize failed: %r\n");
+/* abort(); */
+ goto Return;
+ }
+ flushimage(d, 0); /* flush any pending errors */
+ b = bufimage(d, 1+4+4+1);
+ if(b == 0){
+ freeimage(new);
+ goto Return;
+ }
+ b[0] = 'i';
+ BPLONG(b+1, new->id);
+ BPLONG(b+5, ncache);
+ b[9] = f->ascent;
+ if(flushimage(d, 0) < 0){
+ _drawprint(2, "resize: init failed: %r\n");
+ freeimage(new);
+ goto Return;
+ }
+ freeimage(f->cacheimage);
+ f->cacheimage = new;
+ f->width = wid;
+ f->maxdepth = depth;
+ ret = 1;
+ if(f->ncache != ncache){
+ i = malloc(ncache*sizeof f->cache[0]);
+ if(i != nil){
+ ret = 0;
+ free(f->cache);
+ f->ncache = ncache;
+ f->cache = i;
+ }
+ /* else just wipe the cache clean and things will be ok */
+ }
+ Return:
+ memset(f->cache, 0, f->ncache*sizeof f->cache[0]);
+ return ret;
+}
--- /dev/null
+++ b/libdraw/freesubfont.c
@@ -1,0 +1,16 @@
+#include "lib9.h"
+#include "draw.h"
+
+void
+freesubfont(Subfont *f)
+{
+ if(f == 0)
+ return;
+ f->ref--;
+ if(f->ref > 0)
+ return;
+ uninstallsubfont(f);
+ free(f->info); /* note: f->info must have been malloc'ed! */
+ freeimage(f->bits);
+ free(f);
+}
--- /dev/null
+++ b/libdraw/getdefont.c
@@ -1,0 +1,59 @@
+#include "lib9.h"
+#include "draw.h"
+
+Subfont*
+getdefont(Display *d)
+{
+ char *hdr, *p;
+ int n;
+ Fontchar *fc;
+ Subfont *f;
+ int ld;
+ Rectangle r;
+ Image *i;
+
+ /*
+ * make sure data is word-aligned. this is true with Plan 9 compilers
+ * but not in general. the byte order is right because the data is
+ * declared as char*, not ulong*.
+ */
+ p = (char*)defontdata;
+ n = (ulong)p & 3;
+ if(n != 0){
+ memmove(p+(4-n), p, sizeofdefont-n);
+ p += 4-n;
+ }
+ ld = atoi(p+0*12);
+ r.min.x = atoi(p+1*12);
+ r.min.y = atoi(p+2*12);
+ r.max.x = atoi(p+3*12);
+ r.max.y = atoi(p+4*12);
+
+ i = allocimage(d, r, drawld2chan[ld], 0, 0);
+ if(i == 0)
+ return 0;
+
+ p += 5*12;
+ n = loadimage(i, r, (uchar*)p, (defontdata+sizeofdefont)-(uchar*)p);
+ if(n < 0){
+ freeimage(i);
+ return 0;
+ }
+
+ hdr = p+n;
+ n = atoi(hdr);
+ p = hdr+3*12;
+ fc = malloc(sizeof(Fontchar)*(n+1));
+ if(fc == 0){
+ freeimage(i);
+ return 0;
+ }
+ _unpackinfo(fc, (uchar*)p, n);
+ f = allocsubfont("*default*", n, atoi(hdr+12), atoi(hdr+24), fc, i);
+ if(f == 0){
+ freeimage(i);
+ free(fc);
+ return 0;
+ }
+ return f;
+}
--- /dev/null
+++ b/libdraw/getsubfont.c
@@ -1,0 +1,36 @@
+#include "lib9.h"
+#include "kernel.h"
+#include "draw.h"
+
+/*
+ * Default version: treat as file name
+ */
+
+Subfont*
+_getsubfont(Display *d, char *name)
+{
+ int fd;
+ Subfont *f;
+
+ fd = libopen(name, OREAD);
+
+ if(fd < 0){
+ _drawprint(2, "getsubfont: can't open %s: %r\n", name);
+ return 0;
+ }
+ /*
+ * unlock display so i/o happens with display released, unless
+ * user is doing his own locking, in which case this could break things.
+ * _getsubfont is called only from string.c and stringwidth.c,
+ * which are known to be safe to have this done.
+ */
+ if(d->local == 0)
+ unlockdisplay(d);
+ f = readsubfont(d, name, fd, d->local == 0);
+ if(d->local == 0)
+ lockdisplay(d);
+ if(f == 0)
+ _drawprint(2, "getsubfont: can't read %s: %r\n", name);
+ libclose(fd);
+ return f;
+}
--- /dev/null
+++ b/libdraw/init.c
@@ -1,0 +1,341 @@
+#include "lib9.h"
+#include "draw.h"
+#include "kernel.h"
+#include "interp.h"
+
+int _drawdebug;
+
+enum {
+ CHECKLOCKING = 0
+};
+
+/*
+ * Attach, or possibly reattach, to window.
+ * If reattaching, maintain value of screen pointer.
+ */
+int
+gengetwindow(Display *d, char *winname, Image **winp, Screen **scrp, int ref)
+{
+ int n, fd;
+ char buf[64+1];
+ Image *image;
+
+ fd = libopen(winname, OREAD);
+ if(fd<0 || (n=libread(fd, buf, sizeof buf-1))<=0){
+ *winp = d->image;
+ assert(*winp && (*winp)->chan != 0);
+ return 1;
+ }
+ libclose(fd);
+ buf[n] = '\0';
+ if(*winp != nil){
+ _freeimage1(*winp);
+ freeimage((*scrp)->image);
+ freescreen(*scrp);
+ *scrp = nil;
+ }
+ image = namedimage(d, buf);
+ if(image == 0){
+ *winp = nil;
+ return -1;
+ }
+ assert(image->chan != 0);
+
+ *scrp = allocscreen(image, d->white, 0);
+ if(*scrp == nil){
+ *winp = nil;
+ return -1;
+ }
+
+ *winp = _allocwindow(*winp, *scrp, insetrect(image->r, Borderwidth), ref, DWhite);
+ if(*winp == nil)
+ return -1;
+ assert((*winp)->chan != 0);
+ return 1;
+}
+
+#define NINFO 12*12
+
+Display*
+initdisplay(char *dev, char *win, void(*error)(Display*, char*))
+{
+ char buf[128], info[NINFO+1], *t;
+ int datafd, ctlfd, reffd;
+ Display *disp;
+ Image *image;
+ Dir *dir;
+ void *q;
+ ulong chan;
+
+ fmtinstall('P', Pfmt);
+ fmtinstall('R', Rfmt);
+ if(dev == 0)
+ dev = "/dev";
+ if(win == 0)
+ win = "/dev";
+ if(strlen(dev)>sizeof buf-25 || strlen(win)>sizeof buf-25){
+ kwerrstr("initdisplay: directory name too long");
+ return nil;
+ }
+ t = strdup(win);
+ if(t == nil)
+ return nil;
+
+ q = libqlalloc();
+ if(q == nil)
+ return nil;
+
+ sprint(buf, "%s/draw/new", dev);
+ ctlfd = libopen(buf, ORDWR);
+ if(ctlfd < 0){
+ if(libbind("#i", dev, MBEFORE) < 0){
+ Error1:
+ libqlfree(q);
+ free(t);
+ kwerrstr("initdisplay: %s: %r", buf);
+ return 0;
+ }
+ ctlfd = libopen(buf, ORDWR);
+ }
+ if(ctlfd < 0)
+ goto Error1;
+ if(libread(ctlfd, info, sizeof info) < NINFO){
+ Error2:
+ libclose(ctlfd);
+ goto Error1;
+ }
+
+ if((chan=strtochan(info+2*12)) == 0){
+ kwerrstr("bad channel in %s", buf);
+ goto Error2;
+ }
+
+ sprint(buf, "%s/draw/%d/data", dev, atoi(info+0*12));
+ datafd = libopen(buf, ORDWR);
+ if(datafd < 0)
+ goto Error2;
+ sprint(buf, "%s/draw/%d/refresh", dev, atoi(info+0*12));
+ reffd = libopen(buf, OREAD);
+ if(reffd < 0){
+ Error3:
+ libclose(datafd);
+ goto Error2;
+ }
+ strcpy(buf, "allocation failed");
+ disp = malloc(sizeof(Display));
+ if(disp == 0){
+ Error4:
+ libclose(reffd);
+ goto Error3;
+ }
+ image = malloc(sizeof(Image));
+ if(image == 0){
+ Error5:
+ free(disp);
+ goto Error4;
+ }
+ memset(image, 0, sizeof(Image));
+ memset(disp, 0, sizeof(Display));
+ image->display = disp;
+ image->id = 0;
+ image->chan = chan;
+ image->depth = chantodepth(chan);
+ image->repl = atoi(info+3*12);
+ image->r.min.x = atoi(info+4*12);
+ image->r.min.y = atoi(info+5*12);
+ image->r.max.x = atoi(info+6*12);
+ image->r.max.y = atoi(info+7*12);
+ image->clipr.min.x = atoi(info+8*12);
+ image->clipr.min.y = atoi(info+9*12);
+ image->clipr.max.x = atoi(info+10*12);
+ image->clipr.max.y = atoi(info+11*12);
+ disp->dirno = atoi(info+0*12);
+ disp->datachan = libfdtochan(datafd, ORDWR);
+ disp->refchan = libfdtochan(reffd, OREAD);
+ disp->ctlchan = libfdtochan(ctlfd, ORDWR);
+ if(disp->datachan == nil || disp->refchan == nil || disp->ctlchan == nil)
+ goto Error4;
+ disp->bufsize = Displaybufsize; /* TO DO: iounit(datafd) */
+ if(disp->bufsize <= 0)
+ disp->bufsize = Displaybufsize;
+ if(disp->bufsize < 512){
+ kwerrstr("iounit %d too small", disp->bufsize);
+ goto Error5;
+ }
+ /* TO DO: allocate buffer */
+
+ libclose(datafd);
+ libclose(reffd);
+ disp->image = image;
+ disp->bufp = disp->buf;
+ disp->error = error;
+ disp->chan = image->chan;
+ disp->depth = image->depth;
+ disp->windir = t;
+ disp->devdir = strdup(dev);
+ disp->qlock = q;
+ libqlock(q);
+ disp->white = allocimage(disp, Rect(0, 0, 1, 1), GREY1, 1, DWhite);
+ disp->black = allocimage(disp, Rect(0, 0, 1, 1), GREY1, 1, DBlack);
+ disp->opaque = allocimage(disp, Rect(0, 0, 1, 1), GREY1, 1, DWhite);
+ disp->transparent = allocimage(disp, Rect(0, 0, 1, 1), GREY1, 1, DBlack);
+ if(disp->white == nil || disp->black == nil || disp->opaque == nil || disp->transparent == nil){
+ free(image);
+ free(disp->devdir);
+ free(disp->white);
+ free(disp->black);
+ libclose(ctlfd);
+ goto Error5;
+ }
+ if((dir = libdirfstat(ctlfd))!=nil && dir->type=='i'){
+ disp->local = 1;
+ disp->dataqid = dir->qid.path;
+ }
+ free(dir);
+ libclose(ctlfd);
+
+ if(CHECKLOCKING)
+ disp->local = 0; /* force display locking even for local access */
+
+ assert(disp->chan != 0 && image->chan != 0);
+ return disp;
+}
+
+/*
+ * Call with d unlocked.
+ * Note that disp->defaultfont and defaultsubfont are not freed here.
+ */
+void
+closedisplay(Display *disp)
+{
+ int fd;
+ char buf[128];
+
+ if(disp == nil)
+ return;
+ libqlock(disp->qlock);
+ if(disp->oldlabel[0]){
+ snprint(buf, sizeof buf, "%s/label", disp->windir);
+ fd = libopen(buf, OWRITE);
+ if(fd >= 0){
+ libwrite(fd, disp->oldlabel, strlen(disp->oldlabel));
+ libclose(fd);
+ }
+ }
+
+ free(disp->devdir);
+ free(disp->windir);
+ freeimage(disp->white);
+ freeimage(disp->black);
+ freeimage(disp->opaque);
+ freeimage(disp->transparent);
+ free(disp->image);
+ libchanclose(disp->datachan);
+ libchanclose(disp->refchan);
+ libchanclose(disp->ctlchan);
+ /* should cause refresh slave to shut down */
+ libqunlock(disp->qlock);
+ libqlfree(disp->qlock);
+ free(disp);
+}
+
+int
+lockdisplay(Display *disp)
+{
+ if(disp->local)
+ return 0;
+ if(libqlowner(disp->qlock) != currun()){
+ libqlock(disp->qlock);
+ return 1;
+ }
+ return 0;
+}
+
+void
+unlockdisplay(Display *disp)
+{
+ if(disp->local)
+ return;
+ libqunlock(disp->qlock);
+}
+
+/* use static buffer to avoid stack bloat */
+int
+_drawprint(int fd, char *fmt, ...)
+{
+ int n;
+ va_list arg;
+ char buf[128];
+// static QLock l;
+
+// qlock(&l);
+ va_start(arg, fmt);
+ vseprint(buf, buf+sizeof buf, fmt, arg);
+ va_end(arg);
+ n = libwrite(fd, buf, strlen(buf));
+// qunlock(&l);
+ return n;
+}
+
+#ifdef YYY
+void
+drawerror(Display *d, char *s)
+{
+ char err[ERRMAX];
+
+ if(d->error)
+ d->error(d, s);
+ else{
+ err[0] = 0;
+ errstr(err, sizeof err);
+ _drawprint(2, "draw: %s: %s\n", s, err);
+ exits(s);
+ }
+}
+
+static
+int
+doflush(Display *d)
+{
+ int n;
+
+ n = d->bufp-d->buf;
+ if(n <= 0)
+ return 1;
+
+ if(kchanio(d->datachan, d->buf, n, OWRITE) != n){
+ if(_drawdebug)
+ _drawprint(2, "flushimage fail: d=%p: %r\n", d); /**/
+ d->bufp = d->buf; /* might as well; chance of continuing */
+ return -1;
+ }
+ d->bufp = d->buf;
+ return 1;
+}
+
+int
+flushimage(Display *d, int visible)
+{
+ if(visible)
+ *d->bufp++ = 'v'; /* one byte always reserved for this */
+ return doflush(d);
+}
+
+uchar*
+bufimage(Display *d, int n)
+{
+ uchar *p;
+
+ if(n<0 || n>Displaybufsize){
+ kwerrstr("bad count in bufimage");
+ return 0;
+ }
+ if(d->bufp+n > d->buf+Displaybufsize)
+ if(doflush(d) < 0)
+ return 0;
+ p = d->bufp;
+ d->bufp += n;
+ return p;
+}
+
+#endif
--- /dev/null
+++ b/libdraw/line.c
@@ -1,0 +1,34 @@
+#include "lib9.h"
+#include "draw.h"
+
+void
+line(Image *dst, Point p0, Point p1, int end0, int end1, int radius, Image *src, Point sp)
+{
+ lineop(dst, p0, p1, end0, end1, radius, src, sp, SoverD);
+}
+
+void
+lineop(Image *dst, Point p0, Point p1, int end0, int end1, int radius, Image *src, Point sp, Drawop op)
+{
+ uchar *a;
+
+ _setdrawop(dst->display, op);
+
+ a = bufimage(dst->display, 1+4+2*4+2*4+4+4+4+4+2*4);
+ if(a == 0){
+ _drawprint(2, "image line: %r\n");
+ return;
+ }
+ a[0] = 'L';
+ BPLONG(a+1, dst->id);
+ BPLONG(a+5, p0.x);
+ BPLONG(a+9, p0.y);
+ BPLONG(a+13, p1.x);
+ BPLONG(a+17, p1.y);
+ BPLONG(a+21, end0);
+ BPLONG(a+25, end1);
+ BPLONG(a+29, radius);
+ BPLONG(a+33, src->id);
+ BPLONG(a+37, sp.x);
+ BPLONG(a+41, sp.y);
+}
--- /dev/null
+++ b/libdraw/loadimage.c
@@ -1,0 +1,70 @@
+#include "lib9.h"
+#include "draw.h"
+#include "kernel.h"
+
+int
+loadimage(Image *i, Rectangle r, uchar *data, int ndata)
+{
+ long dy;
+ int n, bpl, roff, dstroff, lskip, llen, y;
+ uchar *a;
+ int chunk;
+ Rectangle dstr;
+
+ chunk = i->display->bufsize - 64;
+
+ bpl = bytesperline(r, i->depth);
+ n = bpl*Dy(r);
+ if(n > ndata){
+ kwerrstr("loadimage: insufficient data");
+ return -1;
+ }
+
+ dstr = r;
+ rectclip(&dstr, i->r);
+ rectclip(&dstr, i->clipr);
+
+ if (!rectinrect(dstr, i->r))
+ return 0;
+
+ roff = (r.min.x*i->depth)>>3;
+ dstroff = dstr.min.x * i->depth >> 3;
+ lskip = dstroff - roff;
+ llen = (dstr.max.x*i->depth + 7 >> 3) - dstroff;
+ data += (dstr.min.y - r.min.y) * bpl + lskip;
+
+ ndata = 0;
+ while(dstr.max.y > dstr.min.y){
+ dy = dstr.max.y - dstr.min.y;
+ if(dy*llen > chunk)
+ dy = chunk/llen;
+ if(dy <= 0){
+ kwerrstr("loadimage: image too wide for buffer");
+ return -1;
+ }
+ n = dy*llen;
+ a = bufimage(i->display, 21+n);
+ if(a == nil){
+ kwerrstr("bufimage failed");
+ return -1;
+ }
+ a[0] = 'y';
+ BPLONG(a+1, i->id);
+ BPLONG(a+5, dstr.min.x);
+ BPLONG(a+9, dstr.min.y);
+ BPLONG(a+13, dstr.max.x);
+ BPLONG(a+17, dstr.min.y+dy);
+ a += 21;
+ for (y = 0; y < dy; y++) {
+ memmove(a, data, llen);
+ a += llen;
+ ndata += llen;
+ data += bpl;
+ }
+ dstr.min.y += dy;
+ }
+ if(flushimage(i->display, 0) < 0)
+ return -1;
+ return ndata;
+}
+
--- /dev/null
+++ b/libdraw/mkfile
@@ -1,0 +1,54 @@
+<../mkconfig
+
+LIB=libdraw.a
+
+OFILES= alloc.$O\
+ allocimagemix.$O\
+ arith.$O\
+ bezier.$O\
+ border.$O\
+ buildfont.$O\
+ bytesperline.$O\
+ chan.$O\
+ cloadimage.$O\
+ computil.$O\
+ creadimage.$O\
+ defont.$O\
+ draw.$O\
+ drawrepl.$O\
+ ellipse.$O\
+ font.$O\
+ freesubfont.$O\
+ getdefont.$O\
+ getsubfont.$O\
+ init.$O\
+ line.$O\
+ mkfont.$O\
+ openfont.$O\
+ poly.$O\
+ loadimage.$O\
+ readcolmap.$O\
+ readimage.$O\
+ readsubfont.$O\
+ rectclip.$O\
+ replclipr.$O\
+ rgb.$O\
+ string.$O\
+ stringbg.$O\
+ stringsubfont.$O\
+ stringwidth.$O\
+ subfont.$O\
+ subfontcache.$O\
+ subfontname.$O\
+ unloadimage.$O\
+ window.$O\
+ writecolmap.$O\
+ writeimage.$O\
+ writesubfont.$O\
+
+HFILES=\
+ $ROOT/include/draw.h \
+ $ROOT/include/interp.h\
+
+<$ROOT/mkfiles/mksyslib-$SHELLTYPE
+
--- /dev/null
+++ b/libdraw/mkfont.c
@@ -1,0 +1,54 @@
+#include "lib9.h"
+#include "draw.h"
+
+/*
+ * Cobble fake font using existing subfont
+ */
+Font*
+mkfont(Subfont *subfont, Rune min)
+{
+ Font *font;
+ Cachefont *c;
+
+ font = malloc(sizeof(Font));
+ if(font == 0)
+ return 0;
+ memset(font, 0, sizeof(Font));
+ font->display = subfont->bits->display;
+ font->name = strdup("<synthetic>");
+ font->ncache = NFCACHE+NFLOOK;
+ font->nsubf = NFSUBF;
+ font->cache = malloc(font->ncache * sizeof(font->cache[0]));
+ font->subf = malloc(font->nsubf * sizeof(font->subf[0]));
+ if(font->name==0 || font->cache==0 || font->subf==0){
+ Err:
+ free(font->name);
+ free(font->cache);
+ free(font->subf);
+ free(font->sub);
+ free(font);
+ return 0;
+ }
+ memset(font->cache, 0, font->ncache*sizeof(font->cache[0]));
+ memset(font->subf, 0, font->nsubf*sizeof(font->subf[0]));
+ font->height = subfont->height;
+ font->ascent = subfont->ascent;
+ font->age = 1;
+ font->sub = malloc(sizeof(Cachefont*));
+ if(font->sub == 0)
+ goto Err;
+ c = malloc(sizeof(Cachefont));
+ if(c == 0)
+ goto Err;
+ font->nsub = 1;
+ font->sub[0] = c;
+ c->min = min;
+ c->max = min+subfont->n-1;
+ c->offset = 0;
+ c->name = 0; /* noticed by freeup() and agefont() */
+ c->subfontname = 0;
+ font->subf[0].age = 0;
+ font->subf[0].cf = c;
+ font->subf[0].f = subfont;
+ return font;
+}
--- /dev/null
+++ b/libdraw/openfont.c
@@ -1,0 +1,37 @@
+#include "lib9.h"
+#include "kernel.h"
+#include "draw.h"
+
+Font*
+openfont(Display *d, char *name)
+{
+ Font *fnt;
+ int fd, i, n;
+ char *buf;
+ Dir *dir;
+
+ fd = libopen(name, OREAD);
+ if(fd < 0)
+ return 0;
+
+ if((dir = libdirfstat(fd)) == nil){
+ Err0:
+ libclose(fd);
+ return 0;
+ }
+ n = dir->length;
+ free(dir);
+ buf = malloc(n+1);
+ if(buf == 0)
+ goto Err0;
+ buf[n] = 0;
+ i = libreadn(fd, buf, n);
+ libclose(fd);
+ if(i != n){
+ free(buf);
+ return 0;
+ }
+ fnt = buildfont(d, buf, name);
+ free(buf);
+ return fnt;
+}
--- /dev/null
+++ b/libdraw/poly.c
@@ -1,0 +1,86 @@
+#include "lib9.h"
+#include "draw.h"
+
+static
+uchar*
+addcoord(uchar *p, int oldx, int newx)
+{
+ int dx;
+
+ dx = newx-oldx;
+ /* does dx fit in 7 signed bits? */
+ if((unsigned)(dx - -0x40) <= 0x7F)
+ *p++ = dx&0x7F;
+ else{
+ *p++ = 0x80 | (newx&0x7F);
+ *p++ = newx>>7;
+ *p++ = newx>>15;
+ }
+ return p;
+}
+
+static
+void
+dopoly(int cmd, Image *dst, Point *pp, int np, int end0, int end1, int radius, Image *src, Point *sp, Drawop op)
+{
+ uchar *a, *t, *u;
+ int i, ox, oy;
+
+ if(np == 0)
+ return;
+ t = malloc(np*2*3);
+ if(t == nil)
+ return;
+ u = t;
+ ox = oy = 0;
+ for(i=0; i<np; i++){
+ u = addcoord(u, ox, pp[i].x);
+ ox = pp[i].x;
+ u = addcoord(u, oy, pp[i].y);
+ oy = pp[i].y;
+ }
+
+ _setdrawop(dst->display, op);
+
+ a = bufimage(dst->display, 1+4+2+4+4+4+4+2*4+(u-t));
+ if(a == 0){
+ free(t);
+ _drawprint(2, "image poly: %r\n");
+ return;
+ }
+ a[0] = cmd;
+ BPLONG(a+1, dst->id);
+ BPSHORT(a+5, np-1);
+ BPLONG(a+7, end0);
+ BPLONG(a+11, end1);
+ BPLONG(a+15, radius);
+ BPLONG(a+19, src->id);
+ BPLONG(a+23, sp->x);
+ BPLONG(a+27, sp->y);
+ memmove(a+31, t, u-t);
+ free(t);
+}
+
+void
+poly(Image *dst, Point *p, int np, int end0, int end1, int radius, Image *src, Point sp)
+{
+ dopoly('p', dst, p, np, end0, end1, radius, src, &sp, SoverD);
+}
+
+void
+polyop(Image *dst, Point *p, int np, int end0, int end1, int radius, Image *src, Point sp, Drawop op)
+{
+ dopoly('p', dst, p, np, end0, end1, radius, src, &sp, op);
+}
+
+void
+fillpoly(Image *dst, Point *p, int np, int wind, Image *src, Point sp)
+{
+ dopoly('P', dst, p, np, wind, 0, 0, src, &sp, SoverD);
+}
+
+void
+fillpolyop(Image *dst, Point *p, int np, int wind, Image *src, Point sp, Drawop op)
+{
+ dopoly('P', dst, p, np, wind, 0, 0, src, &sp, op);
+}
--- /dev/null
+++ b/libdraw/readcolmap.c
@@ -1,0 +1,46 @@
+#include "lib9.h"
+#include "draw.h"
+#include "bio.h"
+
+static ulong
+getval(char **p)
+{
+ ulong v;
+ char *q;
+
+ v = strtoul(*p, &q, 0);
+ v |= v<<8;
+ v |= v<<16;
+ *p = q;
+ return v;
+}
+
+void
+readcolmap(Display *d, RGB *colmap)
+{
+ int i;
+ char *p, *q;
+ Biobuf *b;
+ char buf[128];
+
+ sprint(buf, "/dev/draw/%d/colormap", d->dirno);
+ b = Bopen(buf, OREAD);
+ if(b == 0)
+ drawerror(d, "rdcolmap: can't open colormap device");
+
+ for(;;) {
+ p = Brdline(b, '\n');
+ if(p == 0)
+ break;
+ i = strtoul(p, &q, 0);
+ if(i < 0 || i > 255) {
+ _drawprint(2, "rdcolmap: bad index\n");
+ exits("bad");
+ }
+ p = q;
+ colmap[255-i].red = getval(&p);
+ colmap[255-i].green = getval(&p);
+ colmap[255-i].blue = getval(&p);
+ }
+ Bterm(b);
+}
--- /dev/null
+++ b/libdraw/readimage.c
@@ -1,0 +1,123 @@
+#include "lib9.h"
+#include "kernel.h"
+#include "draw.h"
+
+Image*
+readimage(Display *d, int fd, int dolock)
+{
+ char hdr[5*12+1];
+ int dy;
+ int new;
+ uint l, n;
+ int m, j, chunk;
+ int miny, maxy;
+ Rectangle r;
+ int ldepth;
+ ulong chan;
+ uchar *tmp;
+ Image *i;
+
+ if(libreadn(fd, hdr, 11) != 11) {
+ kwerrstr("readimage: short header");
+ return nil;
+ }
+ if(memcmp(hdr, "compressed\n", 11) == 0)
+ return creadimage(d, fd, dolock);
+ dolock &= 1;
+ if(libreadn(fd, hdr+11, 5*12-11) != 5*12-11) {
+ kwerrstr("readimage: short header");
+ return nil;
+ }
+ chunk = d->bufsize - 32; /* a little room for header */
+
+ /*
+ * distinguish new channel descriptor from old ldepth.
+ * channel descriptors have letters as well as numbers,
+ * while ldepths are a single digit formatted as %-11d.
+ */
+ new = 0;
+ for(m=0; m<10; m++){
+ if(hdr[m] != ' '){
+ new = 1;
+ break;
+ }
+ }
+ if(hdr[11] != ' '){
+ kwerrstr("readimage: bad format");
+ return nil;
+ }
+ if(new){
+ hdr[11] = '\0';
+ if((chan = strtochan(hdr)) == 0){
+ kwerrstr("readimage: bad channel string %s", hdr);
+ return nil;
+ }
+ }else{
+ ldepth = ((int)hdr[10])-'0';
+ if(ldepth<0 || ldepth>3){
+ kwerrstr("readimage: bad ldepth %d", ldepth);
+ return nil;
+ }
+ chan = drawld2chan[ldepth];
+ }
+
+ r.min.x = atoi(hdr+1*12);
+ r.min.y = atoi(hdr+2*12);
+ r.max.x = atoi(hdr+3*12);
+ r.max.y = atoi(hdr+4*12);
+ if(r.min.x>r.max.x || r.min.y>r.max.y){
+ kwerrstr("readimage: bad rectangle");
+ return nil;
+ }
+
+ miny = r.min.y;
+ maxy = r.max.y;
+
+ l = bytesperline(r, chantodepth(chan));
+ if(dolock)
+ dolock = lockdisplay(d);
+ i = allocimage(d, r, chan, 0, -1);
+ if(dolock)
+ unlockdisplay(d);
+ if(i == nil)
+ return nil;
+ tmp = malloc(chunk);
+ if(tmp == nil)
+ goto Err;
+ while(maxy > miny){
+ dy = maxy - miny;
+ if(dy*l > chunk)
+ dy = chunk/l;
+ if(dy <= 0){
+ kwerrstr("readimage: image too wide for buffer");
+ goto Err;
+ }
+ n = dy*l;
+ m = libreadn(fd, tmp, n);
+ if(m != n){
+ kwerrstr("readimage: read count %d not %d: %r", m, n);
+ Err:
+ if(dolock)
+ lockdisplay(d);
+ Err1:
+ freeimage(i);
+ if(dolock)
+ unlockdisplay(d);
+ free(tmp);
+ return nil;
+ }
+ if(!new) /* an old image: must flip all the bits */
+ for(j=0; j<chunk; j++)
+ tmp[j] ^= 0xFF;
+
+ if(dolock)
+ lockdisplay(d);
+ if(loadimage(i, Rect(r.min.x, miny, r.max.x, miny+dy), tmp, chunk) <= 0)
+ goto Err1;
+ if(dolock)
+ unlockdisplay(d);
+ miny += dy;
+ }
+ free(tmp);
+ return i;
+}
--- /dev/null
+++ b/libdraw/readsubfont.c
@@ -1,0 +1,58 @@
+#include "lib9.h"
+#include "kernel.h"
+#include "draw.h"
+
+Subfont*
+readsubfonti(Display*d, char *name, int fd, Image *ai, int dolock)
+{
+ char hdr[3*12+4+1];
+ int n;
+ uchar *p;
+ Fontchar *fc;
+ Subfont *f;
+ Image *i;
+
+ i = ai;
+ if(i == nil){
+ i = readimage(d, fd, dolock|2);
+ if(i == nil)
+ return nil;
+ }
+ if(libreadn(fd, hdr, 3*12) != 3*12){
+ if(ai == nil)
+ freeimage(i);
+ kwerrstr("rdsubfonfile: header read error: %r");
+ return nil;
+ }
+ n = atoi(hdr);
+ p = malloc(6*(n+1));
+ if(p == nil)
+ return nil;
+ if(libreadn(fd, p, 6*(n+1)) != 6*(n+1)){
+ kwerrstr("rdsubfonfile: fontchar read error: %r");
+ Err:
+ free(p);
+ return nil;
+ }
+ fc = malloc(sizeof(Fontchar)*(n+1));
+ if(fc == nil)
+ goto Err;
+ _unpackinfo(fc, p, n);
+ if(dolock)
+ lockdisplay(d);
+ f = allocsubfont(name, n, atoi(hdr+12), atoi(hdr+24), fc, i);
+ if(dolock)
+ unlockdisplay(d);
+ if(f == nil){
+ free(fc);
+ goto Err;
+ }
+ free(p);
+ return f;
+}
+
+Subfont*
+readsubfont(Display*d, char *name, int fd, int dolock)
+{
+ return readsubfonti(d, name, fd, nil, dolock);
+}
--- /dev/null
+++ b/libdraw/rectclip.c
@@ -1,0 +1,24 @@
+#include "lib9.h"
+#include "draw.h"
+
+int
+rectclip(Rectangle *rp, Rectangle b) /* first by reference, second by value */
+{
+ Rectangle *bp = &b;
+ /*
+ * Expand rectXrect() in line for speed
+ */
+ if((rp->min.x<bp->max.x && bp->min.x<rp->max.x &&
+ rp->min.y<bp->max.y && bp->min.y<rp->max.y)==0)
+ return 0;
+ /* They must overlap */
+ if(rp->min.x < bp->min.x)
+ rp->min.x = bp->min.x;
+ if(rp->min.y < bp->min.y)
+ rp->min.y = bp->min.y;
+ if(rp->max.x > bp->max.x)
+ rp->max.x = bp->max.x;
+ if(rp->max.y > bp->max.y)
+ rp->max.y = bp->max.y;
+ return 1;
+}
--- /dev/null
+++ b/libdraw/replclipr.c
@@ -1,0 +1,24 @@
+#include "lib9.h"
+#include "draw.h"
+
+void
+replclipr(Image *i, int repl, Rectangle clipr)
+{
+ uchar *b;
+
+ b = bufimage(i->display, 22);
+ if (b == 0) {
+ _drawprint(2, "replclipr: no bufimage\n");
+ return;
+ }
+ b[0] = 'c';
+ BPLONG(b+1, i->id);
+ repl = repl!=0;
+ b[5] = repl;
+ BPLONG(b+6, clipr.min.x);
+ BPLONG(b+10, clipr.min.y);
+ BPLONG(b+14, clipr.max.x);
+ BPLONG(b+18, clipr.max.y);
+ i->repl = repl;
+ i->clipr = clipr;
+}
--- /dev/null
+++ b/libdraw/rgb.c
@@ -1,0 +1,98 @@
+#include "lib9.h"
+#include "draw.h"
+
+/*
+ * This original version, although fast and a true inverse of
+ * cmap2rgb, in the sense that rgb2cmap(cmap2rgb(c))
+ * returned the original color, does a terrible job for RGB
+ * triples that do not appear in the color map, so it has been
+ * replaced by the much slower version below, that loops
+ * over the color map looking for the nearest point in RGB
+ * space. There is no visual psychology reason for that
+ * criterion, but it's easy to implement and the results are
+ * far more pleasing.
+ *
+int
+rgb2cmap(int cr, int cg, int cb)
+{
+ int r, g, b, v, cv;
+
+ if(cr < 0)
+ cr = 0;
+ else if(cr > 255)
+ cr = 255;
+ if(cg < 0)
+ cg = 0;
+ else if(cg > 255)
+ cg = 255;
+ if(cb < 0)
+ cb = 0;
+ else if(cb > 255)
+ cb = 255;
+ r = cr>>6;
+ g = cg>>6;
+ b = cb>>6;
+ cv = cr;
+ if(cg > cv)
+ cv = cg;
+ if(cb > cv)
+ cv = cb;
+ v = (cv>>4)&3;
+ return ((((r<<2)+v)<<4)+(((g<<2)+b+v-r)&15));
+}
+*/
+
+int
+rgb2cmap(int cr, int cg, int cb)
+{
+ int i, r, g, b, sq;
+ ulong rgb;
+ int best, bestsq;
+
+ best = 0;
+ bestsq = 0x7FFFFFFF;
+ for(i=0; i<256; i++){
+ rgb = cmap2rgb(i);
+ r = (rgb>>16) & 0xFF;
+ g = (rgb>>8) & 0xFF;
+ b = (rgb>>0) & 0xFF;
+ sq = (r-cr)*(r-cr)+(g-cg)*(g-cg)+(b-cb)*(b-cb);
+ if(sq < bestsq){
+ bestsq = sq;
+ best = i;
+ }
+ }
+ return best;
+}
+
+int
+cmap2rgb(int c)
+{
+ int j, num, den, r, g, b, v, rgb;
+
+ r = c>>6;
+ v = (c>>4)&3;
+ j = (c-v+r)&15;
+ g = j>>2;
+ b = j&3;
+ den=r;
+ if(g>den)
+ den=g;
+ if(b>den)
+ den=b;
+ if(den==0) {
+ v *= 17;
+ rgb = (v<<16)|(v<<8)|v;
+ }
+ else{
+ num=17*(4*den+v);
+ rgb = ((r*num/den)<<16)|((g*num/den)<<8)|(b*num/den);
+ }
+ return rgb;
+}
+
+int
+cmap2rgba(int c)
+{
+ return (cmap2rgb(c)<<8)|0xFF;
+}
--- /dev/null
+++ b/libdraw/string.c
@@ -1,0 +1,136 @@
+#include "lib9.h"
+#include "draw.h"
+
+enum
+{
+ Max = 100
+};
+
+Point
+string(Image *dst, Point pt, Image *src, Point sp, Font *f, char *s)
+{
+ return _string(dst, pt, src, sp, f, s, nil, 1<<24, dst->clipr, nil, ZP, SoverD);
+}
+
+Point
+stringop(Image *dst, Point pt, Image *src, Point sp, Font *f, char *s, Drawop op)
+{
+ return _string(dst, pt, src, sp, f, s, nil, 1<<24, dst->clipr, nil, ZP, op);
+}
+
+Point
+stringn(Image *dst, Point pt, Image *src, Point sp, Font *f, char *s, int len)
+{
+ return _string(dst, pt, src, sp, f, s, nil, len, dst->clipr, nil, ZP, SoverD);
+}
+
+Point
+stringnop(Image *dst, Point pt, Image *src, Point sp, Font *f, char *s, int len, Drawop op)
+{
+ return _string(dst, pt, src, sp, f, s, nil, len, dst->clipr, nil, ZP, op);
+}
+
+Point
+runestring(Image *dst, Point pt, Image *src, Point sp, Font *f, Rune *r)
+{
+ return _string(dst, pt, src, sp, f, nil, r, 1<<24, dst->clipr, nil, ZP, SoverD);
+}
+
+Point
+runestringop(Image *dst, Point pt, Image *src, Point sp, Font *f, Rune *r, Drawop op)
+{
+ return _string(dst, pt, src, sp, f, nil, r, 1<<24, dst->clipr, nil, ZP, op);
+}
+
+Point
+runestringn(Image *dst, Point pt, Image *src, Point sp, Font *f, Rune *r, int len)
+{
+ return _string(dst, pt, src, sp, f, nil, r, len, dst->clipr, nil, ZP, SoverD);
+}
+
+Point
+runestringnop(Image *dst, Point pt, Image *src, Point sp, Font *f, Rune *r, int len, Drawop op)
+{
+ return _string(dst, pt, src, sp, f, nil, r, len, dst->clipr, nil, ZP, op);
+}
+
+Point
+_string(Image *dst, Point pt, Image *src, Point sp, Font *f, char *s, Rune *r, int len, Rectangle clipr, Image *bg, Point bgp, Drawop op)
+{
+ int m, n, wid, max;
+ ushort cbuf[Max], *c, *ec;
+ uchar *b;
+ char *subfontname;
+ char **sptr;
+ Rune **rptr;
+ Font *def;
+
+ if(s == nil){
+ s = "";
+ sptr = nil;
+ }else
+ sptr = &s;
+ if(r == nil){
+ r = (Rune*) L"";
+ rptr = nil;
+ }else
+ rptr = &r;
+ while((*s || *r) && len){
+ max = Max;
+ if(len < max)
+ max = len;
+ n = cachechars(f, sptr, rptr, cbuf, max, &wid, &subfontname);
+ if(n > 0){
+ _setdrawop(dst->display, op);
+
+ m = 47+2*n;
+ if(bg)
+ m += 4+2*4;
+ b = bufimage(dst->display, m);
+ if(b == 0){
+ _drawprint(2, "string: %r\n");
+ break;
+ }
+ if(bg)
+ b[0] = 'x';
+ else
+ b[0] = 's';
+ BPLONG(b+1, dst->id);
+ BPLONG(b+5, src->id);
+ BPLONG(b+9, f->cacheimage->id);
+ BPLONG(b+13, pt.x);
+ BPLONG(b+17, pt.y+f->ascent);
+ BPLONG(b+21, clipr.min.x);
+ BPLONG(b+25, clipr.min.y);
+ BPLONG(b+29, clipr.max.x);
+ BPLONG(b+33, clipr.max.y);
+ BPLONG(b+37, sp.x);
+ BPLONG(b+41, sp.y);
+ BPSHORT(b+45, n);
+ b += 47;
+ if(bg){
+ BPLONG(b, bg->id);
+ BPLONG(b+4, bgp.x);
+ BPLONG(b+8, bgp.y);
+ b += 12;
+ }
+ ec = &cbuf[n];
+ for(c=cbuf; c<ec; c++, b+=2)
+ BPSHORT(b, *c);
+ pt.x += wid;
+ bgp.x += wid;
+ agefont(f);
+ len -= n;
+ }
+ if(subfontname){
+ if(_getsubfont(f->display, subfontname) == 0){
+ def = f->display->defaultfont;
+ if(def && f!=def)
+ f = def;
+ else
+ break;
+ }
+ }
+ }
+ return pt;
+}
--- /dev/null
+++ b/libdraw/stringbg.c
@@ -1,0 +1,50 @@
+#include "lib9.h"
+#include "draw.h"
+
+Point
+stringbg(Image *dst, Point pt, Image *src, Point sp, Font *f, char *s, Image *bg, Point bgp)
+{
+ return _string(dst, pt, src, sp, f, s, nil, 1<<24, dst->clipr, bg, bgp, SoverD);
+}
+
+Point
+stringbgop(Image *dst, Point pt, Image *src, Point sp, Font *f, char *s, Image *bg, Point bgp, Drawop op)
+{
+ return _string(dst, pt, src, sp, f, s, nil, 1<<24, dst->clipr, bg, bgp, op);
+}
+
+Point
+stringnbg(Image *dst, Point pt, Image *src, Point sp, Font *f, char *s, int len, Image *bg, Point bgp)
+{
+ return _string(dst, pt, src, sp, f, s, nil, len, dst->clipr, bg, bgp, SoverD);
+}
+
+Point
+stringnbgop(Image *dst, Point pt, Image *src, Point sp, Font *f, char *s, int len, Image *bg, Point bgp, Drawop op)
+{
+ return _string(dst, pt, src, sp, f, s, nil, len, dst->clipr, bg, bgp, op);
+}
+
+Point
+runestringbg(Image *dst, Point pt, Image *src, Point sp, Font *f, Rune *r, Image *bg, Point bgp)
+{
+ return _string(dst, pt, src, sp, f, nil, r, 1<<24, dst->clipr, bg, bgp, SoverD);
+}
+
+Point
+runestringbgop(Image *dst, Point pt, Image *src, Point sp, Font *f, Rune *r, Image *bg, Point bgp, Drawop op)
+{
+ return _string(dst, pt, src, sp, f, nil, r, 1<<24, dst->clipr, bg, bgp, op);
+}
+
+Point
+runestringnbg(Image *dst, Point pt, Image *src, Point sp, Font *f, Rune *r, int len, Image *bg, Point bgp)
+{
+ return _string(dst, pt, src, sp, f, nil, r, len, dst->clipr, bg, bgp, SoverD);
+}
+
+Point
+runestringnbgop(Image *dst, Point pt, Image *src, Point sp, Font *f, Rune *r, int len, Image *bg, Point bgp, Drawop op)
+{
+ return _string(dst, pt, src, sp, f, nil, r, len, dst->clipr, bg, bgp, op);
+}
--- /dev/null
+++ b/libdraw/stringsubfont.c
@@ -1,0 +1,64 @@
+#include "lib9.h"
+#include "draw.h"
+
+Point
+stringsubfont(Image *b, Point p, Image *color, Subfont *f, char *cs)
+{
+ int w, width;
+ uchar *s;
+ Rune c;
+ Fontchar *i;
+
+ s = (uchar*)cs;
+ for(; c=*s; p.x+=width){
+ width = 0;
+ if(c < Runeself)
+ s++;
+ else{
+ w = chartorune(&c, (char*)s);
+ if(w == 0){
+ s++;
+ continue;
+ }
+ s += w;
+ }
+ if(c >= f->n)
+ continue;
+ i = f->info+c;
+ width = i->width;
+ draw(b, Rect(p.x+i->left, p.y+i->top, p.x+i->left+(i[1].x-i[0].x), p.y+i->bottom),
+ color, f->bits, Pt(i->x, i->top));
+ }
+ return p;
+}
+
+Point
+strsubfontwidth(Subfont *f, char *cs)
+{
+ Rune c;
+ Point p;
+ uchar *s;
+ Fontchar *i;
+ int w, width;
+
+ p = Pt(0, f->height);
+ s = (uchar*)cs;
+ for(; c=*s; p.x+=width){
+ width = 0;
+ if(c < Runeself)
+ s++;
+ else{
+ w = chartorune(&c, (char*)s);
+ if(w == 0){
+ s++;
+ continue;
+ }
+ s += w;
+ }
+ if(c >= f->n)
+ continue;
+ i = f->info+c;
+ width = i->width;
+ }
+ return p;
+}
--- /dev/null
+++ b/libdraw/stringwidth.c
@@ -1,0 +1,96 @@
+#include "lib9.h"
+#include "draw.h"
+
+int
+_stringnwidth(Font *f, char *s, Rune *r, int len)
+{
+ int wid, twid, n, max, l;
+ char *name;
+ enum { Max = 64 };
+ ushort cbuf[Max];
+ Rune rune, **rptr;
+ char *subfontname, **sptr;
+ Font *def;
+ static Rune rnull;
+
+ if(s == nil){
+ s = "";
+ sptr = nil;
+ }else
+ sptr = &s;
+ if(r == nil){
+ r = &rnull;
+ rptr = nil;
+ }else
+ rptr = &r;
+ twid = 0;
+ while(len>0 && (*s || *r)){
+ max = Max;
+ if(len < max)
+ max = len;
+ n = 0;
+ while((l = cachechars(f, sptr, rptr, cbuf, max, &wid, &subfontname)) <= 0){
+ if(++n > 10){
+ if(*r)
+ rune = *r;
+ else
+ chartorune(&rune, s);
+ if(f->name != nil)
+ name = f->name;
+ else
+ name = "unnamed font";
+ _drawprint(2, "stringwidth: bad character set for rune 0x%.4ux in %s\n", rune, name);
+ return twid;
+ }
+ if(subfontname){
+ if(_getsubfont(f->display, subfontname) == 0){
+ def = f->display->defaultfont;
+ if(def && f!=def)
+ f = def;
+ else
+ break;
+ }
+ }
+ }
+ agefont(f);
+ twid += wid;
+ len -= l;
+ }
+ return twid;
+}
+
+int
+stringnwidth(Font *f, char *s, int len)
+{
+ return _stringnwidth(f, s, nil, len);
+}
+
+int
+stringwidth(Font *f, char *s)
+{
+ return _stringnwidth(f, s, nil, 1<<24);
+}
+
+Point
+stringsize(Font *f, char *s)
+{
+ return Pt(_stringnwidth(f, s, nil, 1<<24), f->height);
+}
+
+int
+runestringnwidth(Font *f, Rune *r, int len)
+{
+ return _stringnwidth(f, nil, r, len);
+}
+
+int
+runestringwidth(Font *f, Rune *r)
+{
+ return _stringnwidth(f, nil, r, 1<<24);
+}
+
+Point
+runestringsize(Font *f, Rune *r)
+{
+ return Pt(_stringnwidth(f, nil, r, 1<<24), f->height);
+}
--- /dev/null
+++ b/libdraw/subfont.c
@@ -1,0 +1,27 @@
+#include "lib9.h"
+#include "draw.h"
+
+Subfont*
+allocsubfont(char *name, int n, int height, int ascent, Fontchar *info, Image *i)
+{
+ Subfont *f;
+
+ assert(height != 0 /* allocsubfont */);
+
+ f = malloc(sizeof(Subfont));
+ if(f == 0)
+ return 0;
+ f->n = n;
+ f->height = height;
+ f->ascent = ascent;
+ f->info = info;
+ f->bits = i;
+ f->ref = 1;
+ if(name){
+ f->name = strdup(name);
+ if(lookupsubfont(i->display, name) == 0)
+ installsubfont(name, f);
+ }else
+ f->name = 0;
+ return f;
+}
--- /dev/null
+++ b/libdraw/subfontcache.c
@@ -1,0 +1,38 @@
+#include "lib9.h"
+#include "draw.h"
+
+/*
+ * Easy versions of the cache routines; may be substituted by fancier ones for other purposes
+ */
+
+static char *lastname;
+Subfont *lastsubfont;
+
+Subfont*
+lookupsubfont(Display *d, char *name)
+{
+ if(strcmp(name, "*default*") == 0)
+ return d->defaultsubfont;
+ if(lastname && strcmp(name, lastname)==0 && d==lastsubfont->bits->display){
+ lastsubfont->ref++;
+ return lastsubfont;
+ }
+ return 0;
+}
+
+void
+installsubfont(char *name, Subfont *subfont)
+{
+ free(lastname);
+ lastname = strdup(name);
+ lastsubfont = subfont; /* notice we don't free the old one; that's your business */
+}
+
+void
+uninstallsubfont(Subfont *subfont)
+{
+ if(subfont == lastsubfont){
+ lastname = 0;
+ lastsubfont = 0;
+ }
+}
--- /dev/null
+++ b/libdraw/subfontname.c
@@ -1,0 +1,45 @@
+#include "lib9.h"
+#include "draw.h"
+
+/*
+ * Default version: convert to file name
+ */
+
+char*
+subfontname(char *cfname, char *fname, int maxdepth)
+{
+ char *t, *u, tmp1[128], tmp2[128];
+ int i;
+
+ if(strcmp(cfname, "*default*") == 0)
+ return strdup(cfname);
+ t = cfname;
+ if(t[0] != '/'){
+ snprint(tmp2, sizeof tmp2, "%s", fname);
+ u = utfrrune(tmp2, '/');
+ if(u)
+ u[0] = 0;
+ else
+ strcpy(tmp2, ".");
+ snprint(tmp1, sizeof tmp1, "%s/%s", tmp2, t);
+ t = tmp1;
+ }
+
+ if(maxdepth > 8)
+ maxdepth = 8;
+
+ for(i=3; i>=0; i--){
+ if((1<<i) > maxdepth)
+ continue;
+ /* try i-bit grey */
+ snprint(tmp2, sizeof tmp2, "%s.%d", t, i);
+ if(access(tmp2, AREAD) == 0)
+ return strdup(tmp2);
+ }
+
+ /* try default */
+ if(access(t, AREAD) == 0)
+ return strdup(t);
+
+ return nil;
+}
--- /dev/null
+++ b/libdraw/test.c
@@ -1,0 +1,9 @@
+#include "lib9.h"
+#include "draw.h"
+
+
+void
+main(int argc, char **argv)
+{
+ print("%dn", wordsperline(Rect(atoi(argv[1]), atoi(argv[2]), atoi(argv[3]), atoi(argv[4])), atoi(argv[5])));
+}
--- /dev/null
+++ b/libdraw/unloadimage.c
@@ -1,0 +1,58 @@
+#include "lib9.h"
+#include "draw.h"
+#include "kernel.h"
+#include "interp.h"
+
+int
+unloadimage(Image *i, Rectangle r, uchar *data, int ndata)
+{
+ int bpl, n, ntot, dy;
+ uchar *a;
+ Display *d;
+
+ if(!rectinrect(r, i->r)){
+ kwerrstr("unloadimage: bad rectangle");
+ return -1;
+ }
+ bpl = bytesperline(r, i->depth);
+ if(ndata < bpl*Dy(r)){
+ kwerrstr("unloadimage: buffer too small");
+ return -1;
+ }
+
+ d = i->display;
+ flushimage(d, 0); /* make sure subsequent flush is for us only */
+ ntot = 0;
+ while(r.min.y < r.max.y){
+ a = bufimage(d, 1+4+4*4);
+ if(a == 0){
+ kwerrstr("unloadimage: %r");
+ return -1;
+ }
+ dy = 8000/bpl;
+ if(dy <= 0){
+ kwerrstr("unloadimage: image too wide");
+ return -1;
+ }
+ if(dy > Dy(r))
+ dy = Dy(r);
+ a[0] = 'r';
+ BPLONG(a+1, i->id);
+ BPLONG(a+5, r.min.x);
+ BPLONG(a+9, r.min.y);
+ BPLONG(a+13, r.max.x);
+ BPLONG(a+17, r.min.y+dy);
+ if(flushimage(d, 0) < 0)
+ return -1;
+ if(d->local == 0)
+ release();
+ n = kchanio(d->datachan, data+ntot, ndata-ntot, OREAD);
+ if(d->local == 0)
+ acquire();
+ if(n < 0)
+ return n;
+ ntot += n;
+ r.min.y += dy;
+ }
+ return ntot;
+}
--- /dev/null
+++ b/libdraw/window.c
@@ -1,0 +1,203 @@
+#include "lib9.h"
+#include "draw.h"
+#include "kernel.h"
+
+typedef struct Memimage Memimage;
+
+static int screenid;
+
+Screen*
+allocscreen(Image *image, Image *fill, int public)
+{
+ uchar *a;
+ Screen *s;
+ int id, try;
+ Display *d;
+
+ d = image->display;
+ if(d != fill->display){
+ kwerrstr("allocscreen: image and fill on different displays");
+ return 0;
+ }
+ s = malloc(sizeof(Screen));
+ if(s == 0)
+ return 0;
+ SET(id);
+ for(try=0; try<25; try++){
+ /* loop until find a free id */
+ a = bufimage(d, 1+4+4+4+1);
+ if(a == 0){
+ free(s);
+ return 0;
+ }
+ id = ++screenid;
+ a[0] = 'A';
+ BPLONG(a+1, id);
+ BPLONG(a+5, image->id);
+ BPLONG(a+9, fill->id);
+ a[13] = public;
+ if(flushimage(d, 0) != -1)
+ break;
+ }
+ s->display = d;
+ s->id = id;
+ s->image = image;
+// assert(s->image && s->image->chan != 0);
+
+ s->fill = fill;
+ return s;
+}
+
+Screen*
+publicscreen(Display *d, int id, ulong chan)
+{
+ uchar *a;
+ Screen *s;
+
+ s = malloc(sizeof(Screen));
+ if(s == 0)
+ return 0;
+ a = bufimage(d, 1+4+4);
+ if(a == 0){
+ Error:
+ free(s);
+ return 0;
+ }
+ a[0] = 'S';
+ BPLONG(a+1, id);
+ BPLONG(a+5, chan);
+ if(flushimage(d, 0) < 0)
+ goto Error;
+
+ s->display = d;
+ s->id = id;
+ s->image = 0;
+ s->fill = 0;
+ return s;
+}
+
+int
+freescreen(Screen *s)
+{
+ uchar *a;
+ Display *d;
+
+ if(s == 0)
+ return 0;
+ d = s->display;
+ a = bufimage(d, 1+4);
+ if(a == 0)
+ return -1;
+ a[0] = 'F';
+ BPLONG(a+1, s->id);
+ /*
+ * flush(1) because screen is likely holding last reference to
+ * window, and want it to disappear visually.
+ */
+ if(flushimage(d, 1) < 0)
+ return -1;
+ free(s);
+ return 1;
+}
+
+Image*
+allocwindow(Screen *s, Rectangle r, int ref, ulong val)
+{
+ return _allocwindow(nil, s, r, ref, val);
+}
+
+Image*
+_allocwindow(Image *i, Screen *s, Rectangle r, int ref, ulong val)
+{
+ Display *d;
+
+ d = s->display;
+ i = _allocimage(i, d, r, s->image->chan, 0, val, s->id, ref);
+ if(i == 0)
+ return 0;
+ i->screen = s;
+ i->next = s->display->windows;
+ s->display->windows = i;
+ return i;
+}
+
+static
+void
+topbottom(Image **w, int n, int top)
+{
+ int i;
+ uchar *b;
+ Display *d;
+
+ if(n<0 || n>(Displaybufsize-100)/4){
+ _drawprint(2, "top/bottom: ridiculous number of windows\n");
+ return;
+ }
+ if(n==0)
+ return;
+ /* check that all images are on the same display; only it can check the screens */
+ d = w[0]->display;
+ for(i=1; i<n; i++)
+ if(w[i]->display != d){
+ _drawprint(2, "top/bottom: windows not on same display\n");
+ return;
+ }
+ b = bufimage(d, 1+1+2+4*n);
+ if (b == 0) {
+ _drawprint(2, "top/bottom: no bufimage\n");
+ return;
+ }
+ b[0] = 't';
+ b[1] = top;
+ BPSHORT(b+2, n);
+ for(i=0; i<n; i++)
+ BPLONG(b+4+4*i, w[i]->id);
+}
+
+void
+bottomwindow(Image *w)
+{
+ topbottom(&w, 1, 0);
+}
+
+void
+topwindow(Image *w)
+{
+ topbottom(&w, 1, 1);
+}
+
+void
+bottomnwindows(Image **w, int n)
+{
+ topbottom(w, n, 0);
+}
+
+void
+topnwindows(Image **w, int n)
+{
+ topbottom(w, n, 1);
+}
+
+int
+originwindow(Image *w, Point log, Point scr)
+{
+ uchar *b;
+ Point delta;
+
+ flushimage(w->display, 0);
+ b = bufimage(w->display, 1+4+2*4+2*4);
+ if(b == nil)
+ return 0;
+ b[0] = 'o';
+ BPLONG(b+1, w->id);
+ BPLONG(b+5, log.x);
+ BPLONG(b+9, log.y);
+ BPLONG(b+13, scr.x);
+ BPLONG(b+17, scr.y);
+ if(flushimage(w->display, 1) < 0)
+ return -1;
+ delta = subpt(log, w->r.min);
+ w->r = rectaddpt(w->r, delta);
+ w->clipr = rectaddpt(w->clipr, delta);
+ return 1;
+}
--- /dev/null
+++ b/libdraw/writecolmap.c
@@ -1,0 +1,37 @@
+#include "lib9.h"
+#include "draw.h"
+#include "kernel.h"
+
+/*
+ * This code (and the devdraw interface) will have to change
+ * if we ever get bitmaps with ldepth > 3, because the
+ * colormap will have to be written in chunks
+ */
+
+void
+writecolmap(Display *d, RGB *m)
+{
+ int i, n, fd;
+ char buf[64], *t;
+ ulong r, g, b;
+
+ sprint(buf, "/dev/draw/%d/colormap", d->dirno);
+ fd = open(buf, OWRITE);
+ if(fd < 0)
+ drawerror(d, "wrcolmap: open colormap failed");
+ t = malloc(8192);
+ if(t == nil)
+ return;
+ n = 0;
+ for(i = 0; i < 256; i++) {
+ r = m[i].red>>24;
+ g = m[i].green>>24;
+ b = m[i].blue>>24;
+ n += sprint(t+n, "%d %lud %lud %lud\n", 255-i, r, g, b);
+ }
+ i = libwrite(fd, t, n);
+ free(t);
+ close(fd);
+ if(i != n)
+ drawerror(d, "wrcolmap: bad write");
+}
--- /dev/null
+++ b/libdraw/writeimage.c
@@ -1,0 +1,185 @@
+#include "lib9.h"
+#include "draw.h"
+#include "kernel.h"
+
+#define HSHIFT 3 /* HSHIFT==5 runs slightly faster, but hash table is 64x bigger */
+#define NHASH (1<<(HSHIFT*NMATCH))
+#define HMASK (NHASH-1)
+#define hupdate(h, c) ((((h)<<HSHIFT)^(c))&HMASK)
+typedef struct Hlist Hlist;
+struct Hlist{
+ uchar *s;
+ Hlist *next, *prev;
+};
+
+int
+writeimage(int fd, Image *i, int dolock)
+{
+ uchar *outbuf, *outp, *eout; /* encoded data, pointer, end */
+ uchar *loutp; /* start of encoded line */
+ Hlist *hash; /* heads of hash chains of past strings */
+ Hlist *chain, *hp; /* hash chain members, pointer */
+ Hlist *cp; /* next Hlist to fall out of window */
+ int h; /* hash value */
+ uchar *line, *eline; /* input line, end pointer */
+ uchar *data, *edata; /* input buffer, end pointer */
+ ulong n; /* length of input buffer */
+ ulong nb; /* # of bytes returned by unloadimage */
+ int bpl; /* input line length */
+ int offs, runlen; /* offset, length of consumed data */
+ uchar dumpbuf[NDUMP]; /* dump accumulator */
+ int ndump; /* length of dump accumulator */
+ int miny, dy; /* y values while unloading input */
+ int chunk, ncblock;
+ Rectangle r;
+ uchar *p, *q, *s, *es, *t;
+ char hdr[11+5*12+1];
+ char cbuf[20];
+
+ chunk = i->display->bufsize - 32; /* a little room for header */
+ r = i->r;
+ bpl = bytesperline(r, i->depth);
+ n = Dy(r)*bpl;
+ data = malloc(n);
+ ncblock = _compblocksize(r, i->depth);
+ outbuf = malloc(ncblock);
+ hash = malloc(NHASH*sizeof(Hlist));
+ chain = malloc(NMEM*sizeof(Hlist));
+ if(data == 0 || outbuf == 0 || hash == 0 || chain == 0){
+ ErrOut:
+ free(data);
+ free(outbuf);
+ free(hash);
+ free(chain);
+ return -1;
+ }
+ for(miny = r.min.y; miny != r.max.y; miny += dy){
+ dy = r.max.y-miny;
+ if(dy*bpl > chunk)
+ dy = chunk/bpl;
+ if(dolock)
+ lockdisplay(i->display);
+ nb = unloadimage(i, Rect(r.min.x, miny, r.max.x, miny+dy),
+ data+(miny-r.min.y)*bpl, dy*bpl);
+ if(dolock)
+ unlockdisplay(i->display);
+ if(nb != dy*bpl)
+ goto ErrOut;
+ }
+ sprint(hdr, "compressed\n%11s %11d %11d %11d %11d ",
+ chantostr(cbuf, i->chan), r.min.x, r.min.y, r.max.x, r.max.y);
+ if(libwrite(fd, hdr, 11+5*12) != 11+5*12)
+ goto ErrOut;
+ edata = data+n;
+ eout = outbuf+ncblock;
+ line = data;
+ r.max.y = r.min.y;
+ while(line != edata){
+ memset(hash, 0, NHASH*sizeof(Hlist));
+ memset(chain, 0, NMEM*sizeof(Hlist));
+ cp = chain;
+ h = 0;
+ outp = outbuf;
+ for(n = 0; n != NMATCH; n++)
+ h = hupdate(h, line[n]);
+ loutp = outbuf;
+ while(line != edata){
+ ndump = 0;
+ eline = line+bpl;
+ for(p = line; p != eline; ){
+ if(eline-p < NRUN)
+ es = eline;
+ else
+ es = p+NRUN;
+ q = 0;
+ runlen = 0;
+ for(hp = hash[h].next; hp; hp = hp->next){
+ s = p + runlen;
+ if(s >= es)
+ continue;
+ t = hp->s + runlen;
+ for(; s >= p; s--)
+ if(*s != *t--)
+ goto matchloop;
+ t += runlen+2;
+ s += runlen+2;
+ for(; s < es; s++)
+ if(*s != *t++)
+ break;
+ n = s-p;
+ if(n > runlen){
+ runlen = n;
+ q = hp->s;
+ if(n == NRUN)
+ break;
+ }
+ matchloop: ;
+ }
+ if(runlen < NMATCH){
+ if(ndump == NDUMP){
+ if(eout-outp < ndump+1)
+ goto Bfull;
+ *outp++ = ndump-1+128;
+ memmove(outp, dumpbuf, ndump);
+ outp += ndump;
+ ndump = 0;
+ }
+ dumpbuf[ndump++] = *p;
+ runlen = 1;
+ }
+ else{
+ if(ndump != 0){
+ if(eout-outp < ndump+1)
+ goto Bfull;
+ *outp++ = ndump-1+128;
+ memmove(outp, dumpbuf, ndump);
+ outp += ndump;
+ ndump = 0;
+ }
+ offs = p-q-1;
+ if(eout-outp < 2)
+ goto Bfull;
+ *outp++ = ((runlen-NMATCH)<<2) + (offs>>8);
+ *outp++ = offs&255;
+ }
+ for(q = p+runlen; p != q; p++){
+ if(cp->prev)
+ cp->prev->next = 0;
+ cp->next = hash[h].next;
+ cp->prev = &hash[h];
+ if(cp->next)
+ cp->next->prev = cp;
+ cp->prev->next = cp;
+ cp->s = p;
+ if(++cp == &chain[NMEM])
+ cp = chain;
+ if(edata-p > NMATCH)
+ h = hupdate(h, p[NMATCH]);
+ }
+ }
+ if(ndump != 0){
+ if(eout-outp < ndump+1)
+ goto Bfull;
+ *outp++ = ndump-1+128;
+ memmove(outp, dumpbuf, ndump);
+ outp += ndump;
+ }
+ line = eline;
+ loutp = outp;
+ r.max.y++;
+ }
+ Bfull:
+ if(loutp == outbuf)
+ goto ErrOut;
+ n = loutp-outbuf;
+ sprint(hdr, "%11d %11ld ", r.max.y, n);
+ libwrite(fd, hdr, 2*12);
+ libwrite(fd, outbuf, n);
+ r.min.y = r.max.y;
+ }
+ free(data);
+ free(outbuf);
+ free(hash);
+ free(chain);
+ return 0;
+}
--- /dev/null
+++ b/libdraw/writesubfont.c
@@ -1,0 +1,45 @@
+#include "lib9.h"
+#include "draw.h"
+#include "kernel.h"
+
+static
+void
+packinfo(Fontchar *fc, uchar *p, int n)
+{
+ int j;
+
+ for(j=0; j<=n; j++){
+ p[0] = fc->x;
+ p[1] = fc->x>>8;
+ p[2] = fc->top;
+ p[3] = fc->bottom;
+ p[4] = fc->left;
+ p[5] = fc->width;
+ fc++;
+ p += 6;
+ }
+}
+
+int
+writesubfont(int fd, Subfont *f)
+{
+ char hdr[3*12+1];
+ uchar *data;
+ int nb;
+
+ sprint(hdr, "%11d %11d %11d ", f->n, f->height, f->ascent);
+ if(libwrite(fd, hdr, 3*12) != 3*12){
+ Err:
+ kwerrstr("writesubfont: bad write: %r");
+ return -1;
+ }
+ nb = 6*(f->n+1);
+ data = malloc(nb);
+ if(data == nil)
+ return -1;
+ packinfo(f->info, data, f->n);
+ if(libwrite(fd, data, nb) != nb)
+ goto Err;
+ free(data);
+ return 0;
+}
--- /dev/null
+++ b/libdynld/NOTICE
@@ -1,0 +1,28 @@
+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 © 2004-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
+
+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.
+
--- /dev/null
+++ b/libdynld/dynld-386.c
@@ -1,0 +1,42 @@
+#include "lib9.h"
+#include <a.out.h>
+#include <dynld.h>
+
+#define CHK(i,ntab) if((unsigned)(i)>=(ntab))return "bad relocation index"
+
+long
+dynmagic(void)
+{
+ return DYN_MAGIC | I_MAGIC;
+}
+
+char*
+dynreloc(uchar *b, ulong p, int m, Dynsym **tab, int ntab)
+{
+ int i;
+ ulong v, *pp;
+
+ p += (ulong)b;
+ pp = (ulong*)p;
+ v = *pp;
+ switch(m){
+ case 0:
+ v += (ulong)b;
+ break;
+ case 1:
+ i = v>>22;
+ v &= 0x3fffff;
+ CHK(i, ntab);
+ v += tab[i]->addr;
+ break;
+ case 2:
+ i = v>>22;
+ CHK(i, ntab);
+ v = tab[i]->addr -p-4;
+ break;
+ default:
+ return "bad relocation mode";
+ }
+ *pp = v;
+ return nil;
+}
--- /dev/null
+++ b/libdynld/dynld-arm.c
@@ -1,0 +1,44 @@
+#include "lib9.h"
+#include <a.out.h>
+#include <dynld.h>
+
+#define CHK(i,ntab) if((unsigned)(i)>=(ntab))return "bad relocation index"
+
+long
+dynmagic(void)
+{
+ return DYN_MAGIC | E_MAGIC;
+}
+
+char*
+dynreloc(uchar *b, ulong p, int m, Dynsym **tab, int ntab)
+{
+ int i;
+ ulong v, *pp;
+
+ p <<= 2;
+ p += (ulong)b;
+ pp = (ulong*)p;
+ v = *pp;
+ switch(m){
+ case 0:
+ v += (ulong)b;
+ break;
+ case 1:
+ i = v>>22;
+ v &= 0x3fffff;
+ CHK(i, ntab);
+ v += tab[i]->addr;
+ break;
+ case 2:
+ i = v&0x3ff;
+ v &= ~0x3ff;
+ CHK(i, ntab);
+ v |= ((tab[i]->addr-p-8)>>2)&0xffffff;
+ break;
+ default:
+ return "invalid relocation mode";
+ }
+ *pp = v;
+ return nil;
+}
--- /dev/null
+++ b/libdynld/dynld-mips.c
@@ -1,0 +1,22 @@
+#include "lib9.h"
+#include <a.out.h>
+#include <dynld.h>
+
+#define CHK(i,ntab) if((unsigned)(i)>=(ntab))return "bad relocation index"
+
+long
+dynmagic(void)
+{
+ return DYN_MAGIC | V_MAGIC;
+}
+
+char*
+dynreloc(uchar *b, ulong p, int m, Dynsym **tab, int ntab)
+{
+ USED(b);
+ USED(p);
+ USED(m);
+ USED(tab);
+ USED(ntab);
+ return "mips unimplemented";
+}
--- /dev/null
+++ b/libdynld/dynld-power.c
@@ -1,0 +1,65 @@
+#include "lib9.h"
+#include <a.out.h>
+#include <dynld.h>
+
+#define CHK(i,ntab) if((unsigned)(i)>=(ntab))return "bad relocation index"
+
+long
+dynmagic(void)
+{
+ return DYN_MAGIC | Q_MAGIC;
+}
+
+char*
+dynreloc(uchar *b, ulong p, int m, Dynsym **tab, int ntab)
+{
+ int i;
+ ulong v, *pp0, *pp1;
+
+ p <<= 2;
+ p += (ulong)b;
+ pp0 = (ulong*)p;
+ v = *pp0;
+ switch(m){
+ case 0:
+ v += (ulong)b;
+ break;
+ case 1:
+ i = v>>22;
+ v &= 0x3fffff;
+ CHK(i, ntab);
+ v += tab[i]->addr;
+ break;
+ case 2:
+ i = (v&0xffc)>>2;
+ v &= ~0xffc;
+ CHK(i, ntab);
+ v |= (tab[i]->addr-p)&0x3fffffc;
+ break;
+ case 3:
+ case 4:
+ case 5:
+ case 6:
+ pp1 = (ulong*)(p+4);
+ v = (v<<16)|(*pp1&0xffff);
+ if(m&1)
+ v += (ulong)b;
+ else{
+ i = v>>22;
+ v &= 0x3fffff;
+ CHK(i, ntab);
+ v += tab[i]->addr;
+ }
+ if(m >= 5 && (v&0x8000))
+ v += 0x10000;
+ *pp0 &= ~0xffff;
+ *pp0 |= v>>16;
+ *pp1 &= ~0xffff;
+ *pp1 |= v&0xffff;
+ return nil;
+ default:
+ return "invalid relocation mode";
+ }
+ *pp0 = v;
+ return nil;
+}
--- /dev/null
+++ b/libdynld/dynld-sparc.c
@@ -1,0 +1,20 @@
+#include "lib9.h"
+#include <a.out.h>
+#include <dynld.h>
+
+long
+dynmagic(void)
+{
+ return DYN_MAGIC | K_MAGIC;
+}
+
+char*
+dynreloc(uchar *b, ulong p, int m, Dynsym **tab, int ntab)
+{
+ USED(b);
+ USED(p);
+ USED(m);
+ USED(tab);
+ USED(ntab);
+ return "sparc unimplemented";
+}
--- /dev/null
+++ b/libdynld/dynld-spim.c
@@ -1,0 +1,22 @@
+#include "lib9.h"
+#include <a.out.h>
+#include <dynld.h>
+
+#define CHK(i,ntab) if((unsigned)(i)>=(ntab))return "bad relocation index"
+
+long
+dynmagic(void)
+{
+ return DYN_MAGIC | N_MAGIC;
+}
+
+char*
+dynreloc(uchar *b, ulong p, int m, Dynsym **tab, int ntab)
+{
+ USED(b);
+ USED(p);
+ USED(m);
+ USED(tab);
+ USED(ntab);
+ return "mips-le (spim) unimplemented";
+}
--- /dev/null
+++ b/libdynld/dynld.c
@@ -1,0 +1,258 @@
+#include "lib9.h"
+#include <a.out.h>
+#include <dynld.h>
+
+static ulong
+get2(uchar *b)
+{
+ return (b[0] << 8) | b[1];
+}
+
+static ulong
+get4(uchar *b)
+{
+ return (b[0] << 24) | (b[1] << 16) | (b[2] << 8) | b[3];
+}
+
+static ulong
+lgetbe(ulong l)
+{
+ union {
+ ulong l;
+ uchar c[4];
+ } u;
+ u.l = l;
+ return get4(u.c);
+}
+
+Dynsym*
+dynfindsym(char *s, Dynsym *tab, int ntab)
+{
+ int n, n2, d;
+ Dynsym *t, *m;
+
+ t = tab;
+ n = ntab;
+ while(n > 0){
+ n2 = n>>1;
+ m = t+n2;
+ d = strcmp(s, m->name);
+ if(d < 0){
+ n = n2;
+ continue;
+ }
+ if(d > 0){
+ t = m+1;
+ n -= n2+1;
+ continue;
+ }
+ return m;
+ }
+ return nil;
+}
+
+void*
+dynimport(Dynobj *o, char *name, ulong sig)
+{
+ Dynsym *t;
+
+ t = dynfindsym(name, o->export, o->nexport);
+ if(t == nil || sig != 0 && t->sig != 0 && t->sig != sig)
+ return nil;
+ return (void*)t->addr;
+}
+
+int
+dyntabsize(Dynsym *t)
+{
+ int n;
+
+ for(n = 0; t->name != nil; t++)
+ n++;
+ return n;
+}
+
+void
+dynobjfree(Dynobj *o)
+{
+ if(o != nil){
+ free(o->base);
+ free(o->import);
+ free(o);
+ }
+}
+
+void
+dynfreeimport(Dynobj *o)
+{
+ free(o->import);
+ o->import = nil;
+ o->nimport = 0;
+}
+
+static char Ereloc[] = "error reading object file";
+
+Dynobj*
+dynloadgen(void *file, long (*rd)(void*,void*,long), vlong (*sk)(void*,vlong,int), void (*werr)(char*), Dynsym *tab, int ntab, ulong maxsize)
+{
+ int i, m, n, ni, nr, relsize;
+ ulong syms, entry, sig, p, a;
+ uchar *base;
+ Exec e;
+ Dynsym *t;
+ Dynobj *l;
+ char *s, *err, buf[64];
+ uchar *reldata, *rp, *ep;
+ vlong off;
+
+ err = Ereloc; /* default */
+ off = (*sk)(file, 0, 1);
+ l = mallocz(sizeof(Dynobj), 1);
+ if(l == nil){
+ err = "can't allocate Dynobj";
+ goto Error;
+ }
+ if((*rd)(file, &e, sizeof(Exec)) != sizeof(Exec))
+ goto Error;
+ if(lgetbe(e.magic) != dynmagic()){
+ err = "not dynamic object file or wrong platform";
+ goto Error;
+ }
+ l->text = lgetbe(e.text);
+ l->data = lgetbe(e.data);
+ l->bss = lgetbe(e.bss);
+ syms = lgetbe(e.syms)+lgetbe(e.spsz)+lgetbe(e.pcsz);
+ entry = lgetbe(e.entry);
+ l->size = l->text + l->data + l->bss;
+ if(entry < 0 || entry >= l->size || entry & 3){
+ err = "invalid export table pointer (entry point)";
+ goto Error;
+ }
+ if(maxsize && l->size >= maxsize){
+ snprint(buf, sizeof(buf), "%lud: object too big", l->size);
+ err = buf;
+ goto Error;
+ }
+
+ l->base = base = malloc(l->size);
+ if(base == nil){
+ err = "out of memory: loading object file";
+ goto Error;
+ }
+ l->export = (Dynsym*)(base+entry);
+ if((*rd)(file, base, l->text+l->data) != l->text+l->data)
+ goto Error;
+ memset(base+l->text+l->data, 0, l->bss);
+ if((*sk)(file, syms, 1) < 0)
+ goto Error;
+ if((*rd)(file, buf, 4) != 4)
+ goto Error;
+ relsize = get4((uchar*)buf); /* always contains at least an import count (might be zero) */
+ if(relsize < 4)
+ goto Error;
+ reldata = malloc(relsize);
+ if(reldata == nil){
+ err = "out of memory: relocation data";
+ goto Error;
+ }
+ if((*rd)(file, reldata, relsize) != relsize)
+ goto Error;
+ rp = reldata;
+ ep = reldata+relsize;
+ ni = get4(rp);
+ rp += 4;
+ if(ni < 0 || ni > 8000)
+ goto Error; /* implausible size */
+ l->nimport = ni;
+ l->import = malloc(ni*sizeof(Dynsym*));
+ if(l->import == nil){
+ err = "out of memory: symbol table";
+ goto Error;
+ }
+ for(i = 0; i < ni; i++){
+ if(rp+5 > ep)
+ goto Error;
+ sig = get4(rp);
+ rp += 4;
+ s = (char*)rp;
+ while(*rp++)
+ if(rp >= ep)
+ goto Error;
+ t = dynfindsym(s, tab, ntab);
+ if(t == nil){
+ snprint(buf, sizeof(buf), "undefined symbol: %s", s);
+ err = buf;
+ goto Error;
+ }
+ if(sig != 0 && t->sig != 0 && t->sig != sig){
+ snprint(buf, sizeof(buf), "signature mismatch: %s (%lux != %lux)", s, sig, t->sig);
+ err = buf;
+ goto Error;
+ }
+ l->import[i] = t;
+ }
+
+ a = 0;
+ if(rp+4 > ep)
+ goto Error;
+ nr = get4(rp);
+ rp += 4;
+ for(i = 0; i < nr; i++){
+ if(rp >= ep)
+ goto Error;
+ m = *rp++;
+ n = m>>6;
+ if(rp+(1<<n) > ep)
+ goto Error;
+ switch(n){
+ case 0:
+ p = *rp++;
+ break;
+ case 1:
+ p = get2(rp);
+ rp += 2;
+ break;
+ case 2:
+ p = get4(rp);
+ rp += 4;
+ break;
+ default:
+ goto Error;
+ }
+ a += p;
+ err = dynreloc(base, a, m&0xf, l->import, ni);
+ if(err != nil){
+ snprint(buf, sizeof(buf), "dynamic object: %s", err);
+ err = buf;
+ goto Error;
+ }
+ }
+ free(reldata);
+
+ /* could check relocated export table here */
+ l->nexport = dyntabsize(l->export);
+
+ segflush(base, l->text);
+
+ return l;
+
+Error:
+ if(off >= 0)
+ (*sk)(file, off, 0); /* restore original file offset */
+ (*werr)(err);
+ dynobjfree(l);
+ return nil;
+}
+
+int
+dynloadable(void* file, long (*rd)(void*,void*,long), vlong (*sk)(void*,vlong,int))
+{
+ long magic;
+
+ if((*rd)(file, &magic, sizeof(magic)) != sizeof(magic)){
+ (*sk)(file, -(signed int)sizeof(magic), 1);
+ return 0;
+ }
+ (*sk)(file, -(signed int)sizeof(magic), 1);
+ return lgetbe(magic) == dynmagic();
+}
--- /dev/null
+++ b/libdynld/dynloadfd.c
@@ -1,0 +1,35 @@
+#include "lib9.h"
+#include <a.out.h>
+#include <dynld.h>
+
+typedef struct Fd Fd;
+struct Fd {
+ int fd;
+};
+
+static long
+readfd(void *a, void *buf, long nbytes)
+{
+ return read(((Fd*)a)->fd, buf, nbytes);
+}
+
+static vlong
+seekfd(void *a, vlong off, int t)
+{
+ return seek(((Fd*)a)->fd, off, t);
+}
+
+static void
+errfd(char *s)
+{
+ werrstr("%s", s);
+}
+
+Dynobj*
+dynloadfd(int fd, Dynsym *sym, int nsym, ulong maxsize)
+{
+ Fd f;
+
+ f.fd = fd;
+ return dynloadgen(&f, readfd, seekfd, errfd, sym, nsym, maxsize);
+}
--- /dev/null
+++ b/libdynld/mkfile
@@ -1,0 +1,12 @@
+<../mkconfig
+
+LIB=libdynld.a
+
+OFILES=\
+ dynld-$OBJTYPE.$O\
+ dynloadfd.$O\
+ dynld.$O\
+
+HFILES=$ROOT/$SYSTARG/$OBJTYPE/include/lib9.h\
+
+<$ROOT/mkfiles/mksyslib-$SHELLTYPE
--- /dev/null
+++ b/libfreetype/NOTICE/FTL.txt
@@ -1,0 +1,164 @@
+ The FreeType Project LICENSE
+ ----------------------------
+
+ 2000-Feb-08
+
+ Copyright 1996-2000 by
+ David Turner, Robert Wilhelm, and Werner Lemberg
+
+
+
+Introduction
+============
+
+ The FreeType Project is distributed in several archive packages;
+ some of them may contain, in addition to the FreeType font engine,
+ various tools and contributions which rely on, or relate to, the
+ FreeType Project.
+
+ This license applies to all files found in such packages, and
+ which do not fall under their own explicit license. The license
+ affects thus the FreeType font engine, the test programs,
+ documentation and makefiles, at the very least.
+
+ This license was inspired by the BSD, Artistic, and IJG
+ (Independent JPEG Group) licenses, which all encourage inclusion
+ and use of free software in commercial and freeware products
+ alike. As a consequence, its main points are that:
+
+ o We don't promise that this software works. However, we will be
+ interested in any kind of bug reports. (`as is' distribution)
+
+ o You can use this software for whatever you want, in parts or
+ full form, without having to pay us. (`royalty-free' usage)
+
+ o You may not pretend that you wrote this software. If you use
+ it, or only parts of it, in a program, you must acknowledge
+ somewhere in your documentation that you have used the
+ FreeType code. (`credits')
+
+ We specifically permit and encourage the inclusion of this
+ software, with or without modifications, in commercial products.
+ We disclaim all warranties covering The FreeType Project and
+ assume no liability related to The FreeType Project.
+
+
+Legal Terms
+===========
+
+0. Definitions
+--------------
+
+ Throughout this license, the terms `package', `FreeType Project',
+ and `FreeType archive' refer to the set of files originally
+ distributed by the authors (David Turner, Robert Wilhelm, and
+ Werner Lemberg) as the `FreeType Project', be they named as alpha,
+ beta or final release.
+
+ `You' refers to the licensee, or person using the project, where
+ `using' is a generic term including compiling the project's source
+ code as well as linking it to form a `program' or `executable'.
+ This program is referred to as `a program using the FreeType
+ engine'.
+
+ This license applies to all files distributed in the original
+ FreeType Project, including all source code, binaries and
+ documentation, unless otherwise stated in the file in its
+ original, unmodified form as distributed in the original archive.
+ If you are unsure whether or not a particular file is covered by
+ this license, you must contact us to verify this.
+
+ The FreeType Project is copyright (C) 1996-2000 by David Turner,
+ Robert Wilhelm, and Werner Lemberg. All rights reserved except as
+ specified below.
+
+1. No Warranty
+--------------
+
+ THE FREETYPE PROJECT IS PROVIDED `AS IS' WITHOUT WARRANTY OF ANY
+ KIND, EITHER EXPRESS OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
+ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ PURPOSE. IN NO EVENT WILL ANY OF THE AUTHORS OR COPYRIGHT HOLDERS
+ BE LIABLE FOR ANY DAMAGES CAUSED BY THE USE OR THE INABILITY TO
+ USE, OF THE FREETYPE PROJECT.
+
+2. Redistribution
+-----------------
+
+ This license grants a worldwide, royalty-free, perpetual and
+ irrevocable right and license to use, execute, perform, compile,
+ display, copy, create derivative works of, distribute and
+ sublicense the FreeType Project (in both source and object code
+ forms) and derivative works thereof for any purpose; and to
+ authorize others to exercise some or all of the rights granted
+ herein, subject to the following conditions:
+
+ o Redistribution of source code must retain this license file
+ (`LICENSE.TXT') unaltered; any additions, deletions or changes
+ to the original files must be clearly indicated in
+ accompanying documentation. The copyright notices of the
+ unaltered, original files must be preserved in all copies of
+ source files.
+
+ o Redistribution in binary form must provide a disclaimer that
+ states that the software is based in part of the work of the
+ FreeType Team, in the distribution documentation. We also
+ encourage you to put an URL to the FreeType web page in your
+ documentation, though this isn't mandatory.
+
+ These conditions apply to any software derived from or based on
+ the FreeType Project, not just the unmodified files. If you use
+ our work, you must acknowledge us. However, no fee need be paid
+ to us.
+
+3. Advertising
+--------------
+
+ Neither the FreeType authors and contributors nor you shall use
+ the name of the other for commercial, advertising, or promotional
+ purposes without specific prior written permission.
+
+ We suggest, but do not require, that you use one or more of the
+ following phrases to refer to this software in your documentation
+ or advertising materials: `FreeType Project', `FreeType Engine',
+ `FreeType library', or `FreeType Distribution'.
+
+ As you have not signed this license, you are not required to
+ accept it. However, as the FreeType Project is copyrighted
+ material, only this license, or another one contracted with the
+ authors, grants you the right to use, distribute, and modify it.
+ Therefore, by using, distributing, or modifying the FreeType
+ Project, you indicate that you understand and accept all the terms
+ of this license.
+
+4. Contacts
+-----------
+
+ There are two mailing lists related to FreeType:
+
+ o freetype@freetype.org
+
+ Discusses general use and applications of FreeType, as well as
+ future and wanted additions to the library and distribution.
+ If you are looking for support, start in this list if you
+ haven't found anything to help you in the documentation.
+
+ o devel@freetype.org
+
+ Discusses bugs, as well as engine internals, design issues,
+ specific licenses, porting, etc.
+
+ o http://www.freetype.org
+
+ Holds the current FreeType web page, which will allow you to
+ download our latest development version and read online
+ documentation.
+
+ You can also contact us individually at:
+
+ David Turner <david.turner@freetype.org>
+ Robert Wilhelm <robert.wilhelm@freetype.org>
+ Werner Lemberg <werner.lemberg@freetype.org>
+
+
+--- end of LICENSE.TXT ---
--- /dev/null
+++ b/libfreetype/NOTICE/GPL.txt
@@ -1,0 +1,339 @@
+ GNU GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc.
+ 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users. This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it. (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.) You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+ To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have. You must make sure that they, too, receive or can get the
+source code. And you must show them these terms so they know their
+rights.
+
+ We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+ Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software. If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+ Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary. To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ GNU GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License. The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language. (Hereinafter, translation is included without limitation in
+the term "modification".) Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+ 1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+ 2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) You must cause the modified files to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ b) You must cause any work that you distribute or publish, that in
+ whole or in part contains or is derived from the Program or any
+ part thereof, to be licensed as a whole at no charge to all third
+ parties under the terms of this License.
+
+ c) If the modified program normally reads commands interactively
+ when run, you must cause it, when started running for such
+ interactive use in the most ordinary way, to print or display an
+ announcement including an appropriate copyright notice and a
+ notice that there is no warranty (or else, saying that you provide
+ a warranty) and that users may redistribute the program under
+ these conditions, and telling the user how to view a copy of this
+ License. (Exception: if the Program itself is interactive but
+ does not normally print such an announcement, your work based on
+ the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+ a) Accompany it with the complete corresponding machine-readable
+ source code, which must be distributed under the terms of Sections
+ 1 and 2 above on a medium customarily used for software interchange; or,
+
+ b) Accompany it with a written offer, valid for at least three
+ years, to give any third party, for a charge no more than your
+ cost of physically performing source distribution, a complete
+ machine-readable copy of the corresponding source code, to be
+ distributed under the terms of Sections 1 and 2 above on a medium
+ customarily used for software interchange; or,
+
+ c) Accompany it with the information you received as to the offer
+ to distribute corresponding source code. (This alternative is
+ allowed only for noncommercial distribution and only if you
+ received the program in object code or executable form with such
+ an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it. For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable. However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License. Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+ 5. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Program or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+ 6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+ 7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all. For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded. In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+ 9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation. If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+ 10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission. For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this. Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+ NO WARRANTY
+
+ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+ Appendix: How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) 19yy <name of author>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+ Gnomovision version 69, Copyright (C) 19yy name of author
+ Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+ `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+ <signature of Ty Coon>, 1 April 1989
+ Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs. If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library. If this is what you want to do, use the GNU Library General
+Public License instead of this License.
--- /dev/null
+++ b/libfreetype/NOTICE/PATENTS
@@ -1,0 +1,27 @@
+
+ FreeType Patents Disclaimer
+ August 1999
+
+
+
+WE HAVE DISCOVERED THAT APPLE OWNS SEVERAL PATENTS RELATED TO THE
+RENDERING OF TRUETYPE FONTS. THIS COULD MEAN THAT THE FREE USE OF
+FREETYPE MIGHT BE ILLEGAL IN THE USA, JAPAN, AND POSSIBLY OTHER
+COUNTRIES, BE IT IN COMMERCIAL OR OPEN SOURCE PRODUCTS.
+
+FOR MORE DETAILS, WE STRONGLY ADVISE YOU TO GO TO THE FREETYPE
+PATENTS PAGE AT THE FOLLOWING WEB ADDRESS:
+
+ http://www.freetype.org/patents.htm
+
+WE WILL NOT PLACE INFORMATION IN THIS FILE AS THE SITUATION IS STILL
+UNDETERMINED FOR NOW. AT THE TIME THESE LINES ARE WRITTEN, WE HAVE
+CONTACTED APPLE'S LEGAL DEPARTMENT AND ARE STILL WAITING FOR THEIR
+ANSWER ON THE SUBJECT.
+
+PLEASE READ THE `INSTALL' FILE TO SEE HOW TO DISABLE THE ENGINE'S
+BYTECODE INTERPRETER IN ORDER TO BUILD A PATENT-FREE ENGINE, AT THE
+COST OF RENDERING QUALITY.
+
+
+--- end of PATENTS ---
--- /dev/null
+++ b/libfreetype/NOTICE/license.txt
@@ -1,0 +1,10 @@
+
+FreeType comes with two licenses from which you can choose the one which
+fits your needs best:
+
+ . The FreeType License, in file `docs/FTL.txt'.
+
+ . The GNU General Public License, in file `docs/GPL.txt'.
+
+The contributed PCF driver comes with a license similar to that of X Windows
+which is compatible to the above two licenses (see file src/pcf/readme).
--- /dev/null
+++ b/libfreetype/adler32.c
@@ -1,0 +1,48 @@
+/* adler32.c -- compute the Adler-32 checksum of a data stream
+ * Copyright (C) 1995-2002 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/* @(#) $Id: adler32.c,v 1.2 2002/11/06 22:32:54 davidT Exp $ */
+
+#include "zlib.h"
+
+#define BASE 65521L /* largest prime smaller than 65536 */
+#define NMAX 5552
+/* NMAX is the largest n such that 255n(n+1)/2 + (n+1)(BASE-1) <= 2^32-1 */
+
+#define DO1(buf,i) {s1 += buf[i]; s2 += s1;}
+#define DO2(buf,i) DO1(buf,i); DO1(buf,i+1);
+#define DO4(buf,i) DO2(buf,i); DO2(buf,i+2);
+#define DO8(buf,i) DO4(buf,i); DO4(buf,i+4);
+#define DO16(buf) DO8(buf,0); DO8(buf,8);
+
+/* ========================================================================= */
+ZEXTERNDEF uLong ZEXPORT adler32(adler, buf, len)
+ uLong adler;
+ const Bytef *buf;
+ uInt len;
+{
+ unsigned long s1 = adler & 0xffff;
+ unsigned long s2 = (adler >> 16) & 0xffff;
+ int k;
+
+ if (buf == Z_NULL) return 1L;
+
+ while (len > 0) {
+ k = len < NMAX ? len : NMAX;
+ len -= k;
+ while (k >= 16) {
+ DO16(buf);
+ buf += 16;
+ k -= 16;
+ }
+ if (k != 0) do {
+ s1 += *buf++;
+ s2 += s1;
+ } while (--k);
+ s1 %= BASE;
+ s2 %= BASE;
+ }
+ return (s2 << 16) | s1;
+}
--- /dev/null
+++ b/libfreetype/ahangles.c
@@ -1,0 +1,147 @@
+/***************************************************************************/
+/* */
+/* ahangles.h */
+/* */
+/* A routine used to compute vector angles with limited accuracy */
+/* and very high speed (body). */
+/* */
+/* Copyright 2000-2001, 2002 Catharon Productions Inc. */
+/* Author: David Turner */
+/* */
+/* This file is part of the Catharon Typography Project and shall only */
+/* be used, modified, and distributed under the terms of the Catharon */
+/* Open Source License that should come with this file under the name */
+/* `CatharonLicense.txt'. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/* Note that this license is compatible with the FreeType license. */
+/* */
+/***************************************************************************/
+
+
+#include <ft2build.h>
+#include "ahangles.h"
+
+
+ /* the following table has been automatically generated with */
+ /* the `mather.py' Python script */
+
+ const AH_Angle ah_arctan[1L << AH_ATAN_BITS] =
+ {
+ 0, 0, 1, 1, 1, 2, 2, 2,
+ 3, 3, 3, 3, 4, 4, 4, 5,
+ 5, 5, 6, 6, 6, 7, 7, 7,
+ 8, 8, 8, 9, 9, 9, 10, 10,
+ 10, 10, 11, 11, 11, 12, 12, 12,
+ 13, 13, 13, 14, 14, 14, 14, 15,
+ 15, 15, 16, 16, 16, 17, 17, 17,
+ 18, 18, 18, 18, 19, 19, 19, 20,
+ 20, 20, 21, 21, 21, 21, 22, 22,
+ 22, 23, 23, 23, 24, 24, 24, 24,
+ 25, 25, 25, 26, 26, 26, 26, 27,
+ 27, 27, 28, 28, 28, 28, 29, 29,
+ 29, 30, 30, 30, 30, 31, 31, 31,
+ 31, 32, 32, 32, 33, 33, 33, 33,
+ 34, 34, 34, 34, 35, 35, 35, 35,
+ 36, 36, 36, 36, 37, 37, 37, 38,
+ 38, 38, 38, 39, 39, 39, 39, 40,
+ 40, 40, 40, 41, 41, 41, 41, 42,
+ 42, 42, 42, 42, 43, 43, 43, 43,
+ 44, 44, 44, 44, 45, 45, 45, 45,
+ 46, 46, 46, 46, 46, 47, 47, 47,
+ 47, 48, 48, 48, 48, 48, 49, 49,
+ 49, 49, 50, 50, 50, 50, 50, 51,
+ 51, 51, 51, 51, 52, 52, 52, 52,
+ 52, 53, 53, 53, 53, 53, 54, 54,
+ 54, 54, 54, 55, 55, 55, 55, 55,
+ 56, 56, 56, 56, 56, 57, 57, 57,
+ 57, 57, 57, 58, 58, 58, 58, 58,
+ 59, 59, 59, 59, 59, 59, 60, 60,
+ 60, 60, 60, 61, 61, 61, 61, 61,
+ 61, 62, 62, 62, 62, 62, 62, 63,
+ 63, 63, 63, 63, 63, 64, 64, 64
+ };
+
+
+ FT_LOCAL_DEF( AH_Angle )
+ ah_angle( FT_Vector* v )
+ {
+ FT_Pos dx, dy;
+ AH_Angle angle;
+
+
+ dx = v->x;
+ dy = v->y;
+
+ /* check trivial cases */
+ if ( dy == 0 )
+ {
+ angle = 0;
+ if ( dx < 0 )
+ angle = AH_PI;
+ return angle;
+ }
+ else if ( dx == 0 )
+ {
+ angle = AH_HALF_PI;
+ if ( dy < 0 )
+ angle = -AH_HALF_PI;
+ return angle;
+ }
+
+ angle = 0;
+ if ( dx < 0 )
+ {
+ dx = -v->x;
+ dy = -v->y;
+ angle = AH_PI;
+ }
+
+ if ( dy < 0 )
+ {
+ FT_Pos tmp;
+
+
+ tmp = dx;
+ dx = -dy;
+ dy = tmp;
+ angle -= AH_HALF_PI;
+ }
+
+ if ( dx == 0 && dy == 0 )
+ return 0;
+
+ if ( dx == dy )
+ angle += AH_PI / 4;
+ else if ( dx > dy )
+ angle += ah_arctan[FT_DivFix( dy, dx ) >> ( 16 - AH_ATAN_BITS )];
+ else
+ angle += AH_HALF_PI -
+ ah_arctan[FT_DivFix( dx, dy ) >> ( 16 - AH_ATAN_BITS )];
+
+ if ( angle > AH_PI )
+ angle -= AH_2PI;
+
+ return angle;
+ }
+
+
+ FT_LOCAL_DEF( AH_Angle )
+ ah_angle_diff( AH_Angle angle1,
+ AH_Angle angle2 )
+ {
+ AH_Angle delta;
+
+
+ delta = ( angle2 - angle1 );
+ if ( delta < 0 )
+ delta += AH_2PI;
+
+ if ( delta > AH_PI )
+ delta -= AH_2PI;
+
+ return delta;
+ }
+
+/* END */
--- /dev/null
+++ b/libfreetype/ahangles.h
@@ -1,0 +1,64 @@
+/***************************************************************************/
+/* */
+/* ahangles.h */
+/* */
+/* A routine used to compute vector angles with limited accuracy */
+/* and very high speed (specification). */
+/* */
+/* Copyright 2000-2001, 2002 Catharon Productions Inc. */
+/* Author: David Turner */
+/* */
+/* This file is part of the Catharon Typography Project and shall only */
+/* be used, modified, and distributed under the terms of the Catharon */
+/* Open Source License that should come with this file under the name */
+/* `CatharonLicense.txt'. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/* Note that this license is compatible with the FreeType license. */
+/* */
+/***************************************************************************/
+
+
+#ifndef __AHANGLES_H__
+#define __AHANGLES_H__
+
+
+#include <ft2build.h>
+#include FT_INTERNAL_OBJECTS_H
+#include "ahtypes.h"
+
+
+FT_BEGIN_HEADER
+
+
+ /* PI expressed in ah_angles -- we don't really need an important */
+ /* precision, so 256 should be enough */
+#define AH_PI 256
+#define AH_2PI ( AH_PI * 2 )
+#define AH_HALF_PI ( AH_PI / 2 )
+#define AH_2PIMASK ( AH_2PI - 1 )
+
+ /* the number of bits used to express an arc tangent; */
+ /* see the structure of the lookup table */
+#define AH_ATAN_BITS 8
+
+ extern
+ const AH_Angle ah_arctan[1L << AH_ATAN_BITS];
+
+
+ FT_LOCAL( AH_Angle )
+ ah_angle( FT_Vector* v );
+
+
+ FT_LOCAL( AH_Angle )
+ ah_angle_diff( AH_Angle angle1,
+ AH_Angle angle2 );
+
+
+FT_END_HEADER
+
+#endif /* __AHANGLES_H__ */
+
+
+/* END */
--- /dev/null
+++ b/libfreetype/aherrors.h
@@ -1,0 +1,40 @@
+/***************************************************************************/
+/* */
+/* aherrors.h */
+/* */
+/* Autohinter error codes (specification only). */
+/* */
+/* Copyright 2001 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+
+ /*************************************************************************/
+ /* */
+ /* This file is used to define the Autohinter error enumeration */
+ /* constants. */
+ /* */
+ /*************************************************************************/
+
+#ifndef __AHERRORS_H__
+#define __AHERRORS_H__
+
+#include FT_MODULE_ERRORS_H
+
+#undef __FTERRORS_H__
+
+#define FT_ERR_PREFIX AH_Err_
+#define FT_ERR_BASE FT_Mod_Err_Autohint
+
+#include FT_ERRORS_H
+
+#endif /* __AHERRORS_H__ */
+
+/* END */
--- /dev/null
+++ b/libfreetype/ahglobal.c
@@ -1,0 +1,395 @@
+/***************************************************************************/
+/* */
+/* ahglobal.c */
+/* */
+/* Routines used to compute global metrics automatically (body). */
+/* */
+/* Copyright 2000-2001, 2002 Catharon Productions Inc. */
+/* Author: David Turner */
+/* */
+/* This file is part of the Catharon Typography Project and shall only */
+/* be used, modified, and distributed under the terms of the Catharon */
+/* Open Source License that should come with this file under the name */
+/* `CatharonLicense.txt'. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/* Note that this license is compatible with the FreeType license. */
+/* */
+/***************************************************************************/
+
+
+#include <ft2build.h>
+#include FT_INTERNAL_DEBUG_H
+#include "ahglobal.h"
+#include "ahglyph.h"
+
+
+#define MAX_TEST_CHARACTERS 12
+
+ static
+ const char* blue_chars[AH_BLUE_MAX] =
+ {
+ "THEZOCQS",
+ "HEZLOCUS",
+ "xzroesc",
+ "xzroesc",
+ "pqgjy"
+ };
+
+
+ /* simple insertion sort */
+ static void
+ sort_values( FT_Int count,
+ FT_Pos* table )
+ {
+ FT_Int i, j;
+ FT_Pos swap;
+
+
+ for ( i = 1; i < count; i++ )
+ {
+ for ( j = i; j > 0; j-- )
+ {
+ if ( table[j] > table[j - 1] )
+ break;
+
+ swap = table[j];
+ table[j] = table[j - 1];
+ table[j - 1] = swap;
+ }
+ }
+ }
+
+
+ static FT_Error
+ ah_hinter_compute_blues( AH_Hinter hinter )
+ {
+ AH_Blue blue;
+ AH_Globals globals = &hinter->globals->design;
+ FT_Pos flats [MAX_TEST_CHARACTERS];
+ FT_Pos rounds[MAX_TEST_CHARACTERS];
+ FT_Int num_flats;
+ FT_Int num_rounds;
+
+ FT_Face face;
+ FT_GlyphSlot glyph;
+ FT_Error error;
+ FT_CharMap charmap;
+
+
+ face = hinter->face;
+ glyph = face->glyph;
+
+ /* save current charmap */
+ charmap = face->charmap;
+
+ /* do we have a Unicode charmap in there? */
+ error = FT_Select_Charmap( face, FT_ENCODING_UNICODE );
+ if ( error )
+ goto Exit;
+
+ /* we compute the blues simply by loading each character from the */
+ /* 'blue_chars[blues]' string, then compute its top-most and */
+ /* bottom-most points */
+
+ AH_LOG(( "blue zones computation\n" ));
+ AH_LOG(( "------------------------------------------------\n" ));
+
+ for ( blue = AH_BLUE_CAPITAL_TOP; blue < AH_BLUE_MAX; blue++ )
+ {
+ const char* p = blue_chars[blue];
+ const char* limit = p + MAX_TEST_CHARACTERS;
+ FT_Pos *blue_ref, *blue_shoot;
+
+
+ AH_LOG(( "blue %3d: ", blue ));
+
+ num_flats = 0;
+ num_rounds = 0;
+
+ for ( ; p < limit; p++ )
+ {
+ FT_UInt glyph_index;
+ FT_Vector* extremum;
+ FT_Vector* points;
+ FT_Vector* point_limit;
+ FT_Vector* point;
+ FT_Bool round;
+
+
+ /* exit if we reach the end of the string */
+ if ( !*p )
+ break;
+
+ AH_LOG(( "`%c'", *p ));
+
+ /* load the character in the face -- skip unknown or empty ones */
+ glyph_index = FT_Get_Char_Index( face, (FT_UInt)*p );
+ if ( glyph_index == 0 )
+ continue;
+
+ error = FT_Load_Glyph( face, glyph_index, FT_LOAD_NO_SCALE );
+ if ( error || glyph->outline.n_points <= 0 )
+ continue;
+
+ /* now compute min or max point indices and coordinates */
+ points = glyph->outline.points;
+ point_limit = points + glyph->outline.n_points;
+ point = points;
+ extremum = point;
+ point++;
+
+ if ( AH_IS_TOP_BLUE( blue ) )
+ {
+ for ( ; point < point_limit; point++ )
+ if ( point->y > extremum->y )
+ extremum = point;
+ }
+ else
+ {
+ for ( ; point < point_limit; point++ )
+ if ( point->y < extremum->y )
+ extremum = point;
+ }
+
+ AH_LOG(( "%5d", (int)extremum->y ));
+
+ /* now, check whether the point belongs to a straight or round */
+ /* segment; we first need to find in which contour the extremum */
+ /* lies, then see its previous and next points */
+ {
+ FT_Int idx = (FT_Int)( extremum - points );
+ FT_Int n;
+ FT_Int first, last, prev, next, end;
+ FT_Pos dist;
+
+
+ last = -1;
+ first = 0;
+
+ for ( n = 0; n < glyph->outline.n_contours; n++ )
+ {
+ end = glyph->outline.contours[n];
+ if ( end >= idx )
+ {
+ last = end;
+ break;
+ }
+ first = end + 1;
+ }
+
+ /* XXX: should never happen! */
+ if ( last < 0 )
+ continue;
+
+ /* now look for the previous and next points that are not on the */
+ /* same Y coordinate. Threshold the `closeness'... */
+
+ prev = idx;
+ next = prev;
+
+ do
+ {
+ if ( prev > first )
+ prev--;
+ else
+ prev = last;
+
+ dist = points[prev].y - extremum->y;
+ if ( dist < -5 || dist > 5 )
+ break;
+
+ } while ( prev != idx );
+
+ do
+ {
+ if ( next < last )
+ next++;
+ else
+ next = first;
+
+ dist = points[next].y - extremum->y;
+ if ( dist < -5 || dist > 5 )
+ break;
+
+ } while ( next != idx );
+
+ /* now, set the `round' flag depending on the segment's kind */
+ round = FT_BOOL(
+ FT_CURVE_TAG( glyph->outline.tags[prev] ) != FT_CURVE_TAG_ON ||
+ FT_CURVE_TAG( glyph->outline.tags[next] ) != FT_CURVE_TAG_ON );
+
+ AH_LOG(( "%c ", round ? 'r' : 'f' ));
+ }
+
+ if ( round )
+ rounds[num_rounds++] = extremum->y;
+ else
+ flats[num_flats++] = extremum->y;
+ }
+
+ AH_LOG(( "\n" ));
+
+ /* we have computed the contents of the `rounds' and `flats' tables, */
+ /* now determine the reference and overshoot position of the blue; */
+ /* we simply take the median value after a simple short */
+ sort_values( num_rounds, rounds );
+ sort_values( num_flats, flats );
+
+ blue_ref = globals->blue_refs + blue;
+ blue_shoot = globals->blue_shoots + blue;
+ if ( num_flats == 0 && num_rounds == 0 )
+ {
+ *blue_ref = -10000;
+ *blue_shoot = -10000;
+ }
+ else if ( num_flats == 0 )
+ {
+ *blue_ref =
+ *blue_shoot = rounds[num_rounds / 2];
+ }
+ else if ( num_rounds == 0 )
+ {
+ *blue_ref =
+ *blue_shoot = flats[num_flats / 2];
+ }
+ else
+ {
+ *blue_ref = flats[num_flats / 2];
+ *blue_shoot = rounds[num_rounds / 2];
+ }
+
+ /* there are sometimes problems: if the overshoot position of top */
+ /* zones is under its reference position, or the opposite for bottom */
+ /* zones. We must thus check everything there and correct the errors */
+ if ( *blue_shoot != *blue_ref )
+ {
+ FT_Pos ref = *blue_ref;
+ FT_Pos shoot = *blue_shoot;
+ FT_Bool over_ref = FT_BOOL( shoot > ref );
+
+
+ if ( AH_IS_TOP_BLUE( blue ) ^ over_ref )
+ *blue_shoot = *blue_ref = ( shoot + ref ) / 2;
+ }
+
+ AH_LOG(( "-- ref = %ld, shoot = %ld\n", *blue_ref, *blue_shoot ));
+ }
+
+ /* reset original face charmap */
+ FT_Set_Charmap( face, charmap );
+ error = 0;
+
+ Exit:
+ return error;
+ }
+
+
+ static FT_Error
+ ah_hinter_compute_widths( AH_Hinter hinter )
+ {
+ /* scan the array of segments in each direction */
+ AH_Outline outline = hinter->glyph;
+ AH_Segment segments;
+ AH_Segment limit;
+ AH_Globals globals = &hinter->globals->design;
+ FT_Pos* widths;
+ FT_Int dimension;
+ FT_Int* p_num_widths;
+ FT_Error error = 0;
+ FT_Pos edge_distance_threshold = 32000;
+
+
+ globals->num_widths = 0;
+ globals->num_heights = 0;
+
+ /* For now, compute the standard width and height from the `o' */
+ /* character. I started computing the stem width of the `i' and the */
+ /* stem height of the "-", but it wasn't too good. Moreover, we now */
+ /* have a single character that gives us standard width and height. */
+ {
+ FT_UInt glyph_index;
+
+
+ glyph_index = FT_Get_Char_Index( hinter->face, 'o' );
+ if ( glyph_index == 0 )
+ return 0;
+
+ error = FT_Load_Glyph( hinter->face, glyph_index, FT_LOAD_NO_SCALE );
+ if ( error )
+ goto Exit;
+
+ error = ah_outline_load( hinter->glyph, hinter->face );
+ if ( error )
+ goto Exit;
+
+ ah_outline_compute_segments( hinter->glyph );
+ ah_outline_link_segments( hinter->glyph );
+ }
+
+ segments = outline->horz_segments;
+ limit = segments + outline->num_hsegments;
+ widths = globals->heights;
+ p_num_widths = &globals->num_heights;
+
+ for ( dimension = 1; dimension >= 0; dimension-- )
+ {
+ AH_Segment seg = segments;
+ AH_Segment link;
+ FT_Int num_widths = 0;
+
+
+ for ( ; seg < limit; seg++ )
+ {
+ link = seg->link;
+ /* we only consider stem segments there! */
+ if ( link && link->link == seg && link > seg )
+ {
+ FT_Pos dist;
+
+
+ dist = seg->pos - link->pos;
+ if ( dist < 0 )
+ dist = -dist;
+
+ if ( num_widths < AH_MAX_WIDTHS )
+ widths[num_widths++] = dist;
+ }
+ }
+
+ sort_values( num_widths, widths );
+ *p_num_widths = num_widths;
+
+ /* we will now try to find the smallest width */
+ if ( num_widths > 0 && widths[0] < edge_distance_threshold )
+ edge_distance_threshold = widths[0];
+
+ segments = outline->vert_segments;
+ limit = segments + outline->num_vsegments;
+ widths = globals->widths;
+ p_num_widths = &globals->num_widths;
+ }
+
+ /* Now, compute the edge distance threshold as a fraction of the */
+ /* smallest width in the font. Set it in `hinter.glyph' too! */
+ if ( edge_distance_threshold == 32000 )
+ edge_distance_threshold = 50;
+
+ /* let's try 20% */
+ hinter->glyph->edge_distance_threshold = edge_distance_threshold / 5;
+
+ Exit:
+ return error;
+ }
+
+
+ FT_LOCAL_DEF( FT_Error )
+ ah_hinter_compute_globals( AH_Hinter hinter )
+ {
+ return ah_hinter_compute_widths( hinter ) ||
+ ah_hinter_compute_blues ( hinter );
+ }
+
+
+/* END */
--- /dev/null
+++ b/libfreetype/ahglobal.h
@@ -1,0 +1,49 @@
+/***************************************************************************/
+/* */
+/* ahglobal.h */
+/* */
+/* Routines used to compute global metrics automatically */
+/* (specification). */
+/* */
+/* Copyright 2000-2001, 2002 Catharon Productions Inc. */
+/* Author: David Turner */
+/* */
+/* This file is part of the Catharon Typography Project and shall only */
+/* be used, modified, and distributed under the terms of the Catharon */
+/* Open Source License that should come with this file under the name */
+/* `CatharonLicense.txt'. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/* Note that this license is compatible with the FreeType license. */
+/* */
+/***************************************************************************/
+
+
+#ifndef __AHGLOBAL_H__
+#define __AHGLOBAL_H__
+
+
+#include <ft2build.h>
+#include "ahtypes.h"
+#include FT_INTERNAL_OBJECTS_H
+
+
+FT_BEGIN_HEADER
+
+
+#define AH_IS_TOP_BLUE( b ) ( (b) == AH_BLUE_CAPITAL_TOP || \
+ (b) == AH_BLUE_SMALL_TOP )
+
+
+ /* compute global metrics automatically */
+ FT_LOCAL( FT_Error )
+ ah_hinter_compute_globals( AH_Hinter hinter );
+
+
+FT_END_HEADER
+
+#endif /* __AHGLOBAL_H__ */
+
+
+/* END */
--- /dev/null
+++ b/libfreetype/ahglyph.c
@@ -1,0 +1,1579 @@
+/***************************************************************************/
+/* */
+/* ahglyph.c */
+/* */
+/* Routines used to load and analyze a given glyph before hinting */
+/* (body). */
+/* */
+/* Copyright 2000-2001, 2002 Catharon Productions Inc. */
+/* Author: David Turner */
+/* */
+/* This file is part of the Catharon Typography Project and shall only */
+/* be used, modified, and distributed under the terms of the Catharon */
+/* Open Source License that should come with this file under the name */
+/* `CatharonLicense.txt'. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/* Note that this license is compatible with the FreeType license. */
+/* */
+/***************************************************************************/
+
+
+#include <ft2build.h>
+#include "ahglyph.h"
+#include "ahangles.h"
+#include "ahglobal.h"
+#include "aherrors.h"
+
+
+#ifdef AH_DEBUG
+
+#include <stdio.h>
+
+ void
+ ah_dump_edges( AH_Outline outline )
+ {
+ AH_Edge edges;
+ AH_Edge edge_limit;
+ AH_Segment segments;
+ FT_Int dimension;
+
+
+ edges = outline->horz_edges;
+ edge_limit = edges + outline->num_hedges;
+ segments = outline->horz_segments;
+
+ for ( dimension = 1; dimension >= 0; dimension-- )
+ {
+ AH_Edge edge;
+
+
+ printf ( "Table of %s edges:\n",
+ !dimension ? "vertical" : "horizontal" );
+ printf ( " [ index | pos | dir | link |"
+ " serif | blue | opos | pos ]\n" );
+
+ for ( edge = edges; edge < edge_limit; edge++ )
+ {
+ printf ( " [ %5d | %4d | %5s | %4d | %5d | %c | %5.2f | %5.2f ]\n",
+ edge - edges,
+ (int)edge->fpos,
+ edge->dir == AH_DIR_UP
+ ? "up"
+ : ( edge->dir == AH_DIR_DOWN
+ ? "down"
+ : ( edge->dir == AH_DIR_LEFT
+ ? "left"
+ : ( edge->dir == AH_DIR_RIGHT
+ ? "right"
+ : "none" ) ) ),
+ edge->link ? ( edge->link - edges ) : -1,
+ edge->serif ? ( edge->serif - edges ) : -1,
+ edge->blue_edge ? 'y' : 'n',
+ edge->opos / 64.0,
+ edge->pos / 64.0 );
+ }
+
+ edges = outline->vert_edges;
+ edge_limit = edges + outline->num_vedges;
+ segments = outline->vert_segments;
+ }
+ }
+
+
+ /* A function used to dump the array of linked segments */
+ void
+ ah_dump_segments( AH_Outline outline )
+ {
+ AH_Segment segments;
+ AH_Segment segment_limit;
+ AH_Point points;
+ FT_Int dimension;
+
+
+ points = outline->points;
+ segments = outline->horz_segments;
+ segment_limit = segments + outline->num_hsegments;
+
+ for ( dimension = 1; dimension >= 0; dimension-- )
+ {
+ AH_Segment seg;
+
+
+ printf ( "Table of %s segments:\n",
+ !dimension ? "vertical" : "horizontal" );
+ printf ( " [ index | pos | dir | link | serif |"
+ " numl | first | start ]\n" );
+
+ for ( seg = segments; seg < segment_limit; seg++ )
+ {
+ printf ( " [ %5d | %4d | %5s | %4d | %5d | %4d | %5d | %5d ]\n",
+ seg - segments,
+ (int)seg->pos,
+ seg->dir == AH_DIR_UP
+ ? "up"
+ : ( seg->dir == AH_DIR_DOWN
+ ? "down"
+ : ( seg->dir == AH_DIR_LEFT
+ ? "left"
+ : ( seg->dir == AH_DIR_RIGHT
+ ? "right"
+ : "none" ) ) ),
+ seg->link ? (seg->link-segments) : -1,
+ seg->serif ? (seg->serif-segments) : -1,
+ (int)seg->num_linked,
+ seg->first - points,
+ seg->last - points );
+ }
+
+ segments = outline->vert_segments;
+ segment_limit = segments + outline->num_vsegments;
+ }
+ }
+
+#endif /* AH_DEBUG */
+
+
+ /* compute the direction value of a given vector.. */
+ static AH_Direction
+ ah_compute_direction( FT_Pos dx,
+ FT_Pos dy )
+ {
+ AH_Direction dir;
+ FT_Pos ax = ABS( dx );
+ FT_Pos ay = ABS( dy );
+
+
+ dir = AH_DIR_NONE;
+
+ /* test for vertical direction */
+ if ( ax * 12 < ay )
+ {
+ dir = dy > 0 ? AH_DIR_UP : AH_DIR_DOWN;
+ }
+ /* test for horizontal direction */
+ else if ( ay * 12 < ax )
+ {
+ dir = dx > 0 ? AH_DIR_RIGHT : AH_DIR_LEFT;
+ }
+
+ return dir;
+ }
+
+
+ /* this function is used by ah_get_orientation (see below) to test */
+ /* the fill direction of a given bbox extrema */
+ static FT_Int
+ ah_test_extrema( FT_Outline* outline,
+ FT_Int n )
+ {
+ FT_Vector *prev, *cur, *next;
+ FT_Pos product;
+ FT_Int first, last, c;
+ FT_Int retval;
+
+
+ /* we need to compute the `previous' and `next' point */
+ /* for these extrema */
+ cur = outline->points + n;
+ prev = cur - 1;
+ next = cur + 1;
+
+ first = 0;
+ for ( c = 0; c < outline->n_contours; c++ )
+ {
+ last = outline->contours[c];
+
+ if ( n == first )
+ prev = outline->points + last;
+
+ if ( n == last )
+ next = outline->points + first;
+
+ first = last + 1;
+ }
+
+ product = FT_MulDiv( cur->x - prev->x, /* in.x */
+ next->y - cur->y, /* out.y */
+ 0x40 )
+ -
+ FT_MulDiv( cur->y - prev->y, /* in.y */
+ next->x - cur->x, /* out.x */
+ 0x40 );
+
+ retval = 0;
+ if ( product )
+ retval = product > 0 ? 2 : 1;
+
+ return retval;
+ }
+
+
+ /* Compute the orientation of path filling. It differs between TrueType */
+ /* and Type1 formats. We could use the `FT_OUTLINE_REVERSE_FILL' flag, */
+ /* but it is better to re-compute it directly (it seems that this flag */
+ /* isn't correctly set for some weird composite glyphs currently). */
+ /* */
+ /* We do this by computing bounding box points, and computing their */
+ /* curvature. */
+ /* */
+ /* The function returns either 1 or -1. */
+ /* */
+ static FT_Int
+ ah_get_orientation( FT_Outline* outline )
+ {
+ FT_BBox box;
+ FT_Int indices_xMin, indices_yMin, indices_xMax, indices_yMax;
+ FT_Int n, last;
+
+
+ indices_xMin = -1;
+ indices_yMin = -1;
+ indices_xMax = -1;
+ indices_yMax = -1;
+
+ box.xMin = box.yMin = 32767L;
+ box.xMax = box.yMax = -32768L;
+
+ /* is it empty? */
+ if ( outline->n_contours < 1 )
+ return 1;
+
+ last = outline->contours[outline->n_contours - 1];
+
+ for ( n = 0; n <= last; n++ )
+ {
+ FT_Pos x, y;
+
+
+ x = outline->points[n].x;
+ if ( x < box.xMin )
+ {
+ box.xMin = x;
+ indices_xMin = n;
+ }
+ if ( x > box.xMax )
+ {
+ box.xMax = x;
+ indices_xMax = n;
+ }
+
+ y = outline->points[n].y;
+ if ( y < box.yMin )
+ {
+ box.yMin = y;
+ indices_yMin = n;
+ }
+ if ( y > box.yMax )
+ {
+ box.yMax = y;
+ indices_yMax = n;
+ }
+ }
+
+ /* test orientation of the xmin */
+ n = ah_test_extrema( outline, indices_xMin );
+ if ( n )
+ goto Exit;
+
+ n = ah_test_extrema( outline, indices_yMin );
+ if ( n )
+ goto Exit;
+
+ n = ah_test_extrema( outline, indices_xMax );
+ if ( n )
+ goto Exit;
+
+ n = ah_test_extrema( outline, indices_yMax );
+ if ( !n )
+ n = 1;
+
+ Exit:
+ return n;
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* ah_outline_new */
+ /* */
+ /* <Description> */
+ /* Creates a new and empty AH_OutlineRec object. */
+ /* */
+ FT_LOCAL_DEF( FT_Error )
+ ah_outline_new( FT_Memory memory,
+ AH_Outline* aoutline )
+ {
+ FT_Error error;
+ AH_Outline outline;
+
+
+ if ( !FT_NEW( outline ) )
+ {
+ outline->memory = memory;
+ *aoutline = outline;
+ }
+
+ return error;
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* ah_outline_done */
+ /* */
+ /* <Description> */
+ /* Destroys a given AH_OutlineRec object. */
+ /* */
+ FT_LOCAL_DEF( void )
+ ah_outline_done( AH_Outline outline )
+ {
+ FT_Memory memory = outline->memory;
+
+
+ FT_FREE( outline->horz_edges );
+ FT_FREE( outline->horz_segments );
+ FT_FREE( outline->contours );
+ FT_FREE( outline->points );
+
+ FT_FREE( outline );
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* ah_outline_save */
+ /* */
+ /* <Description> */
+ /* Saves the contents of a given AH_OutlineRec object into a face's */
+ /* glyph slot. */
+ /* */
+ FT_LOCAL_DEF( void )
+ ah_outline_save( AH_Outline outline,
+ AH_Loader gloader )
+ {
+ AH_Point point = outline->points;
+ AH_Point point_limit = point + outline->num_points;
+ FT_Vector* vec = gloader->current.outline.points;
+ char* tag = gloader->current.outline.tags;
+
+
+ /* we assume that the glyph loader has already been checked for storage */
+ for ( ; point < point_limit; point++, vec++, tag++ )
+ {
+ vec->x = point->x;
+ vec->y = point->y;
+
+ if ( point->flags & AH_FLAG_CONIC )
+ tag[0] = FT_CURVE_TAG_CONIC;
+ else if ( point->flags & AH_FLAG_CUBIC )
+ tag[0] = FT_CURVE_TAG_CUBIC;
+ else
+ tag[0] = FT_CURVE_TAG_ON;
+ }
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* ah_outline_load */
+ /* */
+ /* <Description> */
+ /* Loads an unscaled outline from a glyph slot into an AH_OutlineRec */
+ /* object. */
+ /* */
+ FT_LOCAL_DEF( FT_Error )
+ ah_outline_load( AH_Outline outline,
+ FT_Face face )
+ {
+ FT_Memory memory = outline->memory;
+ FT_Error error = AH_Err_Ok;
+ FT_Outline* source = &face->glyph->outline;
+ FT_Int num_points = source->n_points;
+ FT_Int num_contours = source->n_contours;
+ AH_Point points;
+
+
+ /* check arguments */
+ if ( !face ||
+ !face->size ||
+ face->glyph->format != FT_GLYPH_FORMAT_OUTLINE )
+ return AH_Err_Invalid_Argument;
+
+ /* first of all, reallocate the contours array if necessary */
+ if ( num_contours > outline->max_contours )
+ {
+ FT_Int new_contours = ( num_contours + 3 ) & -4;
+
+
+ if ( FT_RENEW_ARRAY( outline->contours,
+ outline->max_contours,
+ new_contours ) )
+ goto Exit;
+
+ outline->max_contours = new_contours;
+ }
+
+ /* then, reallocate the points, segments & edges arrays if needed -- */
+ /* note that we reserved two additional point positions, used to */
+ /* hint metrics appropriately */
+ /* */
+ if ( num_points + 2 > outline->max_points )
+ {
+ FT_Int news = ( num_points + 2 + 7 ) & -8;
+ FT_Int max = outline->max_points;
+
+
+ if ( FT_RENEW_ARRAY( outline->points, max, news ) ||
+ FT_RENEW_ARRAY( outline->horz_edges, max * 2, news * 2 ) ||
+ FT_RENEW_ARRAY( outline->horz_segments, max * 2, news * 2 ) )
+ goto Exit;
+
+ /* readjust some pointers */
+ outline->vert_edges = outline->horz_edges + news;
+ outline->vert_segments = outline->horz_segments + news;
+ outline->max_points = news;
+ }
+
+ outline->num_points = num_points;
+ outline->num_contours = num_contours;
+
+ outline->num_hedges = 0;
+ outline->num_vedges = 0;
+ outline->num_hsegments = 0;
+ outline->num_vsegments = 0;
+
+ /* We can't rely on the value of `FT_Outline.flags' to know the fill */
+ /* direction used for a glyph, given that some fonts are broken (e.g. */
+ /* the Arphic ones). We thus recompute it each time we need to. */
+ /* */
+ outline->vert_major_dir = AH_DIR_UP;
+ outline->horz_major_dir = AH_DIR_LEFT;
+
+ if ( ah_get_orientation( source ) > 1 )
+ {
+ outline->vert_major_dir = AH_DIR_DOWN;
+ outline->horz_major_dir = AH_DIR_RIGHT;
+ }
+
+ outline->x_scale = face->size->metrics.x_scale;
+ outline->y_scale = face->size->metrics.y_scale;
+
+ points = outline->points;
+ if ( outline->num_points == 0 )
+ goto Exit;
+
+ {
+ /* do one thing at a time -- it is easier to understand, and */
+ /* the code is clearer */
+ AH_Point point;
+ AH_Point point_limit = points + outline->num_points;
+
+
+ /* compute coordinates */
+ {
+ FT_Vector* vec = source->points;
+ FT_Fixed x_scale = outline->x_scale;
+ FT_Fixed y_scale = outline->y_scale;
+
+
+ for ( point = points; point < point_limit; vec++, point++ )
+ {
+ point->fx = vec->x;
+ point->fy = vec->y;
+ point->ox = point->x = FT_MulFix( vec->x, x_scale );
+ point->oy = point->y = FT_MulFix( vec->y, y_scale );
+
+ point->flags = 0;
+ }
+ }
+
+ /* compute Bezier flags */
+ {
+ char* tag = source->tags;
+
+
+ for ( point = points; point < point_limit; point++, tag++ )
+ {
+ switch ( FT_CURVE_TAG( *tag ) )
+ {
+ case FT_CURVE_TAG_CONIC:
+ point->flags = AH_FLAG_CONIC; break;
+ case FT_CURVE_TAG_CUBIC:
+ point->flags = AH_FLAG_CUBIC; break;
+ default:
+ ;
+ }
+ }
+ }
+
+ /* compute `next' and `prev' */
+ {
+ FT_Int contour_index;
+ AH_Point prev;
+ AH_Point first;
+ AH_Point end;
+
+
+ contour_index = 0;
+
+ first = points;
+ end = points + source->contours[0];
+ prev = end;
+
+ for ( point = points; point < point_limit; point++ )
+ {
+ point->prev = prev;
+ if ( point < end )
+ {
+ point->next = point + 1;
+ prev = point;
+ }
+ else
+ {
+ point->next = first;
+ contour_index++;
+ if ( point + 1 < point_limit )
+ {
+ end = points + source->contours[contour_index];
+ first = point + 1;
+ prev = end;
+ }
+ }
+ }
+ }
+
+ /* set-up the contours array */
+ {
+ AH_Point* contour = outline->contours;
+ AH_Point* contour_limit = contour + outline->num_contours;
+ short* end = source->contours;
+ short idx = 0;
+
+
+ for ( ; contour < contour_limit; contour++, end++ )
+ {
+ contour[0] = points + idx;
+ idx = (short)( end[0] + 1 );
+ }
+ }
+
+ /* compute directions of in & out vectors */
+ {
+ for ( point = points; point < point_limit; point++ )
+ {
+ AH_Point prev;
+ AH_Point next;
+ FT_Vector ivec, ovec;
+
+
+ prev = point->prev;
+ ivec.x = point->fx - prev->fx;
+ ivec.y = point->fy - prev->fy;
+
+ point->in_dir = ah_compute_direction( ivec.x, ivec.y );
+
+ next = point->next;
+ ovec.x = next->fx - point->fx;
+ ovec.y = next->fy - point->fy;
+
+ point->out_dir = ah_compute_direction( ovec.x, ovec.y );
+
+#ifndef AH_OPTION_NO_WEAK_INTERPOLATION
+ if ( point->flags & (AH_FLAG_CONIC | AH_FLAG_CUBIC) )
+ {
+ Is_Weak_Point:
+ point->flags |= AH_FLAG_WEAK_INTERPOLATION;
+ }
+ else if ( point->out_dir == point->in_dir )
+ {
+ AH_Angle angle_in, angle_out, delta;
+
+
+ if ( point->out_dir != AH_DIR_NONE )
+ goto Is_Weak_Point;
+
+ angle_in = ah_angle( &ivec );
+ angle_out = ah_angle( &ovec );
+ delta = angle_in - angle_out;
+
+ if ( delta > AH_PI )
+ delta = AH_2PI - delta;
+
+ if ( delta < 0 )
+ delta = -delta;
+
+ if ( delta < 2 )
+ goto Is_Weak_Point;
+ }
+ else if ( point->in_dir == -point->out_dir )
+ goto Is_Weak_Point;
+#endif
+ }
+ }
+ }
+
+ Exit:
+ return error;
+ }
+
+
+ FT_LOCAL_DEF( void )
+ ah_setup_uv( AH_Outline outline,
+ AH_UV source )
+ {
+ AH_Point point = outline->points;
+ AH_Point point_limit = point + outline->num_points;
+
+
+ for ( ; point < point_limit; point++ )
+ {
+ FT_Pos u, v;
+
+
+ switch ( source )
+ {
+ case AH_UV_FXY:
+ u = point->fx;
+ v = point->fy;
+ break;
+ case AH_UV_FYX:
+ u = point->fy;
+ v = point->fx;
+ break;
+ case AH_UV_OXY:
+ u = point->ox;
+ v = point->oy;
+ break;
+ case AH_UV_OYX:
+ u = point->oy;
+ v = point->ox;
+ break;
+ case AH_UV_YX:
+ u = point->y;
+ v = point->x;
+ break;
+ case AH_UV_OX:
+ u = point->x;
+ v = point->ox;
+ break;
+ case AH_UV_OY:
+ u = point->y;
+ v = point->oy;
+ break;
+ default:
+ u = point->x;
+ v = point->y;
+ break;
+ }
+ point->u = u;
+ point->v = v;
+ }
+ }
+
+
+ /* compute all inflex points in a given glyph */
+ static void
+ ah_outline_compute_inflections( AH_Outline outline )
+ {
+ AH_Point* contour = outline->contours;
+ AH_Point* contour_limit = contour + outline->num_contours;
+
+
+ /* load original coordinates in (u,v) */
+ ah_setup_uv( outline, AH_UV_FXY );
+
+ /* do each contour separately */
+ for ( ; contour < contour_limit; contour++ )
+ {
+ FT_Vector vec;
+ AH_Point point = contour[0];
+ AH_Point first = point;
+ AH_Point start = point;
+ AH_Point end = point;
+ AH_Point before;
+ AH_Point after;
+ AH_Angle angle_in, angle_seg, angle_out;
+ AH_Angle diff_in, diff_out;
+ FT_Int finished = 0;
+
+
+ /* compute first segment in contour */
+ first = point;
+
+ start = end = first;
+ do
+ {
+ end = end->next;
+ if ( end == first )
+ goto Skip;
+
+ } while ( end->u == first->u && end->v == first->v );
+
+ vec.x = end->u - start->u;
+ vec.y = end->v - start->v;
+ angle_seg = ah_angle( &vec );
+
+ /* extend the segment start whenever possible */
+ before = start;
+ do
+ {
+ do
+ {
+ start = before;
+ before = before->prev;
+ if ( before == first )
+ goto Skip;
+
+ } while ( before->u == start->u && before->v == start->v );
+
+ vec.x = start->u - before->u;
+ vec.y = start->v - before->v;
+ angle_in = ah_angle( &vec );
+
+ } while ( angle_in == angle_seg );
+
+ first = start;
+ diff_in = ah_angle_diff( angle_in, angle_seg );
+
+ /* now, process all segments in the contour */
+ do
+ {
+ /* first, extend current segment's end whenever possible */
+ after = end;
+ do
+ {
+ do
+ {
+ end = after;
+ after = after->next;
+ if ( after == first )
+ finished = 1;
+
+ } while ( end->u == after->u && end->v == after->v );
+
+ vec.x = after->u - end->u;
+ vec.y = after->v - end->v;
+ angle_out = ah_angle( &vec );
+
+ } while ( angle_out == angle_seg );
+
+ diff_out = ah_angle_diff( angle_seg, angle_out );
+
+ if ( ( diff_in ^ diff_out ) < 0 )
+ {
+ /* diff_in and diff_out have different signs, we have */
+ /* inflection points here... */
+
+ do
+ {
+ start->flags |= AH_FLAG_INFLECTION;
+ start = start->next;
+
+ } while ( start != end );
+
+ start->flags |= AH_FLAG_INFLECTION;
+ }
+
+ start = end;
+ end = after;
+ angle_seg = angle_out;
+ diff_in = diff_out;
+
+ } while ( !finished );
+
+ Skip:
+ ;
+ }
+ }
+
+
+ FT_LOCAL_DEF( void )
+ ah_outline_compute_segments( AH_Outline outline )
+ {
+ int dimension;
+ AH_Segment segments;
+ FT_Int* p_num_segments;
+ AH_Direction segment_dir;
+ AH_Direction major_dir;
+
+
+ segments = outline->horz_segments;
+ p_num_segments = &outline->num_hsegments;
+ major_dir = AH_DIR_RIGHT; /* This value must be positive! */
+ segment_dir = major_dir;
+
+ /* set up (u,v) in each point */
+ ah_setup_uv( outline, AH_UV_FYX );
+
+ for ( dimension = 1; dimension >= 0; dimension-- )
+ {
+ AH_Point* contour = outline->contours;
+ AH_Point* contour_limit = contour + outline->num_contours;
+ AH_Segment segment = segments;
+ FT_Int num_segments = 0;
+
+#ifdef AH_HINT_METRICS
+ AH_Point min_point = 0;
+ AH_Point max_point = 0;
+ FT_Pos min_coord = 32000;
+ FT_Pos max_coord = -32000;
+#endif
+
+
+ /* do each contour separately */
+ for ( ; contour < contour_limit; contour++ )
+ {
+ AH_Point point = contour[0];
+ AH_Point last = point->prev;
+ int on_edge = 0;
+ FT_Pos min_pos = +32000; /* minimum segment pos != min_coord */
+ FT_Pos max_pos = -32000; /* maximum segment pos != max_coord */
+ FT_Bool passed;
+
+
+#ifdef AH_HINT_METRICS
+ if ( point->u < min_coord )
+ {
+ min_coord = point->u;
+ min_point = point;
+ }
+ if ( point->u > max_coord )
+ {
+ max_coord = point->u;
+ max_point = point;
+ }
+#endif
+
+ if ( point == last ) /* skip singletons -- just in case? */
+ continue;
+
+ if ( ABS( last->out_dir ) == major_dir &&
+ ABS( point->out_dir ) == major_dir )
+ {
+ /* we are already on an edge, try to locate its start */
+ last = point;
+
+ for (;;)
+ {
+ point = point->prev;
+ if ( ABS( point->out_dir ) != major_dir )
+ {
+ point = point->next;
+ break;
+ }
+ if ( point == last )
+ break;
+ }
+ }
+
+ last = point;
+ passed = 0;
+
+ for (;;)
+ {
+ FT_Pos u, v;
+
+
+ if ( on_edge )
+ {
+ u = point->u;
+ if ( u < min_pos )
+ min_pos = u;
+ if ( u > max_pos )
+ max_pos = u;
+
+ if ( point->out_dir != segment_dir || point == last )
+ {
+ /* we are just leaving an edge; record a new segment! */
+ segment->last = point;
+ segment->pos = ( min_pos + max_pos ) >> 1;
+
+ /* a segment is round if either its first or last point */
+ /* is a control point */
+ if ( ( segment->first->flags | point->flags ) &
+ AH_FLAG_CONTROL )
+ segment->flags |= AH_EDGE_ROUND;
+
+ /* compute segment size */
+ min_pos = max_pos = point->v;
+
+ v = segment->first->v;
+ if ( v < min_pos )
+ min_pos = v;
+ if ( v > max_pos )
+ max_pos = v;
+
+ segment->min_coord = min_pos;
+ segment->max_coord = max_pos;
+
+ on_edge = 0;
+ num_segments++;
+ segment++;
+ /* fallthrough */
+ }
+ }
+
+ /* now exit if we are at the start/end point */
+ if ( point == last )
+ {
+ if ( passed )
+ break;
+ passed = 1;
+ }
+
+ if ( !on_edge && ABS( point->out_dir ) == major_dir )
+ {
+ /* this is the start of a new segment! */
+ segment_dir = point->out_dir;
+
+ /* clear all segment fields */
+ FT_ZERO( segment );
+
+ segment->dir = segment_dir;
+ segment->flags = AH_EDGE_NORMAL;
+ min_pos = max_pos = point->u;
+ segment->first = point;
+ segment->last = point;
+ segment->contour = contour;
+ on_edge = 1;
+
+#ifdef AH_HINT_METRICS
+ if ( point == max_point )
+ max_point = 0;
+
+ if ( point == min_point )
+ min_point = 0;
+#endif
+ }
+
+ point = point->next;
+ }
+
+ } /* contours */
+
+#ifdef AH_HINT_METRICS
+ /* we need to ensure that there are edges on the left-most and */
+ /* right-most points of the glyph in order to hint the metrics; */
+ /* we do this by inserting fake segments when needed */
+ if ( dimension == 0 )
+ {
+ AH_Point point = outline->points;
+ AH_Point point_limit = point + outline->num_points;
+
+ FT_Pos min_pos = 32000;
+ FT_Pos max_pos = -32000;
+
+
+ min_point = 0;
+ max_point = 0;
+
+ /* compute minimum and maximum points */
+ for ( ; point < point_limit; point++ )
+ {
+ FT_Pos x = point->fx;
+
+
+ if ( x < min_pos )
+ {
+ min_pos = x;
+ min_point = point;
+ }
+ if ( x > max_pos )
+ {
+ max_pos = x;
+ max_point = point;
+ }
+ }
+
+ /* insert minimum segment */
+ if ( min_point )
+ {
+ /* clear all segment fields */
+ FT_ZERO( segment );
+
+ segment->dir = segment_dir;
+ segment->flags = AH_EDGE_NORMAL;
+ segment->first = min_point;
+ segment->last = min_point;
+ segment->pos = min_pos;
+
+ num_segments++;
+ segment++;
+ }
+
+ /* insert maximum segment */
+ if ( max_point )
+ {
+ /* clear all segment fields */
+ FT_ZERO( segment );
+
+ segment->dir = segment_dir;
+ segment->flags = AH_EDGE_NORMAL;
+ segment->first = max_point;
+ segment->last = max_point;
+ segment->pos = max_pos;
+
+ num_segments++;
+ segment++;
+ }
+ }
+#endif /* AH_HINT_METRICS */
+
+ *p_num_segments = num_segments;
+
+ segments = outline->vert_segments;
+ major_dir = AH_DIR_UP;
+ p_num_segments = &outline->num_vsegments;
+ ah_setup_uv( outline, AH_UV_FXY );
+ }
+ }
+
+
+ FT_LOCAL_DEF( void )
+ ah_outline_link_segments( AH_Outline outline )
+ {
+ AH_Segment segments;
+ AH_Segment segment_limit;
+ int dimension;
+
+
+ ah_setup_uv( outline, AH_UV_FYX );
+
+ segments = outline->horz_segments;
+ segment_limit = segments + outline->num_hsegments;
+
+ for ( dimension = 1; dimension >= 0; dimension-- )
+ {
+ AH_Segment seg1;
+ AH_Segment seg2;
+
+
+ /* now compare each segment to the others */
+ for ( seg1 = segments; seg1 < segment_limit; seg1++ )
+ {
+ FT_Pos best_score;
+ AH_Segment best_segment;
+
+
+ /* the fake segments are introduced to hint the metrics -- */
+ /* we must never link them to anything */
+ if ( seg1->first == seg1->last )
+ continue;
+
+ best_segment = seg1->link;
+ if ( best_segment )
+ best_score = seg1->score;
+ else
+ best_score = 32000;
+
+ for ( seg2 = segments; seg2 < segment_limit; seg2++ )
+ if ( seg1 != seg2 && seg1->dir + seg2->dir == 0 )
+ {
+ FT_Pos pos1 = seg1->pos;
+ FT_Pos pos2 = seg2->pos;
+ FT_Bool is_dir;
+ FT_Bool is_pos;
+
+
+ /* check that the segments are correctly oriented and */
+ /* positioned to form a black distance */
+
+ is_dir = (FT_Bool)( seg1->dir == outline->horz_major_dir ||
+ seg1->dir == outline->vert_major_dir );
+ is_pos = (FT_Bool)( pos1 > pos2 );
+
+ if ( pos1 == pos2 || !(is_dir ^ is_pos) )
+ continue;
+
+ {
+ FT_Pos min = seg1->min_coord;
+ FT_Pos max = seg1->max_coord;
+ FT_Pos len, dist, score;
+
+
+ if ( min < seg2->min_coord )
+ min = seg2->min_coord;
+
+ if ( max > seg2->max_coord )
+ max = seg2->max_coord;
+
+ len = max - min;
+ if ( len >= 8 )
+ {
+ dist = seg2->pos - seg1->pos;
+ if ( dist < 0 )
+ dist = -dist;
+
+ score = dist + 3000 / len;
+
+ if ( score < best_score )
+ {
+ best_score = score;
+ best_segment = seg2;
+ }
+ }
+ }
+ }
+
+ if ( best_segment )
+ {
+ seg1->link = best_segment;
+ seg1->score = best_score;
+
+ best_segment->num_linked++;
+ }
+
+ } /* edges 1 */
+
+ /* now, compute the `serif' segments */
+ for ( seg1 = segments; seg1 < segment_limit; seg1++ )
+ {
+ seg2 = seg1->link;
+
+ if ( seg2 && seg2->link != seg1 )
+ {
+ seg1->link = 0;
+ seg1->serif = seg2->link;
+ }
+ }
+
+ ah_setup_uv( outline, AH_UV_FXY );
+
+ segments = outline->vert_segments;
+ segment_limit = segments + outline->num_vsegments;
+ }
+ }
+
+
+ static void
+ ah_outline_compute_edges( AH_Outline outline )
+ {
+ AH_Edge edges;
+ AH_Segment segments;
+ AH_Segment segment_limit;
+ AH_Direction up_dir;
+ FT_Int* p_num_edges;
+ FT_Int dimension;
+ FT_Fixed scale;
+ FT_Pos edge_distance_threshold;
+
+
+ edges = outline->horz_edges;
+ segments = outline->horz_segments;
+ segment_limit = segments + outline->num_hsegments;
+ p_num_edges = &outline->num_hedges;
+ up_dir = AH_DIR_RIGHT;
+ scale = outline->y_scale;
+
+ for ( dimension = 1; dimension >= 0; dimension-- )
+ {
+ AH_Edge edge;
+ AH_Edge edge_limit; /* really == edge + num_edges */
+ AH_Segment seg;
+
+
+ /*********************************************************************/
+ /* */
+ /* We will begin by generating a sorted table of edges for the */
+ /* current direction. To do so, we simply scan each segment and try */
+ /* to find an edge in our table that corresponds to its position. */
+ /* */
+ /* If no edge is found, we create and insert a new edge in the */
+ /* sorted table. Otherwise, we simply add the segment to the edge's */
+ /* list which will be processed in the second step to compute the */
+ /* edge's properties. */
+ /* */
+ /* Note that the edges table is sorted along the segment/edge */
+ /* position. */
+ /* */
+ /*********************************************************************/
+
+ edge_distance_threshold = FT_MulFix( outline->edge_distance_threshold,
+ scale );
+ if ( edge_distance_threshold > 64 / 4 )
+ edge_distance_threshold = 64 / 4;
+
+ edge_limit = edges;
+ for ( seg = segments; seg < segment_limit; seg++ )
+ {
+ AH_Edge found = 0;
+
+
+ /* look for an edge corresponding to the segment */
+ for ( edge = edges; edge < edge_limit; edge++ )
+ {
+ FT_Pos dist;
+
+
+ dist = seg->pos - edge->fpos;
+ if ( dist < 0 )
+ dist = -dist;
+
+ dist = FT_MulFix( dist, scale );
+ if ( dist < edge_distance_threshold )
+ {
+ found = edge;
+ break;
+ }
+ }
+
+ if ( !found )
+ {
+ /* insert a new edge in the list and */
+ /* sort according to the position */
+ while ( edge > edges && edge[-1].fpos > seg->pos )
+ {
+ edge[0] = edge[-1];
+ edge--;
+ }
+ edge_limit++;
+
+ /* clear all edge fields */
+ FT_MEM_ZERO( edge, sizeof ( *edge ) );
+
+ /* add the segment to the new edge's list */
+ edge->first = seg;
+ edge->last = seg;
+ edge->fpos = seg->pos;
+ edge->opos = edge->pos = FT_MulFix( seg->pos, scale );
+ seg->edge_next = seg;
+ }
+ else
+ {
+ /* if an edge was found, simply add the segment to the edge's */
+ /* list */
+ seg->edge_next = edge->first;
+ edge->last->edge_next = seg;
+ edge->last = seg;
+ }
+ }
+
+ *p_num_edges = (FT_Int)( edge_limit - edges );
+
+
+ /*********************************************************************/
+ /* */
+ /* Good, we will now compute each edge's properties according to */
+ /* segments found on its position. Basically, these are: */
+ /* */
+ /* - edge's main direction */
+ /* - stem edge, serif edge or both (which defaults to stem then) */
+ /* - rounded edge, straigth or both (which defaults to straight) */
+ /* - link for edge */
+ /* */
+ /*********************************************************************/
+
+ /* first of all, set the `edge' field in each segment -- this is */
+ /* required in order to compute edge links */
+ for ( edge = edges; edge < edge_limit; edge++ )
+ {
+ seg = edge->first;
+ if ( seg )
+ do
+ {
+ seg->edge = edge;
+ seg = seg->edge_next;
+ }
+ while ( seg != edge->first );
+ }
+
+ /* now, compute each edge properties */
+ for ( edge = edges; edge < edge_limit; edge++ )
+ {
+ FT_Int is_round = 0; /* does it contain round segments? */
+ FT_Int is_straight = 0; /* does it contain straight segments? */
+ FT_Pos ups = 0; /* number of upwards segments */
+ FT_Pos downs = 0; /* number of downwards segments */
+
+
+ seg = edge->first;
+
+ do
+ {
+ FT_Bool is_serif;
+
+
+ /* check for roundness of segment */
+ if ( seg->flags & AH_EDGE_ROUND )
+ is_round++;
+ else
+ is_straight++;
+
+ /* check for segment direction */
+ if ( seg->dir == up_dir )
+ ups += seg->max_coord-seg->min_coord;
+ else
+ downs += seg->max_coord-seg->min_coord;
+
+ /* check for links -- if seg->serif is set, then seg->link must */
+ /* be ignored */
+ is_serif = (FT_Bool)( seg->serif && seg->serif->edge != edge );
+
+ if ( seg->link || is_serif )
+ {
+ AH_Edge edge2;
+ AH_Segment seg2;
+
+
+ edge2 = edge->link;
+ seg2 = seg->link;
+
+ if ( is_serif )
+ {
+ seg2 = seg->serif;
+ edge2 = edge->serif;
+ }
+
+ if ( edge2 )
+ {
+ FT_Pos edge_delta;
+ FT_Pos seg_delta;
+
+
+ edge_delta = edge->fpos - edge2->fpos;
+ if ( edge_delta < 0 )
+ edge_delta = -edge_delta;
+
+ seg_delta = seg->pos - seg2->pos;
+ if ( seg_delta < 0 )
+ seg_delta = -seg_delta;
+
+ if ( seg_delta < edge_delta )
+ edge2 = seg2->edge;
+ }
+ else
+ edge2 = seg2->edge;
+
+ if ( is_serif )
+ edge->serif = edge2;
+ else
+ edge->link = edge2;
+ }
+
+ seg = seg->edge_next;
+
+ } while ( seg != edge->first );
+
+ /* set the round/straight flags */
+ edge->flags = AH_EDGE_NORMAL;
+
+ if ( is_round > 0 && is_round >= is_straight )
+ edge->flags |= AH_EDGE_ROUND;
+
+ /* set the edge's main direction */
+ edge->dir = AH_DIR_NONE;
+
+ if ( ups > downs )
+ edge->dir = up_dir;
+
+ else if ( ups < downs )
+ edge->dir = - up_dir;
+
+ else if ( ups == downs )
+ edge->dir = 0; /* both up and down !! */
+
+ /* gets rid of serifs if link is set */
+ /* XXX: This gets rid of many unpleasant artefacts! */
+ /* Example: the `c' in cour.pfa at size 13 */
+
+ if ( edge->serif && edge->link )
+ edge->serif = 0;
+ }
+
+ edges = outline->vert_edges;
+ segments = outline->vert_segments;
+ segment_limit = segments + outline->num_vsegments;
+ p_num_edges = &outline->num_vedges;
+ up_dir = AH_DIR_UP;
+ scale = outline->x_scale;
+ }
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* ah_outline_detect_features */
+ /* */
+ /* <Description> */
+ /* Performs feature detection on a given AH_OutlineRec object. */
+ /* */
+ FT_LOCAL_DEF( void )
+ ah_outline_detect_features( AH_Outline outline )
+ {
+ ah_outline_compute_segments ( outline );
+ ah_outline_link_segments ( outline );
+ ah_outline_compute_edges ( outline );
+ ah_outline_compute_inflections( outline );
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* ah_outline_compute_blue_edges */
+ /* */
+ /* <Description> */
+ /* Computes the `blue edges' in a given outline (i.e. those that must */
+ /* be snapped to a blue zone edge (top or bottom). */
+ /* */
+ FT_LOCAL_DEF( void )
+ ah_outline_compute_blue_edges( AH_Outline outline,
+ AH_Face_Globals face_globals )
+ {
+ AH_Edge edge = outline->horz_edges;
+ AH_Edge edge_limit = edge + outline->num_hedges;
+ AH_Globals globals = &face_globals->design;
+ FT_Fixed y_scale = outline->y_scale;
+
+ FT_Bool blue_active[AH_BLUE_MAX];
+
+
+ /* compute which blue zones are active, i.e. have their scaled */
+ /* size < 3/4 pixels */
+ {
+ AH_Blue blue;
+ FT_Bool check = 0;
+
+
+ for ( blue = AH_BLUE_CAPITAL_TOP; blue < AH_BLUE_MAX; blue++ )
+ {
+ FT_Pos ref, shoot, dist;
+
+
+ ref = globals->blue_refs[blue];
+ shoot = globals->blue_shoots[blue];
+ dist = ref-shoot;
+ if ( dist < 0 )
+ dist = -dist;
+
+ blue_active[blue] = 0;
+
+ if ( FT_MulFix( dist, y_scale ) < 48 )
+ {
+ blue_active[blue] = 1;
+ check = 1;
+ }
+ }
+
+ /* return immediately if no blue zone is active */
+ if ( !check )
+ return;
+ }
+
+ /* compute for each horizontal edge, which blue zone is closer */
+ for ( ; edge < edge_limit; edge++ )
+ {
+ AH_Blue blue;
+ FT_Pos* best_blue = 0;
+ FT_Pos best_dist; /* initial threshold */
+
+
+ /* compute the initial threshold as a fraction of the EM size */
+ best_dist = FT_MulFix( face_globals->face->units_per_EM / 40, y_scale );
+ if ( best_dist > 64 / 4 )
+ best_dist = 64 / 4;
+
+ for ( blue = AH_BLUE_CAPITAL_TOP; blue < AH_BLUE_MAX; blue++ )
+ {
+ /* if it is a top zone, check for right edges -- if it is a bottom */
+ /* zone, check for left edges */
+ /* */
+ /* of course, that's for TrueType XXX */
+ FT_Bool is_top_blue =
+ FT_BOOL( AH_IS_TOP_BLUE( blue ) );
+ FT_Bool is_major_dir =
+ FT_BOOL( edge->dir == outline->horz_major_dir );
+
+ if ( !blue_active[blue] )
+ continue;
+
+ /* if it is a top zone, the edge must be against the major */
+ /* direction; if it is a bottom zone, it must be in the major */
+ /* direction */
+ if ( is_top_blue ^ is_major_dir )
+ {
+ FT_Pos dist;
+ FT_Pos* blue_pos = globals->blue_refs + blue;
+
+
+ /* first of all, compare it to the reference position */
+ dist = edge->fpos - *blue_pos;
+ if ( dist < 0 )
+ dist = -dist;
+
+ dist = FT_MulFix( dist, y_scale );
+ if ( dist < best_dist )
+ {
+ best_dist = dist;
+ best_blue = blue_pos;
+ }
+
+ /* now, compare it to the overshoot position if the edge is */
+ /* rounded, and if the edge is over the reference position of a */
+ /* top zone, or under the reference position of a bottom zone */
+ if ( edge->flags & AH_EDGE_ROUND && dist != 0 )
+ {
+ FT_Bool is_under_ref = FT_BOOL( edge->fpos < *blue_pos );
+
+
+ if ( is_top_blue ^ is_under_ref )
+ {
+ blue_pos = globals->blue_shoots + blue;
+ dist = edge->fpos - *blue_pos;
+ if ( dist < 0 )
+ dist = -dist;
+
+ dist = FT_MulFix( dist, y_scale );
+ if ( dist < best_dist )
+ {
+ best_dist = dist;
+ best_blue = blue_pos;
+ }
+ }
+ }
+ }
+ }
+
+ if ( best_blue )
+ edge->blue_edge = best_blue;
+ }
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* ah_outline_scale_blue_edges */
+ /* */
+ /* <Description> */
+ /* This functions must be called before hinting in order to re-adjust */
+ /* the contents of the detected edges (basically change the `blue */
+ /* edge' pointer from `design units' to `scaled ones'). */
+ /* */
+ FT_LOCAL_DEF( void )
+ ah_outline_scale_blue_edges( AH_Outline outline,
+ AH_Face_Globals globals )
+ {
+ AH_Edge edge = outline->horz_edges;
+ AH_Edge edge_limit = edge + outline->num_hedges;
+ FT_Pos delta;
+
+
+ delta = globals->scaled.blue_refs - globals->design.blue_refs;
+
+ for ( ; edge < edge_limit; edge++ )
+ {
+ if ( edge->blue_edge )
+ edge->blue_edge += delta;
+ }
+ }
+
+
+/* END */
--- /dev/null
+++ b/libfreetype/ahglyph.h
@@ -1,0 +1,93 @@
+/***************************************************************************/
+/* */
+/* ahglyph.h */
+/* */
+/* Routines used to load and analyze a given glyph before hinting */
+/* (specification). */
+/* */
+/* Copyright 2000-2001, 2002 Catharon Productions Inc. */
+/* Author: David Turner */
+/* */
+/* This file is part of the Catharon Typography Project and shall only */
+/* be used, modified, and distributed under the terms of the Catharon */
+/* Open Source License that should come with this file under the name */
+/* `CatharonLicense.txt'. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/* Note that this license is compatible with the FreeType license. */
+/* */
+/***************************************************************************/
+
+
+#ifndef __AHGLYPH_H__
+#define __AHGLYPH_H__
+
+
+#include <ft2build.h>
+#include "ahtypes.h"
+
+
+FT_BEGIN_HEADER
+
+
+ typedef enum AH_UV_
+ {
+ AH_UV_FXY,
+ AH_UV_FYX,
+ AH_UV_OXY,
+ AH_UV_OYX,
+ AH_UV_OX,
+ AH_UV_OY,
+ AH_UV_YX,
+ AH_UV_XY /* should always be last! */
+
+ } AH_UV;
+
+
+ FT_LOCAL( void )
+ ah_setup_uv( AH_Outline outline,
+ AH_UV source );
+
+
+ /* AH_OutlineRec functions - they should be typically called in this order */
+
+ FT_LOCAL( FT_Error )
+ ah_outline_new( FT_Memory memory,
+ AH_Outline* aoutline );
+
+ FT_LOCAL( FT_Error )
+ ah_outline_load( AH_Outline outline,
+ FT_Face face );
+
+ FT_LOCAL( void )
+ ah_outline_compute_segments( AH_Outline outline );
+
+ FT_LOCAL( void )
+ ah_outline_link_segments( AH_Outline outline );
+
+ FT_LOCAL( void )
+ ah_outline_detect_features( AH_Outline outline );
+
+ FT_LOCAL( void )
+ ah_outline_compute_blue_edges( AH_Outline outline,
+ AH_Face_Globals globals );
+
+ FT_LOCAL( void )
+ ah_outline_scale_blue_edges( AH_Outline outline,
+ AH_Face_Globals globals );
+
+ FT_LOCAL( void )
+ ah_outline_save( AH_Outline outline,
+ AH_Loader loader );
+
+ FT_LOCAL( void )
+ ah_outline_done( AH_Outline outline );
+
+
+FT_END_HEADER
+
+#endif /* __AHGLYPH_H__ */
+
+
+/* END */
--- /dev/null
+++ b/libfreetype/ahhint.c
@@ -1,0 +1,1493 @@
+/***************************************************************************/
+/* */
+/* ahhint.c */
+/* */
+/* Glyph hinter (body). */
+/* */
+/* Copyright 2000-2001, 2002 Catharon Productions Inc. */
+/* Author: David Turner */
+/* */
+/* This file is part of the Catharon Typography Project and shall only */
+/* be used, modified, and distributed under the terms of the Catharon */
+/* Open Source License that should come with this file under the name */
+/* `CatharonLicense.txt'. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/* Note that this license is compatible with the FreeType license. */
+/* */
+/***************************************************************************/
+
+
+#include <ft2build.h>
+#include "ahhint.h"
+#include "ahglyph.h"
+#include "ahangles.h"
+#include "aherrors.h"
+#include FT_OUTLINE_H
+
+
+#define FACE_GLOBALS( face ) ((AH_Face_Globals)(face)->autohint.data)
+
+#define AH_USE_IUP
+#define OPTIM_STEM_SNAP
+
+ /*************************************************************************/
+ /*************************************************************************/
+ /**** ****/
+ /**** Hinting routines ****/
+ /**** ****/
+ /*************************************************************************/
+ /*************************************************************************/
+
+ /* snap a given width in scaled coordinates to one of the */
+ /* current standard widths */
+ static FT_Pos
+ ah_snap_width( FT_Pos* widths,
+ FT_Int count,
+ FT_Pos width )
+ {
+ int n;
+ FT_Pos best = 64 + 32 + 2;
+ FT_Pos reference = width;
+ FT_Pos scaled;
+
+
+ for ( n = 0; n < count; n++ )
+ {
+ FT_Pos w;
+ FT_Pos dist;
+
+
+ w = widths[n];
+ dist = width - w;
+ if ( dist < 0 )
+ dist = -dist;
+ if ( dist < best )
+ {
+ best = dist;
+ reference = w;
+ }
+ }
+
+ scaled = (reference+32) & -64;
+
+ if ( width >= reference )
+ {
+ if ( width < scaled + 48 )
+ width = reference;
+ }
+ else
+ {
+ if ( width > scaled - 48 )
+ width = reference;
+ }
+
+ return width;
+ }
+
+
+ /* compute the snapped width of a given stem */
+ static FT_Pos
+ ah_compute_stem_width( AH_Hinter hinter,
+ int vertical,
+ FT_Pos width )
+ {
+ AH_Globals globals = &hinter->globals->scaled;
+ FT_Pos dist = width;
+ FT_Int sign = 0;
+
+
+ if ( dist < 0 )
+ {
+ dist = -width;
+ sign = 1;
+ }
+
+ if ( ( vertical && !hinter->do_vert_snapping ) ||
+ ( !vertical && !hinter->do_horz_snapping ) )
+ {
+ /* smooth hinting process, very lightly quantize the stem width */
+ /* */
+ if ( dist < 64 )
+ dist = 64;
+
+ {
+ FT_Pos delta = dist - globals->stds[vertical];
+
+
+ if ( delta < 0 )
+ delta = -delta;
+
+ if ( delta < 40 )
+ {
+ dist = globals->stds[vertical];
+ if ( dist < 48 )
+ dist = 48;
+ }
+
+ if ( dist < 3 * 64 )
+ {
+ delta = ( dist & 63 );
+ dist &= -64;
+
+ if ( delta < 10 )
+ dist += delta;
+
+ else if ( delta < 32 )
+ dist += 10;
+
+ else if ( delta < 54 )
+ dist += 54;
+
+ else
+ dist += delta;
+ }
+ else
+ dist = ( dist + 32 ) & -64;
+ }
+ }
+ else
+ {
+ /* strong hinting process, snap the stem width to integer pixels */
+ /* */
+ if ( vertical )
+ {
+ dist = ah_snap_width( globals->heights, globals->num_heights, dist );
+
+ /* in the case of vertical hinting, always round */
+ /* the stem heights to integer pixels */
+ if ( dist >= 64 )
+ dist = ( dist + 16 ) & -64;
+ else
+ dist = 64;
+ }
+ else
+ {
+ dist = ah_snap_width( globals->widths, globals->num_widths, dist );
+
+ if ( hinter->flags & AH_HINTER_MONOCHROME )
+ {
+ /* monochrome horizontal hinting: snap widths to integer pixels */
+ /* with a different threshold */
+ if ( dist < 64 )
+ dist = 64;
+ else
+ dist = ( dist + 32 ) & -64;
+ }
+ else
+ {
+ /* for horizontal anti-aliased hinting, we adopt a more subtle */
+ /* approach: we strengthen small stems, round stems whose size */
+ /* is between 1 and 2 pixels to an integer, otherwise nothing */
+ if ( dist < 48 )
+ dist = ( dist + 64 ) >> 1;
+
+ else if ( dist < 128 )
+ dist = ( dist + 22 ) & -64;
+ else
+ /* XXX: round otherwise, prevent color fringes in LCD mode */
+ dist = ( dist + 32 ) & -64;
+ }
+ }
+ }
+
+ if ( sign )
+ dist = -dist;
+
+ return dist;
+ }
+
+
+ /* align one stem edge relative to the previous stem edge */
+ static void
+ ah_align_linked_edge( AH_Hinter hinter,
+ AH_Edge base_edge,
+ AH_Edge stem_edge,
+ int vertical )
+ {
+ FT_Pos dist = stem_edge->opos - base_edge->opos;
+
+
+ stem_edge->pos = base_edge->pos +
+ ah_compute_stem_width( hinter, vertical, dist );
+ }
+
+
+ static void
+ ah_align_serif_edge( AH_Hinter hinter,
+ AH_Edge base,
+ AH_Edge serif,
+ int vertical )
+ {
+ FT_Pos dist;
+ FT_Pos sign = 1;
+
+ FT_UNUSED( hinter );
+
+
+ dist = serif->opos - base->opos;
+ if ( dist < 0 )
+ {
+ dist = -dist;
+ sign = -1;
+ }
+
+ /* do not touch serifs widths !! */
+#if 0
+ if ( base->flags & AH_EDGE_DONE )
+ {
+ if ( dist >= 64 )
+ dist = (dist+8) & -64;
+
+ else if ( dist <= 32 && !vertical )
+ dist = ( dist + 33 ) >> 1;
+ else
+ dist = 0;
+ }
+#endif
+
+ serif->pos = base->pos + sign * dist;
+ }
+
+
+ /*************************************************************************/
+ /*************************************************************************/
+ /*************************************************************************/
+ /**** ****/
+ /**** E D G E H I N T I N G ****/
+ /**** ****/
+ /*************************************************************************/
+ /*************************************************************************/
+ /*************************************************************************/
+
+
+ /* Another alternative edge hinting algorithm */
+ static void
+ ah_hint_edges_3( AH_Hinter hinter )
+ {
+ AH_Edge edges;
+ AH_Edge edge_limit;
+ AH_Outline outline = hinter->glyph;
+ FT_Int dimension;
+
+
+ edges = outline->horz_edges;
+ edge_limit = edges + outline->num_hedges;
+
+ for ( dimension = 1; dimension >= 0; dimension-- )
+ {
+ AH_Edge edge;
+ AH_Edge anchor = 0;
+ int has_serifs = 0;
+
+
+ if ( !hinter->do_horz_hints && !dimension )
+ goto Next_Dimension;
+
+ if ( !hinter->do_vert_hints && dimension )
+ goto Next_Dimension;
+
+ /* we begin by aligning all stems relative to the blue zone */
+ /* if needed -- that's only for horizontal edges */
+ if ( dimension )
+ {
+ for ( edge = edges; edge < edge_limit; edge++ )
+ {
+ FT_Pos* blue;
+ AH_EdgeRec *edge1, *edge2;
+
+
+ if ( edge->flags & AH_EDGE_DONE )
+ continue;
+
+ blue = edge->blue_edge;
+ edge1 = 0;
+ edge2 = edge->link;
+
+ if ( blue )
+ {
+ edge1 = edge;
+ }
+ else if (edge2 && edge2->blue_edge)
+ {
+ blue = edge2->blue_edge;
+ edge1 = edge2;
+ edge2 = edge;
+ }
+
+ if ( !edge1 )
+ continue;
+
+ edge1->pos = blue[0];
+ edge1->flags |= AH_EDGE_DONE;
+
+ if ( edge2 && !edge2->blue_edge )
+ {
+ ah_align_linked_edge( hinter, edge1, edge2, dimension );
+ edge2->flags |= AH_EDGE_DONE;
+ }
+
+ if ( !anchor )
+ anchor = edge;
+ }
+ }
+
+ /* now, we will align all stem edges, trying to maintain the */
+ /* relative order of stems in the glyph.. */
+ for ( edge = edges; edge < edge_limit; edge++ )
+ {
+ AH_EdgeRec* edge2;
+
+
+ if ( edge->flags & AH_EDGE_DONE )
+ continue;
+
+ /* skip all non-stem edges */
+ edge2 = edge->link;
+ if ( !edge2 )
+ {
+ has_serifs++;
+ continue;
+ }
+
+ /* now, align the stem */
+
+ /* this should not happen, but it's better to be safe. */
+ if ( edge2->blue_edge || edge2 < edge )
+ {
+
+ ah_align_linked_edge( hinter, edge2, edge, dimension );
+ edge->flags |= AH_EDGE_DONE;
+ continue;
+ }
+
+ if ( !anchor )
+ {
+ edge->pos = ( edge->opos + 32 ) & -64;
+ anchor = edge;
+
+ edge->flags |= AH_EDGE_DONE;
+
+ ah_align_linked_edge( hinter, edge, edge2, dimension );
+ }
+ else
+ {
+ FT_Pos org_pos, org_len, org_center, cur_len;
+ FT_Pos cur_pos1, cur_pos2, delta1, delta2;
+
+
+ org_pos = anchor->pos + (edge->opos - anchor->opos);
+ org_len = edge2->opos - edge->opos;
+ org_center = org_pos + ( org_len >> 1 );
+
+ cur_len = ah_compute_stem_width( hinter, dimension, org_len );
+
+ cur_pos1 = ( org_pos + 32 ) & -64;
+ delta1 = ( cur_pos1 + ( cur_len >> 1 ) - org_center );
+ if ( delta1 < 0 )
+ delta1 = -delta1;
+
+ cur_pos2 = ( ( org_pos + org_len + 32 ) & -64 ) - cur_len;
+ delta2 = ( cur_pos2 + ( cur_len >> 1 ) - org_center );
+ if ( delta2 < 0 )
+ delta2 = -delta2;
+
+ edge->pos = ( delta1 <= delta2 ) ? cur_pos1 : cur_pos2;
+ edge2->pos = edge->pos + cur_len;
+
+ edge->flags |= AH_EDGE_DONE;
+ edge2->flags |= AH_EDGE_DONE;
+
+ if ( edge > edges && edge->pos < edge[-1].pos )
+ edge->pos = edge[-1].pos;
+ }
+ }
+
+ if ( !has_serifs )
+ goto Next_Dimension;
+
+ /* now, hint the remaining edges (serifs and single) in order */
+ /* to complete our processing */
+ for ( edge = edges; edge < edge_limit; edge++ )
+ {
+ if ( edge->flags & AH_EDGE_DONE )
+ continue;
+
+ if ( edge->serif )
+ ah_align_serif_edge( hinter, edge->serif, edge, dimension );
+ else if ( !anchor )
+ {
+ edge->pos = ( edge->opos + 32 ) & -64;
+ anchor = edge;
+ }
+ else
+ edge->pos = anchor->pos +
+ ( ( edge->opos-anchor->opos + 32 ) & -64 );
+
+ edge->flags |= AH_EDGE_DONE;
+
+ if ( edge > edges && edge->pos < edge[-1].pos )
+ edge->pos = edge[-1].pos;
+
+ if ( edge + 1 < edge_limit &&
+ edge[1].flags & AH_EDGE_DONE &&
+ edge->pos > edge[1].pos )
+ edge->pos = edge[1].pos;
+ }
+
+ Next_Dimension:
+ edges = outline->vert_edges;
+ edge_limit = edges + outline->num_vedges;
+ }
+ }
+
+
+ FT_LOCAL_DEF( void )
+ ah_hinter_hint_edges( AH_Hinter hinter )
+ {
+ /* AH_Interpolate_Blue_Edges( hinter ); -- doesn't seem to help */
+ /* reduce the problem of the disappearing eye in the `e' of Times... */
+ /* also, creates some artifacts near the blue zones? */
+ {
+ ah_hint_edges_3( hinter );
+ }
+ }
+
+
+ /*************************************************************************/
+ /*************************************************************************/
+ /*************************************************************************/
+ /**** ****/
+ /**** P O I N T H I N T I N G ****/
+ /**** ****/
+ /*************************************************************************/
+ /*************************************************************************/
+ /*************************************************************************/
+
+ static void
+ ah_hinter_align_edge_points( AH_Hinter hinter )
+ {
+ AH_Outline outline = hinter->glyph;
+ AH_Edge edges;
+ AH_Edge edge_limit;
+ FT_Int dimension;
+
+
+ edges = outline->horz_edges;
+ edge_limit = edges + outline->num_hedges;
+
+ for ( dimension = 1; dimension >= 0; dimension-- )
+ {
+ AH_Edge edge;
+
+
+ edge = edges;
+ for ( ; edge < edge_limit; edge++ )
+ {
+ /* move the points of each segment */
+ /* in each edge to the edge's position */
+ AH_Segment seg = edge->first;
+
+
+ do
+ {
+ AH_Point point = seg->first;
+
+
+ for (;;)
+ {
+ if ( dimension )
+ {
+ point->y = edge->pos;
+ point->flags |= AH_FLAG_TOUCH_Y;
+ }
+ else
+ {
+ point->x = edge->pos;
+ point->flags |= AH_FLAG_TOUCH_X;
+ }
+
+ if ( point == seg->last )
+ break;
+
+ point = point->next;
+ }
+
+ seg = seg->edge_next;
+
+ } while ( seg != edge->first );
+ }
+
+ edges = outline->vert_edges;
+ edge_limit = edges + outline->num_vedges;
+ }
+ }
+
+
+ /* hint the strong points -- this is equivalent to the TrueType `IP' */
+ static void
+ ah_hinter_align_strong_points( AH_Hinter hinter )
+ {
+ AH_Outline outline = hinter->glyph;
+ FT_Int dimension;
+ AH_Edge edges;
+ AH_Edge edge_limit;
+ AH_Point points;
+ AH_Point point_limit;
+ AH_Flags touch_flag;
+
+
+ points = outline->points;
+ point_limit = points + outline->num_points;
+
+ edges = outline->horz_edges;
+ edge_limit = edges + outline->num_hedges;
+ touch_flag = AH_FLAG_TOUCH_Y;
+
+ for ( dimension = 1; dimension >= 0; dimension-- )
+ {
+ AH_Point point;
+ AH_Edge edge;
+
+
+ if ( edges < edge_limit )
+ for ( point = points; point < point_limit; point++ )
+ {
+ FT_Pos u, ou, fu; /* point position */
+ FT_Pos delta;
+
+
+ if ( point->flags & touch_flag )
+ continue;
+
+#ifndef AH_OPTION_NO_WEAK_INTERPOLATION
+ /* if this point is candidate to weak interpolation, we will */
+ /* interpolate it after all strong points have been processed */
+ if ( ( point->flags & AH_FLAG_WEAK_INTERPOLATION ) &&
+ !( point->flags & AH_FLAG_INFLECTION ) )
+ continue;
+#endif
+
+ if ( dimension )
+ {
+ u = point->fy;
+ ou = point->oy;
+ }
+ else
+ {
+ u = point->fx;
+ ou = point->ox;
+ }
+
+ fu = u;
+
+ /* is the point before the first edge? */
+ edge = edges;
+ delta = edge->fpos - u;
+ if ( delta >= 0 )
+ {
+ u = edge->pos - ( edge->opos - ou );
+ goto Store_Point;
+ }
+
+ /* is the point after the last edge ? */
+ edge = edge_limit - 1;
+ delta = u - edge->fpos;
+ if ( delta >= 0 )
+ {
+ u = edge->pos + ( ou - edge->opos );
+ goto Store_Point;
+ }
+
+ /* otherwise, interpolate the point in between */
+ {
+ AH_Edge before = 0;
+ AH_Edge after = 0;
+
+
+ for ( edge = edges; edge < edge_limit; edge++ )
+ {
+ if ( u == edge->fpos )
+ {
+ u = edge->pos;
+ goto Store_Point;
+ }
+ if ( u < edge->fpos )
+ break;
+ before = edge;
+ }
+
+ for ( edge = edge_limit - 1; edge >= edges; edge-- )
+ {
+ if ( u == edge->fpos )
+ {
+ u = edge->pos;
+ goto Store_Point;
+ }
+ if ( u > edge->fpos )
+ break;
+ after = edge;
+ }
+
+ /* assert( before && after && before != after ) */
+ u = before->pos + FT_MulDiv( fu - before->fpos,
+ after->pos - before->pos,
+ after->fpos - before->fpos );
+ }
+
+ Store_Point:
+
+ /* save the point position */
+ if ( dimension )
+ point->y = u;
+ else
+ point->x = u;
+
+ point->flags |= touch_flag;
+ }
+
+ edges = outline->vert_edges;
+ edge_limit = edges + outline->num_vedges;
+ touch_flag = AH_FLAG_TOUCH_X;
+ }
+ }
+
+
+#ifndef AH_OPTION_NO_WEAK_INTERPOLATION
+
+ static void
+ ah_iup_shift( AH_Point p1,
+ AH_Point p2,
+ AH_Point ref )
+ {
+ AH_Point p;
+ FT_Pos delta = ref->u - ref->v;
+
+
+ for ( p = p1; p < ref; p++ )
+ p->u = p->v + delta;
+
+ for ( p = ref + 1; p <= p2; p++ )
+ p->u = p->v + delta;
+ }
+
+
+ static void
+ ah_iup_interp( AH_Point p1,
+ AH_Point p2,
+ AH_Point ref1,
+ AH_Point ref2 )
+ {
+ AH_Point p;
+ FT_Pos u;
+ FT_Pos v1 = ref1->v;
+ FT_Pos v2 = ref2->v;
+ FT_Pos d1 = ref1->u - v1;
+ FT_Pos d2 = ref2->u - v2;
+
+
+ if ( p1 > p2 )
+ return;
+
+ if ( v1 == v2 )
+ {
+ for ( p = p1; p <= p2; p++ )
+ {
+ u = p->v;
+
+ if ( u <= v1 )
+ u += d1;
+ else
+ u += d2;
+
+ p->u = u;
+ }
+ return;
+ }
+
+ if ( v1 < v2 )
+ {
+ for ( p = p1; p <= p2; p++ )
+ {
+ u = p->v;
+
+ if ( u <= v1 )
+ u += d1;
+ else if ( u >= v2 )
+ u += d2;
+ else
+ u = ref1->u + FT_MulDiv( u - v1, ref2->u - ref1->u, v2 - v1 );
+
+ p->u = u;
+ }
+ }
+ else
+ {
+ for ( p = p1; p <= p2; p++ )
+ {
+ u = p->v;
+
+ if ( u <= v2 )
+ u += d2;
+ else if ( u >= v1 )
+ u += d1;
+ else
+ u = ref1->u + FT_MulDiv( u - v1, ref2->u - ref1->u, v2 - v1 );
+
+ p->u = u;
+ }
+ }
+ }
+
+
+ /* interpolate weak points -- this is equivalent to the TrueType `IUP' */
+ static void
+ ah_hinter_align_weak_points( AH_Hinter hinter )
+ {
+ AH_Outline outline = hinter->glyph;
+ FT_Int dimension;
+ AH_Point points;
+ AH_Point point_limit;
+ AH_Point* contour_limit;
+ AH_Flags touch_flag;
+
+
+ points = outline->points;
+ point_limit = points + outline->num_points;
+
+ /* PASS 1: Move segment points to edge positions */
+
+ touch_flag = AH_FLAG_TOUCH_Y;
+
+ contour_limit = outline->contours + outline->num_contours;
+
+ ah_setup_uv( outline, AH_UV_OY );
+
+ for ( dimension = 1; dimension >= 0; dimension-- )
+ {
+ AH_Point point;
+ AH_Point end_point;
+ AH_Point first_point;
+ AH_Point* contour;
+
+
+ point = points;
+ contour = outline->contours;
+
+ for ( ; contour < contour_limit; contour++ )
+ {
+ point = *contour;
+ end_point = point->prev;
+ first_point = point;
+
+ while ( point <= end_point && !( point->flags & touch_flag ) )
+ point++;
+
+ if ( point <= end_point )
+ {
+ AH_Point first_touched = point;
+ AH_Point cur_touched = point;
+
+
+ point++;
+ while ( point <= end_point )
+ {
+ if ( point->flags & touch_flag )
+ {
+ /* we found two successive touched points; we interpolate */
+ /* all contour points between them */
+ ah_iup_interp( cur_touched + 1, point - 1,
+ cur_touched, point );
+ cur_touched = point;
+ }
+ point++;
+ }
+
+ if ( cur_touched == first_touched )
+ {
+ /* this is a special case: only one point was touched in the */
+ /* contour; we thus simply shift the whole contour */
+ ah_iup_shift( first_point, end_point, cur_touched );
+ }
+ else
+ {
+ /* now interpolate after the last touched point to the end */
+ /* of the contour */
+ ah_iup_interp( cur_touched + 1, end_point,
+ cur_touched, first_touched );
+
+ /* if the first contour point isn't touched, interpolate */
+ /* from the contour start to the first touched point */
+ if ( first_touched > points )
+ ah_iup_interp( first_point, first_touched - 1,
+ cur_touched, first_touched );
+ }
+ }
+ }
+
+ /* now save the interpolated values back to x/y */
+ if ( dimension )
+ {
+ for ( point = points; point < point_limit; point++ )
+ point->y = point->u;
+
+ touch_flag = AH_FLAG_TOUCH_X;
+ ah_setup_uv( outline, AH_UV_OX );
+ }
+ else
+ {
+ for ( point = points; point < point_limit; point++ )
+ point->x = point->u;
+
+ break; /* exit loop */
+ }
+ }
+ }
+
+#endif /* !AH_OPTION_NO_WEAK_INTERPOLATION */
+
+
+ FT_LOCAL_DEF( void )
+ ah_hinter_align_points( AH_Hinter hinter )
+ {
+ ah_hinter_align_edge_points( hinter );
+
+#ifndef AH_OPTION_NO_STRONG_INTERPOLATION
+ ah_hinter_align_strong_points( hinter );
+#endif
+
+#ifndef AH_OPTION_NO_WEAK_INTERPOLATION
+ ah_hinter_align_weak_points( hinter );
+#endif
+ }
+
+
+ /*************************************************************************/
+ /*************************************************************************/
+ /*************************************************************************/
+ /**** ****/
+ /**** H I N T E R O B J E C T M E T H O D S ****/
+ /**** ****/
+ /*************************************************************************/
+ /*************************************************************************/
+ /*************************************************************************/
+
+
+ /* scale and fit the global metrics */
+ static void
+ ah_hinter_scale_globals( AH_Hinter hinter,
+ FT_Fixed x_scale,
+ FT_Fixed y_scale )
+ {
+ FT_Int n;
+ AH_Face_Globals globals = hinter->globals;
+ AH_Globals design = &globals->design;
+ AH_Globals scaled = &globals->scaled;
+
+
+ /* copy content */
+ *scaled = *design;
+
+ /* scale the standard widths & heights */
+ for ( n = 0; n < design->num_widths; n++ )
+ scaled->widths[n] = FT_MulFix( design->widths[n], x_scale );
+
+ for ( n = 0; n < design->num_heights; n++ )
+ scaled->heights[n] = FT_MulFix( design->heights[n], y_scale );
+
+ scaled->stds[0] = ( design->num_widths > 0 ) ? scaled->widths[0] : 32000;
+ scaled->stds[1] = ( design->num_heights > 0 ) ? scaled->heights[0] : 32000;
+
+ /* scale the blue zones */
+ for ( n = 0; n < AH_BLUE_MAX; n++ )
+ {
+ FT_Pos delta, delta2;
+
+
+ delta = design->blue_shoots[n] - design->blue_refs[n];
+ delta2 = delta;
+ if ( delta < 0 )
+ delta2 = -delta2;
+ delta2 = FT_MulFix( delta2, y_scale );
+
+ if ( delta2 < 32 )
+ delta2 = 0;
+ else if ( delta2 < 64 )
+ delta2 = 32 + ( ( ( delta2 - 32 ) + 16 ) & -32 );
+ else
+ delta2 = ( delta2 + 32 ) & -64;
+
+ if ( delta < 0 )
+ delta2 = -delta2;
+
+ scaled->blue_refs[n] =
+ ( FT_MulFix( design->blue_refs[n], y_scale ) + 32 ) & -64;
+ scaled->blue_shoots[n] = scaled->blue_refs[n] + delta2;
+ }
+
+ globals->x_scale = x_scale;
+ globals->y_scale = y_scale;
+ }
+
+
+ static void
+ ah_hinter_align( AH_Hinter hinter )
+ {
+ ah_hinter_align_edge_points( hinter );
+ ah_hinter_align_points( hinter );
+ }
+
+
+ /* finalize a hinter object */
+ FT_LOCAL_DEF( void )
+ ah_hinter_done( AH_Hinter hinter )
+ {
+ if ( hinter )
+ {
+ FT_Memory memory = hinter->memory;
+
+
+ ah_loader_done( hinter->loader );
+ ah_outline_done( hinter->glyph );
+
+ /* note: the `globals' pointer is _not_ owned by the hinter */
+ /* but by the current face object, we don't need to */
+ /* release it */
+ hinter->globals = 0;
+ hinter->face = 0;
+
+ FT_FREE( hinter );
+ }
+ }
+
+
+ /* create a new empty hinter object */
+ FT_LOCAL_DEF( FT_Error )
+ ah_hinter_new( FT_Library library,
+ AH_Hinter *ahinter )
+ {
+ AH_Hinter hinter = 0;
+ FT_Memory memory = library->memory;
+ FT_Error error;
+
+
+ *ahinter = 0;
+
+ /* allocate object */
+ if ( FT_NEW( hinter ) )
+ goto Exit;
+
+ hinter->memory = memory;
+ hinter->flags = 0;
+
+ /* allocate outline and loader */
+ error = ah_outline_new( memory, &hinter->glyph ) ||
+ ah_loader_new ( memory, &hinter->loader ) ||
+ ah_loader_create_extra( hinter->loader );
+ if ( error )
+ goto Exit;
+
+ *ahinter = hinter;
+
+ Exit:
+ if ( error )
+ ah_hinter_done( hinter );
+
+ return error;
+ }
+
+
+ /* create a face's autohint globals */
+ FT_LOCAL_DEF( FT_Error )
+ ah_hinter_new_face_globals( AH_Hinter hinter,
+ FT_Face face,
+ AH_Globals globals )
+ {
+ FT_Error error;
+ FT_Memory memory = hinter->memory;
+ AH_Face_Globals face_globals;
+
+
+ if ( FT_NEW( face_globals ) )
+ goto Exit;
+
+ hinter->face = face;
+ hinter->globals = face_globals;
+
+ if ( globals )
+ face_globals->design = *globals;
+ else
+ ah_hinter_compute_globals( hinter );
+
+ face->autohint.data = face_globals;
+ face->autohint.finalizer = (FT_Generic_Finalizer)
+ ah_hinter_done_face_globals;
+ face_globals->face = face;
+
+ Exit:
+ return error;
+ }
+
+
+ /* discard a face's autohint globals */
+ FT_LOCAL_DEF( void )
+ ah_hinter_done_face_globals( AH_Face_Globals globals )
+ {
+ FT_Face face = globals->face;
+ FT_Memory memory = face->memory;
+
+
+ FT_FREE( globals );
+ }
+
+
+ static FT_Error
+ ah_hinter_load( AH_Hinter hinter,
+ FT_UInt glyph_index,
+ FT_Int32 load_flags,
+ FT_UInt depth )
+ {
+ FT_Face face = hinter->face;
+ FT_GlyphSlot slot = face->glyph;
+ FT_Slot_Internal internal = slot->internal;
+ FT_Fixed x_scale = face->size->metrics.x_scale;
+ FT_Fixed y_scale = face->size->metrics.y_scale;
+ FT_Error error;
+ AH_Outline outline = hinter->glyph;
+ AH_Loader gloader = hinter->loader;
+
+
+ /* load the glyph */
+ error = FT_Load_Glyph( face, glyph_index, load_flags );
+ if ( error )
+ goto Exit;
+
+ /* Set `hinter->transformed' after loading with FT_LOAD_NO_RECURSE. */
+ hinter->transformed = internal->glyph_transformed;
+
+ if ( hinter->transformed )
+ {
+ FT_Matrix imatrix;
+
+
+ imatrix = internal->glyph_matrix;
+ hinter->trans_delta = internal->glyph_delta;
+ hinter->trans_matrix = imatrix;
+
+ FT_Matrix_Invert( &imatrix );
+ FT_Vector_Transform( &hinter->trans_delta, &imatrix );
+ }
+
+ /* set linear horizontal metrics */
+ slot->linearHoriAdvance = slot->metrics.horiAdvance;
+ slot->linearVertAdvance = slot->metrics.vertAdvance;
+
+ switch ( slot->format )
+ {
+ case FT_GLYPH_FORMAT_OUTLINE:
+
+ /* translate glyph outline if we need to */
+ if ( hinter->transformed )
+ {
+ FT_UInt n = slot->outline.n_points;
+ FT_Vector* point = slot->outline.points;
+
+
+ for ( ; n > 0; point++, n-- )
+ {
+ point->x += hinter->trans_delta.x;
+ point->y += hinter->trans_delta.y;
+ }
+ }
+
+ /* copy the outline points in the loader's current */
+ /* extra points, which is used to keep original glyph coordinates */
+ error = ah_loader_check_points( gloader, slot->outline.n_points + 2,
+ slot->outline.n_contours );
+ if ( error )
+ goto Exit;
+
+ FT_MEM_COPY( gloader->current.extra_points, slot->outline.points,
+ slot->outline.n_points * sizeof ( FT_Vector ) );
+
+ FT_MEM_COPY( gloader->current.outline.contours, slot->outline.contours,
+ slot->outline.n_contours * sizeof ( short ) );
+
+ FT_MEM_COPY( gloader->current.outline.tags, slot->outline.tags,
+ slot->outline.n_points * sizeof ( char ) );
+
+ gloader->current.outline.n_points = slot->outline.n_points;
+ gloader->current.outline.n_contours = slot->outline.n_contours;
+
+ /* compute original phantom points */
+ hinter->pp1.x = 0;
+ hinter->pp1.y = 0;
+ hinter->pp2.x = FT_MulFix( slot->metrics.horiAdvance, x_scale );
+ hinter->pp2.y = 0;
+
+ /* be sure to check for spacing glyphs */
+ if ( slot->outline.n_points == 0 )
+ goto Hint_Metrics;
+
+ /* now, load the slot image into the auto-outline, and run the */
+ /* automatic hinting process */
+ error = ah_outline_load( outline, face ); /* XXX: change to slot */
+ if ( error )
+ goto Exit;
+
+ /* perform feature detection */
+ ah_outline_detect_features( outline );
+
+ if ( hinter->do_vert_hints )
+ {
+ ah_outline_compute_blue_edges( outline, hinter->globals );
+ ah_outline_scale_blue_edges( outline, hinter->globals );
+ }
+
+ /* perform alignment control */
+ ah_hinter_hint_edges( hinter );
+ ah_hinter_align( hinter );
+
+ /* now save the current outline into the loader's current table */
+ ah_outline_save( outline, gloader );
+
+ /* we now need to hint the metrics according to the change in */
+ /* width/positioning that occured during the hinting process */
+ {
+ FT_Pos old_advance, old_rsb, old_lsb, new_lsb;
+ AH_Edge edge1 = outline->vert_edges; /* leftmost edge */
+ AH_Edge edge2 = edge1 +
+ outline->num_vedges - 1; /* rightmost edge */
+
+
+ old_advance = hinter->pp2.x;
+ old_rsb = old_advance - edge2->opos;
+ old_lsb = edge1->opos;
+ new_lsb = edge1->pos;
+
+ hinter->pp1.x = ( ( new_lsb - old_lsb ) + 32 ) & -64;
+ hinter->pp2.x = ( ( edge2->pos + old_rsb ) + 32 ) & -64;
+
+ /* try to fix certain bad advance computations */
+ if ( hinter->pp2.x + hinter->pp1.x == edge2->pos && old_rsb > 4 )
+ hinter->pp2.x += 64;
+ }
+
+ /* good, we simply add the glyph to our loader's base */
+ ah_loader_add( gloader );
+ break;
+
+ case FT_GLYPH_FORMAT_COMPOSITE:
+ {
+ FT_UInt nn, num_subglyphs = slot->num_subglyphs;
+ FT_UInt num_base_subgs, start_point;
+ FT_SubGlyph subglyph;
+
+
+ start_point = gloader->base.outline.n_points;
+
+ /* first of all, copy the subglyph descriptors in the glyph loader */
+ error = ah_loader_check_subglyphs( gloader, num_subglyphs );
+ if ( error )
+ goto Exit;
+
+ FT_MEM_COPY( gloader->current.subglyphs, slot->subglyphs,
+ num_subglyphs * sizeof ( FT_SubGlyph ) );
+
+ gloader->current.num_subglyphs = num_subglyphs;
+ num_base_subgs = gloader->base.num_subglyphs;
+
+ /* now, read each subglyph independently */
+ for ( nn = 0; nn < num_subglyphs; nn++ )
+ {
+ FT_Vector pp1, pp2;
+ FT_Pos x, y;
+ FT_UInt num_points, num_new_points, num_base_points;
+
+
+ /* gloader.current.subglyphs can change during glyph loading due */
+ /* to re-allocation -- we must recompute the current subglyph on */
+ /* each iteration */
+ subglyph = gloader->base.subglyphs + num_base_subgs + nn;
+
+ pp1 = hinter->pp1;
+ pp2 = hinter->pp2;
+
+ num_base_points = gloader->base.outline.n_points;
+
+ error = ah_hinter_load( hinter, subglyph->index,
+ load_flags, depth + 1 );
+ if ( error )
+ goto Exit;
+
+ /* recompute subglyph pointer */
+ subglyph = gloader->base.subglyphs + num_base_subgs + nn;
+
+ if ( subglyph->flags & FT_SUBGLYPH_FLAG_USE_MY_METRICS )
+ {
+ pp1 = hinter->pp1;
+ pp2 = hinter->pp2;
+ }
+ else
+ {
+ hinter->pp1 = pp1;
+ hinter->pp2 = pp2;
+ }
+
+ num_points = gloader->base.outline.n_points;
+ num_new_points = num_points - num_base_points;
+
+ /* now perform the transform required for this subglyph */
+
+ if ( subglyph->flags & ( FT_SUBGLYPH_FLAG_SCALE |
+ FT_SUBGLYPH_FLAG_XY_SCALE |
+ FT_SUBGLYPH_FLAG_2X2 ) )
+ {
+ FT_Vector* cur = gloader->base.outline.points +
+ num_base_points;
+ FT_Vector* org = gloader->base.extra_points +
+ num_base_points;
+ FT_Vector* limit = cur + num_new_points;
+
+
+ for ( ; cur < limit; cur++, org++ )
+ {
+ FT_Vector_Transform( cur, &subglyph->transform );
+ FT_Vector_Transform( org, &subglyph->transform );
+ }
+ }
+
+ /* apply offset */
+
+ if ( !( subglyph->flags & FT_SUBGLYPH_FLAG_ARGS_ARE_XY_VALUES ) )
+ {
+ FT_Int k = subglyph->arg1;
+ FT_UInt l = subglyph->arg2;
+ FT_Vector* p1;
+ FT_Vector* p2;
+
+
+ if ( start_point + k >= num_base_points ||
+ l >= (FT_UInt)num_new_points )
+ {
+ error = AH_Err_Invalid_Composite;
+ goto Exit;
+ }
+
+ l += num_base_points;
+
+ /* for now, only use the current point coordinates */
+ /* we may consider another approach in the near future */
+ p1 = gloader->base.outline.points + start_point + k;
+ p2 = gloader->base.outline.points + start_point + l;
+
+ x = p1->x - p2->x;
+ y = p1->y - p2->y;
+ }
+ else
+ {
+ x = FT_MulFix( subglyph->arg1, x_scale );
+ y = FT_MulFix( subglyph->arg2, y_scale );
+
+ x = ( x + 32 ) & -64;
+ y = ( y + 32 ) & -64;
+ }
+
+ {
+ FT_Outline dummy = gloader->base.outline;
+
+
+ dummy.points += num_base_points;
+ dummy.n_points = (short)num_new_points;
+
+ FT_Outline_Translate( &dummy, x, y );
+ }
+ }
+ }
+ break;
+
+ default:
+ /* we don't support other formats (yet?) */
+ error = AH_Err_Unimplemented_Feature;
+ }
+
+ Hint_Metrics:
+ if ( depth == 0 )
+ {
+ FT_BBox bbox;
+
+
+ /* transform the hinted outline if needed */
+ if ( hinter->transformed )
+ FT_Outline_Transform( &gloader->base.outline, &hinter->trans_matrix );
+
+ /* we must translate our final outline by -pp1.x, and compute */
+ /* the new metrics */
+ if ( hinter->pp1.x )
+ FT_Outline_Translate( &gloader->base.outline, -hinter->pp1.x, 0 );
+
+ FT_Outline_Get_CBox( &gloader->base.outline, &bbox );
+ bbox.xMin &= -64;
+ bbox.yMin &= -64;
+ bbox.xMax = ( bbox.xMax + 63 ) & -64;
+ bbox.yMax = ( bbox.yMax + 63 ) & -64;
+
+ slot->metrics.width = bbox.xMax - bbox.xMin;
+ slot->metrics.height = bbox.yMax - bbox.yMin;
+ slot->metrics.horiBearingX = bbox.xMin;
+ slot->metrics.horiBearingY = bbox.yMax;
+
+ /* for mono-width fonts (like Andale, Courier, etc.), we need */
+ /* to keep the original rounded advance width */
+ if ( !FT_IS_FIXED_WIDTH( slot->face ) )
+ slot->metrics.horiAdvance = hinter->pp2.x - hinter->pp1.x;
+ else
+ slot->metrics.horiAdvance = FT_MulFix( slot->metrics.horiAdvance,
+ x_scale );
+
+ slot->metrics.horiAdvance = ( slot->metrics.horiAdvance + 32 ) & -64;
+
+ /* now copy outline into glyph slot */
+ ah_loader_rewind( slot->internal->loader );
+ error = ah_loader_copy_points( slot->internal->loader, gloader );
+ if ( error )
+ goto Exit;
+
+ slot->outline = slot->internal->loader->base.outline;
+ slot->format = FT_GLYPH_FORMAT_OUTLINE;
+ }
+
+#ifdef DEBUG_HINTER
+ ah_debug_hinter = hinter;
+#endif
+
+ Exit:
+ return error;
+ }
+
+
+ /* load and hint a given glyph */
+ FT_LOCAL_DEF( FT_Error )
+ ah_hinter_load_glyph( AH_Hinter hinter,
+ FT_GlyphSlot slot,
+ FT_Size size,
+ FT_UInt glyph_index,
+ FT_Int32 load_flags )
+ {
+ FT_Face face = slot->face;
+ FT_Error error;
+ FT_Fixed x_scale = size->metrics.x_scale;
+ FT_Fixed y_scale = size->metrics.y_scale;
+ AH_Face_Globals face_globals = FACE_GLOBALS( face );
+ FT_Render_Mode hint_mode = FT_LOAD_TARGET_MODE(load_flags);
+
+
+ /* first of all, we need to check that we're using the correct face and */
+ /* global hints to load the glyph */
+ if ( hinter->face != face || hinter->globals != face_globals )
+ {
+ hinter->face = face;
+ if ( !face_globals )
+ {
+ error = ah_hinter_new_face_globals( hinter, face, 0 );
+ if ( error )
+ goto Exit;
+
+ }
+ hinter->globals = FACE_GLOBALS( face );
+ face_globals = FACE_GLOBALS( face );
+
+ }
+
+ /* now, we must check the current character pixel size to see if we */
+ /* need to rescale the global metrics */
+ if ( face_globals->x_scale != x_scale ||
+ face_globals->y_scale != y_scale )
+ ah_hinter_scale_globals( hinter, x_scale, y_scale );
+
+ ah_loader_rewind( hinter->loader );
+
+ /* reset hinting flags according to load flags and current render target */
+ hinter->do_horz_hints = !FT_BOOL( load_flags & FT_LOAD_NO_AUTOHINT );
+ hinter->do_vert_hints = !FT_BOOL( load_flags & FT_LOAD_NO_AUTOHINT );
+
+#ifdef DEBUG_HINTER
+ hinter->do_horz_hints = !ah_debug_disable_vert; /* not a bug, the meaning */
+ hinter->do_vert_hints = !ah_debug_disable_horz; /* of h/v is inverted! */
+#endif
+
+ /* we snap the width of vertical stems for the monochrome and */
+ /* horizontal LCD rendering targets only. Corresponds to X snapping. */
+ hinter->do_horz_snapping = FT_BOOL( hint_mode == FT_RENDER_MODE_MONO ||
+ hint_mode == FT_RENDER_MODE_LCD );
+
+ /* we snap the width of horizontal stems for the monochrome and */
+ /* vertical LCD rendering targets only. Corresponds to Y snapping. */
+ hinter->do_vert_snapping = FT_BOOL( hint_mode == FT_RENDER_MODE_MONO ||
+ hint_mode == FT_RENDER_MODE_LCD_V );
+
+#if 1
+ load_flags = FT_LOAD_NO_SCALE
+ | FT_LOAD_IGNORE_TRANSFORM ;
+#else
+ load_flags |= FT_LOAD_NO_SCALE | FT_LOAD_NO_RECURSE;
+#endif
+
+ error = ah_hinter_load( hinter, glyph_index, load_flags, 0 );
+
+ Exit:
+ return error;
+ }
+
+
+ /* retrieve a face's autohint globals for client applications */
+ FT_LOCAL_DEF( void )
+ ah_hinter_get_global_hints( AH_Hinter hinter,
+ FT_Face face,
+ void** global_hints,
+ long* global_len )
+ {
+ AH_Globals globals = 0;
+ FT_Memory memory = hinter->memory;
+ FT_Error error;
+
+
+ /* allocate new master globals */
+ if ( FT_NEW( globals ) )
+ goto Fail;
+
+ /* compute face globals if needed */
+ if ( !FACE_GLOBALS( face ) )
+ {
+ error = ah_hinter_new_face_globals( hinter, face, 0 );
+ if ( error )
+ goto Fail;
+ }
+
+ *globals = FACE_GLOBALS( face )->design;
+ *global_hints = globals;
+ *global_len = sizeof( *globals );
+
+ return;
+
+ Fail:
+ FT_FREE( globals );
+
+ *global_hints = 0;
+ *global_len = 0;
+ }
+
+
+ FT_LOCAL_DEF( void )
+ ah_hinter_done_global_hints( AH_Hinter hinter,
+ void* global_hints )
+ {
+ FT_Memory memory = hinter->memory;
+
+
+ FT_FREE( global_hints );
+ }
+
+
+/* END */
--- /dev/null
+++ b/libfreetype/ahhint.h
@@ -1,0 +1,75 @@
+/***************************************************************************/
+/* */
+/* ahhint.h */
+/* */
+/* Glyph hinter (declaration). */
+/* */
+/* Copyright 2000-2001, 2002 Catharon Productions Inc. */
+/* Author: David Turner */
+/* */
+/* This file is part of the Catharon Typography Project and shall only */
+/* be used, modified, and distributed under the terms of the Catharon */
+/* Open Source License that should come with this file under the name */
+/* `CatharonLicense.txt'. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/* Note that this license is compatible with the FreeType license. */
+/* */
+/***************************************************************************/
+
+
+#ifndef __AHHINT_H__
+#define __AHHINT_H__
+
+
+#include <ft2build.h>
+#include "ahglobal.h"
+
+
+FT_BEGIN_HEADER
+
+
+#define AH_HINT_DEFAULT 0
+#define AH_HINT_NO_ALIGNMENT 1
+#define AH_HINT_NO_HORZ_EDGES 0x200000L /* temporary hack */
+#define AH_HINT_NO_VERT_EDGES 0x400000L /* temporary hack */
+
+
+ /* create a new empty hinter object */
+ FT_LOCAL( FT_Error )
+ ah_hinter_new( FT_Library library,
+ AH_Hinter* ahinter );
+
+ /* Load a hinted glyph in the hinter */
+ FT_LOCAL( FT_Error )
+ ah_hinter_load_glyph( AH_Hinter hinter,
+ FT_GlyphSlot slot,
+ FT_Size size,
+ FT_UInt glyph_index,
+ FT_Int32 load_flags );
+
+ /* finalize a hinter object */
+ FT_LOCAL( void )
+ ah_hinter_done( AH_Hinter hinter );
+
+ FT_LOCAL( void )
+ ah_hinter_done_face_globals( AH_Face_Globals globals );
+
+ FT_LOCAL( void )
+ ah_hinter_get_global_hints( AH_Hinter hinter,
+ FT_Face face,
+ void** global_hints,
+ long* global_len );
+
+ FT_LOCAL( void )
+ ah_hinter_done_global_hints( AH_Hinter hinter,
+ void* global_hints );
+
+
+FT_END_HEADER
+
+#endif /* __AHHINT_H__ */
+
+
+/* END */
--- /dev/null
+++ b/libfreetype/ahloader.h
@@ -1,0 +1,61 @@
+/***************************************************************************/
+/* */
+/* ahloader.h */
+/* */
+/* Glyph loader for the auto-hinting module (declaration only). */
+/* */
+/* Copyright 2000-2001, 2002 Catharon Productions Inc. */
+/* Author: David Turner */
+/* */
+/* This file is part of the Catharon Typography Project and shall only */
+/* be used, modified, and distributed under the terms of the Catharon */
+/* Open Source License that should come with this file under the name */
+/* `CatharonLicense.txt'. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/* Note that this license is compatible with the FreeType license. */
+/* */
+/***************************************************************************/
+
+
+ /*************************************************************************/
+ /* */
+ /* This defines the AH_GlyphLoader type; it is simply a typedef to */
+ /* FT_GlyphLoader. */
+ /* */
+ /*************************************************************************/
+
+
+#ifndef __AHLOADER_H__
+#define __AHLOADER_H__
+
+
+#include <ft2build.h>
+
+
+FT_BEGIN_HEADER
+
+#include FT_INTERNAL_GLYPH_LOADER_H
+
+ #define AH_Load FT_GlyphLoad
+ #define AH_Loader FT_GlyphLoader
+
+ #define ah_loader_new FT_GlyphLoader_New
+ #define ah_loader_done FT_GlyphLoader_Done
+ #define ah_loader_reset FT_GlyphLoader_Reset
+ #define ah_loader_rewind FT_GlyphLoader_Rewind
+ #define ah_loader_create_extra FT_GlyphLoader_CreateExtra
+ #define ah_loader_check_points FT_GlyphLoader_CheckPoints
+ #define ah_loader_check_subglyphs FT_GlyphLoader_CheckSubGlyphs
+ #define ah_loader_prepare FT_GlyphLoader_Prepare
+ #define ah_loader_add FT_GlyphLoader_Add
+ #define ah_loader_copy_points FT_GlyphLoader_CopyPoints
+
+
+FT_END_HEADER
+
+#endif /* __AHLOADER_H__ */
+
+
+/* END */
--- /dev/null
+++ b/libfreetype/ahmodule.c
@@ -1,0 +1,137 @@
+/***************************************************************************/
+/* */
+/* ahmodule.c */
+/* */
+/* Auto-hinting module implementation (declaration). */
+/* */
+/* Copyright 2000-2001, 2002 Catharon Productions Inc. */
+/* Author: David Turner */
+/* */
+/* This file is part of the Catharon Typography Project and shall only */
+/* be used, modified, and distributed under the terms of the Catharon */
+/* Open Source License that should come with this file under the name */
+/* `CatharonLicense.txt'. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/* Note that this license is compatible with the FreeType license. */
+/* */
+/***************************************************************************/
+
+
+#include <ft2build.h>
+#include FT_MODULE_H
+#include "ahhint.h"
+
+
+#ifdef DEBUG_HINTER
+ AH_Hinter ah_debug_hinter = NULL;
+ FT_Bool ah_debug_disable_horz = 0;
+ FT_Bool ah_debug_disable_vert = 0;
+#endif
+
+ typedef struct FT_AutoHinterRec_
+ {
+ FT_ModuleRec root;
+ AH_Hinter hinter;
+
+ } FT_AutoHinterRec;
+
+
+ FT_CALLBACK_DEF( FT_Error )
+ ft_autohinter_init( FT_AutoHinter module )
+ {
+ FT_Error error;
+
+
+ error = ah_hinter_new( module->root.library, &module->hinter );
+#ifdef DEBUG_HINTER
+ if ( !error )
+ ah_debug_hinter = module->hinter;
+#endif
+ return error;
+ }
+
+
+ FT_CALLBACK_DEF( void )
+ ft_autohinter_done( FT_AutoHinter module )
+ {
+ ah_hinter_done( module->hinter );
+
+#ifdef DEBUG_HINTER
+ ah_debug_hinter = NULL;
+#endif
+ }
+
+
+ FT_CALLBACK_DEF( FT_Error )
+ ft_autohinter_load_glyph( FT_AutoHinter module,
+ FT_GlyphSlot slot,
+ FT_Size size,
+ FT_UInt glyph_index,
+ FT_Int32 load_flags )
+ {
+ return ah_hinter_load_glyph( module->hinter,
+ slot, size, glyph_index, load_flags );
+ }
+
+
+ FT_CALLBACK_DEF( void )
+ ft_autohinter_reset_globals( FT_AutoHinter module,
+ FT_Face face )
+ {
+ FT_UNUSED( module );
+
+ if ( face->autohint.data )
+ ah_hinter_done_face_globals( (AH_Face_Globals)(face->autohint.data) );
+ }
+
+
+ FT_CALLBACK_DEF( void )
+ ft_autohinter_get_globals( FT_AutoHinter module,
+ FT_Face face,
+ void** global_hints,
+ long* global_len )
+ {
+ ah_hinter_get_global_hints( module->hinter, face,
+ global_hints, global_len );
+ }
+
+
+ FT_CALLBACK_DEF( void )
+ ft_autohinter_done_globals( FT_AutoHinter module,
+ void* global_hints )
+ {
+ ah_hinter_done_global_hints( module->hinter, global_hints );
+ }
+
+
+ FT_CALLBACK_TABLE_DEF
+ const FT_AutoHinter_ServiceRec ft_autohinter_service =
+ {
+ ft_autohinter_reset_globals,
+ ft_autohinter_get_globals,
+ ft_autohinter_done_globals,
+ ft_autohinter_load_glyph
+ };
+
+
+ FT_CALLBACK_TABLE_DEF
+ const FT_Module_Class autohint_module_class =
+ {
+ ft_module_hinter,
+ sizeof ( FT_AutoHinterRec ),
+
+ "autohinter",
+ 0x10000L, /* version 1.0 of the autohinter */
+ 0x20000L, /* requires FreeType 2.0 or above */
+
+ (const void*) &ft_autohinter_service,
+
+ (FT_Module_Constructor)ft_autohinter_init,
+ (FT_Module_Destructor) ft_autohinter_done,
+ (FT_Module_Requester) 0
+ };
+
+
+/* END */
--- /dev/null
+++ b/libfreetype/ahmodule.h
@@ -1,0 +1,42 @@
+/***************************************************************************/
+/* */
+/* ahmodule.h */
+/* */
+/* Auto-hinting module (declaration). */
+/* */
+/* Copyright 2000-2001 Catharon Productions Inc. */
+/* Author: David Turner */
+/* */
+/* This file is part of the Catharon Typography Project and shall only */
+/* be used, modified, and distributed under the terms of the Catharon */
+/* Open Source License that should come with this file under the name */
+/* `CatharonLicense.txt'. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/* Note that this license is compatible with the FreeType license. */
+/* */
+/***************************************************************************/
+
+
+#ifndef __AHMODULE_H__
+#define __AHMODULE_H__
+
+
+#include <ft2build.h>
+#include FT_MODULE_H
+
+
+FT_BEGIN_HEADER
+
+
+ FT_CALLBACK_TABLE
+ const FT_Module_Class autohint_module_class;
+
+
+FT_END_HEADER
+
+#endif /* __AHMODULE_H__ */
+
+
+/* END */
--- /dev/null
+++ b/libfreetype/ahoptim.c
@@ -1,0 +1,882 @@
+/***************************************************************************/
+/* */
+/* ahoptim.c */
+/* */
+/* FreeType auto hinting outline optimization (body). */
+/* */
+/* Copyright 2000-2001, 2002 Catharon Productions Inc. */
+/* Author: David Turner */
+/* */
+/* This file is part of the Catharon Typography Project and shall only */
+/* be used, modified, and distributed under the terms of the Catharon */
+/* Open Source License that should come with this file under the name */
+/* `CatharonLicense.txt'. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/* Note that this license is compatible with the FreeType license. */
+/* */
+/***************************************************************************/
+
+
+ /*************************************************************************/
+ /* */
+ /* This module is in charge of optimising the outlines produced by the */
+ /* auto-hinter in direct mode. This is required at small pixel sizes in */
+ /* order to ensure coherent spacing, among other things.. */
+ /* */
+ /* The technique used in this module is a simplified simulated */
+ /* annealing. */
+ /* */
+ /*************************************************************************/
+
+
+#include <ft2build.h>
+#include FT_INTERNAL_OBJECTS_H /* for FT_ALLOC_ARRAY() and FT_FREE() */
+#include "ahoptim.h"
+
+
+ /* define this macro to use brute force optimization -- this is slow, */
+ /* but a good way to perfect the distortion function `by hand' through */
+ /* tweaking */
+#define AH_BRUTE_FORCE
+
+
+#define xxxAH_DEBUG_OPTIM
+
+
+#undef LOG
+#ifdef AH_DEBUG_OPTIM
+
+#define LOG( x ) optim_log ## x
+
+#else
+
+#define LOG( x )
+
+#endif /* AH_DEBUG_OPTIM */
+
+
+#ifdef AH_DEBUG_OPTIM
+
+#include <stdarg.h>
+#include <stdlib.h>
+
+#define FLOAT( x ) ( (float)( (x) / 64.0 ) )
+
+
+ static void
+ optim_log( const char* fmt, ... )
+ {
+ va_list ap;
+
+
+ va_start( ap, fmt );
+ vprintf( fmt, ap );
+ va_end( ap );
+ }
+
+
+ static void
+ AH_Dump_Stems( AH_Optimizer* optimizer )
+ {
+ int n;
+ AH_Stem* stem;
+
+
+ stem = optimizer->stems;
+ for ( n = 0; n < optimizer->num_stems; n++, stem++ )
+ {
+ LOG(( " %c%2d [%.1f:%.1f]={%.1f:%.1f}="
+ "<%1.f..%1.f> force=%.1f speed=%.1f\n",
+ optimizer->vertical ? 'V' : 'H', n,
+ FLOAT( stem->edge1->opos ), FLOAT( stem->edge2->opos ),
+ FLOAT( stem->edge1->pos ), FLOAT( stem->edge2->pos ),
+ FLOAT( stem->min_pos ), FLOAT( stem->max_pos ),
+ FLOAT( stem->force ), FLOAT( stem->velocity ) ));
+ }
+ }
+
+
+ static void
+ AH_Dump_Stems2( AH_Optimizer* optimizer )
+ {
+ int n;
+ AH_Stem* stem;
+
+
+ stem = optimizer->stems;
+ for ( n = 0; n < optimizer->num_stems; n++, stem++ )
+ {
+ LOG(( " %c%2d [%.1f]=<%1.f..%1.f> force=%.1f speed=%.1f\n",
+ optimizer->vertical ? 'V' : 'H', n,
+ FLOAT( stem->pos ),
+ FLOAT( stem->min_pos ), FLOAT( stem->max_pos ),
+ FLOAT( stem->force ), FLOAT( stem->velocity ) ));
+ }
+ }
+
+
+ static void
+ AH_Dump_Springs( AH_Optimizer* optimizer )
+ {
+ int n;
+ AH_Spring* spring;
+ AH_Stem* stems;
+
+
+ spring = optimizer->springs;
+ stems = optimizer->stems;
+ LOG(( "%cSprings ", optimizer->vertical ? 'V' : 'H' ));
+
+ for ( n = 0; n < optimizer->num_springs; n++, spring++ )
+ {
+ LOG(( " [%d-%d:%.1f:%1.f:%.1f]",
+ spring->stem1 - stems, spring->stem2 - stems,
+ FLOAT( spring->owidth ),
+ FLOAT( spring->stem2->pos -
+ ( spring->stem1->pos + spring->stem1->width ) ),
+ FLOAT( spring->tension ) ));
+ }
+
+ LOG(( "\n" ));
+ }
+
+#endif /* AH_DEBUG_OPTIM */
+
+
+ /*************************************************************************/
+ /*************************************************************************/
+ /*************************************************************************/
+ /**** ****/
+ /**** COMPUTE STEMS AND SPRINGS IN AN OUTLINE ****/
+ /**** ****/
+ /*************************************************************************/
+ /*************************************************************************/
+ /*************************************************************************/
+
+
+ static int
+ valid_stem_segments( AH_Segment seg1,
+ AH_Segment seg2 )
+ {
+ return seg1->serif == 0 &&
+ seg2 &&
+ seg2->link == seg1 &&
+ seg1->pos < seg2->pos &&
+ seg1->min_coord <= seg2->max_coord &&
+ seg2->min_coord <= seg1->max_coord;
+ }
+
+
+ /* compute all stems in an outline */
+ static int
+ optim_compute_stems( AH_Optimizer* optimizer )
+ {
+ AH_Outline outline = optimizer->outline;
+ FT_Fixed scale;
+ FT_Memory memory = optimizer->memory;
+ FT_Error error = 0;
+ FT_Int dimension;
+ AH_Edge edges;
+ AH_Edge edge_limit;
+ AH_Stem** p_stems;
+ FT_Int* p_num_stems;
+
+
+ edges = outline->horz_edges;
+ edge_limit = edges + outline->num_hedges;
+ scale = outline->y_scale;
+
+ p_stems = &optimizer->horz_stems;
+ p_num_stems = &optimizer->num_hstems;
+
+ for ( dimension = 1; dimension >= 0; dimension-- )
+ {
+ AH_Stem* stems = 0;
+ FT_Int num_stems = 0;
+ AH_Edge edge;
+
+
+ /* first of all, count the number of stems in this direction */
+ for ( edge = edges; edge < edge_limit; edge++ )
+ {
+ AH_Segment seg = edge->first;
+
+
+ do
+ {
+ if (valid_stem_segments( seg, seg->link ) )
+ num_stems++;
+
+ seg = seg->edge_next;
+
+ } while ( seg != edge->first );
+ }
+
+ /* now allocate the stems and build their table */
+ if ( num_stems > 0 )
+ {
+ AH_Stem* stem;
+
+
+ if ( FT_NEW_ARRAY( stems, num_stems ) )
+ goto Exit;
+
+ stem = stems;
+ for ( edge = edges; edge < edge_limit; edge++ )
+ {
+ AH_Segment seg = edge->first;
+ AH_Segment seg2;
+
+
+ do
+ {
+ seg2 = seg->link;
+ if ( valid_stem_segments( seg, seg2 ) )
+ {
+ AH_Edge edge1 = seg->edge;
+ AH_Edge edge2 = seg2->edge;
+
+
+ stem->edge1 = edge1;
+ stem->edge2 = edge2;
+ stem->opos = edge1->opos;
+ stem->pos = edge1->pos;
+ stem->owidth = edge2->opos - edge1->opos;
+ stem->width = edge2->pos - edge1->pos;
+
+ /* compute min_coord and max_coord */
+ {
+ FT_Pos min_coord = seg->min_coord;
+ FT_Pos max_coord = seg->max_coord;
+
+
+ if ( seg2->min_coord > min_coord )
+ min_coord = seg2->min_coord;
+
+ if ( seg2->max_coord < max_coord )
+ max_coord = seg2->max_coord;
+
+ stem->min_coord = min_coord;
+ stem->max_coord = max_coord;
+ }
+
+ /* compute minimum and maximum positions for stem -- */
+ /* note that the left-most/bottom-most stem has always */
+ /* a fixed position */
+ if ( stem == stems || edge1->blue_edge || edge2->blue_edge )
+ {
+ /* this stem cannot move; it is snapped to a blue edge */
+ stem->min_pos = stem->pos;
+ stem->max_pos = stem->pos;
+ }
+ else
+ {
+ /* this edge can move; compute its min and max positions */
+ FT_Pos pos1 = stem->opos;
+ FT_Pos pos2 = pos1 + stem->owidth - stem->width;
+ FT_Pos min1 = pos1 & -64;
+ FT_Pos min2 = pos2 & -64;
+
+
+ stem->min_pos = min1;
+ stem->max_pos = min1 + 64;
+ if ( min2 < min1 )
+ stem->min_pos = min2;
+ else
+ stem->max_pos = min2 + 64;
+
+ /* XXX: just to see what it does */
+ stem->max_pos += 64;
+
+ /* just for the case where direct hinting did some */
+ /* incredible things (e.g. blue edge shifts) */
+ if ( stem->min_pos > stem->pos )
+ stem->min_pos = stem->pos;
+
+ if ( stem->max_pos < stem->pos )
+ stem->max_pos = stem->pos;
+ }
+
+ stem->velocity = 0;
+ stem->force = 0;
+
+ stem++;
+ }
+ seg = seg->edge_next;
+
+ } while ( seg != edge->first );
+ }
+ }
+
+ *p_stems = stems;
+ *p_num_stems = num_stems;
+
+ edges = outline->vert_edges;
+ edge_limit = edges + outline->num_vedges;
+ scale = outline->x_scale;
+
+ p_stems = &optimizer->vert_stems;
+ p_num_stems = &optimizer->num_vstems;
+ }
+
+ Exit:
+
+#ifdef AH_DEBUG_OPTIM
+ AH_Dump_Stems( optimizer );
+#endif
+
+ return error;
+ }
+
+
+ /* returns the spring area between two stems, 0 if none */
+ static FT_Pos
+ stem_spring_area( AH_Stem* stem1,
+ AH_Stem* stem2 )
+ {
+ FT_Pos area1 = stem1->max_coord - stem1->min_coord;
+ FT_Pos area2 = stem2->max_coord - stem2->min_coord;
+ FT_Pos min = stem1->min_coord;
+ FT_Pos max = stem1->max_coord;
+ FT_Pos area;
+
+
+ /* order stems */
+ if ( stem2->opos <= stem1->opos + stem1->owidth )
+ return 0;
+
+ if ( min < stem2->min_coord )
+ min = stem2->min_coord;
+
+ if ( max < stem2->max_coord )
+ max = stem2->max_coord;
+
+ area = ( max-min );
+ if ( 2 * area < area1 && 2 * area < area2 )
+ area = 0;
+
+ return area;
+ }
+
+
+ /* compute all springs in an outline */
+ static int
+ optim_compute_springs( AH_Optimizer* optimizer )
+ {
+ /* basically, a spring exists between two stems if most of their */
+ /* surface is aligned */
+ FT_Memory memory = optimizer->memory;
+
+ AH_Stem* stems;
+ AH_Stem* stem_limit;
+ AH_Stem* stem;
+ int dimension;
+ int error = 0;
+
+ FT_Int* p_num_springs;
+ AH_Spring** p_springs;
+
+
+ stems = optimizer->horz_stems;
+ stem_limit = stems + optimizer->num_hstems;
+
+ p_springs = &optimizer->horz_springs;
+ p_num_springs = &optimizer->num_hsprings;
+
+ for ( dimension = 1; dimension >= 0; dimension-- )
+ {
+ FT_Int num_springs = 0;
+ AH_Spring* springs = 0;
+
+
+ /* first of all, count stem springs */
+ for ( stem = stems; stem + 1 < stem_limit; stem++ )
+ {
+ AH_Stem* stem2;
+
+
+ for ( stem2 = stem+1; stem2 < stem_limit; stem2++ )
+ if ( stem_spring_area( stem, stem2 ) )
+ num_springs++;
+ }
+
+ /* then allocate and build the springs table */
+ if ( num_springs > 0 )
+ {
+ AH_Spring* spring;
+
+
+ /* allocate table of springs */
+ if ( FT_NEW_ARRAY( springs, num_springs ) )
+ goto Exit;
+
+ /* fill the springs table */
+ spring = springs;
+ for ( stem = stems; stem+1 < stem_limit; stem++ )
+ {
+ AH_Stem* stem2;
+ FT_Pos area;
+
+
+ for ( stem2 = stem + 1; stem2 < stem_limit; stem2++ )
+ {
+ area = stem_spring_area( stem, stem2 );
+ if ( area )
+ {
+ /* add a new spring here */
+ spring->stem1 = stem;
+ spring->stem2 = stem2;
+ spring->owidth = stem2->opos - ( stem->opos + stem->owidth );
+ spring->tension = 0;
+
+ spring++;
+ }
+ }
+ }
+ }
+ *p_num_springs = num_springs;
+ *p_springs = springs;
+
+ stems = optimizer->vert_stems;
+ stem_limit = stems + optimizer->num_vstems;
+
+ p_springs = &optimizer->vert_springs;
+ p_num_springs = &optimizer->num_vsprings;
+ }
+
+ Exit:
+
+#ifdef AH_DEBUG_OPTIM
+ AH_Dump_Springs( optimizer );
+#endif
+
+ return error;
+ }
+
+
+ /*************************************************************************/
+ /*************************************************************************/
+ /*************************************************************************/
+ /**** ****/
+ /**** OPTIMIZE THROUGH MY STRANGE SIMULATED ANNEALING ALGO ;-) ****/
+ /**** ****/
+ /*************************************************************************/
+ /*************************************************************************/
+ /*************************************************************************/
+
+#ifndef AH_BRUTE_FORCE
+
+ /* compute all spring tensions */
+ static void
+ optim_compute_tensions( AH_Optimizer* optimizer )
+ {
+ AH_Spring* spring = optimizer->springs;
+ AH_Spring* limit = spring + optimizer->num_springs;
+
+
+ for ( ; spring < limit; spring++ )
+ {
+ AH_Stem* stem1 = spring->stem1;
+ AH_Stem* stem2 = spring->stem2;
+ FT_Int status;
+
+ FT_Pos width;
+ FT_Pos tension;
+ FT_Pos sign;
+
+
+ /* compute the tension; it simply is -K*(new_width-old_width) */
+ width = stem2->pos - ( stem1->pos + stem1->width );
+ tension = width - spring->owidth;
+
+ sign = 1;
+ if ( tension < 0 )
+ {
+ sign = -1;
+ tension = -tension;
+ }
+
+ if ( width <= 0 )
+ tension = 32000;
+ else
+ tension = ( tension << 10 ) / width;
+
+ tension = -sign * FT_MulFix( tension, optimizer->tension_scale );
+ spring->tension = tension;
+
+ /* now, distribute tension among the englobing stems, if they */
+ /* are able to move */
+ status = 0;
+ if ( stem1->pos <= stem1->min_pos )
+ status |= 1;
+ if ( stem2->pos >= stem2->max_pos )
+ status |= 2;
+
+ if ( !status )
+ tension /= 2;
+
+ if ( ( status & 1 ) == 0 )
+ stem1->force -= tension;
+
+ if ( ( status & 2 ) == 0 )
+ stem2->force += tension;
+ }
+ }
+
+
+ /* compute all stem movements -- returns 0 if nothing moved */
+ static int
+ optim_compute_stem_movements( AH_Optimizer* optimizer )
+ {
+ AH_Stem* stems = optimizer->stems;
+ AH_Stem* limit = stems + optimizer->num_stems;
+ AH_Stem* stem = stems;
+ int moved = 0;
+
+
+ /* set initial forces to velocity */
+ for ( stem = stems; stem < limit; stem++ )
+ {
+ stem->force = stem->velocity;
+ stem->velocity /= 2; /* XXX: Heuristics */
+ }
+
+ /* compute the sum of forces applied on each stem */
+ optim_compute_tensions( optimizer );
+
+#ifdef AH_DEBUG_OPTIM
+ AH_Dump_Springs( optimizer );
+ AH_Dump_Stems2( optimizer );
+#endif
+
+ /* now, see whether something can move */
+ for ( stem = stems; stem < limit; stem++ )
+ {
+ if ( stem->force > optimizer->tension_threshold )
+ {
+ /* there is enough tension to move the stem to the right */
+ if ( stem->pos < stem->max_pos )
+ {
+ stem->pos += 64;
+ stem->velocity = stem->force / 2;
+ moved = 1;
+ }
+ else
+ stem->velocity = 0;
+ }
+ else if ( stem->force < optimizer->tension_threshold )
+ {
+ /* there is enough tension to move the stem to the left */
+ if ( stem->pos > stem->min_pos )
+ {
+ stem->pos -= 64;
+ stem->velocity = stem->force / 2;
+ moved = 1;
+ }
+ else
+ stem->velocity = 0;
+ }
+ }
+
+ /* return 0 if nothing moved */
+ return moved;
+ }
+
+#endif /* AH_BRUTE_FORCE */
+
+
+ /* compute current global distortion from springs */
+ static FT_Pos
+ optim_compute_distortion( AH_Optimizer* optimizer )
+ {
+ AH_Spring* spring = optimizer->springs;
+ AH_Spring* limit = spring + optimizer->num_springs;
+ FT_Pos distortion = 0;
+
+
+ for ( ; spring < limit; spring++ )
+ {
+ AH_Stem* stem1 = spring->stem1;
+ AH_Stem* stem2 = spring->stem2;
+ FT_Pos width;
+
+ width = stem2->pos - ( stem1->pos + stem1->width );
+ width -= spring->owidth;
+ if ( width < 0 )
+ width = -width;
+
+ distortion += width;
+ }
+
+ return distortion;
+ }
+
+
+ /* record stems configuration in `best of' history */
+ static void
+ optim_record_configuration( AH_Optimizer* optimizer )
+ {
+ FT_Pos distortion;
+ AH_Configuration* configs = optimizer->configs;
+ AH_Configuration* limit = configs + optimizer->num_configs;
+ AH_Configuration* config;
+
+
+ distortion = optim_compute_distortion( optimizer );
+ LOG(( "config distortion = %.1f ", FLOAT( distortion * 64 ) ));
+
+ /* check that we really need to add this configuration to our */
+ /* sorted history */
+ if ( limit > configs && limit[-1].distortion < distortion )
+ {
+ LOG(( "ejected\n" ));
+ return;
+ }
+
+ /* add new configuration at the end of the table */
+ {
+ int n;
+
+
+ config = limit;
+ if ( optimizer->num_configs < AH_MAX_CONFIGS )
+ optimizer->num_configs++;
+ else
+ config--;
+
+ config->distortion = distortion;
+
+ for ( n = 0; n < optimizer->num_stems; n++ )
+ config->positions[n] = optimizer->stems[n].pos;
+ }
+
+ /* move the current configuration towards the front of the list */
+ /* when necessary -- yes this is slow bubble sort ;-) */
+ while ( config > configs && config[0].distortion < config[-1].distortion )
+ {
+ AH_Configuration temp;
+
+
+ config--;
+ temp = config[0];
+ config[0] = config[1];
+ config[1] = temp;
+ }
+ LOG(( "recorded!\n" ));
+ }
+
+
+#ifdef AH_BRUTE_FORCE
+
+ /* optimize outline in a single direction */
+ static void
+ optim_compute( AH_Optimizer* optimizer )
+ {
+ int n;
+ FT_Bool moved;
+
+ AH_Stem* stem = optimizer->stems;
+ AH_Stem* limit = stem + optimizer->num_stems;
+
+
+ /* empty, exit */
+ if ( stem >= limit )
+ return;
+
+ optimizer->num_configs = 0;
+
+ stem = optimizer->stems;
+ for ( ; stem < limit; stem++ )
+ stem->pos = stem->min_pos;
+
+ do
+ {
+ /* record current configuration */
+ optim_record_configuration( optimizer );
+
+ /* now change configuration */
+ moved = 0;
+ for ( stem = optimizer->stems; stem < limit; stem++ )
+ {
+ if ( stem->pos < stem->max_pos )
+ {
+ stem->pos += 64;
+ moved = 1;
+ break;
+ }
+
+ stem->pos = stem->min_pos;
+ }
+ } while ( moved );
+
+ /* now, set the best stem positions */
+ for ( n = 0; n < optimizer->num_stems; n++ )
+ {
+ AH_Stem* stem = optimizer->stems + n;
+ FT_Pos pos = optimizer->configs[0].positions[n];
+
+
+ stem->edge1->pos = pos;
+ stem->edge2->pos = pos + stem->width;
+
+ stem->edge1->flags |= AH_EDGE_DONE;
+ stem->edge2->flags |= AH_EDGE_DONE;
+ }
+ }
+
+#else /* AH_BRUTE_FORCE */
+
+ /* optimize outline in a single direction */
+ static void
+ optim_compute( AH_Optimizer* optimizer )
+ {
+ int n, counter, counter2;
+
+
+ optimizer->num_configs = 0;
+ optimizer->tension_scale = 0x80000L;
+ optimizer->tension_threshold = 64;
+
+ /* record initial configuration threshold */
+ optim_record_configuration( optimizer );
+
+ counter = 0;
+ for ( counter2 = optimizer->num_stems*8; counter2 >= 0; counter2-- )
+ {
+ if ( counter == 0 )
+ counter = 2 * optimizer->num_stems;
+
+ if ( !optim_compute_stem_movements( optimizer ) )
+ break;
+
+ optim_record_configuration( optimizer );
+
+ counter--;
+ if ( counter == 0 )
+ optimizer->tension_scale /= 2;
+ }
+
+ /* now, set the best stem positions */
+ for ( n = 0; n < optimizer->num_stems; n++ )
+ {
+ AH_Stem* stem = optimizer->stems + n;
+ FT_Pos pos = optimizer->configs[0].positions[n];
+
+
+ stem->edge1->pos = pos;
+ stem->edge2->pos = pos + stem->width;
+
+ stem->edge1->flags |= AH_EDGE_DONE;
+ stem->edge2->flags |= AH_EDGE_DONE;
+ }
+ }
+
+#endif /* AH_BRUTE_FORCE */
+
+
+ /*************************************************************************/
+ /*************************************************************************/
+ /*************************************************************************/
+ /**** ****/
+ /**** HIGH-LEVEL OPTIMIZER API ****/
+ /**** ****/
+ /*************************************************************************/
+ /*************************************************************************/
+ /*************************************************************************/
+
+
+ /* releases the optimization data */
+ void
+ AH_Optimizer_Done( AH_Optimizer* optimizer )
+ {
+ if ( optimizer )
+ {
+ FT_Memory memory = optimizer->memory;
+
+
+ FT_FREE( optimizer->horz_stems );
+ FT_FREE( optimizer->vert_stems );
+ FT_FREE( optimizer->horz_springs );
+ FT_FREE( optimizer->vert_springs );
+ FT_FREE( optimizer->positions );
+ }
+ }
+
+
+ /* loads the outline into the optimizer */
+ int
+ AH_Optimizer_Init( AH_Optimizer* optimizer,
+ AH_Outline outline,
+ FT_Memory memory )
+ {
+ FT_Error error;
+
+
+ FT_MEM_ZERO( optimizer, sizeof ( *optimizer ) );
+ optimizer->outline = outline;
+ optimizer->memory = memory;
+
+ LOG(( "initializing new optimizer\n" ));
+ /* compute stems and springs */
+ error = optim_compute_stems ( optimizer ) ||
+ optim_compute_springs( optimizer );
+ if ( error )
+ goto Fail;
+
+ /* allocate stem positions history and configurations */
+ {
+ int n, max_stems;
+
+
+ max_stems = optimizer->num_hstems;
+ if ( max_stems < optimizer->num_vstems )
+ max_stems = optimizer->num_vstems;
+
+ if ( FT_NEW_ARRAY( optimizer->positions, max_stems * AH_MAX_CONFIGS ) )
+ goto Fail;
+
+ optimizer->num_configs = 0;
+ for ( n = 0; n < AH_MAX_CONFIGS; n++ )
+ optimizer->configs[n].positions = optimizer->positions +
+ n * max_stems;
+ }
+
+ return error;
+
+ Fail:
+ AH_Optimizer_Done( optimizer );
+ return error;
+ }
+
+
+ /* compute optimal outline */
+ void
+ AH_Optimizer_Compute( AH_Optimizer* optimizer )
+ {
+ optimizer->num_stems = optimizer->num_hstems;
+ optimizer->stems = optimizer->horz_stems;
+ optimizer->num_springs = optimizer->num_hsprings;
+ optimizer->springs = optimizer->horz_springs;
+
+ if ( optimizer->num_springs > 0 )
+ {
+ LOG(( "horizontal optimization ------------------------\n" ));
+ optim_compute( optimizer );
+ }
+
+ optimizer->num_stems = optimizer->num_vstems;
+ optimizer->stems = optimizer->vert_stems;
+ optimizer->num_springs = optimizer->num_vsprings;
+ optimizer->springs = optimizer->vert_springs;
+
+ if ( optimizer->num_springs )
+ {
+ LOG(( "vertical optimization --------------------------\n" ));
+ optim_compute( optimizer );
+ }
+ }
+
+
+/* END */
--- /dev/null
+++ b/libfreetype/ahoptim.h
@@ -1,0 +1,137 @@
+/***************************************************************************/
+/* */
+/* ahoptim.h */
+/* */
+/* FreeType auto hinting outline optimization (declaration). */
+/* */
+/* Copyright 2000-2001 Catharon Productions Inc. */
+/* Author: David Turner */
+/* */
+/* This file is part of the Catharon Typography Project and shall only */
+/* be used, modified, and distributed under the terms of the Catharon */
+/* Open Source License that should come with this file under the name */
+/* `CatharonLicense.txt'. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/* Note that this license is compatible with the FreeType license. */
+/* */
+/***************************************************************************/
+
+
+#ifndef __AHOPTIM_H__
+#define __AHOPTIM_H__
+
+
+#include <ft2build.h>
+#include "ahtypes.h"
+
+
+FT_BEGIN_HEADER
+
+
+ /* the maximal number of stem configurations to record */
+ /* during optimization */
+#define AH_MAX_CONFIGS 8
+
+
+ typedef struct AH_Stem_
+ {
+ FT_Pos pos; /* current position */
+ FT_Pos velocity; /* current velocity */
+ FT_Pos force; /* sum of current forces */
+ FT_Pos width; /* normalized width */
+
+ FT_Pos min_pos; /* minimum grid position */
+ FT_Pos max_pos; /* maximum grid position */
+
+ AH_Edge edge1; /* left/bottom edge */
+ AH_Edge edge2; /* right/top edge */
+
+ FT_Pos opos; /* original position */
+ FT_Pos owidth; /* original width */
+
+ FT_Pos min_coord; /* minimum coordinate */
+ FT_Pos max_coord; /* maximum coordinate */
+
+ } AH_Stem;
+
+
+ /* A spring between two stems */
+ typedef struct AH_Spring_
+ {
+ AH_Stem* stem1;
+ AH_Stem* stem2;
+ FT_Pos owidth; /* original width */
+ FT_Pos tension; /* current tension */
+
+ } AH_Spring;
+
+
+ /* A configuration records the position of each stem at a given time */
+ /* as well as the associated distortion */
+ typedef struct AH_Configuration_
+ {
+ FT_Pos* positions;
+ FT_Long distortion;
+
+ } AH_Configuration;
+
+
+ typedef struct AH_Optimizer_
+ {
+ FT_Memory memory;
+ AH_Outline outline;
+
+ FT_Int num_hstems;
+ AH_Stem* horz_stems;
+
+ FT_Int num_vstems;
+ AH_Stem* vert_stems;
+
+ FT_Int num_hsprings;
+ FT_Int num_vsprings;
+ AH_Spring* horz_springs;
+ AH_Spring* vert_springs;
+
+ FT_Int num_configs;
+ AH_Configuration configs[AH_MAX_CONFIGS];
+ FT_Pos* positions;
+
+ /* during each pass, use these instead */
+ FT_Int num_stems;
+ AH_Stem* stems;
+
+ FT_Int num_springs;
+ AH_Spring* springs;
+ FT_Bool vertical;
+
+ FT_Fixed tension_scale;
+ FT_Pos tension_threshold;
+
+ } AH_Optimizer;
+
+
+ /* loads the outline into the optimizer */
+ int
+ AH_Optimizer_Init( AH_Optimizer* optimizer,
+ AH_Outline outline,
+ FT_Memory memory );
+
+
+ /* compute optimal outline */
+ void
+ AH_Optimizer_Compute( AH_Optimizer* optimizer );
+
+
+ /* release the optimization data */
+ void
+ AH_Optimizer_Done( AH_Optimizer* optimizer );
+
+
+FT_END_HEADER
+
+#endif /* __AHOPTIM_H__ */
+
+
+/* END */
--- /dev/null
+++ b/libfreetype/ahtypes.h
@@ -1,0 +1,518 @@
+/***************************************************************************/
+/* */
+/* ahtypes.h */
+/* */
+/* General types and definitions for the auto-hint module */
+/* (specification only). */
+/* */
+/* Copyright 2000-2001, 2002 Catharon Productions Inc. */
+/* Author: David Turner */
+/* */
+/* This file is part of the Catharon Typography Project and shall only */
+/* be used, modified, and distributed under the terms of the Catharon */
+/* Open Source License that should come with this file under the name */
+/* `CatharonLicense.txt'. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/* Note that this license is compatible with the FreeType license. */
+/* */
+/***************************************************************************/
+
+
+#ifndef __AHTYPES_H__
+#define __AHTYPES_H__
+
+
+#include <ft2build.h>
+#include FT_INTERNAL_OBJECTS_H
+
+#ifdef DEBUG_HINTER
+#include <../src/autohint/ahloader.h>
+#else
+#include "ahloader.h"
+#endif
+
+
+#define xxAH_DEBUG
+
+
+#ifdef AH_DEBUG
+
+#include <stdio.h>
+#define AH_LOG( x ) printf ## x
+
+#else
+
+#define AH_LOG( x ) do ; while ( 0 ) /* nothing */
+
+#endif /* AH_DEBUG */
+
+
+FT_BEGIN_HEADER
+
+
+ /*************************************************************************/
+ /*************************************************************************/
+ /*************************************************************************/
+ /**** ****/
+ /**** COMPILE-TIME BUILD OPTIONS ****/
+ /**** ****/
+ /**** Toggle these configuration macros to experiment with `features' ****/
+ /**** of the auto-hinter. ****/
+ /**** ****/
+ /*************************************************************************/
+ /*************************************************************************/
+ /*************************************************************************/
+
+
+ /*************************************************************************/
+ /* */
+ /* If this option is defined, only strong interpolation will be used to */
+ /* place the points between edges. Otherwise, `smooth' points are */
+ /* detected and later hinted through weak interpolation to correct some */
+ /* unpleasant artefacts. */
+ /* */
+#undef AH_OPTION_NO_WEAK_INTERPOLATION
+
+
+ /*************************************************************************/
+ /* */
+ /* If this option is defined, only weak interpolation will be used to */
+ /* place the points between edges. Otherwise, `strong' points are */
+ /* detected and later hinted through strong interpolation to correct */
+ /* some unpleasant artefacts. */
+ /* */
+#undef AH_OPTION_NO_STRONG_INTERPOLATION
+
+
+ /*************************************************************************/
+ /* */
+ /* Undefine this macro if you don't want to hint the metrics. There is */
+ /* no reason to do this (at least for non-CJK scripts), except for */
+ /* experimentation. */
+ /* */
+#undef AH_HINT_METRICS
+
+
+ /*************************************************************************/
+ /* */
+ /* Define this macro if you do not want to insert extra edges at a */
+ /* glyph's x and y extremum (if there isn't one already available). */
+ /* This helps to reduce a number of artefacts and allows hinting of */
+ /* metrics. */
+ /* */
+#undef AH_OPTION_NO_EXTREMUM_EDGES
+
+
+ /* don't touch for now */
+#define AH_MAX_WIDTHS 12
+#define AH_MAX_HEIGHTS 12
+
+
+ /*************************************************************************/
+ /*************************************************************************/
+ /*************************************************************************/
+ /**** ****/
+ /**** TYPE DEFINITIONS ****/
+ /**** ****/
+ /*************************************************************************/
+ /*************************************************************************/
+ /*************************************************************************/
+
+
+ /* see agangles.h */
+ typedef FT_Int AH_Angle;
+
+
+ /* hint flags */
+#define AH_FLAG_NONE 0
+
+ /* bezier control points flags */
+#define AH_FLAG_CONIC 1
+#define AH_FLAG_CUBIC 2
+#define AH_FLAG_CONTROL ( AH_FLAG_CONIC | AH_FLAG_CUBIC )
+
+ /* extrema flags */
+#define AH_FLAG_EXTREMA_X 4
+#define AH_FLAG_EXTREMA_Y 8
+
+ /* roundness */
+#define AH_FLAG_ROUND_X 16
+#define AH_FLAG_ROUND_Y 32
+
+ /* touched */
+#define AH_FLAG_TOUCH_X 64
+#define AH_FLAG_TOUCH_Y 128
+
+ /* weak interpolation */
+#define AH_FLAG_WEAK_INTERPOLATION 256
+#define AH_FLAG_INFLECTION 512
+
+ typedef FT_Int AH_Flags;
+
+
+ /* edge hint flags */
+#define AH_EDGE_NORMAL 0
+#define AH_EDGE_ROUND 1
+#define AH_EDGE_SERIF 2
+#define AH_EDGE_DONE 4
+
+ typedef FT_Int AH_Edge_Flags;
+
+
+ /* hint directions -- the values are computed so that two vectors are */
+ /* in opposite directions iff `dir1+dir2 == 0' */
+#define AH_DIR_NONE 4
+#define AH_DIR_RIGHT 1
+#define AH_DIR_LEFT -1
+#define AH_DIR_UP 2
+#define AH_DIR_DOWN -2
+
+ typedef FT_Int AH_Direction;
+
+
+ typedef struct AH_PointRec_* AH_Point;
+ typedef struct AH_SegmentRec_* AH_Segment;
+ typedef struct AH_EdgeRec_* AH_Edge;
+
+
+ /*************************************************************************/
+ /* */
+ /* <Struct> */
+ /* AH_PointRec */
+ /* */
+ /* <Description> */
+ /* A structure used to model an outline point to the AH_OutlineRec */
+ /* type. */
+ /* */
+ /* <Fields> */
+ /* flags :: The current point hint flags. */
+ /* */
+ /* ox, oy :: The current original scaled coordinates. */
+ /* */
+ /* fx, fy :: The current coordinates in font units. */
+ /* */
+ /* x, y :: The current hinted coordinates. */
+ /* */
+ /* u, v :: Point coordinates -- meaning varies with context. */
+ /* */
+ /* in_dir :: The direction of the inwards vector (prev->point). */
+ /* */
+ /* out_dir :: The direction of the outwards vector (point->next). */
+ /* */
+ /* in_angle :: The angle of the inwards vector. */
+ /* */
+ /* out_angle :: The angle of the outwards vector. */
+ /* */
+ /* next :: The next point in same contour. */
+ /* */
+ /* prev :: The previous point in same contour. */
+ /* */
+ typedef struct AH_PointRec_
+ {
+ AH_Flags flags; /* point flags used by hinter */
+ FT_Pos ox, oy;
+ FT_Pos fx, fy;
+ FT_Pos x, y;
+ FT_Pos u, v;
+
+ AH_Direction in_dir; /* direction of inwards vector */
+ AH_Direction out_dir; /* direction of outwards vector */
+
+ AH_Angle in_angle;
+ AH_Angle out_angle;
+
+ AH_Point next; /* next point in contour */
+ AH_Point prev; /* previous point in contour */
+
+ } AH_PointRec;
+
+
+ /*************************************************************************/
+ /* */
+ /* <Struct> */
+ /* AH_SegmentRec */
+ /* */
+ /* <Description> */
+ /* A structure used to describe an edge segment to the auto-hinter. */
+ /* A segment is simply a sequence of successive points located on the */
+ /* same horizontal or vertical `position', in a given direction. */
+ /* */
+ /* <Fields> */
+ /* flags :: The segment edge flags (straight, rounded, etc.). */
+ /* */
+ /* dir :: The segment direction. */
+ /* */
+ /* first :: The first point in the segment. */
+ /* */
+ /* last :: The last point in the segment. */
+ /* */
+ /* contour :: A pointer to the first point of the segment's */
+ /* contour. */
+ /* */
+ /* pos :: The segment position in font units. */
+ /* */
+ /* size :: The segment size. */
+ /* */
+ /* edge :: The edge of the current segment. */
+ /* */
+ /* edge_next :: The next segment on the same edge. */
+ /* */
+ /* link :: The pairing segment for this edge. */
+ /* */
+ /* serif :: The primary segment for serifs. */
+ /* */
+ /* num_linked :: The number of other segments that link to this one. */
+ /* */
+ /* score :: Used to score the segment when selecting them. */
+ /* */
+ typedef struct AH_SegmentRec_
+ {
+ AH_Edge_Flags flags;
+ AH_Direction dir;
+
+ AH_Point first; /* first point in edge segment */
+ AH_Point last; /* last point in edge segment */
+ AH_Point* contour; /* ptr to first point of segment's contour */
+
+ FT_Pos pos; /* position of segment */
+ FT_Pos min_coord; /* minimum coordinate of segment */
+ FT_Pos max_coord; /* maximum coordinate of segment */
+
+ AH_Edge edge;
+ AH_Segment edge_next;
+
+ AH_Segment link; /* link segment */
+ AH_Segment serif; /* primary segment for serifs */
+ FT_Pos num_linked; /* number of linked segments */
+ FT_Pos score;
+
+ } AH_SegmentRec;
+
+
+ /*************************************************************************/
+ /* */
+ /* <Struct> */
+ /* AH_EdgeRec */
+ /* */
+ /* <Description> */
+ /* A structure used to describe an edge, which really is a horizontal */
+ /* or vertical coordinate to be hinted depending on the segments */
+ /* located on it. */
+ /* */
+ /* <Fields> */
+ /* flags :: The segment edge flags (straight, rounded, etc.). */
+ /* */
+ /* dir :: The main segment direction on this edge. */
+ /* */
+ /* first :: The first edge segment. */
+ /* */
+ /* last :: The last edge segment. */
+ /* */
+ /* fpos :: The original edge position in font units. */
+ /* */
+ /* opos :: The original scaled edge position. */
+ /* */
+ /* pos :: The hinted edge position. */
+ /* */
+ /* link :: The linked edge. */
+ /* */
+ /* serif :: The serif edge. */
+ /* */
+ /* num_paired :: The number of other edges that pair to this one. */
+ /* */
+ /* score :: Used to score the edge when selecting them. */
+ /* */
+ /* blue_edge :: Indicate the blue zone edge this edge is related to. */
+ /* Only set for some of the horizontal edges in a Latin */
+ /* font. */
+ /* */
+ typedef struct AH_EdgeRec_
+ {
+ AH_Edge_Flags flags;
+ AH_Direction dir;
+
+ AH_Segment first;
+ AH_Segment last;
+
+ FT_Pos fpos;
+ FT_Pos opos;
+ FT_Pos pos;
+
+ AH_Edge link;
+ AH_Edge serif;
+ FT_Int num_linked;
+
+ FT_Int score;
+ FT_Pos* blue_edge;
+
+ } AH_EdgeRec;
+
+
+ /* an outline as seen by the hinter */
+ typedef struct AH_OutlineRec_
+ {
+ FT_Memory memory;
+
+ AH_Direction vert_major_dir; /* vertical major direction */
+ AH_Direction horz_major_dir; /* horizontal major direction */
+
+ FT_Fixed x_scale;
+ FT_Fixed y_scale;
+ FT_Pos edge_distance_threshold;
+
+ FT_Int max_points;
+ FT_Int num_points;
+ AH_Point points;
+
+ FT_Int max_contours;
+ FT_Int num_contours;
+ AH_Point * contours;
+
+ FT_Int num_hedges;
+ AH_Edge horz_edges;
+
+ FT_Int num_vedges;
+ AH_Edge vert_edges;
+
+ FT_Int num_hsegments;
+ AH_Segment horz_segments;
+
+ FT_Int num_vsegments;
+ AH_Segment vert_segments;
+
+ } AH_OutlineRec, *AH_Outline;
+
+
+#define AH_BLUE_CAPITAL_TOP 0 /* THEZOCQS */
+#define AH_BLUE_CAPITAL_BOTTOM ( AH_BLUE_CAPITAL_TOP + 1 ) /* HEZLOCUS */
+#define AH_BLUE_SMALL_TOP ( AH_BLUE_CAPITAL_BOTTOM + 1 ) /* xzroesc */
+#define AH_BLUE_SMALL_BOTTOM ( AH_BLUE_SMALL_TOP + 1 ) /* xzroesc */
+#define AH_BLUE_SMALL_MINOR ( AH_BLUE_SMALL_BOTTOM + 1 ) /* pqgjy */
+#define AH_BLUE_MAX ( AH_BLUE_SMALL_MINOR + 1 )
+
+ typedef FT_Int AH_Blue;
+
+
+#define AH_HINTER_MONOCHROME 1
+#define AH_HINTER_OPTIMIZE 2
+
+ typedef FT_Int AH_Hinter_Flags;
+
+
+ /*************************************************************************/
+ /* */
+ /* <Struct> */
+ /* AH_GlobalsRec */
+ /* */
+ /* <Description> */
+ /* Holds the global metrics for a given font face (be it in design */
+ /* units or scaled pixel values). */
+ /* */
+ /* <Fields> */
+ /* num_widths :: The number of widths. */
+ /* */
+ /* num_heights :: The number of heights. */
+ /* */
+ /* widths :: Snap widths, including standard one. */
+ /* */
+ /* heights :: Snap height, including standard one. */
+ /* */
+ /* blue_refs :: The reference positions of blue zones. */
+ /* */
+ /* blue_shoots :: The overshoot positions of blue zones. */
+ /* */
+ typedef struct AH_GlobalsRec_
+ {
+ FT_Int num_widths;
+ FT_Int num_heights;
+
+ FT_Pos stds[2];
+
+ FT_Pos widths [AH_MAX_WIDTHS];
+ FT_Pos heights[AH_MAX_HEIGHTS];
+
+ FT_Pos blue_refs [AH_BLUE_MAX];
+ FT_Pos blue_shoots[AH_BLUE_MAX];
+
+ } AH_GlobalsRec, *AH_Globals;
+
+
+ /*************************************************************************/
+ /* */
+ /* <Struct> */
+ /* AH_Face_GlobalsRec */
+ /* */
+ /* <Description> */
+ /* Holds the complete global metrics for a given font face (i.e., the */
+ /* design units version + a scaled version + the current scales */
+ /* used). */
+ /* */
+ /* <Fields> */
+ /* face :: A handle to the source face object */
+ /* */
+ /* design :: The globals in font design units. */
+ /* */
+ /* scaled :: Scaled globals in sub-pixel values. */
+ /* */
+ /* x_scale :: The current horizontal scale. */
+ /* */
+ /* y_scale :: The current vertical scale. */
+ /* */
+ typedef struct AH_Face_GlobalsRec_
+ {
+ FT_Face face;
+ AH_GlobalsRec design;
+ AH_GlobalsRec scaled;
+ FT_Fixed x_scale;
+ FT_Fixed y_scale;
+ FT_Bool control_overshoot;
+
+ } AH_Face_GlobalsRec, *AH_Face_Globals;
+
+
+ typedef struct AH_HinterRec
+ {
+ FT_Memory memory;
+ AH_Hinter_Flags flags;
+
+ FT_Int algorithm;
+ FT_Face face;
+
+ AH_Face_Globals globals;
+
+ AH_Outline glyph;
+
+ AH_Loader loader;
+ FT_Vector pp1;
+ FT_Vector pp2;
+
+ FT_Bool transformed;
+ FT_Vector trans_delta;
+ FT_Matrix trans_matrix;
+
+ FT_Bool do_horz_hints; /* disable X hinting */
+ FT_Bool do_vert_hints; /* disable Y hinting */
+ FT_Bool do_horz_snapping; /* disable X stem size snapping */
+ FT_Bool do_vert_snapping; /* disable Y stem size snapping */
+
+ } AH_HinterRec, *AH_Hinter;
+
+
+#ifdef DEBUG_HINTER
+ extern AH_Hinter ah_debug_hinter;
+ extern FT_Bool ah_debug_disable_horz;
+ extern FT_Bool ah_debug_disable_vert;
+#else
+#define ah_debug_disable_horz 0
+#define ah_debug_disable_vert 0
+#endif /* DEBUG_HINTER */
+
+
+FT_END_HEADER
+
+#endif /* __AHTYPES_H__ */
+
+
+/* END */
--- /dev/null
+++ b/libfreetype/autohint.c
@@ -1,0 +1,32 @@
+/***************************************************************************/
+/* */
+/* autohint.c */
+/* */
+/* Automatic Hinting wrapper (body only). */
+/* */
+/* Copyright 2000-2001 Catharon Productions Inc. */
+/* Author: David Turner */
+/* */
+/* This file is part of the Catharon Typography Project and shall only */
+/* be used, modified, and distributed under the terms of the Catharon */
+/* Open Source License that should come with this file under the name */
+/* `CatharonLicense.txt'. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/* Note that this license is compatible with the FreeType license. */
+/* */
+/***************************************************************************/
+
+
+#define FT_MAKE_OPTION_SINGLE_OBJECT
+
+#include <ft2build.h>
+#include "ahangles.c"
+#include "ahglyph.c"
+#include "ahglobal.c"
+#include "ahhint.c"
+#include "ahmodule.c"
+
+
+/* END */
--- /dev/null
+++ b/libfreetype/bdf.c
@@ -1,0 +1,34 @@
+/* bdf.c
+
+ FreeType font driver for bdf files
+
+ Copyright (C) 2001, 2002 by
+ Francesco Zappa Nardelli
+
+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.
+*/
+
+#define FT_MAKE_OPTION_SINGLE_OBJECT
+
+#include <ft2build.h>
+#include "bdflib.c"
+#include "bdfdrivr.c"
+
+
+/* END */
--- /dev/null
+++ b/libfreetype/bdf.h
@@ -1,0 +1,295 @@
+/*
+ * Copyright 2000 Computing Research Labs, New Mexico State University
+ * Copyright 2001, 2002 Francesco Zappa Nardelli
+ *
+ * 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 COMPUTING RESEARCH LAB OR NEW MEXICO STATE UNIVERSITY 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.
+ */
+
+
+#ifndef __BDF_H__
+#define __BDF_H__
+
+
+/*
+ * Based on bdf.h,v 1.16 2000/03/16 20:08:51 mleisher
+ */
+
+#include <ft2build.h>
+#include FT_INTERNAL_OBJECTS_H
+#include FT_INTERNAL_STREAM_H
+
+
+FT_BEGIN_HEADER
+
+
+/* Imported from bdfP.h */
+
+#define _bdf_glyph_modified( map, e ) \
+ ( (map)[(e) >> 5] & ( 1 << ( (e) & 31 ) ) )
+#define _bdf_set_glyph_modified( map, e ) \
+ ( (map)[(e) >> 5] |= ( 1 << ( (e) & 31 ) ) )
+#define _bdf_clear_glyph_modified( map, e ) \
+ ( (map)[(e) >> 5] &= ~( 1 << ( (e) & 31 ) ) )
+
+/* end of bdfP.h */
+
+
+ /*************************************************************************/
+ /* */
+ /* BDF font options macros and types. */
+ /* */
+ /*************************************************************************/
+
+
+#define BDF_CORRECT_METRICS 0x01 /* Correct invalid metrics when loading. */
+#define BDF_KEEP_COMMENTS 0x02 /* Preserve the font comments. */
+#define BDF_KEEP_UNENCODED 0x04 /* Keep the unencoded glyphs. */
+#define BDF_PROPORTIONAL 0x08 /* Font has proportional spacing. */
+#define BDF_MONOWIDTH 0x10 /* Font has mono width. */
+#define BDF_CHARCELL 0x20 /* Font has charcell spacing. */
+
+#define BDF_ALL_SPACING ( BDF_PROPORTIONAL | \
+ BDF_MONOWIDTH | \
+ BDF_CHARCELL )
+
+#define BDF_DEFAULT_LOAD_OPTIONS ( BDF_CORRECT_METRICS | \
+ BDF_KEEP_COMMENTS | \
+ BDF_KEEP_UNENCODED | \
+ BDF_PROPORTIONAL )
+
+
+ typedef struct bdf_options_t_
+ {
+ int correct_metrics;
+ int keep_unencoded;
+ int keep_comments;
+ int font_spacing;
+
+ } bdf_options_t;
+
+
+ /* Callback function type for unknown configuration options. */
+ typedef int
+ (*bdf_options_callback_t)( bdf_options_t* opts,
+ char** params,
+ unsigned long nparams,
+ void* client_data );
+
+
+ /*************************************************************************/
+ /* */
+ /* BDF font property macros and types. */
+ /* */
+ /*************************************************************************/
+
+
+#define BDF_ATOM 1
+#define BDF_INTEGER 2
+#define BDF_CARDINAL 3
+
+
+ /* This structure represents a particular property of a font. */
+ /* There are a set of defaults and each font has their own. */
+ typedef struct bdf_property_t_
+ {
+ char* name; /* Name of the property. */
+ int format; /* Format of the property. */
+ int builtin; /* A builtin property. */
+ union
+ {
+ char* atom;
+ long int32;
+ unsigned long card32;
+
+ } value; /* Value of the property. */
+
+ } bdf_property_t;
+
+
+ /*************************************************************************/
+ /* */
+ /* BDF font metric and glyph types. */
+ /* */
+ /*************************************************************************/
+
+
+ typedef struct bdf_bbx_t_
+ {
+ unsigned short width;
+ unsigned short height;
+
+ short x_offset;
+ short y_offset;
+
+ short ascent;
+ short descent;
+
+ } bdf_bbx_t;
+
+
+ typedef struct bdf_glyph_t_
+ {
+ char* name; /* Glyph name. */
+ long encoding; /* Glyph encoding. */
+ unsigned short swidth; /* Scalable width. */
+ unsigned short dwidth; /* Device width. */
+ bdf_bbx_t bbx; /* Glyph bounding box. */
+ unsigned char* bitmap; /* Glyph bitmap. */
+ unsigned long bpr; /* Number of bytes used per row. */
+ unsigned short bytes; /* Number of bytes used for the bitmap. */
+
+ } bdf_glyph_t;
+
+
+ typedef struct _hashnode_
+ {
+ char* key;
+ void* data;
+
+ } _hashnode, *hashnode;
+
+
+ typedef struct hashtable_
+ {
+ int limit;
+ int size;
+ int used;
+ hashnode* table;
+
+ } hashtable;
+
+
+ typedef struct bdf_glyphlist_t_
+ {
+ unsigned short pad; /* Pad to 4-byte boundary. */
+ unsigned short bpp; /* Bits per pixel. */
+ long start; /* Beginning encoding value of glyphs. */
+ long end; /* Ending encoding value of glyphs. */
+ bdf_glyph_t* glyphs; /* Glyphs themselves. */
+ unsigned long glyphs_size; /* Glyph structures allocated. */
+ unsigned long glyphs_used; /* Glyph structures used. */
+ bdf_bbx_t bbx; /* Overall bounding box of glyphs. */
+
+ } bdf_glyphlist_t;
+
+
+ typedef struct bdf_font_t_
+ {
+ char* name; /* Name of the font. */
+ bdf_bbx_t bbx; /* Font bounding box. */
+
+ long point_size; /* Point size of the font. */
+ unsigned long resolution_x; /* Font horizontal resolution. */
+ unsigned long resolution_y; /* Font vertical resolution. */
+
+ int spacing; /* Font spacing value. */
+
+ unsigned short monowidth; /* Logical width for monowidth font. */
+
+ long default_glyph; /* Encoding of the default glyph. */
+
+ long font_ascent; /* Font ascent. */
+ long font_descent; /* Font descent. */
+
+ unsigned long glyphs_size; /* Glyph structures allocated. */
+ unsigned long glyphs_used; /* Glyph structures used. */
+ bdf_glyph_t* glyphs; /* Glyphs themselves. */
+
+ unsigned long unencoded_size; /* Unencoded glyph struct. allocated. */
+ unsigned long unencoded_used; /* Unencoded glyph struct. used. */
+ bdf_glyph_t* unencoded; /* Unencoded glyphs themselves. */
+
+ unsigned long props_size; /* Font properties allocated. */
+ unsigned long props_used; /* Font properties used. */
+ bdf_property_t* props; /* Font properties themselves. */
+
+ char* comments; /* Font comments. */
+ unsigned long comments_len; /* Length of comment string. */
+
+ bdf_glyphlist_t overflow; /* Storage used for glyph insertion. */
+
+ void* internal; /* Internal data for the font. */
+
+ unsigned long nmod[2048]; /* Bitmap indicating modified glyphs. */
+ unsigned long umod[2048]; /* Bitmap indicating modified */
+ /* unencoded glyphs. */
+ unsigned short modified; /* Boolean indicating font modified. */
+ unsigned short bpp; /* Bits per pixel. */
+
+ FT_Memory memory;
+
+ bdf_property_t* user_props;
+ unsigned long nuser_props;
+ hashtable proptbl;
+
+ } bdf_font_t;
+
+
+ /*************************************************************************/
+ /* */
+ /* Types for load/save callbacks. */
+ /* */
+ /*************************************************************************/
+
+
+ /* Error codes. */
+#define BDF_MISSING_START -1
+#define BDF_MISSING_FONTNAME -2
+#define BDF_MISSING_SIZE -3
+#define BDF_MISSING_CHARS -4
+#define BDF_MISSING_STARTCHAR -5
+#define BDF_MISSING_ENCODING -6
+#define BDF_MISSING_BBX -7
+
+#define BDF_OUT_OF_MEMORY -20
+
+#define BDF_INVALID_LINE -100
+
+
+ /*************************************************************************/
+ /* */
+ /* BDF font API. */
+ /* */
+ /*************************************************************************/
+
+ FT_LOCAL( FT_Error )
+ bdf_load_font( FT_Stream stream,
+ FT_Memory memory,
+ bdf_options_t* opts,
+ bdf_font_t* *font );
+
+ FT_LOCAL( void )
+ bdf_free_font( bdf_font_t* font );
+
+ FT_LOCAL( bdf_property_t * )
+ bdf_get_property( char* name,
+ bdf_font_t* font );
+
+ FT_LOCAL( bdf_property_t * )
+ bdf_get_font_property( bdf_font_t* font,
+ char* name );
+
+
+FT_END_HEADER
+
+
+#endif /* __BDF_H__ */
+
+
+/* END */
--- /dev/null
+++ b/libfreetype/bdfdrivr.c
@@ -1,0 +1,674 @@
+/* bdfdrivr.c
+
+ FreeType font driver for bdf files
+
+ Copyright (C) 2001-2002 by
+ Francesco Zappa Nardelli
+
+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.
+*/
+
+#include <ft2build.h>
+
+#include FT_INTERNAL_DEBUG_H
+#include FT_INTERNAL_STREAM_H
+#include FT_INTERNAL_OBJECTS_H
+
+#include "bdf.h"
+#include "bdfdrivr.h"
+
+#include "bdferror.h"
+
+
+ /*************************************************************************/
+ /* */
+ /* The macro FT_COMPONENT is used in trace mode. It is an implicit */
+ /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log */
+ /* messages during execution. */
+ /* */
+#undef FT_COMPONENT
+#define FT_COMPONENT trace_bdfdriver
+
+
+ typedef struct BDF_CMapRec_
+ {
+ FT_CMapRec cmap;
+ FT_UInt num_encodings;
+ BDF_encoding_el* encodings;
+
+ } BDF_CMapRec, *BDF_CMap;
+
+
+ FT_CALLBACK_DEF( FT_Error )
+ bdf_cmap_init( BDF_CMap cmap )
+ {
+ BDF_Face face = (BDF_Face)FT_CMAP_FACE( cmap );
+
+
+ cmap->num_encodings = face->bdffont->glyphs_used;
+ cmap->encodings = face->en_table;
+
+ return FT_Err_Ok;
+ }
+
+
+ FT_CALLBACK_DEF( void )
+ bdf_cmap_done( BDF_CMap cmap )
+ {
+ cmap->encodings = NULL;
+ cmap->num_encodings = 0;
+ }
+
+
+ FT_CALLBACK_DEF( FT_UInt )
+ bdf_cmap_char_index( BDF_CMap cmap,
+ FT_UInt32 charcode )
+ {
+ BDF_encoding_el* encodings = cmap->encodings;
+ FT_UInt min, max, mid;
+ FT_UInt result = 0;
+
+
+ min = 0;
+ max = cmap->num_encodings;
+
+ while ( min < max )
+ {
+ FT_UInt32 code;
+
+
+ mid = ( min + max ) >> 1;
+ code = encodings[mid].enc;
+
+ if ( charcode == code )
+ {
+ result = encodings[mid].glyph + 1;
+ break;
+ }
+
+ if ( charcode < code )
+ max = mid;
+ else
+ min = mid + 1;
+ }
+
+ return result;
+ }
+
+
+ FT_CALLBACK_DEF( FT_UInt )
+ bdf_cmap_char_next( BDF_CMap cmap,
+ FT_UInt32 *acharcode )
+ {
+ BDF_encoding_el* encodings = cmap->encodings;
+ FT_UInt min, max, mid;
+ FT_UInt32 charcode = *acharcode + 1;
+ FT_UInt result = 0;
+
+
+ min = 0;
+ max = cmap->num_encodings;
+
+ while ( min < max )
+ {
+ FT_UInt32 code;
+
+
+ mid = ( min + max ) >> 1;
+ code = encodings[mid].enc;
+
+ if ( charcode == code )
+ {
+ result = encodings[mid].glyph + 1;
+ goto Exit;
+ }
+
+ if ( charcode < code )
+ max = mid;
+ else
+ min = mid + 1;
+ }
+
+ charcode = 0;
+ if ( min < cmap->num_encodings )
+ {
+ charcode = encodings[min].enc;
+ result = encodings[min].glyph + 1;
+ }
+
+ Exit:
+ *acharcode = charcode;
+ return result;
+ }
+
+
+ FT_CALLBACK_TABLE_DEF const FT_CMap_ClassRec bdf_cmap_class =
+ {
+ sizeof( BDF_CMapRec ),
+ (FT_CMap_InitFunc) bdf_cmap_init,
+ (FT_CMap_DoneFunc) bdf_cmap_done,
+ (FT_CMap_CharIndexFunc)bdf_cmap_char_index,
+ (FT_CMap_CharNextFunc) bdf_cmap_char_next
+ };
+
+
+
+
+ FT_CALLBACK_DEF( FT_Error )
+ BDF_Face_Done( BDF_Face face )
+ {
+ FT_Memory memory = FT_FACE_MEMORY( face );
+
+
+ bdf_free_font( face->bdffont );
+
+ FT_FREE( face->en_table );
+
+ FT_FREE( face->charset_encoding );
+ FT_FREE( face->charset_registry );
+ FT_FREE( face->root.family_name );
+
+ FT_FREE( face->root.available_sizes );
+
+ FT_FREE( face->bdffont );
+
+ FT_TRACE4(( "BDF_Face_Done: done face\n" ));
+
+ return BDF_Err_Ok;
+ }
+
+
+ FT_CALLBACK_DEF( FT_Error )
+ BDF_Face_Init( FT_Stream stream,
+ BDF_Face face,
+ FT_Int face_index,
+ FT_Int num_params,
+ FT_Parameter* params )
+ {
+ FT_Error error = BDF_Err_Ok;
+ FT_Memory memory = FT_FACE_MEMORY( face );
+
+ bdf_font_t* font;
+ bdf_options_t options;
+
+ FT_UNUSED( num_params );
+ FT_UNUSED( params );
+ FT_UNUSED( face_index );
+
+
+ if ( FT_STREAM_SEEK( 0 ) )
+ goto Exit;
+
+ options.correct_metrics = 1; /* FZ XXX: options semantics */
+ options.keep_unencoded = 1;
+ options.keep_comments = 0;
+ options.font_spacing = BDF_PROPORTIONAL;
+
+ error = bdf_load_font( stream, memory, &options, &font );
+ if ( error == BDF_Err_Missing_Startfont_Field )
+ {
+ FT_TRACE2(( "[not a valid BDF file]\n" ));
+ goto Fail;
+ }
+ else if ( error )
+ goto Exit;
+
+ /* we have a bdf font: let's construct the face object */
+ face->bdffont = font;
+ {
+ FT_Face root = FT_FACE( face );
+ bdf_property_t* prop = NULL;
+
+
+ FT_TRACE4(( "number of glyphs: %d (%d)\n",
+ font->glyphs_size,
+ font->glyphs_used ));
+ FT_TRACE4(( "number of unencoded glyphs: %d (%d)\n",
+ font->unencoded_size,
+ font->unencoded_used ));
+
+ root->num_faces = 1;
+ root->face_index = 0;
+ root->face_flags = FT_FACE_FLAG_FIXED_SIZES |
+ FT_FACE_FLAG_HORIZONTAL |
+ FT_FACE_FLAG_FAST_GLYPHS;
+
+ prop = bdf_get_font_property( font, (char *)"SPACING" );
+ if ( prop != NULL )
+ if ( prop->format == BDF_ATOM )
+ if ( prop->value.atom != NULL )
+ if ( ( *(prop->value.atom) == 'M' ) ||
+ ( *(prop->value.atom) == 'C' ) )
+ root->face_flags |= FT_FACE_FLAG_FIXED_WIDTH;
+
+ /* FZ XXX: TO DO: FT_FACE_FLAGS_VERTICAL */
+ /* FZ XXX: I need a font to implement this */
+
+ root->style_flags = 0;
+ prop = bdf_get_font_property( font, (char *)"SLANT" );
+ if ( prop != NULL )
+ if ( prop->format == BDF_ATOM )
+ if ( prop->value.atom != NULL )
+ if ( ( *(prop->value.atom) == 'O' ) ||
+ ( *(prop->value.atom) == 'I' ) )
+ root->style_flags |= FT_STYLE_FLAG_ITALIC;
+
+ prop = bdf_get_font_property( font, (char *)"WEIGHT_NAME" );
+ if ( prop != NULL )
+ if ( prop->format == BDF_ATOM )
+ if ( prop->value.atom != NULL )
+ if ( *(prop->value.atom) == 'B' )
+ root->style_flags |= FT_STYLE_FLAG_BOLD;
+
+ prop = bdf_get_font_property( font, (char *)"FAMILY_NAME" );
+ if ( ( prop != NULL ) && ( prop->value.atom != NULL ) )
+ {
+ int l = ft_strlen( prop->value.atom ) + 1;
+
+
+ if ( FT_NEW_ARRAY( root->family_name, l ) )
+ goto Exit;
+ ft_strcpy( root->family_name, prop->value.atom );
+ }
+ else
+ root->family_name = 0;
+
+ root->style_name = (char *)"Regular";
+ if ( root->style_flags & FT_STYLE_FLAG_BOLD )
+ {
+ if ( root->style_flags & FT_STYLE_FLAG_ITALIC )
+ root->style_name = (char *)"Bold Italic";
+ else
+ root->style_name = (char *)"Bold";
+ }
+ else if ( root->style_flags & FT_STYLE_FLAG_ITALIC )
+ root->style_name = (char *)"Italic";
+
+ root->num_glyphs = font->glyphs_size; /* unencoded included */
+
+ root->num_fixed_sizes = 1;
+ if ( FT_NEW_ARRAY( root->available_sizes, 1 ) )
+ goto Exit;
+
+ prop = bdf_get_font_property( font, (char *)"AVERAGE_WIDTH" );
+ if ( ( prop != NULL ) && ( prop->value.int32 >= 10 ) )
+ root->available_sizes->width = (short)( prop->value.int32 / 10 );
+
+ prop = bdf_get_font_property( font, (char *)"PIXEL_SIZE" );
+ if ( prop != NULL )
+ root->available_sizes->height = (short) prop->value.int32;
+ else
+ {
+ prop = bdf_get_font_property( font, (char *)"POINT_SIZE" );
+ if ( prop != NULL )
+ {
+ bdf_property_t *yres;
+
+
+ yres = bdf_get_font_property( font, (char *)"RESOLUTION_Y" );
+ if ( yres != NULL )
+ {
+ FT_TRACE4(( "POINT_SIZE: %d RESOLUTION_Y: %d\n",
+ prop->value.int32, yres->value.int32 ));
+ root->available_sizes->height =
+ (FT_Short)( prop->value.int32 * yres->value.int32 / 720 );
+ }
+ }
+ }
+
+ if ( root->available_sizes->width == 0 )
+ {
+ if ( root->available_sizes->height == 0 )
+ {
+ /* some fonts have broken SIZE declaration (jiskan24.bdf) */
+ FT_ERROR(( "BDF_Face_Init: reading size\n" ));
+ root->available_sizes->width = (FT_Short)font->point_size;
+ }
+ else
+ root->available_sizes->width = root->available_sizes->height;
+ }
+ if ( root->available_sizes->height == 0 )
+ root->available_sizes->height = root->available_sizes->width;
+
+ /* encoding table */
+ {
+ bdf_glyph_t* cur = font->glyphs;
+ unsigned long n;
+
+
+ if ( FT_NEW_ARRAY( face->en_table, font->glyphs_size ) )
+ goto Exit;
+
+ for ( n = 0; n < font->glyphs_size; n++ )
+ {
+ (face->en_table[n]).enc = cur[n].encoding;
+ FT_TRACE4(( "idx %d, val 0x%lX\n", n, cur[n].encoding ));
+ (face->en_table[n]).glyph = (FT_Short)n;
+ }
+ }
+
+ /* charmaps */
+ {
+ bdf_property_t *charset_registry = 0, *charset_encoding = 0;
+ FT_Bool unicode_charmap = 0;
+
+
+ charset_registry =
+ bdf_get_font_property( font, (char *)"CHARSET_REGISTRY" );
+ charset_encoding =
+ bdf_get_font_property( font, (char *)"CHARSET_ENCODING" );
+ if ( ( charset_registry != NULL ) && ( charset_encoding != NULL ) )
+ {
+ if ( ( charset_registry->format == BDF_ATOM ) &&
+ ( charset_encoding->format == BDF_ATOM ) &&
+ ( charset_registry->value.atom != NULL ) &&
+ ( charset_encoding->value.atom != NULL ) )
+ {
+ if ( FT_NEW_ARRAY( face->charset_encoding,
+ strlen( charset_encoding->value.atom ) + 1 ) )
+ goto Exit;
+ if ( FT_NEW_ARRAY( face->charset_registry,
+ strlen( charset_registry->value.atom ) + 1 ) )
+ goto Exit;
+ ft_strcpy( face->charset_registry, charset_registry->value.atom );
+ ft_strcpy( face->charset_encoding, charset_encoding->value.atom );
+ if ( !ft_strcmp( face->charset_registry, "ISO10646" ) ||
+ ( !ft_strcmp( face->charset_registry, "ISO8859" ) &&
+ !ft_strcmp( face->charset_encoding, "1" ) ) )
+ unicode_charmap = 1;
+
+ {
+ FT_CharMapRec charmap;
+
+
+ charmap.face = FT_FACE( face );
+ charmap.encoding = FT_ENCODING_NONE;
+ charmap.platform_id = 0;
+ charmap.encoding_id = 0;
+
+ if ( unicode_charmap )
+ {
+ charmap.encoding = FT_ENCODING_UNICODE;
+ charmap.platform_id = 3;
+ charmap.encoding_id = 1;
+ }
+
+ error = FT_CMap_New( &bdf_cmap_class, NULL, &charmap, NULL );
+
+#if 0
+ /* Select default charmap */
+ if (root->num_charmaps)
+ root->charmap = root->charmaps[0];
+#endif
+ }
+
+ goto Exit;
+ }
+ }
+
+ /* otherwise assume Adobe standard encoding */
+
+ {
+ FT_CharMapRec charmap;
+
+
+ charmap.face = FT_FACE( face );
+ charmap.encoding = FT_ENCODING_ADOBE_STANDARD;
+ charmap.platform_id = 7;
+ charmap.encoding_id = 0;
+
+ error = FT_CMap_New( &bdf_cmap_class, NULL, &charmap, NULL );
+
+ /* Select default charmap */
+ if (root->num_charmaps)
+ root->charmap = root->charmaps[0];
+ }
+ }
+ }
+
+ Exit:
+ return error;
+
+ Fail:
+ BDF_Face_Done( face );
+ return BDF_Err_Unknown_File_Format;
+ }
+
+
+ static FT_Error
+ BDF_Set_Pixel_Size( FT_Size size )
+ {
+ BDF_Face face = (BDF_Face)FT_SIZE_FACE( size );
+ FT_Face root = FT_FACE( face );
+
+
+ FT_TRACE4(( "rec %d - pres %d\n",
+ size->metrics.y_ppem, root->available_sizes->height ));
+
+ if ( size->metrics.y_ppem == root->available_sizes->height )
+ {
+ size->metrics.ascender = face->bdffont->bbx.ascent << 6;
+ size->metrics.descender = face->bdffont->bbx.descent * ( -64 );
+ size->metrics.height = face->bdffont->bbx.height << 6;
+
+ return BDF_Err_Ok;
+ }
+ else
+ return BDF_Err_Invalid_Pixel_Size;
+ }
+
+
+ static FT_Error
+ BDF_Glyph_Load( FT_GlyphSlot slot,
+ FT_Size size,
+ FT_UInt glyph_index,
+ FT_Int32 load_flags )
+ {
+ BDF_Face face = (BDF_Face)FT_SIZE_FACE( size );
+ FT_Error error = BDF_Err_Ok;
+ FT_Bitmap* bitmap = &slot->bitmap;
+ bdf_glyph_t glyph;
+ int bpp = face->bdffont->bpp;
+ int i, j, count;
+ unsigned char *p, *pp;
+
+ FT_Memory memory = face->bdffont->memory;
+
+ FT_UNUSED( load_flags );
+
+
+ if ( !face )
+ {
+ error = BDF_Err_Invalid_Argument;
+ goto Exit;
+ }
+
+ if ( glyph_index > 0 )
+ glyph_index--;
+
+ /* slot, bitmap => freetype, glyph => bdflib */
+ glyph = face->bdffont->glyphs[glyph_index];
+
+ bitmap->rows = glyph.bbx.height;
+ bitmap->width = glyph.bbx.width;
+
+ if ( bpp == 1 )
+ {
+ bitmap->pixel_mode = FT_PIXEL_MODE_MONO;
+ bitmap->pitch = glyph.bpr;
+
+ if ( FT_NEW_ARRAY( bitmap->buffer, glyph.bytes ) )
+ goto Exit;
+ FT_MEM_COPY( bitmap->buffer, glyph.bitmap, glyph.bytes );
+ }
+ else
+ {
+ /* blow up pixmap to have 8 bits per pixel */
+ bitmap->pixel_mode = FT_PIXEL_MODE_GRAY;
+ bitmap->pitch = bitmap->width;
+
+ if ( FT_NEW_ARRAY( bitmap->buffer, bitmap->rows * bitmap->pitch ) )
+ goto Exit;
+
+ switch ( bpp )
+ {
+ case 2:
+ bitmap->num_grays = 4;
+
+ count = 0;
+ p = glyph.bitmap;
+
+ for ( i = 0; i < bitmap->rows; i++ )
+ {
+ pp = p;
+
+ /* get the full bytes */
+ for ( j = 0; j < ( bitmap->width >> 2 ); j++ )
+ {
+ bitmap->buffer[count++] = (FT_Byte)( ( *pp & 0xC0 ) >> 6 );
+ bitmap->buffer[count++] = (FT_Byte)( ( *pp & 0x30 ) >> 4 );
+ bitmap->buffer[count++] = (FT_Byte)( ( *pp & 0x0C ) >> 2 );
+ bitmap->buffer[count++] = (FT_Byte)( *pp & 0x03 );
+
+ pp++;
+ }
+
+ /* get remaining pixels (if any) */
+ switch ( bitmap->width & 3 )
+ {
+ case 3:
+ bitmap->buffer[count++] = (FT_Byte)( ( *pp & 0xC0 ) >> 6 );
+ /* fall through */
+ case 2:
+ bitmap->buffer[count++] = (FT_Byte)( ( *pp & 0x30 ) >> 4 );
+ /* fall through */
+ case 1:
+ bitmap->buffer[count++] = (FT_Byte)( ( *pp & 0x0C ) >> 2 );
+ /* fall through */
+ case 0:
+ break;
+ }
+
+ p += glyph.bpr;
+ }
+ break;
+
+ case 4:
+ bitmap->num_grays = 16;
+
+ count = 0;
+ p = glyph.bitmap;
+
+ for ( i = 0; i < bitmap->rows; i++ )
+ {
+ pp = p;
+
+ /* get the full bytes */
+ for ( j = 0; j < ( bitmap->width >> 1 ); j++ )
+ {
+ bitmap->buffer[count++] = (FT_Byte)( ( *pp & 0xF0 ) >> 4 );
+ bitmap->buffer[count++] = (FT_Byte)( *pp & 0x0F );
+
+ pp++;
+ }
+
+ /* get remaining pixel (if any) */
+ switch ( bitmap->width & 1 )
+ {
+ case 1:
+ bitmap->buffer[count++] = (FT_Byte)( ( *pp & 0xF0 ) >> 4 );
+ /* fall through */
+ case 0:
+ break;
+ }
+
+ p += glyph.bpr;
+ }
+ break;
+
+ case 8:
+ bitmap->num_grays = 256;
+
+ FT_MEM_COPY( bitmap->buffer, glyph.bitmap,
+ bitmap->rows * bitmap->pitch );
+ break;
+ }
+ }
+
+ slot->bitmap_left = 0;
+ slot->bitmap_top = glyph.bbx.ascent;
+
+ /* FZ XXX: TODO: vertical metrics */
+ slot->metrics.horiAdvance = glyph.dwidth << 6;
+ slot->metrics.horiBearingX = glyph.bbx.x_offset << 6;
+ slot->metrics.horiBearingY = ( glyph.bbx.y_offset +
+ glyph.bbx.height ) << 6;
+ slot->metrics.width = bitmap->width << 6;
+ slot->metrics.height = bitmap->rows << 6;
+
+ slot->linearHoriAdvance = (FT_Fixed)glyph.dwidth << 16;
+ slot->format = FT_GLYPH_FORMAT_BITMAP;
+ slot->flags = FT_GLYPH_OWN_BITMAP;
+
+ Exit:
+ return error;
+ }
+
+
+ FT_CALLBACK_TABLE_DEF
+ const FT_Driver_ClassRec bdf_driver_class =
+ {
+ {
+ ft_module_font_driver,
+ sizeof ( FT_DriverRec ),
+
+ "bdf",
+ 0x10000L,
+ 0x20000L,
+
+ 0,
+
+ (FT_Module_Constructor)0,
+ (FT_Module_Destructor) 0,
+ (FT_Module_Requester) 0
+ },
+
+ sizeof ( BDF_FaceRec ),
+ sizeof ( FT_SizeRec ),
+ sizeof ( FT_GlyphSlotRec ),
+
+ (FT_Face_InitFunc) BDF_Face_Init,
+ (FT_Face_DoneFunc) BDF_Face_Done,
+ (FT_Size_InitFunc) 0,
+ (FT_Size_DoneFunc) 0,
+ (FT_Slot_InitFunc) 0,
+ (FT_Slot_DoneFunc) 0,
+
+ (FT_Size_ResetPointsFunc) BDF_Set_Pixel_Size,
+ (FT_Size_ResetPixelsFunc) BDF_Set_Pixel_Size,
+
+ (FT_Slot_LoadFunc) BDF_Glyph_Load,
+
+ (FT_Face_GetKerningFunc) 0,
+ (FT_Face_AttachFunc) 0,
+ (FT_Face_GetAdvancesFunc) 0
+ };
+
+
+/* END */
--- /dev/null
+++ b/libfreetype/bdfdrivr.h
@@ -1,0 +1,74 @@
+/* bdfdrivr.h
+
+ FreeType font driver for bdf fonts
+
+ Copyright (C) 2001, 2002 by
+ Francesco Zappa Nardelli
+
+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.
+*/
+
+
+#ifndef __BDFDRIVR_H__
+#define __BDFDRIVR_H__
+
+#include <ft2build.h>
+#include FT_INTERNAL_DRIVER_H
+
+#include "bdf.h"
+
+
+FT_BEGIN_HEADER
+
+
+ typedef struct BDF_encoding_el_
+ {
+ FT_ULong enc;
+ FT_Short glyph;
+
+ } BDF_encoding_el;
+
+
+ typedef struct BDF_FaceRec_
+ {
+ FT_FaceRec root;
+
+ char* charset_encoding;
+ char* charset_registry;
+
+ bdf_font_t* bdffont;
+
+ BDF_encoding_el* en_table;
+
+ FT_CharMap charmap_handle;
+ FT_CharMapRec charmap; /* a single charmap per face */
+
+ } BDF_FaceRec, *BDF_Face;
+
+
+ FT_EXPORT_VAR( const FT_Driver_ClassRec ) bdf_driver_class;
+
+
+FT_END_HEADER
+
+
+#endif /* __BDFDRIVR_H__ */
+
+
+/* END */
--- /dev/null
+++ b/libfreetype/bdferror.h
@@ -1,0 +1,44 @@
+/*
+ * Copyright 2001, 2002 Francesco Zappa Nardelli
+ *
+ * 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 COMPUTING RESEARCH LAB OR NEW MEXICO STATE UNIVERSITY 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 file is used to define the BDF error enumeration constants. */
+ /* */
+ /*************************************************************************/
+
+#ifndef __BDFERROR_H__
+#define __BDFERROR_H__
+
+#include FT_MODULE_ERRORS_H
+
+#undef __FTERRORS_H__
+
+#define FT_ERR_PREFIX BDF_Err_
+#define FT_ERR_BASE FT_Mod_Err_BDF
+
+#include FT_ERRORS_H
+
+#endif /* __BDFERROR_H__ */
+
+
+/* END */
--- /dev/null
+++ b/libfreetype/bdflib.c
@@ -1,0 +1,2436 @@
+/*
+ * Copyright 2000 Computing Research Labs, New Mexico State University
+ * Copyright 2001, 2002 Francesco Zappa Nardelli
+ *
+ * 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 COMPUTING RESEARCH LAB OR NEW MEXICO STATE UNIVERSITY 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 file is based on bdf.c,v 1.22 2000/03/16 20:08:50 */
+ /* */
+ /* taken from Mark Leisher's xmbdfed package */
+ /* */
+ /*************************************************************************/
+
+
+#include <ft2build.h>
+
+#include FT_FREETYPE_H
+#include FT_INTERNAL_DEBUG_H
+#include FT_INTERNAL_STREAM_H
+#include FT_INTERNAL_OBJECTS_H
+
+#include "bdf.h"
+#include "bdferror.h"
+
+
+ /*************************************************************************/
+ /* */
+ /* The macro FT_COMPONENT is used in trace mode. It is an implicit */
+ /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log */
+ /* messages during execution. */
+ /* */
+#undef FT_COMPONENT
+#define FT_COMPONENT trace_bdflib
+
+
+ /*************************************************************************/
+ /* */
+ /* Default BDF font options. */
+ /* */
+ /*************************************************************************/
+
+
+ static const bdf_options_t _bdf_opts =
+ {
+ 1, /* Correct metrics. */
+ 1, /* Preserve unencoded glyphs. */
+ 0, /* Preserve comments. */
+ BDF_PROPORTIONAL /* Default spacing. */
+ };
+
+
+ /*************************************************************************/
+ /* */
+ /* Builtin BDF font properties. */
+ /* */
+ /*************************************************************************/
+
+ /* List of most properties that might appear in a font. Doesn't include */
+ /* the RAW_* and AXIS_* properties in X11R6 polymorphic fonts. */
+
+ static const bdf_property_t _bdf_properties[] =
+ {
+ { (char *)"ADD_STYLE_NAME", BDF_ATOM, 1, { 0 } },
+ { (char *)"AVERAGE_WIDTH", BDF_INTEGER, 1, { 0 } },
+ { (char *)"AVG_CAPITAL_WIDTH", BDF_INTEGER, 1, { 0 } },
+ { (char *)"AVG_LOWERCASE_WIDTH", BDF_INTEGER, 1, { 0 } },
+ { (char *)"CAP_HEIGHT", BDF_INTEGER, 1, { 0 } },
+ { (char *)"CHARSET_COLLECTIONS", BDF_ATOM, 1, { 0 } },
+ { (char *)"CHARSET_ENCODING", BDF_ATOM, 1, { 0 } },
+ { (char *)"CHARSET_REGISTRY", BDF_ATOM, 1, { 0 } },
+ { (char *)"COMMENT", BDF_ATOM, 1, { 0 } },
+ { (char *)"COPYRIGHT", BDF_ATOM, 1, { 0 } },
+ { (char *)"DEFAULT_CHAR", BDF_CARDINAL, 1, { 0 } },
+ { (char *)"DESTINATION", BDF_CARDINAL, 1, { 0 } },
+ { (char *)"DEVICE_FONT_NAME", BDF_ATOM, 1, { 0 } },
+ { (char *)"END_SPACE", BDF_INTEGER, 1, { 0 } },
+ { (char *)"FACE_NAME", BDF_ATOM, 1, { 0 } },
+ { (char *)"FAMILY_NAME", BDF_ATOM, 1, { 0 } },
+ { (char *)"FIGURE_WIDTH", BDF_INTEGER, 1, { 0 } },
+ { (char *)"FONT", BDF_ATOM, 1, { 0 } },
+ { (char *)"FONTNAME_REGISTRY", BDF_ATOM, 1, { 0 } },
+ { (char *)"FONT_ASCENT", BDF_INTEGER, 1, { 0 } },
+ { (char *)"FONT_DESCENT", BDF_INTEGER, 1, { 0 } },
+ { (char *)"FOUNDRY", BDF_ATOM, 1, { 0 } },
+ { (char *)"FULL_NAME", BDF_ATOM, 1, { 0 } },
+ { (char *)"ITALIC_ANGLE", BDF_INTEGER, 1, { 0 } },
+ { (char *)"MAX_SPACE", BDF_INTEGER, 1, { 0 } },
+ { (char *)"MIN_SPACE", BDF_INTEGER, 1, { 0 } },
+ { (char *)"NORM_SPACE", BDF_INTEGER, 1, { 0 } },
+ { (char *)"NOTICE", BDF_ATOM, 1, { 0 } },
+ { (char *)"PIXEL_SIZE", BDF_INTEGER, 1, { 0 } },
+ { (char *)"POINT_SIZE", BDF_INTEGER, 1, { 0 } },
+ { (char *)"QUAD_WIDTH", BDF_INTEGER, 1, { 0 } },
+ { (char *)"RAW_ASCENT", BDF_INTEGER, 1, { 0 } },
+ { (char *)"RAW_AVERAGE_WIDTH", BDF_INTEGER, 1, { 0 } },
+ { (char *)"RAW_AVG_CAPITAL_WIDTH", BDF_INTEGER, 1, { 0 } },
+ { (char *)"RAW_AVG_LOWERCASE_WIDTH", BDF_INTEGER, 1, { 0 } },
+ { (char *)"RAW_CAP_HEIGHT", BDF_INTEGER, 1, { 0 } },
+ { (char *)"RAW_DESCENT", BDF_INTEGER, 1, { 0 } },
+ { (char *)"RAW_END_SPACE", BDF_INTEGER, 1, { 0 } },
+ { (char *)"RAW_FIGURE_WIDTH", BDF_INTEGER, 1, { 0 } },
+ { (char *)"RAW_MAX_SPACE", BDF_INTEGER, 1, { 0 } },
+ { (char *)"RAW_MIN_SPACE", BDF_INTEGER, 1, { 0 } },
+ { (char *)"RAW_NORM_SPACE", BDF_INTEGER, 1, { 0 } },
+ { (char *)"RAW_PIXEL_SIZE", BDF_INTEGER, 1, { 0 } },
+ { (char *)"RAW_POINT_SIZE", BDF_INTEGER, 1, { 0 } },
+ { (char *)"RAW_PIXELSIZE", BDF_INTEGER, 1, { 0 } },
+ { (char *)"RAW_POINTSIZE", BDF_INTEGER, 1, { 0 } },
+ { (char *)"RAW_QUAD_WIDTH", BDF_INTEGER, 1, { 0 } },
+ { (char *)"RAW_SMALL_CAP_SIZE", BDF_INTEGER, 1, { 0 } },
+ { (char *)"RAW_STRIKEOUT_ASCENT", BDF_INTEGER, 1, { 0 } },
+ { (char *)"RAW_STRIKEOUT_DESCENT", BDF_INTEGER, 1, { 0 } },
+ { (char *)"RAW_SUBSCRIPT_SIZE", BDF_INTEGER, 1, { 0 } },
+ { (char *)"RAW_SUBSCRIPT_X", BDF_INTEGER, 1, { 0 } },
+ { (char *)"RAW_SUBSCRIPT_Y", BDF_INTEGER, 1, { 0 } },
+ { (char *)"RAW_SUPERSCRIPT_SIZE", BDF_INTEGER, 1, { 0 } },
+ { (char *)"RAW_SUPERSCRIPT_X", BDF_INTEGER, 1, { 0 } },
+ { (char *)"RAW_SUPERSCRIPT_Y", BDF_INTEGER, 1, { 0 } },
+ { (char *)"RAW_UNDERLINE_POSITION", BDF_INTEGER, 1, { 0 } },
+ { (char *)"RAW_UNDERLINE_THICKNESS", BDF_INTEGER, 1, { 0 } },
+ { (char *)"RAW_X_HEIGHT", BDF_INTEGER, 1, { 0 } },
+ { (char *)"RELATIVE_SETWIDTH", BDF_CARDINAL, 1, { 0 } },
+ { (char *)"RELATIVE_WEIGHT", BDF_CARDINAL, 1, { 0 } },
+ { (char *)"RESOLUTION", BDF_INTEGER, 1, { 0 } },
+ { (char *)"RESOLUTION_X", BDF_CARDINAL, 1, { 0 } },
+ { (char *)"RESOLUTION_Y", BDF_CARDINAL, 1, { 0 } },
+ { (char *)"SETWIDTH_NAME", BDF_ATOM, 1, { 0 } },
+ { (char *)"SLANT", BDF_ATOM, 1, { 0 } },
+ { (char *)"SMALL_CAP_SIZE", BDF_INTEGER, 1, { 0 } },
+ { (char *)"SPACING", BDF_ATOM, 1, { 0 } },
+ { (char *)"STRIKEOUT_ASCENT", BDF_INTEGER, 1, { 0 } },
+ { (char *)"STRIKEOUT_DESCENT", BDF_INTEGER, 1, { 0 } },
+ { (char *)"SUBSCRIPT_SIZE", BDF_INTEGER, 1, { 0 } },
+ { (char *)"SUBSCRIPT_X", BDF_INTEGER, 1, { 0 } },
+ { (char *)"SUBSCRIPT_Y", BDF_INTEGER, 1, { 0 } },
+ { (char *)"SUPERSCRIPT_SIZE", BDF_INTEGER, 1, { 0 } },
+ { (char *)"SUPERSCRIPT_X", BDF_INTEGER, 1, { 0 } },
+ { (char *)"SUPERSCRIPT_Y", BDF_INTEGER, 1, { 0 } },
+ { (char *)"UNDERLINE_POSITION", BDF_INTEGER, 1, { 0 } },
+ { (char *)"UNDERLINE_THICKNESS", BDF_INTEGER, 1, { 0 } },
+ { (char *)"WEIGHT", BDF_CARDINAL, 1, { 0 } },
+ { (char *)"WEIGHT_NAME", BDF_ATOM, 1, { 0 } },
+ { (char *)"X_HEIGHT", BDF_INTEGER, 1, { 0 } },
+ { (char *)"_MULE_BASELINE_OFFSET", BDF_INTEGER, 1, { 0 } },
+ { (char *)"_MULE_RELATIVE_COMPOSE", BDF_INTEGER, 1, { 0 } },
+ };
+
+ static unsigned long
+ _num_bdf_properties = sizeof ( _bdf_properties ) /
+ sizeof ( _bdf_properties[0] );
+
+
+ /*************************************************************************/
+ /* */
+ /* Hash table utilities for the properties. */
+ /* */
+ /*************************************************************************/
+
+ /* XXX: Replace this with FreeType's hash functions */
+
+
+#define INITIAL_HT_SIZE 241
+
+ typedef void
+ (*hash_free_func)( hashnode node );
+
+ static hashnode*
+ hash_bucket( char* key,
+ hashtable* ht )
+ {
+ char* kp = key;
+ unsigned long res = 0;
+ hashnode* bp = ht->table, *ndp;
+
+
+ /* Mocklisp hash function. */
+ while ( *kp )
+ res = ( res << 5 ) - res + *kp++;
+
+ ndp = bp + ( res % ht->size );
+ while ( *ndp )
+ {
+ kp = (*ndp)->key;
+ if ( kp[0] == key[0] && ft_strcmp( kp, key ) == 0 )
+ break;
+ ndp--;
+ if ( ndp < bp )
+ ndp = bp + ( ht->size - 1 );
+ }
+
+ return ndp;
+ }
+
+
+ static FT_Error
+ hash_rehash( hashtable* ht,
+ FT_Memory memory )
+ {
+ hashnode* obp = ht->table, *bp, *nbp;
+ int i, sz = ht->size;
+ FT_Error error = BDF_Err_Ok;
+
+
+ ht->size <<= 1;
+ ht->limit = ht->size / 3;
+
+ if ( FT_NEW_ARRAY( ht->table, ht->size ) )
+ goto Exit;
+ FT_MEM_ZERO( ht->table, sizeof ( hashnode ) * ht->size );
+
+ for ( i = 0, bp = obp; i < sz; i++, bp++ )
+ {
+ if ( *bp )
+ {
+ nbp = hash_bucket( (*bp)->key, ht );
+ *nbp = *bp;
+ }
+ }
+ FT_FREE( obp );
+
+ Exit:
+ return error;
+ }
+
+
+ static FT_Error
+ hash_init( hashtable* ht,
+ FT_Memory memory )
+ {
+ int sz = INITIAL_HT_SIZE;
+ FT_Error error = BDF_Err_Ok;
+
+
+ ht->size = sz;
+ ht->limit = sz / 3;
+ ht->used = 0;
+
+ if ( FT_NEW_ARRAY( ht->table, sz ) )
+ goto Exit;
+ FT_MEM_ZERO( ht->table, sizeof ( hashnode ) * sz );
+
+ Exit:
+ return error;
+ }
+
+
+ static void
+ hash_free( hashtable* ht,
+ FT_Memory memory )
+ {
+ if ( ht != 0 )
+ {
+ int i, sz = ht->size;
+ hashnode* bp = ht->table;
+
+
+ for ( i = 0; i < sz; i++, bp++ )
+ FT_FREE( *bp );
+
+ FT_FREE( ht->table );
+ }
+ }
+
+
+ static FT_Error
+ hash_insert( char* key,
+ void* data,
+ hashtable* ht,
+ FT_Memory memory )
+ {
+ hashnode nn, *bp = hash_bucket( key, ht );
+ FT_Error error = BDF_Err_Ok;
+
+
+ nn = *bp;
+ if ( !nn )
+ {
+ if ( FT_NEW( nn ) )
+ goto Exit;
+ *bp = nn;
+
+ nn->key = key;
+ nn->data = data;
+
+ if ( ht->used >= ht->limit )
+ {
+ error = hash_rehash( ht, memory );
+ if ( error )
+ goto Exit;
+ }
+ ht->used++;
+ }
+ else
+ nn->data = data;
+
+ Exit:
+ return error;
+ }
+
+
+ static hashnode
+ hash_lookup( char* key,
+ hashtable* ht )
+ {
+ hashnode *np = hash_bucket( key, ht );
+
+
+ return *np;
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* Utility types and functions. */
+ /* */
+ /*************************************************************************/
+
+
+ /* Function type for parsing lines of a BDF font. */
+
+ typedef FT_Error
+ (*_bdf_line_func_t)( char* line,
+ unsigned long linelen,
+ unsigned long lineno,
+ void* call_data,
+ void* client_data );
+
+
+ /* List structure for splitting lines into fields. */
+
+ typedef struct _bdf_list_t_
+ {
+ char** field;
+ unsigned long size;
+ unsigned long used;
+
+ } _bdf_list_t;
+
+
+ /* Structure used while loading BDF fonts. */
+
+ typedef struct _bdf_parse_t_
+ {
+ unsigned long flags;
+ unsigned long cnt;
+ unsigned long row;
+
+ short minlb;
+ short maxlb;
+ short maxrb;
+ short maxas;
+ short maxds;
+
+ short rbearing;
+
+ char* glyph_name;
+ long glyph_enc;
+
+ bdf_font_t* font;
+ bdf_options_t* opts;
+
+ unsigned long have[2048];
+ _bdf_list_t list;
+
+ FT_Memory memory;
+
+ } _bdf_parse_t;
+
+
+#define setsbit( m, cc ) ( m[(cc) >> 3] |= (FT_Byte)( 1 << ( (cc) & 7 ) ) )
+#define sbitset( m, cc ) ( m[(cc) >> 3] & ( 1 << ( (cc) & 7 ) ) )
+
+
+ /* An empty string for empty fields. */
+
+ static char empty[1] = { 0 }; /* XXX eliminate this */
+
+
+ /* Assume the line is NULL-terminated and that the `list' parameter */
+ /* was initialized the first time it was used. */
+
+ static FT_Error
+ _bdf_split( char* separators,
+ char* line,
+ unsigned long linelen,
+ _bdf_list_t* list,
+ FT_Memory memory )
+ {
+ int mult, final_empty;
+ char *sp, *ep, *end;
+ char seps[32];
+ FT_Error error = BDF_Err_Ok;
+
+
+ /* Initialize the list. */
+ list->used = 0;
+
+ /* If the line is empty, then simply return. */
+ if ( linelen == 0 || line[0] == 0 )
+ goto Exit;
+
+ /* In the original code, if the `separators' parameter is NULL or */
+ /* empty, the list is split into individual bytes. We don't need */
+ /* this, so an error is signaled. */
+ if ( separators == 0 || *separators == 0 )
+ {
+ error = BDF_Err_Invalid_Argument;
+ goto Exit;
+ }
+
+ /* Prepare the separator bitmap. */
+ FT_MEM_ZERO( seps, 32 );
+
+ /* If the very last character of the separator string is a plus, then */
+ /* set the `mult' flag to indicate that multiple separators should be */
+ /* collapsed into one. */
+ for ( mult = 0, sp = separators; sp && *sp; sp++ )
+ {
+ if ( *sp == '+' && *( sp + 1 ) == 0 )
+ mult = 1;
+ else
+ setsbit( seps, *sp );
+ }
+
+ /* Break the line up into fields. */
+ for ( final_empty = 0, sp = ep = line, end = sp + linelen;
+ sp < end && *sp; )
+ {
+ /* Collect everything that is not a separator. */
+ for ( ; *ep && !sbitset( seps, *ep ); ep++ )
+ ;
+
+ /* Resize the list if necessary. */
+ if ( list->used == list->size )
+ {
+ if ( list->size == 0 )
+ {
+ if ( FT_NEW_ARRAY( list->field, 5 ) )
+ goto Exit;
+ }
+ else
+ {
+ if ( FT_RENEW_ARRAY ( list->field ,
+ list->size,
+ list->size + 5 ) )
+ goto Exit;
+ }
+
+ list->size += 5;
+ }
+
+ /* Assign the field appropriately. */
+ list->field[list->used++] = ( ep > sp ) ? sp : empty;
+
+ sp = ep;
+
+ if ( mult )
+ {
+ /* If multiple separators should be collapsed, do it now by */
+ /* setting all the separator characters to 0. */
+ for ( ; *ep && sbitset( seps, *ep ); ep++ )
+ *ep = 0;
+ }
+ else if ( *ep != 0 )
+ /* Don't collapse multiple separators by making them 0, so just */
+ /* make the one encountered 0. */
+ *ep++ = 0;
+
+ final_empty = ( ep > sp && *ep == 0 );
+ sp = ep;
+ }
+
+ /* Finally, NULL-terminate the list. */
+ if ( list->used + final_empty + 1 >= list->size )
+ {
+ if ( list->used == list->size )
+ {
+ if ( list->size == 0 )
+ {
+ if ( FT_NEW_ARRAY( list->field, 5 ) )
+ goto Exit;
+ }
+ else
+ {
+ if ( FT_RENEW_ARRAY( list->field,
+ list->size,
+ list->size + 5 ) )
+ goto Exit;
+ }
+
+ list->size += 5;
+ }
+ }
+
+ if ( final_empty )
+ list->field[list->used++] = empty;
+
+ if ( list->used == list->size )
+ {
+ if ( list->size == 0 )
+ {
+ if ( FT_NEW_ARRAY( list->field, 5 ) )
+ goto Exit;
+ }
+ else
+ {
+ if ( FT_RENEW_ARRAY( list->field,
+ list->size,
+ list->size + 5 ) )
+ goto Exit;
+ }
+
+ list->size += 5;
+ }
+
+ list->field[list->used] = 0;
+
+ Exit:
+ return error;
+ }
+
+
+ static void
+ _bdf_shift( unsigned long n,
+ _bdf_list_t* list )
+ {
+ unsigned long i, u;
+
+
+ if ( list == 0 || list->used == 0 || n == 0 )
+ return;
+
+ if ( n >= list->used )
+ {
+ list->used = 0;
+ return;
+ }
+
+ for ( u = n, i = 0; u < list->used; i++, u++ )
+ list->field[i] = list->field[u];
+ list->used -= n;
+ }
+
+
+ static char *
+ _bdf_join( int c,
+ unsigned long* len,
+ _bdf_list_t* list )
+ {
+ unsigned long i, j;
+ char *fp, *dp;
+
+
+ if ( list == 0 || list->used == 0 )
+ return 0;
+
+ *len = 0;
+
+ dp = list->field[0];
+ for ( i = j = 0; i < list->used; i++ )
+ {
+ fp = list->field[i];
+ while ( *fp )
+ dp[j++] = *fp++;
+
+ if ( i + 1 < list->used )
+ dp[j++] = (char)c;
+ }
+ dp[j] = 0;
+
+ *len = j;
+ return dp;
+ }
+
+
+ /* High speed file reader that passes each line to a callback. */
+ static FT_Error
+ bdf_internal_readstream( FT_Stream stream,
+ char* buffer,
+ int count,
+ int *read_bytes )
+ {
+ int rbytes;
+ unsigned long pos = stream->pos;
+ FT_Error error = BDF_Err_Ok;
+
+
+ if ( pos > stream->size )
+ {
+ FT_ERROR(( "bdf_internal_readstream:" ));
+ FT_ERROR(( " invalid i/o; pos = 0x%lx, size = 0x%lx\n",
+ pos, stream->size ));
+ error = BDF_Err_Invalid_Stream_Operation;
+ goto Exit;
+ }
+
+ if ( stream->read )
+ rbytes = stream->read( stream, pos,
+ (unsigned char *)buffer, count );
+ else
+ {
+ rbytes = stream->size - pos;
+ if ( rbytes > count )
+ rbytes = count;
+
+ FT_MEM_COPY( buffer, stream->base + pos, rbytes );
+ }
+
+ stream->pos = pos + rbytes;
+
+ *read_bytes = rbytes;
+
+ Exit:
+ return error;
+ }
+
+
+ static FT_Error
+ _bdf_readstream( FT_Stream stream,
+ _bdf_line_func_t callback,
+ void* client_data,
+ unsigned long *lno )
+ {
+ _bdf_line_func_t cb;
+ unsigned long lineno;
+ int n, res, done, refill, bytes, hold;
+ char *ls, *le, *pp, *pe, *hp;
+ char *buf = 0;
+ FT_Memory memory = stream->memory;
+ FT_Error error = BDF_Err_Ok;
+
+
+ if ( callback == 0 )
+ {
+ error = BDF_Err_Invalid_Argument;
+ goto Exit;
+ }
+
+ if ( FT_NEW_ARRAY( buf, 65536L ) )
+ goto Exit;
+
+ cb = callback;
+ lineno = 1;
+ buf[0] = 0;
+
+ res = done = 0;
+ pp = ls = le = buf;
+
+ bytes = 65536L;
+
+ while ( !done )
+ {
+ error = bdf_internal_readstream( stream, pp, bytes, &n );
+ if ( error )
+ goto Exit;
+
+ if ( n == 0 )
+ break;
+
+ /* Determine the new end of the buffer pages. */
+ pe = pp + n;
+
+ for ( refill = 0; done == 0 && refill == 0; )
+ {
+ while ( le < pe && *le != '\n' && *le != '\r' )
+ le++;
+
+ if ( le == pe )
+ {
+ /* Hit the end of the last page in the buffer. Need to find */
+ /* out how many pages to shift and how many pages need to be */
+ /* read in. Adjust the line start and end pointers down to */
+ /* point to the right places in the pages. */
+
+ pp = buf + ( ( ( ls - buf ) >> 13 ) << 13 );
+ n = pp - buf;
+ ls -= n;
+ le -= n;
+ n = pe - pp;
+
+ FT_MEM_COPY( buf, pp, n );
+
+ pp = buf + n;
+ bytes = 65536L - n;
+ refill = 1;
+ }
+ else
+ {
+ /* Temporarily NULL-terminate the line. */
+ hp = le;
+ hold = *le;
+ *le = 0;
+
+ /* XXX: Use encoding independent value for 0x1a */
+ if ( *ls != '#' && *ls != 0x1a &&
+ le > ls &&
+ ( error = (*cb)( ls, le - ls, lineno, (void *)&cb,
+ client_data ) ) != BDF_Err_Ok )
+ done = 1;
+ else
+ {
+ ls = ++le;
+ /* Handle the case of DOS crlf sequences. */
+ if ( le < pe && hold == '\n' && *le =='\r' )
+ ls = ++le;
+ }
+
+ /* Increment the line number. */
+ lineno++;
+
+ /* Restore the character at the end of the line. */
+ *hp = (char)hold;
+ }
+ }
+ }
+
+ *lno = lineno;
+
+ Exit:
+ FT_FREE( buf );
+ return error;
+ }
+
+
+ /* XXX: make this work with EBCDIC also */
+
+ static const unsigned char a2i[128] =
+ {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+ };
+
+ static const unsigned char odigits[32] =
+ {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ };
+
+ static const unsigned char ddigits[32] =
+ {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x03,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ };
+
+ static const unsigned char hdigits[32] =
+ {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x03,
+ 0x7e, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ };
+
+
+#define isdigok( m, d ) (m[(d) >> 3] & ( 1 << ( (d) & 7 ) ) )
+
+
+ /* Routine to convert an ASCII string into an unsigned long integer. */
+ static unsigned long
+ _bdf_atoul( char* s,
+ char** end,
+ int base )
+ {
+ unsigned long v;
+ const unsigned char* dmap;
+
+
+ if ( s == 0 || *s == 0 )
+ return 0;
+
+ /* Make sure the radix is something recognizable. Default to 10. */
+ switch ( base )
+ {
+ case 8:
+ dmap = odigits;
+ break;
+ case 16:
+ dmap = hdigits;
+ break;
+ default:
+ base = 10;
+ dmap = ddigits;
+ break;
+ }
+
+ /* Check for the special hex prefix. */
+ if ( *s == '0' &&
+ ( *( s + 1 ) == 'x' || *( s + 1 ) == 'X' ) )
+ {
+ base = 16;
+ dmap = hdigits;
+ s += 2;
+ }
+
+ for ( v = 0; isdigok( dmap, *s ); s++ )
+ v = v * base + a2i[(int)*s];
+
+ if ( end != 0 )
+ *end = s;
+
+ return v;
+ }
+
+
+ /* Routine to convert an ASCII string into an signed long integer. */
+ static long
+ _bdf_atol( char* s,
+ char** end,
+ int base )
+ {
+ long v, neg;
+ const unsigned char* dmap;
+
+
+ if ( s == 0 || *s == 0 )
+ return 0;
+
+ /* Make sure the radix is something recognizable. Default to 10. */
+ switch ( base )
+ {
+ case 8:
+ dmap = odigits;
+ break;
+ case 16:
+ dmap = hdigits;
+ break;
+ default:
+ base = 10;
+ dmap = ddigits;
+ break;
+ }
+
+ /* Check for a minus sign. */
+ neg = 0;
+ if ( *s == '-' )
+ {
+ s++;
+ neg = 1;
+ }
+
+ /* Check for the special hex prefix. */
+ if ( *s == '0' &&
+ ( *( s + 1 ) == 'x' || *( s + 1 ) == 'X' ) )
+ {
+ base = 16;
+ dmap = hdigits;
+ s += 2;
+ }
+
+ for ( v = 0; isdigok( dmap, *s ); s++ )
+ v = v * base + a2i[(int)*s];
+
+ if ( end != 0 )
+ *end = s;
+
+ return ( !neg ) ? v : -v;
+ }
+
+
+ /* Routine to convert an ASCII string into an signed short integer. */
+ static short
+ _bdf_atos( char* s,
+ char** end,
+ int base )
+ {
+ short v, neg;
+ const unsigned char* dmap;
+
+
+ if ( s == 0 || *s == 0 )
+ return 0;
+
+ /* Make sure the radix is something recognizable. Default to 10. */
+ switch ( base )
+ {
+ case 8:
+ dmap = odigits;
+ break;
+ case 16:
+ dmap = hdigits;
+ break;
+ default:
+ base = 10;
+ dmap = ddigits;
+ break;
+ }
+
+ /* Check for a minus. */
+ neg = 0;
+ if ( *s == '-' )
+ {
+ s++;
+ neg = 1;
+ }
+
+ /* Check for the special hex prefix. */
+ if ( *s == '0' &&
+ ( *( s + 1 ) == 'x' || *( s + 1 ) == 'X' ) )
+ {
+ base = 16;
+ dmap = hdigits;
+ s += 2;
+ }
+
+ for ( v = 0; isdigok( dmap, *s ); s++ )
+ v = (short)( v * base + a2i[(int)*s] );
+
+ if ( end != 0 )
+ *end = s;
+
+ return (short)( ( !neg ) ? v : -v );
+ }
+
+
+ /* Routine to compare two glyphs by encoding so they can be sorted. */
+ static int
+ by_encoding( const void* a,
+ const void* b )
+ {
+ bdf_glyph_t *c1, *c2;
+
+
+ c1 = (bdf_glyph_t *)a;
+ c2 = (bdf_glyph_t *)b;
+
+ if ( c1->encoding < c2->encoding )
+ return -1;
+ else if ( c1->encoding > c2->encoding )
+ return 1;
+
+ return 0;
+ }
+
+
+ static FT_Error
+ bdf_create_property( char* name,
+ int format,
+ bdf_font_t* font )
+ {
+ unsigned long n;
+ bdf_property_t* p;
+ FT_Memory memory = font->memory;
+ FT_Error error = BDF_Err_Ok;
+
+
+ /* First check to see if the property has */
+ /* already been added or not. If it has, then */
+ /* simply ignore it. */
+ if ( hash_lookup( name, &(font->proptbl) ) )
+ goto Exit;
+
+ if ( font->nuser_props == 0 )
+ {
+ if ( FT_NEW_ARRAY( font->user_props, 1 ) )
+ goto Exit;
+ }
+ else
+ {
+ if ( FT_RENEW_ARRAY( font->user_props,
+ font->nuser_props,
+ font->nuser_props + 1 ) )
+ goto Exit;
+ }
+
+ p = font->user_props + font->nuser_props;
+ FT_MEM_ZERO( p, sizeof ( bdf_property_t ) );
+
+ n = (unsigned long)( ft_strlen( name ) + 1 );
+ if ( FT_NEW_ARRAY( p->name, n ) )
+ goto Exit;
+
+ FT_MEM_COPY( (char *)p->name, name, n );
+
+ p->format = format;
+ p->builtin = 0;
+
+ n = _num_bdf_properties + font->nuser_props;
+
+ error = hash_insert( p->name, (void *)n, &(font->proptbl), memory );
+ if ( error )
+ goto Exit;
+
+ font->nuser_props++;
+
+ Exit:
+ return error;
+ }
+
+
+ FT_LOCAL_DEF( bdf_property_t * )
+ bdf_get_property( char* name,
+ bdf_font_t* font )
+ {
+ hashnode hn;
+ unsigned long propid;
+
+
+ if ( name == 0 || *name == 0 )
+ return 0;
+
+ if ( ( hn = hash_lookup( name, &(font->proptbl) ) ) == 0 )
+ return 0;
+
+ propid = (unsigned long)hn->data;
+ if ( propid >= _num_bdf_properties )
+ return font->user_props + ( propid - _num_bdf_properties );
+
+ return (bdf_property_t*)_bdf_properties + propid;
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* BDF font file parsing flags and functions. */
+ /* */
+ /*************************************************************************/
+
+
+ /* Parse flags. */
+
+#define _BDF_START 0x0001
+#define _BDF_FONT_NAME 0x0002
+#define _BDF_SIZE 0x0004
+#define _BDF_FONT_BBX 0x0008
+#define _BDF_PROPS 0x0010
+#define _BDF_GLYPHS 0x0020
+#define _BDF_GLYPH 0x0040
+#define _BDF_ENCODING 0x0080
+#define _BDF_SWIDTH 0x0100
+#define _BDF_DWIDTH 0x0200
+#define _BDF_BBX 0x0400
+#define _BDF_BITMAP 0x0800
+
+#define _BDF_SWIDTH_ADJ 0x1000
+
+#define _BDF_GLYPH_BITS ( _BDF_GLYPH | \
+ _BDF_ENCODING | \
+ _BDF_SWIDTH | \
+ _BDF_DWIDTH | \
+ _BDF_BBX | \
+ _BDF_BITMAP )
+
+#define _BDF_GLYPH_WIDTH_CHECK 0x40000000L
+#define _BDF_GLYPH_HEIGHT_CHECK 0x80000000L
+
+
+ /* Auto correction messages. */
+#define ACMSG1 "FONT_ASCENT property missing. " \
+ "Added \"FONT_ASCENT %hd\".\n"
+#define ACMSG2 "FONT_DESCENT property missing. " \
+ "Added \"FONT_DESCENT %hd\".\n"
+#define ACMSG3 "Font width != actual width. Old: %hd New: %hd.\n"
+#define ACMSG4 "Font left bearing != actual left bearing. " \
+ "Old: %hd New: %hd.\n"
+#define ACMSG5 "Font ascent != actual ascent. Old: %hd New: %hd.\n"
+#define ACMSG6 "Font descent != actual descent. Old: %hd New: %hd.\n"
+#define ACMSG7 "Font height != actual height. Old: %hd New: %hd.\n"
+#define ACMSG8 "Glyph scalable width (SWIDTH) adjustments made.\n"
+#define ACMSG9 "SWIDTH field missing at line %ld. Set automatically.\n"
+#define ACMSG10 "DWIDTH field missing at line %ld. Set to glyph width.\n"
+#define ACMSG11 "SIZE bits per pixel field adjusted to %hd.\n"
+#define ACMSG12 "Duplicate encoding %ld (%s) changed to unencoded.\n"
+#define ACMSG13 "Glyph %ld extra rows removed.\n"
+#define ACMSG14 "Glyph %ld extra columns removed.\n"
+#define ACMSG15 "Incorrect glyph count: %ld indicated but %ld found.\n"
+
+ /* Error messages. */
+#define ERRMSG1 "[line %ld] Missing \"%s\" line.\n"
+#define ERRMSG2 "[line %ld] Font header corrupted or missing fields.\n"
+#define ERRMSG3 "[line %ld] Font glyphs corrupted or missing fields.\n"
+
+
+ static FT_Error
+ _bdf_add_comment( bdf_font_t* font,
+ char* comment,
+ unsigned long len )
+ {
+ char* cp;
+ FT_Memory memory = font->memory;
+ FT_Error error = BDF_Err_Ok;
+
+
+ if ( font->comments_len == 0 )
+ {
+ if ( FT_NEW_ARRAY( font->comments, len + 1 ) )
+ goto Exit;
+ }
+ else
+ {
+ if ( FT_RENEW_ARRAY( font->comments,
+ font->comments_len,
+ font->comments_len + len + 1 ) )
+ goto Exit;
+ }
+
+ cp = font->comments + font->comments_len;
+ FT_MEM_COPY( cp, comment, len );
+ cp += len;
+ *cp++ = '\n';
+ font->comments_len += len + 1;
+
+ Exit:
+ return error;
+ }
+
+
+ /* Set the spacing from the font name if it exists, or set it to the */
+ /* default specified in the options. */
+ static FT_Error
+ _bdf_set_default_spacing( bdf_font_t* font,
+ bdf_options_t* opts )
+ {
+ unsigned long len;
+ char name[128];
+ _bdf_list_t list;
+ FT_Memory memory;
+ FT_Error error = BDF_Err_Ok;
+
+
+ if ( font == 0 || font->name == 0 || font->name[0] == 0 )
+ {
+ error = BDF_Err_Invalid_Argument;
+ goto Exit;
+ }
+
+ memory = font->memory;
+
+ font->spacing = opts->font_spacing;
+
+ len = (unsigned long)( ft_strlen( font->name ) + 1 );
+ FT_MEM_COPY( name, font->name, len );
+
+ list.size = list.used = 0;
+
+ error = _bdf_split( (char *)"-", name, len, &list, memory );
+ if ( error )
+ goto Exit;
+
+ if ( list.used == 15 )
+ {
+ switch ( list.field[11][0] )
+ {
+ case 'C':
+ case 'c':
+ font->spacing = BDF_CHARCELL;
+ break;
+ case 'M':
+ case 'm':
+ font->spacing = BDF_MONOWIDTH;
+ break;
+ case 'P':
+ case 'p':
+ font->spacing = BDF_PROPORTIONAL;
+ break;
+ }
+ }
+
+ FT_FREE( list.field );
+
+ Exit:
+ return error;
+ }
+
+
+ /* Determine whether the property is an atom or not. If it is, then */
+ /* clean it up so the double quotes are removed if they exist. */
+ static int
+ _bdf_is_atom( char* line,
+ unsigned long linelen,
+ char** name,
+ char** value,
+ bdf_font_t* font )
+ {
+ int hold;
+ char *sp, *ep;
+ bdf_property_t* p;
+
+
+ *name = sp = ep = line;
+
+ while ( *ep && *ep != ' ' && *ep != '\t' )
+ ep++;
+
+ hold = -1;
+ if ( *ep )
+ {
+ hold = *ep;
+ *ep = 0;
+ }
+
+ p = bdf_get_property( sp, font );
+
+ /* Restore the character that was saved before any return can happen. */
+ if ( hold != -1 )
+ *ep = (char)hold;
+
+ /* If the property exists and is not an atom, just return here. */
+ if ( p && p->format != BDF_ATOM )
+ return 0;
+
+ /* The property is an atom. Trim all leading and trailing whitespace */
+ /* and double quotes for the atom value. */
+ sp = ep;
+ ep = line + linelen;
+
+ /* Trim the leading whitespace if it exists. */
+ *sp++ = 0;
+ while ( *sp &&
+ ( *sp == ' ' || *sp == '\t' ) )
+ sp++;
+
+ /* Trim the leading double quote if it exists. */
+ if ( *sp == '"' )
+ sp++;
+ *value = sp;
+
+ /* Trim the trailing whitespace if it exists. */
+ while ( ep > sp &&
+ ( *( ep - 1 ) == ' ' || *( ep - 1 ) == '\t' ) )
+ *--ep = 0;
+
+ /* Trim the trailing double quote if it exists. */
+ if ( ep > sp && *( ep - 1 ) == '"' )
+ *--ep = 0;
+
+ return 1;
+ }
+
+
+ static FT_Error
+ _bdf_add_property( bdf_font_t* font,
+ char* name,
+ char* value )
+ {
+ unsigned long propid;
+ hashnode hn;
+ int len;
+ bdf_property_t *prop, *fp;
+ FT_Memory memory = font->memory;
+ FT_Error error = BDF_Err_Ok;
+
+
+ /* First, check to see if the property already exists in the font. */
+ if ( ( hn = hash_lookup( name, (hashtable *)font->internal ) ) != 0 )
+ {
+ /* The property already exists in the font, so simply replace */
+ /* the value of the property with the current value. */
+ fp = font->props + (unsigned long)hn->data;
+
+ switch ( fp->format )
+ {
+ case BDF_ATOM:
+ /* Delete the current atom if it exists. */
+ FT_FREE( fp->value.atom );
+
+ if ( value == 0 )
+ len = 1;
+ else
+ len = ft_strlen( value ) + 1;
+
+ if ( len > 1 )
+ {
+ if ( FT_NEW_ARRAY( fp->value.atom, len ) )
+ goto Exit;
+ FT_MEM_COPY( fp->value.atom, value, len );
+ }
+ else
+ fp->value.atom = 0;
+ break;
+
+ case BDF_INTEGER:
+ fp->value.int32 = _bdf_atol( value, 0, 10 );
+ break;
+
+ case BDF_CARDINAL:
+ fp->value.card32 = _bdf_atoul( value, 0, 10 );
+ break;
+
+ default:
+ ;
+ }
+
+ goto Exit;
+ }
+
+ /* See whether this property type exists yet or not. */
+ /* If not, create it. */
+ hn = hash_lookup( name, &(font->proptbl) );
+ if ( hn == 0 )
+ {
+ error = bdf_create_property( name, BDF_ATOM, font );
+ if ( error )
+ goto Exit;
+ hn = hash_lookup( name, &(font->proptbl) );
+ }
+
+ /* Allocate another property if this is overflow. */
+ if ( font->props_used == font->props_size )
+ {
+ if ( font->props_size == 0 )
+ {
+ if ( FT_NEW_ARRAY( font->props, 1 ) )
+ goto Exit;
+ }
+ else
+ {
+ if ( FT_RENEW_ARRAY( font->props,
+ font->props_size,
+ font->props_size + 1 ) )
+ goto Exit;
+ }
+
+ fp = font->props + font->props_size;
+ FT_MEM_ZERO( fp, sizeof ( bdf_property_t ) );
+ font->props_size++;
+ }
+
+ propid = (unsigned long)hn->data;
+ if ( propid >= _num_bdf_properties )
+ prop = font->user_props + ( propid - _num_bdf_properties );
+ else
+ prop = (bdf_property_t*)_bdf_properties + propid;
+
+ fp = font->props + font->props_used;
+
+ fp->name = prop->name;
+ fp->format = prop->format;
+ fp->builtin = prop->builtin;
+
+ switch ( prop->format )
+ {
+ case BDF_ATOM:
+ if ( value == 0 )
+ len = 1;
+ else
+ len = ft_strlen( value ) + 1;
+
+ if ( len > 1 )
+ {
+ if ( FT_NEW_ARRAY( fp->value.atom, len ) )
+ goto Exit;
+ FT_MEM_COPY( fp->value.atom, value, len );
+ }
+ else
+ fp->value.atom = 0;
+ break;
+
+ case BDF_INTEGER:
+ fp->value.int32 = _bdf_atol( value, 0, 10 );
+ break;
+
+ case BDF_CARDINAL:
+ fp->value.card32 = _bdf_atoul( value, 0, 10 );
+ break;
+ }
+
+ /* If the property happens to be a comment, then it doesn't need */
+ /* to be added to the internal hash table. */
+ if ( ft_memcmp( name, "COMMENT", 7 ) != 0 ) {
+ /* Add the property to the font property table. */
+ error = hash_insert( fp->name,
+ (void *)font->props_used,
+ (hashtable *)font->internal,
+ memory );
+ if ( error )
+ goto Exit;
+ }
+
+ font->props_used++;
+
+ /* Some special cases need to be handled here. The DEFAULT_CHAR */
+ /* property needs to be located if it exists in the property list, the */
+ /* FONT_ASCENT and FONT_DESCENT need to be assigned if they are */
+ /* present, and the SPACING property should override the default */
+ /* spacing. */
+ if ( ft_memcmp( name, "DEFAULT_CHAR", 12 ) == 0 )
+ font->default_glyph = fp->value.int32;
+ else if ( ft_memcmp( name, "FONT_ASCENT", 11 ) == 0 )
+ font->font_ascent = fp->value.int32;
+ else if ( ft_memcmp( name, "FONT_DESCENT", 12 ) == 0 )
+ font->font_descent = fp->value.int32;
+ else if ( ft_memcmp( name, "SPACING", 7 ) == 0 )
+ {
+ if ( fp->value.atom[0] == 'p' || fp->value.atom[0] == 'P' )
+ font->spacing = BDF_PROPORTIONAL;
+ else if ( fp->value.atom[0] == 'm' || fp->value.atom[0] == 'M' )
+ font->spacing = BDF_MONOWIDTH;
+ else if ( fp->value.atom[0] == 'c' || fp->value.atom[0] == 'C' )
+ font->spacing = BDF_CHARCELL;
+ }
+
+ Exit:
+ return error;
+ }
+
+
+ static const unsigned char nibble_mask[8] =
+ {
+ 0xFF, 0x80, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC, 0xFE
+ };
+
+
+ /* Actually parse the glyph info and bitmaps. */
+ static FT_Error
+ _bdf_parse_glyphs( char* line,
+ unsigned long linelen,
+ unsigned long lineno,
+ void* call_data,
+ void* client_data )
+ {
+ int c, mask_index;
+ char* s;
+ unsigned char* bp;
+ unsigned long i, slen, nibbles;
+
+ _bdf_line_func_t* next;
+ _bdf_parse_t* p;
+ bdf_glyph_t* glyph;
+ bdf_font_t* font;
+
+ FT_Memory memory;
+ FT_Error error = BDF_Err_Ok;
+
+ FT_UNUSED( lineno ); /* only used in debug mode */
+
+
+ next = (_bdf_line_func_t *)call_data;
+ p = (_bdf_parse_t *) client_data;
+
+ font = p->font;
+ memory = font->memory;
+
+ /* Check for a comment. */
+ if ( ft_memcmp( line, "COMMENT", 7 ) == 0 )
+ {
+ linelen -= 7;
+
+ s = line + 7;
+ if ( *s != 0 )
+ {
+ s++;
+ linelen--;
+ }
+ error = _bdf_add_comment( p->font, s, linelen );
+ goto Exit;
+ }
+
+ /* The very first thing expected is the number of glyphs. */
+ if ( !( p->flags & _BDF_GLYPHS ) )
+ {
+ if ( ft_memcmp( line, "CHARS", 5 ) != 0 )
+ {
+ FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG1, lineno, "CHARS" ));
+ error = BDF_Err_Missing_Chars_Field;
+ goto Exit;
+ }
+
+ error = _bdf_split( (char *)" +", line, linelen, &p->list, memory );
+ if ( error )
+ goto Exit;
+ p->cnt = font->glyphs_size = _bdf_atoul( p->list.field[1], 0, 10 );
+
+ /* Make sure the number of glyphs is non-zero. */
+ if ( p->cnt == 0 )
+ font->glyphs_size = 64;
+
+ if ( FT_NEW_ARRAY( font->glyphs, font->glyphs_size ) )
+ goto Exit;
+
+ p->flags |= _BDF_GLYPHS;
+
+ goto Exit;
+ }
+
+ /* Check for the ENDFONT field. */
+ if ( ft_memcmp( line, "ENDFONT", 7 ) == 0 )
+ {
+ /* Sort the glyphs by encoding. */
+ ft_qsort( (char *)font->glyphs,
+ font->glyphs_used,
+ sizeof ( bdf_glyph_t ),
+ by_encoding );
+
+ p->flags &= ~_BDF_START;
+
+ goto Exit;
+ }
+
+ /* Check for the ENDCHAR field. */
+ if ( ft_memcmp( line, "ENDCHAR", 7 ) == 0 )
+ {
+ p->glyph_enc = 0;
+ p->flags &= ~_BDF_GLYPH_BITS;
+
+ goto Exit;
+ }
+
+ /* Check to see whether a glyph is being scanned but should be */
+ /* ignored because it is an unencoded glyph. */
+ if ( ( p->flags & _BDF_GLYPH ) &&
+ p->glyph_enc == -1 &&
+ p->opts->keep_unencoded == 0 )
+ goto Exit;
+
+ /* Check for the STARTCHAR field. */
+ if ( ft_memcmp( line, "STARTCHAR", 9 ) == 0 )
+ {
+ /* Set the character name in the parse info first until the */
+ /* encoding can be checked for an unencoded character. */
+ FT_FREE( p->glyph_name );
+
+ error = _bdf_split( (char *)" +", line, linelen, &p->list,memory );
+ if ( error )
+ goto Exit;
+ _bdf_shift( 1, &p->list );
+
+ s = _bdf_join( ' ', &slen, &p->list );
+
+ if ( FT_NEW_ARRAY( p->glyph_name, slen + 1 ) )
+ goto Exit;
+ FT_MEM_COPY( p->glyph_name, s, slen + 1 );
+
+ p->flags |= _BDF_GLYPH;
+
+ goto Exit;
+ }
+
+ /* Check for the ENCODING field. */
+ if ( ft_memcmp( line, "ENCODING", 8 ) == 0 )
+ {
+ if ( !( p->flags & _BDF_GLYPH ) )
+ {
+ /* Missing STARTCHAR field. */
+ FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG1, lineno, "STARTCHAR" ));
+ error = BDF_Err_Missing_Startchar_Field;
+ goto Exit;
+ }
+
+ error = _bdf_split( (char *)" +", line, linelen, &p->list, memory );
+ if ( error )
+ goto Exit;
+ p->glyph_enc = _bdf_atol( p->list.field[1], 0, 10 );
+
+ /* Check to see whether this encoding has already been encountered. */
+ /* If it has then change it to unencoded so it gets added if */
+ /* indicated. */
+ if ( p->glyph_enc >= 0 )
+ {
+ if ( _bdf_glyph_modified( p->have, p->glyph_enc ) )
+ {
+ /* Emit a message saying a glyph has been moved to the */
+ /* unencoded area. */
+ FT_TRACE2(( "_bdf_parse_glyphs: " ACMSG12,
+ p->glyph_enc, p->glyph_name ));
+ p->glyph_enc = -1;
+ font->modified = 1;
+ }
+ else
+ _bdf_set_glyph_modified( p->have, p->glyph_enc );
+ }
+
+ if ( p->glyph_enc >= 0 )
+ {
+ /* Make sure there are enough glyphs allocated in case the */
+ /* number of characters happen to be wrong. */
+ if ( font->glyphs_used == font->glyphs_size )
+ {
+ if ( FT_RENEW_ARRAY( font->glyphs,
+ font->glyphs_size,
+ font->glyphs_size + 64 ) )
+ goto Exit;
+ FT_MEM_ZERO( font->glyphs + font->glyphs_size,
+ sizeof ( bdf_glyph_t ) * 64 ); /* FZ inutile */
+ font->glyphs_size += 64;
+ }
+
+ glyph = font->glyphs + font->glyphs_used++;
+ glyph->name = p->glyph_name;
+ glyph->encoding = p->glyph_enc;
+
+ /* Reset the initial glyph info. */
+ p->glyph_name = 0;
+ }
+ else
+ {
+ /* Unencoded glyph. Check to see whether it should */
+ /* be added or not. */
+ if ( p->opts->keep_unencoded != 0 )
+ {
+ /* Allocate the next unencoded glyph. */
+ if ( font->unencoded_used == font->unencoded_size )
+ {
+ if ( font->unencoded_size == 0 )
+ {
+ if ( FT_NEW_ARRAY( font->unencoded, 4 ) )
+ goto Exit;
+ }
+ else
+ {
+ if ( FT_RENEW_ARRAY( font->unencoded ,
+ font->unencoded_size,
+ font->unencoded_size + 4 ) )
+ goto Exit;
+ }
+ font->unencoded_size += 4;
+ }
+
+ glyph = font->unencoded + font->unencoded_used;
+ glyph->name = p->glyph_name;
+ glyph->encoding = font->unencoded_used++;
+ }
+ else
+ /* Free up the glyph name if the unencoded shouldn't be */
+ /* kept. */
+ FT_FREE( p->glyph_name );
+
+ p->glyph_name = 0;
+ }
+
+ /* Clear the flags that might be added when width and height are */
+ /* checked for consistency. */
+ p->flags &= ~( _BDF_GLYPH_WIDTH_CHECK | _BDF_GLYPH_HEIGHT_CHECK );
+
+ p->flags |= _BDF_ENCODING;
+
+ goto Exit;
+ }
+
+ /* Point at the glyph being constructed. */
+ if ( p->glyph_enc == -1 )
+ glyph = font->unencoded + ( font->unencoded_used - 1 );
+ else
+ glyph = font->glyphs + ( font->glyphs_used - 1 );
+
+ /* Check to see whether a bitmap is being constructed. */
+ if ( p->flags & _BDF_BITMAP )
+ {
+ /* If there are more rows than are specified in the glyph metrics, */
+ /* ignore the remaining lines. */
+ if ( p->row >= (unsigned long)glyph->bbx.height )
+ {
+ if ( !( p->flags & _BDF_GLYPH_HEIGHT_CHECK ) )
+ {
+ FT_TRACE2(( "_bdf_parse_glyphs: " ACMSG13, glyph->encoding ));
+ p->flags |= _BDF_GLYPH_HEIGHT_CHECK;
+ font->modified = 1;
+ }
+
+ goto Exit;
+ }
+
+ /* Only collect the number of nibbles indicated by the glyph */
+ /* metrics. If there are more columns, they are simply ignored. */
+ nibbles = glyph->bpr << 1;
+ bp = glyph->bitmap + p->row * glyph->bpr;
+
+ for ( i = 0, *bp = 0; i < nibbles; i++ )
+ {
+ c = line[i];
+ *bp = (FT_Byte)( ( *bp << 4 ) + a2i[c] );
+ if ( i + 1 < nibbles && ( i & 1 ) )
+ *++bp = 0;
+ }
+
+ /* Remove possible garbage at the right. */
+ mask_index = ( glyph->bbx.width * p->font->bpp ) & 7;
+ *bp &= nibble_mask[mask_index];
+
+ /* If any line has extra columns, indicate they have been removed. */
+ if ( ( line[nibbles] == '0' || a2i[(int)line[nibbles]] != 0 ) &&
+ !( p->flags & _BDF_GLYPH_WIDTH_CHECK ) )
+ {
+ FT_TRACE2(( "_bdf_parse_glyphs: " ACMSG14, glyph->encoding ));
+ p->flags |= _BDF_GLYPH_WIDTH_CHECK;
+ font->modified = 1;
+ }
+
+ p->row++;
+ goto Exit;
+ }
+
+ /* Expect the SWIDTH (scalable width) field next. */
+ if ( ft_memcmp( line, "SWIDTH", 6 ) == 0 )
+ {
+ if ( !( p->flags & _BDF_ENCODING ) )
+ {
+ /* Missing ENCODING field. */
+ FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG1, lineno, "ENCODING" ));
+ error = BDF_Err_Missing_Encoding_Field;
+ goto Exit;
+ }
+
+ error = _bdf_split( (char *)" +", line, linelen, &p->list, memory );
+ if ( error )
+ goto Exit;
+ glyph->swidth = (unsigned short)_bdf_atoul( p->list.field[1], 0, 10 );
+ p->flags |= _BDF_SWIDTH;
+
+ goto Exit;
+ }
+
+ /* Expect the DWIDTH (scalable width) field next. */
+ if ( ft_memcmp( line, "DWIDTH", 6 ) == 0 )
+ {
+ error = _bdf_split( (char *)" +", line, linelen, &p->list,memory );
+ if ( error )
+ goto Exit;
+ glyph->dwidth = (unsigned short)_bdf_atoul( p->list.field[1], 0, 10 );
+
+ if ( !( p->flags & _BDF_SWIDTH ) )
+ {
+ /* Missing SWIDTH field. Emit an auto correction message and set */
+ /* the scalable width from the device width. */
+ FT_TRACE2(( "_bdf_parse_glyphs: " ACMSG9, lineno ));
+
+ glyph->swidth = (unsigned short)FT_MulDiv(
+ glyph->dwidth, 72000L,
+ (FT_Long)( font->point_size *
+ font->resolution_x ) );
+ }
+
+ p->flags |= _BDF_DWIDTH;
+ goto Exit;
+ }
+
+ /* Expect the BBX field next. */
+ if ( ft_memcmp( line, "BBX", 3 ) == 0 )
+ {
+ error = _bdf_split( (char *)" +", line, linelen, &p->list, memory );
+ if ( error )
+ goto Exit;
+
+ glyph->bbx.width = _bdf_atos( p->list.field[1], 0, 10 );
+ glyph->bbx.height = _bdf_atos( p->list.field[2], 0, 10 );
+ glyph->bbx.x_offset = _bdf_atos( p->list.field[3], 0, 10 );
+ glyph->bbx.y_offset = _bdf_atos( p->list.field[4], 0, 10 );
+
+ /* Generate the ascent and descent of the character. */
+ glyph->bbx.ascent = (short)( glyph->bbx.height + glyph->bbx.y_offset );
+ glyph->bbx.descent = (short)( -glyph->bbx.y_offset );
+
+ /* Determine the overall font bounding box as the characters are */
+ /* loaded so corrections can be done later if indicated. */
+ p->maxas = (short)MAX( glyph->bbx.ascent, p->maxas );
+ p->maxds = (short)MAX( glyph->bbx.descent, p->maxds );
+
+ p->rbearing = (short)( glyph->bbx.width + glyph->bbx.x_offset );
+
+ p->maxrb = (short)MAX( p->rbearing, p->maxrb );
+ p->minlb = (short)MIN( glyph->bbx.x_offset, p->minlb );
+ p->maxlb = (short)MAX( glyph->bbx.x_offset, p->maxlb );
+
+ if ( !( p->flags & _BDF_DWIDTH ) )
+ {
+ /* Missing DWIDTH field. Emit an auto correction message and set */
+ /* the device width to the glyph width. */
+ FT_TRACE2(( "_bdf_parse_glyphs: " ACMSG10, lineno ));
+ glyph->dwidth = glyph->bbx.width;
+ }
+
+ /* If the BDF_CORRECT_METRICS flag is set, then adjust the SWIDTH */
+ /* value if necessary. */
+ if ( p->opts->correct_metrics != 0 )
+ {
+ /* Determine the point size of the glyph. */
+ unsigned short sw = (unsigned short)FT_MulDiv(
+ glyph->dwidth, 72000L,
+ (FT_Long)( font->point_size *
+ font->resolution_x ) );
+
+
+ if ( sw != glyph->swidth )
+ {
+ glyph->swidth = sw;
+
+ if ( p->glyph_enc == -1 )
+ _bdf_set_glyph_modified( font->umod,
+ font->unencoded_used - 1 );
+ else
+ _bdf_set_glyph_modified( font->nmod, glyph->encoding );
+
+ p->flags |= _BDF_SWIDTH_ADJ;
+ font->modified = 1;
+ }
+ }
+
+ p->flags |= _BDF_BBX;
+ goto Exit;
+ }
+
+ /* And finally, gather up the bitmap. */
+ if ( ft_memcmp( line, "BITMAP", 6 ) == 0 )
+ {
+ if ( !( p->flags & _BDF_BBX ) )
+ {
+ /* Missing BBX field. */
+ FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG1, lineno, "BBX" ));
+ error = BDF_Err_Missing_Bbx_Field;
+ goto Exit;
+ }
+
+ /* Allocate enough space for the bitmap. */
+ glyph->bpr = ( glyph->bbx.width * p->font->bpp + 7 ) >> 3;
+ glyph->bytes = (unsigned short)( glyph->bpr * glyph->bbx.height );
+
+ if ( FT_NEW_ARRAY( glyph->bitmap, glyph->bytes ) )
+ goto Exit;
+
+ p->row = 0;
+ p->flags |= _BDF_BITMAP;
+
+ goto Exit;
+ }
+
+ error = BDF_Err_Invalid_File_Format;
+
+ Exit:
+ return error;
+ }
+
+
+ /* Load the font properties. */
+ static FT_Error
+ _bdf_parse_properties( char* line,
+ unsigned long linelen,
+ unsigned long lineno,
+ void* call_data,
+ void* client_data )
+ {
+ unsigned long vlen;
+ _bdf_line_func_t* next;
+ _bdf_parse_t* p;
+ char* name;
+ char* value;
+ char nbuf[128];
+ FT_Memory memory;
+ FT_Error error = BDF_Err_Ok;
+
+ FT_UNUSED( lineno );
+
+
+ next = (_bdf_line_func_t *)call_data;
+ p = (_bdf_parse_t *) client_data;
+
+ memory = p->font->memory;
+
+ /* Check for the end of the properties. */
+ if ( ft_memcmp( line, "ENDPROPERTIES", 13 ) == 0 )
+ {
+ /* If the FONT_ASCENT or FONT_DESCENT properties have not been */
+ /* encountered yet, then make sure they are added as properties and */
+ /* make sure they are set from the font bounding box info. */
+ /* */
+ /* This is *always* done regardless of the options, because X11 */
+ /* requires these two fields to compile fonts. */
+ if ( bdf_get_font_property( p->font, (char *)"FONT_ASCENT" ) == 0 )
+ {
+ p->font->font_ascent = p->font->bbx.ascent;
+ ft_sprintf( nbuf, "%hd", p->font->bbx.ascent );
+ error = _bdf_add_property( p->font, (char *)"FONT_ASCENT", nbuf );
+ if ( error )
+ goto Exit;
+
+ FT_TRACE2(( "_bdf_parse_properties: " ACMSG1, p->font->bbx.ascent ));
+ p->font->modified = 1;
+ }
+
+ if ( bdf_get_font_property( p->font, (char *)"FONT_DESCENT" ) == 0 )
+ {
+ p->font->font_descent = p->font->bbx.descent;
+ ft_sprintf( nbuf, "%hd", p->font->bbx.descent );
+ error = _bdf_add_property( p->font, (char *)"FONT_DESCENT", nbuf );
+ if ( error )
+ goto Exit;
+
+ FT_TRACE2(( "_bdf_parse_properties: " ACMSG2, p->font->bbx.descent ));
+ p->font->modified = 1;
+ }
+
+ p->flags &= ~_BDF_PROPS;
+ *next = _bdf_parse_glyphs;
+
+ goto Exit;
+ }
+
+ /* Ignore the _XFREE86_GLYPH_RANGES properties. */
+ if ( ft_memcmp( line, "_XFREE86_GLYPH_RANGES", 21 ) == 0 )
+ goto Exit;
+
+ /* Handle COMMENT fields and properties in a special way to preserve */
+ /* the spacing. */
+ if ( ft_memcmp( line, "COMMENT", 7 ) == 0 )
+ {
+ name = value = line;
+ value += 7;
+ if ( *value )
+ *value++ = 0;
+ error = _bdf_add_property( p->font, name, value );
+ if ( error )
+ goto Exit;
+ }
+ else if ( _bdf_is_atom( line, linelen, &name, &value, p->font ) )
+ {
+ error = _bdf_add_property( p->font, name, value );
+ if ( error )
+ goto Exit;
+ }
+ else
+ {
+ error = _bdf_split( (char *)" +", line, linelen, &p->list, memory );
+ if ( error )
+ goto Exit;
+ name = p->list.field[0];
+
+ _bdf_shift( 1, &p->list );
+ value = _bdf_join( ' ', &vlen, &p->list );
+
+ error = _bdf_add_property( p->font, name, value );
+ if ( error )
+ goto Exit;
+ }
+
+ Exit:
+ return error;
+ }
+
+
+ /* Load the font header. */
+ static FT_Error
+ _bdf_parse_start( char* line,
+ unsigned long linelen,
+ unsigned long lineno,
+ void* call_data,
+ void* client_data )
+ {
+ unsigned long slen;
+ _bdf_line_func_t* next;
+ _bdf_parse_t* p;
+ bdf_font_t* font;
+ char *s;
+
+ FT_Memory memory = NULL;
+ FT_Error error = BDF_Err_Ok;
+
+ FT_UNUSED( lineno ); /* only used in debug mode */
+
+
+ next = (_bdf_line_func_t *)call_data;
+ p = (_bdf_parse_t *) client_data;
+
+ if ( p->font )
+ memory = p->font->memory;
+
+ /* Check for a comment. This is done to handle those fonts that have */
+ /* comments before the STARTFONT line for some reason. */
+ if ( ft_memcmp( line, "COMMENT", 7 ) == 0 )
+ {
+ if ( p->opts->keep_comments != 0 && p->font != 0 )
+ {
+ linelen -= 7;
+
+ s = line + 7;
+ if ( *s != 0 )
+ {
+ s++;
+ linelen--;
+ }
+
+ error = _bdf_add_comment( p->font, s, linelen );
+ if ( error )
+ goto Exit;
+ /* here font is not defined! */
+ }
+
+ goto Exit;
+ }
+
+ if ( !( p->flags & _BDF_START ) )
+ {
+ memory = p->memory;
+
+ if ( ft_memcmp( line, "STARTFONT", 9 ) != 0 )
+ {
+ /* No STARTFONT field is a good indication of a problem. */
+ error = BDF_Err_Missing_Startfont_Field;
+ goto Exit;
+ }
+
+ p->flags = _BDF_START;
+ font = p->font = 0;
+
+ if ( FT_NEW( font ) )
+ goto Exit;
+ p->font = font;
+
+ font->memory = p->memory;
+ p->memory = 0;
+
+ { /* setup */
+ unsigned long i;
+ bdf_property_t* prop;
+
+
+ error = hash_init( &(font->proptbl), memory );
+ if ( error )
+ goto Exit;
+ for ( i = 0, prop = (bdf_property_t*)_bdf_properties;
+ i < _num_bdf_properties; i++, prop++ )
+ {
+ error = hash_insert( prop->name, (void *)i,
+ &(font->proptbl), memory );
+ if ( error )
+ goto Exit;
+ }
+ }
+
+ if ( FT_ALLOC( p->font->internal, sizeof ( hashtable ) ) )
+ goto Exit;
+ error = hash_init( (hashtable *)p->font->internal,memory );
+ if ( error )
+ goto Exit;
+ p->font->spacing = p->opts->font_spacing;
+ p->font->default_glyph = -1;
+
+ goto Exit;
+ }
+
+ /* Check for the start of the properties. */
+ if ( ft_memcmp( line, "STARTPROPERTIES", 15 ) == 0 )
+ {
+ error = _bdf_split( (char *)" +", line, linelen, &p->list, memory );
+ if ( error )
+ goto Exit;
+ p->cnt = p->font->props_size = _bdf_atoul( p->list.field[1], 0, 10 );
+
+ if ( FT_NEW_ARRAY( p->font->props, p->cnt ) )
+ goto Exit;
+
+ p->flags |= _BDF_PROPS;
+ *next = _bdf_parse_properties;
+
+ goto Exit;
+ }
+
+ /* Check for the FONTBOUNDINGBOX field. */
+ if ( ft_memcmp( line, "FONTBOUNDINGBOX", 15 ) == 0 )
+ {
+ if ( !(p->flags & _BDF_SIZE ) )
+ {
+ /* Missing the SIZE field. */
+ FT_ERROR(( "_bdf_parse_start: " ERRMSG1, lineno, "SIZE" ));
+ error = BDF_Err_Missing_Size_Field;
+ goto Exit;
+ }
+
+ error = _bdf_split( (char *)" +", line, linelen, &p->list , memory );
+ if ( error )
+ goto Exit;
+
+ p->font->bbx.width = _bdf_atos( p->list.field[1], 0, 10 );
+ p->font->bbx.height = _bdf_atos( p->list.field[2], 0, 10 );
+
+ p->font->bbx.x_offset = _bdf_atos( p->list.field[3], 0, 10 );
+ p->font->bbx.y_offset = _bdf_atos( p->list.field[4], 0, 10 );
+
+ p->font->bbx.ascent = (short)( p->font->bbx.height +
+ p->font->bbx.y_offset );
+
+ p->font->bbx.descent = (short)( -p->font->bbx.y_offset );
+
+ p->flags |= _BDF_FONT_BBX;
+
+ goto Exit;
+ }
+
+ /* The next thing to check for is the FONT field. */
+ if ( ft_memcmp( line, "FONT", 4 ) == 0 )
+ {
+ error = _bdf_split( (char *)" +", line, linelen, &p->list , memory );
+ if ( error )
+ goto Exit;
+ _bdf_shift( 1, &p->list );
+
+ s = _bdf_join( ' ', &slen, &p->list );
+ if ( FT_NEW_ARRAY( p->font->name, slen + 1 ) )
+ goto Exit;
+ FT_MEM_COPY( p->font->name, s, slen + 1 );
+
+ /* If the font name is an XLFD name, set the spacing to the one in */
+ /* the font name. If there is no spacing fall back on the default. */
+ error = _bdf_set_default_spacing( p->font, p->opts );
+ if ( error )
+ goto Exit;
+
+ p->flags |= _BDF_FONT_NAME;
+
+ goto Exit;
+ }
+
+ /* Check for the SIZE field. */
+ if ( ft_memcmp( line, "SIZE", 4 ) == 0 )
+ {
+ if ( !( p->flags & _BDF_FONT_NAME ) )
+ {
+ /* Missing the FONT field. */
+ FT_ERROR(( "_bdf_parse_start: " ERRMSG1, lineno, "FONT" ));
+ error = BDF_Err_Missing_Font_Field;
+ goto Exit;
+ }
+
+ error = _bdf_split( (char *)" +", line, linelen, &p->list, memory );
+ if ( error )
+ goto Exit;
+
+ p->font->point_size = _bdf_atoul( p->list.field[1], 0, 10 );
+ p->font->resolution_x = _bdf_atoul( p->list.field[2], 0, 10 );
+ p->font->resolution_y = _bdf_atoul( p->list.field[3], 0, 10 );
+
+ /* Check for the bits per pixel field. */
+ if ( p->list.used == 5 )
+ {
+ unsigned short bitcount, i, shift;
+
+
+ p->font->bpp = (unsigned short)_bdf_atos( p->list.field[4], 0, 10 );
+
+ /* Only values 1, 2, 4, 8 are allowed. */
+ shift = p->font->bpp;
+ bitcount = 0;
+ for ( i = 0; shift > 0; i++ )
+ {
+ if ( shift & 1 )
+ bitcount = i;
+ shift >>= 1;
+ }
+
+ shift = (short)( ( bitcount > 3 ) ? 8 : ( 1 << bitcount ) );
+
+ if ( p->font->bpp > shift || p->font->bpp != shift )
+ {
+ /* select next higher value */
+ p->font->bpp = (unsigned short)( shift << 1 );
+ FT_TRACE2(( "_bdf_parse_start: " ACMSG11, p->font->bpp ));
+ }
+ }
+ else
+ p->font->bpp = 1;
+
+ p->flags |= _BDF_SIZE;
+
+ goto Exit;
+ }
+
+ error = BDF_Err_Invalid_File_Format;
+
+ Exit:
+ return error;
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* API. */
+ /* */
+ /*************************************************************************/
+
+
+ FT_LOCAL_DEF( FT_Error )
+ bdf_load_font( FT_Stream stream,
+ FT_Memory extmemory,
+ bdf_options_t* opts,
+ bdf_font_t* *font )
+ {
+ unsigned long lineno;
+ _bdf_parse_t *p;
+
+ FT_Memory memory = extmemory;
+ FT_Error error = BDF_Err_Ok;
+
+
+ if ( FT_ALLOC( p, sizeof ( _bdf_parse_t ) ) )
+ goto Exit;
+
+ memory = NULL;
+ p->opts = (bdf_options_t*)( ( opts != 0 ) ? opts : &_bdf_opts );
+ p->minlb = 32767;
+ p->memory = extmemory; /* only during font creation */
+
+ error = _bdf_readstream( stream, _bdf_parse_start,
+ (void *)p, &lineno );
+ if ( error )
+ goto Exit;
+
+ if ( p->font != 0 )
+ {
+ /* If the font is not proportional, set the font's monowidth */
+ /* field to the width of the font bounding box. */
+ memory = p->font->memory;
+
+ if ( p->font->spacing != BDF_PROPORTIONAL )
+ p->font->monowidth = p->font->bbx.width;
+
+ /* If the number of glyphs loaded is not that of the original count, */
+ /* indicate the difference. */
+ if ( p->cnt != p->font->glyphs_used + p->font->unencoded_used )
+ {
+ FT_TRACE2(( "bdf_load_font: " ACMSG15, p->cnt,
+ p->font->glyphs_used + p->font->unencoded_used ));
+ p->font->modified = 1;
+ }
+
+ /* Once the font has been loaded, adjust the overall font metrics if */
+ /* necessary. */
+ if ( p->opts->correct_metrics != 0 &&
+ ( p->font->glyphs_used > 0 || p->font->unencoded_used > 0 ) )
+ {
+ if ( p->maxrb - p->minlb != p->font->bbx.width )
+ {
+ FT_TRACE2(( "bdf_load_font: " ACMSG3,
+ p->font->bbx.width, p->maxrb - p->minlb ));
+ p->font->bbx.width = (unsigned short)( p->maxrb - p->minlb );
+ p->font->modified = 1;
+ }
+
+ if ( p->font->bbx.x_offset != p->minlb )
+ {
+ FT_TRACE2(( "bdf_load_font: " ACMSG4,
+ p->font->bbx.x_offset, p->minlb ));
+ p->font->bbx.x_offset = p->minlb;
+ p->font->modified = 1;
+ }
+
+ if ( p->font->bbx.ascent != p->maxas )
+ {
+ FT_TRACE2(( "bdf_load_font: " ACMSG5,
+ p->font->bbx.ascent, p->maxas ));
+ p->font->bbx.ascent = p->maxas;
+ p->font->modified = 1;
+ }
+
+ if ( p->font->bbx.descent != p->maxds )
+ {
+ FT_TRACE2(( "bdf_load_font: " ACMSG6,
+ p->font->bbx.descent, p->maxds ));
+ p->font->bbx.descent = p->maxds;
+ p->font->bbx.y_offset = (short)( -p->maxds );
+ p->font->modified = 1;
+ }
+
+ if ( p->maxas + p->maxds != p->font->bbx.height )
+ {
+ FT_TRACE2(( "bdf_load_font: " ACMSG7,
+ p->font->bbx.height, p->maxas + p->maxds ));
+ p->font->bbx.height = (unsigned short)( p->maxas + p->maxds );
+ }
+
+ if ( p->flags & _BDF_SWIDTH_ADJ )
+ FT_TRACE2(( "bdf_load_font: " ACMSG8 ));
+ }
+ }
+
+ if ( p->flags & _BDF_START )
+ {
+ {
+ /* The ENDFONT field was never reached or did not exist. */
+ if ( !( p->flags & _BDF_GLYPHS ) )
+ /* Error happened while parsing header. */
+ FT_ERROR(( "bdf_load_font: " ERRMSG2, lineno ));
+ else
+ /* Error happened when parsing glyphs. */
+ FT_ERROR(( "bdf_load_font: " ERRMSG3, lineno ));
+ }
+ }
+
+ /* Free up the list used during the parsing. */
+ if ( memory != NULL )
+ FT_FREE( p->list.field );
+
+ if ( p->font != 0 )
+ {
+ /* Make sure the comments are NULL terminated if they exist. */
+ memory = p->font->memory;
+
+ if ( p->font->comments_len > 0 ) {
+ if ( FT_RENEW_ARRAY( p->font->comments,
+ p->font->comments_len,
+ p->font->comments_len + 1 ) )
+ goto Exit;
+
+ p->font->comments[p->font->comments_len] = 0;
+ }
+ }
+ else if ( error == BDF_Err_Ok )
+ error = BDF_Err_Invalid_File_Format;
+
+ *font = p->font;
+
+ Exit:
+ if ( p )
+ {
+ memory = extmemory;
+ FT_FREE( p );
+ }
+
+ return error;
+ }
+
+
+ FT_LOCAL_DEF( void )
+ bdf_free_font( bdf_font_t* font )
+ {
+ bdf_property_t* prop;
+ unsigned long i;
+ bdf_glyph_t* glyphs;
+ FT_Memory memory;
+
+
+ if ( font == 0 )
+ return;
+
+ memory = font->memory;
+
+ FT_FREE( font->name );
+
+ /* Free up the internal hash table of property names. */
+ if ( font->internal )
+ {
+ hash_free( (hashtable *)font->internal, memory );
+ FT_FREE( font->internal );
+ }
+
+ /* Free up the comment info. */
+ FT_FREE( font->comments );
+
+ /* Free up the properties. */
+ for ( i = 0; i < font->props_size; i++ )
+ {
+ if ( font->props[i].format == BDF_ATOM )
+ FT_FREE( font->props[i].value.atom );
+ }
+
+ FT_FREE( font->props );
+
+ /* Free up the character info. */
+ for ( i = 0, glyphs = font->glyphs;
+ i < font->glyphs_used; i++, glyphs++ )
+ {
+ FT_FREE( glyphs->name );
+ FT_FREE( glyphs->bitmap );
+ }
+
+ for ( i = 0, glyphs = font->unencoded; i < font->unencoded_used;
+ i++, glyphs++ )
+ {
+ FT_FREE( glyphs->name );
+ FT_FREE( glyphs->bitmap );
+ }
+
+ FT_FREE( font->glyphs );
+ FT_FREE( font->unencoded );
+
+ /* Free up the overflow storage if it was used. */
+ for ( i = 0, glyphs = font->overflow.glyphs;
+ i < font->overflow.glyphs_used; i++, glyphs++ )
+ {
+ FT_FREE( glyphs->name );
+ FT_FREE( glyphs->bitmap );
+ }
+
+ FT_FREE( font->overflow.glyphs );
+
+ /* bdf_cleanup */
+ hash_free( &(font->proptbl), memory );
+
+ /* Free up the user defined properties. */
+ for (prop = font->user_props, i = 0;
+ i < font->nuser_props; i++, prop++ )
+ {
+ FT_FREE( prop->name );
+ if ( prop->format == BDF_ATOM )
+ FT_FREE( prop->value.atom );
+ }
+
+ FT_FREE( font->user_props );
+
+ /* FREE( font ); */ /* XXX Fixme */
+ }
+
+
+ FT_LOCAL_DEF( bdf_property_t * )
+ bdf_get_font_property( bdf_font_t* font,
+ char* name )
+ {
+ hashnode hn;
+
+
+ if ( font == 0 || font->props_size == 0 || name == 0 || *name == 0 )
+ return 0;
+
+ hn = hash_lookup( name, (hashtable *)font->internal );
+
+ return hn ? ( font->props + (unsigned long)hn->data ) : 0;
+ }
+
+
+/* END */
--- /dev/null
+++ b/libfreetype/cff.c
@@ -1,0 +1,29 @@
+/***************************************************************************/
+/* */
+/* cff.c */
+/* */
+/* FreeType OpenType driver component (body only). */
+/* */
+/* Copyright 1996-2001 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+
+#define FT_MAKE_OPTION_SINGLE_OBJECT
+
+#include <ft2build.h>
+#include "cffdrivr.c"
+#include "cffparse.c"
+#include "cffload.c"
+#include "cffobjs.c"
+#include "cffgload.c"
+#include "cffcmap.c"
+
+/* END */
--- /dev/null
+++ b/libfreetype/cffcmap.c
@@ -1,0 +1,326 @@
+/***************************************************************************/
+/* */
+/* cffcmap.c */
+/* */
+/* CFF character mapping table (cmap) support (body). */
+/* */
+/* Copyright 2002 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+
+#include "cffcmap.h"
+#include "cffload.h"
+
+
+ /*************************************************************************/
+ /*************************************************************************/
+ /***** *****/
+ /***** CFF STANDARD (AND EXPERT) ENCODING CMAPS *****/
+ /***** *****/
+ /*************************************************************************/
+ /*************************************************************************/
+
+ FT_CALLBACK_DEF( FT_Error )
+ cff_cmap_encoding_init( CFF_CMapStd cmap )
+ {
+ TT_Face face = (TT_Face)FT_CMAP_FACE( cmap );
+ CFF_Font cff = (CFF_Font)face->extra.data;
+ CFF_Encoding encoding = &cff->encoding;
+
+
+ cmap->count = encoding->count;
+ cmap->gids = encoding->codes;
+
+ return 0;
+ }
+
+
+ FT_CALLBACK_DEF( void )
+ cff_cmap_encoding_done( CFF_CMapStd cmap )
+ {
+ cmap->count = 0;
+ cmap->gids = NULL;
+ }
+
+
+ FT_CALLBACK_DEF( FT_UInt )
+ cff_cmap_encoding_char_index( CFF_CMapStd cmap,
+ FT_UInt32 char_code )
+ {
+ FT_UInt result = 0;
+
+
+ if ( char_code < cmap->count )
+ result = cmap->gids[char_code];
+
+ return result;
+ }
+
+
+ FT_CALLBACK_DEF( FT_UInt )
+ cff_cmap_encoding_char_next( CFF_CMapStd cmap,
+ FT_UInt32 *pchar_code )
+ {
+ FT_UInt result = 0;
+ FT_UInt32 char_code = *pchar_code;
+
+
+ *pchar_code = 0;
+
+ if ( char_code < cmap->count )
+ {
+ FT_UInt code = (FT_UInt)(char_code + 1);
+
+
+ for (;;)
+ {
+ if ( code >= cmap->count )
+ break;
+
+ result = cmap->gids[code];
+ if ( result != 0 )
+ {
+ *pchar_code = code;
+ break;
+ }
+
+ code++;
+ }
+ }
+ return result;
+ }
+
+
+ FT_CALLBACK_TABLE_DEF const FT_CMap_ClassRec
+ cff_cmap_encoding_class_rec =
+ {
+ sizeof ( CFF_CMapStdRec ),
+
+ (FT_CMap_InitFunc) cff_cmap_encoding_init,
+ (FT_CMap_DoneFunc) cff_cmap_encoding_done,
+ (FT_CMap_CharIndexFunc)cff_cmap_encoding_char_index,
+ (FT_CMap_CharNextFunc) cff_cmap_encoding_char_next
+ };
+
+
+ /*************************************************************************/
+ /*************************************************************************/
+ /***** *****/
+ /***** CFF SYNTHETIC UNICODE ENCODING CMAP *****/
+ /***** *****/
+ /*************************************************************************/
+ /*************************************************************************/
+
+ FT_CALLBACK_DEF( FT_Int )
+ cff_cmap_uni_pair_compare( const void* pair1,
+ const void* pair2 )
+ {
+ FT_UInt32 u1 = ((CFF_CMapUniPair)pair1)->unicode;
+ FT_UInt32 u2 = ((CFF_CMapUniPair)pair2)->unicode;
+
+
+ if ( u1 < u2 )
+ return -1;
+
+ if ( u1 > u2 )
+ return +1;
+
+ return 0;
+ }
+
+
+ FT_CALLBACK_DEF( FT_Error )
+ cff_cmap_unicode_init( CFF_CMapUnicode cmap )
+ {
+ FT_Error error;
+ FT_UInt count;
+ TT_Face face = (TT_Face)FT_CMAP_FACE( cmap );
+ FT_Memory memory = FT_FACE_MEMORY( face );
+ CFF_Font cff = (CFF_Font)face->extra.data;
+ CFF_Charset charset = &cff->charset;
+ PSNames_Service psnames = (PSNames_Service)cff->psnames;
+
+
+ cmap->num_pairs = 0;
+ cmap->pairs = NULL;
+
+ count = (FT_UInt)face->root.num_glyphs;
+
+ if ( !FT_NEW_ARRAY( cmap->pairs, count ) )
+ {
+ FT_UInt n, new_count;
+ CFF_CMapUniPair pair;
+ FT_UInt32 uni_code;
+
+
+ pair = cmap->pairs;
+ for ( n = 0; n < count; n++ )
+ {
+ FT_UInt sid = charset->sids[n];
+ const char* gname;
+
+
+ gname = cff_index_get_sid_string( &cff->string_index, sid, psnames );
+
+ /* build unsorted pair table by matching glyph names */
+ if ( gname )
+ {
+ uni_code = psnames->unicode_value( gname );
+
+ if ( uni_code != 0 )
+ {
+ pair->unicode = uni_code;
+ pair->gindex = n;
+ pair++;
+ }
+
+ FT_FREE( gname );
+ }
+ }
+
+ new_count = (FT_UInt)( pair - cmap->pairs );
+ if ( new_count == 0 )
+ {
+ /* there are no unicode characters in here! */
+ FT_FREE( cmap->pairs );
+ error = FT_Err_Invalid_Argument;
+ }
+ else
+ {
+ /* re-allocate if the new array is much smaller than the original */
+ /* one */
+ if ( new_count != count && new_count < count / 2 )
+ {
+ (void)FT_RENEW_ARRAY( cmap->pairs, count, new_count );
+ error = 0;
+ }
+
+ /* sort the pairs table to allow efficient binary searches */
+ ft_qsort( cmap->pairs,
+ new_count,
+ sizeof ( CFF_CMapUniPairRec ),
+ cff_cmap_uni_pair_compare );
+
+ cmap->num_pairs = new_count;
+ }
+ }
+
+ return error;
+ }
+
+
+ FT_CALLBACK_DEF( void )
+ cff_cmap_unicode_done( CFF_CMapUnicode cmap )
+ {
+ FT_Face face = FT_CMAP_FACE( cmap );
+ FT_Memory memory = FT_FACE_MEMORY( face );
+
+
+ FT_FREE( cmap->pairs );
+ cmap->num_pairs = 0;
+ }
+
+
+ FT_CALLBACK_DEF( FT_UInt )
+ cff_cmap_unicode_char_index( CFF_CMapUnicode cmap,
+ FT_UInt32 char_code )
+ {
+ FT_UInt min = 0;
+ FT_UInt max = cmap->num_pairs;
+ FT_UInt mid;
+ CFF_CMapUniPair pair;
+
+
+ while ( min < max )
+ {
+ mid = min + ( max - min ) / 2;
+ pair = cmap->pairs + mid;
+
+ if ( pair->unicode == char_code )
+ return pair->gindex;
+
+ if ( pair->unicode < char_code )
+ min = mid + 1;
+ else
+ max = mid;
+ }
+ return 0;
+ }
+
+
+ FT_CALLBACK_DEF( FT_UInt )
+ cff_cmap_unicode_char_next( CFF_CMapUnicode cmap,
+ FT_UInt32 *pchar_code )
+ {
+ FT_UInt result = 0;
+ FT_UInt32 char_code = *pchar_code + 1;
+
+
+ Restart:
+ {
+ FT_UInt min = 0;
+ FT_UInt max = cmap->num_pairs;
+ FT_UInt mid;
+ CFF_CMapUniPair pair;
+
+
+ while ( min < max )
+ {
+ mid = min + ( ( max - min ) >> 1 );
+ pair = cmap->pairs + mid;
+
+ if ( pair->unicode == char_code )
+ {
+ result = pair->gindex;
+ if ( result != 0 )
+ goto Exit;
+
+ char_code++;
+ goto Restart;
+ }
+
+ if ( pair->unicode < char_code )
+ min = mid+1;
+ else
+ max = mid;
+ }
+
+ /* we didn't find it, but we have a pair just above it */
+ char_code = 0;
+
+ if ( min < cmap->num_pairs )
+ {
+ pair = cmap->pairs + min;
+ result = pair->gindex;
+ if ( result != 0 )
+ char_code = pair->unicode;
+ }
+ }
+
+ Exit:
+ *pchar_code = char_code;
+ return result;
+ }
+
+
+ FT_CALLBACK_TABLE_DEF const FT_CMap_ClassRec
+ cff_cmap_unicode_class_rec =
+ {
+ sizeof ( CFF_CMapUnicodeRec ),
+
+ (FT_CMap_InitFunc) cff_cmap_unicode_init,
+ (FT_CMap_DoneFunc) cff_cmap_unicode_done,
+ (FT_CMap_CharIndexFunc)cff_cmap_unicode_char_index,
+ (FT_CMap_CharNextFunc) cff_cmap_unicode_char_next
+ };
+
+
+/* END */
--- /dev/null
+++ b/libfreetype/cffcmap.h
@@ -1,0 +1,88 @@
+/***************************************************************************/
+/* */
+/* cffcmap.h */
+/* */
+/* CFF character mapping table (cmap) support (specification). */
+/* */
+/* Copyright 2002 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+
+#ifndef __CFFCMAP_H__
+#define __CFFCMAP_H__
+
+#include "cffobjs.h"
+
+FT_BEGIN_HEADER
+
+
+ /*************************************************************************/
+ /*************************************************************************/
+ /***** *****/
+ /***** TYPE1 STANDARD (AND EXPERT) ENCODING CMAPS *****/
+ /***** *****/
+ /*************************************************************************/
+ /*************************************************************************/
+
+ /* standard (and expert) encoding cmaps */
+ typedef struct CFF_CMapStdRec_* CFF_CMapStd;
+
+ typedef struct CFF_CMapStdRec_
+ {
+ FT_CMapRec cmap;
+ FT_UInt count;
+ FT_UShort* gids; /* up to 256 elements */
+
+ } CFF_CMapStdRec;
+
+
+ FT_CALLBACK_TABLE const FT_CMap_ClassRec
+ cff_cmap_encoding_class_rec;
+
+
+ /*************************************************************************/
+ /*************************************************************************/
+ /***** *****/
+ /***** CFF SYNTHETIC UNICODE ENCODING CMAP *****/
+ /***** *****/
+ /*************************************************************************/
+ /*************************************************************************/
+
+ /* unicode (synthetic) cmaps */
+ typedef struct CFF_CMapUnicodeRec_* CFF_CMapUnicode;
+
+ typedef struct CFF_CMapUniPairRec_
+ {
+ FT_UInt32 unicode;
+ FT_UInt gindex;
+
+ } CFF_CMapUniPairRec, *CFF_CMapUniPair;
+
+
+ typedef struct CFF_CMapUnicodeRec_
+ {
+ FT_CMapRec cmap;
+ FT_UInt num_pairs;
+ CFF_CMapUniPair pairs;
+
+ } CFF_CMapUnicodeRec;
+
+
+ FT_CALLBACK_TABLE const FT_CMap_ClassRec
+ cff_cmap_unicode_class_rec;
+
+
+FT_END_HEADER
+
+#endif /* __CFFCMAP_H__ */
+
+
+/* END */
--- /dev/null
+++ b/libfreetype/cffdrivr.c
@@ -1,0 +1,420 @@
+/***************************************************************************/
+/* */
+/* cffdrivr.c */
+/* */
+/* OpenType font driver implementation (body). */
+/* */
+/* Copyright 1996-2001, 2002 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+
+#include <ft2build.h>
+#include FT_FREETYPE_H
+#include FT_INTERNAL_DEBUG_H
+#include FT_INTERNAL_STREAM_H
+#include FT_INTERNAL_SFNT_H
+#include FT_TRUETYPE_IDS_H
+#include FT_INTERNAL_POSTSCRIPT_NAMES_H
+
+#include "cffdrivr.h"
+#include "cffgload.h"
+#include "cffload.h"
+
+#include "cfferrs.h"
+
+
+ /*************************************************************************/
+ /* */
+ /* The macro FT_COMPONENT is used in trace mode. It is an implicit */
+ /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log */
+ /* messages during execution. */
+ /* */
+#undef FT_COMPONENT
+#define FT_COMPONENT trace_cffdriver
+
+
+ /*************************************************************************/
+ /*************************************************************************/
+ /*************************************************************************/
+ /**** ****/
+ /**** ****/
+ /**** F A C E S ****/
+ /**** ****/
+ /**** ****/
+ /*************************************************************************/
+ /*************************************************************************/
+ /*************************************************************************/
+
+
+#undef PAIR_TAG
+#define PAIR_TAG( left, right ) ( ( (FT_ULong)left << 16 ) | \
+ (FT_ULong)right )
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* Get_Kerning */
+ /* */
+ /* <Description> */
+ /* A driver method used to return the kerning vector between two */
+ /* glyphs of the same face. */
+ /* */
+ /* <Input> */
+ /* face :: A handle to the source face object. */
+ /* */
+ /* left_glyph :: The index of the left glyph in the kern pair. */
+ /* */
+ /* right_glyph :: The index of the right glyph in the kern pair. */
+ /* */
+ /* <Output> */
+ /* kerning :: The kerning vector. This is in font units for */
+ /* scalable formats, and in pixels for fixed-sizes */
+ /* formats. */
+ /* */
+ /* <Return> */
+ /* FreeType error code. 0 means success. */
+ /* */
+ /* <Note> */
+ /* Only horizontal layouts (left-to-right & right-to-left) are */
+ /* supported by this function. Other layouts, or more sophisticated */
+ /* kernings, are out of scope of this method (the basic driver */
+ /* interface is meant to be simple). */
+ /* */
+ /* They can be implemented by format-specific interfaces. */
+ /* */
+ static FT_Error
+ Get_Kerning( TT_Face face,
+ FT_UInt left_glyph,
+ FT_UInt right_glyph,
+ FT_Vector* kerning )
+ {
+ TT_Kern0_Pair pair;
+
+
+ if ( !face )
+ return CFF_Err_Invalid_Face_Handle;
+
+ kerning->x = 0;
+ kerning->y = 0;
+
+ if ( face->kern_pairs )
+ {
+ /* there are some kerning pairs in this font file! */
+ FT_ULong search_tag = PAIR_TAG( left_glyph, right_glyph );
+ FT_Long left, right;
+
+
+ left = 0;
+ right = face->num_kern_pairs - 1;
+
+ while ( left <= right )
+ {
+ FT_Long middle = left + ( ( right - left ) >> 1 );
+ FT_ULong cur_pair;
+
+
+ pair = face->kern_pairs + middle;
+ cur_pair = PAIR_TAG( pair->left, pair->right );
+
+ if ( cur_pair == search_tag )
+ goto Found;
+
+ if ( cur_pair < search_tag )
+ left = middle + 1;
+ else
+ right = middle - 1;
+ }
+ }
+
+ Exit:
+ return CFF_Err_Ok;
+
+ Found:
+ kerning->x = pair->value;
+ goto Exit;
+ }
+
+
+#undef PAIR_TAG
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* Load_Glyph */
+ /* */
+ /* <Description> */
+ /* A driver method used to load a glyph within a given glyph slot. */
+ /* */
+ /* <Input> */
+ /* slot :: A handle to the target slot object where the glyph */
+ /* will be loaded. */
+ /* */
+ /* size :: A handle to the source face size at which the glyph */
+ /* must be scaled, loaded, etc. */
+ /* */
+ /* glyph_index :: The index of the glyph in the font file. */
+ /* */
+ /* load_flags :: A flag indicating what to load for this glyph. The */
+ /* FTLOAD_??? constants can be used to control the */
+ /* glyph loading process (e.g., whether the outline */
+ /* should be scaled, whether to load bitmaps or not, */
+ /* whether to hint the outline, etc). */
+ /* */
+ /* <Return> */
+ /* FreeType error code. 0 means success. */
+ /* */
+ static FT_Error
+ Load_Glyph( CFF_GlyphSlot slot,
+ CFF_Size size,
+ FT_UShort glyph_index,
+ FT_Int32 load_flags )
+ {
+ FT_Error error;
+
+
+ if ( !slot )
+ return CFF_Err_Invalid_Slot_Handle;
+
+ /* check whether we want a scaled outline or bitmap */
+ if ( !size )
+ load_flags |= FT_LOAD_NO_SCALE | FT_LOAD_NO_HINTING;
+
+ if ( load_flags & FT_LOAD_NO_SCALE )
+ size = NULL;
+
+ /* reset the size object if necessary */
+ if ( size )
+ {
+ /* these two object must have the same parent */
+ if ( size->face != slot->root.face )
+ return CFF_Err_Invalid_Face_Handle;
+ }
+
+ /* now load the glyph outline if necessary */
+ error = cff_slot_load( slot, size, glyph_index, load_flags );
+
+ /* force drop-out mode to 2 - irrelevant now */
+ /* slot->outline.dropout_mode = 2; */
+
+ return error;
+ }
+
+
+ /*************************************************************************/
+ /*************************************************************************/
+ /*************************************************************************/
+ /**** ****/
+ /**** ****/
+ /**** C H A R A C T E R M A P P I N G S ****/
+ /**** ****/
+ /**** ****/
+ /*************************************************************************/
+ /*************************************************************************/
+ /*************************************************************************/
+
+ static FT_Error
+ cff_get_glyph_name( CFF_Face face,
+ FT_UInt glyph_index,
+ FT_Pointer buffer,
+ FT_UInt buffer_max )
+ {
+ CFF_Font font = (CFF_Font)face->extra.data;
+ FT_Memory memory = FT_FACE_MEMORY( face );
+ FT_String* gname;
+ FT_UShort sid;
+ PSNames_Service psnames;
+ FT_Error error;
+
+
+ psnames = (PSNames_Service)FT_Get_Module_Interface(
+ face->root.driver->root.library, "psnames" );
+
+ if ( !psnames )
+ {
+ FT_ERROR(( "cff_get_glyph_name:" ));
+ FT_ERROR(( " cannot open CFF & CEF fonts\n" ));
+ FT_ERROR(( " " ));
+ FT_ERROR(( " without the `PSNames' module\n" ));
+ error = CFF_Err_Unknown_File_Format;
+ goto Exit;
+ }
+
+ /* first, locate the sid in the charset table */
+ sid = font->charset.sids[glyph_index];
+
+ /* now, lookup the name itself */
+ gname = cff_index_get_sid_string( &font->string_index, sid, psnames );
+
+ if ( buffer_max > 0 )
+ {
+ FT_UInt len = (FT_UInt)ft_strlen( gname );
+
+
+ if ( len >= buffer_max )
+ len = buffer_max - 1;
+
+ FT_MEM_COPY( buffer, gname, len );
+ ((FT_Byte*)buffer)[len] = 0;
+ }
+
+ FT_FREE ( gname );
+ error = CFF_Err_Ok;
+
+ Exit:
+ return error;
+ }
+
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* cff_get_name_index */
+ /* */
+ /* <Description> */
+ /* Uses the psnames module and the CFF font's charset to to return a */
+ /* a given glyph name's glyph index. */
+ /* */
+ /* <Input> */
+ /* face :: A handle to the source face object. */
+ /* */
+ /* glyph_name :: The glyph name. */
+ /* */
+ /* <Return> */
+ /* Glyph index. 0 means `undefined character code'. */
+ /* */
+ static FT_UInt
+ cff_get_name_index( CFF_Face face,
+ FT_String* glyph_name )
+ {
+ CFF_Font cff;
+ CFF_Charset charset;
+ PSNames_Service psnames;
+ FT_Memory memory = FT_FACE_MEMORY( face );
+ FT_String* name;
+ FT_UShort sid;
+ FT_UInt i;
+ FT_Int result;
+
+
+ cff = (CFF_FontRec *)face->extra.data;
+ charset = &cff->charset;
+
+ psnames = (PSNames_Service)FT_Get_Module_Interface(
+ face->root.driver->root.library, "psnames" );
+
+ for ( i = 0; i < cff->num_glyphs; i++ )
+ {
+ sid = charset->sids[i];
+
+ if ( sid > 390 )
+ name = cff_index_get_name( &cff->string_index, sid - 391 );
+ else
+ name = (FT_String *)psnames->adobe_std_strings( sid );
+
+ result = ft_strcmp( glyph_name, name );
+
+ if ( sid > 390 )
+ FT_FREE( name );
+
+ if ( !result )
+ return i;
+ }
+
+ return 0;
+ }
+
+
+ /*************************************************************************/
+ /*************************************************************************/
+ /*************************************************************************/
+ /**** ****/
+ /**** ****/
+ /**** D R I V E R I N T E R F A C E ****/
+ /**** ****/
+ /**** ****/
+ /*************************************************************************/
+ /*************************************************************************/
+ /*************************************************************************/
+
+ static FT_Module_Interface
+ cff_get_interface( CFF_Driver driver,
+ const char* module_interface )
+ {
+ FT_Module sfnt;
+
+
+#ifndef FT_CONFIG_OPTION_NO_GLYPH_NAMES
+
+ if ( ft_strcmp( (const char*)module_interface, "glyph_name" ) == 0 )
+ return (FT_Module_Interface)cff_get_glyph_name;
+
+ if ( ft_strcmp( (const char*)module_interface, "name_index" ) == 0 )
+ return (FT_Module_Interface)cff_get_name_index;
+
+#endif
+
+ /* we simply pass our request to the `sfnt' module */
+ sfnt = FT_Get_Module( driver->root.root.library, "sfnt" );
+
+ return sfnt ? sfnt->clazz->get_interface( sfnt, module_interface ) : 0;
+ }
+
+
+ /* The FT_DriverInterface structure is defined in ftdriver.h. */
+
+ FT_CALLBACK_TABLE_DEF
+ const FT_Driver_ClassRec cff_driver_class =
+ {
+ /* begin with the FT_Module_Class fields */
+ {
+ ft_module_font_driver |
+ ft_module_driver_scalable |
+ ft_module_driver_has_hinter,
+
+ sizeof( CFF_DriverRec ),
+ "cff",
+ 0x10000L,
+ 0x20000L,
+
+ 0, /* module-specific interface */
+
+ (FT_Module_Constructor)cff_driver_init,
+ (FT_Module_Destructor) cff_driver_done,
+ (FT_Module_Requester) cff_get_interface,
+ },
+
+ /* now the specific driver fields */
+ sizeof( TT_FaceRec ),
+ sizeof( FT_SizeRec ),
+ sizeof( CFF_GlyphSlotRec ),
+
+ (FT_Face_InitFunc) cff_face_init,
+ (FT_Face_DoneFunc) cff_face_done,
+ (FT_Size_InitFunc) cff_size_init,
+ (FT_Size_DoneFunc) cff_size_done,
+ (FT_Slot_InitFunc) cff_slot_init,
+ (FT_Slot_DoneFunc) cff_slot_done,
+
+ (FT_Size_ResetPointsFunc)cff_size_reset,
+ (FT_Size_ResetPixelsFunc)cff_size_reset,
+
+ (FT_Slot_LoadFunc) Load_Glyph,
+
+ (FT_Face_GetKerningFunc) Get_Kerning,
+ (FT_Face_AttachFunc) 0,
+ (FT_Face_GetAdvancesFunc)0,
+ };
+
+
+/* END */
--- /dev/null
+++ b/libfreetype/cffdrivr.h
@@ -1,0 +1,39 @@
+/***************************************************************************/
+/* */
+/* cffdrivr.h */
+/* */
+/* High-level OpenType driver interface (specification). */
+/* */
+/* Copyright 1996-2001, 2002 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+
+#ifndef __CFFDRIVER_H__
+#define __CFFDRIVER_H__
+
+
+#include <ft2build.h>
+#include FT_INTERNAL_DRIVER_H
+
+
+FT_BEGIN_HEADER
+
+
+ FT_CALLBACK_TABLE
+ const FT_Driver_ClassRec cff_driver_class;
+
+
+FT_END_HEADER
+
+#endif /* __CFFDRIVER_H__ */
+
+
+/* END */
--- /dev/null
+++ b/libfreetype/cfferrs.h
@@ -1,0 +1,41 @@
+/***************************************************************************/
+/* */
+/* cfferrs.h */
+/* */
+/* CFF error codes (specification only). */
+/* */
+/* Copyright 2001 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+
+ /*************************************************************************/
+ /* */
+ /* This file is used to define the CFF error enumeration constants. */
+ /* */
+ /*************************************************************************/
+
+#ifndef __CFFERRS_H__
+#define __CFFERRS_H__
+
+#include FT_MODULE_ERRORS_H
+
+#undef __FTERRORS_H__
+
+#define FT_ERR_PREFIX CFF_Err_
+#define FT_ERR_BASE FT_Mod_Err_CFF
+
+
+#include FT_ERRORS_H
+
+#endif /* __CFFERRS_H__ */
+
+
+/* END */
--- /dev/null
+++ b/libfreetype/cffgload.c
@@ -1,0 +1,2481 @@
+/***************************************************************************/
+/* */
+/* cffgload.c */
+/* */
+/* OpenType Glyph Loader (body). */
+/* */
+/* Copyright 1996-2001, 2002 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+
+#include <ft2build.h>
+#include FT_INTERNAL_DEBUG_H
+#include FT_INTERNAL_CALC_H
+#include FT_INTERNAL_STREAM_H
+#include FT_INTERNAL_SFNT_H
+#include FT_OUTLINE_H
+#include FT_TRUETYPE_TAGS_H
+#include FT_INTERNAL_POSTSCRIPT_HINTS_H
+
+#include "cffobjs.h"
+#include "cffload.h"
+#include "cffgload.h"
+
+#include "cfferrs.h"
+
+
+ /*************************************************************************/
+ /* */
+ /* The macro FT_COMPONENT is used in trace mode. It is an implicit */
+ /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log */
+ /* messages during execution. */
+ /* */
+#undef FT_COMPONENT
+#define FT_COMPONENT trace_cffgload
+
+
+ typedef enum CFF_Operator_
+ {
+ cff_op_unknown = 0,
+
+ cff_op_rmoveto,
+ cff_op_hmoveto,
+ cff_op_vmoveto,
+
+ cff_op_rlineto,
+ cff_op_hlineto,
+ cff_op_vlineto,
+
+ cff_op_rrcurveto,
+ cff_op_hhcurveto,
+ cff_op_hvcurveto,
+ cff_op_rcurveline,
+ cff_op_rlinecurve,
+ cff_op_vhcurveto,
+ cff_op_vvcurveto,
+
+ cff_op_flex,
+ cff_op_hflex,
+ cff_op_hflex1,
+ cff_op_flex1,
+
+ cff_op_endchar,
+
+ cff_op_hstem,
+ cff_op_vstem,
+ cff_op_hstemhm,
+ cff_op_vstemhm,
+
+ cff_op_hintmask,
+ cff_op_cntrmask,
+ cff_op_dotsection, /* deprecated, acts as no-op */
+
+ cff_op_abs,
+ cff_op_add,
+ cff_op_sub,
+ cff_op_div,
+ cff_op_neg,
+ cff_op_random,
+ cff_op_mul,
+ cff_op_sqrt,
+
+ cff_op_blend,
+
+ cff_op_drop,
+ cff_op_exch,
+ cff_op_index,
+ cff_op_roll,
+ cff_op_dup,
+
+ cff_op_put,
+ cff_op_get,
+ cff_op_store,
+ cff_op_load,
+
+ cff_op_and,
+ cff_op_or,
+ cff_op_not,
+ cff_op_eq,
+ cff_op_ifelse,
+
+ cff_op_callsubr,
+ cff_op_callgsubr,
+ cff_op_return,
+
+ /* do not remove */
+ cff_op_max
+
+ } CFF_Operator;
+
+
+#define CFF_COUNT_CHECK_WIDTH 0x80
+#define CFF_COUNT_EXACT 0x40
+#define CFF_COUNT_CLEAR_STACK 0x20
+
+
+ static const FT_Byte cff_argument_counts[] =
+ {
+ 0, /* unknown */
+
+ 2 | CFF_COUNT_CHECK_WIDTH | CFF_COUNT_EXACT, /* rmoveto */
+ 1 | CFF_COUNT_CHECK_WIDTH | CFF_COUNT_EXACT,
+ 1 | CFF_COUNT_CHECK_WIDTH | CFF_COUNT_EXACT,
+
+ 0 | CFF_COUNT_CLEAR_STACK, /* rlineto */
+ 0 | CFF_COUNT_CLEAR_STACK,
+ 0 | CFF_COUNT_CLEAR_STACK,
+
+ 0 | CFF_COUNT_CLEAR_STACK, /* rrcurveto */
+ 0 | CFF_COUNT_CLEAR_STACK,
+ 0 | CFF_COUNT_CLEAR_STACK,
+ 0 | CFF_COUNT_CLEAR_STACK,
+ 0 | CFF_COUNT_CLEAR_STACK,
+ 0 | CFF_COUNT_CLEAR_STACK,
+ 0 | CFF_COUNT_CLEAR_STACK,
+
+ 13, /* flex */
+ 7,
+ 9,
+ 11,
+
+ 0 | CFF_COUNT_CHECK_WIDTH, /* endchar */
+
+ 2 | CFF_COUNT_CHECK_WIDTH, /* hstem */
+ 2 | CFF_COUNT_CHECK_WIDTH,
+ 2 | CFF_COUNT_CHECK_WIDTH,
+ 2 | CFF_COUNT_CHECK_WIDTH,
+
+ 0 | CFF_COUNT_CHECK_WIDTH, /* hintmask */
+ 0 | CFF_COUNT_CHECK_WIDTH, /* cntrmask */
+ 0, /* dotsection */
+
+ 1, /* abs */
+ 2,
+ 2,
+ 2,
+ 1,
+ 0,
+ 2,
+ 1,
+
+ 1, /* blend */
+
+ 1, /* drop */
+ 2,
+ 1,
+ 2,
+ 1,
+
+ 2, /* put */
+ 1,
+ 4,
+ 3,
+
+ 2, /* and */
+ 2,
+ 1,
+ 2,
+ 4,
+
+ 1, /* callsubr */
+ 1,
+ 0
+ };
+
+
+ /*************************************************************************/
+ /*************************************************************************/
+ /*************************************************************************/
+ /********** *********/
+ /********** *********/
+ /********** GENERIC CHARSTRING PARSING *********/
+ /********** *********/
+ /********** *********/
+ /*************************************************************************/
+ /*************************************************************************/
+ /*************************************************************************/
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* cff_builder_init */
+ /* */
+ /* <Description> */
+ /* Initializes a given glyph builder. */
+ /* */
+ /* <InOut> */
+ /* builder :: A pointer to the glyph builder to initialize. */
+ /* */
+ /* <Input> */
+ /* face :: The current face object. */
+ /* */
+ /* size :: The current size object. */
+ /* */
+ /* glyph :: The current glyph object. */
+ /* */
+ static void
+ cff_builder_init( CFF_Builder* builder,
+ TT_Face face,
+ CFF_Size size,
+ CFF_GlyphSlot glyph,
+ FT_Bool hinting )
+ {
+ builder->path_begun = 0;
+ builder->load_points = 1;
+
+ builder->face = face;
+ builder->glyph = glyph;
+ builder->memory = face->root.memory;
+
+ if ( glyph )
+ {
+ FT_GlyphLoader loader = glyph->root.internal->loader;
+
+
+ builder->loader = loader;
+ builder->base = &loader->base.outline;
+ builder->current = &loader->current.outline;
+ FT_GlyphLoader_Rewind( loader );
+
+ builder->hint_flags = FT_FACE(face)->internal->hint_flags;
+ builder->hints_globals = 0;
+ builder->hints_funcs = 0;
+
+ if ( hinting && size )
+ {
+ builder->hints_globals = size->internal;
+ builder->hints_funcs = glyph->root.internal->glyph_hints;
+ }
+ }
+
+ if ( size )
+ {
+ builder->scale_x = size->metrics.x_scale;
+ builder->scale_y = size->metrics.y_scale;
+ }
+
+ builder->pos_x = 0;
+ builder->pos_y = 0;
+
+ builder->left_bearing.x = 0;
+ builder->left_bearing.y = 0;
+ builder->advance.x = 0;
+ builder->advance.y = 0;
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* cff_builder_done */
+ /* */
+ /* <Description> */
+ /* Finalizes a given glyph builder. Its contents can still be used */
+ /* after the call, but the function saves important information */
+ /* within the corresponding glyph slot. */
+ /* */
+ /* <Input> */
+ /* builder :: A pointer to the glyph builder to finalize. */
+ /* */
+ static void
+ cff_builder_done( CFF_Builder* builder )
+ {
+ CFF_GlyphSlot glyph = builder->glyph;
+
+
+ if ( glyph )
+ glyph->root.outline = *builder->base;
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* cff_compute_bias */
+ /* */
+ /* <Description> */
+ /* Computes the bias value in dependence of the number of glyph */
+ /* subroutines. */
+ /* */
+ /* <Input> */
+ /* num_subrs :: The number of glyph subroutines. */
+ /* */
+ /* <Return> */
+ /* The bias value. */
+ static FT_Int
+ cff_compute_bias( FT_UInt num_subrs )
+ {
+ FT_Int result;
+
+
+ if ( num_subrs < 1240 )
+ result = 107;
+ else if ( num_subrs < 33900U )
+ result = 1131;
+ else
+ result = 32768U;
+
+ return result;
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* cff_decoder_init */
+ /* */
+ /* <Description> */
+ /* Initializes a given glyph decoder. */
+ /* */
+ /* <InOut> */
+ /* decoder :: A pointer to the glyph builder to initialize. */
+ /* */
+ /* <Input> */
+ /* face :: The current face object. */
+ /* */
+ /* size :: The current size object. */
+ /* */
+ /* slot :: The current glyph object. */
+ /* */
+ FT_LOCAL_DEF( void )
+ cff_decoder_init( CFF_Decoder* decoder,
+ TT_Face face,
+ CFF_Size size,
+ CFF_GlyphSlot slot,
+ FT_Bool hinting,
+ FT_Render_Mode hint_mode )
+ {
+ CFF_Font cff = (CFF_Font)face->extra.data;
+
+
+ /* clear everything */
+ FT_MEM_ZERO( decoder, sizeof ( *decoder ) );
+
+ /* initialize builder */
+ cff_builder_init( &decoder->builder, face, size, slot, hinting );
+
+ /* initialize Type2 decoder */
+ decoder->num_globals = cff->num_global_subrs;
+ decoder->globals = cff->global_subrs;
+ decoder->globals_bias = cff_compute_bias( decoder->num_globals );
+
+ decoder->hint_mode = hint_mode;
+ }
+
+
+ /* this function is used to select the locals subrs array */
+ FT_LOCAL_DEF( void )
+ cff_decoder_prepare( CFF_Decoder* decoder,
+ FT_UInt glyph_index )
+ {
+ CFF_Font cff = (CFF_Font)decoder->builder.face->extra.data;
+ CFF_SubFont sub = &cff->top_font;
+
+
+ /* manage CID fonts */
+ if ( cff->num_subfonts >= 1 )
+ {
+ FT_Byte fd_index = cff_fd_select_get( &cff->fd_select, glyph_index );
+
+
+ sub = cff->subfonts[fd_index];
+ }
+
+ decoder->num_locals = sub->num_local_subrs;
+ decoder->locals = sub->local_subrs;
+ decoder->locals_bias = cff_compute_bias( decoder->num_locals );
+
+ decoder->glyph_width = sub->private_dict.default_width;
+ decoder->nominal_width = sub->private_dict.nominal_width;
+ }
+
+
+ /* check that there is enough room for `count' more points */
+ static FT_Error
+ check_points( CFF_Builder* builder,
+ FT_Int count )
+ {
+ return FT_GlyphLoader_CheckPoints( builder->loader, count, 0 );
+ }
+
+
+ /* add a new point, do not check space */
+ static void
+ cff_builder_add_point( CFF_Builder* builder,
+ FT_Pos x,
+ FT_Pos y,
+ FT_Byte flag )
+ {
+ FT_Outline* outline = builder->current;
+
+
+ if ( builder->load_points )
+ {
+ FT_Vector* point = outline->points + outline->n_points;
+ FT_Byte* control = (FT_Byte*)outline->tags + outline->n_points;
+
+
+ point->x = x >> 16;
+ point->y = y >> 16;
+ *control = (FT_Byte)( flag ? FT_CURVE_TAG_ON : FT_CURVE_TAG_CUBIC );
+
+ builder->last = *point;
+ }
+
+ outline->n_points++;
+ }
+
+
+ /* check space for a new on-curve point, then add it */
+ static FT_Error
+ cff_builder_add_point1( CFF_Builder* builder,
+ FT_Pos x,
+ FT_Pos y )
+ {
+ FT_Error error;
+
+
+ error = check_points( builder, 1 );
+ if ( !error )
+ cff_builder_add_point( builder, x, y, 1 );
+
+ return error;
+ }
+
+
+ /* check room for a new contour, then add it */
+ static FT_Error
+ cff_builder_add_contour( CFF_Builder* builder )
+ {
+ FT_Outline* outline = builder->current;
+ FT_Error error;
+
+
+ if ( !builder->load_points )
+ {
+ outline->n_contours++;
+ return CFF_Err_Ok;
+ }
+
+ error = FT_GlyphLoader_CheckPoints( builder->loader, 0, 1 );
+ if ( !error )
+ {
+ if ( outline->n_contours > 0 )
+ outline->contours[outline->n_contours - 1] =
+ (short)( outline->n_points - 1 );
+
+ outline->n_contours++;
+ }
+
+ return error;
+ }
+
+
+ /* if a path was begun, add its first on-curve point */
+ static FT_Error
+ cff_builder_start_point( CFF_Builder* builder,
+ FT_Pos x,
+ FT_Pos y )
+ {
+ FT_Error error = 0;
+
+
+ /* test whether we are building a new contour */
+ if ( !builder->path_begun )
+ {
+ builder->path_begun = 1;
+ error = cff_builder_add_contour( builder );
+ if ( !error )
+ error = cff_builder_add_point1( builder, x, y );
+ }
+
+ return error;
+ }
+
+
+ /* close the current contour */
+ static void
+ cff_builder_close_contour( CFF_Builder* builder )
+ {
+ FT_Outline* outline = builder->current;
+
+
+ /* XXXX: We must not include the last point in the path if it */
+ /* is located on the first point. */
+ if ( outline->n_points > 1 )
+ {
+ FT_Int first = 0;
+ FT_Vector* p1 = outline->points + first;
+ FT_Vector* p2 = outline->points + outline->n_points - 1;
+ FT_Byte* control = (FT_Byte*)outline->tags + outline->n_points - 1;
+
+
+ if ( outline->n_contours > 1 )
+ {
+ first = outline->contours[outline->n_contours - 2] + 1;
+ p1 = outline->points + first;
+ }
+
+ /* `delete' last point only if it coincides with the first */
+ /* point and if it is not a control point (which can happen). */
+ if ( p1->x == p2->x && p1->y == p2->y )
+ if ( *control == FT_CURVE_TAG_ON )
+ outline->n_points--;
+ }
+
+ if ( outline->n_contours > 0 )
+ outline->contours[outline->n_contours - 1] =
+ (short)( outline->n_points - 1 );
+ }
+
+
+ static FT_Int
+ cff_lookup_glyph_by_stdcharcode( CFF_Font cff,
+ FT_Int charcode )
+ {
+ FT_UInt n;
+ FT_UShort glyph_sid;
+
+
+ /* check range of standard char code */
+ if ( charcode < 0 || charcode > 255 )
+ return -1;
+
+ /* Get code to SID mapping from `cff_standard_encoding'. */
+ glyph_sid = cff_get_standard_encoding( (FT_UInt)charcode );
+
+ for ( n = 0; n < cff->num_glyphs; n++ )
+ {
+ if ( cff->charset.sids[n] == glyph_sid )
+ return n;
+ }
+
+ return -1;
+ }
+
+
+ static FT_Error
+ cff_get_glyph_data( TT_Face face,
+ FT_UInt glyph_index,
+ FT_Byte** pointer,
+ FT_ULong* length )
+ {
+#ifdef FT_CONFIG_OPTION_INCREMENTAL
+ /* For incremental fonts get the character data using the */
+ /* callback function. */
+ if ( face->root.internal->incremental_interface )
+ {
+ FT_Data data;
+ FT_Error error =
+ face->root.internal->incremental_interface->funcs->get_glyph_data(
+ face->root.internal->incremental_interface->object,
+ glyph_index, &data );
+
+
+ *pointer = (FT_Byte*)data.pointer;
+ *length = data.length;
+
+ return error;
+ }
+ else
+#endif /* FT_CONFIG_OPTION_INCREMENTAL */
+
+ {
+ CFF_Font cff = (CFF_Font)(face->extra.data);
+
+
+ return cff_index_access_element( &cff->charstrings_index, glyph_index,
+ pointer, length );
+ }
+ }
+
+
+ static void
+ cff_free_glyph_data( TT_Face face,
+ FT_Byte** pointer,
+ FT_ULong length )
+ {
+#ifndef FT_CONFIG_OPTION_INCREMENTAL
+ FT_UNUSED( length );
+#endif
+
+#ifdef FT_CONFIG_OPTION_INCREMENTAL
+ /* For incremental fonts get the character data using the */
+ /* callback function. */
+ if ( face->root.internal->incremental_interface )
+ {
+ FT_Data data;
+
+
+ data.pointer = *pointer;
+ data.length = length;
+
+ face->root.internal->incremental_interface->funcs->free_glyph_data(
+ face->root.internal->incremental_interface->object,&data );
+ }
+ else
+#endif /* FT_CONFIG_OPTION_INCREMENTAL */
+
+ {
+ CFF_Font cff = (CFF_Font)(face->extra.data);
+
+
+ cff_index_forget_element( &cff->charstrings_index, pointer );
+ }
+ }
+
+
+ static FT_Error
+ cff_operator_seac( CFF_Decoder* decoder,
+ FT_Pos adx,
+ FT_Pos ady,
+ FT_Int bchar,
+ FT_Int achar )
+ {
+ FT_Error error;
+ FT_Int bchar_index, achar_index, n_base_points;
+ FT_Outline* base = decoder->builder.base;
+ TT_Face face = decoder->builder.face;
+ FT_Vector left_bearing, advance;
+ FT_Byte* charstring;
+ FT_ULong charstring_len;
+
+
+#ifdef FT_CONFIG_OPTION_INCREMENTAL
+ /* Incremental fonts don't necessarily have valid charsets. */
+ /* They use the character code, not the glyph index, in this case. */
+ if ( face->root.internal->incremental_interface )
+ {
+ bchar_index = bchar;
+ achar_index = achar;
+ }
+ else
+#endif /* FT_CONFIG_OPTION_INCREMENTAL */
+ {
+ CFF_Font cff = (CFF_Font)(face->extra.data);
+
+
+ bchar_index = cff_lookup_glyph_by_stdcharcode( cff, bchar );
+ achar_index = cff_lookup_glyph_by_stdcharcode( cff, achar );
+ }
+
+ if ( bchar_index < 0 || achar_index < 0 )
+ {
+ FT_ERROR(( "cff_operator_seac:" ));
+ FT_ERROR(( " invalid seac character code arguments\n" ));
+ return CFF_Err_Syntax_Error;
+ }
+
+ /* If we are trying to load a composite glyph, do not load the */
+ /* accent character and return the array of subglyphs. */
+ if ( decoder->builder.no_recurse )
+ {
+ FT_GlyphSlot glyph = (FT_GlyphSlot)decoder->builder.glyph;
+ FT_GlyphLoader loader = glyph->internal->loader;
+ FT_SubGlyph subg;
+
+
+ /* reallocate subglyph array if necessary */
+ error = FT_GlyphLoader_CheckSubGlyphs( loader, 2 );
+ if ( error )
+ goto Exit;
+
+ subg = loader->current.subglyphs;
+
+ /* subglyph 0 = base character */
+ subg->index = bchar_index;
+ subg->flags = FT_SUBGLYPH_FLAG_ARGS_ARE_XY_VALUES |
+ FT_SUBGLYPH_FLAG_USE_MY_METRICS;
+ subg->arg1 = 0;
+ subg->arg2 = 0;
+ subg++;
+
+ /* subglyph 1 = accent character */
+ subg->index = achar_index;
+ subg->flags = FT_SUBGLYPH_FLAG_ARGS_ARE_XY_VALUES;
+ subg->arg1 = (FT_Int)adx;
+ subg->arg2 = (FT_Int)ady;
+
+ /* set up remaining glyph fields */
+ glyph->num_subglyphs = 2;
+ glyph->subglyphs = loader->base.subglyphs;
+ glyph->format = FT_GLYPH_FORMAT_COMPOSITE;
+
+ loader->current.num_subglyphs = 2;
+ }
+
+ /* First load `bchar' in builder */
+ error = cff_get_glyph_data( face, bchar_index,
+ &charstring, &charstring_len );
+ if ( !error )
+ {
+ error = cff_decoder_parse_charstrings( decoder, charstring,
+ charstring_len );
+
+ if ( error )
+ goto Exit;
+
+ cff_free_glyph_data( face, &charstring, charstring_len );
+ }
+
+ n_base_points = base->n_points;
+
+ /* Save the left bearing and width of the base character */
+ /* as they will be erased by the next load. */
+
+ left_bearing = decoder->builder.left_bearing;
+ advance = decoder->builder.advance;
+
+ decoder->builder.left_bearing.x = 0;
+ decoder->builder.left_bearing.y = 0;
+
+ /* Now load `achar' on top of the base outline. */
+ error = cff_get_glyph_data( face, achar_index,
+ &charstring, &charstring_len );
+ if ( !error )
+ {
+ error = cff_decoder_parse_charstrings( decoder, charstring,
+ charstring_len );
+
+ if ( error )
+ goto Exit;
+
+ cff_free_glyph_data( face, &charstring, charstring_len );
+ }
+
+ /* Restore the left side bearing and advance width */
+ /* of the base character. */
+ decoder->builder.left_bearing = left_bearing;
+ decoder->builder.advance = advance;
+
+ /* Finally, move the accent. */
+ if ( decoder->builder.load_points )
+ {
+ FT_Outline dummy;
+
+
+ dummy.n_points = (short)( base->n_points - n_base_points );
+ dummy.points = base->points + n_base_points;
+
+ FT_Outline_Translate( &dummy, adx, ady );
+ }
+
+ Exit:
+ return error;
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* cff_decoder_parse_charstrings */
+ /* */
+ /* <Description> */
+ /* Parses a given Type 2 charstrings program. */
+ /* */
+ /* <InOut> */
+ /* decoder :: The current Type 1 decoder. */
+ /* */
+ /* <Input> */
+ /* charstring_base :: The base of the charstring stream. */
+ /* */
+ /* charstring_len :: The length in bytes of the charstring stream. */
+ /* */
+ /* <Return> */
+ /* FreeType error code. 0 means success. */
+ /* */
+ FT_LOCAL_DEF( FT_Error )
+ cff_decoder_parse_charstrings( CFF_Decoder* decoder,
+ FT_Byte* charstring_base,
+ FT_ULong charstring_len )
+ {
+ FT_Error error;
+ CFF_Decoder_Zone* zone;
+ FT_Byte* ip;
+ FT_Byte* limit;
+ CFF_Builder* builder = &decoder->builder;
+ FT_Pos x, y;
+ FT_Fixed seed;
+ FT_Fixed* stack;
+
+ T2_Hints_Funcs hinter;
+
+
+ /* set default width */
+ decoder->num_hints = 0;
+ decoder->read_width = 1;
+
+ /* compute random seed from stack address of parameter */
+ seed = (FT_Fixed)(char*)&seed ^
+ (FT_Fixed)(char*)&decoder ^
+ (FT_Fixed)(char*)&charstring_base;
+ seed = ( seed ^ ( seed >> 10 ) ^ ( seed >> 20 ) ) & 0xFFFF;
+ if ( seed == 0 )
+ seed = 0x7384;
+
+ /* initialize the decoder */
+ decoder->top = decoder->stack;
+ decoder->zone = decoder->zones;
+ zone = decoder->zones;
+ stack = decoder->top;
+
+ hinter = (T2_Hints_Funcs) builder->hints_funcs;
+
+ builder->path_begun = 0;
+
+ zone->base = charstring_base;
+ limit = zone->limit = charstring_base + charstring_len;
+ ip = zone->cursor = zone->base;
+
+ error = CFF_Err_Ok;
+
+ x = builder->pos_x;
+ y = builder->pos_y;
+
+ /* begin hints recording session, if any */
+ if ( hinter )
+ hinter->open( hinter->hints );
+
+ /* now, execute loop */
+ while ( ip < limit )
+ {
+ CFF_Operator op;
+ FT_Byte v;
+
+
+ /********************************************************************/
+ /* */
+ /* Decode operator or operand */
+ /* */
+ v = *ip++;
+ if ( v >= 32 || v == 28 )
+ {
+ FT_Int shift = 16;
+ FT_Int32 val;
+
+
+ /* this is an operand, push it on the stack */
+ if ( v == 28 )
+ {
+ if ( ip + 1 >= limit )
+ goto Syntax_Error;
+ val = (FT_Short)( ( (FT_Short)ip[0] << 8 ) | ip[1] );
+ ip += 2;
+ }
+ else if ( v < 247 )
+ val = (FT_Long)v - 139;
+ else if ( v < 251 )
+ {
+ if ( ip >= limit )
+ goto Syntax_Error;
+ val = ( (FT_Long)v - 247 ) * 256 + *ip++ + 108;
+ }
+ else if ( v < 255 )
+ {
+ if ( ip >= limit )
+ goto Syntax_Error;
+ val = -( (FT_Long)v - 251 ) * 256 - *ip++ - 108;
+ }
+ else
+ {
+ if ( ip + 3 >= limit )
+ goto Syntax_Error;
+ val = ( (FT_Int32)ip[0] << 24 ) |
+ ( (FT_Int32)ip[1] << 16 ) |
+ ( (FT_Int32)ip[2] << 8 ) |
+ ip[3];
+ ip += 4;
+ shift = 0;
+ }
+ if ( decoder->top - stack >= CFF_MAX_OPERANDS )
+ goto Stack_Overflow;
+
+ val <<= shift;
+ *decoder->top++ = val;
+
+#ifdef FT_DEBUG_LEVEL_TRACE
+ if ( !( val & 0xFFFF ) )
+ FT_TRACE4(( " %d", (FT_Int32)( val >> 16 ) ));
+ else
+ FT_TRACE4(( " %.2f", val / 65536.0 ));
+#endif
+
+ }
+ else
+ {
+ FT_Fixed* args = decoder->top;
+ FT_Int num_args = (FT_Int)( args - decoder->stack );
+ FT_Int req_args;
+
+
+ /* find operator */
+ op = cff_op_unknown;
+
+ switch ( v )
+ {
+ case 1:
+ op = cff_op_hstem;
+ break;
+ case 3:
+ op = cff_op_vstem;
+ break;
+ case 4:
+ op = cff_op_vmoveto;
+ break;
+ case 5:
+ op = cff_op_rlineto;
+ break;
+ case 6:
+ op = cff_op_hlineto;
+ break;
+ case 7:
+ op = cff_op_vlineto;
+ break;
+ case 8:
+ op = cff_op_rrcurveto;
+ break;
+ case 10:
+ op = cff_op_callsubr;
+ break;
+ case 11:
+ op = cff_op_return;
+ break;
+ case 12:
+ {
+ if ( ip >= limit )
+ goto Syntax_Error;
+ v = *ip++;
+
+ switch ( v )
+ {
+ case 0:
+ op = cff_op_dotsection;
+ break;
+ case 3:
+ op = cff_op_and;
+ break;
+ case 4:
+ op = cff_op_or;
+ break;
+ case 5:
+ op = cff_op_not;
+ break;
+ case 8:
+ op = cff_op_store;
+ break;
+ case 9:
+ op = cff_op_abs;
+ break;
+ case 10:
+ op = cff_op_add;
+ break;
+ case 11:
+ op = cff_op_sub;
+ break;
+ case 12:
+ op = cff_op_div;
+ break;
+ case 13:
+ op = cff_op_load;
+ break;
+ case 14:
+ op = cff_op_neg;
+ break;
+ case 15:
+ op = cff_op_eq;
+ break;
+ case 18:
+ op = cff_op_drop;
+ break;
+ case 20:
+ op = cff_op_put;
+ break;
+ case 21:
+ op = cff_op_get;
+ break;
+ case 22:
+ op = cff_op_ifelse;
+ break;
+ case 23:
+ op = cff_op_random;
+ break;
+ case 24:
+ op = cff_op_mul;
+ break;
+ case 26:
+ op = cff_op_sqrt;
+ break;
+ case 27:
+ op = cff_op_dup;
+ break;
+ case 28:
+ op = cff_op_exch;
+ break;
+ case 29:
+ op = cff_op_index;
+ break;
+ case 30:
+ op = cff_op_roll;
+ break;
+ case 34:
+ op = cff_op_hflex;
+ break;
+ case 35:
+ op = cff_op_flex;
+ break;
+ case 36:
+ op = cff_op_hflex1;
+ break;
+ case 37:
+ op = cff_op_flex1;
+ break;
+ default:
+ /* decrement ip for syntax error message */
+ ip--;
+ }
+ }
+ break;
+ case 14:
+ op = cff_op_endchar;
+ break;
+ case 16:
+ op = cff_op_blend;
+ break;
+ case 18:
+ op = cff_op_hstemhm;
+ break;
+ case 19:
+ op = cff_op_hintmask;
+ break;
+ case 20:
+ op = cff_op_cntrmask;
+ break;
+ case 21:
+ op = cff_op_rmoveto;
+ break;
+ case 22:
+ op = cff_op_hmoveto;
+ break;
+ case 23:
+ op = cff_op_vstemhm;
+ break;
+ case 24:
+ op = cff_op_rcurveline;
+ break;
+ case 25:
+ op = cff_op_rlinecurve;
+ break;
+ case 26:
+ op = cff_op_vvcurveto;
+ break;
+ case 27:
+ op = cff_op_hhcurveto;
+ break;
+ case 29:
+ op = cff_op_callgsubr;
+ break;
+ case 30:
+ op = cff_op_vhcurveto;
+ break;
+ case 31:
+ op = cff_op_hvcurveto;
+ break;
+ default:
+ ;
+ }
+ if ( op == cff_op_unknown )
+ goto Syntax_Error;
+
+ /* check arguments */
+ req_args = cff_argument_counts[op];
+ if ( req_args & CFF_COUNT_CHECK_WIDTH )
+ {
+ args = stack;
+
+ if ( num_args > 0 && decoder->read_width )
+ {
+ /* If `nominal_width' is non-zero, the number is really a */
+ /* difference against `nominal_width'. Else, the number here */
+ /* is truly a width, not a difference against `nominal_width'. */
+ /* If the font does not set `nominal_width', then */
+ /* `nominal_width' defaults to zero, and so we can set */
+ /* `glyph_width' to `nominal_width' plus number on the stack */
+ /* -- for either case. */
+
+ FT_Int set_width_ok;
+
+
+ switch ( op )
+ {
+ case cff_op_hmoveto:
+ case cff_op_vmoveto:
+ set_width_ok = num_args & 2;
+ break;
+
+ case cff_op_hstem:
+ case cff_op_vstem:
+ case cff_op_hstemhm:
+ case cff_op_vstemhm:
+ case cff_op_rmoveto:
+ set_width_ok = num_args & 1;
+ break;
+
+ case cff_op_endchar:
+ /* If there is a width specified for endchar, we either have */
+ /* 1 argument or 5 arguments. We like to argue. */
+ set_width_ok = ( ( num_args == 5 ) || ( num_args == 1 ) );
+ break;
+
+ default:
+ set_width_ok = 0;
+ break;
+ }
+
+ if ( set_width_ok )
+ {
+ decoder->glyph_width = decoder->nominal_width +
+ ( stack[0] >> 16 );
+
+ /* Consumed an argument. */
+ num_args--;
+ args++;
+ }
+ }
+
+ decoder->read_width = 0;
+ req_args = 0;
+ }
+
+ req_args &= 15;
+ if ( num_args < req_args )
+ goto Stack_Underflow;
+ args -= req_args;
+ num_args -= req_args;
+
+ switch ( op )
+ {
+ case cff_op_hstem:
+ case cff_op_vstem:
+ case cff_op_hstemhm:
+ case cff_op_vstemhm:
+ /* the number of arguments is always even here */
+ FT_TRACE4(( op == cff_op_hstem ? " hstem" :
+ ( op == cff_op_vstem ? " vstem" :
+ ( op == cff_op_hstemhm ? " hstemhm" : " vstemhm" ) ) ));
+
+ if ( hinter )
+ hinter->stems( hinter->hints,
+ ( op == cff_op_hstem || op == cff_op_hstemhm ),
+ num_args / 2,
+ args );
+
+ decoder->num_hints += num_args / 2;
+ args = stack;
+ break;
+
+ case cff_op_hintmask:
+ case cff_op_cntrmask:
+ FT_TRACE4(( op == cff_op_hintmask ? " hintmask" : " cntrmask" ));
+
+ /* implement vstem when needed -- */
+ /* the specification doesn't say it, but this also works */
+ /* with the 'cntrmask' operator */
+ /* */
+ if ( num_args > 0 )
+ {
+ if ( hinter )
+ hinter->stems( hinter->hints,
+ 0,
+ num_args / 2,
+ args );
+
+ decoder->num_hints += num_args / 2;
+ }
+
+ if ( hinter )
+ {
+ if ( op == cff_op_hintmask )
+ hinter->hintmask( hinter->hints,
+ builder->current->n_points,
+ decoder->num_hints,
+ ip );
+ else
+ hinter->counter( hinter->hints,
+ decoder->num_hints,
+ ip );
+ }
+
+#ifdef FT_DEBUG_LEVEL_TRACE
+ {
+ FT_UInt maskbyte;
+
+
+ FT_TRACE4(( " " ));
+
+ for ( maskbyte = 0;
+ maskbyte < (FT_UInt)(( decoder->num_hints + 7 ) >> 3);
+ maskbyte++, ip++ )
+ FT_TRACE4(( "%02X", *ip ));
+ }
+#else
+ ip += ( decoder->num_hints + 7 ) >> 3;
+#endif
+ if ( ip >= limit )
+ goto Syntax_Error;
+ args = stack;
+ break;
+
+ case cff_op_rmoveto:
+ FT_TRACE4(( " rmoveto" ));
+
+ cff_builder_close_contour( builder );
+ builder->path_begun = 0;
+ x += args[0];
+ y += args[1];
+ args = stack;
+ break;
+
+ case cff_op_vmoveto:
+ FT_TRACE4(( " vmoveto" ));
+
+ cff_builder_close_contour( builder );
+ builder->path_begun = 0;
+ y += args[0];
+ args = stack;
+ break;
+
+ case cff_op_hmoveto:
+ FT_TRACE4(( " hmoveto" ));
+
+ cff_builder_close_contour( builder );
+ builder->path_begun = 0;
+ x += args[0];
+ args = stack;
+ break;
+
+ case cff_op_rlineto:
+ FT_TRACE4(( " rlineto" ));
+
+ if ( cff_builder_start_point ( builder, x, y ) ||
+ check_points( builder, num_args / 2 ) )
+ goto Memory_Error;
+
+ if ( num_args < 2 || num_args & 1 )
+ goto Stack_Underflow;
+
+ args = stack;
+ while ( args < decoder->top )
+ {
+ x += args[0];
+ y += args[1];
+ cff_builder_add_point( builder, x, y, 1 );
+ args += 2;
+ }
+ args = stack;
+ break;
+
+ case cff_op_hlineto:
+ case cff_op_vlineto:
+ {
+ FT_Int phase = ( op == cff_op_hlineto );
+
+
+ FT_TRACE4(( op == cff_op_hlineto ? " hlineto"
+ : " vlineto" ));
+
+ if ( cff_builder_start_point ( builder, x, y ) ||
+ check_points( builder, num_args ) )
+ goto Memory_Error;
+
+ args = stack;
+ while (args < decoder->top )
+ {
+ if ( phase )
+ x += args[0];
+ else
+ y += args[0];
+
+ if ( cff_builder_add_point1( builder, x, y ) )
+ goto Memory_Error;
+
+ args++;
+ phase ^= 1;
+ }
+ args = stack;
+ }
+ break;
+
+ case cff_op_rrcurveto:
+ FT_TRACE4(( " rrcurveto" ));
+
+ /* check number of arguments; must be a multiple of 6 */
+ if ( num_args % 6 != 0 )
+ goto Stack_Underflow;
+
+ if ( cff_builder_start_point ( builder, x, y ) ||
+ check_points( builder, num_args / 2 ) )
+ goto Memory_Error;
+
+ args = stack;
+ while ( args < decoder->top )
+ {
+ x += args[0];
+ y += args[1];
+ cff_builder_add_point( builder, x, y, 0 );
+ x += args[2];
+ y += args[3];
+ cff_builder_add_point( builder, x, y, 0 );
+ x += args[4];
+ y += args[5];
+ cff_builder_add_point( builder, x, y, 1 );
+ args += 6;
+ }
+ args = stack;
+ break;
+
+ case cff_op_vvcurveto:
+ FT_TRACE4(( " vvcurveto" ));
+
+ if ( cff_builder_start_point ( builder, x, y ) )
+ goto Memory_Error;
+
+ args = stack;
+ if ( num_args & 1 )
+ {
+ x += args[0];
+ args++;
+ num_args--;
+ }
+
+ if ( num_args % 4 != 0 )
+ goto Stack_Underflow;
+
+ if ( check_points( builder, 3 * ( num_args / 4 ) ) )
+ goto Memory_Error;
+
+ while ( args < decoder->top )
+ {
+ y += args[0];
+ cff_builder_add_point( builder, x, y, 0 );
+ x += args[1];
+ y += args[2];
+ cff_builder_add_point( builder, x, y, 0 );
+ y += args[3];
+ cff_builder_add_point( builder, x, y, 1 );
+ args += 4;
+ }
+ args = stack;
+ break;
+
+ case cff_op_hhcurveto:
+ FT_TRACE4(( " hhcurveto" ));
+
+ if ( cff_builder_start_point ( builder, x, y ) )
+ goto Memory_Error;
+
+ args = stack;
+ if ( num_args & 1 )
+ {
+ y += args[0];
+ args++;
+ num_args--;
+ }
+
+ if ( num_args % 4 != 0 )
+ goto Stack_Underflow;
+
+ if ( check_points( builder, 3 * ( num_args / 4 ) ) )
+ goto Memory_Error;
+
+ while ( args < decoder->top )
+ {
+ x += args[0];
+ cff_builder_add_point( builder, x, y, 0 );
+ x += args[1];
+ y += args[2];
+ cff_builder_add_point( builder, x, y, 0 );
+ x += args[3];
+ cff_builder_add_point( builder, x, y, 1 );
+ args += 4;
+ }
+ args = stack;
+ break;
+
+ case cff_op_vhcurveto:
+ case cff_op_hvcurveto:
+ {
+ FT_Int phase;
+
+
+ FT_TRACE4(( op == cff_op_vhcurveto ? " vhcurveto"
+ : " hvcurveto" ));
+
+ if ( cff_builder_start_point ( builder, x, y ) )
+ goto Memory_Error;
+
+ args = stack;
+ if (num_args < 4 || ( num_args % 4 ) > 1 )
+ goto Stack_Underflow;
+
+ if ( check_points( builder, ( num_args / 4 ) * 3 ) )
+ goto Stack_Underflow;
+
+ phase = ( op == cff_op_hvcurveto );
+
+ while ( num_args >= 4 )
+ {
+ num_args -= 4;
+ if ( phase )
+ {
+ x += args[0];
+ cff_builder_add_point( builder, x, y, 0 );
+ x += args[1];
+ y += args[2];
+ cff_builder_add_point( builder, x, y, 0 );
+ y += args[3];
+ if ( num_args == 1 )
+ x += args[4];
+ cff_builder_add_point( builder, x, y, 1 );
+ }
+ else
+ {
+ y += args[0];
+ cff_builder_add_point( builder, x, y, 0 );
+ x += args[1];
+ y += args[2];
+ cff_builder_add_point( builder, x, y, 0 );
+ x += args[3];
+ if ( num_args == 1 )
+ y += args[4];
+ cff_builder_add_point( builder, x, y, 1 );
+ }
+ args += 4;
+ phase ^= 1;
+ }
+ args = stack;
+ }
+ break;
+
+ case cff_op_rlinecurve:
+ {
+ FT_Int num_lines = ( num_args - 6 ) / 2;
+
+
+ FT_TRACE4(( " rlinecurve" ));
+
+ if ( num_args < 8 || ( num_args - 6 ) & 1 )
+ goto Stack_Underflow;
+
+ if ( cff_builder_start_point( builder, x, y ) ||
+ check_points( builder, num_lines + 3 ) )
+ goto Memory_Error;
+
+ args = stack;
+
+ /* first, add the line segments */
+ while ( num_lines > 0 )
+ {
+ x += args[0];
+ y += args[1];
+ cff_builder_add_point( builder, x, y, 1 );
+ args += 2;
+ num_lines--;
+ }
+
+ /* then the curve */
+ x += args[0];
+ y += args[1];
+ cff_builder_add_point( builder, x, y, 0 );
+ x += args[2];
+ y += args[3];
+ cff_builder_add_point( builder, x, y, 0 );
+ x += args[4];
+ y += args[5];
+ cff_builder_add_point( builder, x, y, 1 );
+ args = stack;
+ }
+ break;
+
+ case cff_op_rcurveline:
+ {
+ FT_Int num_curves = ( num_args - 2 ) / 6;
+
+
+ FT_TRACE4(( " rcurveline" ));
+
+ if ( num_args < 8 || ( num_args - 2 ) % 6 )
+ goto Stack_Underflow;
+
+ if ( cff_builder_start_point ( builder, x, y ) ||
+ check_points( builder, num_curves*3 + 2 ) )
+ goto Memory_Error;
+
+ args = stack;
+
+ /* first, add the curves */
+ while ( num_curves > 0 )
+ {
+ x += args[0];
+ y += args[1];
+ cff_builder_add_point( builder, x, y, 0 );
+ x += args[2];
+ y += args[3];
+ cff_builder_add_point( builder, x, y, 0 );
+ x += args[4];
+ y += args[5];
+ cff_builder_add_point( builder, x, y, 1 );
+ args += 6;
+ num_curves--;
+ }
+
+ /* then the final line */
+ x += args[0];
+ y += args[1];
+ cff_builder_add_point( builder, x, y, 1 );
+ args = stack;
+ }
+ break;
+
+ case cff_op_hflex1:
+ {
+ FT_Pos start_y;
+
+
+ FT_TRACE4(( " hflex1" ));
+
+ args = stack;
+
+ /* adding five more points; 4 control points, 1 on-curve point */
+ /* make sure we have enough space for the start point if it */
+ /* needs to be added.. */
+ if ( cff_builder_start_point( builder, x, y ) ||
+ check_points( builder, 6 ) )
+ goto Memory_Error;
+
+ /* Record the starting point's y postion for later use */
+ start_y = y;
+
+ /* first control point */
+ x += args[0];
+ y += args[1];
+ cff_builder_add_point( builder, x, y, 0 );
+
+ /* second control point */
+ x += args[2];
+ y += args[3];
+ cff_builder_add_point( builder, x, y, 0 );
+
+ /* join point; on curve, with y-value the same as the last */
+ /* control point's y-value */
+ x += args[4];
+ cff_builder_add_point( builder, x, y, 1 );
+
+ /* third control point, with y-value the same as the join */
+ /* point's y-value */
+ x += args[5];
+ cff_builder_add_point( builder, x, y, 0 );
+
+ /* fourth control point */
+ x += args[6];
+ y += args[7];
+ cff_builder_add_point( builder, x, y, 0 );
+
+ /* ending point, with y-value the same as the start */
+ x += args[8];
+ y = start_y;
+ cff_builder_add_point( builder, x, y, 1 );
+
+ args = stack;
+ break;
+ }
+
+ case cff_op_hflex:
+ {
+ FT_Pos start_y;
+
+
+ FT_TRACE4(( " hflex" ));
+
+ args = stack;
+
+ /* adding six more points; 4 control points, 2 on-curve points */
+ if ( cff_builder_start_point( builder, x, y ) ||
+ check_points ( builder, 6 ) )
+ goto Memory_Error;
+
+ /* record the starting point's y-position for later use */
+ start_y = y;
+
+ /* first control point */
+ x += args[0];
+ cff_builder_add_point( builder, x, y, 0 );
+
+ /* second control point */
+ x += args[1];
+ y += args[2];
+ cff_builder_add_point( builder, x, y, 0 );
+
+ /* join point; on curve, with y-value the same as the last */
+ /* control point's y-value */
+ x += args[3];
+ cff_builder_add_point( builder, x, y, 1 );
+
+ /* third control point, with y-value the same as the join */
+ /* point's y-value */
+ x += args[4];
+ cff_builder_add_point( builder, x, y, 0 );
+
+ /* fourth control point */
+ x += args[5];
+ y = start_y;
+ cff_builder_add_point( builder, x, y, 0 );
+
+ /* ending point, with y-value the same as the start point's */
+ /* y-value -- we don't add this point, though */
+ x += args[6];
+ cff_builder_add_point( builder, x, y, 1 );
+
+ args = stack;
+ break;
+ }
+
+ case cff_op_flex1:
+ {
+ FT_Pos start_x, start_y; /* record start x, y values for alter */
+ /* use */
+ FT_Int dx = 0, dy = 0; /* used in horizontal/vertical */
+ /* algorithm below */
+ FT_Int horizontal, count;
+
+
+ FT_TRACE4(( " flex1" ));
+
+ /* adding six more points; 4 control points, 2 on-curve points */
+ if ( cff_builder_start_point( builder, x, y ) ||
+ check_points( builder, 6 ) )
+ goto Memory_Error;
+
+ /* record the starting point's x, y postion for later use */
+ start_x = x;
+ start_y = y;
+
+ /* XXX: figure out whether this is supposed to be a horizontal */
+ /* or vertical flex; the Type 2 specification is vague... */
+
+ args = stack;
+
+ /* grab up to the last argument */
+ for ( count = 5; count > 0; count-- )
+ {
+ dx += (FT_Int)args[0];
+ dy += (FT_Int)args[1];
+ args += 2;
+ }
+
+ /* rewind */
+ args = stack;
+
+ if ( dx < 0 ) dx = -dx;
+ if ( dy < 0 ) dy = -dy;
+
+ /* strange test, but here it is... */
+ horizontal = ( dx > dy );
+
+ for ( count = 5; count > 0; count-- )
+ {
+ x += args[0];
+ y += args[1];
+ cff_builder_add_point( builder, x, y, (FT_Bool)( count == 3 ) );
+ args += 2;
+ }
+
+ /* is last operand an x- or y-delta? */
+ if ( horizontal )
+ {
+ x += args[0];
+ y = start_y;
+ }
+ else
+ {
+ x = start_x;
+ y += args[0];
+ }
+
+ cff_builder_add_point( builder, x, y, 1 );
+
+ args = stack;
+ break;
+ }
+
+ case cff_op_flex:
+ {
+ FT_UInt count;
+
+
+ FT_TRACE4(( " flex" ));
+
+ if ( cff_builder_start_point( builder, x, y ) ||
+ check_points( builder, 6 ) )
+ goto Memory_Error;
+
+ args = stack;
+ for ( count = 6; count > 0; count-- )
+ {
+ x += args[0];
+ y += args[1];
+ cff_builder_add_point( builder, x, y,
+ (FT_Bool)( count == 3 || count == 0 ) );
+ args += 2;
+ }
+
+ args = stack;
+ }
+ break;
+
+ case cff_op_endchar:
+ FT_TRACE4(( " endchar" ));
+
+ /* We are going to emulate the seac operator. */
+ if ( num_args == 4 )
+ {
+ error = cff_operator_seac( decoder,
+ args[0] >> 16,
+ args[1] >> 16,
+ (FT_Int)( args[2] >> 16 ),
+ (FT_Int)( args[3] >> 16 ) );
+ args += 4;
+ }
+
+ if ( !error )
+ error = CFF_Err_Ok;
+
+ cff_builder_close_contour( builder );
+
+ /* close hints recording session */
+ if ( hinter )
+ {
+ if (hinter->close( hinter->hints, builder->current->n_points ) )
+ goto Syntax_Error;
+
+ /* apply hints to the loaded glyph outline now */
+ hinter->apply( hinter->hints,
+ builder->current,
+ (PSH_Globals)builder->hints_globals,
+ builder->hint_flags );
+ }
+
+ /* add current outline to the glyph slot */
+ FT_GlyphLoader_Add( builder->loader );
+
+ /* return now! */
+ FT_TRACE4(( "\n\n" ));
+ return error;
+
+ case cff_op_abs:
+ FT_TRACE4(( " abs" ));
+
+ if ( args[0] < 0 )
+ args[0] = -args[0];
+ args++;
+ break;
+
+ case cff_op_add:
+ FT_TRACE4(( " add" ));
+
+ args[0] += args[1];
+ args++;
+ break;
+
+ case cff_op_sub:
+ FT_TRACE4(( " sub" ));
+
+ args[0] -= args[1];
+ args++;
+ break;
+
+ case cff_op_div:
+ FT_TRACE4(( " div" ));
+
+ args[0] = FT_DivFix( args[0], args[1] );
+ args++;
+ break;
+
+ case cff_op_neg:
+ FT_TRACE4(( " neg" ));
+
+ args[0] = -args[0];
+ args++;
+ break;
+
+ case cff_op_random:
+ {
+ FT_Fixed Rand;
+
+
+ FT_TRACE4(( " rand" ));
+
+ Rand = seed;
+ if ( Rand >= 0x8000 )
+ Rand++;
+
+ args[0] = Rand;
+ seed = FT_MulFix( seed, 0x10000L - seed );
+ if ( seed == 0 )
+ seed += 0x2873;
+ args++;
+ }
+ break;
+
+ case cff_op_mul:
+ FT_TRACE4(( " mul" ));
+
+ args[0] = FT_MulFix( args[0], args[1] );
+ args++;
+ break;
+
+ case cff_op_sqrt:
+ FT_TRACE4(( " sqrt" ));
+
+ if ( args[0] > 0 )
+ {
+ FT_Int count = 9;
+ FT_Fixed root = args[0];
+ FT_Fixed new_root;
+
+
+ for (;;)
+ {
+ new_root = ( root + FT_DivFix( args[0], root ) + 1 ) >> 1;
+ if ( new_root == root || count <= 0 )
+ break;
+ root = new_root;
+ }
+ args[0] = new_root;
+ }
+ else
+ args[0] = 0;
+ args++;
+ break;
+
+ case cff_op_drop:
+ /* nothing */
+ FT_TRACE4(( " drop" ));
+
+ break;
+
+ case cff_op_exch:
+ {
+ FT_Fixed tmp;
+
+
+ FT_TRACE4(( " exch" ));
+
+ tmp = args[0];
+ args[0] = args[1];
+ args[1] = tmp;
+ args += 2;
+ }
+ break;
+
+ case cff_op_index:
+ {
+ FT_Int idx = (FT_Int)( args[0] >> 16 );
+
+
+ FT_TRACE4(( " index" ));
+
+ if ( idx < 0 )
+ idx = 0;
+ else if ( idx > num_args - 2 )
+ idx = num_args - 2;
+ args[0] = args[-( idx + 1 )];
+ args++;
+ }
+ break;
+
+ case cff_op_roll:
+ {
+ FT_Int count = (FT_Int)( args[0] >> 16 );
+ FT_Int idx = (FT_Int)( args[1] >> 16 );
+
+
+ FT_TRACE4(( " roll" ));
+
+ if ( count <= 0 )
+ count = 1;
+
+ args -= count;
+ if ( args < stack )
+ goto Stack_Underflow;
+
+ if ( idx >= 0 )
+ {
+ while ( idx > 0 )
+ {
+ FT_Fixed tmp = args[count - 1];
+ FT_Int i;
+
+
+ for ( i = count - 2; i >= 0; i-- )
+ args[i + 1] = args[i];
+ args[0] = tmp;
+ idx--;
+ }
+ }
+ else
+ {
+ while ( idx < 0 )
+ {
+ FT_Fixed tmp = args[0];
+ FT_Int i;
+
+
+ for ( i = 0; i < count - 1; i++ )
+ args[i] = args[i + 1];
+ args[count - 1] = tmp;
+ idx++;
+ }
+ }
+ args += count;
+ }
+ break;
+
+ case cff_op_dup:
+ FT_TRACE4(( " dup" ));
+
+ args[1] = args[0];
+ args++;
+ break;
+
+ case cff_op_put:
+ {
+ FT_Fixed val = args[0];
+ FT_Int idx = (FT_Int)( args[1] >> 16 );
+
+
+ FT_TRACE4(( " put" ));
+
+ if ( idx >= 0 && idx < decoder->len_buildchar )
+ decoder->buildchar[idx] = val;
+ }
+ break;
+
+ case cff_op_get:
+ {
+ FT_Int idx = (FT_Int)( args[0] >> 16 );
+ FT_Fixed val = 0;
+
+
+ FT_TRACE4(( " get" ));
+
+ if ( idx >= 0 && idx < decoder->len_buildchar )
+ val = decoder->buildchar[idx];
+
+ args[0] = val;
+ args++;
+ }
+ break;
+
+ case cff_op_store:
+ FT_TRACE4(( " store "));
+
+ goto Unimplemented;
+
+ case cff_op_load:
+ FT_TRACE4(( " load" ));
+
+ goto Unimplemented;
+
+ case cff_op_dotsection:
+ /* this operator is deprecated and ignored by the parser */
+ FT_TRACE4(( " dotsection" ));
+ break;
+
+ case cff_op_and:
+ {
+ FT_Fixed cond = args[0] && args[1];
+
+
+ FT_TRACE4(( " and" ));
+
+ args[0] = cond ? 0x10000L : 0;
+ args++;
+ }
+ break;
+
+ case cff_op_or:
+ {
+ FT_Fixed cond = args[0] || args[1];
+
+
+ FT_TRACE4(( " or" ));
+
+ args[0] = cond ? 0x10000L : 0;
+ args++;
+ }
+ break;
+
+ case cff_op_eq:
+ {
+ FT_Fixed cond = !args[0];
+
+
+ FT_TRACE4(( " eq" ));
+
+ args[0] = cond ? 0x10000L : 0;
+ args++;
+ }
+ break;
+
+ case cff_op_ifelse:
+ {
+ FT_Fixed cond = (args[2] <= args[3]);
+
+
+ FT_TRACE4(( " ifelse" ));
+
+ if ( !cond )
+ args[0] = args[1];
+ args++;
+ }
+ break;
+
+ case cff_op_callsubr:
+ {
+ FT_UInt idx = (FT_UInt)( ( args[0] >> 16 ) +
+ decoder->locals_bias );
+
+
+ FT_TRACE4(( " callsubr(%d)", idx ));
+
+ if ( idx >= decoder->num_locals )
+ {
+ FT_ERROR(( "cff_decoder_parse_charstrings:" ));
+ FT_ERROR(( " invalid local subr index\n" ));
+ goto Syntax_Error;
+ }
+
+ if ( zone - decoder->zones >= CFF_MAX_SUBRS_CALLS )
+ {
+ FT_ERROR(( "cff_decoder_parse_charstrings:"
+ " too many nested subrs\n" ));
+ goto Syntax_Error;
+ }
+
+ zone->cursor = ip; /* save current instruction pointer */
+
+ zone++;
+ zone->base = decoder->locals[idx];
+ zone->limit = decoder->locals[idx + 1];
+ zone->cursor = zone->base;
+
+ if ( !zone->base )
+ {
+ FT_ERROR(( "cff_decoder_parse_charstrings:"
+ " invoking empty subrs!\n" ));
+ goto Syntax_Error;
+ }
+
+ decoder->zone = zone;
+ ip = zone->base;
+ limit = zone->limit;
+ }
+ break;
+
+ case cff_op_callgsubr:
+ {
+ FT_UInt idx = (FT_UInt)( ( args[0] >> 16 ) +
+ decoder->globals_bias );
+
+
+ FT_TRACE4(( " callgsubr(%d)", idx ));
+
+ if ( idx >= decoder->num_globals )
+ {
+ FT_ERROR(( "cff_decoder_parse_charstrings:" ));
+ FT_ERROR(( " invalid global subr index\n" ));
+ goto Syntax_Error;
+ }
+
+ if ( zone - decoder->zones >= CFF_MAX_SUBRS_CALLS )
+ {
+ FT_ERROR(( "cff_decoder_parse_charstrings:"
+ " too many nested subrs\n" ));
+ goto Syntax_Error;
+ }
+
+ zone->cursor = ip; /* save current instruction pointer */
+
+ zone++;
+ zone->base = decoder->globals[idx];
+ zone->limit = decoder->globals[idx + 1];
+ zone->cursor = zone->base;
+
+ if ( !zone->base )
+ {
+ FT_ERROR(( "cff_decoder_parse_charstrings:"
+ " invoking empty subrs!\n" ));
+ goto Syntax_Error;
+ }
+
+ decoder->zone = zone;
+ ip = zone->base;
+ limit = zone->limit;
+ }
+ break;
+
+ case cff_op_return:
+ FT_TRACE4(( " return" ));
+
+ if ( decoder->zone <= decoder->zones )
+ {
+ FT_ERROR(( "cff_decoder_parse_charstrings:"
+ " unexpected return\n" ));
+ goto Syntax_Error;
+ }
+
+ decoder->zone--;
+ zone = decoder->zone;
+ ip = zone->cursor;
+ limit = zone->limit;
+ break;
+
+ default:
+ Unimplemented:
+ FT_ERROR(( "Unimplemented opcode: %d", ip[-1] ));
+
+ if ( ip[-1] == 12 )
+ FT_ERROR(( " %d", ip[0] ));
+ FT_ERROR(( "\n" ));
+
+ return CFF_Err_Unimplemented_Feature;
+ }
+
+ decoder->top = args;
+
+ } /* general operator processing */
+
+ } /* while ip < limit */
+
+ FT_TRACE4(( "..end..\n\n" ));
+
+ return error;
+
+ Syntax_Error:
+ FT_TRACE4(( "cff_decoder_parse_charstrings: syntax error!" ));
+ return CFF_Err_Invalid_File_Format;
+
+ Stack_Underflow:
+ FT_TRACE4(( "cff_decoder_parse_charstrings: stack underflow!" ));
+ return CFF_Err_Too_Few_Arguments;
+
+ Stack_Overflow:
+ FT_TRACE4(( "cff_decoder_parse_charstrings: stack overflow!" ));
+ return CFF_Err_Stack_Overflow;
+
+ Memory_Error:
+ return builder->error;
+ }
+
+
+ /*************************************************************************/
+ /*************************************************************************/
+ /*************************************************************************/
+ /********** *********/
+ /********** *********/
+ /********** COMPUTE THE MAXIMUM ADVANCE WIDTH *********/
+ /********** *********/
+ /********** The following code is in charge of computing *********/
+ /********** the maximum advance width of the font. It *********/
+ /********** quickly processes each glyph charstring to *********/
+ /********** extract the value from either a `sbw' or `seac' *********/
+ /********** operator. *********/
+ /********** *********/
+ /*************************************************************************/
+ /*************************************************************************/
+ /*************************************************************************/
+
+
+#if 0 /* unused until we support pure CFF fonts */
+
+
+ FT_LOCAL_DEF( FT_Error )
+ cff_compute_max_advance( TT_Face face,
+ FT_Int* max_advance )
+ {
+ FT_Error error = 0;
+ CFF_Decoder decoder;
+ FT_Int glyph_index;
+ CFF_Font cff = (CFF_Font)face->other;
+
+
+ *max_advance = 0;
+
+ /* Initialize load decoder */
+ cff_decoder_init( &decoder, face, 0, 0, 0, 0 );
+
+ decoder.builder.metrics_only = 1;
+ decoder.builder.load_points = 0;
+
+ /* For each glyph, parse the glyph charstring and extract */
+ /* the advance width. */
+ for ( glyph_index = 0; glyph_index < face->root.num_glyphs;
+ glyph_index++ )
+ {
+ FT_Byte* charstring;
+ FT_ULong charstring_len;
+
+
+ /* now get load the unscaled outline */
+ error = cff_get_glyph_data( face, glyph_index,
+ &charstring, &charstring_len );
+ if ( !error )
+ {
+ cff_decoder_prepare( &decoder, glyph_index );
+ error = cff_decoder_parse_charstrings( &decoder,
+ charstring, charstring_len );
+
+ cff_free_glyph_data( face, &charstring, &charstring_len );
+ }
+
+ /* ignore the error if one has occurred -- skip to next glyph */
+ error = 0;
+ }
+
+ *max_advance = decoder.builder.advance.x;
+
+ return CFF_Err_Ok;
+ }
+
+
+#endif /* 0 */
+
+
+ /*************************************************************************/
+ /*************************************************************************/
+ /*************************************************************************/
+ /********** *********/
+ /********** *********/
+ /********** UNHINTED GLYPH LOADER *********/
+ /********** *********/
+ /********** The following code is in charge of loading a *********/
+ /********** single outline. It completely ignores hinting *********/
+ /********** and is used when FT_LOAD_NO_HINTING is set. *********/
+ /********** *********/
+ /*************************************************************************/
+ /*************************************************************************/
+ /*************************************************************************/
+
+
+ FT_LOCAL_DEF( FT_Error )
+ cff_slot_load( CFF_GlyphSlot glyph,
+ CFF_Size size,
+ FT_Int glyph_index,
+ FT_Int32 load_flags )
+ {
+ FT_Error error;
+ CFF_Decoder decoder;
+ TT_Face face = (TT_Face)glyph->root.face;
+ FT_Bool hinting;
+ CFF_Font cff = (CFF_Font)face->extra.data;
+
+ FT_Matrix font_matrix;
+ FT_Vector font_offset;
+
+
+ if ( load_flags & FT_LOAD_NO_RECURSE )
+ load_flags |= FT_LOAD_NO_SCALE | FT_LOAD_NO_HINTING;
+
+ glyph->x_scale = 0x10000L;
+ glyph->y_scale = 0x10000L;
+ if ( size )
+ {
+ glyph->x_scale = size->metrics.x_scale;
+ glyph->y_scale = size->metrics.y_scale;
+ }
+
+ glyph->root.outline.n_points = 0;
+ glyph->root.outline.n_contours = 0;
+
+ hinting = FT_BOOL( ( load_flags & FT_LOAD_NO_SCALE ) == 0 &&
+ ( load_flags & FT_LOAD_NO_HINTING ) == 0 );
+
+ glyph->root.format = FT_GLYPH_FORMAT_OUTLINE; /* by default */
+
+ {
+ FT_Byte* charstring;
+ FT_ULong charstring_len;
+
+
+ cff_decoder_init( &decoder, face, size, glyph, hinting,
+ FT_LOAD_TARGET_MODE(load_flags) );
+
+ decoder.builder.no_recurse =
+ (FT_Bool)( ( load_flags & FT_LOAD_NO_RECURSE ) != 0 );
+
+ /* now load the unscaled outline */
+ error = cff_get_glyph_data( face, glyph_index,
+ &charstring, &charstring_len );
+ if ( !error )
+ {
+ cff_decoder_prepare( &decoder, glyph_index );
+ error = cff_decoder_parse_charstrings( &decoder,
+ charstring, charstring_len );
+
+ cff_free_glyph_data( face, &charstring, charstring_len );
+
+
+#ifdef FT_CONFIG_OPTION_INCREMENTAL
+ /* Control data and length may not be available for incremental */
+ /* fonts. */
+ if ( face->root.internal->incremental_interface )
+ {
+ glyph->root.control_data = 0;
+ glyph->root.control_len = 0;
+ }
+ else
+#endif /* FT_CONFIG_OPTION_INCREMENTAL */
+
+ /* We set control_data and control_len if charstrings is loaded. */
+ /* See how charstring loads at cff_index_access_element() in */
+ /* cffload.c. */
+ {
+ CFF_IndexRec csindex = cff->charstrings_index;
+
+
+ glyph->root.control_data =
+ csindex.bytes + csindex.offsets[glyph_index] - 1;
+ glyph->root.control_len =
+ charstring_len;
+ }
+ }
+
+ /* save new glyph tables */
+ cff_builder_done( &decoder.builder );
+ }
+
+ font_matrix = cff->top_font.font_dict.font_matrix;
+ font_offset = cff->top_font.font_dict.font_offset;
+
+ /* Now, set the metrics -- this is rather simple, as */
+ /* the left side bearing is the xMin, and the top side */
+ /* bearing the yMax. */
+ if ( !error )
+ {
+ /* For composite glyphs, return only left side bearing and */
+ /* advance width. */
+ if ( load_flags & FT_LOAD_NO_RECURSE )
+ {
+ FT_Slot_Internal internal = glyph->root.internal;
+
+
+ glyph->root.metrics.horiBearingX = decoder.builder.left_bearing.x;
+ glyph->root.metrics.horiAdvance = decoder.glyph_width;
+ internal->glyph_matrix = font_matrix;
+ internal->glyph_delta = font_offset;
+ internal->glyph_transformed = 1;
+ }
+ else
+ {
+ FT_BBox cbox;
+ FT_Glyph_Metrics* metrics = &glyph->root.metrics;
+
+
+ /* copy the _unscaled_ advance width */
+ metrics->horiAdvance = decoder.glyph_width;
+ glyph->root.linearHoriAdvance = decoder.glyph_width;
+ glyph->root.internal->glyph_transformed = 0;
+
+ /* make up vertical metrics */
+ metrics->vertBearingX = 0;
+ metrics->vertBearingY = 0;
+ metrics->vertAdvance = 0;
+
+ glyph->root.linearVertAdvance = 0;
+
+ glyph->root.format = FT_GLYPH_FORMAT_OUTLINE;
+
+ glyph->root.outline.flags = 0;
+ if ( size && size->metrics.y_ppem < 24 )
+ glyph->root.outline.flags |= FT_OUTLINE_HIGH_PRECISION;
+
+ glyph->root.outline.flags |= FT_OUTLINE_REVERSE_FILL;
+
+ /* apply the font matrix */
+ FT_Outline_Transform( &glyph->root.outline, &font_matrix );
+
+ FT_Outline_Translate( &glyph->root.outline,
+ font_offset.x,
+ font_offset.y );
+
+ if ( ( load_flags & FT_LOAD_NO_SCALE ) == 0 )
+ {
+ /* scale the outline and the metrics */
+ FT_Int n;
+ FT_Outline* cur = &glyph->root.outline;
+ FT_Vector* vec = cur->points;
+ FT_Fixed x_scale = glyph->x_scale;
+ FT_Fixed y_scale = glyph->y_scale;
+
+
+ /* First of all, scale the points */
+ if ( !hinting )
+ for ( n = cur->n_points; n > 0; n--, vec++ )
+ {
+ vec->x = FT_MulFix( vec->x, x_scale );
+ vec->y = FT_MulFix( vec->y, y_scale );
+ }
+
+ FT_Outline_Get_CBox( &glyph->root.outline, &cbox );
+
+ /* Then scale the metrics */
+ metrics->horiAdvance = FT_MulFix( metrics->horiAdvance, x_scale );
+ metrics->vertAdvance = FT_MulFix( metrics->vertAdvance, y_scale );
+
+ metrics->vertBearingX = FT_MulFix( metrics->vertBearingX, x_scale );
+ metrics->vertBearingY = FT_MulFix( metrics->vertBearingY, y_scale );
+
+ if ( hinting )
+ {
+ metrics->horiAdvance = ( metrics->horiAdvance + 32 ) & -64;
+ metrics->vertAdvance = ( metrics->vertAdvance + 32 ) & -64;
+
+ metrics->vertBearingX = ( metrics->vertBearingX + 32 ) & -64;
+ metrics->vertBearingY = ( metrics->vertBearingY + 32 ) & -64;
+ }
+ }
+
+ /* compute the other metrics */
+ FT_Outline_Get_CBox( &glyph->root.outline, &cbox );
+
+ /* grid fit the bounding box if necessary */
+ if ( hinting )
+ {
+ cbox.xMin &= -64;
+ cbox.yMin &= -64;
+ cbox.xMax = ( cbox.xMax + 63 ) & -64;
+ cbox.yMax = ( cbox.yMax + 63 ) & -64;
+ }
+
+ metrics->width = cbox.xMax - cbox.xMin;
+ metrics->height = cbox.yMax - cbox.yMin;
+
+ metrics->horiBearingX = cbox.xMin;
+ metrics->horiBearingY = cbox.yMax;
+ }
+ }
+
+ return error;
+ }
+
+
+/* END */
--- /dev/null
+++ b/libfreetype/cffgload.h
@@ -1,0 +1,214 @@
+/***************************************************************************/
+/* */
+/* cffgload.h */
+/* */
+/* OpenType Glyph Loader (specification). */
+/* */
+/* Copyright 1996-2001, 2002 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+
+#ifndef __CFFGLOAD_H__
+#define __CFFGLOAD_H__
+
+
+#include <ft2build.h>
+#include FT_FREETYPE_H
+#include "cffobjs.h"
+
+
+FT_BEGIN_HEADER
+
+
+#define CFF_MAX_OPERANDS 48
+#define CFF_MAX_SUBRS_CALLS 32
+
+
+ /*************************************************************************/
+ /* */
+ /* <Structure> */
+ /* CFF_Builder */
+ /* */
+ /* <Description> */
+ /* A structure used during glyph loading to store its outline. */
+ /* */
+ /* <Fields> */
+ /* memory :: The current memory object. */
+ /* */
+ /* face :: The current face object. */
+ /* */
+ /* glyph :: The current glyph slot. */
+ /* */
+ /* loader :: The current glyph loader. */
+ /* */
+ /* base :: The base glyph outline. */
+ /* */
+ /* current :: The current glyph outline. */
+ /* */
+ /* last :: The last point position. */
+ /* */
+ /* scale_x :: The horizontal scale (FUnits to sub-pixels). */
+ /* */
+ /* scale_y :: The vertical scale (FUnits to sub-pixels). */
+ /* */
+ /* pos_x :: The horizontal translation (if composite glyph). */
+ /* */
+ /* pos_y :: The vertical translation (if composite glyph). */
+ /* */
+ /* left_bearing :: The left side bearing point. */
+ /* */
+ /* advance :: The horizontal advance vector. */
+ /* */
+ /* bbox :: Unused. */
+ /* */
+ /* path_begun :: A flag which indicates that a new path has begun. */
+ /* */
+ /* load_points :: If this flag is not set, no points are loaded. */
+ /* */
+ /* no_recurse :: Set but not used. */
+ /* */
+ /* error :: An error code that is only used to report memory */
+ /* allocation problems. */
+ /* */
+ /* metrics_only :: A boolean indicating that we only want to compute */
+ /* the metrics of a given glyph, not load all of its */
+ /* points. */
+ /* */
+ /* hints_funcs :: Auxiliary pointer for hinting. */
+ /* */
+ /* hints_globals :: Auxiliary pointer for hinting. */
+ /* */
+ typedef struct CFF_Builder_
+ {
+ FT_Memory memory;
+ TT_Face face;
+ CFF_GlyphSlot glyph;
+ FT_GlyphLoader loader;
+ FT_Outline* base;
+ FT_Outline* current;
+
+ FT_Vector last;
+
+ FT_Fixed scale_x;
+ FT_Fixed scale_y;
+
+ FT_Pos pos_x;
+ FT_Pos pos_y;
+
+ FT_Vector left_bearing;
+ FT_Vector advance;
+
+ FT_BBox bbox; /* bounding box */
+ FT_Bool path_begun;
+ FT_Bool load_points;
+ FT_Bool no_recurse;
+
+ FT_Error error; /* only used for memory errors */
+ FT_Bool metrics_only;
+
+ FT_UInt32 hint_flags;
+
+ void* hints_funcs; /* hinter-specific */
+ void* hints_globals; /* hinter-specific */
+
+ } CFF_Builder;
+
+
+ /* execution context charstring zone */
+
+ typedef struct CFF_Decoder_Zone_
+ {
+ FT_Byte* base;
+ FT_Byte* limit;
+ FT_Byte* cursor;
+
+ } CFF_Decoder_Zone;
+
+
+ typedef struct CFF_Decoder_
+ {
+ CFF_Builder builder;
+ CFF_Font cff;
+
+ FT_Fixed stack[CFF_MAX_OPERANDS + 1];
+ FT_Fixed* top;
+
+ CFF_Decoder_Zone zones[CFF_MAX_SUBRS_CALLS + 1];
+ CFF_Decoder_Zone* zone;
+
+ FT_Int flex_state;
+ FT_Int num_flex_vectors;
+ FT_Vector flex_vectors[7];
+
+ FT_Pos glyph_width;
+ FT_Pos nominal_width;
+
+ FT_Bool read_width;
+ FT_Int num_hints;
+ FT_Fixed* buildchar;
+ FT_Int len_buildchar;
+
+ FT_UInt num_locals;
+ FT_UInt num_globals;
+
+ FT_Int locals_bias;
+ FT_Int globals_bias;
+
+ FT_Byte** locals;
+ FT_Byte** globals;
+
+ FT_Byte** glyph_names; /* for pure CFF fonts only */
+ FT_UInt num_glyphs; /* number of glyphs in font */
+
+ FT_Render_Mode hint_mode;
+
+ } CFF_Decoder;
+
+
+ FT_LOCAL( void )
+ cff_decoder_init( CFF_Decoder* decoder,
+ TT_Face face,
+ CFF_Size size,
+ CFF_GlyphSlot slot,
+ FT_Bool hinting,
+ FT_Render_Mode hint_mode );
+
+ FT_LOCAL( void )
+ cff_decoder_prepare( CFF_Decoder* decoder,
+ FT_UInt glyph_index );
+
+#if 0 /* unused until we support pure CFF fonts */
+
+ /* Compute the maximum advance width of a font through quick parsing */
+ FT_LOCAL( FT_Error )
+ cff_compute_max_advance( TT_Face face,
+ FT_Int* max_advance );
+
+#endif /* 0 */
+
+ FT_LOCAL( FT_Error )
+ cff_decoder_parse_charstrings( CFF_Decoder* decoder,
+ FT_Byte* charstring_base,
+ FT_ULong charstring_len );
+
+ FT_LOCAL( FT_Error )
+ cff_slot_load( CFF_GlyphSlot glyph,
+ CFF_Size size,
+ FT_Int glyph_index,
+ FT_Int32 load_flags );
+
+
+FT_END_HEADER
+
+#endif /* __CFFGLOAD_H__ */
+
+
+/* END */
--- /dev/null
+++ b/libfreetype/cffload.c
@@ -1,0 +1,2247 @@
+/***************************************************************************/
+/* */
+/* cffload.c */
+/* */
+/* OpenType and CFF data/program tables loader (body). */
+/* */
+/* Copyright 1996-2001, 2002 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+
+#include <ft2build.h>
+#include FT_INTERNAL_DEBUG_H
+#include FT_INTERNAL_OBJECTS_H
+#include FT_INTERNAL_STREAM_H
+#include FT_INTERNAL_POSTSCRIPT_NAMES_H
+#include FT_TRUETYPE_TAGS_H
+
+#include "cffload.h"
+#include "cffparse.h"
+
+#include "cfferrs.h"
+
+
+#if 1
+ static const FT_UShort cff_isoadobe_charset[229] =
+ {
+ 0,
+ 1,
+ 2,
+ 3,
+ 4,
+ 5,
+ 6,
+ 7,
+ 8,
+ 9,
+ 10,
+ 11,
+ 12,
+ 13,
+ 14,
+ 15,
+ 16,
+ 17,
+ 18,
+ 19,
+ 20,
+ 21,
+ 22,
+ 23,
+ 24,
+ 25,
+ 26,
+ 27,
+ 28,
+ 29,
+ 30,
+ 31,
+ 32,
+ 33,
+ 34,
+ 35,
+ 36,
+ 37,
+ 38,
+ 39,
+ 40,
+ 41,
+ 42,
+ 43,
+ 44,
+ 45,
+ 46,
+ 47,
+ 48,
+ 49,
+ 50,
+ 51,
+ 52,
+ 53,
+ 54,
+ 55,
+ 56,
+ 57,
+ 58,
+ 59,
+ 60,
+ 61,
+ 62,
+ 63,
+ 64,
+ 65,
+ 66,
+ 67,
+ 68,
+ 69,
+ 70,
+ 71,
+ 72,
+ 73,
+ 74,
+ 75,
+ 76,
+ 77,
+ 78,
+ 79,
+ 80,
+ 81,
+ 82,
+ 83,
+ 84,
+ 85,
+ 86,
+ 87,
+ 88,
+ 89,
+ 90,
+ 91,
+ 92,
+ 93,
+ 94,
+ 95,
+ 96,
+ 97,
+ 98,
+ 99,
+ 100,
+ 101,
+ 102,
+ 103,
+ 104,
+ 105,
+ 106,
+ 107,
+ 108,
+ 109,
+ 110,
+ 111,
+ 112,
+ 113,
+ 114,
+ 115,
+ 116,
+ 117,
+ 118,
+ 119,
+ 120,
+ 121,
+ 122,
+ 123,
+ 124,
+ 125,
+ 126,
+ 127,
+ 128,
+ 129,
+ 130,
+ 131,
+ 132,
+ 133,
+ 134,
+ 135,
+ 136,
+ 137,
+ 138,
+ 139,
+ 140,
+ 141,
+ 142,
+ 143,
+ 144,
+ 145,
+ 146,
+ 147,
+ 148,
+ 149,
+ 150,
+ 151,
+ 152,
+ 153,
+ 154,
+ 155,
+ 156,
+ 157,
+ 158,
+ 159,
+ 160,
+ 161,
+ 162,
+ 163,
+ 164,
+ 165,
+ 166,
+ 167,
+ 168,
+ 169,
+ 170,
+ 171,
+ 172,
+ 173,
+ 174,
+ 175,
+ 176,
+ 177,
+ 178,
+ 179,
+ 180,
+ 181,
+ 182,
+ 183,
+ 184,
+ 185,
+ 186,
+ 187,
+ 188,
+ 189,
+ 190,
+ 191,
+ 192,
+ 193,
+ 194,
+ 195,
+ 196,
+ 197,
+ 198,
+ 199,
+ 200,
+ 201,
+ 202,
+ 203,
+ 204,
+ 205,
+ 206,
+ 207,
+ 208,
+ 209,
+ 210,
+ 211,
+ 212,
+ 213,
+ 214,
+ 215,
+ 216,
+ 217,
+ 218,
+ 219,
+ 220,
+ 221,
+ 222,
+ 223,
+ 224,
+ 225,
+ 226,
+ 227,
+ 228
+ };
+
+ static const FT_UShort cff_expert_charset[166] =
+ {
+ 0,
+ 1,
+ 229,
+ 230,
+ 231,
+ 232,
+ 233,
+ 234,
+ 235,
+ 236,
+ 237,
+ 238,
+ 13,
+ 14,
+ 15,
+ 99,
+ 239,
+ 240,
+ 241,
+ 242,
+ 243,
+ 244,
+ 245,
+ 246,
+ 247,
+ 248,
+ 27,
+ 28,
+ 249,
+ 250,
+ 251,
+ 252,
+ 253,
+ 254,
+ 255,
+ 256,
+ 257,
+ 258,
+ 259,
+ 260,
+ 261,
+ 262,
+ 263,
+ 264,
+ 265,
+ 266,
+ 109,
+ 110,
+ 267,
+ 268,
+ 269,
+ 270,
+ 271,
+ 272,
+ 273,
+ 274,
+ 275,
+ 276,
+ 277,
+ 278,
+ 279,
+ 280,
+ 281,
+ 282,
+ 283,
+ 284,
+ 285,
+ 286,
+ 287,
+ 288,
+ 289,
+ 290,
+ 291,
+ 292,
+ 293,
+ 294,
+ 295,
+ 296,
+ 297,
+ 298,
+ 299,
+ 300,
+ 301,
+ 302,
+ 303,
+ 304,
+ 305,
+ 306,
+ 307,
+ 308,
+ 309,
+ 310,
+ 311,
+ 312,
+ 313,
+ 314,
+ 315,
+ 316,
+ 317,
+ 318,
+ 158,
+ 155,
+ 163,
+ 319,
+ 320,
+ 321,
+ 322,
+ 323,
+ 324,
+ 325,
+ 326,
+ 150,
+ 164,
+ 169,
+ 327,
+ 328,
+ 329,
+ 330,
+ 331,
+ 332,
+ 333,
+ 334,
+ 335,
+ 336,
+ 337,
+ 338,
+ 339,
+ 340,
+ 341,
+ 342,
+ 343,
+ 344,
+ 345,
+ 346,
+ 347,
+ 348,
+ 349,
+ 350,
+ 351,
+ 352,
+ 353,
+ 354,
+ 355,
+ 356,
+ 357,
+ 358,
+ 359,
+ 360,
+ 361,
+ 362,
+ 363,
+ 364,
+ 365,
+ 366,
+ 367,
+ 368,
+ 369,
+ 370,
+ 371,
+ 372,
+ 373,
+ 374,
+ 375,
+ 376,
+ 377,
+ 378
+ };
+
+ static const FT_UShort cff_expertsubset_charset[87] =
+ {
+ 0,
+ 1,
+ 231,
+ 232,
+ 235,
+ 236,
+ 237,
+ 238,
+ 13,
+ 14,
+ 15,
+ 99,
+ 239,
+ 240,
+ 241,
+ 242,
+ 243,
+ 244,
+ 245,
+ 246,
+ 247,
+ 248,
+ 27,
+ 28,
+ 249,
+ 250,
+ 251,
+ 253,
+ 254,
+ 255,
+ 256,
+ 257,
+ 258,
+ 259,
+ 260,
+ 261,
+ 262,
+ 263,
+ 264,
+ 265,
+ 266,
+ 109,
+ 110,
+ 267,
+ 268,
+ 269,
+ 270,
+ 272,
+ 300,
+ 301,
+ 302,
+ 305,
+ 314,
+ 315,
+ 158,
+ 155,
+ 163,
+ 320,
+ 321,
+ 322,
+ 323,
+ 324,
+ 325,
+ 326,
+ 150,
+ 164,
+ 169,
+ 327,
+ 328,
+ 329,
+ 330,
+ 331,
+ 332,
+ 333,
+ 334,
+ 335,
+ 336,
+ 337,
+ 338,
+ 339,
+ 340,
+ 341,
+ 342,
+ 343,
+ 344,
+ 345,
+ 346
+ };
+
+ static const FT_UShort cff_standard_encoding[256] =
+ {
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 1,
+ 2,
+ 3,
+ 4,
+ 5,
+ 6,
+ 7,
+ 8,
+ 9,
+ 10,
+ 11,
+ 12,
+ 13,
+ 14,
+ 15,
+ 16,
+ 17,
+ 18,
+ 19,
+ 20,
+ 21,
+ 22,
+ 23,
+ 24,
+ 25,
+ 26,
+ 27,
+ 28,
+ 29,
+ 30,
+ 31,
+ 32,
+ 33,
+ 34,
+ 35,
+ 36,
+ 37,
+ 38,
+ 39,
+ 40,
+ 41,
+ 42,
+ 43,
+ 44,
+ 45,
+ 46,
+ 47,
+ 48,
+ 49,
+ 50,
+ 51,
+ 52,
+ 53,
+ 54,
+ 55,
+ 56,
+ 57,
+ 58,
+ 59,
+ 60,
+ 61,
+ 62,
+ 63,
+ 64,
+ 65,
+ 66,
+ 67,
+ 68,
+ 69,
+ 70,
+ 71,
+ 72,
+ 73,
+ 74,
+ 75,
+ 76,
+ 77,
+ 78,
+ 79,
+ 80,
+ 81,
+ 82,
+ 83,
+ 84,
+ 85,
+ 86,
+ 87,
+ 88,
+ 89,
+ 90,
+ 91,
+ 92,
+ 93,
+ 94,
+ 95,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 96,
+ 97,
+ 98,
+ 99,
+ 100,
+ 101,
+ 102,
+ 103,
+ 104,
+ 105,
+ 106,
+ 107,
+ 108,
+ 109,
+ 110,
+ 0,
+ 111,
+ 112,
+ 113,
+ 114,
+ 0,
+ 115,
+ 116,
+ 117,
+ 118,
+ 119,
+ 120,
+ 121,
+ 122,
+ 0,
+ 123,
+ 0,
+ 124,
+ 125,
+ 126,
+ 127,
+ 128,
+ 129,
+ 130,
+ 131,
+ 0,
+ 132,
+ 133,
+ 0,
+ 134,
+ 135,
+ 136,
+ 137,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 138,
+ 0,
+ 139,
+ 0,
+ 0,
+ 0,
+ 0,
+ 140,
+ 141,
+ 142,
+ 143,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 144,
+ 0,
+ 0,
+ 0,
+ 145,
+ 0,
+ 0,
+ 146,
+ 147,
+ 148,
+ 149,
+ 0,
+ 0,
+ 0,
+ 0
+ };
+
+ static const FT_UShort cff_expert_encoding[256] =
+ {
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 1,
+ 229,
+ 230,
+ 0,
+ 231,
+ 232,
+ 233,
+ 234,
+ 235,
+ 236,
+ 237,
+ 238,
+ 13,
+ 14,
+ 15,
+ 99,
+ 239,
+ 240,
+ 241,
+ 242,
+ 243,
+ 244,
+ 245,
+ 246,
+ 247,
+ 248,
+ 27,
+ 28,
+ 249,
+ 250,
+ 251,
+ 252,
+ 0,
+ 253,
+ 254,
+ 255,
+ 256,
+ 257,
+ 0,
+ 0,
+ 0,
+ 258,
+ 0,
+ 0,
+ 259,
+ 260,
+ 261,
+ 262,
+ 0,
+ 0,
+ 263,
+ 264,
+ 265,
+ 0,
+ 266,
+ 109,
+ 110,
+ 267,
+ 268,
+ 269,
+ 0,
+ 270,
+ 271,
+ 272,
+ 273,
+ 274,
+ 275,
+ 276,
+ 277,
+ 278,
+ 279,
+ 280,
+ 281,
+ 282,
+ 283,
+ 284,
+ 285,
+ 286,
+ 287,
+ 288,
+ 289,
+ 290,
+ 291,
+ 292,
+ 293,
+ 294,
+ 295,
+ 296,
+ 297,
+ 298,
+ 299,
+ 300,
+ 301,
+ 302,
+ 303,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 304,
+ 305,
+ 306,
+ 0,
+ 0,
+ 307,
+ 308,
+ 309,
+ 310,
+ 311,
+ 0,
+ 312,
+ 0,
+ 0,
+ 312,
+ 0,
+ 0,
+ 314,
+ 315,
+ 0,
+ 0,
+ 316,
+ 317,
+ 318,
+ 0,
+ 0,
+ 0,
+ 158,
+ 155,
+ 163,
+ 319,
+ 320,
+ 321,
+ 322,
+ 323,
+ 324,
+ 325,
+ 0,
+ 0,
+ 326,
+ 150,
+ 164,
+ 169,
+ 327,
+ 328,
+ 329,
+ 330,
+ 331,
+ 332,
+ 333,
+ 334,
+ 335,
+ 336,
+ 337,
+ 338,
+ 339,
+ 340,
+ 341,
+ 342,
+ 343,
+ 344,
+ 345,
+ 346,
+ 347,
+ 348,
+ 349,
+ 350,
+ 351,
+ 352,
+ 353,
+ 354,
+ 355,
+ 356,
+ 357,
+ 358,
+ 359,
+ 360,
+ 361,
+ 362,
+ 363,
+ 364,
+ 365,
+ 366,
+ 367,
+ 368,
+ 369,
+ 370,
+ 371,
+ 372,
+ 373,
+ 374,
+ 375,
+ 376,
+ 377,
+ 378
+ };
+#endif
+
+
+ FT_LOCAL_DEF( FT_UShort )
+ cff_get_standard_encoding( FT_UInt charcode )
+ {
+ return (FT_UShort)(charcode < 256 ? cff_standard_encoding[charcode] : 0);
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* The macro FT_COMPONENT is used in trace mode. It is an implicit */
+ /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log */
+ /* messages during execution. */
+ /* */
+#undef FT_COMPONENT
+#define FT_COMPONENT trace_cffload
+
+
+ /* read a CFF offset from memory */
+ static FT_ULong
+ cff_get_offset( FT_Byte* p,
+ FT_Byte off_size )
+ {
+ FT_ULong result;
+
+
+ for ( result = 0; off_size > 0; off_size-- )
+ {
+ result <<= 8;
+ result |= *p++;
+ }
+
+ return result;
+ }
+
+
+ static FT_Error
+ cff_new_index( CFF_Index idx,
+ FT_Stream stream,
+ FT_Bool load )
+ {
+ FT_Error error;
+ FT_Memory memory = stream->memory;
+ FT_UShort count;
+
+
+ FT_MEM_ZERO( idx, sizeof ( *idx ) );
+
+ idx->stream = stream;
+ if ( !FT_READ_USHORT( count ) &&
+ count > 0 )
+ {
+ FT_Byte* p;
+ FT_Byte offsize;
+ FT_ULong data_size;
+ FT_ULong* poff;
+
+
+ /* there is at least one element; read the offset size, */
+ /* then access the offset table to compute the index's total size */
+ if ( FT_READ_BYTE( offsize ) )
+ goto Exit;
+
+ idx->stream = stream;
+ idx->count = count;
+ idx->off_size = offsize;
+ data_size = (FT_ULong)( count + 1 ) * offsize;
+
+ if ( FT_NEW_ARRAY( idx->offsets, count + 1 ) ||
+ FT_FRAME_ENTER( data_size ) )
+ goto Exit;
+
+ poff = idx->offsets;
+ p = (FT_Byte*)stream->cursor;
+
+ for ( ; (FT_Short)count >= 0; count-- )
+ {
+ poff[0] = cff_get_offset( p, offsize );
+ poff++;
+ p += offsize;
+ }
+
+ FT_FRAME_EXIT();
+
+ idx->data_offset = FT_STREAM_POS();
+ data_size = poff[-1] - 1;
+
+ if ( load )
+ {
+ /* load the data */
+ if ( FT_FRAME_EXTRACT( data_size, idx->bytes ) )
+ goto Exit;
+ }
+ else
+ {
+ /* skip the data */
+ if ( FT_STREAM_SKIP( data_size ) )
+ goto Exit;
+ }
+ }
+
+ Exit:
+ if ( error )
+ FT_FREE( idx->offsets );
+
+ return error;
+ }
+
+
+ static void
+ cff_done_index( CFF_Index idx )
+ {
+ if ( idx->stream )
+ {
+ FT_Stream stream = idx->stream;
+ FT_Memory memory = stream->memory;
+
+
+ if ( idx->bytes )
+ FT_FRAME_RELEASE( idx->bytes );
+
+ FT_FREE( idx->offsets );
+ FT_MEM_ZERO( idx, sizeof ( *idx ) );
+ }
+ }
+
+
+ /* allocate a table containing pointers to an index's elements */
+ static FT_Error
+ cff_index_get_pointers( CFF_Index idx,
+ FT_Byte*** table )
+ {
+ FT_Error error = 0;
+ FT_Memory memory = idx->stream->memory;
+ FT_ULong n, offset, old_offset;
+ FT_Byte** t;
+
+
+ *table = 0;
+
+ if ( idx->count > 0 && !FT_NEW_ARRAY( t, idx->count + 1 ) )
+ {
+ old_offset = 1;
+ for ( n = 0; n <= idx->count; n++ )
+ {
+ offset = idx->offsets[n];
+ if ( !offset )
+ offset = old_offset;
+
+ t[n] = idx->bytes + offset - 1;
+
+ old_offset = offset;
+ }
+ *table = t;
+ }
+
+ return error;
+ }
+
+
+ FT_LOCAL_DEF( FT_Error )
+ cff_index_access_element( CFF_Index idx,
+ FT_UInt element,
+ FT_Byte** pbytes,
+ FT_ULong* pbyte_len )
+ {
+ FT_Error error = 0;
+
+
+ if ( idx && idx->count > element )
+ {
+ /* compute start and end offsets */
+ FT_ULong off1, off2 = 0;
+
+
+ off1 = idx->offsets[element];
+ if ( off1 )
+ {
+ do
+ {
+ element++;
+ off2 = idx->offsets[element];
+
+ } while ( off2 == 0 && element < idx->count );
+
+ if ( !off2 )
+ off1 = 0;
+ }
+
+ /* access element */
+ if ( off1 )
+ {
+ *pbyte_len = off2 - off1;
+
+ if ( idx->bytes )
+ {
+ /* this index was completely loaded in memory, that's easy */
+ *pbytes = idx->bytes + off1 - 1;
+ }
+ else
+ {
+ /* this index is still on disk/file, access it through a frame */
+ FT_Stream stream = idx->stream;
+
+
+ if ( FT_STREAM_SEEK( idx->data_offset + off1 - 1 ) ||
+ FT_FRAME_EXTRACT( off2 - off1, *pbytes ) )
+ goto Exit;
+ }
+ }
+ else
+ {
+ /* empty index element */
+ *pbytes = 0;
+ *pbyte_len = 0;
+ }
+ }
+ else
+ error = CFF_Err_Invalid_Argument;
+
+ Exit:
+ return error;
+ }
+
+
+ FT_LOCAL_DEF( void )
+ cff_index_forget_element( CFF_Index idx,
+ FT_Byte** pbytes )
+ {
+ if ( idx->bytes == 0 )
+ {
+ FT_Stream stream = idx->stream;
+
+
+ FT_FRAME_RELEASE( *pbytes );
+ }
+ }
+
+
+ FT_LOCAL_DEF( FT_String* )
+ cff_index_get_name( CFF_Index idx,
+ FT_UInt element )
+ {
+ FT_Memory memory = idx->stream->memory;
+ FT_Byte* bytes;
+ FT_ULong byte_len;
+ FT_Error error;
+ FT_String* name = 0;
+
+
+ error = cff_index_access_element( idx, element, &bytes, &byte_len );
+ if ( error )
+ goto Exit;
+
+ if ( !FT_ALLOC( name, byte_len + 1 ) )
+ {
+ FT_MEM_COPY( name, bytes, byte_len );
+ name[byte_len] = 0;
+ }
+ cff_index_forget_element( idx, &bytes );
+
+ Exit:
+ return name;
+ }
+
+
+ FT_LOCAL_DEF( FT_String* )
+ cff_index_get_sid_string( CFF_Index idx,
+ FT_UInt sid,
+ PSNames_Service psnames_service )
+ {
+ /* if it is not a standard string, return it */
+ if ( sid > 390 )
+ return cff_index_get_name( idx, sid - 391 );
+
+ /* that's a standard string, fetch a copy from the PSName module */
+ {
+ FT_String* name = 0;
+ const char* adobe_name = psnames_service->adobe_std_strings( sid );
+ FT_UInt len;
+
+
+ if ( adobe_name )
+ {
+ FT_Memory memory = idx->stream->memory;
+ FT_Error error;
+
+
+ len = (FT_UInt)ft_strlen( adobe_name );
+ if ( !FT_ALLOC( name, len + 1 ) )
+ {
+ FT_MEM_COPY( name, adobe_name, len );
+ name[len] = 0;
+ }
+
+ FT_UNUSED( error );
+ }
+
+ return name;
+ }
+ }
+
+
+ /*************************************************************************/
+ /*************************************************************************/
+ /*** ***/
+ /*** FD Select table support ***/
+ /*** ***/
+ /*************************************************************************/
+ /*************************************************************************/
+
+
+ static void
+ CFF_Done_FD_Select( CFF_FDSelect fdselect,
+ FT_Stream stream )
+ {
+ if ( fdselect->data )
+ FT_FRAME_RELEASE( fdselect->data );
+
+ fdselect->data_size = 0;
+ fdselect->format = 0;
+ fdselect->range_count = 0;
+ }
+
+
+ static FT_Error
+ CFF_Load_FD_Select( CFF_FDSelect fdselect,
+ FT_UInt num_glyphs,
+ FT_Stream stream,
+ FT_ULong offset )
+ {
+ FT_Error error;
+ FT_Byte format;
+ FT_UInt num_ranges;
+
+
+ /* read format */
+ if ( FT_STREAM_SEEK( offset ) || FT_READ_BYTE( format ) )
+ goto Exit;
+
+ fdselect->format = format;
+ fdselect->cache_count = 0; /* clear cache */
+
+ switch ( format )
+ {
+ case 0: /* format 0, that's simple */
+ fdselect->data_size = num_glyphs;
+ goto Load_Data;
+
+ case 3: /* format 3, a tad more complex */
+ if ( FT_READ_USHORT( num_ranges ) )
+ goto Exit;
+
+ fdselect->data_size = num_ranges * 3 + 2;
+
+ Load_Data:
+ if ( FT_FRAME_EXTRACT( fdselect->data_size, fdselect->data ) )
+ goto Exit;
+ break;
+
+ default: /* hmm... that's wrong */
+ error = CFF_Err_Invalid_File_Format;
+ }
+
+ Exit:
+ return error;
+ }
+
+
+ FT_LOCAL_DEF( FT_Byte )
+ cff_fd_select_get( CFF_FDSelect fdselect,
+ FT_UInt glyph_index )
+ {
+ FT_Byte fd = 0;
+
+
+ switch ( fdselect->format )
+ {
+ case 0:
+ fd = fdselect->data[glyph_index];
+ break;
+
+ case 3:
+ /* first, compare to cache */
+ if ( (FT_UInt)( glyph_index - fdselect->cache_first ) <
+ fdselect->cache_count )
+ {
+ fd = fdselect->cache_fd;
+ break;
+ }
+
+ /* then, lookup the ranges array */
+ {
+ FT_Byte* p = fdselect->data;
+ FT_Byte* p_limit = p + fdselect->data_size;
+ FT_Byte fd2;
+ FT_UInt first, limit;
+
+
+ first = FT_NEXT_USHORT( p );
+ do
+ {
+ if ( glyph_index < first )
+ break;
+
+ fd2 = *p++;
+ limit = FT_NEXT_USHORT( p );
+
+ if ( glyph_index < limit )
+ {
+ fd = fd2;
+
+ /* update cache */
+ fdselect->cache_first = first;
+ fdselect->cache_count = limit-first;
+ fdselect->cache_fd = fd2;
+ break;
+ }
+ first = limit;
+
+ } while ( p < p_limit );
+ }
+ break;
+
+ default:
+ ;
+ }
+
+ return fd;
+ }
+
+
+ /*************************************************************************/
+ /*************************************************************************/
+ /*** ***/
+ /*** CFF font support ***/
+ /*** ***/
+ /*************************************************************************/
+ /*************************************************************************/
+
+ static void
+ cff_charset_done( CFF_Charset charset,
+ FT_Stream stream )
+ {
+ FT_Memory memory = stream->memory;
+
+
+ FT_FREE( charset->sids );
+ charset->format = 0;
+ charset->offset = 0;
+ }
+
+
+ static FT_Error
+ cff_charset_load( CFF_Charset charset,
+ FT_UInt num_glyphs,
+ FT_Stream stream,
+ FT_ULong base_offset,
+ FT_ULong offset )
+ {
+ FT_Memory memory = stream->memory;
+ FT_Error error = 0;
+ FT_UShort glyph_sid;
+
+
+ /* If the the offset is greater than 2, we have to parse the */
+ /* charset table. */
+ if ( offset > 2 )
+ {
+ FT_UInt j;
+
+
+ charset->offset = base_offset + offset;
+
+ /* Get the format of the table. */
+ if ( FT_STREAM_SEEK( charset->offset ) ||
+ FT_READ_BYTE( charset->format ) )
+ goto Exit;
+
+ /* Allocate memory for sids. */
+ if ( FT_NEW_ARRAY( charset->sids, num_glyphs ) )
+ goto Exit;
+
+ /* assign the .notdef glyph */
+ charset->sids[0] = 0;
+
+ switch ( charset->format )
+ {
+ case 0:
+ if ( num_glyphs > 0 )
+ {
+ if ( FT_FRAME_ENTER( ( num_glyphs - 1 ) * 2 ) )
+ goto Exit;
+
+ for ( j = 1; j < num_glyphs; j++ )
+ charset->sids[j] = FT_GET_USHORT();
+
+ FT_FRAME_EXIT();
+ }
+ break;
+
+ case 1:
+ case 2:
+ {
+ FT_UInt nleft;
+ FT_UInt i;
+
+
+ j = 1;
+
+ while ( j < num_glyphs )
+ {
+
+ /* Read the first glyph sid of the range. */
+ if ( FT_READ_USHORT( glyph_sid ) )
+ goto Exit;
+
+ /* Read the number of glyphs in the range. */
+ if ( charset->format == 2 )
+ {
+ if ( FT_READ_USHORT( nleft ) )
+ goto Exit;
+ }
+ else
+ {
+ if ( FT_READ_BYTE( nleft ) )
+ goto Exit;
+ }
+
+ /* Fill in the range of sids -- `nleft + 1' glyphs. */
+ for ( i = 0; j < num_glyphs && i <= nleft; i++, j++, glyph_sid++ )
+ charset->sids[j] = glyph_sid;
+ }
+ }
+ break;
+
+ default:
+ FT_ERROR(( "cff_charset_load: invalid table format!\n" ));
+ error = CFF_Err_Invalid_File_Format;
+ goto Exit;
+ }
+ }
+ else
+ {
+ /* Parse default tables corresponding to offset == 0, 1, or 2. */
+ /* CFF specification intimates the following: */
+ /* */
+ /* In order to use a predefined charset, the following must be */
+ /* true: The charset constructed for the glyphs in the font's */
+ /* charstrings dictionary must match the predefined charset in */
+ /* the first num_glyphs, and hence must match the predefined */
+ /* charset *exactly*. */
+
+ charset->offset = offset; /* record charset type */
+
+ switch ( (FT_UInt)offset )
+ {
+ case 0:
+ if ( num_glyphs != 229 )
+ {
+ FT_ERROR(("cff_charset_load: implicit charset not equal to\n"
+ "predefined charset (Adobe ISO-Latin)!\n" ));
+ error = CFF_Err_Invalid_File_Format;
+ goto Exit;
+ }
+
+ /* Allocate memory for sids. */
+ if ( FT_NEW_ARRAY( charset->sids, num_glyphs ) )
+ goto Exit;
+
+ /* Copy the predefined charset into the allocated memory. */
+ FT_MEM_COPY( charset->sids, cff_isoadobe_charset,
+ num_glyphs * sizeof ( FT_UShort ) );
+
+ break;
+
+ case 1:
+ if ( num_glyphs != 166 )
+ {
+ FT_ERROR(( "cff_charset_load: implicit charset not equal to\n"
+ "predefined charset (Adobe Expert)!\n" ));
+ error = CFF_Err_Invalid_File_Format;
+ goto Exit;
+ }
+
+ /* Allocate memory for sids. */
+ if ( FT_NEW_ARRAY( charset->sids, num_glyphs ) )
+ goto Exit;
+
+ /* Copy the predefined charset into the allocated memory. */
+ FT_MEM_COPY( charset->sids, cff_expert_charset,
+ num_glyphs * sizeof ( FT_UShort ) );
+
+ break;
+
+ case 2:
+ if ( num_glyphs != 87 )
+ {
+ FT_ERROR(( "cff_charset_load: implicit charset not equal to\n"
+ "predefined charset (Adobe Expert Subset)!\n" ));
+ error = CFF_Err_Invalid_File_Format;
+ goto Exit;
+ }
+
+ /* Allocate memory for sids. */
+ if ( FT_NEW_ARRAY( charset->sids, num_glyphs ) )
+ goto Exit;
+
+ /* Copy the predefined charset into the allocated memory. */
+ FT_MEM_COPY( charset->sids, cff_expertsubset_charset,
+ num_glyphs * sizeof ( FT_UShort ) );
+
+ break;
+
+ default:
+ error = CFF_Err_Invalid_File_Format;
+ goto Exit;
+ }
+ }
+
+ Exit:
+
+ /* Clean up if there was an error. */
+ if ( error )
+ if ( charset->sids )
+ {
+ FT_FREE( charset->sids );
+ charset->format = 0;
+ charset->offset = 0;
+ charset->sids = 0;
+ }
+
+ return error;
+ }
+
+
+
+ static void
+ cff_encoding_done( CFF_Encoding encoding )
+ {
+ encoding->format = 0;
+ encoding->offset = 0;
+ encoding->count = 0;
+ }
+
+
+
+ static FT_Error
+ cff_encoding_load( CFF_Encoding encoding,
+ CFF_Charset charset,
+ FT_UInt num_glyphs,
+ FT_Stream stream,
+ FT_ULong base_offset,
+ FT_ULong offset )
+ {
+ FT_Error error = 0;
+ FT_UInt count;
+ FT_UInt j;
+ FT_UShort glyph_sid;
+ FT_UInt glyph_code;
+
+
+ /* Check for charset->sids. If we do not have this, we fail. */
+ if ( !charset->sids )
+ {
+ error = CFF_Err_Invalid_File_Format;
+ goto Exit;
+ }
+
+ /* Zero out the code to gid/sid mappings. */
+ for ( j = 0; j < 256; j++ )
+ {
+ encoding->sids [j] = 0;
+ encoding->codes[j] = 0;
+ }
+
+ /* Note: The encoding table in a CFF font is indexed by glyph index, */
+ /* where the first encoded glyph index is 1. Hence, we read the char */
+ /* code (`glyph_code') at index j and make the assignment: */
+ /* */
+ /* encoding->codes[glyph_code] = j + 1 */
+ /* */
+ /* We also make the assignment: */
+ /* */
+ /* encoding->sids[glyph_code] = charset->sids[j + 1] */
+ /* */
+ /* This gives us both a code to GID and a code to SID mapping. */
+
+ if ( offset > 1 )
+ {
+
+ encoding->offset = base_offset + offset;
+
+ /* we need to parse the table to determine its size */
+ if ( FT_STREAM_SEEK( encoding->offset ) ||
+ FT_READ_BYTE( encoding->format ) ||
+ FT_READ_BYTE( count ) )
+ goto Exit;
+
+ encoding->count = count + 1;
+
+ switch ( encoding->format & 0x7F )
+ {
+ case 0:
+ {
+ FT_Byte* p;
+
+
+ if ( FT_FRAME_ENTER( count ) )
+ goto Exit;
+
+ p = (FT_Byte*)stream->cursor;
+
+ for ( j = 1; j <= count; j++ )
+ {
+ glyph_code = *p++;
+
+ /* Make sure j is not too big. */
+ if ( (FT_UInt) glyph_code < num_glyphs )
+ {
+ /* Assign code to GID mapping. */
+ encoding->codes[glyph_code] = (FT_UShort)j;
+
+ /* Assign code to SID mapping. */
+ encoding->sids[glyph_code] = charset->sids[j];
+ }
+ }
+
+ FT_FRAME_EXIT();
+ }
+ break;
+
+ case 1:
+ {
+ FT_Byte nleft;
+ FT_UInt i = 1;
+ FT_UInt k;
+
+
+ /* Parse the Format1 ranges. */
+ for ( j = 0; j < count; j++, i += nleft )
+ {
+ /* Read the first glyph code of the range. */
+ if ( FT_READ_BYTE( glyph_code ) )
+ goto Exit;
+
+ /* Read the number of codes in the range. */
+ if ( FT_READ_BYTE( nleft ) )
+ goto Exit;
+
+ /* Increment nleft, so we read `nleft + 1' codes/sids. */
+ nleft++;
+
+ /* Fill in the range of codes/sids. */
+ for ( k = i; k < nleft + i; k++, glyph_code++ )
+ {
+ /* Make sure k is not too big. */
+ if ( k < num_glyphs && glyph_code < 256 )
+ {
+ /* Assign code to GID mapping. */
+ encoding->codes[glyph_code] = (FT_UShort)k;
+
+ /* Assign code to SID mapping. */
+ encoding->sids[glyph_code] = charset->sids[k];
+ }
+ }
+ }
+ }
+ break;
+
+ default:
+ FT_ERROR(( "cff_encoding_load: invalid table format!\n" ));
+ error = CFF_Err_Invalid_File_Format;
+ goto Exit;
+ }
+
+ /* Parse supplemental encodings, if any. */
+ if ( encoding->format & 0x80 )
+ {
+ FT_UInt gindex;
+
+
+ /* count supplements */
+ if ( FT_READ_BYTE( count ) )
+ goto Exit;
+
+ for ( j = 0; j < count; j++ )
+ {
+ /* Read supplemental glyph code. */
+ if ( FT_READ_BYTE( glyph_code ) )
+ goto Exit;
+
+ /* Read the SID associated with this glyph code. */
+ if ( FT_READ_USHORT( glyph_sid ) )
+ goto Exit;
+
+ /* Assign code to SID mapping. */
+ encoding->sids[glyph_code] = glyph_sid;
+
+ /* First, lookup GID which has been assigned to */
+ /* SID glyph_sid. */
+ for ( gindex = 0; gindex < num_glyphs; gindex++ )
+ {
+ if ( charset->sids[gindex] == glyph_sid )
+ {
+ encoding->codes[glyph_code] = (FT_UShort) gindex;
+ break;
+ }
+ }
+ }
+ }
+ }
+ else
+ {
+ FT_UInt i;
+
+
+ /* We take into account the fact a CFF font can use a predefined */
+ /* encoding without containing all of the glyphs encoded by this */
+ /* encoding (see the note at the end of section 12 in the CFF */
+ /* specification). */
+
+ encoding->count = 256;
+
+ switch ( (FT_UInt)offset )
+ {
+ case 0:
+ /* First, copy the code to SID mapping. */
+ FT_MEM_COPY( encoding->sids, cff_standard_encoding,
+ 256 * sizeof ( FT_UShort ) );
+
+ goto Populate;
+
+ case 1:
+ /* First, copy the code to SID mapping. */
+ FT_MEM_COPY( encoding->sids, cff_expert_encoding,
+ 256 * sizeof ( FT_UShort ) );
+
+ Populate:
+ /* Construct code to GID mapping from code to SID mapping */
+ /* and charset. */
+ for ( j = 0; j < 256; j++ )
+ {
+ /* If j is encoded, find the GID for it. */
+ if ( encoding->sids[j] )
+ {
+ for ( i = 1; i < num_glyphs; i++ )
+ /* We matched, so break. */
+ if ( charset->sids[i] == encoding->sids[j] )
+ break;
+
+ /* i will be equal to num_glyphs if we exited the above */
+ /* loop without a match. In this case, we also have to */
+ /* fix the code to SID mapping. */
+ if ( i == num_glyphs )
+ {
+ encoding->codes[j] = 0;
+ encoding->sids [j] = 0;
+ }
+ else
+ encoding->codes[j] = (FT_UShort)i;
+ }
+ }
+ break;
+
+ default:
+ FT_ERROR(( "cff_encoding_load: invalid table format!\n" ));
+ error = CFF_Err_Invalid_File_Format;
+ goto Exit;
+ }
+ }
+
+ Exit:
+
+ /* Clean up if there was an error. */
+ return error;
+ }
+
+
+ static FT_Error
+ cff_subfont_load( CFF_SubFont font,
+ CFF_Index idx,
+ FT_UInt font_index,
+ FT_Stream stream,
+ FT_ULong base_offset )
+ {
+ FT_Error error;
+ CFF_ParserRec parser;
+ FT_Byte* dict;
+ FT_ULong dict_len;
+ CFF_FontRecDict top = &font->font_dict;
+ CFF_Private priv = &font->private_dict;
+
+
+ cff_parser_init( &parser, CFF_CODE_TOPDICT, &font->font_dict );
+
+ /* set defaults */
+ FT_MEM_ZERO( top, sizeof ( *top ) );
+
+ top->underline_position = -100;
+ top->underline_thickness = 50;
+ top->charstring_type = 2;
+ top->font_matrix.xx = 0x10000L;
+ top->font_matrix.yy = 0x10000L;
+ top->cid_count = 8720;
+
+ error = cff_index_access_element( idx, font_index, &dict, &dict_len ) ||
+ cff_parser_run( &parser, dict, dict + dict_len );
+
+ cff_index_forget_element( idx, &dict );
+
+ if ( error )
+ goto Exit;
+
+ /* if it is a CID font, we stop there */
+ if ( top->cid_registry )
+ goto Exit;
+
+ /* parse the private dictionary, if any */
+ if ( top->private_offset && top->private_size )
+ {
+ /* set defaults */
+ FT_MEM_ZERO( priv, sizeof ( *priv ) );
+
+ priv->blue_shift = 7;
+ priv->blue_fuzz = 1;
+ priv->lenIV = -1;
+ priv->expansion_factor = (FT_Fixed)0.06 * 0x10000L;
+ priv->blue_scale = (FT_Fixed)0.039625 * 0x10000L;
+
+ cff_parser_init( &parser, CFF_CODE_PRIVATE, priv );
+
+ if ( FT_STREAM_SEEK( base_offset + font->font_dict.private_offset ) ||
+ FT_FRAME_ENTER( font->font_dict.private_size ) )
+ goto Exit;
+
+ error = cff_parser_run( &parser,
+ (FT_Byte*)stream->cursor,
+ (FT_Byte*)stream->limit );
+ FT_FRAME_EXIT();
+ if ( error )
+ goto Exit;
+ }
+
+ /* read the local subrs, if any */
+ if ( priv->local_subrs_offset )
+ {
+ if ( FT_STREAM_SEEK( base_offset + top->private_offset +
+ priv->local_subrs_offset ) )
+ goto Exit;
+
+ error = cff_new_index( &font->local_subrs_index, stream, 1 );
+ if ( error )
+ goto Exit;
+
+ font->num_local_subrs = font->local_subrs_index.count;
+ error = cff_index_get_pointers( &font->local_subrs_index,
+ &font->local_subrs );
+ if ( error )
+ goto Exit;
+ }
+
+ Exit:
+ return error;
+ }
+
+
+ static void
+ cff_subfont_done( FT_Memory memory,
+ CFF_SubFont subfont )
+ {
+ if ( subfont )
+ {
+ cff_done_index( &subfont->local_subrs_index );
+ FT_FREE( subfont->local_subrs );
+ }
+ }
+
+
+ FT_LOCAL_DEF( FT_Error )
+ cff_font_load( FT_Stream stream,
+ FT_Int face_index,
+ CFF_Font font )
+ {
+ static const FT_Frame_Field cff_header_fields[] =
+ {
+#undef FT_STRUCTURE
+#define FT_STRUCTURE CFF_FontRec
+
+ FT_FRAME_START( 4 ),
+ FT_FRAME_BYTE( version_major ),
+ FT_FRAME_BYTE( version_minor ),
+ FT_FRAME_BYTE( header_size ),
+ FT_FRAME_BYTE( absolute_offsize ),
+ FT_FRAME_END
+ };
+
+ FT_Error error;
+ FT_Memory memory = stream->memory;
+ FT_ULong base_offset;
+ CFF_FontRecDict dict;
+
+ FT_ZERO( font );
+
+ font->stream = stream;
+ font->memory = memory;
+ dict = &font->top_font.font_dict;
+ base_offset = FT_STREAM_POS();
+
+ /* read CFF font header */
+ if ( FT_STREAM_READ_FIELDS( cff_header_fields, font ) )
+ goto Exit;
+
+ /* check format */
+ if ( font->version_major != 1 ||
+ font->header_size < 4 ||
+ font->absolute_offsize > 4 )
+ {
+ FT_TRACE2(( "[not a CFF font header!]\n" ));
+ error = CFF_Err_Unknown_File_Format;
+ goto Exit;
+ }
+
+ /* skip the rest of the header */
+ if ( FT_STREAM_SKIP( font->header_size - 4 ) )
+ goto Exit;
+
+ /* read the name, top dict, string and global subrs index */
+ if ( FT_SET_ERROR( cff_new_index( &font->name_index, stream, 0 )) ||
+ FT_SET_ERROR( cff_new_index( &font->font_dict_index, stream, 0 )) ||
+ FT_SET_ERROR( cff_new_index( &font->string_index, stream, 0 )) ||
+ FT_SET_ERROR( cff_new_index( &font->global_subrs_index, stream, 1 )) )
+ goto Exit;
+
+ /* well, we don't really forget the `disabled' fonts... */
+ font->num_faces = font->name_index.count;
+ if ( face_index >= (FT_Int)font->num_faces )
+ {
+ FT_ERROR(( "cff_font_load: incorrect face index = %d\n",
+ face_index ));
+ error = CFF_Err_Invalid_Argument;
+ }
+
+ /* in case of a font format check, simply exit now */
+ if ( face_index < 0 )
+ goto Exit;
+
+ /* now, parse the top-level font dictionary */
+ error = cff_subfont_load( &font->top_font,
+ &font->font_dict_index,
+ face_index,
+ stream,
+ base_offset );
+ if ( error )
+ goto Exit;
+
+ /* now, check for a CID font */
+ if ( dict->cid_registry )
+ {
+ CFF_IndexRec fd_index;
+ CFF_SubFont sub;
+ FT_UInt idx;
+
+
+ /* this is a CID-keyed font, we must now allocate a table of */
+ /* sub-fonts, then load each of them separately */
+ if ( FT_STREAM_SEEK( base_offset + dict->cid_fd_array_offset ) )
+ goto Exit;
+
+ error = cff_new_index( &fd_index, stream, 0 );
+ if ( error )
+ goto Exit;
+
+ if ( fd_index.count > CFF_MAX_CID_FONTS )
+ {
+ FT_ERROR(( "cff_font_load: FD array too large in CID font\n" ));
+ goto Fail_CID;
+ }
+
+ /* allocate & read each font dict independently */
+ font->num_subfonts = fd_index.count;
+ if ( FT_NEW_ARRAY( sub, fd_index.count ) )
+ goto Fail_CID;
+
+ /* setup pointer table */
+ for ( idx = 0; idx < fd_index.count; idx++ )
+ font->subfonts[idx] = sub + idx;
+
+ /* now load each sub font independently */
+ for ( idx = 0; idx < fd_index.count; idx++ )
+ {
+ sub = font->subfonts[idx];
+ error = cff_subfont_load( sub, &fd_index, idx,
+ stream, base_offset );
+ if ( error )
+ goto Fail_CID;
+ }
+
+ /* now load the FD Select array */
+ error = CFF_Load_FD_Select( &font->fd_select,
+ (FT_UInt)dict->cid_count,
+ stream,
+ base_offset + dict->cid_fd_select_offset );
+
+ Fail_CID:
+ cff_done_index( &fd_index );
+
+ if ( error )
+ goto Exit;
+ }
+ else
+ font->num_subfonts = 0;
+
+ /* read the charstrings index now */
+ if ( dict->charstrings_offset == 0 )
+ {
+ FT_ERROR(( "cff_font_load: no charstrings offset!\n" ));
+ error = CFF_Err_Unknown_File_Format;
+ goto Exit;
+ }
+
+ if ( FT_STREAM_SEEK( base_offset + dict->charstrings_offset ) )
+ goto Exit;
+
+ error = cff_new_index( &font->charstrings_index, stream, 0 );
+ if ( error )
+ goto Exit;
+
+ /* explicit the global subrs */
+ font->num_global_subrs = font->global_subrs_index.count;
+ font->num_glyphs = font->charstrings_index.count;
+
+ error = cff_index_get_pointers( &font->global_subrs_index,
+ &font->global_subrs ) ;
+
+ if ( error )
+ goto Exit;
+
+ /* read the Charset and Encoding tables when available */
+ if ( font->num_glyphs > 0 )
+ {
+ error = cff_charset_load( &font->charset, font->num_glyphs, stream,
+ base_offset, dict->charset_offset );
+ if ( error )
+ goto Exit;
+
+ error = cff_encoding_load( &font->encoding,
+ &font->charset,
+ font->num_glyphs,
+ stream,
+ base_offset,
+ dict->encoding_offset );
+ if ( error )
+ goto Exit;
+ }
+
+ /* get the font name */
+ font->font_name = cff_index_get_name( &font->name_index, face_index );
+
+ Exit:
+ return error;
+ }
+
+
+ FT_LOCAL_DEF( void )
+ cff_font_done( CFF_Font font )
+ {
+ FT_Memory memory = font->memory;
+ FT_UInt idx;
+
+
+ cff_done_index( &font->global_subrs_index );
+ cff_done_index( &font->string_index );
+ cff_done_index( &font->font_dict_index );
+ cff_done_index( &font->name_index );
+ cff_done_index( &font->charstrings_index );
+
+ /* release font dictionaries, but only if working with */
+ /* a CID keyed CFF font */
+ if ( font->num_subfonts > 0 )
+ {
+ for ( idx = 0; idx < font->num_subfonts; idx++ )
+ cff_subfont_done( memory, font->subfonts[idx] );
+
+ FT_FREE( font->subfonts );
+ }
+
+ cff_encoding_done( &font->encoding );
+ cff_charset_done( &font->charset, font->stream );
+
+ cff_subfont_done( memory, &font->top_font );
+
+ CFF_Done_FD_Select( &font->fd_select, font->stream );
+
+ FT_FREE( font->global_subrs );
+ FT_FREE( font->font_name );
+ }
+
+
+/* END */
--- /dev/null
+++ b/libfreetype/cffload.h
@@ -1,0 +1,74 @@
+/***************************************************************************/
+/* */
+/* cffload.h */
+/* */
+/* OpenType & CFF data/program tables loader (specification). */
+/* */
+/* Copyright 1996-2001, 2002 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+
+#ifndef __CFFLOAD_H__
+#define __CFFLOAD_H__
+
+
+#include <ft2build.h>
+#include FT_INTERNAL_CFF_TYPES_H
+#include FT_INTERNAL_POSTSCRIPT_NAMES_H
+
+
+FT_BEGIN_HEADER
+
+ FT_LOCAL( FT_UShort )
+ cff_get_standard_encoding( FT_UInt charcode );
+
+
+ FT_LOCAL( FT_String* )
+ cff_index_get_name( CFF_Index idx,
+ FT_UInt element );
+
+ FT_LOCAL( FT_String* )
+ cff_index_get_sid_string( CFF_Index idx,
+ FT_UInt sid,
+ PSNames_Service psnames_interface );
+
+
+ FT_LOCAL( FT_Error )
+ cff_index_access_element( CFF_Index idx,
+ FT_UInt element,
+ FT_Byte** pbytes,
+ FT_ULong* pbyte_len );
+
+ FT_LOCAL( void )
+ cff_index_forget_element( CFF_Index idx,
+ FT_Byte** pbytes );
+
+
+ FT_LOCAL( FT_Error )
+ cff_font_load( FT_Stream stream,
+ FT_Int face_index,
+ CFF_Font font );
+
+ FT_LOCAL( void )
+ cff_font_done( CFF_Font font );
+
+
+ FT_LOCAL( FT_Byte )
+ cff_fd_select_get( CFF_FDSelect select,
+ FT_UInt glyph_index );
+
+
+FT_END_HEADER
+
+#endif /* __CFFLOAD_H__ */
+
+
+/* END */
--- /dev/null
+++ b/libfreetype/cffobjs.c
@@ -1,0 +1,575 @@
+/***************************************************************************/
+/* */
+/* cffobjs.c */
+/* */
+/* OpenType objects manager (body). */
+/* */
+/* Copyright 1996-2001, 2002 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+
+#include <ft2build.h>
+#include FT_INTERNAL_DEBUG_H
+#include FT_INTERNAL_CALC_H
+#include FT_INTERNAL_STREAM_H
+#include FT_ERRORS_H
+#include FT_TRUETYPE_IDS_H
+#include FT_TRUETYPE_TAGS_H
+#include FT_INTERNAL_SFNT_H
+#include FT_INTERNAL_POSTSCRIPT_NAMES_H
+#include FT_INTERNAL_POSTSCRIPT_HINTS_H
+#include "cffobjs.h"
+#include "cffload.h"
+#include "cffcmap.h"
+#include "cfferrs.h"
+
+
+ /*************************************************************************/
+ /* */
+ /* The macro FT_COMPONENT is used in trace mode. It is an implicit */
+ /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log */
+ /* messages during execution. */
+ /* */
+#undef FT_COMPONENT
+#define FT_COMPONENT trace_cffobjs
+
+
+ /*************************************************************************/
+ /* */
+ /* SIZE FUNCTIONS */
+ /* */
+ /* Note that we store the global hints in the size's "internal" root */
+ /* field. */
+ /* */
+ /*************************************************************************/
+
+
+ static PSH_Globals_Funcs
+ cff_size_get_globals_funcs( CFF_Size size )
+ {
+ CFF_Face face = (CFF_Face)size->face;
+ CFF_Font font = (CFF_FontRec *)face->extra.data;
+ PSHinter_Service pshinter = (PSHinter_Service)font->pshinter;
+ FT_Module module;
+
+
+ module = FT_Get_Module( size->face->driver->root.library,
+ "pshinter" );
+ return ( module && pshinter && pshinter->get_globals_funcs )
+ ? pshinter->get_globals_funcs( module )
+ : 0;
+ }
+
+
+ FT_LOCAL_DEF( void )
+ cff_size_done( CFF_Size size )
+ {
+ if ( size->internal )
+ {
+ PSH_Globals_Funcs funcs;
+
+
+ funcs = cff_size_get_globals_funcs( size );
+ if ( funcs )
+ funcs->destroy( (PSH_Globals)size->internal );
+
+ size->internal = 0;
+ }
+ }
+
+
+ FT_LOCAL_DEF( FT_Error )
+ cff_size_init( CFF_Size size )
+ {
+ FT_Error error = 0;
+ PSH_Globals_Funcs funcs = cff_size_get_globals_funcs( size );
+
+
+ if ( funcs )
+ {
+ PSH_Globals globals;
+ CFF_Face face = (CFF_Face)size->face;
+ CFF_Font font = (CFF_FontRec *)face->extra.data;
+ CFF_SubFont subfont = &font->top_font;
+
+ CFF_Private cpriv = &subfont->private_dict;
+ PS_PrivateRec priv;
+
+
+ /* IMPORTANT: The CFF and Type1 private dictionaries have */
+ /* slightly different structures; we need to */
+ /* synthetize a type1 dictionary on the fly here. */
+
+ {
+ FT_UInt n, count;
+
+
+ FT_MEM_ZERO( &priv, sizeof ( priv ) );
+
+ count = priv.num_blue_values = cpriv->num_blue_values;
+ for ( n = 0; n < count; n++ )
+ priv.blue_values[n] = (FT_Short)cpriv->blue_values[n];
+
+ count = priv.num_other_blues = cpriv->num_other_blues;
+ for ( n = 0; n < count; n++ )
+ priv.other_blues[n] = (FT_Short)cpriv->other_blues[n];
+
+ count = priv.num_family_blues = cpriv->num_family_blues;
+ for ( n = 0; n < count; n++ )
+ priv.family_blues[n] = (FT_Short)cpriv->family_blues[n];
+
+ count = priv.num_family_other_blues = cpriv->num_family_other_blues;
+ for ( n = 0; n < count; n++ )
+ priv.family_other_blues[n] = (FT_Short)cpriv->family_other_blues[n];
+
+ priv.blue_scale = cpriv->blue_scale;
+ priv.blue_shift = (FT_Int)cpriv->blue_shift;
+ priv.blue_fuzz = (FT_Int)cpriv->blue_fuzz;
+
+ priv.standard_width[0] = (FT_UShort)cpriv->standard_width;
+ priv.standard_height[0] = (FT_UShort)cpriv->standard_height;
+
+ count = priv.num_snap_widths = cpriv->num_snap_widths;
+ for ( n = 0; n < count; n++ )
+ priv.snap_widths[n] = (FT_Short)cpriv->snap_widths[n];
+
+ count = priv.num_snap_heights = cpriv->num_snap_heights;
+ for ( n = 0; n < count; n++ )
+ priv.snap_heights[n] = (FT_Short)cpriv->snap_heights[n];
+
+ priv.force_bold = cpriv->force_bold;
+ priv.language_group = cpriv->language_group;
+ priv.lenIV = cpriv->lenIV;
+ }
+
+ error = funcs->create( size->face->memory, &priv, &globals );
+ if ( !error )
+ size->internal = (FT_Size_Internal)(void*)globals;
+ }
+
+ return error;
+ }
+
+
+ FT_LOCAL_DEF( FT_Error )
+ cff_size_reset( CFF_Size size )
+ {
+ PSH_Globals_Funcs funcs = cff_size_get_globals_funcs( size );
+ FT_Error error = 0;
+
+
+ if ( funcs )
+ error = funcs->set_scale( (PSH_Globals)size->internal,
+ size->metrics.x_scale,
+ size->metrics.y_scale,
+ 0, 0 );
+ return error;
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* SLOT FUNCTIONS */
+ /* */
+ /*************************************************************************/
+
+ FT_LOCAL_DEF( void )
+ cff_slot_done( CFF_GlyphSlot slot )
+ {
+ slot->root.internal->glyph_hints = 0;
+ }
+
+
+ FT_LOCAL_DEF( FT_Error )
+ cff_slot_init( CFF_GlyphSlot slot )
+ {
+ CFF_Face face = (CFF_Face)slot->root.face;
+ CFF_Font font = (CFF_FontRec *)face->extra.data;
+ PSHinter_Service pshinter = (PSHinter_Service)font->pshinter;
+
+
+ if ( pshinter )
+ {
+ FT_Module module;
+
+
+ module = FT_Get_Module( slot->root.face->driver->root.library,
+ "pshinter" );
+ if ( module )
+ {
+ T2_Hints_Funcs funcs;
+
+
+ funcs = pshinter->get_t2_funcs( module );
+ slot->root.internal->glyph_hints = (void*)funcs;
+ }
+ }
+
+ return 0;
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* FACE FUNCTIONS */
+ /* */
+ /*************************************************************************/
+
+ static FT_String*
+ cff_strcpy( FT_Memory memory,
+ const FT_String* source )
+ {
+ FT_Error error;
+ FT_String* result = 0;
+ FT_Int len = (FT_Int)ft_strlen( source );
+
+
+ if ( !FT_ALLOC( result, len + 1 ) )
+ {
+ FT_MEM_COPY( result, source, len );
+ result[len] = 0;
+ }
+
+ FT_UNUSED( error );
+
+ return result;
+ }
+
+
+
+
+ FT_LOCAL_DEF( FT_Error )
+ cff_face_init( FT_Stream stream,
+ CFF_Face face,
+ FT_Int face_index,
+ FT_Int num_params,
+ FT_Parameter* params )
+ {
+ FT_Error error;
+ SFNT_Service sfnt;
+ PSNames_Service psnames;
+ PSHinter_Service pshinter;
+ FT_Bool pure_cff = 1;
+ FT_Bool sfnt_format = 0;
+
+
+ sfnt = (SFNT_Service)FT_Get_Module_Interface(
+ face->root.driver->root.library, "sfnt" );
+ if ( !sfnt )
+ goto Bad_Format;
+
+ psnames = (PSNames_Service)FT_Get_Module_Interface(
+ face->root.driver->root.library, "psnames" );
+
+ pshinter = (PSHinter_Service)FT_Get_Module_Interface(
+ face->root.driver->root.library, "pshinter" );
+
+ /* create input stream from resource */
+ if ( FT_STREAM_SEEK( 0 ) )
+ goto Exit;
+
+ /* check that we have a valid OpenType file */
+ error = sfnt->init_face( stream, face, face_index, num_params, params );
+ if ( !error )
+ {
+ if ( face->format_tag != 0x4F54544FL ) /* `OTTO'; OpenType/CFF font */
+ {
+ FT_TRACE2(( "[not a valid OpenType/CFF font]\n" ));
+ goto Bad_Format;
+ }
+
+ /* if we are performing a simple font format check, exit immediately */
+ if ( face_index < 0 )
+ return CFF_Err_Ok;
+
+ sfnt_format = 1;
+
+ /* now, the font can be either an OpenType/CFF font, or an SVG CEF */
+ /* font in the later case; it doesn't have a `head' table */
+ error = face->goto_table( face, TTAG_head, stream, 0 );
+ if ( !error )
+ {
+ pure_cff = 0;
+
+ /* load font directory */
+ error = sfnt->load_face( stream, face,
+ face_index, num_params, params );
+ if ( error )
+ goto Exit;
+ }
+ else
+ {
+ /* load the `cmap' table by hand */
+ error = sfnt->load_charmaps( face, stream );
+ if ( error )
+ goto Exit;
+
+ /* XXX: we don't load the GPOS table, as OpenType Layout */
+ /* support will be added later to a layout library on top of */
+ /* FreeType 2 */
+ }
+
+ /* now, load the CFF part of the file */
+ error = face->goto_table( face, TTAG_CFF, stream, 0 );
+ if ( error )
+ goto Exit;
+ }
+ else
+ {
+ /* rewind to start of file; we are going to load a pure-CFF font */
+ if ( FT_STREAM_SEEK( 0 ) )
+ goto Exit;
+ error = CFF_Err_Ok;
+ }
+
+ /* now load and parse the CFF table in the file */
+ {
+ CFF_Font cff;
+ FT_Memory memory = face->root.memory;
+ FT_Face root;
+ FT_Int32 flags;
+
+
+ if ( FT_NEW( cff ) )
+ goto Exit;
+
+ face->extra.data = cff;
+ error = cff_font_load( stream, face_index, cff );
+ if ( error )
+ goto Exit;
+
+ cff->pshinter = pshinter;
+ cff->psnames = psnames;
+
+ /* Complement the root flags with some interesting information. */
+ /* Note that this is only necessary for pure CFF and CEF fonts. */
+
+ root = &face->root;
+ root->num_glyphs = cff->num_glyphs;
+
+ if ( pure_cff )
+ {
+ CFF_FontRecDict dict = &cff->top_font.font_dict;
+
+
+ /* we need the `PSNames' module for pure-CFF and CEF formats */
+ if ( !psnames )
+ {
+ FT_ERROR(( "cff_face_init:" ));
+ FT_ERROR(( " cannot open CFF & CEF fonts\n" ));
+ FT_ERROR(( " " ));
+ FT_ERROR(( " without the `PSNames' module\n" ));
+ goto Bad_Format;
+ }
+
+ /* Set up num_faces. */
+ root->num_faces = cff->num_faces;
+
+ /* compute number of glyphs */
+ if ( dict->cid_registry )
+ root->num_glyphs = dict->cid_count;
+ else
+ root->num_glyphs = cff->charstrings_index.count;
+
+ /* set global bbox, as well as EM size */
+ root->bbox.xMin = dict->font_bbox.xMin >> 16;
+ root->bbox.yMin = dict->font_bbox.yMin >> 16;
+ root->bbox.xMax = ( dict->font_bbox.xMax + 0xFFFFU ) >> 16;
+ root->bbox.yMax = ( dict->font_bbox.yMax + 0xFFFFU ) >> 16;
+
+
+ root->ascender = (FT_Short)( root->bbox.yMax );
+ root->descender = (FT_Short)( root->bbox.yMin );
+ root->height = (FT_Short)(
+ ( ( root->ascender - root->descender ) * 12 ) / 10 );
+
+ if ( dict->units_per_em )
+ root->units_per_EM = dict->units_per_em;
+ else
+ root->units_per_EM = 1000;
+
+ /* retrieve font family & style name */
+ root->family_name = cff_index_get_name( &cff->name_index, face_index );
+ if ( dict->cid_registry )
+ root->style_name = cff_strcpy( memory, "Regular" ); /* XXXX */
+ else
+ root->style_name = cff_index_get_sid_string( &cff->string_index,
+ dict->weight,
+ psnames );
+
+ /*******************************************************************/
+ /* */
+ /* Compute face flags. */
+ /* */
+ flags = FT_FACE_FLAG_SCALABLE | /* scalable outlines */
+ FT_FACE_FLAG_HORIZONTAL; /* horizontal data */
+
+ if ( sfnt_format )
+ flags |= FT_FACE_FLAG_SFNT;
+
+ /* fixed width font? */
+ if ( dict->is_fixed_pitch )
+ flags |= FT_FACE_FLAG_FIXED_WIDTH;
+
+ /* XXX: WE DO NOT SUPPORT KERNING METRICS IN THE GPOS TABLE FOR NOW */
+#if 0
+ /* kerning available? */
+ if ( face->kern_pairs )
+ flags |= FT_FACE_FLAG_KERNING;
+#endif
+
+#ifndef FT_CONFIG_OPTION_NO_GLYPH_NAMES
+ flags |= FT_FACE_FLAG_GLYPH_NAMES;
+#endif
+
+ root->face_flags = flags;
+
+ /*******************************************************************/
+ /* */
+ /* Compute style flags. */
+ /* */
+ flags = 0;
+
+ if ( dict->italic_angle )
+ flags |= FT_STYLE_FLAG_ITALIC;
+
+ /* XXX: may not be correct */
+ if ( cff->top_font.private_dict.force_bold )
+ flags |= FT_STYLE_FLAG_BOLD;
+
+ root->style_flags = flags;
+ }
+
+ /*******************************************************************/
+ /* */
+ /* Compute char maps. */
+ /* */
+
+ /* Try to synthetize a Unicode charmap if there is none available */
+ /* already. If an OpenType font contains a Unicode "cmap", we */
+ /* will use it, whatever be in the CFF part of the file. */
+ {
+ FT_CharMapRec cmaprec;
+ FT_CharMap cmap;
+ FT_UInt nn;
+ CFF_Encoding encoding = &cff->encoding;
+
+
+ for ( nn = 0; nn < (FT_UInt) root->num_charmaps; nn++ )
+ {
+ cmap = root->charmaps[nn];
+
+ /* Windows Unicode (3,1)? */
+ if ( cmap->platform_id == 3 && cmap->encoding_id == 1 )
+ goto Skip_Unicode;
+
+ /* Deprecated Unicode platform id? */
+ if ( cmap->platform_id == 0 )
+ goto Skip_Unicode; /* Standard Unicode (deprecated) */
+ }
+
+ /* we didn't find a Unicode charmap, synthetize one */
+ cmaprec.face = root;
+ cmaprec.platform_id = 3;
+ cmaprec.encoding_id = 1;
+ cmaprec.encoding = FT_ENCODING_UNICODE;
+
+ nn = (FT_UInt) root->num_charmaps;
+
+ FT_CMap_New( &cff_cmap_unicode_class_rec, NULL, &cmaprec, NULL );
+
+ /* if no Unicode charmap was previously selected, select this one */
+ if ( root->charmap == NULL && nn != (FT_UInt) root->num_charmaps )
+ root->charmap = root->charmaps[nn];
+
+ Skip_Unicode:
+ if ( encoding->count > 0 )
+ {
+ FT_CMap_Class clazz;
+
+
+ cmaprec.face = root;
+ cmaprec.platform_id = 7; /* Adobe platform id */
+
+ if ( encoding->offset == 0 )
+ {
+ cmaprec.encoding_id = 0;
+ cmaprec.encoding = FT_ENCODING_ADOBE_STANDARD;
+ clazz = &cff_cmap_encoding_class_rec;
+ }
+ else if ( encoding->offset == 1 )
+ {
+ cmaprec.encoding_id = 1;
+ cmaprec.encoding = FT_ENCODING_ADOBE_EXPERT;
+ clazz = &cff_cmap_encoding_class_rec;
+ }
+ else
+ {
+ cmaprec.encoding_id = 3;
+ cmaprec.encoding = FT_ENCODING_ADOBE_CUSTOM;
+ clazz = &cff_cmap_encoding_class_rec;
+ }
+
+ FT_CMap_New( clazz, NULL, &cmaprec, NULL );
+ }
+
+ }
+ }
+
+ Exit:
+ return error;
+
+ Bad_Format:
+ error = CFF_Err_Unknown_File_Format;
+ goto Exit;
+ }
+
+
+ FT_LOCAL_DEF( void )
+ cff_face_done( CFF_Face face )
+ {
+ FT_Memory memory = face->root.memory;
+ SFNT_Service sfnt = (SFNT_Service)face->sfnt;
+
+
+ if ( sfnt )
+ sfnt->done_face( face );
+
+ {
+ CFF_Font cff = (CFF_Font)face->extra.data;
+
+
+ if ( cff )
+ {
+ cff_font_done( cff );
+ FT_FREE( face->extra.data );
+ }
+ }
+ }
+
+
+ FT_LOCAL_DEF( FT_Error )
+ cff_driver_init( CFF_Driver driver )
+ {
+ FT_UNUSED( driver );
+
+ return CFF_Err_Ok;
+ }
+
+
+ FT_LOCAL_DEF( void )
+ cff_driver_done( CFF_Driver driver )
+ {
+ FT_UNUSED( driver );
+ }
+
+
+/* END */
--- /dev/null
+++ b/libfreetype/cffobjs.h
@@ -1,0 +1,160 @@
+/***************************************************************************/
+/* */
+/* cffobjs.h */
+/* */
+/* OpenType objects manager (specification). */
+/* */
+/* Copyright 1996-2001, 2002 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+
+#ifndef __CFFOBJS_H__
+#define __CFFOBJS_H__
+
+
+#include <ft2build.h>
+#include FT_INTERNAL_OBJECTS_H
+#include FT_INTERNAL_CFF_TYPES_H
+#include FT_INTERNAL_TRUETYPE_TYPES_H
+#include FT_INTERNAL_POSTSCRIPT_NAMES_H
+
+
+FT_BEGIN_HEADER
+
+
+ /*************************************************************************/
+ /* */
+ /* <Type> */
+ /* CFF_Driver */
+ /* */
+ /* <Description> */
+ /* A handle to an OpenType driver object. */
+ /* */
+ typedef struct CFF_DriverRec_* CFF_Driver;
+
+ typedef TT_Face CFF_Face;
+
+
+ /*************************************************************************/
+ /* */
+ /* <Type> */
+ /* CFF_Size */
+ /* */
+ /* <Description> */
+ /* A handle to an OpenType size object. */
+ /* */
+ typedef FT_Size CFF_Size;
+
+
+ /*************************************************************************/
+ /* */
+ /* <Type> */
+ /* CFF_GlyphSlot */
+ /* */
+ /* <Description> */
+ /* A handle to an OpenType glyph slot object. */
+ /* */
+ typedef struct CFF_GlyphSlotRec_
+ {
+ FT_GlyphSlotRec root;
+
+ FT_Bool hint;
+ FT_Bool scaled;
+
+ FT_Fixed x_scale;
+ FT_Fixed y_scale;
+
+ } CFF_GlyphSlotRec, *CFF_GlyphSlot;
+
+
+
+ /*************************************************************************/
+ /* */
+ /* Subglyph transformation record. */
+ /* */
+ typedef struct CFF_Transform_
+ {
+ FT_Fixed xx, xy; /* transformation matrix coefficients */
+ FT_Fixed yx, yy;
+ FT_F26Dot6 ox, oy; /* offsets */
+
+ } CFF_Transform;
+
+
+ /* this is only used in the case of a pure CFF font with no charmap */
+ typedef struct CFF_CharMapRec_
+ {
+ TT_CharMapRec root;
+ PS_Unicodes unicodes;
+
+ } CFF_CharMapRec, *CFF_CharMap;
+
+
+ /***********************************************************************/
+ /* */
+ /* TrueType driver class. */
+ /* */
+ typedef struct CFF_DriverRec_
+ {
+ FT_DriverRec root;
+ void* extension_component;
+
+ } CFF_DriverRec;
+
+
+ FT_LOCAL( FT_Error )
+ cff_size_init( CFF_Size size );
+
+ FT_LOCAL( void )
+ cff_size_done( CFF_Size size );
+
+ FT_LOCAL( FT_Error )
+ cff_size_reset( CFF_Size size );
+
+ FT_LOCAL( void )
+ cff_slot_done( CFF_GlyphSlot slot );
+
+ FT_LOCAL( FT_Error )
+ cff_slot_init( CFF_GlyphSlot slot );
+
+
+ /*************************************************************************/
+ /* */
+ /* Face functions */
+ /* */
+ FT_LOCAL( FT_Error )
+ cff_face_init( FT_Stream stream,
+ CFF_Face face,
+ FT_Int face_index,
+ FT_Int num_params,
+ FT_Parameter* params );
+
+ FT_LOCAL( void )
+ cff_face_done( CFF_Face face );
+
+
+ /*************************************************************************/
+ /* */
+ /* Driver functions */
+ /* */
+ FT_LOCAL( FT_Error )
+ cff_driver_init( CFF_Driver driver );
+
+ FT_LOCAL( void )
+ cff_driver_done( CFF_Driver driver );
+
+
+FT_END_HEADER
+
+#endif /* __CFFOBJS_H__ */
+
+
+/* END */
--- /dev/null
+++ b/libfreetype/cffparse.c
@@ -1,0 +1,681 @@
+/***************************************************************************/
+/* */
+/* cffparse.c */
+/* */
+/* CFF token stream parser (body) */
+/* */
+/* Copyright 1996-2001, 2002 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+
+#include <ft2build.h>
+#include "cffparse.h"
+#include FT_INTERNAL_STREAM_H
+
+#include "cfferrs.h"
+
+
+ /*************************************************************************/
+ /* */
+ /* The macro FT_COMPONENT is used in trace mode. It is an implicit */
+ /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log */
+ /* messages during execution. */
+ /* */
+#undef FT_COMPONENT
+#define FT_COMPONENT trace_cffparse
+
+
+ enum
+ {
+ cff_kind_none = 0,
+ cff_kind_num,
+ cff_kind_fixed,
+ cff_kind_string,
+ cff_kind_bool,
+ cff_kind_delta,
+ cff_kind_callback,
+
+ cff_kind_max /* do not remove */
+ };
+
+
+ /* now generate handlers for the most simple fields */
+ typedef FT_Error (*CFF_Field_Reader)( CFF_Parser parser );
+
+ typedef struct CFF_Field_Handler_
+ {
+ int kind;
+ int code;
+ FT_UInt offset;
+ FT_Byte size;
+ CFF_Field_Reader reader;
+ FT_UInt array_max;
+ FT_UInt count_offset;
+
+ } CFF_Field_Handler;
+
+
+ FT_LOCAL_DEF( void )
+ cff_parser_init( CFF_Parser parser,
+ FT_UInt code,
+ void* object )
+ {
+ FT_MEM_ZERO( parser, sizeof ( *parser ) );
+
+ parser->top = parser->stack;
+ parser->object_code = code;
+ parser->object = object;
+ }
+
+
+ /* read an integer */
+ static FT_Long
+ cff_parse_integer( FT_Byte* start,
+ FT_Byte* limit )
+ {
+ FT_Byte* p = start;
+ FT_Int v = *p++;
+ FT_Long val = 0;
+
+
+ if ( v == 28 )
+ {
+ if ( p + 2 > limit )
+ goto Bad;
+
+ val = (FT_Short)( ( (FT_Int)p[0] << 8 ) | p[1] );
+ p += 2;
+ }
+ else if ( v == 29 )
+ {
+ if ( p + 4 > limit )
+ goto Bad;
+
+ val = ( (FT_Long)p[0] << 24 ) |
+ ( (FT_Long)p[1] << 16 ) |
+ ( (FT_Long)p[2] << 8 ) |
+ p[3];
+ p += 4;
+ }
+ else if ( v < 247 )
+ {
+ val = v - 139;
+ }
+ else if ( v < 251 )
+ {
+ if ( p + 1 > limit )
+ goto Bad;
+
+ val = ( v - 247 ) * 256 + p[0] + 108;
+ p++;
+ }
+ else
+ {
+ if ( p + 1 > limit )
+ goto Bad;
+
+ val = -( v - 251 ) * 256 - p[0] - 108;
+ p++;
+ }
+
+ Exit:
+ return val;
+
+ Bad:
+ val = 0;
+ goto Exit;
+ }
+
+
+ /* read a real */
+ static FT_Fixed
+ cff_parse_real( FT_Byte* start,
+ FT_Byte* limit,
+ FT_Int power_ten )
+ {
+ FT_Byte* p = start;
+ FT_Long num, divider, result, exp;
+ FT_Int sign = 0, exp_sign = 0;
+ FT_UInt nib;
+ FT_UInt phase;
+
+
+ result = 0;
+ num = 0;
+ divider = 1;
+
+ /* first of all, read the integer part */
+ phase = 4;
+
+ for (;;)
+ {
+ /* If we entered this iteration with phase == 4, we need to */
+ /* read a new byte. This also skips past the intial 0x1E. */
+ if ( phase )
+ {
+ p++;
+
+ /* Make sure we don't read past the end. */
+ if ( p >= limit )
+ goto Bad;
+ }
+
+ /* Get the nibble. */
+ nib = ( p[0] >> phase ) & 0xF;
+ phase = 4 - phase;
+
+ if ( nib == 0xE )
+ sign = 1;
+ else if ( nib > 9 )
+ break;
+ else
+ result = result * 10 + nib;
+ }
+
+ /* read decimal part, if any */
+ if ( nib == 0xa )
+ for (;;)
+ {
+ /* If we entered this iteration with phase == 4, we need */
+ /* to read a new byte. */
+ if ( phase )
+ {
+ p++;
+
+ /* Make sure we don't read past the end. */
+ if ( p >= limit )
+ goto Bad;
+ }
+
+ /* Get the nibble. */
+ nib = ( p[0] >> phase ) & 0xF;
+ phase = 4 - phase;
+ if ( nib >= 10 )
+ break;
+
+ if ( divider < 10000000L )
+ {
+ num = num * 10 + nib;
+ divider *= 10;
+ }
+ }
+
+ /* read exponent, if any */
+ if ( nib == 12 )
+ {
+ exp_sign = 1;
+ nib = 11;
+ }
+
+ if ( nib == 11 )
+ {
+ exp = 0;
+
+ for (;;)
+ {
+ /* If we entered this iteration with phase == 4, we need */
+ /* to read a new byte. */
+ if ( phase )
+ {
+ p++;
+
+ /* Make sure we don't read past the end. */
+ if ( p >= limit )
+ goto Bad;
+ }
+
+ /* Get the nibble. */
+ nib = ( p[0] >> phase ) & 0xF;
+ phase = 4 - phase;
+ if ( nib >= 10 )
+ break;
+
+ exp = exp * 10 + nib;
+ }
+
+ if ( exp_sign )
+ exp = -exp;
+
+ power_ten += (FT_Int)exp;
+ }
+
+ /* raise to power of ten if needed */
+ while ( power_ten > 0 )
+ {
+ result = result * 10;
+ num = num * 10;
+
+ power_ten--;
+ }
+
+ while ( power_ten < 0 )
+ {
+ result = result / 10;
+ divider = divider * 10;
+
+ power_ten++;
+ }
+
+ /* Move the integer part into the high 16 bits. */
+ result <<= 16;
+
+ /* Place the decimal part into the low 16 bits. */
+ if ( num )
+ result |= FT_DivFix( num, divider );
+
+ if ( sign )
+ result = -result;
+
+ Exit:
+ return result;
+
+ Bad:
+ result = 0;
+ goto Exit;
+ }
+
+
+ /* read a number, either integer or real */
+ static FT_Long
+ cff_parse_num( FT_Byte** d )
+ {
+ return ( **d == 30 ? ( cff_parse_real ( d[0], d[1], 0 ) >> 16 )
+ : cff_parse_integer( d[0], d[1] ) );
+ }
+
+
+ /* read a floating point number, either integer or real */
+ static FT_Fixed
+ cff_parse_fixed( FT_Byte** d )
+ {
+ return ( **d == 30 ? cff_parse_real ( d[0], d[1], 0 )
+ : cff_parse_integer( d[0], d[1] ) << 16 );
+ }
+
+ /* read a floating point number, either integer or real, */
+ /* but return 1000 times the number read in. */
+ static FT_Fixed
+ cff_parse_fixed_thousand( FT_Byte** d )
+ {
+ return **d ==
+ 30 ? cff_parse_real ( d[0], d[1], 3 )
+ : (FT_Fixed)FT_MulFix( cff_parse_integer( d[0], d[1] ) << 16, 1000 );
+ }
+
+ static FT_Error
+ cff_parse_font_matrix( CFF_Parser parser )
+ {
+ CFF_FontRecDict dict = (CFF_FontRecDict)parser->object;
+ FT_Matrix* matrix = &dict->font_matrix;
+ FT_Vector* offset = &dict->font_offset;
+ FT_UShort* upm = &dict->units_per_em;
+ FT_Byte** data = parser->stack;
+ FT_Error error;
+ FT_Fixed temp;
+
+
+ error = CFF_Err_Stack_Underflow;
+
+ if ( parser->top >= parser->stack + 6 )
+ {
+ matrix->xx = cff_parse_fixed_thousand( data++ );
+ matrix->yx = cff_parse_fixed_thousand( data++ );
+ matrix->xy = cff_parse_fixed_thousand( data++ );
+ matrix->yy = cff_parse_fixed_thousand( data++ );
+ offset->x = cff_parse_fixed_thousand( data++ );
+ offset->y = cff_parse_fixed_thousand( data );
+
+ temp = ABS( matrix->yy );
+
+ *upm = (FT_UShort)FT_DivFix( 0x10000L, FT_DivFix( temp, 1000 ) );
+
+ if ( temp != 0x10000L )
+ {
+ matrix->xx = FT_DivFix( matrix->xx, temp );
+ matrix->yx = FT_DivFix( matrix->yx, temp );
+ matrix->xy = FT_DivFix( matrix->xy, temp );
+ matrix->yy = FT_DivFix( matrix->yy, temp );
+ offset->x = FT_DivFix( offset->x, temp );
+ offset->y = FT_DivFix( offset->y, temp );
+ }
+
+ /* note that the offsets must be expressed in integer font units */
+ offset->x >>= 16;
+ offset->y >>= 16;
+
+ error = CFF_Err_Ok;
+ }
+
+ return error;
+ }
+
+
+ static FT_Error
+ cff_parse_font_bbox( CFF_Parser parser )
+ {
+ CFF_FontRecDict dict = (CFF_FontRecDict)parser->object;
+ FT_BBox* bbox = &dict->font_bbox;
+ FT_Byte** data = parser->stack;
+ FT_Error error;
+
+
+ error = CFF_Err_Stack_Underflow;
+
+ if ( parser->top >= parser->stack + 4 )
+ {
+ bbox->xMin = FT_RoundFix( cff_parse_fixed( data++ ) );
+ bbox->yMin = FT_RoundFix( cff_parse_fixed( data++ ) );
+ bbox->xMax = FT_RoundFix( cff_parse_fixed( data++ ) );
+ bbox->yMax = FT_RoundFix( cff_parse_fixed( data ) );
+ error = CFF_Err_Ok;
+ }
+
+ return error;
+ }
+
+
+ static FT_Error
+ cff_parse_private_dict( CFF_Parser parser )
+ {
+ CFF_FontRecDict dict = (CFF_FontRecDict)parser->object;
+ FT_Byte** data = parser->stack;
+ FT_Error error;
+
+
+ error = CFF_Err_Stack_Underflow;
+
+ if ( parser->top >= parser->stack + 2 )
+ {
+ dict->private_size = cff_parse_num( data++ );
+ dict->private_offset = cff_parse_num( data );
+ error = CFF_Err_Ok;
+ }
+
+ return error;
+ }
+
+
+ static FT_Error
+ cff_parse_cid_ros( CFF_Parser parser )
+ {
+ CFF_FontRecDict dict = (CFF_FontRecDict)parser->object;
+ FT_Byte** data = parser->stack;
+ FT_Error error;
+
+
+ error = CFF_Err_Stack_Underflow;
+
+ if ( parser->top >= parser->stack + 3 )
+ {
+ dict->cid_registry = (FT_UInt)cff_parse_num ( data++ );
+ dict->cid_ordering = (FT_UInt)cff_parse_num ( data++ );
+ dict->cid_supplement = (FT_ULong)cff_parse_num( data );
+ error = CFF_Err_Ok;
+ }
+
+ return error;
+ }
+
+
+#define CFF_FIELD_NUM( code, name ) \
+ CFF_FIELD( code, name, cff_kind_num )
+#define CFF_FIELD_FIXED( code, name ) \
+ CFF_FIELD( code, name, cff_kind_fixed )
+#define CFF_FIELD_STRING( code, name ) \
+ CFF_FIELD( code, name, cff_kind_string )
+#define CFF_FIELD_BOOL( code, name ) \
+ CFF_FIELD( code, name, cff_kind_bool )
+#define CFF_FIELD_DELTA( code, name, max ) \
+ CFF_FIELD( code, name, cff_kind_delta )
+
+#define CFF_FIELD_CALLBACK( code, name ) \
+ { \
+ cff_kind_callback, \
+ code | CFFCODE, \
+ 0, 0, \
+ cff_parse_ ## name, \
+ 0, 0 \
+ },
+
+#undef CFF_FIELD
+#define CFF_FIELD( code, name, kind ) \
+ { \
+ kind, \
+ code | CFFCODE, \
+ FT_FIELD_OFFSET( name ), \
+ FT_FIELD_SIZE( name ), \
+ 0, 0, 0 \
+ },
+
+#undef CFF_FIELD_DELTA
+#define CFF_FIELD_DELTA( code, name, max ) \
+ { \
+ cff_kind_delta, \
+ code | CFFCODE, \
+ FT_FIELD_OFFSET( name ), \
+ FT_FIELD_SIZE_DELTA( name ), \
+ 0, \
+ max, \
+ FT_FIELD_OFFSET( num_ ## name ) \
+ },
+
+#define CFFCODE_TOPDICT 0x1000
+#define CFFCODE_PRIVATE 0x2000
+
+ static const CFF_Field_Handler cff_field_handlers[] =
+ {
+
+#include "cfftoken.h"
+
+ { 0, 0, 0, 0, 0, 0, 0 }
+ };
+
+
+ FT_LOCAL_DEF( FT_Error )
+ cff_parser_run( CFF_Parser parser,
+ FT_Byte* start,
+ FT_Byte* limit )
+ {
+ FT_Byte* p = start;
+ FT_Error error = CFF_Err_Ok;
+
+
+ parser->top = parser->stack;
+ parser->start = start;
+ parser->limit = limit;
+ parser->cursor = start;
+
+ while ( p < limit )
+ {
+ FT_UInt v = *p;
+
+
+ if ( v >= 27 && v != 31 )
+ {
+ /* it's a number; we will push its position on the stack */
+ if ( parser->top - parser->stack >= CFF_MAX_STACK_DEPTH )
+ goto Stack_Overflow;
+
+ *parser->top ++ = p;
+
+ /* now, skip it */
+ if ( v == 30 )
+ {
+ /* skip real number */
+ p++;
+ for (;;)
+ {
+ if ( p >= limit )
+ goto Syntax_Error;
+ v = p[0] >> 4;
+ if ( v == 15 )
+ break;
+ v = p[0] & 0xF;
+ if ( v == 15 )
+ break;
+ p++;
+ }
+ }
+ else if ( v == 28 )
+ p += 2;
+ else if ( v == 29 )
+ p += 4;
+ else if ( v > 246 )
+ p += 1;
+ }
+ else
+ {
+ /* This is not a number, hence it's an operator. Compute its code */
+ /* and look for it in our current list. */
+
+ FT_UInt code;
+ FT_UInt num_args = (FT_UInt)
+ ( parser->top - parser->stack );
+ const CFF_Field_Handler* field;
+
+
+ *parser->top = p;
+ code = v;
+ if ( v == 12 )
+ {
+ /* two byte operator */
+ p++;
+ if ( p >= limit )
+ goto Syntax_Error;
+
+ code = 0x100 | p[0];
+ }
+ code = code | parser->object_code;
+
+ for ( field = cff_field_handlers; field->kind; field++ )
+ {
+ if ( field->code == (FT_Int)code )
+ {
+ /* we found our field's handler; read it */
+ FT_Long val;
+ FT_Byte* q = (FT_Byte*)parser->object + field->offset;
+
+
+ /* check that we have enough arguments -- except for */
+ /* delta encoded arrays, which can be empty */
+ if ( field->kind != cff_kind_delta && num_args < 1 )
+ goto Stack_Underflow;
+
+ switch ( field->kind )
+ {
+ case cff_kind_bool:
+ case cff_kind_string:
+ case cff_kind_num:
+ val = cff_parse_num( parser->stack );
+ goto Store_Number;
+
+ case cff_kind_fixed:
+ val = cff_parse_fixed( parser->stack );
+
+ Store_Number:
+ switch ( field->size )
+ {
+ case 1:
+ *(FT_Byte*)q = (FT_Byte)val;
+ break;
+
+ case 2:
+ *(FT_Short*)q = (FT_Short)val;
+ break;
+
+ case 4:
+ *(FT_Int32*)q = (FT_Int)val;
+ break;
+
+ default: /* for 64-bit systems where long is 8 bytes */
+ *(FT_Long*)q = val;
+ }
+ break;
+
+ case cff_kind_delta:
+ {
+ FT_Byte* qcount = (FT_Byte*)parser->object +
+ field->count_offset;
+
+ FT_Byte** data = parser->stack;
+
+
+ if ( num_args > field->array_max )
+ num_args = field->array_max;
+
+ /* store count */
+ *qcount = (FT_Byte)num_args;
+
+ val = 0;
+ while ( num_args > 0 )
+ {
+ val += cff_parse_num( data++ );
+ switch ( field->size )
+ {
+ case 1:
+ *(FT_Byte*)q = (FT_Byte)val;
+ break;
+
+ case 2:
+ *(FT_Short*)q = (FT_Short)val;
+ break;
+
+ case 4:
+ *(FT_Int32*)q = (FT_Int)val;
+ break;
+
+ default: /* for 64-bit systems */
+ *(FT_Long*)q = val;
+ }
+
+ q += field->size;
+ num_args--;
+ }
+ }
+ break;
+
+ default: /* callback */
+ error = field->reader( parser );
+ if ( error )
+ goto Exit;
+ }
+ goto Found;
+ }
+ }
+
+ /* this is an unknown operator, or it is unsupported; */
+ /* we will ignore it for now. */
+
+ Found:
+ /* clear stack */
+ parser->top = parser->stack;
+ }
+ p++;
+ }
+
+ Exit:
+ return error;
+
+ Stack_Overflow:
+ error = CFF_Err_Invalid_Argument;
+ goto Exit;
+
+ Stack_Underflow:
+ error = CFF_Err_Invalid_Argument;
+ goto Exit;
+
+ Syntax_Error:
+ error = CFF_Err_Invalid_Argument;
+ goto Exit;
+ }
+
+
+/* END */
--- /dev/null
+++ b/libfreetype/cffparse.h
@@ -1,0 +1,69 @@
+/***************************************************************************/
+/* */
+/* cffparse.h */
+/* */
+/* CFF token stream parser (specification) */
+/* */
+/* Copyright 1996-2001, 2002 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+
+#ifndef __CFF_PARSE_H__
+#define __CFF_PARSE_H__
+
+
+#include <ft2build.h>
+#include FT_INTERNAL_CFF_TYPES_H
+#include FT_INTERNAL_OBJECTS_H
+
+
+FT_BEGIN_HEADER
+
+
+#define CFF_MAX_STACK_DEPTH 96
+
+#define CFF_CODE_TOPDICT 0x1000
+#define CFF_CODE_PRIVATE 0x2000
+
+
+ typedef struct CFF_ParserRec_
+ {
+ FT_Byte* start;
+ FT_Byte* limit;
+ FT_Byte* cursor;
+
+ FT_Byte* stack[CFF_MAX_STACK_DEPTH + 1];
+ FT_Byte** top;
+
+ FT_UInt object_code;
+ void* object;
+
+ } CFF_ParserRec, *CFF_Parser;
+
+
+ FT_LOCAL( void )
+ cff_parser_init( CFF_Parser parser,
+ FT_UInt code,
+ void* object );
+
+ FT_LOCAL( FT_Error )
+ cff_parser_run( CFF_Parser parser,
+ FT_Byte* start,
+ FT_Byte* limit );
+
+
+FT_END_HEADER
+
+
+#endif /* __CFF_PARSE_H__ */
+
+
+/* END */
--- /dev/null
+++ b/libfreetype/cfftoken.h
@@ -1,0 +1,97 @@
+/***************************************************************************/
+/* */
+/* cfftoken.h */
+/* */
+/* CFF token definitions (specification only). */
+/* */
+/* Copyright 1996-2001, 2002 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+
+#undef FT_STRUCTURE
+#define FT_STRUCTURE CFF_FontRecDictRec
+
+#undef CFFCODE
+#define CFFCODE CFFCODE_TOPDICT
+
+ CFF_FIELD_STRING ( 0, version )
+ CFF_FIELD_STRING ( 1, notice )
+ CFF_FIELD_STRING ( 0x100, copyright )
+ CFF_FIELD_STRING ( 2, full_name )
+ CFF_FIELD_STRING ( 3, family_name )
+ CFF_FIELD_STRING ( 4, weight )
+ CFF_FIELD_BOOL ( 0x101, is_fixed_pitch )
+ CFF_FIELD_FIXED ( 0x102, italic_angle )
+ CFF_FIELD_NUM ( 0x103, underline_position )
+ CFF_FIELD_NUM ( 0x104, underline_thickness )
+ CFF_FIELD_NUM ( 0x105, paint_type )
+ CFF_FIELD_NUM ( 0x106, charstring_type )
+ CFF_FIELD_CALLBACK( 0x107, font_matrix )
+ CFF_FIELD_NUM ( 13, unique_id )
+ CFF_FIELD_CALLBACK( 5, font_bbox )
+ CFF_FIELD_NUM ( 0x108, stroke_width )
+ CFF_FIELD_NUM ( 15, charset_offset )
+ CFF_FIELD_NUM ( 16, encoding_offset )
+ CFF_FIELD_NUM ( 17, charstrings_offset )
+ CFF_FIELD_CALLBACK( 18, private_dict )
+ CFF_FIELD_NUM ( 0x114, synthetic_base )
+ CFF_FIELD_STRING ( 0x115, postscript )
+ CFF_FIELD_STRING ( 0x116, base_font_name )
+
+#if 0
+ CFF_FIELD_DELTA ( 0x117, base_font_blend, 16 )
+ CFF_FIELD_CALLBACK( 0x118, multiple_master )
+ CFF_FIELD_CALLBACK( 0x119, blend_axit_types )
+#endif
+
+ CFF_FIELD_CALLBACK( 0x11E, cid_ros )
+ CFF_FIELD_NUM ( 0x11F, cid_font_version )
+ CFF_FIELD_NUM ( 0x120, cid_font_revision )
+ CFF_FIELD_NUM ( 0x121, cid_font_type )
+ CFF_FIELD_NUM ( 0x122, cid_count )
+ CFF_FIELD_NUM ( 0x123, cid_uid_base )
+ CFF_FIELD_NUM ( 0x124, cid_fd_array_offset )
+ CFF_FIELD_NUM ( 0x125, cid_fd_select_offset )
+ CFF_FIELD_STRING ( 0x126, cid_font_name )
+
+#if 0
+ CFF_FIELD_NUM ( 0x127, chameleon )
+#endif
+
+
+#undef FT_STRUCTURE
+#define FT_STRUCTURE CFF_PrivateRec
+#undef CFFCODE
+#define CFFCODE CFFCODE_PRIVATE
+
+ CFF_FIELD_DELTA( 6, blue_values, 14 )
+ CFF_FIELD_DELTA( 7, other_blues, 10 )
+ CFF_FIELD_DELTA( 8, family_blues, 14 )
+ CFF_FIELD_DELTA( 9, family_other_blues, 10 )
+ CFF_FIELD_FIXED( 0x109, blue_scale )
+ CFF_FIELD_NUM ( 0x10A, blue_shift )
+ CFF_FIELD_NUM ( 0x10B, blue_fuzz )
+ CFF_FIELD_NUM ( 10, standard_width )
+ CFF_FIELD_NUM ( 11, standard_height )
+ CFF_FIELD_DELTA( 0x10C, snap_widths, 13 )
+ CFF_FIELD_DELTA( 0x10D, snap_heights, 13 )
+ CFF_FIELD_BOOL ( 0x10E, force_bold )
+ CFF_FIELD_FIXED( 0x10F, force_bold_threshold )
+ CFF_FIELD_NUM ( 0x110, lenIV )
+ CFF_FIELD_NUM ( 0x111, language_group )
+ CFF_FIELD_FIXED( 0x112, expansion_factor )
+ CFF_FIELD_NUM ( 0x113, initial_random_seed )
+ CFF_FIELD_NUM ( 19, local_subrs_offset )
+ CFF_FIELD_NUM ( 20, default_width )
+ CFF_FIELD_NUM ( 21, nominal_width )
+
+
+/* END */
--- /dev/null
+++ b/libfreetype/ciderrs.h
@@ -1,0 +1,40 @@
+/***************************************************************************/
+/* */
+/* ciderrs.h */
+/* */
+/* CID error codes (specification only). */
+/* */
+/* Copyright 2001 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+
+ /*************************************************************************/
+ /* */
+ /* This file is used to define the CID error enumeration constants. */
+ /* */
+ /*************************************************************************/
+
+#ifndef __CIDERRS_H__
+#define __CIDERRS_H__
+
+#include FT_MODULE_ERRORS_H
+
+#undef __FTERRORS_H__
+
+#define FT_ERR_PREFIX CID_Err_
+#define FT_ERR_BASE FT_Mod_Err_CID
+
+#include FT_ERRORS_H
+
+#endif /* __CIDERRS_H__ */
+
+
+/* END */
--- /dev/null
+++ b/libfreetype/cidgload.c
@@ -1,0 +1,437 @@
+/***************************************************************************/
+/* */
+/* cidgload.c */
+/* */
+/* CID-keyed Type1 Glyph Loader (body). */
+/* */
+/* Copyright 1996-2001, 2002 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+
+#include <ft2build.h>
+#include "cidload.h"
+#include "cidgload.h"
+#include FT_INTERNAL_DEBUG_H
+#include FT_INTERNAL_STREAM_H
+#include FT_OUTLINE_H
+
+#include "ciderrs.h"
+
+
+ /*************************************************************************/
+ /* */
+ /* The macro FT_COMPONENT is used in trace mode. It is an implicit */
+ /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log */
+ /* messages during execution. */
+ /* */
+#undef FT_COMPONENT
+#define FT_COMPONENT trace_cidgload
+
+
+ FT_CALLBACK_DEF( FT_Error )
+ cid_load_glyph( T1_Decoder decoder,
+ FT_UInt glyph_index )
+ {
+ CID_Face face = (CID_Face)decoder->builder.face;
+ CID_FaceInfo cid = &face->cid;
+ FT_Byte* p;
+ FT_UInt fd_select;
+ FT_Stream stream = face->root.stream;
+ FT_Error error = 0;
+ FT_Byte* charstring = 0;
+ FT_Memory memory = face->root.memory;
+ FT_UInt glyph_length = 0;
+
+
+#ifdef FT_CONFIG_OPTION_INCREMENTAL
+
+ /* For incremental fonts get the character data using */
+ /* the callback function. */
+ if ( face->root.internal->incremental_interface )
+ {
+ FT_Data glyph_data;
+
+
+ error = face->root.internal->incremental_interface->funcs->get_glyph_data(
+ face->root.internal->incremental_interface->object,
+ glyph_index,
+ &glyph_data );
+ if ( error )
+ goto Exit;
+
+ p = (FT_Byte*)glyph_data.pointer;
+ fd_select = (FT_UInt)cid_get_offset( &p, (FT_Byte)cid->fd_bytes );
+
+ if ( glyph_data.length != 0 )
+ {
+ glyph_length = glyph_data.length - cid->fd_bytes;
+ FT_ALLOC( charstring, glyph_length );
+ if ( !error )
+ ft_memcpy( charstring, glyph_data.pointer + cid->fd_bytes,
+ glyph_length );
+ }
+
+ face->root.internal->incremental_interface->funcs->free_glyph_data(
+ face->root.internal->incremental_interface->object,
+ &glyph_data );
+
+ if ( error )
+ goto Exit;
+ }
+
+ else
+
+#endif
+
+ /* For ordinary fonts read the CID font dictionary index */
+ /* and charstring offset from the CIDMap. */
+ {
+ FT_UInt entry_len = cid->fd_bytes + cid->gd_bytes;
+ FT_ULong off1;
+
+
+ if ( FT_STREAM_SEEK( cid->data_offset + cid->cidmap_offset +
+ glyph_index * entry_len ) ||
+ FT_FRAME_ENTER( 2 * entry_len ) )
+ goto Exit;
+
+ p = (FT_Byte*)stream->cursor;
+ fd_select = (FT_UInt) cid_get_offset( &p, (FT_Byte)cid->fd_bytes );
+ off1 = (FT_ULong)cid_get_offset( &p, (FT_Byte)cid->gd_bytes );
+ p += cid->fd_bytes;
+ glyph_length = (FT_UInt) cid_get_offset(
+ &p, (FT_Byte)cid->gd_bytes ) - off1;
+ FT_FRAME_EXIT();
+
+ if ( glyph_length == 0 )
+ goto Exit;
+ if ( FT_ALLOC( charstring, glyph_length ) )
+ goto Exit;
+ if ( FT_STREAM_READ_AT( cid->data_offset + off1,
+ charstring, glyph_length ) )
+ goto Exit;
+ }
+
+ /* Now set up the subrs array and parse the charstrings. */
+ {
+ CID_FaceDict dict;
+ CID_Subrs cid_subrs = face->subrs + fd_select;
+ FT_Int cs_offset;
+
+
+ /* Set up subrs */
+ decoder->num_subrs = cid_subrs->num_subrs;
+ decoder->subrs = cid_subrs->code;
+ decoder->subrs_len = 0;
+
+ /* Set up font matrix */
+ dict = cid->font_dicts + fd_select;
+
+ decoder->font_matrix = dict->font_matrix;
+ decoder->font_offset = dict->font_offset;
+ decoder->lenIV = dict->private_dict.lenIV;
+
+ /* Decode the charstring. */
+
+ /* Adjustment for seed bytes. */
+ cs_offset = ( decoder->lenIV >= 0 ? decoder->lenIV : 0 );
+
+ /* Decrypt only if lenIV >= 0. */
+ if ( decoder->lenIV >= 0 )
+ cid_decrypt( charstring, glyph_length, 4330 );
+
+ error = decoder->funcs.parse_charstrings( decoder,
+ charstring + cs_offset,
+ glyph_length - cs_offset );
+ }
+
+ FT_FREE( charstring );
+
+#ifdef FT_CONFIG_OPTION_INCREMENTAL
+
+ /* Incremental fonts can optionally override the metrics. */
+ if ( !error &&
+ face->root.internal->incremental_interface &&
+ face->root.internal->incremental_interface->funcs->get_glyph_metrics )
+ {
+ FT_Bool found = FALSE;
+ FT_Incremental_MetricsRec metrics;
+
+
+ error = face->root.internal->incremental_interface->funcs->get_glyph_metrics(
+ face->root.internal->incremental_interface->object,
+ glyph_index, FALSE, &metrics, &found );
+ if ( found )
+ {
+ decoder->builder.left_bearing.x = metrics.bearing_x;
+ decoder->builder.left_bearing.y = metrics.bearing_y;
+ decoder->builder.advance.x = metrics.advance;
+ decoder->builder.advance.y = 0;
+ }
+ }
+
+#endif
+
+ Exit:
+ return error;
+ }
+
+
+#if 0
+
+
+ /*************************************************************************/
+ /*************************************************************************/
+ /*************************************************************************/
+ /********** *********/
+ /********** *********/
+ /********** COMPUTE THE MAXIMUM ADVANCE WIDTH *********/
+ /********** *********/
+ /********** The following code is in charge of computing *********/
+ /********** the maximum advance width of the font. It *********/
+ /********** quickly processes each glyph charstring to *********/
+ /********** extract the value from either a `sbw' or `seac' *********/
+ /********** operator. *********/
+ /********** *********/
+ /*************************************************************************/
+ /*************************************************************************/
+ /*************************************************************************/
+
+
+ FT_LOCAL_DEF( FT_Error )
+ cid_face_compute_max_advance( CID_Face face,
+ FT_Int* max_advance )
+ {
+ FT_Error error;
+ T1_DecoderRec decoder;
+ FT_Int glyph_index;
+
+ PSAux_Service psaux = (PSAux_Service)face->psaux;
+
+
+ *max_advance = 0;
+
+ /* Initialize load decoder */
+ error = psaux->t1_decoder_funcs->init( &decoder,
+ (FT_Face)face,
+ 0, /* size */
+ 0, /* glyph slot */
+ 0, /* glyph names! XXX */
+ 0, /* blend == 0 */
+ 0, /* hinting == 0 */
+ cid_load_glyph );
+ if ( error )
+ return error;
+
+ decoder.builder.metrics_only = 1;
+ decoder.builder.load_points = 0;
+
+ /* for each glyph, parse the glyph charstring and extract */
+ /* the advance width */
+ for ( glyph_index = 0; glyph_index < face->root.num_glyphs;
+ glyph_index++ )
+ {
+ /* now get load the unscaled outline */
+ error = cid_load_glyph( &decoder, glyph_index );
+ /* ignore the error if one occurred - skip to next glyph */
+ }
+
+ *max_advance = decoder.builder.advance.x;
+
+ return CID_Err_Ok;
+ }
+
+
+#endif /* 0 */
+
+
+ /*************************************************************************/
+ /*************************************************************************/
+ /*************************************************************************/
+ /********** *********/
+ /********** *********/
+ /********** UNHINTED GLYPH LOADER *********/
+ /********** *********/
+ /********** The following code is in charge of loading a *********/
+ /********** single outline. It completely ignores hinting *********/
+ /********** and is used when FT_LOAD_NO_HINTING is set. *********/
+ /********** *********/
+ /*************************************************************************/
+ /*************************************************************************/
+ /*************************************************************************/
+
+
+ FT_LOCAL_DEF( FT_Error )
+ cid_slot_load_glyph( CID_GlyphSlot glyph,
+ CID_Size size,
+ FT_Int glyph_index,
+ FT_Int32 load_flags )
+ {
+ FT_Error error;
+ T1_DecoderRec decoder;
+ CID_Face face = (CID_Face)glyph->root.face;
+ FT_Bool hinting;
+
+ PSAux_Service psaux = (PSAux_Service)face->psaux;
+ FT_Matrix font_matrix;
+ FT_Vector font_offset;
+
+
+ if ( load_flags & FT_LOAD_NO_RECURSE )
+ load_flags |= FT_LOAD_NO_SCALE | FT_LOAD_NO_HINTING;
+
+ glyph->x_scale = size->root.metrics.x_scale;
+ glyph->y_scale = size->root.metrics.y_scale;
+
+ glyph->root.outline.n_points = 0;
+ glyph->root.outline.n_contours = 0;
+
+ hinting = FT_BOOL( ( load_flags & FT_LOAD_NO_SCALE ) == 0 &&
+ ( load_flags & FT_LOAD_NO_HINTING ) == 0 );
+
+ glyph->root.format = FT_GLYPH_FORMAT_OUTLINE;
+
+ {
+ error = psaux->t1_decoder_funcs->init( &decoder,
+ (FT_Face)face,
+ (FT_Size)size,
+ (FT_GlyphSlot)glyph,
+ 0, /* glyph names -- XXX */
+ 0, /* blend == 0 */
+ hinting,
+ FT_LOAD_TARGET_MODE(load_flags),
+ cid_load_glyph );
+
+ /* set up the decoder */
+ decoder.builder.no_recurse = FT_BOOL(
+ ( ( load_flags & FT_LOAD_NO_RECURSE ) != 0 ) );
+
+ error = cid_load_glyph( &decoder, glyph_index );
+
+ font_matrix = decoder.font_matrix;
+ font_offset = decoder.font_offset;
+
+ /* save new glyph tables */
+ psaux->t1_decoder_funcs->done( &decoder );
+ }
+
+ /* now, set the metrics -- this is rather simple, as */
+ /* the left side bearing is the xMin, and the top side */
+ /* bearing the yMax */
+ if ( !error )
+ {
+ glyph->root.outline.flags &= FT_OUTLINE_OWNER;
+ glyph->root.outline.flags |= FT_OUTLINE_REVERSE_FILL;
+
+ /* for composite glyphs, return only left side bearing and */
+ /* advance width */
+ if ( load_flags & FT_LOAD_NO_RECURSE )
+ {
+ FT_Slot_Internal internal = glyph->root.internal;
+
+
+ glyph->root.metrics.horiBearingX = decoder.builder.left_bearing.x;
+ glyph->root.metrics.horiAdvance = decoder.builder.advance.x;
+
+ internal->glyph_matrix = font_matrix;
+ internal->glyph_delta = font_offset;
+ internal->glyph_transformed = 1;
+ }
+ else
+ {
+ FT_BBox cbox;
+ FT_Glyph_Metrics* metrics = &glyph->root.metrics;
+
+
+ /* copy the _unscaled_ advance width */
+ metrics->horiAdvance = decoder.builder.advance.x;
+ glyph->root.linearHoriAdvance = decoder.builder.advance.x;
+ glyph->root.internal->glyph_transformed = 0;
+
+ /* make up vertical metrics */
+ metrics->vertBearingX = 0;
+ metrics->vertBearingY = 0;
+ metrics->vertAdvance = 0;
+
+ glyph->root.linearVertAdvance = 0;
+ glyph->root.format = FT_GLYPH_FORMAT_OUTLINE;
+
+ if ( size && size->root.metrics.y_ppem < 24 )
+ glyph->root.outline.flags |= FT_OUTLINE_HIGH_PRECISION;
+
+ /* apply the font matrix */
+ FT_Outline_Transform( &glyph->root.outline, &font_matrix );
+
+ FT_Outline_Translate( &glyph->root.outline,
+ font_offset.x,
+ font_offset.y );
+
+ if ( ( load_flags & FT_LOAD_NO_SCALE ) == 0 )
+ {
+ /* scale the outline and the metrics */
+ FT_Int n;
+ FT_Outline* cur = decoder.builder.base;
+ FT_Vector* vec = cur->points;
+ FT_Fixed x_scale = glyph->x_scale;
+ FT_Fixed y_scale = glyph->y_scale;
+
+
+ /* First of all, scale the points */
+ if ( !hinting )
+ for ( n = cur->n_points; n > 0; n--, vec++ )
+ {
+ vec->x = FT_MulFix( vec->x, x_scale );
+ vec->y = FT_MulFix( vec->y, y_scale );
+ }
+
+ FT_Outline_Get_CBox( &glyph->root.outline, &cbox );
+
+ /* Then scale the metrics */
+ metrics->horiAdvance = FT_MulFix( metrics->horiAdvance, x_scale );
+ metrics->vertAdvance = FT_MulFix( metrics->vertAdvance, y_scale );
+
+ metrics->vertBearingX = FT_MulFix( metrics->vertBearingX, x_scale );
+ metrics->vertBearingY = FT_MulFix( metrics->vertBearingY, y_scale );
+
+ if ( hinting )
+ {
+ metrics->horiAdvance = ( metrics->horiAdvance + 32 ) & -64;
+ metrics->vertAdvance = ( metrics->vertAdvance + 32 ) & -64;
+
+ metrics->vertBearingX = ( metrics->vertBearingX + 32 ) & -64;
+ metrics->vertBearingY = ( metrics->vertBearingY + 32 ) & -64;
+ }
+ }
+
+ /* compute the other metrics */
+ FT_Outline_Get_CBox( &glyph->root.outline, &cbox );
+
+ /* grid fit the bounding box if necessary */
+ if ( hinting )
+ {
+ cbox.xMin &= -64;
+ cbox.yMin &= -64;
+ cbox.xMax = ( cbox.xMax + 63 ) & -64;
+ cbox.yMax = ( cbox.yMax + 63 ) & -64;
+ }
+
+ metrics->width = cbox.xMax - cbox.xMin;
+ metrics->height = cbox.yMax - cbox.yMin;
+
+ metrics->horiBearingX = cbox.xMin;
+ metrics->horiBearingY = cbox.yMax;
+ }
+ }
+ return error;
+ }
+
+
+/* END */
--- /dev/null
+++ b/libfreetype/cidgload.h
@@ -1,0 +1,51 @@
+/***************************************************************************/
+/* */
+/* cidgload.h */
+/* */
+/* OpenType Glyph Loader (specification). */
+/* */
+/* Copyright 1996-2001, 2002 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+
+#ifndef __CIDGLOAD_H__
+#define __CIDGLOAD_H__
+
+
+#include <ft2build.h>
+#include "cidobjs.h"
+
+
+FT_BEGIN_HEADER
+
+
+#if 0
+
+ /* Compute the maximum advance width of a font through quick parsing */
+ FT_LOCAL( FT_Error )
+ cid_face_compute_max_advance( CID_Face face,
+ FT_Int* max_advance );
+
+#endif /* 0 */
+
+ FT_LOCAL( FT_Error )
+ cid_slot_load_glyph( CID_GlyphSlot glyph,
+ CID_Size size,
+ FT_Int glyph_index,
+ FT_Int32 load_flags );
+
+
+FT_END_HEADER
+
+#endif /* __CIDGLOAD_H__ */
+
+
+/* END */
--- /dev/null
+++ b/libfreetype/cidload.c
@@ -1,0 +1,546 @@
+/***************************************************************************/
+/* */
+/* cidload.c */
+/* */
+/* CID-keyed Type1 font loader (body). */
+/* */
+/* Copyright 1996-2001, 2002 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+
+#include <ft2build.h>
+#include FT_INTERNAL_DEBUG_H
+#include FT_CONFIG_CONFIG_H
+#include FT_MULTIPLE_MASTERS_H
+#include FT_INTERNAL_TYPE1_TYPES_H
+
+#include "cidload.h"
+
+#include "ciderrs.h"
+
+
+ /*************************************************************************/
+ /* */
+ /* The macro FT_COMPONENT is used in trace mode. It is an implicit */
+ /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log */
+ /* messages during execution. */
+ /* */
+#undef FT_COMPONENT
+#define FT_COMPONENT trace_cidload
+
+
+ /* read a single offset */
+ FT_LOCAL_DEF( FT_Long )
+ cid_get_offset( FT_Byte** start,
+ FT_Byte offsize )
+ {
+ FT_Long result;
+ FT_Byte* p = *start;
+
+
+ for ( result = 0; offsize > 0; offsize-- )
+ {
+ result <<= 8;
+ result |= *p++;
+ }
+
+ *start = p;
+ return result;
+ }
+
+
+ FT_LOCAL_DEF( void )
+ cid_decrypt( FT_Byte* buffer,
+ FT_Offset length,
+ FT_UShort seed )
+ {
+ while ( length > 0 )
+ {
+ FT_Byte plain;
+
+
+ plain = (FT_Byte)( *buffer ^ ( seed >> 8 ) );
+ seed = (FT_UShort)( ( *buffer + seed ) * 52845U + 22719 );
+ *buffer++ = plain;
+ length--;
+ }
+ }
+
+
+ /*************************************************************************/
+ /*************************************************************************/
+ /***** *****/
+ /***** TYPE 1 SYMBOL PARSING *****/
+ /***** *****/
+ /*************************************************************************/
+ /*************************************************************************/
+
+
+ static FT_Error
+ cid_load_keyword( CID_Face face,
+ CID_Loader* loader,
+ const T1_Field keyword )
+ {
+ FT_Error error;
+ CID_Parser* parser = &loader->parser;
+ FT_Byte* object;
+ void* dummy_object;
+ CID_FaceInfo cid = &face->cid;
+
+
+ /* if the keyword has a dedicated callback, call it */
+ if ( keyword->type == T1_FIELD_TYPE_CALLBACK )
+ {
+ keyword->reader( (FT_Face)face, parser );
+ error = parser->root.error;
+ goto Exit;
+ }
+
+ /* we must now compute the address of our target object */
+ switch ( keyword->location )
+ {
+ case T1_FIELD_LOCATION_CID_INFO:
+ object = (FT_Byte*)cid;
+ break;
+
+ case T1_FIELD_LOCATION_FONT_INFO:
+ object = (FT_Byte*)&cid->font_info;
+ break;
+
+ default:
+ {
+ CID_FaceDict dict;
+
+
+ if ( parser->num_dict < 0 )
+ {
+ FT_ERROR(( "cid_load_keyword: invalid use of `%s'!\n",
+ keyword->ident ));
+ error = CID_Err_Syntax_Error;
+ goto Exit;
+ }
+
+ dict = cid->font_dicts + parser->num_dict;
+ switch ( keyword->location )
+ {
+ case T1_FIELD_LOCATION_PRIVATE:
+ object = (FT_Byte*)&dict->private_dict;
+ break;
+
+ default:
+ object = (FT_Byte*)dict;
+ }
+ }
+ }
+
+ dummy_object = object;
+
+ /* now, load the keyword data in the object's field(s) */
+ if ( keyword->type == T1_FIELD_TYPE_INTEGER_ARRAY ||
+ keyword->type == T1_FIELD_TYPE_FIXED_ARRAY )
+ error = cid_parser_load_field_table( &loader->parser, keyword,
+ &dummy_object );
+ else
+ error = cid_parser_load_field( &loader->parser, keyword, &dummy_object );
+ Exit:
+ return error;
+ }
+
+
+ FT_CALLBACK_DEF( FT_Error )
+ parse_font_bbox( CID_Face face,
+ CID_Parser* parser )
+ {
+ FT_Fixed temp[4];
+ FT_BBox* bbox = &face->cid.font_bbox;
+
+
+ (void)cid_parser_to_fixed_array( parser, 4, temp, 0 );
+ bbox->xMin = FT_RoundFix( temp[0] );
+ bbox->yMin = FT_RoundFix( temp[1] );
+ bbox->xMax = FT_RoundFix( temp[2] );
+ bbox->yMax = FT_RoundFix( temp[3] );
+
+ return CID_Err_Ok; /* this is a callback function; */
+ /* we must return an error code */
+ }
+
+
+ FT_CALLBACK_DEF( FT_Error )
+ parse_font_matrix( CID_Face face,
+ CID_Parser* parser )
+ {
+ FT_Matrix* matrix;
+ FT_Vector* offset;
+ CID_FaceDict dict;
+ FT_Face root = (FT_Face)&face->root;
+ FT_Fixed temp[6];
+ FT_Fixed temp_scale;
+
+
+ if ( parser->num_dict >= 0 )
+ {
+ dict = face->cid.font_dicts + parser->num_dict;
+ matrix = &dict->font_matrix;
+ offset = &dict->font_offset;
+
+ (void)cid_parser_to_fixed_array( parser, 6, temp, 3 );
+
+ temp_scale = ABS( temp[3] );
+
+ /* Set Units per EM based on FontMatrix values. We set the value to */
+ /* `1000/temp_scale', because temp_scale was already multiplied by */
+ /* 1000 (in t1_tofixed(), from psobjs.c). */
+ root->units_per_EM = (FT_UShort)( FT_DivFix( 0x10000L,
+ FT_DivFix( temp_scale, 1000 ) ) );
+
+ /* we need to scale the values by 1.0/temp[3] */
+ if ( temp_scale != 0x10000L )
+ {
+ temp[0] = FT_DivFix( temp[0], temp_scale );
+ temp[1] = FT_DivFix( temp[1], temp_scale );
+ temp[2] = FT_DivFix( temp[2], temp_scale );
+ temp[4] = FT_DivFix( temp[4], temp_scale );
+ temp[5] = FT_DivFix( temp[5], temp_scale );
+ temp[3] = 0x10000L;
+ }
+
+ matrix->xx = temp[0];
+ matrix->yx = temp[1];
+ matrix->xy = temp[2];
+ matrix->yy = temp[3];
+
+ /* note that the font offsets are expressed in integer font units */
+ offset->x = temp[4] >> 16;
+ offset->y = temp[5] >> 16;
+ }
+
+ return CID_Err_Ok; /* this is a callback function; */
+ /* we must return an error code */
+ }
+
+
+ FT_CALLBACK_DEF( FT_Error )
+ parse_fd_array( CID_Face face,
+ CID_Parser* parser )
+ {
+ CID_FaceInfo cid = &face->cid;
+ FT_Memory memory = face->root.memory;
+ FT_Error error = CID_Err_Ok;
+ FT_Long num_dicts;
+
+
+ num_dicts = cid_parser_to_int( parser );
+
+ if ( !cid->font_dicts )
+ {
+ FT_Int n;
+
+
+ if ( FT_NEW_ARRAY( cid->font_dicts, num_dicts ) )
+ goto Exit;
+
+ cid->num_dicts = (FT_UInt)num_dicts;
+
+ /* don't forget to set a few defaults */
+ for ( n = 0; n < cid->num_dicts; n++ )
+ {
+ CID_FaceDict dict = cid->font_dicts + n;
+
+
+ /* default value for lenIV */
+ dict->private_dict.lenIV = 4;
+ }
+ }
+
+ Exit:
+ return error;
+ }
+
+
+ static
+ const T1_FieldRec cid_field_records[] =
+ {
+
+#include "cidtoken.h"
+
+ T1_FIELD_CALLBACK( "FontBBox", parse_font_bbox )
+ T1_FIELD_CALLBACK( "FDArray", parse_fd_array )
+ T1_FIELD_CALLBACK( "FontMatrix", parse_font_matrix )
+ { 0, T1_FIELD_LOCATION_CID_INFO, T1_FIELD_TYPE_NONE, 0, 0, 0, 0, 0 }
+ };
+
+
+ static int
+ is_alpha( char c )
+ {
+ return ( ft_isalnum( (int)c ) ||
+ c == '.' ||
+ c == '_' );
+ }
+
+
+ static FT_Error
+ cid_parse_dict( CID_Face face,
+ CID_Loader* loader,
+ FT_Byte* base,
+ FT_Long size )
+ {
+ CID_Parser* parser = &loader->parser;
+
+
+ parser->root.cursor = base;
+ parser->root.limit = base + size;
+ parser->root.error = 0;
+
+ {
+ FT_Byte* cur = base;
+ FT_Byte* limit = cur + size;
+
+
+ for ( ;cur < limit; cur++ )
+ {
+ /* look for `%ADOBeginFontDict' */
+ if ( *cur == '%' && cur + 20 < limit &&
+ ft_strncmp( (char*)cur, "%ADOBeginFontDict", 17 ) == 0 )
+ {
+ cur += 17;
+
+ /* if /FDArray was found, then cid->num_dicts is > 0, and */
+ /* we can start increasing parser->num_dict */
+ if ( face->cid.num_dicts > 0 )
+ parser->num_dict++;
+ }
+ /* look for immediates */
+ else if ( *cur == '/' && cur + 2 < limit )
+ {
+ FT_Byte* cur2;
+ FT_Int len;
+
+
+ cur++;
+
+ cur2 = cur;
+ while ( cur2 < limit && is_alpha( *cur2 ) )
+ cur2++;
+
+ len = (FT_Int)( cur2 - cur );
+ if ( len > 0 && len < 22 )
+ {
+ /* now compare the immediate name to the keyword table */
+ T1_Field keyword = (T1_Field) cid_field_records;
+
+
+ for (;;)
+ {
+ FT_Byte* name;
+
+
+ name = (FT_Byte*)keyword->ident;
+ if ( !name )
+ break;
+
+ if ( cur[0] == name[0] &&
+ len == (FT_Int)ft_strlen( (const char*)name ) )
+ {
+ FT_Int n;
+
+
+ for ( n = 1; n < len; n++ )
+ if ( cur[n] != name[n] )
+ break;
+
+ if ( n >= len )
+ {
+ /* we found it - run the parsing callback */
+ parser->root.cursor = cur2;
+ cid_parser_skip_spaces( parser );
+ parser->root.error = cid_load_keyword( face,
+ loader,
+ keyword );
+ if ( parser->root.error )
+ return parser->root.error;
+
+ cur = parser->root.cursor;
+ break;
+ }
+ }
+ keyword++;
+ }
+ }
+ }
+ }
+ }
+ return parser->root.error;
+ }
+
+
+ /* read the subrmap and the subrs of each font dict */
+ static FT_Error
+ cid_read_subrs( CID_Face face )
+ {
+ CID_FaceInfo cid = &face->cid;
+ FT_Memory memory = face->root.memory;
+ FT_Stream stream = face->root.stream;
+ FT_Error error;
+ FT_Int n;
+ CID_Subrs subr;
+ FT_UInt max_offsets = 0;
+ FT_ULong* offsets = 0;
+
+
+ if ( FT_NEW_ARRAY( face->subrs, cid->num_dicts ) )
+ goto Exit;
+
+ subr = face->subrs;
+ for ( n = 0; n < cid->num_dicts; n++, subr++ )
+ {
+ CID_FaceDict dict = cid->font_dicts + n;
+ FT_Int lenIV = dict->private_dict.lenIV;
+ FT_UInt count, num_subrs = dict->num_subrs;
+ FT_ULong data_len;
+ FT_Byte* p;
+
+
+ /* reallocate offsets array if needed */
+ if ( num_subrs + 1 > max_offsets )
+ {
+ FT_UInt new_max = ( num_subrs + 1 + 3 ) & -4;
+
+
+ if ( FT_RENEW_ARRAY( offsets, max_offsets, new_max ) )
+ goto Fail;
+
+ max_offsets = new_max;
+ }
+
+ /* read the subrmap's offsets */
+ if ( FT_STREAM_SEEK( cid->data_offset + dict->subrmap_offset ) ||
+ FT_FRAME_ENTER( ( num_subrs + 1 ) * dict->sd_bytes ) )
+ goto Fail;
+
+ p = (FT_Byte*)stream->cursor;
+ for ( count = 0; count <= num_subrs; count++ )
+ offsets[count] = cid_get_offset( &p, (FT_Byte)dict->sd_bytes );
+
+ FT_FRAME_EXIT();
+
+ /* now, compute the size of subrs charstrings, */
+ /* allocate, and read them */
+ data_len = offsets[num_subrs] - offsets[0];
+
+ if ( FT_NEW_ARRAY( subr->code, num_subrs + 1 ) ||
+ FT_ALLOC( subr->code[0], data_len ) )
+ goto Fail;
+
+ if ( FT_STREAM_SEEK( cid->data_offset + offsets[0] ) ||
+ FT_STREAM_READ( subr->code[0], data_len ) )
+ goto Fail;
+
+ /* set up pointers */
+ for ( count = 1; count <= num_subrs; count++ )
+ {
+ FT_ULong len;
+
+
+ len = offsets[count] - offsets[count - 1];
+ subr->code[count] = subr->code[count - 1] + len;
+ }
+
+ /* decrypt subroutines, but only if lenIV >= 0 */
+ if ( lenIV >= 0 )
+ {
+ for ( count = 0; count < num_subrs; count++ )
+ {
+ FT_ULong len;
+
+
+ len = offsets[count + 1] - offsets[count];
+ cid_decrypt( subr->code[count], len, 4330 );
+ }
+ }
+
+ subr->num_subrs = num_subrs;
+ }
+
+ Exit:
+ FT_FREE( offsets );
+ return error;
+
+ Fail:
+ if ( face->subrs )
+ {
+ for ( n = 0; n < cid->num_dicts; n++ )
+ {
+ if ( face->subrs[n].code )
+ FT_FREE( face->subrs[n].code[0] );
+
+ FT_FREE( face->subrs[n].code );
+ }
+ FT_FREE( face->subrs );
+ }
+ goto Exit;
+ }
+
+
+ static void
+ t1_init_loader( CID_Loader* loader,
+ CID_Face face )
+ {
+ FT_UNUSED( face );
+
+ FT_MEM_ZERO( loader, sizeof ( *loader ) );
+ }
+
+
+ static void
+ t1_done_loader( CID_Loader* loader )
+ {
+ CID_Parser* parser = &loader->parser;
+
+
+ /* finalize parser */
+ cid_parser_done( parser );
+ }
+
+
+ FT_LOCAL_DEF( FT_Error )
+ cid_face_open( CID_Face face )
+ {
+ CID_Loader loader;
+ CID_Parser* parser;
+ FT_Error error;
+
+
+ t1_init_loader( &loader, face );
+
+ parser = &loader.parser;
+ error = cid_parser_new( parser, face->root.stream, face->root.memory,
+ (PSAux_Service)face->psaux );
+ if ( error )
+ goto Exit;
+
+ error = cid_parse_dict( face, &loader,
+ parser->postscript,
+ parser->postscript_len );
+ if ( error )
+ goto Exit;
+
+ face->cid.data_offset = loader.parser.data_offset;
+ error = cid_read_subrs( face );
+
+ Exit:
+ t1_done_loader( &loader );
+ return error;
+ }
+
+
+/* END */
--- /dev/null
+++ b/libfreetype/cidload.h
@@ -1,0 +1,57 @@
+/***************************************************************************/
+/* */
+/* cidload.h */
+/* */
+/* CID-keyed Type1 font loader (specification). */
+/* */
+/* Copyright 1996-2001, 2002 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+
+#ifndef __CIDLOAD_H__
+#define __CIDLOAD_H__
+
+
+#include <ft2build.h>
+#include FT_INTERNAL_STREAM_H
+#include "cidparse.h"
+
+
+FT_BEGIN_HEADER
+
+
+ typedef struct CID_Loader_
+ {
+ CID_Parser parser; /* parser used to read the stream */
+ FT_Int num_chars; /* number of characters in encoding */
+
+ } CID_Loader;
+
+
+ FT_LOCAL( FT_Long )
+ cid_get_offset( FT_Byte** start,
+ FT_Byte offsize );
+
+ FT_LOCAL( void )
+ cid_decrypt( FT_Byte* buffer,
+ FT_Offset length,
+ FT_UShort seed );
+
+ FT_LOCAL( FT_Error )
+ cid_face_open( CID_Face face );
+
+
+FT_END_HEADER
+
+#endif /* __CIDLOAD_H__ */
+
+
+/* END */
--- /dev/null
+++ b/libfreetype/cidobjs.c
@@ -1,0 +1,448 @@
+/***************************************************************************/
+/* */
+/* cidobjs.c */
+/* */
+/* CID objects manager (body). */
+/* */
+/* Copyright 1996-2001, 2002 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+
+#include <ft2build.h>
+#include FT_INTERNAL_DEBUG_H
+#include FT_INTERNAL_STREAM_H
+#include "cidgload.h"
+#include "cidload.h"
+#include FT_INTERNAL_POSTSCRIPT_NAMES_H
+#include FT_INTERNAL_POSTSCRIPT_AUX_H
+#include FT_INTERNAL_POSTSCRIPT_HINTS_H
+
+#include "ciderrs.h"
+
+
+ /*************************************************************************/
+ /* */
+ /* The macro FT_COMPONENT is used in trace mode. It is an implicit */
+ /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log */
+ /* messages during execution. */
+ /* */
+#undef FT_COMPONENT
+#define FT_COMPONENT trace_cidobjs
+
+
+ /*************************************************************************/
+ /* */
+ /* SLOT FUNCTIONS */
+ /* */
+ /*************************************************************************/
+
+ FT_LOCAL_DEF( void )
+ cid_slot_done( CID_GlyphSlot slot )
+ {
+ slot->root.internal->glyph_hints = 0;
+ }
+
+
+ FT_LOCAL_DEF( FT_Error )
+ cid_slot_init( CID_GlyphSlot slot )
+ {
+ CID_Face face;
+ PSHinter_Service pshinter;
+
+
+ face = (CID_Face)slot->root.face;
+ pshinter = (PSHinter_Service)face->pshinter;
+
+ if ( pshinter )
+ {
+ FT_Module module;
+
+
+ module = FT_Get_Module( slot->root.face->driver->root.library,
+ "pshinter" );
+ if ( module )
+ {
+ T1_Hints_Funcs funcs;
+
+
+ funcs = pshinter->get_t1_funcs( module );
+ slot->root.internal->glyph_hints = (void*)funcs;
+ }
+ }
+
+ return 0;
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* SIZE FUNCTIONS */
+ /* */
+ /*************************************************************************/
+
+
+ static PSH_Globals_Funcs
+ cid_size_get_globals_funcs( CID_Size size )
+ {
+ CID_Face face = (CID_Face)size->root.face;
+ PSHinter_Service pshinter = (PSHinter_Service)face->pshinter;
+ FT_Module module;
+
+
+ module = FT_Get_Module( size->root.face->driver->root.library,
+ "pshinter" );
+ return ( module && pshinter && pshinter->get_globals_funcs )
+ ? pshinter->get_globals_funcs( module )
+ : 0;
+ }
+
+
+ FT_LOCAL_DEF( void )
+ cid_size_done( CID_Size size )
+ {
+ if ( size->root.internal )
+ {
+ PSH_Globals_Funcs funcs;
+
+
+ funcs = cid_size_get_globals_funcs( size );
+ if ( funcs )
+ funcs->destroy( (PSH_Globals)size->root.internal );
+
+ size->root.internal = 0;
+ }
+ }
+
+
+ FT_LOCAL_DEF( FT_Error )
+ cid_size_init( CID_Size size )
+ {
+ FT_Error error = 0;
+ PSH_Globals_Funcs funcs = cid_size_get_globals_funcs( size );
+
+
+ if ( funcs )
+ {
+ PSH_Globals globals;
+ CID_Face face = (CID_Face)size->root.face;
+ CID_FaceDict dict = face->cid.font_dicts + face->root.face_index;
+ PS_Private priv = &dict->private_dict;
+
+
+ error = funcs->create( size->root.face->memory, priv, &globals );
+ if ( !error )
+ size->root.internal = (FT_Size_Internal)(void*)globals;
+ }
+
+ return error;
+ }
+
+
+ FT_LOCAL_DEF( FT_Error )
+ cid_size_reset( CID_Size size )
+ {
+ PSH_Globals_Funcs funcs = cid_size_get_globals_funcs( size );
+ FT_Error error = 0;
+
+
+ if ( funcs )
+ error = funcs->set_scale( (PSH_Globals)size->root.internal,
+ size->root.metrics.x_scale,
+ size->root.metrics.y_scale,
+ 0, 0 );
+ return error;
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* FACE FUNCTIONS */
+ /* */
+ /*************************************************************************/
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* cid_face_done */
+ /* */
+ /* <Description> */
+ /* Finalizes a given face object. */
+ /* */
+ /* <Input> */
+ /* face :: A pointer to the face object to destroy. */
+ /* */
+ FT_LOCAL_DEF( void )
+ cid_face_done( CID_Face face )
+ {
+ FT_Memory memory;
+
+
+ if ( face )
+ {
+ CID_FaceInfo cid = &face->cid;
+ PS_FontInfo info = &cid->font_info;
+
+
+ memory = face->root.memory;
+
+ /* release subrs */
+ if ( face->subrs )
+ {
+ FT_Int n;
+
+
+ for ( n = 0; n < cid->num_dicts; n++ )
+ {
+ CID_Subrs subr = face->subrs + n;
+
+
+ if ( subr->code )
+ {
+ FT_FREE( subr->code[0] );
+ FT_FREE( subr->code );
+ }
+ }
+
+ FT_FREE( face->subrs );
+ }
+
+ /* release FontInfo strings */
+ FT_FREE( info->version );
+ FT_FREE( info->notice );
+ FT_FREE( info->full_name );
+ FT_FREE( info->family_name );
+ FT_FREE( info->weight );
+
+ /* release font dictionaries */
+ FT_FREE( cid->font_dicts );
+ cid->num_dicts = 0;
+
+ /* release other strings */
+ FT_FREE( cid->cid_font_name );
+ FT_FREE( cid->registry );
+ FT_FREE( cid->ordering );
+
+ face->root.family_name = 0;
+ face->root.style_name = 0;
+ }
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* cid_face_init */
+ /* */
+ /* <Description> */
+ /* Initializes a given CID face object. */
+ /* */
+ /* <Input> */
+ /* stream :: The source font stream. */
+ /* */
+ /* face_index :: The index of the font face in the resource. */
+ /* */
+ /* num_params :: Number of additional generic parameters. Ignored. */
+ /* */
+ /* params :: Additional generic parameters. Ignored. */
+ /* */
+ /* <InOut> */
+ /* face :: The newly built face object. */
+ /* */
+ /* <Return> */
+ /* FreeType error code. 0 means success. */
+ /* */
+ FT_LOCAL_DEF( FT_Error )
+ cid_face_init( FT_Stream stream,
+ CID_Face face,
+ FT_Int face_index,
+ FT_Int num_params,
+ FT_Parameter* params )
+ {
+ FT_Error error;
+ PSNames_Service psnames;
+ PSAux_Service psaux;
+ PSHinter_Service pshinter;
+
+ FT_UNUSED( num_params );
+ FT_UNUSED( params );
+ FT_UNUSED( face_index );
+ FT_UNUSED( stream );
+
+
+ face->root.num_faces = 1;
+
+ psnames = (PSNames_Service)face->psnames;
+ if ( !psnames )
+ {
+ psnames = (PSNames_Service)FT_Get_Module_Interface(
+ FT_FACE_LIBRARY( face ), "psnames" );
+
+ face->psnames = psnames;
+ }
+
+ psaux = (PSAux_Service)face->psaux;
+ if ( !psaux )
+ {
+ psaux = (PSAux_Service)FT_Get_Module_Interface(
+ FT_FACE_LIBRARY( face ), "psaux" );
+
+ face->psaux = psaux;
+ }
+
+ pshinter = (PSHinter_Service)face->pshinter;
+ if ( !pshinter )
+ {
+ pshinter = (PSHinter_Service)FT_Get_Module_Interface(
+ FT_FACE_LIBRARY( face ), "pshinter" );
+
+ face->pshinter = pshinter;
+ }
+
+ /* open the tokenizer; this will also check the font format */
+ if ( FT_STREAM_SEEK( 0 ) )
+ goto Exit;
+
+ error = cid_face_open( face );
+ if ( error )
+ goto Exit;
+
+ /* if we just wanted to check the format, leave successfully now */
+ if ( face_index < 0 )
+ goto Exit;
+
+ /* check the face index */
+ if ( face_index != 0 )
+ {
+ FT_ERROR(( "cid_face_init: invalid face index\n" ));
+ error = CID_Err_Invalid_Argument;
+ goto Exit;
+ }
+
+ /* Now, load the font program into the face object */
+ {
+ /* Init the face object fields */
+ /* Now set up root face fields */
+ {
+ FT_Face root = (FT_Face)&face->root;
+
+
+ root->num_glyphs = face->cid.cid_count;
+ root->num_charmaps = 0;
+
+ root->face_index = face_index;
+ root->face_flags = FT_FACE_FLAG_SCALABLE;
+
+ root->face_flags |= FT_FACE_FLAG_HORIZONTAL;
+
+ if ( face->cid.font_info.is_fixed_pitch )
+ root->face_flags |= FT_FACE_FLAG_FIXED_WIDTH;
+
+ /* XXX: TODO: add kerning with .afm support */
+
+ /* get style name -- be careful, some broken fonts only */
+ /* have a /FontName dictionary entry! */
+ root->family_name = face->cid.font_info.family_name;
+ if ( root->family_name )
+ {
+ char* full = face->cid.font_info.full_name;
+ char* family = root->family_name;
+
+ while ( *family && *full == *family )
+ {
+ family++;
+ full++;
+ }
+
+ root->style_name = ( *full == ' ' ) ? full + 1
+ : (char *)"Regular";
+ }
+ else
+ {
+ /* do we have a `/FontName'? */
+ if ( face->cid.cid_font_name )
+ {
+ root->family_name = face->cid.cid_font_name;
+ root->style_name = (char *)"Regular";
+ }
+ }
+
+ /* no embedded bitmap support */
+ root->num_fixed_sizes = 0;
+ root->available_sizes = 0;
+
+ root->bbox.xMin = face->cid.font_bbox.xMin >> 16;
+ root->bbox.yMin = face->cid.font_bbox.yMin >> 16;
+ root->bbox.xMax = ( face->cid.font_bbox.xMax + 0xFFFFU ) >> 16;
+ root->bbox.yMax = ( face->cid.font_bbox.yMax + 0xFFFFU ) >> 16;
+
+ if ( !root->units_per_EM )
+ root->units_per_EM = 1000;
+
+ root->ascender = (FT_Short)( root->bbox.yMax );
+ root->descender = (FT_Short)( root->bbox.yMin );
+ root->height = (FT_Short)(
+ ( ( root->ascender + root->descender ) * 12 ) / 10 );
+
+ root->underline_position = face->cid.font_info.underline_position;
+ root->underline_thickness = face->cid.font_info.underline_thickness;
+
+ root->internal->max_points = 0;
+ root->internal->max_contours = 0;
+ }
+ }
+
+ Exit:
+ return error;
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* cid_driver_init */
+ /* */
+ /* <Description> */
+ /* Initializes a given CID driver object. */
+ /* */
+ /* <Input> */
+ /* driver :: A handle to the target driver object. */
+ /* */
+ /* <Return> */
+ /* FreeType error code. 0 means success. */
+ /* */
+ FT_LOCAL_DEF( FT_Error )
+ cid_driver_init( CID_Driver driver )
+ {
+ FT_UNUSED( driver );
+
+ return CID_Err_Ok;
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* cid_driver_done */
+ /* */
+ /* <Description> */
+ /* Finalizes a given CID driver. */
+ /* */
+ /* <Input> */
+ /* driver :: A handle to the target CID driver. */
+ /* */
+ FT_LOCAL_DEF( void )
+ cid_driver_done( CID_Driver driver )
+ {
+ FT_UNUSED( driver );
+ }
+
+
+/* END */
--- /dev/null
+++ b/libfreetype/cidobjs.h
@@ -1,0 +1,158 @@
+/***************************************************************************/
+/* */
+/* cidobjs.h */
+/* */
+/* CID objects manager (specification). */
+/* */
+/* Copyright 1996-2001, 2002 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+
+#ifndef __CIDOBJS_H__
+#define __CIDOBJS_H__
+
+
+#include <ft2build.h>
+#include FT_INTERNAL_OBJECTS_H
+#include FT_CONFIG_CONFIG_H
+#include FT_INTERNAL_TYPE1_TYPES_H
+
+
+FT_BEGIN_HEADER
+
+
+ /* The following structures must be defined by the hinter */
+ typedef struct CID_Size_Hints_ CID_Size_Hints;
+ typedef struct CID_Glyph_Hints_ CID_Glyph_Hints;
+
+
+ /*************************************************************************/
+ /* */
+ /* <Type> */
+ /* CID_Driver */
+ /* */
+ /* <Description> */
+ /* A handle to a Type 1 driver object. */
+ /* */
+ typedef struct CID_DriverRec_* CID_Driver;
+
+
+ /*************************************************************************/
+ /* */
+ /* <Type> */
+ /* CID_Size */
+ /* */
+ /* <Description> */
+ /* A handle to a Type 1 size object. */
+ /* */
+ typedef struct CID_SizeRec_* CID_Size;
+
+
+ /*************************************************************************/
+ /* */
+ /* <Type> */
+ /* CID_GlyphSlot */
+ /* */
+ /* <Description> */
+ /* A handle to a Type 1 glyph slot object. */
+ /* */
+ typedef struct CID_GlyphSlotRec_* CID_GlyphSlot;
+
+
+ /*************************************************************************/
+ /* */
+ /* <Type> */
+ /* CID_CharMap */
+ /* */
+ /* <Description> */
+ /* A handle to a Type 1 character mapping object. */
+ /* */
+ /* <Note> */
+ /* The Type 1 format doesn't use a charmap but an encoding table. */
+ /* The driver is responsible for making up charmap objects */
+ /* corresponding to these tables. */
+ /* */
+ typedef struct CID_CharMapRec_* CID_CharMap;
+
+
+ /*************************************************************************/
+ /* */
+ /* HERE BEGINS THE TYPE 1 SPECIFIC STUFF */
+ /* */
+ /*************************************************************************/
+
+
+ typedef struct CID_SizeRec_
+ {
+ FT_SizeRec root;
+ FT_Bool valid;
+
+ } CID_SizeRec;
+
+
+ typedef struct CID_GlyphSlotRec_
+ {
+ FT_GlyphSlotRec root;
+
+ FT_Bool hint;
+ FT_Bool scaled;
+
+ FT_Fixed x_scale;
+ FT_Fixed y_scale;
+
+ } CID_GlyphSlotRec;
+
+
+ FT_LOCAL( void )
+ cid_slot_done( CID_GlyphSlot slot );
+
+ FT_LOCAL( FT_Error )
+ cid_slot_init( CID_GlyphSlot slot );
+
+
+ FT_LOCAL( void )
+ cid_size_done( CID_Size size );
+
+
+ FT_LOCAL( FT_Error )
+ cid_size_init( CID_Size size );
+
+
+ FT_LOCAL( FT_Error )
+ cid_size_reset( CID_Size size );
+
+
+ FT_LOCAL( FT_Error )
+ cid_face_init( FT_Stream stream,
+ CID_Face face,
+ FT_Int face_index,
+ FT_Int num_params,
+ FT_Parameter* params );
+
+
+ FT_LOCAL( void )
+ cid_face_done( CID_Face face );
+
+
+ FT_LOCAL( FT_Error )
+ cid_driver_init( CID_Driver driver );
+
+
+ FT_LOCAL( void )
+ cid_driver_done( CID_Driver driver );
+
+
+FT_END_HEADER
+
+#endif /* __CIDOBJS_H__ */
+
+
+/* END */
--- /dev/null
+++ b/libfreetype/cidparse.c
@@ -1,0 +1,155 @@
+/***************************************************************************/
+/* */
+/* cidparse.c */
+/* */
+/* CID-keyed Type1 parser (body). */
+/* */
+/* Copyright 1996-2001, 2002 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+
+#include <ft2build.h>
+#include FT_INTERNAL_DEBUG_H
+#include FT_INTERNAL_CALC_H
+#include FT_INTERNAL_OBJECTS_H
+#include FT_INTERNAL_STREAM_H
+
+#include "cidparse.h"
+
+#include "ciderrs.h"
+
+
+ /*************************************************************************/
+ /* */
+ /* The macro FT_COMPONENT is used in trace mode. It is an implicit */
+ /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log */
+ /* messages during execution. */
+ /* */
+#undef FT_COMPONENT
+#define FT_COMPONENT trace_cidparse
+
+
+ /*************************************************************************/
+ /*************************************************************************/
+ /*************************************************************************/
+ /***** *****/
+ /***** INPUT STREAM PARSER *****/
+ /***** *****/
+ /*************************************************************************/
+ /*************************************************************************/
+ /*************************************************************************/
+
+
+ FT_LOCAL_DEF( FT_Error )
+ cid_parser_new( CID_Parser* parser,
+ FT_Stream stream,
+ FT_Memory memory,
+ PSAux_Service psaux )
+ {
+ FT_Error error;
+ FT_ULong base_offset, offset, ps_len;
+ FT_Byte buffer[256 + 10];
+ FT_Int buff_len;
+
+
+ FT_MEM_ZERO( parser, sizeof ( *parser ) );
+ psaux->ps_parser_funcs->init( &parser->root, 0, 0, memory );
+
+ parser->stream = stream;
+
+ base_offset = FT_STREAM_POS();
+
+ /* first of all, check the font format in the header */
+ if ( FT_FRAME_ENTER( 31 ) )
+ goto Exit;
+
+ if ( ft_strncmp( (char *)stream->cursor,
+ "%!PS-Adobe-3.0 Resource-CIDFont", 31 ) )
+ {
+ FT_TRACE2(( "[not a valid CID-keyed font]\n" ));
+ error = CID_Err_Unknown_File_Format;
+ }
+
+ FT_FRAME_EXIT();
+ if ( error )
+ goto Exit;
+
+ /* now, read the rest of the file, until we find a `StartData' */
+ buff_len = 256;
+ for (;;)
+ {
+ FT_Byte *p, *limit = buffer + 256;
+ FT_ULong top_position;
+
+
+ /* fill input buffer */
+ buff_len -= 256;
+ if ( buff_len > 0 )
+ FT_MEM_MOVE( buffer, limit, buff_len );
+
+ p = buffer + buff_len;
+
+ if ( FT_STREAM_READ( p, 256 + 10 - buff_len ) )
+ goto Exit;
+
+ top_position = FT_STREAM_POS() - buff_len;
+ buff_len = 256 + 10;
+
+ /* look for `StartData' */
+ for ( p = buffer; p < limit; p++ )
+ {
+ if ( p[0] == 'S' && ft_strncmp( (char*)p, "StartData", 9 ) == 0 )
+ {
+ /* save offset of binary data after `StartData' */
+ offset = (FT_ULong)( top_position - ( limit - p ) + 10 );
+ goto Found;
+ }
+ }
+ }
+
+ Found:
+ /* we have found the start of the binary data. We will now */
+ /* rewind and extract the frame of corresponding to the Postscript */
+ /* section */
+
+ ps_len = offset - base_offset;
+ if ( FT_STREAM_SEEK( base_offset ) ||
+ FT_FRAME_EXTRACT( ps_len, parser->postscript ) )
+ goto Exit;
+
+ parser->data_offset = offset;
+ parser->postscript_len = ps_len;
+ parser->root.base = parser->postscript;
+ parser->root.cursor = parser->postscript;
+ parser->root.limit = parser->root.cursor + ps_len;
+ parser->num_dict = -1;
+
+ Exit:
+ return error;
+ }
+
+
+ FT_LOCAL_DEF( void )
+ cid_parser_done( CID_Parser* parser )
+ {
+ /* always free the private dictionary */
+ if ( parser->postscript )
+ {
+ FT_Stream stream = parser->stream;
+
+
+ FT_FRAME_RELEASE( parser->postscript );
+ }
+ parser->root.funcs.done( &parser->root );
+ }
+
+
+/* END */
--- /dev/null
+++ b/libfreetype/cidparse.h
@@ -1,0 +1,116 @@
+/***************************************************************************/
+/* */
+/* cidparse.h */
+/* */
+/* CID-keyed Type1 parser (specification). */
+/* */
+/* Copyright 1996-2001, 2002 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+
+#ifndef __CIDPARSE_H__
+#define __CIDPARSE_H__
+
+
+#include <ft2build.h>
+#include FT_INTERNAL_TYPE1_TYPES_H
+#include FT_INTERNAL_STREAM_H
+#include FT_INTERNAL_POSTSCRIPT_AUX_H
+
+
+FT_BEGIN_HEADER
+
+
+ /*************************************************************************/
+ /* */
+ /* <Struct> */
+ /* CID_Parser */
+ /* */
+ /* <Description> */
+ /* A CID_Parser is an object used to parse a Type 1 fonts very */
+ /* quickly. */
+ /* */
+ /* <Fields> */
+ /* root :: The root PS_ParserRec fields. */
+ /* */
+ /* stream :: The current input stream. */
+ /* */
+ /* postscript :: A pointer to the data to be parsed. */
+ /* */
+ /* postscript_len :: The length of the data to be parsed. */
+ /* */
+ /* data_offset :: The start position of the binary data (i.e., the */
+ /* end of the data to be parsed. */
+ /* */
+ /* cid :: A structure which holds the information about */
+ /* the current font. */
+ /* */
+ /* num_dict :: The number of font dictionaries. */
+ /* */
+ typedef struct CID_Parser_
+ {
+ PS_ParserRec root;
+ FT_Stream stream;
+
+ FT_Byte* postscript;
+ FT_Long postscript_len;
+
+ FT_ULong data_offset;
+
+ CID_FaceInfo cid;
+ FT_Int num_dict;
+
+ } CID_Parser;
+
+
+ FT_LOCAL( FT_Error )
+ cid_parser_new( CID_Parser* parser,
+ FT_Stream stream,
+ FT_Memory memory,
+ PSAux_Service psaux );
+
+ FT_LOCAL( void )
+ cid_parser_done( CID_Parser* parser );
+
+
+ /*************************************************************************/
+ /* */
+ /* PARSING ROUTINES */
+ /* */
+ /*************************************************************************/
+
+#define cid_parser_skip_spaces( p ) (p)->root.funcs.skip_spaces( &(p)->root )
+#define cid_parser_skip_alpha( p ) (p)->root.funcs.skip_alpha ( &(p)->root )
+
+#define cid_parser_to_int( p ) (p)->root.funcs.to_int( &(p)->root )
+#define cid_parser_to_fixed( p, t ) (p)->root.funcs.to_fixed( &(p)->root, t )
+
+#define cid_parser_to_coord_array( p, m, c ) \
+ (p)->root.funcs.to_coord_array( &(p)->root, m, c )
+#define cid_parser_to_fixed_array( p, m, f, t ) \
+ (p)->root.funcs.to_fixed_array( &(p)->root, m, f, t )
+#define cid_parser_to_token( p, t ) \
+ (p)->root.funcs.to_token( &(p)->root, t )
+#define cid_parser_to_token_array( p, t, m, c ) \
+ (p)->root.funcs.to_token_array( &(p)->root, t, m, c )
+
+#define cid_parser_load_field( p, f, o ) \
+ (p)->root.funcs.load_field( &(p)->root, f, o, 0, 0 )
+#define cid_parser_load_field_table( p, f, o ) \
+ (p)->root.funcs.load_field_table( &(p)->root, f, o, 0, 0 )
+
+
+FT_END_HEADER
+
+#endif /* __CIDPARSE_H__ */
+
+
+/* END */
--- /dev/null
+++ b/libfreetype/cidriver.c
@@ -1,0 +1,113 @@
+/***************************************************************************/
+/* */
+/* cidriver.c */
+/* */
+/* CID driver interface (body). */
+/* */
+/* Copyright 1996-2001, 2002 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+
+#include <ft2build.h>
+#include "cidriver.h"
+#include "cidgload.h"
+#include FT_INTERNAL_DEBUG_H
+#include FT_INTERNAL_STREAM_H
+#include FT_INTERNAL_POSTSCRIPT_NAMES_H
+
+#include "ciderrs.h"
+
+
+ /*************************************************************************/
+ /* */
+ /* The macro FT_COMPONENT is used in trace mode. It is an implicit */
+ /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log */
+ /* messages during execution. */
+ /* */
+#undef FT_COMPONENT
+#define FT_COMPONENT trace_ciddriver
+
+
+ static const char*
+ cid_get_postscript_name( CID_Face face )
+ {
+ const char* result = face->cid.cid_font_name;
+
+
+ if ( result && result[0] == '/' )
+ result++;
+
+ return result;
+ }
+
+
+ static FT_Module_Interface
+ cid_get_interface( FT_Driver driver,
+ const FT_String* cid_interface )
+ {
+ FT_UNUSED( driver );
+ FT_UNUSED( cid_interface );
+
+ if ( ft_strcmp( (const char*)cid_interface, "postscript_name" ) == 0 )
+ return (FT_Module_Interface)cid_get_postscript_name;
+
+ return 0;
+ }
+
+
+
+ FT_CALLBACK_TABLE_DEF
+ const FT_Driver_ClassRec t1cid_driver_class =
+ {
+ /* first of all, the FT_Module_Class fields */
+ {
+ ft_module_font_driver |
+ ft_module_driver_scalable |
+ ft_module_driver_has_hinter ,
+
+ sizeof( FT_DriverRec ),
+ "t1cid", /* module name */
+ 0x10000L, /* version 1.0 of driver */
+ 0x20000L, /* requires FreeType 2.0 */
+
+ 0,
+
+ (FT_Module_Constructor)cid_driver_init,
+ (FT_Module_Destructor) cid_driver_done,
+ (FT_Module_Requester) cid_get_interface
+ },
+
+ /* then the other font drivers fields */
+ sizeof( CID_FaceRec ),
+ sizeof( CID_SizeRec ),
+ sizeof( CID_GlyphSlotRec ),
+
+ (FT_Face_InitFunc) cid_face_init,
+ (FT_Face_DoneFunc) cid_face_done,
+
+ (FT_Size_InitFunc) cid_size_init,
+ (FT_Size_DoneFunc) cid_size_done,
+ (FT_Slot_InitFunc) cid_slot_init,
+ (FT_Slot_DoneFunc) cid_slot_done,
+
+ (FT_Size_ResetPointsFunc)cid_size_reset,
+ (FT_Size_ResetPixelsFunc)cid_size_reset,
+
+ (FT_Slot_LoadFunc) cid_slot_load_glyph,
+
+ (FT_Face_GetKerningFunc) 0,
+ (FT_Face_AttachFunc) 0,
+
+ (FT_Face_GetAdvancesFunc)0,
+ };
+
+
+/* END */
--- /dev/null
+++ b/libfreetype/cidriver.h
@@ -1,0 +1,39 @@
+/***************************************************************************/
+/* */
+/* cidriver.h */
+/* */
+/* High-level CID driver interface (specification). */
+/* */
+/* Copyright 1996-2001, 2002 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+
+#ifndef __CIDRIVER_H__
+#define __CIDRIVER_H__
+
+
+#include <ft2build.h>
+#include FT_INTERNAL_DRIVER_H
+
+
+FT_BEGIN_HEADER
+
+
+ FT_CALLBACK_TABLE
+ const FT_Driver_ClassRec t1cid_driver_class;
+
+
+FT_END_HEADER
+
+#endif /* __CIDRIVER_H__ */
+
+
+/* END */
--- /dev/null
+++ b/libfreetype/cidtoken.h
@@ -1,0 +1,96 @@
+/***************************************************************************/
+/* */
+/* cidtoken.h */
+/* */
+/* CID token definitions (specification only). */
+/* */
+/* Copyright 1996-2001, 2002 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+
+#undef FT_STRUCTURE
+#define FT_STRUCTURE CID_FaceInfoRec
+#undef T1CODE
+#define T1CODE T1_FIELD_LOCATION_CID_INFO
+
+ T1_FIELD_STRING( "CIDFontName", cid_font_name )
+ T1_FIELD_NUM ( "CIDFontVersion", cid_version )
+ T1_FIELD_NUM ( "CIDFontType", cid_font_type )
+ T1_FIELD_STRING( "Registry", registry )
+ T1_FIELD_STRING( "Ordering", ordering )
+ T1_FIELD_NUM ( "Supplement", supplement )
+ T1_FIELD_NUM ( "UIDBase", uid_base )
+ T1_FIELD_NUM ( "CIDMapOffset", cidmap_offset )
+ T1_FIELD_NUM ( "FDBytes", fd_bytes )
+ T1_FIELD_NUM ( "GDBytes", gd_bytes )
+ T1_FIELD_NUM ( "CIDCount", cid_count )
+
+
+#undef FT_STRUCTURE
+#define FT_STRUCTURE PS_FontInfoRec
+#undef T1CODE
+#define T1CODE T1_FIELD_LOCATION_FONT_INFO
+
+ T1_FIELD_STRING ( "version", version )
+ T1_FIELD_STRING ( "Notice", notice )
+ T1_FIELD_STRING ( "FullName", full_name )
+ T1_FIELD_STRING ( "FamilyName", family_name )
+ T1_FIELD_STRING ( "Weight", weight )
+ T1_FIELD_FIXED ( "ItalicAngle", italic_angle )
+ T1_FIELD_TYPE_BOOL( "isFixedPitch", is_fixed_pitch )
+ T1_FIELD_NUM ( "UnderlinePosition", underline_position )
+ T1_FIELD_NUM ( "UnderlineThickness", underline_thickness )
+
+
+#undef FT_STRUCTURE
+#define FT_STRUCTURE CID_FaceDictRec
+#undef T1CODE
+#define T1CODE T1_FIELD_LOCATION_FONT_DICT
+
+ T1_FIELD_NUM ( "PaintType", paint_type )
+ T1_FIELD_NUM ( "FontType", font_type )
+ T1_FIELD_NUM ( "SubrMapOffset", subrmap_offset )
+ T1_FIELD_NUM ( "SDBytes", sd_bytes )
+ T1_FIELD_NUM ( "SubrCount", num_subrs )
+ T1_FIELD_NUM ( "lenBuildCharArray", len_buildchar )
+ T1_FIELD_FIXED( "ForceBoldThreshold", forcebold_threshold )
+ T1_FIELD_FIXED( "ExpansionFactor", expansion_factor )
+ T1_FIELD_NUM ( "StrokeWidth", stroke_width )
+
+
+#undef FT_STRUCTURE
+#define FT_STRUCTURE PS_PrivateRec
+#undef T1CODE
+#define T1CODE T1_FIELD_LOCATION_PRIVATE
+
+ T1_FIELD_NUM ( "UniqueID", unique_id )
+ T1_FIELD_NUM ( "lenIV", lenIV )
+ T1_FIELD_NUM ( "LanguageGroup", language_group )
+ T1_FIELD_NUM ( "password", password )
+
+ T1_FIELD_FIXED ( "BlueScale", blue_scale )
+ T1_FIELD_NUM ( "BlueShift", blue_shift )
+ T1_FIELD_NUM ( "BlueFuzz", blue_fuzz )
+
+ T1_FIELD_NUM_TABLE ( "BlueValues", blue_values, 14 )
+ T1_FIELD_NUM_TABLE ( "OtherBlues", other_blues, 10 )
+ T1_FIELD_NUM_TABLE ( "FamilyBlues", family_blues, 14 )
+ T1_FIELD_NUM_TABLE ( "FamilyOtherBlues", family_other_blues, 10 )
+
+ T1_FIELD_NUM_TABLE2( "StdHW", standard_width, 1 )
+ T1_FIELD_NUM_TABLE2( "StdVW", standard_height, 1 )
+ T1_FIELD_NUM_TABLE2( "MinFeature", min_feature, 2 )
+
+ T1_FIELD_NUM_TABLE ( "StemSnapH", snap_widths, 12 )
+ T1_FIELD_NUM_TABLE ( "StemSnapV", snap_heights, 12 )
+
+
+/* END */
--- /dev/null
+++ b/libfreetype/fnterrs.h
@@ -1,0 +1,41 @@
+/***************************************************************************/
+/* */
+/* fnterrs.h */
+/* */
+/* Win FNT/FON error codes (specification only). */
+/* */
+/* Copyright 2001 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+
+ /*************************************************************************/
+ /* */
+ /* This file is used to define the Windows FNT/FON error enumeration */
+ /* constants. */
+ /* */
+ /*************************************************************************/
+
+#ifndef __FNTERRS_H__
+#define __FNTERRS_H__
+
+#include FT_MODULE_ERRORS_H
+
+#undef __FTERRORS_H__
+
+#define FT_ERR_PREFIX FNT_Err_
+#define FT_ERR_BASE FT_Mod_Err_Winfonts
+
+#include FT_ERRORS_H
+
+#endif /* __FNTERRS_H__ */
+
+
+/* END */
--- /dev/null
+++ b/libfreetype/freetype.c
@@ -1,0 +1,134 @@
+#include "freetype/freetype.h"
+#include "freetype.h"
+
+static char* fterrstr(int);
+
+char*
+ftnewface(char *path, int index, FTface *f, FTfaceinfo *finfo)
+{
+ FT_Library ft_lib;
+ FT_Face ft_face;
+ char *err;
+
+ err = fterrstr(FT_Init_FreeType(&ft_lib));
+ if (err != nil)
+ return err;
+
+ err = fterrstr(FT_New_Face(ft_lib, path, index, &ft_face));
+ if (err != nil) {
+ FT_Done_FreeType(ft_lib);
+ return err;
+ }
+
+ f->ft_lib = ft_lib;
+ f->ft_face = ft_face;
+ finfo->nfaces = ft_face->num_faces;
+ finfo->index = ft_face->face_index;
+ finfo->style = ft_face->style_flags;
+ finfo->height = (FT_MulFix(ft_face->height, ft_face->size->metrics.y_scale)+32)/64;
+ finfo->ascent = (FT_MulFix(ft_face->ascender, ft_face->size->metrics.y_scale)+32)/64;
+ finfo->familyname = ft_face->family_name;
+ finfo->stylename = ft_face->style_name;
+ return nil;
+}
+
+char*
+ftloadmemface(void *buf, int nbytes, int index, FTface *f, FTfaceinfo *finfo)
+{
+ USED(buf);
+ USED(f);
+ USED(finfo);
+ return "not implemented";
+}
+
+char*
+ftsetcharsize(FTface f, int pt, int hdpi, int vdpi, FTfaceinfo *finfo)
+{
+ FT_Face ft_face = f.ft_face;
+ char *err;
+
+ err = fterrstr(FT_Set_Char_Size(ft_face, 0, pt, hdpi, vdpi));
+ if (err != nil)
+ return err;
+ finfo->height = (FT_MulFix(ft_face->height, ft_face->size->metrics.y_scale)+32)/64;
+ finfo->ascent = (FT_MulFix(ft_face->ascender, ft_face->size->metrics.y_scale)+32)/64;
+ return nil;
+}
+
+void
+ftsettransform(FTface f, FTmatrix *m, FTvector *v)
+{
+ /* FTMatrix and FTVector are compatible with FT_Matrix and FT_Vector */
+ FT_Set_Transform(f.ft_face, (FT_Matrix*)m, (FT_Vector*)v);
+}
+
+int
+fthaschar(FTface f, int c)
+{
+ return FT_Get_Char_Index(f.ft_face, c) != 0;
+}
+
+char*
+ftloadglyph(FTface f, int ix, FTglyph *g)
+{
+ FT_Face ft_face = f.ft_face;
+ FT_GlyphSlot ft_glyph;
+ char *err;
+
+ ix = FT_Get_Char_Index(ft_face, ix);
+ err = fterrstr(FT_Load_Glyph(ft_face, ix, FT_LOAD_NO_BITMAP|FT_LOAD_RENDER|FT_LOAD_CROP_BITMAP));
+ if (err != nil)
+ return err;
+
+ ft_glyph = ft_face->glyph;
+ g->top = ft_glyph->bitmap_top;
+ g->left = ft_glyph->bitmap_left;
+ g->height = ft_glyph->bitmap.rows;
+ g->width = ft_glyph->bitmap.width;
+ g->advx = ft_glyph->advance.x;
+ g->advy = ft_glyph->advance.y;
+ g->bpr = ft_glyph->bitmap.pitch;
+ g->bitmap = ft_glyph->bitmap.buffer;
+ return nil;
+}
+
+void
+ftdoneface(FTface f)
+{
+ if (f.ft_face != nil)
+ FT_Done_Face(f.ft_face);
+ if (f.ft_lib != nil)
+ FT_Done_FreeType(f.ft_lib);
+}
+
+/*
+ * get the freetype error strings
+ */
+
+typedef struct FTerr FTerr;
+struct FTerr {
+ int code;
+ char* text;
+};
+
+#define FT_NOERRORDEF_(l,c,t)
+#define FT_ERRORDEF_(l,c,t) c,t,
+
+static FTerr fterrs[] = {
+#include "freetype/fterrdef.h"
+ -1, "",
+};
+
+static char*
+fterrstr(int code)
+{
+ int i;
+ if (code == 0)
+ return nil;
+ for (i = 0; fterrs[i].code > 0; i++) {
+ if (fterrs[i].code == code)
+ return fterrs[i].text;
+ }
+ return "unknown FreeType error";
+}
+
--- /dev/null
+++ b/libfreetype/ftapi.c
@@ -1,0 +1,121 @@
+/***************************************************************************/
+/* */
+/* ftapi.c */
+/* */
+/* The FreeType compatibility functions (body). */
+/* */
+/* Copyright 2002 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+
+#include <ft2build.h>
+#include FT_LIST_H
+#include FT_OUTLINE_H
+#include FT_INTERNAL_OBJECTS_H
+#include FT_INTERNAL_DEBUG_H
+#include FT_INTERNAL_STREAM_H
+#include FT_TRUETYPE_TABLES_H
+#include FT_OUTLINE_H
+
+
+ /*************************************************************************/
+ /*************************************************************************/
+ /*************************************************************************/
+ /**** ****/
+ /**** ****/
+ /**** C O M P A T I B I L I T Y ****/
+ /**** ****/
+ /**** ****/
+ /*************************************************************************/
+ /*************************************************************************/
+ /*************************************************************************/
+
+ /* backwards compatibility API */
+
+ FT_BASE_DEF( void )
+ FT_New_Memory_Stream( FT_Library library,
+ FT_Byte* base,
+ FT_ULong size,
+ FT_Stream stream )
+ {
+ FT_UNUSED( library );
+
+ FT_Stream_OpenMemory( stream, base, size );
+ }
+
+
+ FT_BASE_DEF( FT_Error )
+ FT_Seek_Stream( FT_Stream stream,
+ FT_ULong pos )
+ {
+ return FT_Stream_Seek( stream, pos );
+ }
+
+
+ FT_BASE_DEF( FT_Error )
+ FT_Skip_Stream( FT_Stream stream,
+ FT_Long distance )
+ {
+ return FT_Stream_Skip( stream, distance );
+ }
+
+
+ FT_BASE_DEF( FT_Error )
+ FT_Read_Stream( FT_Stream stream,
+ FT_Byte* buffer,
+ FT_ULong count )
+ {
+ return FT_Stream_Read( stream, buffer, count );
+ }
+
+
+ FT_BASE_DEF( FT_Error )
+ FT_Read_Stream_At( FT_Stream stream,
+ FT_ULong pos,
+ FT_Byte* buffer,
+ FT_ULong count )
+ {
+ return FT_Stream_ReadAt( stream, pos, buffer, count );
+ }
+
+
+ FT_BASE_DEF( FT_Error )
+ FT_Extract_Frame( FT_Stream stream,
+ FT_ULong count,
+ FT_Byte** pbytes )
+ {
+ return FT_Stream_ExtractFrame( stream, count, pbytes );
+ }
+
+
+ FT_BASE_DEF( void )
+ FT_Release_Frame( FT_Stream stream,
+ FT_Byte** pbytes )
+ {
+ FT_Stream_ReleaseFrame( stream, pbytes );
+ }
+
+ FT_BASE_DEF( FT_Error )
+ FT_Access_Frame( FT_Stream stream,
+ FT_ULong count )
+ {
+ return FT_Stream_EnterFrame( stream, count );
+ }
+
+
+ FT_BASE_DEF( void )
+ FT_Forget_Frame( FT_Stream stream )
+ {
+ FT_Stream_ExitFrame( stream );
+ }
+
+
+/* END */
--- /dev/null
+++ b/libfreetype/ftbase.c
@@ -1,0 +1,34 @@
+/***************************************************************************/
+/* */
+/* ftbase.c */
+/* */
+/* Single object library component (body only). */
+/* */
+/* Copyright 1996-2001, 2002 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+
+#include <ft2build.h>
+
+#define FT_MAKE_OPTION_SINGLE_OBJECT
+
+#include "ftutil.c"
+#include "ftdbgmem.c"
+#include "ftstream.c"
+#include "ftcalc.c"
+#include "fttrigon.c"
+#include "ftoutln.c"
+#include "ftgloadr.c"
+#include "ftobjs.c"
+#include "ftnames.c"
+
+
+/* END */
--- /dev/null
+++ b/libfreetype/ftbbox.c
@@ -1,0 +1,653 @@
+/***************************************************************************/
+/* */
+/* ftbbox.c */
+/* */
+/* FreeType bbox computation (body). */
+/* */
+/* Copyright 1996-2001, 2002 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used */
+/* modified and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+
+ /*************************************************************************/
+ /* */
+ /* This component has a _single_ role: to compute exact outline bounding */
+ /* boxes. */
+ /* */
+ /*************************************************************************/
+
+
+#include <ft2build.h>
+#include FT_BBOX_H
+#include FT_IMAGE_H
+#include FT_OUTLINE_H
+#include FT_INTERNAL_CALC_H
+
+
+ typedef struct TBBox_Rec_
+ {
+ FT_Vector last;
+ FT_BBox bbox;
+
+ } TBBox_Rec;
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* BBox_Move_To */
+ /* */
+ /* <Description> */
+ /* This function is used as a `move_to' and `line_to' emitter during */
+ /* FT_Outline_Decompose(). It simply records the destination point */
+ /* in `user->last'; no further computations are necessary since we */
+ /* the cbox as the starting bbox which must be refined. */
+ /* */
+ /* <Input> */
+ /* to :: A pointer to the destination vector. */
+ /* */
+ /* <InOut> */
+ /* user :: A pointer to the current walk context. */
+ /* */
+ /* <Return> */
+ /* Always 0. Needed for the interface only. */
+ /* */
+ static int
+ BBox_Move_To( FT_Vector* to,
+ TBBox_Rec* user )
+ {
+ user->last = *to;
+
+ return 0;
+ }
+
+
+#define CHECK_X( p, bbox ) \
+ ( p->x < bbox.xMin || p->x > bbox.xMax )
+
+#define CHECK_Y( p, bbox ) \
+ ( p->y < bbox.yMin || p->y > bbox.yMax )
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* BBox_Conic_Check */
+ /* */
+ /* <Description> */
+ /* Finds the extrema of a 1-dimensional conic Bezier curve and update */
+ /* a bounding range. This version uses direct computation, as it */
+ /* doesn't need square roots. */
+ /* */
+ /* <Input> */
+ /* y1 :: The start coordinate. */
+ /* y2 :: The coordinate of the control point. */
+ /* y3 :: The end coordinate. */
+ /* */
+ /* <InOut> */
+ /* min :: The address of the current minimum. */
+ /* max :: The address of the current maximum. */
+ /* */
+ static void
+ BBox_Conic_Check( FT_Pos y1,
+ FT_Pos y2,
+ FT_Pos y3,
+ FT_Pos* min,
+ FT_Pos* max )
+ {
+ if ( y1 <= y3 )
+ {
+ if ( y2 == y1 ) /* Flat arc */
+ goto Suite;
+ }
+ else if ( y1 < y3 )
+ {
+ if ( y2 >= y1 && y2 <= y3 ) /* Ascending arc */
+ goto Suite;
+ }
+ else
+ {
+ if ( y2 >= y3 && y2 <= y1 ) /* Descending arc */
+ {
+ y2 = y1;
+ y1 = y3;
+ y3 = y2;
+ goto Suite;
+ }
+ }
+
+ y1 = y3 = y1 - FT_MulDiv( y2 - y1, y2 - y1, y1 - 2*y2 + y3 );
+
+ Suite:
+ if ( y1 < *min ) *min = y1;
+ if ( y3 > *max ) *max = y3;
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* BBox_Conic_To */
+ /* */
+ /* <Description> */
+ /* This function is used as a `conic_to' emitter during */
+ /* FT_Raster_Decompose(). It checks a conic Bezier curve with the */
+ /* current bounding box, and computes its extrema if necessary to */
+ /* update it. */
+ /* */
+ /* <Input> */
+ /* control :: A pointer to a control point. */
+ /* to :: A pointer to the destination vector. */
+ /* */
+ /* <InOut> */
+ /* user :: The address of the current walk context. */
+ /* */
+ /* <Return> */
+ /* Always 0. Needed for the interface only. */
+ /* */
+ /* <Note> */
+ /* In the case of a non-monotonous arc, we compute directly the */
+ /* extremum coordinates, as it is sufficiently fast. */
+ /* */
+ static int
+ BBox_Conic_To( FT_Vector* control,
+ FT_Vector* to,
+ TBBox_Rec* user )
+ {
+ /* we don't need to check `to' since it is always an `on' point, thus */
+ /* within the bbox */
+
+ if ( CHECK_X( control, user->bbox ) )
+
+ BBox_Conic_Check( user->last.x,
+ control->x,
+ to->x,
+ &user->bbox.xMin,
+ &user->bbox.xMax );
+
+ if ( CHECK_Y( control, user->bbox ) )
+
+ BBox_Conic_Check( user->last.y,
+ control->y,
+ to->y,
+ &user->bbox.yMin,
+ &user->bbox.yMax );
+
+ user->last = *to;
+
+ return 0;
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* BBox_Cubic_Check */
+ /* */
+ /* <Description> */
+ /* Finds the extrema of a 1-dimensional cubic Bezier curve and */
+ /* updates a bounding range. This version uses splitting because we */
+ /* don't want to use square roots and extra accuracies. */
+ /* */
+ /* <Input> */
+ /* p1 :: The start coordinate. */
+ /* p2 :: The coordinate of the first control point. */
+ /* p3 :: The coordinate of the second control point. */
+ /* p4 :: The end coordinate. */
+ /* */
+ /* <InOut> */
+ /* min :: The address of the current minimum. */
+ /* max :: The address of the current maximum. */
+ /* */
+#if 0
+ static void
+ BBox_Cubic_Check( FT_Pos p1,
+ FT_Pos p2,
+ FT_Pos p3,
+ FT_Pos p4,
+ FT_Pos* min,
+ FT_Pos* max )
+ {
+ FT_Pos stack[32*3 + 1], *arc;
+
+
+ arc = stack;
+
+ arc[0] = p1;
+ arc[1] = p2;
+ arc[2] = p3;
+ arc[3] = p4;
+
+ do
+ {
+ FT_Pos y1 = arc[0];
+ FT_Pos y2 = arc[1];
+ FT_Pos y3 = arc[2];
+ FT_Pos y4 = arc[3];
+
+
+ if ( y1 == y4 )
+ {
+ if ( y1 == y2 && y1 == y3 ) /* Flat */
+ goto Test;
+ }
+ else if ( y1 < y4 )
+ {
+ if ( y2 >= y1 && y2 <= y4 && y3 >= y1 && y3 <= y4 ) /* Ascending */
+ goto Test;
+ }
+ else
+ {
+ if ( y2 >= y4 && y2 <= y1 && y3 >= y4 && y3 <= y1 ) /* Descending */
+ {
+ y2 = y1;
+ y1 = y4;
+ y4 = y2;
+ goto Test;
+ }
+ }
+
+ /* Unknown direction -- split the arc in two */
+ arc[6] = y4;
+ arc[1] = y1 = ( y1 + y2 ) / 2;
+ arc[5] = y4 = ( y4 + y3 ) / 2;
+ y2 = ( y2 + y3 ) / 2;
+ arc[2] = y1 = ( y1 + y2 ) / 2;
+ arc[4] = y4 = ( y4 + y2 ) / 2;
+ arc[3] = ( y1 + y4 ) / 2;
+
+ arc += 3;
+ goto Suite;
+
+ Test:
+ if ( y1 < *min ) *min = y1;
+ if ( y4 > *max ) *max = y4;
+ arc -= 3;
+
+ Suite:
+ ;
+ } while ( arc >= stack );
+ }
+#else
+
+ static void
+ test_cubic_extrema( FT_Pos y1,
+ FT_Pos y2,
+ FT_Pos y3,
+ FT_Pos y4,
+ FT_Fixed u,
+ FT_Pos* min,
+ FT_Pos* max )
+ {
+ /* FT_Pos a = y4 - 3*y3 + 3*y2 - y1; */
+ FT_Pos b = y3 - 2*y2 + y1;
+ FT_Pos c = y2 - y1;
+ FT_Pos d = y1;
+ FT_Pos y;
+ FT_Fixed uu;
+
+ FT_UNUSED ( y4 );
+
+
+ /* The polynom is */
+ /* */
+ /* a*x^3 + 3b*x^2 + 3c*x + d . */
+ /* */
+ /* However, we also have */
+ /* */
+ /* dP/dx(u) = 0 , */
+ /* */
+ /* which implies that */
+ /* */
+ /* P(u) = b*u^2 + 2c*u + d */
+
+ if ( u > 0 && u < 0x10000L )
+ {
+ uu = FT_MulFix( u, u );
+ y = d + FT_MulFix( c, 2*u ) + FT_MulFix( b, uu );
+
+ if ( y < *min ) *min = y;
+ if ( y > *max ) *max = y;
+ }
+ }
+
+
+ static void
+ BBox_Cubic_Check( FT_Pos y1,
+ FT_Pos y2,
+ FT_Pos y3,
+ FT_Pos y4,
+ FT_Pos* min,
+ FT_Pos* max )
+ {
+ /* always compare first and last points */
+ if ( y1 < *min ) *min = y1;
+ else if ( y1 > *max ) *max = y1;
+
+ if ( y4 < *min ) *min = y4;
+ else if ( y4 > *max ) *max = y4;
+
+ /* now, try to see if there are split points here */
+ if ( y1 <= y4 )
+ {
+ /* flat or ascending arc test */
+ if ( y1 <= y2 && y2 <= y4 && y1 <= y3 && y3 <= y4 )
+ return;
+ }
+ else /* y1 > y4 */
+ {
+ /* descending arc test */
+ if ( y1 >= y2 && y2 >= y4 && y1 >= y3 && y3 >= y4 )
+ return;
+ }
+
+ /* There are some split points. Find them. */
+ {
+ FT_Pos a = y4 - 3*y3 + 3*y2 - y1;
+ FT_Pos b = y3 - 2*y2 + y1;
+ FT_Pos c = y2 - y1;
+ FT_Pos d;
+ FT_Fixed t;
+
+
+ /* We need to solve "ax^2+2bx+c" here, without floating points! */
+ /* The trick is to normalize to a different representation in order */
+ /* to use our 16.16 fixed point routines. */
+ /* */
+ /* We compute FT_MulFix(b,b) and FT_MulFix(a,c) after the */
+ /* the normalization. These values must fit into a single 16.16 */
+ /* value. */
+ /* */
+ /* We normalize a, b, and c to "8.16" fixed float values to ensure */
+ /* that their product is held in a "16.16" value. */
+ /* */
+ {
+ FT_ULong t1, t2;
+ int shift = 0;
+
+
+ /* Technical explanation of what's happening there. */
+ /* */
+ /* The following computation is based on the fact that for */
+ /* any value "y", if "n" is the position of the most */
+ /* significant bit of "abs(y)" (starting from 0 for the */
+ /* least significant bit), then y is in the range */
+ /* */
+ /* "-2^n..2^n-1" */
+ /* */
+ /* We want to shift "a", "b" and "c" concurrently in order */
+ /* to ensure that they all fit in 8.16 values, which maps */
+ /* to the integer range "-2^23..2^23-1". */
+ /* */
+ /* Necessarily, we need to shift "a", "b" and "c" so that */
+ /* the most significant bit of their absolute values is at */
+ /* _most_ at position 23. */
+ /* */
+ /* We begin by computing "t1" as the bitwise "or" of the */
+ /* absolute values of "a", "b", "c". */
+ /* */
+ t1 = (FT_ULong)((a >= 0) ? a : -a );
+ t2 = (FT_ULong)((b >= 0) ? b : -b );
+ t1 |= t2;
+ t2 = (FT_ULong)((c >= 0) ? c : -c );
+ t1 |= t2;
+
+ /* Now, the most significant bit of "t1" is sure to be the */
+ /* msb of one of "a", "b", "c", depending on which one is */
+ /* expressed in the greatest integer range. */
+ /* */
+ /* We now compute the "shift", by shifting "t1" as many */
+ /* times as necessary to move its msb to position 23. */
+ /* */
+ /* This corresponds to a value of t1 that is in the range */
+ /* 0x40_0000..0x7F_FFFF. */
+ /* */
+ /* Finally, we shift "a", "b" and "c" by the same amount. */
+ /* This ensures that all values are now in the range */
+ /* -2^23..2^23, i.e. that they are now expressed as 8.16 */
+ /* fixed float numbers. */
+ /* */
+ /* This also means that we are using 24 bits of precision */
+ /* to compute the zeros, independently of the range of */
+ /* the original polynom coefficients. */
+ /* */
+ /* This should ensure reasonably accurate values for the */
+ /* zeros. Note that the latter are only expressed with */
+ /* 16 bits when computing the extrema (the zeros need to */
+ /* be in 0..1 exclusive to be considered part of the arc). */
+ /* */
+ if ( t1 == 0 ) /* all coefficients are 0! */
+ return;
+
+ if ( t1 > 0x7FFFFFUL )
+ {
+ do
+ {
+ shift++;
+ t1 >>= 1;
+ } while ( t1 > 0x7FFFFFUL );
+
+ /* losing some bits of precision, but we use 24 of them */
+ /* for the computation anyway. */
+ a >>= shift;
+ b >>= shift;
+ c >>= shift;
+ }
+ else if ( t1 < 0x400000UL )
+ {
+ do
+ {
+ shift++;
+ t1 <<= 1;
+ } while ( t1 < 0x400000UL );
+
+ a <<= shift;
+ b <<= shift;
+ c <<= shift;
+ }
+ }
+
+ /* handle a == 0 */
+ if ( a == 0 )
+ {
+ if ( b != 0 )
+ {
+ t = - FT_DivFix( c, b ) / 2;
+ test_cubic_extrema( y1, y2, y3, y4, t, min, max );
+ }
+ }
+ else
+ {
+ /* solve the equation now */
+ d = FT_MulFix( b, b ) - FT_MulFix( a, c );
+ if ( d < 0 )
+ return;
+
+ if ( d == 0 )
+ {
+ /* there is a single split point at -b/a */
+ t = - FT_DivFix( b, a );
+ test_cubic_extrema( y1, y2, y3, y4, t, min, max );
+ }
+ else
+ {
+ /* there are two solutions; we need to filter them though */
+ d = FT_SqrtFixed( (FT_Int32)d );
+ t = - FT_DivFix( b - d, a );
+ test_cubic_extrema( y1, y2, y3, y4, t, min, max );
+
+ t = - FT_DivFix( b + d, a );
+ test_cubic_extrema( y1, y2, y3, y4, t, min, max );
+ }
+ }
+ }
+ }
+
+#endif
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* BBox_Cubic_To */
+ /* */
+ /* <Description> */
+ /* This function is used as a `cubic_to' emitter during */
+ /* FT_Raster_Decompose(). It checks a cubic Bezier curve with the */
+ /* current bounding box, and computes its extrema if necessary to */
+ /* update it. */
+ /* */
+ /* <Input> */
+ /* control1 :: A pointer to the first control point. */
+ /* control2 :: A pointer to the second control point. */
+ /* to :: A pointer to the destination vector. */
+ /* */
+ /* <InOut> */
+ /* user :: The address of the current walk context. */
+ /* */
+ /* <Return> */
+ /* Always 0. Needed for the interface only. */
+ /* */
+ /* <Note> */
+ /* In the case of a non-monotonous arc, we don't compute directly */
+ /* extremum coordinates, we subdivise instead. */
+ /* */
+ static int
+ BBox_Cubic_To( FT_Vector* control1,
+ FT_Vector* control2,
+ FT_Vector* to,
+ TBBox_Rec* user )
+ {
+ /* we don't need to check `to' since it is always an `on' point, thus */
+ /* within the bbox */
+
+ if ( CHECK_X( control1, user->bbox ) ||
+ CHECK_X( control2, user->bbox ) )
+
+ BBox_Cubic_Check( user->last.x,
+ control1->x,
+ control2->x,
+ to->x,
+ &user->bbox.xMin,
+ &user->bbox.xMax );
+
+ if ( CHECK_Y( control1, user->bbox ) ||
+ CHECK_Y( control2, user->bbox ) )
+
+ BBox_Cubic_Check( user->last.y,
+ control1->y,
+ control2->y,
+ to->y,
+ &user->bbox.yMin,
+ &user->bbox.yMax );
+
+ user->last = *to;
+
+ return 0;
+ }
+
+
+ /* documentation is in ftbbox.h */
+
+ FT_EXPORT_DEF( FT_Error )
+ FT_Outline_Get_BBox( FT_Outline* outline,
+ FT_BBox *abbox )
+ {
+ FT_BBox cbox;
+ FT_BBox bbox;
+ FT_Vector* vec;
+ FT_UShort n;
+
+
+ if ( !abbox )
+ return FT_Err_Invalid_Argument;
+
+ if ( !outline )
+ return FT_Err_Invalid_Outline;
+
+ /* if outline is empty, return (0,0,0,0) */
+ if ( outline->n_points == 0 || outline->n_contours <= 0 )
+ {
+ abbox->xMin = abbox->xMax = 0;
+ abbox->yMin = abbox->yMax = 0;
+ return 0;
+ }
+
+ /* We compute the control box as well as the bounding box of */
+ /* all `on' points in the outline. Then, if the two boxes */
+ /* coincide, we exit immediately. */
+
+ vec = outline->points;
+ bbox.xMin = bbox.xMax = cbox.xMin = cbox.xMax = vec->x;
+ bbox.yMin = bbox.yMax = cbox.yMin = cbox.yMax = vec->y;
+ vec++;
+
+ for ( n = 1; n < outline->n_points; n++ )
+ {
+ FT_Pos x = vec->x;
+ FT_Pos y = vec->y;
+
+
+ /* update control box */
+ if ( x < cbox.xMin ) cbox.xMin = x;
+ if ( x > cbox.xMax ) cbox.xMax = x;
+
+ if ( y < cbox.yMin ) cbox.yMin = y;
+ if ( y > cbox.yMax ) cbox.yMax = y;
+
+ if ( FT_CURVE_TAG( outline->tags[n] ) == FT_CURVE_TAG_ON )
+ {
+ /* update bbox for `on' points only */
+ if ( x < bbox.xMin ) bbox.xMin = x;
+ if ( x > bbox.xMax ) bbox.xMax = x;
+
+ if ( y < bbox.yMin ) bbox.yMin = y;
+ if ( y > bbox.yMax ) bbox.yMax = y;
+ }
+
+ vec++;
+ }
+
+ /* test two boxes for equality */
+ if ( cbox.xMin < bbox.xMin || cbox.xMax > bbox.xMax ||
+ cbox.yMin < bbox.yMin || cbox.yMax > bbox.yMax )
+ {
+ /* the two boxes are different, now walk over the outline to */
+ /* get the Bezier arc extrema. */
+
+ static const FT_Outline_Funcs bbox_interface =
+ {
+ (FT_Outline_MoveTo_Func) BBox_Move_To,
+ (FT_Outline_LineTo_Func) BBox_Move_To,
+ (FT_Outline_ConicTo_Func)BBox_Conic_To,
+ (FT_Outline_CubicTo_Func)BBox_Cubic_To,
+ 0, 0
+ };
+
+ FT_Error error;
+ TBBox_Rec user;
+
+
+ user.bbox = bbox;
+
+ error = FT_Outline_Decompose( outline, &bbox_interface, &user );
+ if ( error )
+ return error;
+
+ *abbox = user.bbox;
+ }
+ else
+ *abbox = bbox;
+
+ return FT_Err_Ok;
+ }
+
+
+/* END */
--- /dev/null
+++ b/libfreetype/ftbdf.c
@@ -1,0 +1,63 @@
+/***************************************************************************/
+/* */
+/* ftbdf.c */
+/* */
+/* FreeType API for accessing BDF-specific strings (body). */
+/* */
+/* Copyright 2002 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+
+#include <ft2build.h>
+#include FT_INTERNAL_BDF_TYPES_H
+#include FT_INTERNAL_OBJECTS_H
+
+
+ FT_EXPORT_DEF( FT_Error )
+ FT_Get_BDF_Charset_ID( FT_Face face,
+ const char* *acharset_encoding,
+ const char* *acharset_registry )
+ {
+ FT_Error error;
+ const char* encoding = NULL;
+ const char* registry = NULL;
+
+
+ error = FT_Err_Invalid_Argument;
+
+ if ( face != NULL && face->driver != NULL )
+ {
+ FT_Module driver = (FT_Module) face->driver;
+
+
+ if ( driver->clazz && driver->clazz->module_name &&
+ ft_strcmp( driver->clazz->module_name, "bdf" ) == 0 )
+ {
+ BDF_Public_Face bdf_face = (BDF_Public_Face)face;
+
+
+ encoding = (const char*) bdf_face->charset_encoding;
+ registry = (const char*) bdf_face->charset_registry;
+ error = 0;
+ }
+ }
+
+ if ( acharset_encoding )
+ *acharset_encoding = encoding;
+
+ if ( acharset_registry )
+ *acharset_registry = registry;
+
+ return error;
+ }
+
+
+/* END */
--- /dev/null
+++ b/libfreetype/ftcache.c
@@ -1,0 +1,31 @@
+/***************************************************************************/
+/* */
+/* ftcache.c */
+/* */
+/* The FreeType Caching sub-system (body only). */
+/* */
+/* Copyright 2000-2001 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+
+#define FT_MAKE_OPTION_SINGLE_OBJECT
+
+#include <ft2build.h>
+#include "ftlru.c"
+#include "ftcmanag.c"
+#include "ftccache.c"
+#include "ftcglyph.c"
+#include "ftcimage.c"
+#include "ftcsbits.c"
+#include "ftccmap.c"
+
+
+/* END */
--- /dev/null
+++ b/libfreetype/ftcalc.c
@@ -1,0 +1,561 @@
+/***************************************************************************/
+/* */
+/* ftcalc.c */
+/* */
+/* Arithmetic computations (body). */
+/* */
+/* Copyright 1996-2001, 2002 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+ /*************************************************************************/
+ /* */
+ /* Support for 1-complement arithmetic has been totally dropped in this */
+ /* release. You can still write your own code if you need it. */
+ /* */
+ /*************************************************************************/
+
+ /*************************************************************************/
+ /* */
+ /* Implementing basic computation routines. */
+ /* */
+ /* FT_MulDiv(), FT_MulFix(), FT_DivFix(), FT_RoundFix(), FT_CeilFix(), */
+ /* and FT_FloorFix() are declared in freetype.h. */
+ /* */
+ /*************************************************************************/
+
+
+#include <ft2build.h>
+#include FT_INTERNAL_CALC_H
+#include FT_INTERNAL_DEBUG_H
+#include FT_INTERNAL_OBJECTS_H
+
+
+/* we need to define a 64-bits data type here */
+
+#ifdef FT_LONG64
+
+ typedef FT_INT64 FT_Int64;
+
+#else
+
+ typedef struct FT_Int64_
+ {
+ FT_UInt32 lo;
+ FT_UInt32 hi;
+
+ } FT_Int64;
+
+#endif /* FT_LONG64 */
+
+
+ /*************************************************************************/
+ /* */
+ /* The macro FT_COMPONENT is used in trace mode. It is an implicit */
+ /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log */
+ /* messages during execution. */
+ /* */
+#undef FT_COMPONENT
+#define FT_COMPONENT trace_calc
+
+
+ /* The following three functions are available regardless of whether */
+ /* FT_LONG64 is defined. */
+
+ /* documentation is in freetype.h */
+
+ FT_EXPORT_DEF( FT_Fixed )
+ FT_RoundFix( FT_Fixed a )
+ {
+ return ( a >= 0 ) ? ( a + 0x8000L ) & -0x10000L
+ : -((-a + 0x8000L ) & -0x10000L );
+ }
+
+
+ /* documentation is in freetype.h */
+
+ FT_EXPORT_DEF( FT_Fixed )
+ FT_CeilFix( FT_Fixed a )
+ {
+ return ( a >= 0 ) ? ( a + 0xFFFFL ) & -0x10000L
+ : -((-a + 0xFFFFL ) & -0x10000L );
+ }
+
+
+ /* documentation is in freetype.h */
+
+ FT_EXPORT_DEF( FT_Fixed )
+ FT_FloorFix( FT_Fixed a )
+ {
+ return ( a >= 0 ) ? a & -0x10000L
+ : -((-a) & -0x10000L );
+ }
+
+
+ /* documentation is in ftcalc.h */
+
+ FT_EXPORT_DEF( FT_Int32 )
+ FT_Sqrt32( FT_Int32 x )
+ {
+ FT_ULong val, root, newroot, mask;
+
+
+ root = 0;
+ mask = 0x40000000L;
+ val = (FT_ULong)x;
+
+ do
+ {
+ newroot = root + mask;
+ if ( newroot <= val )
+ {
+ val -= newroot;
+ root = newroot + mask;
+ }
+
+ root >>= 1;
+ mask >>= 2;
+
+ } while ( mask != 0 );
+
+ return root;
+ }
+
+
+#ifdef FT_LONG64
+
+
+ /* documentation is in freetype.h */
+
+ FT_EXPORT_DEF( FT_Long )
+ FT_MulDiv( FT_Long a,
+ FT_Long b,
+ FT_Long c )
+ {
+ FT_Int s;
+ FT_Long d;
+
+
+ s = 1;
+ if ( a < 0 ) { a = -a; s = -1; }
+ if ( b < 0 ) { b = -b; s = -s; }
+ if ( c < 0 ) { c = -c; s = -s; }
+
+ d = (FT_Long)( c > 0 ? ( (FT_Int64)a * b + ( c >> 1 ) ) / c
+ : 0x7FFFFFFFL );
+
+ return ( s > 0 ) ? d : -d;
+ }
+
+
+ /* documentation is in freetype.h */
+
+ FT_EXPORT_DEF( FT_Long )
+ FT_MulFix( FT_Long a,
+ FT_Long b )
+ {
+ FT_Int s = 1;
+ FT_Long c;
+
+
+ if ( a < 0 ) { a = -a; s = -1; }
+ if ( b < 0 ) { b = -b; s = -s; }
+
+ c = (FT_Long)( ( (FT_Int64)a * b + 0x8000 ) >> 16 );
+ return ( s > 0 ) ? c : -c ;
+ }
+
+
+ /* documentation is in freetype.h */
+
+ FT_EXPORT_DEF( FT_Long )
+ FT_DivFix( FT_Long a,
+ FT_Long b )
+ {
+ FT_Int32 s;
+ FT_UInt32 q;
+
+ s = 1;
+ if ( a < 0 ) { a = -a; s = -1; }
+ if ( b < 0 ) { b = -b; s = -s; }
+
+ if ( b == 0 )
+ /* check for division by 0 */
+ q = 0x7FFFFFFFL;
+ else
+ /* compute result directly */
+ q = (FT_UInt32)( ( ( (FT_Int64)a << 16 ) + ( b >> 1 ) ) / b );
+
+ return ( s < 0 ? -(FT_Long)q : (FT_Long)q );
+ }
+
+
+#else /* FT_LONG64 */
+
+
+ static void
+ ft_multo64( FT_UInt32 x,
+ FT_UInt32 y,
+ FT_Int64 *z )
+ {
+ FT_UInt32 lo1, hi1, lo2, hi2, lo, hi, i1, i2;
+
+
+ lo1 = x & 0x0000FFFFU; hi1 = x >> 16;
+ lo2 = y & 0x0000FFFFU; hi2 = y >> 16;
+
+ lo = lo1 * lo2;
+ i1 = lo1 * hi2;
+ i2 = lo2 * hi1;
+ hi = hi1 * hi2;
+
+ /* Check carry overflow of i1 + i2 */
+ i1 += i2;
+ hi += (FT_UInt32)( i1 < i2 ) << 16;
+
+ hi += i1 >> 16;
+ i1 = i1 << 16;
+
+ /* Check carry overflow of i1 + lo */
+ lo += i1;
+ hi += ( lo < i1 );
+
+ z->lo = lo;
+ z->hi = hi;
+ }
+
+
+ static FT_UInt32
+ ft_div64by32( FT_UInt32 hi,
+ FT_UInt32 lo,
+ FT_UInt32 y )
+ {
+ FT_UInt32 r, q;
+ FT_Int i;
+
+
+ q = 0;
+ r = hi;
+
+ if ( r >= y )
+ return (FT_UInt32)0x7FFFFFFFL;
+
+ i = 32;
+ do
+ {
+ r <<= 1;
+ q <<= 1;
+ r |= lo >> 31;
+
+ if ( r >= (FT_UInt32)y )
+ {
+ r -= y;
+ q |= 1;
+ }
+ lo <<= 1;
+ } while ( --i );
+
+ return q;
+ }
+
+
+ /* documentation is in ftcalc.h */
+
+ FT_EXPORT_DEF( void )
+ FT_Add64( FT_Int64* x,
+ FT_Int64* y,
+ FT_Int64 *z )
+ {
+ register FT_UInt32 lo, hi, max;
+
+
+ max = x->lo > y->lo ? x->lo : y->lo;
+ lo = x->lo + y->lo;
+ hi = x->hi + y->hi + ( lo < max );
+
+ z->lo = lo;
+ z->hi = hi;
+ }
+
+
+ /* documentation is in freetype.h */
+
+ FT_EXPORT_DEF( FT_Long )
+ FT_MulDiv( FT_Long a,
+ FT_Long b,
+ FT_Long c )
+ {
+ long s;
+
+
+ if ( a == 0 || b == c )
+ return a;
+
+ s = a; a = ABS( a );
+ s ^= b; b = ABS( b );
+ s ^= c; c = ABS( c );
+
+ if ( a <= 46340L && b <= 46340L && c <= 176095L && c > 0 )
+ {
+ a = ( a * b + ( c >> 1 ) ) / c;
+ }
+ else if ( c > 0 )
+ {
+ FT_Int64 temp, temp2;
+
+
+ ft_multo64( a, b, &temp );
+
+ temp2.hi = 0;
+ temp2.lo = (FT_UInt32)(c >> 1);
+ FT_Add64( &temp, &temp2, &temp );
+ a = ft_div64by32( temp.hi, temp.lo, c );
+ }
+ else
+ a = 0x7FFFFFFFL;
+
+ return ( s < 0 ? -a : a );
+ }
+
+
+ /* documentation is in freetype.h */
+
+ FT_EXPORT_DEF( FT_Long )
+ FT_MulFix( FT_Long a,
+ FT_Long b )
+ {
+ FT_Long s;
+ FT_ULong ua, ub;
+
+
+ if ( a == 0 || b == 0x10000L )
+ return a;
+
+ s = a; a = ABS(a);
+ s ^= b; b = ABS(b);
+
+ ua = (FT_ULong)a;
+ ub = (FT_ULong)b;
+
+ if ( ua <= 2048 && ub <= 1048576L )
+ {
+ ua = ( ua * ub + 0x8000 ) >> 16;
+ }
+ else
+ {
+ FT_ULong al = ua & 0xFFFF;
+
+
+ ua = ( ua >> 16 ) * ub + al * ( ub >> 16 ) +
+ ( ( al * ( ub & 0xFFFF ) + 0x8000 ) >> 16 );
+ }
+
+ return ( s < 0 ? -(FT_Long)ua : (FT_Long)ua );
+ }
+
+
+ /* documentation is in freetype.h */
+
+ FT_EXPORT_DEF( FT_Long )
+ FT_DivFix( FT_Long a,
+ FT_Long b )
+ {
+ FT_Int32 s;
+ FT_UInt32 q;
+
+
+ s = a; a = ABS(a);
+ s ^= b; b = ABS(b);
+
+ if ( b == 0 )
+ {
+ /* check for division by 0 */
+ q = 0x7FFFFFFFL;
+ }
+ else if ( ( a >> 16 ) == 0 )
+ {
+ /* compute result directly */
+ q = (FT_UInt32)( (a << 16) + (b >> 1) ) / (FT_UInt32)b;
+ }
+ else
+ {
+ /* we need more bits; we have to do it by hand */
+ FT_Int64 temp, temp2;
+
+ temp.hi = (FT_Int32) (a >> 16);
+ temp.lo = (FT_UInt32)(a << 16);
+ temp2.hi = 0;
+ temp2.lo = (FT_UInt32)( b >> 1 );
+ FT_Add64( &temp, &temp2, &temp );
+ q = ft_div64by32( temp.hi, temp.lo, b );
+ }
+
+ return ( s < 0 ? -(FT_Int32)q : (FT_Int32)q );
+ }
+
+
+ /* documentation is in ftcalc.h */
+
+ FT_EXPORT_DEF( void )
+ FT_MulTo64( FT_Int32 x,
+ FT_Int32 y,
+ FT_Int64 *z )
+ {
+ FT_Int32 s;
+
+
+ s = x; x = ABS( x );
+ s ^= y; y = ABS( y );
+
+ ft_multo64( x, y, z );
+
+ if ( s < 0 )
+ {
+ z->lo = (FT_UInt32)-(FT_Int32)z->lo;
+ z->hi = ~z->hi + !( z->lo );
+ }
+ }
+
+
+ /* documentation is in ftcalc.h */
+
+ /* apparently, the second version of this code is not compiled correctly */
+ /* on Mac machines with the MPW C compiler.. tsss, tsss, tss... */
+
+#if 1
+
+ FT_EXPORT_DEF( FT_Int32 )
+ FT_Div64by32( FT_Int64* x,
+ FT_Int32 y )
+ {
+ FT_Int32 s;
+ FT_UInt32 q, r, i, lo;
+
+
+ s = x->hi;
+ if ( s < 0 )
+ {
+ x->lo = (FT_UInt32)-(FT_Int32)x->lo;
+ x->hi = ~x->hi + !x->lo;
+ }
+ s ^= y; y = ABS( y );
+
+ /* Shortcut */
+ if ( x->hi == 0 )
+ {
+ if ( y > 0 )
+ q = x->lo / y;
+ else
+ q = 0x7FFFFFFFL;
+
+ return ( s < 0 ? -(FT_Int32)q : (FT_Int32)q );
+ }
+
+ r = x->hi;
+ lo = x->lo;
+
+ if ( r >= (FT_UInt32)y ) /* we know y is to be treated as unsigned here */
+ return ( s < 0 ? 0x80000001UL : 0x7FFFFFFFUL );
+ /* Return Max/Min Int32 if division overflow. */
+ /* This includes division by zero! */
+ q = 0;
+ for ( i = 0; i < 32; i++ )
+ {
+ r <<= 1;
+ q <<= 1;
+ r |= lo >> 31;
+
+ if ( r >= (FT_UInt32)y )
+ {
+ r -= y;
+ q |= 1;
+ }
+ lo <<= 1;
+ }
+
+ return ( s < 0 ? -(FT_Int32)q : (FT_Int32)q );
+ }
+
+#else /* 0 */
+
+ FT_EXPORT_DEF( FT_Int32 )
+ FT_Div64by32( FT_Int64* x,
+ FT_Int32 y )
+ {
+ FT_Int32 s;
+ FT_UInt32 q;
+
+
+ s = x->hi;
+ if ( s < 0 )
+ {
+ x->lo = (FT_UInt32)-(FT_Int32)x->lo;
+ x->hi = ~x->hi + !x->lo;
+ }
+ s ^= y; y = ABS( y );
+
+ /* Shortcut */
+ if ( x->hi == 0 )
+ {
+ if ( y > 0 )
+ q = ( x->lo + ( y >> 1 ) ) / y;
+ else
+ q = 0x7FFFFFFFL;
+
+ return ( s < 0 ? -(FT_Int32)q : (FT_Int32)q );
+ }
+
+ q = ft_div64by32( x->hi, x->lo, y );
+
+ return ( s < 0 ? -(FT_Int32)q : (FT_Int32)q );
+ }
+
+#endif /* 0 */
+
+
+#endif /* FT_LONG64 */
+
+
+ /* a not-so-fast but working 16.16 fixed point square root function */
+
+ FT_EXPORT_DEF( FT_Int32 )
+ FT_SqrtFixed( FT_Int32 x )
+ {
+ FT_UInt32 root, rem_hi, rem_lo, test_div;
+ FT_Int count;
+
+
+ root = 0;
+
+ if ( x > 0 )
+ {
+ rem_hi = 0;
+ rem_lo = x;
+ count = 24;
+ do
+ {
+ rem_hi = ( rem_hi << 2 ) | ( rem_lo >> 30 );
+ rem_lo <<= 2;
+ root <<= 1;
+ test_div = ( root << 1 ) + 1;
+
+ if ( rem_hi >= test_div )
+ {
+ rem_hi -= test_div;
+ root += 1;
+ }
+ } while ( --count );
+ }
+
+ return (FT_Int32)root;
+ }
+
+
+/* END */
--- /dev/null
+++ b/libfreetype/ftccache.c
@@ -1,0 +1,714 @@
+/***************************************************************************/
+/* */
+/* ftccache.c */
+/* */
+/* The FreeType internal cache interface (body). */
+/* */
+/* Copyright 2000-2001, 2002 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+
+#include <ft2build.h>
+#include FT_CACHE_MANAGER_H
+#include FT_INTERNAL_OBJECTS_H
+#include FT_INTERNAL_DEBUG_H
+
+#include "ftcerror.h"
+
+
+#define FTC_HASH_MAX_LOAD 2
+#define FTC_HASH_MIN_LOAD 1
+#define FTC_HASH_SUB_LOAD ( FTC_HASH_MAX_LOAD - FTC_HASH_MIN_LOAD )
+
+/* this one _must_ be a power of 2! */
+#define FTC_HASH_INITIAL_SIZE 8
+
+
+ /*************************************************************************/
+ /*************************************************************************/
+ /***** *****/
+ /***** CACHE NODE DEFINITIONS *****/
+ /***** *****/
+ /*************************************************************************/
+ /*************************************************************************/
+
+ FT_EXPORT_DEF( void )
+ ftc_node_done( FTC_Node node,
+ FTC_Cache cache )
+ {
+ FTC_Family family;
+ FTC_FamilyEntry entry;
+
+
+ entry = cache->manager->families.entries + node->fam_index;
+ family = entry->family;
+
+ /* remove from parent set table - eventually destroy the set */
+ if ( --family->num_nodes == 0 )
+ FT_LruList_Remove( cache->families, (FT_LruNode) family );
+ }
+
+
+ /* add a new node to the head of the manager's circular MRU list */
+ static void
+ ftc_node_mru_link( FTC_Node node,
+ FTC_Manager manager )
+ {
+ FTC_Node first = manager->nodes_list;
+
+
+ if ( first )
+ {
+ FTC_Node last = first->mru_prev;
+
+
+ FT_ASSERT( last->mru_next == first );
+
+ node->mru_prev = last;
+ node->mru_next = first;
+
+ last->mru_next = node;
+ first->mru_prev = node;
+ }
+ else
+ {
+ FT_ASSERT( manager->num_nodes == 0 );
+
+ node->mru_next = node;
+ node->mru_prev = node;
+ }
+
+ manager->nodes_list = node;
+ manager->num_nodes++;
+ }
+
+
+ /* remove a node from the manager's MRU list */
+ static void
+ ftc_node_mru_unlink( FTC_Node node,
+ FTC_Manager manager )
+ {
+ FTC_Node first = manager->nodes_list;
+ FTC_Node prev = node->mru_prev;
+ FTC_Node next = node->mru_next;
+
+
+ FT_ASSERT( first != NULL && manager->num_nodes > 0 );
+ FT_ASSERT( next->mru_prev == node );
+ FT_ASSERT( prev->mru_next == node );
+
+ next->mru_prev = prev;
+ prev->mru_next = next;
+
+ if ( node == first )
+ {
+ /* this is the last node in the list; update its head pointer */
+ if ( node == next )
+ manager->nodes_list = NULL;
+ else
+ manager->nodes_list = next;
+ }
+
+ node->mru_next = NULL;
+ node->mru_prev = NULL;
+ manager->num_nodes--;
+ }
+
+
+ /* move a node to the head of the manager's MRU list */
+ static void
+ ftc_node_mru_up( FTC_Node node,
+ FTC_Manager manager )
+ {
+ FTC_Node first = manager->nodes_list;
+
+
+ if ( node != first )
+ {
+ FTC_Node prev = node->mru_prev;
+ FTC_Node next = node->mru_next;
+ FTC_Node last;
+
+
+ prev->mru_next = next;
+ next->mru_prev = prev;
+
+ last = first->mru_prev;
+ node->mru_next = first;
+ node->mru_prev = last;
+ first->mru_prev = node;
+ last->mru_next = node;
+
+ manager->nodes_list = node;
+ }
+ }
+
+
+ /* remove a node from its cache's hash table */
+ static FT_Error
+ ftc_node_hash_unlink( FTC_Node node,
+ FTC_Cache cache )
+ {
+ FT_Error error = 0;
+ FTC_Node *pnode;
+ FT_UInt idx, num_buckets;
+
+
+ idx = (FT_UInt)( node->hash & cache->mask );
+ if ( idx < cache->p )
+ idx = (FT_UInt)( node->hash & ( 2 * cache->mask + 1 ) );
+
+ pnode = cache->buckets + idx;
+
+ for (;;)
+ {
+ if ( *pnode == NULL )
+ {
+ FT_ERROR(( "ftc_node_hash_unlink: unknown node!\n" ));
+ return FT_Err_Ok;
+ }
+
+ if ( *pnode == node )
+ {
+ *pnode = node->link;
+ node->link = NULL;
+ break;
+ }
+
+ pnode = &(*pnode)->link;
+ }
+
+ num_buckets = ( cache->p + cache->mask + 1 );
+
+ if ( ++cache->slack > (FT_Long)num_buckets * FTC_HASH_SUB_LOAD )
+ {
+ FT_UInt p = cache->p;
+ FT_UInt mask = cache->mask;
+ FT_UInt old_index = p + mask;
+ FTC_Node* pold;
+
+
+ FT_ASSERT( old_index >= FTC_HASH_INITIAL_SIZE );
+
+ if ( p == 0 )
+ {
+ FT_Memory memory = cache->memory;
+
+
+ cache->mask >>= 1;
+ p = cache->mask;
+
+ if ( FT_RENEW_ARRAY( cache->buckets, ( mask + 1 ) * 2, (mask+1) ) )
+ {
+ FT_ERROR(( "ftc_node_hash_unlink: couldn't shunk buckets!\n" ));
+ goto Exit;
+ }
+ }
+ else
+ p--;
+
+ pnode = cache->buckets + p;
+ while ( *pnode )
+ pnode = &(*pnode)->link;
+
+ pold = cache->buckets + old_index;
+ *pnode = *pold;
+ *pold = NULL;
+
+ cache->slack -= FTC_HASH_MAX_LOAD;
+ cache->p = p;
+ }
+
+ Exit:
+ return error;
+ }
+
+
+
+ /* add a node to the "top" of its cache's hash table */
+ static FT_Error
+ ftc_node_hash_link( FTC_Node node,
+ FTC_Cache cache )
+ {
+ FTC_Node *pnode;
+ FT_UInt idx;
+ FT_Error error = 0;
+
+
+ idx = (FT_UInt)( node->hash & cache->mask );
+ if ( idx < cache->p )
+ idx = (FT_UInt)( node->hash & (2 * cache->mask + 1 ) );
+
+ pnode = cache->buckets + idx;
+
+ node->link = *pnode;
+ *pnode = node;
+
+ if ( --cache->slack < 0 )
+ {
+ FT_UInt p = cache->p;
+ FT_UInt mask = cache->mask;
+ FTC_Node new_list;
+
+
+ /* split a single bucket */
+ new_list = NULL;
+ pnode = cache->buckets + p;
+
+ for (;;)
+ {
+ node = *pnode;
+ if ( node == NULL )
+ break;
+
+ if ( node->hash & ( mask + 1 ) )
+ {
+ *pnode = node->link;
+ node->link = new_list;
+ new_list = node;
+ }
+ else
+ pnode = &node->link;
+ }
+
+ cache->buckets[p + mask + 1] = new_list;
+
+ cache->slack += FTC_HASH_MAX_LOAD;
+
+ if ( p >= mask )
+ {
+ FT_Memory memory = cache->memory;
+
+
+ if ( FT_RENEW_ARRAY( cache->buckets,
+ ( mask + 1 ) * 2, ( mask + 1 ) * 4 ) )
+ {
+ FT_ERROR(( "ftc_node_hash_link: couldn't expand buckets!\n" ));
+ goto Exit;
+ }
+
+ cache->mask = 2 * mask + 1;
+ cache->p = 0;
+ }
+ else
+ cache->p = p + 1;
+ }
+
+ Exit:
+ return error;
+ }
+
+
+
+
+ /* remove a node from the cache manager */
+ FT_EXPORT_DEF( void )
+ ftc_node_destroy( FTC_Node node,
+ FTC_Manager manager )
+ {
+ FT_Memory memory = manager->library->memory;
+ FTC_Cache cache;
+ FTC_FamilyEntry entry;
+ FTC_Cache_Class clazz;
+
+
+#ifdef FT_DEBUG_ERROR
+ /* find node's cache */
+ if ( node->fam_index >= manager->families.count )
+ {
+ FT_ERROR(( "ftc_node_destroy: invalid node handle\n" ));
+ return;
+ }
+#endif
+
+ entry = manager->families.entries + node->fam_index;
+ cache = entry->cache;
+
+#ifdef FT_DEBUG_ERROR
+ if ( cache == NULL )
+ {
+ FT_ERROR(( "ftc_node_destroy: invalid node handle\n" ));
+ return;
+ }
+#endif
+
+ clazz = cache->clazz;
+
+ manager->cur_weight -= clazz->node_weight( node, cache );
+
+ /* remove node from mru list */
+ ftc_node_mru_unlink( node, manager );
+
+ /* remove node from cache's hash table */
+ ftc_node_hash_unlink( node, cache );
+
+ /* now finalize it */
+ if ( clazz->node_done )
+ clazz->node_done( node, cache );
+
+ FT_FREE( node );
+
+ /* check, just in case of general corruption :-) */
+ if ( manager->num_nodes == 0 )
+ FT_ERROR(( "ftc_node_destroy: invalid cache node count! = %d\n",
+ manager->num_nodes ));
+ }
+
+
+ /*************************************************************************/
+ /*************************************************************************/
+ /***** *****/
+ /***** CACHE FAMILY DEFINITIONS *****/
+ /***** *****/
+ /*************************************************************************/
+ /*************************************************************************/
+
+
+ FT_EXPORT_DEF( FT_Error )
+ ftc_family_init( FTC_Family family,
+ FTC_Query query,
+ FTC_Cache cache )
+ {
+ FT_Error error;
+ FTC_Manager manager = cache->manager;
+ FT_Memory memory = manager->library->memory;
+ FTC_FamilyEntry entry;
+
+
+ family->cache = cache;
+ family->num_nodes = 0;
+
+ /* now add to manager's family table */
+ error = ftc_family_table_alloc( &manager->families, memory, &entry );
+ if ( !error )
+ {
+ entry->cache = cache;
+ entry->family = family;
+ family->fam_index = entry->index;
+
+ query->family = family; /* save family in query */
+ }
+
+ return error;
+ }
+
+
+ FT_EXPORT_DEF( void )
+ ftc_family_done( FTC_Family family )
+ {
+ FTC_Manager manager = family->cache->manager;
+
+
+ /* remove from manager's family table */
+ ftc_family_table_free( &manager->families, family->fam_index );
+ }
+
+
+ /*************************************************************************/
+ /*************************************************************************/
+ /***** *****/
+ /***** ABSTRACT CACHE CLASS *****/
+ /***** *****/
+ /*************************************************************************/
+ /*************************************************************************/
+
+
+
+ FT_EXPORT_DEF( FT_Error )
+ ftc_cache_init( FTC_Cache cache )
+ {
+ FT_Memory memory = cache->memory;
+ FTC_Cache_Class clazz = cache->clazz;
+ FT_Error error;
+
+
+ cache->p = 0;
+ cache->mask = FTC_HASH_INITIAL_SIZE - 1;
+ cache->slack = FTC_HASH_INITIAL_SIZE * FTC_HASH_MAX_LOAD;
+
+ if ( FT_NEW_ARRAY( cache->buckets, FTC_HASH_INITIAL_SIZE * 2 ) )
+ goto Exit;
+
+ /* now, initialize the lru list of families for this cache */
+ if ( clazz->family_size > 0 )
+ {
+ FT_LruList_ClassRec* lru_class = &cache->family_class;
+
+
+ lru_class->list_size = sizeof( FT_LruListRec );
+ lru_class->list_init = NULL;
+ lru_class->list_done = NULL;
+
+ lru_class->node_size = clazz->family_size;
+ lru_class->node_init = (FT_LruNode_InitFunc) clazz->family_init;
+ lru_class->node_done = (FT_LruNode_DoneFunc) clazz->family_done;
+ lru_class->node_flush = (FT_LruNode_FlushFunc) NULL;
+ lru_class->node_compare = (FT_LruNode_CompareFunc)clazz->family_compare;
+
+ error = FT_LruList_New( (FT_LruList_Class) lru_class,
+ 0, /* max items == 0 => unbounded list */
+ cache,
+ memory,
+ &cache->families );
+ if ( error )
+ FT_FREE( cache->buckets );
+ }
+
+ Exit:
+ return error;
+ }
+
+
+ FT_EXPORT_DEF( void )
+ ftc_cache_clear( FTC_Cache cache )
+ {
+ if ( cache )
+ {
+ FT_Memory memory = cache->memory;
+ FTC_Cache_Class clazz = cache->clazz;
+ FTC_Manager manager = cache->manager;
+ FT_UFast i;
+ FT_UInt count;
+
+ count = cache->p + cache->mask + 1;
+
+ for ( i = 0; i < count; i++ )
+ {
+ FTC_Node *pnode = cache->buckets + i, next, node = *pnode;
+
+
+ while ( node )
+ {
+ next = node->link;
+ node->link = NULL;
+
+ /* remove node from mru list */
+ ftc_node_mru_unlink( node, manager );
+
+ /* now finalize it */
+ manager->cur_weight -= clazz->node_weight( node, cache );
+
+ if ( clazz->node_done )
+ clazz->node_done( node, cache );
+
+ FT_FREE( node );
+ node = next;
+ }
+ cache->buckets[i] = NULL;
+ }
+
+ cache->p = 0;
+
+ /* destroy the families */
+ if ( cache->families )
+ FT_LruList_Reset( cache->families );
+ }
+ }
+
+
+ FT_EXPORT_DEF( void )
+ ftc_cache_done( FTC_Cache cache )
+ {
+ if ( cache )
+ {
+ FT_Memory memory = cache->memory;
+
+
+ ftc_cache_clear( cache );
+
+ FT_FREE( cache->buckets );
+ cache->mask = 0;
+ cache->slack = 0;
+
+ if ( cache->families )
+ {
+ FT_LruList_Destroy( cache->families );
+ cache->families = NULL;
+ }
+ }
+ }
+
+
+ /* Look up a node in "top" of its cache's hash table. */
+ /* If not found, create a new node. */
+ /* */
+ FT_EXPORT_DEF( FT_Error )
+ ftc_cache_lookup( FTC_Cache cache,
+ FTC_Query query,
+ FTC_Node *anode )
+ {
+ FT_Error error = FT_Err_Ok;
+ FT_LruNode lru;
+
+
+ if ( !cache || !query || !anode )
+ return FTC_Err_Invalid_Argument;
+
+ *anode = NULL;
+
+ query->hash = 0;
+ query->family = NULL;
+
+ /* XXX: we break encapsulation for the sake of speed! */
+ {
+ /* first of all, find the relevant family */
+ FT_LruList list = cache->families;
+ FT_LruNode fam, *pfam;
+ FT_LruNode_CompareFunc compare = list->clazz->node_compare;
+
+ pfam = &list->nodes;
+ for (;;)
+ {
+ fam = *pfam;
+ if ( fam == NULL )
+ {
+ error = FT_LruList_Lookup( list, query, &lru );
+ if ( error )
+ goto Exit;
+
+ goto Skip;
+ }
+
+ if ( compare( fam, query, list->data ) )
+ break;
+
+ pfam = &fam->next;
+ }
+
+ FT_ASSERT( fam != NULL );
+
+ /* move to top of list when needed */
+ if ( fam != list->nodes )
+ {
+ *pfam = fam->next;
+ fam->next = list->nodes;
+ list->nodes = fam;
+ }
+
+ lru = fam;
+
+ Skip:
+ ;
+ }
+
+ {
+ FTC_Family family = (FTC_Family) lru;
+ FT_UFast hash = query->hash;
+ FTC_Node* bucket;
+ FT_UInt idx;
+
+
+ idx = hash & cache->mask;
+ if ( idx < cache->p )
+ idx = hash & ( cache->mask * 2 + 1 );
+
+ bucket = cache->buckets + idx;
+
+
+ if ( query->family != family ||
+ family->fam_index >= cache->manager->families.size )
+ {
+ FT_ERROR((
+ "ftc_cache_lookup: invalid query (bad 'family' field)\n" ));
+ return FTC_Err_Invalid_Argument;
+ }
+
+ if ( *bucket )
+ {
+ FTC_Node* pnode = bucket;
+ FTC_Node_CompareFunc compare = cache->clazz->node_compare;
+
+
+ for ( ;; )
+ {
+ FTC_Node node;
+
+
+ node = *pnode;
+ if ( node == NULL )
+ break;
+
+ if ( node->hash == hash &&
+ (FT_UInt)node->fam_index == family->fam_index &&
+ compare( node, query, cache ) )
+ {
+ /* move to head of bucket list */
+ if ( pnode != bucket )
+ {
+ *pnode = node->link;
+ node->link = *bucket;
+ *bucket = node;
+ }
+
+ /* move to head of MRU list */
+ if ( node != cache->manager->nodes_list )
+ ftc_node_mru_up( node, cache->manager );
+
+ *anode = node;
+ goto Exit;
+ }
+
+ pnode = &node->link;
+ }
+ }
+
+ /* didn't find a node, create a new one */
+ {
+ FTC_Cache_Class clazz = cache->clazz;
+ FTC_Manager manager = cache->manager;
+ FT_Memory memory = cache->memory;
+ FTC_Node node;
+
+
+ if ( FT_ALLOC( node, clazz->node_size ) )
+ goto Exit;
+
+ node->fam_index = (FT_UShort) family->fam_index;
+ node->hash = query->hash;
+ node->ref_count = 0;
+
+ error = clazz->node_init( node, query, cache );
+ if ( error )
+ {
+ FT_FREE( node );
+ goto Exit;
+ }
+
+ error = ftc_node_hash_link( node, cache );
+ if ( error )
+ {
+ clazz->node_done( node, cache );
+ FT_FREE( node );
+ goto Exit;
+ }
+
+ ftc_node_mru_link( node, cache->manager );
+
+ cache->manager->cur_weight += clazz->node_weight( node, cache );
+
+ /* now try to compress the node pool when necessary */
+ if ( manager->cur_weight >= manager->max_weight )
+ {
+ node->ref_count++;
+ FTC_Manager_Compress( manager );
+ node->ref_count--;
+ }
+
+ *anode = node;
+ }
+ }
+
+ Exit:
+ return error;
+ }
+
+
+/* END */
--- /dev/null
+++ b/libfreetype/ftccmap.c
@@ -1,0 +1,411 @@
+/***************************************************************************/
+/* */
+/* ftccmap.c */
+/* */
+/* FreeType CharMap cache (body) */
+/* */
+/* Copyright 2000-2001, 2002 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+
+#include <ft2build.h>
+#include FT_FREETYPE_H
+#include FT_CACHE_H
+#include FT_CACHE_CHARMAP_H
+#include FT_CACHE_MANAGER_H
+#include FT_INTERNAL_MEMORY_H
+#include FT_INTERNAL_DEBUG_H
+
+#include "ftcerror.h"
+
+ /*************************************************************************/
+ /* */
+ /* Each FTC_CMapNode contains a simple array to map a range of character */
+ /* codes to equivalent glyph indices. */
+ /* */
+ /* For now, the implementation is very basic: Each node maps a range of */
+ /* 128 consecutive character codes to their corresponding glyph indices. */
+ /* */
+ /* We could do more complex things, but I don't think it is really very */
+ /* useful. */
+ /* */
+ /*************************************************************************/
+
+
+ /* number of glyph indices / character code per node */
+#define FTC_CMAP_INDICES_MAX 128
+
+
+ typedef struct FTC_CMapNodeRec_
+ {
+ FTC_NodeRec node;
+ FT_UInt32 first; /* first character in node */
+ FT_UInt16 indices[FTC_CMAP_INDICES_MAX]; /* array of glyph indices */
+
+ } FTC_CMapNodeRec, *FTC_CMapNode;
+
+
+#define FTC_CMAP_NODE( x ) ( (FTC_CMapNode)( x ) )
+
+
+ /* compute node hash value from cmap family and "requested" glyph index */
+#define FTC_CMAP_HASH( cfam, cquery ) \
+ ( (cfam)->hash + ( (cquery)->char_code / FTC_CMAP_INDICES_MAX ) )
+
+ /* if (indices[n] == FTC_CMAP_UNKNOWN), we assume that the corresponding */
+ /* glyph indices haven't been queried through FT_Get_Glyph_Index() yet */
+#define FTC_CMAP_UNKNOWN ( (FT_UInt16)-1 )
+
+
+ /* the charmap query */
+ typedef struct FTC_CMapQueryRec_
+ {
+ FTC_QueryRec query;
+ FTC_CMapDesc desc;
+ FT_UInt32 char_code;
+
+ } FTC_CMapQueryRec, *FTC_CMapQuery;
+
+
+#define FTC_CMAP_QUERY( x ) ( (FTC_CMapQuery)( x ) )
+
+
+ /* the charmap family */
+ typedef struct FTC_CMapFamilyRec_
+ {
+ FTC_FamilyRec family;
+ FT_UInt32 hash;
+ FTC_CMapDescRec desc;
+ FT_UInt index;
+
+ } FTC_CMapFamilyRec, *FTC_CMapFamily;
+
+
+#define FTC_CMAP_FAMILY( x ) ( (FTC_CMapFamily)( x ) )
+#define FTC_CMAP_FAMILY_MEMORY( x ) FTC_FAMILY( x )->memory
+
+
+ /*************************************************************************/
+ /*************************************************************************/
+ /***** *****/
+ /***** CHARMAP NODES *****/
+ /***** *****/
+ /*************************************************************************/
+ /*************************************************************************/
+
+
+ /* no need for specific finalizer; we use "ftc_node_done" directly */
+
+ /* initialize a new cmap node */
+ FT_CALLBACK_DEF( FT_Error )
+ ftc_cmap_node_init( FTC_CMapNode cnode,
+ FTC_CMapQuery cquery,
+ FTC_Cache cache )
+ {
+ FT_UInt32 first;
+ FT_UInt n;
+ FT_UNUSED( cache );
+
+
+ first = ( cquery->char_code / FTC_CMAP_INDICES_MAX ) *
+ FTC_CMAP_INDICES_MAX;
+
+ cnode->first = first;
+ for ( n = 0; n < FTC_CMAP_INDICES_MAX; n++ )
+ cnode->indices[n] = FTC_CMAP_UNKNOWN;
+
+ return 0;
+ }
+
+
+ /* compute the weight of a given cmap node */
+ FT_CALLBACK_DEF( FT_ULong )
+ ftc_cmap_node_weight( FTC_CMapNode cnode )
+ {
+ FT_UNUSED( cnode );
+
+ return sizeof ( *cnode );
+ }
+
+
+ /* compare a cmap node to a given query */
+ FT_CALLBACK_DEF( FT_Bool )
+ ftc_cmap_node_compare( FTC_CMapNode cnode,
+ FTC_CMapQuery cquery )
+ {
+ FT_UInt32 offset = (FT_UInt32)( cquery->char_code - cnode->first );
+
+
+ return FT_BOOL( offset < FTC_CMAP_INDICES_MAX );
+ }
+
+
+ /*************************************************************************/
+ /*************************************************************************/
+ /***** *****/
+ /***** CHARMAP FAMILY *****/
+ /***** *****/
+ /*************************************************************************/
+ /*************************************************************************/
+
+
+ FT_CALLBACK_DEF( FT_Error )
+ ftc_cmap_family_init( FTC_CMapFamily cfam,
+ FTC_CMapQuery cquery,
+ FTC_Cache cache )
+ {
+ FTC_Manager manager = cache->manager;
+ FTC_CMapDesc desc = cquery->desc;
+ FT_UInt32 hash = 0;
+ FT_Error error;
+ FT_Face face;
+
+
+ /* setup charmap descriptor */
+ cfam->desc = *desc;
+
+ /* let's see whether the rest is correct too */
+ error = FTC_Manager_Lookup_Face( manager, desc->face_id, &face );
+ if ( !error )
+ {
+ FT_UInt count = face->num_charmaps;
+ FT_UInt idx = count;
+ FT_CharMap* cur = face->charmaps;
+
+
+ switch ( desc->type )
+ {
+ case FTC_CMAP_BY_INDEX:
+ idx = desc->u.index;
+ hash = idx * 33;
+ break;
+
+ case FTC_CMAP_BY_ENCODING:
+ for ( idx = 0; idx < count; idx++, cur++ )
+ if ( cur[0]->encoding == desc->u.encoding )
+ break;
+
+ hash = idx * 67;
+ break;
+
+ case FTC_CMAP_BY_ID:
+ for ( idx = 0; idx < count; idx++, cur++ )
+ {
+ if ( (FT_UInt)cur[0]->platform_id == desc->u.id.platform &&
+ (FT_UInt)cur[0]->encoding_id == desc->u.id.encoding )
+ {
+ hash = ( ( desc->u.id.platform << 8 ) | desc->u.id.encoding ) * 7;
+ break;
+ }
+ }
+ break;
+
+ default:
+ ;
+ }
+
+ if ( idx >= count )
+ goto Bad_Descriptor;
+
+ /* compute hash value, both in family and query */
+ cfam->index = idx;
+ cfam->hash = hash ^ FTC_FACE_ID_HASH( desc->face_id );
+ FTC_QUERY( cquery )->hash = FTC_CMAP_HASH( cfam, cquery );
+
+ error = ftc_family_init( FTC_FAMILY( cfam ),
+ FTC_QUERY( cquery ), cache );
+ }
+
+ return error;
+
+ Bad_Descriptor:
+ FT_ERROR(( "ftp_cmap_family_init: invalid charmap descriptor\n" ));
+ return FTC_Err_Invalid_Argument;
+ }
+
+
+ FT_CALLBACK_DEF( FT_Bool )
+ ftc_cmap_family_compare( FTC_CMapFamily cfam,
+ FTC_CMapQuery cquery )
+ {
+ FT_Int result = 0;
+
+
+ /* first, compare face id and type */
+ if ( cfam->desc.face_id != cquery->desc->face_id ||
+ cfam->desc.type != cquery->desc->type )
+ goto Exit;
+
+ switch ( cfam->desc.type )
+ {
+ case FTC_CMAP_BY_INDEX:
+ result = ( cfam->desc.u.index == cquery->desc->u.index );
+ break;
+
+ case FTC_CMAP_BY_ENCODING:
+ result = ( cfam->desc.u.encoding == cquery->desc->u.encoding );
+ break;
+
+ case FTC_CMAP_BY_ID:
+ result = ( cfam->desc.u.id.platform == cquery->desc->u.id.platform &&
+ cfam->desc.u.id.encoding == cquery->desc->u.id.encoding );
+ break;
+
+ default:
+ ;
+ }
+
+ if ( result )
+ {
+ /* when found, update the 'family' and 'hash' field of the query */
+ FTC_QUERY( cquery )->family = FTC_FAMILY( cfam );
+ FTC_QUERY( cquery )->hash = FTC_CMAP_HASH( cfam, cquery );
+ }
+
+ Exit:
+ return FT_BOOL( result );
+ }
+
+
+ /*************************************************************************/
+ /*************************************************************************/
+ /***** *****/
+ /***** GLYPH IMAGE CACHE *****/
+ /***** *****/
+ /*************************************************************************/
+ /*************************************************************************/
+
+
+ FT_CALLBACK_TABLE_DEF
+ const FTC_Cache_ClassRec ftc_cmap_cache_class =
+ {
+ sizeof ( FTC_CacheRec ),
+ (FTC_Cache_InitFunc) ftc_cache_init,
+ (FTC_Cache_ClearFunc)ftc_cache_clear,
+ (FTC_Cache_DoneFunc) ftc_cache_done,
+
+ sizeof ( FTC_CMapFamilyRec ),
+ (FTC_Family_InitFunc) ftc_cmap_family_init,
+ (FTC_Family_CompareFunc)ftc_cmap_family_compare,
+ (FTC_Family_DoneFunc) ftc_family_done,
+
+ sizeof ( FTC_CMapNodeRec ),
+ (FTC_Node_InitFunc) ftc_cmap_node_init,
+ (FTC_Node_WeightFunc) ftc_cmap_node_weight,
+ (FTC_Node_CompareFunc)ftc_cmap_node_compare,
+ (FTC_Node_DoneFunc) ftc_node_done
+ };
+
+
+ /* documentation is in ftccmap.h */
+
+ FT_EXPORT_DEF( FT_Error )
+ FTC_CMapCache_New( FTC_Manager manager,
+ FTC_CMapCache *acache )
+ {
+ return FTC_Manager_Register_Cache(
+ manager,
+ (FTC_Cache_Class)&ftc_cmap_cache_class,
+ FTC_CACHE_P( acache ) );
+ }
+
+
+#ifdef FTC_CACHE_USE_INLINE
+
+#define GEN_CACHE_FAMILY_COMPARE( f, q, c ) \
+ ftc_cmap_family_compare( (FTC_CMapFamily)(f), (FTC_CMapQuery)(q) )
+
+#define GEN_CACHE_NODE_COMPARE( n, q, c ) \
+ ftc_cmap_node_compare( (FTC_CMapNode)(n), (FTC_CMapQuery)(q) )
+
+#define GEN_CACHE_LOOKUP ftc_cmap_cache_lookup
+
+#include "ftccache.i"
+
+#else /* !FTC_CACHE_USE_INLINE */
+
+#define ftc_cmap_cache_lookup ftc_cache_lookup
+
+#endif /* !FTC_CACHE_USE_INLINE */
+
+
+ /* documentation is in ftccmap.h */
+
+ FT_EXPORT_DEF( FT_UInt )
+ FTC_CMapCache_Lookup( FTC_CMapCache cache,
+ FTC_CMapDesc desc,
+ FT_UInt32 char_code )
+ {
+ FTC_CMapQueryRec cquery;
+ FTC_CMapNode node;
+ FT_Error error;
+ FT_UInt gindex = 0;
+
+
+ if ( !cache || !desc )
+ {
+ FT_ERROR(( "FTC_CMapCache_Lookup: bad arguments, returning 0!\n" ));
+ return 0;
+ }
+
+ cquery.desc = desc;
+ cquery.char_code = char_code;
+
+ error = ftc_cmap_cache_lookup( FTC_CACHE( cache ),
+ FTC_QUERY( &cquery ),
+ (FTC_Node*)&node );
+ if ( !error )
+ {
+ FT_UInt offset = (FT_UInt)( char_code - node->first );
+
+
+ FT_ASSERT( offset < FTC_CMAP_INDICES_MAX );
+
+ gindex = node->indices[offset];
+ if ( gindex == FTC_CMAP_UNKNOWN )
+ {
+ FT_Face face;
+
+
+ /* we need to use FT_Get_Char_Index */
+ gindex = 0;
+
+ error = FTC_Manager_Lookup_Face( FTC_CACHE(cache)->manager,
+ desc->face_id,
+ &face );
+ if ( !error )
+ {
+ FT_CharMap old, cmap = NULL;
+ FT_UInt cmap_index;
+
+
+ /* save old charmap, select new one */
+ old = face->charmap;
+ cmap_index = FTC_CMAP_FAMILY( FTC_QUERY( &cquery )->family )->index;
+ cmap = face->charmaps[cmap_index];
+
+ FT_Set_Charmap( face, cmap );
+
+ /* perform lookup */
+ gindex = FT_Get_Char_Index( face, char_code );
+ node->indices[offset] = (FT_UInt16)gindex;
+
+ /* restore old charmap */
+ FT_Set_Charmap( face, old );
+ }
+ }
+ }
+
+ return gindex;
+ }
+
+
+/* END */
--- /dev/null
+++ b/libfreetype/ftcerror.h
@@ -1,0 +1,40 @@
+/***************************************************************************/
+/* */
+/* ftcerror.h */
+/* */
+/* Caching sub-system error codes (specification only). */
+/* */
+/* Copyright 2001 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+
+ /*************************************************************************/
+ /* */
+ /* This file is used to define the caching sub-system error enumeration */
+ /* constants. */
+ /* */
+ /*************************************************************************/
+
+#ifndef __FTCERROR_H__
+#define __FTCERROR_H__
+
+#include FT_MODULE_ERRORS_H
+
+#undef __FTERRORS_H__
+
+#define FT_ERR_PREFIX FTC_Err_
+#define FT_ERR_BASE FT_Mod_Err_Cache
+
+#include FT_ERRORS_H
+
+#endif /* __FTCERROR_H__ */
+
+/* END */
--- /dev/null
+++ b/libfreetype/ftcglyph.c
@@ -1,0 +1,115 @@
+/***************************************************************************/
+/* */
+/* ftcglyph.c */
+/* */
+/* FreeType Glyph Image (FT_Glyph) cache (body). */
+/* */
+/* Copyright 2000-2001 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+
+#include <ft2build.h>
+#include FT_CACHE_H
+#include FT_CACHE_INTERNAL_GLYPH_H
+#include FT_ERRORS_H
+#include FT_LIST_H
+#include FT_INTERNAL_OBJECTS_H
+#include FT_INTERNAL_DEBUG_H
+
+#include "ftcerror.h"
+
+
+ /* create a new chunk node, setting its cache index and ref count */
+ FT_EXPORT_DEF( void )
+ ftc_glyph_node_init( FTC_GlyphNode gnode,
+ FT_UInt gindex,
+ FTC_GlyphFamily gfam )
+ {
+ FT_UInt len;
+ FT_UInt start = FTC_GLYPH_FAMILY_START( gfam, gindex );
+
+
+ gnode->item_start = (FT_UShort)start;
+
+ len = gfam->item_total - start;
+ if ( len > gfam->item_count )
+ len = gfam->item_count;
+
+ gnode->item_count = (FT_UShort)len;
+ gfam->family.num_nodes++;
+ }
+
+
+ FT_EXPORT_DEF( void )
+ ftc_glyph_node_done( FTC_GlyphNode gnode,
+ FTC_Cache cache )
+ {
+ /* finalize the node */
+ gnode->item_count = 0;
+ gnode->item_start = 0;
+
+ ftc_node_done( FTC_NODE( gnode ), cache );
+ }
+
+
+ FT_EXPORT_DEF( FT_Bool )
+ ftc_glyph_node_compare( FTC_GlyphNode gnode,
+ FTC_GlyphQuery gquery )
+ {
+ FT_UInt start = (FT_UInt)gnode->item_start;
+ FT_UInt count = (FT_UInt)gnode->item_count;
+
+ return FT_BOOL( (FT_UInt)( gquery->gindex - start ) < count );
+ }
+
+
+ /*************************************************************************/
+ /*************************************************************************/
+ /***** *****/
+ /***** CHUNK SETS *****/
+ /***** *****/
+ /*************************************************************************/
+ /*************************************************************************/
+
+
+ FT_EXPORT_DEF( FT_Error )
+ ftc_glyph_family_init( FTC_GlyphFamily gfam,
+ FT_UInt32 hash,
+ FT_UInt item_count,
+ FT_UInt item_total,
+ FTC_GlyphQuery gquery,
+ FTC_Cache cache )
+ {
+ FT_Error error;
+
+
+ error = ftc_family_init( FTC_FAMILY( gfam ), FTC_QUERY( gquery ), cache );
+ if ( !error )
+ {
+ gfam->hash = hash;
+ gfam->item_total = item_total;
+ gfam->item_count = item_count;
+
+ FTC_GLYPH_FAMILY_FOUND( gfam, gquery );
+ }
+
+ return error;
+ }
+
+
+ FT_EXPORT_DEF( void )
+ ftc_glyph_family_done( FTC_GlyphFamily gfam )
+ {
+ ftc_family_done( FTC_FAMILY( gfam ) );
+ }
+
+
+/* END */
--- /dev/null
+++ b/libfreetype/ftcimage.c
@@ -1,0 +1,399 @@
+/***************************************************************************/
+/* */
+/* ftcimage.c */
+/* */
+/* FreeType Image cache (body). */
+/* */
+/* Copyright 2000-2001 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+
+#include <ft2build.h>
+#include FT_CACHE_H
+#include FT_CACHE_IMAGE_H
+#include FT_CACHE_INTERNAL_GLYPH_H
+#include FT_INTERNAL_MEMORY_H
+
+#include "ftcerror.h"
+
+
+ /* the FT_Glyph image node type */
+ typedef struct FTC_ImageNodeRec_
+ {
+ FTC_GlyphNodeRec gnode;
+ FT_Glyph glyph;
+
+ } FTC_ImageNodeRec, *FTC_ImageNode;
+
+
+#define FTC_IMAGE_NODE( x ) ( (FTC_ImageNode)( x ) )
+#define FTC_IMAGE_NODE_GINDEX( x ) FTC_GLYPH_NODE_GINDEX( x )
+
+
+ /* the glyph image query */
+ typedef struct FTC_ImageQueryRec_
+ {
+ FTC_GlyphQueryRec gquery;
+ FTC_ImageTypeRec type;
+
+ } FTC_ImageQueryRec, *FTC_ImageQuery;
+
+
+#define FTC_IMAGE_QUERY( x ) ( (FTC_ImageQuery)( x ) )
+
+
+ /* the glyph image set type */
+ typedef struct FTC_ImageFamilyRec_
+ {
+ FTC_GlyphFamilyRec gfam;
+ FTC_ImageTypeRec type;
+
+ } FTC_ImageFamilyRec, *FTC_ImageFamily;
+
+
+#define FTC_IMAGE_FAMILY( x ) ( (FTC_ImageFamily)( x ) )
+#define FTC_IMAGE_FAMILY_MEMORY( x ) FTC_GLYPH_FAMILY_MEMORY( &(x)->gfam )
+
+
+ /*************************************************************************/
+ /*************************************************************************/
+ /***** *****/
+ /***** GLYPH IMAGE NODES *****/
+ /***** *****/
+ /*************************************************************************/
+ /*************************************************************************/
+
+
+ /* finalize a given glyph image node */
+ FT_CALLBACK_DEF( void )
+ ftc_image_node_done( FTC_ImageNode inode,
+ FTC_Cache cache )
+ {
+ if ( inode->glyph )
+ {
+ FT_Done_Glyph( inode->glyph );
+ inode->glyph = NULL;
+ }
+
+ ftc_glyph_node_done( FTC_GLYPH_NODE( inode ), cache );
+ }
+
+
+ /* initialize a new glyph image node */
+ FT_CALLBACK_DEF( FT_Error )
+ ftc_image_node_init( FTC_ImageNode inode,
+ FTC_GlyphQuery gquery,
+ FTC_Cache cache )
+ {
+ FTC_ImageFamily ifam = FTC_IMAGE_FAMILY( gquery->query.family );
+ FT_Error error;
+ FT_Face face;
+ FT_Size size;
+
+
+ /* initialize its inner fields */
+ ftc_glyph_node_init( FTC_GLYPH_NODE( inode ),
+ gquery->gindex,
+ FTC_GLYPH_FAMILY( ifam ) );
+
+ /* we will now load the glyph image */
+ error = FTC_Manager_Lookup_Size( FTC_FAMILY( ifam )->cache->manager,
+ &ifam->type.font,
+ &face, &size );
+ if ( !error )
+ {
+ FT_UInt gindex = FTC_GLYPH_NODE_GINDEX( inode );
+
+
+ error = FT_Load_Glyph( face, gindex, ifam->type.flags );
+ if ( !error )
+ {
+ if ( face->glyph->format == FT_GLYPH_FORMAT_BITMAP ||
+ face->glyph->format == FT_GLYPH_FORMAT_OUTLINE )
+ {
+ /* ok, copy it */
+ FT_Glyph glyph;
+
+
+ error = FT_Get_Glyph( face->glyph, &glyph );
+ if ( !error )
+ {
+ inode->glyph = glyph;
+ goto Exit;
+ }
+ }
+ else
+ error = FTC_Err_Invalid_Argument;
+ }
+ }
+
+ /* in case of error */
+ ftc_glyph_node_done( FTC_GLYPH_NODE(inode), cache );
+
+ Exit:
+ return error;
+ }
+
+
+ FT_CALLBACK_DEF( FT_ULong )
+ ftc_image_node_weight( FTC_ImageNode inode )
+ {
+ FT_ULong size = 0;
+ FT_Glyph glyph = inode->glyph;
+
+
+ switch ( glyph->format )
+ {
+ case FT_GLYPH_FORMAT_BITMAP:
+ {
+ FT_BitmapGlyph bitg;
+
+
+ bitg = (FT_BitmapGlyph)glyph;
+ size = bitg->bitmap.rows * labs( bitg->bitmap.pitch ) +
+ sizeof ( *bitg );
+ }
+ break;
+
+ case FT_GLYPH_FORMAT_OUTLINE:
+ {
+ FT_OutlineGlyph outg;
+
+
+ outg = (FT_OutlineGlyph)glyph;
+ size = outg->outline.n_points *
+ ( sizeof ( FT_Vector ) + sizeof ( FT_Byte ) ) +
+ outg->outline.n_contours * sizeof ( FT_Short ) +
+ sizeof ( *outg );
+ }
+ break;
+
+ default:
+ ;
+ }
+
+ size += sizeof ( *inode );
+ return size;
+ }
+
+
+ /*************************************************************************/
+ /*************************************************************************/
+ /***** *****/
+ /***** GLYPH IMAGE SETS *****/
+ /***** *****/
+ /*************************************************************************/
+ /*************************************************************************/
+
+
+ FT_CALLBACK_DEF( FT_Error )
+ ftc_image_family_init( FTC_ImageFamily ifam,
+ FTC_ImageQuery iquery,
+ FTC_Cache cache )
+ {
+ FTC_Manager manager = cache->manager;
+ FT_Error error;
+ FT_Face face;
+
+
+ ifam->type = iquery->type;
+
+ /* we need to compute "iquery.item_total" now */
+ error = FTC_Manager_Lookup_Face( manager,
+ iquery->type.font.face_id,
+ &face );
+ if ( !error )
+ {
+ error = ftc_glyph_family_init( FTC_GLYPH_FAMILY( ifam ),
+ FTC_IMAGE_TYPE_HASH( &ifam->type ),
+ 1,
+ face->num_glyphs,
+ FTC_GLYPH_QUERY( iquery ),
+ cache );
+ }
+
+ return error;
+ }
+
+
+ FT_CALLBACK_DEF( FT_Bool )
+ ftc_image_family_compare( FTC_ImageFamily ifam,
+ FTC_ImageQuery iquery )
+ {
+ FT_Bool result;
+
+
+ result = FT_BOOL( FTC_IMAGE_TYPE_COMPARE( &ifam->type, &iquery->type ) );
+ if ( result )
+ FTC_GLYPH_FAMILY_FOUND( ifam, iquery );
+
+ return result;
+ }
+
+
+ /*************************************************************************/
+ /*************************************************************************/
+ /***** *****/
+ /***** GLYPH IMAGE CACHE *****/
+ /***** *****/
+ /*************************************************************************/
+ /*************************************************************************/
+
+
+
+ FT_CALLBACK_TABLE_DEF
+ const FTC_Cache_ClassRec ftc_image_cache_class =
+ {
+ sizeof ( FTC_CacheRec ),
+ (FTC_Cache_InitFunc) ftc_cache_init,
+ (FTC_Cache_ClearFunc)ftc_cache_clear,
+ (FTC_Cache_DoneFunc) ftc_cache_done,
+
+ sizeof ( FTC_ImageFamilyRec ),
+ (FTC_Family_InitFunc) ftc_image_family_init,
+ (FTC_Family_CompareFunc)ftc_image_family_compare,
+ (FTC_Family_DoneFunc) ftc_glyph_family_done,
+
+ sizeof ( FTC_ImageNodeRec ),
+ (FTC_Node_InitFunc) ftc_image_node_init,
+ (FTC_Node_WeightFunc) ftc_image_node_weight,
+ (FTC_Node_CompareFunc)ftc_glyph_node_compare,
+ (FTC_Node_DoneFunc) ftc_image_node_done
+ };
+
+
+ /* documentation is in ftcimage.h */
+
+ FT_EXPORT_DEF( FT_Error )
+ FTC_ImageCache_New( FTC_Manager manager,
+ FTC_ImageCache *acache )
+ {
+ return FTC_Manager_Register_Cache(
+ manager,
+ (FTC_Cache_Class)&ftc_image_cache_class,
+ FTC_CACHE_P( acache ) );
+ }
+
+
+ /* documentation is in ftcimage.h */
+
+ FT_EXPORT_DEF( FT_Error )
+ FTC_ImageCache_Lookup( FTC_ImageCache cache,
+ FTC_ImageType type,
+ FT_UInt gindex,
+ FT_Glyph *aglyph,
+ FTC_Node *anode )
+ {
+ FTC_ImageQueryRec iquery;
+ FTC_ImageNode node;
+ FT_Error error;
+
+
+ /* some argument checks are delayed to ftc_cache_lookup */
+ if ( !aglyph )
+ return FTC_Err_Invalid_Argument;
+
+ if ( anode )
+ *anode = NULL;
+
+ iquery.gquery.gindex = gindex;
+ iquery.type = *type;
+
+ error = ftc_cache_lookup( FTC_CACHE( cache ),
+ FTC_QUERY( &iquery ),
+ (FTC_Node*)&node );
+ if ( !error )
+ {
+ *aglyph = node->glyph;
+
+ if ( anode )
+ {
+ *anode = (FTC_Node)node;
+ FTC_NODE( node )->ref_count++;
+ }
+ }
+
+ return error;
+ }
+
+
+ /* backwards-compatibility functions */
+
+ FT_EXPORT_DEF( FT_Error )
+ FTC_Image_Cache_New( FTC_Manager manager,
+ FTC_Image_Cache *acache )
+ {
+ return FTC_ImageCache_New( manager, (FTC_ImageCache*)acache );
+ }
+
+
+ FT_EXPORT_DEF( FT_Error )
+ FTC_Image_Cache_Lookup( FTC_Image_Cache icache,
+ FTC_Image_Desc* desc,
+ FT_UInt gindex,
+ FT_Glyph *aglyph )
+ {
+ FTC_ImageTypeRec type0;
+
+
+ if ( !desc )
+ return FTC_Err_Invalid_Argument;
+
+ type0.font = desc->font;
+
+ /* convert image type flags to load flags */
+ {
+ FT_UInt load_flags = FT_LOAD_DEFAULT;
+ FT_UInt type = desc->image_type;
+
+
+ /* determine load flags, depending on the font description's */
+ /* image type */
+
+ if ( ftc_image_format( type ) == ftc_image_format_bitmap )
+ {
+ if ( type & ftc_image_flag_monochrome )
+ load_flags |= FT_LOAD_MONOCHROME;
+
+ /* disable embedded bitmaps loading if necessary */
+ if ( type & ftc_image_flag_no_sbits )
+ load_flags |= FT_LOAD_NO_BITMAP;
+ }
+ else
+ {
+ /* we want an outline, don't load embedded bitmaps */
+ load_flags |= FT_LOAD_NO_BITMAP;
+
+ if ( type & ftc_image_flag_unscaled )
+ load_flags |= FT_LOAD_NO_SCALE;
+ }
+
+ /* always render glyphs to bitmaps */
+ load_flags |= FT_LOAD_RENDER;
+
+ if ( type & ftc_image_flag_unhinted )
+ load_flags |= FT_LOAD_NO_HINTING;
+
+ if ( type & ftc_image_flag_autohinted )
+ load_flags |= FT_LOAD_FORCE_AUTOHINT;
+
+ type0.flags = load_flags;
+ }
+
+ return FTC_ImageCache_Lookup( (FTC_ImageCache)icache,
+ &type0,
+ gindex,
+ aglyph,
+ NULL );
+ }
+
+
+/* END */
--- /dev/null
+++ b/libfreetype/ftcmanag.c
@@ -1,0 +1,765 @@
+/***************************************************************************/
+/* */
+/* ftcmanag.c */
+/* */
+/* FreeType Cache Manager (body). */
+/* */
+/* Copyright 2000-2001, 2002 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+
+#include <ft2build.h>
+#include FT_CACHE_H
+#include FT_CACHE_MANAGER_H
+#include FT_CACHE_INTERNAL_LRU_H
+#include FT_INTERNAL_OBJECTS_H
+#include FT_INTERNAL_DEBUG_H
+#include FT_SIZES_H
+
+#include "ftcerror.h"
+
+
+#undef FT_COMPONENT
+#define FT_COMPONENT trace_cache
+
+#define FTC_LRU_GET_MANAGER( lru ) ( (FTC_Manager)(lru)->user_data )
+
+
+ /*************************************************************************/
+ /*************************************************************************/
+ /***** *****/
+ /***** FACE LRU IMPLEMENTATION *****/
+ /***** *****/
+ /*************************************************************************/
+ /*************************************************************************/
+
+ typedef struct FTC_FaceNodeRec_* FTC_FaceNode;
+ typedef struct FTC_SizeNodeRec_* FTC_SizeNode;
+
+
+ typedef struct FTC_FaceNodeRec_
+ {
+ FT_LruNodeRec lru;
+ FT_Face face;
+
+ } FTC_FaceNodeRec;
+
+
+ typedef struct FTC_SizeNodeRec_
+ {
+ FT_LruNodeRec lru;
+ FT_Size size;
+
+ } FTC_SizeNodeRec;
+
+
+ FT_CALLBACK_DEF( FT_Error )
+ ftc_face_node_init( FTC_FaceNode node,
+ FTC_FaceID face_id,
+ FTC_Manager manager )
+ {
+ FT_Error error;
+
+
+ error = manager->request_face( face_id,
+ manager->library,
+ manager->request_data,
+ &node->face );
+ if ( !error )
+ {
+ /* destroy initial size object; it will be re-created later */
+ if ( node->face->size )
+ FT_Done_Size( node->face->size );
+ }
+
+ return error;
+ }
+
+
+ /* helper function for ftc_face_node_done() */
+ FT_CALLBACK_DEF( FT_Bool )
+ ftc_size_node_select( FTC_SizeNode node,
+ FT_Face face )
+ {
+ return FT_BOOL( node->size->face == face );
+ }
+
+
+ FT_CALLBACK_DEF( void )
+ ftc_face_node_done( FTC_FaceNode node,
+ FTC_Manager manager )
+ {
+ FT_Face face = node->face;
+
+
+ /* we must begin by removing all sizes for the target face */
+ /* from the manager's list */
+ FT_LruList_Remove_Selection( manager->sizes_list,
+ (FT_LruNode_SelectFunc)ftc_size_node_select,
+ face );
+
+ /* all right, we can discard the face now */
+ FT_Done_Face( face );
+ node->face = NULL;
+ }
+
+
+ FT_CALLBACK_TABLE_DEF
+ const FT_LruList_ClassRec ftc_face_list_class =
+ {
+ sizeof ( FT_LruListRec ),
+ (FT_LruList_InitFunc)0,
+ (FT_LruList_DoneFunc)0,
+
+ sizeof ( FTC_FaceNodeRec ),
+ (FT_LruNode_InitFunc) ftc_face_node_init,
+ (FT_LruNode_DoneFunc) ftc_face_node_done,
+ (FT_LruNode_FlushFunc) 0, /* no flushing needed */
+ (FT_LruNode_CompareFunc)0, /* direct comparison of FTC_FaceID handles */
+ };
+
+
+ /* documentation is in ftcache.h */
+
+ FT_EXPORT_DEF( FT_Error )
+ FTC_Manager_Lookup_Face( FTC_Manager manager,
+ FTC_FaceID face_id,
+ FT_Face *aface )
+ {
+ FT_Error error;
+ FTC_FaceNode node;
+
+
+ if ( aface == NULL )
+ return FTC_Err_Bad_Argument;
+
+ *aface = NULL;
+
+ if ( !manager )
+ return FTC_Err_Invalid_Cache_Handle;
+
+ error = FT_LruList_Lookup( manager->faces_list,
+ (FT_LruKey)face_id,
+ (FT_LruNode*)&node );
+ if ( !error )
+ *aface = node->face;
+
+ return error;
+ }
+
+
+ /*************************************************************************/
+ /*************************************************************************/
+ /***** *****/
+ /***** SIZES LRU IMPLEMENTATION *****/
+ /***** *****/
+ /*************************************************************************/
+ /*************************************************************************/
+
+
+ typedef struct FTC_SizeQueryRec_
+ {
+ FT_Face face;
+ FT_UInt width;
+ FT_UInt height;
+
+ } FTC_SizeQueryRec, *FTC_SizeQuery;
+
+
+ FT_CALLBACK_DEF( FT_Error )
+ ftc_size_node_init( FTC_SizeNode node,
+ FTC_SizeQuery query )
+ {
+ FT_Face face = query->face;
+ FT_Size size;
+ FT_Error error;
+
+
+ node->size = NULL;
+ error = FT_New_Size( face, &size );
+ if ( !error )
+ {
+ FT_Activate_Size( size );
+ error = FT_Set_Pixel_Sizes( query->face,
+ query->width,
+ query->height );
+ if ( error )
+ FT_Done_Size( size );
+ else
+ node->size = size;
+ }
+ return error;
+ }
+
+
+ FT_CALLBACK_DEF( void )
+ ftc_size_node_done( FTC_SizeNode node )
+ {
+ if ( node->size )
+ {
+ FT_Done_Size( node->size );
+ node->size = NULL;
+ }
+ }
+
+
+ FT_CALLBACK_DEF( FT_Error )
+ ftc_size_node_flush( FTC_SizeNode node,
+ FTC_SizeQuery query )
+ {
+ FT_Size size = node->size;
+ FT_Error error;
+
+
+ if ( size->face == query->face )
+ {
+ FT_Activate_Size( size );
+ error = FT_Set_Pixel_Sizes( query->face, query->width, query->height );
+ if ( error )
+ {
+ FT_Done_Size( size );
+ node->size = NULL;
+ }
+ }
+ else
+ {
+ FT_Done_Size( size );
+ node->size = NULL;
+
+ error = ftc_size_node_init( node, query );
+ }
+ return error;
+ }
+
+
+ FT_CALLBACK_DEF( FT_Bool )
+ ftc_size_node_compare( FTC_SizeNode node,
+ FTC_SizeQuery query )
+ {
+ FT_Size size = node->size;
+
+
+ return FT_BOOL( size->face == query->face &&
+ (FT_UInt)size->metrics.x_ppem == query->width &&
+ (FT_UInt)size->metrics.y_ppem == query->height );
+ }
+
+
+ FT_CALLBACK_TABLE_DEF
+ const FT_LruList_ClassRec ftc_size_list_class =
+ {
+ sizeof ( FT_LruListRec ),
+ (FT_LruList_InitFunc)0,
+ (FT_LruList_DoneFunc)0,
+
+ sizeof ( FTC_SizeNodeRec ),
+ (FT_LruNode_InitFunc) ftc_size_node_init,
+ (FT_LruNode_DoneFunc) ftc_size_node_done,
+ (FT_LruNode_FlushFunc) ftc_size_node_flush,
+ (FT_LruNode_CompareFunc)ftc_size_node_compare
+ };
+
+
+ /* documentation is in ftcache.h */
+
+ FT_EXPORT_DEF( FT_Error )
+ FTC_Manager_Lookup_Size( FTC_Manager manager,
+ FTC_Font font,
+ FT_Face *aface,
+ FT_Size *asize )
+ {
+ FT_Error error;
+
+
+ /* check for valid `manager' delayed to FTC_Manager_Lookup_Face() */
+ if ( aface )
+ *aface = 0;
+
+ if ( asize )
+ *asize = 0;
+
+ error = FTC_Manager_Lookup_Face( manager, font->face_id, aface );
+ if ( !error )
+ {
+ FTC_SizeQueryRec query;
+ FTC_SizeNode node;
+
+
+ query.face = *aface;
+ query.width = font->pix_width;
+ query.height = font->pix_height;
+
+ error = FT_LruList_Lookup( manager->sizes_list,
+ (FT_LruKey)&query,
+ (FT_LruNode*)&node );
+ if ( !error )
+ {
+ /* select the size as the current one for this face */
+ FT_Activate_Size( node->size );
+
+ if ( asize )
+ *asize = node->size;
+ }
+ }
+
+ return error;
+ }
+
+
+ /*************************************************************************/
+ /*************************************************************************/
+ /***** *****/
+ /***** SET TABLE MANAGEMENT *****/
+ /***** *****/
+ /*************************************************************************/
+ /*************************************************************************/
+
+ static void
+ ftc_family_table_init( FTC_FamilyTable table )
+ {
+ table->count = 0;
+ table->size = 0;
+ table->entries = NULL;
+ table->free = FTC_FAMILY_ENTRY_NONE;
+ }
+
+
+ static void
+ ftc_family_table_done( FTC_FamilyTable table,
+ FT_Memory memory )
+ {
+ FT_FREE( table->entries );
+ table->free = 0;
+ table->count = 0;
+ table->size = 0;
+ }
+
+
+ FT_EXPORT_DEF( FT_Error )
+ ftc_family_table_alloc( FTC_FamilyTable table,
+ FT_Memory memory,
+ FTC_FamilyEntry *aentry )
+ {
+ FTC_FamilyEntry entry;
+ FT_Error error = 0;
+
+
+ /* re-allocate table size when needed */
+ if ( table->free == FTC_FAMILY_ENTRY_NONE && table->count >= table->size )
+ {
+ FT_UInt old_size = table->size;
+ FT_UInt new_size, idx;
+
+
+ if ( old_size == 0 )
+ new_size = 8;
+ else
+ {
+ new_size = old_size * 2;
+
+ /* check for (unlikely) overflow */
+ if ( new_size < old_size )
+ new_size = 65534;
+ }
+
+ if ( FT_RENEW_ARRAY( table->entries, old_size, new_size ) )
+ return error;
+
+ table->size = new_size;
+
+ entry = table->entries + old_size;
+ table->free = old_size;
+
+ for ( idx = old_size; idx + 1 < new_size; idx++, entry++ )
+ {
+ entry->link = idx + 1;
+ entry->index = idx;
+ }
+
+ entry->link = FTC_FAMILY_ENTRY_NONE;
+ entry->index = idx;
+ }
+
+ if ( table->free != FTC_FAMILY_ENTRY_NONE )
+ {
+ entry = table->entries + table->free;
+ table->free = entry->link;
+ }
+ else if ( table->count < table->size )
+ {
+ entry = table->entries + table->count++;
+ }
+ else
+ {
+ FT_ERROR(( "ftc_family_table_alloc: internal bug!" ));
+ return FTC_Err_Invalid_Argument;
+ }
+
+ entry->link = FTC_FAMILY_ENTRY_NONE;
+ table->count++;
+
+ *aentry = entry;
+ return error;
+ }
+
+
+ FT_EXPORT_DEF( void )
+ ftc_family_table_free( FTC_FamilyTable table,
+ FT_UInt idx )
+ {
+ /* simply add it to the linked list of free entries */
+ if ( idx < table->count )
+ {
+ FTC_FamilyEntry entry = table->entries + idx;
+
+
+ if ( entry->link != FTC_FAMILY_ENTRY_NONE )
+ FT_ERROR(( "ftc_family_table_free: internal bug!\n" ));
+ else
+ {
+ entry->link = table->free;
+ table->free = entry->index;
+ table->count--;
+ }
+ }
+ }
+
+
+ /*************************************************************************/
+ /*************************************************************************/
+ /***** *****/
+ /***** CACHE MANAGER ROUTINES *****/
+ /***** *****/
+ /*************************************************************************/
+ /*************************************************************************/
+
+
+ /* documentation is in ftcache.h */
+
+ FT_EXPORT_DEF( FT_Error )
+ FTC_Manager_New( FT_Library library,
+ FT_UInt max_faces,
+ FT_UInt max_sizes,
+ FT_ULong max_bytes,
+ FTC_Face_Requester requester,
+ FT_Pointer req_data,
+ FTC_Manager *amanager )
+ {
+ FT_Error error;
+ FT_Memory memory;
+ FTC_Manager manager = 0;
+
+
+ if ( !library )
+ return FTC_Err_Invalid_Library_Handle;
+
+ memory = library->memory;
+
+ if ( FT_NEW( manager ) )
+ goto Exit;
+
+ if ( max_faces == 0 )
+ max_faces = FTC_MAX_FACES_DEFAULT;
+
+ if ( max_sizes == 0 )
+ max_sizes = FTC_MAX_SIZES_DEFAULT;
+
+ if ( max_bytes == 0 )
+ max_bytes = FTC_MAX_BYTES_DEFAULT;
+
+ error = FT_LruList_New( &ftc_face_list_class,
+ max_faces,
+ manager,
+ memory,
+ &manager->faces_list );
+ if ( error )
+ goto Exit;
+
+ error = FT_LruList_New( &ftc_size_list_class,
+ max_sizes,
+ manager,
+ memory,
+ &manager->sizes_list );
+ if ( error )
+ goto Exit;
+
+ manager->library = library;
+ manager->max_weight = max_bytes;
+ manager->cur_weight = 0;
+
+ manager->request_face = requester;
+ manager->request_data = req_data;
+
+ ftc_family_table_init( &manager->families );
+
+ *amanager = manager;
+
+ Exit:
+ if ( error && manager )
+ {
+ FT_LruList_Destroy( manager->faces_list );
+ FT_LruList_Destroy( manager->sizes_list );
+ FT_FREE( manager );
+ }
+
+ return error;
+ }
+
+
+ /* documentation is in ftcache.h */
+
+ FT_EXPORT_DEF( void )
+ FTC_Manager_Done( FTC_Manager manager )
+ {
+ FT_Memory memory;
+ FT_UInt idx;
+
+
+ if ( !manager || !manager->library )
+ return;
+
+ memory = manager->library->memory;
+
+ /* now discard all caches */
+ for (idx = 0; idx < FTC_MAX_CACHES; idx++ )
+ {
+ FTC_Cache cache = manager->caches[idx];
+
+
+ if ( cache )
+ {
+ cache->clazz->cache_done( cache );
+ FT_FREE( cache );
+ manager->caches[idx] = 0;
+ }
+ }
+
+ /* discard families table */
+ ftc_family_table_done( &manager->families, memory );
+
+ /* discard faces and sizes */
+ FT_LruList_Destroy( manager->faces_list );
+ manager->faces_list = 0;
+
+ FT_LruList_Destroy( manager->sizes_list );
+ manager->sizes_list = 0;
+
+ FT_FREE( manager );
+ }
+
+
+ /* documentation is in ftcache.h */
+
+ FT_EXPORT_DEF( void )
+ FTC_Manager_Reset( FTC_Manager manager )
+ {
+ if ( manager )
+ {
+ FT_LruList_Reset( manager->sizes_list );
+ FT_LruList_Reset( manager->faces_list );
+ }
+ /* XXX: FIXME: flush the caches? */
+ }
+
+
+#ifdef FT_DEBUG_ERROR
+
+ FT_EXPORT_DEF( void )
+ FTC_Manager_Check( FTC_Manager manager )
+ {
+ FTC_Node node, first;
+
+
+ first = manager->nodes_list;
+
+ /* check node weights */
+ if ( first )
+ {
+ FT_ULong weight = 0;
+
+
+ node = first;
+
+ do
+ {
+ FTC_FamilyEntry entry = manager->families.entries + node->fam_index;
+ FTC_Cache cache;
+
+ if ( (FT_UInt)node->fam_index >= manager->families.count ||
+ entry->link != FTC_FAMILY_ENTRY_NONE )
+ FT_ERROR(( "FTC_Manager_Check: invalid node (family index = %ld\n",
+ node->fam_index ));
+ else
+ {
+ cache = entry->cache;
+ weight += cache->clazz->node_weight( node, cache );
+ }
+
+ node = node->mru_next;
+
+ } while ( node != first );
+
+ if ( weight != manager->cur_weight )
+ FT_ERROR(( "FTC_Manager_Check: invalid weight %ld instead of %ld\n",
+ manager->cur_weight, weight ));
+ }
+
+ /* check circular list */
+ if ( first )
+ {
+ FT_UFast count = 0;
+
+
+ node = first;
+ do
+ {
+ count++;
+ node = node->mru_next;
+
+ } while ( node != first );
+
+ if ( count != manager->num_nodes )
+ FT_ERROR((
+ "FTC_Manager_Check: invalid cache node count %d instead of %d\n",
+ manager->num_nodes, count ));
+ }
+ }
+
+#endif /* FT_DEBUG_ERROR */
+
+
+ /* `Compress' the manager's data, i.e., get rid of old cache nodes */
+ /* that are not referenced anymore in order to limit the total */
+ /* memory used by the cache. */
+
+ /* documentation is in ftcmanag.h */
+
+ FT_EXPORT_DEF( void )
+ FTC_Manager_Compress( FTC_Manager manager )
+ {
+ FTC_Node node, first;
+
+
+ if ( !manager )
+ return;
+
+ first = manager->nodes_list;
+
+#ifdef FT_DEBUG_ERROR
+ FTC_Manager_Check( manager );
+
+ FT_ERROR(( "compressing, weight = %ld, max = %ld, nodes = %d\n",
+ manager->cur_weight, manager->max_weight,
+ manager->num_nodes ));
+#endif
+
+ if ( manager->cur_weight < manager->max_weight || first == NULL )
+ return;
+
+ /* go to last node - it's a circular list */
+ node = first->mru_prev;
+ do
+ {
+ FTC_Node prev = node->mru_prev;
+
+
+ prev = ( node == first ) ? NULL : node->mru_prev;
+
+ if ( node->ref_count <= 0 )
+ ftc_node_destroy( node, manager );
+
+ node = prev;
+
+ } while ( node && manager->cur_weight > manager->max_weight );
+ }
+
+
+ /* documentation is in ftcmanag.h */
+
+ FT_EXPORT_DEF( FT_Error )
+ FTC_Manager_Register_Cache( FTC_Manager manager,
+ FTC_Cache_Class clazz,
+ FTC_Cache *acache )
+ {
+ FT_Error error = FTC_Err_Invalid_Argument;
+ FTC_Cache cache = NULL;
+
+
+ if ( manager && clazz && acache )
+ {
+ FT_Memory memory = manager->library->memory;
+ FT_UInt idx = 0;
+
+
+ /* check for an empty cache slot in the manager's table */
+ for ( idx = 0; idx < FTC_MAX_CACHES; idx++ )
+ {
+ if ( manager->caches[idx] == 0 )
+ break;
+ }
+
+ /* return an error if there are too many registered caches */
+ if ( idx >= FTC_MAX_CACHES )
+ {
+ error = FTC_Err_Too_Many_Caches;
+ FT_ERROR(( "FTC_Manager_Register_Cache:" ));
+ FT_ERROR(( " too many registered caches\n" ));
+ goto Exit;
+ }
+
+ if ( !FT_ALLOC( cache, clazz->cache_size ) )
+ {
+ cache->manager = manager;
+ cache->memory = memory;
+ cache->clazz = clazz;
+
+ /* THIS IS VERY IMPORTANT! IT WILL WRETCH THE MANAGER */
+ /* IF IT IS NOT SET CORRECTLY */
+ cache->cache_index = idx;
+
+ if ( clazz->cache_init )
+ {
+ error = clazz->cache_init( cache );
+ if ( error )
+ {
+ if ( clazz->cache_done )
+ clazz->cache_done( cache );
+
+ FT_FREE( cache );
+ goto Exit;
+ }
+ }
+
+ manager->caches[idx] = cache;
+ }
+ }
+
+ Exit:
+ *acache = cache;
+ return error;
+ }
+
+
+ /* documentation is in ftcmanag.h */
+
+ FT_EXPORT_DEF( void )
+ FTC_Node_Unref( FTC_Node node,
+ FTC_Manager manager )
+ {
+ if ( node && (FT_UInt)node->fam_index < manager->families.count &&
+ manager->families.entries[node->fam_index].cache )
+ {
+ node->ref_count--;
+ }
+ }
+
+
+/* END */
--- /dev/null
+++ b/libfreetype/ftcsbits.c
@@ -1,0 +1,557 @@
+/***************************************************************************/
+/* */
+/* ftcsbits.c */
+/* */
+/* FreeType sbits manager (body). */
+/* */
+/* Copyright 2000-2001, 2002 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+
+#include <ft2build.h>
+#include FT_CACHE_H
+#include FT_CACHE_SMALL_BITMAPS_H
+#include FT_CACHE_INTERNAL_GLYPH_H
+#include FT_INTERNAL_OBJECTS_H
+#include FT_INTERNAL_DEBUG_H
+#include FT_ERRORS_H
+
+#include "ftcerror.h"
+
+
+#define FTC_SBIT_ITEMS_PER_NODE 16
+
+
+ typedef struct FTC_SBitNodeRec_* FTC_SBitNode;
+
+ typedef struct FTC_SBitNodeRec_
+ {
+ FTC_GlyphNodeRec gnode;
+ FTC_SBitRec sbits[FTC_SBIT_ITEMS_PER_NODE];
+
+ } FTC_SBitNodeRec;
+
+
+#define FTC_SBIT_NODE( x ) ( (FTC_SBitNode)( x ) )
+
+
+ typedef struct FTC_SBitQueryRec_
+ {
+ FTC_GlyphQueryRec gquery;
+ FTC_ImageTypeRec type;
+
+ } FTC_SBitQueryRec, *FTC_SBitQuery;
+
+
+#define FTC_SBIT_QUERY( x ) ( (FTC_SBitQuery)( x ) )
+
+
+ typedef struct FTC_SBitFamilyRec_* FTC_SBitFamily;
+
+ /* sbit family structure */
+ typedef struct FTC_SBitFamilyRec_
+ {
+ FTC_GlyphFamilyRec gfam;
+ FTC_ImageTypeRec type;
+
+ } FTC_SBitFamilyRec;
+
+
+#define FTC_SBIT_FAMILY( x ) ( (FTC_SBitFamily)( x ) )
+#define FTC_SBIT_FAMILY_MEMORY( x ) FTC_GLYPH_FAMILY_MEMORY( &( x )->cset )
+
+
+ /*************************************************************************/
+ /*************************************************************************/
+ /***** *****/
+ /***** SBIT CACHE NODES *****/
+ /***** *****/
+ /*************************************************************************/
+ /*************************************************************************/
+
+
+ static FT_Error
+ ftc_sbit_copy_bitmap( FTC_SBit sbit,
+ FT_Bitmap* bitmap,
+ FT_Memory memory )
+ {
+ FT_Error error;
+ FT_Int pitch = bitmap->pitch;
+ FT_ULong size;
+
+
+ if ( pitch < 0 )
+ pitch = -pitch;
+
+ size = (FT_ULong)( pitch * bitmap->rows );
+
+ if ( !FT_ALLOC( sbit->buffer, size ) )
+ FT_MEM_COPY( sbit->buffer, bitmap->buffer, size );
+
+ return error;
+ }
+
+
+ FT_CALLBACK_DEF( void )
+ ftc_sbit_node_done( FTC_SBitNode snode,
+ FTC_Cache cache )
+ {
+ FTC_SBit sbit = snode->sbits;
+ FT_UInt count = FTC_GLYPH_NODE( snode )->item_count;
+ FT_Memory memory = cache->memory;
+
+
+ for ( ; count > 0; sbit++, count-- )
+ FT_FREE( sbit->buffer );
+
+ ftc_glyph_node_done( FTC_GLYPH_NODE( snode ), cache );
+ }
+
+
+ static FT_Error
+ ftc_sbit_node_load( FTC_SBitNode snode,
+ FTC_Manager manager,
+ FTC_SBitFamily sfam,
+ FT_UInt gindex,
+ FT_ULong *asize )
+ {
+ FT_Error error;
+ FTC_GlyphNode gnode = FTC_GLYPH_NODE( snode );
+ FT_Memory memory;
+ FT_Face face;
+ FT_Size size;
+ FTC_SBit sbit;
+
+
+ if ( gindex < (FT_UInt)gnode->item_start ||
+ gindex >= (FT_UInt)gnode->item_start + gnode->item_count )
+ {
+ FT_ERROR(( "ftc_sbit_node_load: invalid glyph index" ));
+ return FTC_Err_Invalid_Argument;
+ }
+
+ memory = manager->library->memory;
+
+ sbit = snode->sbits + ( gindex - gnode->item_start );
+
+ error = FTC_Manager_Lookup_Size( manager, &sfam->type.font,
+ &face, &size );
+ if ( !error )
+ {
+ /* by default, indicates a `missing' glyph */
+ sbit->buffer = 0;
+
+ error = FT_Load_Glyph( face, gindex, sfam->type.flags | FT_LOAD_RENDER );
+ if ( !error )
+ {
+ FT_Int temp;
+ FT_GlyphSlot slot = face->glyph;
+ FT_Bitmap* bitmap = &slot->bitmap;
+ FT_Int xadvance, yadvance;
+
+
+ /* check that our values fit into 8-bit containers! */
+ /* If this is not the case, our bitmap is too large */
+ /* and we will leave it as `missing' with sbit.buffer = 0 */
+
+#define CHECK_CHAR( d ) ( temp = (FT_Char)d, temp == d )
+#define CHECK_BYTE( d ) ( temp = (FT_Byte)d, temp == d )
+
+ /* XXX: FIXME: add support for vertical layouts maybe */
+
+ /* horizontal advance in pixels */
+ xadvance = ( slot->metrics.horiAdvance + 32 ) >> 6;
+ yadvance = ( slot->metrics.vertAdvance + 32 ) >> 6;
+
+ if ( CHECK_BYTE( bitmap->rows ) &&
+ CHECK_BYTE( bitmap->width ) &&
+ CHECK_CHAR( bitmap->pitch ) &&
+ CHECK_CHAR( slot->bitmap_left ) &&
+ CHECK_CHAR( slot->bitmap_top ) &&
+ CHECK_CHAR( xadvance ) &&
+ CHECK_CHAR( yadvance ) )
+ {
+ sbit->width = (FT_Byte)bitmap->width;
+ sbit->height = (FT_Byte)bitmap->rows;
+ sbit->pitch = (FT_Char)bitmap->pitch;
+ sbit->left = (FT_Char)slot->bitmap_left;
+ sbit->top = (FT_Char)slot->bitmap_top;
+ sbit->xadvance = (FT_Char)xadvance;
+ sbit->yadvance = (FT_Char)yadvance;
+ sbit->format = (FT_Byte)bitmap->pixel_mode;
+ sbit->max_grays = (FT_Byte)(bitmap->num_grays - 1);
+
+#if 0 /* this doesn't work well with embedded bitmaps !! */
+
+ /* grab the bitmap when possible - this is a hack! */
+ if ( slot->flags & FT_GLYPH_OWN_BITMAP )
+ {
+ slot->flags &= ~FT_GLYPH_OWN_BITMAP;
+ sbit->buffer = bitmap->buffer;
+ }
+ else
+#endif
+ {
+ /* copy the bitmap into a new buffer -- ignore error */
+ error = ftc_sbit_copy_bitmap( sbit, bitmap, memory );
+ }
+
+ /* now, compute size */
+ if ( asize )
+ *asize = ABS( sbit->pitch ) * sbit->height;
+
+ } /* glyph dimensions ok */
+
+ } /* glyph loading successful */
+
+ /* ignore the errors that might have occurred -- */
+ /* we mark unloaded glyphs with `sbit.buffer == 0' */
+ /* and 'width == 255', 'height == 0' */
+ /* */
+ if ( error )
+ {
+ sbit->width = 255;
+ error = 0;
+ /* sbit->buffer == NULL too! */
+ }
+ }
+
+ return error;
+ }
+
+
+ FT_CALLBACK_DEF( FT_Error )
+ ftc_sbit_node_init( FTC_SBitNode snode,
+ FTC_GlyphQuery gquery,
+ FTC_Cache cache )
+ {
+ FT_Error error;
+
+
+ ftc_glyph_node_init( FTC_GLYPH_NODE( snode ),
+ gquery->gindex,
+ FTC_GLYPH_FAMILY( gquery->query.family ) );
+
+ error = ftc_sbit_node_load( snode,
+ cache->manager,
+ FTC_SBIT_FAMILY( FTC_QUERY( gquery )->family ),
+ gquery->gindex,
+ NULL );
+ if ( error )
+ ftc_glyph_node_done( FTC_GLYPH_NODE( snode ), cache );
+
+ return error;
+ }
+
+
+ FT_CALLBACK_DEF( FT_ULong )
+ ftc_sbit_node_weight( FTC_SBitNode snode )
+ {
+ FTC_GlyphNode gnode = FTC_GLYPH_NODE( snode );
+ FT_UInt count = gnode->item_count;
+ FTC_SBit sbit = snode->sbits;
+ FT_Int pitch;
+ FT_ULong size;
+
+
+ /* the node itself */
+ size = sizeof ( *snode );
+
+ /* the sbit records */
+ size += FTC_GLYPH_NODE( snode )->item_count * sizeof ( FTC_SBitRec );
+
+ for ( ; count > 0; count--, sbit++ )
+ {
+ if ( sbit->buffer )
+ {
+ pitch = sbit->pitch;
+ if ( pitch < 0 )
+ pitch = -pitch;
+
+ /* add the size of a given glyph image */
+ size += pitch * sbit->height;
+ }
+ }
+
+ return size;
+ }
+
+
+ FT_CALLBACK_DEF( FT_Bool )
+ ftc_sbit_node_compare( FTC_SBitNode snode,
+ FTC_SBitQuery squery,
+ FTC_Cache cache )
+ {
+ FTC_GlyphQuery gquery = FTC_GLYPH_QUERY( squery );
+ FTC_GlyphNode gnode = FTC_GLYPH_NODE( snode );
+ FT_Bool result;
+
+
+ result = ftc_glyph_node_compare( gnode, gquery );
+ if ( result )
+ {
+ /* check if we need to load the glyph bitmap now */
+ FT_UInt gindex = gquery->gindex;
+ FTC_SBit sbit = snode->sbits + ( gindex - gnode->item_start );
+
+
+ if ( sbit->buffer == NULL && sbit->width != 255 )
+ {
+ FT_ULong size;
+
+
+ /* yes, it's safe to ignore errors here */
+ ftc_sbit_node_load( snode,
+ cache->manager,
+ FTC_SBIT_FAMILY( FTC_QUERY( squery )->family ),
+ gindex,
+ &size );
+
+ cache->manager->cur_weight += size;
+ }
+ }
+
+ return result;
+ }
+
+
+ /*************************************************************************/
+ /*************************************************************************/
+ /***** *****/
+ /***** SBITS FAMILIES *****/
+ /***** *****/
+ /*************************************************************************/
+ /*************************************************************************/
+
+
+ FT_CALLBACK_DEF( FT_Error )
+ ftc_sbit_family_init( FTC_SBitFamily sfam,
+ FTC_SBitQuery squery,
+ FTC_Cache cache )
+ {
+ FTC_Manager manager = cache->manager;
+ FT_Error error;
+ FT_Face face;
+
+
+ sfam->type = squery->type;
+
+ /* we need to compute "cquery.item_total" now */
+ error = FTC_Manager_Lookup_Face( manager,
+ squery->type.font.face_id,
+ &face );
+ if ( !error )
+ {
+ error = ftc_glyph_family_init( FTC_GLYPH_FAMILY( sfam ),
+ FTC_IMAGE_TYPE_HASH( &sfam->type ),
+ FTC_SBIT_ITEMS_PER_NODE,
+ face->num_glyphs,
+ FTC_GLYPH_QUERY( squery ),
+ cache );
+ }
+
+ return error;
+ }
+
+
+ FT_CALLBACK_DEF( FT_Bool )
+ ftc_sbit_family_compare( FTC_SBitFamily sfam,
+ FTC_SBitQuery squery )
+ {
+ FT_Bool result;
+
+
+ /* we need to set the "cquery.cset" field or our query for */
+ /* faster glyph comparisons in ftc_sbit_node_compare */
+ /* */
+ result = FT_BOOL( FTC_IMAGE_TYPE_COMPARE( &sfam->type, &squery->type ) );
+ if ( result )
+ FTC_GLYPH_FAMILY_FOUND( sfam, squery );
+
+ return result;
+ }
+
+
+ /*************************************************************************/
+ /*************************************************************************/
+ /***** *****/
+ /***** SBITS CACHE *****/
+ /***** *****/
+ /*************************************************************************/
+ /*************************************************************************/
+
+
+ FT_CALLBACK_TABLE_DEF
+ const FTC_Cache_ClassRec ftc_sbit_cache_class =
+ {
+ sizeof ( FTC_CacheRec ),
+ (FTC_Cache_InitFunc) ftc_cache_init,
+ (FTC_Cache_ClearFunc)ftc_cache_clear,
+ (FTC_Cache_DoneFunc) ftc_cache_done,
+
+ sizeof ( FTC_SBitFamilyRec ),
+ (FTC_Family_InitFunc) ftc_sbit_family_init,
+ (FTC_Family_CompareFunc)ftc_sbit_family_compare,
+ (FTC_Family_DoneFunc) ftc_glyph_family_done,
+
+ sizeof ( FTC_SBitNodeRec ),
+ (FTC_Node_InitFunc) ftc_sbit_node_init,
+ (FTC_Node_WeightFunc) ftc_sbit_node_weight,
+ (FTC_Node_CompareFunc)ftc_sbit_node_compare,
+ (FTC_Node_DoneFunc) ftc_sbit_node_done
+ };
+
+
+ /* documentation is in ftcsbits.h */
+
+ FT_EXPORT_DEF( FT_Error )
+ FTC_SBitCache_New( FTC_Manager manager,
+ FTC_SBitCache *acache )
+ {
+ return FTC_Manager_Register_Cache( manager,
+ &ftc_sbit_cache_class,
+ (FTC_Cache*)acache );
+ }
+
+
+ /* documentation is in ftcsbits.h */
+
+#ifdef FTC_CACHE_USE_INLINE
+
+#define GEN_CACHE_FAMILY_COMPARE( f, q, c ) \
+ ftc_sbit_family_compare( (FTC_SBitFamily)(f), (FTC_SBitQuery)(q) )
+
+#define GEN_CACHE_NODE_COMPARE( n, q, c ) \
+ ftc_sbit_node_compare( (FTC_SBitNode)(n), (FTC_SBitQuery)(q), c )
+
+#define GEN_CACHE_LOOKUP ftc_sbit_cache_lookup
+#include "ftccache.i"
+
+#else /* !FTC_CACHE_USE_INLINE */
+
+#define ftc_sbit_cache_lookup ftc_cache_lookup
+
+#endif /* !FTC_CACHE_USE_INLINE */
+
+ FT_EXPORT_DEF( FT_Error )
+ FTC_SBitCache_Lookup( FTC_SBitCache cache,
+ FTC_ImageType type,
+ FT_UInt gindex,
+ FTC_SBit *ansbit,
+ FTC_Node *anode )
+ {
+ FT_Error error;
+ FTC_SBitQueryRec squery;
+ FTC_SBitNode node;
+
+
+ /* other argument checks delayed to ftc_cache_lookup */
+ if ( !ansbit )
+ return FTC_Err_Invalid_Argument;
+
+ *ansbit = NULL;
+
+ if ( anode )
+ *anode = NULL;
+
+ squery.gquery.gindex = gindex;
+ squery.type = *type;
+
+ error = ftc_sbit_cache_lookup( FTC_CACHE( cache ),
+ FTC_QUERY( &squery ),
+ (FTC_Node*)&node );
+ if ( !error )
+ {
+ *ansbit = node->sbits + ( gindex - FTC_GLYPH_NODE( node )->item_start );
+
+ if ( anode )
+ {
+ *anode = FTC_NODE( node );
+ FTC_NODE( node )->ref_count++;
+ }
+ }
+ return error;
+ }
+
+
+ /* backwards-compatibility functions */
+
+ FT_EXPORT_DEF( FT_Error )
+ FTC_SBit_Cache_New( FTC_Manager manager,
+ FTC_SBit_Cache *acache )
+ {
+ return FTC_SBitCache_New( manager, (FTC_SBitCache*)acache );
+ }
+
+
+ FT_EXPORT_DEF( FT_Error )
+ FTC_SBit_Cache_Lookup( FTC_SBit_Cache cache,
+ FTC_Image_Desc* desc,
+ FT_UInt gindex,
+ FTC_SBit *ansbit )
+ {
+ FTC_ImageTypeRec type0;
+
+
+ if ( !desc )
+ return FTC_Err_Invalid_Argument;
+
+ type0.font = desc->font;
+ type0.flags = 0;
+
+ /* convert image type flags to load flags */
+ {
+ FT_UInt load_flags = FT_LOAD_DEFAULT;
+ FT_UInt type = desc->image_type;
+
+
+ /* determine load flags, depending on the font description's */
+ /* image type */
+
+ if ( ftc_image_format( type ) == ftc_image_format_bitmap )
+ {
+ if ( type & ftc_image_flag_monochrome )
+ load_flags |= FT_LOAD_MONOCHROME;
+
+ /* disable embedded bitmaps loading if necessary */
+ if ( type & ftc_image_flag_no_sbits )
+ load_flags |= FT_LOAD_NO_BITMAP;
+ }
+ else
+ {
+ /* we want an outline, don't load embedded bitmaps */
+ load_flags |= FT_LOAD_NO_BITMAP;
+
+ if ( type & ftc_image_flag_unscaled )
+ load_flags |= FT_LOAD_NO_SCALE;
+ }
+
+ /* always render glyphs to bitmaps */
+ load_flags |= FT_LOAD_RENDER;
+
+ if ( type & ftc_image_flag_unhinted )
+ load_flags |= FT_LOAD_NO_HINTING;
+
+ if ( type & ftc_image_flag_autohinted )
+ load_flags |= FT_LOAD_FORCE_AUTOHINT;
+
+ type0.flags = load_flags;
+ }
+
+ return FTC_SBitCache_Lookup( (FTC_SBitCache)cache,
+ &type0,
+ gindex,
+ ansbit,
+ NULL );
+ }
+
+
+/* END */
--- /dev/null
+++ b/libfreetype/ftdbgmem.c
@@ -1,0 +1,672 @@
+/***************************************************************************/
+/* */
+/* ftdbgmem.c */
+/* */
+/* Memory debugger (body). */
+/* */
+/* Copyright 2001, 2002 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+
+#include <ft2build.h>
+#include FT_CONFIG_CONFIG_H
+#include FT_INTERNAL_DEBUG_H
+#include FT_INTERNAL_MEMORY_H
+#include FT_SYSTEM_H
+#include FT_ERRORS_H
+#include FT_TYPES_H
+
+
+#ifdef FT_DEBUG_MEMORY
+
+
+#include <stdio.h>
+#include <stdlib.h>
+
+
+ typedef struct FT_MemNodeRec_* FT_MemNode;
+ typedef struct FT_MemTableRec_* FT_MemTable;
+
+#define FT_MEM_VAL( addr ) ((FT_ULong)(FT_Pointer)( addr ))
+
+ typedef struct FT_MemNodeRec_
+ {
+ FT_Byte* address;
+ FT_Long size; /* < 0 if the block was freed */
+
+ const char* alloc_file_name;
+ FT_Long alloc_line_no;
+
+ const char* free_file_name;
+ FT_Long free_line_no;
+
+ FT_MemNode link;
+
+ } FT_MemNodeRec;
+
+
+ typedef struct FT_MemTableRec_
+ {
+ FT_ULong size;
+ FT_ULong nodes;
+ FT_MemNode* buckets;
+
+ FT_ULong alloc_total;
+ FT_ULong alloc_current;
+ FT_ULong alloc_max;
+
+ const char* file_name;
+ FT_Long line_no;
+
+ FT_Memory memory;
+ FT_Pointer memory_user;
+ FT_Alloc_Func alloc;
+ FT_Free_Func free;
+ FT_Realloc_Func realloc;
+
+ } FT_MemTableRec;
+
+
+#define FT_MEM_SIZE_MIN 7
+#define FT_MEM_SIZE_MAX 13845163
+
+#define FT_FILENAME( x ) ((x) ? (x) : "unknown file")
+
+
+ static const FT_UInt ft_mem_primes[] =
+ {
+ 7,
+ 11,
+ 19,
+ 37,
+ 73,
+ 109,
+ 163,
+ 251,
+ 367,
+ 557,
+ 823,
+ 1237,
+ 1861,
+ 2777,
+ 4177,
+ 6247,
+ 9371,
+ 14057,
+ 21089,
+ 31627,
+ 47431,
+ 71143,
+ 106721,
+ 160073,
+ 240101,
+ 360163,
+ 540217,
+ 810343,
+ 1215497,
+ 1823231,
+ 2734867,
+ 4102283,
+ 6153409,
+ 9230113,
+ 13845163,
+ };
+
+
+
+ extern void
+ ft_mem_debug_panic( const char* fmt, ... )
+ {
+ va_list ap;
+
+
+ printf( "FreeType.Debug: " );
+
+ va_start( ap, fmt );
+ vprintf( fmt, ap );
+ va_end( ap );
+
+ printf( "\n" );
+ exit( EXIT_FAILURE );
+ }
+
+
+ static FT_ULong
+ ft_mem_closest_prime( FT_ULong num )
+ {
+ FT_UInt i;
+
+
+ for ( i = 0;
+ i < sizeof ( ft_mem_primes ) / sizeof ( ft_mem_primes[0] ); i++ )
+ if ( ft_mem_primes[i] > num )
+ return ft_mem_primes[i];
+
+ return FT_MEM_SIZE_MAX;
+ }
+
+
+ static FT_Pointer
+ ft_mem_table_alloc( FT_MemTable table,
+ FT_Long size )
+ {
+ FT_Memory memory = table->memory;
+ FT_Pointer block;
+
+
+ memory->user = table->memory_user;
+ block = table->alloc( memory, size );
+ memory->user = table;
+
+ return block;
+ }
+
+
+ static void
+ ft_mem_table_free( FT_MemTable table,
+ FT_Pointer block )
+ {
+ FT_Memory memory = table->memory;
+
+
+ memory->user = table->memory_user;
+ table->free( memory, block );
+ memory->user = table;
+ }
+
+
+ static void
+ ft_mem_table_resize( FT_MemTable table )
+ {
+ FT_ULong new_size;
+
+
+ new_size = ft_mem_closest_prime( table->nodes );
+ if ( new_size != table->size )
+ {
+ FT_MemNode* new_buckets ;
+ FT_ULong i;
+
+
+ new_buckets = (FT_MemNode *)
+ ft_mem_table_alloc( table,
+ new_size * sizeof ( FT_MemNode ) );
+ if ( new_buckets == NULL )
+ return;
+
+ FT_MEM_ZERO( new_buckets, sizeof ( FT_MemNode ) * new_size );
+
+ for ( i = 0; i < table->size; i++ )
+ {
+ FT_MemNode node, next, *pnode;
+ FT_ULong hash;
+
+
+ node = table->buckets[i];
+ while ( node )
+ {
+ next = node->link;
+ hash = FT_MEM_VAL( node->address ) % new_size;
+ pnode = new_buckets + hash;
+
+ node->link = pnode[0];
+ pnode[0] = node;
+
+ node = next;
+ }
+ }
+
+ if ( table->buckets )
+ ft_mem_table_free( table, table->buckets );
+
+ table->buckets = new_buckets;
+ table->size = new_size;
+ }
+ }
+
+
+ static FT_MemTable
+ ft_mem_table_new( FT_Memory memory )
+ {
+ FT_MemTable table;
+
+
+ table = (FT_MemTable)memory->alloc( memory, sizeof ( *table ) );
+ if ( table == NULL )
+ goto Exit;
+
+ FT_MEM_ZERO( table, sizeof ( *table ) );
+
+ table->size = FT_MEM_SIZE_MIN;
+ table->nodes = 0;
+
+ table->memory = memory;
+
+ table->memory_user = memory->user;
+
+ table->alloc = memory->alloc;
+ table->realloc = memory->realloc;
+ table->free = memory->free;
+
+ table->buckets = (FT_MemNode *)
+ memory->alloc( memory,
+ table->size * sizeof ( FT_MemNode ) );
+ if ( table->buckets )
+ FT_MEM_ZERO( table->buckets, sizeof ( FT_MemNode ) * table->size );
+ else
+ {
+ memory->free( memory, table );
+ table = NULL;
+ }
+
+ Exit:
+ return table;
+ }
+
+
+ static void
+ ft_mem_table_destroy( FT_MemTable table )
+ {
+ FT_ULong i;
+
+
+ if ( table )
+ {
+ FT_Long leak_count = 0;
+ FT_ULong leaks = 0;
+
+
+ for ( i = 0; i < table->size; i++ )
+ {
+ FT_MemNode *pnode = table->buckets + i, next, node = *pnode;
+
+
+ while ( node )
+ {
+ next = node->link;
+ node->link = 0;
+
+ if ( node->size > 0 )
+ {
+ printf(
+ "leaked memory block at address %p, size %8ld in (%s:%ld)\n",
+ node->address, node->size,
+ FT_FILENAME( node->alloc_file_name ),
+ node->alloc_line_no );
+
+ leak_count++;
+ leaks += node->size;
+
+ ft_mem_table_free( table, node->address );
+ }
+
+ node->address = NULL;
+ node->size = 0;
+
+ free( node );
+ node = next;
+ }
+ table->buckets[i] = 0;
+ }
+ ft_mem_table_free( table, table->buckets );
+ table->buckets = NULL;
+
+ table->size = 0;
+ table->nodes = 0;
+
+ printf(
+ "FreeType: total memory allocations = %ld\n", table->alloc_total );
+ printf(
+ "FreeType: maximum memory footprint = %ld\n", table->alloc_max );
+
+ free( table );
+
+ if ( leak_count > 0 )
+ ft_mem_debug_panic(
+ "FreeType: %ld bytes of memory leaked in %ld blocks\n",
+ leaks, leak_count );
+ printf( "FreeType: No memory leaks detected!\n" );
+ }
+ }
+
+
+ static FT_MemNode*
+ ft_mem_table_get_nodep( FT_MemTable table,
+ FT_Byte* address )
+ {
+ FT_ULong hash;
+ FT_MemNode *pnode, node;
+
+
+ hash = FT_MEM_VAL( address );
+ pnode = table->buckets + ( hash % table->size );
+
+ for (;;)
+ {
+ node = pnode[0];
+ if ( !node )
+ break;
+
+ if ( node->address == address )
+ break;
+
+ pnode = &node->link;
+ }
+ return pnode;
+ }
+
+
+ static void
+ ft_mem_table_set( FT_MemTable table,
+ FT_Byte* address,
+ FT_ULong size )
+ {
+ FT_MemNode *pnode, node;
+
+
+ if ( table )
+ {
+ pnode = ft_mem_table_get_nodep( table, address );
+ node = *pnode;
+ if ( node )
+ {
+ if ( node->size < 0 )
+ {
+ /* this block was already freed. This means that our memory is */
+ /* now completely corrupted! */
+ ft_mem_debug_panic(
+ "memory heap corrupted (allocating freed block)" );
+ }
+ else
+ {
+ /* this block was already allocated. This means that our memory */
+ /* is also corrupted! */
+ ft_mem_debug_panic(
+ "memory heap corrupted (re-allocating allocated block)" );
+ }
+ }
+
+ /* we need to create a new node in this table */
+ node = (FT_MemNode)ft_mem_table_alloc( table, sizeof ( *node ) );
+ if ( node == NULL )
+ ft_mem_debug_panic( "not enough memory to run memory tests" );
+
+ node->address = address;
+ node->size = size;
+
+ node->alloc_file_name = table->file_name;
+ node->alloc_line_no = table->line_no;
+
+ node->free_file_name = NULL;
+ node->free_line_no = 0;
+
+ node->link = pnode[0];
+
+ pnode[0] = node;
+ table->nodes++;
+
+ table->alloc_total += size;
+ table->alloc_current += size;
+ if ( table->alloc_current > table->alloc_max )
+ table->alloc_max = table->alloc_current;
+
+ if ( table->nodes * 3 < table->size ||
+ table->size * 3 < table->nodes )
+ ft_mem_table_resize( table );
+ }
+ }
+
+
+ static void
+ ft_mem_table_remove( FT_MemTable table,
+ FT_Byte* address )
+ {
+ if ( table )
+ {
+ FT_MemNode *pnode, node;
+
+
+ pnode = ft_mem_table_get_nodep( table, address );
+ node = *pnode;
+ if ( node )
+ {
+ if ( node->size < 0 )
+ ft_mem_debug_panic(
+ "freeing memory block at %p more than once at (%s:%ld)\n"
+ "block allocated at (%s:%ld) and released at (%s:%ld)",
+ address,
+ FT_FILENAME( table->file_name ), table->line_no,
+ FT_FILENAME( node->alloc_file_name ), node->alloc_line_no,
+ FT_FILENAME( node->free_file_name ), node->free_line_no );
+
+ /* we simply invert the node's size to indicate that the node */
+ /* was freed. We also change its contents. */
+ FT_MEM_SET( address, 0xF3, node->size );
+
+ table->alloc_current -= node->size;
+ node->size = -node->size;
+ node->free_file_name = table->file_name;
+ node->free_line_no = table->line_no;
+ }
+ else
+ ft_mem_debug_panic(
+ "trying to free unknown block at %p in (%s:%ld)\n",
+ address,
+ FT_FILENAME( table->file_name ), table->line_no );
+ }
+ }
+
+
+ extern FT_Pointer
+ ft_mem_debug_alloc( FT_Memory memory,
+ FT_Long size )
+ {
+ FT_MemTable table = (FT_MemTable)memory->user;
+ FT_Byte* block;
+
+
+ if ( size <= 0 )
+ ft_mem_debug_panic( "negative block size allocation (%ld)", size );
+
+ block = (FT_Byte *)ft_mem_table_alloc( table, size );
+ if ( block )
+ ft_mem_table_set( table, block, (FT_ULong)size );
+
+ table->file_name = NULL;
+ table->line_no = 0;
+
+ return (FT_Pointer) block;
+ }
+
+
+ extern void
+ ft_mem_debug_free( FT_Memory memory,
+ FT_Pointer block )
+ {
+ FT_MemTable table = (FT_MemTable)memory->user;
+
+
+ if ( block == NULL )
+ ft_mem_debug_panic( "trying to free NULL in (%s:%ld)",
+ FT_FILENAME( table->file_name ),
+ table->line_no );
+
+ ft_mem_table_remove( table, (FT_Byte*)block );
+
+ /* we never really free the block */
+ table->file_name = NULL;
+ table->line_no = 0;
+ }
+
+
+ extern FT_Pointer
+ ft_mem_debug_realloc( FT_Memory memory,
+ FT_Long cur_size,
+ FT_Long new_size,
+ FT_Pointer block )
+ {
+ FT_MemTable table = (FT_MemTable)memory->user;
+ FT_MemNode node, *pnode;
+ FT_Pointer new_block;
+
+ const char* file_name = FT_FILENAME( table->file_name );
+ FT_Long line_no = table->line_no;
+
+
+ if ( block == NULL || cur_size == 0 )
+ ft_mem_debug_panic( "trying to reallocate NULL in (%s:%ld)",
+ file_name, line_no );
+
+ if ( new_size <= 0 )
+ ft_mem_debug_panic(
+ "trying to reallocate %p to size 0 (current is %ld) in (%s:%ld)",
+ block, cur_size, file_name, line_no );
+
+ /* check 'cur_size' value */
+ pnode = ft_mem_table_get_nodep( table, (FT_Byte*)block );
+ node = *pnode;
+ if ( !node )
+ ft_mem_debug_panic(
+ "trying to reallocate unknown block at %p in (%s:%ld)",
+ block, file_name, line_no );
+
+ if ( node->size <= 0 )
+ ft_mem_debug_panic(
+ "trying to reallocate freed block at %p in (%s:%ld)",
+ block, file_name, line_no );
+
+ if ( node->size != cur_size )
+ ft_mem_debug_panic( "invalid ft_realloc request for %p. cur_size is "
+ "%ld instead of %ld in (%s:%ld)",
+ block, cur_size, node->size, file_name, line_no );
+
+ new_block = ft_mem_debug_alloc( memory, new_size );
+ if ( new_block == NULL )
+ return NULL;
+
+ ft_memcpy( new_block, block, cur_size < new_size ? cur_size : new_size );
+
+ table->file_name = file_name;
+ table->line_no = line_no;
+
+ ft_mem_debug_free( memory, (FT_Byte*)block );
+
+ return new_block;
+ }
+
+
+ extern FT_Int
+ ft_mem_debug_init( FT_Memory memory )
+ {
+ FT_MemTable table;
+ FT_Int result = 0;
+
+
+ if ( getenv( "FT_DEBUG_MEMORY" ) )
+ {
+ table = ft_mem_table_new( memory );
+ if ( table )
+ {
+ memory->user = table;
+ memory->alloc = ft_mem_debug_alloc;
+ memory->realloc = ft_mem_debug_realloc;
+ memory->free = ft_mem_debug_free;
+ result = 1;
+ }
+ }
+ return result;
+ }
+
+
+ extern void
+ ft_mem_debug_done( FT_Memory memory )
+ {
+ FT_MemTable table = (FT_MemTable)memory->user;
+
+
+ if ( table )
+ {
+ memory->free = table->free;
+ memory->realloc = table->realloc;
+ memory->alloc = table->alloc;
+
+ ft_mem_table_destroy( table );
+ memory->user = NULL;
+ }
+ }
+
+
+ FT_BASE_DEF( FT_Error )
+ FT_Alloc_Debug( FT_Memory memory,
+ FT_Long size,
+ void* *P,
+ const char* file_name,
+ FT_Long line_no )
+ {
+ FT_MemTable table = (FT_MemTable)memory->user;
+
+
+ if ( table )
+ {
+ table->file_name = file_name;
+ table->line_no = line_no;
+ }
+ return FT_Alloc( memory, size, P );
+ }
+
+
+ FT_BASE_DEF( FT_Error )
+ FT_Realloc_Debug( FT_Memory memory,
+ FT_Long current,
+ FT_Long size,
+ void* *P,
+ const char* file_name,
+ FT_Long line_no )
+ {
+ FT_MemTable table = (FT_MemTable)memory->user;
+
+
+ if ( table )
+ {
+ table->file_name = file_name;
+ table->line_no = line_no;
+ }
+ return FT_Realloc( memory, current, size, P );
+ }
+
+
+ FT_BASE_DEF( void )
+ FT_Free_Debug( FT_Memory memory,
+ FT_Pointer block,
+ const char* file_name,
+ FT_Long line_no )
+ {
+ FT_MemTable table = (FT_MemTable)memory->user;
+
+
+ if ( table )
+ {
+ table->file_name = file_name;
+ table->line_no = line_no;
+ }
+ FT_Free( memory, (void **)block );
+ }
+
+
+#else /* !FT_DEBUG_MEMORY */
+
+ /* ANSI C doesn't like empty source files */
+ const FT_Byte _debug_mem_dummy = 0;
+
+#endif /* !FT_DEBUG_MEMORY */
+
+
+/* END */
--- /dev/null
+++ b/libfreetype/ftdebug.c
@@ -1,0 +1,197 @@
+/***************************************************************************/
+/* */
+/* ftdebug.c */
+/* */
+/* Debugging and logging component (body). */
+/* */
+/* Copyright 1996-2001 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+
+ /*************************************************************************/
+ /* */
+ /* This component contains various macros and functions used to ease the */
+ /* debugging of the FreeType engine. Its main purpose is in assertion */
+ /* checking, tracing, and error detection. */
+ /* */
+ /* There are now three debugging modes: */
+ /* */
+ /* - trace mode */
+ /* */
+ /* Error and trace messages are sent to the log file (which can be the */
+ /* standard error output). */
+ /* */
+ /* - error mode */
+ /* */
+ /* Only error messages are generated. */
+ /* */
+ /* - release mode: */
+ /* */
+ /* No error message is sent or generated. The code is free from any */
+ /* debugging parts. */
+ /* */
+ /*************************************************************************/
+
+
+#include <ft2build.h>
+#include FT_FREETYPE_H
+#include FT_INTERNAL_DEBUG_H
+
+
+#if defined( FT_DEBUG_LEVEL_ERROR )
+
+ FT_EXPORT_DEF( void )
+ FT_Message( const char* fmt, ... )
+ {
+ va_list ap;
+
+
+ va_start( ap, fmt );
+ vprintf( fmt, ap );
+ va_end( ap );
+ }
+
+
+ FT_EXPORT_DEF( void )
+ FT_Panic( const char* fmt, ... )
+ {
+ va_list ap;
+
+
+ va_start( ap, fmt );
+ vprintf( fmt, ap );
+ va_end( ap );
+
+ exit( EXIT_FAILURE );
+ }
+
+#endif /* FT_DEBUG_LEVEL_ERROR */
+
+
+
+#ifdef FT_DEBUG_LEVEL_TRACE
+
+ /* array of trace levels, initialized to 0 */
+ int ft_trace_levels[trace_count];
+
+ /* define array of trace toggle names */
+#define FT_TRACE_DEF(x) #x ,
+
+ static const char* ft_trace_toggles[trace_count + 1] =
+ {
+#include FT_INTERNAL_TRACE_H
+ NULL
+ };
+
+#undef FT_TRACE_DEF
+
+
+ /*************************************************************************/
+ /* */
+ /* Initialize the tracing sub-system. This is done by retrieving the */
+ /* value of the "FT2_DEBUG" environment variable. It must be a list of */
+ /* toggles, separated by spaces, `;' or `,'. Example: */
+ /* */
+ /* "any:3 memory:6 stream:5" */
+ /* */
+ /* This will request that all levels be set to 3, except the trace level */
+ /* for the memory and stream components which are set to 6 and 5, */
+ /* respectively. */
+ /* */
+ /* See the file <freetype/internal/fttrace.h> for details of the */
+ /* available toggle names. */
+ /* */
+ /* The level must be between 0 and 6; 0 means quiet (except for serious */
+ /* runtime errors), and 6 means _very_ verbose. */
+ /* */
+ FT_BASE_DEF( void )
+ ft_debug_init( void )
+ {
+ const char* ft2_debug = getenv( "FT2_DEBUG" );
+
+ if ( ft2_debug )
+ {
+ const char* p = ft2_debug;
+ const char* q;
+
+
+ for ( ; *p; p++ )
+ {
+ /* skip leading whitespace and separators */
+ if ( *p == ' ' || *p == '\t' || *p == ',' || *p == ';' || *p == '=' )
+ continue;
+
+ /* read toggle name, followed by ':' */
+ q = p;
+ while ( *p && *p != ':' )
+ p++;
+
+ if ( *p == ':' && p > q )
+ {
+ FT_Int n, i, len = (FT_Int)(p - q);
+ FT_Int level = -1, found = -1;
+
+
+ for ( n = 0; n < trace_count; n++ )
+ {
+ const char* toggle = ft_trace_toggles[n];
+
+
+ for ( i = 0; i < len; i++ )
+ {
+ if ( toggle[i] != q[i] )
+ break;
+ }
+
+ if ( i == len && toggle[i] == 0 )
+ {
+ found = n;
+ break;
+ }
+ }
+
+ /* read level */
+ p++;
+ if ( *p )
+ {
+ level = *p++ - '0';
+ if ( level < 0 || level > 6 )
+ level = -1;
+ }
+
+ if ( found >= 0 && level >= 0 )
+ {
+ if ( found == trace_any )
+ {
+ /* special case for "any" */
+ for ( n = 0; n < trace_count; n++ )
+ ft_trace_levels[n] = level;
+ }
+ else
+ ft_trace_levels[found] = level;
+ }
+ }
+ }
+ }
+ }
+
+#else /* !FT_DEBUG_LEVEL_TRACE */
+
+ FT_BASE_DEF( void )
+ ft_debug_init( void )
+ {
+ /* nothing */
+ }
+
+#endif /* !FT_DEBUG_LEVEL_TRACE */
+
+
+/* END */
--- /dev/null
+++ b/libfreetype/ftexcept.c
@@ -1,0 +1,197 @@
+#include <ft2build.h>
+#include FT_EXCEPT_H
+
+
+ FT_BASE_DEF( void )
+ ft_cleanup_stack_init( FT_CleanupStack stack,
+ FT_Memory memory )
+ {
+ stack->chunk = &stack->chunk_0;
+ stack->top = stack->chunk->items;
+ stack->limit = stack->top + FT_CLEANUP_CHUNK_SIZE;
+ stack->chunk_0.link = NULL;
+
+ stack->memory = memory;
+ }
+
+
+
+ FT_BASE_DEF( void )
+ ft_cleanup_stack_done( FT_CleanupStack stack )
+ {
+ FT_Memory memory = stack->memory;
+ FT_CleanupChunk chunk, next;
+
+ for (;;)
+ {
+ chunk = stack->chunk;
+ if ( chunk == &stack->chunk_0 )
+ break;
+
+ stack->chunk = chunk->link;
+
+ FT_Free( chunk, memory );
+ }
+
+ stack->memory = NULL;
+ }
+
+
+
+ FT_BASE_DEF( void )
+ ft_cleanup_stack_push( FT_CleanupStack stack,
+ FT_Pointer item,
+ FT_CleanupFunc item_func,
+ FT_Pointer item_data )
+ {
+ FT_CleanupItem top;
+
+
+ FT_ASSERT( stack && stack->chunk && stack->top );
+ FT_ASSERT( item && item_func );
+
+ top = stack->top;
+
+ top->item = item;
+ top->item_func = item_func;
+ top->item_data = item_data;
+
+ top ++;
+
+ if ( top == stack->limit )
+ {
+ FT_CleanupChunk chunk;
+
+ chunk = FT_QAlloc( sizeof(*chunk), stack->memory );
+
+ chunk->link = stack->chunk;
+ stack->chunk = chunk;
+ stack->limit = chunk->items + FT_CLEANUP_CHUNK_SIZE;
+ top = chunk->items;
+ }
+
+ stack->top = top;
+ }
+
+
+
+ FT_BASE_DEF( void )
+ ft_cleanup_stack_pop( FT_CleanupStack stack,
+ FT_Int destroy )
+ {
+ FT_CleanupItem top;
+
+
+ FT_ASSERT( stack && stack->chunk && stack->top );
+ top = stack->top;
+
+ if ( top == stack->chunk->items )
+ {
+ FT_CleanupChunk chunk;
+
+ chunk = stack->chunk;
+
+ if ( chunk == &stack->chunk_0 )
+ {
+ FT_ERROR(( "cleanup.pop: empty cleanup stack !!\n" ));
+ ft_cleanup_throw( stack, FT_Err_EmptyCleanupStack );
+ }
+
+ chunk = chunk->link;
+ FT_QFree( stack->chunk, stack->memory );
+
+ stack->chunk = chunk;
+ stack->limit = chunk->items + FT_CLEANUP_CHUNK_SIZE;
+ top = stack->limit;
+ }
+
+ top --;
+
+ if ( destroy )
+ top->item_func( top->item, top->item_data );
+
+ top->item = NULL;
+ top->item_func = NULL;
+ top->item_data = NULL;
+
+ stack->top = top;
+ }
+
+
+
+ FT_BASE_DEF( FT_CleanupItem )
+ ft_cleanup_stack_peek( FT_CleanupStack stack )
+ {
+ FT_CleanupItem top;
+ FT_CleanupChunk chunk;
+
+
+ FT_ASSERT( stack && stack->chunk && stack->top );
+
+ top = stack->top;
+ chunk = stack->chunk;
+
+ if ( top > chunk->items )
+ top--;
+ else
+ {
+ chunk = chunk->link;
+ top = NULL;
+ if ( chunk != NULL )
+ top = chunk->items + FT_CLEANUP_CHUNK_SIZE - 1;
+ }
+ return top;
+ }
+
+
+
+ FT_BASE_DEF( void )
+ ft_xhandler_enter( FT_XHandler xhandler,
+ FT_Memory memory )
+ {
+ FT_CleanupStack stack = FT_MEMORY__CLEANUP(memory);
+
+ xhandler->previous = stack->xhandler;
+ xhandler->cleanup = stack->top;
+ xhandler->error = 0;
+ stack->xhandler = xhandler;
+ }
+
+
+
+ FT_BASE_DEF( void )
+ ft_xhandler_exit( FT_XHandler xhandler )
+ {
+ FT_CleanupStack stack = FT_MEMORY__CLEANUP(memory);
+
+ stack->xhandler = xhandler->previous;
+ xhandler->previous = NULL;
+ xhandler->error = error;
+ xhandler->cleanup = NULL;
+ }
+
+
+
+ FT_BASE_DEF( void )
+ ft_cleanup_throw( FT_CleanupStack stack,
+ FT_Error error )
+ {
+ FT_XHandler xhandler = stack->xhandler;
+
+ if ( xhandler == NULL )
+ {
+ /* no exception handler was registered. this */
+ /* means that we have an un-handled exception */
+ /* the only thing we can do is _PANIC_ and */
+ /* halt the current program.. */
+ /* */
+ FT_ERROR(( "FREETYPE PANIC: An un-handled exception occured. Program aborted" ));
+ ft_exit(1);
+ }
+
+ /* cleanup the stack until we reach the handler's */
+ /* starting stack location.. */
+
+ xhandler->error = error;
+ longmp( xhandler->jump_buffer, 1 );
+ }
\ No newline at end of file
--- /dev/null
+++ b/libfreetype/ftgloadr.c
@@ -1,0 +1,361 @@
+/***************************************************************************/
+/* */
+/* ftgloadr.c */
+/* */
+/* The FreeType glyph loader (body). */
+/* */
+/* Copyright 2002 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+
+#include <ft2build.h>
+#include FT_INTERNAL_GLYPH_LOADER_H
+#include FT_INTERNAL_MEMORY_H
+
+#undef FT_COMPONENT
+#define FT_COMPONENT trace_gloader
+
+
+ /*************************************************************************/
+ /*************************************************************************/
+ /*************************************************************************/
+ /***** *****/
+ /***** *****/
+ /***** G L Y P H L O A D E R *****/
+ /***** *****/
+ /***** *****/
+ /*************************************************************************/
+ /*************************************************************************/
+ /*************************************************************************/
+
+ /*************************************************************************/
+ /* */
+ /* The glyph loader is a simple object which is used to load a set of */
+ /* glyphs easily. It is critical for the correct loading of composites. */
+ /* */
+ /* Ideally, one can see it as a stack of abstract `glyph' objects. */
+ /* */
+ /* loader.base Is really the bottom of the stack. It describes a */
+ /* single glyph image made of the juxtaposition of */
+ /* several glyphs (those `in the stack'). */
+ /* */
+ /* loader.current Describes the top of the stack, on which a new */
+ /* glyph can be loaded. */
+ /* */
+ /* Rewind Clears the stack. */
+ /* Prepare Set up `loader.current' for addition of a new glyph */
+ /* image. */
+ /* Add Add the `current' glyph image to the `base' one, */
+ /* and prepare for another one. */
+ /* */
+ /* The glyph loader is now a base object. Each driver used to */
+ /* re-implement it in one way or the other, which wasted code and */
+ /* energy. */
+ /* */
+ /*************************************************************************/
+
+
+ /* create a new glyph loader */
+ FT_BASE_DEF( FT_Error )
+ FT_GlyphLoader_New( FT_Memory memory,
+ FT_GlyphLoader *aloader )
+ {
+ FT_GlyphLoader loader;
+ FT_Error error;
+
+
+ if ( !FT_NEW( loader ) )
+ {
+ loader->memory = memory;
+ *aloader = loader;
+ }
+ return error;
+ }
+
+
+ /* rewind the glyph loader - reset counters to 0 */
+ FT_BASE_DEF( void )
+ FT_GlyphLoader_Rewind( FT_GlyphLoader loader )
+ {
+ FT_GlyphLoad base = &loader->base;
+ FT_GlyphLoad current = &loader->current;
+
+
+ base->outline.n_points = 0;
+ base->outline.n_contours = 0;
+ base->num_subglyphs = 0;
+
+ *current = *base;
+ }
+
+
+ /* reset the glyph loader, frees all allocated tables */
+ /* and starts from zero */
+ FT_BASE_DEF( void )
+ FT_GlyphLoader_Reset( FT_GlyphLoader loader )
+ {
+ FT_Memory memory = loader->memory;
+
+
+ FT_FREE( loader->base.outline.points );
+ FT_FREE( loader->base.outline.tags );
+ FT_FREE( loader->base.outline.contours );
+ FT_FREE( loader->base.extra_points );
+ FT_FREE( loader->base.subglyphs );
+
+ loader->max_points = 0;
+ loader->max_contours = 0;
+ loader->max_subglyphs = 0;
+
+ FT_GlyphLoader_Rewind( loader );
+ }
+
+
+ /* delete a glyph loader */
+ FT_BASE_DEF( void )
+ FT_GlyphLoader_Done( FT_GlyphLoader loader )
+ {
+ if ( loader )
+ {
+ FT_Memory memory = loader->memory;
+
+
+ FT_GlyphLoader_Reset( loader );
+ FT_FREE( loader );
+ }
+ }
+
+
+ /* re-adjust the `current' outline fields */
+ static void
+ FT_GlyphLoader_Adjust_Points( FT_GlyphLoader loader )
+ {
+ FT_Outline* base = &loader->base.outline;
+ FT_Outline* current = &loader->current.outline;
+
+
+ current->points = base->points + base->n_points;
+ current->tags = base->tags + base->n_points;
+ current->contours = base->contours + base->n_contours;
+
+ /* handle extra points table - if any */
+ if ( loader->use_extra )
+ loader->current.extra_points =
+ loader->base.extra_points + base->n_points;
+ }
+
+
+ FT_BASE_DEF( FT_Error )
+ FT_GlyphLoader_CreateExtra( FT_GlyphLoader loader )
+ {
+ FT_Error error;
+ FT_Memory memory = loader->memory;
+
+
+ if ( !FT_NEW_ARRAY( loader->base.extra_points, loader->max_points ) )
+ {
+ loader->use_extra = 1;
+ FT_GlyphLoader_Adjust_Points( loader );
+ }
+ return error;
+ }
+
+
+ /* re-adjust the `current' subglyphs field */
+ static void
+ FT_GlyphLoader_Adjust_Subglyphs( FT_GlyphLoader loader )
+ {
+ FT_GlyphLoad base = &loader->base;
+ FT_GlyphLoad current = &loader->current;
+
+
+ current->subglyphs = base->subglyphs + base->num_subglyphs;
+ }
+
+
+ /* Ensure that we can add `n_points' and `n_contours' to our glyph. this */
+ /* function reallocates its outline tables if necessary. Note that it */
+ /* DOESN'T change the number of points within the loader! */
+ /* */
+ FT_BASE_DEF( FT_Error )
+ FT_GlyphLoader_CheckPoints( FT_GlyphLoader loader,
+ FT_UInt n_points,
+ FT_UInt n_contours )
+ {
+ FT_Memory memory = loader->memory;
+ FT_Error error = FT_Err_Ok;
+ FT_Outline* base = &loader->base.outline;
+ FT_Outline* current = &loader->current.outline;
+ FT_Bool adjust = 1;
+
+ FT_UInt new_max, old_max;
+
+
+ /* check points & tags */
+ new_max = base->n_points + current->n_points + n_points;
+ old_max = loader->max_points;
+
+ if ( new_max > old_max )
+ {
+ new_max = ( new_max + 7 ) & -8;
+
+ if ( FT_RENEW_ARRAY( base->points, old_max, new_max ) ||
+ FT_RENEW_ARRAY( base->tags, old_max, new_max ) )
+ goto Exit;
+
+ if ( loader->use_extra &&
+ FT_RENEW_ARRAY( loader->base.extra_points, old_max, new_max ) )
+ goto Exit;
+
+ adjust = 1;
+ loader->max_points = new_max;
+ }
+
+ /* check contours */
+ old_max = loader->max_contours;
+ new_max = base->n_contours + current->n_contours +
+ n_contours;
+ if ( new_max > old_max )
+ {
+ new_max = ( new_max + 3 ) & -4;
+ if ( FT_RENEW_ARRAY( base->contours, old_max, new_max ) )
+ goto Exit;
+
+ adjust = 1;
+ loader->max_contours = new_max;
+ }
+
+ if ( adjust )
+ FT_GlyphLoader_Adjust_Points( loader );
+
+ Exit:
+ return error;
+ }
+
+
+ /* Ensure that we can add `n_subglyphs' to our glyph. this function */
+ /* reallocates its subglyphs table if necessary. Note that it DOES */
+ /* NOT change the number of subglyphs within the loader! */
+ /* */
+ FT_BASE_DEF( FT_Error )
+ FT_GlyphLoader_CheckSubGlyphs( FT_GlyphLoader loader,
+ FT_UInt n_subs )
+ {
+ FT_Memory memory = loader->memory;
+ FT_Error error = FT_Err_Ok;
+ FT_UInt new_max, old_max;
+
+ FT_GlyphLoad base = &loader->base;
+ FT_GlyphLoad current = &loader->current;
+
+
+ new_max = base->num_subglyphs + current->num_subglyphs + n_subs;
+ old_max = loader->max_subglyphs;
+ if ( new_max > old_max )
+ {
+ new_max = ( new_max + 1 ) & -2;
+ if ( FT_RENEW_ARRAY( base->subglyphs, old_max, new_max ) )
+ goto Exit;
+
+ loader->max_subglyphs = new_max;
+
+ FT_GlyphLoader_Adjust_Subglyphs( loader );
+ }
+
+ Exit:
+ return error;
+ }
+
+
+ /* prepare loader for the addition of a new glyph on top of the base one */
+ FT_BASE_DEF( void )
+ FT_GlyphLoader_Prepare( FT_GlyphLoader loader )
+ {
+ FT_GlyphLoad current = &loader->current;
+
+
+ current->outline.n_points = 0;
+ current->outline.n_contours = 0;
+ current->num_subglyphs = 0;
+
+ FT_GlyphLoader_Adjust_Points ( loader );
+ FT_GlyphLoader_Adjust_Subglyphs( loader );
+ }
+
+
+ /* add current glyph to the base image - and prepare for another */
+ FT_BASE_DEF( void )
+ FT_GlyphLoader_Add( FT_GlyphLoader loader )
+ {
+ FT_GlyphLoad base = &loader->base;
+ FT_GlyphLoad current = &loader->current;
+
+ FT_UInt n_curr_contours = current->outline.n_contours;
+ FT_UInt n_base_points = base->outline.n_points;
+ FT_UInt n;
+
+
+ base->outline.n_points =
+ (short)( base->outline.n_points + current->outline.n_points );
+ base->outline.n_contours =
+ (short)( base->outline.n_contours + current->outline.n_contours );
+
+ base->num_subglyphs += current->num_subglyphs;
+
+ /* adjust contours count in newest outline */
+ for ( n = 0; n < n_curr_contours; n++ )
+ current->outline.contours[n] =
+ (short)( current->outline.contours[n] + n_base_points );
+
+ /* prepare for another new glyph image */
+ FT_GlyphLoader_Prepare( loader );
+ }
+
+
+ FT_BASE_DEF( FT_Error )
+ FT_GlyphLoader_CopyPoints( FT_GlyphLoader target,
+ FT_GlyphLoader source )
+ {
+ FT_Error error;
+ FT_UInt num_points = source->base.outline.n_points;
+ FT_UInt num_contours = source->base.outline.n_contours;
+
+
+ error = FT_GlyphLoader_CheckPoints( target, num_points, num_contours );
+ if ( !error )
+ {
+ FT_Outline* out = &target->base.outline;
+ FT_Outline* in = &source->base.outline;
+
+
+ FT_MEM_COPY( out->points, in->points,
+ num_points * sizeof ( FT_Vector ) );
+ FT_MEM_COPY( out->tags, in->tags,
+ num_points * sizeof ( char ) );
+ FT_MEM_COPY( out->contours, in->contours,
+ num_contours * sizeof ( short ) );
+
+ /* do we need to copy the extra points? */
+ if ( target->use_extra && source->use_extra )
+ FT_MEM_COPY( target->base.extra_points, source->base.extra_points,
+ num_points * sizeof ( FT_Vector ) );
+
+ out->n_points = (short)num_points;
+ out->n_contours = (short)num_contours;
+
+ FT_GlyphLoader_Adjust_Points( target );
+ }
+
+ return error;
+ }
+
+
+/* END */
--- /dev/null
+++ b/libfreetype/ftglyph.c
@@ -1,0 +1,684 @@
+/***************************************************************************/
+/* */
+/* ftglyph.c */
+/* */
+/* FreeType convenience functions to handle glyphs (body). */
+/* */
+/* Copyright 1996-2001, 2002 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+ /*************************************************************************/
+ /* */
+ /* This file contains the definition of several convenience functions */
+ /* that can be used by client applications to easily retrieve glyph */
+ /* bitmaps and outlines from a given face. */
+ /* */
+ /* These functions should be optional if you are writing a font server */
+ /* or text layout engine on top of FreeType. However, they are pretty */
+ /* handy for many other simple uses of the library. */
+ /* */
+ /*************************************************************************/
+
+
+#include <ft2build.h>
+#include FT_GLYPH_H
+#include FT_OUTLINE_H
+#include FT_INTERNAL_OBJECTS_H
+
+
+ /*************************************************************************/
+ /* */
+ /* The macro FT_COMPONENT is used in trace mode. It is an implicit */
+ /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log */
+ /* messages during execution. */
+ /* */
+#undef FT_COMPONENT
+#define FT_COMPONENT trace_glyph
+
+
+ /*************************************************************************/
+ /*************************************************************************/
+ /**** ****/
+ /**** Convenience functions ****/
+ /**** ****/
+ /*************************************************************************/
+ /*************************************************************************/
+
+
+ /* documentation is in ftglyph.h */
+
+ FT_EXPORT_DEF( void )
+ FT_Matrix_Multiply( FT_Matrix* a,
+ FT_Matrix* b )
+ {
+ FT_Fixed xx, xy, yx, yy;
+
+
+ if ( !a || !b )
+ return;
+
+ xx = FT_MulFix( a->xx, b->xx ) + FT_MulFix( a->xy, b->yx );
+ xy = FT_MulFix( a->xx, b->xy ) + FT_MulFix( a->xy, b->yy );
+ yx = FT_MulFix( a->yx, b->xx ) + FT_MulFix( a->yy, b->yx );
+ yy = FT_MulFix( a->yx, b->xy ) + FT_MulFix( a->yy, b->yy );
+
+ b->xx = xx; b->xy = xy;
+ b->yx = yx; b->yy = yy;
+ }
+
+
+ /* documentation is in ftglyph.h */
+
+ FT_EXPORT_DEF( FT_Error )
+ FT_Matrix_Invert( FT_Matrix* matrix )
+ {
+ FT_Pos delta, xx, yy;
+
+
+ if ( !matrix )
+ return FT_Err_Invalid_Argument;
+
+ /* compute discriminant */
+ delta = FT_MulFix( matrix->xx, matrix->yy ) -
+ FT_MulFix( matrix->xy, matrix->yx );
+
+ if ( !delta )
+ return FT_Err_Invalid_Argument; /* matrix can't be inverted */
+
+ matrix->xy = - FT_DivFix( matrix->xy, delta );
+ matrix->yx = - FT_DivFix( matrix->yx, delta );
+
+ xx = matrix->xx;
+ yy = matrix->yy;
+
+ matrix->xx = FT_DivFix( yy, delta );
+ matrix->yy = FT_DivFix( xx, delta );
+
+ return FT_Err_Ok;
+ }
+
+
+ /*************************************************************************/
+ /*************************************************************************/
+ /**** ****/
+ /**** FT_BitmapGlyph support ****/
+ /**** ****/
+ /*************************************************************************/
+ /*************************************************************************/
+
+ static FT_Error
+ ft_bitmap_copy( FT_Memory memory,
+ FT_Bitmap* source,
+ FT_Bitmap* target )
+ {
+ FT_Error error;
+ FT_Int pitch = source->pitch;
+ FT_ULong size;
+
+
+ *target = *source;
+
+ if ( pitch < 0 )
+ pitch = -pitch;
+
+ size = (FT_ULong)( pitch * source->rows );
+
+ if ( !FT_ALLOC( target->buffer, size ) )
+ FT_MEM_COPY( target->buffer, source->buffer, size );
+
+ return error;
+ }
+
+
+ static FT_Error
+ ft_bitmap_glyph_init( FT_BitmapGlyph glyph,
+ FT_GlyphSlot slot )
+ {
+ FT_Error error = FT_Err_Ok;
+ FT_Library library = FT_GLYPH(glyph)->library;
+ FT_Memory memory = library->memory;
+
+
+ if ( slot->format != FT_GLYPH_FORMAT_BITMAP )
+ {
+ error = FT_Err_Invalid_Glyph_Format;
+ goto Exit;
+ }
+
+ /* grab the bitmap in the slot - do lazy copying whenever possible */
+ glyph->bitmap = slot->bitmap;
+ glyph->left = slot->bitmap_left;
+ glyph->top = slot->bitmap_top;
+
+ if ( slot->flags & FT_GLYPH_OWN_BITMAP )
+ slot->flags &= ~FT_GLYPH_OWN_BITMAP;
+ else
+ {
+ /* copy the bitmap into a new buffer */
+ error = ft_bitmap_copy( memory, &slot->bitmap, &glyph->bitmap );
+ }
+
+ Exit:
+ return error;
+ }
+
+
+ static FT_Error
+ ft_bitmap_glyph_copy( FT_BitmapGlyph source,
+ FT_BitmapGlyph target )
+ {
+ FT_Memory memory = source->root.library->memory;
+
+
+ target->left = source->left;
+ target->top = source->top;
+
+ return ft_bitmap_copy( memory, &source->bitmap, &target->bitmap );
+ }
+
+
+ static void
+ ft_bitmap_glyph_done( FT_BitmapGlyph glyph )
+ {
+ FT_Memory memory = FT_GLYPH(glyph)->library->memory;
+
+
+ FT_FREE( glyph->bitmap.buffer );
+ }
+
+
+ static void
+ ft_bitmap_glyph_bbox( FT_BitmapGlyph glyph,
+ FT_BBox* cbox )
+ {
+ cbox->xMin = glyph->left << 6;
+ cbox->xMax = cbox->xMin + ( glyph->bitmap.width << 6 );
+ cbox->yMax = glyph->top << 6;
+ cbox->yMin = cbox->yMax - ( glyph->bitmap.rows << 6 );
+ }
+
+
+ const FT_Glyph_Class ft_bitmap_glyph_class =
+ {
+ sizeof( FT_BitmapGlyphRec ),
+ FT_GLYPH_FORMAT_BITMAP,
+
+ (FT_Glyph_InitFunc) ft_bitmap_glyph_init,
+ (FT_Glyph_DoneFunc) ft_bitmap_glyph_done,
+ (FT_Glyph_CopyFunc) ft_bitmap_glyph_copy,
+ (FT_Glyph_TransformFunc)0,
+ (FT_Glyph_GetBBoxFunc) ft_bitmap_glyph_bbox,
+ (FT_Glyph_PrepareFunc) 0
+ };
+
+
+ /*************************************************************************/
+ /*************************************************************************/
+ /**** ****/
+ /**** FT_OutlineGlyph support ****/
+ /**** ****/
+ /*************************************************************************/
+ /*************************************************************************/
+
+
+ static FT_Error
+ ft_outline_glyph_init( FT_OutlineGlyph glyph,
+ FT_GlyphSlot slot )
+ {
+ FT_Error error = FT_Err_Ok;
+ FT_Library library = FT_GLYPH(glyph)->library;
+ FT_Outline* source = &slot->outline;
+ FT_Outline* target = &glyph->outline;
+
+
+ /* check format in glyph slot */
+ if ( slot->format != FT_GLYPH_FORMAT_OUTLINE )
+ {
+ error = FT_Err_Invalid_Glyph_Format;
+ goto Exit;
+ }
+
+ /* allocate new outline */
+ error = FT_Outline_New( library, source->n_points, source->n_contours,
+ &glyph->outline );
+ if ( error )
+ goto Exit;
+
+ /* copy it */
+ FT_MEM_COPY( target->points, source->points,
+ source->n_points * sizeof ( FT_Vector ) );
+
+ FT_MEM_COPY( target->tags, source->tags,
+ source->n_points * sizeof ( FT_Byte ) );
+
+ FT_MEM_COPY( target->contours, source->contours,
+ source->n_contours * sizeof ( FT_Short ) );
+
+ /* copy all flags, except the `FT_OUTLINE_OWNER' one */
+ target->flags = source->flags | FT_OUTLINE_OWNER;
+
+ Exit:
+ return error;
+ }
+
+
+ static void
+ ft_outline_glyph_done( FT_OutlineGlyph glyph )
+ {
+ FT_Outline_Done( FT_GLYPH( glyph )->library, &glyph->outline );
+ }
+
+
+ static FT_Error
+ ft_outline_glyph_copy( FT_OutlineGlyph source,
+ FT_OutlineGlyph target )
+ {
+ FT_Error error;
+ FT_Library library = FT_GLYPH( source )->library;
+
+
+ error = FT_Outline_New( library, source->outline.n_points,
+ source->outline.n_contours, &target->outline );
+ if ( !error )
+ FT_Outline_Copy( &source->outline, &target->outline );
+
+ return error;
+ }
+
+
+ static void
+ ft_outline_glyph_transform( FT_OutlineGlyph glyph,
+ FT_Matrix* matrix,
+ FT_Vector* delta )
+ {
+ if ( matrix )
+ FT_Outline_Transform( &glyph->outline, matrix );
+
+ if ( delta )
+ FT_Outline_Translate( &glyph->outline, delta->x, delta->y );
+ }
+
+
+ static void
+ ft_outline_glyph_bbox( FT_OutlineGlyph glyph,
+ FT_BBox* bbox )
+ {
+ FT_Outline_Get_CBox( &glyph->outline, bbox );
+ }
+
+
+ static FT_Error
+ ft_outline_glyph_prepare( FT_OutlineGlyph glyph,
+ FT_GlyphSlot slot )
+ {
+ slot->format = FT_GLYPH_FORMAT_OUTLINE;
+ slot->outline = glyph->outline;
+ slot->outline.flags &= ~FT_OUTLINE_OWNER;
+
+ return FT_Err_Ok;
+ }
+
+
+ const FT_Glyph_Class ft_outline_glyph_class =
+ {
+ sizeof( FT_OutlineGlyphRec ),
+ FT_GLYPH_FORMAT_OUTLINE,
+
+ (FT_Glyph_InitFunc) ft_outline_glyph_init,
+ (FT_Glyph_DoneFunc) ft_outline_glyph_done,
+ (FT_Glyph_CopyFunc) ft_outline_glyph_copy,
+ (FT_Glyph_TransformFunc)ft_outline_glyph_transform,
+ (FT_Glyph_GetBBoxFunc) ft_outline_glyph_bbox,
+ (FT_Glyph_PrepareFunc) ft_outline_glyph_prepare
+ };
+
+
+ /*************************************************************************/
+ /*************************************************************************/
+ /**** ****/
+ /**** FT_Glyph class and API ****/
+ /**** ****/
+ /*************************************************************************/
+ /*************************************************************************/
+
+ static FT_Error
+ ft_new_glyph( FT_Library library,
+ const FT_Glyph_Class* clazz,
+ FT_Glyph* aglyph )
+ {
+ FT_Memory memory = library->memory;
+ FT_Error error;
+ FT_Glyph glyph;
+
+
+ *aglyph = 0;
+
+ if ( !FT_ALLOC( glyph, clazz->glyph_size ) )
+ {
+ glyph->library = library;
+ glyph->clazz = clazz;
+ glyph->format = clazz->glyph_format;
+
+ *aglyph = glyph;
+ }
+
+ return error;
+ }
+
+
+ /* documentation is in ftglyph.h */
+
+ FT_EXPORT_DEF( FT_Error )
+ FT_Glyph_Copy( FT_Glyph source,
+ FT_Glyph *target )
+ {
+ FT_Glyph copy;
+ FT_Error error;
+ const FT_Glyph_Class* clazz;
+
+
+ /* check arguments */
+ if ( !target || !source || !source->clazz )
+ {
+ error = FT_Err_Invalid_Argument;
+ goto Exit;
+ }
+
+ *target = 0;
+
+ clazz = source->clazz;
+ error = ft_new_glyph( source->library, clazz, © );
+ if ( error )
+ goto Exit;
+
+ copy->advance = source->advance;
+ copy->format = source->format;
+
+ if ( clazz->glyph_copy )
+ error = clazz->glyph_copy( source, copy );
+
+ if ( error )
+ FT_Done_Glyph( copy );
+ else
+ *target = copy;
+
+ Exit:
+ return error;
+ }
+
+
+ /* documentation is in ftglyph.h */
+
+ FT_EXPORT_DEF( FT_Error )
+ FT_Get_Glyph( FT_GlyphSlot slot,
+ FT_Glyph *aglyph )
+ {
+ FT_Library library = slot->library;
+ FT_Error error;
+ FT_Glyph glyph;
+
+ const FT_Glyph_Class* clazz = 0;
+
+
+ if ( !slot )
+ return FT_Err_Invalid_Slot_Handle;
+
+ if ( !aglyph )
+ return FT_Err_Invalid_Argument;
+
+ /* if it is a bitmap, that's easy :-) */
+ if ( slot->format == FT_GLYPH_FORMAT_BITMAP )
+ clazz = &ft_bitmap_glyph_class;
+
+ /* it it is an outline too */
+ else if ( slot->format == FT_GLYPH_FORMAT_OUTLINE )
+ clazz = &ft_outline_glyph_class;
+
+ else
+ {
+ /* try to find a renderer that supports the glyph image format */
+ FT_Renderer render = FT_Lookup_Renderer( library, slot->format, 0 );
+
+
+ if ( render )
+ clazz = &render->glyph_class;
+ }
+
+ if ( !clazz )
+ {
+ error = FT_Err_Invalid_Glyph_Format;
+ goto Exit;
+ }
+
+ /* create FT_Glyph object */
+ error = ft_new_glyph( library, clazz, &glyph );
+ if ( error )
+ goto Exit;
+
+ /* copy advance while converting it to 16.16 format */
+ glyph->advance.x = slot->advance.x << 10;
+ glyph->advance.y = slot->advance.y << 10;
+
+ /* now import the image from the glyph slot */
+ error = clazz->glyph_init( glyph, slot );
+
+ /* if an error occurred, destroy the glyph */
+ if ( error )
+ FT_Done_Glyph( glyph );
+ else
+ *aglyph = glyph;
+
+ Exit:
+ return error;
+ }
+
+
+ /* documentation is in ftglyph.h */
+
+ FT_EXPORT_DEF( FT_Error )
+ FT_Glyph_Transform( FT_Glyph glyph,
+ FT_Matrix* matrix,
+ FT_Vector* delta )
+ {
+ const FT_Glyph_Class* clazz;
+ FT_Error error = FT_Err_Ok;
+
+
+ if ( !glyph || !glyph->clazz )
+ error = FT_Err_Invalid_Argument;
+ else
+ {
+ clazz = glyph->clazz;
+ if ( clazz->glyph_transform )
+ {
+ /* transform glyph image */
+ clazz->glyph_transform( glyph, matrix, delta );
+
+ /* transform advance vector */
+ if ( matrix )
+ FT_Vector_Transform( &glyph->advance, matrix );
+ }
+ else
+ error = FT_Err_Invalid_Glyph_Format;
+ }
+ return error;
+ }
+
+
+ /* documentation is in ftglyph.h */
+
+ FT_EXPORT_DEF( void )
+ FT_Glyph_Get_CBox( FT_Glyph glyph,
+ FT_UInt bbox_mode,
+ FT_BBox *acbox )
+ {
+ const FT_Glyph_Class* clazz;
+
+
+ if ( !acbox )
+ return;
+
+ acbox->xMin = acbox->yMin = acbox->xMax = acbox->yMax = 0;
+
+ if ( !glyph || !glyph->clazz )
+ return;
+ else
+ {
+ clazz = glyph->clazz;
+ if ( !clazz->glyph_bbox )
+ return;
+ else
+ {
+ /* retrieve bbox in 26.6 coordinates */
+ clazz->glyph_bbox( glyph, acbox );
+
+ /* perform grid fitting if needed */
+ if ( bbox_mode & ft_glyph_bbox_gridfit )
+ {
+ acbox->xMin &= -64;
+ acbox->yMin &= -64;
+ acbox->xMax = ( acbox->xMax + 63 ) & -64;
+ acbox->yMax = ( acbox->yMax + 63 ) & -64;
+ }
+
+ /* convert to integer pixels if needed */
+ if ( bbox_mode & ft_glyph_bbox_truncate )
+ {
+ acbox->xMin >>= 6;
+ acbox->yMin >>= 6;
+ acbox->xMax >>= 6;
+ acbox->yMax >>= 6;
+ }
+ }
+ }
+ return;
+ }
+
+
+ /* documentation is in ftglyph.h */
+
+ FT_EXPORT_DEF( FT_Error )
+ FT_Glyph_To_Bitmap( FT_Glyph* the_glyph,
+ FT_Render_Mode render_mode,
+ FT_Vector* origin,
+ FT_Bool destroy )
+ {
+ FT_GlyphSlotRec dummy;
+ FT_Error error = FT_Err_Ok;
+ FT_Glyph glyph;
+ FT_BitmapGlyph bitmap = NULL;
+
+ const FT_Glyph_Class* clazz;
+
+
+ /* check argument */
+ if ( !the_glyph )
+ goto Bad;
+
+ /* we render the glyph into a glyph bitmap using a `dummy' glyph slot */
+ /* then calling FT_Render_Glyph_Internal() */
+
+ glyph = *the_glyph;
+ if ( !glyph )
+ goto Bad;
+
+ clazz = glyph->clazz;
+
+ /* when called with a bitmap glyph, do nothing and return succesfully */
+ if ( clazz == &ft_bitmap_glyph_class )
+ goto Exit;
+
+ if ( !clazz || !clazz->glyph_prepare )
+ goto Bad;
+
+ FT_MEM_ZERO( &dummy, sizeof ( dummy ) );
+ dummy.library = glyph->library;
+ dummy.format = clazz->glyph_format;
+
+ /* create result bitmap glyph */
+ error = ft_new_glyph( glyph->library, &ft_bitmap_glyph_class,
+ (FT_Glyph*)&bitmap );
+ if ( error )
+ goto Exit;
+
+#if 0
+ /* if `origin' is set, translate the glyph image */
+ if ( origin )
+ FT_Glyph_Transform( glyph, 0, origin );
+#else
+ FT_UNUSED( origin );
+#endif
+
+ /* prepare dummy slot for rendering */
+ error = clazz->glyph_prepare( glyph, &dummy );
+ if ( !error )
+ error = FT_Render_Glyph_Internal( glyph->library, &dummy, render_mode );
+
+#if 0
+ if ( !destroy && origin )
+ {
+ FT_Vector v;
+
+
+ v.x = -origin->x;
+ v.y = -origin->y;
+ FT_Glyph_Transform( glyph, 0, &v );
+ }
+#endif
+
+ if ( error )
+ goto Exit;
+
+ /* in case of success, copy the bitmap to the glyph bitmap */
+ error = ft_bitmap_glyph_init( bitmap, &dummy );
+ if ( error )
+ goto Exit;
+
+ /* copy advance */
+ bitmap->root.advance = glyph->advance;
+
+ if ( destroy )
+ FT_Done_Glyph( glyph );
+
+ *the_glyph = FT_GLYPH( bitmap );
+
+ Exit:
+ if ( error && bitmap )
+ FT_Done_Glyph( FT_GLYPH( bitmap ) );
+
+ return error;
+
+ Bad:
+ error = FT_Err_Invalid_Argument;
+ goto Exit;
+ }
+
+
+ /* documentation is in ftglyph.h */
+
+ FT_EXPORT_DEF( void )
+ FT_Done_Glyph( FT_Glyph glyph )
+ {
+ if ( glyph )
+ {
+ FT_Memory memory = glyph->library->memory;
+ const FT_Glyph_Class* clazz = glyph->clazz;
+
+
+ if ( clazz->glyph_done )
+ clazz->glyph_done( glyph );
+
+ FT_FREE( glyph );
+ }
+ }
+
+
+/* END */
--- /dev/null
+++ b/libfreetype/ftgrays.c
@@ -1,0 +1,2159 @@
+/***************************************************************************/
+/* */
+/* ftgrays.c */
+/* */
+/* A new `perfect' anti-aliasing renderer (body). */
+/* */
+/* Copyright 2000-2001, 2002 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+ /*************************************************************************/
+ /* */
+ /* This file can be compiled without the rest of the FreeType engine, by */
+ /* defining the _STANDALONE_ macro when compiling it. You also need to */
+ /* put the files `ftgrays.h' and `ftimage.h' into the current */
+ /* compilation directory. Typically, you could do something like */
+ /* */
+ /* - copy `src/smooth/ftgrays.c' (this file) to your current directory */
+ /* */
+ /* - copy `include/freetype/ftimage.h' and `src/smooth/ftgrays.h' to the */
+ /* same directory */
+ /* */
+ /* - compile `ftgrays' with the _STANDALONE_ macro defined, as in */
+ /* */
+ /* cc -c -D_STANDALONE_ ftgrays.c */
+ /* */
+ /* The renderer can be initialized with a call to */
+ /* `ft_gray_raster.raster_new'; an anti-aliased bitmap can be generated */
+ /* with a call to `ft_gray_raster.raster_render'. */
+ /* */
+ /* See the comments and documentation in the file `ftimage.h' for more */
+ /* details on how the raster works. */
+ /* */
+ /*************************************************************************/
+
+ /*************************************************************************/
+ /* */
+ /* This is a new anti-aliasing scan-converter for FreeType 2. The */
+ /* algorithm used here is _very_ different from the one in the standard */
+ /* `ftraster' module. Actually, `ftgrays' computes the _exact_ */
+ /* coverage of the outline on each pixel cell. */
+ /* */
+ /* It is based on ideas that I initially found in Raph Levien's */
+ /* excellent LibArt graphics library (see http://www.levien.com/libart */
+ /* for more information, though the web pages do not tell anything */
+ /* about the renderer; you'll have to dive into the source code to */
+ /* understand how it works). */
+ /* */
+ /* Note, however, that this is a _very_ different implementation */
+ /* compared to Raph's. Coverage information is stored in a very */
+ /* different way, and I don't use sorted vector paths. Also, it doesn't */
+ /* use floating point values. */
+ /* */
+ /* This renderer has the following advantages: */
+ /* */
+ /* - It doesn't need an intermediate bitmap. Instead, one can supply a */
+ /* callback function that will be called by the renderer to draw gray */
+ /* spans on any target surface. You can thus do direct composition on */
+ /* any kind of bitmap, provided that you give the renderer the right */
+ /* callback. */
+ /* */
+ /* - A perfect anti-aliaser, i.e., it computes the _exact_ coverage on */
+ /* each pixel cell. */
+ /* */
+ /* - It performs a single pass on the outline (the `standard' FT2 */
+ /* renderer makes two passes). */
+ /* */
+ /* - It can easily be modified to render to _any_ number of gray levels */
+ /* cheaply. */
+ /* */
+ /* - For small (< 20) pixel sizes, it is faster than the standard */
+ /* renderer. */
+ /* */
+ /*************************************************************************/
+
+
+
+/* experimental support for gamma correction within the rasterizer */
+#define xxxGRAYS_USE_GAMMA
+
+
+ /*************************************************************************/
+ /* */
+ /* The macro FT_COMPONENT is used in trace mode. It is an implicit */
+ /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log */
+ /* messages during execution. */
+ /* */
+#undef FT_COMPONENT
+#define FT_COMPONENT trace_smooth
+
+
+#define ErrRaster_MemoryOverflow -4
+
+
+#ifdef _STANDALONE_
+
+#include <string.h> /* for ft_memcpy() */
+#include <setjmp.h>
+#include <limits.h>
+#define FT_UINT_MAX UINT_MAX
+
+#define ft_memset memset
+
+#define ft_setjmp setjmp
+#define ft_longjmp longjmp
+#define ft_jmp_buf jmp_buf
+
+
+#define ErrRaster_Invalid_Mode -2
+#define ErrRaster_Invalid_Outline -1
+
+#define FT_BEGIN_HEADER
+#define FT_END_HEADER
+
+#include "ftimage.h"
+#include "ftgrays.h"
+
+ /* This macro is used to indicate that a function parameter is unused. */
+ /* Its purpose is simply to reduce compiler warnings. Note also that */
+ /* simply defining it as `(void)x' doesn't avoid warnings with certain */
+ /* ANSI compilers (e.g. LCC). */
+#define FT_UNUSED( x ) (x) = (x)
+
+ /* Disable the tracing mechanism for simplicity -- developers can */
+ /* activate it easily by redefining these two macros. */
+#ifndef FT_ERROR
+#define FT_ERROR( x ) do ; while ( 0 ) /* nothing */
+#endif
+
+#ifndef FT_TRACE
+#define FT_TRACE( x ) do ; while ( 0 ) /* nothing */
+#endif
+
+
+#else /* _STANDALONE_ */
+
+
+#include <ft2build.h>
+#include "ftgrays.h"
+#include FT_INTERNAL_OBJECTS_H
+#include FT_INTERNAL_DEBUG_H
+#include FT_OUTLINE_H
+
+#include "ftsmerrs.h"
+
+#define ErrRaster_Invalid_Mode Smooth_Err_Cannot_Render_Glyph
+#define ErrRaster_Invalid_Outline Smooth_Err_Invalid_Outline
+
+
+#endif /* _STANDALONE_ */
+
+
+#ifndef FT_MEM_SET
+#define FT_MEM_SET( d, s, c ) ft_memset( d, s, c )
+#endif
+
+#ifndef FT_MEM_ZERO
+#define FT_MEM_ZERO( dest, count ) FT_MEM_SET( dest, 0, count )
+#endif
+
+ /* define this to dump debugging information */
+#define xxxDEBUG_GRAYS
+
+ /* as usual, for the speed hungry :-) */
+
+#ifndef FT_STATIC_RASTER
+
+
+#define RAS_ARG PRaster raster
+#define RAS_ARG_ PRaster raster,
+
+#define RAS_VAR raster
+#define RAS_VAR_ raster,
+
+#define ras (*raster)
+
+
+#else /* FT_STATIC_RASTER */
+
+
+#define RAS_ARG /* empty */
+#define RAS_ARG_ /* empty */
+#define RAS_VAR /* empty */
+#define RAS_VAR_ /* empty */
+
+ static TRaster ras;
+
+
+#endif /* FT_STATIC_RASTER */
+
+
+ /* must be at least 6 bits! */
+#define PIXEL_BITS 8
+
+#define ONE_PIXEL ( 1L << PIXEL_BITS )
+#define PIXEL_MASK ( -1L << PIXEL_BITS )
+#define TRUNC( x ) ( (TCoord)((x) >> PIXEL_BITS) )
+#define SUBPIXELS( x ) ( (TPos)(x) << PIXEL_BITS )
+#define FLOOR( x ) ( (x) & -ONE_PIXEL )
+#define CEILING( x ) ( ( (x) + ONE_PIXEL - 1 ) & -ONE_PIXEL )
+#define ROUND( x ) ( ( (x) + ONE_PIXEL / 2 ) & -ONE_PIXEL )
+
+#if PIXEL_BITS >= 6
+#define UPSCALE( x ) ( (x) << ( PIXEL_BITS - 6 ) )
+#define DOWNSCALE( x ) ( (x) >> ( PIXEL_BITS - 6 ) )
+#else
+#define UPSCALE( x ) ( (x) >> ( 6 - PIXEL_BITS ) )
+#define DOWNSCALE( x ) ( (x) << ( 6 - PIXEL_BITS ) )
+#endif
+
+ /* Define this if you want to use a more compact storage scheme. This */
+ /* increases the number of cells available in the render pool but slows */
+ /* down the rendering a bit. It is useful if you have a really tiny */
+ /* render pool. */
+#undef GRAYS_COMPACT
+
+
+ /*************************************************************************/
+ /* */
+ /* TYPE DEFINITIONS */
+ /* */
+
+ /* don't change the following types to FT_Int or FT_Pos, since we might */
+ /* need to define them to "float" or "double" when experimenting with */
+ /* new algorithms */
+
+ typedef int TCoord; /* integer scanline/pixel coordinate */
+ typedef long TPos; /* sub-pixel coordinate */
+
+ /* determine the type used to store cell areas. This normally takes at */
+ /* least PIXEL_BYTES*2 + 1. On 16-bit systems, we need to use `long' */
+ /* instead of `int', otherwise bad things happen */
+
+#if PIXEL_BITS <= 7
+
+ typedef int TArea;
+
+#else /* PIXEL_BITS >= 8 */
+
+ /* approximately determine the size of integers using an ANSI-C header */
+#if FT_UINT_MAX == 0xFFFFU
+ typedef long TArea;
+#else
+ typedef int TArea;
+#endif
+
+#endif /* PIXEL_BITS >= 8 */
+
+
+ /* maximal number of gray spans in a call to the span callback */
+#define FT_MAX_GRAY_SPANS 32
+
+
+#ifdef GRAYS_COMPACT
+
+ typedef struct TCell_
+ {
+ short x : 14;
+ short y : 14;
+ int cover : PIXEL_BITS + 2;
+ int area : PIXEL_BITS * 2 + 2;
+
+ } TCell, *PCell;
+
+#else /* GRAYS_COMPACT */
+
+ typedef struct TCell_
+ {
+ TCoord x;
+ TCoord y;
+ int cover;
+ TArea area;
+
+ } TCell, *PCell;
+
+#endif /* GRAYS_COMPACT */
+
+
+ typedef struct TRaster_
+ {
+ PCell cells;
+ int max_cells;
+ int num_cells;
+
+ TPos min_ex, max_ex;
+ TPos min_ey, max_ey;
+
+ TArea area;
+ int cover;
+ int invalid;
+
+ TCoord ex, ey;
+ TCoord cx, cy;
+ TPos x, y;
+
+ TPos last_ey;
+
+ FT_Vector bez_stack[32 * 3 + 1];
+ int lev_stack[32];
+
+ FT_Outline outline;
+ FT_Bitmap target;
+ FT_BBox clip_box;
+
+ FT_Span gray_spans[FT_MAX_GRAY_SPANS];
+ int num_gray_spans;
+
+ FT_Raster_Span_Func render_span;
+ void* render_span_data;
+ int span_y;
+
+ int band_size;
+ int band_shoot;
+ int conic_level;
+ int cubic_level;
+
+ void* memory;
+ ft_jmp_buf jump_buffer;
+
+#ifdef GRAYS_USE_GAMMA
+ unsigned char gamma[257];
+#endif
+
+ } TRaster, *PRaster;
+
+
+ /*************************************************************************/
+ /* */
+ /* Initialize the cells table. */
+ /* */
+ static void
+ gray_init_cells( RAS_ARG_ void* buffer,
+ long byte_size )
+ {
+ ras.cells = (PCell)buffer;
+ ras.max_cells = byte_size / sizeof ( TCell );
+ ras.num_cells = 0;
+ ras.area = 0;
+ ras.cover = 0;
+ ras.invalid = 1;
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* Compute the outline bounding box. */
+ /* */
+ static void
+ gray_compute_cbox( RAS_ARG )
+ {
+ FT_Outline* outline = &ras.outline;
+ FT_Vector* vec = outline->points;
+ FT_Vector* limit = vec + outline->n_points;
+
+
+ if ( outline->n_points <= 0 )
+ {
+ ras.min_ex = ras.max_ex = 0;
+ ras.min_ey = ras.max_ey = 0;
+ return;
+ }
+
+ ras.min_ex = ras.max_ex = vec->x;
+ ras.min_ey = ras.max_ey = vec->y;
+
+ vec++;
+
+ for ( ; vec < limit; vec++ )
+ {
+ TPos x = vec->x;
+ TPos y = vec->y;
+
+
+ if ( x < ras.min_ex ) ras.min_ex = x;
+ if ( x > ras.max_ex ) ras.max_ex = x;
+ if ( y < ras.min_ey ) ras.min_ey = y;
+ if ( y > ras.max_ey ) ras.max_ey = y;
+ }
+
+ /* truncate the bounding box to integer pixels */
+ ras.min_ex = ras.min_ex >> 6;
+ ras.min_ey = ras.min_ey >> 6;
+ ras.max_ex = ( ras.max_ex + 63 ) >> 6;
+ ras.max_ey = ( ras.max_ey + 63 ) >> 6;
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* Record the current cell in the table. */
+ /* */
+ static void
+ gray_record_cell( RAS_ARG )
+ {
+ PCell cell;
+
+
+ if ( !ras.invalid && ( ras.area | ras.cover ) )
+ {
+ if ( ras.num_cells >= ras.max_cells )
+ ft_longjmp( ras.jump_buffer, 1 );
+
+ cell = ras.cells + ras.num_cells++;
+ cell->x = (TCoord)(ras.ex - ras.min_ex);
+ cell->y = (TCoord)(ras.ey - ras.min_ey);
+ cell->area = ras.area;
+ cell->cover = ras.cover;
+ }
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* Set the current cell to a new position. */
+ /* */
+ static void
+ gray_set_cell( RAS_ARG_ TCoord ex,
+ TCoord ey )
+ {
+ int invalid, record, clean;
+
+
+ /* Move the cell pointer to a new position. We set the `invalid' */
+ /* flag to indicate that the cell isn't part of those we're interested */
+ /* in during the render phase. This means that: */
+ /* */
+ /* . the new vertical position must be within min_ey..max_ey-1. */
+ /* . the new horizontal position must be strictly less than max_ex */
+ /* */
+ /* Note that if a cell is to the left of the clipping region, it is */
+ /* actually set to the (min_ex-1) horizontal position. */
+
+ record = 0;
+ clean = 1;
+
+ invalid = ( ey < ras.min_ey || ey >= ras.max_ey || ex >= ras.max_ex );
+ if ( !invalid )
+ {
+ /* All cells that are on the left of the clipping region go to the */
+ /* min_ex - 1 horizontal position. */
+ if ( ex < ras.min_ex )
+ ex = (TCoord)(ras.min_ex - 1);
+
+ /* if our position is new, then record the previous cell */
+ if ( ex != ras.ex || ey != ras.ey )
+ record = 1;
+ else
+ clean = ras.invalid; /* do not clean if we didn't move from */
+ /* a valid cell */
+ }
+
+ /* record the previous cell if needed (i.e., if we changed the cell */
+ /* position, of changed the `invalid' flag) */
+ if ( ras.invalid != invalid || record )
+ gray_record_cell( RAS_VAR );
+
+ if ( clean )
+ {
+ ras.area = 0;
+ ras.cover = 0;
+ }
+
+ ras.invalid = invalid;
+ ras.ex = ex;
+ ras.ey = ey;
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* Start a new contour at a given cell. */
+ /* */
+ static void
+ gray_start_cell( RAS_ARG_ TCoord ex,
+ TCoord ey )
+ {
+ if ( ex < ras.min_ex )
+ ex = (TCoord)(ras.min_ex - 1);
+
+ ras.area = 0;
+ ras.cover = 0;
+ ras.ex = ex;
+ ras.ey = ey;
+ ras.last_ey = SUBPIXELS( ey );
+ ras.invalid = 0;
+
+ gray_set_cell( RAS_VAR_ ex, ey );
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* Render a scanline as one or more cells. */
+ /* */
+ static void
+ gray_render_scanline( RAS_ARG_ TCoord ey,
+ TPos x1,
+ TCoord y1,
+ TPos x2,
+ TCoord y2 )
+ {
+ TCoord ex1, ex2, fx1, fx2, delta;
+ long p, first, dx;
+ int incr, lift, mod, rem;
+
+
+ dx = x2 - x1;
+
+ ex1 = TRUNC( x1 ); /* if (ex1 >= ras.max_ex) ex1 = ras.max_ex-1; */
+ ex2 = TRUNC( x2 ); /* if (ex2 >= ras.max_ex) ex2 = ras.max_ex-1; */
+ fx1 = (TCoord)( x1 - SUBPIXELS( ex1 ) );
+ fx2 = (TCoord)( x2 - SUBPIXELS( ex2 ) );
+
+ /* trivial case. Happens often */
+ if ( y1 == y2 )
+ {
+ gray_set_cell( RAS_VAR_ ex2, ey );
+ return;
+ }
+
+ /* everything is located in a single cell. That is easy! */
+ /* */
+ if ( ex1 == ex2 )
+ {
+ delta = y2 - y1;
+ ras.area += (TArea)( fx1 + fx2 ) * delta;
+ ras.cover += delta;
+ return;
+ }
+
+ /* ok, we'll have to render a run of adjacent cells on the same */
+ /* scanline... */
+ /* */
+ p = ( ONE_PIXEL - fx1 ) * ( y2 - y1 );
+ first = ONE_PIXEL;
+ incr = 1;
+
+ if ( dx < 0 )
+ {
+ p = fx1 * ( y2 - y1 );
+ first = 0;
+ incr = -1;
+ dx = -dx;
+ }
+
+ delta = (TCoord)( p / dx );
+ mod = (TCoord)( p % dx );
+ if ( mod < 0 )
+ {
+ delta--;
+ mod += (TCoord)dx;
+ }
+
+ ras.area += (TArea)( fx1 + first ) * delta;
+ ras.cover += delta;
+
+ ex1 += incr;
+ gray_set_cell( RAS_VAR_ ex1, ey );
+ y1 += delta;
+
+ if ( ex1 != ex2 )
+ {
+ p = ONE_PIXEL * ( y2 - y1 + delta );
+ lift = (TCoord)( p / dx );
+ rem = (TCoord)( p % dx );
+ if ( rem < 0 )
+ {
+ lift--;
+ rem += (TCoord)dx;
+ }
+
+ mod -= dx;
+
+ while ( ex1 != ex2 )
+ {
+ delta = lift;
+ mod += rem;
+ if ( mod >= 0 )
+ {
+ mod -= (TCoord)dx;
+ delta++;
+ }
+
+ ras.area += (TArea)ONE_PIXEL * delta;
+ ras.cover += delta;
+ y1 += delta;
+ ex1 += incr;
+ gray_set_cell( RAS_VAR_ ex1, ey );
+ }
+ }
+
+ delta = y2 - y1;
+ ras.area += (TArea)( fx2 + ONE_PIXEL - first ) * delta;
+ ras.cover += delta;
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* Render a given line as a series of scanlines. */
+ /* */
+ static void
+ gray_render_line( RAS_ARG_ TPos to_x,
+ TPos to_y )
+ {
+ TCoord ey1, ey2, fy1, fy2;
+ TPos dx, dy, x, x2;
+ long p, first;
+ int delta, rem, mod, lift, incr;
+
+
+ ey1 = TRUNC( ras.last_ey );
+ ey2 = TRUNC( to_y ); /* if (ey2 >= ras.max_ey) ey2 = ras.max_ey-1; */
+ fy1 = (TCoord)( ras.y - ras.last_ey );
+ fy2 = (TCoord)( to_y - SUBPIXELS( ey2 ) );
+
+ dx = to_x - ras.x;
+ dy = to_y - ras.y;
+
+ /* XXX: we should do something about the trivial case where dx == 0, */
+ /* as it happens very often! */
+
+ /* perform vertical clipping */
+ {
+ TCoord min, max;
+
+
+ min = ey1;
+ max = ey2;
+ if ( ey1 > ey2 )
+ {
+ min = ey2;
+ max = ey1;
+ }
+ if ( min >= ras.max_ey || max < ras.min_ey )
+ goto End;
+ }
+
+ /* everything is on a single scanline */
+ if ( ey1 == ey2 )
+ {
+ gray_render_scanline( RAS_VAR_ ey1, ras.x, fy1, to_x, fy2 );
+ goto End;
+ }
+
+ /* vertical line - avoid calling gray_render_scanline */
+ incr = 1;
+
+ if ( dx == 0 )
+ {
+ TCoord ex = TRUNC( ras.x );
+ TCoord two_fx = (TCoord)( ( ras.x - SUBPIXELS( ex ) ) << 1 );
+ TPos area;
+
+
+ first = ONE_PIXEL;
+ if ( dy < 0 )
+ {
+ first = 0;
+ incr = -1;
+ }
+
+ delta = (int)( first - fy1 );
+ ras.area += (TArea)two_fx * delta;
+ ras.cover += delta;
+ ey1 += incr;
+
+ gray_set_cell( raster, ex, ey1 );
+
+ delta = (int)( first + first - ONE_PIXEL );
+ area = (TArea)two_fx * delta;
+ while ( ey1 != ey2 )
+ {
+ ras.area += area;
+ ras.cover += delta;
+ ey1 += incr;
+ gray_set_cell( raster, ex, ey1 );
+ }
+
+ delta = (int)( fy2 - ONE_PIXEL + first );
+ ras.area += (TArea)two_fx * delta;
+ ras.cover += delta;
+ goto End;
+ }
+
+ /* ok, we have to render several scanlines */
+ p = ( ONE_PIXEL - fy1 ) * dx;
+ first = ONE_PIXEL;
+ incr = 1;
+
+ if ( dy < 0 )
+ {
+ p = fy1 * dx;
+ first = 0;
+ incr = -1;
+ dy = -dy;
+ }
+
+ delta = (int)( p / dy );
+ mod = (int)( p % dy );
+ if ( mod < 0 )
+ {
+ delta--;
+ mod += (TCoord)dy;
+ }
+
+ x = ras.x + delta;
+ gray_render_scanline( RAS_VAR_ ey1, ras.x, fy1, x, (TCoord)first );
+
+ ey1 += incr;
+ gray_set_cell( RAS_VAR_ TRUNC( x ), ey1 );
+
+ if ( ey1 != ey2 )
+ {
+ p = ONE_PIXEL * dx;
+ lift = (int)( p / dy );
+ rem = (int)( p % dy );
+ if ( rem < 0 )
+ {
+ lift--;
+ rem += (int)dy;
+ }
+ mod -= (int)dy;
+
+ while ( ey1 != ey2 )
+ {
+ delta = lift;
+ mod += rem;
+ if ( mod >= 0 )
+ {
+ mod -= (int)dy;
+ delta++;
+ }
+
+ x2 = x + delta;
+ gray_render_scanline( RAS_VAR_ ey1, x,
+ (TCoord)( ONE_PIXEL - first ), x2,
+ (TCoord)first );
+ x = x2;
+
+ ey1 += incr;
+ gray_set_cell( RAS_VAR_ TRUNC( x ), ey1 );
+ }
+ }
+
+ gray_render_scanline( RAS_VAR_ ey1, x,
+ (TCoord)( ONE_PIXEL - first ), to_x,
+ fy2 );
+
+ End:
+ ras.x = to_x;
+ ras.y = to_y;
+ ras.last_ey = SUBPIXELS( ey2 );
+ }
+
+
+ static void
+ gray_split_conic( FT_Vector* base )
+ {
+ TPos a, b;
+
+
+ base[4].x = base[2].x;
+ b = base[1].x;
+ a = base[3].x = ( base[2].x + b ) / 2;
+ b = base[1].x = ( base[0].x + b ) / 2;
+ base[2].x = ( a + b ) / 2;
+
+ base[4].y = base[2].y;
+ b = base[1].y;
+ a = base[3].y = ( base[2].y + b ) / 2;
+ b = base[1].y = ( base[0].y + b ) / 2;
+ base[2].y = ( a + b ) / 2;
+ }
+
+
+ static void
+ gray_render_conic( RAS_ARG_ FT_Vector* control,
+ FT_Vector* to )
+ {
+ TPos dx, dy;
+ int top, level;
+ int* levels;
+ FT_Vector* arc;
+
+
+ dx = DOWNSCALE( ras.x ) + to->x - ( control->x << 1 );
+ if ( dx < 0 )
+ dx = -dx;
+ dy = DOWNSCALE( ras.y ) + to->y - ( control->y << 1 );
+ if ( dy < 0 )
+ dy = -dy;
+ if ( dx < dy )
+ dx = dy;
+
+ level = 1;
+ dx = dx / ras.conic_level;
+ while ( dx > 0 )
+ {
+ dx >>= 2;
+ level++;
+ }
+
+ /* a shortcut to speed things up */
+ if ( level <= 1 )
+ {
+ /* we compute the mid-point directly in order to avoid */
+ /* calling gray_split_conic() */
+ TPos to_x, to_y, mid_x, mid_y;
+
+
+ to_x = UPSCALE( to->x );
+ to_y = UPSCALE( to->y );
+ mid_x = ( ras.x + to_x + 2 * UPSCALE( control->x ) ) / 4;
+ mid_y = ( ras.y + to_y + 2 * UPSCALE( control->y ) ) / 4;
+
+ gray_render_line( RAS_VAR_ mid_x, mid_y );
+ gray_render_line( RAS_VAR_ to_x, to_y );
+ return;
+ }
+
+ arc = ras.bez_stack;
+ levels = ras.lev_stack;
+ top = 0;
+ levels[0] = level;
+
+ arc[0].x = UPSCALE( to->x );
+ arc[0].y = UPSCALE( to->y );
+ arc[1].x = UPSCALE( control->x );
+ arc[1].y = UPSCALE( control->y );
+ arc[2].x = ras.x;
+ arc[2].y = ras.y;
+
+ while ( top >= 0 )
+ {
+ level = levels[top];
+ if ( level > 1 )
+ {
+ /* check that the arc crosses the current band */
+ TPos min, max, y;
+
+
+ min = max = arc[0].y;
+
+ y = arc[1].y;
+ if ( y < min ) min = y;
+ if ( y > max ) max = y;
+
+ y = arc[2].y;
+ if ( y < min ) min = y;
+ if ( y > max ) max = y;
+
+ if ( TRUNC( min ) >= ras.max_ey || TRUNC( max ) < 0 )
+ goto Draw;
+
+ gray_split_conic( arc );
+ arc += 2;
+ top++;
+ levels[top] = levels[top - 1] = level - 1;
+ continue;
+ }
+
+ Draw:
+ {
+ TPos to_x, to_y, mid_x, mid_y;
+
+
+ to_x = arc[0].x;
+ to_y = arc[0].y;
+ mid_x = ( ras.x + to_x + 2 * arc[1].x ) / 4;
+ mid_y = ( ras.y + to_y + 2 * arc[1].y ) / 4;
+
+ gray_render_line( RAS_VAR_ mid_x, mid_y );
+ gray_render_line( RAS_VAR_ to_x, to_y );
+
+ top--;
+ arc -= 2;
+ }
+ }
+ return;
+ }
+
+
+ static void
+ gray_split_cubic( FT_Vector* base )
+ {
+ TPos a, b, c, d;
+
+
+ base[6].x = base[3].x;
+ c = base[1].x;
+ d = base[2].x;
+ base[1].x = a = ( base[0].x + c ) / 2;
+ base[5].x = b = ( base[3].x + d ) / 2;
+ c = ( c + d ) / 2;
+ base[2].x = a = ( a + c ) / 2;
+ base[4].x = b = ( b + c ) / 2;
+ base[3].x = ( a + b ) / 2;
+
+ base[6].y = base[3].y;
+ c = base[1].y;
+ d = base[2].y;
+ base[1].y = a = ( base[0].y + c ) / 2;
+ base[5].y = b = ( base[3].y + d ) / 2;
+ c = ( c + d ) / 2;
+ base[2].y = a = ( a + c ) / 2;
+ base[4].y = b = ( b + c ) / 2;
+ base[3].y = ( a + b ) / 2;
+ }
+
+
+ static void
+ gray_render_cubic( RAS_ARG_ FT_Vector* control1,
+ FT_Vector* control2,
+ FT_Vector* to )
+ {
+ TPos dx, dy, da, db;
+ int top, level;
+ int* levels;
+ FT_Vector* arc;
+
+
+ dx = DOWNSCALE( ras.x ) + to->x - ( control1->x << 1 );
+ if ( dx < 0 )
+ dx = -dx;
+ dy = DOWNSCALE( ras.y ) + to->y - ( control1->y << 1 );
+ if ( dy < 0 )
+ dy = -dy;
+ if ( dx < dy )
+ dx = dy;
+ da = dx;
+
+ dx = DOWNSCALE( ras.x ) + to->x - 3 * ( control1->x + control2->x );
+ if ( dx < 0 )
+ dx = -dx;
+ dy = DOWNSCALE( ras.y ) + to->y - 3 * ( control1->x + control2->y );
+ if ( dy < 0 )
+ dy = -dy;
+ if ( dx < dy )
+ dx = dy;
+ db = dx;
+
+ level = 1;
+ da = da / ras.cubic_level;
+ db = db / ras.conic_level;
+ while ( da > 0 || db > 0 )
+ {
+ da >>= 2;
+ db >>= 3;
+ level++;
+ }
+
+ if ( level <= 1 )
+ {
+ TPos to_x, to_y, mid_x, mid_y;
+
+
+ to_x = UPSCALE( to->x );
+ to_y = UPSCALE( to->y );
+ mid_x = ( ras.x + to_x +
+ 3 * UPSCALE( control1->x + control2->x ) ) / 8;
+ mid_y = ( ras.y + to_y +
+ 3 * UPSCALE( control1->y + control2->y ) ) / 8;
+
+ gray_render_line( RAS_VAR_ mid_x, mid_y );
+ gray_render_line( RAS_VAR_ to_x, to_y );
+ return;
+ }
+
+ arc = ras.bez_stack;
+ arc[0].x = UPSCALE( to->x );
+ arc[0].y = UPSCALE( to->y );
+ arc[1].x = UPSCALE( control2->x );
+ arc[1].y = UPSCALE( control2->y );
+ arc[2].x = UPSCALE( control1->x );
+ arc[2].y = UPSCALE( control1->y );
+ arc[3].x = ras.x;
+ arc[3].y = ras.y;
+
+ levels = ras.lev_stack;
+ top = 0;
+ levels[0] = level;
+
+ while ( top >= 0 )
+ {
+ level = levels[top];
+ if ( level > 1 )
+ {
+ /* check that the arc crosses the current band */
+ TPos min, max, y;
+
+
+ min = max = arc[0].y;
+ y = arc[1].y;
+ if ( y < min ) min = y;
+ if ( y > max ) max = y;
+ y = arc[2].y;
+ if ( y < min ) min = y;
+ if ( y > max ) max = y;
+ y = arc[3].y;
+ if ( y < min ) min = y;
+ if ( y > max ) max = y;
+ if ( TRUNC( min ) >= ras.max_ey || TRUNC( max ) < 0 )
+ goto Draw;
+ gray_split_cubic( arc );
+ arc += 3;
+ top ++;
+ levels[top] = levels[top - 1] = level - 1;
+ continue;
+ }
+
+ Draw:
+ {
+ TPos to_x, to_y, mid_x, mid_y;
+
+
+ to_x = arc[0].x;
+ to_y = arc[0].y;
+ mid_x = ( ras.x + to_x + 3 * ( arc[1].x + arc[2].x ) ) / 8;
+ mid_y = ( ras.y + to_y + 3 * ( arc[1].y + arc[2].y ) ) / 8;
+
+ gray_render_line( RAS_VAR_ mid_x, mid_y );
+ gray_render_line( RAS_VAR_ to_x, to_y );
+ top --;
+ arc -= 3;
+ }
+ }
+ return;
+ }
+
+
+ /* a macro comparing two cell pointers. Returns true if a <= b. */
+#if 1
+
+#define PACK( a ) ( ( (long)(a)->y << 16 ) + (a)->x )
+#define LESS_THAN( a, b ) ( PACK( a ) < PACK( b ) )
+
+#else /* 1 */
+
+#define LESS_THAN( a, b ) ( (a)->y < (b)->y || \
+ ( (a)->y == (b)->y && (a)->x < (b)->x ) )
+
+#endif /* 1 */
+
+#define SWAP_CELLS( a, b, temp ) do \
+ { \
+ temp = *(a); \
+ *(a) = *(b); \
+ *(b) = temp; \
+ } while ( 0 )
+#define DEBUG_SORT
+#define QUICK_SORT
+
+#ifdef SHELL_SORT
+
+ /* a simple shell sort algorithm that works directly on our */
+ /* cells table */
+ static void
+ gray_shell_sort ( PCell cells,
+ int count )
+ {
+ PCell i, j, limit = cells + count;
+ TCell temp;
+ int gap;
+
+
+ /* compute initial gap */
+ for ( gap = 0; ++gap < count; gap *= 3 )
+ ;
+
+ while ( gap /= 3 )
+ {
+ for ( i = cells + gap; i < limit; i++ )
+ {
+ for ( j = i - gap; ; j -= gap )
+ {
+ PCell k = j + gap;
+
+
+ if ( LESS_THAN( j, k ) )
+ break;
+
+ SWAP_CELLS( j, k, temp );
+
+ if ( j < cells + gap )
+ break;
+ }
+ }
+ }
+ }
+
+#endif /* SHELL_SORT */
+
+
+#ifdef QUICK_SORT
+
+ /* This is a non-recursive quicksort that directly process our cells */
+ /* array. It should be faster than calling the stdlib qsort(), and we */
+ /* can even tailor our insertion threshold... */
+
+#define QSORT_THRESHOLD 9 /* below this size, a sub-array will be sorted */
+ /* through a normal insertion sort */
+
+ static void
+ gray_quick_sort( PCell cells,
+ int count )
+ {
+ PCell stack[40]; /* should be enough ;-) */
+ PCell* top; /* top of stack */
+ PCell base, limit;
+ TCell temp;
+
+
+ limit = cells + count;
+ base = cells;
+ top = stack;
+
+ for (;;)
+ {
+ int len = (int)( limit - base );
+ PCell i, j, pivot;
+
+
+ if ( len > QSORT_THRESHOLD )
+ {
+ /* we use base + len/2 as the pivot */
+ pivot = base + len / 2;
+ SWAP_CELLS( base, pivot, temp );
+
+ i = base + 1;
+ j = limit - 1;
+
+ /* now ensure that *i <= *base <= *j */
+ if ( LESS_THAN( j, i ) )
+ SWAP_CELLS( i, j, temp );
+
+ if ( LESS_THAN( base, i ) )
+ SWAP_CELLS( base, i, temp );
+
+ if ( LESS_THAN( j, base ) )
+ SWAP_CELLS( base, j, temp );
+
+ for (;;)
+ {
+ do i++; while ( LESS_THAN( i, base ) );
+ do j--; while ( LESS_THAN( base, j ) );
+
+ if ( i > j )
+ break;
+
+ SWAP_CELLS( i, j, temp );
+ }
+
+ SWAP_CELLS( base, j, temp );
+
+ /* now, push the largest sub-array */
+ if ( j - base > limit - i )
+ {
+ top[0] = base;
+ top[1] = j;
+ base = i;
+ }
+ else
+ {
+ top[0] = i;
+ top[1] = limit;
+ limit = j;
+ }
+ top += 2;
+ }
+ else
+ {
+ /* the sub-array is small, perform insertion sort */
+ j = base;
+ i = j + 1;
+
+ for ( ; i < limit; j = i, i++ )
+ {
+ for ( ; LESS_THAN( j + 1, j ); j-- )
+ {
+ SWAP_CELLS( j + 1, j, temp );
+ if ( j == base )
+ break;
+ }
+ }
+ if ( top > stack )
+ {
+ top -= 2;
+ base = top[0];
+ limit = top[1];
+ }
+ else
+ break;
+ }
+ }
+ }
+
+#endif /* QUICK_SORT */
+
+
+#ifdef DEBUG_GRAYS
+#ifdef DEBUG_SORT
+
+ static int
+ gray_check_sort( PCell cells,
+ int count )
+ {
+ PCell p, q;
+
+
+ for ( p = cells + count - 2; p >= cells; p-- )
+ {
+ q = p + 1;
+ if ( !LESS_THAN( p, q ) )
+ return 0;
+ }
+ return 1;
+ }
+
+#endif /* DEBUG_SORT */
+#endif /* DEBUG_GRAYS */
+
+
+ static int
+ gray_move_to( FT_Vector* to,
+ FT_Raster raster )
+ {
+ TPos x, y;
+
+
+ /* record current cell, if any */
+ gray_record_cell( (PRaster)raster );
+
+ /* start to a new position */
+ x = UPSCALE( to->x );
+ y = UPSCALE( to->y );
+
+ gray_start_cell( (PRaster)raster, TRUNC( x ), TRUNC( y ) );
+
+ ((PRaster)raster)->x = x;
+ ((PRaster)raster)->y = y;
+ return 0;
+ }
+
+
+ static int
+ gray_line_to( FT_Vector* to,
+ FT_Raster raster )
+ {
+ gray_render_line( (PRaster)raster,
+ UPSCALE( to->x ), UPSCALE( to->y ) );
+ return 0;
+ }
+
+
+ static int
+ gray_conic_to( FT_Vector* control,
+ FT_Vector* to,
+ FT_Raster raster )
+ {
+ gray_render_conic( (PRaster)raster, control, to );
+ return 0;
+ }
+
+
+ static int
+ gray_cubic_to( FT_Vector* control1,
+ FT_Vector* control2,
+ FT_Vector* to,
+ FT_Raster raster )
+ {
+ gray_render_cubic( (PRaster)raster, control1, control2, to );
+ return 0;
+ }
+
+
+ static void
+ gray_render_span( int y,
+ int count,
+ FT_Span* spans,
+ PRaster raster )
+ {
+ unsigned char* p;
+ FT_Bitmap* map = &raster->target;
+
+
+ /* first of all, compute the scanline offset */
+ p = (unsigned char*)map->buffer - y * map->pitch;
+ if ( map->pitch >= 0 )
+ p += ( map->rows - 1 ) * map->pitch;
+
+ for ( ; count > 0; count--, spans++ )
+ {
+ unsigned char coverage = spans->coverage;
+
+
+#ifdef GRAYS_USE_GAMMA
+ coverage = raster->gamma[coverage];
+#endif
+
+ if ( coverage )
+#if 1
+ FT_MEM_SET( p + spans->x, (unsigned char)coverage, spans->len );
+#else /* 1 */
+ {
+ q = p + spans->x;
+ limit = q + spans->len;
+ for ( ; q < limit; q++ )
+ q[0] = (unsigned char)coverage;
+ }
+#endif /* 1 */
+ }
+ }
+
+
+#ifdef DEBUG_GRAYS
+
+#include <stdio.h>
+
+ static void
+ gray_dump_cells( RAS_ARG )
+ {
+ PCell cell, limit;
+ int y = -1;
+
+
+ cell = ras.cells;
+ limit = cell + ras.num_cells;
+
+ for ( ; cell < limit; cell++ )
+ {
+ if ( cell->y != y )
+ {
+ fprintf( stderr, "\n%2d: ", cell->y );
+ y = cell->y;
+ }
+ fprintf( stderr, "[%d %d %d]",
+ cell->x, cell->area, cell->cover );
+ }
+ fprintf(stderr, "\n" );
+ }
+
+#endif /* DEBUG_GRAYS */
+
+
+ static void
+ gray_hline( RAS_ARG_ TCoord x,
+ TCoord y,
+ TPos area,
+ int acount )
+ {
+ FT_Span* span;
+ int count;
+ int coverage;
+
+
+ /* compute the coverage line's coverage, depending on the */
+ /* outline fill rule */
+ /* */
+ /* the coverage percentage is area/(PIXEL_BITS*PIXEL_BITS*2) */
+ /* */
+ coverage = (int)( area >> ( PIXEL_BITS * 2 + 1 - 8 ) );
+ /* use range 0..256 */
+ if ( coverage < 0 )
+ coverage = -coverage;
+
+ if ( ras.outline.flags & FT_OUTLINE_EVEN_ODD_FILL )
+ {
+ coverage &= 511;
+
+ if ( coverage > 256 )
+ coverage = 512 - coverage;
+ else if ( coverage == 256 )
+ coverage = 255;
+ }
+ else
+ {
+ /* normal non-zero winding rule */
+ if ( coverage >= 256 )
+ coverage = 255;
+ }
+
+ y += (TCoord)ras.min_ey;
+ x += (TCoord)ras.min_ex;
+
+ if ( coverage )
+ {
+ /* see if we can add this span to the current list */
+ count = ras.num_gray_spans;
+ span = ras.gray_spans + count - 1;
+ if ( count > 0 &&
+ ras.span_y == y &&
+ (int)span->x + span->len == (int)x &&
+ span->coverage == coverage )
+ {
+ span->len = (unsigned short)( span->len + acount );
+ return;
+ }
+
+ if ( ras.span_y != y || count >= FT_MAX_GRAY_SPANS )
+ {
+ if ( ras.render_span && count > 0 )
+ ras.render_span( ras.span_y, count, ras.gray_spans,
+ ras.render_span_data );
+ /* ras.render_span( span->y, ras.gray_spans, count ); */
+
+#ifdef DEBUG_GRAYS
+
+ if ( ras.span_y >= 0 )
+ {
+ int n;
+
+
+ fprintf( stderr, "y=%3d ", ras.span_y );
+ span = ras.gray_spans;
+ for ( n = 0; n < count; n++, span++ )
+ fprintf( stderr, "[%d..%d]:%02x ",
+ span->x, span->x + span->len - 1, span->coverage );
+ fprintf( stderr, "\n" );
+ }
+
+#endif /* DEBUG_GRAYS */
+
+ ras.num_gray_spans = 0;
+ ras.span_y = y;
+
+ count = 0;
+ span = ras.gray_spans;
+ }
+ else
+ span++;
+
+ /* add a gray span to the current list */
+ span->x = (short)x;
+ span->len = (unsigned short)acount;
+ span->coverage = (unsigned char)coverage;
+ ras.num_gray_spans++;
+ }
+ }
+
+
+ static void
+ gray_sweep( RAS_ARG_ FT_Bitmap* target )
+ {
+ TCoord x, y, cover;
+ TArea area;
+ PCell start, cur, limit;
+
+ FT_UNUSED( target );
+
+
+ if ( ras.num_cells == 0 )
+ return;
+
+ cur = ras.cells;
+ limit = cur + ras.num_cells;
+
+ cover = 0;
+ ras.span_y = -1;
+ ras.num_gray_spans = 0;
+
+ for (;;)
+ {
+ start = cur;
+ y = start->y;
+ x = start->x;
+
+ area = start->area;
+ cover += start->cover;
+
+ /* accumulate all start cells */
+ for (;;)
+ {
+ ++cur;
+ if ( cur >= limit || cur->y != start->y || cur->x != start->x )
+ break;
+
+ area += cur->area;
+ cover += cur->cover;
+ }
+
+ /* if the start cell has a non-null area, we must draw an */
+ /* individual gray pixel there */
+ if ( area && x >= 0 )
+ {
+ gray_hline( RAS_VAR_ x, y, cover * ( ONE_PIXEL * 2 ) - area, 1 );
+ x++;
+ }
+
+ if ( x < 0 )
+ x = 0;
+
+ if ( cur < limit && start->y == cur->y )
+ {
+ /* draw a gray span between the start cell and the current one */
+ if ( cur->x > x )
+ gray_hline( RAS_VAR_ x, y,
+ cover * ( ONE_PIXEL * 2 ), cur->x - x );
+ }
+ else
+ {
+ /* draw a gray span until the end of the clipping region */
+ if ( cover && x < ras.max_ex - ras.min_ex )
+ gray_hline( RAS_VAR_ x, y,
+ cover * ( ONE_PIXEL * 2 ),
+ (int)( ras.max_ex - x - ras.min_ex ) );
+ cover = 0;
+ }
+
+ if ( cur >= limit )
+ break;
+ }
+
+ if ( ras.render_span && ras.num_gray_spans > 0 )
+ ras.render_span( ras.span_y, ras.num_gray_spans,
+ ras.gray_spans, ras.render_span_data );
+
+#ifdef DEBUG_GRAYS
+
+ {
+ int n;
+ FT_Span* span;
+
+
+ fprintf( stderr, "y=%3d ", ras.span_y );
+ span = ras.gray_spans;
+ for ( n = 0; n < ras.num_gray_spans; n++, span++ )
+ fprintf( stderr, "[%d..%d]:%02x ",
+ span->x, span->x + span->len - 1, span->coverage );
+ fprintf( stderr, "\n" );
+ }
+
+#endif /* DEBUG_GRAYS */
+
+ }
+
+
+#ifdef _STANDALONE_
+
+ /*************************************************************************/
+ /* */
+ /* The following function should only compile in stand_alone mode, */
+ /* i.e., when building this component without the rest of FreeType. */
+ /* */
+ /*************************************************************************/
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* FT_Outline_Decompose */
+ /* */
+ /* <Description> */
+ /* Walks over an outline's structure to decompose it into individual */
+ /* segments and Bezier arcs. This function is also able to emit */
+ /* `move to' and `close to' operations to indicate the start and end */
+ /* of new contours in the outline. */
+ /* */
+ /* <Input> */
+ /* outline :: A pointer to the source target. */
+ /* */
+ /* func_interface :: A table of `emitters', i.e,. function pointers */
+ /* called during decomposition to indicate path */
+ /* operations. */
+ /* */
+ /* user :: A typeless pointer which is passed to each */
+ /* emitter during the decomposition. It can be */
+ /* used to store the state during the */
+ /* decomposition. */
+ /* */
+ /* <Return> */
+ /* Error code. 0 means sucess. */
+ /* */
+ static
+ int FT_Outline_Decompose( FT_Outline* outline,
+ const FT_Outline_Funcs* func_interface,
+ void* user )
+ {
+#undef SCALED
+#if 0
+#define SCALED( x ) ( ( (x) << shift ) - delta )
+#else
+#define SCALED( x ) (x)
+#endif
+
+ FT_Vector v_last;
+ FT_Vector v_control;
+ FT_Vector v_start;
+
+ FT_Vector* point;
+ FT_Vector* limit;
+ char* tags;
+
+ int n; /* index of contour in outline */
+ int first; /* index of first point in contour */
+ int error;
+ char tag; /* current point's state */
+
+#if 0
+ int shift = func_interface->shift;
+ TPos delta = func_interface->delta;
+#endif
+
+
+ first = 0;
+
+ for ( n = 0; n < outline->n_contours; n++ )
+ {
+ int last; /* index of last point in contour */
+
+
+ last = outline->contours[n];
+ limit = outline->points + last;
+
+ v_start = outline->points[first];
+ v_last = outline->points[last];
+
+ v_start.x = SCALED( v_start.x ); v_start.y = SCALED( v_start.y );
+ v_last.x = SCALED( v_last.x ); v_last.y = SCALED( v_last.y );
+
+ v_control = v_start;
+
+ point = outline->points + first;
+ tags = outline->tags + first;
+ tag = FT_CURVE_TAG( tags[0] );
+
+ /* A contour cannot start with a cubic control point! */
+ if ( tag == FT_CURVE_TAG_CUBIC )
+ goto Invalid_Outline;
+
+ /* check first point to determine origin */
+ if ( tag == FT_CURVE_TAG_CONIC )
+ {
+ /* first point is conic control. Yes, this happens. */
+ if ( FT_CURVE_TAG( outline->tags[last] ) == FT_CURVE_TAG_ON )
+ {
+ /* start at last point if it is on the curve */
+ v_start = v_last;
+ limit--;
+ }
+ else
+ {
+ /* if both first and last points are conic, */
+ /* start at their middle and record its position */
+ /* for closure */
+ v_start.x = ( v_start.x + v_last.x ) / 2;
+ v_start.y = ( v_start.y + v_last.y ) / 2;
+
+ v_last = v_start;
+ }
+ point--;
+ tags--;
+ }
+
+ error = func_interface->move_to( &v_start, user );
+ if ( error )
+ goto Exit;
+
+ while ( point < limit )
+ {
+ point++;
+ tags++;
+
+ tag = FT_CURVE_TAG( tags[0] );
+ switch ( tag )
+ {
+ case FT_CURVE_TAG_ON: /* emit a single line_to */
+ {
+ FT_Vector vec;
+
+
+ vec.x = SCALED( point->x );
+ vec.y = SCALED( point->y );
+
+ error = func_interface->line_to( &vec, user );
+ if ( error )
+ goto Exit;
+ continue;
+ }
+
+ case FT_CURVE_TAG_CONIC: /* consume conic arcs */
+ {
+ v_control.x = SCALED( point->x );
+ v_control.y = SCALED( point->y );
+
+ Do_Conic:
+ if ( point < limit )
+ {
+ FT_Vector vec;
+ FT_Vector v_middle;
+
+
+ point++;
+ tags++;
+ tag = FT_CURVE_TAG( tags[0] );
+
+ vec.x = SCALED( point->x );
+ vec.y = SCALED( point->y );
+
+ if ( tag == FT_CURVE_TAG_ON )
+ {
+ error = func_interface->conic_to( &v_control, &vec, user );
+ if ( error )
+ goto Exit;
+ continue;
+ }
+
+ if ( tag != FT_CURVE_TAG_CONIC )
+ goto Invalid_Outline;
+
+ v_middle.x = ( v_control.x + vec.x ) / 2;
+ v_middle.y = ( v_control.y + vec.y ) / 2;
+
+ error = func_interface->conic_to( &v_control, &v_middle, user );
+ if ( error )
+ goto Exit;
+
+ v_control = vec;
+ goto Do_Conic;
+ }
+
+ error = func_interface->conic_to( &v_control, &v_start, user );
+ goto Close;
+ }
+
+ default: /* FT_CURVE_TAG_CUBIC */
+ {
+ FT_Vector vec1, vec2;
+
+
+ if ( point + 1 > limit ||
+ FT_CURVE_TAG( tags[1] ) != FT_CURVE_TAG_CUBIC )
+ goto Invalid_Outline;
+
+ point += 2;
+ tags += 2;
+
+ vec1.x = SCALED( point[-2].x ); vec1.y = SCALED( point[-2].y );
+ vec2.x = SCALED( point[-1].x ); vec2.y = SCALED( point[-1].y );
+
+ if ( point <= limit )
+ {
+ FT_Vector vec;
+
+
+ vec.x = SCALED( point->x );
+ vec.y = SCALED( point->y );
+
+ error = func_interface->cubic_to( &vec1, &vec2, &vec, user );
+ if ( error )
+ goto Exit;
+ continue;
+ }
+
+ error = func_interface->cubic_to( &vec1, &vec2, &v_start, user );
+ goto Close;
+ }
+ }
+ }
+
+ /* close the contour with a line segment */
+ error = func_interface->line_to( &v_start, user );
+
+ Close:
+ if ( error )
+ goto Exit;
+
+ first = last + 1;
+ }
+
+ return 0;
+
+ Exit:
+ return error;
+
+ Invalid_Outline:
+ return ErrRaster_Invalid_Outline;
+ }
+
+#endif /* _STANDALONE_ */
+
+
+ typedef struct TBand_
+ {
+ TPos min, max;
+
+ } TBand;
+
+
+ static int
+ gray_convert_glyph_inner( RAS_ARG )
+ {
+ static
+ const FT_Outline_Funcs func_interface =
+ {
+ (FT_Outline_MoveTo_Func) gray_move_to,
+ (FT_Outline_LineTo_Func) gray_line_to,
+ (FT_Outline_ConicTo_Func)gray_conic_to,
+ (FT_Outline_CubicTo_Func)gray_cubic_to,
+ 0,
+ 0
+ };
+
+ volatile int error = 0;
+
+ if ( ft_setjmp( ras.jump_buffer ) == 0 )
+ {
+ error = FT_Outline_Decompose( &ras.outline, &func_interface, &ras );
+ gray_record_cell( RAS_VAR );
+ }
+ else
+ {
+ error = ErrRaster_MemoryOverflow;
+ }
+
+ return error;
+ }
+
+
+ static int
+ gray_convert_glyph( RAS_ARG )
+ {
+ TBand bands[40];
+ volatile TBand* band;
+ volatile int n, num_bands;
+ volatile TPos min, max, max_y;
+ FT_BBox* clip;
+
+
+ /* Set up state in the raster object */
+ gray_compute_cbox( RAS_VAR );
+
+ /* clip to target bitmap, exit if nothing to do */
+ clip = &ras.clip_box;
+
+ if ( ras.max_ex <= clip->xMin || ras.min_ex >= clip->xMax ||
+ ras.max_ey <= clip->yMin || ras.min_ey >= clip->yMax )
+ return 0;
+
+ if ( ras.min_ex < clip->xMin ) ras.min_ex = clip->xMin;
+ if ( ras.min_ey < clip->yMin ) ras.min_ey = clip->yMin;
+
+ if ( ras.max_ex > clip->xMax ) ras.max_ex = clip->xMax;
+ if ( ras.max_ey > clip->yMax ) ras.max_ey = clip->yMax;
+
+ /* simple heuristic used to speed-up the bezier decomposition -- see */
+ /* the code in gray_render_conic() and gray_render_cubic() for more */
+ /* details */
+ ras.conic_level = 32;
+ ras.cubic_level = 16;
+
+ {
+ int level = 0;
+
+
+ if ( ras.max_ex > 24 || ras.max_ey > 24 )
+ level++;
+ if ( ras.max_ex > 120 || ras.max_ey > 120 )
+ level++;
+
+ ras.conic_level <<= level;
+ ras.cubic_level <<= level;
+ }
+
+ /* setup vertical bands */
+ num_bands = (int)( ( ras.max_ey - ras.min_ey ) / ras.band_size );
+ if ( num_bands == 0 ) num_bands = 1;
+ if ( num_bands >= 39 ) num_bands = 39;
+
+ ras.band_shoot = 0;
+
+ min = ras.min_ey;
+ max_y = ras.max_ey;
+
+ for ( n = 0; n < num_bands; n++, min = max )
+ {
+ max = min + ras.band_size;
+ if ( n == num_bands - 1 || max > max_y )
+ max = max_y;
+
+ bands[0].min = min;
+ bands[0].max = max;
+ band = bands;
+
+ while ( band >= bands )
+ {
+ TPos bottom, top, middle;
+ int error;
+
+
+ ras.num_cells = 0;
+ ras.invalid = 1;
+ ras.min_ey = band->min;
+ ras.max_ey = band->max;
+
+#if 1
+ error = gray_convert_glyph_inner( RAS_VAR );
+#else
+ error = FT_Outline_Decompose( outline, &func_interface, &ras ) ||
+ gray_record_cell( RAS_VAR );
+#endif
+
+ if ( !error )
+ {
+#ifdef SHELL_SORT
+ gray_shell_sort( ras.cells, ras.num_cells );
+#else
+ gray_quick_sort( ras.cells, ras.num_cells );
+#endif
+
+#ifdef DEBUG_GRAYS
+ gray_check_sort( ras.cells, ras.num_cells );
+ gray_dump_cells( RAS_VAR );
+#endif
+
+ gray_sweep( RAS_VAR_ &ras.target );
+ band--;
+ continue;
+ }
+ else if ( error != ErrRaster_MemoryOverflow )
+ return 1;
+
+ /* render pool overflow, we will reduce the render band by half */
+ bottom = band->min;
+ top = band->max;
+ middle = bottom + ( ( top - bottom ) >> 1 );
+
+ /* waoow! This is too complex for a single scanline, something */
+ /* must be really rotten here! */
+ if ( middle == bottom )
+ {
+#ifdef DEBUG_GRAYS
+ fprintf( stderr, "Rotten glyph!\n" );
+#endif
+ return 1;
+ }
+
+ if ( bottom-top >= ras.band_size )
+ ras.band_shoot++;
+
+ band[1].min = bottom;
+ band[1].max = middle;
+ band[0].min = middle;
+ band[0].max = top;
+ band++;
+ }
+ }
+
+ if ( ras.band_shoot > 8 && ras.band_size > 16 )
+ ras.band_size = ras.band_size / 2;
+
+ return 0;
+ }
+
+
+ extern int
+ gray_raster_render( PRaster raster,
+ FT_Raster_Params* params )
+ {
+ FT_Outline* outline = (FT_Outline*)params->source;
+ FT_Bitmap* target_map = params->target;
+
+
+ if ( !raster || !raster->cells || !raster->max_cells )
+ return -1;
+
+ /* return immediately if the outline is empty */
+ if ( outline->n_points == 0 || outline->n_contours <= 0 )
+ return 0;
+
+ if ( !outline || !outline->contours || !outline->points )
+ return ErrRaster_Invalid_Outline;
+
+ if ( outline->n_points !=
+ outline->contours[outline->n_contours - 1] + 1 )
+ return ErrRaster_Invalid_Outline;
+
+ /* if direct mode is not set, we must have a target bitmap */
+ if ( ( params->flags & FT_RASTER_FLAG_DIRECT ) == 0 &&
+ ( !target_map || !target_map->buffer ) )
+ return -1;
+
+ /* this version does not support monochrome rendering */
+ if ( !( params->flags & FT_RASTER_FLAG_AA ) )
+ return ErrRaster_Invalid_Mode;
+
+ /* compute clipping box */
+ if ( ( params->flags & FT_RASTER_FLAG_DIRECT ) == 0 )
+ {
+ /* compute clip box from target pixmap */
+ ras.clip_box.xMin = 0;
+ ras.clip_box.yMin = 0;
+ ras.clip_box.xMax = target_map->width;
+ ras.clip_box.yMax = target_map->rows;
+ }
+ else if ( params->flags & FT_RASTER_FLAG_CLIP )
+ {
+ ras.clip_box = params->clip_box;
+ }
+ else
+ {
+ ras.clip_box.xMin = -32768L;
+ ras.clip_box.yMin = -32768L;
+ ras.clip_box.xMax = 32767L;
+ ras.clip_box.yMax = 32767L;
+ }
+
+ ras.outline = *outline;
+ ras.num_cells = 0;
+ ras.invalid = 1;
+
+ if ( target_map )
+ ras.target = *target_map;
+
+ ras.render_span = (FT_Raster_Span_Func)gray_render_span;
+ ras.render_span_data = &ras;
+
+ if ( params->flags & FT_RASTER_FLAG_DIRECT )
+ {
+ ras.render_span = (FT_Raster_Span_Func)params->gray_spans;
+ ras.render_span_data = params->user;
+ }
+
+ return gray_convert_glyph( (PRaster)raster );
+ }
+
+
+ /**** RASTER OBJECT CREATION: In standalone mode, we simply use *****/
+ /**** a static object. *****/
+
+#ifdef GRAYS_USE_GAMMA
+
+ /* initialize the "gamma" table. Yes, this is really a crummy function */
+ /* but the results look pretty good for something that simple. */
+ /* */
+#define M_MAX 255
+#define M_X 128
+#define M_Y 192
+
+ static void
+ grays_init_gamma( PRaster raster )
+ {
+ unsigned int x, a;
+
+
+ for ( x = 0; x < 256; x++ )
+ {
+ if ( x <= M_X )
+ a = ( x * M_Y + M_X / 2) / M_X;
+ else
+ a = M_Y + ( ( x - M_X ) * ( M_MAX - M_Y ) +
+ ( M_MAX - M_X ) / 2 ) / ( M_MAX - M_X );
+
+ raster->gamma[x] = (unsigned char)a;
+ }
+ }
+
+#endif /* GRAYS_USE_GAMMA */
+
+#ifdef _STANDALONE_
+
+ static int
+ gray_raster_new( void* memory,
+ FT_Raster* araster )
+ {
+ static TRaster the_raster;
+
+ FT_UNUSED( memory );
+
+
+ *araster = (FT_Raster)&the_raster;
+ FT_MEM_ZERO( &the_raster, sizeof ( the_raster ) );
+
+#ifdef GRAYS_USE_GAMMA
+ grays_init_gamma( (PRaster)*araster );
+#endif
+
+ return 0;
+ }
+
+
+ static void
+ gray_raster_done( FT_Raster raster )
+ {
+ /* nothing */
+ FT_UNUSED( raster );
+ }
+
+#else /* _STANDALONE_ */
+
+ static int
+ gray_raster_new( FT_Memory memory,
+ FT_Raster* araster )
+ {
+ FT_Error error;
+ PRaster raster;
+
+
+ *araster = 0;
+ if ( !FT_ALLOC( raster, sizeof ( TRaster ) ) )
+ {
+ raster->memory = memory;
+ *araster = (FT_Raster)raster;
+
+#ifdef GRAYS_USE_GAMMA
+ grays_init_gamma( raster );
+#endif
+ }
+
+ return error;
+ }
+
+
+ static void
+ gray_raster_done( FT_Raster raster )
+ {
+ FT_Memory memory = (FT_Memory)((PRaster)raster)->memory;
+
+
+ FT_FREE( raster );
+ }
+
+#endif /* _STANDALONE_ */
+
+
+ static void
+ gray_raster_reset( FT_Raster raster,
+ const char* pool_base,
+ long pool_size )
+ {
+ PRaster rast = (PRaster)raster;
+
+
+ if ( raster && pool_base && pool_size >= 4096 )
+ gray_init_cells( rast, (char*)pool_base, pool_size );
+
+ rast->band_size = (int)( ( pool_size / sizeof ( TCell ) ) / 8 );
+ }
+
+
+ const FT_Raster_Funcs ft_grays_raster =
+ {
+ FT_GLYPH_FORMAT_OUTLINE,
+
+ (FT_Raster_New_Func) gray_raster_new,
+ (FT_Raster_Reset_Func) gray_raster_reset,
+ (FT_Raster_Set_Mode_Func)0,
+ (FT_Raster_Render_Func) gray_raster_render,
+ (FT_Raster_Done_Func) gray_raster_done
+ };
+
+
+/* END */
--- /dev/null
+++ b/libfreetype/ftgrays.h
@@ -1,0 +1,57 @@
+/***************************************************************************/
+/* */
+/* ftgrays.h */
+/* */
+/* FreeType smooth renderer declaration */
+/* */
+/* Copyright 1996-2001 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+
+#ifndef __FTGRAYS_H__
+#define __FTGRAYS_H__
+
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
+
+#ifdef _STANDALONE_
+#include "ftimage.h"
+#else
+#include <ft2build.h>
+#include FT_IMAGE_H
+#endif
+
+
+ /*************************************************************************/
+ /* */
+ /* To make ftgrays.h independent from configuration files we check */
+ /* whether FT_EXPORT_VAR has been defined already. */
+ /* */
+ /* On some systems and compilers (Win32 mostly), an extra keyword is */
+ /* necessary to compile the library as a DLL. */
+ /* */
+#ifndef FT_EXPORT_VAR
+#define FT_EXPORT_VAR( x ) extern x
+#endif
+
+ FT_EXPORT_VAR( const FT_Raster_Funcs ) ft_grays_raster;
+
+
+#ifdef __cplusplus
+ }
+#endif
+
+#endif /* __FTGRAYS_H__ */
+
+
+/* END */
--- /dev/null
+++ b/libfreetype/ftgzip.c
@@ -1,0 +1,561 @@
+/***************************************************************************/
+/* */
+/* ftgzip.c */
+/* */
+/* FreeType support for .gz compressed fileds */
+/* */
+/* this optional component relies on zlib. It should mainly be used to */
+/* parse compressed PCF fonts, as found with many X11 server */
+/* distributions. */
+/* */
+/* Copyright 2002 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+#include <ft2build.h>
+#include FT_INTERNAL_MEMORY_H
+#include FT_INTERNAL_STREAM_H
+#include FT_INTERNAL_DEBUG_H
+#include <string.h>
+
+#ifdef FT_CONFIG_OPTION_USE_ZLIB
+
+#ifdef FT_CONFIG_OPTION_SYSTEM_ZLIB
+
+# include "zlib.h"
+
+#else /* !SYSTEM_ZLIB */
+
+ /* in this case, we include our own modified sources of the ZLib */
+ /* within the "ftgzip" component. The modifications were necessary */
+ /* to #include all files without conflicts, as well as preventing */
+ /* the definition of "extern" functions that may cause linking */
+ /* conflicts when a program is linked with both FreeType and the */
+ /* original ZLib */
+
+# define NO_DUMMY_DECL
+# define BUILDFIXED /* save code size */
+# define MY_ZCALLOC
+
+# include "zlib.h"
+
+# undef SLOW
+# define SLOW 1 /* we can't use asm-optimized sources here !! */
+
+# include "zutil.c"
+# include "inftrees.c"
+# include "infcodes.c"
+# include "infutil.c"
+# include "infblock.c"
+# include "inflate.c"
+# include "adler32.c"
+
+#endif /* !SYSTEM_ZLIB */
+
+
+/***************************************************************************/
+/***************************************************************************/
+/***** *****/
+/***** Z L I B M E M O R Y M A N A G E M E N T *****/
+/***** *****/
+/***************************************************************************/
+/***************************************************************************/
+
+ /* it's better to use FreeType memory routines instead of raw 'malloc/free' */
+
+
+ static voidpf
+ ft_gzip_alloc( FT_Memory memory,
+ uInt items,
+ uInt size )
+ {
+ FT_ULong sz = (FT_ULong)size * items;
+ FT_Pointer p;
+
+ FT_MEM_ALLOC( p, sz );
+
+ return (voidpf) p;
+ }
+
+
+ static void
+ ft_gzip_free( FT_Memory memory,
+ voidpf address )
+ {
+ FT_MEM_FREE( address );
+ }
+
+
+#ifndef FT_CONFIG_OPTION_SYSTEM_ZLIB
+
+ local voidpf
+ zcalloc (opaque, items, size)
+ voidpf opaque;
+ unsigned items;
+ unsigned size;
+ {
+ return ft_gzip_alloc( opaque, items, size );
+ }
+
+ local void
+ zcfree( voidpf opaque,
+ voidpf ptr )
+ {
+ ft_gzip_free( opaque, ptr );
+ }
+
+#endif /* !SYSTEM_ZLIB */
+
+
+/***************************************************************************/
+/***************************************************************************/
+/***** *****/
+/***** Z L I B F I L E D E S C R I P T O R *****/
+/***** *****/
+/***************************************************************************/
+/***************************************************************************/
+
+#define FT_GZIP_BUFFER_SIZE 4096
+
+ typedef struct FT_GZipFileRec_
+ {
+ FT_Stream source; /* parent/source stream */
+ FT_Stream stream; /* embedding stream */
+ FT_Memory memory; /* memory allocator */
+ z_stream zstream; /* zlib input stream */
+
+ FT_ULong start; /* starting position, after .gz header */
+ FT_Byte input[ FT_GZIP_BUFFER_SIZE ]; /* input read buffer */
+
+ FT_Byte buffer[ FT_GZIP_BUFFER_SIZE ]; /* output buffer */
+ FT_ULong pos; /* position in output */
+ FT_Byte* cursor;
+ FT_Byte* limit;
+
+ } FT_GZipFileRec, *FT_GZipFile;
+
+
+/* gzip flag byte */
+#define FT_GZIP_ASCII_FLAG 0x01 /* bit 0 set: file probably ascii text */
+#define FT_GZIP_HEAD_CRC 0x02 /* bit 1 set: header CRC present */
+#define FT_GZIP_EXTRA_FIELD 0x04 /* bit 2 set: extra field present */
+#define FT_GZIP_ORIG_NAME 0x08 /* bit 3 set: original file name present */
+#define FT_GZIP_COMMENT 0x10 /* bit 4 set: file comment present */
+#define FT_GZIP_RESERVED 0xE0 /* bits 5..7: reserved */
+
+
+ /* check and skip .gz header - we don't support "transparent" compression */
+ static FT_Error
+ ft_gzip_check_header( FT_Stream stream )
+ {
+ FT_Error error;
+ FT_Byte head[4];
+
+ if ( FT_STREAM_SEEK( 0 ) ||
+ FT_STREAM_READ( head, 4 ) )
+ goto Exit;
+
+ /* head[0] && head[1] are the magic numbers */
+ /* head[2] is the method, and head[3] the flags */
+ if ( head[0] != 0x1f ||
+ head[1] != 0x8b ||
+ head[2] != Z_DEFLATED ||
+ (head[3] & FT_GZIP_RESERVED) )
+ {
+ error = FT_Err_Invalid_File_Format;
+ goto Exit;
+ }
+
+ /* skip time, xflags and os code */
+ (void)FT_STREAM_SKIP( 6 );
+
+ /* skip the extra field */
+ if ( head[3] && FT_GZIP_EXTRA_FIELD )
+ {
+ FT_UInt len;
+
+ if ( FT_READ_USHORT_LE( len ) ||
+ FT_STREAM_SKIP( len ) )
+ goto Exit;
+ }
+
+ /* skip original file name */
+ if ( head[3] && FT_GZIP_ORIG_NAME )
+ for (;;)
+ {
+ FT_UInt c;
+
+ if ( FT_READ_BYTE( c) )
+ goto Exit;
+
+ if ( c == 0 )
+ break;
+ }
+
+ /* skip .gz comment */
+ if ( head[3] & FT_GZIP_COMMENT )
+ for (;;)
+ {
+ FT_UInt c;
+
+ if ( FT_READ_BYTE( c) )
+ goto Exit;
+
+ if ( c == 0 )
+ break;
+ }
+
+ /* skip CRC */
+ if ( head[3] & FT_GZIP_HEAD_CRC )
+ if ( FT_STREAM_SKIP( 2 ) )
+ goto Exit;
+
+ Exit:
+ return error;
+ }
+
+
+
+ static FT_Error
+ ft_gzip_file_init( FT_GZipFile zip,
+ FT_Stream stream,
+ FT_Stream source )
+ {
+ z_stream* zstream = &zip->zstream;
+ FT_Error error = 0;
+
+ zip->stream = stream;
+ zip->source = source;
+ zip->memory = stream->memory;
+
+ zip->limit = zip->buffer + FT_GZIP_BUFFER_SIZE;
+ zip->cursor = zip->limit;
+ zip->pos = 0;
+
+ /* check and skip .gz header */
+ {
+ stream = source;
+
+ error = ft_gzip_check_header( stream );
+ if (error)
+ goto Exit;
+
+ zip->start = FT_STREAM_POS();
+ }
+
+ /* initialize zlib - there is no zlib header in the compressed stream */
+ zstream->zalloc = (alloc_func) ft_gzip_alloc;
+ zstream->zfree = (free_func) ft_gzip_free;
+ zstream->opaque = stream->memory;
+
+ zstream->avail_in = 0;
+ zstream->next_in = zip->buffer;
+
+ if ( inflateInit2( zstream, -MAX_WBITS ) != Z_OK ||
+ zstream->next_in == NULL )
+ {
+ error = FT_Err_Invalid_File_Format;
+ goto Exit;
+ }
+
+ Exit:
+ return error;
+ }
+
+
+
+ static void
+ ft_gzip_file_done( FT_GZipFile zip )
+ {
+ z_stream* zstream = &zip->zstream;
+
+ /* clear the rest */
+ zstream->zalloc = NULL;
+ zstream->zfree = NULL;
+ zstream->opaque = NULL;
+ zstream->next_in = NULL;
+ zstream->next_out = NULL;
+ zstream->avail_in = 0;
+ zstream->avail_out = 0;
+
+ zip->memory = NULL;
+ zip->source = NULL;
+ zip->stream = NULL;
+ }
+
+
+ static FT_Error
+ ft_gzip_file_reset( FT_GZipFile zip )
+ {
+ FT_Stream stream = zip->source;
+ FT_Error error;
+
+ if ( !FT_STREAM_SEEK( zip->start ) )
+ {
+ z_stream* zstream = &zip->zstream;
+
+ inflateReset( zstream );
+
+ zstream->avail_in = 0;
+ zstream->next_in = zip->input;
+ zstream->avail_out = 0;
+ zstream->next_out = zip->buffer;
+
+ zip->limit = zip->buffer + FT_GZIP_BUFFER_SIZE;
+ zip->cursor = zip->limit;
+ zip->pos = 0;
+ }
+ return error;
+ }
+
+
+ static FT_Error
+ ft_gzip_file_fill_input( FT_GZipFile zip )
+ {
+ z_stream* zstream = &zip->zstream;
+ FT_Stream stream = zip->source;
+ FT_ULong size;
+
+ if ( stream->read )
+ {
+ size = stream->read( stream, stream->pos, zip->input, FT_GZIP_BUFFER_SIZE );
+ if ( size == 0 )
+ return FT_Err_Invalid_Stream_Operation;
+ }
+ else
+ {
+ size = stream->size - stream->pos;
+ if ( size > FT_GZIP_BUFFER_SIZE )
+ size = FT_GZIP_BUFFER_SIZE;
+
+ if ( size == 0 )
+ return FT_Err_Invalid_Stream_Operation;
+
+ FT_MEM_COPY( zip->input, stream->base + stream->pos, size );
+ }
+ stream->pos += size;
+
+ zstream->next_in = zip->input;
+ zstream->avail_in = size;
+
+ return 0;
+ }
+
+
+
+ static FT_Error
+ ft_gzip_file_fill_output( FT_GZipFile zip )
+ {
+ z_stream* zstream = &zip->zstream;
+ FT_Error error = 0;
+
+ zip->cursor = zip->buffer;
+ zstream->next_out = zip->cursor;
+ zstream->avail_out = FT_GZIP_BUFFER_SIZE;
+
+ while ( zstream->avail_out > 0 )
+ {
+ int err;
+
+ if ( zstream->avail_in == 0 )
+ {
+ error = ft_gzip_file_fill_input( zip );
+ if ( error )
+ break;
+ }
+
+ err = inflate( zstream, Z_NO_FLUSH );
+
+ if ( err == Z_STREAM_END )
+ {
+ zip->limit = zstream->next_out;
+ break;
+ }
+ else if ( err != Z_OK )
+ {
+ error = FT_Err_Invalid_Stream_Operation;
+ break;
+ }
+ }
+ return error;
+ }
+
+
+ /* fill output buffer, 'count' must be <= FT_GZIP_BUFFER_SIZE */
+ static FT_Error
+ ft_gzip_file_skip_output( FT_GZipFile zip,
+ FT_ULong count )
+ {
+ FT_Error error = 0;
+ FT_ULong delta;
+
+ for (;;)
+ {
+ delta = (FT_ULong)( zip->limit - zip->cursor );
+ if ( delta >= count )
+ delta = count;
+
+ zip->cursor += delta;
+ zip->pos += delta;
+
+ count -= delta;
+ if ( count == 0 )
+ break;
+
+ error = ft_gzip_file_fill_output( zip );
+ if ( error )
+ break;
+ }
+
+ return error;
+ }
+
+
+ static FT_ULong
+ ft_gzip_file_io( FT_GZipFile zip,
+ FT_ULong pos,
+ FT_Byte* buffer,
+ FT_ULong count )
+ {
+ FT_ULong result = 0;
+ FT_Error error;
+
+ /* reset inflate stream if we're seeking backwards */
+ /* yes, that's not too efficient, but it saves memory :-) */
+ if ( pos < zip->pos )
+ {
+ error = ft_gzip_file_reset( zip );
+ if ( error ) goto Exit;
+ }
+
+ /* skip unwanted bytes */
+ if ( pos > zip->pos )
+ {
+ error = ft_gzip_file_skip_output( zip, (FT_ULong)( pos - zip->pos ) );
+ if (error)
+ goto Exit;
+ }
+
+ if ( count == 0 )
+ goto Exit;
+
+ /* now read the data */
+ for (;;)
+ {
+ FT_ULong delta;
+
+ delta = (FT_ULong)( zip->limit - zip->cursor );
+ if ( delta >= count )
+ delta = count;
+
+ FT_MEM_COPY( buffer, zip->cursor, delta );
+ buffer += delta;
+ result += delta;
+ zip->cursor += delta;
+ zip->pos += delta;
+
+ count -= delta;
+ if ( count == 0 )
+ break;
+
+ error = ft_gzip_file_fill_output( zip );
+ if (error)
+ break;
+ }
+
+ Exit:
+ return result;
+ }
+
+
+/***************************************************************************/
+/***************************************************************************/
+/***** *****/
+/***** G Z E M B E D D I N G S T R E A M *****/
+/***** *****/
+/***************************************************************************/
+/***************************************************************************/
+
+ static void
+ ft_gzip_stream_close( FT_Stream stream )
+ {
+ FT_GZipFile zip = stream->descriptor.pointer;
+ FT_Memory memory = stream->memory;
+
+ if ( zip )
+ {
+ /* finalize gzip file descriptor */
+ ft_gzip_file_done( zip );
+
+ FT_FREE( zip );
+
+ stream->descriptor.pointer = NULL;
+ }
+ }
+
+
+ static FT_ULong
+ ft_gzip_stream_io( FT_Stream stream,
+ FT_ULong pos,
+ FT_Byte* buffer,
+ FT_ULong count )
+ {
+ FT_GZipFile zip = stream->descriptor.pointer;
+
+ return ft_gzip_file_io( zip, pos, buffer, count );
+ }
+
+
+ FT_EXPORT_DEF( FT_Error )
+ FT_Stream_OpenGzip( FT_Stream stream,
+ FT_Stream source )
+ {
+ FT_Error error;
+ FT_Memory memory = source->memory;
+ FT_GZipFile zip;
+
+ FT_ZERO( stream );
+ stream->memory = memory;
+
+ if ( !FT_NEW( zip ) )
+ {
+ error = ft_gzip_file_init( zip, stream, source );
+ if ( error )
+ {
+ FT_FREE( zip );
+ goto Exit;
+ }
+
+ stream->descriptor.pointer = zip;
+ }
+
+ stream->size = 0x7FFFFFFF; /* don't know the real size !! */
+ stream->pos = 0;
+ stream->base = 0;
+ stream->read = ft_gzip_stream_io;
+ stream->close = ft_gzip_stream_close;
+
+ Exit:
+ return error;
+ }
+
+#else /* !FT_CONFIG_OPTION_USE_ZLIB */
+
+ FT_EXPORT_DEF( FT_Error )
+ FT_Stream_OpenGzip( FT_Stream stream,
+ FT_Stream source )
+ {
+ FT_UNUSED( stream );
+ FT_UNUSED( source );
+
+ return FT_Err_Unimplemented_Feature;
+ }
+
+#endif /* !FT_CONFIG_OPTION_USE_ZLIB */
--- /dev/null
+++ b/libfreetype/fthash.c
@@ -1,0 +1,246 @@
+#include <ft2build.h>
+#include FT_TYPES_H
+#include FT_INTERNAL_HASH_H
+#include FT_INTERNAL_MEMORY_H
+#include FT_INTERNAL_DEBUG_H
+
+#define FT_HASH_MAX_LOAD 2
+#define FT_HASH_MIN_LOAD 1
+#define FT_HASH_SUB_LOAD (FT_HASH_MAX_LOAD-FT_HASH_MIN_LOAD)
+
+/* this one _must_ be a power of 2 !! */
+#define FT_HASH_INITIAL_SIZE 8
+
+
+ FT_BASE_DEF( void )
+ ft_hash_done( FT_Hash table,
+ FT_Hash_ForeachFunc node_func,
+ const FT_Pointer node_data )
+ {
+ if ( table )
+ {
+ FT_Memory memory = table->memory;
+
+ if ( node_func )
+ ft_hash_foreach( table, node_func, node_data );
+
+ FT_FREE( table->buckets );
+ table->p = 0;
+ table->mask = 0;
+ table->slack = 0;
+
+ table->node_equal = NULL;
+ }
+ }
+
+
+ FT_BASE_DEF( FT_UInt )
+ ft_hash_get_size( FT_Hash table )
+ {
+ FT_UInt result = 0;
+
+ if ( table )
+ result = (table->p + table->mask + 1)*FT_HASH_MAX_LOAD - table->slack;
+
+ return result;
+ }
+
+
+
+ FT_BASE_DEF( FT_Error )
+ ft_hash_init( FT_Hash table,
+ FT_Hash_EqualFunc equal,
+ FT_Memory memory )
+ {
+ FT_Error error;
+
+ table->memory = memory;
+ table->p = 0;
+ table->mask = FT_HASH_INITIAL_SIZE-1;
+ table->slack = FT_HASH_INITIAL_SIZE*FT_HASH_MAX_LOAD;
+ table->node_equal = equal;
+
+ (void)FT_NEW_ARRAY( table->buckets, FT_HASH_INITIAL_SIZE*2 );
+
+ return error;
+ }
+
+
+
+ FT_BASE_DEF( void )
+ ft_hash_foreach( FT_Hash table,
+ FT_Hash_ForeachFunc foreach_func,
+ const FT_Pointer foreach_data )
+ {
+ FT_UInt count = table->p + table->mask + 1;
+ FT_HashNode* pnode = table->buckets;
+ FT_HashNode node, next;
+
+ for ( ; count > 0; count--, pnode++ )
+ {
+ node = *pnode;
+ while ( node )
+ {
+ next = node->link;
+ foreach_func( node, foreach_data );
+ node = next;
+ }
+ }
+ }
+
+
+
+ FT_BASE_DEF( FT_HashLookup )
+ ft_hash_lookup( FT_Hash table,
+ FT_HashNode keynode )
+ {
+ FT_UInt index;
+ FT_UInt32 hash = keynode->hash;
+ FT_HashNode node, *pnode;
+
+ index = (FT_UInt)(hash & table->mask);
+ if ( index < table->p )
+ index = (FT_UInt)(hash & (2*table->mask+1));
+
+ pnode = &table->buckets[index];
+ for (;;)
+ {
+ node = *pnode;
+ if ( node == NULL )
+ break;
+
+ if ( node->hash == hash && table->node_equal( node, keynode ) )
+ break;
+
+ pnode = &node->link;
+ }
+
+ return pnode;
+ }
+
+
+
+
+ FT_BASE_DEF( FT_Error )
+ ft_hash_add( FT_Hash table,
+ FT_HashLookup lookup,
+ FT_HashNode new_node )
+ {
+ FT_Error error = 0;
+
+ /* add it to the hash table */
+ new_node->link = *lookup;
+ *lookup = new_node;
+
+ if ( --table->slack < 0 )
+ {
+ FT_UInt p = table->p;
+ FT_UInt mask = table->mask;
+ FT_HashNode new_list, node, *pnode;
+
+ /* split a single bucket */
+ new_list = NULL;
+ pnode = table->buckets + p;
+ for (;;)
+ {
+ node = *pnode;
+ if ( node == NULL )
+ break;
+
+ if ( node->hash & mask )
+ {
+ *pnode = node->link;
+ node->link = new_list;
+ new_list = node;
+ }
+ else
+ pnode = &node->link;
+ }
+
+ table->buckets[ p + mask + 1 ] = new_list;
+
+ table->slack += FT_HASH_MAX_LOAD;
+
+ if ( p >= mask )
+ {
+ FT_Memory memory = table->memory;
+
+
+ if (FT_RENEW_ARRAY( table->buckets, (mask+1)*2, (mask+1)*4 ))
+ goto Exit;
+
+ table->mask = 2*mask + 1;
+ table->p = 0;
+ }
+ else
+ table->p = p + 1;
+ }
+ Exit:
+ return error;
+ }
+
+
+
+ FT_BASE_DEF( FT_Error )
+ ft_hash_remove( FT_Hash table,
+ FT_HashLookup lookup )
+ {
+ FT_HashNode node;
+ FT_UInt num_buckets;
+ FT_Error error = 0;
+
+ FT_ASSERT( pnode != NULL && node != NULL );
+
+ node = *lookup;
+ *lookup = node->link;
+ node->link = NULL;
+
+ num_buckets = ( table->p + table->mask + 1) ;
+
+ if ( ++ table->slack > (FT_Long)num_buckets*FT_HASH_SUB_LOAD )
+ {
+ FT_UInt p = table->p;
+ FT_UInt mask = table->mask;
+ FT_UInt old_index = p + mask;
+ FT_HashNode* pnode;
+ FT_HashNode* pold;
+
+ if ( old_index < FT_HASH_INITIAL_SIZE )
+ goto Exit;
+
+ if ( p == 0 )
+ {
+ FT_Memory memory = table->memory;
+
+ table->mask >>= 1;
+ p = table->mask;
+
+ if ( FT_RENEW_ARRAY( table->buckets, (mask+1)*2, (mask+1) ) )
+ {
+ /* this should never happen normally, but who knows :-) */
+ /* we need to re-inject the node in the hash table before */
+ /* returning there, since it's safer */
+ pnode = table->buckets;
+ node->link = *pnode;
+ *pnode = node;
+
+ goto Exit;
+ }
+ }
+ else
+ p--;
+
+ pnode = table->buckets + p;
+ while ( *pnode )
+ pnode = &(*pnode)->link;
+
+ pold = table->buckets + old_index;
+ *pnode = *pold;
+ *pold = NULL;
+
+ table->slack -= FT_HASH_MAX_LOAD;
+ table->p = p;
+ }
+ Exit:
+ return error;
+ }
--- /dev/null
+++ b/libfreetype/ftinit.c
@@ -1,0 +1,161 @@
+/***************************************************************************/
+/* */
+/* ftinit.c */
+/* */
+/* FreeType initialization layer (body). */
+/* */
+/* Copyright 1996-2001, 2002 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+ /*************************************************************************/
+ /* */
+ /* The purpose of this file is to implement the following two */
+ /* functions: */
+ /* */
+ /* FT_Add_Default_Modules(): */
+ /* This function is used to add the set of default modules to a */
+ /* fresh new library object. The set is taken from the header file */
+ /* `freetype/config/ftmodule.h'. See the document `FreeType 2.0 */
+ /* Build System' for more information. */
+ /* */
+ /* FT_Init_FreeType(): */
+ /* This function creates a system object for the current platform, */
+ /* builds a library out of it, then calls FT_Default_Drivers(). */
+ /* */
+ /* Note that even if FT_Init_FreeType() uses the implementation of the */
+ /* system object defined at build time, client applications are still */
+ /* able to provide their own `ftsystem.c'. */
+ /* */
+ /*************************************************************************/
+
+
+#include <ft2build.h>
+#include FT_CONFIG_CONFIG_H
+#include FT_INTERNAL_OBJECTS_H
+#include FT_INTERNAL_DEBUG_H
+#include FT_MODULE_H
+
+
+ /*************************************************************************/
+ /* */
+ /* The macro FT_COMPONENT is used in trace mode. It is an implicit */
+ /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log */
+ /* messages during execution. */
+ /* */
+#undef FT_COMPONENT
+#define FT_COMPONENT trace_init
+
+#undef FT_USE_MODULE
+#ifdef __cplusplus
+#define FT_USE_MODULE( x ) extern "C" const FT_Module_Class* x;
+#else
+#define FT_USE_MODULE( x ) extern const FT_Module_Class* x;
+#endif
+
+
+#include FT_CONFIG_MODULES_H
+
+
+#undef FT_USE_MODULE
+#define FT_USE_MODULE( x ) (const FT_Module_Class*)&x,
+
+ static
+ const FT_Module_Class* const ft_default_modules[] =
+ {
+#include FT_CONFIG_MODULES_H
+ 0
+ };
+
+
+ /* documentation is in ftmodule.h */
+
+ FT_EXPORT_DEF( void )
+ FT_Add_Default_Modules( FT_Library library )
+ {
+ FT_Error error;
+ const FT_Module_Class* const* cur;
+
+
+ /* test for valid `library' delayed to FT_Add_Module() */
+
+ cur = ft_default_modules;
+ while ( *cur )
+ {
+ error = FT_Add_Module( library, *cur );
+ /* notify errors, but don't stop */
+ if ( error )
+ {
+ FT_ERROR(( "FT_Add_Default_Module: Cannot install `%s', error = 0x%x\n",
+ (*cur)->module_name, error ));
+ }
+ cur++;
+ }
+ }
+
+
+ /* documentation is in freetype.h */
+
+ FT_EXPORT_DEF( FT_Error )
+ FT_Init_FreeType( FT_Library *alibrary )
+ {
+ FT_Error error;
+ FT_Memory memory;
+
+
+ /* First of all, allocate a new system object -- this function is part */
+ /* of the system-specific component, i.e. `ftsystem.c'. */
+
+ memory = FT_New_Memory();
+ if ( !memory )
+ {
+ FT_ERROR(( "FT_Init_FreeType: cannot find memory manager\n" ));
+ return FT_Err_Unimplemented_Feature;
+ }
+
+ /* build a library out of it, then fill it with the set of */
+ /* default drivers. */
+
+ error = FT_New_Library( memory, alibrary );
+ if ( !error )
+ {
+ (*alibrary)->version_major = FREETYPE_MAJOR;
+ (*alibrary)->version_minor = FREETYPE_MINOR;
+ (*alibrary)->version_patch = FREETYPE_PATCH;
+
+ FT_Add_Default_Modules( *alibrary );
+ }
+
+ return error;
+ }
+
+
+ /* documentation is in freetype.h */
+
+ FT_EXPORT_DEF( FT_Error )
+ FT_Done_FreeType( FT_Library library )
+ {
+ if ( library )
+ {
+ FT_Memory memory = library->memory;
+
+
+ /* Discard the library object */
+ FT_Done_Library( library );
+
+ /* discard memory manager */
+ FT_Done_Memory( memory );
+ }
+
+ return FT_Err_Ok;
+ }
+
+
+/* END */
--- /dev/null
+++ b/libfreetype/ftlist.c
@@ -1,0 +1,217 @@
+/***************************************************************************/
+/* */
+/* ftlist.c */
+/* */
+/* Generic list support for FreeType (body). */
+/* */
+/* Copyright 1996-2001, 2002 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+ /*************************************************************************/
+ /* */
+ /* This file implements functions relative to list processing. Its */
+ /* data structures are defined in `freetype/internal/ftlist.h'. */
+ /* */
+ /*************************************************************************/
+
+
+#include <ft2build.h>
+#include FT_LIST_H
+#include FT_INTERNAL_DEBUG_H
+#include FT_INTERNAL_OBJECTS_H
+
+
+ /*************************************************************************/
+ /* */
+ /* The macro FT_COMPONENT is used in trace mode. It is an implicit */
+ /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log */
+ /* messages during execution. */
+ /* */
+#undef FT_COMPONENT
+#define FT_COMPONENT trace_list
+
+
+ /* documentation is in ftlist.h */
+
+ FT_EXPORT_DEF( FT_ListNode )
+ FT_List_Find( FT_List list,
+ void* data )
+ {
+ FT_ListNode cur;
+
+
+ cur = list->head;
+ while ( cur )
+ {
+ if ( cur->data == data )
+ return cur;
+
+ cur = cur->next;
+ }
+
+ return (FT_ListNode)0;
+ }
+
+
+ /* documentation is in ftlist.h */
+
+ FT_EXPORT_DEF( void )
+ FT_List_Add( FT_List list,
+ FT_ListNode node )
+ {
+ FT_ListNode before = list->tail;
+
+
+ node->next = 0;
+ node->prev = before;
+
+ if ( before )
+ before->next = node;
+ else
+ list->head = node;
+
+ list->tail = node;
+ }
+
+
+ /* documentation is in ftlist.h */
+
+ FT_EXPORT_DEF( void )
+ FT_List_Insert( FT_List list,
+ FT_ListNode node )
+ {
+ FT_ListNode after = list->head;
+
+
+ node->next = after;
+ node->prev = 0;
+
+ if ( !after )
+ list->tail = node;
+ else
+ after->prev = node;
+
+ list->head = node;
+ }
+
+
+ /* documentation is in ftlist.h */
+
+ FT_EXPORT_DEF( void )
+ FT_List_Remove( FT_List list,
+ FT_ListNode node )
+ {
+ FT_ListNode before, after;
+
+
+ before = node->prev;
+ after = node->next;
+
+ if ( before )
+ before->next = after;
+ else
+ list->head = after;
+
+ if ( after )
+ after->prev = before;
+ else
+ list->tail = before;
+ }
+
+
+ /* documentation is in ftlist.h */
+
+ FT_EXPORT_DEF( void )
+ FT_List_Up( FT_List list,
+ FT_ListNode node )
+ {
+ FT_ListNode before, after;
+
+
+ before = node->prev;
+ after = node->next;
+
+ /* check whether we are already on top of the list */
+ if ( !before )
+ return;
+
+ before->next = after;
+
+ if ( after )
+ after->prev = before;
+ else
+ list->tail = before;
+
+ node->prev = 0;
+ node->next = list->head;
+ list->head->prev = node;
+ list->head = node;
+ }
+
+
+ /* documentation is in ftlist.h */
+
+ FT_EXPORT_DEF( FT_Error )
+ FT_List_Iterate( FT_List list,
+ FT_List_Iterator iterator,
+ void* user )
+ {
+ FT_ListNode cur = list->head;
+ FT_Error error = FT_Err_Ok;
+
+
+ while ( cur )
+ {
+ FT_ListNode next = cur->next;
+
+
+ error = iterator( cur, user );
+ if ( error )
+ break;
+
+ cur = next;
+ }
+
+ return error;
+ }
+
+
+ /* documentation is in ftlist.h */
+
+ FT_EXPORT_DEF( void )
+ FT_List_Finalize( FT_List list,
+ FT_List_Destructor destroy,
+ FT_Memory memory,
+ void* user )
+ {
+ FT_ListNode cur;
+
+
+ cur = list->head;
+ while ( cur )
+ {
+ FT_ListNode next = cur->next;
+ void* data = cur->data;
+
+
+ if ( destroy )
+ destroy( memory, data, user );
+
+ FT_FREE( cur );
+ cur = next;
+ }
+
+ list->head = 0;
+ list->tail = 0;
+ }
+
+
+/* END */
--- /dev/null
+++ b/libfreetype/ftlru.c
@@ -1,0 +1,338 @@
+/***************************************************************************/
+/* */
+/* ftlru.c */
+/* */
+/* Simple LRU list-cache (body). */
+/* */
+/* Copyright 2000-2001, 2002 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+
+#include <ft2build.h>
+#include FT_CACHE_H
+#include FT_CACHE_INTERNAL_LRU_H
+#include FT_LIST_H
+#include FT_INTERNAL_OBJECTS_H
+
+#include "ftcerror.h"
+
+
+ FT_EXPORT_DEF( FT_Error )
+ FT_LruList_New( FT_LruList_Class clazz,
+ FT_UInt max_nodes,
+ FT_Pointer user_data,
+ FT_Memory memory,
+ FT_LruList *alist )
+ {
+ FT_Error error;
+ FT_LruList list;
+
+
+ if ( !alist || !clazz )
+ return FTC_Err_Invalid_Argument;
+
+ *alist = NULL;
+ if ( !FT_ALLOC( list, clazz->list_size ) )
+ {
+ /* initialize common fields */
+ list->clazz = clazz;
+ list->memory = memory;
+ list->max_nodes = max_nodes;
+ list->data = user_data;
+
+ if ( clazz->list_init )
+ {
+ error = clazz->list_init( list );
+ if ( error )
+ {
+ if ( clazz->list_done )
+ clazz->list_done( list );
+
+ FT_FREE( list );
+ }
+ }
+
+ *alist = list;
+ }
+
+ return error;
+ }
+
+
+ FT_EXPORT_DEF( void )
+ FT_LruList_Destroy( FT_LruList list )
+ {
+ FT_Memory memory;
+ FT_LruList_Class clazz;
+
+
+ if ( !list )
+ return;
+
+ memory = list->memory;
+ clazz = list->clazz;
+
+ FT_LruList_Reset( list );
+
+ if ( clazz->list_done )
+ clazz->list_done( list );
+
+ FT_FREE( list );
+ }
+
+
+ FT_EXPORT_DEF( void )
+ FT_LruList_Reset( FT_LruList list )
+ {
+ FT_LruNode node;
+ FT_LruList_Class clazz;
+ FT_Memory memory;
+
+
+ if ( !list )
+ return;
+
+ node = list->nodes;
+ clazz = list->clazz;
+ memory = list->memory;
+
+ while ( node )
+ {
+ FT_LruNode next = node->next;
+
+
+ if ( clazz->node_done )
+ clazz->node_done( node, list->data );
+
+ FT_FREE( node );
+ node = next;
+ }
+
+ list->nodes = NULL;
+ list->num_nodes = 0;
+ }
+
+
+ FT_EXPORT_DEF( FT_Error )
+ FT_LruList_Lookup( FT_LruList list,
+ FT_LruKey key,
+ FT_LruNode *anode )
+ {
+ FT_Error error = 0;
+ FT_LruNode node, *pnode;
+ FT_LruList_Class clazz;
+ FT_LruNode* plast;
+ FT_LruNode result = NULL;
+ FT_Memory memory;
+
+
+ if ( !list || !key || !anode )
+ return FTC_Err_Invalid_Argument;
+
+ pnode = &list->nodes;
+ plast = pnode;
+ node = NULL;
+ clazz = list->clazz;
+ memory = list->memory;
+
+ if ( clazz->node_compare )
+ {
+ for (;;)
+ {
+ node = *pnode;
+ if ( node == NULL )
+ break;
+
+ if ( clazz->node_compare( node, key, list->data ) )
+ break;
+
+ plast = pnode;
+ pnode = &(*pnode)->next;
+ }
+ }
+ else
+ {
+ for (;;)
+ {
+ node = *pnode;
+ if ( node == NULL )
+ break;
+
+ if ( node->key == key )
+ break;
+
+ plast = pnode;
+ pnode = &(*pnode)->next;
+ }
+ }
+
+ if ( node )
+ {
+ /* move element to top of list */
+ if ( list->nodes != node )
+ {
+ *pnode = node->next;
+ node->next = list->nodes;
+ list->nodes = node;
+ }
+ result = node;
+ goto Exit;
+ }
+
+ /* we haven't found the relevant element. We will now try */
+ /* to create a new one. */
+ /* */
+
+ /* first, check if our list if full, when appropriate */
+ if ( list->max_nodes > 0 && list->num_nodes >= list->max_nodes )
+ {
+ /* this list list is full; we will now flush */
+ /* the oldest node, if there's one! */
+ FT_LruNode last = *plast;
+
+
+ if ( last )
+ {
+ if ( clazz->node_flush )
+ {
+ error = clazz->node_flush( last, key, list->data );
+ }
+ else
+ {
+ if ( clazz->node_done )
+ clazz->node_done( last, list->data );
+
+ last->key = key;
+ error = clazz->node_init( last, key, list->data );
+ }
+
+ if ( !error )
+ {
+ /* move it to the top of the list */
+ *plast = NULL;
+ last->next = list->nodes;
+ list->nodes = last;
+
+ result = last;
+ goto Exit;
+ }
+
+ /* in case of error during the flush or done/init cycle, */
+ /* we need to discard the node */
+ if ( clazz->node_done )
+ clazz->node_done( last, list->data );
+
+ *plast = NULL;
+ list->num_nodes--;
+
+ FT_FREE( last );
+ goto Exit;
+ }
+ }
+
+ /* otherwise, simply allocate a new node */
+ if ( FT_ALLOC( node, clazz->node_size ) )
+ goto Exit;
+
+ node->key = key;
+ error = clazz->node_init( node, key, list->data );
+ if ( error )
+ {
+ FT_FREE( node );
+ goto Exit;
+ }
+
+ result = node;
+ node->next = list->nodes;
+ list->nodes = node;
+ list->num_nodes++;
+
+ Exit:
+ *anode = result;
+ return error;
+ }
+
+
+ FT_EXPORT_DEF( void )
+ FT_LruList_Remove( FT_LruList list,
+ FT_LruNode node )
+ {
+ FT_LruNode *pnode;
+
+
+ if ( !list || !node )
+ return;
+
+ pnode = &list->nodes;
+ for (;;)
+ {
+ if ( *pnode == node )
+ {
+ FT_Memory memory = list->memory;
+ FT_LruList_Class clazz = list->clazz;
+
+
+ *pnode = node->next;
+ node->next = NULL;
+
+ if ( clazz->node_done )
+ clazz->node_done( node, list->data );
+
+ FT_FREE( node );
+ list->num_nodes--;
+ break;
+ }
+
+ pnode = &(*pnode)->next;
+ }
+ }
+
+
+ FT_EXPORT_DEF( void )
+ FT_LruList_Remove_Selection( FT_LruList list,
+ FT_LruNode_SelectFunc select_func,
+ FT_Pointer select_data )
+ {
+ FT_LruNode *pnode, node;
+ FT_LruList_Class clazz;
+ FT_Memory memory;
+
+
+ if ( !list || !select_func )
+ return;
+
+ memory = list->memory;
+ clazz = list->clazz;
+ pnode = &list->nodes;
+
+ for (;;)
+ {
+ node = *pnode;
+ if ( node == NULL )
+ break;
+
+ if ( select_func( node, select_data, list->data ) )
+ {
+ *pnode = node->next;
+ node->next = NULL;
+
+ if ( clazz->node_done )
+ clazz->node_done( node, list );
+
+ FT_FREE( node );
+ }
+ else
+ pnode = &(*pnode)->next;
+ }
+ }
+
+
+/* END */
--- /dev/null
+++ b/libfreetype/ftmac.c
@@ -1,0 +1,919 @@
+/***************************************************************************/
+/* */
+/* ftmac.c */
+/* */
+/* Mac FOND support. Written by just@letterror.com. */
+/* */
+/* Copyright 1996-2001, 2002 by */
+/* Just van Rossum, David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+
+ /*
+ Notes
+
+ Mac suitcase files can (and often do!) contain multiple fonts. To
+ support this I use the face_index argument of FT_(Open|New)_Face()
+ functions, and pretend the suitcase file is a collection.
+
+ Warning: Although the FOND driver sets face->num_faces field to the
+ number of available fonts, but the Type 1 driver sets it to 1 anyway.
+ So this field is currently not reliable, and I don't see a clean way
+ to resolve that. The face_index argument translates to
+
+ Get1IndResource( 'FOND', face_index + 1 );
+
+ so clients should figure out the resource index of the FOND.
+ (I'll try to provide some example code for this at some point.)
+
+ The Mac FOND support works roughly like this:
+
+ - Check whether the offered stream points to a Mac suitcase file.
+ This is done by checking the file type: it has to be 'FFIL' or 'tfil'.
+ The stream that gets passed to our init_face() routine is a stdio
+ stream, which isn't usable for us, since the FOND resources live
+ in the resource fork. So we just grab the stream->pathname field.
+
+ - Read the FOND resource into memory, then check whether there is
+ a TrueType font and/or(!) a Type 1 font available.
+
+ - If there is a Type 1 font available (as a separate 'LWFN' file),
+ read its data into memory, massage it slightly so it becomes
+ PFB data, wrap it into a memory stream, load the Type 1 driver
+ and delegate the rest of the work to it by calling FT_Open_Face().
+ (XXX TODO: after this has been done, the kerning data from the FOND
+ resource should be appended to the face: On the Mac there are usually
+ no AFM files available. However, this is tricky since we need to map
+ Mac char codes to ps glyph names to glyph ID's...)
+
+ - If there is a TrueType font (an 'sfnt' resource), read it into
+ memory, wrap it into a memory stream, load the TrueType driver
+ and delegate the rest of the work to it, by calling FT_Open_Face().
+ */
+
+
+#include <ft2build.h>
+#include FT_FREETYPE_H
+#include FT_INTERNAL_STREAM_H
+#include "truetype/ttobjs.h"
+#include "type1/t1objs.h"
+
+#include <Resources.h>
+#include <Fonts.h>
+#include <Errors.h>
+#include <Files.h>
+#include <TextUtils.h>
+
+
+#include FT_MAC_H
+
+
+ /* Set PREFER_LWFN to 1 if LWFN (Type 1) is preferred over
+ TrueType in case *both* are available (this is not common,
+ but it *is* possible). */
+#ifndef PREFER_LWFN
+#define PREFER_LWFN 1
+#endif
+
+ /* Given a pathname, fill in a file spec. */
+ static int
+ file_spec_from_path( const char* pathname,
+ FSSpec* spec )
+ {
+#if TARGET_API_MAC_CARBON
+
+ OSErr e;
+ FSRef ref;
+
+
+ e = FSPathMakeRef( (UInt8 *)pathname, &ref, false /* not a directory */ );
+ if ( e == noErr )
+ e = FSGetCatalogInfo( &ref, kFSCatInfoNone, NULL, NULL, spec, NULL );
+
+ return ( e == noErr ) ? 0 : (-1);
+
+#else
+
+ Str255 p_path;
+ FT_ULong path_len;
+
+
+ /* convert path to a pascal string */
+ path_len = ft_strlen( pathname );
+ if ( path_len > 255 )
+ return -1;
+ p_path[0] = (unsigned char)path_len;
+ ft_strncpy( (char*)p_path + 1, pathname, path_len );
+
+ if ( FSMakeFSSpec( 0, 0, p_path, spec ) != noErr )
+ return -1;
+ else
+ return 0;
+
+#endif
+ }
+
+
+ /* Return the file type of the file specified by spec. */
+ static OSType
+ get_file_type( FSSpec* spec )
+ {
+ FInfo finfo;
+
+
+ if ( FSpGetFInfo( spec, &finfo ) != noErr )
+ return 0; /* file might not exist */
+
+ return finfo.fdType;
+ }
+
+
+#if TARGET_API_MAC_CARBON
+
+ /* is this a Mac OS X .dfont file */
+ static Boolean
+ is_dfont( FSSpec* spec )
+ {
+ int nameLen = spec->name[0];
+
+
+ return nameLen >= 6 &&
+ !memcmp( spec->name + nameLen - 5, ".dfont", 6 );
+ }
+
+#endif
+
+
+ /* Given a PostScript font name, create the Macintosh LWFN file name. */
+ static void
+ create_lwfn_name( char* ps_name,
+ Str255 lwfn_file_name )
+ {
+ int max = 5, count = 0;
+ FT_Byte* p = lwfn_file_name;
+ FT_Byte* q = (FT_Byte*)ps_name;
+
+
+ lwfn_file_name[0] = 0;
+
+ while ( *q )
+ {
+ if ( isupper( *q ) )
+ {
+ if ( count )
+ max = 3;
+ count = 0;
+ }
+ if ( count < max && ( ft_isalnum( *q ) || *q == '_' ) )
+ {
+ *++p = *q;
+ lwfn_file_name[0]++;
+ count++;
+ }
+ q++;
+ }
+ }
+
+
+ /* Given a file reference, answer its location as a vRefNum
+ and a dirID. */
+ static FT_Error
+ get_file_location( short ref_num,
+ short* v_ref_num,
+ long* dir_id,
+ unsigned char* file_name )
+ {
+ FCBPBRec pb;
+ OSErr error;
+
+
+ pb.ioNamePtr = file_name;
+ pb.ioVRefNum = 0;
+ pb.ioRefNum = ref_num;
+ pb.ioFCBIndx = 0;
+
+ error = PBGetFCBInfoSync( &pb );
+ if ( error == noErr )
+ {
+ *v_ref_num = pb.ioFCBVRefNum;
+ *dir_id = pb.ioFCBParID;
+ }
+ return error;
+ }
+
+
+ /* Make a file spec for an LWFN file from a FOND resource and
+ a file name. */
+ static FT_Error
+ make_lwfn_spec( Handle fond,
+ unsigned char* file_name,
+ FSSpec* spec )
+ {
+ FT_Error error;
+ short ref_num, v_ref_num;
+ long dir_id;
+ Str255 fond_file_name;
+
+
+ ref_num = HomeResFile( fond );
+
+ error = ResError();
+ if ( !error )
+ error = get_file_location( ref_num, &v_ref_num,
+ &dir_id, fond_file_name );
+ if ( !error )
+ error = FSMakeFSSpec( v_ref_num, dir_id, file_name, spec );
+
+ return error;
+ }
+
+
+ /* Look inside the FOND data, answer whether there should be an SFNT
+ resource, and answer the name of a possible LWFN Type 1 file.
+
+ Thanks to Paul Miller (paulm@profoundeffects.com) for the fix
+ to load a face OTHER than the first one in the FOND!
+ */
+ static void
+ parse_fond( char* fond_data,
+ short* have_sfnt,
+ short* sfnt_id,
+ Str255 lwfn_file_name,
+ short face_index )
+ {
+ AsscEntry* assoc;
+ AsscEntry* base_assoc;
+ FamRec* fond;
+
+
+ *sfnt_id = 0;
+ *have_sfnt = 0;
+ lwfn_file_name[0] = 0;
+
+ fond = (FamRec*)fond_data;
+ assoc = (AsscEntry*)( fond_data + sizeof ( FamRec ) + 2 );
+ base_assoc = assoc;
+ assoc += face_index; /* add on the face_index! */
+
+ /* if the face at this index is not scalable,
+ fall back to the first one (old behavior) */
+ if ( assoc->fontSize == 0 )
+ {
+ *have_sfnt = 1;
+ *sfnt_id = assoc->fontID;
+ }
+ else if ( base_assoc->fontSize == 0 )
+ {
+ *have_sfnt = 1;
+ *sfnt_id = base_assoc->fontID;
+ }
+
+ if ( fond->ffStylOff )
+ {
+ unsigned char* p = (unsigned char*)fond_data;
+ StyleTable* style;
+ unsigned short string_count;
+ char ps_name[256];
+ unsigned char* names[64];
+ int i;
+
+
+ p += fond->ffStylOff;
+ style = (StyleTable*)p;
+ p += sizeof ( StyleTable );
+ string_count = *(unsigned short*)(p);
+ p += sizeof ( short );
+
+ for ( i = 0 ; i < string_count && i < 64; i++ )
+ {
+ names[i] = p;
+ p += names[i][0];
+ p++;
+ }
+
+ {
+ size_t ps_name_len = (size_t)names[0][0];
+
+
+ if ( ps_name_len != 0 )
+ {
+ memcpy(ps_name, names[0] + 1, ps_name_len);
+ ps_name[ps_name_len] = 0;
+ }
+ if ( style->indexes[0] > 1 )
+ {
+ unsigned char* suffixes = names[style->indexes[0] - 1];
+
+
+ for ( i = 1; i < suffixes[0]; i++ )
+ {
+ unsigned char* s;
+ size_t j = suffixes[i] - 1;
+
+
+ if ( j < string_count && ( s = names[j] ) != NULL )
+ {
+ size_t s_len = (size_t)s[0];
+
+
+ if ( s_len != 0 && ps_name_len + s_len < sizeof ( ps_name ) )
+ {
+ memcpy( ps_name + ps_name_len, s + 1, s_len );
+ ps_name_len += s_len;
+ ps_name[ps_name_len] = 0;
+ }
+ }
+ }
+ }
+ }
+
+ create_lwfn_name( ps_name, lwfn_file_name );
+ }
+ }
+
+
+ /* Read Type 1 data from the POST resources inside the LWFN file,
+ return a PFB buffer. This is somewhat convoluted because the FT2
+ PFB parser wants the ASCII header as one chunk, and the LWFN
+ chunks are often not organized that way, so we'll glue chunks
+ of the same type together. */
+ static FT_Error
+ read_lwfn( FT_Memory memory,
+ FSSpec* lwfn_spec,
+ FT_Byte** pfb_data,
+ FT_ULong* size )
+ {
+ FT_Error error = FT_Err_Ok;
+ short res_ref, res_id;
+ unsigned char *buffer, *p, *size_p = NULL;
+ FT_ULong total_size = 0;
+ FT_ULong post_size, pfb_chunk_size;
+ Handle post_data;
+ char code, last_code;
+
+
+ res_ref = FSpOpenResFile( lwfn_spec, fsRdPerm );
+ if ( ResError() )
+ return FT_Err_Out_Of_Memory;
+ UseResFile( res_ref );
+
+ /* First pass: load all POST resources, and determine the size of
+ the output buffer. */
+ res_id = 501;
+ last_code = -1;
+
+ for (;;)
+ {
+ post_data = Get1Resource( 'POST', res_id++ );
+ if ( post_data == NULL )
+ break; /* we're done */
+
+ code = (*post_data)[0];
+
+ if ( code != last_code )
+ {
+ if ( code == 5 )
+ total_size += 2; /* just the end code */
+ else
+ total_size += 6; /* code + 4 bytes chunk length */
+ }
+
+ total_size += GetHandleSize( post_data ) - 2;
+ last_code = code;
+ }
+
+ if ( FT_ALLOC( buffer, (FT_Long)total_size ) )
+ goto Error;
+
+ /* Second pass: append all POST data to the buffer, add PFB fields.
+ Glue all consecutive chunks of the same type together. */
+ p = buffer;
+ res_id = 501;
+ last_code = -1;
+ pfb_chunk_size = 0;
+
+ for (;;)
+ {
+ post_data = Get1Resource( 'POST', res_id++ );
+ if ( post_data == NULL )
+ break; /* we're done */
+
+ post_size = (FT_ULong)GetHandleSize( post_data ) - 2;
+ code = (*post_data)[0];
+
+ if ( code != last_code )
+ {
+ if ( last_code != -1 )
+ {
+ /* we're done adding a chunk, fill in the size field */
+ if ( size_p != NULL )
+ {
+ *size_p++ = (FT_Byte)( pfb_chunk_size & 0xFF );
+ *size_p++ = (FT_Byte)( ( pfb_chunk_size >> 8 ) & 0xFF );
+ *size_p++ = (FT_Byte)( ( pfb_chunk_size >> 16 ) & 0xFF );
+ *size_p++ = (FT_Byte)( ( pfb_chunk_size >> 24 ) & 0xFF );
+ }
+ pfb_chunk_size = 0;
+ }
+
+ *p++ = 0x80;
+ if ( code == 5 )
+ *p++ = 0x03; /* the end */
+ else if ( code == 2 )
+ *p++ = 0x02; /* binary segment */
+ else
+ *p++ = 0x01; /* ASCII segment */
+
+ if ( code != 5 )
+ {
+ size_p = p; /* save for later */
+ p += 4; /* make space for size field */
+ }
+ }
+
+ ft_memcpy( p, *post_data + 2, post_size );
+ pfb_chunk_size += post_size;
+ p += post_size;
+ last_code = code;
+ }
+
+ *pfb_data = buffer;
+ *size = total_size;
+
+ Error:
+ CloseResFile( res_ref );
+ return error;
+ }
+
+
+ /* Finalizer for a memory stream; gets called by FT_Done_Face().
+ It frees the memory it uses. */
+ static void
+ memory_stream_close( FT_Stream stream )
+ {
+ FT_Memory memory = stream->memory;
+
+
+ FT_FREE( stream->base );
+
+ stream->size = 0;
+ stream->base = 0;
+ stream->close = 0;
+ }
+
+
+ /* Create a new memory stream from a buffer and a size. */
+ static FT_Error
+ new_memory_stream( FT_Library library,
+ FT_Byte* base,
+ FT_ULong size,
+ FT_Stream_CloseFunc close,
+ FT_Stream *astream )
+ {
+ FT_Error error;
+ FT_Memory memory;
+ FT_Stream stream;
+
+
+ if ( !library )
+ return FT_Err_Invalid_Library_Handle;
+
+ if ( !base )
+ return FT_Err_Invalid_Argument;
+
+ *astream = 0;
+ memory = library->memory;
+ if ( FT_NEW( stream ) )
+ goto Exit;
+
+ FT_Stream_OpenMemory( stream, base, size );
+
+ stream->close = close;
+
+ *astream = stream;
+
+ Exit:
+ return error;
+ }
+
+
+ /* Create a new FT_Face given a buffer and a driver name. */
+ static FT_Error
+ open_face_from_buffer( FT_Library library,
+ FT_Byte* base,
+ FT_ULong size,
+ FT_Long face_index,
+ char* driver_name,
+ FT_Face *aface )
+ {
+ FT_Open_Args args;
+ FT_Error error;
+ FT_Stream stream;
+ FT_Memory memory = library->memory;
+
+
+ error = new_memory_stream( library,
+ base,
+ size,
+ memory_stream_close,
+ &stream );
+ if ( error )
+ {
+ FT_FREE( base );
+ return error;
+ }
+
+ args.flags = FT_OPEN_STREAM;
+ args.stream = stream;
+ if ( driver_name )
+ {
+ args.flags = args.flags | FT_OPEN_DRIVER;
+ args.driver = FT_Get_Module( library, driver_name );
+ }
+
+ error = FT_Open_Face( library, &args, face_index, aface );
+ if ( error == FT_Err_Ok )
+ (*aface)->face_flags &= ~FT_FACE_FLAG_EXTERNAL_STREAM;
+ else
+ {
+ FT_Stream_CloseFunc( stream );
+ FT_FREE( stream );
+ }
+
+ return error;
+ }
+
+
+ /* Create a new FT_Face from a file spec to an LWFN file. */
+ static FT_Error
+ FT_New_Face_From_LWFN( FT_Library library,
+ FSSpec* spec,
+ FT_Long face_index,
+ FT_Face *aface )
+ {
+ FT_Byte* pfb_data;
+ FT_ULong pfb_size;
+ FT_Error error;
+
+
+ error = read_lwfn( library->memory, spec, &pfb_data, &pfb_size );
+ if ( error )
+ return error;
+
+ return open_face_from_buffer( library,
+ pfb_data,
+ pfb_size,
+ face_index,
+ "type1",
+ aface );
+ }
+
+
+ /* Create a new FT_Face from an SFNT resource, specified by res ID. */
+ static FT_Error
+ FT_New_Face_From_SFNT( FT_Library library,
+ short sfnt_id,
+ FT_Long face_index,
+ FT_Face *aface )
+ {
+ Handle sfnt = NULL;
+ FT_Byte* sfnt_data;
+ size_t sfnt_size;
+ FT_Error error = 0;
+ FT_Memory memory = library->memory;
+
+
+ sfnt = GetResource( 'sfnt', sfnt_id );
+ if ( ResError() )
+ return FT_Err_Invalid_Handle;
+
+ sfnt_size = (FT_ULong)GetHandleSize( sfnt );
+ if ( FT_ALLOC( sfnt_data, (FT_Long)sfnt_size ) )
+ {
+ ReleaseResource( sfnt );
+ return error;
+ }
+
+ HLock( sfnt );
+ ft_memcpy( sfnt_data, *sfnt, sfnt_size );
+ HUnlock( sfnt );
+ ReleaseResource( sfnt );
+
+ return open_face_from_buffer( library,
+ sfnt_data,
+ sfnt_size,
+ face_index,
+ "truetype",
+ aface );
+ }
+
+
+ /* Create a new FT_Face from a file spec to a suitcase file. */
+ static FT_Error
+ FT_New_Face_From_Suitcase( FT_Library library,
+ FSSpec* spec,
+ FT_Long face_index,
+ FT_Face *aface )
+ {
+ FT_Error error = FT_Err_Ok;
+ short res_ref, res_index;
+ Handle fond;
+
+
+ res_ref = FSpOpenResFile( spec, fsRdPerm );
+ if ( ResError() )
+ return FT_Err_Cannot_Open_Resource;
+ UseResFile( res_ref );
+
+ /* face_index may be -1, in which case we
+ just need to do a sanity check */
+ if ( face_index < 0 )
+ res_index = 1;
+ else
+ {
+ res_index = (short)( face_index + 1 );
+ face_index = 0;
+ }
+ fond = Get1IndResource( 'FOND', res_index );
+ if ( ResError() )
+ {
+ error = FT_Err_Cannot_Open_Resource;
+ goto Error;
+ }
+
+ error = FT_New_Face_From_FOND( library, fond, face_index, aface );
+
+ Error:
+ CloseResFile( res_ref );
+ return error;
+ }
+
+
+#if TARGET_API_MAC_CARBON
+
+ /* Create a new FT_Face from a file spec to a suitcase file. */
+ static FT_Error
+ FT_New_Face_From_dfont( FT_Library library,
+ FSSpec* spec,
+ FT_Long face_index,
+ FT_Face* aface )
+ {
+ FT_Error error = FT_Err_Ok;
+ short res_ref, res_index;
+ Handle fond;
+ FSRef hostContainerRef;
+
+
+ error = FSpMakeFSRef( spec, &hostContainerRef );
+ if ( error == noErr )
+ error = FSOpenResourceFile( &hostContainerRef,
+ 0, NULL, fsRdPerm, &res_ref );
+
+ if ( error != noErr )
+ return FT_Err_Cannot_Open_Resource;
+
+ UseResFile( res_ref );
+
+ /* face_index may be -1, in which case we
+ just need to do a sanity check */
+ if ( face_index < 0 )
+ res_index = 1;
+ else
+ {
+ res_index = (short)( face_index + 1 );
+ face_index = 0;
+ }
+ fond = Get1IndResource( 'FOND', res_index );
+ if ( ResError() )
+ {
+ error = FT_Err_Cannot_Open_Resource;
+ goto Error;
+ }
+
+ error = FT_New_Face_From_FOND( library, fond, face_index, aface );
+
+ Error:
+ CloseResFile( res_ref );
+ return error;
+ }
+
+#endif
+
+
+ /* documentation is in ftmac.h */
+
+ FT_EXPORT_DEF( FT_Error )
+ FT_New_Face_From_FOND( FT_Library library,
+ Handle fond,
+ FT_Long face_index,
+ FT_Face *aface )
+ {
+ short sfnt_id, have_sfnt, have_lwfn = 0;
+ Str255 lwfn_file_name;
+ short fond_id;
+ OSType fond_type;
+ Str255 fond_name;
+ FSSpec lwfn_spec;
+
+
+ GetResInfo( fond, &fond_id, &fond_type, fond_name );
+ if ( ResError() != noErr || fond_type != 'FOND' )
+ return FT_Err_Invalid_File_Format;
+
+ HLock( fond );
+ parse_fond( *fond, &have_sfnt, &sfnt_id, lwfn_file_name, face_index );
+ HUnlock( fond );
+
+ if ( lwfn_file_name[0] )
+ {
+ if ( make_lwfn_spec( fond, lwfn_file_name, &lwfn_spec ) == FT_Err_Ok )
+ have_lwfn = 1; /* yeah, we got one! */
+ else
+ have_lwfn = 0; /* no LWFN file found */
+ }
+
+ if ( have_lwfn && ( !have_sfnt || PREFER_LWFN ) )
+ return FT_New_Face_From_LWFN( library,
+ &lwfn_spec,
+ face_index,
+ aface );
+ else if ( have_sfnt )
+ return FT_New_Face_From_SFNT( library,
+ sfnt_id,
+ face_index,
+ aface );
+
+ return FT_Err_Unknown_File_Format;
+ }
+
+
+ /* documentation is in ftmac.h */
+
+ FT_EXPORT_DEF( FT_Error )
+ FT_GetFile_From_Mac_Name( char* fontName,
+ FSSpec* pathSpec,
+ FT_Long* face_index )
+ {
+ OptionBits options = kFMUseGlobalScopeOption;
+
+ FMFontFamilyIterator famIter;
+ OSStatus status = FMCreateFontFamilyIterator( NULL, NULL,
+ options,
+ &famIter );
+ FMFont the_font = NULL;
+ FMFontFamily family = NULL;
+
+
+ *face_index = 0;
+ while ( status == 0 && !the_font )
+ {
+ status = FMGetNextFontFamily( &famIter, &family );
+ if ( status == 0 )
+ {
+ int stat2;
+ FMFontFamilyInstanceIterator instIter;
+ Str255 famNameStr;
+ char famName[256];
+
+
+ /* get the family name */
+ FMGetFontFamilyName( family, famNameStr );
+ CopyPascalStringToC( famNameStr, famName );
+
+ /* iterate through the styles */
+ FMCreateFontFamilyInstanceIterator( family, &instIter );
+
+ *face_index = 0;
+ stat2 = 0;
+ while ( stat2 == 0 && !the_font )
+ {
+ FMFontStyle style;
+ FMFontSize size;
+ FMFont font;
+
+
+ stat2 = FMGetNextFontFamilyInstance( &instIter, &font,
+ &style, &size );
+ if ( stat2 == 0 && size == 0 )
+ {
+ char fullName[256];
+
+
+ /* build up a complete face name */
+ ft_strcpy( fullName, famName );
+ if ( style & bold )
+ strcat( fullName, " Bold" );
+ if ( style & italic )
+ strcat( fullName, " Italic" );
+
+ /* compare with the name we are looking for */
+ if ( ft_strcmp( fullName, fontName ) == 0 )
+ {
+ /* found it! */
+ the_font = font;
+ }
+ else
+ ++(*face_index);
+ }
+ }
+
+ FMDisposeFontFamilyInstanceIterator( &instIter );
+ }
+ }
+
+ FMDisposeFontFamilyIterator( &famIter );
+
+ if ( the_font )
+ {
+ FMGetFontContainer( the_font, pathSpec );
+ return FT_Err_Ok;
+ }
+ else
+ return FT_Err_Unknown_File_Format;
+ }
+
+
+ static long
+ ResourceForkSize(FSSpec* spec)
+ {
+ long len;
+ short refNum;
+ OSErr e;
+
+
+ e = FSpOpenRF( spec, fsRdPerm, &refNum ); /* I.M. Files 2-155 */
+ if ( e == noErr )
+ {
+ e = GetEOF( refNum, &len );
+ FSClose( refNum );
+ }
+
+ return ( e == noErr ) ? len : 0;
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* FT_New_Face */
+ /* */
+ /* <Description> */
+ /* This is the Mac-specific implementation of FT_New_Face. In */
+ /* addition to the standard FT_New_Face() functionality, it also */
+ /* accepts pathnames to Mac suitcase files. For further */
+ /* documentation see the original FT_New_Face() in freetype.h. */
+ /* */
+ FT_EXPORT_DEF( FT_Error )
+ FT_New_Face( FT_Library library,
+ const char* pathname,
+ FT_Long face_index,
+ FT_Face *aface )
+ {
+ FT_Open_Args args;
+ FSSpec spec;
+ OSType file_type;
+
+
+ /* test for valid `library' and `aface' delayed to FT_Open_Face() */
+ if ( !pathname )
+ return FT_Err_Invalid_Argument;
+
+ if ( file_spec_from_path( pathname, &spec ) )
+ return FT_Err_Invalid_Argument;
+
+ /* Regardless of type, don't try to use the resource fork if it is */
+ /* empty. Some TTF fonts have type `FFIL', for example, but they */
+ /* only have data forks. */
+
+ if ( ResourceForkSize( &spec ) != 0 )
+ {
+ file_type = get_file_type( &spec );
+ if ( file_type == 'FFIL' || file_type == 'tfil' )
+ return FT_New_Face_From_Suitcase( library, &spec, face_index, aface );
+
+ if ( file_type == 'LWFN' )
+ return FT_New_Face_From_LWFN( library, &spec, face_index, aface );
+ }
+
+#if TARGET_API_MAC_CARBON
+
+ if ( is_dfont( &spec ) )
+ return FT_New_Face_From_dfont( library, &spec, face_index, aface );
+
+#endif
+
+ /* let it fall through to normal loader (.ttf, .otf, etc.) */
+ args.flags = FT_OPEN_PATHNAME;
+ args.pathname = (char*)pathname;
+ return FT_Open_Face( library, &args, face_index, aface );
+ }
+
+
+/* END */
--- /dev/null
+++ b/libfreetype/ftmm.c
@@ -1,0 +1,126 @@
+/***************************************************************************/
+/* */
+/* ftmm.c */
+/* */
+/* Multiple Master font support (body). */
+/* */
+/* Copyright 1996-2001 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+
+#include <ft2build.h>
+#include FT_MULTIPLE_MASTERS_H
+#include FT_INTERNAL_OBJECTS_H
+
+
+ /*************************************************************************/
+ /* */
+ /* The macro FT_COMPONENT is used in trace mode. It is an implicit */
+ /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log */
+ /* messages during execution. */
+ /* */
+#undef FT_COMPONENT
+#define FT_COMPONENT trace_mm
+
+
+ /* documentation is in ftmm.h */
+
+ FT_EXPORT_DEF( FT_Error )
+ FT_Get_Multi_Master( FT_Face face,
+ FT_Multi_Master *amaster )
+ {
+ FT_Error error;
+
+
+ if ( !face )
+ return FT_Err_Invalid_Face_Handle;
+
+ error = FT_Err_Invalid_Argument;
+
+ if ( FT_HAS_MULTIPLE_MASTERS( face ) )
+ {
+ FT_Driver driver = face->driver;
+ FT_Get_MM_Func func;
+
+
+ func = (FT_Get_MM_Func)driver->root.clazz->get_interface(
+ FT_MODULE( driver ), "get_mm" );
+ if ( func )
+ error = func( face, amaster );
+ }
+
+ return error;
+ }
+
+
+ /* documentation is in ftmm.h */
+
+ FT_EXPORT_DEF( FT_Error )
+ FT_Set_MM_Design_Coordinates( FT_Face face,
+ FT_UInt num_coords,
+ FT_Long* coords )
+ {
+ FT_Error error;
+
+
+ if ( !face )
+ return FT_Err_Invalid_Face_Handle;
+
+ error = FT_Err_Invalid_Argument;
+
+ if ( FT_HAS_MULTIPLE_MASTERS( face ) )
+ {
+ FT_Driver driver = face->driver;
+ FT_Set_MM_Design_Func func;
+
+
+ func = (FT_Set_MM_Design_Func)driver->root.clazz->get_interface(
+ FT_MODULE( driver ), "set_mm_design" );
+ if ( func )
+ error = func( face, num_coords, coords );
+ }
+
+ return error;
+ }
+
+
+ /* documentation is in ftmm.h */
+
+ FT_EXPORT_DEF( FT_Error )
+ FT_Set_MM_Blend_Coordinates( FT_Face face,
+ FT_UInt num_coords,
+ FT_Fixed* coords )
+ {
+ FT_Error error;
+
+
+ if ( !face )
+ return FT_Err_Invalid_Face_Handle;
+
+ error = FT_Err_Invalid_Argument;
+
+ if ( FT_HAS_MULTIPLE_MASTERS( face ) )
+ {
+ FT_Driver driver = face->driver;
+ FT_Set_MM_Blend_Func func;
+
+
+ func = (FT_Set_MM_Blend_Func)driver->root.clazz->get_interface(
+ FT_MODULE( driver ), "set_mm_blend" );
+ if ( func )
+ error = func( face, num_coords, coords );
+ }
+
+ return error;
+ }
+
+
+/* END */
--- /dev/null
+++ b/libfreetype/ftnames.c
@@ -1,0 +1,94 @@
+/***************************************************************************/
+/* */
+/* ftnames.c */
+/* */
+/* Simple interface to access SFNT name tables (which are used */
+/* to hold font names, copyright info, notices, etc.) (body). */
+/* */
+/* This is _not_ used to retrieve glyph names! */
+/* */
+/* Copyright 1996-2001, 2002 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+
+#include <ft2build.h>
+#include FT_SFNT_NAMES_H
+#include FT_INTERNAL_TRUETYPE_TYPES_H
+#include FT_INTERNAL_STREAM_H
+
+
+#ifdef TT_CONFIG_OPTION_SFNT_NAMES
+
+
+ /* documentation is in ftnames.h */
+
+ FT_EXPORT_DEF( FT_UInt )
+ FT_Get_Sfnt_Name_Count( FT_Face face )
+ {
+ return (face && FT_IS_SFNT( face )) ? ((TT_Face)face)->num_names : 0;
+ }
+
+
+ /* documentation is in ftnames.h */
+
+ FT_EXPORT_DEF( FT_Error )
+ FT_Get_Sfnt_Name( FT_Face face,
+ FT_UInt idx,
+ FT_SfntName *aname )
+ {
+ FT_Error error = FT_Err_Invalid_Argument;
+
+
+ if ( aname && face && FT_IS_SFNT( face ) )
+ {
+ TT_Face ttface = (TT_Face)face;
+
+
+ if ( idx < (FT_UInt)ttface->num_names )
+ {
+ TT_NameEntryRec* entry = ttface->name_table.names + idx;
+
+
+ /* load name on demand */
+ if ( entry->stringLength > 0 && entry->string == NULL )
+ {
+ FT_Memory memory = face->memory;
+ FT_Stream stream = face->stream;
+
+
+ if ( FT_NEW_ARRAY ( entry->string, entry->stringLength ) ||
+ FT_STREAM_SEEK( entry->stringOffset ) ||
+ FT_STREAM_READ( entry->string, entry->stringLength ) )
+ {
+ FT_FREE( entry->string );
+ entry->stringLength = 0;
+ }
+ }
+
+ aname->platform_id = entry->platformID;
+ aname->encoding_id = entry->encodingID;
+ aname->language_id = entry->languageID;
+ aname->name_id = entry->nameID;
+ aname->string = (FT_Byte*)entry->string;
+ aname->string_len = entry->stringLength;
+
+ error = FT_Err_Ok;
+ }
+ }
+
+ return error;
+ }
+
+
+#endif /* TT_CONFIG_OPTION_SFNT_NAMES */
+
+
+/* END */
--- /dev/null
+++ b/libfreetype/ftobject.c
@@ -1,0 +1,396 @@
+#include <ft2build.h>
+#include FT_INTERNAL_OBJECT_H
+#include FT_INTERNAL_DEBUG_H
+#include FT_INTERNAL_OBJECTS_H
+
+#define FT_MAGIC_DEATH 0xDEADdead
+#define FT_MAGIC_CLASS 0x12345678
+
+#define FT_TYPE_HASH(x) (( (FT_UInt32)(x) >> 2 )^( (FT_UInt32)(x) >> 10 ))
+
+#define FT_OBJECT_CHECK(o) \
+ ( FT_OBJECT(o) != NULL && \
+ FT_OBJECT(o)->clazz != NULL && \
+ FT_OBJECT(o)->ref_count >= 1 && \
+ FT_OBJECT(o)->clazz->magic == FT_MAGIC_CLASS )
+
+#define FT_CLASS_CHECK(c) \
+ ( FT_CLASS(c) != NULL && FT_CLASS(c)->magic == FT_MAGIC_CLASS )
+
+#define FT_ASSERT_IS_CLASS(c) FT_ASSERT( FT_CLASS_CHECK(c) )
+
+ /*******************************************************************/
+ /*******************************************************************/
+ /***** *****/
+ /***** *****/
+ /***** M E T A - C L A S S *****/
+ /***** *****/
+ /***** *****/
+ /*******************************************************************/
+ /*******************************************************************/
+
+ /* forward declaration */
+ FT_BASE_DEF( FT_Error )
+ ft_metaclass_init( FT_MetaClass meta,
+ FT_Library library );
+
+ /* forward declaration */
+ FT_BASE_DEF( void )
+ ft_metaclass_done( FT_MetaClass meta );
+
+
+ /* class type for the meta-class itself */
+ static const FT_TypeRec ft_meta_class_type =
+ {
+ "FT2.MetaClass",
+ NULL,
+
+ sizeof( FT_MetaClassRec ),
+ (FT_Object_InitFunc) ft_metaclass_init,
+ (FT_Object_DoneFunc) ft_metaclass_done,
+
+ sizeof( FT_ClassRec ),
+ (FT_Object_InitFunc) NULL,
+ (FT_Object_DoneFunc) NULL
+ };
+
+
+
+
+ /* destroy a given class */
+ static void
+ ft_class_hnode_destroy( FT_ClassHNode node )
+ {
+ FT_Class clazz = node->clazz;
+ FT_Memory memory = clazz->memory;
+
+ if ( clazz->class_done )
+ clazz->class_done( (FT_Object) clazz );
+
+ FT_FREE( clazz );
+
+ node->clazz = NULL;
+ node->type = NULL;
+
+ FT_FREE( node );
+ }
+
+
+ static FT_Int
+ ft_type_equal( FT_Type type1,
+ FT_Type type2 )
+ {
+ if ( type1 == type2 )
+ goto Ok;
+
+ if ( type1 == NULL || type2 == NULL )
+ goto Fail;
+
+ /* compare parent types */
+ if ( type1->super != type2->super )
+ {
+ if ( type1->super == NULL ||
+ type2->super == NULL ||
+ !ft_type_equal( type1, type2 ) )
+ goto Fail;
+ }
+
+ /* compare type names */
+ if ( type1->name != type2->name )
+ {
+ if ( type1->name == NULL ||
+ type2->name == NULL ||
+ ft_strcmp( type1->name, type2->name ) != 0 )
+ goto Fail;
+ }
+
+ /* compare the other type fields */
+ if ( type1->class_size != type2->class_size ||
+ type1->class_init != type2->class_init ||
+ type1->class_done != type2->class_done ||
+ type1->obj_size != type2->obj_size ||
+ type1->obj_init != type2->obj_init ||
+ type1->obj_done != type2->obj_done )
+ goto Fail;
+
+ Ok:
+ return 1;
+
+ Fail:
+ return 0;
+ }
+
+
+ static FT_Int
+ ft_class_hnode_equal( const FT_ClassHNode node1,
+ const FT_ClassHNode node2 )
+ {
+ FT_Type type1 = node1->type;
+ FT_Type type2 = node2->type;
+
+ /* comparing the pointers should work in 99% of cases */
+ return ( type1 == type2 ) ? 1 : ft_type_equal( type1, type2 );
+ }
+
+
+ FT_BASE_DEF( void )
+ ft_metaclass_done( FT_MetaClass meta )
+ {
+ /* clear all classes */
+ ft_hash_done( &meta->type_to_class,
+ (FT_Hash_ForeachFunc) ft_class_hnode_destroy,
+ NULL );
+
+ meta->clazz.object.clazz = NULL;
+ meta->clazz.object.ref_count = 0;
+ meta->clazz.magic = FT_MAGIC_DEATH;
+ }
+
+
+ FT_BASE_DEF( FT_Error )
+ ft_metaclass_init( FT_MetaClass meta,
+ FT_Library library )
+ {
+ FT_ClassRec* clazz = (FT_ClassRec*) &meta->clazz;
+
+ /* the meta-class is its OWN class !! */
+ clazz->object.clazz = (FT_Class) clazz;
+ clazz->object.ref_count = 1;
+ clazz->magic = FT_MAGIC_CLASS;
+ clazz->library = library;
+ clazz->memory = library->memory;
+ clazz->type = &ft_meta_class_type;
+ clazz->info = NULL;
+
+ clazz->class_done = (FT_Object_DoneFunc) ft_metaclass_done;
+
+ clazz->obj_size = sizeof( FT_ClassRec );
+ clazz->obj_init = NULL;
+ clazz->obj_done = NULL;
+
+ return ft_hash_init( &meta->type_to_class,
+ (FT_Hash_EqualFunc) ft_class_hnode_equal,
+ library->memory );
+ }
+
+
+ /* find or create the class corresponding to a given type */
+ /* note that this function will retunr NULL in case of */
+ /* memory overflow */
+ /* */
+ static FT_Class
+ ft_metaclass_get_class( FT_MetaClass meta,
+ FT_Type ctype )
+ {
+ FT_ClassHNodeRec keynode, *node, **pnode;
+ FT_Memory memory;
+ FT_ClassRec* clazz;
+ FT_Class parent;
+ FT_Error error;
+
+ keynode.hnode.hash = FT_TYPE_HASH( ctype );
+ keynode.type = ctype;
+
+ pnode = (FT_ClassHNode*) ft_hash_lookup( &meta->type_to_class,
+ (FT_HashNode) &keynode );
+ node = *pnode;
+ if ( node != NULL )
+ {
+ clazz = (FT_ClassRec*) node->clazz;
+ goto Exit;
+ }
+
+ memory = FT_CLASS__MEMORY(meta);
+ clazz = NULL;
+ parent = NULL;
+ if ( ctype->super != NULL )
+ {
+ FT_ASSERT( ctype->super->class_size <= ctype->class_size );
+ FT_ASSERT( ctype->super->obj_size <= ctype->obj_size );
+
+ parent = ft_metaclass_get_class( meta, ctype->super );
+ }
+
+ if ( !FT_NEW( node ) )
+ {
+ if ( !FT_ALLOC( clazz, ctype->class_size ) )
+ {
+ if ( parent )
+ FT_MEM_COPY( (FT_ClassRec*)clazz, parent, parent->type->class_size );
+
+ clazz->object.clazz = (FT_Class) meta;
+ clazz->object.ref_count = 1;
+
+ clazz->memory = memory;
+ clazz->library = FT_CLASS__LIBRARY(meta);
+ clazz->super = parent;
+ clazz->type = ctype;
+ clazz->info = NULL;
+ clazz->magic = FT_MAGIC_CLASS;
+
+ clazz->class_done = ctype->class_done;
+ clazz->obj_size = ctype->obj_size;
+ clazz->obj_init = ctype->obj_init;
+ clazz->obj_done = ctype->obj_done;
+
+ if ( parent )
+ {
+ if ( clazz->class_done == NULL )
+ clazz->class_done = parent->class_done;
+
+ if ( clazz->obj_init == NULL )
+ clazz->obj_init = parent->obj_init;
+
+ if ( clazz->obj_done == NULL )
+ clazz->obj_done = parent->obj_done;
+ }
+
+ /* find class initializer, if any */
+ {
+ FT_Type ztype = ctype;
+ FT_Object_InitFunc cinit = NULL;
+
+ do
+ {
+ cinit = ztype->class_init;
+ if ( cinit != NULL )
+ break;
+
+ ztype = ztype->super;
+ }
+ while ( ztype != NULL );
+
+ /* then call it when needed */
+ if ( cinit != NULL )
+ error = cinit( (FT_Object) clazz, NULL );
+ }
+ }
+
+ if (error)
+ {
+ if ( clazz )
+ {
+ /* we always call the class destructor when */
+ /* an error was detected in the constructor !! */
+ if ( clazz->class_done )
+ clazz->class_done( (FT_Object) clazz );
+
+ FT_FREE( clazz );
+ }
+ FT_FREE( node );
+ }
+ }
+
+ Exit:
+ return (FT_Class) clazz;
+ }
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ FT_BASE_DEF( FT_Int )
+ ft_object_check( FT_Pointer obj )
+ {
+ return FT_OBJECT_CHECK(obj);
+ }
+
+
+ FT_BASE_DEF( FT_Int )
+ ft_object_is_a( FT_Pointer obj,
+ FT_Class clazz )
+ {
+ if ( FT_OBJECT_CHECK(obj) )
+ {
+ FT_Class c = FT_OBJECT__CLASS(obj);
+
+ do
+ {
+ if ( c == clazz )
+ return 1;
+
+ c = c->super;
+ }
+ while ( c == NULL );
+
+ return (clazz == NULL);
+ }
+ return 0;
+ }
+
+
+ FT_BASE_DEF( FT_Error )
+ ft_object_create( FT_Object *pobject,
+ FT_Class clazz,
+ FT_Pointer init_data )
+ {
+ FT_Memory memory;
+ FT_Error error;
+ FT_Object obj;
+
+ FT_ASSERT_IS_CLASS(clazz);
+
+ memory = FT_CLASS__MEMORY(clazz);
+ if ( !FT_ALLOC( obj, clazz->obj_size ) )
+ {
+ obj->clazz = clazz;
+ obj->ref_count = 1;
+
+ if ( clazz->obj_init )
+ {
+ error = clazz->obj_init( obj, init_data );
+ if ( error )
+ {
+ /* IMPORTANT: call the destructor when an error */
+ /* was detected in the constructor !! */
+ if ( clazz->obj_done )
+ clazz->obj_done( obj );
+
+ FT_FREE( obj );
+ }
+ }
+ }
+ *pobject = obj;
+ return error;
+ }
+
+
+ FT_BASE_DEF( FT_Class )
+ ft_class_find_by_type( FT_Type type,
+ FT_Library library )
+ {
+ FT_MetaClass meta = &library->meta_class;
+
+ return ft_metaclass_get_class( meta, type );
+ }
+
+
+ FT_BASE_DEF( FT_Error )
+ ft_object_create_from_type( FT_Object *pobject,
+ FT_Type type,
+ FT_Pointer init_data,
+ FT_Library library )
+ {
+ FT_Class clazz;
+ FT_Error error;
+
+ clazz = ft_class_find_by_type( type, library );
+ if ( clazz )
+ error = ft_object_create( pobject, clazz, init_data );
+ else
+ {
+ *pobject = NULL;
+ error = FT_Err_Out_Of_Memory;
+ }
+
+ return error;
+ }
--- /dev/null
+++ b/libfreetype/ftobjs.c
@@ -1,0 +1,2505 @@
+/***************************************************************************/
+/* */
+/* ftobjs.c */
+/* */
+/* The FreeType private base classes (body). */
+/* */
+/* Copyright 1996-2001, 2002 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+
+#include <ft2build.h>
+#include FT_LIST_H
+#include FT_OUTLINE_H
+#include FT_INTERNAL_OBJECTS_H
+#include FT_INTERNAL_DEBUG_H
+#include FT_INTERNAL_STREAM_H
+#include FT_TRUETYPE_TABLES_H
+#include FT_OUTLINE_H
+
+
+ FT_BASE_DEF( void )
+ ft_validator_init( FT_Validator valid,
+ const FT_Byte* base,
+ const FT_Byte* limit,
+ FT_ValidationLevel level )
+ {
+ valid->base = base;
+ valid->limit = limit;
+ valid->level = level;
+ valid->error = 0;
+ }
+
+
+ FT_BASE_DEF( FT_Int )
+ ft_validator_run( FT_Validator valid )
+ {
+ int result;
+
+
+ result = ft_setjmp( valid->jump_buffer );
+ return result;
+ }
+
+
+ FT_BASE_DEF( void )
+ ft_validator_error( FT_Validator valid,
+ FT_Error error )
+ {
+ valid->error = error;
+ ft_longjmp( valid->jump_buffer, 1 );
+ }
+
+
+ /*************************************************************************/
+ /*************************************************************************/
+ /*************************************************************************/
+ /**** ****/
+ /**** ****/
+ /**** S T R E A M ****/
+ /**** ****/
+ /**** ****/
+ /*************************************************************************/
+ /*************************************************************************/
+ /*************************************************************************/
+
+
+ /* create a new input stream from a FT_Open_Args structure */
+ /* */
+ static FT_Error
+ ft_input_stream_new( FT_Library library,
+ const FT_Open_Args* args,
+ FT_Stream* astream )
+ {
+ FT_Error error;
+ FT_Memory memory;
+ FT_Stream stream;
+
+
+ if ( !library )
+ return FT_Err_Invalid_Library_Handle;
+
+ if ( !args )
+ return FT_Err_Invalid_Argument;
+
+ *astream = 0;
+ memory = library->memory;
+
+ if ( FT_NEW( stream ) )
+ goto Exit;
+
+ stream->memory = memory;
+
+ if ( args->flags & FT_OPEN_MEMORY )
+ {
+ /* create a memory-based stream */
+ FT_Stream_OpenMemory( stream,
+ (const FT_Byte*)args->memory_base,
+ args->memory_size );
+ }
+ else if ( args->flags & FT_OPEN_PATHNAME )
+ {
+ /* create a normal system stream */
+ error = FT_Stream_Open( stream, args->pathname );
+ stream->pathname.pointer = args->pathname;
+ }
+ else if ( ( args->flags & FT_OPEN_STREAM ) && args->stream )
+ {
+ /* use an existing, user-provided stream */
+
+ /* in this case, we do not need to allocate a new stream object */
+ /* since the caller is responsible for closing it himself */
+ FT_FREE( stream );
+ stream = args->stream;
+ }
+ else
+ error = FT_Err_Invalid_Argument;
+
+ if ( error )
+ FT_FREE( stream );
+ else
+ stream->memory = memory; /* just to be certain */
+
+ *astream = stream;
+
+ Exit:
+ return error;
+ }
+
+
+ static void
+ ft_input_stream_free( FT_Stream stream,
+ FT_Int external )
+ {
+ if ( stream )
+ {
+ FT_Memory memory = stream->memory;
+
+
+ FT_Stream_Close( stream );
+
+ if ( !external )
+ FT_FREE( stream );
+ }
+ }
+
+
+#undef FT_COMPONENT
+#define FT_COMPONENT trace_objs
+
+
+ /*************************************************************************/
+ /*************************************************************************/
+ /*************************************************************************/
+ /**** ****/
+ /**** ****/
+ /**** FACE, SIZE & GLYPH SLOT OBJECTS ****/
+ /**** ****/
+ /**** ****/
+ /*************************************************************************/
+ /*************************************************************************/
+ /*************************************************************************/
+
+
+ static FT_Error
+ ft_glyphslot_init( FT_GlyphSlot slot )
+ {
+ FT_Driver driver = slot->face->driver;
+ FT_Driver_Class clazz = driver->clazz;
+ FT_Memory memory = driver->root.memory;
+ FT_Error error = FT_Err_Ok;
+ FT_Slot_Internal internal;
+
+
+ slot->library = driver->root.library;
+
+ if ( FT_NEW( internal ) )
+ goto Exit;
+
+ slot->internal = internal;
+
+ if ( FT_DRIVER_USES_OUTLINES( driver ) )
+ error = FT_GlyphLoader_New( memory, &internal->loader );
+
+ if ( !error && clazz->init_slot )
+ error = clazz->init_slot( slot );
+
+ Exit:
+ return error;
+ }
+
+
+ static void
+ ft_glyphslot_clear( FT_GlyphSlot slot )
+ {
+ /* free bitmap if needed */
+ if ( slot->flags & FT_GLYPH_OWN_BITMAP )
+ {
+ FT_Memory memory = FT_FACE_MEMORY( slot->face );
+
+
+ FT_FREE( slot->bitmap.buffer );
+ slot->flags &= ~FT_GLYPH_OWN_BITMAP;
+ }
+
+ /* clear all public fields in the glyph slot */
+ FT_ZERO( &slot->metrics );
+ FT_ZERO( &slot->outline );
+
+ slot->bitmap.width = 0;
+ slot->bitmap.rows = 0;
+ slot->bitmap.pitch = 0;
+ slot->bitmap.pixel_mode = 0;
+ /* don't touch 'slot->bitmap.buffer' !! */
+
+ slot->bitmap_left = 0;
+ slot->bitmap_top = 0;
+ slot->num_subglyphs = 0;
+ slot->subglyphs = 0;
+ slot->control_data = 0;
+ slot->control_len = 0;
+ slot->other = 0;
+ slot->format = FT_GLYPH_FORMAT_NONE;
+
+ slot->linearHoriAdvance = 0;
+ slot->linearVertAdvance = 0;
+ }
+
+
+ static void
+ ft_glyphslot_done( FT_GlyphSlot slot )
+ {
+ FT_Driver driver = slot->face->driver;
+ FT_Driver_Class clazz = driver->clazz;
+ FT_Memory memory = driver->root.memory;
+
+
+ if ( clazz->done_slot )
+ clazz->done_slot( slot );
+
+ /* free bitmap buffer if needed */
+ if ( slot->flags & FT_GLYPH_OWN_BITMAP )
+ FT_FREE( slot->bitmap.buffer );
+
+ /* free glyph loader */
+ if ( FT_DRIVER_USES_OUTLINES( driver ) )
+ {
+ FT_GlyphLoader_Done( slot->internal->loader );
+ slot->internal->loader = 0;
+ }
+
+ FT_FREE( slot->internal );
+ }
+
+
+ /* documentation is in ftobjs.h */
+
+ FT_BASE_DEF( FT_Error )
+ FT_New_GlyphSlot( FT_Face face,
+ FT_GlyphSlot *aslot )
+ {
+ FT_Error error;
+ FT_Driver driver;
+ FT_Driver_Class clazz;
+ FT_Memory memory;
+ FT_GlyphSlot slot;
+
+
+ if ( !face || !aslot || !face->driver )
+ return FT_Err_Invalid_Argument;
+
+ *aslot = 0;
+
+ driver = face->driver;
+ clazz = driver->clazz;
+ memory = driver->root.memory;
+
+ FT_TRACE4(( "FT_New_GlyphSlot: Creating new slot object\n" ));
+ if ( !FT_ALLOC( slot, clazz->slot_object_size ) )
+ {
+ slot->face = face;
+
+ error = ft_glyphslot_init( slot );
+ if ( error )
+ {
+ ft_glyphslot_done( slot );
+ FT_FREE( slot );
+ goto Exit;
+ }
+
+ *aslot = slot;
+ }
+
+ Exit:
+ FT_TRACE4(( "FT_New_GlyphSlot: Return %d\n", error ));
+ return error;
+ }
+
+
+ /* documentation is in ftobjs.h */
+
+ FT_BASE_DEF( void )
+ FT_Done_GlyphSlot( FT_GlyphSlot slot )
+ {
+ if ( slot )
+ {
+ FT_Driver driver = slot->face->driver;
+ FT_Memory memory = driver->root.memory;
+ FT_GlyphSlot* parent;
+ FT_GlyphSlot cur;
+
+
+ /* Remove slot from its parent face's list */
+ parent = &slot->face->glyph;
+ cur = *parent;
+
+ while ( cur )
+ {
+ if ( cur == slot )
+ {
+ *parent = cur->next;
+ ft_glyphslot_done( slot );
+ FT_FREE( slot );
+ break;
+ }
+ cur = cur->next;
+ }
+ }
+ }
+
+
+ /* documentation is in freetype.h */
+
+ FT_EXPORT_DEF( void )
+ FT_Set_Transform( FT_Face face,
+ FT_Matrix* matrix,
+ FT_Vector* delta )
+ {
+ FT_Face_Internal internal;
+
+
+ if ( !face )
+ return;
+
+ internal = face->internal;
+
+ internal->transform_flags = 0;
+
+ if ( !matrix )
+ {
+ internal->transform_matrix.xx = 0x10000L;
+ internal->transform_matrix.xy = 0;
+ internal->transform_matrix.yx = 0;
+ internal->transform_matrix.yy = 0x10000L;
+ matrix = &internal->transform_matrix;
+ }
+ else
+ internal->transform_matrix = *matrix;
+
+ /* set transform_flags bit flag 0 if `matrix' isn't the identity */
+ if ( ( matrix->xy | matrix->yx ) ||
+ matrix->xx != 0x10000L ||
+ matrix->yy != 0x10000L )
+ internal->transform_flags |= 1;
+
+ if ( !delta )
+ {
+ internal->transform_delta.x = 0;
+ internal->transform_delta.y = 0;
+ delta = &internal->transform_delta;
+ }
+ else
+ internal->transform_delta = *delta;
+
+ /* set transform_flags bit flag 1 if `delta' isn't the null vector */
+ if ( delta->x | delta->y )
+ internal->transform_flags |= 2;
+ }
+
+
+ /* documentation is in freetype.h */
+
+ FT_EXPORT_DEF( void )
+ FT_Set_Hint_Flags( FT_Face face,
+ FT_ULong flags )
+ {
+ FT_Face_Internal internal;
+
+ if ( !face )
+ return;
+
+ internal = face->internal;
+
+ internal->hint_flags = (FT_UInt)flags;
+ }
+
+
+ static FT_Renderer
+ ft_lookup_glyph_renderer( FT_GlyphSlot slot );
+
+
+ /* documentation is in freetype.h */
+
+ FT_EXPORT_DEF( FT_Error )
+ FT_Load_Glyph( FT_Face face,
+ FT_UInt glyph_index,
+ FT_Int32 load_flags )
+ {
+ FT_Error error;
+ FT_Driver driver;
+ FT_GlyphSlot slot;
+ FT_Library library;
+ FT_Bool autohint;
+ FT_Module hinter;
+
+
+ if ( !face || !face->size || !face->glyph )
+ return FT_Err_Invalid_Face_Handle;
+
+ if ( glyph_index > (FT_UInt)face->num_glyphs )
+ return FT_Err_Invalid_Argument;
+
+ slot = face->glyph;
+ ft_glyphslot_clear( slot );
+
+ driver = face->driver;
+
+ /* if the flag NO_RECURSE is set, we disable hinting and scaling */
+ if ( load_flags & FT_LOAD_NO_RECURSE )
+ {
+ /* disable scaling, hinting, and transformation */
+ load_flags |= FT_LOAD_NO_SCALE |
+ FT_LOAD_NO_HINTING |
+ FT_LOAD_NO_BITMAP |
+ FT_LOAD_IGNORE_TRANSFORM;
+
+ /* disable bitmap rendering */
+ load_flags &= ~FT_LOAD_RENDER;
+ }
+
+ /* do we need to load the glyph through the auto-hinter? */
+ library = driver->root.library;
+ hinter = library->auto_hinter;
+ autohint =
+ FT_BOOL( hinter &&
+ !( load_flags & ( FT_LOAD_NO_SCALE |
+ FT_LOAD_NO_HINTING |
+ FT_LOAD_NO_AUTOHINT ) ) &&
+ FT_DRIVER_IS_SCALABLE( driver ) &&
+ FT_DRIVER_USES_OUTLINES( driver ) );
+ if ( autohint )
+ {
+ if ( FT_DRIVER_HAS_HINTER( driver ) &&
+ !( load_flags & FT_LOAD_FORCE_AUTOHINT ) )
+ autohint = 0;
+ }
+
+ if ( autohint )
+ {
+ FT_AutoHinter_Service hinting;
+
+
+ /* try to load embedded bitmaps first if available */
+ /* */
+ /* XXX: This is really a temporary hack that should disappear */
+ /* promptly with FreeType 2.1! */
+ /* */
+ if ( FT_HAS_FIXED_SIZES( face ) &&
+ ( load_flags & FT_LOAD_NO_BITMAP ) == 0 )
+ {
+ error = driver->clazz->load_glyph( slot, face->size,
+ glyph_index,
+ load_flags | FT_LOAD_SBITS_ONLY );
+
+ if ( !error && slot->format == FT_GLYPH_FORMAT_BITMAP )
+ goto Load_Ok;
+ }
+
+ /* load auto-hinted outline */
+ hinting = (FT_AutoHinter_Service)hinter->clazz->module_interface;
+
+ error = hinting->load_glyph( (FT_AutoHinter)hinter,
+ slot, face->size,
+ glyph_index, load_flags );
+ }
+ else
+ {
+ error = driver->clazz->load_glyph( slot,
+ face->size,
+ glyph_index,
+ load_flags );
+ if ( error )
+ goto Exit;
+
+ /* check that the loaded outline is correct */
+ error = FT_Outline_Check( &slot->outline );
+ if ( error )
+ goto Exit;
+ }
+
+ Load_Ok:
+ /* compute the advance */
+ if ( load_flags & FT_LOAD_VERTICAL_LAYOUT )
+ {
+ slot->advance.x = 0;
+ slot->advance.y = slot->metrics.vertAdvance;
+ }
+ else
+ {
+ slot->advance.x = slot->metrics.horiAdvance;
+ slot->advance.y = 0;
+ }
+
+ /* compute the linear advance in 16.16 pixels */
+ if ( ( load_flags & FT_LOAD_LINEAR_DESIGN ) == 0 )
+ {
+ FT_UInt EM = face->units_per_EM;
+ FT_Size_Metrics* metrics = &face->size->metrics;
+
+
+ slot->linearHoriAdvance = FT_MulDiv( slot->linearHoriAdvance,
+ (FT_Long)metrics->x_ppem << 16, EM );
+
+ slot->linearVertAdvance = FT_MulDiv( slot->linearVertAdvance,
+ (FT_Long)metrics->y_ppem << 16, EM );
+ }
+
+ if ( ( load_flags & FT_LOAD_IGNORE_TRANSFORM ) == 0 )
+ {
+ FT_Face_Internal internal = face->internal;
+
+
+ /* now, transform the glyph image if needed */
+ if ( internal->transform_flags )
+ {
+ /* get renderer */
+ FT_Renderer renderer = ft_lookup_glyph_renderer( slot );
+
+
+ if ( renderer )
+ error = renderer->clazz->transform_glyph(
+ renderer, slot,
+ &internal->transform_matrix,
+ &internal->transform_delta );
+ /* transform advance */
+ FT_Vector_Transform( &slot->advance, &internal->transform_matrix );
+ }
+ }
+
+ /* do we need to render the image now? */
+ if ( !error &&
+ slot->format != FT_GLYPH_FORMAT_BITMAP &&
+ slot->format != FT_GLYPH_FORMAT_COMPOSITE &&
+ load_flags & FT_LOAD_RENDER )
+ {
+ FT_Render_Mode mode = FT_LOAD_TARGET_MODE( load_flags );
+
+
+ if ( mode == FT_RENDER_MODE_NORMAL &&
+ (load_flags & FT_LOAD_MONOCHROME ) )
+ mode = FT_RENDER_MODE_MONO;
+
+ error = FT_Render_Glyph( slot, mode );
+ }
+
+ Exit:
+ return error;
+ }
+
+
+ /* documentation is in freetype.h */
+
+ FT_EXPORT_DEF( FT_Error )
+ FT_Load_Char( FT_Face face,
+ FT_ULong char_code,
+ FT_Int32 load_flags )
+ {
+ FT_UInt glyph_index;
+
+
+ if ( !face )
+ return FT_Err_Invalid_Face_Handle;
+
+ glyph_index = (FT_UInt)char_code;
+ if ( face->charmap )
+ glyph_index = FT_Get_Char_Index( face, char_code );
+
+ return FT_Load_Glyph( face, glyph_index, load_flags );
+ }
+
+
+ /* destructor for sizes list */
+ static void
+ destroy_size( FT_Memory memory,
+ FT_Size size,
+ FT_Driver driver )
+ {
+ /* finalize client-specific data */
+ if ( size->generic.finalizer )
+ size->generic.finalizer( size );
+
+ /* finalize format-specific stuff */
+ if ( driver->clazz->done_size )
+ driver->clazz->done_size( size );
+
+ FT_FREE( size->internal );
+ FT_FREE( size );
+ }
+
+
+ /* destructor for faces list */
+ static void
+ destroy_face( FT_Memory memory,
+ FT_Face face,
+ FT_Driver driver )
+ {
+ FT_Driver_Class clazz = driver->clazz;
+
+
+ /* discard auto-hinting data */
+ if ( face->autohint.finalizer )
+ face->autohint.finalizer( face->autohint.data );
+
+ /* Discard glyph slots for this face. */
+ /* Beware! FT_Done_GlyphSlot() changes the field `face->glyph' */
+ while ( face->glyph )
+ FT_Done_GlyphSlot( face->glyph );
+
+ /* discard all sizes for this face */
+ FT_List_Finalize( &face->sizes_list,
+ (FT_List_Destructor)destroy_size,
+ memory,
+ driver );
+ face->size = 0;
+
+ /* now discard client data */
+ if ( face->generic.finalizer )
+ face->generic.finalizer( face );
+
+ /* discard charmaps */
+ {
+ FT_Int n;
+
+
+ for ( n = 0; n < face->num_charmaps; n++ )
+ {
+ FT_CMap cmap = FT_CMAP( face->charmaps[n] );
+
+
+ FT_CMap_Done( cmap );
+
+ face->charmaps[n] = NULL;
+ }
+
+ FT_FREE( face->charmaps );
+ face->num_charmaps = 0;
+ }
+
+
+ /* finalize format-specific stuff */
+ if ( clazz->done_face )
+ clazz->done_face( face );
+
+ /* close the stream for this face if needed */
+ ft_input_stream_free(
+ face->stream,
+ ( face->face_flags & FT_FACE_FLAG_EXTERNAL_STREAM ) != 0 );
+
+ face->stream = 0;
+
+ /* get rid of it */
+ if ( face->internal )
+ {
+ FT_FREE( face->internal->postscript_name );
+ FT_FREE( face->internal );
+ }
+ FT_FREE( face );
+ }
+
+
+ static void
+ Destroy_Driver( FT_Driver driver )
+ {
+ FT_List_Finalize( &driver->faces_list,
+ (FT_List_Destructor)destroy_face,
+ driver->root.memory,
+ driver );
+
+ /* check whether we need to drop the driver's glyph loader */
+ if ( FT_DRIVER_USES_OUTLINES( driver ) )
+ FT_GlyphLoader_Done( driver->glyph_loader );
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* open_face */
+ /* */
+ /* <Description> */
+ /* This function does some work for FT_Open_Face(). */
+ /* */
+ static FT_Error
+ open_face( FT_Driver driver,
+ FT_Stream stream,
+ FT_Long face_index,
+ FT_Int num_params,
+ FT_Parameter* params,
+ FT_Face* aface )
+ {
+ FT_Memory memory;
+ FT_Driver_Class clazz;
+ FT_Face face = 0;
+ FT_Error error;
+ FT_Face_Internal internal;
+
+
+ clazz = driver->clazz;
+ memory = driver->root.memory;
+
+ /* allocate the face object and perform basic initialization */
+ if ( FT_ALLOC( face, clazz->face_object_size ) )
+ goto Fail;
+
+ if ( FT_NEW( internal ) )
+ goto Fail;
+
+ face->internal = internal;
+
+ face->driver = driver;
+ face->memory = memory;
+ face->stream = stream;
+
+#ifdef FT_CONFIG_OPTION_INCREMENTAL
+ {
+ int i;
+
+
+ face->internal->incremental_interface = 0;
+ for ( i = 0; i < num_params && !face->internal->incremental_interface;
+ i++ )
+ if ( params[i].tag == FT_PARAM_TAG_INCREMENTAL )
+ face->internal->incremental_interface = params[i].data;
+ }
+#endif
+
+ error = clazz->init_face( stream,
+ face,
+ (FT_Int)face_index,
+ num_params,
+ params );
+ if ( error )
+ goto Fail;
+
+ /* select Unicode charmap by default */
+ {
+ FT_Int nn;
+ FT_CharMap unicmap = NULL, cmap;
+
+
+ for ( nn = 0; nn < face->num_charmaps; nn++ )
+ {
+ cmap = face->charmaps[nn];
+
+ if ( cmap->encoding == FT_ENCODING_UNICODE )
+ {
+ unicmap = cmap;
+ break;
+ }
+ }
+
+ if ( unicmap != NULL )
+ face->charmap = unicmap;
+ }
+
+ *aface = face;
+
+ Fail:
+ if ( error )
+ {
+ clazz->done_face( face );
+ FT_FREE( face->internal );
+ FT_FREE( face );
+ *aface = 0;
+ }
+
+ return error;
+ }
+
+
+ /* there's a Mac-specific extended implementation of FT_New_Face() */
+ /* in src/base/ftmac.c */
+
+#ifndef FT_MACINTOSH
+
+ /* documentation is in freetype.h */
+
+ FT_EXPORT_DEF( FT_Error )
+ FT_New_Face( FT_Library library,
+ const char* pathname,
+ FT_Long face_index,
+ FT_Face *aface )
+ {
+ FT_Open_Args args;
+
+
+ /* test for valid `library' and `aface' delayed to FT_Open_Face() */
+ if ( !pathname )
+ return FT_Err_Invalid_Argument;
+
+ args.flags = FT_OPEN_PATHNAME;
+ args.pathname = (char*)pathname;
+
+ return FT_Open_Face( library, &args, face_index, aface );
+ }
+
+#endif /* !FT_MACINTOSH */
+
+
+ /* documentation is in freetype.h */
+
+ FT_EXPORT_DEF( FT_Error )
+ FT_New_Memory_Face( FT_Library library,
+ const FT_Byte* file_base,
+ FT_Long file_size,
+ FT_Long face_index,
+ FT_Face *aface )
+ {
+ FT_Open_Args args;
+
+
+ /* test for valid `library' and `face' delayed to FT_Open_Face() */
+ if ( !file_base )
+ return FT_Err_Invalid_Argument;
+
+ args.flags = FT_OPEN_MEMORY;
+ args.memory_base = file_base;
+ args.memory_size = file_size;
+
+ return FT_Open_Face( library, &args, face_index, aface );
+ }
+
+
+ /* documentation is in freetype.h */
+
+ FT_EXPORT_DEF( FT_Error )
+ FT_Open_Face( FT_Library library,
+ const FT_Open_Args* args,
+ FT_Long face_index,
+ FT_Face *aface )
+ {
+ FT_Error error;
+ FT_Driver driver;
+ FT_Memory memory;
+ FT_Stream stream;
+ FT_Face face = 0;
+ FT_ListNode node = 0;
+ FT_Bool external_stream;
+
+
+ /* test for valid `library' delayed to */
+ /* ft_input_stream_new() */
+
+ if ( !aface || !args )
+ return FT_Err_Invalid_Argument;
+
+ *aface = 0;
+
+ external_stream = FT_BOOL( ( args->flags & FT_OPEN_STREAM ) &&
+ args->stream );
+
+ /* create input stream */
+ error = ft_input_stream_new( library, args, &stream );
+ if ( error )
+ goto Exit;
+
+ memory = library->memory;
+
+ /* If the font driver is specified in the `args' structure, use */
+ /* it. Otherwise, we scan the list of registered drivers. */
+ if ( ( args->flags & FT_OPEN_DRIVER ) && args->driver )
+ {
+ driver = FT_DRIVER( args->driver );
+
+ /* not all modules are drivers, so check... */
+ if ( FT_MODULE_IS_DRIVER( driver ) )
+ {
+ FT_Int num_params = 0;
+ FT_Parameter* params = 0;
+
+
+ if ( args->flags & FT_OPEN_PARAMS )
+ {
+ num_params = args->num_params;
+ params = args->params;
+ }
+
+ error = open_face( driver, stream, face_index,
+ num_params, params, &face );
+ if ( !error )
+ goto Success;
+ }
+ else
+ error = FT_Err_Invalid_Handle;
+
+ ft_input_stream_free( stream, external_stream );
+ goto Fail;
+ }
+ else
+ {
+ /* check each font driver for an appropriate format */
+ FT_Module* cur = library->modules;
+ FT_Module* limit = cur + library->num_modules;
+
+
+ for ( ; cur < limit; cur++ )
+ {
+ /* not all modules are font drivers, so check... */
+ if ( FT_MODULE_IS_DRIVER( cur[0] ) )
+ {
+ FT_Int num_params = 0;
+ FT_Parameter* params = 0;
+
+
+ driver = FT_DRIVER( cur[0] );
+
+ if ( args->flags & FT_OPEN_PARAMS )
+ {
+ num_params = args->num_params;
+ params = args->params;
+ }
+
+ error = open_face( driver, stream, face_index,
+ num_params, params, &face );
+ if ( !error )
+ goto Success;
+
+ if ( FT_ERROR_BASE( error ) != FT_Err_Unknown_File_Format )
+ goto Fail2;
+ }
+ }
+
+ /* no driver is able to handle this format */
+ error = FT_Err_Unknown_File_Format;
+
+ Fail2:
+ ft_input_stream_free( stream, external_stream );
+ goto Fail;
+ }
+
+ Success:
+ FT_TRACE4(( "FT_Open_Face: New face object, adding to list\n" ));
+
+ /* set the FT_FACE_FLAG_EXTERNAL_STREAM bit for FT_Done_Face */
+ if ( external_stream )
+ face->face_flags |= FT_FACE_FLAG_EXTERNAL_STREAM;
+
+ /* add the face object to its driver's list */
+ if ( FT_NEW( node ) )
+ goto Fail;
+
+ node->data = face;
+ /* don't assume driver is the same as face->driver, so use */
+ /* face->driver instead. */
+ FT_List_Add( &face->driver->faces_list, node );
+
+ /* now allocate a glyph slot object for the face */
+ {
+ FT_GlyphSlot slot;
+
+
+ FT_TRACE4(( "FT_Open_Face: Creating glyph slot\n" ));
+
+ error = FT_New_GlyphSlot( face, &slot );
+ if ( error )
+ goto Fail;
+
+ face->glyph = slot;
+ }
+
+ /* finally, allocate a size object for the face */
+ {
+ FT_Size size;
+
+
+ FT_TRACE4(( "FT_Open_Face: Creating size object\n" ));
+
+ error = FT_New_Size( face, &size );
+ if ( error )
+ goto Fail;
+
+ face->size = size;
+ }
+
+ /* initialize internal face data */
+ {
+ FT_Face_Internal internal = face->internal;
+
+
+ internal->transform_matrix.xx = 0x10000L;
+ internal->transform_matrix.xy = 0;
+ internal->transform_matrix.yx = 0;
+ internal->transform_matrix.yy = 0x10000L;
+
+ internal->transform_delta.x = 0;
+ internal->transform_delta.y = 0;
+ }
+
+ *aface = face;
+ goto Exit;
+
+ Fail:
+ FT_Done_Face( face );
+
+ Exit:
+ FT_TRACE4(( "FT_Open_Face: Return %d\n", error ));
+
+ return error;
+ }
+
+
+ /* documentation is in freetype.h */
+
+ FT_EXPORT_DEF( FT_Error )
+ FT_Attach_File( FT_Face face,
+ const char* filepathname )
+ {
+ FT_Open_Args open;
+
+
+ /* test for valid `face' delayed to FT_Attach_Stream() */
+
+ if ( !filepathname )
+ return FT_Err_Invalid_Argument;
+
+ open.flags = FT_OPEN_PATHNAME;
+ open.pathname = (char*)filepathname;
+
+ return FT_Attach_Stream( face, &open );
+ }
+
+
+ /* documentation is in freetype.h */
+
+ FT_EXPORT_DEF( FT_Error )
+ FT_Attach_Stream( FT_Face face,
+ FT_Open_Args* parameters )
+ {
+ FT_Stream stream;
+ FT_Error error;
+ FT_Driver driver;
+
+ FT_Driver_Class clazz;
+
+
+ /* test for valid `parameters' delayed to ft_input_stream_new() */
+
+ if ( !face )
+ return FT_Err_Invalid_Face_Handle;
+
+ driver = face->driver;
+ if ( !driver )
+ return FT_Err_Invalid_Driver_Handle;
+
+ error = ft_input_stream_new( driver->root.library, parameters, &stream );
+ if ( error )
+ goto Exit;
+
+ /* we implement FT_Attach_Stream in each driver through the */
+ /* `attach_file' interface */
+
+ error = FT_Err_Unimplemented_Feature;
+ clazz = driver->clazz;
+ if ( clazz->attach_file )
+ error = clazz->attach_file( face, stream );
+
+ /* close the attached stream */
+ ft_input_stream_free( stream,
+ (FT_Bool)( parameters->stream &&
+ ( parameters->flags & FT_OPEN_STREAM ) ) );
+
+ Exit:
+ return error;
+ }
+
+
+ /* documentation is in freetype.h */
+
+ FT_EXPORT_DEF( FT_Error )
+ FT_Done_Face( FT_Face face )
+ {
+ FT_Error error;
+ FT_Driver driver;
+ FT_Memory memory;
+ FT_ListNode node;
+
+
+ error = FT_Err_Invalid_Face_Handle;
+ if ( face && face->driver )
+ {
+ driver = face->driver;
+ memory = driver->root.memory;
+
+ /* find face in driver's list */
+ node = FT_List_Find( &driver->faces_list, face );
+ if ( node )
+ {
+ /* remove face object from the driver's list */
+ FT_List_Remove( &driver->faces_list, node );
+ FT_FREE( node );
+
+ /* now destroy the object proper */
+ destroy_face( memory, face, driver );
+ error = FT_Err_Ok;
+ }
+ }
+ return error;
+ }
+
+
+ /* documentation is in ftobjs.h */
+
+ FT_EXPORT_DEF( FT_Error )
+ FT_New_Size( FT_Face face,
+ FT_Size *asize )
+ {
+ FT_Error error;
+ FT_Memory memory;
+ FT_Driver driver;
+ FT_Driver_Class clazz;
+
+ FT_Size size = 0;
+ FT_ListNode node = 0;
+
+
+ if ( !face )
+ return FT_Err_Invalid_Face_Handle;
+
+ if ( !asize )
+ return FT_Err_Invalid_Size_Handle;
+
+ if ( !face->driver )
+ return FT_Err_Invalid_Driver_Handle;
+
+ *asize = 0;
+
+ driver = face->driver;
+ clazz = driver->clazz;
+ memory = face->memory;
+
+ /* Allocate new size object and perform basic initialisation */
+ if ( FT_ALLOC( size, clazz->size_object_size ) || FT_NEW( node ) )
+ goto Exit;
+
+ size->face = face;
+
+ /* for now, do not use any internal fields in size objects */
+ size->internal = 0;
+
+ if ( clazz->init_size )
+ error = clazz->init_size( size );
+
+ /* in case of success, add to the face's list */
+ if ( !error )
+ {
+ *asize = size;
+ node->data = size;
+ FT_List_Add( &face->sizes_list, node );
+ }
+
+ Exit:
+ if ( error )
+ {
+ FT_FREE( node );
+ FT_FREE( size );
+ }
+
+ return error;
+ }
+
+
+ /* documentation is in ftobjs.h */
+
+ FT_EXPORT_DEF( FT_Error )
+ FT_Done_Size( FT_Size size )
+ {
+ FT_Error error;
+ FT_Driver driver;
+ FT_Memory memory;
+ FT_Face face;
+ FT_ListNode node;
+
+
+ if ( !size )
+ return FT_Err_Invalid_Size_Handle;
+
+ face = size->face;
+ if ( !face )
+ return FT_Err_Invalid_Face_Handle;
+
+ driver = face->driver;
+ if ( !driver )
+ return FT_Err_Invalid_Driver_Handle;
+
+ memory = driver->root.memory;
+
+ error = FT_Err_Ok;
+ node = FT_List_Find( &face->sizes_list, size );
+ if ( node )
+ {
+ FT_List_Remove( &face->sizes_list, node );
+ FT_FREE( node );
+
+ if ( face->size == size )
+ {
+ face->size = 0;
+ if ( face->sizes_list.head )
+ face->size = (FT_Size)(face->sizes_list.head->data);
+ }
+
+ destroy_size( memory, size, driver );
+ }
+ else
+ error = FT_Err_Invalid_Size_Handle;
+
+ return error;
+ }
+
+
+ static void
+ ft_recompute_scaled_metrics( FT_Face face,
+ FT_Size_Metrics* metrics )
+ {
+ /* Compute root ascender, descender, test height, and max_advance */
+
+ metrics->ascender = ( FT_MulFix( face->ascender,
+ metrics->y_scale ) + 32 ) & -64;
+
+ metrics->descender = ( FT_MulFix( face->descender,
+ metrics->y_scale ) + 32 ) & -64;
+
+ metrics->height = ( FT_MulFix( face->height,
+ metrics->y_scale ) + 32 ) & -64;
+
+ metrics->max_advance = ( FT_MulFix( face->max_advance_width,
+ metrics->x_scale ) + 32 ) & -64;
+ }
+
+
+ /* documentation is in freetype.h */
+
+ FT_EXPORT_DEF( FT_Error )
+ FT_Set_Char_Size( FT_Face face,
+ FT_F26Dot6 char_width,
+ FT_F26Dot6 char_height,
+ FT_UInt horz_resolution,
+ FT_UInt vert_resolution )
+ {
+ FT_Error error = FT_Err_Ok;
+ FT_Driver driver;
+ FT_Driver_Class clazz;
+ FT_Size_Metrics* metrics;
+ FT_Long dim_x, dim_y;
+
+
+ if ( !face || !face->size || !face->driver )
+ return FT_Err_Invalid_Face_Handle;
+
+ driver = face->driver;
+ metrics = &face->size->metrics;
+
+ if ( !char_width )
+ char_width = char_height;
+
+ else if ( !char_height )
+ char_height = char_width;
+
+ if ( !horz_resolution )
+ horz_resolution = 72;
+
+ if ( !vert_resolution )
+ vert_resolution = 72;
+
+ driver = face->driver;
+ clazz = driver->clazz;
+
+ /* default processing -- this can be overridden by the driver */
+ if ( char_width < 1 * 64 )
+ char_width = 1 * 64;
+ if ( char_height < 1 * 64 )
+ char_height = 1 * 64;
+
+ /* Compute pixel sizes in 26.6 units */
+ dim_x = ( ( ( char_width * horz_resolution ) / 72 ) + 32 ) & -64;
+ dim_y = ( ( ( char_height * vert_resolution ) / 72 ) + 32 ) & -64;
+
+ metrics->x_ppem = (FT_UShort)( dim_x >> 6 );
+ metrics->y_ppem = (FT_UShort)( dim_y >> 6 );
+
+ metrics->x_scale = 0x10000L;
+ metrics->y_scale = 0x10000L;
+
+ if ( face->face_flags & FT_FACE_FLAG_SCALABLE )
+ {
+ metrics->x_scale = FT_DivFix( dim_x, face->units_per_EM );
+ metrics->y_scale = FT_DivFix( dim_y, face->units_per_EM );
+
+ ft_recompute_scaled_metrics( face, metrics );
+ }
+
+ if ( clazz->set_char_sizes )
+ error = clazz->set_char_sizes( face->size,
+ char_width,
+ char_height,
+ horz_resolution,
+ vert_resolution );
+ return error;
+ }
+
+
+ /* documentation is in freetype.h */
+
+ FT_EXPORT_DEF( FT_Error )
+ FT_Set_Pixel_Sizes( FT_Face face,
+ FT_UInt pixel_width,
+ FT_UInt pixel_height )
+ {
+ FT_Error error = FT_Err_Ok;
+ FT_Driver driver;
+ FT_Driver_Class clazz;
+ FT_Size_Metrics* metrics = &face->size->metrics;
+
+
+ if ( !face || !face->size || !face->driver )
+ return FT_Err_Invalid_Face_Handle;
+
+ driver = face->driver;
+ clazz = driver->clazz;
+
+ /* default processing -- this can be overridden by the driver */
+ if ( pixel_width == 0 )
+ pixel_width = pixel_height;
+
+ else if ( pixel_height == 0 )
+ pixel_height = pixel_width;
+
+ if ( pixel_width < 1 )
+ pixel_width = 1;
+ if ( pixel_height < 1 )
+ pixel_height = 1;
+
+ metrics->x_ppem = (FT_UShort)pixel_width;
+ metrics->y_ppem = (FT_UShort)pixel_height;
+
+ if ( face->face_flags & FT_FACE_FLAG_SCALABLE )
+ {
+ metrics->x_scale = FT_DivFix( metrics->x_ppem << 6,
+ face->units_per_EM );
+
+ metrics->y_scale = FT_DivFix( metrics->y_ppem << 6,
+ face->units_per_EM );
+
+ ft_recompute_scaled_metrics( face, metrics );
+ }
+
+ if ( clazz->set_pixel_sizes )
+ error = clazz->set_pixel_sizes( face->size,
+ pixel_width,
+ pixel_height );
+ return error;
+ }
+
+
+ /* documentation is in freetype.h */
+
+ FT_EXPORT_DEF( FT_Error )
+ FT_Get_Kerning( FT_Face face,
+ FT_UInt left_glyph,
+ FT_UInt right_glyph,
+ FT_UInt kern_mode,
+ FT_Vector *akerning )
+ {
+ FT_Error error = FT_Err_Ok;
+ FT_Driver driver;
+
+
+ if ( !face )
+ return FT_Err_Invalid_Face_Handle;
+
+ if ( !akerning )
+ return FT_Err_Invalid_Argument;
+
+ driver = face->driver;
+
+ akerning->x = 0;
+ akerning->y = 0;
+
+ if ( driver->clazz->get_kerning )
+ {
+ error = driver->clazz->get_kerning( face,
+ left_glyph,
+ right_glyph,
+ akerning );
+ if ( !error )
+ {
+ if ( kern_mode != FT_KERNING_UNSCALED )
+ {
+ akerning->x = FT_MulFix( akerning->x, face->size->metrics.x_scale );
+ akerning->y = FT_MulFix( akerning->y, face->size->metrics.y_scale );
+
+ if ( kern_mode != FT_KERNING_UNFITTED )
+ {
+ akerning->x = ( akerning->x + 32 ) & -64;
+ akerning->y = ( akerning->y + 32 ) & -64;
+ }
+ }
+ }
+ }
+
+ return error;
+ }
+
+
+ /* documentation is in freetype.h */
+
+ FT_EXPORT_DEF( FT_Error )
+ FT_Select_Charmap( FT_Face face,
+ FT_Encoding encoding )
+ {
+ FT_CharMap* cur;
+ FT_CharMap* limit;
+
+
+ if ( !face )
+ return FT_Err_Invalid_Face_Handle;
+
+ cur = face->charmaps;
+ if ( !cur )
+ return FT_Err_Invalid_CharMap_Handle;
+
+ limit = cur + face->num_charmaps;
+
+ for ( ; cur < limit; cur++ )
+ {
+ if ( cur[0]->encoding == encoding )
+ {
+ face->charmap = cur[0];
+ return 0;
+ }
+ }
+
+ return FT_Err_Invalid_Argument;
+ }
+
+
+ /* documentation is in freetype.h */
+
+ FT_EXPORT_DEF( FT_Error )
+ FT_Set_Charmap( FT_Face face,
+ FT_CharMap charmap )
+ {
+ FT_CharMap* cur;
+ FT_CharMap* limit;
+
+
+ if ( !face )
+ return FT_Err_Invalid_Face_Handle;
+
+ cur = face->charmaps;
+ if ( !cur )
+ return FT_Err_Invalid_CharMap_Handle;
+
+ limit = cur + face->num_charmaps;
+
+ for ( ; cur < limit; cur++ )
+ {
+ if ( cur[0] == charmap )
+ {
+ face->charmap = cur[0];
+ return 0;
+ }
+ }
+ return FT_Err_Invalid_Argument;
+ }
+
+
+ FT_BASE_DEF( void )
+ FT_CMap_Done( FT_CMap cmap )
+ {
+ if ( cmap )
+ {
+ FT_CMap_Class clazz = cmap->clazz;
+ FT_Face face = cmap->charmap.face;
+ FT_Memory memory = FT_FACE_MEMORY(face);
+
+
+ if ( clazz->done )
+ clazz->done( cmap );
+
+ FT_FREE( cmap );
+ }
+ }
+
+
+ FT_BASE_DEF( FT_Error )
+ FT_CMap_New( FT_CMap_Class clazz,
+ FT_Pointer init_data,
+ FT_CharMap charmap,
+ FT_CMap *acmap )
+ {
+ FT_Error error = 0;
+ FT_Face face;
+ FT_Memory memory;
+ FT_CMap cmap;
+
+
+ if ( clazz == NULL || charmap == NULL || charmap->face == NULL )
+ return FT_Err_Invalid_Argument;
+
+ face = charmap->face;
+ memory = FT_FACE_MEMORY(face);
+
+ if ( !FT_ALLOC( cmap, clazz->size ) )
+ {
+ cmap->charmap = *charmap;
+ cmap->clazz = clazz;
+
+ if ( clazz->init )
+ {
+ error = clazz->init( cmap, init_data );
+ if ( error )
+ goto Fail;
+ }
+
+ /* add it to our list of charmaps */
+ if ( FT_RENEW_ARRAY( face->charmaps,
+ face->num_charmaps,
+ face->num_charmaps+1 ) )
+ goto Fail;
+
+ face->charmaps[face->num_charmaps++] = (FT_CharMap)cmap;
+ }
+
+ Exit:
+ if ( acmap )
+ *acmap = cmap;
+
+ return error;
+
+ Fail:
+ FT_CMap_Done( cmap );
+ cmap = NULL;
+ goto Exit;
+ }
+
+
+ /* documentation is in freetype.h */
+
+ FT_EXPORT_DEF( FT_UInt )
+ FT_Get_Char_Index( FT_Face face,
+ FT_ULong charcode )
+ {
+ FT_UInt result = 0;
+
+
+ if ( face && face->charmap )
+ {
+ FT_CMap cmap = FT_CMAP( face->charmap );
+
+
+ result = cmap->clazz->char_index( cmap, charcode );
+ }
+ return result;
+ }
+
+
+
+ /* documentation is in freetype.h */
+
+ FT_EXPORT_DEF( FT_ULong )
+ FT_Get_First_Char( FT_Face face,
+ FT_UInt *agindex )
+ {
+ FT_ULong result = 0;
+ FT_UInt gindex = 0;
+
+
+ if ( face && face->charmap )
+ {
+ gindex = FT_Get_Char_Index( face, 0 );
+ if ( gindex == 0 )
+ result = FT_Get_Next_Char( face, 0, &gindex );
+ }
+
+ if ( agindex )
+ *agindex = gindex;
+
+ return result;
+ }
+
+ /* documentation is in freetype.h */
+
+
+ FT_EXPORT_DEF( FT_ULong )
+ FT_Get_Next_Char( FT_Face face,
+ FT_ULong charcode,
+ FT_UInt *agindex )
+ {
+ FT_ULong result = 0;
+ FT_UInt gindex = 0;
+
+
+ if ( face && face->charmap )
+ {
+ FT_UInt32 code = (FT_UInt32)charcode;
+ FT_CMap cmap = FT_CMAP( face->charmap );
+
+
+ gindex = cmap->clazz->char_next( cmap, &code );
+ result = ( gindex == 0 ) ? 0 : code;
+ }
+
+ if ( agindex )
+ *agindex = gindex;
+
+ return result;
+ }
+
+
+
+ /* documentation is in freetype.h */
+
+ FT_EXPORT_DEF( FT_UInt )
+ FT_Get_Name_Index( FT_Face face,
+ FT_String* glyph_name )
+ {
+ FT_UInt result = 0;
+
+
+ if ( face && FT_HAS_GLYPH_NAMES( face ) )
+ {
+ /* now, lookup for glyph name */
+ FT_Driver driver = face->driver;
+ FT_Module_Class* clazz = FT_MODULE_CLASS( driver );
+
+
+ if ( clazz->get_interface )
+ {
+ FT_Face_GetGlyphNameIndexFunc requester;
+
+
+ requester = (FT_Face_GetGlyphNameIndexFunc)clazz->get_interface(
+ FT_MODULE( driver ), "name_index" );
+ if ( requester )
+ result = requester( face, glyph_name );
+ }
+ }
+
+ return result;
+ }
+
+
+ /* documentation is in freetype.h */
+
+ FT_EXPORT_DEF( FT_Error )
+ FT_Get_Glyph_Name( FT_Face face,
+ FT_UInt glyph_index,
+ FT_Pointer buffer,
+ FT_UInt buffer_max )
+ {
+ FT_Error error = FT_Err_Invalid_Argument;
+
+
+ /* clean up buffer */
+ if ( buffer && buffer_max > 0 )
+ ((FT_Byte*)buffer)[0] = 0;
+
+ if ( face &&
+ glyph_index <= (FT_UInt)face->num_glyphs &&
+ FT_HAS_GLYPH_NAMES( face ) )
+ {
+ /* now, lookup for glyph name */
+ FT_Driver driver = face->driver;
+ FT_Module_Class* clazz = FT_MODULE_CLASS( driver );
+
+
+ if ( clazz->get_interface )
+ {
+ FT_Face_GetGlyphNameFunc requester;
+
+
+ requester = (FT_Face_GetGlyphNameFunc)clazz->get_interface(
+ FT_MODULE( driver ), "glyph_name" );
+ if ( requester )
+ error = requester( face, glyph_index, buffer, buffer_max );
+ }
+ }
+
+ return error;
+ }
+
+
+ /* documentation is in freetype.h */
+
+ FT_EXPORT_DEF( const char* )
+ FT_Get_Postscript_Name( FT_Face face )
+ {
+ const char* result = NULL;
+
+
+ if ( !face )
+ goto Exit;
+
+ result = face->internal->postscript_name;
+ if ( !result )
+ {
+ /* now, look up glyph name */
+ FT_Driver driver = face->driver;
+ FT_Module_Class* clazz = FT_MODULE_CLASS( driver );
+
+
+ if ( clazz->get_interface )
+ {
+ FT_Face_GetPostscriptNameFunc requester;
+
+
+ requester = (FT_Face_GetPostscriptNameFunc)clazz->get_interface(
+ FT_MODULE( driver ), "postscript_name" );
+ if ( requester )
+ result = requester( face );
+ }
+ }
+ Exit:
+ return result;
+ }
+
+
+ /* documentation is in tttables.h */
+
+ FT_EXPORT_DEF( void* )
+ FT_Get_Sfnt_Table( FT_Face face,
+ FT_Sfnt_Tag tag )
+ {
+ void* table = 0;
+ FT_Get_Sfnt_Table_Func func;
+ FT_Driver driver;
+
+
+ if ( !face || !FT_IS_SFNT( face ) )
+ goto Exit;
+
+ driver = face->driver;
+ func = (FT_Get_Sfnt_Table_Func)driver->root.clazz->get_interface(
+ FT_MODULE( driver ), "get_sfnt" );
+ if ( func )
+ table = func( face, tag );
+
+ Exit:
+ return table;
+ }
+
+
+ FT_EXPORT_DEF( FT_Error )
+ FT_Activate_Size( FT_Size size )
+ {
+ FT_Face face;
+
+
+ if ( size == NULL )
+ return FT_Err_Bad_Argument;
+
+ face = size->face;
+ if ( face == NULL || face->driver == NULL )
+ return FT_Err_Bad_Argument;
+
+ /* we don't need anything more complex than that; all size objects */
+ /* are already listed by the face */
+ face->size = size;
+
+ return FT_Err_Ok;
+ }
+
+
+ /*************************************************************************/
+ /*************************************************************************/
+ /*************************************************************************/
+ /**** ****/
+ /**** ****/
+ /**** R E N D E R E R S ****/
+ /**** ****/
+ /**** ****/
+ /*************************************************************************/
+ /*************************************************************************/
+ /*************************************************************************/
+
+ /* lookup a renderer by glyph format in the library's list */
+ FT_BASE_DEF( FT_Renderer )
+ FT_Lookup_Renderer( FT_Library library,
+ FT_Glyph_Format format,
+ FT_ListNode* node )
+ {
+ FT_ListNode cur;
+ FT_Renderer result = 0;
+
+
+ if ( !library )
+ goto Exit;
+
+ cur = library->renderers.head;
+
+ if ( node )
+ {
+ if ( *node )
+ cur = (*node)->next;
+ *node = 0;
+ }
+
+ while ( cur )
+ {
+ FT_Renderer renderer = FT_RENDERER( cur->data );
+
+
+ if ( renderer->glyph_format == format )
+ {
+ if ( node )
+ *node = cur;
+
+ result = renderer;
+ break;
+ }
+ cur = cur->next;
+ }
+
+ Exit:
+ return result;
+ }
+
+
+ static FT_Renderer
+ ft_lookup_glyph_renderer( FT_GlyphSlot slot )
+ {
+ FT_Face face = slot->face;
+ FT_Library library = FT_FACE_LIBRARY( face );
+ FT_Renderer result = library->cur_renderer;
+
+
+ if ( !result || result->glyph_format != slot->format )
+ result = FT_Lookup_Renderer( library, slot->format, 0 );
+
+ return result;
+ }
+
+
+ static void
+ ft_set_current_renderer( FT_Library library )
+ {
+ FT_Renderer renderer;
+
+
+ renderer = FT_Lookup_Renderer( library, FT_GLYPH_FORMAT_OUTLINE, 0 );
+ library->cur_renderer = renderer;
+ }
+
+
+ static FT_Error
+ ft_add_renderer( FT_Module module )
+ {
+ FT_Library library = module->library;
+ FT_Memory memory = library->memory;
+ FT_Error error;
+ FT_ListNode node;
+
+
+ if ( FT_NEW( node ) )
+ goto Exit;
+
+ {
+ FT_Renderer render = FT_RENDERER( module );
+ FT_Renderer_Class* clazz = (FT_Renderer_Class*)module->clazz;
+
+
+ render->clazz = clazz;
+ render->glyph_format = clazz->glyph_format;
+
+ /* allocate raster object if needed */
+ if ( clazz->glyph_format == FT_GLYPH_FORMAT_OUTLINE &&
+ clazz->raster_class->raster_new )
+ {
+ error = clazz->raster_class->raster_new( memory, &render->raster );
+ if ( error )
+ goto Fail;
+
+ render->raster_render = clazz->raster_class->raster_render;
+ render->render = clazz->render_glyph;
+ }
+
+ /* add to list */
+ node->data = module;
+ FT_List_Add( &library->renderers, node );
+
+ ft_set_current_renderer( library );
+ }
+
+ Fail:
+ if ( error )
+ FT_FREE( node );
+
+ Exit:
+ return error;
+ }
+
+
+ static void
+ ft_remove_renderer( FT_Module module )
+ {
+ FT_Library library = module->library;
+ FT_Memory memory = library->memory;
+ FT_ListNode node;
+
+
+ node = FT_List_Find( &library->renderers, module );
+ if ( node )
+ {
+ FT_Renderer render = FT_RENDERER( module );
+
+
+ /* release raster object, if any */
+ if ( render->raster )
+ render->clazz->raster_class->raster_done( render->raster );
+
+ /* remove from list */
+ FT_List_Remove( &library->renderers, node );
+ FT_FREE( node );
+
+ ft_set_current_renderer( library );
+ }
+ }
+
+
+ /* documentation is in ftrender.h */
+
+ FT_EXPORT_DEF( FT_Renderer )
+ FT_Get_Renderer( FT_Library library,
+ FT_Glyph_Format format )
+ {
+ /* test for valid `library' delayed to FT_Lookup_Renderer() */
+
+ return FT_Lookup_Renderer( library, format, 0 );
+ }
+
+
+ /* documentation is in ftrender.h */
+
+ FT_EXPORT_DEF( FT_Error )
+ FT_Set_Renderer( FT_Library library,
+ FT_Renderer renderer,
+ FT_UInt num_params,
+ FT_Parameter* parameters )
+ {
+ FT_ListNode node;
+ FT_Error error = FT_Err_Ok;
+
+
+ if ( !library )
+ return FT_Err_Invalid_Library_Handle;
+
+ if ( !renderer )
+ return FT_Err_Invalid_Argument;
+
+ node = FT_List_Find( &library->renderers, renderer );
+ if ( !node )
+ {
+ error = FT_Err_Invalid_Argument;
+ goto Exit;
+ }
+
+ FT_List_Up( &library->renderers, node );
+
+ if ( renderer->glyph_format == FT_GLYPH_FORMAT_OUTLINE )
+ library->cur_renderer = renderer;
+
+ if ( num_params > 0 )
+ {
+ FT_Renderer_SetModeFunc set_mode = renderer->clazz->set_mode;
+
+
+ for ( ; num_params > 0; num_params-- )
+ {
+ error = set_mode( renderer, parameters->tag, parameters->data );
+ if ( error )
+ break;
+ }
+ }
+
+ Exit:
+ return error;
+ }
+
+
+ FT_BASE_DEF( FT_Error )
+ FT_Render_Glyph_Internal( FT_Library library,
+ FT_GlyphSlot slot,
+ FT_Render_Mode render_mode )
+ {
+ FT_Error error = FT_Err_Ok;
+ FT_Renderer renderer;
+
+
+ /* if it is already a bitmap, no need to do anything */
+ switch ( slot->format )
+ {
+ case FT_GLYPH_FORMAT_BITMAP: /* already a bitmap, don't do anything */
+ break;
+
+ default:
+ {
+ FT_ListNode node = 0;
+ FT_Bool update = 0;
+
+
+ /* small shortcut for the very common case */
+ if ( slot->format == FT_GLYPH_FORMAT_OUTLINE )
+ {
+ renderer = library->cur_renderer;
+ node = library->renderers.head;
+ }
+ else
+ renderer = FT_Lookup_Renderer( library, slot->format, &node );
+
+ error = FT_Err_Unimplemented_Feature;
+ while ( renderer )
+ {
+ error = renderer->render( renderer, slot, render_mode, NULL );
+ if ( !error ||
+ FT_ERROR_BASE( error ) != FT_Err_Cannot_Render_Glyph )
+ break;
+
+ /* FT_Err_Cannot_Render_Glyph is returned if the render mode */
+ /* is unsupported by the current renderer for this glyph image */
+ /* format. */
+
+ /* now, look for another renderer that supports the same */
+ /* format. */
+ renderer = FT_Lookup_Renderer( library, slot->format, &node );
+ update = 1;
+ }
+
+ /* if we changed the current renderer for the glyph image format */
+ /* we need to select it as the next current one */
+ if ( !error && update && renderer )
+ FT_Set_Renderer( library, renderer, 0, 0 );
+ }
+ }
+
+ return error;
+ }
+
+
+ /* documentation is in freetype.h */
+
+ FT_EXPORT_DEF( FT_Error )
+ FT_Render_Glyph( FT_GlyphSlot slot,
+ FT_Render_Mode render_mode )
+ {
+ FT_Library library;
+
+
+ if ( !slot )
+ return FT_Err_Invalid_Argument;
+
+ library = FT_FACE_LIBRARY( slot->face );
+
+ return FT_Render_Glyph_Internal( library, slot, render_mode );
+ }
+
+
+ /*************************************************************************/
+ /*************************************************************************/
+ /*************************************************************************/
+ /**** ****/
+ /**** ****/
+ /**** M O D U L E S ****/
+ /**** ****/
+ /**** ****/
+ /*************************************************************************/
+ /*************************************************************************/
+ /*************************************************************************/
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* Destroy_Module */
+ /* */
+ /* <Description> */
+ /* Destroys a given module object. For drivers, this also destroys */
+ /* all child faces. */
+ /* */
+ /* <InOut> */
+ /* module :: A handle to the target driver object. */
+ /* */
+ /* <Note> */
+ /* The driver _must_ be LOCKED! */
+ /* */
+ static void
+ Destroy_Module( FT_Module module )
+ {
+ FT_Memory memory = module->memory;
+ FT_Module_Class* clazz = module->clazz;
+ FT_Library library = module->library;
+
+
+ /* finalize client-data - before anything else */
+ if ( module->generic.finalizer )
+ module->generic.finalizer( module );
+
+ if ( library && library->auto_hinter == module )
+ library->auto_hinter = 0;
+
+ /* if the module is a renderer */
+ if ( FT_MODULE_IS_RENDERER( module ) )
+ ft_remove_renderer( module );
+
+ /* if the module is a font driver, add some steps */
+ if ( FT_MODULE_IS_DRIVER( module ) )
+ Destroy_Driver( FT_DRIVER( module ) );
+
+ /* finalize the module object */
+ if ( clazz->module_done )
+ clazz->module_done( module );
+
+ /* discard it */
+ FT_FREE( module );
+ }
+
+
+ /* documentation is in ftmodule.h */
+
+ FT_EXPORT_DEF( FT_Error )
+ FT_Add_Module( FT_Library library,
+ const FT_Module_Class* clazz )
+ {
+ FT_Error error;
+ FT_Memory memory;
+ FT_Module module;
+ FT_UInt nn;
+
+
+#define FREETYPE_VER_FIXED ( ( (FT_Long)FREETYPE_MAJOR << 16 ) | \
+ FREETYPE_MINOR )
+
+ if ( !library )
+ return FT_Err_Invalid_Library_Handle;
+
+ if ( !clazz )
+ return FT_Err_Invalid_Argument;
+
+ /* check freetype version */
+ if ( clazz->module_requires > FREETYPE_VER_FIXED )
+ return FT_Err_Invalid_Version;
+
+ /* look for a module with the same name in the library's table */
+ for ( nn = 0; nn < library->num_modules; nn++ )
+ {
+ module = library->modules[nn];
+ if ( ft_strcmp( module->clazz->module_name, clazz->module_name ) == 0 )
+ {
+ /* this installed module has the same name, compare their versions */
+ if ( clazz->module_version <= module->clazz->module_version )
+ return FT_Err_Lower_Module_Version;
+
+ /* remove the module from our list, then exit the loop to replace */
+ /* it by our new version.. */
+ FT_Remove_Module( library, module );
+ break;
+ }
+ }
+
+ memory = library->memory;
+ error = FT_Err_Ok;
+
+ if ( library->num_modules >= FT_MAX_MODULES )
+ {
+ error = FT_Err_Too_Many_Drivers;
+ goto Exit;
+ }
+
+ /* allocate module object */
+ if ( FT_ALLOC( module, clazz->module_size ) )
+ goto Exit;
+
+ /* base initialization */
+ module->library = library;
+ module->memory = memory;
+ module->clazz = (FT_Module_Class*)clazz;
+
+ /* check whether the module is a renderer - this must be performed */
+ /* before the normal module initialization */
+ if ( FT_MODULE_IS_RENDERER( module ) )
+ {
+ /* add to the renderers list */
+ error = ft_add_renderer( module );
+ if ( error )
+ goto Fail;
+ }
+
+ /* is the module a auto-hinter? */
+ if ( FT_MODULE_IS_HINTER( module ) )
+ library->auto_hinter = module;
+
+ /* if the module is a font driver */
+ if ( FT_MODULE_IS_DRIVER( module ) )
+ {
+ /* allocate glyph loader if needed */
+ FT_Driver driver = FT_DRIVER( module );
+
+
+ driver->clazz = (FT_Driver_Class)module->clazz;
+ if ( FT_DRIVER_USES_OUTLINES( driver ) )
+ {
+ error = FT_GlyphLoader_New( memory, &driver->glyph_loader );
+ if ( error )
+ goto Fail;
+ }
+ }
+
+ if ( clazz->module_init )
+ {
+ error = clazz->module_init( module );
+ if ( error )
+ goto Fail;
+ }
+
+ /* add module to the library's table */
+ library->modules[library->num_modules++] = module;
+
+ Exit:
+ return error;
+
+ Fail:
+ if ( FT_MODULE_IS_DRIVER( module ) )
+ {
+ FT_Driver driver = FT_DRIVER( module );
+
+
+ if ( FT_DRIVER_USES_OUTLINES( driver ) )
+ FT_GlyphLoader_Done( driver->glyph_loader );
+ }
+
+ if ( FT_MODULE_IS_RENDERER( module ) )
+ {
+ FT_Renderer renderer = FT_RENDERER( module );
+
+
+ if ( renderer->raster )
+ renderer->clazz->raster_class->raster_done( renderer->raster );
+ }
+
+ FT_FREE( module );
+ goto Exit;
+ }
+
+
+ /* documentation is in ftmodule.h */
+
+ FT_EXPORT_DEF( FT_Module )
+ FT_Get_Module( FT_Library library,
+ const char* module_name )
+ {
+ FT_Module result = 0;
+ FT_Module* cur;
+ FT_Module* limit;
+
+
+ if ( !library || !module_name )
+ return result;
+
+ cur = library->modules;
+ limit = cur + library->num_modules;
+
+ for ( ; cur < limit; cur++ )
+ if ( ft_strcmp( cur[0]->clazz->module_name, module_name ) == 0 )
+ {
+ result = cur[0];
+ break;
+ }
+
+ return result;
+ }
+
+
+ /* documentation is in ftobjs.h */
+
+ FT_BASE_DEF( const void* )
+ FT_Get_Module_Interface( FT_Library library,
+ const char* mod_name )
+ {
+ FT_Module module;
+
+
+ /* test for valid `library' delayed to FT_Get_Module() */
+
+ module = FT_Get_Module( library, mod_name );
+
+ return module ? module->clazz->module_interface : 0;
+ }
+
+
+ /* documentation is in ftmodule.h */
+
+ FT_EXPORT_DEF( FT_Error )
+ FT_Remove_Module( FT_Library library,
+ FT_Module module )
+ {
+ /* try to find the module from the table, then remove it from there */
+
+ if ( !library )
+ return FT_Err_Invalid_Library_Handle;
+
+ if ( module )
+ {
+ FT_Module* cur = library->modules;
+ FT_Module* limit = cur + library->num_modules;
+
+
+ for ( ; cur < limit; cur++ )
+ {
+ if ( cur[0] == module )
+ {
+ /* remove it from the table */
+ library->num_modules--;
+ limit--;
+ while ( cur < limit )
+ {
+ cur[0] = cur[1];
+ cur++;
+ }
+ limit[0] = 0;
+
+ /* destroy the module */
+ Destroy_Module( module );
+
+ return FT_Err_Ok;
+ }
+ }
+ }
+ return FT_Err_Invalid_Driver_Handle;
+ }
+
+
+ /*************************************************************************/
+ /*************************************************************************/
+ /*************************************************************************/
+ /**** ****/
+ /**** ****/
+ /**** L I B R A R Y ****/
+ /**** ****/
+ /**** ****/
+ /*************************************************************************/
+ /*************************************************************************/
+ /*************************************************************************/
+
+
+ /* documentation is in ftmodule.h */
+
+ FT_EXPORT_DEF( FT_Error )
+ FT_New_Library( FT_Memory memory,
+ FT_Library *alibrary )
+ {
+ FT_Library library = 0;
+ FT_Error error;
+
+
+ if ( !memory )
+ return FT_Err_Invalid_Argument;
+
+#ifdef FT_DEBUG_LEVEL_ERROR
+ /* init debugging support */
+ ft_debug_init();
+#endif
+
+ /* first of all, allocate the library object */
+ if ( FT_NEW( library ) )
+ return error;
+
+ library->memory = memory;
+
+ /* allocate the render pool */
+ library->raster_pool_size = FT_RENDER_POOL_SIZE;
+ if ( FT_ALLOC( library->raster_pool, FT_RENDER_POOL_SIZE ) )
+ goto Fail;
+
+ /* That's ok now */
+ *alibrary = library;
+
+ return FT_Err_Ok;
+
+ Fail:
+ FT_FREE( library );
+ return error;
+ }
+
+
+ /* documentation is in freetype.h */
+
+ FT_EXPORT_DEF( void )
+ FT_Library_Version( FT_Library library,
+ FT_Int *amajor,
+ FT_Int *aminor,
+ FT_Int *apatch )
+ {
+ FT_Int major = 0;
+ FT_Int minor = 0;
+ FT_Int patch = 0;
+
+
+ if ( library )
+ {
+ major = library->version_major;
+ minor = library->version_minor;
+ patch = library->version_patch;
+ }
+
+ if ( amajor )
+ *amajor = major;
+
+ if ( aminor )
+ *aminor = minor;
+
+ if ( apatch )
+ *apatch = patch;
+ }
+
+
+ /* documentation is in ftmodule.h */
+
+ FT_EXPORT_DEF( FT_Error )
+ FT_Done_Library( FT_Library library )
+ {
+ FT_Memory memory;
+
+
+ if ( !library )
+ return FT_Err_Invalid_Library_Handle;
+
+ memory = library->memory;
+
+ /* Discard client-data */
+ if ( library->generic.finalizer )
+ library->generic.finalizer( library );
+
+ /* Close all modules in the library */
+#if 1
+ while ( library->num_modules > 0 )
+ FT_Remove_Module( library, library->modules[0] );
+#else
+ {
+ FT_UInt n;
+
+
+ for ( n = 0; n < library->num_modules; n++ )
+ {
+ FT_Module module = library->modules[n];
+
+
+ if ( module )
+ {
+ Destroy_Module( module );
+ library->modules[n] = 0;
+ }
+ }
+ }
+#endif
+
+ /* Destroy raster objects */
+ FT_FREE( library->raster_pool );
+ library->raster_pool_size = 0;
+
+ FT_FREE( library );
+ return FT_Err_Ok;
+ }
+
+
+ /* documentation is in ftmodule.h */
+
+ FT_EXPORT_DEF( void )
+ FT_Set_Debug_Hook( FT_Library library,
+ FT_UInt hook_index,
+ FT_DebugHook_Func debug_hook )
+ {
+ if ( library && debug_hook &&
+ hook_index <
+ ( sizeof ( library->debug_hooks ) / sizeof ( void* ) ) )
+ library->debug_hooks[hook_index] = debug_hook;
+ }
+
+
+/* END */
--- /dev/null
+++ b/libfreetype/ftoutln.c
@@ -1,0 +1,658 @@
+/***************************************************************************/
+/* */
+/* ftoutln.c */
+/* */
+/* FreeType outline management (body). */
+/* */
+/* Copyright 1996-2001, 2002 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+
+ /*************************************************************************/
+ /* */
+ /* All functions are declared in freetype.h. */
+ /* */
+ /*************************************************************************/
+
+
+#include <ft2build.h>
+#include FT_OUTLINE_H
+#include FT_INTERNAL_OBJECTS_H
+
+
+ /*************************************************************************/
+ /* */
+ /* The macro FT_COMPONENT is used in trace mode. It is an implicit */
+ /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log */
+ /* messages during execution. */
+ /* */
+#undef FT_COMPONENT
+#define FT_COMPONENT trace_outline
+
+
+ static
+ const FT_Outline null_outline = { 0, 0, 0, 0, 0, 0 };
+
+
+ /* documentation is in ftoutln.h */
+
+ FT_EXPORT_DEF( FT_Error )
+ FT_Outline_Decompose( FT_Outline* outline,
+ const FT_Outline_Funcs* func_interface,
+ void* user )
+ {
+#undef SCALED
+#define SCALED( x ) ( ( (x) << shift ) - delta )
+
+ FT_Vector v_last;
+ FT_Vector v_control;
+ FT_Vector v_start;
+
+ FT_Vector* point;
+ FT_Vector* limit;
+ char* tags;
+
+ FT_Error error;
+
+ FT_Int n; /* index of contour in outline */
+ FT_UInt first; /* index of first point in contour */
+ FT_Int tag; /* current point's state */
+
+ FT_Int shift;
+ FT_Pos delta;
+
+
+ if ( !outline || !func_interface )
+ return FT_Err_Invalid_Argument;
+
+ shift = func_interface->shift;
+ delta = func_interface->delta;
+ first = 0;
+
+ for ( n = 0; n < outline->n_contours; n++ )
+ {
+ FT_Int last; /* index of last point in contour */
+
+
+ last = outline->contours[n];
+ limit = outline->points + last;
+
+ v_start = outline->points[first];
+ v_last = outline->points[last];
+
+ v_start.x = SCALED( v_start.x ); v_start.y = SCALED( v_start.y );
+ v_last.x = SCALED( v_last.x ); v_last.y = SCALED( v_last.y );
+
+ v_control = v_start;
+
+ point = outline->points + first;
+ tags = outline->tags + first;
+ tag = FT_CURVE_TAG( tags[0] );
+
+ /* A contour cannot start with a cubic control point! */
+ if ( tag == FT_CURVE_TAG_CUBIC )
+ goto Invalid_Outline;
+
+ /* check first point to determine origin */
+ if ( tag == FT_CURVE_TAG_CONIC )
+ {
+ /* first point is conic control. Yes, this happens. */
+ if ( FT_CURVE_TAG( outline->tags[last] ) == FT_CURVE_TAG_ON )
+ {
+ /* start at last point if it is on the curve */
+ v_start = v_last;
+ limit--;
+ }
+ else
+ {
+ /* if both first and last points are conic, */
+ /* start at their middle and record its position */
+ /* for closure */
+ v_start.x = ( v_start.x + v_last.x ) / 2;
+ v_start.y = ( v_start.y + v_last.y ) / 2;
+
+ v_last = v_start;
+ }
+ point--;
+ tags--;
+ }
+
+ error = func_interface->move_to( &v_start, user );
+ if ( error )
+ goto Exit;
+
+ while ( point < limit )
+ {
+ point++;
+ tags++;
+
+ tag = FT_CURVE_TAG( tags[0] );
+ switch ( tag )
+ {
+ case FT_CURVE_TAG_ON: /* emit a single line_to */
+ {
+ FT_Vector vec;
+
+
+ vec.x = SCALED( point->x );
+ vec.y = SCALED( point->y );
+
+ error = func_interface->line_to( &vec, user );
+ if ( error )
+ goto Exit;
+ continue;
+ }
+
+ case FT_CURVE_TAG_CONIC: /* consume conic arcs */
+ v_control.x = SCALED( point->x );
+ v_control.y = SCALED( point->y );
+
+ Do_Conic:
+ if ( point < limit )
+ {
+ FT_Vector vec;
+ FT_Vector v_middle;
+
+
+ point++;
+ tags++;
+ tag = FT_CURVE_TAG( tags[0] );
+
+ vec.x = SCALED( point->x );
+ vec.y = SCALED( point->y );
+
+ if ( tag == FT_CURVE_TAG_ON )
+ {
+ error = func_interface->conic_to( &v_control, &vec, user );
+ if ( error )
+ goto Exit;
+ continue;
+ }
+
+ if ( tag != FT_CURVE_TAG_CONIC )
+ goto Invalid_Outline;
+
+ v_middle.x = ( v_control.x + vec.x ) / 2;
+ v_middle.y = ( v_control.y + vec.y ) / 2;
+
+ error = func_interface->conic_to( &v_control, &v_middle, user );
+ if ( error )
+ goto Exit;
+
+ v_control = vec;
+ goto Do_Conic;
+ }
+
+ error = func_interface->conic_to( &v_control, &v_start, user );
+ goto Close;
+
+ default: /* FT_CURVE_TAG_CUBIC */
+ {
+ FT_Vector vec1, vec2;
+
+
+ if ( point + 1 > limit ||
+ FT_CURVE_TAG( tags[1] ) != FT_CURVE_TAG_CUBIC )
+ goto Invalid_Outline;
+
+ point += 2;
+ tags += 2;
+
+ vec1.x = SCALED( point[-2].x ); vec1.y = SCALED( point[-2].y );
+ vec2.x = SCALED( point[-1].x ); vec2.y = SCALED( point[-1].y );
+
+ if ( point <= limit )
+ {
+ FT_Vector vec;
+
+
+ vec.x = SCALED( point->x );
+ vec.y = SCALED( point->y );
+
+ error = func_interface->cubic_to( &vec1, &vec2, &vec, user );
+ if ( error )
+ goto Exit;
+ continue;
+ }
+
+ error = func_interface->cubic_to( &vec1, &vec2, &v_start, user );
+ goto Close;
+ }
+ }
+ }
+
+ /* close the contour with a line segment */
+ error = func_interface->line_to( &v_start, user );
+
+ Close:
+ if ( error )
+ goto Exit;
+
+ first = last + 1;
+ }
+
+ return 0;
+
+ Exit:
+ return error;
+
+ Invalid_Outline:
+ return FT_Err_Invalid_Outline;
+ }
+
+
+ FT_EXPORT_DEF( FT_Error )
+ FT_Outline_New_Internal( FT_Memory memory,
+ FT_UInt numPoints,
+ FT_Int numContours,
+ FT_Outline *anoutline )
+ {
+ FT_Error error;
+
+
+ if ( !anoutline || !memory )
+ return FT_Err_Invalid_Argument;
+
+ *anoutline = null_outline;
+
+ if ( FT_NEW_ARRAY( anoutline->points, numPoints * 2L ) ||
+ FT_NEW_ARRAY( anoutline->tags, numPoints ) ||
+ FT_NEW_ARRAY( anoutline->contours, numContours ) )
+ goto Fail;
+
+ anoutline->n_points = (FT_UShort)numPoints;
+ anoutline->n_contours = (FT_Short)numContours;
+ anoutline->flags |= FT_OUTLINE_OWNER;
+
+ return FT_Err_Ok;
+
+ Fail:
+ anoutline->flags |= FT_OUTLINE_OWNER;
+ FT_Outline_Done_Internal( memory, anoutline );
+
+ return error;
+ }
+
+
+ /* documentation is in ftoutln.h */
+
+ FT_EXPORT_DEF( FT_Error )
+ FT_Outline_New( FT_Library library,
+ FT_UInt numPoints,
+ FT_Int numContours,
+ FT_Outline *anoutline )
+ {
+ if ( !library )
+ return FT_Err_Invalid_Library_Handle;
+
+ return FT_Outline_New_Internal( library->memory, numPoints,
+ numContours, anoutline );
+ }
+
+
+ /* documentation is in ftoutln.h */
+
+ FT_EXPORT_DEF( FT_Error )
+ FT_Outline_Check( FT_Outline* outline )
+ {
+ if ( outline )
+ {
+ FT_Int n_points = outline->n_points;
+ FT_Int n_contours = outline->n_contours;
+ FT_Int end0, end;
+ FT_Int n;
+
+
+ /* empty glyph? */
+ if ( n_points == 0 && n_contours == 0 )
+ return 0;
+
+ /* check point and contour counts */
+ if ( n_points <= 0 || n_contours <= 0 )
+ goto Bad;
+
+ end0 = end = -1;
+ for ( n = 0; n < n_contours; n++ )
+ {
+ end = outline->contours[n];
+
+ /* note that we don't accept empty contours */
+ if ( end <= end0 || end >= n_points )
+ goto Bad;
+
+ end0 = end;
+ }
+
+ if ( end != n_points - 1 )
+ goto Bad;
+
+ /* XXX: check the tags array */
+ return 0;
+ }
+
+ Bad:
+ return FT_Err_Invalid_Argument;
+ }
+
+
+ /* documentation is in ftoutln.h */
+
+ FT_EXPORT_DEF( FT_Error )
+ FT_Outline_Copy( FT_Outline* source,
+ FT_Outline *target )
+ {
+ FT_Int is_owner;
+
+
+ if ( !source || !target ||
+ source->n_points != target->n_points ||
+ source->n_contours != target->n_contours )
+ return FT_Err_Invalid_Argument;
+
+ FT_MEM_COPY( target->points, source->points,
+ source->n_points * sizeof ( FT_Vector ) );
+
+ FT_MEM_COPY( target->tags, source->tags,
+ source->n_points * sizeof ( FT_Byte ) );
+
+ FT_MEM_COPY( target->contours, source->contours,
+ source->n_contours * sizeof ( FT_Short ) );
+
+ /* copy all flags, except the `FT_OUTLINE_OWNER' one */
+ is_owner = target->flags & FT_OUTLINE_OWNER;
+ target->flags = source->flags;
+
+ target->flags &= ~FT_OUTLINE_OWNER;
+ target->flags |= is_owner;
+
+ return FT_Err_Ok;
+ }
+
+
+ FT_EXPORT_DEF( FT_Error )
+ FT_Outline_Done_Internal( FT_Memory memory,
+ FT_Outline* outline )
+ {
+ if ( outline )
+ {
+ if ( outline->flags & FT_OUTLINE_OWNER )
+ {
+ FT_FREE( outline->points );
+ FT_FREE( outline->tags );
+ FT_FREE( outline->contours );
+ }
+ *outline = null_outline;
+
+ return FT_Err_Ok;
+ }
+ else
+ return FT_Err_Invalid_Argument;
+ }
+
+
+ /* documentation is in ftoutln.h */
+
+ FT_EXPORT_DEF( FT_Error )
+ FT_Outline_Done( FT_Library library,
+ FT_Outline* outline )
+ {
+ /* check for valid `outline' in FT_Outline_Done_Internal() */
+
+ if ( !library )
+ return FT_Err_Invalid_Library_Handle;
+
+ return FT_Outline_Done_Internal( library->memory, outline );
+ }
+
+
+ /* documentation is in ftoutln.h */
+
+ FT_EXPORT_DEF( void )
+ FT_Outline_Get_CBox( FT_Outline* outline,
+ FT_BBox *acbox )
+ {
+ FT_Pos xMin, yMin, xMax, yMax;
+
+
+ if ( outline && acbox )
+ {
+ if ( outline->n_points == 0 )
+ {
+ xMin = 0;
+ yMin = 0;
+ xMax = 0;
+ yMax = 0;
+ }
+ else
+ {
+ FT_Vector* vec = outline->points;
+ FT_Vector* limit = vec + outline->n_points;
+
+
+ xMin = xMax = vec->x;
+ yMin = yMax = vec->y;
+ vec++;
+
+ for ( ; vec < limit; vec++ )
+ {
+ FT_Pos x, y;
+
+
+ x = vec->x;
+ if ( x < xMin ) xMin = x;
+ if ( x > xMax ) xMax = x;
+
+ y = vec->y;
+ if ( y < yMin ) yMin = y;
+ if ( y > yMax ) yMax = y;
+ }
+ }
+ acbox->xMin = xMin;
+ acbox->xMax = xMax;
+ acbox->yMin = yMin;
+ acbox->yMax = yMax;
+ }
+ }
+
+
+ /* documentation is in ftoutln.h */
+
+ FT_EXPORT_DEF( void )
+ FT_Outline_Translate( FT_Outline* outline,
+ FT_Pos xOffset,
+ FT_Pos yOffset )
+ {
+ FT_UShort n;
+ FT_Vector* vec = outline->points;
+
+
+ for ( n = 0; n < outline->n_points; n++ )
+ {
+ vec->x += xOffset;
+ vec->y += yOffset;
+ vec++;
+ }
+ }
+
+
+ /* documentation is in ftoutln.h */
+
+ FT_EXPORT_DEF( void )
+ FT_Outline_Reverse( FT_Outline* outline )
+ {
+ FT_UShort n;
+ FT_Int first, last;
+
+
+ first = 0;
+
+ for ( n = 0; n < outline->n_contours; n++ )
+ {
+ last = outline->contours[n];
+
+ /* reverse point table */
+ {
+ FT_Vector* p = outline->points + first;
+ FT_Vector* q = outline->points + last;
+ FT_Vector swap;
+
+
+ while ( p < q )
+ {
+ swap = *p;
+ *p = *q;
+ *q = swap;
+ p++;
+ q--;
+ }
+ }
+
+ /* reverse tags table */
+ {
+ char* p = outline->tags + first;
+ char* q = outline->tags + last;
+ char swap;
+
+
+ while ( p < q )
+ {
+ swap = *p;
+ *p = *q;
+ *q = swap;
+ p++;
+ q--;
+ }
+ }
+
+ first = last + 1;
+ }
+
+ outline->flags ^= FT_OUTLINE_REVERSE_FILL;
+ }
+
+
+ /* documentation is in ftoutln.h */
+
+ FT_EXPORT_DEF( FT_Error )
+ FT_Outline_Render( FT_Library library,
+ FT_Outline* outline,
+ FT_Raster_Params* params )
+ {
+ FT_Error error;
+ FT_Bool update = 0;
+ FT_Renderer renderer;
+ FT_ListNode node;
+
+
+ if ( !library )
+ return FT_Err_Invalid_Library_Handle;
+
+ if ( !params )
+ return FT_Err_Invalid_Argument;
+
+ renderer = library->cur_renderer;
+ node = library->renderers.head;
+
+ params->source = (void*)outline;
+
+ error = FT_Err_Cannot_Render_Glyph;
+ while ( renderer )
+ {
+ error = renderer->raster_render( renderer->raster, params );
+ if ( !error || FT_ERROR_BASE( error ) != FT_Err_Cannot_Render_Glyph )
+ break;
+
+ /* FT_Err_Cannot_Render_Glyph is returned if the render mode */
+ /* is unsupported by the current renderer for this glyph image */
+ /* format */
+
+ /* now, look for another renderer that supports the same */
+ /* format */
+ renderer = FT_Lookup_Renderer( library, FT_GLYPH_FORMAT_OUTLINE,
+ &node );
+ update = 1;
+ }
+
+ /* if we changed the current renderer for the glyph image format */
+ /* we need to select it as the next current one */
+ if ( !error && update && renderer )
+ FT_Set_Renderer( library, renderer, 0, 0 );
+
+ return error;
+ }
+
+
+ /* documentation is in ftoutln.h */
+
+ FT_EXPORT_DEF( FT_Error )
+ FT_Outline_Get_Bitmap( FT_Library library,
+ FT_Outline* outline,
+ FT_Bitmap *abitmap )
+ {
+ FT_Raster_Params params;
+
+
+ if ( !abitmap )
+ return FT_Err_Invalid_Argument;
+
+ /* other checks are delayed to FT_Outline_Render() */
+
+ params.target = abitmap;
+ params.flags = 0;
+
+ if ( abitmap->pixel_mode == FT_PIXEL_MODE_GRAY ||
+ abitmap->pixel_mode == FT_PIXEL_MODE_LCD ||
+ abitmap->pixel_mode == FT_PIXEL_MODE_LCD_V )
+ params.flags |= FT_RASTER_FLAG_AA;
+
+ return FT_Outline_Render( library, outline, ¶ms );
+ }
+
+
+ /* documentation is in ftoutln.h */
+
+ FT_EXPORT_DEF( void )
+ FT_Vector_Transform( FT_Vector* vector,
+ FT_Matrix* matrix )
+ {
+ FT_Pos xz, yz;
+
+
+ if ( !vector || !matrix )
+ return;
+
+ xz = FT_MulFix( vector->x, matrix->xx ) +
+ FT_MulFix( vector->y, matrix->xy );
+
+ yz = FT_MulFix( vector->x, matrix->yx ) +
+ FT_MulFix( vector->y, matrix->yy );
+
+ vector->x = xz;
+ vector->y = yz;
+ }
+
+
+ /* documentation is in ftoutln.h */
+
+ FT_EXPORT_DEF( void )
+ FT_Outline_Transform( FT_Outline* outline,
+ FT_Matrix* matrix )
+ {
+ FT_Vector* vec = outline->points;
+ FT_Vector* limit = vec + outline->n_points;
+
+
+ for ( ; vec < limit; vec++ )
+ FT_Vector_Transform( vec, matrix );
+ }
+
+
+/* END */
--- /dev/null
+++ b/libfreetype/ftpfr.c
@@ -1,0 +1,105 @@
+/***************************************************************************/
+/* */
+/* ftpfr.c */
+/* */
+/* FreeType API for accessing PFR-specific data */
+/* */
+/* Copyright 2002 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+#include <ft2build.h>
+#include FT_INTERNAL_PFR_H
+#include FT_INTERNAL_OBJECTS_H
+
+
+ /* check the format */
+ static FT_Error
+ ft_pfr_check( FT_Face face,
+ FT_PFR_Service *aservice )
+ {
+ FT_Error error = FT_Err_Bad_Argument;
+
+ if ( face && face->driver )
+ {
+ FT_Module module = (FT_Module) face->driver;
+ const char* name = module->clazz->module_name;
+
+ if ( name[0] == 'p' &&
+ name[1] == 'f' &&
+ name[2] == 'r' &&
+ name[4] == 0 )
+ {
+ *aservice = (FT_PFR_Service) module->clazz->module_interface;
+ error = 0;
+ }
+ }
+ return error;
+ }
+
+
+
+ FT_EXPORT_DEF( FT_Error )
+ FT_Get_PFR_Metrics( FT_Face face,
+ FT_UInt *aoutline_resolution,
+ FT_UInt *ametrics_resolution,
+ FT_Fixed *ametrics_x_scale,
+ FT_Fixed *ametrics_y_scale )
+ {
+ FT_Error error;
+ FT_PFR_Service service;
+
+ error = ft_pfr_check( face, &service );
+ if ( !error )
+ {
+ error = service->get_metrics( face,
+ aoutline_resolution,
+ ametrics_resolution,
+ ametrics_x_scale,
+ ametrics_y_scale );
+ }
+ return error;
+ }
+
+ FT_EXPORT_DEF( FT_Error )
+ FT_Get_PFR_Kerning( FT_Face face,
+ FT_UInt left,
+ FT_UInt right,
+ FT_Vector *avector )
+ {
+ FT_Error error;
+ FT_PFR_Service service;
+
+ error = ft_pfr_check( face, &service );
+ if ( !error )
+ {
+ error = service->get_kerning( face, left, right, avector );
+ }
+ return error;
+ }
+
+
+ FT_EXPORT_DEF( FT_Error )
+ FT_Get_PFR_Advance( FT_Face face,
+ FT_UInt gindex,
+ FT_Pos *aadvance )
+ {
+ FT_Error error;
+ FT_PFR_Service service;
+
+ error = ft_pfr_check( face, &service );
+ if ( !error )
+ {
+ error = service->get_advance( face, gindex, aadvance );
+ }
+ return error;
+ }
+
+/* END */
--- /dev/null
+++ b/libfreetype/ftraster.c
@@ -1,0 +1,3288 @@
+/***************************************************************************/
+/* */
+/* ftraster.c */
+/* */
+/* The FreeType glyph rasterizer (body). */
+/* */
+/* Copyright 1996-2001, 2002 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+ /*************************************************************************/
+ /* */
+ /* This is a rewrite of the FreeType 1.x scan-line converter */
+ /* */
+ /*************************************************************************/
+
+
+#include <ft2build.h>
+#include "ftraster.h"
+#include FT_INTERNAL_CALC_H /* for FT_MulDiv only */
+
+
+ /*************************************************************************/
+ /* */
+ /* A simple technical note on how the raster works */
+ /* ----------------------------------------------- */
+ /* */
+ /* Converting an outline into a bitmap is achieved in several steps: */
+ /* */
+ /* 1 - Decomposing the outline into successive `profiles'. Each */
+ /* profile is simply an array of scanline intersections on a given */
+ /* dimension. A profile's main attributes are */
+ /* */
+ /* o its scanline position boundaries, i.e. `Ymin' and `Ymax'. */
+ /* */
+ /* o an array of intersection coordinates for each scanline */
+ /* between `Ymin' and `Ymax'. */
+ /* */
+ /* o a direction, indicating whether it was built going `up' or */
+ /* `down', as this is very important for filling rules. */
+ /* */
+ /* 2 - Sweeping the target map's scanlines in order to compute segment */
+ /* `spans' which are then filled. Additionally, this pass */
+ /* performs drop-out control. */
+ /* */
+ /* The outline data is parsed during step 1 only. The profiles are */
+ /* built from the bottom of the render pool, used as a stack. The */
+ /* following graphics shows the profile list under construction: */
+ /* */
+ /* ____________________________________________________________ _ _ */
+ /* | | | | | */
+ /* | profile | coordinates for | profile | coordinates for |--> */
+ /* | 1 | profile 1 | 2 | profile 2 |--> */
+ /* |_________|___________________|_________|_________________|__ _ _ */
+ /* */
+ /* ^ ^ */
+ /* | | */
+ /* start of render pool top */
+ /* */
+ /* The top of the profile stack is kept in the `top' variable. */
+ /* */
+ /* As you can see, a profile record is pushed on top of the render */
+ /* pool, which is then followed by its coordinates/intersections. If */
+ /* a change of direction is detected in the outline, a new profile is */
+ /* generated until the end of the outline. */
+ /* */
+ /* Note that when all profiles have been generated, the function */
+ /* Finalize_Profile_Table() is used to record, for each profile, its */
+ /* bottom-most scanline as well as the scanline above its upmost */
+ /* boundary. These positions are called `y-turns' because they (sort */
+ /* of) correspond to local extrema. They are stored in a sorted list */
+ /* built from the top of the render pool as a downwards stack: */
+ /* */
+ /* _ _ _______________________________________ */
+ /* | | */
+ /* <--| sorted list of | */
+ /* <--| extrema scanlines | */
+ /* _ _ __________________|____________________| */
+ /* */
+ /* ^ ^ */
+ /* | | */
+ /* maxBuff sizeBuff = end of pool */
+ /* */
+ /* This list is later used during the sweep phase in order to */
+ /* optimize performance (see technical note on the sweep below). */
+ /* */
+ /* Of course, the raster detects whether the two stacks collide and */
+ /* handles the situation propertly. */
+ /* */
+ /*************************************************************************/
+
+
+ /*************************************************************************/
+ /*************************************************************************/
+ /** **/
+ /** CONFIGURATION MACROS **/
+ /** **/
+ /*************************************************************************/
+ /*************************************************************************/
+
+ /* define DEBUG_RASTER if you want to compile a debugging version */
+#define xxxDEBUG_RASTER
+
+ /* The default render pool size in bytes */
+#define RASTER_RENDER_POOL 8192
+
+ /* undefine FT_RASTER_OPTION_ANTI_ALIASING if you do not want to support */
+ /* 5-levels anti-aliasing */
+#ifdef FT_CONFIG_OPTION_5_GRAY_LEVELS
+#define FT_RASTER_OPTION_ANTI_ALIASING
+#endif
+
+ /* The size of the two-lines intermediate bitmap used */
+ /* for anti-aliasing, in bytes. */
+#define RASTER_GRAY_LINES 2048
+
+
+ /*************************************************************************/
+ /*************************************************************************/
+ /** **/
+ /** OTHER MACROS (do not change) **/
+ /** **/
+ /*************************************************************************/
+ /*************************************************************************/
+
+ /*************************************************************************/
+ /* */
+ /* The macro FT_COMPONENT is used in trace mode. It is an implicit */
+ /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log */
+ /* messages during execution. */
+ /* */
+#undef FT_COMPONENT
+#define FT_COMPONENT trace_raster
+
+
+#ifdef _STANDALONE_
+
+
+ /* This macro is used to indicate that a function parameter is unused. */
+ /* Its purpose is simply to reduce compiler warnings. Note also that */
+ /* simply defining it as `(void)x' doesn't avoid warnings with certain */
+ /* ANSI compilers (e.g. LCC). */
+#define FT_UNUSED( x ) (x) = (x)
+
+ /* Disable the tracing mechanism for simplicity -- developers can */
+ /* activate it easily by redefining these two macros. */
+#ifndef FT_ERROR
+#define FT_ERROR( x ) do ; while ( 0 ) /* nothing */
+#endif
+
+#ifndef FT_TRACE
+#define FT_TRACE( x ) do ; while ( 0 ) /* nothing */
+#endif
+
+#define Raster_Err_None 0
+#define Raster_Err_Not_Ini -1
+#define Raster_Err_Overflow -2
+#define Raster_Err_Neg_Height -3
+#define Raster_Err_Invalid -4
+#define Raster_Err_Unsupported -5
+
+
+#else /* _STANDALONE_ */
+
+
+#include FT_INTERNAL_OBJECTS_H
+#include FT_INTERNAL_DEBUG_H /* for FT_TRACE() and FT_ERROR() */
+
+#include "rasterrs.h"
+
+#define Raster_Err_None Raster_Err_Ok
+#define Raster_Err_Not_Ini Raster_Err_Raster_Uninitialized
+#define Raster_Err_Overflow Raster_Err_Raster_Overflow
+#define Raster_Err_Neg_Height Raster_Err_Raster_Negative_Height
+#define Raster_Err_Invalid Raster_Err_Invalid_Outline
+#define Raster_Err_Unsupported Raster_Err_Cannot_Render_Glyph
+
+
+#endif /* _STANDALONE_ */
+
+
+#ifndef FT_MEM_SET
+#define FT_MEM_SET( d, s, c ) ft_memset( d, s, c )
+#endif
+
+
+ /* FMulDiv means `Fast MulDiv'; it is used in case where `b' is */
+ /* typically a small value and the result of a*b is known to fit into */
+ /* 32 bits. */
+#define FMulDiv( a, b, c ) ( (a) * (b) / (c) )
+
+ /* On the other hand, SMulDiv means `Slow MulDiv', and is used typically */
+ /* for clipping computations. It simply uses the FT_MulDiv() function */
+ /* defined in `ftcalc.h'. */
+#define SMulDiv FT_MulDiv
+
+ /* The rasterizer is a very general purpose component; please leave */
+ /* the following redefinitions there (you never know your target */
+ /* environment). */
+
+#ifndef TRUE
+#define TRUE 1
+#endif
+
+#ifndef FALSE
+#define FALSE 0
+#endif
+
+#ifndef NULL
+#define NULL (void*)0
+#endif
+
+#ifndef SUCCESS
+#define SUCCESS 0
+#endif
+
+#ifndef FAILURE
+#define FAILURE 1
+#endif
+
+
+#define MaxBezier 32 /* The maximum number of stacked Bezier curves. */
+ /* Setting this constant to more than 32 is a */
+ /* pure waste of space. */
+
+#define Pixel_Bits 6 /* fractional bits of *input* coordinates */
+
+
+ /*************************************************************************/
+ /*************************************************************************/
+ /** **/
+ /** SIMPLE TYPE DECLARATIONS **/
+ /** **/
+ /*************************************************************************/
+ /*************************************************************************/
+
+ typedef int Int;
+ typedef unsigned int UInt;
+ typedef short Short;
+ typedef unsigned short UShort, *PUShort;
+ typedef long Long, *PLong;
+ typedef unsigned long ULong;
+
+ typedef unsigned char Byte, *PByte;
+ typedef char Bool;
+
+ typedef struct TPoint_
+ {
+ Long x;
+ Long y;
+
+ } TPoint;
+
+
+ typedef enum TFlow_
+ {
+ Flow_None = 0,
+ Flow_Up = 1,
+ Flow_Down = -1
+
+ } TFlow;
+
+
+ /* States of each line, arc, and profile */
+ typedef enum TStates_
+ {
+ Unknown_State,
+ Ascending_State,
+ Descending_State,
+ Flat_State
+
+ } TStates;
+
+
+ typedef struct TProfile_ TProfile;
+ typedef TProfile* PProfile;
+
+ struct TProfile_
+ {
+ FT_F26Dot6 X; /* current coordinate during sweep */
+ PProfile link; /* link to next profile - various purpose */
+ PLong offset; /* start of profile's data in render pool */
+ int flow; /* Profile orientation: Asc/Descending */
+ long height; /* profile's height in scanlines */
+ long start; /* profile's starting scanline */
+
+ unsigned countL; /* number of lines to step before this */
+ /* profile becomes drawable */
+
+ PProfile next; /* next profile in same contour, used */
+ /* during drop-out control */
+ };
+
+ typedef PProfile TProfileList;
+ typedef PProfile* PProfileList;
+
+
+ /* Simple record used to implement a stack of bands, required */
+ /* by the sub-banding mechanism */
+ typedef struct TBand_
+ {
+ Short y_min; /* band's minimum */
+ Short y_max; /* band's maximum */
+
+ } TBand;
+
+
+#define AlignProfileSize \
+ ( ( sizeof ( TProfile ) + sizeof ( long ) - 1 ) / sizeof ( long ) )
+
+
+#ifdef TT_STATIC_RASTER
+
+
+#define RAS_ARGS /* void */
+#define RAS_ARG /* void */
+
+#define RAS_VARS /* void */
+#define RAS_VAR /* void */
+
+#define FT_UNUSED_RASTER do ; while ( 0 )
+
+
+#else /* TT_STATIC_RASTER */
+
+
+#define RAS_ARGS TRaster_Instance* raster,
+#define RAS_ARG TRaster_Instance* raster
+
+#define RAS_VARS raster,
+#define RAS_VAR raster
+
+#define FT_UNUSED_RASTER FT_UNUSED( raster )
+
+
+#endif /* TT_STATIC_RASTER */
+
+
+ typedef struct TRaster_Instance_ TRaster_Instance;
+
+
+ /* prototypes used for sweep function dispatch */
+ typedef void
+ Function_Sweep_Init( RAS_ARGS Short* min,
+ Short* max );
+
+ typedef void
+ Function_Sweep_Span( RAS_ARGS Short y,
+ FT_F26Dot6 x1,
+ FT_F26Dot6 x2,
+ PProfile left,
+ PProfile right );
+
+ typedef void
+ Function_Sweep_Step( RAS_ARG );
+
+
+ /* NOTE: These operations are only valid on 2's complement processors */
+
+#define FLOOR( x ) ( (x) & -ras.precision )
+#define CEILING( x ) ( ( (x) + ras.precision - 1 ) & -ras.precision )
+#define TRUNC( x ) ( (signed long)(x) >> ras.precision_bits )
+#define FRAC( x ) ( (x) & ( ras.precision - 1 ) )
+#define SCALED( x ) ( ( (x) << ras.scale_shift ) - ras.precision_half )
+
+ /* Note that I have moved the location of some fields in the */
+ /* structure to ensure that the most used variables are used */
+ /* at the top. Thus, their offset can be coded with less */
+ /* opcodes, and it results in a smaller executable. */
+
+ struct TRaster_Instance_
+ {
+ Int precision_bits; /* precision related variables */
+ Int precision;
+ Int precision_half;
+ Long precision_mask;
+ Int precision_shift;
+ Int precision_step;
+ Int precision_jitter;
+
+ Int scale_shift; /* == precision_shift for bitmaps */
+ /* == precision_shift+1 for pixmaps */
+
+ PLong buff; /* The profiles buffer */
+ PLong sizeBuff; /* Render pool size */
+ PLong maxBuff; /* Profiles buffer size */
+ PLong top; /* Current cursor in buffer */
+
+ FT_Error error;
+
+ Int numTurns; /* number of Y-turns in outline */
+
+ TPoint* arc; /* current Bezier arc pointer */
+
+ UShort bWidth; /* target bitmap width */
+ PByte bTarget; /* target bitmap buffer */
+ PByte gTarget; /* target pixmap buffer */
+
+ Long lastX, lastY, minY, maxY;
+
+ UShort num_Profs; /* current number of profiles */
+
+ Bool fresh; /* signals a fresh new profile which */
+ /* 'start' field must be completed */
+ Bool joint; /* signals that the last arc ended */
+ /* exactly on a scanline. Allows */
+ /* removal of doublets */
+ PProfile cProfile; /* current profile */
+ PProfile fProfile; /* head of linked list of profiles */
+ PProfile gProfile; /* contour's first profile in case */
+ /* of impact */
+
+ TStates state; /* rendering state */
+
+ FT_Bitmap target; /* description of target bit/pixmap */
+ FT_Outline outline;
+
+ Long traceOfs; /* current offset in target bitmap */
+ Long traceG; /* current offset in target pixmap */
+
+ Short traceIncr; /* sweep's increment in target bitmap */
+
+ Short gray_min_x; /* current min x during gray rendering */
+ Short gray_max_x; /* current max x during gray rendering */
+
+ /* dispatch variables */
+
+ Function_Sweep_Init* Proc_Sweep_Init;
+ Function_Sweep_Span* Proc_Sweep_Span;
+ Function_Sweep_Span* Proc_Sweep_Drop;
+ Function_Sweep_Step* Proc_Sweep_Step;
+
+ Byte dropOutControl; /* current drop_out control method */
+
+ Bool second_pass; /* indicates wether a horizontal pass */
+ /* should be performed to control */
+ /* drop-out accurately when calling */
+ /* Render_Glyph. Note that there is */
+ /* no horizontal pass during gray */
+ /* rendering. */
+
+ TPoint arcs[3 * MaxBezier + 1]; /* The Bezier stack */
+
+ TBand band_stack[16]; /* band stack used for sub-banding */
+ Int band_top; /* band stack top */
+
+ Int count_table[256]; /* Look-up table used to quickly count */
+ /* set bits in a gray 2x2 cell */
+
+ void* memory;
+
+#ifdef FT_RASTER_OPTION_ANTI_ALIASING
+
+ Byte grays[5]; /* Palette of gray levels used for */
+ /* render. */
+
+ Byte gray_lines[RASTER_GRAY_LINES];
+ /* Intermediate table used to render the */
+ /* graylevels pixmaps. */
+ /* gray_lines is a buffer holding two */
+ /* monochrome scanlines */
+
+ Short gray_width; /* width in bytes of one monochrome */
+ /* intermediate scanline of gray_lines. */
+ /* Each gray pixel takes 2 bits long there */
+
+ /* The gray_lines must hold 2 lines, thus with size */
+ /* in bytes of at least `gray_width*2'. */
+
+#endif /* FT_RASTER_ANTI_ALIASING */
+
+#if 0
+ PByte flags; /* current flags table */
+ PUShort outs; /* current outlines table */
+ FT_Vector* coords;
+
+ UShort nPoints; /* number of points in current glyph */
+ Short nContours; /* number of contours in current glyph */
+#endif
+
+ };
+
+
+#ifdef FT_CONFIG_OPTION_STATIC_RASTER
+
+ static TRaster_Instance cur_ras;
+#define ras cur_ras
+
+#else
+
+#define ras (*raster)
+
+#endif /* FT_CONFIG_OPTION_STATIC_RASTER */
+
+
+ /*************************************************************************/
+ /*************************************************************************/
+ /** **/
+ /** PROFILES COMPUTATION **/
+ /** **/
+ /*************************************************************************/
+ /*************************************************************************/
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* Set_High_Precision */
+ /* */
+ /* <Description> */
+ /* Sets precision variables according to param flag. */
+ /* */
+ /* <Input> */
+ /* High :: Set to True for high precision (typically for ppem < 18), */
+ /* false otherwise. */
+ /* */
+ static void
+ Set_High_Precision( RAS_ARGS Int High )
+ {
+ if ( High )
+ {
+ ras.precision_bits = 10;
+ ras.precision_step = 128;
+ ras.precision_jitter = 24;
+ }
+ else
+ {
+ ras.precision_bits = 6;
+ ras.precision_step = 32;
+ ras.precision_jitter = 2;
+ }
+
+ FT_TRACE6(( "Set_High_Precision(%s)\n", High ? "true" : "false" ));
+
+ ras.precision = 1 << ras.precision_bits;
+ ras.precision_half = ras.precision / 2;
+ ras.precision_shift = ras.precision_bits - Pixel_Bits;
+ ras.precision_mask = -ras.precision;
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* New_Profile */
+ /* */
+ /* <Description> */
+ /* Creates a new profile in the render pool. */
+ /* */
+ /* <Input> */
+ /* aState :: The state/orientation of the new profile. */
+ /* */
+ /* <Return> */
+ /* SUCCESS on success. FAILURE in case of overflow or of incoherent */
+ /* profile. */
+ /* */
+ static Bool
+ New_Profile( RAS_ARGS TStates aState )
+ {
+ if ( !ras.fProfile )
+ {
+ ras.cProfile = (PProfile)ras.top;
+ ras.fProfile = ras.cProfile;
+ ras.top += AlignProfileSize;
+ }
+
+ if ( ras.top >= ras.maxBuff )
+ {
+ ras.error = Raster_Err_Overflow;
+ return FAILURE;
+ }
+
+ switch ( aState )
+ {
+ case Ascending_State:
+ ras.cProfile->flow = Flow_Up;
+ FT_TRACE6(( "New ascending profile = %lx\n", (long)ras.cProfile ));
+ break;
+
+ case Descending_State:
+ ras.cProfile->flow = Flow_Down;
+ FT_TRACE6(( "New descending profile = %lx\n", (long)ras.cProfile ));
+ break;
+
+ default:
+ FT_ERROR(( "New_Profile: invalid profile direction!\n" ));
+ ras.error = Raster_Err_Invalid;
+ return FAILURE;
+ }
+
+ ras.cProfile->start = 0;
+ ras.cProfile->height = 0;
+ ras.cProfile->offset = ras.top;
+ ras.cProfile->link = (PProfile)0;
+ ras.cProfile->next = (PProfile)0;
+
+ if ( !ras.gProfile )
+ ras.gProfile = ras.cProfile;
+
+ ras.state = aState;
+ ras.fresh = TRUE;
+ ras.joint = FALSE;
+
+ return SUCCESS;
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* End_Profile */
+ /* */
+ /* <Description> */
+ /* Finalizes the current profile. */
+ /* */
+ /* <Return> */
+ /* SUCCESS on success. FAILURE in case of overflow or incoherency. */
+ /* */
+ static Bool
+ End_Profile( RAS_ARG )
+ {
+ Long h;
+ PProfile oldProfile;
+
+
+ h = (Long)( ras.top - ras.cProfile->offset );
+
+ if ( h < 0 )
+ {
+ FT_ERROR(( "End_Profile: negative height encountered!\n" ));
+ ras.error = Raster_Err_Neg_Height;
+ return FAILURE;
+ }
+
+ if ( h > 0 )
+ {
+ FT_TRACE6(( "Ending profile %lx, start = %ld, height = %ld\n",
+ (long)ras.cProfile, ras.cProfile->start, h ));
+
+ oldProfile = ras.cProfile;
+ ras.cProfile->height = h;
+ ras.cProfile = (PProfile)ras.top;
+
+ ras.top += AlignProfileSize;
+
+ ras.cProfile->height = 0;
+ ras.cProfile->offset = ras.top;
+ oldProfile->next = ras.cProfile;
+ ras.num_Profs++;
+ }
+
+ if ( ras.top >= ras.maxBuff )
+ {
+ FT_TRACE1(( "overflow in End_Profile\n" ));
+ ras.error = Raster_Err_Overflow;
+ return FAILURE;
+ }
+
+ ras.joint = FALSE;
+
+ return SUCCESS;
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* Insert_Y_Turn */
+ /* */
+ /* <Description> */
+ /* Inserts a salient into the sorted list placed on top of the render */
+ /* pool. */
+ /* */
+ /* <Input> */
+ /* New y scanline position. */
+ /* */
+ /* <Return> */
+ /* SUCCESS on success. FAILURE in case of overflow. */
+ /* */
+ static Bool
+ Insert_Y_Turn( RAS_ARGS Int y )
+ {
+ PLong y_turns;
+ Int y2, n;
+
+
+ n = ras.numTurns - 1;
+ y_turns = ras.sizeBuff - ras.numTurns;
+
+ /* look for first y value that is <= */
+ while ( n >= 0 && y < y_turns[n] )
+ n--;
+
+ /* if it is <, simply insert it, ignore if == */
+ if ( n >= 0 && y > y_turns[n] )
+ while ( n >= 0 )
+ {
+ y2 = (Int)y_turns[n];
+ y_turns[n] = y;
+ y = y2;
+ n--;
+ }
+
+ if ( n < 0 )
+ {
+ if ( ras.maxBuff <= ras.top )
+ {
+ ras.error = Raster_Err_Overflow;
+ return FAILURE;
+ }
+ ras.maxBuff--;
+ ras.numTurns++;
+ ras.sizeBuff[-ras.numTurns] = y;
+ }
+
+ return SUCCESS;
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* Finalize_Profile_Table */
+ /* */
+ /* <Description> */
+ /* Adjusts all links in the profiles list. */
+ /* */
+ /* <Return> */
+ /* SUCCESS on success. FAILURE in case of overflow. */
+ /* */
+ static Bool
+ Finalize_Profile_Table( RAS_ARG )
+ {
+ Int bottom, top;
+ UShort n;
+ PProfile p;
+
+
+ n = ras.num_Profs;
+
+ if ( n > 1 )
+ {
+ p = ras.fProfile;
+ while ( n > 0 )
+ {
+ if ( n > 1 )
+ p->link = (PProfile)( p->offset + p->height );
+ else
+ p->link = NULL;
+
+ switch ( p->flow )
+ {
+ case Flow_Down:
+ bottom = (Int)( p->start - p->height + 1 );
+ top = (Int)p->start;
+ p->start = bottom;
+ p->offset += p->height - 1;
+ break;
+
+ case Flow_Up:
+ default:
+ bottom = (Int)p->start;
+ top = (Int)( p->start + p->height - 1 );
+ }
+
+ if ( Insert_Y_Turn( RAS_VARS bottom ) ||
+ Insert_Y_Turn( RAS_VARS top + 1 ) )
+ return FAILURE;
+
+ p = p->link;
+ n--;
+ }
+ }
+ else
+ ras.fProfile = NULL;
+
+ return SUCCESS;
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* Split_Conic */
+ /* */
+ /* <Description> */
+ /* Subdivides one conic Bezier into two joint sub-arcs in the Bezier */
+ /* stack. */
+ /* */
+ /* <Input> */
+ /* None (subdivided Bezier is taken from the top of the stack). */
+ /* */
+ /* <Note> */
+ /* This routine is the `beef' of this component. It is _the_ inner */
+ /* loop that should be optimized to hell to get the best performance. */
+ /* */
+ static void
+ Split_Conic( TPoint* base )
+ {
+ Long a, b;
+
+
+ base[4].x = base[2].x;
+ b = base[1].x;
+ a = base[3].x = ( base[2].x + b ) / 2;
+ b = base[1].x = ( base[0].x + b ) / 2;
+ base[2].x = ( a + b ) / 2;
+
+ base[4].y = base[2].y;
+ b = base[1].y;
+ a = base[3].y = ( base[2].y + b ) / 2;
+ b = base[1].y = ( base[0].y + b ) / 2;
+ base[2].y = ( a + b ) / 2;
+
+ /* hand optimized. gcc doesn't seem to be too good at common */
+ /* expression substitution and instruction scheduling ;-) */
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* Split_Cubic */
+ /* */
+ /* <Description> */
+ /* Subdivides a third-order Bezier arc into two joint sub-arcs in the */
+ /* Bezier stack. */
+ /* */
+ /* <Note> */
+ /* This routine is the `beef' of the component. It is one of _the_ */
+ /* inner loops that should be optimized like hell to get the best */
+ /* performance. */
+ /* */
+ static void
+ Split_Cubic( TPoint* base )
+ {
+ Long a, b, c, d;
+
+
+ base[6].x = base[3].x;
+ c = base[1].x;
+ d = base[2].x;
+ base[1].x = a = ( base[0].x + c + 1 ) >> 1;
+ base[5].x = b = ( base[3].x + d + 1 ) >> 1;
+ c = ( c + d + 1 ) >> 1;
+ base[2].x = a = ( a + c + 1 ) >> 1;
+ base[4].x = b = ( b + c + 1 ) >> 1;
+ base[3].x = ( a + b + 1 ) >> 1;
+
+ base[6].y = base[3].y;
+ c = base[1].y;
+ d = base[2].y;
+ base[1].y = a = ( base[0].y + c + 1 ) >> 1;
+ base[5].y = b = ( base[3].y + d + 1 ) >> 1;
+ c = ( c + d + 1 ) >> 1;
+ base[2].y = a = ( a + c + 1 ) >> 1;
+ base[4].y = b = ( b + c + 1 ) >> 1;
+ base[3].y = ( a + b + 1 ) >> 1;
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* Line_Up */
+ /* */
+ /* <Description> */
+ /* Computes the x-coordinates of an ascending line segment and stores */
+ /* them in the render pool. */
+ /* */
+ /* <Input> */
+ /* x1 :: The x-coordinate of the segment's start point. */
+ /* */
+ /* y1 :: The y-coordinate of the segment's start point. */
+ /* */
+ /* x2 :: The x-coordinate of the segment's end point. */
+ /* */
+ /* y2 :: The y-coordinate of the segment's end point. */
+ /* */
+ /* miny :: A lower vertical clipping bound value. */
+ /* */
+ /* maxy :: An upper vertical clipping bound value. */
+ /* */
+ /* <Return> */
+ /* SUCCESS on success, FAILURE on render pool overflow. */
+ /* */
+ static Bool
+ Line_Up( RAS_ARGS Long x1,
+ Long y1,
+ Long x2,
+ Long y2,
+ Long miny,
+ Long maxy )
+ {
+ Long Dx, Dy;
+ Int e1, e2, f1, f2, size; /* XXX: is `Short' sufficient? */
+ Long Ix, Rx, Ax;
+
+ PLong top;
+
+
+ Dx = x2 - x1;
+ Dy = y2 - y1;
+
+ if ( Dy <= 0 || y2 < miny || y1 > maxy )
+ return SUCCESS;
+
+ if ( y1 < miny )
+ {
+ /* Take care: miny-y1 can be a very large value; we use */
+ /* a slow MulDiv function to avoid clipping bugs */
+ x1 += SMulDiv( Dx, miny - y1, Dy );
+ e1 = TRUNC( miny );
+ f1 = 0;
+ }
+ else
+ {
+ e1 = (Int)TRUNC( y1 );
+ f1 = (Int)FRAC( y1 );
+ }
+
+ if ( y2 > maxy )
+ {
+ /* x2 += FMulDiv( Dx, maxy - y2, Dy ); UNNECESSARY */
+ e2 = (Int)TRUNC( maxy );
+ f2 = 0;
+ }
+ else
+ {
+ e2 = (Int)TRUNC( y2 );
+ f2 = (Int)FRAC( y2 );
+ }
+
+ if ( f1 > 0 )
+ {
+ if ( e1 == e2 )
+ return SUCCESS;
+ else
+ {
+ x1 += FMulDiv( Dx, ras.precision - f1, Dy );
+ e1 += 1;
+ }
+ }
+ else
+ if ( ras.joint )
+ {
+ ras.top--;
+ ras.joint = FALSE;
+ }
+
+ ras.joint = (char)( f2 == 0 );
+
+ if ( ras.fresh )
+ {
+ ras.cProfile->start = e1;
+ ras.fresh = FALSE;
+ }
+
+ size = e2 - e1 + 1;
+ if ( ras.top + size >= ras.maxBuff )
+ {
+ ras.error = Raster_Err_Overflow;
+ return FAILURE;
+ }
+
+ if ( Dx > 0 )
+ {
+ Ix = ( ras.precision * Dx ) / Dy;
+ Rx = ( ras.precision * Dx ) % Dy;
+ Dx = 1;
+ }
+ else
+ {
+ Ix = -( ( ras.precision * -Dx ) / Dy );
+ Rx = ( ras.precision * -Dx ) % Dy;
+ Dx = -1;
+ }
+
+ Ax = -Dy;
+ top = ras.top;
+
+ while ( size > 0 )
+ {
+ *top++ = x1;
+
+ x1 += Ix;
+ Ax += Rx;
+ if ( Ax >= 0 )
+ {
+ Ax -= Dy;
+ x1 += Dx;
+ }
+ size--;
+ }
+
+ ras.top = top;
+ return SUCCESS;
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* Line_Down */
+ /* */
+ /* <Description> */
+ /* Computes the x-coordinates of an descending line segment and */
+ /* stores them in the render pool. */
+ /* */
+ /* <Input> */
+ /* x1 :: The x-coordinate of the segment's start point. */
+ /* */
+ /* y1 :: The y-coordinate of the segment's start point. */
+ /* */
+ /* x2 :: The x-coordinate of the segment's end point. */
+ /* */
+ /* y2 :: The y-coordinate of the segment's end point. */
+ /* */
+ /* miny :: A lower vertical clipping bound value. */
+ /* */
+ /* maxy :: An upper vertical clipping bound value. */
+ /* */
+ /* <Return> */
+ /* SUCCESS on success, FAILURE on render pool overflow. */
+ /* */
+ static Bool
+ Line_Down( RAS_ARGS Long x1,
+ Long y1,
+ Long x2,
+ Long y2,
+ Long miny,
+ Long maxy )
+ {
+ Bool result, fresh;
+
+
+ fresh = ras.fresh;
+
+ result = Line_Up( RAS_VARS x1, -y1, x2, -y2, -maxy, -miny );
+
+ if ( fresh && !ras.fresh )
+ ras.cProfile->start = -ras.cProfile->start;
+
+ return result;
+ }
+
+
+ /* A function type describing the functions used to split Bezier arcs */
+ typedef void (*TSplitter)( TPoint* base );
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* Bezier_Up */
+ /* */
+ /* <Description> */
+ /* Computes the x-coordinates of an ascending Bezier arc and stores */
+ /* them in the render pool. */
+ /* */
+ /* <Input> */
+ /* degree :: The degree of the Bezier arc (either 2 or 3). */
+ /* */
+ /* splitter :: The function to split Bezier arcs. */
+ /* */
+ /* miny :: A lower vertical clipping bound value. */
+ /* */
+ /* maxy :: An upper vertical clipping bound value. */
+ /* */
+ /* <Return> */
+ /* SUCCESS on success, FAILURE on render pool overflow. */
+ /* */
+ static Bool
+ Bezier_Up( RAS_ARGS Int degree,
+ TSplitter splitter,
+ Long miny,
+ Long maxy )
+ {
+ Long y1, y2, e, e2, e0;
+ Short f1;
+
+ TPoint* arc;
+ TPoint* start_arc;
+
+ PLong top;
+
+
+ arc = ras.arc;
+ y1 = arc[degree].y;
+ y2 = arc[0].y;
+ top = ras.top;
+
+ if ( y2 < miny || y1 > maxy )
+ goto Fin;
+
+ e2 = FLOOR( y2 );
+
+ if ( e2 > maxy )
+ e2 = maxy;
+
+ e0 = miny;
+
+ if ( y1 < miny )
+ e = miny;
+ else
+ {
+ e = CEILING( y1 );
+ f1 = (Short)( FRAC( y1 ) );
+ e0 = e;
+
+ if ( f1 == 0 )
+ {
+ if ( ras.joint )
+ {
+ top--;
+ ras.joint = FALSE;
+ }
+
+ *top++ = arc[degree].x;
+
+ e += ras.precision;
+ }
+ }
+
+ if ( ras.fresh )
+ {
+ ras.cProfile->start = TRUNC( e0 );
+ ras.fresh = FALSE;
+ }
+
+ if ( e2 < e )
+ goto Fin;
+
+ if ( ( top + TRUNC( e2 - e ) + 1 ) >= ras.maxBuff )
+ {
+ ras.top = top;
+ ras.error = Raster_Err_Overflow;
+ return FAILURE;
+ }
+
+ start_arc = arc;
+
+ while ( arc >= start_arc && e <= e2 )
+ {
+ ras.joint = FALSE;
+
+ y2 = arc[0].y;
+
+ if ( y2 > e )
+ {
+ y1 = arc[degree].y;
+ if ( y2 - y1 >= ras.precision_step )
+ {
+ splitter( arc );
+ arc += degree;
+ }
+ else
+ {
+ *top++ = arc[degree].x + FMulDiv( arc[0].x-arc[degree].x,
+ e - y1, y2 - y1 );
+ arc -= degree;
+ e += ras.precision;
+ }
+ }
+ else
+ {
+ if ( y2 == e )
+ {
+ ras.joint = TRUE;
+ *top++ = arc[0].x;
+
+ e += ras.precision;
+ }
+ arc -= degree;
+ }
+ }
+
+ Fin:
+ ras.top = top;
+ ras.arc -= degree;
+ return SUCCESS;
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* Bezier_Down */
+ /* */
+ /* <Description> */
+ /* Computes the x-coordinates of an descending Bezier arc and stores */
+ /* them in the render pool. */
+ /* */
+ /* <Input> */
+ /* degree :: The degree of the Bezier arc (either 2 or 3). */
+ /* */
+ /* splitter :: The function to split Bezier arcs. */
+ /* */
+ /* miny :: A lower vertical clipping bound value. */
+ /* */
+ /* maxy :: An upper vertical clipping bound value. */
+ /* */
+ /* <Return> */
+ /* SUCCESS on success, FAILURE on render pool overflow. */
+ /* */
+ static Bool
+ Bezier_Down( RAS_ARGS Int degree,
+ TSplitter splitter,
+ Long miny,
+ Long maxy )
+ {
+ TPoint* arc = ras.arc;
+ Bool result, fresh;
+
+
+ arc[0].y = -arc[0].y;
+ arc[1].y = -arc[1].y;
+ arc[2].y = -arc[2].y;
+ if ( degree > 2 )
+ arc[3].y = -arc[3].y;
+
+ fresh = ras.fresh;
+
+ result = Bezier_Up( RAS_VARS degree, splitter, -maxy, -miny );
+
+ if ( fresh && !ras.fresh )
+ ras.cProfile->start = -ras.cProfile->start;
+
+ arc[0].y = -arc[0].y;
+ return result;
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* Line_To */
+ /* */
+ /* <Description> */
+ /* Injects a new line segment and adjusts Profiles list. */
+ /* */
+ /* <Input> */
+ /* x :: The x-coordinate of the segment's end point (its start point */
+ /* is stored in `LastX'). */
+ /* */
+ /* y :: The y-coordinate of the segment's end point (its start point */
+ /* is stored in `LastY'). */
+ /* */
+ /* <Return> */
+ /* SUCCESS on success, FAILURE on render pool overflow or incorrect */
+ /* profile. */
+ /* */
+ static Bool
+ Line_To( RAS_ARGS Long x,
+ Long y )
+ {
+ /* First, detect a change of direction */
+
+ switch ( ras.state )
+ {
+ case Unknown_State:
+ if ( y > ras.lastY )
+ {
+ if ( New_Profile( RAS_VARS Ascending_State ) )
+ return FAILURE;
+ }
+ else
+ {
+ if ( y < ras.lastY )
+ if ( New_Profile( RAS_VARS Descending_State ) )
+ return FAILURE;
+ }
+ break;
+
+ case Ascending_State:
+ if ( y < ras.lastY )
+ {
+ if ( End_Profile( RAS_VAR ) ||
+ New_Profile( RAS_VARS Descending_State ) )
+ return FAILURE;
+ }
+ break;
+
+ case Descending_State:
+ if ( y > ras.lastY )
+ {
+ if ( End_Profile( RAS_VAR ) ||
+ New_Profile( RAS_VARS Ascending_State ) )
+ return FAILURE;
+ }
+ break;
+
+ default:
+ ;
+ }
+
+ /* Then compute the lines */
+
+ switch ( ras.state )
+ {
+ case Ascending_State:
+ if ( Line_Up( RAS_VARS ras.lastX, ras.lastY,
+ x, y, ras.minY, ras.maxY ) )
+ return FAILURE;
+ break;
+
+ case Descending_State:
+ if ( Line_Down( RAS_VARS ras.lastX, ras.lastY,
+ x, y, ras.minY, ras.maxY ) )
+ return FAILURE;
+ break;
+
+ default:
+ ;
+ }
+
+ ras.lastX = x;
+ ras.lastY = y;
+
+ return SUCCESS;
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* Conic_To */
+ /* */
+ /* <Description> */
+ /* Injects a new conic arc and adjusts the profile list. */
+ /* */
+ /* <Input> */
+ /* cx :: The x-coordinate of the arc's new control point. */
+ /* */
+ /* cy :: The y-coordinate of the arc's new control point. */
+ /* */
+ /* x :: The x-coordinate of the arc's end point (its start point is */
+ /* stored in `LastX'). */
+ /* */
+ /* y :: The y-coordinate of the arc's end point (its start point is */
+ /* stored in `LastY'). */
+ /* */
+ /* <Return> */
+ /* SUCCESS on success, FAILURE on render pool overflow or incorrect */
+ /* profile. */
+ /* */
+ static Bool
+ Conic_To( RAS_ARGS Long cx,
+ Long cy,
+ Long x,
+ Long y )
+ {
+ Long y1, y2, y3, x3, ymin, ymax;
+ TStates state_bez;
+
+
+ ras.arc = ras.arcs;
+ ras.arc[2].x = ras.lastX;
+ ras.arc[2].y = ras.lastY;
+ ras.arc[1].x = cx; ras.arc[1].y = cy;
+ ras.arc[0].x = x; ras.arc[0].y = y;
+
+ do
+ {
+ y1 = ras.arc[2].y;
+ y2 = ras.arc[1].y;
+ y3 = ras.arc[0].y;
+ x3 = ras.arc[0].x;
+
+ /* first, categorize the Bezier arc */
+
+ if ( y1 <= y3 )
+ {
+ ymin = y1;
+ ymax = y3;
+ }
+ else
+ {
+ ymin = y3;
+ ymax = y1;
+ }
+
+ if ( y2 < ymin || y2 > ymax )
+ {
+ /* this arc has no given direction, split it! */
+ Split_Conic( ras.arc );
+ ras.arc += 2;
+ }
+ else if ( y1 == y3 )
+ {
+ /* this arc is flat, ignore it and pop it from the Bezier stack */
+ ras.arc -= 2;
+ }
+ else
+ {
+ /* the arc is y-monotonous, either ascending or descending */
+ /* detect a change of direction */
+ state_bez = y1 < y3 ? Ascending_State : Descending_State;
+ if ( ras.state != state_bez )
+ {
+ /* finalize current profile if any */
+ if ( ras.state != Unknown_State &&
+ End_Profile( RAS_VAR ) )
+ goto Fail;
+
+ /* create a new profile */
+ if ( New_Profile( RAS_VARS state_bez ) )
+ goto Fail;
+ }
+
+ /* now call the appropriate routine */
+ if ( state_bez == Ascending_State )
+ {
+ if ( Bezier_Up( RAS_VARS 2, Split_Conic, ras.minY, ras.maxY ) )
+ goto Fail;
+ }
+ else
+ if ( Bezier_Down( RAS_VARS 2, Split_Conic, ras.minY, ras.maxY ) )
+ goto Fail;
+ }
+
+ } while ( ras.arc >= ras.arcs );
+
+ ras.lastX = x3;
+ ras.lastY = y3;
+
+ return SUCCESS;
+
+ Fail:
+ return FAILURE;
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* Cubic_To */
+ /* */
+ /* <Description> */
+ /* Injects a new cubic arc and adjusts the profile list. */
+ /* */
+ /* <Input> */
+ /* cx1 :: The x-coordinate of the arc's first new control point. */
+ /* */
+ /* cy1 :: The y-coordinate of the arc's first new control point. */
+ /* */
+ /* cx2 :: The x-coordinate of the arc's second new control point. */
+ /* */
+ /* cy2 :: The y-coordinate of the arc's second new control point. */
+ /* */
+ /* x :: The x-coordinate of the arc's end point (its start point is */
+ /* stored in `LastX'). */
+ /* */
+ /* y :: The y-coordinate of the arc's end point (its start point is */
+ /* stored in `LastY'). */
+ /* */
+ /* <Return> */
+ /* SUCCESS on success, FAILURE on render pool overflow or incorrect */
+ /* profile. */
+ /* */
+ static Bool
+ Cubic_To( RAS_ARGS Long cx1,
+ Long cy1,
+ Long cx2,
+ Long cy2,
+ Long x,
+ Long y )
+ {
+ Long y1, y2, y3, y4, x4, ymin1, ymax1, ymin2, ymax2;
+ TStates state_bez;
+
+
+ ras.arc = ras.arcs;
+ ras.arc[3].x = ras.lastX;
+ ras.arc[3].y = ras.lastY;
+ ras.arc[2].x = cx1; ras.arc[2].y = cy1;
+ ras.arc[1].x = cx2; ras.arc[1].y = cy2;
+ ras.arc[0].x = x; ras.arc[0].y = y;
+
+ do
+ {
+ y1 = ras.arc[3].y;
+ y2 = ras.arc[2].y;
+ y3 = ras.arc[1].y;
+ y4 = ras.arc[0].y;
+ x4 = ras.arc[0].x;
+
+ /* first, categorize the Bezier arc */
+
+ if ( y1 <= y4 )
+ {
+ ymin1 = y1;
+ ymax1 = y4;
+ }
+ else
+ {
+ ymin1 = y4;
+ ymax1 = y1;
+ }
+
+ if ( y2 <= y3 )
+ {
+ ymin2 = y2;
+ ymax2 = y3;
+ }
+ else
+ {
+ ymin2 = y3;
+ ymax2 = y2;
+ }
+
+ if ( ymin2 < ymin1 || ymax2 > ymax1 )
+ {
+ /* this arc has no given direction, split it! */
+ Split_Cubic( ras.arc );
+ ras.arc += 3;
+ }
+ else if ( y1 == y4 )
+ {
+ /* this arc is flat, ignore it and pop it from the Bezier stack */
+ ras.arc -= 3;
+ }
+ else
+ {
+ state_bez = ( y1 <= y4 ) ? Ascending_State : Descending_State;
+
+ /* detect a change of direction */
+ if ( ras.state != state_bez )
+ {
+ if ( ras.state != Unknown_State &&
+ End_Profile( RAS_VAR ) )
+ goto Fail;
+
+ if ( New_Profile( RAS_VARS state_bez ) )
+ goto Fail;
+ }
+
+ /* compute intersections */
+ if ( state_bez == Ascending_State )
+ {
+ if ( Bezier_Up( RAS_VARS 3, Split_Cubic, ras.minY, ras.maxY ) )
+ goto Fail;
+ }
+ else
+ if ( Bezier_Down( RAS_VARS 3, Split_Cubic, ras.minY, ras.maxY ) )
+ goto Fail;
+ }
+
+ } while ( ras.arc >= ras.arcs );
+
+ ras.lastX = x4;
+ ras.lastY = y4;
+
+ return SUCCESS;
+
+ Fail:
+ return FAILURE;
+ }
+
+
+#undef SWAP_
+#define SWAP_( x, y ) do \
+ { \
+ Long swap = x; \
+ \
+ \
+ x = y; \
+ y = swap; \
+ } while ( 0 )
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* Decompose_Curve */
+ /* */
+ /* <Description> */
+ /* Scans the outline arays in order to emit individual segments and */
+ /* Beziers by calling Line_To() and Bezier_To(). It handles all */
+ /* weird cases, like when the first point is off the curve, or when */
+ /* there are simply no `on' points in the contour! */
+ /* */
+ /* <Input> */
+ /* first :: The index of the first point in the contour. */
+ /* */
+ /* last :: The index of the last point in the contour. */
+ /* */
+ /* flipped :: If set, flip the direction of the curve. */
+ /* */
+ /* <Return> */
+ /* SUCCESS on success, FAILURE on error. */
+ /* */
+ static Bool
+ Decompose_Curve( RAS_ARGS UShort first,
+ UShort last,
+ int flipped )
+ {
+ FT_Vector v_last;
+ FT_Vector v_control;
+ FT_Vector v_start;
+
+ FT_Vector* points;
+ FT_Vector* point;
+ FT_Vector* limit;
+ char* tags;
+
+ unsigned tag; /* current point's state */
+
+
+ points = ras.outline.points;
+ limit = points + last;
+
+ v_start.x = SCALED( points[first].x );
+ v_start.y = SCALED( points[first].y );
+ v_last.x = SCALED( points[last].x );
+ v_last.y = SCALED( points[last].y );
+
+ if ( flipped )
+ {
+ SWAP_( v_start.x, v_start.y );
+ SWAP_( v_last.x, v_last.y );
+ }
+
+ v_control = v_start;
+
+ point = points + first;
+ tags = ras.outline.tags + first;
+ tag = FT_CURVE_TAG( tags[0] );
+
+ /* A contour cannot start with a cubic control point! */
+ if ( tag == FT_CURVE_TAG_CUBIC )
+ goto Invalid_Outline;
+
+ /* check first point to determine origin */
+ if ( tag == FT_CURVE_TAG_CONIC )
+ {
+ /* first point is conic control. Yes, this happens. */
+ if ( FT_CURVE_TAG( ras.outline.tags[last] ) == FT_CURVE_TAG_ON )
+ {
+ /* start at last point if it is on the curve */
+ v_start = v_last;
+ limit--;
+ }
+ else
+ {
+ /* if both first and last points are conic, */
+ /* start at their middle and record its position */
+ /* for closure */
+ v_start.x = ( v_start.x + v_last.x ) / 2;
+ v_start.y = ( v_start.y + v_last.y ) / 2;
+
+ v_last = v_start;
+ }
+ point--;
+ tags--;
+ }
+
+ ras.lastX = v_start.x;
+ ras.lastY = v_start.y;
+
+ while ( point < limit )
+ {
+ point++;
+ tags++;
+
+ tag = FT_CURVE_TAG( tags[0] );
+
+ switch ( tag )
+ {
+ case FT_CURVE_TAG_ON: /* emit a single line_to */
+ {
+ Long x, y;
+
+
+ x = SCALED( point->x );
+ y = SCALED( point->y );
+ if ( flipped )
+ SWAP_( x, y );
+
+ if ( Line_To( RAS_VARS x, y ) )
+ goto Fail;
+ continue;
+ }
+
+ case FT_CURVE_TAG_CONIC: /* consume conic arcs */
+ v_control.x = SCALED( point[0].x );
+ v_control.y = SCALED( point[0].y );
+
+ if ( flipped )
+ SWAP_( v_control.x, v_control.y );
+
+ Do_Conic:
+ if ( point < limit )
+ {
+ FT_Vector v_middle;
+ Long x, y;
+
+
+ point++;
+ tags++;
+ tag = FT_CURVE_TAG( tags[0] );
+
+ x = SCALED( point[0].x );
+ y = SCALED( point[0].y );
+
+ if ( flipped )
+ SWAP_( x, y );
+
+ if ( tag == FT_CURVE_TAG_ON )
+ {
+ if ( Conic_To( RAS_VARS v_control.x, v_control.y, x, y ) )
+ goto Fail;
+ continue;
+ }
+
+ if ( tag != FT_CURVE_TAG_CONIC )
+ goto Invalid_Outline;
+
+ v_middle.x = ( v_control.x + x ) / 2;
+ v_middle.y = ( v_control.y + y ) / 2;
+
+ if ( Conic_To( RAS_VARS v_control.x, v_control.y,
+ v_middle.x, v_middle.y ) )
+ goto Fail;
+
+ v_control.x = x;
+ v_control.y = y;
+
+ goto Do_Conic;
+ }
+
+ if ( Conic_To( RAS_VARS v_control.x, v_control.y,
+ v_start.x, v_start.y ) )
+ goto Fail;
+
+ goto Close;
+
+ default: /* FT_CURVE_TAG_CUBIC */
+ {
+ Long x1, y1, x2, y2, x3, y3;
+
+
+ if ( point + 1 > limit ||
+ FT_CURVE_TAG( tags[1] ) != FT_CURVE_TAG_CUBIC )
+ goto Invalid_Outline;
+
+ point += 2;
+ tags += 2;
+
+ x1 = SCALED( point[-2].x );
+ y1 = SCALED( point[-2].y );
+ x2 = SCALED( point[-1].x );
+ y2 = SCALED( point[-1].y );
+ x3 = SCALED( point[ 0].x );
+ y3 = SCALED( point[ 0].y );
+
+ if ( flipped )
+ {
+ SWAP_( x1, y1 );
+ SWAP_( x2, y2 );
+ SWAP_( x3, y3 );
+ }
+
+ if ( point <= limit )
+ {
+ if ( Cubic_To( RAS_VARS x1, y1, x2, y2, x3, y3 ) )
+ goto Fail;
+ continue;
+ }
+
+ if ( Cubic_To( RAS_VARS x1, y1, x2, y2, v_start.x, v_start.y ) )
+ goto Fail;
+ goto Close;
+ }
+ }
+ }
+
+ /* close the contour with a line segment */
+ if ( Line_To( RAS_VARS v_start.x, v_start.y ) )
+ goto Fail;
+
+ Close:
+ return SUCCESS;
+
+ Invalid_Outline:
+ ras.error = Raster_Err_Invalid;
+
+ Fail:
+ return FAILURE;
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* Convert_Glyph */
+ /* */
+ /* <Description> */
+ /* Converts a glyph into a series of segments and arcs and makes a */
+ /* profiles list with them. */
+ /* */
+ /* <Input> */
+ /* flipped :: If set, flip the direction of curve. */
+ /* */
+ /* <Return> */
+ /* SUCCESS on success, FAILURE if any error was encountered during */
+ /* rendering. */
+ /* */
+ static Bool
+ Convert_Glyph( RAS_ARGS int flipped )
+ {
+ int i;
+ unsigned start;
+
+ PProfile lastProfile;
+
+
+ ras.fProfile = NULL;
+ ras.joint = FALSE;
+ ras.fresh = FALSE;
+
+ ras.maxBuff = ras.sizeBuff - AlignProfileSize;
+
+ ras.numTurns = 0;
+
+ ras.cProfile = (PProfile)ras.top;
+ ras.cProfile->offset = ras.top;
+ ras.num_Profs = 0;
+
+ start = 0;
+
+ for ( i = 0; i < ras.outline.n_contours; i++ )
+ {
+ ras.state = Unknown_State;
+ ras.gProfile = NULL;
+
+ if ( Decompose_Curve( RAS_VARS (unsigned short)start,
+ ras.outline.contours[i],
+ flipped ) )
+ return FAILURE;
+
+ start = ras.outline.contours[i] + 1;
+
+ /* We must now see whether the extreme arcs join or not */
+ if ( FRAC( ras.lastY ) == 0 &&
+ ras.lastY >= ras.minY &&
+ ras.lastY <= ras.maxY )
+ if ( ras.gProfile && ras.gProfile->flow == ras.cProfile->flow )
+ ras.top--;
+ /* Note that ras.gProfile can be nil if the contour was too small */
+ /* to be drawn. */
+
+ lastProfile = ras.cProfile;
+ if ( End_Profile( RAS_VAR ) )
+ return FAILURE;
+
+ /* close the `next profile in contour' linked list */
+ if ( ras.gProfile )
+ lastProfile->next = ras.gProfile;
+ }
+
+ if ( Finalize_Profile_Table( RAS_VAR ) )
+ return FAILURE;
+
+ return (Bool)( ras.top < ras.maxBuff ? SUCCESS : FAILURE );
+ }
+
+
+ /*************************************************************************/
+ /*************************************************************************/
+ /** **/
+ /** SCAN-LINE SWEEPS AND DRAWING **/
+ /** **/
+ /*************************************************************************/
+ /*************************************************************************/
+
+
+ /*************************************************************************/
+ /* */
+ /* Init_Linked */
+ /* */
+ /* Initializes an empty linked list. */
+ /* */
+ static void
+ Init_Linked( TProfileList* l )
+ {
+ *l = NULL;
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* InsNew */
+ /* */
+ /* Inserts a new profile in a linked list. */
+ /* */
+ static void
+ InsNew( PProfileList list,
+ PProfile profile )
+ {
+ PProfile *old, current;
+ Long x;
+
+
+ old = list;
+ current = *old;
+ x = profile->X;
+
+ while ( current )
+ {
+ if ( x < current->X )
+ break;
+ old = ¤t->link;
+ current = *old;
+ }
+
+ profile->link = current;
+ *old = profile;
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* DelOld */
+ /* */
+ /* Removes an old profile from a linked list. */
+ /* */
+ static void
+ DelOld( PProfileList list,
+ PProfile profile )
+ {
+ PProfile *old, current;
+
+
+ old = list;
+ current = *old;
+
+ while ( current )
+ {
+ if ( current == profile )
+ {
+ *old = current->link;
+ return;
+ }
+
+ old = ¤t->link;
+ current = *old;
+ }
+
+ /* we should never get there, unless the profile was not part of */
+ /* the list. */
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* Sort */
+ /* */
+ /* Sorts a trace list. In 95%, the list is already sorted. We need */
+ /* an algorithm which is fast in this case. Bubble sort is enough */
+ /* and simple. */
+ /* */
+ static void
+ Sort( PProfileList list )
+ {
+ PProfile *old, current, next;
+
+
+ /* First, set the new X coordinate of each profile */
+ current = *list;
+ while ( current )
+ {
+ current->X = *current->offset;
+ current->offset += current->flow;
+ current->height--;
+ current = current->link;
+ }
+
+ /* Then sort them */
+ old = list;
+ current = *old;
+
+ if ( !current )
+ return;
+
+ next = current->link;
+
+ while ( next )
+ {
+ if ( current->X <= next->X )
+ {
+ old = ¤t->link;
+ current = *old;
+
+ if ( !current )
+ return;
+ }
+ else
+ {
+ *old = next;
+ current->link = next->link;
+ next->link = current;
+
+ old = list;
+ current = *old;
+ }
+
+ next = current->link;
+ }
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* Vertical Sweep Procedure Set */
+ /* */
+ /* These four routines are used during the vertical black/white sweep */
+ /* phase by the generic Draw_Sweep() function. */
+ /* */
+ /*************************************************************************/
+
+ static void
+ Vertical_Sweep_Init( RAS_ARGS Short* min,
+ Short* max )
+ {
+ Long pitch = ras.target.pitch;
+
+ FT_UNUSED( max );
+
+
+ ras.traceIncr = (Short)-pitch;
+ ras.traceOfs = -*min * pitch;
+ if ( pitch > 0 )
+ ras.traceOfs += ( ras.target.rows - 1 ) * pitch;
+
+ ras.gray_min_x = 0;
+ ras.gray_max_x = 0;
+ }
+
+
+ static void
+ Vertical_Sweep_Span( RAS_ARGS Short y,
+ FT_F26Dot6 x1,
+ FT_F26Dot6 x2,
+ PProfile left,
+ PProfile right )
+ {
+ Long e1, e2;
+ int c1, c2;
+ Byte f1, f2;
+ Byte* target;
+
+ FT_UNUSED( y );
+ FT_UNUSED( left );
+ FT_UNUSED( right );
+
+
+ /* Drop-out control */
+
+ e1 = TRUNC( CEILING( x1 ) );
+
+ if ( x2 - x1 - ras.precision <= ras.precision_jitter )
+ e2 = e1;
+ else
+ e2 = TRUNC( FLOOR( x2 ) );
+
+ if ( e2 >= 0 && e1 < ras.bWidth )
+ {
+ if ( e1 < 0 )
+ e1 = 0;
+ if ( e2 >= ras.bWidth )
+ e2 = ras.bWidth - 1;
+
+ c1 = (Short)( e1 >> 3 );
+ c2 = (Short)( e2 >> 3 );
+
+ f1 = (Byte) ( 0xFF >> ( e1 & 7 ) );
+ f2 = (Byte) ~( 0x7F >> ( e2 & 7 ) );
+
+ if ( ras.gray_min_x > c1 ) ras.gray_min_x = (short)c1;
+ if ( ras.gray_max_x < c2 ) ras.gray_max_x = (short)c2;
+
+ target = ras.bTarget + ras.traceOfs + c1;
+ c2 -= c1;
+
+ if ( c2 > 0 )
+ {
+ target[0] |= f1;
+
+ /* memset() is slower than the following code on many platforms. */
+ /* This is due to the fact that, in the vast majority of cases, */
+ /* the span length in bytes is relatively small. */
+ c2--;
+ while ( c2 > 0 )
+ {
+ *(++target) = 0xFF;
+ c2--;
+ }
+ target[1] |= f2;
+ }
+ else
+ *target |= ( f1 & f2 );
+ }
+ }
+
+
+ static void
+ Vertical_Sweep_Drop( RAS_ARGS Short y,
+ FT_F26Dot6 x1,
+ FT_F26Dot6 x2,
+ PProfile left,
+ PProfile right )
+ {
+ Long e1, e2;
+ Short c1, f1;
+
+
+ /* Drop-out control */
+
+ e1 = CEILING( x1 );
+ e2 = FLOOR ( x2 );
+
+ if ( e1 > e2 )
+ {
+ if ( e1 == e2 + ras.precision )
+ {
+ switch ( ras.dropOutControl )
+ {
+ case 1:
+ e1 = e2;
+ break;
+
+ case 4:
+ e1 = CEILING( (x1 + x2 + 1) / 2 );
+ break;
+
+ case 2:
+ case 5:
+ /* Drop-out Control Rule #4 */
+
+ /* The spec is not very clear regarding rule #4. It */
+ /* presents a method that is way too costly to implement */
+ /* while the general idea seems to get rid of `stubs'. */
+ /* */
+ /* Here, we only get rid of stubs recognized if: */
+ /* */
+ /* upper stub: */
+ /* */
+ /* - P_Left and P_Right are in the same contour */
+ /* - P_Right is the successor of P_Left in that contour */
+ /* - y is the top of P_Left and P_Right */
+ /* */
+ /* lower stub: */
+ /* */
+ /* - P_Left and P_Right are in the same contour */
+ /* - P_Left is the successor of P_Right in that contour */
+ /* - y is the bottom of P_Left */
+ /* */
+
+ /* FIXXXME: uncommenting this line solves the disappearing */
+ /* bit problem in the `7' of verdana 10pts, but */
+ /* makes a new one in the `C' of arial 14pts */
+
+#if 0
+ if ( x2 - x1 < ras.precision_half )
+#endif
+ {
+ /* upper stub test */
+ if ( left->next == right && left->height <= 0 )
+ return;
+
+ /* lower stub test */
+ if ( right->next == left && left->start == y )
+ return;
+ }
+
+ /* check that the rightmost pixel isn't set */
+
+ e1 = TRUNC( e1 );
+
+ c1 = (Short)( e1 >> 3 );
+ f1 = (Short)( e1 & 7 );
+
+ if ( e1 >= 0 && e1 < ras.bWidth &&
+ ras.bTarget[ras.traceOfs + c1] & ( 0x80 >> f1 ) )
+ return;
+
+ if ( ras.dropOutControl == 2 )
+ e1 = e2;
+ else
+ e1 = CEILING( ( x1 + x2 + 1 ) / 2 );
+
+ break;
+
+ default:
+ return; /* unsupported mode */
+ }
+ }
+ else
+ return;
+ }
+
+ e1 = TRUNC( e1 );
+
+ if ( e1 >= 0 && e1 < ras.bWidth )
+ {
+ c1 = (Short)( e1 >> 3 );
+ f1 = (Short)( e1 & 7 );
+
+ if ( ras.gray_min_x > c1 ) ras.gray_min_x = c1;
+ if ( ras.gray_max_x < c1 ) ras.gray_max_x = c1;
+
+ ras.bTarget[ras.traceOfs + c1] |= (char)( 0x80 >> f1 );
+ }
+ }
+
+
+ static void
+ Vertical_Sweep_Step( RAS_ARG )
+ {
+ ras.traceOfs += ras.traceIncr;
+ }
+
+
+ /***********************************************************************/
+ /* */
+ /* Horizontal Sweep Procedure Set */
+ /* */
+ /* These four routines are used during the horizontal black/white */
+ /* sweep phase by the generic Draw_Sweep() function. */
+ /* */
+ /***********************************************************************/
+
+ static void
+ Horizontal_Sweep_Init( RAS_ARGS Short* min,
+ Short* max )
+ {
+ /* nothing, really */
+ FT_UNUSED( raster );
+ FT_UNUSED( min );
+ FT_UNUSED( max );
+ }
+
+
+ static void
+ Horizontal_Sweep_Span( RAS_ARGS Short y,
+ FT_F26Dot6 x1,
+ FT_F26Dot6 x2,
+ PProfile left,
+ PProfile right )
+ {
+ Long e1, e2;
+ PByte bits;
+ Byte f1;
+
+ FT_UNUSED( left );
+ FT_UNUSED( right );
+
+
+ if ( x2 - x1 < ras.precision )
+ {
+ e1 = CEILING( x1 );
+ e2 = FLOOR ( x2 );
+
+ if ( e1 == e2 )
+ {
+ bits = ras.bTarget + ( y >> 3 );
+ f1 = (Byte)( 0x80 >> ( y & 7 ) );
+
+ e1 = TRUNC( e1 );
+
+ if ( e1 >= 0 && e1 < ras.target.rows )
+ {
+ PByte p;
+
+
+ p = bits - e1*ras.target.pitch;
+ if ( ras.target.pitch > 0 )
+ p += ( ras.target.rows - 1 ) * ras.target.pitch;
+
+ p[0] |= f1;
+ }
+ }
+ }
+ }
+
+
+ static void
+ Horizontal_Sweep_Drop( RAS_ARGS Short y,
+ FT_F26Dot6 x1,
+ FT_F26Dot6 x2,
+ PProfile left,
+ PProfile right )
+ {
+ Long e1, e2;
+ PByte bits;
+ Byte f1;
+
+
+ /* During the horizontal sweep, we only take care of drop-outs */
+
+ e1 = CEILING( x1 );
+ e2 = FLOOR ( x2 );
+
+ if ( e1 > e2 )
+ {
+ if ( e1 == e2 + ras.precision )
+ {
+ switch ( ras.dropOutControl )
+ {
+ case 1:
+ e1 = e2;
+ break;
+
+ case 4:
+ e1 = CEILING( ( x1 + x2 + 1 ) / 2 );
+ break;
+
+ case 2:
+ case 5:
+
+ /* Drop-out Control Rule #4 */
+
+ /* The spec is not very clear regarding rule #4. It */
+ /* presents a method that is way too costly to implement */
+ /* while the general idea seems to get rid of `stubs'. */
+ /* */
+
+ /* rightmost stub test */
+ if ( left->next == right && left->height <= 0 )
+ return;
+
+ /* leftmost stub test */
+ if ( right->next == left && left->start == y )
+ return;
+
+ /* check that the rightmost pixel isn't set */
+
+ e1 = TRUNC( e1 );
+
+ bits = ras.bTarget + ( y >> 3 );
+ f1 = (Byte)( 0x80 >> ( y & 7 ) );
+
+ bits -= e1 * ras.target.pitch;
+ if ( ras.target.pitch > 0 )
+ bits += ( ras.target.rows - 1 ) * ras.target.pitch;
+
+ if ( e1 >= 0 &&
+ e1 < ras.target.rows &&
+ *bits & f1 )
+ return;
+
+ if ( ras.dropOutControl == 2 )
+ e1 = e2;
+ else
+ e1 = CEILING( ( x1 + x2 + 1 ) / 2 );
+
+ break;
+
+ default:
+ return; /* unsupported mode */
+ }
+ }
+ else
+ return;
+ }
+
+ bits = ras.bTarget + ( y >> 3 );
+ f1 = (Byte)( 0x80 >> ( y & 7 ) );
+
+ e1 = TRUNC( e1 );
+
+ if ( e1 >= 0 && e1 < ras.target.rows )
+ {
+ bits -= e1 * ras.target.pitch;
+ if ( ras.target.pitch > 0 )
+ bits += ( ras.target.rows - 1 ) * ras.target.pitch;
+
+ bits[0] |= f1;
+ }
+ }
+
+
+ static void
+ Horizontal_Sweep_Step( RAS_ARG )
+ {
+ /* Nothing, really */
+ FT_UNUSED( raster );
+ }
+
+
+#ifdef FT_RASTER_OPTION_ANTI_ALIASING
+
+
+ /*************************************************************************/
+ /* */
+ /* Vertical Gray Sweep Procedure Set */
+ /* */
+ /* These two routines are used during the vertical gray-levels sweep */
+ /* phase by the generic Draw_Sweep() function. */
+ /* */
+ /* NOTES */
+ /* */
+ /* - The target pixmap's width *must* be a multiple of 4. */
+ /* */
+ /* - You have to use the function Vertical_Sweep_Span() for the gray */
+ /* span call. */
+ /* */
+ /*************************************************************************/
+
+ static void
+ Vertical_Gray_Sweep_Init( RAS_ARGS Short* min,
+ Short* max )
+ {
+ Long pitch, byte_len;
+
+
+ *min = *min & -2;
+ *max = ( *max + 3 ) & -2;
+
+ ras.traceOfs = 0;
+ pitch = ras.target.pitch;
+ byte_len = -pitch;
+ ras.traceIncr = (Short)byte_len;
+ ras.traceG = ( *min / 2 ) * byte_len;
+
+ if ( pitch > 0 )
+ {
+ ras.traceG += ( ras.target.rows - 1 ) * pitch;
+ byte_len = -byte_len;
+ }
+
+ ras.gray_min_x = (Short)byte_len;
+ ras.gray_max_x = -(Short)byte_len;
+ }
+
+
+ static void
+ Vertical_Gray_Sweep_Step( RAS_ARG )
+ {
+ Int c1, c2;
+ PByte pix, bit, bit2;
+ Int* count = ras.count_table;
+ Byte* grays;
+
+
+ ras.traceOfs += ras.gray_width;
+
+ if ( ras.traceOfs > ras.gray_width )
+ {
+ pix = ras.gTarget + ras.traceG + ras.gray_min_x * 4;
+ grays = ras.grays;
+
+ if ( ras.gray_max_x >= 0 )
+ {
+ Long last_pixel = ras.target.width - 1;
+ Int last_cell = last_pixel >> 2;
+ Int last_bit = last_pixel & 3;
+ Bool over = 0;
+
+
+ if ( ras.gray_max_x >= last_cell && last_bit != 3 )
+ {
+ ras.gray_max_x = last_cell - 1;
+ over = 1;
+ }
+
+ if ( ras.gray_min_x < 0 )
+ ras.gray_min_x = 0;
+
+ bit = ras.bTarget + ras.gray_min_x;
+ bit2 = bit + ras.gray_width;
+
+ c1 = ras.gray_max_x - ras.gray_min_x;
+
+ while ( c1 >= 0 )
+ {
+ c2 = count[*bit] + count[*bit2];
+
+ if ( c2 )
+ {
+ pix[0] = grays[(c2 >> 12) & 0x000F];
+ pix[1] = grays[(c2 >> 8 ) & 0x000F];
+ pix[2] = grays[(c2 >> 4 ) & 0x000F];
+ pix[3] = grays[ c2 & 0x000F];
+
+ *bit = 0;
+ *bit2 = 0;
+ }
+
+ bit++;
+ bit2++;
+ pix += 4;
+ c1--;
+ }
+
+ if ( over )
+ {
+ c2 = count[*bit] + count[*bit2];
+ if ( c2 )
+ {
+ switch ( last_bit )
+ {
+ case 2:
+ pix[2] = grays[(c2 >> 4 ) & 0x000F];
+ case 1:
+ pix[1] = grays[(c2 >> 8 ) & 0x000F];
+ default:
+ pix[0] = grays[(c2 >> 12) & 0x000F];
+ }
+
+ *bit = 0;
+ *bit2 = 0;
+ }
+ }
+ }
+
+ ras.traceOfs = 0;
+ ras.traceG += ras.traceIncr;
+
+ ras.gray_min_x = 32000;
+ ras.gray_max_x = -32000;
+ }
+ }
+
+
+ static void
+ Horizontal_Gray_Sweep_Span( RAS_ARGS Short y,
+ FT_F26Dot6 x1,
+ FT_F26Dot6 x2,
+ PProfile left,
+ PProfile right )
+ {
+ /* nothing, really */
+ FT_UNUSED( raster );
+ FT_UNUSED( y );
+ FT_UNUSED( x1 );
+ FT_UNUSED( x2 );
+ FT_UNUSED( left );
+ FT_UNUSED( right );
+ }
+
+
+ static void
+ Horizontal_Gray_Sweep_Drop( RAS_ARGS Short y,
+ FT_F26Dot6 x1,
+ FT_F26Dot6 x2,
+ PProfile left,
+ PProfile right )
+ {
+ Long e1, e2;
+ PByte pixel;
+ Byte color;
+
+
+ /* During the horizontal sweep, we only take care of drop-outs */
+ e1 = CEILING( x1 );
+ e2 = FLOOR ( x2 );
+
+ if ( e1 > e2 )
+ {
+ if ( e1 == e2 + ras.precision )
+ {
+ switch ( ras.dropOutControl )
+ {
+ case 1:
+ e1 = e2;
+ break;
+
+ case 4:
+ e1 = CEILING( ( x1 + x2 + 1 ) / 2 );
+ break;
+
+ case 2:
+ case 5:
+
+ /* Drop-out Control Rule #4 */
+
+ /* The spec is not very clear regarding rule #4. It */
+ /* presents a method that is way too costly to implement */
+ /* while the general idea seems to get rid of `stubs'. */
+ /* */
+
+ /* rightmost stub test */
+ if ( left->next == right && left->height <= 0 )
+ return;
+
+ /* leftmost stub test */
+ if ( right->next == left && left->start == y )
+ return;
+
+ if ( ras.dropOutControl == 2 )
+ e1 = e2;
+ else
+ e1 = CEILING( ( x1 + x2 + 1 ) / 2 );
+
+ break;
+
+ default:
+ return; /* unsupported mode */
+ }
+ }
+ else
+ return;
+ }
+
+ if ( e1 >= 0 )
+ {
+ if ( x2 - x1 >= ras.precision_half )
+ color = ras.grays[2];
+ else
+ color = ras.grays[1];
+
+ e1 = TRUNC( e1 ) / 2;
+ if ( e1 < ras.target.rows )
+ {
+ pixel = ras.gTarget - e1 * ras.target.pitch + y / 2;
+ if ( ras.target.pitch > 0 )
+ pixel += ( ras.target.rows - 1 ) * ras.target.pitch;
+
+ if ( pixel[0] == ras.grays[0] )
+ pixel[0] = color;
+ }
+ }
+ }
+
+
+#endif /* FT_RASTER_OPTION_ANTI_ALIASING */
+
+
+ /*************************************************************************/
+ /* */
+ /* Generic Sweep Drawing routine */
+ /* */
+ /*************************************************************************/
+
+ static Bool
+ Draw_Sweep( RAS_ARG )
+ {
+ Short y, y_change, y_height;
+
+ PProfile P, Q, P_Left, P_Right;
+
+ Short min_Y, max_Y, top, bottom, dropouts;
+
+ Long x1, x2, xs, e1, e2;
+
+ TProfileList waiting;
+ TProfileList draw_left, draw_right;
+
+
+ /* Init empty linked lists */
+
+ Init_Linked( &waiting );
+
+ Init_Linked( &draw_left );
+ Init_Linked( &draw_right );
+
+ /* first, compute min and max Y */
+
+ P = ras.fProfile;
+ max_Y = (Short)TRUNC( ras.minY );
+ min_Y = (Short)TRUNC( ras.maxY );
+
+ while ( P )
+ {
+ Q = P->link;
+
+ bottom = (Short)P->start;
+ top = (Short)( P->start + P->height - 1 );
+
+ if ( min_Y > bottom ) min_Y = bottom;
+ if ( max_Y < top ) max_Y = top;
+
+ P->X = 0;
+ InsNew( &waiting, P );
+
+ P = Q;
+ }
+
+ /* Check the Y-turns */
+ if ( ras.numTurns == 0 )
+ {
+ ras.error = Raster_Err_Invalid;
+ return FAILURE;
+ }
+
+ /* Now inits the sweep */
+
+ ras.Proc_Sweep_Init( RAS_VARS &min_Y, &max_Y );
+
+ /* Then compute the distance of each profile from min_Y */
+
+ P = waiting;
+
+ while ( P )
+ {
+ P->countL = (UShort)( P->start - min_Y );
+ P = P->link;
+ }
+
+ /* Let's go */
+
+ y = min_Y;
+ y_height = 0;
+
+ if ( ras.numTurns > 0 &&
+ ras.sizeBuff[-ras.numTurns] == min_Y )
+ ras.numTurns--;
+
+ while ( ras.numTurns > 0 )
+ {
+ /* look in the waiting list for new activations */
+
+ P = waiting;
+
+ while ( P )
+ {
+ Q = P->link;
+ P->countL -= y_height;
+ if ( P->countL == 0 )
+ {
+ DelOld( &waiting, P );
+
+ switch ( P->flow )
+ {
+ case Flow_Up:
+ InsNew( &draw_left, P );
+ break;
+
+ case Flow_Down:
+ InsNew( &draw_right, P );
+ break;
+ }
+ }
+
+ P = Q;
+ }
+
+ /* Sort the drawing lists */
+
+ Sort( &draw_left );
+ Sort( &draw_right );
+
+ y_change = (Short)ras.sizeBuff[-ras.numTurns--];
+ y_height = (Short)( y_change - y );
+
+ while ( y < y_change )
+ {
+ /* Let's trace */
+
+ dropouts = 0;
+
+ P_Left = draw_left;
+ P_Right = draw_right;
+
+ while ( P_Left )
+ {
+ x1 = P_Left ->X;
+ x2 = P_Right->X;
+
+ if ( x1 > x2 )
+ {
+ xs = x1;
+ x1 = x2;
+ x2 = xs;
+ }
+
+ if ( x2 - x1 <= ras.precision )
+ {
+ e1 = FLOOR( x1 );
+ e2 = CEILING( x2 );
+
+ if ( ras.dropOutControl != 0 &&
+ ( e1 > e2 || e2 == e1 + ras.precision ) )
+ {
+ /* a drop out was detected */
+
+ P_Left ->X = x1;
+ P_Right->X = x2;
+
+ /* mark profile for drop-out processing */
+ P_Left->countL = 1;
+ dropouts++;
+
+ goto Skip_To_Next;
+ }
+ }
+
+ ras.Proc_Sweep_Span( RAS_VARS y, x1, x2, P_Left, P_Right );
+
+ Skip_To_Next:
+
+ P_Left = P_Left->link;
+ P_Right = P_Right->link;
+ }
+
+ /* now perform the dropouts _after_ the span drawing -- */
+ /* drop-outs processing has been moved out of the loop */
+ /* for performance tuning */
+ if ( dropouts > 0 )
+ goto Scan_DropOuts;
+
+ Next_Line:
+
+ ras.Proc_Sweep_Step( RAS_VAR );
+
+ y++;
+
+ if ( y < y_change )
+ {
+ Sort( &draw_left );
+ Sort( &draw_right );
+ }
+ }
+
+ /* Now finalize the profiles that needs it */
+
+ P = draw_left;
+ while ( P )
+ {
+ Q = P->link;
+ if ( P->height == 0 )
+ DelOld( &draw_left, P );
+ P = Q;
+ }
+
+ P = draw_right;
+ while ( P )
+ {
+ Q = P->link;
+ if ( P->height == 0 )
+ DelOld( &draw_right, P );
+ P = Q;
+ }
+ }
+
+ /* for gray-scaling, flushes the bitmap scanline cache */
+ while ( y <= max_Y )
+ {
+ ras.Proc_Sweep_Step( RAS_VAR );
+ y++;
+ }
+
+ return SUCCESS;
+
+ Scan_DropOuts:
+
+ P_Left = draw_left;
+ P_Right = draw_right;
+
+ while ( P_Left )
+ {
+ if ( P_Left->countL )
+ {
+ P_Left->countL = 0;
+#if 0
+ dropouts--; /* -- this is useful when debugging only */
+#endif
+ ras.Proc_Sweep_Drop( RAS_VARS y,
+ P_Left->X,
+ P_Right->X,
+ P_Left,
+ P_Right );
+ }
+
+ P_Left = P_Left->link;
+ P_Right = P_Right->link;
+ }
+
+ goto Next_Line;
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* Render_Single_Pass */
+ /* */
+ /* <Description> */
+ /* Performs one sweep with sub-banding. */
+ /* */
+ /* <Input> */
+ /* flipped :: If set, flip the direction of the outline. */
+ /* */
+ /* <Return> */
+ /* Renderer error code. */
+ /* */
+ static int
+ Render_Single_Pass( RAS_ARGS Bool flipped )
+ {
+ Short i, j, k;
+
+
+ while ( ras.band_top >= 0 )
+ {
+ ras.maxY = (Long)ras.band_stack[ras.band_top].y_max * ras.precision;
+ ras.minY = (Long)ras.band_stack[ras.band_top].y_min * ras.precision;
+
+ ras.top = ras.buff;
+
+ ras.error = Raster_Err_None;
+
+ if ( Convert_Glyph( RAS_VARS flipped ) )
+ {
+ if ( ras.error != Raster_Err_Overflow )
+ return FAILURE;
+
+ ras.error = Raster_Err_None;
+
+ /* sub-banding */
+
+#ifdef DEBUG_RASTER
+ ClearBand( RAS_VARS TRUNC( ras.minY ), TRUNC( ras.maxY ) );
+#endif
+
+ i = ras.band_stack[ras.band_top].y_min;
+ j = ras.band_stack[ras.band_top].y_max;
+
+ k = (Short)( ( i + j ) / 2 );
+
+ if ( ras.band_top >= 7 || k < i )
+ {
+ ras.band_top = 0;
+ ras.error = Raster_Err_Invalid;
+
+ return ras.error;
+ }
+
+ ras.band_stack[ras.band_top + 1].y_min = k;
+ ras.band_stack[ras.band_top + 1].y_max = j;
+
+ ras.band_stack[ras.band_top].y_max = (Short)( k - 1 );
+
+ ras.band_top++;
+ }
+ else
+ {
+ if ( ras.fProfile )
+ if ( Draw_Sweep( RAS_VAR ) )
+ return ras.error;
+ ras.band_top--;
+ }
+ }
+
+ return SUCCESS;
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* Render_Glyph */
+ /* */
+ /* <Description> */
+ /* Renders a glyph in a bitmap. Sub-banding if needed. */
+ /* */
+ /* <Return> */
+ /* FreeType error code. 0 means success. */
+ /* */
+ FT_LOCAL_DEF( FT_Error )
+ Render_Glyph( RAS_ARG )
+ {
+ FT_Error error;
+
+
+ Set_High_Precision( RAS_VARS ras.outline.flags &
+ FT_OUTLINE_HIGH_PRECISION );
+ ras.scale_shift = ras.precision_shift;
+ ras.dropOutControl = 2;
+ ras.second_pass = (FT_Byte)( !( ras.outline.flags &
+ FT_OUTLINE_SINGLE_PASS ) );
+
+ /* Vertical Sweep */
+ ras.Proc_Sweep_Init = Vertical_Sweep_Init;
+ ras.Proc_Sweep_Span = Vertical_Sweep_Span;
+ ras.Proc_Sweep_Drop = Vertical_Sweep_Drop;
+ ras.Proc_Sweep_Step = Vertical_Sweep_Step;
+
+ ras.band_top = 0;
+ ras.band_stack[0].y_min = 0;
+ ras.band_stack[0].y_max = (short)( ras.target.rows - 1 );
+
+ ras.bWidth = (unsigned short)ras.target.width;
+ ras.bTarget = (Byte*)ras.target.buffer;
+
+ if ( ( error = Render_Single_Pass( RAS_VARS 0 ) ) != 0 )
+ return error;
+
+ /* Horizontal Sweep */
+ if ( ras.second_pass && ras.dropOutControl != 0 )
+ {
+ ras.Proc_Sweep_Init = Horizontal_Sweep_Init;
+ ras.Proc_Sweep_Span = Horizontal_Sweep_Span;
+ ras.Proc_Sweep_Drop = Horizontal_Sweep_Drop;
+ ras.Proc_Sweep_Step = Horizontal_Sweep_Step;
+
+ ras.band_top = 0;
+ ras.band_stack[0].y_min = 0;
+ ras.band_stack[0].y_max = (short)( ras.target.width - 1 );
+
+ if ( ( error = Render_Single_Pass( RAS_VARS 1 ) ) != 0 )
+ return error;
+ }
+
+ return Raster_Err_Ok;
+ }
+
+
+#ifdef FT_RASTER_OPTION_ANTI_ALIASING
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* Render_Gray_Glyph */
+ /* */
+ /* <Description> */
+ /* Renders a glyph with grayscaling. Sub-banding if needed. */
+ /* */
+ /* <Return> */
+ /* FreeType error code. 0 means success. */
+ /* */
+ FT_LOCAL_DEF( FT_Error )
+ Render_Gray_Glyph( RAS_ARG )
+ {
+ Long pixel_width;
+ FT_Error error;
+
+
+ Set_High_Precision( RAS_VARS ras.outline.flags &
+ FT_OUTLINE_HIGH_PRECISION );
+ ras.scale_shift = ras.precision_shift + 1;
+ ras.dropOutControl = 2;
+ ras.second_pass = !( ras.outline.flags & FT_OUTLINE_SINGLE_PASS );
+
+ /* Vertical Sweep */
+
+ ras.band_top = 0;
+ ras.band_stack[0].y_min = 0;
+ ras.band_stack[0].y_max = 2 * ras.target.rows - 1;
+
+ ras.bWidth = ras.gray_width;
+ pixel_width = 2 * ( ( ras.target.width + 3 ) >> 2 );
+
+ if ( ras.bWidth > pixel_width )
+ ras.bWidth = pixel_width;
+
+ ras.bWidth = ras.bWidth * 8;
+ ras.bTarget = (Byte*)ras.gray_lines;
+ ras.gTarget = (Byte*)ras.target.buffer;
+
+ ras.Proc_Sweep_Init = Vertical_Gray_Sweep_Init;
+ ras.Proc_Sweep_Span = Vertical_Sweep_Span;
+ ras.Proc_Sweep_Drop = Vertical_Sweep_Drop;
+ ras.Proc_Sweep_Step = Vertical_Gray_Sweep_Step;
+
+ error = Render_Single_Pass( RAS_VARS 0 );
+ if ( error )
+ return error;
+
+ /* Horizontal Sweep */
+ if ( ras.second_pass && ras.dropOutControl != 0 )
+ {
+ ras.Proc_Sweep_Init = Horizontal_Sweep_Init;
+ ras.Proc_Sweep_Span = Horizontal_Gray_Sweep_Span;
+ ras.Proc_Sweep_Drop = Horizontal_Gray_Sweep_Drop;
+ ras.Proc_Sweep_Step = Horizontal_Sweep_Step;
+
+ ras.band_top = 0;
+ ras.band_stack[0].y_min = 0;
+ ras.band_stack[0].y_max = ras.target.width * 2 - 1;
+
+ error = Render_Single_Pass( RAS_VARS 1 );
+ if ( error )
+ return error;
+ }
+
+ return Raster_Err_Ok;
+ }
+
+#else /* !FT_RASTER_OPTION_ANTI_ALIASING */
+
+ FT_LOCAL_DEF( FT_Error )
+ Render_Gray_Glyph( RAS_ARG )
+ {
+ FT_UNUSED_RASTER;
+
+ return Raster_Err_Cannot_Render_Glyph;
+ }
+
+#endif /* !FT_RASTER_OPTION_ANTI_ALIASING */
+
+
+ static void
+ ft_black_init( TRaster_Instance* raster )
+ {
+ FT_UInt n;
+ FT_ULong c;
+
+
+ /* setup count table */
+ for ( n = 0; n < 256; n++ )
+ {
+ c = ( n & 0x55 ) + ( ( n & 0xAA ) >> 1 );
+
+ c = ( ( c << 6 ) & 0x3000 ) |
+ ( ( c << 4 ) & 0x0300 ) |
+ ( ( c << 2 ) & 0x0030 ) |
+ (c & 0x0003 );
+
+ raster->count_table[n] = (UInt)c;
+ }
+
+#ifdef FT_RASTER_OPTION_ANTI_ALIASING
+
+ /* set default 5-levels gray palette */
+ for ( n = 0; n < 5; n++ )
+ raster->grays[n] = n * 255 / 4;
+
+ raster->gray_width = RASTER_GRAY_LINES / 2;
+
+#endif
+ }
+
+
+ /**** RASTER OBJECT CREATION: In standalone mode, we simply use *****/
+ /**** a static object. *****/
+
+
+#ifdef _STANDALONE_
+
+
+ static int
+ ft_black_new( void* memory,
+ FT_Raster *araster )
+ {
+ static FT_RasterRec_ the_raster;
+
+
+ *araster = &the_raster;
+ FT_MEM_ZERO( &the_raster, sizeof ( the_raster ) );
+ ft_black_init( &the_raster );
+
+ return 0;
+ }
+
+
+ static void
+ ft_black_done( FT_Raster raster )
+ {
+ /* nothing */
+ raster->init = 0;
+ }
+
+
+#else /* _STANDALONE_ */
+
+
+ static int
+ ft_black_new( FT_Memory memory,
+ TRaster_Instance** araster )
+ {
+ FT_Error error;
+ TRaster_Instance* raster;
+
+
+ *araster = 0;
+ if ( !FT_NEW( raster ) )
+ {
+ raster->memory = memory;
+ ft_black_init( raster );
+
+ *araster = raster;
+ }
+
+ return error;
+ }
+
+
+ static void
+ ft_black_done( TRaster_Instance* raster )
+ {
+ FT_Memory memory = (FT_Memory)raster->memory;
+ FT_FREE( raster );
+ }
+
+
+#endif /* _STANDALONE_ */
+
+
+ static void
+ ft_black_reset( TRaster_Instance* raster,
+ const char* pool_base,
+ long pool_size )
+ {
+ if ( raster && pool_base && pool_size >= 4096 )
+ {
+ /* save the pool */
+ raster->buff = (PLong)pool_base;
+ raster->sizeBuff = raster->buff + pool_size / sizeof ( Long );
+ }
+ }
+
+
+ static void
+ ft_black_set_mode( TRaster_Instance* raster,
+ unsigned long mode,
+ const char* palette )
+ {
+#ifdef FT_RASTER_OPTION_ANTI_ALIASING
+
+ if ( mode == FT_MAKE_TAG( 'p', 'a', 'l', '5' ) )
+ {
+ /* set 5-levels gray palette */
+ raster->grays[0] = palette[0];
+ raster->grays[1] = palette[1];
+ raster->grays[2] = palette[2];
+ raster->grays[3] = palette[3];
+ raster->grays[4] = palette[4];
+ }
+
+#else
+
+ FT_UNUSED( raster );
+ FT_UNUSED( mode );
+ FT_UNUSED( palette );
+
+#endif
+ }
+
+
+ static int
+ ft_black_render( TRaster_Instance* raster,
+ FT_Raster_Params* params )
+ {
+ FT_Outline* outline = (FT_Outline*)params->source;
+ FT_Bitmap* target_map = params->target;
+
+
+ if ( !raster || !raster->buff || !raster->sizeBuff )
+ return Raster_Err_Not_Ini;
+
+ /* return immediately if the outline is empty */
+ if ( outline->n_points == 0 || outline->n_contours <= 0 )
+ return Raster_Err_None;
+
+ if ( !outline || !outline->contours || !outline->points )
+ return Raster_Err_Invalid;
+
+ if ( outline->n_points != outline->contours[outline->n_contours - 1] + 1 )
+ return Raster_Err_Invalid;
+
+ /* this version of the raster does not support direct rendering, sorry */
+ if ( params->flags & FT_RASTER_FLAG_DIRECT )
+ return Raster_Err_Unsupported;
+
+ if ( !target_map || !target_map->buffer )
+ return Raster_Err_Invalid;
+
+ ras.outline = *outline;
+ ras.target = *target_map;
+
+ return ( ( params->flags & FT_RASTER_FLAG_AA )
+ ? Render_Gray_Glyph( raster )
+ : Render_Glyph( raster ) );
+ }
+
+
+ const FT_Raster_Funcs ft_standard_raster =
+ {
+ FT_GLYPH_FORMAT_OUTLINE,
+ (FT_Raster_New_Func) ft_black_new,
+ (FT_Raster_Reset_Func) ft_black_reset,
+ (FT_Raster_Set_Mode_Func)ft_black_set_mode,
+ (FT_Raster_Render_Func) ft_black_render,
+ (FT_Raster_Done_Func) ft_black_done
+ };
+
+
+/* END */
--- /dev/null
+++ b/libfreetype/ftraster.h
@@ -1,0 +1,46 @@
+/***************************************************************************/
+/* */
+/* ftraster.h */
+/* */
+/* The FreeType glyph rasterizer (specification). */
+/* */
+/* Copyright 1996-2001 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used */
+/* modified and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+
+#ifndef __FTRASTER_H__
+#define __FTRASTER_H__
+
+
+#include <ft2build.h>
+#include FT_CONFIG_CONFIG_H
+#include FT_IMAGE_H
+
+
+FT_BEGIN_HEADER
+
+
+ /*************************************************************************/
+ /* */
+ /* Uncomment the following line if you are using ftraster.c as a */
+ /* standalone module, fully independent of FreeType. */
+ /* */
+/* #define _STANDALONE_ */
+
+ FT_EXPORT_VAR( const FT_Raster_Funcs ) ft_standard_raster;
+
+
+FT_END_HEADER
+
+#endif /* __FTRASTER_H__ */
+
+
+/* END */
--- /dev/null
+++ b/libfreetype/ftrend1.c
@@ -1,0 +1,273 @@
+/***************************************************************************/
+/* */
+/* ftrend1.c */
+/* */
+/* The FreeType glyph rasterizer interface (body). */
+/* */
+/* Copyright 1996-2001, 2002 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+
+#include <ft2build.h>
+#include FT_INTERNAL_OBJECTS_H
+#include FT_OUTLINE_H
+#include "ftrend1.h"
+#include "ftraster.h"
+
+#include "rasterrs.h"
+
+
+ /* initialize renderer -- init its raster */
+ static FT_Error
+ ft_raster1_init( FT_Renderer render )
+ {
+ FT_Library library = FT_MODULE_LIBRARY( render );
+
+
+ render->clazz->raster_class->raster_reset( render->raster,
+ library->raster_pool,
+ library->raster_pool_size );
+
+ return Raster_Err_Ok;
+ }
+
+
+ /* set render-specific mode */
+ static FT_Error
+ ft_raster1_set_mode( FT_Renderer render,
+ FT_ULong mode_tag,
+ FT_Pointer data )
+ {
+ /* we simply pass it to the raster */
+ return render->clazz->raster_class->raster_set_mode( render->raster,
+ mode_tag,
+ data );
+ }
+
+
+ /* transform a given glyph image */
+ static FT_Error
+ ft_raster1_transform( FT_Renderer render,
+ FT_GlyphSlot slot,
+ FT_Matrix* matrix,
+ FT_Vector* delta )
+ {
+ FT_Error error = Raster_Err_Ok;
+
+
+ if ( slot->format != render->glyph_format )
+ {
+ error = Raster_Err_Invalid_Argument;
+ goto Exit;
+ }
+
+ if ( matrix )
+ FT_Outline_Transform( &slot->outline, matrix );
+
+ if ( delta )
+ FT_Outline_Translate( &slot->outline, delta->x, delta->y );
+
+ Exit:
+ return error;
+ }
+
+
+ /* return the glyph's control box */
+ static void
+ ft_raster1_get_cbox( FT_Renderer render,
+ FT_GlyphSlot slot,
+ FT_BBox* cbox )
+ {
+ FT_MEM_ZERO( cbox, sizeof ( *cbox ) );
+
+ if ( slot->format == render->glyph_format )
+ FT_Outline_Get_CBox( &slot->outline, cbox );
+ }
+
+
+ /* convert a slot's glyph image into a bitmap */
+ static FT_Error
+ ft_raster1_render( FT_Renderer render,
+ FT_GlyphSlot slot,
+ FT_Render_Mode mode,
+ FT_Vector* origin )
+ {
+ FT_Error error;
+ FT_Outline* outline;
+ FT_BBox cbox;
+ FT_UInt width, height, pitch;
+ FT_Bitmap* bitmap;
+ FT_Memory memory;
+
+ FT_Raster_Params params;
+
+
+ /* check glyph image format */
+ if ( slot->format != render->glyph_format )
+ {
+ error = Raster_Err_Invalid_Argument;
+ goto Exit;
+ }
+
+ /* check rendering mode */
+ if ( mode != FT_RENDER_MODE_MONO )
+ {
+ /* raster1 is only capable of producing monochrome bitmaps */
+ if ( render->clazz == &ft_raster1_renderer_class )
+ return Raster_Err_Cannot_Render_Glyph;
+ }
+ else
+ {
+ /* raster5 is only capable of producing 5-gray-levels bitmaps */
+ if ( render->clazz == &ft_raster5_renderer_class )
+ return Raster_Err_Cannot_Render_Glyph;
+ }
+
+ outline = &slot->outline;
+
+ /* translate the outline to the new origin if needed */
+ if ( origin )
+ FT_Outline_Translate( outline, origin->x, origin->y );
+
+ /* compute the control box, and grid fit it */
+ FT_Outline_Get_CBox( outline, &cbox );
+
+ cbox.xMin &= -64;
+ cbox.yMin &= -64;
+ cbox.xMax = ( cbox.xMax + 63 ) & -64;
+ cbox.yMax = ( cbox.yMax + 63 ) & -64;
+
+ width = (FT_UInt)( ( cbox.xMax - cbox.xMin ) >> 6 );
+ height = (FT_UInt)( ( cbox.yMax - cbox.yMin ) >> 6 );
+ bitmap = &slot->bitmap;
+ memory = render->root.memory;
+
+ /* release old bitmap buffer */
+ if ( slot->flags & FT_GLYPH_OWN_BITMAP )
+ {
+ FT_FREE( bitmap->buffer );
+ slot->flags &= ~FT_GLYPH_OWN_BITMAP;
+ }
+
+ /* allocate new one, depends on pixel format */
+ if ( !( mode & FT_RENDER_MODE_MONO ) )
+ {
+ /* we pad to 32 bits, only for backwards compatibility with FT 1.x */
+ pitch = ( width + 3 ) & -4;
+ bitmap->pixel_mode = FT_PIXEL_MODE_GRAY;
+ bitmap->num_grays = 256;
+ }
+ else
+ {
+ pitch = ( ( width + 15 ) >> 4 ) << 1;
+ bitmap->pixel_mode = FT_PIXEL_MODE_MONO;
+ }
+
+ bitmap->width = width;
+ bitmap->rows = height;
+ bitmap->pitch = pitch;
+
+ if ( FT_ALLOC( bitmap->buffer, (FT_ULong)pitch * height ) )
+ goto Exit;
+
+ slot->flags |= FT_GLYPH_OWN_BITMAP;
+
+ /* translate outline to render it into the bitmap */
+ FT_Outline_Translate( outline, -cbox.xMin, -cbox.yMin );
+
+ /* set up parameters */
+ params.target = bitmap;
+ params.source = outline;
+ params.flags = 0;
+
+ if ( bitmap->pixel_mode == FT_PIXEL_MODE_GRAY )
+ params.flags |= FT_RASTER_FLAG_AA;
+
+ /* render outline into the bitmap */
+ error = render->raster_render( render->raster, ¶ms );
+
+ FT_Outline_Translate( outline, cbox.xMin, cbox.yMin );
+
+ if ( error )
+ goto Exit;
+
+ slot->format = FT_GLYPH_FORMAT_BITMAP;
+ slot->bitmap_left = (FT_Int)( cbox.xMin >> 6 );
+ slot->bitmap_top = (FT_Int)( cbox.yMax >> 6 );
+
+ Exit:
+ return error;
+ }
+
+
+ FT_CALLBACK_TABLE_DEF
+ const FT_Renderer_Class ft_raster1_renderer_class =
+ {
+ {
+ ft_module_renderer,
+ sizeof( FT_RendererRec ),
+
+ "raster1",
+ 0x10000L,
+ 0x20000L,
+
+ 0, /* module specific interface */
+
+ (FT_Module_Constructor)ft_raster1_init,
+ (FT_Module_Destructor) 0,
+ (FT_Module_Requester) 0
+ },
+
+ FT_GLYPH_FORMAT_OUTLINE,
+
+ (FT_Renderer_RenderFunc) ft_raster1_render,
+ (FT_Renderer_TransformFunc)ft_raster1_transform,
+ (FT_Renderer_GetCBoxFunc) ft_raster1_get_cbox,
+ (FT_Renderer_SetModeFunc) ft_raster1_set_mode,
+
+ (FT_Raster_Funcs*) &ft_standard_raster
+ };
+
+
+ /* This renderer is _NOT_ part of the default modules; you will need */
+ /* to register it by hand in your application. It should only be */
+ /* used for backwards-compatibility with FT 1.x anyway. */
+ /* */
+ FT_CALLBACK_TABLE_DEF
+ const FT_Renderer_Class ft_raster5_renderer_class =
+ {
+ {
+ ft_module_renderer,
+ sizeof( FT_RendererRec ),
+
+ "raster5",
+ 0x10000L,
+ 0x20000L,
+
+ 0, /* module specific interface */
+
+ (FT_Module_Constructor)ft_raster1_init,
+ (FT_Module_Destructor) 0,
+ (FT_Module_Requester) 0
+ },
+
+ FT_GLYPH_FORMAT_OUTLINE,
+
+ (FT_Renderer_RenderFunc) ft_raster1_render,
+ (FT_Renderer_TransformFunc)ft_raster1_transform,
+ (FT_Renderer_GetCBoxFunc) ft_raster1_get_cbox,
+ (FT_Renderer_SetModeFunc) ft_raster1_set_mode,
+
+ (FT_Raster_Funcs*) &ft_standard_raster
+ };
+
+
+/* END */
--- /dev/null
+++ b/libfreetype/ftrend1.h
@@ -1,0 +1,44 @@
+/***************************************************************************/
+/* */
+/* ftrend1.h */
+/* */
+/* The FreeType glyph rasterizer interface (specification). */
+/* */
+/* Copyright 1996-2001 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+
+#ifndef __FTREND1_H__
+#define __FTREND1_H__
+
+
+#include <ft2build.h>
+#include FT_RENDER_H
+
+
+FT_BEGIN_HEADER
+
+
+ FT_EXPORT_VAR( const FT_Renderer_Class ) ft_raster1_renderer_class;
+
+ /* this renderer is _NOT_ part of the default modules, you'll need */
+ /* to register it by hand in your application. It should only be */
+ /* used for backwards-compatibility with FT 1.x anyway. */
+ /* */
+ FT_EXPORT_VAR( const FT_Renderer_Class ) ft_raster5_renderer_class;
+
+
+FT_END_HEADER
+
+#endif /* __FTREND1_H__ */
+
+
+/* END */
--- /dev/null
+++ b/libfreetype/ftsmerrs.h
@@ -1,0 +1,41 @@
+/***************************************************************************/
+/* */
+/* ftsmerrs.h */
+/* */
+/* smooth renderer error codes (specification only). */
+/* */
+/* Copyright 2001 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+
+ /*************************************************************************/
+ /* */
+ /* This file is used to define the smooth renderer error enumeration */
+ /* constants. */
+ /* */
+ /*************************************************************************/
+
+#ifndef __FTSMERRS_H__
+#define __FTSMERRS_H__
+
+#include FT_MODULE_ERRORS_H
+
+#undef __FTERRORS_H__
+
+#define FT_ERR_PREFIX Smooth_Err_
+#define FT_ERR_BASE FT_Mod_Err_Smooth
+
+#include FT_ERRORS_H
+
+#endif /* __FTSMERRS_H__ */
+
+
+/* END */
--- /dev/null
+++ b/libfreetype/ftsmooth.c
@@ -1,0 +1,371 @@
+/***************************************************************************/
+/* */
+/* ftsmooth.c */
+/* */
+/* Anti-aliasing renderer interface (body). */
+/* */
+/* Copyright 2000-2001, 2002 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+
+#include <ft2build.h>
+#include FT_INTERNAL_OBJECTS_H
+#include FT_OUTLINE_H
+#include "ftsmooth.h"
+#include "ftgrays.h"
+
+#include "ftsmerrs.h"
+
+
+ /* initialize renderer -- init its raster */
+ static FT_Error
+ ft_smooth_init( FT_Renderer render )
+ {
+ FT_Library library = FT_MODULE_LIBRARY( render );
+
+
+ render->clazz->raster_class->raster_reset( render->raster,
+ library->raster_pool,
+ library->raster_pool_size );
+
+ return 0;
+ }
+
+
+ /* sets render-specific mode */
+ static FT_Error
+ ft_smooth_set_mode( FT_Renderer render,
+ FT_ULong mode_tag,
+ FT_Pointer data )
+ {
+ /* we simply pass it to the raster */
+ return render->clazz->raster_class->raster_set_mode( render->raster,
+ mode_tag,
+ data );
+ }
+
+ /* transform a given glyph image */
+ static FT_Error
+ ft_smooth_transform( FT_Renderer render,
+ FT_GlyphSlot slot,
+ FT_Matrix* matrix,
+ FT_Vector* delta )
+ {
+ FT_Error error = Smooth_Err_Ok;
+
+
+ if ( slot->format != render->glyph_format )
+ {
+ error = Smooth_Err_Invalid_Argument;
+ goto Exit;
+ }
+
+ if ( matrix )
+ FT_Outline_Transform( &slot->outline, matrix );
+
+ if ( delta )
+ FT_Outline_Translate( &slot->outline, delta->x, delta->y );
+
+ Exit:
+ return error;
+ }
+
+
+ /* return the glyph's control box */
+ static void
+ ft_smooth_get_cbox( FT_Renderer render,
+ FT_GlyphSlot slot,
+ FT_BBox* cbox )
+ {
+ FT_MEM_ZERO( cbox, sizeof ( *cbox ) );
+
+ if ( slot->format == render->glyph_format )
+ FT_Outline_Get_CBox( &slot->outline, cbox );
+ }
+
+
+ /* convert a slot's glyph image into a bitmap */
+ static FT_Error
+ ft_smooth_render_generic( FT_Renderer render,
+ FT_GlyphSlot slot,
+ FT_Render_Mode mode,
+ FT_Vector* origin,
+ FT_Render_Mode required_mode,
+ FT_Int hmul,
+ FT_Int vmul )
+ {
+ FT_Error error;
+ FT_Outline* outline = NULL;
+ FT_BBox cbox;
+ FT_UInt width, height, pitch;
+ FT_Bitmap* bitmap;
+ FT_Memory memory;
+
+ FT_Raster_Params params;
+
+
+ /* check glyph image format */
+ if ( slot->format != render->glyph_format )
+ {
+ error = Smooth_Err_Invalid_Argument;
+ goto Exit;
+ }
+
+ /* check mode */
+ if ( mode != required_mode )
+ return Smooth_Err_Cannot_Render_Glyph;
+
+ outline = &slot->outline;
+
+ /* translate the outline to the new origin if needed */
+ if ( origin )
+ FT_Outline_Translate( outline, origin->x, origin->y );
+
+ /* compute the control box, and grid fit it */
+ FT_Outline_Get_CBox( outline, &cbox );
+
+ cbox.xMin &= -64;
+ cbox.yMin &= -64;
+ cbox.xMax = ( cbox.xMax + 63 ) & -64;
+ cbox.yMax = ( cbox.yMax + 63 ) & -64;
+
+ width = ( cbox.xMax - cbox.xMin ) >> 6;
+ height = ( cbox.yMax - cbox.yMin ) >> 6;
+ bitmap = &slot->bitmap;
+ memory = render->root.memory;
+
+ /* release old bitmap buffer */
+ if ( slot->flags & FT_GLYPH_OWN_BITMAP )
+ {
+ FT_FREE( bitmap->buffer );
+ slot->flags &= ~FT_GLYPH_OWN_BITMAP;
+ }
+
+ /* allocate new one, depends on pixel format */
+ pitch = width;
+ if ( hmul )
+ {
+ width = width * hmul;
+ pitch = ( width + 3 ) & -4;
+ }
+
+ if ( vmul )
+ height *= vmul;
+
+ bitmap->pixel_mode = FT_PIXEL_MODE_GRAY;
+ bitmap->num_grays = 256;
+ bitmap->width = width;
+ bitmap->rows = height;
+ bitmap->pitch = pitch;
+
+ if ( FT_ALLOC( bitmap->buffer, (FT_ULong)pitch * height ) )
+ goto Exit;
+
+ slot->flags |= FT_GLYPH_OWN_BITMAP;
+
+ /* translate outline to render it into the bitmap */
+ FT_Outline_Translate( outline, -cbox.xMin, -cbox.yMin );
+
+ /* set up parameters */
+ params.target = bitmap;
+ params.source = outline;
+ params.flags = FT_RASTER_FLAG_AA;
+
+ /* implode outline if needed */
+ {
+ FT_Int n;
+ FT_Vector* vec;
+
+
+ if ( hmul )
+ for ( vec = outline->points, n = 0; n < outline->n_points; n++, vec++ )
+ vec->x *= hmul;
+
+ if ( vmul )
+ for ( vec = outline->points, n = 0; n < outline->n_points; n++, vec++ )
+ vec->y *= vmul;
+ }
+
+ /* render outline into the bitmap */
+ error = render->raster_render( render->raster, ¶ms );
+
+ /* deflate outline if needed */
+ {
+ FT_Int n;
+ FT_Vector* vec;
+
+
+ if ( hmul )
+ for ( vec = outline->points, n = 0; n < outline->n_points; n++, vec++ )
+ vec->x /= hmul;
+
+ if ( vmul )
+ for ( vec = outline->points, n = 0; n < outline->n_points; n++, vec++ )
+ vec->y /= vmul;
+ }
+
+ FT_Outline_Translate( outline, cbox.xMin, cbox.yMin );
+
+ if ( error )
+ goto Exit;
+
+ slot->format = FT_GLYPH_FORMAT_BITMAP;
+ slot->bitmap_left = (FT_Int)( cbox.xMin >> 6 );
+ slot->bitmap_top = (FT_Int)( cbox.yMax >> 6 );
+
+ Exit:
+ if ( outline && origin )
+ FT_Outline_Translate( outline, -origin->x, -origin->y );
+
+ return error;
+ }
+
+
+ /* convert a slot's glyph image into a bitmap */
+ static FT_Error
+ ft_smooth_render( FT_Renderer render,
+ FT_GlyphSlot slot,
+ FT_Render_Mode mode,
+ FT_Vector* origin )
+ {
+ return ft_smooth_render_generic( render, slot, mode, origin,
+ FT_RENDER_MODE_NORMAL,
+ 0, 0 );
+ }
+
+
+ /* convert a slot's glyph image into a horizontal LCD bitmap */
+ static FT_Error
+ ft_smooth_render_lcd( FT_Renderer render,
+ FT_GlyphSlot slot,
+ FT_Render_Mode mode,
+ FT_Vector* origin )
+ {
+ FT_Error error;
+
+ error = ft_smooth_render_generic( render, slot, mode, origin,
+ FT_RENDER_MODE_LCD,
+ 3, 0 );
+ if ( !error )
+ slot->bitmap.pixel_mode = FT_PIXEL_MODE_LCD;
+
+ return error;
+ }
+
+
+ /* convert a slot's glyph image into a vertical LCD bitmap */
+ static FT_Error
+ ft_smooth_render_lcd_v( FT_Renderer render,
+ FT_GlyphSlot slot,
+ FT_Render_Mode mode,
+ FT_Vector* origin )
+ {
+ FT_Error error;
+
+ error = ft_smooth_render_generic( render, slot, mode, origin,
+ FT_RENDER_MODE_LCD_V,
+ 0, 3 );
+ if ( !error )
+ slot->bitmap.pixel_mode = FT_PIXEL_MODE_LCD_V;
+
+ return error;
+ }
+
+
+ FT_CALLBACK_TABLE_DEF
+ const FT_Renderer_Class ft_smooth_renderer_class =
+ {
+ {
+ ft_module_renderer,
+ sizeof( FT_RendererRec ),
+
+ "smooth",
+ 0x10000L,
+ 0x20000L,
+
+ 0, /* module specific interface */
+
+ (FT_Module_Constructor)ft_smooth_init,
+ (FT_Module_Destructor) 0,
+ (FT_Module_Requester) 0
+ },
+
+ FT_GLYPH_FORMAT_OUTLINE,
+
+ (FT_Renderer_RenderFunc) ft_smooth_render,
+ (FT_Renderer_TransformFunc)ft_smooth_transform,
+ (FT_Renderer_GetCBoxFunc) ft_smooth_get_cbox,
+ (FT_Renderer_SetModeFunc) ft_smooth_set_mode,
+
+ (FT_Raster_Funcs*) &ft_grays_raster
+ };
+
+
+ FT_CALLBACK_TABLE_DEF
+ const FT_Renderer_Class ft_smooth_lcd_renderer_class =
+ {
+ {
+ ft_module_renderer,
+ sizeof( FT_RendererRec ),
+
+ "smooth-lcd",
+ 0x10000L,
+ 0x20000L,
+
+ 0, /* module specific interface */
+
+ (FT_Module_Constructor)ft_smooth_init,
+ (FT_Module_Destructor) 0,
+ (FT_Module_Requester) 0
+ },
+
+ FT_GLYPH_FORMAT_OUTLINE,
+
+ (FT_Renderer_RenderFunc) ft_smooth_render_lcd,
+ (FT_Renderer_TransformFunc)ft_smooth_transform,
+ (FT_Renderer_GetCBoxFunc) ft_smooth_get_cbox,
+ (FT_Renderer_SetModeFunc) ft_smooth_set_mode,
+
+ (FT_Raster_Funcs*) &ft_grays_raster
+ };
+
+
+
+ FT_CALLBACK_TABLE_DEF
+ const FT_Renderer_Class ft_smooth_lcdv_renderer_class =
+ {
+ {
+ ft_module_renderer,
+ sizeof( FT_RendererRec ),
+
+ "smooth-lcdv",
+ 0x10000L,
+ 0x20000L,
+
+ 0, /* module specific interface */
+
+ (FT_Module_Constructor)ft_smooth_init,
+ (FT_Module_Destructor) 0,
+ (FT_Module_Requester) 0
+ },
+
+ FT_GLYPH_FORMAT_OUTLINE,
+
+ (FT_Renderer_RenderFunc) ft_smooth_render_lcd_v,
+ (FT_Renderer_TransformFunc)ft_smooth_transform,
+ (FT_Renderer_GetCBoxFunc) ft_smooth_get_cbox,
+ (FT_Renderer_SetModeFunc) ft_smooth_set_mode,
+
+ (FT_Raster_Funcs*) &ft_grays_raster
+ };
+
+
+/* END */
--- /dev/null
+++ b/libfreetype/ftsmooth.h
@@ -1,0 +1,49 @@
+/***************************************************************************/
+/* */
+/* ftsmooth.h */
+/* */
+/* Anti-aliasing renderer interface (specification). */
+/* */
+/* Copyright 1996-2001 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+
+#ifndef __FTSMOOTH_H__
+#define __FTSMOOTH_H__
+
+
+#include <ft2build.h>
+#include FT_RENDER_H
+
+
+FT_BEGIN_HEADER
+
+
+#ifndef FT_CONFIG_OPTION_NO_STD_RASTER
+ FT_EXPORT_VAR( const FT_Renderer_Class ) ft_std_renderer_class;
+#endif
+
+#ifndef FT_CONFIG_OPTION_NO_SMOOTH_RASTER
+ FT_EXPORT_VAR( const FT_Renderer_Class ) ft_smooth_renderer_class;
+
+ FT_EXPORT_VAR( const FT_Renderer_Class ) ft_smooth_lcd_renderer_class;
+
+ FT_EXPORT_VAR( const FT_Renderer_Class ) ft_smooth_lcd_v_renderer_class;
+#endif
+
+
+
+FT_END_HEADER
+
+#endif /* __FTSMOOTH_H__ */
+
+
+/* END */
--- /dev/null
+++ b/libfreetype/ftstream.c
@@ -1,0 +1,803 @@
+/***************************************************************************/
+/* */
+/* ftstream.c */
+/* */
+/* I/O stream support (body). */
+/* */
+/* Copyright 2000-2001, 2002 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+
+#include <ft2build.h>
+#include FT_INTERNAL_STREAM_H
+#include FT_INTERNAL_DEBUG_H
+
+
+ /*************************************************************************/
+ /* */
+ /* The macro FT_COMPONENT is used in trace mode. It is an implicit */
+ /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log */
+ /* messages during execution. */
+ /* */
+#undef FT_COMPONENT
+#define FT_COMPONENT trace_stream
+
+
+ FT_BASE_DEF( void )
+ FT_Stream_OpenMemory( FT_Stream stream,
+ const FT_Byte* base,
+ FT_ULong size )
+ {
+ stream->base = (FT_Byte*) base;
+ stream->size = size;
+ stream->pos = 0;
+ stream->cursor = 0;
+ stream->read = 0;
+ stream->close = 0;
+ }
+
+
+ FT_BASE_DEF( void )
+ FT_Stream_Close( FT_Stream stream )
+ {
+ if ( stream && stream->close )
+ {
+ stream->close( stream );
+ stream->close = NULL;
+ }
+ }
+
+
+ FT_BASE_DEF( FT_Error )
+ FT_Stream_Seek( FT_Stream stream,
+ FT_ULong pos )
+ {
+ FT_Error error = FT_Err_Ok;
+
+
+ stream->pos = pos;
+
+ if ( stream->read )
+ {
+ if ( stream->read( stream, pos, 0, 0 ) )
+ {
+ FT_ERROR(( "FT_Stream_Seek: invalid i/o; pos = 0x%lx, size = 0x%lx\n",
+ pos, stream->size ));
+
+ error = FT_Err_Invalid_Stream_Operation;
+ }
+ }
+ /* note that seeking to the first position after the file is valid */
+ else if ( pos > stream->size )
+ {
+ FT_ERROR(( "FT_Stream_Seek: invalid i/o; pos = 0x%lx, size = 0x%lx\n",
+ pos, stream->size ));
+
+ error = FT_Err_Invalid_Stream_Operation;
+ }
+
+ return error;
+ }
+
+
+ FT_BASE_DEF( FT_Error )
+ FT_Stream_Skip( FT_Stream stream,
+ FT_Long distance )
+ {
+ return FT_Stream_Seek( stream, (FT_ULong)( stream->pos + distance ) );
+ }
+
+
+ FT_BASE_DEF( FT_Long )
+ FT_Stream_Pos( FT_Stream stream )
+ {
+ return stream->pos;
+ }
+
+
+ FT_BASE_DEF( FT_Error )
+ FT_Stream_Read( FT_Stream stream,
+ FT_Byte* buffer,
+ FT_ULong count )
+ {
+ return FT_Stream_ReadAt( stream, stream->pos, buffer, count );
+ }
+
+
+ FT_BASE_DEF( FT_Error )
+ FT_Stream_ReadAt( FT_Stream stream,
+ FT_ULong pos,
+ FT_Byte* buffer,
+ FT_ULong count )
+ {
+ FT_Error error = FT_Err_Ok;
+ FT_ULong read_bytes;
+
+
+ if ( pos >= stream->size )
+ {
+ FT_ERROR(( "FT_Stream_ReadAt: invalid i/o; pos = 0x%lx, size = 0x%lx\n",
+ pos, stream->size ));
+
+ return FT_Err_Invalid_Stream_Operation;
+ }
+
+ if ( stream->read )
+ read_bytes = stream->read( stream, pos, buffer, count );
+ else
+ {
+ read_bytes = stream->size - pos;
+ if ( read_bytes > count )
+ read_bytes = count;
+
+ FT_MEM_COPY( buffer, stream->base + pos, read_bytes );
+ }
+
+ stream->pos = pos + read_bytes;
+
+ if ( read_bytes < count )
+ {
+ FT_ERROR(( "FT_Stream_ReadAt:" ));
+ FT_ERROR(( " invalid read; expected %lu bytes, got %lu\n",
+ count, read_bytes ));
+
+ error = FT_Err_Invalid_Stream_Operation;
+ }
+
+ return error;
+ }
+
+
+ FT_BASE_DEF( FT_Error )
+ FT_Stream_ExtractFrame( FT_Stream stream,
+ FT_ULong count,
+ FT_Byte** pbytes )
+ {
+ FT_Error error;
+
+
+ error = FT_Stream_EnterFrame( stream, count );
+ if ( !error )
+ {
+ *pbytes = (FT_Byte*)stream->cursor;
+
+ /* equivalent to FT_Stream_ExitFrame(), with no memory block release */
+ stream->cursor = 0;
+ stream->limit = 0;
+ }
+
+ return error;
+ }
+
+
+ FT_BASE_DEF( void )
+ FT_Stream_ReleaseFrame( FT_Stream stream,
+ FT_Byte** pbytes )
+ {
+ if ( stream->read )
+ {
+ FT_Memory memory = stream->memory;
+
+
+ FT_FREE( *pbytes );
+ }
+ *pbytes = 0;
+ }
+
+
+ FT_BASE_DEF( FT_Error )
+ FT_Stream_EnterFrame( FT_Stream stream,
+ FT_ULong count )
+ {
+ FT_Error error = FT_Err_Ok;
+ FT_ULong read_bytes;
+
+
+ /* check for nested frame access */
+ FT_ASSERT( stream && stream->cursor == 0 );
+
+ if ( stream->read )
+ {
+ /* allocate the frame in memory */
+ FT_Memory memory = stream->memory;
+
+
+ if ( FT_ALLOC( stream->base, count ) )
+ goto Exit;
+
+ /* read it */
+ read_bytes = stream->read( stream, stream->pos,
+ stream->base, count );
+ if ( read_bytes < count )
+ {
+ FT_ERROR(( "FT_Stream_EnterFrame:" ));
+ FT_ERROR(( " invalid read; expected %lu bytes, got %lu\n",
+ count, read_bytes ));
+
+ FT_FREE( stream->base );
+ error = FT_Err_Invalid_Stream_Operation;
+ }
+ stream->cursor = stream->base;
+ stream->limit = stream->cursor + count;
+ stream->pos += read_bytes;
+ }
+ else
+ {
+ /* check current and new position */
+ if ( stream->pos >= stream->size ||
+ stream->pos + count > stream->size )
+ {
+ FT_ERROR(( "FT_Stream_EnterFrame:" ));
+ FT_ERROR(( " invalid i/o; pos = 0x%lx, count = %lu, size = 0x%lx\n",
+ stream->pos, count, stream->size ));
+
+ error = FT_Err_Invalid_Stream_Operation;
+ goto Exit;
+ }
+
+ /* set cursor */
+ stream->cursor = stream->base + stream->pos;
+ stream->limit = stream->cursor + count;
+ stream->pos += count;
+ }
+
+ Exit:
+ return error;
+ }
+
+
+ FT_BASE_DEF( void )
+ FT_Stream_ExitFrame( FT_Stream stream )
+ {
+ /* IMPORTANT: The assertion stream->cursor != 0 was removed, given */
+ /* that it is possible to access a frame of length 0 in */
+ /* some weird fonts (usually, when accessing an array of */
+ /* 0 records, like in some strange kern tables). */
+ /* */
+ /* In this case, the loader code handles the 0-length table */
+ /* gracefully; however, stream.cursor is really set to 0 by the */
+ /* FT_Stream_EnterFrame() call, and this is not an error. */
+ /* */
+ FT_ASSERT( stream );
+
+ if ( stream->read )
+ {
+ FT_Memory memory = stream->memory;
+
+
+ FT_FREE( stream->base );
+ }
+ stream->cursor = 0;
+ stream->limit = 0;
+ }
+
+
+ FT_BASE_DEF( FT_Char )
+ FT_Stream_GetChar( FT_Stream stream )
+ {
+ FT_Char result;
+
+
+ FT_ASSERT( stream && stream->cursor );
+
+ result = 0;
+ if ( stream->cursor < stream->limit )
+ result = *stream->cursor++;
+
+ return result;
+ }
+
+
+ FT_BASE_DEF( FT_Short )
+ FT_Stream_GetShort( FT_Stream stream )
+ {
+ FT_Byte* p;
+ FT_Short result;
+
+
+ FT_ASSERT( stream && stream->cursor );
+
+ result = 0;
+ p = stream->cursor;
+ if ( p + 1 < stream->limit )
+ result = FT_NEXT_SHORT( p );
+ stream->cursor = p;
+
+ return result;
+ }
+
+
+ FT_BASE_DEF( FT_Short )
+ FT_Stream_GetShortLE( FT_Stream stream )
+ {
+ FT_Byte* p;
+ FT_Short result;
+
+
+ FT_ASSERT( stream && stream->cursor );
+
+ result = 0;
+ p = stream->cursor;
+ if ( p + 1 < stream->limit )
+ result = FT_NEXT_SHORT_LE( p );
+ stream->cursor = p;
+
+ return result;
+ }
+
+
+ FT_BASE_DEF( FT_Long )
+ FT_Stream_GetOffset( FT_Stream stream )
+ {
+ FT_Byte* p;
+ FT_Long result;
+
+
+ FT_ASSERT( stream && stream->cursor );
+
+ result = 0;
+ p = stream->cursor;
+ if ( p + 2 < stream->limit )
+ result = FT_NEXT_OFF3( p );
+ stream->cursor = p;
+ return result;
+ }
+
+
+ FT_BASE_DEF( FT_Long )
+ FT_Stream_GetLong( FT_Stream stream )
+ {
+ FT_Byte* p;
+ FT_Long result;
+
+
+ FT_ASSERT( stream && stream->cursor );
+
+ result = 0;
+ p = stream->cursor;
+ if ( p + 3 < stream->limit )
+ result = FT_NEXT_LONG( p );
+ stream->cursor = p;
+ return result;
+ }
+
+
+ FT_BASE_DEF( FT_Long )
+ FT_Stream_GetLongLE( FT_Stream stream )
+ {
+ FT_Byte* p;
+ FT_Long result;
+
+
+ FT_ASSERT( stream && stream->cursor );
+
+ result = 0;
+ p = stream->cursor;
+ if ( p + 3 < stream->limit )
+ result = FT_NEXT_LONG_LE( p );
+ stream->cursor = p;
+ return result;
+ }
+
+
+ FT_BASE_DEF( FT_Char )
+ FT_Stream_ReadChar( FT_Stream stream,
+ FT_Error* error )
+ {
+ FT_Byte result = 0;
+
+
+ FT_ASSERT( stream );
+
+ *error = FT_Err_Ok;
+
+ if ( stream->read )
+ {
+ if ( stream->read( stream, stream->pos, &result, 1L ) != 1L )
+ goto Fail;
+ }
+ else
+ {
+ if ( stream->pos < stream->size )
+ result = stream->base[stream->pos];
+ else
+ goto Fail;
+ }
+ stream->pos++;
+
+ return result;
+
+ Fail:
+ *error = FT_Err_Invalid_Stream_Operation;
+ FT_ERROR(( "FT_Stream_ReadChar: invalid i/o; pos = 0x%lx, size = 0x%lx\n",
+ stream->pos, stream->size ));
+
+ return 0;
+ }
+
+
+ FT_BASE_DEF( FT_Short )
+ FT_Stream_ReadShort( FT_Stream stream,
+ FT_Error* error )
+ {
+ FT_Byte reads[2];
+ FT_Byte* p = 0;
+ FT_Short result = 0;
+
+
+ FT_ASSERT( stream );
+
+ *error = FT_Err_Ok;
+
+ if ( stream->pos + 1 < stream->size )
+ {
+ if ( stream->read )
+ {
+ if ( stream->read( stream, stream->pos, reads, 2L ) != 2L )
+ goto Fail;
+
+ p = reads;
+ }
+ else
+ {
+ p = stream->base + stream->pos;
+ }
+
+ if ( p )
+ result = FT_NEXT_SHORT( p );
+ }
+ else
+ goto Fail;
+
+ stream->pos += 2;
+
+ return result;
+
+ Fail:
+ *error = FT_Err_Invalid_Stream_Operation;
+ FT_ERROR(( "FT_Stream_ReadShort:" ));
+ FT_ERROR(( " invalid i/o; pos = 0x%lx, size = 0x%lx\n",
+ stream->pos, stream->size ));
+
+ return 0;
+ }
+
+
+ FT_BASE_DEF( FT_Short )
+ FT_Stream_ReadShortLE( FT_Stream stream,
+ FT_Error* error )
+ {
+ FT_Byte reads[2];
+ FT_Byte* p = 0;
+ FT_Short result = 0;
+
+
+ FT_ASSERT( stream );
+
+ *error = FT_Err_Ok;
+
+ if ( stream->pos + 1 < stream->size )
+ {
+ if ( stream->read )
+ {
+ if ( stream->read( stream, stream->pos, reads, 2L ) != 2L )
+ goto Fail;
+
+ p = reads;
+ }
+ else
+ {
+ p = stream->base + stream->pos;
+ }
+
+ if ( p )
+ result = FT_NEXT_SHORT_LE( p );
+ }
+ else
+ goto Fail;
+
+ stream->pos += 2;
+
+ return result;
+
+ Fail:
+ *error = FT_Err_Invalid_Stream_Operation;
+ FT_ERROR(( "FT_Stream_ReadShortLE:" ));
+ FT_ERROR(( " invalid i/o; pos = 0x%lx, size = 0x%lx\n",
+ stream->pos, stream->size ));
+
+ return 0;
+ }
+
+
+ FT_BASE_DEF( FT_Long )
+ FT_Stream_ReadOffset( FT_Stream stream,
+ FT_Error* error )
+ {
+ FT_Byte reads[3];
+ FT_Byte* p = 0;
+ FT_Long result = 0;
+
+
+ FT_ASSERT( stream );
+
+ *error = FT_Err_Ok;
+
+ if ( stream->pos + 2 < stream->size )
+ {
+ if ( stream->read )
+ {
+ if (stream->read( stream, stream->pos, reads, 3L ) != 3L )
+ goto Fail;
+
+ p = reads;
+ }
+ else
+ {
+ p = stream->base + stream->pos;
+ }
+
+ if ( p )
+ result = FT_NEXT_OFF3( p );
+ }
+ else
+ goto Fail;
+
+ stream->pos += 3;
+
+ return result;
+
+ Fail:
+ *error = FT_Err_Invalid_Stream_Operation;
+ FT_ERROR(( "FT_Stream_ReadOffset:" ));
+ FT_ERROR(( " invalid i/o; pos = 0x%lx, size = 0x%lx\n",
+ stream->pos, stream->size ));
+
+ return 0;
+ }
+
+
+ FT_BASE_DEF( FT_Long )
+ FT_Stream_ReadLong( FT_Stream stream,
+ FT_Error* error )
+ {
+ FT_Byte reads[4];
+ FT_Byte* p = 0;
+ FT_Long result = 0;
+
+
+ FT_ASSERT( stream );
+
+ *error = FT_Err_Ok;
+
+ if ( stream->pos + 3 < stream->size )
+ {
+ if ( stream->read )
+ {
+ if ( stream->read( stream, stream->pos, reads, 4L ) != 4L )
+ goto Fail;
+
+ p = reads;
+ }
+ else
+ {
+ p = stream->base + stream->pos;
+ }
+
+ if ( p )
+ result = FT_NEXT_LONG( p );
+ }
+ else
+ goto Fail;
+
+ stream->pos += 4;
+
+ return result;
+
+ Fail:
+ FT_ERROR(( "FT_Stream_ReadLong: invalid i/o; pos = 0x%lx, size = 0x%lx\n",
+ stream->pos, stream->size ));
+ *error = FT_Err_Invalid_Stream_Operation;
+
+ return 0;
+ }
+
+
+ FT_BASE_DEF( FT_Long )
+ FT_Stream_ReadLongLE( FT_Stream stream,
+ FT_Error* error )
+ {
+ FT_Byte reads[4];
+ FT_Byte* p = 0;
+ FT_Long result = 0;
+
+
+ FT_ASSERT( stream );
+
+ *error = FT_Err_Ok;
+
+ if ( stream->pos + 3 < stream->size )
+ {
+ if ( stream->read )
+ {
+ if ( stream->read( stream, stream->pos, reads, 4L ) != 4L )
+ goto Fail;
+
+ p = reads;
+ }
+ else
+ {
+ p = stream->base + stream->pos;
+ }
+
+ if ( p )
+ result = FT_NEXT_LONG_LE( p );
+ }
+ else
+ goto Fail;
+
+ stream->pos += 4;
+
+ return result;
+
+ Fail:
+ FT_ERROR(( "FT_Stream_ReadLongLE:" ));
+ FT_ERROR(( " invalid i/o; pos = 0x%lx, size = 0x%lx\n",
+ stream->pos, stream->size ));
+ *error = FT_Err_Invalid_Stream_Operation;
+
+ return 0;
+ }
+
+
+ FT_BASE_DEF( FT_Error )
+ FT_Stream_ReadFields( FT_Stream stream,
+ const FT_Frame_Field* fields,
+ void* structure )
+ {
+ FT_Error error;
+ FT_Bool frame_accessed = 0;
+ FT_Byte* cursor = stream->cursor;
+
+
+ if ( !fields || !stream )
+ return FT_Err_Invalid_Argument;
+
+ error = FT_Err_Ok;
+ do
+ {
+ FT_ULong value;
+ FT_Int sign_shift;
+ FT_Byte* p;
+
+
+ switch ( fields->value )
+ {
+ case ft_frame_start: /* access a new frame */
+ error = FT_Stream_EnterFrame( stream, fields->offset );
+ if ( error )
+ goto Exit;
+
+ frame_accessed = 1;
+ cursor = stream->cursor;
+ fields++;
+ continue; /* loop! */
+
+ case ft_frame_bytes: /* read a byte sequence */
+ case ft_frame_skip: /* skip some bytes */
+ {
+ FT_UInt len = fields->size;
+
+
+ if ( cursor + len > stream->limit )
+ {
+ error = FT_Err_Invalid_Stream_Operation;
+ goto Exit;
+ }
+
+ if ( fields->value == ft_frame_bytes )
+ {
+ p = (FT_Byte*)structure + fields->offset;
+ FT_MEM_COPY( p, cursor, len );
+ }
+ cursor += len;
+ fields++;
+ continue;
+ }
+
+ case ft_frame_byte:
+ case ft_frame_schar: /* read a single byte */
+ value = FT_NEXT_BYTE(cursor);
+ sign_shift = 24;
+ break;
+
+ case ft_frame_short_be:
+ case ft_frame_ushort_be: /* read a 2-byte big-endian short */
+ value = FT_NEXT_USHORT(cursor);
+ sign_shift = 16;
+ break;
+
+ case ft_frame_short_le:
+ case ft_frame_ushort_le: /* read a 2-byte little-endian short */
+ value = FT_NEXT_USHORT_LE(cursor);
+ sign_shift = 16;
+ break;
+
+ case ft_frame_long_be:
+ case ft_frame_ulong_be: /* read a 4-byte big-endian long */
+ value = FT_NEXT_ULONG(cursor);
+ sign_shift = 0;
+ break;
+
+ case ft_frame_long_le:
+ case ft_frame_ulong_le: /* read a 4-byte little-endian long */
+ value = FT_NEXT_ULONG_LE(cursor);
+ sign_shift = 0;
+ break;
+
+ case ft_frame_off3_be:
+ case ft_frame_uoff3_be: /* read a 3-byte big-endian long */
+ value = FT_NEXT_UOFF3(cursor);
+ sign_shift = 8;
+ break;
+
+ case ft_frame_off3_le:
+ case ft_frame_uoff3_le: /* read a 3-byte little-endian long */
+ value = FT_NEXT_UOFF3_LE(cursor);
+ sign_shift = 8;
+ break;
+
+ default:
+ /* otherwise, exit the loop */
+ stream->cursor = cursor;
+ goto Exit;
+ }
+
+ /* now, compute the signed value is necessary */
+ if ( fields->value & FT_FRAME_OP_SIGNED )
+ value = (FT_ULong)( (FT_Int32)( value << sign_shift ) >> sign_shift );
+
+ /* finally, store the value in the object */
+
+ p = (FT_Byte*)structure + fields->offset;
+ switch ( fields->size )
+ {
+ case 1:
+ *(FT_Byte*)p = (FT_Byte)value;
+ break;
+
+ case 2:
+ *(FT_UShort*)p = (FT_UShort)value;
+ break;
+
+ case 4:
+ *(FT_UInt32*)p = (FT_UInt32)value;
+ break;
+
+ default: /* for 64-bit systems */
+ *(FT_ULong*)p = (FT_ULong)value;
+ }
+
+ /* go to next field */
+ fields++;
+ }
+ while ( 1 );
+
+ Exit:
+ /* close the frame if it was opened by this read */
+ if ( frame_accessed )
+ FT_Stream_ExitFrame( stream );
+
+ return error;
+ }
+
+
+/* END */
--- /dev/null
+++ b/libfreetype/ftstroker.c
@@ -1,0 +1,1364 @@
+#include <ft2build.h>
+#include FT_STROKER_H
+#include FT_TRIGONOMETRY_H
+#include FT_INTERNAL_MEMORY_H
+#include FT_INTERNAL_DEBUG_H
+
+ /***************************************************************************/
+ /***************************************************************************/
+ /***** *****/
+ /***** BEZIER COMPUTATIONS *****/
+ /***** *****/
+ /***************************************************************************/
+ /***************************************************************************/
+
+#define FT_SMALL_CONIC_THRESHOLD (FT_ANGLE_PI/6)
+#define FT_SMALL_CUBIC_THRESHOLD (FT_ANGLE_PI/6)
+#define FT_EPSILON 2
+
+#define FT_IS_SMALL(x) ((x) > -FT_EPSILON && (x) < FT_EPSILON)
+
+ static FT_Pos
+ ft_pos_abs( FT_Pos x )
+ {
+ return x >= 0 ? x : -x ;
+ }
+
+ static void
+ ft_conic_split( FT_Vector* base )
+ {
+ FT_Pos a, b;
+
+
+ base[4].x = base[2].x;
+ b = base[1].x;
+ a = base[3].x = ( base[2].x + b )/2;
+ b = base[1].x = ( base[0].x + b )/2;
+ base[2].x = ( a + b )/2;
+
+ base[4].y = base[2].y;
+ b = base[1].y;
+ a = base[3].y = ( base[2].y + b )/2;
+ b = base[1].y = ( base[0].y + b )/2;
+ base[2].y = ( a + b )/2;
+ }
+
+
+ static FT_Bool
+ ft_conic_is_small_enough( FT_Vector* base,
+ FT_Angle *angle_in,
+ FT_Angle *angle_out )
+ {
+ FT_Vector d1, d2;
+ FT_Angle theta;
+ FT_Int close1, close2;
+
+ d1.x = base[1].x - base[2].x;
+ d1.y = base[1].y - base[2].y;
+ d2.x = base[0].x - base[1].x;
+ d2.y = base[0].y - base[1].y;
+
+ close1 = FT_IS_SMALL(d1.x) && FT_IS_SMALL(d1.y);
+ close2 = FT_IS_SMALL(d2.x) && FT_IS_SMALL(d2.y);
+
+ if (close1)
+ {
+ if (close2)
+ *angle_in = *angle_out = 0;
+ else
+ *angle_in = *angle_out = FT_Atan2( d2.x, d2.y );
+ }
+ else if (close2)
+ {
+ *angle_in = *angle_out = FT_Atan2( d1.x, d1.y );
+ }
+ else
+ {
+ *angle_in = FT_Atan2( d1.x, d1.y );
+ *angle_out = FT_Atan2( d2.x, d2.y );
+ }
+
+ theta = ft_pos_abs( FT_Angle_Diff( *angle_in, *angle_out ) );
+
+ return FT_BOOL( theta < FT_SMALL_CONIC_THRESHOLD );
+ }
+
+
+ static void
+ ft_cubic_split( FT_Vector* base )
+ {
+ FT_Pos a, b, c, d;
+
+
+ base[6].x = base[3].x;
+ c = base[1].x;
+ d = base[2].x;
+ base[1].x = a = ( base[0].x + c )/2;
+ base[5].x = b = ( base[3].x + d )/2;
+ c = ( c + d )/2;
+ base[2].x = a = ( a + c )/2;
+ base[4].x = b = ( b + c )/2;
+ base[3].x = ( a + b )/2;
+
+ base[6].y = base[3].y;
+ c = base[1].y;
+ d = base[2].y;
+ base[1].y = a = ( base[0].y + c )/2;
+ base[5].y = b = ( base[3].y + d )/2;
+ c = ( c + d )/2;
+ base[2].y = a = ( a + c )/2;
+ base[4].y = b = ( b + c )/2;
+ base[3].y = ( a + b )/2;
+ }
+
+
+ static FT_Bool
+ ft_cubic_is_small_enough( FT_Vector* base,
+ FT_Angle *angle_in,
+ FT_Angle *angle_mid,
+ FT_Angle *angle_out )
+ {
+ FT_Vector d1, d2, d3;
+ FT_Angle theta1, theta2;
+ FT_Int close1, close2, close3;
+
+ d1.x = base[2].x - base[3].x;
+ d1.y = base[2].y - base[3].y;
+ d2.x = base[1].x - base[2].x;
+ d2.y = base[1].y - base[2].y;
+ d3.x = base[0].x - base[1].x;
+ d3.y = base[0].y - base[1].y;
+
+ close1 = FT_IS_SMALL(d1.x) && FT_IS_SMALL(d1.y);
+ close2 = FT_IS_SMALL(d2.x) && FT_IS_SMALL(d2.y);
+ close3 = FT_IS_SMALL(d3.x) && FT_IS_SMALL(d3.y);
+
+ if (close1 || close3)
+ {
+ if (close2)
+ {
+ /* basically a point */
+ *angle_in = *angle_out = *angle_mid = 0;
+ }
+ else if (close1)
+ {
+ *angle_in = *angle_mid = FT_Atan2( d2.x, d2.y );
+ *angle_out = FT_Atan2( d3.x, d3.y );
+ }
+ else /* close2 */
+ {
+ *angle_in = FT_Atan2( d1.x, d1.y );
+ *angle_mid = *angle_out = FT_Atan2( d2.x, d2.y );
+ }
+ }
+ else if (close2)
+ {
+ *angle_in = *angle_mid = FT_Atan2( d1.x, d1.y );
+ *angle_out = FT_Atan2( d3.x, d3.y );
+ }
+ else
+ {
+ *angle_in = FT_Atan2( d1.x, d1.y );
+ *angle_mid = FT_Atan2( d2.x, d2.y );
+ *angle_out = FT_Atan2( d3.x, d3.y );
+ }
+ theta1 = ft_pos_abs( FT_Angle_Diff( *angle_in, *angle_mid ) );
+ theta2 = ft_pos_abs( FT_Angle_Diff( *angle_mid, *angle_out ) );
+
+ return FT_BOOL( theta1 < FT_SMALL_CUBIC_THRESHOLD &&
+ theta2 < FT_SMALL_CUBIC_THRESHOLD );
+ }
+
+
+
+ /***************************************************************************/
+ /***************************************************************************/
+ /***** *****/
+ /***** STROKE BORDERS *****/
+ /***** *****/
+ /***************************************************************************/
+ /***************************************************************************/
+
+ typedef enum
+ {
+ FT_STROKE_TAG_ON = 1, /* on-curve point */
+ FT_STROKE_TAG_CUBIC = 2, /* cubic off-point */
+ FT_STROKE_TAG_BEGIN = 4, /* sub-path start */
+ FT_STROKE_TAG_END = 8 /* sub-path end */
+
+ } FT_StrokeTags;
+
+
+ typedef struct FT_StrokeBorderRec_
+ {
+ FT_UInt num_points;
+ FT_UInt max_points;
+ FT_Vector* points;
+ FT_Byte* tags;
+ FT_Bool movable;
+ FT_Int start; /* index of current sub-path start point */
+ FT_Memory memory;
+
+ } FT_StrokeBorderRec, *FT_StrokeBorder;
+
+
+ static FT_Error
+ ft_stroke_border_grow( FT_StrokeBorder border,
+ FT_UInt new_points )
+ {
+ FT_UInt old_max = border->max_points;
+ FT_UInt new_max = border->num_points + new_points;
+ FT_Error error = 0;
+
+ if ( new_max > old_max )
+ {
+ FT_UInt cur_max = old_max;
+ FT_Memory memory = border->memory;
+
+ while ( cur_max < new_max )
+ cur_max += (cur_max >> 1) + 16;
+
+ if ( FT_RENEW_ARRAY( border->points, old_max, cur_max ) ||
+ FT_RENEW_ARRAY( border->tags, old_max, cur_max ) )
+ goto Exit;
+
+ border->max_points = cur_max;
+ }
+ Exit:
+ return error;
+ }
+
+ static void
+ ft_stroke_border_close( FT_StrokeBorder border )
+ {
+ FT_ASSERT( border->start >= 0 );
+
+ border->tags[ border->start ] |= FT_STROKE_TAG_BEGIN;
+ border->tags[ border->num_points-1 ] |= FT_STROKE_TAG_END;
+
+ border->start = -1;
+ border->movable = 0;
+ }
+
+
+ static FT_Error
+ ft_stroke_border_lineto( FT_StrokeBorder border,
+ FT_Vector* to,
+ FT_Bool movable )
+ {
+ FT_Error error = 0;
+
+ FT_ASSERT( border->start >= 0 );
+
+ if ( border->movable )
+ {
+ /* move last point */
+ border->points[ border->num_points-1 ] = *to;
+ }
+ else
+ {
+ /* add one point */
+ error = ft_stroke_border_grow( border, 1 );
+ if (!error)
+ {
+ FT_Vector* vec = border->points + border->num_points;
+ FT_Byte* tag = border->tags + border->num_points;
+
+ vec[0] = *to;
+ tag[0] = FT_STROKE_TAG_ON;
+
+ border->num_points += 1;
+ }
+ }
+ border->movable = movable;
+ return error;
+ }
+
+
+ static FT_Error
+ ft_stroke_border_conicto( FT_StrokeBorder border,
+ FT_Vector* control,
+ FT_Vector* to )
+ {
+ FT_Error error;
+
+ FT_ASSERT( border->start >= 0 );
+
+ error = ft_stroke_border_grow( border, 2 );
+ if (!error)
+ {
+ FT_Vector* vec = border->points + border->num_points;
+ FT_Byte* tag = border->tags + border->num_points;
+
+ vec[0] = *control;
+ vec[1] = *to;
+
+ tag[0] = 0;
+ tag[1] = FT_STROKE_TAG_ON;
+
+ border->num_points += 2;
+ }
+ border->movable = 0;
+ return error;
+ }
+
+
+ static FT_Error
+ ft_stroke_border_cubicto( FT_StrokeBorder border,
+ FT_Vector* control1,
+ FT_Vector* control2,
+ FT_Vector* to )
+ {
+ FT_Error error;
+
+ FT_ASSERT( border->start >= 0 );
+
+ error = ft_stroke_border_grow( border, 3 );
+ if (!error)
+ {
+ FT_Vector* vec = border->points + border->num_points;
+ FT_Byte* tag = border->tags + border->num_points;
+
+ vec[0] = *control1;
+ vec[1] = *control2;
+ vec[2] = *to;
+
+ tag[0] = FT_STROKE_TAG_CUBIC;
+ tag[1] = FT_STROKE_TAG_CUBIC;
+ tag[2] = FT_STROKE_TAG_ON;
+
+ border->num_points += 3;
+ }
+ border->movable = 0;
+ return error;
+ }
+
+
+#define FT_ARC_CUBIC_ANGLE (FT_ANGLE_PI/2)
+
+
+ static FT_Error
+ ft_stroke_border_arcto( FT_StrokeBorder border,
+ FT_Vector* center,
+ FT_Fixed radius,
+ FT_Angle angle_start,
+ FT_Angle angle_diff )
+ {
+ FT_Angle total, angle, step, rotate, next, theta;
+ FT_Vector a, b, a2, b2;
+ FT_Fixed length;
+ FT_Error error = 0;
+
+ /* compute start point */
+ FT_Vector_From_Polar( &a, radius, angle_start );
+ a.x += center->x;
+ a.y += center->y;
+
+ total = angle_diff;
+ angle = angle_start;
+ rotate = ( angle_diff >= 0 ) ? FT_ANGLE_PI2 : -FT_ANGLE_PI2;
+
+ while (total != 0)
+ {
+ step = total;
+ if ( step > FT_ARC_CUBIC_ANGLE )
+ step = FT_ARC_CUBIC_ANGLE;
+
+ else if ( step < -FT_ARC_CUBIC_ANGLE )
+ step = -FT_ARC_CUBIC_ANGLE;
+
+ next = angle + step;
+ theta = step;
+ if ( theta < 0 )
+ theta = -theta;
+
+ theta >>= 1;
+
+ /* compute end point */
+ FT_Vector_From_Polar( &b, radius, next );
+ b.x += center->x;
+ b.y += center->y;
+
+ /* compute first and second control points */
+ length = FT_MulDiv( radius, FT_Sin(theta)*4,
+ (0x10000L + FT_Cos(theta))*3 );
+
+ FT_Vector_From_Polar( &a2, length, angle + rotate );
+ a2.x += a.x;
+ a2.y += a.y;
+
+ FT_Vector_From_Polar( &b2, length, next - rotate );
+ b2.x += b.x;
+ b2.y += b.y;
+
+ /* add cubic arc */
+ error = ft_stroke_border_cubicto( border, &a2, &b2, &b );
+ if (error) break;
+
+ /* process the rest of the arc ?? */
+ a = b;
+ total -= step;
+ angle = next;
+ }
+ return error;
+ }
+
+
+ static FT_Error
+ ft_stroke_border_moveto( FT_StrokeBorder border,
+ FT_Vector* to )
+ {
+ /* close current open path if any ? */
+ if ( border->start >= 0 )
+ ft_stroke_border_close( border );
+
+ border->start = border->num_points;
+ border->movable = 0;
+
+ return ft_stroke_border_lineto( border, to, 0 );
+ }
+
+
+ static void
+ ft_stroke_border_init( FT_StrokeBorder border,
+ FT_Memory memory )
+ {
+ border->memory = memory;
+ border->points = NULL;
+ border->tags = NULL;
+
+ border->num_points = 0;
+ border->max_points = 0;
+ border->start = -1;
+ }
+
+
+ static void
+ ft_stroke_border_reset( FT_StrokeBorder border )
+ {
+ border->num_points = 0;
+ border->start = -1;
+ }
+
+
+ static void
+ ft_stroke_border_done( FT_StrokeBorder border )
+ {
+ FT_Memory memory = border->memory;
+
+ FT_FREE( border->points );
+ FT_FREE( border->tags );
+
+ border->num_points = 0;
+ border->max_points = 0;
+ border->start = -1;
+ }
+
+
+ static FT_Error
+ ft_stroke_border_get_counts( FT_StrokeBorder border,
+ FT_UInt *anum_points,
+ FT_UInt *anum_contours )
+ {
+ FT_Error error = 0;
+ FT_UInt num_points = 0;
+ FT_UInt num_contours = 0;
+
+ FT_UInt count = border->num_points;
+ FT_Vector* point = border->points;
+ FT_Byte* tags = border->tags;
+ FT_Int in_contour = 0;
+
+ for ( ; count > 0; count--, point++, tags++ )
+ {
+ if ( tags[0] & FT_STROKE_TAG_BEGIN )
+ {
+ if ( in_contour != 0 )
+ goto Fail;
+
+ in_contour = 1;
+ }
+ else if ( in_contour == 0 )
+ goto Fail;
+
+ if ( tags[0] & FT_STROKE_TAG_END )
+ {
+ if ( in_contour == 0 )
+ goto Fail;
+
+ in_contour = 0;
+ num_contours++;
+ }
+ }
+ if ( in_contour != 0 )
+ goto Fail;
+
+ Exit:
+ *anum_points = num_points;
+ *anum_contours = num_contours;
+ return error;
+
+ Fail:
+ num_points = 0;
+ num_contours = 0;
+ goto Exit;
+ }
+
+
+ static void
+ ft_stroke_border_export( FT_StrokeBorder border,
+ FT_Outline* outline )
+ {
+ /* copy point locations */
+ FT_MEM_COPY( outline->points + outline->n_points,
+ border->points,
+ border->num_points * sizeof(FT_Vector) );
+
+ /* copy tags */
+ {
+ FT_UInt count = border->num_points;
+ FT_Byte* read = border->tags;
+ FT_Byte* write = (FT_Byte*) outline->tags + outline->n_points;
+
+ for ( ; count > 0; count--, read++, write++ )
+ {
+ if ( *read & FT_STROKE_TAG_ON )
+ *write = FT_CURVE_TAG_ON;
+ else if ( *read & FT_STROKE_TAG_CUBIC )
+ *write = FT_CURVE_TAG_CUBIC;
+ else
+ *write = FT_CURVE_TAG_CONIC;
+ }
+ }
+
+ /* copy contours */
+ {
+ FT_UInt count = border->num_points;
+ FT_Byte* tags = border->tags;
+ FT_Short* write = outline->contours + outline->n_contours;
+ FT_Short index = (FT_Short) outline->n_points;
+
+ for ( ; count > 0; count--, tags++, write++, index++ )
+ {
+ if ( *tags & FT_STROKE_TAG_END )
+ {
+ *write++ = index;
+ outline->n_contours++;
+ }
+ }
+ }
+
+ outline->n_points = (short)( outline->n_points + border->num_points );
+
+ FT_ASSERT( FT_Outline_Check( outline ) == 0 );
+ }
+
+
+ /***************************************************************************/
+ /***************************************************************************/
+ /***** *****/
+ /***** STROKER *****/
+ /***** *****/
+ /***************************************************************************/
+ /***************************************************************************/
+
+#define FT_SIDE_TO_ROTATE(s) (FT_ANGLE_PI2 - (s)*FT_ANGLE_PI)
+
+ typedef struct FT_StrokerRec_
+ {
+ FT_Angle angle_in;
+ FT_Angle angle_out;
+ FT_Vector center;
+ FT_Bool first_point;
+ FT_Bool subpath_open;
+ FT_Angle subpath_angle;
+ FT_Vector subpath_start;
+
+ FT_Stroker_LineCap line_cap;
+ FT_Stroker_LineJoin line_join;
+ FT_Fixed miter_limit;
+ FT_Fixed radius;
+
+ FT_Bool valid;
+ FT_StrokeBorderRec borders[2];
+ FT_Memory memory;
+
+ } FT_StrokerRec;
+
+
+ FT_EXPORT_DEF( FT_Error )
+ FT_Stroker_New( FT_Memory memory,
+ FT_Stroker *astroker )
+ {
+ FT_Error error;
+ FT_Stroker stroker;
+
+ if ( !FT_NEW( stroker ) )
+ {
+ stroker->memory = memory;
+
+ ft_stroke_border_init( &stroker->borders[0], memory );
+ ft_stroke_border_init( &stroker->borders[1], memory );
+ }
+ *astroker = stroker;
+ return error;
+ }
+
+
+ FT_EXPORT_DEF( void )
+ FT_Stroker_Set( FT_Stroker stroker,
+ FT_Fixed radius,
+ FT_Stroker_LineCap line_cap,
+ FT_Stroker_LineJoin line_join,
+ FT_Fixed miter_limit )
+ {
+ stroker->radius = radius;
+ stroker->line_cap = line_cap;
+ stroker->line_join = line_join;
+ stroker->miter_limit = miter_limit;
+
+ stroker->valid = 0;
+
+ ft_stroke_border_reset( &stroker->borders[0] );
+ ft_stroke_border_reset( &stroker->borders[1] );
+ }
+
+
+ FT_EXPORT_DEF( void )
+ FT_Stroker_Done( FT_Stroker stroker )
+ {
+ if ( stroker )
+ {
+ FT_Memory memory = stroker->memory;
+
+ ft_stroke_border_done( &stroker->borders[0] );
+ ft_stroke_border_done( &stroker->borders[1] );
+
+ stroker->memory = NULL;
+ FT_FREE( stroker );
+ }
+ }
+
+
+
+ /* creates a circular arc at a corner or cap */
+ static FT_Error
+ ft_stroker_arcto( FT_Stroker stroker,
+ FT_Int side )
+ {
+ FT_Angle total, rotate;
+ FT_Fixed radius = stroker->radius;
+ FT_Error error = 0;
+ FT_StrokeBorder border = stroker->borders + side;
+
+ rotate = FT_SIDE_TO_ROTATE(side);
+
+ total = FT_Angle_Diff( stroker->angle_in, stroker->angle_out );
+ if (total == FT_ANGLE_PI)
+ total = -rotate*2;
+
+ error = ft_stroke_border_arcto( border,
+ &stroker->center,
+ radius,
+ stroker->angle_in + rotate,
+ total );
+ border->movable = 0;
+ return error;
+ }
+
+
+ /* adds a cap at the end of an opened path */
+ static FT_Error
+ ft_stroker_cap( FT_Stroker stroker,
+ FT_Angle angle,
+ FT_Int side )
+ {
+ FT_Error error = 0;
+
+ if ( stroker->line_cap == FT_STROKER_LINECAP_ROUND )
+ {
+ /* add a round cap */
+ stroker->angle_in = angle;
+ stroker->angle_out = angle + FT_ANGLE_PI;
+ error = ft_stroker_arcto( stroker, side );
+ }
+ else if ( stroker->line_cap == FT_STROKER_LINECAP_SQUARE )
+ {
+ /* add a square cap */
+ FT_Vector delta, delta2;
+ FT_Angle rotate = FT_SIDE_TO_ROTATE(side);
+ FT_Fixed radius = stroker->radius;
+ FT_StrokeBorder border = stroker->borders + side;
+
+ FT_Vector_From_Polar( &delta2, radius, angle+rotate );
+ FT_Vector_From_Polar( &delta, radius, angle );
+
+ delta.x += stroker->center.x + delta2.x;
+ delta.y += stroker->center.y + delta2.y;
+
+ error = ft_stroke_border_lineto( border, &delta, 0 );
+ if (error) goto Exit;
+
+ FT_Vector_From_Polar( &delta2, radius, angle-rotate );
+ FT_Vector_From_Polar( &delta, radius, angle );
+
+ delta.x += delta2.x + stroker->center.x;
+ delta.y += delta2.y + stroker->center.y;
+
+ error = ft_stroke_border_lineto( border, &delta, 0 );
+ }
+ Exit:
+ return error;
+ }
+
+
+
+ /* process an inside corner, i.e. compute intersection */
+ static FT_Error
+ ft_stroker_inside( FT_Stroker stroker,
+ FT_Int side)
+ {
+ FT_StrokeBorder border = stroker->borders + side;
+ FT_Angle phi, theta, rotate;
+ FT_Fixed length, thcos, sigma;
+ FT_Vector delta;
+ FT_Error error = 0;
+
+
+ rotate = FT_SIDE_TO_ROTATE(side);
+
+ /* compute median angle */
+ theta = FT_Angle_Diff( stroker->angle_in, stroker->angle_out );
+ if ( theta == FT_ANGLE_PI )
+ theta = rotate;
+ else
+ theta = theta/2;
+
+ phi = stroker->angle_in + theta;
+
+ thcos = FT_Cos( theta );
+ sigma = FT_MulFix( stroker->miter_limit, thcos );
+
+ if ( sigma < 0x10000L )
+ {
+ FT_Vector_From_Polar( &delta, stroker->radius, stroker->angle_out + rotate );
+ delta.x += stroker->center.x;
+ delta.y += stroker->center.y;
+ border->movable = 0;
+ }
+ else
+ {
+ length = FT_DivFix( stroker->radius, thcos );
+
+ FT_Vector_From_Polar( &delta, length, phi + rotate );
+ delta.x += stroker->center.x;
+ delta.y += stroker->center.y;
+ }
+
+ error = ft_stroke_border_lineto( border, &delta, 0 );
+
+ return error;
+ }
+
+
+ /* process an outside corner, i.e. compute bevel/miter/round */
+ static FT_Error
+ ft_stroker_outside( FT_Stroker stroker,
+ FT_Int side )
+ {
+ FT_StrokeBorder border = stroker->borders + side;
+ FT_Error error;
+ FT_Angle rotate;
+
+ if ( stroker->line_join == FT_STROKER_LINEJOIN_ROUND )
+ {
+ error = ft_stroker_arcto( stroker, side );
+ }
+ else
+ {
+ /* this is a mitered or beveled corner */
+ FT_Fixed sigma, radius = stroker->radius;
+ FT_Angle theta, phi;
+ FT_Fixed thcos;
+ FT_Bool miter;
+
+ rotate = FT_SIDE_TO_ROTATE(side);
+ miter = FT_BOOL( stroker->line_join == FT_STROKER_LINEJOIN_MITER );
+
+ theta = FT_Angle_Diff( stroker->angle_in, stroker->angle_out );
+ if (theta == FT_ANGLE_PI)
+ theta = rotate;
+ else
+ theta = theta/2;
+
+ thcos = FT_Cos( theta );
+ sigma = FT_MulFix( stroker->miter_limit, thcos );
+
+ if ( sigma >= 0x10000L )
+ miter = 0;
+
+ phi = stroker->angle_in + theta + rotate;
+
+ if (miter) /* this is a miter (broken angle) */
+ {
+ FT_Vector middle, delta;
+ FT_Fixed length;
+
+ /* compute middle point */
+ FT_Vector_From_Polar( &middle, FT_MulFix( radius, stroker->miter_limit ),
+ phi );
+ middle.x += stroker->center.x;
+ middle.y += stroker->center.y;
+
+ /* compute first angle point */
+ length = FT_MulFix( radius, FT_DivFix( 0x10000L - sigma,
+ ft_pos_abs( FT_Sin( theta ) ) ) );
+
+ FT_Vector_From_Polar( &delta, length, phi + rotate );
+ delta.x += middle.x;
+ delta.y += middle.y;
+
+ error = ft_stroke_border_lineto( border, &delta, 0 );
+ if (error) goto Exit;
+
+ /* compute second angle point */
+ FT_Vector_From_Polar( &delta, length, phi - rotate );
+ delta.x += middle.x;
+ delta.y += middle.y;
+
+ error = ft_stroke_border_lineto( border, &delta, 0 );
+ if (error) goto Exit;
+
+ /* finally, add a movable end point */
+ FT_Vector_From_Polar( &delta, radius, stroker->angle_out + rotate );
+ delta.x += stroker->center.x;
+ delta.y += stroker->center.y;
+
+ error = ft_stroke_border_lineto( border, &delta, 1 );
+ }
+ else /* this is a bevel (intersection) */
+ {
+ FT_Fixed length;
+ FT_Vector delta;
+
+ length = FT_DivFix( stroker->radius, thcos );
+
+ FT_Vector_From_Polar( &delta, length, phi );
+ delta.x += stroker->center.x;
+ delta.y += stroker->center.y;
+
+ error = ft_stroke_border_lineto( border, &delta, 0 );
+ if (error) goto Exit;
+
+ /* now add end point */
+ FT_Vector_From_Polar( &delta, stroker->radius, stroker->angle_out + rotate );
+ delta.x += stroker->center.x;
+ delta.y += stroker->center.y;
+
+ error = ft_stroke_border_lineto( border, &delta, 1 );
+ }
+ }
+ Exit:
+ return error;
+ }
+
+
+ static FT_Error
+ ft_stroker_process_corner( FT_Stroker stroker )
+ {
+ FT_Error error = 0;
+ FT_Angle turn;
+ FT_Int inside_side;
+
+ turn = FT_Angle_Diff( stroker->angle_in, stroker->angle_out );
+
+ /* no specific corner processing is required if the turn is 0 */
+ if (turn == 0)
+ goto Exit;
+
+ /* when we turn to the right, the inside side is 0 */
+ inside_side = 0;
+
+ /* otherwise, the inside side is 1 */
+ if (turn < 0)
+ inside_side = 1;
+
+ /* process the inside side */
+ error = ft_stroker_inside( stroker, inside_side );
+ if (error) goto Exit;
+
+ /* process the outside side */
+ error = ft_stroker_outside( stroker, 1-inside_side );
+
+ Exit:
+ return error;
+ }
+
+
+ /* add two points to the left and right borders corresponding to the */
+ /* start of the subpath.. */
+ static FT_Error
+ ft_stroker_subpath_start( FT_Stroker stroker,
+ FT_Angle start_angle )
+ {
+ FT_Vector delta;
+ FT_Vector point;
+ FT_Error error;
+ FT_StrokeBorder border;
+
+ FT_Vector_From_Polar( &delta, stroker->radius, start_angle + FT_ANGLE_PI2 );
+
+ point.x = stroker->center.x + delta.x;
+ point.y = stroker->center.y + delta.y;
+
+ border = stroker->borders;
+ error = ft_stroke_border_moveto( border, &point );
+ if (error) goto Exit;
+
+ point.x = stroker->center.x - delta.x;
+ point.y = stroker->center.y - delta.y;
+
+ border++;
+ error = ft_stroke_border_moveto( border, &point );
+
+ /* save angle for last cap */
+ stroker->subpath_angle = start_angle;
+ stroker->first_point = 0;
+
+ Exit:
+ return error;
+ }
+
+
+ FT_EXPORT_DEF( FT_Error )
+ FT_Stroker_LineTo( FT_Stroker stroker,
+ FT_Vector* to )
+ {
+ FT_Error error = 0;
+ FT_StrokeBorder border;
+ FT_Vector delta;
+ FT_Angle angle;
+ FT_Int side;
+
+ delta.x = to->x - stroker->center.x;
+ delta.y = to->y - stroker->center.y;
+
+ angle = FT_Atan2( delta.x, delta.y );
+ FT_Vector_From_Polar( &delta, stroker->radius, angle + FT_ANGLE_PI2 );
+
+ /* process corner if necessary */
+ if ( stroker->first_point )
+ {
+ /* this is the first segment of a subpath. We need to */
+ /* add a point to each border at their respective starting */
+ /* point locations.. */
+ error = ft_stroker_subpath_start( stroker, angle );
+ if (error) goto Exit;
+ }
+ else
+ {
+ /* process the current corner */
+ stroker->angle_out = angle;
+ error = ft_stroker_process_corner( stroker );
+ if (error) goto Exit;
+ }
+
+ /* now add a line segment to both the "inside" and "outside" paths */
+
+ for ( border = stroker->borders, side = 1; side >= 0; side--, border++ )
+ {
+ FT_Vector point;
+
+ point.x = to->x + delta.x;
+ point.y = to->y + delta.y;
+
+ error = ft_stroke_border_lineto( border, &point, 1 );
+ if (error) goto Exit;
+
+ delta.x = -delta.x;
+ delta.y = -delta.y;
+ }
+
+ stroker->angle_in = angle;
+ stroker->center = *to;
+
+ Exit:
+ return error;
+ }
+
+
+
+ FT_EXPORT_DEF( FT_Error )
+ FT_Stroker_ConicTo( FT_Stroker stroker,
+ FT_Vector* control,
+ FT_Vector* to )
+ {
+ FT_Error error = 0;
+ FT_Vector bez_stack[34];
+ FT_Vector* arc;
+ FT_Vector* limit = bez_stack + 30;
+ FT_Angle start_angle;
+ FT_Bool first_arc = 1;
+
+ arc = bez_stack;
+ arc[0] = *to;
+ arc[1] = *control;
+ arc[2] = stroker->center;
+
+ while ( arc >= bez_stack )
+ {
+ FT_Angle angle_in, angle_out;
+
+ angle_in = angle_out = 0; /* remove compiler warnings */
+
+ if ( arc < limit &&
+ !ft_conic_is_small_enough( arc, &angle_in, &angle_out ) )
+ {
+ ft_conic_split( arc );
+ arc += 2;
+ continue;
+ }
+
+ if ( first_arc )
+ {
+ first_arc = 0;
+
+ start_angle = angle_in;
+
+ /* process corner if necessary */
+ if ( stroker->first_point )
+ error = ft_stroker_subpath_start( stroker, start_angle );
+ else
+ {
+ stroker->angle_out = start_angle;
+ error = ft_stroker_process_corner( stroker );
+ }
+ }
+
+ /* the arc's angle is small enough, we can add it directly to each */
+ /* border.. */
+ {
+ FT_Vector ctrl, end;
+ FT_Angle theta, phi, rotate;
+ FT_Fixed length;
+ FT_Int side;
+
+ theta = FT_Angle_Diff( angle_in, angle_out )/2;
+ phi = angle_in + theta;
+ length = FT_DivFix( stroker->radius, FT_Cos(theta) );
+
+ for ( side = 0; side <= 1; side++ )
+ {
+ rotate = FT_SIDE_TO_ROTATE(side);
+
+ /* compute control point */
+ FT_Vector_From_Polar( &ctrl, length, phi + rotate );
+ ctrl.x += arc[1].x;
+ ctrl.y += arc[1].y;
+
+ /* compute end point */
+ FT_Vector_From_Polar( &end, stroker->radius, angle_out + rotate );
+ end.x += arc[0].x;
+ end.y += arc[0].y;
+
+ error = ft_stroke_border_conicto( stroker->borders + side, &ctrl, &end );
+ if (error) goto Exit;
+ }
+ }
+
+ arc -= 2;
+
+ if (arc < bez_stack)
+ stroker->angle_in = angle_out;
+ }
+
+ stroker->center = *to;
+
+ Exit:
+ return error;
+ }
+
+
+
+ FT_EXPORT_DEF( FT_Error )
+ FT_Stroker_CubicTo( FT_Stroker stroker,
+ FT_Vector* control1,
+ FT_Vector* control2,
+ FT_Vector* to )
+ {
+ FT_Error error = 0;
+ FT_Vector bez_stack[37];
+ FT_Vector* arc;
+ FT_Vector* limit = bez_stack + 32;
+ FT_Angle start_angle;
+ FT_Bool first_arc = 1;
+
+ arc = bez_stack;
+ arc[0] = *to;
+ arc[1] = *control2;
+ arc[2] = *control1;
+ arc[3] = stroker->center;
+
+ while ( arc >= bez_stack )
+ {
+ FT_Angle angle_in, angle_mid, angle_out;
+
+ /* remove compiler warnings */
+ angle_in = angle_out = angle_mid = 0;
+
+ if ( arc < limit &&
+ !ft_cubic_is_small_enough( arc, &angle_in, &angle_mid, &angle_out ) )
+ {
+ ft_cubic_split( arc );
+ arc += 3;
+ continue;
+ }
+
+ if ( first_arc )
+ {
+ first_arc = 0;
+
+ /* process corner if necessary */
+ start_angle = angle_in;
+
+ if ( stroker->first_point )
+ error = ft_stroker_subpath_start( stroker, start_angle );
+ else
+ {
+ stroker->angle_out = start_angle;
+ error = ft_stroker_process_corner( stroker );
+ }
+ if (error) goto Exit;
+ }
+
+ /* the arc's angle is small enough, we can add it directly to each */
+ /* border.. */
+ {
+ FT_Vector ctrl1, ctrl2, end;
+ FT_Angle theta1, phi1, theta2, phi2, rotate;
+ FT_Fixed length1, length2;
+ FT_Int side;
+
+ theta1 = ft_pos_abs( angle_mid - angle_in )/2;
+ theta2 = ft_pos_abs( angle_out - angle_mid )/2;
+ phi1 = (angle_mid+angle_in)/2;
+ phi2 = (angle_mid+angle_out)/2;
+ length1 = FT_DivFix( stroker->radius, FT_Cos(theta1) );
+ length2 = FT_DivFix( stroker->radius, FT_Cos(theta2) );
+
+ for ( side = 0; side <= 1; side++ )
+ {
+ rotate = FT_SIDE_TO_ROTATE(side);
+
+ /* compute control points */
+ FT_Vector_From_Polar( &ctrl1, length1, phi1 + rotate );
+ ctrl1.x += arc[2].x;
+ ctrl1.y += arc[2].y;
+
+ FT_Vector_From_Polar( &ctrl2, length2, phi2 + rotate );
+ ctrl2.x += arc[1].x;
+ ctrl2.y += arc[1].y;
+
+ /* compute end point */
+ FT_Vector_From_Polar( &end, stroker->radius, angle_out + rotate );
+ end.x += arc[0].x;
+ end.y += arc[0].y;
+
+ error = ft_stroke_border_cubicto( stroker->borders + side, &ctrl1, &ctrl2, &end );
+ if (error) goto Exit;
+ }
+ }
+
+ arc -= 3;
+ if (arc < bez_stack)
+ stroker->angle_in = angle_out;
+ }
+
+ stroker->center = *to;
+
+ Exit:
+ return error;
+ }
+
+
+ FT_EXPORT_DEF( FT_Error )
+ FT_Stroker_BeginSubPath( FT_Stroker stroker,
+ FT_Vector* to,
+ FT_Bool open )
+ {
+ /* we cannot process the first point, because there is not enough */
+ /* information regarding its corner/cap. The latter will be processed */
+ /* in the "end_subpath" routine */
+ /* */
+ stroker->first_point = 1;
+ stroker->center = *to;
+ stroker->subpath_open = open;
+
+ /* record the subpath start point index for each border */
+ stroker->subpath_start = *to;
+ return 0;
+ }
+
+
+ static
+ FT_Error ft_stroker_add_reverse_left( FT_Stroker stroker,
+ FT_Bool open )
+ {
+ FT_StrokeBorder right = stroker->borders + 0;
+ FT_StrokeBorder left = stroker->borders + 1;
+ FT_Int new_points;
+ FT_Error error = 0;
+
+ FT_ASSERT( left->start >= 0 );
+
+ new_points = left->num_points - left->start;
+ if ( new_points > 0 )
+ {
+ error = ft_stroke_border_grow( right, (FT_UInt)new_points );
+ if (error) goto Exit;
+ {
+ FT_Vector* dst_point = right->points + right->num_points;
+ FT_Byte* dst_tag = right->tags + right->num_points;
+ FT_Vector* src_point = left->points + left->num_points - 1;
+ FT_Byte* src_tag = left->tags + left->num_points - 1;
+
+ while ( src_point >= left->points + left->start )
+ {
+ *dst_point = *src_point;
+ *dst_tag = *src_tag;
+
+ if (open)
+ dst_tag[0] &= ~(FT_STROKE_TAG_BEGIN | FT_STROKE_TAG_END);
+ else
+ {
+ /* switch begin/end tags if necessary.. */
+ if (dst_tag[0] & (FT_STROKE_TAG_BEGIN | FT_STROKE_TAG_END))
+ dst_tag[0] ^= (FT_STROKE_TAG_BEGIN | FT_STROKE_TAG_END);
+ }
+
+ src_point--;
+ src_tag--;
+ dst_point++;
+ dst_tag++;
+ }
+ }
+ left->num_points = left->start;
+ right->num_points += new_points;
+
+ right->movable = 0;
+ left->movable = 0;
+ }
+ Exit:
+ return error;
+ }
+
+
+ /* there's a lot of magic in this function !! */
+ FT_EXPORT_DEF( FT_Error )
+ FT_Stroker_EndSubPath( FT_Stroker stroker )
+ {
+ FT_Error error = 0;
+
+ if ( stroker->subpath_open )
+ {
+ FT_StrokeBorder right = stroker->borders;
+
+ /* all right, this is an opened path, we need to add a cap between */
+ /* right & left, add the reverse of left, then add a final cap between */
+ /* left & right.. */
+ error = ft_stroker_cap( stroker, stroker->angle_in, 0 );
+ if (error) goto Exit;
+
+ /* add reversed points from "left" to "right" */
+ error = ft_stroker_add_reverse_left( stroker, 1 );
+ if (error) goto Exit;
+
+ /* now add the final cap */
+ stroker->center = stroker->subpath_start;
+ error = ft_stroker_cap( stroker, stroker->subpath_angle+FT_ANGLE_PI, 0 );
+ if (error) goto Exit;
+
+ /* now, end the right subpath accordingly. the left one is */
+ /* rewind and doesn't need further processing.. */
+ ft_stroke_border_close( right );
+ }
+ else
+ {
+ FT_Angle turn;
+ FT_Int inside_side;
+
+ /* process the corner ... */
+ stroker->angle_out = stroker->subpath_angle;
+ turn = FT_Angle_Diff( stroker->angle_in, stroker->angle_out );
+
+ /* no specific corner processing is required if the turn is 0 */
+ if (turn != 0)
+ {
+ /* when we turn to the right, the inside side is 0 */
+ inside_side = 0;
+
+ /* otherwise, the inside side is 1 */
+ if (turn < 0)
+ inside_side = 1;
+
+ /* IMPORTANT: WE DO NOT PROCESS THE INSIDE BORDER HERE !! */
+ /* process the inside side */
+ /* error = ft_stroker_inside( stroker, inside_side );
+ if (error) goto Exit; */
+
+ /* process the outside side */
+ error = ft_stroker_outside( stroker, 1-inside_side );
+ if (error) goto Exit;
+ }
+
+ /* we will first end our two subpaths */
+ ft_stroke_border_close( stroker->borders + 0 );
+ ft_stroke_border_close( stroker->borders + 1 );
+
+ /* now, add the reversed left subpath to "right" */
+ error = ft_stroker_add_reverse_left( stroker, 0 );
+ if (error) goto Exit;
+ }
+
+ Exit:
+ return error;
+ }
+
+
+ FT_EXPORT_DEF( FT_Error )
+ FT_Stroker_GetCounts( FT_Stroker stroker,
+ FT_UInt *anum_points,
+ FT_UInt *anum_contours )
+ {
+ FT_UInt count1, count2, num_points = 0;
+ FT_UInt count3, count4, num_contours = 0;
+ FT_Error error;
+
+ error = ft_stroke_border_get_counts( stroker->borders+0, &count1, &count2 );
+ if (error) goto Exit;
+
+ error = ft_stroke_border_get_counts( stroker->borders+1, &count3, &count4 );
+ if (error) goto Exit;
+
+ num_points = count1 + count3;
+ num_contours = count2 + count4;
+
+ stroker->valid = 1;
+
+ Exit:
+ *anum_points = num_points;
+ *anum_contours = num_contours;
+ return error;
+ }
+
+
+ FT_EXPORT_DEF( void )
+ FT_Stroker_Export( FT_Stroker stroker,
+ FT_Outline* outline )
+ {
+ if ( stroker->valid )
+ {
+ ft_stroke_border_export( stroker->borders+0, outline );
+ ft_stroke_border_export( stroker->borders+1, outline );
+ }
+ }
--- /dev/null
+++ b/libfreetype/ftsynth.c
@@ -1,0 +1,286 @@
+/***************************************************************************/
+/* */
+/* ftsynth.c */
+/* */
+/* FreeType synthesizing code for emboldening and slanting (body). */
+/* */
+/* Copyright 2000-2001 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+
+#include <ft2build.h>
+#include FT_INTERNAL_OBJECTS_H
+#include FT_INTERNAL_CALC_H
+#include FT_OUTLINE_H
+#include FT_TRIGONOMETRY_H
+#include FT_SYNTHESIS_H
+
+
+#define FT_BOLD_THRESHOLD 0x0100
+
+
+ /*************************************************************************/
+ /*************************************************************************/
+ /**** ****/
+ /**** EXPERIMENTAL OBLIQUING SUPPORT ****/
+ /**** ****/
+ /*************************************************************************/
+ /*************************************************************************/
+
+ FT_EXPORT_DEF( void )
+ FT_GlyphSlot_Oblique( FT_GlyphSlot slot )
+ {
+ FT_Matrix transform;
+ FT_Outline* outline = &slot->outline;
+
+
+ /* only oblique outline glyphs */
+ if ( slot->format != FT_GLYPH_FORMAT_OUTLINE )
+ return;
+
+ /* we don't touch the advance width */
+
+ /* For italic, simply apply a shear transform, with an angle */
+ /* of about 12 degrees. */
+
+ transform.xx = 0x10000L;
+ transform.yx = 0x00000L;
+
+ transform.xy = 0x06000L;
+ transform.yy = 0x10000L;
+
+ FT_Outline_Transform( outline, &transform );
+ }
+
+
+ /*************************************************************************/
+ /*************************************************************************/
+ /**** ****/
+ /**** EXPERIMENTAL EMBOLDENING/OUTLINING SUPPORT ****/
+ /**** ****/
+ /*************************************************************************/
+ /*************************************************************************/
+
+
+
+ static int
+ ft_test_extrema( FT_Outline* outline,
+ int n )
+ {
+ FT_Vector *prev, *cur, *next;
+ FT_Pos product;
+ FT_Int c, first, last;
+
+
+ /* we need to compute the `previous' and `next' point */
+ /* for these extrema. */
+ cur = outline->points + n;
+ prev = cur - 1;
+ next = cur + 1;
+
+ first = 0;
+ for ( c = 0; c < outline->n_contours; c++ )
+ {
+ last = outline->contours[c];
+
+ if ( n == first )
+ prev = outline->points + last;
+
+ if ( n == last )
+ next = outline->points + first;
+
+ first = last + 1;
+ }
+
+ product = FT_MulDiv( cur->x - prev->x, /* in.x */
+ next->y - cur->y, /* out.y */
+ 0x40 )
+ -
+ FT_MulDiv( cur->y - prev->y, /* in.y */
+ next->x - cur->x, /* out.x */
+ 0x40 );
+
+ if ( product )
+ product = product > 0 ? 1 : -1;
+
+ return product;
+ }
+
+
+ /* Compute the orientation of path filling. It differs between TrueType */
+ /* and Type1 formats. We could use the `FT_OUTLINE_REVERSE_FILL' flag, */
+ /* but it is better to re-compute it directly (it seems that this flag */
+ /* isn't correctly set for some weird composite glyphs currently). */
+ /* */
+ /* We do this by computing bounding box points, and computing their */
+ /* curvature. */
+ /* */
+ /* The function returns either 1 or -1. */
+ /* */
+ static int
+ ft_get_orientation( FT_Outline* outline )
+ {
+ FT_BBox box;
+ FT_BBox indices;
+ int n, last;
+
+
+ indices.xMin = -1;
+ indices.yMin = -1;
+ indices.xMax = -1;
+ indices.yMax = -1;
+
+ box.xMin = box.yMin = 32767;
+ box.xMax = box.yMax = -32768;
+
+ /* is it empty ? */
+ if ( outline->n_contours < 1 )
+ return 1;
+
+ last = outline->contours[outline->n_contours - 1];
+
+ for ( n = 0; n <= last; n++ )
+ {
+ FT_Pos x, y;
+
+
+ x = outline->points[n].x;
+ if ( x < box.xMin )
+ {
+ box.xMin = x;
+ indices.xMin = n;
+ }
+ if ( x > box.xMax )
+ {
+ box.xMax = x;
+ indices.xMax = n;
+ }
+
+ y = outline->points[n].y;
+ if ( y < box.yMin )
+ {
+ box.yMin = y;
+ indices.yMin = n;
+ }
+ if ( y > box.yMax )
+ {
+ box.yMax = y;
+ indices.yMax = n;
+ }
+ }
+
+ /* test orientation of the xmin */
+ n = ft_test_extrema( outline, indices.xMin );
+ if ( n )
+ goto Exit;
+
+ n = ft_test_extrema( outline, indices.yMin );
+ if ( n )
+ goto Exit;
+
+ n = ft_test_extrema( outline, indices.xMax );
+ if ( n )
+ goto Exit;
+
+ n = ft_test_extrema( outline, indices.yMax );
+ if ( !n )
+ n = 1;
+
+ Exit:
+ return n;
+ }
+
+
+ FT_EXPORT_DEF( void )
+ FT_GlyphSlot_Embolden( FT_GlyphSlot slot )
+ {
+ FT_Vector* points;
+ FT_Vector v_prev, v_first, v_next, v_cur;
+ FT_Pos distance;
+ FT_Outline* outline = &slot->outline;
+ FT_Face face = FT_SLOT_FACE( slot );
+ FT_Angle rotate, angle_in, angle_out;
+ FT_Int c, n, first, orientation;
+
+
+ /* only embolden outline glyph images */
+ if ( slot->format != FT_GLYPH_FORMAT_OUTLINE )
+ return;
+
+ /* compute control distance */
+ distance = FT_MulFix( face->units_per_EM / 60,
+ face->size->metrics.y_scale );
+
+ orientation = ft_get_orientation( outline );
+ rotate = FT_ANGLE_PI2*orientation;
+
+ points = outline->points;
+
+ first = 0;
+ for ( c = 0; c < outline->n_contours; c++ )
+ {
+ int last = outline->contours[c];
+
+
+ v_first = points[first];
+ v_prev = points[last];
+ v_cur = v_first;
+
+ for ( n = first; n <= last; n++ )
+ {
+ FT_Pos d;
+ FT_Vector in, out;
+ FT_Fixed scale;
+ FT_Angle angle_diff;
+
+
+ if ( n < last ) v_next = points[n + 1];
+ else v_next = v_first;
+
+ /* compute the in and out vectors */
+ in.x = v_cur.x - v_prev.x;
+ in.y = v_cur.y - v_prev.y;
+
+ out.x = v_next.x - v_cur.x;
+ out.y = v_next.y - v_cur.y;
+
+ angle_in = FT_Atan2( in.x, in.y );
+ angle_out = FT_Atan2( out.x, out.y );
+ angle_diff = FT_Angle_Diff( angle_in, angle_out );
+ scale = FT_Cos( angle_diff/2 );
+
+ if ( scale < 0x400L && scale > -0x400L )
+ {
+ if ( scale >= 0 )
+ scale = 0x400L;
+ else
+ scale = -0x400L;
+ }
+
+ d = FT_DivFix( distance, scale );
+
+ FT_Vector_From_Polar( &in, d, angle_in + angle_diff/2 - rotate );
+
+ outline->points[n].x = v_cur.x + distance + in.x;
+ outline->points[n].y = v_cur.y + distance + in.y;
+
+ v_prev = v_cur;
+ v_cur = v_next;
+ }
+
+ first = last + 1;
+ }
+
+ slot->metrics.horiAdvance = ( slot->metrics.horiAdvance + distance*4 ) & -64;
+ }
+
+
+/* END */
--- /dev/null
+++ b/libfreetype/ftsysio.c
@@ -1,0 +1,131 @@
+#include <ft2build.h>
+#include FT_SYSTEM_STREAM_H
+
+#include <stdio.h>
+
+ /* the ISO/ANSI standard stream object */
+ typedef struct FT_StdStreamRec_
+ {
+ FT_StreamRec stream;
+ FILE* file;
+ const char* pathname;
+
+ } FT_StdStreamRec, *FT_StdStream;
+
+
+
+ /* read bytes from a standard stream */
+ static FT_ULong
+ ft_std_stream_read( FT_StdStream stream,
+ FT_Byte* buffer,
+ FT_ULong size )
+ {
+ long read_bytes;
+
+ read_bytes = fread( buffer, 1, size, stream->file );
+ if ( read_bytes < 0 )
+ read_bytes = 0;
+
+ return (FT_ULong) read_bytes;
+ }
+
+
+ /* seek the standard stream to a new position */
+ static FT_Error
+ ft_std_stream_seek( FT_StdStream stream,
+ FT_ULong pos )
+ {
+ return ( fseek( stream->file, pos, SEEK_SET ) < 0 )
+ ? FT_Err_Stream_Seek
+ : FT_Err_Ok;
+ }
+
+
+ /* close a standard stream */
+ static void
+ ft_std_stream_done( FT_StdStream stream )
+ {
+ fclose( stream->file );
+ stream->file = NULL;
+ stream->pathname = NULL;
+ }
+
+
+ /* open a standard stream from a given pathname */
+ static void
+ ft_std_stream_init( FT_StdStream stream,
+ const char* pathname )
+ {
+ FT_ASSERT( pathname != NULL );
+
+ stream->file = fopen( pathname, "rb" );
+ if ( stream->file == NULL )
+ {
+ FT_ERROR(( "iso.stream.init: could not open '%s'\n", pathname ));
+ FT_XTHROW( FT_Err_Stream_Open );
+ }
+
+ /* compute total size in bytes */
+ fseek( file, 0, SEEK_END );
+ FT_STREAM__SIZE(stream) = ftell( file );
+ fseek( file, 0, SEEK_SET );
+
+ stream->pathname = pathname;
+ stream->pos = 0;
+
+ FT_TRACE1(( "iso.stream.init: opened '%s' (%ld bytes) succesfully\n",
+ pathname, FT_STREAM__SIZE(stream) ));
+ }
+
+
+ static void
+ ft_std_stream_class_init( FT_ClassRec* _clazz )
+ {
+ FT_StreamClassRec* clazz = FT_STREAM_CLASS(_clazz);
+
+ clazz->stream_read = (FT_Stream_ReadFunc) ft_std_stream_read;
+ clazz->stream_seek = (FT_Stream_SeekFunc) ft_std_stream_seek;
+ }
+
+
+ static const FT_TypeRec ft_std_stream_type;
+ {
+ "StreamClass",
+ NULL,
+
+ sizeof( FT_ClassRec ),
+ ft_stream_class_init,
+ NULL,
+
+ sizeof( FT_StdStreamRec ),
+ ft_std_stream_init,
+ ft_std_stream_done,
+ NULL,
+ };
+
+
+
+ FT_EXPORT_DEF( FT_Stream )
+ ft_std_stream_new( FT_Memory memory,
+ const char* pathname )
+ {
+ FT_Class clazz;
+
+ clazz = ft_class_from_type( memory, &ft_std_stream_type );
+
+ return (FT_Stream) ft_object_new( clazz, pathname );
+ }
+
+
+ FT_EXPORT_DEF( void )
+ ft_std_stream_create( FT_Memory memory,
+ const char* pathname,
+ FT_Stream* astream )
+ {
+ FT_Class clazz;
+
+ clazz = ft_class_from_type( memory, &ft_std_stream_type );
+
+ ft_object_create( clazz, pathname, FT_OBJECT_P(astream) );
+ }
+
--- /dev/null
+++ b/libfreetype/ftsysmem.c
@@ -1,0 +1,30 @@
+#include <ft2build.h>
+#include FT_SYSTEM_MEMORY_H
+
+ static FT_Memory
+ ft_memory_new_default( FT_ULong size )
+ {
+ return (FT_Memory) ft_malloc( size );
+ }
+
+ static void
+ ft_memory_destroy_default( FT_Memory memory )
+ {
+ ft_free( memory );
+ }
+
+
+ /* notice that in normal builds, we use the ISO C library functions */
+ /* 'malloc', 'free' and 'realloc' directly.. */
+ /* */
+ static const FT_Memory_FuncsRec ft_memory_funcs_default_rec =
+ {
+ (FT_Memory_CreateFunc) ft_memory_new_iso,
+ (FT_Memory_DestroyFunc) ft_memory_destroy_iso,
+ (FT_Memory_AllocFunc) ft_malloc,
+ (FT_Memory_FreeFunc) ft_free,
+ (FT_Memory_ReallocFunc) ft_realloc
+ };
+
+ FT_APIVAR_DEF( const FT_Memory_Funcs )
+ ft_memory_funcs_default = &ft_memory_funcs_defaults_rec;
--- /dev/null
+++ b/libfreetype/ftsystem.c
@@ -1,0 +1,303 @@
+/***************************************************************************/
+/* */
+/* ftsystem.c */
+/* */
+/* ANSI-specific FreeType low-level system interface (body). */
+/* */
+/* Copyright 1996-2001, 2002 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+ /*************************************************************************/
+ /* */
+ /* This file contains the default interface used by FreeType to access */
+ /* low-level, i.e. memory management, i/o access as well as thread */
+ /* synchronisation. It can be replaced by user-specific routines if */
+ /* necessary. */
+ /* */
+ /*************************************************************************/
+
+
+#include <ft2build.h>
+#include FT_CONFIG_CONFIG_H
+#include FT_INTERNAL_DEBUG_H
+#include FT_SYSTEM_H
+#include FT_ERRORS_H
+#include FT_TYPES_H
+
+#include <stdio.h>
+#include <stdlib.h>
+
+
+ /*************************************************************************/
+ /* */
+ /* MEMORY MANAGEMENT INTERFACE */
+ /* */
+ /*************************************************************************/
+
+ /*************************************************************************/
+ /* */
+ /* It is not necessary to do any error checking for the */
+ /* allocation-related functions. This will be done by the higher level */
+ /* routines like FT_Alloc() or FT_Realloc(). */
+ /* */
+ /*************************************************************************/
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* ft_alloc */
+ /* */
+ /* <Description> */
+ /* The memory allocation function. */
+ /* */
+ /* <Input> */
+ /* memory :: A pointer to the memory object. */
+ /* */
+ /* size :: The requested size in bytes. */
+ /* */
+ /* <Return> */
+ /* The address of newly allocated block. */
+ /* */
+ FT_CALLBACK_DEF( void* )
+ ft_alloc( FT_Memory memory,
+ long size )
+ {
+ FT_UNUSED( memory );
+
+ return malloc( size );
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* ft_realloc */
+ /* */
+ /* <Description> */
+ /* The memory reallocation function. */
+ /* */
+ /* <Input> */
+ /* memory :: A pointer to the memory object. */
+ /* */
+ /* cur_size :: The current size of the allocated memory block. */
+ /* */
+ /* new_size :: The newly requested size in bytes. */
+ /* */
+ /* block :: The current address of the block in memory. */
+ /* */
+ /* <Return> */
+ /* The address of the reallocated memory block. */
+ /* */
+ FT_CALLBACK_DEF( void* )
+ ft_realloc( FT_Memory memory,
+ long cur_size,
+ long new_size,
+ void* block )
+ {
+ FT_UNUSED( memory );
+ FT_UNUSED( cur_size );
+
+ return realloc( block, new_size );
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* ft_free */
+ /* */
+ /* <Description> */
+ /* The memory release function. */
+ /* */
+ /* <Input> */
+ /* memory :: A pointer to the memory object. */
+ /* */
+ /* block :: The address of block in memory to be freed. */
+ /* */
+ FT_CALLBACK_DEF( void )
+ ft_free( FT_Memory memory,
+ void* block )
+ {
+ FT_UNUSED( memory );
+
+ free( block );
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* RESOURCE MANAGEMENT INTERFACE */
+ /* */
+ /*************************************************************************/
+
+
+ /*************************************************************************/
+ /* */
+ /* The macro FT_COMPONENT is used in trace mode. It is an implicit */
+ /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log */
+ /* messages during execution. */
+ /* */
+#undef FT_COMPONENT
+#define FT_COMPONENT trace_io
+
+ /* We use the macro STREAM_FILE for convenience to extract the */
+ /* system-specific stream handle from a given FreeType stream object */
+#define STREAM_FILE( stream ) ( (FILE*)stream->descriptor.pointer )
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* ft_ansi_stream_close */
+ /* */
+ /* <Description> */
+ /* The function to close a stream. */
+ /* */
+ /* <Input> */
+ /* stream :: A pointer to the stream object. */
+ /* */
+ FT_CALLBACK_DEF( void )
+ ft_ansi_stream_close( FT_Stream stream )
+ {
+ fclose( STREAM_FILE( stream ) );
+
+ stream->descriptor.pointer = NULL;
+ stream->size = 0;
+ stream->base = 0;
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* ft_ansi_stream_io */
+ /* */
+ /* <Description> */
+ /* The function to open a stream. */
+ /* */
+ /* <Input> */
+ /* stream :: A pointer to the stream object. */
+ /* */
+ /* offset :: The position in the data stream to start reading. */
+ /* */
+ /* buffer :: The address of buffer to store the read data. */
+ /* */
+ /* count :: The number of bytes to read from the stream. */
+ /* */
+ /* <Return> */
+ /* The number of bytes actually read. */
+ /* */
+ FT_CALLBACK_DEF( unsigned long )
+ ft_ansi_stream_io( FT_Stream stream,
+ unsigned long offset,
+ unsigned char* buffer,
+ unsigned long count )
+ {
+ FILE* file;
+
+
+ file = STREAM_FILE( stream );
+
+ fseek( file, offset, SEEK_SET );
+
+ return (unsigned long)fread( buffer, 1, count, file );
+ }
+
+
+ /* documentation is in ftobjs.h */
+
+ FT_EXPORT_DEF( FT_Error )
+ FT_Stream_Open( FT_Stream stream,
+ const char* filepathname )
+ {
+ FILE* file;
+
+
+ if ( !stream )
+ return FT_Err_Invalid_Stream_Handle;
+
+ file = fopen( filepathname, "rb" );
+ if ( !file )
+ {
+ FT_ERROR(( "FT_Stream_Open:" ));
+ FT_ERROR(( " could not open `%s'\n", filepathname ));
+
+ return FT_Err_Cannot_Open_Resource;
+ }
+
+ fseek( file, 0, SEEK_END );
+ stream->size = ftell( file );
+ fseek( file, 0, SEEK_SET );
+
+ stream->descriptor.pointer = file;
+ stream->pathname.pointer = (char*)filepathname;
+ stream->pos = 0;
+
+ stream->read = ft_ansi_stream_io;
+ stream->close = ft_ansi_stream_close;
+
+ FT_TRACE1(( "FT_Stream_Open:" ));
+ FT_TRACE1(( " opened `%s' (%d bytes) successfully\n",
+ filepathname, stream->size ));
+
+ return FT_Err_Ok;
+ }
+
+
+#ifdef FT_DEBUG_MEMORY
+
+ extern FT_Int
+ ft_mem_debug_init( FT_Memory memory );
+
+ extern void
+ ft_mem_debug_done( FT_Memory memory );
+
+#endif
+
+
+ /* documentation is in ftobjs.h */
+
+ FT_EXPORT_DEF( FT_Memory )
+ FT_New_Memory( void )
+ {
+ FT_Memory memory;
+
+
+ memory = (FT_Memory)malloc( sizeof ( *memory ) );
+ if ( memory )
+ {
+ memory->user = 0;
+ memory->alloc = ft_alloc;
+ memory->realloc = ft_realloc;
+ memory->free = ft_free;
+#ifdef FT_DEBUG_MEMORY
+ ft_mem_debug_init( memory );
+#endif
+ }
+
+ return memory;
+ }
+
+
+ /* documentation is in ftobjs.h */
+
+ FT_EXPORT_DEF( void )
+ FT_Done_Memory( FT_Memory memory )
+ {
+#ifdef FT_DEBUG_MEMORY
+ ft_mem_debug_done( memory );
+#endif
+ memory->free( memory, memory );
+ }
+
+
+/* END */
--- /dev/null
+++ b/libfreetype/ftsystem_inf.c
@@ -1,0 +1,308 @@
+/***************************************************************************/
+/* */
+/* ftsystem.c */
+/* */
+/* ANSI-specific FreeType low-level system interface (body). */
+/* */
+/* Copyright 1996-2001, 2002 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+ /*************************************************************************/
+ /* */
+ /* This file contains the default interface used by FreeType to access */
+ /* low-level, i.e. memory management, i/o access as well as thread */
+ /* synchronisation. It can be replaced by user-specific routines if */
+ /* necessary. */
+ /* */
+ /*************************************************************************/
+
+/* This is the Inferno version */
+
+
+#include <ft2build.h>
+#include FT_CONFIG_CONFIG_H
+#include FT_INTERNAL_DEBUG_H
+#include FT_SYSTEM_H
+#include FT_ERRORS_H
+#include FT_TYPES_H
+
+#include "kernel.h"
+
+/*#include <stdio.h>*/
+/*#include <stdlib.h>*/
+
+
+ /*************************************************************************/
+ /* */
+ /* MEMORY MANAGEMENT INTERFACE */
+ /* */
+ /*************************************************************************/
+
+ /*************************************************************************/
+ /* */
+ /* It is not necessary to do any error checking for the */
+ /* allocation-related functions. This will be done by the higher level */
+ /* routines like FT_Alloc() or FT_Realloc(). */
+ /* */
+ /*************************************************************************/
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* ft_alloc */
+ /* */
+ /* <Description> */
+ /* The memory allocation function. */
+ /* */
+ /* <Input> */
+ /* memory :: A pointer to the memory object. */
+ /* */
+ /* size :: The requested size in bytes. */
+ /* */
+ /* <Return> */
+ /* The address of newly allocated block. */
+ /* */
+ FT_CALLBACK_DEF( void* )
+ ft_alloc( FT_Memory memory,
+ long size )
+ {
+ FT_UNUSED( memory );
+
+ return malloc( size );
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* ft_realloc */
+ /* */
+ /* <Description> */
+ /* The memory reallocation function. */
+ /* */
+ /* <Input> */
+ /* memory :: A pointer to the memory object. */
+ /* */
+ /* cur_size :: The current size of the allocated memory block. */
+ /* */
+ /* new_size :: The newly requested size in bytes. */
+ /* */
+ /* block :: The current address of the block in memory. */
+ /* */
+ /* <Return> */
+ /* The address of the reallocated memory block. */
+ /* */
+ FT_CALLBACK_DEF( void* )
+ ft_realloc( FT_Memory memory,
+ long cur_size,
+ long new_size,
+ void* block )
+ {
+ FT_UNUSED( memory );
+ FT_UNUSED( cur_size );
+
+ return realloc( block, new_size );
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* ft_free */
+ /* */
+ /* <Description> */
+ /* The memory release function. */
+ /* */
+ /* <Input> */
+ /* memory :: A pointer to the memory object. */
+ /* */
+ /* block :: The address of block in memory to be freed. */
+ /* */
+ FT_CALLBACK_DEF( void )
+ ft_free( FT_Memory memory,
+ void* block )
+ {
+ FT_UNUSED( memory );
+
+ free( block );
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* RESOURCE MANAGEMENT INTERFACE */
+ /* */
+ /*************************************************************************/
+
+
+ /*************************************************************************/
+ /* */
+ /* The macro FT_COMPONENT is used in trace mode. It is an implicit */
+ /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log */
+ /* messages during execution. */
+ /* */
+#undef FT_COMPONENT
+#define FT_COMPONENT trace_io
+
+ /* We use the macro STREAM_FD for convenience to extract the */
+ /* fd from a given FreeType stream object */
+#define STREAM_FD( stream ) ( (int)stream->descriptor.pointer )
+#define CLOSED_FD (void*)-1
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* ft_ansi_stream_close */
+ /* */
+ /* <Description> */
+ /* The function to close a stream. */
+ /* */
+ /* <Input> */
+ /* stream :: A pointer to the stream object. */
+ /* */
+ FT_CALLBACK_DEF( void )
+ ft_ansi_stream_close( FT_Stream stream )
+ {
+ kclose( STREAM_FD( stream ) );
+
+ stream->descriptor.pointer = CLOSED_FD;
+ stream->size = 0;
+ stream->base = 0;
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* ft_ansi_stream_io */
+ /* */
+ /* <Description> */
+ /* The function to open a stream. */
+ /* */
+ /* <Input> */
+ /* stream :: A pointer to the stream object. */
+ /* */
+ /* offset :: The position in the data stream to start reading. */
+ /* */
+ /* buffer :: The address of buffer to store the read data. */
+ /* */
+ /* count :: The number of bytes to read from the stream. */
+ /* */
+ /* <Return> */
+ /* The number of bytes actually read. */
+ /* */
+ FT_CALLBACK_DEF( unsigned long )
+ ft_ansi_stream_io( FT_Stream stream,
+ unsigned long offset,
+ unsigned char* buffer,
+ unsigned long count )
+ {
+ int fd;
+
+ fd = STREAM_FD( stream );
+ kseek( fd, offset, SEEK_SET );
+ if(count == 0)
+ return 0;
+ return (unsigned long)kread( fd, buffer, count);
+}
+
+
+ /* documentation is in ftobjs.h */
+
+FT_EXPORT_DEF( FT_Error )
+FT_Stream_Open( FT_Stream stream, const char* filepathname)
+{
+ Dir *dir;
+ int file;
+
+ if ( !stream )
+ return FT_Err_Invalid_Stream_Handle;
+ file = kopen( (char*)filepathname, OREAD);
+ if ( file < 0) {
+ FT_ERROR(( "FT_Stream_Open:" ));
+ FT_ERROR(( " could not open `%s'\n", filepathname ));
+ return FT_Err_Cannot_Open_Resource;
+ }
+ dir = kdirfstat(file);
+ if (dir == nil) {
+ kclose(file);
+ FT_ERROR(( "FT_Stream_Open:" ));
+ FT_ERROR(( " could not stat `%s'\n", filepathname ));
+ return FT_Err_Cannot_Open_Resource;
+ }
+ stream->size = dir->length;
+ free(dir);
+
+ stream->descriptor.pointer = (void*)file;
+ stream->pathname.pointer = (char*)filepathname;
+ stream->pos = 0;
+
+ stream->read = ft_ansi_stream_io;
+ stream->close = ft_ansi_stream_close;
+
+ FT_TRACE1(( "FT_Stream_Open:" ));
+ FT_TRACE1(( " opened `%s' (%d bytes) successfully\n",
+ filepathname, stream->size ));
+
+ return FT_Err_Ok;
+}
+
+
+#ifdef FT_DEBUG_MEMORY
+
+ extern FT_Int
+ ft_mem_debug_init( FT_Memory memory );
+
+ extern void
+ ft_mem_debug_done( FT_Memory memory );
+
+#endif
+
+
+ /* documentation is in ftobjs.h */
+
+ FT_EXPORT_DEF( FT_Memory )
+ FT_New_Memory( void )
+ {
+ FT_Memory memory;
+
+
+ memory = (FT_Memory)malloc( sizeof ( *memory ) );
+ if ( memory )
+ {
+ memory->user = 0;
+ memory->alloc = ft_alloc;
+ memory->realloc = ft_realloc;
+ memory->free = ft_free;
+#ifdef FT_DEBUG_MEMORY
+ ft_mem_debug_init( memory );
+#endif
+ }
+
+ return memory;
+ }
+
+
+ /* documentation is in ftobjs.h */
+
+ FT_EXPORT_DEF( void )
+ FT_Done_Memory( FT_Memory memory )
+ {
+#ifdef FT_DEBUG_MEMORY
+ ft_mem_debug_done( memory );
+#endif
+ memory->free( memory, memory );
+ }
+
+
+/* END */
--- /dev/null
+++ b/libfreetype/fttrigon.c
@@ -1,0 +1,485 @@
+/***************************************************************************/
+/* */
+/* fttrigon.c */
+/* */
+/* FreeType trigonometric functions (body). */
+/* */
+/* Copyright 2001 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+
+#include <ft2build.h>
+#include FT_TRIGONOMETRY_H
+
+
+ /* the following is 0.2715717684432231 * 2^30 */
+#define FT_TRIG_COSCALE 0x11616E8EUL
+
+ /* this table was generated for FT_PI = 180L << 16, i.e. degrees */
+#define FT_TRIG_MAX_ITERS 23
+
+ static const FT_Fixed
+ ft_trig_arctan_table[24] =
+ {
+ 4157273L, 2949120L, 1740967L, 919879L, 466945L, 234379L, 117304L,
+ 58666L, 29335L, 14668L, 7334L, 3667L, 1833L, 917L, 458L, 229L, 115L,
+ 57L, 29L, 14L, 7L, 4L, 2L, 1L
+ };
+
+ /* the Cordic shrink factor, multiplied by 2^32 */
+#define FT_TRIG_SCALE 1166391785UL /* 0x4585BA38UL */
+
+
+#ifdef FT_CONFIG_HAS_INT64
+
+ /* multiply a given value by the CORDIC shrink factor */
+ static FT_Fixed
+ ft_trig_downscale( FT_Fixed val )
+ {
+ FT_Fixed s;
+ FT_Int64 v;
+
+
+ s = val;
+ val = ( val >= 0 ) ? val : -val;
+
+ v = ( val * (FT_Int64)FT_TRIG_SCALE ) + 0x100000000UL;
+ val = (FT_Fixed)( v >> 32 );
+
+ return ( s >= 0 ) ? val : -val;
+ }
+
+#else /* !FT_CONFIG_HAS_INT64 */
+
+ /* multiply a given value by the CORDIC shrink factor */
+ static FT_Fixed
+ ft_trig_downscale( FT_Fixed val )
+ {
+ FT_Fixed s;
+ FT_UInt32 v1, v2, k1, k2, hi, lo1, lo2, lo3;
+
+
+ s = val;
+ val = ( val >= 0 ) ? val : -val;
+
+ v1 = (FT_UInt32)val >> 16;
+ v2 = (FT_UInt32)val & 0xFFFF;
+
+ k1 = FT_TRIG_SCALE >> 16; /* constant */
+ k2 = FT_TRIG_SCALE & 0xFFFF; /* constant */
+
+ hi = k1 * v1;
+ lo1 = k1 * v2 + k2 * v1; /* can't overflow */
+
+ lo2 = ( k2 * v2 ) >> 16;
+ lo3 = ( lo1 >= lo2 ) ? lo1 : lo2;
+ lo1 += lo2;
+
+ hi += lo1 >> 16;
+ if ( lo1 < lo3 )
+ hi += 0x10000UL;
+
+ val = (FT_Fixed)hi;
+
+ return ( s >= 0 ) ? val : -val;
+ }
+
+#endif /* !FT_CONFIG_HAS_INT64 */
+
+
+ static FT_Int
+ ft_trig_prenorm( FT_Vector* vec )
+ {
+ FT_Fixed x, y, z;
+ FT_Int shift;
+
+
+ x = vec->x;
+ y = vec->y;
+
+ z = ( ( x >= 0 ) ? x : - x ) | ( (y >= 0) ? y : -y );
+ shift = 0;
+
+ if ( z < ( 1L << 27 ) )
+ {
+ do
+ {
+ shift++;
+ z <<= 1;
+ } while ( z < ( 1L << 27 ) );
+
+ vec->x = x << shift;
+ vec->y = y << shift;
+ }
+ else if ( z > ( 1L << 28 ) )
+ {
+ do
+ {
+ shift++;
+ z >>= 1;
+ } while ( z > ( 1L << 28 ) );
+
+ vec->x = x >> shift;
+ vec->y = y >> shift;
+ shift = -shift;
+ }
+ return shift;
+ }
+
+
+ static void
+ ft_trig_pseudo_rotate( FT_Vector* vec,
+ FT_Angle theta )
+ {
+ FT_Int i;
+ FT_Fixed x, y, xtemp;
+ const FT_Fixed *arctanptr;
+
+
+ x = vec->x;
+ y = vec->y;
+
+ /* Get angle between -90 and 90 degrees */
+ while ( theta <= -FT_ANGLE_PI2 )
+ {
+ x = -x;
+ y = -y;
+ theta += FT_ANGLE_PI;
+ }
+
+ while ( theta > FT_ANGLE_PI2 )
+ {
+ x = -x;
+ y = -y;
+ theta -= FT_ANGLE_PI;
+ }
+
+ /* Initial pseudorotation, with left shift */
+ arctanptr = ft_trig_arctan_table;
+
+ if ( theta < 0 )
+ {
+ xtemp = x + ( y << 1 );
+ y = y - ( x << 1 );
+ x = xtemp;
+ theta += *arctanptr++;
+ }
+ else
+ {
+ xtemp = x - ( y << 1 );
+ y = y + ( x << 1 );
+ x = xtemp;
+ theta -= *arctanptr++;
+ }
+
+ /* Subsequent pseudorotations, with right shifts */
+ i = 0;
+ do
+ {
+ if ( theta < 0 )
+ {
+ xtemp = x + ( y >> i );
+ y = y - ( x >> i );
+ x = xtemp;
+ theta += *arctanptr++;
+ }
+ else
+ {
+ xtemp = x - ( y >> i );
+ y = y + ( x >> i );
+ x = xtemp;
+ theta -= *arctanptr++;
+ }
+ } while ( ++i < FT_TRIG_MAX_ITERS );
+
+ vec->x = x;
+ vec->y = y;
+ }
+
+
+ static void
+ ft_trig_pseudo_polarize( FT_Vector* vec )
+ {
+ FT_Fixed theta;
+ FT_Fixed yi, i;
+ FT_Fixed x, y;
+ const FT_Fixed *arctanptr;
+
+
+ x = vec->x;
+ y = vec->y;
+
+ /* Get the vector into the right half plane */
+ theta = 0;
+ if ( x < 0 )
+ {
+ x = -x;
+ y = -y;
+ theta = 2 * FT_ANGLE_PI2;
+ }
+
+ if ( y > 0 )
+ theta = - theta;
+
+ arctanptr = ft_trig_arctan_table;
+
+ if ( y < 0 )
+ {
+ /* Rotate positive */
+ yi = y + ( x << 1 );
+ x = x - ( y << 1 );
+ y = yi;
+ theta -= *arctanptr++; /* Subtract angle */
+ }
+ else
+ {
+ /* Rotate negative */
+ yi = y - ( x << 1 );
+ x = x + ( y << 1 );
+ y = yi;
+ theta += *arctanptr++; /* Add angle */
+ }
+
+ i = 0;
+ do
+ {
+ if ( y < 0 )
+ {
+ /* Rotate positive */
+ yi = y + ( x >> i );
+ x = x - ( y >> i );
+ y = yi;
+ theta -= *arctanptr++;
+ }
+ else
+ {
+ /* Rotate negative */
+ yi = y - ( x >> i );
+ x = x + ( y >> i );
+ y = yi;
+ theta += *arctanptr++;
+ }
+ } while ( ++i < FT_TRIG_MAX_ITERS );
+
+ /* round theta */
+ if ( theta >= 0 )
+ theta = ( theta + 16 ) & -32;
+ else
+ theta = - (( -theta + 16 ) & -32);
+
+ vec->x = x;
+ vec->y = theta;
+ }
+
+
+ /* documentation is in fttrigon.h */
+
+ FT_EXPORT_DEF( FT_Fixed )
+ FT_Cos( FT_Angle angle )
+ {
+ FT_Vector v;
+
+
+ v.x = FT_TRIG_COSCALE >> 2;
+ v.y = 0;
+ ft_trig_pseudo_rotate( &v, angle );
+
+ return v.x / ( 1 << 12 );
+ }
+
+
+ /* documentation is in fttrigon.h */
+
+ FT_EXPORT_DEF( FT_Fixed )
+ FT_Sin( FT_Angle angle )
+ {
+ return FT_Cos( FT_ANGLE_PI2 - angle );
+ }
+
+
+ /* documentation is in fttrigon.h */
+
+ FT_EXPORT_DEF( FT_Fixed )
+ FT_Tan( FT_Angle angle )
+ {
+ FT_Vector v;
+
+
+ v.x = FT_TRIG_COSCALE >> 2;
+ v.y = 0;
+ ft_trig_pseudo_rotate( &v, angle );
+
+ return FT_DivFix( v.y, v.x );
+ }
+
+
+ /* documentation is in fttrigon.h */
+
+ FT_EXPORT_DEF( FT_Angle )
+ FT_Atan2( FT_Fixed dx,
+ FT_Fixed dy )
+ {
+ FT_Vector v;
+
+
+ if ( dx == 0 && dy == 0 )
+ return 0;
+
+ v.x = dx;
+ v.y = dy;
+ ft_trig_prenorm( &v );
+ ft_trig_pseudo_polarize( &v );
+
+ return v.y;
+ }
+
+
+ /* documentation is in fttrigon.h */
+
+ FT_EXPORT_DEF( void )
+ FT_Vector_Unit( FT_Vector* vec,
+ FT_Angle angle )
+ {
+ vec->x = FT_TRIG_COSCALE >> 2;
+ vec->y = 0;
+ ft_trig_pseudo_rotate( vec, angle );
+ vec->x >>= 12;
+ vec->y >>= 12;
+ }
+
+
+ /* documentation is in fttrigon.h */
+
+ FT_EXPORT_DEF( void )
+ FT_Vector_Rotate( FT_Vector* vec,
+ FT_Angle angle )
+ {
+ FT_Int shift;
+ FT_Vector v;
+
+
+ v.x = vec->x;
+ v.y = vec->y;
+
+ if ( angle && ( v.x != 0 || v.y != 0 ) )
+ {
+ shift = ft_trig_prenorm( &v );
+ ft_trig_pseudo_rotate( &v, angle );
+ v.x = ft_trig_downscale( v.x );
+ v.y = ft_trig_downscale( v.y );
+
+ if ( shift >= 0 )
+ {
+ vec->x = v.x >> shift;
+ vec->y = v.y >> shift;
+ }
+ else
+ {
+ shift = -shift;
+ vec->x = v.x << shift;
+ vec->y = v.y << shift;
+ }
+ }
+ }
+
+
+ /* documentation is in fttrigon.h */
+
+ FT_EXPORT_DEF( FT_Fixed )
+ FT_Vector_Length( FT_Vector* vec )
+ {
+ FT_Int shift;
+ FT_Vector v;
+
+
+ v = *vec;
+
+ /* handle trivial cases */
+ if ( v.x == 0 )
+ {
+ return ( v.y >= 0 ) ? v.y : -v.y;
+ }
+ else if ( v.y == 0 )
+ {
+ return ( v.x >= 0 ) ? v.x : -v.x;
+ }
+
+ /* general case */
+ shift = ft_trig_prenorm( &v );
+ ft_trig_pseudo_polarize( &v );
+
+ v.x = ft_trig_downscale( v.x );
+
+ if ( shift > 0 )
+ return ( v.x + ( 1 << ( shift - 1 ) ) ) >> shift;
+
+ return v.x << -shift;
+ }
+
+
+ /* documentation is in fttrigon.h */
+
+ FT_EXPORT_DEF( void )
+ FT_Vector_Polarize( FT_Vector* vec,
+ FT_Fixed *length,
+ FT_Angle *angle )
+ {
+ FT_Int shift;
+ FT_Vector v;
+
+
+ v = *vec;
+
+ if ( v.x == 0 && v.y == 0 )
+ return;
+
+ shift = ft_trig_prenorm( &v );
+ ft_trig_pseudo_polarize( &v );
+
+ v.x = ft_trig_downscale( v.x );
+
+ *length = ( shift >= 0 ) ? ( v.x >> shift ) : ( v.x << -shift );
+ *angle = v.y;
+ }
+
+
+ /* documentation is in fttrigon.h */
+
+ FT_EXPORT_DEF( void )
+ FT_Vector_From_Polar( FT_Vector* vec,
+ FT_Fixed length,
+ FT_Angle angle )
+ {
+ vec->x = length;
+ vec->y = 0;
+
+ FT_Vector_Rotate( vec, angle );
+ }
+
+
+ /* documentation is in fttrigon.h */
+
+ FT_EXPORT_DEF( FT_Angle )
+ FT_Angle_Diff( FT_Angle angle1,
+ FT_Angle angle2 )
+ {
+ FT_Angle delta = angle2 - angle1;
+
+ delta %= FT_ANGLE_2PI;
+
+ if ( delta > FT_ANGLE_PI )
+ delta -= FT_ANGLE_2PI;
+
+ return delta;
+ }
+
+
+/* END */
--- /dev/null
+++ b/libfreetype/fttype1.c
@@ -1,0 +1,87 @@
+/***************************************************************************/
+/* */
+/* fttype1.c */
+/* */
+/* FreeType utility file for PS names support (body). */
+/* */
+/* Copyright 2002 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+
+#include <ft2build.h>
+#include FT_INTERNAL_TYPE1_TYPES_H
+#include FT_INTERNAL_TYPE42_TYPES_H
+#include FT_INTERNAL_OBJECTS_H
+
+
+ /* documentation is in t1tables.h */
+
+ FT_EXPORT_DEF( FT_Error )
+ FT_Get_PS_Font_Info( FT_Face face,
+ PS_FontInfoRec* afont_info )
+ {
+ PS_FontInfo font_info = NULL;
+ FT_Error error = FT_Err_Invalid_Argument;
+ const char* driver_name;
+
+
+ if ( face && face->driver && face->driver->root.clazz )
+ {
+ driver_name = face->driver->root.clazz->module_name;
+ if ( ft_strcmp( driver_name, "type1" ) == 0 )
+ font_info = &((T1_Face)face)->type1.font_info;
+ else if ( ft_strcmp( driver_name, "t1cid" ) == 0 )
+ font_info = &((CID_Face)face)->cid.font_info;
+ else if ( ft_strcmp( driver_name, "type42" ) == 0 )
+ font_info = &((T42_Face)face)->type1.font_info;
+ }
+ if ( font_info != NULL )
+ {
+ *afont_info = *font_info;
+ error = FT_Err_Ok;
+ }
+
+ return error;
+ }
+
+
+ /* XXX: Bad hack, but I didn't want to change several drivers here. */
+
+ /* documentation is in t1tables.h */
+
+ FT_EXPORT_DEF( FT_Int )
+ FT_Has_PS_Glyph_Names( FT_Face face )
+ {
+ FT_Int result = 0;
+ const char* driver_name;
+
+
+ if ( face && face->driver && face->driver->root.clazz )
+ {
+ /* Currently, only the type1, type42, and cff drivers provide */
+ /* reliable glyph names... */
+
+ /* We could probably hack the TrueType driver to recognize */
+ /* certain cases where the glyph names are most certainly */
+ /* correct (e.g. using a 20 or 22 format `post' table), but */
+ /* this will probably happen later... */
+
+ driver_name = face->driver->root.clazz->module_name;
+ result = ( ft_strcmp( driver_name, "type1" ) == 0 ||
+ ft_strcmp( driver_name, "type42" ) == 0 ||
+ ft_strcmp( driver_name, "cff" ) == 0 );
+ }
+
+ return result;
+ }
+
+
+/* END */
--- /dev/null
+++ b/libfreetype/ftutil.c
@@ -1,0 +1,330 @@
+/***************************************************************************/
+/* */
+/* ftutil.c */
+/* */
+/* FreeType utility file for memory and list management (body). */
+/* */
+/* Copyright 2002 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+
+#include <ft2build.h>
+#include FT_INTERNAL_DEBUG_H
+#include FT_INTERNAL_MEMORY_H
+#include FT_LIST_H
+
+
+ /*************************************************************************/
+ /* */
+ /* The macro FT_COMPONENT is used in trace mode. It is an implicit */
+ /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log */
+ /* messages during execution. */
+ /* */
+#undef FT_COMPONENT
+#define FT_COMPONENT trace_memory
+
+
+ /*************************************************************************/
+ /*************************************************************************/
+ /*************************************************************************/
+ /***** *****/
+ /***** *****/
+ /***** M E M O R Y M A N A G E M E N T *****/
+ /***** *****/
+ /***** *****/
+ /*************************************************************************/
+ /*************************************************************************/
+ /*************************************************************************/
+
+ /* documentation is in ftmemory.h */
+
+ FT_BASE_DEF( FT_Error )
+ FT_Alloc( FT_Memory memory,
+ FT_Long size,
+ void* *P )
+ {
+ FT_ASSERT( P != 0 );
+
+ if ( size > 0 )
+ {
+ *P = memory->alloc( memory, size );
+ if ( !*P )
+ {
+ FT_ERROR(( "FT_Alloc:" ));
+ FT_ERROR(( " Out of memory? (%ld requested)\n",
+ size ));
+
+ return FT_Err_Out_Of_Memory;
+ }
+ FT_MEM_ZERO( *P, size );
+ }
+ else
+ *P = NULL;
+
+ FT_TRACE7(( "FT_Alloc:" ));
+ FT_TRACE7(( " size = %ld, block = 0x%08p, ref = 0x%08p\n",
+ size, *P, P ));
+
+ return FT_Err_Ok;
+ }
+
+
+ /* documentation is in ftmemory.h */
+
+ FT_BASE_DEF( FT_Error )
+ FT_Realloc( FT_Memory memory,
+ FT_Long current,
+ FT_Long size,
+ void** P )
+ {
+ void* Q;
+
+
+ FT_ASSERT( P != 0 );
+
+ /* if the original pointer is NULL, call FT_Alloc() */
+ if ( !*P )
+ return FT_Alloc( memory, size, P );
+
+ /* if the new block if zero-sized, clear the current one */
+ if ( size <= 0 )
+ {
+ FT_Free( memory, P );
+ return FT_Err_Ok;
+ }
+
+ Q = memory->realloc( memory, current, size, *P );
+ if ( !Q )
+ goto Fail;
+
+ if ( size > current )
+ FT_MEM_ZERO( (char*)Q + current, size - current );
+
+ *P = Q;
+ return FT_Err_Ok;
+
+ Fail:
+ FT_ERROR(( "FT_Realloc:" ));
+ FT_ERROR(( " Failed (current %ld, requested %ld)\n",
+ current, size ));
+ return FT_Err_Out_Of_Memory;
+ }
+
+
+ /* documentation is in ftmemory.h */
+
+ FT_BASE_DEF( void )
+ FT_Free( FT_Memory memory,
+ void** P )
+ {
+ FT_TRACE7(( "FT_Free:" ));
+ FT_TRACE7(( " Freeing block 0x%08p, ref 0x%08p\n",
+ P, P ? *P : (void*)0 ));
+
+ if ( P && *P )
+ {
+ memory->free( memory, *P );
+ *P = 0;
+ }
+ }
+
+
+ /*************************************************************************/
+ /*************************************************************************/
+ /*************************************************************************/
+ /***** *****/
+ /***** *****/
+ /***** D O U B L Y L I N K E D L I S T S *****/
+ /***** *****/
+ /***** *****/
+ /*************************************************************************/
+ /*************************************************************************/
+ /*************************************************************************/
+
+#undef FT_COMPONENT
+#define FT_COMPONENT trace_list
+
+ /* documentation is in ftlist.h */
+
+ FT_EXPORT_DEF( FT_ListNode )
+ FT_List_Find( FT_List list,
+ void* data )
+ {
+ FT_ListNode cur;
+
+
+ cur = list->head;
+ while ( cur )
+ {
+ if ( cur->data == data )
+ return cur;
+
+ cur = cur->next;
+ }
+
+ return (FT_ListNode)0;
+ }
+
+
+ /* documentation is in ftlist.h */
+
+ FT_EXPORT_DEF( void )
+ FT_List_Add( FT_List list,
+ FT_ListNode node )
+ {
+ FT_ListNode before = list->tail;
+
+
+ node->next = 0;
+ node->prev = before;
+
+ if ( before )
+ before->next = node;
+ else
+ list->head = node;
+
+ list->tail = node;
+ }
+
+
+ /* documentation is in ftlist.h */
+
+ FT_EXPORT_DEF( void )
+ FT_List_Insert( FT_List list,
+ FT_ListNode node )
+ {
+ FT_ListNode after = list->head;
+
+
+ node->next = after;
+ node->prev = 0;
+
+ if ( !after )
+ list->tail = node;
+ else
+ after->prev = node;
+
+ list->head = node;
+ }
+
+
+ /* documentation is in ftlist.h */
+
+ FT_EXPORT_DEF( void )
+ FT_List_Remove( FT_List list,
+ FT_ListNode node )
+ {
+ FT_ListNode before, after;
+
+
+ before = node->prev;
+ after = node->next;
+
+ if ( before )
+ before->next = after;
+ else
+ list->head = after;
+
+ if ( after )
+ after->prev = before;
+ else
+ list->tail = before;
+ }
+
+
+ /* documentation is in ftlist.h */
+
+ FT_EXPORT_DEF( void )
+ FT_List_Up( FT_List list,
+ FT_ListNode node )
+ {
+ FT_ListNode before, after;
+
+
+ before = node->prev;
+ after = node->next;
+
+ /* check whether we are already on top of the list */
+ if ( !before )
+ return;
+
+ before->next = after;
+
+ if ( after )
+ after->prev = before;
+ else
+ list->tail = before;
+
+ node->prev = 0;
+ node->next = list->head;
+ list->head->prev = node;
+ list->head = node;
+ }
+
+
+ /* documentation is in ftlist.h */
+
+ FT_EXPORT_DEF( FT_Error )
+ FT_List_Iterate( FT_List list,
+ FT_List_Iterator iterator,
+ void* user )
+ {
+ FT_ListNode cur = list->head;
+ FT_Error error = FT_Err_Ok;
+
+
+ while ( cur )
+ {
+ FT_ListNode next = cur->next;
+
+
+ error = iterator( cur, user );
+ if ( error )
+ break;
+
+ cur = next;
+ }
+
+ return error;
+ }
+
+
+ /* documentation is in ftlist.h */
+
+ FT_EXPORT_DEF( void )
+ FT_List_Finalize( FT_List list,
+ FT_List_Destructor destroy,
+ FT_Memory memory,
+ void* user )
+ {
+ FT_ListNode cur;
+
+
+ cur = list->head;
+ while ( cur )
+ {
+ FT_ListNode next = cur->next;
+ void* data = cur->data;
+
+
+ if ( destroy )
+ destroy( memory, data, user );
+
+ FT_FREE( cur );
+ cur = next;
+ }
+
+ list->head = 0;
+ list->tail = 0;
+ }
+
+
+/* END */
--- /dev/null
+++ b/libfreetype/ftxf86.c
@@ -1,0 +1,80 @@
+/***************************************************************************/
+/* */
+/* ftxf86.c */
+/* */
+/* FreeType utility file for X11 support (body). */
+/* */
+/* Copyright 2002 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+
+#include <ft2build.h>
+#include FT_XFREE86_H
+#include FT_INTERNAL_OBJECTS_H
+
+ /* XXX: This really is a sad hack, but I didn't want to change every */
+ /* driver just to support this at the moment, since other important */
+ /* changes are coming anyway. */
+
+ typedef struct FT_FontFormatRec_
+ {
+ const char* driver_name;
+ const char* format_name;
+
+ } FT_FontFormatRec;
+
+
+ FT_EXPORT_DEF( const char* )
+ FT_Get_X11_Font_Format( FT_Face face )
+ {
+ static const FT_FontFormatRec font_formats[] =
+ {
+ { "type1", "Type 1" },
+ { "truetype", "TrueType" },
+ { "bdf", "BDF" },
+ { "pcf", "PCF" },
+ { "type42", "Type 42" },
+ { "cidtype1", "CID Type 1" },
+ { "cff", "CFF" },
+ { "pfr", "PFR" },
+ { "winfonts", "Windows FNT" }
+ };
+
+ const char* result = NULL;
+
+
+ if ( face && face->driver )
+ {
+ FT_Module driver = (FT_Module)face->driver;
+
+
+ if ( driver->clazz && driver->clazz->module_name )
+ {
+ FT_Int n;
+ FT_Int count = sizeof( font_formats ) / sizeof ( font_formats[0] );
+
+
+ result = driver->clazz->module_name;
+
+ for ( n = 0; n < count; n++ )
+ if ( ft_strcmp( result, font_formats[n].driver_name ) == 0 )
+ {
+ result = font_formats[n].format_name;
+ break;
+ }
+ }
+ }
+
+ return result;
+ }
+
+
+/* END */
--- /dev/null
+++ b/libfreetype/infblock.c
@@ -1,0 +1,383 @@
+/* infblock.c -- interpret and process block types to last block
+ * Copyright (C) 1995-2002 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+#include "zutil.h"
+#include "infblock.h"
+#include "inftrees.h"
+#include "infcodes.h"
+#include "infutil.h"
+
+
+/* simplify the use of the inflate_huft type with some defines */
+#define exop word.what.Exop
+#define bits word.what.Bits
+
+/* Table for deflate from PKZIP's appnote.txt. */
+local const uInt border[] = { /* Order of the bit length code lengths */
+ 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15};
+
+/*
+ Notes beyond the 1.93a appnote.txt:
+
+ 1. Distance pointers never point before the beginning of the output
+ stream.
+ 2. Distance pointers can point back across blocks, up to 32k away.
+ 3. There is an implied maximum of 7 bits for the bit length table and
+ 15 bits for the actual data.
+ 4. If only one code exists, then it is encoded using one bit. (Zero
+ would be more efficient, but perhaps a little confusing.) If two
+ codes exist, they are coded using one bit each (0 and 1).
+ 5. There is no way of sending zero distance codes--a dummy must be
+ sent if there are none. (History: a pre 2.0 version of PKZIP would
+ store blocks with no distance codes, but this was discovered to be
+ too harsh a criterion.) Valid only for 1.93a. 2.04c does allow
+ zero distance codes, which is sent as one code of zero bits in
+ length.
+ 6. There are up to 286 literal/length codes. Code 256 represents the
+ end-of-block. Note however that the static length tree defines
+ 288 codes just to fill out the Huffman codes. Codes 286 and 287
+ cannot be used though, since there is no length base or extra bits
+ defined for them. Similarily, there are up to 30 distance codes.
+ However, static trees define 32 codes (all 5 bits) to fill out the
+ Huffman codes, but the last two had better not show up in the data.
+ 7. Unzip can check dynamic Huffman blocks for complete code sets.
+ The exception is that a single code would not be complete (see #4).
+ 8. The five bits following the block type is really the number of
+ literal codes sent minus 257.
+ 9. Length codes 8,16,16 are interpreted as 13 length codes of 8 bits
+ (1+6+6). Therefore, to output three times the length, you output
+ three codes (1+1+1), whereas to output four times the same length,
+ you only need two codes (1+3). Hmm.
+ 10. In the tree reconstruction algorithm, Code = Code + Increment
+ only if BitLength(i) is not zero. (Pretty obvious.)
+ 11. Correction: 4 Bits: # of Bit Length codes - 4 (4 - 19)
+ 12. Note: length code 284 can represent 227-258, but length code 285
+ really is 258. The last length deserves its own, short code
+ since it gets used a lot in very redundant files. The length
+ 258 is special since 258 - 3 (the min match length) is 255.
+ 13. The literal/length and distance code bit lengths are read as a
+ single stream of lengths. It is possible (and advantageous) for
+ a repeat code (16, 17, or 18) to go across the boundary between
+ the two sets of lengths.
+ */
+
+
+local void inflate_blocks_reset(s, z, c)
+inflate_blocks_statef *s;
+z_streamp z;
+uLongf *c;
+{
+ if (c != Z_NULL)
+ *c = s->check;
+ if (s->mode == BTREE || s->mode == DTREE)
+ ZFREE(z, s->sub.trees.blens);
+ if (s->mode == CODES)
+ inflate_codes_free(s->sub.decode.codes, z);
+ s->mode = TYPE;
+ s->bitk = 0;
+ s->bitb = 0;
+ s->read = s->write = s->window;
+ if (s->checkfn != Z_NULL)
+ z->adler = s->check = (*s->checkfn)(0L, (const Bytef *)Z_NULL, 0);
+ Tracev((stderr, "inflate: blocks reset\n"));
+}
+
+
+local inflate_blocks_statef *inflate_blocks_new(z, c, w)
+z_streamp z;
+check_func c;
+uInt w;
+{
+ inflate_blocks_statef *s;
+
+ if ((s = (inflate_blocks_statef *)ZALLOC
+ (z,1,sizeof(struct inflate_blocks_state))) == Z_NULL)
+ return s;
+ if ((s->hufts =
+ (inflate_huft *)ZALLOC(z, sizeof(inflate_huft), MANY)) == Z_NULL)
+ {
+ ZFREE(z, s);
+ return Z_NULL;
+ }
+ if ((s->window = (Bytef *)ZALLOC(z, 1, w)) == Z_NULL)
+ {
+ ZFREE(z, s->hufts);
+ ZFREE(z, s);
+ return Z_NULL;
+ }
+ s->end = s->window + w;
+ s->checkfn = c;
+ s->mode = TYPE;
+ Tracev((stderr, "inflate: blocks allocated\n"));
+ inflate_blocks_reset(s, z, Z_NULL);
+ return s;
+}
+
+
+local int inflate_blocks(s, z, r)
+inflate_blocks_statef *s;
+z_streamp z;
+int r;
+{
+ uInt t; /* temporary storage */
+ uLong b; /* bit buffer */
+ uInt k; /* bits in bit buffer */
+ Bytef *p; /* input data pointer */
+ uInt n; /* bytes available there */
+ Bytef *q; /* output window write pointer */
+ uInt m; /* bytes to end of window or read pointer */
+
+ /* copy input/output information to locals (UPDATE macro restores) */
+ LOAD
+
+ /* process input based on current state */
+ while (1) switch (s->mode)
+ {
+ case TYPE:
+ NEEDBITS(3)
+ t = (uInt)b & 7;
+ s->last = t & 1;
+ switch (t >> 1)
+ {
+ case 0: /* stored */
+ Tracev((stderr, "inflate: stored block%s\n",
+ s->last ? " (last)" : ""));
+ DUMPBITS(3)
+ t = k & 7; /* go to byte boundary */
+ DUMPBITS(t)
+ s->mode = LENS; /* get length of stored block */
+ break;
+ case 1: /* fixed */
+ Tracev((stderr, "inflate: fixed codes block%s\n",
+ s->last ? " (last)" : ""));
+ {
+ uInt bl, bd;
+ inflate_huft *tl, *td;
+
+ inflate_trees_fixed(&bl, &bd, &tl, &td, z);
+ s->sub.decode.codes = inflate_codes_new(bl, bd, tl, td, z);
+ if (s->sub.decode.codes == Z_NULL)
+ {
+ r = Z_MEM_ERROR;
+ LEAVE
+ }
+ }
+ DUMPBITS(3)
+ s->mode = CODES;
+ break;
+ case 2: /* dynamic */
+ Tracev((stderr, "inflate: dynamic codes block%s\n",
+ s->last ? " (last)" : ""));
+ DUMPBITS(3)
+ s->mode = TABLE;
+ break;
+ case 3: /* illegal */
+ DUMPBITS(3)
+ s->mode = BAD;
+ z->msg = (char*)"invalid block type";
+ r = Z_DATA_ERROR;
+ LEAVE
+ }
+ break;
+ case LENS:
+ NEEDBITS(32)
+ if ((((~b) >> 16) & 0xffff) != (b & 0xffff))
+ {
+ s->mode = BAD;
+ z->msg = (char*)"invalid stored block lengths";
+ r = Z_DATA_ERROR;
+ LEAVE
+ }
+ s->sub.left = (uInt)b & 0xffff;
+ b = k = 0; /* dump bits */
+ Tracev((stderr, "inflate: stored length %u\n", s->sub.left));
+ s->mode = s->sub.left ? STORED : (s->last ? DRY : TYPE);
+ break;
+ case STORED:
+ if (n == 0)
+ LEAVE
+ NEEDOUT
+ t = s->sub.left;
+ if (t > n) t = n;
+ if (t > m) t = m;
+ zmemcpy(q, p, t);
+ p += t; n -= t;
+ q += t; m -= t;
+ if ((s->sub.left -= t) != 0)
+ break;
+ Tracev((stderr, "inflate: stored end, %lu total out\n",
+ z->total_out + (q >= s->read ? q - s->read :
+ (s->end - s->read) + (q - s->window))));
+ s->mode = s->last ? DRY : TYPE;
+ break;
+ case TABLE:
+ NEEDBITS(14)
+ s->sub.trees.table = t = (uInt)b & 0x3fff;
+#ifndef PKZIP_BUG_WORKAROUND
+ if ((t & 0x1f) > 29 || ((t >> 5) & 0x1f) > 29)
+ {
+ s->mode = BAD;
+ z->msg = (char*)"too many length or distance symbols";
+ r = Z_DATA_ERROR;
+ LEAVE
+ }
+#endif
+ t = 258 + (t & 0x1f) + ((t >> 5) & 0x1f);
+ if ((s->sub.trees.blens = (uIntf*)ZALLOC(z, t, sizeof(uInt))) == Z_NULL)
+ {
+ r = Z_MEM_ERROR;
+ LEAVE
+ }
+ DUMPBITS(14)
+ s->sub.trees.index = 0;
+ Tracev((stderr, "inflate: table sizes ok\n"));
+ s->mode = BTREE;
+ case BTREE:
+ while (s->sub.trees.index < 4 + (s->sub.trees.table >> 10))
+ {
+ NEEDBITS(3)
+ s->sub.trees.blens[border[s->sub.trees.index++]] = (uInt)b & 7;
+ DUMPBITS(3)
+ }
+ while (s->sub.trees.index < 19)
+ s->sub.trees.blens[border[s->sub.trees.index++]] = 0;
+ s->sub.trees.bb = 7;
+ t = inflate_trees_bits(s->sub.trees.blens, &s->sub.trees.bb,
+ &s->sub.trees.tb, s->hufts, z);
+ if (t != Z_OK)
+ {
+ r = t;
+ if (r == Z_DATA_ERROR)
+ {
+ ZFREE(z, s->sub.trees.blens);
+ s->mode = BAD;
+ }
+ LEAVE
+ }
+ s->sub.trees.index = 0;
+ Tracev((stderr, "inflate: bits tree ok\n"));
+ s->mode = DTREE;
+ case DTREE:
+ while (t = s->sub.trees.table,
+ s->sub.trees.index < 258 + (t & 0x1f) + ((t >> 5) & 0x1f))
+ {
+ inflate_huft *h;
+ uInt i, j, c;
+
+ t = s->sub.trees.bb;
+ NEEDBITS(t)
+ h = s->sub.trees.tb + ((uInt)b & inflate_mask[t]);
+ t = h->bits;
+ c = h->base;
+ if (c < 16)
+ {
+ DUMPBITS(t)
+ s->sub.trees.blens[s->sub.trees.index++] = c;
+ }
+ else /* c == 16..18 */
+ {
+ i = c == 18 ? 7 : c - 14;
+ j = c == 18 ? 11 : 3;
+ NEEDBITS(t + i)
+ DUMPBITS(t)
+ j += (uInt)b & inflate_mask[i];
+ DUMPBITS(i)
+ i = s->sub.trees.index;
+ t = s->sub.trees.table;
+ if (i + j > 258 + (t & 0x1f) + ((t >> 5) & 0x1f) ||
+ (c == 16 && i < 1))
+ {
+ ZFREE(z, s->sub.trees.blens);
+ s->mode = BAD;
+ z->msg = (char*)"invalid bit length repeat";
+ r = Z_DATA_ERROR;
+ LEAVE
+ }
+ c = c == 16 ? s->sub.trees.blens[i - 1] : 0;
+ do {
+ s->sub.trees.blens[i++] = c;
+ } while (--j);
+ s->sub.trees.index = i;
+ }
+ }
+ s->sub.trees.tb = Z_NULL;
+ {
+ uInt bl, bd;
+ inflate_huft *tl, *td;
+ inflate_codes_statef *c;
+
+ bl = 9; /* must be <= 9 for lookahead assumptions */
+ bd = 6; /* must be <= 9 for lookahead assumptions */
+ t = s->sub.trees.table;
+ t = inflate_trees_dynamic(257 + (t & 0x1f), 1 + ((t >> 5) & 0x1f),
+ s->sub.trees.blens, &bl, &bd, &tl, &td,
+ s->hufts, z);
+ if (t != Z_OK)
+ {
+ if (t == (uInt)Z_DATA_ERROR)
+ {
+ ZFREE(z, s->sub.trees.blens);
+ s->mode = BAD;
+ }
+ r = t;
+ LEAVE
+ }
+ Tracev((stderr, "inflate: trees ok\n"));
+ if ((c = inflate_codes_new(bl, bd, tl, td, z)) == Z_NULL)
+ {
+ r = Z_MEM_ERROR;
+ LEAVE
+ }
+ s->sub.decode.codes = c;
+ }
+ ZFREE(z, s->sub.trees.blens);
+ s->mode = CODES;
+ case CODES:
+ UPDATE
+ if ((r = inflate_codes(s, z, r)) != Z_STREAM_END)
+ return inflate_flush(s, z, r);
+ r = Z_OK;
+ inflate_codes_free(s->sub.decode.codes, z);
+ LOAD
+ Tracev((stderr, "inflate: codes end, %lu total out\n",
+ z->total_out + (q >= s->read ? q - s->read :
+ (s->end - s->read) + (q - s->window))));
+ if (!s->last)
+ {
+ s->mode = TYPE;
+ break;
+ }
+ s->mode = DRY;
+ case DRY:
+ FLUSH
+ if (s->read != s->write)
+ LEAVE
+ s->mode = DONE;
+ case DONE:
+ r = Z_STREAM_END;
+ LEAVE
+ case BAD:
+ r = Z_DATA_ERROR;
+ LEAVE
+ default:
+ r = Z_STREAM_ERROR;
+ LEAVE
+ }
+}
+
+
+local int inflate_blocks_free(s, z)
+inflate_blocks_statef *s;
+z_streamp z;
+{
+ inflate_blocks_reset(s, z, Z_NULL);
+ ZFREE(z, s->window);
+ ZFREE(z, s->hufts);
+ ZFREE(z, s);
+ Tracev((stderr, "inflate: blocks freed\n"));
+ return Z_OK;
+}
+
+
--- /dev/null
+++ b/libfreetype/infblock.h
@@ -1,0 +1,36 @@
+/* infblock.h -- header to use infblock.c
+ * Copyright (C) 1995-2002 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/* WARNING: this file should *not* be used by applications. It is
+ part of the implementation of the compression library and is
+ subject to change. Applications should only use zlib.h.
+ */
+
+#ifndef _INFBLOCK_H
+#define _INFBLOCK_H
+
+struct inflate_blocks_state;
+typedef struct inflate_blocks_state FAR inflate_blocks_statef;
+
+local inflate_blocks_statef * inflate_blocks_new OF((
+ z_streamp z,
+ check_func c, /* check function */
+ uInt w)); /* window size */
+
+local int inflate_blocks OF((
+ inflate_blocks_statef *,
+ z_streamp ,
+ int)); /* initial return code */
+
+local void inflate_blocks_reset OF((
+ inflate_blocks_statef *,
+ z_streamp ,
+ uLongf *)); /* check value on output */
+
+local int inflate_blocks_free OF((
+ inflate_blocks_statef *,
+ z_streamp));
+
+#endif /* _INFBLOCK_H */
--- /dev/null
+++ b/libfreetype/infcodes.c
@@ -1,0 +1,250 @@
+/* infcodes.c -- process literals and length/distance pairs
+ * Copyright (C) 1995-2002 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+#include "zutil.h"
+#include "inftrees.h"
+#include "infblock.h"
+#include "infcodes.h"
+#include "infutil.h"
+
+/* simplify the use of the inflate_huft type with some defines */
+#define exop word.what.Exop
+#define bits word.what.Bits
+
+typedef enum { /* waiting for "i:"=input, "o:"=output, "x:"=nothing */
+ START, /* x: set up for LEN */
+ LEN, /* i: get length/literal/eob next */
+ LENEXT, /* i: getting length extra (have base) */
+ DIST, /* i: get distance next */
+ DISTEXT, /* i: getting distance extra */
+ COPY, /* o: copying bytes in window, waiting for space */
+ LIT, /* o: got literal, waiting for output space */
+ WASH, /* o: got eob, possibly still output waiting */
+ END, /* x: got eob and all data flushed */
+ BADCODE} /* x: got error */
+inflate_codes_mode;
+
+/* inflate codes private state */
+struct inflate_codes_state {
+
+ /* mode */
+ inflate_codes_mode mode; /* current inflate_codes mode */
+
+ /* mode dependent information */
+ uInt len;
+ union {
+ struct {
+ inflate_huft *tree; /* pointer into tree */
+ uInt need; /* bits needed */
+ } code; /* if LEN or DIST, where in tree */
+ uInt lit; /* if LIT, literal */
+ struct {
+ uInt get; /* bits to get for extra */
+ uInt dist; /* distance back to copy from */
+ } copy; /* if EXT or COPY, where and how much */
+ } sub; /* submode */
+
+ /* mode independent information */
+ Byte lbits; /* ltree bits decoded per branch */
+ Byte dbits; /* dtree bits decoder per branch */
+ inflate_huft *ltree; /* literal/length/eob tree */
+ inflate_huft *dtree; /* distance tree */
+
+};
+
+
+local inflate_codes_statef *inflate_codes_new(bl, bd, tl, td, z)
+uInt bl, bd;
+inflate_huft *tl;
+inflate_huft *td; /* need separate declaration for Borland C++ */
+z_streamp z;
+{
+ inflate_codes_statef *c;
+
+ if ((c = (inflate_codes_statef *)
+ ZALLOC(z,1,sizeof(struct inflate_codes_state))) != Z_NULL)
+ {
+ c->mode = START;
+ c->lbits = (Byte)bl;
+ c->dbits = (Byte)bd;
+ c->ltree = tl;
+ c->dtree = td;
+ Tracev((stderr, "inflate: codes new\n"));
+ }
+ return c;
+}
+
+
+local int inflate_codes(s, z, r)
+inflate_blocks_statef *s;
+z_streamp z;
+int r;
+{
+ uInt j; /* temporary storage */
+ inflate_huft *t; /* temporary pointer */
+ uInt e; /* extra bits or operation */
+ uLong b; /* bit buffer */
+ uInt k; /* bits in bit buffer */
+ Bytef *p; /* input data pointer */
+ uInt n; /* bytes available there */
+ Bytef *q; /* output window write pointer */
+ uInt m; /* bytes to end of window or read pointer */
+ Bytef *f; /* pointer to copy strings from */
+ inflate_codes_statef *c = s->sub.decode.codes; /* codes state */
+
+ /* copy input/output information to locals (UPDATE macro restores) */
+ LOAD
+
+ /* process input and output based on current state */
+ while (1) switch (c->mode)
+ { /* waiting for "i:"=input, "o:"=output, "x:"=nothing */
+ case START: /* x: set up for LEN */
+#ifndef SLOW
+ if (m >= 258 && n >= 10)
+ {
+ UPDATE
+ r = inflate_fast(c->lbits, c->dbits, c->ltree, c->dtree, s, z);
+ LOAD
+ if (r != Z_OK)
+ {
+ c->mode = r == Z_STREAM_END ? WASH : BADCODE;
+ break;
+ }
+ }
+#endif /* !SLOW */
+ c->sub.code.need = c->lbits;
+ c->sub.code.tree = c->ltree;
+ c->mode = LEN;
+ case LEN: /* i: get length/literal/eob next */
+ j = c->sub.code.need;
+ NEEDBITS(j)
+ t = c->sub.code.tree + ((uInt)b & inflate_mask[j]);
+ DUMPBITS(t->bits)
+ e = (uInt)(t->exop);
+ if (e == 0) /* literal */
+ {
+ c->sub.lit = t->base;
+ Tracevv((stderr, t->base >= 0x20 && t->base < 0x7f ?
+ "inflate: literal '%c'\n" :
+ "inflate: literal 0x%02x\n", t->base));
+ c->mode = LIT;
+ break;
+ }
+ if (e & 16) /* length */
+ {
+ c->sub.copy.get = e & 15;
+ c->len = t->base;
+ c->mode = LENEXT;
+ break;
+ }
+ if ((e & 64) == 0) /* next table */
+ {
+ c->sub.code.need = e;
+ c->sub.code.tree = t + t->base;
+ break;
+ }
+ if (e & 32) /* end of block */
+ {
+ Tracevv((stderr, "inflate: end of block\n"));
+ c->mode = WASH;
+ break;
+ }
+ c->mode = BADCODE; /* invalid code */
+ z->msg = (char*)"invalid literal/length code";
+ r = Z_DATA_ERROR;
+ LEAVE
+ case LENEXT: /* i: getting length extra (have base) */
+ j = c->sub.copy.get;
+ NEEDBITS(j)
+ c->len += (uInt)b & inflate_mask[j];
+ DUMPBITS(j)
+ c->sub.code.need = c->dbits;
+ c->sub.code.tree = c->dtree;
+ Tracevv((stderr, "inflate: length %u\n", c->len));
+ c->mode = DIST;
+ case DIST: /* i: get distance next */
+ j = c->sub.code.need;
+ NEEDBITS(j)
+ t = c->sub.code.tree + ((uInt)b & inflate_mask[j]);
+ DUMPBITS(t->bits)
+ e = (uInt)(t->exop);
+ if (e & 16) /* distance */
+ {
+ c->sub.copy.get = e & 15;
+ c->sub.copy.dist = t->base;
+ c->mode = DISTEXT;
+ break;
+ }
+ if ((e & 64) == 0) /* next table */
+ {
+ c->sub.code.need = e;
+ c->sub.code.tree = t + t->base;
+ break;
+ }
+ c->mode = BADCODE; /* invalid code */
+ z->msg = (char*)"invalid distance code";
+ r = Z_DATA_ERROR;
+ LEAVE
+ case DISTEXT: /* i: getting distance extra */
+ j = c->sub.copy.get;
+ NEEDBITS(j)
+ c->sub.copy.dist += (uInt)b & inflate_mask[j];
+ DUMPBITS(j)
+ Tracevv((stderr, "inflate: distance %u\n", c->sub.copy.dist));
+ c->mode = COPY;
+ case COPY: /* o: copying bytes in window, waiting for space */
+ f = q - c->sub.copy.dist;
+ while (f < s->window) /* modulo window size-"while" instead */
+ f += s->end - s->window; /* of "if" handles invalid distances */
+ while (c->len)
+ {
+ NEEDOUT
+ OUTBYTE(*f++)
+ if (f == s->end)
+ f = s->window;
+ c->len--;
+ }
+ c->mode = START;
+ break;
+ case LIT: /* o: got literal, waiting for output space */
+ NEEDOUT
+ OUTBYTE(c->sub.lit)
+ c->mode = START;
+ break;
+ case WASH: /* o: got eob, possibly more output */
+ if (k > 7) /* return unused byte, if any */
+ {
+ Assert(k < 16, "inflate_codes grabbed too many bytes")
+ k -= 8;
+ n++;
+ p--; /* can always return one */
+ }
+ FLUSH
+ if (s->read != s->write)
+ LEAVE
+ c->mode = END;
+ case END:
+ r = Z_STREAM_END;
+ LEAVE
+ case BADCODE: /* x: got error */
+ r = Z_DATA_ERROR;
+ LEAVE
+ default:
+ r = Z_STREAM_ERROR;
+ LEAVE
+ }
+#ifdef NEED_DUMMY_RETURN
+ return Z_STREAM_ERROR; /* Some dumb compilers complain without this */
+#endif
+}
+
+
+local void inflate_codes_free(c, z)
+inflate_codes_statef *c;
+z_streamp z;
+{
+ ZFREE(z, c);
+ Tracev((stderr, "inflate: codes free\n"));
+}
--- /dev/null
+++ b/libfreetype/infcodes.h
@@ -1,0 +1,31 @@
+/* infcodes.h -- header to use infcodes.c
+ * Copyright (C) 1995-2002 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/* WARNING: this file should *not* be used by applications. It is
+ part of the implementation of the compression library and is
+ subject to change. Applications should only use zlib.h.
+ */
+
+#ifndef _INFCODES_H
+#define _INFCODES_H
+
+struct inflate_codes_state;
+typedef struct inflate_codes_state FAR inflate_codes_statef;
+
+local inflate_codes_statef *inflate_codes_new OF((
+ uInt, uInt,
+ inflate_huft *, inflate_huft *,
+ z_streamp ));
+
+local int inflate_codes OF((
+ inflate_blocks_statef *,
+ z_streamp ,
+ int));
+
+local void inflate_codes_free OF((
+ inflate_codes_statef *,
+ z_streamp ));
+
+#endif /* _INFCODES_H */
--- /dev/null
+++ b/libfreetype/inffixed.h
@@ -1,0 +1,151 @@
+/* inffixed.h -- table for decoding fixed codes
+ * Generated automatically by the maketree.c program
+ */
+
+/* WARNING: this file should *not* be used by applications. It is
+ part of the implementation of the compression library and is
+ subject to change. Applications should only use zlib.h.
+ */
+
+local uInt fixed_bl = 9;
+local uInt fixed_bd = 5;
+local inflate_huft fixed_tl[] = {
+ {{{96,7}},256}, {{{0,8}},80}, {{{0,8}},16}, {{{84,8}},115},
+ {{{82,7}},31}, {{{0,8}},112}, {{{0,8}},48}, {{{0,9}},192},
+ {{{80,7}},10}, {{{0,8}},96}, {{{0,8}},32}, {{{0,9}},160},
+ {{{0,8}},0}, {{{0,8}},128}, {{{0,8}},64}, {{{0,9}},224},
+ {{{80,7}},6}, {{{0,8}},88}, {{{0,8}},24}, {{{0,9}},144},
+ {{{83,7}},59}, {{{0,8}},120}, {{{0,8}},56}, {{{0,9}},208},
+ {{{81,7}},17}, {{{0,8}},104}, {{{0,8}},40}, {{{0,9}},176},
+ {{{0,8}},8}, {{{0,8}},136}, {{{0,8}},72}, {{{0,9}},240},
+ {{{80,7}},4}, {{{0,8}},84}, {{{0,8}},20}, {{{85,8}},227},
+ {{{83,7}},43}, {{{0,8}},116}, {{{0,8}},52}, {{{0,9}},200},
+ {{{81,7}},13}, {{{0,8}},100}, {{{0,8}},36}, {{{0,9}},168},
+ {{{0,8}},4}, {{{0,8}},132}, {{{0,8}},68}, {{{0,9}},232},
+ {{{80,7}},8}, {{{0,8}},92}, {{{0,8}},28}, {{{0,9}},152},
+ {{{84,7}},83}, {{{0,8}},124}, {{{0,8}},60}, {{{0,9}},216},
+ {{{82,7}},23}, {{{0,8}},108}, {{{0,8}},44}, {{{0,9}},184},
+ {{{0,8}},12}, {{{0,8}},140}, {{{0,8}},76}, {{{0,9}},248},
+ {{{80,7}},3}, {{{0,8}},82}, {{{0,8}},18}, {{{85,8}},163},
+ {{{83,7}},35}, {{{0,8}},114}, {{{0,8}},50}, {{{0,9}},196},
+ {{{81,7}},11}, {{{0,8}},98}, {{{0,8}},34}, {{{0,9}},164},
+ {{{0,8}},2}, {{{0,8}},130}, {{{0,8}},66}, {{{0,9}},228},
+ {{{80,7}},7}, {{{0,8}},90}, {{{0,8}},26}, {{{0,9}},148},
+ {{{84,7}},67}, {{{0,8}},122}, {{{0,8}},58}, {{{0,9}},212},
+ {{{82,7}},19}, {{{0,8}},106}, {{{0,8}},42}, {{{0,9}},180},
+ {{{0,8}},10}, {{{0,8}},138}, {{{0,8}},74}, {{{0,9}},244},
+ {{{80,7}},5}, {{{0,8}},86}, {{{0,8}},22}, {{{192,8}},0},
+ {{{83,7}},51}, {{{0,8}},118}, {{{0,8}},54}, {{{0,9}},204},
+ {{{81,7}},15}, {{{0,8}},102}, {{{0,8}},38}, {{{0,9}},172},
+ {{{0,8}},6}, {{{0,8}},134}, {{{0,8}},70}, {{{0,9}},236},
+ {{{80,7}},9}, {{{0,8}},94}, {{{0,8}},30}, {{{0,9}},156},
+ {{{84,7}},99}, {{{0,8}},126}, {{{0,8}},62}, {{{0,9}},220},
+ {{{82,7}},27}, {{{0,8}},110}, {{{0,8}},46}, {{{0,9}},188},
+ {{{0,8}},14}, {{{0,8}},142}, {{{0,8}},78}, {{{0,9}},252},
+ {{{96,7}},256}, {{{0,8}},81}, {{{0,8}},17}, {{{85,8}},131},
+ {{{82,7}},31}, {{{0,8}},113}, {{{0,8}},49}, {{{0,9}},194},
+ {{{80,7}},10}, {{{0,8}},97}, {{{0,8}},33}, {{{0,9}},162},
+ {{{0,8}},1}, {{{0,8}},129}, {{{0,8}},65}, {{{0,9}},226},
+ {{{80,7}},6}, {{{0,8}},89}, {{{0,8}},25}, {{{0,9}},146},
+ {{{83,7}},59}, {{{0,8}},121}, {{{0,8}},57}, {{{0,9}},210},
+ {{{81,7}},17}, {{{0,8}},105}, {{{0,8}},41}, {{{0,9}},178},
+ {{{0,8}},9}, {{{0,8}},137}, {{{0,8}},73}, {{{0,9}},242},
+ {{{80,7}},4}, {{{0,8}},85}, {{{0,8}},21}, {{{80,8}},258},
+ {{{83,7}},43}, {{{0,8}},117}, {{{0,8}},53}, {{{0,9}},202},
+ {{{81,7}},13}, {{{0,8}},101}, {{{0,8}},37}, {{{0,9}},170},
+ {{{0,8}},5}, {{{0,8}},133}, {{{0,8}},69}, {{{0,9}},234},
+ {{{80,7}},8}, {{{0,8}},93}, {{{0,8}},29}, {{{0,9}},154},
+ {{{84,7}},83}, {{{0,8}},125}, {{{0,8}},61}, {{{0,9}},218},
+ {{{82,7}},23}, {{{0,8}},109}, {{{0,8}},45}, {{{0,9}},186},
+ {{{0,8}},13}, {{{0,8}},141}, {{{0,8}},77}, {{{0,9}},250},
+ {{{80,7}},3}, {{{0,8}},83}, {{{0,8}},19}, {{{85,8}},195},
+ {{{83,7}},35}, {{{0,8}},115}, {{{0,8}},51}, {{{0,9}},198},
+ {{{81,7}},11}, {{{0,8}},99}, {{{0,8}},35}, {{{0,9}},166},
+ {{{0,8}},3}, {{{0,8}},131}, {{{0,8}},67}, {{{0,9}},230},
+ {{{80,7}},7}, {{{0,8}},91}, {{{0,8}},27}, {{{0,9}},150},
+ {{{84,7}},67}, {{{0,8}},123}, {{{0,8}},59}, {{{0,9}},214},
+ {{{82,7}},19}, {{{0,8}},107}, {{{0,8}},43}, {{{0,9}},182},
+ {{{0,8}},11}, {{{0,8}},139}, {{{0,8}},75}, {{{0,9}},246},
+ {{{80,7}},5}, {{{0,8}},87}, {{{0,8}},23}, {{{192,8}},0},
+ {{{83,7}},51}, {{{0,8}},119}, {{{0,8}},55}, {{{0,9}},206},
+ {{{81,7}},15}, {{{0,8}},103}, {{{0,8}},39}, {{{0,9}},174},
+ {{{0,8}},7}, {{{0,8}},135}, {{{0,8}},71}, {{{0,9}},238},
+ {{{80,7}},9}, {{{0,8}},95}, {{{0,8}},31}, {{{0,9}},158},
+ {{{84,7}},99}, {{{0,8}},127}, {{{0,8}},63}, {{{0,9}},222},
+ {{{82,7}},27}, {{{0,8}},111}, {{{0,8}},47}, {{{0,9}},190},
+ {{{0,8}},15}, {{{0,8}},143}, {{{0,8}},79}, {{{0,9}},254},
+ {{{96,7}},256}, {{{0,8}},80}, {{{0,8}},16}, {{{84,8}},115},
+ {{{82,7}},31}, {{{0,8}},112}, {{{0,8}},48}, {{{0,9}},193},
+ {{{80,7}},10}, {{{0,8}},96}, {{{0,8}},32}, {{{0,9}},161},
+ {{{0,8}},0}, {{{0,8}},128}, {{{0,8}},64}, {{{0,9}},225},
+ {{{80,7}},6}, {{{0,8}},88}, {{{0,8}},24}, {{{0,9}},145},
+ {{{83,7}},59}, {{{0,8}},120}, {{{0,8}},56}, {{{0,9}},209},
+ {{{81,7}},17}, {{{0,8}},104}, {{{0,8}},40}, {{{0,9}},177},
+ {{{0,8}},8}, {{{0,8}},136}, {{{0,8}},72}, {{{0,9}},241},
+ {{{80,7}},4}, {{{0,8}},84}, {{{0,8}},20}, {{{85,8}},227},
+ {{{83,7}},43}, {{{0,8}},116}, {{{0,8}},52}, {{{0,9}},201},
+ {{{81,7}},13}, {{{0,8}},100}, {{{0,8}},36}, {{{0,9}},169},
+ {{{0,8}},4}, {{{0,8}},132}, {{{0,8}},68}, {{{0,9}},233},
+ {{{80,7}},8}, {{{0,8}},92}, {{{0,8}},28}, {{{0,9}},153},
+ {{{84,7}},83}, {{{0,8}},124}, {{{0,8}},60}, {{{0,9}},217},
+ {{{82,7}},23}, {{{0,8}},108}, {{{0,8}},44}, {{{0,9}},185},
+ {{{0,8}},12}, {{{0,8}},140}, {{{0,8}},76}, {{{0,9}},249},
+ {{{80,7}},3}, {{{0,8}},82}, {{{0,8}},18}, {{{85,8}},163},
+ {{{83,7}},35}, {{{0,8}},114}, {{{0,8}},50}, {{{0,9}},197},
+ {{{81,7}},11}, {{{0,8}},98}, {{{0,8}},34}, {{{0,9}},165},
+ {{{0,8}},2}, {{{0,8}},130}, {{{0,8}},66}, {{{0,9}},229},
+ {{{80,7}},7}, {{{0,8}},90}, {{{0,8}},26}, {{{0,9}},149},
+ {{{84,7}},67}, {{{0,8}},122}, {{{0,8}},58}, {{{0,9}},213},
+ {{{82,7}},19}, {{{0,8}},106}, {{{0,8}},42}, {{{0,9}},181},
+ {{{0,8}},10}, {{{0,8}},138}, {{{0,8}},74}, {{{0,9}},245},
+ {{{80,7}},5}, {{{0,8}},86}, {{{0,8}},22}, {{{192,8}},0},
+ {{{83,7}},51}, {{{0,8}},118}, {{{0,8}},54}, {{{0,9}},205},
+ {{{81,7}},15}, {{{0,8}},102}, {{{0,8}},38}, {{{0,9}},173},
+ {{{0,8}},6}, {{{0,8}},134}, {{{0,8}},70}, {{{0,9}},237},
+ {{{80,7}},9}, {{{0,8}},94}, {{{0,8}},30}, {{{0,9}},157},
+ {{{84,7}},99}, {{{0,8}},126}, {{{0,8}},62}, {{{0,9}},221},
+ {{{82,7}},27}, {{{0,8}},110}, {{{0,8}},46}, {{{0,9}},189},
+ {{{0,8}},14}, {{{0,8}},142}, {{{0,8}},78}, {{{0,9}},253},
+ {{{96,7}},256}, {{{0,8}},81}, {{{0,8}},17}, {{{85,8}},131},
+ {{{82,7}},31}, {{{0,8}},113}, {{{0,8}},49}, {{{0,9}},195},
+ {{{80,7}},10}, {{{0,8}},97}, {{{0,8}},33}, {{{0,9}},163},
+ {{{0,8}},1}, {{{0,8}},129}, {{{0,8}},65}, {{{0,9}},227},
+ {{{80,7}},6}, {{{0,8}},89}, {{{0,8}},25}, {{{0,9}},147},
+ {{{83,7}},59}, {{{0,8}},121}, {{{0,8}},57}, {{{0,9}},211},
+ {{{81,7}},17}, {{{0,8}},105}, {{{0,8}},41}, {{{0,9}},179},
+ {{{0,8}},9}, {{{0,8}},137}, {{{0,8}},73}, {{{0,9}},243},
+ {{{80,7}},4}, {{{0,8}},85}, {{{0,8}},21}, {{{80,8}},258},
+ {{{83,7}},43}, {{{0,8}},117}, {{{0,8}},53}, {{{0,9}},203},
+ {{{81,7}},13}, {{{0,8}},101}, {{{0,8}},37}, {{{0,9}},171},
+ {{{0,8}},5}, {{{0,8}},133}, {{{0,8}},69}, {{{0,9}},235},
+ {{{80,7}},8}, {{{0,8}},93}, {{{0,8}},29}, {{{0,9}},155},
+ {{{84,7}},83}, {{{0,8}},125}, {{{0,8}},61}, {{{0,9}},219},
+ {{{82,7}},23}, {{{0,8}},109}, {{{0,8}},45}, {{{0,9}},187},
+ {{{0,8}},13}, {{{0,8}},141}, {{{0,8}},77}, {{{0,9}},251},
+ {{{80,7}},3}, {{{0,8}},83}, {{{0,8}},19}, {{{85,8}},195},
+ {{{83,7}},35}, {{{0,8}},115}, {{{0,8}},51}, {{{0,9}},199},
+ {{{81,7}},11}, {{{0,8}},99}, {{{0,8}},35}, {{{0,9}},167},
+ {{{0,8}},3}, {{{0,8}},131}, {{{0,8}},67}, {{{0,9}},231},
+ {{{80,7}},7}, {{{0,8}},91}, {{{0,8}},27}, {{{0,9}},151},
+ {{{84,7}},67}, {{{0,8}},123}, {{{0,8}},59}, {{{0,9}},215},
+ {{{82,7}},19}, {{{0,8}},107}, {{{0,8}},43}, {{{0,9}},183},
+ {{{0,8}},11}, {{{0,8}},139}, {{{0,8}},75}, {{{0,9}},247},
+ {{{80,7}},5}, {{{0,8}},87}, {{{0,8}},23}, {{{192,8}},0},
+ {{{83,7}},51}, {{{0,8}},119}, {{{0,8}},55}, {{{0,9}},207},
+ {{{81,7}},15}, {{{0,8}},103}, {{{0,8}},39}, {{{0,9}},175},
+ {{{0,8}},7}, {{{0,8}},135}, {{{0,8}},71}, {{{0,9}},239},
+ {{{80,7}},9}, {{{0,8}},95}, {{{0,8}},31}, {{{0,9}},159},
+ {{{84,7}},99}, {{{0,8}},127}, {{{0,8}},63}, {{{0,9}},223},
+ {{{82,7}},27}, {{{0,8}},111}, {{{0,8}},47}, {{{0,9}},191},
+ {{{0,8}},15}, {{{0,8}},143}, {{{0,8}},79}, {{{0,9}},255}
+ };
+local inflate_huft fixed_td[] = {
+ {{{80,5}},1}, {{{87,5}},257}, {{{83,5}},17}, {{{91,5}},4097},
+ {{{81,5}},5}, {{{89,5}},1025}, {{{85,5}},65}, {{{93,5}},16385},
+ {{{80,5}},3}, {{{88,5}},513}, {{{84,5}},33}, {{{92,5}},8193},
+ {{{82,5}},9}, {{{90,5}},2049}, {{{86,5}},129}, {{{192,5}},24577},
+ {{{80,5}},2}, {{{87,5}},385}, {{{83,5}},25}, {{{91,5}},6145},
+ {{{81,5}},7}, {{{89,5}},1537}, {{{85,5}},97}, {{{93,5}},24577},
+ {{{80,5}},4}, {{{88,5}},769}, {{{84,5}},49}, {{{92,5}},12289},
+ {{{82,5}},13}, {{{90,5}},3073}, {{{86,5}},193}, {{{192,5}},24577}
+ };
--- /dev/null
+++ b/libfreetype/inflate.c
@@ -1,0 +1,273 @@
+/* inflate.c -- zlib interface to inflate modules
+ * Copyright (C) 1995-2002 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+#include "zutil.h"
+#include "infblock.h"
+
+#define DONE INFLATE_DONE
+#define BAD INFLATE_BAD
+
+typedef enum {
+ METHOD, /* waiting for method byte */
+ FLAG, /* waiting for flag byte */
+ DICT4, /* four dictionary check bytes to go */
+ DICT3, /* three dictionary check bytes to go */
+ DICT2, /* two dictionary check bytes to go */
+ DICT1, /* one dictionary check byte to go */
+ DICT0, /* waiting for inflateSetDictionary */
+ BLOCKS, /* decompressing blocks */
+ CHECK4, /* four check bytes to go */
+ CHECK3, /* three check bytes to go */
+ CHECK2, /* two check bytes to go */
+ CHECK1, /* one check byte to go */
+ DONE, /* finished check, done */
+ BAD} /* got an error--stay here */
+inflate_mode;
+
+/* inflate private state */
+struct internal_state {
+
+ /* mode */
+ inflate_mode mode; /* current inflate mode */
+
+ /* mode dependent information */
+ union {
+ uInt method; /* if FLAGS, method byte */
+ struct {
+ uLong was; /* computed check value */
+ uLong need; /* stream check value */
+ } check; /* if CHECK, check values to compare */
+ uInt marker; /* if BAD, inflateSync's marker bytes count */
+ } sub; /* submode */
+
+ /* mode independent information */
+ int nowrap; /* flag for no wrapper */
+ uInt wbits; /* log2(window size) (8..15, defaults to 15) */
+ inflate_blocks_statef
+ *blocks; /* current inflate_blocks state */
+
+};
+
+
+int ZEXPORT inflateReset(z)
+z_streamp z;
+{
+ if (z == Z_NULL || z->state == Z_NULL)
+ return Z_STREAM_ERROR;
+ z->total_in = z->total_out = 0;
+ z->msg = Z_NULL;
+ z->state->mode = z->state->nowrap ? BLOCKS : METHOD;
+ inflate_blocks_reset(z->state->blocks, z, Z_NULL);
+ Tracev((stderr, "inflate: reset\n"));
+ return Z_OK;
+}
+
+
+int ZEXPORT inflateEnd(z)
+z_streamp z;
+{
+ if (z == Z_NULL || z->state == Z_NULL || z->zfree == Z_NULL)
+ return Z_STREAM_ERROR;
+ if (z->state->blocks != Z_NULL)
+ inflate_blocks_free(z->state->blocks, z);
+ ZFREE(z, z->state);
+ z->state = Z_NULL;
+ Tracev((stderr, "inflate: end\n"));
+ return Z_OK;
+}
+
+
+int ZEXPORT inflateInit2_(z, w, version, stream_size)
+z_streamp z;
+int w;
+const char *version;
+int stream_size;
+{
+ if (version == Z_NULL || version[0] != ZLIB_VERSION[0] ||
+ stream_size != sizeof(z_stream))
+ return Z_VERSION_ERROR;
+
+ /* initialize state */
+ if (z == Z_NULL)
+ return Z_STREAM_ERROR;
+ z->msg = Z_NULL;
+ if (z->zalloc == Z_NULL)
+ {
+ z->zalloc = zcalloc;
+ z->opaque = (voidpf)0;
+ }
+ if (z->zfree == Z_NULL) z->zfree = zcfree;
+ if ((z->state = (struct internal_state FAR *)
+ ZALLOC(z,1,sizeof(struct internal_state))) == Z_NULL)
+ return Z_MEM_ERROR;
+ z->state->blocks = Z_NULL;
+
+ /* handle undocumented nowrap option (no zlib header or check) */
+ z->state->nowrap = 0;
+ if (w < 0)
+ {
+ w = - w;
+ z->state->nowrap = 1;
+ }
+
+ /* set window size */
+ if (w < 8 || w > 15)
+ {
+ inflateEnd(z);
+ return Z_STREAM_ERROR;
+ }
+ z->state->wbits = (uInt)w;
+
+ /* create inflate_blocks state */
+ if ((z->state->blocks =
+ inflate_blocks_new(z, z->state->nowrap ? Z_NULL : adler32, (uInt)1 << w))
+ == Z_NULL)
+ {
+ inflateEnd(z);
+ return Z_MEM_ERROR;
+ }
+ Tracev((stderr, "inflate: allocated\n"));
+
+ /* reset state */
+ inflateReset(z);
+ return Z_OK;
+}
+
+
+
+#undef NEEDBYTE
+#define NEEDBYTE {if(z->avail_in==0)return r;r=f;}
+
+#undef NEXTBYTE
+#define NEXTBYTE (z->avail_in--,z->total_in++,*z->next_in++)
+
+
+int ZEXPORT inflate(z, f)
+z_streamp z;
+int f;
+{
+ int r;
+ uInt b;
+
+ if (z == Z_NULL || z->state == Z_NULL || z->next_in == Z_NULL)
+ return Z_STREAM_ERROR;
+ f = f == Z_FINISH ? Z_BUF_ERROR : Z_OK;
+ r = Z_BUF_ERROR;
+ while (1) switch (z->state->mode)
+ {
+ case METHOD:
+ NEEDBYTE
+ if (((z->state->sub.method = NEXTBYTE) & 0xf) != Z_DEFLATED)
+ {
+ z->state->mode = BAD;
+ z->msg = (char*)"unknown compression method";
+ z->state->sub.marker = 5; /* can't try inflateSync */
+ break;
+ }
+ if ((z->state->sub.method >> 4) + 8 > z->state->wbits)
+ {
+ z->state->mode = BAD;
+ z->msg = (char*)"invalid window size";
+ z->state->sub.marker = 5; /* can't try inflateSync */
+ break;
+ }
+ z->state->mode = FLAG;
+ case FLAG:
+ NEEDBYTE
+ b = NEXTBYTE;
+ if (((z->state->sub.method << 8) + b) % 31)
+ {
+ z->state->mode = BAD;
+ z->msg = (char*)"incorrect header check";
+ z->state->sub.marker = 5; /* can't try inflateSync */
+ break;
+ }
+ Tracev((stderr, "inflate: zlib header ok\n"));
+ if (!(b & PRESET_DICT))
+ {
+ z->state->mode = BLOCKS;
+ break;
+ }
+ z->state->mode = DICT4;
+ case DICT4:
+ NEEDBYTE
+ z->state->sub.check.need = (uLong)NEXTBYTE << 24;
+ z->state->mode = DICT3;
+ case DICT3:
+ NEEDBYTE
+ z->state->sub.check.need += (uLong)NEXTBYTE << 16;
+ z->state->mode = DICT2;
+ case DICT2:
+ NEEDBYTE
+ z->state->sub.check.need += (uLong)NEXTBYTE << 8;
+ z->state->mode = DICT1;
+ case DICT1:
+ NEEDBYTE
+ z->state->sub.check.need += (uLong)NEXTBYTE;
+ z->adler = z->state->sub.check.need;
+ z->state->mode = DICT0;
+ return Z_NEED_DICT;
+ case DICT0:
+ z->state->mode = BAD;
+ z->msg = (char*)"need dictionary";
+ z->state->sub.marker = 0; /* can try inflateSync */
+ return Z_STREAM_ERROR;
+ case BLOCKS:
+ r = inflate_blocks(z->state->blocks, z, r);
+ if (r == Z_DATA_ERROR)
+ {
+ z->state->mode = BAD;
+ z->state->sub.marker = 0; /* can try inflateSync */
+ break;
+ }
+ if (r == Z_OK)
+ r = f;
+ if (r != Z_STREAM_END)
+ return r;
+ r = f;
+ inflate_blocks_reset(z->state->blocks, z, &z->state->sub.check.was);
+ if (z->state->nowrap)
+ {
+ z->state->mode = DONE;
+ break;
+ }
+ z->state->mode = CHECK4;
+ case CHECK4:
+ NEEDBYTE
+ z->state->sub.check.need = (uLong)NEXTBYTE << 24;
+ z->state->mode = CHECK3;
+ case CHECK3:
+ NEEDBYTE
+ z->state->sub.check.need += (uLong)NEXTBYTE << 16;
+ z->state->mode = CHECK2;
+ case CHECK2:
+ NEEDBYTE
+ z->state->sub.check.need += (uLong)NEXTBYTE << 8;
+ z->state->mode = CHECK1;
+ case CHECK1:
+ NEEDBYTE
+ z->state->sub.check.need += (uLong)NEXTBYTE;
+
+ if (z->state->sub.check.was != z->state->sub.check.need)
+ {
+ z->state->mode = BAD;
+ z->msg = (char*)"incorrect data check";
+ z->state->sub.marker = 5; /* can't try inflateSync */
+ break;
+ }
+ Tracev((stderr, "inflate: zlib check ok\n"));
+ z->state->mode = DONE;
+ case DONE:
+ return Z_STREAM_END;
+ case BAD:
+ return Z_DATA_ERROR;
+ default:
+ return Z_STREAM_ERROR;
+ }
+#ifdef NEED_DUMMY_RETURN
+ return Z_STREAM_ERROR; /* Some dumb compilers complain without this */
+#endif
+}
+
--- /dev/null
+++ b/libfreetype/inftrees.c
@@ -1,0 +1,453 @@
+/* inftrees.c -- generate Huffman trees for efficient decoding
+ * Copyright (C) 1995-2002 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+#include "zutil.h"
+#include "inftrees.h"
+
+#if !defined(BUILDFIXED) && !defined(STDC)
+# define BUILDFIXED /* non ANSI compilers may not accept inffixed.h */
+#endif
+
+local const char inflate_copyright[] =
+ " inflate 1.1.4 Copyright 1995-2002 Mark Adler ";
+/*
+ If you use the zlib library in a product, an acknowledgment is welcome
+ in the documentation of your product. If for some reason you cannot
+ include such an acknowledgment, I would appreciate that you keep this
+ copyright string in the executable of your product.
+ */
+
+/* simplify the use of the inflate_huft type with some defines */
+#define exop word.what.Exop
+#define bits word.what.Bits
+
+
+local int huft_build OF((
+ uIntf *, /* code lengths in bits */
+ uInt, /* number of codes */
+ uInt, /* number of "simple" codes */
+ const uIntf *, /* list of base values for non-simple codes */
+ const uIntf *, /* list of extra bits for non-simple codes */
+ inflate_huft * FAR*,/* result: starting table */
+ uIntf *, /* maximum lookup bits (returns actual) */
+ inflate_huft *, /* space for trees */
+ uInt *, /* hufts used in space */
+ uIntf * )); /* space for values */
+
+/* Tables for deflate from PKZIP's appnote.txt. */
+local const uInt cplens[31] = { /* Copy lengths for literal codes 257..285 */
+ 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31,
+ 35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0};
+ /* see note #13 above about 258 */
+local const uInt cplext[31] = { /* Extra bits for literal codes 257..285 */
+ 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2,
+ 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0, 112, 112}; /* 112==invalid */
+local const uInt cpdist[30] = { /* Copy offsets for distance codes 0..29 */
+ 1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193,
+ 257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145,
+ 8193, 12289, 16385, 24577};
+local const uInt cpdext[30] = { /* Extra bits for distance codes */
+ 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6,
+ 7, 7, 8, 8, 9, 9, 10, 10, 11, 11,
+ 12, 12, 13, 13};
+
+/*
+ Huffman code decoding is performed using a multi-level table lookup.
+ The fastest way to decode is to simply build a lookup table whose
+ size is determined by the longest code. However, the time it takes
+ to build this table can also be a factor if the data being decoded
+ is not very long. The most common codes are necessarily the
+ shortest codes, so those codes dominate the decoding time, and hence
+ the speed. The idea is you can have a shorter table that decodes the
+ shorter, more probable codes, and then point to subsidiary tables for
+ the longer codes. The time it costs to decode the longer codes is
+ then traded against the time it takes to make longer tables.
+
+ This results of this trade are in the variables lbits and dbits
+ below. lbits is the number of bits the first level table for literal/
+ length codes can decode in one step, and dbits is the same thing for
+ the distance codes. Subsequent tables are also less than or equal to
+ those sizes. These values may be adjusted either when all of the
+ codes are shorter than that, in which case the longest code length in
+ bits is used, or when the shortest code is *longer* than the requested
+ table size, in which case the length of the shortest code in bits is
+ used.
+
+ There are two different values for the two tables, since they code a
+ different number of possibilities each. The literal/length table
+ codes 286 possible values, or in a flat code, a little over eight
+ bits. The distance table codes 30 possible values, or a little less
+ than five bits, flat. The optimum values for speed end up being
+ about one bit more than those, so lbits is 8+1 and dbits is 5+1.
+ The optimum values may differ though from machine to machine, and
+ possibly even between compilers. Your mileage may vary.
+ */
+
+
+/* If BMAX needs to be larger than 16, then h and x[] should be uLong. */
+#define BMAX 15 /* maximum bit length of any code */
+
+local int huft_build(b, n, s, d, e, t, m, hp, hn, v)
+uIntf *b; /* code lengths in bits (all assumed <= BMAX) */
+uInt n; /* number of codes (assumed <= 288) */
+uInt s; /* number of simple-valued codes (0..s-1) */
+const uIntf *d; /* list of base values for non-simple codes */
+const uIntf *e; /* list of extra bits for non-simple codes */
+inflate_huft * FAR *t; /* result: starting table */
+uIntf *m; /* maximum lookup bits, returns actual */
+inflate_huft *hp; /* space for trees */
+uInt *hn; /* hufts used in space */
+uIntf *v; /* working area: values in order of bit length */
+/* Given a list of code lengths and a maximum table size, make a set of
+ tables to decode that set of codes. Return Z_OK on success, Z_BUF_ERROR
+ if the given code set is incomplete (the tables are still built in this
+ case), or Z_DATA_ERROR if the input is invalid. */
+{
+
+ uInt a; /* counter for codes of length k */
+ uInt c[BMAX+1]; /* bit length count table */
+ uInt f; /* i repeats in table every f entries */
+ int g; /* maximum code length */
+ int h; /* table level */
+ register uInt i; /* counter, current code */
+ register uInt j; /* counter */
+ register int k; /* number of bits in current code */
+ int l; /* bits per table (returned in m) */
+ uInt mask; /* (1 << w) - 1, to avoid cc -O bug on HP */
+ register uIntf *p; /* pointer into c[], b[], or v[] */
+ inflate_huft *q; /* points to current table */
+ struct inflate_huft_s r; /* table entry for structure assignment */
+ inflate_huft *u[BMAX]; /* table stack */
+ register int w; /* bits before this table == (l * h) */
+ uInt x[BMAX+1]; /* bit offsets, then code stack */
+ uIntf *xp; /* pointer into x */
+ int y; /* number of dummy codes added */
+ uInt z; /* number of entries in current table */
+
+
+ /* Generate counts for each bit length */
+ p = c;
+#define C0 *p++ = 0;
+#define C2 C0 C0 C0 C0
+#define C4 C2 C2 C2 C2
+ C4 /* clear c[]--assume BMAX+1 is 16 */
+ p = b; i = n;
+ do {
+ c[*p++]++; /* assume all entries <= BMAX */
+ } while (--i);
+ if (c[0] == n) /* null input--all zero length codes */
+ {
+ *t = (inflate_huft *)Z_NULL;
+ *m = 0;
+ return Z_OK;
+ }
+
+
+ /* Find minimum and maximum length, bound *m by those */
+ l = *m;
+ for (j = 1; j <= BMAX; j++)
+ if (c[j])
+ break;
+ k = j; /* minimum code length */
+ if ((uInt)l < j)
+ l = j;
+ for (i = BMAX; i; i--)
+ if (c[i])
+ break;
+ g = i; /* maximum code length */
+ if ((uInt)l > i)
+ l = i;
+ *m = l;
+
+
+ /* Adjust last length count to fill out codes, if needed */
+ for (y = 1 << j; j < i; j++, y <<= 1)
+ if ((y -= c[j]) < 0)
+ return Z_DATA_ERROR;
+ if ((y -= c[i]) < 0)
+ return Z_DATA_ERROR;
+ c[i] += y;
+
+
+ /* Generate starting offsets into the value table for each length */
+ x[1] = j = 0;
+ p = c + 1; xp = x + 2;
+ while (--i) { /* note that i == g from above */
+ *xp++ = (j += *p++);
+ }
+
+
+ /* Make a table of values in order of bit lengths */
+ p = b; i = 0;
+ do {
+ if ((j = *p++) != 0)
+ v[x[j]++] = i;
+ } while (++i < n);
+ n = x[g]; /* set n to length of v */
+
+
+ /* Generate the Huffman codes and for each, make the table entries */
+ x[0] = i = 0; /* first Huffman code is zero */
+ p = v; /* grab values in bit order */
+ h = -1; /* no tables yet--level -1 */
+ w = -l; /* bits decoded == (l * h) */
+ u[0] = (inflate_huft *)Z_NULL; /* just to keep compilers happy */
+ q = (inflate_huft *)Z_NULL; /* ditto */
+ z = 0; /* ditto */
+
+ /* go through the bit lengths (k already is bits in shortest code) */
+ for (; k <= g; k++)
+ {
+ a = c[k];
+ while (a--)
+ {
+ /* here i is the Huffman code of length k bits for value *p */
+ /* make tables up to required level */
+ while (k > w + l)
+ {
+ h++;
+ w += l; /* previous table always l bits */
+
+ /* compute minimum size table less than or equal to l bits */
+ z = g - w;
+ z = z > (uInt)l ? (uInt)l : z; /* table size upper limit */
+ if ((f = 1 << (j = k - w)) > a + 1) /* try a k-w bit table */
+ { /* too few codes for k-w bit table */
+ f -= a + 1; /* deduct codes from patterns left */
+ xp = c + k;
+ if (j < z)
+ while (++j < z) /* try smaller tables up to z bits */
+ {
+ if ((f <<= 1) <= *++xp)
+ break; /* enough codes to use up j bits */
+ f -= *xp; /* else deduct codes from patterns */
+ }
+ }
+ z = 1 << j; /* table entries for j-bit table */
+
+ /* allocate new table */
+ if (*hn + z > MANY) /* (note: doesn't matter for fixed) */
+ return Z_DATA_ERROR; /* overflow of MANY */
+ u[h] = q = hp + *hn;
+ *hn += z;
+
+ /* connect to last table, if there is one */
+ if (h)
+ {
+ x[h] = i; /* save pattern for backing up */
+ r.bits = (Byte)l; /* bits to dump before this table */
+ r.exop = (Byte)j; /* bits in this table */
+ j = i >> (w - l);
+ r.base = (uInt)(q - u[h-1] - j); /* offset to this table */
+ u[h-1][j] = r; /* connect to last table */
+ }
+ else
+ *t = q; /* first table is returned result */
+ }
+
+ /* set up table entry in r */
+ r.bits = (Byte)(k - w);
+ if (p >= v + n)
+ r.exop = 128 + 64; /* out of values--invalid code */
+ else if (*p < s)
+ {
+ r.exop = (Byte)(*p < 256 ? 0 : 32 + 64); /* 256 is end-of-block */
+ r.base = *p++; /* simple code is just the value */
+ }
+ else
+ {
+ r.exop = (Byte)(e[*p - s] + 16 + 64);/* non-simple--look up in lists */
+ r.base = d[*p++ - s];
+ }
+
+ /* fill code-like entries with r */
+ f = 1 << (k - w);
+ for (j = i >> w; j < z; j += f)
+ q[j] = r;
+
+ /* backwards increment the k-bit code i */
+ for (j = 1 << (k - 1); i & j; j >>= 1)
+ i ^= j;
+ i ^= j;
+
+ /* backup over finished tables */
+ mask = (1 << w) - 1; /* needed on HP, cc -O bug */
+ while ((i & mask) != x[h])
+ {
+ h--; /* don't need to update q */
+ w -= l;
+ mask = (1 << w) - 1;
+ }
+ }
+ }
+
+
+ /* Return Z_BUF_ERROR if we were given an incomplete table */
+ return y != 0 && g != 1 ? Z_BUF_ERROR : Z_OK;
+}
+
+
+local int inflate_trees_bits(c, bb, tb, hp, z)
+uIntf *c; /* 19 code lengths */
+uIntf *bb; /* bits tree desired/actual depth */
+inflate_huft * FAR *tb; /* bits tree result */
+inflate_huft *hp; /* space for trees */
+z_streamp z; /* for messages */
+{
+ int r;
+ uInt hn = 0; /* hufts used in space */
+ uIntf *v; /* work area for huft_build */
+
+ if ((v = (uIntf*)ZALLOC(z, 19, sizeof(uInt))) == Z_NULL)
+ return Z_MEM_ERROR;
+ r = huft_build(c, 19, 19, (uIntf*)Z_NULL, (uIntf*)Z_NULL,
+ tb, bb, hp, &hn, v);
+ if (r == Z_DATA_ERROR)
+ z->msg = (char*)"oversubscribed dynamic bit lengths tree";
+ else if (r == Z_BUF_ERROR || *bb == 0)
+ {
+ z->msg = (char*)"incomplete dynamic bit lengths tree";
+ r = Z_DATA_ERROR;
+ }
+ ZFREE(z, v);
+ return r;
+}
+
+
+local int inflate_trees_dynamic(nl, nd, c, bl, bd, tl, td, hp, z)
+uInt nl; /* number of literal/length codes */
+uInt nd; /* number of distance codes */
+uIntf *c; /* that many (total) code lengths */
+uIntf *bl; /* literal desired/actual bit depth */
+uIntf *bd; /* distance desired/actual bit depth */
+inflate_huft * FAR *tl; /* literal/length tree result */
+inflate_huft * FAR *td; /* distance tree result */
+inflate_huft *hp; /* space for trees */
+z_streamp z; /* for messages */
+{
+ int r;
+ uInt hn = 0; /* hufts used in space */
+ uIntf *v; /* work area for huft_build */
+
+ /* allocate work area */
+ if ((v = (uIntf*)ZALLOC(z, 288, sizeof(uInt))) == Z_NULL)
+ return Z_MEM_ERROR;
+
+ /* build literal/length tree */
+ r = huft_build(c, nl, 257, cplens, cplext, tl, bl, hp, &hn, v);
+ if (r != Z_OK || *bl == 0)
+ {
+ if (r == Z_DATA_ERROR)
+ z->msg = (char*)"oversubscribed literal/length tree";
+ else if (r != Z_MEM_ERROR)
+ {
+ z->msg = (char*)"incomplete literal/length tree";
+ r = Z_DATA_ERROR;
+ }
+ ZFREE(z, v);
+ return r;
+ }
+
+ /* build distance tree */
+ r = huft_build(c + nl, nd, 0, cpdist, cpdext, td, bd, hp, &hn, v);
+ if (r != Z_OK || (*bd == 0 && nl > 257))
+ {
+ if (r == Z_DATA_ERROR)
+ z->msg = (char*)"oversubscribed distance tree";
+ else if (r == Z_BUF_ERROR) {
+#ifdef PKZIP_BUG_WORKAROUND
+ r = Z_OK;
+ }
+#else
+ z->msg = (char*)"incomplete distance tree";
+ r = Z_DATA_ERROR;
+ }
+ else if (r != Z_MEM_ERROR)
+ {
+ z->msg = (char*)"empty distance tree with lengths";
+ r = Z_DATA_ERROR;
+ }
+ ZFREE(z, v);
+ return r;
+#endif
+ }
+
+ /* done */
+ ZFREE(z, v);
+ return Z_OK;
+}
+
+
+/* build fixed tables only once--keep them here */
+#ifdef BUILDFIXED
+local int fixed_built = 0;
+#define FIXEDH 544 /* number of hufts used by fixed tables */
+local inflate_huft fixed_mem[FIXEDH];
+local uInt fixed_bl;
+local uInt fixed_bd;
+local inflate_huft *fixed_tl;
+local inflate_huft *fixed_td;
+#else
+#include "inffixed.h"
+#endif
+
+
+local int inflate_trees_fixed(bl, bd, tl, td, z)
+uIntf *bl; /* literal desired/actual bit depth */
+uIntf *bd; /* distance desired/actual bit depth */
+inflate_huft * FAR *tl; /* literal/length tree result */
+inflate_huft * FAR *td; /* distance tree result */
+z_streamp z; /* for memory allocation */
+{
+#ifdef BUILDFIXED
+ /* build fixed tables if not already */
+ if (!fixed_built)
+ {
+ int k; /* temporary variable */
+ uInt f = 0; /* number of hufts used in fixed_mem */
+ uIntf *c; /* length list for huft_build */
+ uIntf *v; /* work area for huft_build */
+
+ /* allocate memory */
+ if ((c = (uIntf*)ZALLOC(z, 288, sizeof(uInt))) == Z_NULL)
+ return Z_MEM_ERROR;
+ if ((v = (uIntf*)ZALLOC(z, 288, sizeof(uInt))) == Z_NULL)
+ {
+ ZFREE(z, c);
+ return Z_MEM_ERROR;
+ }
+
+ /* literal table */
+ for (k = 0; k < 144; k++)
+ c[k] = 8;
+ for (; k < 256; k++)
+ c[k] = 9;
+ for (; k < 280; k++)
+ c[k] = 7;
+ for (; k < 288; k++)
+ c[k] = 8;
+ fixed_bl = 9;
+ huft_build(c, 288, 257, cplens, cplext, &fixed_tl, &fixed_bl,
+ fixed_mem, &f, v);
+
+ /* distance table */
+ for (k = 0; k < 30; k++)
+ c[k] = 5;
+ fixed_bd = 5;
+ huft_build(c, 30, 0, cpdist, cpdext, &fixed_td, &fixed_bd,
+ fixed_mem, &f, v);
+
+ /* done */
+ ZFREE(z, v);
+ ZFREE(z, c);
+ fixed_built = 1;
+ }
+#endif
+ *bl = fixed_bl;
+ *bd = fixed_bd;
+ *tl = fixed_tl;
+ *td = fixed_td;
+ return Z_OK;
+}
--- /dev/null
+++ b/libfreetype/inftrees.h
@@ -1,0 +1,63 @@
+/* inftrees.h -- header to use inftrees.c
+ * Copyright (C) 1995-2002 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/* WARNING: this file should *not* be used by applications. It is
+ part of the implementation of the compression library and is
+ subject to change. Applications should only use zlib.h.
+ */
+
+/* Huffman code lookup table entry--this entry is four bytes for machines
+ that have 16-bit pointers (e.g. PC's in the small or medium model). */
+
+#ifndef _INFTREES_H
+#define _INFTREES_H
+
+typedef struct inflate_huft_s FAR inflate_huft;
+
+struct inflate_huft_s {
+ union {
+ struct {
+ Byte Exop; /* number of extra bits or operation */
+ Byte Bits; /* number of bits in this code or subcode */
+ } what;
+ uInt pad; /* pad structure to a power of 2 (4 bytes for */
+ } word; /* 16-bit, 8 bytes for 32-bit int's) */
+ uInt base; /* literal, length base, distance base,
+ or table offset */
+};
+
+/* Maximum size of dynamic tree. The maximum found in a long but non-
+ exhaustive search was 1004 huft structures (850 for length/literals
+ and 154 for distances, the latter actually the result of an
+ exhaustive search). The actual maximum is not known, but the
+ value below is more than safe. */
+#define MANY 1440
+
+local int inflate_trees_bits OF((
+ uIntf *, /* 19 code lengths */
+ uIntf *, /* bits tree desired/actual depth */
+ inflate_huft * FAR *, /* bits tree result */
+ inflate_huft *, /* space for trees */
+ z_streamp)); /* for messages */
+
+local int inflate_trees_dynamic OF((
+ uInt, /* number of literal/length codes */
+ uInt, /* number of distance codes */
+ uIntf *, /* that many (total) code lengths */
+ uIntf *, /* literal desired/actual bit depth */
+ uIntf *, /* distance desired/actual bit depth */
+ inflate_huft * FAR *, /* literal/length tree result */
+ inflate_huft * FAR *, /* distance tree result */
+ inflate_huft *, /* space for trees */
+ z_streamp)); /* for messages */
+
+local int inflate_trees_fixed OF((
+ uIntf *, /* literal desired/actual bit depth */
+ uIntf *, /* distance desired/actual bit depth */
+ inflate_huft * FAR *, /* literal/length tree result */
+ inflate_huft * FAR *, /* distance tree result */
+ z_streamp)); /* for memory allocation */
+
+#endif /* _INFTREES_H */
--- /dev/null
+++ b/libfreetype/infutil.c
@@ -1,0 +1,86 @@
+/* inflate_util.c -- data and routines common to blocks and codes
+ * Copyright (C) 1995-2002 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+#include "zutil.h"
+#include "infblock.h"
+#include "inftrees.h"
+#include "infcodes.h"
+#include "infutil.h"
+
+
+/* And'ing with mask[n] masks the lower n bits */
+local uInt inflate_mask[17] = {
+ 0x0000,
+ 0x0001, 0x0003, 0x0007, 0x000f, 0x001f, 0x003f, 0x007f, 0x00ff,
+ 0x01ff, 0x03ff, 0x07ff, 0x0fff, 0x1fff, 0x3fff, 0x7fff, 0xffff
+};
+
+
+/* copy as much as possible from the sliding window to the output area */
+local int inflate_flush(s, z, r)
+inflate_blocks_statef *s;
+z_streamp z;
+int r;
+{
+ uInt n;
+ Bytef *p;
+ Bytef *q;
+
+ /* local copies of source and destination pointers */
+ p = z->next_out;
+ q = s->read;
+
+ /* compute number of bytes to copy as far as end of window */
+ n = (uInt)((q <= s->write ? s->write : s->end) - q);
+ if (n > z->avail_out) n = z->avail_out;
+ if (n && r == Z_BUF_ERROR) r = Z_OK;
+
+ /* update counters */
+ z->avail_out -= n;
+ z->total_out += n;
+
+ /* update check information */
+ if (s->checkfn != Z_NULL)
+ z->adler = s->check = (*s->checkfn)(s->check, q, n);
+
+ /* copy as far as end of window */
+ zmemcpy(p, q, n);
+ p += n;
+ q += n;
+
+ /* see if more to copy at beginning of window */
+ if (q == s->end)
+ {
+ /* wrap pointers */
+ q = s->window;
+ if (s->write == s->end)
+ s->write = s->window;
+
+ /* compute bytes to copy */
+ n = (uInt)(s->write - q);
+ if (n > z->avail_out) n = z->avail_out;
+ if (n && r == Z_BUF_ERROR) r = Z_OK;
+
+ /* update counters */
+ z->avail_out -= n;
+ z->total_out += n;
+
+ /* update check information */
+ if (s->checkfn != Z_NULL)
+ z->adler = s->check = (*s->checkfn)(s->check, q, n);
+
+ /* copy */
+ zmemcpy(p, q, n);
+ p += n;
+ q += n;
+ }
+
+ /* update pointers */
+ z->next_out = p;
+ s->read = q;
+
+ /* done */
+ return r;
+}
--- /dev/null
+++ b/libfreetype/infutil.h
@@ -1,0 +1,96 @@
+/* infutil.h -- types and macros common to blocks and codes
+ * Copyright (C) 1995-2002 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/* WARNING: this file should *not* be used by applications. It is
+ part of the implementation of the compression library and is
+ subject to change. Applications should only use zlib.h.
+ */
+
+#ifndef _INFUTIL_H
+#define _INFUTIL_H
+
+typedef enum {
+ TYPE, /* get type bits (3, including end bit) */
+ LENS, /* get lengths for stored */
+ STORED, /* processing stored block */
+ TABLE, /* get table lengths */
+ BTREE, /* get bit lengths tree for a dynamic block */
+ DTREE, /* get length, distance trees for a dynamic block */
+ CODES, /* processing fixed or dynamic block */
+ DRY, /* output remaining window bytes */
+ DONE, /* finished last block, done */
+ BAD} /* got a data error--stuck here */
+inflate_block_mode;
+
+/* inflate blocks semi-private state */
+struct inflate_blocks_state {
+
+ /* mode */
+ inflate_block_mode mode; /* current inflate_block mode */
+
+ /* mode dependent information */
+ union {
+ uInt left; /* if STORED, bytes left to copy */
+ struct {
+ uInt table; /* table lengths (14 bits) */
+ uInt index; /* index into blens (or border) */
+ uIntf *blens; /* bit lengths of codes */
+ uInt bb; /* bit length tree depth */
+ inflate_huft *tb; /* bit length decoding tree */
+ } trees; /* if DTREE, decoding info for trees */
+ struct {
+ inflate_codes_statef
+ *codes;
+ } decode; /* if CODES, current state */
+ } sub; /* submode */
+ uInt last; /* true if this block is the last block */
+
+ /* mode independent information */
+ uInt bitk; /* bits in bit buffer */
+ uLong bitb; /* bit buffer */
+ inflate_huft *hufts; /* single malloc for tree space */
+ Bytef *window; /* sliding window */
+ Bytef *end; /* one byte after sliding window */
+ Bytef *read; /* window read pointer */
+ Bytef *write; /* window write pointer */
+ check_func checkfn; /* check function */
+ uLong check; /* check on output */
+
+};
+
+
+/* defines for inflate input/output */
+/* update pointers and return */
+#define UPDBITS {s->bitb=b;s->bitk=k;}
+#define UPDIN {z->avail_in=n;z->total_in+=p-z->next_in;z->next_in=p;}
+#define UPDOUT {s->write=q;}
+#define UPDATE {UPDBITS UPDIN UPDOUT}
+#define LEAVE {UPDATE return inflate_flush(s,z,r);}
+/* get bytes and bits */
+#define LOADIN {p=z->next_in;n=z->avail_in;b=s->bitb;k=s->bitk;}
+#define NEEDBYTE {if(n)r=Z_OK;else LEAVE}
+#define NEXTBYTE (n--,*p++)
+#define NEEDBITS(j) {while(k<(j)){NEEDBYTE;b|=((uLong)NEXTBYTE)<<k;k+=8;}}
+#define DUMPBITS(j) {b>>=(j);k-=(j);}
+/* output bytes */
+#define WAVAIL (uInt)(q<s->read?s->read-q-1:s->end-q)
+#define LOADOUT {q=s->write;m=(uInt)WAVAIL;}
+#define WRAP {if(q==s->end&&s->read!=s->window){q=s->window;m=(uInt)WAVAIL;}}
+#define FLUSH {UPDOUT r=inflate_flush(s,z,r); LOADOUT}
+#define NEEDOUT {if(m==0){WRAP if(m==0){FLUSH WRAP if(m==0) LEAVE}}r=Z_OK;}
+#define OUTBYTE(a) {*q++=(Byte)(a);m--;}
+/* load local pointers */
+#define LOAD {LOADIN LOADOUT}
+
+/* masks for lower bits (size given to avoid silly warnings with Visual C++) */
+local uInt inflate_mask[17];
+
+/* copy as much as possible from the sliding window to the output area */
+local int inflate_flush OF((
+ inflate_blocks_statef *,
+ z_streamp ,
+ int));
+
+#endif
--- /dev/null
+++ b/libfreetype/mkfile
@@ -1,0 +1,49 @@
+<../mkconfig
+
+LIB=libfreetype.a
+
+OFILES=\
+ freetype.$O\
+ autohint.$O\
+ ftbase.$O\
+ ftglyph.$O\
+ cff.$O\
+ psaux.$O\
+ psnames.$O\
+ raster.$O\
+ sfnt.$O\
+ smooth.$O\
+ truetype.$O\
+ type1.$O\
+ type42.$O\
+ ftsystem_inf.$O\
+ ftinit.$O\
+ pshinter.$O\
+ pfr.$O\
+
+# optional modules - see include/freetype/config/ftmodule.h
+# type1cid.$O\
+# winfnt.$O\
+
+<$ROOT/mkfiles/mksyslib-$SHELLTYPE
+
+CFLAGS= $ANSICPP $CFLAGS -I$ROOT/include/freetype -I.
+
+freetype.$O: $ROOT/include/freetype.h
+
+# FreeType is organised by #include of .c files
+# here are the necessary depenencies
+
+autohint.$O: ahangles.c ahglyph.c ahglobal.c ahhint.c ahmodule.c
+ftbase.$O: ftutil.c ftdbgmem.c ftstream.c ftcalc.c fttrigon.c ftoutln.c ftgloadr.c ftobjs.c ftnames.c
+cff.$O: cffdrivr.c cffparse.c cffload.c cffobjs.c cffgload.c cffcmap.c
+psaux.$O: psobjs.c psauxmod.c t1decode.c t1cmap.c
+psnames.$O: psmodule.c
+raster.$O: ftraster.c ftrend1.c
+sfnt.$O: ttload.c ttcmap.c ttcmap0.c sfobjs.c sfdriver.c
+smooth.$O: ftgrays.c ftsmooth.c
+truetype.$O: ttdriver.c ttpload.c ttgload.c ttobjs.c
+type1.$O: t1parse.c t1load.c t1objs.c t1driver.c t1gload.c
+type42.$O: t42objs.c t42parse.c t42drivr.c
+pshinter.$O: pshrec.c pshglob.c pshalgo1.c pshalgo2.c pshalgo3.c pshmod.c
+pfr.$O: pfrload.c pfrgload.c pfrcmap.c pfrobjs.c pfrdrivr.c pfrsbit.c
--- /dev/null
+++ b/libfreetype/otlayout.h
@@ -1,0 +1,205 @@
+#ifndef __OT_LAYOUT_H__
+#define __OT_LAYOUT_H__
+
+
+#include "otlconf.h"
+
+OTL_BEGIN_HEADER
+
+ /************************************************************************/
+ /************************************************************************/
+ /***** *****/
+ /***** BASE DATA TYPES *****/
+ /***** *****/
+ /************************************************************************/
+ /************************************************************************/
+
+ typedef unsigned char OTL_Byte;
+ typedef const OTL_Byte* OTL_Bytes;
+
+ typedef int OTL_Error;
+
+ typedef void* OTL_Pointer;
+
+ typedef int OTL_Int;
+ typedef unsigned int OTL_UInt;
+
+ typedef long OTL_Long;
+ typedef unsigned long OTL_ULong;
+
+ typedef short OTL_Int16;
+ typedef unsigned short OTL_UInt16;
+
+
+#if OTL_SIZEOF_INT == 4
+
+ typedef int OTL_Int32;
+ typedef unsigned int OTL_UInt32;
+
+#elif OTL_SIZEOF_LONG == 4
+
+ typedef long OTL_Int32;
+ typedef unsigned long OTL_UInt32;
+
+#else
+# error "no 32-bits type found"
+#endif
+
+ typedef OTL_UInt32 OTL_Tag;
+
+ /************************************************************************/
+ /************************************************************************/
+ /***** *****/
+ /***** ERROR CODES *****/
+ /***** *****/
+ /************************************************************************/
+ /************************************************************************/
+
+ typedef enum
+ {
+ OTL_Err_Ok = 0,
+ OTL_Err_InvalidArgument,
+ OTL_Err_InvalidFormat,
+ OTL_Err_InvalidOffset,
+
+ OTL_Err_Max
+
+ } OTL_Error;
+
+
+ /************************************************************************/
+ /************************************************************************/
+ /***** *****/
+ /***** MEMORY MANAGEMENT *****/
+ /***** *****/
+ /************************************************************************/
+ /************************************************************************/
+
+ typedef OTL_Pointer (*OTL_AllocFunc)( OTL_ULong size,
+ OTL_Pointer data );
+
+ typedef OTL_Pointer (*OTL_ReallocFunc)( OTL_Pointer block,
+ OTL_ULong size,
+ OTL_Pointer data );
+
+ typedef void (*OTL_FreeFunc)( OTL_Pointer block,
+ OTL_Pointer data );
+
+ typedef struct OTL_MemoryRec_
+ {
+ OTL_Pointer mem_data;
+ OTL_AllocFunc mem_alloc;
+ OTL_ReallocFunc mem_realloc;
+ OTL_FreeFunc mem_free;
+
+ } OTL_MemoryRec, *OTL_Memory;
+
+ /************************************************************************/
+ /************************************************************************/
+ /***** *****/
+ /***** ENUMERATIONS *****/
+ /***** *****/
+ /************************************************************************/
+ /************************************************************************/
+
+/* re-define OTL_MAKE_TAG to something different if you're not */
+/* using an ASCII-based character set (Vaxes anyone ?) */
+#ifndef OTL_MAKE_TAG
+#define OTL_MAKE_TAG(c1,c2,c3,c4) \
+ ( ( (OTL_UInt32)(c1) << 24 ) | \
+ (OTL_UInt32)(c2) << 16 ) | \
+ (OTL_UInt32)(c3) << 8 ) | \
+ (OTL_UInt32)(c4) )
+#endif
+
+ typedef enum OTL_ScriptTag_
+ {
+ OTL_SCRIPT_NONE = 0,
+
+#define OTL_SCRIPT_TAG(c1,c2,c3,c4,s,n) OTL_SCRIPT_TAG_ ## n = OTL_MAKE_TAG(c1,c2,c3,c4),
+#include "otltags.h"
+
+ OTL_SCRIPT_MAX
+
+ } OTL_ScriptTag;
+
+
+ typedef enum OTL_LangTag_
+ {
+ OTL_LANG_DEFAULT = 0,
+
+#define OTL_LANG_TAG(c1,c2,c3,c4,s,n) OTL_LANG_TAG_ ## n = OTL_MAKE_TAG(c1,c2,c3,c4),
+#include "otltags.h"
+
+ OTL_LANG_MAX
+
+ } OTL_LangTag;
+
+
+ /************************************************************************/
+ /************************************************************************/
+ /***** *****/
+ /***** MEMORY READS *****/
+ /***** *****/
+ /************************************************************************/
+ /************************************************************************/
+
+#define OTL_PEEK_USHORT(p) ( ((OTL_UInt)((p)[0]) << 8) | \
+ ((OTL_UInt)((p)[1]) ) )
+
+#define OTL_PEEK_ULONG(p) ( ((OTL_UInt32)((p)[0]) << 24) | \
+ ((OTL_UInt32)((p)[1]) << 16) | \
+ ((OTL_UInt32)((p)[2]) << 8) | \
+ ((OTL_UInt32)((p)[3]) ) )
+
+#define OTL_PEEK_SHORT(p) ((OTL_Int16)OTL_PEEK_USHORT(p))
+
+#define OTL_PEEK_LONG(p) ((OTL_Int32)OTL_PEEK_ULONG(p))
+
+#define OTL_NEXT_USHORT(p) ( (p) += 2, OTL_PEEK_USHORT((p)-2) )
+#define OTL_NEXT_ULONG(p) ( (p) += 4, OTL_PEEK_ULONG((p)-4) )
+
+#define OTL_NEXT_SHORT(p) ((OTL_Int16)OTL_NEXT_USHORT(p))
+#define OTL_NEXT_LONG(p) ((OTL_Int32)OTL_NEXT_ULONG(p))
+
+ /************************************************************************/
+ /************************************************************************/
+ /***** *****/
+ /***** VALIDATION *****/
+ /***** *****/
+ /************************************************************************/
+ /************************************************************************/
+
+ typedef struct OTL_ValidatorRec_* OTL_Validator;
+
+ typedef struct OTL_ValidatorRec_
+ {
+ OTL_Bytes limit;
+ OTL_Bytes base;
+ OTL_Error error;
+ OTL_jmp_buf jump_buffer;
+
+ } OTL_ValidatorRec;
+
+ typedef void (*OTL_ValidateFunc)( OTL_Bytes table,
+ OTL_Valid valid );
+
+ OTL_API( void )
+ otl_validator_error( OTL_Validator validator,
+ OTL_Error error );
+
+#define OTL_INVALID(e) otl_validator_error( valid, e )
+
+#define OTL_INVALID_TOO_SHORT OTL_INVALID( OTL_Err_InvalidOffset )
+#define OTL_INVALID_DATA OTL_INVALID( OTL_Err_InvalidFormat )
+
+#define OTL_CHECK(_count) OTL_BEGIN_STMNT \
+ if ( p + (_count) > valid->limit ) \
+ OTL_INVALID_TOO_SHORT; \
+ OTL_END_STMNT
+
+ /* */
+
+OTL_END_HEADER
+
+#endif /* __OPENTYPE_LAYOUT_H__ */
--- /dev/null
+++ b/libfreetype/otlbase.c
@@ -1,0 +1,181 @@
+#include "otlbase.h"
+#include "otlcommn.h"
+
+ static void
+ otl_base_coord_validate( OTL_Bytes table,
+ OTL_Validator valid )
+ {
+ OTL_Bytes p = table;
+ OTL_UInt format;
+
+ OTL_CHECK( 4 );
+
+ format = OTL_NEXT_USHORT( p );
+ p += 2;
+
+ switch ( format )
+ {
+ case 1:
+ break;
+
+ case 2:
+ OTL_CHECK( 4 );
+ break;
+
+ case 3:
+ OTL_CHECK( 2 );
+ otl_device_table_validate( table + OTL_PEEK_USHORT( p ) );
+ break;
+
+ default:
+ OTL_INVALID_DATA;
+ }
+ }
+
+
+ static void
+ otl_base_tag_list_validate( OTL_Bytes table,
+ OTL_Validator valid )
+ {
+ OTL_Bytes p = table;
+ OTL_UInt count;
+
+ OTL_CHECK(2);
+
+ count = OTL_NEXT_USHORT( p );
+ OTL_CHECK( count*4 );
+ }
+
+
+
+ static void
+ otl_base_values_validate( OTL_Bytes table,
+ OTL_Validator valid )
+ {
+ OTL_Bytes p = table;
+ OTL_UInt count;
+
+ OTL_CHECK( 4 );
+
+ p += 2; /* skip default index */
+ count = OTL_NEXT_USHORT( p );
+
+ OTL_CHECK( count*2 );
+
+ for ( ; count > 0; count-- )
+ otl_base_coord_validate( table + OTL_NEXT_USHORT( p ), valid );
+ }
+
+
+ static void
+ otl_base_minmax_validate( OTL_Bytes table,
+ OTL_Validator valid )
+ {
+ OTL_Bytes p = table;
+ OTL_UInt min_coord, max_coord, count;
+
+ OTL_CHECK(6);
+ min_coord = OTL_NEXT_USHORT( p );
+ max_coord = OTL_NEXT_USHORT( p );
+ count = OTL_NEXT_USHORT( p );
+
+ if ( min_coord )
+ otl_base_coord_validate( table + min_coord, valid );
+
+ if ( max_coord )
+ otl_base_coord_validate( table + max_coord, valid );
+
+ OTL_CHECK( count*8 );
+ for ( ; count > 0; count-- )
+ {
+ p += 4; /* ignore tag */
+ min_coord = OTL_NEXT_USHORT( p );
+ max_coord = OTL_NEXT_USHORT( p );
+
+ if ( min_coord )
+ otl_base_coord_validate( table + min_coord, valid );
+
+ if ( max_coord )
+ otl_base_coord_validate( table + max_coord, valid );
+ }
+ }
+
+
+ static void
+ otl_base_script_validate( OTL_Bytes table,
+ OTL_Validator valid )
+ {
+ OTL_Bytes p = table;
+ OTL_UInt values, default_minmax;
+
+ OTL_CHECK(6);
+
+ values = OTL_NEXT_USHORT( p );
+ default_minmax = OTL_NEXT_USHORT( p );
+ count = OTL_NEXT_USHORT( p );
+
+ if ( values )
+ otl_base_values_validate( table + values, valid );
+
+ if ( default_minmax )
+ otl_base_minmax_validate( table + default_minmax, valid );
+
+ OTL_CHECK( count*6 );
+ for ( ; count > 0; count-- )
+ {
+ p += 4; /* ignore tag */
+ otl_base_minmax_validate( table + OTL_NEXT_USHORT( p ), valid );
+ }
+ }
+
+
+ static void
+ otl_base_script_list_validate( OTL_Bytes table,
+ OTL_Validator valid )
+ {
+ OTL_Bytes p = table;
+ OTL_UInt count;
+
+ OTL_CHECK(2);
+
+ count = OTL_NEXT_USHORT( p );
+ OTL_CHECK(count*6);
+
+ for ( ; count > 0; count-- )
+ {
+ p += 4; /* ignore script tag */
+ otl_base_script_validate( table + OTL_NEXT_USHORT( p ) );
+ }
+ }
+
+ static void
+ otl_axis_table_validate( OTL_Bytes table,
+ OTL_Validator valid )
+ {
+ OTL_Bytes p = table;
+ OTL_UInt tags;
+
+ OTL_CHECK(4);
+
+ tags = OTL_NEXT_USHORT( p );
+ if ( tags )
+ otl_base_tag_list_validate ( table + tags );
+
+ otl_base_script_list_validate( table + OTL_NEXT_USHORT( p ) );
+ }
+
+
+ OTL_LOCALDEF( void )
+ otl_base_validate( OTL_Bytes table,
+ OTL_Validator valid )
+ {
+ OTL_Bytes p = table;
+
+ OTL_CHECK(6);
+
+ if ( OTL_NEXT_ULONG( p ) != 0x10000UL )
+ OTL_INVALID_DATA;
+
+ otl_axis_table_validate( table + OTL_NEXT_USHORT( p ) );
+ otl_axis_table_validate( table + OTL_NEXT_USHORT( p ) );
+ }
\ No newline at end of file
--- /dev/null
+++ b/libfreetype/otlbase.h
@@ -1,0 +1,14 @@
+#ifndef __OTL_BASE_H__
+#define __OTL_BASE_H__
+
+#include "otlayout.h"
+
+OTL_BEGIN_HEADER
+
+ OTL_LOCAL( void )
+ otl_base_validate( OTL_Bytes table,
+ OTL_Validator valid );
+
+OTL_END_HEADER
+
+#endif /* __OTL_BASE_H__ */
--- /dev/null
+++ b/libfreetype/otlcommn.c
@@ -1,0 +1,940 @@
+/***************************************************************************/
+/* */
+/* otlcommn.c */
+/* */
+/* OpenType layout support, common tables (body). */
+/* */
+/* Copyright 2002 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+
+#include "otlayout.h"
+
+
+ /*************************************************************************/
+ /*************************************************************************/
+ /***** *****/
+ /***** COVERAGE TABLE *****/
+ /***** *****/
+ /*************************************************************************/
+ /*************************************************************************/
+
+ OTL_LOCALDEF( void )
+ otl_coverage_validate( OTL_Bytes table,
+ OTL_Validator valid )
+ {
+ OTL_Bytes p;
+ OTL_UInt format;
+
+
+ if ( table + 4 > valid->limit )
+ OTL_INVALID_TOO_SHORT;
+
+ format = OTL_NEXT_USHORT( p );
+ switch ( format )
+ {
+ case 1:
+ {
+ OTL_UInt count = OTL_NEXT_USHORT( p );
+
+
+ if ( p + count * 2 >= valid->limit )
+ OTL_INVALID_TOO_SHORT;
+
+ /* XXX: check glyph indices */
+ }
+ break;
+
+ case 2:
+ {
+ OTL_UInt n, num_ranges = OTL_NEXT_USHORT( p );
+ OTL_UInt start, end, start_cover, total = 0, last = 0;
+
+
+ if ( p + num_ranges * 6 >= valid->limit )
+ OTL_INVALID_TOO_SHORT;
+
+ for ( n = 0; n < num_ranges; n++ )
+ {
+ start = OTL_NEXT_USHORT( p );
+ end = OTL_NEXT_USHORT( p );
+ start_cover = OTL_NEXT_USHORT( p );
+
+ if ( start > end || start_cover != total )
+ OTL_INVALID_DATA;
+
+ if ( n > 0 && start <= last )
+ OTL_INVALID_DATA;
+
+ total += end - start + 1;
+ last = end;
+ }
+ }
+ break;
+
+ default:
+ OTL_INVALID_FORMAT;
+ }
+ }
+
+
+ OTL_LOCALDEF( OTL_UInt )
+ otl_coverage_get_count( OTL_Bytes table )
+ {
+ OTL_Bytes p = table;
+ OTL_UInt format = OTL_NEXT_USHORT( p );
+ OTL_UInt count = OTL_NEXT_USHORT( p );
+ OTL_UInt result = 0;
+
+
+ switch ( format )
+ {
+ case 1:
+ return count;
+
+ case 2:
+ {
+ OTL_UInt start, end;
+
+
+ for ( ; count > 0; count-- )
+ {
+ start = OTL_NEXT_USHORT( p );
+ end = OTL_NEXT_USHORT( p );
+ p += 2; /* skip start_index */
+
+ result += end - start + 1;
+ }
+ }
+ break;
+
+ default:
+ ;
+ }
+
+ return result;
+ }
+
+
+ OTL_LOCALDEF( OTL_Int )
+ otl_coverage_get_index( OTL_Bytes table,
+ OTL_UInt glyph_index )
+ {
+ OTL_Bytes p = table;
+ OTL_UInt format = OTL_NEXT_USHORT( p );
+ OTL_UInt count = OTL_NEXT_USHORT( p );
+
+
+ switch ( format )
+ {
+ case 1:
+ {
+ OTL_UInt min = 0, max = count, mid, gindex;
+
+
+ table += 4;
+ while ( min < max )
+ {
+ mid = ( min + max ) >> 1;
+ p = table + 2 * mid;
+ gindex = OTL_PEEK_USHORT( p );
+
+ if ( glyph_index == gindex )
+ return (OTL_Int)mid;
+
+ if ( glyph_index < gindex )
+ max = mid;
+ else
+ min = mid + 1;
+ }
+ }
+ break;
+
+ case 2:
+ {
+ OTL_UInt min = 0, max = count, mid;
+ OTL_UInt start, end, delta, start_cover;
+
+
+ table += 4;
+ while ( min < max )
+ {
+ mid = ( min + max ) >> 1;
+ p = table + 6 * mid;
+ start = OTL_NEXT_USHORT( p );
+ end = OTL_NEXT_USHORT( p );
+
+ if ( glyph_index < start )
+ max = mid;
+ else if ( glyph_index > end )
+ min = mid + 1;
+ else
+ return (OTL_Int)( glyph_index + OTL_NEXT_USHORT( p ) - start );
+ }
+ }
+ break;
+
+ default:
+ ;
+ }
+
+ return -1;
+ }
+
+
+ /*************************************************************************/
+ /*************************************************************************/
+ /***** *****/
+ /***** CLASS DEFINITION TABLE *****/
+ /***** *****/
+ /*************************************************************************/
+ /*************************************************************************/
+
+ OTL_LOCALDEF( void )
+ otl_class_definition_validate( OTL_Bytes table,
+ OTL_Validator valid )
+ {
+ OTL_Bytes p = table;
+ OTL_UInt format;
+
+
+ if ( p + 4 > valid->limit )
+ OTL_INVALID_TOO_SHORT;
+
+ format = OTL_NEXT_USHORT( p );
+ switch ( format )
+ {
+ case 1:
+ {
+ OTL_UInt count, start = OTL_NEXT_USHORT( p );
+
+
+ if ( p + 2 > valid->limit )
+ OTL_INVALID_TOO_SHORT;
+
+ count = OTL_NEXT_USHORT( p );
+
+ if ( p + count * 2 > valid->limit )
+ OTL_INVALID_TOO_SHORT;
+
+ /* XXX: check glyph indices */
+ }
+ break;
+
+ case 2:
+ {
+ OTL_UInt n, num_ranges = OTL_NEXT_USHORT( p );
+ OTL_UInt start, end, value, last = 0;
+
+
+ if ( p + num_ranges * 6 > valid->limit )
+ OTL_INVALID_TOO_SHORT;
+
+ for ( n = 0; n < num_ranges; n++ )
+ {
+ start = OTL_NEXT_USHORT( p );
+ end = OTL_NEXT_USHORT( p );
+ value = OTL_NEXT_USHORT( p ); /* ignored */
+
+ if ( start > end || ( n > 0 && start <= last ) )
+ OTL_INVALID_DATA;
+
+ last = end;
+ }
+ }
+ break;
+
+ default:
+ OTL_INVALID_FORMAT;
+ }
+ }
+
+
+ OTL_LOCALDEF( OTL_UInt )
+ otl_class_definition_get_value( OTL_Bytes table,
+ OTL_UInt glyph_index )
+ {
+ OTL_Bytes p = table;
+ OTL_UInt format = OTL_NEXT_USHORT( p );
+
+
+ switch ( format )
+ {
+ case 1:
+ {
+ OTL_UInt start = OTL_NEXT_USHORT( p );
+ OTL_UInt count = OTL_NEXT_USHORT( p );
+ OTL_UInt idx = (OTL_UInt)( glyph_index - start );
+
+
+ if ( idx < count )
+ {
+ p += 2 * idx;
+ return OTL_PEEK_USHORT( p );
+ }
+ }
+ break;
+
+ case 2:
+ {
+ OTL_UInt count = OTL_NEXT_USHORT( p );
+ OTL_UInt min = 0, max = count, mid, gindex;
+
+
+ table += 4;
+ while ( min < max )
+ {
+ mid = ( min + max ) >> 1;
+ p = table + 6 * mid;
+ start = OTL_NEXT_USHORT( p );
+ end = OTL_NEXT_USHORT( p );
+
+ if ( glyph_index < start )
+ max = mid;
+ else if ( glyph_index > end )
+ min = mid + 1;
+ else
+ return OTL_PEEK_USHORT( p );
+ }
+ }
+ break;
+
+ default:
+ ;
+ }
+
+ return 0;
+ }
+
+
+ /*************************************************************************/
+ /*************************************************************************/
+ /***** *****/
+ /***** DEVICE TABLE *****/
+ /***** *****/
+ /*************************************************************************/
+ /*************************************************************************/
+
+ OTL_LOCALDEF( void )
+ otl_device_table_validate( OTL_Bytes table,
+ OTL_Validator valid )
+ {
+ OTL_Bytes p = table;
+ OTL_UInt start, end, count, format, count;
+
+
+ if ( p + 8 > valid->limit )
+ OTL_INVALID_TOO_SHORT;
+
+ start = OTL_NEXT_USHORT( p );
+ end = OTL_NEXT_USHORT( p );
+ format = OTL_NEXT_USHORT( p );
+
+ if ( format < 1 || format > 3 || end < start )
+ OTL_INVALID_DATA;
+
+ count = (OTL_UInt)( end - start + 1 );
+
+ if ( p + ( ( 1 << format ) * count ) / 8 > valid->limit )
+ OTL_INVALID_TOO_SHORT;
+ }
+
+
+ OTL_LOCALDEF( OTL_UInt )
+ otl_device_table_get_start( OTL_Bytes table )
+ {
+ OTL_Bytes p = table;
+
+
+ return OTL_PEEK_USHORT( p );
+ }
+
+
+ OTL_LOCALDEF( OTL_UInt )
+ otl_device_table_get_end( OTL_Bytes table )
+ {
+ OTL_Bytes p = table + 2;
+
+
+ return OTL_PEEK_USHORT( p );
+ }
+
+
+ OTL_LOCALDEF( OTL_Int )
+ otl_device_table_get_delta( OTL_Bytes table,
+ OTL_UInt size )
+ {
+ OTL_Bytes p = table;
+ OTL_Int result = 0;
+ OTL_UInt start, end, format, idx, value;
+
+
+ start = OTL_NEXT_USHORT( p );
+ end = OTL_NEXT_USHORT( p );
+ format = OTL_NEXT_USHORT( p );
+
+ if ( size >= start && size <= end )
+ {
+ /* we could do that with clever bit operations, but a switch is */
+ /* much simpler to understand and maintain */
+ /* */
+ switch ( format )
+ {
+ case 1:
+ idx = (OTL_UInt)( ( size - start ) * 2 );
+ p += idx / 16;
+ value = OTL_PEEK_USHORT( p );
+ shift = idx & 15;
+ result = (OTL_Short)( value << shift ) >> ( 14 - shift );
+
+ break;
+
+ case 2:
+ idx = (OTL_UInt)( ( size - start ) * 4 );
+ p += idx / 16;
+ value = OTL_PEEK_USHORT( p );
+ shift = idx & 15;
+ result = (OTL_Short)( value << shift ) >> ( 12 - shift );
+
+ break;
+
+ case 3:
+ idx = (OTL_UInt)( ( size - start ) * 8 );
+ p += idx / 16;
+ value = OTL_PEEK_USHORT( p );
+ shift = idx & 15;
+ result = (OTL_Short)( value << shift ) >> ( 8 - shift );
+
+ break;
+
+ default:
+ ;
+ }
+ }
+
+ return result;
+ }
+
+
+ /*************************************************************************/
+ /*************************************************************************/
+ /***** *****/
+ /***** LOOKUP LISTS *****/
+ /***** *****/
+ /*************************************************************************/
+ /*************************************************************************/
+
+ OTL_LOCALDEF( void )
+ otl_lookup_validate( OTL_Bytes table,
+ OTL_Validator valid )
+ {
+ OTL_Bytes p = table;
+ OTL_UInt num_tables;
+
+
+ if ( table + 6 > valid->limit )
+ OTL_INVALID_TOO_SHORT;
+
+ p += 4;
+ num_tables = OTL_NEXT_USHORT( p );
+
+ if ( p + num_tables * 2 > valid->limit )
+ OTL_INVALID_TOO_SHORT;
+
+ for ( ; num_tables > 0; num_tables-- )
+ {
+ offset = OTL_NEXT_USHORT( p );
+
+ if ( table + offset >= valid->limit )
+ OTL_INVALID_OFFSET;
+ }
+
+ /* XXX: check sub-tables? */
+ }
+
+
+ OTL_LOCALDEF( OTL_UInt )
+ otl_lookup_get_count( OTL_Bytes table )
+ {
+ OTL_Bytes p = table + 4;
+
+
+ return OTL_PEEK_USHORT( p );
+ }
+
+
+ OTL_LOCALDEF( OTL_Bytes )
+ otl_lookup_get_table( OTL_Bytes table,
+ OTL_UInt idx )
+ {
+ OTL_Bytes p, result = NULL;
+ OTL_UInt count;
+
+
+ p = table + 4;
+ count = OTL_NEXT_USHORT( p );
+ if ( idx < count )
+ {
+ p += idx * 2;
+ result = table + OTL_PEEK_USHORT( p );
+ }
+
+ return result;
+ }
+
+
+ /*************************************************************************/
+ /*************************************************************************/
+ /***** *****/
+ /***** LOOKUP LISTS *****/
+ /***** *****/
+ /*************************************************************************/
+ /*************************************************************************/
+
+ OTL_LOCALDEF( void )
+ otl_lookup_list_validate( OTL_Bytes table,
+ OTL_Validator valid )
+ {
+ OTL_Bytes p = table, q;
+ OTL_UInt num_lookups, offset;
+
+
+ if ( p + 2 > valid->limit )
+ OTL_INVALID_TOO_SHORT;
+
+ num_lookups = OTL_NEXT_USHORT( p );
+
+ if ( p + num_lookups * 2 > valid->limit )
+ OTL_INVALID_TOO_SHORT;
+
+ for ( ; num_lookups > 0; num_lookups-- )
+ {
+ offset = OTL_NEXT_USHORT( p );
+
+ otl_lookup_validate( table + offset, valid );
+ }
+ }
+
+
+ OTL_LOCALDEF( OTL_UInt )
+ otl_lookup_list_get_count( OTL_Bytes table )
+ {
+ OTL_Bytes p = table;
+
+
+ return OTL_PEEK_USHORT( p );
+ }
+
+
+ OTL_LOCALDEF( OTL_Bytes )
+ otl_lookup_list_get_lookup( OTL_Bytes table,
+ OTL_UInt idx )
+ {
+ OTL_Bytes p, result = 0;
+ OTL_UInt count;
+
+
+ p = table;
+ count = OTL_NEXT_USHORT( p );
+ if ( idx < count )
+ {
+ p += idx * 2;
+ result = table + OTL_PEEK_USHORT( p );
+ }
+
+ return result;
+ }
+
+
+ OTL_LOCALDEF( OTL_Bytes )
+ otl_lookup_list_get_table( OTL_Bytes table,
+ OTL_UInt lookup_index,
+ OTL_UInt table_index )
+ {
+ OTL_Bytes result = NULL;
+
+
+ result = otl_lookup_list_get_lookup( table, lookup_index );
+ if ( result )
+ result = otl_lookup_get_table( result, table_index );
+
+ return result;
+ }
+
+
+ OTL_LOCALDEF( void )
+ otl_lookup_list_foreach( OTL_Bytes table,
+ OTL_ForeachFunc func,
+ OTL_Pointer func_data )
+ {
+ OTL_Bytes p = table;
+ OTL_UInt count = OTL_NEXT_USHORT( p );
+
+
+ for ( ; count > 0; count-- )
+ func( table + OTL_NEXT_USHORT( p ), func_data );
+ }
+
+
+ /*************************************************************************/
+ /*************************************************************************/
+ /***** *****/
+ /***** FEATURES *****/
+ /***** *****/
+ /*************************************************************************/
+ /*************************************************************************/
+
+ OTL_LOCALDEF( void )
+ otl_feature_validate( OTL_Bytes table,
+ OTL_Validator valid )
+ {
+ OTL_Bytes p = table;
+ OTL_UInt feat_params, num_lookups;
+
+
+ if ( p + 4 > valid->limit )
+ OTL_INVALID_TOO_SHORT;
+
+ feat_params = OTL_NEXT_USHORT( p ); /* ignored */
+ num_lookups = OTL_NEXT_USHORT( p );
+
+ if ( p + num_lookups * 2 > valid->limit )
+ OTL_INVALID_TOO_SHORT;
+
+ /* XXX: check lookup indices */
+ }
+
+
+ OTL_LOCALDEF( OTL_UInt )
+ otl_feature_get_count( OTL_Bytes table )
+ {
+ OTL_Bytes p = table + 4;
+
+
+ return OTL_PEEK_USHORT( p );
+ }
+
+
+ OTL_LOCALDEF( OTL_UInt )
+ otl_feature_get_lookups( OTL_Bytes table,
+ OTL_UInt start,
+ OTL_UInt count,
+ OTL_UInt *lookups )
+ {
+ OTL_Bytes p;
+ OTL_UInt num_features, result = 0;
+
+
+ p = table + 4;
+ num_features = OTL_NEXT_USHORT( p );
+
+ p += start * 2;
+
+ for ( ; count > 0 && start < num_features; count--, start++ )
+ {
+ lookups[0] = OTL_NEXT_USHORT(p);
+ lookups++;
+ result++;
+ }
+
+ return result;
+ }
+
+
+ /*************************************************************************/
+ /*************************************************************************/
+ /***** *****/
+ /***** FEATURE LIST *****/
+ /***** *****/
+ /*************************************************************************/
+ /*************************************************************************/
+
+ OTL_LOCALDEF( void )
+ otl_feature_list_validate( OTL_Bytes table,
+ OTL_Validator valid )
+ {
+ OTL_Bytes p = table;
+ OTL_UInt num_features, offset;
+
+
+ if ( table + 2 > valid->limit )
+ OTL_INVALID_TOO_SHORT;
+
+ num_features = OTL_NEXT_USHORT( p );
+
+ if ( p + num_features * 2 > valid->limit )
+ OTL_INVALID_TOO_SHORT;
+
+ for ( ; num_features > 0; num_features-- )
+ {
+ p += 4; /* skip tag */
+ offset = OTL_NEXT_USHORT( p );
+
+ otl_feature_table_validate( table + offset, valid );
+ }
+ }
+
+
+ OTL_LOCALDEF( OTL_UInt )
+ otl_feature_list_get_count( OTL_Bytes table )
+ {
+ OTL_Bytes p = table;
+
+
+ return OTL_PEEK_USHORT( p );
+ }
+
+
+ OTL_LOCALDEF( OTL_Bytes )
+ otl_feature_list_get_feature( OTL_Bytes table,
+ OTL_UInt idx )
+ {
+ OTL_Bytes p, result = NULL;
+ OTL_UInt count;
+
+
+ p = table;
+ count = OTL_NEXT_USHORT( p );
+
+ if ( idx < count )
+ {
+ p += idx * 2;
+ result = table + OTL_PEEK_USHORT( p );
+ }
+
+ return result;
+ }
+
+
+ OTL_LOCALDEF( void )
+ otl_feature_list_foreach( OTL_Bytes table,
+ OTL_ForeachFunc func,
+ OTL_Pointer func_data )
+ {
+ OTL_Bytes p;
+ OTL_UInt count;
+
+
+ p = table;
+ count = OTL_NEXT_USHORT( p );
+
+ for ( ; count > 0; count-- )
+ func( table + OTL_NEXT_USHORT( p ), func_data );
+ }
+
+
+ /*************************************************************************/
+ /*************************************************************************/
+ /***** *****/
+ /***** LANGUAGE SYSTEM *****/
+ /***** *****/
+ /*************************************************************************/
+ /*************************************************************************/
+
+
+ OTL_LOCALDEF( void )
+ otl_lang_validate( OTL_Bytes table,
+ OTL_Validator valid )
+ {
+ OTL_Bytes p = table;
+ OTL_UInt lookup_order;
+ OTL_UInt req_feature;
+ OTL_UInt num_features;
+
+
+ if ( table + 6 >= valid->limit )
+ OTL_INVALID_TOO_SHORT;
+
+ lookup_order = OTL_NEXT_USHORT( p );
+ req_feature = OTL_NEXT_USHORT( p );
+ num_features = OTL_NEXT_USHORT( p );
+
+ /* XXX: check req_feature if not 0xFFFFU */
+
+ if ( p + 2 * num_features >= valid->limit )
+ OTL_INVALID_TOO_SHORT;
+
+ /* XXX: check features indices! */
+ }
+
+
+ OTL_LOCALDEF( OTL_UInt )
+ otl_lang_get_count( OTL_Bytes table )
+ {
+ OTL_Bytes p = table + 4;
+
+ return OTL_PEEK_USHORT( p );
+ }
+
+
+ OTL_LOCALDEF( OTL_UInt )
+ otl_lang_get_req_feature( OTL_Bytes table )
+ {
+ OTL_Bytes p = table + 2;
+
+
+ return OTL_PEEK_USHORT( p );
+ }
+
+
+ OTL_LOCALDEF( OTL_UInt )
+ otl_lang_get_features( OTL_Bytes table,
+ OTL_UInt start,
+ OTL_UInt count,
+ OTL_UInt *features )
+ {
+ OTL_Bytes p = table + 4;
+ OTL_UInt num_features = OTL_NEXT_USHORT( p );
+ OTL_UInt result = 0;
+
+
+ p += start * 2;
+
+ for ( ; count > 0 && start < num_features; start++, count-- )
+ {
+ features[0] = OTL_NEXT_USHORT( p );
+ features++;
+ result++;
+ }
+
+ return result;
+ }
+
+
+
+
+ /*************************************************************************/
+ /*************************************************************************/
+ /***** *****/
+ /***** SCRIPTS *****/
+ /***** *****/
+ /*************************************************************************/
+ /*************************************************************************/
+
+
+ OTL_LOCALDEF( void )
+ otl_script_validate( OTL_Bytes table,
+ OTL_Validator valid )
+ {
+ OTL_UInt default_lang;
+ OTL_Bytes p = table;
+
+
+ if ( table + 4 > valid->limit )
+ OTL_INVALID_TOO_SHORT;
+
+ default_lang = OTL_NEXT_USHORT( p );
+ num_langs = OTL_NEXT_USHORT( p );
+
+ if ( default_lang != 0 )
+ {
+ if ( table + default_lang >= valid->limit )
+ OTL_INVALID_OFFSET;
+ }
+
+ if ( p + num_langs * 6 >= valid->limit )
+ OTL_INVALID_OFFSET;
+
+ for ( ; num_langs > 0; num_langs-- )
+ {
+ OTL_UInt offset;
+
+
+ p += 4; /* skip tag */
+ offset = OTL_NEXT_USHORT( p );
+
+ otl_lang_validate( table + offset, valid );
+ }
+ }
+
+
+ OTL_LOCALDEF( void )
+ otl_script_list_validate( OTL_Bytes list,
+ OTL_Validator valid )
+ {
+ OTL_UInt num_scripts;
+ OTL_Bytes p = list;
+
+
+ if ( list + 2 > valid->limit )
+ OTL_INVALID_TOO_SHORT;
+
+ num_scripts = OTL_NEXT_USHORT( p );
+
+ if ( p + num_scripts * 6 > valid->limit )
+ OTL_INVALID_TOO_SHORT;
+
+ for ( ; num_scripts > 0; num_scripts-- )
+ {
+ OTL_UInt offset;
+
+
+ p += 4; /* skip tag */
+ offset = OTL_NEXT_USHORT( p );
+
+ otl_script_table_validate( list + offset, valid );
+ }
+ }
+
+
+ /*************************************************************************/
+ /*************************************************************************/
+ /***** *****/
+ /***** LOOKUP LISTS *****/
+ /***** *****/
+ /*************************************************************************/
+ /*************************************************************************/
+
+ static void
+ otl_lookup_table_validate( OTL_Bytes table,
+ OTL_UInt type_count,
+ OTL_ValidateFunc* type_funcs,
+ OTL_Validator valid )
+ {
+ OTL_Bytes p = table;
+ OTL_UInt lookup_type, lookup_flag, count;
+ OTL_ValidateFunc validate;
+
+ OTL_CHECK( 6 );
+ lookup_type = OTL_NEXT_USHORT( p );
+ lookup_flag = OTL_NEXT_USHORT( p );
+ count = OTL_NEXT_USHORT( p );
+
+ if ( lookup_type == 0 || lookup_type >= type_count )
+ OTL_INVALID_DATA;
+
+ validate = type_funcs[ lookup_type - 1 ];
+
+ OTL_CHECK( 2*count );
+ for ( ; count > 0; count-- )
+ validate( table + OTL_NEXT_USHORT( p ), valid );
+ }
+
+
+ OTL_LOCALDEF( void )
+ otl_lookup_list_validate( OTL_Bytes table,
+ OTL_UInt type_count,
+ OTL_ValidateFunc* type_funcs,
+ OTL_Validator valid )
+ {
+ OTL_Bytes p = table;
+ OTL_UInt count;
+
+ OTL_CHECK( 2 );
+ count = OTL_NEXT_USHORT( p );
+
+ OTL_CHECK( 2*count );
+ for ( ; count > 0; count-- )
+ otl_lookup_table_validate( table + OTL_NEXT_USHORT( p ),
+ type_count, type_funcs, valid );
+ }
+
+/* END */
--- /dev/null
+++ b/libfreetype/otlcommn.h
@@ -1,0 +1,277 @@
+/***************************************************************************/
+/* */
+/* otlcommn.h */
+/* */
+/* OpenType layout support, common tables (specification). */
+/* */
+/* Copyright 2002 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+
+#ifndef __OTLCOMMN_H__
+#define __OTLCOMMN_H__
+
+#include "otlayout.h"
+
+OTL_BEGIN_HEADER
+
+
+ /*************************************************************************/
+ /*************************************************************************/
+ /***** *****/
+ /***** COVERAGE TABLE *****/
+ /***** *****/
+ /*************************************************************************/
+ /*************************************************************************/
+
+ /* validate coverage table */
+ OTL_LOCALDEF( void )
+ otl_coverage_validate( OTL_Bytes base,
+ OTL_Validator valid );
+
+ /* return number of covered glyphs */
+ OTL_LOCALDEF( OTL_UInt )
+ otl_coverage_get_count( OTL_Bytes base );
+
+ /* Return the coverage index corresponding to a glyph glyph index. */
+ /* Return -1 if the glyph isn't covered. */
+ OTL_LOCALDEF( OTL_Int )
+ otl_coverage_get_index( OTL_Bytes base,
+ OTL_UInt glyph_index );
+
+
+ /*************************************************************************/
+ /*************************************************************************/
+ /***** *****/
+ /***** CLASS DEFINITION TABLE *****/
+ /***** *****/
+ /*************************************************************************/
+ /*************************************************************************/
+
+ /* validate class definition table */
+ OTL_LOCALDEF( void )
+ otl_class_definition_validate( OTL_Bytes table,
+ OTL_Validator valid );
+
+ /* return class value for a given glyph index */
+ OTL_LOCALDEF( OTL_UInt )
+ otl_class_definition_get_value( OTL_Bytes table,
+ OTL_UInt glyph_index );
+
+
+ /*************************************************************************/
+ /*************************************************************************/
+ /***** *****/
+ /***** DEVICE TABLE *****/
+ /***** *****/
+ /*************************************************************************/
+ /*************************************************************************/
+
+ /* validate a device table */
+ OTL_LOCALDEF( void )
+ otl_device_table_validate( OTL_Bytes table,
+ OTL_Validator valid );
+
+ /* return a device table's first size */
+ OTL_LOCALDEF( OTL_UInt )
+ otl_device_table_get_start( OTL_Bytes table );
+
+ /* return a device table's last size */
+ OTL_LOCALDEF( OTL_UInt )
+ otl_device_table_get_end( OTL_Bytes table );
+
+ /* return pixel adjustment for a given size */
+ OTL_LOCALDEF( OTL_Int )
+ otl_device_table_get_delta( OTL_Bytes table,
+ OTL_UInt size );
+
+
+ /*************************************************************************/
+ /*************************************************************************/
+ /***** *****/
+ /***** LOOKUPS *****/
+ /***** *****/
+ /*************************************************************************/
+ /*************************************************************************/
+
+ /* validate lookup table */
+ OTL_LOCALDEF( void )
+ otl_lookup_validate( OTL_Bytes table,
+ OTL_Validator valid );
+
+ /* return number of sub-tables in a lookup */
+ OTL_LOCALDEF( OTL_UInt )
+ otl_lookup_get_count( OTL_Bytes table );
+
+
+ /* return lookup sub-table */
+ OTL_LOCALDEF( OTL_Bytes )
+ otl_lookup_get_table( OTL_Bytes table,
+ OTL_UInt idx );
+
+
+ /*************************************************************************/
+ /*************************************************************************/
+ /***** *****/
+ /***** LOOKUP LISTS *****/
+ /***** *****/
+ /*************************************************************************/
+ /*************************************************************************/
+
+ /* validate lookup list */
+ OTL_LOCALDEF( void )
+ otl_lookup_list_validate( OTL_Bytes table,
+ OTL_Validator valid );
+
+ /* return number of lookups in list */
+ OTL_LOCALDEF( OTL_UInt )
+ otl_lookup_list_get_count( OTL_Bytes table );
+
+ /* return a given lookup from a list */
+ OTL_LOCALDEF( OTL_Bytes )
+ otl_lookup_list_get_lookup( OTL_Bytes table,
+ OTL_UInt idx );
+
+ /* return lookup sub-table from a list */
+ OTL_LOCALDEF( OTL_Bytes )
+ otl_lookup_list_get_table( OTL_Bytes table,
+ OTL_UInt lookup_index,
+ OTL_UInt table_index );
+
+ /* iterate over lookup list */
+ OTL_LOCALDEF( void )
+ otl_lookup_list_foreach( OTL_Bytes table,
+ OTL_ForeachFunc func,
+ OTL_Pointer func_data );
+
+
+ /*************************************************************************/
+ /*************************************************************************/
+ /***** *****/
+ /***** FEATURES *****/
+ /***** *****/
+ /*************************************************************************/
+ /*************************************************************************/
+
+ /* validate feature table */
+ OTL_LOCALDEF( void )
+ otl_feature_validate( OTL_Bytes table,
+ OTL_Validator valid );
+
+ /* return feature's lookup count */
+ OTL_LOCALDEF( OTL_UInt )
+ otl_feature_get_count( OTL_Bytes table );
+
+ /* get several lookups indices from a feature. returns the number of */
+ /* lookups grabbed */
+ OTL_LOCALDEF( OTL_UInt )
+ otl_feature_get_lookups( OTL_Bytes table,
+ OTL_UInt start,
+ OTL_UInt count,
+ OTL_UInt *lookups );
+
+
+ /*************************************************************************/
+ /*************************************************************************/
+ /***** *****/
+ /***** FEATURE LIST *****/
+ /***** *****/
+ /*************************************************************************/
+ /*************************************************************************/
+
+ /* validate a feature list */
+ OTL_LOCALDEF( void )
+ otl_feature_list_validate( OTL_Bytes table,
+ OTL_Validator valid );
+
+ /* return number of features in list */
+ OTL_LOCALDEF( OTL_UInt )
+ otl_feature_list_get_count( OTL_Bytes table );
+
+
+ /* return a given feature from a list */
+ OTL_LOCALDEF( OTL_Bytes )
+ otl_feature_list_get_feature( OTL_Bytes table,
+ OTL_UInt idx );
+
+ /* iterate over all features in a list */
+ OTL_LOCALDEF( void )
+ otl_feature_list_foreach( OTL_Bytes table,
+ OTL_ForeachFunc func,
+ OTL_Pointer func_data );
+
+
+ /*************************************************************************/
+ /*************************************************************************/
+ /***** *****/
+ /***** LANGUAGE SYSTEM *****/
+ /***** *****/
+ /*************************************************************************/
+ /*************************************************************************/
+
+ OTL_LOCAL( void )
+ otl_lang_validate( OTL_Bytes table,
+ OTL_Validator valid );
+
+
+ OTL_LOCAL( OTL_UInt )
+ otl_lang_get_req_feature( OTL_Bytes table );
+
+
+ OTL_LOCAL( OTL_UInt )
+ otl_lang_get_count( OTL_Bytes table );
+
+
+ OTL_LOCAL( OTL_UInt )
+ otl_lang_get_features( OTL_Bytes table,
+ OTL_UInt start,
+ OTL_UInt count,
+ OTL_UInt *features );
+
+
+ /*************************************************************************/
+ /*************************************************************************/
+ /***** *****/
+ /***** SCRIPTS *****/
+ /***** *****/
+ /*************************************************************************/
+ /*************************************************************************/
+
+ OTL_LOCAL( void )
+ otl_script_list_validate( OTL_Bytes list,
+ OTL_Validator valid );
+
+ OTL_LOCAL( OTL_Bytes )
+ otl_script_list_get_script( OTL_Bytes table );
+
+
+ /*************************************************************************/
+ /*************************************************************************/
+ /***** *****/
+ /***** LOOKUP LISTS *****/
+ /***** *****/
+ /*************************************************************************/
+ /*************************************************************************/
+
+ OTL_LOCAL( void )
+ otl_lookup_list_validate( OTL_Bytes list,
+ OTL_UInt type_count,
+ OTL_ValidateFunc* type_funcs,
+ OTL_Validator valid );
+
+ /* */
+
+OTL_END_HEADER
+
+#endif /* __OTLCOMMN_H__ */
+
+
+/* END */
--- /dev/null
+++ b/libfreetype/otlconf.h
@@ -1,0 +1,78 @@
+#ifndef __OT_LAYOUT_CONFIG_H__
+#define __OT_LAYOUT_CONFIG_H__
+
+ /************************************************************************/
+ /************************************************************************/
+ /***** *****/
+ /***** CONFIGURATION MACROS *****/
+ /***** *****/
+ /************************************************************************/
+ /************************************************************************/
+
+#ifdef __cplusplus
+# define OTL_BEGIN_HEADER extern "C" {
+#else
+# define OTL_BEGIN_HEADER /* nothing */
+#endif
+
+#ifdef __cplusplus
+# define OTL_END_HEADER }
+#else
+# define OTL_END_HEADER /* nothing */
+#endif
+
+#ifndef OTL_API
+# ifdef __cplusplus
+# define OTL_API( x ) extern "C"
+# else
+# define OTL_API( x ) extern x
+# endif
+#endif
+
+#ifndef OTL_APIDEF
+# define OTL_APIDEF( x ) x
+#endif
+
+#ifndef OTL_LOCAL
+# define OTL_LOCAL( x ) extern x
+#endif
+
+#ifndef OTL_LOCALDEF
+# define OTL_LOCALDEF( x ) x
+#endif
+
+#define OTL_BEGIN_STMNT do {
+#define OTL_END_STMNT } while (0)
+#define OTL_DUMMY_STMNT OTL_BEGIN_STMNT OTL_END_STMNT
+
+#define OTL_UNUSED( x ) (x)=(x)
+#define OTL_UNUSED_CONST(x) (void)(x)
+
+
+#include <limits.h>
+#if UINT_MAX == 0xFFFFU
+# define OTL_SIZEOF_INT 2
+#elif UINT_MAX == 0xFFFFFFFFU
+# define OTL_SIZEOF_INT 4
+#elif UINT_MAX > 0xFFFFFFFFU && UINT_MAX == 0xFFFFFFFFFFFFFFFFU
+# define OTL_SIZEOF_INT 8
+#else
+# error "unsupported number of bytes in 'int' type!"
+#endif
+
+#if ULONG_MAX == 0xFFFFFFFFU
+# define OTL_SIZEOF_LONG 4
+#elif ULONG_MAX > 0xFFFFFFFFU && ULONG_MAX == 0xFFFFFFFFFFFFFFFFU
+# define OTL_SIZEOF_LONG 8
+#else
+# error "unsupported number of bytes in 'long' type!"
+#endif
+
+#include <setjmp.h>
+#define OTL_jmp_buf jmp_buf
+#define otl_setjmp setjmp
+#define otl_longjmp longjmp
+
+/* */
+
+#endif /* __OT_LAYOUT_CONFIG_H__ */
--- /dev/null
+++ b/libfreetype/otlgdef.c
@@ -1,0 +1,175 @@
+#include "otlgdef.h"
+#include "otlcommn.h"
+
+ /************************************************************************/
+ /************************************************************************/
+ /***** *****/
+ /***** ATTACHMENTS LIST *****/
+ /***** *****/
+ /************************************************************************/
+ /************************************************************************/
+
+ static void
+ otl_attach_point_validate( OTL_Bytes table,
+ OTL_Validator valid )
+ {
+ OTL_Bytes p = table;
+ OTL_UInt count;
+
+ if ( p + 2 > valid->limit )
+ OTL_INVALID_TOO_SHORT;
+
+ count = OTL_NEXT_USHORT( p );
+ if ( table + count*2 > valid->limit )
+ OTL_INVALID_TOO_SHORT;
+ }
+
+
+ static void
+ otl_attach_list_validate( OTL_Bytes table,
+ OTL_Validator valid )
+ {
+ OTL_Bytes p = table;
+ OTL_Bytes coverage;
+ OTL_UInt count;
+
+ if ( p + 4 > valid->limit )
+ OTL_INVALID_TOO_SHORT;
+
+ coverage = table + OTL_NEXT_USHORT( p );
+ count = OTL_NEXT_USHORT( p );
+
+ otl_coverage_validate( coverage, valid );
+ if ( count != otl_coverage_get_count( coverage ) )
+ OTL_INVALID_DATA;
+
+ if ( p + count*2 > valid->limit )
+ OTL_INVALID_TOO_SHORT;
+
+ for ( ; count > 0; count-- )
+ otl_attach_point_validate( table + OTL_NEXT_USHORT( p ) );
+ }
+
+
+ /************************************************************************/
+ /************************************************************************/
+ /***** *****/
+ /***** LIGATURE CARETS *****/
+ /***** *****/
+ /************************************************************************/
+ /************************************************************************/
+
+ static void
+ otl_caret_value_validate( OTL_Bytes table,
+ OTL_Validator valid )
+ {
+ OTL_Bytes p = table;
+
+ if ( p + 4 > valid->limit )
+ OTL_INVALID_TOO_SHORT;
+
+ format = OTL_NEXT_USHORT( p );
+ switch ( format )
+ {
+ case 1:
+ case 2:
+ break;
+
+ case 3:
+ {
+ OTL_Bytes device;
+
+ p += 2;
+ if ( p + 2 > valid->limit )
+ OTL_INVALID_TOO_SHORT;
+
+ otl_device_table_validate( table + OTL_PEEK_USHORT( p ) );
+ }
+ break;
+
+ default:
+ OTL_INVALID_DATA;
+ }
+ }
+
+
+ static void
+ otl_ligature_glyph_validate( OTL_Bytes table,
+ OTL_Validator valid )
+ {
+ OTL_Bytes p = table;
+ OTL_UInt count;
+
+ if ( p + 2 > valid->limit )
+ OTL_INVALID_TOO_SHORT;
+
+ count = OTL_NEXT_USHORT( p );
+
+ if ( p + count*2 > valid->limit )
+ OTL_INVALID_TOO_SHORT;
+
+ for ( ; count > 0; count-- )
+ otl_caret_value_validate( table + OTL_NEXT_USHORT( p ) );
+ }
+
+
+ static void
+ otl_ligature_caret_list_validate( OTL_Bytes table,
+ OTL_Validator valid )
+ {
+ OTL_Bytes p = table;
+ OTL_Bytes coverage;
+ OTL_UInt count;
+
+ if ( p + 4 > valid->limit )
+ OTL_INVALID_TOO_SHORT;
+
+ coverage = table + OTL_NEXT_USHORT( p );
+ count = OTL_NEXT_USHORT( p );
+
+ otl_coverage_validate( coverage, valid );
+ if ( count != otl_coverage_get_count( coverage ) )
+ OTL_INVALID_DATA;
+
+ if ( p + count*2 > valid->limit )
+ OTL_INVALID_TOO_SHORT;
+
+ for ( ; count > 0; count-- )
+ otl_ligature_glyph_validate( table + OTL_NEXT_USHORT( p ) );
+ }
+
+
+ /************************************************************************/
+ /************************************************************************/
+ /***** *****/
+ /***** GDEF TABLE *****/
+ /***** *****/
+ /************************************************************************/
+ /************************************************************************/
+
+ OTL_APIDEF( void )
+ otl_gdef_validate( OTL_Bytes table,
+ OTL_Validator valid )
+ {
+ OTL_Bytes p = table;
+
+ if ( p + 12 > valid->limit )
+ OTL_INVALID_TOO_SHORT;
+
+ /* check format */
+ if ( OTL_NEXT_ULONG( p ) != 0x00010000UL )
+ OTL_INVALID_FORMAT;
+
+ /* validate class definition table */
+ otl_class_definition_validate( table + OTL_NEXT_USHORT( p ) );
+
+ /* validate attachment point list */
+ otl_attach_list_validate( table + OTL_NEXT_USHORT( p ) );
+
+ /* validate ligature caret list */
+ otl_ligature_caret_list_validate( table + OTL_NEXT_USHORT( p ) );
+
+ /* validate mark attach class */
+ otl_class_definition_validate( table + OTL_NEXT_USHORT( p ) );
+ }
+
--- /dev/null
+++ b/libfreetype/otlgdef.h
@@ -1,0 +1,14 @@
+#ifndef __OTL_GDEF_H__
+#define __OTL_GDEF_H__
+
+#include "otltable.h"
+
+OTL_BEGIN_HEADER
+
+ OTL_API( void )
+ otl_gdef_validate( OTL_Bytes table,
+ OTL_Valid valid );
+
+OTL_END_HEADER
+
+#endif /* __OTL_GDEF_H__ */
--- /dev/null
+++ b/libfreetype/otlgpos.c
@@ -1,0 +1,980 @@
+#include "otlgpos.h"
+#include "otlcommn.h"
+
+ /* forward declaration */
+ static OTL_ValidateFunc otl_gpos_validate_funcs[];
+
+
+ /************************************************************************/
+ /************************************************************************/
+ /***** *****/
+ /***** VALUE RECORDS *****/
+ /***** *****/
+ /************************************************************************/
+ /************************************************************************/
+
+ static OTL_UInt
+ otl_value_length( OTL_UInt format )
+ {
+ FT_UInt count;
+
+ count = (( format & 0xAA ) >> 1) + ( format & 0x55 );
+ count = (( count & 0xCC ) >> 2) + ( count & 0x33 );
+ count = (( count & 0xF0 ) >> 4) + ( count & 0x0F );
+
+ return count;
+ }
+
+
+ static void
+ otl_value_validate( OTL_Bytes table,
+ OTL_Bytes pos_table,
+ OTL_UInt format,
+ OTL_Validator valid )
+ {
+ OTL_Bytes p = table;
+ OTL_UInt count, device;
+
+ if ( format >= 0x100U )
+ OTL_INVALID_DATA;
+
+ for ( count = 4; count > 0; count-- )
+ {
+ if ( format & 1 )
+ {
+ OTL_CHECK( 2 );
+ p += 2;
+ }
+
+ format >>= 1;
+ }
+
+ for ( count = 4; count > 0; count-- )
+ {
+ if ( format & 1 )
+ {
+ OTL_CHECK( 2 );
+ device = OTL_NEXT_USHORT( p );
+ if ( device )
+ otl_device_table_validate( pos_table + device, valid );
+ }
+ format >>= 1;
+ }
+ }
+
+
+ /************************************************************************/
+ /************************************************************************/
+ /***** *****/
+ /***** ANCHORS *****/
+ /***** *****/
+ /************************************************************************/
+ /************************************************************************/
+
+ static void
+ otl_anchor_validate( OTL_Bytes table,
+ OTL_Validator valid )
+ {
+ OTL_Bytes p = table;
+ OTL_UInt format;
+
+ OTL_CHECK( 6 );
+ format = OTL_NEXT_USHORT( p );
+ p += 4;
+
+ switch ( format )
+ {
+ case 1:
+ break;
+
+ case 2:
+ OTL_CHECK( 2 ); /* anchor point */
+ break;
+
+ case 3:
+ {
+ OTL_UInt x_device, y_device;
+
+ OTL_CHECK( 4 );
+ x_device = OTL_NEXT_USHORT( p );
+ y_device = OTL_NEXT_USHORT( p );
+
+ if ( x_device )
+ otl_device_table_validate( table + x_device, valid );
+
+ if ( y_device )
+ otl_device_table_validate( table + y_device, valid );
+ }
+ break;
+
+ default:
+ OTL_INVALID_DATA;
+ }
+ }
+
+
+ /************************************************************************/
+ /************************************************************************/
+ /***** *****/
+ /***** MARK ARRAY *****/
+ /***** *****/
+ /************************************************************************/
+ /************************************************************************/
+
+ static void
+ otl_mark_array_validate( OTL_Bytes table,
+ OTL_Validator valid )
+ {
+ OTL_Bytes p = table;
+ OTL_UInt count;
+
+ OTL_CHECK( 2 );
+
+ count = OTL_NEXT_USHORT( p );
+ OTL_CHECK( count * 4 );
+ for ( ; count > 0; count-- )
+ {
+ p += 2; /* ignore class index */
+ otl_anchor_validate( table + OTL_NEXT_USHORT( p ), valid );
+ }
+ }
+
+
+ /************************************************************************/
+ /************************************************************************/
+ /***** *****/
+ /***** GPOS LOOKUP TYPE 1 *****/
+ /***** *****/
+ /************************************************************************/
+ /************************************************************************/
+
+ static void
+ otl_gpos_lookup1_validate( OTL_Bytes table,
+ OTL_Validator valid )
+ {
+ OTL_Bytes p = table;
+ OTL_UInt format;
+
+ OTL_CHECK( 2 );
+ format = OTL_NEXT_USHORT( p );
+ switch ( format )
+ {
+ case 1:
+ {
+ FT_UInt coverage, value_format;
+
+ OTL_CHECK( 4 );
+ coverage = OTL_NEXT_USHORT( p );
+ value_format = OTL_NEXT_USHORT( p );
+
+ otl_coverage_validate( table + coverage, valid );
+ otl_value_validate( p, table, value_format, valid );
+ }
+ break;
+
+ case 2:
+ {
+ FT_UInt coverage, value_format, count, len;
+
+ OTL_CHECK( 6 );
+ coverage = OTL_NEXT_USHORT( p );
+ value_format = OTL_NEXT_USHORT( p );
+ count = OTL_NEXT_USHORT( p );
+ len = otl_value_length( value_format );
+
+ otl_coverage_validate( table + coverage, valid );
+
+ OTL_CHECK( count * len );
+ for ( ; count > 0; count-- )
+ {
+ otl_value_validate( p, table, value_format, valid );
+ p += len;
+ }
+ }
+ break;
+
+ default:
+ OTL_INVALID_DATA;
+ }
+ }
+
+
+ /************************************************************************/
+ /************************************************************************/
+ /***** *****/
+ /***** GPOS LOOKUP TYPE 2 *****/
+ /***** *****/
+ /************************************************************************/
+ /************************************************************************/
+
+ static otl_gpos_pairset_validate( OTL_Bytes table,
+ OTL_Bytes pos_table,
+ OTL_UInt format1,
+ OTL_UInt format2,
+ OTL_Validator valid )
+ {
+ OTL_Bytes p = table;
+ OTL_UInt len1, len2, count;
+
+ OTL_CHECK( 2 );
+ count = OTL_NEXT_USHORT( p );
+ len1 = otl_value_length( format1 );
+ len2 = otl_value_length( format2 );
+
+ OTL_CHECK( count * (len1+len2+2) );
+ for ( ; count > 0; count-- )
+ {
+ p += 2; /* ignore glyph id */
+ otl_value_validate( p, pos_table, format1, valid );
+ p += len1;
+
+ otl_value_validate( p, pos_table, format2, valid );
+ p += len2;
+ }
+ }
+
+ static void
+ otl_gpos_lookup2_validate( OTL_Bytes table,
+ OTL_Validator valid )
+ {
+ OTL_Bytes p = table;
+ OTL_UInt format;
+
+ OTL_CHECK( 2 );
+ format = OTL_NEXT_USHORT( p );
+ switch (format)
+ {
+ case 1:
+ {
+ OTL_UInt coverage, value1, value2, count;
+
+ OTL_CHECK( 8 );
+ coverage = OTL_NEXT_USHORT( p );
+ value1 = OTL_NEXT_USHORT( p );
+ value2 = OTL_NEXT_USHORT( p );
+ count = OTL_NEXT_USHORT( p );
+
+ otl_coverage_validate( table + coverage, valid );
+
+ OTL_CHECK( count*2 );
+ for ( ; count > 0; count-- )
+ {
+ otl_gpos_pairset_validate( table + OTL_NEXT_USHORT( p ),
+ table, value1, value2, valid );
+ }
+ }
+ break;
+
+ case 2:
+ {
+ OTL_UInt coverage, value1, value2, class1, class2, count1, count2;
+ OTL_UInt len1, len2;
+
+ OTL_CHECK( 14 );
+ coverage = OTL_NEXT_USHORT( p );
+ value1 = OTL_NEXT_USHORT( p );
+ value2 = OTL_NEXT_USHORT( p );
+ class1 = OTL_NEXT_USHORT( p );
+ class2 = OTL_NEXT_USHORT( p );
+ count1 = OTL_NEXT_USHORT( p );
+ count2 = OTL_NEXT_USHORT( p );
+
+ len1 = otl_value_length( value1 );
+ len2 = otl_value_length( value2 );
+
+ otl_coverage_validate( table + coverage, valid );
+
+ OTL_CHECK( count1*count2*(len1+len2) );
+ for ( ; count1 > 0; count1-- )
+ {
+ for ( ; count2 > 0; count2-- )
+ {
+ otl_value_validate( p, table, value1, valid );
+ p += len1;
+
+ otl_value_validate( p, table, value2, valid );
+ p += len2;
+ }
+ }
+ }
+ break;
+
+ default:
+ OTL_INVALID_DATA;
+ }
+ }
+
+
+ /************************************************************************/
+ /************************************************************************/
+ /***** *****/
+ /***** GPOS LOOKUP TYPE 3 *****/
+ /***** *****/
+ /************************************************************************/
+ /************************************************************************/
+
+ static void
+ otl_gpos_lookup3_validate( OTL_Bytes table,
+ OTL_Valid valid )
+ {
+ OTL_Bytes p = table;
+ OTL_UInt format;
+
+ OTL_CHECK( 2 );
+ format = OTL_NEXT_USHORT( p );
+ switch (format)
+ {
+ case 1:
+ {
+ OTL_UInt coverage, count, anchor1, anchor2;
+
+ OTL_CHECK( 4 );
+ coverage = OTL_NEXT_USHORT( p );
+ count = OTL_NEXT_USHORT( p );
+
+ otl_coverage_validate( table + coverage, valid );
+
+ OTL_CHECK( count*4 );
+ for ( ; count > 0; count-- )
+ {
+ anchor1 = OTL_NEXT_USHORT( p );
+ anchor2 = OTL_NEXT_USHORT( p );
+
+ if ( anchor1 )
+ otl_anchor_validate( table + anchor1, valid );
+
+ if ( anchor2 )
+ otl_anchor_validate( table + anchor2, valid );
+ }
+ }
+ break;
+
+ default:
+ OTL_INVALID_DATA;
+ }
+ }
+
+
+ /************************************************************************/
+ /************************************************************************/
+ /***** *****/
+ /***** GPOS LOOKUP TYPE 4 *****/
+ /***** *****/
+ /************************************************************************/
+ /************************************************************************/
+
+ static void
+ otl_base_array_validate( OTL_Bytes table,
+ OTL_UInt class_count,
+ OTL_Validator valid )
+ {
+ OTL_Bytes p = table;
+ OTL_UInt count, count2;
+
+ OTL_CHECK( 2 );
+ count = OTL_NEXT_USHORT( p );
+
+ OTL_CHECK( count*class_count*2 );
+ for ( ; count > 0; count-- )
+ for ( count2 = class_count; count2 > 0; count2-- )
+ otl_anchor_validate( table + OTL_NEXT_USHORT( p ) );
+ }
+
+
+ static void
+ otl_gpos_lookup4_validate( OTL_Bytes table,
+ OTL_Valid valid )
+ {
+ OTL_Bytes p = table;
+ OTL_UInt format;
+
+ OTL_CHECK( 2 );
+ format = OTL_NEXT_USHORT( p );
+ switch (format)
+ {
+ case 1:
+ {
+ OTL_UInt mark_coverage, base_coverage, class_count;
+ OTL_UInt mark_array, base_array;
+
+ OTL_CHECK( 10 );
+ mark_coverage = OTL_NEXT_USHORT( p );
+ base_coverage = OTL_NEXT_USHORT( p );
+ class_count = OTL_NEXT_USHORT( p );
+ mark_array = OTL_NEXT_USHORT( p );
+ base_array = OTL_NEXT_USHORT( p );
+
+ otl_coverage_validate( table + mark_coverage, valid );
+ otl_coverage_validate( table + base_coverage, valid );
+
+ otl_mark_array_validate( table + mark_array, valid );
+ otl_base_array_validate( table, class_count, valid );
+ }
+ break;
+
+ default:
+ OTL_INVALID_DATA;
+ }
+ }
+
+ /************************************************************************/
+ /************************************************************************/
+ /***** *****/
+ /***** GPOS LOOKUP TYPE 5 *****/
+ /***** *****/
+ /************************************************************************/
+ /************************************************************************/
+
+ static void
+ otl_liga_attach_validate( OTL_Bytes table,
+ OTL_UInt class_count,
+ OTL_Validator valid )
+ {
+ OTL_Bytes p = table;
+ OTL_UInt count, count2;
+
+ OTL_CHECK( 2 );
+ count = OTL_NEXT_USHORT( p );
+
+ OTL_CHECK( count*class_count*2 );
+ for ( ; count > 0; count-- )
+ for ( count2 = class_count; class_count > 0; class_count-- )
+ otl_anchor_validate( table + OTL_NEXT_USHORT( p ), valid );
+ }
+
+
+ static void
+ otl_liga_array_validate( OTL_Bytes table,
+ OTL_UInt class_count,
+ OTL_Validator valid )
+ {
+ OTL_Bytes p = table;
+ OTL_UInt count, count2;
+
+ OTL_CHECK( 2 );
+ count = OTL_NEXT_USHORT( p );
+
+ OTL_CHECK( count*2 );
+ for ( ; count > 0; count-- )
+ otl_liga_attach_validate( table + OTL_NEXT_USHORT( p ), valid );
+ }
+
+
+ static void
+ otl_gpos_lookup5_validate( OTL_Bytes table,
+ OTL_Valid valid )
+ {
+ OTL_Bytes p = table;
+ OTL_UInt format;
+
+ OTL_CHECK( 2 );
+ format = OTL_NEXT_USHORT( p );
+ switch (format)
+ {
+ case 1:
+ {
+ OTL_UInt mark_coverage, lig_coverage, class_count;
+ OTL_UInt mar_array, lig_array;
+
+ OTL_CHECK( 10 );
+ mark_coverage = OTL_NEXT_USHORT( p );
+ liga_coverage = OTL_NEXT_USHORT( p );
+ class_count = OTL_NEXT_USHORT( p );
+ mark_array = OTL_NEXT_USHORT( p );
+ liga_array = OTL_NEXT_USHORT( p );
+
+ otl_coverage_validate( table + mark_coverage, valid );
+ otl_coverage_validate( table + liga_coverage, valid );
+
+ otl_mark_array_validate( table + mark_array, valid );
+ otl_liga_array_validate( table + liga_array, class_count, valid );
+ }
+ break;
+
+ default:
+ OTL_INVALID_DATA;
+ }
+ }
+
+ /************************************************************************/
+ /************************************************************************/
+ /***** *****/
+ /***** GPOS LOOKUP TYPE 6 *****/
+ /***** *****/
+ /************************************************************************/
+ /************************************************************************/
+
+
+ static void
+ otl_mark2_array_validate( OTL_Bytes table,
+ OTL_UInt class_count,
+ OTL_Validator valid )
+ {
+ OTL_Bytes p = table;
+ OTL_UInt count, count2;
+
+ OTL_CHECK( 2 );
+ count = OTL_NEXT_USHORT( p );
+
+ OTL_CHECK( count*class_count*2 );
+ for ( ; count > 0; count-- )
+ for ( count2 = class_count; class_count > 0; class_count-- )
+ otl_anchor_validate( table + OTL_NEXT_USHORT( p ), valid );
+ }
+
+
+ static void
+ otl_gpos_lookup6_validate( OTL_Bytes table,
+ OTL_Valid valid )
+ {
+ OTL_Bytes p = table;
+ OTL_UInt format;
+
+ OTL_CHECK( 2 );
+ format = OTL_NEXT_USHORT( p );
+ switch (format)
+ {
+ case 1:
+ {
+ OTL_UInt coverage1, coverage2, class_count, array1, array2;
+
+ OTL_CHECK( 10 );
+ coverage1 = OTL_NEXT_USHORT( p );
+ coverage2 = OTL_NEXT_USHORT( p );
+ class_count = OTL_NEXT_USHORT( p );
+ array1 = OTL_NEXT_USHORT( p );
+ array2 = OTL_NEXT_USHORT( p );
+
+ otl_coverage_validate( table + coverage1, valid );
+ otl_coverage_validate( table + coverage2, valid );
+
+ otl_mark_array_validate( table + array1, valid );
+ otl_mark2_array_validate( table + array2, valid );
+ }
+ break;
+
+ default:
+ OTL_INVALID_DATA;
+ }
+ }
+
+
+ /************************************************************************/
+ /************************************************************************/
+ /***** *****/
+ /***** GPOS LOOKUP TYPE 7 *****/
+ /***** *****/
+ /************************************************************************/
+ /************************************************************************/
+
+ static void
+ otl_pos_rule_validate( OTL_Bytes table,
+ OTL_Validator valid )
+ {
+ OTL_Bytes p = table;
+ OTL_UInt glyph_count, pos_count;
+
+ OTL_CHECK( 4 );
+ glyph_count = OTL_NEXT_USHORT( p );
+ pos_count = OTL_NEXT_USHORT( p );
+
+ if ( glyph_count == 0 )
+ OTL_INVALID_DATA;
+
+ OTL_CHECK( (glyph_count-1)*2 + pos_count*4 );
+
+ /* XXX: check glyph indices and pos lookups */
+ }
+
+
+ static void
+ otl_pos_rule_set_validate( OTL_Bytes table,
+ OTL_Validator valid )
+ {
+ OTL_Bytes p = table;
+ OTL_UInt count;
+
+ OTL_CHECK( 2 );
+ count = OTL_NEXT_USHORT( p );
+
+ OTL_CHECK( count*2 );
+ for ( ; count > 0; count-- )
+ otl_pos_rule_validate( table + OTL_NEXT_USHORT(p), valid );
+ }
+
+
+
+ static void
+ otl_pos_class_rule_validate( OTL_Bytes table,
+ OTL_Validator valid )
+ {
+ OTL_Bytes p = table;
+ OTL_UInt glyph_count, pos_count;
+
+ OTL_CHECK( 4 );
+ glyph_count = OTL_NEXT_USHORT( p );
+ pos_count = OTL_NEXT_USHORT( p );
+
+ if ( glyph_count == 0 )
+ OTL_INVALID_DATA;
+
+ OTL_CHECK( (glyph_count-1)*2 + pos_count*4 );
+
+ /* XXX: check glyph indices and pos lookups */
+ }
+
+
+ static void
+ otl_pos_class_set_validate( OTL_Bytes table,
+ OTL_Validator valid )
+ {
+ OTL_Bytes p = table;
+ OTL_UInt count;
+
+ OTL_CHECK( 2 );
+ count = OTL_NEXT_USHORT( p );
+
+ OTL_CHECK( count*2 );
+ for ( ; count > 0; count-- )
+ otl_pos_rule_validate( table + OTL_NEXT_USHORT(p), valid );
+ }
+
+
+ static void
+ otl_gpos_lookup7_validate( OTL_Bytes table,
+ OTL_Validator valid )
+ {
+ OTL_Bytes p = table;
+ OTL_UInt format;
+
+ OTL_CHECK( 2 );
+ format = OTL_NEXT_USHORT( p );
+ switch (format)
+ {
+ case 1:
+ {
+ OTL_UInt coverage, count;
+
+ OTL_CHECK( 4 );
+ coverage = OTL_NEXT_USHORT( p );
+ count = OTL_NEXT_USHORT( p );
+
+ otl_coverage_validate( table + coverage, valid );
+
+ OTL_CHECK( count*2 );
+ for ( ; count > 0; count-- )
+ otl_pos_rule_set_validate( table + OTL_NEXT_USHORT( p ), valid );
+ }
+ break;
+
+ case 2:
+ {
+ OTL_UInt coverage, class_def, count;
+
+ OTL_CHECK( 6 );
+ coverage = OTL_NEXT_USHORT( p );
+ class_def = OTL_NEXT_USHORT( p );
+ count = OTL_NEXT_USHORT( p );
+
+ otl_coverage_validate ( table + coverage, valid );
+ otl_class_definition_validate( table + class_def, valid );
+
+ OTL_CHECK( count*2 );
+ for ( ; count > 0; count-- )
+ otl_
+ }
+ break;
+
+ case 3:
+ {
+ OTL_UInt glyph_count, pos_count;
+
+ OTL_CHECK( 4 );
+ glyph_count = OTL_NEXT_USHORT( p );
+ pos_count = OTL_NEXT_USHORT( p );
+
+ OTL_CHECK( glyph_count*2 + pos_count*4 );
+ for ( ; glyph_count > 0; glyph_count )
+ otl_coverage_validate( table + OTL_NEXT_USHORT( p ), valid );
+
+ /* XXX: check pos lookups */
+ }
+ break;
+
+ default:
+ OTL_INVALID_DATA;
+ }
+ }
+
+
+ /************************************************************************/
+ /************************************************************************/
+ /***** *****/
+ /***** GPOS LOOKUP TYPE 8 *****/
+ /***** *****/
+ /************************************************************************/
+ /************************************************************************/
+
+ static void
+ otl_chain_pos_rule_validate( OTL_Bytes table,
+ OTL_Validator valid )
+ {
+ OTL_Bytes p = table;
+ OTL_UInt back_count, input_count, ahead_count, pos_count;
+
+ OTL_CHECK( 2 );
+ back_count = OTL_NEXT_USHORT( p );
+
+ OTL_CHECK( back_count*2 + 2 );
+ p += back_count*2;
+
+ input_count = OTL_NEXT_USHORT( p );
+ if ( input_count == 0 )
+ OTL_INVALID_DATA;
+
+ OTL_CHECK( input_count*2 );
+ p += (input_count-1)*2;
+
+ ahead_count = OTL_NEXT_USHORT( p );
+ OTL_CHECK( ahead_count*2 + 2 );
+ p += ahead_count*2;
+
+ pos_count = OTL_NEXT_USHORT( p );
+ OTL_CHECK( pos_count*4 );
+ }
+
+
+ static void
+ otl_chain_pos_rule_set_validate( OTL_Bytes table,
+ OTL_Validator valid )
+ {
+ OTL_Bytes p = table;
+ OTL_UInt count;
+
+ OTL_CHECK( 2 );
+ count = OTL_NEXT_USHORT( p );
+
+ OTL_CHECK( 2*count );
+ for ( ; count > 0; count-- )
+ otl_chain_pos_rule_validate( table + OTL_NEXT_USHORT( p ), valid );
+ }
+
+
+
+ static void
+ otl_chain_pos_class_rule_validate( OTL_Bytes table,
+ OTL_Validator valid )
+ {
+ OTL_Bytes p = table;
+ OTL_UInt back_count, input_count, ahead_count, pos_count;
+
+ OTL_CHECK( 2 );
+ back_count = OTL_NEXT_USHORT( p );
+
+ OTL_CHECK( back_count*2 + 2 );
+ p += back_count*2;
+
+ input_count = OTL_NEXT_USHORT( p );
+ if ( input_count == 0 )
+ OTL_INVALID_DATA;
+
+ OTL_CHECK( input_count*2 );
+ p += (input_count-1)*2;
+
+ ahead_count = OTL_NEXT_USHORT( p );
+ OTL_CHECK( ahead_count*2 + 2 );
+ p += ahead_count*2;
+
+ pos_count = OTL_NEXT_USHORT( p );
+ OTL_CHECK( pos_count*4 );
+ }
+
+
+ static void
+ otl_chain_pos_class_set_validate( OTL_Bytes table,
+ OTL_Validator valid )
+ {
+ OTL_Bytes p = table;
+ OTL_UInt count;
+
+ OTL_CHECK( 2 );
+ count = OTL_NEXT_USHORT( p );
+
+ OTL_CHECK( 2*count );
+ for ( ; count > 0; count-- )
+ otl_chain_pos_class_rule_validate( table + OTL_NEXT_USHORT( p ), valid );
+ }
+
+
+ static void
+ otl_gpos_lookup8_validate( OTL_Bytes table,
+ OTL_Validator valid )
+ {
+ OTL_Bytes p = table;
+ OTL_UInt format;
+
+ OTL_CHECK( 2 );
+ format = OTL_NEXT_USHORT( p );
+ switch (format)
+ {
+ case 1:
+ {
+ OTL_UInt coverage, count;
+
+ OTL_CHECK( 4 );
+ coverage = OTL_NEXT_USHORT( p );
+ count = OTL_NEXT_USHORT( p );
+
+ otl_coverage_validate( table + coverage, valid );
+
+ OTL_CHECK( count*2 );
+ for ( ; count > 0; count-- )
+ otl_chain_pos_rule_set_validate( table + OTL_NEXT_USHORT( p ),
+ valid );
+ }
+ break;
+
+ case 2:
+ {
+ OTL_UInt coverage, back_class, input_class, ahead_class, count;
+
+ OTL_CHECK( 10 );
+ coverage = OTL_NEXT_USHORT( p );
+ back_class = OTL_NEXT_USHORT( p );
+ input_class = OTL_NEXT_USHORT( p );
+ ahead_class = OTL_NEXT_USHORT( p );
+ count = OTL_NEXT_USHORT( p );
+
+ otl_coverage_validate( table + coverage, valid );
+
+ otl_class_definition_validate( table + back_class, valid );
+ otl_class_definition_validate( table + input_class, valid );
+ otl_class_definition_validate( table + ahead_class, valid );
+
+ OTL_CHECK( count*2 );
+ for ( ; count > 0; count-- )
+ otl_chain_pos_class_set_validate( table + OTL_NEXT_USHORT( p ),
+ valid );
+ }
+ break;
+
+ case 3:
+ {
+ OTL_UInt back_count, input_count, ahead_count, pos_count, count;
+
+ OTL_CHECK( 2 );
+ back_count = OTL_NEXT_USHORT( p );
+
+ OTL_CHECK( 2*back_count+2 );
+ for ( count = back_count; count > 0; count-- )
+ otl_coverage_validate( table + OTL_NEXT_USHORT( p ), valid );
+
+ input_count = OTL_NEXT_USHORT( p );
+
+ OTL_CHECK( 2*input_count+2 );
+ for ( count = input_count; count > 0; count-- )
+ otl_coverage_validate( table + OTL_NEXT_USHORT( p ), valid );
+
+ ahead_count = OTL_NEXT_USHORT( p );
+
+ OTL_CHECK( 2*ahead_count+2 );
+ for ( count = ahead_count; count > 0; count-- )
+ otl_coverage_validate( table + OTL_NEXT_USHORT( p ), valid );
+
+ pos_count = OTL_NEXT_USHORT( p );
+ OTL_CHECK( pos_count*4 );
+ }
+ break;
+
+ default:
+ OTL_INVALID_DATA;
+ }
+ }
+
+ /************************************************************************/
+ /************************************************************************/
+ /***** *****/
+ /***** GPOS LOOKUP TYPE 9 *****/
+ /***** *****/
+ /************************************************************************/
+ /************************************************************************/
+
+ static void
+ otl_gpos_lookup9_validate( OTL_Bytes table,
+ OTL_Valid valid )
+ {
+ OTL_Bytes p = table;
+ OTL_UInt format;
+
+ OTL_CHECK( 2 );
+ format = OTL_NEXT_USHORT( p );
+ switch (format)
+ {
+ case 1:
+ {
+ OTL_UInt lookup_type, lookup_offset;
+ OTL_ValidateFunc validate;
+
+ OTL_CHECK( 6 );
+ lookup_type = OTL_NEXT_USHORT( p );
+ lookup_offset = OTL_NEXT_ULONG( p );
+
+ if ( lookup_type == 0 || lookup_type >= 9 )
+ OTL_INVALID_DATA;
+
+ validate = otl_gpos_validate_funcs[ lookup_type-1 ];
+ validate( table + lookup_offset, valid );
+ }
+ break;
+
+ default:
+ OTL_INVALID_DATA;
+ }
+ }
+
+ static OTL_ValidateFunc otl_gpos_validate_funcs[ 9 ] =
+ {
+ otl_gpos_lookup1_validate,
+ otl_gpos_lookup2_validate,
+ otl_gpos_lookup3_validate,
+ otl_gpos_lookup4_validate,
+ otl_gpos_lookup5_validate,
+ otl_gpos_lookup6_validate,
+ otl_gpos_lookup7_validate,
+ otl_gpos_lookup8_validate,
+ otl_gpos_lookup9_validate,
+ };
+
+
+ /************************************************************************/
+ /************************************************************************/
+ /***** *****/
+ /***** GPOS TABLE *****/
+ /***** *****/
+ /************************************************************************/
+ /************************************************************************/
+
+
+ OTL_LOCALDEF( void )
+ otl_gpos_validate( OTL_Bytes table,
+ OTL_Validator valid )
+ {
+ OTL_Bytes p = table;
+ OTL_UInt scripts, features, lookups;
+
+ OTL_CHECK( 10 );
+
+ if ( OTL_NEXT_USHORT( p ) != 0x10000UL )
+ OTL_INVALID_DATA;
+
+ scripts = OTL_NEXT_USHORT( p );
+ features = OTL_NEXT_USHORT( p );
+ lookups = OTL_NEXT_USHORT( p );
+
+ otl_script_list_validate ( table + scripts, valid );
+ otl_feature_list_validate( table + features, valid );
+
+ otl_lookup_list_validate( table + lookups, 9, otl_gpos_validate_funcs,
+ valid );
+ }
+
\ No newline at end of file
--- /dev/null
+++ b/libfreetype/otlgpos.h
@@ -1,0 +1,14 @@
+#ifndef __OTL_GPOS_H__
+#define __OTL_GPOS_H__
+
+#include "otlayout.h"
+
+OTL_BEGIN_HEADER
+
+ OTL_LOCAL( void )
+ otl_gpos_validate( OTL_Bytes table,
+ OTL_Validator valid );
+
+OTL_END_HEADER
+
+#endif /* __OTL_GPOS_H__ */
--- /dev/null
+++ b/libfreetype/otlgsub.c
@@ -1,0 +1,867 @@
+#include "otlgsub.h"
+#include "otlcommn.h"
+
+ /************************************************************************/
+ /************************************************************************/
+ /***** *****/
+ /***** GSUB LOOKUP TYPE 1 *****/
+ /***** *****/
+ /************************************************************************/
+ /************************************************************************/
+
+ /*
+ * 1: Single Substitution - Table format(s)
+ *
+ * This table is used to substiture individual glyph indices
+ * with another one. There are only two sub-formats:
+ *
+ * Name Offset Size Description
+ * ------------------------------------------
+ * format 0 2 sub-table format (1)
+ * offset 2 2 offset to coverage table
+ * delta 4 2 16-bit delta to apply on all
+ * covered glyph indices
+ *
+ * Name Offset Size Description
+ * ------------------------------------------
+ * format 0 2 sub-table format (2)
+ * offset 2 2 offset to coverage table
+ * count 4 2 coverage table count
+ * substs[] 6 2*count substituted glyph indices,
+ *
+ */
+
+ static void
+ otl_gsub_lookup1_validate( OTL_Bytes table,
+ OTL_Validator valid )
+ {
+ OTL_Bytes p = table;
+ OTL_UInt format;
+
+ OTL_CHECK( 2 );
+ format = OTL_NEXT_USHORT( p );
+ switch ( format )
+ {
+ case 1:
+ {
+ OTL_UInt coverage;
+
+ OTL_CHECK( 4 );
+ coverage = OTL_NEXT_USHORT( p );
+
+ otl_coverage_validate( table + coverage, valid );
+ }
+ break;
+
+ case 2:
+ {
+ OTL_UInt coverage, count;
+
+ OTL_CHECK( 4 );
+ coverage = OTL_NEXT_USHORT( p );
+ count = OTL_NEXT_USHORT( p );
+
+ otl_coverage_validate( table + coverage, valid );
+
+ OTL_CHECK( 2*count );
+
+ /* NB: we don't check that there are at most 'count' */
+ /* elements in the coverage table. This is delayed */
+ /* to the lookup function... */
+ }
+ break;
+
+ default:
+ OTL_INVALID_DATA;
+ }
+ }
+
+
+ static OTL_Bool
+ otl_gsub_lookup1_apply( OTL_Bytes table,
+ OTL_Parser parser )
+ {
+ OTL_Bytes p = table;
+ OTL_Bytes coverage;
+ OTL_UInt format, gindex, property;
+ OTL_Int index;
+ OTL_Bool subst = 0;
+
+ if ( parser->context_len != 0xFFFF && parser->context_len < 1 )
+ goto Exit;
+
+ gindex = otl_parser_get_gindex( parser );
+
+ if ( !otl_parser_check_property( parser, gindex, &property ) )
+ goto Exit;
+
+ format = OTL_NEXT_USHORT(p);
+ coverage = table + OTL_NEXT_USHORT(p);
+ index = otl_coverage_lookup( coverage, gindex );
+
+ if ( index >= 0 )
+ {
+ switch ( format )
+ {
+ case 1:
+ {
+ OTL_Int delta = OTL_NEXT_SHORT(p);
+
+ gindex = ( gindex + delta ) & 0xFFFF;
+ otl_parser_replace_1( parser, gindex );
+ subst = 1;
+ }
+ break;
+
+ case 2:
+ {
+ OTL_UInt count = OTL_NEXT_USHORT(p);
+
+ if ( (OTL_UInt) index < count )
+ {
+ p += index*2;
+ otl_parser_replace_1( parser, OTL_PEEK_USHORT(p) );
+ subst = 1;
+ }
+ }
+ break;
+
+ default:
+ ;
+ }
+ }
+ Exit:
+ return subst;
+ }
+
+ /************************************************************************/
+ /************************************************************************/
+ /***** *****/
+ /***** GSUB LOOKUP TYPE 2 *****/
+ /***** *****/
+ /************************************************************************/
+ /************************************************************************/
+
+ /*
+ * 2: Multiple Substitution - Table format(s)
+ *
+ * Replaces a single glyph with one or more glyphs.
+ *
+ * Name Offset Size Description
+ * -----------------------------------------------------------
+ * format 0 2 sub-table format (1)
+ * offset 2 2 offset to coverage table
+ * count 4 2 coverage table count
+ * sequencess[] 6 2*count offsets to sequence items
+ *
+ * each sequence item has the following format:
+ *
+ * Name Offset Size Description
+ * -----------------------------------------------------------
+ * count 0 2 number of replacement glyphs
+ * gindices[] 2 2*count string of glyph indices
+ */
+
+ static void
+ otl_seq_validate( OTL_Bytes table,
+ OTL_Validator valid )
+ {
+ OTL_Bytes p = table;
+ OTL_UInt count;
+
+ OTL_CHECK( 2 );
+ count = OTL_NEXT_USHORT( p );
+
+ /* XXX: according to the spec, 'count' should be > 0 */
+ /* we can deal with these cases pretty well however */
+
+ OTL_CHECK( 2*count );
+ /* check glyph indices */
+ }
+
+
+ static void
+ otl_gsub_lookup2_validate( OTL_Bytes table,
+ OTL_Validator valid )
+ {
+ OTL_Bytes p = table;
+ OTL_UInt format, coverage;
+
+ OTL_CHECK( 2 );
+ format = OTL_NEXT_USHORT( p );
+ switch ( format )
+ {
+ case 1:
+ {
+ OTL_UInt coverage, seq_count;
+
+ OTL_CHECK( 4 );
+ coverage = OTL_NEXT_USHORT( p );
+ seq_count = OTL_NEXT_USHORT( p );
+
+ otl_coverage_validate( table + coverage, valid );
+
+ OTL_CHECK( seq_count*2 );
+ for ( ; seq_count > 0; seq_count-- )
+ otl_seq_validate( table + OTL_NEXT_USHORT( p ), valid );
+ }
+ break;
+
+ default:
+ OTL_INVALID_DATA;
+ }
+ }
+
+
+ static OTL_Bool
+ otl_gsub_lookup2_apply( OTL_Bytes table,
+ OTL_Parser parser )
+ {
+ OTL_Bytes p = table;
+ OTL_Bytes coverage, sequence;
+ OTL_UInt format, gindex, index, property;
+ OTL_Int index;
+ OTL_Bool subst = 0;
+
+ if ( context_len != 0xFFFF && context_len < 1 )
+ goto Exit;
+
+ gindex = otl_parser_get_gindex( parser );
+
+ if ( !otl_parser_check_property( parser, gindex, &property ) )
+ goto Exit;
+
+ p += 2; /* skip format */
+ coverage = table + OTL_NEXT_USHORT(p);
+ seq_count = OTL_NEXT_USHORT(p);
+ index = otl_coverage_lookup( coverage, gindex );
+
+ if ( (OTL_UInt) index >= seq_count )
+ goto Exit;
+
+ p += index*2;
+ sequence = table + OTL_PEEK_USHORT(p);
+ p = sequence;
+ count = OTL_NEXT_USHORT(p);
+
+ otl_parser_replace_n( parser, count, p );
+ subst = 1;
+
+ Exit:
+ return subst;
+ }
+
+ /************************************************************************/
+ /************************************************************************/
+ /***** *****/
+ /***** GSUB LOOKUP TYPE 3 *****/
+ /***** *****/
+ /************************************************************************/
+ /************************************************************************/
+
+ /*
+ * 3: Alternate Substitution - Table format(s)
+ *
+ * Replaces a single glyph by another one taken liberally
+ * in a list of alternatives
+ *
+ * Name Offset Size Description
+ * -----------------------------------------------------------
+ * format 0 2 sub-table format (1)
+ * offset 2 2 offset to coverage table
+ * count 4 2 coverage table count
+ * alternates[] 6 2*count offsets to alternate items
+ *
+ * each alternate item has the following format:
+ *
+ * Name Offset Size Description
+ * -----------------------------------------------------------
+ * count 0 2 number of replacement glyphs
+ * gindices[] 2 2*count string of glyph indices, each one
+ * is a valid alternative
+ */
+
+ static void
+ otl_alternate_set_validate( OTL_Bytes table,
+ OTL_Validator valid )
+ {
+ OTL_Bytes p = table;
+ OTL_UInt count;
+
+ OTL_CHECK( 2 );
+ count = OTL_NEXT_USHORT( p );
+
+ OTL_CHECK( 2*count );
+ /* XXX: check glyph indices */
+ }
+
+
+ static void
+ otl_gsub_lookup3_validate( OTL_Bytes table,
+ OTL_Validator valid )
+ {
+ OTL_Bytes p = table;
+ OTL_UInt format, coverage;
+
+ OTL_CHECK( 2 );
+ format = OTL_NEXT_USHORT( p );
+ switch ( format )
+ {
+ case 1:
+ {
+ OTL_UInt coverage, count;
+
+ OTL_CHECK( 4 );
+ coverage = OTL_NEXT_USHORT( p );
+ count = OTL_NEXT_USHORT( p );
+
+ otl_coverage_validate( table + coverage, valid );
+
+ OTL_CHECK( 2*count );
+ for ( ; count > 0; count-- )
+ otl_alternate_set_validate( table + OTL_NEXT_USHORT( p ), valid );
+ }
+ break;
+
+ default:
+ OTL_INVALID_DATA;
+ }
+ }
+
+
+ static OTL_Bool
+ otl_gsub_lookup3_apply( OTL_Bytes table,
+ OTL_Parser parser )
+ {
+ OTL_Bytes p = table;
+ OTL_Bytes coverage, alternates;
+ OTL_UInt format, gindex, index, property;
+ OTL_Int index;
+ OTL_Bool subst = 0;
+
+ OTL_GSUB_Alternate alternate = parser->alternate;
+
+ if ( context_len != 0xFFFF && context_len < 1 )
+ goto Exit;
+
+ if ( alternate == NULL )
+ goto Exit;
+
+ gindex = otl_parser_get_gindex( parser );
+
+ if ( !otl_parser_check_property( parser, gindex, &property ) )
+ goto Exit;
+
+ p += 2; /* skip format */
+ coverage = table + OTL_NEXT_USHORT(p);
+ seq_count = OTL_NEXT_USHORT(p);
+ index = otl_coverage_lookup( coverage, gindex );
+
+ if ( (OTL_UInt) index >= seq_count )
+ goto Exit;
+
+ p += index*2;
+ alternates = table + OTL_PEEK_USHORT(p);
+ p = alternates;
+ count = OTL_NEXT_USHORT(p);
+
+ gindex = alternate->handler_func(
+ gindex, count, p, alternate->handler_data );
+
+ otl_parser_replace_1( parser, gindex );
+ subst = 1;
+
+ Exit:
+ return subst;
+ }
+
+ /************************************************************************/
+ /************************************************************************/
+ /***** *****/
+ /***** GSUB LOOKUP TYPE 4 *****/
+ /***** *****/
+ /************************************************************************/
+ /************************************************************************/
+
+ static void
+ otl_ligature_validate( OTL_Bytes table,
+ OTL_Validator valid )
+ {
+ OTL_UInt glyph_id, count;
+
+ OTL_CHECK( 4 );
+ glyph_id = OTL_NEXT_USHORT( p );
+ count = OTL_NEXT_USHORT( p );
+
+ if ( count == 0 )
+ OTL_INVALID_DATA;
+
+ OTL_CHECK( 2*(count-1) );
+ /* XXX: check glyph indices */
+ }
+
+
+ static void
+ otl_ligature_set_validate( OTL_Bytes table,
+ OTL_Validator valid )
+ {
+ OTL_Bytes p = table;
+ OTL_UInt count;
+
+ OTL_CHECK( 2 );
+ count = OTL_NEXT_USHORT( p );
+
+ OTL_CHECK( 2*count );
+ for ( ; count > 0; count-- )
+ otl_ligature_validate( table + OTL_NEXT_USHORT( p ), valid );
+ }
+
+
+ static void
+ otl_gsub_lookup4_validate( OTL_Bytes table,
+ OTL_Validator valid )
+ {
+ OTL_Bytes p = table;
+ OTL_UInt format, coverage;
+
+ OTL_CHECK( 2 );
+ format = OTL_NEXT_USHORT( p );
+ switch ( format )
+ {
+ case 1:
+ {
+ OTL_UInt coverage, count;
+
+ OTL_CHECK( 4 );
+ coverage = OTL_NEXT_USHORT( p );
+ count = OTL_NEXT_USHORT( p );
+
+ otl_coverage_validate( table + coverage, valid );
+
+ OTL_CHECK( 2*count );
+ for ( ; count > 0; count-- )
+ otl_ligature_set_validate( table + OTL_NEXT_USHORT( p ), valid );
+ }
+ break;
+
+ default:
+ OTL_INVALID_DATA;
+ }
+ }
+
+
+ /************************************************************************/
+ /************************************************************************/
+ /***** *****/
+ /***** GSUB LOOKUP TYPE 5 *****/
+ /***** *****/
+ /************************************************************************/
+ /************************************************************************/
+
+
+ static void
+ otl_sub_rule_validate( OTL_Bytes table,
+ OTL_Validator valid )
+ {
+ OTL_Bytes p = table;
+ OTL_UInt glyph_count, subst_count;
+
+ OTL_CHECK( 4 );
+ glyph_count = OTL_NEXT_USHORT( p );
+ subst_count = OTL_NEXT_USHORT( p );
+
+ if ( glyph_count == 0 )
+ OTL_INVALID_DATA;
+
+ OTL_CHECK( (glyph_count-1)*2 + substcount*4 );
+
+ /* XXX: check glyph indices and subst lookups */
+ }
+
+
+ static void
+ otl_sub_rule_set_validate( OTL_Bytes table,
+ OTL_Validator valid )
+ {
+ OTL_Bytes p = table;
+ OTL_UInt count;
+
+ OTL_CHECK( 2 );
+ count = OTL_NEXT_USHORT( p );
+
+ OTL_CHECK( 2*count );
+ for ( ; count > 0; count-- )
+ otl_sub_rule_validate( table + OTL_NEXT_USHORT( p ), valid );
+ }
+
+
+ static void
+ otl_sub_class_rule_validate( OTL_Bytes table,
+ OTL_Validator valid )
+ {
+ OTL_UInt glyph_count, subst_count;
+
+ OTL_CHECK( 4 );
+ glyph_count = OTL_NEXT_USHORT( p );
+ subst_count = OTL_NEXT_USHORT( p );
+
+ if ( glyph_count == 0 )
+ OTL_INVALID_DATA;
+
+ OTL_CHECK( (glyph_count-1)*2 + substcount*4 );
+
+ /* XXX: check glyph indices and subst lookups */
+ }
+
+
+ static void
+ otl_sub_class_rule_set_validate( OTL_Bytes table,
+ OTL_Validator valid )
+ {
+ OTL_Bytes p = table;
+ OTL_UInt count;
+
+ OTL_CHECK( 2 );
+ count = OTL_NEXT_USHORT( p );
+
+ OTL_CHECK( 2*count );
+ for ( ; count > 0; count-- )
+ otl_sub_class_rule_validate( table + OTL_NEXT_USHORT( p ), valid );
+ }
+
+
+ static void
+ otl_gsub_lookup5_validate( OTL_Bytes table,
+ OTL_Validator valid )
+ {
+ OTL_Bytes p = table;
+ OTL_UInt format, coverage;
+
+ OTL_CHECK( 2 );
+ format = OTL_NEXT_USHORT( p );
+ switch ( format )
+ {
+ case 1:
+ {
+ OTL_UInt coverage, count;
+
+ OTL_CHECK( 4 );
+ coverage = OTL_NEXT_USHORT( p );
+ count = OTL_NEXT_USHORT( p );
+
+ otl_coverage_validate( table + coverage, valid );
+
+ OTL_CHECK( 2*count );
+ for ( ; count > 0; count-- )
+ otl_sub_rule_set_validate( table + coverage, valid );
+ }
+ break;
+
+ case 2:
+ {
+ OTL_UInt coverage, class_def, count;
+
+ OTL_CHECK( 6 );
+ coverage = OTL_NEXT_USHORT( p );
+ class_def = OTL_NEXT_USHORT( p );
+ count = OTL_NEXT_USHORT( p );
+
+ otl_coverage_validate ( table + coverage, valid );
+ otl_class_definition_validate( table + class_def, valid );
+
+ OTL_CHECK( 2*count );
+ for ( ; count > 0; count-- )
+ otl_sub_class_rule_set_validate( table + coveragen valid );
+ }
+ break;
+
+ case 3:
+ {
+ OTL_UInt glyph_count, subst_count, count;
+
+ OTL_CHECK( 4 );
+ glyph_count = OTL_NEXT_USHORT( p );
+ subst_count = OTL_NEXT_USHORT( p );
+
+ OTL_CHECK( 2*glyph_count + 4*subst_count );
+ for ( count = glyph_count; count > 0; count-- )
+ otl_coverage_validate( table + OTL_NEXT_USHORT( p ), valid );
+ }
+ break;
+
+ default:
+ OTL_INVALID_DATA;
+ }
+ }
+
+
+ /************************************************************************/
+ /************************************************************************/
+ /***** *****/
+ /***** GSUB LOOKUP TYPE 6 *****/
+ /***** *****/
+ /************************************************************************/
+ /************************************************************************/
+
+
+ static void
+ otl_chain_sub_rule_validate( OTL_Bytes table,
+ OTL_Validator valid )
+ {
+ OTL_Bytes p = table;
+ OTL_UInt back_count, input_count, ahead_count, subst_count, count;
+
+ OTL_CHECK( 2 );
+ back_count = OTL_NEXT_USHORT( p );
+
+ OTL_CHECK( 2*back_count+2 );
+ p += 2*back_count;
+
+ input_count = OTL_NEXT_USHORT( p );
+ if ( input_count == 0 )
+ OTL_INVALID_DATA;
+
+ OTL_CHECK( 2*input_count );
+ p += 2*(input_count-1);
+
+ ahead_count = OTL_NEXT_USHORT( p );
+ OTL_CHECK( 2*ahead_count + 2 );
+ p += 2*ahead_count;
+
+ count = OTL_NEXT_USHORT( p );
+ OTL_CHECK( 4*count );
+
+ /* XXX: check glyph indices and subst lookups */
+ }
+
+
+ static void
+ otl_chain_sub_rule_set_validate( OTL_Bytes table,
+ OTL_Validator valid )
+ {
+ OTL_Bytes p = table;
+ OTL_UInt count;
+
+ OTL_CHECK( 2 );
+ count = OTL_NEXT_USHORT( p );
+
+ OTL_CHECK( 2*count );
+ for ( ; count > 0; count-- )
+ otl_chain_sub_rule_validate( table + OTL_NEXT_USHORT( p ), valid );
+ }
+
+
+ static void
+ otl_chain_sub_class_rule_validate( OTL_Bytes table,
+ OTL_Validator valid )
+ {
+ OTL_Bytes p = table;
+ OTL_UInt back_count, input_count, ahead_count, subst_count, count;
+
+ OTL_CHECK( 2 );
+ back_count = OTL_NEXT_USHORT( p );
+
+ OTL_CHECK( 2*back_count+2 );
+ p += 2*back_count;
+
+ input_count = OTL_NEXT_USHORT( p );
+ if ( input_count == 0 )
+ OTL_INVALID_DATA;
+
+ OTL_CHECK( 2*input_count );
+ p += 2*(input_count-1);
+
+ ahead_count = OTL_NEXT_USHORT( p );
+ OTL_CHECK( 2*ahead_count + 2 );
+ p += 2*ahead_count;
+
+ count = OTL_NEXT_USHORT( p );
+ OTL_CHECK( 4*count );
+
+ /* XXX: check class indices and subst lookups */
+ }
+
+
+
+ static void
+ otl_chain_sub_class_set_validate( OTL_Bytes table,
+ OTL_Validator valid )
+ {
+ OTL_Bytes p = table;
+ OTL_UInt count;
+
+ OTL_CHECK( 2 );
+ count = OTL_NEXT_USHORT( p );
+
+ OTL_CHECK( 2*count );
+ for ( ; count > 0; count-- )
+ otl_chain_sub_rule_validate( table + OTL_NEXT_USHORT( p ), valid );
+ }
+
+
+ static void
+ otl_gsub_lookup6_validate( OTL_Bytes table,
+ OTL_Validator valid )
+ {
+ OTL_Bytes p = table;
+ OTL_UInt format, coverage;
+
+ OTL_CHECK( 2 );
+ format = OTL_NEXT_USHORT( p );
+ switch ( format )
+ {
+ case 1:
+ {
+ OTL_UInt coverage, count;
+
+ OTL_CHECK( 4 );
+ coverage = OTL_NEXT_USHORT( p );
+ count = OTL_NEXT_USHORT( p );
+
+ otl_coverage_validate( table + coverage, valid );
+
+ OTL_CHECK( 2*count );
+ for ( ; count > 0; count-- )
+ otl_chain_sub_rule_set_validate( table + coverage, valid );
+ }
+ break;
+
+ case 2:
+ {
+ OTL_UInt coverage, back_class, input_class, ahead_class, count;
+
+ OTL_CHECK( 10 );
+ coverage = OTL_NEXT_USHORT( p );
+ back_class = OTL_NEXT_USHORT( p );
+ input_class = OTL_NEXT_USHORT( p );
+ ahead_class = OTL_NEXT_USHORT( p );
+ count = OTL_NEXT_USHORT( p );
+
+ otl_coverage_validate( table + coverage, valid );
+
+ otl_class_definition_validate( table + back_class, valid );
+ otl_class_definition_validate( table + input_class, valid );
+ otl_class_definition_validate( table + ahead_class, valid );
+
+ OTL_CHECK( 2*count );
+ for ( ; count > 0; count-- )
+ otl_chain_sub_class_set( table + OTL_NEXT_USHORT( p ), valid );
+ }
+ break;
+
+ case 3:
+ {
+ OTL_UInt back_count, input_count, ahead_count, subst_count, count;
+
+ OTL_CHECK( 2 );
+ back_count = OTL_NEXT_USHORT( p );
+
+ OTL_CHECK( 2*back_count+2 );
+ for ( count = back_count; count > 0; count-- )
+ otl_coverage_validate( table + OTL_NEXT_USHORT( p ), valid );
+
+ input_count = OTL_NEXT_USHORT( p );
+
+ OTL_CHECK( 2*input_count+2 );
+ for ( count = input_count; count > 0; count-- )
+ otl_coverage_validate( table + OTL_NEXT_USHORT( p ), valid );
+
+ ahead_count = OTL_NEXT_USHORT( p );
+
+ OTL_CHECK( 2*ahead_count+2 );
+ for ( count = ahead_count; count > 0; count-- )
+ otl_coverage_validate( table + OTL_NEXT_USHORT( p ), valid );
+
+ subst_count = OTL_NEXT_USHORT( p );
+ OTL_CHECK( subst_count*4 );
+ }
+ break;
+
+ default:
+ OTL_INVALID_DATA;
+ }
+ }
+
+ /************************************************************************/
+ /************************************************************************/
+ /***** *****/
+ /***** GSUB LOOKUP TYPE 6 *****/
+ /***** *****/
+ /************************************************************************/
+ /************************************************************************/
+
+ static void
+ otl_gsub_lookup7_validate( OTL_Bytes table,
+ OTL_Validator valid )
+ {
+ OTL_Bytes p = table;
+ OTL_UInt format, coverage;
+
+ OTL_CHECK( 2 );
+ format = OTL_NEXT_USHORT( p );
+ switch ( format )
+ {
+ case 1:
+ {
+ OTL_UInt lookup_type, lookup_offset;
+ OTL_ValidateFunc validate;
+
+ OTL_CHECK( 6 );
+ lookup_type = OTL_NEXT_USHORT( p );
+ lookup_offset = OTL_NEXT_ULONG( p );
+
+ if ( lookup_type == 0 || lookup_type >= 7 )
+ OTL_INVALID_DATA;
+
+ validate = otl_gsub_validate_funcs[ lookup_type-1 ];
+ validate( table + lookup_offset, valid );
+ }
+ break;
+
+ default:
+ OTL_INVALID_DATA;
+ }
+ }
+
+
+ static const OTL_ValidateFunc otl_gsub_validate_funcs[ 7 ] =
+ {
+ otl_gsub_lookup1_validate,
+ otl_gsub_lookup2_validate,
+ otl_gsub_lookup3_validate,
+ otl_gsub_lookup4_validate,
+ otl_gsub_lookup5_validate,
+ otl_gsub_lookup6_validate
+ };
+
+ /************************************************************************/
+ /************************************************************************/
+ /***** *****/
+ /***** GSUB TABLE *****/
+ /***** *****/
+ /************************************************************************/
+ /************************************************************************/
+
+
+ OTL_LOCALDEF( void )
+ otl_gsub_validate( OTL_Bytes table,
+ OTL_Validator valid )
+ {
+ OTL_Bytes p = table;
+ OTL_UInt scripts, features, lookups;
+
+ OTL_CHECK( 10 );
+
+ if ( OTL_NEXT_USHORT( p ) != 0x10000UL )
+ OTL_INVALID_DATA;
+
+ scripts = OTL_NEXT_USHORT( p );
+ features = OTL_NEXT_USHORT( p );
+ lookups = OTL_NEXT_USHORT( p );
+
+ otl_script_list_validate ( table + scripts, valid );
+ otl_feature_list_validate( table + features, valid );
+
+ otl_lookup_list_validate( table + lookups, 7, otl_gsub_validate_funcs,
+ valid );
+ }
--- /dev/null
+++ b/libfreetype/otlgsub.h
@@ -1,0 +1,26 @@
+#ifndef __OTL_GSUB_H__
+#define __OTL_GSUB_H__
+
+#include "otlayout.h"
+
+OTL_BEGIN_HEADER
+
+ typedef OTL_UInt (*OTL_GSUB_AlternateFunc)( OTL_UInt gindex,
+ OTL_UInt count,
+ OTL_Bytes alternates,
+ OTL_Pointer data );
+
+ typedef struct OTL_GSUB_AlternateRec_
+ {
+ OTL_GSUB_AlternateFunc handler_func;
+ OTL_Pointer handler_data;
+
+ } OTL_GSUB_AlternateRec, *OTL_GSUB_Alternate;
+
+ OTL_LOCAL( void )
+ otl_gsub_validate( OTL_Bytes table,
+ OTL_Validator valid );
+
+OTL_END_HEADER
+
+#endif /* __OTL_GSUB_H__ */
--- /dev/null
+++ b/libfreetype/otljstf.c
@@ -1,0 +1,189 @@
+#include "otljstf.h"
+#include "otlcommn.h"
+#include "otlgpos.h"
+
+ static void
+ otl_jstf_extender_validate( OTL_Bytes table,
+ OTL_Validator valid )
+ {
+ OTL_Bytes p = table;
+ OTL_UInt count;
+
+ OTL_CHECK( 2 );
+
+ count = OTL_NEXT_USHORT( p );
+
+ OTL_CHECK( count*2 );
+ }
+
+
+ static void
+ otl_jstf_gsub_mods_validate( OTL_Bytes table,
+ OTL_Validator valid )
+ {
+ OTL_Bytes p = table;
+ OTL_UInt count;
+
+ OTL_CHECK( 2 );
+ count = OTL_NEXT_USHORT( p );
+ OTL_CHECK( count*2 );
+
+ /* XXX: check GSUB lookup indices */
+ }
+
+
+ static void
+ otl_jstf_gpos_mods_validate( OTL_Bytes table,
+ OTL_Validator valid )
+ {
+ OTL_Bytes p = table;
+ OTL_UInt count;
+
+ OTL_CHECK( 2 );
+ count = OTL_NEXT_USHORT( p );
+ OTL_CHECK( count*2 );
+
+ /* XXX: check GPOS lookup indices */
+ }
+
+
+ static void
+ otl_jstf_max_validate( OTL_Bytes table,
+ OTL_Validator valid )
+ {
+ OTL_Bytes p = table;
+ OTL_UInt count;
+
+ OTL_CHECK( 2 );
+
+ count = OTL_NEXT_USHORT( p );
+
+ OTL_CHECK( count*2 );
+ for ( ; count > 0; count-- )
+ otl_gpos_subtable_check( table + OTL_NEXT_USHORT( p ), valid );
+ }
+
+
+ static void
+ otl_jstf_priority_validate( OTL_Bytes table,
+ OTL_Validator valid )
+ {
+ OTL_Bytes p = table;
+ OTL_UInt offset;
+
+ OTL_CHECK( 20 );
+
+ /* shrinkage GSUB enable/disable */
+ val = OTL_NEXT_USHORT( p );
+ if ( val )
+ otl_jstf_gsub_mods_validate( table + val, valid );
+
+ val = OTL_NEXT_USHORT( p );
+ if ( val )
+ otl_jstf_gsub_mods_validate( table + val, valid );
+
+ /* shrinkage GPOS enable/disable */
+ val = OTL_NEXT_USHORT( p );
+ if ( val )
+ otl_jstf_gpos_mods_validate( table + val, valid );
+
+ val = OTL_NEXT_USHORT( p );
+ if ( val )
+ otl_jstf_gpos_mods_validate( table + val, valid );
+
+ /* shrinkage JSTF max */
+ val = OTL_NEXT_USHORT( p );
+ if ( val )
+ otl_jstf_max_validate( table + val, valid );
+
+ /* extension GSUB enable/disable */
+ val = OTL_NEXT_USHORT( p );
+ if ( val )
+ otl_jstf_gsub_mods_validate( table + val, valid );
+
+ val = OTL_NEXT_USHORT( p );
+ if ( val )
+ otl_jstf_gsub_mods_validate( table + val, valid );
+
+ /* extension GPOS enable/disable */
+ val = OTL_NEXT_USHORT( p );
+ if ( val )
+ otl_jstf_gpos_mods_validate( table + val, valid );
+
+ val = OTL_NEXT_USHORT( p );
+ if ( val )
+ otl_jstf_gpos_mods_validate( table + val, valid );
+
+ /* extension JSTF max */
+ val = OTL_NEXT_USHORT( p );
+ if ( val )
+ otl_jstf_max_validate( table + val, valid );
+ }
+
+ static void
+ otl_jstf_lang_validate( OTL_Bytes table,
+ OTL_Validator valid )
+ {
+ OTL_Bytes p = table;
+ OTL_UInt count;
+
+ OTL_CHECK( 2 );
+
+ count = OTL_NEXT_USHORT( p );
+
+ OTL_CHECK( count*2 );
+ for ( ; count > 0; count-- )
+ otl_jstf_priority_validate( table + OTL_NEXT_USHORT( p ), valid );
+ }
+
+
+ static void
+ otl_jstf_script_validate( OTL_Bytes table,
+ OTL_Validator valid )
+ {
+ OTL_Bytes p = table;
+ OTL_UInt count, extender, default_lang;
+
+ OTL_CHECK( 6 );
+ extender = OTL_NEXT_USHORT( p );
+ default_lang = OTL_NEXT_USHORT( p );
+ count = OTL_NEXT_USHORT( p );
+
+ if ( extender )
+ otl_jstf_extender_validate( table + extender, valid );
+
+ if ( default_lang )
+ otl_jstf_lang_validate( table + default_lang, valid );
+
+ OTL_CHECK( 6*count );
+
+ for ( ; count > 0; count-- )
+ {
+ p += 4; /* ignore tag */
+ otl_jstf_lang_validate( table + OTL_NEXT_USHORT( p ), valid );
+ }
+ }
+
+
+ OTL_LOCALDEF( void )
+ otl_jstf_validate( OTL_Bytes table,
+ OTL_Validator valid )
+ {
+ OTL_Bytes p = table;
+ OTL_UInt count;
+
+ OTL_CHECK( 4 );
+
+ if ( OTL_NEXT_ULONG( p ) != 0x10000UL )
+ OTL_INVALID_DATA;
+
+ count = OTL_NEXT_USHORT( p );
+ OTL_CHECK( count*6 );
+
+ for ( ; count > 0; count++ )
+ {
+ p += 4; /* ignore tag */
+ otl_jstf_script_validate( table + OTL_NEXT_USHORT( p ), valid );
+ }
+ }
+
\ No newline at end of file
--- /dev/null
+++ b/libfreetype/otljstf.h
@@ -1,0 +1,14 @@
+#ifndef __OTL_JSTF_H__
+#define __OTL_JSTF_H__
+
+#include "otlayout.h"
+
+OTL_BEGIN_HEADER
+
+ OTL_LOCAL( void )
+ otl_jstf_validate( OTL_Bytes table,
+ OTL_Validator valid );
+
+OTL_END_HEADER
+
+#endif /* __OTL_JSTF_H__ */
\ No newline at end of file
--- /dev/null
+++ b/libfreetype/otlparse.c
@@ -1,0 +1,142 @@
+#include "otlparse.h"
+#include "otlutils.h"
+
+ static void
+ otl_string_ensure( OTL_String string,
+ OTL_UInt count,
+ OTL_Parser parser )
+ {
+ count += string->length;
+
+ if ( count > string->capacity )
+ {
+ OTL_UInt old_count = string->capacity;
+ OTL_UInt new_count = old_count;
+ OTL_Memory memory = parser->memory;
+
+ while ( new_count < count )
+ new_count += (new_count >> 1) + 16;
+
+ if ( OTL_MEM_RENEW_ARRAY( string->glyphs, old_count, new_count ) )
+ otl_parser_error( parser, OTL_Parse_Err_Memory );
+
+ string->capacity = new_count;
+ }
+ }
+
+#define OTL_STRING_ENSURE(str,count,parser) \
+ OTL_BEGIN_STMNT \
+ if ( (str)->length + (count) > (str)>capacity ) \
+ otl_string_ensure( str, count, parser ); \
+ OTL_END_STMNT
+
+
+ OTL_LOCALDEF( OTL_UInt )
+ otl_parser_get_gindex( OTL_Parser parser )
+ {
+ OTL_String in = parser->str_in;
+
+ if ( in->cursor >= in->num_glyphs )
+ otl_parser_error( parser, OTL_Err_Parser_Internal );
+
+ return in->str[ in->cursor ].gindex;
+ }
+
+
+ OTL_LOCALDEF( void )
+ otl_parser_error( OTL_Parser parser,
+ OTL_ParseError error; )
+ {
+ parser->error = error;
+ otl_longjmp( parser->jump_buffer, 1 );
+ }
+
+#define OTL_PARSER_UNCOVERED(x) otl_parser_error( x, OTL_Parse_Err_UncoveredGlyph );
+
+ OTL_LOCAL( void )
+ otl_parser_check_property( OTL_Parser parser,
+ OTL_UInt gindex,
+ OTL_UInt flags,
+ OTL_UInt *aproperty );
+
+ OTL_LOCALDEF( void )
+ otl_parser_replace_1( OTL_Parser parser,
+ OTL_UInt gindex )
+ {
+ OTL_String in = parser->str_in;
+ OTL_String out = parser->str_out;
+ OTL_StringGlyph glyph, in_glyph;
+
+ /* sanity check */
+ if ( in == NULL ||
+ out == NULL ||
+ in->length == 0 ||
+ in->cursor >= in->length )
+ {
+ /* report as internal error, since these should */
+ /* never happen !! */
+ otl_parser_error( parser, OTL_Err_Parse_Internal );
+ }
+
+ OTL_STRING_ENSURE( out, 1, parser );
+ glyph = out->glyphs + out->length;
+ in_glyph = in->glyphs + in->cursor;
+
+ glyph->gindex = gindex;
+ glyph->property = in_glyph->property;
+ glyph->lig_component = in_glyph->lig_component;
+ glyph->lig_id = in_glyph->lig_id;
+
+ out->length += 1;
+ out->cursor = out->length;
+ in->cursor += 1;
+ }
+
+ OTL_LOCALDEF( void )
+ otl_parser_replace_n( OTL_Parser parser,
+ OTL_UInt count,
+ OTL_Bytes indices )
+ {
+ OTL_UInt lig_component, lig_id, property;
+ OTL_String in = parser->str_in;
+ OTL_String out = parser->str_out;
+ OTL_StringGlyph glyph, in_glyph;
+ OTL_Bytes p = indices;
+
+ /* sanity check */
+ if ( in == NULL ||
+ out == NULL ||
+ in->length == 0 ||
+ in->cursor >= in->length )
+ {
+ /* report as internal error, since these should */
+ /* never happen !! */
+ otl_parser_error( parser, OTL_Err_Parse_Internal );
+ }
+
+ OTL_STRING_ENSURE( out, count, parser );
+ glyph = out->glyphs + out->length;
+ in_glyph = in->glyphs + in->cursor;
+
+ glyph->gindex = gindex;
+
+ lig_component = in_glyph->lig_component;
+ lig_id = in_glyph->lid_id;
+ property = in_glyph->property;
+
+ for ( ; count > 0; count-- )
+ {
+ glyph->gindex = OTL_NEXT_USHORT(p);
+ glyph->property = property;
+ glyph->lig_component = lig_component;
+ glyph->lig_id = lig_id;
+
+ out->length ++;
+ }
+
+ out->cursor = out->length;
+ in->cursor += 1;
+ }
+
+
+
--- /dev/null
+++ b/libfreetype/otlparse.h
@@ -1,0 +1,99 @@
+#ifndef __OTL_PARSER_H__
+#define __OTL_PARSER_H__
+
+#include "otlayout.h"
+#include "otlgdef.h"
+#include "otlgsub.h"
+#include "otlgpos.h"
+
+OTL_BEGIN_HEADER
+
+ typedef struct OTL_ParserRec_* OTL_Parser;
+
+ typedef struct OTL_StringRec_* OTL_String;
+
+ typedef struct OTL_StringGlyphRec_
+ {
+ OTL_UInt gindex;
+ OTL_UInt properties;
+ OTL_UInt lig_component;
+ OTL_UInt lig_id;
+
+ } OTL_StringGlyphRec, *OTL_StringGlyph;
+
+ typedef struct OTL_StringRec_
+ {
+ OTL_StringGlyph glyphs;
+ OTL_UInt cursor;
+ OTL_UInt length;
+ OTL_UInt capacity;
+
+ } OTL_StringRec;
+
+ typedef struct OTL_ParserRec_
+ {
+ OTL_Bytes tab_gdef;
+ OTL_Bytes tab_gsub;
+ OTL_Bytes tab_gpos;
+ OTL_Bytes tab_base;
+ OTL_Bytes tab_jstf;
+
+ OTL_Alternate alternate; /* external alternate handler */
+
+ OTL_UInt context_len;
+ OTL_UInt markup_flags;
+
+ OTL_jmp_buf jump_buffer;
+ OTL_Memory memory;
+ OTL_Error error;
+
+ OTL_StringRec strings[2];
+ OTL_String str_in;
+ OTL_String str_out;
+
+ } OTL_ParserRec;
+
+ typedef enum
+ {
+ OTL_Err_Parser_Ok = 0,
+ OTL_Err_Parser_InvalidData,
+ OTL_Err_Parser_UncoveredGlyph
+
+ } OTL_ParseError;
+
+ OTL_LOCAL( OTL_UInt )
+ otl_parser_get_gindex( OTL_Parser parser );
+
+
+ OTL_LOCAL( void )
+ otl_parser_error( OTL_Parser parser, OTL_ParserError error );
+
+#define OTL_PARSER_UNCOVERED(x) \
+ otl_parser_error( x, OTL_Err_Parser_UncoveredGlyph )
+
+ OTL_LOCAL( void )
+ otl_parser_check_property( OTL_Parser parser,
+ OTL_UInt gindex,
+ OTL_UInt flags,
+ OTL_UInt *aproperty );
+
+ /* copy current input glyph to output */
+ OTL_LOCAL( void )
+ otl_parser_copy_1( OTL_Parser parser );
+
+ /* copy current input glyph to output, replacing its index */
+ OTL_LOCAL( void )
+ otl_parser_replace_1( OTL_Parser parser,
+ OTL_UInt gindex );
+
+ /* copy current input glyph to output, replacing it by several indices */
+ /* read directly from the table */
+ OTL_LOCAL( void )
+ otl_parser_replace_n( OTL_Parser parser,
+ OTL_UInt count,
+ OTL_Bytes indices );
+
+OTL_END_HEADER
+
+#endif /* __OTL_PARSER_H__ */
+
--- /dev/null
+++ b/libfreetype/otltable.h
@@ -1,0 +1,60 @@
+#ifndef __OTL_TABLE_H__
+#define __OTL_TABLE_H__
+
+#include "otlayout.h"
+
+OTL_BEGIN_HEADER
+
+ typedef struct OTL_TableRec_* OTL_Table;
+
+ typedef enum
+ {
+ OTL_TABLE_TYPE_GDEF = 1,
+ OTL_TABLE_TYPE_GSUB,
+ OTL_TABLE_TYPE_GPOS,
+ OTL_TABLE_TYPE_BASE,
+ OTL_TABLE_TYPE_JSTF
+
+ } OTL_TableType;
+
+
+ /* this may become a private structure later */
+ typedef struct OTL_TableRec_
+ {
+ OTL_TableType type;
+ OTL_Bytes base;
+ OTL_Bytes limit;
+
+ OTL_Tag script_tag;
+ OTL_Tag lang_tag;
+
+ OTL_UInt lookup_count;
+ OTL_Byte* lookup_flags;
+
+ OTL_UInt feature_count;
+ OTL_Tag feature_tags;
+ OTL_Byte* feature_flags;
+
+ } OTL_TableRec;
+
+
+ OTL_API( OTL_Error )
+ otl_table_validate( OTL_Bytes table,
+ OTL_Size size,
+ OTL_TableType type,
+ OTL_Size *abyte_size );
+
+ OTL_API( void )
+ otl_table_init( OTL_Table table,
+ OTL_TableType type,
+ OTL_Bytes base,
+ OTL_Size size );
+
+ OTL_API( void )
+ otl_table_set_script( OTL_Table table,
+ OTL_ScriptTag script,
+ OTL_LangTag language );
+
+OTL_END_HEADER
+
+#endif /* __OTL_TABLE_H__ */
--- /dev/null
+++ b/libfreetype/otltags.h
@@ -1,0 +1,86 @@
+/* this file may be included several times by other parts of */
+/* the OpenType Layout library.. don't add #ifdef .. #endif */
+/* delimiters to it... */
+
+ /************************************************************************/
+ /************************************************************************/
+ /***** *****/
+ /***** SCRIPT TAGS *****/
+ /***** *****/
+ /************************************************************************/
+ /************************************************************************/
+
+#ifndef OTL_SCRIPT_TAG
+#define OTL_SCRIPT_TAG(c1,c2,c3,c4,s,n) /* void */
+#endif
+
+OTL_SCRIPT_TAG( 'a','r','a','b', "Arabic", ARABIC )
+OTL_SCRIPT_TAG( 'a','r','m','n', "Armenian", ARMENIAN )
+OTL_SCRIPT_TAG( 'b','e','n','g', "Bengali", BENGALI )
+OTL_SCRIPT_TAG( 'b','o','p','o', "Bopomofo", BOPOMOFO )
+OTL_SCRIPT_TAG( 'b','r','a','i', "Braille", BRAILLE )
+OTL_SCRIPT_TAG( 'c','a','n','s', "Canadian Syllabic", CANADIAN )
+OTL_SCRIPT_TAG( 'c','h','e','r', "Cherokee", CHEROKEE )
+OTL_SCRIPT_TAG( 'h','a','n','i', "CJK Ideographic", CJK )
+OTL_SCRIPT_TAG( 'c','y','r','l', "Cyrillic", CYRILLIC )
+OTL_SCRIPT_TAG( 'd','e','v','a', "Devanagari", DEVANAGARI )
+OTL_SCRIPT_TAG( 'e','t','h','i', "Ethiopic", ETHIOPIC )
+OTL_SCRIPT_TAG( 'g','e','o','r', "Georgian", GEORGIAN )
+OTL_SCRIPT_TAG( 'g','r','e','k', "Greek", GREEK )
+OTL_SCRIPT_TAG( 'g','u','j','r', "Gujarati", GUJARATI )
+OTL_SCRIPT_TAG( 'g','u','r','u', "Gurmukhi", GURMUKHI )
+OTL_SCRIPT_TAG( 'j','a','m','o', "Hangul Jamo", JAMO )
+OTL_SCRIPT_TAG( 'h','a','n','g', "Hangul", HANGUL )
+OTL_SCRIPT_TAG( 'h','e','b','r', "Hebrew", HEBREW )
+OTL_SCRIPT_TAG( 'h','i','r','a', "Hiragana", HIRAGANA )
+OTL_SCRIPT_TAG( 'k','n','d','a', "Kannada", KANNADA )
+OTL_SCRIPT_TAG( 'k','a','n','a', "Katakana", KATAKANA )
+OTL_SCRIPT_TAG( 'k','h','m','r', "Khmer", KHMER )
+OTL_SCRIPT_TAG( 'l','a','o',' ', "Lao", LAO )
+OTL_SCRIPT_TAG( 'l','a','t','n', "Latin", LATIN )
+OTL_SCRIPT_TAG( 'm','l','y','m', "Malayalam", MALAYALAM )
+OTL_SCRIPT_TAG( 'm','o','n','g', "Mongolian", MONGOLIAN )
+OTL_SCRIPT_TAG( 'm','y','m','r', "Myanmar", MYANMAR )
+OTL_SCRIPT_TAG( 'o','g','a','m', "Ogham", OGHAM )
+OTL_SCRIPT_TAG( 'o','r','y','a', "Oriya", ORIYA )
+OTL_SCRIPT_TAG( 'r','u','n','r', "Runic", RUNIC )
+OTL_SCRIPT_TAG( 's','i','n','h', "Sinhala", SINHALA )
+OTL_SCRIPT_TAG( 's','y','r','c', "Syriac", SYRIAC )
+OTL_SCRIPT_TAG( 't','a','m','l', "Tamil", TAMIL )
+OTL_SCRIPT_TAG( 't','e','l','u', "Telugu", TELUGU )
+OTL_SCRIPT_TAG( 't','h','a','a', "Thaana", THAANA )
+OTL_SCRIPT_TAG( 't','h','a','i', "Thai", THAI )
+OTL_SCRIPT_TAG( 't','i','b','t', "Tibetan", TIBETAN )
+OTL_SCRIPT_TAG( 'y','i',' ',' ', "Yi", YI )
+
+#undef OTL_SCRIPT_TAG
+
+ /************************************************************************/
+ /************************************************************************/
+ /***** *****/
+ /***** LANGUAGE TAGS *****/
+ /***** *****/
+ /************************************************************************/
+ /************************************************************************/
+
+#ifndef OTL_LANG_TAG
+#define OTL_LANG_TAG(c1,c2,c3,c4,s,n) /* void */
+#endif
+
+#undef OTL_LANG_TAG
+
+
+ /************************************************************************/
+ /************************************************************************/
+ /***** *****/
+ /***** FEATURE TAGS *****/
+ /***** *****/
+ /************************************************************************/
+ /************************************************************************/
+
+#ifndef OTL_FEATURE_TAG
+#define OTL_FEATURE_TAG(c1,c2,c3,c4,s,n) /* void */
+#endif
+
+#undef OTL_FEATURE_TAG
+
--- /dev/null
+++ b/libfreetype/otlutils.h
@@ -1,0 +1,33 @@
+#ifndef __OTLAYOUT_UTILS_H__
+#define __OTLAYOUT_UTILS_H__
+
+#include "otlayout.h"
+
+OTL_BEGIN_HEADER
+
+ OTL_LOCAL( OTL_Error )
+ otl_mem_alloc( OTL_Pointer* pblock,
+ OTL_ULong size,
+ OTL_Memory memory );
+
+ OTL_LOCAL( void )
+ otl_mem_free( OTL_Pointer* pblock,
+ OTL_Memory memory );
+
+ OTL_LOCAL( OTL_Error )
+ otl_mem_realloc( OTL_Pointer *pblock,
+ OTL_ULong cur_size,
+ OTL_ULong new_size,
+ OTL_Memory memory );
+
+#define OTL_MEM_ALLOC(p,s) otl_mem_alloc( (void**)&(p), (s), memory )
+#define OTL_MEM_FREE(p) otl_mem_free( (void**)&(p), memory )
+#define OTL_MEM_REALLOC(p,c,n) otl_mem_realloc( (void**)&(p), (c), (s), memory )
+
+#define OTL_MEM_NEW(p) OTL_MEM_ALLOC(p,sizeof(*(p)))
+#define OTL_MEM_NEW_ARRAY(p,c) OTL_MEM_ALLOC(p,(c)*sizeof(*(p)))
+#define OTL_MEM_RENEW_ARRAY(p,c,n) OTL_MEM_REALLOC(p,(c)*sizeof(*(p)),(n)*sizeof(*(p)))
+
+OTL_END_HEADER
+
+#endif /* __OTLAYOUT_UTILS_H__ */
--- /dev/null
+++ b/libfreetype/pcf.c
@@ -1,0 +1,36 @@
+/* pcf.c
+
+ FreeType font driver for pcf fonts
+
+ Copyright 2000-2001 by
+ Francesco Zappa Nardelli
+
+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.
+*/
+
+
+#define FT_MAKE_OPTION_SINGLE_OBJECT
+
+
+#include <ft2build.h>
+#include "pcfutil.c"
+#include "pcfread.c"
+#include "pcfdriver.c"
+
+/* END */
--- /dev/null
+++ b/libfreetype/pcf.h
@@ -1,0 +1,238 @@
+/* pcf.h
+
+ FreeType font driver for pcf fonts
+
+ Copyright (C) 2000-2001, 2002 by
+ Francesco Zappa Nardelli
+
+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.
+*/
+
+
+#ifndef __PCF_H__
+#define __PCF_H__
+
+
+#include <ft2build.h>
+#include FT_INTERNAL_DRIVER_H
+#include FT_INTERNAL_STREAM_H
+
+
+FT_BEGIN_HEADER
+
+ typedef struct PCF_TableRec_
+ {
+ FT_ULong type;
+ FT_ULong format;
+ FT_ULong size;
+ FT_ULong offset;
+
+ } PCF_TableRec, *PCF_Table;
+
+
+ typedef struct PCF_TocRec_
+ {
+ FT_ULong version;
+ FT_ULong count;
+ PCF_Table tables;
+
+ } PCF_TocRec, *PCF_Toc;
+
+
+ typedef struct PCF_ParsePropertyRec_
+ {
+ FT_Long name;
+ FT_Byte isString;
+ FT_Long value;
+
+ } PCF_ParsePropertyRec, *PCF_ParseProperty;
+
+
+ typedef struct PCF_PropertyRec_
+ {
+ FT_String* name;
+ FT_Byte isString;
+
+ union
+ {
+ FT_String* atom;
+ FT_Long integer;
+ FT_ULong cardinal;
+
+ } value;
+
+ } PCF_PropertyRec, *PCF_Property;
+
+
+ typedef struct PCF_Compressed_MetricRec_
+ {
+ FT_Byte leftSideBearing;
+ FT_Byte rightSideBearing;
+ FT_Byte characterWidth;
+ FT_Byte ascent;
+ FT_Byte descent;
+
+ } PCF_Compressed_MetricRec, *PCF_Compressed_Metric;
+
+
+ typedef struct PCF_MetricRec_
+ {
+ FT_Short leftSideBearing;
+ FT_Short rightSideBearing;
+ FT_Short characterWidth;
+ FT_Short ascent;
+ FT_Short descent;
+ FT_Short attributes;
+ FT_ULong bits;
+
+ } PCF_MetricRec, *PCF_Metric;
+
+
+ typedef struct PCF_AccelRec_
+ {
+ FT_Byte noOverlap;
+ FT_Byte constantMetrics;
+ FT_Byte terminalFont;
+ FT_Byte constantWidth;
+ FT_Byte inkInside;
+ FT_Byte inkMetrics;
+ FT_Byte drawDirection;
+ FT_Long fontAscent;
+ FT_Long fontDescent;
+ FT_Long maxOverlap;
+ PCF_MetricRec minbounds;
+ PCF_MetricRec maxbounds;
+ PCF_MetricRec ink_minbounds;
+ PCF_MetricRec ink_maxbounds;
+
+ } PCF_AccelRec, *PCF_Accel;
+
+
+ typedef struct PCD_EncodingRec_
+ {
+ FT_Long enc;
+ FT_Short glyph;
+
+ } PCF_EncodingRec, *PCF_Encoding;
+
+
+ typedef struct PCF_FaceRec_
+ {
+ FT_FaceRec root;
+
+ FT_StreamRec gzip_stream;
+ FT_Stream gzip_source;
+
+ char* charset_encoding;
+ char* charset_registry;
+
+ PCF_TocRec toc;
+ PCF_AccelRec accel;
+
+ int nprops;
+ PCF_Property properties;
+
+ FT_Long nmetrics;
+ PCF_Metric metrics;
+ FT_Long nencodings;
+ PCF_Encoding encodings;
+
+ FT_Short defaultChar;
+
+ FT_ULong bitmapsFormat;
+
+ FT_CharMap charmap_handle;
+ FT_CharMapRec charmap; /* a single charmap per face */
+
+ } PCF_FaceRec, *PCF_Face;
+
+
+ /* macros for pcf font format */
+
+#define LSBFirst 0
+#define MSBFirst 1
+
+#define PCF_FILE_VERSION ( ( 'p' << 24 ) | \
+ ( 'c' << 16 ) | \
+ ( 'f' << 8 ) | 1 )
+#define PCF_FORMAT_MASK 0xFFFFFF00L
+
+#define PCF_DEFAULT_FORMAT 0x00000000L
+#define PCF_INKBOUNDS 0x00000200L
+#define PCF_ACCEL_W_INKBOUNDS 0x00000100L
+#define PCF_COMPRESSED_METRICS 0x00000100L
+
+#define PCF_FORMAT_MATCH( a, b ) \
+ ( ( (a) & PCF_FORMAT_MASK ) == ( (b) & PCF_FORMAT_MASK ) )
+
+#define PCF_GLYPH_PAD_MASK ( 3 << 0 )
+#define PCF_BYTE_MASK ( 1 << 2 )
+#define PCF_BIT_MASK ( 1 << 3 )
+#define PCF_SCAN_UNIT_MASK ( 3 << 4 )
+
+#define PCF_BYTE_ORDER( f ) \
+ ( ( (f) & PCF_BYTE_MASK ) ? MSBFirst : LSBFirst )
+#define PCF_BIT_ORDER( f ) \
+ ( ( (f) & PCF_BIT_MASK ) ? MSBFirst : LSBFirst )
+#define PCF_GLYPH_PAD_INDEX( f ) \
+ ( (f) & PCF_GLYPH_PAD_MASK )
+#define PCF_GLYPH_PAD( f ) \
+ ( 1 << PCF_GLYPH_PAD_INDEX( f ) )
+#define PCF_SCAN_UNIT_INDEX( f ) \
+ ( ( (f) & PCF_SCAN_UNIT_MASK ) >> 4 )
+#define PCF_SCAN_UNIT( f ) \
+ ( 1 << PCF_SCAN_UNIT_INDEX( f ) )
+#define PCF_FORMAT_BITS( f ) \
+ ( (f) & ( PCF_GLYPH_PAD_MASK | \
+ PCF_BYTE_MASK | \
+ PCF_BIT_MASK | \
+ PCF_SCAN_UNIT_MASK ) )
+
+#define PCF_SIZE_TO_INDEX( s ) ( (s) == 4 ? 2 : (s) == 2 ? 1 : 0 )
+#define PCF_INDEX_TO_SIZE( b ) ( 1 << b )
+
+#define PCF_FORMAT( bit, byte, glyph, scan ) \
+ ( ( PCF_SIZE_TO_INDEX( scan ) << 4 ) | \
+ ( ( (bit) == MSBFirst ? 1 : 0 ) << 3 ) | \
+ ( ( (byte) == MSBFirst ? 1 : 0 ) << 2 ) | \
+ ( PCF_SIZE_TO_INDEX( glyph ) << 0 ) )
+
+#define PCF_PROPERTIES ( 1 << 0 )
+#define PCF_ACCELERATORS ( 1 << 1 )
+#define PCF_METRICS ( 1 << 2 )
+#define PCF_BITMAPS ( 1 << 3 )
+#define PCF_INK_METRICS ( 1 << 4 )
+#define PCF_BDF_ENCODINGS ( 1 << 5 )
+#define PCF_SWIDTHS ( 1 << 6 )
+#define PCF_GLYPH_NAMES ( 1 << 7 )
+#define PCF_BDF_ACCELERATORS ( 1 << 8 )
+
+#define GLYPHPADOPTIONS 4 /* I'm not sure about this */
+
+ FT_LOCAL( FT_Error )
+ pcf_load_font( FT_Stream,
+ PCF_Face );
+
+
+FT_END_HEADER
+
+#endif /* __PCF_H__ */
+
+
+/* END */
--- /dev/null
+++ b/libfreetype/pcfdriver.c
@@ -1,0 +1,501 @@
+/* pcfdriver.c
+
+ FreeType font driver for pcf files
+
+ Copyright (C) 2000-2001, 2002 by
+ Francesco Zappa Nardelli
+
+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.
+*/
+
+
+#include <ft2build.h>
+
+#include FT_INTERNAL_DEBUG_H
+#include FT_INTERNAL_STREAM_H
+#include FT_INTERNAL_OBJECTS_H
+#include FT_GZIP_H
+#include FT_ERRORS_H
+
+#include "pcf.h"
+#include "pcfdriver.h"
+#include "pcfutil.h"
+
+#include "pcferror.h"
+
+#undef FT_COMPONENT
+#define FT_COMPONENT trace_pcfread
+
+
+ typedef struct PCF_CMapRec_
+ {
+ FT_CMapRec cmap;
+ FT_UInt num_encodings;
+ PCF_Encoding encodings;
+
+ } PCF_CMapRec, *PCF_CMap;
+
+
+ FT_CALLBACK_DEF( FT_Error )
+ pcf_cmap_init( PCF_CMap cmap )
+ {
+ PCF_Face face = (PCF_Face)FT_CMAP_FACE( cmap );
+
+
+ cmap->num_encodings = (FT_UInt)face->nencodings;
+ cmap->encodings = face->encodings;
+
+ return FT_Err_Ok;
+ }
+
+
+ FT_CALLBACK_DEF( void )
+ pcf_cmap_done( PCF_CMap cmap )
+ {
+ cmap->encodings = NULL;
+ cmap->num_encodings = 0;
+ }
+
+
+ FT_CALLBACK_DEF( FT_UInt )
+ pcf_cmap_char_index( PCF_CMap cmap,
+ FT_UInt32 charcode )
+ {
+ PCF_Encoding encodings = cmap->encodings;
+ FT_UInt min, max, mid;
+ FT_UInt result = 0;
+
+
+ min = 0;
+ max = cmap->num_encodings;
+
+ while ( min < max )
+ {
+ FT_UInt32 code;
+
+
+ mid = ( min + max ) >> 1;
+ code = encodings[mid].enc;
+
+ if ( charcode == code )
+ {
+ result = encodings[mid].glyph + 1;
+ break;
+ }
+
+ if ( charcode < code )
+ max = mid;
+ else
+ min = mid + 1;
+ }
+
+ return result;
+ }
+
+
+ FT_CALLBACK_DEF( FT_UInt )
+ pcf_cmap_char_next( PCF_CMap cmap,
+ FT_UInt32 *acharcode )
+ {
+ PCF_Encoding encodings = cmap->encodings;
+ FT_UInt min, max, mid;
+ FT_UInt32 charcode = *acharcode + 1;
+ FT_UInt result = 0;
+
+
+ min = 0;
+ max = cmap->num_encodings;
+
+ while ( min < max )
+ {
+ FT_UInt32 code;
+
+
+ mid = ( min + max ) >> 1;
+ code = encodings[mid].enc;
+
+ if ( charcode == code )
+ {
+ result = encodings[mid].glyph + 1;
+ goto Exit;
+ }
+
+ if ( charcode < code )
+ max = mid;
+ else
+ min = mid + 1;
+ }
+
+ charcode = 0;
+ if ( min < cmap->num_encodings )
+ {
+ charcode = encodings[min].enc;
+ result = encodings[min].glyph + 1;
+ }
+
+ Exit:
+ *acharcode = charcode;
+ return result;
+ }
+
+
+ FT_CALLBACK_TABLE_DEF const FT_CMap_ClassRec pcf_cmap_class =
+ {
+ sizeof( PCF_CMapRec ),
+ (FT_CMap_InitFunc) pcf_cmap_init,
+ (FT_CMap_DoneFunc) pcf_cmap_done,
+ (FT_CMap_CharIndexFunc)pcf_cmap_char_index,
+ (FT_CMap_CharNextFunc) pcf_cmap_char_next
+ };
+
+
+ /*************************************************************************/
+ /* */
+ /* The macro FT_COMPONENT is used in trace mode. It is an implicit */
+ /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log */
+ /* messages during execution. */
+ /* */
+#undef FT_COMPONENT
+#define FT_COMPONENT trace_pcfdriver
+
+
+ FT_CALLBACK_DEF( FT_Error )
+ PCF_Face_Done( PCF_Face face )
+ {
+ FT_Memory memory = FT_FACE_MEMORY( face );
+
+
+ FT_FREE( face->encodings );
+ FT_FREE( face->metrics );
+
+ /* free properties */
+ {
+ PCF_Property prop = face->properties;
+ FT_Int i;
+
+
+ for ( i = 0; i < face->nprops; i++ )
+ {
+ prop = &face->properties[i];
+
+ FT_FREE( prop->name );
+ if ( prop->isString )
+ FT_FREE( prop->value );
+ }
+
+ FT_FREE( face->properties );
+ }
+
+ FT_FREE( face->toc.tables );
+ FT_FREE( face->root.family_name );
+ FT_FREE( face->root.available_sizes );
+ FT_FREE( face->charset_encoding );
+ FT_FREE( face->charset_registry );
+
+ FT_TRACE4(( "PCF_Face_Done: done face\n" ));
+
+ /* close gzip stream if any */
+ if ( face->root.stream == &face->gzip_stream )
+ {
+ FT_Stream_Close( &face->gzip_stream );
+ face->root.stream = face->gzip_source;
+ }
+
+ return PCF_Err_Ok;
+ }
+
+
+ FT_CALLBACK_DEF( FT_Error )
+ PCF_Face_Init( FT_Stream stream,
+ PCF_Face face,
+ FT_Int face_index,
+ FT_Int num_params,
+ FT_Parameter* params )
+ {
+ FT_Error error = PCF_Err_Ok;
+
+ FT_UNUSED( num_params );
+ FT_UNUSED( params );
+ FT_UNUSED( face_index );
+
+
+ error = pcf_load_font( stream, face );
+ if ( error )
+ {
+ FT_Error error2;
+
+ /* this didn't work, try gzip support !! */
+ error2 = FT_Stream_OpenGzip( &face->gzip_stream, stream );
+ if ( error2 == FT_Err_Unimplemented_Feature )
+ goto Fail;
+
+ error = error2;
+ if ( error )
+ goto Fail;
+
+ face->gzip_source = stream;
+ face->root.stream = &face->gzip_stream;
+
+ stream = face->root.stream;
+
+ error = pcf_load_font( stream, face );
+ if ( error )
+ goto Fail;
+ }
+
+ /* set-up charmap */
+ {
+ FT_String *charset_registry, *charset_encoding;
+ FT_Bool unicode_charmap = 0;
+
+
+ charset_registry = face->charset_registry;
+ charset_encoding = face->charset_encoding;
+
+ if ( ( charset_registry != NULL ) &&
+ ( charset_encoding != NULL ) )
+ {
+ if ( !ft_strcmp( face->charset_registry, "ISO10646" ) ||
+ ( !ft_strcmp( face->charset_registry, "ISO8859" ) &&
+ !ft_strcmp( face->charset_encoding, "1" ) ) )
+ unicode_charmap = 1;
+ }
+
+ {
+ FT_CharMapRec charmap;
+
+
+ charmap.face = FT_FACE( face );
+ charmap.encoding = FT_ENCODING_NONE;
+ charmap.platform_id = 0;
+ charmap.encoding_id = 0;
+
+ if ( unicode_charmap )
+ {
+ charmap.encoding = FT_ENCODING_UNICODE;
+ charmap.platform_id = 3;
+ charmap.encoding_id = 1;
+ }
+
+ error = FT_CMap_New( &pcf_cmap_class, NULL, &charmap, NULL );
+
+#if 0
+ /* Select default charmap */
+ if (face->root.num_charmaps)
+ face->root.charmap = face->root.charmaps[0];
+#endif
+ }
+ }
+
+ Exit:
+ return error;
+
+ Fail:
+ FT_TRACE2(( "[not a valid PCF file]\n" ));
+ error = PCF_Err_Unknown_File_Format; /* error */
+ goto Exit;
+ }
+
+
+ static FT_Error
+ PCF_Set_Pixel_Size( FT_Size size )
+ {
+ PCF_Face face = (PCF_Face)FT_SIZE_FACE( size );
+
+
+ FT_TRACE4(( "rec %d - pres %d\n", size->metrics.y_ppem,
+ face->root.available_sizes->height ));
+
+ if ( size->metrics.y_ppem == face->root.available_sizes->height )
+ {
+ size->metrics.ascender = face->accel.fontAscent << 6;
+ size->metrics.descender = face->accel.fontDescent * (-64);
+#if 0
+ size->metrics.height = face->accel.maxbounds.ascent << 6;
+#endif
+ size->metrics.height = size->metrics.ascender -
+ size->metrics.descender;
+
+ size->metrics.max_advance = face->accel.maxbounds.characterWidth << 6;
+
+ return PCF_Err_Ok;
+ }
+ else
+ {
+ FT_TRACE4(( "size WRONG\n" ));
+ return PCF_Err_Invalid_Pixel_Size;
+ }
+ }
+
+
+ static FT_Error
+ PCF_Glyph_Load( FT_GlyphSlot slot,
+ FT_Size size,
+ FT_UInt glyph_index,
+ FT_Int32 load_flags )
+ {
+ PCF_Face face = (PCF_Face)FT_SIZE_FACE( size );
+ FT_Stream stream = face->root.stream;
+ FT_Error error = PCF_Err_Ok;
+ FT_Memory memory = FT_FACE( face )->memory;
+ FT_Bitmap* bitmap = &slot->bitmap;
+ PCF_Metric metric;
+ int bytes;
+
+ FT_UNUSED( load_flags );
+
+
+ FT_TRACE4(( "load_glyph %d ---", glyph_index ));
+
+ if ( !face )
+ {
+ error = PCF_Err_Invalid_Argument;
+ goto Exit;
+ }
+
+ if ( glyph_index > 0 )
+ glyph_index--;
+
+ metric = face->metrics + glyph_index;
+
+ bitmap->rows = metric->ascent + metric->descent;
+ bitmap->width = metric->rightSideBearing - metric->leftSideBearing;
+ bitmap->num_grays = 1;
+ bitmap->pixel_mode = FT_PIXEL_MODE_MONO;
+
+ FT_TRACE6(( "BIT_ORDER %d ; BYTE_ORDER %d ; GLYPH_PAD %d\n",
+ PCF_BIT_ORDER( face->bitmapsFormat ),
+ PCF_BYTE_ORDER( face->bitmapsFormat ),
+ PCF_GLYPH_PAD( face->bitmapsFormat ) ));
+
+ switch ( PCF_GLYPH_PAD( face->bitmapsFormat ) )
+ {
+ case 1:
+ bitmap->pitch = ( bitmap->width + 7 ) >> 3;
+ break;
+
+ case 2:
+ bitmap->pitch = ( ( bitmap->width + 15 ) >> 4 ) << 1;
+ break;
+
+ case 4:
+ bitmap->pitch = ( ( bitmap->width + 31 ) >> 5 ) << 2;
+ break;
+
+ case 8:
+ bitmap->pitch = ( ( bitmap->width + 63 ) >> 6 ) << 3;
+ break;
+
+ default:
+ return PCF_Err_Invalid_File_Format;
+ }
+
+ /* XXX: to do: are there cases that need repadding the bitmap? */
+ bytes = bitmap->pitch * bitmap->rows;
+
+ if ( FT_ALLOC( bitmap->buffer, bytes ) )
+ goto Exit;
+
+ if ( FT_STREAM_SEEK( metric->bits ) ||
+ FT_STREAM_READ( bitmap->buffer, bytes ) )
+ goto Exit;
+
+ if ( PCF_BIT_ORDER( face->bitmapsFormat ) != MSBFirst )
+ BitOrderInvert( bitmap->buffer, bytes );
+
+ if ( ( PCF_BYTE_ORDER( face->bitmapsFormat ) !=
+ PCF_BIT_ORDER( face->bitmapsFormat ) ) )
+ {
+ switch ( PCF_SCAN_UNIT( face->bitmapsFormat ) )
+ {
+ case 1:
+ break;
+
+ case 2:
+ TwoByteSwap( bitmap->buffer, bytes );
+ break;
+
+ case 4:
+ FourByteSwap( bitmap->buffer, bytes );
+ break;
+ }
+ }
+
+ slot->bitmap_left = metric->leftSideBearing;
+ slot->bitmap_top = metric->ascent;
+
+ slot->metrics.horiAdvance = metric->characterWidth << 6 ;
+ slot->metrics.horiBearingX = metric->leftSideBearing << 6 ;
+ slot->metrics.horiBearingY = metric->ascent << 6 ;
+ slot->metrics.width = ( metric->rightSideBearing -
+ metric->leftSideBearing ) << 6;
+ slot->metrics.height = bitmap->rows << 6;
+
+ slot->linearHoriAdvance = (FT_Fixed)bitmap->width << 16;
+ slot->format = FT_GLYPH_FORMAT_BITMAP;
+ slot->flags = FT_GLYPH_OWN_BITMAP;
+
+ FT_TRACE4(( " --- ok\n" ));
+
+ Exit:
+ return error;
+ }
+
+
+ FT_CALLBACK_TABLE_DEF
+ const FT_Driver_ClassRec pcf_driver_class =
+ {
+ {
+ ft_module_font_driver,
+ sizeof ( FT_DriverRec ),
+
+ "pcf",
+ 0x10000L,
+ 0x20000L,
+
+ 0,
+
+ (FT_Module_Constructor)0,
+ (FT_Module_Destructor) 0,
+ (FT_Module_Requester) 0
+ },
+
+ sizeof( PCF_FaceRec ),
+ sizeof( FT_SizeRec ),
+ sizeof( FT_GlyphSlotRec ),
+
+ (FT_Face_InitFunc) PCF_Face_Init,
+ (FT_Face_DoneFunc) PCF_Face_Done,
+ (FT_Size_InitFunc) 0,
+ (FT_Size_DoneFunc) 0,
+ (FT_Slot_InitFunc) 0,
+ (FT_Slot_DoneFunc) 0,
+
+ (FT_Size_ResetPointsFunc) PCF_Set_Pixel_Size,
+ (FT_Size_ResetPixelsFunc) PCF_Set_Pixel_Size,
+
+ (FT_Slot_LoadFunc) PCF_Glyph_Load,
+
+ (FT_Face_GetKerningFunc) 0,
+ (FT_Face_AttachFunc) 0,
+ (FT_Face_GetAdvancesFunc) 0
+ };
+
+
+/* END */
--- /dev/null
+++ b/libfreetype/pcfdriver.h
@@ -1,0 +1,44 @@
+/* pcfdriver.h
+
+ FreeType font driver for pcf fonts
+
+ Copyright 2000-2001, 2002 by
+ Francesco Zappa Nardelli
+
+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.
+*/
+
+
+#ifndef __PCFDRIVER_H__
+#define __PCFDRIVER_H__
+
+#include <ft2build.h>
+#include FT_INTERNAL_DRIVER_H
+
+FT_BEGIN_HEADER
+
+ FT_EXPORT_VAR( const FT_Driver_ClassRec ) pcf_driver_class;
+
+FT_END_HEADER
+
+
+#endif /* __PCFDRIVER_H__ */
+
+
+/* END */
--- /dev/null
+++ b/libfreetype/pcferror.h
@@ -1,0 +1,40 @@
+/***************************************************************************/
+/* */
+/* pcferror.h */
+/* */
+/* PCF error codes (specification only). */
+/* */
+/* Copyright 2001 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+
+ /*************************************************************************/
+ /* */
+ /* This file is used to define the PCF error enumeration constants. */
+ /* */
+ /*************************************************************************/
+
+#ifndef __PCFERROR_H__
+#define __PCFERROR_H__
+
+#include FT_MODULE_ERRORS_H
+
+#undef __FTERRORS_H__
+
+#define FT_ERR_PREFIX PCF_Err_
+#define FT_ERR_BASE FT_Mod_Err_PCF
+
+#include FT_ERRORS_H
+
+#endif /* __PCFERROR_H__ */
+
+
+/* END */
--- /dev/null
+++ b/libfreetype/pcfread.c
@@ -1,0 +1,1057 @@
+/* pcfread.c
+
+ FreeType font driver for pcf fonts
+
+ Copyright 2000-2001, 2002 by
+ Francesco Zappa Nardelli
+
+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.
+*/
+
+
+#include <ft2build.h>
+
+#include FT_INTERNAL_DEBUG_H
+#include FT_INTERNAL_STREAM_H
+#include FT_INTERNAL_OBJECTS_H
+
+#include "pcf.h"
+#include "pcfdriver.h"
+
+#include "pcferror.h"
+
+
+ /*************************************************************************/
+ /* */
+ /* The macro FT_COMPONENT is used in trace mode. It is an implicit */
+ /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log */
+ /* messages during execution. */
+ /* */
+#undef FT_COMPONENT
+#define FT_COMPONENT trace_pcfread
+
+
+#if defined( FT_DEBUG_LEVEL_TRACE )
+ static const char* tableNames[] =
+ {
+ "prop", "accl", "mtrcs", "bmps", "imtrcs",
+ "enc", "swidth", "names", "accel"
+ };
+#endif
+
+
+ static
+ const FT_Frame_Field pcf_toc_header[] =
+ {
+#undef FT_STRUCTURE
+#define FT_STRUCTURE PCF_TocRec
+
+ FT_FRAME_START( 8 ),
+ FT_FRAME_ULONG_LE( version ),
+ FT_FRAME_ULONG_LE( count ),
+ FT_FRAME_END
+ };
+
+
+ static
+ const FT_Frame_Field pcf_table_header[] =
+ {
+#undef FT_STRUCTURE
+#define FT_STRUCTURE PCF_TableRec
+
+ FT_FRAME_START( 16 ),
+ FT_FRAME_ULONG_LE( type ),
+ FT_FRAME_ULONG_LE( format ),
+ FT_FRAME_ULONG_LE( size ),
+ FT_FRAME_ULONG_LE( offset ),
+ FT_FRAME_END
+ };
+
+
+ static FT_Error
+ pcf_read_TOC( FT_Stream stream,
+ PCF_Face face )
+ {
+ FT_Error error;
+ PCF_Toc toc = &face->toc;
+ PCF_Table tables;
+
+ FT_Memory memory = FT_FACE(face)->memory;
+ FT_UInt n;
+
+
+ if ( FT_STREAM_SEEK ( 0 ) ||
+ FT_STREAM_READ_FIELDS ( pcf_toc_header, toc ) )
+ return PCF_Err_Cannot_Open_Resource;
+
+ if ( toc->version != PCF_FILE_VERSION )
+ return PCF_Err_Invalid_File_Format;
+
+ if ( FT_NEW_ARRAY( face->toc.tables, toc->count ) )
+ return PCF_Err_Out_Of_Memory;
+
+ tables = face->toc.tables;
+ for ( n = 0; n < toc->count; n++ )
+ {
+ if ( FT_STREAM_READ_FIELDS( pcf_table_header, tables ) )
+ goto Exit;
+ tables++;
+ }
+
+#if defined( FT_DEBUG_LEVEL_TRACE )
+
+ {
+ FT_UInt i, j;
+ const char* name = "?";
+
+
+ FT_TRACE4(( "Tables count: %ld\n", face->toc.count ));
+ tables = face->toc.tables;
+ for ( i = 0; i < toc->count; i++ )
+ {
+ for( j = 0; j < sizeof ( tableNames ) / sizeof ( tableNames[0] ); j++ )
+ if ( tables[i].type == (FT_UInt)( 1 << j ) )
+ name = tableNames[j];
+
+ FT_TRACE4(( "Table %d: type=%-6s format=0x%04lX "
+ "size=0x%06lX (%8ld) offset=0x%04lX\n",
+ i, name,
+ tables[i].format,
+ tables[i].size, tables[i].size,
+ tables[i].offset ));
+ }
+ }
+
+#endif
+
+ return PCF_Err_Ok;
+
+ Exit:
+ FT_FREE( face->toc.tables );
+ return error;
+ }
+
+
+ static
+ const FT_Frame_Field pcf_metric_header[] =
+ {
+#undef FT_STRUCTURE
+#define FT_STRUCTURE PCF_MetricRec
+
+ FT_FRAME_START( 12 ),
+ FT_FRAME_SHORT_LE( leftSideBearing ),
+ FT_FRAME_SHORT_LE( rightSideBearing ),
+ FT_FRAME_SHORT_LE( characterWidth ),
+ FT_FRAME_SHORT_LE( ascent ),
+ FT_FRAME_SHORT_LE( descent ),
+ FT_FRAME_SHORT_LE( attributes ),
+ FT_FRAME_END
+ };
+
+
+ static
+ const FT_Frame_Field pcf_metric_msb_header[] =
+ {
+#undef FT_STRUCTURE
+#define FT_STRUCTURE PCF_MetricRec
+
+ FT_FRAME_START( 12 ),
+ FT_FRAME_SHORT( leftSideBearing ),
+ FT_FRAME_SHORT( rightSideBearing ),
+ FT_FRAME_SHORT( characterWidth ),
+ FT_FRAME_SHORT( ascent ),
+ FT_FRAME_SHORT( descent ),
+ FT_FRAME_SHORT( attributes ),
+ FT_FRAME_END
+ };
+
+
+ static
+ const FT_Frame_Field pcf_compressed_metric_header[] =
+ {
+#undef FT_STRUCTURE
+#define FT_STRUCTURE PCF_Compressed_MetricRec
+
+ FT_FRAME_START( 5 ),
+ FT_FRAME_BYTE( leftSideBearing ),
+ FT_FRAME_BYTE( rightSideBearing ),
+ FT_FRAME_BYTE( characterWidth ),
+ FT_FRAME_BYTE( ascent ),
+ FT_FRAME_BYTE( descent ),
+ FT_FRAME_END
+ };
+
+
+ static FT_Error
+ pcf_get_metric( FT_Stream stream,
+ FT_ULong format,
+ PCF_Metric metric )
+ {
+ FT_Error error = PCF_Err_Ok;
+
+
+ if ( PCF_FORMAT_MATCH( format, PCF_DEFAULT_FORMAT ) )
+ {
+ const FT_Frame_Field* fields;
+
+
+ /* parsing normal metrics */
+ fields = PCF_BYTE_ORDER( format ) == MSBFirst
+ ? pcf_metric_msb_header
+ : pcf_metric_header;
+
+ /* the following sets 'error' but doesn't return in case of failure */
+ (void)FT_STREAM_READ_FIELDS( fields, metric );
+ }
+ else
+ {
+ PCF_Compressed_MetricRec compr;
+
+
+ /* parsing compressed metrics */
+ if ( FT_STREAM_READ_FIELDS( pcf_compressed_metric_header, &compr ) )
+ goto Exit;
+
+ metric->leftSideBearing = (FT_Short)( compr.leftSideBearing - 0x80 );
+ metric->rightSideBearing = (FT_Short)( compr.rightSideBearing - 0x80 );
+ metric->characterWidth = (FT_Short)( compr.characterWidth - 0x80 );
+ metric->ascent = (FT_Short)( compr.ascent - 0x80 );
+ metric->descent = (FT_Short)( compr.descent - 0x80 );
+ metric->attributes = 0;
+ }
+
+ Exit:
+ return error;
+ }
+
+
+ static FT_Error
+ pcf_seek_to_table_type( FT_Stream stream,
+ PCF_Table tables,
+ FT_Int ntables,
+ FT_ULong type,
+ FT_ULong *aformat,
+ FT_ULong *asize )
+ {
+ FT_Error error = 0;
+ FT_Int i;
+
+
+ for ( i = 0; i < ntables; i++ )
+ if ( tables[i].type == type )
+ {
+ if ( stream->pos > tables[i].offset )
+ return PCF_Err_Invalid_Stream_Skip;
+
+ if ( FT_STREAM_SKIP( tables[i].offset - stream->pos ) )
+ return PCF_Err_Invalid_Stream_Skip;
+
+ *asize = tables[i].size; /* unused - to be removed */
+ *aformat = tables[i].format;
+
+ return PCF_Err_Ok;
+ }
+
+ return PCF_Err_Invalid_File_Format;
+ }
+
+
+ static FT_Bool
+ pcf_has_table_type( PCF_Table tables,
+ FT_Int ntables,
+ FT_ULong type )
+ {
+ FT_Int i;
+
+
+ for ( i = 0; i < ntables; i++ )
+ if ( tables[i].type == type )
+ return TRUE;
+
+ return FALSE;
+ }
+
+
+ static
+ const FT_Frame_Field pcf_property_header[] =
+ {
+#undef FT_STRUCTURE
+#define FT_STRUCTURE PCF_ParsePropertyRec
+
+ FT_FRAME_START( 9 ),
+ FT_FRAME_LONG_LE( name ),
+ FT_FRAME_BYTE ( isString ),
+ FT_FRAME_LONG_LE( value ),
+ FT_FRAME_END
+ };
+
+
+ static
+ const FT_Frame_Field pcf_property_msb_header[] =
+ {
+#undef FT_STRUCTURE
+#define FT_STRUCTURE PCF_ParsePropertyRec
+
+ FT_FRAME_START( 9 ),
+ FT_FRAME_LONG( name ),
+ FT_FRAME_BYTE( isString ),
+ FT_FRAME_LONG( value ),
+ FT_FRAME_END
+ };
+
+
+ static PCF_Property
+ pcf_find_property( PCF_Face face,
+ const FT_String* prop )
+ {
+ PCF_Property properties = face->properties;
+ FT_Bool found = 0;
+ int i;
+
+
+ for ( i = 0 ; i < face->nprops && !found; i++ )
+ {
+ if ( !ft_strcmp( properties[i].name, prop ) )
+ found = 1;
+ }
+
+ if ( found )
+ return properties + i - 1;
+ else
+ return NULL;
+ }
+
+
+ static FT_Error
+ pcf_get_properties( FT_Stream stream,
+ PCF_Face face )
+ {
+ PCF_ParseProperty props = 0;
+ PCF_Property properties = 0;
+ FT_Int nprops, i;
+ FT_ULong format, size;
+ FT_Error error;
+ FT_Memory memory = FT_FACE(face)->memory;
+ FT_ULong string_size;
+ FT_String* strings = 0;
+
+
+ error = pcf_seek_to_table_type( stream,
+ face->toc.tables,
+ face->toc.count,
+ PCF_PROPERTIES,
+ &format,
+ &size );
+ if ( error )
+ goto Bail;
+
+ if ( FT_READ_ULONG_LE( format ) )
+ goto Bail;
+
+ FT_TRACE4(( "get_prop: format = %ld\n", format ));
+
+ if ( !PCF_FORMAT_MATCH( format, PCF_DEFAULT_FORMAT ) )
+ goto Bail;
+
+ if ( PCF_BYTE_ORDER( format ) == MSBFirst )
+ (void)FT_READ_ULONG( nprops );
+ else
+ (void)FT_READ_ULONG_LE( nprops );
+ if ( error )
+ goto Bail;
+
+ FT_TRACE4(( "get_prop: nprop = %d\n", nprops ));
+
+ if ( FT_NEW_ARRAY( props, nprops ) )
+ goto Bail;
+
+ for ( i = 0; i < nprops; i++ )
+ {
+ if ( PCF_BYTE_ORDER( format ) == MSBFirst )
+ {
+ if ( FT_STREAM_READ_FIELDS( pcf_property_msb_header, props + i ) )
+ goto Bail;
+ }
+ else
+ {
+ if ( FT_STREAM_READ_FIELDS( pcf_property_header, props + i ) )
+ goto Bail;
+ }
+ }
+
+ /* pad the property array */
+ /* */
+ /* clever here - nprops is the same as the number of odd-units read, */
+ /* as only isStringProp are odd length (Keith Packard) */
+ /* */
+ if ( nprops & 3 )
+ {
+ i = 4 - ( nprops & 3 );
+ FT_Stream_Skip( stream, i );
+ }
+
+ if ( PCF_BYTE_ORDER( format ) == MSBFirst )
+ (void)FT_READ_ULONG( string_size );
+ else
+ (void)FT_READ_ULONG_LE( string_size );
+ if ( error )
+ goto Bail;
+
+ FT_TRACE4(( "get_prop: string_size = %ld\n", string_size ));
+
+ if ( FT_NEW_ARRAY( strings, string_size ) )
+ goto Bail;
+
+ error = FT_Stream_Read( stream, (FT_Byte*)strings, string_size );
+ if ( error )
+ goto Bail;
+
+ if ( FT_NEW_ARRAY( properties, nprops ) )
+ goto Bail;
+
+ for ( i = 0; i < nprops; i++ )
+ {
+ /* XXX: make atom */
+ if ( FT_NEW_ARRAY( properties[i].name,
+ ft_strlen( strings + props[i].name ) + 1 ) )
+ goto Bail;
+ ft_strcpy( properties[i].name,strings + props[i].name );
+
+ properties[i].isString = props[i].isString;
+
+ if ( props[i].isString )
+ {
+ if ( FT_NEW_ARRAY( properties[i].value.atom,
+ ft_strlen( strings + props[i].value ) + 1 ) )
+ goto Bail;
+ ft_strcpy( properties[i].value.atom, strings + props[i].value );
+ }
+ else
+ properties[i].value.integer = props[i].value;
+ }
+
+ face->properties = properties;
+ face->nprops = nprops;
+
+ FT_FREE( props );
+ FT_FREE( strings );
+
+ return PCF_Err_Ok;
+
+ Bail:
+ FT_FREE( props );
+ FT_FREE( strings );
+
+ return error;
+ }
+
+
+ static FT_Error
+ pcf_get_metrics( FT_Stream stream,
+ PCF_Face face )
+ {
+ FT_Error error = PCF_Err_Ok;
+ FT_Memory memory = FT_FACE(face)->memory;
+ FT_ULong format = 0;
+ FT_ULong size = 0;
+ PCF_Metric metrics = 0;
+ int i;
+ int nmetrics = -1;
+
+
+ error = pcf_seek_to_table_type( stream,
+ face->toc.tables,
+ face->toc.count,
+ PCF_METRICS,
+ &format,
+ &size );
+ if ( error )
+ return error;
+
+ error = FT_READ_ULONG_LE( format );
+
+ if ( !PCF_FORMAT_MATCH( format, PCF_DEFAULT_FORMAT ) &&
+ !PCF_FORMAT_MATCH( format, PCF_COMPRESSED_METRICS ) )
+ return PCF_Err_Invalid_File_Format;
+
+ if ( PCF_FORMAT_MATCH( format, PCF_DEFAULT_FORMAT ) )
+ {
+ if ( PCF_BYTE_ORDER( format ) == MSBFirst )
+ (void)FT_READ_ULONG( nmetrics );
+ else
+ (void)FT_READ_ULONG_LE( nmetrics );
+ }
+ else
+ {
+ if ( PCF_BYTE_ORDER( format ) == MSBFirst )
+ (void)FT_READ_USHORT( nmetrics );
+ else
+ (void)FT_READ_USHORT_LE( nmetrics );
+ }
+ if ( error || nmetrics == -1 )
+ return PCF_Err_Invalid_File_Format;
+
+ face->nmetrics = nmetrics;
+
+ if ( FT_NEW_ARRAY( face->metrics, nmetrics ) )
+ return PCF_Err_Out_Of_Memory;
+
+ metrics = face->metrics;
+ for ( i = 0; i < nmetrics; i++ )
+ {
+ pcf_get_metric( stream, format, metrics + i );
+
+ metrics[i].bits = 0;
+
+ FT_TRACE4(( "%d : width=%d, "
+ "lsb=%d, rsb=%d, ascent=%d, descent=%d, swidth=%d\n",
+ i,
+ ( metrics + i )->characterWidth,
+ ( metrics + i )->leftSideBearing,
+ ( metrics + i )->rightSideBearing,
+ ( metrics + i )->ascent,
+ ( metrics + i )->descent,
+ ( metrics + i )->attributes ));
+
+ if ( error )
+ break;
+ }
+
+ if ( error )
+ FT_FREE( face->metrics );
+ return error;
+ }
+
+
+ static FT_Error
+ pcf_get_bitmaps( FT_Stream stream,
+ PCF_Face face )
+ {
+ FT_Error error = PCF_Err_Ok;
+ FT_Memory memory = FT_FACE(face)->memory;
+ FT_Long* offsets;
+ FT_Long bitmapSizes[GLYPHPADOPTIONS];
+ FT_ULong format, size;
+ int nbitmaps, i, sizebitmaps = 0;
+ char* bitmaps;
+
+
+ error = pcf_seek_to_table_type( stream,
+ face->toc.tables,
+ face->toc.count,
+ PCF_BITMAPS,
+ &format,
+ &size );
+ if ( error )
+ return error;
+
+ error = FT_Stream_EnterFrame( stream, 8 );
+ if ( error )
+ return error;
+
+ format = FT_GET_ULONG_LE();
+ if ( PCF_BYTE_ORDER( format ) == MSBFirst )
+ nbitmaps = FT_GET_ULONG();
+ else
+ nbitmaps = FT_GET_ULONG_LE();
+
+ FT_Stream_ExitFrame( stream );
+
+ if ( !PCF_FORMAT_MATCH( format, PCF_DEFAULT_FORMAT ) )
+ return PCF_Err_Invalid_File_Format;
+
+ if ( nbitmaps != face->nmetrics )
+ return PCF_Err_Invalid_File_Format;
+
+ if ( FT_NEW_ARRAY( offsets, nbitmaps ) )
+ return error;
+
+ for ( i = 0; i < nbitmaps; i++ )
+ {
+ if ( PCF_BYTE_ORDER( format ) == MSBFirst )
+ (void)FT_READ_LONG( offsets[i] );
+ else
+ (void)FT_READ_LONG_LE( offsets[i] );
+
+ FT_TRACE4(( "bitmap %d is at offset %ld\n", i, offsets[i] ));
+ }
+ if ( error )
+ goto Bail;
+
+ for ( i = 0; i < GLYPHPADOPTIONS; i++ )
+ {
+ if ( PCF_BYTE_ORDER( format ) == MSBFirst )
+ (void)FT_READ_LONG( bitmapSizes[i] );
+ else
+ (void)FT_READ_LONG_LE( bitmapSizes[i] );
+ if ( error )
+ goto Bail;
+
+ sizebitmaps = bitmapSizes[PCF_GLYPH_PAD_INDEX( format )];
+
+ FT_TRACE4(( "padding %d implies a size of %ld\n", i, bitmapSizes[i] ));
+ }
+
+ FT_TRACE4(( " %d bitmaps, padding index %ld\n",
+ nbitmaps,
+ PCF_GLYPH_PAD_INDEX( format ) ));
+ FT_TRACE4(( "bitmap size = %d\n", sizebitmaps ));
+
+ FT_UNUSED( sizebitmaps ); /* only used for debugging */
+
+ for ( i = 0; i < nbitmaps; i++ )
+ face->metrics[i].bits = stream->pos + offsets[i];
+
+ face->bitmapsFormat = format;
+
+ FT_FREE ( offsets );
+ return error;
+
+ Bail:
+ FT_FREE ( offsets );
+ FT_FREE ( bitmaps );
+ return error;
+ }
+
+
+ static FT_Error
+ pcf_get_encodings( FT_Stream stream,
+ PCF_Face face )
+ {
+ FT_Error error = PCF_Err_Ok;
+ FT_Memory memory = FT_FACE(face)->memory;
+ FT_ULong format, size;
+ int firstCol, lastCol;
+ int firstRow, lastRow;
+ int nencoding, encodingOffset;
+ int i, j;
+ PCF_Encoding tmpEncoding, encoding = 0;
+
+
+ error = pcf_seek_to_table_type( stream,
+ face->toc.tables,
+ face->toc.count,
+ PCF_BDF_ENCODINGS,
+ &format,
+ &size );
+ if ( error )
+ return error;
+
+ error = FT_Stream_EnterFrame( stream, 14 );
+ if ( error )
+ return error;
+
+ format = FT_GET_ULONG_LE();
+
+ if ( PCF_BYTE_ORDER( format ) == MSBFirst )
+ {
+ firstCol = FT_GET_SHORT();
+ lastCol = FT_GET_SHORT();
+ firstRow = FT_GET_SHORT();
+ lastRow = FT_GET_SHORT();
+ face->defaultChar = FT_GET_SHORT();
+ }
+ else
+ {
+ firstCol = FT_GET_SHORT_LE();
+ lastCol = FT_GET_SHORT_LE();
+ firstRow = FT_GET_SHORT_LE();
+ lastRow = FT_GET_SHORT_LE();
+ face->defaultChar = FT_GET_SHORT_LE();
+ }
+
+ FT_Stream_ExitFrame( stream );
+
+ if ( !PCF_FORMAT_MATCH( format, PCF_DEFAULT_FORMAT ) )
+ return PCF_Err_Invalid_File_Format;
+
+ FT_TRACE4(( "enc: firstCol %d, lastCol %d, firstRow %d, lastRow %d\n",
+ firstCol, lastCol, firstRow, lastRow ));
+
+ nencoding = ( lastCol - firstCol + 1 ) * ( lastRow - firstRow + 1 );
+
+ if ( FT_NEW_ARRAY( tmpEncoding, nencoding ) )
+ return PCF_Err_Out_Of_Memory;
+
+ error = FT_Stream_EnterFrame( stream, 2 * nencoding );
+ if ( error )
+ goto Bail;
+
+ for ( i = 0, j = 0 ; i < nencoding; i++ )
+ {
+ if ( PCF_BYTE_ORDER( format ) == MSBFirst )
+ encodingOffset = FT_GET_SHORT();
+ else
+ encodingOffset = FT_GET_SHORT_LE();
+
+ if ( encodingOffset != -1 )
+ {
+ tmpEncoding[j].enc = ( ( ( i / ( lastCol - firstCol + 1 ) ) +
+ firstRow ) * 256 ) +
+ ( ( i % ( lastCol - firstCol + 1 ) ) +
+ firstCol );
+
+ tmpEncoding[j].glyph = (FT_Short)encodingOffset;
+ j++;
+ }
+
+ FT_TRACE4(( "enc n. %d ; Uni %ld ; Glyph %d\n",
+ i, tmpEncoding[j - 1].enc, encodingOffset ));
+ }
+ FT_Stream_ExitFrame( stream );
+
+ if ( FT_NEW_ARRAY( encoding, j ) )
+ goto Bail;
+
+ for ( i = 0; i < j; i++ )
+ {
+ encoding[i].enc = tmpEncoding[i].enc;
+ encoding[i].glyph = tmpEncoding[i].glyph;
+ }
+
+ face->nencodings = j;
+ face->encodings = encoding;
+ FT_FREE( tmpEncoding );
+
+ return error;
+
+ Bail:
+ FT_FREE( encoding );
+ FT_FREE( tmpEncoding );
+ return error;
+ }
+
+
+ static
+ const FT_Frame_Field pcf_accel_header[] =
+ {
+#undef FT_STRUCTURE
+#define FT_STRUCTURE PCF_AccelRec
+
+ FT_FRAME_START( 20 ),
+ FT_FRAME_BYTE ( noOverlap ),
+ FT_FRAME_BYTE ( constantMetrics ),
+ FT_FRAME_BYTE ( terminalFont ),
+ FT_FRAME_BYTE ( constantWidth ),
+ FT_FRAME_BYTE ( inkInside ),
+ FT_FRAME_BYTE ( inkMetrics ),
+ FT_FRAME_BYTE ( drawDirection ),
+ FT_FRAME_SKIP_BYTES( 1 ),
+ FT_FRAME_LONG_LE ( fontAscent ),
+ FT_FRAME_LONG_LE ( fontDescent ),
+ FT_FRAME_LONG_LE ( maxOverlap ),
+ FT_FRAME_END
+ };
+
+
+ static
+ const FT_Frame_Field pcf_accel_msb_header[] =
+ {
+#undef FT_STRUCTURE
+#define FT_STRUCTURE PCF_AccelRec
+
+ FT_FRAME_START( 20 ),
+ FT_FRAME_BYTE ( noOverlap ),
+ FT_FRAME_BYTE ( constantMetrics ),
+ FT_FRAME_BYTE ( terminalFont ),
+ FT_FRAME_BYTE ( constantWidth ),
+ FT_FRAME_BYTE ( inkInside ),
+ FT_FRAME_BYTE ( inkMetrics ),
+ FT_FRAME_BYTE ( drawDirection ),
+ FT_FRAME_SKIP_BYTES( 1 ),
+ FT_FRAME_LONG ( fontAscent ),
+ FT_FRAME_LONG ( fontDescent ),
+ FT_FRAME_LONG ( maxOverlap ),
+ FT_FRAME_END
+ };
+
+
+ static FT_Error
+ pcf_get_accel( FT_Stream stream,
+ PCF_Face face,
+ FT_ULong type )
+ {
+ FT_ULong format, size;
+ FT_Error error = PCF_Err_Ok;
+ PCF_Accel accel = &face->accel;
+
+
+ error = pcf_seek_to_table_type( stream,
+ face->toc.tables,
+ face->toc.count,
+ type,
+ &format,
+ &size );
+ if ( error )
+ goto Bail;
+
+ error = FT_READ_ULONG_LE( format );
+
+ if ( !PCF_FORMAT_MATCH( format, PCF_DEFAULT_FORMAT ) &&
+ !PCF_FORMAT_MATCH( format, PCF_ACCEL_W_INKBOUNDS ) )
+ goto Bail;
+
+ if ( PCF_BYTE_ORDER( format ) == MSBFirst )
+ {
+ if ( FT_STREAM_READ_FIELDS( pcf_accel_msb_header, accel ) )
+ goto Bail;
+ }
+ else
+ {
+ if ( FT_STREAM_READ_FIELDS( pcf_accel_header, accel ) )
+ goto Bail;
+ }
+
+ error = pcf_get_metric( stream,
+ format & ( ~PCF_FORMAT_MASK ),
+ &(accel->minbounds) );
+ if ( error )
+ goto Bail;
+
+ error = pcf_get_metric( stream,
+ format & ( ~PCF_FORMAT_MASK ),
+ &(accel->maxbounds) );
+ if ( error )
+ goto Bail;
+
+ if ( PCF_FORMAT_MATCH( format, PCF_ACCEL_W_INKBOUNDS ) )
+ {
+ error = pcf_get_metric( stream,
+ format & ( ~PCF_FORMAT_MASK ),
+ &(accel->ink_minbounds) );
+ if ( error )
+ goto Bail;
+
+ error = pcf_get_metric( stream,
+ format & ( ~PCF_FORMAT_MASK ),
+ &(accel->ink_maxbounds) );
+ if ( error )
+ goto Bail;
+ }
+ else
+ {
+ accel->ink_minbounds = accel->minbounds; /* I'm not sure about this */
+ accel->ink_maxbounds = accel->maxbounds;
+ }
+ return error;
+
+ Bail:
+ return error;
+ }
+
+
+ FT_LOCAL_DEF( FT_Error )
+ pcf_load_font( FT_Stream stream,
+ PCF_Face face )
+ {
+ FT_Error error = PCF_Err_Ok;
+ FT_Memory memory = FT_FACE(face)->memory;
+ FT_Bool hasBDFAccelerators;
+
+
+ error = pcf_read_TOC( stream, face );
+ if ( error )
+ goto Exit;
+
+ error = pcf_get_properties( stream, face );
+ if ( error )
+ goto Exit;
+
+ /* Use the old accelerators if no BDF accelerators are in the file. */
+ hasBDFAccelerators = pcf_has_table_type( face->toc.tables,
+ face->toc.count,
+ PCF_BDF_ACCELERATORS );
+ if ( !hasBDFAccelerators )
+ {
+ error = pcf_get_accel( stream, face, PCF_ACCELERATORS );
+ if ( error )
+ goto Exit;
+ }
+
+ /* metrics */
+ error = pcf_get_metrics( stream, face );
+ if ( error )
+ goto Exit;
+
+ /* bitmaps */
+ error = pcf_get_bitmaps( stream, face );
+ if ( error )
+ goto Exit;
+
+ /* encodings */
+ error = pcf_get_encodings( stream, face );
+ if ( error )
+ goto Exit;
+
+ /* BDF style accelerators (i.e. bounds based on encoded glyphs) */
+ if ( hasBDFAccelerators )
+ {
+ error = pcf_get_accel( stream, face, PCF_BDF_ACCELERATORS );
+ if ( error )
+ goto Exit;
+ }
+
+ /* XXX: TO DO: inkmetrics and glyph_names are missing */
+
+ /* now construct the face object */
+ {
+ FT_Face root = FT_FACE( face );
+ PCF_Property prop;
+ int size_set = 0;
+
+
+ root->num_faces = 1;
+ root->face_index = 0;
+ root->face_flags = FT_FACE_FLAG_FIXED_SIZES |
+ FT_FACE_FLAG_HORIZONTAL |
+ FT_FACE_FLAG_FAST_GLYPHS;
+
+ if ( face->accel.constantWidth )
+ root->face_flags |= FT_FACE_FLAG_FIXED_WIDTH;
+
+ root->style_flags = 0;
+ prop = pcf_find_property( face, "SLANT" );
+ if ( prop != NULL )
+ if ( prop->isString )
+ if ( ( *(prop->value.atom) == 'O' ) ||
+ ( *(prop->value.atom) == 'I' ) )
+ root->style_flags |= FT_STYLE_FLAG_ITALIC;
+
+ prop = pcf_find_property( face, "WEIGHT_NAME" );
+ if ( prop != NULL )
+ if ( prop->isString )
+ if ( *(prop->value.atom) == 'B' )
+ root->style_flags |= FT_STYLE_FLAG_BOLD;
+
+ root->style_name = (char *)"Regular";
+
+ if ( root->style_flags & FT_STYLE_FLAG_BOLD ) {
+ if ( root->style_flags & FT_STYLE_FLAG_ITALIC )
+ root->style_name = (char *)"Bold Italic";
+ else
+ root->style_name = (char *)"Bold";
+ }
+ else if ( root->style_flags & FT_STYLE_FLAG_ITALIC )
+ root->style_name = (char *)"Italic";
+
+ prop = pcf_find_property( face, "FAMILY_NAME" );
+ if ( prop != NULL )
+ {
+ if ( prop->isString )
+ {
+ int l = ft_strlen( prop->value.atom ) + 1;
+
+
+ if ( FT_NEW_ARRAY( root->family_name, l ) )
+ goto Exit;
+ ft_strcpy( root->family_name, prop->value.atom );
+ }
+ }
+ else
+ root->family_name = 0;
+
+ root->num_glyphs = face->nmetrics;
+
+ root->num_fixed_sizes = 1;
+ if ( FT_NEW_ARRAY( root->available_sizes, 1 ) )
+ goto Exit;
+
+ prop = pcf_find_property( face, "PIXEL_SIZE" );
+ if ( prop != NULL )
+ {
+ root->available_sizes->height =
+ root->available_sizes->width = (FT_Short)( prop->value.integer );
+
+ size_set = 1;
+ }
+ else
+ {
+ prop = pcf_find_property( face, "POINT_SIZE" );
+ if ( prop != NULL )
+ {
+ PCF_Property xres, yres, avgw;
+
+
+ xres = pcf_find_property( face, "RESOLUTION_X" );
+ yres = pcf_find_property( face, "RESOLUTION_Y" );
+ avgw = pcf_find_property( face, "AVERAGE_WIDTH" );
+
+ if ( ( yres != NULL ) && ( xres != NULL ) )
+ {
+ root->available_sizes->height =
+ (FT_Short)( prop->value.integer *
+ yres->value.integer / 720 );
+
+ root->available_sizes->width =
+ (FT_Short)( prop->value.integer *
+ xres->value.integer / 720 );
+
+ size_set = 1;
+ }
+ }
+ }
+
+ if (size_set == 0 )
+ {
+ root->available_sizes->width = 12;
+ root->available_sizes->height = 12;
+ }
+
+ /* set-up charset */
+ {
+ PCF_Property charset_registry = 0, charset_encoding = 0;
+
+
+ charset_registry = pcf_find_property( face, "CHARSET_REGISTRY" );
+ charset_encoding = pcf_find_property( face, "CHARSET_ENCODING" );
+
+ if ( ( charset_registry != NULL ) &&
+ ( charset_encoding != NULL ) )
+ {
+ if ( ( charset_registry->isString ) &&
+ ( charset_encoding->isString ) )
+ {
+ if ( FT_NEW_ARRAY( face->charset_encoding,
+ ft_strlen( charset_encoding->value.atom ) + 1 ) )
+ goto Exit;
+
+ if ( FT_NEW_ARRAY( face->charset_registry,
+ ft_strlen( charset_registry->value.atom ) + 1 ) )
+ goto Exit;
+
+ ft_strcpy( face->charset_registry, charset_registry->value.atom );
+ ft_strcpy( face->charset_encoding, charset_encoding->value.atom );
+ }
+ }
+ }
+ }
+
+ Exit:
+ if ( error )
+ {
+ /* this is done to respect the behaviour of the original */
+ /* PCF font driver. */
+ error = PCF_Err_Invalid_File_Format;
+ }
+
+ return error;
+ }
+
+
+/* END */
--- /dev/null
+++ b/libfreetype/pcfutil.c
@@ -1,0 +1,215 @@
+/*
+
+Copyright 1990, 1994, 1998 The Open Group
+
+All Rights Reserved.
+
+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
+OPEN GROUP 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.
+
+Except as contained in this notice, the name of The Open Group shall not be
+used in advertising or otherwise to promote the sale, use or other dealings
+in this Software without prior written authorization from The Open Group.
+
+*/
+/* $XFree86: xc/lib/font/util/utilbitmap.c,v 1.3 1999/08/22 08:58:58 dawes Exp $ */
+
+/*
+ * Author: Keith Packard, MIT X Consortium
+ */
+
+
+#include <ft2build.h>
+#include "pcfutil.h"
+
+
+ /* Utility functions for reformatting font bitmaps */
+
+ static const unsigned char _reverse_byte[0x100] =
+ {
+ 0x00, 0x80, 0x40, 0xc0, 0x20, 0xa0, 0x60, 0xe0,
+ 0x10, 0x90, 0x50, 0xd0, 0x30, 0xb0, 0x70, 0xf0,
+ 0x08, 0x88, 0x48, 0xc8, 0x28, 0xa8, 0x68, 0xe8,
+ 0x18, 0x98, 0x58, 0xd8, 0x38, 0xb8, 0x78, 0xf8,
+ 0x04, 0x84, 0x44, 0xc4, 0x24, 0xa4, 0x64, 0xe4,
+ 0x14, 0x94, 0x54, 0xd4, 0x34, 0xb4, 0x74, 0xf4,
+ 0x0c, 0x8c, 0x4c, 0xcc, 0x2c, 0xac, 0x6c, 0xec,
+ 0x1c, 0x9c, 0x5c, 0xdc, 0x3c, 0xbc, 0x7c, 0xfc,
+ 0x02, 0x82, 0x42, 0xc2, 0x22, 0xa2, 0x62, 0xe2,
+ 0x12, 0x92, 0x52, 0xd2, 0x32, 0xb2, 0x72, 0xf2,
+ 0x0a, 0x8a, 0x4a, 0xca, 0x2a, 0xaa, 0x6a, 0xea,
+ 0x1a, 0x9a, 0x5a, 0xda, 0x3a, 0xba, 0x7a, 0xfa,
+ 0x06, 0x86, 0x46, 0xc6, 0x26, 0xa6, 0x66, 0xe6,
+ 0x16, 0x96, 0x56, 0xd6, 0x36, 0xb6, 0x76, 0xf6,
+ 0x0e, 0x8e, 0x4e, 0xce, 0x2e, 0xae, 0x6e, 0xee,
+ 0x1e, 0x9e, 0x5e, 0xde, 0x3e, 0xbe, 0x7e, 0xfe,
+ 0x01, 0x81, 0x41, 0xc1, 0x21, 0xa1, 0x61, 0xe1,
+ 0x11, 0x91, 0x51, 0xd1, 0x31, 0xb1, 0x71, 0xf1,
+ 0x09, 0x89, 0x49, 0xc9, 0x29, 0xa9, 0x69, 0xe9,
+ 0x19, 0x99, 0x59, 0xd9, 0x39, 0xb9, 0x79, 0xf9,
+ 0x05, 0x85, 0x45, 0xc5, 0x25, 0xa5, 0x65, 0xe5,
+ 0x15, 0x95, 0x55, 0xd5, 0x35, 0xb5, 0x75, 0xf5,
+ 0x0d, 0x8d, 0x4d, 0xcd, 0x2d, 0xad, 0x6d, 0xed,
+ 0x1d, 0x9d, 0x5d, 0xdd, 0x3d, 0xbd, 0x7d, 0xfd,
+ 0x03, 0x83, 0x43, 0xc3, 0x23, 0xa3, 0x63, 0xe3,
+ 0x13, 0x93, 0x53, 0xd3, 0x33, 0xb3, 0x73, 0xf3,
+ 0x0b, 0x8b, 0x4b, 0xcb, 0x2b, 0xab, 0x6b, 0xeb,
+ 0x1b, 0x9b, 0x5b, 0xdb, 0x3b, 0xbb, 0x7b, 0xfb,
+ 0x07, 0x87, 0x47, 0xc7, 0x27, 0xa7, 0x67, 0xe7,
+ 0x17, 0x97, 0x57, 0xd7, 0x37, 0xb7, 0x77, 0xf7,
+ 0x0f, 0x8f, 0x4f, 0xcf, 0x2f, 0xaf, 0x6f, 0xef,
+ 0x1f, 0x9f, 0x5f, 0xdf, 0x3f, 0xbf, 0x7f, 0xff
+ };
+
+ /*
+ * Invert bit order within each BYTE of an array.
+ */
+
+ void
+ BitOrderInvert( unsigned char* buf,
+ int nbytes )
+ {
+ const unsigned char* rev = _reverse_byte;
+
+
+ for ( ; --nbytes >= 0; buf++ )
+ *buf = rev[*buf];
+ }
+
+
+ /*
+ * Invert byte order within each 16-bits of an array.
+ */
+
+ void
+ TwoByteSwap( unsigned char* buf,
+ int nbytes )
+ {
+ unsigned char c;
+
+
+ for ( ; nbytes > 0; nbytes -= 2, buf += 2 )
+ {
+ c = buf[0];
+ buf[0] = buf[1];
+ buf[1] = c;
+ }
+ }
+
+ /*
+ * Invert byte order within each 32-bits of an array.
+ */
+
+ void
+ FourByteSwap( unsigned char* buf,
+ int nbytes )
+ {
+ unsigned char c;
+
+
+ for ( ; nbytes > 0; nbytes -= 4, buf += 4 )
+ {
+ c = buf[0];
+ buf[0] = buf[3];
+ buf[3] = c;
+
+ c = buf[1];
+ buf[1] = buf[2];
+ buf[2] = c;
+ }
+ }
+
+
+ /*
+ * Repad a bitmap.
+ */
+
+ int
+ RepadBitmap( char* pSrc,
+ char* pDst,
+ unsigned int srcPad,
+ unsigned int dstPad,
+ int width,
+ int height )
+ {
+ int srcWidthBytes, dstWidthBytes;
+ int row, col;
+ char *pTmpSrc, *pTmpDst;
+
+
+ switch ( srcPad )
+ {
+ case 1:
+ srcWidthBytes = ( width + 7 ) >> 3;
+ break;
+
+ case 2:
+ srcWidthBytes = ( ( width + 15 ) >> 4 ) << 1;
+ break;
+
+ case 4:
+ srcWidthBytes = ( ( width + 31 ) >> 5 ) << 2;
+ break;
+
+ case 8:
+ srcWidthBytes = ( ( width + 63 ) >> 6 ) << 3;
+ break;
+
+ default:
+ return 0;
+ }
+
+ switch ( dstPad )
+ {
+ case 1:
+ dstWidthBytes = ( width + 7 ) >> 3;
+ break;
+
+ case 2:
+ dstWidthBytes = ( ( width + 15 ) >> 4 ) << 1;
+ break;
+
+ case 4:
+ dstWidthBytes = ( ( width + 31 ) >> 5 ) << 2;
+ break;
+
+ case 8:
+ dstWidthBytes = ( ( width + 63 ) >> 6 ) << 3;
+ break;
+
+ default:
+ return 0;
+ }
+
+ width = srcWidthBytes;
+ if ( width > dstWidthBytes )
+ width = dstWidthBytes;
+
+ pTmpSrc= pSrc;
+ pTmpDst= pDst;
+
+ for ( row = 0; row < height; row++ )
+ {
+ for ( col = 0; col < width; col++ )
+ *pTmpDst++ = *pTmpSrc++;
+
+ while ( col < dstWidthBytes )
+ {
+ *pTmpDst++ = '\0';
+ col++;
+ }
+ pTmpSrc += srcWidthBytes - width;
+ }
+
+ return dstWidthBytes * height;
+ }
+
+
+/* END */
--- /dev/null
+++ b/libfreetype/pcfutil.h
@@ -1,0 +1,58 @@
+/* pcfutil.h
+
+ FreeType font driver for pcf fonts
+
+ Copyright 2000-2001 by
+ Francesco Zappa Nardelli
+
+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.
+*/
+
+
+#ifndef __PCFUTIL_H__
+#define __PCFUTIL_H__
+
+
+#include <ft2build.h>
+
+
+ void
+ BitOrderInvert( unsigned char* buf,
+ int nbytes);
+
+ void
+ TwoByteSwap( unsigned char* buf,
+ int nbytes);
+
+ void
+ FourByteSwap( unsigned char* buf,
+ int nbytes);
+
+ int
+ RepadBitmap( char* pSrc,
+ char* pDst,
+ unsigned int srcPad,
+ unsigned int dstPad,
+ int width,
+ int height);
+
+#endif /* __PCFUTIL_H__ */
+
+
+/* END */
--- /dev/null
+++ b/libfreetype/pfr.c
@@ -1,0 +1,29 @@
+/***************************************************************************/
+/* */
+/* pfr.c */
+/* */
+/* FreeType PFR driver component. */
+/* */
+/* Copyright 2002 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+#define FT_MAKE_OPTION_SINGLE_OBJECT
+
+#include <ft2build.h>
+
+#include "pfrload.c"
+#include "pfrgload.c"
+#include "pfrcmap.c"
+#include "pfrobjs.c"
+#include "pfrdrivr.c"
+#include "pfrsbit.c"
+
+/* END */
--- /dev/null
+++ b/libfreetype/pfrcmap.c
@@ -1,0 +1,158 @@
+/***************************************************************************/
+/* */
+/* pfrcmap.c */
+/* */
+/* FreeType PFR cmap handling (body). */
+/* */
+/* Copyright 2002 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+
+#include "pfrcmap.h"
+#include "pfrobjs.h"
+#include FT_INTERNAL_DEBUG_H
+
+
+ FT_CALLBACK_DEF( FT_Error )
+ pfr_cmap_init( PFR_CMap cmap )
+ {
+ PFR_Face face = (PFR_Face)FT_CMAP_FACE( cmap );
+
+
+ cmap->num_chars = face->phy_font.num_chars;
+ cmap->chars = face->phy_font.chars;
+
+ /* just for safety, check that the character entries are correctly */
+ /* sorted in increasing character code order */
+ {
+ FT_UInt n;
+
+
+ for ( n = 1; n < cmap->num_chars; n++ )
+ {
+ if ( cmap->chars[n - 1].char_code >= cmap->chars[n].char_code )
+ FT_ASSERT( 0 );
+ }
+ }
+
+ return 0;
+ }
+
+
+ FT_CALLBACK_DEF( void )
+ pfr_cmap_done( PFR_CMap cmap )
+ {
+ cmap->chars = NULL;
+ cmap->num_chars = 0;
+ }
+
+
+ FT_CALLBACK_DEF( FT_UInt )
+ pfr_cmap_char_index( PFR_CMap cmap,
+ FT_UInt32 char_code )
+ {
+ FT_UInt min = 0;
+ FT_UInt max = cmap->num_chars;
+ FT_UInt mid;
+ PFR_Char gchar;
+
+
+ while ( min < max )
+ {
+ mid = min + ( max - min ) / 2;
+ gchar = cmap->chars + mid;
+
+ if ( gchar->char_code == char_code )
+ return mid + 1;
+
+ if ( gchar->char_code < char_code )
+ min = mid + 1;
+ else
+ max = mid;
+ }
+ return 0;
+ }
+
+
+ FT_CALLBACK_DEF( FT_UInt )
+ pfr_cmap_char_next( PFR_CMap cmap,
+ FT_UInt32 *pchar_code )
+ {
+ FT_UInt result = 0;
+ FT_UInt32 char_code = *pchar_code + 1;
+
+
+ Restart:
+ {
+ FT_UInt min = 0;
+ FT_UInt max = cmap->num_chars;
+ FT_UInt mid;
+ PFR_Char gchar;
+
+
+ while ( min < max )
+ {
+ mid = min + ( ( max - min ) >> 1 );
+ gchar = cmap->chars + mid;
+
+ if ( gchar->char_code == char_code )
+ {
+ result = mid;
+ if ( result != 0 )
+ {
+ result++;
+ goto Exit;
+ }
+
+ char_code++;
+ goto Restart;
+ }
+
+ if ( gchar->char_code < char_code )
+ min = mid+1;
+ else
+ max = mid;
+ }
+
+ /* we didn't find it, but we have a pair just above it */
+ char_code = 0;
+
+ if ( min < cmap->num_chars )
+ {
+ gchar = cmap->chars + min;
+ result = min;
+ if ( result != 0 )
+ {
+ result++;
+ char_code = gchar->char_code;
+ }
+ }
+ }
+
+ Exit:
+ *pchar_code = char_code;
+ return result;
+ }
+
+
+ FT_CALLBACK_TABLE_DEF const FT_CMap_ClassRec
+ pfr_cmap_class_rec =
+ {
+ sizeof ( PFR_CMapRec ),
+
+ (FT_CMap_InitFunc) pfr_cmap_init,
+ (FT_CMap_DoneFunc) pfr_cmap_done,
+ (FT_CMap_CharIndexFunc)pfr_cmap_char_index,
+ (FT_CMap_CharNextFunc) pfr_cmap_char_next
+ };
+
+
+/* END */
--- /dev/null
+++ b/libfreetype/pfrcmap.h
@@ -1,0 +1,46 @@
+/***************************************************************************/
+/* */
+/* pfrcmap.h */
+/* */
+/* FreeType PFR cmap handling (specification). */
+/* */
+/* Copyright 2002 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+
+#ifndef __PFRCMAP_H__
+#define __PFRCMAP_H__
+
+#include <ft2build.h>
+#include FT_INTERNAL_OBJECTS_H
+#include "pfrtypes.h"
+
+
+FT_BEGIN_HEADER
+
+ typedef struct PFR_CMapRec_
+ {
+ FT_CMapRec cmap;
+ FT_UInt num_chars;
+ PFR_Char chars;
+
+ } PFR_CMapRec, *PFR_CMap;
+
+
+ FT_CALLBACK_TABLE const FT_CMap_ClassRec pfr_cmap_class_rec;
+
+FT_END_HEADER
+
+
+#endif /* __PFRCMAP_H__ */
+
+
+/* END */
--- /dev/null
+++ b/libfreetype/pfrdrivr.c
@@ -1,0 +1,168 @@
+/***************************************************************************/
+/* */
+/* pfrdrivr.c */
+/* */
+/* FreeType PFR driver interface (body). */
+/* */
+/* Copyright 2002 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+
+#include <ft2build.h>
+#include FT_INTERNAL_DEBUG_H
+#include FT_INTERNAL_STREAM_H
+#include FT_INTERNAL_PFR_H
+#include "pfrdrivr.h"
+#include "pfrobjs.h"
+
+
+ static FT_Error
+ pfr_get_kerning( PFR_Face face,
+ FT_UInt left,
+ FT_UInt right,
+ FT_Vector *avector )
+ {
+ FT_Error error;
+
+ error = pfr_face_get_kerning( face, left, right, avector );
+ if ( !error )
+ {
+ PFR_PhyFont phys = &face->phy_font;
+
+ /* convert from metrics to outline units when necessary */
+ if ( phys->outline_resolution != phys->metrics_resolution )
+ {
+ if ( avector->x != 0 )
+ avector->x = FT_MulDiv( avector->x, phys->outline_resolution,
+ phys->metrics_resolution );
+
+ if ( avector->y != 0 )
+ avector->y = FT_MulDiv( avector->x, phys->outline_resolution,
+ phys->metrics_resolution );
+ }
+ }
+ return error;
+ }
+
+
+ static FT_Error
+ pfr_get_advance( PFR_Face face,
+ FT_UInt gindex,
+ FT_Pos *aadvance )
+ {
+ FT_Error error = FT_Err_Bad_Argument;
+
+ *aadvance = 0;
+ if ( face )
+ {
+ PFR_PhyFont phys = &face->phy_font;
+
+ if ( gindex < phys->num_chars )
+ {
+ *aadvance = phys->chars[ gindex ].advance;
+ error = 0;
+ }
+ }
+
+ return error;
+ }
+
+
+ static FT_Error
+ pfr_get_metrics( PFR_Face face,
+ FT_UInt *aoutline_resolution,
+ FT_UInt *ametrics_resolution,
+ FT_Fixed *ametrics_x_scale,
+ FT_Fixed *ametrics_y_scale )
+ {
+ PFR_PhyFont phys = &face->phy_font;
+ FT_Fixed x_scale, y_scale;
+ FT_Size size = face->root.size;
+
+ if ( aoutline_resolution )
+ *aoutline_resolution = phys->outline_resolution;
+
+ if ( ametrics_resolution )
+ *ametrics_resolution = phys->metrics_resolution;
+
+ x_scale = 0x10000L;
+ y_scale = 0x10000L;
+
+ if ( size )
+ {
+ x_scale = FT_DivFix( size->metrics.x_ppem << 6,
+ phys->metrics_resolution );
+
+ y_scale = FT_DivFix( size->metrics.y_ppem << 6,
+ phys->metrics_resolution );
+ }
+
+ if ( ametrics_x_scale )
+ *ametrics_x_scale = x_scale;
+
+ if ( ametrics_y_scale )
+ *ametrics_y_scale = y_scale;
+
+ return 0;
+ }
+
+
+ FT_CALLBACK_TABLE_DEF
+ const FT_PFR_ServiceRec pfr_service_rec =
+ {
+ (FT_PFR_GetMetricsFunc) pfr_get_metrics,
+ (FT_PFR_GetKerningFunc) pfr_get_kerning,
+ (FT_PFR_GetAdvanceFunc) pfr_get_advance
+ };
+
+
+ FT_CALLBACK_TABLE_DEF
+ const FT_Driver_ClassRec pfr_driver_class =
+ {
+ {
+ ft_module_font_driver |
+ ft_module_driver_scalable,
+
+ sizeof( FT_DriverRec ),
+
+ "pfr",
+ 0x10000L,
+ 0x20000L,
+
+ (FT_PFR_Service) &pfr_service_rec, /* format interface */
+
+ (FT_Module_Constructor)NULL,
+ (FT_Module_Destructor) NULL,
+ (FT_Module_Requester) NULL
+ },
+
+ sizeof( PFR_FaceRec ),
+ sizeof( PFR_SizeRec ),
+ sizeof( PFR_SlotRec ),
+
+ (FT_Face_InitFunc) pfr_face_init,
+ (FT_Face_DoneFunc) pfr_face_done,
+ (FT_Size_InitFunc) NULL,
+ (FT_Size_DoneFunc) NULL,
+ (FT_Slot_InitFunc) pfr_slot_init,
+ (FT_Slot_DoneFunc) pfr_slot_done,
+
+ (FT_Size_ResetPointsFunc) NULL,
+ (FT_Size_ResetPixelsFunc) NULL,
+ (FT_Slot_LoadFunc) pfr_slot_load,
+
+ (FT_Face_GetKerningFunc) pfr_get_kerning,
+ (FT_Face_AttachFunc) 0,
+ (FT_Face_GetAdvancesFunc) 0
+ };
+
+
+/* END */
--- /dev/null
+++ b/libfreetype/pfrdrivr.h
@@ -1,0 +1,39 @@
+/***************************************************************************/
+/* */
+/* pfrdrivr.h */
+/* */
+/* High-level Type PFR driver interface (specification). */
+/* */
+/* Copyright 2002 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+
+#ifndef __PFRDRIVR_H__
+#define __PFRDRIVR_H__
+
+
+#include <ft2build.h>
+#include FT_INTERNAL_DRIVER_H
+
+
+FT_BEGIN_HEADER
+
+
+ FT_EXPORT_VAR( const FT_Driver_ClassRec ) pfr_driver_class;
+
+
+FT_END_HEADER
+
+
+#endif /* __PFRDRIVR_H__ */
+
+
+/* END */
--- /dev/null
+++ b/libfreetype/pfrerror.h
@@ -1,0 +1,40 @@
+/***************************************************************************/
+/* */
+/* pfrerror.h */
+/* */
+/* PFR error codes (specification only). */
+/* */
+/* Copyright 2002 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+
+ /*************************************************************************/
+ /* */
+ /* This file is used to define the PFR error enumeration constants. */
+ /* */
+ /*************************************************************************/
+
+#ifndef __PFRERROR_H__
+#define __PFRERROR_H__
+
+#include FT_MODULE_ERRORS_H
+
+#undef __FTERRORS_H__
+
+#define FT_ERR_PREFIX PFR_Err_
+#define FT_ERR_BASE FT_Mod_Err_PFR
+
+#include FT_ERRORS_H
+
+#endif /* __PFRERROR_H__ */
+
+
+/* END */
--- /dev/null
+++ b/libfreetype/pfrgload.c
@@ -1,0 +1,801 @@
+/***************************************************************************/
+/* */
+/* pfrgload.c */
+/* */
+/* FreeType PFR glyph loader (body). */
+/* */
+/* Copyright 2002 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+
+#include "pfrgload.h"
+#include "pfrsbit.h"
+#include "pfrload.h" /* for macro definitions */
+#include FT_INTERNAL_DEBUG_H
+
+#include "pfrerror.h"
+
+#undef FT_COMPONENT
+#define FT_COMPONENT trace_pfr
+
+
+ /*************************************************************************/
+ /*************************************************************************/
+ /***** *****/
+ /***** PFR GLYPH BUILDER *****/
+ /***** *****/
+ /*************************************************************************/
+ /*************************************************************************/
+
+
+ FT_LOCAL_DEF( void )
+ pfr_glyph_init( PFR_Glyph glyph,
+ FT_GlyphLoader loader )
+ {
+ FT_ZERO( glyph );
+
+ glyph->loader = loader;
+ glyph->path_begun = 0;
+
+ FT_GlyphLoader_Rewind( loader );
+ }
+
+
+ FT_LOCAL_DEF( void )
+ pfr_glyph_done( PFR_Glyph glyph )
+ {
+ FT_Memory memory = glyph->loader->memory;
+
+
+ FT_FREE( glyph->x_control );
+ glyph->y_control = NULL;
+
+ glyph->max_xy_control = 0;
+ glyph->num_x_control = 0;
+ glyph->num_y_control = 0;
+
+ FT_FREE( glyph->subs );
+
+ glyph->max_subs = 0;
+ glyph->num_subs = 0;
+
+ glyph->loader = NULL;
+ glyph->path_begun = 0;
+ }
+
+
+ /* close current contour, if any */
+ static void
+ pfr_glyph_close_contour( PFR_Glyph glyph )
+ {
+ FT_GlyphLoader loader = glyph->loader;
+ FT_Outline* outline = &loader->current.outline;
+ FT_Int last, first;
+
+
+ if ( !glyph->path_begun )
+ return;
+
+ /* compute first and last point indices in current glyph outline */
+ last = outline->n_points - 1;
+ first = 0;
+ if ( outline->n_contours > 0 )
+ first = outline->contours[outline->n_contours - 1];
+
+ /* if the last point falls on the same location than the first one */
+ /* we need to delete it */
+ if ( last > first )
+ {
+ FT_Vector* p1 = outline->points + first;
+ FT_Vector* p2 = outline->points + last;
+
+
+ if ( p1->x == p2->x && p1->y == p2->y )
+ {
+ outline->n_points--;
+ last--;
+ }
+ }
+
+ /* don't add empty contours */
+ if ( last >= first )
+ outline->contours[outline->n_contours++] = (short)last;
+
+ glyph->path_begun = 0;
+ }
+
+
+ /* reset glyph to start the loading of a new glyph */
+ static void
+ pfr_glyph_start( PFR_Glyph glyph )
+ {
+ glyph->path_begun = 0;
+ }
+
+
+ static FT_Error
+ pfr_glyph_line_to( PFR_Glyph glyph,
+ FT_Vector* to )
+ {
+ FT_GlyphLoader loader = glyph->loader;
+ FT_Outline* outline = &loader->current.outline;
+ FT_Error error;
+
+
+ /* check that we have begun a new path */
+ FT_ASSERT( glyph->path_begun != 0 );
+
+ error = FT_GlyphLoader_CheckPoints( loader, 1, 0 );
+ if ( !error )
+ {
+ FT_UInt n = outline->n_points;
+
+
+ outline->points[n] = *to;
+ outline->tags [n] = FT_CURVE_TAG_ON;
+
+ outline->n_points++;
+ }
+
+ return error;
+ }
+
+
+ static FT_Error
+ pfr_glyph_curve_to( PFR_Glyph glyph,
+ FT_Vector* control1,
+ FT_Vector* control2,
+ FT_Vector* to )
+ {
+ FT_GlyphLoader loader = glyph->loader;
+ FT_Outline* outline = &loader->current.outline;
+ FT_Error error;
+
+
+ /* check that we have begun a new path */
+ FT_ASSERT( glyph->path_begun != 0 );
+
+ error = FT_GlyphLoader_CheckPoints( loader, 3, 0 );
+ if ( !error )
+ {
+ FT_Vector* vec = outline->points + outline->n_points;
+ FT_Byte* tag = (FT_Byte*)outline->tags + outline->n_points;
+
+
+ vec[0] = *control1;
+ vec[1] = *control2;
+ vec[2] = *to;
+ tag[0] = FT_CURVE_TAG_CUBIC;
+ tag[1] = FT_CURVE_TAG_CUBIC;
+ tag[2] = FT_CURVE_TAG_ON;
+
+ outline->n_points = (FT_Short)( outline->n_points + 3 );
+ }
+
+ return error;
+ }
+
+
+ static FT_Error
+ pfr_glyph_move_to( PFR_Glyph glyph,
+ FT_Vector* to )
+ {
+ FT_GlyphLoader loader = glyph->loader;
+ FT_Error error;
+
+
+ /* close current contour if any */
+ pfr_glyph_close_contour( glyph );
+
+ /* indicate that a new contour has started */
+ glyph->path_begun = 1;
+
+ /* check that there is room for a new contour and a new point */
+ error = FT_GlyphLoader_CheckPoints( loader, 1, 1 );
+ if ( !error )
+ /* add new start point */
+ error = pfr_glyph_line_to( glyph, to );
+
+ return error;
+ }
+
+
+ static void
+ pfr_glyph_end( PFR_Glyph glyph )
+ {
+ /* close current contour if any */
+ pfr_glyph_close_contour( glyph );
+
+ /* merge the current glyph into the stack */
+ FT_GlyphLoader_Add( glyph->loader );
+ }
+
+
+ /*************************************************************************/
+ /*************************************************************************/
+ /***** *****/
+ /***** PFR GLYPH LOADER *****/
+ /***** *****/
+ /*************************************************************************/
+ /*************************************************************************/
+
+
+ /* load a simple glyph */
+ static FT_Error
+ pfr_glyph_load_simple( PFR_Glyph glyph,
+ FT_Byte* p,
+ FT_Byte* limit )
+ {
+ FT_Error error = 0;
+ FT_Memory memory = glyph->loader->memory;
+ FT_UInt flags, x_count, y_count, i, count, mask;
+ FT_Int x;
+
+
+ PFR_CHECK( 1 );
+ flags = PFR_NEXT_BYTE( p );
+
+ /* test for composite glyphs */
+ FT_ASSERT( ( flags & PFR_GLYPH_IS_COMPOUND ) == 0 );
+
+ x_count = 0;
+ y_count = 0;
+
+ if ( flags & PFR_GLYPH_1BYTE_XYCOUNT )
+ {
+ PFR_CHECK( 1 );
+ count = PFR_NEXT_BYTE( p );
+ x_count = ( count & 15 );
+ y_count = ( count >> 4 );
+ }
+ else
+ {
+ if ( flags & PFR_GLYPH_XCOUNT )
+ {
+ PFR_CHECK( 1 );
+ x_count = PFR_NEXT_BYTE( p );
+ }
+
+ if ( flags & PFR_GLYPH_YCOUNT )
+ {
+ PFR_CHECK( 1 );
+ y_count = PFR_NEXT_BYTE( p );
+ }
+ }
+
+ count = x_count + y_count;
+
+ /* re-allocate array when necessary */
+ if ( count > glyph->max_xy_control )
+ {
+ FT_UInt new_max = ( count + 7 ) & -8;
+
+
+ if ( FT_RENEW_ARRAY( glyph->x_control,
+ glyph->max_xy_control,
+ new_max ) )
+ goto Exit;
+
+ glyph->max_xy_control = new_max;
+ }
+
+ glyph->y_control = glyph->x_control + x_count;
+
+ mask = 0;
+ x = 0;
+
+ for ( i = 0; i < count; i++ )
+ {
+ if ( ( i & 7 ) == 0 )
+ {
+ PFR_CHECK( 1 );
+ mask = PFR_NEXT_BYTE( p );
+ }
+
+ if ( mask & 1 )
+ {
+ PFR_CHECK( 2 );
+ x = PFR_NEXT_SHORT( p );
+ }
+ else
+ {
+ PFR_CHECK( 1 );
+ x += PFR_NEXT_BYTE( p );
+ }
+
+ glyph->x_control[i] = x;
+
+ mask >>= 1;
+ }
+
+ /* XXX: for now we ignore the secondary stroke and edge definitions */
+ /* since we don't want to support native PFR hinting */
+ /* */
+ if ( flags & PFR_GLYPH_EXTRA_ITEMS )
+ {
+ error = pfr_extra_items_skip( &p, limit );
+ if ( error )
+ goto Exit;
+ }
+
+ pfr_glyph_start( glyph );
+
+ /* now load a simple glyph */
+ {
+ FT_Vector pos[4];
+ FT_Vector* cur;
+
+
+ pos[0].x = pos[0].y = 0;
+ pos[3] = pos[0];
+
+ for (;;)
+ {
+ FT_Int format, args_format = 0, args_count, n;
+
+
+ /***************************************************************/
+ /* read instruction */
+ /* */
+ PFR_CHECK( 1 );
+ format = PFR_NEXT_BYTE( p );
+
+ switch ( format >> 4 )
+ {
+ case 0: /* end glyph */
+ FT_TRACE6(( "- end glyph" ));
+ args_count = 0;
+ break;
+
+ case 1: /* general line operation */
+ FT_TRACE6(( "- general line" ));
+ goto Line1;
+
+ case 4: /* move to inside contour */
+ FT_TRACE6(( "- move to inside" ));
+ goto Line1;
+
+ case 5: /* move to outside contour */
+ FT_TRACE6(( "- move to outside" ));
+ Line1:
+ args_format = format & 15;
+ args_count = 1;
+ break;
+
+ case 2: /* horizontal line to */
+ FT_TRACE6(( "- horizontal line to cx.%d", format & 15 ));
+ pos[0].y = pos[3].y;
+ pos[0].x = glyph->x_control[format & 15];
+ pos[3] = pos[0];
+ args_count = 0;
+ break;
+
+ case 3: /* vertical line to */
+ FT_TRACE6(( "- vertical line to cy.%d", format & 15 ));
+ pos[0].x = pos[3].x;
+ pos[0].y = glyph->y_control[format & 15];
+ pos[3] = pos[0];
+ args_count = 0;
+ break;
+
+ case 6: /* horizontal to vertical curve */
+ FT_TRACE6(( "- hv curve " ));
+ args_format = 0xB8E;
+ args_count = 3;
+ break;
+
+ case 7: /* vertical to horizontal curve */
+ FT_TRACE6(( "- vh curve" ));
+ args_format = 0xE2B;
+ args_count = 3;
+ break;
+
+ default: /* general curve to */
+ FT_TRACE6(( "- general curve" ));
+ args_count = 4;
+ args_format = format & 15;
+ }
+
+ /***********************************************************/
+ /* now read arguments */
+ /* */
+ cur = pos;
+ for ( n = 0; n < args_count; n++ )
+ {
+ FT_Int idx, delta;
+
+
+ /* read the X argument */
+ switch ( args_format & 3 )
+ {
+ case 0: /* 8-bit index */
+ PFR_CHECK( 1 );
+ idx = PFR_NEXT_BYTE( p );
+ cur->x = glyph->x_control[idx];
+ FT_TRACE7(( " cx#%d", idx ));
+ break;
+
+ case 1: /* 16-bit value */
+ PFR_CHECK( 2 );
+ cur->x = PFR_NEXT_SHORT( p );
+ FT_TRACE7(( " x.%d", cur->x ));
+ break;
+
+ case 2: /* 8-bit delta */
+ PFR_CHECK( 1 );
+ delta = PFR_NEXT_INT8( p );
+ cur->x = pos[3].x + delta;
+ FT_TRACE7(( " dx.%d", delta ));
+ break;
+
+ default:
+ FT_TRACE7(( " |" ));
+ cur->x = pos[3].x;
+ }
+
+ /* read the Y argument */
+ switch ( ( args_format >> 2 ) & 3 )
+ {
+ case 0: /* 8-bit index */
+ PFR_CHECK( 1 );
+ idx = PFR_NEXT_BYTE( p );
+ cur->y = glyph->y_control[idx];
+ FT_TRACE7(( " cy#%d", idx ));
+ break;
+
+ case 1: /* 16-bit absolute value */
+ PFR_CHECK( 2 );
+ cur->y = PFR_NEXT_SHORT( p );
+ FT_TRACE7(( " y.%d", cur->y ));
+ break;
+
+ case 2: /* 8-bit delta */
+ PFR_CHECK( 1 );
+ delta = PFR_NEXT_INT8( p );
+ cur->y = pos[3].y + delta;
+ FT_TRACE7(( " dy.%d", delta ));
+ break;
+
+ default:
+ FT_TRACE7(( " -" ));
+ cur->y = pos[3].y;
+ }
+
+ /* read the additional format flag for the general curve */
+ if ( n == 0 && args_count == 4 )
+ {
+ PFR_CHECK( 1 );
+ args_format = PFR_NEXT_BYTE( p );
+ args_count--;
+ }
+ else
+ args_format >>= 4;
+
+ /* save the previous point */
+ pos[3] = cur[0];
+ cur++;
+ }
+
+ FT_TRACE7(( "\n" ));
+
+ /***********************************************************/
+ /* finally, execute instruction */
+ /* */
+ switch ( format >> 4 )
+ {
+ case 0: /* end glyph => EXIT */
+ pfr_glyph_end( glyph );
+ goto Exit;
+
+ case 1: /* line operations */
+ case 2:
+ case 3:
+ error = pfr_glyph_line_to( glyph, pos );
+ goto Test_Error;
+
+ case 4: /* move to inside contour */
+ case 5: /* move to outside contour */
+ error = pfr_glyph_move_to( glyph, pos );
+ goto Test_Error;
+
+ default: /* curve operations */
+ error = pfr_glyph_curve_to( glyph, pos, pos + 1, pos + 2 );
+
+ Test_Error: /* test error condition */
+ if ( error )
+ goto Exit;
+ }
+ } /* for (;;) */
+ }
+
+ Exit:
+ return error;
+
+ Too_Short:
+ error = PFR_Err_Invalid_Table;
+ FT_ERROR(( "pfr_glyph_load_simple: invalid glyph data\n" ));
+ goto Exit;
+ }
+
+
+ /* load a composite/compound glyph */
+ static FT_Error
+ pfr_glyph_load_compound( PFR_Glyph glyph,
+ FT_Byte* p,
+ FT_Byte* limit )
+ {
+ FT_Error error = 0;
+ FT_GlyphLoader loader = glyph->loader;
+ FT_Memory memory = loader->memory;
+ PFR_SubGlyph subglyph;
+ FT_UInt flags, i, count, org_count;
+ FT_Int x_pos, y_pos;
+
+
+ PFR_CHECK( 1 );
+ flags = PFR_NEXT_BYTE( p );
+
+ /* test for composite glyphs */
+ FT_ASSERT( ( flags & PFR_GLYPH_IS_COMPOUND ) != 0 );
+
+ count = flags & 0x3F;
+
+ /* ignore extra items when present */
+ /* */
+ if ( flags & PFR_GLYPH_EXTRA_ITEMS )
+ {
+ error = pfr_extra_items_skip( &p, limit );
+ if (error) goto Exit;
+ }
+
+ /* we can't rely on the FT_GlyphLoader to load sub-glyphs, because */
+ /* the PFR format is dumb, using direct file offsets to point to the */
+ /* sub-glyphs (instead of glyph indices). Sigh. */
+ /* */
+ /* For now, we load the list of sub-glyphs into a different array */
+ /* but this will prevent us from using the auto-hinter at its best */
+ /* quality. */
+ /* */
+ org_count = glyph->num_subs;
+
+ if ( org_count + count > glyph->max_subs )
+ {
+ FT_UInt new_max = ( org_count + count + 3 ) & -4;
+
+
+ if ( FT_RENEW_ARRAY( glyph->subs, glyph->max_subs, new_max ) )
+ goto Exit;
+
+ glyph->max_subs = new_max;
+ }
+
+ subglyph = glyph->subs + org_count;
+
+ for ( i = 0; i < count; i++, subglyph++ )
+ {
+ FT_UInt format;
+
+
+ x_pos = 0;
+ y_pos = 0;
+
+ PFR_CHECK( 1 );
+ format = PFR_NEXT_BYTE( p );
+
+ /* read scale when available */
+ subglyph->x_scale = 0x10000L;
+ if ( format & PFR_SUBGLYPH_XSCALE )
+ {
+ PFR_CHECK( 2 );
+ subglyph->x_scale = PFR_NEXT_SHORT( p ) << 4;
+ }
+
+ subglyph->y_scale = 0x10000L;
+ if ( format & PFR_SUBGLYPH_YSCALE )
+ {
+ PFR_CHECK( 2 );
+ subglyph->y_scale = PFR_NEXT_SHORT( p ) << 4;
+ }
+
+ /* read offset */
+ switch ( format & 3 )
+ {
+ case 1:
+ PFR_CHECK( 2 );
+ x_pos = PFR_NEXT_SHORT( p );
+ break;
+
+ case 2:
+ PFR_CHECK( 1 );
+ x_pos += PFR_NEXT_INT8( p );
+ break;
+
+ default:
+ ;
+ }
+
+ switch ( ( format >> 2 ) & 3 )
+ {
+ case 1:
+ PFR_CHECK( 2 );
+ y_pos = PFR_NEXT_SHORT( p );
+ break;
+
+ case 2:
+ PFR_CHECK( 1 );
+ y_pos += PFR_NEXT_INT8( p );
+ break;
+
+ default:
+ ;
+ }
+
+ subglyph->x_delta = x_pos;
+ subglyph->y_delta = y_pos;
+
+ /* read glyph position and size now */
+ if ( format & PFR_SUBGLYPH_2BYTE_SIZE )
+ {
+ PFR_CHECK( 2 );
+ subglyph->gps_size = PFR_NEXT_USHORT( p );
+ }
+ else
+ {
+ PFR_CHECK( 1 );
+ subglyph->gps_size = PFR_NEXT_BYTE( p );
+ }
+
+ if ( format & PFR_SUBGLYPH_3BYTE_OFFSET )
+ {
+ PFR_CHECK( 3 );
+ subglyph->gps_offset = PFR_NEXT_LONG( p );
+ }
+ else
+ {
+ PFR_CHECK( 2 );
+ subglyph->gps_offset = PFR_NEXT_USHORT( p );
+ }
+
+ glyph->num_subs++;
+ }
+
+ Exit:
+ return error;
+
+ Too_Short:
+ error = PFR_Err_Invalid_Table;
+ FT_ERROR(( "pfr_glyph_load_compound: invalid glyph data\n" ));
+ goto Exit;
+ }
+
+
+
+
+
+ static FT_Error
+ pfr_glyph_load_rec( PFR_Glyph glyph,
+ FT_Stream stream,
+ FT_ULong gps_offset,
+ FT_ULong offset,
+ FT_ULong size )
+ {
+ FT_Error error;
+ FT_Byte* p;
+ FT_Byte* limit;
+
+
+ if ( FT_STREAM_SEEK( gps_offset + offset ) ||
+ FT_FRAME_ENTER( size ) )
+ goto Exit;
+
+ p = (FT_Byte*)stream->cursor;
+ limit = p + size;
+
+ if ( size > 0 && *p & PFR_GLYPH_IS_COMPOUND )
+ {
+ FT_Int n, old_count, count;
+ FT_GlyphLoader loader = glyph->loader;
+ FT_Outline* base = &loader->base.outline;
+
+
+ old_count = glyph->num_subs;
+
+ /* this is a compound glyph - load it */
+ error = pfr_glyph_load_compound( glyph, p, limit );
+
+ FT_FRAME_EXIT();
+
+ if ( error )
+ goto Exit;
+
+ count = glyph->num_subs - old_count;
+
+ /* now, load each individual glyph */
+ for ( n = 0; n < count; n++ )
+ {
+ FT_Int i, old_points, num_points;
+ PFR_SubGlyph subglyph;
+
+
+ subglyph = glyph->subs + old_count + n;
+ old_points = base->n_points;
+
+ error = pfr_glyph_load_rec( glyph, stream, gps_offset,
+ subglyph->gps_offset,
+ subglyph->gps_size );
+ if ( error )
+ goto Exit;
+
+ /* note that `glyph->subs' might have been re-allocated */
+ subglyph = glyph->subs + old_count + n;
+ num_points = base->n_points - old_points;
+
+ /* translate and eventually scale the new glyph points */
+ if ( subglyph->x_scale != 0x10000L || subglyph->y_scale != 0x10000L )
+ {
+ FT_Vector* vec = base->points + old_points;
+
+
+ for ( i = 0; i < num_points; i++, vec++ )
+ {
+ vec->x = FT_MulFix( vec->x, subglyph->x_scale ) +
+ subglyph->x_delta;
+ vec->y = FT_MulFix( vec->y, subglyph->y_scale ) +
+ subglyph->y_delta;
+ }
+ }
+ else
+ {
+ FT_Vector* vec = loader->base.outline.points + old_points;
+
+
+ for ( i = 0; i < num_points; i++, vec++ )
+ {
+ vec->x += subglyph->x_delta;
+ vec->y += subglyph->y_delta;
+ }
+ }
+
+ /* proceed to next sub-glyph */
+ }
+ }
+ else
+ {
+ /* load a simple glyph */
+ error = pfr_glyph_load_simple( glyph, p, limit );
+
+ FT_FRAME_EXIT();
+ }
+
+ Exit:
+ return error;
+ }
+
+
+
+
+
+ FT_LOCAL_DEF( FT_Error )
+ pfr_glyph_load( PFR_Glyph glyph,
+ FT_Stream stream,
+ FT_ULong gps_offset,
+ FT_ULong offset,
+ FT_ULong size )
+ {
+ /* initialize glyph loader */
+ FT_GlyphLoader_Rewind( glyph->loader );
+
+ /* load the glyph, recursively when needed */
+ return pfr_glyph_load_rec( glyph, stream, gps_offset, offset, size );
+ }
+
+
+/* END */
--- /dev/null
+++ b/libfreetype/pfrgload.h
@@ -1,0 +1,49 @@
+/***************************************************************************/
+/* */
+/* pfrgload.h */
+/* */
+/* FreeType PFR glyph loader (specification). */
+/* */
+/* Copyright 2002 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+
+#ifndef __PFRGLOAD_H__
+#define __PFRGLOAD_H__
+
+#include "pfrtypes.h"
+
+FT_BEGIN_HEADER
+
+
+ FT_LOCAL( void )
+ pfr_glyph_init( PFR_Glyph glyph,
+ FT_GlyphLoader loader );
+
+ FT_LOCAL( void )
+ pfr_glyph_done( PFR_Glyph glyph );
+
+
+ FT_LOCAL( FT_Error )
+ pfr_glyph_load( PFR_Glyph glyph,
+ FT_Stream stream,
+ FT_ULong gps_offset,
+ FT_ULong offset,
+ FT_ULong size );
+
+
+FT_END_HEADER
+
+
+#endif /* __PFRGLOAD_H__ */
+
+
+/* END */
--- /dev/null
+++ b/libfreetype/pfrload.c
@@ -1,0 +1,901 @@
+/***************************************************************************/
+/* */
+/* pfrload.c */
+/* */
+/* FreeType PFR loader (body). */
+/* */
+/* Copyright 2002 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+
+#include "pfrload.h"
+#include FT_INTERNAL_DEBUG_H
+#include FT_INTERNAL_STREAM_H
+
+#include "pfrerror.h"
+
+#undef FT_COMPONENT
+#define FT_COMPONENT trace_pfr
+
+
+ /*************************************************************************/
+ /*************************************************************************/
+ /***** *****/
+ /***** EXTRA ITEMS *****/
+ /***** *****/
+ /*************************************************************************/
+ /*************************************************************************/
+
+
+ FT_LOCAL_DEF( FT_Error )
+ pfr_extra_items_skip( FT_Byte* *pp,
+ FT_Byte* limit )
+ {
+ return pfr_extra_items_parse( pp, limit, NULL, NULL );
+ }
+
+
+ FT_LOCAL_DEF( FT_Error )
+ pfr_extra_items_parse( FT_Byte* *pp,
+ FT_Byte* limit,
+ PFR_ExtraItem item_list,
+ FT_Pointer item_data )
+ {
+ FT_Error error = 0;
+ FT_Byte* p = *pp;
+ FT_UInt num_items, item_type, item_size;
+
+
+ PFR_CHECK( 1 );
+ num_items = PFR_NEXT_BYTE( p );
+
+ for ( ; num_items > 0; num_items-- )
+ {
+ PFR_CHECK( 2 );
+ item_size = PFR_NEXT_BYTE( p );
+ item_type = PFR_NEXT_BYTE( p );
+
+ PFR_CHECK( item_size );
+
+ if ( item_list )
+ {
+ PFR_ExtraItem extra = item_list;
+
+
+ for ( extra = item_list; extra->parser != NULL; extra++ )
+ {
+ if ( extra->type == item_type )
+ {
+ error = extra->parser( p, p + item_size, item_data );
+ if ( error ) goto Exit;
+
+ break;
+ }
+ }
+ }
+
+ p += item_size;
+ }
+
+ Exit:
+ *pp = p;
+ return error;
+
+ Too_Short:
+ FT_ERROR(( "pfr_extra_items_parse: invalid extra items table\n" ));
+ error = PFR_Err_Invalid_Table;
+ goto Exit;
+ }
+
+
+ /*************************************************************************/
+ /*************************************************************************/
+ /***** *****/
+ /***** PFR HEADER *****/
+ /***** *****/
+ /*************************************************************************/
+ /*************************************************************************/
+
+ static const FT_Frame_Field pfr_header_fields[] =
+ {
+#undef FT_STRUCTURE
+#define FT_STRUCTURE PFR_HeaderRec
+
+ FT_FRAME_START( 58 ),
+ FT_FRAME_ULONG ( signature ),
+ FT_FRAME_USHORT( version ),
+ FT_FRAME_USHORT( signature2 ),
+ FT_FRAME_USHORT( header_size ),
+
+ FT_FRAME_USHORT( log_dir_size ),
+ FT_FRAME_USHORT( log_dir_offset ),
+
+ FT_FRAME_USHORT( log_font_max_size ),
+ FT_FRAME_UOFF3 ( log_font_section_size ),
+ FT_FRAME_UOFF3 ( log_font_section_offset ),
+
+ FT_FRAME_USHORT( phy_font_max_size ),
+ FT_FRAME_UOFF3 ( phy_font_section_size ),
+ FT_FRAME_UOFF3 ( phy_font_section_offset ),
+
+ FT_FRAME_USHORT( gps_max_size ),
+ FT_FRAME_UOFF3 ( gps_section_size ),
+ FT_FRAME_UOFF3 ( gps_section_offset ),
+
+ FT_FRAME_BYTE ( max_blue_values ),
+ FT_FRAME_BYTE ( max_x_orus ),
+ FT_FRAME_BYTE ( max_y_orus ),
+
+ FT_FRAME_BYTE ( phy_font_max_size_high ),
+ FT_FRAME_BYTE ( color_flags ),
+
+ FT_FRAME_UOFF3 ( bct_max_size ),
+ FT_FRAME_UOFF3 ( bct_set_max_size ),
+ FT_FRAME_UOFF3 ( phy_bct_set_max_size ),
+
+ FT_FRAME_USHORT( num_phy_fonts ),
+ FT_FRAME_BYTE ( max_vert_stem_snap ),
+ FT_FRAME_BYTE ( max_horz_stem_snap ),
+ FT_FRAME_USHORT( max_chars ),
+ FT_FRAME_END
+ };
+
+
+ FT_LOCAL_DEF( FT_Error )
+ pfr_header_load( PFR_Header header,
+ FT_Stream stream )
+ {
+ FT_Error error;
+
+
+ /* read header directly */
+ if ( !FT_STREAM_SEEK( 0 ) &&
+ !FT_STREAM_READ_FIELDS( pfr_header_fields, header ) )
+ {
+ /* make a few adjustments to the header */
+ header->phy_font_max_size +=
+ (FT_UInt32)header->phy_font_max_size_high << 16;
+ }
+
+ return error;
+ }
+
+
+ FT_LOCAL_DEF( FT_Bool )
+ pfr_header_check( PFR_Header header )
+ {
+ FT_Bool result = 1;
+
+
+ /* check signature and header size */
+ if ( header->signature != 0x50465230L || /* "PFR0" */
+ header->version > 4 ||
+ header->header_size < 58 ||
+ header->signature2 != 0x0d0a ) /* CR/LF */
+ {
+ result = 0;
+ }
+ return result;
+ }
+
+
+ /***********************************************************************/
+ /***********************************************************************/
+ /***** *****/
+ /***** PFR LOGICAL FONTS *****/
+ /***** *****/
+ /***********************************************************************/
+ /***********************************************************************/
+
+
+ FT_LOCAL_DEF( FT_Error )
+ pfr_log_font_count( FT_Stream stream,
+ FT_UInt32 section_offset,
+ FT_UInt *acount )
+ {
+ FT_Error error;
+ FT_UInt count;
+ FT_UInt result = 0;
+
+
+ if ( FT_STREAM_SEEK( section_offset ) || FT_READ_USHORT( count ) )
+ goto Exit;
+
+ result = count;
+
+ Exit:
+ *acount = result;
+ return error;
+ }
+
+
+ FT_LOCAL_DEF( FT_Error )
+ pfr_log_font_load( PFR_LogFont log_font,
+ FT_Stream stream,
+ FT_UInt idx,
+ FT_UInt32 section_offset,
+ FT_Bool size_increment )
+ {
+ FT_UInt num_log_fonts;
+ FT_UInt flags;
+ FT_UInt32 offset;
+ FT_UInt32 size;
+ FT_Error error;
+
+
+ if ( FT_STREAM_SEEK( section_offset ) ||
+ FT_READ_USHORT( num_log_fonts ) )
+ goto Exit;
+
+ if ( idx >= num_log_fonts )
+ return PFR_Err_Invalid_Argument;
+
+ if ( FT_STREAM_SKIP( idx * 5 ) ||
+ FT_READ_USHORT( size ) ||
+ FT_READ_UOFF3 ( offset ) )
+ goto Exit;
+
+ /* save logical font size and offset */
+ log_font->size = size;
+ log_font->offset = offset;
+
+ /* now, check the rest of the table before loading it */
+ {
+ FT_Byte* p;
+ FT_Byte* limit;
+ FT_UInt local;
+
+
+ if ( FT_STREAM_SEEK( offset ) || FT_FRAME_ENTER( size ) )
+ goto Exit;
+
+ p = stream->cursor;
+ limit = p + size;
+
+ PFR_CHECK(13);
+
+ log_font->matrix[0] = PFR_NEXT_LONG( p );
+ log_font->matrix[1] = PFR_NEXT_LONG( p );
+ log_font->matrix[2] = PFR_NEXT_LONG( p );
+ log_font->matrix[3] = PFR_NEXT_LONG( p );
+
+ flags = PFR_NEXT_BYTE( p );
+
+ local = 0;
+ if ( flags & PFR_LOG_STROKE )
+ {
+ local++;
+ if ( flags & PFR_LOG_2BYTE_STROKE )
+ local++;
+
+ if ( (flags & PFR_LINE_JOIN_MASK) == PFR_LINE_JOIN_MITER )
+ local += 3;
+ }
+ if ( flags & PFR_LOG_BOLD )
+ {
+ local++;
+ if ( flags & PFR_LOG_2BYTE_BOLD )
+ local++;
+ }
+
+ PFR_CHECK( local );
+
+ if ( flags & PFR_LOG_STROKE )
+ {
+ log_font->stroke_thickness = ( flags & PFR_LOG_2BYTE_STROKE )
+ ? PFR_NEXT_SHORT( p )
+ : PFR_NEXT_BYTE( p );
+
+ if ( ( flags & PFR_LINE_JOIN_MASK ) == PFR_LINE_JOIN_MITER )
+ log_font->miter_limit = PFR_NEXT_LONG( p );
+ }
+
+ if ( flags & PFR_LOG_BOLD )
+ {
+ log_font->bold_thickness = ( flags & PFR_LOG_2BYTE_BOLD )
+ ? PFR_NEXT_SHORT( p )
+ : PFR_NEXT_BYTE( p );
+ }
+
+ if ( flags & PFR_LOG_EXTRA_ITEMS )
+ {
+ error = pfr_extra_items_skip( &p, limit );
+ if (error) goto Fail;
+ }
+
+ PFR_CHECK(5);
+ log_font->phys_size = PFR_NEXT_USHORT( p );
+ log_font->phys_offset = PFR_NEXT_ULONG( p );
+ if ( size_increment )
+ {
+ PFR_CHECK( 1 );
+ log_font->phys_size += (FT_UInt32)PFR_NEXT_BYTE( p ) << 16;
+ }
+ }
+
+ Fail:
+ FT_FRAME_EXIT();
+
+ Exit:
+ return error;
+
+ Too_Short:
+ FT_ERROR(( "pfr_log_font_load: invalid logical font table\n" ));
+ error = PFR_Err_Invalid_Table;
+ goto Fail;
+ }
+
+
+ /***********************************************************************/
+ /***********************************************************************/
+ /***** *****/
+ /***** PFR PHYSICAL FONTS *****/
+ /***** *****/
+ /***********************************************************************/
+ /***********************************************************************/
+
+
+ /* load bitmap strikes lists */
+ FT_CALLBACK_DEF( FT_Error )
+ pfr_extra_item_load_bitmap_info( FT_Byte* p,
+ FT_Byte* limit,
+ PFR_PhyFont phy_font )
+ {
+ FT_Memory memory = phy_font->memory;
+ PFR_Strike strike;
+ FT_UInt flags0;
+ FT_UInt n, count, size1;
+ FT_Error error = 0;
+
+
+ PFR_CHECK( 5 );
+
+ p += 3; /* skip bctSize */
+ flags0 = PFR_NEXT_BYTE( p );
+ count = PFR_NEXT_BYTE( p );
+
+ /* re-allocate when needed */
+ if ( phy_font->num_strikes + count > phy_font->max_strikes )
+ {
+ FT_UInt new_max = (phy_font->num_strikes + count + 3) & -4;
+
+ if ( FT_RENEW_ARRAY( phy_font->strikes,
+ phy_font->num_strikes,
+ new_max ) )
+ goto Exit;
+
+ phy_font->max_strikes = new_max;
+ }
+
+ size1 = 1 + 1 + 1 + 2 + 2 + 1;
+ if ( flags0 & PFR_STRIKE_2BYTE_XPPM )
+ size1++;
+
+ if ( flags0 & PFR_STRIKE_2BYTE_YPPM )
+ size1++;
+
+ if ( flags0 & PFR_STRIKE_3BYTE_SIZE )
+ size1++;
+
+ if ( flags0 & PFR_STRIKE_3BYTE_OFFSET )
+ size1++;
+
+ if ( flags0 & PFR_STRIKE_2BYTE_COUNT )
+ size1++;
+
+ strike = phy_font->strikes + phy_font->num_strikes;
+
+ PFR_CHECK( count * size1 );
+
+ for ( n = 0; n < count; n++, strike++ )
+ {
+ strike->x_ppm = ( flags0 & PFR_STRIKE_2BYTE_XPPM )
+ ? PFR_NEXT_USHORT( p )
+ : PFR_NEXT_BYTE( p );
+
+ strike->y_ppm = ( flags0 & PFR_STRIKE_2BYTE_YPPM )
+ ? PFR_NEXT_USHORT( p )
+ : PFR_NEXT_BYTE( p );
+
+ strike->flags = PFR_NEXT_BYTE( p );
+
+ strike->bct_size = ( flags0 & PFR_STRIKE_3BYTE_SIZE )
+ ? PFR_NEXT_ULONG( p )
+ : PFR_NEXT_USHORT( p );
+
+ strike->bct_offset = ( flags0 & PFR_STRIKE_3BYTE_OFFSET )
+ ? PFR_NEXT_ULONG( p )
+ : PFR_NEXT_USHORT( p );
+
+ strike->num_bitmaps = ( flags0 & PFR_STRIKE_2BYTE_COUNT )
+ ? PFR_NEXT_USHORT( p )
+ : PFR_NEXT_BYTE( p );
+ }
+
+ phy_font->num_strikes += count;
+
+ Exit:
+ return error;
+
+ Too_Short:
+ error = PFR_Err_Invalid_Table;
+ FT_ERROR(( "pfr_extra_item_load_bitmap_info: invalid bitmap info table\n" ));
+ goto Exit;
+ }
+
+
+ /* load font ID, i.e. name */
+ FT_CALLBACK_DEF( FT_Error )
+ pfr_extra_item_load_font_id( FT_Byte* p,
+ FT_Byte* limit,
+ PFR_PhyFont phy_font )
+ {
+ FT_Error error = 0;
+ FT_Memory memory = phy_font->memory;
+ FT_UInt len = (FT_UInt)( limit - p );
+
+
+ if ( phy_font->font_id != NULL )
+ goto Exit;
+
+ if ( FT_ALLOC( phy_font->font_id, len+1 ) )
+ goto Exit;
+
+ /* copy font ID name, and terminate it for safety */
+ FT_MEM_COPY( phy_font->font_id, p, len );
+ phy_font->font_id[len] = 0;
+
+ Exit:
+ return error;
+ }
+
+
+ /* load stem snap tables */
+ FT_CALLBACK_DEF( FT_Error )
+ pfr_extra_item_load_stem_snaps( FT_Byte* p,
+ FT_Byte* limit,
+ PFR_PhyFont phy_font )
+ {
+ FT_UInt count, num_vert, num_horz;
+ FT_Int* snaps;
+ FT_Error error = 0;
+ FT_Memory memory = phy_font->memory;
+
+
+ if ( phy_font->vertical.stem_snaps != NULL )
+ goto Exit;
+
+ PFR_CHECK( 1 );
+ count = PFR_NEXT_BYTE( p );
+
+ num_vert = count & 15;
+ num_horz = count >> 4;
+ count = num_vert + num_horz;
+
+ PFR_CHECK( count * 2 );
+
+ if ( FT_NEW_ARRAY( snaps, count ) )
+ goto Exit;
+
+ phy_font->vertical.stem_snaps = snaps;
+ phy_font->horizontal.stem_snaps = snaps + num_vert;
+
+ for ( ; count > 0; count--, snaps++ )
+ *snaps = FT_NEXT_SHORT( p );
+
+ Exit:
+ return error;
+
+ Too_Short:
+ error = PFR_Err_Invalid_Table;
+ FT_ERROR(( "pfr_exta_item_load_stem_snaps: invalid stem snaps table\n" ));
+ goto Exit;
+ }
+
+
+#if 0
+
+ /* load kerning pair data */
+ FT_CALLBACK_DEF( FT_Error )
+ pfr_extra_item_load_kerning_pairs( FT_Byte* p,
+ FT_Byte* limit,
+ PFR_PhyFont phy_font )
+ {
+ FT_Int count;
+ FT_UShort base_adj;
+ FT_UInt flags;
+ FT_UInt num_pairs;
+ PFR_KernPair pairs;
+ FT_Error error = 0;
+ FT_Memory memory = phy_font->memory;
+
+
+ /* allocate a new kerning item */
+ /* XXX: there may be multiple extra items for kerning */
+ if ( phy_font->kern_pairs != NULL )
+ goto Exit;
+
+ FT_TRACE2(( "pfr_extra_item_load_kerning_pairs()\n" ));
+
+ PFR_CHECK( 4 );
+
+ num_pairs = PFR_NEXT_BYTE( p );
+ base_adj = PFR_NEXT_SHORT( p );
+ flags = PFR_NEXT_BYTE( p );
+
+#ifndef PFR_CONFIG_NO_CHECKS
+ count = 3;
+
+ if ( flags & PFR_KERN_2BYTE_CHAR )
+ count += 2;
+
+ if ( flags & PFR_KERN_2BYTE_ADJ )
+ count += 1;
+
+ PFR_CHECK( num_pairs * count );
+#endif
+
+ if ( FT_NEW_ARRAY( pairs, num_pairs ) )
+ goto Exit;
+
+ phy_font->num_kern_pairs = num_pairs;
+ phy_font->kern_pairs = pairs;
+
+ for (count = num_pairs ; count > 0; count--, pairs++ )
+ {
+ if ( flags & PFR_KERN_2BYTE_CHAR )
+ {
+ pairs->glyph1 = PFR_NEXT_USHORT( p );
+ pairs->glyph2 = PFR_NEXT_USHORT( p );
+ }
+ else
+ {
+ pairs->glyph1 = PFR_NEXT_BYTE( p );
+ pairs->glyph2 = PFR_NEXT_BYTE( p );
+ }
+
+ if ( flags & PFR_KERN_2BYTE_ADJ )
+ pairs->kerning.x = base_adj + PFR_NEXT_SHORT( p );
+ else
+ pairs->kerning.x = base_adj + PFR_NEXT_INT8( p );
+
+ pairs->kerning.y = 0;
+
+ FT_TRACE2(( "kerning %d <-> %d : %ld\n",
+ pairs->glyph1, pairs->glyph2, pairs->kerning.x ));
+ }
+
+ Exit:
+ return error;
+
+ Too_Short:
+ error = PFR_Err_Invalid_Table;
+ FT_ERROR(( "pfr_extra_item_load_kerning_pairs: "
+ "invalid kerning pairs table\n" ));
+ goto Exit;
+ }
+
+#else /* 0 */
+
+ /* load kerning pair data */
+ FT_CALLBACK_DEF( FT_Error )
+ pfr_extra_item_load_kerning_pairs( FT_Byte* p,
+ FT_Byte* limit,
+ PFR_PhyFont phy_font )
+ {
+ PFR_KernItem item;
+ FT_Error error = 0;
+ FT_Memory memory = phy_font->memory;
+
+
+ FT_TRACE2(( "pfr_extra_item_load_kerning_pairs()\n" ));
+
+ if ( FT_NEW( item ) )
+ goto Exit;
+
+ PFR_CHECK( 4 );
+
+ item->pair_count = PFR_NEXT_BYTE( p );
+ item->base_adj = PFR_NEXT_SHORT( p );
+ item->flags = PFR_NEXT_BYTE( p );
+ item->offset = phy_font->offset + ( p - phy_font->cursor );
+
+#ifndef PFR_CONFIG_NO_CHECKS
+ item->pair_size = 3;
+
+ if ( item->flags & PFR_KERN_2BYTE_CHAR )
+ item->pair_size += 2;
+
+ if ( item->flags & PFR_KERN_2BYTE_ADJ )
+ item->pair_size += 1;
+
+ PFR_CHECK( item->pair_count * item->pair_size );
+#endif
+
+ /* load first and last pairs into the item to speed up */
+ /* lookup later... */
+ if ( item->pair_count > 0 )
+ {
+ FT_UInt char1, char2;
+ FT_Byte* q;
+
+
+ if ( item->flags & PFR_KERN_2BYTE_CHAR )
+ {
+ q = p;
+ char1 = PFR_NEXT_USHORT( q );
+ char2 = PFR_NEXT_USHORT( q );
+
+ item->pair1 = PFR_KERN_INDEX( char1, char2 );
+
+ q = p + item->pair_size * ( item->pair_count - 1 );
+ char1 = PFR_NEXT_USHORT( q );
+ char2 = PFR_NEXT_USHORT( q );
+
+ item->pair2 = PFR_KERN_INDEX( char1, char2 );
+ }
+ else
+ {
+ q = p;
+ char1 = PFR_NEXT_BYTE( q );
+ char2 = PFR_NEXT_BYTE( q );
+
+ item->pair1 = PFR_KERN_INDEX( char1, char2 );
+
+ q = p + item->pair_size * ( item->pair_count - 1 );
+ char1 = PFR_NEXT_BYTE( q );
+ char2 = PFR_NEXT_BYTE( q );
+
+ item->pair2 = PFR_KERN_INDEX( char1, char2 );
+ }
+
+ /* add new item to the current list */
+ item->next = NULL;
+ *phy_font->kern_items_tail = item;
+ phy_font->kern_items_tail = &item->next;
+ phy_font->num_kern_pairs += item->pair_count;
+ }
+ else
+ {
+ /* empty item! */
+ FT_FREE( item );
+ }
+
+ Exit:
+ return error;
+
+ Too_Short:
+ FT_FREE( item );
+
+ error = PFR_Err_Invalid_Table;
+ FT_ERROR(( "pfr_extra_item_load_kerning_pairs: "
+ "invalid kerning pairs table\n" ));
+ goto Exit;
+ }
+#endif /* 0 */
+
+
+ static const PFR_ExtraItemRec pfr_phy_font_extra_items[] =
+ {
+ { 1, (PFR_ExtraItem_ParseFunc) pfr_extra_item_load_bitmap_info },
+ { 2, (PFR_ExtraItem_ParseFunc) pfr_extra_item_load_font_id },
+ { 3, (PFR_ExtraItem_ParseFunc) pfr_extra_item_load_stem_snaps },
+ { 4, (PFR_ExtraItem_ParseFunc) pfr_extra_item_load_kerning_pairs },
+ { 0, NULL }
+ };
+
+
+ FT_LOCAL_DEF( void )
+ pfr_phy_font_done( PFR_PhyFont phy_font,
+ FT_Memory memory )
+ {
+ if ( phy_font->font_id )
+ FT_FREE( phy_font->font_id );
+
+ FT_FREE( phy_font->vertical.stem_snaps );
+ phy_font->vertical.num_stem_snaps = 0;
+
+ phy_font->horizontal.stem_snaps = NULL;
+ phy_font->horizontal.num_stem_snaps = 0;
+
+ FT_FREE( phy_font->strikes );
+ phy_font->num_strikes = 0;
+ phy_font->max_strikes = 0;
+
+ FT_FREE( phy_font->chars );
+ phy_font->num_chars = 0;
+ phy_font->chars_offset = 0;
+
+ FT_FREE( phy_font->blue_values );
+ phy_font->num_blue_values = 0;
+
+ {
+ PFR_KernItem item, next;
+
+
+ item = phy_font->kern_items;
+ while ( item )
+ {
+ next = item->next;
+ FT_FREE( item );
+ item = next;
+ }
+ phy_font->kern_items = NULL;
+ phy_font->kern_items_tail = NULL;
+ }
+
+ phy_font->num_kern_pairs = 0;
+ }
+
+
+ FT_LOCAL_DEF( FT_Error )
+ pfr_phy_font_load( PFR_PhyFont phy_font,
+ FT_Stream stream,
+ FT_UInt32 offset,
+ FT_UInt32 size )
+ {
+ FT_Error error;
+ FT_Memory memory = stream->memory;
+ FT_UInt flags, num_aux;
+ FT_Byte* p;
+ FT_Byte* limit;
+
+
+ phy_font->memory = memory;
+ phy_font->offset = offset;
+
+ phy_font->kern_items = NULL;
+ phy_font->kern_items_tail = &phy_font->kern_items;
+
+ if ( FT_STREAM_SEEK( offset ) || FT_FRAME_ENTER( size ) )
+ goto Exit;
+
+ phy_font->cursor = stream->cursor;
+
+ p = stream->cursor;
+ limit = p + size;
+
+ PFR_CHECK( 15 );
+ phy_font->font_ref_number = PFR_NEXT_USHORT( p );
+ phy_font->outline_resolution = PFR_NEXT_USHORT( p );
+ phy_font->metrics_resolution = PFR_NEXT_USHORT( p );
+ phy_font->bbox.xMin = PFR_NEXT_SHORT( p );
+ phy_font->bbox.yMin = PFR_NEXT_SHORT( p );
+ phy_font->bbox.xMax = PFR_NEXT_SHORT( p );
+ phy_font->bbox.yMax = PFR_NEXT_SHORT( p );
+ phy_font->flags = flags = PFR_NEXT_BYTE( p );
+
+ /* get the standard advance for non-proprotional fonts */
+ if ( !(flags & PFR_PHY_PROPORTIONAL) )
+ {
+ PFR_CHECK( 2 );
+ phy_font->standard_advance = PFR_NEXT_SHORT( p );
+ }
+
+ /* load the extra items when present */
+ if ( flags & PFR_PHY_EXTRA_ITEMS )
+ {
+ error = pfr_extra_items_parse( &p, limit,
+ pfr_phy_font_extra_items, phy_font );
+
+ if ( error )
+ goto Fail;
+ }
+
+ /* skip the aux bytes */
+ PFR_CHECK( 3 );
+ num_aux = PFR_NEXT_ULONG( p );
+
+ PFR_CHECK( num_aux );
+ p += num_aux;
+
+ /* read the blue values */
+ {
+ FT_UInt n, count;
+
+ PFR_CHECK( 1 );
+ phy_font->num_blue_values = count = PFR_NEXT_BYTE( p );
+
+ PFR_CHECK( count * 2 );
+
+ if ( FT_NEW_ARRAY( phy_font->blue_values, count ) )
+ goto Fail;
+
+ for ( n = 0; n < count; n++ )
+ phy_font->blue_values[n] = PFR_NEXT_SHORT( p );
+ }
+
+ PFR_CHECK( 8 );
+ phy_font->blue_fuzz = PFR_NEXT_BYTE( p );
+ phy_font->blue_scale = PFR_NEXT_BYTE( p );
+
+ phy_font->vertical.standard = PFR_NEXT_USHORT( p );
+ phy_font->horizontal.standard = PFR_NEXT_USHORT( p );
+
+ /* read the character descriptors */
+ {
+ FT_UInt n, count, Size;
+
+
+ phy_font->num_chars = count = PFR_NEXT_USHORT( p );
+ phy_font->chars_offset = offset + ( p - stream->cursor );
+
+ if ( FT_NEW_ARRAY( phy_font->chars, count ) )
+ goto Fail;
+
+ Size = 1 + 1 + 2;
+ if ( flags & PFR_PHY_2BYTE_CHARCODE )
+ Size += 1;
+
+ if ( flags & PFR_PHY_PROPORTIONAL )
+ Size += 2;
+
+ if ( flags & PFR_PHY_ASCII_CODE )
+ Size += 1;
+
+ if ( flags & PFR_PHY_2BYTE_GPS_SIZE )
+ Size += 1;
+
+ if ( flags & PFR_PHY_3BYTE_GPS_OFFSET )
+ Size += 1;
+
+ PFR_CHECK( count * Size );
+
+ for ( n = 0; n < count; n++ )
+ {
+ PFR_Char cur = &phy_font->chars[n];
+
+
+ cur->char_code = ( flags & PFR_PHY_2BYTE_CHARCODE )
+ ? PFR_NEXT_USHORT( p )
+ : PFR_NEXT_BYTE( p );
+
+ cur->advance = ( flags & PFR_PHY_PROPORTIONAL )
+ ? PFR_NEXT_SHORT( p )
+ : (FT_Int) phy_font->standard_advance;
+
+#if 0
+ cur->ascii = ( flags & PFR_PHY_ASCII_CODE )
+ ? PFR_NEXT_BYTE( p )
+ : 0;
+#else
+ if ( flags & PFR_PHY_ASCII_CODE )
+ p += 1;
+#endif
+ cur->gps_size = ( flags & PFR_PHY_2BYTE_GPS_SIZE )
+ ? PFR_NEXT_USHORT( p )
+ : PFR_NEXT_BYTE( p );
+
+ cur->gps_offset = ( flags & PFR_PHY_3BYTE_GPS_OFFSET )
+ ? PFR_NEXT_ULONG( p )
+ : PFR_NEXT_USHORT( p );
+ }
+ }
+
+ /* that's it !! */
+ Fail:
+ FT_FRAME_EXIT();
+
+ /* save position of bitmap info */
+ phy_font->bct_offset = FT_STREAM_POS();
+ phy_font->cursor = NULL;
+
+ Exit:
+ return error;
+
+ Too_Short:
+ error = PFR_Err_Invalid_Table;
+ FT_ERROR(( "pfr_phy_font_load: invalid physical font table\n" ));
+ goto Fail;
+ }
+
+
+/* END */
--- /dev/null
+++ b/libfreetype/pfrload.h
@@ -1,0 +1,118 @@
+/***************************************************************************/
+/* */
+/* pfrload.h */
+/* */
+/* FreeType PFR loader (specification). */
+/* */
+/* Copyright 2002 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+
+#ifndef __PFRLOAD_H__
+#define __PFRLOAD_H__
+
+#include "pfrobjs.h"
+#include FT_INTERNAL_STREAM_H
+
+
+FT_BEGIN_HEADER
+
+#ifdef PFR_CONFIG_NO_CHECKS
+#define PFR_CHECK( x ) do { } while ( 0 )
+#else
+#define PFR_CHECK( x ) do \
+ { \
+ if ( p + (x) > limit ) \
+ goto Too_Short; \
+ } while ( 0 )
+#endif
+
+#define PFR_NEXT_BYTE( p ) FT_NEXT_BYTE( p )
+#define PFR_NEXT_INT8( p ) FT_NEXT_CHAR( p )
+#define PFR_NEXT_SHORT( p ) FT_NEXT_SHORT( p )
+#define PFR_NEXT_USHORT( p ) FT_NEXT_USHORT( p )
+#define PFR_NEXT_LONG( p ) FT_NEXT_OFF3( p )
+#define PFR_NEXT_ULONG( p ) FT_NEXT_UOFF3( p )
+
+
+ /* handling extra items */
+
+ typedef FT_Error
+ (*PFR_ExtraItem_ParseFunc)( FT_Byte* p,
+ FT_Byte* limit,
+ FT_Pointer data );
+
+ typedef struct PFR_ExtraItemRec_
+ {
+ FT_UInt type;
+ PFR_ExtraItem_ParseFunc parser;
+
+ } PFR_ExtraItemRec;
+
+ typedef const struct PFR_ExtraItemRec_* PFR_ExtraItem;
+
+
+ FT_LOCAL( FT_Error )
+ pfr_extra_items_skip( FT_Byte* *pp,
+ FT_Byte* limit );
+
+ FT_LOCAL( FT_Error )
+ pfr_extra_items_parse( FT_Byte* *pp,
+ FT_Byte* limit,
+ PFR_ExtraItem item_list,
+ FT_Pointer item_data );
+
+
+ /* load a PFR header */
+ FT_LOCAL( FT_Error )
+ pfr_header_load( PFR_Header header,
+ FT_Stream stream );
+
+ /* check a PFR header */
+ FT_LOCAL( FT_Bool )
+ pfr_header_check( PFR_Header header );
+
+
+ /* return number of logical fonts in this file */
+ FT_LOCAL( FT_Error )
+ pfr_log_font_count( FT_Stream stream,
+ FT_UInt32 log_section_offset,
+ FT_UInt *acount );
+
+ /* load a pfr logical font entry */
+ FT_LOCAL( FT_Error )
+ pfr_log_font_load( PFR_LogFont log_font,
+ FT_Stream stream,
+ FT_UInt face_index,
+ FT_UInt32 section_offset,
+ FT_Bool size_increment );
+
+
+ /* load a physical font entry */
+ FT_LOCAL( FT_Error )
+ pfr_phy_font_load( PFR_PhyFont phy_font,
+ FT_Stream stream,
+ FT_UInt32 offset,
+ FT_UInt32 size );
+
+ /* finalize a physical font */
+ FT_LOCAL( void )
+ pfr_phy_font_done( PFR_PhyFont phy_font,
+ FT_Memory memory );
+
+ /* */
+
+FT_END_HEADER
+
+#endif /* __PFRLOAD_H__ */
+
+
+/* END */
--- /dev/null
+++ b/libfreetype/pfrobjs.c
@@ -1,0 +1,437 @@
+/***************************************************************************/
+/* */
+/* pfrobjs.c */
+/* */
+/* FreeType PFR object methods (body). */
+/* */
+/* Copyright 2002 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+
+#include "pfrobjs.h"
+#include "pfrload.h"
+#include "pfrgload.h"
+#include "pfrcmap.h"
+#include "pfrsbit.h"
+#include FT_OUTLINE_H
+#include FT_INTERNAL_DEBUG_H
+
+#include "pfrerror.h"
+
+#undef FT_COMPONENT
+#define FT_COMPONENT trace_pfr
+
+
+ /*************************************************************************/
+ /*************************************************************************/
+ /***** *****/
+ /***** FACE OBJECT METHODS *****/
+ /***** *****/
+ /*************************************************************************/
+ /*************************************************************************/
+
+ FT_LOCAL_DEF( void )
+ pfr_face_done( PFR_Face face )
+ {
+ /* finalize the physical font record */
+ pfr_phy_font_done( &face->phy_font, FT_FACE_MEMORY( face ) );
+
+ /* no need to finalize the logical font or the header */
+ }
+
+
+ FT_LOCAL_DEF( FT_Error )
+ pfr_face_init( FT_Stream stream,
+ PFR_Face face,
+ FT_Int face_index,
+ FT_Int num_params,
+ FT_Parameter* params )
+ {
+ FT_Error error;
+
+ FT_UNUSED( num_params );
+ FT_UNUSED( params );
+
+
+ /* load the header and check it */
+ error = pfr_header_load( &face->header, stream );
+ if ( error )
+ goto Exit;
+
+ if ( !pfr_header_check( &face->header ) )
+ {
+ FT_TRACE4(( "pfr_face_init: not a valid PFR font\n" ));
+ error = PFR_Err_Unknown_File_Format;
+ goto Exit;
+ }
+
+ /* check face index */
+ {
+ FT_UInt num_faces;
+
+
+ error = pfr_log_font_count( stream,
+ face->header.log_dir_offset,
+ &num_faces );
+ if ( error )
+ goto Exit;
+
+ face->root.num_faces = num_faces;
+ }
+
+ if ( face_index < 0 )
+ goto Exit;
+
+ if ( face_index >= face->root.num_faces )
+ {
+ FT_ERROR(( "pfr_face_init: invalid face index\n" ));
+ error = PFR_Err_Invalid_Argument;
+ goto Exit;
+ }
+
+ /* load the face */
+ error = pfr_log_font_load(
+ &face->log_font, stream, face_index,
+ face->header.log_dir_offset,
+ FT_BOOL( face->header.phy_font_max_size_high != 0 ) );
+ if ( error )
+ goto Exit;
+
+ /* now load the physical font descriptor */
+ error = pfr_phy_font_load( &face->phy_font, stream,
+ face->log_font.phys_offset,
+ face->log_font.phys_size );
+ if ( error )
+ goto Exit;
+
+ /* now, set-up all root face fields */
+ {
+ FT_Face root = FT_FACE( face );
+ PFR_PhyFont phy_font = &face->phy_font;
+
+
+ root->face_index = face_index;
+ root->num_glyphs = phy_font->num_chars;
+ root->face_flags = FT_FACE_FLAG_SCALABLE;
+
+ if ( (phy_font->flags & PFR_PHY_PROPORTIONAL) == 0 )
+ root->face_flags |= FT_FACE_FLAG_FIXED_WIDTH;
+
+ if ( phy_font->flags & PFR_PHY_VERTICAL )
+ root->face_flags |= FT_FACE_FLAG_VERTICAL;
+ else
+ root->face_flags |= FT_FACE_FLAG_HORIZONTAL;
+
+ if ( phy_font->num_strikes > 0 )
+ root->face_flags |= FT_FACE_FLAG_FIXED_SIZES;
+
+ if ( phy_font->num_kern_pairs > 0 )
+ root->face_flags |= FT_FACE_FLAG_KERNING;
+
+ root->family_name = phy_font->font_id;
+ root->style_name = NULL; /* no style name in font file */
+
+ root->num_fixed_sizes = 0;
+ root->available_sizes = 0;
+
+ root->bbox = phy_font->bbox;
+ root->units_per_EM = (FT_UShort)phy_font->outline_resolution;
+ root->ascender = (FT_Short) phy_font->bbox.yMax;
+ root->descender = (FT_Short) phy_font->bbox.yMin;
+ root->height = (FT_Short)
+ ( ( ( root->ascender - root->descender ) * 12 )
+ / 10 );
+
+ /* now compute maximum advance width */
+ if ( ( phy_font->flags & PFR_PHY_PROPORTIONAL ) == 0 )
+ root->max_advance_width = (FT_Short)phy_font->standard_advance;
+ else
+ {
+ FT_Int max = 0;
+ FT_UInt count = phy_font->num_chars;
+ PFR_Char gchar = phy_font->chars;
+
+
+ for ( ; count > 0; count--, gchar++ )
+ {
+ if ( max < gchar->advance )
+ max = gchar->advance;
+ }
+
+ root->max_advance_width = (FT_Short)max;
+ }
+
+ root->max_advance_height = root->height;
+
+ root->underline_position = (FT_Short)( - root->units_per_EM / 10 );
+ root->underline_thickness = (FT_Short)( root->units_per_EM / 30 );
+
+ /* create charmap */
+ {
+ FT_CharMapRec charmap;
+
+
+ charmap.face = root;
+ charmap.platform_id = 3;
+ charmap.encoding_id = 1;
+ charmap.encoding = FT_ENCODING_UNICODE;
+
+ FT_CMap_New( &pfr_cmap_class_rec, NULL, &charmap, NULL );
+
+#if 0
+ /* Select default charmap */
+ if (root->num_charmaps)
+ root->charmap = root->charmaps[0];
+#endif
+ }
+
+ /* check whether we've loaded any kerning pairs */
+ if ( phy_font->num_kern_pairs )
+ root->face_flags |= FT_FACE_FLAG_KERNING;
+ }
+
+ Exit:
+ return error;
+ }
+
+
+ /*************************************************************************/
+ /*************************************************************************/
+ /***** *****/
+ /***** SLOT OBJECT METHOD *****/
+ /***** *****/
+ /*************************************************************************/
+ /*************************************************************************/
+
+ FT_LOCAL_DEF( FT_Error )
+ pfr_slot_init( PFR_Slot slot )
+ {
+ FT_GlyphLoader loader = slot->root.internal->loader;
+
+ pfr_glyph_init( &slot->glyph, loader );
+
+ return 0;
+ }
+
+
+ FT_LOCAL_DEF( void )
+ pfr_slot_done( PFR_Slot slot )
+ {
+ pfr_glyph_done( &slot->glyph );
+ }
+
+
+ FT_LOCAL_DEF( FT_Error )
+ pfr_slot_load( PFR_Slot slot,
+ PFR_Size size,
+ FT_UInt gindex,
+ FT_Int32 load_flags )
+ {
+ FT_Error error;
+ PFR_Face face = (PFR_Face)slot->root.face;
+ PFR_Char gchar;
+ FT_Outline* outline = &slot->root.outline;
+ FT_ULong gps_offset;
+
+ if (gindex > 0)
+ gindex--;
+
+ /* check that the glyph index is correct */
+ FT_ASSERT( gindex < face->phy_font.num_chars );
+
+ /* try to load an embedded bitmap */
+ if ( ( load_flags & ( FT_LOAD_NO_SCALE | FT_LOAD_NO_BITMAP ) ) == 0 )
+ {
+ error = pfr_slot_load_bitmap( slot, size, gindex );
+ if ( error == 0 )
+ goto Exit;
+ }
+
+ gchar = face->phy_font.chars + gindex;
+ slot->root.format = FT_GLYPH_FORMAT_OUTLINE;
+ outline->n_points = 0;
+ outline->n_contours = 0;
+ gps_offset = face->header.gps_section_offset;
+
+ /* load the glyph outline (FT_LOAD_NO_RECURSE isn't supported) */
+ error = pfr_glyph_load( &slot->glyph, face->root.stream,
+ gps_offset, gchar->gps_offset, gchar->gps_size );
+
+ if ( !error )
+ {
+ FT_BBox cbox;
+ FT_Glyph_Metrics* metrics = &slot->root.metrics;
+ FT_Pos advance;
+ FT_Int em_metrics, em_outline;
+ FT_Bool scaling;
+
+
+ scaling = FT_BOOL( ( load_flags & FT_LOAD_NO_SCALE ) == 0 );
+
+ /* copy outline data */
+ *outline = slot->glyph.loader->base.outline;
+
+ outline->flags &= ~FT_OUTLINE_OWNER;
+ outline->flags |= FT_OUTLINE_REVERSE_FILL;
+
+ if ( size && size->root.metrics.y_ppem < 24 )
+ outline->flags |= FT_OUTLINE_HIGH_PRECISION;
+
+ /* compute the advance vector */
+ metrics->horiAdvance = 0;
+ metrics->vertAdvance = 0;
+
+ advance = gchar->advance;
+ em_metrics = face->phy_font.metrics_resolution;
+ em_outline = face->phy_font.outline_resolution;
+
+ if ( em_metrics != em_outline )
+ advance = FT_MulDiv( advance, em_outline, em_metrics );
+
+ if ( face->phy_font.flags & PFR_PHY_VERTICAL )
+ metrics->vertAdvance = advance;
+ else
+ metrics->horiAdvance = advance;
+
+ slot->root.linearHoriAdvance = metrics->horiAdvance;
+ slot->root.linearVertAdvance = metrics->vertAdvance;
+
+ /* make-up vertical metrics(?) */
+ metrics->vertBearingX = 0;
+ metrics->vertBearingY = 0;
+
+ /* scale when needed */
+ if ( scaling )
+ {
+ FT_Int n;
+ FT_Fixed x_scale = size->root.metrics.x_scale;
+ FT_Fixed y_scale = size->root.metrics.y_scale;
+ FT_Vector* vec = outline->points;
+
+
+ /* scale outline points */
+ for ( n = 0; n < outline->n_points; n++, vec++ )
+ {
+ vec->x = FT_MulFix( vec->x, x_scale );
+ vec->y = FT_MulFix( vec->y, y_scale );
+ }
+
+ /* scale the advance */
+ metrics->horiAdvance = FT_MulFix( metrics->horiAdvance, x_scale );
+ metrics->vertAdvance = FT_MulFix( metrics->vertAdvance, y_scale );
+ }
+
+ /* compute the rest of the metrics */
+ FT_Outline_Get_CBox( outline, &cbox );
+
+ metrics->width = cbox.xMax - cbox.xMin;
+ metrics->height = cbox.yMax - cbox.yMin;
+ metrics->horiBearingX = cbox.xMin;
+ metrics->horiBearingY = cbox.yMax - metrics->height;
+ }
+
+ Exit:
+ return error;
+ }
+
+
+ /*************************************************************************/
+ /*************************************************************************/
+ /***** *****/
+ /***** KERNING METHOD *****/
+ /***** *****/
+ /*************************************************************************/
+ /*************************************************************************/
+
+ FT_LOCAL_DEF( FT_Error )
+ pfr_face_get_kerning( PFR_Face face,
+ FT_UInt glyph1,
+ FT_UInt glyph2,
+ FT_Vector* kerning )
+ {
+ FT_Error error;
+ PFR_PhyFont phy_font = &face->phy_font;
+ PFR_KernItem item = phy_font->kern_items;
+ FT_UInt32 idx = PFR_KERN_INDEX( glyph1, glyph2 );
+
+
+ kerning->x = 0;
+ kerning->y = 0;
+
+ /* find the kerning item containing our pair */
+ while ( item )
+ {
+ if ( item->pair1 <= idx && idx <= item->pair2 )
+ goto Found_Item;
+
+ item = item->next;
+ }
+
+ /* not found */
+ goto Exit;
+
+ Found_Item:
+ {
+ /* perform simply binary search within the item */
+ FT_UInt min, mid, max;
+ FT_Stream stream = face->root.stream;
+ FT_Byte* p;
+
+
+ if ( FT_STREAM_SEEK( item->offset ) ||
+ FT_FRAME_ENTER( item->pair_count * item->pair_size ) )
+ goto Exit;
+
+ min = 0;
+ max = item->pair_count;
+ while ( min < max )
+ {
+ FT_UInt char1, char2, charcode;
+
+
+ mid = ( min + max ) >> 1;
+ p = stream->cursor + mid*item->pair_size;
+
+ if ( item->flags & PFR_KERN_2BYTE_CHAR )
+ {
+ char1 = FT_NEXT_USHORT( p );
+ char2 = FT_NEXT_USHORT( p );
+ }
+ else
+ {
+ char1 = FT_NEXT_USHORT( p );
+ char2 = FT_NEXT_USHORT( p );
+ }
+ charcode = PFR_KERN_INDEX( char1, char2 );
+
+ if ( idx == charcode )
+ {
+ if ( item->flags & PFR_KERN_2BYTE_ADJ )
+ kerning->x = item->base_adj + FT_NEXT_SHORT( p );
+ else
+ kerning->x = item->base_adj + FT_NEXT_CHAR( p );
+
+ break;
+ }
+ if ( idx > charcode )
+ min = mid + 1;
+ else
+ max = mid;
+ }
+
+ FT_FRAME_EXIT();
+ }
+
+ Exit:
+ return 0;
+ }
+
+/* END */
--- /dev/null
+++ b/libfreetype/pfrobjs.h
@@ -1,0 +1,96 @@
+/***************************************************************************/
+/* */
+/* pfrobjs.h */
+/* */
+/* FreeType PFR object methods (specification). */
+/* */
+/* Copyright 2002 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+
+#ifndef __PFROBJS_H__
+#define __PFROBJS_H__
+
+#include "pfrtypes.h"
+
+
+FT_BEGIN_HEADER
+
+ typedef struct PFR_FaceRec_* PFR_Face;
+
+ typedef struct PFR_SizeRec_* PFR_Size;
+
+ typedef struct PFR_SlotRec_* PFR_Slot;
+
+
+ typedef struct PFR_FaceRec_
+ {
+ FT_FaceRec root;
+ PFR_HeaderRec header;
+ PFR_LogFontRec log_font;
+ PFR_PhyFontRec phy_font;
+
+ } PFR_FaceRec;
+
+
+ typedef struct PFR_SizeRec_
+ {
+ FT_SizeRec root;
+
+ } PFR_SizeRec;
+
+
+ typedef struct PFR_SlotRec_
+ {
+ FT_GlyphSlotRec root;
+ PFR_GlyphRec glyph;
+
+ } PFR_SlotRec;
+
+
+ FT_LOCAL( FT_Error )
+ pfr_face_init( FT_Stream stream,
+ PFR_Face face,
+ FT_Int face_index,
+ FT_Int num_params,
+ FT_Parameter* params );
+
+ FT_LOCAL( void )
+ pfr_face_done( PFR_Face face );
+
+
+ FT_LOCAL( FT_Error )
+ pfr_face_get_kerning( PFR_Face face,
+ FT_UInt glyph1,
+ FT_UInt glyph2,
+ FT_Vector* kerning );
+
+
+ FT_LOCAL( FT_Error )
+ pfr_slot_init( PFR_Slot slot );
+
+ FT_LOCAL( void )
+ pfr_slot_done( PFR_Slot slot );
+
+
+ FT_LOCAL( FT_Error )
+ pfr_slot_load( PFR_Slot slot,
+ PFR_Size size,
+ FT_UInt gindex,
+ FT_Int32 load_flags );
+
+
+FT_END_HEADER
+
+#endif /* __PFROBJS_H__ */
+
+
+/* END */
--- /dev/null
+++ b/libfreetype/pfrsbit.c
@@ -1,0 +1,670 @@
+/***************************************************************************/
+/* */
+/* pfrsbit.c */
+/* */
+/* FreeType PFR bitmap loader (body). */
+/* */
+/* Copyright 2002 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+
+#include "pfrsbit.h"
+#include "pfrload.h"
+#include FT_INTERNAL_DEBUG_H
+#include FT_INTERNAL_STREAM_H
+
+#include "pfrerror.h"
+
+#undef FT_COMPONENT
+#define FT_COMPONENT trace_pfr
+
+
+ /*************************************************************************/
+ /*************************************************************************/
+ /***** *****/
+ /***** PFR BIT WRITER *****/
+ /***** *****/
+ /*************************************************************************/
+ /*************************************************************************/
+
+ typedef struct PFR_BitWriter_
+ {
+ FT_Byte* line; /* current line start */
+ FT_Int pitch; /* line size in bytes */
+ FT_Int width; /* width in pixels/bits */
+ FT_Int rows; /* number of remaining rows to scan */
+ FT_Int total; /* total number of bits to draw */
+
+ } PFR_BitWriterRec, *PFR_BitWriter;
+
+
+ static void
+ pfr_bitwriter_init( PFR_BitWriter writer,
+ FT_Bitmap* target,
+ FT_Bool decreasing )
+ {
+ writer->line = target->buffer;
+ writer->pitch = target->pitch;
+ writer->width = target->width;
+ writer->rows = target->rows;
+ writer->total = writer->width * writer->rows;
+
+ if ( !decreasing )
+ {
+ writer->line += writer->pitch * ( target->rows-1 );
+ writer->pitch = -writer->pitch;
+ }
+ }
+
+
+ static void
+ pfr_bitwriter_decode_bytes( PFR_BitWriter writer,
+ FT_Byte* p,
+ FT_Byte* limit )
+ {
+ FT_Int n, reload;
+ FT_Int left = writer->width;
+ FT_Byte* cur = writer->line;
+ FT_UInt mask = 0x80;
+ FT_UInt val = 0;
+ FT_UInt c = 0;
+
+
+ n = (FT_Int)( limit - p ) * 8;
+ if ( n > writer->total )
+ n = writer->total;
+
+ reload = n & 7;
+
+ for ( ; n > 0; n-- )
+ {
+ if ( ( n & 7 ) == reload )
+ val = *p++;
+
+ if ( val & 0x80 )
+ c |= mask;
+
+ val <<= 1;
+ mask >>= 1;
+
+ if ( --left <= 0 )
+ {
+ cur[0] = (FT_Byte)c;
+ left = writer->width;
+ mask = 0x80;
+
+ writer->line += writer->pitch;
+ cur = writer->line;
+ c = 0;
+ }
+ else if ( mask == 0 )
+ {
+ cur[0] = c;
+ mask = 0x80;
+ c = 0;
+ cur ++;
+ }
+ }
+
+ if ( mask != 0x80 )
+ cur[0] = c;
+ }
+
+
+ static void
+ pfr_bitwriter_decode_rle1( PFR_BitWriter writer,
+ FT_Byte* p,
+ FT_Byte* limit )
+ {
+ FT_Int n, phase, count, counts[2], reload;
+ FT_Int left = writer->width;
+ FT_Byte* cur = writer->line;
+ FT_UInt mask = 0x80;
+ FT_UInt c = 0;
+
+
+ n = writer->total;
+
+ phase = 1;
+ counts[0] = 0;
+ counts[1] = 0;
+ count = 0;
+ reload = 1;
+
+ for ( ; n > 0; n-- )
+ {
+ if ( reload )
+ {
+ do
+ {
+ if ( phase )
+ {
+ FT_Int v;
+
+
+ if ( p >= limit )
+ break;
+
+ v = *p++;
+ counts[0] = v >> 4;
+ counts[1] = v & 15;
+ phase = 0;
+ count = counts[0];
+ }
+ else
+ {
+ phase = 1;
+ count = counts[1];
+ }
+
+ } while ( count == 0 );
+ }
+
+ if ( phase )
+ c |= mask;
+
+ mask >>= 1;
+
+ if ( --left <= 0 )
+ {
+ cur[0] = (FT_Byte) c;
+ left = writer->width;
+ mask = 0x80;
+
+ writer->line += writer->pitch;
+ cur = writer->line;
+ c = 0;
+ }
+ else if ( mask == 0 )
+ {
+ cur[0] = c;
+ mask = 0x80;
+ c = 0;
+ cur ++;
+ }
+
+ reload = ( --count <= 0 );
+ }
+
+ if ( mask != 0x80 )
+ cur[0] = (FT_Byte) c;
+ }
+
+
+ static void
+ pfr_bitwriter_decode_rle2( PFR_BitWriter writer,
+ FT_Byte* p,
+ FT_Byte* limit )
+ {
+ FT_Int n, phase, count, reload;
+ FT_Int left = writer->width;
+ FT_Byte* cur = writer->line;
+ FT_UInt mask = 0x80;
+ FT_UInt c = 0;
+
+
+ n = writer->total;
+
+ phase = 1;
+ count = 0;
+ reload = 1;
+
+ for ( ; n > 0; n-- )
+ {
+ if ( reload )
+ {
+ do
+ {
+ if ( p >= limit )
+ break;
+
+ count = *p++;
+ phase = phase ^ 1;
+
+ } while ( count == 0 );
+ }
+
+ if ( phase )
+ c |= mask;
+
+ mask >>= 1;
+
+ if ( --left <= 0 )
+ {
+ cur[0] = (FT_Byte) c;
+ c = 0;
+ mask = 0x80;
+ left = writer->width;
+
+ writer->line += writer->pitch;
+ cur = writer->line;
+ }
+ else if ( mask == 0 )
+ {
+ cur[0] = c;
+ c = 0;
+ mask = 0x80;
+ cur ++;
+ }
+
+ reload = ( --count <= 0 );
+ }
+
+ if ( mask != 0x80 )
+ cur[0] = (FT_Byte) c;
+ }
+
+
+ /*************************************************************************/
+ /*************************************************************************/
+ /***** *****/
+ /***** BITMAP DATA DECODING *****/
+ /***** *****/
+ /*************************************************************************/
+ /*************************************************************************/
+
+ static void
+ pfr_lookup_bitmap_data( FT_Byte* base,
+ FT_Byte* limit,
+ FT_Int count,
+ FT_Byte flags,
+ FT_UInt char_code,
+ FT_ULong* found_offset,
+ FT_ULong* found_size )
+ {
+ FT_UInt left, right, char_len;
+ FT_Bool two = flags & 1;
+ FT_Byte* buff;
+
+
+ char_len = 4;
+ if ( two ) char_len += 1;
+ if ( flags & 2 ) char_len += 1;
+ if ( flags & 4 ) char_len += 1;
+
+ left = 0;
+ right = count;
+
+ while ( left < right )
+ {
+ FT_UInt middle, code;
+
+
+ middle = ( left + right ) >> 1;
+ buff = base + middle * char_len;
+
+ /* check that we are not outside of the table -- */
+ /* this is possible with broken fonts... */
+ if ( buff + char_len > limit )
+ goto Fail;
+
+ if ( two )
+ code = PFR_NEXT_USHORT( buff );
+ else
+ code = PFR_NEXT_BYTE( buff );
+
+ if ( code == char_code )
+ goto Found_It;
+
+ if ( code < char_code )
+ left = middle;
+ else
+ right = middle;
+ }
+
+ Fail:
+ /* Not found */
+ *found_size = 0;
+ *found_offset = 0;
+ return;
+
+ Found_It:
+ if ( flags & 2 )
+ *found_size = PFR_NEXT_USHORT( buff );
+ else
+ *found_size = PFR_NEXT_BYTE( buff );
+
+ if ( flags & 4 )
+ *found_offset = PFR_NEXT_ULONG( buff );
+ else
+ *found_offset = PFR_NEXT_USHORT( buff );
+ }
+
+
+ /* load bitmap metrics. "*padvance" must be set to the default value */
+ /* before calling this function... */
+ /* */
+ static FT_Error
+ pfr_load_bitmap_metrics( FT_Byte** pdata,
+ FT_Byte* limit,
+ FT_Long scaled_advance,
+ FT_Long *axpos,
+ FT_Long *aypos,
+ FT_UInt *axsize,
+ FT_UInt *aysize,
+ FT_Long *aadvance,
+ FT_UInt *aformat )
+ {
+ FT_Error error = 0;
+ FT_Byte flags;
+ FT_Char b;
+ FT_Byte* p = *pdata;
+ FT_Long xpos, ypos, advance;
+ FT_UInt xsize, ysize;
+
+
+ PFR_CHECK( 1 );
+ flags = PFR_NEXT_BYTE( p );
+
+ xpos = 0;
+ ypos = 0;
+ xsize = 0;
+ ysize = 0;
+ advance = 0;
+
+ switch ( flags & 3 )
+ {
+ case 0:
+ PFR_CHECK( 1 );
+ b = PFR_NEXT_INT8( p );
+ xpos = b >> 4;
+ ypos = ( (FT_Char)( b << 4 ) ) >> 4;
+ break;
+
+ case 1:
+ PFR_CHECK( 2 );
+ xpos = PFR_NEXT_INT8( p );
+ ypos = PFR_NEXT_INT8( p );
+ break;
+
+ case 2:
+ PFR_CHECK( 4 );
+ xpos = PFR_NEXT_SHORT( p );
+ ypos = PFR_NEXT_SHORT( p );
+ break;
+
+ case 3:
+ PFR_CHECK( 6 );
+ xpos = PFR_NEXT_LONG( p );
+ ypos = PFR_NEXT_LONG( p );
+ break;
+
+ default:
+ ;
+ }
+
+ flags >>= 2;
+ switch ( flags & 3 )
+ {
+ case 0:
+ /* blank image */
+ xsize = 0;
+ ysize = 0;
+ break;
+
+ case 1:
+ PFR_CHECK( 1 );
+ b = PFR_NEXT_BYTE( p );
+ xsize = ( b >> 4 ) & 0xF;
+ ysize = b & 0xF;
+ break;
+
+ case 2:
+ PFR_CHECK( 2 );
+ xsize = PFR_NEXT_BYTE( p );
+ ysize = PFR_NEXT_BYTE( p );
+ break;
+
+ case 3:
+ PFR_CHECK( 4 );
+ xsize = PFR_NEXT_USHORT( p );
+ ysize = PFR_NEXT_USHORT( p );
+ break;
+
+ default:
+ ;
+ }
+
+ flags >>= 2;
+ switch ( flags & 3 )
+ {
+ case 0:
+ advance = scaled_advance;
+ break;
+
+ case 1:
+ PFR_CHECK( 1 );
+ advance = PFR_NEXT_INT8( p ) << 8;
+ break;
+
+ case 2:
+ PFR_CHECK( 2 );
+ advance = PFR_NEXT_SHORT( p );
+ break;
+
+ case 3:
+ PFR_CHECK( 3 );
+ advance = PFR_NEXT_LONG( p );
+ break;
+
+ default:
+ ;
+ }
+
+ *axpos = xpos;
+ *aypos = ypos;
+ *axsize = xsize;
+ *aysize = ysize;
+ *aadvance = advance;
+ *aformat = flags >> 2;
+ *pdata = p;
+
+ Exit:
+ return error;
+
+ Too_Short:
+ error = PFR_Err_Invalid_Table;
+ FT_ERROR(( "pfr_load_bitmap_metrics: invalid glyph data\n" ));
+ goto Exit;
+ }
+
+
+ static FT_Error
+ pfr_load_bitmap_bits( FT_Byte* p,
+ FT_Byte* limit,
+ FT_UInt format,
+ FT_UInt decreasing,
+ FT_Bitmap* target )
+ {
+ FT_Error error = 0;
+ PFR_BitWriterRec writer;
+
+
+ if ( target->rows > 0 && target->width > 0 )
+ {
+ pfr_bitwriter_init( &writer, target, decreasing );
+
+ switch ( format )
+ {
+ case 0: /* packed bits */
+ pfr_bitwriter_decode_bytes( &writer, p, limit );
+ break;
+
+ case 1: /* RLE1 */
+ pfr_bitwriter_decode_rle1( &writer, p, limit );
+ break;
+
+ case 2: /* RLE2 */
+ pfr_bitwriter_decode_rle2( &writer, p, limit );
+ break;
+
+ default:
+ FT_ERROR(( "pfr_read_bitmap_data: invalid image type\n" ));
+ error = FT_Err_Invalid_File_Format;
+ }
+ }
+
+ return error;
+ }
+
+
+ /*************************************************************************/
+ /*************************************************************************/
+ /***** *****/
+ /***** BITMAP LOADING *****/
+ /***** *****/
+ /*************************************************************************/
+ /*************************************************************************/
+
+ FT_LOCAL( FT_Error )
+ pfr_slot_load_bitmap( PFR_Slot glyph,
+ PFR_Size size,
+ FT_UInt glyph_index )
+ {
+ FT_Error error;
+ PFR_Face face = (PFR_Face) glyph->root.face;
+ FT_Stream stream = face->root.stream;
+ PFR_PhyFont phys = &face->phy_font;
+ FT_ULong gps_offset;
+ FT_ULong gps_size;
+ PFR_Char character;
+ PFR_Strike strike;
+
+
+ character = &phys->chars[glyph_index];
+
+ /* Look-up a bitmap strike corresponding to the current */
+ /* character dimensions */
+ {
+ FT_UInt n;
+
+
+ strike = phys->strikes;
+ for ( n = 0; n < phys->num_strikes; n++ )
+ {
+ if ( strike->x_ppm == (FT_UInt)size->root.metrics.x_ppem &&
+ strike->y_ppm == (FT_UInt)size->root.metrics.y_ppem )
+ {
+ goto Found_Strike;
+ }
+
+ strike++;
+ }
+
+ /* couldn't find it */
+ return FT_Err_Invalid_Argument;
+ }
+
+ Found_Strike:
+
+ /* Now lookup the glyph's position within the file */
+ {
+ FT_UInt char_len;
+
+
+ char_len = 4;
+ if ( strike->flags & 1 ) char_len += 1;
+ if ( strike->flags & 2 ) char_len += 1;
+ if ( strike->flags & 4 ) char_len += 1;
+
+ /* Access data directly in the frame to speed lookups */
+ if ( FT_STREAM_SEEK( phys->bct_offset + strike->bct_offset ) ||
+ FT_FRAME_ENTER( char_len * strike->num_bitmaps ) )
+ goto Exit;
+
+ pfr_lookup_bitmap_data( stream->cursor,
+ stream->limit,
+ strike->num_bitmaps,
+ strike->flags,
+ character->char_code,
+ &gps_offset,
+ &gps_size );
+
+ FT_FRAME_EXIT();
+
+ if ( gps_size == 0 )
+ {
+ /* Could not find a bitmap program string for this glyph */
+ error = FT_Err_Invalid_Argument;
+ goto Exit;
+ }
+ }
+
+ /* get the bitmap metrics */
+ {
+ FT_Long xpos, ypos, advance;
+ FT_UInt xsize, ysize, format;
+ FT_Byte* p;
+
+
+ advance = FT_MulDiv( size->root.metrics.x_ppem << 8,
+ character->advance,
+ phys->metrics_resolution );
+
+ /* XXX: handle linearHoriAdvance correctly! */
+
+ if ( FT_STREAM_SEEK( face->header.gps_section_offset + gps_offset ) ||
+ FT_FRAME_ENTER( gps_size ) )
+ goto Exit;
+
+ p = stream->cursor;
+ error = pfr_load_bitmap_metrics( &p, stream->limit,
+ advance,
+ &xpos, &ypos,
+ &xsize, &ysize,
+ &advance, &format );
+ if ( !error )
+ {
+ glyph->root.format = FT_GLYPH_FORMAT_BITMAP;
+
+ /* Set up glyph bitmap and metrics */
+ glyph->root.bitmap.width = (FT_Int)xsize;
+ glyph->root.bitmap.rows = (FT_Int)ysize;
+ glyph->root.bitmap.pitch = (FT_Long)( xsize + 7 ) >> 3;
+ glyph->root.bitmap.pixel_mode = FT_PIXEL_MODE_MONO;
+
+ glyph->root.metrics.width = (FT_Long)xsize << 6;
+ glyph->root.metrics.height = (FT_Long)ysize << 6;
+ glyph->root.metrics.horiBearingX = xpos << 6;
+ glyph->root.metrics.horiBearingY = ypos << 6;
+ glyph->root.metrics.horiAdvance = ( ( advance >> 2 ) + 32 ) & -64;
+ glyph->root.metrics.vertBearingX = - glyph->root.metrics.width >> 1;
+ glyph->root.metrics.vertBearingY = 0;
+ glyph->root.metrics.vertAdvance = size->root.metrics.height;
+
+ glyph->root.bitmap_left = xpos;
+ glyph->root.bitmap_top = ypos + ysize;
+
+ /* Allocate and read bitmap data */
+ {
+ FT_Memory memory = face->root.memory;
+ FT_Long len = glyph->root.bitmap.pitch * ysize;
+
+
+ if ( !FT_ALLOC( glyph->root.bitmap.buffer, len ) )
+ {
+ error = pfr_load_bitmap_bits( p,
+ stream->limit,
+ format,
+ face->header.color_flags & 2,
+ &glyph->root.bitmap );
+ }
+ }
+ }
+
+ FT_FRAME_EXIT();
+ }
+
+ Exit:
+ return error;
+ }
+
+/* END */
--- /dev/null
+++ b/libfreetype/pfrsbit.h
@@ -1,0 +1,36 @@
+/***************************************************************************/
+/* */
+/* pfrsbit.h */
+/* */
+/* FreeType PFR bitmap loader (specification). */
+/* */
+/* Copyright 2002 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+
+#ifndef __PFRSBIT_H__
+#define __PFRSBIT_H__
+
+#include "pfrobjs.h"
+
+FT_BEGIN_HEADER
+
+ FT_LOCAL( FT_Error )
+ pfr_slot_load_bitmap( PFR_Slot glyph,
+ PFR_Size size,
+ FT_UInt glyph_index );
+
+FT_END_HEADER
+
+#endif /* __PFR_SBIT_H__ */
+
+
+/* END */
--- /dev/null
+++ b/libfreetype/pfrtypes.h
@@ -1,0 +1,354 @@
+/***************************************************************************/
+/* */
+/* pfrtypes.h */
+/* */
+/* FreeType PFR data structures (specification only). */
+/* */
+/* Copyright 2002 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+
+#ifndef __PFRTYPES_H__
+#define __PFRTYPES_H__
+
+#include <ft2build.h>
+#include FT_INTERNAL_OBJECTS_H
+
+FT_BEGIN_HEADER
+
+ /************************************************************************/
+
+ /* the PFR Header structure */
+ typedef struct PFR_HeaderRec_
+ {
+ FT_UInt32 signature;
+ FT_UInt version;
+ FT_UInt signature2;
+ FT_UInt header_size;
+
+ FT_UInt log_dir_size;
+ FT_UInt log_dir_offset;
+
+ FT_UInt log_font_max_size;
+ FT_UInt32 log_font_section_size;
+ FT_UInt32 log_font_section_offset;
+
+ FT_UInt32 phy_font_max_size;
+ FT_UInt32 phy_font_section_size;
+ FT_UInt32 phy_font_section_offset;
+
+ FT_UInt gps_max_size;
+ FT_UInt32 gps_section_size;
+ FT_UInt32 gps_section_offset;
+
+ FT_UInt max_blue_values;
+ FT_UInt max_x_orus;
+ FT_UInt max_y_orus;
+
+ FT_UInt phy_font_max_size_high;
+ FT_UInt color_flags;
+
+ FT_UInt32 bct_max_size;
+ FT_UInt32 bct_set_max_size;
+ FT_UInt32 phy_bct_set_max_size;
+
+ FT_UInt num_phy_fonts;
+ FT_UInt max_vert_stem_snap;
+ FT_UInt max_horz_stem_snap;
+ FT_UInt max_chars;
+
+ } PFR_HeaderRec, *PFR_Header;
+
+
+ /* used in `color_flags' field of the PFR_Header */
+ typedef enum PFR_HeaderFlags_
+ {
+ PFR_FLAG_BLACK_PIXEL = 1,
+ PFR_FLAG_INVERT_BITMAP = 2
+
+ } PFR_HeaderFlags;
+
+
+ /************************************************************************/
+
+ typedef struct PFR_LogFontRec_
+ {
+ FT_UInt32 size;
+ FT_UInt32 offset;
+
+ FT_Int32 matrix[4];
+ FT_UInt stroke_flags;
+ FT_Int stroke_thickness;
+ FT_Int bold_thickness;
+ FT_Int32 miter_limit;
+
+ FT_UInt32 phys_size;
+ FT_UInt32 phys_offset;
+
+ } PFR_LogFontRec, *PFR_LogFont;
+
+
+ typedef enum PFR_LogFlags_
+ {
+ PFR_LOG_EXTRA_ITEMS = 0x40,
+ PFR_LOG_2BYTE_BOLD = 0x20,
+ PFR_LOG_BOLD = 0x10,
+ PFR_LOG_2BYTE_STROKE = 8,
+ PFR_LOG_STROKE = 4,
+ PFR_LINE_JOIN_MASK = 3
+
+ } PFR_LogFlags;
+
+
+ typedef enum PFR_LineJoinFlags_
+ {
+ PFR_LINE_JOIN_MITER = 0,
+ PFR_LINE_JOIN_ROUND = 1,
+ PFR_LINE_JOIN_BEVEL = 2
+
+ } PFR_LineJoinFlags;
+
+
+ /************************************************************************/
+
+ typedef enum PFR_BitmapFlags_
+ {
+ PFR_BITMAP_3BYTE_OFFSET = 4,
+ PFR_BITMAP_2BYTE_SIZE = 2,
+ PFR_BITMAP_2BYTE_CHARCODE = 1
+
+ } PFR_BitmapFlags;
+
+
+ typedef struct PFR_BitmapCharRec_
+ {
+ FT_UInt char_code;
+ FT_UInt gps_size;
+ FT_UInt32 gps_offset;
+
+ } PFR_BitmapCharRec, *PFR_BitmapChar;
+
+
+ typedef enum PFR_StrikeFlags_
+ {
+ PFR_STRIKE_2BYTE_COUNT = 0x10,
+ PFR_STRIKE_3BYTE_OFFSET = 0x08,
+ PFR_STRIKE_3BYTE_SIZE = 0x04,
+ PFR_STRIKE_2BYTE_YPPM = 0x02,
+ PFR_STRIKE_2BYTE_XPPM = 0x01
+
+ } PFR_StrikeFlags;
+
+
+ typedef struct PFR_StrikeRec_
+ {
+ FT_UInt x_ppm;
+ FT_UInt y_ppm;
+ FT_UInt flags;
+
+ FT_UInt32 gps_size;
+ FT_UInt32 gps_offset;
+
+ FT_UInt32 bct_size;
+ FT_UInt32 bct_offset;
+
+ /* optional */
+ FT_UInt num_bitmaps;
+ PFR_BitmapChar bitmaps;
+
+ } PFR_StrikeRec, *PFR_Strike;
+
+
+ /************************************************************************/
+
+ typedef struct PFR_CharRec_
+ {
+ FT_UInt char_code;
+ FT_Int advance;
+ FT_UInt gps_size;
+ FT_UInt32 gps_offset;
+
+ } PFR_CharRec, *PFR_Char;
+
+
+ /************************************************************************/
+
+ typedef struct PFR_DimensionRec_
+ {
+ FT_UInt standard;
+ FT_UInt num_stem_snaps;
+ FT_Int* stem_snaps;
+
+ } PFR_DimensionRec, *PFR_Dimension;
+
+ /************************************************************************/
+
+ typedef struct PFR_KernItemRec_* PFR_KernItem;
+
+ typedef struct PFR_KernItemRec_
+ {
+ PFR_KernItem next;
+ FT_UInt pair_count;
+ FT_UInt pair_size;
+ FT_Int base_adj;
+ FT_UInt flags;
+ FT_UInt32 offset;
+ FT_UInt32 pair1;
+ FT_UInt32 pair2;
+
+ } PFR_KernItemRec;
+
+#define PFR_KERN_INDEX( g1, g2 ) \
+ ( ( (FT_UInt32)(g1) << 16 ) | (FT_UInt16)(g2) )
+
+ typedef struct PFR_KernPairRec_
+ {
+ FT_UInt glyph1;
+ FT_UInt glyph2;
+ FT_Vector kerning;
+
+ } PFR_KernPairRec, *PFR_KernPair;
+
+ /************************************************************************/
+
+ typedef struct PFR_PhyFontRec_
+ {
+ FT_Memory memory;
+ FT_UInt32 offset;
+
+ FT_UInt font_ref_number;
+ FT_UInt outline_resolution;
+ FT_UInt metrics_resolution;
+ FT_BBox bbox;
+ FT_UInt flags;
+ FT_UInt standard_advance;
+
+ PFR_DimensionRec horizontal;
+ PFR_DimensionRec vertical;
+
+ FT_String* font_id;
+
+ FT_UInt num_strikes;
+ FT_UInt max_strikes;
+ PFR_StrikeRec* strikes;
+
+ FT_UInt num_blue_values;
+ FT_Int *blue_values;
+ FT_UInt blue_fuzz;
+ FT_UInt blue_scale;
+
+ FT_UInt num_chars;
+ FT_UInt32 chars_offset;
+ PFR_Char chars;
+
+ FT_UInt num_kern_pairs;
+ PFR_KernItem kern_items;
+ PFR_KernItem* kern_items_tail;
+
+ /* not part of the spec, but used during load */
+ FT_UInt32 bct_offset;
+ FT_Byte* cursor;
+
+ } PFR_PhyFontRec, *PFR_PhyFont;
+
+
+ typedef enum PFR_PhyFlags_
+ {
+ PFR_PHY_EXTRA_ITEMS = 0x80,
+ PFR_PHY_3BYTE_GPS_OFFSET = 0x20,
+ PFR_PHY_2BYTE_GPS_SIZE = 0x10,
+ PFR_PHY_ASCII_CODE = 0x08,
+ PFR_PHY_PROPORTIONAL = 0x04,
+ PFR_PHY_2BYTE_CHARCODE = 0x02,
+ PFR_PHY_VERTICAL = 0x01
+
+ } PFR_PhyFlags;
+
+
+ typedef enum PFR_KernFlags_
+ {
+ PFR_KERN_2BYTE_ADJ = 0x01,
+ PFR_KERN_2BYTE_CHAR = 0x02
+
+ } PFR_KernFlags;
+
+
+ /************************************************************************/
+
+ typedef enum PFR_GlyphFlags_
+ {
+ PFR_GLYPH_IS_COMPOUND = 0x80,
+ PFR_GLYPH_EXTRA_ITEMS = 0x08,
+ PFR_GLYPH_1BYTE_XYCOUNT = 0x04,
+ PFR_GLYPH_XCOUNT = 0x02,
+ PFR_GLYPH_YCOUNT = 0x01
+
+ } PFR_GlyphFlags;
+
+
+ /* controlled coordinate */
+ typedef struct PFR_CoordRec_
+ {
+ FT_UInt org;
+ FT_UInt cur;
+
+ } PFR_CoordRec, *PFR_Coord;
+
+
+ typedef struct PFR_SubGlyphRec_
+ {
+ FT_Fixed x_scale;
+ FT_Fixed y_scale;
+ FT_Int x_delta;
+ FT_Int y_delta;
+ FT_UInt32 gps_offset;
+ FT_UInt gps_size;
+
+ } PFR_SubGlyphRec, *PFR_SubGlyph;
+
+
+ typedef enum PFR_SubgGlyphFlags_
+ {
+ PFR_SUBGLYPH_3BYTE_OFFSET = 0x80,
+ PFR_SUBGLYPH_2BYTE_SIZE = 0x40,
+ PFR_SUBGLYPH_YSCALE = 0x20,
+ PFR_SUBGLYPH_XSCALE = 0x10
+
+ } PFR_SubGlyphFlags;
+
+
+ typedef struct PFR_GlyphRec_
+ {
+ FT_Byte format;
+
+ FT_UInt num_x_control;
+ FT_UInt num_y_control;
+ FT_UInt max_xy_control;
+ FT_Pos* x_control;
+ FT_Pos* y_control;
+
+
+ FT_UInt num_subs;
+ FT_UInt max_subs;
+ PFR_SubGlyphRec* subs;
+
+ FT_GlyphLoader loader;
+ FT_Bool path_begun;
+
+ } PFR_GlyphRec, *PFR_Glyph;
+
+
+FT_END_HEADER
+
+#endif /* __PFRTYPES_H__ */
+
+
+/* END */
--- /dev/null
+++ b/libfreetype/psaux.c
@@ -1,0 +1,28 @@
+/***************************************************************************/
+/* */
+/* psaux.c */
+/* */
+/* FreeType auxiliary PostScript driver component (body only). */
+/* */
+/* Copyright 1996-2001, 2002 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+
+#define FT_MAKE_OPTION_SINGLE_OBJECT
+
+#include <ft2build.h>
+#include "psobjs.c"
+#include "psauxmod.c"
+#include "t1decode.c"
+#include "t1cmap.c"
+
+
+/* END */
--- /dev/null
+++ b/libfreetype/psauxerr.h
@@ -1,0 +1,41 @@
+/***************************************************************************/
+/* */
+/* psauxerr.h */
+/* */
+/* PS auxiliary module error codes (specification only). */
+/* */
+/* Copyright 2001 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+
+ /*************************************************************************/
+ /* */
+ /* This file is used to define the PS auxiliary module error enumeration */
+ /* constants. */
+ /* */
+ /*************************************************************************/
+
+#ifndef __PSAUXERR_H__
+#define __PSAUXERR_H__
+
+#include FT_MODULE_ERRORS_H
+
+#undef __FTERRORS_H__
+
+#define FT_ERR_PREFIX PSaux_Err_
+#define FT_ERR_BASE FT_Mod_Err_PSaux
+
+#include FT_ERRORS_H
+
+#endif /* __PSAUXERR_H__ */
+
+
+/* END */
--- /dev/null
+++ b/libfreetype/psauxmod.c
@@ -1,0 +1,118 @@
+/***************************************************************************/
+/* */
+/* psauxmod.c */
+/* */
+/* FreeType auxiliary PostScript module implementation (body). */
+/* */
+/* Copyright 2000-2001, 2002 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+
+#include <ft2build.h>
+#include "psauxmod.h"
+#include "psobjs.h"
+#include "t1decode.h"
+#include "t1cmap.h"
+
+
+ FT_CALLBACK_TABLE_DEF
+ const PS_Table_FuncsRec ps_table_funcs =
+ {
+ ps_table_new,
+ ps_table_done,
+ ps_table_add,
+ ps_table_release
+ };
+
+
+ FT_CALLBACK_TABLE_DEF
+ const PS_Parser_FuncsRec ps_parser_funcs =
+ {
+ ps_parser_init,
+ ps_parser_done,
+ ps_parser_skip_spaces,
+ ps_parser_skip_alpha,
+ ps_parser_to_int,
+ ps_parser_to_fixed,
+ ps_parser_to_coord_array,
+ ps_parser_to_fixed_array,
+ ps_parser_to_token,
+ ps_parser_to_token_array,
+ ps_parser_load_field,
+ ps_parser_load_field_table
+ };
+
+
+ FT_CALLBACK_TABLE_DEF
+ const T1_Builder_FuncsRec t1_builder_funcs =
+ {
+ t1_builder_init,
+ t1_builder_done,
+ t1_builder_check_points,
+ t1_builder_add_point,
+ t1_builder_add_point1,
+ t1_builder_add_contour,
+ t1_builder_start_point,
+ t1_builder_close_contour
+ };
+
+
+ FT_CALLBACK_TABLE_DEF
+ const T1_Decoder_FuncsRec t1_decoder_funcs =
+ {
+ t1_decoder_init,
+ t1_decoder_done,
+ t1_decoder_parse_charstrings
+ };
+
+
+ FT_CALLBACK_TABLE_DEF
+ const T1_CMap_ClassesRec t1_cmap_classes =
+ {
+ &t1_cmap_standard_class_rec,
+ &t1_cmap_expert_class_rec,
+ &t1_cmap_custom_class_rec,
+ &t1_cmap_unicode_class_rec
+ };
+
+
+ static
+ const PSAux_Interface psaux_interface =
+ {
+ &ps_table_funcs,
+ &ps_parser_funcs,
+ &t1_builder_funcs,
+ &t1_decoder_funcs,
+
+ t1_decrypt,
+
+ (const T1_CMap_ClassesRec*) &t1_cmap_classes,
+ };
+
+
+ FT_CALLBACK_TABLE_DEF
+ const FT_Module_Class psaux_module_class =
+ {
+ 0,
+ sizeof( FT_ModuleRec ),
+ "psaux",
+ 0x10000L,
+ 0x20000L,
+
+ &psaux_interface, /* module-specific interface */
+
+ (FT_Module_Constructor)0,
+ (FT_Module_Destructor) 0,
+ (FT_Module_Requester) 0
+ };
+
+
+/* END */
--- /dev/null
+++ b/libfreetype/psauxmod.h
@@ -1,0 +1,38 @@
+/***************************************************************************/
+/* */
+/* psauxmod.h */
+/* */
+/* FreeType auxiliary PostScript module implementation (specification). */
+/* */
+/* Copyright 2000-2001 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+
+#ifndef __PSAUXMOD_H__
+#define __PSAUXMOD_H__
+
+
+#include <ft2build.h>
+#include FT_MODULE_H
+
+
+FT_BEGIN_HEADER
+
+
+ FT_EXPORT_VAR( const FT_Module_Class ) psaux_driver_class;
+
+
+FT_END_HEADER
+
+#endif /* __PSAUXMOD_H__ */
+
+
+/* END */
--- /dev/null
+++ b/libfreetype/pshalgo.h
@@ -1,0 +1,53 @@
+/***************************************************************************/
+/* */
+/* pshalgo.h */
+/* */
+/* This header file defines the used hinting algorithm. */
+/* */
+/* Copyright 2001 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used */
+/* modified and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+
+#ifndef __PSHALGO_H__
+#define __PSHALGO_H__
+
+FT_BEGIN_HEADER
+
+/* define to choose hinting algorithm */
+#define PSH_ALGORITHM_3
+
+#if defined(PSH_ALGORITHM_1)
+
+# include "pshalgo1.h"
+# define PS_HINTS_APPLY_FUNC ps1_hints_apply
+
+#elif defined(PSH_ALGORITHM_2)
+
+# include "pshalgo2.h"
+# define PS_HINTS_APPLY_FUNC ps2_hints_apply
+
+#elif defined(PSH_ALGORITHM_3)
+
+# include "pshalgo3.h"
+# define PS_HINTS_APPLY_FUNC ps3_hints_apply
+
+#else
+
+# error "invalid Postscript Hinter algorithm selection"
+
+#endif
+
+FT_END_HEADER
+
+#endif /* __PSHALGO_H__ */
+
+
+/* END */
--- /dev/null
+++ b/libfreetype/pshalgo1.c
@@ -1,0 +1,785 @@
+/***************************************************************************/
+/* */
+/* pshalgo1.c */
+/* */
+/* PostScript hinting algorithm 1 (body). */
+/* */
+/* Copyright 2001, 2002 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used */
+/* modified and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+
+#include <ft2build.h>
+#include FT_INTERNAL_OBJECTS_H
+#include FT_INTERNAL_DEBUG_H
+#include "pshalgo1.h"
+
+#undef FT_COMPONENT
+#define FT_COMPONENT trace_pshalgo1
+
+#ifdef DEBUG_HINTER
+ PSH1_Hint_Table ps1_debug_hint_table = 0;
+ PSH1_HintFunc ps1_debug_hint_func = 0;
+#endif
+
+
+ /************************************************************************/
+ /************************************************************************/
+ /***** *****/
+ /***** BASIC HINTS RECORDINGS *****/
+ /***** *****/
+ /************************************************************************/
+ /************************************************************************/
+
+ /* return true iff two stem hints overlap */
+ static FT_Int
+ psh1_hint_overlap( PSH1_Hint hint1,
+ PSH1_Hint hint2 )
+ {
+ return ( hint1->org_pos + hint1->org_len >= hint2->org_pos &&
+ hint2->org_pos + hint2->org_len >= hint1->org_pos );
+ }
+
+
+ /* destroy hints table */
+ static void
+ psh1_hint_table_done( PSH1_Hint_Table table,
+ FT_Memory memory )
+ {
+ FT_FREE( table->zones );
+ table->num_zones = 0;
+ table->zone = 0;
+
+ FT_FREE( table->sort );
+ FT_FREE( table->hints );
+ table->num_hints = 0;
+ table->max_hints = 0;
+ table->sort_global = 0;
+ }
+
+
+ /* deactivate all hints in a table */
+ static void
+ psh1_hint_table_deactivate( PSH1_Hint_Table table )
+ {
+ FT_UInt count = table->max_hints;
+ PSH1_Hint hint = table->hints;
+
+
+ for ( ; count > 0; count--, hint++ )
+ {
+ psh1_hint_deactivate( hint );
+ hint->order = -1;
+ }
+ }
+
+
+ /* internal function used to record a new hint */
+ static void
+ psh1_hint_table_record( PSH1_Hint_Table table,
+ FT_UInt idx )
+ {
+ PSH1_Hint hint = table->hints + idx;
+
+
+ if ( idx >= table->max_hints )
+ {
+ FT_ERROR(( "%s.activate: invalid hint index %d\n", idx ));
+ return;
+ }
+
+ /* ignore active hints */
+ if ( psh1_hint_is_active( hint ) )
+ return;
+
+ psh1_hint_activate( hint );
+
+ /* now scan the current active hint set in order to determine */
+ /* if we are overlapping with another segment */
+ {
+ PSH1_Hint* sorted = table->sort_global;
+ FT_UInt count = table->num_hints;
+ PSH1_Hint hint2;
+
+
+ hint->parent = 0;
+ for ( ; count > 0; count--, sorted++ )
+ {
+ hint2 = sorted[0];
+
+ if ( psh1_hint_overlap( hint, hint2 ) )
+ {
+ hint->parent = hint2;
+ break;
+ }
+ }
+ }
+
+ if ( table->num_hints < table->max_hints )
+ table->sort_global[table->num_hints++] = hint;
+ else
+ FT_ERROR(( "%s.activate: too many sorted hints! BUG!\n",
+ "ps.fitter" ));
+ }
+
+
+ static void
+ psh1_hint_table_record_mask( PSH1_Hint_Table table,
+ PS_Mask hint_mask )
+ {
+ FT_Int mask = 0, val = 0;
+ FT_Byte* cursor = hint_mask->bytes;
+ FT_UInt idx, limit;
+
+
+ limit = hint_mask->num_bits;
+
+ if ( limit != table->max_hints )
+ FT_ERROR(( "%s.activate_mask: invalid bit count (%d instead of %d)\n",
+ "ps.fitter", hint_mask->num_bits, table->max_hints ));
+
+ for ( idx = 0; idx < limit; idx++ )
+ {
+ if ( mask == 0 )
+ {
+ val = *cursor++;
+ mask = 0x80;
+ }
+
+ if ( val & mask )
+ psh1_hint_table_record( table, idx );
+
+ mask >>= 1;
+ }
+ }
+
+
+ /* create hints table */
+ static FT_Error
+ psh1_hint_table_init( PSH1_Hint_Table table,
+ PS_Hint_Table hints,
+ PS_Mask_Table hint_masks,
+ PS_Mask_Table counter_masks,
+ FT_Memory memory )
+ {
+ FT_UInt count = hints->num_hints;
+ FT_Error error;
+
+ FT_UNUSED( counter_masks );
+
+
+ /* allocate our tables */
+ if ( FT_NEW_ARRAY( table->sort, 2 * count ) ||
+ FT_NEW_ARRAY( table->hints, count ) ||
+ FT_NEW_ARRAY( table->zones, 2 * count + 1 ) )
+ goto Exit;
+
+ table->max_hints = count;
+ table->sort_global = table->sort + count;
+ table->num_hints = 0;
+ table->num_zones = 0;
+ table->zone = 0;
+
+ /* now, initialize the "hints" array */
+ {
+ PSH1_Hint write = table->hints;
+ PS_Hint read = hints->hints;
+
+
+ for ( ; count > 0; count--, write++, read++ )
+ {
+ write->org_pos = read->pos;
+ write->org_len = read->len;
+ write->flags = read->flags;
+ }
+ }
+
+ /* we now need to determine the initial "parent" stems; first */
+ /* activate the hints that are given by the initial hint masks */
+ if ( hint_masks )
+ {
+ FT_UInt Count = hint_masks->num_masks;
+ PS_Mask Mask = hint_masks->masks;
+
+
+ table->hint_masks = hint_masks;
+
+ for ( ; Count > 0; Count--, Mask++ )
+ psh1_hint_table_record_mask( table, Mask );
+ }
+
+ /* now, do a linear parse in case some hints were left alone */
+ if ( table->num_hints != table->max_hints )
+ {
+ FT_UInt Index, Count;
+
+
+ FT_ERROR(( "%s.init: missing/incorrect hint masks!\n" ));
+ Count = table->max_hints;
+ for ( Index = 0; Index < Count; Index++ )
+ psh1_hint_table_record( table, Index );
+ }
+
+ Exit:
+ return error;
+ }
+
+
+ static void
+ psh1_hint_table_activate_mask( PSH1_Hint_Table table,
+ PS_Mask hint_mask )
+ {
+ FT_Int mask = 0, val = 0;
+ FT_Byte* cursor = hint_mask->bytes;
+ FT_UInt idx, limit, count;
+
+
+ limit = hint_mask->num_bits;
+ count = 0;
+
+ psh1_hint_table_deactivate( table );
+
+ for ( idx = 0; idx < limit; idx++ )
+ {
+ if ( mask == 0 )
+ {
+ val = *cursor++;
+ mask = 0x80;
+ }
+
+ if ( val & mask )
+ {
+ PSH1_Hint hint = &table->hints[idx];
+
+
+ if ( !psh1_hint_is_active( hint ) )
+ {
+ PSH1_Hint* sort = table->sort;
+ FT_UInt count2;
+ PSH1_Hint hint2;
+
+
+ for ( count2 = count; count2 > 0; count2--, sort++ )
+ {
+ hint2 = sort[0];
+ if ( psh1_hint_overlap( hint, hint2 ) )
+ {
+ FT_ERROR(( "%s.activate_mask: found overlapping hints\n",
+ "psf.hint" ));
+ break;
+ }
+ }
+
+ if ( count2 == 0 )
+ {
+ psh1_hint_activate( hint );
+ if ( count < table->max_hints )
+ table->sort[count++] = hint;
+ else
+ FT_ERROR(( "%s.activate_mask: too many active hints\n",
+ "psf.hint" ));
+ }
+ }
+ }
+
+ mask >>= 1;
+ }
+ table->num_hints = count;
+
+ /* now, sort the hints; they are guaranteed to not overlap */
+ /* so we can compare their "org_pos" field directly */
+ {
+ FT_Int i1, i2;
+ PSH1_Hint hint1, hint2;
+ PSH1_Hint* sort = table->sort;
+
+
+ /* a simple bubble sort will do, since in 99% of cases, the hints */
+ /* will be already sorted; and the sort will be linear */
+ for ( i1 = 1; i1 < (FT_Int)count; i1++ )
+ {
+ hint1 = sort[i1];
+
+ for ( i2 = i1 - 1; i2 >= 0; i2-- )
+ {
+ hint2 = sort[i2];
+ if ( hint2->org_pos < hint1->org_pos )
+ break;
+
+ sort[i2 + 1] = hint2;
+ sort[i2] = hint1;
+ }
+ }
+ }
+ }
+
+
+ /*************************************************************************/
+ /*************************************************************************/
+ /***** *****/
+ /***** HINTS GRID-FITTING AND OPTIMIZATION *****/
+ /***** *****/
+ /*************************************************************************/
+ /*************************************************************************/
+
+#ifdef DEBUG_HINTER
+ void
+ ps_simple_scale( PSH1_Hint_Table table,
+ FT_Fixed scale,
+ FT_Fixed delta,
+ FT_Int vertical )
+ {
+ PSH1_Hint hint;
+ FT_UInt count;
+
+
+ for ( count = 0; count < table->num_hints; count++ )
+ {
+ hint = table->sort[count];
+ if ( psh1_hint_is_active( hint ) )
+ {
+ hint->cur_pos = FT_MulFix( hint->org_pos, scale ) + delta;
+ hint->cur_len = FT_MulFix( hint->org_len, scale );
+
+ if ( ps1_debug_hint_func )
+ ps1_debug_hint_func( hint, vertical );
+ }
+ }
+ }
+#endif
+
+
+ FT_LOCAL_DEF( FT_Error )
+ psh1_hint_table_optimize( PSH1_Hint_Table table,
+ PSH_Globals globals,
+ FT_Outline* outline,
+ FT_Int vertical )
+ {
+ PSH_Dimension dim = &globals->dimension[vertical];
+ FT_Fixed scale = dim->scale_mult;
+ FT_Fixed delta = dim->scale_delta;
+
+ FT_UNUSED( outline );
+
+
+#ifdef DEBUG_HINTER
+ if ( ps_debug_no_vert_hints && vertical )
+ {
+ ps_simple_scale( table, scale, delta, vertical );
+ return 0;
+ }
+
+ if ( ps_debug_no_horz_hints && !vertical )
+ {
+ ps_simple_scale( table, scale, delta, vertical );
+ return 0;
+ }
+#endif
+
+ /* XXXX: for now, we only scale the hints to test all other aspects */
+ /* of the PostScript hinter */
+ {
+ PSH1_Hint hint;
+ FT_UInt count;
+
+
+ for ( count = 0; count < table->num_hints; count++ )
+ {
+ hint = table->sort[count];
+ if ( psh1_hint_is_active( hint ) )
+ {
+#if 1
+ FT_Pos pos = FT_MulFix( hint->org_pos, scale ) + delta;
+ FT_Pos len = FT_MulFix( hint->org_len, scale );
+
+ FT_Pos fit_center;
+ FT_Pos fit_len;
+
+ PSH_AlignmentRec align;
+
+
+ /* compute fitted width/height */
+ fit_len = psh_dimension_snap_width( dim, hint->org_len );
+ if ( fit_len < 64 )
+ fit_len = 64;
+ else
+ fit_len = ( fit_len + 32 ) & -64;
+
+ hint->cur_len = fit_len;
+
+ /* check blue zones for horizontal stems */
+ align.align = PSH_BLUE_ALIGN_NONE;
+ align.align_bot = align.align_top = 0;
+ if ( !vertical )
+ {
+ psh_blues_snap_stem( &globals->blues,
+ hint->org_pos + hint->org_len,
+ hint->org_pos,
+ &align );
+ }
+
+ switch ( align.align )
+ {
+ case PSH_BLUE_ALIGN_TOP:
+ /* the top of the stem is aligned against a blue zone */
+ hint->cur_pos = align.align_top - fit_len;
+ break;
+
+ case PSH_BLUE_ALIGN_BOT:
+ /* the bottom of the stem is aligned against a blue zone */
+ hint->cur_pos = align.align_bot;
+ break;
+
+ case PSH_BLUE_ALIGN_TOP | PSH_BLUE_ALIGN_BOT:
+ /* both edges of the stem are aligned against blue zones */
+ hint->cur_pos = align.align_bot;
+ hint->cur_len = align.align_top - align.align_bot;
+ break;
+
+ default:
+ /* normal processing */
+ if ( ( fit_len / 64 ) & 1 )
+ {
+ /* odd number of pixels */
+ fit_center = ( ( pos + ( len >> 1 ) ) & -64 ) + 32;
+ }
+ else
+ {
+ /* even number of pixels */
+ fit_center = ( pos + ( len >> 1 ) + 32 ) & -64;
+ }
+
+ hint->cur_pos = fit_center - ( fit_len >> 1 );
+ }
+
+# else
+
+ hint->cur_pos = ( FT_MulFix( hint->org_pos, scale ) + delta + 32 )
+ & -64;
+ hint->cur_len = FT_MulFix( hint->org_len, scale );
+
+# endif
+
+#ifdef DEBUG_HINTER
+ if ( ps1_debug_hint_func )
+ ps1_debug_hint_func( hint, vertical );
+#endif
+ }
+ }
+ }
+
+ return 0;
+ }
+
+
+ /*************************************************************************/
+ /*************************************************************************/
+ /***** *****/
+ /***** POINTS INTERPOLATION ROUTINES *****/
+ /***** *****/
+ /*************************************************************************/
+ /*************************************************************************/
+
+#define PSH1_ZONE_MIN -3200000
+#define PSH1_ZONE_MAX +3200000
+
+#define xxDEBUG_ZONES
+
+
+#ifdef DEBUG_ZONES
+
+#include <stdio.h>
+
+ static void
+ psh1_print_zone( PSH1_Zone zone )
+ {
+ printf( "zone [scale,delta,min,max] = [%.3f,%.3f,%d,%d]\n",
+ zone->scale / 65536.0,
+ zone->delta / 64.0,
+ zone->min,
+ zone->max );
+ }
+
+#else
+#define psh1_print_zone( x ) do { } while ( 0 )
+#endif
+
+ /* setup interpolation zones once the hints have been grid-fitted */
+ /* by the optimizer */
+ static void
+ psh1_hint_table_setup_zones( PSH1_Hint_Table table,
+ FT_Fixed scale,
+ FT_Fixed delta )
+ {
+ FT_UInt count;
+ PSH1_Zone zone;
+ PSH1_Hint *sort, hint, hint2;
+
+
+ zone = table->zones;
+
+ /* special case, no hints defined */
+ if ( table->num_hints == 0 )
+ {
+ zone->scale = scale;
+ zone->delta = delta;
+ zone->min = PSH1_ZONE_MIN;
+ zone->max = PSH1_ZONE_MAX;
+
+ table->num_zones = 1;
+ table->zone = zone;
+ return;
+ }
+
+ /* the first zone is before the first hint */
+ /* x' = (x-x0)*s + x0' = x*s + ( x0' - x0*s ) */
+
+ sort = table->sort;
+ hint = sort[0];
+
+ zone->scale = scale;
+ zone->delta = hint->cur_pos - FT_MulFix( hint->org_pos, scale );
+ zone->min = PSH1_ZONE_MIN;
+ zone->max = hint->org_pos;
+
+ psh1_print_zone( zone );
+
+ zone++;
+
+ for ( count = table->num_hints; count > 0; count-- )
+ {
+ FT_Fixed scale2;
+
+
+ if ( hint->org_len > 0 )
+ {
+ /* setup a zone for inner-stem interpolation */
+ /* (x' - x0') = (x - x0)*(x1'-x0')/(x1-x0) */
+ /* x' = x*s2 + x0' - x0*s2 */
+
+ scale2 = FT_DivFix( hint->cur_len, hint->org_len );
+ zone->scale = scale2;
+ zone->min = hint->org_pos;
+ zone->max = hint->org_pos + hint->org_len;
+ zone->delta = hint->cur_pos - FT_MulFix( zone->min, scale2 );
+
+ psh1_print_zone( zone );
+
+ zone++;
+ }
+
+ if ( count == 1 )
+ break;
+
+ sort++;
+ hint2 = sort[0];
+
+ /* setup zone for inter-stem interpolation */
+ /* (x'-x1') = (x-x1)*(x2'-x1')/(x2-x1) */
+ /* x' = x*s3 + x1' - x1*s3 */
+
+ scale2 = FT_DivFix( hint2->cur_pos - (hint->cur_pos + hint->cur_len),
+ hint2->org_pos - (hint->org_pos + hint->org_len) );
+ zone->scale = scale2;
+ zone->min = hint->org_pos + hint->org_len;
+ zone->max = hint2->org_pos;
+ zone->delta = hint->cur_pos + hint->cur_len -
+ FT_MulFix( zone->min, scale2 );
+
+ psh1_print_zone( zone );
+
+ zone++;
+
+ hint = hint2;
+ }
+
+ /* the last zone */
+ zone->scale = scale;
+ zone->min = hint->org_pos + hint->org_len;
+ zone->max = PSH1_ZONE_MAX;
+ zone->delta = hint->cur_pos + hint->cur_len -
+ FT_MulFix( zone->min, scale );
+
+ psh1_print_zone( zone );
+
+ zone++;
+
+ table->num_zones = zone - table->zones;
+ table->zone = table->zones;
+ }
+
+
+ /* tune a single coordinate with the current interpolation zones */
+ static FT_Pos
+ psh1_hint_table_tune_coord( PSH1_Hint_Table table,
+ FT_Int coord )
+ {
+ PSH1_Zone zone;
+
+
+ zone = table->zone;
+
+ if ( coord < zone->min )
+ {
+ do
+ {
+ if ( zone == table->zones )
+ break;
+
+ zone--;
+
+ } while ( coord < zone->min );
+ table->zone = zone;
+ }
+ else if ( coord > zone->max )
+ {
+ do
+ {
+ if ( zone == table->zones + table->num_zones - 1 )
+ break;
+
+ zone++;
+
+ } while ( coord > zone->max );
+ table->zone = zone;
+ }
+
+ return FT_MulFix( coord, zone->scale ) + zone->delta;
+ }
+
+
+ /* tune a given outline with current interpolation zones. */
+ /* The function only works in a single dimension. */
+ static void
+ psh1_hint_table_tune_outline( PSH1_Hint_Table table,
+ FT_Outline* outline,
+ PSH_Globals globals,
+ FT_Int vertical )
+
+ {
+ FT_UInt count, first, last;
+ PS_Mask_Table hint_masks = table->hint_masks;
+ PS_Mask mask;
+ PSH_Dimension dim = &globals->dimension[vertical];
+ FT_Fixed scale = dim->scale_mult;
+ FT_Fixed delta = dim->scale_delta;
+
+
+ if ( hint_masks && hint_masks->num_masks > 0 )
+ {
+ first = 0;
+ mask = hint_masks->masks;
+ count = hint_masks->num_masks;
+
+ for ( ; count > 0; count--, mask++ )
+ {
+ last = mask->end_point;
+
+ if ( last > first )
+ {
+ FT_Vector* vec;
+ FT_Int count2;
+
+
+ psh1_hint_table_activate_mask( table, mask );
+ psh1_hint_table_optimize( table, globals, outline, vertical );
+ psh1_hint_table_setup_zones( table, scale, delta );
+ last = mask->end_point;
+
+ vec = outline->points + first;
+ count2 = last - first;
+
+ for ( ; count2 > 0; count2--, vec++ )
+ {
+ FT_Pos x, *px;
+
+
+ px = vertical ? &vec->x : &vec->y;
+ x = *px;
+
+ *px = psh1_hint_table_tune_coord( table, (FT_Int)x );
+ }
+ }
+
+ first = last;
+ }
+ }
+ else /* no hints in this glyph, simply scale the outline */
+ {
+ FT_Vector* vec;
+
+
+ vec = outline->points;
+ count = outline->n_points;
+
+ if ( vertical )
+ {
+ for ( ; count > 0; count--, vec++ )
+ vec->x = FT_MulFix( vec->x, scale ) + delta;
+ }
+ else
+ {
+ for ( ; count > 0; count--, vec++ )
+ vec->y = FT_MulFix( vec->y, scale ) + delta;
+ }
+ }
+ }
+
+
+ /*************************************************************************/
+ /*************************************************************************/
+ /***** *****/
+ /***** HIGH-LEVEL INTERFACE *****/
+ /***** *****/
+ /*************************************************************************/
+ /*************************************************************************/
+
+ FT_Error
+ ps1_hints_apply( PS_Hints ps_hints,
+ FT_Outline* outline,
+ PSH_Globals globals,
+ FT_Render_Mode hint_mode )
+ {
+ PSH1_Hint_TableRec hints;
+ FT_Error error = 0;
+ FT_Int dimension;
+
+
+ FT_UNUSED( hint_mode );
+
+ for ( dimension = 1; dimension >= 0; dimension-- )
+ {
+ PS_Dimension dim = &ps_hints->dimension[dimension];
+
+
+ /* initialize hints table */
+ FT_MEM_ZERO( &hints, sizeof ( hints ) );
+ error = psh1_hint_table_init( &hints,
+ &dim->hints,
+ &dim->masks,
+ &dim->counters,
+ ps_hints->memory );
+ if ( error )
+ goto Exit;
+
+ psh1_hint_table_tune_outline( &hints,
+ outline,
+ globals,
+ dimension );
+
+ psh1_hint_table_done( &hints, ps_hints->memory );
+ }
+
+ Exit:
+ return error;
+ }
+
+
+/* END */
--- /dev/null
+++ b/libfreetype/pshalgo1.h
@@ -1,0 +1,110 @@
+/***************************************************************************/
+/* */
+/* pshalgo1.h */
+/* */
+/* PostScript hinting algorithm 1 (specification). */
+/* */
+/* Copyright 2001 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+
+#ifndef __PSHALGO1_H__
+#define __PSHALGO1_H__
+
+#include "pshrec.h"
+
+FT_BEGIN_HEADER
+
+ typedef struct PSH1_HintRec_* PSH1_Hint;
+
+ typedef enum
+ {
+ PSH1_HINT_FLAG_GHOST = PS_HINT_FLAG_GHOST,
+ PSH1_HINT_FLAG_BOTTOM = PS_HINT_FLAG_BOTTOM,
+ PSH1_HINT_FLAG_ACTIVE = 4
+
+ } PSH1_Hint_Flags;
+
+#define psh1_hint_is_active( x ) \
+ ( ( (x)->flags & PSH1_HINT_FLAG_ACTIVE ) != 0 )
+#define psh1_hint_is_ghost( x ) \
+ ( ( (x)->flags & PSH1_HINT_FLAG_GHOST ) != 0 )
+
+#define psh1_hint_activate( x ) (x)->flags |= PSH1_HINT_FLAG_ACTIVE
+#define psh1_hint_deactivate( x ) (x)->flags &= ~PSH1_HINT_FLAG_ACTIVE
+
+ typedef struct PSH1_HintRec_
+ {
+ FT_Int org_pos;
+ FT_Int org_len;
+ FT_Pos cur_pos;
+ FT_Pos cur_len;
+
+ FT_UInt flags;
+
+ PSH1_Hint parent;
+ FT_Int order;
+
+ } PSH1_HintRec;
+
+
+ /* this is an interpolation zone used for strong points; */
+ /* weak points are interpolated according to their strong */
+ /* neighbours */
+ typedef struct PSH1_ZoneRec_
+ {
+ FT_Fixed scale;
+ FT_Fixed delta;
+ FT_Pos min;
+ FT_Pos max;
+
+ } PSH1_ZoneRec, *PSH1_Zone;
+
+
+ typedef struct PSH1_Hint_TableRec_
+ {
+ FT_UInt max_hints;
+ FT_UInt num_hints;
+ PSH1_Hint hints;
+ PSH1_Hint* sort;
+ PSH1_Hint* sort_global;
+ FT_UInt num_zones;
+ PSH1_Zone zones;
+ PSH1_Zone zone;
+ PS_Mask_Table hint_masks;
+ PS_Mask_Table counter_masks;
+
+ } PSH1_Hint_TableRec, *PSH1_Hint_Table;
+
+
+ extern FT_Error
+ ps1_hints_apply( PS_Hints ps_hints,
+ FT_Outline* outline,
+ PSH_Globals globals,
+ FT_Render_Mode hint_mode );
+
+
+#ifdef DEBUG_HINTER
+ extern PSH1_Hint_Table ps1_debug_hint_table;
+
+ typedef void
+ (*PSH1_HintFunc)( PSH1_Hint hint,
+ FT_Bool vertical );
+
+ extern PSH1_HintFunc ps1_debug_hint_func;
+#endif
+
+FT_END_HEADER
+
+#endif /* __PSHALGO1_H__ */
+
+
+/* END */
--- /dev/null
+++ b/libfreetype/pshalgo2.c
@@ -1,0 +1,1557 @@
+/***************************************************************************/
+/* */
+/* pshalgo2.c */
+/* */
+/* PostScript hinting algorithm 2 (body). */
+/* */
+/* Copyright 2001, 2002 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used */
+/* modified and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+
+#include <ft2build.h>
+#include FT_INTERNAL_OBJECTS_H
+#include FT_INTERNAL_DEBUG_H
+#include "pshalgo2.h"
+
+#undef FT_COMPONENT
+#define FT_COMPONENT trace_pshalgo2
+
+#ifdef DEBUG_HINTER
+ PSH2_Hint_Table ps2_debug_hint_table = 0;
+ PSH2_HintFunc ps2_debug_hint_func = 0;
+ PSH2_Glyph ps2_debug_glyph = 0;
+#endif
+
+
+ /*************************************************************************/
+ /*************************************************************************/
+ /***** *****/
+ /***** BASIC HINTS RECORDINGS *****/
+ /***** *****/
+ /*************************************************************************/
+ /*************************************************************************/
+
+ /* return true iff two stem hints overlap */
+ static FT_Int
+ psh2_hint_overlap( PSH2_Hint hint1,
+ PSH2_Hint hint2 )
+ {
+ return ( hint1->org_pos + hint1->org_len >= hint2->org_pos &&
+ hint2->org_pos + hint2->org_len >= hint1->org_pos );
+ }
+
+
+ /* destroy hints table */
+ static void
+ psh2_hint_table_done( PSH2_Hint_Table table,
+ FT_Memory memory )
+ {
+ FT_FREE( table->zones );
+ table->num_zones = 0;
+ table->zone = 0;
+
+ FT_FREE( table->sort );
+ FT_FREE( table->hints );
+ table->num_hints = 0;
+ table->max_hints = 0;
+ table->sort_global = 0;
+ }
+
+
+ /* deactivate all hints in a table */
+ static void
+ psh2_hint_table_deactivate( PSH2_Hint_Table table )
+ {
+ FT_UInt count = table->max_hints;
+ PSH2_Hint hint = table->hints;
+
+
+ for ( ; count > 0; count--, hint++ )
+ {
+ psh2_hint_deactivate( hint );
+ hint->order = -1;
+ }
+ }
+
+
+ /* internal function used to record a new hint */
+ static void
+ psh2_hint_table_record( PSH2_Hint_Table table,
+ FT_UInt idx )
+ {
+ PSH2_Hint hint = table->hints + idx;
+
+
+ if ( idx >= table->max_hints )
+ {
+ FT_ERROR(( "%s.activate: invalid hint index %d\n", idx ));
+ return;
+ }
+
+ /* ignore active hints */
+ if ( psh2_hint_is_active( hint ) )
+ return;
+
+ psh2_hint_activate( hint );
+
+ /* now scan the current active hint set in order to determine */
+ /* if we are overlapping with another segment */
+ {
+ PSH2_Hint* sorted = table->sort_global;
+ FT_UInt count = table->num_hints;
+ PSH2_Hint hint2;
+
+
+ hint->parent = 0;
+ for ( ; count > 0; count--, sorted++ )
+ {
+ hint2 = sorted[0];
+
+ if ( psh2_hint_overlap( hint, hint2 ) )
+ {
+ hint->parent = hint2;
+ break;
+ }
+ }
+ }
+
+ if ( table->num_hints < table->max_hints )
+ table->sort_global[table->num_hints++] = hint;
+ else
+ FT_ERROR(( "%s.activate: too many sorted hints! BUG!\n",
+ "ps.fitter" ));
+ }
+
+
+ static void
+ psh2_hint_table_record_mask( PSH2_Hint_Table table,
+ PS_Mask hint_mask )
+ {
+ FT_Int mask = 0, val = 0;
+ FT_Byte* cursor = hint_mask->bytes;
+ FT_UInt idx, limit;
+
+
+ limit = hint_mask->num_bits;
+
+ for ( idx = 0; idx < limit; idx++ )
+ {
+ if ( mask == 0 )
+ {
+ val = *cursor++;
+ mask = 0x80;
+ }
+
+ if ( val & mask )
+ psh2_hint_table_record( table, idx );
+
+ mask >>= 1;
+ }
+ }
+
+
+ /* create hints table */
+ static FT_Error
+ psh2_hint_table_init( PSH2_Hint_Table table,
+ PS_Hint_Table hints,
+ PS_Mask_Table hint_masks,
+ PS_Mask_Table counter_masks,
+ FT_Memory memory )
+ {
+ FT_UInt count = hints->num_hints;
+ FT_Error error;
+
+ FT_UNUSED( counter_masks );
+
+
+ /* allocate our tables */
+ if ( FT_NEW_ARRAY( table->sort, 2 * count ) ||
+ FT_NEW_ARRAY( table->hints, count ) ||
+ FT_NEW_ARRAY( table->zones, 2 * count + 1 ) )
+ goto Exit;
+
+ table->max_hints = count;
+ table->sort_global = table->sort + count;
+ table->num_hints = 0;
+ table->num_zones = 0;
+ table->zone = 0;
+
+ /* now, initialize the "hints" array */
+ {
+ PSH2_Hint write = table->hints;
+ PS_Hint read = hints->hints;
+
+
+ for ( ; count > 0; count--, write++, read++ )
+ {
+ write->org_pos = read->pos;
+ write->org_len = read->len;
+ write->flags = read->flags;
+ }
+ }
+
+ /* we now need to determine the initial "parent" stems; first */
+ /* activate the hints that are given by the initial hint masks */
+ if ( hint_masks )
+ {
+ FT_UInt Count = hint_masks->num_masks;
+ PS_Mask Mask = hint_masks->masks;
+
+
+ table->hint_masks = hint_masks;
+
+ for ( ; Count > 0; Count--, Mask++ )
+ psh2_hint_table_record_mask( table, Mask );
+ }
+
+ /* now, do a linear parse in case some hints were left alone */
+ if ( table->num_hints != table->max_hints )
+ {
+ FT_UInt Index, Count;
+
+
+ FT_ERROR(( "%s.init: missing/incorrect hint masks!\n" ));
+ Count = table->max_hints;
+ for ( Index = 0; Index < Count; Index++ )
+ psh2_hint_table_record( table, Index );
+ }
+
+ Exit:
+ return error;
+ }
+
+
+ static void
+ psh2_hint_table_activate_mask( PSH2_Hint_Table table,
+ PS_Mask hint_mask )
+ {
+ FT_Int mask = 0, val = 0;
+ FT_Byte* cursor = hint_mask->bytes;
+ FT_UInt idx, limit, count;
+
+
+ limit = hint_mask->num_bits;
+ count = 0;
+
+ psh2_hint_table_deactivate( table );
+
+ for ( idx = 0; idx < limit; idx++ )
+ {
+ if ( mask == 0 )
+ {
+ val = *cursor++;
+ mask = 0x80;
+ }
+
+ if ( val & mask )
+ {
+ PSH2_Hint hint = &table->hints[idx];
+
+
+ if ( !psh2_hint_is_active( hint ) )
+ {
+ FT_UInt count2;
+
+#if 0
+ PSH2_Hint* sort = table->sort;
+ PSH2_Hint hint2;
+
+ for ( count2 = count; count2 > 0; count2--, sort++ )
+ {
+ hint2 = sort[0];
+ if ( psh2_hint_overlap( hint, hint2 ) )
+ FT_ERROR(( "%s.activate_mask: found overlapping hints\n",
+ "psf.hint" ));
+ }
+#else
+ count2 = 0;
+#endif
+
+ if ( count2 == 0 )
+ {
+ psh2_hint_activate( hint );
+ if ( count < table->max_hints )
+ table->sort[count++] = hint;
+ else
+ FT_ERROR(( "%s.activate_mask: too many active hints\n",
+ "psf.hint" ));
+ }
+ }
+ }
+
+ mask >>= 1;
+ }
+ table->num_hints = count;
+
+ /* now, sort the hints; they are guaranteed to not overlap */
+ /* so we can compare their "org_pos" field directly */
+ {
+ FT_Int i1, i2;
+ PSH2_Hint hint1, hint2;
+ PSH2_Hint* sort = table->sort;
+
+
+ /* a simple bubble sort will do, since in 99% of cases, the hints */
+ /* will be already sorted -- and the sort will be linear */
+ for ( i1 = 1; i1 < (FT_Int)count; i1++ )
+ {
+ hint1 = sort[i1];
+ for ( i2 = i1 - 1; i2 >= 0; i2-- )
+ {
+ hint2 = sort[i2];
+
+ if ( hint2->org_pos < hint1->org_pos )
+ break;
+
+ sort[i2 + 1] = hint2;
+ sort[i2] = hint1;
+ }
+ }
+ }
+ }
+
+
+ /*************************************************************************/
+ /*************************************************************************/
+ /***** *****/
+ /***** HINTS GRID-FITTING AND OPTIMIZATION *****/
+ /***** *****/
+ /*************************************************************************/
+ /*************************************************************************/
+
+#ifdef DEBUG_HINTER
+ static void
+ ps2_simple_scale( PSH2_Hint_Table table,
+ FT_Fixed scale,
+ FT_Fixed delta,
+ FT_Int dimension )
+ {
+ PSH2_Hint hint;
+ FT_UInt count;
+
+
+ for ( count = 0; count < table->max_hints; count++ )
+ {
+ hint = table->hints + count;
+
+ hint->cur_pos = FT_MulFix( hint->org_pos, scale ) + delta;
+ hint->cur_len = FT_MulFix( hint->org_len, scale );
+
+ if ( ps2_debug_hint_func )
+ ps2_debug_hint_func( hint, dimension );
+ }
+ }
+#endif
+
+
+ static void
+ psh2_hint_align( PSH2_Hint hint,
+ PSH_Globals globals,
+ FT_Int dimension )
+ {
+ PSH_Dimension dim = &globals->dimension[dimension];
+ FT_Fixed scale = dim->scale_mult;
+ FT_Fixed delta = dim->scale_delta;
+
+
+ if ( !psh2_hint_is_fitted(hint) )
+ {
+ FT_Pos pos = FT_MulFix( hint->org_pos, scale ) + delta;
+ FT_Pos len = FT_MulFix( hint->org_len, scale );
+
+ FT_Pos fit_center;
+ FT_Pos fit_len;
+
+ PSH_AlignmentRec align;
+
+
+ /* compute fitted width/height */
+ fit_len = 0;
+ if ( hint->org_len )
+ {
+ fit_len = psh_dimension_snap_width( dim, hint->org_len );
+ if ( fit_len < 64 )
+ fit_len = 64;
+ else
+ fit_len = ( fit_len + 32 ) & -64;
+ }
+
+ hint->cur_len = fit_len;
+
+ /* check blue zones for horizontal stems */
+ align.align = PSH_BLUE_ALIGN_NONE;
+ align.align_bot = align.align_top = 0;
+
+ if ( dimension == 1 )
+ psh_blues_snap_stem( &globals->blues,
+ hint->org_pos + hint->org_len,
+ hint->org_pos,
+ &align );
+
+ switch ( align.align )
+ {
+ case PSH_BLUE_ALIGN_TOP:
+ /* the top of the stem is aligned against a blue zone */
+ hint->cur_pos = align.align_top - fit_len;
+ break;
+
+ case PSH_BLUE_ALIGN_BOT:
+ /* the bottom of the stem is aligned against a blue zone */
+ hint->cur_pos = align.align_bot;
+ break;
+
+ case PSH_BLUE_ALIGN_TOP | PSH_BLUE_ALIGN_BOT:
+ /* both edges of the stem are aligned against blue zones */
+ hint->cur_pos = align.align_bot;
+ hint->cur_len = align.align_top - align.align_bot;
+ break;
+
+ default:
+ {
+ PSH2_Hint parent = hint->parent;
+
+
+ if ( parent )
+ {
+ FT_Pos par_org_center, par_cur_center;
+ FT_Pos cur_org_center, cur_delta;
+
+
+ /* ensure that parent is already fitted */
+ if ( !psh2_hint_is_fitted( parent ) )
+ psh2_hint_align( parent, globals, dimension );
+
+ par_org_center = parent->org_pos + ( parent->org_len / 2);
+ par_cur_center = parent->cur_pos + ( parent->cur_len / 2);
+ cur_org_center = hint->org_pos + ( hint->org_len / 2);
+
+ cur_delta = FT_MulFix( cur_org_center - par_org_center, scale );
+#if 0
+ if ( cur_delta >= 0 )
+ cur_delta = ( cur_delta + 16 ) & -64;
+ else
+ cur_delta = -( (-cur_delta + 16 ) & -64 );
+#endif
+ pos = par_cur_center + cur_delta - ( len >> 1 );
+ }
+
+ /* normal processing */
+ if ( ( fit_len / 64 ) & 1 )
+ {
+ /* odd number of pixels */
+ fit_center = ( ( pos + ( len >> 1 ) ) & -64 ) + 32;
+ }
+ else
+ {
+ /* even number of pixels */
+ fit_center = ( pos + ( len >> 1 ) + 32 ) & -64;
+ }
+
+ hint->cur_pos = fit_center - ( fit_len >> 1 );
+ }
+ }
+
+ psh2_hint_set_fitted( hint );
+
+#ifdef DEBUG_HINTER
+ if ( ps2_debug_hint_func )
+ ps2_debug_hint_func( hint, dimension );
+#endif
+ }
+ }
+
+
+ static void
+ psh2_hint_table_align_hints( PSH2_Hint_Table table,
+ PSH_Globals globals,
+ FT_Int dimension )
+ {
+ PSH2_Hint hint;
+ FT_UInt count;
+
+#ifdef DEBUG_HINTER
+ PSH_Dimension dim = &globals->dimension[dimension];
+ FT_Fixed scale = dim->scale_mult;
+ FT_Fixed delta = dim->scale_delta;
+
+
+ if ( ps_debug_no_vert_hints && dimension == 0 )
+ {
+ ps2_simple_scale( table, scale, delta, dimension );
+ return;
+ }
+
+ if ( ps_debug_no_horz_hints && dimension == 1 )
+ {
+ ps2_simple_scale( table, scale, delta, dimension );
+ return;
+ }
+#endif
+
+ hint = table->hints;
+ count = table->max_hints;
+
+ for ( ; count > 0; count--, hint++ )
+ psh2_hint_align( hint, globals, dimension );
+ }
+
+
+ /*************************************************************************/
+ /*************************************************************************/
+ /***** *****/
+ /***** POINTS INTERPOLATION ROUTINES *****/
+ /***** *****/
+ /*************************************************************************/
+ /*************************************************************************/
+
+#define PSH2_ZONE_MIN -3200000
+#define PSH2_ZONE_MAX +3200000
+
+#define xxDEBUG_ZONES
+
+
+#ifdef DEBUG_ZONES
+
+#include <stdio.h>
+
+ static void
+ psh2_print_zone( PSH2_Zone zone )
+ {
+ printf( "zone [scale,delta,min,max] = [%.3f,%.3f,%d,%d]\n",
+ zone->scale/65536.0,
+ zone->delta/64.0,
+ zone->min,
+ zone->max );
+ }
+
+#else
+
+#define psh2_print_zone( x ) do { } while ( 0 )
+
+#endif
+
+#if 0
+ /* setup interpolation zones once the hints have been grid-fitted */
+ /* by the optimizer */
+ static void
+ psh2_hint_table_setup_zones( PSH2_Hint_Table table,
+ FT_Fixed scale,
+ FT_Fixed delta )
+ {
+ FT_UInt count;
+ PSH2_Zone zone;
+ PSH2_Hint *sort, hint, hint2;
+
+
+ zone = table->zones;
+
+ /* special case, no hints defined */
+ if ( table->num_hints == 0 )
+ {
+ zone->scale = scale;
+ zone->delta = delta;
+ zone->min = PSH2_ZONE_MIN;
+ zone->max = PSH2_ZONE_MAX;
+
+ table->num_zones = 1;
+ table->zone = zone;
+ return;
+ }
+
+ /* the first zone is before the first hint */
+ /* x' = (x-x0)*s + x0' = x*s + ( x0' - x0*s ) */
+ sort = table->sort;
+ hint = sort[0];
+
+ zone->scale = scale;
+ zone->delta = hint->cur_pos - FT_MulFix( hint->org_pos, scale );
+ zone->min = PSH2_ZONE_MIN;
+ zone->max = hint->org_pos;
+
+ psh2_print_zone( zone );
+
+ zone++;
+
+ for ( count = table->num_hints; count > 0; count-- )
+ {
+ FT_Fixed scale2;
+
+
+ if ( hint->org_len > 0 )
+ {
+ /* setup a zone for inner-stem interpolation */
+ /* (x' - x0') = (x - x0)*(x1'-x0')/(x1-x0) */
+ /* x' = x*s2 + x0' - x0*s2 */
+
+ scale2 = FT_DivFix( hint->cur_len, hint->org_len );
+ zone->scale = scale2;
+ zone->min = hint->org_pos;
+ zone->max = hint->org_pos + hint->org_len;
+ zone->delta = hint->cur_pos - FT_MulFix( zone->min, scale2 );
+
+ psh2_print_zone( zone );
+
+ zone++;
+ }
+
+ if ( count == 1 )
+ break;
+
+ sort++;
+ hint2 = sort[0];
+
+ /* setup zone for inter-stem interpolation */
+ /* (x'-x1') = (x-x1)*(x2'-x1')/(x2-x1) */
+ /* x' = x*s3 + x1' - x1*s3 */
+
+ scale2 = FT_DivFix( hint2->cur_pos - (hint->cur_pos + hint->cur_len),
+ hint2->org_pos - (hint->org_pos + hint->org_len) );
+ zone->scale = scale2;
+ zone->min = hint->org_pos + hint->org_len;
+ zone->max = hint2->org_pos;
+ zone->delta = hint->cur_pos + hint->cur_len -
+ FT_MulFix( zone->min, scale2 );
+
+ psh2_print_zone( zone );
+
+ zone++;
+
+ hint = hint2;
+ }
+
+ /* the last zone */
+ zone->scale = scale;
+ zone->min = hint->org_pos + hint->org_len;
+ zone->max = PSH2_ZONE_MAX;
+ zone->delta = hint->cur_pos + hint->cur_len -
+ FT_MulFix( zone->min, scale );
+
+ psh2_print_zone( zone );
+
+ zone++;
+
+ table->num_zones = zone - table->zones;
+ table->zone = table->zones;
+ }
+#endif
+
+#if 0
+ /* tune a single coordinate with the current interpolation zones */
+ static FT_Pos
+ psh2_hint_table_tune_coord( PSH2_Hint_Table table,
+ FT_Int coord )
+ {
+ PSH2_Zone zone;
+
+
+ zone = table->zone;
+
+ if ( coord < zone->min )
+ {
+ do
+ {
+ if ( zone == table->zones )
+ break;
+
+ zone--;
+
+ } while ( coord < zone->min );
+ table->zone = zone;
+ }
+ else if ( coord > zone->max )
+ {
+ do
+ {
+ if ( zone == table->zones + table->num_zones - 1 )
+ break;
+
+ zone++;
+
+ } while ( coord > zone->max );
+ table->zone = zone;
+ }
+
+ return FT_MulFix( coord, zone->scale ) + zone->delta;
+ }
+#endif
+
+#if 0
+ /* tune a given outline with current interpolation zones */
+ /* the function only works in a single dimension.. */
+ static void
+ psh2_hint_table_tune_outline( PSH2_Hint_Table table,
+ FT_Outline* outline,
+ PSH_Globals globals,
+ FT_Int dimension )
+
+ {
+ FT_UInt count, first, last;
+ PS_Mask_Table hint_masks = table->hint_masks;
+ PS_Mask mask;
+ PSH_Dimension dim = &globals->dimension[dimension];
+ FT_Fixed scale = dim->scale_mult;
+ FT_Fixed delta = dim->scale_delta;
+
+
+ if ( hint_masks && hint_masks->num_masks > 0 )
+ {
+ first = 0;
+ mask = hint_masks->masks;
+ count = hint_masks->num_masks;
+
+ for ( ; count > 0; count--, mask++ )
+ {
+ last = mask->end_point;
+
+ if ( last > first )
+ {
+ FT_Vector* vec;
+ FT_Int count2;
+
+
+ psh2_hint_table_activate_mask( table, mask );
+ psh2_hint_table_optimize( table, globals, outline, dimension );
+ psh2_hint_table_setup_zones( table, scale, delta );
+ last = mask->end_point;
+
+ vec = outline->points + first;
+ count2 = last - first;
+
+ for ( ; count2 > 0; count2--, vec++ )
+ {
+ FT_Pos x, *px;
+
+
+ px = dimension ? &vec->y : &vec->x;
+ x = *px;
+
+ *px = psh2_hint_table_tune_coord( table, (FT_Int)x );
+ }
+ }
+
+ first = last;
+ }
+ }
+ else /* no hints in this glyph, simply scale the outline */
+ {
+ FT_Vector* vec;
+
+
+ vec = outline->points;
+ count = outline->n_points;
+
+ if ( dimension == 0 )
+ {
+ for ( ; count > 0; count--, vec++ )
+ vec->x = FT_MulFix( vec->x, scale ) + delta;
+ }
+ else
+ {
+ for ( ; count > 0; count--, vec++ )
+ vec->y = FT_MulFix( vec->y, scale ) + delta;
+ }
+ }
+ }
+#endif
+
+
+ /*************************************************************************/
+ /*************************************************************************/
+ /***** *****/
+ /***** HINTER GLYPH MANAGEMENT *****/
+ /***** *****/
+ /*************************************************************************/
+ /*************************************************************************/
+
+ static int
+ psh2_point_is_extremum( PSH2_Point point )
+ {
+ PSH2_Point before = point;
+ PSH2_Point after = point;
+ FT_Pos d_before;
+ FT_Pos d_after;
+
+
+ do
+ {
+ before = before->prev;
+ if ( before == point )
+ return 0;
+
+ d_before = before->org_u - point->org_u;
+
+ } while ( d_before == 0 );
+
+ do
+ {
+ after = after->next;
+ if ( after == point )
+ return 0;
+
+ d_after = after->org_u - point->org_u;
+
+ } while ( d_after == 0 );
+
+ return ( ( d_before > 0 && d_after > 0 ) ||
+ ( d_before < 0 && d_after < 0 ) );
+ }
+
+
+ static void
+ psh2_glyph_done( PSH2_Glyph glyph )
+ {
+ FT_Memory memory = glyph->memory;
+
+
+ psh2_hint_table_done( &glyph->hint_tables[1], memory );
+ psh2_hint_table_done( &glyph->hint_tables[0], memory );
+
+ FT_FREE( glyph->points );
+ FT_FREE( glyph->contours );
+
+ glyph->num_points = 0;
+ glyph->num_contours = 0;
+
+ glyph->memory = 0;
+ }
+
+
+ static int
+ psh2_compute_dir( FT_Pos dx,
+ FT_Pos dy )
+ {
+ FT_Pos ax, ay;
+ int result = PSH2_DIR_NONE;
+
+
+ ax = ( dx >= 0 ) ? dx : -dx;
+ ay = ( dy >= 0 ) ? dy : -dy;
+
+ if ( ay * 12 < ax )
+ {
+ /* |dy| <<< |dx| means a near-horizontal segment */
+ result = ( dx >= 0 ) ? PSH2_DIR_RIGHT : PSH2_DIR_LEFT;
+ }
+ else if ( ax * 12 < ay )
+ {
+ /* |dx| <<< |dy| means a near-vertical segment */
+ result = ( dy >= 0 ) ? PSH2_DIR_UP : PSH2_DIR_DOWN;
+ }
+
+ return result;
+ }
+
+
+ static FT_Error
+ psh2_glyph_init( PSH2_Glyph glyph,
+ FT_Outline* outline,
+ PS_Hints ps_hints,
+ PSH_Globals globals )
+ {
+ FT_Error error;
+ FT_Memory memory;
+
+
+ /* clear all fields */
+ FT_MEM_ZERO( glyph, sizeof ( *glyph ) );
+
+ memory = globals->memory;
+
+ /* allocate and setup points + contours arrays */
+ if ( FT_NEW_ARRAY( glyph->points, outline->n_points ) ||
+ FT_NEW_ARRAY( glyph->contours, outline->n_contours ) )
+ goto Exit;
+
+ glyph->num_points = outline->n_points;
+ glyph->num_contours = outline->n_contours;
+
+ {
+ FT_UInt first = 0, next, n;
+ PSH2_Point points = glyph->points;
+ PSH2_Contour contour = glyph->contours;
+
+
+ for ( n = 0; n < glyph->num_contours; n++ )
+ {
+ FT_Int count;
+ PSH2_Point point;
+
+
+ next = outline->contours[n] + 1;
+ count = next - first;
+
+ contour->start = points + first;
+ contour->count = (FT_UInt)count;
+
+ if ( count > 0 )
+ {
+ point = points + first;
+
+ point->prev = points + next - 1;
+ point->contour = contour;
+
+ for ( ; count > 1; count-- )
+ {
+ point[0].next = point + 1;
+ point[1].prev = point;
+ point++;
+ point->contour = contour;
+ }
+ point->next = points + first;
+ }
+
+ contour++;
+ first = next;
+ }
+ }
+
+ {
+ PSH2_Point points = glyph->points;
+ PSH2_Point point = points;
+ FT_Vector* vec = outline->points;
+ FT_UInt n;
+
+
+ for ( n = 0; n < glyph->num_points; n++, point++ )
+ {
+ FT_Int n_prev = point->prev - points;
+ FT_Int n_next = point->next - points;
+ FT_Pos dxi, dyi, dxo, dyo;
+
+
+ if ( !( outline->tags[n] & FT_CURVE_TAG_ON ) )
+ point->flags = PSH2_POINT_OFF;
+
+ dxi = vec[n].x - vec[n_prev].x;
+ dyi = vec[n].y - vec[n_prev].y;
+
+ point->dir_in = (FT_Char)psh2_compute_dir( dxi, dyi );
+
+ dxo = vec[n_next].x - vec[n].x;
+ dyo = vec[n_next].y - vec[n].y;
+
+ point->dir_out = (FT_Char)psh2_compute_dir( dxo, dyo );
+
+ /* detect smooth points */
+ if ( point->flags & PSH2_POINT_OFF )
+ point->flags |= PSH2_POINT_SMOOTH;
+ else if ( point->dir_in != PSH2_DIR_NONE ||
+ point->dir_out != PSH2_DIR_NONE )
+ {
+ if ( point->dir_in == point->dir_out )
+ point->flags |= PSH2_POINT_SMOOTH;
+ }
+ else
+ {
+ FT_Angle angle_in, angle_out, diff;
+
+
+ angle_in = FT_Atan2( dxi, dyi );
+ angle_out = FT_Atan2( dxo, dyo );
+
+ diff = angle_in - angle_out;
+ if ( diff < 0 )
+ diff = -diff;
+
+ if ( diff > FT_ANGLE_PI )
+ diff = FT_ANGLE_2PI - diff;
+
+ if ( diff < FT_ANGLE_PI / 16 )
+ point->flags |= PSH2_POINT_SMOOTH;
+ }
+ }
+ }
+
+ glyph->memory = memory;
+ glyph->outline = outline;
+ glyph->globals = globals;
+
+ /* now deal with hints tables */
+ error = psh2_hint_table_init( &glyph->hint_tables [0],
+ &ps_hints->dimension[0].hints,
+ &ps_hints->dimension[0].masks,
+ &ps_hints->dimension[0].counters,
+ memory );
+ if ( error )
+ goto Exit;
+
+ error = psh2_hint_table_init( &glyph->hint_tables [1],
+ &ps_hints->dimension[1].hints,
+ &ps_hints->dimension[1].masks,
+ &ps_hints->dimension[1].counters,
+ memory );
+ if ( error )
+ goto Exit;
+
+ Exit:
+ return error;
+ }
+
+
+ /* load outline point coordinates into hinter glyph */
+ static void
+ psh2_glyph_load_points( PSH2_Glyph glyph,
+ FT_Int dimension )
+ {
+ FT_Vector* vec = glyph->outline->points;
+ PSH2_Point point = glyph->points;
+ FT_UInt count = glyph->num_points;
+
+
+ for ( ; count > 0; count--, point++, vec++ )
+ {
+ point->flags &= PSH2_POINT_OFF | PSH2_POINT_SMOOTH;
+ point->hint = 0;
+ if ( dimension == 0 )
+ point->org_u = vec->x;
+ else
+ point->org_u = vec->y;
+
+#ifdef DEBUG_HINTER
+ point->org_x = vec->x;
+ point->org_y = vec->y;
+#endif
+ }
+ }
+
+
+ /* save hinted point coordinates back to outline */
+ static void
+ psh2_glyph_save_points( PSH2_Glyph glyph,
+ FT_Int dimension )
+ {
+ FT_UInt n;
+ PSH2_Point point = glyph->points;
+ FT_Vector* vec = glyph->outline->points;
+ char* tags = glyph->outline->tags;
+
+
+ for ( n = 0; n < glyph->num_points; n++ )
+ {
+ if ( dimension == 0 )
+ vec[n].x = point->cur_u;
+ else
+ vec[n].y = point->cur_u;
+
+ if ( psh2_point_is_strong( point ) )
+ tags[n] |= (char)( ( dimension == 0 ) ? 32 : 64 );
+
+#ifdef DEBUG_HINTER
+ if ( dimension == 0 )
+ {
+ point->cur_x = point->cur_u;
+ point->flags_x = point->flags;
+ }
+ else
+ {
+ point->cur_y = point->cur_u;
+ point->flags_y = point->flags;
+ }
+#endif
+ point++;
+ }
+ }
+
+
+#define PSH2_STRONG_THRESHOLD 10
+
+
+ static void
+ psh2_hint_table_find_strong_point( PSH2_Hint_Table table,
+ PSH2_Point point,
+ FT_Int major_dir )
+ {
+ PSH2_Hint* sort = table->sort;
+ FT_UInt num_hints = table->num_hints;
+
+
+ for ( ; num_hints > 0; num_hints--, sort++ )
+ {
+ PSH2_Hint hint = sort[0];
+
+
+ if ( ABS( point->dir_in ) == major_dir ||
+ ABS( point->dir_out ) == major_dir )
+ {
+ FT_Pos d;
+
+
+ d = point->org_u - hint->org_pos;
+ if ( ABS( d ) < PSH2_STRONG_THRESHOLD )
+ {
+ Is_Strong:
+ psh2_point_set_strong( point );
+ point->hint = hint;
+ break;
+ }
+
+ d -= hint->org_len;
+ if ( ABS( d ) < PSH2_STRONG_THRESHOLD )
+ goto Is_Strong;
+ }
+
+#if 1
+ if ( point->org_u >= hint->org_pos &&
+ point->org_u <= hint->org_pos + hint->org_len &&
+ psh2_point_is_extremum( point ) )
+ {
+ /* attach to hint, but don't mark as strong */
+ point->hint = hint;
+ break;
+ }
+#endif
+ }
+ }
+
+
+ /* find strong points in a glyph */
+ static void
+ psh2_glyph_find_strong_points( PSH2_Glyph glyph,
+ FT_Int dimension )
+ {
+ /* a point is strong if it is located on a stem */
+ /* edge and has an "in" or "out" tangent to the hint's direction */
+ {
+ PSH2_Hint_Table table = &glyph->hint_tables[dimension];
+ PS_Mask mask = table->hint_masks->masks;
+ FT_UInt num_masks = table->hint_masks->num_masks;
+ FT_UInt first = 0;
+ FT_Int major_dir = dimension == 0 ? PSH2_DIR_UP : PSH2_DIR_RIGHT;
+
+
+ /* process secondary hints to "selected" points */
+ if ( num_masks > 1 && glyph->num_points > 0 )
+ {
+ first = mask->end_point;
+ mask++;
+ for ( ; num_masks > 1; num_masks--, mask++ )
+ {
+ FT_UInt next;
+ FT_Int count;
+
+
+ next = mask->end_point;
+ count = next - first;
+ if ( count > 0 )
+ {
+ PSH2_Point point = glyph->points + first;
+
+
+ psh2_hint_table_activate_mask( table, mask );
+
+ for ( ; count > 0; count--, point++ )
+ psh2_hint_table_find_strong_point( table, point, major_dir );
+ }
+ first = next;
+ }
+ }
+
+ /* process primary hints for all points */
+ if ( num_masks == 1 )
+ {
+ FT_UInt count = glyph->num_points;
+ PSH2_Point point = glyph->points;
+
+
+ psh2_hint_table_activate_mask( table, table->hint_masks->masks );
+ for ( ; count > 0; count--, point++ )
+ {
+ if ( !psh2_point_is_strong( point ) )
+ psh2_hint_table_find_strong_point( table, point, major_dir );
+ }
+ }
+
+ /* now, certain points may have been attached to hint and */
+ /* not marked as strong; update their flags then */
+ {
+ FT_UInt count = glyph->num_points;
+ PSH2_Point point = glyph->points;
+
+
+ for ( ; count > 0; count--, point++ )
+ if ( point->hint && !psh2_point_is_strong( point ) )
+ psh2_point_set_strong( point );
+ }
+ }
+ }
+
+
+ /* interpolate strong points with the help of hinted coordinates */
+ static void
+ psh2_glyph_interpolate_strong_points( PSH2_Glyph glyph,
+ FT_Int dimension )
+ {
+ PSH_Dimension dim = &glyph->globals->dimension[dimension];
+ FT_Fixed scale = dim->scale_mult;
+
+
+ {
+ FT_UInt count = glyph->num_points;
+ PSH2_Point point = glyph->points;
+
+
+ for ( ; count > 0; count--, point++ )
+ {
+ PSH2_Hint hint = point->hint;
+
+
+ if ( hint )
+ {
+ FT_Pos delta;
+
+
+ delta = point->org_u - hint->org_pos;
+
+ if ( delta <= 0 )
+ point->cur_u = hint->cur_pos + FT_MulFix( delta, scale );
+
+ else if ( delta >= hint->org_len )
+ point->cur_u = hint->cur_pos + hint->cur_len +
+ FT_MulFix( delta - hint->org_len, scale );
+
+ else if ( hint->org_len > 0 )
+ point->cur_u = hint->cur_pos +
+ FT_MulDiv( delta, hint->cur_len, hint->org_len );
+ else
+ point->cur_u = hint->cur_pos;
+
+ psh2_point_set_fitted( point );
+ }
+ }
+ }
+ }
+
+
+ static void
+ psh2_glyph_interpolate_normal_points( PSH2_Glyph glyph,
+ FT_Int dimension )
+ {
+#if 1
+ PSH_Dimension dim = &glyph->globals->dimension[dimension];
+ FT_Fixed scale = dim->scale_mult;
+
+
+ /* first technique: a point is strong if it is a local extrema */
+ {
+ FT_UInt count = glyph->num_points;
+ PSH2_Point point = glyph->points;
+
+
+ for ( ; count > 0; count--, point++ )
+ {
+ if ( psh2_point_is_strong( point ) )
+ continue;
+
+ /* sometimes, some local extremas are smooth points */
+ if ( psh2_point_is_smooth( point ) )
+ {
+ if ( point->dir_in == PSH2_DIR_NONE ||
+ point->dir_in != point->dir_out )
+ continue;
+
+ if ( !psh2_point_is_extremum( point ) )
+ continue;
+
+ point->flags &= ~PSH2_POINT_SMOOTH;
+ }
+
+ /* find best enclosing point coordinates */
+ {
+ PSH2_Point before = 0;
+ PSH2_Point after = 0;
+
+ FT_Pos diff_before = -32000;
+ FT_Pos diff_after = 32000;
+ FT_Pos u = point->org_u;
+
+ FT_Int count2 = glyph->num_points;
+ PSH2_Point cur = glyph->points;
+
+
+ for ( ; count2 > 0; count2--, cur++ )
+ {
+ if ( psh2_point_is_strong( cur ) )
+ {
+ FT_Pos diff = cur->org_u - u;;
+
+
+ if ( diff <= 0 )
+ {
+ if ( diff > diff_before )
+ {
+ diff_before = diff;
+ before = cur;
+ }
+ }
+ else if ( diff >= 0 )
+ {
+ if ( diff < diff_after )
+ {
+ diff_after = diff;
+ after = cur;
+ }
+ }
+ }
+ }
+
+ if ( !before )
+ {
+ if ( !after )
+ continue;
+
+ /* we are before the first strong point coordinate; */
+ /* simply translate the point */
+ point->cur_u = after->cur_u +
+ FT_MulFix( point->org_u - after->org_u, scale );
+ }
+ else if ( !after )
+ {
+ /* we are after the last strong point coordinate; */
+ /* simply translate the point */
+ point->cur_u = before->cur_u +
+ FT_MulFix( point->org_u - before->org_u, scale );
+ }
+ else
+ {
+ if ( diff_before == 0 )
+ point->cur_u = before->cur_u;
+
+ else if ( diff_after == 0 )
+ point->cur_u = after->cur_u;
+
+ else
+ point->cur_u = before->cur_u +
+ FT_MulDiv( u - before->org_u,
+ after->cur_u - before->cur_u,
+ after->org_u - before->org_u );
+ }
+
+ psh2_point_set_fitted( point );
+ }
+ }
+ }
+#endif
+ }
+
+
+ /* interpolate other points */
+ static void
+ psh2_glyph_interpolate_other_points( PSH2_Glyph glyph,
+ FT_Int dimension )
+ {
+ PSH_Dimension dim = &glyph->globals->dimension[dimension];
+ FT_Fixed scale = dim->scale_mult;
+ FT_Fixed delta = dim->scale_delta;
+ PSH2_Contour contour = glyph->contours;
+ FT_UInt num_contours = glyph->num_contours;
+
+
+ for ( ; num_contours > 0; num_contours--, contour++ )
+ {
+ PSH2_Point start = contour->start;
+ PSH2_Point first, next, point;
+ FT_UInt fit_count;
+
+
+ /* count the number of strong points in this contour */
+ next = start + contour->count;
+ fit_count = 0;
+ first = 0;
+
+ for ( point = start; point < next; point++ )
+ if ( psh2_point_is_fitted( point ) )
+ {
+ if ( !first )
+ first = point;
+
+ fit_count++;
+ }
+
+ /* if there are less than 2 fitted points in the contour, we */
+ /* simply scale and eventually translate the contour points */
+ if ( fit_count < 2 )
+ {
+ if ( fit_count == 1 )
+ delta = first->cur_u - FT_MulFix( first->org_u, scale );
+
+ for ( point = start; point < next; point++ )
+ if ( point != first )
+ point->cur_u = FT_MulFix( point->org_u, scale ) + delta;
+
+ goto Next_Contour;
+ }
+
+ /* there are more than 2 strong points in this contour; we */
+ /* need to interpolate weak points between them */
+ start = first;
+ do
+ {
+ point = first;
+
+ /* skip consecutive fitted points */
+ for (;;)
+ {
+ next = first->next;
+ if ( next == start )
+ goto Next_Contour;
+
+ if ( !psh2_point_is_fitted( next ) )
+ break;
+
+ first = next;
+ }
+
+ /* find next fitted point after unfitted one */
+ for (;;)
+ {
+ next = next->next;
+ if ( psh2_point_is_fitted( next ) )
+ break;
+ }
+
+ /* now interpolate between them */
+ {
+ FT_Pos org_a, org_ab, cur_a, cur_ab;
+ FT_Pos org_c, org_ac, cur_c;
+ FT_Fixed scale_ab;
+
+
+ if ( first->org_u <= next->org_u )
+ {
+ org_a = first->org_u;
+ cur_a = first->cur_u;
+ org_ab = next->org_u - org_a;
+ cur_ab = next->cur_u - cur_a;
+ }
+ else
+ {
+ org_a = next->org_u;
+ cur_a = next->cur_u;
+ org_ab = first->org_u - org_a;
+ cur_ab = first->cur_u - cur_a;
+ }
+
+ scale_ab = 0x10000L;
+ if ( org_ab > 0 )
+ scale_ab = FT_DivFix( cur_ab, org_ab );
+
+ point = first->next;
+ do
+ {
+ org_c = point->org_u;
+ org_ac = org_c - org_a;
+
+ if ( org_ac <= 0 )
+ {
+ /* on the left of the interpolation zone */
+ cur_c = cur_a + FT_MulFix( org_ac, scale );
+ }
+ else if ( org_ac >= org_ab )
+ {
+ /* on the right on the interpolation zone */
+ cur_c = cur_a + cur_ab + FT_MulFix( org_ac - org_ab, scale );
+ }
+ else
+ {
+ /* within the interpolation zone */
+ cur_c = cur_a + FT_MulFix( org_ac, scale_ab );
+ }
+
+ point->cur_u = cur_c;
+
+ point = point->next;
+
+ } while ( point != next );
+ }
+
+ /* keep going until all points in the contours have been processed */
+ first = next;
+
+ } while ( first != start );
+
+ Next_Contour:
+ ;
+ }
+ }
+
+
+ /*************************************************************************/
+ /*************************************************************************/
+ /***** *****/
+ /***** HIGH-LEVEL INTERFACE *****/
+ /***** *****/
+ /*************************************************************************/
+ /*************************************************************************/
+
+ FT_Error
+ ps2_hints_apply( PS_Hints ps_hints,
+ FT_Outline* outline,
+ PSH_Globals globals,
+ FT_Render_Mode hint_mode )
+ {
+ PSH2_GlyphRec glyphrec;
+ PSH2_Glyph glyph = &glyphrec;
+ FT_Error error;
+#ifdef DEBUG_HINTER
+ FT_Memory memory;
+#endif
+ FT_Int dimension;
+
+ FT_UNUSED( hint_mode );
+
+#ifdef DEBUG_HINTER
+ memory = globals->memory;
+
+ if ( ps2_debug_glyph )
+ {
+ psh2_glyph_done( ps2_debug_glyph );
+ FT_FREE( ps2_debug_glyph );
+ }
+
+ if ( FT_NEW( glyph ) )
+ return error;
+
+ ps2_debug_glyph = glyph;
+#endif
+
+ error = psh2_glyph_init( glyph, outline, ps_hints, globals );
+ if ( error )
+ goto Exit;
+
+ for ( dimension = 0; dimension < 2; dimension++ )
+ {
+ /* load outline coordinates into glyph */
+ psh2_glyph_load_points( glyph, dimension );
+
+ /* compute aligned stem/hints positions */
+ psh2_hint_table_align_hints( &glyph->hint_tables[dimension],
+ glyph->globals,
+ dimension );
+
+ /* find strong points, align them, then interpolate others */
+ psh2_glyph_find_strong_points( glyph, dimension );
+ psh2_glyph_interpolate_strong_points( glyph, dimension );
+ psh2_glyph_interpolate_normal_points( glyph, dimension );
+ psh2_glyph_interpolate_other_points( glyph, dimension );
+
+ /* save hinted coordinates back to outline */
+ psh2_glyph_save_points( glyph, dimension );
+ }
+
+ Exit:
+#ifndef DEBUG_HINTER
+ psh2_glyph_done( glyph );
+#endif
+ return error;
+ }
+
+
+/* END */
--- /dev/null
+++ b/libfreetype/pshalgo2.h
@@ -1,0 +1,203 @@
+/***************************************************************************/
+/* */
+/* pshalgo2.h */
+/* */
+/* PostScript hinting algorithm 2 (specification). */
+/* */
+/* Copyright 2001 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+
+#ifndef __PSHALGO2_H__
+#define __PSHALGO2_H__
+
+
+#include "pshrec.h"
+#include "pshglob.h"
+#include FT_TRIGONOMETRY_H
+
+
+FT_BEGIN_HEADER
+
+
+ typedef struct PSH2_HintRec_* PSH2_Hint;
+
+ typedef enum
+ {
+ PSH2_HINT_GHOST = PS_HINT_FLAG_GHOST,
+ PSH2_HINT_BOTTOM = PS_HINT_FLAG_BOTTOM,
+ PSH2_HINT_ACTIVE = 4,
+ PSH2_HINT_FITTED = 8
+
+ } PSH2_Hint_Flags;
+
+
+#define psh2_hint_is_active( x ) ( ( (x)->flags & PSH2_HINT_ACTIVE ) != 0 )
+#define psh2_hint_is_ghost( x ) ( ( (x)->flags & PSH2_HINT_GHOST ) != 0 )
+#define psh2_hint_is_fitted( x ) ( ( (x)->flags & PSH2_HINT_FITTED ) != 0 )
+
+#define psh2_hint_activate( x ) (x)->flags |= PSH2_HINT_ACTIVE
+#define psh2_hint_deactivate( x ) (x)->flags &= ~PSH2_HINT_ACTIVE
+#define psh2_hint_set_fitted( x ) (x)->flags |= PSH2_HINT_FITTED
+
+
+ typedef struct PSH2_HintRec_
+ {
+ FT_Int org_pos;
+ FT_Int org_len;
+ FT_Pos cur_pos;
+ FT_Pos cur_len;
+ FT_UInt flags;
+ PSH2_Hint parent;
+ FT_Int order;
+
+ } PSH2_HintRec;
+
+
+ /* this is an interpolation zone used for strong points; */
+ /* weak points are interpolated according to their strong */
+ /* neighbours */
+ typedef struct PSH2_ZoneRec_
+ {
+ FT_Fixed scale;
+ FT_Fixed delta;
+ FT_Pos min;
+ FT_Pos max;
+
+ } PSH2_ZoneRec, *PSH2_Zone;
+
+
+ typedef struct PSH2_Hint_TableRec_
+ {
+ FT_UInt max_hints;
+ FT_UInt num_hints;
+ PSH2_Hint hints;
+ PSH2_Hint* sort;
+ PSH2_Hint* sort_global;
+ FT_UInt num_zones;
+ PSH2_Zone zones;
+ PSH2_Zone zone;
+ PS_Mask_Table hint_masks;
+ PS_Mask_Table counter_masks;
+
+ } PSH2_Hint_TableRec, *PSH2_Hint_Table;
+
+
+ typedef struct PSH2_PointRec_* PSH2_Point;
+ typedef struct PSH2_ContourRec_* PSH2_Contour;
+
+ enum
+ {
+ PSH2_DIR_NONE = 4,
+ PSH2_DIR_UP = 1,
+ PSH2_DIR_DOWN = -1,
+ PSH2_DIR_LEFT = -2,
+ PSH2_DIR_RIGHT = 2
+ };
+
+ enum
+ {
+ PSH2_POINT_OFF = 1, /* point is off the curve */
+ PSH2_POINT_STRONG = 2, /* point is strong */
+ PSH2_POINT_SMOOTH = 4, /* point is smooth */
+ PSH2_POINT_FITTED = 8 /* point is already fitted */
+ };
+
+
+ typedef struct PSH2_PointRec_
+ {
+ PSH2_Point prev;
+ PSH2_Point next;
+ PSH2_Contour contour;
+ FT_UInt flags;
+ FT_Char dir_in;
+ FT_Char dir_out;
+ FT_Angle angle_in;
+ FT_Angle angle_out;
+ PSH2_Hint hint;
+ FT_Pos org_u;
+ FT_Pos cur_u;
+#ifdef DEBUG_HINTER
+ FT_Pos org_x;
+ FT_Pos cur_x;
+ FT_Pos org_y;
+ FT_Pos cur_y;
+ FT_UInt flags_x;
+ FT_UInt flags_y;
+#endif
+
+ } PSH2_PointRec;
+
+
+#define psh2_point_is_strong( p ) ( (p)->flags & PSH2_POINT_STRONG )
+#define psh2_point_is_fitted( p ) ( (p)->flags & PSH2_POINT_FITTED )
+#define psh2_point_is_smooth( p ) ( (p)->flags & PSH2_POINT_SMOOTH )
+
+#define psh2_point_set_strong( p ) (p)->flags |= PSH2_POINT_STRONG
+#define psh2_point_set_fitted( p ) (p)->flags |= PSH2_POINT_FITTED
+#define psh2_point_set_smooth( p ) (p)->flags |= PSH2_POINT_SMOOTH
+
+
+ typedef struct PSH2_ContourRec_
+ {
+ PSH2_Point start;
+ FT_UInt count;
+
+ } PSH2_ContourRec;
+
+
+ typedef struct PSH2_GlyphRec_
+ {
+ FT_UInt num_points;
+ FT_UInt num_contours;
+
+ PSH2_Point points;
+ PSH2_Contour contours;
+
+ FT_Memory memory;
+ FT_Outline* outline;
+ PSH_Globals globals;
+ PSH2_Hint_TableRec hint_tables[2];
+
+ FT_Bool vertical;
+ FT_Int major_dir;
+ FT_Int minor_dir;
+
+ } PSH2_GlyphRec, *PSH2_Glyph;
+
+
+#ifdef DEBUG_HINTER
+ extern PSH2_Hint_Table ps2_debug_hint_table;
+
+ typedef void
+ (*PSH2_HintFunc)( PSH2_Hint hint,
+ FT_Bool vertical );
+
+ extern PSH2_HintFunc ps2_debug_hint_func;
+
+ extern PSH2_Glyph ps2_debug_glyph;
+#endif
+
+
+ extern FT_Error
+ ps2_hints_apply( PS_Hints ps_hints,
+ FT_Outline* outline,
+ PSH_Globals globals,
+ FT_Render_Mode hint_mode );
+
+
+FT_END_HEADER
+
+
+#endif /* __PSHALGO2_H__ */
+
+
+/* END */
--- /dev/null
+++ b/libfreetype/pshalgo3.c
@@ -1,0 +1,1757 @@
+/***************************************************************************/
+/* */
+/* pshalgo3.c */
+/* */
+/* PostScript hinting algorithm 3 (body). */
+/* */
+/* Copyright 2001, 2002 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used */
+/* modified and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+
+#include <ft2build.h>
+#include FT_INTERNAL_OBJECTS_H
+#include FT_INTERNAL_DEBUG_H
+#include "pshalgo3.h"
+
+
+#undef FT_COMPONENT
+#define FT_COMPONENT trace_pshalgo2
+
+
+#ifdef DEBUG_HINTER
+ PSH3_Hint_Table ps3_debug_hint_table = 0;
+ PSH3_HintFunc ps3_debug_hint_func = 0;
+ PSH3_Glyph ps3_debug_glyph = 0;
+#endif
+
+
+#define COMPUTE_INFLEXS /* compute inflection points to optimize "S" and others */
+#define STRONGER /* slightly increase the contrast of smooth hinting */
+
+ /*************************************************************************/
+ /*************************************************************************/
+ /***** *****/
+ /***** BASIC HINTS RECORDINGS *****/
+ /***** *****/
+ /*************************************************************************/
+ /*************************************************************************/
+
+ /* return true iff two stem hints overlap */
+ static FT_Int
+ psh3_hint_overlap( PSH3_Hint hint1,
+ PSH3_Hint hint2 )
+ {
+ return ( hint1->org_pos + hint1->org_len >= hint2->org_pos &&
+ hint2->org_pos + hint2->org_len >= hint1->org_pos );
+ }
+
+
+ /* destroy hints table */
+ static void
+ psh3_hint_table_done( PSH3_Hint_Table table,
+ FT_Memory memory )
+ {
+ FT_FREE( table->zones );
+ table->num_zones = 0;
+ table->zone = 0;
+
+ FT_FREE( table->sort );
+ FT_FREE( table->hints );
+ table->num_hints = 0;
+ table->max_hints = 0;
+ table->sort_global = 0;
+ }
+
+
+ /* deactivate all hints in a table */
+ static void
+ psh3_hint_table_deactivate( PSH3_Hint_Table table )
+ {
+ FT_UInt count = table->max_hints;
+ PSH3_Hint hint = table->hints;
+
+
+ for ( ; count > 0; count--, hint++ )
+ {
+ psh3_hint_deactivate( hint );
+ hint->order = -1;
+ }
+ }
+
+
+ /* internal function used to record a new hint */
+ static void
+ psh3_hint_table_record( PSH3_Hint_Table table,
+ FT_UInt idx )
+ {
+ PSH3_Hint hint = table->hints + idx;
+
+
+ if ( idx >= table->max_hints )
+ {
+ FT_ERROR(( "psh3_hint_table_record: invalid hint index %d\n", idx ));
+ return;
+ }
+
+ /* ignore active hints */
+ if ( psh3_hint_is_active( hint ) )
+ return;
+
+ psh3_hint_activate( hint );
+
+ /* now scan the current active hint set in order to determine */
+ /* if we are overlapping with another segment */
+ {
+ PSH3_Hint* sorted = table->sort_global;
+ FT_UInt count = table->num_hints;
+ PSH3_Hint hint2;
+
+
+ hint->parent = 0;
+ for ( ; count > 0; count--, sorted++ )
+ {
+ hint2 = sorted[0];
+
+ if ( psh3_hint_overlap( hint, hint2 ) )
+ {
+ hint->parent = hint2;
+ break;
+ }
+ }
+ }
+
+ if ( table->num_hints < table->max_hints )
+ table->sort_global[table->num_hints++] = hint;
+ else
+ FT_ERROR(( "psh3_hint_table_record: too many sorted hints! BUG!\n" ));
+ }
+
+
+ static void
+ psh3_hint_table_record_mask( PSH3_Hint_Table table,
+ PS_Mask hint_mask )
+ {
+ FT_Int mask = 0, val = 0;
+ FT_Byte* cursor = hint_mask->bytes;
+ FT_UInt idx, limit;
+
+
+ limit = hint_mask->num_bits;
+
+ for ( idx = 0; idx < limit; idx++ )
+ {
+ if ( mask == 0 )
+ {
+ val = *cursor++;
+ mask = 0x80;
+ }
+
+ if ( val & mask )
+ psh3_hint_table_record( table, idx );
+
+ mask >>= 1;
+ }
+ }
+
+
+ /* create hints table */
+ static FT_Error
+ psh3_hint_table_init( PSH3_Hint_Table table,
+ PS_Hint_Table hints,
+ PS_Mask_Table hint_masks,
+ PS_Mask_Table counter_masks,
+ FT_Memory memory )
+ {
+ FT_UInt count = hints->num_hints;
+ FT_Error error;
+
+ FT_UNUSED( counter_masks );
+
+
+ /* allocate our tables */
+ if ( FT_NEW_ARRAY( table->sort, 2 * count ) ||
+ FT_NEW_ARRAY( table->hints, count ) ||
+ FT_NEW_ARRAY( table->zones, 2 * count + 1 ) )
+ goto Exit;
+
+ table->max_hints = count;
+ table->sort_global = table->sort + count;
+ table->num_hints = 0;
+ table->num_zones = 0;
+ table->zone = 0;
+
+ /* now, initialize the "hints" array */
+ {
+ PSH3_Hint write = table->hints;
+ PS_Hint read = hints->hints;
+
+
+ for ( ; count > 0; count--, write++, read++ )
+ {
+ write->org_pos = read->pos;
+ write->org_len = read->len;
+ write->flags = read->flags;
+ }
+ }
+
+ /* we now need to determine the initial "parent" stems; first */
+ /* activate the hints that are given by the initial hint masks */
+ if ( hint_masks )
+ {
+ FT_UInt Count = hint_masks->num_masks;
+ PS_Mask Mask = hint_masks->masks;
+
+
+ table->hint_masks = hint_masks;
+
+ for ( ; Count > 0; Count--, Mask++ )
+ psh3_hint_table_record_mask( table, Mask );
+ }
+
+ /* now, do a linear parse in case some hints were left alone */
+ if ( table->num_hints != table->max_hints )
+ {
+ FT_UInt Index, Count;
+
+
+ FT_ERROR(( "psh3_hint_table_init: missing/incorrect hint masks!\n" ));
+ Count = table->max_hints;
+ for ( Index = 0; Index < Count; Index++ )
+ psh3_hint_table_record( table, Index );
+ }
+
+ Exit:
+ return error;
+ }
+
+
+ static void
+ psh3_hint_table_activate_mask( PSH3_Hint_Table table,
+ PS_Mask hint_mask )
+ {
+ FT_Int mask = 0, val = 0;
+ FT_Byte* cursor = hint_mask->bytes;
+ FT_UInt idx, limit, count;
+
+
+ limit = hint_mask->num_bits;
+ count = 0;
+
+ psh3_hint_table_deactivate( table );
+
+ for ( idx = 0; idx < limit; idx++ )
+ {
+ if ( mask == 0 )
+ {
+ val = *cursor++;
+ mask = 0x80;
+ }
+
+ if ( val & mask )
+ {
+ PSH3_Hint hint = &table->hints[idx];
+
+
+ if ( !psh3_hint_is_active( hint ) )
+ {
+ FT_UInt count2;
+
+#if 0
+ PSH3_Hint* sort = table->sort;
+ PSH3_Hint hint2;
+
+
+ for ( count2 = count; count2 > 0; count2--, sort++ )
+ {
+ hint2 = sort[0];
+ if ( psh3_hint_overlap( hint, hint2 ) )
+ FT_ERROR(( "psh3_hint_table_activate_mask:"
+ " found overlapping hints\n" ))
+ }
+#else
+ count2 = 0;
+#endif
+
+ if ( count2 == 0 )
+ {
+ psh3_hint_activate( hint );
+ if ( count < table->max_hints )
+ table->sort[count++] = hint;
+ else
+ FT_ERROR(( "psh3_hint_tableactivate_mask:"
+ " too many active hints\n" ));
+ }
+ }
+ }
+
+ mask >>= 1;
+ }
+ table->num_hints = count;
+
+ /* now, sort the hints; they are guaranteed to not overlap */
+ /* so we can compare their "org_pos" field directly */
+ {
+ FT_Int i1, i2;
+ PSH3_Hint hint1, hint2;
+ PSH3_Hint* sort = table->sort;
+
+
+ /* a simple bubble sort will do, since in 99% of cases, the hints */
+ /* will be already sorted -- and the sort will be linear */
+ for ( i1 = 1; i1 < (FT_Int)count; i1++ )
+ {
+ hint1 = sort[i1];
+ for ( i2 = i1 - 1; i2 >= 0; i2-- )
+ {
+ hint2 = sort[i2];
+
+ if ( hint2->org_pos < hint1->org_pos )
+ break;
+
+ sort[i2 + 1] = hint2;
+ sort[i2] = hint1;
+ }
+ }
+ }
+ }
+
+
+ /*************************************************************************/
+ /*************************************************************************/
+ /***** *****/
+ /***** HINTS GRID-FITTING AND OPTIMIZATION *****/
+ /***** *****/
+ /*************************************************************************/
+ /*************************************************************************/
+
+ static FT_Pos
+ psh3_dimension_quantize_len( PSH_Dimension dim,
+ FT_Pos len,
+ FT_Bool do_snapping )
+ {
+ if ( len <= 64 )
+ len = 64;
+ else
+ {
+ FT_Pos delta = len - dim->stdw.widths[0].cur;
+
+
+ if ( delta < 0 )
+ delta = -delta;
+
+ if ( delta < 40 )
+ {
+ len = dim->stdw.widths[0].cur;
+ if ( len < 48 )
+ len = 48;
+ }
+
+ if ( len < 3 * 64 )
+ {
+ delta = ( len & 63 );
+ len &= -64;
+
+ if ( delta < 10 )
+ len += delta;
+
+ else if ( delta < 32 )
+ len += 10;
+
+ else if ( delta < 54 )
+ len += 54;
+
+ else
+ len += delta;
+ }
+ else
+ len = ( len + 32 ) & -64;
+ }
+
+ if ( do_snapping )
+ len = ( len + 32 ) & -64;
+
+ return len;
+ }
+
+
+#ifdef DEBUG_HINTER
+
+ static void
+ ps3_simple_scale( PSH3_Hint_Table table,
+ FT_Fixed scale,
+ FT_Fixed delta,
+ FT_Int dimension )
+ {
+ PSH3_Hint hint;
+ FT_UInt count;
+
+
+ for ( count = 0; count < table->max_hints; count++ )
+ {
+ hint = table->hints + count;
+
+ hint->cur_pos = FT_MulFix( hint->org_pos, scale ) + delta;
+ hint->cur_len = FT_MulFix( hint->org_len, scale );
+
+ if ( ps3_debug_hint_func )
+ ps3_debug_hint_func( hint, dimension );
+ }
+ }
+
+#endif /* DEBUG_HINTER */
+
+
+ static FT_Fixed
+ psh3_hint_snap_stem_side_delta( FT_Fixed pos,
+ FT_Fixed len )
+ {
+ FT_Fixed delta1 = ( ( pos + 32 ) & -64 ) - pos;
+ FT_Fixed delta2 = ( ( pos + len + 32 ) & -64 ) - pos - len;
+
+
+ if ( ABS( delta1 ) <= ABS( delta2 ) )
+ return delta1;
+ else
+ return delta2;
+ }
+
+
+ static void
+ psh3_hint_align( PSH3_Hint hint,
+ PSH_Globals globals,
+ FT_Int dimension,
+ PSH3_Glyph glyph )
+ {
+ PSH_Dimension dim = &globals->dimension[dimension];
+ FT_Fixed scale = dim->scale_mult;
+ FT_Fixed delta = dim->scale_delta;
+
+
+ if ( !psh3_hint_is_fitted( hint ) )
+ {
+ FT_Pos pos = FT_MulFix( hint->org_pos, scale ) + delta;
+ FT_Pos len = FT_MulFix( hint->org_len, scale );
+
+ FT_Int do_snapping;
+ FT_Pos fit_len;
+ PSH_AlignmentRec align;
+
+
+ /* ignore stem alignments when requested through the hint flags */
+ if ( ( dimension == 0 && !glyph->do_horz_hints ) ||
+ ( dimension == 1 && !glyph->do_vert_hints ) )
+ {
+ hint->cur_pos = pos;
+ hint->cur_len = len;
+
+ psh3_hint_set_fitted( hint );
+ return;
+ }
+
+ /* perform stem snapping when requested */
+ do_snapping = ( dimension == 0 && glyph->do_horz_snapping ) ||
+ ( dimension == 1 && glyph->do_vert_snapping );
+
+ hint->cur_len = fit_len = len;
+
+ /* check blue zones for horizontal stems */
+ align.align = PSH_BLUE_ALIGN_NONE;
+ align.align_bot = align.align_top = 0;
+
+ if ( dimension == 1 )
+ psh_blues_snap_stem( &globals->blues,
+ hint->org_pos + hint->org_len,
+ hint->org_pos,
+ &align );
+
+ switch ( align.align )
+ {
+ case PSH_BLUE_ALIGN_TOP:
+ /* the top of the stem is aligned against a blue zone */
+ hint->cur_pos = align.align_top - fit_len;
+ break;
+
+ case PSH_BLUE_ALIGN_BOT:
+ /* the bottom of the stem is aligned against a blue zone */
+ hint->cur_pos = align.align_bot;
+ break;
+
+ case PSH_BLUE_ALIGN_TOP | PSH_BLUE_ALIGN_BOT:
+ /* both edges of the stem are aligned against blue zones */
+ hint->cur_pos = align.align_bot;
+ hint->cur_len = align.align_top - align.align_bot;
+ break;
+
+ default:
+ {
+ PSH3_Hint parent = hint->parent;
+
+
+ if ( parent )
+ {
+ FT_Pos par_org_center, par_cur_center;
+ FT_Pos cur_org_center, cur_delta;
+
+
+ /* ensure that parent is already fitted */
+ if ( !psh3_hint_is_fitted( parent ) )
+ psh3_hint_align( parent, globals, dimension, glyph );
+
+ par_org_center = parent->org_pos + ( parent->org_len >> 1 );
+ par_cur_center = parent->cur_pos + ( parent->cur_len >> 1 );
+ cur_org_center = hint->org_pos + ( hint->org_len >> 1 );
+
+ cur_delta = FT_MulFix( cur_org_center - par_org_center, scale );
+ pos = par_cur_center + cur_delta - ( len >> 1 );
+ }
+
+ hint->cur_pos = pos;
+ hint->cur_len = fit_len;
+
+ if ( len <= 64 )
+ {
+ /* the stem is less than one pixel, we will center it */
+ /* around the nearest pixel center */
+ /* */
+ pos = ( pos + ( (len >> 1) & -64 ) );
+ len = 64;
+ }
+ else
+ {
+ len = psh3_dimension_quantize_len( dim, len, 0 );
+ }
+
+ /* now that we have a good hinted stem width, try to position */
+ /* the stem along a pixel grid integer coordinate */
+ hint->cur_pos = pos + psh3_hint_snap_stem_side_delta( pos, len );
+ hint->cur_len = len;
+ }
+ }
+
+ if ( do_snapping )
+ {
+ pos = hint->cur_pos;
+ len = hint->cur_len;
+
+ if ( len < 64 )
+ len = 64;
+ else
+ len = ( len + 32 ) & -64;
+
+ switch ( align.align )
+ {
+ case PSH_BLUE_ALIGN_TOP:
+ hint->cur_pos = align.align_top - len;
+ hint->cur_len = len;
+ break;
+
+ case PSH_BLUE_ALIGN_BOT:
+ hint->cur_len = len;
+ break;
+
+ case PSH_BLUE_ALIGN_BOT | PSH_BLUE_ALIGN_TOP:
+ /* don't touch */
+ break;
+
+
+ default:
+ hint->cur_len = len;
+ if ( len & 64 )
+ pos = ( ( pos + ( len >> 1 ) ) & -64 ) + 32;
+ else
+ pos = ( pos + ( len >> 1 ) + 32 ) & -64;
+
+ hint->cur_pos = pos - ( len >> 1 );
+ hint->cur_len = len;
+ }
+ }
+
+ psh3_hint_set_fitted( hint );
+
+#ifdef DEBUG_HINTER
+ if ( ps3_debug_hint_func )
+ ps3_debug_hint_func( hint, dimension );
+#endif
+ }
+ }
+
+
+ static void
+ psh3_hint_table_align_hints( PSH3_Hint_Table table,
+ PSH_Globals globals,
+ FT_Int dimension,
+ PSH3_Glyph glyph )
+ {
+ PSH3_Hint hint;
+ FT_UInt count;
+
+#ifdef DEBUG_HINTER
+
+ PSH_Dimension dim = &globals->dimension[dimension];
+ FT_Fixed scale = dim->scale_mult;
+ FT_Fixed delta = dim->scale_delta;
+
+
+ if ( ps_debug_no_vert_hints && dimension == 0 )
+ {
+ ps3_simple_scale( table, scale, delta, dimension );
+ return;
+ }
+
+ if ( ps_debug_no_horz_hints && dimension == 1 )
+ {
+ ps3_simple_scale( table, scale, delta, dimension );
+ return;
+ }
+
+#endif /* DEBUG_HINTER*/
+
+ hint = table->hints;
+ count = table->max_hints;
+
+ for ( ; count > 0; count--, hint++ )
+ psh3_hint_align( hint, globals, dimension, glyph );
+ }
+
+
+ /*************************************************************************/
+ /*************************************************************************/
+ /***** *****/
+ /***** POINTS INTERPOLATION ROUTINES *****/
+ /***** *****/
+ /*************************************************************************/
+ /*************************************************************************/
+
+#define PSH3_ZONE_MIN -3200000L
+#define PSH3_ZONE_MAX +3200000L
+
+#define xxDEBUG_ZONES
+
+
+#ifdef DEBUG_ZONES
+
+#include <stdio.h>
+
+ static void
+ psh3_print_zone( PSH3_Zone zone )
+ {
+ printf( "zone [scale,delta,min,max] = [%.3f,%.3f,%d,%d]\n",
+ zone->scale / 65536.0,
+ zone->delta / 64.0,
+ zone->min,
+ zone->max );
+ }
+
+#else
+
+#define psh3_print_zone( x ) do { } while ( 0 )
+
+#endif /* DEBUG_ZONES */
+
+
+ /*************************************************************************/
+ /*************************************************************************/
+ /***** *****/
+ /***** HINTER GLYPH MANAGEMENT *****/
+ /***** *****/
+ /*************************************************************************/
+ /*************************************************************************/
+
+#ifdef COMPUTE_INFLEXS
+
+ /* compute all inflex points in a given glyph */
+ static void
+ psh3_glyph_compute_inflections( PSH3_Glyph glyph )
+ {
+ FT_UInt n;
+
+
+ for ( n = 0; n < glyph->num_contours; n++ )
+ {
+ PSH3_Point first, start, end, before, after;
+ FT_Angle angle_in, angle_seg, angle_out;
+ FT_Angle diff_in, diff_out;
+ FT_Int finished = 0;
+
+
+ /* we need at least 4 points to create an inflection point */
+ if ( glyph->contours[n].count < 4 )
+ continue;
+
+ /* compute first segment in contour */
+ first = glyph->contours[n].start;
+
+ start = end = first;
+ do
+ {
+ end = end->next;
+ if ( end == first )
+ goto Skip;
+
+ } while ( PSH3_POINT_EQUAL_ORG( end, first ) );
+
+ angle_seg = PSH3_POINT_ANGLE( start, end );
+
+ /* extend the segment start whenever possible */
+ before = start;
+ do
+ {
+ do
+ {
+ start = before;
+ before = before->prev;
+ if ( before == first )
+ goto Skip;
+
+ } while ( PSH3_POINT_EQUAL_ORG( before, start ) );
+
+ angle_in = PSH3_POINT_ANGLE( before, start );
+
+ } while ( angle_in == angle_seg );
+
+ first = start;
+ diff_in = FT_Angle_Diff( angle_in, angle_seg );
+
+ /* now, process all segments in the contour */
+ do
+ {
+ /* first, extend current segment's end whenever possible */
+ after = end;
+ do
+ {
+ do
+ {
+ end = after;
+ after = after->next;
+ if ( after == first )
+ finished = 1;
+
+ } while ( PSH3_POINT_EQUAL_ORG( end, after ) );
+
+ angle_out = PSH3_POINT_ANGLE( end, after );
+
+ } while ( angle_out == angle_seg );
+
+ diff_out = FT_Angle_Diff( angle_seg, angle_out );
+
+ if ( ( diff_in ^ diff_out ) < 0 )
+ {
+ /* diff_in and diff_out have different signs, we have */
+ /* inflection points here... */
+
+ do
+ {
+ psh3_point_set_inflex( start );
+ start = start->next;
+ }
+ while ( start != end );
+
+ psh3_point_set_inflex( start );
+ }
+
+ start = end;
+ end = after;
+ angle_seg = angle_out;
+ diff_in = diff_out;
+
+ } while ( !finished );
+
+ Skip:
+ ;
+ }
+ }
+
+#endif /* COMPUTE_INFLEXS */
+
+
+ static void
+ psh3_glyph_done( PSH3_Glyph glyph )
+ {
+ FT_Memory memory = glyph->memory;
+
+
+ psh3_hint_table_done( &glyph->hint_tables[1], memory );
+ psh3_hint_table_done( &glyph->hint_tables[0], memory );
+
+ FT_FREE( glyph->points );
+ FT_FREE( glyph->contours );
+
+ glyph->num_points = 0;
+ glyph->num_contours = 0;
+
+ glyph->memory = 0;
+ }
+
+
+ static int
+ psh3_compute_dir( FT_Pos dx,
+ FT_Pos dy )
+ {
+ FT_Pos ax, ay;
+ int result = PSH3_DIR_NONE;
+
+
+ ax = ( dx >= 0 ) ? dx : -dx;
+ ay = ( dy >= 0 ) ? dy : -dy;
+
+ if ( ay * 12 < ax )
+ {
+ /* |dy| <<< |dx| means a near-horizontal segment */
+ result = ( dx >= 0 ) ? PSH3_DIR_RIGHT : PSH3_DIR_LEFT;
+ }
+ else if ( ax * 12 < ay )
+ {
+ /* |dx| <<< |dy| means a near-vertical segment */
+ result = ( dy >= 0 ) ? PSH3_DIR_UP : PSH3_DIR_DOWN;
+ }
+
+ return result;
+ }
+
+
+ /* load outline point coordinates into hinter glyph */
+ static void
+ psh3_glyph_load_points( PSH3_Glyph glyph,
+ FT_Int dimension )
+ {
+ FT_Vector* vec = glyph->outline->points;
+ PSH3_Point point = glyph->points;
+ FT_UInt count = glyph->num_points;
+
+
+ for ( ; count > 0; count--, point++, vec++ )
+ {
+ point->flags2 = 0;
+ point->hint = NULL;
+ if ( dimension == 0 )
+ {
+ point->org_u = vec->x;
+ point->org_v = vec->y;
+ }
+ else
+ {
+ point->org_u = vec->y;
+ point->org_v = vec->x;
+ }
+
+#ifdef DEBUG_HINTER
+ point->org_x = vec->x;
+ point->org_y = vec->y;
+#endif
+
+ }
+ }
+
+
+ /* save hinted point coordinates back to outline */
+ static void
+ psh3_glyph_save_points( PSH3_Glyph glyph,
+ FT_Int dimension )
+ {
+ FT_UInt n;
+ PSH3_Point point = glyph->points;
+ FT_Vector* vec = glyph->outline->points;
+ char* tags = glyph->outline->tags;
+
+
+ for ( n = 0; n < glyph->num_points; n++ )
+ {
+ if ( dimension == 0 )
+ vec[n].x = point->cur_u;
+ else
+ vec[n].y = point->cur_u;
+
+ if ( psh3_point_is_strong( point ) )
+ tags[n] |= (char)( ( dimension == 0 ) ? 32 : 64 );
+
+#ifdef DEBUG_HINTER
+
+ if ( dimension == 0 )
+ {
+ point->cur_x = point->cur_u;
+ point->flags_x = point->flags2 | point->flags;
+ }
+ else
+ {
+ point->cur_y = point->cur_u;
+ point->flags_y = point->flags2 | point->flags;
+ }
+
+#endif
+
+ point++;
+ }
+ }
+
+
+ static FT_Error
+ psh3_glyph_init( PSH3_Glyph glyph,
+ FT_Outline* outline,
+ PS_Hints ps_hints,
+ PSH_Globals globals )
+ {
+ FT_Error error;
+ FT_Memory memory;
+
+
+ /* clear all fields */
+ FT_MEM_ZERO( glyph, sizeof ( *glyph ) );
+
+ memory = globals->memory;
+
+ /* allocate and setup points + contours arrays */
+ if ( FT_NEW_ARRAY( glyph->points, outline->n_points ) ||
+ FT_NEW_ARRAY( glyph->contours, outline->n_contours ) )
+ goto Exit;
+
+ glyph->num_points = outline->n_points;
+ glyph->num_contours = outline->n_contours;
+
+ {
+ FT_UInt first = 0, next, n;
+ PSH3_Point points = glyph->points;
+ PSH3_Contour contour = glyph->contours;
+
+
+ for ( n = 0; n < glyph->num_contours; n++ )
+ {
+ FT_Int count;
+ PSH3_Point point;
+
+
+ next = outline->contours[n] + 1;
+ count = next - first;
+
+ contour->start = points + first;
+ contour->count = (FT_UInt)count;
+
+ if ( count > 0 )
+ {
+ point = points + first;
+
+ point->prev = points + next - 1;
+ point->contour = contour;
+
+ for ( ; count > 1; count-- )
+ {
+ point[0].next = point + 1;
+ point[1].prev = point;
+ point++;
+ point->contour = contour;
+ }
+ point->next = points + first;
+ }
+
+ contour++;
+ first = next;
+ }
+ }
+
+ {
+ PSH3_Point points = glyph->points;
+ PSH3_Point point = points;
+ FT_Vector* vec = outline->points;
+ FT_UInt n;
+
+
+ for ( n = 0; n < glyph->num_points; n++, point++ )
+ {
+ FT_Int n_prev = point->prev - points;
+ FT_Int n_next = point->next - points;
+ FT_Pos dxi, dyi, dxo, dyo;
+
+
+ if ( !( outline->tags[n] & FT_CURVE_TAG_ON ) )
+ point->flags = PSH3_POINT_OFF;
+
+ dxi = vec[n].x - vec[n_prev].x;
+ dyi = vec[n].y - vec[n_prev].y;
+
+ point->dir_in = (FT_Char)psh3_compute_dir( dxi, dyi );
+
+ dxo = vec[n_next].x - vec[n].x;
+ dyo = vec[n_next].y - vec[n].y;
+
+ point->dir_out = (FT_Char)psh3_compute_dir( dxo, dyo );
+
+ /* detect smooth points */
+ if ( point->flags & PSH3_POINT_OFF )
+ point->flags |= PSH3_POINT_SMOOTH;
+ else if ( point->dir_in != PSH3_DIR_NONE ||
+ point->dir_out != PSH3_DIR_NONE )
+ {
+ if ( point->dir_in == point->dir_out )
+ point->flags |= PSH3_POINT_SMOOTH;
+ }
+ else
+ {
+ FT_Angle angle_in, angle_out, diff;
+
+
+ angle_in = FT_Atan2( dxi, dyi );
+ angle_out = FT_Atan2( dxo, dyo );
+
+ diff = angle_in - angle_out;
+ if ( diff < 0 )
+ diff = -diff;
+
+ if ( diff > FT_ANGLE_PI )
+ diff = FT_ANGLE_2PI - diff;
+
+ if ( diff < FT_ANGLE_PI / 16 )
+ point->flags |= PSH3_POINT_SMOOTH;
+ }
+ }
+ }
+
+ glyph->memory = memory;
+ glyph->outline = outline;
+ glyph->globals = globals;
+
+#ifdef COMPUTE_INFLEXS
+ psh3_glyph_load_points( glyph, 0 );
+ psh3_glyph_compute_inflections( glyph );
+#endif /* COMPUTE_INFLEXS */
+
+ /* now deal with hints tables */
+ error = psh3_hint_table_init( &glyph->hint_tables [0],
+ &ps_hints->dimension[0].hints,
+ &ps_hints->dimension[0].masks,
+ &ps_hints->dimension[0].counters,
+ memory );
+ if ( error )
+ goto Exit;
+
+ error = psh3_hint_table_init( &glyph->hint_tables [1],
+ &ps_hints->dimension[1].hints,
+ &ps_hints->dimension[1].masks,
+ &ps_hints->dimension[1].counters,
+ memory );
+ if ( error )
+ goto Exit;
+
+ Exit:
+ return error;
+ }
+
+
+ /* compute all extrema in a glyph for a given dimension */
+ static void
+ psh3_glyph_compute_extrema( PSH3_Glyph glyph )
+ {
+ FT_UInt n;
+
+
+ /* first of all, compute all local extrema */
+ for ( n = 0; n < glyph->num_contours; n++ )
+ {
+ PSH3_Point first = glyph->contours[n].start;
+ PSH3_Point point, before, after;
+
+
+ point = first;
+ before = point;
+ after = point;
+
+ do
+ {
+ before = before->prev;
+ if ( before == first )
+ goto Skip;
+
+ } while ( before->org_u == point->org_u );
+
+ first = point = before->next;
+
+ for (;;)
+ {
+ after = point;
+ do
+ {
+ after = after->next;
+ if ( after == first )
+ goto Next;
+
+ } while ( after->org_u == point->org_u );
+
+ if ( before->org_u < point->org_u )
+ {
+ if ( after->org_u < point->org_u )
+ {
+ /* local maximum */
+ goto Extremum;
+ }
+ }
+ else /* before->org_u > point->org_u */
+ {
+ if ( after->org_u > point->org_u )
+ {
+ /* local minimum */
+ Extremum:
+ do
+ {
+ psh3_point_set_extremum( point );
+ point = point->next;
+
+ } while ( point != after );
+ }
+ }
+
+ before = after->prev;
+ point = after;
+
+ } /* for */
+
+ Next:
+ ;
+ }
+
+ /* for each extrema, determine its direction along the */
+ /* orthogonal axis */
+ for ( n = 0; n < glyph->num_points; n++ )
+ {
+ PSH3_Point point, before, after;
+
+
+ point = &glyph->points[n];
+ before = point;
+ after = point;
+
+ if ( psh3_point_is_extremum( point ) )
+ {
+ do
+ {
+ before = before->prev;
+ if ( before == point )
+ goto Skip;
+
+ } while ( before->org_v == point->org_v );
+
+ do
+ {
+ after = after->next;
+ if ( after == point )
+ goto Skip;
+
+ } while ( after->org_v == point->org_v );
+ }
+
+ if ( before->org_v < point->org_v &&
+ after->org_v > point->org_v )
+ {
+ psh3_point_set_positive( point );
+ }
+ else if ( before->org_v > point->org_v &&
+ after->org_v < point->org_v )
+ {
+ psh3_point_set_negative( point );
+ }
+
+ Skip:
+ ;
+ }
+ }
+
+
+#define PSH3_STRONG_THRESHOLD 30
+
+
+ /* major_dir is the direction for points on the bottom/left of the stem; */
+ /* Points on the top/right of the stem will have a direction of */
+ /* -major_dir. */
+
+ static void
+ psh3_hint_table_find_strong_point( PSH3_Hint_Table table,
+ PSH3_Point point,
+ FT_Int major_dir )
+ {
+ PSH3_Hint* sort = table->sort;
+ FT_UInt num_hints = table->num_hints;
+ FT_Int point_dir = 0;
+
+
+ if ( PSH3_DIR_COMPARE( point->dir_in, major_dir ) )
+ point_dir = point->dir_in;
+
+ else if ( PSH3_DIR_COMPARE( point->dir_out, major_dir ) )
+ point_dir = point->dir_out;
+
+ if ( point_dir )
+ {
+ FT_UInt flag;
+
+
+ for ( ; num_hints > 0; num_hints--, sort++ )
+ {
+ PSH3_Hint hint = sort[0];
+ FT_Pos d;
+
+
+ if ( point_dir == major_dir )
+ {
+ flag = PSH3_POINT_EDGE_MIN;
+ d = point->org_u - hint->org_pos;
+
+ if ( ABS( d ) < PSH3_STRONG_THRESHOLD )
+ {
+ Is_Strong:
+ psh3_point_set_strong( point );
+ point->flags2 |= flag;
+ point->hint = hint;
+ break;
+ }
+ }
+ else if ( point_dir == -major_dir )
+ {
+ flag = PSH3_POINT_EDGE_MAX;
+ d = point->org_u - hint->org_pos - hint->org_len;
+
+ if ( ABS( d ) < PSH3_STRONG_THRESHOLD )
+ goto Is_Strong;
+ }
+ }
+ }
+
+#if 1
+ else if ( psh3_point_is_extremum( point ) )
+ {
+ /* treat extrema as special cases for stem edge alignment */
+ FT_UInt min_flag, max_flag;
+
+
+ if ( major_dir == PSH3_DIR_HORIZONTAL )
+ {
+ min_flag = PSH3_POINT_POSITIVE;
+ max_flag = PSH3_POINT_NEGATIVE;
+ }
+ else
+ {
+ min_flag = PSH3_POINT_NEGATIVE;
+ max_flag = PSH3_POINT_POSITIVE;
+ }
+
+ for ( ; num_hints > 0; num_hints--, sort++ )
+ {
+ PSH3_Hint hint = sort[0];
+ FT_Pos d, flag;
+
+
+ if ( point->flags2 & min_flag )
+ {
+ flag = PSH3_POINT_EDGE_MIN;
+ d = point->org_u - hint->org_pos;
+
+ if ( ABS( d ) < PSH3_STRONG_THRESHOLD )
+ {
+ Is_Strong2:
+ point->flags2 |= flag;
+ point->hint = hint;
+ psh3_point_set_strong( point );
+ break;
+ }
+ }
+ else if ( point->flags2 & max_flag )
+ {
+ flag = PSH3_POINT_EDGE_MAX;
+ d = point->org_u - hint->org_pos - hint->org_len;
+
+ if ( ABS( d ) < PSH3_STRONG_THRESHOLD )
+ goto Is_Strong2;
+ }
+
+ if ( point->org_u >= hint->org_pos &&
+ point->org_u <= hint->org_pos + hint->org_len )
+ {
+ point->hint = hint;
+ }
+ }
+ }
+
+#endif /* 1 */
+ }
+
+
+ /* find strong points in a glyph */
+ static void
+ psh3_glyph_find_strong_points( PSH3_Glyph glyph,
+ FT_Int dimension )
+ {
+ /* a point is strong if it is located on a stem */
+ /* edge and has an "in" or "out" tangent to the hint's direction */
+ {
+ PSH3_Hint_Table table = &glyph->hint_tables[dimension];
+ PS_Mask mask = table->hint_masks->masks;
+ FT_UInt num_masks = table->hint_masks->num_masks;
+ FT_UInt first = 0;
+ FT_Int major_dir = dimension == 0 ? PSH3_DIR_VERTICAL
+ : PSH3_DIR_HORIZONTAL;
+
+
+ /* process secondary hints to "selected" points */
+ if ( num_masks > 1 && glyph->num_points > 0 )
+ {
+ first = mask->end_point;
+ mask++;
+ for ( ; num_masks > 1; num_masks--, mask++ )
+ {
+ FT_UInt next;
+ FT_Int count;
+
+
+ next = mask->end_point;
+ count = next - first;
+ if ( count > 0 )
+ {
+ PSH3_Point point = glyph->points + first;
+
+
+ psh3_hint_table_activate_mask( table, mask );
+
+ for ( ; count > 0; count--, point++ )
+ psh3_hint_table_find_strong_point( table, point, major_dir );
+ }
+ first = next;
+ }
+ }
+
+ /* process primary hints for all points */
+ if ( num_masks == 1 )
+ {
+ FT_UInt count = glyph->num_points;
+ PSH3_Point point = glyph->points;
+
+
+ psh3_hint_table_activate_mask( table, table->hint_masks->masks );
+ for ( ; count > 0; count--, point++ )
+ {
+ if ( !psh3_point_is_strong( point ) )
+ psh3_hint_table_find_strong_point( table, point, major_dir );
+ }
+ }
+
+ /* now, certain points may have been attached to hint and */
+ /* not marked as strong; update their flags then */
+ {
+ FT_UInt count = glyph->num_points;
+ PSH3_Point point = glyph->points;
+
+
+ for ( ; count > 0; count--, point++ )
+ if ( point->hint && !psh3_point_is_strong( point ) )
+ psh3_point_set_strong( point );
+ }
+ }
+ }
+
+
+ /* interpolate strong points with the help of hinted coordinates */
+ static void
+ psh3_glyph_interpolate_strong_points( PSH3_Glyph glyph,
+ FT_Int dimension )
+ {
+ PSH_Dimension dim = &glyph->globals->dimension[dimension];
+ FT_Fixed scale = dim->scale_mult;
+
+
+ {
+ FT_UInt count = glyph->num_points;
+ PSH3_Point point = glyph->points;
+
+
+ for ( ; count > 0; count--, point++ )
+ {
+ PSH3_Hint hint = point->hint;
+
+
+ if ( hint )
+ {
+ FT_Pos delta;
+
+
+ if ( psh3_point_is_edge_min( point ) )
+ {
+ point->cur_u = hint->cur_pos;
+ }
+ else if ( psh3_point_is_edge_max( point ) )
+ {
+ point->cur_u = hint->cur_pos + hint->cur_len;
+ }
+ else
+ {
+ delta = point->org_u - hint->org_pos;
+
+ if ( delta <= 0 )
+ point->cur_u = hint->cur_pos + FT_MulFix( delta, scale );
+
+ else if ( delta >= hint->org_len )
+ point->cur_u = hint->cur_pos + hint->cur_len +
+ FT_MulFix( delta - hint->org_len, scale );
+
+ else if ( hint->org_len > 0 )
+ point->cur_u = hint->cur_pos +
+ FT_MulDiv( delta, hint->cur_len,
+ hint->org_len );
+ else
+ point->cur_u = hint->cur_pos;
+ }
+ psh3_point_set_fitted( point );
+ }
+ }
+ }
+ }
+
+
+ static void
+ psh3_glyph_interpolate_normal_points( PSH3_Glyph glyph,
+ FT_Int dimension )
+ {
+
+#if 1
+
+ PSH_Dimension dim = &glyph->globals->dimension[dimension];
+ FT_Fixed scale = dim->scale_mult;
+
+
+ /* first technique: a point is strong if it is a local extrema */
+ {
+ FT_UInt count = glyph->num_points;
+ PSH3_Point point = glyph->points;
+
+
+ for ( ; count > 0; count--, point++ )
+ {
+ if ( psh3_point_is_strong( point ) )
+ continue;
+
+ /* sometimes, some local extremas are smooth points */
+ if ( psh3_point_is_smooth( point ) )
+ {
+ if ( point->dir_in == PSH3_DIR_NONE ||
+ point->dir_in != point->dir_out )
+ continue;
+
+ if ( !psh3_point_is_extremum( point ) &&
+ !psh3_point_is_inflex( point ) )
+ continue;
+
+ point->flags &= ~PSH3_POINT_SMOOTH;
+ }
+
+ /* find best enclosing point coordinates */
+ {
+ PSH3_Point before = 0;
+ PSH3_Point after = 0;
+
+ FT_Pos diff_before = -32000;
+ FT_Pos diff_after = 32000;
+ FT_Pos u = point->org_u;
+
+ FT_Int count2 = glyph->num_points;
+ PSH3_Point cur = glyph->points;
+
+
+ for ( ; count2 > 0; count2--, cur++ )
+ {
+ if ( psh3_point_is_strong( cur ) )
+ {
+ FT_Pos diff = cur->org_u - u;;
+
+
+ if ( diff <= 0 )
+ {
+ if ( diff > diff_before )
+ {
+ diff_before = diff;
+ before = cur;
+ }
+ }
+ else if ( diff >= 0 )
+ {
+ if ( diff < diff_after )
+ {
+ diff_after = diff;
+ after = cur;
+ }
+ }
+ }
+ }
+
+ if ( !before )
+ {
+ if ( !after )
+ continue;
+
+ /* we are before the first strong point coordinate; */
+ /* simply translate the point */
+ point->cur_u = after->cur_u +
+ FT_MulFix( point->org_u - after->org_u, scale );
+ }
+ else if ( !after )
+ {
+ /* we are after the last strong point coordinate; */
+ /* simply translate the point */
+ point->cur_u = before->cur_u +
+ FT_MulFix( point->org_u - before->org_u, scale );
+ }
+ else
+ {
+ if ( diff_before == 0 )
+ point->cur_u = before->cur_u;
+
+ else if ( diff_after == 0 )
+ point->cur_u = after->cur_u;
+
+ else
+ point->cur_u = before->cur_u +
+ FT_MulDiv( u - before->org_u,
+ after->cur_u - before->cur_u,
+ after->org_u - before->org_u );
+ }
+
+ psh3_point_set_fitted( point );
+ }
+ }
+ }
+
+#endif /* 1 */
+
+ }
+
+
+ /* interpolate other points */
+ static void
+ psh3_glyph_interpolate_other_points( PSH3_Glyph glyph,
+ FT_Int dimension )
+ {
+ PSH_Dimension dim = &glyph->globals->dimension[dimension];
+ FT_Fixed scale = dim->scale_mult;
+ FT_Fixed delta = dim->scale_delta;
+ PSH3_Contour contour = glyph->contours;
+ FT_UInt num_contours = glyph->num_contours;
+
+
+ for ( ; num_contours > 0; num_contours--, contour++ )
+ {
+ PSH3_Point start = contour->start;
+ PSH3_Point first, next, point;
+ FT_UInt fit_count;
+
+
+ /* count the number of strong points in this contour */
+ next = start + contour->count;
+ fit_count = 0;
+ first = 0;
+
+ for ( point = start; point < next; point++ )
+ if ( psh3_point_is_fitted( point ) )
+ {
+ if ( !first )
+ first = point;
+
+ fit_count++;
+ }
+
+ /* if there are less than 2 fitted points in the contour, we */
+ /* simply scale and eventually translate the contour points */
+ if ( fit_count < 2 )
+ {
+ if ( fit_count == 1 )
+ delta = first->cur_u - FT_MulFix( first->org_u, scale );
+
+ for ( point = start; point < next; point++ )
+ if ( point != first )
+ point->cur_u = FT_MulFix( point->org_u, scale ) + delta;
+
+ goto Next_Contour;
+ }
+
+ /* there are more than 2 strong points in this contour; we */
+ /* need to interpolate weak points between them */
+ start = first;
+ do
+ {
+ point = first;
+
+ /* skip consecutive fitted points */
+ for (;;)
+ {
+ next = first->next;
+ if ( next == start )
+ goto Next_Contour;
+
+ if ( !psh3_point_is_fitted( next ) )
+ break;
+
+ first = next;
+ }
+
+ /* find next fitted point after unfitted one */
+ for (;;)
+ {
+ next = next->next;
+ if ( psh3_point_is_fitted( next ) )
+ break;
+ }
+
+ /* now interpolate between them */
+ {
+ FT_Pos org_a, org_ab, cur_a, cur_ab;
+ FT_Pos org_c, org_ac, cur_c;
+ FT_Fixed scale_ab;
+
+
+ if ( first->org_u <= next->org_u )
+ {
+ org_a = first->org_u;
+ cur_a = first->cur_u;
+ org_ab = next->org_u - org_a;
+ cur_ab = next->cur_u - cur_a;
+ }
+ else
+ {
+ org_a = next->org_u;
+ cur_a = next->cur_u;
+ org_ab = first->org_u - org_a;
+ cur_ab = first->cur_u - cur_a;
+ }
+
+ scale_ab = 0x10000L;
+ if ( org_ab > 0 )
+ scale_ab = FT_DivFix( cur_ab, org_ab );
+
+ point = first->next;
+ do
+ {
+ org_c = point->org_u;
+ org_ac = org_c - org_a;
+
+ if ( org_ac <= 0 )
+ {
+ /* on the left of the interpolation zone */
+ cur_c = cur_a + FT_MulFix( org_ac, scale );
+ }
+ else if ( org_ac >= org_ab )
+ {
+ /* on the right on the interpolation zone */
+ cur_c = cur_a + cur_ab + FT_MulFix( org_ac - org_ab, scale );
+ }
+ else
+ {
+ /* within the interpolation zone */
+ cur_c = cur_a + FT_MulFix( org_ac, scale_ab );
+ }
+
+ point->cur_u = cur_c;
+
+ point = point->next;
+
+ } while ( point != next );
+ }
+
+ /* keep going until all points in the contours have been processed */
+ first = next;
+
+ } while ( first != start );
+
+ Next_Contour:
+ ;
+ }
+ }
+
+
+ /*************************************************************************/
+ /*************************************************************************/
+ /***** *****/
+ /***** HIGH-LEVEL INTERFACE *****/
+ /***** *****/
+ /*************************************************************************/
+ /*************************************************************************/
+
+ FT_Error
+ ps3_hints_apply( PS_Hints ps_hints,
+ FT_Outline* outline,
+ PSH_Globals globals,
+ FT_Render_Mode hint_mode )
+ {
+ PSH3_GlyphRec glyphrec;
+ PSH3_Glyph glyph = &glyphrec;
+ FT_Error error;
+#ifdef DEBUG_HINTER
+ FT_Memory memory;
+#endif
+ FT_Int dimension;
+
+
+#ifdef DEBUG_HINTER
+
+ memory = globals->memory;
+
+ if ( ps3_debug_glyph )
+ {
+ psh3_glyph_done( ps3_debug_glyph );
+ FT_FREE( ps3_debug_glyph );
+ }
+
+ if ( FT_NEW( glyph ) )
+ return error;
+
+ ps3_debug_glyph = glyph;
+
+#endif /* DEBUG_HINTER */
+
+ error = psh3_glyph_init( glyph, outline, ps_hints, globals );
+ if ( error )
+ goto Exit;
+
+ glyph->do_horz_hints = 1;
+ glyph->do_vert_hints = 1;
+
+ glyph->do_horz_snapping = FT_BOOL( hint_mode == FT_RENDER_MODE_MONO ||
+ hint_mode == FT_RENDER_MODE_LCD );
+
+ glyph->do_vert_snapping = FT_BOOL( hint_mode == FT_RENDER_MODE_MONO ||
+ hint_mode == FT_RENDER_MODE_LCD_V );
+
+ for ( dimension = 0; dimension < 2; dimension++ )
+ {
+ /* load outline coordinates into glyph */
+ psh3_glyph_load_points( glyph, dimension );
+
+ /* compute local extrema */
+ psh3_glyph_compute_extrema( glyph );
+
+ /* compute aligned stem/hints positions */
+ psh3_hint_table_align_hints( &glyph->hint_tables[dimension],
+ glyph->globals,
+ dimension,
+ glyph );
+
+ /* find strong points, align them, then interpolate others */
+ psh3_glyph_find_strong_points( glyph, dimension );
+ psh3_glyph_interpolate_strong_points( glyph, dimension );
+ psh3_glyph_interpolate_normal_points( glyph, dimension );
+ psh3_glyph_interpolate_other_points( glyph, dimension );
+
+ /* save hinted coordinates back to outline */
+ psh3_glyph_save_points( glyph, dimension );
+ }
+
+ Exit:
+
+#ifndef DEBUG_HINTER
+ psh3_glyph_done( glyph );
+#endif
+
+ return error;
+ }
+
+
+/* END */
--- /dev/null
+++ b/libfreetype/pshalgo3.h
@@ -1,0 +1,254 @@
+/***************************************************************************/
+/* */
+/* pshalgo3.h */
+/* */
+/* PostScript hinting algorithm 3 (specification). */
+/* */
+/* Copyright 2001, 2002 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+
+#ifndef __PSHALGO3_H__
+#define __PSHALGO3_H__
+
+
+#include "pshrec.h"
+#include "pshglob.h"
+#include FT_TRIGONOMETRY_H
+
+
+FT_BEGIN_HEADER
+
+
+ /* handle to Hint structure */
+ typedef struct PSH3_HintRec_* PSH3_Hint;
+
+ /* hint bit-flags */
+ typedef enum
+ {
+ PSH3_HINT_GHOST = PS_HINT_FLAG_GHOST,
+ PSH3_HINT_BOTTOM = PS_HINT_FLAG_BOTTOM,
+ PSH3_HINT_ACTIVE = 4,
+ PSH3_HINT_FITTED = 8
+
+ } PSH3_Hint_Flags;
+
+
+#define psh3_hint_is_active( x ) ( ( (x)->flags & PSH3_HINT_ACTIVE ) != 0 )
+#define psh3_hint_is_ghost( x ) ( ( (x)->flags & PSH3_HINT_GHOST ) != 0 )
+#define psh3_hint_is_fitted( x ) ( ( (x)->flags & PSH3_HINT_FITTED ) != 0 )
+
+#define psh3_hint_activate( x ) (x)->flags |= PSH3_HINT_ACTIVE
+#define psh3_hint_deactivate( x ) (x)->flags &= ~PSH3_HINT_ACTIVE
+#define psh3_hint_set_fitted( x ) (x)->flags |= PSH3_HINT_FITTED
+
+ /* hint structure */
+ typedef struct PSH3_HintRec_
+ {
+ FT_Int org_pos;
+ FT_Int org_len;
+ FT_Pos cur_pos;
+ FT_Pos cur_len;
+ FT_UInt flags;
+ PSH3_Hint parent;
+ FT_Int order;
+
+ } PSH3_HintRec;
+
+
+ /* this is an interpolation zone used for strong points; */
+ /* weak points are interpolated according to their strong */
+ /* neighbours */
+ typedef struct PSH3_ZoneRec_
+ {
+ FT_Fixed scale;
+ FT_Fixed delta;
+ FT_Pos min;
+ FT_Pos max;
+
+ } PSH3_ZoneRec, *PSH3_Zone;
+
+
+ typedef struct PSH3_Hint_TableRec_
+ {
+ FT_UInt max_hints;
+ FT_UInt num_hints;
+ PSH3_Hint hints;
+ PSH3_Hint* sort;
+ PSH3_Hint* sort_global;
+ FT_UInt num_zones;
+ PSH3_ZoneRec* zones;
+ PSH3_Zone zone;
+ PS_Mask_Table hint_masks;
+ PS_Mask_Table counter_masks;
+
+ } PSH3_Hint_TableRec, *PSH3_Hint_Table;
+
+
+ typedef struct PSH3_PointRec_* PSH3_Point;
+ typedef struct PSH3_ContourRec_* PSH3_Contour;
+
+ enum
+ {
+ PSH3_DIR_NONE = 4,
+ PSH3_DIR_UP = -1,
+ PSH3_DIR_DOWN = 1,
+ PSH3_DIR_LEFT = -2,
+ PSH3_DIR_RIGHT = 2
+ };
+
+#define PSH3_DIR_HORIZONTAL 2
+#define PSH3_DIR_VERTICAL 1
+
+#define PSH3_DIR_COMPARE( d1, d2 ) ( (d1) == (d2) || (d1) == -(d2) )
+#define PSH3_DIR_IS_HORIZONTAL( d ) PSH3_DIR_COMPARE( d, PSH3_DIR_HORIZONTAL )
+#define PSH3_DIR_IS_VERTICAL( d ) PSH3_DIR_COMPARE( d, PSH3_DIR_VERTICAL )
+
+
+ /* the following bit-flags are computed once by the glyph */
+ /* analyzer, for both dimensions */
+ enum
+ {
+ PSH3_POINT_OFF = 1, /* point is off the curve */
+ PSH3_POINT_SMOOTH = 2, /* point is smooth */
+ PSH3_POINT_INFLEX = 4 /* point is inflection */
+ };
+
+#define psh3_point_is_smooth( p ) ( (p)->flags & PSH3_POINT_SMOOTH )
+#define psh3_point_is_off( p ) ( (p)->flags & PSH3_POINT_OFF )
+#define psh3_point_is_inflex( p ) ( (p)->flags & PSH3_POINT_INFLEX )
+
+#define psh3_point_set_smooth( p ) (p)->flags |= PSH3_POINT_SMOOTH
+#define psh3_point_set_off( p ) (p)->flags |= PSH3_POINT_OFF
+#define psh3_point_set_inflex( p ) (p)->flags |= PSH3_POINT_INFLEX
+
+ /* the following bit-flags are re-computed for each dimension */
+ enum
+ {
+ PSH3_POINT_STRONG = 16, /* point is strong */
+ PSH3_POINT_FITTED = 32, /* point is already fitted */
+ PSH3_POINT_EXTREMUM = 64, /* point is local extremum */
+ PSH3_POINT_POSITIVE = 128, /* extremum has positive contour flow */
+ PSH3_POINT_NEGATIVE = 256, /* extremum has negative contour flow */
+ PSH3_POINT_EDGE_MIN = 512, /* point is aligned to left/bottom stem edge */
+ PSH3_POINT_EDGE_MAX = 1024 /* point is aligned to top/right stem edge */
+ };
+
+#define psh3_point_is_strong( p ) ( (p)->flags2 & PSH3_POINT_STRONG )
+#define psh3_point_is_fitted( p ) ( (p)->flags2 & PSH3_POINT_FITTED )
+#define psh3_point_is_extremum( p ) ( (p)->flags2 & PSH3_POINT_EXTREMUM )
+#define psh3_point_is_positive( p ) ( (p)->flags2 & PSH3_POINT_POSITIVE )
+#define psh3_point_is_negative( p ) ( (p)->flags2 & PSH3_POINT_NEGATIVE )
+#define psh3_point_is_edge_min( p ) ( (p)->flags2 & PSH3_POINT_EDGE_MIN )
+#define psh3_point_is_edge_max( p ) ( (p)->flags2 & PSH3_POINT_EDGE_MAX )
+
+#define psh3_point_set_strong( p ) (p)->flags2 |= PSH3_POINT_STRONG
+#define psh3_point_set_fitted( p ) (p)->flags2 |= PSH3_POINT_FITTED
+#define psh3_point_set_extremum( p ) (p)->flags2 |= PSH3_POINT_EXTREMUM
+#define psh3_point_set_positive( p ) (p)->flags2 |= PSH3_POINT_POSITIVE
+#define psh3_point_set_negative( p ) (p)->flags2 |= PSH3_POINT_NEGATIVE
+#define psh3_point_set_edge_min( p ) (p)->flags2 |= PSH3_POINT_EDGE_MIN
+#define psh3_point_set_edge_max( p ) (p)->flags2 |= PSH3_POINT_EDGE_MAX
+
+
+ typedef struct PSH3_PointRec_
+ {
+ PSH3_Point prev;
+ PSH3_Point next;
+ PSH3_Contour contour;
+ FT_UInt flags;
+ FT_UInt flags2;
+ FT_Char dir_in;
+ FT_Char dir_out;
+ FT_Angle angle_in;
+ FT_Angle angle_out;
+ PSH3_Hint hint;
+ FT_Pos org_u;
+ FT_Pos org_v;
+ FT_Pos cur_u;
+#ifdef DEBUG_HINTER
+ FT_Pos org_x;
+ FT_Pos cur_x;
+ FT_Pos org_y;
+ FT_Pos cur_y;
+ FT_UInt flags_x;
+ FT_UInt flags_y;
+#endif
+
+ } PSH3_PointRec;
+
+
+#define PSH3_POINT_EQUAL_ORG( a, b ) ( (a)->org_u == (b)->org_u && \
+ (a)->org_v == (b)->org_v )
+
+#define PSH3_POINT_ANGLE( a, b ) FT_Atan2( (b)->org_u - (a)->org_u, \
+ (b)->org_v - (a)->org_v )
+
+ typedef struct PSH3_ContourRec_
+ {
+ PSH3_Point start;
+ FT_UInt count;
+
+ } PSH3_ContourRec;
+
+
+ typedef struct PSH3_GlyphRec_
+ {
+ FT_UInt num_points;
+ FT_UInt num_contours;
+
+ PSH3_Point points;
+ PSH3_Contour contours;
+
+ FT_Memory memory;
+ FT_Outline* outline;
+ PSH_Globals globals;
+ PSH3_Hint_TableRec hint_tables[2];
+
+ FT_Bool vertical;
+ FT_Int major_dir;
+ FT_Int minor_dir;
+
+ FT_Bool do_horz_hints;
+ FT_Bool do_vert_hints;
+ FT_Bool do_horz_snapping;
+ FT_Bool do_vert_snapping;
+
+ } PSH3_GlyphRec, *PSH3_Glyph;
+
+
+#ifdef DEBUG_HINTER
+ extern PSH3_Hint_Table ps3_debug_hint_table;
+
+ typedef void
+ (*PSH3_HintFunc)( PSH3_Hint hint,
+ FT_Bool vertical );
+
+ extern PSH3_HintFunc ps3_debug_hint_func;
+
+ extern PSH3_Glyph ps3_debug_glyph;
+#endif
+
+
+ extern FT_Error
+ ps3_hints_apply( PS_Hints ps_hints,
+ FT_Outline* outline,
+ PSH_Globals globals,
+ FT_Render_Mode hint_mode );
+
+
+FT_END_HEADER
+
+
+#endif /* __PSHALGO3_H__ */
+
+
+/* END */
--- /dev/null
+++ b/libfreetype/pshglob.c
@@ -1,0 +1,743 @@
+/***************************************************************************/
+/* */
+/* pshglob.c */
+/* */
+/* PostScript hinter global hinting management (body). */
+/* Inspired by the new auto-hinter module. */
+/* */
+/* Copyright 2001, 2002 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used */
+/* modified and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+
+#include <ft2build.h>
+#include FT_FREETYPE_H
+#include FT_INTERNAL_OBJECTS_H
+#include "pshglob.h"
+
+#ifdef DEBUG_HINTER
+ PSH_Globals ps_debug_globals = 0;
+#endif
+
+
+ /*************************************************************************/
+ /*************************************************************************/
+ /***** *****/
+ /***** STANDARD WIDTHS *****/
+ /***** *****/
+ /*************************************************************************/
+ /*************************************************************************/
+
+
+ /* scale the widths/heights table */
+ static void
+ psh_globals_scale_widths( PSH_Globals globals,
+ FT_UInt direction )
+ {
+ PSH_Dimension dim = &globals->dimension[direction];
+ PSH_Widths stdw = &dim->stdw;
+ FT_UInt count = stdw->count;
+ PSH_Width width = stdw->widths;
+ PSH_Width stand = width; /* standard width/height */
+ FT_Fixed scale = dim->scale_mult;
+
+
+ if ( count > 0 )
+ {
+ width->cur = FT_MulFix( width->org, scale );
+ width->fit = FT_RoundFix( width->cur );
+
+ width++;
+ count--;
+
+ for ( ; count > 0; count--, width++ )
+ {
+ FT_Pos w, dist;
+
+
+ w = FT_MulFix( width->org, scale );
+ dist = w - stand->cur;
+
+ if ( dist < 0 )
+ dist = -dist;
+
+ if ( dist < 128 )
+ w = stand->cur;
+
+ width->cur = w;
+ width->fit = FT_RoundFix( w );
+ }
+ }
+ }
+
+
+ /* org_width is is font units, result in device pixels, 26.6 format */
+ FT_LOCAL_DEF( FT_Pos )
+ psh_dimension_snap_width( PSH_Dimension dimension,
+ FT_Int org_width )
+ {
+ FT_UInt n;
+ FT_Pos width = FT_MulFix( org_width, dimension->scale_mult );
+ FT_Pos best = 64 + 32 + 2;
+ FT_Pos reference = width;
+
+
+ for ( n = 0; n < dimension->stdw.count; n++ )
+ {
+ FT_Pos w;
+ FT_Pos dist;
+
+
+ w = dimension->stdw.widths[n].cur;
+ dist = width - w;
+ if ( dist < 0 )
+ dist = -dist;
+ if ( dist < best )
+ {
+ best = dist;
+ reference = w;
+ }
+ }
+
+ if ( width >= reference )
+ {
+ width -= 0x21;
+ if ( width < reference )
+ width = reference;
+ }
+ else
+ {
+ width += 0x21;
+ if ( width > reference )
+ width = reference;
+ }
+
+ return width;
+ }
+
+
+ /*************************************************************************/
+ /*************************************************************************/
+ /***** *****/
+ /***** BLUE ZONES *****/
+ /***** *****/
+ /*************************************************************************/
+ /*************************************************************************/
+
+ static void
+ psh_blues_set_zones_0( PSH_Blues target,
+ FT_Bool is_others,
+ FT_UInt read_count,
+ FT_Short* read,
+ PSH_Blue_Table top_table,
+ PSH_Blue_Table bot_table )
+ {
+ FT_UInt count_top = top_table->count;
+ FT_UInt count_bot = bot_table->count;
+ FT_Bool first = 1;
+
+ FT_UNUSED( target );
+
+
+ for ( ; read_count > 0; read_count -= 2 )
+ {
+ FT_Int reference, delta;
+ FT_UInt count;
+ PSH_Blue_Zone zones, zone;
+ FT_Bool top;
+
+
+ /* read blue zone entry, and select target top/bottom zone */
+ top = 0;
+ if ( first || is_others )
+ {
+ reference = read[1];
+ delta = read[0] - reference;
+
+ zones = bot_table->zones;
+ count = count_bot;
+ first = 0;
+ }
+ else
+ {
+ reference = read[0];
+ delta = read[1] - reference;
+
+ zones = top_table->zones;
+ count = count_top;
+ top = 1;
+ }
+
+ /* insert into sorted table */
+ zone = zones;
+ for ( ; count > 0; count--, zone++ )
+ {
+ if ( reference < zone->org_ref )
+ break;
+
+ if ( reference == zone->org_ref )
+ {
+ FT_Int delta0 = zone->org_delta;
+
+
+ /* we have two zones on the same reference position -- */
+ /* only keep the largest one */
+ if ( delta < 0 )
+ {
+ if ( delta < delta0 )
+ zone->org_delta = delta;
+ }
+ else
+ {
+ if ( delta > delta0 )
+ zone->org_delta = delta;
+ }
+ goto Skip;
+ }
+ }
+
+ for ( ; count > 0; count-- )
+ zone[count] = zone[count-1];
+
+ zone->org_ref = reference;
+ zone->org_delta = delta;
+
+ if ( top )
+ count_top++;
+ else
+ count_bot++;
+
+ Skip:
+ read += 2;
+ }
+
+ top_table->count = count_top;
+ bot_table->count = count_bot;
+ }
+
+
+ /* Re-read blue zones from the original fonts and store them into out */
+ /* private structure. This function re-orders, sanitizes and */
+ /* fuzz-expands the zones as well. */
+ static void
+ psh_blues_set_zones( PSH_Blues target,
+ FT_UInt count,
+ FT_Short* blues,
+ FT_UInt count_others,
+ FT_Short* other_blues,
+ FT_Int fuzz,
+ FT_Int family )
+ {
+ PSH_Blue_Table top_table, bot_table;
+ FT_Int count_top, count_bot;
+
+
+ if ( family )
+ {
+ top_table = &target->family_top;
+ bot_table = &target->family_bottom;
+ }
+ else
+ {
+ top_table = &target->normal_top;
+ bot_table = &target->normal_bottom;
+ }
+
+ /* read the input blue zones, and build two sorted tables */
+ /* (one for the top zones, the other for the bottom zones) */
+ top_table->count = 0;
+ bot_table->count = 0;
+
+ /* first, the blues */
+ psh_blues_set_zones_0( target, 0,
+ count, blues, top_table, bot_table );
+ psh_blues_set_zones_0( target, 1,
+ count_others, other_blues, top_table, bot_table );
+
+ count_top = top_table->count;
+ count_bot = bot_table->count;
+
+ /* sanitize top table */
+ if ( count_top > 0 )
+ {
+ PSH_Blue_Zone zone = top_table->zones;
+
+
+ for ( count = count_top; count > 0; count--, zone++ )
+ {
+ FT_Int delta;
+
+
+ if ( count > 1 )
+ {
+ delta = zone[1].org_ref - zone[0].org_ref;
+ if ( zone->org_delta > delta )
+ zone->org_delta = delta;
+ }
+
+ zone->org_bottom = zone->org_ref;
+ zone->org_top = zone->org_delta + zone->org_ref;
+ }
+ }
+
+ /* sanitize bottom table */
+ if ( count_bot > 0 )
+ {
+ PSH_Blue_Zone zone = bot_table->zones;
+
+
+ for ( count = count_bot; count > 0; count--, zone++ )
+ {
+ FT_Int delta;
+
+
+ if ( count > 1 )
+ {
+ delta = zone[0].org_ref - zone[1].org_ref;
+ if ( zone->org_delta < delta )
+ zone->org_delta = delta;
+ }
+
+ zone->org_top = zone->org_ref;
+ zone->org_bottom = zone->org_delta + zone->org_ref;
+ }
+ }
+
+ /* expand top and bottom tables with blue fuzz */
+ {
+ FT_Int dim, top, bot, delta;
+ PSH_Blue_Zone zone;
+
+
+ zone = top_table->zones;
+ count = count_top;
+
+ for ( dim = 1; dim >= 0; dim-- )
+ {
+ if ( count > 0 )
+ {
+ /* expand the bottom of the lowest zone normally */
+ zone->org_bottom -= fuzz;
+
+ /* expand the top and bottom of intermediate zones; */
+ /* checking that the interval is smaller than the fuzz */
+ top = zone->org_top;
+
+ for ( count--; count > 0; count-- )
+ {
+ bot = zone[1].org_bottom;
+ delta = bot - top;
+
+ if ( delta < 2 * fuzz )
+ zone[0].org_top = zone[1].org_bottom = top + delta / 2;
+ else
+ {
+ zone[0].org_top = top + fuzz;
+ zone[1].org_bottom = bot - fuzz;
+ }
+
+ zone++;
+ top = zone->org_top;
+ }
+
+ /* expand the top of the highest zone normally */
+ zone->org_top = top + fuzz;
+ }
+ zone = bot_table->zones;
+ count = count_bot;
+ }
+ }
+ }
+
+
+ /* reset the blues table when the device transform changes */
+ static void
+ psh_blues_scale_zones( PSH_Blues blues,
+ FT_Fixed scale,
+ FT_Pos delta )
+ {
+ FT_UInt count;
+ FT_UInt num;
+ PSH_Blue_Table table = 0;
+
+ /* */
+ /* Determine whether we need to suppress overshoots or */
+ /* not. We simply need to compare the vertical scale */
+ /* parameter to the raw bluescale value. Here is why: */
+ /* */
+ /* We need to suppress overshoots for all pointsizes. */
+ /* At 300dpi that satisfy: */
+ /* */
+ /* pointsize < 240*bluescale + 0.49 */
+ /* */
+ /* This corresponds to: */
+ /* */
+ /* pixelsize < 1000*bluescale + 49/24 */
+ /* */
+ /* scale*EM_Size < 1000*bluescale + 49/24 */
+ /* */
+ /* However, for normal Type 1 fonts, EM_Size is 1000! */
+ /* We thus only check: */
+ /* */
+ /* scale < bluescale + 49/24000 */
+ /* */
+ /* which we shorten to */
+ /* */
+ /* "scale < bluescale" */
+ /* */
+ blues->no_overshoots = FT_BOOL( scale < blues->blue_scale );
+
+ /* */
+ /* The blue threshold is the font units distance under */
+ /* which overshoots are suppressed due to the BlueShift */
+ /* even if the scale is greater than BlueScale. */
+ /* */
+ /* It is the smallest distance such that */
+ /* */
+ /* dist <= BlueShift && dist*scale <= 0.5 pixels */
+ /* */
+ {
+ FT_Int threshold = blues->blue_shift;
+
+
+ while ( threshold > 0 && FT_MulFix( threshold, scale ) > 32 )
+ threshold --;
+
+ blues->blue_threshold = threshold;
+ }
+
+ for ( num = 0; num < 4; num++ )
+ {
+ PSH_Blue_Zone zone;
+
+
+ switch ( num )
+ {
+ case 0:
+ table = &blues->normal_top;
+ break;
+ case 1:
+ table = &blues->normal_bottom;
+ break;
+ case 2:
+ table = &blues->family_top;
+ break;
+ default:
+ table = &blues->family_bottom;
+ break;
+ }
+
+ zone = table->zones;
+ count = table->count;
+ for ( ; count > 0; count--, zone++ )
+ {
+ zone->cur_top = FT_MulFix( zone->org_top, scale ) + delta;
+ zone->cur_bottom = FT_MulFix( zone->org_bottom, scale ) + delta;
+ zone->cur_ref = FT_MulFix( zone->org_ref, scale ) + delta;
+ zone->cur_delta = FT_MulFix( zone->org_delta, scale );
+
+ /* round scaled reference position */
+ zone->cur_ref = ( zone->cur_ref + 32 ) & -64;
+
+#if 0
+ if ( zone->cur_ref > zone->cur_top )
+ zone->cur_ref -= 64;
+ else if ( zone->cur_ref < zone->cur_bottom )
+ zone->cur_ref += 64;
+#endif
+ }
+ }
+
+ /* process the families now */
+
+ for ( num = 0; num < 2; num++ )
+ {
+ PSH_Blue_Zone zone1, zone2;
+ FT_UInt count1, count2;
+ PSH_Blue_Table normal, family;
+
+
+ switch ( num )
+ {
+ case 0:
+ normal = &blues->normal_top;
+ family = &blues->family_top;
+ break;
+
+ default:
+ normal = &blues->normal_bottom;
+ family = &blues->family_bottom;
+ }
+
+ zone1 = normal->zones;
+ count1 = normal->count;
+
+ for ( ; count1 > 0; count1--, zone1++ )
+ {
+ /* try to find a family zone whose reference position is less */
+ /* than 1 pixel far from the current zone */
+ zone2 = family->zones;
+ count2 = family->count;
+
+ for ( ; count2 > 0; count2--, zone2++ )
+ {
+ FT_Pos Delta;
+
+
+ Delta = zone1->org_ref - zone2->org_ref;
+ if ( Delta < 0 )
+ Delta = -Delta;
+
+ if ( FT_MulFix( Delta, scale ) < 64 )
+ {
+ zone1->cur_top = zone2->cur_top;
+ zone1->cur_bottom = zone2->cur_bottom;
+ zone1->cur_ref = zone2->cur_ref;
+ zone1->cur_delta = zone2->cur_delta;
+ break;
+ }
+ }
+ }
+ }
+ }
+
+
+ FT_LOCAL_DEF( void )
+ psh_blues_snap_stem( PSH_Blues blues,
+ FT_Int stem_top,
+ FT_Int stem_bot,
+ PSH_Alignment alignment )
+ {
+ PSH_Blue_Table table;
+ FT_UInt count;
+ FT_Pos delta;
+ PSH_Blue_Zone zone;
+ FT_Int no_shoots;
+
+
+ alignment->align = PSH_BLUE_ALIGN_NONE;
+
+ no_shoots = blues->no_overshoots;
+
+ /* lookup stem top in top zones table */
+ table = &blues->normal_top;
+ count = table->count;
+ zone = table->zones;
+
+ for ( ; count > 0; count--, zone++ )
+ {
+ delta = stem_top - zone->org_bottom;
+ if ( delta < -blues->blue_fuzz )
+ break;
+
+ if ( stem_top <= zone->org_top + blues->blue_fuzz )
+ {
+ if ( no_shoots || delta <= blues->blue_threshold )
+ {
+ alignment->align |= PSH_BLUE_ALIGN_TOP;
+ alignment->align_top = zone->cur_ref;
+ }
+ break;
+ }
+ }
+
+ /* look up stem bottom in bottom zones table */
+ table = &blues->normal_bottom;
+ count = table->count;
+ zone = table->zones + count-1;
+
+ for ( ; count > 0; count--, zone-- )
+ {
+ delta = zone->org_top - stem_bot;
+ if ( delta < -blues->blue_fuzz )
+ break;
+
+ if ( stem_bot >= zone->org_bottom - blues->blue_fuzz )
+ {
+ if ( no_shoots || delta < blues->blue_shift )
+ {
+ alignment->align |= PSH_BLUE_ALIGN_BOT;
+ alignment->align_bot = zone->cur_ref;
+ }
+ break;
+ }
+ }
+ }
+
+
+ /*************************************************************************/
+ /*************************************************************************/
+ /***** *****/
+ /***** GLOBAL HINTS *****/
+ /***** *****/
+ /*************************************************************************/
+ /*************************************************************************/
+
+ static void
+ psh_globals_destroy( PSH_Globals globals )
+ {
+ if ( globals )
+ {
+ FT_Memory memory;
+
+
+ memory = globals->memory;
+ globals->dimension[0].stdw.count = 0;
+ globals->dimension[1].stdw.count = 0;
+
+ globals->blues.normal_top.count = 0;
+ globals->blues.normal_bottom.count = 0;
+ globals->blues.family_top.count = 0;
+ globals->blues.family_bottom.count = 0;
+
+ FT_FREE( globals );
+
+#ifdef DEBUG_HINTER
+ ps_debug_globals = 0;
+#endif
+ }
+ }
+
+
+ static FT_Error
+ psh_globals_new( FT_Memory memory,
+ T1_Private* priv,
+ PSH_Globals *aglobals )
+ {
+ PSH_Globals globals;
+ FT_Error error;
+
+
+ if ( !FT_NEW( globals ) )
+ {
+ FT_UInt count;
+ FT_Short* read;
+
+
+ globals->memory = memory;
+
+ /* copy standard widths */
+ {
+ PSH_Dimension dim = &globals->dimension[1];
+ PSH_Width write = dim->stdw.widths;
+
+
+ write->org = priv->standard_width[0];
+ write++;
+
+ read = priv->snap_widths;
+ for ( count = priv->num_snap_widths; count > 0; count-- )
+ {
+ write->org = *read;
+ write++;
+ read++;
+ }
+
+ dim->stdw.count = write - dim->stdw.widths;
+ }
+
+ /* copy standard heights */
+ {
+ PSH_Dimension dim = &globals->dimension[0];
+ PSH_Width write = dim->stdw.widths;
+
+
+ write->org = priv->standard_height[0];
+ write++;
+ read = priv->snap_heights;
+ for ( count = priv->num_snap_heights; count > 0; count-- )
+ {
+ write->org = *read;
+ write++;
+ read++;
+ }
+
+ dim->stdw.count = write - dim->stdw.widths;
+ }
+
+ /* copy blue zones */
+ psh_blues_set_zones( &globals->blues, priv->num_blue_values,
+ priv->blue_values, priv->num_other_blues,
+ priv->other_blues, priv->blue_fuzz, 0 );
+
+ psh_blues_set_zones( &globals->blues, priv->num_family_blues,
+ priv->family_blues, priv->num_family_other_blues,
+ priv->family_other_blues, priv->blue_fuzz, 1 );
+
+ globals->blues.blue_scale = priv->blue_scale
+ ? priv->blue_scale
+ : 0x28937L; /* 0.039625 * 0x400000L */
+
+ globals->blues.blue_shift = priv->blue_shift
+ ? priv->blue_shift
+ : 7;
+
+ globals->blues.blue_fuzz = priv->blue_fuzz;
+
+ globals->dimension[0].scale_mult = 0;
+ globals->dimension[0].scale_delta = 0;
+ globals->dimension[1].scale_mult = 0;
+ globals->dimension[1].scale_delta = 0;
+
+#ifdef DEBUG_HINTER
+ ps_debug_globals = globals;
+#endif
+ }
+
+ *aglobals = globals;
+ return error;
+ }
+
+
+ static FT_Error
+ psh_globals_set_scale( PSH_Globals globals,
+ FT_Fixed x_scale,
+ FT_Fixed y_scale,
+ FT_Fixed x_delta,
+ FT_Fixed y_delta )
+ {
+ PSH_Dimension dim = &globals->dimension[0];
+
+
+ dim = &globals->dimension[0];
+ if ( x_scale != dim->scale_mult ||
+ x_delta != dim->scale_delta )
+ {
+ dim->scale_mult = x_scale;
+ dim->scale_delta = x_delta;
+
+ psh_globals_scale_widths( globals, 0 );
+ }
+
+ dim = &globals->dimension[1];
+ if ( y_scale != dim->scale_mult ||
+ y_delta != dim->scale_delta )
+ {
+ dim->scale_mult = y_scale;
+ dim->scale_delta = y_delta;
+
+ psh_globals_scale_widths( globals, 1 );
+ psh_blues_scale_zones( &globals->blues, y_scale, y_delta );
+ }
+
+ return 0;
+ }
+
+
+ FT_LOCAL_DEF( void )
+ psh_globals_funcs_init( PSH_Globals_FuncsRec* funcs )
+ {
+ funcs->create = psh_globals_new;
+ funcs->set_scale = psh_globals_set_scale;
+ funcs->destroy = psh_globals_destroy;
+ }
+
+
+/* END */
--- /dev/null
+++ b/libfreetype/pshglob.h
@@ -1,0 +1,187 @@
+/***************************************************************************/
+/* */
+/* pshglob.h */
+/* */
+/* PostScript hinter global hinting management. */
+/* */
+/* Copyright 2001, 2002 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+
+#ifndef __PSHGLOB_H__
+#define __PSHGLOB_H__
+
+
+#include FT_FREETYPE_H
+#include FT_INTERNAL_POSTSCRIPT_HINTS_H
+
+
+FT_BEGIN_HEADER
+
+
+ /*************************************************************************/
+ /*************************************************************************/
+ /***** *****/
+ /***** GLOBAL HINTS INTERNALS *****/
+ /***** *****/
+ /*************************************************************************/
+ /*************************************************************************/
+
+
+ /*************************************************************************/
+ /* */
+ /* @constant: */
+ /* PS_GLOBALS_MAX_BLUE_ZONES */
+ /* */
+ /* @description: */
+ /* The maximum number of blue zones in a font global hints structure. */
+ /* See @PS_Globals_BluesRec. */
+ /* */
+#define PS_GLOBALS_MAX_BLUE_ZONES 16
+
+
+ /*************************************************************************/
+ /* */
+ /* @constant: */
+ /* PS_GLOBALS_MAX_STD_WIDTHS */
+ /* */
+ /* @description: */
+ /* The maximum number of standard and snap widths in either the */
+ /* horizontal or vertical direction. See @PS_Globals_WidthsRec. */
+ /* */
+#define PS_GLOBALS_MAX_STD_WIDTHS 16
+
+
+ /* standard and snap width */
+ typedef struct PSH_WidthRec_
+ {
+ FT_Int org;
+ FT_Pos cur;
+ FT_Pos fit;
+
+ } PSH_WidthRec, *PSH_Width;
+
+
+ /* standard and snap widths table */
+ typedef struct PSH_WidthsRec_
+ {
+ FT_UInt count;
+ PSH_WidthRec widths[PS_GLOBALS_MAX_STD_WIDTHS];
+
+ } PSH_WidthsRec, *PSH_Widths;
+
+
+ typedef struct PSH_DimensionRec_
+ {
+ PSH_WidthsRec stdw;
+ FT_Fixed scale_mult;
+ FT_Fixed scale_delta;
+
+ } PSH_DimensionRec, *PSH_Dimension;
+
+
+ /* blue zone descriptor */
+ typedef struct PSH_Blue_ZoneRec_
+ {
+ FT_Int org_ref;
+ FT_Int org_delta;
+ FT_Int org_top;
+ FT_Int org_bottom;
+
+ FT_Pos cur_ref;
+ FT_Pos cur_delta;
+ FT_Pos cur_bottom;
+ FT_Pos cur_top;
+
+ } PSH_Blue_ZoneRec, *PSH_Blue_Zone;
+
+
+ typedef struct PSH_Blue_TableRec_
+ {
+ FT_UInt count;
+ PSH_Blue_ZoneRec zones[PS_GLOBALS_MAX_BLUE_ZONES];
+
+ } PSH_Blue_TableRec, *PSH_Blue_Table;
+
+
+ /* blue zones table */
+ typedef struct PSH_BluesRec_
+ {
+ PSH_Blue_TableRec normal_top;
+ PSH_Blue_TableRec normal_bottom;
+ PSH_Blue_TableRec family_top;
+ PSH_Blue_TableRec family_bottom;
+
+ FT_Fixed blue_scale;
+ FT_Int blue_shift;
+ FT_Int blue_threshold;
+ FT_Int blue_fuzz;
+ FT_Bool no_overshoots;
+
+ } PSH_BluesRec, *PSH_Blues;
+
+
+ /* font globals. */
+ /* dimension 0 => X coordinates + vertical hints/stems */
+ /* dimension 1 => Y coordinates + horizontal hints/stems */
+ typedef struct PSH_GlobalsRec_
+ {
+ FT_Memory memory;
+ PSH_DimensionRec dimension[2];
+ PSH_BluesRec blues;
+
+ } PSH_GlobalsRec;
+
+
+#define PSH_BLUE_ALIGN_NONE 0
+#define PSH_BLUE_ALIGN_TOP 1
+#define PSH_BLUE_ALIGN_BOT 2
+
+
+ typedef struct PSH_AlignmentRec_
+ {
+ int align;
+ FT_Pos align_top;
+ FT_Pos align_bot;
+
+ } PSH_AlignmentRec, *PSH_Alignment;
+
+
+ FT_LOCAL( void )
+ psh_globals_funcs_init( PSH_Globals_FuncsRec* funcs );
+
+
+ /* snap a stem width to fitter coordinates. `org_width' is in font */
+ /* units. The result is in device pixels (26.6 format). */
+ FT_LOCAL( FT_Pos )
+ psh_dimension_snap_width( PSH_Dimension dimension,
+ FT_Int org_width );
+
+ /* snap a stem to one or two blue zones */
+ FT_LOCAL( void )
+ psh_blues_snap_stem( PSH_Blues blues,
+ FT_Int stem_top,
+ FT_Int stem_bot,
+ PSH_Alignment alignment );
+ /* */
+
+#ifdef DEBUG_HINTER
+ extern PSH_Globals ps_debug_globals;
+#endif
+
+
+FT_END_HEADER
+
+
+#endif /* __PSHGLOB_H__ */
+
+
+/* END */
--- /dev/null
+++ b/libfreetype/pshinter.c
@@ -1,0 +1,30 @@
+/***************************************************************************/
+/* */
+/* pshinter.c */
+/* */
+/* FreeType PostScript Hinting module */
+/* */
+/* Copyright 2001 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+
+#define FT_MAKE_OPTION_SINGLE_OBJECT
+
+#include <ft2build.h>
+#include "pshrec.c"
+#include "pshglob.c"
+#include "pshalgo1.c"
+#include "pshalgo2.c"
+#include "pshalgo3.c"
+#include "pshmod.c"
+
+
+/* END */
--- /dev/null
+++ b/libfreetype/pshmod.c
@@ -1,0 +1,120 @@
+/***************************************************************************/
+/* */
+/* pshmod.c */
+/* */
+/* FreeType PostScript hinter module implementation (body). */
+/* */
+/* Copyright 2001, 2002 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+
+#include <ft2build.h>
+#include FT_INTERNAL_OBJECTS_H
+#include "pshrec.h"
+#include "pshalgo.h"
+
+
+ /* the Postscript Hinter module structure */
+ typedef struct PS_Hinter_Module_Rec_
+ {
+ FT_ModuleRec root;
+ PS_HintsRec ps_hints;
+
+ PSH_Globals_FuncsRec globals_funcs;
+ T1_Hints_FuncsRec t1_funcs;
+ T2_Hints_FuncsRec t2_funcs;
+
+ } PS_Hinter_ModuleRec, *PS_Hinter_Module;
+
+
+ /* finalize module */
+ FT_CALLBACK_DEF( void )
+ ps_hinter_done( PS_Hinter_Module module )
+ {
+ module->t1_funcs.hints = NULL;
+ module->t2_funcs.hints = NULL;
+
+ ps_hints_done( &module->ps_hints );
+ }
+
+
+ /* initialize module, create hints recorder and the interface */
+ FT_CALLBACK_DEF( FT_Error )
+ ps_hinter_init( PS_Hinter_Module module )
+ {
+ FT_Memory memory = module->root.memory;
+
+
+ ps_hints_init( &module->ps_hints, memory );
+
+ psh_globals_funcs_init( &module->globals_funcs );
+
+ t1_hints_funcs_init( &module->t1_funcs );
+ module->t1_funcs.hints = (T1_Hints)&module->ps_hints;
+
+ t2_hints_funcs_init( &module->t2_funcs );
+ module->t2_funcs.hints = (T2_Hints)&module->ps_hints;
+
+ return 0;
+ }
+
+
+ /* returns global hints interface */
+ FT_CALLBACK_DEF( PSH_Globals_Funcs )
+ pshinter_get_globals_funcs( FT_Module module )
+ {
+ return &((PS_Hinter_Module)module)->globals_funcs;
+ }
+
+
+ /* return Type 1 hints interface */
+ FT_CALLBACK_DEF( T1_Hints_Funcs )
+ pshinter_get_t1_funcs( FT_Module module )
+ {
+ return &((PS_Hinter_Module)module)->t1_funcs;
+ }
+
+
+ /* return Type 2 hints interface */
+ FT_CALLBACK_DEF( T2_Hints_Funcs )
+ pshinter_get_t2_funcs( FT_Module module )
+ {
+ return &((PS_Hinter_Module)module)->t2_funcs;
+ }
+
+
+ static
+ const PSHinter_Interface pshinter_interface =
+ {
+ pshinter_get_globals_funcs,
+ pshinter_get_t1_funcs,
+ pshinter_get_t2_funcs
+ };
+
+
+ FT_CALLBACK_TABLE_DEF
+ const FT_Module_Class pshinter_module_class =
+ {
+ 0,
+ sizeof ( PS_Hinter_ModuleRec ),
+ "pshinter",
+ 0x10000L,
+ 0x20000L,
+
+ &pshinter_interface, /* module-specific interface */
+
+ (FT_Module_Constructor)ps_hinter_init,
+ (FT_Module_Destructor) ps_hinter_done,
+ (FT_Module_Requester) 0 /* no additional interface for now */
+ };
+
+
+/* END */
--- /dev/null
+++ b/libfreetype/pshmod.h
@@ -1,0 +1,39 @@
+/***************************************************************************/
+/* */
+/* pshmod.h */
+/* */
+/* PostScript hinter module interface (specification). */
+/* */
+/* Copyright 2001 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+
+#ifndef __PSHMOD_H__
+#define __PSHMOD_H__
+
+
+#include <ft2build.h>
+#include FT_MODULE_H
+
+
+FT_BEGIN_HEADER
+
+
+ FT_EXPORT_VAR( const FT_Module_Class ) pshinter_module_class;
+
+
+FT_END_HEADER
+
+
+#endif /* __PSHMOD_H__ */
+
+
+/* END */
--- /dev/null
+++ b/libfreetype/pshrec.c
@@ -1,0 +1,1211 @@
+/***************************************************************************/
+/* */
+/* pshrec.c */
+/* */
+/* FreeType PostScript hints recorder (body). */
+/* */
+/* Copyright 2001, 2002 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+
+#include <ft2build.h>
+#include FT_FREETYPE_H
+#include FT_INTERNAL_OBJECTS_H
+#include FT_INTERNAL_DEBUG_H
+#include "pshrec.h"
+#include "pshalgo.h"
+
+#undef FT_COMPONENT
+#define FT_COMPONENT trace_pshrec
+
+#ifdef DEBUG_HINTER
+ PS_Hints ps_debug_hints = 0;
+ int ps_debug_no_horz_hints = 0;
+ int ps_debug_no_vert_hints = 0;
+#endif
+
+
+ /*************************************************************************/
+ /*************************************************************************/
+ /***** *****/
+ /***** PS_HINT MANAGEMENT *****/
+ /***** *****/
+ /*************************************************************************/
+ /*************************************************************************/
+
+ /* destroy hints table */
+ static void
+ ps_hint_table_done( PS_Hint_Table table,
+ FT_Memory memory )
+ {
+ FT_FREE( table->hints );
+ table->num_hints = 0;
+ table->max_hints = 0;
+ }
+
+
+ /* ensure that a table can contain "count" elements */
+ static FT_Error
+ ps_hint_table_ensure( PS_Hint_Table table,
+ FT_UInt count,
+ FT_Memory memory )
+ {
+ FT_UInt old_max = table->max_hints;
+ FT_UInt new_max = count;
+ FT_Error error = 0;
+
+
+ if ( new_max > old_max )
+ {
+ /* try to grow the table */
+ new_max = ( new_max + 7 ) & -8;
+ if ( !FT_RENEW_ARRAY( table->hints, old_max, new_max ) )
+ table->max_hints = new_max;
+ }
+ return error;
+ }
+
+
+ static FT_Error
+ ps_hint_table_alloc( PS_Hint_Table table,
+ FT_Memory memory,
+ PS_Hint *ahint )
+ {
+ FT_Error error = 0;
+ FT_UInt count;
+ PS_Hint hint = 0;
+
+
+ count = table->num_hints;
+ count++;
+
+ if ( count >= table->max_hints )
+ {
+ error = ps_hint_table_ensure( table, count, memory );
+ if ( error )
+ goto Exit;
+ }
+
+ hint = table->hints + count - 1;
+ hint->pos = 0;
+ hint->len = 0;
+ hint->flags = 0;
+
+ table->num_hints = count;
+
+ Exit:
+ *ahint = hint;
+ return error;
+ }
+
+
+ /*************************************************************************/
+ /*************************************************************************/
+ /***** *****/
+ /***** PS_MASK MANAGEMENT *****/
+ /***** *****/
+ /*************************************************************************/
+ /*************************************************************************/
+
+ /* destroy mask */
+ static void
+ ps_mask_done( PS_Mask mask,
+ FT_Memory memory )
+ {
+ FT_FREE( mask->bytes );
+ mask->num_bits = 0;
+ mask->max_bits = 0;
+ mask->end_point = 0;
+ }
+
+
+ /* ensure that a mask can contain "count" bits */
+ static FT_Error
+ ps_mask_ensure( PS_Mask mask,
+ FT_UInt count,
+ FT_Memory memory )
+ {
+ FT_UInt old_max = ( mask->max_bits + 7 ) >> 3;
+ FT_UInt new_max = ( count + 7 ) >> 3;
+ FT_Error error = 0;
+
+
+ if ( new_max > old_max )
+ {
+ new_max = ( new_max + 7 ) & -8;
+ if ( !FT_RENEW_ARRAY( mask->bytes, old_max, new_max ) )
+ mask->max_bits = new_max * 8;
+ }
+ return error;
+ }
+
+
+ /* test a bit value in a given mask */
+ static FT_Int
+ ps_mask_test_bit( PS_Mask mask,
+ FT_Int idx )
+ {
+ if ( (FT_UInt)idx >= mask->num_bits )
+ return 0;
+
+ return mask->bytes[idx >> 3] & ( 0x80 >> ( idx & 7 ) );
+ }
+
+
+ /* clear a given bit */
+ static void
+ ps_mask_clear_bit( PS_Mask mask,
+ FT_Int idx )
+ {
+ FT_Byte* p;
+
+
+ if ( (FT_UInt)idx >= mask->num_bits )
+ return;
+
+ p = mask->bytes + ( idx >> 3 );
+ p[0] = (FT_Byte)( p[0] & ~( 0x80 >> ( idx & 7 ) ) );
+ }
+
+
+ /* set a given bit, possibly grow the mask */
+ static FT_Error
+ ps_mask_set_bit( PS_Mask mask,
+ FT_Int idx,
+ FT_Memory memory )
+ {
+ FT_Error error = 0;
+ FT_Byte* p;
+
+
+ if ( idx < 0 )
+ goto Exit;
+
+ if ( (FT_UInt)idx >= mask->num_bits )
+ {
+ error = ps_mask_ensure( mask, idx + 1, memory );
+ if ( error )
+ goto Exit;
+
+ mask->num_bits = idx + 1;
+ }
+
+ p = mask->bytes + ( idx >> 3 );
+ p[0] = (FT_Byte)( p[0] | ( 0x80 >> ( idx & 7 ) ) );
+
+ Exit:
+ return error;
+ }
+
+
+ /* destroy mask table */
+ static void
+ ps_mask_table_done( PS_Mask_Table table,
+ FT_Memory memory )
+ {
+ FT_UInt count = table->max_masks;
+ PS_Mask mask = table->masks;
+
+
+ for ( ; count > 0; count--, mask++ )
+ ps_mask_done( mask, memory );
+
+ FT_FREE( table->masks );
+ table->num_masks = 0;
+ table->max_masks = 0;
+ }
+
+
+ /* ensure that a mask table can contain "count" masks */
+ static FT_Error
+ ps_mask_table_ensure( PS_Mask_Table table,
+ FT_UInt count,
+ FT_Memory memory )
+ {
+ FT_UInt old_max = table->max_masks;
+ FT_UInt new_max = count;
+ FT_Error error = 0;
+
+
+ if ( new_max > old_max )
+ {
+ new_max = ( new_max + 7 ) & -8;
+ if ( !FT_RENEW_ARRAY( table->masks, old_max, new_max ) )
+ table->max_masks = new_max;
+ }
+ return error;
+ }
+
+
+ /* allocate a new mask in a table */
+ static FT_Error
+ ps_mask_table_alloc( PS_Mask_Table table,
+ FT_Memory memory,
+ PS_Mask *amask )
+ {
+ FT_UInt count;
+ FT_Error error = 0;
+ PS_Mask mask = 0;
+
+
+ count = table->num_masks;
+ count++;
+
+ if ( count > table->max_masks )
+ {
+ error = ps_mask_table_ensure( table, count, memory );
+ if ( error )
+ goto Exit;
+ }
+
+ mask = table->masks + count - 1;
+ mask->num_bits = 0;
+ mask->end_point = 0;
+ table->num_masks = count;
+
+ Exit:
+ *amask = mask;
+ return error;
+ }
+
+
+ /* return last hint mask in a table, create one if the table is empty */
+ static FT_Error
+ ps_mask_table_last( PS_Mask_Table table,
+ FT_Memory memory,
+ PS_Mask *amask )
+ {
+ FT_Error error = 0;
+ FT_UInt count;
+ PS_Mask mask;
+
+
+ count = table->num_masks;
+ if ( count == 0 )
+ {
+ error = ps_mask_table_alloc( table, memory, &mask );
+ if ( error )
+ goto Exit;
+ }
+ else
+ mask = table->masks + count - 1;
+
+ Exit:
+ *amask = mask;
+ return error;
+ }
+
+
+ /* set a new mask to a given bit range */
+ static FT_Error
+ ps_mask_table_set_bits( PS_Mask_Table table,
+ FT_Byte* source,
+ FT_UInt bit_pos,
+ FT_UInt bit_count,
+ FT_Memory memory )
+ {
+ FT_Error error = 0;
+ PS_Mask mask;
+
+
+ /* allocate new mask, and grow it to "bit_count" bits */
+ error = ps_mask_table_alloc( table, memory, &mask );
+ if ( error )
+ goto Exit;
+
+ error = ps_mask_ensure( mask, bit_count, memory );
+ if ( error )
+ goto Exit;
+
+ mask->num_bits = bit_count;
+
+ /* now, copy bits */
+ {
+ FT_Byte* read = source + ( bit_pos >> 3 );
+ FT_Int rmask = 0x80 >> ( bit_pos & 7 );
+ FT_Byte* write = mask->bytes;
+ FT_Int wmask = 0x80;
+ FT_Int val;
+
+
+ for ( ; bit_count > 0; bit_count-- )
+ {
+ val = write[0] & ~wmask;
+
+ if ( read[0] & rmask )
+ val |= wmask;
+
+ write[0] = (FT_Byte)val;
+
+ rmask >>= 1;
+ if ( rmask == 0 )
+ {
+ read++;
+ rmask = 0x80;
+ }
+
+ wmask >>= 1;
+ if ( wmask == 0 )
+ {
+ write++;
+ wmask = 0x80;
+ }
+ }
+ }
+
+ Exit:
+ return error;
+ }
+
+
+ /* test whether two masks in a table intersect */
+ static FT_Int
+ ps_mask_table_test_intersect( PS_Mask_Table table,
+ FT_Int index1,
+ FT_Int index2 )
+ {
+ PS_Mask mask1 = table->masks + index1;
+ PS_Mask mask2 = table->masks + index2;
+ FT_Byte* p1 = mask1->bytes;
+ FT_Byte* p2 = mask2->bytes;
+ FT_UInt count1 = mask1->num_bits;
+ FT_UInt count2 = mask2->num_bits;
+ FT_UInt count;
+
+
+ count = ( count1 <= count2 ) ? count1 : count2;
+ for ( ; count >= 8; count -= 8 )
+ {
+ if ( p1[0] & p2[0] )
+ return 1;
+
+ p1++;
+ p2++;
+ }
+
+ if ( count == 0 )
+ return 0;
+
+ return ( p1[0] & p2[0] ) & ~( 0xFF >> count );
+ }
+
+
+ /* merge two masks, used by ps_mask_table_merge_all */
+ static FT_Error
+ ps_mask_table_merge( PS_Mask_Table table,
+ FT_Int index1,
+ FT_Int index2,
+ FT_Memory memory )
+ {
+ FT_UInt temp;
+ FT_Error error = 0;
+
+
+ /* swap index1 and index2 so that index1 < index2 */
+ if ( index1 > index2 )
+ {
+ temp = index1;
+ index1 = index2;
+ index2 = temp;
+ }
+
+ if ( index1 < index2 && index1 >= 0 && index2 < (FT_Int)table->num_masks )
+ {
+ /* we need to merge the bitsets of index1 and index2 with a */
+ /* simple union */
+ PS_Mask mask1 = table->masks + index1;
+ PS_Mask mask2 = table->masks + index2;
+ FT_UInt count1 = mask1->num_bits;
+ FT_UInt count2 = mask2->num_bits;
+ FT_Int delta;
+
+
+ if ( count2 > 0 )
+ {
+ FT_UInt pos;
+ FT_Byte* read;
+ FT_Byte* write;
+
+
+ /* if "count2" is greater than "count1", we need to grow the */
+ /* first bitset, and clear the highest bits */
+ if ( count2 > count1 )
+ {
+ error = ps_mask_ensure( mask1, count2, memory );
+ if ( error )
+ goto Exit;
+
+ for ( pos = count1; pos < count2; pos++ )
+ ps_mask_clear_bit( mask1, pos );
+ }
+
+ /* merge (unite) the bitsets */
+ read = mask2->bytes;
+ write = mask1->bytes;
+ pos = (FT_UInt)( ( count2 + 7 ) >> 3 );
+
+ for ( ; pos > 0; pos-- )
+ {
+ write[0] = (FT_Byte)( write[0] | read[0] );
+ write++;
+ read++;
+ }
+ }
+
+ /* Now, remove "mask2" from the list. We need to keep the masks */
+ /* sorted in order of importance, so move table elements. */
+ mask2->num_bits = 0;
+ mask2->end_point = 0;
+
+ delta = table->num_masks - 1 - index2; /* number of masks to move */
+ if ( delta > 0 )
+ {
+ /* move to end of table for reuse */
+ PS_MaskRec dummy = *mask2;
+
+
+ ft_memmove( mask2, mask2 + 1, delta * sizeof ( PS_MaskRec ) );
+
+ mask2[delta] = dummy;
+ }
+
+ table->num_masks--;
+ }
+ else
+ FT_ERROR(( "ps_mask_table_merge: ignoring invalid indices (%d,%d)\n",
+ index1, index2 ));
+
+ Exit:
+ return error;
+ }
+
+
+ /* Try to merge all masks in a given table. This is used to merge */
+ /* all counter masks into independent counter "paths". */
+ /* */
+ static FT_Error
+ ps_mask_table_merge_all( PS_Mask_Table table,
+ FT_Memory memory )
+ {
+ FT_Int index1, index2;
+ FT_Error error = 0;
+
+
+ for ( index1 = table->num_masks - 1; index1 > 0; index1-- )
+ {
+ for ( index2 = index1 - 1; index2 >= 0; index2-- )
+ {
+ if ( ps_mask_table_test_intersect( table, index1, index2 ) )
+ {
+ error = ps_mask_table_merge( table, index2, index1, memory );
+ if ( error )
+ goto Exit;
+
+ break;
+ }
+ }
+ }
+
+ Exit:
+ return error;
+ }
+
+
+ /*************************************************************************/
+ /*************************************************************************/
+ /***** *****/
+ /***** PS_DIMENSION MANAGEMENT *****/
+ /***** *****/
+ /*************************************************************************/
+ /*************************************************************************/
+
+
+ /* finalize a given dimension */
+ static void
+ ps_dimension_done( PS_Dimension dimension,
+ FT_Memory memory )
+ {
+ ps_mask_table_done( &dimension->counters, memory );
+ ps_mask_table_done( &dimension->masks, memory );
+ ps_hint_table_done( &dimension->hints, memory );
+ }
+
+
+ /* initialize a given dimension */
+ static void
+ ps_dimension_init( PS_Dimension dimension )
+ {
+ dimension->hints.num_hints = 0;
+ dimension->masks.num_masks = 0;
+ dimension->counters.num_masks = 0;
+ }
+
+
+#if 0
+
+ /* set a bit at a given index in the current hint mask */
+ static FT_Error
+ ps_dimension_set_mask_bit( PS_Dimension dim,
+ FT_UInt idx,
+ FT_Memory memory )
+ {
+ PS_Mask mask;
+ FT_Error error = 0;
+
+
+ /* get last hint mask */
+ error = ps_mask_table_last( &dim->masks, memory, &mask );
+ if ( error )
+ goto Exit;
+
+ error = ps_mask_set_bit( mask, idx, memory );
+
+ Exit:
+ return error;
+ }
+
+#endif
+
+ /* set the end point in a mask, called from "End" & "Reset" methods */
+ static void
+ ps_dimension_end_mask( PS_Dimension dim,
+ FT_UInt end_point )
+ {
+ FT_UInt count = dim->masks.num_masks;
+ PS_Mask mask;
+
+
+ if ( count > 0 )
+ {
+ mask = dim->masks.masks + count - 1;
+ mask->end_point = end_point;
+ }
+ }
+
+
+ /* set the end point in the current mask, then create a new empty one */
+ /* (called by "Reset" method) */
+ static FT_Error
+ ps_dimension_reset_mask( PS_Dimension dim,
+ FT_UInt end_point,
+ FT_Memory memory )
+ {
+ PS_Mask mask;
+
+
+ /* end current mask */
+ ps_dimension_end_mask( dim, end_point );
+
+ /* allocate new one */
+ return ps_mask_table_alloc( &dim->masks, memory, &mask );
+ }
+
+
+ /* set a new mask, called from the "T2Stem" method */
+ static FT_Error
+ ps_dimension_set_mask_bits( PS_Dimension dim,
+ const FT_Byte* source,
+ FT_UInt source_pos,
+ FT_UInt source_bits,
+ FT_UInt end_point,
+ FT_Memory memory )
+ {
+ FT_Error error = 0;
+
+
+ /* reset current mask, if any */
+ error = ps_dimension_reset_mask( dim, end_point, memory );
+ if ( error )
+ goto Exit;
+
+ /* set bits in new mask */
+ error = ps_mask_table_set_bits( &dim->masks, (FT_Byte*)source,
+ source_pos, source_bits, memory );
+
+ Exit:
+ return error;
+ }
+
+
+ /* add a new single stem (called from "T1Stem" method) */
+ static FT_Error
+ ps_dimension_add_t1stem( PS_Dimension dim,
+ FT_Int pos,
+ FT_Int len,
+ FT_Memory memory,
+ FT_Int *aindex )
+ {
+ FT_Error error = 0;
+ FT_UInt flags = 0;
+
+
+ /* detect ghost stem */
+ if ( len < 0 )
+ {
+ flags |= PS_HINT_FLAG_GHOST;
+ if ( len == -21 )
+ {
+ flags |= PS_HINT_FLAG_BOTTOM;
+ pos += len;
+ }
+ len = 0;
+ }
+
+ if ( aindex )
+ *aindex = -1;
+
+ /* now, lookup stem in the current hints table */
+ {
+ PS_Mask mask;
+ FT_UInt idx;
+ FT_UInt max = dim->hints.num_hints;
+ PS_Hint hint = dim->hints.hints;
+
+
+ for ( idx = 0; idx < max; idx++, hint++ )
+ {
+ if ( hint->pos == pos && hint->len == len )
+ break;
+ }
+
+ /* we need to create a new hint in the table */
+ if ( idx >= max )
+ {
+ error = ps_hint_table_alloc( &dim->hints, memory, &hint );
+ if ( error )
+ goto Exit;
+
+ hint->pos = pos;
+ hint->len = len;
+ hint->flags = flags;
+ }
+
+ /* now, store the hint in the current mask */
+ error = ps_mask_table_last( &dim->masks, memory, &mask );
+ if ( error )
+ goto Exit;
+
+ error = ps_mask_set_bit( mask, idx, memory );
+ if ( error )
+ goto Exit;
+
+ if ( aindex )
+ *aindex = (FT_Int)idx;
+ }
+
+ Exit:
+ return error;
+ }
+
+
+ /* add a "hstem3/vstem3" counter to our dimension table */
+ static FT_Error
+ ps_dimension_add_counter( PS_Dimension dim,
+ FT_Int hint1,
+ FT_Int hint2,
+ FT_Int hint3,
+ FT_Memory memory )
+ {
+ FT_Error error = 0;
+ FT_UInt count = dim->counters.num_masks;
+ PS_Mask counter = dim->counters.masks;
+
+
+ /* try to find an existing counter mask that already uses */
+ /* one of these stems here */
+ for ( ; count > 0; count--, counter++ )
+ {
+ if ( ps_mask_test_bit( counter, hint1 ) ||
+ ps_mask_test_bit( counter, hint2 ) ||
+ ps_mask_test_bit( counter, hint3 ) )
+ break;
+ }
+
+ /* creat a new counter when needed */
+ if ( count == 0 )
+ {
+ error = ps_mask_table_alloc( &dim->counters, memory, &counter );
+ if ( error )
+ goto Exit;
+ }
+
+ /* now, set the bits for our hints in the counter mask */
+ error = ps_mask_set_bit( counter, hint1, memory );
+ if ( error )
+ goto Exit;
+
+ error = ps_mask_set_bit( counter, hint2, memory );
+ if ( error )
+ goto Exit;
+
+ error = ps_mask_set_bit( counter, hint3, memory );
+ if ( error )
+ goto Exit;
+
+ Exit:
+ return error;
+ }
+
+
+ /* end of recording session for a given dimension */
+ static FT_Error
+ ps_dimension_end( PS_Dimension dim,
+ FT_UInt end_point,
+ FT_Memory memory )
+ {
+ /* end hint mask table */
+ ps_dimension_end_mask( dim, end_point );
+
+ /* merge all counter masks into independent "paths" */
+ return ps_mask_table_merge_all( &dim->counters, memory );
+ }
+
+
+ /*************************************************************************/
+ /*************************************************************************/
+ /***** *****/
+ /***** PS_RECORDER MANAGEMENT *****/
+ /***** *****/
+ /*************************************************************************/
+ /*************************************************************************/
+
+
+ /* destroy hints */
+ FT_LOCAL( void )
+ ps_hints_done( PS_Hints hints )
+ {
+ FT_Memory memory = hints->memory;
+
+
+ ps_dimension_done( &hints->dimension[0], memory );
+ ps_dimension_done( &hints->dimension[1], memory );
+
+ hints->error = 0;
+ hints->memory = 0;
+ }
+
+
+ FT_LOCAL( FT_Error )
+ ps_hints_init( PS_Hints hints,
+ FT_Memory memory )
+ {
+ FT_MEM_ZERO( hints, sizeof ( *hints ) );
+ hints->memory = memory;
+ return 0;
+ }
+
+
+ /* initialize a hints for a new session */
+ static void
+ ps_hints_open( PS_Hints hints,
+ PS_Hint_Type hint_type )
+ {
+ switch ( hint_type )
+ {
+ case PS_HINT_TYPE_1:
+ case PS_HINT_TYPE_2:
+ hints->error = 0;
+ hints->hint_type = hint_type;
+
+ ps_dimension_init( &hints->dimension[0] );
+ ps_dimension_init( &hints->dimension[1] );
+ break;
+
+ default:
+ hints->error = FT_Err_Invalid_Argument;
+ hints->hint_type = hint_type;
+
+ FT_ERROR(( "ps_hints_open: invalid charstring type!\n" ));
+ break;
+ }
+ }
+
+
+ /* add one or more stems to the current hints table */
+ static void
+ ps_hints_stem( PS_Hints hints,
+ FT_Int dimension,
+ FT_UInt count,
+ FT_Long* stems )
+ {
+ if ( !hints->error )
+ {
+ /* limit "dimension" to 0..1 */
+ if ( dimension < 0 || dimension > 1 )
+ {
+ FT_ERROR(( "ps_hints_stem: invalid dimension (%d) used\n",
+ dimension ));
+ dimension = ( dimension != 0 );
+ }
+
+ /* record the stems in the current hints/masks table */
+ switch ( hints->hint_type )
+ {
+ case PS_HINT_TYPE_1: /* Type 1 "hstem" or "vstem" operator */
+ case PS_HINT_TYPE_2: /* Type 2 "hstem" or "vstem" operator */
+ {
+ PS_Dimension dim = &hints->dimension[dimension];
+
+
+ for ( ; count > 0; count--, stems += 2 )
+ {
+ FT_Error error;
+ FT_Memory memory = hints->memory;
+
+
+ error = ps_dimension_add_t1stem( dim, stems[0], stems[1],
+ memory, NULL );
+ if ( error )
+ {
+ FT_ERROR(( "ps_hints_stem: could not add stem"
+ " (%d,%d) to hints table\n", stems[0], stems[1] ));
+
+ hints->error = error;
+ return;
+ }
+ }
+ break;
+ }
+
+ default:
+ FT_ERROR(( "ps_hints_stem: called with invalid hint type (%d)\n",
+ hints->hint_type ));
+ break;
+ }
+ }
+ }
+
+
+ /* add one Type1 counter stem to the current hints table */
+ static void
+ ps_hints_t1stem3( PS_Hints hints,
+ FT_Int dimension,
+ FT_Long* stems )
+ {
+ FT_Error error = 0;
+
+
+ if ( !hints->error )
+ {
+ PS_Dimension dim;
+ FT_Memory memory = hints->memory;
+ FT_Int count;
+ FT_Int idx[3];
+
+
+ /* limit "dimension" to 0..1 */
+ if ( dimension < 0 || dimension > 1 )
+ {
+ FT_ERROR(( "ps_hints_t1stem3: invalid dimension (%d) used\n",
+ dimension ));
+ dimension = ( dimension != 0 );
+ }
+
+ dim = &hints->dimension[dimension];
+
+ /* there must be 6 elements in the 'stem' array */
+ if ( hints->hint_type == PS_HINT_TYPE_1 )
+ {
+ /* add the three stems to our hints/masks table */
+ for ( count = 0; count < 3; count++, stems += 2 )
+ {
+ error = ps_dimension_add_t1stem( dim, stems[0], stems[1],
+ memory, &idx[count] );
+ if ( error )
+ goto Fail;
+ }
+
+ /* now, add the hints to the counters table */
+ error = ps_dimension_add_counter( dim, idx[0], idx[1], idx[2],
+ memory );
+ if ( error )
+ goto Fail;
+ }
+ else
+ {
+ FT_ERROR(( "ps_hints_t1stem3: called with invalid hint type!\n" ));
+ error = FT_Err_Invalid_Argument;
+ goto Fail;
+ }
+ }
+
+ return;
+
+ Fail:
+ FT_ERROR(( "ps_hints_t1stem3: could not add counter stems to table\n" ));
+ hints->error = error;
+ }
+
+
+ /* reset hints (only with Type 1 hints) */
+ static void
+ ps_hints_t1reset( PS_Hints hints,
+ FT_UInt end_point )
+ {
+ FT_Error error = 0;
+
+
+ if ( !hints->error )
+ {
+ FT_Memory memory = hints->memory;
+
+
+ if ( hints->hint_type == PS_HINT_TYPE_1 )
+ {
+ error = ps_dimension_reset_mask( &hints->dimension[0],
+ end_point, memory );
+ if ( error )
+ goto Fail;
+
+ error = ps_dimension_reset_mask( &hints->dimension[1],
+ end_point, memory );
+ if ( error )
+ goto Fail;
+ }
+ else
+ {
+ /* invalid hint type */
+ error = FT_Err_Invalid_Argument;
+ goto Fail;
+ }
+ }
+ return;
+
+ Fail:
+ hints->error = error;
+ }
+
+
+ /* Type2 "hintmask" operator, add a new hintmask to each direction */
+ static void
+ ps_hints_t2mask( PS_Hints hints,
+ FT_UInt end_point,
+ FT_UInt bit_count,
+ const FT_Byte* bytes )
+ {
+ FT_Error error;
+
+
+ if ( !hints->error )
+ {
+ PS_Dimension dim = hints->dimension;
+ FT_Memory memory = hints->memory;
+ FT_UInt count1 = dim[0].hints.num_hints;
+ FT_UInt count2 = dim[1].hints.num_hints;
+
+
+ /* check bit count; must be equal to current total hint count */
+ if ( bit_count != count1 + count2 )
+ {
+ FT_ERROR(( "ps_hints_t2mask: "
+ "called with invalid bitcount %d (instead of %d)\n",
+ bit_count, count1 + count2 ));
+
+ /* simply ignore the operator */
+ return;
+ }
+
+ /* set-up new horizontal and vertical hint mask now */
+ error = ps_dimension_set_mask_bits( &dim[0], bytes, 0, count1,
+ end_point, memory );
+ if ( error )
+ goto Fail;
+
+ error = ps_dimension_set_mask_bits( &dim[1], bytes, count1, count2,
+ end_point, memory );
+ if ( error )
+ goto Fail;
+ }
+ return;
+
+ Fail:
+ hints->error = error;
+ }
+
+
+ static void
+ ps_hints_t2counter( PS_Hints hints,
+ FT_UInt bit_count,
+ const FT_Byte* bytes )
+ {
+ FT_Error error;
+
+
+ if ( !hints->error )
+ {
+ PS_Dimension dim = hints->dimension;
+ FT_Memory memory = hints->memory;
+ FT_UInt count1 = dim[0].hints.num_hints;
+ FT_UInt count2 = dim[1].hints.num_hints;
+
+
+ /* check bit count, must be equal to current total hint count */
+ if ( bit_count != count1 + count2 )
+ {
+ FT_ERROR(( "ps_hints_t2counter: "
+ "called with invalid bitcount %d (instead of %d)\n",
+ bit_count, count1 + count2 ));
+
+ /* simply ignore the operator */
+ return;
+ }
+
+ /* set-up new horizontal and vertical hint mask now */
+ error = ps_dimension_set_mask_bits( &dim[0], bytes, 0, count1,
+ 0, memory );
+ if ( error )
+ goto Fail;
+
+ error = ps_dimension_set_mask_bits( &dim[1], bytes, count1, count2,
+ 0, memory );
+ if ( error )
+ goto Fail;
+ }
+ return;
+
+ Fail:
+ hints->error = error;
+ }
+
+
+ /* end recording session */
+ static FT_Error
+ ps_hints_close( PS_Hints hints,
+ FT_UInt end_point )
+ {
+ FT_Error error;
+
+
+ error = hints->error;
+ if ( !error )
+ {
+ FT_Memory memory = hints->memory;
+ PS_Dimension dim = hints->dimension;
+
+
+ error = ps_dimension_end( &dim[0], end_point, memory );
+ if ( !error )
+ {
+ error = ps_dimension_end( &dim[1], end_point, memory );
+ }
+ }
+
+#ifdef DEBUG_HINTER
+ if ( !error )
+ ps_debug_hints = hints;
+#endif
+ return error;
+ }
+
+
+ /*************************************************************************/
+ /*************************************************************************/
+ /***** *****/
+ /***** TYPE 1 HINTS RECORDING INTERFACE *****/
+ /***** *****/
+ /*************************************************************************/
+ /*************************************************************************/
+
+ static void
+ t1_hints_open( T1_Hints hints )
+ {
+ ps_hints_open( (PS_Hints)hints, PS_HINT_TYPE_1 );
+ }
+
+ static void
+ t1_hints_stem( T1_Hints hints,
+ FT_Int dimension,
+ FT_Long* coords )
+ {
+ ps_hints_stem( (PS_Hints)hints, dimension, 1, coords );
+ }
+
+
+ FT_LOCAL_DEF( void )
+ t1_hints_funcs_init( T1_Hints_FuncsRec* funcs )
+ {
+ FT_MEM_ZERO( (char*)funcs, sizeof ( *funcs ) );
+
+ funcs->open = (T1_Hints_OpenFunc) t1_hints_open;
+ funcs->close = (T1_Hints_CloseFunc) ps_hints_close;
+ funcs->stem = (T1_Hints_SetStemFunc) t1_hints_stem;
+ funcs->stem3 = (T1_Hints_SetStem3Func)ps_hints_t1stem3;
+ funcs->reset = (T1_Hints_ResetFunc) ps_hints_t1reset;
+ funcs->apply = (T1_Hints_ApplyFunc) PS_HINTS_APPLY_FUNC;
+ }
+
+
+ /*************************************************************************/
+ /*************************************************************************/
+ /***** *****/
+ /***** TYPE 2 HINTS RECORDING INTERFACE *****/
+ /***** *****/
+ /*************************************************************************/
+ /*************************************************************************/
+
+ static void
+ t2_hints_open( T2_Hints hints )
+ {
+ ps_hints_open( (PS_Hints)hints, PS_HINT_TYPE_2 );
+ }
+
+
+ static void
+ t2_hints_stems( T2_Hints hints,
+ FT_Int dimension,
+ FT_Int count,
+ FT_Fixed* coords )
+ {
+ FT_Pos stems[32], y, n, total = count;
+
+
+ y = 0;
+ while ( total > 0 )
+ {
+ /* determine number of stems to write */
+ count = total;
+ if ( count > 16 )
+ count = 16;
+
+ /* compute integer stem positions in font units */
+ for ( n = 0; n < count * 2; n++ )
+ {
+ y += coords[n];
+ stems[n] = ( y + 0x8000 ) >> 16;
+ }
+
+ /* compute lengths */
+ for ( n = 0; n < count * 2; n += 2 )
+ stems[n + 1] = stems[n + 1] - stems[n];
+
+ /* add them to the current dimension */
+ ps_hints_stem( (PS_Hints)hints, dimension, count, stems );
+
+ total -= count;
+ }
+ }
+
+
+ FT_LOCAL_DEF( void )
+ t2_hints_funcs_init( T2_Hints_FuncsRec* funcs )
+ {
+ FT_MEM_ZERO( funcs, sizeof ( *funcs ) );
+
+ funcs->open = (T2_Hints_OpenFunc) t2_hints_open;
+ funcs->close = (T2_Hints_CloseFunc) ps_hints_close;
+ funcs->stems = (T2_Hints_StemsFunc) t2_hints_stems;
+ funcs->hintmask= (T2_Hints_MaskFunc) ps_hints_t2mask;
+ funcs->counter = (T2_Hints_CounterFunc)ps_hints_t2counter;
+ funcs->apply = (T2_Hints_ApplyFunc) PS_HINTS_APPLY_FUNC;
+ }
+
+
+/* END */
--- /dev/null
+++ b/libfreetype/pshrec.h
@@ -1,0 +1,180 @@
+/***************************************************************************/
+/* */
+/* pshrec.h */
+/* */
+/* Postscript (Type1/Type2) hints recorder (specification). */
+/* */
+/* Copyright 2001, 2002 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+
+ /**************************************************************************/
+ /* */
+ /* The functions defined here are called from the Type 1, CID and CFF */
+ /* font drivers to record the hints of a given character/glyph. */
+ /* */
+ /* The hints are recorded in a unified format, and are later processed */
+ /* by the "optimizer" and "fitter" to adjust the outlines to the pixel */
+ /* grid. */
+ /* */
+ /**************************************************************************/
+
+
+#ifndef __PSHREC_H__
+#define __PSHREC_H__
+
+
+#include <ft2build.h>
+#include FT_INTERNAL_POSTSCRIPT_HINTS_H
+#include "pshglob.h"
+
+
+FT_BEGIN_HEADER
+
+
+ /*************************************************************************/
+ /*************************************************************************/
+ /***** *****/
+ /***** GLYPH HINTS RECORDER INTERNALS *****/
+ /***** *****/
+ /*************************************************************************/
+ /*************************************************************************/
+
+ /* handle to hint record */
+ typedef struct PS_HintRec_* PS_Hint;
+
+ /* hint types */
+ typedef enum
+ {
+ PS_HINT_TYPE_1 = 1,
+ PS_HINT_TYPE_2 = 2
+
+ } PS_Hint_Type;
+
+
+ /* hint flags */
+ typedef enum
+ {
+ PS_HINT_FLAG_GHOST = 1,
+ PS_HINT_FLAG_BOTTOM = 2
+
+ } PS_Hint_Flags;
+
+
+ /* hint descriptor */
+ typedef struct PS_HintRec_
+ {
+ FT_Int pos;
+ FT_Int len;
+ FT_UInt flags;
+
+ } PS_HintRec;
+
+
+#define ps_hint_is_active( x ) ( (x)->flags & PS_HINT_FLAG_ACTIVE )
+#define ps_hint_is_ghost( x ) ( (x)->flags & PS_HINT_FLAG_GHOST )
+#define ps_hint_is_bottom( x ) ( (x)->flags & PS_HINT_FLAG_BOTTOM )
+
+
+ /* hints table descriptor */
+ typedef struct PS_Hint_TableRec_
+ {
+ FT_UInt num_hints;
+ FT_UInt max_hints;
+ PS_Hint hints;
+
+ } PS_Hint_TableRec, *PS_Hint_Table;
+
+
+ /* hint and counter mask descriptor */
+ typedef struct PS_MaskRec_
+ {
+ FT_UInt num_bits;
+ FT_UInt max_bits;
+ FT_Byte* bytes;
+ FT_UInt end_point;
+
+ } PS_MaskRec, *PS_Mask;
+
+
+ /* masks and counters table descriptor */
+ typedef struct PS_Mask_TableRec_
+ {
+ FT_UInt num_masks;
+ FT_UInt max_masks;
+ PS_Mask masks;
+
+ } PS_Mask_TableRec, *PS_Mask_Table;
+
+
+ /* dimension-specific hints descriptor */
+ typedef struct PS_DimensionRec_
+ {
+ PS_Hint_TableRec hints;
+ PS_Mask_TableRec masks;
+ PS_Mask_TableRec counters;
+
+ } PS_DimensionRec, *PS_Dimension;
+
+
+ /* magic value used within PS_HintsRec */
+#define PS_HINTS_MAGIC 0x68696e74 /* "hint" */
+
+
+ /* glyph hints descriptor */
+ /* dimension 0 => X coordinates + vertical hints/stems */
+ /* dimension 1 => Y coordinates + horizontal hints/stems */
+ typedef struct PS_HintsRec_
+ {
+ FT_Memory memory;
+ FT_Error error;
+ FT_UInt32 magic;
+ PS_Hint_Type hint_type;
+ PS_DimensionRec dimension[2];
+
+ } PS_HintsRec, *PS_Hints;
+
+ /* */
+
+ /* initialize hints recorder */
+ FT_LOCAL( FT_Error )
+ ps_hints_init( PS_Hints hints,
+ FT_Memory memory );
+
+ /* finalize hints recorder */
+ FT_LOCAL( void )
+ ps_hints_done( PS_Hints hints );
+
+ /* initialize Type1 hints recorder interface */
+ FT_LOCAL( void )
+ t1_hints_funcs_init( T1_Hints_FuncsRec* funcs );
+
+ /* initialize Type2 hints recorder interface */
+ FT_LOCAL( void )
+ t2_hints_funcs_init( T2_Hints_FuncsRec* funcs );
+
+
+#ifdef DEBUG_HINTER
+ extern PS_Hints ps_debug_hints;
+ extern int ps_debug_no_horz_hints;
+ extern int ps_debug_no_vert_hints;
+#endif
+
+ /* */
+
+
+FT_END_HEADER
+
+
+#endif /* __PS_HINTER_RECORD_H__ */
+
+
+/* END */
--- /dev/null
+++ b/libfreetype/psmodule.c
@@ -1,0 +1,357 @@
+/***************************************************************************/
+/* */
+/* psmodule.c */
+/* */
+/* PSNames module implementation (body). */
+/* */
+/* Copyright 1996-2001, 2002 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+
+#include <ft2build.h>
+#include FT_INTERNAL_POSTSCRIPT_NAMES_H
+#include FT_INTERNAL_OBJECTS_H
+
+#include "psmodule.h"
+#include "pstables.h"
+
+#include "psnamerr.h"
+
+
+#ifndef FT_CONFIG_OPTION_NO_POSTSCRIPT_NAMES
+
+
+#ifdef FT_CONFIG_OPTION_ADOBE_GLYPH_LIST
+
+
+ /* return the Unicode value corresponding to a given glyph. Note that */
+ /* we do deal with glyph variants by detecting a non-initial dot in */
+ /* the name, as in `A.swash' or `e.final', etc. */
+ /* */
+ static FT_UInt32
+ ps_unicode_value( const char* glyph_name )
+ {
+ FT_Int n;
+ char first = glyph_name[0];
+ char temp[64];
+
+
+ /* if the name begins with `uni', then the glyph name may be a */
+ /* hard-coded unicode character code. */
+ if ( glyph_name[0] == 'u' &&
+ glyph_name[1] == 'n' &&
+ glyph_name[2] == 'i' )
+ {
+ /* determine whether the next four characters following are */
+ /* hexadecimal. */
+
+ /* XXX: Add code to deal with ligatures, i.e. glyph names like */
+ /* `uniXXXXYYYYZZZZ'... */
+
+ FT_Int count;
+ FT_ULong value = 0;
+ const char* p = glyph_name + 3;
+
+
+ for ( count = 4; count > 0; count--, p++ )
+ {
+ char c = *p;
+ unsigned int d;
+
+
+ d = (unsigned char)c - '0';
+ if ( d >= 10 )
+ {
+ d = (unsigned char)c - 'A';
+ if ( d >= 6 )
+ d = 16;
+ else
+ d += 10;
+ }
+
+ /* exit if a non-uppercase hexadecimal character was found */
+ if ( d >= 16 )
+ break;
+
+ value = ( value << 4 ) + d;
+ }
+ if ( count == 0 )
+ return value;
+ }
+
+ /* look for a non-initial dot in the glyph name in order to */
+ /* sort-out variants like `A.swash', `e.final', etc. */
+ {
+ const char* p;
+ int len;
+
+
+ p = glyph_name;
+
+ while ( *p && *p != '.' )
+ p++;
+
+ len = (int)( p - glyph_name );
+
+ if ( *p && len < 64 )
+ {
+ ft_strncpy( temp, glyph_name, len );
+ temp[len] = 0;
+ glyph_name = temp;
+ }
+ }
+
+ /* now, look up the glyph in the Adobe Glyph List */
+ for ( n = 0; n < NUM_ADOBE_GLYPHS; n++ )
+ {
+ const char* name = sid_standard_names[n];
+
+
+ if ( first == name[0] && ft_strcmp( glyph_name, name ) == 0 )
+ return ps_names_to_unicode[n];
+ }
+
+ /* not found, there is probably no Unicode value for this glyph name */
+ return 0;
+ }
+
+
+ /* ft_qsort callback to sort the unicode map */
+ FT_CALLBACK_DEF( int )
+ compare_uni_maps( const void* a,
+ const void* b )
+ {
+ PS_UniMap* map1 = (PS_UniMap*)a;
+ PS_UniMap* map2 = (PS_UniMap*)b;
+
+
+ return ( map1->unicode - map2->unicode );
+ }
+
+
+ /* Builds a table that maps Unicode values to glyph indices */
+ static FT_Error
+ ps_build_unicode_table( FT_Memory memory,
+ FT_UInt num_glyphs,
+ const char** glyph_names,
+ PS_Unicodes* table )
+ {
+ FT_Error error;
+
+
+ /* we first allocate the table */
+ table->num_maps = 0;
+ table->maps = 0;
+
+ if ( !FT_NEW_ARRAY( table->maps, num_glyphs ) )
+ {
+ FT_UInt n;
+ FT_UInt count;
+ PS_UniMap* map;
+ FT_UInt32 uni_char;
+
+
+ map = table->maps;
+
+ for ( n = 0; n < num_glyphs; n++ )
+ {
+ const char* gname = glyph_names[n];
+
+
+ if ( gname )
+ {
+ uni_char = ps_unicode_value( gname );
+
+ if ( uni_char != 0 && uni_char != 0xFFFF )
+ {
+ map->unicode = uni_char;
+ map->glyph_index = n;
+ map++;
+ }
+ }
+ }
+
+ /* now, compress the table a bit */
+ count = (FT_UInt)( map - table->maps );
+
+ if ( count > 0 && FT_REALLOC( table->maps,
+ num_glyphs * sizeof ( PS_UniMap ),
+ count * sizeof ( PS_UniMap ) ) )
+ count = 0;
+
+ if ( count == 0 )
+ {
+ FT_FREE( table->maps );
+ if ( !error )
+ error = PSnames_Err_Invalid_Argument; /* no unicode chars here! */
+ }
+ else
+ /* sort the table in increasing order of unicode values */
+ ft_qsort( table->maps, count, sizeof ( PS_UniMap ), compare_uni_maps );
+
+ table->num_maps = count;
+ }
+
+ return error;
+ }
+
+
+ static FT_UInt
+ ps_lookup_unicode( PS_Unicodes* table,
+ FT_ULong unicode )
+ {
+ PS_UniMap *min, *max, *mid;
+
+
+ /* perform a binary search on the table */
+
+ min = table->maps;
+ max = min + table->num_maps - 1;
+
+ while ( min <= max )
+ {
+ mid = min + ( max - min ) / 2;
+ if ( mid->unicode == unicode )
+ return mid->glyph_index;
+
+ if ( min == max )
+ break;
+
+ if ( mid->unicode < unicode )
+ min = mid + 1;
+ else
+ max = mid - 1;
+ }
+
+ return 0xFFFF;
+ }
+
+
+ static FT_ULong
+ ps_next_unicode( PS_Unicodes* table,
+ FT_ULong unicode )
+ {
+ PS_UniMap *min, *max, *mid;
+
+
+ unicode++;
+ /* perform a binary search on the table */
+
+ min = table->maps;
+ max = min + table->num_maps - 1;
+
+ while ( min <= max )
+ {
+ mid = min + ( max - min ) / 2;
+ if ( mid->unicode == unicode )
+ return unicode;
+
+ if ( min == max )
+ break;
+
+ if ( mid->unicode < unicode )
+ min = mid + 1;
+ else
+ max = mid - 1;
+ }
+
+ if ( max < table->maps )
+ max = table->maps;
+
+ while ( max < table->maps + table->num_maps )
+ {
+ if ( unicode < max->unicode )
+ return max->unicode;
+ max++;
+ }
+
+ return 0;
+ }
+
+
+#endif /* FT_CONFIG_OPTION_ADOBE_GLYPH_LIST */
+
+
+ static const char*
+ ps_get_macintosh_name( FT_UInt name_index )
+ {
+ if ( name_index >= 258 )
+ name_index = 0;
+
+ return ps_glyph_names[mac_standard_names[name_index]];
+ }
+
+
+ static const char*
+ ps_get_standard_strings( FT_UInt sid )
+ {
+ return ( sid < NUM_SID_GLYPHS ? sid_standard_names[sid] : 0 );
+ }
+
+
+ static
+ const PSNames_Interface psnames_interface =
+ {
+#ifdef FT_CONFIG_OPTION_ADOBE_GLYPH_LIST
+
+ (PS_Unicode_Value_Func) ps_unicode_value,
+ (PS_Build_Unicodes_Func) ps_build_unicode_table,
+ (PS_Lookup_Unicode_Func) ps_lookup_unicode,
+
+#else
+
+ 0,
+ 0,
+ 0,
+
+#endif /* FT_CONFIG_OPTION_ADOBE_GLYPH_LIST */
+
+ (PS_Macintosh_Name_Func) ps_get_macintosh_name,
+ (PS_Adobe_Std_Strings_Func) ps_get_standard_strings,
+
+ t1_standard_encoding,
+ t1_expert_encoding,
+
+#ifdef FT_CONFIG_OPTION_ADOBE_GLYPH_LIST
+ (PS_Next_Unicode_Func) ps_next_unicode
+#else
+ 0
+#endif /* FT_CONFIG_OPTION_ADOBE_GLYPH_LIST */
+
+ };
+
+
+#endif /* !FT_CONFIG_OPTION_NO_POSTSCRIPT_NAMES */
+
+
+ FT_CALLBACK_TABLE_DEF
+ const FT_Module_Class psnames_module_class =
+ {
+ 0, /* this is not a font driver, nor a renderer */
+ sizeof ( FT_ModuleRec ),
+
+ "psnames", /* driver name */
+ 0x10000L, /* driver version */
+ 0x20000L, /* driver requires FreeType 2 or above */
+
+#ifdef FT_CONFIG_OPTION_NO_POSTSCRIPT_NAMES
+ 0,
+#else
+ (void*)&psnames_interface, /* module specific interface */
+#endif
+
+ (FT_Module_Constructor)0,
+ (FT_Module_Destructor) 0,
+ (FT_Module_Requester) 0
+ };
+
+
+/* END */
--- /dev/null
+++ b/libfreetype/psmodule.h
@@ -1,0 +1,38 @@
+/***************************************************************************/
+/* */
+/* psmodule.h */
+/* */
+/* High-level PSNames module interface (specification). */
+/* */
+/* Copyright 1996-2001 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+
+#ifndef __PSMODULE_H__
+#define __PSMODULE_H__
+
+
+#include <ft2build.h>
+#include FT_MODULE_H
+
+
+FT_BEGIN_HEADER
+
+
+ FT_EXPORT_VAR( const FT_Module_Class ) psnames_module_class;
+
+
+FT_END_HEADER
+
+#endif /* __PSMODULE_H__ */
+
+
+/* END */
--- /dev/null
+++ b/libfreetype/psnamerr.h
@@ -1,0 +1,41 @@
+/***************************************************************************/
+/* */
+/* psnamerr.h */
+/* */
+/* PS names module error codes (specification only). */
+/* */
+/* Copyright 2001 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+
+ /*************************************************************************/
+ /* */
+ /* This file is used to define the PS names module error enumeration */
+ /* constants. */
+ /* */
+ /*************************************************************************/
+
+#ifndef __PSNAMERR_H__
+#define __PSNAMERR_H__
+
+#include FT_MODULE_ERRORS_H
+
+#undef __FTERRORS_H__
+
+#define FT_ERR_PREFIX PSnames_Err_
+#define FT_ERR_BASE FT_Mod_Err_PSnames
+
+#include FT_ERRORS_H
+
+#endif /* __PSNAMERR_H__ */
+
+
+/* END */
--- /dev/null
+++ b/libfreetype/psnames.c
@@ -1,0 +1,25 @@
+/***************************************************************************/
+/* */
+/* psnames.c */
+/* */
+/* FreeType PSNames module component (body only). */
+/* */
+/* Copyright 1996-2001 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+
+#define FT_MAKE_OPTION_SINGLE_OBJECT
+
+#include <ft2build.h>
+#include "psmodule.c"
+
+
+/* END */
--- /dev/null
+++ b/libfreetype/psobjs.c
@@ -1,0 +1,1403 @@
+/***************************************************************************/
+/* */
+/* psobjs.c */
+/* */
+/* Auxiliary functions for PostScript fonts (body). */
+/* */
+/* Copyright 1996-2001, 2002 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+
+#include <ft2build.h>
+#include FT_INTERNAL_POSTSCRIPT_AUX_H
+#include FT_INTERNAL_DEBUG_H
+
+#include "psobjs.h"
+
+#include "psauxerr.h"
+
+
+ /*************************************************************************/
+ /*************************************************************************/
+ /***** *****/
+ /***** PS_TABLE *****/
+ /***** *****/
+ /*************************************************************************/
+ /*************************************************************************/
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* ps_table_new */
+ /* */
+ /* <Description> */
+ /* Initializes a PS_Table. */
+ /* */
+ /* <InOut> */
+ /* table :: The address of the target table. */
+ /* */
+ /* <Input> */
+ /* count :: The table size = the maximum number of elements. */
+ /* */
+ /* memory :: The memory object to use for all subsequent */
+ /* reallocations. */
+ /* */
+ /* <Return> */
+ /* FreeType error code. 0 means success. */
+ /* */
+ FT_LOCAL_DEF( FT_Error )
+ ps_table_new( PS_Table table,
+ FT_Int count,
+ FT_Memory memory )
+ {
+ FT_Error error;
+
+
+ table->memory = memory;
+ if ( FT_NEW_ARRAY( table->elements, count ) ||
+ FT_NEW_ARRAY( table->lengths, count ) )
+ goto Exit;
+
+ table->max_elems = count;
+ table->init = 0xDEADBEEFUL;
+ table->num_elems = 0;
+ table->block = 0;
+ table->capacity = 0;
+ table->cursor = 0;
+
+ *(PS_Table_FuncsRec*)&table->funcs = ps_table_funcs;
+
+ Exit:
+ if ( error )
+ FT_FREE( table->elements );
+
+ return error;
+ }
+
+
+ static void
+ shift_elements( PS_Table table,
+ FT_Byte* old_base )
+ {
+ FT_Long delta = (FT_Long)( table->block - old_base );
+ FT_Byte** offset = table->elements;
+ FT_Byte** limit = offset + table->max_elems;
+
+
+ for ( ; offset < limit; offset++ )
+ {
+ if ( offset[0] )
+ offset[0] += delta;
+ }
+ }
+
+
+ static FT_Error
+ reallocate_t1_table( PS_Table table,
+ FT_Long new_size )
+ {
+ FT_Memory memory = table->memory;
+ FT_Byte* old_base = table->block;
+ FT_Error error;
+
+
+ /* allocate new base block */
+ if ( FT_ALLOC( table->block, new_size ) )
+ return error;
+
+ /* copy elements and shift offsets */
+ if (old_base )
+ {
+ FT_MEM_COPY( table->block, old_base, table->capacity );
+ shift_elements( table, old_base );
+ FT_FREE( old_base );
+ }
+
+ table->capacity = new_size;
+
+ return PSaux_Err_Ok;
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* ps_table_add */
+ /* */
+ /* <Description> */
+ /* Adds an object to a PS_Table, possibly growing its memory block. */
+ /* */
+ /* <InOut> */
+ /* table :: The target table. */
+ /* */
+ /* <Input> */
+ /* idx :: The index of the object in the table. */
+ /* */
+ /* object :: The address of the object to copy in memory. */
+ /* */
+ /* length :: The length in bytes of the source object. */
+ /* */
+ /* <Return> */
+ /* FreeType error code. 0 means success. An error is returned if a */
+ /* reallocation fails. */
+ /* */
+ FT_LOCAL_DEF( FT_Error )
+ ps_table_add( PS_Table table,
+ FT_Int idx,
+ void* object,
+ FT_Int length )
+ {
+ if ( idx < 0 || idx > table->max_elems )
+ {
+ FT_ERROR(( "ps_table_add: invalid index\n" ));
+ return PSaux_Err_Invalid_Argument;
+ }
+
+ /* grow the base block if needed */
+ if ( table->cursor + length > table->capacity )
+ {
+ FT_Error error;
+ FT_Offset new_size = table->capacity;
+ FT_Long in_offset;
+
+
+ in_offset = (FT_Long)((FT_Byte*)object - table->block);
+ if ( (FT_ULong)in_offset >= table->capacity )
+ in_offset = -1;
+
+ while ( new_size < table->cursor + length )
+ {
+ /* increase size by 25% and round up to the nearest multiple of 1024 */
+ new_size += (new_size >> 2) + 1;
+ new_size = ( new_size + 1023 ) & -1024;
+ }
+
+ error = reallocate_t1_table( table, new_size );
+ if ( error )
+ return error;
+
+ if ( in_offset >= 0 )
+ object = table->block + in_offset;
+ }
+
+ /* add the object to the base block and adjust offset */
+ table->elements[idx] = table->block + table->cursor;
+ table->lengths [idx] = length;
+ FT_MEM_COPY( table->block + table->cursor, object, length );
+
+ table->cursor += length;
+ return PSaux_Err_Ok;
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* ps_table_done */
+ /* */
+ /* <Description> */
+ /* Finalizes a PS_TableRec (i.e., reallocate it to its current */
+ /* cursor). */
+ /* */
+ /* <InOut> */
+ /* table :: The target table. */
+ /* */
+ /* <Note> */
+ /* This function does NOT release the heap's memory block. It is up */
+ /* to the caller to clean it, or reference it in its own structures. */
+ /* */
+ FT_LOCAL_DEF( void )
+ ps_table_done( PS_Table table )
+ {
+ FT_Memory memory = table->memory;
+ FT_Error error;
+ FT_Byte* old_base = table->block;
+
+
+ /* should never fail, because rec.cursor <= rec.size */
+ if ( !old_base )
+ return;
+
+ if ( FT_ALLOC( table->block, table->cursor ) )
+ return;
+ FT_MEM_COPY( table->block, old_base, table->cursor );
+ shift_elements( table, old_base );
+
+ table->capacity = table->cursor;
+ FT_FREE( old_base );
+
+ FT_UNUSED( error );
+ }
+
+
+ FT_LOCAL_DEF( void )
+ ps_table_release( PS_Table table )
+ {
+ FT_Memory memory = table->memory;
+
+
+ if ( (FT_ULong)table->init == 0xDEADBEEFUL )
+ {
+ FT_FREE( table->block );
+ FT_FREE( table->elements );
+ FT_FREE( table->lengths );
+ table->init = 0;
+ }
+ }
+
+
+ /*************************************************************************/
+ /*************************************************************************/
+ /***** *****/
+ /***** T1 PARSER *****/
+ /***** *****/
+ /*************************************************************************/
+ /*************************************************************************/
+
+
+#define IS_T1_WHITESPACE( c ) ( (c) == ' ' || (c) == '\t' )
+#define IS_T1_LINESPACE( c ) ( (c) == '\r' || (c) == '\n' )
+
+#define IS_T1_SPACE( c ) ( IS_T1_WHITESPACE( c ) || IS_T1_LINESPACE( c ) )
+
+
+ FT_LOCAL_DEF( void )
+ ps_parser_skip_spaces( PS_Parser parser )
+ {
+ FT_Byte* cur = parser->cursor;
+ FT_Byte* limit = parser->limit;
+
+
+ while ( cur < limit )
+ {
+ FT_Byte c = *cur;
+
+
+ if ( !IS_T1_SPACE( c ) )
+ break;
+ cur++;
+ }
+ parser->cursor = cur;
+ }
+
+
+ FT_LOCAL_DEF( void )
+ ps_parser_skip_alpha( PS_Parser parser )
+ {
+ FT_Byte* cur = parser->cursor;
+ FT_Byte* limit = parser->limit;
+
+
+ while ( cur < limit )
+ {
+ FT_Byte c = *cur;
+
+
+ if ( IS_T1_SPACE( c ) )
+ break;
+ cur++;
+ }
+ parser->cursor = cur;
+ }
+
+
+ FT_LOCAL_DEF( void )
+ ps_parser_to_token( PS_Parser parser,
+ T1_Token token )
+ {
+ FT_Byte* cur;
+ FT_Byte* limit;
+ FT_Byte starter, ender;
+ FT_Int embed;
+
+
+ token->type = T1_TOKEN_TYPE_NONE;
+ token->start = 0;
+ token->limit = 0;
+
+ /* first of all, skip space */
+ ps_parser_skip_spaces( parser );
+
+ cur = parser->cursor;
+ limit = parser->limit;
+
+ if ( cur < limit )
+ {
+ switch ( *cur )
+ {
+ /************* check for strings ***********************/
+ case '(':
+ token->type = T1_TOKEN_TYPE_STRING;
+ ender = ')';
+ goto Lookup_Ender;
+
+ /************* check for programs/array ****************/
+ case '{':
+ token->type = T1_TOKEN_TYPE_ARRAY;
+ ender = '}';
+ goto Lookup_Ender;
+
+ /************* check for table/array ******************/
+ case '[':
+ token->type = T1_TOKEN_TYPE_ARRAY;
+ ender = ']';
+
+ Lookup_Ender:
+ embed = 1;
+ starter = *cur++;
+ token->start = cur;
+ while ( cur < limit )
+ {
+ if ( *cur == starter )
+ embed++;
+ else if ( *cur == ender )
+ {
+ embed--;
+ if ( embed <= 0 )
+ {
+ token->limit = cur++;
+ break;
+ }
+ }
+ cur++;
+ }
+ break;
+
+ /* **************** otherwise, it's any token **********/
+ default:
+ token->start = cur++;
+ token->type = T1_TOKEN_TYPE_ANY;
+ while ( cur < limit && !IS_T1_SPACE( *cur ) )
+ cur++;
+
+ token->limit = cur;
+ }
+
+ if ( !token->limit )
+ {
+ token->start = 0;
+ token->type = T1_TOKEN_TYPE_NONE;
+ }
+
+ parser->cursor = cur;
+ }
+ }
+
+
+ FT_LOCAL_DEF( void )
+ ps_parser_to_token_array( PS_Parser parser,
+ T1_Token tokens,
+ FT_UInt max_tokens,
+ FT_Int* pnum_tokens )
+ {
+ T1_TokenRec master;
+
+
+ *pnum_tokens = -1;
+
+ ps_parser_to_token( parser, &master );
+ if ( master.type == T1_TOKEN_TYPE_ARRAY )
+ {
+ FT_Byte* old_cursor = parser->cursor;
+ FT_Byte* old_limit = parser->limit;
+ T1_Token cur = tokens;
+ T1_Token limit = cur + max_tokens;
+
+
+ parser->cursor = master.start;
+ parser->limit = master.limit;
+
+ while ( parser->cursor < parser->limit )
+ {
+ T1_TokenRec token;
+
+
+ ps_parser_to_token( parser, &token );
+ if ( !token.type )
+ break;
+
+ if ( cur < limit )
+ *cur = token;
+
+ cur++;
+ }
+
+ *pnum_tokens = (FT_Int)( cur - tokens );
+
+ parser->cursor = old_cursor;
+ parser->limit = old_limit;
+ }
+ }
+
+
+ static FT_Long
+ T1Radix( FT_Long radixBase,
+ FT_Byte** cur,
+ FT_Byte* limit )
+ {
+ FT_Long result = 0;
+ FT_Byte radixEndChar0 =
+ (FT_Byte)( radixBase > 10 ? '9' + 1 : '0' + radixBase );
+ FT_Byte radixEndChar1 =
+ (FT_Byte)( 'A' + radixBase - 10 );
+ FT_Byte radixEndChar2 =
+ (FT_Byte)( 'a' + radixBase - 10 );
+
+
+ while( *cur < limit )
+ {
+ if ( (*cur)[0] >= '0' && (*cur)[0] < radixEndChar0 )
+ result = result * radixBase + (*cur)[0] - '0';
+
+ else if ( radixBase > 10 &&
+ (*cur)[0] >= 'A' && (*cur)[0] < radixEndChar1 )
+ result = result * radixBase + ( (*cur)[0] - 'A' + 10 );
+
+ else if ( radixBase > 10 &&
+ (*cur)[0] >= 'a' && (*cur)[0] < radixEndChar2 )
+ result = result * radixBase + ( (*cur)[0] - 'a' + 10 );
+
+ else
+ return result;
+
+ (*cur)++;
+ }
+
+ return result;
+ }
+
+
+ static FT_Long
+ t1_toint( FT_Byte** cursor,
+ FT_Byte* limit )
+ {
+ FT_Long result = 0;
+ FT_Byte* cur = *cursor;
+ FT_Byte c = '\0', d;
+
+
+ for ( ; cur < limit; cur++ )
+ {
+ c = *cur;
+ d = (FT_Byte)( c - '0' );
+ if ( d < 10 )
+ break;
+
+ if ( c == '-' )
+ {
+ cur++;
+ break;
+ }
+ }
+
+ if ( cur < limit )
+ {
+ do
+ {
+ d = (FT_Byte)( cur[0] - '0' );
+ if ( d >= 10 )
+ {
+ if ( cur[0] == '#' )
+ {
+ cur++;
+ result = T1Radix( result, &cur, limit );
+ }
+ break;
+ }
+
+ result = result * 10 + d;
+ cur++;
+
+ } while ( cur < limit );
+
+ if ( c == '-' )
+ result = -result;
+ }
+
+ *cursor = cur;
+ return result;
+ }
+
+
+ static FT_Long
+ t1_tofixed( FT_Byte** cursor,
+ FT_Byte* limit,
+ FT_Long power_ten )
+ {
+ FT_Byte* cur = *cursor;
+ FT_Long num, divider, result;
+ FT_Int sign = 0;
+ FT_Byte d;
+
+
+ if ( cur >= limit )
+ return 0;
+
+ /* first of all, check the sign */
+ if ( *cur == '-' )
+ {
+ sign = 1;
+ cur++;
+ }
+
+ /* then, read the integer part, if any */
+ if ( *cur != '.' )
+ result = t1_toint( &cur, limit ) << 16;
+ else
+ result = 0;
+
+ num = 0;
+ divider = 1;
+
+ if ( cur >= limit )
+ goto Exit;
+
+ /* read decimal part, if any */
+ if ( *cur == '.' && cur + 1 < limit )
+ {
+ cur++;
+
+ for (;;)
+ {
+ d = (FT_Byte)( *cur - '0' );
+ if ( d >= 10 )
+ break;
+
+ if ( divider < 10000000L )
+ {
+ num = num * 10 + d;
+ divider *= 10;
+ }
+
+ cur++;
+ if ( cur >= limit )
+ break;
+ }
+ }
+
+ /* read exponent, if any */
+ if ( cur + 1 < limit && ( *cur == 'e' || *cur == 'E' ) )
+ {
+ cur++;
+ power_ten += t1_toint( &cur, limit );
+ }
+
+ Exit:
+ /* raise to power of ten if needed */
+ while ( power_ten > 0 )
+ {
+ result = result * 10;
+ num = num * 10;
+ power_ten--;
+ }
+
+ while ( power_ten < 0 )
+ {
+ result = result / 10;
+ divider = divider * 10;
+ power_ten++;
+ }
+
+ if ( num )
+ result += FT_DivFix( num, divider );
+
+ if ( sign )
+ result = -result;
+
+ *cursor = cur;
+ return result;
+ }
+
+
+ static FT_Int
+ t1_tocoordarray( FT_Byte** cursor,
+ FT_Byte* limit,
+ FT_Int max_coords,
+ FT_Short* coords )
+ {
+ FT_Byte* cur = *cursor;
+ FT_Int count = 0;
+ FT_Byte c, ender;
+
+
+ if ( cur >= limit )
+ goto Exit;
+
+ /* check for the beginning of an array; if not, only one number will */
+ /* be read */
+ c = *cur;
+ ender = 0;
+
+ if ( c == '[' )
+ ender = ']';
+
+ if ( c == '{' )
+ ender = '}';
+
+ if ( ender )
+ cur++;
+
+ /* now, read the coordinates */
+ for ( ; cur < limit; )
+ {
+ /* skip whitespace in front of data */
+ for (;;)
+ {
+ c = *cur;
+ if ( c != ' ' && c != '\t' )
+ break;
+
+ cur++;
+ if ( cur >= limit )
+ goto Exit;
+ }
+
+ if ( count >= max_coords || c == ender )
+ break;
+
+ coords[count] = (FT_Short)( t1_tofixed( &cur, limit, 0 ) >> 16 );
+ count++;
+
+ if ( !ender )
+ break;
+ }
+
+ Exit:
+ *cursor = cur;
+ return count;
+ }
+
+
+ static FT_Int
+ t1_tofixedarray( FT_Byte** cursor,
+ FT_Byte* limit,
+ FT_Int max_values,
+ FT_Fixed* values,
+ FT_Int power_ten )
+ {
+ FT_Byte* cur = *cursor;
+ FT_Int count = 0;
+ FT_Byte c, ender;
+
+
+ if ( cur >= limit ) goto Exit;
+
+ /* check for the beginning of an array. If not, only one number will */
+ /* be read */
+ c = *cur;
+ ender = 0;
+
+ if ( c == '[' )
+ ender = ']';
+
+ if ( c == '{' )
+ ender = '}';
+
+ if ( ender )
+ cur++;
+
+ /* now, read the values */
+ for ( ; cur < limit; )
+ {
+ /* skip whitespace in front of data */
+ for (;;)
+ {
+ c = *cur;
+ if ( c != ' ' && c != '\t' )
+ break;
+
+ cur++;
+ if ( cur >= limit )
+ goto Exit;
+ }
+
+ if ( count >= max_values || c == ender )
+ break;
+
+ values[count] = t1_tofixed( &cur, limit, power_ten );
+ count++;
+
+ if ( !ender )
+ break;
+ }
+
+ Exit:
+ *cursor = cur;
+ return count;
+ }
+
+
+#if 0
+
+ static FT_String*
+ t1_tostring( FT_Byte** cursor,
+ FT_Byte* limit,
+ FT_Memory memory )
+ {
+ FT_Byte* cur = *cursor;
+ FT_PtrDist len = 0;
+ FT_Int count;
+ FT_String* result;
+ FT_Error error;
+
+
+ /* XXX: some stupid fonts have a `Notice' or `Copyright' string */
+ /* that simply doesn't begin with an opening parenthesis, even */
+ /* though they have a closing one! E.g. "amuncial.pfb" */
+ /* */
+ /* We must deal with these ill-fated cases there. Note that */
+ /* these fonts didn't work with the old Type 1 driver as the */
+ /* notice/copyright was not recognized as a valid string token */
+ /* and made the old token parser commit errors. */
+
+ while ( cur < limit && ( *cur == ' ' || *cur == '\t' ) )
+ cur++;
+ if ( cur + 1 >= limit )
+ return 0;
+
+ if ( *cur == '(' )
+ cur++; /* skip the opening parenthesis, if there is one */
+
+ *cursor = cur;
+ count = 0;
+
+ /* then, count its length */
+ for ( ; cur < limit; cur++ )
+ {
+ if ( *cur == '(' )
+ count++;
+
+ else if ( *cur == ')' )
+ {
+ count--;
+ if ( count < 0 )
+ break;
+ }
+ }
+
+ len = cur - *cursor;
+ if ( cur >= limit || FT_ALLOC( result, len + 1 ) )
+ return 0;
+
+ /* now copy the string */
+ FT_MEM_COPY( result, *cursor, len );
+ result[len] = '\0';
+ *cursor = cur;
+ return result;
+ }
+
+#endif /* 0 */
+
+
+ static int
+ t1_tobool( FT_Byte** cursor,
+ FT_Byte* limit )
+ {
+ FT_Byte* cur = *cursor;
+ FT_Bool result = 0;
+
+
+ /* return 1 if we find `true', 0 otherwise */
+ if ( cur + 3 < limit &&
+ cur[0] == 't' &&
+ cur[1] == 'r' &&
+ cur[2] == 'u' &&
+ cur[3] == 'e' )
+ {
+ result = 1;
+ cur += 5;
+ }
+ else if ( cur + 4 < limit &&
+ cur[0] == 'f' &&
+ cur[1] == 'a' &&
+ cur[2] == 'l' &&
+ cur[3] == 's' &&
+ cur[4] == 'e' )
+ {
+ result = 0;
+ cur += 6;
+ }
+
+ *cursor = cur;
+ return result;
+ }
+
+
+ /* Load a simple field (i.e. non-table) into the current list of objects */
+ FT_LOCAL_DEF( FT_Error )
+ ps_parser_load_field( PS_Parser parser,
+ const T1_Field field,
+ void** objects,
+ FT_UInt max_objects,
+ FT_ULong* pflags )
+ {
+ T1_TokenRec token;
+ FT_Byte* cur;
+ FT_Byte* limit;
+ FT_UInt count;
+ FT_UInt idx;
+ FT_Error error;
+
+
+ ps_parser_to_token( parser, &token );
+ if ( !token.type )
+ goto Fail;
+
+ count = 1;
+ idx = 0;
+ cur = token.start;
+ limit = token.limit;
+
+ /* we must detect arrays */
+ if ( field->type == T1_FIELD_TYPE_BBOX )
+ {
+ T1_TokenRec token2;
+ FT_Byte* old_cur = parser->cursor;
+ FT_Byte* old_limit = parser->limit;
+
+
+ parser->cursor = token.start;
+ parser->limit = token.limit;
+
+ ps_parser_to_token( parser, &token2 );
+ parser->cursor = old_cur;
+ parser->limit = old_limit;
+
+ if ( token2.type == T1_TOKEN_TYPE_ARRAY )
+ goto FieldArray;
+ }
+ else if ( token.type == T1_TOKEN_TYPE_ARRAY )
+ {
+ FieldArray:
+ /* if this is an array, and we have no blend, an error occurs */
+ if ( max_objects == 0 )
+ goto Fail;
+
+ count = max_objects;
+ idx = 1;
+ }
+
+ for ( ; count > 0; count--, idx++ )
+ {
+ FT_Byte* q = (FT_Byte*)objects[idx] + field->offset;
+ FT_Long val;
+ FT_String* string;
+
+
+ switch ( field->type )
+ {
+ case T1_FIELD_TYPE_BOOL:
+ val = t1_tobool( &cur, limit );
+ goto Store_Integer;
+
+ case T1_FIELD_TYPE_FIXED:
+ val = t1_tofixed( &cur, limit, 3 );
+ goto Store_Integer;
+
+ case T1_FIELD_TYPE_INTEGER:
+ val = t1_toint( &cur, limit );
+
+ Store_Integer:
+ switch ( field->size )
+ {
+ case 1:
+ *(FT_Byte*)q = (FT_Byte)val;
+ break;
+
+ case 2:
+ *(FT_UShort*)q = (FT_UShort)val;
+ break;
+
+ case 4:
+ *(FT_UInt32*)q = (FT_UInt32)val;
+ break;
+
+ default: /* for 64-bit systems */
+ *(FT_Long*)q = val;
+ }
+ break;
+
+ case T1_FIELD_TYPE_STRING:
+ {
+ FT_Memory memory = parser->memory;
+ FT_UInt len = (FT_UInt)( limit - cur );
+
+
+ if ( *(FT_String**)q )
+ /* with synthetic fonts, it's possible to find a field twice */
+ break;
+
+ if ( FT_ALLOC( string, len + 1 ) )
+ goto Exit;
+
+ FT_MEM_COPY( string, cur, len );
+ string[len] = 0;
+
+ *(FT_String**)q = string;
+ }
+ break;
+
+ case T1_FIELD_TYPE_BBOX:
+ {
+ FT_Fixed temp[4];
+ FT_BBox* bbox = (FT_BBox*)q;
+
+
+ /* we need the '[' and ']' delimiters */
+ token.start--;
+ token.limit++;
+ (void)t1_tofixedarray( &token.start, token.limit, 4, temp, 0 );
+
+ bbox->xMin = FT_RoundFix( temp[0] );
+ bbox->yMin = FT_RoundFix( temp[1] );
+ bbox->xMax = FT_RoundFix( temp[2] );
+ bbox->yMax = FT_RoundFix( temp[3] );
+ }
+ break;
+
+ default:
+ /* an error occured */
+ goto Fail;
+ }
+ }
+
+#if 0 /* obsolete - keep for reference */
+ if ( pflags )
+ *pflags |= 1L << field->flag_bit;
+#else
+ FT_UNUSED( pflags );
+#endif
+
+ error = PSaux_Err_Ok;
+
+ Exit:
+ return error;
+
+ Fail:
+ error = PSaux_Err_Invalid_File_Format;
+ goto Exit;
+ }
+
+
+#define T1_MAX_TABLE_ELEMENTS 32
+
+
+ FT_LOCAL_DEF( FT_Error )
+ ps_parser_load_field_table( PS_Parser parser,
+ const T1_Field field,
+ void** objects,
+ FT_UInt max_objects,
+ FT_ULong* pflags )
+ {
+ T1_TokenRec elements[T1_MAX_TABLE_ELEMENTS];
+ T1_Token token;
+ FT_Int num_elements;
+ FT_Error error = 0;
+ FT_Byte* old_cursor;
+ FT_Byte* old_limit;
+ T1_FieldRec fieldrec = *(T1_Field)field;
+
+
+#if 1
+ fieldrec.type = T1_FIELD_TYPE_INTEGER;
+ if ( field->type == T1_FIELD_TYPE_FIXED_ARRAY )
+ fieldrec.type = T1_FIELD_TYPE_FIXED;
+#endif
+
+ ps_parser_to_token_array( parser, elements, 32, &num_elements );
+ if ( num_elements < 0 )
+ goto Fail;
+
+ if ( num_elements > T1_MAX_TABLE_ELEMENTS )
+ num_elements = T1_MAX_TABLE_ELEMENTS;
+
+ old_cursor = parser->cursor;
+ old_limit = parser->limit;
+
+ /* we store the elements count */
+ *(FT_Byte*)( (FT_Byte*)objects[0] + field->count_offset ) =
+ (FT_Byte)num_elements;
+
+ /* we now load each element, adjusting the field.offset on each one */
+ token = elements;
+ for ( ; num_elements > 0; num_elements--, token++ )
+ {
+ parser->cursor = token->start;
+ parser->limit = token->limit;
+ ps_parser_load_field( parser, &fieldrec, objects, max_objects, 0 );
+ fieldrec.offset += fieldrec.size;
+ }
+
+#if 0 /* obsolete -- keep for reference */
+ if ( pflags )
+ *pflags |= 1L << field->flag_bit;
+#else
+ FT_UNUSED( pflags );
+#endif
+
+ parser->cursor = old_cursor;
+ parser->limit = old_limit;
+
+ Exit:
+ return error;
+
+ Fail:
+ error = PSaux_Err_Invalid_File_Format;
+ goto Exit;
+ }
+
+
+ FT_LOCAL_DEF( FT_Long )
+ ps_parser_to_int( PS_Parser parser )
+ {
+ return t1_toint( &parser->cursor, parser->limit );
+ }
+
+
+ FT_LOCAL_DEF( FT_Fixed )
+ ps_parser_to_fixed( PS_Parser parser,
+ FT_Int power_ten )
+ {
+ return t1_tofixed( &parser->cursor, parser->limit, power_ten );
+ }
+
+
+ FT_LOCAL_DEF( FT_Int )
+ ps_parser_to_coord_array( PS_Parser parser,
+ FT_Int max_coords,
+ FT_Short* coords )
+ {
+ return t1_tocoordarray( &parser->cursor, parser->limit,
+ max_coords, coords );
+ }
+
+
+ FT_LOCAL_DEF( FT_Int )
+ ps_parser_to_fixed_array( PS_Parser parser,
+ FT_Int max_values,
+ FT_Fixed* values,
+ FT_Int power_ten )
+ {
+ return t1_tofixedarray( &parser->cursor, parser->limit,
+ max_values, values, power_ten );
+ }
+
+
+#if 0
+
+ FT_LOCAL_DEF( FT_String* )
+ T1_ToString( PS_Parser parser )
+ {
+ return t1_tostring( &parser->cursor, parser->limit, parser->memory );
+ }
+
+
+ FT_LOCAL_DEF( FT_Bool )
+ T1_ToBool( PS_Parser parser )
+ {
+ return t1_tobool( &parser->cursor, parser->limit );
+ }
+
+#endif /* 0 */
+
+
+ FT_LOCAL_DEF( void )
+ ps_parser_init( PS_Parser parser,
+ FT_Byte* base,
+ FT_Byte* limit,
+ FT_Memory memory )
+ {
+ parser->error = 0;
+ parser->base = base;
+ parser->limit = limit;
+ parser->cursor = base;
+ parser->memory = memory;
+ parser->funcs = ps_parser_funcs;
+ }
+
+
+ FT_LOCAL_DEF( void )
+ ps_parser_done( PS_Parser parser )
+ {
+ FT_UNUSED( parser );
+ }
+
+
+ /*************************************************************************/
+ /*************************************************************************/
+ /***** *****/
+ /***** T1 BUILDER *****/
+ /***** *****/
+ /*************************************************************************/
+ /*************************************************************************/
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* t1_builder_init */
+ /* */
+ /* <Description> */
+ /* Initializes a given glyph builder. */
+ /* */
+ /* <InOut> */
+ /* builder :: A pointer to the glyph builder to initialize. */
+ /* */
+ /* <Input> */
+ /* face :: The current face object. */
+ /* */
+ /* size :: The current size object. */
+ /* */
+ /* glyph :: The current glyph object. */
+ /* */
+ /* hinting :: Whether hinting should be applied. */
+ /* */
+ FT_LOCAL_DEF( void )
+ t1_builder_init( T1_Builder builder,
+ FT_Face face,
+ FT_Size size,
+ FT_GlyphSlot glyph,
+ FT_Bool hinting )
+ {
+ builder->path_begun = 0;
+ builder->load_points = 1;
+
+ builder->face = face;
+ builder->glyph = glyph;
+ builder->memory = face->memory;
+
+ if ( glyph )
+ {
+ FT_GlyphLoader loader = glyph->internal->loader;
+
+
+ builder->loader = loader;
+ builder->base = &loader->base.outline;
+ builder->current = &loader->current.outline;
+ FT_GlyphLoader_Rewind( loader );
+
+ builder->hints_globals = size->internal;
+ builder->hints_funcs = 0;
+
+ if ( hinting )
+ builder->hints_funcs = glyph->internal->glyph_hints;
+ }
+
+ if ( size )
+ {
+ builder->scale_x = size->metrics.x_scale;
+ builder->scale_y = size->metrics.y_scale;
+ }
+
+ builder->pos_x = 0;
+ builder->pos_y = 0;
+
+ builder->left_bearing.x = 0;
+ builder->left_bearing.y = 0;
+ builder->advance.x = 0;
+ builder->advance.y = 0;
+
+ builder->funcs = t1_builder_funcs;
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* t1_builder_done */
+ /* */
+ /* <Description> */
+ /* Finalizes a given glyph builder. Its contents can still be used */
+ /* after the call, but the function saves important information */
+ /* within the corresponding glyph slot. */
+ /* */
+ /* <Input> */
+ /* builder :: A pointer to the glyph builder to finalize. */
+ /* */
+ FT_LOCAL_DEF( void )
+ t1_builder_done( T1_Builder builder )
+ {
+ FT_GlyphSlot glyph = builder->glyph;
+
+
+ if ( glyph )
+ glyph->outline = *builder->base;
+ }
+
+
+ /* check that there is enough space for `count' more points */
+ FT_LOCAL_DEF( FT_Error )
+ t1_builder_check_points( T1_Builder builder,
+ FT_Int count )
+ {
+ return FT_GlyphLoader_CheckPoints( builder->loader, count, 0 );
+ }
+
+
+ /* add a new point, do not check space */
+ FT_LOCAL_DEF( void )
+ t1_builder_add_point( T1_Builder builder,
+ FT_Pos x,
+ FT_Pos y,
+ FT_Byte flag )
+ {
+ FT_Outline* outline = builder->current;
+
+
+ if ( builder->load_points )
+ {
+ FT_Vector* point = outline->points + outline->n_points;
+ FT_Byte* control = (FT_Byte*)outline->tags + outline->n_points;
+
+
+ if ( builder->shift )
+ {
+ x >>= 16;
+ y >>= 16;
+ }
+ point->x = x;
+ point->y = y;
+ *control = (FT_Byte)( flag ? FT_CURVE_TAG_ON : FT_CURVE_TAG_CUBIC );
+
+ builder->last = *point;
+ }
+ outline->n_points++;
+ }
+
+
+ /* check space for a new on-curve point, then add it */
+ FT_LOCAL_DEF( FT_Error )
+ t1_builder_add_point1( T1_Builder builder,
+ FT_Pos x,
+ FT_Pos y )
+ {
+ FT_Error error;
+
+
+ error = t1_builder_check_points( builder, 1 );
+ if ( !error )
+ t1_builder_add_point( builder, x, y, 1 );
+
+ return error;
+ }
+
+
+ /* check room for a new contour, then add it */
+ FT_LOCAL_DEF( FT_Error )
+ t1_builder_add_contour( T1_Builder builder )
+ {
+ FT_Outline* outline = builder->current;
+ FT_Error error;
+
+
+ if ( !builder->load_points )
+ {
+ outline->n_contours++;
+ return PSaux_Err_Ok;
+ }
+
+ error = FT_GlyphLoader_CheckPoints( builder->loader, 0, 1 );
+ if ( !error )
+ {
+ if ( outline->n_contours > 0 )
+ outline->contours[outline->n_contours - 1] =
+ (short)( outline->n_points - 1 );
+
+ outline->n_contours++;
+ }
+
+ return error;
+ }
+
+
+ /* if a path was begun, add its first on-curve point */
+ FT_LOCAL_DEF( FT_Error )
+ t1_builder_start_point( T1_Builder builder,
+ FT_Pos x,
+ FT_Pos y )
+ {
+ FT_Error error = 0;
+
+
+ /* test whether we are building a new contour */
+ if ( !builder->path_begun )
+ {
+ builder->path_begun = 1;
+ error = t1_builder_add_contour( builder );
+ if ( !error )
+ error = t1_builder_add_point1( builder, x, y );
+ }
+ return error;
+ }
+
+
+ /* close the current contour */
+ FT_LOCAL_DEF( void )
+ t1_builder_close_contour( T1_Builder builder )
+ {
+ FT_Outline* outline = builder->current;
+
+
+ /* XXXX: We must not include the last point in the path if it */
+ /* is located on the first point. */
+ if ( outline->n_points > 1 )
+ {
+ FT_Int first = 0;
+ FT_Vector* p1 = outline->points + first;
+ FT_Vector* p2 = outline->points + outline->n_points - 1;
+ FT_Byte* control = (FT_Byte*)outline->tags + outline->n_points - 1;
+
+
+ if ( outline->n_contours > 1 )
+ {
+ first = outline->contours[outline->n_contours - 2] + 1;
+ p1 = outline->points + first;
+ }
+
+ /* `delete' last point only if it coincides with the first */
+ /* point and it is not a control point (which can happen). */
+ if ( p1->x == p2->x && p1->y == p2->y )
+ if ( *control == FT_CURVE_TAG_ON )
+ outline->n_points--;
+ }
+
+ if ( outline->n_contours > 0 )
+ outline->contours[outline->n_contours - 1] =
+ (short)( outline->n_points - 1 );
+ }
+
+
+ /*************************************************************************/
+ /*************************************************************************/
+ /***** *****/
+ /***** OTHER *****/
+ /***** *****/
+ /*************************************************************************/
+ /*************************************************************************/
+
+ FT_LOCAL_DEF( void )
+ t1_decrypt( FT_Byte* buffer,
+ FT_Offset length,
+ FT_UShort seed )
+ {
+ while ( length > 0 )
+ {
+ FT_Byte plain;
+
+
+ plain = (FT_Byte)( *buffer ^ ( seed >> 8 ) );
+ seed = (FT_UShort)( ( *buffer + seed ) * 52845U + 22719 );
+ *buffer++ = plain;
+ length--;
+ }
+ }
+
+
+/* END */
--- /dev/null
+++ b/libfreetype/psobjs.h
@@ -1,0 +1,204 @@
+/***************************************************************************/
+/* */
+/* psobjs.h */
+/* */
+/* Auxiliary functions for PostScript fonts (specification). */
+/* */
+/* Copyright 1996-2001, 2002 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+
+#ifndef __PSOBJS_H__
+#define __PSOBJS_H__
+
+
+#include <ft2build.h>
+#include FT_INTERNAL_POSTSCRIPT_AUX_H
+
+
+FT_BEGIN_HEADER
+
+
+ /*************************************************************************/
+ /*************************************************************************/
+ /***** *****/
+ /***** T1_TABLE *****/
+ /***** *****/
+ /*************************************************************************/
+ /*************************************************************************/
+
+
+ FT_CALLBACK_TABLE
+ const PS_Table_FuncsRec ps_table_funcs;
+
+ FT_CALLBACK_TABLE
+ const PS_Parser_FuncsRec ps_parser_funcs;
+
+ FT_CALLBACK_TABLE
+ const T1_Builder_FuncsRec t1_builder_funcs;
+
+
+ FT_LOCAL( FT_Error )
+ ps_table_new( PS_Table table,
+ FT_Int count,
+ FT_Memory memory );
+
+ FT_LOCAL( FT_Error )
+ ps_table_add( PS_Table table,
+ FT_Int idx,
+ void* object,
+ FT_Int length );
+
+ FT_LOCAL( void )
+ ps_table_done( PS_Table table );
+
+
+ FT_LOCAL( void )
+ ps_table_release( PS_Table table );
+
+
+ /*************************************************************************/
+ /*************************************************************************/
+ /***** *****/
+ /***** T1 PARSER *****/
+ /***** *****/
+ /*************************************************************************/
+ /*************************************************************************/
+
+
+ FT_LOCAL( void )
+ ps_parser_skip_spaces( PS_Parser parser );
+
+ FT_LOCAL( void )
+ ps_parser_skip_alpha( PS_Parser parser );
+
+ FT_LOCAL( void )
+ ps_parser_to_token( PS_Parser parser,
+ T1_Token token );
+
+ FT_LOCAL( void )
+ ps_parser_to_token_array( PS_Parser parser,
+ T1_Token tokens,
+ FT_UInt max_tokens,
+ FT_Int* pnum_tokens );
+
+ FT_LOCAL( FT_Error )
+ ps_parser_load_field( PS_Parser parser,
+ const T1_Field field,
+ void** objects,
+ FT_UInt max_objects,
+ FT_ULong* pflags );
+
+ FT_LOCAL( FT_Error )
+ ps_parser_load_field_table( PS_Parser parser,
+ const T1_Field field,
+ void** objects,
+ FT_UInt max_objects,
+ FT_ULong* pflags );
+
+ FT_LOCAL( FT_Long )
+ ps_parser_to_int( PS_Parser parser );
+
+
+ FT_LOCAL( FT_Fixed )
+ ps_parser_to_fixed( PS_Parser parser,
+ FT_Int power_ten );
+
+
+ FT_LOCAL( FT_Int )
+ ps_parser_to_coord_array( PS_Parser parser,
+ FT_Int max_coords,
+ FT_Short* coords );
+
+ FT_LOCAL( FT_Int )
+ ps_parser_to_fixed_array( PS_Parser parser,
+ FT_Int max_values,
+ FT_Fixed* values,
+ FT_Int power_ten );
+
+
+ FT_LOCAL( void )
+ ps_parser_init( PS_Parser parser,
+ FT_Byte* base,
+ FT_Byte* limit,
+ FT_Memory memory );
+
+ FT_LOCAL( void )
+ ps_parser_done( PS_Parser parser );
+
+
+ /*************************************************************************/
+ /*************************************************************************/
+ /***** *****/
+ /***** T1 BUILDER *****/
+ /***** *****/
+ /*************************************************************************/
+ /*************************************************************************/
+
+ FT_LOCAL( void )
+ t1_builder_init( T1_Builder builder,
+ FT_Face face,
+ FT_Size size,
+ FT_GlyphSlot glyph,
+ FT_Bool hinting );
+
+ FT_LOCAL( void )
+ t1_builder_done( T1_Builder builder );
+
+ FT_LOCAL( FT_Error )
+ t1_builder_check_points( T1_Builder builder,
+ FT_Int count );
+
+ FT_LOCAL( void )
+ t1_builder_add_point( T1_Builder builder,
+ FT_Pos x,
+ FT_Pos y,
+ FT_Byte flag );
+
+ FT_LOCAL( FT_Error )
+ t1_builder_add_point1( T1_Builder builder,
+ FT_Pos x,
+ FT_Pos y );
+
+ FT_LOCAL( FT_Error )
+ t1_builder_add_contour( T1_Builder builder );
+
+
+ FT_LOCAL( FT_Error )
+ t1_builder_start_point( T1_Builder builder,
+ FT_Pos x,
+ FT_Pos y );
+
+
+ FT_LOCAL( void )
+ t1_builder_close_contour( T1_Builder builder );
+
+
+ /*************************************************************************/
+ /*************************************************************************/
+ /***** *****/
+ /***** OTHER *****/
+ /***** *****/
+ /*************************************************************************/
+ /*************************************************************************/
+
+ FT_LOCAL( void )
+ t1_decrypt( FT_Byte* buffer,
+ FT_Offset length,
+ FT_UShort seed );
+
+
+FT_END_HEADER
+
+#endif /* __PSOBJS_H__ */
+
+
+/* END */
--- /dev/null
+++ b/libfreetype/pstables.h
@@ -1,0 +1,2967 @@
+/***************************************************************************/
+/* */
+/* pstables.h */
+/* */
+/* PostScript glyph names (specification only). */
+/* */
+/* Copyright 2000-2001 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+
+ /* this file has been generated automatically -- do not edit! */
+
+
+ static const char* const ps_glyph_names[] =
+ {
+ ".null",
+ "nonmarkingreturn",
+ "nonbreakingspace",
+ "apple",
+ ".notdef",
+ "space",
+ "exclam",
+ "quotedbl",
+ "numbersign",
+ "dollar",
+ "percent",
+ "ampersand",
+ "quoteright",
+ "parenleft",
+ "parenright",
+ "asterisk",
+ "plus",
+ "comma",
+ "hyphen",
+ "period",
+ "slash",
+ "zero",
+ "one",
+ "two",
+ "three",
+ "four",
+ "five",
+ "six",
+ "seven",
+ "eight",
+ "nine",
+ "colon",
+ "semicolon",
+ "less",
+ "equal",
+ "greater",
+ "question",
+ "at",
+ "A",
+ "B",
+ "C",
+ "D",
+ "E",
+ "F",
+ "G",
+ "H",
+ "I",
+ "J",
+ "K",
+ "L",
+ "M",
+ "N",
+ "O",
+ "P",
+ "Q",
+ "R",
+ "S",
+ "T",
+ "U",
+ "V",
+ "W",
+ "X",
+ "Y",
+ "Z",
+ "bracketleft",
+ "backslash",
+ "bracketright",
+ "asciicircum",
+ "underscore",
+ "quoteleft",
+ "a",
+ "b",
+ "c",
+ "d",
+ "e",
+ "f",
+ "g",
+ "h",
+ "i",
+ "j",
+ "k",
+ "l",
+ "m",
+ "n",
+ "o",
+ "p",
+ "q",
+ "r",
+ "s",
+ "t",
+ "u",
+ "v",
+ "w",
+ "x",
+ "y",
+ "z",
+ "braceleft",
+ "bar",
+ "braceright",
+ "asciitilde",
+ "exclamdown",
+ "cent",
+ "sterling",
+ "fraction",
+ "yen",
+ "florin",
+ "section",
+ "currency",
+ "quotesingle",
+ "quotedblleft",
+ "guillemotleft",
+ "guilsinglleft",
+ "guilsinglright",
+ "fi",
+ "fl",
+ "endash",
+ "dagger",
+ "daggerdbl",
+ "periodcentered",
+ "paragraph",
+ "bullet",
+ "quotesinglbase",
+ "quotedblbase",
+ "quotedblright",
+ "guillemotright",
+ "ellipsis",
+ "perthousand",
+ "questiondown",
+ "grave",
+ "acute",
+ "circumflex",
+ "tilde",
+ "macron",
+ "breve",
+ "dotaccent",
+ "dieresis",
+ "ring",
+ "cedilla",
+ "hungarumlaut",
+ "ogonek",
+ "caron",
+ "emdash",
+ "AE",
+ "ordfeminine",
+ "Lslash",
+ "Oslash",
+ "OE",
+ "ordmasculine",
+ "ae",
+ "dotlessi",
+ "lslash",
+ "oslash",
+ "oe",
+ "germandbls",
+ "onesuperior",
+ "logicalnot",
+ "mu",
+ "trademark",
+ "Eth",
+ "onehalf",
+ "plusminus",
+ "Thorn",
+ "onequarter",
+ "divide",
+ "brokenbar",
+ "degree",
+ "thorn",
+ "threequarters",
+ "twosuperior",
+ "registered",
+ "minus",
+ "eth",
+ "multiply",
+ "threesuperior",
+ "copyright",
+ "Aacute",
+ "Acircumflex",
+ "Adieresis",
+ "Agrave",
+ "Aring",
+ "Atilde",
+ "Ccedilla",
+ "Eacute",
+ "Ecircumflex",
+ "Edieresis",
+ "Egrave",
+ "Iacute",
+ "Icircumflex",
+ "Idieresis",
+ "Igrave",
+ "Ntilde",
+ "Oacute",
+ "Ocircumflex",
+ "Odieresis",
+ "Ograve",
+ "Otilde",
+ "Scaron",
+ "Uacute",
+ "Ucircumflex",
+ "Udieresis",
+ "Ugrave",
+ "Yacute",
+ "Ydieresis",
+ "Zcaron",
+ "aacute",
+ "acircumflex",
+ "adieresis",
+ "agrave",
+ "aring",
+ "atilde",
+ "ccedilla",
+ "eacute",
+ "ecircumflex",
+ "edieresis",
+ "egrave",
+ "iacute",
+ "icircumflex",
+ "idieresis",
+ "igrave",
+ "ntilde",
+ "oacute",
+ "ocircumflex",
+ "odieresis",
+ "ograve",
+ "otilde",
+ "scaron",
+ "uacute",
+ "ucircumflex",
+ "udieresis",
+ "ugrave",
+ "yacute",
+ "ydieresis",
+ "zcaron",
+ "exclamsmall",
+ "Hungarumlautsmall",
+ "dollaroldstyle",
+ "dollarsuperior",
+ "ampersandsmall",
+ "Acutesmall",
+ "parenleftsuperior",
+ "parenrightsuperior",
+ "twodotenleader",
+ "onedotenleader",
+ "zerooldstyle",
+ "oneoldstyle",
+ "twooldstyle",
+ "threeoldstyle",
+ "fouroldstyle",
+ "fiveoldstyle",
+ "sixoldstyle",
+ "sevenoldstyle",
+ "eightoldstyle",
+ "nineoldstyle",
+ "commasuperior",
+ "threequartersemdash",
+ "periodsuperior",
+ "questionsmall",
+ "asuperior",
+ "bsuperior",
+ "centsuperior",
+ "dsuperior",
+ "esuperior",
+ "isuperior",
+ "lsuperior",
+ "msuperior",
+ "nsuperior",
+ "osuperior",
+ "rsuperior",
+ "ssuperior",
+ "tsuperior",
+ "ff",
+ "ffi",
+ "ffl",
+ "parenleftinferior",
+ "parenrightinferior",
+ "Circumflexsmall",
+ "hyphensuperior",
+ "Gravesmall",
+ "Asmall",
+ "Bsmall",
+ "Csmall",
+ "Dsmall",
+ "Esmall",
+ "Fsmall",
+ "Gsmall",
+ "Hsmall",
+ "Ismall",
+ "Jsmall",
+ "Ksmall",
+ "Lsmall",
+ "Msmall",
+ "Nsmall",
+ "Osmall",
+ "Psmall",
+ "Qsmall",
+ "Rsmall",
+ "Ssmall",
+ "Tsmall",
+ "Usmall",
+ "Vsmall",
+ "Wsmall",
+ "Xsmall",
+ "Ysmall",
+ "Zsmall",
+ "colonmonetary",
+ "onefitted",
+ "rupiah",
+ "Tildesmall",
+ "exclamdownsmall",
+ "centoldstyle",
+ "Lslashsmall",
+ "Scaronsmall",
+ "Zcaronsmall",
+ "Dieresissmall",
+ "Brevesmall",
+ "Caronsmall",
+ "Dotaccentsmall",
+ "Macronsmall",
+ "figuredash",
+ "hypheninferior",
+ "Ogoneksmall",
+ "Ringsmall",
+ "Cedillasmall",
+ "questiondownsmall",
+ "oneeighth",
+ "threeeighths",
+ "fiveeighths",
+ "seveneighths",
+ "onethird",
+ "twothirds",
+ "zerosuperior",
+ "foursuperior",
+ "fivesuperior",
+ "sixsuperior",
+ "sevensuperior",
+ "eightsuperior",
+ "ninesuperior",
+ "zeroinferior",
+ "oneinferior",
+ "twoinferior",
+ "threeinferior",
+ "fourinferior",
+ "fiveinferior",
+ "sixinferior",
+ "seveninferior",
+ "eightinferior",
+ "nineinferior",
+ "centinferior",
+ "dollarinferior",
+ "periodinferior",
+ "commainferior",
+ "Agravesmall",
+ "Aacutesmall",
+ "Acircumflexsmall",
+ "Atildesmall",
+ "Adieresissmall",
+ "Aringsmall",
+ "AEsmall",
+ "Ccedillasmall",
+ "Egravesmall",
+ "Eacutesmall",
+ "Ecircumflexsmall",
+ "Edieresissmall",
+ "Igravesmall",
+ "Iacutesmall",
+ "Icircumflexsmall",
+ "Idieresissmall",
+ "Ethsmall",
+ "Ntildesmall",
+ "Ogravesmall",
+ "Oacutesmall",
+ "Ocircumflexsmall",
+ "Otildesmall",
+ "Odieresissmall",
+ "OEsmall",
+ "Oslashsmall",
+ "Ugravesmall",
+ "Uacutesmall",
+ "Ucircumflexsmall",
+ "Udieresissmall",
+ "Yacutesmall",
+ "Thornsmall",
+ "Ydieresissmall",
+ "001.000",
+ "001.001",
+ "001.002",
+ "001.003",
+ "Black",
+ "Bold",
+ "Book",
+ "Light",
+ "Medium",
+ "Regular",
+ "Roman",
+ "Semibold",
+
+#ifdef FT_CONFIG_OPTION_ADOBE_GLYPH_LIST
+
+ "AEacute",
+ "Abreve",
+ "Acute",
+ "Alpha",
+ "Alphatonos",
+ "Amacron",
+ "Aogonek",
+ "Aringacute",
+ "Beta",
+ "Cacute",
+ "Caron",
+ "Ccaron",
+ "Ccircumflex",
+ "Cdotaccent",
+ "Chi",
+ "Dcaron",
+ "Dcroat",
+ "Delta",
+ "Delta",
+ "Dieresis",
+ "DieresisAcute",
+ "DieresisGrave",
+ "Ebreve",
+ "Ecaron",
+ "Edotaccent",
+ "Emacron",
+ "Eng",
+ "Eogonek",
+ "Epsilon",
+ "Epsilontonos",
+ "Eta",
+ "Etatonos",
+ "Euro",
+ "Gamma",
+ "Gbreve",
+ "Gcaron",
+ "Gcircumflex",
+ "Gcommaaccent",
+ "Gdotaccent",
+ "Grave",
+ "H18533",
+ "H18543",
+ "H18551",
+ "H22073",
+ "Hbar",
+ "Hcircumflex",
+ "Hungarumlaut",
+ "IJ",
+ "Ibreve",
+ "Idotaccent",
+ "Ifraktur",
+ "Imacron",
+ "Iogonek",
+ "Iota",
+ "Iotadieresis",
+ "Iotatonos",
+ "Itilde",
+ "Jcircumflex",
+ "Kappa",
+ "Kcommaaccent",
+ "LL",
+ "Lacute",
+ "Lambda",
+ "Lcaron",
+ "Lcommaaccent",
+ "Ldot",
+ "Macron",
+ "Mu",
+ "Nacute",
+ "Ncaron",
+ "Ncommaaccent",
+ "Nu",
+ "Obreve",
+ "Ohorn",
+ "Ohungarumlaut",
+ "Omacron",
+ "Omega",
+ "Omega",
+ "Omegatonos",
+ "Omicron",
+ "Omicrontonos",
+ "Oslashacute",
+ "Phi",
+ "Pi",
+ "Psi",
+ "Racute",
+ "Rcaron",
+ "Rcommaaccent",
+ "Rfraktur",
+ "Rho",
+ "SF010000",
+ "SF020000",
+ "SF030000",
+ "SF040000",
+ "SF050000",
+ "SF060000",
+ "SF070000",
+ "SF080000",
+ "SF090000",
+ "SF100000",
+ "SF110000",
+ "SF190000",
+ "SF200000",
+ "SF210000",
+ "SF220000",
+ "SF230000",
+ "SF240000",
+ "SF250000",
+ "SF260000",
+ "SF270000",
+ "SF280000",
+ "SF360000",
+ "SF370000",
+ "SF380000",
+ "SF390000",
+ "SF400000",
+ "SF410000",
+ "SF420000",
+ "SF430000",
+ "SF440000",
+ "SF450000",
+ "SF460000",
+ "SF470000",
+ "SF480000",
+ "SF490000",
+ "SF500000",
+ "SF510000",
+ "SF520000",
+ "SF530000",
+ "SF540000",
+ "Sacute",
+ "Scedilla",
+ "Scedilla",
+ "Scircumflex",
+ "Scommaaccent",
+ "Sigma",
+ "Tau",
+ "Tbar",
+ "Tcaron",
+ "Tcommaaccent",
+ "Tcommaaccent",
+ "Theta",
+ "Ubreve",
+ "Uhorn",
+ "Uhungarumlaut",
+ "Umacron",
+ "Uogonek",
+ "Upsilon",
+ "Upsilon1",
+ "Upsilondieresis",
+ "Upsilontonos",
+ "Uring",
+ "Utilde",
+ "Wacute",
+ "Wcircumflex",
+ "Wdieresis",
+ "Wgrave",
+ "Xi",
+ "Ycircumflex",
+ "Ygrave",
+ "Zacute",
+ "Zdotaccent",
+ "Zeta",
+ "abreve",
+ "acutecomb",
+ "aeacute",
+ "afii00208",
+ "afii10017",
+ "afii10018",
+ "afii10019",
+ "afii10020",
+ "afii10021",
+ "afii10022",
+ "afii10023",
+ "afii10024",
+ "afii10025",
+ "afii10026",
+ "afii10027",
+ "afii10028",
+ "afii10029",
+ "afii10030",
+ "afii10031",
+ "afii10032",
+ "afii10033",
+ "afii10034",
+ "afii10035",
+ "afii10036",
+ "afii10037",
+ "afii10038",
+ "afii10039",
+ "afii10040",
+ "afii10041",
+ "afii10042",
+ "afii10043",
+ "afii10044",
+ "afii10045",
+ "afii10046",
+ "afii10047",
+ "afii10048",
+ "afii10049",
+ "afii10050",
+ "afii10051",
+ "afii10052",
+ "afii10053",
+ "afii10054",
+ "afii10055",
+ "afii10056",
+ "afii10057",
+ "afii10058",
+ "afii10059",
+ "afii10060",
+ "afii10061",
+ "afii10062",
+ "afii10063",
+ "afii10064",
+ "afii10065",
+ "afii10066",
+ "afii10067",
+ "afii10068",
+ "afii10069",
+ "afii10070",
+ "afii10071",
+ "afii10072",
+ "afii10073",
+ "afii10074",
+ "afii10075",
+ "afii10076",
+ "afii10077",
+ "afii10078",
+ "afii10079",
+ "afii10080",
+ "afii10081",
+ "afii10082",
+ "afii10083",
+ "afii10084",
+ "afii10085",
+ "afii10086",
+ "afii10087",
+ "afii10088",
+ "afii10089",
+ "afii10090",
+ "afii10091",
+ "afii10092",
+ "afii10093",
+ "afii10094",
+ "afii10095",
+ "afii10096",
+ "afii10097",
+ "afii10098",
+ "afii10099",
+ "afii10100",
+ "afii10101",
+ "afii10102",
+ "afii10103",
+ "afii10104",
+ "afii10105",
+ "afii10106",
+ "afii10107",
+ "afii10108",
+ "afii10109",
+ "afii10110",
+ "afii10145",
+ "afii10146",
+ "afii10147",
+ "afii10148",
+ "afii10192",
+ "afii10193",
+ "afii10194",
+ "afii10195",
+ "afii10196",
+ "afii10831",
+ "afii10832",
+ "afii10846",
+ "afii299",
+ "afii300",
+ "afii301",
+ "afii57381",
+ "afii57388",
+ "afii57392",
+ "afii57393",
+ "afii57394",
+ "afii57395",
+ "afii57396",
+ "afii57397",
+ "afii57398",
+ "afii57399",
+ "afii57400",
+ "afii57401",
+ "afii57403",
+ "afii57407",
+ "afii57409",
+ "afii57410",
+ "afii57411",
+ "afii57412",
+ "afii57413",
+ "afii57414",
+ "afii57415",
+ "afii57416",
+ "afii57417",
+ "afii57418",
+ "afii57419",
+ "afii57420",
+ "afii57421",
+ "afii57422",
+ "afii57423",
+ "afii57424",
+ "afii57425",
+ "afii57426",
+ "afii57427",
+ "afii57428",
+ "afii57429",
+ "afii57430",
+ "afii57431",
+ "afii57432",
+ "afii57433",
+ "afii57434",
+ "afii57440",
+ "afii57441",
+ "afii57442",
+ "afii57443",
+ "afii57444",
+ "afii57445",
+ "afii57446",
+ "afii57448",
+ "afii57449",
+ "afii57450",
+ "afii57451",
+ "afii57452",
+ "afii57453",
+ "afii57454",
+ "afii57455",
+ "afii57456",
+ "afii57457",
+ "afii57458",
+ "afii57470",
+ "afii57505",
+ "afii57506",
+ "afii57507",
+ "afii57508",
+ "afii57509",
+ "afii57511",
+ "afii57512",
+ "afii57513",
+ "afii57514",
+ "afii57519",
+ "afii57534",
+ "afii57636",
+ "afii57645",
+ "afii57658",
+ "afii57664",
+ "afii57665",
+ "afii57666",
+ "afii57667",
+ "afii57668",
+ "afii57669",
+ "afii57670",
+ "afii57671",
+ "afii57672",
+ "afii57673",
+ "afii57674",
+ "afii57675",
+ "afii57676",
+ "afii57677",
+ "afii57678",
+ "afii57679",
+ "afii57680",
+ "afii57681",
+ "afii57682",
+ "afii57683",
+ "afii57684",
+ "afii57685",
+ "afii57686",
+ "afii57687",
+ "afii57688",
+ "afii57689",
+ "afii57690",
+ "afii57694",
+ "afii57695",
+ "afii57700",
+ "afii57705",
+ "afii57716",
+ "afii57717",
+ "afii57718",
+ "afii57723",
+ "afii57793",
+ "afii57794",
+ "afii57795",
+ "afii57796",
+ "afii57797",
+ "afii57798",
+ "afii57799",
+ "afii57800",
+ "afii57801",
+ "afii57802",
+ "afii57803",
+ "afii57804",
+ "afii57806",
+ "afii57807",
+ "afii57839",
+ "afii57841",
+ "afii57842",
+ "afii57929",
+ "afii61248",
+ "afii61289",
+ "afii61352",
+ "afii61573",
+ "afii61574",
+ "afii61575",
+ "afii61664",
+ "afii63167",
+ "afii64937",
+ "aleph",
+ "alpha",
+ "alphatonos",
+ "amacron",
+ "angle",
+ "angleleft",
+ "angleright",
+ "anoteleia",
+ "aogonek",
+ "approxequal",
+ "aringacute",
+ "arrowboth",
+ "arrowdblboth",
+ "arrowdbldown",
+ "arrowdblleft",
+ "arrowdblright",
+ "arrowdblup",
+ "arrowdown",
+ "arrowhorizex",
+ "arrowleft",
+ "arrowright",
+ "arrowup",
+ "arrowupdn",
+ "arrowupdnbse",
+ "arrowvertex",
+ "asteriskmath",
+ "beta",
+ "block",
+ "braceex",
+ "braceleftbt",
+ "braceleftmid",
+ "bracelefttp",
+ "bracerightbt",
+ "bracerightmid",
+ "bracerighttp",
+ "bracketleftbt",
+ "bracketleftex",
+ "bracketlefttp",
+ "bracketrightbt",
+ "bracketrightex",
+ "bracketrighttp",
+ "cacute",
+ "carriagereturn",
+ "ccaron",
+ "ccircumflex",
+ "cdotaccent",
+ "chi",
+ "circle",
+ "circlemultiply",
+ "circleplus",
+ "club",
+ "commaaccent",
+ "congruent",
+ "copyrightsans",
+ "copyrightserif",
+ "cyrBreve",
+ "cyrFlex",
+ "cyrbreve",
+ "cyrflex",
+ "dblGrave",
+ "dblgrave",
+ "dcaron",
+ "dcroat",
+ "delta",
+ "diamond",
+ "dieresisacute",
+ "dieresisgrave",
+ "dieresistonos",
+ "dkshade",
+ "dnblock",
+ "dong",
+ "dotbelowcomb",
+ "dotlessj",
+ "dotmath",
+ "ebreve",
+ "ecaron",
+ "edotaccent",
+ "element",
+ "emacron",
+ "emptyset",
+ "eng",
+ "eogonek",
+ "epsilon",
+ "epsilontonos",
+ "equivalence",
+ "estimated",
+ "eta",
+ "etatonos",
+ "exclamdbl",
+ "existential",
+ "female",
+ "filledbox",
+ "filledrect",
+ "franc",
+ "gamma",
+ "gbreve",
+ "gcaron",
+ "gcircumflex",
+ "gcommaaccent",
+ "gdotaccent",
+ "gradient",
+ "gravecomb",
+ "greaterequal",
+ "hbar",
+ "hcircumflex",
+ "heart",
+ "hookabovecomb",
+ "house",
+ "ibreve",
+ "ij",
+ "imacron",
+ "infinity",
+ "integral",
+ "integralbt",
+ "integralex",
+ "integraltp",
+ "intersection",
+ "invbullet",
+ "invcircle",
+ "invsmileface",
+ "iogonek",
+ "iota",
+ "iotadieresis",
+ "iotadieresistonos",
+ "iotatonos",
+ "itilde",
+ "jcircumflex",
+ "kappa",
+ "kcommaaccent",
+ "kgreenlandic",
+ "lacute",
+ "lambda",
+ "lcaron",
+ "lcommaaccent",
+ "ldot",
+ "lessequal",
+ "lfblock",
+ "lira",
+ "ll",
+ "logicaland",
+ "logicalor",
+ "longs",
+ "lozenge",
+ "ltshade",
+ "male",
+ "minute",
+ "musicalnote",
+ "musicalnotedbl",
+ "nacute",
+ "napostrophe",
+ "ncaron",
+ "ncommaaccent",
+ "notelement",
+ "notequal",
+ "notsubset",
+ "nu",
+ "obreve",
+ "ohorn",
+ "ohungarumlaut",
+ "omacron",
+ "omega",
+ "omega1",
+ "omegatonos",
+ "omicron",
+ "omicrontonos",
+ "openbullet",
+ "orthogonal",
+ "oslashacute",
+ "parenleftbt",
+ "parenleftex",
+ "parenlefttp",
+ "parenrightbt",
+ "parenrightex",
+ "parenrighttp",
+ "partialdiff",
+ "perpendicular",
+ "peseta",
+ "phi",
+ "phi1",
+ "pi",
+ "prescription",
+ "product",
+ "propersubset",
+ "propersuperset",
+ "proportional",
+ "psi",
+ "quotereversed",
+ "racute",
+ "radical",
+ "radicalex",
+ "rcaron",
+ "rcommaaccent",
+ "reflexsubset",
+ "reflexsuperset",
+ "registersans",
+ "registerserif",
+ "revlogicalnot",
+ "rho",
+ "rtblock",
+ "sacute",
+ "scedilla",
+ "scedilla",
+ "scircumflex",
+ "scommaaccent",
+ "second",
+ "shade",
+ "sigma",
+ "sigma1",
+ "similar",
+ "smileface",
+ "spade",
+ "suchthat",
+ "summation",
+ "sun",
+ "tau",
+ "tbar",
+ "tcaron",
+ "tcommaaccent",
+ "tcommaaccent",
+ "therefore",
+ "theta",
+ "theta1",
+ "tildecomb",
+ "tonos",
+ "trademarksans",
+ "trademarkserif",
+ "triagdn",
+ "triaglf",
+ "triagrt",
+ "triagup",
+ "ubreve",
+ "uhorn",
+ "uhungarumlaut",
+ "umacron",
+ "underscoredbl",
+ "union",
+ "universal",
+ "uogonek",
+ "upblock",
+ "upsilon",
+ "upsilondieresis",
+ "upsilondieresistonos",
+ "upsilontonos",
+ "uring",
+ "utilde",
+ "wacute",
+ "wcircumflex",
+ "wdieresis",
+ "weierstrass",
+ "wgrave",
+ "xi",
+ "ycircumflex",
+ "ygrave",
+ "zacute",
+ "zdotaccent",
+ "zeta",
+
+#endif /* FT_CONFIG_OPTION_ADOBE_GLYPH_LIST */
+
+ NULL
+ };
+
+
+ static const char* const * const sid_standard_names = ps_glyph_names + 4;
+
+
+#define NUM_SID_GLYPHS 391
+
+#ifdef FT_CONFIG_OPTION_ADOBE_GLYPH_LIST
+#define NUM_ADOBE_GLYPHS 1058
+#else
+#define NUM_ADOBE_GLYPHS 391
+#endif
+
+
+ static const unsigned short mac_standard_names[259] =
+ {
+ 4,
+ 0,
+ 1,
+ 5,
+ 6,
+ 7,
+ 8,
+ 9,
+ 10,
+ 11,
+ 108,
+ 13,
+ 14,
+ 15,
+ 16,
+ 17,
+ 18,
+ 19,
+ 20,
+ 21,
+ 22,
+ 23,
+ 24,
+ 25,
+ 26,
+ 27,
+ 28,
+ 29,
+ 30,
+ 31,
+ 32,
+ 33,
+ 34,
+ 35,
+ 36,
+ 37,
+ 38,
+ 39,
+ 40,
+ 41,
+ 42,
+ 43,
+ 44,
+ 45,
+ 46,
+ 47,
+ 48,
+ 49,
+ 50,
+ 51,
+ 52,
+ 53,
+ 54,
+ 55,
+ 56,
+ 57,
+ 58,
+ 59,
+ 60,
+ 61,
+ 62,
+ 63,
+ 64,
+ 65,
+ 66,
+ 67,
+ 68,
+ 128,
+ 70,
+ 71,
+ 72,
+ 73,
+ 74,
+ 75,
+ 76,
+ 77,
+ 78,
+ 79,
+ 80,
+ 81,
+ 82,
+ 83,
+ 84,
+ 85,
+ 86,
+ 87,
+ 88,
+ 89,
+ 90,
+ 91,
+ 92,
+ 93,
+ 94,
+ 95,
+ 96,
+ 97,
+ 98,
+ 99,
+ 177,
+ 179,
+ 181,
+ 182,
+ 190,
+ 193,
+ 199,
+ 204,
+ 207,
+ 205,
+ 206,
+ 209,
+ 208,
+ 210,
+ 211,
+ 214,
+ 212,
+ 213,
+ 215,
+ 218,
+ 216,
+ 217,
+ 219,
+ 220,
+ 223,
+ 221,
+ 222,
+ 224,
+ 226,
+ 229,
+ 227,
+ 228,
+ 116,
+ 165,
+ 101,
+ 102,
+ 106,
+ 120,
+ 119,
+ 153,
+ 169,
+ 174,
+ 157,
+ 129,
+ 135,
+ 959,
+ 142,
+ 145,
+ 917,
+ 160,
+ 941,
+ 908,
+ 104,
+ 156,
+ 980,
+ 1018,
+ 987,
+ 985,
+ 918,
+ 143,
+ 147,
+ 471,
+ 148,
+ 151,
+ 127,
+ 100,
+ 155,
+ 994,
+ 105,
+ 815,
+ 412,
+ 110,
+ 124,
+ 125,
+ 2,
+ 178,
+ 180,
+ 195,
+ 146,
+ 152,
+ 115,
+ 141,
+ 109,
+ 123,
+ 69,
+ 12,
+ 163,
+ 948,
+ 231,
+ 202,
+ 103,
+ 107,
+ 111,
+ 112,
+ 113,
+ 114,
+ 117,
+ 118,
+ 121,
+ 122,
+ 126,
+ 176,
+ 183,
+ 175,
+ 184,
+ 185,
+ 186,
+ 187,
+ 188,
+ 189,
+ 191,
+ 192,
+ 3,
+ 194,
+ 197,
+ 198,
+ 200,
+ 149,
+ 130,
+ 131,
+ 132,
+ 133,
+ 134,
+ 136,
+ 137,
+ 138,
+ 139,
+ 140,
+ 144,
+ 150,
+ 196,
+ 225,
+ 203,
+ 232,
+ 164,
+ 158,
+ 171,
+ 201,
+ 230,
+ 161,
+ 166,
+ 170,
+ 172,
+ 154,
+ 168,
+ 173,
+ 159,
+ 162,
+ 167,
+ 899,
+ 429,
+ 901,
+ 444,
+ 526,
+ 1006,
+ 404,
+ 847,
+ 406,
+ 849,
+ 868,
+ 0
+ };
+
+
+
+ static const unsigned short ps_names_to_unicode[1059] =
+ {
+ 0,
+ 0x0020,
+ 0x0021,
+ 0x0022,
+ 0x0023,
+ 0x0024,
+ 0x0025,
+ 0x0026,
+ 0x2019,
+ 0x0028,
+ 0x0029,
+ 0x002A,
+ 0x002B,
+ 0x002C,
+ 0x002D,
+ 0x002E,
+ 0x002F,
+ 0x0030,
+ 0x0031,
+ 0x0032,
+ 0x0033,
+ 0x0034,
+ 0x0035,
+ 0x0036,
+ 0x0037,
+ 0x0038,
+ 0x0039,
+ 0x003A,
+ 0x003B,
+ 0x003C,
+ 0x003D,
+ 0x003E,
+ 0x003F,
+ 0x0040,
+ 0x0041,
+ 0x0042,
+ 0x0043,
+ 0x0044,
+ 0x0045,
+ 0x0046,
+ 0x0047,
+ 0x0048,
+ 0x0049,
+ 0x004A,
+ 0x004B,
+ 0x004C,
+ 0x004D,
+ 0x004E,
+ 0x004F,
+ 0x0050,
+ 0x0051,
+ 0x0052,
+ 0x0053,
+ 0x0054,
+ 0x0055,
+ 0x0056,
+ 0x0057,
+ 0x0058,
+ 0x0059,
+ 0x005A,
+ 0x005B,
+ 0x005C,
+ 0x005D,
+ 0x005E,
+ 0x005F,
+ 0x2018,
+ 0x0061,
+ 0x0062,
+ 0x0063,
+ 0x0064,
+ 0x0065,
+ 0x0066,
+ 0x0067,
+ 0x0068,
+ 0x0069,
+ 0x006A,
+ 0x006B,
+ 0x006C,
+ 0x006D,
+ 0x006E,
+ 0x006F,
+ 0x0070,
+ 0x0071,
+ 0x0072,
+ 0x0073,
+ 0x0074,
+ 0x0075,
+ 0x0076,
+ 0x0077,
+ 0x0078,
+ 0x0079,
+ 0x007A,
+ 0x007B,
+ 0x007C,
+ 0x007D,
+ 0x007E,
+ 0x00A1,
+ 0x00A2,
+ 0x00A3,
+ 0x2044,
+ 0x00A5,
+ 0x0192,
+ 0x00A7,
+ 0x00A4,
+ 0x0027,
+ 0x201C,
+ 0x00AB,
+ 0x2039,
+ 0x203A,
+ 0xFB01,
+ 0xFB02,
+ 0x2013,
+ 0x2020,
+ 0x2021,
+ 0x00B7,
+ 0x00B6,
+ 0x2022,
+ 0x201A,
+ 0x201E,
+ 0x201D,
+ 0x00BB,
+ 0x2026,
+ 0x2030,
+ 0x00BF,
+ 0x0060,
+ 0x00B4,
+ 0x02C6,
+ 0x02DC,
+ 0x00AF,
+ 0x02D8,
+ 0x02D9,
+ 0x00A8,
+ 0x02DA,
+ 0x00B8,
+ 0x02DD,
+ 0x02DB,
+ 0x02C7,
+ 0x2014,
+ 0x00C6,
+ 0x00AA,
+ 0x0141,
+ 0x00D8,
+ 0x0152,
+ 0x00BA,
+ 0x00E6,
+ 0x0131,
+ 0x0142,
+ 0x00F8,
+ 0x0153,
+ 0x00DF,
+ 0x00B9,
+ 0x00AC,
+ 0x00B5,
+ 0x2122,
+ 0x00D0,
+ 0x00BD,
+ 0x00B1,
+ 0x00DE,
+ 0x00BC,
+ 0x00F7,
+ 0x00A6,
+ 0x00B0,
+ 0x00FE,
+ 0x00BE,
+ 0x00B2,
+ 0x00AE,
+ 0x2212,
+ 0x00F0,
+ 0x00D7,
+ 0x00B3,
+ 0x00A9,
+ 0x00C1,
+ 0x00C2,
+ 0x00C4,
+ 0x00C0,
+ 0x00C5,
+ 0x00C3,
+ 0x00C7,
+ 0x00C9,
+ 0x00CA,
+ 0x00CB,
+ 0x00C8,
+ 0x00CD,
+ 0x00CE,
+ 0x00CF,
+ 0x00CC,
+ 0x00D1,
+ 0x00D3,
+ 0x00D4,
+ 0x00D6,
+ 0x00D2,
+ 0x00D5,
+ 0x0160,
+ 0x00DA,
+ 0x00DB,
+ 0x00DC,
+ 0x00D9,
+ 0x00DD,
+ 0x0178,
+ 0x017D,
+ 0x00E1,
+ 0x00E2,
+ 0x00E4,
+ 0x00E0,
+ 0x00E5,
+ 0x00E3,
+ 0x00E7,
+ 0x00E9,
+ 0x00EA,
+ 0x00EB,
+ 0x00E8,
+ 0x00ED,
+ 0x00EE,
+ 0x00EF,
+ 0x00EC,
+ 0x00F1,
+ 0x00F3,
+ 0x00F4,
+ 0x00F6,
+ 0x00F2,
+ 0x00F5,
+ 0x0161,
+ 0x00FA,
+ 0x00FB,
+ 0x00FC,
+ 0x00F9,
+ 0x00FD,
+ 0x00FF,
+ 0x017E,
+ 0xF721,
+ 0xF6F8,
+ 0xF724,
+ 0xF6E4,
+ 0xF726,
+ 0xF7B4,
+ 0x207D,
+ 0x207E,
+ 0x2025,
+ 0x2024,
+ 0xF730,
+ 0xF731,
+ 0xF732,
+ 0xF733,
+ 0xF734,
+ 0xF735,
+ 0xF736,
+ 0xF737,
+ 0xF738,
+ 0xF739,
+ 0xF6E2,
+ 0xF6DE,
+ 0xF6E8,
+ 0xF73F,
+ 0xF6E9,
+ 0xF6EA,
+ 0xF6E0,
+ 0xF6EB,
+ 0xF6EC,
+ 0xF6ED,
+ 0xF6EE,
+ 0xF6EF,
+ 0x207F,
+ 0xF6F0,
+ 0xF6F1,
+ 0xF6F2,
+ 0xF6F3,
+ 0xFB00,
+ 0xFB03,
+ 0xFB04,
+ 0x208D,
+ 0x208E,
+ 0xF6F6,
+ 0xF6E6,
+ 0xF760,
+ 0xF761,
+ 0xF762,
+ 0xF763,
+ 0xF764,
+ 0xF765,
+ 0xF766,
+ 0xF767,
+ 0xF768,
+ 0xF769,
+ 0xF76A,
+ 0xF76B,
+ 0xF76C,
+ 0xF76D,
+ 0xF76E,
+ 0xF76F,
+ 0xF770,
+ 0xF771,
+ 0xF772,
+ 0xF773,
+ 0xF774,
+ 0xF775,
+ 0xF776,
+ 0xF777,
+ 0xF778,
+ 0xF779,
+ 0xF77A,
+ 0x20A1,
+ 0xF6DC,
+ 0xF6DD,
+ 0xF6FE,
+ 0xF7A1,
+ 0xF7A2,
+ 0xF6F9,
+ 0xF6FD,
+ 0xF6FF,
+ 0xF7A8,
+ 0xF6F4,
+ 0xF6F5,
+ 0xF6F7,
+ 0xF7AF,
+ 0x2012,
+ 0xF6E5,
+ 0xF6FB,
+ 0xF6FC,
+ 0xF7B8,
+ 0xF7BF,
+ 0x215B,
+ 0x215C,
+ 0x215D,
+ 0x215E,
+ 0x2153,
+ 0x2154,
+ 0x2070,
+ 0x2074,
+ 0x2075,
+ 0x2076,
+ 0x2077,
+ 0x2078,
+ 0x2079,
+ 0x2080,
+ 0x2081,
+ 0x2082,
+ 0x2083,
+ 0x2084,
+ 0x2085,
+ 0x2086,
+ 0x2087,
+ 0x2088,
+ 0x2089,
+ 0xF6DF,
+ 0xF6E3,
+ 0xF6E7,
+ 0xF6E1,
+ 0xF7E0,
+ 0xF7E1,
+ 0xF7E2,
+ 0xF7E3,
+ 0xF7E4,
+ 0xF7E5,
+ 0xF7E6,
+ 0xF7E7,
+ 0xF7E8,
+ 0xF7E9,
+ 0xF7EA,
+ 0xF7EB,
+ 0xF7EC,
+ 0xF7ED,
+ 0xF7EE,
+ 0xF7EF,
+ 0xF7F0,
+ 0xF7F1,
+ 0xF7F2,
+ 0xF7F3,
+ 0xF7F4,
+ 0xF7F5,
+ 0xF7F6,
+ 0xF6FA,
+ 0xF7F8,
+ 0xF7F9,
+ 0xF7FA,
+ 0xF7FB,
+ 0xF7FC,
+ 0xF7FD,
+ 0xF7FE,
+ 0xF7FF,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+
+#ifdef FT_CONFIG_OPTION_ADOBE_GLYPH_LIST
+
+ 0x01FC,
+ 0x0102,
+ 0xF6C9,
+ 0x0391,
+ 0x0386,
+ 0x0100,
+ 0x0104,
+ 0x01FA,
+ 0x0392,
+ 0x0106,
+ 0xF6CA,
+ 0x010C,
+ 0x0108,
+ 0x010A,
+ 0x03A7,
+ 0x010E,
+ 0x0110,
+ 0x2206,
+ 0x2206,
+ 0xF6CB,
+ 0xF6CC,
+ 0xF6CD,
+ 0x0114,
+ 0x011A,
+ 0x0116,
+ 0x0112,
+ 0x014A,
+ 0x0118,
+ 0x0395,
+ 0x0388,
+ 0x0397,
+ 0x0389,
+ 0x20AC,
+ 0x0393,
+ 0x011E,
+ 0x01E6,
+ 0x011C,
+ 0x0122,
+ 0x0120,
+ 0xF6CE,
+ 0x25CF,
+ 0x25AA,
+ 0x25AB,
+ 0x25A1,
+ 0x0126,
+ 0x0124,
+ 0xF6CF,
+ 0x0132,
+ 0x012C,
+ 0x0130,
+ 0x2111,
+ 0x012A,
+ 0x012E,
+ 0x0399,
+ 0x03AA,
+ 0x038A,
+ 0x0128,
+ 0x0134,
+ 0x039A,
+ 0x0136,
+ 0xF6BF,
+ 0x0139,
+ 0x039B,
+ 0x013D,
+ 0x013B,
+ 0x013F,
+ 0xF6D0,
+ 0x039C,
+ 0x0143,
+ 0x0147,
+ 0x0145,
+ 0x039D,
+ 0x014E,
+ 0x01A0,
+ 0x0150,
+ 0x014C,
+ 0x2126,
+ 0x2126,
+ 0x038F,
+ 0x039F,
+ 0x038C,
+ 0x01FE,
+ 0x03A6,
+ 0x03A0,
+ 0x03A8,
+ 0x0154,
+ 0x0158,
+ 0x0156,
+ 0x211C,
+ 0x03A1,
+ 0x250C,
+ 0x2514,
+ 0x2510,
+ 0x2518,
+ 0x253C,
+ 0x252C,
+ 0x2534,
+ 0x251C,
+ 0x2524,
+ 0x2500,
+ 0x2502,
+ 0x2561,
+ 0x2562,
+ 0x2556,
+ 0x2555,
+ 0x2563,
+ 0x2551,
+ 0x2557,
+ 0x255D,
+ 0x255C,
+ 0x255B,
+ 0x255E,
+ 0x255F,
+ 0x255A,
+ 0x2554,
+ 0x2569,
+ 0x2566,
+ 0x2560,
+ 0x2550,
+ 0x256C,
+ 0x2567,
+ 0x2568,
+ 0x2564,
+ 0x2565,
+ 0x2559,
+ 0x2558,
+ 0x2552,
+ 0x2553,
+ 0x256B,
+ 0x256A,
+ 0x015A,
+ 0x015E,
+ 0x015E,
+ 0x015C,
+ 0x0218,
+ 0x03A3,
+ 0x03A4,
+ 0x0166,
+ 0x0164,
+ 0x0162,
+ 0x0162,
+ 0x0398,
+ 0x016C,
+ 0x01AF,
+ 0x0170,
+ 0x016A,
+ 0x0172,
+ 0x03A5,
+ 0x03D2,
+ 0x03AB,
+ 0x038E,
+ 0x016E,
+ 0x0168,
+ 0x1E82,
+ 0x0174,
+ 0x1E84,
+ 0x1E80,
+ 0x039E,
+ 0x0176,
+ 0x1EF2,
+ 0x0179,
+ 0x017B,
+ 0x0396,
+ 0x0103,
+ 0x0301,
+ 0x01FD,
+ 0x2015,
+ 0x0410,
+ 0x0411,
+ 0x0412,
+ 0x0413,
+ 0x0414,
+ 0x0415,
+ 0x0401,
+ 0x0416,
+ 0x0417,
+ 0x0418,
+ 0x0419,
+ 0x041A,
+ 0x041B,
+ 0x041C,
+ 0x041D,
+ 0x041E,
+ 0x041F,
+ 0x0420,
+ 0x0421,
+ 0x0422,
+ 0x0423,
+ 0x0424,
+ 0x0425,
+ 0x0426,
+ 0x0427,
+ 0x0428,
+ 0x0429,
+ 0x042A,
+ 0x042B,
+ 0x042C,
+ 0x042D,
+ 0x042E,
+ 0x042F,
+ 0x0490,
+ 0x0402,
+ 0x0403,
+ 0x0404,
+ 0x0405,
+ 0x0406,
+ 0x0407,
+ 0x0408,
+ 0x0409,
+ 0x040A,
+ 0x040B,
+ 0x040C,
+ 0x040E,
+ 0xF6C4,
+ 0xF6C5,
+ 0x0430,
+ 0x0431,
+ 0x0432,
+ 0x0433,
+ 0x0434,
+ 0x0435,
+ 0x0451,
+ 0x0436,
+ 0x0437,
+ 0x0438,
+ 0x0439,
+ 0x043A,
+ 0x043B,
+ 0x043C,
+ 0x043D,
+ 0x043E,
+ 0x043F,
+ 0x0440,
+ 0x0441,
+ 0x0442,
+ 0x0443,
+ 0x0444,
+ 0x0445,
+ 0x0446,
+ 0x0447,
+ 0x0448,
+ 0x0449,
+ 0x044A,
+ 0x044B,
+ 0x044C,
+ 0x044D,
+ 0x044E,
+ 0x044F,
+ 0x0491,
+ 0x0452,
+ 0x0453,
+ 0x0454,
+ 0x0455,
+ 0x0456,
+ 0x0457,
+ 0x0458,
+ 0x0459,
+ 0x045A,
+ 0x045B,
+ 0x045C,
+ 0x045E,
+ 0x040F,
+ 0x0462,
+ 0x0472,
+ 0x0474,
+ 0xF6C6,
+ 0x045F,
+ 0x0463,
+ 0x0473,
+ 0x0475,
+ 0xF6C7,
+ 0xF6C8,
+ 0x04D9,
+ 0x200E,
+ 0x200F,
+ 0x200D,
+ 0x066A,
+ 0x060C,
+ 0x0660,
+ 0x0661,
+ 0x0662,
+ 0x0663,
+ 0x0664,
+ 0x0665,
+ 0x0666,
+ 0x0667,
+ 0x0668,
+ 0x0669,
+ 0x061B,
+ 0x061F,
+ 0x0621,
+ 0x0622,
+ 0x0623,
+ 0x0624,
+ 0x0625,
+ 0x0626,
+ 0x0627,
+ 0x0628,
+ 0x0629,
+ 0x062A,
+ 0x062B,
+ 0x062C,
+ 0x062D,
+ 0x062E,
+ 0x062F,
+ 0x0630,
+ 0x0631,
+ 0x0632,
+ 0x0633,
+ 0x0634,
+ 0x0635,
+ 0x0636,
+ 0x0637,
+ 0x0638,
+ 0x0639,
+ 0x063A,
+ 0x0640,
+ 0x0641,
+ 0x0642,
+ 0x0643,
+ 0x0644,
+ 0x0645,
+ 0x0646,
+ 0x0648,
+ 0x0649,
+ 0x064A,
+ 0x064B,
+ 0x064C,
+ 0x064D,
+ 0x064E,
+ 0x064F,
+ 0x0650,
+ 0x0651,
+ 0x0652,
+ 0x0647,
+ 0x06A4,
+ 0x067E,
+ 0x0686,
+ 0x0698,
+ 0x06AF,
+ 0x0679,
+ 0x0688,
+ 0x0691,
+ 0x06BA,
+ 0x06D2,
+ 0x06D5,
+ 0x20AA,
+ 0x05BE,
+ 0x05C3,
+ 0x05D0,
+ 0x05D1,
+ 0x05D2,
+ 0x05D3,
+ 0x05D4,
+ 0x05D5,
+ 0x05D6,
+ 0x05D7,
+ 0x05D8,
+ 0x05D9,
+ 0x05DA,
+ 0x05DB,
+ 0x05DC,
+ 0x05DD,
+ 0x05DE,
+ 0x05DF,
+ 0x05E0,
+ 0x05E1,
+ 0x05E2,
+ 0x05E3,
+ 0x05E4,
+ 0x05E5,
+ 0x05E6,
+ 0x05E7,
+ 0x05E8,
+ 0x05E9,
+ 0x05EA,
+ 0xFB2A,
+ 0xFB2B,
+ 0xFB4B,
+ 0xFB1F,
+ 0x05F0,
+ 0x05F1,
+ 0x05F2,
+ 0xFB35,
+ 0x05B4,
+ 0x05B5,
+ 0x05B6,
+ 0x05BB,
+ 0x05B8,
+ 0x05B7,
+ 0x05B0,
+ 0x05B2,
+ 0x05B1,
+ 0x05B3,
+ 0x05C2,
+ 0x05C1,
+ 0x05B9,
+ 0x05BC,
+ 0x05BD,
+ 0x05BF,
+ 0x05C0,
+ 0x02BC,
+ 0x2105,
+ 0x2113,
+ 0x2116,
+ 0x202C,
+ 0x202D,
+ 0x202E,
+ 0x200C,
+ 0x066D,
+ 0x02BD,
+ 0x2135,
+ 0x03B1,
+ 0x03AC,
+ 0x0101,
+ 0x2220,
+ 0x2329,
+ 0x232A,
+ 0x0387,
+ 0x0105,
+ 0x2248,
+ 0x01FB,
+ 0x2194,
+ 0x21D4,
+ 0x21D3,
+ 0x21D0,
+ 0x21D2,
+ 0x21D1,
+ 0x2193,
+ 0xF8E7,
+ 0x2190,
+ 0x2192,
+ 0x2191,
+ 0x2195,
+ 0x21A8,
+ 0xF8E6,
+ 0x2217,
+ 0x03B2,
+ 0x2588,
+ 0xF8F4,
+ 0xF8F3,
+ 0xF8F2,
+ 0xF8F1,
+ 0xF8FE,
+ 0xF8FD,
+ 0xF8FC,
+ 0xF8F0,
+ 0xF8EF,
+ 0xF8EE,
+ 0xF8FB,
+ 0xF8FA,
+ 0xF8F9,
+ 0x0107,
+ 0x21B5,
+ 0x010D,
+ 0x0109,
+ 0x010B,
+ 0x03C7,
+ 0x25CB,
+ 0x2297,
+ 0x2295,
+ 0x2663,
+ 0xF6C3,
+ 0x2245,
+ 0xF8E9,
+ 0xF6D9,
+ 0xF6D1,
+ 0xF6D2,
+ 0xF6D4,
+ 0xF6D5,
+ 0xF6D3,
+ 0xF6D6,
+ 0x010F,
+ 0x0111,
+ 0x03B4,
+ 0x2666,
+ 0xF6D7,
+ 0xF6D8,
+ 0x0385,
+ 0x2593,
+ 0x2584,
+ 0x20AB,
+ 0x0323,
+ 0xF6BE,
+ 0x22C5,
+ 0x0115,
+ 0x011B,
+ 0x0117,
+ 0x2208,
+ 0x0113,
+ 0x2205,
+ 0x014B,
+ 0x0119,
+ 0x03B5,
+ 0x03AD,
+ 0x2261,
+ 0x212E,
+ 0x03B7,
+ 0x03AE,
+ 0x203C,
+ 0x2203,
+ 0x2640,
+ 0x25A0,
+ 0x25AC,
+ 0x20A3,
+ 0x03B3,
+ 0x011F,
+ 0x01E7,
+ 0x011D,
+ 0x0123,
+ 0x0121,
+ 0x2207,
+ 0x0300,
+ 0x2265,
+ 0x0127,
+ 0x0125,
+ 0x2665,
+ 0x0309,
+ 0x2302,
+ 0x012D,
+ 0x0133,
+ 0x012B,
+ 0x221E,
+ 0x222B,
+ 0x2321,
+ 0xF8F5,
+ 0x2320,
+ 0x2229,
+ 0x25D8,
+ 0x25D9,
+ 0x263B,
+ 0x012F,
+ 0x03B9,
+ 0x03CA,
+ 0x0390,
+ 0x03AF,
+ 0x0129,
+ 0x0135,
+ 0x03BA,
+ 0x0137,
+ 0x0138,
+ 0x013A,
+ 0x03BB,
+ 0x013E,
+ 0x013C,
+ 0x0140,
+ 0x2264,
+ 0x258C,
+ 0x20A4,
+ 0xF6C0,
+ 0x2227,
+ 0x2228,
+ 0x017F,
+ 0x25CA,
+ 0x2591,
+ 0x2642,
+ 0x2032,
+ 0x266A,
+ 0x266B,
+ 0x0144,
+ 0x0149,
+ 0x0148,
+ 0x0146,
+ 0x2209,
+ 0x2260,
+ 0x2284,
+ 0x03BD,
+ 0x014F,
+ 0x01A1,
+ 0x0151,
+ 0x014D,
+ 0x03C9,
+ 0x03D6,
+ 0x03CE,
+ 0x03BF,
+ 0x03CC,
+ 0x25E6,
+ 0x221F,
+ 0x01FF,
+ 0xF8ED,
+ 0xF8EC,
+ 0xF8EB,
+ 0xF8F8,
+ 0xF8F7,
+ 0xF8F6,
+ 0x2202,
+ 0x22A5,
+ 0x20A7,
+ 0x03C6,
+ 0x03D5,
+ 0x03C0,
+ 0x211E,
+ 0x220F,
+ 0x2282,
+ 0x2283,
+ 0x221D,
+ 0x03C8,
+ 0x201B,
+ 0x0155,
+ 0x221A,
+ 0xF8E5,
+ 0x0159,
+ 0x0157,
+ 0x2286,
+ 0x2287,
+ 0xF8E8,
+ 0xF6DA,
+ 0x2310,
+ 0x03C1,
+ 0x2590,
+ 0x015B,
+ 0x015F,
+ 0x015F,
+ 0x015D,
+ 0x0219,
+ 0x2033,
+ 0x2592,
+ 0x03C3,
+ 0x03C2,
+ 0x223C,
+ 0x263A,
+ 0x2660,
+ 0x220B,
+ 0x2211,
+ 0x263C,
+ 0x03C4,
+ 0x0167,
+ 0x0165,
+ 0x0163,
+ 0x0163,
+ 0x2234,
+ 0x03B8,
+ 0x03D1,
+ 0x0303,
+ 0x0384,
+ 0xF8EA,
+ 0xF6DB,
+ 0x25BC,
+ 0x25C4,
+ 0x25BA,
+ 0x25B2,
+ 0x016D,
+ 0x01B0,
+ 0x0171,
+ 0x016B,
+ 0x2017,
+ 0x222A,
+ 0x2200,
+ 0x0173,
+ 0x2580,
+ 0x03C5,
+ 0x03CB,
+ 0x03B0,
+ 0x03CD,
+ 0x016F,
+ 0x0169,
+ 0x1E83,
+ 0x0175,
+ 0x1E85,
+ 0x2118,
+ 0x1E81,
+ 0x03BE,
+ 0x0177,
+ 0x1EF3,
+ 0x017A,
+ 0x017C,
+ 0x03B6,
+
+#endif /* FT_CONFIG_OPTION_ADOBE_GLYPH_LIST */
+ 0
+ };
+
+
+
+ static const unsigned short t1_standard_encoding[257] =
+ {
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 1,
+ 2,
+ 3,
+ 4,
+ 5,
+ 6,
+ 7,
+ 8,
+ 9,
+ 10,
+ 11,
+ 12,
+ 13,
+ 14,
+ 15,
+ 16,
+ 17,
+ 18,
+ 19,
+ 20,
+ 21,
+ 22,
+ 23,
+ 24,
+ 25,
+ 26,
+ 27,
+ 28,
+ 29,
+ 30,
+ 31,
+ 32,
+ 33,
+ 34,
+ 35,
+ 36,
+ 37,
+ 38,
+ 39,
+ 40,
+ 41,
+ 42,
+ 43,
+ 44,
+ 45,
+ 46,
+ 47,
+ 48,
+ 49,
+ 50,
+ 51,
+ 52,
+ 53,
+ 54,
+ 55,
+ 56,
+ 57,
+ 58,
+ 59,
+ 60,
+ 61,
+ 62,
+ 63,
+ 64,
+ 65,
+ 66,
+ 67,
+ 68,
+ 69,
+ 70,
+ 71,
+ 72,
+ 73,
+ 74,
+ 75,
+ 76,
+ 77,
+ 78,
+ 79,
+ 80,
+ 81,
+ 82,
+ 83,
+ 84,
+ 85,
+ 86,
+ 87,
+ 88,
+ 89,
+ 90,
+ 91,
+ 92,
+ 93,
+ 94,
+ 95,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 96,
+ 97,
+ 98,
+ 99,
+ 100,
+ 101,
+ 102,
+ 103,
+ 104,
+ 105,
+ 106,
+ 107,
+ 108,
+ 109,
+ 110,
+ 0,
+ 111,
+ 112,
+ 113,
+ 114,
+ 0,
+ 115,
+ 116,
+ 117,
+ 118,
+ 119,
+ 120,
+ 121,
+ 122,
+ 0,
+ 123,
+ 0,
+ 124,
+ 125,
+ 126,
+ 127,
+ 128,
+ 129,
+ 130,
+ 131,
+ 0,
+ 132,
+ 133,
+ 0,
+ 134,
+ 135,
+ 136,
+ 137,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 138,
+ 0,
+ 139,
+ 0,
+ 0,
+ 0,
+ 0,
+ 140,
+ 141,
+ 142,
+ 143,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 144,
+ 0,
+ 0,
+ 0,
+ 145,
+ 0,
+ 0,
+ 146,
+ 147,
+ 148,
+ 149,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0
+ };
+
+
+ static const unsigned short t1_expert_encoding[257] =
+ {
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 1,
+ 229,
+ 230,
+ 0,
+ 231,
+ 232,
+ 233,
+ 234,
+ 235,
+ 236,
+ 237,
+ 238,
+ 13,
+ 14,
+ 15,
+ 99,
+ 239,
+ 240,
+ 241,
+ 242,
+ 243,
+ 244,
+ 245,
+ 246,
+ 247,
+ 248,
+ 27,
+ 28,
+ 249,
+ 250,
+ 251,
+ 252,
+ 0,
+ 253,
+ 254,
+ 255,
+ 256,
+ 257,
+ 0,
+ 0,
+ 0,
+ 258,
+ 0,
+ 0,
+ 259,
+ 260,
+ 261,
+ 262,
+ 0,
+ 0,
+ 263,
+ 264,
+ 265,
+ 0,
+ 266,
+ 109,
+ 110,
+ 267,
+ 268,
+ 269,
+ 0,
+ 270,
+ 271,
+ 272,
+ 273,
+ 274,
+ 275,
+ 276,
+ 277,
+ 278,
+ 279,
+ 280,
+ 281,
+ 282,
+ 283,
+ 284,
+ 285,
+ 286,
+ 287,
+ 288,
+ 289,
+ 290,
+ 291,
+ 292,
+ 293,
+ 294,
+ 295,
+ 296,
+ 297,
+ 298,
+ 299,
+ 300,
+ 301,
+ 302,
+ 303,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 304,
+ 305,
+ 306,
+ 0,
+ 0,
+ 307,
+ 308,
+ 309,
+ 310,
+ 311,
+ 0,
+ 312,
+ 0,
+ 0,
+ 313,
+ 0,
+ 0,
+ 314,
+ 315,
+ 0,
+ 0,
+ 316,
+ 317,
+ 318,
+ 0,
+ 0,
+ 0,
+ 158,
+ 155,
+ 163,
+ 319,
+ 320,
+ 321,
+ 322,
+ 323,
+ 324,
+ 325,
+ 0,
+ 0,
+ 326,
+ 150,
+ 164,
+ 169,
+ 327,
+ 328,
+ 329,
+ 330,
+ 331,
+ 332,
+ 333,
+ 334,
+ 335,
+ 336,
+ 337,
+ 338,
+ 339,
+ 340,
+ 341,
+ 342,
+ 343,
+ 344,
+ 345,
+ 346,
+ 347,
+ 348,
+ 349,
+ 350,
+ 351,
+ 352,
+ 353,
+ 354,
+ 355,
+ 356,
+ 357,
+ 358,
+ 359,
+ 360,
+ 361,
+ 362,
+ 363,
+ 364,
+ 365,
+ 366,
+ 367,
+ 368,
+ 369,
+ 370,
+ 371,
+ 372,
+ 373,
+ 374,
+ 375,
+ 376,
+ 377,
+ 378,
+ 0
+ };
+
+
+/* END */
--- /dev/null
+++ b/libfreetype/raster.c
@@ -1,0 +1,26 @@
+/***************************************************************************/
+/* */
+/* raster.c */
+/* */
+/* FreeType monochrome rasterer module component (body only). */
+/* */
+/* Copyright 1996-2001 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+
+#define FT_MAKE_OPTION_SINGLE_OBJECT
+
+#include <ft2build.h>
+#include "ftraster.c"
+#include "ftrend1.c"
+
+
+/* END */
--- /dev/null
+++ b/libfreetype/rasterrs.h
@@ -1,0 +1,41 @@
+/***************************************************************************/
+/* */
+/* rasterrs.h */
+/* */
+/* monochrome renderer error codes (specification only). */
+/* */
+/* Copyright 2001 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+
+ /*************************************************************************/
+ /* */
+ /* This file is used to define the monochrome renderer error enumeration */
+ /* constants. */
+ /* */
+ /*************************************************************************/
+
+#ifndef __RASTERRS_H__
+#define __RASTERRS_H__
+
+#include FT_MODULE_ERRORS_H
+
+#undef __FTERRORS_H__
+
+#define FT_ERR_PREFIX Raster_Err_
+#define FT_ERR_BASE FT_Mod_Err_Raster
+
+#include FT_ERRORS_H
+
+#endif /* __RASTERRS_H__ */
+
+
+/* END */
--- /dev/null
+++ b/libfreetype/sfdriver.c
@@ -1,0 +1,332 @@
+/***************************************************************************/
+/* */
+/* sfdriver.c */
+/* */
+/* High-level SFNT driver interface (body). */
+/* */
+/* Copyright 1996-2001, 2002 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+
+#include <ft2build.h>
+#include FT_INTERNAL_SFNT_H
+#include FT_INTERNAL_OBJECTS_H
+
+#include "sfdriver.h"
+#include "ttload.h"
+#include "ttcmap.h"
+#include "sfobjs.h"
+
+#ifdef TT_CONFIG_OPTION_EMBEDDED_BITMAPS
+#include "ttsbit.h"
+#endif
+
+#ifdef TT_CONFIG_OPTION_POSTSCRIPT_NAMES
+#include "ttpost.h"
+#endif
+
+
+ static void*
+ get_sfnt_table( TT_Face face,
+ FT_Sfnt_Tag tag )
+ {
+ void* table;
+
+
+ switch ( tag )
+ {
+ case ft_sfnt_head:
+ table = &face->header;
+ break;
+
+ case ft_sfnt_hhea:
+ table = &face->horizontal;
+ break;
+
+ case ft_sfnt_vhea:
+ table = face->vertical_info ? &face->vertical : 0;
+ break;
+
+ case ft_sfnt_os2:
+ table = face->os2.version == 0xFFFFU ? 0 : &face->os2;
+ break;
+
+ case ft_sfnt_post:
+ table = &face->postscript;
+ break;
+
+ case ft_sfnt_maxp:
+ table = &face->max_profile;
+ break;
+
+ case ft_sfnt_pclt:
+ table = face->pclt.Version ? &face->pclt : 0;
+ break;
+
+ default:
+ table = 0;
+ }
+
+ return table;
+ }
+
+
+#ifdef TT_CONFIG_OPTION_POSTSCRIPT_NAMES
+
+
+ static FT_Error
+ get_sfnt_glyph_name( TT_Face face,
+ FT_UInt glyph_index,
+ FT_Pointer buffer,
+ FT_UInt buffer_max )
+ {
+ FT_String* gname;
+ FT_Error error;
+
+
+ error = tt_face_get_ps_name( face, glyph_index, &gname );
+ if ( !error && buffer_max > 0 )
+ {
+ FT_UInt len = (FT_UInt)( ft_strlen( gname ) );
+
+
+ if ( len >= buffer_max )
+ len = buffer_max - 1;
+
+ FT_MEM_COPY( buffer, gname, len );
+ ((FT_Byte*)buffer)[len] = 0;
+ }
+
+ return error;
+ }
+
+
+ static const char*
+ get_sfnt_postscript_name( TT_Face face )
+ {
+ FT_Int n, found_win, found_apple;
+ const char* result = NULL;
+
+
+ /* shouldn't happen, but just in case to avoid memory leaks */
+ if ( face->root.internal->postscript_name )
+ return face->root.internal->postscript_name;
+
+ /* scan the name table to see whether we have a Postscript name here, */
+ /* either in Macintosh or Windows platform encodings */
+ found_win = -1;
+ found_apple = -1;
+
+ for ( n = 0; n < face->num_names; n++ )
+ {
+ TT_NameEntryRec* name = face->name_table.names + n;
+
+
+ if ( name->nameID == 6 && name->stringLength > 0 )
+ {
+ if ( name->platformID == 3 &&
+ name->encodingID == 1 &&
+ name->languageID == 0x409 )
+ found_win = n;
+
+ if ( name->platformID == 1 &&
+ name->encodingID == 0 &&
+ name->languageID == 0 )
+ found_apple = n;
+ }
+ }
+
+ if ( found_win != -1 )
+ {
+ FT_Memory memory = face->root.memory;
+ TT_NameEntryRec* name = face->name_table.names + found_win;
+ FT_UInt len = name->stringLength / 2;
+ FT_Error error;
+
+
+ if ( !FT_ALLOC( result, name->stringLength + 1 ) )
+ {
+ FT_Stream stream = face->name_table.stream;
+ FT_String* r = (FT_String*)result;
+ FT_Byte* p = (FT_Byte*)name->string;
+
+
+ if ( FT_STREAM_SEEK( name->stringOffset ) ||
+ FT_FRAME_ENTER( name->stringLength ) )
+ {
+ FT_FREE( result );
+ name->stringLength = 0;
+ name->stringOffset = 0;
+ FT_FREE( name->string );
+
+ goto Exit;
+ }
+
+ p = (FT_Byte*)stream->cursor;
+
+ for ( ; len > 0; len--, p += 2 )
+ {
+ if ( p[0] == 0 && p[1] >= 32 && p[1] < 128 )
+ *r++ = p[1];
+ }
+ *r = '\0';
+
+ FT_FRAME_EXIT();
+ }
+ goto Exit;
+ }
+
+ if ( found_apple != -1 )
+ {
+ FT_Memory memory = face->root.memory;
+ TT_NameEntryRec* name = face->name_table.names + found_apple;
+ FT_UInt len = name->stringLength;
+ FT_Error error;
+
+
+ if ( !FT_ALLOC( result, len + 1 ) )
+ {
+ FT_Stream stream = face->name_table.stream;
+
+
+ if ( FT_STREAM_SEEK( name->stringOffset ) ||
+ FT_STREAM_READ( result, len ) )
+ {
+ name->stringOffset = 0;
+ name->stringLength = 0;
+ FT_FREE( name->string );
+ FT_FREE( result );
+ goto Exit;
+ }
+ ((char*)result)[len] = '\0';
+ }
+ }
+
+ Exit:
+ face->root.internal->postscript_name = result;
+ return result;
+ }
+
+
+#endif /* TT_CONFIG_OPTION_POSTSCRIPT_NAMES */
+
+
+ FT_CALLBACK_DEF( FT_Module_Interface )
+ sfnt_get_interface( FT_Module module,
+ const char* module_interface )
+ {
+ FT_UNUSED( module );
+
+ if ( ft_strcmp( module_interface, "get_sfnt" ) == 0 )
+ return (FT_Module_Interface)get_sfnt_table;
+
+#ifdef TT_CONFIG_OPTION_POSTSCRIPT_NAMES
+ if ( ft_strcmp( module_interface, "glyph_name" ) == 0 )
+ return (FT_Module_Interface)get_sfnt_glyph_name;
+#endif
+
+ if ( ft_strcmp( module_interface, "postscript_name" ) == 0 )
+ return (FT_Module_Interface)get_sfnt_postscript_name;
+
+ return 0;
+ }
+
+
+ static
+ const SFNT_Interface sfnt_interface =
+ {
+ tt_face_goto_table,
+
+ sfnt_init_face,
+ sfnt_load_face,
+ sfnt_done_face,
+ sfnt_get_interface,
+
+ tt_face_load_any,
+ tt_face_load_sfnt_header,
+ tt_face_load_directory,
+
+ tt_face_load_header,
+ tt_face_load_metrics_header,
+ tt_face_load_cmap,
+ tt_face_load_max_profile,
+ tt_face_load_os2,
+ tt_face_load_postscript,
+
+ tt_face_load_names,
+ tt_face_free_names,
+
+ tt_face_load_hdmx,
+ tt_face_free_hdmx,
+
+ tt_face_load_kern,
+ tt_face_load_gasp,
+ tt_face_load_pclt,
+
+#ifdef TT_CONFIG_OPTION_EMBEDDED_BITMAPS
+
+ /* see `ttload.h' */
+ tt_face_load_bitmap_header,
+
+ /* see `ttsbit.h' */
+ tt_face_set_sbit_strike,
+ tt_face_load_sbit_strikes,
+ tt_face_load_sbit_image,
+ tt_face_free_sbit_strikes,
+
+#else /* TT_CONFIG_OPTION_EMBEDDED_BITMAPS */
+
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+
+#endif /* TT_CONFIG_OPTION_EMBEDDED_BITMAPS */
+
+#ifdef TT_CONFIG_OPTION_POSTSCRIPT_NAMES
+
+ /* see `ttpost.h' */
+ tt_face_get_ps_name,
+ tt_face_free_ps_names,
+
+#else /* TT_CONFIG_OPTION_POSTSCRIPT_NAMES */
+
+ 0,
+ 0,
+
+#endif /* TT_CONFIG_OPTION_POSTSCRIPT_NAMES */
+
+ /* see `ttcmap.h' */
+ tt_face_load_charmap,
+ tt_face_free_charmap,
+ };
+
+
+ FT_CALLBACK_TABLE_DEF
+ const FT_Module_Class sfnt_module_class =
+ {
+ 0, /* not a font driver or renderer */
+ sizeof( FT_ModuleRec ),
+
+ "sfnt", /* driver name */
+ 0x10000L, /* driver version 1.0 */
+ 0x20000L, /* driver requires FreeType 2.0 or higher */
+
+ (const void*)&sfnt_interface, /* module specific interface */
+
+ (FT_Module_Constructor)0,
+ (FT_Module_Destructor) 0,
+ (FT_Module_Requester) sfnt_get_interface
+ };
+
+
+/* END */
--- /dev/null
+++ b/libfreetype/sfdriver.h
@@ -1,0 +1,38 @@
+/***************************************************************************/
+/* */
+/* sfdriver.h */
+/* */
+/* High-level SFNT driver interface (specification). */
+/* */
+/* Copyright 1996-2001 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+
+#ifndef __SFDRIVER_H__
+#define __SFDRIVER_H__
+
+
+#include <ft2build.h>
+#include FT_MODULE_H
+
+
+FT_BEGIN_HEADER
+
+
+ FT_EXPORT_VAR( const FT_Module_Class ) sfnt_module_class;
+
+
+FT_END_HEADER
+
+#endif /* __SFDRIVER_H__ */
+
+
+/* END */
--- /dev/null
+++ b/libfreetype/sferrors.h
@@ -1,0 +1,39 @@
+/***************************************************************************/
+/* */
+/* sferrors.h */
+/* */
+/* SFNT error codes (specification only). */
+/* */
+/* Copyright 2001 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+
+ /*************************************************************************/
+ /* */
+ /* This file is used to define the SFNT error enumeration constants. */
+ /* */
+ /*************************************************************************/
+
+#ifndef __SFERRORS_H__
+#define __SFERRORS_H__
+
+#include FT_MODULE_ERRORS_H
+
+#undef __FTERRORS_H__
+
+#define FT_ERR_PREFIX SFNT_Err_
+#define FT_ERR_BASE FT_Mod_Err_SFNT
+
+#include FT_ERRORS_H
+
+#endif /* __SFERRORS_H__ */
+
+/* END */
--- /dev/null
+++ b/libfreetype/sfnt.c
@@ -1,0 +1,37 @@
+/***************************************************************************/
+/* */
+/* sfnt.c */
+/* */
+/* Single object library component. */
+/* */
+/* Copyright 1996-2001, 2002 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+
+#define FT_MAKE_OPTION_SINGLE_OBJECT
+
+#include <ft2build.h>
+#include "ttload.c"
+#include "ttcmap.c"
+#include "ttcmap0.c"
+#include "sfobjs.c"
+#include "sfdriver.c"
+
+#ifdef TT_CONFIG_OPTION_EMBEDDED_BITMAPS
+#include "ttsbit.c"
+#endif
+
+#ifdef TT_CONFIG_OPTION_POSTSCRIPT_NAMES
+#include "ttpost.c"
+#endif
+
+
+/* END */
--- /dev/null
+++ b/libfreetype/sfobjs.c
@@ -1,0 +1,829 @@
+/***************************************************************************/
+/* */
+/* sfobjs.c */
+/* */
+/* SFNT object management (base). */
+/* */
+/* Copyright 1996-2001, 2002 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+
+#include <ft2build.h>
+#include "sfobjs.h"
+#include "ttload.h"
+#include "ttcmap0.h"
+#include FT_INTERNAL_SFNT_H
+#include FT_INTERNAL_POSTSCRIPT_NAMES_H
+#include FT_TRUETYPE_IDS_H
+#include FT_TRUETYPE_TAGS_H
+
+#include "sferrors.h"
+
+
+ /*************************************************************************/
+ /* */
+ /* The macro FT_COMPONENT is used in trace mode. It is an implicit */
+ /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log */
+ /* messages during execution. */
+ /* */
+#undef FT_COMPONENT
+#define FT_COMPONENT trace_sfobjs
+
+
+
+ /* convert a UTF-16 name entry to ASCII */
+ static FT_String*
+ tt_name_entry_ascii_from_utf16( TT_NameEntry entry,
+ FT_Memory memory )
+ {
+ FT_String* string;
+ FT_UInt len, code, n;
+ FT_Byte* read = (FT_Byte*)entry->string;
+
+
+ len = (FT_UInt)entry->stringLength / 2;
+
+ if ( FT_MEM_NEW_ARRAY( string, len + 1 ) )
+ return NULL;
+
+ for ( n = 0; n < len; n++ )
+ {
+ code = FT_NEXT_USHORT( read );
+ if ( code < 32 || code > 127 )
+ code = '?';
+
+ string[n] = (char)code;
+ }
+
+ string[len] = 0;
+
+ return string;
+ }
+
+
+ /* convert a UCS-4 name entry to ASCII */
+ static FT_String*
+ tt_name_entry_ascii_from_ucs4( TT_NameEntry entry,
+ FT_Memory memory )
+ {
+ FT_String* string;
+ FT_UInt len, code, n;
+ FT_Byte* read = (FT_Byte*)entry->string;
+
+
+ len = (FT_UInt)entry->stringLength / 4;
+
+ if ( FT_MEM_NEW_ARRAY( string, len + 1 ) )
+ return NULL;
+
+ for ( n = 0; n < len; n++ )
+ {
+ code = (FT_UInt)FT_NEXT_ULONG( read );
+ if ( code < 32 || code > 127 )
+ code = '?';
+
+ string[n] = (char)code;
+ }
+
+ string[len] = 0;
+
+ return string;
+ }
+
+
+ /* convert an Apple Roman or symbol name entry to ASCII */
+ static FT_String*
+ tt_name_entry_ascii_from_other( TT_NameEntry entry,
+ FT_Memory memory )
+ {
+ FT_String* string;
+ FT_UInt len, code, n;
+ FT_Byte* read = (FT_Byte*)entry->string;
+
+
+ len = (FT_UInt)entry->stringLength;
+
+ if ( FT_MEM_NEW_ARRAY( string, len + 1 ) )
+ return NULL;
+
+ for ( n = 0; n < len; n++ )
+ {
+ code = *read++;
+ if ( code < 32 || code > 127 )
+ code = '?';
+
+ string[n] = (char)code;
+ }
+
+ string[len] = 0;
+
+ return string;
+ }
+
+
+ typedef FT_String* (*TT_NameEntry_ConvertFunc)( TT_NameEntry entry,
+ FT_Memory memory );
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* tt_face_get_name */
+ /* */
+ /* <Description> */
+ /* Returns a given ENGLISH name record in ASCII. */
+ /* */
+ /* <Input> */
+ /* face :: A handle to the source face object. */
+ /* */
+ /* nameid :: The name id of the name record to return. */
+ /* */
+ /* <Return> */
+ /* Character string. NULL if no name is present. */
+ /* */
+ static FT_String*
+ tt_face_get_name( TT_Face face,
+ FT_UShort nameid )
+ {
+ FT_Memory memory = face->root.memory;
+ FT_String* result = NULL;
+ FT_UShort n;
+ TT_NameEntryRec* rec;
+ FT_Int found_apple = -1;
+ FT_Int found_win = -1;
+ FT_Int found_unicode = -1;
+
+ TT_NameEntry_ConvertFunc convert;
+
+
+ rec = face->name_table.names;
+ for ( n = 0; n < face->num_names; n++, rec++ )
+ {
+ /* According to the OpenType 1.3 specification, only Microsoft or */
+ /* Apple platform IDs might be used in the `name' table. The */
+ /* `Unicode' platform is reserved for the `cmap' table, and the */
+ /* `Iso' one is deprecated. */
+ /* */
+ /* However, the Apple TrueType specification doesn't say the same */
+ /* thing and goes to suggest that all Unicode `name' table entries */
+ /* should be coded in UTF-16 (in big-endian format I suppose). */
+ /* */
+ if ( rec->nameID == nameid && rec->stringLength > 0 )
+ {
+ switch ( rec->platformID )
+ {
+ case TT_PLATFORM_APPLE_UNICODE:
+ case TT_PLATFORM_ISO:
+ /* there is `languageID' to check there. We should use this */
+ /* field only as a last solution when nothing else is */
+ /* available. */
+ /* */
+ found_unicode = n;
+ break;
+
+ case TT_PLATFORM_MACINTOSH:
+ if ( rec->languageID == TT_MAC_LANGID_ENGLISH )
+ found_apple = n;
+
+ break;
+
+ case TT_PLATFORM_MICROSOFT:
+ /* we only take a non-English name when there is nothing */
+ /* else available in the font */
+ /* */
+ if ( found_win == -1 || ( rec->languageID & 0x3FF ) == 0x009 )
+ {
+ switch ( rec->encodingID )
+ {
+ case TT_MS_ID_SYMBOL_CS:
+ case TT_MS_ID_UNICODE_CS:
+ case TT_MS_ID_UCS_4:
+ found_win = n;
+ break;
+
+ default:
+ ;
+ }
+ }
+ break;
+
+ default:
+ ;
+ }
+ }
+ }
+
+ /* some fonts contain invalid Unicode or Macintosh formatted entries; */
+ /* we will thus favor names encoded in Windows formats if available */
+ /* */
+ convert = NULL;
+ if ( found_win >= 0 )
+ {
+ rec = face->name_table.names + found_win;
+ switch ( rec->encodingID )
+ {
+ case TT_MS_ID_UNICODE_CS:
+ case TT_MS_ID_SYMBOL_CS:
+ convert = tt_name_entry_ascii_from_utf16;
+ break;
+
+ case TT_MS_ID_UCS_4:
+ convert = tt_name_entry_ascii_from_ucs4;
+ break;
+
+ default:
+ ;
+ }
+ }
+ else if ( found_apple >= 0 )
+ {
+ rec = face->name_table.names + found_apple;
+ convert = tt_name_entry_ascii_from_other;
+ }
+ else if ( found_unicode >= 0 )
+ {
+ rec = face->name_table.names + found_unicode;
+ convert = tt_name_entry_ascii_from_utf16;
+ }
+
+ if ( rec && convert )
+ {
+ if ( rec->string == NULL )
+ {
+ FT_Error error;
+ FT_Stream stream = face->name_table.stream;
+
+
+ if ( FT_NEW_ARRAY ( rec->string, rec->stringLength ) ||
+ FT_STREAM_SEEK( rec->stringOffset ) ||
+ FT_STREAM_READ( rec->string, rec->stringLength ) )
+ {
+ FT_FREE( rec->string );
+ rec->stringLength = 0;
+ result = NULL;
+ goto Exit;
+ }
+ }
+
+ result = convert( rec, memory );
+ }
+
+ Exit:
+ return result;
+ }
+
+
+ static FT_Encoding
+ sfnt_find_encoding( int platform_id,
+ int encoding_id )
+ {
+ typedef struct TEncoding
+ {
+ int platform_id;
+ int encoding_id;
+ FT_Encoding encoding;
+
+ } TEncoding;
+
+ static
+ const TEncoding tt_encodings[] =
+ {
+ { TT_PLATFORM_ISO, -1, FT_ENCODING_UNICODE },
+
+ { TT_PLATFORM_APPLE_UNICODE, -1, FT_ENCODING_UNICODE },
+
+ { TT_PLATFORM_MACINTOSH, TT_MAC_ID_ROMAN, FT_ENCODING_APPLE_ROMAN },
+
+ { TT_PLATFORM_MICROSOFT, TT_MS_ID_SYMBOL_CS, FT_ENCODING_MS_SYMBOL },
+ { TT_PLATFORM_MICROSOFT, TT_MS_ID_UCS_4, FT_ENCODING_UNICODE },
+ { TT_PLATFORM_MICROSOFT, TT_MS_ID_UNICODE_CS, FT_ENCODING_UNICODE },
+ { TT_PLATFORM_MICROSOFT, TT_MS_ID_SJIS, FT_ENCODING_MS_SJIS },
+ { TT_PLATFORM_MICROSOFT, TT_MS_ID_GB2312, FT_ENCODING_MS_GB2312 },
+ { TT_PLATFORM_MICROSOFT, TT_MS_ID_BIG_5, FT_ENCODING_MS_BIG5 },
+ { TT_PLATFORM_MICROSOFT, TT_MS_ID_WANSUNG, FT_ENCODING_MS_WANSUNG },
+ { TT_PLATFORM_MICROSOFT, TT_MS_ID_JOHAB, FT_ENCODING_MS_JOHAB }
+ };
+
+ const TEncoding *cur, *limit;
+
+
+ cur = tt_encodings;
+ limit = cur + sizeof ( tt_encodings ) / sizeof ( tt_encodings[0] );
+
+ for ( ; cur < limit; cur++ )
+ {
+ if ( cur->platform_id == platform_id )
+ {
+ if ( cur->encoding_id == encoding_id ||
+ cur->encoding_id == -1 )
+ return cur->encoding;
+ }
+ }
+
+ return FT_ENCODING_NONE;
+ }
+
+
+ FT_LOCAL_DEF( FT_Error )
+ sfnt_init_face( FT_Stream stream,
+ TT_Face face,
+ FT_Int face_index,
+ FT_Int num_params,
+ FT_Parameter* params )
+ {
+ FT_Error error;
+ FT_Library library = face->root.driver->root.library;
+ SFNT_Service sfnt;
+ SFNT_HeaderRec sfnt_header;
+
+ /* for now, parameters are unused */
+ FT_UNUSED( num_params );
+ FT_UNUSED( params );
+
+
+ sfnt = (SFNT_Service)face->sfnt;
+ if ( !sfnt )
+ {
+ sfnt = (SFNT_Service)FT_Get_Module_Interface( library, "sfnt" );
+ if ( !sfnt )
+ {
+ error = SFNT_Err_Invalid_File_Format;
+ goto Exit;
+ }
+
+ face->sfnt = sfnt;
+ face->goto_table = sfnt->goto_table;
+ }
+
+ if ( !face->psnames )
+ {
+ face->psnames = (PSNames_Service)
+ FT_Get_Module_Interface( library, "psnames" );
+ }
+
+ /* check that we have a valid TrueType file */
+ error = sfnt->load_sfnt_header( face, stream, face_index, &sfnt_header );
+ if ( error )
+ goto Exit;
+
+ face->format_tag = sfnt_header.format_tag;
+ face->num_tables = sfnt_header.num_tables;
+
+ /* Load font directory */
+ error = sfnt->load_directory( face, stream, &sfnt_header );
+ if ( error )
+ goto Exit;
+
+ face->root.num_faces = face->ttc_header.count;
+ if ( face->root.num_faces < 1 )
+ face->root.num_faces = 1;
+
+ Exit:
+ return error;
+ }
+
+
+#undef LOAD_
+#define LOAD_( x ) ( ( error = sfnt->load_##x( face, stream ) ) \
+ != SFNT_Err_Ok )
+
+
+ FT_LOCAL_DEF( FT_Error )
+ sfnt_load_face( FT_Stream stream,
+ TT_Face face,
+ FT_Int face_index,
+ FT_Int num_params,
+ FT_Parameter* params )
+ {
+ FT_Error error;
+ FT_Bool has_outline;
+ FT_Bool is_apple_sbit;
+
+ SFNT_Service sfnt = (SFNT_Service)face->sfnt;
+
+ FT_UNUSED( face_index );
+ FT_UNUSED( num_params );
+ FT_UNUSED( params );
+
+
+ /* Load tables */
+
+ /* We now support two SFNT-based bitmapped font formats. They */
+ /* are recognized easily as they do not include a `glyf' */
+ /* table. */
+ /* */
+ /* The first format comes from Apple, and uses a table named */
+ /* `bhed' instead of `head' to store the font header (using */
+ /* the same format). It also doesn't include horizontal and */
+ /* vertical metrics tables (i.e. `hhea' and `vhea' tables are */
+ /* missing). */
+ /* */
+ /* The other format comes from Microsoft, and is used with */
+ /* WinCE/PocketPC. It looks like a standard TTF, except that */
+ /* it doesn't contain outlines. */
+ /* */
+
+ /* do we have outlines in there? */
+#ifdef FT_CONFIG_OPTION_INCREMENTAL
+ has_outline = FT_BOOL( face->root.internal->incremental_interface != 0 ||
+ tt_face_lookup_table( face, TTAG_glyf ) != 0 ||
+ tt_face_lookup_table( face, TTAG_CFF ) != 0 );
+#else
+ has_outline = FT_BOOL( tt_face_lookup_table( face, TTAG_glyf ) != 0 ||
+ tt_face_lookup_table( face, TTAG_CFF ) != 0 );
+#endif
+
+ is_apple_sbit = 0;
+
+#ifdef TT_CONFIG_OPTION_EMBEDDED_BITMAPS
+
+ /* if this font doesn't contain outlines, we try to load */
+ /* a `bhed' table */
+ if ( !has_outline )
+ is_apple_sbit = FT_BOOL( !LOAD_( bitmap_header ) );
+
+#endif /* TT_CONFIG_OPTION_EMBEDDED_BITMAPS */
+
+ /* load the font header (`head' table) if this isn't an Apple */
+ /* sbit font file */
+ if ( !is_apple_sbit && LOAD_( header ) )
+ goto Exit;
+
+ /* the following tables are often not present in embedded TrueType */
+ /* fonts within PDF documents, so don't check for them. */
+ (void)LOAD_( max_profile );
+ (void)LOAD_( charmaps );
+
+ /* the following tables are optional in PCL fonts -- */
+ /* don't check for errors */
+ (void)LOAD_( names );
+ (void)LOAD_( psnames );
+
+ /* do not load the metrics headers and tables if this is an Apple */
+ /* sbit font file */
+ if ( !is_apple_sbit )
+ {
+ /* load the `hhea' and `hmtx' tables at once */
+ error = sfnt->load_metrics( face, stream, 0 );
+ if ( error )
+ goto Exit;
+
+ /* try to load the `vhea' and `vmtx' tables at once */
+ error = sfnt->load_metrics( face, stream, 1 );
+ if ( error )
+ goto Exit;
+
+ if ( LOAD_( os2 ) )
+ goto Exit;
+ }
+
+ /* the optional tables */
+
+#ifdef TT_CONFIG_OPTION_EMBEDDED_BITMAPS
+
+ /* embedded bitmap support. */
+ if ( sfnt->load_sbits && LOAD_( sbits ) )
+ {
+ /* return an error if this font file has no outlines */
+ if ( error == SFNT_Err_Table_Missing && has_outline )
+ error = SFNT_Err_Ok;
+ else
+ goto Exit;
+ }
+
+#endif /* TT_CONFIG_OPTION_EMBEDDED_BITMAPS */
+
+ if ( LOAD_( hdmx ) ||
+ LOAD_( gasp ) ||
+ LOAD_( kerning ) ||
+ LOAD_( pclt ) )
+ goto Exit;
+
+ face->root.family_name = tt_face_get_name( face,
+ TT_NAME_ID_FONT_FAMILY );
+ face->root.style_name = tt_face_get_name( face,
+ TT_NAME_ID_FONT_SUBFAMILY );
+
+ /* now set up root fields */
+ {
+ FT_Face root = &face->root;
+ FT_Int32 flags = 0;
+ FT_Memory memory;
+
+
+ memory = root->memory;
+
+ /*********************************************************************/
+ /* */
+ /* Compute face flags. */
+ /* */
+ if ( has_outline == TRUE )
+ flags = FT_FACE_FLAG_SCALABLE; /* scalable outlines */
+
+ flags |= FT_FACE_FLAG_SFNT | /* SFNT file format */
+ FT_FACE_FLAG_HORIZONTAL; /* horizontal data */
+
+#ifdef TT_CONFIG_OPTION_POSTSCRIPT_NAMES
+ /* might need more polish to detect the presence of a Postscript */
+ /* name table in the font */
+ flags |= FT_FACE_FLAG_GLYPH_NAMES;
+#endif
+
+ /* fixed width font? */
+ if ( face->postscript.isFixedPitch )
+ flags |= FT_FACE_FLAG_FIXED_WIDTH;
+
+ /* vertical information? */
+ if ( face->vertical_info )
+ flags |= FT_FACE_FLAG_VERTICAL;
+
+ /* kerning available ? */
+ if ( face->kern_pairs )
+ flags |= FT_FACE_FLAG_KERNING;
+
+ root->face_flags = flags;
+
+ /*********************************************************************/
+ /* */
+ /* Compute style flags. */
+ /* */
+ flags = 0;
+ if ( has_outline == TRUE && face->os2.version != 0xFFFF )
+ {
+ /* we have an OS/2 table; use the `fsSelection' field */
+ if ( face->os2.fsSelection & 1 )
+ flags |= FT_STYLE_FLAG_ITALIC;
+
+ if ( face->os2.fsSelection & 32 )
+ flags |= FT_STYLE_FLAG_BOLD;
+ }
+ else
+ {
+ /* this is an old Mac font, use the header field */
+ if ( face->header.Mac_Style & 1 )
+ flags |= FT_STYLE_FLAG_BOLD;
+
+ if ( face->header.Mac_Style & 2 )
+ flags |= FT_STYLE_FLAG_ITALIC;
+ }
+
+ root->style_flags = flags;
+
+ /*********************************************************************/
+ /* */
+ /* Polish the charmaps. */
+ /* */
+ /* Try to set the charmap encoding according to the platform & */
+ /* encoding ID of each charmap. */
+ /* */
+
+ tt_face_build_cmaps( face ); /* ignore errors */
+
+
+ /* set the encoding fields */
+ {
+ FT_Int m;
+
+
+ for ( m = 0; m < root->num_charmaps; m++ )
+ {
+ FT_CharMap charmap = root->charmaps[m];
+
+
+ charmap->encoding = sfnt_find_encoding( charmap->platform_id,
+ charmap->encoding_id );
+
+#if 0
+ if ( root->charmap == NULL &&
+ charmap->encoding == FT_ENCODING_UNICODE )
+ {
+ /* set 'root->charmap' to the first Unicode encoding we find */
+ root->charmap = charmap;
+ }
+#endif
+ }
+ }
+
+
+#ifdef TT_CONFIG_OPTION_EMBEDDED_BITMAPS
+
+ if ( face->num_sbit_strikes )
+ {
+ FT_ULong n;
+
+
+ root->face_flags |= FT_FACE_FLAG_FIXED_SIZES;
+
+#if 0
+ /* XXX: I don't know criteria whether layout is horizontal */
+ /* or vertical. */
+ if ( has_outline.... )
+ {
+ ...
+ root->face_flags |= FT_FACE_FLAG_VERTICAL;
+ }
+#endif
+ root->num_fixed_sizes = face->num_sbit_strikes;
+
+ if ( FT_NEW_ARRAY( root->available_sizes, face->num_sbit_strikes ) )
+ goto Exit;
+
+ for ( n = 0 ; n < face->num_sbit_strikes ; n++ )
+ {
+ root->available_sizes[n].width =
+ face->sbit_strikes[n].x_ppem;
+
+ root->available_sizes[n].height =
+ face->sbit_strikes[n].y_ppem;
+ }
+ }
+ else
+
+#endif /* TT_CONFIG_OPTION_EMBEDDED_BITMAPS */
+
+ {
+ root->num_fixed_sizes = 0;
+ root->available_sizes = 0;
+ }
+
+ /*********************************************************************/
+ /* */
+ /* Set up metrics. */
+ /* */
+ if ( has_outline == TRUE )
+ {
+ /* XXX What about if outline header is missing */
+ /* (e.g. sfnt wrapped outline)? */
+ root->bbox.xMin = face->header.xMin;
+ root->bbox.yMin = face->header.yMin;
+ root->bbox.xMax = face->header.xMax;
+ root->bbox.yMax = face->header.yMax;
+ root->units_per_EM = face->header.Units_Per_EM;
+
+
+ /* XXX: Computing the ascender/descender/height is very different */
+ /* from what the specification tells you. Apparently, we */
+ /* must be careful because */
+ /* */
+ /* - not all fonts have an OS/2 table; in this case, we take */
+ /* the values in the horizontal header. However, these */
+ /* values very often are not reliable. */
+ /* */
+ /* - otherwise, the correct typographic values are in the */
+ /* sTypoAscender, sTypoDescender & sTypoLineGap fields. */
+ /* */
+ /* However, certains fonts have these fields set to 0. */
+ /* Rather, they have usWinAscent & usWinDescent correctly */
+ /* set (but with different values). */
+ /* */
+ /* As an example, Arial Narrow is implemented through four */
+ /* files ARIALN.TTF, ARIALNI.TTF, ARIALNB.TTF & ARIALNBI.TTF */
+ /* */
+ /* Strangely, all fonts have the same values in their */
+ /* sTypoXXX fields, except ARIALNB which sets them to 0. */
+ /* */
+ /* On the other hand, they all have different */
+ /* usWinAscent/Descent values -- as a conclusion, the OS/2 */
+ /* table cannot be used to compute the text height reliably! */
+ /* */
+
+ /* The ascender/descender/height are computed from the OS/2 table */
+ /* when found. Otherwise, they're taken from the horizontal */
+ /* header. */
+ /* */
+
+ root->ascender = face->horizontal.Ascender;
+ root->descender = face->horizontal.Descender;
+
+ root->height = (FT_Short)( root->ascender - root->descender +
+ face->horizontal.Line_Gap );
+
+ /* if the line_gap is 0, we add an extra 15% to the text height -- */
+ /* this computation is based on various versions of Times New Roman */
+ if ( face->horizontal.Line_Gap == 0 )
+ root->height = (FT_Short)( ( root->height * 115 + 50 ) / 100 );
+
+#if 0
+
+ /* some fonts have the OS/2 "sTypoAscender", "sTypoDescender" & */
+ /* "sTypoLineGap" fields set to 0, like ARIALNB.TTF */
+ if ( face->os2.version != 0xFFFF && root->ascender )
+ {
+ FT_Int height;
+
+
+ root->ascender = face->os2.sTypoAscender;
+ root->descender = -face->os2.sTypoDescender;
+
+ height = root->ascender + root->descender + face->os2.sTypoLineGap;
+ if ( height > root->height )
+ root->height = height;
+ }
+
+#endif /* 0 */
+
+ root->max_advance_width = face->horizontal.advance_Width_Max;
+
+ root->max_advance_height = (FT_Short)( face->vertical_info
+ ? face->vertical.advance_Height_Max
+ : root->height );
+
+ root->underline_position = face->postscript.underlinePosition;
+ root->underline_thickness = face->postscript.underlineThickness;
+
+ /* root->max_points -- already set up */
+ /* root->max_contours -- already set up */
+ }
+ }
+
+ Exit:
+ return error;
+ }
+
+
+#undef LOAD_
+
+
+ FT_LOCAL_DEF( void )
+ sfnt_done_face( TT_Face face )
+ {
+ FT_Memory memory = face->root.memory;
+ SFNT_Service sfnt = (SFNT_Service)face->sfnt;
+
+
+ if ( sfnt )
+ {
+ /* destroy the postscript names table if it is loaded */
+ if ( sfnt->free_psnames )
+ sfnt->free_psnames( face );
+
+ /* destroy the embedded bitmaps table if it is loaded */
+ if ( sfnt->free_sbits )
+ sfnt->free_sbits( face );
+ }
+
+ /* freeing the kerning table */
+ FT_FREE( face->kern_pairs );
+ face->num_kern_pairs = 0;
+
+ /* freeing the collection table */
+ FT_FREE( face->ttc_header.offsets );
+ face->ttc_header.count = 0;
+
+ /* freeing table directory */
+ FT_FREE( face->dir_tables );
+ face->num_tables = 0;
+
+ {
+ FT_Stream stream = FT_FACE_STREAM( face );
+
+
+ /* simply release the 'cmap' table frame */
+ FT_FRAME_RELEASE( face->cmap_table );
+ face->cmap_size = 0;
+ }
+
+ /* freeing the horizontal metrics */
+ FT_FREE( face->horizontal.long_metrics );
+ FT_FREE( face->horizontal.short_metrics );
+
+ /* freeing the vertical ones, if any */
+ if ( face->vertical_info )
+ {
+ FT_FREE( face->vertical.long_metrics );
+ FT_FREE( face->vertical.short_metrics );
+ face->vertical_info = 0;
+ }
+
+ /* freeing the gasp table */
+ FT_FREE( face->gasp.gaspRanges );
+ face->gasp.numRanges = 0;
+
+ /* freeing the name table */
+ sfnt->free_names( face );
+
+ /* freeing the hdmx table */
+ sfnt->free_hdmx( face );
+
+ /* freeing family and style name */
+ FT_FREE( face->root.family_name );
+ FT_FREE( face->root.style_name );
+
+ /* freeing sbit size table */
+ face->root.num_fixed_sizes = 0;
+ if ( face->root.available_sizes )
+ FT_FREE( face->root.available_sizes );
+
+ face->sfnt = 0;
+ }
+
+
+/* END */
--- /dev/null
+++ b/libfreetype/sfobjs.h
@@ -1,0 +1,54 @@
+/***************************************************************************/
+/* */
+/* sfobjs.h */
+/* */
+/* SFNT object management (specification). */
+/* */
+/* Copyright 1996-2001, 2002 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+
+#ifndef __SFOBJS_H__
+#define __SFOBJS_H__
+
+
+#include <ft2build.h>
+#include FT_INTERNAL_SFNT_H
+#include FT_INTERNAL_OBJECTS_H
+
+
+FT_BEGIN_HEADER
+
+
+ FT_LOCAL( FT_Error )
+ sfnt_init_face( FT_Stream stream,
+ TT_Face face,
+ FT_Int face_index,
+ FT_Int num_params,
+ FT_Parameter* params );
+
+ FT_LOCAL( FT_Error )
+ sfnt_load_face( FT_Stream stream,
+ TT_Face face,
+ FT_Int face_index,
+ FT_Int num_params,
+ FT_Parameter* params );
+
+ FT_LOCAL( void )
+ sfnt_done_face( TT_Face face );
+
+
+FT_END_HEADER
+
+#endif /* __SFDRIVER_H__ */
+
+
+/* END */
--- /dev/null
+++ b/libfreetype/smooth.c
@@ -1,0 +1,26 @@
+/***************************************************************************/
+/* */
+/* smooth.c */
+/* */
+/* FreeType anti-aliasing rasterer module component (body only). */
+/* */
+/* Copyright 1996-2001 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+
+#define FT_MAKE_OPTION_SINGLE_OBJECT
+
+#include <ft2build.h>
+#include "ftgrays.c"
+#include "ftsmooth.c"
+
+
+/* END */
--- /dev/null
+++ b/libfreetype/stddef.h
@@ -1,0 +1,36 @@
+/* there's a better way. we should use it. */
+#ifdef _STDDEF_H_
+#define __STDDEF_H
+#endif
+#ifdef _SYS_TYPES_H_
+#define __STDDEF_H
+#endif
+#ifdef _STDLIB_H_
+#define __STDDEF_H
+#endif
+
+#ifndef __STDDEF_H
+#define __STDDEF_H /* various */
+#define _STDDEF_H_ /* FreeBSD */
+
+#ifndef NULL
+#define NULL 0
+#endif
+
+#ifndef _PTRDIFF_T
+#define _PTRDIFF_T
+typedef long ptrdiff_t;
+#endif
+#undef _BSD_PTRDIFF_T
+#ifndef _SIZE_T
+#define _SIZE_T
+typedef unsigned long size_t;
+#endif
+#undef _BSD_SIZE_T
+#ifndef _WCHAR_T
+#define _WCHAR_T
+typedef unsigned short wchar_t;
+#endif
+#undef _BSD_WCHAR_T
+
+#endif /* __STDDEF_H */
--- /dev/null
+++ b/libfreetype/t1afm.c
@@ -1,0 +1,282 @@
+/***************************************************************************/
+/* */
+/* t1afm.c */
+/* */
+/* AFM support for Type 1 fonts (body). */
+/* */
+/* Copyright 1996-2001, 2002 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+
+#include <ft2build.h>
+#include "t1afm.h"
+#include FT_INTERNAL_STREAM_H
+#include FT_INTERNAL_TYPE1_TYPES_H
+
+
+ /*************************************************************************/
+ /* */
+ /* The macro FT_COMPONENT is used in trace mode. It is an implicit */
+ /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log */
+ /* messages during execution. */
+ /* */
+#undef FT_COMPONENT
+#define FT_COMPONENT trace_t1afm
+
+
+ FT_LOCAL_DEF( void )
+ T1_Done_AFM( FT_Memory memory,
+ T1_AFM* afm )
+ {
+ FT_FREE( afm->kern_pairs );
+ afm->num_pairs = 0;
+ FT_FREE( afm );
+ }
+
+
+#undef IS_KERN_PAIR
+#define IS_KERN_PAIR( p ) ( p[0] == 'K' && p[1] == 'P' )
+
+#define IS_ALPHANUM( c ) ( ft_isalnum( c ) || \
+ c == '_' || \
+ c == '.' )
+
+
+ /* read a glyph name and return the equivalent glyph index */
+ static FT_UInt
+ afm_atoindex( FT_Byte** start,
+ FT_Byte* limit,
+ T1_Font type1 )
+ {
+ FT_Byte* p = *start;
+ FT_PtrDist len;
+ FT_UInt result = 0;
+ char temp[64];
+
+
+ /* skip whitespace */
+ while ( ( *p == ' ' || *p == '\t' || *p == ':' || *p == ';' ) &&
+ p < limit )
+ p++;
+ *start = p;
+
+ /* now, read glyph name */
+ while ( IS_ALPHANUM( *p ) && p < limit )
+ p++;
+
+ len = p - *start;
+
+ if ( len > 0 && len < 64 )
+ {
+ FT_Int n;
+
+
+ /* copy glyph name to intermediate array */
+ FT_MEM_COPY( temp, *start, len );
+ temp[len] = 0;
+
+ /* lookup glyph name in face array */
+ for ( n = 0; n < type1->num_glyphs; n++ )
+ {
+ char* gname = (char*)type1->glyph_names[n];
+
+
+ if ( gname && gname[0] == temp[0] && ft_strcmp( gname, temp ) == 0 )
+ {
+ result = n;
+ break;
+ }
+ }
+ }
+ *start = p;
+ return result;
+ }
+
+
+ /* read an integer */
+ static int
+ afm_atoi( FT_Byte** start,
+ FT_Byte* limit )
+ {
+ FT_Byte* p = *start;
+ int sum = 0;
+ int sign = 1;
+
+
+ /* skip everything that is not a number */
+ while ( p < limit && !isdigit( *p ) )
+ {
+ sign = 1;
+ if ( *p == '-' )
+ sign = -1;
+
+ p++;
+ }
+
+ while ( p < limit && isdigit( *p ) )
+ {
+ sum = sum * 10 + ( *p - '0' );
+ p++;
+ }
+ *start = p;
+
+ return sum * sign;
+ }
+
+
+#undef KERN_INDEX
+#define KERN_INDEX( g1, g2 ) ( ( (FT_ULong)g1 << 16 ) | g2 )
+
+
+ /* compare two kerning pairs */
+ FT_CALLBACK_DEF( int )
+ compare_kern_pairs( const void* a,
+ const void* b )
+ {
+ T1_Kern_Pair* pair1 = (T1_Kern_Pair*)a;
+ T1_Kern_Pair* pair2 = (T1_Kern_Pair*)b;
+
+ FT_ULong index1 = KERN_INDEX( pair1->glyph1, pair1->glyph2 );
+ FT_ULong index2 = KERN_INDEX( pair2->glyph1, pair2->glyph2 );
+
+
+ return ( index1 - index2 );
+ }
+
+
+ /* parse an AFM file -- for now, only read the kerning pairs */
+ FT_LOCAL_DEF( FT_Error )
+ T1_Read_AFM( FT_Face t1_face,
+ FT_Stream stream )
+ {
+ FT_Error error;
+ FT_Memory memory = stream->memory;
+ FT_Byte* start;
+ FT_Byte* limit;
+ FT_Byte* p;
+ FT_Int count = 0;
+ T1_Kern_Pair* pair;
+ T1_Font type1 = &((T1_Face)t1_face)->type1;
+ T1_AFM* afm = 0;
+
+
+ if ( FT_FRAME_ENTER( stream->size ) )
+ return error;
+
+ start = (FT_Byte*)stream->cursor;
+ limit = (FT_Byte*)stream->limit;
+ p = start;
+
+ /* we are now going to count the occurences of `KP' or `KPX' in */
+ /* the AFM file */
+ count = 0;
+ for ( p = start; p < limit - 3; p++ )
+ {
+ if ( IS_KERN_PAIR( p ) )
+ count++;
+ }
+
+ /* Actually, kerning pairs are simply optional! */
+ if ( count == 0 )
+ goto Exit;
+
+ /* allocate the pairs */
+ if ( FT_NEW( afm ) || FT_NEW_ARRAY( afm->kern_pairs, count ) )
+ goto Exit;
+
+ /* now, read each kern pair */
+ pair = afm->kern_pairs;
+ afm->num_pairs = count;
+
+ /* save in face object */
+ ((T1_Face)t1_face)->afm_data = afm;
+
+ t1_face->face_flags |= FT_FACE_FLAG_KERNING;
+
+ for ( p = start; p < limit - 3; p++ )
+ {
+ if ( IS_KERN_PAIR( p ) )
+ {
+ FT_Byte* q;
+
+
+ /* skip keyword (KP or KPX) */
+ q = p + 2;
+ if ( *q == 'X' )
+ q++;
+
+ pair->glyph1 = afm_atoindex( &q, limit, type1 );
+ pair->glyph2 = afm_atoindex( &q, limit, type1 );
+ pair->kerning.x = afm_atoi( &q, limit );
+
+ pair->kerning.y = 0;
+ if ( p[2] != 'X' )
+ pair->kerning.y = afm_atoi( &q, limit );
+
+ pair++;
+ }
+ }
+
+ /* now, sort the kern pairs according to their glyph indices */
+ ft_qsort( afm->kern_pairs, count, sizeof ( T1_Kern_Pair ),
+ compare_kern_pairs );
+
+ Exit:
+ if ( error )
+ FT_FREE( afm );
+
+ FT_FRAME_EXIT();
+
+ return error;
+ }
+
+
+ /* find the kerning for a given glyph pair */
+ FT_LOCAL_DEF( void )
+ T1_Get_Kerning( T1_AFM* afm,
+ FT_UInt glyph1,
+ FT_UInt glyph2,
+ FT_Vector* kerning )
+ {
+ T1_Kern_Pair *min, *mid, *max;
+ FT_ULong idx = KERN_INDEX( glyph1, glyph2 );
+
+
+ /* simple binary search */
+ min = afm->kern_pairs;
+ max = min + afm->num_pairs - 1;
+
+ while ( min <= max )
+ {
+ FT_ULong midi;
+
+
+ mid = min + ( max - min ) / 2;
+ midi = KERN_INDEX( mid->glyph1, mid->glyph2 );
+
+ if ( midi == idx )
+ {
+ *kerning = mid->kerning;
+ return;
+ }
+
+ if ( midi < idx )
+ min = mid + 1;
+ else
+ max = mid - 1;
+ }
+
+ kerning->x = 0;
+ kerning->y = 0;
+ }
+
+
+/* END */
--- /dev/null
+++ b/libfreetype/t1afm.h
@@ -1,0 +1,66 @@
+/***************************************************************************/
+/* */
+/* t1afm.h */
+/* */
+/* AFM support for Type 1 fonts (specification). */
+/* */
+/* Copyright 1996-2001, 2002 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+
+#ifndef __T1AFM_H__
+#define __T1AFM_H__
+
+#include <ft2build.h>
+#include "t1objs.h"
+
+
+FT_BEGIN_HEADER
+
+
+ typedef struct T1_Kern_Pair_
+ {
+ FT_UInt glyph1;
+ FT_UInt glyph2;
+ FT_Vector kerning;
+
+ } T1_Kern_Pair;
+
+
+ typedef struct T1_AFM_
+ {
+ FT_Int num_pairs;
+ T1_Kern_Pair* kern_pairs;
+
+ } T1_AFM;
+
+
+ FT_LOCAL( FT_Error )
+ T1_Read_AFM( FT_Face face,
+ FT_Stream stream );
+
+ FT_LOCAL( void )
+ T1_Done_AFM( FT_Memory memory,
+ T1_AFM* afm );
+
+ FT_LOCAL( void )
+ T1_Get_Kerning( T1_AFM* afm,
+ FT_UInt glyph1,
+ FT_UInt glyph2,
+ FT_Vector* kerning );
+
+
+FT_END_HEADER
+
+#endif /* __T1AFM_H__ */
+
+
+/* END */
--- /dev/null
+++ b/libfreetype/t1cmap.c
@@ -1,0 +1,454 @@
+/***************************************************************************/
+/* */
+/* t1cmap.c */
+/* */
+/* Type 1 character map support (body). */
+/* */
+/* Copyright 2002 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+
+#include "t1cmap.h"
+
+#include FT_INTERNAL_DEBUG_H
+
+
+ /*************************************************************************/
+ /*************************************************************************/
+ /***** *****/
+ /***** TYPE1 STANDARD (AND EXPERT) ENCODING CMAPS *****/
+ /***** *****/
+ /*************************************************************************/
+ /*************************************************************************/
+
+ static void
+ t1_cmap_std_init( T1_CMapStd cmap,
+ FT_Int is_expert )
+ {
+ T1_Face face = (T1_Face)FT_CMAP_FACE( cmap );
+ PSNames_Service psnames = (PSNames_Service)face->psnames;
+
+
+ cmap->num_glyphs = face->type1.num_glyphs;
+ cmap->glyph_names = (const char* const*)face->type1.glyph_names;
+ cmap->sid_to_string = psnames->adobe_std_strings;
+ cmap->code_to_sid = is_expert ? psnames->adobe_expert_encoding
+ : psnames->adobe_std_encoding;
+
+ FT_ASSERT( cmap->code_to_sid != NULL );
+ }
+
+
+ FT_CALLBACK_DEF( void )
+ t1_cmap_std_done( T1_CMapStd cmap )
+ {
+ cmap->num_glyphs = 0;
+ cmap->glyph_names = NULL;
+ cmap->sid_to_string = NULL;
+ cmap->code_to_sid = NULL;
+ }
+
+
+ FT_CALLBACK_DEF( FT_UInt )
+ t1_cmap_std_char_index( T1_CMapStd cmap,
+ FT_UInt32 char_code )
+ {
+ FT_UInt result = 0;
+
+
+ if ( char_code < 256 )
+ {
+ FT_UInt code, n;
+ const char* glyph_name;
+
+
+ /* convert character code to Adobe SID string */
+ code = cmap->code_to_sid[char_code];
+ glyph_name = cmap->sid_to_string( code );
+
+ /* look for the corresponding glyph name */
+ for ( n = 0; n < cmap->num_glyphs; n++ )
+ {
+ const char* gname = cmap->glyph_names[n];
+
+
+ if ( gname && gname[0] == glyph_name[0] &&
+ ft_strcmp( gname, glyph_name ) == 0 )
+ {
+ result = n;
+ break;
+ }
+ }
+ }
+
+ return result;
+ }
+
+
+ FT_CALLBACK_DEF( FT_UInt )
+ t1_cmap_std_char_next( T1_CMapStd cmap,
+ FT_UInt32 *pchar_code )
+ {
+ FT_UInt result = 0;
+ FT_UInt32 char_code = *pchar_code + 1;
+
+
+ while ( char_code < 256 )
+ {
+ result = t1_cmap_std_char_index( cmap, char_code );
+ if ( result != 0 )
+ goto Exit;
+
+ char_code++;
+ }
+ char_code = 0;
+
+ Exit:
+ *pchar_code = char_code;
+ return result;
+ }
+
+
+ FT_CALLBACK_DEF( FT_Error )
+ t1_cmap_standard_init( T1_CMapStd cmap )
+ {
+ t1_cmap_std_init( cmap, 0 );
+ return 0;
+ }
+
+
+ FT_CALLBACK_TABLE_DEF const FT_CMap_ClassRec
+ t1_cmap_standard_class_rec =
+ {
+ sizeof ( T1_CMapStdRec ),
+
+ (FT_CMap_InitFunc) t1_cmap_standard_init,
+ (FT_CMap_DoneFunc) t1_cmap_std_done,
+ (FT_CMap_CharIndexFunc)t1_cmap_std_char_index,
+ (FT_CMap_CharNextFunc) t1_cmap_std_char_next
+ };
+
+
+ FT_CALLBACK_DEF( FT_Error )
+ t1_cmap_expert_init( T1_CMapStd cmap )
+ {
+ t1_cmap_std_init( cmap, 1 );
+ return 0;
+ }
+
+ FT_CALLBACK_TABLE_DEF const FT_CMap_ClassRec
+ t1_cmap_expert_class_rec =
+ {
+ sizeof ( T1_CMapStdRec ),
+
+ (FT_CMap_InitFunc) t1_cmap_expert_init,
+ (FT_CMap_DoneFunc) t1_cmap_std_done,
+ (FT_CMap_CharIndexFunc)t1_cmap_std_char_index,
+ (FT_CMap_CharNextFunc) t1_cmap_std_char_next
+ };
+
+
+ /*************************************************************************/
+ /*************************************************************************/
+ /***** *****/
+ /***** TYPE1 CUSTOM ENCODING CMAP *****/
+ /***** *****/
+ /*************************************************************************/
+ /*************************************************************************/
+
+
+ FT_CALLBACK_DEF( FT_Error )
+ t1_cmap_custom_init( T1_CMapCustom cmap )
+ {
+ T1_Face face = (T1_Face)FT_CMAP_FACE( cmap );
+ T1_Encoding encoding = &face->type1.encoding;
+
+
+ cmap->first = encoding->code_first;
+ cmap->count = (FT_UInt)( encoding->code_last - cmap->first + 1 );
+ cmap->indices = encoding->char_index;
+
+ FT_ASSERT( cmap->indices != NULL );
+ FT_ASSERT( encoding->code_first <= encoding->code_last );
+
+ return 0;
+ }
+
+
+ FT_CALLBACK_DEF( void )
+ t1_cmap_custom_done( T1_CMapCustom cmap )
+ {
+ cmap->indices = NULL;
+ cmap->first = 0;
+ cmap->count = 0;
+ }
+
+
+ FT_CALLBACK_DEF( FT_UInt )
+ t1_cmap_custom_char_index( T1_CMapCustom cmap,
+ FT_UInt32 char_code )
+ {
+ FT_UInt result = 0;
+
+
+ if ( ( char_code >= cmap->first ) &&
+ ( char_code < ( cmap->first + cmap->count ) ) )
+ result = cmap->indices[char_code];
+
+ return result;
+ }
+
+
+ FT_CALLBACK_DEF( FT_UInt )
+ t1_cmap_custom_char_next( T1_CMapCustom cmap,
+ FT_UInt32 *pchar_code )
+ {
+ FT_UInt result = 0;
+ FT_UInt32 char_code = *pchar_code;
+
+
+ ++char_code;
+
+ if ( char_code < cmap->first )
+ char_code = cmap->first;
+
+ for ( ; char_code < ( cmap->first + cmap->count ); char_code++ )
+ {
+ result = cmap->indices[char_code];
+ if ( result != 0 )
+ goto Exit;
+ }
+
+ char_code = 0;
+
+ Exit:
+ *pchar_code = char_code;
+ return result;
+ }
+
+
+ FT_CALLBACK_TABLE_DEF const FT_CMap_ClassRec
+ t1_cmap_custom_class_rec =
+ {
+ sizeof ( T1_CMapCustomRec ),
+
+ (FT_CMap_InitFunc) t1_cmap_custom_init,
+ (FT_CMap_DoneFunc) t1_cmap_custom_done,
+ (FT_CMap_CharIndexFunc)t1_cmap_custom_char_index,
+ (FT_CMap_CharNextFunc) t1_cmap_custom_char_next
+ };
+
+
+ /*************************************************************************/
+ /*************************************************************************/
+ /***** *****/
+ /***** TYPE1 SYNTHETIC UNICODE ENCODING CMAP *****/
+ /***** *****/
+ /*************************************************************************/
+ /*************************************************************************/
+
+ FT_CALLBACK_DEF( FT_Int )
+ t1_cmap_uni_pair_compare( const void* pair1,
+ const void* pair2 )
+ {
+ FT_UInt32 u1 = ((T1_CMapUniPair)pair1)->unicode;
+ FT_UInt32 u2 = ((T1_CMapUniPair)pair2)->unicode;
+
+
+ if ( u1 < u2 )
+ return -1;
+
+ if ( u1 > u2 )
+ return +1;
+
+ return 0;
+ }
+
+
+ FT_CALLBACK_DEF( FT_Error )
+ t1_cmap_unicode_init( T1_CMapUnicode cmap )
+ {
+ FT_Error error;
+ FT_UInt count;
+ T1_Face face = (T1_Face)FT_CMAP_FACE( cmap );
+ FT_Memory memory = FT_FACE_MEMORY( face );
+ PSNames_Service psnames = (PSNames_Service)face->psnames;
+
+
+ cmap->num_pairs = 0;
+ cmap->pairs = NULL;
+
+ count = face->type1.num_glyphs;
+
+ if ( !FT_NEW_ARRAY( cmap->pairs, count ) )
+ {
+ FT_UInt n, new_count;
+ T1_CMapUniPair pair;
+ FT_UInt32 uni_code;
+
+
+ pair = cmap->pairs;
+ for ( n = 0; n < count; n++ )
+ {
+ const char* gname = face->type1.glyph_names[n];
+
+
+ /* build unsorted pair table by matching glyph names */
+ if ( gname )
+ {
+ uni_code = psnames->unicode_value( gname );
+
+ if ( uni_code != 0 )
+ {
+ pair->unicode = uni_code;
+ pair->gindex = n;
+ pair++;
+ }
+ }
+ }
+
+ new_count = (FT_UInt)( pair - cmap->pairs );
+ if ( new_count == 0 )
+ {
+ /* there are no unicode characters in here! */
+ FT_FREE( cmap->pairs );
+ error = FT_Err_Invalid_Argument;
+ }
+ else
+ {
+ /* re-allocate if the new array is much smaller than the original */
+ /* one */
+ if ( new_count != count && new_count < count / 2 )
+ {
+ (void)FT_RENEW_ARRAY( cmap->pairs, count, new_count );
+ error = 0;
+ }
+
+ /* sort the pairs table to allow efficient binary searches */
+ ft_qsort( cmap->pairs,
+ new_count,
+ sizeof ( T1_CMapUniPairRec ),
+ t1_cmap_uni_pair_compare );
+
+ cmap->num_pairs = new_count;
+ }
+ }
+
+ return error;
+ }
+
+
+ FT_CALLBACK_DEF( void )
+ t1_cmap_unicode_done( T1_CMapUnicode cmap )
+ {
+ FT_Face face = FT_CMAP_FACE(cmap);
+ FT_Memory memory = FT_FACE_MEMORY(face);
+
+ FT_FREE( cmap->pairs );
+ cmap->num_pairs = 0;
+ }
+
+
+ FT_CALLBACK_DEF( FT_UInt )
+ t1_cmap_unicode_char_index( T1_CMapUnicode cmap,
+ FT_UInt32 char_code )
+ {
+ FT_UInt min = 0;
+ FT_UInt max = cmap->num_pairs;
+ FT_UInt mid;
+ T1_CMapUniPair pair;
+
+
+ while ( min < max )
+ {
+ mid = min + ( max - min ) / 2;
+ pair = cmap->pairs + mid;
+
+ if ( pair->unicode == char_code )
+ return pair->gindex;
+
+ if ( pair->unicode < char_code )
+ min = mid + 1;
+ else
+ max = mid;
+ }
+ return 0;
+ }
+
+
+ FT_CALLBACK_DEF( FT_UInt )
+ t1_cmap_unicode_char_next( T1_CMapUnicode cmap,
+ FT_UInt32 *pchar_code )
+ {
+ FT_UInt result = 0;
+ FT_UInt32 char_code = *pchar_code + 1;
+
+
+ Restart:
+ {
+ FT_UInt min = 0;
+ FT_UInt max = cmap->num_pairs;
+ FT_UInt mid;
+ T1_CMapUniPair pair;
+
+
+ while ( min < max )
+ {
+ mid = min + ( ( max - min ) >> 1 );
+ pair = cmap->pairs + mid;
+
+ if ( pair->unicode == char_code )
+ {
+ result = pair->gindex;
+ if ( result != 0 )
+ goto Exit;
+
+ char_code++;
+ goto Restart;
+ }
+
+ if ( pair->unicode < char_code )
+ min = mid+1;
+ else
+ max = mid;
+ }
+
+ /* we didn't find it, but we have a pair just above it */
+ char_code = 0;
+
+ if ( min < cmap->num_pairs )
+ {
+ pair = cmap->pairs + min;
+ result = pair->gindex;
+ if ( result != 0 )
+ char_code = pair->unicode;
+ }
+ }
+
+ Exit:
+ *pchar_code = char_code;
+ return result;
+ }
+
+
+ FT_CALLBACK_TABLE_DEF const FT_CMap_ClassRec
+ t1_cmap_unicode_class_rec =
+ {
+ sizeof ( T1_CMapUnicodeRec ),
+
+ (FT_CMap_InitFunc) t1_cmap_unicode_init,
+ (FT_CMap_DoneFunc) t1_cmap_unicode_done,
+ (FT_CMap_CharIndexFunc)t1_cmap_unicode_char_index,
+ (FT_CMap_CharNextFunc) t1_cmap_unicode_char_next
+ };
+
+
+/* END */
--- /dev/null
+++ b/libfreetype/t1cmap.h
@@ -1,0 +1,124 @@
+/***************************************************************************/
+/* */
+/* t1cmap.h */
+/* */
+/* Type 1 character map support (specification). */
+/* */
+/* Copyright 2002 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+
+#ifndef __T1CMAP_H__
+#define __T1CMAP_H__
+
+#include <ft2build.h>
+#include FT_INTERNAL_OBJECTS_H
+#include FT_INTERNAL_TYPE1_TYPES_H
+#include FT_INTERNAL_POSTSCRIPT_NAMES_H
+
+FT_BEGIN_HEADER
+
+
+ /*************************************************************************/
+ /*************************************************************************/
+ /***** *****/
+ /***** TYPE1 STANDARD (AND EXPERT) ENCODING CMAPS *****/
+ /***** *****/
+ /*************************************************************************/
+ /*************************************************************************/
+
+ /* standard (and expert) encoding cmaps */
+ typedef struct T1_CMapStdRec_* T1_CMapStd;
+
+ typedef struct T1_CMapStdRec_
+ {
+ FT_CMapRec cmap;
+
+ const FT_UShort* code_to_sid;
+ PS_Adobe_Std_Strings_Func sid_to_string;
+
+ FT_UInt num_glyphs;
+ const char* const* glyph_names;
+
+ } T1_CMapStdRec;
+
+
+ FT_CALLBACK_TABLE const FT_CMap_ClassRec
+ t1_cmap_standard_class_rec;
+
+ FT_CALLBACK_TABLE const FT_CMap_ClassRec
+ t1_cmap_expert_class_rec;
+
+
+ /*************************************************************************/
+ /*************************************************************************/
+ /***** *****/
+ /***** TYPE1 CUSTOM ENCODING CMAP *****/
+ /***** *****/
+ /*************************************************************************/
+ /*************************************************************************/
+
+ typedef struct T1_CMapCustomRec_* T1_CMapCustom;
+
+ typedef struct T1_CMapCustomRec_
+ {
+ FT_CMapRec cmap;
+ FT_UInt first;
+ FT_UInt count;
+ FT_UShort* indices;
+
+ } T1_CMapCustomRec;
+
+
+ FT_CALLBACK_TABLE const FT_CMap_ClassRec
+ t1_cmap_custom_class_rec;
+
+
+ /*************************************************************************/
+ /*************************************************************************/
+ /***** *****/
+ /***** TYPE1 SYNTHETIC UNICODE ENCODING CMAP *****/
+ /***** *****/
+ /*************************************************************************/
+ /*************************************************************************/
+
+ /* unicode (syntehtic) cmaps */
+ typedef struct T1_CMapUnicodeRec_* T1_CMapUnicode;
+
+ typedef struct T1_CMapUniPairRec_
+ {
+ FT_UInt32 unicode;
+ FT_UInt gindex;
+
+ } T1_CMapUniPairRec, *T1_CMapUniPair;
+
+
+ typedef struct T1_CMapUnicodeRec_
+ {
+ FT_CMapRec cmap;
+ FT_UInt num_pairs;
+ T1_CMapUniPair pairs;
+
+ } T1_CMapUnicodeRec;
+
+
+ FT_CALLBACK_TABLE const FT_CMap_ClassRec
+ t1_cmap_unicode_class_rec;
+
+ /* */
+
+
+FT_END_HEADER
+
+#endif /* __T1CMAP_H__ */
+
+
+/* END */
--- /dev/null
+++ b/libfreetype/t1decode.c
@@ -1,0 +1,1170 @@
+/***************************************************************************/
+/* */
+/* t1decode.c */
+/* */
+/* PostScript Type 1 decoding routines (body). */
+/* */
+/* Copyright 2000-2001, 2002 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+
+#include <ft2build.h>
+#include FT_INTERNAL_DEBUG_H
+#include FT_INTERNAL_POSTSCRIPT_HINTS_H
+#include FT_OUTLINE_H
+
+#include "t1decode.h"
+#include "psobjs.h"
+
+#include "psauxerr.h"
+
+
+ /*************************************************************************/
+ /* */
+ /* The macro FT_COMPONENT is used in trace mode. It is an implicit */
+ /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log */
+ /* messages during execution. */
+ /* */
+#undef FT_COMPONENT
+#define FT_COMPONENT trace_t1decode
+
+
+ typedef enum T1_Operator_
+ {
+ op_none = 0,
+ op_endchar,
+ op_hsbw,
+ op_seac,
+ op_sbw,
+ op_closepath,
+ op_hlineto,
+ op_hmoveto,
+ op_hvcurveto,
+ op_rlineto,
+ op_rmoveto,
+ op_rrcurveto,
+ op_vhcurveto,
+ op_vlineto,
+ op_vmoveto,
+ op_dotsection,
+ op_hstem,
+ op_hstem3,
+ op_vstem,
+ op_vstem3,
+ op_div,
+ op_callothersubr,
+ op_callsubr,
+ op_pop,
+ op_return,
+ op_setcurrentpoint,
+
+ op_max /* never remove this one */
+
+ } T1_Operator;
+
+
+ static
+ const FT_Int t1_args_count[op_max] =
+ {
+ 0, /* none */
+ 0, /* endchar */
+ 2, /* hsbw */
+ 5, /* seac */
+ 4, /* sbw */
+ 0, /* closepath */
+ 1, /* hlineto */
+ 1, /* hmoveto */
+ 4, /* hvcurveto */
+ 2, /* rlineto */
+ 2, /* rmoveto */
+ 6, /* rrcurveto */
+ 4, /* vhcurveto */
+ 1, /* vlineto */
+ 1, /* vmoveto */
+ 0, /* dotsection */
+ 2, /* hstem */
+ 6, /* hstem3 */
+ 2, /* vstem */
+ 6, /* vstem3 */
+ 2, /* div */
+ -1, /* callothersubr */
+ 1, /* callsubr */
+ 0, /* pop */
+ 0, /* return */
+ 2 /* setcurrentpoint */
+ };
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* t1_lookup_glyph_by_stdcharcode */
+ /* */
+ /* <Description> */
+ /* Looks up a given glyph by its StandardEncoding charcode. Used to */
+ /* implement the SEAC Type 1 operator. */
+ /* */
+ /* <Input> */
+ /* face :: The current face object. */
+ /* */
+ /* charcode :: The character code to look for. */
+ /* */
+ /* <Return> */
+ /* A glyph index in the font face. Returns -1 if the corresponding */
+ /* glyph wasn't found. */
+ /* */
+ static FT_Int
+ t1_lookup_glyph_by_stdcharcode( T1_Decoder decoder,
+ FT_Int charcode )
+ {
+ FT_UInt n;
+ const FT_String* glyph_name;
+ PSNames_Service psnames = decoder->psnames;
+
+
+ /* check range of standard char code */
+ if ( charcode < 0 || charcode > 255 )
+ return -1;
+
+ glyph_name = psnames->adobe_std_strings(
+ psnames->adobe_std_encoding[charcode]);
+
+ for ( n = 0; n < decoder->num_glyphs; n++ )
+ {
+ FT_String* name = (FT_String*)decoder->glyph_names[n];
+
+
+ if ( name && name[0] == glyph_name[0] &&
+ ft_strcmp( name,glyph_name ) == 0 )
+ return n;
+ }
+
+ return -1;
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* t1operator_seac */
+ /* */
+ /* <Description> */
+ /* Implements the `seac' Type 1 operator for a Type 1 decoder. */
+ /* */
+ /* <Input> */
+ /* decoder :: The current CID decoder. */
+ /* */
+ /* asb :: The accent's side bearing. */
+ /* */
+ /* adx :: The horizontal offset of the accent. */
+ /* */
+ /* ady :: The vertical offset of the accent. */
+ /* */
+ /* bchar :: The base character's StandardEncoding charcode. */
+ /* */
+ /* achar :: The accent character's StandardEncoding charcode. */
+ /* */
+ /* <Return> */
+ /* FreeType error code. 0 means success. */
+ /* */
+ static FT_Error
+ t1operator_seac( T1_Decoder decoder,
+ FT_Pos asb,
+ FT_Pos adx,
+ FT_Pos ady,
+ FT_Int bchar,
+ FT_Int achar )
+ {
+ FT_Error error;
+ FT_Int bchar_index, achar_index;
+#if 0
+ FT_Int n_base_points;
+ FT_Outline* base = decoder->builder.base;
+#endif
+ FT_Vector left_bearing, advance;
+
+
+ /* seac weirdness */
+ adx += decoder->builder.left_bearing.x;
+
+ /* `glyph_names' is set to 0 for CID fonts which do not */
+ /* include an encoding. How can we deal with these? */
+ if ( decoder->glyph_names == 0 )
+ {
+ FT_ERROR(( "t1operator_seac:" ));
+ FT_ERROR(( " glyph names table not available in this font!\n" ));
+ return PSaux_Err_Syntax_Error;
+ }
+
+ bchar_index = t1_lookup_glyph_by_stdcharcode( decoder, bchar );
+ achar_index = t1_lookup_glyph_by_stdcharcode( decoder, achar );
+
+ if ( bchar_index < 0 || achar_index < 0 )
+ {
+ FT_ERROR(( "t1operator_seac:" ));
+ FT_ERROR(( " invalid seac character code arguments\n" ));
+ return PSaux_Err_Syntax_Error;
+ }
+
+ /* if we are trying to load a composite glyph, do not load the */
+ /* accent character and return the array of subglyphs. */
+ if ( decoder->builder.no_recurse )
+ {
+ FT_GlyphSlot glyph = (FT_GlyphSlot)decoder->builder.glyph;
+ FT_GlyphLoader loader = glyph->internal->loader;
+ FT_SubGlyph subg;
+
+
+ /* reallocate subglyph array if necessary */
+ error = FT_GlyphLoader_CheckSubGlyphs( loader, 2 );
+ if ( error )
+ goto Exit;
+
+ subg = loader->current.subglyphs;
+
+ /* subglyph 0 = base character */
+ subg->index = bchar_index;
+ subg->flags = FT_SUBGLYPH_FLAG_ARGS_ARE_XY_VALUES |
+ FT_SUBGLYPH_FLAG_USE_MY_METRICS;
+ subg->arg1 = 0;
+ subg->arg2 = 0;
+ subg++;
+
+ /* subglyph 1 = accent character */
+ subg->index = achar_index;
+ subg->flags = FT_SUBGLYPH_FLAG_ARGS_ARE_XY_VALUES;
+ subg->arg1 = adx - asb;
+ subg->arg2 = ady;
+
+ /* set up remaining glyph fields */
+ glyph->num_subglyphs = 2;
+ glyph->subglyphs = loader->base.subglyphs;
+ glyph->format = FT_GLYPH_FORMAT_COMPOSITE;
+
+ loader->current.num_subglyphs = 2;
+ goto Exit;
+ }
+
+ /* First load `bchar' in builder */
+ /* now load the unscaled outline */
+
+ FT_GlyphLoader_Prepare( decoder->builder.loader ); /* prepare loader */
+
+ error = t1_decoder_parse_glyph( decoder, bchar_index );
+ if ( error )
+ goto Exit;
+
+#if 0
+ n_base_points = base->n_points;
+#endif
+
+ /* save the left bearing and width of the base character */
+ /* as they will be erased by the next load. */
+
+ left_bearing = decoder->builder.left_bearing;
+ advance = decoder->builder.advance;
+
+ decoder->builder.left_bearing.x = 0;
+ decoder->builder.left_bearing.y = 0;
+
+ decoder->builder.pos_x = adx - asb;
+ decoder->builder.pos_y = ady;
+
+ /* Now load `achar' on top of */
+ /* the base outline */
+ error = t1_decoder_parse_glyph( decoder, achar_index );
+ if ( error )
+ goto Exit;
+
+ /* restore the left side bearing and */
+ /* advance width of the base character */
+
+ decoder->builder.left_bearing = left_bearing;
+ decoder->builder.advance = advance;
+
+ /* XXX: old code doesn't work with PostScript hinter */
+#if 0
+ /* Finally, move the accent */
+ if ( decoder->builder.load_points )
+ {
+ FT_Outline dummy;
+
+
+ dummy.n_points = (short)( base->n_points - n_base_points );
+ dummy.points = base->points + n_base_points;
+
+ FT_Outline_Translate( &dummy, adx - asb, ady );
+ }
+#else
+ decoder->builder.pos_x = 0;
+ decoder->builder.pos_y = 0;
+#endif
+
+ Exit:
+ return error;
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* t1_decoder_parse_charstrings */
+ /* */
+ /* <Description> */
+ /* Parses a given Type 1 charstrings program. */
+ /* */
+ /* <Input> */
+ /* decoder :: The current Type 1 decoder. */
+ /* */
+ /* charstring_base :: The base address of the charstring stream. */
+ /* */
+ /* charstring_len :: The length in bytes of the charstring stream. */
+ /* */
+ /* <Return> */
+ /* FreeType error code. 0 means success. */
+ /* */
+ FT_LOCAL_DEF( FT_Error )
+ t1_decoder_parse_charstrings( T1_Decoder decoder,
+ FT_Byte* charstring_base,
+ FT_UInt charstring_len )
+ {
+ FT_Error error;
+ T1_Decoder_Zone zone;
+ FT_Byte* ip;
+ FT_Byte* limit;
+ T1_Builder builder = &decoder->builder;
+ FT_Pos x, y, orig_x, orig_y;
+
+ T1_Hints_Funcs hinter;
+
+
+ /* we don't want to touch the source code -- use macro trick */
+#define start_point t1_builder_start_point
+#define check_points t1_builder_check_points
+#define add_point t1_builder_add_point
+#define add_point1 t1_builder_add_point1
+#define add_contour t1_builder_add_contour
+#define close_contour t1_builder_close_contour
+
+ /* First of all, initialize the decoder */
+ decoder->top = decoder->stack;
+ decoder->zone = decoder->zones;
+ zone = decoder->zones;
+
+ builder->path_begun = 0;
+
+ hinter = (T1_Hints_Funcs)builder->hints_funcs;
+
+ zone->base = charstring_base;
+ limit = zone->limit = charstring_base + charstring_len;
+ ip = zone->cursor = zone->base;
+
+ error = PSaux_Err_Ok;
+
+ x = orig_x = builder->pos_x;
+ y = orig_y = builder->pos_y;
+
+ /* begin hints recording session, if any */
+ if ( hinter )
+ hinter->open( hinter->hints );
+
+ /* now, execute loop */
+ while ( ip < limit )
+ {
+ FT_Long* top = decoder->top;
+ T1_Operator op = op_none;
+ FT_Long value = 0;
+
+
+ /*********************************************************************/
+ /* */
+ /* Decode operator or operand */
+ /* */
+ /* */
+
+ /* first of all, decompress operator or value */
+ switch ( *ip++ )
+ {
+ case 1:
+ op = op_hstem;
+ break;
+
+ case 3:
+ op = op_vstem;
+ break;
+ case 4:
+ op = op_vmoveto;
+ break;
+ case 5:
+ op = op_rlineto;
+ break;
+ case 6:
+ op = op_hlineto;
+ break;
+ case 7:
+ op = op_vlineto;
+ break;
+ case 8:
+ op = op_rrcurveto;
+ break;
+ case 9:
+ op = op_closepath;
+ break;
+ case 10:
+ op = op_callsubr;
+ break;
+ case 11:
+ op = op_return;
+ break;
+
+ case 13:
+ op = op_hsbw;
+ break;
+ case 14:
+ op = op_endchar;
+ break;
+
+ case 15: /* undocumented, obsolete operator */
+ op = op_none;
+ break;
+
+ case 21:
+ op = op_rmoveto;
+ break;
+ case 22:
+ op = op_hmoveto;
+ break;
+
+ case 30:
+ op = op_vhcurveto;
+ break;
+ case 31:
+ op = op_hvcurveto;
+ break;
+
+ case 12:
+ if ( ip > limit )
+ {
+ FT_ERROR(( "t1_decoder_parse_charstrings: "
+ "invalid escape (12+EOF)\n" ));
+ goto Syntax_Error;
+ }
+
+ switch ( *ip++ )
+ {
+ case 0:
+ op = op_dotsection;
+ break;
+ case 1:
+ op = op_vstem3;
+ break;
+ case 2:
+ op = op_hstem3;
+ break;
+ case 6:
+ op = op_seac;
+ break;
+ case 7:
+ op = op_sbw;
+ break;
+ case 12:
+ op = op_div;
+ break;
+ case 16:
+ op = op_callothersubr;
+ break;
+ case 17:
+ op = op_pop;
+ break;
+ case 33:
+ op = op_setcurrentpoint;
+ break;
+
+ default:
+ FT_ERROR(( "t1_decoder_parse_charstrings: "
+ "invalid escape (12+%d)\n",
+ ip[-1] ));
+ goto Syntax_Error;
+ }
+ break;
+
+ case 255: /* four bytes integer */
+ if ( ip + 4 > limit )
+ {
+ FT_ERROR(( "t1_decoder_parse_charstrings: "
+ "unexpected EOF in integer\n" ));
+ goto Syntax_Error;
+ }
+
+ value = (FT_Int32)( ((FT_Long)ip[0] << 24) |
+ ((FT_Long)ip[1] << 16) |
+ ((FT_Long)ip[2] << 8 ) |
+ ip[3] );
+ ip += 4;
+ break;
+
+ default:
+ if ( ip[-1] >= 32 )
+ {
+ if ( ip[-1] < 247 )
+ value = (FT_Long)ip[-1] - 139;
+ else
+ {
+ if ( ++ip > limit )
+ {
+ FT_ERROR(( "t1_decoder_parse_charstrings: " ));
+ FT_ERROR(( "unexpected EOF in integer\n" ));
+ goto Syntax_Error;
+ }
+
+ if ( ip[-2] < 251 )
+ value = ( ( (FT_Long)ip[-2] - 247 ) << 8 ) + ip[-1] + 108;
+ else
+ value = -( ( ( (FT_Long)ip[-2] - 251 ) << 8 ) + ip[-1] + 108 );
+ }
+ }
+ else
+ {
+ FT_ERROR(( "t1_decoder_parse_charstrings: "
+ "invalid byte (%d)\n", ip[-1] ));
+ goto Syntax_Error;
+ }
+ }
+
+ /*********************************************************************/
+ /* */
+ /* Push value on stack, or process operator */
+ /* */
+ /* */
+ if ( op == op_none )
+ {
+ if ( top - decoder->stack >= T1_MAX_CHARSTRINGS_OPERANDS )
+ {
+ FT_ERROR(( "t1_decoder_parse_charstrings: stack overflow!\n" ));
+ goto Syntax_Error;
+ }
+
+ FT_TRACE4(( " %ld", value ));
+
+ *top++ = value;
+ decoder->top = top;
+ }
+ else if ( op == op_callothersubr ) /* callothersubr */
+ {
+ FT_TRACE4(( " callothersubr" ));
+
+ if ( top - decoder->stack < 2 )
+ goto Stack_Underflow;
+
+ top -= 2;
+ switch ( top[1] )
+ {
+ case 1: /* start flex feature */
+ if ( top[0] != 0 )
+ goto Unexpected_OtherSubr;
+
+ decoder->flex_state = 1;
+ decoder->num_flex_vectors = 0;
+ if ( start_point( builder, x, y ) ||
+ check_points( builder, 6 ) )
+ goto Memory_Error;
+ break;
+
+ case 2: /* add flex vectors */
+ {
+ FT_Int idx;
+
+
+ if ( top[0] != 0 )
+ goto Unexpected_OtherSubr;
+
+ /* note that we should not add a point for index 0; */
+ /* this will move our current position to the flex */
+ /* point without adding any point to the outline */
+ idx = decoder->num_flex_vectors++;
+ if ( idx > 0 && idx < 7 )
+ add_point( builder,
+ x,
+ y,
+ (FT_Byte)( idx == 3 || idx == 6 ) );
+ }
+ break;
+
+ case 0: /* end flex feature */
+ if ( top[0] != 3 )
+ goto Unexpected_OtherSubr;
+
+ if ( decoder->flex_state == 0 ||
+ decoder->num_flex_vectors != 7 )
+ {
+ FT_ERROR(( "t1_decoder_parse_charstrings: "
+ "unexpected flex end\n" ));
+ goto Syntax_Error;
+ }
+
+ /* now consume the remaining `pop pop setcurpoint' */
+ if ( ip + 6 > limit ||
+ ip[0] != 12 || ip[1] != 17 || /* pop */
+ ip[2] != 12 || ip[3] != 17 || /* pop */
+ ip[4] != 12 || ip[5] != 33 ) /* setcurpoint */
+ {
+ FT_ERROR(( "t1_decoder_parse_charstrings: "
+ "invalid flex charstring\n" ));
+ goto Syntax_Error;
+ }
+
+ ip += 6;
+ decoder->flex_state = 0;
+ break;
+
+ case 3: /* change hints */
+ if ( top[0] != 1 )
+ goto Unexpected_OtherSubr;
+
+ /* eat the following `pop' */
+ if ( ip + 2 > limit )
+ {
+ FT_ERROR(( "t1_decoder_parse_charstrings: "
+ "invalid escape (12+%d)\n", ip[-1] ));
+ goto Syntax_Error;
+ }
+
+ if ( ip[0] != 12 || ip[1] != 17 )
+ {
+ FT_ERROR(( "t1_decoder_parse_charstrings: " ));
+ FT_ERROR(( "`pop' expected, found (%d %d)\n", ip[0], ip[1] ));
+ goto Syntax_Error;
+ }
+ ip += 2;
+
+ if ( hinter )
+ hinter->reset( hinter->hints, builder->current->n_points );
+
+ break;
+
+ case 12:
+ case 13:
+ /* counter control hints, clear stack */
+ top = decoder->stack;
+ break;
+
+ case 14:
+ case 15:
+ case 16:
+ case 17:
+ case 18: /* multiple masters */
+ {
+ PS_Blend blend = decoder->blend;
+ FT_UInt num_points, nn, mm;
+ FT_Long* delta;
+ FT_Long* values;
+
+
+ if ( !blend )
+ {
+ FT_ERROR(( "t1_decoder_parse_charstrings: " ));
+ FT_ERROR(( "unexpected multiple masters operator!\n" ));
+ goto Syntax_Error;
+ }
+
+ num_points = (FT_UInt)top[1] - 13 + ( top[1] == 18 );
+ if ( top[0] != (FT_Int)( num_points * blend->num_designs ) )
+ {
+ FT_ERROR(( "t1_decoder_parse_charstrings: " ));
+ FT_ERROR(( "incorrect number of mm arguments\n" ));
+ goto Syntax_Error;
+ }
+
+ top -= blend->num_designs * num_points;
+ if ( top < decoder->stack )
+ goto Stack_Underflow;
+
+ /* we want to compute: */
+ /* */
+ /* a0*w0 + a1*w1 + ... + ak*wk */
+ /* */
+ /* but we only have the a0, a1-a0, a2-a0, .. ak-a0 */
+ /* however, given that w0 + w1 + ... + wk == 1, we can */
+ /* rewrite it easily as: */
+ /* */
+ /* a0 + (a1-a0)*w1 + (a2-a0)*w2 + .. + (ak-a0)*wk */
+ /* */
+ /* where k == num_designs-1 */
+ /* */
+ /* I guess that's why it's written in this `compact' */
+ /* form. */
+ /* */
+ delta = top + num_points;
+ values = top;
+ for ( nn = 0; nn < num_points; nn++ )
+ {
+ FT_Int tmp = values[0];
+
+
+ for ( mm = 1; mm < blend->num_designs; mm++ )
+ tmp += FT_MulFix( *delta++, blend->weight_vector[mm] );
+
+ *values++ = tmp;
+ }
+ /* note that `top' will be incremented later by calls to `pop' */
+ break;
+ }
+
+ default:
+ Unexpected_OtherSubr:
+ FT_ERROR(( "t1_decoder_parse_charstrings: "
+ "invalid othersubr [%d %d]!\n", top[0], top[1] ));
+ goto Syntax_Error;
+ }
+ decoder->top = top;
+ }
+ else /* general operator */
+ {
+ FT_Int num_args = t1_args_count[op];
+
+
+ if ( top - decoder->stack < num_args )
+ goto Stack_Underflow;
+
+ top -= num_args;
+
+ switch ( op )
+ {
+ case op_endchar:
+ FT_TRACE4(( " endchar" ));
+
+ close_contour( builder );
+
+ /* close hints recording session */
+ if ( hinter )
+ {
+ if (hinter->close( hinter->hints, builder->current->n_points ))
+ goto Syntax_Error;
+
+ /* apply hints to the loaded glyph outline now */
+ hinter->apply( hinter->hints,
+ builder->current,
+ (PSH_Globals) builder->hints_globals,
+ decoder->hint_mode );
+ }
+
+ /* add current outline to the glyph slot */
+ FT_GlyphLoader_Add( builder->loader );
+
+ /* return now! */
+ FT_TRACE4(( "\n\n" ));
+ return PSaux_Err_Ok;
+
+ case op_hsbw:
+ FT_TRACE4(( " hsbw" ));
+
+ builder->left_bearing.x += top[0];
+ builder->advance.x = top[1];
+ builder->advance.y = 0;
+
+ orig_x = builder->last.x = x = builder->pos_x + top[0];
+ orig_y = builder->last.y = y = builder->pos_y;
+
+ FT_UNUSED( orig_y );
+
+ /* the `metrics_only' indicates that we only want to compute */
+ /* the glyph's metrics (lsb + advance width), not load the */
+ /* rest of it; so exit immediately */
+ if ( builder->metrics_only )
+ return PSaux_Err_Ok;
+
+ break;
+
+ case op_seac:
+ /* return immediately after the processing */
+ return t1operator_seac( decoder, top[0], top[1],
+ top[2], top[3], top[4] );
+
+ case op_sbw:
+ FT_TRACE4(( " sbw" ));
+
+ builder->left_bearing.x += top[0];
+ builder->left_bearing.y += top[1];
+ builder->advance.x = top[2];
+ builder->advance.y = top[3];
+
+ builder->last.x = x = builder->pos_x + top[0];
+ builder->last.y = y = builder->pos_y + top[1];
+
+ /* the `metrics_only' indicates that we only want to compute */
+ /* the glyph's metrics (lsb + advance width), not load the */
+ /* rest of it; so exit immediately */
+ if ( builder->metrics_only )
+ return PSaux_Err_Ok;
+
+ break;
+
+ case op_closepath:
+ FT_TRACE4(( " closepath" ));
+
+ close_contour( builder );
+ builder->path_begun = 0;
+ break;
+
+ case op_hlineto:
+ FT_TRACE4(( " hlineto" ));
+
+ if ( start_point( builder, x, y ) )
+ goto Memory_Error;
+
+ x += top[0];
+ goto Add_Line;
+
+ case op_hmoveto:
+ FT_TRACE4(( " hmoveto" ));
+
+ x += top[0];
+ if ( !decoder->flex_state )
+ builder->path_begun = 0;
+ break;
+
+ case op_hvcurveto:
+ FT_TRACE4(( " hvcurveto" ));
+
+ if ( start_point( builder, x, y ) ||
+ check_points( builder, 3 ) )
+ goto Memory_Error;
+
+ x += top[0];
+ add_point( builder, x, y, 0 );
+ x += top[1];
+ y += top[2];
+ add_point( builder, x, y, 0 );
+ y += top[3];
+ add_point( builder, x, y, 1 );
+ break;
+
+ case op_rlineto:
+ FT_TRACE4(( " rlineto" ));
+
+ if ( start_point( builder, x, y ) )
+ goto Memory_Error;
+
+ x += top[0];
+ y += top[1];
+
+ Add_Line:
+ if ( add_point1( builder, x, y ) )
+ goto Memory_Error;
+ break;
+
+ case op_rmoveto:
+ FT_TRACE4(( " rmoveto" ));
+
+ x += top[0];
+ y += top[1];
+ if ( !decoder->flex_state )
+ builder->path_begun = 0;
+ break;
+
+ case op_rrcurveto:
+ FT_TRACE4(( " rcurveto" ));
+
+ if ( start_point( builder, x, y ) ||
+ check_points( builder, 3 ) )
+ goto Memory_Error;
+
+ x += top[0];
+ y += top[1];
+ add_point( builder, x, y, 0 );
+
+ x += top[2];
+ y += top[3];
+ add_point( builder, x, y, 0 );
+
+ x += top[4];
+ y += top[5];
+ add_point( builder, x, y, 1 );
+ break;
+
+ case op_vhcurveto:
+ FT_TRACE4(( " vhcurveto" ));
+
+ if ( start_point( builder, x, y ) ||
+ check_points( builder, 3 ) )
+ goto Memory_Error;
+
+ y += top[0];
+ add_point( builder, x, y, 0 );
+ x += top[1];
+ y += top[2];
+ add_point( builder, x, y, 0 );
+ x += top[3];
+ add_point( builder, x, y, 1 );
+ break;
+
+ case op_vlineto:
+ FT_TRACE4(( " vlineto" ));
+
+ if ( start_point( builder, x, y ) )
+ goto Memory_Error;
+
+ y += top[0];
+ goto Add_Line;
+
+ case op_vmoveto:
+ FT_TRACE4(( " vmoveto" ));
+
+ y += top[0];
+ if ( !decoder->flex_state )
+ builder->path_begun = 0;
+ break;
+
+ case op_div:
+ FT_TRACE4(( " div" ));
+
+ if ( top[1] )
+ {
+ *top = top[0] / top[1];
+ ++top;
+ }
+ else
+ {
+ FT_ERROR(( "t1_decoder_parse_charstrings: division by 0\n" ));
+ goto Syntax_Error;
+ }
+ break;
+
+ case op_callsubr:
+ {
+ FT_Int idx;
+
+
+ FT_TRACE4(( " callsubr" ));
+
+ idx = top[0];
+ if ( idx < 0 || idx >= (FT_Int)decoder->num_subrs )
+ {
+ FT_ERROR(( "t1_decoder_parse_charstrings: "
+ "invalid subrs index\n" ));
+ goto Syntax_Error;
+ }
+
+ if ( zone - decoder->zones >= T1_MAX_SUBRS_CALLS )
+ {
+ FT_ERROR(( "t1_decoder_parse_charstrings: "
+ "too many nested subrs\n" ));
+ goto Syntax_Error;
+ }
+
+ zone->cursor = ip; /* save current instruction pointer */
+
+ zone++;
+
+ /* The Type 1 driver stores subroutines without the seed bytes. */
+ /* The CID driver stores subroutines with seed bytes. This */
+ /* case is taken care of when decoder->subrs_len == 0. */
+ zone->base = decoder->subrs[idx];
+
+ if ( decoder->subrs_len )
+ zone->limit = zone->base + decoder->subrs_len[idx];
+ else
+ {
+ /* We are using subroutines from a CID font. We must adjust */
+ /* for the seed bytes. */
+ zone->base += ( decoder->lenIV >= 0 ? decoder->lenIV : 0 );
+ zone->limit = decoder->subrs[idx + 1];
+ }
+
+ zone->cursor = zone->base;
+
+ if ( !zone->base )
+ {
+ FT_ERROR(( "t1_decoder_parse_charstrings: "
+ "invoking empty subrs!\n" ));
+ goto Syntax_Error;
+ }
+
+ decoder->zone = zone;
+ ip = zone->base;
+ limit = zone->limit;
+ break;
+ }
+
+ case op_pop:
+ FT_TRACE4(( " pop" ));
+
+ /* theoretically, the arguments are already on the stack */
+ top++;
+ break;
+
+ case op_return:
+ FT_TRACE4(( " return" ));
+
+ if ( zone <= decoder->zones )
+ {
+ FT_ERROR(( "t1_decoder_parse_charstrings: unexpected return\n" ));
+ goto Syntax_Error;
+ }
+
+ zone--;
+ ip = zone->cursor;
+ limit = zone->limit;
+ decoder->zone = zone;
+ break;
+
+ case op_dotsection:
+ FT_TRACE4(( " dotsection" ));
+
+ break;
+
+ case op_hstem:
+ FT_TRACE4(( " hstem" ));
+
+ /* record horizontal hint */
+ if ( hinter )
+ {
+ /* top[0] += builder->left_bearing.y; */
+ hinter->stem( hinter->hints, 1, top );
+ }
+
+ break;
+
+ case op_hstem3:
+ FT_TRACE4(( " hstem3" ));
+
+ /* record horizontal counter-controlled hints */
+ if ( hinter )
+ hinter->stem3( hinter->hints, 1, top );
+
+ break;
+
+ case op_vstem:
+ FT_TRACE4(( " vstem" ));
+
+ /* record vertical hint */
+ if ( hinter )
+ {
+ top[0] += orig_x;
+ hinter->stem( hinter->hints, 0, top );
+ }
+
+ break;
+
+ case op_vstem3:
+ FT_TRACE4(( " vstem3" ));
+
+ /* record vertical counter-controlled hints */
+ if ( hinter )
+ {
+ FT_Pos dx = orig_x;
+
+
+ top[0] += dx;
+ top[2] += dx;
+ top[4] += dx;
+ hinter->stem3( hinter->hints, 0, top );
+ }
+ break;
+
+ case op_setcurrentpoint:
+ FT_TRACE4(( " setcurrentpoint" ));
+
+ FT_ERROR(( "t1_decoder_parse_charstrings: " ));
+ FT_ERROR(( "unexpected `setcurrentpoint'\n" ));
+ goto Syntax_Error;
+
+ default:
+ FT_ERROR(( "t1_decoder_parse_charstrings: "
+ "unhandled opcode %d\n", op ));
+ goto Syntax_Error;
+ }
+
+ decoder->top = top;
+
+ } /* general operator processing */
+
+ } /* while ip < limit */
+
+ FT_TRACE4(( "..end..\n\n" ));
+
+ return error;
+
+ Syntax_Error:
+ return PSaux_Err_Syntax_Error;
+
+ Stack_Underflow:
+ return PSaux_Err_Stack_Underflow;
+
+ Memory_Error:
+ return builder->error;
+ }
+
+
+ /* parse a single Type 1 glyph */
+ FT_LOCAL_DEF( FT_Error )
+ t1_decoder_parse_glyph( T1_Decoder decoder,
+ FT_UInt glyph )
+ {
+ return decoder->parse_callback( decoder, glyph );
+ }
+
+
+ /* initialize T1 decoder */
+ FT_LOCAL_DEF( FT_Error )
+ t1_decoder_init( T1_Decoder decoder,
+ FT_Face face,
+ FT_Size size,
+ FT_GlyphSlot slot,
+ FT_Byte** glyph_names,
+ PS_Blend blend,
+ FT_Bool hinting,
+ FT_Render_Mode hint_mode,
+ T1_Decoder_Callback parse_callback )
+ {
+ FT_MEM_ZERO( decoder, sizeof ( *decoder ) );
+
+ /* retrieve PSNames interface from list of current modules */
+ {
+ PSNames_Service psnames = 0;
+
+
+ psnames = (PSNames_Service)FT_Get_Module_Interface(
+ FT_FACE_LIBRARY(face), "psnames" );
+ if ( !psnames )
+ {
+ FT_ERROR(( "t1_decoder_init: " ));
+ FT_ERROR(( "the `psnames' module is not available\n" ));
+ return PSaux_Err_Unimplemented_Feature;
+ }
+
+ decoder->psnames = psnames;
+ }
+
+ t1_builder_init( &decoder->builder, face, size, slot, hinting );
+
+ decoder->num_glyphs = (FT_UInt)face->num_glyphs;
+ decoder->glyph_names = glyph_names;
+ decoder->hint_flags = face->internal->hint_flags;
+ decoder->hint_mode = hint_mode;
+ decoder->blend = blend;
+ decoder->parse_callback = parse_callback;
+
+ decoder->funcs = t1_decoder_funcs;
+
+ return 0;
+ }
+
+
+ /* finalize T1 decoder */
+ FT_LOCAL_DEF( void )
+ t1_decoder_done( T1_Decoder decoder )
+ {
+ t1_builder_done( &decoder->builder );
+ }
+
+
+/* END */
--- /dev/null
+++ b/libfreetype/t1decode.h
@@ -1,0 +1,65 @@
+/***************************************************************************/
+/* */
+/* t1decode.h */
+/* */
+/* PostScript Type 1 decoding routines (specification). */
+/* */
+/* Copyright 2000-2001, 2002 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+
+#ifndef __T1DECODE_H__
+#define __T1DECODE_H__
+
+
+#include <ft2build.h>
+#include FT_INTERNAL_POSTSCRIPT_AUX_H
+#include FT_INTERNAL_POSTSCRIPT_NAMES_H
+#include FT_INTERNAL_TYPE1_TYPES_H
+
+
+FT_BEGIN_HEADER
+
+
+ FT_CALLBACK_TABLE
+ const T1_Decoder_FuncsRec t1_decoder_funcs;
+
+
+ FT_LOCAL( FT_Error )
+ t1_decoder_parse_glyph( T1_Decoder decoder,
+ FT_UInt glyph_index );
+
+ FT_LOCAL( FT_Error )
+ t1_decoder_parse_charstrings( T1_Decoder decoder,
+ FT_Byte* base,
+ FT_UInt len );
+
+ FT_LOCAL( FT_Error )
+ t1_decoder_init( T1_Decoder decoder,
+ FT_Face face,
+ FT_Size size,
+ FT_GlyphSlot slot,
+ FT_Byte** glyph_names,
+ PS_Blend blend,
+ FT_Bool hinting,
+ FT_Render_Mode hint_mode,
+ T1_Decoder_Callback parse_glyph );
+
+ FT_LOCAL( void )
+ t1_decoder_done( T1_Decoder decoder );
+
+
+FT_END_HEADER
+
+#endif /* __T1DECODE_H__ */
+
+
+/* END */
--- /dev/null
+++ b/libfreetype/t1driver.c
@@ -1,0 +1,279 @@
+/***************************************************************************/
+/* */
+/* t1driver.c */
+/* */
+/* Type 1 driver interface (body). */
+/* */
+/* Copyright 1996-2001, 2002 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+
+#include <ft2build.h>
+#include "t1driver.h"
+#include "t1gload.h"
+#include "t1load.h"
+
+#include "t1errors.h"
+
+#ifndef T1_CONFIG_OPTION_NO_AFM
+#include "t1afm.h"
+#endif
+
+#include FT_INTERNAL_DEBUG_H
+#include FT_INTERNAL_STREAM_H
+#include FT_INTERNAL_POSTSCRIPT_NAMES_H
+
+
+ /*************************************************************************/
+ /* */
+ /* The macro FT_COMPONENT is used in trace mode. It is an implicit */
+ /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log */
+ /* messages during execution. */
+ /* */
+#undef FT_COMPONENT
+#define FT_COMPONENT trace_t1driver
+
+
+ static FT_Error
+ t1_get_glyph_name( T1_Face face,
+ FT_UInt glyph_index,
+ FT_Pointer buffer,
+ FT_UInt buffer_max )
+ {
+ FT_String* gname;
+
+
+ gname = face->type1.glyph_names[glyph_index];
+
+ if ( buffer_max > 0 )
+ {
+ FT_UInt len = (FT_UInt)( ft_strlen( gname ) );
+
+
+ if (len >= buffer_max)
+ len = buffer_max - 1;
+
+ FT_MEM_COPY( buffer, gname, len );
+ ((FT_Byte*)buffer)[len] = 0;
+ }
+
+ return T1_Err_Ok;
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* t1_get_name_index */
+ /* */
+ /* <Description> */
+ /* Uses the Type 1 font's `glyph_names' table to find a given glyph */
+ /* name's glyph index. */
+ /* */
+ /* <Input> */
+ /* face :: A handle to the source face object. */
+ /* */
+ /* glyph_name :: The glyph name. */
+ /* */
+ /* <Return> */
+ /* Glyph index. 0 means `undefined character code'. */
+ /* */
+ static FT_UInt
+ t1_get_name_index( T1_Face face,
+ FT_String* glyph_name )
+ {
+ FT_Int i;
+ FT_String* gname;
+
+
+ for ( i = 0; i < face->type1.num_glyphs; i++ )
+ {
+ gname = face->type1.glyph_names[i];
+
+ if ( !ft_strcmp( glyph_name, gname ) )
+ return (FT_UInt)i;
+ }
+
+ return 0;
+ }
+
+
+ static const char*
+ t1_get_ps_name( T1_Face face )
+ {
+ return (const char*) face->type1.font_name;
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* Get_Interface */
+ /* */
+ /* <Description> */
+ /* Each driver can provide one or more extensions to the base */
+ /* FreeType API. These can be used to access format specific */
+ /* features (e.g., all TrueType/OpenType resources share a common */
+ /* file structure and common tables which can be accessed through the */
+ /* `sfnt' interface), or more simply generic ones (e.g., the */
+ /* `postscript names' interface which can be used to retrieve the */
+ /* PostScript name of a given glyph index). */
+ /* */
+ /* <InOut> */
+ /* driver :: A handle to a driver object. */
+ /* */
+ /* <Input> */
+ /* t1_interface :: A string designing the interface. Examples are */
+ /* `sfnt', `post_names', `charmaps', etc. */
+ /* */
+ /* <Return> */
+ /* A typeless pointer to the extension's interface (normally a table */
+ /* of function pointers). Returns NULL if the requested extension */
+ /* isn't available (i.e., wasn't compiled in the driver at build */
+ /* time). */
+ /* */
+ static FT_Module_Interface
+ Get_Interface( FT_Driver driver,
+ const FT_String* t1_interface )
+ {
+ FT_UNUSED( driver );
+ FT_UNUSED( t1_interface );
+
+ if ( ft_strcmp( (const char*)t1_interface, "glyph_name" ) == 0 )
+ return (FT_Module_Interface)t1_get_glyph_name;
+
+ if ( ft_strcmp( (const char*)t1_interface, "name_index" ) == 0 )
+ return (FT_Module_Interface)t1_get_name_index;
+
+ if ( ft_strcmp( (const char*)t1_interface, "postscript_name" ) == 0 )
+ return (FT_Module_Interface)t1_get_ps_name;
+
+#ifndef T1_CONFIG_OPTION_NO_MM_SUPPORT
+ if ( ft_strcmp( (const char*)t1_interface, "get_mm" ) == 0 )
+ return (FT_Module_Interface)T1_Get_Multi_Master;
+
+ if ( ft_strcmp( (const char*)t1_interface, "set_mm_design") == 0 )
+ return (FT_Module_Interface)T1_Set_MM_Design;
+
+ if ( ft_strcmp( (const char*)t1_interface, "set_mm_blend") == 0 )
+ return (FT_Module_Interface)T1_Set_MM_Blend;
+#endif
+ return 0;
+ }
+
+
+#ifndef T1_CONFIG_OPTION_NO_AFM
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* Get_Kerning */
+ /* */
+ /* <Description> */
+ /* A driver method used to return the kerning vector between two */
+ /* glyphs of the same face. */
+ /* */
+ /* <Input> */
+ /* face :: A handle to the source face object. */
+ /* */
+ /* left_glyph :: The index of the left glyph in the kern pair. */
+ /* */
+ /* right_glyph :: The index of the right glyph in the kern pair. */
+ /* */
+ /* <Output> */
+ /* kerning :: The kerning vector. This is in font units for */
+ /* scalable formats, and in pixels for fixed-sizes */
+ /* formats. */
+ /* */
+ /* <Return> */
+ /* FreeType error code. 0 means success. */
+ /* */
+ /* <Note> */
+ /* Only horizontal layouts (left-to-right & right-to-left) are */
+ /* supported by this function. Other layouts, or more sophisticated */
+ /* kernings are out of scope of this method (the basic driver */
+ /* interface is meant to be simple). */
+ /* */
+ /* They can be implemented by format-specific interfaces. */
+ /* */
+ static FT_Error
+ Get_Kerning( T1_Face face,
+ FT_UInt left_glyph,
+ FT_UInt right_glyph,
+ FT_Vector* kerning )
+ {
+ T1_AFM* afm;
+
+
+ kerning->x = 0;
+ kerning->y = 0;
+
+ afm = (T1_AFM*)face->afm_data;
+ if ( afm )
+ T1_Get_Kerning( afm, left_glyph, right_glyph, kerning );
+
+ return T1_Err_Ok;
+ }
+
+
+#endif /* T1_CONFIG_OPTION_NO_AFM */
+
+
+
+
+ FT_CALLBACK_TABLE_DEF
+ const FT_Driver_ClassRec t1_driver_class =
+ {
+ {
+ ft_module_font_driver |
+ ft_module_driver_scalable |
+ ft_module_driver_has_hinter,
+
+ sizeof( FT_DriverRec ),
+
+ "type1",
+ 0x10000L,
+ 0x20000L,
+
+ 0, /* format interface */
+
+ (FT_Module_Constructor)T1_Driver_Init,
+ (FT_Module_Destructor) T1_Driver_Done,
+ (FT_Module_Requester) Get_Interface,
+ },
+
+ sizeof( T1_FaceRec ),
+ sizeof( T1_SizeRec ),
+ sizeof( T1_GlyphSlotRec ),
+
+ (FT_Face_InitFunc) T1_Face_Init,
+ (FT_Face_DoneFunc) T1_Face_Done,
+ (FT_Size_InitFunc) T1_Size_Init,
+ (FT_Size_DoneFunc) T1_Size_Done,
+ (FT_Slot_InitFunc) T1_GlyphSlot_Init,
+ (FT_Slot_DoneFunc) T1_GlyphSlot_Done,
+
+ (FT_Size_ResetPointsFunc) T1_Size_Reset,
+ (FT_Size_ResetPixelsFunc) T1_Size_Reset,
+ (FT_Slot_LoadFunc) T1_Load_Glyph,
+
+#ifdef T1_CONFIG_OPTION_NO_AFM
+ (FT_Face_GetKerningFunc) 0,
+ (FT_Face_AttachFunc) 0,
+#else
+ (FT_Face_GetKerningFunc) Get_Kerning,
+ (FT_Face_AttachFunc) T1_Read_AFM,
+#endif
+ (FT_Face_GetAdvancesFunc) 0
+ };
+
+
+/* END */
--- /dev/null
+++ b/libfreetype/t1driver.h
@@ -1,0 +1,38 @@
+/***************************************************************************/
+/* */
+/* t1driver.h */
+/* */
+/* High-level Type 1 driver interface (specification). */
+/* */
+/* Copyright 1996-2001, 2002 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+
+#ifndef __T1DRIVER_H__
+#define __T1DRIVER_H__
+
+
+#include <ft2build.h>
+#include FT_INTERNAL_DRIVER_H
+
+
+FT_BEGIN_HEADER
+
+
+ FT_EXPORT_VAR( const FT_Driver_ClassRec ) t1_driver_class;
+
+
+FT_END_HEADER
+
+#endif /* __T1DRIVER_H__ */
+
+
+/* END */
--- /dev/null
+++ b/libfreetype/t1errors.h
@@ -1,0 +1,40 @@
+/***************************************************************************/
+/* */
+/* t1errors.h */
+/* */
+/* Type 1 error codes (specification only). */
+/* */
+/* Copyright 2001 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+
+ /*************************************************************************/
+ /* */
+ /* This file is used to define the Type 1 error enumeration constants. */
+ /* */
+ /*************************************************************************/
+
+#ifndef __T1ERRORS_H__
+#define __T1ERRORS_H__
+
+#include FT_MODULE_ERRORS_H
+
+#undef __FTERRORS_H__
+
+#define FT_ERR_PREFIX T1_Err_
+#define FT_ERR_BASE FT_Mod_Err_Type1
+
+#include FT_ERRORS_H
+
+#endif /* __T1ERRORS_H__ */
+
+
+/* END */
--- /dev/null
+++ b/libfreetype/t1gload.c
@@ -1,0 +1,416 @@
+/***************************************************************************/
+/* */
+/* t1gload.c */
+/* */
+/* Type 1 Glyph Loader (body). */
+/* */
+/* Copyright 1996-2001, 2002 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+
+#include <ft2build.h>
+#include "t1gload.h"
+#include FT_INTERNAL_DEBUG_H
+#include FT_INTERNAL_STREAM_H
+#include FT_OUTLINE_H
+#include FT_INTERNAL_POSTSCRIPT_AUX_H
+
+#include "t1errors.h"
+
+
+ /*************************************************************************/
+ /* */
+ /* The macro FT_COMPONENT is used in trace mode. It is an implicit */
+ /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log */
+ /* messages during execution. */
+ /* */
+#undef FT_COMPONENT
+#define FT_COMPONENT trace_t1gload
+
+
+ /*************************************************************************/
+ /*************************************************************************/
+ /*************************************************************************/
+ /********** *********/
+ /********** COMPUTE THE MAXIMUM ADVANCE WIDTH *********/
+ /********** *********/
+ /********** The following code is in charge of computing *********/
+ /********** the maximum advance width of the font. It *********/
+ /********** quickly processes each glyph charstring to *********/
+ /********** extract the value from either a `sbw' or `seac' *********/
+ /********** operator. *********/
+ /********** *********/
+ /*************************************************************************/
+ /*************************************************************************/
+ /*************************************************************************/
+
+
+ FT_LOCAL_DEF( FT_Error )
+ T1_Parse_Glyph_And_Get_Char_String( T1_Decoder decoder,
+ FT_UInt glyph_index,
+ FT_Data* char_string )
+ {
+ T1_Face face = (T1_Face)decoder->builder.face;
+ T1_Font type1 = &face->type1;
+ FT_Error error = 0;
+
+
+ decoder->font_matrix = type1->font_matrix;
+ decoder->font_offset = type1->font_offset;
+
+#ifdef FT_CONFIG_OPTION_INCREMENTAL
+
+ /* For incremental fonts get the character data using the */
+ /* callback function. */
+ if ( face->root.internal->incremental_interface )
+ error = face->root.internal->incremental_interface->funcs->get_glyph_data(
+ face->root.internal->incremental_interface->object,
+ glyph_index, char_string );
+ else
+
+#endif
+
+ /* For ordinary fonts get the character data stored in the face record. */
+ {
+ char_string->pointer = type1->charstrings[glyph_index];
+ char_string->length = type1->charstrings_len[glyph_index];
+ }
+
+ if ( !error )
+ error = decoder->funcs.parse_charstrings(
+ decoder, (FT_Byte*)char_string->pointer,
+ char_string->length );
+
+#ifdef FT_CONFIG_OPTION_INCREMENTAL
+
+ /* Incremental fonts can optionally override the metrics. */
+ if ( !error && face->root.internal->incremental_interface &&
+ face->root.internal->incremental_interface->funcs->get_glyph_metrics )
+ {
+ FT_Bool found = FALSE;
+ FT_Incremental_MetricsRec metrics;
+
+
+ error = face->root.internal->incremental_interface->funcs->get_glyph_metrics(
+ face->root.internal->incremental_interface->object,
+ glyph_index, FALSE, &metrics, &found );
+ if ( found )
+ {
+ decoder->builder.left_bearing.x = metrics.bearing_x;
+ decoder->builder.left_bearing.y = metrics.bearing_y;
+ decoder->builder.advance.x = metrics.advance;
+ decoder->builder.advance.y = 0;
+ }
+ }
+
+#endif
+
+ return error;
+ }
+
+
+ FT_CALLBACK_DEF( FT_Error )
+ T1_Parse_Glyph( T1_Decoder decoder,
+ FT_UInt glyph_index )
+ {
+ FT_Data glyph_data;
+ FT_Error error = T1_Parse_Glyph_And_Get_Char_String(
+ decoder, glyph_index, &glyph_data );
+
+
+#ifdef FT_CONFIG_OPTION_INCREMENTAL
+ if ( !error )
+ {
+ T1_Face face = (T1_Face)decoder->builder.face;
+
+
+ if ( face->root.internal->incremental_interface )
+ face->root.internal->incremental_interface->funcs->free_glyph_data(
+ face->root.internal->incremental_interface->object,
+ &glyph_data );
+ }
+#endif
+
+ return error;
+ }
+
+
+ FT_LOCAL_DEF( FT_Error )
+ T1_Compute_Max_Advance( T1_Face face,
+ FT_Int* max_advance )
+ {
+ FT_Error error;
+ T1_DecoderRec decoder;
+ FT_Int glyph_index;
+ T1_Font type1 = &face->type1;
+ PSAux_Service psaux = (PSAux_Service)face->psaux;
+
+
+ *max_advance = 0;
+
+ /* initialize load decoder */
+ error = psaux->t1_decoder_funcs->init( &decoder,
+ (FT_Face)face,
+ 0, /* size */
+ 0, /* glyph slot */
+ (FT_Byte**)type1->glyph_names,
+ face->blend,
+ 0,
+ FT_RENDER_MODE_NORMAL,
+ T1_Parse_Glyph );
+ if ( error )
+ return error;
+
+ decoder.builder.metrics_only = 1;
+ decoder.builder.load_points = 0;
+
+ decoder.num_subrs = type1->num_subrs;
+ decoder.subrs = type1->subrs;
+ decoder.subrs_len = type1->subrs_len;
+
+ *max_advance = 0;
+
+ /* for each glyph, parse the glyph charstring and extract */
+ /* the advance width */
+ for ( glyph_index = 0; glyph_index < type1->num_glyphs; glyph_index++ )
+ {
+ /* now get load the unscaled outline */
+ error = T1_Parse_Glyph( &decoder, glyph_index );
+ if ( glyph_index == 0 || decoder.builder.advance.x > *max_advance )
+ *max_advance = decoder.builder.advance.x;
+
+ /* ignore the error if one occured - skip to next glyph */
+ }
+
+ return T1_Err_Ok;
+ }
+
+
+ /*************************************************************************/
+ /*************************************************************************/
+ /*************************************************************************/
+ /********** *********/
+ /********** UNHINTED GLYPH LOADER *********/
+ /********** *********/
+ /********** The following code is in charge of loading a *********/
+ /********** single outline. It completely ignores hinting *********/
+ /********** and is used when FT_LOAD_NO_HINTING is set. *********/
+ /********** *********/
+ /********** The Type 1 hinter is located in `t1hint.c' *********/
+ /********** *********/
+ /*************************************************************************/
+ /*************************************************************************/
+ /*************************************************************************/
+
+
+ FT_LOCAL_DEF( FT_Error )
+ T1_Load_Glyph( T1_GlyphSlot glyph,
+ T1_Size size,
+ FT_UInt glyph_index,
+ FT_Int32 load_flags )
+ {
+ FT_Error error;
+ T1_DecoderRec decoder;
+ T1_Face face = (T1_Face)glyph->root.face;
+ FT_Bool hinting;
+ T1_Font type1 = &face->type1;
+ PSAux_Service psaux = (PSAux_Service)face->psaux;
+ const T1_Decoder_Funcs decoder_funcs = psaux->t1_decoder_funcs;
+
+ FT_Matrix font_matrix;
+ FT_Vector font_offset;
+ FT_Data glyph_data;
+ FT_Bool glyph_data_loaded = 0;
+
+
+ if ( load_flags & FT_LOAD_NO_RECURSE )
+ load_flags |= FT_LOAD_NO_SCALE | FT_LOAD_NO_HINTING;
+
+ glyph->x_scale = size->root.metrics.x_scale;
+ glyph->y_scale = size->root.metrics.y_scale;
+
+ glyph->root.outline.n_points = 0;
+ glyph->root.outline.n_contours = 0;
+
+ hinting = FT_BOOL( ( load_flags & FT_LOAD_NO_SCALE ) == 0 &&
+ ( load_flags & FT_LOAD_NO_HINTING ) == 0 );
+
+ glyph->root.format = FT_GLYPH_FORMAT_OUTLINE;
+
+ error = decoder_funcs->init( &decoder,
+ (FT_Face)face,
+ (FT_Size)size,
+ (FT_GlyphSlot)glyph,
+ (FT_Byte**)type1->glyph_names,
+ face->blend,
+ FT_BOOL( hinting ),
+ FT_LOAD_TARGET_MODE(load_flags),
+ T1_Parse_Glyph );
+ if ( error )
+ goto Exit;
+
+ decoder.builder.no_recurse = FT_BOOL(
+ ( load_flags & FT_LOAD_NO_RECURSE ) != 0 );
+
+ decoder.num_subrs = type1->num_subrs;
+ decoder.subrs = type1->subrs;
+ decoder.subrs_len = type1->subrs_len;
+
+ /* now load the unscaled outline */
+ error = T1_Parse_Glyph_And_Get_Char_String( &decoder, glyph_index,
+ &glyph_data );
+ if ( error )
+ goto Exit;
+ glyph_data_loaded = 1;
+
+ font_matrix = decoder.font_matrix;
+ font_offset = decoder.font_offset;
+
+ /* save new glyph tables */
+ decoder_funcs->done( &decoder );
+
+ /* now, set the metrics -- this is rather simple, as */
+ /* the left side bearing is the xMin, and the top side */
+ /* bearing the yMax */
+ if ( !error )
+ {
+ glyph->root.outline.flags &= FT_OUTLINE_OWNER;
+ glyph->root.outline.flags |= FT_OUTLINE_REVERSE_FILL;
+
+ /* for composite glyphs, return only left side bearing and */
+ /* advance width */
+ if ( load_flags & FT_LOAD_NO_RECURSE )
+ {
+ FT_Slot_Internal internal = glyph->root.internal;
+
+
+ glyph->root.metrics.horiBearingX = decoder.builder.left_bearing.x;
+ glyph->root.metrics.horiAdvance = decoder.builder.advance.x;
+ internal->glyph_matrix = font_matrix;
+ internal->glyph_delta = font_offset;
+ internal->glyph_transformed = 1;
+ }
+ else
+ {
+ FT_BBox cbox;
+ FT_Glyph_Metrics* metrics = &glyph->root.metrics;
+
+
+ /* copy the _unscaled_ advance width */
+ metrics->horiAdvance = decoder.builder.advance.x;
+ glyph->root.linearHoriAdvance = decoder.builder.advance.x;
+ glyph->root.internal->glyph_transformed = 0;
+
+ /* make up vertical metrics */
+ metrics->vertBearingX = 0;
+ metrics->vertBearingY = 0;
+ metrics->vertAdvance = 0;
+
+ glyph->root.linearVertAdvance = 0;
+
+ glyph->root.format = FT_GLYPH_FORMAT_OUTLINE;
+
+ if ( size && size->root.metrics.y_ppem < 24 )
+ glyph->root.outline.flags |= FT_OUTLINE_HIGH_PRECISION;
+
+#if 1
+ /* apply the font matrix, if any */
+ FT_Outline_Transform( &glyph->root.outline, &font_matrix );
+
+ FT_Outline_Translate( &glyph->root.outline,
+ font_offset.x,
+ font_offset.y );
+#endif
+
+ if ( ( load_flags & FT_LOAD_NO_SCALE ) == 0 )
+ {
+ /* scale the outline and the metrics */
+ FT_Int n;
+ FT_Outline* cur = decoder.builder.base;
+ FT_Vector* vec = cur->points;
+ FT_Fixed x_scale = glyph->x_scale;
+ FT_Fixed y_scale = glyph->y_scale;
+
+
+ /* First of all, scale the points, if we are not hinting */
+ if ( !hinting )
+ for ( n = cur->n_points; n > 0; n--, vec++ )
+ {
+ vec->x = FT_MulFix( vec->x, x_scale );
+ vec->y = FT_MulFix( vec->y, y_scale );
+ }
+
+ FT_Outline_Get_CBox( &glyph->root.outline, &cbox );
+
+ /* Then scale the metrics */
+ metrics->horiAdvance = FT_MulFix( metrics->horiAdvance, x_scale );
+ metrics->vertAdvance = FT_MulFix( metrics->vertAdvance, y_scale );
+
+ metrics->vertBearingX = FT_MulFix( metrics->vertBearingX, x_scale );
+ metrics->vertBearingY = FT_MulFix( metrics->vertBearingY, y_scale );
+
+ if ( hinting )
+ {
+ metrics->horiAdvance = ( metrics->horiAdvance + 32 ) & -64;
+ metrics->vertAdvance = ( metrics->vertAdvance + 32 ) & -64;
+
+ metrics->vertBearingX = ( metrics->vertBearingX + 32 ) & -64;
+ metrics->vertBearingY = ( metrics->vertBearingY + 32 ) & -64;
+ }
+ }
+
+ /* compute the other metrics */
+ FT_Outline_Get_CBox( &glyph->root.outline, &cbox );
+
+ /* grid fit the bounding box if necessary */
+ if ( hinting )
+ {
+ cbox.xMin &= -64;
+ cbox.yMin &= -64;
+ cbox.xMax = ( cbox.xMax+63 ) & -64;
+ cbox.yMax = ( cbox.yMax+63 ) & -64;
+ }
+
+ metrics->width = cbox.xMax - cbox.xMin;
+ metrics->height = cbox.yMax - cbox.yMin;
+
+ metrics->horiBearingX = cbox.xMin;
+ metrics->horiBearingY = cbox.yMax;
+ }
+
+ /* Set control data to the glyph charstrings. Note that this is */
+ /* _not_ zero-terminated. */
+ glyph->root.control_data = (FT_Byte*)glyph_data.pointer;
+ glyph->root.control_len = glyph_data.length;
+ }
+
+
+ Exit:
+
+#ifdef FT_CONFIG_OPTION_INCREMENTAL
+ if ( glyph_data_loaded && face->root.internal->incremental_interface )
+ {
+ face->root.internal->incremental_interface->funcs->free_glyph_data(
+ face->root.internal->incremental_interface->object,
+ &glyph_data );
+
+ /* Set the control data to null - it is no longer available if */
+ /* loaded incrementally. */
+ glyph->root.control_data = 0;
+ glyph->root.control_len = 0;
+ }
+#endif
+
+ return error;
+ }
+
+
+/* END */
--- /dev/null
+++ b/libfreetype/t1gload.h
@@ -1,0 +1,46 @@
+/***************************************************************************/
+/* */
+/* t1gload.h */
+/* */
+/* Type 1 Glyph Loader (specification). */
+/* */
+/* Copyright 1996-2001, 2002 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+
+#ifndef __T1GLOAD_H__
+#define __T1GLOAD_H__
+
+
+#include <ft2build.h>
+#include "t1objs.h"
+
+
+FT_BEGIN_HEADER
+
+
+ FT_LOCAL( FT_Error )
+ T1_Compute_Max_Advance( T1_Face face,
+ FT_Int* max_advance );
+
+ FT_LOCAL( FT_Error )
+ T1_Load_Glyph( T1_GlyphSlot glyph,
+ T1_Size size,
+ FT_UInt glyph_index,
+ FT_Int32 load_flags );
+
+
+FT_END_HEADER
+
+#endif /* __T1GLOAD_H__ */
+
+
+/* END */
--- /dev/null
+++ b/libfreetype/t1load.c
@@ -1,0 +1,1791 @@
+/***************************************************************************/
+/* */
+/* t1load.c */
+/* */
+/* Type 1 font loader (body). */
+/* */
+/* Copyright 1996-2001, 2002 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+
+ /*************************************************************************/
+ /* */
+ /* This is the new and improved Type 1 data loader for FreeType 2. The */
+ /* old loader has several problems: it is slow, complex, difficult to */
+ /* maintain, and contains incredible hacks to make it accept some */
+ /* ill-formed Type 1 fonts without hiccup-ing. Moreover, about 5% of */
+ /* the Type 1 fonts on my machine still aren't loaded correctly by it. */
+ /* */
+ /* This version is much simpler, much faster and also easier to read and */
+ /* maintain by a great order of magnitude. The idea behind it is to */
+ /* _not_ try to read the Type 1 token stream with a state machine (i.e. */
+ /* a Postscript-like interpreter) but rather to perform simple pattern */
+ /* matching. */
+ /* */
+ /* Indeed, nearly all data definitions follow a simple pattern like */
+ /* */
+ /* ... /Field <data> ... */
+ /* */
+ /* where <data> can be a number, a boolean, a string, or an array of */
+ /* numbers. There are a few exceptions, namely the encoding, font name, */
+ /* charstrings, and subrs; they are handled with a special pattern */
+ /* matching routine. */
+ /* */
+ /* All other common cases are handled very simply. The matching rules */
+ /* are defined in the file `t1tokens.h' through the use of several */
+ /* macros calls PARSE_XXX. */
+ /* */
+ /* This file is included twice here; the first time to generate parsing */
+ /* callback functions, the second to generate a table of keywords (with */
+ /* pointers to the associated callback). */
+ /* */
+ /* The function `parse_dict' simply scans *linearly* a given dictionary */
+ /* (either the top-level or private one) and calls the appropriate */
+ /* callback when it encounters an immediate keyword. */
+ /* */
+ /* This is by far the fastest way one can find to parse and read all */
+ /* data. */
+ /* */
+ /* This led to tremendous code size reduction. Note that later, the */
+ /* glyph loader will also be _greatly_ simplified, and the automatic */
+ /* hinter will replace the clumsy `t1hinter'. */
+ /* */
+ /*************************************************************************/
+
+
+#include <ft2build.h>
+#include FT_INTERNAL_DEBUG_H
+#include FT_CONFIG_CONFIG_H
+#include FT_MULTIPLE_MASTERS_H
+#include FT_INTERNAL_TYPE1_TYPES_H
+
+#include "t1load.h"
+#include "t1errors.h"
+
+
+
+ /*************************************************************************/
+ /* */
+ /* The macro FT_COMPONENT is used in trace mode. It is an implicit */
+ /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log */
+ /* messages during execution. */
+ /* */
+#undef FT_COMPONENT
+#define FT_COMPONENT trace_t1load
+
+
+#ifndef T1_CONFIG_OPTION_NO_MM_SUPPORT
+
+
+ /*************************************************************************/
+ /*************************************************************************/
+ /***** *****/
+ /***** MULTIPLE MASTERS SUPPORT *****/
+ /***** *****/
+ /*************************************************************************/
+ /*************************************************************************/
+
+ static FT_Error
+ t1_allocate_blend( T1_Face face,
+ FT_UInt num_designs,
+ FT_UInt num_axis )
+ {
+ PS_Blend blend;
+ FT_Memory memory = face->root.memory;
+ FT_Error error = 0;
+
+
+ blend = face->blend;
+ if ( !blend )
+ {
+ if ( FT_NEW( blend ) )
+ goto Exit;
+
+ face->blend = blend;
+ }
+
+ /* allocate design data if needed */
+ if ( num_designs > 0 )
+ {
+ if ( blend->num_designs == 0 )
+ {
+ FT_UInt nn;
+
+
+ /* allocate the blend `private' and `font_info' dictionaries */
+ if ( FT_NEW_ARRAY( blend->font_infos[1], num_designs ) ||
+ FT_NEW_ARRAY( blend->privates[1], num_designs ) ||
+ FT_NEW_ARRAY( blend->bboxes[1], num_designs ) ||
+ FT_NEW_ARRAY( blend->weight_vector, num_designs * 2 ) )
+ goto Exit;
+
+ blend->default_weight_vector = blend->weight_vector + num_designs;
+
+ blend->font_infos[0] = &face->type1.font_info;
+ blend->privates [0] = &face->type1.private_dict;
+ blend->bboxes [0] = &face->type1.font_bbox;
+
+ for ( nn = 2; nn <= num_designs; nn++ )
+ {
+ blend->privates[nn] = blend->privates [nn - 1] + 1;
+ blend->font_infos[nn] = blend->font_infos[nn - 1] + 1;
+ blend->bboxes[nn] = blend->bboxes [nn - 1] + 1;
+ }
+
+ blend->num_designs = num_designs;
+ }
+ else if ( blend->num_designs != num_designs )
+ goto Fail;
+ }
+
+ /* allocate axis data if needed */
+ if ( num_axis > 0 )
+ {
+ if ( blend->num_axis != 0 && blend->num_axis != num_axis )
+ goto Fail;
+
+ blend->num_axis = num_axis;
+ }
+
+ /* allocate the blend design pos table if needed */
+ num_designs = blend->num_designs;
+ num_axis = blend->num_axis;
+ if ( num_designs && num_axis && blend->design_pos[0] == 0 )
+ {
+ FT_UInt n;
+
+
+ if ( FT_NEW_ARRAY( blend->design_pos[0], num_designs * num_axis ) )
+ goto Exit;
+
+ for ( n = 1; n < num_designs; n++ )
+ blend->design_pos[n] = blend->design_pos[0] + num_axis * n;
+ }
+
+ Exit:
+ return error;
+
+ Fail:
+ error = -1;
+ goto Exit;
+ }
+
+
+ FT_LOCAL_DEF( FT_Error )
+ T1_Get_Multi_Master( T1_Face face,
+ FT_Multi_Master* master )
+ {
+ PS_Blend blend = face->blend;
+ FT_UInt n;
+ FT_Error error;
+
+
+ error = T1_Err_Invalid_Argument;
+
+ if ( blend )
+ {
+ master->num_axis = blend->num_axis;
+ master->num_designs = blend->num_designs;
+
+ for ( n = 0; n < blend->num_axis; n++ )
+ {
+ FT_MM_Axis* axis = master->axis + n;
+ PS_DesignMap map = blend->design_map + n;
+
+
+ axis->name = blend->axis_names[n];
+ axis->minimum = map->design_points[0];
+ axis->maximum = map->design_points[map->num_points - 1];
+ }
+ error = 0;
+ }
+ return error;
+ }
+
+
+ FT_LOCAL_DEF( FT_Error )
+ T1_Set_MM_Blend( T1_Face face,
+ FT_UInt num_coords,
+ FT_Fixed* coords )
+ {
+ PS_Blend blend = face->blend;
+ FT_Error error;
+ FT_UInt n, m;
+
+
+ error = T1_Err_Invalid_Argument;
+
+ if ( blend && blend->num_axis == num_coords )
+ {
+ /* recompute the weight vector from the blend coordinates */
+ error = T1_Err_Ok;
+
+ for ( n = 0; n < blend->num_designs; n++ )
+ {
+ FT_Fixed result = 0x10000L; /* 1.0 fixed */
+
+
+ for ( m = 0; m < blend->num_axis; m++ )
+ {
+ FT_Fixed factor;
+
+
+ /* get current blend axis position */
+ factor = coords[m];
+ if ( factor < 0 ) factor = 0;
+ if ( factor > 0x10000L ) factor = 0x10000L;
+
+ if ( ( n & ( 1 << m ) ) == 0 )
+ factor = 0x10000L - factor;
+
+ result = FT_MulFix( result, factor );
+ }
+ blend->weight_vector[n] = result;
+ }
+
+ error = T1_Err_Ok;
+ }
+ return error;
+ }
+
+
+ FT_LOCAL_DEF( FT_Error )
+ T1_Set_MM_Design( T1_Face face,
+ FT_UInt num_coords,
+ FT_Long* coords )
+ {
+ PS_Blend blend = face->blend;
+ FT_Error error;
+ FT_UInt n, p;
+
+
+ error = T1_Err_Invalid_Argument;
+ if ( blend && blend->num_axis == num_coords )
+ {
+ /* compute the blend coordinates through the blend design map */
+ FT_Fixed final_blends[T1_MAX_MM_DESIGNS];
+
+
+ for ( n = 0; n < blend->num_axis; n++ )
+ {
+ FT_Long design = coords[n];
+ FT_Fixed the_blend;
+ PS_DesignMap map = blend->design_map + n;
+ FT_Fixed* designs = map->design_points;
+ FT_Fixed* blends = map->blend_points;
+ FT_Int before = -1, after = -1;
+
+
+ for ( p = 0; p < (FT_UInt)map->num_points; p++ )
+ {
+ FT_Fixed p_design = designs[p];
+
+
+ /* exact match ? */
+ if ( design == p_design )
+ {
+ the_blend = blends[p];
+ goto Found;
+ }
+
+ if ( design < p_design )
+ {
+ after = p;
+ break;
+ }
+
+ before = p;
+ }
+
+ /* now, interpolate if needed */
+ if ( before < 0 )
+ the_blend = blends[0];
+
+ else if ( after < 0 )
+ the_blend = blends[map->num_points - 1];
+
+ else
+ the_blend = FT_MulDiv( design - designs[before],
+ blends [after] - blends [before],
+ designs[after] - designs[before] );
+
+ Found:
+ final_blends[n] = the_blend;
+ }
+
+ error = T1_Set_MM_Blend( face, num_coords, final_blends );
+ }
+
+ return error;
+ }
+
+
+ FT_LOCAL_DEF( void )
+ T1_Done_Blend( T1_Face face )
+ {
+ FT_Memory memory = face->root.memory;
+ PS_Blend blend = face->blend;
+
+
+ if ( blend )
+ {
+ FT_UInt num_designs = blend->num_designs;
+ FT_UInt num_axis = blend->num_axis;
+ FT_UInt n;
+
+
+ /* release design pos table */
+ FT_FREE( blend->design_pos[0] );
+ for ( n = 1; n < num_designs; n++ )
+ blend->design_pos[n] = 0;
+
+ /* release blend `private' and `font info' dictionaries */
+ FT_FREE( blend->privates[1] );
+ FT_FREE( blend->font_infos[1] );
+ FT_FREE( blend->bboxes[1] );
+
+ for ( n = 0; n < num_designs; n++ )
+ {
+ blend->privates [n] = 0;
+ blend->font_infos[n] = 0;
+ blend->bboxes [n] = 0;
+ }
+
+ /* release weight vectors */
+ FT_FREE( blend->weight_vector );
+ blend->default_weight_vector = 0;
+
+ /* release axis names */
+ for ( n = 0; n < num_axis; n++ )
+ FT_FREE( blend->axis_names[n] );
+
+ /* release design map */
+ for ( n = 0; n < num_axis; n++ )
+ {
+ PS_DesignMap dmap = blend->design_map + n;
+
+
+ FT_FREE( dmap->design_points );
+ dmap->num_points = 0;
+ }
+
+ FT_FREE( face->blend );
+ }
+ }
+
+
+ static void
+ parse_blend_axis_types( T1_Face face,
+ T1_Loader loader )
+ {
+ T1_TokenRec axis_tokens[ T1_MAX_MM_AXIS ];
+ FT_Int n, num_axis;
+ FT_Error error = 0;
+ PS_Blend blend;
+ FT_Memory memory;
+
+
+ /* take an array of objects */
+ T1_ToTokenArray( &loader->parser, axis_tokens,
+ T1_MAX_MM_AXIS, &num_axis );
+ if ( num_axis <= 0 || num_axis > T1_MAX_MM_AXIS )
+ {
+ FT_ERROR(( "parse_blend_axis_types: incorrect number of axes: %d\n",
+ num_axis ));
+ error = T1_Err_Invalid_File_Format;
+ goto Exit;
+ }
+
+ /* allocate blend if necessary */
+ error = t1_allocate_blend( face, 0, (FT_UInt)num_axis );
+ if ( error )
+ goto Exit;
+
+ blend = face->blend;
+ memory = face->root.memory;
+
+ /* each token is an immediate containing the name of the axis */
+ for ( n = 0; n < num_axis; n++ )
+ {
+ T1_Token token = axis_tokens + n;
+ FT_Byte* name;
+ FT_PtrDist len;
+
+
+ /* skip first slash, if any */
+ if ( token->start[0] == '/' )
+ token->start++;
+
+ len = token->limit - token->start;
+ if ( len <= 0 )
+ {
+ error = T1_Err_Invalid_File_Format;
+ goto Exit;
+ }
+
+ if ( FT_ALLOC( blend->axis_names[n], len + 1 ) )
+ goto Exit;
+
+ name = (FT_Byte*)blend->axis_names[n];
+ FT_MEM_COPY( name, token->start, len );
+ name[len] = 0;
+ }
+
+ Exit:
+ loader->parser.root.error = error;
+ }
+
+
+ static void
+ parse_blend_design_positions( T1_Face face,
+ T1_Loader loader )
+ {
+ T1_TokenRec design_tokens[ T1_MAX_MM_DESIGNS ];
+ FT_Int num_designs;
+ FT_Int num_axis;
+ T1_Parser parser = &loader->parser;
+
+ FT_Error error = 0;
+ PS_Blend blend;
+
+
+ /* get the array of design tokens - compute number of designs */
+ T1_ToTokenArray( parser, design_tokens, T1_MAX_MM_DESIGNS, &num_designs );
+ if ( num_designs <= 0 || num_designs > T1_MAX_MM_DESIGNS )
+ {
+ FT_ERROR(( "parse_blend_design_positions:" ));
+ FT_ERROR(( " incorrect number of designs: %d\n",
+ num_designs ));
+ error = T1_Err_Invalid_File_Format;
+ goto Exit;
+ }
+
+ {
+ FT_Byte* old_cursor = parser->root.cursor;
+ FT_Byte* old_limit = parser->root.limit;
+ FT_UInt n;
+
+
+ blend = face->blend;
+ num_axis = 0; /* make compiler happy */
+
+ for ( n = 0; n < (FT_UInt)num_designs; n++ )
+ {
+ T1_TokenRec axis_tokens[ T1_MAX_MM_DESIGNS ];
+ T1_Token token;
+ FT_Int axis, n_axis;
+
+
+ /* read axis/coordinates tokens */
+ token = design_tokens + n;
+ parser->root.cursor = token->start - 1;
+ parser->root.limit = token->limit + 1;
+ T1_ToTokenArray( parser, axis_tokens, T1_MAX_MM_AXIS, &n_axis );
+
+ if ( n == 0 )
+ {
+ num_axis = n_axis;
+ error = t1_allocate_blend( face, num_designs, num_axis );
+ if ( error )
+ goto Exit;
+ blend = face->blend;
+ }
+ else if ( n_axis != num_axis )
+ {
+ FT_ERROR(( "parse_blend_design_positions: incorrect table\n" ));
+ error = T1_Err_Invalid_File_Format;
+ goto Exit;
+ }
+
+ /* now, read each axis token into the design position */
+ for ( axis = 0; axis < n_axis; axis++ )
+ {
+ T1_Token token2 = axis_tokens + axis;
+
+
+ parser->root.cursor = token2->start;
+ parser->root.limit = token2->limit;
+ blend->design_pos[n][axis] = T1_ToFixed( parser, 0 );
+ }
+ }
+
+ loader->parser.root.cursor = old_cursor;
+ loader->parser.root.limit = old_limit;
+ }
+
+ Exit:
+ loader->parser.root.error = error;
+ }
+
+
+ static void
+ parse_blend_design_map( T1_Face face,
+ T1_Loader loader )
+ {
+ FT_Error error = 0;
+ T1_Parser parser = &loader->parser;
+ PS_Blend blend;
+ T1_TokenRec axis_tokens[T1_MAX_MM_AXIS];
+ FT_Int n, num_axis;
+ FT_Byte* old_cursor;
+ FT_Byte* old_limit;
+ FT_Memory memory = face->root.memory;
+
+
+ T1_ToTokenArray( parser, axis_tokens, T1_MAX_MM_AXIS, &num_axis );
+ if ( num_axis <= 0 || num_axis > T1_MAX_MM_AXIS )
+ {
+ FT_ERROR(( "parse_blend_design_map: incorrect number of axes: %d\n",
+ num_axis ));
+ error = T1_Err_Invalid_File_Format;
+ goto Exit;
+ }
+ old_cursor = parser->root.cursor;
+ old_limit = parser->root.limit;
+
+ error = t1_allocate_blend( face, 0, num_axis );
+ if ( error )
+ goto Exit;
+ blend = face->blend;
+
+ /* now, read each axis design map */
+ for ( n = 0; n < num_axis; n++ )
+ {
+ PS_DesignMap map = blend->design_map + n;
+ T1_Token token;
+ FT_Int p, num_points;
+
+
+ token = axis_tokens + n;
+ parser->root.cursor = token->start;
+ parser->root.limit = token->limit;
+
+ /* count the number of map points */
+ {
+ FT_Byte* ptr = token->start;
+ FT_Byte* limit = token->limit;
+
+
+ num_points = 0;
+ for ( ; ptr < limit; ptr++ )
+ if ( ptr[0] == '[' )
+ num_points++;
+ }
+ if ( num_points <= 0 || num_points > T1_MAX_MM_MAP_POINTS )
+ {
+ FT_ERROR(( "parse_blend_design_map: incorrect table\n" ));
+ error = T1_Err_Invalid_File_Format;
+ goto Exit;
+ }
+
+ /* allocate design map data */
+ if ( FT_NEW_ARRAY( map->design_points, num_points * 2 ) )
+ goto Exit;
+ map->blend_points = map->design_points + num_points;
+ map->num_points = (FT_Byte)num_points;
+
+ for ( p = 0; p < num_points; p++ )
+ {
+ map->design_points[p] = T1_ToInt( parser );
+ map->blend_points [p] = T1_ToFixed( parser, 0 );
+ }
+ }
+
+ parser->root.cursor = old_cursor;
+ parser->root.limit = old_limit;
+
+ Exit:
+ parser->root.error = error;
+ }
+
+
+ static void
+ parse_weight_vector( T1_Face face,
+ T1_Loader loader )
+ {
+ FT_Error error = 0;
+ T1_Parser parser = &loader->parser;
+ PS_Blend blend = face->blend;
+ T1_TokenRec master;
+ FT_UInt n;
+ FT_Byte* old_cursor;
+ FT_Byte* old_limit;
+
+
+ if ( !blend || blend->num_designs == 0 )
+ {
+ FT_ERROR(( "parse_weight_vector: too early!\n" ));
+ error = T1_Err_Invalid_File_Format;
+ goto Exit;
+ }
+
+ T1_ToToken( parser, &master );
+ if ( master.type != T1_TOKEN_TYPE_ARRAY )
+ {
+ FT_ERROR(( "parse_weight_vector: incorrect format!\n" ));
+ error = T1_Err_Invalid_File_Format;
+ goto Exit;
+ }
+
+ old_cursor = parser->root.cursor;
+ old_limit = parser->root.limit;
+
+ parser->root.cursor = master.start;
+ parser->root.limit = master.limit;
+
+ for ( n = 0; n < blend->num_designs; n++ )
+ {
+ blend->default_weight_vector[n] =
+ blend->weight_vector[n] = T1_ToFixed( parser, 0 );
+ }
+
+ parser->root.cursor = old_cursor;
+ parser->root.limit = old_limit;
+
+ Exit:
+ parser->root.error = error;
+ }
+
+
+ /* the keyword `/shareddict' appears in some multiple master fonts */
+ /* with a lot of Postscript garbage behind it (that's completely out */
+ /* of spec!); we detect it and terminate the parsing */
+ /* */
+ static void
+ parse_shared_dict( T1_Face face,
+ T1_Loader loader )
+ {
+ T1_Parser parser = &loader->parser;
+
+ FT_UNUSED( face );
+
+
+ parser->root.cursor = parser->root.limit;
+ parser->root.error = 0;
+ }
+
+#endif /* T1_CONFIG_OPTION_NO_MM_SUPPORT */
+
+
+ /*************************************************************************/
+ /*************************************************************************/
+ /***** *****/
+ /***** TYPE 1 SYMBOL PARSING *****/
+ /***** *****/
+ /*************************************************************************/
+ /*************************************************************************/
+
+
+ /*************************************************************************/
+ /* */
+ /* First of all, define the token field static variables. This is a set */
+ /* of T1_FieldRec variables used later. */
+ /* */
+ /*************************************************************************/
+
+
+ static FT_Error
+ t1_load_keyword( T1_Face face,
+ T1_Loader loader,
+ T1_Field field )
+ {
+ FT_Error error;
+ void* dummy_object;
+ void** objects;
+ FT_UInt max_objects;
+ PS_Blend blend = face->blend;
+
+
+ /* if the keyword has a dedicated callback, call it */
+ if ( field->type == T1_FIELD_TYPE_CALLBACK )
+ {
+ field->reader( (FT_Face)face, loader );
+ error = loader->parser.root.error;
+ goto Exit;
+ }
+
+ /* now, the keyword is either a simple field, or a table of fields; */
+ /* we are now going to take care of it */
+ switch ( field->location )
+ {
+ case T1_FIELD_LOCATION_FONT_INFO:
+ dummy_object = &face->type1.font_info;
+ objects = &dummy_object;
+ max_objects = 0;
+
+ if ( blend )
+ {
+ objects = (void**)blend->font_infos;
+ max_objects = blend->num_designs;
+ }
+ break;
+
+ case T1_FIELD_LOCATION_PRIVATE:
+ dummy_object = &face->type1.private_dict;
+ objects = &dummy_object;
+ max_objects = 0;
+
+ if ( blend )
+ {
+ objects = (void**)blend->privates;
+ max_objects = blend->num_designs;
+ }
+ break;
+
+ case T1_FIELD_LOCATION_BBOX:
+ dummy_object = &face->type1.font_bbox;
+ objects = &dummy_object;
+ max_objects = 0;
+
+ if ( blend )
+ {
+ objects = (void**)blend->bboxes;
+ max_objects = blend->num_designs;
+ }
+ break;
+
+ default:
+ dummy_object = &face->type1;
+ objects = &dummy_object;
+ max_objects = 0;
+ }
+
+ if ( field->type == T1_FIELD_TYPE_INTEGER_ARRAY ||
+ field->type == T1_FIELD_TYPE_FIXED_ARRAY )
+ error = T1_Load_Field_Table( &loader->parser, field,
+ objects, max_objects, 0 );
+ else
+ error = T1_Load_Field( &loader->parser, field,
+ objects, max_objects, 0 );
+
+ Exit:
+ return error;
+ }
+
+
+ static int
+ is_space( FT_Byte c )
+ {
+ return ( c == ' ' || c == '\t' || c == '\r' || c == '\n' );
+ }
+
+
+ static int
+ is_alpha( FT_Byte c )
+ {
+ /* Note: we must accept "+" as a valid character, as it is used in */
+ /* embedded type1 fonts in PDF documents. */
+ /* */
+ return ( ft_isalnum( c ) ||
+ c == '.' ||
+ c == '_' ||
+ c == '-' ||
+ c == '+' );
+ }
+
+
+ static int
+ read_binary_data( T1_Parser parser,
+ FT_Long* size,
+ FT_Byte** base )
+ {
+ FT_Byte* cur;
+ FT_Byte* limit = parser->root.limit;
+
+
+ /* the binary data has the following format */
+ /* */
+ /* `size' [white*] RD white ....... ND */
+ /* */
+
+ T1_Skip_Spaces( parser );
+ cur = parser->root.cursor;
+
+ if ( cur < limit && (FT_Byte)( *cur - '0' ) < 10 )
+ {
+ *size = T1_ToInt( parser );
+
+ T1_Skip_Spaces( parser );
+ T1_Skip_Alpha ( parser ); /* `RD' or `-|' or something else */
+
+ /* there is only one whitespace char after the */
+ /* `RD' or `-|' token */
+ *base = parser->root.cursor + 1;
+
+ parser->root.cursor += *size + 1;
+ return 1;
+ }
+
+ FT_ERROR(( "read_binary_data: invalid size field\n" ));
+ parser->root.error = T1_Err_Invalid_File_Format;
+ return 0;
+ }
+
+
+ /* we will now define the routines used to handle */
+ /* the `/Encoding', `/Subrs', and `/CharStrings' */
+ /* dictionaries */
+
+ static void
+ parse_font_name( T1_Face face,
+ T1_Loader loader )
+ {
+ T1_Parser parser = &loader->parser;
+ FT_Error error;
+ FT_Memory memory = parser->root.memory;
+ FT_PtrDist len;
+ FT_Byte* cur;
+ FT_Byte* cur2;
+ FT_Byte* limit;
+
+
+ if ( face->type1.font_name )
+ /* with synthetic fonts, it's possible we get here twice */
+ return;
+
+ T1_Skip_Spaces( parser );
+
+ cur = parser->root.cursor;
+ limit = parser->root.limit;
+
+ if ( cur >= limit - 1 || *cur != '/' )
+ return;
+
+ cur++;
+ cur2 = cur;
+ while ( cur2 < limit && is_alpha( *cur2 ) )
+ cur2++;
+
+ len = cur2 - cur;
+ if ( len > 0 )
+ {
+ if ( FT_ALLOC( face->type1.font_name, len + 1 ) )
+ {
+ parser->root.error = error;
+ return;
+ }
+
+ FT_MEM_COPY( face->type1.font_name, cur, len );
+ face->type1.font_name[len] = '\0';
+ }
+ parser->root.cursor = cur2;
+ }
+
+
+#if 0
+ static void
+ parse_font_bbox( T1_Face face,
+ T1_Loader loader )
+ {
+ T1_Parser parser = &loader->parser;
+ FT_Fixed temp[4];
+ FT_BBox* bbox = &face->type1.font_bbox;
+
+
+ (void)T1_ToFixedArray( parser, 4, temp, 0 );
+ bbox->xMin = FT_RoundFix( temp[0] );
+ bbox->yMin = FT_RoundFix( temp[1] );
+ bbox->xMax = FT_RoundFix( temp[2] );
+ bbox->yMax = FT_RoundFix( temp[3] );
+ }
+#endif
+
+
+ static void
+ parse_font_matrix( T1_Face face,
+ T1_Loader loader )
+ {
+ T1_Parser parser = &loader->parser;
+ FT_Matrix* matrix = &face->type1.font_matrix;
+ FT_Vector* offset = &face->type1.font_offset;
+ FT_Face root = (FT_Face)&face->root;
+ FT_Fixed temp[6];
+ FT_Fixed temp_scale;
+
+
+ if ( matrix->xx || matrix->yx )
+ /* with synthetic fonts, it's possible we get here twice */
+ return;
+
+ (void)T1_ToFixedArray( parser, 6, temp, 3 );
+
+ temp_scale = ABS( temp[3] );
+
+ /* Set Units per EM based on FontMatrix values. We set the value to */
+ /* 1000 / temp_scale, because temp_scale was already multiplied by */
+ /* 1000 (in t1_tofixed, from psobjs.c). */
+
+ root->units_per_EM = (FT_UShort)( FT_DivFix( 1000 * 0x10000L,
+ temp_scale ) >> 16 );
+
+ /* we need to scale the values by 1.0/temp_scale */
+ if ( temp_scale != 0x10000L )
+ {
+ temp[0] = FT_DivFix( temp[0], temp_scale );
+ temp[1] = FT_DivFix( temp[1], temp_scale );
+ temp[2] = FT_DivFix( temp[2], temp_scale );
+ temp[4] = FT_DivFix( temp[4], temp_scale );
+ temp[5] = FT_DivFix( temp[5], temp_scale );
+ temp[3] = 0x10000L;
+ }
+
+ matrix->xx = temp[0];
+ matrix->yx = temp[1];
+ matrix->xy = temp[2];
+ matrix->yy = temp[3];
+
+ /* note that the offsets must be expressed in integer font units */
+ offset->x = temp[4] >> 16;
+ offset->y = temp[5] >> 16;
+ }
+
+
+ static void
+ parse_encoding( T1_Face face,
+ T1_Loader loader )
+ {
+ T1_Parser parser = &loader->parser;
+ FT_Byte* cur = parser->root.cursor;
+ FT_Byte* limit = parser->root.limit;
+
+ PSAux_Service psaux = (PSAux_Service)face->psaux;
+
+
+ /* skip whitespace */
+ while ( is_space( *cur ) )
+ {
+ cur++;
+ if ( cur >= limit )
+ {
+ FT_ERROR(( "parse_encoding: out of bounds!\n" ));
+ parser->root.error = T1_Err_Invalid_File_Format;
+ return;
+ }
+ }
+
+ /* if we have a number, then the encoding is an array, */
+ /* and we must load it now */
+ if ( (FT_Byte)( *cur - '0' ) < 10 )
+ {
+ T1_Encoding encode = &face->type1.encoding;
+ FT_Int count, n;
+ PS_Table char_table = &loader->encoding_table;
+ FT_Memory memory = parser->root.memory;
+ FT_Error error;
+
+
+ if ( encode->char_index )
+ /* with synthetic fonts, it's possible we get here twice */
+ return;
+
+ /* read the number of entries in the encoding, should be 256 */
+ count = (FT_Int)T1_ToInt( parser );
+ if ( parser->root.error )
+ return;
+
+ /* we use a T1_Table to store our charnames */
+ loader->num_chars = encode->num_chars = count;
+ if ( FT_NEW_ARRAY( encode->char_index, count ) ||
+ FT_NEW_ARRAY( encode->char_name, count ) ||
+ FT_SET_ERROR( psaux->ps_table_funcs->init(
+ char_table, count, memory ) ) )
+ {
+ parser->root.error = error;
+ return;
+ }
+
+ /* We need to `zero' out encoding_table.elements */
+ for ( n = 0; n < count; n++ )
+ {
+ char* notdef = (char *)".notdef";
+
+
+ T1_Add_Table( char_table, n, notdef, 8 );
+ }
+
+ /* Now, we will need to read a record of the form */
+ /* ... charcode /charname ... for each entry in our table */
+ /* */
+ /* We simply look for a number followed by an immediate */
+ /* name. Note that this ignores correctly the sequence */
+ /* that is often seen in type1 fonts: */
+ /* */
+ /* 0 1 255 { 1 index exch /.notdef put } for dup */
+ /* */
+ /* used to clean the encoding array before anything else. */
+ /* */
+ /* We stop when we encounter a `def'. */
+
+ cur = parser->root.cursor;
+ limit = parser->root.limit;
+ n = 0;
+
+ for ( ; cur < limit; )
+ {
+ FT_Byte c;
+
+
+ c = *cur;
+
+ /* we stop when we encounter a `def' */
+ if ( c == 'd' && cur + 3 < limit )
+ {
+ if ( cur[1] == 'e' &&
+ cur[2] == 'f' &&
+ is_space( cur[-1] ) &&
+ is_space( cur[3] ) )
+ {
+ FT_TRACE6(( "encoding end\n" ));
+ break;
+ }
+ }
+
+ /* otherwise, we must find a number before anything else */
+ if ( (FT_Byte)( c - '0' ) < 10 )
+ {
+ FT_Int charcode;
+
+
+ parser->root.cursor = cur;
+ charcode = (FT_Int)T1_ToInt( parser );
+ cur = parser->root.cursor;
+
+ /* skip whitespace */
+ while ( cur < limit && is_space( *cur ) )
+ cur++;
+
+ if ( cur < limit && *cur == '/' )
+ {
+ /* bingo, we have an immediate name -- it must be a */
+ /* character name */
+ FT_Byte* cur2 = cur + 1;
+ FT_PtrDist len;
+
+
+ while ( cur2 < limit && is_alpha( *cur2 ) )
+ cur2++;
+
+ len = cur2 - cur - 1;
+
+ parser->root.error = T1_Add_Table( char_table, charcode,
+ cur + 1, len + 1 );
+ char_table->elements[charcode][len] = '\0';
+ if ( parser->root.error )
+ return;
+
+ cur = cur2;
+ }
+ }
+ else
+ cur++;
+ }
+
+ face->type1.encoding_type = T1_ENCODING_TYPE_ARRAY;
+ parser->root.cursor = cur;
+ }
+ /* Otherwise, we should have either `StandardEncoding', */
+ /* `ExpertEncoding', or `ISOLatin1Encoding' */
+ else
+ {
+ if ( cur + 17 < limit &&
+ ft_strncmp( (const char*)cur, "StandardEncoding", 16 ) == 0 )
+ face->type1.encoding_type = T1_ENCODING_TYPE_STANDARD;
+
+ else if ( cur + 15 < limit &&
+ ft_strncmp( (const char*)cur, "ExpertEncoding", 14 ) == 0 )
+ face->type1.encoding_type = T1_ENCODING_TYPE_EXPERT;
+
+ else if ( cur + 18 < limit &&
+ ft_strncmp( (const char*)cur, "ISOLatin1Encoding", 17 ) == 0 )
+ face->type1.encoding_type = T1_ENCODING_TYPE_ISOLATIN1;
+
+ else
+ {
+ FT_ERROR(( "parse_encoding: invalid token!\n" ));
+ parser->root.error = T1_Err_Invalid_File_Format;
+ }
+ }
+ }
+
+
+ static void
+ parse_subrs( T1_Face face,
+ T1_Loader loader )
+ {
+ T1_Parser parser = &loader->parser;
+ PS_Table table = &loader->subrs;
+ FT_Memory memory = parser->root.memory;
+ FT_Error error;
+ FT_Int n;
+
+ PSAux_Service psaux = (PSAux_Service)face->psaux;
+
+
+ if ( loader->num_subrs )
+ /* with synthetic fonts, it's possible we get here twice */
+ return;
+
+ loader->num_subrs = (FT_Int)T1_ToInt( parser );
+ if ( parser->root.error )
+ return;
+
+ /* position the parser right before the `dup' of the first subr */
+ T1_Skip_Spaces( parser );
+ T1_Skip_Alpha( parser ); /* `array' */
+ T1_Skip_Spaces( parser );
+
+ /* initialize subrs array */
+ error = psaux->ps_table_funcs->init( table, loader->num_subrs, memory );
+ if ( error )
+ goto Fail;
+
+ /* the format is simple: */
+ /* */
+ /* `index' + binary data */
+ /* */
+ for ( n = 0; n < loader->num_subrs; n++ )
+ {
+ FT_Long idx, size;
+ FT_Byte* base;
+
+
+ /* If the next token isn't `dup', we are also done. This */
+ /* happens when there are `holes' in the Subrs array. */
+ if ( ft_strncmp( (char*)parser->root.cursor, "dup", 3 ) != 0 )
+ break;
+
+ idx = T1_ToInt( parser );
+
+ if ( !read_binary_data( parser, &size, &base ) )
+ return;
+
+ /* The binary string is followed by one token, e.g. `NP' */
+ /* (bound to `noaccess put') or by two separate tokens: */
+ /* `noaccess' & `put'. We position the parser right */
+ /* before the next `dup', if any. */
+ T1_Skip_Spaces( parser );
+ T1_Skip_Alpha( parser ); /* `NP' or `I' or `noaccess' */
+ T1_Skip_Spaces( parser );
+
+ if ( ft_strncmp( (char*)parser->root.cursor, "put", 3 ) == 0 )
+ {
+ T1_Skip_Alpha( parser ); /* skip `put' */
+ T1_Skip_Spaces( parser );
+ }
+
+ /* some fonts use a value of -1 for lenIV to indicate that */
+ /* the charstrings are unencoded */
+ /* */
+ /* thanks to Tom Kacvinsky for pointing this out */
+ /* */
+ if ( face->type1.private_dict.lenIV >= 0 )
+ {
+ FT_Byte* temp;
+
+
+ /* t1_decrypt() shouldn't write to base -- make temporary copy */
+ if ( FT_ALLOC( temp, size ) )
+ goto Fail;
+ FT_MEM_COPY( temp, base, size );
+ psaux->t1_decrypt( temp, size, 4330 );
+ size -= face->type1.private_dict.lenIV;
+ error = T1_Add_Table( table, idx,
+ temp + face->type1.private_dict.lenIV, size );
+ FT_FREE( temp );
+ }
+ else
+ error = T1_Add_Table( table, idx, base, size );
+ if ( error )
+ goto Fail;
+ }
+ return;
+
+ Fail:
+ parser->root.error = error;
+ }
+
+
+ static void
+ parse_charstrings( T1_Face face,
+ T1_Loader loader )
+ {
+ T1_Parser parser = &loader->parser;
+ PS_Table code_table = &loader->charstrings;
+ PS_Table name_table = &loader->glyph_names;
+ PS_Table swap_table = &loader->swap_table;
+ FT_Memory memory = parser->root.memory;
+ FT_Error error;
+
+ PSAux_Service psaux = (PSAux_Service)face->psaux;
+
+ FT_Byte* cur;
+ FT_Byte* limit = parser->root.limit;
+ FT_Int n;
+ FT_UInt notdef_index = 0;
+ FT_Byte notdef_found = 0;
+
+
+ if ( loader->num_glyphs )
+ /* with synthetic fonts, it's possible we get here twice */
+ return;
+
+ loader->num_glyphs = (FT_Int)T1_ToInt( parser );
+ if ( parser->root.error )
+ return;
+
+ /* initialize tables (leaving room for addition of .notdef, */
+ /* if necessary). */
+
+ error = psaux->ps_table_funcs->init( code_table,
+ loader->num_glyphs + 1,
+ memory );
+ if ( error )
+ goto Fail;
+
+ error = psaux->ps_table_funcs->init( name_table,
+ loader->num_glyphs + 1,
+ memory );
+ if ( error )
+ goto Fail;
+
+ /* Initialize table for swapping index notdef_index and */
+ /* index 0 names and codes (if necessary). */
+
+ error = psaux->ps_table_funcs->init( swap_table, 4, memory );
+
+ if ( error )
+ goto Fail;
+
+ n = 0;
+
+ for (;;)
+ {
+ FT_Long size;
+ FT_Byte* base;
+
+
+ /* the format is simple: */
+ /* `/glyphname' + binary data */
+ /* */
+ /* note that we stop when we find a `def' */
+ /* */
+ T1_Skip_Spaces( parser );
+
+ cur = parser->root.cursor;
+ if ( cur >= limit )
+ break;
+
+ /* we stop when we find a `def' or `end' keyword */
+ if ( *cur == 'd' &&
+ cur + 3 < limit &&
+ cur[1] == 'e' &&
+ cur[2] == 'f' )
+ break;
+
+ if ( *cur == 'e' &&
+ cur + 3 < limit &&
+ cur[1] == 'n' &&
+ cur[2] == 'd' )
+ break;
+
+ if ( *cur != '/' )
+ T1_Skip_Alpha( parser );
+ else
+ {
+ FT_Byte* cur2 = cur + 1;
+ FT_PtrDist len;
+
+
+ while ( cur2 < limit && is_alpha( *cur2 ) )
+ cur2++;
+ len = cur2 - cur - 1;
+
+ error = T1_Add_Table( name_table, n, cur + 1, len + 1 );
+ if ( error )
+ goto Fail;
+
+ /* add a trailing zero to the name table */
+ name_table->elements[n][len] = '\0';
+
+ /* record index of /.notdef */
+ if ( ft_strcmp( (const char*)".notdef",
+ (const char*)(name_table->elements[n]) ) == 0 )
+ {
+ notdef_index = n;
+ notdef_found = 1;
+ }
+
+ parser->root.cursor = cur2;
+ if ( !read_binary_data( parser, &size, &base ) )
+ return;
+
+ if ( face->type1.private_dict.lenIV >= 0 )
+ {
+ FT_Byte* temp;
+
+
+ /* t1_decrypt() shouldn't write to base -- make temporary copy */
+ if ( FT_ALLOC( temp, size ) )
+ goto Fail;
+ FT_MEM_COPY( temp, base, size );
+ psaux->t1_decrypt( temp, size, 4330 );
+ size -= face->type1.private_dict.lenIV;
+ error = T1_Add_Table( code_table, n,
+ temp + face->type1.private_dict.lenIV, size );
+ FT_FREE( temp );
+ }
+ else
+ error = T1_Add_Table( code_table, n, base, size );
+ if ( error )
+ goto Fail;
+
+ n++;
+ if ( n >= loader->num_glyphs )
+ break;
+ }
+ }
+
+ loader->num_glyphs = n;
+
+ /* if /.notdef is found but does not occupy index 0, do our magic. */
+ if ( ft_strcmp( (const char*)".notdef",
+ (const char*)name_table->elements[0] ) &&
+ notdef_found )
+ {
+ /* Swap glyph in index 0 with /.notdef glyph. First, add index 0 */
+ /* name and code entries to swap_table. Then place notdef_index name */
+ /* and code entries into swap_table. Then swap name and code */
+ /* entries at indices notdef_index and 0 using values stored in */
+ /* swap_table. */
+
+ /* Index 0 name */
+ error = T1_Add_Table( swap_table, 0,
+ name_table->elements[0],
+ name_table->lengths [0] );
+ if ( error )
+ goto Fail;
+
+ /* Index 0 code */
+ error = T1_Add_Table( swap_table, 1,
+ code_table->elements[0],
+ code_table->lengths [0] );
+ if ( error )
+ goto Fail;
+
+ /* Index notdef_index name */
+ error = T1_Add_Table( swap_table, 2,
+ name_table->elements[notdef_index],
+ name_table->lengths [notdef_index] );
+ if ( error )
+ goto Fail;
+
+ /* Index notdef_index code */
+ error = T1_Add_Table( swap_table, 3,
+ code_table->elements[notdef_index],
+ code_table->lengths [notdef_index] );
+ if ( error )
+ goto Fail;
+
+ error = T1_Add_Table( name_table, notdef_index,
+ swap_table->elements[0],
+ swap_table->lengths [0] );
+ if ( error )
+ goto Fail;
+
+ error = T1_Add_Table( code_table, notdef_index,
+ swap_table->elements[1],
+ swap_table->lengths [1] );
+ if ( error )
+ goto Fail;
+
+ error = T1_Add_Table( name_table, 0,
+ swap_table->elements[2],
+ swap_table->lengths [2] );
+ if ( error )
+ goto Fail;
+
+ error = T1_Add_Table( code_table, 0,
+ swap_table->elements[3],
+ swap_table->lengths [3] );
+ if ( error )
+ goto Fail;
+
+ }
+ else if ( !notdef_found )
+ {
+ /* notdef_index is already 0, or /.notdef is undefined in */
+ /* charstrings dictionary. Worry about /.notdef undefined. */
+ /* We take index 0 and add it to the end of the table(s) */
+ /* and add our own /.notdef glyph to index 0. */
+
+ /* 0 333 hsbw endchar */
+ FT_Byte notdef_glyph[] = {0x8B, 0xF7, 0xE1, 0x0D, 0x0E};
+ char* notdef_name = (char *)".notdef";
+
+
+ error = T1_Add_Table( swap_table, 0,
+ name_table->elements[0],
+ name_table->lengths [0] );
+ if ( error )
+ goto Fail;
+
+ error = T1_Add_Table( swap_table, 1,
+ code_table->elements[0],
+ code_table->lengths [0] );
+ if ( error )
+ goto Fail;
+
+ error = T1_Add_Table( name_table, 0, notdef_name, 8 );
+ if ( error )
+ goto Fail;
+
+ error = T1_Add_Table( code_table, 0, notdef_glyph, 5 );
+
+ if ( error )
+ goto Fail;
+
+ error = T1_Add_Table( name_table, n,
+ swap_table->elements[0],
+ swap_table->lengths [0] );
+ if ( error )
+ goto Fail;
+
+ error = T1_Add_Table( code_table, n,
+ swap_table->elements[1],
+ swap_table->lengths [1] );
+ if ( error )
+ goto Fail;
+
+ /* we added a glyph. */
+ loader->num_glyphs = n + 1;
+ }
+
+ return;
+
+ Fail:
+ parser->root.error = error;
+ }
+
+
+ static
+ const T1_FieldRec t1_keywords[] =
+ {
+
+#include "t1tokens.h"
+
+ /* now add the special functions... */
+ T1_FIELD_CALLBACK( "FontName", parse_font_name )
+#if 0
+ T1_FIELD_CALLBACK( "FontBBox", parse_font_bbox )
+#endif
+ T1_FIELD_CALLBACK( "FontMatrix", parse_font_matrix )
+ T1_FIELD_CALLBACK( "Encoding", parse_encoding )
+ T1_FIELD_CALLBACK( "Subrs", parse_subrs )
+ T1_FIELD_CALLBACK( "CharStrings", parse_charstrings )
+
+#ifndef T1_CONFIG_OPTION_NO_MM_SUPPORT
+ T1_FIELD_CALLBACK( "BlendDesignPositions", parse_blend_design_positions )
+ T1_FIELD_CALLBACK( "BlendDesignMap", parse_blend_design_map )
+ T1_FIELD_CALLBACK( "BlendAxisTypes", parse_blend_axis_types )
+ T1_FIELD_CALLBACK( "WeightVector", parse_weight_vector )
+ T1_FIELD_CALLBACK( "shareddict", parse_shared_dict )
+#endif
+
+ { 0, T1_FIELD_LOCATION_CID_INFO, T1_FIELD_TYPE_NONE, 0, 0, 0, 0, 0 }
+ };
+
+
+ static FT_Error
+ parse_dict( T1_Face face,
+ T1_Loader loader,
+ FT_Byte* base,
+ FT_Long size )
+ {
+ T1_Parser parser = &loader->parser;
+
+
+ parser->root.cursor = base;
+ parser->root.limit = base + size;
+ parser->root.error = 0;
+
+ {
+ FT_Byte* cur = base;
+ FT_Byte* limit = cur + size;
+
+
+ for ( ; cur < limit; cur++ )
+ {
+ /* look for `FontDirectory', which causes problems on some fonts */
+ if ( *cur == 'F' && cur + 25 < limit &&
+ ft_strncmp( (char*)cur, "FontDirectory", 13 ) == 0 )
+ {
+ FT_Byte* cur2;
+
+
+ /* skip the `FontDirectory' keyword */
+ cur += 13;
+ cur2 = cur;
+
+ /* lookup the `known' keyword */
+ while ( cur < limit && *cur != 'k' &&
+ ft_strncmp( (char*)cur, "known", 5 ) )
+ cur++;
+
+ if ( cur < limit )
+ {
+ T1_TokenRec token;
+
+
+ /* skip the `known' keyword and the token following it */
+ cur += 5;
+ loader->parser.root.cursor = cur;
+ T1_ToToken( &loader->parser, &token );
+
+ /* if the last token was an array, skip it! */
+ if ( token.type == T1_TOKEN_TYPE_ARRAY )
+ cur2 = parser->root.cursor;
+ }
+ cur = cur2;
+ }
+ /* look for immediates */
+ else if ( *cur == '/' && cur + 2 < limit )
+ {
+ FT_Byte* cur2;
+ FT_PtrDist len;
+
+
+ cur++;
+ cur2 = cur;
+ while ( cur2 < limit && is_alpha( *cur2 ) )
+ cur2++;
+
+ len = cur2 - cur;
+ if ( len > 0 && len < 22 )
+ {
+ {
+ /* now, compare the immediate name to the keyword table */
+ T1_Field keyword = (T1_Field)t1_keywords;
+
+
+ for (;;)
+ {
+ FT_Byte* name;
+
+
+ name = (FT_Byte*)keyword->ident;
+ if ( !name )
+ break;
+
+ if ( cur[0] == name[0] &&
+ len == ft_strlen( (const char*)name ) )
+ {
+ FT_PtrDist n;
+
+
+ for ( n = 1; n < len; n++ )
+ if ( cur[n] != name[n] )
+ break;
+
+ if ( n >= len )
+ {
+ /* we found it -- run the parsing callback! */
+ parser->root.cursor = cur2;
+ T1_Skip_Spaces( parser );
+ parser->root.error = t1_load_keyword( face,
+ loader,
+ keyword );
+ if ( parser->root.error )
+ return parser->root.error;
+
+ cur = parser->root.cursor;
+ break;
+ }
+ }
+ keyword++;
+ }
+ }
+ }
+ }
+ }
+ }
+ return parser->root.error;
+ }
+
+
+ static void
+ t1_init_loader( T1_Loader loader,
+ T1_Face face )
+ {
+ FT_UNUSED( face );
+
+ FT_MEM_ZERO( loader, sizeof ( *loader ) );
+ loader->num_glyphs = 0;
+ loader->num_chars = 0;
+
+ /* initialize the tables -- simply set their `init' field to 0 */
+ loader->encoding_table.init = 0;
+ loader->charstrings.init = 0;
+ loader->glyph_names.init = 0;
+ loader->subrs.init = 0;
+ loader->swap_table.init = 0;
+ loader->fontdata = 0;
+ }
+
+
+ static void
+ t1_done_loader( T1_Loader loader )
+ {
+ T1_Parser parser = &loader->parser;
+
+
+ /* finalize tables */
+ T1_Release_Table( &loader->encoding_table );
+ T1_Release_Table( &loader->charstrings );
+ T1_Release_Table( &loader->glyph_names );
+ T1_Release_Table( &loader->swap_table );
+ T1_Release_Table( &loader->subrs );
+
+ /* finalize parser */
+ T1_Finalize_Parser( parser );
+ }
+
+
+ FT_LOCAL_DEF( FT_Error )
+ T1_Open_Face( T1_Face face )
+ {
+ T1_LoaderRec loader;
+ T1_Parser parser;
+ T1_Font type1 = &face->type1;
+ FT_Error error;
+
+ PSAux_Service psaux = (PSAux_Service)face->psaux;
+
+
+ t1_init_loader( &loader, face );
+
+ /* default lenIV */
+ type1->private_dict.lenIV = 4;
+
+ /* default blue fuzz, we put it there since 0 is a valid value */
+ type1->private_dict.blue_fuzz = 1;
+
+ parser = &loader.parser;
+ error = T1_New_Parser( parser,
+ face->root.stream,
+ face->root.memory,
+ psaux );
+ if ( error )
+ goto Exit;
+
+ error = parse_dict( face, &loader, parser->base_dict, parser->base_len );
+ if ( error )
+ goto Exit;
+
+ error = T1_Get_Private_Dict( parser, psaux );
+ if ( error )
+ goto Exit;
+
+ error = parse_dict( face, &loader, parser->private_dict,
+ parser->private_len );
+ if ( error )
+ goto Exit;
+
+ /* now, propagate the subrs, charstrings, and glyphnames tables */
+ /* to the Type1 data */
+ type1->num_glyphs = loader.num_glyphs;
+
+ if ( loader.subrs.init )
+ {
+ loader.subrs.init = 0;
+ type1->num_subrs = loader.num_subrs;
+ type1->subrs_block = loader.subrs.block;
+ type1->subrs = loader.subrs.elements;
+ type1->subrs_len = loader.subrs.lengths;
+ }
+
+#ifdef FT_CONFIG_OPTION_INCREMENTAL
+ if ( !face->root.internal->incremental_interface )
+#endif
+ if ( !loader.charstrings.init )
+ {
+ FT_ERROR(( "T1_Open_Face: no charstrings array in face!\n" ));
+ error = T1_Err_Invalid_File_Format;
+ }
+
+ loader.charstrings.init = 0;
+ type1->charstrings_block = loader.charstrings.block;
+ type1->charstrings = loader.charstrings.elements;
+ type1->charstrings_len = loader.charstrings.lengths;
+
+ /* we copy the glyph names `block' and `elements' fields; */
+ /* the `lengths' field must be released later */
+ type1->glyph_names_block = loader.glyph_names.block;
+ type1->glyph_names = (FT_String**)loader.glyph_names.elements;
+ loader.glyph_names.block = 0;
+ loader.glyph_names.elements = 0;
+
+ /* we must now build type1.encoding when we have a custom array */
+ if ( type1->encoding_type == T1_ENCODING_TYPE_ARRAY )
+ {
+ FT_Int charcode, idx, min_char, max_char;
+ FT_Byte* char_name;
+ FT_Byte* glyph_name;
+
+
+ /* OK, we do the following: for each element in the encoding */
+ /* table, look up the index of the glyph having the same name */
+ /* the index is then stored in type1.encoding.char_index, and */
+ /* a the name to type1.encoding.char_name */
+
+ min_char = +32000;
+ max_char = -32000;
+
+ charcode = 0;
+ for ( ; charcode < loader.encoding_table.max_elems; charcode++ )
+ {
+ type1->encoding.char_index[charcode] = 0;
+ type1->encoding.char_name [charcode] = (char *)".notdef";
+
+ char_name = loader.encoding_table.elements[charcode];
+ if ( char_name )
+ for ( idx = 0; idx < type1->num_glyphs; idx++ )
+ {
+ glyph_name = (FT_Byte*)type1->glyph_names[idx];
+ if ( ft_strcmp( (const char*)char_name,
+ (const char*)glyph_name ) == 0 )
+ {
+ type1->encoding.char_index[charcode] = (FT_UShort)idx;
+ type1->encoding.char_name [charcode] = (char*)glyph_name;
+
+ /* Change min/max encoded char only if glyph name is */
+ /* not /.notdef */
+ if ( ft_strcmp( (const char*)".notdef",
+ (const char*)glyph_name ) != 0 )
+ {
+ if ( charcode < min_char ) min_char = charcode;
+ if ( charcode > max_char ) max_char = charcode;
+ }
+ break;
+ }
+ }
+ }
+ type1->encoding.code_first = min_char;
+ type1->encoding.code_last = max_char;
+ type1->encoding.num_chars = loader.num_chars;
+ }
+
+ Exit:
+ t1_done_loader( &loader );
+ return error;
+ }
+
+
+/* END */
--- /dev/null
+++ b/libfreetype/t1load.h
@@ -1,0 +1,84 @@
+/***************************************************************************/
+/* */
+/* t1load.h */
+/* */
+/* Type 1 font loader (specification). */
+/* */
+/* Copyright 1996-2001, 2002 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+
+#ifndef __T1LOAD_H__
+#define __T1LOAD_H__
+
+
+#include <ft2build.h>
+#include FT_INTERNAL_STREAM_H
+#include FT_INTERNAL_POSTSCRIPT_AUX_H
+#include FT_MULTIPLE_MASTERS_H
+
+#include "t1parse.h"
+
+
+FT_BEGIN_HEADER
+
+
+ typedef struct T1_Loader_
+ {
+ T1_ParserRec parser; /* parser used to read the stream */
+
+ FT_Int num_chars; /* number of characters in encoding */
+ PS_TableRec encoding_table; /* PS_Table used to store the */
+ /* encoding character names */
+
+ FT_Int num_glyphs;
+ PS_TableRec glyph_names;
+ PS_TableRec charstrings;
+ PS_TableRec swap_table; /* For moving .notdef glyph to index 0. */
+
+ FT_Int num_subrs;
+ PS_TableRec subrs;
+ FT_Bool fontdata;
+
+ } T1_LoaderRec, *T1_Loader;
+
+
+ FT_LOCAL( FT_Error )
+ T1_Open_Face( T1_Face face );
+
+#ifndef T1_CONFIG_OPTION_NO_MM_SUPPORT
+
+ FT_LOCAL( FT_Error )
+ T1_Get_Multi_Master( T1_Face face,
+ FT_Multi_Master* master );
+
+ FT_LOCAL( FT_Error )
+ T1_Set_MM_Blend( T1_Face face,
+ FT_UInt num_coords,
+ FT_Fixed* coords );
+
+ FT_LOCAL( FT_Error )
+ T1_Set_MM_Design( T1_Face face,
+ FT_UInt num_coords,
+ FT_Long* coords );
+
+ FT_LOCAL( void )
+ T1_Done_Blend( T1_Face face );
+
+#endif /* !T1_CONFIG_OPTION_NO_MM_SUPPORT */
+
+
+FT_END_HEADER
+
+#endif /* __T1LOAD_H__ */
+
+
+/* END */
--- /dev/null
+++ b/libfreetype/t1objs.c
@@ -1,0 +1,541 @@
+/***************************************************************************/
+/* */
+/* t1objs.c */
+/* */
+/* Type 1 objects manager (body). */
+/* */
+/* Copyright 1996-2001, 2002 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+
+#include <ft2build.h>
+#include FT_INTERNAL_DEBUG_H
+#include FT_INTERNAL_STREAM_H
+
+#include "t1gload.h"
+#include "t1load.h"
+
+#include "t1errors.h"
+
+#ifndef T1_CONFIG_OPTION_NO_AFM
+#include "t1afm.h"
+#endif
+
+#include FT_INTERNAL_POSTSCRIPT_NAMES_H
+#include FT_INTERNAL_POSTSCRIPT_AUX_H
+
+
+ /*************************************************************************/
+ /* */
+ /* The macro FT_COMPONENT is used in trace mode. It is an implicit */
+ /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log */
+ /* messages during execution. */
+ /* */
+#undef FT_COMPONENT
+#define FT_COMPONENT trace_t1objs
+
+
+ /*************************************************************************/
+ /* */
+ /* SIZE FUNCTIONS */
+ /* */
+ /* note that we store the global hints in the size's "internal" root */
+ /* field */
+ /* */
+ /*************************************************************************/
+
+
+ static PSH_Globals_Funcs
+ T1_Size_Get_Globals_Funcs( T1_Size size )
+ {
+ T1_Face face = (T1_Face)size->root.face;
+ PSHinter_Service pshinter = (PSHinter_Service)face->pshinter;
+ FT_Module module;
+
+
+ module = FT_Get_Module( size->root.face->driver->root.library,
+ "pshinter" );
+ return ( module && pshinter && pshinter->get_globals_funcs )
+ ? pshinter->get_globals_funcs( module )
+ : 0 ;
+ }
+
+
+ FT_LOCAL_DEF( void )
+ T1_Size_Done( T1_Size size )
+ {
+ if ( size->root.internal )
+ {
+ PSH_Globals_Funcs funcs;
+
+
+ funcs = T1_Size_Get_Globals_Funcs( size );
+ if ( funcs )
+ funcs->destroy( (PSH_Globals)size->root.internal );
+
+ size->root.internal = 0;
+ }
+ }
+
+
+ FT_LOCAL_DEF( FT_Error )
+ T1_Size_Init( T1_Size size )
+ {
+ FT_Error error = 0;
+ PSH_Globals_Funcs funcs = T1_Size_Get_Globals_Funcs( size );
+
+
+ if ( funcs )
+ {
+ PSH_Globals globals;
+ T1_Face face = (T1_Face)size->root.face;
+
+
+ error = funcs->create( size->root.face->memory,
+ &face->type1.private_dict, &globals );
+ if ( !error )
+ size->root.internal = (FT_Size_Internal)(void*)globals;
+ }
+
+ return error;
+ }
+
+
+ FT_LOCAL_DEF( FT_Error )
+ T1_Size_Reset( T1_Size size )
+ {
+ PSH_Globals_Funcs funcs = T1_Size_Get_Globals_Funcs( size );
+ FT_Error error = 0;
+
+
+ if ( funcs )
+ error = funcs->set_scale( (PSH_Globals)size->root.internal,
+ size->root.metrics.x_scale,
+ size->root.metrics.y_scale,
+ 0, 0 );
+ return error;
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* SLOT FUNCTIONS */
+ /* */
+ /*************************************************************************/
+
+ FT_LOCAL_DEF( void )
+ T1_GlyphSlot_Done( T1_GlyphSlot slot )
+ {
+ slot->root.internal->glyph_hints = 0;
+ }
+
+
+ FT_LOCAL_DEF( FT_Error )
+ T1_GlyphSlot_Init( T1_GlyphSlot slot )
+ {
+ T1_Face face;
+ PSHinter_Service pshinter;
+
+
+ face = (T1_Face)slot->root.face;
+ pshinter = (PSHinter_Service)face->pshinter;
+
+ if ( pshinter )
+ {
+ FT_Module module;
+
+
+ module = FT_Get_Module( slot->root.face->driver->root.library, "pshinter" );
+ if (module)
+ {
+ T1_Hints_Funcs funcs;
+
+ funcs = pshinter->get_t1_funcs( module );
+ slot->root.internal->glyph_hints = (void*)funcs;
+ }
+ }
+ return 0;
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* FACE FUNCTIONS */
+ /* */
+ /*************************************************************************/
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* T1_Face_Done */
+ /* */
+ /* <Description> */
+ /* The face object destructor. */
+ /* */
+ /* <Input> */
+ /* face :: A typeless pointer to the face object to destroy. */
+ /* */
+ FT_LOCAL_DEF( void )
+ T1_Face_Done( T1_Face face )
+ {
+ FT_Memory memory;
+ T1_Font type1 = &face->type1;
+
+
+ if ( face )
+ {
+ memory = face->root.memory;
+
+#ifndef T1_CONFIG_OPTION_NO_MM_SUPPORT
+ /* release multiple masters information */
+ T1_Done_Blend( face );
+ face->blend = 0;
+#endif
+
+ /* release font info strings */
+ {
+ PS_FontInfo info = &type1->font_info;
+
+
+ FT_FREE( info->version );
+ FT_FREE( info->notice );
+ FT_FREE( info->full_name );
+ FT_FREE( info->family_name );
+ FT_FREE( info->weight );
+ }
+
+ /* release top dictionary */
+ FT_FREE( type1->charstrings_len );
+ FT_FREE( type1->charstrings );
+ FT_FREE( type1->glyph_names );
+
+ FT_FREE( type1->subrs );
+ FT_FREE( type1->subrs_len );
+
+ FT_FREE( type1->subrs_block );
+ FT_FREE( type1->charstrings_block );
+ FT_FREE( type1->glyph_names_block );
+
+ FT_FREE( type1->encoding.char_index );
+ FT_FREE( type1->encoding.char_name );
+ FT_FREE( type1->font_name );
+
+#ifndef T1_CONFIG_OPTION_NO_AFM
+ /* release afm data if present */
+ if ( face->afm_data )
+ T1_Done_AFM( memory, (T1_AFM*)face->afm_data );
+#endif
+
+ /* release unicode map, if any */
+ FT_FREE( face->unicode_map.maps );
+ face->unicode_map.num_maps = 0;
+
+ face->root.family_name = 0;
+ face->root.style_name = 0;
+ }
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* T1_Face_Init */
+ /* */
+ /* <Description> */
+ /* The face object constructor. */
+ /* */
+ /* <Input> */
+ /* stream :: input stream where to load font data. */
+ /* */
+ /* face_index :: The index of the font face in the resource. */
+ /* */
+ /* num_params :: Number of additional generic parameters. Ignored. */
+ /* */
+ /* params :: Additional generic parameters. Ignored. */
+ /* */
+ /* <InOut> */
+ /* face :: The face record to build. */
+ /* */
+ /* <Return> */
+ /* FreeType error code. 0 means success. */
+ /* */
+ FT_LOCAL_DEF( FT_Error )
+ T1_Face_Init( FT_Stream stream,
+ T1_Face face,
+ FT_Int face_index,
+ FT_Int num_params,
+ FT_Parameter* params )
+ {
+ FT_Error error;
+ PSNames_Service psnames;
+ PSAux_Service psaux;
+ PSHinter_Service pshinter;
+
+ FT_UNUSED( num_params );
+ FT_UNUSED( params );
+ FT_UNUSED( face_index );
+ FT_UNUSED( stream );
+
+
+ face->root.num_faces = 1;
+
+ face->psnames = FT_Get_Module_Interface( FT_FACE_LIBRARY( face ),
+ "psnames" );
+ psnames = (PSNames_Service)face->psnames;
+
+ face->psaux = FT_Get_Module_Interface( FT_FACE_LIBRARY( face ),
+ "psaux" );
+ psaux = (PSAux_Service)face->psaux;
+
+ face->pshinter = FT_Get_Module_Interface( FT_FACE_LIBRARY( face ),
+ "pshinter" );
+ pshinter = (PSHinter_Service)face->pshinter;
+
+ /* open the tokenizer, this will also check the font format */
+ error = T1_Open_Face( face );
+ if ( error )
+ goto Exit;
+
+ /* if we just wanted to check the format, leave successfully now */
+ if ( face_index < 0 )
+ goto Exit;
+
+ /* check the face index */
+ if ( face_index != 0 )
+ {
+ FT_ERROR(( "T1_Face_Init: invalid face index\n" ));
+ error = T1_Err_Invalid_Argument;
+ goto Exit;
+ }
+
+ /* Now, load the font program into the face object */
+
+ /* Init the face object fields */
+ /* Now set up root face fields */
+ {
+ FT_Face root = (FT_Face)&face->root;
+
+
+ root->num_glyphs = face->type1.num_glyphs;
+ root->face_index = face_index;
+
+ root->face_flags = FT_FACE_FLAG_SCALABLE;
+ root->face_flags |= FT_FACE_FLAG_HORIZONTAL;
+ root->face_flags |= FT_FACE_FLAG_GLYPH_NAMES;
+
+ if ( face->type1.font_info.is_fixed_pitch )
+ root->face_flags |= FT_FACE_FLAG_FIXED_WIDTH;
+
+ if ( face->blend )
+ root->face_flags |= FT_FACE_FLAG_MULTIPLE_MASTERS;
+
+ /* XXX: TODO -- add kerning with .afm support */
+
+ /* get style name -- be careful, some broken fonts only */
+ /* have a `/FontName' dictionary entry! */
+ root->family_name = face->type1.font_info.family_name;
+ if ( root->family_name )
+ {
+ char* full = face->type1.font_info.full_name;
+ char* family = root->family_name;
+
+
+ if ( full )
+ {
+ while ( *family && *full == *family )
+ {
+ family++;
+ full++;
+ }
+
+ root->style_name = ( *full == ' ' ? full + 1
+ : (char *)"Regular" );
+ }
+ else
+ root->style_name = (char *)"Regular";
+ }
+ else
+ {
+ /* do we have a `/FontName'? */
+ if ( face->type1.font_name )
+ {
+ root->family_name = face->type1.font_name;
+ root->style_name = (char *)"Regular";
+ }
+ }
+
+ /* compute style flags */
+ root->style_flags = 0;
+ if ( face->type1.font_info.italic_angle )
+ root->style_flags |= FT_STYLE_FLAG_ITALIC;
+ if ( face->type1.font_info.weight )
+ {
+ if ( !ft_strcmp( face->type1.font_info.weight, "Bold" ) ||
+ !ft_strcmp( face->type1.font_info.weight, "Black" ) )
+ root->style_flags |= FT_STYLE_FLAG_BOLD;
+ }
+
+ /* no embedded bitmap support */
+ root->num_fixed_sizes = 0;
+ root->available_sizes = 0;
+
+ root->bbox.xMin = face->type1.font_bbox.xMin >> 16;
+ root->bbox.yMin = face->type1.font_bbox.yMin >> 16;
+ root->bbox.xMax = ( face->type1.font_bbox.xMax + 0xFFFFU ) >> 16;
+ root->bbox.yMax = ( face->type1.font_bbox.yMax + 0xFFFFU ) >> 16;
+
+ /* Set units_per_EM if we didn't set it in parse_font_matrix. */
+ if ( !root->units_per_EM )
+ root->units_per_EM = 1000;
+
+ root->ascender = (FT_Short)( root->bbox.yMax );
+ root->descender = (FT_Short)( root->bbox.yMin );
+ root->height = (FT_Short)(
+ ( ( root->ascender - root->descender ) * 12 ) / 10 );
+
+ /* now compute the maximum advance width */
+ root->max_advance_width =
+ (FT_Short)( root->bbox.xMax );
+ {
+ FT_Int max_advance;
+
+
+ error = T1_Compute_Max_Advance( face, &max_advance );
+
+ /* in case of error, keep the standard width */
+ if ( !error )
+ root->max_advance_width = (FT_Short)max_advance;
+ else
+ error = 0; /* clear error */
+ }
+
+ root->max_advance_height = root->height;
+
+ root->underline_position = face->type1.font_info.underline_position;
+ root->underline_thickness = face->type1.font_info.underline_thickness;
+
+ root->internal->max_points = 0;
+ root->internal->max_contours = 0;
+ }
+
+ {
+ FT_Face root = &face->root;
+
+
+ if ( psnames && psaux )
+ {
+ FT_CharMapRec charmap;
+ T1_CMap_Classes cmap_classes = psaux->t1_cmap_classes;
+ FT_CMap_Class clazz;
+
+
+ charmap.face = root;
+
+ /* first of all, try to synthetize a Unicode charmap */
+ charmap.platform_id = 3;
+ charmap.encoding_id = 1;
+ charmap.encoding = FT_ENCODING_UNICODE;
+
+ FT_CMap_New( cmap_classes->unicode, NULL, &charmap, NULL );
+
+ /* now, generate an Adobe Standard encoding when appropriate */
+ charmap.platform_id = 7;
+ clazz = NULL;
+
+ switch ( face->type1.encoding_type )
+ {
+ case T1_ENCODING_TYPE_STANDARD:
+ charmap.encoding = FT_ENCODING_ADOBE_STANDARD;
+ charmap.encoding_id = 0;
+ clazz = cmap_classes->standard;
+ break;
+
+ case T1_ENCODING_TYPE_EXPERT:
+ charmap.encoding = FT_ENCODING_ADOBE_EXPERT;
+ charmap.encoding_id = 1;
+ clazz = cmap_classes->expert;
+ break;
+
+ case T1_ENCODING_TYPE_ARRAY:
+ charmap.encoding = FT_ENCODING_ADOBE_CUSTOM;
+ charmap.encoding_id = 2;
+ clazz = cmap_classes->custom;
+ break;
+
+ case T1_ENCODING_TYPE_ISOLATIN1:
+ charmap.encoding = FT_ENCODING_ADOBE_LATIN_1;
+ charmap.encoding_id = 3;
+ clazz = cmap_classes->unicode;
+ break;
+
+ default:
+ ;
+ }
+
+ if ( clazz )
+ FT_CMap_New( clazz, NULL, &charmap, NULL );
+
+#if 0
+ /* Select default charmap */
+ if (root->num_charmaps)
+ root->charmap = root->charmaps[0];
+#endif
+ }
+ }
+
+ Exit:
+ return error;
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* T1_Driver_Init */
+ /* */
+ /* <Description> */
+ /* Initializes a given Type 1 driver object. */
+ /* */
+ /* <Input> */
+ /* driver :: A handle to the target driver object. */
+ /* */
+ /* <Return> */
+ /* FreeType error code. 0 means success. */
+ /* */
+ FT_LOCAL_DEF( FT_Error )
+ T1_Driver_Init( T1_Driver driver )
+ {
+ FT_UNUSED( driver );
+
+ return T1_Err_Ok;
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* T1_Driver_Done */
+ /* */
+ /* <Description> */
+ /* Finalizes a given Type 1 driver. */
+ /* */
+ /* <Input> */
+ /* driver :: A handle to the target Type 1 driver. */
+ /* */
+ FT_LOCAL_DEF( void )
+ T1_Driver_Done( T1_Driver driver )
+ {
+ FT_UNUSED( driver );
+ }
+
+
+/* END */
--- /dev/null
+++ b/libfreetype/t1objs.h
@@ -1,0 +1,170 @@
+/***************************************************************************/
+/* */
+/* t1objs.h */
+/* */
+/* Type 1 objects manager (specification). */
+/* */
+/* Copyright 1996-2001, 2002 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+
+#ifndef __T1OBJS_H__
+#define __T1OBJS_H__
+
+
+#include <ft2build.h>
+#include FT_INTERNAL_OBJECTS_H
+#include FT_CONFIG_CONFIG_H
+#include FT_INTERNAL_TYPE1_TYPES_H
+
+
+FT_BEGIN_HEADER
+
+
+ /* The following structures must be defined by the hinter */
+ typedef struct T1_Size_Hints_ T1_Size_Hints;
+ typedef struct T1_Glyph_Hints_ T1_Glyph_Hints;
+
+
+ /*************************************************************************/
+ /* */
+ /* <Type> */
+ /* T1_Driver */
+ /* */
+ /* <Description> */
+ /* A handle to a Type 1 driver object. */
+ /* */
+ typedef struct T1_DriverRec_ *T1_Driver;
+
+
+ /*************************************************************************/
+ /* */
+ /* <Type> */
+ /* T1_Size */
+ /* */
+ /* <Description> */
+ /* A handle to a Type 1 size object. */
+ /* */
+ typedef struct T1_SizeRec_* T1_Size;
+
+
+ /*************************************************************************/
+ /* */
+ /* <Type> */
+ /* T1_GlyphSlot */
+ /* */
+ /* <Description> */
+ /* A handle to a Type 1 glyph slot object. */
+ /* */
+ typedef struct T1_GlyphSlotRec_* T1_GlyphSlot;
+
+
+ /*************************************************************************/
+ /* */
+ /* <Type> */
+ /* T1_CharMap */
+ /* */
+ /* <Description> */
+ /* A handle to a Type 1 character mapping object. */
+ /* */
+ /* <Note> */
+ /* The Type 1 format doesn't use a charmap but an encoding table. */
+ /* The driver is responsible for making up charmap objects */
+ /* corresponding to these tables. */
+ /* */
+ typedef struct T1_CharMapRec_* T1_CharMap;
+
+
+ /*************************************************************************/
+ /* */
+ /* HERE BEGINS THE TYPE1 SPECIFIC STUFF */
+ /* */
+ /*************************************************************************/
+
+
+ /*************************************************************************/
+ /* */
+ /* <Type> */
+ /* T1_SizeRec */
+ /* */
+ /* <Description> */
+ /* Type 1 size record. */
+ /* */
+ typedef struct T1_SizeRec_
+ {
+ FT_SizeRec root;
+
+ } T1_SizeRec;
+
+
+ FT_LOCAL( void )
+ T1_Size_Done( T1_Size size );
+
+ FT_LOCAL( FT_Error )
+ T1_Size_Reset( T1_Size size );
+
+ FT_LOCAL( FT_Error )
+ T1_Size_Init( T1_Size size );
+
+
+ /*************************************************************************/
+ /* */
+ /* <Type> */
+ /* T1_GlyphSlotRec */
+ /* */
+ /* <Description> */
+ /* Type 1 glyph slot record. */
+ /* */
+ typedef struct T1_GlyphSlotRec_
+ {
+ FT_GlyphSlotRec root;
+
+ FT_Bool hint;
+ FT_Bool scaled;
+
+ FT_Int max_points;
+ FT_Int max_contours;
+
+ FT_Fixed x_scale;
+ FT_Fixed y_scale;
+
+ } T1_GlyphSlotRec;
+
+
+ FT_LOCAL( FT_Error )
+ T1_Face_Init( FT_Stream stream,
+ T1_Face face,
+ FT_Int face_index,
+ FT_Int num_params,
+ FT_Parameter* params );
+
+ FT_LOCAL( void )
+ T1_Face_Done( T1_Face face );
+
+ FT_LOCAL( FT_Error )
+ T1_GlyphSlot_Init( T1_GlyphSlot slot );
+
+ FT_LOCAL( void )
+ T1_GlyphSlot_Done( T1_GlyphSlot slot );
+
+ FT_LOCAL( FT_Error )
+ T1_Driver_Init( T1_Driver driver );
+
+ FT_LOCAL( void )
+ T1_Driver_Done( T1_Driver driver );
+
+
+FT_END_HEADER
+
+#endif /* __T1OBJS_H__ */
+
+
+/* END */
--- /dev/null
+++ b/libfreetype/t1parse.c
@@ -1,0 +1,460 @@
+/***************************************************************************/
+/* */
+/* t1parse.c */
+/* */
+/* Type 1 parser (body). */
+/* */
+/* Copyright 1996-2001, 2002 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+
+ /*************************************************************************/
+ /* */
+ /* The Type 1 parser is in charge of the following: */
+ /* */
+ /* - provide an implementation of a growing sequence of objects called */
+ /* a `T1_Table' (used to build various tables needed by the loader). */
+ /* */
+ /* - opening .pfb and .pfa files to extract their top-level and private */
+ /* dictionaries. */
+ /* */
+ /* - read numbers, arrays & strings from any dictionary. */
+ /* */
+ /* See `t1load.c' to see how data is loaded from the font file. */
+ /* */
+ /*************************************************************************/
+
+
+#include <ft2build.h>
+#include FT_INTERNAL_DEBUG_H
+#include FT_INTERNAL_CALC_H
+#include FT_INTERNAL_STREAM_H
+#include FT_INTERNAL_POSTSCRIPT_AUX_H
+
+#include "t1parse.h"
+
+#include "t1errors.h"
+
+
+ /*************************************************************************/
+ /* */
+ /* The macro FT_COMPONENT is used in trace mode. It is an implicit */
+ /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log */
+ /* messages during execution. */
+ /* */
+#undef FT_COMPONENT
+#define FT_COMPONENT trace_t1parse
+
+
+ /*************************************************************************/
+ /*************************************************************************/
+ /*************************************************************************/
+ /***** *****/
+ /***** INPUT STREAM PARSER *****/
+ /***** *****/
+ /*************************************************************************/
+ /*************************************************************************/
+ /*************************************************************************/
+
+
+#define IS_T1_WHITESPACE( c ) ( (c) == ' ' || (c) == '\t' )
+#define IS_T1_LINESPACE( c ) ( (c) == '\r' || (c) == '\n' )
+
+#define IS_T1_SPACE( c ) ( IS_T1_WHITESPACE( c ) || IS_T1_LINESPACE( c ) )
+
+
+ typedef struct PFB_Tag_
+ {
+ FT_UShort tag;
+ FT_Long size;
+
+ } PFB_Tag;
+
+
+#undef FT_STRUCTURE
+#define FT_STRUCTURE PFB_Tag
+
+
+ static
+ const FT_Frame_Field pfb_tag_fields[] =
+ {
+ FT_FRAME_START( 6 ),
+ FT_FRAME_USHORT ( tag ),
+ FT_FRAME_LONG_LE( size ),
+ FT_FRAME_END
+ };
+
+
+ static FT_Error
+ read_pfb_tag( FT_Stream stream,
+ FT_UShort* tag,
+ FT_Long* size )
+ {
+ FT_Error error;
+ PFB_Tag head;
+
+
+ *tag = 0;
+ *size = 0;
+ if ( !FT_STREAM_READ_FIELDS( pfb_tag_fields, &head ) )
+ {
+ if ( head.tag == 0x8001U || head.tag == 0x8002U )
+ {
+ *tag = head.tag;
+ *size = head.size;
+ }
+ }
+ return error;
+ }
+
+
+ FT_LOCAL_DEF( FT_Error )
+ T1_New_Parser( T1_Parser parser,
+ FT_Stream stream,
+ FT_Memory memory,
+ PSAux_Service psaux )
+ {
+ FT_Error error;
+ FT_UShort tag;
+ FT_Long size;
+
+
+ psaux->ps_parser_funcs->init( &parser->root,0, 0, memory );
+
+ parser->stream = stream;
+ parser->base_len = 0;
+ parser->base_dict = 0;
+ parser->private_len = 0;
+ parser->private_dict = 0;
+ parser->in_pfb = 0;
+ parser->in_memory = 0;
+ parser->single_block = 0;
+
+ /******************************************************************/
+ /* */
+ /* Here a short summary of what is going on: */
+ /* */
+ /* When creating a new Type 1 parser, we try to locate and load */
+ /* the base dictionary if this is possible (i.e. for PFB */
+ /* files). Otherwise, we load the whole font into memory. */
+ /* */
+ /* When `loading' the base dictionary, we only setup pointers */
+ /* in the case of a memory-based stream. Otherwise, we */
+ /* allocate and load the base dictionary in it. */
+ /* */
+ /* parser->in_pfb is set if we are in a binary (".pfb") font. */
+ /* parser->in_memory is set if we have a memory stream. */
+ /* */
+
+ /* try to compute the size of the base dictionary; */
+ /* look for a Postscript binary file tag, i.e 0x8001 */
+ if ( FT_STREAM_SEEK( 0L ) )
+ goto Exit;
+
+ error = read_pfb_tag( stream, &tag, &size );
+ if ( error )
+ goto Exit;
+
+ if ( tag != 0x8001U )
+ {
+ /* assume that this is a PFA file for now; an error will */
+ /* be produced later when more things are checked */
+ if ( FT_STREAM_SEEK( 0L ) )
+ goto Exit;
+ size = stream->size;
+ }
+ else
+ parser->in_pfb = 1;
+
+ /* now, try to load `size' bytes of the `base' dictionary we */
+ /* found previously */
+
+ /* if it is a memory-based resource, set up pointers */
+ if ( !stream->read )
+ {
+ parser->base_dict = (FT_Byte*)stream->base + stream->pos;
+ parser->base_len = size;
+ parser->in_memory = 1;
+
+ /* check that the `size' field is valid */
+ if ( FT_STREAM_SKIP( size ) )
+ goto Exit;
+ }
+ else
+ {
+ /* read segment in memory */
+ if ( FT_ALLOC( parser->base_dict, size ) ||
+ FT_STREAM_READ( parser->base_dict, size ) )
+ goto Exit;
+ parser->base_len = size;
+ }
+
+ /* Now check font format; we must see `%!PS-AdobeFont-1' */
+ /* or `%!FontType' */
+ {
+ if ( size <= 16 ||
+ ( ft_strncmp( (const char*)parser->base_dict,
+ "%!PS-AdobeFont-1", 16 ) &&
+ ft_strncmp( (const char*)parser->base_dict,
+ "%!FontType", 10 ) ) )
+ {
+ FT_TRACE2(( "[not a Type1 font]\n" ));
+ error = T1_Err_Unknown_File_Format;
+ }
+ else
+ {
+ parser->root.base = parser->base_dict;
+ parser->root.cursor = parser->base_dict;
+ parser->root.limit = parser->root.cursor + parser->base_len;
+ }
+ }
+
+ Exit:
+ if ( error && !parser->in_memory )
+ FT_FREE( parser->base_dict );
+
+ return error;
+ }
+
+
+ FT_LOCAL_DEF( void )
+ T1_Finalize_Parser( T1_Parser parser )
+ {
+ FT_Memory memory = parser->root.memory;
+
+
+ /* always free the private dictionary */
+ FT_FREE( parser->private_dict );
+
+ /* free the base dictionary only when we have a disk stream */
+ if ( !parser->in_memory )
+ FT_FREE( parser->base_dict );
+
+ parser->root.funcs.done( &parser->root );
+ }
+
+
+ /* return the value of an hexadecimal digit */
+ static int
+ hexa_value( char c )
+ {
+ unsigned int d;
+
+
+ d = (unsigned int)( c - '0' );
+ if ( d <= 9 )
+ return (int)d;
+
+ d = (unsigned int)( c - 'a' );
+ if ( d <= 5 )
+ return (int)( d + 10 );
+
+ d = (unsigned int)( c - 'A' );
+ if ( d <= 5 )
+ return (int)( d + 10 );
+
+ return -1;
+ }
+
+
+ FT_LOCAL_DEF( FT_Error )
+ T1_Get_Private_Dict( T1_Parser parser,
+ PSAux_Service psaux )
+ {
+ FT_Stream stream = parser->stream;
+ FT_Memory memory = parser->root.memory;
+ FT_Error error = 0;
+ FT_Long size;
+
+
+ if ( parser->in_pfb )
+ {
+ /* in the case of the PFB format, the private dictionary can be */
+ /* made of several segments. We thus first read the number of */
+ /* segments to compute the total size of the private dictionary */
+ /* then re-read them into memory. */
+ FT_Long start_pos = FT_STREAM_POS();
+ FT_UShort tag;
+
+
+ parser->private_len = 0;
+ for (;;)
+ {
+ error = read_pfb_tag( stream, &tag, &size );
+ if ( error )
+ goto Fail;
+
+ if ( tag != 0x8002U )
+ break;
+
+ parser->private_len += size;
+
+ if ( FT_STREAM_SKIP( size ) )
+ goto Fail;
+ }
+
+ /* Check that we have a private dictionary there */
+ /* and allocate private dictionary buffer */
+ if ( parser->private_len == 0 )
+ {
+ FT_ERROR(( "T1_Get_Private_Dict:" ));
+ FT_ERROR(( " invalid private dictionary section\n" ));
+ error = T1_Err_Invalid_File_Format;
+ goto Fail;
+ }
+
+ if ( FT_STREAM_SEEK( start_pos ) ||
+ FT_ALLOC( parser->private_dict, parser->private_len ) )
+ goto Fail;
+
+ parser->private_len = 0;
+ for (;;)
+ {
+ error = read_pfb_tag( stream, &tag, &size );
+ if ( error || tag != 0x8002U )
+ {
+ error = T1_Err_Ok;
+ break;
+ }
+
+ if ( FT_STREAM_READ( parser->private_dict + parser->private_len, size ) )
+ goto Fail;
+
+ parser->private_len += size;
+ }
+ }
+ else
+ {
+ /* we have already `loaded' the whole PFA font file into memory; */
+ /* if this is a memory resource, allocate a new block to hold */
+ /* the private dict. Otherwise, simply overwrite into the base */
+ /* dictionary block in the heap. */
+
+ /* first of all, look at the `eexec' keyword */
+ FT_Byte* cur = parser->base_dict;
+ FT_Byte* limit = cur + parser->base_len;
+ FT_Byte c;
+
+
+ for (;;)
+ {
+ c = cur[0];
+ if ( c == 'e' && cur + 9 < limit ) /* 9 = 5 letters for `eexec' + */
+ /* newline + 4 chars */
+ {
+ if ( cur[1] == 'e' && cur[2] == 'x' &&
+ cur[3] == 'e' && cur[4] == 'c' )
+ {
+ cur += 6; /* we skip the newling after the `eexec' */
+
+ /* XXX: Some fonts use DOS-linefeeds, i.e. \r\n; we need to */
+ /* skip the extra \n if we find it */
+ if ( cur[0] == '\n' )
+ cur++;
+
+ break;
+ }
+ }
+ cur++;
+ if ( cur >= limit )
+ {
+ FT_ERROR(( "T1_Get_Private_Dict:" ));
+ FT_ERROR(( " could not find `eexec' keyword\n" ));
+ error = T1_Err_Invalid_File_Format;
+ goto Exit;
+ }
+ }
+
+ /* now determine where to write the _encrypted_ binary private */
+ /* dictionary. We overwrite the base dictionary for disk-based */
+ /* resources and allocate a new block otherwise */
+
+ size = (FT_Long)( parser->base_len - ( cur - parser->base_dict ) );
+
+ if ( parser->in_memory )
+ {
+ /* note that we allocate one more byte to put a terminating `0' */
+ if ( FT_ALLOC( parser->private_dict, size + 1 ) )
+ goto Fail;
+ parser->private_len = size;
+ }
+ else
+ {
+ parser->single_block = 1;
+ parser->private_dict = parser->base_dict;
+ parser->private_len = size;
+ parser->base_dict = 0;
+ parser->base_len = 0;
+ }
+
+ /* now determine whether the private dictionary is encoded in binary */
+ /* or hexadecimal ASCII format -- decode it accordingly */
+
+ /* we need to access the next 4 bytes (after the final \r following */
+ /* the `eexec' keyword); if they all are hexadecimal digits, then */
+ /* we have a case of ASCII storage */
+
+ if ( ( hexa_value( cur[0] ) | hexa_value( cur[1] ) |
+ hexa_value( cur[2] ) | hexa_value( cur[3] ) ) < 0 )
+
+ /* binary encoding -- `simply' copy the private dict */
+ FT_MEM_COPY( parser->private_dict, cur, size );
+
+ else
+ {
+ /* ASCII hexadecimal encoding */
+
+ FT_Byte* write;
+ FT_Int count;
+
+
+ write = parser->private_dict;
+ count = 0;
+
+ for ( ;cur < limit; cur++ )
+ {
+ int hex1;
+
+
+ /* check for newline */
+ if ( cur[0] == '\r' || cur[0] == '\n' )
+ continue;
+
+ /* exit if we have a non-hexadecimal digit that isn't a newline */
+ hex1 = hexa_value( cur[0] );
+ if ( hex1 < 0 || cur + 1 >= limit )
+ break;
+
+ /* otherwise, store byte */
+ *write++ = (FT_Byte)( ( hex1 << 4 ) | hexa_value( cur[1] ) );
+ count++;
+ cur++;
+ }
+
+ /* put a safeguard */
+ parser->private_len = write - parser->private_dict;
+ *write++ = 0;
+ }
+ }
+
+ /* we now decrypt the encoded binary private dictionary */
+ psaux->t1_decrypt( parser->private_dict, parser->private_len, 55665U );
+ parser->root.base = parser->private_dict;
+ parser->root.cursor = parser->private_dict;
+ parser->root.limit = parser->root.cursor + parser->private_len;
+
+ Fail:
+ Exit:
+ return error;
+ }
+
+
+/* END */
--- /dev/null
+++ b/libfreetype/t1parse.h
@@ -1,0 +1,135 @@
+/***************************************************************************/
+/* */
+/* t1parse.h */
+/* */
+/* Type 1 parser (specification). */
+/* */
+/* Copyright 1996-2001, 2002 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+
+#ifndef __T1PARSE_H__
+#define __T1PARSE_H__
+
+
+#include <ft2build.h>
+#include FT_INTERNAL_TYPE1_TYPES_H
+#include FT_INTERNAL_STREAM_H
+
+
+FT_BEGIN_HEADER
+
+
+ /*************************************************************************/
+ /* */
+ /* <Struct> */
+ /* T1_ParserRec */
+ /* */
+ /* <Description> */
+ /* A PS_ParserRec is an object used to parse a Type 1 fonts very */
+ /* quickly. */
+ /* */
+ /* <Fields> */
+ /* root :: The root parser. */
+ /* */
+ /* stream :: The current input stream. */
+ /* */
+ /* base_dict :: A pointer to the top-level dictionary. */
+ /* */
+ /* base_len :: The length in bytes of the top dictionary. */
+ /* */
+ /* private_dict :: A pointer to the private dictionary. */
+ /* */
+ /* private_len :: The length in bytes of the private dictionary. */
+ /* */
+ /* in_pfb :: A boolean. Indicates that we are handling a PFB */
+ /* file. */
+ /* */
+ /* in_memory :: A boolean. Indicates a memory-based stream. */
+ /* */
+ /* single_block :: A boolean. Indicates that the private dictionary */
+ /* is stored in lieu of the base dictionary. */
+ /* */
+ typedef struct T1_ParserRec_
+ {
+ PS_ParserRec root;
+ FT_Stream stream;
+
+ FT_Byte* base_dict;
+ FT_Long base_len;
+
+ FT_Byte* private_dict;
+ FT_Long private_len;
+
+ FT_Byte in_pfb;
+ FT_Byte in_memory;
+ FT_Byte single_block;
+
+ } T1_ParserRec, *T1_Parser;
+
+
+#define T1_Add_Table( p, i, o, l ) (p)->funcs.add( (p), i, o, l )
+#define T1_Done_Table( p ) \
+ do \
+ { \
+ if ( (p)->funcs.done ) \
+ (p)->funcs.done( p ); \
+ } while ( 0 )
+#define T1_Release_Table( p ) \
+ do \
+ { \
+ if ( (p)->funcs.release ) \
+ (p)->funcs.release( p ); \
+ } while ( 0 )
+
+
+#define T1_Skip_Spaces( p ) (p)->root.funcs.skip_spaces( &(p)->root )
+#define T1_Skip_Alpha( p ) (p)->root.funcs.skip_alpha ( &(p)->root )
+
+#define T1_ToInt( p ) (p)->root.funcs.to_int( &(p)->root )
+#define T1_ToFixed( p, t ) (p)->root.funcs.to_fixed( &(p)->root, t )
+
+#define T1_ToCoordArray( p, m, c ) \
+ (p)->root.funcs.to_coord_array( &(p)->root, m, c )
+#define T1_ToFixedArray( p, m, f, t ) \
+ (p)->root.funcs.to_fixed_array( &(p)->root, m, f, t )
+#define T1_ToToken( p, t ) \
+ (p)->root.funcs.to_token( &(p)->root, t )
+#define T1_ToTokenArray( p, t, m, c ) \
+ (p)->root.funcs.to_token_array( &(p)->root, t, m, c )
+
+#define T1_Load_Field( p, f, o, m, pf ) \
+ (p)->root.funcs.load_field( &(p)->root, f, o, m, pf )
+
+#define T1_Load_Field_Table( p, f, o, m, pf ) \
+ (p)->root.funcs.load_field_table( &(p)->root, f, o, m, pf )
+
+
+ FT_LOCAL( FT_Error )
+ T1_New_Parser( T1_Parser parser,
+ FT_Stream stream,
+ FT_Memory memory,
+ PSAux_Service psaux );
+
+ FT_LOCAL( FT_Error )
+ T1_Get_Private_Dict( T1_Parser parser,
+ PSAux_Service psaux );
+
+ FT_LOCAL( void )
+ T1_Finalize_Parser( T1_Parser parser );
+
+
+FT_END_HEADER
+
+#endif /* __T1PARSE_H__ */
+
+
+/* END */
--- /dev/null
+++ b/libfreetype/t1tokens.h
@@ -1,0 +1,80 @@
+/***************************************************************************/
+/* */
+/* t1tokens.h */
+/* */
+/* Type 1 tokenizer (specification). */
+/* */
+/* Copyright 1996-2001, 2002 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+
+#undef FT_STRUCTURE
+#define FT_STRUCTURE PS_FontInfoRec
+#undef T1CODE
+#define T1CODE T1_FIELD_LOCATION_FONT_INFO
+
+ T1_FIELD_STRING ( "version", version )
+ T1_FIELD_STRING ( "Notice", notice )
+ T1_FIELD_STRING ( "FullName", full_name )
+ T1_FIELD_STRING ( "FamilyName", family_name )
+ T1_FIELD_STRING ( "Weight", weight )
+
+ T1_FIELD_NUM ( "ItalicAngle", italic_angle )
+ T1_FIELD_TYPE_BOOL( "isFixedPitch", is_fixed_pitch )
+ T1_FIELD_NUM ( "UnderlinePosition", underline_position )
+ T1_FIELD_NUM ( "UnderlineThickness", underline_thickness )
+
+
+#undef FT_STRUCTURE
+#define FT_STRUCTURE PS_PrivateRec
+#undef T1CODE
+#define T1CODE T1_FIELD_LOCATION_PRIVATE
+
+ T1_FIELD_NUM ( "UniqueID", unique_id )
+ T1_FIELD_NUM ( "lenIV", lenIV )
+ T1_FIELD_NUM ( "LanguageGroup", language_group )
+ T1_FIELD_NUM ( "password", password )
+
+ T1_FIELD_FIXED ( "BlueScale", blue_scale )
+ T1_FIELD_NUM ( "BlueShift", blue_shift )
+ T1_FIELD_NUM ( "BlueFuzz", blue_fuzz )
+
+ T1_FIELD_NUM_TABLE ( "BlueValues", blue_values, 14 )
+ T1_FIELD_NUM_TABLE ( "OtherBlues", other_blues, 10 )
+ T1_FIELD_NUM_TABLE ( "FamilyBlues", family_blues, 14 )
+ T1_FIELD_NUM_TABLE ( "FamilyOtherBlues", family_other_blues, 10 )
+
+ T1_FIELD_NUM_TABLE2( "StdHW", standard_width, 1 )
+ T1_FIELD_NUM_TABLE2( "StdVW", standard_height, 1 )
+ T1_FIELD_NUM_TABLE2( "MinFeature", min_feature, 2 )
+
+ T1_FIELD_NUM_TABLE ( "StemSnapH", snap_widths, 12 )
+ T1_FIELD_NUM_TABLE ( "StemSnapV", snap_heights, 12 )
+
+
+#undef FT_STRUCTURE
+#define FT_STRUCTURE T1_FontRec
+#undef T1CODE
+#define T1CODE T1_FIELD_LOCATION_FONT_DICT
+
+ T1_FIELD_NUM( "PaintType", paint_type )
+ T1_FIELD_NUM( "FontType", font_type )
+ T1_FIELD_NUM( "StrokeWidth", stroke_width )
+
+#undef FT_STRUCTURE
+#define FT_STRUCTURE FT_BBox
+#undef T1CODE
+#define T1CODE T1_FIELD_LOCATION_BBOX
+
+ T1_FIELD_BBOX("FontBBox", xMin )
+
+
+/* END */
--- /dev/null
+++ b/libfreetype/t42drivr.c
@@ -1,0 +1,169 @@
+/***************************************************************************/
+/* */
+/* t42drivr.c */
+/* */
+/* High-level Type 42 driver interface (body). */
+/* */
+/* Copyright 2002 by Roberto Alameda. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+
+ /*************************************************************************/
+ /* */
+ /* This driver implements Type42 fonts as described in the */
+ /* Technical Note #5012 from Adobe, with these limitations: */
+ /* */
+ /* 1) CID Fonts are not currently supported. */
+ /* 2) Incremental fonts making use of the GlyphDirectory keyword */
+ /* will be loaded, but the rendering will be using the TrueType */
+ /* tables. */
+ /* 3) The sfnts array is expected to be ASCII, not binary. */
+ /* 4) As for Type1 fonts, CDevProc is not supported. */
+ /* 5) The Metrics dictionary is not supported. */
+ /* 6) AFM metrics are not supported. */
+ /* */
+ /* In other words, this driver supports Type42 fonts derived from */
+ /* TrueType fonts in a non-CID manner, as done by usual conversion */
+ /* programs. */
+ /* */
+ /*************************************************************************/
+
+
+#include "t42drivr.h"
+#include "t42objs.h"
+#include "t42error.h"
+#include FT_INTERNAL_DEBUG_H
+
+
+#undef FT_COMPONENT
+#define FT_COMPONENT trace_t42
+
+
+ static FT_Error
+ t42_get_glyph_name( T42_Face face,
+ FT_UInt glyph_index,
+ FT_Pointer buffer,
+ FT_UInt buffer_max )
+ {
+ FT_String* gname;
+
+
+ gname = face->type1.glyph_names[glyph_index];
+
+ if ( buffer_max > 0 )
+ {
+ FT_UInt len = (FT_UInt)( ft_strlen( gname ) );
+
+
+ if ( len >= buffer_max )
+ len = buffer_max - 1;
+
+ FT_MEM_COPY( buffer, gname, len );
+ ((FT_Byte*)buffer)[len] = 0;
+ }
+
+ return T42_Err_Ok;
+ }
+
+
+ static const char*
+ t42_get_ps_name( T42_Face face )
+ {
+ return (const char*)face->type1.font_name;
+ }
+
+
+ static FT_UInt
+ t42_get_name_index( T42_Face face,
+ FT_String* glyph_name )
+ {
+ FT_Int i;
+ FT_String* gname;
+
+
+ for ( i = 0; i < face->type1.num_glyphs; i++ )
+ {
+ gname = face->type1.glyph_names[i];
+
+ if ( !ft_strcmp( glyph_name, gname ) )
+ return ft_atoi( (const char *)face->type1.charstrings[i] );
+ }
+
+ return 0;
+ }
+
+
+ static FT_Module_Interface
+ T42_Get_Interface( FT_Driver driver,
+ const FT_String* t42_interface )
+ {
+ FT_UNUSED( driver );
+
+ /* Any additional interface are defined here */
+ if (ft_strcmp( (const char*)t42_interface, "glyph_name" ) == 0 )
+ return (FT_Module_Interface)t42_get_glyph_name;
+
+ if ( ft_strcmp( (const char*)t42_interface, "name_index" ) == 0 )
+ return (FT_Module_Interface)t42_get_name_index;
+
+ if ( ft_strcmp( (const char*)t42_interface, "postscript_name" ) == 0 )
+ return (FT_Module_Interface)t42_get_ps_name;
+
+ return 0;
+ }
+
+
+ const FT_Driver_ClassRec t42_driver_class =
+ {
+ {
+ ft_module_font_driver |
+ ft_module_driver_scalable |
+#ifdef TT_CONFIG_OPTION_BYTECODE_INTERPRETER
+ ft_module_driver_has_hinter,
+#else
+ 0,
+#endif
+
+ sizeof ( T42_DriverRec ),
+
+ "type42",
+ 0x10000L,
+ 0x20000L,
+
+ 0, /* format interface */
+
+ (FT_Module_Constructor)T42_Driver_Init,
+ (FT_Module_Destructor) T42_Driver_Done,
+ (FT_Module_Requester) T42_Get_Interface,
+ },
+
+ sizeof ( T42_FaceRec ),
+ sizeof ( T42_SizeRec ),
+ sizeof ( T42_GlyphSlotRec ),
+
+ (FT_Face_InitFunc) T42_Face_Init,
+ (FT_Face_DoneFunc) T42_Face_Done,
+ (FT_Size_InitFunc) T42_Size_Init,
+ (FT_Size_DoneFunc) T42_Size_Done,
+ (FT_Slot_InitFunc) T42_GlyphSlot_Init,
+ (FT_Slot_DoneFunc) T42_GlyphSlot_Done,
+
+ (FT_Size_ResetPointsFunc) T42_Size_SetChars,
+ (FT_Size_ResetPixelsFunc) T42_Size_SetPixels,
+ (FT_Slot_LoadFunc) T42_GlyphSlot_Load,
+
+ (FT_Face_GetKerningFunc) 0,
+ (FT_Face_AttachFunc) 0,
+
+ (FT_Face_GetAdvancesFunc) 0
+ };
+
+
+/* END */
--- /dev/null
+++ b/libfreetype/t42drivr.h
@@ -1,0 +1,38 @@
+/***************************************************************************/
+/* */
+/* t42drivr.h */
+/* */
+/* High-level Type 42 driver interface (specification). */
+/* */
+/* Copyright 2002 by Roberto Alameda. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+
+#ifndef __T42DRIVR_H__
+#define __T42DRIVR_H__
+
+
+#include <ft2build.h>
+#include FT_INTERNAL_DRIVER_H
+
+
+FT_BEGIN_HEADER
+
+
+ FT_EXPORT_VAR( const FT_Driver_ClassRec ) t42_driver_class;
+
+
+FT_END_HEADER
+
+
+#endif /* __T42DRIVR_H__ */
+
+
+/* END */
--- /dev/null
+++ b/libfreetype/t42error.h
@@ -1,0 +1,40 @@
+/***************************************************************************/
+/* */
+/* t42error.h */
+/* */
+/* Type 42 error codes (specification only). */
+/* */
+/* Copyright 2002 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+
+ /*************************************************************************/
+ /* */
+ /* This file is used to define the Type 42 error enumeration constants. */
+ /* */
+ /*************************************************************************/
+
+#ifndef __T42ERROR_H__
+#define __T42ERROR_H__
+
+#include FT_MODULE_ERRORS_H
+
+#undef __FTERRORS_H__
+
+#define FT_ERR_PREFIX T42_Err_
+#define FT_ERR_BASE FT_Mod_Err_T42
+
+#include FT_ERRORS_H
+
+#endif /* __T42ERROR_H__ */
+
+
+/* END */
--- /dev/null
+++ b/libfreetype/t42objs.c
@@ -1,0 +1,637 @@
+/***************************************************************************/
+/* */
+/* t42objs.c */
+/* */
+/* Type 42 objects manager (body). */
+/* */
+/* Copyright 2002 by Roberto Alameda. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+
+#include "t42objs.h"
+#include "t42parse.h"
+#include "t42error.h"
+#include FT_INTERNAL_DEBUG_H
+#include FT_INTERNAL_STREAM_H
+#include FT_LIST_H
+
+
+#undef FT_COMPONENT
+#define FT_COMPONENT trace_t42
+
+
+ static FT_Error
+ T42_Open_Face( T42_Face face )
+ {
+ T42_LoaderRec loader;
+ T42_Parser parser;
+ T1_Font type1 = &face->type1;
+ FT_Memory memory = face->root.memory;
+ FT_Error error;
+
+ PSAux_Service psaux = (PSAux_Service)face->psaux;
+
+
+ t42_loader_init( &loader, face );
+
+ parser = &loader.parser;
+
+ if ( FT_ALLOC( face->ttf_data, 12 ) )
+ goto Exit;
+
+ error = t42_parser_init( parser,
+ face->root.stream,
+ memory,
+ psaux);
+ if ( error )
+ goto Exit;
+
+ error = t42_parse_dict( face, &loader, parser->base_dict, parser->base_len );
+
+ if ( type1->font_type != 42 )
+ {
+ error = T42_Err_Unknown_File_Format;
+ goto Exit;
+ }
+
+ /* now, propagate the charstrings and glyphnames tables */
+ /* to the Type1 data */
+ type1->num_glyphs = loader.num_glyphs;
+
+ if ( !loader.charstrings.init ) {
+ FT_ERROR(( "T42_Open_Face: no charstrings array in face!\n" ));
+ error = T42_Err_Invalid_File_Format;
+ }
+
+ loader.charstrings.init = 0;
+ type1->charstrings_block = loader.charstrings.block;
+ type1->charstrings = loader.charstrings.elements;
+ type1->charstrings_len = loader.charstrings.lengths;
+
+ /* we copy the glyph names `block' and `elements' fields; */
+ /* the `lengths' field must be released later */
+ type1->glyph_names_block = loader.glyph_names.block;
+ type1->glyph_names = (FT_String**)loader.glyph_names.elements;
+ loader.glyph_names.block = 0;
+ loader.glyph_names.elements = 0;
+
+ /* we must now build type1.encoding when we have a custom array */
+ if ( type1->encoding_type == T1_ENCODING_TYPE_ARRAY )
+ {
+ FT_Int charcode, idx, min_char, max_char;
+ FT_Byte* char_name;
+ FT_Byte* glyph_name;
+
+
+ /* OK, we do the following: for each element in the encoding */
+ /* table, look up the index of the glyph having the same name */
+ /* as defined in the CharStrings array. */
+ /* The index is then stored in type1.encoding.char_index, and */
+ /* the name in type1.encoding.char_name */
+
+ min_char = +32000;
+ max_char = -32000;
+
+ charcode = 0;
+ for ( ; charcode < loader.encoding_table.max_elems; charcode++ )
+ {
+ type1->encoding.char_index[charcode] = 0;
+ type1->encoding.char_name [charcode] = (char *)".notdef";
+
+ char_name = loader.encoding_table.elements[charcode];
+ if ( char_name )
+ for ( idx = 0; idx < type1->num_glyphs; idx++ )
+ {
+ glyph_name = (FT_Byte*)type1->glyph_names[idx];
+ if ( ft_strcmp( (const char*)char_name,
+ (const char*)glyph_name ) == 0 )
+ {
+ type1->encoding.char_index[charcode] = (FT_UShort)idx;
+ type1->encoding.char_name [charcode] = (char*)glyph_name;
+
+ /* Change min/max encoded char only if glyph name is */
+ /* not /.notdef */
+ if ( ft_strcmp( (const char*)".notdef",
+ (const char*)glyph_name ) != 0 )
+ {
+ if ( charcode < min_char ) min_char = charcode;
+ if ( charcode > max_char ) max_char = charcode;
+ }
+ break;
+ }
+ }
+ }
+ type1->encoding.code_first = min_char;
+ type1->encoding.code_last = max_char;
+ type1->encoding.num_chars = loader.num_chars;
+ }
+
+ Exit:
+ t42_loader_done( &loader );
+ return error;
+ }
+
+
+ /***************** Driver Functions *************/
+
+
+ FT_LOCAL_DEF( FT_Error )
+ T42_Face_Init( FT_Stream stream,
+ T42_Face face,
+ FT_Int face_index,
+ FT_Int num_params,
+ FT_Parameter* params )
+ {
+ FT_Error error;
+ PSNames_Service psnames;
+ PSAux_Service psaux;
+ FT_Face root = (FT_Face)&face->root;
+
+ FT_UNUSED( num_params );
+ FT_UNUSED( params );
+ FT_UNUSED( face_index );
+ FT_UNUSED( stream );
+
+
+ face->ttf_face = NULL;
+ face->root.num_faces = 1;
+
+ face->psnames = FT_Get_Module_Interface( FT_FACE_LIBRARY( face ),
+ "psnames" );
+ psnames = (PSNames_Service)face->psnames;
+
+ face->psaux = FT_Get_Module_Interface( FT_FACE_LIBRARY( face ),
+ "psaux" );
+ psaux = (PSAux_Service)face->psaux;
+
+ /* open the tokenizer, this will also check the font format */
+ error = T42_Open_Face( face );
+ if ( error )
+ goto Exit;
+
+ /* if we just wanted to check the format, leave successfully now */
+ if ( face_index < 0 )
+ goto Exit;
+
+ /* check the face index */
+ if ( face_index != 0 )
+ {
+ FT_ERROR(( "T42_Face_Init: invalid face index\n" ));
+ error = T42_Err_Invalid_Argument;
+ goto Exit;
+ }
+
+ /* Now, load the font program into the face object */
+
+ /* Init the face object fields */
+ /* Now set up root face fields */
+
+ root->num_glyphs = face->type1.num_glyphs;
+ root->num_charmaps = 0;
+ root->face_index = face_index;
+
+ root->face_flags = FT_FACE_FLAG_SCALABLE;
+ root->face_flags |= FT_FACE_FLAG_HORIZONTAL;
+ root->face_flags |= FT_FACE_FLAG_GLYPH_NAMES;
+
+ if ( face->type1.font_info.is_fixed_pitch )
+ root->face_flags |= FT_FACE_FLAG_FIXED_WIDTH;
+
+ /* XXX: TODO -- add kerning with .afm support */
+
+ /* get style name -- be careful, some broken fonts only */
+ /* have a `/FontName' dictionary entry! */
+ root->family_name = face->type1.font_info.family_name;
+ if ( root->family_name )
+ {
+ char* full = face->type1.font_info.full_name;
+ char* family = root->family_name;
+
+
+ if ( full )
+ {
+ while ( *family && *full == *family )
+ {
+ family++;
+ full++;
+ }
+
+ root->style_name = ( *full == ' ' ? full + 1
+ : (char *)"Regular" );
+ }
+ else
+ root->style_name = (char *)"Regular";
+ }
+ else
+ {
+ /* do we have a `/FontName'? */
+ if ( face->type1.font_name )
+ {
+ root->family_name = face->type1.font_name;
+ root->style_name = (char *)"Regular";
+ }
+ }
+
+ /* no embedded bitmap support */
+ root->num_fixed_sizes = 0;
+ root->available_sizes = 0;
+
+ /* Load the TTF font embedded in the T42 font */
+ error = FT_New_Memory_Face( FT_FACE_LIBRARY( face ),
+ face->ttf_data,
+ face->ttf_size,
+ 0,
+ &face->ttf_face );
+ if ( error )
+ goto Exit;
+
+ FT_Done_Size( face->ttf_face->size );
+
+ /* Ignore info in FontInfo dictionary and use the info from the */
+ /* loaded TTF font. The PostScript interpreter also ignores it. */
+ root->bbox = face->ttf_face->bbox;
+ root->units_per_EM = face->ttf_face->units_per_EM;
+
+ root->ascender = face->ttf_face->ascender;
+ root->descender = face->ttf_face->descender;
+ root->height = face->ttf_face->height;
+
+ root->max_advance_width = face->ttf_face->max_advance_width;
+ root->max_advance_height = face->ttf_face->max_advance_height;
+
+ root->underline_position = face->type1.font_info.underline_position;
+ root->underline_thickness = face->type1.font_info.underline_thickness;
+
+ root->internal->max_points = 0;
+ root->internal->max_contours = 0;
+
+ /* compute style flags */
+ root->style_flags = 0;
+ if ( face->type1.font_info.italic_angle )
+ root->style_flags |= FT_STYLE_FLAG_ITALIC;
+
+ if ( face->ttf_face->style_flags & FT_STYLE_FLAG_BOLD )
+ root->style_flags |= FT_STYLE_FLAG_BOLD;
+
+ if ( face->ttf_face->face_flags & FT_FACE_FLAG_VERTICAL )
+ root->face_flags |= FT_FACE_FLAG_VERTICAL;
+
+ {
+ if ( psnames && psaux )
+ {
+ FT_CharMapRec charmap;
+ T1_CMap_Classes cmap_classes = psaux->t1_cmap_classes;
+ FT_CMap_Class clazz;
+
+
+ charmap.face = root;
+
+ /* first of all, try to synthetize a Unicode charmap */
+ charmap.platform_id = 3;
+ charmap.encoding_id = 1;
+ charmap.encoding = FT_ENCODING_UNICODE;
+
+ FT_CMap_New( cmap_classes->unicode, NULL, &charmap, NULL );
+
+ /* now, generate an Adobe Standard encoding when appropriate */
+ charmap.platform_id = 7;
+ clazz = NULL;
+
+ switch ( face->type1.encoding_type )
+ {
+ case T1_ENCODING_TYPE_STANDARD:
+ charmap.encoding = FT_ENCODING_ADOBE_STANDARD;
+ charmap.encoding_id = 0;
+ clazz = cmap_classes->standard;
+ break;
+
+ case T1_ENCODING_TYPE_EXPERT:
+ charmap.encoding = FT_ENCODING_ADOBE_EXPERT;
+ charmap.encoding_id = 1;
+ clazz = cmap_classes->expert;
+ break;
+
+ case T1_ENCODING_TYPE_ARRAY:
+ charmap.encoding = FT_ENCODING_ADOBE_CUSTOM;
+ charmap.encoding_id = 2;
+ clazz = cmap_classes->custom;
+ break;
+
+ case T1_ENCODING_TYPE_ISOLATIN1:
+ charmap.encoding = FT_ENCODING_ADOBE_LATIN_1;
+ charmap.encoding_id = 3;
+ clazz = cmap_classes->unicode;
+ break;
+
+ default:
+ ;
+ }
+
+ if ( clazz )
+ FT_CMap_New( clazz, NULL, &charmap, NULL );
+
+#if 0
+ /* Select default charmap */
+ if (root->num_charmaps)
+ root->charmap = root->charmaps[0];
+#endif
+ }
+ }
+ Exit:
+ return error;
+ }
+
+
+ FT_LOCAL_DEF( void )
+ T42_Face_Done( T42_Face face )
+ {
+ T1_Font type1;
+ PS_FontInfo info;
+ FT_Memory memory;
+
+
+ if ( face )
+ {
+ type1 = &face->type1;
+ info = &type1->font_info;
+ memory = face->root.memory;
+
+ /* delete internal ttf face prior to freeing face->ttf_data */
+ if ( face->ttf_face )
+ FT_Done_Face( face->ttf_face );
+
+ /* release font info strings */
+ FT_FREE( info->version );
+ FT_FREE( info->notice );
+ FT_FREE( info->full_name );
+ FT_FREE( info->family_name );
+ FT_FREE( info->weight );
+
+ /* release top dictionary */
+ FT_FREE( type1->charstrings_len );
+ FT_FREE( type1->charstrings );
+ FT_FREE( type1->glyph_names );
+
+ FT_FREE( type1->charstrings_block );
+ FT_FREE( type1->glyph_names_block );
+
+ FT_FREE( type1->encoding.char_index );
+ FT_FREE( type1->encoding.char_name );
+ FT_FREE( type1->font_name );
+
+ FT_FREE( face->ttf_data );
+
+#if 0
+ /* release afm data if present */
+ if ( face->afm_data )
+ T1_Done_AFM( memory, (T1_AFM*)face->afm_data );
+#endif
+
+ /* release unicode map, if any */
+ FT_FREE( face->unicode_map.maps );
+ face->unicode_map.num_maps = 0;
+
+ face->root.family_name = 0;
+ face->root.style_name = 0;
+ }
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* T42_Driver_Init */
+ /* */
+ /* <Description> */
+ /* Initializes a given Type 42 driver object. */
+ /* */
+ /* <Input> */
+ /* driver :: A handle to the target driver object. */
+ /* */
+ /* <Return> */
+ /* FreeType error code. 0 means success. */
+ /* */
+ FT_LOCAL_DEF( FT_Error )
+ T42_Driver_Init( T42_Driver driver )
+ {
+ FT_Module ttmodule;
+
+
+ ttmodule = FT_Get_Module( FT_MODULE(driver)->library, "truetype" );
+ driver->ttclazz = (FT_Driver_Class)ttmodule->clazz;
+
+ return T42_Err_Ok;
+ }
+
+
+ FT_LOCAL_DEF( void )
+ T42_Driver_Done( T42_Driver driver )
+ {
+ FT_UNUSED( driver );
+ }
+
+
+
+
+ FT_LOCAL_DEF( FT_Error )
+ T42_Size_Init( T42_Size size )
+ {
+ FT_Face face = size->root.face;
+ T42_Face t42face = (T42_Face)face;
+ FT_Size ttsize;
+ FT_Error error = T42_Err_Ok;
+
+
+ error = FT_New_Size( t42face->ttf_face, &ttsize );
+ size->ttsize = ttsize;
+
+ FT_Activate_Size( ttsize );
+
+ return error;
+ }
+
+
+ FT_LOCAL_DEF( void )
+ T42_Size_Done( T42_Size size )
+ {
+ FT_Face face = size->root.face;
+ T42_Face t42face = (T42_Face)face;
+ FT_ListNode node;
+
+
+ node = FT_List_Find( &t42face->ttf_face->sizes_list, size->ttsize );
+ if ( node )
+ {
+ FT_Done_Size( size->ttsize );
+ size->ttsize = NULL;
+ }
+ }
+
+
+ FT_LOCAL_DEF( FT_Error )
+ T42_GlyphSlot_Init( T42_GlyphSlot slot )
+ {
+ FT_Face face = slot->root.face;
+ T42_Face t42face = (T42_Face)face;
+ FT_GlyphSlot ttslot;
+ FT_Error error = T42_Err_Ok;
+
+
+ if ( face->glyph == NULL )
+ {
+ /* First glyph slot for this face */
+ slot->ttslot = t42face->ttf_face->glyph;
+ }
+ else
+ {
+ error = FT_New_GlyphSlot( t42face->ttf_face, &ttslot );
+ slot->ttslot = ttslot;
+ }
+
+ return error;
+ }
+
+
+ FT_LOCAL_DEF( void )
+ T42_GlyphSlot_Done( T42_GlyphSlot slot )
+ {
+ FT_Face face = slot->root.face;
+ T42_Face t42face = (T42_Face)face;
+ FT_GlyphSlot cur = t42face->ttf_face->glyph;
+
+
+ while ( cur )
+ {
+ if ( cur == slot->ttslot )
+ {
+ FT_Done_GlyphSlot( slot->ttslot );
+ break;
+ }
+
+ cur = cur->next;
+ }
+ }
+
+
+
+ FT_LOCAL_DEF( FT_Error )
+ T42_Size_SetChars( T42_Size size,
+ FT_F26Dot6 char_width,
+ FT_F26Dot6 char_height,
+ FT_UInt horz_resolution,
+ FT_UInt vert_resolution )
+ {
+ FT_Face face = size->root.face;
+ T42_Face t42face = (T42_Face)face;
+
+
+ FT_Activate_Size(size->ttsize);
+
+ return FT_Set_Char_Size( t42face->ttf_face,
+ char_width,
+ char_height,
+ horz_resolution,
+ vert_resolution );
+ }
+
+
+ FT_LOCAL_DEF( FT_Error )
+ T42_Size_SetPixels( T42_Size size,
+ FT_UInt pixel_width,
+ FT_UInt pixel_height )
+ {
+ FT_Face face = size->root.face;
+ T42_Face t42face = (T42_Face)face;
+
+
+ FT_Activate_Size(size->ttsize);
+
+ return FT_Set_Pixel_Sizes( t42face->ttf_face,
+ pixel_width,
+ pixel_height );
+ }
+
+
+ static void
+ ft_glyphslot_clear( FT_GlyphSlot slot )
+ {
+ /* free bitmap if needed */
+ if ( slot->flags & FT_GLYPH_OWN_BITMAP )
+ {
+ FT_Memory memory = FT_FACE_MEMORY( slot->face );
+
+
+ FT_FREE( slot->bitmap.buffer );
+ slot->flags &= ~FT_GLYPH_OWN_BITMAP;
+ }
+
+ /* clear all public fields in the glyph slot */
+ FT_ZERO( &slot->metrics );
+ FT_ZERO( &slot->outline );
+ FT_ZERO( &slot->bitmap );
+
+ slot->bitmap_left = 0;
+ slot->bitmap_top = 0;
+ slot->num_subglyphs = 0;
+ slot->subglyphs = 0;
+ slot->control_data = 0;
+ slot->control_len = 0;
+ slot->other = 0;
+ slot->format = FT_GLYPH_FORMAT_NONE;
+
+ slot->linearHoriAdvance = 0;
+ slot->linearVertAdvance = 0;
+ }
+
+
+ FT_LOCAL_DEF( FT_Error )
+ T42_GlyphSlot_Load( FT_GlyphSlot glyph,
+ FT_Size size,
+ FT_Int glyph_index,
+ FT_Int32 load_flags )
+ {
+ FT_Error error;
+ T42_GlyphSlot t42slot = (T42_GlyphSlot)glyph;
+ T42_Size t42size = (T42_Size)size;
+ FT_Driver_Class ttclazz = ((T42_Driver)glyph->face->driver)->ttclazz;
+
+
+ ft_glyphslot_clear( t42slot->ttslot );
+ error = ttclazz->load_glyph( t42slot->ttslot,
+ t42size->ttsize,
+ glyph_index,
+ load_flags | FT_LOAD_NO_BITMAP );
+
+ if ( !error )
+ {
+ glyph->metrics = t42slot->ttslot->metrics;
+
+ glyph->linearHoriAdvance = t42slot->ttslot->linearHoriAdvance;
+ glyph->linearVertAdvance = t42slot->ttslot->linearVertAdvance;
+
+ glyph->format = t42slot->ttslot->format;
+ glyph->outline = t42slot->ttslot->outline;
+
+ glyph->bitmap = t42slot->ttslot->bitmap;
+ glyph->bitmap_left = t42slot->ttslot->bitmap_left;
+ glyph->bitmap_top = t42slot->ttslot->bitmap_top;
+
+ glyph->num_subglyphs = t42slot->ttslot->num_subglyphs;
+ glyph->subglyphs = t42slot->ttslot->subglyphs;
+
+ glyph->control_data = t42slot->ttslot->control_data;
+ glyph->control_len = t42slot->ttslot->control_len;
+ }
+
+ return error;
+ }
+
+
+/* END */
--- /dev/null
+++ b/libfreetype/t42objs.h
@@ -1,0 +1,126 @@
+/***************************************************************************/
+/* */
+/* t42objs.h */
+/* */
+/* Type 42 objects manager (specification). */
+/* */
+/* Copyright 2002 by Roberto Alameda. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+
+#ifndef __T42OBJS_H__
+#define __T42OBJS_H__
+
+#include <ft2build.h>
+#include FT_FREETYPE_H
+#include FT_TYPE1_TABLES_H
+#include FT_INTERNAL_TYPE1_TYPES_H
+#include FT_INTERNAL_TYPE42_TYPES_H
+#include FT_INTERNAL_OBJECTS_H
+#include FT_INTERNAL_DRIVER_H
+#include FT_INTERNAL_POSTSCRIPT_NAMES_H
+#include FT_INTERNAL_POSTSCRIPT_HINTS_H
+
+
+FT_BEGIN_HEADER
+
+
+ /* Type42 size */
+ typedef struct T42_SizeRec_
+ {
+ FT_SizeRec root;
+ FT_Size ttsize;
+
+ } T42_SizeRec, *T42_Size;
+
+
+ /* Type42 slot */
+ typedef struct T42_GlyphSlotRec_
+ {
+ FT_GlyphSlotRec root;
+ FT_GlyphSlot ttslot;
+
+ } T42_GlyphSlotRec, *T42_GlyphSlot;
+
+
+ /* Type 42 driver */
+ typedef struct T42_DriverRec_
+ {
+ FT_DriverRec root;
+ FT_Driver_Class ttclazz;
+ void* extension_component;
+
+ } T42_DriverRec, *T42_Driver;
+
+
+ /* */
+
+
+ FT_LOCAL( FT_Error )
+ T42_Face_Init( FT_Stream stream,
+ T42_Face face,
+ FT_Int face_index,
+ FT_Int num_params,
+ FT_Parameter* params );
+
+
+ FT_LOCAL( void )
+ T42_Face_Done( T42_Face face );
+
+
+ FT_LOCAL( FT_Error )
+ T42_Size_Init( T42_Size size );
+
+
+ FT_LOCAL( FT_Error )
+ T42_Size_SetChars( T42_Size size,
+ FT_F26Dot6 char_width,
+ FT_F26Dot6 char_height,
+ FT_UInt horz_resolution,
+ FT_UInt vert_resolution );
+
+ FT_LOCAL( FT_Error )
+ T42_Size_SetPixels( T42_Size size,
+ FT_UInt pixel_width,
+ FT_UInt pixel_height );
+
+ FT_LOCAL( void )
+ T42_Size_Done( T42_Size size );
+
+
+ FT_LOCAL( FT_Error )
+ T42_GlyphSlot_Init( T42_GlyphSlot slot );
+
+
+ FT_LOCAL( FT_Error )
+ T42_GlyphSlot_Load( FT_GlyphSlot glyph,
+ FT_Size size,
+ FT_Int glyph_index,
+ FT_Int32 load_flags );
+
+ FT_LOCAL( void )
+ T42_GlyphSlot_Done( T42_GlyphSlot slot );
+
+
+ FT_LOCAL( FT_Error )
+ T42_Driver_Init( T42_Driver driver );
+
+ FT_LOCAL( void )
+ T42_Driver_Done( T42_Driver driver );
+
+ /* */
+
+FT_END_HEADER
+
+
+#endif /* __T42OBJS_H__ */
+
+
+/* END */
--- /dev/null
+++ b/libfreetype/t42parse.c
@@ -1,0 +1,994 @@
+/***************************************************************************/
+/* */
+/* t42parse.c */
+/* */
+/* Type 42 font parser (body). */
+/* */
+/* Copyright 2002 by Roberto Alameda. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+
+#include "t42parse.h"
+#include "t42error.h"
+#include FT_INTERNAL_DEBUG_H
+#include FT_INTERNAL_STREAM_H
+#include FT_LIST_H
+#include FT_INTERNAL_POSTSCRIPT_AUX_H
+
+
+ /*************************************************************************/
+ /* */
+ /* The macro FT_COMPONENT is used in trace mode. It is an implicit */
+ /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log */
+ /* messages during execution. */
+ /* */
+#undef FT_COMPONENT
+#define FT_COMPONENT trace_t42
+
+
+ static void
+ t42_parse_font_name( T42_Face face,
+ T42_Loader loader );
+
+ static void
+ t42_parse_font_bbox( T42_Face face,
+ T42_Loader loader );
+
+ static void
+ t42_parse_font_matrix( T42_Face face,
+ T42_Loader loader );
+ static void
+ t42_parse_encoding( T42_Face face,
+ T42_Loader loader );
+
+ static void
+ t42_parse_charstrings( T42_Face face,
+ T42_Loader loader );
+
+ static void
+ t42_parse_sfnts( T42_Face face,
+ T42_Loader loader );
+
+
+ static const
+ T1_FieldRec t42_keywords[] = {
+
+#undef FT_STRUCTURE
+#define FT_STRUCTURE T1_FontInfo
+#undef T1CODE
+#define T1CODE T1_FIELD_LOCATION_FONT_INFO
+
+ T1_FIELD_STRING ( "version", version )
+ T1_FIELD_STRING ( "Notice", notice )
+ T1_FIELD_STRING ( "FullName", full_name )
+ T1_FIELD_STRING ( "FamilyName", family_name )
+ T1_FIELD_STRING ( "Weight", weight )
+ T1_FIELD_NUM ( "ItalicAngle", italic_angle )
+ T1_FIELD_TYPE_BOOL( "isFixedPitch", is_fixed_pitch )
+ T1_FIELD_NUM ( "UnderlinePosition", underline_position )
+ T1_FIELD_NUM ( "UnderlineThickness", underline_thickness )
+
+#undef FT_STRUCTURE
+#define FT_STRUCTURE T1_FontRec
+#undef T1CODE
+#define T1CODE T1_FIELD_LOCATION_FONT_DICT
+
+ T1_FIELD_NUM( "PaintType", paint_type )
+ T1_FIELD_NUM( "FontType", font_type )
+ T1_FIELD_NUM( "StrokeWidth", stroke_width )
+
+ T1_FIELD_CALLBACK( "FontName", t42_parse_font_name )
+ T1_FIELD_CALLBACK( "FontBBox", t42_parse_font_bbox )
+ T1_FIELD_CALLBACK( "FontMatrix", t42_parse_font_matrix )
+ T1_FIELD_CALLBACK( "Encoding", t42_parse_encoding )
+ T1_FIELD_CALLBACK( "CharStrings", t42_parse_charstrings )
+ T1_FIELD_CALLBACK( "sfnts", t42_parse_sfnts )
+
+ { 0, T1_FIELD_LOCATION_CID_INFO, T1_FIELD_TYPE_NONE, 0, 0, 0, 0, 0 }
+ };
+
+
+#define T1_Add_Table( p, i, o, l ) (p)->funcs.add( (p), i, o, l )
+#define T1_Done_Table( p ) \
+ do \
+ { \
+ if ( (p)->funcs.done ) \
+ (p)->funcs.done( p ); \
+ } while ( 0 )
+#define T1_Release_Table( p ) \
+ do \
+ { \
+ if ( (p)->funcs.release ) \
+ (p)->funcs.release( p ); \
+ } while ( 0 )
+
+#define T1_Skip_Spaces( p ) (p)->root.funcs.skip_spaces( &(p)->root )
+#define T1_Skip_Alpha( p ) (p)->root.funcs.skip_alpha ( &(p)->root )
+
+#define T1_ToInt( p ) (p)->root.funcs.to_int( &(p)->root )
+#define T1_ToFixed( p, t ) (p)->root.funcs.to_fixed( &(p)->root, t )
+
+#define T1_ToCoordArray( p, m, c ) \
+ (p)->root.funcs.to_coord_array( &(p)->root, m, c )
+#define T1_ToFixedArray( p, m, f, t ) \
+ (p)->root.funcs.to_fixed_array( &(p)->root, m, f, t )
+#define T1_ToToken( p, t ) \
+ (p)->root.funcs.to_token( &(p)->root, t )
+#define T1_ToTokenArray( p, t, m, c ) \
+ (p)->root.funcs.to_token_array( &(p)->root, t, m, c )
+
+#define T1_Load_Field( p, f, o, m, pf ) \
+ (p)->root.funcs.load_field( &(p)->root, f, o, m, pf )
+#define T1_Load_Field_Table( p, f, o, m, pf ) \
+ (p)->root.funcs.load_field_table( &(p)->root, f, o, m, pf )
+
+
+ /********************* Parsing Functions ******************/
+
+ FT_LOCAL_DEF( FT_Error )
+ t42_parser_init( T42_Parser parser,
+ FT_Stream stream,
+ FT_Memory memory,
+ PSAux_Service psaux )
+ {
+ FT_Error error = T42_Err_Ok;
+ FT_Long size;
+
+
+ psaux->ps_parser_funcs->init( &parser->root, 0, 0, memory );
+
+ parser->stream = stream;
+ parser->base_len = 0;
+ parser->base_dict = 0;
+ parser->in_memory = 0;
+
+ /*******************************************************************/
+ /* */
+ /* Here a short summary of what is going on: */
+ /* */
+ /* When creating a new Type 42 parser, we try to locate and load */
+ /* the base dictionary, loading the whole font into memory. */
+ /* */
+ /* When `loading' the base dictionary, we only setup pointers in */
+ /* the case of a memory-based stream. Otherwise, we allocate */
+ /* and load the base dictionary in it. */
+ /* */
+ /* parser->in_memory is set if we have a memory stream. */
+ /* */
+
+ if ( FT_STREAM_SEEK( 0L ) )
+ goto Exit;
+
+ size = stream->size;
+
+ /* now, try to load `size' bytes of the `base' dictionary we */
+ /* found previously */
+
+ /* if it is a memory-based resource, set up pointers */
+ if ( !stream->read )
+ {
+ parser->base_dict = (FT_Byte*)stream->base + stream->pos;
+ parser->base_len = size;
+ parser->in_memory = 1;
+
+ /* check that the `size' field is valid */
+ if ( FT_STREAM_SKIP( size ) )
+ goto Exit;
+ }
+ else
+ {
+ /* read segment in memory */
+ if ( FT_ALLOC( parser->base_dict, size ) ||
+ FT_STREAM_READ( parser->base_dict, size ) )
+ goto Exit;
+
+ parser->base_len = size;
+ }
+
+ /* Now check font format; we must see `%!PS-TrueTypeFont' */
+ if (size <= 17 ||
+ ( ft_strncmp( (const char*)parser->base_dict,
+ "%!PS-TrueTypeFont", 17) ) )
+ error = T42_Err_Unknown_File_Format;
+ else
+ {
+ parser->root.base = parser->base_dict;
+ parser->root.cursor = parser->base_dict;
+ parser->root.limit = parser->root.cursor + parser->base_len;
+ }
+
+ Exit:
+ if ( error && !parser->in_memory )
+ FT_FREE( parser->base_dict );
+
+ return error;
+ }
+
+
+ FT_LOCAL_DEF( void )
+ t42_parser_done( T42_Parser parser )
+ {
+ FT_Memory memory = parser->root.memory;
+
+
+ /* free the base dictionary only when we have a disk stream */
+ if ( !parser->in_memory )
+ FT_FREE( parser->base_dict );
+
+ parser->root.funcs.done( &parser->root );
+ }
+
+
+ static int
+ t42_is_alpha( FT_Byte c )
+ {
+ /* Note: we must accept "+" as a valid character, as it is used in */
+ /* embedded type1 fonts in PDF documents. */
+ /* */
+ return ( ft_isalnum( c ) ||
+ c == '.' ||
+ c == '_' ||
+ c == '-' ||
+ c == '+' );
+ }
+
+
+ static int
+ t42_is_space( FT_Byte c )
+ {
+ return ( c == ' ' || c == '\t' || c == '\r' || c == '\n' );
+ }
+
+
+ static void
+ t42_parse_font_name( T42_Face face,
+ T42_Loader loader )
+ {
+ T42_Parser parser = &loader->parser;
+ FT_Error error;
+ FT_Memory memory = parser->root.memory;
+ FT_Int len;
+ FT_Byte* cur;
+ FT_Byte* cur2;
+ FT_Byte* limit;
+
+
+ T1_Skip_Spaces( parser );
+
+ cur = parser->root.cursor;
+ limit = parser->root.limit;
+
+ if ( cur >= limit - 1 ||
+ ( *cur != '/' && *cur != '(') )
+ return;
+
+ cur++;
+ cur2 = cur;
+ while ( cur2 < limit && t42_is_alpha( *cur2 ) )
+ cur2++;
+
+ len = (FT_Int)( cur2 - cur );
+ if ( len > 0 )
+ {
+ if ( FT_ALLOC( face->type1.font_name, len + 1 ) )
+ {
+ parser->root.error = error;
+ return;
+ }
+
+ FT_MEM_COPY( face->type1.font_name, cur, len );
+ face->type1.font_name[len] = '\0';
+ }
+ parser->root.cursor = cur2;
+ }
+
+
+ static void
+ t42_parse_font_bbox( T42_Face face,
+ T42_Loader loader )
+ {
+ T42_Parser parser = &loader->parser;
+ FT_BBox* bbox = &face->type1.font_bbox;
+
+ bbox->xMin = T1_ToInt( parser );
+ bbox->yMin = T1_ToInt( parser );
+ bbox->xMax = T1_ToInt( parser );
+ bbox->yMax = T1_ToInt( parser );
+ }
+
+
+ static void
+ t42_parse_font_matrix( T42_Face face,
+ T42_Loader loader )
+ {
+ T42_Parser parser = &loader->parser;
+ FT_Matrix* matrix = &face->type1.font_matrix;
+ FT_Vector* offset = &face->type1.font_offset;
+ FT_Face root = (FT_Face)&face->root;
+ FT_Fixed temp[6];
+ FT_Fixed temp_scale;
+
+
+ (void)T1_ToFixedArray( parser, 6, temp, 3 );
+
+ temp_scale = ABS( temp[3] );
+
+ /* Set Units per EM based on FontMatrix values. We set the value to */
+ /* 1000 / temp_scale, because temp_scale was already multiplied by */
+ /* 1000 (in t1_tofixed, from psobjs.c). */
+
+ root->units_per_EM = (FT_UShort)( FT_DivFix( 1000 * 0x10000L,
+ temp_scale ) >> 16 );
+
+ /* we need to scale the values by 1.0/temp_scale */
+ if ( temp_scale != 0x10000L ) {
+ temp[0] = FT_DivFix( temp[0], temp_scale );
+ temp[1] = FT_DivFix( temp[1], temp_scale );
+ temp[2] = FT_DivFix( temp[2], temp_scale );
+ temp[4] = FT_DivFix( temp[4], temp_scale );
+ temp[5] = FT_DivFix( temp[5], temp_scale );
+ temp[3] = 0x10000L;
+ }
+
+ matrix->xx = temp[0];
+ matrix->yx = temp[1];
+ matrix->xy = temp[2];
+ matrix->yy = temp[3];
+
+ /* note that the offsets must be expressed in integer font units */
+ offset->x = temp[4] >> 16;
+ offset->y = temp[5] >> 16;
+ }
+
+
+ static void
+ t42_parse_encoding( T42_Face face,
+ T42_Loader loader )
+ {
+ T42_Parser parser = &loader->parser;
+ FT_Byte* cur = parser->root.cursor;
+ FT_Byte* limit = parser->root.limit;
+
+ PSAux_Service psaux = (PSAux_Service)face->psaux;
+
+
+ /* skip whitespace */
+ while ( t42_is_space( *cur ) )
+ {
+ cur++;
+ if ( cur >= limit )
+ {
+ FT_ERROR(( "t42_parse_encoding: out of bounds!\n" ));
+ parser->root.error = T42_Err_Invalid_File_Format;
+ return;
+ }
+ }
+
+ /* if we have a number, then the encoding is an array, */
+ /* and we must load it now */
+ if ( (FT_Byte)( *cur - '0' ) < 10 )
+ {
+ T1_Encoding encode = &face->type1.encoding;
+ FT_Int count, n;
+ PS_Table char_table = &loader->encoding_table;
+ FT_Memory memory = parser->root.memory;
+ FT_Error error;
+
+
+ /* read the number of entries in the encoding, should be 256 */
+ count = T1_ToInt( parser );
+ if ( parser->root.error )
+ return;
+
+ /* we use a T1_Table to store our charnames */
+ loader->num_chars = encode->num_chars = count;
+ if ( FT_NEW_ARRAY( encode->char_index, count ) ||
+ FT_NEW_ARRAY( encode->char_name, count ) ||
+ FT_SET_ERROR( psaux->ps_table_funcs->init(
+ char_table, count, memory ) ) )
+ {
+ parser->root.error = error;
+ return;
+ }
+
+ /* We need to `zero' out encoding_table.elements */
+ for ( n = 0; n < count; n++ )
+ {
+ char* notdef = (char *)".notdef";
+
+
+ T1_Add_Table( char_table, n, notdef, 8 );
+ }
+
+ /* Now, we will need to read a record of the form */
+ /* ... charcode /charname ... for each entry in our table */
+ /* */
+ /* We simply look for a number followed by an immediate */
+ /* name. Note that this ignores correctly the sequence */
+ /* that is often seen in type1 fonts: */
+ /* */
+ /* 0 1 255 { 1 index exch /.notdef put } for dup */
+ /* */
+ /* used to clean the encoding array before anything else. */
+ /* */
+ /* We stop when we encounter a `def'. */
+
+ cur = parser->root.cursor;
+ limit = parser->root.limit;
+ n = 0;
+
+ for ( ; cur < limit; )
+ {
+ FT_Byte c;
+
+
+ c = *cur;
+
+ /* we stop when we encounter a `def' */
+ if ( c == 'd' && cur + 3 < limit )
+ {
+ if ( cur[1] == 'e' &&
+ cur[2] == 'f' &&
+ t42_is_space( cur[-1] ) &&
+ t42_is_space( cur[3] ) )
+ {
+ FT_TRACE6(( "encoding end\n" ));
+ break;
+ }
+ }
+
+ /* otherwise, we must find a number before anything else */
+ if ( (FT_Byte)( c - '0' ) < 10 )
+ {
+ FT_Int charcode;
+
+
+ parser->root.cursor = cur;
+ charcode = T1_ToInt( parser );
+ cur = parser->root.cursor;
+
+ /* skip whitespace */
+ while ( cur < limit && t42_is_space( *cur ) )
+ cur++;
+
+ if ( cur < limit && *cur == '/' )
+ {
+ /* bingo, we have an immediate name -- it must be a */
+ /* character name */
+ FT_Byte* cur2 = cur + 1;
+ FT_Int len;
+
+
+ while ( cur2 < limit && t42_is_alpha( *cur2 ) )
+ cur2++;
+
+ len = (FT_Int)( cur2 - cur - 1 );
+
+ parser->root.error = T1_Add_Table( char_table, charcode,
+ cur + 1, len + 1 );
+ char_table->elements[charcode][len] = '\0';
+ if ( parser->root.error )
+ return;
+
+ cur = cur2;
+ }
+ }
+ else
+ cur++;
+ }
+
+ face->type1.encoding_type = T1_ENCODING_TYPE_ARRAY;
+ parser->root.cursor = cur;
+ }
+ /* Otherwise, we should have either `StandardEncoding', */
+ /* `ExpertEncoding', or `ISOLatin1Encoding' */
+ else
+ {
+ if ( cur + 17 < limit &&
+ ft_strncmp( (const char*)cur, "StandardEncoding", 16 ) == 0 )
+ face->type1.encoding_type = T1_ENCODING_TYPE_STANDARD;
+
+ else if ( cur + 15 < limit &&
+ ft_strncmp( (const char*)cur, "ExpertEncoding", 14 ) == 0 )
+ face->type1.encoding_type = T1_ENCODING_TYPE_EXPERT;
+
+ else if ( cur + 18 < limit &&
+ ft_strncmp( (const char*)cur, "ISOLatin1Encoding", 17 ) == 0 )
+ face->type1.encoding_type = T1_ENCODING_TYPE_ISOLATIN1;
+
+ else {
+ FT_ERROR(( "t42_parse_encoding: invalid token!\n" ));
+ parser->root.error = T42_Err_Invalid_File_Format;
+ }
+ }
+ }
+
+
+ static FT_UInt
+ t42_hexval( FT_Byte v )
+ {
+ FT_UInt d;
+
+ d = (FT_UInt)( v - 'A' );
+ if ( d < 6 )
+ {
+ d += 10;
+ goto Exit;
+ }
+
+ d = (FT_UInt)( v - 'a' );
+ if ( d < 6 )
+ {
+ d += 10;
+ goto Exit;
+ }
+
+ d = (FT_UInt)( v - '0' );
+ if ( d < 10 )
+ goto Exit;
+
+ d = 0;
+
+ Exit:
+ return d;
+ }
+
+
+ static void
+ t42_parse_sfnts( T42_Face face,
+ T42_Loader loader )
+ {
+ T42_Parser parser = &loader->parser;
+ FT_Memory memory = parser->root.memory;
+ FT_Byte* cur = parser->root.cursor;
+ FT_Byte* limit = parser->root.limit;
+ FT_Error error;
+ FT_Int num_tables = 0, status;
+ FT_ULong count, ttf_size = 0, string_size = 0;
+ FT_Bool in_string = 0;
+ FT_Byte v = 0;
+
+
+ /* The format is `/sfnts [ <...> <...> ... ] def' */
+
+ while ( t42_is_space( *cur ) )
+ cur++;
+
+ if (*cur++ == '[')
+ {
+ status = 0;
+ count = 0;
+ }
+ else
+ {
+ FT_ERROR(( "t42_parse_sfnts: can't find begin of sfnts vector!\n" ));
+ error = T42_Err_Invalid_File_Format;
+ goto Fail;
+ }
+
+ while ( cur < limit - 2 )
+ {
+ while ( t42_is_space( *cur ) )
+ cur++;
+
+ switch ( *cur )
+ {
+ case ']':
+ parser->root.cursor = cur++;
+ return;
+
+ case '<':
+ in_string = 1;
+ string_size = 0;
+ cur++;
+ continue;
+
+ case '>':
+ if ( !in_string )
+ {
+ FT_ERROR(( "t42_parse_sfnts: found unpaired `>'!\n" ));
+ error = T42_Err_Invalid_File_Format;
+ goto Fail;
+ }
+
+ /* A string can have, as a last byte, */
+ /* a zero byte for padding. If so, ignore it */
+ if ( ( v == 0 ) && ( string_size % 2 == 1 ) )
+ count--;
+ in_string = 0;
+ cur++;
+ continue;
+
+ case '%':
+ if ( !in_string )
+ {
+ /* Comment found; skip till end of line */
+ while ( *cur != '\n' )
+ cur++;
+ continue;
+ }
+ else
+ {
+ FT_ERROR(( "t42_parse_sfnts: found `%' in string!\n" ));
+ error = T42_Err_Invalid_File_Format;
+ goto Fail;
+ }
+
+ default:
+ if ( !ft_xdigit( *cur ) || !ft_xdigit( *(cur + 1) ) )
+ {
+ FT_ERROR(( "t42_parse_sfnts: found non-hex characters in string" ));
+ error = T42_Err_Invalid_File_Format;
+ goto Fail;
+ }
+
+ v = (FT_Byte)( 16 * t42_hexval( cur[0] ) + t42_hexval( cur[1] ) );
+ cur += 2;
+ string_size++;
+ }
+
+ switch ( status )
+ {
+ case 0: /* The '[' was read, so load offset table, 12 bytes */
+ if ( count < 12 )
+ {
+ face->ttf_data[count++] = v;
+ continue;
+ }
+ else
+ {
+ num_tables = 16 * face->ttf_data[4] + face->ttf_data[5];
+ status = 1;
+ ttf_size = 12 + 16 * num_tables;
+
+ if ( FT_REALLOC( face->ttf_data, 12, ttf_size ) )
+ goto Fail;
+ }
+ /* No break, fall-through */
+
+ case 1: /* The offset table is read; read now the table directory */
+ if ( count < ttf_size )
+ {
+ face->ttf_data[count++] = v;
+ continue;
+ }
+ else
+ {
+ int i;
+ FT_ULong len;
+
+
+ for ( i = 0; i < num_tables; i++ )
+ {
+ FT_Byte* p = face->ttf_data + 12 + 16*i + 12;
+
+ len = FT_PEEK_ULONG( p );
+
+ /* Pad to a 4-byte boundary length */
+ ttf_size += ( len + 3 ) & ~3;
+ }
+
+ status = 2;
+ face->ttf_size = ttf_size;
+
+ if ( FT_REALLOC( face->ttf_data, 12 + 16 * num_tables,
+ ttf_size + 1 ) )
+ goto Fail;
+ }
+ /* No break, fall-through */
+
+ case 2: /* We are reading normal tables; just swallow them */
+ face->ttf_data[count++] = v;
+
+ }
+ }
+
+ /* If control reaches this point, the format was not valid */
+ error = T42_Err_Invalid_File_Format;
+
+ Fail:
+ parser->root.error = error;
+ }
+
+
+ static void
+ t42_parse_charstrings( T42_Face face,
+ T42_Loader loader )
+ {
+ T42_Parser parser = &loader->parser;
+ PS_Table code_table = &loader->charstrings;
+ PS_Table name_table = &loader->glyph_names;
+ FT_Memory memory = parser->root.memory;
+ FT_Error error;
+
+ PSAux_Service psaux = (PSAux_Service)face->psaux;
+
+ FT_Byte* cur;
+ FT_Byte* limit = parser->root.limit;
+ FT_Int n;
+
+
+ loader->num_glyphs = T1_ToInt( parser );
+ if ( parser->root.error )
+ return;
+
+ /* initialize tables */
+
+ error = psaux->ps_table_funcs->init( code_table,
+ loader->num_glyphs,
+ memory );
+ if ( error )
+ goto Fail;
+
+ error = psaux->ps_table_funcs->init( name_table,
+ loader->num_glyphs,
+ memory );
+ if ( error )
+ goto Fail;
+
+ n = 0;
+
+ for (;;)
+ {
+ /* the format is simple: */
+ /* `/glyphname' + index + def */
+ /* */
+ /* note that we stop when we find an `end' */
+ /* */
+ T1_Skip_Spaces( parser );
+
+ cur = parser->root.cursor;
+ if ( cur >= limit )
+ break;
+
+ /* we stop when we find an `end' keyword */
+ if ( *cur == 'e' &&
+ cur + 3 < limit &&
+ cur[1] == 'n' &&
+ cur[2] == 'd' )
+ break;
+
+ if ( *cur != '/' )
+ T1_Skip_Alpha( parser );
+ else
+ {
+ FT_Byte* cur2 = cur + 1;
+ FT_Int len;
+
+
+ while ( cur2 < limit && t42_is_alpha( *cur2 ) )
+ cur2++;
+ len = (FT_Int)( cur2 - cur - 1 );
+
+ error = T1_Add_Table( name_table, n, cur + 1, len + 1 );
+ if ( error )
+ goto Fail;
+
+ /* add a trailing zero to the name table */
+ name_table->elements[n][len] = '\0';
+
+ parser->root.cursor = cur2;
+ T1_Skip_Spaces( parser );
+
+ cur2 = cur = parser->root.cursor;
+ if ( cur >= limit )
+ break;
+
+ while ( cur2 < limit && t42_is_alpha( *cur2 ) )
+ cur2++;
+ len = (FT_Int)( cur2 - cur );
+
+ error = T1_Add_Table( code_table, n, cur, len + 1 );
+ if ( error )
+ goto Fail;
+
+ code_table->elements[n][len] = '\0';
+
+ n++;
+ if ( n >= loader->num_glyphs )
+ break;
+ }
+ }
+
+ /* Index 0 must be a .notdef element */
+ if ( ft_strcmp( (char *)name_table->elements[0], ".notdef" ) )
+ {
+ FT_ERROR(( "t42_parse_charstrings: Index 0 is not `.notdef'!\n" ));
+ error = T42_Err_Invalid_File_Format;
+ goto Fail;
+ }
+
+ loader->num_glyphs = n;
+ return;
+
+ Fail:
+ parser->root.error = error;
+ }
+
+
+ static FT_Error
+ t42_load_keyword( T42_Face face,
+ T42_Loader loader,
+ T1_Field field )
+ {
+ FT_Error error;
+ void* dummy_object;
+ void** objects;
+ FT_UInt max_objects = 0;
+
+
+ /* if the keyword has a dedicated callback, call it */
+ if ( field->type == T1_FIELD_TYPE_CALLBACK ) {
+ field->reader( (FT_Face)face, loader );
+ error = loader->parser.root.error;
+ goto Exit;
+ }
+
+ /* now, the keyword is either a simple field, or a table of fields; */
+ /* we are now going to take care of it */
+ switch ( field->location )
+ {
+ case T1_FIELD_LOCATION_FONT_INFO:
+ dummy_object = &face->type1.font_info;
+ objects = &dummy_object;
+ break;
+
+ default:
+ dummy_object = &face->type1;
+ objects = &dummy_object;
+ }
+
+ if ( field->type == T1_FIELD_TYPE_INTEGER_ARRAY ||
+ field->type == T1_FIELD_TYPE_FIXED_ARRAY )
+ error = T1_Load_Field_Table( &loader->parser, field,
+ objects, max_objects, 0 );
+ else
+ error = T1_Load_Field( &loader->parser, field,
+ objects, max_objects, 0 );
+
+ Exit:
+ return error;
+ }
+
+
+ FT_LOCAL_DEF( FT_Error )
+ t42_parse_dict( T42_Face face,
+ T42_Loader loader,
+ FT_Byte* base,
+ FT_Long size )
+ {
+ T42_Parser parser = &loader->parser;
+ FT_Byte* cur = base;
+ FT_Byte* limit = cur + size;
+ FT_UInt n_keywords = sizeof ( t42_keywords ) /
+ sizeof ( t42_keywords[0] );
+
+
+ parser->root.cursor = base;
+ parser->root.limit = base + size;
+ parser->root.error = 0;
+
+ for ( ; cur < limit; cur++ )
+ {
+ /* look for `FontDirectory', which causes problems on some fonts */
+ if ( *cur == 'F' && cur + 25 < limit &&
+ ft_strncmp( (char*)cur, "FontDirectory", 13 ) == 0 )
+ {
+ FT_Byte* cur2;
+
+
+ /* skip the `FontDirectory' keyword */
+ cur += 13;
+ cur2 = cur;
+
+ /* lookup the `known' keyword */
+ while ( cur < limit && *cur != 'k' &&
+ ft_strncmp( (char*)cur, "known", 5 ) )
+ cur++;
+
+ if ( cur < limit )
+ {
+ T1_TokenRec token;
+
+
+ /* skip the `known' keyword and the token following it */
+ cur += 5;
+ loader->parser.root.cursor = cur;
+ T1_ToToken( &loader->parser, &token );
+
+ /* if the last token was an array, skip it! */
+ if ( token.type == T1_TOKEN_TYPE_ARRAY )
+ cur2 = parser->root.cursor;
+ }
+ cur = cur2;
+ }
+ /* look for immediates */
+ else if ( *cur == '/' && cur + 2 < limit )
+ {
+ FT_Byte* cur2;
+ FT_UInt i, len;
+
+
+ cur++;
+ cur2 = cur;
+ while ( cur2 < limit && t42_is_alpha( *cur2 ) )
+ cur2++;
+
+ len = (FT_UInt)( cur2 - cur );
+ if ( len > 0 && len < 22 ) /* XXX What shall it this 22? */
+ {
+ /* now, compare the immediate name to the keyword table */
+
+ /* Loop through all known keywords */
+ for ( i = 0; i < n_keywords; i++ )
+ {
+ T1_Field keyword = (T1_Field)&t42_keywords[i];
+ FT_Byte *name = (FT_Byte*)keyword->ident;
+
+
+ if ( !name )
+ continue;
+
+ if ( ( len == ft_strlen( (const char *)name ) ) &&
+ ( ft_memcmp( cur, name, len ) == 0 ) )
+ {
+ /* we found it -- run the parsing callback! */
+ parser->root.cursor = cur2;
+ T1_Skip_Spaces( parser );
+ parser->root.error = t42_load_keyword(face,
+ loader,
+ keyword );
+ if ( parser->root.error )
+ return parser->root.error;
+ cur = parser->root.cursor;
+ break;
+ }
+ }
+ }
+ }
+ }
+ return parser->root.error;
+ }
+
+
+ FT_LOCAL_DEF( void )
+ t42_loader_init( T42_Loader loader,
+ T42_Face face )
+ {
+ FT_UNUSED( face );
+
+ FT_MEM_ZERO( loader, sizeof ( *loader ) );
+ loader->num_glyphs = 0;
+ loader->num_chars = 0;
+
+ /* initialize the tables -- simply set their `init' field to 0 */
+ loader->encoding_table.init = 0;
+ loader->charstrings.init = 0;
+ loader->glyph_names.init = 0;
+ }
+
+
+ FT_LOCAL_DEF( void )
+ t42_loader_done( T42_Loader loader )
+ {
+ T42_Parser parser = &loader->parser;
+
+
+ /* finalize tables */
+ T1_Release_Table( &loader->encoding_table );
+ T1_Release_Table( &loader->charstrings );
+ T1_Release_Table( &loader->glyph_names );
+
+ /* finalize parser */
+ t42_parser_done( parser );
+ }
+
+
+/* END */
--- /dev/null
+++ b/libfreetype/t42parse.h
@@ -1,0 +1,89 @@
+/***************************************************************************/
+/* */
+/* t42parse.h */
+/* */
+/* Type 42 font parser (specification). */
+/* */
+/* Copyright 2002 by Roberto Alameda. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+
+#ifndef __T42PARSE_H__
+#define __T42PARSE_H__
+
+
+#include "t42objs.h"
+#include FT_INTERNAL_POSTSCRIPT_AUX_H
+
+
+FT_BEGIN_HEADER
+
+ typedef struct T42_ParserRec_
+ {
+ PS_ParserRec root;
+ FT_Stream stream;
+
+ FT_Byte* base_dict;
+ FT_Int base_len;
+
+ FT_Byte in_memory;
+
+ } T42_ParserRec, *T42_Parser;
+
+
+ typedef struct T42_Loader_
+ {
+ T42_ParserRec parser; /* parser used to read the stream */
+
+ FT_Int num_chars; /* number of characters in encoding */
+ PS_TableRec encoding_table; /* PS_Table used to store the */
+ /* encoding character names */
+
+ FT_Int num_glyphs;
+ PS_TableRec glyph_names;
+ PS_TableRec charstrings;
+
+ } T42_LoaderRec, *T42_Loader;
+
+
+ FT_LOCAL( FT_Error )
+ t42_parser_init( T42_Parser parser,
+ FT_Stream stream,
+ FT_Memory memory,
+ PSAux_Service psaux );
+
+ FT_LOCAL( void )
+ t42_parser_done( T42_Parser parser );
+
+
+ FT_LOCAL( FT_Error )
+ t42_parse_dict( T42_Face face,
+ T42_Loader loader,
+ FT_Byte* base,
+ FT_Long size );
+
+
+ FT_LOCAL( void )
+ t42_loader_init( T42_Loader loader,
+ T42_Face face );
+
+ FT_LOCAL( void )
+ t42_loader_done( T42_Loader loader );
+
+
+ /* */
+
+FT_END_HEADER
+
+
+#endif /* __T42PARSE_H__ */
+
+
+/* END */
--- /dev/null
+++ b/libfreetype/test_bbox.c
@@ -1,0 +1,160 @@
+#include <ft2build.h>
+#include FT_FREETYPE_H
+#include FT_BBOX_H
+
+
+#include <time.h> /* for clock() */
+
+/* SunOS 4.1.* does not define CLOCKS_PER_SEC, so include <sys/param.h> */
+/* to get the HZ macro which is the equivalent. */
+#if defined(__sun__) && !defined(SVR4) && !defined(__SVR4)
+#include <sys/param.h>
+#define CLOCKS_PER_SEC HZ
+#endif
+
+ static long
+ get_time( void )
+ {
+ return clock() * 10000L / CLOCKS_PER_SEC;
+ }
+
+
+
+
+ /* test bbox computations */
+
+#define XSCALE 65536
+#define XX(x) ((FT_Pos)(x*XSCALE))
+#define XVEC(x,y) { XX(x), XX(y) }
+#define XVAL(x) ((x)/(1.0*XSCALE))
+
+ /* dummy outline #1 */
+ static FT_Vector dummy_vec_1[4] =
+ {
+#if 1
+ XVEC( 408.9111, 535.3164 ),
+ XVEC( 455.8887, 634.396 ),
+ XVEC( -37.8765, 786.2207 ),
+ XVEC( 164.6074, 535.3164 )
+#else
+ { (FT_Int32)0x0198E93DL , (FT_Int32)0x021750FFL }, /* 408.9111, 535.3164 */
+ { (FT_Int32)0x01C7E312L , (FT_Int32)0x027A6560L }, /* 455.8887, 634.3960 */
+ { (FT_Int32)0xFFDA1F9EL , (FT_Int32)0x0312387FL }, /* -37.8765, 786.2207 */
+ { (FT_Int32)0x00A49B7EL , (FT_Int32)0x021750FFL } /* 164.6074, 535.3164 */
+#endif
+ };
+
+ static char dummy_tag_1[4] =
+ {
+ FT_CURVE_TAG_ON,
+ FT_CURVE_TAG_CUBIC,
+ FT_CURVE_TAG_CUBIC,
+ FT_CURVE_TAG_ON
+ };
+
+ static short dummy_contour_1[1] =
+ {
+ 3
+ };
+
+ static FT_Outline dummy_outline_1 =
+ {
+ 1,
+ 4,
+ dummy_vec_1,
+ dummy_tag_1,
+ dummy_contour_1,
+ 0
+ };
+
+
+ /* dummy outline #2 */
+ static FT_Vector dummy_vec_2[4] =
+ {
+ XVEC( 100.0, 100.0 ),
+ XVEC( 100.0, 200.0 ),
+ XVEC( 200.0, 200.0 ),
+ XVEC( 200.0, 133.0 )
+ };
+
+ static FT_Outline dummy_outline_2 =
+ {
+ 1,
+ 4,
+ dummy_vec_2,
+ dummy_tag_1,
+ dummy_contour_1,
+ 0
+ };
+
+
+ static void
+ dump_outline( FT_Outline* outline )
+ {
+ FT_BBox bbox;
+
+ /* compute and display cbox */
+ FT_Outline_Get_CBox( outline, &bbox );
+ printf( "cbox = [%.2f %.2f %.2f %.2f]\n",
+ XVAL( bbox.xMin ),
+ XVAL( bbox.yMin ),
+ XVAL( bbox.xMax ),
+ XVAL( bbox.yMax ) );
+
+ /* compute and display bbox */
+ FT_Outline_Get_BBox( outline, &bbox );
+ printf( "bbox = [%.2f %.2f %.2f %.2f]\n",
+ XVAL( bbox.xMin ),
+ XVAL( bbox.yMin ),
+ XVAL( bbox.xMax ),
+ XVAL( bbox.yMax ) );
+ }
+
+
+
+ static void
+ profile_outline( FT_Outline* outline,
+ long repeat )
+ {
+ FT_BBox bbox;
+ long count;
+ long time0;
+
+ time0 = get_time();
+ for ( count = repeat; count > 0; count-- )
+ FT_Outline_Get_CBox( outline, &bbox );
+
+ time0 = get_time() - time0;
+ printf( "time = %5.2f cbox = [%.2f %.2f %.2f %.2f]\n",
+ ((double)time0/10000.0),
+ XVAL( bbox.xMin ),
+ XVAL( bbox.yMin ),
+ XVAL( bbox.xMax ),
+ XVAL( bbox.yMax ) );
+
+
+ time0 = get_time();
+ for ( count = repeat; count > 0; count-- )
+ FT_Outline_Get_BBox( outline, &bbox );
+
+ time0 = get_time() - time0;
+ printf( "time = %5.2f bbox = [%.2f %.2f %.2f %.2f]\n",
+ ((double)time0/10000.0),
+ XVAL( bbox.xMin ),
+ XVAL( bbox.yMin ),
+ XVAL( bbox.xMax ),
+ XVAL( bbox.yMax ) );
+ }
+
+#define REPEAT 100000L
+
+ int main( int argc, char** argv )
+ {
+ printf( "outline #1\n" );
+ profile_outline( &dummy_outline_1, REPEAT );
+
+ printf( "outline #2\n" );
+ profile_outline( &dummy_outline_2, REPEAT );
+ return 0;
+ }
+
--- /dev/null
+++ b/libfreetype/test_trig.c
@@ -1,0 +1,236 @@
+#include <ft2build.h>
+#include FT_FREETYPE_H
+#include FT_TRIGONOMETRY_H
+
+#include <math.h>
+#include <stdio.h>
+
+#define PI 3.14159265358979323846
+#define SPI (PI/FT_ANGLE_PI)
+
+/* the precision in 16.16 fixed float points of the checks. Expect */
+/* between 2 and 5 noise LSB bits during operations, due to */
+/* rounding errors.. */
+#define THRESHOLD 64
+
+ static error = 0;
+
+ static void
+ test_cos( void )
+ {
+ FT_Fixed f1, f2;
+ double d1, d2;
+ int i;
+
+ for ( i = 0; i < FT_ANGLE_2PI; i += 0x10000 )
+ {
+ f1 = FT_Cos(i);
+ d1 = f1/65536.0;
+ d2 = cos( i*SPI );
+ f2 = (FT_Fixed)(d2*65536.0);
+
+ if ( abs( f2-f1 ) > THRESHOLD )
+ {
+ error = 1;
+ printf( "FT_Cos[%3d] = %.7f cos[%3d] = %.7f\n",
+ (i >> 16), f1/65536.0, (i >> 16), d2 );
+ }
+ }
+ }
+
+
+
+ static void
+ test_sin( void )
+ {
+ FT_Fixed f1, f2;
+ double d1, d2;
+ int i;
+
+ for ( i = 0; i < FT_ANGLE_2PI; i += 0x10000 )
+ {
+ f1 = FT_Sin(i);
+ d1 = f1/65536.0;
+ d2 = sin( i*SPI );
+ f2 = (FT_Fixed)(d2*65536.0);
+
+ if ( abs( f2-f1 ) > THRESHOLD )
+ {
+ error = 1;
+ printf( "FT_Sin[%3d] = %.7f sin[%3d] = %.7f\n",
+ (i >> 16), f1/65536.0, (i >> 16), d2 );
+ }
+ }
+ }
+
+
+ static void
+ test_tan( void )
+ {
+ FT_Fixed f1, f2;
+ double d1, d2;
+ int i;
+
+ for ( i = 0; i < FT_ANGLE_PI2-0x2000000; i += 0x10000 )
+ {
+ f1 = FT_Tan(i);
+ d1 = f1/65536.0;
+ d2 = tan( i*SPI );
+ f2 = (FT_Fixed)(d2*65536.0);
+
+ if ( abs( f2-f1 ) > THRESHOLD )
+ {
+ error = 1;
+ printf( "FT_Tan[%3d] = %.7f tan[%3d] = %.7f\n",
+ (i >> 16), f1/65536.0, (i >> 16), d2 );
+ }
+ }
+ }
+
+
+ static void
+ test_atan2( void )
+ {
+ FT_Fixed c2, s2;
+ double l, a, c1, s1;
+ int i, j;
+
+ for ( i = 0; i < FT_ANGLE_2PI; i += 0x10000 )
+ {
+ l = 5.0;
+ a = i*SPI;
+
+ c1 = l * cos(a);
+ s1 = l * sin(a);
+
+ c2 = (FT_Fixed)(c1*65536.0);
+ s2 = (FT_Fixed)(s1*65536.0);
+
+ j = FT_Atan2( c2, s2 );
+ if ( j < 0 )
+ j += FT_ANGLE_2PI;
+
+ if ( abs( i - j ) > 1 )
+ {
+ printf( "FT_Atan2( %.7f, %.7f ) = %.5f, atan = %.5f\n",
+ c2/65536.0, s2/65536.0, j/65536.0, i/65536.0 );
+ }
+ }
+ }
+
+ static void
+ test_unit( void )
+ {
+ FT_Vector v;
+ double a, c1, s1;
+ FT_Fixed c2, s2;
+ int i;
+
+ for ( i = 0; i < FT_ANGLE_2PI; i += 0x10000 )
+ {
+ FT_Vector_Unit( &v, i );
+ a = ( i*SPI );
+ c1 = cos(a);
+ s1 = sin(a);
+ c2 = (FT_Fixed)(c1*65536.0);
+ s2 = (FT_Fixed)(s1*65536.0);
+
+ if ( abs( v.x-c2 ) > THRESHOLD ||
+ abs( v.y-s2 ) > THRESHOLD )
+ {
+ error = 1;
+ printf( "FT_Vector_Unit[%3d] = ( %.7f, %.7f ) vec = ( %.7f, %.7f )\n",
+ (i >> 16),
+ v.x/65536.0, v.y/65536.0,
+ c1, s1 );
+ }
+ }
+ }
+
+
+ static void
+ test_length( void )
+ {
+ FT_Vector v;
+ FT_Fixed l, l2;
+ int i;
+
+ for ( i = 0; i < FT_ANGLE_2PI; i += 0x10000 )
+ {
+ l = (FT_Fixed)(500.0*65536.0);
+ v.x = (FT_Fixed)( l * cos( i*SPI ) );
+ v.y = (FT_Fixed)( l * sin( i*SPI ) );
+ l2 = FT_Vector_Length( &v );
+
+ if ( abs( l2-l ) > THRESHOLD )
+ {
+ error = 1;
+ printf( "FT_Length( %.7f, %.7f ) = %.5f, length = %.5f\n",
+ v.x/65536.0, v.y/65536.0, l2/65536.0, l/65536.0 );
+ }
+ }
+ }
+
+
+ static void
+ test_rotate( void )
+ {
+ FT_Fixed c2, s2, c4, s4;
+ FT_Vector v;
+ double l, ra, a, c1, s1, cra, sra, c3, s3;
+ int i, j, rotate;
+
+ for ( rotate = 0; rotate < FT_ANGLE_2PI; rotate += 0x10000 )
+ {
+ ra = rotate*SPI;
+ cra = cos( ra );
+ sra = sin( ra );
+
+ for ( i = 0; i < FT_ANGLE_2PI; i += 0x10000 )
+ {
+ l = 500.0;
+ a = i*SPI;
+
+ c1 = l * cos(a);
+ s1 = l * sin(a);
+
+ v.x = c2 = (FT_Fixed)(c1*65536.0);
+ v.y = s2 = (FT_Fixed)(s1*65536.0);
+
+ FT_Vector_Rotate( &v, rotate );
+
+ c3 = c1 * cra - s1 * sra;
+ s3 = c1 * sra + s1 * cra;
+
+ c4 = (FT_Fixed)(c3*65536.0);
+ s4 = (FT_Fixed)(s3*65536.0);
+
+ if ( abs( c4 - v.x ) > THRESHOLD ||
+ abs( s4 - v.y ) > THRESHOLD )
+ {
+ error = 1;
+ printf( "FT_Rotate( (%.7f,%.7f), %.5f ) = ( %.7f, %.7f ), rot = ( %.7f, %.7f )\n",
+ c1, s1, ra,
+ c2/65536.0, s2/65536.0,
+ c4/65536.0, s4/65536.0 );
+ }
+ }
+ }
+ }
+
+
+ int main( void )
+ {
+ test_cos();
+ test_sin();
+ test_tan();
+ test_atan2();
+ test_unit();
+ test_length();
+ test_rotate();
+
+ if (!error)
+ printf( "trigonometry test ok !\n" );
+
+ return !error;
+ }
--- /dev/null
+++ b/libfreetype/truetype.c
@@ -1,0 +1,32 @@
+/***************************************************************************/
+/* */
+/* truetype.c */
+/* */
+/* FreeType TrueType driver component (body only). */
+/* */
+/* Copyright 1996-2001 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+
+#define FT_MAKE_OPTION_SINGLE_OBJECT
+
+#include <ft2build.h>
+#include "ttdriver.c" /* driver interface */
+#include "ttpload.c" /* tables loader */
+#include "ttgload.c" /* glyph loader */
+#include "ttobjs.c" /* object manager */
+
+#ifdef TT_CONFIG_OPTION_BYTECODE_INTERPRETER
+#include "ttinterp.c"
+#endif
+
+
+/* END */
--- /dev/null
+++ b/libfreetype/ttcmap.c
@@ -1,0 +1,1110 @@
+/***************************************************************************/
+/* */
+/* ttcmap.c */
+/* */
+/* TrueType character mapping table (cmap) support (body). */
+/* */
+/* Copyright 1996-2001, 2002 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+
+#include <ft2build.h>
+#include FT_INTERNAL_DEBUG_H
+#include "ttload.h"
+#include "ttcmap.h"
+
+#include "sferrors.h"
+
+
+ /*************************************************************************/
+ /* */
+ /* The macro FT_COMPONENT is used in trace mode. It is an implicit */
+ /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log */
+ /* messages during execution. */
+ /* */
+#undef FT_COMPONENT
+#define FT_COMPONENT trace_ttcmap
+
+
+ FT_CALLBACK_DEF( FT_UInt )
+ code_to_index0( TT_CMapTable charmap,
+ FT_ULong char_code );
+
+ FT_CALLBACK_DEF( FT_ULong )
+ code_to_next0( TT_CMapTable charmap,
+ FT_ULong char_code );
+
+ FT_CALLBACK_DEF( FT_UInt )
+ code_to_index2( TT_CMapTable charmap,
+ FT_ULong char_code );
+
+ FT_CALLBACK_DEF( FT_ULong )
+ code_to_next2( TT_CMapTable charmap,
+ FT_ULong char_code );
+
+ FT_CALLBACK_DEF( FT_UInt )
+ code_to_index4( TT_CMapTable charmap,
+ FT_ULong char_code );
+
+ FT_CALLBACK_DEF( FT_ULong )
+ code_to_next4( TT_CMapTable charmap,
+ FT_ULong char_code );
+
+ FT_CALLBACK_DEF( FT_UInt )
+ code_to_index6( TT_CMapTable charmap,
+ FT_ULong char_code );
+
+ FT_CALLBACK_DEF( FT_ULong )
+ code_to_next6( TT_CMapTable charmap,
+ FT_ULong char_code );
+
+ FT_CALLBACK_DEF( FT_UInt )
+ code_to_index8_12( TT_CMapTable charmap,
+ FT_ULong char_code );
+
+ FT_CALLBACK_DEF( FT_ULong )
+ code_to_next8_12( TT_CMapTable charmap,
+ FT_ULong char_code );
+
+ FT_CALLBACK_DEF( FT_UInt )
+ code_to_index10( TT_CMapTable charmap,
+ FT_ULong char_code );
+
+ FT_CALLBACK_DEF( FT_ULong )
+ code_to_next10( TT_CMapTable charmap,
+ FT_ULong char_code );
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* tt_face_load_charmap */
+ /* */
+ /* <Description> */
+ /* Loads a given TrueType character map into memory. */
+ /* */
+ /* <Input> */
+ /* face :: A handle to the parent face object. */
+ /* */
+ /* stream :: A handle to the current stream object. */
+ /* */
+ /* <InOut> */
+ /* table :: A pointer to a cmap object. */
+ /* */
+ /* <Return> */
+ /* FreeType error code. 0 means success. */
+ /* */
+ /* <Note> */
+ /* The function assumes that the stream is already in use (i.e., */
+ /* opened). In case of error, all partially allocated tables are */
+ /* released. */
+ /* */
+ FT_LOCAL_DEF( FT_Error )
+ tt_face_load_charmap( TT_Face face,
+ TT_CMapTable cmap,
+ FT_Stream stream )
+ {
+ FT_Error error;
+ FT_Memory memory;
+ FT_UShort num_SH, num_Seg, i;
+ FT_ULong j, n;
+
+ FT_UShort u, l;
+
+ TT_CMap0 cmap0;
+ TT_CMap2 cmap2;
+ TT_CMap4 cmap4;
+ TT_CMap6 cmap6;
+ TT_CMap8_12 cmap8_12;
+ TT_CMap10 cmap10;
+
+ TT_CMap2SubHeader cmap2sub;
+ TT_CMap4Segment segments;
+ TT_CMapGroup groups;
+
+
+ if ( cmap->loaded )
+ return SFNT_Err_Ok;
+
+ memory = stream->memory;
+
+ if ( FT_STREAM_SEEK( cmap->offset ) )
+ return error;
+
+ switch ( cmap->format )
+ {
+ case 0:
+ cmap0 = &cmap->c.cmap0;
+
+ if ( FT_READ_USHORT( cmap0->language ) ||
+ FT_ALLOC( cmap0->glyphIdArray, 256L ) ||
+ FT_STREAM_READ( cmap0->glyphIdArray, 256L ) )
+ goto Fail;
+
+ cmap->get_index = code_to_index0;
+ cmap->get_next_char = code_to_next0;
+ break;
+
+ case 2:
+ num_SH = 0;
+ cmap2 = &cmap->c.cmap2;
+
+ /* allocate subheader keys */
+
+ if ( FT_NEW_ARRAY( cmap2->subHeaderKeys, 256 ) ||
+ FT_FRAME_ENTER( 2L + 512L ) )
+ goto Fail;
+
+ cmap2->language = FT_GET_USHORT();
+
+ for ( i = 0; i < 256; i++ )
+ {
+ u = (FT_UShort)( FT_GET_USHORT() / 8 );
+ cmap2->subHeaderKeys[i] = u;
+
+ if ( num_SH < u )
+ num_SH = u;
+ }
+
+ FT_FRAME_EXIT();
+
+ /* load subheaders */
+
+ cmap2->numGlyphId = l = (FT_UShort)(
+ ( ( cmap->length - 2L * ( 256 + 3 ) - num_SH * 8L ) & 0xFFFFU ) / 2 );
+
+ if ( FT_NEW_ARRAY( cmap2->subHeaders, num_SH + 1 ) ||
+ FT_FRAME_ENTER( ( num_SH + 1 ) * 8L ) )
+ {
+ FT_FREE( cmap2->subHeaderKeys );
+ goto Fail;
+ }
+
+ cmap2sub = cmap2->subHeaders;
+
+ for ( i = 0; i <= num_SH; i++ )
+ {
+ cmap2sub->firstCode = FT_GET_USHORT();
+ cmap2sub->entryCount = FT_GET_USHORT();
+ cmap2sub->idDelta = FT_GET_SHORT();
+ /* we apply the location offset immediately */
+ cmap2sub->idRangeOffset = (FT_UShort)(
+ FT_GET_USHORT() - ( num_SH - i ) * 8 - 2 );
+
+ cmap2sub++;
+ }
+
+ FT_FRAME_EXIT();
+
+ /* load glyph IDs */
+
+ if ( FT_NEW_ARRAY( cmap2->glyphIdArray, l ) ||
+ FT_FRAME_ENTER( l * 2L ) )
+ {
+ FT_FREE( cmap2->subHeaders );
+ FT_FREE( cmap2->subHeaderKeys );
+ goto Fail;
+ }
+
+ for ( i = 0; i < l; i++ )
+ cmap2->glyphIdArray[i] = FT_GET_USHORT();
+
+ FT_FRAME_EXIT();
+
+ cmap->get_index = code_to_index2;
+ cmap->get_next_char = code_to_next2;
+ break;
+
+ case 4:
+ cmap4 = &cmap->c.cmap4;
+
+ /* load header */
+
+ if ( FT_FRAME_ENTER( 10L ) )
+ goto Fail;
+
+ cmap4->language = FT_GET_USHORT();
+ cmap4->segCountX2 = FT_GET_USHORT();
+ cmap4->searchRange = FT_GET_USHORT();
+ cmap4->entrySelector = FT_GET_USHORT();
+ cmap4->rangeShift = FT_GET_USHORT();
+
+ num_Seg = (FT_UShort)( cmap4->segCountX2 / 2 );
+
+ FT_FRAME_EXIT();
+
+ /* load segments */
+
+ if ( FT_NEW_ARRAY( cmap4->segments, num_Seg ) ||
+ FT_FRAME_ENTER( ( num_Seg * 4 + 1 ) * 2L ) )
+ goto Fail;
+
+ segments = cmap4->segments;
+
+ for ( i = 0; i < num_Seg; i++ )
+ segments[i].endCount = FT_GET_USHORT();
+
+ (void)FT_GET_USHORT();
+
+ for ( i = 0; i < num_Seg; i++ )
+ segments[i].startCount = FT_GET_USHORT();
+
+ for ( i = 0; i < num_Seg; i++ )
+ segments[i].idDelta = FT_GET_SHORT();
+
+ for ( i = 0; i < num_Seg; i++ )
+ segments[i].idRangeOffset = FT_GET_USHORT();
+
+ FT_FRAME_EXIT();
+
+ cmap4->numGlyphId = l = (FT_UShort)(
+ ( ( cmap->length - ( 16L + 8L * num_Seg ) ) & 0xFFFFU ) / 2 );
+
+ /* load IDs */
+
+ if ( FT_NEW_ARRAY( cmap4->glyphIdArray, l ) ||
+ FT_FRAME_ENTER( l * 2L ) )
+ {
+ FT_FREE( cmap4->segments );
+ goto Fail;
+ }
+
+ for ( i = 0; i < l; i++ )
+ cmap4->glyphIdArray[i] = FT_GET_USHORT();
+
+ FT_FRAME_EXIT();
+
+ cmap4->last_segment = cmap4->segments;
+
+ cmap->get_index = code_to_index4;
+ cmap->get_next_char = code_to_next4;
+ break;
+
+ case 6:
+ cmap6 = &cmap->c.cmap6;
+
+ if ( FT_FRAME_ENTER( 6L ) )
+ goto Fail;
+
+ cmap6->language = FT_GET_USHORT();
+ cmap6->firstCode = FT_GET_USHORT();
+ cmap6->entryCount = FT_GET_USHORT();
+
+ FT_FRAME_EXIT();
+
+ l = cmap6->entryCount;
+
+ if ( FT_NEW_ARRAY( cmap6->glyphIdArray, l ) ||
+ FT_FRAME_ENTER( l * 2L ) )
+ goto Fail;
+
+ for ( i = 0; i < l; i++ )
+ cmap6->glyphIdArray[i] = FT_GET_USHORT();
+
+ FT_FRAME_EXIT();
+ cmap->get_index = code_to_index6;
+ cmap->get_next_char = code_to_next6;
+ break;
+
+ case 8:
+ case 12:
+ cmap8_12 = &cmap->c.cmap8_12;
+
+ if ( FT_FRAME_ENTER( 8L ) )
+ goto Fail;
+
+ cmap->length = FT_GET_ULONG();
+ cmap8_12->language = FT_GET_ULONG();
+
+ FT_FRAME_EXIT();
+
+ if ( cmap->format == 8 )
+ if ( FT_STREAM_SKIP( 8192L ) )
+ goto Fail;
+
+ if ( FT_READ_ULONG( cmap8_12->nGroups ) )
+ goto Fail;
+
+ n = cmap8_12->nGroups;
+
+ if ( FT_NEW_ARRAY( cmap8_12->groups, n ) ||
+ FT_FRAME_ENTER( n * 3 * 4L ) )
+ goto Fail;
+
+ groups = cmap8_12->groups;
+
+ for ( j = 0; j < n; j++ )
+ {
+ groups[j].startCharCode = FT_GET_ULONG();
+ groups[j].endCharCode = FT_GET_ULONG();
+ groups[j].startGlyphID = FT_GET_ULONG();
+ }
+
+ FT_FRAME_EXIT();
+
+ cmap8_12->last_group = cmap8_12->groups;
+
+ cmap->get_index = code_to_index8_12;
+ cmap->get_next_char = code_to_next8_12;
+ break;
+
+ case 10:
+ cmap10 = &cmap->c.cmap10;
+
+ if ( FT_FRAME_ENTER( 16L ) )
+ goto Fail;
+
+ cmap->length = FT_GET_ULONG();
+ cmap10->language = FT_GET_ULONG();
+ cmap10->startCharCode = FT_GET_ULONG();
+ cmap10->numChars = FT_GET_ULONG();
+
+ FT_FRAME_EXIT();
+
+ n = cmap10->numChars;
+
+ if ( FT_NEW_ARRAY( cmap10->glyphs, n ) ||
+ FT_FRAME_ENTER( n * 2L ) )
+ goto Fail;
+
+ for ( j = 0; j < n; j++ )
+ cmap10->glyphs[j] = FT_GET_USHORT();
+
+ FT_FRAME_EXIT();
+ cmap->get_index = code_to_index10;
+ cmap->get_next_char = code_to_next10;
+ break;
+
+ default: /* corrupt character mapping table */
+ return SFNT_Err_Invalid_CharMap_Format;
+
+ }
+
+ return SFNT_Err_Ok;
+
+ Fail:
+ tt_face_free_charmap( face, cmap );
+ return error;
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* tt_face_free_charmap */
+ /* */
+ /* <Description> */
+ /* Destroys a character mapping table. */
+ /* */
+ /* <Input> */
+ /* face :: A handle to the parent face object. */
+ /* */
+ /* cmap :: A handle to a cmap object. */
+ /* */
+ /* <Return> */
+ /* FreeType error code. 0 means success. */
+ /* */
+ FT_LOCAL_DEF( FT_Error )
+ tt_face_free_charmap( TT_Face face,
+ TT_CMapTable cmap )
+ {
+ FT_Memory memory;
+
+
+ if ( !cmap )
+ return SFNT_Err_Ok;
+
+ memory = face->root.driver->root.memory;
+
+ switch ( cmap->format )
+ {
+ case 0:
+ FT_FREE( cmap->c.cmap0.glyphIdArray );
+ break;
+
+ case 2:
+ FT_FREE( cmap->c.cmap2.subHeaderKeys );
+ FT_FREE( cmap->c.cmap2.subHeaders );
+ FT_FREE( cmap->c.cmap2.glyphIdArray );
+ break;
+
+ case 4:
+ FT_FREE( cmap->c.cmap4.segments );
+ FT_FREE( cmap->c.cmap4.glyphIdArray );
+ cmap->c.cmap4.segCountX2 = 0;
+ break;
+
+ case 6:
+ FT_FREE( cmap->c.cmap6.glyphIdArray );
+ cmap->c.cmap6.entryCount = 0;
+ break;
+
+ case 8:
+ case 12:
+ FT_FREE( cmap->c.cmap8_12.groups );
+ cmap->c.cmap8_12.nGroups = 0;
+ break;
+
+ case 10:
+ FT_FREE( cmap->c.cmap10.glyphs );
+ cmap->c.cmap10.numChars = 0;
+ break;
+
+ default:
+ /* invalid table format, do nothing */
+ ;
+ }
+
+ cmap->loaded = FALSE;
+ return SFNT_Err_Ok;
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* code_to_index0 */
+ /* */
+ /* <Description> */
+ /* Converts the character code into a glyph index. Uses format 0. */
+ /* `charCode' must be in the range 0x00-0xFF (otherwise 0 is */
+ /* returned). */
+ /* */
+ /* <Input> */
+ /* charCode :: The wanted character code. */
+ /* */
+ /* cmap0 :: A pointer to a cmap table in format 0. */
+ /* */
+ /* <Return> */
+ /* Glyph index into the glyphs array. 0 if the glyph does not exist. */
+ /* */
+ FT_CALLBACK_DEF( FT_UInt )
+ code_to_index0( TT_CMapTable cmap,
+ FT_ULong charCode )
+ {
+ TT_CMap0 cmap0 = &cmap->c.cmap0;
+
+
+ return ( charCode <= 0xFF ? cmap0->glyphIdArray[charCode] : 0 );
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* code_to_next0 */
+ /* */
+ /* <Description> */
+ /* Finds the next encoded character after the given one. Uses */
+ /* format 0. `charCode' must be in the range 0x00-0xFF (otherwise 0 */
+ /* is returned). */
+ /* */
+ /* <Input> */
+ /* charCode :: The wanted character code. */
+ /* */
+ /* cmap0 :: A pointer to a cmap table in format 0. */
+ /* */
+ /* <Return> */
+ /* Next char code. 0 if no higher one is encoded. */
+ /* */
+ FT_CALLBACK_DEF( FT_ULong )
+ code_to_next0( TT_CMapTable cmap,
+ FT_ULong charCode )
+ {
+ TT_CMap0 cmap0 = &cmap->c.cmap0;
+
+
+ while ( ++charCode <= 0xFF )
+ if ( cmap0->glyphIdArray[charCode] )
+ return ( charCode );
+ return ( 0 );
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* code_to_index2 */
+ /* */
+ /* <Description> */
+ /* Converts the character code into a glyph index. Uses format 2. */
+ /* */
+ /* <Input> */
+ /* charCode :: The wanted character code. */
+ /* */
+ /* cmap2 :: A pointer to a cmap table in format 2. */
+ /* */
+ /* <Return> */
+ /* Glyph index into the glyphs array. 0 if the glyph does not exist. */
+ /* */
+ FT_CALLBACK_DEF( FT_UInt )
+ code_to_index2( TT_CMapTable cmap,
+ FT_ULong charCode )
+ {
+ FT_UInt result, index1, offset;
+ FT_UInt char_lo;
+ FT_ULong char_hi;
+ TT_CMap2SubHeader sh2;
+ TT_CMap2 cmap2;
+
+
+ cmap2 = &cmap->c.cmap2;
+ result = 0;
+ char_lo = (FT_UInt)( charCode & 0xFF );
+ char_hi = charCode >> 8;
+
+ if ( char_hi == 0 )
+ {
+ /* an 8-bit character code -- we use the subHeader 0 in this case */
+ /* to test whether the character code is in the charmap */
+ index1 = cmap2->subHeaderKeys[char_lo];
+ if ( index1 != 0 )
+ return 0;
+ }
+ else
+ {
+ /* a 16-bit character code */
+ index1 = cmap2->subHeaderKeys[char_hi & 0xFF];
+ if ( index1 == 0 )
+ return 0;
+ }
+
+ sh2 = cmap2->subHeaders + index1;
+ char_lo -= sh2->firstCode;
+
+ if ( char_lo < (FT_UInt)sh2->entryCount )
+ {
+ offset = sh2->idRangeOffset / 2 + char_lo;
+ if ( offset < (FT_UInt)cmap2->numGlyphId )
+ {
+ result = cmap2->glyphIdArray[offset];
+ if ( result )
+ result = ( result + sh2->idDelta ) & 0xFFFFU;
+ }
+ }
+
+ return result;
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* code_to_next2 */
+ /* */
+ /* <Description> */
+ /* Find the next encoded character. Uses format 2. */
+ /* */
+ /* <Input> */
+ /* charCode :: The wanted character code. */
+ /* */
+ /* cmap2 :: A pointer to a cmap table in format 2. */
+ /* */
+ /* <Return> */
+ /* Next encoded character. 0 if none exists. */
+ /* */
+ FT_CALLBACK_DEF( FT_ULong )
+ code_to_next2( TT_CMapTable cmap,
+ FT_ULong charCode )
+ {
+ FT_UInt index1, offset;
+ FT_UInt char_lo;
+ FT_ULong char_hi;
+ TT_CMap2SubHeader sh2;
+ TT_CMap2 cmap2;
+
+
+ cmap2 = &cmap->c.cmap2;
+ charCode++;
+
+ /*
+ * This is relatively simplistic -- look for a subHeader containing
+ * glyphs and then walk to the first glyph in that subHeader.
+ */
+ while ( charCode < 0x10000L )
+ {
+ char_lo = (FT_UInt)( charCode & 0xFF );
+ char_hi = charCode >> 8;
+
+ if ( char_hi == 0 )
+ {
+ /* an 8-bit character code -- we use the subHeader 0 in this case */
+ /* to test whether the character code is in the charmap */
+ index1 = cmap2->subHeaderKeys[char_lo];
+ if ( index1 != 0 )
+ {
+ charCode++;
+ continue;
+ }
+ }
+ else
+ {
+ /* a 16-bit character code */
+ index1 = cmap2->subHeaderKeys[char_hi & 0xFF];
+ if ( index1 == 0 )
+ {
+ charCode = ( char_hi + 1 ) << 8;
+ continue;
+ }
+ }
+
+ sh2 = cmap2->subHeaders + index1;
+ char_lo -= sh2->firstCode;
+
+ if ( char_lo > (FT_UInt)sh2->entryCount )
+ {
+ charCode = ( char_hi + 1 ) << 8;
+ continue;
+ }
+
+ offset = sh2->idRangeOffset / 2 + char_lo;
+ if ( offset >= (FT_UInt)cmap2->numGlyphId ||
+ cmap2->glyphIdArray[offset] == 0 )
+ {
+ charCode++;
+ continue;
+ }
+
+ return charCode;
+ }
+ return 0;
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* code_to_index4 */
+ /* */
+ /* <Description> */
+ /* Converts the character code into a glyph index. Uses format 4. */
+ /* */
+ /* <Input> */
+ /* charCode :: The wanted character code. */
+ /* */
+ /* cmap4 :: A pointer to a cmap table in format 4. */
+ /* */
+ /* <Return> */
+ /* Glyph index into the glyphs array. 0 if the glyph does not exist. */
+ /* */
+ FT_CALLBACK_DEF( FT_UInt )
+ code_to_index4( TT_CMapTable cmap,
+ FT_ULong charCode )
+ {
+ FT_UInt result, index1, segCount;
+ TT_CMap4 cmap4;
+ TT_CMap4SegmentRec *seg4, *limit;
+
+
+ cmap4 = &cmap->c.cmap4;
+ result = 0;
+ segCount = cmap4->segCountX2 / 2;
+ limit = cmap4->segments + segCount;
+
+ /* first, check against the last used segment */
+
+ seg4 = cmap4->last_segment;
+
+ /* the following is equivalent to performing two tests, as in */
+ /* */
+ /* if ( charCode >= seg4->startCount && charCode <= seg4->endCount ) */
+ /* */
+ /* This is a bit strange, but it is faster, and the idea behind the */
+ /* cache is to significantly speed up charcode to glyph index */
+ /* conversion. */
+
+ if ( (FT_ULong)( charCode - seg4->startCount ) <
+ (FT_ULong)( seg4->endCount - seg4->startCount ) )
+ goto Found1;
+
+ for ( seg4 = cmap4->segments; seg4 < limit; seg4++ )
+ {
+ /* the ranges are sorted in increasing order. If we are out of */
+ /* the range here, the char code isn't in the charmap, so exit. */
+
+ if ( charCode > (FT_UInt)seg4->endCount )
+ continue;
+
+ if ( charCode >= (FT_UInt)seg4->startCount )
+ goto Found;
+ }
+ return 0;
+
+ Found:
+ cmap4->last_segment = seg4;
+
+ Found1:
+ /* if the idRangeOffset is 0, we can compute the glyph index */
+ /* directly */
+
+ if ( seg4->idRangeOffset == 0 )
+ result = (FT_UInt)( charCode + seg4->idDelta ) & 0xFFFFU;
+ else
+ {
+ /* otherwise, we must use the glyphIdArray to do it */
+ index1 = (FT_UInt)( seg4->idRangeOffset / 2
+ + ( charCode - seg4->startCount )
+ + ( seg4 - cmap4->segments )
+ - segCount );
+
+ if ( index1 < (FT_UInt)cmap4->numGlyphId &&
+ cmap4->glyphIdArray[index1] != 0 )
+ result = ( cmap4->glyphIdArray[index1] + seg4->idDelta ) & 0xFFFFU;
+ }
+
+ return result;
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* code_to_next4 */
+ /* */
+ /* <Description> */
+ /* Find the next encoded character. Uses format 4. */
+ /* */
+ /* <Input> */
+ /* charCode :: The wanted character code. */
+ /* */
+ /* cmap :: A pointer to a cmap table in format 4. */
+ /* */
+ /* <Return> */
+ /* Next encoded character. 0 if none exists. */
+ /* */
+ FT_CALLBACK_DEF( FT_ULong )
+ code_to_next4( TT_CMapTable cmap,
+ FT_ULong charCode )
+ {
+ FT_UInt index1, segCount;
+ TT_CMap4 cmap4;
+ TT_CMap4SegmentRec *seg4, *limit;
+
+
+ cmap4 = &cmap->c.cmap4;
+ segCount = cmap4->segCountX2 / 2;
+ limit = cmap4->segments + segCount;
+
+ charCode++;
+
+ for ( seg4 = cmap4->segments; seg4 < limit; seg4++ )
+ {
+ /* The ranges are sorted in increasing order. If we are out of */
+ /* the range here, the char code isn't in the charmap, so exit. */
+
+ if ( charCode <= (FT_UInt)seg4->endCount )
+ goto Found;
+ }
+ return 0;
+
+ Found:
+ if ( charCode < (FT_ULong) seg4->startCount )
+ charCode = seg4->startCount;
+
+ /* if the idRangeOffset is 0, all chars in the map exist */
+
+ if ( seg4->idRangeOffset == 0 )
+ return ( charCode );
+
+ while ( charCode <= (FT_UInt) seg4->endCount )
+ {
+ /* otherwise, we must use the glyphIdArray to do it */
+ index1 = (FT_UInt)( seg4->idRangeOffset / 2
+ + ( charCode - seg4->startCount )
+ + ( seg4 - cmap4->segments )
+ - segCount );
+
+ if ( index1 < (FT_UInt)cmap4->numGlyphId &&
+ cmap4->glyphIdArray[index1] != 0 )
+ return ( charCode );
+ charCode++;
+ }
+
+ return 0;
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* code_to_index6 */
+ /* */
+ /* <Description> */
+ /* Converts the character code into a glyph index. Uses format 6. */
+ /* */
+ /* <Input> */
+ /* charCode :: The wanted character code. */
+ /* */
+ /* cmap6 :: A pointer to a cmap table in format 6. */
+ /* */
+ /* <Return> */
+ /* Glyph index into the glyphs array. 0 if the glyph does not exist. */
+ /* */
+ FT_CALLBACK_DEF( FT_UInt )
+ code_to_index6( TT_CMapTable cmap,
+ FT_ULong charCode )
+ {
+ TT_CMap6 cmap6;
+ FT_UInt result = 0;
+
+
+ cmap6 = &cmap->c.cmap6;
+ charCode -= cmap6->firstCode;
+
+ if ( charCode < (FT_UInt)cmap6->entryCount )
+ result = cmap6->glyphIdArray[charCode];
+
+ return result;
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* code_to_next6 */
+ /* */
+ /* <Description> */
+ /* Find the next encoded character. Uses format 6. */
+ /* */
+ /* <Input> */
+ /* charCode :: The wanted character code. */
+ /* */
+ /* cmap :: A pointer to a cmap table in format 6. */
+ /* */
+ /* <Return> */
+ /* Next encoded character. 0 if none exists. */
+ /* */
+ FT_CALLBACK_DEF( FT_ULong )
+ code_to_next6( TT_CMapTable cmap,
+ FT_ULong charCode )
+ {
+ TT_CMap6 cmap6;
+
+
+ charCode++;
+
+ cmap6 = &cmap->c.cmap6;
+
+ if ( charCode < (FT_ULong) cmap6->firstCode )
+ charCode = cmap6->firstCode;
+
+ charCode -= cmap6->firstCode;
+
+ while ( charCode < (FT_UInt)cmap6->entryCount )
+ {
+ if ( cmap6->glyphIdArray[charCode] != 0 )
+ return charCode + cmap6->firstCode;
+ charCode++;
+ }
+
+ return 0;
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* code_to_index8_12 */
+ /* */
+ /* <Description> */
+ /* Converts the (possibly 32bit) character code into a glyph index. */
+ /* Uses format 8 or 12. */
+ /* */
+ /* <Input> */
+ /* charCode :: The wanted character code. */
+ /* */
+ /* cmap8_12 :: A pointer to a cmap table in format 8 or 12. */
+ /* */
+ /* <Return> */
+ /* Glyph index into the glyphs array. 0 if the glyph does not exist. */
+ /* */
+ FT_CALLBACK_DEF( FT_UInt )
+ code_to_index8_12( TT_CMapTable cmap,
+ FT_ULong charCode )
+ {
+ TT_CMap8_12 cmap8_12;
+ TT_CMapGroupRec *group, *limit;
+
+
+ cmap8_12 = &cmap->c.cmap8_12;
+ limit = cmap8_12->groups + cmap8_12->nGroups;
+
+ /* first, check against the last used group */
+
+ group = cmap8_12->last_group;
+
+ /* the following is equivalent to performing two tests, as in */
+ /* */
+ /* if ( charCode >= group->startCharCode && */
+ /* charCode <= group->endCharCode ) */
+ /* */
+ /* This is a bit strange, but it is faster, and the idea behind the */
+ /* cache is to significantly speed up charcode to glyph index */
+ /* conversion. */
+
+ if ( (FT_ULong)( charCode - group->startCharCode ) <
+ (FT_ULong)( group->endCharCode - group->startCharCode ) )
+ goto Found1;
+
+ for ( group = cmap8_12->groups; group < limit; group++ )
+ {
+ /* the ranges are sorted in increasing order. If we are out of */
+ /* the range here, the char code isn't in the charmap, so exit. */
+
+ if ( charCode > group->endCharCode )
+ continue;
+
+ if ( charCode >= group->startCharCode )
+ goto Found;
+ }
+ return 0;
+
+ Found:
+ cmap8_12->last_group = group;
+
+ Found1:
+ return (FT_UInt)( group->startGlyphID +
+ ( charCode - group->startCharCode ) );
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* code_to_next8_12 */
+ /* */
+ /* <Description> */
+ /* Find the next encoded character. Uses format 8 or 12. */
+ /* */
+ /* <Input> */
+ /* charCode :: The wanted character code. */
+ /* */
+ /* cmap :: A pointer to a cmap table in format 8 or 12. */
+ /* */
+ /* <Return> */
+ /* Next encoded character. 0 if none exists. */
+ /* */
+ FT_CALLBACK_DEF( FT_ULong )
+ code_to_next8_12( TT_CMapTable cmap,
+ FT_ULong charCode )
+ {
+ TT_CMap8_12 cmap8_12;
+ TT_CMapGroupRec *group, *limit;
+
+
+ charCode++;
+ cmap8_12 = &cmap->c.cmap8_12;
+ limit = cmap8_12->groups + cmap8_12->nGroups;
+
+ for ( group = cmap8_12->groups; group < limit; group++ )
+ {
+ /* the ranges are sorted in increasing order. If we are out of */
+ /* the range here, the char code isn't in the charmap, so exit. */
+
+ if ( charCode <= group->endCharCode )
+ goto Found;
+ }
+ return 0;
+
+ Found:
+ if ( charCode < group->startCharCode )
+ charCode = group->startCharCode;
+
+ return charCode;
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* code_to_index10 */
+ /* */
+ /* <Description> */
+ /* Converts the (possibly 32bit) character code into a glyph index. */
+ /* Uses format 10. */
+ /* */
+ /* <Input> */
+ /* charCode :: The wanted character code. */
+ /* */
+ /* cmap10 :: A pointer to a cmap table in format 10. */
+ /* */
+ /* <Return> */
+ /* Glyph index into the glyphs array. 0 if the glyph does not exist. */
+ /* */
+ FT_CALLBACK_DEF( FT_UInt )
+ code_to_index10( TT_CMapTable cmap,
+ FT_ULong charCode )
+ {
+ TT_CMap10 cmap10;
+ FT_UInt result = 0;
+
+
+ cmap10 = &cmap->c.cmap10;
+ charCode -= cmap10->startCharCode;
+
+ /* the overflow trick for comparison works here also since the number */
+ /* of glyphs (even if numChars is specified as ULong in the specs) in */
+ /* an OpenType font is limited to 64k */
+
+ if ( charCode < cmap10->numChars )
+ result = cmap10->glyphs[charCode];
+
+ return result;
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* code_to_next10 */
+ /* */
+ /* <Description> */
+ /* Find the next encoded character. Uses format 10. */
+ /* */
+ /* <Input> */
+ /* charCode :: The wanted character code. */
+ /* */
+ /* cmap :: A pointer to a cmap table in format 10. */
+ /* */
+ /* <Return> */
+ /* Next encoded character. 0 if none exists. */
+ /* */
+ FT_CALLBACK_DEF( FT_ULong )
+ code_to_next10( TT_CMapTable cmap,
+ FT_ULong charCode )
+ {
+ TT_CMap10 cmap10;
+
+
+ charCode++;
+ cmap10 = &cmap->c.cmap10;
+
+ if ( charCode < cmap10->startCharCode )
+ charCode = cmap10->startCharCode;
+
+ charCode -= cmap10->startCharCode;
+
+ /* the overflow trick for comparison works here also since the number */
+ /* of glyphs (even if numChars is specified as ULong in the specs) in */
+ /* an OpenType font is limited to 64k */
+
+ while ( charCode < cmap10->numChars )
+ {
+ if ( cmap10->glyphs[charCode] )
+ return ( charCode + cmap10->startCharCode );
+ charCode++;
+ }
+
+ return 0;
+ }
+
+
+/* END */
--- /dev/null
+++ b/libfreetype/ttcmap.h
@@ -1,0 +1,45 @@
+/***************************************************************************/
+/* */
+/* ttcmap.h */
+/* */
+/* TrueType character mapping table (cmap) support (specification). */
+/* */
+/* Copyright 1996-2001, 2002 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+
+#ifndef __TTCMAP_H__
+#define __TTCMAP_H__
+
+
+#include <ft2build.h>
+#include FT_INTERNAL_TRUETYPE_TYPES_H
+
+
+FT_BEGIN_HEADER
+
+
+ FT_LOCAL( FT_Error )
+ tt_face_load_charmap( TT_Face face,
+ TT_CMapTable cmap,
+ FT_Stream input );
+
+ FT_LOCAL( FT_Error )
+ tt_face_free_charmap( TT_Face face,
+ TT_CMapTable cmap );
+
+
+FT_END_HEADER
+
+#endif /* __TTCMAP_H__ */
+
+
+/* END */
--- /dev/null
+++ b/libfreetype/ttcmap0.c
@@ -1,0 +1,1784 @@
+/***************************************************************************/
+/* */
+/* ttcmap0.c */
+/* */
+/* TrueType new character mapping table (cmap) support (body). */
+/* */
+/* Copyright 2002 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+
+#include <ft2build.h>
+#include FT_INTERNAL_DEBUG_H
+#include FT_INTERNAL_OBJECTS_H
+#include FT_INTERNAL_STREAM_H
+#include "ttload.h"
+#include "ttcmap0.h"
+
+#include "sferrors.h"
+
+ /*************************************************************************/
+ /* */
+ /* The macro FT_COMPONENT is used in trace mode. It is an implicit */
+ /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log */
+ /* messages during execution. */
+ /* */
+#undef FT_COMPONENT
+#define FT_COMPONENT trace_ttcmap
+
+
+#define TT_PEEK_SHORT FT_PEEK_SHORT
+#define TT_PEEK_USHORT FT_PEEK_USHORT
+#define TT_PEEK_LONG FT_PEEK_LONG
+#define TT_PEEK_ULONG FT_PEEK_ULONG
+
+#define TT_NEXT_SHORT FT_NEXT_SHORT
+#define TT_NEXT_USHORT FT_NEXT_USHORT
+#define TT_NEXT_LONG FT_NEXT_LONG
+#define TT_NEXT_ULONG FT_NEXT_ULONG
+
+
+ FT_CALLBACK_DEF( FT_Error )
+ tt_cmap_init( TT_CMap cmap,
+ FT_Byte* table )
+ {
+ cmap->data = table;
+ return 0;
+ }
+
+
+ /*************************************************************************/
+ /*************************************************************************/
+ /***** *****/
+ /***** FORMAT 0 *****/
+ /***** *****/
+ /*************************************************************************/
+ /*************************************************************************/
+
+ /*************************************************************************/
+ /* */
+ /* TABLE OVERVIEW */
+ /* -------------- */
+ /* */
+ /* NAME OFFSET TYPE DESCRIPTION */
+ /* */
+ /* format 0 USHORT must be 0 */
+ /* length 2 USHORT table length in bytes */
+ /* language 4 USHORT Mac language code */
+ /* glyph_ids 6 BYTE[256] array of glyph indices */
+ /* 262 */
+ /* */
+
+#ifdef TT_CONFIG_CMAP_FORMAT_0
+
+ FT_CALLBACK_DEF( void )
+ tt_cmap0_validate( FT_Byte* table,
+ FT_Validator valid )
+ {
+ FT_Byte* p = table + 2;
+ FT_UInt length = TT_NEXT_USHORT( p );
+
+
+ if ( table + length > valid->limit || length < 262 )
+ FT_INVALID_TOO_SHORT;
+
+ /* check glyph indices whenever necessary */
+ if ( valid->level >= FT_VALIDATE_TIGHT )
+ {
+ FT_UInt n, idx;
+
+
+ p = table + 6;
+ for ( n = 0; n < 256; n++ )
+ {
+ idx = *p++;
+ if ( idx >= TT_VALID_GLYPH_COUNT( valid ) )
+ FT_INVALID_GLYPH_ID;
+ }
+ }
+ }
+
+
+ FT_CALLBACK_DEF( FT_UInt )
+ tt_cmap0_char_index( TT_CMap cmap,
+ FT_UInt32 char_code )
+ {
+ FT_Byte* table = cmap->data;
+
+
+ return char_code < 256 ? table[6 + char_code] : 0;
+ }
+
+
+ FT_CALLBACK_DEF( FT_UInt )
+ tt_cmap0_char_next( TT_CMap cmap,
+ FT_UInt32 *pchar_code )
+ {
+ FT_Byte* table = cmap->data;
+ FT_UInt32 charcode = *pchar_code;
+ FT_UInt32 result = 0;
+ FT_UInt gindex = 0;
+
+
+ table += 6; /* go to glyph ids */
+ while ( ++charcode < 256 )
+ {
+ gindex = table[charcode];
+ if ( gindex != 0 )
+ {
+ result = charcode;
+ break;
+ }
+ }
+
+ *pchar_code = result;
+ return gindex;
+ }
+
+
+ FT_CALLBACK_TABLE_DEF
+ const TT_CMap_ClassRec tt_cmap0_class_rec =
+ {
+ {
+ sizeof( TT_CMapRec ),
+
+ (FT_CMap_InitFunc) tt_cmap_init,
+ (FT_CMap_DoneFunc) NULL,
+ (FT_CMap_CharIndexFunc)tt_cmap0_char_index,
+ (FT_CMap_CharNextFunc) tt_cmap0_char_next
+ },
+ 0,
+ (TT_CMap_ValidateFunc) tt_cmap0_validate
+ };
+
+#endif /* TT_CONFIG_CMAP_FORMAT_0 */
+
+
+ /*************************************************************************/
+ /*************************************************************************/
+ /***** *****/
+ /***** FORMAT 2 *****/
+ /***** *****/
+ /***** This is used for certain CJK encodings that encode text in a *****/
+ /***** mixed 8/16 bits encoding along the following lines: *****/
+ /***** *****/
+ /***** * Certain byte values correspond to an 8-bit character code *****/
+ /***** (typically in the range 0..127 for ASCII compatibility). *****/
+ /***** *****/
+ /***** * Certain byte values signal the first byte of a 2-byte *****/
+ /***** character code (but these values are also valid as the *****/
+ /***** second byte of a 2-byte character). *****/
+ /***** *****/
+ /***** The following charmap lookup and iteration functions all *****/
+ /***** assume that the value "charcode" correspond to following: *****/
+ /***** *****/
+ /***** - For one byte characters, "charcode" is simply the *****/
+ /***** character code. *****/
+ /***** *****/
+ /***** - For two byte characters, "charcode" is the 2-byte *****/
+ /***** character code in big endian format. More exactly: *****/
+ /***** *****/
+ /***** (charcode >> 8) is the first byte value *****/
+ /***** (charcode & 0xFF) is the second byte value *****/
+ /***** *****/
+ /***** Note that not all values of "charcode" are valid according *****/
+ /***** to these rules, and the function moderately check the *****/
+ /***** arguments. *****/
+ /***** *****/
+ /*************************************************************************/
+ /*************************************************************************/
+
+ /*************************************************************************/
+ /* */
+ /* TABLE OVERVIEW */
+ /* -------------- */
+ /* */
+ /* NAME OFFSET TYPE DESCRIPTION */
+ /* */
+ /* format 0 USHORT must be 2 */
+ /* length 2 USHORT table length in bytes */
+ /* language 4 USHORT Mac language code */
+ /* keys 6 USHORT[256] sub-header keys */
+ /* subs 518 SUBHEAD[NSUBS] sub-headers array */
+ /* glyph_ids 518+NSUB*8 USHORT[] glyph id array */
+ /* */
+ /* The `keys' table is used to map charcode high-bytes to sub-headers. */
+ /* The value of `NSUBS' is the number of sub-headers defined in the */
+ /* table and is computed by finding the maximum of the `keys' table. */
+ /* */
+ /* Note that for any n, `keys[n]' is a byte offset within the `subs' */
+ /* table, i.e., it is the corresponding sub-header index multiplied */
+ /* by 8. */
+ /* */
+ /* Each sub-header has the following format: */
+ /* */
+ /* NAME OFFSET TYPE DESCRIPTION */
+ /* */
+ /* first 0 USHORT first valid low-byte */
+ /* count 2 USHORT number of valid low-bytes */
+ /* delta 4 SHORT see below */
+ /* offset 6 USHORT see below */
+ /* */
+ /* A sub-header defines, for each high-byte, the range of valid */
+ /* low-bytes within the charmap. Note that the range defined by `first' */
+ /* and `count' must be completely included in the interval [0..255] */
+ /* according to the specification. */
+ /* */
+ /* If a character code is contained within a given sub-header, then */
+ /* mapping it to a glyph index is done as follows: */
+ /* */
+ /* * The value of `offset' is read. This is a _byte_ distance from the */
+ /* location of the `offset' field itself into a slice of the */
+ /* `glyph_ids' table. Let's call it `slice' (it's a USHORT[] too). */
+ /* */
+ /* * The value `slice[char.lo - first]' is read. If it is 0, there is */
+ /* no glyph for the charcode. Otherwise, the value of `delta' is */
+ /* added to it (modulo 65536) to form a new glyph index. */
+ /* */
+ /* It is up to the validation routine to check that all offsets fall */
+ /* within the glyph ids table (and not within the `subs' table itself or */
+ /* outside of the CMap). */
+ /* */
+
+#ifdef TT_CONFIG_CMAP_FORMAT_2
+
+ FT_CALLBACK_DEF( void )
+ tt_cmap2_validate( FT_Byte* table,
+ FT_Validator valid )
+ {
+ FT_Byte* p = table + 2; /* skip format */
+ FT_UInt length = TT_PEEK_USHORT( p );
+ FT_UInt n, max_subs;
+ FT_Byte* keys; /* keys table */
+ FT_Byte* subs; /* sub-headers */
+ FT_Byte* glyph_ids; /* glyph id array */
+
+
+ if ( table + length > valid->limit || length < 6 + 512 )
+ FT_INVALID_TOO_SHORT;
+
+ keys = table + 6;
+
+ /* parse keys to compute sub-headers count */
+ p = keys;
+ max_subs = 0;
+ for ( n = 0; n < 256; n++ )
+ {
+ FT_UInt idx = TT_NEXT_USHORT( p );
+
+
+ /* value must be multiple of 8 */
+ if ( valid->level >= FT_VALIDATE_PARANOID && ( idx & 7 ) != 0 )
+ FT_INVALID_DATA;
+
+ idx >>= 3;
+
+ if ( idx > max_subs )
+ max_subs = idx;
+ }
+
+ FT_ASSERT( p == table + 518 );
+
+ subs = p;
+ glyph_ids = subs + (max_subs + 1) * 8;
+ if ( glyph_ids > valid->limit )
+ FT_INVALID_TOO_SHORT;
+
+ /* parse sub-headers */
+ for ( n = 0; n <= max_subs; n++ )
+ {
+ FT_UInt first_code, code_count, offset;
+ FT_Int delta;
+ FT_Byte* ids;
+
+
+ first_code = TT_NEXT_USHORT( p );
+ code_count = TT_NEXT_USHORT( p );
+ delta = TT_NEXT_SHORT( p );
+ offset = TT_NEXT_USHORT( p );
+
+ /* check range within 0..255 */
+ if ( valid->level >= FT_VALIDATE_PARANOID )
+ {
+ if ( first_code >= 256 || first_code + code_count > 256 )
+ FT_INVALID_DATA;
+ }
+
+ /* check offset */
+ if ( offset != 0 )
+ {
+ ids = p - 2 + offset;
+ if ( ids < glyph_ids || ids + code_count*2 > table + length )
+ FT_INVALID_OFFSET;
+
+ /* check glyph ids */
+ if ( valid->level >= FT_VALIDATE_TIGHT )
+ {
+ FT_Byte* limit = p + code_count * 2;
+ FT_UInt idx;
+
+
+ for ( ; p < limit; )
+ {
+ idx = TT_NEXT_USHORT( p );
+ if ( idx != 0 )
+ {
+ idx = ( idx + delta ) & 0xFFFFU;
+ if ( idx >= TT_VALID_GLYPH_COUNT( valid ) )
+ FT_INVALID_GLYPH_ID;
+ }
+ }
+ }
+ }
+ }
+ }
+
+
+ /* return sub header corresponding to a given character code */
+ /* NULL on invalid charcode */
+ static FT_Byte*
+ tt_cmap2_get_subheader( FT_Byte* table,
+ FT_UInt32 char_code )
+ {
+ FT_Byte* result = NULL;
+
+
+ if ( char_code < 0x10000UL )
+ {
+ FT_UInt char_lo = (FT_UInt)( char_code & 0xFF );
+ FT_UInt char_hi = (FT_UInt)( char_code >> 8 );
+ FT_Byte* p = table + 6; /* keys table */
+ FT_Byte* subs = table + 518; /* subheaders table */
+ FT_Byte* sub;
+
+
+ if ( char_hi == 0 )
+ {
+ /* an 8-bit character code -- we use subHeader 0 in this case */
+ /* to test whether the character code is in the charmap */
+ /* */
+ sub = subs; /* jump to first sub-header */
+
+ /* check that the sub-header for this byte is 0, which */
+ /* indicates that it's really a valid one-byte value */
+ /* Otherwise, return 0 */
+ /* */
+ p += char_lo * 2;
+ if ( TT_PEEK_USHORT( p ) != 0 )
+ goto Exit;
+ }
+ else
+ {
+ /* a 16-bit character code */
+ p += char_hi * 2; /* jump to key entry */
+ sub = subs + ( TT_PEEK_USHORT( p ) & -8 ); /* jump to sub-header */
+
+ /* check that the hi byte isn't a valid one-byte value */
+ if ( sub == subs )
+ goto Exit;
+ }
+ result = sub;
+ }
+ Exit:
+ return result;
+ }
+
+
+ FT_CALLBACK_DEF( FT_UInt )
+ tt_cmap2_char_index( TT_CMap cmap,
+ FT_UInt32 char_code )
+ {
+ FT_Byte* table = cmap->data;
+ FT_UInt result = 0;
+ FT_Byte* subheader;
+
+
+ subheader = tt_cmap2_get_subheader( table, char_code );
+ if ( subheader )
+ {
+ FT_Byte* p = subheader;
+ FT_UInt idx = (FT_UInt)(char_code & 0xFF);
+ FT_UInt start, count;
+ FT_Int delta;
+ FT_UInt offset;
+
+
+ start = TT_NEXT_USHORT( p );
+ count = TT_NEXT_USHORT( p );
+ delta = TT_NEXT_SHORT ( p );
+ offset = TT_PEEK_USHORT( p );
+
+ idx -= start;
+ if ( idx < count && offset != 0 )
+ {
+ p += offset + 2 * idx;
+ idx = TT_PEEK_USHORT( p );
+
+ if ( idx != 0 )
+ result = (FT_UInt)( idx + delta ) & 0xFFFFU;
+ }
+ }
+ return result;
+ }
+
+
+ FT_CALLBACK_DEF( FT_UInt )
+ tt_cmap2_char_next( TT_CMap cmap,
+ FT_UInt32 *pcharcode )
+ {
+ FT_Byte* table = cmap->data;
+ FT_UInt gindex = 0;
+ FT_UInt32 result = 0;
+ FT_UInt32 charcode = *pcharcode + 1;
+ FT_Byte* subheader;
+
+
+ while ( charcode < 0x10000UL )
+ {
+ subheader = tt_cmap2_get_subheader( table, charcode );
+ if ( subheader )
+ {
+ FT_Byte* p = subheader;
+ FT_UInt start = TT_NEXT_USHORT( p );
+ FT_UInt count = TT_NEXT_USHORT( p );
+ FT_Int delta = TT_NEXT_SHORT ( p );
+ FT_UInt offset = TT_PEEK_USHORT( p );
+ FT_UInt char_lo = (FT_UInt)( charcode & 0xFF );
+ FT_UInt pos, idx;
+
+
+ if ( offset == 0 )
+ goto Next_SubHeader;
+
+ if ( char_lo < start )
+ {
+ char_lo = start;
+ pos = 0;
+ }
+ else
+ pos = (FT_UInt)( char_lo - start );
+
+ p += offset + pos * 2;
+ charcode = ( charcode & -256 ) + char_lo;
+
+ for ( ; pos < count; pos++, charcode++ )
+ {
+ idx = TT_NEXT_USHORT( p );
+
+ if ( idx != 0 )
+ {
+ gindex = ( idx + delta ) & 0xFFFFU;
+ if ( gindex != 0 )
+ {
+ result = charcode;
+ goto Exit;
+ }
+ }
+ }
+ }
+
+ /* jump to next sub-header, i.e. higher byte value */
+ Next_SubHeader:
+ charcode = ( charcode & -256 ) + 256;
+ }
+
+ Exit:
+ *pcharcode = result;
+
+ return gindex;
+ }
+
+
+ FT_CALLBACK_TABLE_DEF
+ const TT_CMap_ClassRec tt_cmap2_class_rec =
+ {
+ {
+ sizeof( TT_CMapRec ),
+
+ (FT_CMap_InitFunc) tt_cmap_init,
+ (FT_CMap_DoneFunc) NULL,
+ (FT_CMap_CharIndexFunc)tt_cmap2_char_index,
+ (FT_CMap_CharNextFunc) tt_cmap2_char_next
+ },
+ 2,
+ (TT_CMap_ValidateFunc) tt_cmap2_validate
+ };
+
+#endif /* TT_CONFIG_CMAP_FORMAT_2 */
+
+
+ /*************************************************************************/
+ /*************************************************************************/
+ /***** *****/
+ /***** FORMAT 4 *****/
+ /***** *****/
+ /*************************************************************************/
+ /*************************************************************************/
+
+ /*************************************************************************/
+ /* */
+ /* TABLE OVERVIEW */
+ /* -------------- */
+ /* */
+ /* NAME OFFSET TYPE DESCRIPTION */
+ /* */
+ /* format 0 USHORT must be 4 */
+ /* length 2 USHORT table length */
+ /* in bytes */
+ /* language 4 USHORT Mac language code */
+ /* */
+ /* segCountX2 6 USHORT 2*NUM_SEGS */
+ /* searchRange 8 USHORT 2*(1 << LOG_SEGS) */
+ /* entrySelector 10 USHORT LOG_SEGS */
+ /* rangeShift 12 USHORT segCountX2 - */
+ /* searchRange */
+ /* */
+ /* endCount 14 USHORT[NUM_SEGS] end charcode for */
+ /* each segment; last */
+ /* is 0xFFFF */
+ /* */
+ /* pad 14+NUM_SEGS*2 USHORT padding */
+ /* */
+ /* startCount 16+NUM_SEGS*2 USHORT[NUM_SEGS] first charcode for */
+ /* each segment */
+ /* */
+ /* idDelta 16+NUM_SEGS*4 SHORT[NUM_SEGS] delta for each */
+ /* segment */
+ /* idOffset 16+NUM_SEGS*6 SHORT[NUM_SEGS] range offset for */
+ /* each segment; can be */
+ /* zero */
+ /* */
+ /* glyphIds 16+NUM_SEGS*8 USHORT[] array of glyph id */
+ /* ranges */
+ /* */
+ /* Character codes are modelled by a series of ordered (increasing) */
+ /* intervals called segments. Each segment has start and end codes, */
+ /* provided by the `startCount' and `endCount' arrays. Segments must */
+ /* not be overlapping and the last segment should always contain the */
+ /* `0xFFFF' endCount. */
+ /* */
+ /* The fields `searchRange', `entrySelector' and `rangeShift' are better */
+ /* ignored (they are traces of over-engineering in the TrueType */
+ /* specification). */
+ /* */
+ /* Each segment also has a signed `delta', as well as an optional offset */
+ /* within the `glyphIds' table. */
+ /* */
+ /* If a segment's idOffset is 0, the glyph index corresponding to any */
+ /* charcode within the segment is obtained by adding the value of */
+ /* `idDelta' directly to the charcode, modulo 65536. */
+ /* */
+ /* Otherwise, a glyph index is taken from the glyph ids sub-array for */
+ /* the segment, and the value of `idDelta' is added to it. */
+ /* */
+ /* */
+ /* Finally, note that certain fonts contain invalid charmaps that */
+ /* contain end=0xFFFF, start=0xFFFF, delta=0x0001, offset=0xFFFF at the */
+ /* of their charmaps (e.g. opens___.ttf which comes with OpenOffice.org) */
+ /* we need special code to deal with them correctly... */
+ /* */
+
+#ifdef TT_CONFIG_CMAP_FORMAT_4
+
+ FT_CALLBACK_DEF( void )
+ tt_cmap4_validate( FT_Byte* table,
+ FT_Validator valid )
+ {
+ FT_Byte* p = table + 2; /* skip format */
+ FT_UInt length = TT_NEXT_USHORT( p );
+ FT_Byte *ends, *starts, *offsets, *deltas, *glyph_ids;
+ FT_UInt num_segs;
+
+
+ /* in certain fonts, the `length' field is invalid and goes */
+ /* out of bound. We try to correct this here... */
+ if ( length < 16 )
+ FT_INVALID_TOO_SHORT;
+
+ if ( table + length > valid->limit )
+ {
+ if ( valid->level >= FT_VALIDATE_TIGHT )
+ FT_INVALID_TOO_SHORT;
+
+ length = (FT_UInt)( valid->limit - table );
+ }
+
+ p = table + 6;
+ num_segs = TT_NEXT_USHORT( p ); /* read segCountX2 */
+
+ if ( valid->level >= FT_VALIDATE_PARANOID )
+ {
+ /* check that we have an even value here */
+ if ( num_segs & 1 )
+ FT_INVALID_DATA;
+ }
+
+ num_segs /= 2;
+
+ /* check the search parameters - even though we never use them */
+ /* */
+ if ( valid->level >= FT_VALIDATE_PARANOID )
+ {
+ /* check the values of 'searchRange', 'entrySelector', 'rangeShift' */
+ FT_UInt search_range = TT_NEXT_USHORT( p );
+ FT_UInt entry_selector = TT_NEXT_USHORT( p );
+ FT_UInt range_shift = TT_NEXT_USHORT( p );
+
+
+ if ( ( search_range | range_shift ) & 1 ) /* must be even values */
+ FT_INVALID_DATA;
+
+ search_range /= 2;
+ range_shift /= 2;
+
+ /* `search range' is the greatest power of 2 that is <= num_segs */
+
+ if ( search_range > num_segs ||
+ search_range * 2 < num_segs ||
+ search_range + range_shift != num_segs ||
+ search_range != ( 1U << entry_selector ) )
+ FT_INVALID_DATA;
+ }
+
+ ends = table + 14;
+ starts = table + 16 + num_segs * 2;
+ deltas = starts + num_segs * 2;
+ offsets = deltas + num_segs * 2;
+ glyph_ids = offsets + num_segs * 2;
+
+ if ( glyph_ids > table + length )
+ FT_INVALID_TOO_SHORT;
+
+ /* check last segment, its end count must be FFFF */
+ if ( valid->level >= FT_VALIDATE_PARANOID )
+ {
+ p = ends + ( num_segs - 1 ) * 2;
+ if ( TT_PEEK_USHORT( p ) != 0xFFFFU )
+ FT_INVALID_DATA;
+ }
+
+ /* check that segments are sorted in increasing order and do not */
+ /* overlap; check also the offsets */
+ {
+ FT_UInt start, end, last = 0, offset, n;
+ FT_Int delta;
+
+
+ for ( n = 0; n < num_segs; n++ )
+ {
+ p = starts + n * 2;
+ start = TT_PEEK_USHORT( p );
+ p = ends + n * 2;
+ end = TT_PEEK_USHORT( p );
+ p = deltas + n * 2;
+ delta = TT_PEEK_SHORT( p );
+ p = offsets + n * 2;
+ offset = TT_PEEK_USHORT( p );
+
+ if ( start > end )
+ FT_INVALID_DATA;
+
+ /* this test should be performed at default validation level; */
+ /* unfortunately, some popular Asian fonts present overlapping */
+ /* ranges in their charmaps */
+ /* */
+ if ( valid->level >= FT_VALIDATE_TIGHT )
+ {
+ if ( n > 0 && start <= last )
+ FT_INVALID_DATA;
+ }
+
+ if ( offset && offset != 0xFFFFU )
+ {
+ p += offset; /* start of glyph id array */
+
+ /* check that we point within the glyph ids table only */
+ if ( p < glyph_ids ||
+ p + ( end - start + 1 ) * 2 > table + length )
+ FT_INVALID_DATA;
+
+ /* check glyph indices within the segment range */
+ if ( valid->level >= FT_VALIDATE_TIGHT )
+ {
+ FT_UInt i, idx;
+
+
+ for ( i = start; i < end; i++ )
+ {
+ idx = FT_NEXT_USHORT( p );
+ if ( idx != 0 )
+ {
+ idx = (FT_UInt)( idx + delta ) & 0xFFFFU;
+
+ if ( idx >= TT_VALID_GLYPH_COUNT( valid ) )
+ FT_INVALID_GLYPH_ID;
+ }
+ }
+ }
+ }
+ else if ( offset == 0xFFFFU )
+ {
+ /* Some fonts (erroneously?) use a range offset of 0xFFFF */
+ /* to mean missing glyph in cmap table */
+ /* */
+ if ( valid->level >= FT_VALIDATE_PARANOID ||
+ n != num_segs - 1 ||
+ !( start == 0xFFFFU && end == 0xFFFFU && delta == 0x1U ) )
+ FT_INVALID_DATA;
+ }
+
+ last = end;
+ }
+ }
+ }
+
+
+ FT_CALLBACK_DEF( FT_UInt )
+ tt_cmap4_char_index( TT_CMap cmap,
+ FT_UInt32 char_code )
+ {
+ FT_Byte* table = cmap->data;
+ FT_UInt result = 0;
+
+
+ if ( char_code < 0x10000UL )
+ {
+ FT_UInt idx, num_segs2;
+ FT_Int delta;
+ FT_UInt code = (FT_UInt)char_code;
+ FT_Byte* p;
+
+
+ p = table + 6;
+ num_segs2 = TT_PEEK_USHORT( p ) & -2; /* be paranoid! */
+
+#if 1
+ /* Some fonts have more than 170 segments in their charmaps! */
+ /* We changed this function to use a more efficient binary */
+ /* search for improving performance */
+ {
+ FT_UInt min = 0;
+ FT_UInt max = num_segs2 >> 1;
+ FT_UInt mid, start, end, offset;
+
+
+ while ( min < max )
+ {
+ mid = ( min + max ) >> 1;
+ p = table + 14 + mid * 2;
+ end = TT_NEXT_USHORT( p );
+ p += num_segs2;
+ start = TT_PEEK_USHORT( p);
+
+ if ( code < start )
+ max = mid;
+
+ else if ( code > end )
+ min = mid + 1;
+
+ else
+ {
+ /* we found the segment */
+ idx = code;
+
+ p += num_segs2;
+ delta = TT_PEEK_SHORT( p );
+
+ p += num_segs2;
+ offset = TT_PEEK_USHORT( p );
+
+ if ( offset == 0xFFFFU )
+ goto Exit;
+
+ if ( offset != 0 )
+ {
+ p += offset + 2 * ( idx - start );
+ idx = TT_PEEK_USHORT( p );
+ }
+
+ if ( idx != 0 )
+ result = (FT_UInt)( idx + delta ) & 0xFFFFU;
+
+ goto Exit;
+ }
+ }
+ }
+
+#else /* 0 - old code */
+
+ {
+ FT_UInt n;
+ FT_Byte* q;
+
+
+ p = table + 14; /* ends table */
+ q = table + 16 + num_segs2; /* starts table */
+
+
+ for ( n = 0; n < num_segs2; n += 2 )
+ {
+ FT_UInt end = TT_NEXT_USHORT( p );
+ FT_UInt start = TT_NEXT_USHORT( q );
+ FT_UInt offset;
+
+
+ if ( code < start )
+ break;
+
+ if ( code <= end )
+ {
+ idx = code;
+
+ p = q + num_segs2 - 2;
+ delta = TT_PEEK_SHORT( p );
+ p += num_segs2;
+ offset = TT_PEEK_USHORT( p );
+
+ if ( offset == 0xFFFFU )
+ goto Exit;
+
+ if ( offset != 0 )
+ {
+ p += offset + 2 * ( idx - start );
+ idx = TT_PEEK_USHORT( p );
+ }
+
+ if ( idx != 0 )
+ result = (FT_UInt)( idx + delta ) & 0xFFFFU;
+ }
+ }
+ }
+
+#endif /* 0 */
+
+ }
+
+ Exit:
+ return result;
+ }
+
+
+ FT_CALLBACK_DEF( FT_UInt )
+ tt_cmap4_char_next( TT_CMap cmap,
+ FT_UInt32 *pchar_code )
+ {
+ FT_Byte* table = cmap->data;
+ FT_UInt32 result = 0;
+ FT_UInt32 char_code = *pchar_code + 1;
+ FT_UInt gindex = 0;
+ FT_Byte* p;
+ FT_Byte* q;
+ FT_UInt code, num_segs2;
+
+
+ if ( char_code >= 0x10000UL )
+ goto Exit;
+
+ code = (FT_UInt)char_code;
+ p = table + 6;
+ num_segs2 = TT_PEEK_USHORT(p) & -2; /* ensure even-ness */
+
+ for (;;)
+ {
+ FT_UInt offset, n;
+ FT_Int delta;
+
+
+ p = table + 14; /* ends table */
+ q = table + 16 + num_segs2; /* starts table */
+
+ for ( n = 0; n < num_segs2; n += 2 )
+ {
+ FT_UInt end = TT_NEXT_USHORT( p );
+ FT_UInt start = TT_NEXT_USHORT( q );
+
+
+ if ( code < start )
+ code = start;
+
+ if ( code <= end )
+ {
+ p = q + num_segs2 - 2;
+ delta = TT_PEEK_SHORT( p );
+ p += num_segs2;
+ offset = TT_PEEK_USHORT( p );
+
+ if ( offset != 0 && offset != 0xFFFFU )
+ {
+ /* parse the glyph ids array for non-0 index */
+ p += offset + ( code - start ) * 2;
+ while ( code <= end )
+ {
+ gindex = TT_NEXT_USHORT( p );
+ if ( gindex != 0 )
+ {
+ gindex = (FT_UInt)( gindex + delta ) & 0xFFFFU;
+ if ( gindex != 0 )
+ break;
+ }
+ code++;
+ }
+ }
+ else if ( offset == 0xFFFFU )
+ {
+ /* an offset of 0xFFFF means an empty glyph in certain fonts! */
+ code = end;
+ break;
+ }
+ else
+ gindex = (FT_UInt)( code + delta ) & 0xFFFFU;
+
+ if ( gindex == 0 )
+ break;
+
+ result = code;
+ goto Exit;
+ }
+ }
+
+ /* loop to next trial charcode */
+ if ( code >= 0xFFFFU )
+ break;
+
+ code++;
+ }
+ return (FT_UInt)result;
+
+ Exit:
+ *pchar_code = result;
+ return gindex;
+ }
+
+
+ FT_CALLBACK_TABLE_DEF
+ const TT_CMap_ClassRec tt_cmap4_class_rec =
+ {
+ {
+ sizeof ( TT_CMapRec ),
+
+ (FT_CMap_InitFunc) tt_cmap_init,
+ (FT_CMap_DoneFunc) NULL,
+ (FT_CMap_CharIndexFunc)tt_cmap4_char_index,
+ (FT_CMap_CharNextFunc) tt_cmap4_char_next
+ },
+ 4,
+ (TT_CMap_ValidateFunc) tt_cmap4_validate
+ };
+
+#endif /* TT_CONFIG_CMAP_FORMAT_4 */
+
+
+ /*************************************************************************/
+ /*************************************************************************/
+ /***** *****/
+ /***** FORMAT 6 *****/
+ /***** *****/
+ /*************************************************************************/
+ /*************************************************************************/
+
+ /*************************************************************************/
+ /* */
+ /* TABLE OVERVIEW */
+ /* -------------- */
+ /* */
+ /* NAME OFFSET TYPE DESCRIPTION */
+ /* */
+ /* format 0 USHORT must be 4 */
+ /* length 2 USHORT table length in bytes */
+ /* language 4 USHORT Mac language code */
+ /* */
+ /* first 6 USHORT first segment code */
+ /* count 8 USHORT segment size in chars */
+ /* glyphIds 10 USHORT[count] glyph ids */
+ /* */
+ /* A very simplified segment mapping. */
+ /* */
+
+#ifdef TT_CONFIG_CMAP_FORMAT_6
+
+ FT_CALLBACK_DEF( void )
+ tt_cmap6_validate( FT_Byte* table,
+ FT_Validator valid )
+ {
+ FT_Byte* p;
+ FT_UInt length, start, count;
+
+
+ if ( table + 10 > valid->limit )
+ FT_INVALID_TOO_SHORT;
+
+ p = table + 2;
+ length = TT_NEXT_USHORT( p );
+
+ p = table + 6; /* skip language */
+ start = TT_NEXT_USHORT( p );
+ count = TT_NEXT_USHORT( p );
+
+ if ( table + length > valid->limit || length < 10 + count * 2 )
+ FT_INVALID_TOO_SHORT;
+
+ /* check glyph indices */
+ if ( valid->level >= FT_VALIDATE_TIGHT )
+ {
+ FT_UInt gindex;
+
+
+ for ( ; count > 0; count-- )
+ {
+ gindex = TT_NEXT_USHORT( p );
+ if ( gindex >= TT_VALID_GLYPH_COUNT( valid ) )
+ FT_INVALID_GLYPH_ID;
+ }
+ }
+ }
+
+
+ FT_CALLBACK_DEF( FT_UInt )
+ tt_cmap6_char_index( TT_CMap cmap,
+ FT_UInt32 char_code )
+ {
+ FT_Byte* table = cmap->data;
+ FT_UInt result = 0;
+ FT_Byte* p = table + 6;
+ FT_UInt start = TT_NEXT_USHORT( p );
+ FT_UInt count = TT_NEXT_USHORT( p );
+ FT_UInt idx = (FT_UInt)( char_code - start );
+
+
+ if ( idx < count )
+ {
+ p += 2 * idx;
+ result = TT_PEEK_USHORT( p );
+ }
+ return result;
+ }
+
+
+ FT_CALLBACK_DEF( FT_UInt )
+ tt_cmap6_char_next( TT_CMap cmap,
+ FT_UInt32 *pchar_code )
+ {
+ FT_Byte* table = cmap->data;
+ FT_UInt32 result = 0;
+ FT_UInt32 char_code = *pchar_code + 1;
+ FT_UInt gindex = 0;
+
+ FT_Byte* p = table + 6;
+ FT_UInt start = TT_NEXT_USHORT( p );
+ FT_UInt count = TT_NEXT_USHORT( p );
+ FT_UInt idx;
+
+
+ if ( char_code >= 0x10000UL )
+ goto Exit;
+
+ if ( char_code < start )
+ char_code = start;
+
+ idx = (FT_UInt)( char_code - start );
+ p += 2 * idx;
+
+ for ( ; idx < count; idx++ )
+ {
+ gindex = TT_NEXT_USHORT( p );
+ if ( gindex != 0 )
+ {
+ result = char_code;
+ break;
+ }
+ char_code++;
+ }
+
+ Exit:
+ *pchar_code = result;
+ return gindex;
+ }
+
+
+ FT_CALLBACK_TABLE_DEF
+ const TT_CMap_ClassRec tt_cmap6_class_rec =
+ {
+ {
+ sizeof ( TT_CMapRec ),
+
+ (FT_CMap_InitFunc) tt_cmap_init,
+ (FT_CMap_DoneFunc) NULL,
+ (FT_CMap_CharIndexFunc)tt_cmap6_char_index,
+ (FT_CMap_CharNextFunc) tt_cmap6_char_next
+ },
+ 6,
+ (TT_CMap_ValidateFunc) tt_cmap6_validate
+ };
+
+#endif /* TT_CONFIG_CMAP_FORMAT_6 */
+
+
+ /*************************************************************************/
+ /*************************************************************************/
+ /***** *****/
+ /***** FORMAT 8 *****/
+ /***** *****/
+ /***** It's hard to completely understand what the OpenType spec *****/
+ /***** says about this format, but here is my conclusion. *****/
+ /***** *****/
+ /***** The purpose of this format is to easily map UTF-16 text to *****/
+ /***** glyph indices. Basically, the `char_code' must be in one of *****/
+ /***** the following formats: *****/
+ /***** *****/
+ /***** - A 16-bit value that isn't part of the Unicode Surrogates *****/
+ /***** Area (i.e. U+D800-U+DFFF). *****/
+ /***** *****/
+ /***** - A 32-bit value, made of two surrogate values, i.e.. if *****/
+ /***** `char_code = (char_hi << 16) | char_lo', then both *****/
+ /***** `char_hi' and `char_lo' must be in the Surrogates Area. *****/
+ /***** Area. *****/
+ /***** *****/
+ /***** The 'is32' table embedded in the charmap indicates whether a *****/
+ /***** given 16-bit value is in the surrogates area or not. *****/
+ /***** *****/
+ /***** So, for any given `char_code', we can assert the following: *****/
+ /***** *****/
+ /***** If `char_hi == 0' then we must have `is32[char_lo] == 0'. *****/
+ /***** *****/
+ /***** If `char_hi != 0' then we must have both *****/
+ /***** `is32[char_hi] != 0' and `is32[char_lo] != 0'. *****/
+ /***** *****/
+ /*************************************************************************/
+ /*************************************************************************/
+
+ /*************************************************************************/
+ /* */
+ /* TABLE OVERVIEW */
+ /* -------------- */
+ /* */
+ /* NAME OFFSET TYPE DESCRIPTION */
+ /* */
+ /* format 0 USHORT must be 8 */
+ /* reseved 2 USHORT reserved */
+ /* length 4 ULONG length in bytes */
+ /* language 8 ULONG Mac language code */
+ /* is32 12 BYTE[8192] 32-bitness bitmap */
+ /* count 8204 ULONG number of groups */
+ /* */
+ /* This header is followed by 'count' groups of the following format: */
+ /* */
+ /* start 0 ULONG first charcode */
+ /* end 4 ULONG last charcode */
+ /* startId 8 ULONG start glyph id for the group */
+ /* */
+
+#ifdef TT_CONFIG_CMAP_FORMAT_8
+
+ FT_CALLBACK_DEF( void )
+ tt_cmap8_validate( FT_Byte* table,
+ FT_Validator valid )
+ {
+ FT_Byte* p = table + 4;
+ FT_Byte* is32;
+ FT_UInt32 length;
+ FT_UInt32 num_groups;
+
+
+ if ( table + 16 + 8192 > valid->limit )
+ FT_INVALID_TOO_SHORT;
+
+ length = TT_NEXT_ULONG( p );
+ if ( table + length > valid->limit || length < 8208 )
+ FT_INVALID_TOO_SHORT;
+
+ is32 = table + 12;
+ p = is32 + 8192; /* skip `is32' array */
+ num_groups = TT_NEXT_ULONG( p );
+
+ if ( p + num_groups * 12 > valid->limit )
+ FT_INVALID_TOO_SHORT;
+
+ /* check groups, they must be in increasing order */
+ {
+ FT_UInt32 n, start, end, start_id, count, last = 0;
+
+
+ for ( n = 0; n < num_groups; n++ )
+ {
+ FT_UInt hi, lo;
+
+
+ start = TT_NEXT_ULONG( p );
+ end = TT_NEXT_ULONG( p );
+ start_id = TT_NEXT_ULONG( p );
+
+ if ( start > end )
+ FT_INVALID_DATA;
+
+ if ( n > 0 && start <= last )
+ FT_INVALID_DATA;
+
+ if ( valid->level >= FT_VALIDATE_TIGHT )
+ {
+ if ( start_id + end - start >= TT_VALID_GLYPH_COUNT( valid ) )
+ FT_INVALID_GLYPH_ID;
+
+ count = (FT_UInt32)( end - start + 1 );
+
+ if ( start & ~0xFFFFU )
+ {
+ /* start_hi != 0; check that is32[i] is 1 for each i in */
+ /* the `hi' and `lo' of the range [start..end] */
+ for ( ; count > 0; count--, start++ )
+ {
+ hi = (FT_UInt)( start >> 16 );
+ lo = (FT_UInt)( start & 0xFFFFU );
+
+ if ( (is32[hi >> 3] & ( 0x80 >> ( hi & 7 ) ) ) == 0 )
+ FT_INVALID_DATA;
+
+ if ( (is32[lo >> 3] & ( 0x80 >> ( lo & 7 ) ) ) == 0 )
+ FT_INVALID_DATA;
+ }
+ }
+ else
+ {
+ /* start_hi == 0; check that is32[i] is 0 for each i in */
+ /* the range [start..end] */
+
+ /* end_hi cannot be != 0! */
+ if ( end & ~0xFFFFU )
+ FT_INVALID_DATA;
+
+ for ( ; count > 0; count--, start++ )
+ {
+ lo = (FT_UInt)( start & 0xFFFFU );
+
+ if ( (is32[lo >> 3] & ( 0x80 >> ( lo & 7 ) ) ) != 0 )
+ FT_INVALID_DATA;
+ }
+ }
+ }
+
+ last = end;
+ }
+ }
+ }
+
+
+ FT_CALLBACK_DEF( FT_UInt )
+ tt_cmap8_char_index( TT_CMap cmap,
+ FT_UInt32 char_code )
+ {
+ FT_Byte* table = cmap->data;
+ FT_UInt result = 0;
+ FT_Byte* p = table + 8204;
+ FT_UInt32 num_groups = TT_NEXT_ULONG( p );
+ FT_UInt32 start, end, start_id;
+
+
+ for ( ; num_groups > 0; num_groups-- )
+ {
+ start = TT_NEXT_ULONG( p );
+ end = TT_NEXT_ULONG( p );
+ start_id = TT_NEXT_ULONG( p );
+
+ if ( char_code < start )
+ break;
+
+ if ( char_code <= end )
+ {
+ result = (FT_UInt)( start_id + char_code - start );
+ break;
+ }
+ }
+ return result;
+ }
+
+
+ FT_CALLBACK_DEF( FT_UInt )
+ tt_cmap8_char_next( TT_CMap cmap,
+ FT_UInt32 *pchar_code )
+ {
+ FT_UInt32 result = 0;
+ FT_UInt32 char_code = *pchar_code + 1;
+ FT_UInt gindex = 0;
+ FT_Byte* table = cmap->data;
+ FT_Byte* p = table + 8204;
+ FT_UInt32 num_groups = TT_NEXT_ULONG( p );
+ FT_UInt32 start, end, start_id;
+
+
+ p = table + 8208;
+
+ for ( ; num_groups > 0; num_groups-- )
+ {
+ start = TT_NEXT_ULONG( p );
+ end = TT_NEXT_ULONG( p );
+ start_id = TT_NEXT_ULONG( p );
+
+ if ( char_code < start )
+ char_code = start;
+
+ if ( char_code <= end )
+ {
+ gindex = (FT_UInt)( char_code - start + start_id );
+ if ( gindex != 0 )
+ {
+ result = char_code;
+ goto Exit;
+ }
+ }
+ }
+
+ Exit:
+ *pchar_code = result;
+ return gindex;
+ }
+
+
+ FT_CALLBACK_TABLE_DEF
+ const TT_CMap_ClassRec tt_cmap8_class_rec =
+ {
+ {
+ sizeof ( TT_CMapRec ),
+
+ (FT_CMap_InitFunc) tt_cmap_init,
+ (FT_CMap_DoneFunc) NULL,
+ (FT_CMap_CharIndexFunc)tt_cmap8_char_index,
+ (FT_CMap_CharNextFunc) tt_cmap8_char_next
+ },
+ 8,
+ (TT_CMap_ValidateFunc) tt_cmap8_validate
+ };
+
+#endif /* TT_CONFIG_CMAP_FORMAT_8 */
+
+
+ /*************************************************************************/
+ /*************************************************************************/
+ /***** *****/
+ /***** FORMAT 10 *****/
+ /***** *****/
+ /*************************************************************************/
+ /*************************************************************************/
+
+ /*************************************************************************/
+ /* */
+ /* TABLE OVERVIEW */
+ /* -------------- */
+ /* */
+ /* NAME OFFSET TYPE DESCRIPTION */
+ /* */
+ /* format 0 USHORT must be 10 */
+ /* reserved 2 USHORT reserved */
+ /* length 4 ULONG length in bytes */
+ /* language 8 ULONG Mac language code */
+ /* */
+ /* start 12 ULONG first char in range */
+ /* count 16 ULONG number of chars in range */
+ /* glyphIds 20 USHORT[count] glyph indices covered */
+ /* */
+
+#ifdef TT_CONFIG_CMAP_FORMAT_10
+
+ FT_CALLBACK_DEF( void )
+ tt_cmap10_validate( FT_Byte* table,
+ FT_Validator valid )
+ {
+ FT_Byte* p = table + 4;
+ FT_ULong length, start, count;
+
+
+ if ( table + 20 > valid->limit )
+ FT_INVALID_TOO_SHORT;
+
+ length = TT_NEXT_ULONG( p );
+ p = table + 12;
+ start = TT_NEXT_ULONG( p );
+ count = TT_NEXT_ULONG( p );
+
+ if ( table + length > valid->limit || length < 20 + count * 2 )
+ FT_INVALID_TOO_SHORT;
+
+ /* check glyph indices */
+ if ( valid->level >= FT_VALIDATE_TIGHT )
+ {
+ FT_UInt gindex;
+
+
+ for ( ; count > 0; count-- )
+ {
+ gindex = TT_NEXT_USHORT( p );
+ if ( gindex >= TT_VALID_GLYPH_COUNT( valid ) )
+ FT_INVALID_GLYPH_ID;
+ }
+ }
+ }
+
+
+ FT_CALLBACK_DEF( FT_UInt )
+ tt_cmap10_char_index( TT_CMap cmap,
+ FT_UInt32 char_code )
+ {
+ FT_Byte* table = cmap->data;
+ FT_UInt result = 0;
+ FT_Byte* p = table + 12;
+ FT_UInt32 start = TT_NEXT_ULONG( p );
+ FT_UInt32 count = TT_NEXT_ULONG( p );
+ FT_UInt32 idx = (FT_ULong)( char_code - start );
+
+
+ if ( idx < count )
+ {
+ p += 2 * idx;
+ result = TT_PEEK_USHORT( p );
+ }
+ return result;
+ }
+
+
+ FT_CALLBACK_DEF( FT_UInt )
+ tt_cmap10_char_next( TT_CMap cmap,
+ FT_UInt32 *pchar_code )
+ {
+ FT_Byte* table = cmap->data;
+ FT_UInt32 result = 0;
+ FT_UInt32 char_code = *pchar_code + 1;
+ FT_UInt gindex = 0;
+ FT_Byte* p = table + 12;
+ FT_UInt32 start = TT_NEXT_ULONG( p );
+ FT_UInt32 count = TT_NEXT_ULONG( p );
+ FT_UInt32 idx;
+
+
+ if ( char_code < start )
+ char_code = start;
+
+ idx = (FT_UInt32)( char_code - start );
+ p += 2 * idx;
+
+ for ( ; idx < count; idx++ )
+ {
+ gindex = TT_NEXT_USHORT( p );
+ if ( gindex != 0 )
+ {
+ result = char_code;
+ break;
+ }
+ char_code++;
+ }
+
+ *pchar_code = char_code;
+ return gindex;
+ }
+
+
+ FT_CALLBACK_TABLE_DEF
+ const TT_CMap_ClassRec tt_cmap10_class_rec =
+ {
+ {
+ sizeof ( TT_CMapRec ),
+
+ (FT_CMap_InitFunc) tt_cmap_init,
+ (FT_CMap_DoneFunc) NULL,
+ (FT_CMap_CharIndexFunc)tt_cmap10_char_index,
+ (FT_CMap_CharNextFunc) tt_cmap10_char_next
+ },
+ 10,
+ (TT_CMap_ValidateFunc) tt_cmap10_validate
+ };
+
+#endif /* TT_CONFIG_CMAP_FORMAT_10 */
+
+
+ /*************************************************************************/
+ /*************************************************************************/
+ /***** *****/
+ /***** FORMAT 12 *****/
+ /***** *****/
+ /*************************************************************************/
+ /*************************************************************************/
+
+ /*************************************************************************/
+ /* */
+ /* TABLE OVERVIEW */
+ /* -------------- */
+ /* */
+ /* NAME OFFSET TYPE DESCRIPTION */
+ /* */
+ /* format 0 USHORT must be 12 */
+ /* reserved 2 USHORT reserved */
+ /* length 4 ULONG length in bytes */
+ /* language 8 ULONG Mac language code */
+ /* count 12 ULONG number of groups */
+ /* 16 */
+ /* */
+ /* This header is followed by `count' groups of the following format: */
+ /* */
+ /* start 0 ULONG first charcode */
+ /* end 4 ULONG last charcode */
+ /* startId 8 ULONG start glyph id for the group */
+ /* */
+
+#ifdef TT_CONFIG_CMAP_FORMAT_12
+
+ FT_CALLBACK_DEF( void )
+ tt_cmap12_validate( FT_Byte* table,
+ FT_Validator valid )
+ {
+ FT_Byte* p;
+ FT_ULong length;
+ FT_ULong num_groups;
+
+
+ if ( table + 16 > valid->limit )
+ FT_INVALID_TOO_SHORT;
+
+ p = table + 4;
+ length = TT_NEXT_ULONG( p );
+
+ p = table + 12;
+ num_groups = TT_NEXT_ULONG( p );
+
+ if ( table + length > valid->limit || length < 16 + 12 * num_groups )
+ FT_INVALID_TOO_SHORT;
+
+ /* check groups, they must be in increasing order */
+ {
+ FT_ULong n, start, end, start_id, last = 0;
+
+
+ for ( n = 0; n < num_groups; n++ )
+ {
+ start = TT_NEXT_ULONG( p );
+ end = TT_NEXT_ULONG( p );
+ start_id = TT_NEXT_ULONG( p );
+
+ if ( start > end )
+ FT_INVALID_DATA;
+
+ if ( n > 0 && start <= last )
+ FT_INVALID_DATA;
+
+ if ( valid->level >= FT_VALIDATE_TIGHT )
+ {
+ if ( start_id + end - start >= TT_VALID_GLYPH_COUNT( valid ) )
+ FT_INVALID_GLYPH_ID;
+ }
+
+ last = end;
+ }
+ }
+ }
+
+
+ FT_CALLBACK_DEF( FT_UInt )
+ tt_cmap12_char_index( TT_CMap cmap,
+ FT_UInt32 char_code )
+ {
+ FT_UInt result = 0;
+ FT_Byte* table = cmap->data;
+ FT_Byte* p = table + 12;
+ FT_UInt32 num_groups = TT_NEXT_ULONG( p );
+ FT_UInt32 start, end, start_id;
+
+
+ for ( ; num_groups > 0; num_groups-- )
+ {
+ start = TT_NEXT_ULONG( p );
+ end = TT_NEXT_ULONG( p );
+ start_id = TT_NEXT_ULONG( p );
+
+ if ( char_code < start )
+ break;
+
+ if ( char_code <= end )
+ {
+ result = (FT_UInt)( start_id + char_code - start );
+ break;
+ }
+ }
+ return result;
+ }
+
+
+ FT_CALLBACK_DEF( FT_UInt )
+ tt_cmap12_char_next( TT_CMap cmap,
+ FT_UInt32 *pchar_code )
+ {
+ FT_Byte* table = cmap->data;
+ FT_UInt32 result = 0;
+ FT_UInt32 char_code = *pchar_code + 1;
+ FT_UInt gindex = 0;
+ FT_Byte* p = table + 12;
+ FT_UInt32 num_groups = TT_NEXT_ULONG( p );
+ FT_UInt32 start, end, start_id;
+
+
+ p = table + 16;
+
+ for ( ; num_groups > 0; num_groups-- )
+ {
+ start = TT_NEXT_ULONG( p );
+ end = TT_NEXT_ULONG( p );
+ start_id = TT_NEXT_ULONG( p );
+
+ if ( char_code < start )
+ char_code = start;
+
+ if ( char_code <= end )
+ {
+ gindex = (FT_UInt)(char_code - start + start_id);
+ if ( gindex != 0 )
+ {
+ result = char_code;
+ goto Exit;
+ }
+ }
+ }
+
+ Exit:
+ *pchar_code = result;
+ return gindex;
+ }
+
+
+ FT_CALLBACK_TABLE_DEF
+ const TT_CMap_ClassRec tt_cmap12_class_rec =
+ {
+ {
+ sizeof ( TT_CMapRec ),
+
+ (FT_CMap_InitFunc) tt_cmap_init,
+ (FT_CMap_DoneFunc) NULL,
+ (FT_CMap_CharIndexFunc)tt_cmap12_char_index,
+ (FT_CMap_CharNextFunc) tt_cmap12_char_next
+ },
+ 12,
+ (TT_CMap_ValidateFunc) tt_cmap12_validate
+ };
+
+
+#endif /* TT_CONFIG_CMAP_FORMAT_12 */
+
+
+ static const TT_CMap_Class tt_cmap_classes[] =
+ {
+#ifdef TT_CONFIG_CMAP_FORMAT_0
+ &tt_cmap0_class_rec,
+#endif
+
+#ifdef TT_CONFIG_CMAP_FORMAT_2
+ &tt_cmap2_class_rec,
+#endif
+
+#ifdef TT_CONFIG_CMAP_FORMAT_4
+ &tt_cmap4_class_rec,
+#endif
+
+#ifdef TT_CONFIG_CMAP_FORMAT_6
+ &tt_cmap6_class_rec,
+#endif
+
+#ifdef TT_CONFIG_CMAP_FORMAT_8
+ &tt_cmap8_class_rec,
+#endif
+
+#ifdef TT_CONFIG_CMAP_FORMAT_10
+ &tt_cmap10_class_rec,
+#endif
+
+#ifdef TT_CONFIG_CMAP_FORMAT_12
+ &tt_cmap12_class_rec,
+#endif
+
+ NULL,
+ };
+
+
+ /* parse the `cmap' table and build the corresponding TT_CMap objects */
+ /* in the current face */
+ /* */
+ FT_LOCAL_DEF( FT_Error )
+ tt_face_build_cmaps( TT_Face face )
+ {
+ FT_Byte* table = face->cmap_table;
+ FT_Byte* limit = table + face->cmap_size;
+ FT_UInt volatile num_cmaps;
+ FT_Byte* volatile p = table;
+
+
+ if ( p + 4 > limit )
+ return FT_Err_Invalid_Table;
+
+ /* only recognize format 0 */
+ if ( TT_NEXT_USHORT( p ) != 0 )
+ {
+ p -= 2;
+ FT_ERROR(( "tt_face_build_cmaps: unsupported `cmap' table format = %d\n",
+ TT_PEEK_USHORT( p ) ));
+ return FT_Err_Invalid_Table;
+ }
+
+ num_cmaps = TT_NEXT_USHORT( p );
+
+ for ( ; num_cmaps > 0 && p + 8 <= limit; num_cmaps-- )
+ {
+ FT_CharMapRec charmap;
+ FT_UInt32 offset;
+
+
+ charmap.platform_id = TT_NEXT_USHORT( p );
+ charmap.encoding_id = TT_NEXT_USHORT( p );
+ charmap.face = FT_FACE( face );
+ charmap.encoding = FT_ENCODING_NONE; /* will be filled later */
+ offset = TT_NEXT_ULONG( p );
+
+ if ( offset && table + offset + 2 < limit )
+ {
+ FT_Byte* cmap = table + offset;
+ FT_UInt format = TT_PEEK_USHORT( cmap );
+ const TT_CMap_Class* volatile pclazz = tt_cmap_classes;
+ TT_CMap_Class clazz;
+
+
+ for ( ; *pclazz; pclazz++ )
+ {
+ clazz = *pclazz;
+ if ( clazz->format == format )
+ {
+ volatile TT_ValidatorRec valid;
+
+
+ ft_validator_init( FT_VALIDATOR( &valid ), cmap, limit,
+ FT_VALIDATE_DEFAULT );
+
+ valid.num_glyphs = (FT_UInt)face->root.num_glyphs;
+
+ if ( ft_setjmp( FT_VALIDATOR( &valid )->jump_buffer ) == 0 )
+ {
+ /* validate this cmap sub-table */
+ clazz->validate( cmap, FT_VALIDATOR( &valid ) );
+ }
+
+ if ( valid.validator.error == 0 )
+ (void)FT_CMap_New( (FT_CMap_Class)clazz, cmap, &charmap, NULL );
+ else
+ {
+ FT_ERROR(( "tt_face_build_cmaps:" ));
+ FT_ERROR(( " broken cmap sub-table ignored!\n" ));
+ }
+ }
+ }
+ }
+ }
+
+ return 0;
+ }
+
+
+/* END */
--- /dev/null
+++ b/libfreetype/ttcmap0.h
@@ -1,0 +1,74 @@
+/***************************************************************************/
+/* */
+/* ttcmap0.h */
+/* */
+/* TrueType new character mapping table (cmap) support (specification). */
+/* */
+/* Copyright 2002 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+
+#ifndef __TTCMAP0_H__
+#define __TTCMAP0_H__
+
+
+#include <ft2build.h>
+#include FT_INTERNAL_TRUETYPE_TYPES_H
+#include FT_INTERNAL_OBJECTS_H
+
+
+FT_BEGIN_HEADER
+
+ typedef struct TT_CMapRec_
+ {
+ FT_CMapRec cmap;
+ FT_Byte* data; /* pointer to in-memory cmap table */
+
+ } TT_CMapRec, *TT_CMap;
+
+ typedef const struct TT_CMap_ClassRec_* TT_CMap_Class;
+
+
+ typedef FT_Error
+ (*TT_CMap_ValidateFunc)( FT_Byte* data,
+ FT_Validator valid );
+
+ typedef struct TT_CMap_ClassRec_
+ {
+ FT_CMap_ClassRec clazz;
+ FT_UInt format;
+ TT_CMap_ValidateFunc validate;
+
+ } TT_CMap_ClassRec;
+
+
+ typedef struct TT_ValidatorRec_
+ {
+ FT_ValidatorRec validator;
+ FT_UInt num_glyphs;
+
+ } TT_ValidatorRec, *TT_Validator;
+
+
+#define TT_VALIDATOR( x ) ((TT_Validator)( x ))
+#define TT_VALID_GLYPH_COUNT( x ) TT_VALIDATOR( x )->num_glyphs
+
+
+ FT_LOCAL( FT_Error )
+ tt_face_build_cmaps( TT_Face face );
+
+
+FT_END_HEADER
+
+#endif /* __TTCMAP0_H__ */
+
+
+/* END */
--- /dev/null
+++ b/libfreetype/ttdriver.c
@@ -1,0 +1,420 @@
+/***************************************************************************/
+/* */
+/* ttdriver.c */
+/* */
+/* TrueType font driver implementation (body). */
+/* */
+/* Copyright 1996-2001, 2002 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+
+#include <ft2build.h>
+#include FT_INTERNAL_DEBUG_H
+#include FT_INTERNAL_STREAM_H
+#include FT_INTERNAL_SFNT_H
+#include FT_TRUETYPE_IDS_H
+
+#include "ttdriver.h"
+#include "ttgload.h"
+
+#include "tterrors.h"
+
+
+ /*************************************************************************/
+ /* */
+ /* The macro FT_COMPONENT is used in trace mode. It is an implicit */
+ /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log */
+ /* messages during execution. */
+ /* */
+#undef FT_COMPONENT
+#define FT_COMPONENT trace_ttdriver
+
+
+ /*************************************************************************/
+ /*************************************************************************/
+ /*************************************************************************/
+ /**** ****/
+ /**** ****/
+ /**** F A C E S ****/
+ /**** ****/
+ /**** ****/
+ /*************************************************************************/
+ /*************************************************************************/
+ /*************************************************************************/
+
+
+#undef PAIR_TAG
+#define PAIR_TAG( left, right ) ( ( (FT_ULong)left << 16 ) | \
+ (FT_ULong)right )
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* Get_Kerning */
+ /* */
+ /* <Description> */
+ /* A driver method used to return the kerning vector between two */
+ /* glyphs of the same face. */
+ /* */
+ /* <Input> */
+ /* face :: A handle to the source face object. */
+ /* */
+ /* left_glyph :: The index of the left glyph in the kern pair. */
+ /* */
+ /* right_glyph :: The index of the right glyph in the kern pair. */
+ /* */
+ /* <Output> */
+ /* kerning :: The kerning vector. This is in font units for */
+ /* scalable formats, and in pixels for fixed-sizes */
+ /* formats. */
+ /* */
+ /* <Return> */
+ /* FreeType error code. 0 means success. */
+ /* */
+ /* <Note> */
+ /* Only horizontal layouts (left-to-right & right-to-left) are */
+ /* supported by this function. Other layouts, or more sophisticated */
+ /* kernings, are out of scope of this method (the basic driver */
+ /* interface is meant to be simple). */
+ /* */
+ /* They can be implemented by format-specific interfaces. */
+ /* */
+ static FT_Error
+ Get_Kerning( TT_Face face,
+ FT_UInt left_glyph,
+ FT_UInt right_glyph,
+ FT_Vector* kerning )
+ {
+ TT_Kern0_Pair pair;
+
+
+ if ( !face )
+ return TT_Err_Invalid_Face_Handle;
+
+ kerning->x = 0;
+ kerning->y = 0;
+
+ if ( face->kern_pairs )
+ {
+ /* there are some kerning pairs in this font file! */
+ FT_ULong search_tag = PAIR_TAG( left_glyph, right_glyph );
+ FT_Long left, right;
+
+
+ left = 0;
+ right = face->num_kern_pairs - 1;
+
+ while ( left <= right )
+ {
+ FT_Int middle = left + ( ( right - left ) >> 1 );
+ FT_ULong cur_pair;
+
+
+ pair = face->kern_pairs + middle;
+ cur_pair = PAIR_TAG( pair->left, pair->right );
+
+ if ( cur_pair == search_tag )
+ goto Found;
+
+ if ( cur_pair < search_tag )
+ left = middle + 1;
+ else
+ right = middle - 1;
+ }
+ }
+
+ Exit:
+ return TT_Err_Ok;
+
+ Found:
+ kerning->x = pair->value;
+ goto Exit;
+ }
+
+
+#undef PAIR_TAG
+
+
+ /*************************************************************************/
+ /*************************************************************************/
+ /*************************************************************************/
+ /**** ****/
+ /**** ****/
+ /**** S I Z E S ****/
+ /**** ****/
+ /**** ****/
+ /*************************************************************************/
+ /*************************************************************************/
+ /*************************************************************************/
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* Set_Char_Sizes */
+ /* */
+ /* <Description> */
+ /* A driver method used to reset a size's character sizes (horizontal */
+ /* and vertical) expressed in fractional points. */
+ /* */
+ /* <Input> */
+ /* char_width :: The character width expressed in 26.6 */
+ /* fractional points. */
+ /* */
+ /* char_height :: The character height expressed in 26.6 */
+ /* fractional points. */
+ /* */
+ /* horz_resolution :: The horizontal resolution of the output device. */
+ /* */
+ /* vert_resolution :: The vertical resolution of the output device. */
+ /* */
+ /* <InOut> */
+ /* size :: A handle to the target size object. */
+ /* */
+ /* <Return> */
+ /* FreeType error code. 0 means success. */
+ /* */
+ static FT_Error
+ Set_Char_Sizes( TT_Size size,
+ FT_F26Dot6 char_width,
+ FT_F26Dot6 char_height,
+ FT_UInt horz_resolution,
+ FT_UInt vert_resolution )
+ {
+ FT_Size_Metrics* metrics = &size->root.metrics;
+ TT_Face face = (TT_Face)size->root.face;
+ FT_Long dim_x, dim_y;
+
+
+ /* This bit flag, when set, indicates that the pixel size must be */
+ /* truncated to an integer. Nearly all TrueType fonts have this */
+ /* bit set, as hinting won't work really well otherwise. */
+ /* */
+ /* However, for those rare fonts who do not set it, we override */
+ /* the default computations performed by the base layer. I */
+ /* really don't know whether this is useful, but hey, that's the */
+ /* spec :-) */
+ /* */
+ if ( ( face->header.Flags & 8 ) == 0 )
+ {
+ /* Compute pixel sizes in 26.6 units */
+ dim_x = ( char_width * horz_resolution + 36 ) / 72;
+ dim_y = ( char_height * vert_resolution + 36 ) / 72;
+
+ metrics->x_scale = FT_DivFix( dim_x, face->root.units_per_EM );
+ metrics->y_scale = FT_DivFix( dim_y, face->root.units_per_EM );
+
+ metrics->x_ppem = (FT_UShort)( dim_x >> 6 );
+ metrics->y_ppem = (FT_UShort)( dim_y >> 6 );
+ }
+
+ size->ttmetrics.valid = FALSE;
+#ifdef TT_CONFIG_OPTION_EMBEDDED_BITMAPS
+ size->strike_index = 0xFFFF;
+#endif
+
+ return tt_size_reset( size );
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* Set_Pixel_Sizes */
+ /* */
+ /* <Description> */
+ /* A driver method used to reset a size's character sizes (horizontal */
+ /* and vertical) expressed in integer pixels. */
+ /* */
+ /* <Input> */
+ /* pixel_width :: The character width expressed in integer pixels. */
+ /* */
+ /* pixel_height :: The character height expressed in integer pixels. */
+ /* */
+ /* <InOut> */
+ /* size :: A handle to the target size object. */
+ /* */
+ /* <Return> */
+ /* FreeType error code. 0 means success. */
+ /* */
+ static FT_Error
+ Set_Pixel_Sizes( TT_Size size,
+ FT_UInt pixel_width,
+ FT_UInt pixel_height )
+ {
+ FT_UNUSED( pixel_width );
+ FT_UNUSED( pixel_height );
+
+ /* many things have been pre-computed by the base layer */
+
+ size->ttmetrics.valid = FALSE;
+#ifdef TT_CONFIG_OPTION_EMBEDDED_BITMAPS
+ size->strike_index = 0xFFFF;
+#endif
+
+ return tt_size_reset( size );
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* Load_Glyph */
+ /* */
+ /* <Description> */
+ /* A driver method used to load a glyph within a given glyph slot. */
+ /* */
+ /* <Input> */
+ /* slot :: A handle to the target slot object where the glyph */
+ /* will be loaded. */
+ /* */
+ /* size :: A handle to the source face size at which the glyph */
+ /* must be scaled, loaded, etc. */
+ /* */
+ /* glyph_index :: The index of the glyph in the font file. */
+ /* */
+ /* load_flags :: A flag indicating what to load for this glyph. The */
+ /* FTLOAD_??? constants can be used to control the */
+ /* glyph loading process (e.g., whether the outline */
+ /* should be scaled, whether to load bitmaps or not, */
+ /* whether to hint the outline, etc). */
+ /* */
+ /* <Return> */
+ /* FreeType error code. 0 means success. */
+ /* */
+ static FT_Error
+ Load_Glyph( TT_GlyphSlot slot,
+ TT_Size size,
+ FT_UShort glyph_index,
+ FT_Int32 load_flags )
+ {
+ FT_Error error;
+
+
+ if ( !slot )
+ return TT_Err_Invalid_Slot_Handle;
+
+ /* check whether we want a scaled outline or bitmap */
+ if ( !size )
+ load_flags |= FT_LOAD_NO_SCALE | FT_LOAD_NO_HINTING;
+
+ if ( load_flags & FT_LOAD_NO_SCALE )
+ size = NULL;
+
+ /* reset the size object if necessary */
+ if ( size )
+ {
+ /* these two object must have the same parent */
+ if ( size->root.face != slot->face )
+ return TT_Err_Invalid_Face_Handle;
+
+ if ( !size->ttmetrics.valid )
+ {
+ if ( FT_SET_ERROR( tt_size_reset( size ) ) )
+ return error;
+ }
+ }
+
+ /* now load the glyph outline if necessary */
+ error = TT_Load_Glyph( size, slot, glyph_index, load_flags );
+
+ /* force drop-out mode to 2 - irrelevant now */
+ /* slot->outline.dropout_mode = 2; */
+
+ return error;
+ }
+
+
+ /*************************************************************************/
+ /*************************************************************************/
+ /*************************************************************************/
+ /**** ****/
+ /**** ****/
+ /**** D R I V E R I N T E R F A C E ****/
+ /**** ****/
+ /**** ****/
+ /*************************************************************************/
+ /*************************************************************************/
+ /*************************************************************************/
+
+
+ static FT_Module_Interface
+ tt_get_interface( TT_Driver driver,
+ const char* tt_interface )
+ {
+ FT_Module sfntd = FT_Get_Module( driver->root.root.library,
+ "sfnt" );
+ SFNT_Service sfnt;
+
+
+ /* only return the default interface from the SFNT module */
+ if ( sfntd )
+ {
+ sfnt = (SFNT_Service)( sfntd->clazz->module_interface );
+ if ( sfnt )
+ return sfnt->get_interface( FT_MODULE( driver ), tt_interface );
+ }
+
+ return 0;
+ }
+
+
+ /* The FT_DriverInterface structure is defined in ftdriver.h. */
+
+ FT_CALLBACK_TABLE_DEF
+ const FT_Driver_ClassRec tt_driver_class =
+ {
+ {
+ ft_module_font_driver |
+ ft_module_driver_scalable |
+#ifdef TT_CONFIG_OPTION_BYTECODE_INTERPRETER
+ ft_module_driver_has_hinter,
+#else
+ 0,
+#endif
+
+ sizeof ( TT_DriverRec ),
+
+ "truetype", /* driver name */
+ 0x10000L, /* driver version == 1.0 */
+ 0x20000L, /* driver requires FreeType 2.0 or above */
+
+ (void*)0, /* driver specific interface */
+
+ (FT_Module_Constructor)tt_driver_init,
+ (FT_Module_Destructor) tt_driver_done,
+ (FT_Module_Requester) tt_get_interface,
+ },
+
+ sizeof ( TT_FaceRec ),
+ sizeof ( TT_SizeRec ),
+ sizeof ( FT_GlyphSlotRec ),
+
+
+ (FT_Face_InitFunc) tt_face_init,
+ (FT_Face_DoneFunc) tt_face_done,
+ (FT_Size_InitFunc) tt_size_init,
+ (FT_Size_DoneFunc) tt_size_done,
+ (FT_Slot_InitFunc) 0,
+ (FT_Slot_DoneFunc) 0,
+
+ (FT_Size_ResetPointsFunc) Set_Char_Sizes,
+ (FT_Size_ResetPixelsFunc) Set_Pixel_Sizes,
+ (FT_Slot_LoadFunc) Load_Glyph,
+
+ (FT_Face_GetKerningFunc) Get_Kerning,
+ (FT_Face_AttachFunc) 0,
+ (FT_Face_GetAdvancesFunc) 0
+ };
+
+
+/* END */
--- /dev/null
+++ b/libfreetype/ttdriver.h
@@ -1,0 +1,38 @@
+/***************************************************************************/
+/* */
+/* ttdriver.h */
+/* */
+/* High-level TrueType driver interface (specification). */
+/* */
+/* Copyright 1996-2001, 2002 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+
+#ifndef __TTDRIVER_H__
+#define __TTDRIVER_H__
+
+
+#include <ft2build.h>
+#include FT_INTERNAL_DRIVER_H
+
+
+FT_BEGIN_HEADER
+
+
+ FT_EXPORT_VAR( const FT_Driver_ClassRec ) tt_driver_class;
+
+
+FT_END_HEADER
+
+#endif /* __TTDRIVER_H__ */
+
+
+/* END */
--- /dev/null
+++ b/libfreetype/tterrors.h
@@ -1,0 +1,40 @@
+/***************************************************************************/
+/* */
+/* tterrors.h */
+/* */
+/* TrueType error codes (specification only). */
+/* */
+/* Copyright 2001 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+
+ /*************************************************************************/
+ /* */
+ /* This file is used to define the TrueType error enumeration */
+ /* constants. */
+ /* */
+ /*************************************************************************/
+
+#ifndef __TTERRORS_H__
+#define __TTERRORS_H__
+
+#include FT_MODULE_ERRORS_H
+
+#undef __FTERRORS_H__
+
+#define FT_ERR_PREFIX TT_Err_
+#define FT_ERR_BASE FT_Mod_Err_TrueType
+
+#include FT_ERRORS_H
+
+#endif /* __TTERRORS_H__ */
+
+/* END */
--- /dev/null
+++ b/libfreetype/ttgload.c
@@ -1,0 +1,1783 @@
+/***************************************************************************/
+/* */
+/* ttgload.c */
+/* */
+/* TrueType Glyph Loader (body). */
+/* */
+/* Copyright 1996-2001, 2002 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+
+#include <ft2build.h>
+#include FT_INTERNAL_DEBUG_H
+#include FT_INTERNAL_CALC_H
+#include FT_INTERNAL_STREAM_H
+#include FT_INTERNAL_SFNT_H
+#include FT_TRUETYPE_TAGS_H
+#include FT_OUTLINE_H
+
+#include "ttgload.h"
+
+#include "tterrors.h"
+
+
+ /*************************************************************************/
+ /* */
+ /* The macro FT_COMPONENT is used in trace mode. It is an implicit */
+ /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log */
+ /* messages during execution. */
+ /* */
+#undef FT_COMPONENT
+#define FT_COMPONENT trace_ttgload
+
+
+ /*************************************************************************/
+ /* */
+ /* Composite font flags. */
+ /* */
+#define ARGS_ARE_WORDS 0x0001
+#define ARGS_ARE_XY_VALUES 0x0002
+#define ROUND_XY_TO_GRID 0x0004
+#define WE_HAVE_A_SCALE 0x0008
+/* reserved 0x0010 */
+#define MORE_COMPONENTS 0x0020
+#define WE_HAVE_AN_XY_SCALE 0x0040
+#define WE_HAVE_A_2X2 0x0080
+#define WE_HAVE_INSTR 0x0100
+#define USE_MY_METRICS 0x0200
+#define OVERLAP_COMPOUND 0x0400
+#define SCALED_COMPONENT_OFFSET 0x0800
+#define UNSCALED_COMPONENT_OFFSET 0x1000
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* TT_Get_Metrics */
+ /* */
+ /* <Description> */
+ /* Returns the horizontal or vertical metrics in font units for a */
+ /* given glyph. The metrics are the left side bearing (resp. top */
+ /* side bearing) and advance width (resp. advance height). */
+ /* */
+ /* <Input> */
+ /* header :: A pointer to either the horizontal or vertical metrics */
+ /* structure. */
+ /* */
+ /* idx :: The glyph index. */
+ /* */
+ /* <Output> */
+ /* bearing :: The bearing, either left side or top side. */
+ /* */
+ /* advance :: The advance width resp. advance height. */
+ /* */
+ /* <Note> */
+ /* This function will much probably move to another component in the */
+ /* near future, but I haven't decided which yet. */
+ /* */
+ FT_LOCAL_DEF( void )
+ TT_Get_Metrics( TT_HoriHeader* header,
+ FT_UInt idx,
+ FT_Short* bearing,
+ FT_UShort* advance )
+ {
+ TT_LongMetrics longs_m;
+ FT_UShort k = header->number_Of_HMetrics;
+
+
+ if ( k == 0 )
+ {
+ *bearing = *advance = 0;
+ return;
+ }
+
+ if ( idx < (FT_UInt)k )
+ {
+ longs_m = (TT_LongMetrics )header->long_metrics + idx;
+ *bearing = longs_m->bearing;
+ *advance = longs_m->advance;
+ }
+ else
+ {
+ *bearing = ((TT_ShortMetrics*)header->short_metrics)[idx - k];
+ *advance = ((TT_LongMetrics )header->long_metrics)[k - 1].advance;
+ }
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* Returns the horizontal metrics in font units for a given glyph. If */
+ /* `check' is true, take care of monospaced fonts by returning the */
+ /* advance width maximum. */
+ /* */
+ static void
+ Get_HMetrics( TT_Face face,
+ FT_UInt idx,
+ FT_Bool check,
+ FT_Short* lsb,
+ FT_UShort* aw )
+ {
+ TT_Get_Metrics( &face->horizontal, idx, lsb, aw );
+
+ if ( check && face->postscript.isFixedPitch )
+ *aw = face->horizontal.advance_Width_Max;
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* Returns the advance width table for a given pixel size if it is found */
+ /* in the font's `hdmx' table (if any). */
+ /* */
+ static FT_Byte*
+ Get_Advance_Widths( TT_Face face,
+ FT_UShort ppem )
+ {
+ FT_UShort n;
+
+
+ for ( n = 0; n < face->hdmx.num_records; n++ )
+ if ( face->hdmx.records[n].ppem == ppem )
+ return face->hdmx.records[n].widths;
+
+ return NULL;
+ }
+
+
+#define cur_to_org( n, zone ) \
+ FT_MEM_COPY( (zone)->org, (zone)->cur, (n) * sizeof ( FT_Vector ) )
+
+#define org_to_cur( n, zone ) \
+ FT_MEM_COPY( (zone)->cur, (zone)->org, (n) * sizeof ( FT_Vector ) )
+
+
+ /*************************************************************************/
+ /* */
+ /* Translates an array of coordinates. */
+ /* */
+ static void
+ translate_array( FT_UInt n,
+ FT_Vector* coords,
+ FT_Pos delta_x,
+ FT_Pos delta_y )
+ {
+ FT_UInt k;
+
+
+ if ( delta_x )
+ for ( k = 0; k < n; k++ )
+ coords[k].x += delta_x;
+
+ if ( delta_y )
+ for ( k = 0; k < n; k++ )
+ coords[k].y += delta_y;
+ }
+
+
+ static void
+ tt_prepare_zone( TT_GlyphZone zone,
+ FT_GlyphLoad load,
+ FT_UInt start_point,
+ FT_UInt start_contour )
+ {
+ zone->n_points = (FT_UShort)( load->outline.n_points - start_point );
+ zone->n_contours = (FT_Short) ( load->outline.n_contours - start_contour );
+ zone->org = load->extra_points + start_point;
+ zone->cur = load->outline.points + start_point;
+ zone->tags = (FT_Byte*)load->outline.tags + start_point;
+ zone->contours = (FT_UShort*)load->outline.contours + start_contour;
+ }
+
+
+#undef IS_HINTED
+#define IS_HINTED( flags ) ( ( flags & FT_LOAD_NO_HINTING ) == 0 )
+
+
+ /*************************************************************************/
+ /* */
+ /* The following functions are used by default with TrueType fonts. */
+ /* However, they can be replaced by alternatives if we need to support */
+ /* TrueType-compressed formats (like MicroType) in the future. */
+ /* */
+ /*************************************************************************/
+
+ FT_CALLBACK_DEF( FT_Error )
+ TT_Access_Glyph_Frame( TT_Loader loader,
+ FT_UInt glyph_index,
+ FT_ULong offset,
+ FT_UInt byte_count )
+ {
+ FT_Error error;
+ FT_Stream stream = loader->stream;
+
+ /* for non-debug mode */
+ FT_UNUSED( glyph_index );
+
+
+ FT_TRACE5(( "Glyph %ld\n", glyph_index ));
+
+ /* the following line sets the `error' variable through macros! */
+ if ( FT_STREAM_SEEK( offset ) || FT_FRAME_ENTER( byte_count ) )
+ return error;
+
+ return TT_Err_Ok;
+ }
+
+
+ FT_CALLBACK_DEF( void )
+ TT_Forget_Glyph_Frame( TT_Loader loader )
+ {
+ FT_Stream stream = loader->stream;
+
+
+ FT_FRAME_EXIT();
+ }
+
+
+ FT_CALLBACK_DEF( FT_Error )
+ TT_Load_Glyph_Header( TT_Loader loader )
+ {
+ FT_Stream stream = loader->stream;
+ FT_Int byte_len = loader->byte_len - 10;
+
+
+ if ( byte_len < 0 )
+ return TT_Err_Invalid_Outline;
+
+ loader->n_contours = FT_GET_SHORT();
+
+ loader->bbox.xMin = FT_GET_SHORT();
+ loader->bbox.yMin = FT_GET_SHORT();
+ loader->bbox.xMax = FT_GET_SHORT();
+ loader->bbox.yMax = FT_GET_SHORT();
+
+ FT_TRACE5(( " # of contours: %d\n", loader->n_contours ));
+ FT_TRACE5(( " xMin: %4d xMax: %4d\n", loader->bbox.xMin,
+ loader->bbox.xMax ));
+ FT_TRACE5(( " yMin: %4d yMax: %4d\n", loader->bbox.yMin,
+ loader->bbox.yMax ));
+ loader->byte_len = byte_len;
+
+ return TT_Err_Ok;
+ }
+
+
+ FT_CALLBACK_DEF( FT_Error )
+ TT_Load_Simple_Glyph( TT_Loader load )
+ {
+ FT_Error error;
+ FT_Stream stream = load->stream;
+ FT_GlyphLoader gloader = load->gloader;
+ FT_Int n_contours = load->n_contours;
+ FT_Outline* outline;
+ TT_Face face = (TT_Face)load->face;
+ TT_GlyphSlot slot = (TT_GlyphSlot)load->glyph;
+ FT_UShort n_ins;
+ FT_Int n, n_points;
+ FT_Int byte_len = load->byte_len;
+
+
+ /* reading the contours endpoints & number of points */
+ {
+ short* cur = gloader->current.outline.contours;
+ short* limit = cur + n_contours;
+
+
+ /* check space for contours array + instructions count */
+ byte_len -= 2 * ( n_contours + 1 );
+ if ( byte_len < 0 )
+ goto Invalid_Outline;
+
+ for ( ; cur < limit; cur++ )
+ cur[0] = FT_GET_USHORT();
+
+ n_points = 0;
+ if ( n_contours > 0 )
+ n_points = cur[-1] + 1;
+
+ error = FT_GlyphLoader_CheckPoints( gloader, n_points + 2, 0 );
+ if ( error )
+ goto Fail;
+
+ /* we'd better check the contours table right now */
+ outline = &gloader->current.outline;
+
+ for ( cur = outline->contours + 1; cur < limit; cur++ )
+ if ( cur[-1] >= cur[0] )
+ goto Invalid_Outline;
+ }
+
+ /* reading the bytecode instructions */
+ slot->control_len = 0;
+ slot->control_data = 0;
+
+ n_ins = FT_GET_USHORT();
+
+ FT_TRACE5(( " Instructions size: %d\n", n_ins ));
+
+ if ( n_ins > face->max_profile.maxSizeOfInstructions )
+ {
+ FT_TRACE0(( "TT_Load_Simple_Glyph: Too many instructions!\n" ));
+ error = TT_Err_Too_Many_Hints;
+ goto Fail;
+ }
+
+ byte_len -= n_ins;
+ if ( byte_len < 0 )
+ {
+ FT_TRACE0(( "TT_Load_Simple_Glyph: Instruction count mismatch!\n" ));
+ error = TT_Err_Too_Many_Hints;
+ goto Fail;
+ }
+
+#ifdef TT_CONFIG_OPTION_BYTECODE_INTERPRETER
+
+ if ( ( load->load_flags &
+ ( FT_LOAD_NO_SCALE | FT_LOAD_NO_HINTING ) ) == 0 &&
+ load->instructions )
+ {
+ slot->control_len = n_ins;
+ slot->control_data = load->instructions;
+
+ FT_MEM_COPY( load->instructions, stream->cursor, n_ins );
+ }
+
+#endif /* TT_CONFIG_OPTION_BYTECODE_INTERPRETER */
+
+ stream->cursor += n_ins;
+
+ /* reading the point tags */
+ {
+ FT_Byte* flag = (FT_Byte*)outline->tags;
+ FT_Byte* limit = flag + n_points;
+ FT_Byte c, count;
+
+
+ while ( flag < limit )
+ {
+ if ( --byte_len < 0 )
+ goto Invalid_Outline;
+
+ *flag++ = c = FT_GET_BYTE();
+ if ( c & 8 )
+ {
+ if ( --byte_len < 0 )
+ goto Invalid_Outline;
+
+ count = FT_GET_BYTE();
+ if ( flag + count > limit )
+ goto Invalid_Outline;
+
+ for ( ; count > 0; count-- )
+ *flag++ = c;
+ }
+ }
+
+ /* check that there is enough room to load the coordinates */
+ for ( flag = (FT_Byte*)outline->tags; flag < limit; flag++ )
+ {
+ if ( *flag & 2 )
+ byte_len -= 1;
+ else if ( ( *flag & 16 ) == 0 )
+ byte_len -= 2;
+
+ if ( *flag & 4 )
+ byte_len -= 1;
+ else if ( ( *flag & 32 ) == 0 )
+ byte_len -= 2;
+ }
+
+ if ( byte_len < 0 )
+ goto Invalid_Outline;
+ }
+
+ /* reading the X coordinates */
+
+ {
+ FT_Vector* vec = outline->points;
+ FT_Vector* limit = vec + n_points;
+ FT_Byte* flag = (FT_Byte*)outline->tags;
+ FT_Pos x = 0;
+
+
+ for ( ; vec < limit; vec++, flag++ )
+ {
+ FT_Pos y = 0;
+
+
+ if ( *flag & 2 )
+ {
+ y = FT_GET_BYTE();
+ if ( ( *flag & 16 ) == 0 )
+ y = -y;
+ }
+ else if ( ( *flag & 16 ) == 0 )
+ y = FT_GET_SHORT();
+
+ x += y;
+ vec->x = x;
+ }
+ }
+
+ /* reading the Y coordinates */
+
+ {
+ FT_Vector* vec = gloader->current.outline.points;
+ FT_Vector* limit = vec + n_points;
+ FT_Byte* flag = (FT_Byte*)outline->tags;
+ FT_Pos x = 0;
+
+
+ for ( ; vec < limit; vec++, flag++ )
+ {
+ FT_Pos y = 0;
+
+
+ if ( *flag & 4 )
+ {
+ y = FT_GET_BYTE();
+ if ( ( *flag & 32 ) == 0 )
+ y = -y;
+ }
+ else if ( ( *flag & 32 ) == 0 )
+ y = FT_GET_SHORT();
+
+ x += y;
+ vec->y = x;
+ }
+ }
+
+ /* clear the touch tags */
+ for ( n = 0; n < n_points; n++ )
+ outline->tags[n] &= FT_CURVE_TAG_ON;
+
+ outline->n_points = (FT_UShort)n_points;
+ outline->n_contours = (FT_Short) n_contours;
+
+ load->byte_len = byte_len;
+
+ Fail:
+ return error;
+
+ Invalid_Outline:
+ error = TT_Err_Invalid_Outline;
+ goto Fail;
+ }
+
+
+ FT_CALLBACK_DEF( FT_Error )
+ TT_Load_Composite_Glyph( TT_Loader loader )
+ {
+ FT_Error error;
+ FT_Stream stream = loader->stream;
+ FT_GlyphLoader gloader = loader->gloader;
+ FT_SubGlyph subglyph;
+ FT_UInt num_subglyphs;
+ FT_Int byte_len = loader->byte_len;
+
+
+ num_subglyphs = 0;
+
+ do
+ {
+ FT_Fixed xx, xy, yy, yx;
+
+
+ /* check that we can load a new subglyph */
+ error = FT_GlyphLoader_CheckSubGlyphs( gloader, num_subglyphs + 1 );
+ if ( error )
+ goto Fail;
+
+ /* check space */
+ byte_len -= 4;
+ if ( byte_len < 0 )
+ goto Invalid_Composite;
+
+ subglyph = gloader->current.subglyphs + num_subglyphs;
+
+ subglyph->arg1 = subglyph->arg2 = 0;
+
+ subglyph->flags = FT_GET_USHORT();
+ subglyph->index = FT_GET_USHORT();
+
+ /* check space */
+ byte_len -= 2;
+ if ( subglyph->flags & ARGS_ARE_WORDS )
+ byte_len -= 2;
+ if ( subglyph->flags & WE_HAVE_A_SCALE )
+ byte_len -= 2;
+ else if ( subglyph->flags & WE_HAVE_AN_XY_SCALE )
+ byte_len -= 4;
+ else if ( subglyph->flags & WE_HAVE_A_2X2 )
+ byte_len -= 8;
+
+ if ( byte_len < 0 )
+ goto Invalid_Composite;
+
+ /* read arguments */
+ if ( subglyph->flags & ARGS_ARE_WORDS )
+ {
+ subglyph->arg1 = FT_GET_SHORT();
+ subglyph->arg2 = FT_GET_SHORT();
+ }
+ else
+ {
+ subglyph->arg1 = FT_GET_CHAR();
+ subglyph->arg2 = FT_GET_CHAR();
+ }
+
+ /* read transform */
+ xx = yy = 0x10000L;
+ xy = yx = 0;
+
+ if ( subglyph->flags & WE_HAVE_A_SCALE )
+ {
+ xx = (FT_Fixed)FT_GET_SHORT() << 2;
+ yy = xx;
+ }
+ else if ( subglyph->flags & WE_HAVE_AN_XY_SCALE )
+ {
+ xx = (FT_Fixed)FT_GET_SHORT() << 2;
+ yy = (FT_Fixed)FT_GET_SHORT() << 2;
+ }
+ else if ( subglyph->flags & WE_HAVE_A_2X2 )
+ {
+ xx = (FT_Fixed)FT_GET_SHORT() << 2;
+ yx = (FT_Fixed)FT_GET_SHORT() << 2;
+ xy = (FT_Fixed)FT_GET_SHORT() << 2;
+ yy = (FT_Fixed)FT_GET_SHORT() << 2;
+ }
+
+ subglyph->transform.xx = xx;
+ subglyph->transform.xy = xy;
+ subglyph->transform.yx = yx;
+ subglyph->transform.yy = yy;
+
+ num_subglyphs++;
+
+ } while ( subglyph->flags & MORE_COMPONENTS );
+
+ gloader->current.num_subglyphs = num_subglyphs;
+
+#ifdef TT_CONFIG_OPTION_BYTECODE_INTERPRETER
+ {
+ /* we must undo the FT_FRAME_ENTER in order to point to the */
+ /* composite instructions, if we find some. */
+ /* we will process them later... */
+ /* */
+ loader->ins_pos = (FT_ULong)( FT_STREAM_POS() +
+ stream->cursor - stream->limit );
+ }
+#endif
+
+ loader->byte_len = byte_len;
+
+ Fail:
+ return error;
+
+ Invalid_Composite:
+ error = TT_Err_Invalid_Composite;
+ goto Fail;
+ }
+
+
+ FT_LOCAL_DEF( void )
+ TT_Init_Glyph_Loading( TT_Face face )
+ {
+ face->access_glyph_frame = TT_Access_Glyph_Frame;
+ face->read_glyph_header = TT_Load_Glyph_Header;
+ face->read_simple_glyph = TT_Load_Simple_Glyph;
+ face->read_composite_glyph = TT_Load_Composite_Glyph;
+ face->forget_glyph_frame = TT_Forget_Glyph_Frame;
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* TT_Process_Simple_Glyph */
+ /* */
+ /* <Description> */
+ /* Once a simple glyph has been loaded, it needs to be processed. */
+ /* Usually, this means scaling and hinting through bytecode */
+ /* interpretation. */
+ /* */
+ static FT_Error
+ TT_Process_Simple_Glyph( TT_Loader load,
+ FT_Bool debug )
+ {
+ FT_GlyphLoader gloader = load->gloader;
+ FT_Outline* outline = &gloader->current.outline;
+ FT_UInt n_points = outline->n_points;
+#ifdef TT_CONFIG_OPTION_BYTECODE_INTERPRETER
+ FT_UInt n_ins;
+#endif
+ TT_GlyphZone zone = &load->zone;
+ FT_Error error = TT_Err_Ok;
+
+ FT_UNUSED( debug ); /* used by truetype interpreter only */
+
+
+#ifdef TT_CONFIG_OPTION_BYTECODE_INTERPRETER
+ n_ins = load->glyph->control_len;
+#endif
+
+ /* add shadow points */
+
+ /* Now add the two shadow points at n and n + 1. */
+ /* We need the left side bearing and advance width. */
+
+ {
+ FT_Vector* pp1;
+ FT_Vector* pp2;
+
+
+ /* pp1 = xMin - lsb */
+ pp1 = outline->points + n_points;
+ pp1->x = load->bbox.xMin - load->left_bearing;
+ pp1->y = 0;
+
+ /* pp2 = pp1 + aw */
+ pp2 = pp1 + 1;
+ pp2->x = pp1->x + load->advance;
+ pp2->y = 0;
+
+ outline->tags[n_points ] = 0;
+ outline->tags[n_points + 1] = 0;
+ }
+
+ /* Note that we return two more points that are not */
+ /* part of the glyph outline. */
+
+ n_points += 2;
+
+ /* set up zone for hinting */
+ tt_prepare_zone( zone, &gloader->current, 0, 0 );
+
+ /* eventually scale the glyph */
+ if ( !( load->load_flags & FT_LOAD_NO_SCALE ) )
+ {
+ FT_Vector* vec = zone->cur;
+ FT_Vector* limit = vec + n_points;
+ FT_Fixed x_scale = load->size->metrics.x_scale;
+ FT_Fixed y_scale = load->size->metrics.y_scale;
+
+
+ /* first scale the glyph points */
+ for ( ; vec < limit; vec++ )
+ {
+ vec->x = FT_MulFix( vec->x, x_scale );
+ vec->y = FT_MulFix( vec->y, y_scale );
+ }
+ }
+
+ cur_to_org( n_points, zone );
+
+ /* eventually hint the glyph */
+ if ( IS_HINTED( load->load_flags ) )
+ {
+ FT_Pos x = zone->org[n_points-2].x;
+
+
+ x = ( ( x + 32 ) & -64 ) - x;
+ translate_array( n_points, zone->org, x, 0 );
+
+ org_to_cur( n_points, zone );
+
+ zone->cur[n_points - 1].x = ( zone->cur[n_points - 1].x + 32 ) & -64;
+
+#ifdef TT_CONFIG_OPTION_BYTECODE_INTERPRETER
+
+ /* now consider hinting */
+ if ( n_ins > 0 )
+ {
+ error = TT_Set_CodeRange( load->exec, tt_coderange_glyph,
+ load->exec->glyphIns, n_ins );
+ if ( error )
+ goto Exit;
+
+ load->exec->is_composite = FALSE;
+ load->exec->pedantic_hinting = (FT_Bool)( load->load_flags &
+ FT_LOAD_PEDANTIC );
+ load->exec->pts = *zone;
+ load->exec->pts.n_points += 2;
+
+ error = TT_Run_Context( load->exec, debug );
+ if ( error && load->exec->pedantic_hinting )
+ goto Exit;
+
+ error = TT_Err_Ok; /* ignore bytecode errors in non-pedantic mode */
+ }
+
+#endif /* TT_CONFIG_OPTION_BYTECODE_INTERPRETER */
+
+ }
+
+ /* save glyph phantom points */
+ if ( !load->preserve_pps )
+ {
+ load->pp1 = zone->cur[n_points - 2];
+ load->pp2 = zone->cur[n_points - 1];
+ }
+
+#ifdef TT_CONFIG_OPTION_BYTECODE_INTERPRETER
+ Exit:
+#endif
+ return error;
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* load_truetype_glyph */
+ /* */
+ /* <Description> */
+ /* Loads a given truetype glyph. Handles composites and uses a */
+ /* TT_Loader object. */
+ /* */
+ static FT_Error
+ load_truetype_glyph( TT_Loader loader,
+ FT_UInt glyph_index )
+ {
+
+#ifdef TT_CONFIG_OPTION_BYTECODE_INTERPRETER
+ FT_Stream stream = loader->stream;
+#endif
+
+ FT_Error error;
+ TT_Face face = (TT_Face)loader->face;
+ FT_ULong offset;
+ FT_Int contours_count;
+ FT_UInt num_points, count;
+ FT_Fixed x_scale, y_scale;
+ FT_GlyphLoader gloader = loader->gloader;
+ FT_Bool opened_frame = 0;
+
+#ifdef FT_CONFIG_OPTION_INCREMENTAL
+ struct FT_StreamRec_ inc_stream;
+ FT_Data glyph_data;
+ FT_Bool glyph_data_loaded = 0;
+#endif
+
+
+ /* check glyph index */
+ if ( glyph_index >= (FT_UInt)face->root.num_glyphs )
+ {
+ error = TT_Err_Invalid_Glyph_Index;
+ goto Exit;
+ }
+
+ loader->glyph_index = glyph_index;
+ num_points = 0;
+
+ x_scale = 0x10000L;
+ y_scale = 0x10000L;
+ if ( ( loader->load_flags & FT_LOAD_NO_SCALE ) == 0 )
+ {
+ x_scale = loader->size->metrics.x_scale;
+ y_scale = loader->size->metrics.y_scale;
+ }
+
+ /* get horizontal metrics */
+ {
+ FT_Short left_bearing = 0;
+ FT_UShort advance_width = 0;
+
+#ifdef FT_CONFIG_OPTION_INCREMENTAL
+ FT_Bool metrics_found = FALSE;
+
+
+ /* If this is an incrementally loaded font see if there are */
+ /* overriding metrics for this glyph. */
+ if ( face->root.internal->incremental_interface &&
+ face->root.internal->incremental_interface->funcs->get_glyph_metrics )
+ {
+ FT_Incremental_MetricsRec m;
+
+
+ error = face->root.internal->incremental_interface->funcs->get_glyph_metrics(
+ face->root.internal->incremental_interface->object,
+ glyph_index, FALSE, &m, &metrics_found );
+ if ( error )
+ goto Exit;
+ left_bearing = (FT_Short)m.bearing_x;
+ advance_width = (FT_UShort)m.advance;
+ }
+
+ if ( !metrics_found )
+ Get_HMetrics( face, glyph_index,
+ (FT_Bool)!( loader->load_flags &
+ FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH ),
+ &left_bearing,
+ &advance_width );
+
+#else
+
+ Get_HMetrics( face, glyph_index,
+ (FT_Bool)!( loader->load_flags &
+ FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH ),
+ &left_bearing,
+ &advance_width );
+
+#endif /* FT_CONFIG_OPTION_INCREMENTAL */
+
+ loader->left_bearing = left_bearing;
+ loader->advance = advance_width;
+
+ if ( !loader->linear_def )
+ {
+ loader->linear_def = 1;
+ loader->linear = advance_width;
+ }
+ }
+
+#ifdef FT_CONFIG_OPTION_INCREMENTAL
+
+ /* Set `offset' to the start of the glyph program relative to the */
+ /* start of the 'glyf' table, and `count' to the length of the */
+ /* glyph program in bytes. */
+ /* */
+ /* If we are loading glyph data via the incremental interface, set */
+ /* the loader stream to a memory stream reading the data returned */
+ /* by the interface. */
+
+ if ( face->root.internal->incremental_interface )
+ {
+ error = face->root.internal->incremental_interface->funcs->get_glyph_data(
+ face->root.internal->incremental_interface->object,
+ glyph_index, &glyph_data );
+ if ( error )
+ goto Exit;
+
+ glyph_data_loaded = 1;
+ offset = 0;
+ count = glyph_data.length;
+
+ FT_MEM_ZERO( &inc_stream, sizeof ( inc_stream ) );
+ FT_Stream_OpenMemory( &inc_stream,
+ glyph_data.pointer, glyph_data.length );
+
+ loader->stream = &inc_stream;
+ }
+ else
+
+#endif /* FT_CONFIG_OPTION_INCREMENTAL */
+
+ {
+ offset = face->glyph_locations[glyph_index];
+ count = 0;
+
+ if ( glyph_index < (FT_UInt)face->num_locations - 1 )
+ count = face->glyph_locations[glyph_index + 1] - offset;
+ }
+
+ if ( count == 0 )
+ {
+ /* as described by Frederic Loyer, these are spaces, and */
+ /* not the unknown glyph. */
+ loader->bbox.xMin = 0;
+ loader->bbox.xMax = 0;
+ loader->bbox.yMin = 0;
+ loader->bbox.yMax = 0;
+
+ loader->pp1.x = 0;
+ loader->pp2.x = loader->advance;
+
+ if ( ( loader->load_flags & FT_LOAD_NO_SCALE ) == 0 )
+ loader->pp2.x = FT_MulFix( loader->pp2.x, x_scale );
+
+#ifdef TT_CONFIG_OPTION_BYTECODE_INTERPRETER
+
+ if ( loader->exec )
+ loader->exec->glyphSize = 0;
+
+#endif
+
+ error = TT_Err_Ok;
+ goto Exit;
+ }
+
+ loader->byte_len = (FT_Int)count;
+
+ offset = loader->glyf_offset + offset;
+
+ /* access glyph frame */
+ error = face->access_glyph_frame( loader, glyph_index, offset, count );
+ if ( error )
+ goto Exit;
+
+ opened_frame = 1;
+
+ /* read first glyph header */
+ error = face->read_glyph_header( loader );
+ if ( error )
+ goto Fail;
+
+ contours_count = loader->n_contours;
+
+ count -= 10;
+
+ loader->pp1.x = loader->bbox.xMin - loader->left_bearing;
+ loader->pp1.y = 0;
+ loader->pp2.x = loader->pp1.x + loader->advance;
+ loader->pp2.y = 0;
+
+ if ( ( loader->load_flags & FT_LOAD_NO_SCALE ) == 0 )
+ {
+ loader->pp1.x = FT_MulFix( loader->pp1.x, x_scale );
+ loader->pp2.x = FT_MulFix( loader->pp2.x, x_scale );
+ }
+
+ /***********************************************************************/
+ /***********************************************************************/
+ /***********************************************************************/
+
+ /* if it is a simple glyph, load it */
+
+ if ( contours_count >= 0 )
+ {
+ /* check that we can add the contours to the glyph */
+ error = FT_GlyphLoader_CheckPoints( gloader, 0, contours_count );
+ if ( error )
+ goto Fail;
+
+ error = face->read_simple_glyph( loader );
+ if ( error )
+ goto Fail;
+
+#ifdef TT_CONFIG_OPTION_BYTECODE_INTERPRETER
+
+ {
+ TT_Size size = (TT_Size)loader->size;
+
+
+ error = TT_Process_Simple_Glyph( loader,
+ (FT_Bool)( size && size->debug ) );
+ }
+
+#else
+
+ error = TT_Process_Simple_Glyph( loader, 0 );
+
+#endif
+
+ if ( error )
+ goto Fail;
+
+ FT_GlyphLoader_Add( gloader );
+
+ /* Note: We could have put the simple loader source there */
+ /* but the code is fat enough already :-) */
+ }
+
+ /***********************************************************************/
+ /***********************************************************************/
+ /***********************************************************************/
+
+ /* otherwise, load a composite! */
+ else
+ {
+ TT_GlyphSlot glyph = (TT_GlyphSlot)loader->glyph;
+ FT_UInt start_point;
+#ifdef TT_CONFIG_OPTION_BYTECODE_INTERPRETER
+ FT_UInt start_contour;
+ FT_ULong ins_pos; /* position of composite instructions, if any */
+#endif
+
+
+ /* for each subglyph, read composite header */
+ start_point = gloader->base.outline.n_points;
+#ifdef TT_CONFIG_OPTION_BYTECODE_INTERPRETER
+ start_contour = gloader->base.outline.n_contours;
+#endif
+
+ error = face->read_composite_glyph( loader );
+ if ( error )
+ goto Fail;
+
+#ifdef TT_CONFIG_OPTION_BYTECODE_INTERPRETER
+ ins_pos = loader->ins_pos;
+#endif
+ face->forget_glyph_frame( loader );
+ opened_frame = 0;
+
+ /* if the flag FT_LOAD_NO_RECURSE is set, we return the subglyph */
+ /* `as is' in the glyph slot (the client application will be */
+ /* responsible for interpreting these data)... */
+ /* */
+ if ( loader->load_flags & FT_LOAD_NO_RECURSE )
+ {
+ /* set up remaining glyph fields */
+ FT_GlyphLoader_Add( gloader );
+
+ glyph->num_subglyphs = gloader->base.num_subglyphs;
+ glyph->format = FT_GLYPH_FORMAT_COMPOSITE;
+ glyph->subglyphs = gloader->base.subglyphs;
+
+ goto Exit;
+ }
+
+ /*********************************************************************/
+ /*********************************************************************/
+ /*********************************************************************/
+
+ /* Now, read each subglyph independently. */
+ {
+ FT_Int n, num_base_points, num_new_points;
+ FT_SubGlyph subglyph = 0;
+
+ FT_UInt num_subglyphs = gloader->current.num_subglyphs;
+ FT_UInt num_base_subgs = gloader->base.num_subglyphs;
+
+
+ FT_GlyphLoader_Add( gloader );
+
+ for ( n = 0; n < (FT_Int)num_subglyphs; n++ )
+ {
+ FT_Vector pp1, pp2;
+ FT_Pos x, y;
+
+
+ /* Each time we call load_truetype_glyph in this loop, the */
+ /* value of `gloader.base.subglyphs' can change due to table */
+ /* reallocations. We thus need to recompute the subglyph */
+ /* pointer on each iteration. */
+ subglyph = gloader->base.subglyphs + num_base_subgs + n;
+
+ pp1 = loader->pp1;
+ pp2 = loader->pp2;
+
+ num_base_points = gloader->base.outline.n_points;
+
+ error = load_truetype_glyph( loader, subglyph->index );
+ if ( error )
+ goto Fail;
+
+ /* restore subglyph pointer */
+ subglyph = gloader->base.subglyphs + num_base_subgs + n;
+
+ if ( subglyph->flags & USE_MY_METRICS )
+ {
+ pp1 = loader->pp1;
+ pp2 = loader->pp2;
+ }
+ else
+ {
+ loader->pp1 = pp1;
+ loader->pp2 = pp2;
+ }
+
+ num_points = gloader->base.outline.n_points;
+
+ num_new_points = num_points - num_base_points;
+
+ /* now perform the transform required for this subglyph */
+
+ if ( subglyph->flags & ( WE_HAVE_A_SCALE |
+ WE_HAVE_AN_XY_SCALE |
+ WE_HAVE_A_2X2 ) )
+ {
+ FT_Vector* cur = gloader->base.outline.points +
+ num_base_points;
+ FT_Vector* org = gloader->base.extra_points +
+ num_base_points;
+ FT_Vector* limit = cur + num_new_points;
+
+
+ for ( ; cur < limit; cur++, org++ )
+ {
+ FT_Vector_Transform( cur, &subglyph->transform );
+ FT_Vector_Transform( org, &subglyph->transform );
+ }
+ }
+
+ /* apply offset */
+
+ if ( !( subglyph->flags & ARGS_ARE_XY_VALUES ) )
+ {
+ FT_UInt k = subglyph->arg1;
+ FT_UInt l = subglyph->arg2;
+ FT_Vector* p1;
+ FT_Vector* p2;
+
+
+ if ( start_point + k >= (FT_UInt)num_base_points ||
+ l >= (FT_UInt)num_new_points )
+ {
+ error = TT_Err_Invalid_Composite;
+ goto Fail;
+ }
+
+ l += num_base_points;
+
+ p1 = gloader->base.outline.points + start_point + k;
+ p2 = gloader->base.outline.points + start_point + l;
+
+ x = p1->x - p2->x;
+ y = p1->y - p2->y;
+ }
+ else
+ {
+ x = subglyph->arg1;
+ y = subglyph->arg2;
+
+ /* Use a default value dependent on */
+ /* TT_CONFIG_OPTION_COMPONENT_OFFSET_SCALED. This is useful for old TT */
+ /* fonts which don't set the xxx_COMPONENT_OFFSET bit. */
+
+#ifdef TT_CONFIG_OPTION_COMPONENT_OFFSET_SCALED
+ if ( !( subglyph->flags & UNSCALED_COMPONENT_OFFSET ) &&
+#else
+ if ( ( subglyph->flags & SCALED_COMPONENT_OFFSET ) &&
+#endif
+ ( subglyph->flags & ( WE_HAVE_A_SCALE |
+ WE_HAVE_AN_XY_SCALE |
+ WE_HAVE_A_2X2 )) )
+ {
+#if 0
+
+ /*************************************************************************/
+ /* */
+ /* This algorithm is what Apple documents. But it doesn't work. */
+ /* */
+ int a = subglyph->transform.xx > 0 ? subglyph->transform.xx
+ : -subglyph->transform.xx;
+ int b = subglyph->transform.yx > 0 ? subglyph->transform.yx
+ : -subglyph->transform.yx;
+ int c = subglyph->transform.xy > 0 ? subglyph->transform.xy
+ : -subglyph->transform.xy;
+ int d = subglyph->transform.yy > 0 ? subglyph->transform.yy
+ : -subglyph->transform.yy;
+ int m = a > b ? a : b;
+ int n = c > d ? c : d;
+
+
+ if ( a - b <= 33 && a - b >= -33 )
+ m *= 2;
+ if ( c - d <= 33 && c - d >= -33 )
+ n *= 2;
+ x = FT_MulFix( x, m );
+ y = FT_MulFix( y, n );
+
+#else /* 0 */
+
+ /*************************************************************************/
+ /* */
+ /* This algorithm is a guess and works much better than the above. */
+ /* */
+ int mac_xscale = FT_SqrtFixed(
+ FT_MulFix( subglyph->transform.xx,
+ subglyph->transform.xx ) +
+ FT_MulFix( subglyph->transform.xy,
+ subglyph->transform.xy) );
+ int mac_yscale = FT_SqrtFixed(
+ FT_MulFix( subglyph->transform.yy,
+ subglyph->transform.yy ) +
+ FT_MulFix( subglyph->transform.yx,
+ subglyph->transform.yx ) );
+
+
+ x = FT_MulFix( x, mac_xscale );
+ y = FT_MulFix( y, mac_yscale );
+#endif /* 0 */
+
+ }
+
+ if ( !( loader->load_flags & FT_LOAD_NO_SCALE ) )
+ {
+ x = FT_MulFix( x, x_scale );
+ y = FT_MulFix( y, y_scale );
+
+ if ( subglyph->flags & ROUND_XY_TO_GRID )
+ {
+ x = ( x + 32 ) & -64;
+ y = ( y + 32 ) & -64;
+ }
+ }
+ }
+
+ if ( x || y )
+ {
+ translate_array( num_new_points,
+ gloader->base.outline.points + num_base_points,
+ x, y );
+
+ translate_array( num_new_points,
+ gloader->base.extra_points + num_base_points,
+ x, y );
+ }
+ }
+
+ /*******************************************************************/
+ /*******************************************************************/
+ /*******************************************************************/
+
+ /* we have finished loading all sub-glyphs; now, look for */
+ /* instructions for this composite! */
+
+#ifdef TT_CONFIG_OPTION_BYTECODE_INTERPRETER
+
+ if ( num_subglyphs > 0 &&
+ loader->exec &&
+ ins_pos > 0 &&
+ subglyph->flags & WE_HAVE_INSTR )
+ {
+ FT_UShort n_ins;
+ TT_ExecContext exec = loader->exec;
+ TT_GlyphZone pts;
+ FT_Vector* pp1;
+
+
+ /* read size of instructions */
+ if ( FT_STREAM_SEEK( ins_pos ) ||
+ FT_READ_USHORT( n_ins ) )
+ goto Fail;
+ FT_TRACE5(( " Instructions size = %d\n", n_ins ));
+
+ /* in some fonts? */
+ if ( n_ins == 0xFFFFU )
+ n_ins = 0;
+
+ /* check it */
+ if ( n_ins > face->max_profile.maxSizeOfInstructions )
+ {
+ FT_TRACE0(( "Too many instructions (%d) in composite glyph %ld\n",
+ n_ins, subglyph->index ));
+ error = TT_Err_Too_Many_Hints;
+ goto Fail;
+ }
+
+ /* read the instructions */
+ if ( FT_STREAM_READ( exec->glyphIns, n_ins ) )
+ goto Fail;
+
+ glyph->control_data = exec->glyphIns;
+ glyph->control_len = n_ins;
+
+ error = TT_Set_CodeRange( exec,
+ tt_coderange_glyph,
+ exec->glyphIns,
+ n_ins );
+ if ( error )
+ goto Fail;
+
+ /* prepare the execution context */
+ tt_prepare_zone( &exec->pts, &gloader->base,
+ start_point, start_contour );
+ pts = &exec->pts;
+
+ pts->n_points = (short)(num_points + 2);
+ pts->n_contours = gloader->base.outline.n_contours;
+
+ /* add phantom points */
+ pp1 = pts->cur + num_points;
+ pp1[0] = loader->pp1;
+ pp1[1] = loader->pp2;
+
+ pts->tags[num_points ] = 0;
+ pts->tags[num_points + 1] = 0;
+
+ /* if hinting, round the phantom points */
+ if ( IS_HINTED( loader->load_flags ) )
+ {
+ pp1[0].x = ( ( loader->pp1.x + 32 ) & -64 );
+ pp1[1].x = ( ( loader->pp2.x + 32 ) & -64 );
+ }
+
+ {
+ FT_UInt k;
+
+
+ for ( k = 0; k < num_points; k++ )
+ pts->tags[k] &= FT_CURVE_TAG_ON;
+ }
+
+ cur_to_org( num_points + 2, pts );
+
+ /* now consider hinting */
+ if ( IS_HINTED( loader->load_flags ) && n_ins > 0 )
+ {
+ exec->is_composite = TRUE;
+ exec->pedantic_hinting =
+ (FT_Bool)( loader->load_flags & FT_LOAD_PEDANTIC );
+
+ error = TT_Run_Context( exec, ((TT_Size)loader->size)->debug );
+ if ( error && exec->pedantic_hinting )
+ goto Fail;
+ }
+
+ /* save glyph origin and advance points */
+ loader->pp1 = pp1[0];
+ loader->pp2 = pp1[1];
+ }
+
+#endif /* TT_CONFIG_OPTION_BYTECODE_INTERPRETER */
+
+ }
+ /* end of composite loading */
+ }
+
+ /***********************************************************************/
+ /***********************************************************************/
+ /***********************************************************************/
+
+ Fail:
+ if ( opened_frame )
+ face->forget_glyph_frame( loader );
+
+ Exit:
+
+#ifdef FT_CONFIG_OPTION_INCREMENTAL
+ if ( glyph_data_loaded )
+ face->root.internal->incremental_interface->funcs->free_glyph_data(
+ face->root.internal->incremental_interface->object,
+ &glyph_data );
+#endif
+
+ return error;
+ }
+
+
+ static FT_Error
+ compute_glyph_metrics( TT_Loader loader,
+ FT_UInt glyph_index )
+ {
+ FT_BBox bbox;
+ TT_Face face = (TT_Face)loader->face;
+ FT_Fixed y_scale;
+ TT_GlyphSlot glyph = loader->glyph;
+ TT_Size size = (TT_Size)loader->size;
+
+
+ y_scale = 0x10000L;
+ if ( ( loader->load_flags & FT_LOAD_NO_SCALE ) == 0 )
+ y_scale = size->root.metrics.y_scale;
+
+ if ( glyph->format != FT_GLYPH_FORMAT_COMPOSITE )
+ {
+ glyph->outline.flags &= ~FT_OUTLINE_SINGLE_PASS;
+
+ /* copy outline to our glyph slot */
+ FT_GlyphLoader_CopyPoints( glyph->internal->loader, loader->gloader );
+ glyph->outline = glyph->internal->loader->base.outline;
+
+ /* translate array so that (0,0) is the glyph's origin */
+ FT_Outline_Translate( &glyph->outline, -loader->pp1.x, 0 );
+
+ FT_Outline_Get_CBox( &glyph->outline, &bbox );
+
+ if ( IS_HINTED( loader->load_flags ) )
+ {
+ /* grid-fit the bounding box */
+ bbox.xMin &= -64;
+ bbox.yMin &= -64;
+ bbox.xMax = ( bbox.xMax + 63 ) & -64;
+ bbox.yMax = ( bbox.yMax + 63 ) & -64;
+ }
+ }
+ else
+ bbox = loader->bbox;
+
+ /* get the device-independent horizontal advance. It is scaled later */
+ /* by the base layer. */
+ {
+ FT_Pos advance = loader->linear;
+
+
+ /* the flag FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH was introduced to */
+ /* correctly support DynaLab fonts, which have an incorrect */
+ /* `advance_Width_Max' field! It is used, to my knowledge, */
+ /* exclusively in the X-TrueType font server. */
+ /* */
+ if ( face->postscript.isFixedPitch &&
+ ( loader->load_flags & FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH ) == 0 )
+ advance = face->horizontal.advance_Width_Max;
+
+ /* we need to return the advance in font units in linearHoriAdvance, */
+ /* it will be scaled later by the base layer. */
+ glyph->linearHoriAdvance = advance;
+ }
+
+ glyph->metrics.horiBearingX = bbox.xMin;
+ glyph->metrics.horiBearingY = bbox.yMax;
+ glyph->metrics.horiAdvance = loader->pp2.x - loader->pp1.x;
+
+ /* don't forget to hint the advance when we need to */
+ if ( IS_HINTED( loader->load_flags ) )
+ glyph->metrics.horiAdvance = ( glyph->metrics.horiAdvance + 32 ) & -64;
+
+ /* Now take care of vertical metrics. In the case where there is */
+ /* no vertical information within the font (relatively common), make */
+ /* up some metrics by `hand'... */
+
+ {
+ FT_Short top_bearing; /* vertical top side bearing (EM units) */
+ FT_UShort advance_height; /* vertical advance height (EM units) */
+
+ FT_Pos left; /* scaled vertical left side bearing */
+ FT_Pos top; /* scaled vertical top side bearing */
+ FT_Pos advance; /* scaled vertical advance height */
+ FT_Bool metrics_found = FALSE;
+
+#ifdef FT_CONFIG_OPTION_INCREMENTAL
+
+ /* If this is an incrementally loaded font see if there are */
+ /* overriding metrics for this glyph. */
+ if ( face->root.internal->incremental_interface &&
+ face->root.internal->incremental_interface->funcs->get_glyph_metrics )
+ {
+ FT_Incremental_MetricsRec m;
+ FT_Error error =
+ face->root.internal->incremental_interface->funcs->get_glyph_metrics(
+ face->root.internal->incremental_interface->object,
+ glyph_index, TRUE, &m, &metrics_found );
+
+
+ if ( error )
+ return error;
+
+ top_bearing = (FT_Short)m.bearing_y;
+ advance_height = (FT_UShort)m.advance;
+ }
+
+#endif /* FT_CONFIG_OPTION_INCREMENTAL */
+
+ /* Get the unscaled top bearing and advance height. */
+ if ( !metrics_found && face->vertical_info &&
+ face->vertical.number_Of_VMetrics > 0 )
+ {
+ /* Don't assume that both the vertical header and vertical */
+ /* metrics are present in the same font :-) */
+
+ TT_Get_Metrics( (TT_HoriHeader*)&face->vertical,
+ glyph_index,
+ &top_bearing,
+ &advance_height );
+ }
+ else
+ {
+ /* Make up the distances from the horizontal header. */
+
+ /* NOTE: The OS/2 values are the only `portable' ones, */
+ /* which is why we use them, if there is an OS/2 */
+ /* table in the font. Otherwise, we use the */
+ /* values defined in the horizontal header. */
+ /* */
+ /* NOTE2: The sTypoDescender is negative, which is why */
+ /* we compute the baseline-to-baseline distance */
+ /* here with: */
+ /* ascender - descender + linegap */
+ /* */
+ if ( face->os2.version != 0xFFFFU )
+ {
+ top_bearing = (FT_Short)( face->os2.sTypoLineGap / 2 );
+ advance_height = (FT_UShort)( face->os2.sTypoAscender -
+ face->os2.sTypoDescender +
+ face->os2.sTypoLineGap );
+ }
+ else
+ {
+ top_bearing = (FT_Short)( face->horizontal.Line_Gap / 2 );
+ advance_height = (FT_UShort)( face->horizontal.Ascender +
+ face->horizontal.Descender +
+ face->horizontal.Line_Gap );
+ }
+ }
+
+ /* We must adjust the top_bearing value from the bounding box given */
+ /* in the glyph header to te bounding box calculated with */
+ /* FT_Get_Outline_CBox(). */
+
+ /* scale the metrics */
+ if ( !( loader->load_flags & FT_LOAD_NO_SCALE ) )
+ {
+ top = FT_MulFix( top_bearing + loader->bbox.yMax, y_scale )
+ - bbox.yMax;
+ advance = FT_MulFix( advance_height, y_scale );
+ }
+ else
+ {
+ top = top_bearing + loader->bbox.yMax - bbox.yMax;
+ advance = advance_height;
+ }
+
+ /* set the advance height in design units. It is scaled later by */
+ /* the base layer. */
+ glyph->linearVertAdvance = advance_height;
+
+ /* XXX: for now, we have no better algorithm for the lsb, but it */
+ /* should work fine. */
+ /* */
+ left = ( bbox.xMin - bbox.xMax ) / 2;
+
+ /* grid-fit them if necessary */
+ if ( IS_HINTED( loader->load_flags ) )
+ {
+ left &= -64;
+ top = ( top + 63 ) & -64;
+ advance = ( advance + 32 ) & -64;
+ }
+
+ glyph->metrics.vertBearingX = left;
+ glyph->metrics.vertBearingY = top;
+ glyph->metrics.vertAdvance = advance;
+ }
+
+ /* adjust advance width to the value contained in the hdmx table */
+ if ( !face->postscript.isFixedPitch && size &&
+ IS_HINTED( loader->load_flags ) )
+ {
+ FT_Byte* widths = Get_Advance_Widths( face,
+ size->root.metrics.x_ppem );
+
+
+ if ( widths )
+ glyph->metrics.horiAdvance = widths[glyph_index] << 6;
+ }
+
+ /* set glyph dimensions */
+ glyph->metrics.width = bbox.xMax - bbox.xMin;
+ glyph->metrics.height = bbox.yMax - bbox.yMin;
+
+ return 0;
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* TT_Load_Glyph */
+ /* */
+ /* <Description> */
+ /* A function used to load a single glyph within a given glyph slot, */
+ /* for a given size. */
+ /* */
+ /* <Input> */
+ /* glyph :: A handle to a target slot object where the glyph */
+ /* will be loaded. */
+ /* */
+ /* size :: A handle to the source face size at which the glyph */
+ /* must be scaled/loaded. */
+ /* */
+ /* glyph_index :: The index of the glyph in the font file. */
+ /* */
+ /* load_flags :: A flag indicating what to load for this glyph. The */
+ /* FT_LOAD_XXX constants can be used to control the */
+ /* glyph loading process (e.g., whether the outline */
+ /* should be scaled, whether to load bitmaps or not, */
+ /* whether to hint the outline, etc). */
+ /* */
+ /* <Return> */
+ /* FreeType error code. 0 means success. */
+ /* */
+ FT_LOCAL_DEF( FT_Error )
+ TT_Load_Glyph( TT_Size size,
+ TT_GlyphSlot glyph,
+ FT_UShort glyph_index,
+ FT_Int32 load_flags )
+ {
+ SFNT_Service sfnt;
+ TT_Face face;
+ FT_Stream stream;
+ FT_Error error;
+ TT_LoaderRec loader;
+
+
+ face = (TT_Face)glyph->face;
+ sfnt = (SFNT_Service)face->sfnt;
+ stream = face->root.stream;
+ error = 0;
+
+ if ( !size || ( load_flags & FT_LOAD_NO_SCALE ) ||
+ ( load_flags & FT_LOAD_NO_RECURSE ) )
+ {
+ size = NULL;
+ load_flags |= FT_LOAD_NO_SCALE |
+ FT_LOAD_NO_HINTING |
+ FT_LOAD_NO_BITMAP;
+ }
+
+ glyph->num_subglyphs = 0;
+
+#ifdef TT_CONFIG_OPTION_EMBEDDED_BITMAPS
+
+ /* try to load embedded bitmap if any */
+ /* */
+ /* XXX: The convention should be emphasized in */
+ /* the documents because it can be confusing. */
+ if ( size &&
+ size->strike_index != 0xFFFFU &&
+ sfnt->load_sbits &&
+ ( load_flags & FT_LOAD_NO_BITMAP ) == 0 )
+
+ {
+ TT_SBit_MetricsRec metrics;
+
+
+ error = sfnt->load_sbit_image( face,
+ size->strike_index,
+ glyph_index,
+ load_flags,
+ stream,
+ &glyph->bitmap,
+ &metrics );
+ if ( !error )
+ {
+ glyph->outline.n_points = 0;
+ glyph->outline.n_contours = 0;
+
+ glyph->metrics.width = (FT_Pos)metrics.width << 6;
+ glyph->metrics.height = (FT_Pos)metrics.height << 6;
+
+ glyph->metrics.horiBearingX = (FT_Pos)metrics.horiBearingX << 6;
+ glyph->metrics.horiBearingY = (FT_Pos)metrics.horiBearingY << 6;
+ glyph->metrics.horiAdvance = (FT_Pos)metrics.horiAdvance << 6;
+
+ glyph->metrics.vertBearingX = (FT_Pos)metrics.vertBearingX << 6;
+ glyph->metrics.vertBearingY = (FT_Pos)metrics.vertBearingY << 6;
+ glyph->metrics.vertAdvance = (FT_Pos)metrics.vertAdvance << 6;
+
+ glyph->format = FT_GLYPH_FORMAT_BITMAP;
+ if ( load_flags & FT_LOAD_VERTICAL_LAYOUT )
+ {
+ glyph->bitmap_left = metrics.vertBearingX;
+ glyph->bitmap_top = metrics.vertBearingY;
+ }
+ else
+ {
+ glyph->bitmap_left = metrics.horiBearingX;
+ glyph->bitmap_top = metrics.horiBearingY;
+ }
+ return error;
+ }
+ }
+
+#endif /* TT_CONFIG_OPTION_EMBEDDED_BITMAPS */
+
+ /* return immediately if we only want the embedded bitmaps */
+ if ( load_flags & FT_LOAD_SBITS_ONLY )
+ return FT_Err_Invalid_Argument;
+
+ /* seek to the beginning of the glyph table. For Type 42 fonts */
+ /* the table might be accessed from a Postscript stream or something */
+ /* else... */
+
+#ifdef FT_CONFIG_OPTION_INCREMENTAL
+
+ /* Don't look for the glyph table if this is an incremental font. */
+ if ( !face->root.internal->incremental_interface )
+
+#endif
+
+ {
+ error = face->goto_table( face, TTAG_glyf, stream, 0 );
+ if ( error )
+ {
+ FT_ERROR(( "TT_Load_Glyph: could not access glyph table\n" ));
+ goto Exit;
+ }
+ }
+
+ FT_MEM_ZERO( &loader, sizeof ( loader ) );
+
+ /* update the glyph zone bounds */
+ {
+ FT_GlyphLoader gloader = FT_FACE_DRIVER(face)->glyph_loader;
+
+
+ loader.gloader = gloader;
+
+ FT_GlyphLoader_Rewind( gloader );
+
+ tt_prepare_zone( &loader.zone, &gloader->base, 0, 0 );
+ tt_prepare_zone( &loader.base, &gloader->base, 0, 0 );
+ }
+
+#ifdef TT_CONFIG_OPTION_BYTECODE_INTERPRETER
+
+ if ( size )
+ {
+ /* query new execution context */
+ loader.exec = size->debug ? size->context : TT_New_Context( face );
+ if ( !loader.exec )
+ return TT_Err_Could_Not_Find_Context;
+
+ TT_Load_Context( loader.exec, face, size );
+ loader.instructions = loader.exec->glyphIns;
+
+ /* load default graphics state - if needed */
+ if ( size->GS.instruct_control & 2 )
+ loader.exec->GS = tt_default_graphics_state;
+ }
+
+#endif /* TT_CONFIG_OPTION_BYTECODE_INTERPRETER */
+
+ /* clear all outline flags, except the `owner' one */
+ glyph->outline.flags = 0;
+
+ /* let's initialize the rest of our loader now */
+
+ loader.load_flags = load_flags;
+
+ loader.face = (FT_Face)face;
+ loader.size = (FT_Size)size;
+ loader.glyph = (FT_GlyphSlot)glyph;
+ loader.stream = stream;
+
+#ifdef FT_CONFIG_OPTION_INCREMENTAL
+
+ if ( face->root.internal->incremental_interface )
+ loader.glyf_offset = 0;
+ else
+
+#endif
+
+ loader.glyf_offset = FT_STREAM_POS();
+
+#ifdef TT_CONFIG_OPTION_BYTECODE_INTERPRETER
+
+ /* if the cvt program has disabled hinting, the argument */
+ /* is ignored. */
+ if ( size && ( size->GS.instruct_control & 1 ) )
+ loader.load_flags |= FT_LOAD_NO_HINTING;
+
+#endif /* TT_CONFIG_OPTION_BYTECODE_INTERPRETER */
+
+ /* Main loading loop */
+ glyph->format = FT_GLYPH_FORMAT_OUTLINE;
+ glyph->num_subglyphs = 0;
+
+ error = load_truetype_glyph( &loader, glyph_index );
+ if ( !error )
+ compute_glyph_metrics( &loader, glyph_index );
+
+#ifdef TT_CONFIG_OPTION_BYTECODE_INTERPRETER
+
+ if ( !size || !size->debug )
+ TT_Done_Context( loader.exec );
+
+#endif /* TT_CONFIG_OPTION_BYTECODE_INTERPRETER */
+
+ /* Set the `high precision' bit flag. */
+ /* This is _critical_ to get correct output for monochrome */
+ /* TrueType glyphs at all sizes using the bytecode interpreter. */
+ /* */
+ if ( size && size->root.metrics.y_ppem < 24 )
+ glyph->outline.flags |= FT_OUTLINE_HIGH_PRECISION;
+
+ Exit:
+ return error;
+ }
+
+
+/* END */
--- /dev/null
+++ b/libfreetype/ttgload.h
@@ -1,0 +1,55 @@
+/***************************************************************************/
+/* */
+/* ttgload.h */
+/* */
+/* TrueType Glyph Loader (specification). */
+/* */
+/* Copyright 1996-2001, 2002 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+
+#ifndef __TTGLOAD_H__
+#define __TTGLOAD_H__
+
+
+#include <ft2build.h>
+#include "ttobjs.h"
+
+#ifdef TT_CONFIG_OPTION_BYTECODE_INTERPRETER
+#include "ttinterp.h"
+#endif
+
+
+FT_BEGIN_HEADER
+
+
+ FT_LOCAL( void )
+ TT_Get_Metrics( TT_HoriHeader* header,
+ FT_UInt index,
+ FT_Short* bearing,
+ FT_UShort* advance );
+
+ FT_LOCAL( void )
+ TT_Init_Glyph_Loading( TT_Face face );
+
+ FT_LOCAL( FT_Error )
+ TT_Load_Glyph( TT_Size size,
+ TT_GlyphSlot glyph,
+ FT_UShort glyph_index,
+ FT_Int32 load_flags );
+
+
+FT_END_HEADER
+
+#endif /* __TTGLOAD_H__ */
+
+
+/* END */
--- /dev/null
+++ b/libfreetype/ttinterp.c
@@ -1,0 +1,7496 @@
+/***************************************************************************/
+/* */
+/* ttinterp.c */
+/* */
+/* TrueType bytecode interpreter (body). */
+/* */
+/* Copyright 1996-2001, 2002 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+
+#include <ft2build.h>
+#include FT_INTERNAL_DEBUG_H
+#include FT_INTERNAL_CALC_H
+#include FT_TRIGONOMETRY_H
+#include FT_SYSTEM_H
+
+#include "ttinterp.h"
+
+#include "tterrors.h"
+
+
+#ifdef TT_CONFIG_OPTION_BYTECODE_INTERPRETER
+
+
+#define TT_MULFIX FT_MulFix
+#define TT_MULDIV FT_MulDiv
+#define TT_INT64 FT_Int64
+
+ /*************************************************************************/
+ /* */
+ /* The macro FT_COMPONENT is used in trace mode. It is an implicit */
+ /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log */
+ /* messages during execution. */
+ /* */
+#undef FT_COMPONENT
+#define FT_COMPONENT trace_ttinterp
+
+#undef NO_APPLE_PATENT
+#define APPLE_THRESHOLD 0x4000000L
+
+ /*************************************************************************/
+ /* */
+ /* In order to detect infinite loops in the code, we set up a counter */
+ /* within the run loop. A single stroke of interpretation is now */
+ /* limitet to a maximal number of opcodes defined below. */
+ /* */
+#define MAX_RUNNABLE_OPCODES 1000000L
+
+
+ /*************************************************************************/
+ /* */
+ /* There are two kinds of implementations: */
+ /* */
+ /* a. static implementation */
+ /* */
+ /* The current execution context is a static variable, which fields */
+ /* are accessed directly by the interpreter during execution. The */
+ /* context is named `cur'. */
+ /* */
+ /* This version is non-reentrant, of course. */
+ /* */
+ /* b. indirect implementation */
+ /* */
+ /* The current execution context is passed to _each_ function as its */
+ /* first argument, and each field is thus accessed indirectly. */
+ /* */
+ /* This version is fully re-entrant. */
+ /* */
+ /* The idea is that an indirect implementation may be slower to execute */
+ /* on low-end processors that are used in some systems (like 386s or */
+ /* even 486s). */
+ /* */
+ /* As a consequence, the indirect implementation is now the default, as */
+ /* its performance costs can be considered negligible in our context. */
+ /* Note, however, that we kept the same source with macros because: */
+ /* */
+ /* - The code is kept very close in design to the Pascal code used for */
+ /* development. */
+ /* */
+ /* - It's much more readable that way! */
+ /* */
+ /* - It's still open to experimentation and tuning. */
+ /* */
+ /*************************************************************************/
+
+
+#ifndef TT_CONFIG_OPTION_STATIC_INTERPRETER /* indirect implementation */
+
+#define CUR (*exc) /* see ttobjs.h */
+
+#else /* static implementation */
+
+#define CUR cur
+
+ static
+ TT_ExecContextRec cur; /* static exec. context variable */
+
+ /* apparently, we have a _lot_ of direct indexing when accessing */
+ /* the static `cur', which makes the code bigger (due to all the */
+ /* four bytes addresses). */
+
+#endif /* TT_CONFIG_OPTION_STATIC_INTERPRETER */
+
+
+ /*************************************************************************/
+ /* */
+ /* The instruction argument stack. */
+ /* */
+#define INS_ARG EXEC_OP_ FT_Long* args /* see ttobjs.h for EXEC_OP_ */
+
+
+ /*************************************************************************/
+ /* */
+ /* This macro is used whenever `exec' is unused in a function, to avoid */
+ /* stupid warnings from pedantic compilers. */
+ /* */
+#define FT_UNUSED_EXEC FT_UNUSED( CUR )
+
+
+ /*************************************************************************/
+ /* */
+ /* This macro is used whenever `args' is unused in a function, to avoid */
+ /* stupid warnings from pedantic compilers. */
+ /* */
+#define FT_UNUSED_ARG FT_UNUSED_EXEC; FT_UNUSED( args )
+
+
+ /*************************************************************************/
+ /* */
+ /* The following macros hide the use of EXEC_ARG and EXEC_ARG_ to */
+ /* increase readabilty of the code. */
+ /* */
+ /*************************************************************************/
+
+
+#define SKIP_Code() \
+ SkipCode( EXEC_ARG )
+
+#define GET_ShortIns() \
+ GetShortIns( EXEC_ARG )
+
+#define NORMalize( x, y, v ) \
+ Normalize( EXEC_ARG_ x, y, v )
+
+#define SET_SuperRound( scale, flags ) \
+ SetSuperRound( EXEC_ARG_ scale, flags )
+
+#define ROUND_None( d, c ) \
+ Round_None( EXEC_ARG_ d, c )
+
+#define INS_Goto_CodeRange( range, ip ) \
+ Ins_Goto_CodeRange( EXEC_ARG_ range, ip )
+
+#define CUR_Func_project( x, y ) \
+ CUR.func_project( EXEC_ARG_ x, y )
+
+#define CUR_Func_move( z, p, d ) \
+ CUR.func_move( EXEC_ARG_ z, p, d )
+
+#define CUR_Func_dualproj( x, y ) \
+ CUR.func_dualproj( EXEC_ARG_ x, y )
+
+#define CUR_Func_freeProj( x, y ) \
+ CUR.func_freeProj( EXEC_ARG_ x, y )
+
+#define CUR_Func_round( d, c ) \
+ CUR.func_round( EXEC_ARG_ d, c )
+
+#define CUR_Func_read_cvt( index ) \
+ CUR.func_read_cvt( EXEC_ARG_ index )
+
+#define CUR_Func_write_cvt( index, val ) \
+ CUR.func_write_cvt( EXEC_ARG_ index, val )
+
+#define CUR_Func_move_cvt( index, val ) \
+ CUR.func_move_cvt( EXEC_ARG_ index, val )
+
+#define CURRENT_Ratio() \
+ Current_Ratio( EXEC_ARG )
+
+#define CURRENT_Ppem() \
+ Current_Ppem( EXEC_ARG )
+
+#define CUR_Ppem() \
+ Cur_PPEM( EXEC_ARG )
+
+#define INS_SxVTL( a, b, c, d ) \
+ Ins_SxVTL( EXEC_ARG_ a, b, c, d )
+
+#define COMPUTE_Funcs() \
+ Compute_Funcs( EXEC_ARG )
+
+#define COMPUTE_Round( a ) \
+ Compute_Round( EXEC_ARG_ a )
+
+#define COMPUTE_Point_Displacement( a, b, c, d ) \
+ Compute_Point_Displacement( EXEC_ARG_ a, b, c, d )
+
+#define MOVE_Zp2_Point( a, b, c, t ) \
+ Move_Zp2_Point( EXEC_ARG_ a, b, c, t )
+
+
+ /*************************************************************************/
+ /* */
+ /* Instruction dispatch function, as used by the interpreter. */
+ /* */
+ typedef void (*TInstruction_Function)( INS_ARG );
+
+
+ /*************************************************************************/
+ /* */
+ /* A simple bounds-checking macro. */
+ /* */
+#define BOUNDS( x, n ) ( (FT_UInt)(x) >= (FT_UInt)(n) )
+
+
+#undef SUCCESS
+#define SUCCESS 0
+
+#undef FAILURE
+#define FAILURE 1
+
+
+ /*************************************************************************/
+ /* */
+ /* CODERANGE FUNCTIONS */
+ /* */
+ /*************************************************************************/
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* TT_Goto_CodeRange */
+ /* */
+ /* <Description> */
+ /* Switches to a new code range (updates the code related elements in */
+ /* `exec', and `IP'). */
+ /* */
+ /* <Input> */
+ /* range :: The new execution code range. */
+ /* */
+ /* IP :: The new IP in the new code range. */
+ /* */
+ /* <InOut> */
+ /* exec :: The target execution context. */
+ /* */
+ /* <Return> */
+ /* FreeType error code. 0 means success. */
+ /* */
+ FT_LOCAL_DEF( FT_Error )
+ TT_Goto_CodeRange( TT_ExecContext exec,
+ FT_Int range,
+ FT_Long IP )
+ {
+ TT_CodeRange* coderange;
+
+
+ FT_ASSERT( range >= 1 && range <= 3 );
+
+ coderange = &exec->codeRangeTable[range - 1];
+
+ FT_ASSERT( coderange->base != NULL );
+
+ /* NOTE: Because the last instruction of a program may be a CALL */
+ /* which will return to the first byte *after* the code */
+ /* range, we test for IP <= Size instead of IP < Size. */
+ /* */
+ FT_ASSERT( (FT_ULong)IP <= coderange->size );
+
+ exec->code = coderange->base;
+ exec->codeSize = coderange->size;
+ exec->IP = IP;
+ exec->curRange = range;
+
+ return TT_Err_Ok;
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* TT_Set_CodeRange */
+ /* */
+ /* <Description> */
+ /* Sets a code range. */
+ /* */
+ /* <Input> */
+ /* range :: The code range index. */
+ /* */
+ /* base :: The new code base. */
+ /* */
+ /* length :: The range size in bytes. */
+ /* */
+ /* <InOut> */
+ /* exec :: The target execution context. */
+ /* */
+ /* <Return> */
+ /* FreeType error code. 0 means success. */
+ /* */
+ FT_LOCAL_DEF( FT_Error )
+ TT_Set_CodeRange( TT_ExecContext exec,
+ FT_Int range,
+ void* base,
+ FT_Long length )
+ {
+ FT_ASSERT( range >= 1 && range <= 3 );
+
+ exec->codeRangeTable[range - 1].base = (FT_Byte*)base;
+ exec->codeRangeTable[range - 1].size = length;
+
+ return TT_Err_Ok;
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* TT_Clear_CodeRange */
+ /* */
+ /* <Description> */
+ /* Clears a code range. */
+ /* */
+ /* <Input> */
+ /* range :: The code range index. */
+ /* */
+ /* <InOut> */
+ /* exec :: The target execution context. */
+ /* */
+ /* <Return> */
+ /* FreeType error code. 0 means success. */
+ /* */
+ /* <Note> */
+ /* Does not set the Error variable. */
+ /* */
+ FT_LOCAL_DEF( FT_Error )
+ TT_Clear_CodeRange( TT_ExecContext exec,
+ FT_Int range )
+ {
+ FT_ASSERT( range >= 1 && range <= 3 );
+
+ exec->codeRangeTable[range - 1].base = NULL;
+ exec->codeRangeTable[range - 1].size = 0;
+
+ return TT_Err_Ok;
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* EXECUTION CONTEXT ROUTINES */
+ /* */
+ /*************************************************************************/
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* TT_Destroy_Context */
+ /* */
+ /* <Description> */
+ /* Destroys a given context. */
+ /* */
+ /* <Input> */
+ /* exec :: A handle to the target execution context. */
+ /* */
+ /* memory :: A handle to the parent memory object. */
+ /* */
+ /* <Return> */
+ /* FreeType error code. 0 means success. */
+ /* */
+ /* <Note> */
+ /* Only the glyph loader and debugger should call this function. */
+ /* */
+ FT_LOCAL_DEF( FT_Error )
+ TT_Destroy_Context( TT_ExecContext exec,
+ FT_Memory memory )
+ {
+ /* free composite load stack */
+ FT_FREE( exec->loadStack );
+ exec->loadSize = 0;
+
+ /* points zone */
+ exec->maxPoints = 0;
+ exec->maxContours = 0;
+
+ /* free stack */
+ FT_FREE( exec->stack );
+ exec->stackSize = 0;
+
+ /* free call stack */
+ FT_FREE( exec->callStack );
+ exec->callSize = 0;
+ exec->callTop = 0;
+
+ /* free glyph code range */
+ FT_FREE( exec->glyphIns );
+ exec->glyphSize = 0;
+
+ exec->size = NULL;
+ exec->face = NULL;
+
+ FT_FREE( exec );
+ return TT_Err_Ok;
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* Init_Context */
+ /* */
+ /* <Description> */
+ /* Initializes a context object. */
+ /* */
+ /* <Input> */
+ /* memory :: A handle to the parent memory object. */
+ /* */
+ /* face :: A handle to the source TrueType face object. */
+ /* */
+ /* <InOut> */
+ /* exec :: A handle to the target execution context. */
+ /* */
+ /* <Return> */
+ /* FreeType error code. 0 means success. */
+ /* */
+ static FT_Error
+ Init_Context( TT_ExecContext exec,
+ TT_Face face,
+ FT_Memory memory )
+ {
+ FT_Error error;
+
+
+ FT_TRACE1(( "Init_Context: new object at 0x%08p, parent = 0x%08p\n",
+ exec, face ));
+
+ exec->memory = memory;
+ exec->callSize = 32;
+
+ if ( FT_NEW_ARRAY( exec->callStack, exec->callSize ) )
+ goto Fail_Memory;
+
+ /* all values in the context are set to 0 already, but this is */
+ /* here as a remainder */
+ exec->maxPoints = 0;
+ exec->maxContours = 0;
+
+ exec->stackSize = 0;
+ exec->loadSize = 0;
+ exec->glyphSize = 0;
+
+ exec->stack = NULL;
+ exec->loadStack = NULL;
+ exec->glyphIns = NULL;
+
+ exec->face = face;
+ exec->size = NULL;
+
+ return TT_Err_Ok;
+
+ Fail_Memory:
+ FT_ERROR(( "Init_Context: not enough memory for 0x%08lx\n",
+ (FT_Long)exec ));
+ TT_Destroy_Context( exec, memory );
+
+ return error;
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* Update_Max */
+ /* */
+ /* <Description> */
+ /* Checks the size of a buffer and reallocates it if necessary. */
+ /* */
+ /* <Input> */
+ /* memory :: A handle to the parent memory object. */
+ /* */
+ /* multiplier :: The size in bytes of each element in the buffer. */
+ /* */
+ /* new_max :: The new capacity (size) of the buffer. */
+ /* */
+ /* <InOut> */
+ /* size :: The address of the buffer's current size expressed */
+ /* in elements. */
+ /* */
+ /* buff :: The address of the buffer base pointer. */
+ /* */
+ /* <Return> */
+ /* FreeType error code. 0 means success. */
+ /* */
+ static FT_Error
+ Update_Max( FT_Memory memory,
+ FT_ULong* size,
+ FT_Long multiplier,
+ void** buff,
+ FT_ULong new_max )
+ {
+ FT_Error error;
+
+
+ if ( *size < new_max )
+ {
+ FT_FREE( *buff );
+ if ( FT_ALLOC( *buff, new_max * multiplier ) )
+ return error;
+ *size = new_max;
+ }
+
+ return TT_Err_Ok;
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* TT_Load_Context */
+ /* */
+ /* <Description> */
+ /* Prepare an execution context for glyph hinting. */
+ /* */
+ /* <Input> */
+ /* face :: A handle to the source face object. */
+ /* */
+ /* size :: A handle to the source size object. */
+ /* */
+ /* <InOut> */
+ /* exec :: A handle to the target execution context. */
+ /* */
+ /* <Return> */
+ /* FreeType error code. 0 means success. */
+ /* */
+ /* <Note> */
+ /* Only the glyph loader and debugger should call this function. */
+ /* */
+ FT_LOCAL_DEF( FT_Error )
+ TT_Load_Context( TT_ExecContext exec,
+ TT_Face face,
+ TT_Size size )
+ {
+ FT_Int i;
+ FT_ULong tmp;
+ TT_MaxProfile* maxp;
+ FT_Error error;
+
+
+ exec->face = face;
+ maxp = &face->max_profile;
+ exec->size = size;
+
+ if ( size )
+ {
+ exec->numFDefs = size->num_function_defs;
+ exec->maxFDefs = size->max_function_defs;
+ exec->numIDefs = size->num_instruction_defs;
+ exec->maxIDefs = size->max_instruction_defs;
+ exec->FDefs = size->function_defs;
+ exec->IDefs = size->instruction_defs;
+ exec->tt_metrics = size->ttmetrics;
+ exec->metrics = size->root.metrics;
+
+ exec->maxFunc = size->max_func;
+ exec->maxIns = size->max_ins;
+
+ for ( i = 0; i < TT_MAX_CODE_RANGES; i++ )
+ exec->codeRangeTable[i] = size->codeRangeTable[i];
+
+ /* set graphics state */
+ exec->GS = size->GS;
+
+ exec->cvtSize = size->cvt_size;
+ exec->cvt = size->cvt;
+
+ exec->storeSize = size->storage_size;
+ exec->storage = size->storage;
+
+ exec->twilight = size->twilight;
+ }
+
+ error = Update_Max( exec->memory,
+ &exec->loadSize,
+ sizeof ( TT_SubGlyphRec ),
+ (void**)&exec->loadStack,
+ exec->face->max_components + 1 );
+ if ( error )
+ return error;
+
+ /* XXX: We reserve a little more elements on the stack to deal safely */
+ /* with broken fonts like arialbs, courbs, timesbs, etc. */
+ tmp = exec->stackSize;
+ error = Update_Max( exec->memory,
+ &tmp,
+ sizeof ( FT_F26Dot6 ),
+ (void**)&exec->stack,
+ maxp->maxStackElements + 32 );
+ exec->stackSize = (FT_UInt)tmp;
+ if ( error )
+ return error;
+
+ tmp = exec->glyphSize;
+ error = Update_Max( exec->memory,
+ &tmp,
+ sizeof ( FT_Byte ),
+ (void**)&exec->glyphIns,
+ maxp->maxSizeOfInstructions );
+ exec->glyphSize = (FT_UShort)tmp;
+ if ( error )
+ return error;
+
+ exec->pts.n_points = 0;
+ exec->pts.n_contours = 0;
+
+ exec->instruction_trap = FALSE;
+
+ return TT_Err_Ok;
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* TT_Save_Context */
+ /* */
+ /* <Description> */
+ /* Saves the code ranges in a `size' object. */
+ /* */
+ /* <Input> */
+ /* exec :: A handle to the source execution context. */
+ /* */
+ /* <InOut> */
+ /* size :: A handle to the target size object. */
+ /* */
+ /* <Return> */
+ /* FreeType error code. 0 means success. */
+ /* */
+ /* <Note> */
+ /* Only the glyph loader and debugger should call this function. */
+ /* */
+ FT_LOCAL_DEF( FT_Error )
+ TT_Save_Context( TT_ExecContext exec,
+ TT_Size size )
+ {
+ FT_Int i;
+
+
+ /* XXXX: Will probably disappear soon with all the code range */
+ /* management, which is now rather obsolete. */
+ /* */
+ size->num_function_defs = exec->numFDefs;
+ size->num_instruction_defs = exec->numIDefs;
+
+ size->max_func = exec->maxFunc;
+ size->max_ins = exec->maxIns;
+
+ for ( i = 0; i < TT_MAX_CODE_RANGES; i++ )
+ size->codeRangeTable[i] = exec->codeRangeTable[i];
+
+ return TT_Err_Ok;
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* TT_Run_Context */
+ /* */
+ /* <Description> */
+ /* Executes one or more instructions in the execution context. */
+ /* */
+ /* <Input> */
+ /* debug :: A Boolean flag. If set, the function sets some internal */
+ /* variables and returns immediately, otherwise TT_RunIns() */
+ /* is called. */
+ /* */
+ /* This is commented out currently. */
+ /* */
+ /* <Input> */
+ /* exec :: A handle to the target execution context. */
+ /* */
+ /* <Return> */
+ /* TrueTyoe error code. 0 means success. */
+ /* */
+ /* <Note> */
+ /* Only the glyph loader and debugger should call this function. */
+ /* */
+ FT_LOCAL_DEF( FT_Error )
+ TT_Run_Context( TT_ExecContext exec,
+ FT_Bool debug )
+ {
+ FT_Error error;
+
+
+ if ( ( error = TT_Goto_CodeRange( exec, tt_coderange_glyph, 0 ) )
+ != TT_Err_Ok )
+ return error;
+
+ exec->zp0 = exec->pts;
+ exec->zp1 = exec->pts;
+ exec->zp2 = exec->pts;
+
+ exec->GS.gep0 = 1;
+ exec->GS.gep1 = 1;
+ exec->GS.gep2 = 1;
+
+ exec->GS.projVector.x = 0x4000;
+ exec->GS.projVector.y = 0x0000;
+
+ exec->GS.freeVector = exec->GS.projVector;
+ exec->GS.dualVector = exec->GS.projVector;
+
+ exec->GS.round_state = 1;
+ exec->GS.loop = 1;
+
+ /* some glyphs leave something on the stack. so we clean it */
+ /* before a new execution. */
+ exec->top = 0;
+ exec->callTop = 0;
+
+#if 1
+ FT_UNUSED( debug );
+
+ return exec->face->interpreter( exec );
+#else
+ if ( !debug )
+ return TT_RunIns( exec );
+ else
+ return TT_Err_Ok;
+#endif
+ }
+
+
+ const TT_GraphicsState tt_default_graphics_state =
+ {
+ 0, 0, 0,
+ { 0x4000, 0 },
+ { 0x4000, 0 },
+ { 0x4000, 0 },
+ 1, 64, 1,
+ TRUE, 68, 0, 0, 9, 3,
+ 0, FALSE, 2, 1, 1, 1
+ };
+
+
+ /* documentation is in ttinterp.h */
+
+ FT_EXPORT_DEF( TT_ExecContext )
+ TT_New_Context( TT_Face face )
+ {
+ TT_Driver driver;
+ TT_ExecContext exec;
+ FT_Memory memory;
+
+
+ if ( !face )
+ return 0;
+
+ driver = (TT_Driver)face->root.driver;
+
+ memory = driver->root.root.memory;
+ exec = driver->context;
+
+ if ( !driver->context )
+ {
+ FT_Error error;
+
+
+ /* allocate object */
+ if ( FT_NEW( exec ) )
+ goto Exit;
+
+ /* initialize it */
+ error = Init_Context( exec, face, memory );
+ if ( error )
+ goto Fail;
+
+ /* store it into the driver */
+ driver->context = exec;
+ }
+
+ Exit:
+ return driver->context;
+
+ Fail:
+ FT_FREE( exec );
+
+ return 0;
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* TT_Done_Context */
+ /* */
+ /* <Description> */
+ /* Discards an execution context. */
+ /* */
+ /* <Input> */
+ /* exec :: A handle to the target execution context. */
+ /* */
+ /* <Return> */
+ /* FreeType error code. 0 means success. */
+ /* */
+ /* <Note> */
+ /* Only the glyph loader and debugger should call this function. */
+ /* */
+ FT_LOCAL_DEF( FT_Error )
+ TT_Done_Context( TT_ExecContext exec )
+ {
+ /* Nothing at all for now */
+ FT_UNUSED( exec );
+
+ return TT_Err_Ok;
+ }
+
+
+
+ /*************************************************************************/
+ /* */
+ /* Before an opcode is executed, the interpreter verifies that there are */
+ /* enough arguments on the stack, with the help of the Pop_Push_Count */
+ /* table. */
+ /* */
+ /* For each opcode, the first column gives the number of arguments that */
+ /* are popped from the stack; the second one gives the number of those */
+ /* that are pushed in result. */
+ /* */
+ /* Note that for opcodes with a varying number of parameters, either 0 */
+ /* or 1 arg is verified before execution, depending on the nature of the */
+ /* instruction: */
+ /* */
+ /* - if the number of arguments is given by the bytecode stream or the */
+ /* loop variable, 0 is chosen. */
+ /* */
+ /* - if the first argument is a count n that is followed by arguments */
+ /* a1 .. an, then 1 is chosen. */
+ /* */
+ /*************************************************************************/
+
+
+#undef PACK
+#define PACK( x, y ) ( ( x << 4 ) | y )
+
+
+ static
+ const FT_Byte Pop_Push_Count[256] =
+ {
+ /* opcodes are gathered in groups of 16 */
+ /* please keep the spaces as they are */
+
+ /* SVTCA y */ PACK( 0, 0 ),
+ /* SVTCA x */ PACK( 0, 0 ),
+ /* SPvTCA y */ PACK( 0, 0 ),
+ /* SPvTCA x */ PACK( 0, 0 ),
+ /* SFvTCA y */ PACK( 0, 0 ),
+ /* SFvTCA x */ PACK( 0, 0 ),
+ /* SPvTL // */ PACK( 2, 0 ),
+ /* SPvTL + */ PACK( 2, 0 ),
+ /* SFvTL // */ PACK( 2, 0 ),
+ /* SFvTL + */ PACK( 2, 0 ),
+ /* SPvFS */ PACK( 2, 0 ),
+ /* SFvFS */ PACK( 2, 0 ),
+ /* GPV */ PACK( 0, 2 ),
+ /* GFV */ PACK( 0, 2 ),
+ /* SFvTPv */ PACK( 0, 0 ),
+ /* ISECT */ PACK( 5, 0 ),
+
+ /* SRP0 */ PACK( 1, 0 ),
+ /* SRP1 */ PACK( 1, 0 ),
+ /* SRP2 */ PACK( 1, 0 ),
+ /* SZP0 */ PACK( 1, 0 ),
+ /* SZP1 */ PACK( 1, 0 ),
+ /* SZP2 */ PACK( 1, 0 ),
+ /* SZPS */ PACK( 1, 0 ),
+ /* SLOOP */ PACK( 1, 0 ),
+ /* RTG */ PACK( 0, 0 ),
+ /* RTHG */ PACK( 0, 0 ),
+ /* SMD */ PACK( 1, 0 ),
+ /* ELSE */ PACK( 0, 0 ),
+ /* JMPR */ PACK( 1, 0 ),
+ /* SCvTCi */ PACK( 1, 0 ),
+ /* SSwCi */ PACK( 1, 0 ),
+ /* SSW */ PACK( 1, 0 ),
+
+ /* DUP */ PACK( 1, 2 ),
+ /* POP */ PACK( 1, 0 ),
+ /* CLEAR */ PACK( 0, 0 ),
+ /* SWAP */ PACK( 2, 2 ),
+ /* DEPTH */ PACK( 0, 1 ),
+ /* CINDEX */ PACK( 1, 1 ),
+ /* MINDEX */ PACK( 1, 0 ),
+ /* AlignPTS */ PACK( 2, 0 ),
+ /* INS_$28 */ PACK( 0, 0 ),
+ /* UTP */ PACK( 1, 0 ),
+ /* LOOPCALL */ PACK( 2, 0 ),
+ /* CALL */ PACK( 1, 0 ),
+ /* FDEF */ PACK( 1, 0 ),
+ /* ENDF */ PACK( 0, 0 ),
+ /* MDAP[0] */ PACK( 1, 0 ),
+ /* MDAP[1] */ PACK( 1, 0 ),
+
+ /* IUP[0] */ PACK( 0, 0 ),
+ /* IUP[1] */ PACK( 0, 0 ),
+ /* SHP[0] */ PACK( 0, 0 ),
+ /* SHP[1] */ PACK( 0, 0 ),
+ /* SHC[0] */ PACK( 1, 0 ),
+ /* SHC[1] */ PACK( 1, 0 ),
+ /* SHZ[0] */ PACK( 1, 0 ),
+ /* SHZ[1] */ PACK( 1, 0 ),
+ /* SHPIX */ PACK( 1, 0 ),
+ /* IP */ PACK( 0, 0 ),
+ /* MSIRP[0] */ PACK( 2, 0 ),
+ /* MSIRP[1] */ PACK( 2, 0 ),
+ /* AlignRP */ PACK( 0, 0 ),
+ /* RTDG */ PACK( 0, 0 ),
+ /* MIAP[0] */ PACK( 2, 0 ),
+ /* MIAP[1] */ PACK( 2, 0 ),
+
+ /* NPushB */ PACK( 0, 0 ),
+ /* NPushW */ PACK( 0, 0 ),
+ /* WS */ PACK( 2, 0 ),
+ /* RS */ PACK( 1, 1 ),
+ /* WCvtP */ PACK( 2, 0 ),
+ /* RCvt */ PACK( 1, 1 ),
+ /* GC[0] */ PACK( 1, 1 ),
+ /* GC[1] */ PACK( 1, 1 ),
+ /* SCFS */ PACK( 2, 0 ),
+ /* MD[0] */ PACK( 2, 1 ),
+ /* MD[1] */ PACK( 2, 1 ),
+ /* MPPEM */ PACK( 0, 1 ),
+ /* MPS */ PACK( 0, 1 ),
+ /* FlipON */ PACK( 0, 0 ),
+ /* FlipOFF */ PACK( 0, 0 ),
+ /* DEBUG */ PACK( 1, 0 ),
+
+ /* LT */ PACK( 2, 1 ),
+ /* LTEQ */ PACK( 2, 1 ),
+ /* GT */ PACK( 2, 1 ),
+ /* GTEQ */ PACK( 2, 1 ),
+ /* EQ */ PACK( 2, 1 ),
+ /* NEQ */ PACK( 2, 1 ),
+ /* ODD */ PACK( 1, 1 ),
+ /* EVEN */ PACK( 1, 1 ),
+ /* IF */ PACK( 1, 0 ),
+ /* EIF */ PACK( 0, 0 ),
+ /* AND */ PACK( 2, 1 ),
+ /* OR */ PACK( 2, 1 ),
+ /* NOT */ PACK( 1, 1 ),
+ /* DeltaP1 */ PACK( 1, 0 ),
+ /* SDB */ PACK( 1, 0 ),
+ /* SDS */ PACK( 1, 0 ),
+
+ /* ADD */ PACK( 2, 1 ),
+ /* SUB */ PACK( 2, 1 ),
+ /* DIV */ PACK( 2, 1 ),
+ /* MUL */ PACK( 2, 1 ),
+ /* ABS */ PACK( 1, 1 ),
+ /* NEG */ PACK( 1, 1 ),
+ /* FLOOR */ PACK( 1, 1 ),
+ /* CEILING */ PACK( 1, 1 ),
+ /* ROUND[0] */ PACK( 1, 1 ),
+ /* ROUND[1] */ PACK( 1, 1 ),
+ /* ROUND[2] */ PACK( 1, 1 ),
+ /* ROUND[3] */ PACK( 1, 1 ),
+ /* NROUND[0] */ PACK( 1, 1 ),
+ /* NROUND[1] */ PACK( 1, 1 ),
+ /* NROUND[2] */ PACK( 1, 1 ),
+ /* NROUND[3] */ PACK( 1, 1 ),
+
+ /* WCvtF */ PACK( 2, 0 ),
+ /* DeltaP2 */ PACK( 1, 0 ),
+ /* DeltaP3 */ PACK( 1, 0 ),
+ /* DeltaCn[0] */ PACK( 1, 0 ),
+ /* DeltaCn[1] */ PACK( 1, 0 ),
+ /* DeltaCn[2] */ PACK( 1, 0 ),
+ /* SROUND */ PACK( 1, 0 ),
+ /* S45Round */ PACK( 1, 0 ),
+ /* JROT */ PACK( 2, 0 ),
+ /* JROF */ PACK( 2, 0 ),
+ /* ROFF */ PACK( 0, 0 ),
+ /* INS_$7B */ PACK( 0, 0 ),
+ /* RUTG */ PACK( 0, 0 ),
+ /* RDTG */ PACK( 0, 0 ),
+ /* SANGW */ PACK( 1, 0 ),
+ /* AA */ PACK( 1, 0 ),
+
+ /* FlipPT */ PACK( 0, 0 ),
+ /* FlipRgON */ PACK( 2, 0 ),
+ /* FlipRgOFF */ PACK( 2, 0 ),
+ /* INS_$83 */ PACK( 0, 0 ),
+ /* INS_$84 */ PACK( 0, 0 ),
+ /* ScanCTRL */ PACK( 1, 0 ),
+ /* SDVPTL[0] */ PACK( 2, 0 ),
+ /* SDVPTL[1] */ PACK( 2, 0 ),
+ /* GetINFO */ PACK( 1, 1 ),
+ /* IDEF */ PACK( 1, 0 ),
+ /* ROLL */ PACK( 3, 3 ),
+ /* MAX */ PACK( 2, 1 ),
+ /* MIN */ PACK( 2, 1 ),
+ /* ScanTYPE */ PACK( 1, 0 ),
+ /* InstCTRL */ PACK( 2, 0 ),
+ /* INS_$8F */ PACK( 0, 0 ),
+
+ /* INS_$90 */ PACK( 0, 0 ),
+ /* INS_$91 */ PACK( 0, 0 ),
+ /* INS_$92 */ PACK( 0, 0 ),
+ /* INS_$93 */ PACK( 0, 0 ),
+ /* INS_$94 */ PACK( 0, 0 ),
+ /* INS_$95 */ PACK( 0, 0 ),
+ /* INS_$96 */ PACK( 0, 0 ),
+ /* INS_$97 */ PACK( 0, 0 ),
+ /* INS_$98 */ PACK( 0, 0 ),
+ /* INS_$99 */ PACK( 0, 0 ),
+ /* INS_$9A */ PACK( 0, 0 ),
+ /* INS_$9B */ PACK( 0, 0 ),
+ /* INS_$9C */ PACK( 0, 0 ),
+ /* INS_$9D */ PACK( 0, 0 ),
+ /* INS_$9E */ PACK( 0, 0 ),
+ /* INS_$9F */ PACK( 0, 0 ),
+
+ /* INS_$A0 */ PACK( 0, 0 ),
+ /* INS_$A1 */ PACK( 0, 0 ),
+ /* INS_$A2 */ PACK( 0, 0 ),
+ /* INS_$A3 */ PACK( 0, 0 ),
+ /* INS_$A4 */ PACK( 0, 0 ),
+ /* INS_$A5 */ PACK( 0, 0 ),
+ /* INS_$A6 */ PACK( 0, 0 ),
+ /* INS_$A7 */ PACK( 0, 0 ),
+ /* INS_$A8 */ PACK( 0, 0 ),
+ /* INS_$A9 */ PACK( 0, 0 ),
+ /* INS_$AA */ PACK( 0, 0 ),
+ /* INS_$AB */ PACK( 0, 0 ),
+ /* INS_$AC */ PACK( 0, 0 ),
+ /* INS_$AD */ PACK( 0, 0 ),
+ /* INS_$AE */ PACK( 0, 0 ),
+ /* INS_$AF */ PACK( 0, 0 ),
+
+ /* PushB[0] */ PACK( 0, 1 ),
+ /* PushB[1] */ PACK( 0, 2 ),
+ /* PushB[2] */ PACK( 0, 3 ),
+ /* PushB[3] */ PACK( 0, 4 ),
+ /* PushB[4] */ PACK( 0, 5 ),
+ /* PushB[5] */ PACK( 0, 6 ),
+ /* PushB[6] */ PACK( 0, 7 ),
+ /* PushB[7] */ PACK( 0, 8 ),
+ /* PushW[0] */ PACK( 0, 1 ),
+ /* PushW[1] */ PACK( 0, 2 ),
+ /* PushW[2] */ PACK( 0, 3 ),
+ /* PushW[3] */ PACK( 0, 4 ),
+ /* PushW[4] */ PACK( 0, 5 ),
+ /* PushW[5] */ PACK( 0, 6 ),
+ /* PushW[6] */ PACK( 0, 7 ),
+ /* PushW[7] */ PACK( 0, 8 ),
+
+ /* MDRP[00] */ PACK( 1, 0 ),
+ /* MDRP[01] */ PACK( 1, 0 ),
+ /* MDRP[02] */ PACK( 1, 0 ),
+ /* MDRP[03] */ PACK( 1, 0 ),
+ /* MDRP[04] */ PACK( 1, 0 ),
+ /* MDRP[05] */ PACK( 1, 0 ),
+ /* MDRP[06] */ PACK( 1, 0 ),
+ /* MDRP[07] */ PACK( 1, 0 ),
+ /* MDRP[08] */ PACK( 1, 0 ),
+ /* MDRP[09] */ PACK( 1, 0 ),
+ /* MDRP[10] */ PACK( 1, 0 ),
+ /* MDRP[11] */ PACK( 1, 0 ),
+ /* MDRP[12] */ PACK( 1, 0 ),
+ /* MDRP[13] */ PACK( 1, 0 ),
+ /* MDRP[14] */ PACK( 1, 0 ),
+ /* MDRP[15] */ PACK( 1, 0 ),
+
+ /* MDRP[16] */ PACK( 1, 0 ),
+ /* MDRP[17] */ PACK( 1, 0 ),
+ /* MDRP[18] */ PACK( 1, 0 ),
+ /* MDRP[19] */ PACK( 1, 0 ),
+ /* MDRP[20] */ PACK( 1, 0 ),
+ /* MDRP[21] */ PACK( 1, 0 ),
+ /* MDRP[22] */ PACK( 1, 0 ),
+ /* MDRP[23] */ PACK( 1, 0 ),
+ /* MDRP[24] */ PACK( 1, 0 ),
+ /* MDRP[25] */ PACK( 1, 0 ),
+ /* MDRP[26] */ PACK( 1, 0 ),
+ /* MDRP[27] */ PACK( 1, 0 ),
+ /* MDRP[28] */ PACK( 1, 0 ),
+ /* MDRP[29] */ PACK( 1, 0 ),
+ /* MDRP[30] */ PACK( 1, 0 ),
+ /* MDRP[31] */ PACK( 1, 0 ),
+
+ /* MIRP[00] */ PACK( 2, 0 ),
+ /* MIRP[01] */ PACK( 2, 0 ),
+ /* MIRP[02] */ PACK( 2, 0 ),
+ /* MIRP[03] */ PACK( 2, 0 ),
+ /* MIRP[04] */ PACK( 2, 0 ),
+ /* MIRP[05] */ PACK( 2, 0 ),
+ /* MIRP[06] */ PACK( 2, 0 ),
+ /* MIRP[07] */ PACK( 2, 0 ),
+ /* MIRP[08] */ PACK( 2, 0 ),
+ /* MIRP[09] */ PACK( 2, 0 ),
+ /* MIRP[10] */ PACK( 2, 0 ),
+ /* MIRP[11] */ PACK( 2, 0 ),
+ /* MIRP[12] */ PACK( 2, 0 ),
+ /* MIRP[13] */ PACK( 2, 0 ),
+ /* MIRP[14] */ PACK( 2, 0 ),
+ /* MIRP[15] */ PACK( 2, 0 ),
+
+ /* MIRP[16] */ PACK( 2, 0 ),
+ /* MIRP[17] */ PACK( 2, 0 ),
+ /* MIRP[18] */ PACK( 2, 0 ),
+ /* MIRP[19] */ PACK( 2, 0 ),
+ /* MIRP[20] */ PACK( 2, 0 ),
+ /* MIRP[21] */ PACK( 2, 0 ),
+ /* MIRP[22] */ PACK( 2, 0 ),
+ /* MIRP[23] */ PACK( 2, 0 ),
+ /* MIRP[24] */ PACK( 2, 0 ),
+ /* MIRP[25] */ PACK( 2, 0 ),
+ /* MIRP[26] */ PACK( 2, 0 ),
+ /* MIRP[27] */ PACK( 2, 0 ),
+ /* MIRP[28] */ PACK( 2, 0 ),
+ /* MIRP[29] */ PACK( 2, 0 ),
+ /* MIRP[30] */ PACK( 2, 0 ),
+ /* MIRP[31] */ PACK( 2, 0 )
+ };
+
+
+ static
+ const FT_Char opcode_length[256] =
+ {
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+
+ -1,-1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 2, 3, 4, 5, 6, 7, 8, 9, 3, 5, 7, 9, 11,13,15,17,
+
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1
+ };
+
+ static
+ const FT_Vector Null_Vector = {0,0};
+
+
+#undef PACK
+
+
+#undef NULL_Vector
+#define NULL_Vector (FT_Vector*)&Null_Vector
+
+
+ /* compute (a*b)/2^14 with maximal accuracy and rounding */
+ static FT_Int32
+ TT_MulFix14( FT_Int32 a,
+ FT_Int b )
+ {
+ FT_Int32 m, s, hi;
+ FT_UInt32 l, lo;
+
+
+ /* compute ax*bx as 64-bit value */
+ l = (FT_UInt32)( ( a & 0xFFFFU ) * b );
+ m = ( a >> 16 ) * b;
+
+ lo = l + (FT_UInt32)( m << 16 );
+ hi = ( m >> 16 ) + ( (FT_Int32)l >> 31 ) + ( lo < l );
+
+ /* divide the result by 2^14 with rounding */
+ s = hi >> 31;
+ l = lo + (FT_UInt32)s;
+ hi += s + ( l < lo );
+ lo = l;
+
+ l = lo + 0x2000U;
+ hi += (l < lo);
+
+ return ( hi << 18 ) | ( l >> 14 );
+ }
+
+
+ /* compute (ax*bx+ay*by)/2^14 with maximal accuracy and rounding */
+ static FT_Int32
+ TT_DotFix14( FT_Int32 ax,
+ FT_Int32 ay,
+ FT_Int bx,
+ FT_Int by )
+ {
+ FT_Int32 m, s, hi1, hi2, hi;
+ FT_UInt32 l, lo1, lo2, lo;
+
+
+ /* compute ax*bx as 64-bit value */
+ l = (FT_UInt32)( ( ax & 0xFFFFU ) * bx );
+ m = ( ax >> 16 ) * bx;
+
+ lo1 = l + (FT_UInt32)( m << 16 );
+ hi1 = ( m >> 16 ) + ( (FT_Int32)l >> 31 ) + ( lo1 < l );
+
+ /* compute ay*by as 64-bit value */
+ l = (FT_UInt32)( ( ay & 0xFFFFU ) * by );
+ m = ( ay >> 16 ) * by;
+
+ lo2 = l + (FT_UInt32)( m << 16 );
+ hi2 = ( m >> 16 ) + ( (FT_Int32)l >> 31 ) + ( lo2 < l );
+
+ /* add them */
+ lo = lo1 + lo2;
+ hi = hi1 + hi2 + ( lo < lo1 );
+
+ /* divide the result by 2^14 with rounding */
+ s = hi >> 31;
+ l = lo + (FT_UInt32)s;
+ hi += s + ( l < lo );
+ lo = l;
+
+ l = lo + 0x2000U;
+ hi += ( l < lo );
+
+ return ( hi << 18 ) | ( l >> 14 );
+ }
+
+
+ /* return length of given vector */
+
+#if 0
+
+ static FT_Int32
+ TT_VecLen( FT_Int32 x,
+ FT_Int32 y )
+ {
+ FT_Int32 m, hi1, hi2, hi;
+ FT_UInt32 l, lo1, lo2, lo;
+
+
+ /* compute x*x as 64-bit value */
+ lo = (FT_UInt32)( x & 0xFFFFU );
+ hi = x >> 16;
+
+ l = lo * lo;
+ m = hi * lo;
+ hi = hi * hi;
+
+ lo1 = l + (FT_UInt32)( m << 17 );
+ hi1 = hi + ( m >> 15 ) + ( lo1 < l );
+
+ /* compute y*y as 64-bit value */
+ lo = (FT_UInt32)( y & 0xFFFFU );
+ hi = y >> 16;
+
+ l = lo * lo;
+ m = hi * lo;
+ hi = hi * hi;
+
+ lo2 = l + (FT_UInt32)( m << 17 );
+ hi2 = hi + ( m >> 15 ) + ( lo2 < l );
+
+ /* add them to get 'x*x+y*y' as 64-bit value */
+ lo = lo1 + lo2;
+ hi = hi1 + hi2 + ( lo < lo1 );
+
+ /* compute the square root of this value */
+ {
+ FT_UInt32 root, rem, test_div;
+ FT_Int count;
+
+
+ root = 0;
+
+ {
+ rem = 0;
+ count = 32;
+ do
+ {
+ rem = ( rem << 2 ) | ( (FT_UInt32)hi >> 30 );
+ hi = ( hi << 2 ) | ( lo >> 30 );
+ lo <<= 2;
+ root <<= 1;
+ test_div = ( root << 1 ) + 1;
+
+ if ( rem >= test_div )
+ {
+ rem -= test_div;
+ root += 1;
+ }
+ } while ( --count );
+ }
+
+ return (FT_Int32)root;
+ }
+ }
+
+#else
+
+ /* this version uses FT_Vector_Length which computes the same value */
+ /* much, much faster.. */
+ /* */
+ static FT_F26Dot6
+ TT_VecLen( FT_F26Dot6 X,
+ FT_F26Dot6 Y )
+ {
+ FT_Vector v;
+
+
+ v.x = X;
+ v.y = Y;
+
+ return FT_Vector_Length( &v );
+ }
+
+#endif
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* Current_Ratio */
+ /* */
+ /* <Description> */
+ /* Returns the current aspect ratio scaling factor depending on the */
+ /* projection vector's state and device resolutions. */
+ /* */
+ /* <Return> */
+ /* The aspect ratio in 16.16 format, always <= 1.0 . */
+ /* */
+ static FT_Long
+ Current_Ratio( EXEC_OP )
+ {
+ if ( CUR.tt_metrics.ratio )
+ return CUR.tt_metrics.ratio;
+
+ if ( CUR.GS.projVector.y == 0 )
+ CUR.tt_metrics.ratio = CUR.tt_metrics.x_ratio;
+
+ else if ( CUR.GS.projVector.x == 0 )
+ CUR.tt_metrics.ratio = CUR.tt_metrics.y_ratio;
+
+ else
+ {
+ FT_Long x, y;
+
+ x = TT_MULDIV( CUR.GS.projVector.x, CUR.tt_metrics.x_ratio, 0x4000 );
+ y = TT_MULDIV( CUR.GS.projVector.y, CUR.tt_metrics.y_ratio, 0x4000 );
+ CUR.tt_metrics.ratio = TT_VecLen( x, y );
+ }
+
+ return CUR.tt_metrics.ratio;
+ }
+
+
+ static FT_Long
+ Current_Ppem( EXEC_OP )
+ {
+ return TT_MULFIX( CUR.tt_metrics.ppem, CURRENT_Ratio() );
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* Functions related to the control value table (CVT). */
+ /* */
+ /*************************************************************************/
+
+
+ FT_CALLBACK_DEF( FT_F26Dot6 )
+ Read_CVT( EXEC_OP_ FT_ULong idx )
+ {
+ return CUR.cvt[idx];
+ }
+
+
+ FT_CALLBACK_DEF( FT_F26Dot6 )
+ Read_CVT_Stretched( EXEC_OP_ FT_ULong idx )
+ {
+ return TT_MULFIX( CUR.cvt[idx], CURRENT_Ratio() );
+ }
+
+
+ FT_CALLBACK_DEF( void )
+ Write_CVT( EXEC_OP_ FT_ULong idx,
+ FT_F26Dot6 value )
+ {
+ CUR.cvt[idx] = value;
+ }
+
+
+ FT_CALLBACK_DEF( void )
+ Write_CVT_Stretched( EXEC_OP_ FT_ULong idx,
+ FT_F26Dot6 value )
+ {
+ CUR.cvt[idx] = FT_DivFix( value, CURRENT_Ratio() );
+ }
+
+
+ FT_CALLBACK_DEF( void )
+ Move_CVT( EXEC_OP_ FT_ULong idx,
+ FT_F26Dot6 value )
+ {
+ CUR.cvt[idx] += value;
+ }
+
+
+ FT_CALLBACK_DEF( void )
+ Move_CVT_Stretched( EXEC_OP_ FT_ULong idx,
+ FT_F26Dot6 value )
+ {
+ CUR.cvt[idx] += FT_DivFix( value, CURRENT_Ratio() );
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* GetShortIns */
+ /* */
+ /* <Description> */
+ /* Returns a short integer taken from the instruction stream at */
+ /* address IP. */
+ /* */
+ /* <Return> */
+ /* Short read at code[IP]. */
+ /* */
+ /* <Note> */
+ /* This one could become a macro. */
+ /* */
+ static FT_Short
+ GetShortIns( EXEC_OP )
+ {
+ /* Reading a byte stream so there is no endianess (DaveP) */
+ CUR.IP += 2;
+ return (FT_Short)( ( CUR.code[CUR.IP - 2] << 8 ) +
+ CUR.code[CUR.IP - 1] );
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* Ins_Goto_CodeRange */
+ /* */
+ /* <Description> */
+ /* Goes to a certain code range in the instruction stream. */
+ /* */
+ /* <Input> */
+ /* aRange :: The index of the code range. */
+ /* */
+ /* aIP :: The new IP address in the code range. */
+ /* */
+ /* <Return> */
+ /* SUCCESS or FAILURE. */
+ /* */
+ static FT_Bool
+ Ins_Goto_CodeRange( EXEC_OP_ FT_Int aRange,
+ FT_ULong aIP )
+ {
+ TT_CodeRange* range;
+
+
+ if ( aRange < 1 || aRange > 3 )
+ {
+ CUR.error = TT_Err_Bad_Argument;
+ return FAILURE;
+ }
+
+ range = &CUR.codeRangeTable[aRange - 1];
+
+ if ( range->base == NULL ) /* invalid coderange */
+ {
+ CUR.error = TT_Err_Invalid_CodeRange;
+ return FAILURE;
+ }
+
+ /* NOTE: Because the last instruction of a program may be a CALL */
+ /* which will return to the first byte *after* the code */
+ /* range, we test for AIP <= Size, instead of AIP < Size. */
+
+ if ( aIP > range->size )
+ {
+ CUR.error = TT_Err_Code_Overflow;
+ return FAILURE;
+ }
+
+ CUR.code = range->base;
+ CUR.codeSize = range->size;
+ CUR.IP = aIP;
+ CUR.curRange = aRange;
+
+ return SUCCESS;
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* Direct_Move */
+ /* */
+ /* <Description> */
+ /* Moves a point by a given distance along the freedom vector. The */
+ /* point will be `touched'. */
+ /* */
+ /* <Input> */
+ /* point :: The index of the point to move. */
+ /* */
+ /* distance :: The distance to apply. */
+ /* */
+ /* <InOut> */
+ /* zone :: The affected glyph zone. */
+ /* */
+ static void
+ Direct_Move( EXEC_OP_ TT_GlyphZone zone,
+ FT_UShort point,
+ FT_F26Dot6 distance )
+ {
+ FT_F26Dot6 v;
+
+
+ v = CUR.GS.freeVector.x;
+
+ if ( v != 0 )
+ {
+
+#ifdef NO_APPLE_PATENT
+
+ if ( ABS( CUR.F_dot_P ) > APPLE_THRESHOLD )
+ zone->cur[point].x += distance;
+
+#else
+
+ zone->cur[point].x += TT_MULDIV( distance,
+ v * 0x10000L,
+ CUR.F_dot_P );
+
+#endif
+
+ zone->tags[point] |= FT_CURVE_TAG_TOUCH_X;
+ }
+
+ v = CUR.GS.freeVector.y;
+
+ if ( v != 0 )
+ {
+
+#ifdef NO_APPLE_PATENT
+
+ if ( ABS( CUR.F_dot_P ) > APPLE_THRESHOLD )
+ zone->cur[point].y += distance;
+
+#else
+
+ zone->cur[point].y += TT_MULDIV( distance,
+ v * 0x10000L,
+ CUR.F_dot_P );
+
+#endif
+
+ zone->tags[point] |= FT_CURVE_TAG_TOUCH_Y;
+ }
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* Special versions of Direct_Move() */
+ /* */
+ /* The following versions are used whenever both vectors are both */
+ /* along one of the coordinate unit vectors, i.e. in 90% of the cases. */
+ /* */
+ /*************************************************************************/
+
+
+ static void
+ Direct_Move_X( EXEC_OP_ TT_GlyphZone zone,
+ FT_UShort point,
+ FT_F26Dot6 distance )
+ {
+ FT_UNUSED_EXEC;
+
+ zone->cur[point].x += distance;
+ zone->tags[point] |= FT_CURVE_TAG_TOUCH_X;
+ }
+
+
+ static void
+ Direct_Move_Y( EXEC_OP_ TT_GlyphZone zone,
+ FT_UShort point,
+ FT_F26Dot6 distance )
+ {
+ FT_UNUSED_EXEC;
+
+ zone->cur[point].y += distance;
+ zone->tags[point] |= FT_CURVE_TAG_TOUCH_Y;
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* Round_None */
+ /* */
+ /* <Description> */
+ /* Does not round, but adds engine compensation. */
+ /* */
+ /* <Input> */
+ /* distance :: The distance (not) to round. */
+ /* */
+ /* compensation :: The engine compensation. */
+ /* */
+ /* <Return> */
+ /* The compensated distance. */
+ /* */
+ /* <Note> */
+ /* The TrueType specification says very few about the relationship */
+ /* between rounding and engine compensation. However, it seems from */
+ /* the description of super round that we should add the compensation */
+ /* before rounding. */
+ /* */
+ static FT_F26Dot6
+ Round_None( EXEC_OP_ FT_F26Dot6 distance,
+ FT_F26Dot6 compensation )
+ {
+ FT_F26Dot6 val;
+
+ FT_UNUSED_EXEC;
+
+
+ if ( distance >= 0 )
+ {
+ val = distance + compensation;
+ if ( val < 0 )
+ val = 0;
+ }
+ else {
+ val = distance - compensation;
+ if ( val > 0 )
+ val = 0;
+ }
+ return val;
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* Round_To_Grid */
+ /* */
+ /* <Description> */
+ /* Rounds value to grid after adding engine compensation. */
+ /* */
+ /* <Input> */
+ /* distance :: The distance to round. */
+ /* */
+ /* compensation :: The engine compensation. */
+ /* */
+ /* <Return> */
+ /* Rounded distance. */
+ /* */
+ static FT_F26Dot6
+ Round_To_Grid( EXEC_OP_ FT_F26Dot6 distance,
+ FT_F26Dot6 compensation )
+ {
+ FT_F26Dot6 val;
+
+ FT_UNUSED_EXEC;
+
+
+ if ( distance >= 0 )
+ {
+ val = distance + compensation + 32;
+ if ( val > 0 )
+ val &= ~63;
+ else
+ val = 0;
+ }
+ else
+ {
+ val = -( ( compensation - distance + 32 ) & -64 );
+ if ( val > 0 )
+ val = 0;
+ }
+
+ return val;
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* Round_To_Half_Grid */
+ /* */
+ /* <Description> */
+ /* Rounds value to half grid after adding engine compensation. */
+ /* */
+ /* <Input> */
+ /* distance :: The distance to round. */
+ /* */
+ /* compensation :: The engine compensation. */
+ /* */
+ /* <Return> */
+ /* Rounded distance. */
+ /* */
+ static FT_F26Dot6
+ Round_To_Half_Grid( EXEC_OP_ FT_F26Dot6 distance,
+ FT_F26Dot6 compensation )
+ {
+ FT_F26Dot6 val;
+
+ FT_UNUSED_EXEC;
+
+
+ if ( distance >= 0 )
+ {
+ val = ( ( distance + compensation ) & -64 ) + 32;
+ if ( val < 0 )
+ val = 0;
+ }
+ else
+ {
+ val = -( ( (compensation - distance) & -64 ) + 32 );
+ if ( val > 0 )
+ val = 0;
+ }
+
+ return val;
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* Round_Down_To_Grid */
+ /* */
+ /* <Description> */
+ /* Rounds value down to grid after adding engine compensation. */
+ /* */
+ /* <Input> */
+ /* distance :: The distance to round. */
+ /* */
+ /* compensation :: The engine compensation. */
+ /* */
+ /* <Return> */
+ /* Rounded distance. */
+ /* */
+ static FT_F26Dot6
+ Round_Down_To_Grid( EXEC_OP_ FT_F26Dot6 distance,
+ FT_F26Dot6 compensation )
+ {
+ FT_F26Dot6 val;
+
+ FT_UNUSED_EXEC;
+
+
+ if ( distance >= 0 )
+ {
+ val = distance + compensation;
+ if ( val > 0 )
+ val &= ~63;
+ else
+ val = 0;
+ }
+ else
+ {
+ val = -( ( compensation - distance ) & -64 );
+ if ( val > 0 )
+ val = 0;
+ }
+
+ return val;
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* Round_Up_To_Grid */
+ /* */
+ /* <Description> */
+ /* Rounds value up to grid after adding engine compensation. */
+ /* */
+ /* <Input> */
+ /* distance :: The distance to round. */
+ /* */
+ /* compensation :: The engine compensation. */
+ /* */
+ /* <Return> */
+ /* Rounded distance. */
+ /* */
+ static FT_F26Dot6
+ Round_Up_To_Grid( EXEC_OP_ FT_F26Dot6 distance,
+ FT_F26Dot6 compensation )
+ {
+ FT_F26Dot6 val;
+
+
+ FT_UNUSED_EXEC;
+
+ if ( distance >= 0 )
+ {
+ val = distance + compensation + 63;
+ if ( val > 0 )
+ val &= ~63;
+ else
+ val = 0;
+ }
+ else
+ {
+ val = -( ( compensation - distance + 63 ) & -64 );
+ if ( val > 0 )
+ val = 0;
+ }
+
+ return val;
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* Round_To_Double_Grid */
+ /* */
+ /* <Description> */
+ /* Rounds value to double grid after adding engine compensation. */
+ /* */
+ /* <Input> */
+ /* distance :: The distance to round. */
+ /* */
+ /* compensation :: The engine compensation. */
+ /* */
+ /* <Return> */
+ /* Rounded distance. */
+ /* */
+ static FT_F26Dot6
+ Round_To_Double_Grid( EXEC_OP_ FT_F26Dot6 distance,
+ FT_F26Dot6 compensation )
+ {
+ FT_F26Dot6 val;
+
+ FT_UNUSED_EXEC;
+
+
+ if ( distance >= 0 )
+ {
+ val = distance + compensation + 16;
+ if ( val > 0 )
+ val &= ~31;
+ else
+ val = 0;
+ }
+ else
+ {
+ val = -( ( compensation - distance + 16 ) & -32 );
+ if ( val > 0 )
+ val = 0;
+ }
+
+ return val;
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* Round_Super */
+ /* */
+ /* <Description> */
+ /* Super-rounds value to grid after adding engine compensation. */
+ /* */
+ /* <Input> */
+ /* distance :: The distance to round. */
+ /* */
+ /* compensation :: The engine compensation. */
+ /* */
+ /* <Return> */
+ /* Rounded distance. */
+ /* */
+ /* <Note> */
+ /* The TrueType specification says very few about the relationship */
+ /* between rounding and engine compensation. However, it seems from */
+ /* the description of super round that we should add the compensation */
+ /* before rounding. */
+ /* */
+ static FT_F26Dot6
+ Round_Super( EXEC_OP_ FT_F26Dot6 distance,
+ FT_F26Dot6 compensation )
+ {
+ FT_F26Dot6 val;
+
+
+ if ( distance >= 0 )
+ {
+ val = ( distance - CUR.phase + CUR.threshold + compensation ) &
+ -CUR.period;
+ if ( val < 0 )
+ val = 0;
+ val += CUR.phase;
+ }
+ else
+ {
+ val = -( ( CUR.threshold - CUR.phase - distance + compensation ) &
+ -CUR.period );
+ if ( val > 0 )
+ val = 0;
+ val -= CUR.phase;
+ }
+
+ return val;
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* Round_Super_45 */
+ /* */
+ /* <Description> */
+ /* Super-rounds value to grid after adding engine compensation. */
+ /* */
+ /* <Input> */
+ /* distance :: The distance to round. */
+ /* */
+ /* compensation :: The engine compensation. */
+ /* */
+ /* <Return> */
+ /* Rounded distance. */
+ /* */
+ /* <Note> */
+ /* There is a separate function for Round_Super_45() as we may need */
+ /* greater precision. */
+ /* */
+ static FT_F26Dot6
+ Round_Super_45( EXEC_OP_ FT_F26Dot6 distance,
+ FT_F26Dot6 compensation )
+ {
+ FT_F26Dot6 val;
+
+
+ if ( distance >= 0 )
+ {
+ val = ( ( distance - CUR.phase + CUR.threshold + compensation ) /
+ CUR.period ) * CUR.period;
+ if ( val < 0 )
+ val = 0;
+ val += CUR.phase;
+ }
+ else
+ {
+ val = -( ( ( CUR.threshold - CUR.phase - distance + compensation ) /
+ CUR.period ) * CUR.period );
+ if ( val > 0 )
+ val = 0;
+ val -= CUR.phase;
+ }
+
+ return val;
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* Compute_Round */
+ /* */
+ /* <Description> */
+ /* Sets the rounding mode. */
+ /* */
+ /* <Input> */
+ /* round_mode :: The rounding mode to be used. */
+ /* */
+ static void
+ Compute_Round( EXEC_OP_ FT_Byte round_mode )
+ {
+ switch ( round_mode )
+ {
+ case TT_Round_Off:
+ CUR.func_round = (TT_Round_Func)Round_None;
+ break;
+
+ case TT_Round_To_Grid:
+ CUR.func_round = (TT_Round_Func)Round_To_Grid;
+ break;
+
+ case TT_Round_Up_To_Grid:
+ CUR.func_round = (TT_Round_Func)Round_Up_To_Grid;
+ break;
+
+ case TT_Round_Down_To_Grid:
+ CUR.func_round = (TT_Round_Func)Round_Down_To_Grid;
+ break;
+
+ case TT_Round_To_Half_Grid:
+ CUR.func_round = (TT_Round_Func)Round_To_Half_Grid;
+ break;
+
+ case TT_Round_To_Double_Grid:
+ CUR.func_round = (TT_Round_Func)Round_To_Double_Grid;
+ break;
+
+ case TT_Round_Super:
+ CUR.func_round = (TT_Round_Func)Round_Super;
+ break;
+
+ case TT_Round_Super_45:
+ CUR.func_round = (TT_Round_Func)Round_Super_45;
+ break;
+ }
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* SetSuperRound */
+ /* */
+ /* <Description> */
+ /* Sets Super Round parameters. */
+ /* */
+ /* <Input> */
+ /* GridPeriod :: Grid period */
+ /* selector :: SROUND opcode */
+ /* */
+ static void
+ SetSuperRound( EXEC_OP_ FT_F26Dot6 GridPeriod,
+ FT_Long selector )
+ {
+ switch ( (FT_Int)( selector & 0xC0 ) )
+ {
+ case 0:
+ CUR.period = GridPeriod / 2;
+ break;
+
+ case 0x40:
+ CUR.period = GridPeriod;
+ break;
+
+ case 0x80:
+ CUR.period = GridPeriod * 2;
+ break;
+
+ /* This opcode is reserved, but... */
+
+ case 0xC0:
+ CUR.period = GridPeriod;
+ break;
+ }
+
+ switch ( (FT_Int)( selector & 0x30 ) )
+ {
+ case 0:
+ CUR.phase = 0;
+ break;
+
+ case 0x10:
+ CUR.phase = CUR.period / 4;
+ break;
+
+ case 0x20:
+ CUR.phase = CUR.period / 2;
+ break;
+
+ case 0x30:
+ CUR.phase = GridPeriod * 3 / 4;
+ break;
+ }
+
+ if ( (selector & 0x0F) == 0 )
+ CUR.threshold = CUR.period - 1;
+ else
+ CUR.threshold = ( (FT_Int)( selector & 0x0F ) - 4 ) * CUR.period / 8;
+
+ CUR.period /= 256;
+ CUR.phase /= 256;
+ CUR.threshold /= 256;
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* Project */
+ /* */
+ /* <Description> */
+ /* Computes the projection of vector given by (v2-v1) along the */
+ /* current projection vector. */
+ /* */
+ /* <Input> */
+ /* v1 :: First input vector. */
+ /* v2 :: Second input vector. */
+ /* */
+ /* <Return> */
+ /* The distance in F26dot6 format. */
+ /* */
+ static FT_F26Dot6
+ Project( EXEC_OP_ FT_Vector* v1,
+ FT_Vector* v2 )
+ {
+ return TT_DotFix14( v1->x - v2->x,
+ v1->y - v2->y,
+ CUR.GS.projVector.x,
+ CUR.GS.projVector.y );
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* Dual_Project */
+ /* */
+ /* <Description> */
+ /* Computes the projection of the vector given by (v2-v1) along the */
+ /* current dual vector. */
+ /* */
+ /* <Input> */
+ /* v1 :: First input vector. */
+ /* v2 :: Second input vector. */
+ /* */
+ /* <Return> */
+ /* The distance in F26dot6 format. */
+ /* */
+ static FT_F26Dot6
+ Dual_Project( EXEC_OP_ FT_Vector* v1,
+ FT_Vector* v2 )
+ {
+ return TT_DotFix14( v1->x - v2->x,
+ v1->y - v2->y,
+ CUR.GS.dualVector.x,
+ CUR.GS.dualVector.y );
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* Free_Project */
+ /* */
+ /* <Description> */
+ /* Computes the projection of the vector given by (v2-v1) along the */
+ /* current freedom vector. */
+ /* */
+ /* <Input> */
+ /* v1 :: First input vector. */
+ /* v2 :: Second input vector. */
+ /* */
+ /* <Return> */
+ /* The distance in F26dot6 format. */
+ /* */
+ static FT_F26Dot6
+ Free_Project( EXEC_OP_ FT_Vector* v1,
+ FT_Vector* v2 )
+ {
+ return TT_DotFix14( v1->x - v2->x,
+ v1->y - v2->y,
+ CUR.GS.freeVector.x,
+ CUR.GS.freeVector.y );
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* Project_x */
+ /* */
+ /* <Description> */
+ /* Computes the projection of the vector given by (v2-v1) along the */
+ /* horizontal axis. */
+ /* */
+ /* <Input> */
+ /* v1 :: First input vector. */
+ /* v2 :: Second input vector. */
+ /* */
+ /* <Return> */
+ /* The distance in F26dot6 format. */
+ /* */
+ static FT_F26Dot6
+ Project_x( EXEC_OP_ FT_Vector* v1,
+ FT_Vector* v2 )
+ {
+ FT_UNUSED_EXEC;
+
+ return ( v1->x - v2->x );
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* Project_y */
+ /* */
+ /* <Description> */
+ /* Computes the projection of the vector given by (v2-v1) along the */
+ /* vertical axis. */
+ /* */
+ /* <Input> */
+ /* v1 :: First input vector. */
+ /* v2 :: Second input vector. */
+ /* */
+ /* <Return> */
+ /* The distance in F26dot6 format. */
+ /* */
+ static FT_F26Dot6
+ Project_y( EXEC_OP_ FT_Vector* v1,
+ FT_Vector* v2 )
+ {
+ FT_UNUSED_EXEC;
+
+ return ( v1->y - v2->y );
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* Compute_Funcs */
+ /* */
+ /* <Description> */
+ /* Computes the projection and movement function pointers according */
+ /* to the current graphics state. */
+ /* */
+ static void
+ Compute_Funcs( EXEC_OP )
+ {
+ if ( CUR.GS.freeVector.x == 0x4000 )
+ {
+ CUR.func_freeProj = (TT_Project_Func)Project_x;
+ CUR.F_dot_P = CUR.GS.projVector.x * 0x10000L;
+ }
+ else
+ {
+ if ( CUR.GS.freeVector.y == 0x4000 )
+ {
+ CUR.func_freeProj = (TT_Project_Func)Project_y;
+ CUR.F_dot_P = CUR.GS.projVector.y * 0x10000L;
+ }
+ else
+ {
+ CUR.func_freeProj = (TT_Project_Func)Free_Project;
+ CUR.F_dot_P = (FT_Long)CUR.GS.projVector.x * CUR.GS.freeVector.x * 4 +
+ (FT_Long)CUR.GS.projVector.y * CUR.GS.freeVector.y * 4;
+ }
+ }
+
+ if ( CUR.GS.projVector.x == 0x4000 )
+ CUR.func_project = (TT_Project_Func)Project_x;
+ else
+ {
+ if ( CUR.GS.projVector.y == 0x4000 )
+ CUR.func_project = (TT_Project_Func)Project_y;
+ else
+ CUR.func_project = (TT_Project_Func)Project;
+ }
+
+ if ( CUR.GS.dualVector.x == 0x4000 )
+ CUR.func_dualproj = (TT_Project_Func)Project_x;
+ else
+ {
+ if ( CUR.GS.dualVector.y == 0x4000 )
+ CUR.func_dualproj = (TT_Project_Func)Project_y;
+ else
+ CUR.func_dualproj = (TT_Project_Func)Dual_Project;
+ }
+
+ CUR.func_move = (TT_Move_Func)Direct_Move;
+
+ if ( CUR.F_dot_P == 0x40000000L )
+ {
+ if ( CUR.GS.freeVector.x == 0x4000 )
+ CUR.func_move = (TT_Move_Func)Direct_Move_X;
+ else
+ {
+ if ( CUR.GS.freeVector.y == 0x4000 )
+ CUR.func_move = (TT_Move_Func)Direct_Move_Y;
+ }
+ }
+
+ /* at small sizes, F_dot_P can become too small, resulting */
+ /* in overflows and `spikes' in a number of glyphs like `w'. */
+
+ if ( ABS( CUR.F_dot_P ) < 0x4000000L )
+ CUR.F_dot_P = 0x40000000L;
+
+ /* Disable cached aspect ratio */
+ CUR.tt_metrics.ratio = 0;
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* Normalize */
+ /* */
+ /* <Description> */
+ /* Norms a vector. */
+ /* */
+ /* <Input> */
+ /* Vx :: The horizontal input vector coordinate. */
+ /* Vy :: The vertical input vector coordinate. */
+ /* */
+ /* <Output> */
+ /* R :: The normed unit vector. */
+ /* */
+ /* <Return> */
+ /* Returns FAILURE if a vector parameter is zero. */
+ /* */
+ /* <Note> */
+ /* In case Vx and Vy are both zero, Normalize() returns SUCCESS, and */
+ /* R is undefined. */
+ /* */
+
+
+ static FT_Bool
+ Normalize( EXEC_OP_ FT_F26Dot6 Vx,
+ FT_F26Dot6 Vy,
+ FT_UnitVector* R )
+ {
+ FT_F26Dot6 W;
+ FT_Bool S1, S2;
+
+ FT_UNUSED_EXEC;
+
+
+ if ( ABS( Vx ) < 0x10000L && ABS( Vy ) < 0x10000L )
+ {
+ Vx *= 0x100;
+ Vy *= 0x100;
+
+ W = TT_VecLen( Vx, Vy );
+
+ if ( W == 0 )
+ {
+ /* XXX: UNDOCUMENTED! It seems that it is possible to try */
+ /* to normalize the vector (0,0). Return immediately. */
+ return SUCCESS;
+ }
+
+ R->x = (FT_F2Dot14)FT_MulDiv( Vx, 0x4000L, W );
+ R->y = (FT_F2Dot14)FT_MulDiv( Vy, 0x4000L, W );
+
+ return SUCCESS;
+ }
+
+ W = TT_VecLen( Vx, Vy );
+
+ Vx = FT_MulDiv( Vx, 0x4000L, W );
+ Vy = FT_MulDiv( Vy, 0x4000L, W );
+
+ W = Vx * Vx + Vy * Vy;
+
+ /* Now, we want that Sqrt( W ) = 0x4000 */
+ /* Or 0x1000000 <= W < 0x1004000 */
+
+ if ( Vx < 0 )
+ {
+ Vx = -Vx;
+ S1 = TRUE;
+ }
+ else
+ S1 = FALSE;
+
+ if ( Vy < 0 )
+ {
+ Vy = -Vy;
+ S2 = TRUE;
+ }
+ else
+ S2 = FALSE;
+
+ while ( W < 0x1000000L )
+ {
+ /* We need to increase W by a minimal amount */
+ if ( Vx < Vy )
+ Vx++;
+ else
+ Vy++;
+
+ W = Vx * Vx + Vy * Vy;
+ }
+
+ while ( W >= 0x1004000L )
+ {
+ /* We need to decrease W by a minimal amount */
+ if ( Vx < Vy )
+ Vx--;
+ else
+ Vy--;
+
+ W = Vx * Vx + Vy * Vy;
+ }
+
+ /* Note that in various cases, we can only */
+ /* compute a Sqrt(W) of 0x3FFF, eg. Vx = Vy */
+
+ if ( S1 )
+ Vx = -Vx;
+
+ if ( S2 )
+ Vy = -Vy;
+
+ R->x = (FT_F2Dot14)Vx; /* Type conversion */
+ R->y = (FT_F2Dot14)Vy; /* Type conversion */
+
+ return SUCCESS;
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* Here we start with the implementation of the various opcodes. */
+ /* */
+ /*************************************************************************/
+
+
+ static FT_Bool
+ Ins_SxVTL( EXEC_OP_ FT_UShort aIdx1,
+ FT_UShort aIdx2,
+ FT_Int aOpc,
+ FT_UnitVector* Vec )
+ {
+ FT_Long A, B, C;
+ FT_Vector* p1;
+ FT_Vector* p2;
+
+
+ if ( BOUNDS( aIdx1, CUR.zp2.n_points ) ||
+ BOUNDS( aIdx2, CUR.zp1.n_points ) )
+ {
+ if ( CUR.pedantic_hinting )
+ CUR.error = TT_Err_Invalid_Reference;
+ return FAILURE;
+ }
+
+ p1 = CUR.zp1.cur + aIdx2;
+ p2 = CUR.zp2.cur + aIdx1;
+
+ A = p1->x - p2->x;
+ B = p1->y - p2->y;
+
+ if ( ( aOpc & 1 ) != 0 )
+ {
+ C = B; /* counter clockwise rotation */
+ B = A;
+ A = -C;
+ }
+
+ NORMalize( A, B, Vec );
+
+ return SUCCESS;
+ }
+
+
+ /* When not using the big switch statements, the interpreter uses a */
+ /* call table defined later below in this source. Each opcode must */
+ /* thus have a corresponding function, even trivial ones. */
+ /* */
+ /* They are all defined there. */
+
+#define DO_SVTCA \
+ { \
+ FT_Short A, B; \
+ \
+ \
+ A = (FT_Short)( CUR.opcode & 1 ) << 14; \
+ B = A ^ (FT_Short)0x4000; \
+ \
+ CUR.GS.freeVector.x = A; \
+ CUR.GS.projVector.x = A; \
+ CUR.GS.dualVector.x = A; \
+ \
+ CUR.GS.freeVector.y = B; \
+ CUR.GS.projVector.y = B; \
+ CUR.GS.dualVector.y = B; \
+ \
+ COMPUTE_Funcs(); \
+ }
+
+
+#define DO_SPVTCA \
+ { \
+ FT_Short A, B; \
+ \
+ \
+ A = (FT_Short)( CUR.opcode & 1 ) << 14; \
+ B = A ^ (FT_Short)0x4000; \
+ \
+ CUR.GS.projVector.x = A; \
+ CUR.GS.dualVector.x = A; \
+ \
+ CUR.GS.projVector.y = B; \
+ CUR.GS.dualVector.y = B; \
+ \
+ COMPUTE_Funcs(); \
+ }
+
+
+#define DO_SFVTCA \
+ { \
+ FT_Short A, B; \
+ \
+ \
+ A = (FT_Short)( CUR.opcode & 1 ) << 14; \
+ B = A ^ (FT_Short)0x4000; \
+ \
+ CUR.GS.freeVector.x = A; \
+ CUR.GS.freeVector.y = B; \
+ \
+ COMPUTE_Funcs(); \
+ }
+
+
+#define DO_SPVTL \
+ if ( INS_SxVTL( (FT_UShort)args[1], \
+ (FT_UShort)args[0], \
+ CUR.opcode, \
+ &CUR.GS.projVector ) == SUCCESS ) \
+ { \
+ CUR.GS.dualVector = CUR.GS.projVector; \
+ COMPUTE_Funcs(); \
+ }
+
+
+#define DO_SFVTL \
+ if ( INS_SxVTL( (FT_UShort)args[1], \
+ (FT_UShort)args[0], \
+ CUR.opcode, \
+ &CUR.GS.freeVector ) == SUCCESS ) \
+ COMPUTE_Funcs();
+
+
+#define DO_SFVTPV \
+ CUR.GS.freeVector = CUR.GS.projVector; \
+ COMPUTE_Funcs();
+
+
+#define DO_SPVFS \
+ { \
+ FT_Short S; \
+ FT_Long X, Y; \
+ \
+ \
+ /* Only use low 16bits, then sign extend */ \
+ S = (FT_Short)args[1]; \
+ Y = (FT_Long)S; \
+ S = (FT_Short)args[0]; \
+ X = (FT_Long)S; \
+ \
+ NORMalize( X, Y, &CUR.GS.projVector ); \
+ \
+ CUR.GS.dualVector = CUR.GS.projVector; \
+ COMPUTE_Funcs(); \
+ }
+
+
+#define DO_SFVFS \
+ { \
+ FT_Short S; \
+ FT_Long X, Y; \
+ \
+ \
+ /* Only use low 16bits, then sign extend */ \
+ S = (FT_Short)args[1]; \
+ Y = (FT_Long)S; \
+ S = (FT_Short)args[0]; \
+ X = S; \
+ \
+ NORMalize( X, Y, &CUR.GS.freeVector ); \
+ COMPUTE_Funcs(); \
+ }
+
+
+#define DO_GPV \
+ args[0] = CUR.GS.projVector.x; \
+ args[1] = CUR.GS.projVector.y;
+
+
+#define DO_GFV \
+ args[0] = CUR.GS.freeVector.x; \
+ args[1] = CUR.GS.freeVector.y;
+
+
+#define DO_SRP0 \
+ CUR.GS.rp0 = (FT_UShort)args[0];
+
+
+#define DO_SRP1 \
+ CUR.GS.rp1 = (FT_UShort)args[0];
+
+
+#define DO_SRP2 \
+ CUR.GS.rp2 = (FT_UShort)args[0];
+
+
+#define DO_RTHG \
+ CUR.GS.round_state = TT_Round_To_Half_Grid; \
+ CUR.func_round = (TT_Round_Func)Round_To_Half_Grid;
+
+
+#define DO_RTG \
+ CUR.GS.round_state = TT_Round_To_Grid; \
+ CUR.func_round = (TT_Round_Func)Round_To_Grid;
+
+
+#define DO_RTDG \
+ CUR.GS.round_state = TT_Round_To_Double_Grid; \
+ CUR.func_round = (TT_Round_Func)Round_To_Double_Grid;
+
+
+#define DO_RUTG \
+ CUR.GS.round_state = TT_Round_Up_To_Grid; \
+ CUR.func_round = (TT_Round_Func)Round_Up_To_Grid;
+
+
+#define DO_RDTG \
+ CUR.GS.round_state = TT_Round_Down_To_Grid; \
+ CUR.func_round = (TT_Round_Func)Round_Down_To_Grid;
+
+
+#define DO_ROFF \
+ CUR.GS.round_state = TT_Round_Off; \
+ CUR.func_round = (TT_Round_Func)Round_None;
+
+
+#define DO_SROUND \
+ SET_SuperRound( 0x4000, args[0] ); \
+ CUR.GS.round_state = TT_Round_Super; \
+ CUR.func_round = (TT_Round_Func)Round_Super;
+
+
+#define DO_S45ROUND \
+ SET_SuperRound( 0x2D41, args[0] ); \
+ CUR.GS.round_state = TT_Round_Super_45; \
+ CUR.func_round = (TT_Round_Func)Round_Super_45;
+
+
+#define DO_SLOOP \
+ if ( args[0] < 0 ) \
+ CUR.error = TT_Err_Bad_Argument; \
+ else \
+ CUR.GS.loop = args[0];
+
+
+#define DO_SMD \
+ CUR.GS.minimum_distance = args[0];
+
+
+#define DO_SCVTCI \
+ CUR.GS.control_value_cutin = (FT_F26Dot6)args[0];
+
+
+#define DO_SSWCI \
+ CUR.GS.single_width_cutin = (FT_F26Dot6)args[0];
+
+
+ /* XXX: UNDOCUMENTED! or bug in the Windows engine? */
+ /* */
+ /* It seems that the value that is read here is */
+ /* expressed in 16.16 format rather than in font */
+ /* units. */
+ /* */
+#define DO_SSW \
+ CUR.GS.single_width_value = (FT_F26Dot6)( args[0] >> 10 );
+
+
+#define DO_FLIPON \
+ CUR.GS.auto_flip = TRUE;
+
+
+#define DO_FLIPOFF \
+ CUR.GS.auto_flip = FALSE;
+
+
+#define DO_SDB \
+ CUR.GS.delta_base = (FT_Short)args[0];
+
+
+#define DO_SDS \
+ CUR.GS.delta_shift = (FT_Short)args[0];
+
+
+#define DO_MD /* nothing */
+
+
+#define DO_MPPEM \
+ args[0] = CURRENT_Ppem();
+
+
+ /* Note: The pointSize should be irrelevant in a given font program; */
+ /* we thus decide to return only the ppem. */
+#if 0
+
+#define DO_MPS \
+ args[0] = CUR.metrics.pointSize;
+
+#else
+
+#define DO_MPS \
+ args[0] = CURRENT_Ppem();
+
+#endif /* 0 */
+
+
+#define DO_DUP \
+ args[1] = args[0];
+
+
+#define DO_CLEAR \
+ CUR.new_top = 0;
+
+
+#define DO_SWAP \
+ { \
+ FT_Long L; \
+ \
+ \
+ L = args[0]; \
+ args[0] = args[1]; \
+ args[1] = L; \
+ }
+
+
+#define DO_DEPTH \
+ args[0] = CUR.top;
+
+
+#define DO_CINDEX \
+ { \
+ FT_Long L; \
+ \
+ \
+ L = args[0]; \
+ \
+ if ( L <= 0 || L > CUR.args ) \
+ CUR.error = TT_Err_Invalid_Reference; \
+ else \
+ args[0] = CUR.stack[CUR.args - L]; \
+ }
+
+
+#define DO_JROT \
+ if ( args[1] != 0 ) \
+ { \
+ CUR.IP += args[0]; \
+ CUR.step_ins = FALSE; \
+ }
+
+
+#define DO_JMPR \
+ CUR.IP += args[0]; \
+ CUR.step_ins = FALSE;
+
+
+#define DO_JROF \
+ if ( args[1] == 0 ) \
+ { \
+ CUR.IP += args[0]; \
+ CUR.step_ins = FALSE; \
+ }
+
+
+#define DO_LT \
+ args[0] = ( args[0] < args[1] );
+
+
+#define DO_LTEQ \
+ args[0] = ( args[0] <= args[1] );
+
+
+#define DO_GT \
+ args[0] = ( args[0] > args[1] );
+
+
+#define DO_GTEQ \
+ args[0] = ( args[0] >= args[1] );
+
+
+#define DO_EQ \
+ args[0] = ( args[0] == args[1] );
+
+
+#define DO_NEQ \
+ args[0] = ( args[0] != args[1] );
+
+
+#define DO_ODD \
+ args[0] = ( ( CUR_Func_round( args[0], 0 ) & 127 ) == 64 );
+
+
+#define DO_EVEN \
+ args[0] = ( ( CUR_Func_round( args[0], 0 ) & 127 ) == 0 );
+
+
+#define DO_AND \
+ args[0] = ( args[0] && args[1] );
+
+
+#define DO_OR \
+ args[0] = ( args[0] || args[1] );
+
+
+#define DO_NOT \
+ args[0] = !args[0];
+
+
+#define DO_ADD \
+ args[0] += args[1];
+
+
+#define DO_SUB \
+ args[0] -= args[1];
+
+
+#define DO_DIV \
+ if ( args[1] == 0 ) \
+ CUR.error = TT_Err_Divide_By_Zero; \
+ else \
+ args[0] = TT_MULDIV( args[0], 64L, args[1] );
+
+
+#define DO_MUL \
+ args[0] = TT_MULDIV( args[0], args[1], 64L );
+
+
+#define DO_ABS \
+ args[0] = ABS( args[0] );
+
+
+#define DO_NEG \
+ args[0] = -args[0];
+
+
+#define DO_FLOOR \
+ args[0] &= -64;
+
+
+#define DO_CEILING \
+ args[0] = ( args[0] + 63 ) & -64;
+
+
+#define DO_RS \
+ { \
+ FT_ULong I = (FT_ULong)args[0]; \
+ \
+ \
+ if ( BOUNDS( I, CUR.storeSize ) ) \
+ { \
+ if ( CUR.pedantic_hinting ) \
+ { \
+ ARRAY_BOUND_ERROR; \
+ } \
+ else \
+ args[0] = 0; \
+ } \
+ else \
+ args[0] = CUR.storage[I]; \
+ }
+
+
+#define DO_WS \
+ { \
+ FT_ULong I = (FT_ULong)args[0]; \
+ \
+ \
+ if ( BOUNDS( I, CUR.storeSize ) ) \
+ { \
+ if ( CUR.pedantic_hinting ) \
+ { \
+ ARRAY_BOUND_ERROR; \
+ } \
+ } \
+ else \
+ CUR.storage[I] = args[1]; \
+ }
+
+
+#define DO_RCVT \
+ { \
+ FT_ULong I = (FT_ULong)args[0]; \
+ \
+ \
+ if ( BOUNDS( I, CUR.cvtSize ) ) \
+ { \
+ if ( CUR.pedantic_hinting ) \
+ { \
+ ARRAY_BOUND_ERROR; \
+ } \
+ else \
+ args[0] = 0; \
+ } \
+ else \
+ args[0] = CUR_Func_read_cvt( I ); \
+ }
+
+
+#define DO_WCVTP \
+ { \
+ FT_ULong I = (FT_ULong)args[0]; \
+ \
+ \
+ if ( BOUNDS( I, CUR.cvtSize ) ) \
+ { \
+ if ( CUR.pedantic_hinting ) \
+ { \
+ ARRAY_BOUND_ERROR; \
+ } \
+ } \
+ else \
+ CUR_Func_write_cvt( I, args[1] ); \
+ }
+
+
+#define DO_WCVTF \
+ { \
+ FT_ULong I = (FT_ULong)args[0]; \
+ \
+ \
+ if ( BOUNDS( I, CUR.cvtSize ) ) \
+ { \
+ if ( CUR.pedantic_hinting ) \
+ { \
+ ARRAY_BOUND_ERROR; \
+ } \
+ } \
+ else \
+ CUR.cvt[I] = TT_MULFIX( args[1], CUR.tt_metrics.scale ); \
+ }
+
+
+#define DO_DEBUG \
+ CUR.error = TT_Err_Debug_OpCode;
+
+
+#define DO_ROUND \
+ args[0] = CUR_Func_round( \
+ args[0], \
+ CUR.tt_metrics.compensations[CUR.opcode - 0x68] );
+
+
+#define DO_NROUND \
+ args[0] = ROUND_None( args[0], \
+ CUR.tt_metrics.compensations[CUR.opcode - 0x6C] );
+
+
+#define DO_MAX \
+ if ( args[1] > args[0] ) \
+ args[0] = args[1];
+
+
+#define DO_MIN \
+ if ( args[1] < args[0] ) \
+ args[0] = args[1];
+
+
+#ifndef TT_CONFIG_OPTION_INTERPRETER_SWITCH
+
+
+#undef ARRAY_BOUND_ERROR
+#define ARRAY_BOUND_ERROR \
+ { \
+ CUR.error = TT_Err_Invalid_Reference; \
+ return; \
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* SVTCA[a]: Set (F and P) Vectors to Coordinate Axis */
+ /* Opcode range: 0x00-0x01 */
+ /* Stack: --> */
+ /* */
+ static void
+ Ins_SVTCA( INS_ARG )
+ {
+ DO_SVTCA
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* SPVTCA[a]: Set PVector to Coordinate Axis */
+ /* Opcode range: 0x02-0x03 */
+ /* Stack: --> */
+ /* */
+ static void
+ Ins_SPVTCA( INS_ARG )
+ {
+ DO_SPVTCA
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* SFVTCA[a]: Set FVector to Coordinate Axis */
+ /* Opcode range: 0x04-0x05 */
+ /* Stack: --> */
+ /* */
+ static void
+ Ins_SFVTCA( INS_ARG )
+ {
+ DO_SFVTCA
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* SPVTL[a]: Set PVector To Line */
+ /* Opcode range: 0x06-0x07 */
+ /* Stack: uint32 uint32 --> */
+ /* */
+ static void
+ Ins_SPVTL( INS_ARG )
+ {
+ DO_SPVTL
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* SFVTL[a]: Set FVector To Line */
+ /* Opcode range: 0x08-0x09 */
+ /* Stack: uint32 uint32 --> */
+ /* */
+ static void
+ Ins_SFVTL( INS_ARG )
+ {
+ DO_SFVTL
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* SFVTPV[]: Set FVector To PVector */
+ /* Opcode range: 0x0E */
+ /* Stack: --> */
+ /* */
+ static void
+ Ins_SFVTPV( INS_ARG )
+ {
+ DO_SFVTPV
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* SPVFS[]: Set PVector From Stack */
+ /* Opcode range: 0x0A */
+ /* Stack: f2.14 f2.14 --> */
+ /* */
+ static void
+ Ins_SPVFS( INS_ARG )
+ {
+ DO_SPVFS
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* SFVFS[]: Set FVector From Stack */
+ /* Opcode range: 0x0B */
+ /* Stack: f2.14 f2.14 --> */
+ /* */
+ static void
+ Ins_SFVFS( INS_ARG )
+ {
+ DO_SFVFS
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* GPV[]: Get Projection Vector */
+ /* Opcode range: 0x0C */
+ /* Stack: ef2.14 --> ef2.14 */
+ /* */
+ static void
+ Ins_GPV( INS_ARG )
+ {
+ DO_GPV
+ }
+
+
+ /*************************************************************************/
+ /* GFV[]: Get Freedom Vector */
+ /* Opcode range: 0x0D */
+ /* Stack: ef2.14 --> ef2.14 */
+ /* */
+ static void
+ Ins_GFV( INS_ARG )
+ {
+ DO_GFV
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* SRP0[]: Set Reference Point 0 */
+ /* Opcode range: 0x10 */
+ /* Stack: uint32 --> */
+ /* */
+ static void
+ Ins_SRP0( INS_ARG )
+ {
+ DO_SRP0
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* SRP1[]: Set Reference Point 1 */
+ /* Opcode range: 0x11 */
+ /* Stack: uint32 --> */
+ /* */
+ static void
+ Ins_SRP1( INS_ARG )
+ {
+ DO_SRP1
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* SRP2[]: Set Reference Point 2 */
+ /* Opcode range: 0x12 */
+ /* Stack: uint32 --> */
+ /* */
+ static void
+ Ins_SRP2( INS_ARG )
+ {
+ DO_SRP2
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* RTHG[]: Round To Half Grid */
+ /* Opcode range: 0x19 */
+ /* Stack: --> */
+ /* */
+ static void
+ Ins_RTHG( INS_ARG )
+ {
+ DO_RTHG
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* RTG[]: Round To Grid */
+ /* Opcode range: 0x18 */
+ /* Stack: --> */
+ /* */
+ static void
+ Ins_RTG( INS_ARG )
+ {
+ DO_RTG
+ }
+
+
+ /*************************************************************************/
+ /* RTDG[]: Round To Double Grid */
+ /* Opcode range: 0x3D */
+ /* Stack: --> */
+ /* */
+ static void
+ Ins_RTDG( INS_ARG )
+ {
+ DO_RTDG
+ }
+
+
+ /*************************************************************************/
+ /* RUTG[]: Round Up To Grid */
+ /* Opcode range: 0x7C */
+ /* Stack: --> */
+ /* */
+ static void
+ Ins_RUTG( INS_ARG )
+ {
+ DO_RUTG
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* RDTG[]: Round Down To Grid */
+ /* Opcode range: 0x7D */
+ /* Stack: --> */
+ /* */
+ static void
+ Ins_RDTG( INS_ARG )
+ {
+ DO_RDTG
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* ROFF[]: Round OFF */
+ /* Opcode range: 0x7A */
+ /* Stack: --> */
+ /* */
+ static void
+ Ins_ROFF( INS_ARG )
+ {
+ DO_ROFF
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* SROUND[]: Super ROUND */
+ /* Opcode range: 0x76 */
+ /* Stack: Eint8 --> */
+ /* */
+ static void
+ Ins_SROUND( INS_ARG )
+ {
+ DO_SROUND
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* S45ROUND[]: Super ROUND 45 degrees */
+ /* Opcode range: 0x77 */
+ /* Stack: uint32 --> */
+ /* */
+ static void
+ Ins_S45ROUND( INS_ARG )
+ {
+ DO_S45ROUND
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* SLOOP[]: Set LOOP variable */
+ /* Opcode range: 0x17 */
+ /* Stack: int32? --> */
+ /* */
+ static void
+ Ins_SLOOP( INS_ARG )
+ {
+ DO_SLOOP
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* SMD[]: Set Minimum Distance */
+ /* Opcode range: 0x1A */
+ /* Stack: f26.6 --> */
+ /* */
+ static void
+ Ins_SMD( INS_ARG )
+ {
+ DO_SMD
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* SCVTCI[]: Set Control Value Table Cut In */
+ /* Opcode range: 0x1D */
+ /* Stack: f26.6 --> */
+ /* */
+ static void
+ Ins_SCVTCI( INS_ARG )
+ {
+ DO_SCVTCI
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* SSWCI[]: Set Single Width Cut In */
+ /* Opcode range: 0x1E */
+ /* Stack: f26.6 --> */
+ /* */
+ static void
+ Ins_SSWCI( INS_ARG )
+ {
+ DO_SSWCI
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* SSW[]: Set Single Width */
+ /* Opcode range: 0x1F */
+ /* Stack: int32? --> */
+ /* */
+ static void
+ Ins_SSW( INS_ARG )
+ {
+ DO_SSW
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* FLIPON[]: Set auto-FLIP to ON */
+ /* Opcode range: 0x4D */
+ /* Stack: --> */
+ /* */
+ static void
+ Ins_FLIPON( INS_ARG )
+ {
+ DO_FLIPON
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* FLIPOFF[]: Set auto-FLIP to OFF */
+ /* Opcode range: 0x4E */
+ /* Stack: --> */
+ /* */
+ static void
+ Ins_FLIPOFF( INS_ARG )
+ {
+ DO_FLIPOFF
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* SANGW[]: Set ANGle Weight */
+ /* Opcode range: 0x7E */
+ /* Stack: uint32 --> */
+ /* */
+ static void
+ Ins_SANGW( INS_ARG )
+ {
+ /* instruction not supported anymore */
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* SDB[]: Set Delta Base */
+ /* Opcode range: 0x5E */
+ /* Stack: uint32 --> */
+ /* */
+ static void
+ Ins_SDB( INS_ARG )
+ {
+ DO_SDB
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* SDS[]: Set Delta Shift */
+ /* Opcode range: 0x5F */
+ /* Stack: uint32 --> */
+ /* */
+ static void
+ Ins_SDS( INS_ARG )
+ {
+ DO_SDS
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* MPPEM[]: Measure Pixel Per EM */
+ /* Opcode range: 0x4B */
+ /* Stack: --> Euint16 */
+ /* */
+ static void
+ Ins_MPPEM( INS_ARG )
+ {
+ DO_MPPEM
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* MPS[]: Measure Point Size */
+ /* Opcode range: 0x4C */
+ /* Stack: --> Euint16 */
+ /* */
+ static void
+ Ins_MPS( INS_ARG )
+ {
+ DO_MPS
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* DUP[]: DUPlicate the top stack's element */
+ /* Opcode range: 0x20 */
+ /* Stack: StkElt --> StkElt StkElt */
+ /* */
+ static void
+ Ins_DUP( INS_ARG )
+ {
+ DO_DUP
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* POP[]: POP the stack's top element */
+ /* Opcode range: 0x21 */
+ /* Stack: StkElt --> */
+ /* */
+ static void
+ Ins_POP( INS_ARG )
+ {
+ /* nothing to do */
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* CLEAR[]: CLEAR the entire stack */
+ /* Opcode range: 0x22 */
+ /* Stack: StkElt... --> */
+ /* */
+ static void
+ Ins_CLEAR( INS_ARG )
+ {
+ DO_CLEAR
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* SWAP[]: SWAP the stack's top two elements */
+ /* Opcode range: 0x23 */
+ /* Stack: 2 * StkElt --> 2 * StkElt */
+ /* */
+ static void
+ Ins_SWAP( INS_ARG )
+ {
+ DO_SWAP
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* DEPTH[]: return the stack DEPTH */
+ /* Opcode range: 0x24 */
+ /* Stack: --> uint32 */
+ /* */
+ static void
+ Ins_DEPTH( INS_ARG )
+ {
+ DO_DEPTH
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* CINDEX[]: Copy INDEXed element */
+ /* Opcode range: 0x25 */
+ /* Stack: int32 --> StkElt */
+ /* */
+ static void
+ Ins_CINDEX( INS_ARG )
+ {
+ DO_CINDEX
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* EIF[]: End IF */
+ /* Opcode range: 0x59 */
+ /* Stack: --> */
+ /* */
+ static void
+ Ins_EIF( INS_ARG )
+ {
+ /* nothing to do */
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* JROT[]: Jump Relative On True */
+ /* Opcode range: 0x78 */
+ /* Stack: StkElt int32 --> */
+ /* */
+ static void
+ Ins_JROT( INS_ARG )
+ {
+ DO_JROT
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* JMPR[]: JuMP Relative */
+ /* Opcode range: 0x1C */
+ /* Stack: int32 --> */
+ /* */
+ static void
+ Ins_JMPR( INS_ARG )
+ {
+ DO_JMPR
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* JROF[]: Jump Relative On False */
+ /* Opcode range: 0x79 */
+ /* Stack: StkElt int32 --> */
+ /* */
+ static void
+ Ins_JROF( INS_ARG )
+ {
+ DO_JROF
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* LT[]: Less Than */
+ /* Opcode range: 0x50 */
+ /* Stack: int32? int32? --> bool */
+ /* */
+ static void
+ Ins_LT( INS_ARG )
+ {
+ DO_LT
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* LTEQ[]: Less Than or EQual */
+ /* Opcode range: 0x51 */
+ /* Stack: int32? int32? --> bool */
+ /* */
+ static void
+ Ins_LTEQ( INS_ARG )
+ {
+ DO_LTEQ
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* GT[]: Greater Than */
+ /* Opcode range: 0x52 */
+ /* Stack: int32? int32? --> bool */
+ /* */
+ static void
+ Ins_GT( INS_ARG )
+ {
+ DO_GT
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* GTEQ[]: Greater Than or EQual */
+ /* Opcode range: 0x53 */
+ /* Stack: int32? int32? --> bool */
+ /* */
+ static void
+ Ins_GTEQ( INS_ARG )
+ {
+ DO_GTEQ
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* EQ[]: EQual */
+ /* Opcode range: 0x54 */
+ /* Stack: StkElt StkElt --> bool */
+ /* */
+ static void
+ Ins_EQ( INS_ARG )
+ {
+ DO_EQ
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* NEQ[]: Not EQual */
+ /* Opcode range: 0x55 */
+ /* Stack: StkElt StkElt --> bool */
+ /* */
+ static void
+ Ins_NEQ( INS_ARG )
+ {
+ DO_NEQ
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* ODD[]: Is ODD */
+ /* Opcode range: 0x56 */
+ /* Stack: f26.6 --> bool */
+ /* */
+ static void
+ Ins_ODD( INS_ARG )
+ {
+ DO_ODD
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* EVEN[]: Is EVEN */
+ /* Opcode range: 0x57 */
+ /* Stack: f26.6 --> bool */
+ /* */
+ static void
+ Ins_EVEN( INS_ARG )
+ {
+ DO_EVEN
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* AND[]: logical AND */
+ /* Opcode range: 0x5A */
+ /* Stack: uint32 uint32 --> uint32 */
+ /* */
+ static void
+ Ins_AND( INS_ARG )
+ {
+ DO_AND
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* OR[]: logical OR */
+ /* Opcode range: 0x5B */
+ /* Stack: uint32 uint32 --> uint32 */
+ /* */
+ static void
+ Ins_OR( INS_ARG )
+ {
+ DO_OR
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* NOT[]: logical NOT */
+ /* Opcode range: 0x5C */
+ /* Stack: StkElt --> uint32 */
+ /* */
+ static void
+ Ins_NOT( INS_ARG )
+ {
+ DO_NOT
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* ADD[]: ADD */
+ /* Opcode range: 0x60 */
+ /* Stack: f26.6 f26.6 --> f26.6 */
+ /* */
+ static void
+ Ins_ADD( INS_ARG )
+ {
+ DO_ADD
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* SUB[]: SUBtract */
+ /* Opcode range: 0x61 */
+ /* Stack: f26.6 f26.6 --> f26.6 */
+ /* */
+ static void
+ Ins_SUB( INS_ARG )
+ {
+ DO_SUB
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* DIV[]: DIVide */
+ /* Opcode range: 0x62 */
+ /* Stack: f26.6 f26.6 --> f26.6 */
+ /* */
+ static void
+ Ins_DIV( INS_ARG )
+ {
+ DO_DIV
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* MUL[]: MULtiply */
+ /* Opcode range: 0x63 */
+ /* Stack: f26.6 f26.6 --> f26.6 */
+ /* */
+ static void
+ Ins_MUL( INS_ARG )
+ {
+ DO_MUL
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* ABS[]: ABSolute value */
+ /* Opcode range: 0x64 */
+ /* Stack: f26.6 --> f26.6 */
+ /* */
+ static void
+ Ins_ABS( INS_ARG )
+ {
+ DO_ABS
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* NEG[]: NEGate */
+ /* Opcode range: 0x65 */
+ /* Stack: f26.6 --> f26.6 */
+ /* */
+ static void
+ Ins_NEG( INS_ARG )
+ {
+ DO_NEG
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* FLOOR[]: FLOOR */
+ /* Opcode range: 0x66 */
+ /* Stack: f26.6 --> f26.6 */
+ /* */
+ static void
+ Ins_FLOOR( INS_ARG )
+ {
+ DO_FLOOR
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* CEILING[]: CEILING */
+ /* Opcode range: 0x67 */
+ /* Stack: f26.6 --> f26.6 */
+ /* */
+ static void
+ Ins_CEILING( INS_ARG )
+ {
+ DO_CEILING
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* RS[]: Read Store */
+ /* Opcode range: 0x43 */
+ /* Stack: uint32 --> uint32 */
+ /* */
+ static void
+ Ins_RS( INS_ARG )
+ {
+ DO_RS
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* WS[]: Write Store */
+ /* Opcode range: 0x42 */
+ /* Stack: uint32 uint32 --> */
+ /* */
+ static void
+ Ins_WS( INS_ARG )
+ {
+ DO_WS
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* WCVTP[]: Write CVT in Pixel units */
+ /* Opcode range: 0x44 */
+ /* Stack: f26.6 uint32 --> */
+ /* */
+ static void
+ Ins_WCVTP( INS_ARG )
+ {
+ DO_WCVTP
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* WCVTF[]: Write CVT in Funits */
+ /* Opcode range: 0x70 */
+ /* Stack: uint32 uint32 --> */
+ /* */
+ static void
+ Ins_WCVTF( INS_ARG )
+ {
+ DO_WCVTF
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* RCVT[]: Read CVT */
+ /* Opcode range: 0x45 */
+ /* Stack: uint32 --> f26.6 */
+ /* */
+ static void
+ Ins_RCVT( INS_ARG )
+ {
+ DO_RCVT
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* AA[]: Adjust Angle */
+ /* Opcode range: 0x7F */
+ /* Stack: uint32 --> */
+ /* */
+ static void
+ Ins_AA( INS_ARG )
+ {
+ /* intentionally no longer supported */
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* DEBUG[]: DEBUG. Unsupported. */
+ /* Opcode range: 0x4F */
+ /* Stack: uint32 --> */
+ /* */
+ /* Note: The original instruction pops a value from the stack. */
+ /* */
+ static void
+ Ins_DEBUG( INS_ARG )
+ {
+ DO_DEBUG
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* ROUND[ab]: ROUND value */
+ /* Opcode range: 0x68-0x6B */
+ /* Stack: f26.6 --> f26.6 */
+ /* */
+ static void
+ Ins_ROUND( INS_ARG )
+ {
+ DO_ROUND
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* NROUND[ab]: No ROUNDing of value */
+ /* Opcode range: 0x6C-0x6F */
+ /* Stack: f26.6 --> f26.6 */
+ /* */
+ static void
+ Ins_NROUND( INS_ARG )
+ {
+ DO_NROUND
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* MAX[]: MAXimum */
+ /* Opcode range: 0x68 */
+ /* Stack: int32? int32? --> int32 */
+ /* */
+ static void
+ Ins_MAX( INS_ARG )
+ {
+ DO_MAX
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* MIN[]: MINimum */
+ /* Opcode range: 0x69 */
+ /* Stack: int32? int32? --> int32 */
+ /* */
+ static void
+ Ins_MIN( INS_ARG )
+ {
+ DO_MIN
+ }
+
+
+#endif /* !TT_CONFIG_OPTION_INTERPRETER_SWITCH */
+
+
+ /*************************************************************************/
+ /* */
+ /* The following functions are called as is within the switch statement. */
+ /* */
+ /*************************************************************************/
+
+
+ /*************************************************************************/
+ /* */
+ /* MINDEX[]: Move INDEXed element */
+ /* Opcode range: 0x26 */
+ /* Stack: int32? --> StkElt */
+ /* */
+ static void
+ Ins_MINDEX( INS_ARG )
+ {
+ FT_Long L, K;
+
+
+ L = args[0];
+
+ if ( L <= 0 || L > CUR.args )
+ {
+ CUR.error = TT_Err_Invalid_Reference;
+ return;
+ }
+
+ K = CUR.stack[CUR.args - L];
+
+ FT_MEM_MOVE( &CUR.stack[CUR.args - L ],
+ &CUR.stack[CUR.args - L + 1],
+ ( L - 1 ) * sizeof ( FT_Long ) );
+
+ CUR.stack[CUR.args - 1] = K;
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* ROLL[]: ROLL top three elements */
+ /* Opcode range: 0x8A */
+ /* Stack: 3 * StkElt --> 3 * StkElt */
+ /* */
+ static void
+ Ins_ROLL( INS_ARG )
+ {
+ FT_Long A, B, C;
+
+ FT_UNUSED_EXEC;
+
+
+ A = args[2];
+ B = args[1];
+ C = args[0];
+
+ args[2] = C;
+ args[1] = A;
+ args[0] = B;
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* MANAGING THE FLOW OF CONTROL */
+ /* */
+ /* Instructions appear in the specification's order. */
+ /* */
+ /*************************************************************************/
+
+
+ static FT_Bool
+ SkipCode( EXEC_OP )
+ {
+ CUR.IP += CUR.length;
+
+ if ( CUR.IP < CUR.codeSize )
+ {
+ CUR.opcode = CUR.code[CUR.IP];
+
+ CUR.length = opcode_length[CUR.opcode];
+ if ( CUR.length < 0 )
+ {
+ if ( CUR.IP + 1 > CUR.codeSize )
+ goto Fail_Overflow;
+ CUR.length = CUR.code[CUR.IP + 1] + 2;
+ }
+
+ if ( CUR.IP + CUR.length <= CUR.codeSize )
+ return SUCCESS;
+ }
+
+ Fail_Overflow:
+ CUR.error = TT_Err_Code_Overflow;
+ return FAILURE;
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* IF[]: IF test */
+ /* Opcode range: 0x58 */
+ /* Stack: StkElt --> */
+ /* */
+ static void
+ Ins_IF( INS_ARG )
+ {
+ FT_Int nIfs;
+ FT_Bool Out;
+
+
+ if ( args[0] != 0 )
+ return;
+
+ nIfs = 1;
+ Out = 0;
+
+ do
+ {
+ if ( SKIP_Code() == FAILURE )
+ return;
+
+ switch ( CUR.opcode )
+ {
+ case 0x58: /* IF */
+ nIfs++;
+ break;
+
+ case 0x1B: /* ELSE */
+ Out = FT_BOOL( nIfs == 1 );
+ break;
+
+ case 0x59: /* EIF */
+ nIfs--;
+ Out = FT_BOOL( nIfs == 0 );
+ break;
+ }
+ } while ( Out == 0 );
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* ELSE[]: ELSE */
+ /* Opcode range: 0x1B */
+ /* Stack: --> */
+ /* */
+ static void
+ Ins_ELSE( INS_ARG )
+ {
+ FT_Int nIfs;
+
+ FT_UNUSED_ARG;
+
+
+ nIfs = 1;
+
+ do
+ {
+ if ( SKIP_Code() == FAILURE )
+ return;
+
+ switch ( CUR.opcode )
+ {
+ case 0x58: /* IF */
+ nIfs++;
+ break;
+
+ case 0x59: /* EIF */
+ nIfs--;
+ break;
+ }
+ } while ( nIfs != 0 );
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* DEFINING AND USING FUNCTIONS AND INSTRUCTIONS */
+ /* */
+ /* Instructions appear in the specification's order. */
+ /* */
+ /*************************************************************************/
+
+
+ /*************************************************************************/
+ /* */
+ /* FDEF[]: Function DEFinition */
+ /* Opcode range: 0x2C */
+ /* Stack: uint32 --> */
+ /* */
+ static void
+ Ins_FDEF( INS_ARG )
+ {
+ FT_ULong n;
+ TT_DefRecord* rec;
+ TT_DefRecord* limit;
+
+
+ /* some font programs are broken enough to redefine functions! */
+ /* We will then parse the current table. */
+
+ rec = CUR.FDefs;
+ limit = rec + CUR.numFDefs;
+ n = args[0];
+
+ for ( ; rec < limit; rec++ )
+ {
+ if ( rec->opc == n )
+ break;
+ }
+
+ if ( rec == limit )
+ {
+ /* check that there is enough room for new functions */
+ if ( CUR.numFDefs >= CUR.maxFDefs )
+ {
+ CUR.error = TT_Err_Too_Many_Function_Defs;
+ return;
+ }
+ CUR.numFDefs++;
+ }
+
+ rec->range = CUR.curRange;
+ rec->opc = n;
+ rec->start = CUR.IP + 1;
+ rec->active = TRUE;
+
+ if ( n > CUR.maxFunc )
+ CUR.maxFunc = n;
+
+ /* Now skip the whole function definition. */
+ /* We don't allow nested IDEFS & FDEFs. */
+
+ while ( SKIP_Code() == SUCCESS )
+ {
+ switch ( CUR.opcode )
+ {
+ case 0x89: /* IDEF */
+ case 0x2C: /* FDEF */
+ CUR.error = TT_Err_Nested_DEFS;
+ return;
+
+ case 0x2D: /* ENDF */
+ return;
+ }
+ }
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* ENDF[]: END Function definition */
+ /* Opcode range: 0x2D */
+ /* Stack: --> */
+ /* */
+ static void
+ Ins_ENDF( INS_ARG )
+ {
+ TT_CallRec* pRec;
+
+ FT_UNUSED_ARG;
+
+
+ if ( CUR.callTop <= 0 ) /* We encountered an ENDF without a call */
+ {
+ CUR.error = TT_Err_ENDF_In_Exec_Stream;
+ return;
+ }
+
+ CUR.callTop--;
+
+ pRec = &CUR.callStack[CUR.callTop];
+
+ pRec->Cur_Count--;
+
+ CUR.step_ins = FALSE;
+
+ if ( pRec->Cur_Count > 0 )
+ {
+ CUR.callTop++;
+ CUR.IP = pRec->Cur_Restart;
+ }
+ else
+ /* Loop through the current function */
+ INS_Goto_CodeRange( pRec->Caller_Range,
+ pRec->Caller_IP );
+
+ /* Exit the current call frame. */
+
+ /* NOTE: If the last intruction of a program is a */
+ /* CALL or LOOPCALL, the return address is */
+ /* always out of the code range. This is a */
+ /* valid address, and it is why we do not test */
+ /* the result of Ins_Goto_CodeRange() here! */
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* CALL[]: CALL function */
+ /* Opcode range: 0x2B */
+ /* Stack: uint32? --> */
+ /* */
+ static void
+ Ins_CALL( INS_ARG )
+ {
+ FT_ULong F;
+ TT_CallRec* pCrec;
+ TT_DefRecord* def;
+
+
+ /* first of all, check the index */
+
+ F = args[0];
+ if ( BOUNDS( F, CUR.maxFunc + 1 ) )
+ goto Fail;
+
+ /* Except for some old Apple fonts, all functions in a TrueType */
+ /* font are defined in increasing order, starting from 0. This */
+ /* means that we normally have */
+ /* */
+ /* CUR.maxFunc+1 == CUR.numFDefs */
+ /* CUR.FDefs[n].opc == n for n in 0..CUR.maxFunc */
+ /* */
+ /* If this isn't true, we need to look up the function table. */
+
+ def = CUR.FDefs + F;
+ if ( CUR.maxFunc + 1 != CUR.numFDefs || def->opc != F )
+ {
+ /* look up the FDefs table */
+ TT_DefRecord* limit;
+
+
+ def = CUR.FDefs;
+ limit = def + CUR.numFDefs;
+
+ while ( def < limit && def->opc != F )
+ def++;
+
+ if ( def == limit )
+ goto Fail;
+ }
+
+ /* check that the function is active */
+ if ( !def->active )
+ goto Fail;
+
+ /* check the call stack */
+ if ( CUR.callTop >= CUR.callSize )
+ {
+ CUR.error = TT_Err_Stack_Overflow;
+ return;
+ }
+
+ pCrec = CUR.callStack + CUR.callTop;
+
+ pCrec->Caller_Range = CUR.curRange;
+ pCrec->Caller_IP = CUR.IP + 1;
+ pCrec->Cur_Count = 1;
+ pCrec->Cur_Restart = def->start;
+
+ CUR.callTop++;
+
+ INS_Goto_CodeRange( def->range,
+ def->start );
+
+ CUR.step_ins = FALSE;
+ return;
+
+ Fail:
+ CUR.error = TT_Err_Invalid_Reference;
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* LOOPCALL[]: LOOP and CALL function */
+ /* Opcode range: 0x2A */
+ /* Stack: uint32? Eint16? --> */
+ /* */
+ static void
+ Ins_LOOPCALL( INS_ARG )
+ {
+ FT_ULong F;
+ TT_CallRec* pCrec;
+ TT_DefRecord* def;
+
+
+ /* first of all, check the index */
+ F = args[1];
+ if ( BOUNDS( F, CUR.maxFunc + 1 ) )
+ goto Fail;
+
+ /* Except for some old Apple fonts, all functions in a TrueType */
+ /* font are defined in increasing order, starting from 0. This */
+ /* means that we normally have */
+ /* */
+ /* CUR.maxFunc+1 == CUR.numFDefs */
+ /* CUR.FDefs[n].opc == n for n in 0..CUR.maxFunc */
+ /* */
+ /* If this isn't true, we need to look up the function table. */
+
+ def = CUR.FDefs + F;
+ if ( CUR.maxFunc + 1 != CUR.numFDefs || def->opc != F )
+ {
+ /* look up the FDefs table */
+ TT_DefRecord* limit;
+
+
+ def = CUR.FDefs;
+ limit = def + CUR.numFDefs;
+
+ while ( def < limit && def->opc != F )
+ def++;
+
+ if ( def == limit )
+ goto Fail;
+ }
+
+ /* check that the function is active */
+ if ( !def->active )
+ goto Fail;
+
+ /* check stack */
+ if ( CUR.callTop >= CUR.callSize )
+ {
+ CUR.error = TT_Err_Stack_Overflow;
+ return;
+ }
+
+ if ( args[0] > 0 )
+ {
+ pCrec = CUR.callStack + CUR.callTop;
+
+ pCrec->Caller_Range = CUR.curRange;
+ pCrec->Caller_IP = CUR.IP + 1;
+ pCrec->Cur_Count = (FT_Int)args[0];
+ pCrec->Cur_Restart = def->start;
+
+ CUR.callTop++;
+
+ INS_Goto_CodeRange( def->range, def->start );
+
+ CUR.step_ins = FALSE;
+ }
+ return;
+
+ Fail:
+ CUR.error = TT_Err_Invalid_Reference;
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* IDEF[]: Instruction DEFinition */
+ /* Opcode range: 0x89 */
+ /* Stack: Eint8 --> */
+ /* */
+ static void
+ Ins_IDEF( INS_ARG )
+ {
+ TT_DefRecord* def;
+ TT_DefRecord* limit;
+
+
+ /* First of all, look for the same function in our table */
+
+ def = CUR.IDefs;
+ limit = def + CUR.numIDefs;
+
+ for ( ; def < limit; def++ )
+ if ( def->opc == (FT_ULong)args[0] )
+ break;
+
+ if ( def == limit )
+ {
+ /* check that there is enough room for a new instruction */
+ if ( CUR.numIDefs >= CUR.maxIDefs )
+ {
+ CUR.error = TT_Err_Too_Many_Instruction_Defs;
+ return;
+ }
+ CUR.numIDefs++;
+ }
+
+ def->opc = args[0];
+ def->start = CUR.IP+1;
+ def->range = CUR.curRange;
+ def->active = TRUE;
+
+ if ( (FT_ULong)args[0] > CUR.maxIns )
+ CUR.maxIns = args[0];
+
+ /* Now skip the whole function definition. */
+ /* We don't allow nested IDEFs & FDEFs. */
+
+ while ( SKIP_Code() == SUCCESS )
+ {
+ switch ( CUR.opcode )
+ {
+ case 0x89: /* IDEF */
+ case 0x2C: /* FDEF */
+ CUR.error = TT_Err_Nested_DEFS;
+ return;
+ case 0x2D: /* ENDF */
+ return;
+ }
+ }
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* PUSHING DATA ONTO THE INTERPRETER STACK */
+ /* */
+ /* Instructions appear in the specification's order. */
+ /* */
+ /*************************************************************************/
+
+
+ /*************************************************************************/
+ /* */
+ /* NPUSHB[]: PUSH N Bytes */
+ /* Opcode range: 0x40 */
+ /* Stack: --> uint32... */
+ /* */
+ static void
+ Ins_NPUSHB( INS_ARG )
+ {
+ FT_UShort L, K;
+
+
+ L = (FT_UShort)CUR.code[CUR.IP + 1];
+
+ if ( BOUNDS( L, CUR.stackSize + 1 - CUR.top ) )
+ {
+ CUR.error = TT_Err_Stack_Overflow;
+ return;
+ }
+
+ for ( K = 1; K <= L; K++ )
+ args[K - 1] = CUR.code[CUR.IP + K + 1];
+
+ CUR.new_top += L;
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* NPUSHW[]: PUSH N Words */
+ /* Opcode range: 0x41 */
+ /* Stack: --> int32... */
+ /* */
+ static void
+ Ins_NPUSHW( INS_ARG )
+ {
+ FT_UShort L, K;
+
+
+ L = (FT_UShort)CUR.code[CUR.IP + 1];
+
+ if ( BOUNDS( L, CUR.stackSize + 1 - CUR.top ) )
+ {
+ CUR.error = TT_Err_Stack_Overflow;
+ return;
+ }
+
+ CUR.IP += 2;
+
+ for ( K = 0; K < L; K++ )
+ args[K] = GET_ShortIns();
+
+ CUR.step_ins = FALSE;
+ CUR.new_top += L;
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* PUSHB[abc]: PUSH Bytes */
+ /* Opcode range: 0xB0-0xB7 */
+ /* Stack: --> uint32... */
+ /* */
+ static void
+ Ins_PUSHB( INS_ARG )
+ {
+ FT_UShort L, K;
+
+
+ L = (FT_UShort)(CUR.opcode - 0xB0 + 1);
+
+ if ( BOUNDS( L, CUR.stackSize + 1 - CUR.top ) )
+ {
+ CUR.error = TT_Err_Stack_Overflow;
+ return;
+ }
+
+ for ( K = 1; K <= L; K++ )
+ args[K - 1] = CUR.code[CUR.IP + K];
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* PUSHW[abc]: PUSH Words */
+ /* Opcode range: 0xB8-0xBF */
+ /* Stack: --> int32... */
+ /* */
+ static void
+ Ins_PUSHW( INS_ARG )
+ {
+ FT_UShort L, K;
+
+
+ L = (FT_UShort)(CUR.opcode - 0xB8 + 1);
+
+ if ( BOUNDS( L, CUR.stackSize + 1 - CUR.top ) )
+ {
+ CUR.error = TT_Err_Stack_Overflow;
+ return;
+ }
+
+ CUR.IP++;
+
+ for ( K = 0; K < L; K++ )
+ args[K] = GET_ShortIns();
+
+ CUR.step_ins = FALSE;
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* MANAGING THE GRAPHICS STATE */
+ /* */
+ /* Instructions appear in the specs' order. */
+ /* */
+ /*************************************************************************/
+
+
+ /*************************************************************************/
+ /* */
+ /* GC[a]: Get Coordinate projected onto */
+ /* Opcode range: 0x46-0x47 */
+ /* Stack: uint32 --> f26.6 */
+ /* */
+ /* BULLSHIT: Measures from the original glyph must be taken along the */
+ /* dual projection vector! */
+ /* */
+ static void
+ Ins_GC( INS_ARG )
+ {
+ FT_ULong L;
+ FT_F26Dot6 R;
+
+
+ L = (FT_ULong)args[0];
+
+ if ( BOUNDS( L, CUR.zp2.n_points ) )
+ {
+ if ( CUR.pedantic_hinting )
+ {
+ CUR.error = TT_Err_Invalid_Reference;
+ return;
+ }
+ else
+ R = 0;
+ }
+ else
+ {
+ if ( CUR.opcode & 1 )
+ R = CUR_Func_dualproj( CUR.zp2.org + L, NULL_Vector );
+ else
+ R = CUR_Func_project( CUR.zp2.cur + L, NULL_Vector );
+ }
+
+ args[0] = R;
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* SCFS[]: Set Coordinate From Stack */
+ /* Opcode range: 0x48 */
+ /* Stack: f26.6 uint32 --> */
+ /* */
+ /* Formula: */
+ /* */
+ /* OA := OA + ( value - OA.p )/( f.p ) * f */
+ /* */
+ static void
+ Ins_SCFS( INS_ARG )
+ {
+ FT_Long K;
+ FT_UShort L;
+
+
+ L = (FT_UShort)args[0];
+
+ if ( BOUNDS( L, CUR.zp2.n_points ) )
+ {
+ if ( CUR.pedantic_hinting )
+ CUR.error = TT_Err_Invalid_Reference;
+ return;
+ }
+
+ K = CUR_Func_project( CUR.zp2.cur + L, NULL_Vector );
+
+ CUR_Func_move( &CUR.zp2, L, args[1] - K );
+
+ /* not part of the specs, but here for safety */
+
+ if ( CUR.GS.gep2 == 0 )
+ CUR.zp2.org[L] = CUR.zp2.cur[L];
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* MD[a]: Measure Distance */
+ /* Opcode range: 0x49-0x4A */
+ /* Stack: uint32 uint32 --> f26.6 */
+ /* */
+ /* BULLSHIT: Measure taken in the original glyph must be along the dual */
+ /* projection vector. */
+ /* */
+ /* Second BULLSHIT: Flag attributes are inverted! */
+ /* 0 => measure distance in original outline */
+ /* 1 => measure distance in grid-fitted outline */
+ /* */
+ /* Third one: `zp0 - zp1', and not `zp2 - zp1! */
+ /* */
+ static void
+ Ins_MD( INS_ARG )
+ {
+ FT_UShort K, L;
+ FT_F26Dot6 D;
+
+
+ K = (FT_UShort)args[1];
+ L = (FT_UShort)args[0];
+
+ if( BOUNDS( L, CUR.zp0.n_points ) ||
+ BOUNDS( K, CUR.zp1.n_points ) )
+ {
+ if ( CUR.pedantic_hinting )
+ {
+ CUR.error = TT_Err_Invalid_Reference;
+ return;
+ }
+ D = 0;
+ }
+ else
+ {
+ if ( CUR.opcode & 1 )
+ D = CUR_Func_project( CUR.zp0.cur + L, CUR.zp1.cur + K );
+ else
+ D = CUR_Func_dualproj( CUR.zp0.org + L, CUR.zp1.org + K );
+ }
+
+ args[0] = D;
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* SDPVTL[a]: Set Dual PVector to Line */
+ /* Opcode range: 0x86-0x87 */
+ /* Stack: uint32 uint32 --> */
+ /* */
+ static void
+ Ins_SDPVTL( INS_ARG )
+ {
+ FT_Long A, B, C;
+ FT_UShort p1, p2; /* was FT_Int in pas type ERROR */
+
+
+ p1 = (FT_UShort)args[1];
+ p2 = (FT_UShort)args[0];
+
+ if ( BOUNDS( p2, CUR.zp1.n_points ) ||
+ BOUNDS( p1, CUR.zp2.n_points ) )
+ {
+ if ( CUR.pedantic_hinting )
+ CUR.error = TT_Err_Invalid_Reference;
+ return;
+ }
+
+ {
+ FT_Vector* v1 = CUR.zp1.org + p2;
+ FT_Vector* v2 = CUR.zp2.org + p1;
+
+
+ A = v1->x - v2->x;
+ B = v1->y - v2->y;
+ }
+
+ if ( ( CUR.opcode & 1 ) != 0 )
+ {
+ C = B; /* counter clockwise rotation */
+ B = A;
+ A = -C;
+ }
+
+ NORMalize( A, B, &CUR.GS.dualVector );
+
+ {
+ FT_Vector* v1 = CUR.zp1.cur + p2;
+ FT_Vector* v2 = CUR.zp2.cur + p1;
+
+
+ A = v1->x - v2->x;
+ B = v1->y - v2->y;
+ }
+
+ if ( ( CUR.opcode & 1 ) != 0 )
+ {
+ C = B; /* counter clockwise rotation */
+ B = A;
+ A = -C;
+ }
+
+ NORMalize( A, B, &CUR.GS.projVector );
+
+ COMPUTE_Funcs();
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* SZP0[]: Set Zone Pointer 0 */
+ /* Opcode range: 0x13 */
+ /* Stack: uint32 --> */
+ /* */
+ static void
+ Ins_SZP0( INS_ARG )
+ {
+ switch ( (FT_Int)args[0] )
+ {
+ case 0:
+ CUR.zp0 = CUR.twilight;
+ break;
+
+ case 1:
+ CUR.zp0 = CUR.pts;
+ break;
+
+ default:
+ if ( CUR.pedantic_hinting )
+ CUR.error = TT_Err_Invalid_Reference;
+ return;
+ }
+
+ CUR.GS.gep0 = (FT_UShort)args[0];
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* SZP1[]: Set Zone Pointer 1 */
+ /* Opcode range: 0x14 */
+ /* Stack: uint32 --> */
+ /* */
+ static void
+ Ins_SZP1( INS_ARG )
+ {
+ switch ( (FT_Int)args[0] )
+ {
+ case 0:
+ CUR.zp1 = CUR.twilight;
+ break;
+
+ case 1:
+ CUR.zp1 = CUR.pts;
+ break;
+
+ default:
+ if ( CUR.pedantic_hinting )
+ CUR.error = TT_Err_Invalid_Reference;
+ return;
+ }
+
+ CUR.GS.gep1 = (FT_UShort)args[0];
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* SZP2[]: Set Zone Pointer 2 */
+ /* Opcode range: 0x15 */
+ /* Stack: uint32 --> */
+ /* */
+ static void
+ Ins_SZP2( INS_ARG )
+ {
+ switch ( (FT_Int)args[0] )
+ {
+ case 0:
+ CUR.zp2 = CUR.twilight;
+ break;
+
+ case 1:
+ CUR.zp2 = CUR.pts;
+ break;
+
+ default:
+ if ( CUR.pedantic_hinting )
+ CUR.error = TT_Err_Invalid_Reference;
+ return;
+ }
+
+ CUR.GS.gep2 = (FT_UShort)args[0];
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* SZPS[]: Set Zone PointerS */
+ /* Opcode range: 0x16 */
+ /* Stack: uint32 --> */
+ /* */
+ static void
+ Ins_SZPS( INS_ARG )
+ {
+ switch ( (FT_Int)args[0] )
+ {
+ case 0:
+ CUR.zp0 = CUR.twilight;
+ break;
+
+ case 1:
+ CUR.zp0 = CUR.pts;
+ break;
+
+ default:
+ if ( CUR.pedantic_hinting )
+ CUR.error = TT_Err_Invalid_Reference;
+ return;
+ }
+
+ CUR.zp1 = CUR.zp0;
+ CUR.zp2 = CUR.zp0;
+
+ CUR.GS.gep0 = (FT_UShort)args[0];
+ CUR.GS.gep1 = (FT_UShort)args[0];
+ CUR.GS.gep2 = (FT_UShort)args[0];
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* INSTCTRL[]: INSTruction ConTRoL */
+ /* Opcode range: 0x8e */
+ /* Stack: int32 int32 --> */
+ /* */
+ static void
+ Ins_INSTCTRL( INS_ARG )
+ {
+ FT_Long K, L;
+
+
+ K = args[1];
+ L = args[0];
+
+ if ( K < 1 || K > 2 )
+ {
+ if ( CUR.pedantic_hinting )
+ CUR.error = TT_Err_Invalid_Reference;
+ return;
+ }
+
+ if ( L != 0 )
+ L = K;
+
+ CUR.GS.instruct_control = FT_BOOL(
+ ( (FT_Byte)CUR.GS.instruct_control & ~(FT_Byte)K ) | (FT_Byte)L );
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* SCANCTRL[]: SCAN ConTRoL */
+ /* Opcode range: 0x85 */
+ /* Stack: uint32? --> */
+ /* */
+ static void
+ Ins_SCANCTRL( INS_ARG )
+ {
+ FT_Int A;
+
+
+ /* Get Threshold */
+ A = (FT_Int)( args[0] & 0xFF );
+
+ if ( A == 0xFF )
+ {
+ CUR.GS.scan_control = TRUE;
+ return;
+ }
+ else if ( A == 0 )
+ {
+ CUR.GS.scan_control = FALSE;
+ return;
+ }
+
+ A *= 64;
+
+#if 0
+ if ( (args[0] & 0x100) != 0 && CUR.metrics.pointSize <= A )
+ CUR.GS.scan_control = TRUE;
+#endif
+
+ if ( (args[0] & 0x200) != 0 && CUR.tt_metrics.rotated )
+ CUR.GS.scan_control = TRUE;
+
+ if ( (args[0] & 0x400) != 0 && CUR.tt_metrics.stretched )
+ CUR.GS.scan_control = TRUE;
+
+#if 0
+ if ( (args[0] & 0x800) != 0 && CUR.metrics.pointSize > A )
+ CUR.GS.scan_control = FALSE;
+#endif
+
+ if ( (args[0] & 0x1000) != 0 && CUR.tt_metrics.rotated )
+ CUR.GS.scan_control = FALSE;
+
+ if ( (args[0] & 0x2000) != 0 && CUR.tt_metrics.stretched )
+ CUR.GS.scan_control = FALSE;
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* SCANTYPE[]: SCAN TYPE */
+ /* Opcode range: 0x8D */
+ /* Stack: uint32? --> */
+ /* */
+ static void
+ Ins_SCANTYPE( INS_ARG )
+ {
+ /* for compatibility with future enhancements, */
+ /* we must ignore new modes */
+
+ if ( args[0] >= 0 && args[0] <= 5 )
+ {
+ if ( args[0] == 3 )
+ args[0] = 2;
+
+ CUR.GS.scan_type = (FT_Int)args[0];
+ }
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* MANAGING OUTLINES */
+ /* */
+ /* Instructions appear in the specification's order. */
+ /* */
+ /*************************************************************************/
+
+
+ /*************************************************************************/
+ /* */
+ /* FLIPPT[]: FLIP PoinT */
+ /* Opcode range: 0x80 */
+ /* Stack: uint32... --> */
+ /* */
+ static void
+ Ins_FLIPPT( INS_ARG )
+ {
+ FT_UShort point;
+
+ FT_UNUSED_ARG;
+
+
+ if ( CUR.top < CUR.GS.loop )
+ {
+ CUR.error = TT_Err_Too_Few_Arguments;
+ return;
+ }
+
+ while ( CUR.GS.loop > 0 )
+ {
+ CUR.args--;
+
+ point = (FT_UShort)CUR.stack[CUR.args];
+
+ if ( BOUNDS( point, CUR.pts.n_points ) )
+ {
+ if ( CUR.pedantic_hinting )
+ {
+ CUR.error = TT_Err_Invalid_Reference;
+ return;
+ }
+ }
+ else
+ CUR.pts.tags[point] ^= FT_CURVE_TAG_ON;
+
+ CUR.GS.loop--;
+ }
+
+ CUR.GS.loop = 1;
+ CUR.new_top = CUR.args;
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* FLIPRGON[]: FLIP RanGe ON */
+ /* Opcode range: 0x81 */
+ /* Stack: uint32 uint32 --> */
+ /* */
+ static void
+ Ins_FLIPRGON( INS_ARG )
+ {
+ FT_UShort I, K, L;
+
+
+ K = (FT_UShort)args[1];
+ L = (FT_UShort)args[0];
+
+ if ( BOUNDS( K, CUR.pts.n_points ) ||
+ BOUNDS( L, CUR.pts.n_points ) )
+ {
+ if ( CUR.pedantic_hinting )
+ CUR.error = TT_Err_Invalid_Reference;
+ return;
+ }
+
+ for ( I = L; I <= K; I++ )
+ CUR.pts.tags[I] |= FT_CURVE_TAG_ON;
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* FLIPRGOFF: FLIP RanGe OFF */
+ /* Opcode range: 0x82 */
+ /* Stack: uint32 uint32 --> */
+ /* */
+ static void
+ Ins_FLIPRGOFF( INS_ARG )
+ {
+ FT_UShort I, K, L;
+
+
+ K = (FT_UShort)args[1];
+ L = (FT_UShort)args[0];
+
+ if ( BOUNDS( K, CUR.pts.n_points ) ||
+ BOUNDS( L, CUR.pts.n_points ) )
+ {
+ if ( CUR.pedantic_hinting )
+ CUR.error = TT_Err_Invalid_Reference;
+ return;
+ }
+
+ for ( I = L; I <= K; I++ )
+ CUR.pts.tags[I] &= ~FT_CURVE_TAG_ON;
+ }
+
+
+ static FT_Bool
+ Compute_Point_Displacement( EXEC_OP_ FT_F26Dot6* x,
+ FT_F26Dot6* y,
+ TT_GlyphZone zone,
+ FT_UShort* refp )
+ {
+ TT_GlyphZoneRec zp;
+ FT_UShort p;
+ FT_F26Dot6 d;
+
+
+ if ( CUR.opcode & 1 )
+ {
+ zp = CUR.zp0;
+ p = CUR.GS.rp1;
+ }
+ else
+ {
+ zp = CUR.zp1;
+ p = CUR.GS.rp2;
+ }
+
+ if ( BOUNDS( p, zp.n_points ) )
+ {
+ if ( CUR.pedantic_hinting )
+ CUR.error = TT_Err_Invalid_Reference;
+ return FAILURE;
+ }
+
+ *zone = zp;
+ *refp = p;
+
+ d = CUR_Func_project( zp.cur + p, zp.org + p );
+
+#ifdef NO_APPLE_PATENT
+
+ *x = TT_MulFix14( d, CUR.GS.freeVector.x );
+ *y = TT_MulFix14( d, CUR.GS.freeVector.y );
+
+#else
+
+ *x = TT_MULDIV( d,
+ (FT_Long)CUR.GS.freeVector.x * 0x10000L,
+ CUR.F_dot_P );
+ *y = TT_MULDIV( d,
+ (FT_Long)CUR.GS.freeVector.y * 0x10000L,
+ CUR.F_dot_P );
+
+#endif /* NO_APPLE_PATENT */
+
+ return SUCCESS;
+ }
+
+
+ static void
+ Move_Zp2_Point( EXEC_OP_ FT_UShort point,
+ FT_F26Dot6 dx,
+ FT_F26Dot6 dy,
+ FT_Bool touch )
+ {
+ if ( CUR.GS.freeVector.x != 0 )
+ {
+ CUR.zp2.cur[point].x += dx;
+ if ( touch )
+ CUR.zp2.tags[point] |= FT_CURVE_TAG_TOUCH_X;
+ }
+
+ if ( CUR.GS.freeVector.y != 0 )
+ {
+ CUR.zp2.cur[point].y += dy;
+ if ( touch )
+ CUR.zp2.tags[point] |= FT_CURVE_TAG_TOUCH_Y;
+ }
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* SHP[a]: SHift Point by the last point */
+ /* Opcode range: 0x32-0x33 */
+ /* Stack: uint32... --> */
+ /* */
+ static void
+ Ins_SHP( INS_ARG )
+ {
+ TT_GlyphZoneRec zp;
+ FT_UShort refp;
+
+ FT_F26Dot6 dx,
+ dy;
+ FT_UShort point;
+
+ FT_UNUSED_ARG;
+
+
+ if ( CUR.top < CUR.GS.loop )
+ {
+ CUR.error = TT_Err_Invalid_Reference;
+ return;
+ }
+
+ if ( COMPUTE_Point_Displacement( &dx, &dy, &zp, &refp ) )
+ return;
+
+ while ( CUR.GS.loop > 0 )
+ {
+ CUR.args--;
+ point = (FT_UShort)CUR.stack[CUR.args];
+
+ if ( BOUNDS( point, CUR.zp2.n_points ) )
+ {
+ if ( CUR.pedantic_hinting )
+ {
+ CUR.error = TT_Err_Invalid_Reference;
+ return;
+ }
+ }
+ else
+ /* XXX: UNDOCUMENTED! SHP touches the points */
+ MOVE_Zp2_Point( point, dx, dy, TRUE );
+
+ CUR.GS.loop--;
+ }
+
+ CUR.GS.loop = 1;
+ CUR.new_top = CUR.args;
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* SHC[a]: SHift Contour */
+ /* Opcode range: 0x34-35 */
+ /* Stack: uint32 --> */
+ /* */
+ static void
+ Ins_SHC( INS_ARG )
+ {
+ TT_GlyphZoneRec zp;
+ FT_UShort refp;
+ FT_F26Dot6 dx,
+ dy;
+
+ FT_Short contour;
+ FT_UShort first_point, last_point, i;
+
+
+ contour = (FT_UShort)args[0];
+
+ if ( BOUNDS( contour, CUR.pts.n_contours ) )
+ {
+ if ( CUR.pedantic_hinting )
+ CUR.error = TT_Err_Invalid_Reference;
+ return;
+ }
+
+ if ( COMPUTE_Point_Displacement( &dx, &dy, &zp, &refp ) )
+ return;
+
+ if ( contour == 0 )
+ first_point = 0;
+ else
+ first_point = (FT_UShort)(CUR.pts.contours[contour - 1] + 1);
+
+ last_point = CUR.pts.contours[contour];
+
+ /* XXX: this is probably wrong... at least it prevents memory */
+ /* corruption when zp2 is the twilight zone */
+ if ( last_point > CUR.zp2.n_points )
+ {
+ if ( CUR.zp2.n_points > 0 )
+ last_point = (FT_UShort)(CUR.zp2.n_points - 1);
+ else
+ last_point = 0;
+ }
+
+ /* XXX: UNDOCUMENTED! SHC doesn't touch the points */
+ for ( i = first_point; i <= last_point; i++ )
+ {
+ if ( zp.cur != CUR.zp2.cur || refp != i )
+ MOVE_Zp2_Point( i, dx, dy, FALSE );
+ }
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* SHZ[a]: SHift Zone */
+ /* Opcode range: 0x36-37 */
+ /* Stack: uint32 --> */
+ /* */
+ static void
+ Ins_SHZ( INS_ARG )
+ {
+ TT_GlyphZoneRec zp;
+ FT_UShort refp;
+ FT_F26Dot6 dx,
+ dy;
+
+ FT_UShort last_point, i;
+
+
+ if ( BOUNDS( args[0], 2 ) )
+ {
+ if ( CUR.pedantic_hinting )
+ CUR.error = TT_Err_Invalid_Reference;
+ return;
+ }
+
+ if ( COMPUTE_Point_Displacement( &dx, &dy, &zp, &refp ) )
+ return;
+
+ if ( CUR.zp2.n_points > 0 )
+ last_point = (FT_UShort)(CUR.zp2.n_points - 1);
+ else
+ last_point = 0;
+
+ /* XXX: UNDOCUMENTED! SHZ doesn't touch the points */
+ for ( i = 0; i <= last_point; i++ )
+ {
+ if ( zp.cur != CUR.zp2.cur || refp != i )
+ MOVE_Zp2_Point( i, dx, dy, FALSE );
+ }
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* SHPIX[]: SHift points by a PIXel amount */
+ /* Opcode range: 0x38 */
+ /* Stack: f26.6 uint32... --> */
+ /* */
+ static void
+ Ins_SHPIX( INS_ARG )
+ {
+ FT_F26Dot6 dx, dy;
+ FT_UShort point;
+
+
+ if ( CUR.top < CUR.GS.loop + 1 )
+ {
+ CUR.error = TT_Err_Invalid_Reference;
+ return;
+ }
+
+ dx = TT_MulFix14( args[0], CUR.GS.freeVector.x );
+ dy = TT_MulFix14( args[0], CUR.GS.freeVector.y );
+
+ while ( CUR.GS.loop > 0 )
+ {
+ CUR.args--;
+
+ point = (FT_UShort)CUR.stack[CUR.args];
+
+ if ( BOUNDS( point, CUR.zp2.n_points ) )
+ {
+ if ( CUR.pedantic_hinting )
+ {
+ CUR.error = TT_Err_Invalid_Reference;
+ return;
+ }
+ }
+ else
+ MOVE_Zp2_Point( point, dx, dy, TRUE );
+
+ CUR.GS.loop--;
+ }
+
+ CUR.GS.loop = 1;
+ CUR.new_top = CUR.args;
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* MSIRP[a]: Move Stack Indirect Relative Position */
+ /* Opcode range: 0x3A-0x3B */
+ /* Stack: f26.6 uint32 --> */
+ /* */
+ static void
+ Ins_MSIRP( INS_ARG )
+ {
+ FT_UShort point;
+ FT_F26Dot6 distance;
+
+
+ point = (FT_UShort)args[0];
+
+ if ( BOUNDS( point, CUR.zp1.n_points ) ||
+ BOUNDS( CUR.GS.rp0, CUR.zp0.n_points ) )
+ {
+ if ( CUR.pedantic_hinting )
+ CUR.error = TT_Err_Invalid_Reference;
+ return;
+ }
+
+ /* XXX: UNDOCUMENTED! behaviour */
+ if ( CUR.GS.gep0 == 0 ) /* if in twilight zone */
+ {
+ CUR.zp1.org[point] = CUR.zp0.org[CUR.GS.rp0];
+ CUR.zp1.cur[point] = CUR.zp1.org[point];
+ }
+
+ distance = CUR_Func_project( CUR.zp1.cur + point,
+ CUR.zp0.cur + CUR.GS.rp0 );
+
+ CUR_Func_move( &CUR.zp1, point, args[1] - distance );
+
+ CUR.GS.rp1 = CUR.GS.rp0;
+ CUR.GS.rp2 = point;
+
+ if ( (CUR.opcode & 1) != 0 )
+ CUR.GS.rp0 = point;
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* MDAP[a]: Move Direct Absolute Point */
+ /* Opcode range: 0x2E-0x2F */
+ /* Stack: uint32 --> */
+ /* */
+ static void
+ Ins_MDAP( INS_ARG )
+ {
+ FT_UShort point;
+ FT_F26Dot6 cur_dist,
+ distance;
+
+
+ point = (FT_UShort)args[0];
+
+ if ( BOUNDS( point, CUR.zp0.n_points ) )
+ {
+ if ( CUR.pedantic_hinting )
+ CUR.error = TT_Err_Invalid_Reference;
+ return;
+ }
+
+ /* XXX: Is there some undocumented feature while in the */
+ /* twilight zone? ? */
+ if ( ( CUR.opcode & 1 ) != 0 )
+ {
+ cur_dist = CUR_Func_project( CUR.zp0.cur + point, NULL_Vector );
+ distance = CUR_Func_round( cur_dist,
+ CUR.tt_metrics.compensations[0] ) - cur_dist;
+ }
+ else
+ distance = 0;
+
+ CUR_Func_move( &CUR.zp0, point, distance );
+
+ CUR.GS.rp0 = point;
+ CUR.GS.rp1 = point;
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* MIAP[a]: Move Indirect Absolute Point */
+ /* Opcode range: 0x3E-0x3F */
+ /* Stack: uint32 uint32 --> */
+ /* */
+ static void
+ Ins_MIAP( INS_ARG )
+ {
+ FT_ULong cvtEntry;
+ FT_UShort point;
+ FT_F26Dot6 distance,
+ org_dist;
+
+
+ cvtEntry = (FT_ULong)args[1];
+ point = (FT_UShort)args[0];
+
+ if ( BOUNDS( point, CUR.zp0.n_points ) ||
+ BOUNDS( cvtEntry, CUR.cvtSize ) )
+ {
+ if ( CUR.pedantic_hinting )
+ CUR.error = TT_Err_Invalid_Reference;
+ return;
+ }
+
+ /* UNDOCUMENTED! */
+ /* */
+ /* The behaviour of an MIAP instruction is quite */
+ /* different when used in the twilight zone. */
+ /* */
+ /* First, no control value cutin test is performed */
+ /* as it would fail anyway. Second, the original */
+ /* point, i.e. (org_x,org_y) of zp0.point, is set */
+ /* to the absolute, unrounded distance found in */
+ /* the CVT. */
+ /* */
+ /* This is used in the CVT programs of the Microsoft */
+ /* fonts Arial, Times, etc., in order to re-adjust */
+ /* some key font heights. It allows the use of the */
+ /* IP instruction in the twilight zone, which */
+ /* otherwise would be `illegal' according to the */
+ /* specification. */
+ /* */
+ /* We implement it with a special sequence for the */
+ /* twilight zone. This is a bad hack, but it seems */
+ /* to work. */
+
+ distance = CUR_Func_read_cvt( cvtEntry );
+
+ if ( CUR.GS.gep0 == 0 ) /* If in twilight zone */
+ {
+ CUR.zp0.org[point].x = TT_MulFix14( distance, CUR.GS.freeVector.x );
+ CUR.zp0.org[point].y = TT_MulFix14( distance, CUR.GS.freeVector.y ),
+ CUR.zp0.cur[point] = CUR.zp0.org[point];
+ }
+
+ org_dist = CUR_Func_project( CUR.zp0.cur + point, NULL_Vector );
+
+ if ( ( CUR.opcode & 1 ) != 0 ) /* rounding and control cutin flag */
+ {
+ if ( ABS( distance - org_dist ) > CUR.GS.control_value_cutin )
+ distance = org_dist;
+
+ distance = CUR_Func_round( distance, CUR.tt_metrics.compensations[0] );
+ }
+
+ CUR_Func_move( &CUR.zp0, point, distance - org_dist );
+
+ CUR.GS.rp0 = point;
+ CUR.GS.rp1 = point;
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* MDRP[abcde]: Move Direct Relative Point */
+ /* Opcode range: 0xC0-0xDF */
+ /* Stack: uint32 --> */
+ /* */
+ static void
+ Ins_MDRP( INS_ARG )
+ {
+ FT_UShort point;
+ FT_F26Dot6 org_dist, distance;
+
+
+ point = (FT_UShort)args[0];
+
+ if ( BOUNDS( point, CUR.zp1.n_points ) ||
+ BOUNDS( CUR.GS.rp0, CUR.zp0.n_points ) )
+ {
+ if ( CUR.pedantic_hinting )
+ CUR.error = TT_Err_Invalid_Reference;
+ return;
+ }
+
+ /* XXX: Is there some undocumented feature while in the */
+ /* twilight zone? */
+
+ org_dist = CUR_Func_dualproj( CUR.zp1.org + point,
+ CUR.zp0.org + CUR.GS.rp0 );
+
+ /* single width cutin test */
+
+ if ( ABS( org_dist ) < CUR.GS.single_width_cutin )
+ {
+ if ( org_dist >= 0 )
+ org_dist = CUR.GS.single_width_value;
+ else
+ org_dist = -CUR.GS.single_width_value;
+ }
+
+ /* round flag */
+
+ if ( ( CUR.opcode & 4 ) != 0 )
+ distance = CUR_Func_round(
+ org_dist,
+ CUR.tt_metrics.compensations[CUR.opcode & 3] );
+ else
+ distance = ROUND_None(
+ org_dist,
+ CUR.tt_metrics.compensations[CUR.opcode & 3] );
+
+ /* minimum distance flag */
+
+ if ( ( CUR.opcode & 8 ) != 0 )
+ {
+ if ( org_dist >= 0 )
+ {
+ if ( distance < CUR.GS.minimum_distance )
+ distance = CUR.GS.minimum_distance;
+ }
+ else
+ {
+ if ( distance > -CUR.GS.minimum_distance )
+ distance = -CUR.GS.minimum_distance;
+ }
+ }
+
+ /* now move the point */
+
+ org_dist = CUR_Func_project( CUR.zp1.cur + point,
+ CUR.zp0.cur + CUR.GS.rp0 );
+
+ CUR_Func_move( &CUR.zp1, point, distance - org_dist );
+
+ CUR.GS.rp1 = CUR.GS.rp0;
+ CUR.GS.rp2 = point;
+
+ if ( ( CUR.opcode & 16 ) != 0 )
+ CUR.GS.rp0 = point;
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* MIRP[abcde]: Move Indirect Relative Point */
+ /* Opcode range: 0xE0-0xFF */
+ /* Stack: int32? uint32 --> */
+ /* */
+ static void
+ Ins_MIRP( INS_ARG )
+ {
+ FT_UShort point;
+ FT_ULong cvtEntry;
+
+ FT_F26Dot6 cvt_dist,
+ distance,
+ cur_dist,
+ org_dist;
+
+
+ point = (FT_UShort)args[0];
+ cvtEntry = (FT_ULong)( args[1] + 1 );
+
+ /* XXX: UNDOCUMENTED! cvt[-1] = 0 always */
+
+ if ( BOUNDS( point, CUR.zp1.n_points ) ||
+ BOUNDS( cvtEntry, CUR.cvtSize + 1 ) ||
+ BOUNDS( CUR.GS.rp0, CUR.zp0.n_points ) )
+ {
+ if ( CUR.pedantic_hinting )
+ CUR.error = TT_Err_Invalid_Reference;
+ return;
+ }
+
+ if ( !cvtEntry )
+ cvt_dist = 0;
+ else
+ cvt_dist = CUR_Func_read_cvt( cvtEntry - 1 );
+
+ /* single width test */
+
+ if ( ABS( cvt_dist ) < CUR.GS.single_width_cutin )
+ {
+ if ( cvt_dist >= 0 )
+ cvt_dist = CUR.GS.single_width_value;
+ else
+ cvt_dist = -CUR.GS.single_width_value;
+ }
+
+ /* XXX: UNDOCUMENTED! -- twilight zone */
+
+ if ( CUR.GS.gep1 == 0 )
+ {
+ CUR.zp1.org[point].x = CUR.zp0.org[CUR.GS.rp0].x +
+ TT_MulFix14( cvt_dist, CUR.GS.freeVector.x );
+
+ CUR.zp1.org[point].y = CUR.zp0.org[CUR.GS.rp0].y +
+ TT_MulFix14( cvt_dist, CUR.GS.freeVector.y );
+
+ CUR.zp1.cur[point] = CUR.zp1.org[point];
+ }
+
+ org_dist = CUR_Func_dualproj( CUR.zp1.org + point,
+ CUR.zp0.org + CUR.GS.rp0 );
+
+ cur_dist = CUR_Func_project( CUR.zp1.cur + point,
+ CUR.zp0.cur + CUR.GS.rp0 );
+
+ /* auto-flip test */
+
+ if ( CUR.GS.auto_flip )
+ {
+ if ( ( org_dist ^ cvt_dist ) < 0 )
+ cvt_dist = -cvt_dist;
+ }
+
+ /* control value cutin and round */
+
+ if ( ( CUR.opcode & 4 ) != 0 )
+ {
+ /* XXX: UNDOCUMENTED! Only perform cut-in test when both points */
+ /* refer to the same zone. */
+
+ if ( CUR.GS.gep0 == CUR.GS.gep1 )
+ if ( ABS( cvt_dist - org_dist ) >= CUR.GS.control_value_cutin )
+ cvt_dist = org_dist;
+
+ distance = CUR_Func_round(
+ cvt_dist,
+ CUR.tt_metrics.compensations[CUR.opcode & 3] );
+ }
+ else
+ distance = ROUND_None(
+ cvt_dist,
+ CUR.tt_metrics.compensations[CUR.opcode & 3] );
+
+ /* minimum distance test */
+
+ if ( ( CUR.opcode & 8 ) != 0 )
+ {
+ if ( org_dist >= 0 )
+ {
+ if ( distance < CUR.GS.minimum_distance )
+ distance = CUR.GS.minimum_distance;
+ }
+ else
+ {
+ if ( distance > -CUR.GS.minimum_distance )
+ distance = -CUR.GS.minimum_distance;
+ }
+ }
+
+ CUR_Func_move( &CUR.zp1, point, distance - cur_dist );
+
+ CUR.GS.rp1 = CUR.GS.rp0;
+
+ if ( ( CUR.opcode & 16 ) != 0 )
+ CUR.GS.rp0 = point;
+
+ /* XXX: UNDOCUMENTED! */
+
+ CUR.GS.rp2 = point;
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* ALIGNRP[]: ALIGN Relative Point */
+ /* Opcode range: 0x3C */
+ /* Stack: uint32 uint32... --> */
+ /* */
+ static void
+ Ins_ALIGNRP( INS_ARG )
+ {
+ FT_UShort point;
+ FT_F26Dot6 distance;
+
+ FT_UNUSED_ARG;
+
+
+ if ( CUR.top < CUR.GS.loop ||
+ BOUNDS( CUR.GS.rp0, CUR.zp0.n_points ) )
+ {
+ if ( CUR.pedantic_hinting )
+ CUR.error = TT_Err_Invalid_Reference;
+ return;
+ }
+
+ while ( CUR.GS.loop > 0 )
+ {
+ CUR.args--;
+
+ point = (FT_UShort)CUR.stack[CUR.args];
+
+ if ( BOUNDS( point, CUR.zp1.n_points ) )
+ {
+ if ( CUR.pedantic_hinting )
+ {
+ CUR.error = TT_Err_Invalid_Reference;
+ return;
+ }
+ }
+ else
+ {
+ distance = CUR_Func_project( CUR.zp1.cur + point,
+ CUR.zp0.cur + CUR.GS.rp0 );
+
+ CUR_Func_move( &CUR.zp1, point, -distance );
+ }
+
+ CUR.GS.loop--;
+ }
+
+ CUR.GS.loop = 1;
+ CUR.new_top = CUR.args;
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* ISECT[]: moves point to InterSECTion */
+ /* Opcode range: 0x0F */
+ /* Stack: 5 * uint32 --> */
+ /* */
+ static void
+ Ins_ISECT( INS_ARG )
+ {
+ FT_UShort point,
+ a0, a1,
+ b0, b1;
+
+ FT_F26Dot6 discriminant;
+
+ FT_F26Dot6 dx, dy,
+ dax, day,
+ dbx, dby;
+
+ FT_F26Dot6 val;
+
+ FT_Vector R;
+
+
+ point = (FT_UShort)args[0];
+
+ a0 = (FT_UShort)args[1];
+ a1 = (FT_UShort)args[2];
+ b0 = (FT_UShort)args[3];
+ b1 = (FT_UShort)args[4];
+
+ if ( BOUNDS( b0, CUR.zp0.n_points ) ||
+ BOUNDS( b1, CUR.zp0.n_points ) ||
+ BOUNDS( a0, CUR.zp1.n_points ) ||
+ BOUNDS( a1, CUR.zp1.n_points ) ||
+ BOUNDS( point, CUR.zp2.n_points ) )
+ {
+ if ( CUR.pedantic_hinting )
+ CUR.error = TT_Err_Invalid_Reference;
+ return;
+ }
+
+ dbx = CUR.zp0.cur[b1].x - CUR.zp0.cur[b0].x;
+ dby = CUR.zp0.cur[b1].y - CUR.zp0.cur[b0].y;
+
+ dax = CUR.zp1.cur[a1].x - CUR.zp1.cur[a0].x;
+ day = CUR.zp1.cur[a1].y - CUR.zp1.cur[a0].y;
+
+ dx = CUR.zp0.cur[b0].x - CUR.zp1.cur[a0].x;
+ dy = CUR.zp0.cur[b0].y - CUR.zp1.cur[a0].y;
+
+ CUR.zp2.tags[point] |= FT_CURVE_TAG_TOUCH_BOTH;
+
+ discriminant = TT_MULDIV( dax, -dby, 0x40 ) +
+ TT_MULDIV( day, dbx, 0x40 );
+
+ if ( ABS( discriminant ) >= 0x40 )
+ {
+ val = TT_MULDIV( dx, -dby, 0x40 ) + TT_MULDIV( dy, dbx, 0x40 );
+
+ R.x = TT_MULDIV( val, dax, discriminant );
+ R.y = TT_MULDIV( val, day, discriminant );
+
+ CUR.zp2.cur[point].x = CUR.zp1.cur[a0].x + R.x;
+ CUR.zp2.cur[point].y = CUR.zp1.cur[a0].y + R.y;
+ }
+ else
+ {
+ /* else, take the middle of the middles of A and B */
+
+ CUR.zp2.cur[point].x = ( CUR.zp1.cur[a0].x +
+ CUR.zp1.cur[a1].x +
+ CUR.zp0.cur[b0].x +
+ CUR.zp0.cur[b1].x ) / 4;
+ CUR.zp2.cur[point].y = ( CUR.zp1.cur[a0].y +
+ CUR.zp1.cur[a1].y +
+ CUR.zp0.cur[b0].y +
+ CUR.zp0.cur[b1].y ) / 4;
+ }
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* ALIGNPTS[]: ALIGN PoinTS */
+ /* Opcode range: 0x27 */
+ /* Stack: uint32 uint32 --> */
+ /* */
+ static void
+ Ins_ALIGNPTS( INS_ARG )
+ {
+ FT_UShort p1, p2;
+ FT_F26Dot6 distance;
+
+
+ p1 = (FT_UShort)args[0];
+ p2 = (FT_UShort)args[1];
+
+ if ( BOUNDS( args[0], CUR.zp1.n_points ) ||
+ BOUNDS( args[1], CUR.zp0.n_points ) )
+ {
+ if ( CUR.pedantic_hinting )
+ CUR.error = TT_Err_Invalid_Reference;
+ return;
+ }
+
+ distance = CUR_Func_project( CUR.zp0.cur + p2,
+ CUR.zp1.cur + p1 ) / 2;
+
+ CUR_Func_move( &CUR.zp1, p1, distance );
+ CUR_Func_move( &CUR.zp0, p2, -distance );
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* IP[]: Interpolate Point */
+ /* Opcode range: 0x39 */
+ /* Stack: uint32... --> */
+ /* */
+ static void
+ Ins_IP( INS_ARG )
+ {
+ FT_F26Dot6 org_a, org_b, org_x,
+ cur_a, cur_b, cur_x,
+ distance;
+ FT_UShort point;
+
+ FT_UNUSED_ARG;
+
+
+ if ( CUR.top < CUR.GS.loop )
+ {
+ CUR.error = TT_Err_Invalid_Reference;
+ return;
+ }
+
+ /* XXX: There are some glyphs in some braindead but popular */
+ /* fonts out there (e.g. [aeu]grave in monotype.ttf) */
+ /* calling IP[] with bad values of rp[12]. */
+ /* Do something sane when this odd thing happens. */
+
+ if ( BOUNDS( CUR.GS.rp1, CUR.zp0.n_points ) ||
+ BOUNDS( CUR.GS.rp2, CUR.zp1.n_points ) )
+ {
+ org_a = cur_a = 0;
+ org_b = cur_b = 0;
+ }
+ else
+ {
+ org_a = CUR_Func_dualproj( CUR.zp0.org + CUR.GS.rp1, NULL_Vector );
+ org_b = CUR_Func_dualproj( CUR.zp1.org + CUR.GS.rp2, NULL_Vector );
+
+ cur_a = CUR_Func_project( CUR.zp0.cur + CUR.GS.rp1, NULL_Vector );
+ cur_b = CUR_Func_project( CUR.zp1.cur + CUR.GS.rp2, NULL_Vector );
+ }
+
+ while ( CUR.GS.loop > 0 )
+ {
+ CUR.args--;
+
+ point = (FT_UShort)CUR.stack[CUR.args];
+ if ( BOUNDS( point, CUR.zp2.n_points ) )
+ {
+ if ( CUR.pedantic_hinting )
+ {
+ CUR.error = TT_Err_Invalid_Reference;
+ return;
+ }
+ }
+ else
+ {
+ org_x = CUR_Func_dualproj( CUR.zp2.org + point, NULL_Vector );
+ cur_x = CUR_Func_project ( CUR.zp2.cur + point, NULL_Vector );
+
+ if ( ( org_a <= org_b && org_x <= org_a ) ||
+ ( org_a > org_b && org_x >= org_a ) )
+
+ distance = ( cur_a - org_a ) + ( org_x - cur_x );
+
+ else if ( ( org_a <= org_b && org_x >= org_b ) ||
+ ( org_a > org_b && org_x < org_b ) )
+
+ distance = ( cur_b - org_b ) + ( org_x - cur_x );
+
+ else
+ /* note: it seems that rounding this value isn't a good */
+ /* idea (cf. width of capital `S' in Times) */
+
+ distance = TT_MULDIV( cur_b - cur_a,
+ org_x - org_a,
+ org_b - org_a ) + ( cur_a - cur_x );
+
+ CUR_Func_move( &CUR.zp2, point, distance );
+ }
+
+ CUR.GS.loop--;
+ }
+
+ CUR.GS.loop = 1;
+ CUR.new_top = CUR.args;
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* UTP[a]: UnTouch Point */
+ /* Opcode range: 0x29 */
+ /* Stack: uint32 --> */
+ /* */
+ static void
+ Ins_UTP( INS_ARG )
+ {
+ FT_UShort point;
+ FT_Byte mask;
+
+
+ point = (FT_UShort)args[0];
+
+ if ( BOUNDS( point, CUR.zp0.n_points ) )
+ {
+ if ( CUR.pedantic_hinting )
+ CUR.error = TT_Err_Invalid_Reference;
+ return;
+ }
+
+ mask = 0xFF;
+
+ if ( CUR.GS.freeVector.x != 0 )
+ mask &= ~FT_CURVE_TAG_TOUCH_X;
+
+ if ( CUR.GS.freeVector.y != 0 )
+ mask &= ~FT_CURVE_TAG_TOUCH_Y;
+
+ CUR.zp0.tags[point] &= mask;
+ }
+
+
+ /* Local variables for Ins_IUP: */
+ struct LOC_Ins_IUP
+ {
+ FT_Vector* orgs; /* original and current coordinate */
+ FT_Vector* curs; /* arrays */
+ };
+
+
+ static void
+ Shift( FT_UInt p1,
+ FT_UInt p2,
+ FT_UInt p,
+ struct LOC_Ins_IUP* LINK )
+ {
+ FT_UInt i;
+ FT_F26Dot6 x;
+
+
+ x = LINK->curs[p].x - LINK->orgs[p].x;
+
+ for ( i = p1; i < p; i++ )
+ LINK->curs[i].x += x;
+
+ for ( i = p + 1; i <= p2; i++ )
+ LINK->curs[i].x += x;
+ }
+
+
+ static void
+ Interp( FT_UInt p1,
+ FT_UInt p2,
+ FT_UInt ref1,
+ FT_UInt ref2,
+ struct LOC_Ins_IUP* LINK )
+ {
+ FT_UInt i;
+ FT_F26Dot6 x, x1, x2, d1, d2;
+
+
+ if ( p1 > p2 )
+ return;
+
+ x1 = LINK->orgs[ref1].x;
+ d1 = LINK->curs[ref1].x - LINK->orgs[ref1].x;
+ x2 = LINK->orgs[ref2].x;
+ d2 = LINK->curs[ref2].x - LINK->orgs[ref2].x;
+
+ if ( x1 == x2 )
+ {
+ for ( i = p1; i <= p2; i++ )
+ {
+ x = LINK->orgs[i].x;
+
+ if ( x <= x1 )
+ x += d1;
+ else
+ x += d2;
+
+ LINK->curs[i].x = x;
+ }
+ return;
+ }
+
+ if ( x1 < x2 )
+ {
+ for ( i = p1; i <= p2; i++ )
+ {
+ x = LINK->orgs[i].x;
+
+ if ( x <= x1 )
+ x += d1;
+ else
+ {
+ if ( x >= x2 )
+ x += d2;
+ else
+ x = LINK->curs[ref1].x +
+ TT_MULDIV( x - x1,
+ LINK->curs[ref2].x - LINK->curs[ref1].x,
+ x2 - x1 );
+ }
+ LINK->curs[i].x = x;
+ }
+ return;
+ }
+
+ /* x2 < x1 */
+
+ for ( i = p1; i <= p2; i++ )
+ {
+ x = LINK->orgs[i].x;
+ if ( x <= x2 )
+ x += d2;
+ else
+ {
+ if ( x >= x1 )
+ x += d1;
+ else
+ x = LINK->curs[ref1].x +
+ TT_MULDIV( x - x1,
+ LINK->curs[ref2].x - LINK->curs[ref1].x,
+ x2 - x1 );
+ }
+ LINK->curs[i].x = x;
+ }
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* IUP[a]: Interpolate Untouched Points */
+ /* Opcode range: 0x30-0x31 */
+ /* Stack: --> */
+ /* */
+ static void
+ Ins_IUP( INS_ARG )
+ {
+ struct LOC_Ins_IUP V;
+ FT_Byte mask;
+
+ FT_UInt first_point; /* first point of contour */
+ FT_UInt end_point; /* end point (last+1) of contour */
+
+ FT_UInt first_touched; /* first touched point in contour */
+ FT_UInt cur_touched; /* current touched point in contour */
+
+ FT_UInt point; /* current point */
+ FT_Short contour; /* current contour */
+
+ FT_UNUSED_ARG;
+
+
+ if ( CUR.opcode & 1 )
+ {
+ mask = FT_CURVE_TAG_TOUCH_X;
+ V.orgs = CUR.pts.org;
+ V.curs = CUR.pts.cur;
+ }
+ else
+ {
+ mask = FT_CURVE_TAG_TOUCH_Y;
+ V.orgs = (FT_Vector*)( (FT_Pos*)CUR.pts.org + 1 );
+ V.curs = (FT_Vector*)( (FT_Pos*)CUR.pts.cur + 1 );
+ }
+
+ contour = 0;
+ point = 0;
+
+ do
+ {
+ end_point = CUR.pts.contours[contour];
+ first_point = point;
+
+ while ( point <= end_point && (CUR.pts.tags[point] & mask) == 0 )
+ point++;
+
+ if ( point <= end_point )
+ {
+ first_touched = point;
+ cur_touched = point;
+
+ point++;
+
+ while ( point <= end_point )
+ {
+ if ( ( CUR.pts.tags[point] & mask ) != 0 )
+ {
+ if ( point > 0 )
+ Interp( cur_touched + 1,
+ point - 1,
+ cur_touched,
+ point,
+ &V );
+ cur_touched = point;
+ }
+
+ point++;
+ }
+
+ if ( cur_touched == first_touched )
+ Shift( first_point, end_point, cur_touched, &V );
+ else
+ {
+ Interp( (FT_UShort)( cur_touched + 1 ),
+ end_point,
+ cur_touched,
+ first_touched,
+ &V );
+
+ if ( first_touched > 0 )
+ Interp( first_point,
+ first_touched - 1,
+ cur_touched,
+ first_touched,
+ &V );
+ }
+ }
+ contour++;
+ } while ( contour < CUR.pts.n_contours );
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* DELTAPn[]: DELTA exceptions P1, P2, P3 */
+ /* Opcode range: 0x5D,0x71,0x72 */
+ /* Stack: uint32 (2 * uint32)... --> */
+ /* */
+ static void
+ Ins_DELTAP( INS_ARG )
+ {
+ FT_ULong k, nump;
+ FT_UShort A;
+ FT_ULong C;
+ FT_Long B;
+
+
+ nump = (FT_ULong)args[0]; /* some points theoretically may occur more
+ than once, thus UShort isn't enough */
+
+ for ( k = 1; k <= nump; k++ )
+ {
+ if ( CUR.args < 2 )
+ {
+ CUR.error = TT_Err_Too_Few_Arguments;
+ return;
+ }
+
+ CUR.args -= 2;
+
+ A = (FT_UShort)CUR.stack[CUR.args + 1];
+ B = CUR.stack[CUR.args];
+
+ /* XXX: Because some popular fonts contain some invalid DeltaP */
+ /* instructions, we simply ignore them when the stacked */
+ /* point reference is off limit, rather than returning an */
+ /* error. As a delta instruction doesn't change a glyph */
+ /* in great ways, this shouldn't be a problem. */
+
+ if ( !BOUNDS( A, CUR.zp0.n_points ) )
+ {
+ C = ( (FT_ULong)B & 0xF0 ) >> 4;
+
+ switch ( CUR.opcode )
+ {
+ case 0x5D:
+ break;
+
+ case 0x71:
+ C += 16;
+ break;
+
+ case 0x72:
+ C += 32;
+ break;
+ }
+
+ C += CUR.GS.delta_base;
+
+ if ( CURRENT_Ppem() == (FT_Long)C )
+ {
+ B = ( (FT_ULong)B & 0xF ) - 8;
+ if ( B >= 0 )
+ B++;
+ B = B * 64 / ( 1L << CUR.GS.delta_shift );
+
+ CUR_Func_move( &CUR.zp0, A, B );
+ }
+ }
+ else
+ if ( CUR.pedantic_hinting )
+ CUR.error = TT_Err_Invalid_Reference;
+ }
+
+ CUR.new_top = CUR.args;
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* DELTACn[]: DELTA exceptions C1, C2, C3 */
+ /* Opcode range: 0x73,0x74,0x75 */
+ /* Stack: uint32 (2 * uint32)... --> */
+ /* */
+ static void
+ Ins_DELTAC( INS_ARG )
+ {
+ FT_ULong nump, k;
+ FT_ULong A, C;
+ FT_Long B;
+
+
+ nump = (FT_ULong)args[0];
+
+ for ( k = 1; k <= nump; k++ )
+ {
+ if ( CUR.args < 2 )
+ {
+ CUR.error = TT_Err_Too_Few_Arguments;
+ return;
+ }
+
+ CUR.args -= 2;
+
+ A = (FT_ULong)CUR.stack[CUR.args + 1];
+ B = CUR.stack[CUR.args];
+
+ if ( BOUNDS( A, CUR.cvtSize ) )
+ {
+ if ( CUR.pedantic_hinting )
+ {
+ CUR.error = TT_Err_Invalid_Reference;
+ return;
+ }
+ }
+ else
+ {
+ C = ( (FT_ULong)B & 0xF0 ) >> 4;
+
+ switch ( CUR.opcode )
+ {
+ case 0x73:
+ break;
+
+ case 0x74:
+ C += 16;
+ break;
+
+ case 0x75:
+ C += 32;
+ break;
+ }
+
+ C += CUR.GS.delta_base;
+
+ if ( CURRENT_Ppem() == (FT_Long)C )
+ {
+ B = ( (FT_ULong)B & 0xF ) - 8;
+ if ( B >= 0 )
+ B++;
+ B = B * 64 / ( 1L << CUR.GS.delta_shift );
+
+ CUR_Func_move_cvt( A, B );
+ }
+ }
+ }
+
+ CUR.new_top = CUR.args;
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* MISC. INSTRUCTIONS */
+ /* */
+ /*************************************************************************/
+
+
+ /*************************************************************************/
+ /* */
+ /* GETINFO[]: GET INFOrmation */
+ /* Opcode range: 0x88 */
+ /* Stack: uint32 --> uint32 */
+ /* */
+ /* XXX: According to Apple specs, bits 1 & 2 of the argument ought to be */
+ /* consulted before rotated/stretched info is returned. */
+ static void
+ Ins_GETINFO( INS_ARG )
+ {
+ FT_Long K;
+
+
+ K = 0;
+
+ /* We return then Windows 3.1 version number */
+ /* for the font scaler */
+ if ( ( args[0] & 1 ) != 0 )
+ K = 3;
+
+ /* Has the glyph been rotated ? */
+ if ( CUR.tt_metrics.rotated )
+ K |= 0x80;
+
+ /* Has the glyph been stretched ? */
+ if ( CUR.tt_metrics.stretched )
+ K |= 0x100;
+
+ args[0] = K;
+ }
+
+
+ static void
+ Ins_UNKNOWN( INS_ARG )
+ {
+ TT_DefRecord* def = CUR.IDefs;
+ TT_DefRecord* limit = def + CUR.numIDefs;
+
+ FT_UNUSED_ARG;
+
+
+ for ( ; def < limit; def++ )
+ {
+ if ( (FT_Byte)def->opc == CUR.opcode && def->active )
+ {
+ TT_CallRec* call;
+
+
+ if ( CUR.callTop >= CUR.callSize )
+ {
+ CUR.error = TT_Err_Stack_Overflow;
+ return;
+ }
+
+ call = CUR.callStack + CUR.callTop++;
+
+ call->Caller_Range = CUR.curRange;
+ call->Caller_IP = CUR.IP+1;
+ call->Cur_Count = 1;
+ call->Cur_Restart = def->start;
+
+ INS_Goto_CodeRange( def->range, def->start );
+
+ CUR.step_ins = FALSE;
+ return;
+ }
+ }
+
+ CUR.error = TT_Err_Invalid_Opcode;
+ }
+
+
+#ifndef TT_CONFIG_OPTION_INTERPRETER_SWITCH
+
+
+ static
+ TInstruction_Function Instruct_Dispatch[256] =
+ {
+ /* Opcodes are gathered in groups of 16. */
+ /* Please keep the spaces as they are. */
+
+ /* SVTCA y */ Ins_SVTCA,
+ /* SVTCA x */ Ins_SVTCA,
+ /* SPvTCA y */ Ins_SPVTCA,
+ /* SPvTCA x */ Ins_SPVTCA,
+ /* SFvTCA y */ Ins_SFVTCA,
+ /* SFvTCA x */ Ins_SFVTCA,
+ /* SPvTL // */ Ins_SPVTL,
+ /* SPvTL + */ Ins_SPVTL,
+ /* SFvTL // */ Ins_SFVTL,
+ /* SFvTL + */ Ins_SFVTL,
+ /* SPvFS */ Ins_SPVFS,
+ /* SFvFS */ Ins_SFVFS,
+ /* GPV */ Ins_GPV,
+ /* GFV */ Ins_GFV,
+ /* SFvTPv */ Ins_SFVTPV,
+ /* ISECT */ Ins_ISECT,
+
+ /* SRP0 */ Ins_SRP0,
+ /* SRP1 */ Ins_SRP1,
+ /* SRP2 */ Ins_SRP2,
+ /* SZP0 */ Ins_SZP0,
+ /* SZP1 */ Ins_SZP1,
+ /* SZP2 */ Ins_SZP2,
+ /* SZPS */ Ins_SZPS,
+ /* SLOOP */ Ins_SLOOP,
+ /* RTG */ Ins_RTG,
+ /* RTHG */ Ins_RTHG,
+ /* SMD */ Ins_SMD,
+ /* ELSE */ Ins_ELSE,
+ /* JMPR */ Ins_JMPR,
+ /* SCvTCi */ Ins_SCVTCI,
+ /* SSwCi */ Ins_SSWCI,
+ /* SSW */ Ins_SSW,
+
+ /* DUP */ Ins_DUP,
+ /* POP */ Ins_POP,
+ /* CLEAR */ Ins_CLEAR,
+ /* SWAP */ Ins_SWAP,
+ /* DEPTH */ Ins_DEPTH,
+ /* CINDEX */ Ins_CINDEX,
+ /* MINDEX */ Ins_MINDEX,
+ /* AlignPTS */ Ins_ALIGNPTS,
+ /* INS_0x28 */ Ins_UNKNOWN,
+ /* UTP */ Ins_UTP,
+ /* LOOPCALL */ Ins_LOOPCALL,
+ /* CALL */ Ins_CALL,
+ /* FDEF */ Ins_FDEF,
+ /* ENDF */ Ins_ENDF,
+ /* MDAP[0] */ Ins_MDAP,
+ /* MDAP[1] */ Ins_MDAP,
+
+ /* IUP[0] */ Ins_IUP,
+ /* IUP[1] */ Ins_IUP,
+ /* SHP[0] */ Ins_SHP,
+ /* SHP[1] */ Ins_SHP,
+ /* SHC[0] */ Ins_SHC,
+ /* SHC[1] */ Ins_SHC,
+ /* SHZ[0] */ Ins_SHZ,
+ /* SHZ[1] */ Ins_SHZ,
+ /* SHPIX */ Ins_SHPIX,
+ /* IP */ Ins_IP,
+ /* MSIRP[0] */ Ins_MSIRP,
+ /* MSIRP[1] */ Ins_MSIRP,
+ /* AlignRP */ Ins_ALIGNRP,
+ /* RTDG */ Ins_RTDG,
+ /* MIAP[0] */ Ins_MIAP,
+ /* MIAP[1] */ Ins_MIAP,
+
+ /* NPushB */ Ins_NPUSHB,
+ /* NPushW */ Ins_NPUSHW,
+ /* WS */ Ins_WS,
+ /* RS */ Ins_RS,
+ /* WCvtP */ Ins_WCVTP,
+ /* RCvt */ Ins_RCVT,
+ /* GC[0] */ Ins_GC,
+ /* GC[1] */ Ins_GC,
+ /* SCFS */ Ins_SCFS,
+ /* MD[0] */ Ins_MD,
+ /* MD[1] */ Ins_MD,
+ /* MPPEM */ Ins_MPPEM,
+ /* MPS */ Ins_MPS,
+ /* FlipON */ Ins_FLIPON,
+ /* FlipOFF */ Ins_FLIPOFF,
+ /* DEBUG */ Ins_DEBUG,
+
+ /* LT */ Ins_LT,
+ /* LTEQ */ Ins_LTEQ,
+ /* GT */ Ins_GT,
+ /* GTEQ */ Ins_GTEQ,
+ /* EQ */ Ins_EQ,
+ /* NEQ */ Ins_NEQ,
+ /* ODD */ Ins_ODD,
+ /* EVEN */ Ins_EVEN,
+ /* IF */ Ins_IF,
+ /* EIF */ Ins_EIF,
+ /* AND */ Ins_AND,
+ /* OR */ Ins_OR,
+ /* NOT */ Ins_NOT,
+ /* DeltaP1 */ Ins_DELTAP,
+ /* SDB */ Ins_SDB,
+ /* SDS */ Ins_SDS,
+
+ /* ADD */ Ins_ADD,
+ /* SUB */ Ins_SUB,
+ /* DIV */ Ins_DIV,
+ /* MUL */ Ins_MUL,
+ /* ABS */ Ins_ABS,
+ /* NEG */ Ins_NEG,
+ /* FLOOR */ Ins_FLOOR,
+ /* CEILING */ Ins_CEILING,
+ /* ROUND[0] */ Ins_ROUND,
+ /* ROUND[1] */ Ins_ROUND,
+ /* ROUND[2] */ Ins_ROUND,
+ /* ROUND[3] */ Ins_ROUND,
+ /* NROUND[0] */ Ins_NROUND,
+ /* NROUND[1] */ Ins_NROUND,
+ /* NROUND[2] */ Ins_NROUND,
+ /* NROUND[3] */ Ins_NROUND,
+
+ /* WCvtF */ Ins_WCVTF,
+ /* DeltaP2 */ Ins_DELTAP,
+ /* DeltaP3 */ Ins_DELTAP,
+ /* DeltaCn[0] */ Ins_DELTAC,
+ /* DeltaCn[1] */ Ins_DELTAC,
+ /* DeltaCn[2] */ Ins_DELTAC,
+ /* SROUND */ Ins_SROUND,
+ /* S45Round */ Ins_S45ROUND,
+ /* JROT */ Ins_JROT,
+ /* JROF */ Ins_JROF,
+ /* ROFF */ Ins_ROFF,
+ /* INS_0x7B */ Ins_UNKNOWN,
+ /* RUTG */ Ins_RUTG,
+ /* RDTG */ Ins_RDTG,
+ /* SANGW */ Ins_SANGW,
+ /* AA */ Ins_AA,
+
+ /* FlipPT */ Ins_FLIPPT,
+ /* FlipRgON */ Ins_FLIPRGON,
+ /* FlipRgOFF */ Ins_FLIPRGOFF,
+ /* INS_0x83 */ Ins_UNKNOWN,
+ /* INS_0x84 */ Ins_UNKNOWN,
+ /* ScanCTRL */ Ins_SCANCTRL,
+ /* SDPVTL[0] */ Ins_SDPVTL,
+ /* SDPVTL[1] */ Ins_SDPVTL,
+ /* GetINFO */ Ins_GETINFO,
+ /* IDEF */ Ins_IDEF,
+ /* ROLL */ Ins_ROLL,
+ /* MAX */ Ins_MAX,
+ /* MIN */ Ins_MIN,
+ /* ScanTYPE */ Ins_SCANTYPE,
+ /* InstCTRL */ Ins_INSTCTRL,
+ /* INS_0x8F */ Ins_UNKNOWN,
+
+ /* INS_0x90 */ Ins_UNKNOWN,
+ /* INS_0x91 */ Ins_UNKNOWN,
+ /* INS_0x92 */ Ins_UNKNOWN,
+ /* INS_0x93 */ Ins_UNKNOWN,
+ /* INS_0x94 */ Ins_UNKNOWN,
+ /* INS_0x95 */ Ins_UNKNOWN,
+ /* INS_0x96 */ Ins_UNKNOWN,
+ /* INS_0x97 */ Ins_UNKNOWN,
+ /* INS_0x98 */ Ins_UNKNOWN,
+ /* INS_0x99 */ Ins_UNKNOWN,
+ /* INS_0x9A */ Ins_UNKNOWN,
+ /* INS_0x9B */ Ins_UNKNOWN,
+ /* INS_0x9C */ Ins_UNKNOWN,
+ /* INS_0x9D */ Ins_UNKNOWN,
+ /* INS_0x9E */ Ins_UNKNOWN,
+ /* INS_0x9F */ Ins_UNKNOWN,
+
+ /* INS_0xA0 */ Ins_UNKNOWN,
+ /* INS_0xA1 */ Ins_UNKNOWN,
+ /* INS_0xA2 */ Ins_UNKNOWN,
+ /* INS_0xA3 */ Ins_UNKNOWN,
+ /* INS_0xA4 */ Ins_UNKNOWN,
+ /* INS_0xA5 */ Ins_UNKNOWN,
+ /* INS_0xA6 */ Ins_UNKNOWN,
+ /* INS_0xA7 */ Ins_UNKNOWN,
+ /* INS_0xA8 */ Ins_UNKNOWN,
+ /* INS_0xA9 */ Ins_UNKNOWN,
+ /* INS_0xAA */ Ins_UNKNOWN,
+ /* INS_0xAB */ Ins_UNKNOWN,
+ /* INS_0xAC */ Ins_UNKNOWN,
+ /* INS_0xAD */ Ins_UNKNOWN,
+ /* INS_0xAE */ Ins_UNKNOWN,
+ /* INS_0xAF */ Ins_UNKNOWN,
+
+ /* PushB[0] */ Ins_PUSHB,
+ /* PushB[1] */ Ins_PUSHB,
+ /* PushB[2] */ Ins_PUSHB,
+ /* PushB[3] */ Ins_PUSHB,
+ /* PushB[4] */ Ins_PUSHB,
+ /* PushB[5] */ Ins_PUSHB,
+ /* PushB[6] */ Ins_PUSHB,
+ /* PushB[7] */ Ins_PUSHB,
+ /* PushW[0] */ Ins_PUSHW,
+ /* PushW[1] */ Ins_PUSHW,
+ /* PushW[2] */ Ins_PUSHW,
+ /* PushW[3] */ Ins_PUSHW,
+ /* PushW[4] */ Ins_PUSHW,
+ /* PushW[5] */ Ins_PUSHW,
+ /* PushW[6] */ Ins_PUSHW,
+ /* PushW[7] */ Ins_PUSHW,
+
+ /* MDRP[00] */ Ins_MDRP,
+ /* MDRP[01] */ Ins_MDRP,
+ /* MDRP[02] */ Ins_MDRP,
+ /* MDRP[03] */ Ins_MDRP,
+ /* MDRP[04] */ Ins_MDRP,
+ /* MDRP[05] */ Ins_MDRP,
+ /* MDRP[06] */ Ins_MDRP,
+ /* MDRP[07] */ Ins_MDRP,
+ /* MDRP[08] */ Ins_MDRP,
+ /* MDRP[09] */ Ins_MDRP,
+ /* MDRP[10] */ Ins_MDRP,
+ /* MDRP[11] */ Ins_MDRP,
+ /* MDRP[12] */ Ins_MDRP,
+ /* MDRP[13] */ Ins_MDRP,
+ /* MDRP[14] */ Ins_MDRP,
+ /* MDRP[15] */ Ins_MDRP,
+
+ /* MDRP[16] */ Ins_MDRP,
+ /* MDRP[17] */ Ins_MDRP,
+ /* MDRP[18] */ Ins_MDRP,
+ /* MDRP[19] */ Ins_MDRP,
+ /* MDRP[20] */ Ins_MDRP,
+ /* MDRP[21] */ Ins_MDRP,
+ /* MDRP[22] */ Ins_MDRP,
+ /* MDRP[23] */ Ins_MDRP,
+ /* MDRP[24] */ Ins_MDRP,
+ /* MDRP[25] */ Ins_MDRP,
+ /* MDRP[26] */ Ins_MDRP,
+ /* MDRP[27] */ Ins_MDRP,
+ /* MDRP[28] */ Ins_MDRP,
+ /* MDRP[29] */ Ins_MDRP,
+ /* MDRP[30] */ Ins_MDRP,
+ /* MDRP[31] */ Ins_MDRP,
+
+ /* MIRP[00] */ Ins_MIRP,
+ /* MIRP[01] */ Ins_MIRP,
+ /* MIRP[02] */ Ins_MIRP,
+ /* MIRP[03] */ Ins_MIRP,
+ /* MIRP[04] */ Ins_MIRP,
+ /* MIRP[05] */ Ins_MIRP,
+ /* MIRP[06] */ Ins_MIRP,
+ /* MIRP[07] */ Ins_MIRP,
+ /* MIRP[08] */ Ins_MIRP,
+ /* MIRP[09] */ Ins_MIRP,
+ /* MIRP[10] */ Ins_MIRP,
+ /* MIRP[11] */ Ins_MIRP,
+ /* MIRP[12] */ Ins_MIRP,
+ /* MIRP[13] */ Ins_MIRP,
+ /* MIRP[14] */ Ins_MIRP,
+ /* MIRP[15] */ Ins_MIRP,
+
+ /* MIRP[16] */ Ins_MIRP,
+ /* MIRP[17] */ Ins_MIRP,
+ /* MIRP[18] */ Ins_MIRP,
+ /* MIRP[19] */ Ins_MIRP,
+ /* MIRP[20] */ Ins_MIRP,
+ /* MIRP[21] */ Ins_MIRP,
+ /* MIRP[22] */ Ins_MIRP,
+ /* MIRP[23] */ Ins_MIRP,
+ /* MIRP[24] */ Ins_MIRP,
+ /* MIRP[25] */ Ins_MIRP,
+ /* MIRP[26] */ Ins_MIRP,
+ /* MIRP[27] */ Ins_MIRP,
+ /* MIRP[28] */ Ins_MIRP,
+ /* MIRP[29] */ Ins_MIRP,
+ /* MIRP[30] */ Ins_MIRP,
+ /* MIRP[31] */ Ins_MIRP
+ };
+
+
+#endif /* !TT_CONFIG_OPTION_INTERPRETER_SWITCH */
+
+
+ /*************************************************************************/
+ /* */
+ /* RUN */
+ /* */
+ /* This function executes a run of opcodes. It will exit in the */
+ /* following cases: */
+ /* */
+ /* - Errors (in which case it returns FALSE). */
+ /* */
+ /* - Reaching the end of the main code range (returns TRUE). */
+ /* Reaching the end of a code range within a function call is an */
+ /* error. */
+ /* */
+ /* - After executing one single opcode, if the flag `Instruction_Trap' */
+ /* is set to TRUE (returns TRUE). */
+ /* */
+ /* On exit whith TRUE, test IP < CodeSize to know wether it comes from */
+ /* an instruction trap or a normal termination. */
+ /* */
+ /* */
+ /* Note: The documented DEBUG opcode pops a value from the stack. This */
+ /* behaviour is unsupported; here a DEBUG opcode is always an */
+ /* error. */
+ /* */
+ /* */
+ /* THIS IS THE INTERPRETER'S MAIN LOOP. */
+ /* */
+ /* Instructions appear in the specification's order. */
+ /* */
+ /*************************************************************************/
+
+
+ /* documentation is in ttinterp.h */
+
+ FT_EXPORT_DEF( FT_Error )
+ TT_RunIns( TT_ExecContext exc )
+ {
+ FT_Long ins_counter = 0; /* executed instructions counter */
+
+
+#ifdef TT_CONFIG_OPTION_STATIC_RASTER
+ cur = *exc;
+#endif
+
+ /* set CVT functions */
+ CUR.tt_metrics.ratio = 0;
+ if ( CUR.metrics.x_ppem != CUR.metrics.y_ppem )
+ {
+ /* non-square pixels, use the stretched routines */
+ CUR.func_read_cvt = Read_CVT_Stretched;
+ CUR.func_write_cvt = Write_CVT_Stretched;
+ CUR.func_move_cvt = Move_CVT_Stretched;
+ }
+ else
+ {
+ /* square pixels, use normal routines */
+ CUR.func_read_cvt = Read_CVT;
+ CUR.func_write_cvt = Write_CVT;
+ CUR.func_move_cvt = Move_CVT;
+ }
+
+ COMPUTE_Funcs();
+ COMPUTE_Round( (FT_Byte)exc->GS.round_state );
+
+ do
+ {
+ CUR.opcode = CUR.code[CUR.IP];
+
+ if ( ( CUR.length = opcode_length[CUR.opcode] ) < 0 )
+ {
+ if ( CUR.IP + 1 > CUR.codeSize )
+ goto LErrorCodeOverflow_;
+
+ CUR.length = CUR.code[CUR.IP + 1] + 2;
+ }
+
+ if ( CUR.IP + CUR.length > CUR.codeSize )
+ goto LErrorCodeOverflow_;
+
+ /* First, let's check for empty stack and overflow */
+ CUR.args = CUR.top - ( Pop_Push_Count[CUR.opcode] >> 4 );
+
+ /* `args' is the top of the stack once arguments have been popped. */
+ /* One can also interpret it as the index of the last argument. */
+ if ( CUR.args < 0 )
+ {
+ CUR.error = TT_Err_Too_Few_Arguments;
+ goto LErrorLabel_;
+ }
+
+ CUR.new_top = CUR.args + ( Pop_Push_Count[CUR.opcode] & 15 );
+
+ /* `new_top' is the new top of the stack, after the instruction's */
+ /* execution. `top' will be set to `new_top' after the `switch' */
+ /* statement. */
+ if ( CUR.new_top > CUR.stackSize )
+ {
+ CUR.error = TT_Err_Stack_Overflow;
+ goto LErrorLabel_;
+ }
+
+ CUR.step_ins = TRUE;
+ CUR.error = TT_Err_Ok;
+
+#ifdef TT_CONFIG_OPTION_INTERPRETER_SWITCH
+
+ {
+ FT_Long* args = CUR.stack + CUR.args;
+ FT_Byte opcode = CUR.opcode;
+
+
+#undef ARRAY_BOUND_ERROR
+#define ARRAY_BOUND_ERROR goto Set_Invalid_Ref
+
+
+ switch ( opcode )
+ {
+ case 0x00: /* SVTCA y */
+ case 0x01: /* SVTCA x */
+ case 0x02: /* SPvTCA y */
+ case 0x03: /* SPvTCA x */
+ case 0x04: /* SFvTCA y */
+ case 0x05: /* SFvTCA x */
+ {
+ FT_Short AA, BB;
+
+
+ AA = (FT_Short)( ( opcode & 1 ) << 14 );
+ BB = (FT_Short)( AA ^ 0x4000 );
+
+ if ( opcode < 4 )
+ {
+ CUR.GS.projVector.x = AA;
+ CUR.GS.projVector.y = BB;
+
+ CUR.GS.dualVector.x = AA;
+ CUR.GS.dualVector.y = BB;
+ }
+
+ if ( ( opcode & 2 ) == 0 )
+ {
+ CUR.GS.freeVector.x = AA;
+ CUR.GS.freeVector.y = BB;
+ }
+
+ COMPUTE_Funcs();
+ }
+ break;
+
+ case 0x06: /* SPvTL // */
+ case 0x07: /* SPvTL + */
+ DO_SPVTL
+ break;
+
+ case 0x08: /* SFvTL // */
+ case 0x09: /* SFvTL + */
+ DO_SFVTL
+ break;
+
+ case 0x0A: /* SPvFS */
+ DO_SPVFS
+ break;
+
+ case 0x0B: /* SFvFS */
+ DO_SFVFS
+ break;
+
+ case 0x0C: /* GPV */
+ DO_GPV
+ break;
+
+ case 0x0D: /* GFV */
+ DO_GFV
+ break;
+
+ case 0x0E: /* SFvTPv */
+ DO_SFVTPV
+ break;
+
+ case 0x0F: /* ISECT */
+ Ins_ISECT( EXEC_ARG_ args );
+ break;
+
+ case 0x10: /* SRP0 */
+ DO_SRP0
+ break;
+
+ case 0x11: /* SRP1 */
+ DO_SRP1
+ break;
+
+ case 0x12: /* SRP2 */
+ DO_SRP2
+ break;
+
+ case 0x13: /* SZP0 */
+ Ins_SZP0( EXEC_ARG_ args );
+ break;
+
+ case 0x14: /* SZP1 */
+ Ins_SZP1( EXEC_ARG_ args );
+ break;
+
+ case 0x15: /* SZP2 */
+ Ins_SZP2( EXEC_ARG_ args );
+ break;
+
+ case 0x16: /* SZPS */
+ Ins_SZPS( EXEC_ARG_ args );
+ break;
+
+ case 0x17: /* SLOOP */
+ DO_SLOOP
+ break;
+
+ case 0x18: /* RTG */
+ DO_RTG
+ break;
+
+ case 0x19: /* RTHG */
+ DO_RTHG
+ break;
+
+ case 0x1A: /* SMD */
+ DO_SMD
+ break;
+
+ case 0x1B: /* ELSE */
+ Ins_ELSE( EXEC_ARG_ args );
+ break;
+
+ case 0x1C: /* JMPR */
+ DO_JMPR
+ break;
+
+ case 0x1D: /* SCVTCI */
+ DO_SCVTCI
+ break;
+
+ case 0x1E: /* SSWCI */
+ DO_SSWCI
+ break;
+
+ case 0x1F: /* SSW */
+ DO_SSW
+ break;
+
+ case 0x20: /* DUP */
+ DO_DUP
+ break;
+
+ case 0x21: /* POP */
+ /* nothing :-) */
+ break;
+
+ case 0x22: /* CLEAR */
+ DO_CLEAR
+ break;
+
+ case 0x23: /* SWAP */
+ DO_SWAP
+ break;
+
+ case 0x24: /* DEPTH */
+ DO_DEPTH
+ break;
+
+ case 0x25: /* CINDEX */
+ DO_CINDEX
+ break;
+
+ case 0x26: /* MINDEX */
+ Ins_MINDEX( EXEC_ARG_ args );
+ break;
+
+ case 0x27: /* ALIGNPTS */
+ Ins_ALIGNPTS( EXEC_ARG_ args );
+ break;
+
+ case 0x28: /* ???? */
+ Ins_UNKNOWN( EXEC_ARG_ args );
+ break;
+
+ case 0x29: /* UTP */
+ Ins_UTP( EXEC_ARG_ args );
+ break;
+
+ case 0x2A: /* LOOPCALL */
+ Ins_LOOPCALL( EXEC_ARG_ args );
+ break;
+
+ case 0x2B: /* CALL */
+ Ins_CALL( EXEC_ARG_ args );
+ break;
+
+ case 0x2C: /* FDEF */
+ Ins_FDEF( EXEC_ARG_ args );
+ break;
+
+ case 0x2D: /* ENDF */
+ Ins_ENDF( EXEC_ARG_ args );
+ break;
+
+ case 0x2E: /* MDAP */
+ case 0x2F: /* MDAP */
+ Ins_MDAP( EXEC_ARG_ args );
+ break;
+
+
+ case 0x30: /* IUP */
+ case 0x31: /* IUP */
+ Ins_IUP( EXEC_ARG_ args );
+ break;
+
+ case 0x32: /* SHP */
+ case 0x33: /* SHP */
+ Ins_SHP( EXEC_ARG_ args );
+ break;
+
+ case 0x34: /* SHC */
+ case 0x35: /* SHC */
+ Ins_SHC( EXEC_ARG_ args );
+ break;
+
+ case 0x36: /* SHZ */
+ case 0x37: /* SHZ */
+ Ins_SHZ( EXEC_ARG_ args );
+ break;
+
+ case 0x38: /* SHPIX */
+ Ins_SHPIX( EXEC_ARG_ args );
+ break;
+
+ case 0x39: /* IP */
+ Ins_IP( EXEC_ARG_ args );
+ break;
+
+ case 0x3A: /* MSIRP */
+ case 0x3B: /* MSIRP */
+ Ins_MSIRP( EXEC_ARG_ args );
+ break;
+
+ case 0x3C: /* AlignRP */
+ Ins_ALIGNRP( EXEC_ARG_ args );
+ break;
+
+ case 0x3D: /* RTDG */
+ DO_RTDG
+ break;
+
+ case 0x3E: /* MIAP */
+ case 0x3F: /* MIAP */
+ Ins_MIAP( EXEC_ARG_ args );
+ break;
+
+ case 0x40: /* NPUSHB */
+ Ins_NPUSHB( EXEC_ARG_ args );
+ break;
+
+ case 0x41: /* NPUSHW */
+ Ins_NPUSHW( EXEC_ARG_ args );
+ break;
+
+ case 0x42: /* WS */
+ DO_WS
+ break;
+
+ Set_Invalid_Ref:
+ CUR.error = TT_Err_Invalid_Reference;
+ break;
+
+ case 0x43: /* RS */
+ DO_RS
+ break;
+
+ case 0x44: /* WCVTP */
+ DO_WCVTP
+ break;
+
+ case 0x45: /* RCVT */
+ DO_RCVT
+ break;
+
+ case 0x46: /* GC */
+ case 0x47: /* GC */
+ Ins_GC( EXEC_ARG_ args );
+ break;
+
+ case 0x48: /* SCFS */
+ Ins_SCFS( EXEC_ARG_ args );
+ break;
+
+ case 0x49: /* MD */
+ case 0x4A: /* MD */
+ Ins_MD( EXEC_ARG_ args );
+ break;
+
+ case 0x4B: /* MPPEM */
+ DO_MPPEM
+ break;
+
+ case 0x4C: /* MPS */
+ DO_MPS
+ break;
+
+ case 0x4D: /* FLIPON */
+ DO_FLIPON
+ break;
+
+ case 0x4E: /* FLIPOFF */
+ DO_FLIPOFF
+ break;
+
+ case 0x4F: /* DEBUG */
+ DO_DEBUG
+ break;
+
+ case 0x50: /* LT */
+ DO_LT
+ break;
+
+ case 0x51: /* LTEQ */
+ DO_LTEQ
+ break;
+
+ case 0x52: /* GT */
+ DO_GT
+ break;
+
+ case 0x53: /* GTEQ */
+ DO_GTEQ
+ break;
+
+ case 0x54: /* EQ */
+ DO_EQ
+ break;
+
+ case 0x55: /* NEQ */
+ DO_NEQ
+ break;
+
+ case 0x56: /* ODD */
+ DO_ODD
+ break;
+
+ case 0x57: /* EVEN */
+ DO_EVEN
+ break;
+
+ case 0x58: /* IF */
+ Ins_IF( EXEC_ARG_ args );
+ break;
+
+ case 0x59: /* EIF */
+ /* do nothing */
+ break;
+
+ case 0x5A: /* AND */
+ DO_AND
+ break;
+
+ case 0x5B: /* OR */
+ DO_OR
+ break;
+
+ case 0x5C: /* NOT */
+ DO_NOT
+ break;
+
+ case 0x5D: /* DELTAP1 */
+ Ins_DELTAP( EXEC_ARG_ args );
+ break;
+
+ case 0x5E: /* SDB */
+ DO_SDB
+ break;
+
+ case 0x5F: /* SDS */
+ DO_SDS
+ break;
+
+ case 0x60: /* ADD */
+ DO_ADD
+ break;
+
+ case 0x61: /* SUB */
+ DO_SUB
+ break;
+
+ case 0x62: /* DIV */
+ DO_DIV
+ break;
+
+ case 0x63: /* MUL */
+ DO_MUL
+ break;
+
+ case 0x64: /* ABS */
+ DO_ABS
+ break;
+
+ case 0x65: /* NEG */
+ DO_NEG
+ break;
+
+ case 0x66: /* FLOOR */
+ DO_FLOOR
+ break;
+
+ case 0x67: /* CEILING */
+ DO_CEILING
+ break;
+
+ case 0x68: /* ROUND */
+ case 0x69: /* ROUND */
+ case 0x6A: /* ROUND */
+ case 0x6B: /* ROUND */
+ DO_ROUND
+ break;
+
+ case 0x6C: /* NROUND */
+ case 0x6D: /* NROUND */
+ case 0x6E: /* NRRUND */
+ case 0x6F: /* NROUND */
+ DO_NROUND
+ break;
+
+ case 0x70: /* WCVTF */
+ DO_WCVTF
+ break;
+
+ case 0x71: /* DELTAP2 */
+ case 0x72: /* DELTAP3 */
+ Ins_DELTAP( EXEC_ARG_ args );
+ break;
+
+ case 0x73: /* DELTAC0 */
+ case 0x74: /* DELTAC1 */
+ case 0x75: /* DELTAC2 */
+ Ins_DELTAC( EXEC_ARG_ args );
+ break;
+
+ case 0x76: /* SROUND */
+ DO_SROUND
+ break;
+
+ case 0x77: /* S45Round */
+ DO_S45ROUND
+ break;
+
+ case 0x78: /* JROT */
+ DO_JROT
+ break;
+
+ case 0x79: /* JROF */
+ DO_JROF
+ break;
+
+ case 0x7A: /* ROFF */
+ DO_ROFF
+ break;
+
+ case 0x7B: /* ???? */
+ Ins_UNKNOWN( EXEC_ARG_ args );
+ break;
+
+ case 0x7C: /* RUTG */
+ DO_RUTG
+ break;
+
+ case 0x7D: /* RDTG */
+ DO_RDTG
+ break;
+
+ case 0x7E: /* SANGW */
+ case 0x7F: /* AA */
+ /* nothing - obsolete */
+ break;
+
+ case 0x80: /* FLIPPT */
+ Ins_FLIPPT( EXEC_ARG_ args );
+ break;
+
+ case 0x81: /* FLIPRGON */
+ Ins_FLIPRGON( EXEC_ARG_ args );
+ break;
+
+ case 0x82: /* FLIPRGOFF */
+ Ins_FLIPRGOFF( EXEC_ARG_ args );
+ break;
+
+ case 0x83: /* UNKNOWN */
+ case 0x84: /* UNKNOWN */
+ Ins_UNKNOWN( EXEC_ARG_ args );
+ break;
+
+ case 0x85: /* SCANCTRL */
+ Ins_SCANCTRL( EXEC_ARG_ args );
+ break;
+
+ case 0x86: /* SDPVTL */
+ case 0x87: /* SDPVTL */
+ Ins_SDPVTL( EXEC_ARG_ args );
+ break;
+
+ case 0x88: /* GETINFO */
+ Ins_GETINFO( EXEC_ARG_ args );
+ break;
+
+ case 0x89: /* IDEF */
+ Ins_IDEF( EXEC_ARG_ args );
+ break;
+
+ case 0x8A: /* ROLL */
+ Ins_ROLL( EXEC_ARG_ args );
+ break;
+
+ case 0x8B: /* MAX */
+ DO_MAX
+ break;
+
+ case 0x8C: /* MIN */
+ DO_MIN
+ break;
+
+ case 0x8D: /* SCANTYPE */
+ Ins_SCANTYPE( EXEC_ARG_ args );
+ break;
+
+ case 0x8E: /* INSTCTRL */
+ Ins_INSTCTRL( EXEC_ARG_ args );
+ break;
+
+ case 0x8F:
+ Ins_UNKNOWN( EXEC_ARG_ args );
+ break;
+
+ default:
+ if ( opcode >= 0xE0 )
+ Ins_MIRP( EXEC_ARG_ args );
+ else if ( opcode >= 0xC0 )
+ Ins_MDRP( EXEC_ARG_ args );
+ else if ( opcode >= 0xB8 )
+ Ins_PUSHW( EXEC_ARG_ args );
+ else if ( opcode >= 0xB0 )
+ Ins_PUSHB( EXEC_ARG_ args );
+ else
+ Ins_UNKNOWN( EXEC_ARG_ args );
+ }
+
+ }
+
+#else
+
+ Instruct_Dispatch[CUR.opcode]( EXEC_ARG_ &CUR.stack[CUR.args] );
+
+#endif /* TT_CONFIG_OPTION_INTERPRETER_SWITCH */
+
+ if ( CUR.error != TT_Err_Ok )
+ {
+ switch ( CUR.error )
+ {
+ case TT_Err_Invalid_Opcode: /* looking for redefined instructions */
+ {
+ TT_DefRecord* def = CUR.IDefs;
+ TT_DefRecord* limit = def + CUR.numIDefs;
+
+
+ for ( ; def < limit; def++ )
+ {
+ if ( def->active && CUR.opcode == (FT_Byte)def->opc )
+ {
+ TT_CallRec* callrec;
+
+
+ if ( CUR.callTop >= CUR.callSize )
+ {
+ CUR.error = TT_Err_Invalid_Reference;
+ goto LErrorLabel_;
+ }
+
+ callrec = &CUR.callStack[CUR.callTop];
+
+ callrec->Caller_Range = CUR.curRange;
+ callrec->Caller_IP = CUR.IP + 1;
+ callrec->Cur_Count = 1;
+ callrec->Cur_Restart = def->start;
+
+ if ( INS_Goto_CodeRange( def->range, def->start ) == FAILURE )
+ goto LErrorLabel_;
+
+ goto LSuiteLabel_;
+ }
+ }
+ }
+
+ CUR.error = TT_Err_Invalid_Opcode;
+ goto LErrorLabel_;
+
+#if 0
+ break; /* Unreachable code warning suppression. */
+ /* Leave to remind in case a later change the editor */
+ /* to consider break; */
+#endif
+
+ default:
+ goto LErrorLabel_;
+
+#if 0
+ break;
+#endif
+ }
+ }
+
+ CUR.top = CUR.new_top;
+
+ if ( CUR.step_ins )
+ CUR.IP += CUR.length;
+
+ /* increment instruction counter and check if we didn't */
+ /* run this program for too long (e.g. infinite loops). */
+ if ( ++ins_counter > MAX_RUNNABLE_OPCODES )
+ return TT_Err_Execution_Too_Long;
+
+ LSuiteLabel_:
+ if ( CUR.IP >= CUR.codeSize )
+ {
+ if ( CUR.callTop > 0 )
+ {
+ CUR.error = TT_Err_Code_Overflow;
+ goto LErrorLabel_;
+ }
+ else
+ goto LNo_Error_;
+ }
+ } while ( !CUR.instruction_trap );
+
+ LNo_Error_:
+
+#ifdef TT_CONFIG_OPTION_STATIC_RASTER
+ *exc = cur;
+#endif
+
+ return TT_Err_Ok;
+
+ LErrorCodeOverflow_:
+ CUR.error = TT_Err_Code_Overflow;
+
+ LErrorLabel_:
+
+#ifdef TT_CONFIG_OPTION_STATIC_RASTER
+ *exc = cur;
+#endif
+
+ return CUR.error;
+ }
+
+
+#endif /* TT_CONFIG_OPTION_BYTECODE_INTERPRETER */
+
+
+/* END */
--- /dev/null
+++ b/libfreetype/ttinterp.h
@@ -1,0 +1,317 @@
+/***************************************************************************/
+/* */
+/* ttinterp.h */
+/* */
+/* TrueType bytecode interpreter (specification). */
+/* */
+/* Copyright 1996-2001, 2002 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+
+#ifndef __TTINTERP_H__
+#define __TTINTERP_H__
+
+
+#include <ft2build.h>
+#include "ttobjs.h"
+
+
+FT_BEGIN_HEADER
+
+
+#ifndef TT_CONFIG_OPTION_STATIC_INTEPRETER /* indirect implementation */
+
+#define EXEC_OP_ TT_ExecContext exc,
+#define EXEC_OP TT_ExecContext exc
+#define EXEC_ARG_ exc,
+#define EXEC_ARG exc
+
+#else /* static implementation */
+
+#define EXEC_OP_ /* void */
+#define EXEC_OP /* void */
+#define EXEC_ARG_ /* void */
+#define EXEC_ARG /* void */
+
+#endif /* TT_CONFIG_OPTION_STATIC_INTERPRETER */
+
+
+ /*************************************************************************/
+ /* */
+ /* Rounding mode constants. */
+ /* */
+#define TT_Round_Off 5
+#define TT_Round_To_Half_Grid 0
+#define TT_Round_To_Grid 1
+#define TT_Round_To_Double_Grid 2
+#define TT_Round_Up_To_Grid 4
+#define TT_Round_Down_To_Grid 3
+#define TT_Round_Super 6
+#define TT_Round_Super_45 7
+
+
+ /*************************************************************************/
+ /* */
+ /* Function types used by the interpreter, depending on various modes */
+ /* (e.g. the rounding mode, whether to render a vertical or horizontal */
+ /* line etc). */
+ /* */
+ /*************************************************************************/
+
+ /* Rounding function */
+ typedef FT_F26Dot6
+ (*TT_Round_Func)( EXEC_OP_ FT_F26Dot6 distance,
+ FT_F26Dot6 compensation );
+
+ /* Point displacement along the freedom vector routine */
+ typedef void
+ (*TT_Move_Func)( EXEC_OP_ TT_GlyphZone zone,
+ FT_UShort point,
+ FT_F26Dot6 distance );
+
+ /* Distance projection along one of the projection vectors */
+ typedef FT_F26Dot6
+ (*TT_Project_Func)( EXEC_OP_ FT_Vector* v1,
+ FT_Vector* v2 );
+
+ /* reading a cvt value. Take care of non-square pixels if necessary */
+ typedef FT_F26Dot6
+ (*TT_Get_CVT_Func)( EXEC_OP_ FT_ULong idx );
+
+ /* setting or moving a cvt value. Take care of non-square pixels */
+ /* if necessary */
+ typedef void
+ (*TT_Set_CVT_Func)( EXEC_OP_ FT_ULong idx,
+ FT_F26Dot6 value );
+
+
+ /*************************************************************************/
+ /* */
+ /* This structure defines a call record, used to manage function calls. */
+ /* */
+ typedef struct TT_CallRec_
+ {
+ FT_Int Caller_Range;
+ FT_Long Caller_IP;
+ FT_Long Cur_Count;
+ FT_Long Cur_Restart;
+
+ } TT_CallRec, *TT_CallStack;
+
+
+ /*************************************************************************/
+ /* */
+ /* The main structure for the interpreter which collects all necessary */
+ /* variables and states. */
+ /* */
+ typedef struct TT_ExecContextRec_
+ {
+ TT_Face face;
+ TT_Size size;
+ FT_Memory memory;
+
+ /* instructions state */
+
+ FT_Error error; /* last execution error */
+
+ FT_Long top; /* top of exec. stack */
+
+ FT_UInt stackSize; /* size of exec. stack */
+ FT_Long* stack; /* current exec. stack */
+
+ FT_Long args;
+ FT_UInt new_top; /* new top after exec. */
+
+ TT_GlyphZoneRec zp0, /* zone records */
+ zp1,
+ zp2,
+ pts,
+ twilight;
+
+ FT_Size_Metrics metrics;
+ TT_Size_Metrics tt_metrics; /* size metrics */
+
+ TT_GraphicsState GS; /* current graphics state */
+
+ FT_Int curRange; /* current code range number */
+ FT_Byte* code; /* current code range */
+ FT_Long IP; /* current instruction pointer */
+ FT_Long codeSize; /* size of current range */
+
+ FT_Byte opcode; /* current opcode */
+ FT_Int length; /* length of current opcode */
+
+ FT_Bool step_ins; /* true if the interpreter must */
+ /* increment IP after ins. exec */
+ FT_Long cvtSize;
+ FT_Long* cvt;
+
+ FT_UInt glyphSize; /* glyph instructions buffer size */
+ FT_Byte* glyphIns; /* glyph instructions buffer */
+
+ FT_UInt numFDefs; /* number of function defs */
+ FT_UInt maxFDefs; /* maximum number of function defs */
+ TT_DefArray FDefs; /* table of FDefs entries */
+
+ FT_UInt numIDefs; /* number of instruction defs */
+ FT_UInt maxIDefs; /* maximum number of ins defs */
+ TT_DefArray IDefs; /* table of IDefs entries */
+
+ FT_UInt maxFunc; /* maximum function index */
+ FT_UInt maxIns; /* maximum instruction index */
+
+ FT_Int callTop, /* top of call stack during execution */
+ callSize; /* size of call stack */
+ TT_CallStack callStack; /* call stack */
+
+ FT_UShort maxPoints; /* capacity of this context's `pts' */
+ FT_Short maxContours; /* record, expressed in points and */
+ /* contours. */
+
+ TT_CodeRangeTable codeRangeTable; /* table of valid code ranges */
+ /* useful for the debugger */
+
+ FT_UShort storeSize; /* size of current storage */
+ FT_Long* storage; /* storage area */
+
+ FT_F26Dot6 period; /* values used for the */
+ FT_F26Dot6 phase; /* `SuperRounding' */
+ FT_F26Dot6 threshold;
+
+#if 0
+ /* this seems to be unused */
+ FT_Int cur_ppem; /* ppem along the current proj vector */
+#endif
+
+ FT_Bool instruction_trap; /* If `True', the interpreter will */
+ /* exit after each instruction */
+
+ TT_GraphicsState default_GS; /* graphics state resulting from */
+ /* the prep program */
+ FT_Bool is_composite; /* true if the glyph is composite */
+ FT_Bool pedantic_hinting; /* true if pedantic interpretation */
+
+ /* latest interpreter additions */
+
+ FT_Long F_dot_P; /* dot product of freedom and projection */
+ /* vectors */
+ TT_Round_Func func_round; /* current rounding function */
+
+ TT_Project_Func func_project, /* current projection function */
+ func_dualproj, /* current dual proj. function */
+ func_freeProj; /* current freedom proj. func */
+
+ TT_Move_Func func_move; /* current point move function */
+
+ TT_Get_CVT_Func func_read_cvt; /* read a cvt entry */
+ TT_Set_CVT_Func func_write_cvt; /* write a cvt entry (in pixels) */
+ TT_Set_CVT_Func func_move_cvt; /* incr a cvt entry (in pixels) */
+
+ FT_ULong loadSize;
+ TT_SubGlyph_Stack loadStack; /* loading subglyph stack */
+
+ } TT_ExecContextRec;
+
+
+ extern const TT_GraphicsState tt_default_graphics_state;
+
+
+ FT_LOCAL( FT_Error )
+ TT_Goto_CodeRange( TT_ExecContext exec,
+ FT_Int range,
+ FT_Long IP );
+
+ FT_LOCAL( FT_Error )
+ TT_Set_CodeRange( TT_ExecContext exec,
+ FT_Int range,
+ void* base,
+ FT_Long length );
+
+ FT_LOCAL( FT_Error )
+ TT_Clear_CodeRange( TT_ExecContext exec,
+ FT_Int range );
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* TT_New_Context */
+ /* */
+ /* <Description> */
+ /* Queries the face context for a given font. Note that there is */
+ /* now a _single_ execution context in the TrueType driver which is */
+ /* shared among faces. */
+ /* */
+ /* <Input> */
+ /* face :: A handle to the source face object. */
+ /* */
+ /* <Return> */
+ /* A handle to the execution context. Initialized for `face'. */
+ /* */
+ /* <Note> */
+ /* Only the glyph loader and debugger should call this function. */
+ /* */
+ FT_EXPORT( TT_ExecContext )
+ TT_New_Context( TT_Face face );
+
+
+ FT_LOCAL( FT_Error )
+ TT_Done_Context( TT_ExecContext exec );
+
+ FT_LOCAL( FT_Error )
+ TT_Destroy_Context( TT_ExecContext exec,
+ FT_Memory memory );
+
+ FT_LOCAL( FT_Error )
+ TT_Load_Context( TT_ExecContext exec,
+ TT_Face face,
+ TT_Size size );
+
+ FT_LOCAL( FT_Error )
+ TT_Save_Context( TT_ExecContext exec,
+ TT_Size ins );
+
+ FT_LOCAL( FT_Error )
+ TT_Run_Context( TT_ExecContext exec,
+ FT_Bool debug );
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* TT_RunIns */
+ /* */
+ /* <Description> */
+ /* Executes one or more instruction in the execution context. This */
+ /* is the main function of the TrueType opcode interpreter. */
+ /* */
+ /* <Input> */
+ /* exec :: A handle to the target execution context. */
+ /* */
+ /* <Return> */
+ /* FreeType error code. 0 means success. */
+ /* */
+ /* <Note> */
+ /* Only the object manager and debugger should call this function. */
+ /* */
+ /* This function is publicly exported because it is directly */
+ /* invoked by the TrueType debugger. */
+ /* */
+ FT_EXPORT( FT_Error )
+ TT_RunIns( TT_ExecContext exec );
+
+
+FT_END_HEADER
+
+#endif /* __TTINTERP_H__ */
+
+
+/* END */
--- /dev/null
+++ b/libfreetype/ttload.c
@@ -1,0 +1,1849 @@
+/***************************************************************************/
+/* */
+/* ttload.c */
+/* */
+/* Load the basic TrueType tables, i.e., tables that can be either in */
+/* TTF or OTF fonts (body). */
+/* */
+/* Copyright 1996-2001, 2002 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+
+#include <ft2build.h>
+#include FT_INTERNAL_DEBUG_H
+#include FT_INTERNAL_STREAM_H
+#include FT_TRUETYPE_TAGS_H
+#include "ttload.h"
+#include "ttcmap.h"
+
+#include "sferrors.h"
+
+
+ /*************************************************************************/
+ /* */
+ /* The macro FT_COMPONENT is used in trace mode. It is an implicit */
+ /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log */
+ /* messages during execution. */
+ /* */
+#undef FT_COMPONENT
+#define FT_COMPONENT trace_ttload
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* tt_face_lookup_table */
+ /* */
+ /* <Description> */
+ /* Looks for a TrueType table by name. */
+ /* */
+ /* <Input> */
+ /* face :: A face object handle. */
+ /* */
+ /* tag :: The searched tag. */
+ /* */
+ /* <Return> */
+ /* A pointer to the table directory entry. 0 if not found. */
+ /* */
+ FT_LOCAL_DEF( TT_Table )
+ tt_face_lookup_table( TT_Face face,
+ FT_ULong tag )
+ {
+ TT_Table entry;
+ TT_Table limit;
+
+
+ FT_TRACE3(( "tt_face_lookup_table: %08p, `%c%c%c%c' -- ",
+ face,
+ (FT_Char)( tag >> 24 ),
+ (FT_Char)( tag >> 16 ),
+ (FT_Char)( tag >> 8 ),
+ (FT_Char)( tag ) ));
+
+ entry = face->dir_tables;
+ limit = entry + face->num_tables;
+
+ for ( ; entry < limit; entry++ )
+ {
+ /* For compatibility with Windows, we consider 0-length */
+ /* tables the same as missing tables. */
+ if ( entry->Tag == tag && entry->Length != 0 )
+ {
+ FT_TRACE3(( "found table.\n" ));
+ return entry;
+ }
+ }
+
+ FT_TRACE3(( "could not find table!\n" ));
+ return 0;
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* tt_face_goto_table */
+ /* */
+ /* <Description> */
+ /* Looks for a TrueType table by name, then seek a stream to it. */
+ /* */
+ /* <Input> */
+ /* face :: A face object handle. */
+ /* */
+ /* tag :: The searched tag. */
+ /* */
+ /* stream :: The stream to seek when the table is found. */
+ /* */
+ /* <Output> */
+ /* length :: The length of the table if found, undefined otherwise. */
+ /* */
+ /* <Return> */
+ /* FreeType error code. 0 means success. */
+ /* */
+ FT_LOCAL_DEF( FT_Error )
+ tt_face_goto_table( TT_Face face,
+ FT_ULong tag,
+ FT_Stream stream,
+ FT_ULong* length )
+ {
+ TT_Table table;
+ FT_Error error;
+
+
+ table = tt_face_lookup_table( face, tag );
+ if ( table )
+ {
+ if ( length )
+ *length = table->Length;
+
+ if ( FT_STREAM_SEEK( table->Offset ) )
+ goto Exit;
+ }
+ else
+ error = SFNT_Err_Table_Missing;
+
+ Exit:
+ return error;
+ }
+
+
+ /* In theory, we should check the values of `search_range', */
+ /* `entry_selector', and `range_shift' to detect non-SFNT based files */
+ /* whose header might also start with 0x100000L (yes, these exist). */
+ /* */
+ /* Very unfortunately, many TrueType fonts don't have these fields */
+ /* set correctly and we must ignore them to support them. An alternative */
+ /* way to check the font file is thus to: */
+ /* */
+ /* - check that `num_tables' is valid */
+ /* - look for a "head" table, check its size, and parse it to */
+ /* see if its "magic" field is correctly set */
+ /* */
+ /* When checking directory entries, ignore the tables `glyx' and `locx' */
+ /* which are hacked-out versions of `glyf' and `loca' in some PostScript */
+ /* Type 42 fonts, and will generally be invalid. */
+ /* */
+ static FT_Error
+ sfnt_dir_check( FT_Stream stream,
+ FT_ULong offset,
+ FT_UInt num_tables )
+ {
+ FT_Error error;
+ FT_UInt nn, has_head = 0;
+
+ const FT_ULong glyx_tag = FT_MAKE_TAG( 'g', 'l', 'y', 'x' );
+ const FT_ULong locx_tag = FT_MAKE_TAG( 'l', 'o', 'c', 'x' );
+
+ static const FT_Frame_Field sfnt_dir_entry_fields[] =
+ {
+#undef FT_STRUCTURE
+#define FT_STRUCTURE TT_TableRec
+
+ FT_FRAME_START( 16 ),
+ FT_FRAME_ULONG( Tag ),
+ FT_FRAME_ULONG( CheckSum ),
+ FT_FRAME_ULONG( Offset ),
+ FT_FRAME_ULONG( Length ),
+ FT_FRAME_END
+ };
+
+
+ /* if 'num_tables' is 0, read the table count from the file */
+ if ( num_tables == 0 )
+ {
+ FT_ULong format_tag;
+
+
+ if ( FT_STREAM_SEEK( offset ) ||
+ FT_READ_ULONG ( format_tag ) ||
+ FT_READ_USHORT( num_tables ) ||
+ FT_STREAM_SKIP( 6 ) )
+ goto Bad_Format;
+
+ if ( offset + 12 + num_tables*16 > stream->size )
+ goto Bad_Format;
+ }
+ else if ( FT_STREAM_SEEK( offset + 12 ) )
+ goto Bad_Format;
+
+ for ( nn = 0; nn < num_tables; nn++ )
+ {
+ TT_TableRec table;
+
+
+ if ( FT_STREAM_READ_FIELDS( sfnt_dir_entry_fields, &table ) )
+ goto Bad_Format;
+
+ if ( table.Offset + table.Length > stream->size &&
+ table.Tag != glyx_tag && table.Tag != locx_tag )
+ goto Bad_Format;
+
+ if ( table.Tag == TTAG_head )
+ {
+ FT_UInt32 magic;
+
+
+ has_head = 1;
+
+ if ( table.Length != 0x36 ||
+ FT_STREAM_SEEK( table.Offset + 12 ) ||
+ FT_READ_ULONG( magic ) ||
+ magic != 0x5F0F3CF5UL )
+ goto Bad_Format;
+
+ if ( FT_STREAM_SEEK( offset + 28 + 16*nn ) )
+ goto Bad_Format;
+ }
+ }
+
+ if ( has_head == 0 )
+ goto Bad_Format;
+
+ Exit:
+ return error;
+
+ Bad_Format:
+ error = FT_Err_Unknown_File_Format;
+ goto Exit;
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* tt_face_load_sfnt_header */
+ /* */
+ /* <Description> */
+ /* Loads the header of a SFNT font file. Supports collections. */
+ /* */
+ /* <Input> */
+ /* face :: A handle to the target face object. */
+ /* */
+ /* stream :: The input stream. */
+ /* */
+ /* face_index :: If the font is a collection, the number of the font */
+ /* in the collection, ignored otherwise. */
+ /* */
+ /* <Output> */
+ /* sfnt :: The SFNT header. */
+ /* */
+ /* <Return> */
+ /* FreeType error code. 0 means success. */
+ /* */
+ /* <Note> */
+ /* The stream cursor must be at the font file's origin. */
+ /* */
+ /* This function recognizes fonts embedded in a `TrueType collection' */
+ /* */
+ /* The header will be checked whether it is valid by looking at the */
+ /* values of `search_range', `entry_selector', and `range_shift'. */
+ /* */
+ FT_LOCAL_DEF( FT_Error )
+ tt_face_load_sfnt_header( TT_Face face,
+ FT_Stream stream,
+ FT_Long face_index,
+ SFNT_Header sfnt )
+ {
+ FT_Error error;
+ FT_ULong format_tag, offset;
+ FT_Memory memory = stream->memory;
+
+ static const FT_Frame_Field sfnt_header_fields[] =
+ {
+#undef FT_STRUCTURE
+#define FT_STRUCTURE SFNT_HeaderRec
+
+ FT_FRAME_START( 8 ),
+ FT_FRAME_USHORT( num_tables ),
+ FT_FRAME_USHORT( search_range ),
+ FT_FRAME_USHORT( entry_selector ),
+ FT_FRAME_USHORT( range_shift ),
+ FT_FRAME_END
+ };
+
+ static const FT_Frame_Field ttc_header_fields[] =
+ {
+#undef FT_STRUCTURE
+#define FT_STRUCTURE TTC_HeaderRec
+
+ FT_FRAME_START( 8 ),
+ FT_FRAME_LONG( version ),
+ FT_FRAME_LONG( count ),
+ FT_FRAME_END
+ };
+
+
+ FT_TRACE2(( "tt_face_load_sfnt_header: %08p, %ld\n",
+ face, face_index ));
+
+ face->ttc_header.tag = 0;
+ face->ttc_header.version = 0;
+ face->ttc_header.count = 0;
+
+ face->num_tables = 0;
+
+ /* first of all, read the first 4 bytes. If it is `ttcf', then the */
+ /* file is a TrueType collection, otherwise it can be any other */
+ /* kind of font. */
+ /* */
+ offset = FT_STREAM_POS();
+
+ if ( FT_READ_ULONG( format_tag ) )
+ goto Exit;
+
+ if ( format_tag == TTAG_ttcf )
+ {
+ FT_Int n;
+
+
+ FT_TRACE3(( "tt_face_load_sfnt_header: file is a collection\n" ));
+
+ /* It is a TrueType collection, i.e. a file containing several */
+ /* font files. Read the font directory now */
+ if ( FT_STREAM_READ_FIELDS( ttc_header_fields, &face->ttc_header ) )
+ goto Exit;
+
+ /* now read the offsets of each font in the file */
+ if ( FT_NEW_ARRAY( face->ttc_header.offsets, face->ttc_header.count ) ||
+ FT_FRAME_ENTER( face->ttc_header.count * 4L ) )
+ goto Exit;
+
+ for ( n = 0; n < face->ttc_header.count; n++ )
+ face->ttc_header.offsets[n] = FT_GET_ULONG();
+
+ FT_FRAME_EXIT();
+
+ /* check face index */
+ if ( face_index >= face->ttc_header.count )
+ {
+ error = SFNT_Err_Bad_Argument;
+ goto Exit;
+ }
+
+ /* seek to the appropriate TrueType file, then read tag */
+ offset = face->ttc_header.offsets[face_index];
+
+ if ( FT_STREAM_SEEK( offset ) ||
+ FT_READ_LONG( format_tag ) )
+ goto Exit;
+ }
+
+ /* the format tag was read, now check the rest of the header */
+ sfnt->format_tag = format_tag;
+ sfnt->offset = offset;
+
+ if ( FT_STREAM_READ_FIELDS( sfnt_header_fields, sfnt ) )
+ goto Exit;
+
+ /* now check the sfnt directory */
+ error = sfnt_dir_check( stream, offset, sfnt->num_tables );
+ if ( error )
+ {
+ FT_TRACE2(( "tt_face_load_sfnt_header: file is not SFNT!\n" ));
+ error = SFNT_Err_Unknown_File_Format;
+ }
+
+ Exit:
+ return error;
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* tt_face_load_directory */
+ /* */
+ /* <Description> */
+ /* Loads the table directory into a face object. */
+ /* */
+ /* <InOut> */
+ /* face :: A handle to the target face object. */
+ /* */
+ /* <Input> */
+ /* stream :: The input stream. */
+ /* */
+ /* sfnt :: The SFNT directory header. */
+ /* */
+ /* <Return> */
+ /* FreeType error code. 0 means success. */
+ /* */
+ /* <Note> */
+ /* The stream cursor must be at the font file's origin. */
+ /* */
+ FT_LOCAL_DEF( FT_Error )
+ tt_face_load_directory( TT_Face face,
+ FT_Stream stream,
+ SFNT_Header sfnt )
+ {
+ FT_Error error;
+ FT_Memory memory = stream->memory;
+
+ TT_TableRec *entry, *limit;
+
+
+ FT_TRACE2(( "tt_face_load_directory: %08p\n", face ));
+
+ FT_TRACE2(( "-- Tables count: %12u\n", sfnt->num_tables ));
+ FT_TRACE2(( "-- Format version: %08lx\n", sfnt->format_tag ));
+
+ face->num_tables = sfnt->num_tables;
+
+ if ( FT_NEW_ARRAY( face->dir_tables, face->num_tables ) )
+ goto Exit;
+
+ if ( FT_STREAM_SEEK( sfnt->offset + 12 ) ||
+ FT_FRAME_ENTER( face->num_tables * 16L ) )
+ goto Exit;
+
+ entry = face->dir_tables;
+ limit = entry + face->num_tables;
+
+ for ( ; entry < limit; entry++ )
+ { /* loop through the tables and get all entries */
+ entry->Tag = FT_GET_TAG4();
+ entry->CheckSum = FT_GET_ULONG();
+ entry->Offset = FT_GET_LONG();
+ entry->Length = FT_GET_LONG();
+
+ FT_TRACE2(( " %c%c%c%c - %08lx - %08lx\n",
+ (FT_Char)( entry->Tag >> 24 ),
+ (FT_Char)( entry->Tag >> 16 ),
+ (FT_Char)( entry->Tag >> 8 ),
+ (FT_Char)( entry->Tag ),
+ entry->Offset,
+ entry->Length ));
+ }
+
+ FT_FRAME_EXIT();
+
+ FT_TRACE2(( "Directory loaded\n\n" ));
+
+ Exit:
+ return error;
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* tt_face_load_any */
+ /* */
+ /* <Description> */
+ /* Loads any font table into client memory. */
+ /* */
+ /* <Input> */
+ /* face :: The face object to look for. */
+ /* */
+ /* tag :: The tag of table to load. Use the value 0 if you want */
+ /* to access the whole font file, else set this parameter */
+ /* to a valid TrueType table tag that you can forge with */
+ /* the MAKE_TT_TAG macro. */
+ /* */
+ /* offset :: The starting offset in the table (or the file if */
+ /* tag == 0). */
+ /* */
+ /* length :: The address of the decision variable: */
+ /* */
+ /* If length == NULL: */
+ /* Loads the whole table. Returns an error if */
+ /* `offset' == 0! */
+ /* */
+ /* If *length == 0: */
+ /* Exits immediately; returning the length of the given */
+ /* table or of the font file, depending on the value of */
+ /* `tag'. */
+ /* */
+ /* If *length != 0: */
+ /* Loads the next `length' bytes of table or font, */
+ /* starting at offset `offset' (in table or font too). */
+ /* */
+ /* <Output> */
+ /* buffer :: The address of target buffer. */
+ /* */
+ /* <Return> */
+ /* FreeType error code. 0 means success. */
+ /* */
+ FT_LOCAL_DEF( FT_Error )
+ tt_face_load_any( TT_Face face,
+ FT_ULong tag,
+ FT_Long offset,
+ FT_Byte* buffer,
+ FT_ULong* length )
+ {
+ FT_Error error;
+ FT_Stream stream;
+ TT_Table table;
+ FT_ULong size;
+
+
+ if ( tag != 0 )
+ {
+ /* look for tag in font directory */
+ table = tt_face_lookup_table( face, tag );
+ if ( !table )
+ {
+ error = SFNT_Err_Table_Missing;
+ goto Exit;
+ }
+
+ offset += table->Offset;
+ size = table->Length;
+ }
+ else
+ /* tag == 0 -- the user wants to access the font file directly */
+ size = face->root.stream->size;
+
+ if ( length && *length == 0 )
+ {
+ *length = size;
+
+ return SFNT_Err_Ok;
+ }
+
+ if ( length )
+ size = *length;
+
+ stream = face->root.stream;
+ /* the `if' is syntactic sugar for picky compilers */
+ if ( FT_STREAM_READ_AT( offset, buffer, size ) )
+ goto Exit;
+
+ Exit:
+ return error;
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* tt_face_load_generic_header */
+ /* */
+ /* <Description> */
+ /* Loads the TrueType table `head' or `bhed'. */
+ /* */
+ /* <Input> */
+ /* face :: A handle to the target face object. */
+ /* */
+ /* stream :: The input stream. */
+ /* */
+ /* <Return> */
+ /* FreeType error code. 0 means success. */
+ /* */
+ static FT_Error
+ tt_face_load_generic_header( TT_Face face,
+ FT_Stream stream,
+ FT_ULong tag )
+ {
+ FT_Error error;
+ TT_Header* header;
+
+ static const FT_Frame_Field header_fields[] =
+ {
+#undef FT_STRUCTURE
+#define FT_STRUCTURE TT_Header
+
+ FT_FRAME_START( 54 ),
+ FT_FRAME_ULONG ( Table_Version ),
+ FT_FRAME_ULONG ( Font_Revision ),
+ FT_FRAME_LONG ( CheckSum_Adjust ),
+ FT_FRAME_LONG ( Magic_Number ),
+ FT_FRAME_USHORT( Flags ),
+ FT_FRAME_USHORT( Units_Per_EM ),
+ FT_FRAME_LONG ( Created[0] ),
+ FT_FRAME_LONG ( Created[1] ),
+ FT_FRAME_LONG ( Modified[0] ),
+ FT_FRAME_LONG ( Modified[1] ),
+ FT_FRAME_SHORT ( xMin ),
+ FT_FRAME_SHORT ( yMin ),
+ FT_FRAME_SHORT ( xMax ),
+ FT_FRAME_SHORT ( yMax ),
+ FT_FRAME_USHORT( Mac_Style ),
+ FT_FRAME_USHORT( Lowest_Rec_PPEM ),
+ FT_FRAME_SHORT ( Font_Direction ),
+ FT_FRAME_SHORT ( Index_To_Loc_Format ),
+ FT_FRAME_SHORT ( Glyph_Data_Format ),
+ FT_FRAME_END
+ };
+
+
+ FT_TRACE2(( "tt_face_load_generic_header: "
+ "%08p, looking up font table `%c%c%c%c'.\n",
+ face,
+ (FT_Char)( tag >> 24 ),
+ (FT_Char)( tag >> 16 ),
+ (FT_Char)( tag >> 8 ),
+ (FT_Char)( tag ) ));
+
+ error = face->goto_table( face, tag, stream, 0 );
+ if ( error )
+ {
+ FT_TRACE2(( "tt_face_load_generic_header: Font table is missing!\n" ));
+ goto Exit;
+ }
+
+ header = &face->header;
+
+ if ( FT_STREAM_READ_FIELDS( header_fields, header ) )
+ goto Exit;
+
+ FT_TRACE2(( " Units per EM: %8u\n", header->Units_Per_EM ));
+ FT_TRACE2(( " IndexToLoc: %8d\n", header->Index_To_Loc_Format ));
+ FT_TRACE2(( "tt_face_load_generic_header: Font table loaded.\n" ));
+
+ Exit:
+ return error;
+ }
+
+
+ FT_LOCAL_DEF( FT_Error )
+ tt_face_load_header( TT_Face face,
+ FT_Stream stream )
+ {
+ return tt_face_load_generic_header( face, stream, TTAG_head );
+ }
+
+
+#ifdef TT_CONFIG_OPTION_EMBEDDED_BITMAPS
+
+ FT_LOCAL_DEF( FT_Error )
+ tt_face_load_bitmap_header( TT_Face face,
+ FT_Stream stream )
+ {
+ return tt_face_load_generic_header( face, stream, TTAG_bhed );
+ }
+
+#endif /* TT_CONFIG_OPTION_EMBEDDED_BITMAPS */
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* tt_face_load_max_profile */
+ /* */
+ /* <Description> */
+ /* Loads the maximum profile into a face object. */
+ /* */
+ /* <Input> */
+ /* face :: A handle to the target face object. */
+ /* */
+ /* stream :: The input stream. */
+ /* */
+ /* <Return> */
+ /* FreeType error code. 0 means success. */
+ /* */
+ FT_LOCAL_DEF( FT_Error )
+ tt_face_load_max_profile( TT_Face face,
+ FT_Stream stream )
+ {
+ FT_Error error;
+ TT_MaxProfile* maxProfile = &face->max_profile;
+
+ const FT_Frame_Field maxp_fields[] =
+ {
+#undef FT_STRUCTURE
+#define FT_STRUCTURE TT_MaxProfile
+
+ FT_FRAME_START( 6 ),
+ FT_FRAME_LONG ( version ),
+ FT_FRAME_USHORT( numGlyphs ),
+ FT_FRAME_END
+ };
+
+ const FT_Frame_Field maxp_fields_extra[] =
+ {
+ FT_FRAME_START( 26 ),
+ FT_FRAME_USHORT( maxPoints ),
+ FT_FRAME_USHORT( maxContours ),
+ FT_FRAME_USHORT( maxCompositePoints ),
+ FT_FRAME_USHORT( maxCompositeContours ),
+ FT_FRAME_USHORT( maxZones ),
+ FT_FRAME_USHORT( maxTwilightPoints ),
+ FT_FRAME_USHORT( maxStorage ),
+ FT_FRAME_USHORT( maxFunctionDefs ),
+ FT_FRAME_USHORT( maxInstructionDefs ),
+ FT_FRAME_USHORT( maxStackElements ),
+ FT_FRAME_USHORT( maxSizeOfInstructions ),
+ FT_FRAME_USHORT( maxComponentElements ),
+ FT_FRAME_USHORT( maxComponentDepth ),
+ FT_FRAME_END
+ };
+
+
+ FT_TRACE2(( "Load_TT_MaxProfile: %08p\n", face ));
+
+ error = face->goto_table( face, TTAG_maxp, stream, 0 );
+ if ( error )
+ goto Exit;
+
+ if ( FT_STREAM_READ_FIELDS( maxp_fields, maxProfile ) )
+ goto Exit;
+
+ maxProfile->maxPoints = 0;
+ maxProfile->maxContours = 0;
+ maxProfile->maxCompositePoints = 0;
+ maxProfile->maxCompositeContours = 0;
+ maxProfile->maxZones = 0;
+ maxProfile->maxTwilightPoints = 0;
+ maxProfile->maxStorage = 0;
+ maxProfile->maxFunctionDefs = 0;
+ maxProfile->maxInstructionDefs = 0;
+ maxProfile->maxStackElements = 0;
+ maxProfile->maxSizeOfInstructions = 0;
+ maxProfile->maxComponentElements = 0;
+ maxProfile->maxComponentDepth = 0;
+
+ if ( maxProfile->version >= 0x10000L )
+ {
+ if ( FT_STREAM_READ_FIELDS( maxp_fields_extra, maxProfile ) )
+ goto Exit;
+
+ /* XXX: an adjustment that is necessary to load certain */
+ /* broken fonts like `Keystrokes MT' :-( */
+ /* */
+ /* We allocate 64 function entries by default when */
+ /* the maxFunctionDefs field is null. */
+
+ if ( maxProfile->maxFunctionDefs == 0 )
+ maxProfile->maxFunctionDefs = 64;
+
+ face->root.num_glyphs = maxProfile->numGlyphs;
+
+ face->root.internal->max_points =
+ (FT_UShort)MAX( maxProfile->maxCompositePoints,
+ maxProfile->maxPoints );
+
+ face->root.internal->max_contours =
+ (FT_Short)MAX( maxProfile->maxCompositeContours,
+ maxProfile->maxContours );
+
+ face->max_components = (FT_ULong)maxProfile->maxComponentElements +
+ maxProfile->maxComponentDepth;
+
+ /* XXX: some fonts have maxComponents set to 0; we will */
+ /* then use 16 of them by default. */
+ if ( face->max_components == 0 )
+ face->max_components = 16;
+
+ /* We also increase maxPoints and maxContours in order to support */
+ /* some broken fonts. */
+ face->root.internal->max_points += (FT_UShort)8;
+ face->root.internal->max_contours += (FT_Short) 4;
+ }
+
+ FT_TRACE2(( "MAXP loaded.\n" ));
+
+ Exit:
+ return error;
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* tt_face_load_metrics */
+ /* */
+ /* <Description> */
+ /* Loads the horizontal or vertical metrics table into a face object. */
+ /* */
+ /* <Input> */
+ /* face :: A handle to the target face object. */
+ /* */
+ /* stream :: The input stream. */
+ /* */
+ /* vertical :: A boolean flag. If set, load vertical metrics. */
+ /* */
+ /* <Return> */
+ /* FreeType error code. 0 means success. */
+ /* */
+ static FT_Error
+ tt_face_load_metrics( TT_Face face,
+ FT_Stream stream,
+ FT_Bool vertical )
+ {
+ FT_Error error;
+ FT_Memory memory = stream->memory;
+
+ FT_ULong table_len;
+ FT_Long num_shorts, num_longs, num_shorts_checked;
+
+ TT_LongMetrics * longs;
+ TT_ShortMetrics** shorts;
+
+
+ FT_TRACE2(( "TT_Load_%s_Metrics: %08p\n", vertical ? "Vertical"
+ : "Horizontal",
+ face ));
+
+ if ( vertical )
+ {
+ /* The table is optional, quit silently if it wasn't found */
+ /* */
+ /* XXX: Some fonts have a valid vertical header with a non-null */
+ /* `number_of_VMetrics' fields, but no corresponding `vmtx' */
+ /* table to get the metrics from (e.g. mingliu). */
+ /* */
+ /* For safety, we set the field to 0! */
+ /* */
+ error = face->goto_table( face, TTAG_vmtx, stream, &table_len );
+ if ( error )
+ {
+ /* Set number_Of_VMetrics to 0! */
+ FT_TRACE2(( " no vertical header in file.\n" ));
+ face->vertical.number_Of_VMetrics = 0;
+ error = SFNT_Err_Ok;
+ goto Exit;
+ }
+
+ num_longs = face->vertical.number_Of_VMetrics;
+ longs = (TT_LongMetrics *)&face->vertical.long_metrics;
+ shorts = (TT_ShortMetrics**)&face->vertical.short_metrics;
+ }
+ else
+ {
+ error = face->goto_table( face, TTAG_hmtx, stream, &table_len );
+ if ( error )
+ {
+ FT_ERROR(( " no horizontal metrics in file!\n" ));
+ error = SFNT_Err_Hmtx_Table_Missing;
+ goto Exit;
+ }
+
+ num_longs = face->horizontal.number_Of_HMetrics;
+ longs = (TT_LongMetrics *)&face->horizontal.long_metrics;
+ shorts = (TT_ShortMetrics**)&face->horizontal.short_metrics;
+ }
+
+ /* never trust derived values */
+
+ num_shorts = face->max_profile.numGlyphs - num_longs;
+ num_shorts_checked = ( table_len - num_longs * 4L ) / 2;
+
+ if ( num_shorts < 0 )
+ {
+ FT_ERROR(( "TT_Load_%s_Metrics: more metrics than glyphs!\n",
+ vertical ? "Vertical"
+ : "Horizontal" ));
+
+ error = vertical ? SFNT_Err_Invalid_Vert_Metrics
+ : SFNT_Err_Invalid_Horiz_Metrics;
+ goto Exit;
+ }
+
+ if ( FT_NEW_ARRAY( *longs, num_longs ) ||
+ FT_NEW_ARRAY( *shorts, num_shorts ) )
+ goto Exit;
+
+ if ( FT_FRAME_ENTER( table_len ) )
+ goto Exit;
+
+ {
+ TT_LongMetrics cur = *longs;
+ TT_LongMetrics limit = cur + num_longs;
+
+
+ for ( ; cur < limit; cur++ )
+ {
+ cur->advance = FT_GET_USHORT();
+ cur->bearing = FT_GET_SHORT();
+ }
+ }
+
+ /* do we have an inconsistent number of metric values? */
+ {
+ TT_ShortMetrics* cur = *shorts;
+ TT_ShortMetrics* limit = cur + MIN( num_shorts, num_shorts_checked );
+
+
+ for ( ; cur < limit; cur++ )
+ *cur = FT_GET_SHORT();
+
+ /* we fill up the missing left side bearings with the */
+ /* last valid value. Since this will occur for buggy CJK */
+ /* fonts usually only, nothing serious will happen */
+ if ( num_shorts > num_shorts_checked && num_shorts_checked > 0 )
+ {
+ FT_Short val = (*shorts)[num_shorts_checked - 1];
+
+
+ limit = *shorts + num_shorts;
+ for ( ; cur < limit; cur++ )
+ *cur = val;
+ }
+ }
+
+ FT_FRAME_EXIT();
+
+ FT_TRACE2(( "loaded\n" ));
+
+ Exit:
+ return error;
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* tt_face_load_metrics_header */
+ /* */
+ /* <Description> */
+ /* Loads the horizontal or vertical header in a face object. */
+ /* */
+ /* <Input> */
+ /* face :: A handle to the target face object. */
+ /* */
+ /* stream :: The input stream. */
+ /* */
+ /* vertical :: A boolean flag. If set, load vertical metrics. */
+ /* */
+ /* <Return> */
+ /* FreeType error code. 0 means success. */
+ /* */
+ FT_LOCAL_DEF( FT_Error )
+ tt_face_load_metrics_header( TT_Face face,
+ FT_Stream stream,
+ FT_Bool vertical )
+ {
+ FT_Error error;
+ TT_HoriHeader* header;
+
+ const FT_Frame_Field metrics_header_fields[] =
+ {
+#undef FT_STRUCTURE
+#define FT_STRUCTURE TT_HoriHeader
+
+ FT_FRAME_START( 36 ),
+ FT_FRAME_ULONG ( Version ),
+ FT_FRAME_SHORT ( Ascender ),
+ FT_FRAME_SHORT ( Descender ),
+ FT_FRAME_SHORT ( Line_Gap ),
+ FT_FRAME_USHORT( advance_Width_Max ),
+ FT_FRAME_SHORT ( min_Left_Side_Bearing ),
+ FT_FRAME_SHORT ( min_Right_Side_Bearing ),
+ FT_FRAME_SHORT ( xMax_Extent ),
+ FT_FRAME_SHORT ( caret_Slope_Rise ),
+ FT_FRAME_SHORT ( caret_Slope_Run ),
+ FT_FRAME_SHORT ( caret_Offset ),
+ FT_FRAME_SHORT ( Reserved[0] ),
+ FT_FRAME_SHORT ( Reserved[1] ),
+ FT_FRAME_SHORT ( Reserved[2] ),
+ FT_FRAME_SHORT ( Reserved[3] ),
+ FT_FRAME_SHORT ( metric_Data_Format ),
+ FT_FRAME_USHORT( number_Of_HMetrics ),
+ FT_FRAME_END
+ };
+
+
+ FT_TRACE2(( vertical ? "Vertical header " : "Horizontal header " ));
+
+ if ( vertical )
+ {
+ face->vertical_info = 0;
+
+ /* The vertical header table is optional, so return quietly if */
+ /* we don't find it. */
+ error = face->goto_table( face, TTAG_vhea, stream, 0 );
+ if ( error )
+ {
+ error = SFNT_Err_Ok;
+ goto Exit;
+ }
+
+ face->vertical_info = 1;
+ header = (TT_HoriHeader*)&face->vertical;
+ }
+ else
+ {
+ /* The horizontal header is mandatory; return an error if we */
+ /* don't find it. */
+ error = face->goto_table( face, TTAG_hhea, stream, 0 );
+ if ( error )
+ {
+ error = SFNT_Err_Horiz_Header_Missing;
+ goto Exit;
+ }
+
+ header = &face->horizontal;
+ }
+
+ if ( FT_STREAM_READ_FIELDS( metrics_header_fields, header ) )
+ goto Exit;
+
+ header->long_metrics = NULL;
+ header->short_metrics = NULL;
+
+ FT_TRACE2(( "loaded\n" ));
+
+ /* Now try to load the corresponding metrics */
+
+ error = tt_face_load_metrics( face, stream, vertical );
+
+ Exit:
+ return error;
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* tt_face_load_names */
+ /* */
+ /* <Description> */
+ /* Loads the name records. */
+ /* */
+ /* <Input> */
+ /* face :: A handle to the target face object. */
+ /* */
+ /* stream :: The input stream. */
+ /* */
+ /* <Return> */
+ /* FreeType error code. 0 means success. */
+ /* */
+ FT_LOCAL_DEF( FT_Error )
+ tt_face_load_names( TT_Face face,
+ FT_Stream stream )
+ {
+ FT_Error error;
+ FT_Memory memory = stream->memory;
+ FT_ULong table_pos, table_len;
+ FT_ULong storage_start, storage_limit;
+ FT_UInt count;
+ TT_NameTable table;
+
+ static const FT_Frame_Field name_table_fields[] =
+ {
+#undef FT_STRUCTURE
+#define FT_STRUCTURE TT_NameTableRec
+
+ FT_FRAME_START( 6 ),
+ FT_FRAME_USHORT( format ),
+ FT_FRAME_USHORT( numNameRecords ),
+ FT_FRAME_USHORT( storageOffset ),
+ FT_FRAME_END
+ };
+
+ static const FT_Frame_Field name_record_fields[] =
+ {
+#undef FT_STRUCTURE
+#define FT_STRUCTURE TT_NameEntryRec
+
+ /* no FT_FRAME_START */
+ FT_FRAME_USHORT( platformID ),
+ FT_FRAME_USHORT( encodingID ),
+ FT_FRAME_USHORT( languageID ),
+ FT_FRAME_USHORT( nameID ),
+ FT_FRAME_USHORT( stringLength ),
+ FT_FRAME_USHORT( stringOffset ),
+ FT_FRAME_END
+ };
+
+
+ table = &face->name_table;
+ table->stream = stream;
+
+ FT_TRACE2(( "Names " ));
+
+ error = face->goto_table( face, TTAG_name, stream, &table_len );
+ if ( error )
+ {
+ /* The name table is required so indicate failure. */
+ FT_TRACE2(( "is missing!\n" ));
+ error = SFNT_Err_Name_Table_Missing;
+ goto Exit;
+ }
+
+ table_pos = FT_STREAM_POS();
+
+
+ if ( FT_STREAM_READ_FIELDS( name_table_fields, table ) )
+ goto Exit;
+
+ /* Some popular asian fonts have an invalid `storageOffset' value */
+ /* (it should be at least "6 + 12*num_names"). However, the string */
+ /* offsets, computed as "storageOffset + entry->stringOffset", are */
+ /* valid pointers within the name table... */
+ /* */
+ /* We thus can't check `storageOffset' right now. */
+ /* */
+ storage_start = table_pos + 6 + 12*table->numNameRecords;
+ storage_limit = table_pos + table_len;
+
+ if ( storage_start > storage_limit )
+ {
+ FT_ERROR(( "tt_face_load_names: invalid `name' table\n" ));
+ error = SFNT_Err_Name_Table_Missing;
+ goto Exit;
+ }
+
+ /* Allocate the array of name records. */
+ count = table->numNameRecords;
+ table->numNameRecords = 0;
+
+ if ( FT_NEW_ARRAY( table->names, count ) ||
+ FT_FRAME_ENTER( count * 12 ) )
+ goto Exit;
+
+ /* Load the name records and determine how much storage is needed */
+ /* to hold the strings themselves. */
+ {
+ TT_NameEntryRec* entry = table->names;
+
+
+ for ( ; count > 0; count-- )
+ {
+ if ( FT_STREAM_READ_FIELDS( name_record_fields, entry ) )
+ continue;
+
+ /* check that the name is not empty */
+ if ( entry->stringLength == 0 )
+ continue;
+
+ /* check that the name string is within the table */
+ entry->stringOffset += table_pos + table->storageOffset;
+ if ( entry->stringOffset < storage_start ||
+ entry->stringOffset + entry->stringLength > storage_limit )
+ {
+ /* invalid entry - ignore it */
+ entry->stringOffset = 0;
+ entry->stringLength = 0;
+ continue;
+ }
+
+ entry++;
+ }
+
+ table->numNameRecords = (FT_UInt)( entry - table->names );
+ }
+
+ FT_FRAME_EXIT();
+
+ FT_TRACE2(( "loaded\n" ));
+
+ /* everything went well, update face->num_names */
+ face->num_names = (FT_UShort) table->numNameRecords;
+
+ Exit:
+ return error;
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* tt_face_free_names */
+ /* */
+ /* <Description> */
+ /* Frees the name records. */
+ /* */
+ /* <Input> */
+ /* face :: A handle to the target face object. */
+ /* */
+ FT_LOCAL_DEF( void )
+ tt_face_free_names( TT_Face face )
+ {
+ FT_Memory memory = face->root.driver->root.memory;
+ TT_NameTable table = &face->name_table;
+ TT_NameEntry entry = table->names;
+ FT_UInt count = table->numNameRecords;
+
+
+ for ( ; count > 0; count--, entry++ )
+ {
+ FT_FREE( entry->string );
+ entry->stringLength = 0;
+ }
+
+ /* free strings table */
+ FT_FREE( table->names );
+
+ table->numNameRecords = 0;
+ table->format = 0;
+ table->storageOffset = 0;
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* tt_face_load_cmap */
+ /* */
+ /* <Description> */
+ /* Loads the cmap directory in a face object. The cmaps itselves are */
+ /* loaded on demand in the `ttcmap.c' module. */
+ /* */
+ /* <Input> */
+ /* face :: A handle to the target face object. */
+ /* */
+ /* stream :: A handle to the input stream. */
+ /* */
+ /* <Return> */
+ /* FreeType error code. 0 means success. */
+ /* */
+
+ FT_LOCAL_DEF( FT_Error )
+ tt_face_load_cmap( TT_Face face,
+ FT_Stream stream )
+ {
+ FT_Error error;
+
+
+ error = face->goto_table( face, TTAG_cmap, stream, &face->cmap_size );
+ if ( error )
+ {
+ FT_TRACE2(( "No `cmap' table in font !\n" ));
+ error = SFNT_Err_CMap_Table_Missing;
+ goto Exit;
+ }
+
+ if ( !FT_FRAME_EXTRACT( face->cmap_size, face->cmap_table ) )
+ FT_TRACE2(( "`cmap' table loaded\n" ));
+ else
+ {
+ FT_ERROR(( "`cmap' table is too short!\n" ));
+ face->cmap_size = 0;
+ }
+
+ Exit:
+ return error;
+ }
+
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* tt_face_load_os2 */
+ /* */
+ /* <Description> */
+ /* Loads the OS2 table. */
+ /* */
+ /* <Input> */
+ /* face :: A handle to the target face object. */
+ /* */
+ /* stream :: A handle to the input stream. */
+ /* */
+ /* <Return> */
+ /* FreeType error code. 0 means success. */
+ /* */
+ FT_LOCAL_DEF( FT_Error )
+ tt_face_load_os2( TT_Face face,
+ FT_Stream stream )
+ {
+ FT_Error error;
+ TT_OS2* os2;
+
+ const FT_Frame_Field os2_fields[] =
+ {
+#undef FT_STRUCTURE
+#define FT_STRUCTURE TT_OS2
+
+ FT_FRAME_START( 78 ),
+ FT_FRAME_USHORT( version ),
+ FT_FRAME_SHORT ( xAvgCharWidth ),
+ FT_FRAME_USHORT( usWeightClass ),
+ FT_FRAME_USHORT( usWidthClass ),
+ FT_FRAME_SHORT ( fsType ),
+ FT_FRAME_SHORT ( ySubscriptXSize ),
+ FT_FRAME_SHORT ( ySubscriptYSize ),
+ FT_FRAME_SHORT ( ySubscriptXOffset ),
+ FT_FRAME_SHORT ( ySubscriptYOffset ),
+ FT_FRAME_SHORT ( ySuperscriptXSize ),
+ FT_FRAME_SHORT ( ySuperscriptYSize ),
+ FT_FRAME_SHORT ( ySuperscriptXOffset ),
+ FT_FRAME_SHORT ( ySuperscriptYOffset ),
+ FT_FRAME_SHORT ( yStrikeoutSize ),
+ FT_FRAME_SHORT ( yStrikeoutPosition ),
+ FT_FRAME_SHORT ( sFamilyClass ),
+ FT_FRAME_BYTE ( panose[0] ),
+ FT_FRAME_BYTE ( panose[1] ),
+ FT_FRAME_BYTE ( panose[2] ),
+ FT_FRAME_BYTE ( panose[3] ),
+ FT_FRAME_BYTE ( panose[4] ),
+ FT_FRAME_BYTE ( panose[5] ),
+ FT_FRAME_BYTE ( panose[6] ),
+ FT_FRAME_BYTE ( panose[7] ),
+ FT_FRAME_BYTE ( panose[8] ),
+ FT_FRAME_BYTE ( panose[9] ),
+ FT_FRAME_ULONG ( ulUnicodeRange1 ),
+ FT_FRAME_ULONG ( ulUnicodeRange2 ),
+ FT_FRAME_ULONG ( ulUnicodeRange3 ),
+ FT_FRAME_ULONG ( ulUnicodeRange4 ),
+ FT_FRAME_BYTE ( achVendID[0] ),
+ FT_FRAME_BYTE ( achVendID[1] ),
+ FT_FRAME_BYTE ( achVendID[2] ),
+ FT_FRAME_BYTE ( achVendID[3] ),
+
+ FT_FRAME_USHORT( fsSelection ),
+ FT_FRAME_USHORT( usFirstCharIndex ),
+ FT_FRAME_USHORT( usLastCharIndex ),
+ FT_FRAME_SHORT ( sTypoAscender ),
+ FT_FRAME_SHORT ( sTypoDescender ),
+ FT_FRAME_SHORT ( sTypoLineGap ),
+ FT_FRAME_USHORT( usWinAscent ),
+ FT_FRAME_USHORT( usWinDescent ),
+ FT_FRAME_END
+ };
+
+ const FT_Frame_Field os2_fields_extra[] =
+ {
+ FT_FRAME_START( 8 ),
+ FT_FRAME_ULONG( ulCodePageRange1 ),
+ FT_FRAME_ULONG( ulCodePageRange2 ),
+ FT_FRAME_END
+ };
+
+ const FT_Frame_Field os2_fields_extra2[] =
+ {
+ FT_FRAME_START( 10 ),
+ FT_FRAME_SHORT ( sxHeight ),
+ FT_FRAME_SHORT ( sCapHeight ),
+ FT_FRAME_USHORT( usDefaultChar ),
+ FT_FRAME_USHORT( usBreakChar ),
+ FT_FRAME_USHORT( usMaxContext ),
+ FT_FRAME_END
+ };
+
+
+ FT_TRACE2(( "OS/2 Table " ));
+
+ /* We now support old Mac fonts where the OS/2 table doesn't */
+ /* exist. Simply put, we set the `version' field to 0xFFFF */
+ /* and test this value each time we need to access the table. */
+ error = face->goto_table( face, TTAG_OS2, stream, 0 );
+ if ( error )
+ {
+ FT_TRACE2(( "is missing!\n" ));
+ face->os2.version = 0xFFFFU;
+ error = SFNT_Err_Ok;
+ goto Exit;
+ }
+
+ os2 = &face->os2;
+
+ if ( FT_STREAM_READ_FIELDS( os2_fields, os2 ) )
+ goto Exit;
+
+ os2->ulCodePageRange1 = 0;
+ os2->ulCodePageRange2 = 0;
+ os2->sxHeight = 0;
+ os2->sCapHeight = 0;
+ os2->usDefaultChar = 0;
+ os2->usBreakChar = 0;
+ os2->usMaxContext = 0;
+
+ if ( os2->version >= 0x0001 )
+ {
+ /* only version 1 tables */
+ if ( FT_STREAM_READ_FIELDS( os2_fields_extra, os2 ) )
+ goto Exit;
+
+ if ( os2->version >= 0x0002 )
+ {
+ /* only version 2 tables */
+ if ( FT_STREAM_READ_FIELDS( os2_fields_extra2, os2 ) )
+ goto Exit;
+ }
+ }
+
+ FT_TRACE2(( "loaded\n" ));
+
+ Exit:
+ return error;
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* tt_face_load_postscript */
+ /* */
+ /* <Description> */
+ /* Loads the Postscript table. */
+ /* */
+ /* <Input> */
+ /* face :: A handle to the target face object. */
+ /* */
+ /* stream :: A handle to the input stream. */
+ /* */
+ /* <Return> */
+ /* FreeType error code. 0 means success. */
+ /* */
+ FT_LOCAL_DEF( FT_Error )
+ tt_face_load_postscript( TT_Face face,
+ FT_Stream stream )
+ {
+ FT_Error error;
+ TT_Postscript* post = &face->postscript;
+
+ static const FT_Frame_Field post_fields[] =
+ {
+#undef FT_STRUCTURE
+#define FT_STRUCTURE TT_Postscript
+
+ FT_FRAME_START( 32 ),
+ FT_FRAME_ULONG( FormatType ),
+ FT_FRAME_ULONG( italicAngle ),
+ FT_FRAME_SHORT( underlinePosition ),
+ FT_FRAME_SHORT( underlineThickness ),
+ FT_FRAME_ULONG( isFixedPitch ),
+ FT_FRAME_ULONG( minMemType42 ),
+ FT_FRAME_ULONG( maxMemType42 ),
+ FT_FRAME_ULONG( minMemType1 ),
+ FT_FRAME_ULONG( maxMemType1 ),
+ FT_FRAME_END
+ };
+
+
+ FT_TRACE2(( "PostScript " ));
+
+ error = face->goto_table( face, TTAG_post, stream, 0 );
+ if ( error )
+ return SFNT_Err_Post_Table_Missing;
+
+ if ( FT_STREAM_READ_FIELDS( post_fields, post ) )
+ return error;
+
+ /* we don't load the glyph names, we do that in another */
+ /* module (ttpost). */
+ FT_TRACE2(( "loaded\n" ));
+
+ return SFNT_Err_Ok;
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* tt_face_load_pclt */
+ /* */
+ /* <Description> */
+ /* Loads the PCL 5 Table. */
+ /* */
+ /* <Input> */
+ /* face :: A handle to the target face object. */
+ /* */
+ /* stream :: A handle to the input stream. */
+ /* */
+ /* <Return> */
+ /* FreeType error code. 0 means success. */
+ /* */
+ FT_LOCAL_DEF( FT_Error )
+ tt_face_load_pclt( TT_Face face,
+ FT_Stream stream )
+ {
+ static const FT_Frame_Field pclt_fields[] =
+ {
+#undef FT_STRUCTURE
+#define FT_STRUCTURE TT_PCLT
+
+ FT_FRAME_START( 54 ),
+ FT_FRAME_ULONG ( Version ),
+ FT_FRAME_ULONG ( FontNumber ),
+ FT_FRAME_USHORT( Pitch ),
+ FT_FRAME_USHORT( xHeight ),
+ FT_FRAME_USHORT( Style ),
+ FT_FRAME_USHORT( TypeFamily ),
+ FT_FRAME_USHORT( CapHeight ),
+ FT_FRAME_BYTES ( TypeFace, 16 ),
+ FT_FRAME_BYTES ( CharacterComplement, 8 ),
+ FT_FRAME_BYTES ( FileName, 6 ),
+ FT_FRAME_CHAR ( StrokeWeight ),
+ FT_FRAME_CHAR ( WidthType ),
+ FT_FRAME_BYTE ( SerifStyle ),
+ FT_FRAME_BYTE ( Reserved ),
+ FT_FRAME_END
+ };
+
+ FT_Error error;
+ TT_PCLT* pclt = &face->pclt;
+
+
+ FT_TRACE2(( "PCLT " ));
+
+ /* optional table */
+ error = face->goto_table( face, TTAG_PCLT, stream, 0 );
+ if ( error )
+ {
+ FT_TRACE2(( "missing (optional)\n" ));
+ pclt->Version = 0;
+ return SFNT_Err_Ok;
+ }
+
+ if ( FT_STREAM_READ_FIELDS( pclt_fields, pclt ) )
+ goto Exit;
+
+ FT_TRACE2(( "loaded\n" ));
+
+ Exit:
+ return error;
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* tt_face_load_gasp */
+ /* */
+ /* <Description> */
+ /* Loads the `gasp' table into a face object. */
+ /* */
+ /* <Input> */
+ /* face :: A handle to the target face object. */
+ /* */
+ /* stream :: The input stream. */
+ /* */
+ /* <Return> */
+ /* FreeType error code. 0 means success. */
+ /* */
+ FT_LOCAL_DEF( FT_Error )
+ tt_face_load_gasp( TT_Face face,
+ FT_Stream stream )
+ {
+ FT_Error error;
+ FT_Memory memory = stream->memory;
+
+ FT_UInt j,num_ranges;
+ TT_GaspRange gaspranges;
+
+
+ FT_TRACE2(( "tt_face_load_gasp: %08p\n", face ));
+
+ /* the gasp table is optional */
+ error = face->goto_table( face, TTAG_gasp, stream, 0 );
+ if ( error )
+ return SFNT_Err_Ok;
+
+ if ( FT_FRAME_ENTER( 4L ) )
+ goto Exit;
+
+ face->gasp.version = FT_GET_USHORT();
+ face->gasp.numRanges = FT_GET_USHORT();
+
+ FT_FRAME_EXIT();
+
+ num_ranges = face->gasp.numRanges;
+ FT_TRACE3(( "number of ranges = %d\n", num_ranges ));
+
+ if ( FT_NEW_ARRAY( gaspranges, num_ranges ) ||
+ FT_FRAME_ENTER( num_ranges * 4L ) )
+ goto Exit;
+
+ face->gasp.gaspRanges = gaspranges;
+
+ for ( j = 0; j < num_ranges; j++ )
+ {
+ gaspranges[j].maxPPEM = FT_GET_USHORT();
+ gaspranges[j].gaspFlag = FT_GET_USHORT();
+
+ FT_TRACE3(( " [max:%d flag:%d]",
+ gaspranges[j].maxPPEM,
+ gaspranges[j].gaspFlag ));
+ }
+ FT_TRACE3(( "\n" ));
+
+ FT_FRAME_EXIT();
+ FT_TRACE2(( "GASP loaded\n" ));
+
+ Exit:
+ return error;
+ }
+
+
+ FT_CALLBACK_DEF( int )
+ tt_kern_pair_compare( const void* a,
+ const void* b );
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* tt_face_load_kern */
+ /* */
+ /* <Description> */
+ /* Loads the first kerning table with format 0 in the font. Only */
+ /* accepts the first horizontal kerning table. Developers should use */
+ /* the `ftxkern' extension to access other kerning tables in the font */
+ /* file, if they really want to. */
+ /* */
+ /* <Input> */
+ /* face :: A handle to the target face object. */
+ /* */
+ /* stream :: The input stream. */
+ /* */
+ /* <Return> */
+ /* FreeType error code. 0 means success. */
+ /* */
+ FT_LOCAL_DEF( FT_Error )
+ tt_face_load_kern( TT_Face face,
+ FT_Stream stream )
+ {
+ FT_Error error;
+ FT_Memory memory = stream->memory;
+
+ FT_UInt n, num_tables;
+
+
+ /* the kern table is optional; exit silently if it is missing */
+ error = face->goto_table( face, TTAG_kern, stream, 0 );
+ if ( error )
+ return SFNT_Err_Ok;
+
+ if ( FT_FRAME_ENTER( 4L ) )
+ goto Exit;
+
+ (void)FT_GET_USHORT(); /* version */
+ num_tables = FT_GET_USHORT();
+
+ FT_FRAME_EXIT();
+
+ for ( n = 0; n < num_tables; n++ )
+ {
+ FT_UInt coverage;
+ FT_UInt length;
+
+
+ if ( FT_FRAME_ENTER( 6L ) )
+ goto Exit;
+
+ (void)FT_GET_USHORT(); /* version */
+ length = FT_GET_USHORT() - 6; /* substract header length */
+ coverage = FT_GET_USHORT();
+
+ FT_FRAME_EXIT();
+
+ if ( coverage == 0x0001 )
+ {
+ FT_UInt num_pairs;
+ TT_Kern0_Pair pair;
+ TT_Kern0_Pair limit;
+
+
+ /* found a horizontal format 0 kerning table! */
+ if ( FT_FRAME_ENTER( 8L ) )
+ goto Exit;
+
+ num_pairs = FT_GET_USHORT();
+
+ /* skip the rest */
+
+ FT_FRAME_EXIT();
+
+ /* allocate array of kerning pairs */
+ if ( FT_NEW_ARRAY( face->kern_pairs, num_pairs ) ||
+ FT_FRAME_ENTER( 6L * num_pairs ) )
+ goto Exit;
+
+ pair = face->kern_pairs;
+ limit = pair + num_pairs;
+ for ( ; pair < limit; pair++ )
+ {
+ pair->left = FT_GET_USHORT();
+ pair->right = FT_GET_USHORT();
+ pair->value = FT_GET_USHORT();
+ }
+
+ FT_FRAME_EXIT();
+
+ face->num_kern_pairs = num_pairs;
+ face->kern_table_index = n;
+
+ /* ensure that the kerning pair table is sorted (yes, some */
+ /* fonts have unsorted tables!) */
+ {
+ FT_UInt i;
+ TT_Kern0_Pair pair0;
+
+
+ pair0 = face->kern_pairs;
+
+ for ( i = 1; i < num_pairs; i++, pair0++ )
+ {
+ if ( tt_kern_pair_compare( pair0, pair0 + 1 ) != -1 )
+ {
+ ft_qsort( (void*)face->kern_pairs, (int)num_pairs,
+ sizeof ( TT_Kern0_PairRec ), tt_kern_pair_compare );
+ break;
+ }
+ }
+ }
+
+ goto Exit;
+ }
+
+ if ( FT_STREAM_SKIP( length ) )
+ goto Exit;
+ }
+
+ /* no kern table found -- doesn't matter */
+ face->kern_table_index = -1;
+ face->num_kern_pairs = 0;
+ face->kern_pairs = NULL;
+
+ Exit:
+ return error;
+ }
+
+
+#undef TT_KERN_INDEX
+#define TT_KERN_INDEX( g1, g2 ) ( ( (FT_ULong)g1 << 16 ) | g2 )
+
+
+ FT_CALLBACK_DEF( int )
+ tt_kern_pair_compare( const void* a,
+ const void* b )
+ {
+ TT_Kern0_Pair pair1 = (TT_Kern0_Pair)a;
+ TT_Kern0_Pair pair2 = (TT_Kern0_Pair)b;
+
+ FT_ULong index1 = TT_KERN_INDEX( pair1->left, pair1->right );
+ FT_ULong index2 = TT_KERN_INDEX( pair2->left, pair2->right );
+
+
+ return ( index1 < index2 ? -1 :
+ ( index1 > index2 ? 1 : 0 ));
+ }
+
+
+#undef TT_KERN_INDEX
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* tt_face_load_hdmx */
+ /* */
+ /* <Description> */
+ /* Loads the horizontal device metrics table. */
+ /* */
+ /* <Input> */
+ /* face :: A handle to the target face object. */
+ /* */
+ /* stream :: A handle to the input stream. */
+ /* */
+ /* <Return> */
+ /* FreeType error code. 0 means success. */
+ /* */
+ FT_LOCAL_DEF( FT_Error )
+ tt_face_load_hdmx( TT_Face face,
+ FT_Stream stream )
+ {
+ FT_Error error;
+ FT_Memory memory = stream->memory;
+
+ TT_Hdmx hdmx = &face->hdmx;
+ FT_Long num_glyphs;
+ FT_Long record_size;
+
+
+ hdmx->version = 0;
+ hdmx->num_records = 0;
+ hdmx->records = 0;
+
+ /* this table is optional */
+ error = face->goto_table( face, TTAG_hdmx, stream, 0 );
+ if ( error )
+ return SFNT_Err_Ok;
+
+ if ( FT_FRAME_ENTER( 8L ) )
+ goto Exit;
+
+ hdmx->version = FT_GET_USHORT();
+ hdmx->num_records = FT_GET_SHORT();
+ record_size = FT_GET_LONG();
+
+ FT_FRAME_EXIT();
+
+ /* Only recognize format 0 */
+ if ( hdmx->version != 0 )
+ goto Exit;
+
+ if ( FT_NEW_ARRAY( hdmx->records, hdmx->num_records ) )
+ goto Exit;
+
+ num_glyphs = face->root.num_glyphs;
+ record_size -= num_glyphs + 2;
+
+ {
+ TT_HdmxEntry cur = hdmx->records;
+ TT_HdmxEntry limit = cur + hdmx->num_records;
+
+
+ for ( ; cur < limit; cur++ )
+ {
+ /* read record */
+ if ( FT_READ_BYTE( cur->ppem ) ||
+ FT_READ_BYTE( cur->max_width ) )
+ goto Exit;
+
+ if ( FT_ALLOC( cur->widths, num_glyphs ) ||
+ FT_STREAM_READ( cur->widths, num_glyphs ) )
+ goto Exit;
+
+ /* skip padding bytes */
+ if ( record_size > 0 && FT_STREAM_SKIP( record_size ) )
+ goto Exit;
+ }
+ }
+
+ Exit:
+ return error;
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* tt_face_free_hdmx */
+ /* */
+ /* <Description> */
+ /* Frees the horizontal device metrics table. */
+ /* */
+ /* <Input> */
+ /* face :: A handle to the target face object. */
+ /* */
+ FT_LOCAL_DEF( void )
+ tt_face_free_hdmx( TT_Face face )
+ {
+ if ( face )
+ {
+ FT_Int n;
+ FT_Memory memory = face->root.driver->root.memory;
+
+
+ for ( n = 0; n < face->hdmx.num_records; n++ )
+ FT_FREE( face->hdmx.records[n].widths );
+
+ FT_FREE( face->hdmx.records );
+ face->hdmx.num_records = 0;
+ }
+ }
+
+
+/* END */
--- /dev/null
+++ b/libfreetype/ttload.h
@@ -1,0 +1,137 @@
+/***************************************************************************/
+/* */
+/* ttload.h */
+/* */
+/* Load the basic TrueType tables, i.e., tables that can be either in */
+/* TTF or OTF fonts (specification). */
+/* */
+/* Copyright 1996-2001, 2002 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+
+#ifndef __TTLOAD_H__
+#define __TTLOAD_H__
+
+
+#include <ft2build.h>
+#include FT_INTERNAL_STREAM_H
+#include FT_INTERNAL_TRUETYPE_TYPES_H
+
+
+FT_BEGIN_HEADER
+
+
+ FT_LOCAL( TT_Table )
+ tt_face_lookup_table( TT_Face face,
+ FT_ULong tag );
+
+ FT_LOCAL( FT_Error )
+ tt_face_goto_table( TT_Face face,
+ FT_ULong tag,
+ FT_Stream stream,
+ FT_ULong* length );
+
+
+ FT_LOCAL( FT_Error )
+ tt_face_load_sfnt_header( TT_Face face,
+ FT_Stream stream,
+ FT_Long face_index,
+ SFNT_Header sfnt );
+
+ FT_LOCAL( FT_Error )
+ tt_face_load_directory( TT_Face face,
+ FT_Stream stream,
+ SFNT_Header sfnt );
+
+ FT_LOCAL( FT_Error )
+ tt_face_load_any( TT_Face face,
+ FT_ULong tag,
+ FT_Long offset,
+ FT_Byte* buffer,
+ FT_ULong* length );
+
+
+ FT_LOCAL( FT_Error )
+ tt_face_load_header( TT_Face face,
+ FT_Stream stream );
+
+
+ FT_LOCAL( FT_Error )
+ tt_face_load_metrics_header( TT_Face face,
+ FT_Stream stream,
+ FT_Bool vertical );
+
+
+ FT_LOCAL( FT_Error )
+ tt_face_load_cmap( TT_Face face,
+ FT_Stream stream );
+
+
+ FT_LOCAL( FT_Error )
+ tt_face_load_max_profile( TT_Face face,
+ FT_Stream stream );
+
+
+ FT_LOCAL( FT_Error )
+ tt_face_load_names( TT_Face face,
+ FT_Stream stream );
+
+
+ FT_LOCAL( FT_Error )
+ tt_face_load_os2( TT_Face face,
+ FT_Stream stream );
+
+
+ FT_LOCAL( FT_Error )
+ tt_face_load_postscript( TT_Face face,
+ FT_Stream stream );
+
+
+ FT_LOCAL( FT_Error )
+ tt_face_load_hdmx( TT_Face face,
+ FT_Stream stream );
+
+ FT_LOCAL( FT_Error )
+ tt_face_load_pclt( TT_Face face,
+ FT_Stream stream );
+
+ FT_LOCAL( void )
+ tt_face_free_names( TT_Face face );
+
+
+ FT_LOCAL( void )
+ tt_face_free_hdmx ( TT_Face face );
+
+
+ FT_LOCAL( FT_Error )
+ tt_face_load_kern( TT_Face face,
+ FT_Stream stream );
+
+
+ FT_LOCAL( FT_Error )
+ tt_face_load_gasp( TT_Face face,
+ FT_Stream stream );
+
+#ifdef TT_CONFIG_OPTION_EMBEDDED_BITMAPS
+
+ FT_LOCAL( FT_Error )
+ tt_face_load_bitmap_header( TT_Face face,
+ FT_Stream stream );
+
+#endif /* TT_CONFIG_OPTION_EMBEDDED_BITMAPS */
+
+
+FT_END_HEADER
+
+#endif /* __TTLOAD_H__ */
+
+
+/* END */
--- /dev/null
+++ b/libfreetype/ttobjs.c
@@ -1,0 +1,861 @@
+/***************************************************************************/
+/* */
+/* ttobjs.c */
+/* */
+/* Objects manager (body). */
+/* */
+/* Copyright 1996-2001, 2002 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+
+#include <ft2build.h>
+#include FT_INTERNAL_DEBUG_H
+#include FT_INTERNAL_CALC_H
+#include FT_INTERNAL_STREAM_H
+#include FT_TRUETYPE_IDS_H
+#include FT_TRUETYPE_TAGS_H
+#include FT_INTERNAL_SFNT_H
+#include FT_INTERNAL_POSTSCRIPT_NAMES_H
+
+#include "ttgload.h"
+#include "ttpload.h"
+
+#include "tterrors.h"
+
+#ifdef TT_CONFIG_OPTION_BYTECODE_INTERPRETER
+#include "ttinterp.h"
+#endif
+
+
+ /*************************************************************************/
+ /* */
+ /* The macro FT_COMPONENT is used in trace mode. It is an implicit */
+ /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log */
+ /* messages during execution. */
+ /* */
+#undef FT_COMPONENT
+#define FT_COMPONENT trace_ttobjs
+
+
+#ifdef TT_CONFIG_OPTION_BYTECODE_INTERPRETER
+
+ /*************************************************************************/
+ /* */
+ /* GLYPH ZONE FUNCTIONS */
+ /* */
+ /*************************************************************************/
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* tt_glyphzone_done */
+ /* */
+ /* <Description> */
+ /* Deallocates a glyph zone. */
+ /* */
+ /* <Input> */
+ /* zone :: A pointer to the target glyph zone. */
+ /* */
+ FT_LOCAL_DEF( void )
+ tt_glyphzone_done( TT_GlyphZone zone )
+ {
+ FT_Memory memory = zone->memory;
+
+
+ FT_FREE( zone->contours );
+ FT_FREE( zone->tags );
+ FT_FREE( zone->cur );
+ FT_FREE( zone->org );
+
+ zone->max_points = zone->n_points = 0;
+ zone->max_contours = zone->n_contours = 0;
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* tt_glyphzone_new */
+ /* */
+ /* <Description> */
+ /* Allocates a new glyph zone. */
+ /* */
+ /* <Input> */
+ /* memory :: A handle to the current memory object. */
+ /* */
+ /* maxPoints :: The capacity of glyph zone in points. */
+ /* */
+ /* maxContours :: The capacity of glyph zone in contours. */
+ /* */
+ /* <Output> */
+ /* zone :: A pointer to the target glyph zone record. */
+ /* */
+ /* <Return> */
+ /* FreeType error code. 0 means success. */
+ /* */
+ FT_LOCAL_DEF( FT_Error )
+ tt_glyphzone_new( FT_Memory memory,
+ FT_UShort maxPoints,
+ FT_Short maxContours,
+ TT_GlyphZone zone )
+ {
+ FT_Error error;
+
+
+ if ( maxPoints > 0 )
+ maxPoints += 2;
+
+ FT_MEM_ZERO( zone, sizeof ( *zone ) );
+ zone->memory = memory;
+
+ if ( FT_NEW_ARRAY( zone->org, maxPoints * 2 ) ||
+ FT_NEW_ARRAY( zone->cur, maxPoints * 2 ) ||
+ FT_NEW_ARRAY( zone->tags, maxPoints ) ||
+ FT_NEW_ARRAY( zone->contours, maxContours ) )
+ {
+ tt_glyphzone_done( zone );
+ }
+
+ return error;
+ }
+#endif /* TT_CONFIG_OPTION_BYTECODE_INTERPRETER */
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* tt_face_init */
+ /* */
+ /* <Description> */
+ /* Initializes a given TrueType face object. */
+ /* */
+ /* <Input> */
+ /* stream :: The source font stream. */
+ /* */
+ /* face_index :: The index of the font face in the resource. */
+ /* */
+ /* num_params :: Number of additional generic parameters. Ignored. */
+ /* */
+ /* params :: Additional generic parameters. Ignored. */
+ /* */
+ /* <InOut> */
+ /* face :: The newly built face object. */
+ /* */
+ /* <Return> */
+ /* FreeType error code. 0 means success. */
+ /* */
+ FT_LOCAL_DEF( FT_Error )
+ tt_face_init( FT_Stream stream,
+ TT_Face face,
+ FT_Int face_index,
+ FT_Int num_params,
+ FT_Parameter* params )
+ {
+ FT_Error error;
+ FT_Library library;
+ SFNT_Service sfnt;
+
+
+ library = face->root.driver->root.library;
+ sfnt = (SFNT_Service)FT_Get_Module_Interface( library, "sfnt" );
+ if ( !sfnt )
+ goto Bad_Format;
+
+ /* create input stream from resource */
+ if ( FT_STREAM_SEEK( 0 ) )
+ goto Exit;
+
+ /* check that we have a valid TrueType file */
+ error = sfnt->init_face( stream, face, face_index, num_params, params );
+ if ( error )
+ goto Exit;
+
+ /* We must also be able to accept Mac/GX fonts, as well as OT ones */
+ if ( face->format_tag != 0x00010000L && /* MS fonts */
+ face->format_tag != TTAG_true ) /* Mac fonts */
+ {
+ FT_TRACE2(( "[not a valid TTF font]\n" ));
+ goto Bad_Format;
+ }
+
+ /* If we are performing a simple font format check, exit immediately */
+ if ( face_index < 0 )
+ return TT_Err_Ok;
+
+ /* Load font directory */
+ error = sfnt->load_face( stream, face, face_index, num_params, params );
+ if ( error )
+ goto Exit;
+
+ if ( face->root.face_flags & FT_FACE_FLAG_SCALABLE )
+ {
+
+#ifdef FT_CONFIG_OPTION_INCREMENTAL
+
+ if ( !face->root.internal->incremental_interface )
+ error = tt_face_load_loca( face, stream );
+ if ( !error )
+ error = tt_face_load_cvt ( face, stream ) ||
+ tt_face_load_fpgm ( face, stream );
+
+#else
+
+ if ( !error )
+ error = tt_face_load_loca( face, stream ) ||
+ tt_face_load_cvt ( face, stream ) ||
+ tt_face_load_fpgm ( face, stream );
+
+#endif
+
+ }
+
+ /* initialize standard glyph loading routines */
+ TT_Init_Glyph_Loading( face );
+
+ Exit:
+ return error;
+
+ Bad_Format:
+ error = TT_Err_Unknown_File_Format;
+ goto Exit;
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* tt_face_done */
+ /* */
+ /* <Description> */
+ /* Finalizes a given face object. */
+ /* */
+ /* <Input> */
+ /* face :: A pointer to the face object to destroy. */
+ /* */
+ FT_LOCAL_DEF( void )
+ tt_face_done( TT_Face face )
+ {
+ FT_Memory memory = face->root.memory;
+ FT_Stream stream = face->root.stream;
+
+ SFNT_Service sfnt = (SFNT_Service)face->sfnt;
+
+
+ /* for `extended TrueType formats' (i.e. compressed versions) */
+ if ( face->extra.finalizer )
+ face->extra.finalizer( face->extra.data );
+
+ if ( sfnt )
+ sfnt->done_face( face );
+
+ /* freeing the locations table */
+ FT_FREE( face->glyph_locations );
+ face->num_locations = 0;
+
+ /* freeing the CVT */
+ FT_FREE( face->cvt );
+ face->cvt_size = 0;
+
+ /* freeing the programs */
+ FT_FRAME_RELEASE( face->font_program );
+ FT_FRAME_RELEASE( face->cvt_program );
+ face->font_program_size = 0;
+ face->cvt_program_size = 0;
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* SIZE FUNCTIONS */
+ /* */
+ /*************************************************************************/
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* tt_size_init */
+ /* */
+ /* <Description> */
+ /* Initializes a new TrueType size object. */
+ /* */
+ /* <InOut> */
+ /* size :: A handle to the size object. */
+ /* */
+ /* <Return> */
+ /* FreeType error code. 0 means success. */
+ /* */
+ FT_LOCAL_DEF( FT_Error )
+ tt_size_init( TT_Size size )
+ {
+ FT_Error error = TT_Err_Ok;
+
+
+#ifdef TT_CONFIG_OPTION_BYTECODE_INTERPRETER
+
+ TT_Face face = (TT_Face)size->root.face;
+ FT_Memory memory = face->root.memory;
+ FT_Int i;
+
+ TT_ExecContext exec;
+ FT_UShort n_twilight;
+ TT_MaxProfile* maxp = &face->max_profile;
+
+
+ size->ttmetrics.valid = FALSE;
+
+ size->max_function_defs = maxp->maxFunctionDefs;
+ size->max_instruction_defs = maxp->maxInstructionDefs;
+
+ size->num_function_defs = 0;
+ size->num_instruction_defs = 0;
+
+ size->max_func = 0;
+ size->max_ins = 0;
+
+ size->cvt_size = face->cvt_size;
+ size->storage_size = maxp->maxStorage;
+
+ /* Set default metrics */
+ {
+ FT_Size_Metrics* metrics = &size->root.metrics;
+ TT_Size_Metrics* metrics2 = &size->ttmetrics;
+
+
+ metrics->x_ppem = 0;
+ metrics->y_ppem = 0;
+
+ metrics2->rotated = FALSE;
+ metrics2->stretched = FALSE;
+
+ /* set default compensation (all 0) */
+ for ( i = 0; i < 4; i++ )
+ metrics2->compensations[i] = 0;
+ }
+
+ /* allocate function defs, instruction defs, cvt, and storage area */
+ if ( FT_NEW_ARRAY( size->function_defs, size->max_function_defs ) ||
+ FT_NEW_ARRAY( size->instruction_defs, size->max_instruction_defs ) ||
+ FT_NEW_ARRAY( size->cvt, size->cvt_size ) ||
+ FT_NEW_ARRAY( size->storage, size->storage_size ) )
+
+ goto Fail_Memory;
+
+ /* reserve twilight zone */
+ n_twilight = maxp->maxTwilightPoints;
+ error = tt_glyphzone_new( memory, n_twilight, 0, &size->twilight );
+ if ( error )
+ goto Fail_Memory;
+
+ size->twilight.n_points = n_twilight;
+
+ /* set `face->interpreter' according to the debug hook present */
+ {
+ FT_Library library = face->root.driver->root.library;
+
+
+ face->interpreter = (TT_Interpreter)
+ library->debug_hooks[FT_DEBUG_HOOK_TRUETYPE];
+ if ( !face->interpreter )
+ face->interpreter = (TT_Interpreter)TT_RunIns;
+ }
+
+ /* Fine, now execute the font program! */
+ exec = size->context;
+ /* size objects used during debugging have their own context */
+ if ( !size->debug )
+ exec = TT_New_Context( face );
+
+ if ( !exec )
+ {
+ error = TT_Err_Could_Not_Find_Context;
+ goto Fail_Memory;
+ }
+
+ size->GS = tt_default_graphics_state;
+ TT_Load_Context( exec, face, size );
+
+ exec->callTop = 0;
+ exec->top = 0;
+
+ exec->period = 64;
+ exec->phase = 0;
+ exec->threshold = 0;
+
+ {
+ FT_Size_Metrics* metrics = &exec->metrics;
+ TT_Size_Metrics* tt_metrics = &exec->tt_metrics;
+
+
+ metrics->x_ppem = 0;
+ metrics->y_ppem = 0;
+ metrics->x_scale = 0;
+ metrics->y_scale = 0;
+
+ tt_metrics->ppem = 0;
+ tt_metrics->scale = 0;
+ tt_metrics->ratio = 0x10000L;
+ }
+
+ exec->instruction_trap = FALSE;
+
+ exec->cvtSize = size->cvt_size;
+ exec->cvt = size->cvt;
+
+ exec->F_dot_P = 0x10000L;
+
+ /* allow font program execution */
+ TT_Set_CodeRange( exec,
+ tt_coderange_font,
+ face->font_program,
+ face->font_program_size );
+
+ /* disable CVT and glyph programs coderange */
+ TT_Clear_CodeRange( exec, tt_coderange_cvt );
+ TT_Clear_CodeRange( exec, tt_coderange_glyph );
+
+ if ( face->font_program_size > 0 )
+ {
+ error = TT_Goto_CodeRange( exec, tt_coderange_font, 0 );
+ if ( !error )
+ error = face->interpreter( exec );
+
+ if ( error )
+ goto Fail_Exec;
+ }
+ else
+ error = TT_Err_Ok;
+
+ TT_Save_Context( exec, size );
+
+ if ( !size->debug )
+ TT_Done_Context( exec );
+
+#endif /* TT_CONFIG_OPTION_BYTECODE_INTERPRETER */
+
+ size->ttmetrics.valid = FALSE;
+ return error;
+
+#ifdef TT_CONFIG_OPTION_BYTECODE_INTERPRETER
+
+ Fail_Exec:
+ if ( !size->debug )
+ TT_Done_Context( exec );
+
+ Fail_Memory:
+
+ tt_size_done( size );
+ return error;
+
+#endif /* TT_CONFIG_OPTION_BYTECODE_INTERPRETER */
+
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* tt_size_done */
+ /* */
+ /* <Description> */
+ /* The TrueType size object finalizer. */
+ /* */
+ /* <Input> */
+ /* size :: A handle to the target size object. */
+ /* */
+ FT_LOCAL_DEF( void )
+ tt_size_done( TT_Size size )
+ {
+
+#ifdef TT_CONFIG_OPTION_BYTECODE_INTERPRETER
+
+ FT_Memory memory = size->root.face->memory;
+
+
+ if ( size->debug )
+ {
+ /* the debug context must be deleted by the debugger itself */
+ size->context = NULL;
+ size->debug = FALSE;
+ }
+
+ FT_FREE( size->cvt );
+ size->cvt_size = 0;
+
+ /* free storage area */
+ FT_FREE( size->storage );
+ size->storage_size = 0;
+
+ /* twilight zone */
+ tt_glyphzone_done( &size->twilight );
+
+ FT_FREE( size->function_defs );
+ FT_FREE( size->instruction_defs );
+
+ size->num_function_defs = 0;
+ size->max_function_defs = 0;
+ size->num_instruction_defs = 0;
+ size->max_instruction_defs = 0;
+
+ size->max_func = 0;
+ size->max_ins = 0;
+
+#endif
+
+ size->ttmetrics.valid = FALSE;
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* Reset_Outline_Size */
+ /* */
+ /* <Description> */
+ /* Resets a TrueType outline size when resolutions and character */
+ /* dimensions have been changed. */
+ /* */
+ /* <Input> */
+ /* size :: A handle to the target size object. */
+ /* */
+ static FT_Error
+ Reset_Outline_Size( TT_Size size )
+ {
+ TT_Face face;
+ FT_Error error = TT_Err_Ok;
+
+ FT_Size_Metrics* metrics;
+
+
+ if ( size->ttmetrics.valid )
+ return TT_Err_Ok;
+
+ face = (TT_Face)size->root.face;
+
+ metrics = &size->root.metrics;
+
+ if ( metrics->x_ppem < 1 || metrics->y_ppem < 1 )
+ return TT_Err_Invalid_PPem;
+
+ /* compute new transformation */
+ if ( metrics->x_ppem >= metrics->y_ppem )
+ {
+ size->ttmetrics.scale = metrics->x_scale;
+ size->ttmetrics.ppem = metrics->x_ppem;
+ size->ttmetrics.x_ratio = 0x10000L;
+ size->ttmetrics.y_ratio = FT_MulDiv( metrics->y_ppem,
+ 0x10000L,
+ metrics->x_ppem );
+ }
+ else
+ {
+ size->ttmetrics.scale = metrics->y_scale;
+ size->ttmetrics.ppem = metrics->y_ppem;
+ size->ttmetrics.x_ratio = FT_MulDiv( metrics->x_ppem,
+ 0x10000L,
+ metrics->y_ppem );
+ size->ttmetrics.y_ratio = 0x10000L;
+ }
+
+ /* Compute root ascender, descender, test height, and max_advance */
+ metrics->ascender = ( FT_MulFix( face->root.ascender,
+ metrics->y_scale ) + 32 ) & -64;
+ metrics->descender = ( FT_MulFix( face->root.descender,
+ metrics->y_scale ) + 32 ) & -64;
+ metrics->height = ( FT_MulFix( face->root.height,
+ metrics->y_scale ) + 32 ) & -64;
+ metrics->max_advance = ( FT_MulFix( face->root.max_advance_width,
+ metrics->x_scale ) + 32 ) & -64;
+
+#ifdef TT_CONFIG_OPTION_EMBEDDED_BITMAPS
+ /* set to `invalid' by default */
+ size->strike_index = 0xFFFFU;
+#endif
+
+#ifdef TT_CONFIG_OPTION_BYTECODE_INTERPRETER
+
+ {
+ TT_ExecContext exec;
+ FT_UInt i, j;
+
+
+ /* Scale the cvt values to the new ppem. */
+ /* We use by default the y ppem to scale the CVT. */
+ for ( i = 0; i < size->cvt_size; i++ )
+ size->cvt[i] = FT_MulFix( face->cvt[i], size->ttmetrics.scale );
+
+ /* All twilight points are originally zero */
+ for ( j = 0; j < (FT_UInt)size->twilight.n_points; j++ )
+ {
+ size->twilight.org[j].x = 0;
+ size->twilight.org[j].y = 0;
+ size->twilight.cur[j].x = 0;
+ size->twilight.cur[j].y = 0;
+ }
+
+ /* clear storage area */
+ for ( i = 0; i < (FT_UInt)size->storage_size; i++ )
+ size->storage[i] = 0;
+
+ size->GS = tt_default_graphics_state;
+
+ /* get execution context and run prep program */
+ if ( size->debug )
+ exec = size->context;
+ else
+ exec = TT_New_Context( face );
+ /* debugging instances have their own context */
+
+ if ( !exec )
+ return TT_Err_Could_Not_Find_Context;
+
+ TT_Load_Context( exec, face, size );
+
+ TT_Set_CodeRange( exec,
+ tt_coderange_cvt,
+ face->cvt_program,
+ face->cvt_program_size );
+
+ TT_Clear_CodeRange( exec, tt_coderange_glyph );
+
+ exec->instruction_trap = FALSE;
+
+ exec->top = 0;
+ exec->callTop = 0;
+
+ if ( face->cvt_program_size > 0 )
+ {
+ error = TT_Goto_CodeRange( exec, tt_coderange_cvt, 0 );
+ if ( error )
+ goto End;
+
+ if ( !size->debug )
+ error = face->interpreter( exec );
+ }
+ else
+ error = TT_Err_Ok;
+
+ size->GS = exec->GS;
+ /* save default graphics state */
+
+ End:
+ TT_Save_Context( exec, size );
+
+ if ( !size->debug )
+ TT_Done_Context( exec );
+ /* debugging instances keep their context */
+ }
+
+#endif /* TT_CONFIG_OPTION_BYTECODE_INTERPRETER */
+
+ if ( !error )
+ size->ttmetrics.valid = TRUE;
+
+ return error;
+ }
+
+
+#ifdef TT_CONFIG_OPTION_EMBEDDED_BITMAPS
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* Reset_SBit_Size */
+ /* */
+ /* <Description> */
+ /* Resets a TrueType sbit size when resolutions and character */
+ /* dimensions have been changed. */
+ /* */
+ /* <Input> */
+ /* size :: A handle to the target size object. */
+ /* */
+ static FT_Error
+ Reset_SBit_Size( TT_Size size )
+ {
+ TT_Face face;
+ FT_Error error = TT_Err_Ok;
+
+ FT_ULong strike_index;
+ FT_Size_Metrics* metrics;
+ FT_Size_Metrics* sbit_metrics;
+ SFNT_Service sfnt;
+
+
+ metrics = &size->root.metrics;
+
+ if ( size->strike_index != 0xFFFFU )
+ return TT_Err_Ok;
+
+ face = (TT_Face)size->root.face;
+ sfnt = (SFNT_Service)face->sfnt;
+
+ sbit_metrics = &size->strike_metrics;
+
+ error = sfnt->set_sbit_strike(face,
+ metrics->x_ppem, metrics->y_ppem,
+ &strike_index);
+
+ if ( !error )
+ {
+ TT_SBit_Strike strike = face->sbit_strikes + strike_index;
+
+
+ sbit_metrics->x_ppem = metrics->x_ppem;
+ sbit_metrics->y_ppem = metrics->y_ppem;
+#if 0
+ /*
+ * sbit_metrics->?_scale
+ * are not used now.
+ */
+ sbit_metrics->x_scale = 1 << 16;
+ sbit_metrics->y_scale = 1 << 16;
+#endif
+
+ sbit_metrics->ascender = strike->hori.ascender << 6;
+ sbit_metrics->descender = strike->hori.descender << 6;
+
+ /* XXX: Is this correct? */
+ sbit_metrics->height = sbit_metrics->ascender -
+ sbit_metrics->descender;
+
+ /* XXX: Is this correct? */
+ sbit_metrics->max_advance = ( strike->hori.min_origin_SB +
+ strike->hori.max_width +
+ strike->hori.min_advance_SB ) << 6;
+
+ size->strike_index = strike_index;
+ }
+ else
+ {
+ size->strike_index = 0xFFFFU;
+
+ sbit_metrics->x_ppem = 0;
+ sbit_metrics->y_ppem = 0;
+ sbit_metrics->ascender = 0;
+ sbit_metrics->descender = 0;
+ sbit_metrics->height = 0;
+ sbit_metrics->max_advance = 0;
+ }
+
+ return error;
+ }
+
+#endif /* TT_CONFIG_OPTION_EMBEDDED_BITMAPS */
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* tt_size_reset */
+ /* */
+ /* <Description> */
+ /* Resets a TrueType size when resolutions and character dimensions */
+ /* have been changed. */
+ /* */
+ /* <Input> */
+ /* size :: A handle to the target size object. */
+ /* */
+ FT_LOCAL_DEF( FT_Error )
+ tt_size_reset( TT_Size size )
+ {
+ FT_Face face;
+ FT_Error error = TT_Err_Ok;
+
+
+ face = size->root.face;
+
+ if ( face->face_flags & FT_FACE_FLAG_SCALABLE )
+ {
+ if ( !size->ttmetrics.valid )
+ error = Reset_Outline_Size( size );
+
+ if ( error )
+ return error;
+ }
+
+#ifdef TT_CONFIG_OPTION_EMBEDDED_BITMAPS
+
+ if ( face->face_flags & FT_FACE_FLAG_FIXED_SIZES )
+ {
+ if ( size->strike_index == 0xFFFFU )
+ error = Reset_SBit_Size( size );
+
+ if ( !error && !( face->face_flags & FT_FACE_FLAG_SCALABLE ) )
+ size->root.metrics = size->strike_metrics;
+ }
+
+#endif /* TT_CONFIG_OPTION_EMBEDDED_BITMAPS */
+
+ if ( face->face_flags & FT_FACE_FLAG_SCALABLE )
+ return TT_Err_Ok;
+ else
+ return error;
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* tt_driver_init */
+ /* */
+ /* <Description> */
+ /* Initializes a given TrueType driver object. */
+ /* */
+ /* <Input> */
+ /* driver :: A handle to the target driver object. */
+ /* */
+ /* <Return> */
+ /* FreeType error code. 0 means success. */
+ /* */
+ FT_LOCAL_DEF( FT_Error )
+ tt_driver_init( TT_Driver driver )
+ {
+ FT_Error error;
+
+
+ /* set `extra' in glyph loader */
+ error = FT_GlyphLoader_CreateExtra( FT_DRIVER( driver )->glyph_loader );
+
+ return error;
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* tt_driver_done */
+ /* */
+ /* <Description> */
+ /* Finalizes a given TrueType driver. */
+ /* */
+ /* <Input> */
+ /* driver :: A handle to the target TrueType driver. */
+ /* */
+ FT_LOCAL_DEF( void )
+ tt_driver_done( TT_Driver driver )
+ {
+#ifdef TT_CONFIG_OPTION_BYTECODE_INTERPRETER
+
+ /* destroy the execution context */
+ if ( driver->context )
+ {
+ TT_Destroy_Context( driver->context, driver->root.root.memory );
+ driver->context = NULL;
+ }
+#else
+ FT_UNUSED( driver );
+#endif
+
+ }
+
+
+/* END */
--- /dev/null
+++ b/libfreetype/ttobjs.h
@@ -1,0 +1,422 @@
+/***************************************************************************/
+/* */
+/* ttobjs.h */
+/* */
+/* Objects manager (specification). */
+/* */
+/* Copyright 1996-2001, 2002 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+
+#ifndef __TTOBJS_H__
+#define __TTOBJS_H__
+
+
+#include <ft2build.h>
+#include FT_INTERNAL_OBJECTS_H
+#include FT_INTERNAL_TRUETYPE_TYPES_H
+
+
+FT_BEGIN_HEADER
+
+
+ /*************************************************************************/
+ /* */
+ /* <Type> */
+ /* TT_Driver */
+ /* */
+ /* <Description> */
+ /* A handle to a TrueType driver object. */
+ /* */
+ typedef struct TT_DriverRec_* TT_Driver;
+
+
+ /*************************************************************************/
+ /* */
+ /* <Type> */
+ /* TT_Instance */
+ /* */
+ /* <Description> */
+ /* A handle to a TrueType size object. */
+ /* */
+ typedef struct TT_SizeRec_* TT_Size;
+
+
+ /*************************************************************************/
+ /* */
+ /* <Type> */
+ /* TT_GlyphSlot */
+ /* */
+ /* <Description> */
+ /* A handle to a TrueType glyph slot object. */
+ /* */
+ /* <Note> */
+ /* This is a direct typedef of FT_GlyphSlot, as there is nothing */
+ /* specific about the TrueType glyph slot. */
+ /* */
+ typedef FT_GlyphSlot TT_GlyphSlot;
+
+
+ /*************************************************************************/
+ /* */
+ /* <Struct> */
+ /* TT_GraphicsState */
+ /* */
+ /* <Description> */
+ /* The TrueType graphics state used during bytecode interpretation. */
+ /* */
+ typedef struct TT_GraphicsState_
+ {
+ FT_UShort rp0;
+ FT_UShort rp1;
+ FT_UShort rp2;
+
+ FT_UnitVector dualVector;
+ FT_UnitVector projVector;
+ FT_UnitVector freeVector;
+
+ FT_Long loop;
+ FT_F26Dot6 minimum_distance;
+ FT_Int round_state;
+
+ FT_Bool auto_flip;
+ FT_F26Dot6 control_value_cutin;
+ FT_F26Dot6 single_width_cutin;
+ FT_F26Dot6 single_width_value;
+ FT_Short delta_base;
+ FT_Short delta_shift;
+
+ FT_Byte instruct_control;
+ FT_Bool scan_control;
+ FT_Int scan_type;
+
+ FT_UShort gep0;
+ FT_UShort gep1;
+ FT_UShort gep2;
+
+ } TT_GraphicsState;
+
+
+#ifdef TT_CONFIG_OPTION_BYTECODE_INTERPRETER
+
+ FT_LOCAL( void )
+ tt_glyphzone_done( TT_GlyphZone zone );
+
+ FT_LOCAL( FT_Error )
+ tt_glyphzone_new( FT_Memory memory,
+ FT_UShort maxPoints,
+ FT_Short maxContours,
+ TT_GlyphZone zone );
+
+#endif /* TT_CONFIG_OPTION_BYTECODE_INTERPRETER */
+
+
+
+ /*************************************************************************/
+ /* */
+ /* EXECUTION SUBTABLES */
+ /* */
+ /* These sub-tables relate to instruction execution. */
+ /* */
+ /*************************************************************************/
+
+
+#define TT_MAX_CODE_RANGES 3
+
+
+ /*************************************************************************/
+ /* */
+ /* There can only be 3 active code ranges at once: */
+ /* - the Font Program */
+ /* - the CVT Program */
+ /* - a glyph's instructions set */
+ /* */
+ typedef enum TT_CodeRange_Tag_
+ {
+ tt_coderange_none = 0,
+ tt_coderange_font,
+ tt_coderange_cvt,
+ tt_coderange_glyph
+
+ } TT_CodeRange_Tag;
+
+
+ typedef struct TT_CodeRange_
+ {
+ FT_Byte* base;
+ FT_ULong size;
+
+ } TT_CodeRange;
+
+ typedef TT_CodeRange TT_CodeRangeTable[TT_MAX_CODE_RANGES];
+
+
+ /*************************************************************************/
+ /* */
+ /* Defines a function/instruction definition record. */
+ /* */
+ typedef struct TT_DefRecord_
+ {
+ FT_Int range; /* in which code range is it located? */
+ FT_Long start; /* where does it start? */
+ FT_UInt opc; /* function #, or instruction code */
+ FT_Bool active; /* is it active? */
+
+ } TT_DefRecord, *TT_DefArray;
+
+
+ /*************************************************************************/
+ /* */
+ /* Subglyph transformation record. */
+ /* */
+ typedef struct TT_Transform_
+ {
+ FT_Fixed xx, xy; /* transformation matrix coefficients */
+ FT_Fixed yx, yy;
+ FT_F26Dot6 ox, oy; /* offsets */
+
+ } TT_Transform;
+
+
+ /*************************************************************************/
+ /* */
+ /* Subglyph loading record. Used to load composite components. */
+ /* */
+ typedef struct TT_SubglyphRec_
+ {
+ FT_Long index; /* subglyph index; initialized with -1 */
+ FT_Bool is_scaled; /* is the subglyph scaled? */
+ FT_Bool is_hinted; /* should it be hinted? */
+ FT_Bool preserve_pps; /* preserve phantom points? */
+
+ FT_Long file_offset;
+
+ FT_BBox bbox;
+ FT_Pos left_bearing;
+ FT_Pos advance;
+
+ TT_GlyphZoneRec zone;
+
+ FT_Long arg1; /* first argument */
+ FT_Long arg2; /* second argument */
+
+ FT_UShort element_flag; /* current load element flag */
+
+ TT_Transform transform; /* transformation matrix */
+
+ FT_Vector pp1, pp2; /* phantom points */
+
+ } TT_SubGlyphRec, *TT_SubGlyph_Stack;
+
+
+ /*************************************************************************/
+ /* */
+ /* A note regarding non-squared pixels: */
+ /* */
+ /* (This text will probably go into some docs at some time; for now, it */
+ /* is kept here to explain some definitions in the TIns_Metrics */
+ /* record). */
+ /* */
+ /* The CVT is a one-dimensional array containing values that control */
+ /* certain important characteristics in a font, like the height of all */
+ /* capitals, all lowercase letter, default spacing or stem width/height. */
+ /* */
+ /* These values are found in FUnits in the font file, and must be scaled */
+ /* to pixel coordinates before being used by the CVT and glyph programs. */
+ /* Unfortunately, when using distinct x and y resolutions (or distinct x */
+ /* and y pointsizes), there are two possible scalings. */
+ /* */
+ /* A first try was to implement a `lazy' scheme where all values were */
+ /* scaled when first used. However, while some values are always used */
+ /* in the same direction, some others are used under many different */
+ /* circumstances and orientations. */
+ /* */
+ /* I have found a simpler way to do the same, and it even seems to work */
+ /* in most of the cases: */
+ /* */
+ /* - All CVT values are scaled to the maximum ppem size. */
+ /* */
+ /* - When performing a read or write in the CVT, a ratio factor is used */
+ /* to perform adequate scaling. Example: */
+ /* */
+ /* x_ppem = 14 */
+ /* y_ppem = 10 */
+ /* */
+ /* We choose ppem = x_ppem = 14 as the CVT scaling size. All cvt */
+ /* entries are scaled to it. */
+ /* */
+ /* x_ratio = 1.0 */
+ /* y_ratio = y_ppem/ppem (< 1.0) */
+ /* */
+ /* We compute the current ratio like: */
+ /* */
+ /* - If projVector is horizontal, */
+ /* ratio = x_ratio = 1.0 */
+ /* */
+ /* - if projVector is vertical, */
+ /* ratio = y_ratio */
+ /* */
+ /* - else, */
+ /* ratio = sqrt( (proj.x * x_ratio) ^ 2 + (proj.y * y_ratio) ^ 2 ) */
+ /* */
+ /* Reading a cvt value returns */
+ /* ratio * cvt[index] */
+ /* */
+ /* Writing a cvt value in pixels: */
+ /* cvt[index] / ratio */
+ /* */
+ /* The current ppem is simply */
+ /* ratio * ppem */
+ /* */
+ /*************************************************************************/
+
+
+ /*************************************************************************/
+ /* */
+ /* Metrics used by the TrueType size and context objects. */
+ /* */
+ typedef struct TT_Size_Metrics_
+ {
+ /* for non-square pixels */
+ FT_Long x_ratio;
+ FT_Long y_ratio;
+
+ FT_UShort ppem; /* maximum ppem size */
+ FT_Long ratio; /* current ratio */
+ FT_Fixed scale;
+
+ FT_F26Dot6 compensations[4]; /* device-specific compensations */
+
+ FT_Bool valid;
+
+ FT_Bool rotated; /* `is the glyph rotated?'-flag */
+ FT_Bool stretched; /* `is the glyph stretched?'-flag */
+
+ } TT_Size_Metrics;
+
+
+ /*************************************************************************/
+ /* */
+ /* TrueType size class. */
+ /* */
+ typedef struct TT_SizeRec_
+ {
+ FT_SizeRec root;
+
+ TT_Size_Metrics ttmetrics;
+
+#ifdef TT_CONFIG_OPTION_EMBEDDED_BITMAPS
+
+ FT_UInt strike_index; /* 0xFFFF to indicate invalid */
+ FT_Size_Metrics strike_metrics; /* current strike's metrics */
+
+#endif
+
+#ifdef TT_CONFIG_OPTION_BYTECODE_INTERPRETER
+
+ FT_UInt num_function_defs; /* number of function definitions */
+ FT_UInt max_function_defs;
+ TT_DefArray function_defs; /* table of function definitions */
+
+ FT_UInt num_instruction_defs; /* number of ins. definitions */
+ FT_UInt max_instruction_defs;
+ TT_DefArray instruction_defs; /* table of ins. definitions */
+
+ FT_UInt max_func;
+ FT_UInt max_ins;
+
+ TT_CodeRangeTable codeRangeTable;
+
+ TT_GraphicsState GS;
+
+ FT_ULong cvt_size; /* the scaled control value table */
+ FT_Long* cvt;
+
+ FT_UShort storage_size; /* The storage area is now part of */
+ FT_Long* storage; /* the instance */
+
+ TT_GlyphZoneRec twilight; /* The instance's twilight zone */
+
+ /* debugging variables */
+
+ /* When using the debugger, we must keep the */
+ /* execution context tied to the instance */
+ /* object rather than asking it on demand. */
+
+ FT_Bool debug;
+ TT_ExecContext context;
+
+#endif /* TT_CONFIG_OPTION_BYTECODE_INTERPRETER */
+
+ } TT_SizeRec;
+
+
+ /*************************************************************************/
+ /* */
+ /* TrueType driver class. */
+ /* */
+ typedef struct TT_DriverRec_
+ {
+ FT_DriverRec root;
+ TT_ExecContext context; /* execution context */
+ TT_GlyphZoneRec zone; /* glyph loader points zone */
+
+ void* extension_component;
+
+ } TT_DriverRec;
+
+
+ /*************************************************************************/
+ /* */
+ /* Face functions */
+ /* */
+ FT_LOCAL( FT_Error )
+ tt_face_init( FT_Stream stream,
+ TT_Face face,
+ FT_Int face_index,
+ FT_Int num_params,
+ FT_Parameter* params );
+
+ FT_LOCAL( void )
+ tt_face_done( TT_Face face );
+
+
+ /*************************************************************************/
+ /* */
+ /* Size functions */
+ /* */
+ FT_LOCAL( FT_Error )
+ tt_size_init( TT_Size size );
+
+ FT_LOCAL( void )
+ tt_size_done( TT_Size size );
+
+ FT_LOCAL( FT_Error )
+ tt_size_reset( TT_Size size );
+
+
+ /*************************************************************************/
+ /* */
+ /* Driver functions */
+ /* */
+ FT_LOCAL( FT_Error )
+ tt_driver_init( TT_Driver driver );
+
+ FT_LOCAL( void )
+ tt_driver_done( TT_Driver driver );
+
+
+FT_END_HEADER
+
+#endif /* __TTOBJS_H__ */
+
+
+/* END */
--- /dev/null
+++ b/libfreetype/ttpload.c
@@ -1,0 +1,264 @@
+/***************************************************************************/
+/* */
+/* ttpload.c */
+/* */
+/* TrueType glyph data/program tables loader (body). */
+/* */
+/* Copyright 1996-2001, 2002 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+
+#include <ft2build.h>
+#include FT_INTERNAL_DEBUG_H
+#include FT_INTERNAL_OBJECTS_H
+#include FT_INTERNAL_STREAM_H
+#include FT_TRUETYPE_TAGS_H
+
+#include "ttpload.h"
+
+#include "tterrors.h"
+
+
+ /*************************************************************************/
+ /* */
+ /* The macro FT_COMPONENT is used in trace mode. It is an implicit */
+ /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log */
+ /* messages during execution. */
+ /* */
+#undef FT_COMPONENT
+#define FT_COMPONENT trace_ttpload
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* tt_face_load_loca */
+ /* */
+ /* <Description> */
+ /* Loads the locations table. */
+ /* */
+ /* <InOut> */
+ /* face :: A handle to the target face object. */
+ /* */
+ /* <Input> */
+ /* stream :: The input stream. */
+ /* */
+ /* <Return> */
+ /* FreeType error code. 0 means success. */
+ /* */
+ FT_LOCAL_DEF( FT_Error )
+ tt_face_load_loca( TT_Face face,
+ FT_Stream stream )
+ {
+ FT_Error error;
+ FT_Memory memory = stream->memory;
+ FT_Short LongOffsets;
+ FT_ULong table_len;
+
+
+ FT_TRACE2(( "Locations " ));
+ LongOffsets = face->header.Index_To_Loc_Format;
+
+ error = face->goto_table( face, TTAG_loca, stream, &table_len );
+ if ( error )
+ {
+ error = TT_Err_Locations_Missing;
+ goto Exit;
+ }
+
+ if ( LongOffsets != 0 )
+ {
+ face->num_locations = (FT_UShort)( table_len >> 2 );
+
+ FT_TRACE2(( "(32bit offsets): %12d ", face->num_locations ));
+
+ if ( FT_NEW_ARRAY( face->glyph_locations, face->num_locations ) )
+ goto Exit;
+
+ if ( FT_FRAME_ENTER( face->num_locations * 4L ) )
+ goto Exit;
+
+ {
+ FT_Long* loc = face->glyph_locations;
+ FT_Long* limit = loc + face->num_locations;
+
+
+ for ( ; loc < limit; loc++ )
+ *loc = FT_GET_LONG();
+ }
+
+ FT_FRAME_EXIT();
+ }
+ else
+ {
+ face->num_locations = (FT_UShort)( table_len >> 1 );
+
+ FT_TRACE2(( "(16bit offsets): %12d ", face->num_locations ));
+
+ if ( FT_NEW_ARRAY( face->glyph_locations, face->num_locations ) )
+ goto Exit;
+
+ if ( FT_FRAME_ENTER( face->num_locations * 2L ) )
+ goto Exit;
+ {
+ FT_Long* loc = face->glyph_locations;
+ FT_Long* limit = loc + face->num_locations;
+
+
+ for ( ; loc < limit; loc++ )
+ *loc = (FT_Long)( (FT_ULong)FT_GET_USHORT() * 2 );
+ }
+ FT_FRAME_EXIT();
+ }
+
+ FT_TRACE2(( "loaded\n" ));
+
+ Exit:
+ return error;
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* tt_face_load_cvt */
+ /* */
+ /* <Description> */
+ /* Loads the control value table into a face object. */
+ /* */
+ /* <InOut> */
+ /* face :: A handle to the target face object. */
+ /* */
+ /* <Input> */
+ /* stream :: A handle to the input stream. */
+ /* */
+ /* <Return> */
+ /* FreeType error code. 0 means success. */
+ /* */
+ FT_LOCAL_DEF( FT_Error )
+ tt_face_load_cvt( TT_Face face,
+ FT_Stream stream )
+ {
+ FT_Error error;
+ FT_Memory memory = stream->memory;
+ FT_ULong table_len;
+
+
+ FT_TRACE2(( "CVT " ));
+
+ error = face->goto_table( face, TTAG_cvt, stream, &table_len );
+ if ( error )
+ {
+ FT_TRACE2(( "is missing!\n" ));
+
+ face->cvt_size = 0;
+ face->cvt = NULL;
+ error = TT_Err_Ok;
+
+ goto Exit;
+ }
+
+ face->cvt_size = table_len / 2;
+
+ if ( FT_NEW_ARRAY( face->cvt, face->cvt_size ) )
+ goto Exit;
+
+ if ( FT_FRAME_ENTER( face->cvt_size * 2L ) )
+ goto Exit;
+
+ {
+ FT_Short* cur = face->cvt;
+ FT_Short* limit = cur + face->cvt_size;
+
+
+ for ( ; cur < limit; cur++ )
+ *cur = FT_GET_SHORT();
+ }
+
+ FT_FRAME_EXIT();
+ FT_TRACE2(( "loaded\n" ));
+
+ Exit:
+ return error;
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* tt_face_load_fpgm */
+ /* */
+ /* <Description> */
+ /* Loads the font program and the cvt program. */
+ /* */
+ /* <InOut> */
+ /* face :: A handle to the target face object. */
+ /* */
+ /* <Input> */
+ /* stream :: A handle to the input stream. */
+ /* */
+ /* <Return> */
+ /* FreeType error code. 0 means success. */
+ /* */
+ FT_LOCAL_DEF( FT_Error )
+ tt_face_load_fpgm( TT_Face face,
+ FT_Stream stream )
+ {
+ FT_Error error;
+ FT_ULong table_len;
+
+
+ FT_TRACE2(( "Font program " ));
+
+ /* The font program is optional */
+ error = face->goto_table( face, TTAG_fpgm, stream, &table_len );
+ if ( error )
+ {
+ face->font_program = NULL;
+ face->font_program_size = 0;
+
+ FT_TRACE2(( "is missing!\n" ));
+ }
+ else
+ {
+ face->font_program_size = table_len;
+ if ( FT_FRAME_EXTRACT( table_len, face->font_program ) )
+ goto Exit;
+
+ FT_TRACE2(( "loaded, %12d bytes\n", face->font_program_size ));
+ }
+
+ FT_TRACE2(( "Prep program " ));
+
+ error = face->goto_table( face, TTAG_prep, stream, &table_len );
+ if ( error )
+ {
+ face->cvt_program = NULL;
+ face->cvt_program_size = 0;
+ error = TT_Err_Ok;
+
+ FT_TRACE2(( "is missing!\n" ));
+ }
+ else
+ {
+ face->cvt_program_size = table_len;
+ if ( FT_FRAME_EXTRACT( table_len, face->cvt_program ) )
+ goto Exit;
+
+ FT_TRACE2(( "loaded, %12d bytes\n", face->cvt_program_size ));
+ }
+
+ Exit:
+ return error;
+ }
+
+
+/* END */
--- /dev/null
+++ b/libfreetype/ttpload.h
@@ -1,0 +1,48 @@
+/***************************************************************************/
+/* */
+/* ttpload.h */
+/* */
+/* TrueType glyph data/program tables loader (specification). */
+/* */
+/* Copyright 1996-2001, 2002 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+
+#ifndef __TTPLOAD_H__
+#define __TTPLOAD_H__
+
+
+#include <ft2build.h>
+#include FT_INTERNAL_TRUETYPE_TYPES_H
+
+
+FT_BEGIN_HEADER
+
+
+ FT_LOCAL( FT_Error )
+ tt_face_load_loca( TT_Face face,
+ FT_Stream stream );
+
+ FT_LOCAL( FT_Error )
+ tt_face_load_cvt( TT_Face face,
+ FT_Stream stream );
+
+ FT_LOCAL( FT_Error )
+ tt_face_load_fpgm( TT_Face face,
+ FT_Stream stream );
+
+
+FT_END_HEADER
+
+#endif /* __TTPLOAD_H__ */
+
+
+/* END */
--- /dev/null
+++ b/libfreetype/ttpost.c
@@ -1,0 +1,521 @@
+/***************************************************************************/
+/* */
+/* ttpost.c */
+/* */
+/* Postcript name table processing for TrueType and OpenType fonts */
+/* (body). */
+/* */
+/* Copyright 1996-2001, 2002 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+ /*************************************************************************/
+ /* */
+ /* The post table is not completely loaded by the core engine. This */
+ /* file loads the missing PS glyph names and implements an API to access */
+ /* them. */
+ /* */
+ /*************************************************************************/
+
+
+#include <ft2build.h>
+#include FT_INTERNAL_STREAM_H
+#include FT_TRUETYPE_TAGS_H
+#include "ttpost.h"
+#include "ttload.h"
+
+#include "sferrors.h"
+
+
+ /*************************************************************************/
+ /* */
+ /* The macro FT_COMPONENT is used in trace mode. It is an implicit */
+ /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log */
+ /* messages during execution. */
+ /* */
+#undef FT_COMPONENT
+#define FT_COMPONENT trace_ttpost
+
+
+ /* If this configuration macro is defined, we rely on the `PSNames' */
+ /* module to grab the glyph names. */
+
+#ifdef FT_CONFIG_OPTION_POSTSCRIPT_NAMES
+
+
+#include FT_INTERNAL_POSTSCRIPT_NAMES_H
+
+#define MAC_NAME( x ) ( (FT_String*)psnames->macintosh_name( x ) )
+
+
+#else /* FT_CONFIG_OPTION_POSTSCRIPT_NAMES */
+
+
+ /* Otherwise, we ignore the `PSNames' module, and provide our own */
+ /* table of Mac names. Thus, it is possible to build a version of */
+ /* FreeType without the Type 1 driver & PSNames module. */
+
+#define MAC_NAME( x ) tt_post_default_names[x]
+
+ /* the 258 default Mac PS glyph names */
+
+ static const FT_String* tt_post_default_names[258] =
+ {
+ /* 0 */
+ ".notdef", ".null", "CR", "space", "exclam",
+ "quotedbl", "numbersign", "dollar", "percent", "ampersand",
+ /* 10 */
+ "quotesingle", "parenleft", "parenright", "asterisk", "plus",
+ "comma", "hyphen", "period", "slash", "zero",
+ /* 20 */
+ "one", "two", "three", "four", "five",
+ "six", "seven", "eight", "nine", "colon",
+ /* 30 */
+ "semicolon", "less", "equal", "greater", "question",
+ "at", "A", "B", "C", "D",
+ /* 40 */
+ "E", "F", "G", "H", "I",
+ "J", "K", "L", "M", "N",
+ /* 50 */
+ "O", "P", "Q", "R", "S",
+ "T", "U", "V", "W", "X",
+ /* 60 */
+ "Y", "Z", "bracketleft", "backslash", "bracketright",
+ "asciicircum", "underscore", "grave", "a", "b",
+ /* 70 */
+ "c", "d", "e", "f", "g",
+ "h", "i", "j", "k", "l",
+ /* 80 */
+ "m", "n", "o", "p", "q",
+ "r", "s", "t", "u", "v",
+ /* 90 */
+ "w", "x", "y", "z", "braceleft",
+ "bar", "braceright", "asciitilde", "Adieresis", "Aring",
+ /* 100 */
+ "Ccedilla", "Eacute", "Ntilde", "Odieresis", "Udieresis",
+ "aacute", "agrave", "acircumflex", "adieresis", "atilde",
+ /* 110 */
+ "aring", "ccedilla", "eacute", "egrave", "ecircumflex",
+ "edieresis", "iacute", "igrave", "icircumflex", "idieresis",
+ /* 120 */
+ "ntilde", "oacute", "ograve", "ocircumflex", "odieresis",
+ "otilde", "uacute", "ugrave", "ucircumflex", "udieresis",
+ /* 130 */
+ "dagger", "degree", "cent", "sterling", "section",
+ "bullet", "paragraph", "germandbls", "registered", "copyright",
+ /* 140 */
+ "trademark", "acute", "dieresis", "notequal", "AE",
+ "Oslash", "infinity", "plusminus", "lessequal", "greaterequal",
+ /* 150 */
+ "yen", "mu", "partialdiff", "summation", "product",
+ "pi", "integral", "ordfeminine", "ordmasculine", "Omega",
+ /* 160 */
+ "ae", "oslash", "questiondown", "exclamdown", "logicalnot",
+ "radical", "florin", "approxequal", "Delta", "guillemotleft",
+ /* 170 */
+ "guillemotright", "ellipsis", "nbspace", "Agrave", "Atilde",
+ "Otilde", "OE", "oe", "endash", "emdash",
+ /* 180 */
+ "quotedblleft", "quotedblright", "quoteleft", "quoteright", "divide",
+ "lozenge", "ydieresis", "Ydieresis", "fraction", "currency",
+ /* 190 */
+ "guilsinglleft", "guilsinglright", "fi", "fl", "daggerdbl",
+ "periodcentered", "quotesinglbase", "quotedblbase", "perthousand", "Acircumflex",
+ /* 200 */
+ "Ecircumflex", "Aacute", "Edieresis", "Egrave", "Iacute",
+ "Icircumflex", "Idieresis", "Igrave", "Oacute", "Ocircumflex",
+ /* 210 */
+ "apple", "Ograve", "Uacute", "Ucircumflex", "Ugrave",
+ "dotlessi", "circumflex", "tilde", "macron", "breve",
+ /* 220 */
+ "dotaccent", "ring", "cedilla", "hungarumlaut", "ogonek",
+ "caron", "Lslash", "lslash", "Scaron", "scaron",
+ /* 230 */
+ "Zcaron", "zcaron", "brokenbar", "Eth", "eth",
+ "Yacute", "yacute", "Thorn", "thorn", "minus",
+ /* 240 */
+ "multiply", "onesuperior", "twosuperior", "threesuperior", "onehalf",
+ "onequarter", "threequarters", "franc", "Gbreve", "gbreve",
+ /* 250 */
+ "Idot", "Scedilla", "scedilla", "Cacute", "cacute",
+ "Ccaron", "ccaron", "dmacron",
+ };
+
+
+#endif /* FT_CONFIG_OPTION_POSTSCRIPT_NAMES */
+
+
+ static FT_Error
+ load_format_20( TT_Face face,
+ FT_Stream stream )
+ {
+ FT_Memory memory = stream->memory;
+ FT_Error error;
+
+ FT_Int num_glyphs;
+ FT_UShort num_names;
+
+ FT_UShort* glyph_indices = 0;
+ FT_Char** name_strings = 0;
+
+
+ if ( FT_READ_USHORT( num_glyphs ) )
+ goto Exit;
+
+ /* UNDOCUMENTED! The number of glyphs in this table can be smaller */
+ /* than the value in the maxp table (cf. cyberbit.ttf). */
+
+ /* There already exist fonts which have more than 32768 glyph names */
+ /* in this table, so the test for this threshold has been dropped. */
+
+ if ( num_glyphs > face->root.num_glyphs )
+ {
+ error = SFNT_Err_Invalid_File_Format;
+ goto Exit;
+ }
+
+ /* load the indices */
+ {
+ FT_Int n;
+
+
+ if ( FT_NEW_ARRAY ( glyph_indices, num_glyphs ) ||
+ FT_FRAME_ENTER( num_glyphs * 2L ) )
+ goto Fail;
+
+ for ( n = 0; n < num_glyphs; n++ )
+ glyph_indices[n] = FT_GET_USHORT();
+
+ FT_FRAME_EXIT();
+ }
+
+ /* compute number of names stored in table */
+ {
+ FT_Int n;
+
+
+ num_names = 0;
+
+ for ( n = 0; n < num_glyphs; n++ )
+ {
+ FT_Int idx;
+
+
+ idx = glyph_indices[n];
+ if ( idx >= 258 )
+ {
+ idx -= 257;
+ if ( idx > num_names )
+ num_names = (FT_UShort)idx;
+ }
+ }
+ }
+
+ /* now load the name strings */
+ {
+ FT_UShort n;
+
+
+ if ( FT_NEW_ARRAY( name_strings, num_names ) )
+ goto Fail;
+
+ for ( n = 0; n < num_names; n++ )
+ {
+ FT_UInt len;
+
+
+ if ( FT_READ_BYTE ( len ) ||
+ FT_NEW_ARRAY( name_strings[n], len + 1 ) ||
+ FT_STREAM_READ ( name_strings[n], len ) )
+ goto Fail1;
+
+ name_strings[n][len] = '\0';
+ }
+ }
+
+ /* all right, set table fields and exit successfuly */
+ {
+ TT_Post_20 table = &face->postscript_names.names.format_20;
+
+
+ table->num_glyphs = (FT_UShort)num_glyphs;
+ table->num_names = (FT_UShort)num_names;
+ table->glyph_indices = glyph_indices;
+ table->glyph_names = name_strings;
+ }
+ return SFNT_Err_Ok;
+
+ Fail1:
+ {
+ FT_UShort n;
+
+
+ for ( n = 0; n < num_names; n++ )
+ FT_FREE( name_strings[n] );
+ }
+
+ Fail:
+ FT_FREE( name_strings );
+ FT_FREE( glyph_indices );
+
+ Exit:
+ return error;
+ }
+
+
+ static FT_Error
+ load_format_25( TT_Face face,
+ FT_Stream stream )
+ {
+ FT_Memory memory = stream->memory;
+ FT_Error error;
+
+ FT_Int num_glyphs;
+ FT_Char* offset_table = 0;
+
+
+ /* UNDOCUMENTED! This value appears only in the Apple TT specs. */
+ if ( FT_READ_USHORT( num_glyphs ) )
+ goto Exit;
+
+ /* check the number of glyphs */
+ if ( num_glyphs > face->root.num_glyphs || num_glyphs > 258 )
+ {
+ error = SFNT_Err_Invalid_File_Format;
+ goto Exit;
+ }
+
+ if ( FT_ALLOC( offset_table, num_glyphs ) ||
+ FT_STREAM_READ( offset_table, num_glyphs ) )
+ goto Fail;
+
+ /* now check the offset table */
+ {
+ FT_Int n;
+
+
+ for ( n = 0; n < num_glyphs; n++ )
+ {
+ FT_Long idx = (FT_Long)n + offset_table[n];
+
+
+ if ( idx < 0 || idx > num_glyphs )
+ {
+ error = SFNT_Err_Invalid_File_Format;
+ goto Fail;
+ }
+ }
+ }
+
+ /* OK, set table fields and exit successfuly */
+ {
+ TT_Post_25 table = &face->postscript_names.names.format_25;
+
+
+ table->num_glyphs = (FT_UShort)num_glyphs;
+ table->offsets = offset_table;
+ }
+
+ return SFNT_Err_Ok;
+
+ Fail:
+ FT_FREE( offset_table );
+
+ Exit:
+ return error;
+ }
+
+
+ static FT_Error
+ load_post_names( TT_Face face )
+ {
+ FT_Stream stream;
+ FT_Error error;
+ FT_Fixed format;
+
+
+ /* get a stream for the face's resource */
+ stream = face->root.stream;
+
+ /* seek to the beginning of the PS names table */
+ error = face->goto_table( face, TTAG_post, stream, 0 );
+ if ( error )
+ goto Exit;
+
+ format = face->postscript.FormatType;
+
+ /* go to beginning of subtable */
+ if ( FT_STREAM_SKIP( 32 ) )
+ goto Exit;
+
+ /* now read postscript table */
+ if ( format == 0x00020000L )
+ error = load_format_20( face, stream );
+ else if ( format == 0x00028000L )
+ error = load_format_25( face, stream );
+ else
+ error = SFNT_Err_Invalid_File_Format;
+
+ face->postscript_names.loaded = 1;
+
+ Exit:
+ return error;
+ }
+
+
+ FT_LOCAL_DEF( void )
+ tt_face_free_ps_names( TT_Face face )
+ {
+ FT_Memory memory = face->root.memory;
+ TT_Post_Names names = &face->postscript_names;
+ FT_Fixed format;
+
+
+ if ( names->loaded )
+ {
+ format = face->postscript.FormatType;
+
+ if ( format == 0x00020000L )
+ {
+ TT_Post_20 table = &names->names.format_20;
+ FT_UShort n;
+
+
+ FT_FREE( table->glyph_indices );
+ table->num_glyphs = 0;
+
+ for ( n = 0; n < table->num_names; n++ )
+ FT_FREE( table->glyph_names[n] );
+
+ FT_FREE( table->glyph_names );
+ table->num_names = 0;
+ }
+ else if ( format == 0x00028000L )
+ {
+ TT_Post_25 table = &names->names.format_25;
+
+
+ FT_FREE( table->offsets );
+ table->num_glyphs = 0;
+ }
+ }
+ names->loaded = 0;
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* tt_face_get_ps_name */
+ /* */
+ /* <Description> */
+ /* Gets the PostScript glyph name of a glyph. */
+ /* */
+ /* <Input> */
+ /* face :: A handle to the parent face. */
+ /* */
+ /* idx :: The glyph index. */
+ /* */
+ /* PSname :: The address of a string pointer. Will be NULL in case */
+ /* of error, otherwise it is a pointer to the glyph name. */
+ /* */
+ /* You must not modify the returned string! */
+ /* */
+ /* <Output> */
+ /* FreeType error code. 0 means success. */
+ /* */
+ FT_LOCAL_DEF( FT_Error )
+ tt_face_get_ps_name( TT_Face face,
+ FT_UInt idx,
+ FT_String** PSname )
+ {
+ FT_Error error;
+ TT_Post_Names names;
+ FT_Fixed format;
+
+#ifdef FT_CONFIG_OPTION_POSTSCRIPT_NAMES
+ PSNames_Service psnames;
+#endif
+
+
+ if ( !face )
+ return SFNT_Err_Invalid_Face_Handle;
+
+ if ( idx >= (FT_UInt)face->root.num_glyphs )
+ return SFNT_Err_Invalid_Glyph_Index;
+
+#ifdef FT_CONFIG_OPTION_POSTSCRIPT_NAMES
+ psnames = (PSNames_Service)face->psnames;
+ if ( !psnames )
+ return SFNT_Err_Unimplemented_Feature;
+#endif
+
+ names = &face->postscript_names;
+
+ /* `.notdef' by default */
+ *PSname = MAC_NAME( 0 );
+
+ format = face->postscript.FormatType;
+
+ if ( format == 0x00010000L )
+ {
+ if ( idx < 258 ) /* paranoid checking */
+ *PSname = MAC_NAME( idx );
+ }
+ else if ( format == 0x00020000L )
+ {
+ TT_Post_20 table = &names->names.format_20;
+
+
+ if ( !names->loaded )
+ {
+ error = load_post_names( face );
+ if ( error )
+ goto End;
+ }
+
+ if ( idx < (FT_UInt)table->num_glyphs )
+ {
+ FT_UShort name_index = table->glyph_indices[idx];
+
+
+ if ( name_index < 258 )
+ *PSname = MAC_NAME( name_index );
+ else
+ *PSname = (FT_String*)table->glyph_names[name_index - 258];
+ }
+ }
+ else if ( format == 0x00028000L )
+ {
+ TT_Post_25 table = &names->names.format_25;
+
+
+ if ( !names->loaded )
+ {
+ error = load_post_names( face );
+ if ( error )
+ goto End;
+ }
+
+ if ( idx < (FT_UInt)table->num_glyphs ) /* paranoid checking */
+ {
+ idx += table->offsets[idx];
+ *PSname = MAC_NAME( idx );
+ }
+ }
+
+ /* nothing to do for format == 0x00030000L */
+
+ End:
+ return SFNT_Err_Ok;
+ }
+
+
+/* END */
--- /dev/null
+++ b/libfreetype/ttpost.h
@@ -1,0 +1,46 @@
+/***************************************************************************/
+/* */
+/* ttpost.h */
+/* */
+/* Postcript name table processing for TrueType and OpenType fonts */
+/* (specification). */
+/* */
+/* Copyright 1996-2001, 2002 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+
+#ifndef __TTPOST_H__
+#define __TTPOST_H__
+
+
+#include <ft2build.h>
+#include FT_CONFIG_CONFIG_H
+#include FT_INTERNAL_TRUETYPE_TYPES_H
+
+
+FT_BEGIN_HEADER
+
+
+ FT_LOCAL( FT_Error )
+ tt_face_get_ps_name( TT_Face face,
+ FT_UInt idx,
+ FT_String** PSname );
+
+ FT_LOCAL( void )
+ tt_face_free_ps_names( TT_Face face );
+
+
+FT_END_HEADER
+
+#endif /* __TTPOST_H__ */
+
+
+/* END */
--- /dev/null
+++ b/libfreetype/ttsbit.c
@@ -1,0 +1,1474 @@
+/***************************************************************************/
+/* */
+/* ttsbit.c */
+/* */
+/* TrueType and OpenType embedded bitmap support (body). */
+/* */
+/* Copyright 1996-2001, 2002 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+
+#include <ft2build.h>
+#include FT_INTERNAL_DEBUG_H
+#include FT_INTERNAL_STREAM_H
+#include FT_TRUETYPE_TAGS_H
+#include "ttsbit.h"
+
+#include "sferrors.h"
+
+
+ /*************************************************************************/
+ /* */
+ /* The macro FT_COMPONENT is used in trace mode. It is an implicit */
+ /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log */
+ /* messages during execution. */
+ /* */
+#undef FT_COMPONENT
+#define FT_COMPONENT trace_ttsbit
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* blit_sbit */
+ /* */
+ /* <Description> */
+ /* Blits a bitmap from an input stream into a given target. Supports */
+ /* x and y offsets as well as byte padded lines. */
+ /* */
+ /* <Input> */
+ /* target :: The target bitmap/pixmap. */
+ /* */
+ /* source :: The input packed bitmap data. */
+ /* */
+ /* line_bits :: The number of bits per line. */
+ /* */
+ /* byte_padded :: A flag which is true if lines are byte-padded. */
+ /* */
+ /* x_offset :: The horizontal offset. */
+ /* */
+ /* y_offset :: The vertical offset. */
+ /* */
+ /* <Note> */
+ /* IMPORTANT: The x and y offsets are relative to the top corner of */
+ /* the target bitmap (unlike the normal TrueType */
+ /* convention). A positive y offset indicates a downwards */
+ /* direction! */
+ /* */
+ static void
+ blit_sbit( FT_Bitmap* target,
+ FT_Byte* source,
+ FT_Int line_bits,
+ FT_Bool byte_padded,
+ FT_Int x_offset,
+ FT_Int y_offset )
+ {
+ FT_Byte* line_buff;
+ FT_Int line_incr;
+ FT_Int height;
+
+ FT_UShort acc;
+ FT_UInt loaded;
+
+
+ /* first of all, compute starting write position */
+ line_incr = target->pitch;
+ line_buff = target->buffer;
+
+ if ( line_incr < 0 )
+ line_buff -= line_incr * ( target->rows - 1 );
+
+ line_buff += ( x_offset >> 3 ) + y_offset * line_incr;
+
+ /***********************************************************************/
+ /* */
+ /* We use the extra-classic `accumulator' trick to extract the bits */
+ /* from the source byte stream. */
+ /* */
+ /* Namely, the variable `acc' is a 16-bit accumulator containing the */
+ /* last `loaded' bits from the input stream. The bits are shifted to */
+ /* the upmost position in `acc'. */
+ /* */
+ /***********************************************************************/
+
+ acc = 0; /* clear accumulator */
+ loaded = 0; /* no bits were loaded */
+
+ for ( height = target->rows; height > 0; height-- )
+ {
+ FT_Byte* cur = line_buff; /* current write cursor */
+ FT_Int count = line_bits; /* # of bits to extract per line */
+ FT_Byte shift = (FT_Byte)( x_offset & 7 ); /* current write shift */
+ FT_Byte space = (FT_Byte)( 8 - shift );
+
+
+ /* first of all, read individual source bytes */
+ if ( count >= 8 )
+ {
+ count -= 8;
+ {
+ do
+ {
+ FT_Byte val;
+
+
+ /* ensure that there are at least 8 bits in the accumulator */
+ if ( loaded < 8 )
+ {
+ acc |= (FT_UShort)((FT_UShort)*source++ << ( 8 - loaded ));
+ loaded += 8;
+ }
+
+ /* now write one byte */
+ val = (FT_Byte)( acc >> 8 );
+ if ( shift )
+ {
+ cur[0] |= (FT_Byte)( val >> shift );
+ cur[1] |= (FT_Byte)( val << space );
+ }
+ else
+ cur[0] |= val;
+
+ cur++;
+ acc <<= 8; /* remove bits from accumulator */
+ loaded -= 8;
+ count -= 8;
+
+ } while ( count >= 0 );
+ }
+
+ /* restore `count' to correct value */
+ count += 8;
+ }
+
+ /* now write remaining bits (count < 8) */
+ if ( count > 0 )
+ {
+ FT_Byte val;
+
+
+ /* ensure that there are at least `count' bits in the accumulator */
+ if ( (FT_Int)loaded < count )
+ {
+ acc |= (FT_UShort)((FT_UShort)*source++ << ( 8 - loaded ));
+ loaded += 8;
+ }
+
+ /* now write remaining bits */
+ val = (FT_Byte)( ( (FT_Byte)( acc >> 8 ) ) & ~( 0xFF >> count ) );
+ cur[0] |= (FT_Byte)( val >> shift );
+
+ if ( count > space )
+ cur[1] |= (FT_Byte)( val << space );
+
+ acc <<= count;
+ loaded -= count;
+ }
+
+ /* now, skip to next line */
+ if ( byte_padded )
+ {
+ acc = 0;
+ loaded = 0; /* clear accumulator on byte-padded lines */
+ }
+
+ line_buff += line_incr;
+ }
+ }
+
+
+ const FT_Frame_Field sbit_metrics_fields[] =
+ {
+#undef FT_STRUCTURE
+#define FT_STRUCTURE TT_SBit_MetricsRec
+
+ FT_FRAME_START( 8 ),
+ FT_FRAME_BYTE( height ),
+ FT_FRAME_BYTE( width ),
+
+ FT_FRAME_CHAR( horiBearingX ),
+ FT_FRAME_CHAR( horiBearingY ),
+ FT_FRAME_BYTE( horiAdvance ),
+
+ FT_FRAME_CHAR( vertBearingX ),
+ FT_FRAME_CHAR( vertBearingY ),
+ FT_FRAME_BYTE( vertAdvance ),
+ FT_FRAME_END
+ };
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* TT_Load_SBit_Const_Metrics */
+ /* */
+ /* <Description> */
+ /* Loads the metrics for `EBLC' index tables format 2 and 5. */
+ /* */
+ /* <Input> */
+ /* range :: The target range. */
+ /* */
+ /* stream :: The input stream. */
+ /* */
+ /* <Return> */
+ /* FreeType error code. 0 means success. */
+ /* */
+ static FT_Error
+ Load_SBit_Const_Metrics( TT_SBit_Range range,
+ FT_Stream stream )
+ {
+ FT_Error error;
+
+
+ if ( FT_READ_ULONG( range->image_size ) )
+ return error;
+
+ return FT_STREAM_READ_FIELDS( sbit_metrics_fields, &range->metrics );
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* TT_Load_SBit_Range_Codes */
+ /* */
+ /* <Description> */
+ /* Loads the range codes for `EBLC' index tables format 4 and 5. */
+ /* */
+ /* <Input> */
+ /* range :: The target range. */
+ /* */
+ /* stream :: The input stream. */
+ /* */
+ /* load_offsets :: A flag whether to load the glyph offset table. */
+ /* */
+ /* <Return> */
+ /* FreeType error code. 0 means success. */
+ /* */
+ static FT_Error
+ Load_SBit_Range_Codes( TT_SBit_Range range,
+ FT_Stream stream,
+ FT_Bool load_offsets )
+ {
+ FT_Error error;
+ FT_ULong count, n, size;
+ FT_Memory memory = stream->memory;
+
+
+ if ( FT_READ_ULONG( count ) )
+ goto Exit;
+
+ range->num_glyphs = count;
+
+ /* Allocate glyph offsets table if needed */
+ if ( load_offsets )
+ {
+ if ( FT_NEW_ARRAY( range->glyph_offsets, count ) )
+ goto Exit;
+
+ size = count * 4L;
+ }
+ else
+ size = count * 2L;
+
+ /* Allocate glyph codes table and access frame */
+ if ( FT_NEW_ARRAY ( range->glyph_codes, count ) ||
+ FT_FRAME_ENTER( size ) )
+ goto Exit;
+
+ for ( n = 0; n < count; n++ )
+ {
+ range->glyph_codes[n] = FT_GET_USHORT();
+
+ if ( load_offsets )
+ range->glyph_offsets[n] = (FT_ULong)range->image_offset +
+ FT_GET_USHORT();
+ }
+
+ FT_FRAME_EXIT();
+
+ Exit:
+ return error;
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* TT_Load_SBit_Range */
+ /* */
+ /* <Description> */
+ /* Loads a given `EBLC' index/range table. */
+ /* */
+ /* <Input> */
+ /* range :: The target range. */
+ /* */
+ /* stream :: The input stream. */
+ /* */
+ /* <Return> */
+ /* FreeType error code. 0 means success. */
+ /* */
+ static FT_Error
+ Load_SBit_Range( TT_SBit_Range range,
+ FT_Stream stream )
+ {
+ FT_Error error;
+ FT_Memory memory = stream->memory;
+
+
+ switch( range->index_format )
+ {
+ case 1: /* variable metrics with 4-byte offsets */
+ case 3: /* variable metrics with 2-byte offsets */
+ {
+ FT_ULong num_glyphs, n;
+ FT_Int size_elem;
+ FT_Bool large = FT_BOOL( range->index_format == 1 );
+
+
+ num_glyphs = range->last_glyph - range->first_glyph + 1L;
+ range->num_glyphs = num_glyphs;
+ num_glyphs++; /* XXX: BEWARE - see spec */
+
+ size_elem = large ? 4 : 2;
+
+ if ( FT_NEW_ARRAY( range->glyph_offsets, num_glyphs ) ||
+ FT_FRAME_ENTER( num_glyphs * size_elem ) )
+ goto Exit;
+
+ for ( n = 0; n < num_glyphs; n++ )
+ range->glyph_offsets[n] = (FT_ULong)( range->image_offset +
+ ( large ? FT_GET_ULONG()
+ : FT_GET_USHORT() ) );
+ FT_FRAME_EXIT();
+ }
+ break;
+
+ case 2: /* all glyphs have identical metrics */
+ error = Load_SBit_Const_Metrics( range, stream );
+ break;
+
+ case 4:
+ error = Load_SBit_Range_Codes( range, stream, 1 );
+ break;
+
+ case 5:
+ error = Load_SBit_Const_Metrics( range, stream ) ||
+ Load_SBit_Range_Codes( range, stream, 0 );
+ break;
+
+ default:
+ error = SFNT_Err_Invalid_File_Format;
+ }
+
+ Exit:
+ return error;
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* tt_face_load_sbit_strikes */
+ /* */
+ /* <Description> */
+ /* Loads the table of embedded bitmap sizes for this face. */
+ /* */
+ /* <Input> */
+ /* face :: The target face object. */
+ /* */
+ /* stream :: The input stream. */
+ /* */
+ /* <Return> */
+ /* FreeType error code. 0 means success. */
+ /* */
+ FT_LOCAL_DEF( FT_Error )
+ tt_face_load_sbit_strikes( TT_Face face,
+ FT_Stream stream )
+ {
+ FT_Error error = 0;
+ FT_Memory memory = stream->memory;
+ FT_Fixed version;
+ FT_ULong num_strikes;
+ FT_ULong table_base;
+
+ const FT_Frame_Field sbit_line_metrics_fields[] =
+ {
+#undef FT_STRUCTURE
+#define FT_STRUCTURE TT_SBit_LineMetricsRec
+
+ /* no FT_FRAME_START */
+ FT_FRAME_CHAR( ascender ),
+ FT_FRAME_CHAR( descender ),
+ FT_FRAME_BYTE( max_width ),
+
+ FT_FRAME_CHAR( caret_slope_numerator ),
+ FT_FRAME_CHAR( caret_slope_denominator ),
+ FT_FRAME_CHAR( caret_offset ),
+
+ FT_FRAME_CHAR( min_origin_SB ),
+ FT_FRAME_CHAR( min_advance_SB ),
+ FT_FRAME_CHAR( max_before_BL ),
+ FT_FRAME_CHAR( min_after_BL ),
+ FT_FRAME_CHAR( pads[0] ),
+ FT_FRAME_CHAR( pads[1] ),
+ FT_FRAME_END
+ };
+
+ const FT_Frame_Field strike_start_fields[] =
+ {
+#undef FT_STRUCTURE
+#define FT_STRUCTURE TT_SBit_StrikeRec
+
+ /* no FT_FRAME_START */
+ FT_FRAME_ULONG( ranges_offset ),
+ FT_FRAME_SKIP_LONG,
+ FT_FRAME_ULONG( num_ranges ),
+ FT_FRAME_ULONG( color_ref ),
+ FT_FRAME_END
+ };
+
+ const FT_Frame_Field strike_end_fields[] =
+ {
+ /* no FT_FRAME_START */
+ FT_FRAME_USHORT( start_glyph ),
+ FT_FRAME_USHORT( end_glyph ),
+ FT_FRAME_BYTE ( x_ppem ),
+ FT_FRAME_BYTE ( y_ppem ),
+ FT_FRAME_BYTE ( bit_depth ),
+ FT_FRAME_CHAR ( flags ),
+ FT_FRAME_END
+ };
+
+
+ face->num_sbit_strikes = 0;
+
+ /* this table is optional */
+ error = face->goto_table( face, TTAG_EBLC, stream, 0 );
+ if ( error )
+ error = face->goto_table( face, TTAG_bloc, stream, 0 );
+ if ( error )
+ goto Exit;
+
+ table_base = FT_STREAM_POS();
+ if ( FT_FRAME_ENTER( 8L ) )
+ goto Exit;
+
+ version = FT_GET_LONG();
+ num_strikes = FT_GET_ULONG();
+
+ FT_FRAME_EXIT();
+
+ /* check version number and strike count */
+ if ( version != 0x00020000L ||
+ num_strikes >= 0x10000L )
+ {
+ FT_ERROR(( "tt_face_load_sbit_strikes: invalid table version!\n" ));
+ error = SFNT_Err_Invalid_File_Format;
+
+ goto Exit;
+ }
+
+ /* allocate the strikes table */
+ if ( FT_NEW_ARRAY( face->sbit_strikes, num_strikes ) )
+ goto Exit;
+
+ face->num_sbit_strikes = num_strikes;
+
+ /* now read each strike table separately */
+ {
+ TT_SBit_Strike strike = face->sbit_strikes;
+ FT_ULong count = num_strikes;
+
+
+ if ( FT_FRAME_ENTER( 48L * num_strikes ) )
+ goto Exit;
+
+ while ( count > 0 )
+ {
+ if ( FT_STREAM_READ_FIELDS( strike_start_fields, strike ) ||
+ FT_STREAM_READ_FIELDS( sbit_line_metrics_fields, &strike->hori ) ||
+ FT_STREAM_READ_FIELDS( sbit_line_metrics_fields, &strike->vert ) ||
+ FT_STREAM_READ_FIELDS( strike_end_fields, strike ) )
+ break;
+
+ count--;
+ strike++;
+ }
+
+ FT_FRAME_EXIT();
+ }
+
+ /* allocate the index ranges for each strike table */
+ {
+ TT_SBit_Strike strike = face->sbit_strikes;
+ FT_ULong count = num_strikes;
+
+
+ while ( count > 0 )
+ {
+ TT_SBit_Range range;
+ FT_ULong count2 = strike->num_ranges;
+
+
+ if ( FT_NEW_ARRAY( strike->sbit_ranges, strike->num_ranges ) )
+ goto Exit;
+
+ /* read each range */
+ if ( FT_STREAM_SEEK( table_base + strike->ranges_offset ) ||
+ FT_FRAME_ENTER( strike->num_ranges * 8L ) )
+ goto Exit;
+
+ range = strike->sbit_ranges;
+ while ( count2 > 0 )
+ {
+ range->first_glyph = FT_GET_USHORT();
+ range->last_glyph = FT_GET_USHORT();
+ range->table_offset = table_base + strike->ranges_offset +
+ FT_GET_ULONG();
+ count2--;
+ range++;
+ }
+
+ FT_FRAME_EXIT();
+
+ /* Now, read each index table */
+ count2 = strike->num_ranges;
+ range = strike->sbit_ranges;
+ while ( count2 > 0 )
+ {
+ /* Read the header */
+ if ( FT_STREAM_SEEK( range->table_offset ) ||
+ FT_FRAME_ENTER( 8L ) )
+ goto Exit;
+
+ range->index_format = FT_GET_USHORT();
+ range->image_format = FT_GET_USHORT();
+ range->image_offset = FT_GET_ULONG();
+
+ FT_FRAME_EXIT();
+
+ error = Load_SBit_Range( range, stream );
+ if ( error )
+ goto Exit;
+
+ count2--;
+ range++;
+ }
+
+ count--;
+ strike++;
+ }
+ }
+
+ Exit:
+ return error;
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* tt_face_free_sbit_strikes */
+ /* */
+ /* <Description> */
+ /* Releases the embedded bitmap tables. */
+ /* */
+ /* <Input> */
+ /* face :: The target face object. */
+ /* */
+ FT_LOCAL_DEF( void )
+ tt_face_free_sbit_strikes( TT_Face face )
+ {
+ FT_Memory memory = face->root.memory;
+ TT_SBit_Strike strike = face->sbit_strikes;
+ TT_SBit_Strike strike_limit = strike + face->num_sbit_strikes;
+
+
+ if ( strike )
+ {
+ for ( ; strike < strike_limit; strike++ )
+ {
+ TT_SBit_Range range = strike->sbit_ranges;
+ TT_SBit_Range range_limit = range + strike->num_ranges;
+
+
+ if ( range )
+ {
+ for ( ; range < range_limit; range++ )
+ {
+ /* release the glyph offsets and codes tables */
+ /* where appropriate */
+ FT_FREE( range->glyph_offsets );
+ FT_FREE( range->glyph_codes );
+ }
+ }
+ FT_FREE( strike->sbit_ranges );
+ strike->num_ranges = 0;
+ }
+ FT_FREE( face->sbit_strikes );
+ }
+ face->num_sbit_strikes = 0;
+ }
+
+
+ FT_LOCAL_DEF( FT_Error )
+ tt_face_set_sbit_strike( TT_Face face,
+ FT_Int x_ppem,
+ FT_Int y_ppem,
+ FT_ULong *astrike_index )
+ {
+ FT_ULong i;
+
+
+ if ( x_ppem < 0 || x_ppem > 255 ||
+ y_ppem < 1 || y_ppem > 255 )
+ return SFNT_Err_Invalid_PPem;
+
+ for ( i = 0; i < face->num_sbit_strikes; i++ )
+ {
+ if ( ( face->sbit_strikes[i].y_ppem == y_ppem ) &&
+ ( ( x_ppem == 0 ) ||
+ ( face->sbit_strikes[i].x_ppem == x_ppem ) ) )
+ {
+ *astrike_index = i;
+ return SFNT_Err_Ok;
+ }
+ }
+
+ return SFNT_Err_Invalid_PPem;
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* find_sbit_range */
+ /* */
+ /* <Description> */
+ /* Scans a given strike's ranges and return, for a given glyph */
+ /* index, the corresponding sbit range, and `EBDT' offset. */
+ /* */
+ /* <Input> */
+ /* glyph_index :: The glyph index. */
+ /* */
+ /* strike :: The source/current sbit strike. */
+ /* */
+ /* <Output> */
+ /* arange :: The sbit range containing the glyph index. */
+ /* */
+ /* aglyph_offset :: The offset of the glyph data in `EBDT' table. */
+ /* */
+ /* <Return> */
+ /* FreeType error code. 0 means the glyph index was found. */
+ /* */
+ static FT_Error
+ find_sbit_range( FT_UInt glyph_index,
+ TT_SBit_Strike strike,
+ TT_SBit_Range *arange,
+ FT_ULong *aglyph_offset )
+ {
+ TT_SBit_RangeRec *range, *range_limit;
+
+
+ /* check whether the glyph index is within this strike's */
+ /* glyph range */
+ if ( glyph_index < (FT_UInt)strike->start_glyph ||
+ glyph_index > (FT_UInt)strike->end_glyph )
+ goto Fail;
+
+ /* scan all ranges in strike */
+ range = strike->sbit_ranges;
+ range_limit = range + strike->num_ranges;
+ if ( !range )
+ goto Fail;
+
+ for ( ; range < range_limit; range++ )
+ {
+ if ( glyph_index >= (FT_UInt)range->first_glyph &&
+ glyph_index <= (FT_UInt)range->last_glyph )
+ {
+ FT_UShort delta = (FT_UShort)( glyph_index - range->first_glyph );
+
+
+ switch ( range->index_format )
+ {
+ case 1:
+ case 3:
+ *aglyph_offset = range->glyph_offsets[delta];
+ break;
+
+ case 2:
+ *aglyph_offset = range->image_offset +
+ range->image_size * delta;
+ break;
+
+ case 4:
+ case 5:
+ {
+ FT_ULong n;
+
+
+ for ( n = 0; n < range->num_glyphs; n++ )
+ {
+ if ( (FT_UInt)range->glyph_codes[n] == glyph_index )
+ {
+ if ( range->index_format == 4 )
+ *aglyph_offset = range->glyph_offsets[n];
+ else
+ *aglyph_offset = range->image_offset +
+ n * range->image_size;
+ goto Found;
+ }
+ }
+ }
+
+ /* fall-through */
+ default:
+ goto Fail;
+ }
+
+ Found:
+ /* return successfully! */
+ *arange = range;
+ return 0;
+ }
+ }
+
+ Fail:
+ *arange = 0;
+ *aglyph_offset = 0;
+
+ return SFNT_Err_Invalid_Argument;
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* find_sbit_image */
+ /* */
+ /* <Description> */
+ /* Checks whether an embedded bitmap (an `sbit') exists for a given */
+ /* glyph, at a given strike. */
+ /* */
+ /* <Input> */
+ /* face :: The target face object. */
+ /* */
+ /* glyph_index :: The glyph index. */
+ /* */
+ /* strike_index :: The current strike index. */
+ /* */
+ /* <Output> */
+ /* arange :: The SBit range containing the glyph index. */
+ /* */
+ /* astrike :: The SBit strike containing the glyph index. */
+ /* */
+ /* aglyph_offset :: The offset of the glyph data in `EBDT' table. */
+ /* */
+ /* <Return> */
+ /* FreeType error code. 0 means success. Returns */
+ /* SFNT_Err_Invalid_Argument if no sbit exists for the requested */
+ /* glyph. */
+ /* */
+ static FT_Error
+ find_sbit_image( TT_Face face,
+ FT_UInt glyph_index,
+ FT_ULong strike_index,
+ TT_SBit_Range *arange,
+ TT_SBit_Strike *astrike,
+ FT_ULong *aglyph_offset )
+ {
+ FT_Error error;
+ TT_SBit_Strike strike;
+
+
+ if ( !face->sbit_strikes ||
+ ( face->num_sbit_strikes <= strike_index ) )
+ goto Fail;
+
+ strike = &face->sbit_strikes[strike_index];
+
+ error = find_sbit_range( glyph_index, strike,
+ arange, aglyph_offset );
+ if ( error )
+ goto Fail;
+
+ *astrike = strike;
+
+ return SFNT_Err_Ok;
+
+ Fail:
+ /* no embedded bitmap for this glyph in face */
+ *arange = 0;
+ *astrike = 0;
+ *aglyph_offset = 0;
+
+ return SFNT_Err_Invalid_Argument;
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* load_sbit_metrics */
+ /* */
+ /* <Description> */
+ /* Gets the big metrics for a given SBit. */
+ /* */
+ /* <Input> */
+ /* stream :: The input stream. */
+ /* */
+ /* range :: The SBit range containing the glyph. */
+ /* */
+ /* <Output> */
+ /* big_metrics :: A big SBit metrics structure for the glyph. */
+ /* */
+ /* <Return> */
+ /* FreeType error code. 0 means success. */
+ /* */
+ /* <Note> */
+ /* The stream cursor must be positioned at the glyph's offset within */
+ /* the `EBDT' table before the call. */
+ /* */
+ /* If the image format uses variable metrics, the stream cursor is */
+ /* positioned just after the metrics header in the `EBDT' table on */
+ /* function exit. */
+ /* */
+ static FT_Error
+ load_sbit_metrics( FT_Stream stream,
+ TT_SBit_Range range,
+ TT_SBit_Metrics metrics )
+ {
+ FT_Error error = SFNT_Err_Ok;
+
+
+ switch ( range->image_format )
+ {
+ case 1:
+ case 2:
+ case 8:
+ /* variable small metrics */
+ {
+ TT_SBit_SmallMetricsRec smetrics;
+
+ const FT_Frame_Field sbit_small_metrics_fields[] =
+ {
+#undef FT_STRUCTURE
+#define FT_STRUCTURE TT_SBit_SmallMetricsRec
+
+ FT_FRAME_START( 5 ),
+ FT_FRAME_BYTE( height ),
+ FT_FRAME_BYTE( width ),
+ FT_FRAME_CHAR( bearingX ),
+ FT_FRAME_CHAR( bearingY ),
+ FT_FRAME_BYTE( advance ),
+ FT_FRAME_END
+ };
+
+
+ /* read small metrics */
+ if ( FT_STREAM_READ_FIELDS( sbit_small_metrics_fields, &smetrics ) )
+ goto Exit;
+
+ /* convert it to a big metrics */
+ metrics->height = smetrics.height;
+ metrics->width = smetrics.width;
+ metrics->horiBearingX = smetrics.bearingX;
+ metrics->horiBearingY = smetrics.bearingY;
+ metrics->horiAdvance = smetrics.advance;
+
+ /* these metrics are made up at a higher level when */
+ /* needed. */
+ metrics->vertBearingX = 0;
+ metrics->vertBearingY = 0;
+ metrics->vertAdvance = 0;
+ }
+ break;
+
+ case 6:
+ case 7:
+ case 9:
+ /* variable big metrics */
+ if ( FT_STREAM_READ_FIELDS( sbit_metrics_fields, metrics ) )
+ goto Exit;
+ break;
+
+ case 5:
+ default: /* constant metrics */
+ if ( range->index_format == 2 || range->index_format == 5 )
+ *metrics = range->metrics;
+ else
+ return SFNT_Err_Invalid_File_Format;
+ }
+
+ Exit:
+ return error;
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* crop_bitmap */
+ /* */
+ /* <Description> */
+ /* Crops a bitmap to its tightest bounding box, and adjusts its */
+ /* metrics. */
+ /* */
+ /* <InOut> */
+ /* map :: The bitmap. */
+ /* */
+ /* metrics :: The corresponding metrics structure. */
+ /* */
+ static void
+ crop_bitmap( FT_Bitmap* map,
+ TT_SBit_Metrics metrics )
+ {
+ /***********************************************************************/
+ /* */
+ /* In this situation, some bounding boxes of embedded bitmaps are too */
+ /* large. We need to crop it to a reasonable size. */
+ /* */
+ /* --------- */
+ /* | | ----- */
+ /* | *** | |***| */
+ /* | * | | * | */
+ /* | * | ------> | * | */
+ /* | * | | * | */
+ /* | * | | * | */
+ /* | *** | |***| */
+ /* --------- ----- */
+ /* */
+ /***********************************************************************/
+
+ FT_Int rows, count;
+ FT_Long line_len;
+ FT_Byte* line;
+
+
+ /***********************************************************************/
+ /* */
+ /* first of all, check the top-most lines of the bitmap, and remove */
+ /* them if they're empty. */
+ /* */
+ {
+ line = (FT_Byte*)map->buffer;
+ rows = map->rows;
+ line_len = map->pitch;
+
+
+ for ( count = 0; count < rows; count++ )
+ {
+ FT_Byte* cur = line;
+ FT_Byte* limit = line + line_len;
+
+
+ for ( ; cur < limit; cur++ )
+ if ( cur[0] )
+ goto Found_Top;
+
+ /* the current line was empty - skip to next one */
+ line = limit;
+ }
+
+ Found_Top:
+ /* check that we have at least one filled line */
+ if ( count >= rows )
+ goto Empty_Bitmap;
+
+ /* now, crop the empty upper lines */
+ if ( count > 0 )
+ {
+ line = (FT_Byte*)map->buffer;
+
+ FT_MEM_MOVE( line, line + count * line_len,
+ ( rows - count ) * line_len );
+
+ metrics->height = (FT_Byte)( metrics->height - count );
+ metrics->horiBearingY = (FT_Char)( metrics->horiBearingY - count );
+ metrics->vertBearingY = (FT_Char)( metrics->vertBearingY - count );
+
+ map->rows -= count;
+ rows -= count;
+ }
+ }
+
+ /***********************************************************************/
+ /* */
+ /* second, crop the lower lines */
+ /* */
+ {
+ line = (FT_Byte*)map->buffer + ( rows - 1 ) * line_len;
+
+ for ( count = 0; count < rows; count++ )
+ {
+ FT_Byte* cur = line;
+ FT_Byte* limit = line + line_len;
+
+
+ for ( ; cur < limit; cur++ )
+ if ( cur[0] )
+ goto Found_Bottom;
+
+ /* the current line was empty - skip to previous one */
+ line -= line_len;
+ }
+
+ Found_Bottom:
+ if ( count > 0 )
+ {
+ metrics->height = (FT_Byte)( metrics->height - count );
+ rows -= count;
+ map->rows -= count;
+ }
+ }
+
+ /***********************************************************************/
+ /* */
+ /* third, get rid of the space on the left side of the glyph */
+ /* */
+ do
+ {
+ FT_Byte* limit;
+
+
+ line = (FT_Byte*)map->buffer;
+ limit = line + rows * line_len;
+
+ for ( ; line < limit; line += line_len )
+ if ( line[0] & 0x80 )
+ goto Found_Left;
+
+ /* shift the whole glyph one pixel to the left */
+ line = (FT_Byte*)map->buffer;
+ limit = line + rows * line_len;
+
+ for ( ; line < limit; line += line_len )
+ {
+ FT_Int n, width = map->width;
+ FT_Byte old;
+ FT_Byte* cur = line;
+
+
+ old = (FT_Byte)(cur[0] << 1);
+ for ( n = 8; n < width; n += 8 )
+ {
+ FT_Byte val;
+
+
+ val = cur[1];
+ cur[0] = (FT_Byte)( old | ( val >> 7 ) );
+ old = (FT_Byte)( val << 1 );
+ cur++;
+ }
+ cur[0] = old;
+ }
+
+ map->width--;
+ metrics->horiBearingX++;
+ metrics->vertBearingX++;
+ metrics->width--;
+
+ } while ( map->width > 0 );
+
+ Found_Left:
+
+ /***********************************************************************/
+ /* */
+ /* finally, crop the bitmap width to get rid of the space on the right */
+ /* side of the glyph. */
+ /* */
+ do
+ {
+ FT_Int right = map->width - 1;
+ FT_Byte* limit;
+ FT_Byte mask;
+
+
+ line = (FT_Byte*)map->buffer + ( right >> 3 );
+ limit = line + rows * line_len;
+ mask = (FT_Byte)( 0x80 >> ( right & 7 ) );
+
+ for ( ; line < limit; line += line_len )
+ if ( line[0] & mask )
+ goto Found_Right;
+
+ /* crop the whole glyph to the right */
+ map->width--;
+ metrics->width--;
+
+ } while ( map->width > 0 );
+
+ Found_Right:
+ /* all right, the bitmap was cropped */
+ return;
+
+ Empty_Bitmap:
+ map->width = 0;
+ map->rows = 0;
+ map->pitch = 0;
+ map->pixel_mode = FT_PIXEL_MODE_MONO;
+ }
+
+
+ static FT_Error
+ Load_SBit_Single( FT_Bitmap* map,
+ FT_Int x_offset,
+ FT_Int y_offset,
+ FT_Int pix_bits,
+ FT_UShort image_format,
+ TT_SBit_Metrics metrics,
+ FT_Stream stream )
+ {
+ FT_Error error;
+
+
+ /* check that the source bitmap fits into the target pixmap */
+ if ( x_offset < 0 || x_offset + metrics->width > map->width ||
+ y_offset < 0 || y_offset + metrics->height > map->rows )
+ {
+ error = SFNT_Err_Invalid_Argument;
+
+ goto Exit;
+ }
+
+ {
+ FT_Int glyph_width = metrics->width;
+ FT_Int glyph_height = metrics->height;
+ FT_Int glyph_size;
+ FT_Int line_bits = pix_bits * glyph_width;
+ FT_Bool pad_bytes = 0;
+
+
+ /* compute size of glyph image */
+ switch ( image_format )
+ {
+ case 1: /* byte-padded formats */
+ case 6:
+ {
+ FT_Int line_length;
+
+
+ switch ( pix_bits )
+ {
+ case 1:
+ line_length = ( glyph_width + 7 ) >> 3;
+ break;
+ case 2:
+ line_length = ( glyph_width + 3 ) >> 2;
+ break;
+ case 4:
+ line_length = ( glyph_width + 1 ) >> 1;
+ break;
+ default:
+ line_length = glyph_width;
+ }
+
+ glyph_size = glyph_height * line_length;
+ pad_bytes = 1;
+ }
+ break;
+
+ case 2:
+ case 5:
+ case 7:
+ line_bits = glyph_width * pix_bits;
+ glyph_size = ( glyph_height * line_bits + 7 ) >> 3;
+ break;
+
+ default: /* invalid format */
+ return SFNT_Err_Invalid_File_Format;
+ }
+
+ /* Now read data and draw glyph into target pixmap */
+ if ( FT_FRAME_ENTER( glyph_size ) )
+ goto Exit;
+
+ /* don't forget to multiply `x_offset' by `map->pix_bits' as */
+ /* the sbit blitter doesn't make a difference between pixmap */
+ /* depths. */
+ blit_sbit( map, (FT_Byte*)stream->cursor, line_bits, pad_bytes,
+ x_offset * pix_bits, y_offset );
+
+ FT_FRAME_EXIT();
+ }
+
+ Exit:
+ return error;
+ }
+
+
+ static FT_Error
+ Load_SBit_Image( TT_SBit_Strike strike,
+ TT_SBit_Range range,
+ FT_ULong ebdt_pos,
+ FT_ULong glyph_offset,
+ FT_Bitmap* map,
+ FT_Int x_offset,
+ FT_Int y_offset,
+ FT_Stream stream,
+ TT_SBit_Metrics metrics )
+ {
+ FT_Memory memory = stream->memory;
+ FT_Error error;
+
+
+ /* place stream at beginning of glyph data and read metrics */
+ if ( FT_STREAM_SEEK( ebdt_pos + glyph_offset ) )
+ goto Exit;
+
+ error = load_sbit_metrics( stream, range, metrics );
+ if ( error )
+ goto Exit;
+
+ /* this function is recursive. At the top-level call, the */
+ /* field map.buffer is NULL. We thus begin by finding the */
+ /* dimensions of the higher-level glyph to allocate the */
+ /* final pixmap buffer */
+ if ( map->buffer == 0 )
+ {
+ FT_Long size;
+
+
+ map->width = metrics->width;
+ map->rows = metrics->height;
+
+ switch ( strike->bit_depth )
+ {
+ case 1:
+ map->pixel_mode = FT_PIXEL_MODE_MONO;
+ map->pitch = ( map->width + 7 ) >> 3;
+ break;
+
+ case 2:
+ map->pixel_mode = FT_PIXEL_MODE_GRAY2;
+ map->pitch = ( map->width + 3 ) >> 2;
+ break;
+
+ case 4:
+ map->pixel_mode = FT_PIXEL_MODE_GRAY4;
+ map->pitch = ( map->width + 1 ) >> 1;
+ break;
+
+ case 8:
+ map->pixel_mode = FT_PIXEL_MODE_GRAY;
+ map->pitch = map->width;
+ break;
+
+ default:
+ return SFNT_Err_Invalid_File_Format;
+ }
+
+ size = map->rows * map->pitch;
+
+ /* check that there is no empty image */
+ if ( size == 0 )
+ goto Exit; /* exit successfully! */
+
+ if ( FT_ALLOC( map->buffer, size ) )
+ goto Exit;
+ }
+
+ switch ( range->image_format )
+ {
+ case 1: /* single sbit image - load it */
+ case 2:
+ case 5:
+ case 6:
+ case 7:
+ return Load_SBit_Single( map, x_offset, y_offset, strike->bit_depth,
+ range->image_format, metrics, stream );
+
+ case 8: /* compound format */
+ FT_Stream_Skip( stream, 1L );
+ /* fallthrough */
+
+ case 9:
+ break;
+
+ default: /* invalid image format */
+ return SFNT_Err_Invalid_File_Format;
+ }
+
+ /* All right, we have a compound format. First of all, read */
+ /* the array of elements. */
+ {
+ TT_SBit_Component components;
+ TT_SBit_Component comp;
+ FT_UShort num_components, count;
+
+
+ if ( FT_READ_USHORT( num_components ) ||
+ FT_NEW_ARRAY( components, num_components ) )
+ goto Exit;
+
+ count = num_components;
+
+ if ( FT_FRAME_ENTER( 4L * num_components ) )
+ goto Fail_Memory;
+
+ for ( comp = components; count > 0; count--, comp++ )
+ {
+ comp->glyph_code = FT_GET_USHORT();
+ comp->x_offset = FT_GET_CHAR();
+ comp->y_offset = FT_GET_CHAR();
+ }
+
+ FT_FRAME_EXIT();
+
+ /* Now recursively load each element glyph */
+ count = num_components;
+ comp = components;
+ for ( ; count > 0; count--, comp++ )
+ {
+ TT_SBit_Range elem_range;
+ TT_SBit_MetricsRec elem_metrics;
+ FT_ULong elem_offset;
+
+
+ /* find the range for this element */
+ error = find_sbit_range( comp->glyph_code,
+ strike,
+ &elem_range,
+ &elem_offset );
+ if ( error )
+ goto Fail_Memory;
+
+ /* now load the element, recursively */
+ error = Load_SBit_Image( strike,
+ elem_range,
+ ebdt_pos,
+ elem_offset,
+ map,
+ x_offset + comp->x_offset,
+ y_offset + comp->y_offset,
+ stream,
+ &elem_metrics );
+ if ( error )
+ goto Fail_Memory;
+ }
+
+ Fail_Memory:
+ FT_FREE( components );
+ }
+
+ Exit:
+ return error;
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* tt_face_load_sbit_image */
+ /* */
+ /* <Description> */
+ /* Loads a given glyph sbit image from the font resource. This also */
+ /* returns its metrics. */
+ /* */
+ /* <Input> */
+ /* face :: The target face object. */
+ /* */
+ /* strike_index :: The current strike index. */
+ /* */
+ /* glyph_index :: The current glyph index. */
+ /* */
+ /* load_flags :: The glyph load flags (the code checks for the flag */
+ /* FT_LOAD_CROP_BITMAP). */
+ /* */
+ /* stream :: The input stream. */
+ /* */
+ /* <Output> */
+ /* map :: The target pixmap. */
+ /* */
+ /* metrics :: A big sbit metrics structure for the glyph image. */
+ /* */
+ /* <Return> */
+ /* FreeType error code. 0 means success. Returns an error if no */
+ /* glyph sbit exists for the index. */
+ /* */
+ /* <Note> */
+ /* The `map.buffer' field is always freed before the glyph is loaded. */
+ /* */
+ FT_LOCAL_DEF( FT_Error )
+ tt_face_load_sbit_image( TT_Face face,
+ FT_ULong strike_index,
+ FT_UInt glyph_index,
+ FT_UInt load_flags,
+ FT_Stream stream,
+ FT_Bitmap *map,
+ TT_SBit_MetricsRec *metrics )
+ {
+ FT_Error error;
+ FT_Memory memory = stream->memory;
+ FT_ULong ebdt_pos, glyph_offset;
+
+ TT_SBit_Strike strike;
+ TT_SBit_Range range;
+
+
+ /* Check whether there is a glyph sbit for the current index */
+ error = find_sbit_image( face, glyph_index, strike_index,
+ &range, &strike, &glyph_offset );
+ if ( error )
+ goto Exit;
+
+ /* now, find the location of the `EBDT' table in */
+ /* the font file */
+ error = face->goto_table( face, TTAG_EBDT, stream, 0 );
+ if ( error )
+ error = face->goto_table( face, TTAG_bdat, stream, 0 );
+ if (error)
+ goto Exit;
+
+ ebdt_pos = FT_STREAM_POS();
+
+ /* clear the bitmap & load the bitmap */
+ if ( face->root.glyph->flags & FT_GLYPH_OWN_BITMAP )
+ FT_FREE( map->buffer );
+
+ map->rows = map->pitch = map->width = 0;
+
+ error = Load_SBit_Image( strike, range, ebdt_pos, glyph_offset,
+ map, 0, 0, stream, metrics );
+ if ( error )
+ goto Exit;
+
+ /* the glyph slot owns this bitmap buffer */
+ face->root.glyph->flags |= FT_GLYPH_OWN_BITMAP;
+
+ /* setup vertical metrics if needed */
+ if ( strike->flags & 1 )
+ {
+ /* in case of a horizontal strike only */
+ FT_Int advance;
+
+
+ advance = strike->hori.ascender - strike->hori.descender;
+
+ /* some heuristic values */
+
+ metrics->vertBearingX = (FT_Char)(-metrics->width / 2 );
+ metrics->vertBearingY = (FT_Char)( advance / 10 );
+ metrics->vertAdvance = (FT_Char)( advance * 12 / 10 );
+ }
+
+ /* Crop the bitmap now, unless specified otherwise */
+ if ( load_flags & FT_LOAD_CROP_BITMAP )
+ crop_bitmap( map, metrics );
+
+ Exit:
+ return error;
+ }
+
+
+/* END */
--- /dev/null
+++ b/libfreetype/ttsbit.h
@@ -1,0 +1,59 @@
+/***************************************************************************/
+/* */
+/* ttsbit.h */
+/* */
+/* TrueType and OpenType embedded bitmap support (specification). */
+/* */
+/* Copyright 1996-2001, 2002 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+
+#ifndef __TTSBIT_H__
+#define __TTSBIT_H__
+
+
+#include <ft2build.h>
+#include "ttload.h"
+
+
+FT_BEGIN_HEADER
+
+
+ FT_LOCAL( FT_Error )
+ tt_face_load_sbit_strikes( TT_Face face,
+ FT_Stream stream );
+
+ FT_LOCAL( void )
+ tt_face_free_sbit_strikes( TT_Face face );
+
+
+ FT_LOCAL( FT_Error )
+ tt_face_set_sbit_strike( TT_Face face,
+ FT_Int x_ppem,
+ FT_Int y_ppem,
+ FT_ULong *astrike_index );
+
+ FT_LOCAL( FT_Error )
+ tt_face_load_sbit_image( TT_Face face,
+ FT_ULong strike_index,
+ FT_UInt glyph_index,
+ FT_UInt load_flags,
+ FT_Stream stream,
+ FT_Bitmap *map,
+ TT_SBit_MetricsRec *metrics );
+
+
+FT_END_HEADER
+
+#endif /* __TTSBIT_H__ */
+
+
+/* END */
--- /dev/null
+++ b/libfreetype/type1.c
@@ -1,0 +1,33 @@
+/***************************************************************************/
+/* */
+/* type1.c */
+/* */
+/* FreeType Type 1 driver component (body only). */
+/* */
+/* Copyright 1996-2001 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+
+#define FT_MAKE_OPTION_SINGLE_OBJECT
+
+#include <ft2build.h>
+#include "t1parse.c"
+#include "t1load.c"
+#include "t1objs.c"
+#include "t1driver.c"
+#include "t1gload.c"
+
+#ifndef T1_CONFIG_OPTION_NO_AFM
+#include "t1afm.c"
+#endif
+
+
+/* END */
--- /dev/null
+++ b/libfreetype/type1cid.c
@@ -1,0 +1,29 @@
+/***************************************************************************/
+/* */
+/* type1cid.c */
+/* */
+/* FreeType OpenType driver component (body only). */
+/* */
+/* Copyright 1996-2001 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+
+#define FT_MAKE_OPTION_SINGLE_OBJECT
+
+#include <ft2build.h>
+#include "cidparse.c"
+#include "cidload.c"
+#include "cidobjs.c"
+#include "cidriver.c"
+#include "cidgload.c"
+
+
+/* END */
--- /dev/null
+++ b/libfreetype/type42.c
@@ -1,0 +1,25 @@
+/***************************************************************************/
+/* */
+/* type42.c */
+/* */
+/* FreeType Type 42 driver component. */
+/* */
+/* Copyright 2002 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+#define FT_MAKE_OPTION_SINGLE_OBJECT
+
+#include <ft2build.h>
+#include "t42objs.c"
+#include "t42parse.c"
+#include "t42drivr.c"
+
+/* END */
--- /dev/null
+++ b/libfreetype/winfnt.c
@@ -1,0 +1,691 @@
+/***************************************************************************/
+/* */
+/* winfnt.c */
+/* */
+/* FreeType font driver for Windows FNT/FON files */
+/* */
+/* Copyright 1996-2001, 2002 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+
+#include <ft2build.h>
+#include FT_INTERNAL_DEBUG_H
+#include FT_INTERNAL_STREAM_H
+#include FT_INTERNAL_OBJECTS_H
+#include FT_INTERNAL_FNT_TYPES_H
+
+#include "winfnt.h"
+
+#include "fnterrs.h"
+
+
+ /*************************************************************************/
+ /* */
+ /* The macro FT_COMPONENT is used in trace mode. It is an implicit */
+ /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log */
+ /* messages during execution. */
+ /* */
+#undef FT_COMPONENT
+#define FT_COMPONENT trace_winfnt
+
+
+ static
+ const FT_Frame_Field winmz_header_fields[] =
+ {
+#undef FT_STRUCTURE
+#define FT_STRUCTURE WinMZ_HeaderRec
+
+ FT_FRAME_START( 64 ),
+ FT_FRAME_USHORT_LE ( magic ),
+ FT_FRAME_SKIP_BYTES( 29 * 2 ),
+ FT_FRAME_ULONG_LE ( lfanew ),
+ FT_FRAME_END
+ };
+
+ static
+ const FT_Frame_Field winne_header_fields[] =
+ {
+#undef FT_STRUCTURE
+#define FT_STRUCTURE WinNE_HeaderRec
+
+ FT_FRAME_START( 40 ),
+ FT_FRAME_USHORT_LE ( magic ),
+ FT_FRAME_SKIP_BYTES( 34 ),
+ FT_FRAME_USHORT_LE ( resource_tab_offset ),
+ FT_FRAME_USHORT_LE ( rname_tab_offset ),
+ FT_FRAME_END
+ };
+
+ static
+ const FT_Frame_Field winfnt_header_fields[] =
+ {
+#undef FT_STRUCTURE
+#define FT_STRUCTURE WinFNT_HeaderRec
+
+ FT_FRAME_START( 134 ),
+ FT_FRAME_USHORT_LE( version ),
+ FT_FRAME_ULONG_LE ( file_size ),
+ FT_FRAME_BYTES ( copyright, 60 ),
+ FT_FRAME_USHORT_LE( file_type ),
+ FT_FRAME_USHORT_LE( nominal_point_size ),
+ FT_FRAME_USHORT_LE( vertical_resolution ),
+ FT_FRAME_USHORT_LE( horizontal_resolution ),
+ FT_FRAME_USHORT_LE( ascent ),
+ FT_FRAME_USHORT_LE( internal_leading ),
+ FT_FRAME_USHORT_LE( external_leading ),
+ FT_FRAME_BYTE ( italic ),
+ FT_FRAME_BYTE ( underline ),
+ FT_FRAME_BYTE ( strike_out ),
+ FT_FRAME_USHORT_LE( weight ),
+ FT_FRAME_BYTE ( charset ),
+ FT_FRAME_USHORT_LE( pixel_width ),
+ FT_FRAME_USHORT_LE( pixel_height ),
+ FT_FRAME_BYTE ( pitch_and_family ),
+ FT_FRAME_USHORT_LE( avg_width ),
+ FT_FRAME_USHORT_LE( max_width ),
+ FT_FRAME_BYTE ( first_char ),
+ FT_FRAME_BYTE ( last_char ),
+ FT_FRAME_BYTE ( default_char ),
+ FT_FRAME_BYTE ( break_char ),
+ FT_FRAME_USHORT_LE( bytes_per_row ),
+ FT_FRAME_ULONG_LE ( device_offset ),
+ FT_FRAME_ULONG_LE ( face_name_offset ),
+ FT_FRAME_ULONG_LE ( bits_pointer ),
+ FT_FRAME_ULONG_LE ( bits_offset ),
+ FT_FRAME_BYTE ( reserved ),
+ FT_FRAME_ULONG_LE ( flags ),
+ FT_FRAME_USHORT_LE( A_space ),
+ FT_FRAME_USHORT_LE( B_space ),
+ FT_FRAME_USHORT_LE( C_space ),
+ FT_FRAME_USHORT_LE( color_table_offset ),
+ FT_FRAME_BYTES ( reserved, 4 ),
+ FT_FRAME_END
+ };
+
+
+ static void
+ fnt_font_done( FNT_Font font,
+ FT_Stream stream )
+ {
+ if ( font->fnt_frame )
+ FT_FRAME_RELEASE( font->fnt_frame );
+
+ font->fnt_size = 0;
+ font->fnt_frame = 0;
+ }
+
+
+ static FT_Error
+ fnt_font_load( FNT_Font font,
+ FT_Stream stream )
+ {
+ FT_Error error;
+ WinFNT_Header header = &font->header;
+
+
+ /* first of all, read the FNT header */
+ if ( FT_STREAM_SEEK( font->offset ) ||
+ FT_STREAM_READ_FIELDS( winfnt_header_fields, header ) )
+ goto Exit;
+
+ /* check header */
+ if ( header->version != 0x200 &&
+ header->version != 0x300 )
+ {
+ FT_TRACE2(( "[not a valid FNT file]\n" ));
+ error = FNT_Err_Unknown_File_Format;
+ goto Exit;
+ }
+
+ if ( header->file_type & 1 )
+ {
+ FT_TRACE2(( "[can't handle vector FNT fonts]\n" ));
+ error = FNT_Err_Unknown_File_Format;
+ goto Exit;
+ }
+
+ /* small fixup -- some fonts have the `pixel_width' field set to 0 */
+ if ( header->pixel_width == 0 )
+ header->pixel_width = header->pixel_height;
+
+ /* this is a FNT file/table, we now extract its frame */
+ if ( FT_STREAM_SEEK( font->offset ) ||
+ FT_FRAME_EXTRACT( header->file_size, font->fnt_frame ) )
+ goto Exit;
+
+ Exit:
+ return error;
+ }
+
+
+ static void
+ fnt_face_done_fonts( FNT_Face face )
+ {
+ FT_Memory memory = FT_FACE( face )->memory;
+ FT_Stream stream = FT_FACE( face )->stream;
+ FNT_Font cur = face->fonts;
+ FNT_Font limit = cur + face->num_fonts;
+
+
+ for ( ; cur < limit; cur++ )
+ fnt_font_done( cur, stream );
+
+ FT_FREE( face->fonts );
+ face->num_fonts = 0;
+ }
+
+
+ static FT_Error
+ fnt_face_get_dll_fonts( FNT_Face face )
+ {
+ FT_Error error;
+ FT_Stream stream = FT_FACE( face )->stream;
+ FT_Memory memory = FT_FACE( face )->memory;
+ WinMZ_HeaderRec mz_header;
+
+
+ face->fonts = 0;
+ face->num_fonts = 0;
+
+ /* does it begin with a MZ header? */
+ if ( FT_STREAM_SEEK( 0 ) ||
+ FT_STREAM_READ_FIELDS( winmz_header_fields, &mz_header ) )
+ goto Exit;
+
+ error = FNT_Err_Unknown_File_Format;
+ if ( mz_header.magic == WINFNT_MZ_MAGIC )
+ {
+ /* yes, now look for a NE header in the file */
+ WinNE_HeaderRec ne_header;
+
+
+ if ( FT_STREAM_SEEK( mz_header.lfanew ) ||
+ FT_STREAM_READ_FIELDS( winne_header_fields, &ne_header ) )
+ goto Exit;
+
+ error = FNT_Err_Unknown_File_Format;
+ if ( ne_header.magic == WINFNT_NE_MAGIC )
+ {
+ /* good, now look in the resource table for each FNT resource */
+ FT_ULong res_offset = mz_header.lfanew +
+ ne_header.resource_tab_offset;
+
+ FT_UShort size_shift;
+ FT_UShort font_count = 0;
+ FT_ULong font_offset = 0;
+
+
+ if ( FT_STREAM_SEEK( res_offset ) ||
+ FT_FRAME_ENTER( ne_header.rname_tab_offset -
+ ne_header.resource_tab_offset ) )
+ goto Exit;
+
+ size_shift = FT_GET_USHORT_LE();
+
+ for (;;)
+ {
+ FT_UShort type_id, count;
+
+
+ type_id = FT_GET_USHORT_LE();
+ if ( !type_id )
+ break;
+
+ count = FT_GET_USHORT_LE();
+
+ if ( type_id == 0x8008 )
+ {
+ font_count = count;
+ font_offset = (FT_ULong)( FT_STREAM_POS() + 4 +
+ ( stream->cursor - stream->limit ) );
+ break;
+ }
+
+ stream->cursor += 4 + count * 12;
+ }
+ FT_FRAME_EXIT();
+
+ if ( !font_count || !font_offset )
+ {
+ FT_TRACE2(( "this file doesn't contain any FNT resources!\n" ));
+ error = FNT_Err_Unknown_File_Format;
+ goto Exit;
+ }
+
+ if ( FT_STREAM_SEEK( font_offset ) ||
+ FT_NEW_ARRAY( face->fonts, font_count ) )
+ goto Exit;
+
+ face->num_fonts = font_count;
+
+ if ( FT_FRAME_ENTER( (FT_Long)font_count * 12 ) )
+ goto Exit;
+
+ /* now read the offset and position of each FNT font */
+ {
+ FNT_Font cur = face->fonts;
+ FNT_Font limit = cur + font_count;
+
+
+ for ( ; cur < limit; cur++ )
+ {
+ cur->offset = (FT_ULong)FT_GET_USHORT_LE() << size_shift;
+ cur->fnt_size = (FT_ULong)FT_GET_USHORT_LE() << size_shift;
+ cur->size_shift = size_shift;
+ stream->cursor += 8;
+ }
+ }
+ FT_FRAME_EXIT();
+
+ /* finally, try to load each font there */
+ {
+ FNT_Font cur = face->fonts;
+ FNT_Font limit = cur + font_count;
+
+
+ for ( ; cur < limit; cur++ )
+ {
+ error = fnt_font_load( cur, stream );
+ if ( error )
+ goto Fail;
+ }
+ }
+ }
+ }
+
+ Fail:
+ if ( error )
+ fnt_face_done_fonts( face );
+
+ Exit:
+ return error;
+ }
+
+
+
+ typedef struct FNT_CMapRec_
+ {
+ FT_CMapRec cmap;
+ FT_UInt32 first;
+ FT_UInt32 count;
+
+ } FNT_CMapRec, *FNT_CMap;
+
+
+ static FT_Error
+ fnt_cmap_init( FNT_CMap cmap )
+ {
+ FNT_Face face = (FNT_Face)FT_CMAP_FACE( cmap );
+ FNT_Font font = face->fonts;
+
+
+ cmap->first = (FT_UInt32) font->header.first_char;
+ cmap->count = (FT_UInt32)( font->header.last_char - cmap->first + 1 );
+
+ return 0;
+ }
+
+
+ static FT_UInt
+ fnt_cmap_char_index( FNT_CMap cmap,
+ FT_UInt32 char_code )
+ {
+ FT_UInt gindex = 0;
+
+
+ char_code -= cmap->first;
+ if ( char_code < cmap->count )
+ gindex = char_code + 1;
+
+ return gindex;
+ }
+
+
+ static FT_UInt
+ fnt_cmap_char_next( FNT_CMap cmap,
+ FT_UInt32 *pchar_code )
+ {
+ FT_UInt gindex = 0;
+ FT_UInt32 result = 0;
+ FT_UInt32 char_code = *pchar_code + 1;
+
+
+ if ( char_code <= cmap->first )
+ {
+ result = cmap->first;
+ gindex = 1;
+ }
+ else
+ {
+ char_code -= cmap->first;
+ if ( char_code < cmap->count )
+ {
+ result = cmap->first + char_code;
+ gindex = char_code + 1;
+ }
+ }
+
+ *pchar_code = result;
+ return gindex;
+ }
+
+
+ static FT_CMap_ClassRec fnt_cmap_class_rec =
+ {
+ sizeof ( FNT_CMapRec ),
+
+ (FT_CMap_InitFunc) fnt_cmap_init,
+ (FT_CMap_DoneFunc) NULL,
+ (FT_CMap_CharIndexFunc)fnt_cmap_char_index,
+ (FT_CMap_CharNextFunc) fnt_cmap_char_next
+ };
+
+ static FT_CMap_Class fnt_cmap_class = &fnt_cmap_class_rec;
+
+
+
+ static void
+ FNT_Face_Done( FNT_Face face )
+ {
+ FT_Memory memory = FT_FACE_MEMORY( face );
+
+
+ fnt_face_done_fonts( face );
+
+ FT_FREE( face->root.available_sizes );
+ face->root.num_fixed_sizes = 0;
+ }
+
+
+ static FT_Error
+ FNT_Face_Init( FT_Stream stream,
+ FNT_Face face,
+ FT_Int face_index,
+ FT_Int num_params,
+ FT_Parameter* params )
+ {
+ FT_Error error;
+ FT_Memory memory = FT_FACE_MEMORY( face );
+
+ FT_UNUSED( num_params );
+ FT_UNUSED( params );
+ FT_UNUSED( face_index );
+
+
+ /* try to load several fonts from a DLL */
+ error = fnt_face_get_dll_fonts( face );
+ if ( error )
+ {
+ /* this didn't work, now try to load a single FNT font */
+ FNT_Font font;
+
+
+ if ( FT_NEW( face->fonts ) )
+ goto Exit;
+
+ face->num_fonts = 1;
+ font = face->fonts;
+
+ font->offset = 0;
+ font->fnt_size = stream->size;
+
+ error = fnt_font_load( font, stream );
+ if ( error )
+ goto Fail;
+ }
+
+ /* all right, one or more fonts were loaded; we now need to */
+ /* fill the root FT_Face fields with relevant information */
+ {
+ FT_Face root = FT_FACE( face );
+ FNT_Font fonts = face->fonts;
+ FNT_Font limit = fonts + face->num_fonts;
+ FNT_Font cur;
+
+
+ root->num_faces = 1;
+ root->face_flags = FT_FACE_FLAG_FIXED_SIZES |
+ FT_FACE_FLAG_HORIZONTAL;
+
+ if ( fonts->header.avg_width == fonts->header.max_width )
+ root->face_flags |= FT_FACE_FLAG_FIXED_WIDTH;
+
+ if ( fonts->header.italic )
+ root->style_flags |= FT_STYLE_FLAG_ITALIC;
+
+ if ( fonts->header.weight >= 800 )
+ root->style_flags |= FT_STYLE_FLAG_BOLD;
+
+ /* Setup the `fixed_sizes' array */
+ if ( FT_NEW_ARRAY( root->available_sizes, face->num_fonts ) )
+ goto Fail;
+
+ root->num_fixed_sizes = face->num_fonts;
+
+ {
+ FT_Bitmap_Size* size = root->available_sizes;
+
+
+ for ( cur = fonts; cur < limit; cur++, size++ )
+ {
+ size->width = cur->header.pixel_width;
+ size->height = cur->header.pixel_height;
+ }
+ }
+
+ {
+ FT_CharMapRec charmap;
+
+ charmap.encoding = FT_ENCODING_UNICODE;
+ charmap.platform_id = 3;
+ charmap.encoding_id = 1;
+ charmap.face = root;
+
+ error = FT_CMap_New( fnt_cmap_class,
+ NULL,
+ &charmap,
+ NULL );
+ if ( error )
+ goto Fail;
+
+ /* Select default charmap */
+ if ( root->num_charmaps )
+ root->charmap = root->charmaps[0];
+ }
+
+ /* setup remaining flags */
+ root->num_glyphs = fonts->header.last_char -
+ fonts->header.first_char + 1;
+
+ root->family_name = (FT_String*)fonts->fnt_frame +
+ fonts->header.face_name_offset;
+ root->style_name = (char *)"Regular";
+
+ if ( root->style_flags & FT_STYLE_FLAG_BOLD )
+ {
+ if ( root->style_flags & FT_STYLE_FLAG_ITALIC )
+ root->style_name = (char *)"Bold Italic";
+ else
+ root->style_name = (char *)"Bold";
+ }
+ else if ( root->style_flags & FT_STYLE_FLAG_ITALIC )
+ root->style_name = (char *)"Italic";
+ }
+
+ Fail:
+ if ( error )
+ FNT_Face_Done( face );
+
+ Exit:
+ return error;
+ }
+
+
+ static FT_Error
+ FNT_Size_Set_Pixels( FNT_Size size )
+ {
+ /* look up a font corresponding to the current pixel size */
+ FNT_Face face = (FNT_Face)FT_SIZE_FACE( size );
+ FNT_Font cur = face->fonts;
+ FNT_Font limit = cur + face->num_fonts;
+
+
+ size->font = 0;
+ for ( ; cur < limit; cur++ )
+ {
+ /* we only compare the character height, as fonts used some strange */
+ /* values */
+ if ( cur->header.pixel_height == size->root.metrics.y_ppem )
+ {
+ size->font = cur;
+
+ size->root.metrics.ascender = cur->header.ascent * 64;
+ size->root.metrics.descender = ( cur->header.pixel_height -
+ cur->header.ascent ) * 64;
+ size->root.metrics.height = cur->header.pixel_height * 64;
+ break;
+ }
+ }
+
+ return ( size->font ? FNT_Err_Ok : FNT_Err_Invalid_Pixel_Size );
+ }
+
+
+ static FT_Error
+ FNT_Load_Glyph( FT_GlyphSlot slot,
+ FNT_Size size,
+ FT_UInt glyph_index,
+ FT_Int32 load_flags )
+ {
+ FNT_Font font = size->font;
+ FT_Error error = 0;
+ FT_Byte* p;
+ FT_Int len;
+ FT_Bitmap* bitmap = &slot->bitmap;
+ FT_ULong offset;
+ FT_Bool new_format;
+
+ FT_UNUSED( slot );
+ FT_UNUSED( load_flags );
+
+
+ if ( !font )
+ {
+ error = FNT_Err_Invalid_Argument;
+ goto Exit;
+ }
+
+ if ( glyph_index > 0 )
+ glyph_index--;
+ else
+ glyph_index = font->header.default_char - font->header.first_char;
+
+ new_format = FT_BOOL( font->header.version == 0x300 );
+ len = new_format ? 6 : 4;
+
+ /* jump to glyph entry */
+ p = font->fnt_frame + 118 + len * glyph_index;
+
+ bitmap->width = FT_NEXT_SHORT_LE( p );
+
+ if ( new_format )
+ offset = FT_NEXT_ULONG_LE( p );
+ else
+ offset = FT_NEXT_USHORT_LE( p );
+
+ /* jump to glyph data */
+ p = font->fnt_frame + /* font->header.bits_offset */ + offset;
+
+ /* allocate and build bitmap */
+ {
+ FT_Memory memory = FT_FACE_MEMORY( slot->face );
+ FT_Int pitch = ( bitmap->width + 7 ) >> 3;
+ FT_Byte* column;
+ FT_Byte* write;
+
+
+ bitmap->pitch = pitch;
+ bitmap->rows = font->header.pixel_height;
+ bitmap->pixel_mode = FT_PIXEL_MODE_MONO;
+
+ if ( FT_ALLOC( bitmap->buffer, pitch * bitmap->rows ) )
+ goto Exit;
+
+ column = (FT_Byte*)bitmap->buffer;
+
+ for ( ; pitch > 0; pitch--, column++ )
+ {
+ FT_Byte* limit = p + bitmap->rows;
+
+
+ for ( write = column; p < limit; p++, write += bitmap->pitch )
+ write[0] = p[0];
+ }
+ }
+
+ slot->flags = FT_GLYPH_OWN_BITMAP;
+ slot->bitmap_left = 0;
+ slot->bitmap_top = font->header.ascent;
+ slot->format = FT_GLYPH_FORMAT_BITMAP;
+
+ /* now set up metrics */
+ slot->metrics.horiAdvance = bitmap->width << 6;
+ slot->metrics.horiBearingX = 0;
+ slot->metrics.horiBearingY = slot->bitmap_top << 6;
+
+ slot->linearHoriAdvance = (FT_Fixed)bitmap->width << 16;
+ slot->format = FT_GLYPH_FORMAT_BITMAP;
+
+ Exit:
+ return error;
+ }
+
+
+ FT_CALLBACK_TABLE_DEF
+ const FT_Driver_ClassRec winfnt_driver_class =
+ {
+ {
+ ft_module_font_driver,
+ sizeof ( FT_DriverRec ),
+
+ "winfonts",
+ 0x10000L,
+ 0x20000L,
+
+ 0,
+
+ (FT_Module_Constructor)0,
+ (FT_Module_Destructor) 0,
+ (FT_Module_Requester) 0
+ },
+
+ sizeof( FNT_FaceRec ),
+ sizeof( FNT_SizeRec ),
+ sizeof( FT_GlyphSlotRec ),
+
+ (FT_Face_InitFunc) FNT_Face_Init,
+ (FT_Face_DoneFunc) FNT_Face_Done,
+ (FT_Size_InitFunc) 0,
+ (FT_Size_DoneFunc) 0,
+ (FT_Slot_InitFunc) 0,
+ (FT_Slot_DoneFunc) 0,
+
+ (FT_Size_ResetPointsFunc) FNT_Size_Set_Pixels,
+ (FT_Size_ResetPixelsFunc) FNT_Size_Set_Pixels,
+ (FT_Slot_LoadFunc) FNT_Load_Glyph,
+
+ (FT_Face_GetKerningFunc) 0,
+ (FT_Face_AttachFunc) 0,
+ (FT_Face_GetAdvancesFunc) 0
+ };
+
+
+/* END */
--- /dev/null
+++ b/libfreetype/winfnt.h
@@ -1,0 +1,39 @@
+/***************************************************************************/
+/* */
+/* winfnt.h */
+/* */
+/* FreeType font driver for Windows FNT/FON files */
+/* */
+/* Copyright 1996-2001, 2002 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+
+#ifndef __WINFNT_H__
+#define __WINFNT_H__
+
+
+#include <ft2build.h>
+#include FT_INTERNAL_DRIVER_H
+
+
+FT_BEGIN_HEADER
+
+
+ FT_EXPORT_VAR( const FT_Driver_ClassRec ) winfnt_driver_class;
+
+
+FT_END_HEADER
+
+
+#endif /* __WINFNT_H__ */
+
+
+/* END */
--- /dev/null
+++ b/libfreetype/zconf.h
@@ -1,0 +1,275 @@
+/* zconf.h -- configuration of the zlib compression library
+ * Copyright (C) 1995-2002 Jean-loup Gailly.
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/* @(#) $Id: zconf.h,v 1.2 2002/11/06 22:32:54 davidT Exp $ */
+
+#ifndef _ZCONF_H
+#define _ZCONF_H
+
+/*
+ * If you *really* need a unique prefix for all types and library functions,
+ * compile with -DZ_PREFIX. The "standard" zlib should be compiled without it.
+ */
+#ifdef Z_PREFIX
+# define deflateInit_ z_deflateInit_
+# define deflate z_deflate
+# define deflateEnd z_deflateEnd
+# define inflateInit_ z_inflateInit_
+# define inflate z_inflate
+# define inflateEnd z_inflateEnd
+# define deflateInit2_ z_deflateInit2_
+# define deflateSetDictionary z_deflateSetDictionary
+# define deflateCopy z_deflateCopy
+# define deflateReset z_deflateReset
+# define deflateParams z_deflateParams
+# define inflateInit2_ z_inflateInit2_
+# define inflateSetDictionary z_inflateSetDictionary
+# define inflateSync z_inflateSync
+# define inflateSyncPoint z_inflateSyncPoint
+# define inflateReset z_inflateReset
+# define compress z_compress
+# define compress2 z_compress2
+# define uncompress z_uncompress
+# define adler32 z_adler32
+# define crc32 z_crc32
+# define get_crc_table z_get_crc_table
+
+# define Byte z_Byte
+# define uInt z_uInt
+# define uLong z_uLong
+# define Bytef z_Bytef
+# define charf z_charf
+# define intf z_intf
+# define uIntf z_uIntf
+# define uLongf z_uLongf
+# define voidpf z_voidpf
+# define voidp z_voidp
+#endif
+
+#if (defined(_WIN32) || defined(__WIN32__)) && !defined(WIN32)
+# define WIN32
+#endif
+#if defined(__GNUC__) || defined(WIN32) || defined(__386__) || defined(i386)
+# ifndef __32BIT__
+# define __32BIT__
+# endif
+#endif
+#if defined(__MSDOS__) && !defined(MSDOS)
+# define MSDOS
+#endif
+
+/*
+ * Compile with -DMAXSEG_64K if the alloc function cannot allocate more
+ * than 64k bytes at a time (needed on systems with 16-bit int).
+ */
+#if defined(MSDOS) && !defined(__32BIT__)
+# define MAXSEG_64K
+#endif
+#ifdef MSDOS
+# define UNALIGNED_OK
+#endif
+
+#if (defined(MSDOS) || defined(_WINDOWS) || defined(WIN32)) && !defined(STDC)
+# define STDC
+#endif
+#if defined(__STDC__) || defined(__cplusplus) || defined(__OS2__)
+# ifndef STDC
+# define STDC
+# endif
+#endif
+
+#ifndef STDC
+# ifndef const /* cannot use !defined(STDC) && !defined(const) on Mac */
+# define const
+# endif
+#endif
+
+/* Some Mac compilers merge all .h files incorrectly: */
+#if defined(__MWERKS__) || defined(applec) ||defined(THINK_C) ||defined(__SC__)
+# define NO_DUMMY_DECL
+#endif
+
+/* Old Borland C incorrectly complains about missing returns: */
+#if defined(__BORLANDC__) && (__BORLANDC__ < 0x500)
+# define NEED_DUMMY_RETURN
+#endif
+
+
+/* Maximum value for memLevel in deflateInit2 */
+#ifndef MAX_MEM_LEVEL
+# ifdef MAXSEG_64K
+# define MAX_MEM_LEVEL 8
+# else
+# define MAX_MEM_LEVEL 9
+# endif
+#endif
+
+/* Maximum value for windowBits in deflateInit2 and inflateInit2.
+ * WARNING: reducing MAX_WBITS makes minigzip unable to extract .gz files
+ * created by gzip. (Files created by minigzip can still be extracted by
+ * gzip.)
+ */
+#ifndef MAX_WBITS
+# define MAX_WBITS 15 /* 32K LZ77 window */
+#endif
+
+/* The memory requirements for deflate are (in bytes):
+ (1 << (windowBits+2)) + (1 << (memLevel+9))
+ that is: 128K for windowBits=15 + 128K for memLevel = 8 (default values)
+ plus a few kilobytes for small objects. For example, if you want to reduce
+ the default memory requirements from 256K to 128K, compile with
+ make CFLAGS="-O -DMAX_WBITS=14 -DMAX_MEM_LEVEL=7"
+ Of course this will generally degrade compression (there's no free lunch).
+
+ The memory requirements for inflate are (in bytes) 1 << windowBits
+ that is, 32K for windowBits=15 (default value) plus a few kilobytes
+ for small objects.
+*/
+
+ /* Type declarations */
+
+#ifndef OF /* function prototypes */
+# ifdef STDC
+# define OF(args) args
+# else
+# define OF(args) ()
+# endif
+#endif
+
+/* The following definitions for FAR are needed only for MSDOS mixed
+ * model programming (small or medium model with some far allocations).
+ * This was tested only with MSC; for other MSDOS compilers you may have
+ * to define NO_MEMCPY in zutil.h. If you don't need the mixed model,
+ * just define FAR to be empty.
+ */
+#if (defined(M_I86SM) || defined(M_I86MM)) && !defined(__32BIT__)
+ /* MSC small or medium model */
+# define SMALL_MEDIUM
+# ifdef _MSC_VER
+# define FAR _far
+# else
+# define FAR far
+# endif
+#endif
+#if defined(__BORLANDC__) && (defined(__SMALL__) || defined(__MEDIUM__))
+# ifndef __32BIT__
+# define SMALL_MEDIUM
+# define FAR _far
+# endif
+#endif
+
+/* Compile with -DZLIB_DLL for Windows DLL support */
+#if defined(ZLIB_DLL)
+# if defined(_WINDOWS) || defined(WINDOWS)
+# ifdef FAR
+# undef FAR
+# endif
+# include <windows.h>
+# define ZEXPORT WINAPI
+# ifdef WIN32
+# define ZEXPORTVA WINAPIV
+# else
+# define ZEXPORTVA FAR _cdecl _export
+# endif
+# endif
+# if defined (__BORLANDC__)
+# if (__BORLANDC__ >= 0x0500) && defined (WIN32)
+# include <windows.h>
+# define ZEXPORT __declspec(dllexport) WINAPI
+# define ZEXPORTRVA __declspec(dllexport) WINAPIV
+# else
+# if defined (_Windows) && defined (__DLL__)
+# define ZEXPORT _export
+# define ZEXPORTVA _export
+# endif
+# endif
+# endif
+#endif
+
+
+#ifndef ZEXPORT
+# define ZEXPORT
+#endif
+#ifndef ZEXPORTVA
+# define ZEXPORTVA
+#endif
+#ifndef ZEXTERN
+# define ZEXTERN static
+#endif
+#ifndef ZEXTERNDEF
+# define ZEXTERNDEF static
+#endif
+
+#ifndef FAR
+# define FAR
+#endif
+
+#if !defined(MACOS) && !defined(TARGET_OS_MAC)
+typedef unsigned char Byte; /* 8 bits */
+#endif
+typedef unsigned int uInt; /* 16 bits or more */
+typedef unsigned long uLong; /* 32 bits or more */
+
+#ifdef SMALL_MEDIUM
+ /* Borland C/C++ and some old MSC versions ignore FAR inside typedef */
+# define Bytef Byte FAR
+#else
+ typedef Byte FAR Bytef;
+#endif
+typedef char FAR charf;
+typedef int FAR intf;
+typedef uInt FAR uIntf;
+typedef uLong FAR uLongf;
+
+#ifdef STDC
+ typedef void FAR *voidpf;
+ typedef void *voidp;
+#else
+ typedef Byte FAR *voidpf;
+ typedef Byte *voidp;
+#endif
+
+#ifdef HAVE_UNISTD_H
+# include <sys/types.h> /* for off_t */
+# include <unistd.h> /* for SEEK_* and off_t */
+# define z_off_t off_t
+#endif
+#ifndef SEEK_SET
+# define SEEK_SET 0 /* Seek from beginning of file. */
+# define SEEK_CUR 1 /* Seek from current position. */
+# define SEEK_END 2 /* Set file pointer to EOF plus "offset" */
+#endif
+#ifndef z_off_t
+# define z_off_t long
+#endif
+
+/* MVS linker does not support external names larger than 8 bytes */
+#if defined(__MVS__)
+# pragma map(deflateInit_,"DEIN")
+# pragma map(deflateInit2_,"DEIN2")
+# pragma map(deflateEnd,"DEEND")
+# pragma map(inflateInit_,"ININ")
+# pragma map(inflateInit2_,"ININ2")
+# pragma map(inflateEnd,"INEND")
+# pragma map(inflateSync,"INSY")
+# pragma map(inflateSetDictionary,"INSEDI")
+# pragma map(inflate_blocks,"INBL")
+# pragma map(inflate_blocks_new,"INBLNE")
+# pragma map(inflate_blocks_free,"INBLFR")
+# pragma map(inflate_blocks_reset,"INBLRE")
+# pragma map(inflate_codes_free,"INCOFR")
+# pragma map(inflate_codes,"INCO")
+# pragma map(inflate_fast,"INFA")
+# pragma map(inflate_flush,"INFLU")
+# pragma map(inflate_mask,"INMA")
+# pragma map(inflate_set_dictionary,"INSEDI2")
+# pragma map(inflate_copyright,"INCOPY")
+# pragma map(inflate_trees_bits,"INTRBI")
+# pragma map(inflate_trees_dynamic,"INTRDY")
+# pragma map(inflate_trees_fixed,"INTRFI")
+# pragma map(inflate_trees_free,"INTRFR")
+#endif
+
+#endif /* _ZCONF_H */
--- /dev/null
+++ b/libfreetype/zlib.h
@@ -1,0 +1,830 @@
+/* zlib.h -- interface of the 'zlib' general purpose compression library
+ version 1.1.4, March 11th, 2002
+
+ Copyright (C) 1995-2002 Jean-loup Gailly and Mark Adler
+
+ This software is provided 'as-is', without any express or implied
+ warranty. In no event will the authors be held liable for any damages
+ arising from the use of this software.
+
+ Permission is granted to anyone to use this software for any purpose,
+ including commercial applications, and to alter it and redistribute it
+ freely, subject to the following restrictions:
+
+ 1. The origin of this software must not be misrepresented; you must not
+ claim that you wrote the original software. If you use this software
+ in a product, an acknowledgment in the product documentation would be
+ appreciated but is not required.
+ 2. Altered source versions must be plainly marked as such, and must not be
+ misrepresented as being the original software.
+ 3. This notice may not be removed or altered from any source distribution.
+
+ Jean-loup Gailly Mark Adler
+ jloup@gzip.org madler@alumni.caltech.edu
+
+
+ The data format used by the zlib library is described by RFCs (Request for
+ Comments) 1950 to 1952 in the files ftp://ds.internic.net/rfc/rfc1950.txt
+ (zlib format), rfc1951.txt (deflate format) and rfc1952.txt (gzip format).
+*/
+
+#ifndef _ZLIB_H
+#define _ZLIB_H
+
+#include "zconf.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define ZLIB_VERSION "1.1.4"
+
+/*
+ The 'zlib' compression library provides in-memory compression and
+ decompression functions, including integrity checks of the uncompressed
+ data. This version of the library supports only one compression method
+ (deflation) but other algorithms will be added later and will have the same
+ stream interface.
+
+ Compression can be done in a single step if the buffers are large
+ enough (for example if an input file is mmap'ed), or can be done by
+ repeated calls of the compression function. In the latter case, the
+ application must provide more input and/or consume the output
+ (providing more output space) before each call.
+
+ The library also supports reading and writing files in gzip (.gz) format
+ with an interface similar to that of stdio.
+
+ The library does not install any signal handler. The decoder checks
+ the consistency of the compressed data, so the library should never
+ crash even in case of corrupted input.
+*/
+
+typedef voidpf (*alloc_func) OF((voidpf opaque, uInt items, uInt size));
+typedef void (*free_func) OF((voidpf opaque, voidpf address));
+
+struct internal_state;
+
+typedef struct z_stream_s {
+ Bytef *next_in; /* next input byte */
+ uInt avail_in; /* number of bytes available at next_in */
+ uLong total_in; /* total nb of input bytes read so far */
+
+ Bytef *next_out; /* next output byte should be put there */
+ uInt avail_out; /* remaining free space at next_out */
+ uLong total_out; /* total nb of bytes output so far */
+
+ char *msg; /* last error message, NULL if no error */
+ struct internal_state FAR *state; /* not visible by applications */
+
+ alloc_func zalloc; /* used to allocate the internal state */
+ free_func zfree; /* used to free the internal state */
+ voidpf opaque; /* private data object passed to zalloc and zfree */
+
+ int data_type; /* best guess about the data type: ascii or binary */
+ uLong adler; /* adler32 value of the uncompressed data */
+ uLong reserved; /* reserved for future use */
+} z_stream;
+
+typedef z_stream FAR *z_streamp;
+
+/*
+ The application must update next_in and avail_in when avail_in has
+ dropped to zero. It must update next_out and avail_out when avail_out
+ has dropped to zero. The application must initialize zalloc, zfree and
+ opaque before calling the init function. All other fields are set by the
+ compression library and must not be updated by the application.
+
+ The opaque value provided by the application will be passed as the first
+ parameter for calls of zalloc and zfree. This can be useful for custom
+ memory management. The compression library attaches no meaning to the
+ opaque value.
+
+ zalloc must return Z_NULL if there is not enough memory for the object.
+ If zlib is used in a multi-threaded application, zalloc and zfree must be
+ thread safe.
+
+ On 16-bit systems, the functions zalloc and zfree must be able to allocate
+ exactly 65536 bytes, but will not be required to allocate more than this
+ if the symbol MAXSEG_64K is defined (see zconf.h). WARNING: On MSDOS,
+ pointers returned by zalloc for objects of exactly 65536 bytes *must*
+ have their offset normalized to zero. The default allocation function
+ provided by this library ensures this (see zutil.c). To reduce memory
+ requirements and avoid any allocation of 64K objects, at the expense of
+ compression ratio, compile the library with -DMAX_WBITS=14 (see zconf.h).
+
+ The fields total_in and total_out can be used for statistics or
+ progress reports. After compression, total_in holds the total size of
+ the uncompressed data and may be saved for use in the decompressor
+ (particularly if the decompressor wants to decompress everything in
+ a single step).
+*/
+
+ /* constants */
+
+#define Z_NO_FLUSH 0
+#define Z_PARTIAL_FLUSH 1 /* will be removed, use Z_SYNC_FLUSH instead */
+#define Z_SYNC_FLUSH 2
+#define Z_FULL_FLUSH 3
+#define Z_FINISH 4
+/* Allowed flush values; see deflate() below for details */
+
+#define Z_OK 0
+#define Z_STREAM_END 1
+#define Z_NEED_DICT 2
+#define Z_ERRNO (-1)
+#define Z_STREAM_ERROR (-2)
+#define Z_DATA_ERROR (-3)
+#define Z_MEM_ERROR (-4)
+#define Z_BUF_ERROR (-5)
+#define Z_VERSION_ERROR (-6)
+/* Return codes for the compression/decompression functions. Negative
+ * values are errors, positive values are used for special but normal events.
+ */
+
+#define Z_NO_COMPRESSION 0
+#define Z_BEST_SPEED 1
+#define Z_BEST_COMPRESSION 9
+#define Z_DEFAULT_COMPRESSION (-1)
+/* compression levels */
+
+#define Z_FILTERED 1
+#define Z_HUFFMAN_ONLY 2
+#define Z_DEFAULT_STRATEGY 0
+/* compression strategy; see deflateInit2() below for details */
+
+#define Z_BINARY 0
+#define Z_ASCII 1
+#define Z_UNKNOWN 2
+/* Possible values of the data_type field */
+
+#define Z_DEFLATED 8
+/* The deflate compression method (the only one supported in this version) */
+
+#define Z_NULL 0 /* for initializing zalloc, zfree, opaque */
+
+
+ /* basic functions */
+
+/* The application can compare zlibVersion and ZLIB_VERSION for consistency.
+ If the first character differs, the library code actually used is
+ not compatible with the zlib.h header file used by the application.
+ This check is automatically made by deflateInit and inflateInit.
+ */
+
+/*
+ZEXTERN int ZEXPORT deflateInit OF((z_streamp strm, int level));
+
+ Initializes the internal stream state for compression. The fields
+ zalloc, zfree and opaque must be initialized before by the caller.
+ If zalloc and zfree are set to Z_NULL, deflateInit updates them to
+ use default allocation functions.
+
+ The compression level must be Z_DEFAULT_COMPRESSION, or between 0 and 9:
+ 1 gives best speed, 9 gives best compression, 0 gives no compression at
+ all (the input data is simply copied a block at a time).
+ Z_DEFAULT_COMPRESSION requests a default compromise between speed and
+ compression (currently equivalent to level 6).
+
+ deflateInit returns Z_OK if success, Z_MEM_ERROR if there was not
+ enough memory, Z_STREAM_ERROR if level is not a valid compression level,
+ Z_VERSION_ERROR if the zlib library version (zlib_version) is incompatible
+ with the version assumed by the caller (ZLIB_VERSION).
+ msg is set to null if there is no error message. deflateInit does not
+ perform any compression: this will be done by deflate().
+*/
+
+
+/*
+ deflate compresses as much data as possible, and stops when the input
+ buffer becomes empty or the output buffer becomes full. It may introduce some
+ output latency (reading input without producing any output) except when
+ forced to flush.
+
+ The detailed semantics are as follows. deflate performs one or both of the
+ following actions:
+
+ - Compress more input starting at next_in and update next_in and avail_in
+ accordingly. If not all input can be processed (because there is not
+ enough room in the output buffer), next_in and avail_in are updated and
+ processing will resume at this point for the next call of deflate().
+
+ - Provide more output starting at next_out and update next_out and avail_out
+ accordingly. This action is forced if the parameter flush is non zero.
+ Forcing flush frequently degrades the compression ratio, so this parameter
+ should be set only when necessary (in interactive applications).
+ Some output may be provided even if flush is not set.
+
+ Before the call of deflate(), the application should ensure that at least
+ one of the actions is possible, by providing more input and/or consuming
+ more output, and updating avail_in or avail_out accordingly; avail_out
+ should never be zero before the call. The application can consume the
+ compressed output when it wants, for example when the output buffer is full
+ (avail_out == 0), or after each call of deflate(). If deflate returns Z_OK
+ and with zero avail_out, it must be called again after making room in the
+ output buffer because there might be more output pending.
+
+ If the parameter flush is set to Z_SYNC_FLUSH, all pending output is
+ flushed to the output buffer and the output is aligned on a byte boundary, so
+ that the decompressor can get all input data available so far. (In particular
+ avail_in is zero after the call if enough output space has been provided
+ before the call.) Flushing may degrade compression for some compression
+ algorithms and so it should be used only when necessary.
+
+ If flush is set to Z_FULL_FLUSH, all output is flushed as with
+ Z_SYNC_FLUSH, and the compression state is reset so that decompression can
+ restart from this point if previous compressed data has been damaged or if
+ random access is desired. Using Z_FULL_FLUSH too often can seriously degrade
+ the compression.
+
+ If deflate returns with avail_out == 0, this function must be called again
+ with the same value of the flush parameter and more output space (updated
+ avail_out), until the flush is complete (deflate returns with non-zero
+ avail_out).
+
+ If the parameter flush is set to Z_FINISH, pending input is processed,
+ pending output is flushed and deflate returns with Z_STREAM_END if there
+ was enough output space; if deflate returns with Z_OK, this function must be
+ called again with Z_FINISH and more output space (updated avail_out) but no
+ more input data, until it returns with Z_STREAM_END or an error. After
+ deflate has returned Z_STREAM_END, the only possible operations on the
+ stream are deflateReset or deflateEnd.
+
+ Z_FINISH can be used immediately after deflateInit if all the compression
+ is to be done in a single step. In this case, avail_out must be at least
+ 0.1% larger than avail_in plus 12 bytes. If deflate does not return
+ Z_STREAM_END, then it must be called again as described above.
+
+ deflate() sets strm->adler to the adler32 checksum of all input read
+ so far (that is, total_in bytes).
+
+ deflate() may update data_type if it can make a good guess about
+ the input data type (Z_ASCII or Z_BINARY). In doubt, the data is considered
+ binary. This field is only for information purposes and does not affect
+ the compression algorithm in any manner.
+
+ deflate() returns Z_OK if some progress has been made (more input
+ processed or more output produced), Z_STREAM_END if all input has been
+ consumed and all output has been produced (only when flush is set to
+ Z_FINISH), Z_STREAM_ERROR if the stream state was inconsistent (for example
+ if next_in or next_out was NULL), Z_BUF_ERROR if no progress is possible
+ (for example avail_in or avail_out was zero).
+*/
+
+
+/*
+ All dynamically allocated data structures for this stream are freed.
+ This function discards any unprocessed input and does not flush any
+ pending output.
+
+ deflateEnd returns Z_OK if success, Z_STREAM_ERROR if the
+ stream state was inconsistent, Z_DATA_ERROR if the stream was freed
+ prematurely (some input or output was discarded). In the error case,
+ msg may be set but then points to a static string (which must not be
+ deallocated).
+*/
+
+
+/*
+ZEXTERN int ZEXPORT inflateInit OF((z_streamp strm));
+
+ Initializes the internal stream state for decompression. The fields
+ next_in, avail_in, zalloc, zfree and opaque must be initialized before by
+ the caller. If next_in is not Z_NULL and avail_in is large enough (the exact
+ value depends on the compression method), inflateInit determines the
+ compression method from the zlib header and allocates all data structures
+ accordingly; otherwise the allocation will be deferred to the first call of
+ inflate. If zalloc and zfree are set to Z_NULL, inflateInit updates them to
+ use default allocation functions.
+
+ inflateInit returns Z_OK if success, Z_MEM_ERROR if there was not enough
+ memory, Z_VERSION_ERROR if the zlib library version is incompatible with the
+ version assumed by the caller. msg is set to null if there is no error
+ message. inflateInit does not perform any decompression apart from reading
+ the zlib header if present: this will be done by inflate(). (So next_in and
+ avail_in may be modified, but next_out and avail_out are unchanged.)
+*/
+
+
+ZEXTERN int ZEXPORT inflate OF((z_streamp strm, int flush));
+/*
+ inflate decompresses as much data as possible, and stops when the input
+ buffer becomes empty or the output buffer becomes full. It may some
+ introduce some output latency (reading input without producing any output)
+ except when forced to flush.
+
+ The detailed semantics are as follows. inflate performs one or both of the
+ following actions:
+
+ - Decompress more input starting at next_in and update next_in and avail_in
+ accordingly. If not all input can be processed (because there is not
+ enough room in the output buffer), next_in is updated and processing
+ will resume at this point for the next call of inflate().
+
+ - Provide more output starting at next_out and update next_out and avail_out
+ accordingly. inflate() provides as much output as possible, until there
+ is no more input data or no more space in the output buffer (see below
+ about the flush parameter).
+
+ Before the call of inflate(), the application should ensure that at least
+ one of the actions is possible, by providing more input and/or consuming
+ more output, and updating the next_* and avail_* values accordingly.
+ The application can consume the uncompressed output when it wants, for
+ example when the output buffer is full (avail_out == 0), or after each
+ call of inflate(). If inflate returns Z_OK and with zero avail_out, it
+ must be called again after making room in the output buffer because there
+ might be more output pending.
+
+ If the parameter flush is set to Z_SYNC_FLUSH, inflate flushes as much
+ output as possible to the output buffer. The flushing behavior of inflate is
+ not specified for values of the flush parameter other than Z_SYNC_FLUSH
+ and Z_FINISH, but the current implementation actually flushes as much output
+ as possible anyway.
+
+ inflate() should normally be called until it returns Z_STREAM_END or an
+ error. However if all decompression is to be performed in a single step
+ (a single call of inflate), the parameter flush should be set to
+ Z_FINISH. In this case all pending input is processed and all pending
+ output is flushed; avail_out must be large enough to hold all the
+ uncompressed data. (The size of the uncompressed data may have been saved
+ by the compressor for this purpose.) The next operation on this stream must
+ be inflateEnd to deallocate the decompression state. The use of Z_FINISH
+ is never required, but can be used to inform inflate that a faster routine
+ may be used for the single inflate() call.
+
+ If a preset dictionary is needed at this point (see inflateSetDictionary
+ below), inflate sets strm-adler to the adler32 checksum of the
+ dictionary chosen by the compressor and returns Z_NEED_DICT; otherwise
+ it sets strm->adler to the adler32 checksum of all output produced
+ so far (that is, total_out bytes) and returns Z_OK, Z_STREAM_END or
+ an error code as described below. At the end of the stream, inflate()
+ checks that its computed adler32 checksum is equal to that saved by the
+ compressor and returns Z_STREAM_END only if the checksum is correct.
+
+ inflate() returns Z_OK if some progress has been made (more input processed
+ or more output produced), Z_STREAM_END if the end of the compressed data has
+ been reached and all uncompressed output has been produced, Z_NEED_DICT if a
+ preset dictionary is needed at this point, Z_DATA_ERROR if the input data was
+ corrupted (input stream not conforming to the zlib format or incorrect
+ adler32 checksum), Z_STREAM_ERROR if the stream structure was inconsistent
+ (for example if next_in or next_out was NULL), Z_MEM_ERROR if there was not
+ enough memory, Z_BUF_ERROR if no progress is possible or if there was not
+ enough room in the output buffer when Z_FINISH is used. In the Z_DATA_ERROR
+ case, the application may then call inflateSync to look for a good
+ compression block.
+*/
+
+
+ZEXTERN int ZEXPORT inflateEnd OF((z_streamp strm));
+/*
+ All dynamically allocated data structures for this stream are freed.
+ This function discards any unprocessed input and does not flush any
+ pending output.
+
+ inflateEnd returns Z_OK if success, Z_STREAM_ERROR if the stream state
+ was inconsistent. In the error case, msg may be set but then points to a
+ static string (which must not be deallocated).
+*/
+
+ /* Advanced functions */
+
+/*
+ The following functions are needed only in some special applications.
+*/
+
+/*
+ZEXTERN int ZEXPORT deflateInit2 OF((z_streamp strm,
+ int level,
+ int method,
+ int windowBits,
+ int memLevel,
+ int strategy));
+
+ This is another version of deflateInit with more compression options. The
+ fields next_in, zalloc, zfree and opaque must be initialized before by
+ the caller.
+
+ The method parameter is the compression method. It must be Z_DEFLATED in
+ this version of the library.
+
+ The windowBits parameter is the base two logarithm of the window size
+ (the size of the history buffer). It should be in the range 8..15 for this
+ version of the library. Larger values of this parameter result in better
+ compression at the expense of memory usage. The default value is 15 if
+ deflateInit is used instead.
+
+ The memLevel parameter specifies how much memory should be allocated
+ for the internal compression state. memLevel=1 uses minimum memory but
+ is slow and reduces compression ratio; memLevel=9 uses maximum memory
+ for optimal speed. The default value is 8. See zconf.h for total memory
+ usage as a function of windowBits and memLevel.
+
+ The strategy parameter is used to tune the compression algorithm. Use the
+ value Z_DEFAULT_STRATEGY for normal data, Z_FILTERED for data produced by a
+ filter (or predictor), or Z_HUFFMAN_ONLY to force Huffman encoding only (no
+ string match). Filtered data consists mostly of small values with a
+ somewhat random distribution. In this case, the compression algorithm is
+ tuned to compress them better. The effect of Z_FILTERED is to force more
+ Huffman coding and less string matching; it is somewhat intermediate
+ between Z_DEFAULT and Z_HUFFMAN_ONLY. The strategy parameter only affects
+ the compression ratio but not the correctness of the compressed output even
+ if it is not set appropriately.
+
+ deflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was not enough
+ memory, Z_STREAM_ERROR if a parameter is invalid (such as an invalid
+ method). msg is set to null if there is no error message. deflateInit2 does
+ not perform any compression: this will be done by deflate().
+*/
+
+/*
+ Initializes the compression dictionary from the given byte sequence
+ without producing any compressed output. This function must be called
+ immediately after deflateInit, deflateInit2 or deflateReset, before any
+ call of deflate. The compressor and decompressor must use exactly the same
+ dictionary (see inflateSetDictionary).
+
+ The dictionary should consist of strings (byte sequences) that are likely
+ to be encountered later in the data to be compressed, with the most commonly
+ used strings preferably put towards the end of the dictionary. Using a
+ dictionary is most useful when the data to be compressed is short and can be
+ predicted with good accuracy; the data can then be compressed better than
+ with the default empty dictionary.
+
+ Depending on the size of the compression data structures selected by
+ deflateInit or deflateInit2, a part of the dictionary may in effect be
+ discarded, for example if the dictionary is larger than the window size in
+ deflate or deflate2. Thus the strings most likely to be useful should be
+ put at the end of the dictionary, not at the front.
+
+ Upon return of this function, strm->adler is set to the Adler32 value
+ of the dictionary; the decompressor may later use this value to determine
+ which dictionary has been used by the compressor. (The Adler32 value
+ applies to the whole dictionary even if only a subset of the dictionary is
+ actually used by the compressor.)
+
+ deflateSetDictionary returns Z_OK if success, or Z_STREAM_ERROR if a
+ parameter is invalid (such as NULL dictionary) or the stream state is
+ inconsistent (for example if deflate has already been called for this stream
+ or if the compression method is bsort). deflateSetDictionary does not
+ perform any compression: this will be done by deflate().
+*/
+
+/*
+ Sets the destination stream as a complete copy of the source stream.
+
+ This function can be useful when several compression strategies will be
+ tried, for example when there are several ways of pre-processing the input
+ data with a filter. The streams that will be discarded should then be freed
+ by calling deflateEnd. Note that deflateCopy duplicates the internal
+ compression state which can be quite large, so this strategy is slow and
+ can consume lots of memory.
+
+ deflateCopy returns Z_OK if success, Z_MEM_ERROR if there was not
+ enough memory, Z_STREAM_ERROR if the source stream state was inconsistent
+ (such as zalloc being NULL). msg is left unchanged in both source and
+ destination.
+*/
+
+/*
+ This function is equivalent to deflateEnd followed by deflateInit,
+ but does not free and reallocate all the internal compression state.
+ The stream will keep the same compression level and any other attributes
+ that may have been set by deflateInit2.
+
+ deflateReset returns Z_OK if success, or Z_STREAM_ERROR if the source
+ stream state was inconsistent (such as zalloc or state being NULL).
+*/
+
+/*
+ Dynamically update the compression level and compression strategy. The
+ interpretation of level and strategy is as in deflateInit2. This can be
+ used to switch between compression and straight copy of the input data, or
+ to switch to a different kind of input data requiring a different
+ strategy. If the compression level is changed, the input available so far
+ is compressed with the old level (and may be flushed); the new level will
+ take effect only at the next call of deflate().
+
+ Before the call of deflateParams, the stream state must be set as for
+ a call of deflate(), since the currently available input may have to
+ be compressed and flushed. In particular, strm->avail_out must be non-zero.
+
+ deflateParams returns Z_OK if success, Z_STREAM_ERROR if the source
+ stream state was inconsistent or if a parameter was invalid, Z_BUF_ERROR
+ if strm->avail_out was zero.
+*/
+
+/*
+ZEXTERN int ZEXPORT inflateInit2 OF((z_streamp strm,
+ int windowBits));
+
+ This is another version of inflateInit with an extra parameter. The
+ fields next_in, avail_in, zalloc, zfree and opaque must be initialized
+ before by the caller.
+
+ The windowBits parameter is the base two logarithm of the maximum window
+ size (the size of the history buffer). It should be in the range 8..15 for
+ this version of the library. The default value is 15 if inflateInit is used
+ instead. If a compressed stream with a larger window size is given as
+ input, inflate() will return with the error code Z_DATA_ERROR instead of
+ trying to allocate a larger window.
+
+ inflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was not enough
+ memory, Z_STREAM_ERROR if a parameter is invalid (such as a negative
+ memLevel). msg is set to null if there is no error message. inflateInit2
+ does not perform any decompression apart from reading the zlib header if
+ present: this will be done by inflate(). (So next_in and avail_in may be
+ modified, but next_out and avail_out are unchanged.)
+*/
+
+/*
+ Initializes the decompression dictionary from the given uncompressed byte
+ sequence. This function must be called immediately after a call of inflate
+ if this call returned Z_NEED_DICT. The dictionary chosen by the compressor
+ can be determined from the Adler32 value returned by this call of
+ inflate. The compressor and decompressor must use exactly the same
+ dictionary (see deflateSetDictionary).
+
+ inflateSetDictionary returns Z_OK if success, Z_STREAM_ERROR if a
+ parameter is invalid (such as NULL dictionary) or the stream state is
+ inconsistent, Z_DATA_ERROR if the given dictionary doesn't match the
+ expected one (incorrect Adler32 value). inflateSetDictionary does not
+ perform any decompression: this will be done by subsequent calls of
+ inflate().
+*/
+
+/*
+ Skips invalid compressed data until a full flush point (see above the
+ description of deflate with Z_FULL_FLUSH) can be found, or until all
+ available input is skipped. No output is provided.
+
+ inflateSync returns Z_OK if a full flush point has been found, Z_BUF_ERROR
+ if no more input was provided, Z_DATA_ERROR if no flush point has been found,
+ or Z_STREAM_ERROR if the stream structure was inconsistent. In the success
+ case, the application may save the current current value of total_in which
+ indicates where valid compressed data was found. In the error case, the
+ application may repeatedly call inflateSync, providing more input each time,
+ until success or end of the input data.
+*/
+
+ZEXTERN int ZEXPORT inflateReset OF((z_streamp strm));
+/*
+ This function is equivalent to inflateEnd followed by inflateInit,
+ but does not free and reallocate all the internal decompression state.
+ The stream will keep attributes that may have been set by inflateInit2.
+
+ inflateReset returns Z_OK if success, or Z_STREAM_ERROR if the source
+ stream state was inconsistent (such as zalloc or state being NULL).
+*/
+
+
+ /* utility functions */
+
+/*
+ The following utility functions are implemented on top of the
+ basic stream-oriented functions. To simplify the interface, some
+ default options are assumed (compression level and memory usage,
+ standard memory allocation functions). The source code of these
+ utility functions can easily be modified if you need special options.
+*/
+
+/*
+ Compresses the source buffer into the destination buffer. sourceLen is
+ the byte length of the source buffer. Upon entry, destLen is the total
+ size of the destination buffer, which must be at least 0.1% larger than
+ sourceLen plus 12 bytes. Upon exit, destLen is the actual size of the
+ compressed buffer.
+ This function can be used to compress a whole file at once if the
+ input file is mmap'ed.
+ compress returns Z_OK if success, Z_MEM_ERROR if there was not
+ enough memory, Z_BUF_ERROR if there was not enough room in the output
+ buffer.
+*/
+
+/*
+ Compresses the source buffer into the destination buffer. The level
+ parameter has the same meaning as in deflateInit. sourceLen is the byte
+ length of the source buffer. Upon entry, destLen is the total size of the
+ destination buffer, which must be at least 0.1% larger than sourceLen plus
+ 12 bytes. Upon exit, destLen is the actual size of the compressed buffer.
+
+ compress2 returns Z_OK if success, Z_MEM_ERROR if there was not enough
+ memory, Z_BUF_ERROR if there was not enough room in the output buffer,
+ Z_STREAM_ERROR if the level parameter is invalid.
+*/
+
+/*
+ Decompresses the source buffer into the destination buffer. sourceLen is
+ the byte length of the source buffer. Upon entry, destLen is the total
+ size of the destination buffer, which must be large enough to hold the
+ entire uncompressed data. (The size of the uncompressed data must have
+ been saved previously by the compressor and transmitted to the decompressor
+ by some mechanism outside the scope of this compression library.)
+ Upon exit, destLen is the actual size of the compressed buffer.
+ This function can be used to decompress a whole file at once if the
+ input file is mmap'ed.
+
+ uncompress returns Z_OK if success, Z_MEM_ERROR if there was not
+ enough memory, Z_BUF_ERROR if there was not enough room in the output
+ buffer, or Z_DATA_ERROR if the input data was corrupted.
+*/
+
+
+/*
+ Opens a gzip (.gz) file for reading or writing. The mode parameter
+ is as in fopen ("rb" or "wb") but can also include a compression level
+ ("wb9") or a strategy: 'f' for filtered data as in "wb6f", 'h' for
+ Huffman only compression as in "wb1h". (See the description
+ of deflateInit2 for more information about the strategy parameter.)
+
+ gzopen can be used to read a file which is not in gzip format; in this
+ case gzread will directly read from the file without decompression.
+
+ gzopen returns NULL if the file could not be opened or if there was
+ insufficient memory to allocate the (de)compression state; errno
+ can be checked to distinguish the two cases (if errno is zero, the
+ zlib error is Z_MEM_ERROR). */
+
+/*
+ gzdopen() associates a gzFile with the file descriptor fd. File
+ descriptors are obtained from calls like open, dup, creat, pipe or
+ fileno (in the file has been previously opened with fopen).
+ The mode parameter is as in gzopen.
+ The next call of gzclose on the returned gzFile will also close the
+ file descriptor fd, just like fclose(fdopen(fd), mode) closes the file
+ descriptor fd. If you want to keep fd open, use gzdopen(dup(fd), mode).
+ gzdopen returns NULL if there was insufficient memory to allocate
+ the (de)compression state.
+*/
+
+/*
+ Dynamically update the compression level or strategy. See the description
+ of deflateInit2 for the meaning of these parameters.
+ gzsetparams returns Z_OK if success, or Z_STREAM_ERROR if the file was not
+ opened for writing.
+*/
+
+/*
+ Reads the given number of uncompressed bytes from the compressed file.
+ If the input file was not in gzip format, gzread copies the given number
+ of bytes into the buffer.
+ gzread returns the number of uncompressed bytes actually read (0 for
+ end of file, -1 for error). */
+
+/*
+ Writes the given number of uncompressed bytes into the compressed file.
+ gzwrite returns the number of uncompressed bytes actually written
+ (0 in case of error).
+*/
+
+/*
+ Converts, formats, and writes the args to the compressed file under
+ control of the format string, as in fprintf. gzprintf returns the number of
+ uncompressed bytes actually written (0 in case of error).
+*/
+
+/*
+ Writes the given null-terminated string to the compressed file, excluding
+ the terminating null character.
+ gzputs returns the number of characters written, or -1 in case of error.
+*/
+
+/*
+ Reads bytes from the compressed file until len-1 characters are read, or
+ a newline character is read and transferred to buf, or an end-of-file
+ condition is encountered. The string is then terminated with a null
+ character.
+ gzgets returns buf, or Z_NULL in case of error.
+*/
+
+/*
+ Writes c, converted to an unsigned char, into the compressed file.
+ gzputc returns the value that was written, or -1 in case of error.
+*/
+
+/*
+ Reads one byte from the compressed file. gzgetc returns this byte
+ or -1 in case of end of file or error.
+*/
+
+/*
+ Flushes all pending output into the compressed file. The parameter
+ flush is as in the deflate() function. The return value is the zlib
+ error number (see function gzerror below). gzflush returns Z_OK if
+ the flush parameter is Z_FINISH and all output could be flushed.
+ gzflush should be called only when strictly necessary because it can
+ degrade compression.
+*/
+
+/*
+ Sets the starting position for the next gzread or gzwrite on the
+ given compressed file. The offset represents a number of bytes in the
+ uncompressed data stream. The whence parameter is defined as in lseek(2);
+ the value SEEK_END is not supported.
+ If the file is opened for reading, this function is emulated but can be
+ extremely slow. If the file is opened for writing, only forward seeks are
+ supported; gzseek then compresses a sequence of zeroes up to the new
+ starting position.
+
+ gzseek returns the resulting offset location as measured in bytes from
+ the beginning of the uncompressed stream, or -1 in case of error, in
+ particular if the file is opened for writing and the new starting position
+ would be before the current position.
+*/
+
+/*
+ Rewinds the given file. This function is supported only for reading.
+
+ gzrewind(file) is equivalent to (int)gzseek(file, 0L, SEEK_SET)
+*/
+
+/*
+ Returns the starting position for the next gzread or gzwrite on the
+ given compressed file. This position represents a number of bytes in the
+ uncompressed data stream.
+
+ gztell(file) is equivalent to gzseek(file, 0L, SEEK_CUR)
+*/
+
+/*
+ Returns 1 when EOF has previously been detected reading the given
+ input stream, otherwise zero.
+*/
+
+/*
+ Flushes all pending output if necessary, closes the compressed file
+ and deallocates all the (de)compression state. The return value is the zlib
+ error number (see function gzerror below).
+*/
+
+/*
+ Returns the error message for the last error which occurred on the
+ given compressed file. errnum is set to zlib error number. If an
+ error occurred in the file system and not in the compression library,
+ errnum is set to Z_ERRNO and the application may consult errno
+ to get the exact error code.
+*/
+
+ /* checksum functions */
+
+/*
+ These functions are not related to compression but are exported
+ anyway because they might be useful in applications using the
+ compression library.
+*/
+
+ZEXTERN uLong ZEXPORT adler32 OF((uLong adler, const Bytef *buf, uInt len));
+
+/*
+ Update a running Adler-32 checksum with the bytes buf[0..len-1] and
+ return the updated checksum. If buf is NULL, this function returns
+ the required initial value for the checksum.
+ An Adler-32 checksum is almost as reliable as a CRC32 but can be computed
+ much faster. Usage example:
+
+ uLong adler = adler32(0L, Z_NULL, 0);
+
+ while (read_buffer(buffer, length) != EOF) {
+ adler = adler32(adler, buffer, length);
+ }
+ if (adler != original_adler) error();
+*/
+
+/*
+ Update a running crc with the bytes buf[0..len-1] and return the updated
+ crc. If buf is NULL, this function returns the required initial value
+ for the crc. Pre- and post-conditioning (one's complement) is performed
+ within this function so it shouldn't be done by the application.
+ Usage example:
+
+ uLong crc = crc32(0L, Z_NULL, 0);
+
+ while (read_buffer(buffer, length) != EOF) {
+ crc = crc32(crc, buffer, length);
+ }
+ if (crc != original_crc) error();
+*/
+
+
+ /* various hacks, don't look :) */
+
+/* deflateInit and inflateInit are macros to allow checking the zlib version
+ * and the compiler's view of z_stream:
+ */
+ZEXTERN int ZEXPORT inflateInit2_ OF((z_streamp strm, int windowBits,
+ const char *version, int stream_size));
+#define deflateInit(strm, level) \
+ deflateInit_((strm), (level), ZLIB_VERSION, sizeof(z_stream))
+#define inflateInit(strm) \
+ inflateInit_((strm), ZLIB_VERSION, sizeof(z_stream))
+#define deflateInit2(strm, level, method, windowBits, memLevel, strategy) \
+ deflateInit2_((strm),(level),(method),(windowBits),(memLevel),\
+ (strategy), ZLIB_VERSION, sizeof(z_stream))
+#define inflateInit2(strm, windowBits) \
+ inflateInit2_((strm), (windowBits), ZLIB_VERSION, sizeof(z_stream))
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _ZLIB_H */
--- /dev/null
+++ b/libfreetype/zutil.c
@@ -1,0 +1,181 @@
+/* zutil.c -- target dependent utility functions for the compression library
+ * Copyright (C) 1995-2002 Jean-loup Gailly.
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/* @(#) $Id: zutil.c,v 1.2 2002/11/06 22:32:54 davidT Exp $ */
+
+#include "zutil.h"
+
+#ifndef STDC
+extern void exit OF((int));
+#endif
+
+
+#ifndef HAVE_MEMCPY
+
+void zmemcpy(dest, source, len)
+ Bytef* dest;
+ const Bytef* source;
+ uInt len;
+{
+ if (len == 0) return;
+ do {
+ *dest++ = *source++; /* ??? to be unrolled */
+ } while (--len != 0);
+}
+
+int zmemcmp(s1, s2, len)
+ const Bytef* s1;
+ const Bytef* s2;
+ uInt len;
+{
+ uInt j;
+
+ for (j = 0; j < len; j++) {
+ if (s1[j] != s2[j]) return 2*(s1[j] > s2[j])-1;
+ }
+ return 0;
+}
+
+void zmemzero(dest, len)
+ Bytef* dest;
+ uInt len;
+{
+ if (len == 0) return;
+ do {
+ *dest++ = 0; /* ??? to be unrolled */
+ } while (--len != 0);
+}
+#endif
+
+#ifdef __TURBOC__
+#if (defined( __BORLANDC__) || !defined(SMALL_MEDIUM)) && !defined(__32BIT__)
+/* Small and medium model in Turbo C are for now limited to near allocation
+ * with reduced MAX_WBITS and MAX_MEM_LEVEL
+ */
+# define MY_ZCALLOC
+
+/* Turbo C malloc() does not allow dynamic allocation of 64K bytes
+ * and farmalloc(64K) returns a pointer with an offset of 8, so we
+ * must fix the pointer. Warning: the pointer must be put back to its
+ * original form in order to free it, use zcfree().
+ */
+
+#define MAX_PTR 10
+/* 10*64K = 640K */
+
+local int next_ptr = 0;
+
+typedef struct ptr_table_s {
+ voidpf org_ptr;
+ voidpf new_ptr;
+} ptr_table;
+
+local ptr_table table[MAX_PTR];
+/* This table is used to remember the original form of pointers
+ * to large buffers (64K). Such pointers are normalized with a zero offset.
+ * Since MSDOS is not a preemptive multitasking OS, this table is not
+ * protected from concurrent access. This hack doesn't work anyway on
+ * a protected system like OS/2. Use Microsoft C instead.
+ */
+
+voidpf zcalloc (voidpf opaque, unsigned items, unsigned size)
+{
+ voidpf buf = opaque; /* just to make some compilers happy */
+ ulg bsize = (ulg)items*size;
+
+ /* If we allocate less than 65520 bytes, we assume that farmalloc
+ * will return a usable pointer which doesn't have to be normalized.
+ */
+ if (bsize < 65520L) {
+ buf = farmalloc(bsize);
+ if (*(ush*)&buf != 0) return buf;
+ } else {
+ buf = farmalloc(bsize + 16L);
+ }
+ if (buf == NULL || next_ptr >= MAX_PTR) return NULL;
+ table[next_ptr].org_ptr = buf;
+
+ /* Normalize the pointer to seg:0 */
+ *((ush*)&buf+1) += ((ush)((uch*)buf-0) + 15) >> 4;
+ *(ush*)&buf = 0;
+ table[next_ptr++].new_ptr = buf;
+ return buf;
+}
+
+void zcfree (voidpf opaque, voidpf ptr)
+{
+ int n;
+ if (*(ush*)&ptr != 0) { /* object < 64K */
+ farfree(ptr);
+ return;
+ }
+ /* Find the original pointer */
+ for (n = 0; n < next_ptr; n++) {
+ if (ptr != table[n].new_ptr) continue;
+
+ farfree(table[n].org_ptr);
+ while (++n < next_ptr) {
+ table[n-1] = table[n];
+ }
+ next_ptr--;
+ return;
+ }
+ ptr = opaque; /* just to make some compilers happy */
+ Assert(0, "zcfree: ptr not found");
+}
+#endif
+#endif /* __TURBOC__ */
+
+
+#if defined(M_I86) && !defined(__32BIT__)
+/* Microsoft C in 16-bit mode */
+
+# define MY_ZCALLOC
+
+#if (!defined(_MSC_VER) || (_MSC_VER <= 600))
+# define _halloc halloc
+# define _hfree hfree
+#endif
+
+voidpf zcalloc (voidpf opaque, unsigned items, unsigned size)
+{
+ if (opaque) opaque = 0; /* to make compiler happy */
+ return _halloc((long)items, size);
+}
+
+void zcfree (voidpf opaque, voidpf ptr)
+{
+ if (opaque) opaque = 0; /* to make compiler happy */
+ _hfree(ptr);
+}
+
+#endif /* MSC */
+
+
+#ifndef MY_ZCALLOC /* Any system without a special alloc function */
+
+#ifndef STDC
+extern voidp calloc OF((uInt items, uInt size));
+extern void free OF((voidpf ptr));
+#endif
+
+voidpf zcalloc (opaque, items, size)
+ voidpf opaque;
+ unsigned items;
+ unsigned size;
+{
+ if (opaque) items += size - size; /* make compiler happy */
+ return (voidpf)calloc(items, size);
+}
+
+void zcfree (opaque, ptr)
+ voidpf opaque;
+ voidpf ptr;
+{
+ free(ptr);
+ if (opaque) return; /* make compiler happy */
+}
+
+#endif /* MY_ZCALLOC */
--- /dev/null
+++ b/libfreetype/zutil.h
@@ -1,0 +1,216 @@
+/* zutil.h -- internal interface and configuration of the compression library
+ * Copyright (C) 1995-2002 Jean-loup Gailly.
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/* WARNING: this file should *not* be used by applications. It is
+ part of the implementation of the compression library and is
+ subject to change. Applications should only use zlib.h.
+ */
+
+/* @(#) $Id: zutil.h,v 1.2 2002/11/06 22:32:54 davidT Exp $ */
+
+#ifndef _Z_UTIL_H
+#define _Z_UTIL_H
+
+#include "zlib.h"
+
+#ifdef STDC
+# include <stddef.h>
+# include <string.h>
+# include <stdlib.h>
+#endif
+#ifdef NO_ERRNO_H
+ extern int errno;
+#else
+# include <errno.h>
+#endif
+
+#ifndef local
+# define local static
+#endif
+/* compile with -Dlocal if your debugger can't find static symbols */
+
+typedef unsigned char uch;
+typedef uch FAR uchf;
+typedef unsigned short ush;
+typedef ush FAR ushf;
+typedef unsigned long ulg;
+
+
+#define ERR_RETURN(strm,err) \
+ return (strm->msg = (char*)ERR_MSG(err), (err))
+/* To be used only when the state is known to be valid */
+
+ /* common constants */
+
+#ifndef DEF_WBITS
+# define DEF_WBITS MAX_WBITS
+#endif
+/* default windowBits for decompression. MAX_WBITS is for compression only */
+
+#if MAX_MEM_LEVEL >= 8
+# define DEF_MEM_LEVEL 8
+#else
+# define DEF_MEM_LEVEL MAX_MEM_LEVEL
+#endif
+/* default memLevel */
+
+#define STORED_BLOCK 0
+#define STATIC_TREES 1
+#define DYN_TREES 2
+/* The three kinds of block type */
+
+#define MIN_MATCH 3
+#define MAX_MATCH 258
+/* The minimum and maximum match lengths */
+
+#define PRESET_DICT 0x20 /* preset dictionary flag in zlib header */
+
+ /* target dependencies */
+
+#ifdef MSDOS
+# define OS_CODE 0x00
+# if defined(__TURBOC__) || defined(__BORLANDC__)
+# if(__STDC__ == 1) && (defined(__LARGE__) || defined(__COMPACT__))
+ /* Allow compilation with ANSI keywords only enabled */
+ void _Cdecl farfree( void *block );
+ void *_Cdecl farmalloc( unsigned long nbytes );
+# else
+# include <alloc.h>
+# endif
+# else /* MSC or DJGPP */
+# include <malloc.h>
+# endif
+#endif
+
+#ifdef OS2
+# define OS_CODE 0x06
+#endif
+
+#ifdef WIN32 /* Window 95 & Windows NT */
+# define OS_CODE 0x0b
+#endif
+
+#if defined(VAXC) || defined(VMS)
+# define OS_CODE 0x02
+# define F_OPEN(name, mode) \
+ fopen((name), (mode), "mbc=60", "ctx=stm", "rfm=fix", "mrs=512")
+#endif
+
+#ifdef AMIGA
+# define OS_CODE 0x01
+#endif
+
+#if defined(ATARI) || defined(atarist)
+# define OS_CODE 0x05
+#endif
+
+#if defined(MACOS) || defined(TARGET_OS_MAC)
+# define OS_CODE 0x07
+# if defined(__MWERKS__) && __dest_os != __be_os && __dest_os != __win32_os
+# include <unix.h> /* for fdopen */
+# else
+# ifndef fdopen
+# define fdopen(fd,mode) NULL /* No fdopen() */
+# endif
+# endif
+#endif
+
+#ifdef __50SERIES /* Prime/PRIMOS */
+# define OS_CODE 0x0F
+#endif
+
+#ifdef TOPS20
+# define OS_CODE 0x0a
+#endif
+
+#if defined(_BEOS_) || defined(RISCOS)
+# define fdopen(fd,mode) NULL /* No fdopen() */
+#endif
+
+#if (defined(_MSC_VER) && (_MSC_VER > 600))
+# define fdopen(fd,type) _fdopen(fd,type)
+#endif
+
+
+ /* Common defaults */
+
+#ifndef OS_CODE
+# define OS_CODE 0x03 /* assume Unix */
+#endif
+
+#ifndef F_OPEN
+# define F_OPEN(name, mode) fopen((name), (mode))
+#endif
+
+ /* functions */
+
+#ifdef HAVE_STRERROR
+ extern char *strerror OF((int));
+# define zstrerror(errnum) strerror(errnum)
+#else
+# define zstrerror(errnum) ""
+#endif
+
+#if defined(pyr)
+# define NO_MEMCPY
+#endif
+#if defined(SMALL_MEDIUM) && !defined(_MSC_VER) && !defined(__SC__)
+ /* Use our own functions for small and medium model with MSC <= 5.0.
+ * You may have to use the same strategy for Borland C (untested).
+ * The __SC__ check is for Symantec.
+ */
+# define NO_MEMCPY
+#endif
+#if defined(STDC) && !defined(HAVE_MEMCPY) && !defined(NO_MEMCPY)
+# define HAVE_MEMCPY
+#endif
+#ifdef HAVE_MEMCPY
+# ifdef SMALL_MEDIUM /* MSDOS small or medium model */
+# define zmemcpy _fmemcpy
+# define zmemcmp _fmemcmp
+# define zmemzero(dest, len) _fmemset(dest, 0, len)
+# else
+# define zmemcpy ft_memcpy
+# define zmemcmp memcmp
+# define zmemzero(dest, len) memset(dest, 0, len)
+# endif
+#else
+ extern void zmemcpy OF((Bytef* dest, const Bytef* source, uInt len));
+ extern int zmemcmp OF((const Bytef* s1, const Bytef* s2, uInt len));
+ extern void zmemzero OF((Bytef* dest, uInt len));
+#endif
+
+/* Diagnostic functions */
+#ifdef DEBUG
+# include <stdio.h>
+ extern int z_verbose;
+ extern void z_error OF((char *m));
+# define Assert(cond,msg) {if(!(cond)) z_error(msg);}
+# define Trace(x) {if (z_verbose>=0) fprintf x ;}
+# define Tracev(x) {if (z_verbose>0) fprintf x ;}
+# define Tracevv(x) {if (z_verbose>1) fprintf x ;}
+# define Tracec(c,x) {if (z_verbose>0 && (c)) fprintf x ;}
+# define Tracecv(c,x) {if (z_verbose>1 && (c)) fprintf x ;}
+#else
+# define Assert(cond,msg)
+# define Trace(x)
+# define Tracev(x)
+# define Tracevv(x)
+# define Tracec(c,x)
+# define Tracecv(c,x)
+#endif
+
+
+typedef uLong (ZEXPORT *check_func) OF((uLong check, const Bytef *buf,
+ uInt len));
+local voidpf zcalloc OF((voidpf opaque, unsigned items, unsigned size));
+local void zcfree OF((voidpf opaque, voidpf ptr));
+
+#define ZALLOC(strm, items, size) \
+ (*((strm)->zalloc))((strm)->opaque, (items), (size))
+#define ZFREE(strm, addr) (*((strm)->zfree))((strm)->opaque, (voidpf)(addr))
+#define TRY_FREE(s, p) {if (p) ZFREE(s, p);}
+
+#endif /* _Z_UTIL_H */
--- /dev/null
+++ b/libinterp/NOTICE
@@ -1,0 +1,17 @@
+Copyright © 1995-1999 Lucent Technologies Inc.
+Portions Copyright © 1997-2000 Vita Nuova Limited
+Portions Copyright © 2000-2009 Vita Nuova Holdings Limited
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU Lesser General Public License (`LGPL') as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
--- /dev/null
+++ b/libinterp/README
@@ -1,0 +1,1 @@
+comp-68020.c has not been tested recently
--- /dev/null
+++ b/libinterp/alt.c
@@ -1,0 +1,294 @@
+#include "lib9.h"
+#include "isa.h"
+#include "interp.h"
+#include "raise.h"
+
+#define OP(fn) void fn(void)
+#define W(p) *((WORD*)(p))
+
+#define CANGET(c) ((c)->size > 0)
+#define CANPUT(c) ((c)->buf != H && (c)->size < (c)->buf->len)
+
+extern OP(isend);
+extern OP(irecv);
+
+/*
+ * Count the number of ready channels in an array of channels
+ * Set each channel's alt pointer to the owning prog
+ */
+static int
+altmark(Channel *c, Prog *p)
+{
+ int nrdy;
+ Array *a;
+ Channel **ca, **ec;
+
+ nrdy = 0;
+ a = (Array*)c;
+ ca = (Channel**)a->data;
+ ec = ca + a->len;
+ while(ca < ec) {
+ c = *ca;
+ if(c != H) {
+ if(c->send->prog || CANGET(c))
+ nrdy++;
+ cqadd(&c->recv, p);
+ }
+ ca++;
+ }
+
+ return nrdy;
+}
+
+/*
+ * Remove alt references to an array of channels
+ */
+static void
+altunmark(Channel *c, WORD *ptr, Prog *p, int sr, Channel **sel, int dn)
+{
+ int n;
+ Array *a;
+ Channel **ca, **ec;
+
+ n = 0;
+ a = (Array*)c;
+ ca = (Channel**)a->data;
+ ec = ca + a->len;
+ while(ca < ec) {
+ c = *ca;
+ if(c != H && c->recv->prog)
+ cqdelp(&c->recv, p);
+ if(sr == 1 && *sel == c) {
+ W(p->R.d) = dn;
+ p->ptr = ptr + 1;
+ ptr[0] = n;
+ *sel = nil;
+ }
+ ca++;
+ n++;
+ }
+}
+
+/*
+ * ALT Pass 1 - Count the number of ready channels and mark
+ * each channel as ALT by this prog
+ */
+static int
+altrdy(Alt *a, Prog *p)
+{
+ char *e;
+ Type *t;
+ int nrdy;
+ Channel *c;
+ Altc *ac, *eac;
+
+ e = nil;
+ nrdy = 0;
+
+ ac = a->ac + a->nsend;
+ eac = ac + a->nrecv;
+ while(ac < eac) {
+ c = ac->c;
+ ac++;
+ if(c == H) {
+ e = exNilref;
+ continue;
+ }
+ t = D2H(c)->t;
+ if(t == &Tarray)
+ nrdy += altmark(c, p);
+ else {
+ if(c->send->prog || CANGET(c))
+ nrdy++;
+ cqadd(&c->recv, p);
+ }
+ }
+
+ ac = a->ac;
+ eac = ac + a->nsend;
+ while(ac < eac) {
+ c = ac->c;
+ ac++;
+ if(c == H) {
+ e = exNilref;
+ continue;
+ }
+ if(c->recv->prog || CANPUT(c)) {
+ if(c->recv->prog == p) {
+ e = exAlt;
+ continue;
+ }
+ nrdy++;
+ }
+ cqadd(&c->send, p);
+ }
+
+ if(e != nil) {
+ altdone(a, p, nil, -1);
+ error(e);
+ }
+
+ return nrdy;
+}
+
+/*
+ * ALT Pass 3 - Pull out of an ALT cancelling the channel pointers in each item
+ */
+void
+altdone(Alt *a, Prog *p, Channel *sel, int sr)
+{
+ int n;
+ Type *t;
+ Channel *c;
+ Altc *ac, *eac;
+
+ n = 0;
+ ac = a->ac;
+ eac = a->ac + a->nsend;
+ while(ac < eac) {
+ c = ac->c;
+ if(c != H) {
+ if(c->send->prog)
+ cqdelp(&c->send, p);
+ if(sr == 0 && c == sel) {
+ p->ptr = ac->ptr;
+ W(p->R.d) = n;
+ sel = nil;
+ }
+ }
+ ac++;
+ n++;
+ }
+
+ eac = a->ac + a->nsend + a->nrecv;
+ while(ac < eac) {
+ c = ac->c;
+ if(c != H) {
+ t = D2H(c)->t;
+ if(t == &Tarray)
+ altunmark(c, ac->ptr, p, sr, &sel, n);
+ else {
+ if(c->recv->prog)
+ cqdelp(&c->recv, p);
+ if(sr == 1 && c == sel) {
+ p->ptr = ac->ptr;
+ W(p->R.d) = n;
+ sel = nil;
+ }
+ }
+ }
+ ac++;
+ n++;
+ }
+}
+
+/*
+ * ALT Pass 2 - Perform the communication on the chosen channel
+ */
+static void
+altcomm(Alt *a, int which)
+{
+ Type *t;
+ Array *r;
+ int n, an;
+ WORD *ptr;
+ Altc *ac, *eac;
+ Channel *c, **ca, **ec;
+
+ n = 0;
+ ac = a->ac;
+ eac = ac + a->nsend;
+ while(ac < eac) {
+ c = ac->c;
+ if((c->recv->prog != nil || CANPUT(c)) && which-- == 0) {
+ W(R.d) = n;
+ R.s = ac->ptr;
+ R.d = &c;
+ isend();
+ return;
+ }
+ ac++;
+ n++;
+ }
+
+ eac = eac + a->nrecv;
+ while(ac < eac) {
+ c = ac->c;
+ t = D2H(c)->t;
+ if(t == &Tarray) {
+ an = 0;
+ r = (Array*)c;
+ ca = (Channel**)r->data;
+ ec = ca + r->len;
+ while(ca < ec) {
+ c = *ca;
+ if(c != H && (c->send->prog != nil || CANGET(c)) && which-- == 0) {
+ W(R.d) = n;
+ R.s = &c;
+ ptr = ac->ptr;
+ R.d = ptr + 1;
+ ptr[0] = an;
+ irecv();
+ return;
+ }
+ ca++;
+ an++;
+ }
+ }
+ else
+ if((c->send->prog != nil || CANGET(c)) && which-- == 0) {
+ W(R.d) = n;
+ R.s = &c;
+ R.d = ac->ptr;
+ irecv();
+ return;
+ }
+ ac++;
+ n++;
+ }
+ return;
+}
+
+void
+altgone(Prog *p)
+{
+ Alt *a;
+
+ if (p->state == Palt) {
+ a = p->R.s;
+ altdone(a, p, nil, -1);
+ p->kill = "alt channel hungup";
+ addrun(p);
+ }
+}
+
+void
+xecalt(int block)
+{
+ Alt *a;
+ Prog *p;
+ int nrdy;
+ static ulong xrand = 0x20342;
+
+ p = currun();
+
+ a = R.s;
+ nrdy = altrdy(a, p);
+ if(nrdy == 0) {
+ if(block) {
+ delrun(Palt);
+ p->R.s = R.s;
+ p->R.d = R.d;
+ R.IC = 1;
+ R.t = 1;
+ return;
+ }
+ W(R.d) = a->nsend + a->nrecv;
+ altdone(a, p, nil, -1);
+ return;
+ }
+
+ xrand = xrand*1103515245 + 12345;
+ altcomm(a, (xrand>>8)%nrdy);
+ altdone(a, p, nil, -1);
+}
--- /dev/null
+++ b/libinterp/comp-386.c
@@ -1,0 +1,1991 @@
+#include "lib9.h"
+#include "isa.h"
+#include "interp.h"
+#include "raise.h"
+
+#define DOT ((ulong)code)
+
+#define RESCHED 1 /* check for interpreter reschedule */
+
+enum
+{
+ RAX = 0,
+ RAH = 4,
+ RCX = 1,
+ RDX = 2,
+ RBX = 3,
+ RSP = 4,
+ RBP = 5,
+ RSI = 6,
+ RDI = 7,
+
+ RFP = RSI,
+ RMP = RDI,
+ RTA = RDX,
+ RTMP = RBX,
+
+ Omovzxb = 0xb6,
+ Omovzxw = 0xb7,
+ Osal = 0xd1,
+ Oaddf = 0xdc,
+ Ocall = 0xe8,
+ Ocallrm = 0xff,
+ Ocdq = 0x99,
+ Ocld = 0xfc,
+ Ocmpb = 0x38,
+ Ocmpw = 0x39,
+ Ocmpi = 0x83,
+ Odecrm = 0xff,
+ Oincr = 0x40,
+ Oincrm = 0xff,
+ Ojccl = 0x83,
+ Ojcsl = 0x82,
+ Ojeqb = 0x74,
+ Ojeql = 0x84,
+ Ojgel = 0x8d,
+ Ojgtl = 0x8f,
+ Ojhil = 0x87,
+ Ojlel = 0x8e,
+ Ojlsl = 0x86,
+ Ojltl = 0x8c,
+ Ojol = 0x80,
+ Ojnol = 0x81,
+ Ojbl = 0x82,
+ Ojael = 0x83,
+ Ojal = 0x87,
+ Ojnel = 0x85,
+ Ojbel = 0x86,
+ Ojneb = 0x75,
+ Ojgtb = 0x7f,
+ Ojgeb = 0x7d,
+ Ojleb = 0x7e,
+ Ojltb = 0x7c,
+ Ojmp = 0xe9,
+ Ojmpb = 0xeb,
+ Ojmprm = 0xff,
+ Oldb = 0x8a,
+ Olds = 0x89,
+ Oldw = 0x8b,
+ Olea = 0x8d,
+ Otestib = 0xf6,
+ Oshld = 0xa5,
+ Oshrd = 0xad,
+ Osar = 0xd3,
+ Osarimm = 0xc1,
+ Omov = 0xc7,
+ Omovf = 0xdd,
+ Omovimm = 0xb8,
+ Omovsb = 0xa4,
+ Orep = 0xf3,
+ Oret = 0xc3,
+ Oshl = 0xd3,
+ Oshr = 0xd1,
+ Ostb = 0x88,
+ Ostw = 0x89,
+ Osubf = 0xdc,
+ Oxchg = 0x87,
+ OxchgAX = 0x90,
+ Oxor = 0x31,
+ Opopl = 0x58,
+ Opushl = 0x50,
+ Opushrm = 0xff,
+ Oneg = 0xf7,
+
+ SRCOP = (1<<0),
+ DSTOP = (1<<1),
+ WRTPC = (1<<2),
+ TCHECK = (1<<3),
+ NEWPC = (1<<4),
+ DBRAN = (1<<5),
+ THREOP = (1<<6),
+
+ ANDAND = 1,
+ OROR = 2,
+ EQAND = 3,
+
+ MacFRP = 0,
+ MacRET = 1,
+ MacCASE = 2,
+ MacCOLR = 3,
+ MacMCAL = 4,
+ MacFRAM = 5,
+ MacMFRA = 6,
+ MacRELQ = 7,
+ NMACRO
+};
+
+static uchar* code;
+static uchar* base;
+static ulong* patch;
+static int pass;
+static Module* mod;
+static uchar* tinit;
+static ulong* litpool;
+static int nlit;
+static void macfrp(void);
+static void macret(void);
+static void maccase(void);
+static void maccolr(void);
+static void macmcal(void);
+static void macfram(void);
+static void macmfra(void);
+static void macrelq(void);
+static ulong macro[NMACRO];
+ void (*comvec)(void);
+extern void das(uchar*, int);
+
+#define T(r) *((void**)(R.r))
+
+struct
+{
+ int idx;
+ void (*gen)(void);
+} mactab[] =
+{
+ MacFRP, macfrp, /* decrement and free pointer */
+ MacRET, macret, /* return instruction */
+ MacCASE, maccase, /* case instruction */
+ MacCOLR, maccolr, /* increment and color pointer */
+ MacMCAL, macmcal, /* mcall bottom half */
+ MacFRAM, macfram, /* frame instruction */
+ MacMFRA, macmfra, /* punt mframe because t->initialize==0 */
+ MacRELQ, macrelq, /* reschedule */
+};
+
+static void
+bounds(void)
+{
+ error(exBounds);
+}
+
+static void
+rdestroy(void)
+{
+ destroy(R.s);
+}
+
+static void
+rmcall(void)
+{
+ Prog *p;
+ Frame *f;
+
+ if((void*)R.dt == H)
+ error(exModule);
+
+ f = (Frame*)R.FP;
+ if(f == H)
+ error(exModule);
+
+ f->mr = nil;
+ ((void(*)(Frame*))R.dt)(f);
+ R.SP = (uchar*)f;
+ R.FP = f->fp;
+ if(f->t == nil)
+ unextend(f);
+ else
+ freeptrs(f, f->t);
+ p = currun();
+ if(p->kill != nil)
+ error(p->kill);
+}
+
+static void
+rmfram(void)
+{
+ Type *t;
+ Frame *f;
+ uchar *nsp;
+
+ t = (Type*)R.s;
+ if(t == H)
+ error(exModule);
+
+ nsp = R.SP + t->size;
+ if(nsp >= R.TS) {
+ R.s = t;
+ extend();
+ T(d) = R.s;
+ return;
+ }
+ f = (Frame*)R.SP;
+ R.SP = nsp;
+ f->t = t;
+ f->mr = nil;
+ initmem(t, f);
+ T(d) = f;
+}
+
+static int
+bc(int o)
+{
+ if(o < 127 && o > -128)
+ return 1;
+ return 0;
+}
+
+static void
+urk(void)
+{
+ error(exCompile);
+}
+
+static void
+genb(uchar o)
+{
+ *code++ = o;
+}
+
+static void
+gen2(uchar o1, uchar o2)
+{
+ code[0] = o1;
+ code[1] = o2;
+ code += 2;
+}
+
+static void
+genw(ulong o)
+{
+ *(ulong*)code = o;
+ code += 4;
+}
+
+static void
+modrm(int inst, ulong disp, int rm, int r)
+{
+ *code++ = inst;
+ if(disp == 0) {
+ *code++ = (0<<6)|(r<<3)|rm;
+ return;
+ }
+ if(bc(disp)) {
+ code[0] = (1<<6)|(r<<3)|rm;
+ code[1] = disp;
+ code += 2;
+ return;
+ }
+ *code++ = (2<<6)|(r<<3)|rm;
+ *(ulong*)code = disp;
+ code += 4;
+}
+
+static void
+con(ulong o, int r)
+{
+ if(o == 0) {
+ gen2(Oxor, (3<<6)|(r<<3)|r);
+ return;
+ }
+ genb(Omovimm+r);
+ genw(o);
+}
+
+static void
+opwld(Inst *i, int mi, int r)
+{
+ int ir, rta;
+
+ switch(UXSRC(i->add)) {
+ default:
+ print("%D\n", i);
+ urk();
+ case SRC(AFP):
+ modrm(mi, i->s.ind, RFP, r);
+ return;
+ case SRC(AMP):
+ modrm(mi, i->s.ind, RMP, r);
+ return;
+ case SRC(AIMM):
+ con(i->s.imm, r);
+ return;
+ case SRC(AIND|AFP):
+ ir = RFP;
+ break;
+ case SRC(AIND|AMP):
+ ir = RMP;
+ break;
+ }
+ rta = RTA;
+ if(mi == Olea)
+ rta = r;
+ modrm(Oldw, i->s.i.f, ir, rta);
+ modrm(mi, i->s.i.s, rta, r);
+}
+
+static void
+opwst(Inst *i, int mi, int r)
+{
+ int ir, rta;
+
+ switch(UXDST(i->add)) {
+ default:
+ print("%D\n", i);
+ urk();
+ case DST(AIMM):
+ con(i->d.imm, r);
+ return;
+ case DST(AFP):
+ modrm(mi, i->d.ind, RFP, r);
+ return;
+ case DST(AMP):
+ modrm(mi, i->d.ind, RMP, r);
+ return;
+ case DST(AIND|AFP):
+ ir = RFP;
+ break;
+ case DST(AIND|AMP):
+ ir = RMP;
+ break;
+ }
+ rta = RTA;
+ if(mi == Olea)
+ rta = r;
+ modrm(Oldw, i->d.i.f, ir, rta);
+ modrm(mi, i->d.i.s, rta, r);
+}
+
+static void
+bra(ulong dst, int op)
+{
+ dst -= (DOT+5);
+ genb(op);
+ genw(dst);
+}
+
+static void
+rbra(ulong dst, int op)
+{
+ dst += (ulong)base;
+ dst -= DOT+5;
+ genb(op);
+ genw(dst);
+}
+
+static void
+literal(ulong imm, int roff)
+{
+ nlit++;
+
+ genb(Omovimm+RAX);
+ genw((ulong)litpool);
+ modrm(Ostw, roff, RTMP, RAX);
+
+ if(pass == 0)
+ return;
+
+ *litpool = imm;
+ litpool++;
+}
+
+static void
+punt(Inst *i, int m, void (*fn)(void))
+{
+ ulong pc;
+
+ con((ulong)&R, RTMP);
+
+ if(m & SRCOP) {
+ if(UXSRC(i->add) == SRC(AIMM))
+ literal(i->s.imm, O(REG, s));
+ else {
+ opwld(i, Olea, RAX);
+ modrm(Ostw, O(REG, s), RTMP, RAX);
+ }
+ }
+
+ if(m & DSTOP) {
+ opwst(i, Olea, 0);
+ modrm(Ostw, O(REG, d), RTMP, RAX);
+ }
+ if(m & WRTPC) {
+ modrm(Omov, O(REG, PC), RTMP, 0);
+ pc = patch[i-mod->prog+1];
+ genw((ulong)base + pc);
+ }
+ if(m & DBRAN) {
+ pc = patch[(Inst*)i->d.imm-mod->prog];
+ literal((ulong)base+pc, O(REG, d));
+ }
+
+ switch(i->add&ARM) {
+ case AXNON:
+ if(m & THREOP) {
+ modrm(Oldw, O(REG, d), RTMP, RAX);
+ modrm(Ostw, O(REG, m), RTMP, RAX);
+ }
+ break;
+ case AXIMM:
+ literal((short)i->reg, O(REG, m));
+ break;
+ case AXINF:
+ modrm(Olea, i->reg, RFP, RAX);
+ modrm(Ostw, O(REG, m), RTMP, RAX);
+ break;
+ case AXINM:
+ modrm(Olea, i->reg, RMP, RAX);
+ modrm(Ostw, O(REG, m), RTMP, RAX);
+ break;
+ }
+ modrm(Ostw, O(REG, FP), RTMP, RFP);
+
+ bra((ulong)fn, Ocall);
+
+ con((ulong)&R, RTMP);
+ if(m & TCHECK) {
+ modrm(Ocmpi, O(REG, t), RTMP, 7);// CMPL $0, R.t
+ genb(0x00);
+ gen2(Ojeqb, 0x06); // JEQ .+6
+ genb(Opopl+RDI);
+ genb(Opopl+RSI);
+ genb(Opopl+RDX);
+ genb(Opopl+RCX);
+ genb(Opopl+RBX);
+ genb(Oret);
+ }
+
+ modrm(Oldw, O(REG, FP), RTMP, RFP);
+ modrm(Oldw, O(REG, MP), RTMP, RMP);
+
+ if(m & NEWPC) {
+ modrm(Oldw, O(REG, PC), RTMP, RAX);
+ gen2(Ojmprm, (3<<6)|(4<<3)|RAX);
+ }
+}
+
+static void
+mid(Inst *i, uchar mi, int r)
+{
+ int ir;
+
+ switch(i->add&ARM) {
+ default:
+ opwst(i, mi, r);
+ return;
+ case AXIMM:
+ con((short)i->reg, r);
+ return;
+ case AXINF:
+ ir = RFP;
+ break;
+ case AXINM:
+ ir = RMP;
+ break;
+ }
+ modrm(mi, i->reg, ir, r);
+}
+
+static void
+arith(Inst *i, int op2, int rm)
+{
+ if(UXSRC(i->add) != SRC(AIMM)) {
+ if(i->add&ARM) {
+ mid(i, Oldw, RAX);
+ opwld(i, op2|2, 0);
+ opwst(i, Ostw, 0);
+ return;
+ }
+ opwld(i, Oldw, RAX);
+ opwst(i, op2, 0);
+ return;
+ }
+ if(i->add&ARM) {
+ mid(i, Oldw, RAX);
+ if(bc(i->s.imm)) {
+ gen2(0x83, (3<<6)|(rm<<3)|RAX);
+ genb(i->s.imm);
+ }
+ else {
+ gen2(0x81, (3<<6)|(rm<<3)|RAX);
+ genw(i->s.imm);
+ }
+ opwst(i, Ostw, RAX);
+ return;
+ }
+ if(bc(i->s.imm)) {
+ opwst(i, 0x83, rm);
+ genb(i->s.imm);
+ return;
+ }
+ opwst(i, 0x81, rm);
+ genw(i->s.imm);
+}
+
+static void
+arithb(Inst *i, int op2)
+{
+ if(UXSRC(i->add) == SRC(AIMM))
+ urk();
+
+ if(i->add&ARM) {
+ mid(i, Oldb, RAX);
+ opwld(i, op2|2, 0);
+ opwst(i, Ostb, 0);
+ return;
+ }
+ opwld(i, Oldb, RAX);
+ opwst(i, op2, RAX);
+}
+
+static void
+shift(Inst *i, int ld, int st, int op, int r)
+{
+ mid(i, ld, RAX);
+ opwld(i, Oldw, RCX);
+ gen2(op, (3<<6)|(r<<3)|RAX);
+ opwst(i, st, RAX);
+}
+
+static void
+arithf(Inst *i, int op)
+{
+ opwld(i, Omovf, 0);
+ mid(i, 0xdc, op);
+ opwst(i, Omovf, 3);
+}
+
+static void
+cmpl(int r, ulong v)
+{
+ if(bc(v)) {
+ gen2(0x83, (3<<6)|(7<<3)|r);
+ genb(v);
+ return;
+ }
+ gen2(0x81, (3<<6)|(7<<3)|r);
+ genw(v);
+}
+
+static int
+swapbraop(int b)
+{
+ switch(b) {
+ case Ojgel:
+ return Ojlel;
+ case Ojlel:
+ return Ojgel;
+ case Ojgtl:
+ return Ojltl;
+ case Ojltl:
+ return Ojgtl;
+ }
+ return b;
+}
+
+static void
+schedcheck(Inst *i)
+{
+ if(RESCHED && i->d.ins <= i){
+ con((ulong)&R, RTMP);
+ /* sub $1, R.IC */
+ modrm(0x83, O(REG, IC), RTMP, 5);
+ genb(1);
+ gen2(Ojgtb, 5);
+ rbra(macro[MacRELQ], Ocall);
+ }
+}
+
+static void
+cbra(Inst *i, int jmp)
+{
+ if(RESCHED)
+ schedcheck(i);
+ mid(i, Oldw, RAX);
+ if(UXSRC(i->add) == SRC(AIMM)) {
+ cmpl(RAX, i->s.imm);
+ jmp = swapbraop(jmp);
+ }
+ else
+ opwld(i, Ocmpw, RAX);
+ genb(0x0f);
+ rbra(patch[i->d.ins-mod->prog], jmp);
+}
+
+static void
+cbral(Inst *i, int jmsw, int jlsw, int mode)
+{
+ ulong dst;
+ uchar *label;
+
+ if(RESCHED)
+ schedcheck(i);
+ opwld(i, Olea, RTMP);
+ mid(i, Olea, RTA);
+ modrm(Oldw, 4, RTA, RAX);
+ modrm(Ocmpw, 4, RTMP, RAX);
+ label = 0;
+ dst = patch[i->d.ins-mod->prog];
+ switch(mode) {
+ case ANDAND:
+ gen2(Ojneb, 0);
+ label = code-1;
+ break;
+ case OROR:
+ genb(0x0f);
+ rbra(dst, jmsw);
+ break;
+ case EQAND:
+ genb(0x0f);
+ rbra(dst, jmsw);
+ gen2(Ojneb, 0);
+ label = code-1;
+ break;
+ }
+ modrm(Oldw, 0, RTA, RAX);
+ modrm(Ocmpw, 0, RTMP, RAX);
+ genb(0x0f);
+ rbra(dst, jlsw);
+ if(label != nil)
+ *label = code-label-1;
+}
+
+static void
+cbrab(Inst *i, int jmp)
+{
+ if(RESCHED)
+ schedcheck(i);
+ mid(i, Oldb, RAX);
+ if(UXSRC(i->add) == SRC(AIMM))
+ urk();
+
+ opwld(i, Ocmpb, RAX);
+ genb(0x0f);
+ rbra(patch[i->d.ins-mod->prog], jmp);
+}
+
+static void
+cbraf(Inst *i, int jmp)
+{
+ if(RESCHED)
+ schedcheck(i);
+ opwld(i, Omovf, 0);
+ mid(i, 0xdc, 3); // FCOMP
+ genb(0x9b); // FWAIT
+ gen2(0xdf, 0xe0); // FSTSW AX
+ genb(0x9e); // SAHF
+
+ genb(0x0f);
+ rbra(patch[i->d.ins-mod->prog], jmp);
+}
+
+static void
+comcase(Inst *i, int w)
+{
+ int l;
+ WORD *t, *e;
+
+ if(w != 0) {
+ opwld(i, Oldw, RAX); // v
+ genb(Opushl+RSI);
+ opwst(i, Olea, RSI); // table
+ rbra(macro[MacCASE], Ojmp);
+ }
+
+ t = (WORD*)(mod->origmp+i->d.ind+4);
+ l = t[-1];
+
+ /* have to take care not to relocate the same table twice -
+ * the limbo compiler can duplicate a case instruction
+ * during its folding phase
+ */
+
+ if(pass == 0) {
+ if(l >= 0)
+ t[-1] = -l-1; /* Mark it not done */
+ return;
+ }
+ if(l >= 0) /* Check pass 2 done */
+ return;
+ t[-1] = -l-1; /* Set real count */
+ e = t + t[-1]*3;
+ while(t < e) {
+ t[2] = (ulong)base + patch[t[2]];
+ t += 3;
+ }
+ t[0] = (ulong)base + patch[t[0]];
+}
+
+static void
+comcasel(Inst *i)
+{
+ int l;
+ WORD *t, *e;
+
+ t = (WORD*)(mod->origmp+i->d.ind+8);
+ l = t[-2];
+ if(pass == 0) {
+ if(l >= 0)
+ t[-2] = -l-1; /* Mark it not done */
+ return;
+ }
+ if(l >= 0) /* Check pass 2 done */
+ return;
+ t[-2] = -l-1; /* Set real count */
+ e = t + t[-2]*6;
+ while(t < e) {
+ t[4] = (ulong)base + patch[t[4]];
+ t += 6;
+ }
+ t[0] = (ulong)base + patch[t[0]];
+}
+
+static void
+commframe(Inst *i)
+{
+ int o;
+ uchar *punt, *mlnil;
+
+ opwld(i, Oldw, RAX);
+ cmpl(RAX, (ulong)H);
+ gen2(Ojeqb, 0);
+ mlnil = code - 1;
+ if((i->add&ARM) == AXIMM) {
+ o = OA(Modlink, links)+i->reg*sizeof(Modl)+O(Modl, frame);
+ modrm(Oldw, o, RAX, RTA);
+ } else {
+ gen2(Oldw, (3<<6)|(RTMP<<3)|RAX); // MOVL AX, RTMP
+ mid(i, Oldw, RCX); // index
+ gen2(Olea, (0<<6)|(0<<3)|4); // lea (AX)(RCX*8)
+ genb((3<<6)|(RCX<<3)|RAX); // assumes sizeof(Modl) == 8 hence 3
+ o = OA(Modlink, links)+O(Modl, frame);
+ modrm(Oldw, o, RAX, RTA); // frame
+ genb(OxchgAX+RTMP); // get old AX back
+ }
+ modrm(0x83, O(Type, initialize), RTA, 7);
+ genb(0);
+ gen2(Ojneb, 0);
+ punt = code - 1;
+ genb(OxchgAX+RTA);
+ opwst(i, Olea, RTA);
+ *mlnil = code-mlnil-1;
+ rbra(macro[MacMFRA], Ocall);
+ rbra(patch[i-mod->prog+1], Ojmp);
+
+ *punt = code-punt-1;
+ rbra(macro[MacFRAM], Ocall);
+ opwst(i, Ostw, RCX);
+}
+
+static void
+commcall(Inst *i)
+{
+ uchar *mlnil;
+
+ con((ulong)&R, RTMP); // MOVL $R, RTMP
+ opwld(i, Oldw, RCX);
+ modrm(Omov, O(Frame, lr), RCX, 0); // MOVL $.+1, lr(CX) f->lr = R.PC
+ genw((ulong)base+patch[i-mod->prog+1]);
+ modrm(Ostw, O(Frame, fp), RCX, RFP); // MOVL RFP, fp(CX) f->fp = R.FP
+ modrm(Oldw, O(REG, M), RTMP, RTA); // MOVL R.M, RTA
+ modrm(Ostw, O(Frame, mr), RCX, RTA); // MOVL RTA, mr(CX) f->mr = R.M
+ opwst(i, Oldw, RTA); // MOVL ml, RTA
+ cmpl(RTA, (ulong)H);
+ gen2(Ojeqb, 0);
+ mlnil = code - 1;
+ if((i->add&ARM) == AXIMM)
+ modrm(Oldw, OA(Modlink, links)+i->reg*sizeof(Modl)+O(Modl, u.pc), RTA, RAX);
+ else {
+ genb(Opushl+RCX);
+ mid(i, Oldw, RCX); // index
+ gen2(Olea, (0<<6)|(0<<3)|4); // lea (RTA)(RCX*8)
+ genb((3<<6)|(RCX<<3)|RTA); // assumes sizeof(Modl) == 8 hence 3
+ modrm(Oldw, OA(Modlink, links)+O(Modl, u.pc), RAX, RAX);
+ genb(Opopl+RCX);
+ }
+ *mlnil = code-mlnil-1;
+ rbra(macro[MacMCAL], Ocall);
+}
+
+static void
+larith(Inst *i, int op, int opc)
+{
+ opwld(i, Olea, RTMP);
+ mid(i, Olea, RTA);
+ modrm(Oldw, 0, RTA, RAX); // MOVL 0(RTA), AX
+ modrm(op, 0, RTMP, RAX); // ADDL 0(RTMP), AX
+ modrm(Oldw, 4, RTA, RCX); // MOVL 4(RTA), CX
+ modrm(opc, 4, RTMP, RCX); // ADCL 4(RTMP), CX
+ if((i->add&ARM) != AXNON)
+ opwst(i, Olea, RTA);
+ modrm(Ostw, 0, RTA, RAX);
+ modrm(Ostw, 4, RTA, RCX);
+}
+
+static void
+shll(Inst *i)
+{
+ uchar *label, *label1;
+
+ opwld(i, Oldw, RCX);
+ mid(i, Olea, RTA);
+ gen2(Otestib, (3<<6)|(0<<3)|RCX);
+ genb(0x20);
+ gen2(Ojneb, 0);
+ label = code-1;
+ modrm(Oldw, 0, RTA, RAX);
+ modrm(Oldw, 4, RTA, RBX);
+ genb(0x0f);
+ gen2(Oshld, (3<<6)|(RAX<<3)|RBX);
+ gen2(Oshl, (3<<6)|(4<<3)|RAX);
+ gen2(Ojmpb, 0);
+ label1 = code-1;
+ *label = code-label-1;
+ modrm(Oldw, 0, RTA, RBX);
+ con(0, RAX);
+ gen2(Oshl, (3<<6)|(4<<3)|RBX);
+ *label1 = code-label1-1;
+ opwst(i, Olea, RTA);
+ modrm(Ostw, 0, RTA, RAX);
+ modrm(Ostw, 4, RTA, RBX);
+}
+
+static void
+shrl(Inst *i)
+{
+ uchar *label, *label1;
+
+ opwld(i, Oldw, RCX);
+ mid(i, Olea, RTA);
+ gen2(Otestib, (3<<6)|(0<<3)|RCX);
+ genb(0x20);
+ gen2(Ojneb, 0);
+ label = code-1;
+ modrm(Oldw, 0, RTA, RAX);
+ modrm(Oldw, 4, RTA, RBX);
+ genb(0x0f);
+ gen2(Oshrd, (3<<6)|(RBX<<3)|RAX);
+ gen2(Osar, (3<<6)|(7<<3)|RBX);
+ gen2(Ojmpb, 0);
+ label1 = code-1;
+ *label = code-label-1;
+ modrm(Oldw, 4, RTA, RBX);
+ gen2(Oldw, (3<<6)|(RAX<<3)|RBX);
+ gen2(Osarimm, (3<<6)|(7<<3)|RBX);
+ genb(0x1f);
+ gen2(Osar, (3<<6)|(7<<3)|RAX);
+ *label1 = code-label1-1;
+ opwst(i, Olea, RTA);
+ modrm(Ostw, 0, RTA, RAX);
+ modrm(Ostw, 4, RTA, RBX);
+}
+
+static
+void
+compdbg(void)
+{
+ print("%s:%lud@%.8lux\n", R.M->m->name, *(ulong*)R.m, *(ulong*)R.s);
+}
+
+static void
+comp(Inst *i)
+{
+ int r;
+ WORD *t, *e;
+ char buf[64];
+
+ if(0) {
+ Inst xx;
+ xx.add = AXIMM|SRC(AIMM);
+ xx.s.imm = (ulong)code;
+ xx.reg = i-mod->prog;
+ punt(&xx, SRCOP, compdbg);
+ }
+
+ switch(i->op) {
+ default:
+ snprint(buf, sizeof buf, "%s compile, no '%D'", mod->name, i);
+ error(buf);
+ break;
+ case IMCALL:
+ if((i->add&ARM) == AXIMM)
+ commcall(i);
+ else
+ punt(i, SRCOP|DSTOP|THREOP|WRTPC|NEWPC, optab[i->op]);
+ break;
+ case ISEND:
+ case IRECV:
+ case IALT:
+ punt(i, SRCOP|DSTOP|TCHECK|WRTPC, optab[i->op]);
+ break;
+ case ISPAWN:
+ punt(i, SRCOP|DBRAN, optab[i->op]);
+ break;
+ case IBNEC:
+ case IBEQC:
+ case IBLTC:
+ case IBLEC:
+ case IBGTC:
+ case IBGEC:
+ punt(i, SRCOP|DBRAN|NEWPC|WRTPC, optab[i->op]);
+ break;
+ case ICASEC:
+ comcase(i, 0);
+ punt(i, SRCOP|DSTOP|NEWPC, optab[i->op]);
+ break;
+ case ICASEL:
+ comcasel(i);
+ punt(i, SRCOP|DSTOP|NEWPC, optab[i->op]);
+ break;
+ case IADDC:
+ case IMULL:
+ case IDIVL:
+ case IMODL:
+ case IMNEWZ:
+ case ILSRW:
+ case ILSRL:
+ punt(i, SRCOP|DSTOP|THREOP, optab[i->op]);
+ break;
+ case ILOAD:
+ case INEWA:
+ case INEWAZ:
+ case INEW:
+ case INEWZ:
+ case ISLICEA:
+ case ISLICELA:
+ case ICONSB:
+ case ICONSW:
+ case ICONSL:
+ case ICONSF:
+ case ICONSM:
+ case ICONSMP:
+ case ICONSP:
+ case IMOVMP:
+ case IHEADMP:
+ case IHEADL:
+ case IINSC:
+ case ICVTAC:
+ case ICVTCW:
+ case ICVTWC:
+ case ICVTLC:
+ case ICVTCL:
+ case ICVTFC:
+ case ICVTCF:
+ case ICVTRF:
+ case ICVTFR:
+ case ICVTWS:
+ case ICVTSW:
+ case IMSPAWN:
+ case ICVTCA:
+ case ISLICEC:
+ case INBALT:
+ punt(i, SRCOP|DSTOP, optab[i->op]);
+ break;
+ case INEWCM:
+ case INEWCMP:
+ punt(i, SRCOP|DSTOP|THREOP, optab[i->op]);
+ break;
+ case IMFRAME:
+ if((i->add&ARM) == AXIMM)
+ commframe(i);
+ else
+ punt(i, SRCOP|DSTOP|THREOP, optab[i->op]);
+ break;
+ case INEWCB:
+ case INEWCW:
+ case INEWCF:
+ case INEWCP:
+ case INEWCL:
+ punt(i, DSTOP|THREOP, optab[i->op]);
+ break;
+ case IEXIT:
+ punt(i, 0, optab[i->op]);
+ break;
+ case ICVTBW:
+ opwld(i, Oldb, RAX);
+ genb(0x0f);
+ gen2(0xb6, (3<<6)|(RAX<<3)|RAX);
+ opwst(i, Ostw, RAX);
+ break;
+ case ICVTWB:
+ opwld(i, Oldw, RAX);
+ opwst(i, Ostb, RAX);
+ break;
+ case ICVTFW:
+ if(1){
+ punt(i, SRCOP|DSTOP, optab[i->op]);
+ break;
+ }
+ opwld(i, Omovf, 0);
+ opwst(i, 0xdb, 3);
+ break;
+ case ICVTWF:
+ if(1){
+ punt(i, SRCOP|DSTOP, optab[i->op]);
+ break;
+ }
+ opwld(i, 0xdb, 0);
+ opwst(i, Omovf, 3);
+ break;
+ case ICVTLF:
+ if(1){
+ punt(i, SRCOP|DSTOP, optab[i->op]);
+ break;
+ }
+ opwld(i, 0xdf, 5);
+ opwst(i, Omovf, 3);
+ break;
+ case ICVTFL:
+ if(1){
+ punt(i, SRCOP|DSTOP, optab[i->op]);
+ break;
+ }
+ opwld(i, Omovf, 0);
+ opwst(i, 0xdf, 7);
+ break;
+ case IHEADM:
+ opwld(i, Oldw, RAX);
+ modrm(Olea, OA(List, data), RAX, RAX);
+ goto movm;
+ case IMOVM:
+ opwld(i, Olea, RAX);
+ movm:
+ opwst(i, Olea, RBX);
+ mid(i, Oldw, RCX);
+ genb(OxchgAX+RSI);
+ gen2(Oxchg, (3<<6)|(RDI<<3)|RBX);
+ genb(Ocld);
+ gen2(Orep, Omovsb);
+ genb(OxchgAX+RSI);
+ gen2(Oxchg, (3<<6)|(RDI<<3)|RBX);
+ break;
+ case IRET:
+ rbra(macro[MacRET], Ojmp);
+ break;
+ case IFRAME:
+ if(UXSRC(i->add) != SRC(AIMM)) {
+ punt(i, SRCOP|DSTOP, optab[i->op]);
+ break;
+ }
+ tinit[i->s.imm] = 1;
+ con((ulong)mod->type[i->s.imm], RTA);
+ rbra(macro[MacFRAM], Ocall);
+ opwst(i, Ostw, RCX);
+ break;
+ case ILEA:
+ if(UXSRC(i->add) == SRC(AIMM)) {
+ gen2(Ojmpb, 4);
+ genw(i->s.imm);
+ con((ulong)(code-4), RAX);
+ }
+ else
+ opwld(i, Olea, RAX);
+ opwst(i, Ostw, RAX);
+ break;
+ case IHEADW:
+ opwld(i, Oldw, RAX);
+ modrm(Oldw, OA(List, data), RAX, RAX);
+ opwst(i, Ostw, RAX);
+ break;
+ case IHEADF:
+ opwld(i, Oldw, RAX);
+ modrm(Omovf, OA(List, data), RAX, 0);
+ opwst(i, Omovf, 3);
+ break;
+ case IHEADB:
+ opwld(i, Oldw, RAX);
+ modrm(Oldb, OA(List, data), RAX, RAX);
+ opwst(i, Ostb, RAX);
+ break;
+ case ITAIL:
+ opwld(i, Oldw, RAX);
+ modrm(Oldw, O(List, tail), RAX, RBX);
+ goto movp;
+ case IMOVP:
+ case IHEADP:
+ opwld(i, Oldw, RBX);
+ if(i->op == IHEADP)
+ modrm(Oldw, OA(List, data), RBX, RBX);
+ movp:
+ cmpl(RBX, (ulong)H);
+ gen2(Ojeqb, 0x05);
+ rbra(macro[MacCOLR], Ocall);
+ opwst(i, Oldw, RAX);
+ opwst(i, Ostw, RBX);
+ rbra(macro[MacFRP], Ocall);
+ break;
+ case ILENA:
+ opwld(i, Oldw, RBX);
+ con(0, RAX);
+ cmpl(RBX, (ulong)H);
+ gen2(Ojeqb, 0x02);
+ modrm(Oldw, O(Array, len), RBX, RAX);
+ opwst(i, Ostw, RAX);
+ break;
+ case ILENC:
+ opwld(i, Oldw, RBX);
+ con(0, RAX);
+ cmpl(RBX, (ulong)H);
+ gen2(Ojeqb, 0x09);
+ modrm(Oldw, O(String, len), RBX, RAX);
+ cmpl(RAX, 0);
+ gen2(Ojgeb, 0x02);
+ gen2(Oneg, (3<<6)|(3<<3)|RAX);
+ opwst(i, Ostw, RAX);
+ break;
+ case ILENL:
+ con(0, RAX);
+ opwld(i, Oldw, RBX);
+ cmpl(RBX, (ulong)H);
+ gen2(Ojeqb, 0x05);
+ modrm(Oldw, O(List, tail), RBX, RBX);
+ genb(Oincr+RAX);
+ gen2(Ojmpb, 0xf6);
+ opwst(i, Ostw, RAX);
+ break;
+ case IBEQF:
+ cbraf(i, Ojeql);
+ break;
+ case IBNEF:
+ cbraf(i, Ojnel);
+ break;
+ case IBLEF:
+ cbraf(i, Ojlsl);
+ break;
+ case IBLTF:
+ cbraf(i, Ojcsl);
+ break;
+ case IBGEF:
+ cbraf(i, Ojccl);
+ break;
+ case IBGTF:
+ cbraf(i, Ojhil);
+ break;
+ case IBEQW:
+ cbra(i, Ojeql);
+ break;
+ case IBLEW:
+ cbra(i, Ojlel);
+ break;
+ case IBNEW:
+ cbra(i, Ojnel);
+ break;
+ case IBGTW:
+ cbra(i, Ojgtl);
+ break;
+ case IBLTW:
+ cbra(i, Ojltl);
+ break;
+ case IBGEW:
+ cbra(i, Ojgel);
+ break;
+ case IBEQB:
+ cbrab(i, Ojeql);
+ break;
+ case IBLEB:
+ cbrab(i, Ojlsl);
+ break;
+ case IBNEB:
+ cbrab(i, Ojnel);
+ break;
+ case IBGTB:
+ cbrab(i, Ojhil);
+ break;
+ case IBLTB:
+ cbrab(i, Ojbl);
+ break;
+ case IBGEB:
+ cbrab(i, Ojael);
+ break;
+ case ISUBW:
+ arith(i, 0x29, 5);
+ break;
+ case ISUBB:
+ arithb(i, 0x28);
+ break;
+ case ISUBF:
+ arithf(i, 5);
+ break;
+ case IADDW:
+ arith(i, 0x01, 0);
+ break;
+ case IADDB:
+ arithb(i, 0x00);
+ break;
+ case IADDF:
+ arithf(i, 0);
+ break;
+ case IORW:
+ arith(i, 0x09, 1);
+ break;
+ case IORB:
+ arithb(i, 0x08);
+ break;
+ case IANDW:
+ arith(i, 0x21, 4);
+ break;
+ case IANDB:
+ arithb(i, 0x20);
+ break;
+ case IXORW:
+ arith(i, Oxor, 6);
+ break;
+ case IXORB:
+ arithb(i, 0x30);
+ break;
+ case ISHLW:
+ shift(i, Oldw, Ostw, 0xd3, 4);
+ break;
+ case ISHLB:
+ shift(i, Oldb, Ostb, 0xd2, 4);
+ break;
+ case ISHRW:
+ shift(i, Oldw, Ostw, 0xd3, 7);
+ break;
+ case ISHRB:
+ shift(i, Oldb, Ostb, 0xd2, 5);
+ break;
+ case IMOVF:
+ opwld(i, Omovf, 0);
+ opwst(i, Omovf, 3);
+ break;
+ case INEGF:
+ opwld(i, Omovf, 0);
+ genb(0xd9);
+ genb(0xe0);
+ opwst(i, Omovf, 3);
+ break;
+ case IMOVB:
+ opwld(i, Oldb, RAX);
+ opwst(i, Ostb, RAX);
+ break;
+ case IMOVW:
+ case ICVTLW: // Little endian
+ if(UXSRC(i->add) == SRC(AIMM)) {
+ opwst(i, Omov, RAX);
+ genw(i->s.imm);
+ break;
+ }
+ opwld(i, Oldw, RAX);
+ opwst(i, Ostw, RAX);
+ break;
+ case ICVTWL:
+ opwst(i, Olea, RTMP);
+ opwld(i, Oldw, RAX);
+ modrm(Ostw, 0, RTMP, RAX);
+ genb(0x99);
+ modrm(Ostw, 4, RTMP, RDX);
+ break;
+ case ICALL:
+ if(UXDST(i->add) != DST(AIMM))
+ opwst(i, Oldw, RTA);
+ opwld(i, Oldw, RAX);
+ modrm(Omov, O(Frame, lr), RAX, 0); // MOVL $.+1, lr(AX)
+ genw((ulong)base+patch[i-mod->prog+1]);
+ modrm(Ostw, O(Frame, fp), RAX, RFP); // MOVL RFP, fp(AX)
+ gen2(Oldw, (3<<6)|(RFP<<3)|RAX); // MOVL AX,RFP
+ if(UXDST(i->add) != DST(AIMM)){
+ gen2(Ojmprm, (3<<6)|(4<<3)|RTA);
+ break;
+ }
+ /* no break */
+ case IJMP:
+ if(RESCHED)
+ schedcheck(i);
+ rbra(patch[i->d.ins-mod->prog], Ojmp);
+ break;
+ case IMOVPC:
+ opwst(i, Omov, RAX);
+ genw(patch[i->s.imm]+(ulong)base);
+ break;
+ case IGOTO:
+ opwst(i, Olea, RBX);
+ opwld(i, Oldw, RAX);
+ gen2(Ojmprm, (0<<6)|(4<<3)|4);
+ genb((2<<6)|(RAX<<3)|RBX);
+
+ if(pass == 0)
+ break;
+
+ t = (WORD*)(mod->origmp+i->d.ind);
+ e = t + t[-1];
+ t[-1] = 0;
+ while(t < e) {
+ t[0] = (ulong)base + patch[t[0]];
+ t++;
+ }
+ break;
+ case IMULF:
+ arithf(i, 1);
+ break;
+ case IDIVF:
+ arithf(i, 7);
+ break;
+ case IMODW:
+ case IDIVW:
+ case IMULW:
+ mid(i, Oldw, RAX);
+ opwld(i, Oldw, RTMP);
+ if(i->op == IMULW)
+ gen2(0xf7, (3<<6)|(4<<3)|RTMP);
+ else {
+ genb(Ocdq);
+ gen2(0xf7, (3<<6)|(7<<3)|RTMP); // IDIV AX, RTMP
+ if(i->op == IMODW)
+ genb(0x90+RDX); // XCHG AX, DX
+ }
+ opwst(i, Ostw, RAX);
+ break;
+ case IMODB:
+ case IDIVB:
+ case IMULB:
+ mid(i, Oldb, RAX);
+ opwld(i, Oldb, RTMP);
+ if(i->op == IMULB)
+ gen2(0xf6, (3<<6)|(4<<3)|RTMP);
+ else {
+ genb(Ocdq);
+ gen2(0xf6, (3<<6)|(7<<3)|RTMP); // IDIV AX, RTMP
+ if(i->op == IMODB)
+ genb(0x90+RDX); // XCHG AX, DX
+ }
+ opwst(i, Ostb, RAX);
+ break;
+ case IINDX:
+ opwld(i, Oldw, RTMP); // MOVW xx(s), BX
+
+ if(bflag){
+ opwst(i, Oldw, RAX);
+ modrm(0x3b, O(Array, len), RTMP, RAX); /* CMP index, len */
+ gen2(0x72, 5); /* JB */
+ bra((ulong)bounds, Ocall);
+ modrm(Oldw, O(Array, t), RTMP, RTA);
+ modrm(0xf7, O(Type, size), RTA, 5); /* IMULL AX, xx(t) */
+ }
+ else{
+ modrm(Oldw, O(Array, t), RTMP, RAX); // MOVW t(BX), AX
+ modrm(Oldw, O(Type, size), RAX, RAX); // MOVW size(AX), AX
+ if(UXDST(i->add) == DST(AIMM)) {
+ gen2(0x69, (3<<6)|(RAX<<3)|0);
+ genw(i->d.imm);
+ }
+ else
+ opwst(i, 0xf7, 5); // IMULL AX,xx(d)
+ }
+
+ modrm(0x03, O(Array, data), RBX, RAX); // ADDL data(BX), AX
+ r = RMP;
+ if((i->add&ARM) == AXINF)
+ r = RFP;
+ modrm(Ostw, i->reg, r, RAX);
+ break;
+ case IINDB:
+ r = 0;
+ goto idx;
+ case IINDF:
+ case IINDL:
+ r = 3;
+ goto idx;
+ case IINDW:
+ r = 2;
+ idx:
+ opwld(i, Oldw, RAX);
+ opwst(i, Oldw, RTMP);
+ if(bflag){
+ modrm(0x3b, O(Array, len), RAX, RTMP); /* CMP index, len */
+ gen2(0x72, 5); /* JB */
+ bra((ulong)bounds, Ocall);
+ }
+ modrm(Oldw, O(Array, data), RAX, RAX);
+ gen2(Olea, (0<<6)|(0<<3)|4); /* lea (AX)(RTMP*r) */
+ genb((r<<6)|(RTMP<<3)|RAX);
+ r = RMP;
+ if((i->add&ARM) == AXINF)
+ r = RFP;
+ modrm(Ostw, i->reg, r, RAX);
+ break;
+ case IINDC:
+ opwld(i, Oldw, RAX); // string
+ mid(i, Oldw, RBX); // index
+ if(bflag){
+ modrm(Oldw, O(String, len), RAX, RTA);
+ cmpl(RTA, 0);
+ gen2(Ojltb, 16);
+ gen2(0x3b, (3<<6)|(RBX<<3)|RTA); /* cmp index, len */
+ gen2(0x72, 5); /* JB */
+ bra((ulong)bounds, Ocall);
+ genb(0x0f);
+ gen2(Omovzxb, (1<<6)|(0<<3)|4);
+ gen2((0<<6)|(RBX<<3)|RAX, O(String, data));
+ gen2(Ojmpb, sizeof(Rune)==4? 10: 11);
+ gen2(Oneg, (3<<6)|(3<<3)|RTA);
+ gen2(0x3b, (3<<6)|(RBX<<3)|RTA); /* cmp index, len */
+ gen2(0x73, 0xee); /* JNB */
+ if(sizeof(Rune) == 4){
+ gen2(Oldw, (1<<6)|(0<<3)|4);
+ gen2((2<<6)|(RBX<<3)|RAX, O(String, data));
+ }else{
+ genb(0x0f);
+ gen2(Omovzxw, (1<<6)|(0<<3)|4);
+ gen2((1<<6)|(RBX<<3)|RAX, O(String, data));
+ }
+ opwst(i, Ostw, RAX);
+ break;
+ }
+ modrm(Ocmpi, O(String, len), RAX, 7);
+ genb(0);
+ gen2(Ojltb, 7);
+ genb(0x0f);
+ gen2(Omovzxb, (1<<6)|(0<<3)|4); /* movzbx 12(AX)(RBX*1), RAX */
+ gen2((0<<6)|(RBX<<3)|RAX, O(String, data));
+ if(sizeof(Rune) == 4){
+ gen2(Ojmpb, 4);
+ gen2(Oldw, (1<<6)|(0<<3)|4); /* movl 12(AX)(RBX*4), RAX */
+ gen2((2<<6)|(RBX<<3)|RAX, O(String, data));
+ }else{
+ gen2(Ojmpb, 5);
+ genb(0x0f);
+ gen2(Omovzxw, (1<<6)|(0<<3)|4); /* movzwx 12(AX)(RBX*2), RAX */
+ gen2((1<<6)|(RBX<<3)|RAX, O(String, data));
+ }
+ opwst(i, Ostw, RAX);
+ break;
+ case ICASE:
+ comcase(i, 1);
+ break;
+ case IMOVL:
+ opwld(i, Olea, RTA);
+ opwst(i, Olea, RTMP);
+ modrm(Oldw, 0, RTA, RAX);
+ modrm(Ostw, 0, RTMP, RAX);
+ modrm(Oldw, 4, RTA, RAX);
+ modrm(Ostw, 4, RTMP, RAX);
+ break;
+ case IADDL:
+ larith(i, 0x03, 0x13);
+ break;
+ case ISUBL:
+ larith(i, 0x2b, 0x1b);
+ break;
+ case IORL:
+ larith(i, 0x0b, 0x0b);
+ break;
+ case IANDL:
+ larith(i, 0x23, 0x23);
+ break;
+ case IXORL:
+ larith(i, 0x33, 0x33);
+ break;
+ case IBEQL:
+ cbral(i, Ojnel, Ojeql, ANDAND);
+ break;
+ case IBNEL:
+ cbral(i, Ojnel, Ojnel, OROR);
+ break;
+ case IBLEL:
+ cbral(i, Ojltl, Ojbel, EQAND);
+ break;
+ case IBGTL:
+ cbral(i, Ojgtl, Ojal, EQAND);
+ break;
+ case IBLTL:
+ cbral(i, Ojltl, Ojbl, EQAND);
+ break;
+ case IBGEL:
+ cbral(i, Ojgtl, Ojael, EQAND);
+ break;
+ case ISHLL:
+ shll(i);
+ break;
+ case ISHRL:
+ shrl(i);
+ break;
+ case IRAISE:
+ punt(i, SRCOP|WRTPC|NEWPC, optab[i->op]);
+ break;
+ case IMULX:
+ case IDIVX:
+ case ICVTXX:
+ case IMULX0:
+ case IDIVX0:
+ case ICVTXX0:
+ case IMULX1:
+ case IDIVX1:
+ case ICVTXX1:
+ case ICVTFX:
+ case ICVTXF:
+ case IEXPW:
+ case IEXPL:
+ case IEXPF:
+ punt(i, SRCOP|DSTOP|THREOP, optab[i->op]);
+ break;
+ case ISELF:
+ punt(i, DSTOP, optab[i->op]);
+ break;
+ }
+}
+
+static void
+preamble(void)
+{
+ if(comvec)
+ return;
+
+ comvec = malloc(32);
+ if(comvec == nil)
+ error(exNomem);
+ code = (uchar*)comvec;
+
+ genb(Opushl+RBX);
+ genb(Opushl+RCX);
+ genb(Opushl+RDX);
+ genb(Opushl+RSI);
+ genb(Opushl+RDI);
+ con((ulong)&R, RTMP);
+ modrm(Oldw, O(REG, FP), RTMP, RFP);
+ modrm(Oldw, O(REG, MP), RTMP, RMP);
+ modrm(Ojmprm, O(REG, PC), RTMP, 4);
+
+ segflush(comvec, 32);
+}
+
+static void
+maccase(void)
+{
+ uchar *loop, *def, *lab1;
+
+ modrm(Oldw, 0, RSI, RDX); // n = t[0]
+ modrm(Olea, 4, RSI, RSI); // t = &t[1]
+ gen2(Oldw, (3<<6)|(RBX<<3)|RDX); // MOVL DX, BX
+ gen2(Oshr, (3<<6)|(4<<3)|RBX); // SHL BX,1
+ gen2(0x01, (3<<6)|(RDX<<3)|RBX); // ADDL DX, BX BX = n*3
+ gen2(Opushrm, (0<<6)|(6<<3)|4);
+ genb((2<<6)|(RBX<<3)|RSI); // PUSHL 0(SI)(BX*4)
+ loop = code;
+ cmpl(RDX, 0);
+ gen2(Ojleb, 0);
+ def = code-1;
+ gen2(Oldw, (3<<6)|(RCX<<3)|RDX); // MOVL DX, CX n2 = n
+ gen2(Oshr, (3<<6)|(5<<3)|RCX); // SHR CX,1 n2 = n2>>1
+ gen2(Oldw, (3<<6)|(RBX<<3)|RCX); // MOVL CX, BX
+ gen2(Oshr, (3<<6)|(4<<3)|RBX); // SHL BX,1
+ gen2(0x01, (3<<6)|(RCX<<3)|RBX); // ADDL CX, BX BX = n2*3
+ gen2(0x3b, (0<<6)|(RAX<<3)|4);
+ genb((2<<6)|(RBX<<3)|RSI); // CMPL AX, 0(SI)(BX*4)
+ gen2(Ojgeb, 0); // JGE lab1
+ lab1 = code-1;
+ gen2(Oldw, (3<<6)|(RDX<<3)|RCX);
+ gen2(Ojmpb, loop-code-2);
+ *lab1 = code-lab1-1; // lab1:
+ gen2(0x3b, (1<<6)|(RAX<<3)|4);
+ gen2((2<<6)|(RBX<<3)|RSI, 4); // CMPL AX, 4(SI)(BX*4)
+ gen2(Ojltb, 0);
+ lab1 = code-1;
+ gen2(Olea, (1<<6)|(RSI<<3)|4);
+ gen2((2<<6)|(RBX<<3)|RSI, 12); // LEA 12(SI)(RBX*4), RSI
+ gen2(0x2b, (3<<6)|(RDX<<3)|RCX); // SUBL CX, DX n -= n2
+ gen2(Odecrm, (3<<6)|(1<<3)|RDX); // DECL DX n -= 1
+ gen2(Ojmpb, loop-code-2);
+ *lab1 = code-lab1-1; // lab1:
+ gen2(Oldw, (1<<6)|(RAX<<3)|4);
+ gen2((2<<6)|(RBX<<3)|RSI, 8); // MOVL 8(SI)(BX*4), AX
+ genb(Opopl+RSI); // ditch default
+ genb(Opopl+RSI);
+ gen2(Ojmprm, (3<<6)|(4<<3)|RAX); // JMP*L AX
+ *def = code-def-1; // def:
+ genb(Opopl+RAX); // ditch default
+ genb(Opopl+RSI);
+ gen2(Ojmprm, (3<<6)|(4<<3)|RAX);
+}
+
+static void
+macfrp(void)
+{
+ cmpl(RAX, (ulong)H); // CMPL AX, $H
+ gen2(Ojneb, 0x01); // JNE .+1
+ genb(Oret); // RET
+ modrm(0x83, O(Heap, ref)-sizeof(Heap), RAX, 7);
+ genb(0x01); // CMP AX.ref, $1
+ gen2(Ojeqb, 0x04); // JNE .+4
+ modrm(Odecrm, O(Heap, ref)-sizeof(Heap), RAX, 1);
+ genb(Oret); // DEC AX.ref
+ // RET
+ con((ulong)&R, RTMP); // MOV $R, RTMP
+ modrm(Ostw, O(REG, FP), RTMP, RFP); // MOVL RFP, R.FP
+ modrm(Ostw, O(REG, s), RTMP, RAX); // MOVL RAX, R.s
+ bra((ulong)rdestroy, Ocall); // CALL rdestroy
+ con((ulong)&R, RTMP); // MOVL $R, RTMP
+ modrm(Oldw, O(REG, FP), RTMP, RFP); // MOVL R.MP, RMP
+ modrm(Oldw, O(REG, MP), RTMP, RMP); // MOVL R.FP, RFP
+ genb(Oret);
+}
+
+static void
+macret(void)
+{
+ Inst i;
+ uchar *s;
+ static ulong lpunt, lnomr, lfrmr, linterp;
+
+ s = code;
+
+ lpunt -= 2;
+ lnomr -= 2;
+ lfrmr -= 2;
+ linterp -= 2;
+
+ con(0, RBX); // MOVL $0, RBX
+ modrm(Oldw, O(Frame, t), RFP, RAX); // MOVL t(FP), RAX
+ gen2(Ocmpw, (3<<6)|(RAX<<3)|RBX); // CMPL RAX, RBX
+ gen2(Ojeqb, lpunt-(code-s)); // JEQ lpunt
+ modrm(Oldw, O(Type, destroy), RAX, RAX);// MOVL destroy(RAX), RAX
+ gen2(Ocmpw, (3<<6)|(RAX<<3)|RBX); // CMPL RAX, RBX
+ gen2(Ojeqb, lpunt-(code-s)); // JEQ lpunt
+ modrm(Ocmpw, O(Frame, fp), RFP, RBX); // CMPL fp(FP), RBX
+ gen2(Ojeqb, lpunt-(code-s)); // JEQ lpunt
+ modrm(Ocmpw, O(Frame, mr), RFP, RBX); // CMPL mr(FP), RBX
+ gen2(Ojeqb, lnomr-(code-s)); // JEQ lnomr
+ con((ulong)&R, RTMP); // MOVL $R, RTMP
+ modrm(Oldw, O(REG, M), RTMP, RTA); // MOVL R.M, RTA
+ modrm(Odecrm, O(Heap, ref)-sizeof(Heap), RTA, 1);
+ gen2(Ojneb, lfrmr-(code-s)); // JNE lfrmr
+ modrm(Oincrm, O(Heap, ref)-sizeof(Heap), RTA, 0);
+ gen2(Ojmpb, lpunt-(code-s)); // JMP lpunt
+ lfrmr = code - s;
+ modrm(Oldw, O(Frame, mr), RFP, RTA); // MOVL mr(FP), RTA
+ modrm(Ostw, O(REG, M), RTMP, RTA); // MOVL RTA, R.M
+ modrm(Oldw, O(Modlink, MP), RTA, RMP); // MOVL MP(RTA), RMP
+ modrm(Ostw, O(REG, MP), RTMP, RMP); // MOVL RMP, R.MP
+ modrm(Ocmpi, O(Modlink, compiled), RTA, 7);// CMPL $0, M.compiled
+ genb(0x00);
+ gen2(Ojeqb, linterp-(code-s)); // JEQ linterp
+ lnomr = code - s;
+ gen2(Ocallrm, (3<<6)|(2<<3)|RAX); // CALL* AX
+ con((ulong)&R, RTMP); // MOVL $R, RTMP
+ modrm(Ostw, O(REG, SP), RTMP, RFP); // MOVL RFP, R.SP
+ modrm(Oldw, O(Frame, lr), RFP, RAX); // MOVL lr(RFP), RAX
+ modrm(Oldw, O(Frame, fp), RFP, RFP); // MOVL fp(RFP), RFP
+ modrm(Ostw, O(REG, FP), RTMP, RFP); // MOVL RFP, R.FP
+ gen2(Ojmprm, (3<<6)|(4<<3)|RAX); // JMP*L AX
+
+ linterp = code - s; // return to uncompiled code
+ gen2(Ocallrm, (3<<6)|(2<<3)|RAX); // CALL* AX
+ con((ulong)&R, RTMP); // MOVL $R, RTMP
+ modrm(Ostw, O(REG, SP), RTMP, RFP); // MOVL RFP, R.SP
+ modrm(Oldw, O(Frame, lr), RFP, RAX); // MOVL lr(RFP), RAX
+ modrm(Ostw, O(REG, PC), RTMP, RAX); // MOVL RAX, R.PC
+ modrm(Oldw, O(Frame, fp), RFP, RFP); // MOVL fp(RFP), RFP
+ modrm(Ostw, O(REG, FP), RTMP, RFP); // MOVL RFP, R.FP
+ genb(Opopl+RDI); // return to uncompiled code
+ genb(Opopl+RSI);
+ genb(Opopl+RDX);
+ genb(Opopl+RCX);
+ genb(Opopl+RBX);
+ genb(Oret);
+ // label:
+ lpunt = code - s;
+
+ i.add = AXNON;
+ punt(&i, TCHECK|NEWPC, optab[IRET]);
+}
+
+static void
+maccolr(void)
+{
+ modrm(Oincrm, O(Heap, ref)-sizeof(Heap), RBX, 0);
+ gen2(Oldw, (0<<6)|(RAX<<3)|5); // INCL ref(BX)
+ genw((ulong)&mutator); // MOVL mutator, RAX
+ modrm(Ocmpw, O(Heap, color)-sizeof(Heap), RBX, RAX);
+ gen2(Ojneb, 0x01); // CMPL color(BX), RAX
+ genb(Oret); // MOVL $propagator,RTMP
+ con(propagator, RAX); // MOVL RTMP, color(BX)
+ modrm(Ostw, O(Heap, color)-sizeof(Heap), RBX, RAX);
+ gen2(Ostw, (0<<6)|(RAX<<3)|5); // can be any !0 value
+ genw((ulong)&nprop); // MOVL RBX, nprop
+ genb(Oret);
+}
+
+static void
+macmcal(void)
+{
+ uchar *label, *mlnil, *interp;
+
+ cmpl(RAX, (ulong)H);
+ gen2(Ojeqb, 0);
+ mlnil = code - 1;
+ modrm(0x83, O(Modlink, prog), RTA, 7); // CMPL $0, ml->prog
+ genb(0x00);
+ gen2(Ojneb, 0); // JNE patch
+ label = code-1;
+ *mlnil = code-mlnil-1;
+ modrm(Ostw, O(REG, FP), RTMP, RCX);
+ modrm(Ostw, O(REG, dt), RTMP, RAX);
+ bra((ulong)rmcall, Ocall); // CALL rmcall
+ con((ulong)&R, RTMP); // MOVL $R, RTMP
+ modrm(Oldw, O(REG, FP), RTMP, RFP);
+ modrm(Oldw, O(REG, MP), RTMP, RMP);
+ genb(Oret); // RET
+ *label = code-label-1; // patch:
+ gen2(Oldw, (3<<6)|(RFP<<3)|RCX); // MOVL CX, RFP R.FP = f
+ modrm(Ostw, O(REG, M), RTMP, RTA); // MOVL RTA, R.M
+ modrm(Oincrm, O(Heap, ref)-sizeof(Heap), RTA, 0);
+ modrm(Oldw, O(Modlink, MP), RTA, RMP); // MOVL R.M->mp, RMP
+ modrm(Ostw, O(REG, MP), RTMP, RMP); // MOVL RMP, R.MP R.MP = ml->MP
+ modrm(Ocmpi, O(Modlink, compiled), RTA, 7);// CMPL $0, M.compiled
+ genb(0x00);
+ genb(Opopl+RTA); // balance call
+ gen2(Ojeqb, 0); // JEQ interp
+ interp = code-1;
+ gen2(Ojmprm, (3<<6)|(4<<3)|RAX); // JMP*L AX
+ *interp = code-interp-1; // interp:
+ modrm(Ostw, O(REG, FP), RTMP, RFP); // MOVL FP, R.FP
+ modrm(Ostw, O(REG, PC), RTMP, RAX); // MOVL PC, R.PC
+ genb(Opopl+RDI); // call to uncompiled code
+ genb(Opopl+RSI);
+ genb(Opopl+RDX);
+ genb(Opopl+RCX);
+ genb(Opopl+RBX);
+ genb(Oret);
+}
+
+static void
+macfram(void)
+{
+ uchar *label;
+
+ con((ulong)&R, RTMP); // MOVL $R, RTMP
+ modrm(Oldw, O(REG, SP), RTMP, RAX); // MOVL R.SP, AX
+ modrm(0x03, O(Type, size), RTA, RAX); // ADDL size(RCX), RAX
+ modrm(0x3b, O(REG, TS), RTMP, RAX); // CMPL AX, R.TS
+ gen2(0x7c, 0x00); // JL .+(patch)
+ label = code-1;
+
+ modrm(Ostw, O(REG, s), RTMP, RTA);
+ modrm(Ostw, O(REG, FP), RTMP, RFP); // MOVL RFP, R.FP
+ bra((ulong)extend, Ocall); // CALL extend
+ con((ulong)&R, RTMP);
+ modrm(Oldw, O(REG, FP), RTMP, RFP); // MOVL R.MP, RMP
+ modrm(Oldw, O(REG, MP), RTMP, RMP); // MOVL R.FP, RFP
+ modrm(Oldw, O(REG, s), RTMP, RCX); // MOVL R.s, *R.d
+ genb(Oret); // RET
+ *label = code-label-1;
+ modrm(Oldw, O(REG, SP), RTMP, RCX); // MOVL R.SP, CX
+ modrm(Ostw, O(REG, SP), RTMP, RAX); // MOVL AX, R.SP
+
+ modrm(Ostw, O(Frame, t), RCX, RTA); // MOVL RTA, t(CX) f->t = t
+ modrm(Omov, REGMOD*4, RCX, 0); // MOVL $0, mr(CX) f->mr
+ genw(0);
+ modrm(Oldw, O(Type, initialize), RTA, RTA);
+ gen2(Ojmprm, (3<<6)|(4<<3)|RTA); // JMP*L RTA
+ genb(Oret); // RET
+}
+
+static void
+macmfra(void)
+{
+ con((ulong)&R, RTMP); // MOVL $R, RTMP
+ modrm(Ostw, O(REG, FP), RTMP, RFP);
+ modrm(Ostw, O(REG, s), RTMP, RAX); // Save type
+ modrm(Ostw, O(REG, d), RTMP, RTA); // Save destination
+ bra((ulong)rmfram, Ocall); // CALL rmfram
+ con((ulong)&R, RTMP); // MOVL $R, RTMP
+ modrm(Oldw, O(REG, FP), RTMP, RFP);
+ modrm(Oldw, O(REG, MP), RTMP, RMP);
+ genb(Oret); // RET
+}
+
+static void
+macrelq(void)
+{
+ modrm(Ostw, O(REG, FP), RTMP, RFP); // MOVL FP, R.FP
+ genb(Opopl+RAX);
+ modrm(Ostw, O(REG, PC), RTMP, RAX); // MOVL PC, R.PC
+ genb(Opopl+RDI);
+ genb(Opopl+RSI);
+ genb(Opopl+RDX);
+ genb(Opopl+RCX);
+ genb(Opopl+RBX);
+ genb(Oret);
+}
+
+void
+comd(Type *t)
+{
+ int i, j, m, c;
+
+ for(i = 0; i < t->np; i++) {
+ c = t->map[i];
+ j = i<<5;
+ for(m = 0x80; m != 0; m >>= 1) {
+ if(c & m) {
+ modrm(Oldw, j, RFP, RAX);
+ rbra(macro[MacFRP], Ocall);
+ }
+ j += sizeof(WORD*);
+ }
+ }
+ genb(Oret);
+}
+
+void
+comi(Type *t)
+{
+ int i, j, m, c;
+
+ con((ulong)H, RAX);
+ for(i = 0; i < t->np; i++) {
+ c = t->map[i];
+ j = i<<5;
+ for(m = 0x80; m != 0; m >>= 1) {
+ if(c & m)
+ modrm(Ostw, j, RCX, RAX);
+ j += sizeof(WORD*);
+ }
+ }
+ genb(Oret);
+}
+
+void
+typecom(Type *t)
+{
+ int n;
+ uchar *tmp;
+
+ if(t == nil || t->initialize != 0)
+ return;
+
+ tmp = mallocz(4096*sizeof(uchar), 0);
+ if(tmp == nil)
+ error(exNomem);
+
+ code = tmp;
+ comi(t);
+ n = code - tmp;
+ code = tmp;
+ comd(t);
+ n += code - tmp;
+ free(tmp);
+
+ code = mallocz(n, 0);
+ if(code == nil)
+ return;
+
+ t->initialize = code;
+ comi(t);
+ t->destroy = code;
+ comd(t);
+
+ if(cflag > 3)
+ print("typ= %.8lux %4d i %.8lux d %.8lux asm=%d\n",
+ (ulong)t, t->size, (ulong)t->initialize, (ulong)t->destroy, n);
+
+ segflush(t->initialize, n);
+}
+
+static void
+patchex(Module *m, ulong *p)
+{
+ Handler *h;
+ Except *e;
+
+ if((h = m->htab) == nil)
+ return;
+ for( ; h->etab != nil; h++){
+ h->pc1 = p[h->pc1];
+ h->pc2 = p[h->pc2];
+ for(e = h->etab; e->s != nil; e++)
+ e->pc = p[e->pc];
+ if(e->pc != -1)
+ e->pc = p[e->pc];
+ }
+}
+
+int
+compile(Module *m, int size, Modlink *ml)
+{
+ ulong v;
+ Modl *e;
+ Link *l;
+ int i, n;
+ uchar *s, *tmp;
+
+ base = nil;
+ patch = mallocz(size*sizeof(*patch), 0);
+ tinit = malloc(m->ntype*sizeof(*tinit));
+ tmp = mallocz(4096*sizeof(uchar),0);
+ if(tinit == nil || patch == nil || tmp == nil)
+ goto bad;
+
+ preamble();
+
+ mod = m;
+ n = 0;
+ pass = 0;
+ nlit = 0;
+
+ for(i = 0; i < size; i++) {
+ code = tmp;
+ comp(&m->prog[i]);
+ patch[i] = n;
+ n += code - tmp;
+ }
+
+ for(i = 0; i < nelem(mactab); i++) {
+ code = tmp;
+ mactab[i].gen();
+ macro[mactab[i].idx] = n;
+ n += code - tmp;
+ }
+
+ n = (n+3)&~3;
+
+ nlit *= sizeof(ulong);
+ base = mallocz(n + nlit, 0);
+ if(base == nil)
+ goto bad;
+
+ if(cflag > 3)
+ print("dis=%5d %5d 386=%5d asm=%.8lux lit=%d: %s\n",
+ size, size*sizeof(Inst), n, (ulong)base, nlit, m->name);
+
+ pass++;
+ nlit = 0;
+ litpool = (ulong*)(base+n);
+ code = base;
+
+ for(i = 0; i < size; i++) {
+ s = code;
+ comp(&m->prog[i]);
+ if(cflag > 4) {
+ print("%D\n", &m->prog[i]);
+ das(s, code-s);
+ }
+ }
+
+ for(i = 0; i < nelem(mactab); i++)
+ mactab[i].gen();
+
+ v = (ulong)base;
+ for(l = m->ext; l->name; l++) {
+ l->u.pc = (Inst*)(v+patch[l->u.pc-m->prog]);
+ typecom(l->frame);
+ }
+ if(ml != nil) {
+ e = &ml->links[0];
+ for(i = 0; i < ml->nlinks; i++) {
+ e->u.pc = (Inst*)(v+patch[e->u.pc-m->prog]);
+ typecom(e->frame);
+ e++;
+ }
+ }
+ for(i = 0; i < m->ntype; i++) {
+ if(tinit[i] != 0)
+ typecom(m->type[i]);
+ }
+ patchex(m, patch);
+ m->entry = (Inst*)(v+patch[mod->entry-mod->prog]);
+ free(patch);
+ free(tinit);
+ free(tmp);
+ free(m->prog);
+ m->prog = (Inst*)base;
+ m->compiled = 1;
+ segflush(base, n*sizeof(base));
+ return 1;
+bad:
+ free(patch);
+ free(tinit);
+ free(tmp);
+ free(base);
+ return 0;
+}
+
--- /dev/null
+++ b/libinterp/comp-arm.c
@@ -1,0 +1,2280 @@
+#include "lib9.h"
+#include "isa.h"
+#include "interp.h"
+#include "raise.h"
+
+/*
+ * to do:
+ * eliminate litpool?
+ * eliminate long constants in comi/comd
+ * enable and check inline FP code (not much point with fpemu)
+ */
+
+#define RESCHED 1 /* check for interpreter reschedule */
+#define SOFTFP 1
+
+enum
+{
+ R0 = 0,
+ R1 = 1,
+ R2 = 2,
+ R3 = 3,
+ R4 = 4,
+ R5 = 5,
+ R6 = 6,
+ R7 = 7,
+ R8 = 8,
+ R9 = 9,
+ R10 = 10,
+ R11 = 11,
+ R12 = 12, /* C's SB */
+ R13 = 13, /* C's SP */
+ R14 = 14, /* Link Register */
+ R15 = 15, /* PC */
+
+ RLINK = 14,
+
+ RFP = R9, /* Frame Pointer */
+ RMP = R8, /* Module Pointer */
+ RTA = R7, /* Intermediate address for double indirect */
+ RCON = R6, /* Constant builder */
+ RREG = R5, /* Pointer to REG */
+ RA3 = R4, /* gpr 3 */
+ RA2 = R3, /* gpr 2 2+3 = L */
+ RA1 = R2, /* gpr 1 */
+ RA0 = R1, /* gpr 0 0+1 = L */
+
+
+ FA2 = 2, /* Floating */
+ FA3 = 3,
+ FA4 = 4,
+ FA5 = 5,
+
+ EQ = 0,
+ NE = 1,
+ CS = 2,
+ CC = 3,
+ MI = 4,
+ PL = 5,
+ VS = 6,
+ VC = 7,
+ HI = 8,
+ LS = 9,
+ GE = 10,
+ LT = 11,
+ GT = 12,
+ LE = 13,
+ AL = 14,
+ NV = 15,
+
+ HS = CS,
+ LO = CC,
+
+ And = 0,
+ Eor = 1,
+ Sub = 2,
+ Rsb = 3,
+ Add = 4,
+ Adc = 5,
+ Sbc = 6,
+ Rsc = 7,
+ Tst = 8,
+ Teq = 9,
+ Cmp = 10,
+ Cmn = 11,
+ Orr = 12,
+ Mov = 13,
+ Bic = 14,
+ Mvn = 15,
+
+ Adf = 0,
+ Muf = 1,
+ Suf = 2,
+ Rsf = 3,
+ Dvf = 4,
+ Rdf = 5,
+ Rmf = 8,
+
+ Mvf = 0,
+ Mnf = 1,
+ Abs = 2,
+ Rnd = 3,
+
+ Flt = 0,
+ Fix = 1,
+
+ Cmf = 4,
+ Cnf = 5,
+
+ Lea = 100, /* macro memory ops */
+ Ldw,
+ Ldb,
+ Stw,
+ Stb,
+ Ldf,
+ Stf,
+ Ldh,
+
+ Blo = 0, /* offset of low order word in big */
+ Bhi = 4, /* offset of high order word in big */
+
+ Lg2Rune = 2,
+
+ NCON = (0xFFC-8)/4,
+
+ SRCOP = (1<<0),
+ DSTOP = (1<<1),
+ WRTPC = (1<<2),
+ TCHECK = (1<<3),
+ NEWPC = (1<<4),
+ DBRAN = (1<<5),
+ THREOP = (1<<6),
+
+ ANDAND = 1,
+ OROR = 2,
+ EQAND = 3,
+
+ MacFRP = 0,
+ MacRET,
+ MacCASE,
+ MacCOLR,
+ MacMCAL,
+ MacFRAM,
+ MacMFRA,
+ MacRELQ,
+ NMACRO
+};
+
+#define BITS(B) (1<<B)
+#define IMM(O) (O & ((1<<12)-1))
+#define SBIT (1<<20)
+#define PBIT (1<<24)
+#define UPBIT (1<<23)
+
+#define LDW(C, Rn, Rd, O) *code++ = (C<<28)|(1<<26)|(1<<24)|(1<<23)|(1<<20)|\
+ (Rn<<16)|(Rd<<12)|IMM(O)
+#define STW(C, Rn, Rd, O) *code++ = (C<<28)|(1<<26)|(1<<24)|(1<<23)|\
+ (Rn<<16)|(Rd<<12)|IMM(O)
+#define LDB(C, Rn, Rd, O) *code++ = (C<<28)|(1<<26)|(1<<24)|(1<<23)|(1<<20)|(1<<22)|\
+ (Rn<<16)|(Rd<<12)|IMM(O)
+#define STB(C, Rn, Rd, O) *code++ = (C<<28)|(1<<26)|(1<<24)|(1<<23)|(1<<22)|\
+ (Rn<<16)|(Rd<<12)|IMM(O)
+
+#define LDxP(C, Rn, Rd, O, B) *code++ = (C<<28)|(1<<26)|(B<<22)|(1<<23)|(1<<20)|\
+ (Rn<<16)|(Rd<<12)|IMM(O)
+#define STxP(C, Rn, Rd, O, B) *code++ = (C<<28)|(1<<26)|(B<<22)|(1<<23)|\
+ (Rn<<16)|(Rd<<12)|IMM(O)
+#define LDRW(C, Rn, Rd, SH, R) *code++ = (C<<28)|(3<<25)|(1<<24)|(1<<23)|(1<<20)|\
+ (Rn<<16)|(Rd<<12)|(SH<<4)|R
+#define STRW(C, Rn, Rd, SH, R) *code++ = (C<<28)|(3<<25)|(1<<24)|(1<<23)|\
+ (Rn<<16)|(Rd<<12)|(SH<<4)|R
+#define LDRB(C, Rn, Rd, SH, R) *code++ = (C<<28)|(3<<25)|(1<<24)|(1<<23)|(1<<20)|(1<<22)|\
+ (Rn<<16)|(Rd<<12)|(SH<<4)|R
+#define STRB(C, Rn, Rd, SH, R) *code++ = (C<<28)|(3<<25)|(1<<24)|(1<<23)|(1<<22)|\
+ (Rn<<16)|(Rd<<12)|(SH<<4)|R
+
+#define DPI(C, Op, Rn, Rd, RO, O) *code++ = (C<<28)|(1<<25)|(Op<<21)|\
+ (Rn<<16)|(Rd<<12)|(RO<<8)|((O)&0xff)
+#define DP(C, Op, Rn, Rd, Sh, Ro) *code++ = (C<<28)|(Op<<21)|(Rn<<16)|\
+ (Rd<<12)|((Sh)<<4)|Ro
+#define CMPI(C, Rn, Rd, RO, O) *code++ = (C<<28)|(1<<25)|(Cmp<<21)|(1<<20)|\
+ (Rn<<16)|(Rd<<12)|(RO<<8)|((O)&0xff)
+#define CMNI(C, Rn, Rd, RO, O) *code++ = (C<<28)|(1<<25)|(Cmn<<21)|(1<<20)|\
+ (Rn<<16)|(Rd<<12)|(RO<<8)|((O)&0xff)
+#define CMP(C, Rn, Rd, Sh, Ro) *code++ = (C<<28)|(Cmp<<21)|(Rn<<16)|(1<<20)|\
+ (Rd<<12)|((Sh)<<4)|Ro
+#define CMN(C, Rn, Rd, Sh, Ro) *code++ = (C<<28)|(Cmn<<21)|(Rn<<16)|(1<<20)|\
+ (Rd<<12)|((Sh)<<4)|Ro
+#define MUL(C, Rm, Rs, Rd) *code++ = (C<<28)|(Rd<<16)|(Rm<<0)|(Rs<<8)|\
+ (9<<4)
+
+#define LDF(C, Rn, Fd, O) *code++ = (C<<28)|(6<<25)|(1<<24)|(1<<23)|(1<<20)|\
+ (Rn<<16)|(1<<15)|(Fd<<12)|(1<<8)|((O)&0xff)
+#define STF(C, Rn, Fd, O) *code++ = (C<<28)|(6<<25)|(1<<24)|(1<<23)|\
+ (Rn<<16)|(1<<15)|(Fd<<12)|(1<<8)|((O)&0xff)
+#define CMF(C, Fn, Fm) *code++ = (C<<28)|(7<<25)|(4<<21)|(1<<20)|(Fn<<16)|\
+ (0xF<<12)|(1<<8)|(1<<4)|(Fm)
+
+#define LDH(C, Rn, Rd, O) *code++ = (C<<28)|(0<<25)|(1<<24)|(1<<23)|(1<<22)|(1<<20)|\
+ (Rn<<16)|(Rd<<12)|(((O)&0xf0)<<4)|(0xb<<4)|((O)&0xf)
+#define LDRH(C, Rn, Rd, Rm) *code++ = (C<<28)|(0<<25)|(1<<24)|(1<<23)|(1<<20)|\
+ (Rn<<16)|(Rd<<12)|(0xb<<4)|Rm
+
+#define CPDO2(C, Op, Fn, Fd, Fm) *code++ = (C<<28)|(0xE<<24)|(Op<<20)|(Fn<<16)|(Fd<<12)|(1<<8)|(1<<7)|(Fm)
+#define CPDO1(C, Op, Fd, Fm) CPDO2((C),(Op),0,(Fd),(Fm))|(1<<15)
+#define CPFLT(C, Fn, Rd) *code++ = (C<<28)|(0xE<<24)|(0<<20)|(Fn<<16)|(Rd<<12)|(1<<8)|(9<<4)
+#define CPFIX(C, Rd, Fm) *code++ = (C<<28)|(0xE<<24)|(1<<20)|(0<<16)|(Rd<<12)|(1<<8)|(9<<4)|(Fm)
+
+#define BRAW(C, o) ((C<<28)|(5<<25)|((o) & 0x00ffffff))
+#define BRA(C, o) gen(BRAW((C),(o)))
+#define IA(s, o) (ulong)(base+s[o])
+#define BRADIS(C, o) BRA(C, (IA(patch, o)-(ulong)code-8)>>2)
+#define BRAMAC(r, o) BRA(r, (IA(macro, o)-(ulong)code-8)>>2)
+#define BRANCH(C, o) gen(BRAW(C, ((ulong)(o)-(ulong)code-8)>>2))
+#define CALL(o) gen(BRAW(AL, ((ulong)(o)-(ulong)code-8)>>2)|(1<<24))
+#define CCALL(C,o) gen(BRAW((C), ((ulong)(o)-(ulong)code-8)>>2)|(1<<24))
+#define CALLMAC(C,o) gen(BRAW((C), (IA(macro, o)-(ulong)code-8)>>2)|(1<<24))
+#define RELPC(pc) (ulong)(base+(pc))
+#define RETURN DPI(AL, Add, RLINK, R15, 0, 0)
+#define CRETURN(C) DPI(C, Add, RLINK, R15, 0, 0)
+#define PATCH(ptr) *ptr |= (((ulong)code-(ulong)(ptr)-8)>>2) & 0x00ffffff
+
+#define MOV(src, dst) DP(AL, Mov, 0, dst, 0, src)
+
+#define FITS12(v) ((ulong)(v)<BITS(12))
+#define FITS8(v) ((ulong)(v)<BITS(8))
+#define FITS5(v) ((ulong)(v)<BITS(5))
+
+/* assumes H==-1 */
+#define CMPH(C, r) CMNI(C, r, 0, 0, 1)
+#define NOTNIL(r) (CMPH(AL, (r)), CCALL(EQ, nullity))
+
+/* array bounds checking */
+#define BCK(r, rb) (CMP(AL, rb, 0, 0, r), CCALL(LS, bounds))
+#define BCKI(i, rb) (CMPI(AL, rb, 0, 0, i), CCALL(LS, bounds))
+#define BCKR(i, rb) (CMPI(AL, rb, 0, 0, 0)|(i), CCALL(LS, bounds))
+
+static ulong* code;
+static ulong* base;
+static ulong* patch;
+static ulong codeoff;
+static int pass;
+static int puntpc = 1;
+static Module* mod;
+static uchar* tinit;
+static ulong* litpool;
+static int nlit;
+static ulong macro[NMACRO];
+ void (*comvec)(void);
+static void macfrp(void);
+static void macret(void);
+static void maccase(void);
+static void maccolr(void);
+static void macmcal(void);
+static void macfram(void);
+static void macmfra(void);
+static void macrelq(void);
+static void movmem(Inst*);
+static void mid(Inst*, int, int);
+extern void das(ulong*, int);
+
+#define T(r) *((void**)(R.r))
+
+struct
+{
+ int idx;
+ void (*gen)(void);
+ char* name;
+} mactab[] =
+{
+ MacFRP, macfrp, "FRP", /* decrement and free pointer */
+ MacRET, macret, "RET", /* return instruction */
+ MacCASE, maccase, "CASE", /* case instruction */
+ MacCOLR, maccolr, "COLR", /* increment and color pointer */
+ MacMCAL, macmcal, "MCAL", /* mcall bottom half */
+ MacFRAM, macfram, "FRAM", /* frame instruction */
+ MacMFRA, macmfra, "MFRA", /* punt mframe because t->initialize==0 */
+ MacRELQ, macrelq, /* reschedule */
+};
+
+typedef struct Const Const;
+struct Const
+{
+ ulong o;
+ ulong* code;
+ ulong* pc;
+};
+
+typedef struct Con Con;
+struct Con
+{
+ int ptr;
+ Const table[NCON];
+};
+static Con rcon;
+
+static void
+rdestroy(void)
+{
+ destroy(R.s);
+}
+
+static void
+rmcall(void)
+{
+ Frame *f;
+ Prog *p;
+
+ if((void*)R.dt == H)
+ error(exModule);
+
+ f = (Frame*)R.FP;
+ if(f == H)
+ error(exModule);
+
+ f->mr = nil;
+ ((void(*)(Frame*))R.dt)(f);
+ R.SP = (uchar*)f;
+ R.FP = f->fp;
+ if(f->t == nil)
+ unextend(f);
+ else
+ freeptrs(f, f->t);
+ p = currun();
+ if(p->kill != nil)
+ error(p->kill);
+}
+
+static void
+rmfram(void)
+{
+ Type *t;
+ Frame *f;
+ uchar *nsp;
+
+ if(R.d == H)
+ error(exModule);
+ t = (Type*)R.s;
+ if(t == H)
+ error(exModule);
+ nsp = R.SP + t->size;
+ if(nsp >= R.TS) {
+ R.s = t;
+ extend();
+ T(d) = R.s;
+ return;
+ }
+ f = (Frame*)R.SP;
+ R.SP = nsp;
+ f->t = t;
+ f->mr = nil;
+ initmem(t, f);
+ T(d) = f;
+}
+
+static void
+urk(char *s)
+{
+ USED(s);
+ error(exCompile); //production
+ //panic("compile failed: urk: %s\n", s); //debugging
+}
+
+static void
+gen(ulong w)
+{
+ *code++ = w;
+}
+
+static long
+immrot(ulong v)
+{
+ int i;
+
+ for(i=0; i<16; i++) {
+ if((v & ~0xff) == 0)
+ return (i<<8) | v | (1<<25);
+ v = (v<<2) | (v>>30);
+ }
+ return 0;
+}
+
+static long
+immaddr(long v)
+{
+
+ if(v >= 0 && v <= 0xfff)
+ return (v & 0xfff) |
+ (1<<24) | /* pre indexing */
+ (1<<23); /* pre indexing, up */
+ if(v >= -0xfff && v < 0)
+ return (-v & 0xfff) |
+ (1<<24); /* pre indexing */
+ return 0;
+}
+
+static void
+flushcon(int genbr)
+{
+ int i;
+ Const *c;
+ ulong disp;
+
+ if(rcon.ptr == 0)
+ return;
+ if(genbr){
+ if(0)print("BR %d(PC)=%8.8p (len=%d)\n", (rcon.ptr*4+4-8)>>2, code+rcon.ptr+1, rcon.ptr);
+ BRA(AL, (rcon.ptr*4+4-8)>>2);
+ }
+ c = &rcon.table[0];
+ for(i = 0; i < rcon.ptr; i++) {
+ if(pass){
+ disp = (code - c->code) * sizeof(*code) - 8;
+ if(disp >= BITS(12))
+ print("INVALID constant range %lud", disp);
+ if(0)print("data %8.8p %8.8lux (%8.8p, ins=%8.8lux cpc=%8.8p)\n", code, c->o, c->code, *c->code, c->pc);
+ *c->code |= (disp&0xfff);
+ }
+ *code++ = c->o;
+ c++;
+ }
+ rcon.ptr = 0;
+}
+
+static void
+flushchk(void)
+{
+ if(rcon.ptr >= NCON || rcon.ptr > 0 && (code+codeoff+2-rcon.table[0].pc)*sizeof(*code) >= BITS(12)-256){ // 256 allows for a little delay in calling flushchk
+ if(0)print("flushed constant table: len %ux disp %ld\n", rcon.ptr, (code+codeoff-rcon.table[0].pc)*sizeof(*code)-8);
+ flushcon(1);
+ }
+}
+
+static void
+ccon(int cc, ulong o, int r, int opt)
+{
+ ulong u;
+ Const *c;
+
+ if(opt != 0) {
+ u = o & ~0xff;
+ if(u == 0) {
+ DPI(cc, Mov, 0, r, 0, o);
+ return;
+ }
+ if(u == ~0xff) {
+ DPI(cc, Mvn, 0, r, 0, ~o);
+ return;
+ }
+ u = immrot(o);
+ if(u) {
+ DPI(cc, Mov, 0, r, 0, 0) | u;
+ return;
+ }
+ u = o & ~0xffff;
+ if(u == 0) {
+ DPI(cc, Mov, 0, r, 0, o);
+ DPI(cc, Orr, r, r, (24/2), o>>8);
+ return;
+ }
+ }
+ flushchk();
+ c = &rcon.table[rcon.ptr++];
+ c->o = o;
+ c->code = code;
+ c->pc = code+codeoff;
+ LDW(cc, R15, r, 0);
+}
+
+static void
+memc(int c, int inst, ulong disp, int rm, int r)
+{
+ int bit;
+
+ if(inst == Lea) {
+ if(disp < BITS(8)) {
+ if(disp != 0 || rm != r)
+ DPI(c, Add, rm, r, 0, disp);
+ return;
+ }
+ if(-disp < BITS(8)) {
+ DPI(c, Sub, rm, r, 0, -disp);
+ return;
+ }
+ bit = immrot(disp);
+ if(bit) {
+ DPI(c, Add, rm, r, 0, 0) | bit;
+ return;
+ }
+ ccon(c, disp, RCON, 1);
+ DP(c, Add, rm, r, 0, RCON);
+ return;
+ }
+
+ if(disp < BITS(12) || -disp < BITS(12)) { /* Direct load */
+ if(disp < BITS(12))
+ bit = 0;
+ else {
+ disp = -disp;
+ bit = UPBIT;
+ }
+ switch(inst) {
+ case Ldw:
+ LDW(c, rm, r, disp);
+ break;
+ case Ldb:
+ LDB(c, rm, r, disp);
+ break;
+ case Stw:
+ STW(c, rm, r, disp);
+ break;
+ case Stb:
+ STB(c, rm, r, disp);
+ break;
+ }
+ if(bit)
+ code[-1] ^= bit;
+ return;
+ }
+
+ ccon(c, disp, RCON, 1);
+ switch(inst) {
+ case Ldw:
+ LDRW(c, rm, r, 0, RCON);
+ break;
+ case Ldb:
+ LDRB(c, rm, r, 0, RCON);
+ break;
+ case Stw:
+ STRW(c, rm, r, 0, RCON);
+ break;
+ case Stb:
+ STRB(c, rm, r, 0, RCON);
+ break;
+ }
+}
+
+static void
+con(ulong o, int r, int opt)
+{
+ ccon(AL, o, r, opt);
+}
+
+static void
+mem(int inst, ulong disp, int rm, int r)
+{
+ memc(AL, inst, disp, rm, r);
+}
+
+static void
+opx(int mode, Adr *a, int mi, int r, int li)
+{
+ int ir, rta;
+
+ switch(mode) {
+ default:
+ urk("opx");
+ case AFP:
+ mem(mi, a->ind, RFP, r);
+ return;
+ case AMP:
+ mem(mi, a->ind, RMP, r);
+ return;
+ case AIMM:
+ con(a->imm, r, 1);
+ if(mi == Lea) { /* could be simpler if con generates reachable literal */
+ mem(Stw, li, RREG, r);
+ mem(Lea, li, RREG, r);
+ }
+ return;
+ case AIND|AFP:
+ ir = RFP;
+ break;
+ case AIND|AMP:
+ ir = RMP;
+ break;
+ }
+ rta = RTA;
+ if(mi == Lea)
+ rta = r;
+ mem(Ldw, a->i.f, ir, rta);
+ mem(mi, a->i.s, rta, r);
+}
+
+static void
+opwld(Inst *i, int op, int reg)
+{
+ opx(USRC(i->add), &i->s, op, reg, O(REG, st));
+}
+
+static void
+opwst(Inst *i, int op, int reg)
+{
+ opx(UDST(i->add), &i->d, op, reg, O(REG, dt));
+}
+
+static void
+memfl(int cc, int inst, ulong disp, int rm, int r)
+{
+ int bit, wd;
+
+ wd = (disp&03)==0;
+ bit = 0;
+ if(wd && disp < BITS(10))
+ disp >>= 2; /* direct load */
+ else if(wd && -disp < BITS(10)){
+ bit = UPBIT;
+ disp = -disp >> 2;
+ }else{
+ ccon(cc, disp, RCON, 1);
+ DP(cc, Add, RCON, RCON, 0, rm);
+ rm = RCON;
+ disp = 0;
+ }
+ switch(inst) {
+ case Ldf:
+ LDF(cc, rm, r, disp);
+ break;
+ case Stf:
+ STF(cc, rm, r, disp);
+ break;
+ }
+ if(bit)
+ code[-1] ^= bit;
+}
+
+static void
+opfl(Adr *a, int am, int mi, int r)
+{
+ int ir;
+
+ switch(am) {
+ default:
+ urk("opfl");
+ case AFP:
+ memfl(AL, mi, a->ind, RFP, r);
+ return;
+ case AMP:
+ memfl(AL, mi, a->ind, RMP, r);
+ return;
+ case AIND|AFP:
+ ir = RFP;
+ break;
+ case AIND|AMP:
+ ir = RMP;
+ break;
+ }
+ mem(Ldw, a->i.f, ir, RTA);
+ memfl(AL, mi, a->i.s, RTA, r);
+}
+
+static void
+opflld(Inst *i, int mi, int r)
+{
+ opfl(&i->s, USRC(i->add), mi, r);
+}
+
+static void
+opflst(Inst *i, int mi, int r)
+{
+ opfl(&i->d, UDST(i->add), mi, r);
+}
+
+static void
+literal(ulong imm, int roff)
+{
+ nlit++;
+
+ con((ulong)litpool, RTA, 0);
+ mem(Stw, roff, RREG, RTA);
+
+ if(pass == 0)
+ return;
+
+ *litpool = imm;
+ litpool++;
+}
+
+static void
+schedcheck(Inst *i)
+{
+ if(RESCHED && i->d.ins <= i){
+ mem(Ldw, O(REG, IC), RREG, RA0);
+ DPI(AL, Sub, RA0, RA0, 0, 1) | SBIT;
+ mem(Stw, O(REG, IC), RREG, RA0);
+ /* CMPI(AL, RA0, 0, 0, 1); */
+ CALLMAC(LE, MacRELQ);
+ }
+}
+
+static void
+bounds(void)
+{
+ /* mem(Stw, O(REG,FP), RREG, RFP); */
+ error(exBounds);
+}
+
+static void
+nullity(void)
+{
+ /* mem(Stw, O(REG,FP), RREG, RFP); */
+ error(exNilref);
+}
+
+static void
+punt(Inst *i, int m, void (*fn)(void))
+{
+ ulong pc;
+
+ if(m & SRCOP) {
+ if(UXSRC(i->add) == SRC(AIMM))
+ literal(i->s.imm, O(REG, s));
+ else {
+ opwld(i, Lea, RA0);
+ mem(Stw, O(REG, s), RREG, RA0);
+ }
+ }
+
+ if(m & DSTOP) {
+ opwst(i, Lea, RA0);
+ mem(Stw, O(REG, d), RREG, RA0);
+ }
+ if(m & WRTPC) {
+ con(RELPC(patch[i-mod->prog+1]), RA0, 0);
+ mem(Stw, O(REG, PC), RREG, RA0);
+ }
+ if(m & DBRAN) {
+ pc = patch[i->d.ins-mod->prog];
+ literal((ulong)(base+pc), O(REG, d));
+ }
+
+ switch(i->add&ARM) {
+ case AXNON:
+ if(m & THREOP) {
+ mem(Ldw, O(REG, d), RREG, RA0);
+ mem(Stw, O(REG, m), RREG, RA0);
+ }
+ break;
+ case AXIMM:
+ literal((short)i->reg, O(REG,m));
+ break;
+ case AXINF:
+ mem(Lea, i->reg, RFP, RA2);
+ mem(Stw, O(REG, m), RREG, RA2);
+ break;
+ case AXINM:
+ mem(Lea, i->reg, RMP, RA2);
+ mem(Stw, O(REG, m), RREG, RA2);
+ break;
+ }
+ mem(Stw, O(REG, FP), RREG, RFP);
+
+ CALL(fn);
+
+ con((ulong)&R, RREG, 1);
+ if(m & TCHECK) {
+ mem(Ldw, O(REG, t), RREG, RA0);
+ CMPI(AL, RA0, 0, 0, 0);
+ memc(NE, Ldw, O(REG, xpc), RREG, RLINK);
+ CRETURN(NE); /* if(R.t) goto(R.xpc) */
+ }
+ mem(Ldw, O(REG, FP), RREG, RFP);
+ mem(Ldw, O(REG, MP), RREG, RMP);
+
+ if(m & NEWPC){
+ mem(Ldw, O(REG, PC), RREG, R15);
+ flushcon(0);
+ }
+}
+
+static void
+midfl(Inst *i, int mi, int r)
+{
+ int ir;
+
+ switch(i->add&ARM) {
+ default:
+ opflst(i, mi, r);
+ return;
+ case AXIMM:
+ con((short)i->reg, r, 1); // BUG
+ return;
+ case AXINF:
+ ir = RFP;
+ break;
+ case AXINM:
+ ir = RMP;
+ break;
+ }
+ memfl(AL, mi, i->reg, ir, r);
+}
+
+static void
+mid(Inst *i, int mi, int r)
+{
+ int ir;
+
+ switch(i->add&ARM) {
+ default:
+ opwst(i, mi, r);
+ return;
+ case AXIMM:
+ if(mi == Lea)
+ urk("mid/lea");
+ con((short)i->reg, r, 1);
+ return;
+ case AXINF:
+ ir = RFP;
+ break;
+ case AXINM:
+ ir = RMP;
+ break;
+ }
+ mem(mi, i->reg, ir, r);
+}
+
+static int
+swapbraop(int b)
+{
+ switch(b) {
+ case GE:
+ return LE;
+ case LE:
+ return GE;
+ case GT:
+ return LT;
+ case LT:
+ return GT;
+ }
+ return b;
+}
+
+static void
+cbra(Inst *i, int r)
+{
+ if(RESCHED)
+ schedcheck(i);
+ if(UXSRC(i->add) == SRC(AIMM) && FITS8(i->s.imm)) {
+ mid(i, Ldw, RA1);
+ CMPI(AL, RA1, 0, 0, i->s.imm);
+ r = swapbraop(r);
+ } else if(UXSRC(i->add) == SRC(AIMM) && FITS8(-i->s.imm)) {
+ mid(i, Ldw, RA1);
+ CMNI(AL, RA1, 0, 0, -i->s.imm);
+ r = swapbraop(r);
+ } else if((i->add & ARM) == AXIMM && FITS8(i->reg)) {
+ opwld(i, Ldw, RA1);
+ CMPI(AL, RA1, 0, 0, i->reg);
+ } else if((i->add & ARM) == AXIMM && FITS8(-(short)i->reg)) {
+ opwld(i, Ldw, RA1);
+ CMNI(AL, RA1, 0, 0, -(short)i->reg);
+ } else {
+ opwld(i, Ldw, RA0);
+ mid(i, Ldw, RA1);
+ CMP(AL, RA0, 0, 0, RA1);
+ }
+ BRADIS(r, i->d.ins-mod->prog);
+}
+
+static void
+cbrab(Inst *i, int r)
+{
+ if(RESCHED)
+ schedcheck(i);
+ if(UXSRC(i->add) == SRC(AIMM)) {
+ mid(i, Ldb, RA1);
+ CMPI(AL, RA1, 0, 0, i->s.imm&0xFF);
+ r = swapbraop(r);
+ } else if((i->add & ARM) == AXIMM) {
+ opwld(i, Ldb, RA1);
+ CMPI(AL, RA1, 0, 0, i->reg&0xFF);
+ } else {
+ opwld(i, Ldb, RA0);
+ mid(i, Ldb, RA1);
+ CMP(AL, RA0, 0, 0, RA1);
+ }
+ BRADIS(r, i->d.ins-mod->prog);
+}
+
+static void
+cbral(Inst *i, int jmsw, int jlsw, int mode)
+{
+ ulong dst, *label;
+
+ if(RESCHED)
+ schedcheck(i);
+ opwld(i, Lea, RA1);
+ mid(i, Lea, RA3);
+ mem(Ldw, Bhi, RA1, RA2);
+ mem(Ldw, Bhi, RA3, RA0);
+ CMP(AL, RA2, 0, 0, RA0);
+ label = nil;
+ dst = i->d.ins-mod->prog;
+ switch(mode) {
+ case ANDAND:
+ label = code;
+ BRA(jmsw, 0);
+ break;
+ case OROR:
+ BRADIS(jmsw, dst);
+ break;
+ case EQAND:
+ BRADIS(jmsw, dst);
+ label = code;
+ BRA(NE, 0);
+ break;
+ }
+ mem(Ldw, Blo, RA3, RA0);
+ mem(Ldw, Blo, RA1, RA2);
+ CMP(AL, RA2, 0, 0, RA0);
+ BRADIS(jlsw, dst);
+ if(label != nil)
+ PATCH(label);
+}
+
+static void
+cbraf(Inst *i, int r)
+{
+ if(RESCHED)
+ schedcheck(i);
+ if(!SOFTFP){
+ ulong *s=code;
+ opflld(i, Ldf, FA4);
+ midfl(i, Ldf, FA2);
+ CMF(AL, FA4, FA2);
+ BRADIS(r, i->d.ins-mod->prog);
+ if(pass){print("%D\n", i); das(s, code-s);}
+ }else
+ punt(i, SRCOP|THREOP|DBRAN|NEWPC|WRTPC, optab[i->op]);
+}
+
+static void
+comcase(Inst *i, int w)
+{
+ int l;
+ WORD *t, *e;
+
+ if(w != 0) {
+ opwld(i, Ldw, RA1); // v
+ opwst(i, Lea, RA3); // table
+ BRAMAC(AL, MacCASE);
+ }
+
+ t = (WORD*)(mod->origmp+i->d.ind+4);
+ l = t[-1];
+
+ /* have to take care not to relocate the same table twice -
+ * the limbo compiler can duplicate a case instruction
+ * during its folding phase
+ */
+
+ if(pass == 0) {
+ if(l >= 0)
+ t[-1] = -l-1; /* Mark it not done */
+ return;
+ }
+ if(l >= 0) /* Check pass 2 done */
+ return;
+ t[-1] = -l-1; /* Set real count */
+ e = t + t[-1]*3;
+ while(t < e) {
+ t[2] = RELPC(patch[t[2]]);
+ t += 3;
+ }
+ t[0] = RELPC(patch[t[0]]);
+}
+
+static void
+comcasel(Inst *i)
+{
+ int l;
+ WORD *t, *e;
+
+ t = (WORD*)(mod->origmp+i->d.ind+8);
+ l = t[-2];
+ if(pass == 0) {
+ if(l >= 0)
+ t[-2] = -l-1; /* Mark it not done */
+ return;
+ }
+ if(l >= 0) /* Check pass 2 done */
+ return;
+ t[-2] = -l-1; /* Set real count */
+ e = t + t[-2]*6;
+ while(t < e) {
+ t[4] = RELPC(patch[t[4]]);
+ t += 6;
+ }
+ t[0] = RELPC(patch[t[0]]);
+}
+
+static void
+commframe(Inst *i)
+{
+ ulong *punt, *mlnil;
+
+ opwld(i, Ldw, RA0);
+ CMPH(AL, RA0);
+ mlnil = code;
+ BRA(EQ, 0);
+
+ if((i->add&ARM) == AXIMM) {
+ mem(Ldw, OA(Modlink, links)+i->reg*sizeof(Modl)+O(Modl, frame), RA0, RA3);
+ } else {
+ mid(i, Ldw, RA1);
+ DP(AL, Add, RA0, RA1, (3<<3), RA1); // assumes sizeof(Modl) == 8
+ mem(Ldw, OA(Modlink, links)+O(Modl, frame), RA1, RA3);
+ }
+
+ mem(Ldw, O(Type, initialize), RA3, RA1);
+ CMPI(AL, RA1, 0, 0, 0);
+ punt = code;
+ BRA(NE, 0);
+
+ opwst(i, Lea, RA0);
+
+ /* Type in RA3, destination in RA0 */
+ PATCH(mlnil);
+ con(RELPC(patch[i-mod->prog+1]), RLINK, 0);
+ BRAMAC(AL, MacMFRA);
+
+ /* Type in RA3 */
+ PATCH(punt);
+ CALLMAC(AL, MacFRAM);
+ opwst(i, Stw, RA2);
+}
+
+static void
+commcall(Inst *i)
+{
+ ulong *mlnil;
+
+ opwld(i, Ldw, RA2);
+ con(RELPC(patch[i-mod->prog+1]), RA0, 0);
+ mem(Stw, O(Frame, lr), RA2, RA0);
+ mem(Stw, O(Frame, fp), RA2, RFP);
+ mem(Ldw, O(REG, M), RREG, RA3);
+ mem(Stw, O(Frame, mr), RA2, RA3);
+ opwst(i, Ldw, RA3);
+ CMPH(AL, RA3);
+ mlnil = code;
+ BRA(EQ, 0);
+ if((i->add&ARM) == AXIMM) {
+ mem(Ldw, OA(Modlink, links)+i->reg*sizeof(Modl)+O(Modl, u.pc), RA3, RA0);
+ } else {
+ mid(i, Ldw, RA1);
+ DP(AL, Add, RA3, RA1, (3<<3), RA1); // assumes sizeof(Modl) == 8
+ mem(Ldw, OA(Modlink, links)+O(Modl, u.pc), RA1, RA0);
+ }
+ PATCH(mlnil);
+ CALLMAC(AL, MacMCAL);
+}
+
+static void
+larith(Inst *i, int op, int opc)
+{
+ opwld(i, Lea, RA0);
+ mid(i, Lea, RA3);
+ mem(Ldw, Blo, RA0, RA1); // ls
+ mem(Ldw, Blo, RA3, RA2);
+ DP(AL, op, RA2, RA2, 0, RA1) | SBIT; // ls: RA2 = RA2 op RA1
+ mem(Ldw, Bhi, RA0, RA1);
+ mem(Ldw, Bhi, RA3, RA0);
+ DP(AL, opc, RA0, RA0, 0, RA1); // ms: RA0 = RA0 opc RA1
+ if((i->add&ARM) != AXNON)
+ opwst(i, Lea, RA3);
+ mem(Stw, Blo, RA3, RA2);
+ mem(Stw, Bhi, RA3, RA0);
+}
+
+static void
+movloop(Inst *i, int s)
+{
+ int b;
+
+ b = (s==1);
+ opwst(i, Lea, RA2);
+ LDxP(AL, RA1, RA0, s, b);
+ STxP(AL, RA2, RA0, s, b);
+ DPI(AL, Sub, RA3, RA3, 0, 1) | SBIT;
+ BRA(NE, (-3*4-8)>>2);
+}
+
+static void
+movmem(Inst *i)
+{
+ ulong *cp;
+
+ // source address already in RA1
+ if((i->add&ARM) != AXIMM){
+ mid(i, Ldw, RA3);
+ CMPI(AL, RA3, 0, 0, 0);
+ cp = code;
+ BRA(LE, 0);
+ movloop(i, 1);
+ PATCH(cp);
+ return;
+ }
+ switch(i->reg){
+ case 0:
+ break;
+ case 4:
+ LDW(AL, RA1, RA2, 0);
+ opwst(i, Stw, RA2);
+ break;
+ case 8:
+ LDW(AL, RA1, RA2, 0);
+ opwst(i, Lea, RA3);
+ LDW(AL, RA1, RA1, 4);
+ STW(AL, RA3, RA2, 0);
+ STW(AL, RA3, RA1, 4);
+ break;
+ default:
+ // could use ldm/stm loop...
+ if((i->reg&3) == 0) {
+ con(i->reg>>2, RA3, 1);
+ movloop(i, 4);
+ } else {
+ con(i->reg, RA3, 1);
+ movloop(i, 1);
+ }
+ break;
+ }
+}
+
+static
+void
+compdbg(void)
+{
+ print("%s:%lud@%.8lux\n", R.M->m->name, *(ulong*)R.m, *(ulong*)R.s);
+}
+
+static void
+comgoto(Inst *i)
+{
+ WORD *t, *e;
+
+ opwld(i, Ldw, RA1);
+ opwst(i, Lea, RA0);
+ LDRW(AL, RA0, R15, (2<<3), RA1);
+ flushcon(0);
+
+ if(pass == 0)
+ return;
+
+ t = (WORD*)(mod->origmp+i->d.ind);
+ e = t + t[-1];
+ t[-1] = 0;
+ while(t < e) {
+ t[0] = RELPC(patch[t[0]]);
+ t++;
+ }
+}
+
+static void
+comp(Inst *i)
+{
+ int r, imm;
+ char buf[64];
+//ulong *s = code;
+ if(0) {
+ Inst xx;
+ xx.add = AXIMM|SRC(AIMM);
+ xx.s.imm = (ulong)code;
+ xx.reg = i-mod->prog;
+ puntpc = 0;
+ punt(&xx, SRCOP, compdbg);
+ puntpc = 1;
+ flushcon(1);
+ }
+ flushchk();
+
+ switch(i->op) {
+ default:
+ snprint(buf, sizeof buf, "%s compile, no '%D'", mod->name, i);
+ error(buf);
+ break;
+ case IMCALL:
+ if((i->add&ARM) == AXIMM)
+ commcall(i);
+ else
+ punt(i, SRCOP|DSTOP|THREOP|WRTPC|NEWPC, optab[i->op]);
+ break;
+ case ISEND:
+ case IRECV:
+ case IALT:
+ punt(i, SRCOP|DSTOP|TCHECK|WRTPC, optab[i->op]);
+ break;
+ case ISPAWN:
+ punt(i, SRCOP|DBRAN, optab[i->op]);
+ break;
+ case IBNEC:
+ case IBEQC:
+ case IBLTC:
+ case IBLEC:
+ case IBGTC:
+ case IBGEC:
+ punt(i, SRCOP|DBRAN|NEWPC|WRTPC, optab[i->op]);
+ break;
+ case ICASEC:
+ comcase(i, 0);
+ punt(i, SRCOP|DSTOP|NEWPC, optab[i->op]);
+ break;
+ case ICASEL:
+ comcasel(i);
+ punt(i, SRCOP|DSTOP|NEWPC, optab[i->op]);
+ break;
+ case IADDC:
+ case IMULL:
+ case IDIVL:
+ case IMODL:
+ case IMNEWZ:
+ case ILSRW:
+ case ILSRL:
+ case IMODW:
+ case IMODB:
+ case IDIVW:
+ case IDIVB:
+ punt(i, SRCOP|DSTOP|THREOP, optab[i->op]);
+ break;
+ case ILOAD:
+ case INEWA:
+ case INEWAZ:
+ case INEW:
+ case INEWZ:
+ case ISLICEA:
+ case ISLICELA:
+ case ICONSB:
+ case ICONSW:
+ case ICONSL:
+ case ICONSF:
+ case ICONSM:
+ case ICONSMP:
+ case ICONSP:
+ case IMOVMP:
+ case IHEADMP:
+ case IHEADB:
+ case IHEADW:
+ case IHEADL:
+ case IINSC:
+ case ICVTAC:
+ case ICVTCW:
+ case ICVTWC:
+ case ICVTLC:
+ case ICVTCL:
+ case ICVTFC:
+ case ICVTCF:
+ case ICVTRF:
+ case ICVTFR:
+ case ICVTWS:
+ case ICVTSW:
+ case IMSPAWN:
+ case ICVTCA:
+ case ISLICEC:
+ case INBALT:
+ punt(i, SRCOP|DSTOP, optab[i->op]);
+ break;
+ case INEWCM:
+ case INEWCMP:
+ punt(i, SRCOP|DSTOP|THREOP, optab[i->op]);
+ break;
+ case IMFRAME:
+ if((i->add&ARM) == AXIMM)
+ commframe(i);
+ else
+ punt(i, SRCOP|DSTOP|THREOP, optab[i->op]);
+ break;
+ case ICASE:
+ comcase(i, 1);
+ break;
+ case IGOTO:
+ comgoto(i);
+ break;
+ case IMOVF:
+ if(!SOFTFP){
+ opflld(i, Ldf, FA2);
+ opflst(i, Stf, FA2);
+ break;
+ }
+ /* if no hardware, just fall through */
+ case IMOVL:
+ opwld(i, Lea, RA1);
+ LDW(AL, RA1, RA2, 0);
+ LDW(AL, RA1, RA3, 4);
+ opwst(i, Lea, RA1);
+ STW(AL, RA1, RA2, 0);
+ STW(AL, RA1, RA3, 4);
+ break;
+ break;
+ case IHEADM:
+ opwld(i, Ldw, RA1);
+ NOTNIL(RA1);
+ if(OA(List,data) != 0)
+ DPI(AL, Add, RA1, RA1, 0, OA(List,data));
+ movmem(i);
+ break;
+/*
+ case IHEADW:
+ opwld(i, Ldw, RA0);
+ NOTNIL(RA0);
+ mem(Ldw, OA(List, data), RA0, RA0);
+ opwst(i, Stw, RA0);
+ break;
+*/
+ case IMOVM:
+ opwld(i, Lea, RA1);
+ movmem(i);
+ break;
+ case IFRAME:
+ if(UXSRC(i->add) != SRC(AIMM)) {
+ punt(i, SRCOP|DSTOP, optab[i->op]);
+ break;
+ }
+ tinit[i->s.imm] = 1;
+ con((ulong)mod->type[i->s.imm], RA3, 1);
+ CALL(base+macro[MacFRAM]);
+ opwst(i, Stw, RA2);
+ break;
+ case INEWCB:
+ case INEWCW:
+ case INEWCF:
+ case INEWCP:
+ case INEWCL:
+ punt(i, DSTOP|THREOP, optab[i->op]);
+ break;
+ case IEXIT:
+ punt(i, 0, optab[i->op]);
+ break;
+ case ICVTBW:
+ opwld(i, Ldb, RA0);
+ opwst(i, Stw, RA0);
+ break;
+ case ICVTWB:
+ opwld(i, Ldw, RA0);
+ opwst(i, Stb, RA0);
+ break;
+ case ILEA:
+ opwld(i, Lea, RA0);
+ opwst(i, Stw, RA0);
+ break;
+ case IMOVW:
+ opwld(i, Ldw, RA0);
+ opwst(i, Stw, RA0);
+ break;
+ case IMOVB:
+ opwld(i, Ldb, RA0);
+ opwst(i, Stb, RA0);
+ break;
+ case ITAIL:
+ opwld(i, Ldw, RA0);
+ NOTNIL(RA0);
+ mem(Ldw, O(List, tail), RA0, RA1);
+ goto movp;
+ case IMOVP:
+ opwld(i, Ldw, RA1);
+ goto movp;
+ case IHEADP:
+ opwld(i, Ldw, RA0);
+ NOTNIL(RA0);
+ mem(Ldw, OA(List, data), RA0, RA1);
+ movp:
+ CMPH(AL, RA1);
+ CALLMAC(NE, MacCOLR); // colour if not H
+ opwst(i, Lea, RA2);
+ mem(Ldw, 0,RA2, RA0);
+ mem(Stw, 0,RA2, RA1);
+ CALLMAC(AL, MacFRP);
+ break;
+ case ILENA:
+ opwld(i, Ldw, RA1);
+ con(0, RA0, 1);
+ CMPH(AL, RA1);
+ LDW(NE, RA1, RA0, O(Array,len));
+ opwst(i, Stw, RA0);
+ break;
+ case ILENC:
+ opwld(i, Ldw, RA1);
+ con(0, RA0, 1);
+ CMPH(AL, RA1);
+ memc(NE, Ldw, O(String,len),RA1, RA0);
+ CMPI(AL, RA0, 0, 0, 0);
+ DPI(LT, Rsb, RA0, RA0, 0, 0);
+ opwst(i, Stw, RA0);
+ break;
+ case ILENL:
+ con(0, RA0, 1);
+ opwld(i, Ldw, RA1);
+
+ CMPH(AL, RA1);
+ LDW(NE, RA1, RA1, O(List, tail));
+ DPI(NE, Add, RA0, RA0, 0, 1);
+ BRA(NE, (-4*3-8)>>2);
+
+ opwst(i, Stw, RA0);
+ break;
+ case ICALL:
+ opwld(i, Ldw, RA0);
+ con(RELPC(patch[i-mod->prog+1]), RA1, 0);
+ mem(Stw, O(Frame, lr), RA0, RA1);
+ mem(Stw, O(Frame, fp), RA0, RFP);
+ MOV(RA0, RFP);
+ BRADIS(AL, i->d.ins-mod->prog);
+ flushcon(0);
+ break;
+ case IJMP:
+ if(RESCHED)
+ schedcheck(i);
+ BRADIS(AL, i->d.ins-mod->prog);
+ flushcon(0);
+ break;
+ case IBEQW:
+ cbra(i, EQ);
+ break;
+ case IBNEW:
+ cbra(i, NE);
+ break;
+ case IBLTW:
+ cbra(i, LT);
+ break;
+ case IBLEW:
+ cbra(i, LE);
+ break;
+ case IBGTW:
+ cbra(i, GT);
+ break;
+ case IBGEW:
+ cbra(i, GE);
+ break;
+ case IBEQB:
+ cbrab(i, EQ);
+ break;
+ case IBNEB:
+ cbrab(i, NE);
+ break;
+ case IBLTB:
+ cbrab(i, LT);
+ break;
+ case IBLEB:
+ cbrab(i, LE);
+ break;
+ case IBGTB:
+ cbrab(i, GT);
+ break;
+ case IBGEB:
+ cbrab(i, GE);
+ break;
+ case IBEQF:
+ cbraf(i, EQ);
+ break;
+ case IBNEF:
+ cbraf(i, NE);
+ break;
+ case IBLTF:
+ cbraf(i, LT);
+ break;
+ case IBLEF:
+ cbraf(i, LE);
+ break;
+ case IBGTF:
+ cbraf(i, GT);
+ break;
+ case IBGEF:
+ cbraf(i, GE);
+ break;
+ case IRET:
+ mem(Ldw, O(Frame,t), RFP, RA1);
+ BRAMAC(AL, MacRET);
+ break;
+ case IMULW:
+ opwld(i, Ldw, RA1);
+ mid(i, Ldw, RA0);
+ MUL(AL, RA1, RA0, RA0);
+ opwst(i, Stw, RA0);
+ break;
+ case IMULB:
+ opwld(i, Ldb, RA1);
+ mid(i, Ldb, RA0);
+ MUL(AL, RA1, RA0, RA0);
+ opwst(i, Stb, RA0);
+ break;
+ case IORW:
+ r = Orr;
+ goto arithw;
+ case IANDW:
+ r = And;
+ goto arithw;
+ case IXORW:
+ r = Eor;
+ goto arithw;
+ case ISUBW:
+ r = Sub;
+ goto arithw;
+ case IADDW:
+ r = Add;
+ arithw:
+ mid(i, Ldw, RA1);
+ if(UXSRC(i->add) == SRC(AIMM) && FITS8(i->s.imm))
+ DPI(AL, r, RA1, RA0, 0, i->s.imm);
+ else if(UXSRC(i->add) == SRC(AIMM) && immrot(i->s.imm)){
+ DPI(AL, r, RA1, RA0, 0, 0) | immrot(i->s.imm);
+ //print("rot: %ux %ux\n", i->s.imm, immrot(i->s.imm)); das(code-1, 1);
+ } else {
+ opwld(i, Ldw, RA0);
+ DP(AL, r, RA1, RA0, 0, RA0);
+ }
+ opwst(i, Stw, RA0);
+ break;
+ case ISHRW:
+ r = 2;
+ shiftw:
+ mid(i, Ldw, RA1);
+ if(UXSRC(i->add) == SRC(AIMM) && FITS5(i->s.imm))
+ DP(AL, Mov, 0, RA0, ((i->s.imm&0x3F)<<3)|(r<<1), RA1);
+ else {
+ opwld(i, Ldw, RA0);
+ DP(AL, Mov, 0, RA0, (RA0<<4)|(r<<1)|1, RA1);
+ }
+ opwst(i, Stw, RA0);
+ break;
+ case ISHLW:
+ r = 0;
+ goto shiftw;
+ break;
+ case IORB:
+ r = Orr;
+ goto arithb;
+ case IANDB:
+ r = And;
+ goto arithb;
+ case IXORB:
+ r = Eor;
+ goto arithb;
+ case ISUBB:
+ r = Sub;
+ goto arithb;
+ case IADDB:
+ r = Add;
+ arithb:
+ mid(i, Ldb, RA1);
+ if(UXSRC(i->add) == SRC(AIMM))
+ DPI(AL, r, RA1, RA0, 0, i->s.imm);
+ else {
+ opwld(i, Ldb, RA0);
+ DP(AL, r, RA1, RA0, 0, RA0);
+ }
+ opwst(i, Stb, RA0);
+ break;
+ case ISHRB:
+ r = 2;
+ goto shiftb;
+ case ISHLB:
+ r = 0;
+ shiftb:
+ mid(i, Ldb, RA1);
+ if(UXSRC(i->add) == SRC(AIMM) && FITS5(i->s.imm))
+ DP(AL, Mov, 0, RA0, ((i->s.imm&0x3F)<<3)|(r<<1), RA1);
+ else {
+ opwld(i, Ldw, RA0);
+ DP(AL, Mov, 0, RA0, (RA0<<4)|(r<<1)|1, RA1);
+ }
+ opwst(i, Stb, RA0);
+ break;
+ case IINDC:
+ opwld(i, Ldw, RA1); // RA1 = string
+ NOTNIL(RA1);
+ imm = 1;
+ if((i->add&ARM) != AXIMM || !FITS12((short)i->reg<<Lg2Rune) || immrot((short)i->reg) == 0){
+ mid(i, Ldw, RA2); // RA2 = i
+ imm = 0;
+ }
+ mem(Ldw, O(String,len),RA1, RA0); // len<0 => index Runes, otherwise bytes
+ if(bflag){
+ DPI(AL, Orr, RA0, RA3, 0, 0);
+ DPI(LT, Rsb, RA3, RA3, 0, 0);
+ if(imm)
+ BCKR(immrot((short)i->reg), RA3);
+ else
+ BCK(RA2, RA3);
+ }
+ DPI(AL, Add, RA1, RA1, 0, O(String,data));
+ CMPI(AL, RA0, 0, 0, 0);
+ if(imm){
+ LDB(GE, RA1, RA3, i->reg);
+ LDW(LT, RA1, RA3, (short)i->reg<<Lg2Rune);
+ } else {
+ LDRB(GE, RA1, RA3, 0, RA2);
+ DP(LT, Mov, 0, RA2, (Lg2Rune<<3), RA2);
+ LDRW(LT, RA1, RA3, 0, RA2);
+ }
+ opwst(i, Stw, RA3);
+//if(pass){print("%D\n", i); das(s, code-s);}
+ break;
+ case IINDL:
+ case IINDF:
+ case IINDW:
+ case IINDB:
+ opwld(i, Ldw, RA0); /* a */
+ NOTNIL(RA0);
+ if(bflag)
+ mem(Ldw, O(Array, len), RA0, RA2);
+ mem(Ldw, O(Array, data), RA0, RA0);
+ r = 0;
+ switch(i->op) {
+ case IINDL:
+ case IINDF:
+ r = 3;
+ break;
+ case IINDW:
+ r = 2;
+ break;
+ }
+ if(UXDST(i->add) == DST(AIMM) && (imm = immrot(i->d.imm)) != 0) {
+ if(bflag)
+ BCKR(imm, RA2);
+ if(i->d.imm != 0)
+ DPI(AL, Add, RA0, RA0, 0, 0) | immrot(i->d.imm<<r);
+ } else {
+ opwst(i, Ldw, RA1);
+ if(bflag)
+ BCK(RA1, RA2);
+ DP(AL, Add, RA0, RA0, r<<3, RA1);
+ }
+ mid(i, Stw, RA0);
+//if(pass){print("%D\n", i); das(s, code-s);}
+ break;
+ case IINDX:
+ opwld(i, Ldw, RA0); /* a */
+ NOTNIL(RA0);
+ opwst(i, Ldw, RA1); /* i */
+
+ if(bflag){
+ mem(Ldw, O(Array, len), RA0, RA2);
+ BCK(RA1, RA2);
+ }
+ mem(Ldw, O(Array, t), RA0, RA2);
+ mem(Ldw, O(Array, data), RA0, RA0);
+ mem(Ldw, O(Type, size), RA2, RA2);
+ MUL(AL, RA2, RA1, RA1);
+ DP(AL, Add, RA1, RA0, 0, RA0);
+ mid(i, Stw, RA0);
+//if(pass){print("%D\n", i); das(s, code-s);}
+ break;
+ case IADDL:
+ larith(i, Add, Adc);
+ break;
+ case ISUBL:
+ larith(i, Sub, Sbc);
+ break;
+ case IORL:
+ larith(i, Orr, Orr);
+ break;
+ case IANDL:
+ larith(i, And, And);
+ break;
+ case IXORL:
+ larith(i, Eor, Eor);
+ break;
+ case ICVTWL:
+ opwld(i, Ldw, RA1);
+ opwst(i, Lea, RA2);
+ DP(AL, Mov, 0, RA0, (0<<3)|(2<<1), RA1); // ASR 32
+ STW(AL, RA2, RA1, Blo);
+ STW(AL, RA2, RA0, Bhi);
+ break;
+ case ICVTLW:
+ opwld(i, Lea, RA0);
+ mem(Ldw, Blo, RA0, RA0);
+ opwst(i, Stw, RA0);
+ break;
+ case IBEQL:
+ cbral(i, NE, EQ, ANDAND);
+ break;
+ case IBNEL:
+ cbral(i, NE, NE, OROR);
+ break;
+ case IBLEL:
+ cbral(i, LT, LS, EQAND);
+ break;
+ case IBGTL:
+ cbral(i, GT, HI, EQAND);
+ break;
+ case IBLTL:
+ cbral(i, LT, CC, EQAND);
+ break;
+ case IBGEL:
+ cbral(i, GT, CS, EQAND);
+ break;
+ case ICVTFL:
+ case ICVTLF:
+ punt(i, SRCOP|DSTOP, optab[i->op]);
+ break;
+ case IDIVF:
+ r = Dvf;
+ goto arithf;
+ case IMULF:
+ r = Muf;
+ goto arithf;
+ case ISUBF:
+ r = Suf;
+ goto arithf;
+ case IADDF:
+ r = Adf;
+ arithf:
+ if(SOFTFP){
+ /* software fp */
+ USED(r);
+ punt(i, SRCOP|DSTOP|THREOP, optab[i->op]);
+ break;
+ }
+ opflld(i, Ldf, FA2);
+ midfl(i, Ldf, FA4);
+ CPDO2(AL, r, FA4, FA4, FA2);
+ opflst(i, Stf, FA4);
+ break;
+ case INEGF:
+ if(SOFTFP){
+ punt(i, SRCOP|DSTOP, optab[i->op]);
+ break;
+ }
+ opflld(i, Ldf, FA2);
+ CPDO1(AL, Mnf, FA2, FA2);
+ opflst(i, Stf, FA2);
+//if(pass){print("%D\n", i); das(s, code-s);}
+ break;
+ case ICVTWF:
+ if(SOFTFP){
+ punt(i, SRCOP|DSTOP, optab[i->op]);
+ break;
+ }
+ opwld(i, Ldw, RA2);
+ CPFLT(AL, FA2, RA2);
+ opflst(i, Stf, FA2);
+//if(pass){print("%D\n", i); das(s, code-s);}
+ break;
+ case ICVTFW:
+ if(SOFTFP){
+ punt(i, SRCOP|DSTOP, optab[i->op]);
+ break;
+ }
+ opflld(i, Ldf, FA2);
+ CPFIX(AL, RA2, FA2);
+ opwst(i, Stw, RA2);
+//if(pass){print("%D\n", i); das(s, code-s);}
+ break;
+ case ISHLL:
+ /* should do better */
+ punt(i, SRCOP|DSTOP|THREOP, optab[i->op]);
+ break;
+ case ISHRL:
+ /* should do better */
+ punt(i, SRCOP|DSTOP|THREOP, optab[i->op]);
+ break;
+ case IRAISE:
+ punt(i, SRCOP|WRTPC|NEWPC, optab[i->op]);
+ break;
+ case IMULX:
+ case IDIVX:
+ case ICVTXX:
+ case IMULX0:
+ case IDIVX0:
+ case ICVTXX0:
+ case IMULX1:
+ case IDIVX1:
+ case ICVTXX1:
+ case ICVTFX:
+ case ICVTXF:
+ case IEXPW:
+ case IEXPL:
+ case IEXPF:
+ punt(i, SRCOP|DSTOP|THREOP, optab[i->op]);
+ break;
+ case ISELF:
+ punt(i, DSTOP, optab[i->op]);
+ break;
+ }
+}
+
+static void
+preamble(void)
+{
+ if(comvec)
+ return;
+
+ comvec = malloc(10 * sizeof(*code));
+ if(comvec == nil)
+ error(exNomem);
+ code = (ulong*)comvec;
+
+ con((ulong)&R, RREG, 0);
+ mem(Stw, O(REG, xpc), RREG, RLINK);
+ mem(Ldw, O(REG, FP), RREG, RFP);
+ mem(Ldw, O(REG, MP), RREG, RMP);
+ mem(Ldw, O(REG, PC), RREG, R15);
+ pass++;
+ flushcon(0);
+ pass--;
+
+ segflush(comvec, 10 * sizeof(*code));
+}
+
+static void
+maccase(void)
+{
+ ulong *cp1, *loop, *inner;
+/*
+ * RA1 = value (input arg), t
+ * RA2 = count, n
+ * RA3 = table pointer (input arg)
+ * RA0 = n/2, n2
+ * RCON = pivot element t+n/2*3, l
+ */
+ LDW(AL, RA3, RA2, 0); // count from table
+ MOV(RA3, RLINK); // initial table pointer
+
+ loop = code; // loop:
+ CMPI(AL, RA2, 0, 0, 0);
+ cp1 = code;
+ BRA(LE, 0); // n <= 0? goto out
+
+ inner = code;
+ DP(AL, Mov, 0, RA0, (1<<3)|2, RA2); // n2 = n>>1
+ DP(AL, Add, RA0, RCON, (1<<3), RA0); // n' = n2+(n2<<1) = 3*n2
+ DP(AL, Add, RA3, RCON, (2<<3), RCON); // l = t + n2*3;
+
+ LDW(AL, RCON, RTA, 4);
+ CMP(AL, RA1, 0, 0, RTA);
+ DP(LT, Mov, 0, RA2, 0, RA0); // v < l[1]? n=n2
+ BRANCH(LT, loop); // v < l[1]? goto loop
+
+ LDW(AL, RCON, RTA, 8);
+ CMP(AL, RA1, 0, 0, RTA);
+ LDW(LT, RCON, R15, 12); // v >= l[1] && v < l[2] => found; goto l[3]
+
+ // v >= l[2] (high)
+ DPI(AL, Add, RCON, RA3, 0, 12); // t = l+3;
+ DPI(AL, Add, RA0, RTA, 0, 1);
+ DP(AL, Sub, RA2, RA2, 0, RTA) | SBIT; // n -= n2+1
+ BRANCH(GT, inner); // n > 0? goto loop
+
+ PATCH(cp1); // out:
+ LDW(AL, RLINK, RA2, 0); // initial n
+ DP(AL, Add, RA2, RA2, (1<<3), RA2); // n = n+(n<<1) = 3*n
+ DP(AL, Add, RLINK, RLINK, (2<<3), RA2); // t' = &(initial t)[n*3]
+ LDW(AL, RLINK, R15, 4); // goto (initial t)[n*3+1]
+}
+
+static void
+macfrp(void)
+{
+ /* destroy the pointer in RA0 */
+ CMPH(AL, RA0);
+ CRETURN(EQ); // arg == H? => return
+
+ mem(Ldw, O(Heap, ref)-sizeof(Heap), RA0, RA2);
+ DPI(AL, Sub, RA2, RA2, 0, 1) | SBIT;
+ memc(NE, Stw, O(Heap, ref)-sizeof(Heap), RA0, RA2);
+ CRETURN(NE); // --h->ref != 0 => return
+
+ mem(Stw, O(REG, FP), RREG, RFP);
+ mem(Stw, O(REG, st), RREG, RLINK);
+ mem(Stw, O(REG, s), RREG, RA0);
+ CALL(rdestroy);
+ con((ulong)&R, RREG, 1);
+ mem(Ldw, O(REG, st), RREG, RLINK);
+ mem(Ldw, O(REG, FP), RREG, RFP);
+ mem(Ldw, O(REG, MP), RREG, RMP);
+ RETURN;
+ flushcon(0);
+}
+
+static void
+maccolr(void)
+{
+ /* color the pointer in RA1 */
+ mem(Ldw, O(Heap, ref)-sizeof(Heap), RA1, RA0);
+ DPI(AL, Add, RA0, RA0, 0, 1);
+ mem(Stw, O(Heap, ref)-sizeof(Heap), RA1, RA0); // h->ref++
+ con((ulong)&mutator, RA2, 1);
+ mem(Ldw, O(Heap, color)-sizeof(Heap), RA1, RA0);
+ mem(Ldw, 0, RA2, RA2);
+ CMP(AL, RA0, 0, 0, RA2);
+ CRETURN(EQ); // return if h->color == mutator
+ con(propagator, RA2, 1);
+ mem(Stw, O(Heap, color)-sizeof(Heap), RA1, RA2); // h->color = propagator
+ con((ulong)&nprop, RA2, 1);
+ mem(Stw, 0, RA2, RA2); // nprop = !0
+ RETURN;
+ flushcon(0);
+}
+
+static void
+macret(void)
+{
+ Inst i;
+ ulong *cp1, *cp2, *cp3, *cp4, *cp5, *linterp;
+
+ CMPI(AL, RA1, 0, 0, 0);
+ cp1 = code;
+ BRA(EQ, 0); // t(Rfp) == 0
+
+ mem(Ldw, O(Type,destroy),RA1, RA0);
+ CMPI(AL, RA0, 0, 0, 0);
+ cp2 = code;
+ BRA(EQ, 0); // destroy(t(fp)) == 0
+
+ mem(Ldw, O(Frame,fp),RFP, RA2);
+ CMPI(AL, RA2, 0, 0, 0);
+ cp3 = code;
+ BRA(EQ, 0); // fp(Rfp) == 0
+
+ mem(Ldw, O(Frame,mr),RFP, RA3);
+ CMPI(AL, RA3, 0, 0, 0);
+ cp4 = code;
+ BRA(EQ, 0); // mr(Rfp) == 0
+
+ mem(Ldw, O(REG,M),RREG, RA2);
+ mem(Ldw, O(Heap,ref)-sizeof(Heap),RA2, RA3);
+ DPI(AL, Sub, RA3, RA3, 0, 1) | SBIT;
+ cp5 = code;
+ BRA(EQ, 0); // --ref(arg) == 0
+ mem(Stw, O(Heap,ref)-sizeof(Heap),RA2, RA3);
+
+ mem(Ldw, O(Frame,mr),RFP, RA1);
+ mem(Stw, O(REG,M),RREG, RA1);
+ mem(Ldw, O(Modlink,MP),RA1, RMP);
+ mem(Stw, O(REG,MP),RREG, RMP);
+ mem(Ldw, O(Modlink,compiled), RA1, RA3); // R.M->compiled
+ CMPI(AL, RA3, 0, 0, 0);
+ linterp = code;
+ BRA(EQ, 0);
+
+ PATCH(cp4);
+ MOV(R15, R14); // call destroy(t(fp))
+ MOV(RA0, R15);
+
+ mem(Stw, O(REG,SP),RREG, RFP);
+ mem(Ldw, O(Frame,lr),RFP, RA1);
+ mem(Ldw, O(Frame,fp),RFP, RFP);
+ mem(Stw, O(REG,FP),RREG, RFP); // R.FP = RFP
+ DP(AL, Mov, 0, R15, 0, RA1); // goto lr(Rfp), if compiled
+
+ PATCH(linterp);
+ MOV(R15, R14); // call destroy(t(fp))
+ MOV(RA0, R15);
+
+ mem(Stw, O(REG,SP),RREG, RFP);
+ mem(Ldw, O(Frame,lr),RFP, RA1);
+ mem(Ldw, O(Frame,fp),RFP, RFP);
+ mem(Stw, O(REG,PC),RREG, RA1); // R.PC = fp->lr
+ mem(Stw, O(REG,FP),RREG, RFP); // R.FP = RFP
+ mem(Ldw, O(REG, xpc), RREG, RLINK);
+ RETURN; // return to xec uncompiled code
+
+ PATCH(cp1);
+ PATCH(cp2);
+ PATCH(cp3);
+ PATCH(cp5);
+ i.add = AXNON;
+ punt(&i, TCHECK|NEWPC, optab[IRET]);
+}
+
+static void
+macmcal(void)
+{
+ ulong *lab;
+
+ CMPH(AL, RA0);
+ memc(NE, Ldw, O(Modlink, prog), RA3, RA1); // RA0 != H
+ CMPI(NE, RA1, 0, 0, 0); // RA0 != H
+ lab = code;
+ BRA(NE, 0); // RA0 != H && m->prog!=0
+
+ mem(Stw, O(REG, st), RREG, RLINK);
+ mem(Stw, O(REG, FP), RREG, RA2);
+ mem(Stw, O(REG, dt), RREG, RA0);
+ CALL(rmcall); // CALL rmcall
+
+ con((ulong)&R, RREG, 1); // MOVL $R, RREG
+ mem(Ldw, O(REG, st), RREG, RLINK);
+ mem(Ldw, O(REG, FP), RREG, RFP);
+ mem(Ldw, O(REG, MP), RREG, RMP);
+ RETURN;
+
+ PATCH(lab); // patch:
+ DP(AL, Mov, 0, RFP, 0, RA2);
+ mem(Stw, O(REG, M), RREG, RA3); // MOVL RA3, R.M
+ mem(Ldw, O(Heap, ref)-sizeof(Heap), RA3, RA1);
+ DPI(AL, Add, RA1, RA1, 0, 1);
+ mem(Stw, O(Heap, ref)-sizeof(Heap), RA3, RA1);
+ mem(Ldw, O(Modlink, MP), RA3, RMP); // MOVL R.M->mp, RMP
+ mem(Stw, O(REG, MP), RREG, RMP); // MOVL RA3, R.MP R.MP = ml->m
+ mem(Ldw, O(Modlink,compiled), RA3, RA1); // M.compiled?
+ CMPI(AL, RA1, 0, 0, 0);
+ DP(NE, Mov, 0, R15, 0, RA0); // return to compiled code
+ mem(Stw, O(REG,FP),RREG, RFP); // R.FP = RFP
+ mem(Stw, O(REG,PC),RREG, RA0); // R.PC = RPC
+ mem(Ldw, O(REG, xpc), RREG, RLINK);
+ RETURN; // return to xec uncompiled code
+ flushcon(0);
+}
+
+static void
+macfram(void)
+{
+ ulong *lab1;
+
+ mem(Ldw, O(REG, SP), RREG, RA0); // MOVL R.SP, RA0
+ mem(Ldw, O(Type, size), RA3, RA1);
+ DP(AL, Add, RA0, RA0, 0, RA1); // nsp = R.SP + t->size
+ mem(Ldw, O(REG, TS), RREG, RA1);
+ CMP(AL, RA0, 0, 0, RA1); // nsp :: R.TS
+ lab1 = code;
+ BRA(CS, 0); // nsp >= R.TS; must expand
+
+ mem(Ldw, O(REG, SP), RREG, RA2); // MOVL R.SP, RA2
+ mem(Stw, O(REG, SP), RREG, RA0); // MOVL RA0, R.SP
+
+ mem(Stw, O(Frame, t), RA2, RA3); // MOVL RA3, t(RA2) f->t = t
+ con(0, RA0, 1);
+ mem(Stw, O(Frame,mr), RA2, RA0); // MOVL $0, mr(RA2) f->mr
+ mem(Ldw, O(Type, initialize), RA3, R15); // become t->init(RA2), returning RA2
+
+ PATCH(lab1);
+ mem(Stw, O(REG, s), RREG, RA3);
+ mem(Stw, O(REG, st), RREG, RLINK);
+ mem(Stw, O(REG, FP), RREG, RFP); // MOVL RFP, R.FP
+ CALL(extend); // CALL extend
+
+ con((ulong)&R, RREG, 1);
+ mem(Ldw, O(REG, st), RREG, RLINK);
+ mem(Ldw, O(REG, FP), RREG, RFP); // MOVL R.FP, RFP
+ mem(Ldw, O(REG, s), RREG, RA2); // MOVL R.s, *R.d
+ mem(Ldw, O(REG, MP), RREG, RMP); // MOVL R.MP, RMP
+ RETURN; // RET
+}
+
+static void
+macmfra(void)
+{
+ mem(Stw, O(REG, st), RREG, RLINK);
+ mem(Stw, O(REG, s), RREG, RA3); // Save type
+ mem(Stw, O(REG, d), RREG, RA0); // Save destination
+ mem(Stw, O(REG, FP), RREG, RFP);
+ CALL(rmfram); // CALL rmfram
+
+ con((ulong)&R, RREG, 1);
+ mem(Ldw, O(REG, st), RREG, RLINK);
+ mem(Ldw, O(REG, FP), RREG, RFP);
+ mem(Ldw, O(REG, MP), RREG, RMP);
+ RETURN;
+}
+
+static void
+macrelq(void)
+{
+ mem(Stw, O(REG,FP),RREG, RFP); // R.FP = RFP
+ mem(Stw, O(REG,PC),RREG, RLINK); // R.PC = RLINK
+ mem(Ldw, O(REG, xpc), RREG, RLINK);
+ RETURN;
+}
+
+void
+comd(Type *t)
+{
+ int i, j, m, c;
+
+ mem(Stw, O(REG, dt), RREG, RLINK);
+ for(i = 0; i < t->np; i++) {
+ c = t->map[i];
+ j = i<<5;
+ for(m = 0x80; m != 0; m >>= 1) {
+ if(c & m) {
+ mem(Ldw, j, RFP, RA0);
+ CALL(base+macro[MacFRP]);
+ }
+ j += sizeof(WORD*);
+ }
+ flushchk();
+ }
+ mem(Ldw, O(REG, dt), RREG, RLINK);
+ RETURN;
+ flushcon(0);
+}
+
+void
+comi(Type *t)
+{
+ int i, j, m, c;
+
+ con((ulong)H, RA0, 1);
+ for(i = 0; i < t->np; i++) {
+ c = t->map[i];
+ j = i<<5;
+ for(m = 0x80; m != 0; m >>= 1) {
+ if(c & m)
+ mem(Stw, j, RA2, RA0);
+ j += sizeof(WORD*);
+ }
+ flushchk();
+ }
+ RETURN;
+ flushcon(0);
+}
+
+void
+typecom(Type *t)
+{
+ int n;
+ ulong *tmp, *start;
+
+ if(t == nil || t->initialize != 0)
+ return;
+
+ tmp = mallocz(4096*sizeof(ulong), 0);
+ if(tmp == nil)
+ error(exNomem);
+
+ code = tmp;
+ comi(t);
+ n = code - tmp;
+ code = tmp;
+ comd(t);
+ n += code - tmp;
+ free(tmp);
+
+ n *= sizeof(*code);
+ code = mallocz(n, 0);
+ if(code == nil)
+ return;
+
+ start = code;
+ t->initialize = code;
+ comi(t);
+ t->destroy = code;
+ comd(t);
+
+ segflush(start, n);
+
+ if(cflag > 3)
+ print("typ= %.8p %4d i %.8p d %.8p asm=%d\n",
+ t, t->size, t->initialize, t->destroy, n);
+}
+
+static void
+patchex(Module *m, ulong *p)
+{
+ Handler *h;
+ Except *e;
+
+ if((h = m->htab) == nil)
+ return;
+ for( ; h->etab != nil; h++){
+ h->pc1 = p[h->pc1];
+ h->pc2 = p[h->pc2];
+ for(e = h->etab; e->s != nil; e++)
+ e->pc = p[e->pc];
+ if(e->pc != -1)
+ e->pc = p[e->pc];
+ }
+}
+
+int
+compile(Module *m, int size, Modlink *ml)
+{
+ Link *l;
+ Modl *e;
+ int i, n;
+ ulong *s, *tmp;
+
+ base = nil;
+ patch = mallocz(size*sizeof(*patch), 0);
+ tinit = malloc(m->ntype*sizeof(*tinit));
+ tmp = malloc(4096*sizeof(ulong));
+ if(tinit == nil || patch == nil || tmp == nil)
+ goto bad;
+
+ preamble();
+
+ mod = m;
+ n = 0;
+ pass = 0;
+ nlit = 0;
+
+ for(i = 0; i < size; i++) {
+ codeoff = n;
+ code = tmp;
+ comp(&m->prog[i]);
+ patch[i] = n;
+ n += code - tmp;
+ }
+
+ for(i = 0; i < nelem(mactab); i++) {
+ codeoff = n;
+ code = tmp;
+ mactab[i].gen();
+ macro[mactab[i].idx] = n;
+ n += code - tmp;
+ }
+ code = tmp;
+ flushcon(0);
+ n += code - tmp;
+
+ base = mallocz((n+nlit)*sizeof(*code), 0);
+ if(base == nil)
+ goto bad;
+
+ if(cflag > 3)
+ print("dis=%5d %5d 386=%5d asm=%.8p: %s\n",
+ size, size*sizeof(Inst), n, base, m->name);
+
+ pass++;
+ nlit = 0;
+ litpool = base+n;
+ code = base;
+ n = 0;
+ codeoff = 0;
+ for(i = 0; i < size; i++) {
+ s = code;
+ comp(&m->prog[i]);
+ if(patch[i] != n) {
+ print("%3d %D\n", i, &m->prog[i]);
+ print("%lud != %d\n", patch[i], n);
+ urk("phase error");
+ }
+ n += code - s;
+ if(cflag > 4) {
+ print("%3d %D\n", i, &m->prog[i]);
+ das(s, code-s);
+ }
+ }
+
+ for(i = 0; i < nelem(mactab); i++) {
+ s = code;
+ mactab[i].gen();
+ if(macro[mactab[i].idx] != n){
+ print("mac phase err: %lud != %d\n", macro[mactab[i].idx], n);
+ urk("phase error");
+ }
+ n += code - s;
+ if(cflag > 4) {
+ print("%s:\n", mactab[i].name);
+ das(s, code-s);
+ }
+ }
+ s = code;
+ flushcon(0);
+ n += code - s;
+
+ for(l = m->ext; l->name; l++) {
+ l->u.pc = (Inst*)RELPC(patch[l->u.pc-m->prog]);
+ typecom(l->frame);
+ }
+ if(ml != nil) {
+ e = &ml->links[0];
+ for(i = 0; i < ml->nlinks; i++) {
+ e->u.pc = (Inst*)RELPC(patch[e->u.pc-m->prog]);
+ typecom(e->frame);
+ e++;
+ }
+ }
+ for(i = 0; i < m->ntype; i++) {
+ if(tinit[i] != 0)
+ typecom(m->type[i]);
+ }
+ patchex(m, patch);
+ m->entry = (Inst*)RELPC(patch[mod->entry-mod->prog]);
+ free(patch);
+ free(tinit);
+ free(tmp);
+ free(m->prog);
+ m->prog = (Inst*)base;
+ m->compiled = 1;
+ segflush(base, n*sizeof(*base));
+ return 1;
+bad:
+ free(patch);
+ free(tinit);
+ free(base);
+ free(tmp);
+ return 0;
+}
--- /dev/null
+++ b/libinterp/comp-mips.c
@@ -1,0 +1,1962 @@
+#include "lib9.h"
+#include "isa.h"
+#include "interp.h"
+#include "raise.h"
+
+#define T(r) *((void**)(R.r))
+
+#define SRR(op,c,r1,r2) gen((op)|((c)<<6)|((r1)<<16)|((r2)<<11))
+#define RRR(op,r1,r2,r3) gen((op)|((r1)<<16)|((r2)<<21)|((r3)<<11))
+#define FRRR(op,r1,r2,r3) gen((op)|((r1)<<16)|((r2)<<11)|((r3)<<6))
+#define FI(op,c) gen((op)|((c)&0xffff))
+#define IRR(op,c,r1,r2) gen((op)|((c)&0xffff)|((r1)<<21)|((r2)<<16))
+#define BRRI(op,r1,r2,c) gen((op)|((r1)<<21)|((r2)<<16)|((c)&0xffff))
+#define BRI(op,r,c) gen((op)|((r)<<21)|((c)&0xffff))
+#define JR(op,r) gen((op)|((r)<<21))
+#define J(op,c) gen((op)|(((ulong)(c)>>2)&0x3FFFFFFUL))
+
+#ifndef HIOFFSET
+#define HIOFFSET 0 /* big endian */
+#endif
+
+enum
+{
+ Rzero = 0,
+
+ Ro1 = 8,
+ Ro2 = 9,
+ Ro3 = 10,
+ Ri = 11,
+ Rj = 12,
+
+ Rmp = 13,
+ Rfp = 14,
+ Rreg = 15,
+
+ Rpic = 25,
+ Rlink = 31,
+
+ Rf1 = 4,
+ Rf2 = 6,
+
+ Olw = 0x23<<26,
+ Olbu = 0x24<<26,
+ Olhu = 0x25<<26,
+ Osw = 0x2b<<26,
+ Osb = 0x28<<26,
+ Oaddui = 0x09<<26,
+ Olui = 0x0f<<26,
+ Oori = 0x0d<<26,
+ Odiv = (0x00<<26) | 0x1a,
+ Omul = (0x00<<26) | 0x18,
+ Omfhi = (0x00<<26) | 0x10,
+ Omflo = (0x00<<26) | 0x12,
+ Osubu = (0x00<<26) | 0x23,
+ Oaddu = (0x00<<26) | 0x21,
+ Oand = (0x00<<26) | 0x24,
+ Oor = (0x00<<26) | 0x25,
+ Oxor = (0x00<<26) | 0x26,
+ Odelay = (0x00<<26) | 0x27,
+ Osll = (0x00<<26) | 0x00,
+ Osrl = (0x00<<26) | 0x02,
+ Osra = (0x00<<26) | 0x03,
+ Osllv = (0x00<<26) | 0x04,
+ Osrlv = (0x00<<26) | 0x06,
+ Osrav = (0x00<<26) | 0x07,
+ Oslt = (0x00<<26) | 0x2a,
+ Osltu = (0x00<<26) | 0x2b,
+ Obeq = 0x04<<26,
+ Obne = 0x05<<26,
+ Obltz = (0x01<<26) | (0x0<<16),
+ Obgtz = (0x07<<26) | (0x0<<16),
+ Oblez = (0x06<<26) | (0x0<<16),
+ Obgez = (0x01<<26) | (0x1<<16),
+ Ojr = (0x00<<26) | 0x08,
+ Ojalr = (0x00<<26) | 0x09 | (Rlink<<11),
+ Oj = (0x02<<26),
+ Ojal = (0x03<<26),
+ Olea = Oaddui, // pseudo op
+
+ Olf = 0x31<<26,
+ Osf = 0x39<<26,
+ Oaddf = (0x11<<26) | (17<<21) | 0,
+ Osubf = (0x11<<26) | (17<<21) | 1,
+ Omulf = (0x11<<26) | (17<<21) | 2,
+ Odivf = (0x11<<26) | (17<<21) | 3,
+ Onegf = (0x11<<26) | (17<<21) | 7,
+
+ Ocvtwf = (0x11<<26) | (20<<21) | 33,
+ Ocvtfw = (0x11<<26) | (17<<21) | 36,
+
+ Ofeq = (0x11<<26) | (17<<21) | (3<<4) | 2,
+ Oflt = (0x11<<26) | (17<<21) | (3<<4) | 12,
+
+ Obrf = (0x11<<26) | (0x100<<16),
+ Obrt = (0x11<<26) | (0x101<<16),
+
+ SRCOP = (1<<0),
+ DSTOP = (1<<1),
+ WRTPC = (1<<2),
+ TCHECK = (1<<3),
+ NEWPC = (1<<4),
+ DBRAN = (1<<5),
+ THREOP = (1<<6),
+
+ ANDAND = 1,
+ OROR,
+ EQAND,
+
+ XOR,
+ IOR,
+ AND,
+ ADD,
+ SUB,
+
+ OMASK = (1<<4) - 1,
+ REV1 = 1<<4,
+ REV2 = 1<<5,
+
+ Bhi = HIOFFSET,
+ Blo = Bhi ^ 4,
+
+ MacRET = 0,
+ MacFRP,
+ MacINDX,
+ MacCASE,
+ MacLENA,
+ MacFRAM,
+ MacMOVM,
+ MacCOLR,
+ MacMCAL,
+ MacMFRA,
+ MacEND,
+ NMACRO
+};
+
+extern char Tmodule[];
+ void (*comvec)(void);
+extern void das(ulong*);
+static ulong* code;
+static ulong* base;
+static ulong* patch;
+static int pass;
+static int regdelay;
+static Module* mod;
+static ulong* tinit;
+static ulong* litpool;
+static int nlit;
+static ulong macro[NMACRO];
+static void rdestroy(void);
+static void macret(void);
+static void macfrp(void);
+static void macindx(void);
+static void maccase(void);
+static void maclena(void);
+static void macfram(void);
+static void macmovm(void);
+static void maccvtfw(void);
+static void maccolr(void);
+static void macend(void);
+static void macmcal(void);
+static void macmfra(void);
+
+struct
+{
+ int o;
+ void (*f)(void);
+} macinit[] =
+{
+ MacFRP, macfrp, /* decrement and free pointer */
+ MacRET, macret, /* return instruction */
+ MacCASE, maccase, /* case instruction */
+ MacCOLR, maccolr, /* increment and color pointer */
+ MacFRAM, macfram, /* frame instruction */
+ MacMCAL, macmcal, /* mcall bottom half */
+ MacMFRA, macmfra, /* punt mframe because t->initialize==0 */
+ MacMOVM, macmovm,
+ MacLENA, maclena,
+ MacINDX, macindx,
+ MacEND, macend,
+ 0
+};
+
+static void
+rdestroy(void)
+{
+ destroy(R.s);
+}
+
+static void
+rmcall(void)
+{
+ Prog *p;
+ Frame *f;
+
+ f = (Frame*)R.FP;
+ if(f == H)
+ error(exModule);
+
+ f->mr = nil;
+ ((void(*)(Frame*))R.dt)(f);
+ R.SP = (uchar*)f;
+ R.FP = f->fp;
+ if(f->t == nil)
+ unextend(f);
+ else
+ freeptrs(f, f->t);
+ p = currun();
+ if(p->kill != nil)
+ error(p->kill);
+}
+
+static void
+rmfram(void)
+{
+ Type *t;
+ Frame *f;
+ uchar *nsp;
+
+ t = (Type*)R.s;
+ nsp = R.SP + t->size;
+ if(nsp >= R.TS) {
+ R.s = t;
+ extend();
+ T(d) = R.s;
+ return;
+ }
+ f = (Frame*)R.SP;
+ R.SP = nsp;
+ f->t = t;
+ f->mr = nil;
+ initmem(t, f);
+ T(d) = f;
+}
+
+void
+urk(char *s)
+{
+ print("urk: %s\n", s);
+ exits(0);
+}
+
+void
+gen(ulong o)
+{
+ *code++ = o;
+}
+
+void
+delay(void)
+{
+ gen(Odelay);
+}
+
+int
+bigc(long c)
+{
+ c >>= 15;
+ if(c == 0 || c == -1)
+ return 0;
+ return 1;
+}
+
+void
+ldbigc(ulong c, int reg)
+{
+ IRR(Olui, c>>16,Rzero,reg);
+ IRR(Oori, c,reg,reg);
+}
+
+void
+ldc(ulong c, int reg)
+{
+
+ if(bigc(c))
+ ldbigc(c, reg);
+ else
+ IRR(Oaddui, c,Rzero, reg);
+}
+
+void
+xchg(void)
+{
+ ulong t;
+
+ t = code[-1];
+ code[-1] = code[-2];
+ code[-2] = t;
+}
+
+void
+opx(int mode, Adr *a, int op, int reg, int del)
+{
+ ulong c;
+ int r, rx;
+
+ switch(mode) {
+ case AFP:
+ c = a->ind;
+ if(bigc(c))
+ urk("bigc op1b 1");
+ if(regdelay == Rfp)
+ delay();
+ IRR(op, c,Rfp, reg);
+ break;
+ case AMP:
+ c = a->ind;
+ if(bigc(c))
+ urk("bigc op1b 2");
+ if(regdelay == Rmp)
+ delay();
+ IRR(op, c,Rmp, reg);
+ break;
+ case AIMM:
+ if(op == Olea) {
+ if(a->imm != 0) {
+ ldc(a->imm, reg);
+ IRR(Osw, O(REG,st),Rreg, reg);
+ } else
+ IRR(Osw, O(REG,st),Rreg, Rzero);
+ IRR(Oaddui, O(REG,st),Rreg, reg);
+ } else
+ ldc(a->imm, reg);
+ return;
+ case AIND|AFP:
+ r = Rfp;
+ goto offset;
+ case AIND|AMP:
+ r = Rmp;
+ offset:
+ if(regdelay == r)
+ delay();
+ c = a->i.s;
+ rx = Ri;
+ if(op == Olea || op == Olw)
+ rx = reg;
+ IRR(Olw, a->i.f,r, rx);
+ if(c != 0 || op != Oaddui) {
+ delay();
+ IRR(op, c,rx, reg);
+ }
+ break;
+ }
+ if(op != Olea && del)
+ delay();
+ regdelay = 0;
+}
+
+void
+op1(Inst *i, int op, int reg, int del)
+{
+ opx(USRC(i->add), &i->s, op, reg, del);
+}
+
+void
+op3(Inst *i, int op, int reg, int del)
+{
+ opx(UDST(i->add), &i->d, op, reg, del);
+}
+
+void
+op2(Inst *i, int op, int reg, int del)
+{
+ switch(i->add & ARM) {
+ case AXNON:
+ op3(i, op, reg, del);
+ return;
+ case AXIMM:
+ if(op == Olea) {
+ if((short)i->reg != 0) {
+ ldc((short)i->reg, reg);
+ IRR(Osw, O(REG,t),Rreg, reg);
+ } else
+ IRR(Osw, O(REG,t),Rreg, Rzero);
+ IRR(Oaddui, O(REG,t),Rreg, reg);
+ } else
+ ldc((short)i->reg, reg);
+ return;
+ case AXINF:
+ IRR(op, i->reg,Rfp, reg);
+ break;
+ case AXINM:
+ IRR(op, i->reg,Rmp, reg);
+ break;
+ }
+ if(op != Olea && del)
+ delay();
+}
+
+ulong
+branch(Inst *i)
+{
+ ulong rel;
+
+ if(base == 0)
+ return 0;
+ rel = patch[(Inst*)i->d.imm - mod->prog];
+ rel += (base - code) - 1;
+ return rel & 0xffff;
+}
+
+static void
+literal(ulong imm, int roff)
+{
+ nlit++;
+
+ ldbigc((ulong)litpool, Ro1);
+ IRR(Osw, roff, Rreg, Ro1);
+
+ if(pass == 0)
+ return;
+
+ *litpool = imm;
+ litpool++;
+}
+
+void
+punt(Inst *i, int m, void (*fn)(void))
+{
+ ulong *cp, pc;
+
+ if(m & SRCOP) {
+ op1(i, Olea, Ro1, 1);
+ IRR(Osw, O(REG,s),Rreg, Ro1);
+ }
+ if(m & DSTOP) {
+ op3(i, Olea, Ro3, 1);
+ IRR(Osw, O(REG,d),Rreg, Ro3);
+ }
+ if(m & WRTPC) {
+ pc = patch[i-mod->prog+1];
+ ldbigc((ulong)(base+pc), Ro1);
+ IRR(Osw, O(REG,PC),Rreg, Ro1);
+ }
+ if(m & DBRAN) {
+ pc = patch[(Inst*)i->d.imm-mod->prog];
+ literal((ulong)(base+pc), O(REG, d));
+ }
+
+ if((i->add&ARM) == AXNON) {
+ if(m & THREOP) {
+ delay();
+ IRR(Olw, O(REG,d),Rreg, Ro2);
+ delay();
+ IRR(Osw, O(REG,m),Rreg, Ro2);
+ }
+ } else {
+ op2(i, Olea, Ro2, 1);
+ IRR(Osw, O(REG,m),Rreg, Ro2);
+ }
+
+ ldc((ulong)fn, Rpic);
+ JR(Ojalr, Rpic);
+ IRR(Osw, O(REG,FP),Rreg, Rfp);
+
+ ldc((ulong)&R, Rreg);
+ IRR(Olw, O(REG,FP),Rreg, Rfp);
+ IRR(Olw, O(REG,MP),Rreg, Rmp);
+ regdelay = Rmp;
+
+ if(m & TCHECK) {
+ IRR(Olw, O(REG,t),Rreg, Ro1);
+ xchg();
+ cp = code;
+ BRRI(Obeq,Ro1,Rzero,0);
+ IRR(Olw, O(REG,xpc),Rreg, Ro2);
+ delay();
+ JR(Ojr, Ro2);
+ delay();
+ *cp |= (code - cp) - 1;
+ regdelay = 0;
+ }
+
+ if(m & NEWPC) {
+ IRR(Olw, O(REG,PC),Rreg, Ro1);
+ if(m & TCHECK)
+ delay();
+ else
+ xchg();
+ JR(Ojr, Ro1);
+ delay();
+ regdelay = 0;
+ }
+}
+
+static void
+comgoto(Inst *i)
+{
+ WORD *t, *e;
+
+ op1(i, Olw, Ro2, 0);
+ op3(i, Olea, Ro3, 0);
+ SRR(Osll, 2, Ro2, Ro2);
+ RRR(Oaddu, Ro2, Ro3, Ro3);
+ IRR(Olw, 0,Ro3, Ro1);
+ delay();
+ JR(Ojr, Ro1);
+ delay();
+
+ if(pass == 0)
+ return;
+
+ t = (WORD*)(mod->origmp+i->d.ind);
+ e = t + t[-1];
+ t[-1] = 0;
+ while(t < e) {
+ t[0] = (ulong)(base + patch[t[0]]);
+ t++;
+ }
+}
+
+static void
+comcase(Inst *i, int w)
+{
+ int l;
+ WORD *t, *e;
+
+ if(w != 0) {
+ op1(i, Olw, Ro1, 0); // v
+ op3(i, Olea, Ro3, 0); // table
+ J(Oj, base+macro[MacCASE]);
+ xchg();
+ }
+
+ t = (WORD*)(mod->origmp+i->d.ind+4);
+ l = t[-1];
+
+ /* have to take care not to relocate the same table twice -
+ * the limbo compiler can duplicate a case instruction
+ * during its folding phase
+ */
+
+ if(pass == 0) {
+ if(l >= 0)
+ t[-1] = -l-1; /* Mark it not done */
+ return;
+ }
+ if(l >= 0) /* Check pass 2 done */
+ return;
+ t[-1] = -l-1; /* Set real count */
+ e = t + t[-1]*3;
+ while(t < e) {
+ t[2] = (ulong)(base + patch[t[2]]);
+ t += 3;
+ }
+ t[0] = (ulong)(base + patch[t[0]]);
+}
+
+static void
+comcasel(Inst *i)
+{
+ int l;
+ WORD *t, *e;
+
+ t = (WORD*)(mod->origmp+i->d.ind+8);
+ l = t[-2];
+ if(pass == 0) {
+ if(l >= 0)
+ t[-2] = -l-1; /* Mark it not done */
+ return;
+ }
+ if(l >= 0) /* Check pass 2 done */
+ return;
+ t[-2] = -l-1; /* Set real count */
+ e = t + t[-2]*6;
+ while(t < e) {
+ t[4] = (ulong)base + patch[t[4]];
+ t += 6;
+ }
+ t[0] = (ulong)base + patch[t[0]];
+}
+
+static void
+commframe(Inst *i)
+{
+ Modlink *ml;
+ ulong *cp1, *cp2;
+
+ op1(i, Olw, Ro1, 0);
+ ldc((ulong)H, Ri);
+ cp1 = code;
+ BRRI(Obeq, Ro1,Ri, 0);
+ delay();
+
+ ml = nil;
+ IRR(Olw, (ulong)&ml->links[i->reg].frame,Ro1, Ri);
+ delay();
+ IRR(Olw, O(Type,initialize),Ri, Ro2);
+ delay();
+ cp2 = code;
+ BRRI(Obne, Ro2,Rzero, 0);
+ delay();
+
+ op3(i, Olea, Rj, 0);
+
+ *cp1 |= (code - cp1) - 1;
+ ldbigc((ulong)(base+patch[i-mod->prog+1]), Rlink);
+ J(Oj, base+macro[MacMFRA]);
+ xchg();
+
+ *cp2 |= (code - cp2) - 1;
+ J(Ojal, base+macro[MacFRAM]);
+ delay();
+ op3(i, Osw, Ro1, 0);
+}
+
+static void
+commcall(Inst *i)
+{
+ Modlink *ml;
+
+ op1(i, Olw, Ro1, 0); // f in Ro1
+ IRR(Olw, O(REG,M),Rreg, Ro3);
+ IRR(Osw, O(Frame,fp),Ro1, Rfp); // f->fp = R.FP
+ IRR(Osw, O(Frame,mr),Ro1, Ro3); // f->mr = R.M
+ op3(i, Olw, Ri, 1);
+ ml = nil;
+ IRR(Olw, (ulong)&ml->links[i->reg].u.pc,Ri, Rj);// ml->entry in Rj
+ J(Ojal, base+macro[MacMCAL]);
+ xchg();
+}
+
+static void
+cbral(Inst *i, int op, int mode)
+{
+ ulong *cp;
+
+ cp = 0;
+ op1(i, Olea, Ri, 0);
+ op2(i, Olea, Rj, 0);
+ IRR(Olw, Bhi,Ri, Ro1);
+ IRR(Olw, Bhi,Rj, Ro2);
+ IRR(Olw, Blo,Ri, Ri);
+
+ switch(mode & OMASK) {
+ case ANDAND:
+ cp = code;
+ BRRI(Obne, Ro2,Ro1, 0);
+ goto b1;
+
+ case OROR:
+ BRRI(Obne, Ro2,Ro1, branch(i));
+ b1:
+ IRR(Olw, Blo,Rj, Rj);
+ delay();
+ BRRI(op, Rj,Ri, branch(i));
+ break;
+
+ case EQAND:
+ if(mode & REV1)
+ RRR(Oslt, Ro2,Ro1, Ro3);
+ else
+ RRR(Oslt, Ro1,Ro2, Ro3);
+ BRI(Obne, Ro3, branch(i));
+ IRR(Olw, Blo,Rj, Rj);
+ cp = code;
+ BRRI(Obne, Ro2,Ro1, 0);
+ if(mode & REV2)
+ RRR(Osltu, Rj,Ri, Ro3);
+ else
+ RRR(Osltu, Ri,Rj, Ro3);
+ BRI(op, Ro3, branch(i));
+ break;
+ }
+ delay();
+ if(cp)
+ *cp |= (code - cp) - 1;
+}
+
+static void
+op12(Inst *i, int b1flag, int b2flag)
+{
+ int o1, o2;
+
+ o1 = Olw;
+ if(b1flag)
+ o1 = Olbu;
+ o2 = Olw;
+ if(b2flag)
+ o2 = Olbu;
+ if((i->add & ARM) == AXIMM) {
+ op1(i, o1, Ro1, 0);
+ op2(i, o2, Ro2, 1);
+ } else {
+ op2(i, o2, Ro2, 0);
+ op1(i, o1, Ro1, 1);
+ }
+}
+
+static void
+op13(Inst *i, int o1, int o2)
+{
+ op1(i, o1, Ro1, 1);
+ op3(i, o2, Ro1, 0);
+}
+
+static void
+shrl(Inst *i)
+{
+ int c;
+
+ if(USRC(i->add) != AIMM) {
+ punt(i, SRCOP|DSTOP|THREOP, optab[i->op]);
+ return;
+ }
+ c = i->s.imm;
+ op2(i, Olea, Ro3, 1);
+ IRR(Olw, Bhi,Ro3, Ro1);
+ if(c >= 32) {
+ if((i->add&ARM) != AXNON)
+ op3(i, Olea, Ro3, 0);
+ else
+ delay();
+ SRR(Osra, 31, Ro1, Ro2);
+ IRR(Osw, Bhi,Ro3, Ro2);
+ if(c >= 64) {
+ IRR(Osw, Blo,Ro3, Ro2);
+ return;
+ }
+ if(c > 32)
+ SRR(Osra, c-32, Ro1, Ro1);
+ IRR(Osw, Blo,Ro3, Ro1);
+ return;
+ }
+ IRR(Olw, Blo,Ro3, Ro2);
+ if((i->add&ARM) != AXNON)
+ op3(i, Olea, Ro3, !c);
+ if(c != 0) {
+ SRR(Osll, 32-c, Ro1, Ri);
+ SRR(Osra, c, Ro1, Ro1);
+ SRR(Osrl, c, Ro2, Ro2);
+ RRR(Oor, Ri, Ro2, Ro2);
+ }
+ IRR(Osw, Blo,Ro3, Ro2);
+ IRR(Osw, Bhi,Ro3, Ro1);
+}
+
+static void
+shll(Inst *i)
+{
+ int c;
+
+ if(USRC(i->add) != AIMM) {
+ punt(i, SRCOP|DSTOP|THREOP, optab[i->op]);
+ return;
+ }
+ c = i->s.imm;
+ if(c >= 64) {
+ op3(i, Olea, Ro3, 1);
+ IRR(Osw, Bhi,Ro3, Rzero);
+ IRR(Osw, Blo,Ro3, Rzero);
+ return;
+ }
+ op2(i, Olea, Ro3, 1);
+ if(c >= 32) {
+ IRR(Olw, Blo,Ro3, Ro1);
+ if((i->add&ARM) != AXNON)
+ op3(i, Olea, Ro3, 1);
+ IRR(Osw, Blo,Ro3, Rzero);
+ if(c > 32)
+ SRR(Osll, c-32, Ro1, Ro1);
+ IRR(Osw, Bhi,Ro3, Ro1);
+ return;
+ }
+ IRR(Olw, Blo,Ro3, Ro2);
+ IRR(Olw, Bhi,Ro3, Ro1);
+ if((i->add&ARM) != AXNON)
+ op3(i, Olea, Ro3, !c);
+ if(c != 0) {
+ SRR(Osrl, 32-c, Ro2, Ri);
+ SRR(Osll, c, Ro2, Ro2);
+ SRR(Osll, c, Ro1, Ro1);
+ RRR(Oor, Ri, Ro1, Ro1);
+ }
+ IRR(Osw, Blo,Ro3, Ro2);
+ IRR(Osw, Bhi,Ro3, Ro1);
+}
+
+static void
+compdbg(void)
+{
+ print("%s:%d@%.8ux\n", R.M->m->name, R.t, R.st);
+}
+
+static void
+comp(Inst *i)
+{
+ int o, q, b;
+ ulong *cp, *cp1;
+ char buf[64];
+
+ if(0) {
+ Inst xx;
+ xx.add = AXIMM|SRC(AIMM);
+ xx.s.imm = (ulong)code;
+ xx.reg = i-mod->prog;
+ punt(&xx, SRCOP, compdbg);
+ }
+
+ switch(i->op) {
+ default:
+ snprint(buf, sizeof buf, "%s compile, no '%D'", mod->name, i);
+ error(buf);
+ break;
+ case IMCALL:
+ if((i->add&ARM) == AXIMM)
+ commcall(i);
+ else
+ punt(i, SRCOP|DSTOP|THREOP|WRTPC|NEWPC, optab[i->op]);
+ break;
+ case ISEND:
+ case IRECV:
+ case IALT:
+ punt(i, SRCOP|DSTOP|TCHECK|WRTPC, optab[i->op]);
+ break;
+ case ISPAWN:
+ punt(i, SRCOP|DBRAN, optab[i->op]);
+ break;
+ case IBNEC:
+ case IBEQC:
+ case IBLTC:
+ case IBLEC:
+ case IBGTC:
+ case IBGEC:
+ punt(i, SRCOP|DBRAN|NEWPC|WRTPC, optab[i->op]);
+ break;
+ case ICASEC:
+ comcase(i, 0);
+ punt(i, SRCOP|DSTOP|NEWPC, optab[i->op]);
+ break;
+ case ICASEL:
+ comcasel(i);
+ punt(i, SRCOP|DSTOP|NEWPC, optab[i->op]);
+ break;
+ case IADDC:
+ case IMULL:
+ case IDIVL:
+ case IMODL:
+ case ILSRL:
+ case IMNEWZ:
+ punt(i, SRCOP|DSTOP|THREOP, optab[i->op]);
+ break;
+ case IMFRAME:
+ if((i->add&ARM) == AXIMM)
+ commframe(i);
+ else
+ punt(i, SRCOP|DSTOP|THREOP, optab[i->op]);
+ break;
+ case ILOAD:
+ case INEWA:
+ case INEWAZ:
+ case INEW:
+ case INEWZ:
+ case ISLICEA:
+ case ISLICELA:
+ case ICONSB:
+ case ICONSW:
+ case ICONSL:
+ case ICONSF:
+ case ICONSM:
+ case ICONSMP:
+ case ICONSP:
+ case IMOVMP:
+ case IHEADL:
+ case IHEADMP:
+ case IINDC:
+ case ILENC:
+ case IINSC:
+ case ICVTAC:
+ case ICVTCW:
+ case ICVTWC:
+ case ICVTCL:
+ case ICVTLC:
+ case ICVTFC:
+ case ICVTCF:
+ case ICVTFL:
+ case ICVTLF:
+ case ICVTFR:
+ case ICVTRF:
+ case IMSPAWN:
+ case ICVTCA:
+ case ISLICEC:
+ case INBALT:
+ punt(i, SRCOP|DSTOP, optab[i->op]);
+ break;
+ case INEWCM:
+ case INEWCMP:
+ punt(i, SRCOP|DSTOP|THREOP, optab[i->op]);
+ break;
+ case INEWCB:
+ case INEWCW:
+ case INEWCF:
+ case INEWCP:
+ case INEWCL:
+ punt(i, DSTOP|THREOP, optab[i->op]);
+ break;
+ case IEXIT:
+ punt(i, 0, optab[i->op]);
+ break;
+ case ICVTWB:
+ op13(i, Olw, Osb);
+ break;
+ case ICVTBW:
+ op13(i, Olbu, Osw);
+ break;
+ case ICVTWS:
+ op13(i, Olw, Osb);
+ break;
+ case ICVTSW:
+ op13(i, Olhu, Osw);
+ break;
+ case IMOVB:
+ op13(i, Olbu, Osb);
+ break;
+ case IMOVW:
+ if(USRC(i->add) == AIMM && i->s.imm == 0) {
+ op3(i, Osw, Rzero, 0);
+ break;
+ }
+ op13(i, Olw, Osw);
+ break;
+ case ICVTLW:
+ op1(i, Olea, Ro1, 1);
+ IRR(Olw, Blo,Ro1, Ro1);
+ delay();
+ op3(i, Osw, Ro1, 0);
+ break;
+ case ICVTWL:
+ op1(i, Olw, Ro1, 0);
+ op3(i, Olea, Ro2, 0);
+ SRR(Osra, 31, Ro1, Ro3);
+ IRR(Osw, Blo,Ro2, Ro1);
+ IRR(Osw, Bhi,Ro2, Ro3);
+ break;
+ case IHEADM:
+ op1(i, Olw, Ro1, 1);
+ IRR(Oaddui, OA(List,data),Ro1, Ro1);
+ goto m1;
+ case IMOVM:
+ op1(i, Olea, Ro1, 0);
+ m1:
+ op2(i, Olw, Ro2, 0);
+ op3(i, Olea, Ro3, 0);
+ J(Ojal, base+macro[MacMOVM]);
+ xchg();
+ break;
+ case IRET:
+ J(Oj, base+macro[MacRET]);
+ delay();
+ break;
+ case IFRAME:
+ if(UXSRC(i->add) != SRC(AIMM)) {
+ punt(i, SRCOP|DSTOP, optab[i->op]);
+ break;
+ }
+ ldc((ulong)mod->type[i->s.imm], Ri);
+ J(Ojal, base+macro[MacFRAM]);
+ xchg();
+ op3(i, Osw, Ro1, 0);
+ tinit[i->s.imm] = 1;
+ break;
+ case ILEA:
+ op13(i, Olea, Osw);
+ break;
+ case IHEADW:
+ op1(i, Olw, Ro1, 1);
+ IRR(Olw, OA(List,data),Ro1, Ro1);
+ delay();
+ op3(i, Osw, Ro1, 0);
+ break;
+ case IHEADF:
+ op1(i, Olw, Ro1, 1);
+ IRR(Olw, OA(List,data),Ro1, Ro2);
+ IRR(Olw, OA(List,data)+4,Ro1, Ro3);
+ op3(i, Olea, Ro1, 1);
+ IRR(Osw, 0,Ro1, Ro2);
+ IRR(Osw, 4,Ro1, Ro3);
+ break;
+ case IHEADB:
+ op1(i, Olw, Ro1, 1);
+ IRR(Olbu , OA(List,data),Ro1, Ro1);
+ delay();
+ op3(i, Osb, Ro1, 0);
+ break;
+ case ITAIL:
+ op1(i, Olw, Ro1, 1);
+ IRR(Olw, O(List,tail),Ro1, Ro1);
+ goto movp;
+ case IMOVP:
+ op1(i, Olw, Ro1, 0);
+ goto movp;
+ case IHEADP:
+ op1(i, Olw, Ro1, 1);
+ IRR(Olw, OA(List,data),Ro1, Ro1);
+ movp:
+ ldc((ulong)H, Ro2);
+ cp = code;
+ BRRI(Obeq,Ro1,Ro2,0);
+ ldbigc((ulong)&mutator, Ri);
+ J(Ojal, base+macro[MacCOLR]);
+ xchg();
+ *cp |= (code - cp) - 1;
+ op3(i, Olea, Ro3, 1);
+ IRR(Olw, 0,Ro3, Ri);
+ J(Ojal, base+macro[MacFRP]);
+ IRR(Osw, 0,Ro3, Ro1);
+ break;
+ case ILENA:
+ op1(i, Olw, Ri, 0);
+ J(Ojal, base+macro[MacLENA]);
+ xchg();
+ op3(i, Osw, Ro1, 0);
+ break;
+ case ILENL:
+ op1(i, Olw, Ro1, 0);
+ ldc((ulong)H, Ro2);
+ cp = code;
+ BRRI(Obeq, Ro1,Ro2, 0);
+ ldc(0, Ro3);
+
+ cp1 = code;
+ IRR(Olw, O(List,tail),Ro1, Ro1);
+ IRR(Oaddui, 1,Ro3, Ro3);
+ BRRI(Obne, Ro1,Ro2, (cp1-code)-1);
+ delay();
+
+ *cp |= (code - cp) - 1;
+ op3(i, Osw, Ro3, 0);
+ break;
+ case IMOVL:
+ case IMOVF:
+ op1(i, Olea, Ro1, 1);
+ IRR(Olw, 0,Ro1, Ro2);
+ IRR(Olw, 4,Ro1, Ro3);
+ op3(i, Olea, Ro1, 1);
+ IRR(Osw, 0,Ro1, Ro2);
+ IRR(Osw, 4,Ro1, Ro3);
+ break;
+ case ICVTFW:
+ op1(i, Olea, Ro1, 1);
+ IRR(Olf, Bhi,Ro1, Rf2+1);
+ IRR(Olf, Blo,Ro1, Rf2);
+ delay();
+ FRRR(Ocvtfw, 0, Rf2, Rf2);
+ op3(i, Olea, Ro2, 1);
+ IRR(Osf, 0,Ro2, Rf2);
+ break;
+ case ICVTWF:
+ op1(i, Olea, Ro1, 1);
+ IRR(Olf, 0,Ro1, Rf2);
+ delay();
+ FRRR(Ocvtwf, 0, Rf2, Rf2);
+ op3(i, Olea, Ro2, 1);
+ IRR(Osf, Bhi,Ro2, Rf2+1);
+ IRR(Osf, Blo,Ro2, Rf2);
+ break;
+ case INEGF:
+ op1(i, Olea, Ro1, 1);
+ IRR(Olf, Bhi,Ro1, Rf1+1);
+ IRR(Olf, Blo,Ro1, Rf1);
+ op3(i, Olea, Ro2, 1);
+ FRRR(Onegf, 0, Rf1,Rf2);
+ IRR(Osf, Bhi,Ro2, Rf2+1);
+ IRR(Osf, Blo,Ro2, Rf2);
+ break;
+ case IXORL:
+ case IORL:
+ case IANDL:
+ case IADDL:
+ case ISUBL:
+ op1(i, Olea, Ro1, 0);
+ op2(i, Olea, Ro3, 0);
+
+ IRR(Olw, Blo,Ro1, Rj); /* ls */
+ IRR(Olw, Blo,Ro3, Ro2);
+ IRR(Olw, Bhi,Ro1, Ri); /* ms */
+ IRR(Olw, Bhi,Ro3, Ro1);
+
+ switch(i->op) {
+ case IXORL:
+ o = Oxor;
+ goto l1;
+ case IORL:
+ o = Oor;
+ goto l1;
+ case IANDL:
+ o = Oand;
+ l1:
+ RRR(o, Ri,Ro1, Ro1);
+ RRR(o, Rj,Ro2, Ro2);
+ break;
+ case IADDL:
+ RRR(Oaddu, Ri,Ro1, Ro1);
+ RRR(Oaddu, Rj,Ro2, Ro2);
+ RRR(Osltu, Rj,Ro2, Ri);
+ RRR(Oaddu, Ri,Ro1, Ro1);
+ break;
+ case ISUBL:
+ RRR(Osubu, Ri,Ro1, Ro1);
+ RRR(Osltu, Rj,Ro2, Ri);
+ RRR(Osubu, Rj,Ro2, Ro2);
+ RRR(Osubu, Ri,Ro1, Ro1);
+ break;
+ }
+ if((i->add&ARM) != AXNON)
+ op3(i, Olea, Ro3, 1);
+ IRR(Osw, Bhi,Ro3, Ro1);
+ IRR(Osw, Blo,Ro3, Ro2);
+ break;
+ case ISHLL:
+ shll(i);
+ break;
+ case ISHRL:
+ shrl(i);
+ break;
+ case IADDF:
+ case ISUBF:
+ case IMULF:
+ case IDIVF:
+ case IBEQF:
+ case IBGEF:
+ case IBGTF:
+ case IBLEF:
+ case IBLTF:
+ case IBNEF:
+ op1(i, Olea, Ro1, 0);
+ op2(i, Olea, Ro2, 0);
+ IRR(Olf, Bhi,Ro1, Rf1+1);
+ IRR(Olf, Blo,Ro1, Rf1);
+ IRR(Olf, Bhi,Ro2, Rf2+1);
+ IRR(Olf, Blo,Ro2, Rf2);
+ switch(i->op) {
+ case IADDF: o = Oaddf; goto f1;
+ case ISUBF: o = Osubf; goto f1;
+ case IMULF: o = Omulf; goto f1;
+ case IDIVF: o = Odivf; goto f1;
+ case IBEQF: o = Ofeq; q = Obrt; goto f2;
+ case IBGEF: o = Oflt; q = Obrf; goto f3;
+ case IBGTF: o = Oflt; q = Obrt; goto f2;
+ case IBLEF: o = Oflt; q = Obrf; goto f2;
+ case IBLTF: o = Oflt; q = Obrt; goto f3;
+ case IBNEF: o = Ofeq; q = Obrf; goto f2;
+ f1:
+ op3(i, Olea, Ro1, 0);
+ FRRR(o, Rf1,Rf2, Rf2);
+ IRR(Osf, Bhi,Ro1, Rf2+1);
+ IRR(Osf, Blo,Ro1, Rf2);
+ break;
+ f2:
+ delay();
+ FRRR(o, Rf1,Rf2, 0);
+ goto f4;
+ f3:
+ delay();
+ FRRR(o, Rf2,Rf1, 0);
+ goto f4;
+ f4:
+ delay();
+ FI(q, branch(i));
+ delay();
+ break;
+ }
+ break;
+
+ case IBLTB:
+ case IBLEB:
+ case IBGTB:
+ case IBGEB:
+ case IBEQB:
+ case IBNEB:
+ b = 1;
+ goto s1;
+ case IBLTW:
+ case IBLEW:
+ case IBGTW:
+ case IBGEW:
+ case IBEQW:
+ case IBNEW:
+ b = 0;
+ s1:
+ op12(i, b, b);
+ switch(i->op) {
+ case IBLTB:
+ case IBLTW: o = Obne; goto b1;
+ case IBGEB:
+ case IBGEW: o = Obeq; goto b1;
+ case IBGTB:
+ case IBGTW: o = Obne; goto b2;
+ case IBLEB:
+ case IBLEW: o = Obeq; goto b2;
+ case IBEQB:
+ case IBEQW: o = Obeq; goto b3;
+ case IBNEB:
+ case IBNEW: o = Obne; goto b3;
+ b1: RRR(Oslt, Ro2,Ro1, Ro3);
+ BRI(o,Ro3, branch(i));
+ break;
+ b2: RRR(Oslt, Ro1,Ro2, Ro3);
+ BRI(o,Ro3, branch(i));
+ break;
+ b3: BRRI(o, Ro2,Ro1, branch(i));
+ break;
+ }
+ delay();
+ break;
+
+ case IBEQL:
+ cbral(i, Obeq, ANDAND);
+ break;
+ case IBNEL:
+ cbral(i, Obne, OROR);
+ break;
+ case IBLEL:
+ cbral(i, Obeq, EQAND|REV1);
+ break;
+ case IBGTL:
+ cbral(i, Obne, EQAND);
+ break;
+ case IBLTL:
+ cbral(i, Obne, EQAND|REV1|REV2);
+ break;
+ case IBGEL:
+ cbral(i, Obeq, EQAND|REV2);
+ break;
+
+ case ISUBB:
+ case IADDB:
+ case IANDB:
+ case IORB:
+ case IXORB:
+ case IMODB:
+ case IDIVB:
+ case IMULB:
+ b = 1;
+ op12(i, b, b);
+ goto s2;
+ case ISHLB:
+ case ISHRB:
+ b = 1;
+ op12(i, 0, b);
+ goto s2;
+ case ISUBW:
+ case IADDW:
+ case IANDW:
+ case IORW:
+ case IXORW:
+ case ISHLW:
+ case ISHRW:
+ case IMODW:
+ case IDIVW:
+ case IMULW:
+ b = 0;
+ op12(i, b, b);
+ s2:
+ switch(i->op) {
+ case IADDB:
+ case IADDW: o = Oaddu; goto c1;
+ case ISUBB:
+ case ISUBW: o = Osubu; goto c1;
+ case IANDB:
+ case IANDW: o = Oand; goto c1;
+ case IORB:
+ case IORW: o = Oor; goto c1;
+ case IXORB:
+ case IXORW: o = Oxor; goto c1;
+ c1:
+ RRR(o, Ro1,Ro2, Ro3);
+ break;
+ case ISHLB:
+ case ISHLW: o = Osllv; goto c2;
+ case ILSRW: o = Osrlv; goto c2;
+ case ISHRB:
+ case ISHRW: o = Osrav; goto c2;
+ c2:
+ RRR(o, Ro2,Ro1, Ro3);
+ break;
+ case IMULB:
+ case IMULW: q = Omul; o = Omflo; goto c3;
+ case IDIVB:
+ case IDIVW: q = Odiv; o = Omflo; goto c3;
+ case IMODB:
+ case IMODW: q = Odiv; o = Omfhi; goto c3;
+ c3:
+ RRR(q, Ro1,Ro2, Rzero);
+ RRR(o, Rzero,Rzero, Ro3);
+ break;
+ }
+ op3(i, b? Osb: Osw, Ro3, 0);
+ break;
+ case ICALL:
+ op1(i, Olw, Ro1, 0);
+ ldbigc((ulong)(base+patch[i-mod->prog+1]), Ro2);
+ IRR(Osw, O(Frame,lr),Ro1, Ro2);
+ IRR(Osw, O(Frame,fp),Ro1, Rfp);
+ J(Oj, base+patch[(Inst*)i->d.imm - mod->prog]);
+ RRR(Oaddu, Ro1,Rzero, Rfp);
+ break;
+ case IJMP:
+ J(Oj, base+patch[(Inst*)i->d.imm - mod->prog]);
+ delay();
+ break;
+ case IGOTO:
+ comgoto(i);
+ break;
+ case IINDX:
+ op1(i, Olw, Ro1, 0); /* Ro1 = a */
+ op3(i, Olw, Ro3, 0); /* Ro2 = i */
+ J(Ojal, base+macro[MacINDX]);
+ xchg();
+ op2(i, Osw, Ro2, 0);
+ break;
+ case IINDB:
+ case IINDF:
+ case IINDW:
+ case IINDL:
+ op1(i, Olw, Ro1, 0); /* Ro1 = a */
+ op3(i, Olw, Ro3, 0); /* Ro3 = i */
+ IRR(Olw, O(Array,data),Ro1, Ro1); /* Ro1 = a->data */
+ switch(i->op) {
+ case IINDL:
+ case IINDF:
+ SRR(Osll, 3, Ro3, Ro3); /* Ro3 = i*8 */
+ break;
+ case IINDW:
+ SRR(Osll, 2, Ro3, Ro3); /* Ro3 = i*4 */
+ break;
+ case IINDB:
+ delay();
+ break;
+ }
+ RRR(Oaddu, Ro1,Ro3, Ro2); /* Ro2 = i*size + data */
+ op2(i, Osw, Ro2, 0);
+ break;
+ case ICASE:
+ comcase(i, 1);
+ break;
+ case IRAISE:
+ punt(i, SRCOP|WRTPC|NEWPC, optab[i->op]);
+ break;
+ case IMULX:
+ case IDIVX:
+ case ICVTXX:
+ case IMULX0:
+ case IDIVX0:
+ case ICVTXX0:
+ case IMULX1:
+ case IDIVX1:
+ case ICVTXX1:
+ case ICVTFX:
+ case ICVTXF:
+ case IEXPW:
+ case IEXPL:
+ case IEXPF:
+ punt(i, SRCOP|DSTOP|THREOP, optab[i->op]);
+ break;
+ case ISELF:
+ punt(i, DSTOP, optab[i->op]);
+ break;
+ }
+}
+
+static void
+preamble(void)
+{
+ ldc((ulong)&R, Rreg);
+ IRR(Olw, O(REG,PC),Rreg, Ri);
+ IRR(Olw, O(REG,FP),Rreg, Rfp);
+ IRR(Olw, O(REG,MP),Rreg, Rmp);
+ IRR(Osw, O(REG,xpc),Rreg, Rlink);
+ JR(Ojr, Ri);
+ delay();
+}
+
+static void
+macfrp(void)
+{
+ ulong *cp1, *cp2;
+
+ ldc((ulong)H, Ro1);
+ cp1 = code;
+ BRRI(Obeq, Ri,Ro1, 0); // arg == $H
+ delay();
+
+ IRR(Olw, O(Heap,ref)-sizeof(Heap),Ri, Ro2);
+ ldc((ulong)1, Ro1);
+ cp2 = code;
+ BRRI(Obeq, Ro1,Ro2, 0); // ref(arg) == $1
+ IRR(Oaddui, -1,Ro2, Ro2); // ref(arg)--
+ JR(Ojr, Rlink);
+ IRR(Osw, O(Heap,ref)-sizeof(Heap),Ri, Ro2);
+
+ *cp2 |= (code - cp2) - 1;
+ IRR(Osw, O(REG,st),Rreg, Rlink);
+ IRR(Osw, O(REG,FP),Rreg, Rfp);
+
+ ldc((ulong)rdestroy, Rpic);
+ JR(Ojalr, Rpic); // CALL destroy
+ IRR(Osw, O(REG,s),Rreg, Ri);
+
+ ldc((ulong)&R, Rreg);
+ IRR(Olw, O(REG,st),Rreg, Rlink);
+ IRR(Olw, O(REG,FP),Rreg, Rfp);
+ IRR(Olw, O(REG,MP),Rreg, Rmp);
+
+ *cp1 |= (code - cp1) - 1;
+ JR(Ojr, Rlink);
+ delay();
+}
+
+static void
+macret(void)
+{
+ ulong *cp1, *cp2, *cp3, *cp4, *cp5, *cp6;
+ Inst i;
+
+// NOTE this needs to be scheduled
+
+ IRR(Olw, O(Frame,t),Rfp, Ro1);
+ delay();
+ cp1 = code;
+ BRRI(Obeq, Ro1,Rzero, 0); // t(Rfp) == 0
+ delay();
+
+ IRR(Olw, O(Type,destroy),Ro1, Rpic);
+ delay();
+ cp2 = code;
+ BRRI(Obeq, Rpic,Rzero, 0); // destroy(t(fp)) == 0
+ delay();
+
+ IRR(Olw, O(Frame,fp),Rfp, Ro2);
+ delay();
+ cp3 = code;
+ BRRI(Obeq, Ro2,Rzero, 0); // fp(Rfp) == 0
+ delay();
+
+ IRR(Olw, O(Frame,mr),Rfp, Ro3);
+ delay();
+ cp4 = code;
+ BRRI(Obeq, Ro3,Rzero, 0); // mr(Rfp) == 0
+ delay();
+
+ IRR(Olw, O(REG,M),Rreg, Ro2);
+ delay();
+ IRR(Olw, O(Heap,ref)-sizeof(Heap),Ro2, Ro3);
+ delay();
+ IRR(Oaddui, -1,Ro3, Ro3);
+ cp5 = code;
+ BRRI(Obeq, Ro3,Rzero, 0); // --ref(arg) == 0
+ delay();
+ IRR(Osw, O(Heap,ref)-sizeof(Heap),Ro2, Ro3);
+
+ IRR(Olw, O(Frame,mr),Rfp, Ro1);
+ delay();
+ IRR(Osw, O(REG,M),Rreg, Ro1);
+ IRR(Olw, O(Modlink,compiled),Ro1, Ro2); // check for uncompiled module
+ IRR(Olw, O(Modlink,MP),Ro1, Rmp);
+ cp6 = code;
+ BRRI(Obeq, Ro2,Rzero, 0);
+ IRR(Osw, O(REG,MP),Rreg, Rmp);
+
+ *cp4 |= (code - cp4) - 1;
+ JR(Ojalr, Rpic); // call destroy(t(fp))
+ delay();
+ IRR(Osw, O(REG,SP),Rreg, Rfp);
+ IRR(Olw, O(Frame,lr),Rfp, Ro1);
+ IRR(Olw, O(Frame,fp),Rfp, Rfp);
+ IRR(Osw, O(REG,FP),Rreg, Rfp);
+ JR(Ojr, Ro1); // goto lr(Rfp)
+ delay();
+
+ *cp6 |= (code - cp6) - 1; // returning to uncompiled module
+ JR(Ojalr, Rpic); // call destroy(t(fp))
+ delay();
+ IRR(Osw, O(REG,SP),Rreg, Rfp);
+ IRR(Olw, O(Frame,lr),Rfp, Ro1);
+ IRR(Olw, O(Frame,fp),Rfp, Rfp);
+ IRR(Osw, O(REG,FP),Rreg, Rfp);
+ IRR(Olw, O(REG,xpc),Rreg, Ro2);
+ JR(Ojr, Ro2); // return to uncompiled code
+ IRR(Osw, O(REG,PC),Rreg, Ro1);
+
+ *cp1 |= (code - cp1) - 1;
+ *cp2 |= (code - cp2) - 1;
+ *cp3 |= (code - cp3) - 1;
+ *cp5 |= (code - cp5) - 1;
+ i.add = AXNON;
+ punt(&i, TCHECK|NEWPC, optab[IRET]);
+}
+
+static void
+macindx(void)
+{
+
+ IRR(Olw, O(Array,t),Ro1, Ro2);
+ IRR(Olw, O(Array,data),Ro1, Ro1); // Ro1 = data
+ IRR(Olw, O(Type,size),Ro2, Ro2); // Ro2 = size
+ delay();
+
+ RRR(Omul, Ro3,Ro2,Rzero); // Ro2 = i*size
+ RRR(Omflo, Rzero,Rzero,Ro2);
+ JR(Ojr, Rlink);
+ RRR(Oaddu, Ro1,Ro2,Ro2); // Ro2 = i*size + data
+}
+
+static void
+maccase(void)
+{
+ ulong *cp1, *cp2, *cp3;
+
+/*
+ * Ro1 = value (input arg), t
+ * Ro2 = count, n
+ * Ro3 = table pointer (input arg)
+ * Ri = n/2, n2
+ * Rj = pivot element t+n/2*3, l
+ */
+
+ IRR(Olw, 0,Ro3, Ro2); // count
+ IRR(Oaddui, 0,Ro3, Rlink); // initial table pointer
+
+ cp1 = code; // loop:
+ BRI(Oblez,Ro2, 0); // n <= 0? goto out
+ SRR(Osra, 1, Ro2, Ri); // n2 = n>>1
+ SRR(Osll, 1, Ri, Rj);
+ RRR(Oaddu, Rj, Ri, Rj);
+ SRR(Osll, 2, Rj, Rj);
+ RRR(Oaddu, Ro3, Rj, Rj); // l = t + n2*3;
+ IRR(Olw, 4,Rj, Rpic);
+ delay();
+ RRR(Oslt, Rpic, Ro1, Rpic);
+ cp2 = code;
+ BRI(Obne, Rpic, 0); // v < l[1]? goto low
+ delay();
+
+ IRR(Olw, 8,Rj, Rpic);
+ delay();
+ RRR(Oslt, Rpic, Ro1, Rpic);
+ cp3 = code;
+ BRI(Obeq, Rpic, 0); // v >= l[2]? goto high
+ delay();
+
+ IRR(Olw, 12,Rj, Ro3); // found
+ delay();
+ JR(Ojr, Ro3);
+ delay();
+
+ *cp2 |= (code - cp2) - 1; // low:
+ BRRI(Obeq, Rzero,Rzero, (cp1-code)-1);
+ IRR(Oaddui, 0, Ri, Ro2); // n = n2
+
+ *cp3 |= (code - cp3) - 1; // high:
+ IRR(Oaddui, 12, Rj, Ro3); // t = l+3;
+ IRR(Oaddui, 1, Ri, Rpic);
+ BRRI(Obeq, Rzero,Rzero, (cp1-code)-1);
+ RRR(Osubu, Rpic, Ro2, Ro2); // n -= n2 + 1
+
+ *cp1 |= (code - cp1) - 1; // out:
+ IRR(Olw, 0,Rlink, Ro2); // initial n
+ delay();
+ SRR(Osll, 1, Ro2, Ro3);
+ RRR(Oaddu, Ro3, Ro2, Ro2);
+ SRR(Osll, 2, Ro2, Ro2);
+ RRR(Oaddu, Ro2, Rlink, Rlink);
+ IRR(Olw, 4,Rlink, Ro3); // (initital t)[n*3+1]
+ delay();
+ JR(Ojr, Ro3);
+ delay();
+}
+
+static void
+maclena(void)
+{
+ ulong *cp;
+
+ ldc((ulong)H, Ro1);
+ cp = code;
+ BRRI(Obeq, Ri,Ro1, 0);
+ delay();
+ IRR(Olw, O(Array,len),Ri, Ro1);
+ JR(Ojr, Rlink);
+ delay();
+ *cp |= (code - cp) - 1;
+ JR(Ojr, Rlink);
+ ldc(0, Ro1);
+}
+
+static void
+macmcal(void)
+{
+ ulong *cp1, *cp2;
+
+ IRR(Olw, O(Modlink,prog),Ri, Ro2);
+ IRR(Osw, O(Frame,lr),Ro1, Rlink); // f->lr = return
+ cp1 = code;
+ BRRI(Obne, Ro2, Rzero, 0); // CMPL ml->m->prog != 0
+ IRR(Oaddui, 0,Ro1, Rfp); // R.FP = f
+
+ IRR(Osw, O(REG,st),Rreg, Rlink);
+ ldc((ulong)rmcall, Rpic);
+ IRR(Osw, O(REG,FP),Rreg, Ro1);
+ IRR(Osw, O(REG,dt),Rreg, Rj);
+ JR(Ojalr, Rpic); // CALL rmcall
+ xchg();
+ ldc((ulong)&R, Rreg);
+ IRR(Olw, O(REG,st),Rreg, Rlink);
+ IRR(Olw, O(REG,FP),Rreg, Rfp);
+ IRR(Olw, O(REG,MP),Rreg, Rmp);
+ JR(Ojr, Rlink);
+ delay();
+
+ *cp1 |= (code - cp1) - 1;
+ IRR(Olw, O(Heap,ref)-sizeof(Heap),Ri, Ro2);
+ IRR(Osw, O(REG,M),Rreg, Ri);
+ IRR(Oaddui, 1,Ro2, Ro2);
+ IRR(Olw, O(Modlink,MP),Ri, Rmp);
+ IRR(Olw, O(Modlink,compiled),Ri, Ro1);
+ IRR(Osw, O(Heap,ref)-sizeof(Heap),Ri, Ro2);
+ cp2 = code;
+ BRRI(Obeq, Ro1,Rzero, 0);
+ IRR(Osw, O(REG,MP),Rreg, Rmp);
+
+ JR(Ojr, Rj);
+ delay();
+
+ *cp2 |= (code - cp2) - 1;
+ IRR(Osw, O(REG,FP),Rreg, Rfp); // call to uncompiled code
+ IRR(Olw, O(REG,xpc),Rreg, Ro1);
+ JR(Ojr, Ro1);
+ IRR(Osw, O(REG,PC),Rreg, Rj);
+}
+
+static void
+macmfra(void)
+{
+ ldc((ulong)rmfram, Rpic);
+ IRR(Osw, O(REG,st),Rreg, Rlink);
+ IRR(Osw, O(REG,FP),Rreg, Rfp);
+ IRR(Osw, O(REG,s),Rreg, Ri);
+ IRR(Osw, O(REG,d),Rreg, Rj);
+ JR(Ojalr, Rpic); // CALL rmfram
+ xchg();
+ ldc((ulong)&R, Rreg);
+ IRR(Olw, O(REG,st),Rreg, Rlink);
+ IRR(Olw, O(REG,FP),Rreg, Rfp);
+ IRR(Olw, O(REG,MP),Rreg, Rmp);
+ JR(Ojr, Rlink);
+ delay();
+}
+
+static void
+macfram(void)
+{
+ ulong *cp;
+
+ /*
+ * Ri has t
+ */
+ IRR(Olw, O(Type,initialize),Ri, Rj);
+ IRR(Olw, O(Type,size),Ri, Ro3); // MOVL $t->size, Ro3
+ IRR(Olw, O(REG,SP),Rreg, Ro2); // MOVL R.SP, Ro2
+ IRR(Olw, O(REG,TS),Rreg, Ro1); // MOVL R.TS, Ro1
+ RRR(Oaddu,Ro3,Ro2, Ro2); // ADDL $t->size, Ro2
+ RRR(Osltu, Ro1,Ro2, Ro3); // CMP Ro1,Ro2,Ro3
+ cp = code;
+ BRI(Obne,Ro3,0); // BLT Ro3,**
+ delay();
+
+ IRR(Osw, O(REG,s),Rreg, Ri); // MOVL t, R.s
+ IRR(Osw, O(REG,st),Rreg, Rlink); // MOVL Rlink, R.st
+ ldc((ulong)extend, Rpic);
+ JR(Ojalr, Rpic); // CALL extend
+ IRR(Osw, O(REG,FP),Rreg, Rfp); // MOVL RFP, R.FP
+ ldc((ulong)&R, Rreg);
+ IRR(Olw, O(REG,st),Rreg, Rlink); // reload registers
+ IRR(Olw, O(REG,FP),Rreg, Rfp);
+ IRR(Olw, O(REG,MP),Rreg, Rmp);
+ IRR(Olw, O(REG,s),Rreg, Ro1); // return arg
+ JR(Ojr, Rlink);
+ delay();
+
+ *cp |= (code - cp) - 1;
+ IRR(Olw, O(REG,SP),Rreg, Ro1);
+ IRR(Osw, O(REG,SP),Rreg, Ro2);
+ IRR(Osw, O(Frame,mr),Ro1, Rzero);
+ JR(Ojr, Rj); // return from tinit to main program
+ IRR(Osw, O(Frame,t),Ro1, Ri);
+}
+
+static void
+macmovm(void)
+{
+ ulong *cp1, *cp2;
+
+ /*
+ * from = Ro1
+ * to = Ro3
+ * count = Ro2
+ */
+
+ cp1 = code;
+ BRRI(Obeq, Ro2, Rzero, 0);
+ delay();
+
+ cp2 = code;
+ IRR(Olbu, 0,Ro1, Ri);
+ IRR(Oaddui, -1,Ro2, Ro2);
+ IRR(Osb, 0,Ro3, Ri);
+ IRR(Oaddui, 1,Ro1, Ro1);
+ BRRI(Obne, Ro2, Rzero, (cp2-code)-1);
+ IRR(Oaddui, 1,Ro3, Ro3);
+
+ *cp1 |= (code - cp1) - 1;
+ JR(Ojr, Rlink);
+ delay();
+}
+
+static void
+maccolr(void)
+{
+ ulong *cp;
+
+ IRR(Olw, 0,Ri, Ri);
+ IRR(Olw, O(Heap,color)-sizeof(Heap),Ro1, Ro3);
+
+ IRR(Olw, O(Heap,ref)-sizeof(Heap),Ro1, Ro2);
+
+ cp = code;
+ BRRI(Obeq, Ri, Ro3, 0);
+ IRR(Oaddui, 1,Ro2, Ro2);
+
+ ldc(propagator, Ro3);
+ IRR(Osw, O(Heap,color)-sizeof(Heap),Ro1, Ro3);
+ ldc((ulong)&nprop, Ro3);
+ IRR(Osw, 0,Ro3, Ro1);
+
+ *cp |= (code - cp) - 1;
+ JR(Ojr, Rlink);
+ IRR(Osw, O(Heap,ref)-sizeof(Heap),Ro1, Ro2);
+}
+
+static void
+macend(void)
+{
+}
+
+void
+comd(Type *t)
+{
+ int i, j, m, c;
+
+ IRR(Osw, O(REG,dt),Rreg, Rlink);
+ for(i = 0; i < t->np; i++) {
+ c = t->map[i];
+ j = i<<5;
+ for(m = 0x80; m != 0; m >>= 1) {
+ if(c & m) {
+ J(Ojal, base+macro[MacFRP]);
+ IRR(Olw, j,Rfp, Ri);
+ }
+ j += sizeof(WORD*);
+ }
+ }
+ IRR(Olw, O(REG,dt),Rreg, Rlink);
+ delay();
+ JR(Ojr, Rlink);
+ delay();
+}
+
+void
+comi(Type *t)
+{
+ int i, j, m, c;
+
+ ldc((ulong)H, Ri);
+ for(i = 0; i < t->np; i++) {
+ c = t->map[i];
+ j = i<<5;
+ for(m = 0x80; m != 0; m >>= 1) {
+ if(c & m)
+ IRR(Osw, j,Ro1, Ri);
+ j += sizeof(WORD*);
+ }
+ }
+ JR(Ojr, Rlink);
+ xchg();
+}
+
+void
+typecom(Type *t)
+{
+ int n;
+ ulong *tmp, *start;
+
+ if(t == nil || t->initialize != 0)
+ return;
+
+ tmp = mallocz(4096, 0);
+ if(tmp == nil)
+ return;
+ code = tmp;
+ comi(t);
+ n = code - tmp;
+ code = tmp;
+ comd(t);
+ n += code - tmp;
+ free(tmp);
+
+ n *= sizeof(*code);
+ code = mallocz(n, 0);
+ if(code == nil)
+ return;
+
+ start = code;
+ t->initialize = code;
+ comi(t);
+ t->destroy = code;
+ comd(t);
+
+ segflush(start, n);
+
+ if(cflag > 1)
+ print("typ= %.8p %4d i %.8p d %.8p asm=%d\n",
+ t, t->size, t->initialize, t->destroy, n);
+}
+
+static void
+patchex(Module *m, ulong *p)
+{
+ Handler *h;
+ Except *e;
+
+ if((h = m->htab) == nil)
+ return;
+ for( ; h->etab != nil; h++){
+ h->pc1 = p[h->pc1];
+ h->pc2 = p[h->pc2];
+ for(e = h->etab; e->s != nil; e++)
+ e->pc = p[e->pc];
+ if(e->pc != -1)
+ e->pc = p[e->pc];
+ }
+}
+
+int
+compile(Module *m, int size, Modlink *ml)
+{
+ Link *l;
+ Modl *e;
+ int i, n;
+ ulong *s, tmp[512];
+
+ patch = mallocz(size*sizeof(*patch), 0);
+ tinit = malloc(m->ntype*sizeof(*tinit));
+ base = 0;
+
+ if(!comvec) {
+ i = 10; /* length of comvec */
+ code = malloc(i*sizeof(*code));
+ s = code;
+ preamble();
+ if(code >= (ulong*)(s + i))
+ urk("preamble");
+ comvec = (void*)s;
+ segflush(s, i*sizeof(*s));
+ if(cflag > 1) {
+ print("comvec\n");
+ while(s < code)
+ das(s++);
+ }/**/
+ }
+
+ mod = m;
+ n = 0;
+ regdelay = 0;
+ pass = 0;
+ nlit = 0;
+
+ for(i = 0; i < size; i++) {
+ code = tmp;
+ comp(&m->prog[i]);
+ if(code >= &tmp[nelem(tmp)]) {
+ print("%3d %D\n", i, &m->prog[i]);
+ urk("tmp ovflo");
+ }
+ patch[i] = n;
+ n += code - tmp;
+ }
+
+ for(i=0; macinit[i].f; i++) {
+ code = tmp;
+ (*macinit[i].f)();
+ macro[macinit[i].o] = n;
+ n += code - tmp;
+ }
+
+ base = malloc((n+nlit)*sizeof(*base));
+ if(cflag > 1)
+ print("dis=%5d %5d mips=%5d asm=%.8p lit=%d: %s\n",
+ size, size*sizeof(Inst), n, base, nlit, m->name);
+
+ pass++;
+ code = base;
+ litpool = base+n;
+ n = 0;
+ nlit = 0;
+ regdelay = 0;
+
+ for(i = 0; i < size; i++) {
+ s = code;
+ comp(&m->prog[i]);
+ if(patch[i] != n) {
+ print("%3d %D\n", i, &m->prog[i]);
+ urk(exCphase);
+ }
+ n += code - s;
+ if(cflag > 1) {
+ print("%3d %D\n", i, &m->prog[i]);
+ while(s < code)
+ das(s++);
+ }/**/
+ }
+
+ for(i=0; macinit[i].f; i++) {
+ if(macro[macinit[i].o] != n) {
+ print("macinit %d\n", macinit[i].o);
+ urk(exCphase);
+ }
+ s = code;
+ (*macinit[i].f)();
+ n += code - s;
+ if(cflag > 1) {
+ print("macinit %d\n", macinit[i].o);
+ while(s < code)
+ das(s++);
+ }/**/
+ }
+
+ for(l = m->ext; l->name; l++) {
+ l->u.pc = (Inst*)(base+patch[l->u.pc-m->prog]);
+ typecom(l->frame);
+ }
+ if(ml != nil) {
+ e = &ml->links[0];
+ for(i = 0; i < ml->nlinks; i++) {
+ e->u.pc = (Inst*)(base+patch[e->u.pc-m->prog]);
+ typecom(e->frame);
+ e++;
+ }
+ }
+ for(i = 0; i < m->ntype; i++) {
+ if(tinit[i] != 0)
+ typecom(m->type[i]);
+ }
+ patchex(m, patch);
+ m->entry = (Inst*)(base+patch[mod->entry-mod->prog]);
+ free(patch);
+ free(tinit);
+ free(m->prog);
+ m->prog = (Inst*)base;
+ m->compiled = 1;
+ segflush(base, n*sizeof(*base));
+ return 1;
+}
--- /dev/null
+++ b/libinterp/comp-power.c
@@ -1,0 +1,2261 @@
+#include "lib9.h"
+#include "isa.h"
+#include "interp.h"
+#include "raise.h"
+
+/*
+ * Copyright © 1997 C H Forsyth (forsyth@terzarima.net)
+ */
+
+#define ROMABLE 0 /* costs something to zero patch vectors */
+#define RESCHED 1 /* check for interpreter reschedule */
+
+#define PATCH(ptr) *ptr |= ((ulong)code-(ulong)ptr) & 0xfffc
+
+#define T(r) *((void**)(R.r))
+
+#define XO(o,xo) (((o)<<26)|((xo)<<1))
+
+/* botch: ARRR, AIRR, LRRR, etc have dest first (will fix soon) */
+
+#define OPARRR(o,d,a,b) ((o)|((d)<<21)|((a)<<16)|((b)<<11))
+#define ARRR(o,d,a,b) gen((o)|((d)<<21)|((a)<<16)|((b)<<11))
+#define AIRR(o,d,a,v) gen((o)|((d)<<21)|((a)<<16)|((v)&0xFFFF))
+#define IRR(o,v,a,d) AIRR((o),(d),(a),(v))
+#define RRR(o,b,a,d) ARRR((o),(d),(a),(b))
+#define LRRR(o,a,s,b) ARRR((o),(s),(a),(b))
+#define LIRR(o,a,s,v) AIRR((o),(s),(a),(v))
+#define Bx(li,aa) gen((18<<26)|((li)&0x3FFFFFC)|((aa)<<1))
+#define RLW(op,a,s,sh,mb,me) ((op)|(((s)&31L)<<21)|(((a)&31L)<<16)|(((sh)&31L)<<11)|\
+ (((mb)&31L)<<6)|(((me)&31L)<<1))
+#define MFSPR(s, d) gen(XO(31,339) | ((d)<<21) | ((s)<<11))
+#define MTSPR(s, d) gen(XO(31,467) | ((s)<<21) | ((d)<<11));
+
+#define SLWI(d,a,n) gen(slw((d),(a),(n),0))
+#define LRET() gen(Oblr)
+
+#define SETR0() if(macjit){ AIRR(Oaddi, Rzero, 0, 0); } /* set R0 to 0 */
+
+/* assumes H can be formed from signed halfword */
+#define CMPH(r) AIRR(Ocmpi, Rcrf0, (r), (ulong)H);
+#define NOTNIL(r) (CMPH((r)), CCALL(EQ, bounds))
+
+enum
+{
+ Rzero = 0, /* zero by design, not definition (P9/Inferno) */
+
+ Rsp = 1,
+ Rsb = 2,
+ Rarg = 3,
+
+ Ro1 = 8,
+ Ro2 = 9,
+ Ro3 = 10,
+ Ri = 11,
+ Rj = 12,
+
+ Rmp = 13,
+ Rfp = 14,
+ Rreg = 15,
+ Rta = 16, /* unused */
+ Rpic = 17, /* address for computed goto, for move to CTR or LR */
+
+ Rcon = 26, /* constant builder; temporary */
+ /* 27, 28, 29, 30 are potentially external registers (P9/Inferno) */
+ Rlink = 31, /* holds copies of LR; linker temp */
+
+ Rfret = 0,
+ Rf1 = 4,
+ Rf2 = 6,
+ Rfcvi = 27, /* floating conversion constant (P9/Inferno) */
+ Rfzero = 28, /* 0.0 (P9/Inferno) */
+ Rfhalf = 29, /* 0.5 (P9/Inferno) */
+
+ Rlr = 8<<5, /* SPR(LR) */
+ Rctr = 9<<5, /* SPR(CTR) */
+
+ Rcrf0 = 0, /* condition code field 0 */
+ Rcrf1 = 1<<2, /* condition code field 1 */
+
+ Rcrbrel = 31, /* condition code bit set to force relinquish */
+
+ Olwz = XO(32, 0),
+ Olwzu = XO(33, 0),
+ Olwzx = XO(31, 23),
+ Olbz = XO(34, 0),
+ Olbzu = XO(35, 0),
+ Olbzx = XO(31, 87),
+ Olfd = XO(50, 0),
+ Olhz = XO(40, 0),
+ Olhzx = XO(31, 279),
+ Ostw = XO(36, 0),
+ Ostwu = XO(37, 0),
+ Ostwx = XO(31, 151),
+ Ostb = XO(38, 0),
+ Ostbu = XO(39, 0),
+ Ostbx = XO(31, 215),
+ Osth = XO(44,0),
+ Osthx = XO(31, 407),
+ Ostfd = XO(54, 0),
+ Ostfdu = XO(55, 0),
+
+ Oaddc = XO(31,10),
+ Oadde = XO(31, 138),
+ Oaddi = XO(14, 0), /* simm */
+ Oaddic_ = XO(13, 0),
+ Oaddis = XO(15, 0),
+ Ocrxor = XO(19, 193),
+ Ofadd = XO(63, 21),
+ Ofcmpo = XO(63, 32),
+ Ofctiwz = XO(63, 15),
+ Ofsub = XO(63, 20),
+ Ofmr = XO(63, 72),
+ Ofmul = XO(63, 25),
+ Ofdiv = XO(63, 18),
+ Ofneg = XO(63, 40),
+ Oori = XO(24,0), /* uimm */
+ Ooris = XO(25,0), /* uimm */
+ Odivw = XO(31, 491),
+ Odivwu = XO(31, 459),
+ Omulhw = XO(31, 75),
+ Omulhwu = XO(31, 11),
+ Omulli = XO(7, 0),
+ Omullw = XO(31, 235),
+ Osubf = XO(31, 40),
+ Osubfc = XO(31,8),
+ Osubfe = XO(31,136),
+ Osubfic = XO(8, 0),
+ Oadd = XO(31, 266),
+ Oand = XO(31, 28),
+ Oneg = XO(31, 104),
+ Oor = XO(31, 444),
+ Oxor = XO(31, 316),
+
+ Ocmpi = XO(11, 0),
+ Ocmp = XO(31, 0),
+ Ocmpl = XO(31, 32),
+ Ocmpli = XO(10,0),
+
+ Orlwinm = XO(21, 0),
+ Oslw = XO(31, 24),
+ Osraw = XO(31,792),
+ Osrawi = XO(31,824),
+ Osrw = XO(31,536),
+
+ Cnone = OPARRR(0,20,0,0), /* unconditional */
+ Ceq = OPARRR(0,12,2,0),
+ Cle = OPARRR(0,4,1,0),
+ Clt = OPARRR(0,12,0,0),
+ Cdnz = OPARRR(0,16,0,0),
+ Cgt = OPARRR(0,12,1,0),
+ Cne = OPARRR(0,4,2,0),
+ Cge = OPARRR(0,4,0,0),
+ Cle1 = OPARRR(0,4,5,0), /* Cle on CR1 */
+ Crelq = OPARRR(0,12,Rcrbrel,0), /* relinquish */
+ Cnrelq = OPARRR(0,4,Rcrbrel,0), /* not relinquish */
+ Cpredict = OPARRR(0,1,0,0), /* reverse prediction */
+ Lk = 1,
+ Aa = 2,
+
+ Obeq = OPARRR(16<<26,12,2,0),
+ Obge = OPARRR(16<<26,4,0,0),
+ Obgt = OPARRR(16<<26,12,1,0),
+ Oble = OPARRR(16<<26,4,1,0),
+ Oblt = OPARRR(16<<26,12,0,0),
+ Obne = OPARRR(16<<26,4,2,0),
+
+ Ob = XO(18, 0),
+ Obc = XO(16, 0),
+ Obcctr = XO(19,528),
+ Obcctrl = Obcctr | Lk,
+ Obctr = Obcctr | Cnone,
+ Obctrl = Obctr | Lk,
+ Obclr = XO(19, 16),
+ Oblr = Obclr | Cnone,
+ Oblrl = Oblr | Lk,
+
+ Olea = 100, // pseudo op
+
+ SRCOP = (1<<0),
+ DSTOP = (1<<1),
+ WRTPC = (1<<2), /* update R.PC */
+ TCHECK = (1<<3), /* check R.t for continue/ret */
+ NEWPC = (1<<4), /* goto R.PC */
+ DBRAN = (1<<5), /* dest is branch */
+ THREOP = (1<<6),
+
+ Lg2Rune = sizeof(Rune)==4? 2: 1,
+ ANDAND = 1,
+ OROR,
+ EQAND,
+
+ MacRET = 0,
+ MacFRP,
+ MacCASE,
+ MacFRAM,
+ MacCOLR,
+ MacMCAL,
+ MacMFRA,
+ MacCVTFW,
+ MacRELQ,
+ MacEND,
+ NMACRO
+};
+
+ void (*comvec)(void);
+ int macjit;
+extern long das(ulong*);
+static ulong* code;
+static ulong* base;
+static ulong* patch;
+static int pass;
+static Module* mod;
+static ulong* tinit;
+static ulong* litpool;
+static int nlit;
+static ulong macro[NMACRO];
+static void ldbigc(long, int);
+static void rdestroy(void);
+static void macret(void);
+static void macfrp(void);
+static void maccase(void);
+static void maccvtfw(void);
+static void macfram(void);
+static void maccolr(void);
+static void macend(void);
+static void macmcal(void);
+static void macmfra(void);
+static void macrelq(void);
+static void movmem(Inst*);
+
+struct
+{
+ int o;
+ void (*f)(void);
+} macinit[] =
+{
+ MacFRP, macfrp, /* decrement and free pointer */
+ MacRET, macret, /* return instruction */
+ MacCASE, maccase, /* case instruction */
+ MacCOLR, maccolr, /* increment and color pointer */
+ MacFRAM, macfram, /* frame instruction */
+ MacMCAL, macmcal, /* mcall bottom half */
+ MacMFRA, macmfra, /* punt mframe because t->initialize==0 */
+ MacCVTFW, maccvtfw,
+ MacRELQ, macrelq, /* reschedule */
+ MacEND, macend,
+ 0
+};
+
+static void
+rdestroy(void)
+{
+ destroy(R.s);
+}
+
+static void
+rmcall(void)
+{
+ Frame *f;
+ Prog *p;
+
+ if((void*)R.dt == H)
+ error(exModule);
+
+ f = (Frame*)R.FP;
+ if(f == H)
+ error(exModule);
+
+ f->mr = nil;
+ ((void(*)(Frame*))R.dt)(f);
+ R.SP = (uchar*)f;
+ R.FP = f->fp;
+ if(f->t == nil)
+ unextend(f);
+ else
+ freeptrs(f, f->t);
+ p = currun();
+ if(p->kill != nil)
+ error(p->kill);
+}
+
+static void
+rmfram(void)
+{
+ Type *t;
+ Frame *f;
+ uchar *nsp;
+
+ t = (Type*)R.s;
+ if(t == H)
+ error(exModule);
+ nsp = R.SP + t->size;
+ if(nsp >= R.TS) {
+ R.s = t;
+ extend();
+ T(d) = R.s;
+ return;
+ }
+ f = (Frame*)R.SP;
+ R.SP = nsp;
+ f->t = t;
+ f->mr = nil;
+ initmem(t, f);
+ T(d) = f;
+}
+
+void
+urk(char *s)
+{
+ print("compile failed: %s\n", s); // debugging
+ error(exCompile); // production
+}
+
+static void
+gen(ulong o)
+{
+ *code++ = o;
+}
+
+static void
+br(ulong op, ulong disp)
+{
+ *code++ = op | (disp & 0xfffc);
+}
+
+static void
+mfspr(int d, int s)
+{
+ MFSPR(s, d);
+}
+
+static void
+mtspr(int d, int s)
+{
+ MTSPR(s, d);
+}
+
+static ulong
+slw(int d, int s, int v, int rshift)
+{
+ int m0, m1;
+
+ if(v < 0 || v > 32)
+ urk("slw v");
+ if(v < 0)
+ v = 0;
+ else if(v > 32)
+ v = 32;
+ if(rshift) { /* shift right */
+ m0 = v;
+ m1 = 31;
+ v = 32-v;
+ } else {
+ m0 = 0;
+ m1 = 31-v;
+ }
+ return RLW(Orlwinm, d, s, v, m0, m1);
+}
+
+static void
+jr(int reg)
+{
+ mtspr(Rctr, reg); /* code would be faster if this were loaded well before branch */
+ gen(Obctr);
+}
+
+static void
+jrl(int reg)
+{
+ mtspr(Rctr, reg);
+ gen(Obctrl);
+}
+
+static void
+jrc(int op, int reg)
+{
+ mtspr(Rctr, reg);
+ gen(Obcctr | op);
+}
+
+static long
+brdisp(ulong *dest)
+{
+ ulong d, top;
+
+ d = (ulong)dest - (ulong)code;
+ if(!ROMABLE)
+ return d & 0x3fffffc;
+ top = d>>25;
+ if(top == 0 || top == 0x7F){
+ /* fits in 26-bit signed displacement */
+ return d & 0x3fffffc;
+ }
+ return -1;
+}
+
+static void
+jmp(ulong *dest)
+{
+ long d;
+
+ if((d = brdisp(dest)) < 0){
+ ldbigc((ulong)dest, Rpic); /* Rpic & Rctr must be free */
+ jr(Rpic);
+ } else
+ gen(Ob | d);
+}
+
+static void
+jmpl(ulong *dest)
+{
+ long d;
+
+ if((d = brdisp(dest)) < 0){
+ ldbigc((ulong)dest, Rpic); /* Rpic must be free */
+ jrl(Rpic);
+ } else
+ gen(Ob | d | Lk);
+}
+
+static void
+jmpc(int op, ulong *dest)
+{
+ ldbigc((ulong)dest, Rpic);
+ jrc(op, Rpic);
+}
+
+static int
+bigc(long c)
+{
+ if(c >= -0x8000 && c <= 0x7FFF)
+ return 0;
+ return 1;
+}
+
+static void
+ldbigc(long c, int reg)
+{
+ AIRR(Oaddis, reg,Rzero,c>>16);
+ LIRR(Oori, reg,reg,c);
+}
+
+static void
+ldc(long c, int reg)
+{
+ if(!bigc(c))
+ AIRR(Oaddi, reg, Rzero, c);
+ else if((ulong)c <= 0xFFFF)
+ LIRR(Oori, reg, Rzero, c);
+ else if((c&0xFFFF) == 0)
+ LIRR(Ooris, reg, Rzero, c>>16);
+ else {
+ AIRR(Oaddis, reg,Rzero,c>>16);
+ LIRR(Oori, reg,reg,c);
+ }
+}
+
+static void
+mem(int inst, long disp, int rm, int r)
+{
+ if(bigc(disp)) {
+ ldc(disp, Rcon);
+ switch(inst){
+ default: urk("mem op"); break;
+ case Olea: inst = Oadd; break;
+ case Olwz: inst = Olwzx; break;
+ case Olbz: inst = Olbzx; break;
+ case Olhz: inst = Olhzx; break;
+ case Ostw: inst = Ostwx; break;
+ case Ostb: inst = Ostbx; break;
+ case Osth: inst = Osthx; break;
+ }
+ ARRR(inst, r, Rcon, rm);
+ } else {
+ if(inst == Olea)
+ inst = Oaddi;
+ AIRR(inst, r, rm,disp);
+ }
+}
+
+static void
+opx(int mode, Adr *a, int op, int reg)
+{
+ ulong c;
+ int r, rx, lea;
+
+ lea = 0;
+ if(op == Olea){
+ lea = 1;
+ op = Oaddi;
+ }
+ switch(mode) {
+ case AFP:
+ c = a->ind;
+ if(bigc(c))
+ urk("bigc op1b 1");
+ AIRR(op, reg, Rfp,c);
+ break;
+ case AMP:
+ c = a->ind;
+ if(bigc(c))
+ urk("bigc op1b 2");
+ AIRR(op, reg, Rmp,c);
+ break;
+ case AIMM:
+ if(lea) {
+ if(a->imm != 0) {
+ ldc(a->imm, reg);
+ AIRR(Ostw, reg, Rreg,O(REG,st));
+ } else
+ AIRR(Ostw, Rzero, Rreg,O(REG,st));
+ AIRR(Oaddi, reg, Rreg,O(REG,st));
+ } else
+ ldc(a->imm, reg);
+ return;
+ case AIND|AFP:
+ r = Rfp;
+ goto offset;
+ case AIND|AMP:
+ r = Rmp;
+ offset:
+ c = a->i.s;
+ rx = Ri;
+ if(lea || op == Olwz)
+ rx = reg;
+ AIRR(Olwz, rx, r,a->i.f);
+ if(!lea || c != 0)
+ AIRR(op, reg, rx,c);
+ break;
+ }
+}
+
+static void
+opwld(Inst *i, int op, int reg)
+{
+ opx(USRC(i->add), &i->s, op, reg);
+}
+
+static void
+opwst(Inst *i, int op, int reg)
+{
+ opx(UDST(i->add), &i->d, op, reg);
+}
+
+static void
+op2(Inst *i, int op, int reg)
+{
+ int lea;
+
+ lea = 0;
+ if(op == Olea){
+ op = Oaddi;
+ lea = 1;
+ }
+ switch(i->add & ARM) {
+ case AXNON:
+ if(lea)
+ op = Olea;
+ opwst(i, op, reg);
+ return;
+ case AXIMM:
+ if(lea)
+ urk("op2/lea");
+ ldc((short)i->reg, reg);
+ return;
+ case AXINF:
+ IRR(op, i->reg,Rfp, reg);
+ break;
+ case AXINM:
+ IRR(op, i->reg,Rmp, reg);
+ break;
+ }
+}
+
+static void
+op12(Inst *i, int b1flag, int b2flag)
+{
+ int o1, o2;
+
+ o1 = Olwz;
+ if(b1flag)
+ o1 = Olbz;
+ o2 = Olwz;
+ if(b2flag)
+ o2 = Olbz;
+ if((i->add & ARM) == AXIMM) {
+ opwld(i, o1, Ro1);
+ op2(i, o2, Ro2);
+ } else {
+ op2(i, o2, Ro2);
+ opwld(i, o1, Ro1);
+ }
+}
+
+static void
+op13(Inst *i, int o1, int o2)
+{
+ opwld(i, o1, Ro1);
+ opwst(i, o2, Ro1);
+}
+
+static ulong
+branch(Inst *i)
+{
+ ulong rel;
+
+ if(base == 0)
+ return 0;
+ rel = (ulong)(base+patch[i->d.ins - mod->prog]);
+ rel -= (ulong)code;
+ if(rel & 3 || (long)rel <= -(1<<16) || (long)rel >= 1<<16)
+ urk("branch off");
+ return rel & 0xfffc;
+}
+
+static void
+schedcheck(Inst *i)
+{
+ ulong *cp;
+
+ if(i != nil && i->d.ins != nil && i->d.ins > i)
+ return; /* only backwards jumps can loop: needn't check forward ones */
+ cp = code;
+ gen(Obc | Cnrelq | Cpredict);
+ jmpl(base+macro[MacRELQ]);
+ PATCH(cp);
+}
+
+static void
+literal(ulong imm, int roff)
+{
+ nlit++;
+
+ ldbigc((ulong)litpool, Ro1);
+ IRR(Ostw, roff, Rreg, Ro1);
+
+ if(pass == 0)
+ return;
+
+ *litpool = imm;
+ litpool++;
+}
+
+static void
+bounds(void)
+{
+ /* mem(Ostw, O(REG,FP), Rreg, Rfp); */
+ error(exBounds);
+}
+
+static void
+punt(Inst *i, int m, void (*fn)(void))
+{
+ ulong pc;
+
+ if(m & SRCOP) {
+ if(UXSRC(i->add) == SRC(AIMM))
+ literal(i->s.imm, O(REG, s));
+ else {
+ opwld(i, Olea, Ro1);
+ mem(Ostw, O(REG, s), Rreg, Ro1);
+ }
+ }
+ if(m & DSTOP) {
+ opwst(i, Olea, Ro3);
+ IRR(Ostw, O(REG,d),Rreg, Ro3);
+ }
+ if(m & WRTPC) {
+ pc = patch[i-mod->prog+1];
+ ldbigc((ulong)(base+pc), Ro1);
+ IRR(Ostw, O(REG,PC),Rreg, Ro1);
+ }
+ if(m & DBRAN) {
+ pc = patch[i->d.ins-mod->prog];
+ literal((ulong)(base+pc), O(REG, d));
+ }
+
+ switch(i->add&ARM) {
+ case AXNON:
+ if(m & THREOP) {
+ IRR(Olwz, O(REG,d),Rreg, Ro2);
+ IRR(Ostw, O(REG,m),Rreg, Ro2);
+ }
+ break;
+ case AXIMM:
+ literal((short)i->reg, O(REG,m));
+ break;
+ case AXINF:
+ mem(Olea, i->reg, Rfp, Ro2);
+ mem(Ostw, O(REG, m), Rreg, Ro2);
+ break;
+ case AXINM:
+ mem(Olea, i->reg, Rmp, Ro2);
+ mem(Ostw, O(REG, m), Rreg, Ro2);
+ break;
+ }
+ IRR(Ostw, O(REG,FP),Rreg, Rfp);
+
+ jmpl((ulong*)fn);
+
+ ldc((ulong)&R, Rreg);
+ SETR0();
+ if(m & TCHECK) {
+ IRR(Olwz, O(REG,t),Rreg, Ro1);
+ IRR(Olwz, O(REG,xpc),Rreg, Ro2);
+ IRR(Ocmpi, 0, Ro1, Rcrf0);
+ mtspr(Rctr, Ro2);
+ gen(Obcctr | Cne);
+ }
+ IRR(Olwz, O(REG,FP),Rreg, Rfp);
+ IRR(Olwz, O(REG,MP),Rreg, Rmp);
+
+ if(m & NEWPC) {
+ IRR(Olwz, O(REG,PC),Rreg, Ro1);
+ jr(Ro1);
+ }
+}
+
+static void
+comgoto(Inst *i)
+{
+ WORD *t, *e;
+
+ opwld(i, Olwz, Ro2);
+ opwst(i, Olea, Ro3);
+ SLWI(Ro2, Ro2, 2);
+ ARRR(Olwzx, Ro1, Ro3,Ro2);
+ jr(Ro1);
+
+ if(pass == 0)
+ return;
+
+ t = (WORD*)(mod->origmp+i->d.ind);
+ e = t + t[-1];
+ t[-1] = 0;
+ while(t < e) {
+ t[0] = (ulong)(base + patch[t[0]]);
+ t++;
+ }
+}
+
+static void
+comcase(Inst *i, int w)
+{
+ int l;
+ WORD *t, *e;
+
+ if(w != 0) {
+ opwld(i, Olwz, Ro1); // v
+ opwst(i, Olea, Ro3); // table
+ jmp(base+macro[MacCASE]);
+ }
+
+ t = (WORD*)(mod->origmp+i->d.ind+4);
+ l = t[-1];
+
+ /* have to take care not to relocate the same table twice -
+ * the limbo compiler can duplicate a case instruction
+ * during its folding phase
+ */
+
+ if(pass == 0) {
+ if(l >= 0)
+ t[-1] = -l-1; /* Mark it not done */
+ return;
+ }
+ if(l >= 0) /* Check pass 2 done */
+ return;
+ t[-1] = -l-1; /* Set real count */
+ e = t + t[-1]*3;
+ while(t < e) {
+ t[2] = (ulong)(base + patch[t[2]]);
+ t += 3;
+ }
+ t[0] = (ulong)(base + patch[t[0]]);
+}
+
+static void
+comcasel(Inst *i)
+{
+ int l;
+ WORD *t, *e;
+
+ t = (WORD*)(mod->origmp+i->d.ind+8);
+ l = t[-2];
+ if(pass == 0) {
+ if(l >= 0)
+ t[-2] = -l-1; /* Mark it not done */
+ return;
+ }
+ if(l >= 0) /* Check pass 2 done */
+ return;
+ t[-2] = -l-1; /* Set real count */
+ e = t + t[-2]*6;
+ while(t < e) {
+ t[4] = (ulong)base + patch[t[4]];
+ t += 6;
+ }
+ t[0] = (ulong)base + patch[t[0]];
+}
+
+static void
+commframe(Inst *i)
+{
+ ulong *cp1, *cp2;
+
+ opwld(i, Olwz, Ri); // must use Ri for MacFRAM
+ CMPH(Ri);
+ cp1 = code;
+ br(Obeq, 0);
+
+ if((i->add&ARM) == AXIMM) {
+ mem(Olwz, OA(Modlink, links)+i->reg*sizeof(Modl)+O(Modl, frame), Ri, Ri);
+ } else {
+ op2(i, Olwz, Ro2);
+ SLWI(Ro2, Ro2, 3); // assumes sizeof(Modl) == 8
+ ARRR(Oadd, Ri, Ro2, Ro2);
+ mem(Olwz, OA(Modlink, links)+O(Modl, frame), Ri, Ri);
+ }
+
+ AIRR(Olwz, Ro2, Ri,O(Type,initialize));
+ AIRR(Ocmpi, Rcrf0, Ro2, 0);
+ cp2 = code;
+ br(Obne, 0);
+
+ opwst(i, Olea, Rj);
+
+ PATCH(cp1);
+ ldbigc((ulong)(base+patch[i-mod->prog+1]), Rpic);
+ mtspr(Rlr, Rpic);
+ jmp(base+macro[MacMFRA]);
+
+ PATCH(cp2);
+ jmpl(base+macro[MacFRAM]);
+ opwst(i, Ostw, Ro1);
+}
+
+static void
+commcall(Inst *i)
+{
+ opwld(i, Olwz, Ro1); // f in Ro1
+ AIRR(Olwz, Ro3, Rreg,O(REG,M));
+ AIRR(Ostw, Rfp, Ro1,O(Frame,fp)); // f->fp = R.FP
+ AIRR(Ostw, Ro3, Ro1,O(Frame,mr)); // f->mr = R.M
+ opwst(i, Olwz, Ri);
+ if((i->add&ARM) == AXIMM) {
+ mem(Olwz, OA(Modlink, links)+i->reg*sizeof(Modl)+O(Modl, u.pc), Ri, Rj); // ml->entry in Rj
+ } else {
+ op2(i, Olwz, Rj);
+ SLWI(Rj, Rj, 3); // assumes sizeof(Modl) == 8
+ ARRR(Oadd, Ri, Rj, Rj);
+ mem(Olwz, OA(Modlink, links)+O(Modl, u.pc), Rj, Rj);
+ }
+ jmpl(base+macro[MacMCAL]);
+}
+
+static int
+swapbraop(int b)
+{
+ switch(b) {
+ case Obge:
+ return Oble;
+ case Oble:
+ return Obge;
+ case Obgt:
+ return Oblt;
+ case Oblt:
+ return Obgt;
+ }
+ return b;
+}
+
+static void
+cbra(Inst *i, int op)
+{
+ if(RESCHED)
+ schedcheck(i);
+ if(UXSRC(i->add) == SRC(AIMM) && !bigc(i->s.imm)) {
+ op2(i, Olwz, Ro1);
+ AIRR(Ocmpi, Rcrf0, Ro1, i->s.imm);
+ op = swapbraop(op);
+ } else if((i->add & ARM) == AXIMM) {
+ opwld(i, Olwz, Ro1);
+ AIRR(Ocmpi, Rcrf0, Ro1, i->reg);
+ } else {
+ op12(i, 0, 0);
+ ARRR(Ocmp, Rcrf0, Ro1, Ro2);
+ }
+ br(op, branch(i));
+}
+
+static void
+cbrab(Inst *i, int op)
+{
+ if(RESCHED)
+ schedcheck(i);
+ if(UXSRC(i->add) == SRC(AIMM)) {
+ op2(i, Olbz, Ro1);
+ AIRR(Ocmpi, Rcrf0, Ro1, i->s.imm&0xFF);
+ op = swapbraop(op);
+ } else if((i->add & ARM) == AXIMM) {
+ opwld(i, Olbz, Ro1);
+ AIRR(Ocmpi, Rcrf0, Ro1, i->reg&0xFF); // mask i->reg?
+ } else {
+ op12(i, 1, 1);
+ ARRR(Ocmp, Rcrf0, Ro1, Ro2);
+ }
+ br(op, branch(i));
+}
+
+static void
+cbraf(Inst *i, int op)
+{
+ if(RESCHED)
+ schedcheck(i);
+ opwld(i, Olfd, Rf1);
+ op2(i, Olfd, Rf2);
+ ARRR(Ofcmpo, Rcrf0, Rf1, Rf2);
+ br(op, branch(i));
+}
+
+static void
+cbral(Inst *i, int cms, int cls, int mode)
+{
+ ulong *cp;
+
+ if(RESCHED)
+ schedcheck(i);
+ cp = nil;
+ opwld(i, Olea, Ri);
+ op2(i, Olea, Rj);
+ IRR(Olwz, 0,Ri, Ro1);
+ IRR(Olwz, 0,Rj, Ro2);
+ ARRR(Ocmp, Rcrf0, Ro1, Ro2);
+ switch(mode) {
+ case ANDAND:
+ cp = code;
+ br(cms, 0);
+ break;
+ case OROR:
+ br(cms, branch(i));
+ break;
+ case EQAND:
+ br(cms, branch(i));
+ cp = code;
+ br(Obne, 0);
+ break;
+ }
+ IRR(Olwz, 4,Ri, Ro1);
+ IRR(Olwz, 4,Rj, Ro2);
+ ARRR(Ocmpl, Rcrf0, Ro1, Ro2);
+ br(cls, branch(i));
+ if(cp)
+ PATCH(cp);
+}
+
+static void
+shrl(Inst *i)
+{
+// int c;
+
+// if(USRC(i->add) != AIMM) {
+ punt(i, SRCOP|DSTOP|THREOP, optab[i->op]);
+ return;
+// }
+/*
+ c = i->s.imm;
+ op2(i, Olea, Ro3);
+ IRR(Olwz, 0,Ro3, Ro1);
+ if(c >= 32) {
+ if((i->add&ARM) != AXNON)
+ opwst(i, Olea, Ro3);
+ SRR(Osra, 31, Ro1, Ro2);
+ IRR(Ostw, 0,Ro3, Ro2);
+ if(c >= 64) {
+ IRR(Ostw, 4,Ro3, Ro2);
+ return;
+ }
+ if(c > 32)
+ SRR(Osra, c-32, Ro1, Ro1);
+ IRR(Ostw, 4,Ro3, Ro1);
+ return;
+ }
+ IRR(Olwz, 4,Ro3, Ro2);
+ if((i->add&ARM) != AXNON)
+ opwst(i, Olea, Ro3);
+ if(c != 0) {
+ SRR(Osll, 32-c, Ro1, Ri);
+ SRR(Osra, c, Ro1, Ro1);
+ SRR(Osrl, c, Ro2, Ro2);
+ RRR(Oor, Ri, Ro2, Ro2);
+ }
+ IRR(Ostw, 4,Ro3, Ro2);
+ IRR(Ostw, 0,Ro3, Ro1);
+*/
+}
+
+static void
+shll(Inst *i)
+{
+// int c;
+
+// if(USRC(i->add) != AIMM) {
+ punt(i, SRCOP|DSTOP|THREOP, optab[i->op]);
+ return;
+// }
+/*
+ c = i->s.imm;
+ if(c >= 64) {
+ opwst(i, Olea, Ro3);
+ IRR(Ostw, 0,Ro3, Rzero);
+ IRR(Ostw, 4,Ro3, Rzero);
+ return;
+ }
+ op2(i, Olea, Ro3);
+ if(c >= 32) {
+ IRR(Olwz, 4,Ro3, Ro1);
+ if((i->add&ARM) != AXNON)
+ opwst(i, Olea, Ro3);
+ IRR(Ostw, 4,Ro3, Rzero);
+ if(c > 32)
+ SRR(Osll, c-32, Ro1, Ro1);
+ IRR(Ostw, 0,Ro3, Ro1);
+ return;
+ }
+ IRR(Olwz, 4,Ro3, Ro2);
+ IRR(Olwz, 0,Ro3, Ro1);
+ if((i->add&ARM) != AXNON)
+ opwst(i, Olea, Ro3);
+ if(c != 0) {
+ SRR(Osrl, 32-c, Ro2, Ri);
+ SRR(Osll, c, Ro2, Ro2);
+ SRR(Osll, c, Ro1, Ro1);
+ RRR(Oor, Ri, Ro1, Ro1);
+ }
+ IRR(Ostw, 4,Ro3, Ro2);
+ IRR(Ostw, 0,Ro3, Ro1);
+*/
+}
+
+static void
+compdbg(void)
+{
+ print("%s:%lud@%.8lux\n", R.M->m->name, *(ulong*)R.m, *(ulong*)R.s);
+}
+
+static void
+comp(Inst *i)
+{
+ int o, q, b;
+ ulong *cp, *cp1;
+ char buf[64];
+
+ if(0) {
+ Inst xx;
+ xx.add = AXIMM|SRC(AIMM);
+ xx.s.imm = (ulong)code;
+ xx.reg = i-mod->prog;
+ punt(&xx, SRCOP, compdbg);
+ }
+
+ switch(i->op) {
+ default:
+ snprint(buf, sizeof buf, "%s compile, no '%D'", mod->name, i);
+ error(buf);
+ break;
+ case IMCALL:
+ if((i->add&ARM) == AXIMM)
+ commcall(i);
+ else
+ punt(i, SRCOP|DSTOP|THREOP|WRTPC|NEWPC, optab[i->op]);
+ break;
+ case ISEND:
+ case IRECV:
+ case IALT:
+ punt(i, SRCOP|DSTOP|TCHECK|WRTPC, optab[i->op]);
+ break;
+ case ISPAWN:
+ punt(i, SRCOP|DBRAN, optab[i->op]);
+ break;
+ case IBNEC:
+ case IBEQC:
+ case IBLTC:
+ case IBLEC:
+ case IBGTC:
+ case IBGEC:
+ punt(i, SRCOP|DBRAN|NEWPC|WRTPC, optab[i->op]);
+ break;
+ case ICASEC:
+ comcase(i, 0);
+ punt(i, SRCOP|DSTOP|NEWPC, optab[i->op]);
+ break;
+ case ICASEL:
+ comcasel(i);
+ punt(i, SRCOP|DSTOP|NEWPC, optab[i->op]);
+ break;
+ case IADDC:
+ case IMULL:
+ case IDIVL:
+ case IMODL:
+ case IMNEWZ:
+ case ILSRW:
+ case ILSRL:
+ punt(i, SRCOP|DSTOP|THREOP, optab[i->op]);
+ break;
+ case IMFRAME:
+ if((i->add&ARM) == AXIMM)
+ commframe(i);
+ else
+ punt(i, SRCOP|DSTOP|THREOP, optab[i->op]);
+ break;
+ case ILOAD:
+ case INEWA:
+ case INEWAZ:
+ case INEW:
+ case INEWZ:
+ case ISLICEA:
+ case ISLICELA:
+ case ICONSB:
+ case ICONSW:
+ case ICONSL:
+ case ICONSF:
+ case ICONSM:
+ case ICONSMP:
+ case ICONSP:
+ case IMOVMP:
+ case IHEADMP:
+ case IINSC:
+ case ICVTAC:
+ case ICVTCW:
+ case ICVTWC:
+ case ICVTCL:
+ case ICVTLC:
+ case ICVTFC:
+ case ICVTCF:
+ case ICVTFL:
+ case ICVTLF:
+ case ICVTRF:
+ case ICVTFR:
+ case ICVTWS:
+ case ICVTSW:
+ case IMSPAWN:
+ case ICVTCA:
+ case ISLICEC:
+ case INBALT:
+ punt(i, SRCOP|DSTOP, optab[i->op]);
+ break;
+ case INEWCM:
+ case INEWCMP:
+ punt(i, SRCOP|DSTOP|THREOP, optab[i->op]);
+ break;
+ case INEWCB:
+ case INEWCW:
+ case INEWCF:
+ case INEWCP:
+ case INEWCL:
+ punt(i, DSTOP|THREOP, optab[i->op]);
+ break;
+ case IEXIT:
+ punt(i, 0, optab[i->op]);
+ break;
+ case ICVTWB:
+ op13(i, Olwz, Ostb);
+ break;
+ case ICVTBW:
+ op13(i, Olbz, Ostw);
+ break;
+ case IMOVB:
+ if(USRC(i->add) == AIMM && i->s.imm == 0) {
+ opwst(i, Ostb, Rzero);
+ break;
+ }
+ op13(i, Olbz, Ostb);
+ break;
+ case IMOVW:
+ if(USRC(i->add) == AIMM && i->s.imm == 0) {
+ opwst(i, Ostw, Rzero);
+ break;
+ }
+ op13(i, Olwz, Ostw);
+ break;
+ case ICVTLW:
+ opwld(i, Olea, Ro1);
+ AIRR(Olwz, Ro2, Ro1,4);
+ opwst(i, Ostw, Ro2);
+ break;
+ case ICVTWL:
+ opwld(i, Olwz, Ro1);
+ opwst(i, Olea, Ro2);
+ LRRR(Osrawi, Ro3, Ro1, 31);
+ AIRR(Ostw, Ro1, Ro2,4);
+ AIRR(Ostw, Ro3, Ro2,0);
+ break;
+ case IHEADM:
+ opwld(i, Olwz, Ro1);
+ AIRR(Oaddi, Ro1, Ro1,OA(List,data));
+ movmem(i);
+ break;
+ case IMOVM:
+ opwld(i, Olea, Ro1);
+ movmem(i);
+ break;
+ case IRET:
+ jmp(base+macro[MacRET]);
+ break;
+ case IFRAME:
+ if(UXSRC(i->add) != SRC(AIMM)) {
+ punt(i, SRCOP|DSTOP, optab[i->op]);
+ break;
+ }
+ tinit[i->s.imm] = 1;
+ ldc((ulong)mod->type[i->s.imm], Ri);
+ jmpl(base+macro[MacFRAM]);
+ opwst(i, Ostw, Ro1);
+ break;
+ case ILEA:
+ op13(i, Olea, Ostw);
+ break;
+ case IHEADW:
+ opwld(i, Olwz, Ro1);
+ AIRR(Olwz, Ro1, Ro1,OA(List,data));
+ opwst(i, Ostw, Ro1);
+ break;
+ case IHEADF:
+ opwld(i, Olwz, Ro1);
+ AIRR(Olfd, Rf1, Ro1,OA(List,data));
+ opwst(i, Ostfd, Rf1);
+ break;
+ case IHEADB:
+ opwld(i, Olwz, Ro1);
+ AIRR(Olbz, Ro1, Ro1,OA(List,data));
+ opwst(i, Ostb, Ro1);
+ break;
+ case ITAIL:
+ opwld(i, Olwz, Ro1);
+ AIRR(Olwz, Ro1, Ro1,O(List,tail));
+ goto movp;
+ case IMOVP:
+ opwld(i, Olwz, Ro1);
+ goto movp;
+ case IHEADP:
+ opwld(i, Olwz, Ro1);
+ AIRR(Olwz, Ro1, Ro1,OA(List,data));
+ movp:
+ CMPH(Ro1);
+ cp = code;
+ br(Obeq, 0);
+ jmpl(base+macro[MacCOLR]);
+ PATCH(cp);
+ opwst(i, Olea, Ro3);
+ AIRR(Olwz, Ri, Ro3,0);
+ AIRR(Ostw, Ro1, Ro3,0);
+ jmpl(base+macro[MacFRP]);
+ break;
+ case ILENA:
+ opwld(i, Olwz, Ri);
+ ldc(0, Ro1);
+ CMPH(Ri);
+ cp = code;
+ br(Obeq, 0);
+ AIRR(Olwz, Ro1, Ri,O(Array,len));
+ PATCH(cp);
+ opwst(i, Ostw, Ro1);
+ break;
+ case ILENC:
+ opwld(i, Olwz, Ri);
+ ldc(0, Ro1);
+ CMPH(Ri);
+ cp = code;
+ br(Obeq, 0);
+ AIRR(Olwz, Ro1, Ri,O(String,len));
+ AIRR(Ocmpi, Rcrf0, Ro1, 0);
+ br(Obge, 2*4); // BGE 2(PC); skip
+ ARRR(Oneg, Ro1, Ro1, 0);
+ PATCH(cp);
+ opwst(i, Ostw, Ro1);
+ break;
+ case ILENL:
+ opwld(i, Olwz, Ro1);
+ ldc(0, Ro3);
+ CMPH(Ro1);
+ cp = code;
+ br(Obeq, 0);
+
+ cp1 = code;
+ AIRR(Olwz, Ro1, Ro1,O(List,tail));
+ AIRR(Oaddi, Ro3, Ro3, 1);
+ CMPH(Ro1);
+ br(Obne, ((ulong)cp1-(ulong)code));
+
+ PATCH(cp);
+ opwst(i, Ostw, Ro3);
+ break;
+ case IMOVL:
+ opwld(i, Olea, Ro1);
+ AIRR(Olwz, Ro2, Ro1,0);
+ AIRR(Olwz, Ro3, Ro1,4);
+ opwst(i, Olea, Ro1);
+ AIRR(Ostw, Ro2, Ro1,0);
+ AIRR(Ostw, Ro3, Ro1,4);
+ break;
+ case IMOVF:
+ opwld(i, Olfd, Rf1);
+ opwst(i, Ostfd, Rf1);
+ break;
+ case ICVTFW:
+ if(!macjit){
+ opwld(i, Olfd, Rf1);
+ jmpl(base+macro[MacCVTFW]);
+ opwst(i, Ostw, Ro1);
+ break;
+ }
+ case ICVTWF:
+ punt(i, SRCOP|DSTOP, optab[i->op]);
+ break;
+ case INEGF:
+ opwld(i, Olfd, Rf1);
+ ARRR(Ofneg, Rf2, 0, Rf1);
+ opwst(i, Ostfd, Rf2);
+ break;
+ case IXORL:
+ case IORL:
+ case IANDL:
+ case IADDL:
+ case ISUBL:
+ opwld(i, Olea, Ro1);
+ op2(i, Olea, Ro3);
+
+ AIRR(Olwz, Rj, Ro1,4); /* ls */
+ AIRR(Olwz, Ro2, Ro3,4);
+ AIRR(Olwz, Ri, Ro1,0); /* ms */
+ AIRR(Olwz, Ro1, Ro3,0);
+
+ switch(i->op) {
+ case IXORL:
+ o = Oxor;
+ goto l1;
+ case IORL:
+ o = Oor;
+ goto l1;
+ case IANDL:
+ o = Oand;
+ l1:
+ LRRR(o, Ro1, Ri, Ro1);
+ LRRR(o, Ro2, Rj, Ro2);
+ break;
+ case IADDL:
+ RRR(Oaddc, Rj,Ro2, Ro2);
+ RRR(Oadde, Ri,Ro1, Ro1);
+ break;
+ case ISUBL:
+ RRR(Osubfc, Ro2,Rj, Ro2);
+ RRR(Osubfe, Ro1,Ri, Ro1);
+ break;
+ }
+ if((i->add&ARM) != AXNON)
+ opwst(i, Olea, Ro3);
+ IRR(Ostw, 0,Ro3, Ro1);
+ IRR(Ostw, 4,Ro3, Ro2);
+ break;
+ case ISHLL:
+ shll(i);
+ break;
+ case ISHRL:
+ shrl(i);
+ break;
+ case IADDF: o = Ofadd; goto f1;
+ case ISUBF: o = Ofsub; goto f1;
+ case IMULF: o = Ofmul; goto f1;
+ case IDIVF: o = Ofdiv; goto f1;
+ f1:
+ opwld(i, Olfd, Rf1);
+ op2(i, Olfd, Rf2);
+ if(o == Ofmul)
+ gen(o | (Rf2<<21) | (Rf2<<16) | (Rf1<<6)); /* odd one out: op D,A,-,C */
+ else
+ ARRR(o, Rf2, Rf2, Rf1);
+ opwst(i, Ostfd, Rf2);
+ break;
+
+ case IBEQF:
+ cbraf(i, Obeq);
+ break;
+ case IBGEF:
+ cbraf(i, Obge);
+ case IBGTF:
+ cbraf(i, Obgt);
+ break;
+ case IBLEF:
+ cbraf(i, Oble);
+ break;
+ case IBLTF:
+ cbraf(i, Oblt);
+ break;
+ case IBNEF:
+ cbraf(i, Obne);
+ break;
+
+ case IBLTB:
+ cbrab(i, Oblt);
+ break;
+ case IBLEB:
+ cbrab(i, Oble);
+ break;
+ case IBGTB:
+ cbrab(i, Obgt);
+ break;
+ case IBGEB:
+ cbrab(i, Obge);
+ break;
+ case IBEQB:
+ cbrab(i, Obeq);
+ break;
+ case IBNEB:
+ cbrab(i, Obne);
+ break;
+
+ case IBLTW:
+ cbra(i, Oblt);
+ break;
+ case IBLEW:
+ cbra(i, Oble);
+ break;
+ case IBGTW:
+ cbra(i, Obgt);
+ break;
+ case IBGEW:
+ cbra(i, Obge);
+ break;
+ case IBEQW:
+ cbra(i, Obeq);
+ break;
+ case IBNEW:
+ cbra(i, Obne);
+ break;
+
+ case IBEQL:
+ cbral(i, Obne, Obeq, ANDAND);
+ break;
+ case IBNEL:
+ cbral(i, Obne, Obne, OROR);
+ break;
+ case IBLTL:
+ cbral(i, Oblt, Oblt, EQAND);
+ break;
+ case IBLEL:
+ cbral(i, Oblt, Oble, EQAND);
+ break;
+ case IBGTL:
+ cbral(i, Obgt, Obgt, EQAND);
+ break;
+ case IBGEL:
+ cbral(i, Obgt, Obge, EQAND);
+ break;
+
+ case ISUBB:
+ case IADDB:
+ case IANDB:
+ case IORB:
+ case IXORB:
+ case IMODB:
+ case IDIVB:
+ case IMULB:
+ b = 1;
+ op12(i, b, b);
+ goto s2;
+ case ISHLB:
+ case ISHRB:
+ b = 1;
+ op12(i, 0, b);
+ goto s2;
+ case ISUBW:
+ case IADDW:
+ case IANDW:
+ case IORW:
+ case IXORW:
+ case ISHLW:
+ case ISHRW:
+ case IMODW:
+ case IDIVW:
+ case IMULW:
+ b = 0;
+ op12(i, b, b);
+ s2:
+ q = 0;
+ switch(i->op) {
+ case ISUBB:
+ case ISUBW: o = Osubf; q = Osubfic;
+ // TO DO: if immediate operand, should use opcode q
+ USED(q);
+ ARRR(o, Ro3, Ro1, Ro2);
+ break;
+ case IADDB:
+ case IADDW: o = Oadd; q = Oaddi; goto c1;
+ case IMULB:
+ case IMULW: o = Omullw; q = Omulli; goto c1;
+ case IDIVB:
+ case IDIVW: o = Odivw; goto c1;
+ c1:
+ // TO DO: if immediate operand, should use opcode q
+ USED(q);
+ ARRR(o, Ro3, Ro2, Ro1);
+ break;
+ case IANDB:
+ case IANDW: o = Oand; goto c2;
+ case IORB:
+ case IORW: o = Oor; goto c2;
+ case IXORB:
+ case IXORW: o = Oxor; goto c2;
+ case ISHLB:
+ case ISHLW: o = Oslw; goto c2;
+ case ISHRB:
+ case ISHRW: o = Osraw; goto c2;
+ c2:
+ LRRR(o, Ro3,Ro2,Ro1);
+ break;
+ case IMODB:
+ case IMODW:
+ ARRR(Odivw, Ro3, Ro2, Ro1);
+ ARRR(Omullw, Ro3, Ro3, Ro1);
+ ARRR(Osubf, Ro3, Ro3, Ro2);
+ break;
+ }
+ opwst(i, b? Ostb: Ostw, Ro3);
+ break;
+ case ICALL:
+ opwld(i, Olwz, Ro1); /* f = T(s) */
+ ldbigc((ulong)(base+patch[i-mod->prog+1]), Ro2); /* R.pc */
+ AIRR(Ostw, Rfp, Ro1,O(Frame,fp)); /* f->fp = R.fp */
+ AIRR(Ostw, Ro2, Ro1,O(Frame,lr)); /* f->lr = R.pc */
+ AIRR(Oaddi, Rfp, Ro1, 0); /* R.fp = (uchar*)f */
+ jmp(base+patch[i->d.ins - mod->prog]);
+ break;
+ case IJMP:
+ if(RESCHED)
+ schedcheck(i);
+ jmp(base+patch[i->d.ins - mod->prog]);
+ break;
+ case IGOTO:
+ comgoto(i);
+ break;
+ case IINDC:
+ opwld(i, Olwz, Ro1); // Ro1 = string
+ if((i->add&ARM) != AXIMM)
+ op2(i, Olwz, Ro2); // Ro2 = i
+ AIRR(Olwz, Ri, Ro1,O(String,len)); // len<0 => index Runes, otherwise bytes
+ AIRR(Oaddi, Ro1, Ro1,O(String,data));
+ AIRR(Ocmpi, Rcrf0, Ri, 0);
+ if(bflag){
+ br(Obge, 2*4);
+ ARRR(Oneg, Ri, Ri, 0);
+ if((i->add&ARM) != AXIMM)
+ ARRR(Ocmpl, Rcrf1, Ri, Ro2); /* CMPU len, i */
+ else
+ AIRR(Ocmpli, Rcrf1, Ri, i->reg); /* CMPU len, i */
+ jmpc(Cle1, (ulong*)bounds);
+ }
+ cp = code;
+ br(Obge, 0);
+ if((i->add&ARM) != AXIMM){
+ SLWI(Ro2, Ro2, Lg2Rune);
+ if(sizeof(Rune) == 4)
+ ARRR(Olwz, Ro3, Ro1, Ro2);
+ else
+ ARRR(Olhzx, Ro3, Ro1, Ro2);
+ } else
+ mem(Olwz, (short)i->reg<<Lg2Rune, Ro1, Ro3); /* BUG: TO DO: 16-bit signed displacement */
+ gen(Ob | (2*4)); // skip
+ PATCH(cp);
+ if((i->add&ARM) != AXIMM)
+ ARRR(Olbzx, Ro3, Ro1, Ro2);
+ else
+ AIRR(Olbz, Ro3, Ro1,i->reg);
+ opwst(i, Ostw, Ro3);
+ break;
+ case IINDX:
+ case IINDB:
+ case IINDF:
+ case IINDW:
+ case IINDL:
+ opwld(i, Olwz, Ro1); /* Ro1 = a */
+ opwst(i, Olwz, Ro3); /* Ro3 = i */
+ if(bflag){
+ AIRR(Olwz, Ro2, Ro1, O(Array, len)); /* Ro2 = a->len */
+ ARRR(Ocmpl, Rcrf0, Ro3, Ro2); /* CMPU i, len */
+ jmpc(Cge, (ulong*)bounds);
+ }
+ // TO DO: check a != H
+ AIRR(Olwz, Ro2, Ro1,O(Array,data)); /* Ro2 = a->data */
+ switch(i->op) {
+ case IINDX:
+ AIRR(Olwz, Ri, Ro1,O(Array,t)); // Ri = a->t
+ AIRR(Olwz, Ro1, Ri,O(Type,size)); // Ro1 = a->t->size
+ ARRR(Omullw, Ro3, Ro3, Ro1); // Ro3 = i*size
+ break;
+ case IINDL:
+ case IINDF:
+ SLWI(Ro3, Ro3, 3); /* Ro3 = i*8 */
+ break;
+ case IINDW:
+ SLWI(Ro3, Ro3, 2); /* Ro3 = i*4 */
+ break;
+ case IINDB:
+ /* no further work */
+ break;
+ }
+ ARRR(Oadd, Ro2, Ro2, Ro3); /* Ro2 = i*size + data */
+ op2(i, Ostw, Ro2);
+ break;
+ case ICASE:
+ comcase(i, 1);
+ break;
+ case IRAISE:
+ punt(i, SRCOP|WRTPC|NEWPC, optab[i->op]);
+ break;
+ case IMULX:
+ case IDIVX:
+ case ICVTXX:
+ case IMULX0:
+ case IDIVX0:
+ case ICVTXX0:
+ case IMULX1:
+ case IDIVX1:
+ case ICVTXX1:
+ case ICVTFX:
+ case ICVTXF:
+ case IEXPW:
+ case IEXPL:
+ case IEXPF:
+ punt(i, SRCOP|DSTOP|THREOP, optab[i->op]);
+ break;
+ case ISELF:
+ punt(i, DSTOP, optab[i->op]);
+ break;
+ }
+}
+
+enum {
+ PREFLEN = 20, /* max instruction words in comvec */
+};
+
+static void
+preamble(void)
+{
+ ulong *s;
+
+ if(comvec != nil)
+ return;
+ s = code = malloc(PREFLEN*sizeof(*code));
+ if(s == nil)
+ error(exNomem);
+ ldc((ulong)&R, Rreg);
+ SETR0();
+ mfspr(Rlink, Rlr);
+ AIRR(Ostw, Rlink, Rreg,O(REG,xpc));
+ AIRR(Olwz, Ri, Rreg,O(REG,PC));
+ mtspr(Rctr, Ri);
+ AIRR(Olwz, Rfp, Rreg,O(REG,FP));
+ AIRR(Olwz, Rmp, Rreg,O(REG,MP));
+ gen(Obctr);
+ if(code >= (ulong*)(s + PREFLEN))
+ urk("preamble");
+ comvec = (void*)s;
+ segflush(s, PREFLEN*sizeof(*s));
+ if(cflag > 3) {
+ print("comvec\n");
+ while(s < code)
+ s += das(s);
+ }
+}
+
+static void
+macfrp(void)
+{
+ CMPH(Ri);
+ gen(Obclr | Ceq); // arg == $H? => return
+
+ AIRR(Olwz, Ro2, Ri,O(Heap,ref)-sizeof(Heap));
+ AIRR(Oaddic_, Rj, Ro2, -1); // ref(arg)-- and test
+ AIRR(Ostw, Rj, Ri,O(Heap,ref)-sizeof(Heap));
+ gen(Obclr | Cne); // ref(arg) nonzero? => return
+
+ AIRR(Ostw, Ro2, Ri,O(Heap,ref)-sizeof(Heap)); // restore ref count of 1 for destroy
+ mfspr(Rlink, Rlr);
+ AIRR(Ostw, Rlink, Rreg,O(REG,st));
+ AIRR(Ostw, Rfp, Rreg,O(REG,FP));
+ AIRR(Ostw, Ri, Rreg,O(REG,s));
+
+ jmpl((ulong*)rdestroy); // CALL destroy
+
+ ldc((ulong)&R, Rreg);
+ SETR0();
+ AIRR(Olwz, Rlink, Rreg,O(REG,st));
+ mtspr(Rlr, Rlink);
+ AIRR(Olwz, Rfp, Rreg,O(REG,FP));
+ AIRR(Olwz, Rmp, Rreg,O(REG,MP));
+ LRET();
+}
+
+static void
+macret(void)
+{
+ ulong *cp1, *cp2, *cp3, *cp4, *cp5, *linterp;
+ Inst i;
+
+ AIRR(Olwz, Ro1, Rfp,O(Frame,t));
+ AIRR(Ocmpi, Rcrf0, Ro1, 0);
+ cp1 = code;
+ br(Obeq, 0); // t(Rfp) == 0
+
+ AIRR(Olwz, Rpic, Ro1,O(Type,destroy));
+ AIRR(Ocmpi, Rcrf0, Rpic, 0);
+ cp2 = code;
+ br(Obeq, 0); // destroy(t(fp)) == 0
+
+ AIRR(Olwz, Ro2, Rfp,O(Frame,fp));
+ AIRR(Ocmpi, Rcrf0, Ro2, 0);
+ cp3 = code;
+ br(Obeq, 0); // fp(Rfp) == 0
+
+ AIRR(Olwz, Ro3, Rfp,O(Frame,mr));
+ AIRR(Ocmpi, Rcrf0, Ro3, 0);
+ cp4 = code;
+ br(Obeq, 0); // mr(Rfp) == 0
+
+ AIRR(Olwz, Ro2, Rreg,O(REG,M));
+ AIRR(Olwz, Ro3, Ro2,O(Heap,ref)-sizeof(Heap));
+ AIRR(Oaddic_, Ro3, Ro3, -1); // --ref(arg), set cc
+ cp5 = code;
+ br(Obeq, 0); // --ref(arg) == 0?
+ AIRR(Ostw, Ro3, Ro2,O(Heap,ref)-sizeof(Heap));
+
+ AIRR(Olwz, Ro1, Rfp,O(Frame,mr));
+ AIRR(Ostw, Ro1, Rreg,O(REG,M));
+ AIRR(Olwz, Rmp, Ro1,O(Modlink,MP));
+ AIRR(Ostw, Rmp, Rreg,O(REG,MP));
+ AIRR(Olwz, Ro3, Ro1,O(Modlink,compiled)); // R.M->compiled?
+ AIRR(Ocmpi, Rcrf0, Ro3, 0);
+ linterp = code;
+ br(Obeq, 0);
+
+ PATCH(cp4);
+ jrl(Rpic); // call destroy(t(fp))
+ AIRR(Ostw, Rfp, Rreg,O(REG,SP));
+ AIRR(Olwz, Ro1, Rfp,O(Frame,lr));
+ AIRR(Olwz, Rfp, Rfp,O(Frame,fp));
+ AIRR(Ostw, Rfp, Rreg,O(REG,FP)); // R.FP = Rfp
+ jr(Ro1); // goto lr(Rfp)
+
+ PATCH(linterp);
+ jrl(Rpic); // call destroy(t(fp))
+ AIRR(Ostw, Rfp, Rreg,O(REG,SP));
+ AIRR(Olwz, Ro1, Rfp,O(Frame,lr));
+ AIRR(Olwz, Rfp, Rfp,O(Frame,fp));
+ AIRR(Ostw, Ro1, Rreg,O(REG,PC)); // R.PC = fp->lr
+ AIRR(Ostw, Rfp, Rreg,O(REG,FP)); // R.FP = Rfp
+ AIRR(Olwz, Rpic, Rreg,O(REG,xpc));
+ mtspr(Rlr, Rpic);
+ gen(Oblr); // return to xec uncompiled code
+
+ PATCH(cp1);
+ PATCH(cp2);
+ PATCH(cp3);
+ PATCH(cp5);
+ i.add = AXNON;
+ punt(&i, TCHECK|NEWPC, optab[IRET]);
+}
+
+static void
+maccase(void)
+{
+ ulong *cp1, *cp2, *cp3, *loop;
+
+/*
+ * Ro1 = value (input arg), t
+ * Ro2 = count, n
+ * Ro3 = table pointer (input arg)
+ * Ri = n/2, n2
+ * Rj = pivot element t+n/2*3, l
+ */
+
+ IRR(Olwz, 0,Ro3, Ro2); // count
+ IRR(Oaddi, 0,Ro3, Rlink); // initial table pointer
+
+ loop = code; // loop:
+ AIRR(Ocmpi, Rcrf0, Ro2, 0);
+ cp1 = code;
+ br(Oble, 0); // n <= 0? goto out
+ LRRR(Osrawi, Ri, Ro2, 1); // n2 = n>>1
+ SLWI(Rj, Ri, 1);
+ ARRR(Oadd, Rj, Rj, Ri);
+ SLWI(Rj, Rj, 2);
+ ARRR(Oadd, Rj, Rj, Ro3); // l = t + n2*3;
+ AIRR(Olwz, Rpic, Rj,4);
+ ARRR(Ocmp, Rcrf0, Ro1, Rpic);
+ cp2 = code;
+ br(Oblt, 0); // v < l[1]? goto low
+
+ IRR(Olwz, 8,Rj, Rpic);
+ ARRR(Ocmp, Rcrf0, Ro1, Rpic);
+ cp3 = code;
+ br(Obge, 0); // v >= l[2]? goto high
+
+ IRR(Olwz, 12,Rj, Ro3); // found
+ jr(Ro3);
+
+ PATCH(cp2); // low:
+ IRR(Oaddi, 0, Ri, Ro2); // n = n2
+ jmp(loop);
+
+ PATCH(cp3); // high:
+ IRR(Oaddi, 12, Rj, Ro3); // t = l+3;
+ IRR(Oaddi, 1, Ri, Rpic);
+ RRR(Osubf, Ro2, Rpic, Ro2); // n -= n2 + 1
+ jmp(loop);
+
+ PATCH(cp1); // out:
+ IRR(Olwz, 0,Rlink, Ro2); // initial n
+ SLWI(Ro3, Ro2, 1);
+ RRR(Oadd, Ro3, Ro2, Ro2);
+ SLWI(Ro2, Ro2, 2);
+ RRR(Oadd, Ro2, Rlink, Rlink);
+ IRR(Olwz, 4,Rlink, Ro3); // (initial t)[n*3+1]
+ jr(Ro3);
+}
+
+static void
+macmcal(void)
+{
+ ulong *cp;
+
+ AIRR(Olwz, Ro2, Ri,O(Modlink,prog));
+ mfspr(Rlink, Rlr);
+ AIRR(Ostw, Rlink, Ro1,O(Frame,lr)); // f->lr = return
+ AIRR(Ocmpi, Rcrf0, Ro2, 0);
+ AIRR(Oaddi, Rfp, Ro1, 0); // R.FP = f
+ cp = code;
+ br(Obne, 0); // CMPL ml->m->prog != 0
+
+ AIRR(Ostw, Rlink, Rreg,O(REG,st));
+ AIRR(Ostw, Ro1, Rreg,O(REG,FP));
+ AIRR(Ostw, Rj, Rreg,O(REG,dt));
+ jmpl((ulong*)rmcall); // CALL rmcall
+ ldc((ulong)&R, Rreg);
+ SETR0();
+ AIRR(Olwz, Rlink, Rreg,O(REG,st));
+ mtspr(Rlr, Rlink);
+ AIRR(Olwz, Rfp, Rreg,O(REG,FP));
+ AIRR(Olwz, Rmp, Rreg,O(REG,MP));
+ gen(Oblr); // RET
+
+ PATCH(cp);
+ AIRR(Olwz, Ro2, Ri,O(Heap,ref)-sizeof(Heap));
+ AIRR(Ostw, Ri, Rreg,O(REG,M));
+ AIRR(Oaddi, Ro2, Ro2, 1);
+ AIRR(Olwz, Rmp, Ri,O(Modlink,MP));
+ AIRR(Ostw, Ro2, Ri,O(Heap,ref)-sizeof(Heap));
+ AIRR(Ostw, Rmp, Rreg,O(REG,MP));
+ AIRR(Olwz, Ro2, Ri,O(Modlink,compiled));
+ AIRR(Ocmpi, Rcrf0, Ro2, 0);
+ mtspr(Rctr, Rj);
+ gen(Obcctr | Cne); // return to compiled code
+
+ AIRR(Ostw, Rfp, Rreg,O(REG,FP)); // R.FP = Rfp
+ AIRR(Ostw, Rj, Rreg,O(REG,PC)); // R.PC = Rj
+ AIRR(Olwz, Rpic, Rreg,O(REG,xpc));
+ mtspr(Rlr, Rpic);
+ gen(Oblr); // return to xec uncompiled code
+}
+
+static void
+macmfra(void)
+{
+ mfspr(Rlink, Rlr);
+ AIRR(Ostw, Rlink, Rreg,O(REG,st));
+ AIRR(Ostw, Rfp, Rreg,O(REG,FP));
+ AIRR(Ostw, Ri, Rreg,O(REG,s));
+ AIRR(Ostw, Rj, Rreg,O(REG,d));
+ jmpl((ulong*)rmfram);
+ ldc((ulong)&R, Rreg);
+ SETR0();
+ AIRR(Olwz, Rlink, Rreg,O(REG,st));
+ mtspr(Rlr, Rlink);
+ AIRR(Olwz, Rfp, Rreg,O(REG,FP));
+ AIRR(Olwz, Rmp, Rreg,O(REG,MP));
+ gen(Oblr);
+}
+
+static void
+macfram(void)
+{
+ ulong *cp;
+
+ /*
+ * Ri has t
+ */
+ AIRR(Olwz, Ro2, Ri,O(Type,size)); // MOVW t->size, Ro3
+ AIRR(Olwz, Ro1, Rreg,O(REG,SP)); // MOVW R.SP, Ro1 (=(Frame*)R.SP)
+ AIRR(Olwz, Ro3, Rreg,O(REG,TS)); // MOVW R.TS, tmp
+ ARRR(Oadd, Ro2, Ro2, Ro1); // ADD Ro1, t->size, nsp
+ ARRR(Ocmpl, Rcrf0, Ro2, Ro3); // CMPU nsp,tmp (nsp >= R.TS?)
+ cp = code;
+ br(Obge, 0); // BGE expand
+
+ AIRR(Olwz, Rj, Ri,O(Type,initialize));
+ mtspr(Rctr, Rj);
+ AIRR(Ostw, Ro2, Rreg,O(REG,SP)); // R.SP = nsp
+ AIRR(Ostw, Rzero, Ro1,O(Frame,mr)); // Ro1->mr = nil
+ AIRR(Ostw, Ri, Ro1,O(Frame,t)); // Ro1->t = t
+ gen(Obctr); // become t->init(Ro1), returning Ro1
+
+ PATCH(cp); // expand:
+ AIRR(Ostw, Ri, Rreg,O(REG,s)); // MOVL t, R.s
+ mfspr(Rlink, Rlr);
+ AIRR(Ostw, Rlink, Rreg,O(REG,st)); // MOVL Rlink, R.st
+ AIRR(Ostw, Rfp, Rreg,O(REG,FP)); // MOVL RFP, R.FP
+ jmpl((ulong*)extend); // CALL extend
+ ldc((ulong)&R, Rreg);
+ SETR0();
+ AIRR(Olwz, Rlink, Rreg,O(REG,st)); // reload registers
+ mtspr(Rlr, Rlink);
+ AIRR(Olwz, Rfp, Rreg,O(REG,FP));
+ AIRR(Olwz, Rmp, Rreg,O(REG,MP));
+ AIRR(Olwz, Ro1, Rreg,O(REG,s)); // return R.s set by extend
+ LRET(); // RET
+}
+
+static void
+movloop(int ldu, int stu, int adj)
+{
+ ulong *cp;
+
+ AIRR(Oaddi, Ro1, Ro1, -adj); // adjust for update ld/st
+ AIRR(Oaddi, Ro3, Ro3, -adj);
+ mtspr(Rctr, Ro2);
+
+ cp = code; // l0:
+ AIRR(ldu, Ri, Ro1,adj);
+ AIRR(stu, Ri, Ro3,adj);
+ br(Obc | Cdnz, ((ulong)cp-(ulong)code)); // DBNZ l0
+}
+
+static void
+movmem(Inst *i)
+{
+ ulong *cp;
+
+ // source address already in Ro1
+ if((i->add&ARM) != AXIMM){
+ op2(i, Olwz, Ro2);
+ AIRR(Ocmpi, Rcrf0, Ro2, 0);
+ cp = code;
+ br(Oble, 0);
+ opwst(i, Olea, Ro3);
+ movloop(Olbzu, Ostbu, 1);
+ PATCH(cp);
+ return;
+ }
+ switch(i->reg){
+ case 4:
+ AIRR(Olwz, Ro2, Ro1,0);
+ opwst(i, Ostw, Ro2);
+ break;
+ case 8:
+ AIRR(Olwz, Ro2, Ro1,0);
+ opwst(i, Olea, Ro3);
+ AIRR(Olwz, Ro1, Ro1,4);
+ AIRR(Ostw, Ro2, Ro3,0);
+ AIRR(Ostw, Ro1, Ro3,4);
+ break;
+ default:
+ // could use lwsi/stwsi loop...
+ opwst(i, Olea, Ro3);
+ if((i->reg&3) == 0) {
+ ldc(i->reg>>2, Ro2);
+ movloop(Olwzu, Ostwu, 4);
+ } else {
+ ldc(i->reg, Ro2);
+ movloop(Olbzu, Ostbu, 1);
+ }
+ break;
+ }
+}
+
+static void
+maccolr(void)
+{
+ ldbigc((ulong)&mutator, Ri);
+ AIRR(Olwz, Ri, Ri,0);
+ AIRR(Olwz, Ro3, Ro1,O(Heap,color)-sizeof(Heap)); // h->color
+
+ AIRR(Olwz, Ro2, Ro1,O(Heap,ref)-sizeof(Heap)); // h->ref
+
+ ARRR(Ocmp, Rcrf0, Ri, Ro3);
+ AIRR(Oaddi, Ro2, Ro2, 1); // h->ref++
+ AIRR(Ostw, Ro2, Ro1,O(Heap,ref)-sizeof(Heap));
+ gen(Obclr | Ceq); // return if h->color == mutator
+
+ ldc(propagator, Ro3);
+ AIRR(Ostw, Ro3, Ro1,O(Heap,color)-sizeof(Heap)); // h->color = propagator
+ ldc((ulong)&nprop, Ro3);
+ AIRR(Ostw, Ro1, Ro3,0); // nprop = !0
+ LRET();
+}
+
+static void
+maccvtfw(void)
+{
+ ulong *cp;
+
+ ARRR(Ofcmpo, Rcrf0, Rf1, Rfzero);
+ ARRR(Ofneg, Rf2, 0, Rfhalf);
+ cp = code;
+ br(Oblt, 0);
+ ARRR(Ofmr, Rf2, 0, Rfhalf);
+ PATCH(cp);
+ ARRR(Ofadd, Rf1, Rf1, Rf2); //x<0? x-.5: x+.5
+ ARRR(Ofctiwz, Rf2, 0, Rf1);
+ /* avoid using Ostfdu for now, since software emulation will run on same stack */
+ if(0){
+ AIRR(Ostfdu, Rf2, Rsp,-8); // MOVDU Rf2, -8(R1) (store in temp)
+ }else{
+ AIRR(Oaddi, Rsp, Rsp, -8); // SUB $8, R1
+ AIRR(Ostfd, Rf2, Rsp,0); // MOVD Rf2, 0(R1) (store in temp)
+ }
+ AIRR(Olwz, Ro1, Rsp,4); // MOVW 4(R1), Ro1
+ AIRR(Oaddi, Rsp, Rsp, 8); // ADD $8, R1
+ LRET();
+}
+
+static void
+macrelq(void)
+{
+ ARRR(Ocrxor, Rcrbrel, Rcrbrel, Rcrbrel); /* clear the relinquish condition */
+ mfspr(Rlink, Rlr);
+ IRR(Ostw, O(REG,FP),Rreg, Rfp);
+ IRR(Ostw, O(REG,PC),Rreg, Rlink);
+ IRR(Olwz, O(REG,xpc),Rreg, Ro2);
+ jr(Ro2);
+}
+
+static void
+macend(void)
+{
+}
+
+void
+comd(Type *t)
+{
+ int i, j, m, c;
+
+ mfspr(Rlink, Rlr);
+ AIRR(Ostw, Rlink, Rreg,O(REG,dt));
+ for(i = 0; i < t->np; i++) {
+ c = t->map[i];
+ j = i<<5;
+ for(m = 0x80; m != 0; m >>= 1) {
+ if(c & m) {
+ mem(Olwz, j, Rfp, Ri);
+ jmpl(base+macro[MacFRP]);
+ }
+ j += sizeof(WORD*);
+ }
+ }
+ AIRR(Olwz, Rlink, Rreg,O(REG,dt));
+ mtspr(Rlr, Rlink);
+ gen(Oblr);
+}
+
+void
+comi(Type *t)
+{
+ int i, j, m, c;
+
+ ldc((ulong)H, Ri);
+ for(i = 0; i < t->np; i++) {
+ c = t->map[i];
+ j = i<<5;
+ for(m = 0x80; m != 0; m >>= 1) {
+ if(c & m)
+ mem(Ostw, j, Ro1, Ri);
+ j += sizeof(WORD*);
+ }
+ }
+ LRET();
+}
+
+void
+typecom(Type *t)
+{
+ int n;
+ ulong *tmp, *start;
+
+ if(t == nil || t->initialize != 0)
+ return;
+
+ tmp = mallocz(4096*sizeof(ulong), 0);
+ if(tmp == nil)
+ error(exNomem);
+
+ code = tmp;
+ comi(t);
+ n = code - tmp;
+ code = tmp;
+ comd(t);
+ n += code - tmp;
+ free(tmp);
+
+ n *= sizeof(*code);
+ code = mallocz(n, 0);
+ if(code == nil)
+ return;
+
+ start = code;
+ t->initialize = code;
+ comi(t);
+ t->destroy = code;
+ comd(t);
+
+ segflush(start, n);
+
+ if(cflag > 3)
+ print("typ= %.8lux %4d i %.8lux d %.8lux asm=%d\n",
+ (ulong)t, t->size, (ulong)t->initialize, (ulong)t->destroy, n);
+}
+
+static void
+patchex(Module *m, ulong *p)
+{
+ Handler *h;
+ Except *e;
+
+ if((h = m->htab) == nil)
+ return;
+ for( ; h->etab != nil; h++){
+ h->pc1 = p[h->pc1];
+ h->pc2 = p[h->pc2];
+ for(e = h->etab; e->s != nil; e++)
+ e->pc = p[e->pc];
+ if(e->pc != -1)
+ e->pc = p[e->pc];
+ }
+}
+
+int
+compile(Module *m, int size, Modlink *ml)
+{
+ Link *l;
+ Modl *e;
+ int i, n;
+ ulong *s, *tmp;
+
+ base = nil;
+ patch = mallocz(size*sizeof(*patch), ROMABLE);
+ tinit = malloc(m->ntype*sizeof(*tinit));
+ tmp = malloc(4096*sizeof(ulong));
+ if(tinit == nil || patch == nil || tmp == nil)
+ goto bad;
+
+ preamble();
+
+ mod = m;
+ n = 0;
+ pass = 0;
+ nlit = 0;
+
+ for(i = 0; i < size; i++) {
+ code = tmp;
+ comp(&m->prog[i]);
+ if(code >= &tmp[4096]) {
+ print("%3d %D\n", i, &m->prog[i]);
+ urk("tmp ovflo");
+ }
+ patch[i] = n;
+ n += code - tmp;
+ }
+
+ for(i=0; macinit[i].f; i++) {
+ code = tmp;
+ (*macinit[i].f)();
+ macro[macinit[i].o] = n;
+ n += code - tmp;
+ }
+
+ base = mallocz((n+nlit)*sizeof(*base), 0);
+ if(base == nil)
+ goto bad;
+
+ if(cflag > 3)
+ print("dis=%5d %5d ppc=%5d asm=%.8lux lit=%d: %s\n",
+ size, size*sizeof(Inst), n, (ulong)base, nlit, m->name);
+
+ pass++;
+ nlit = 0;
+ litpool = base+n;
+ code = base;
+ n = 0;
+
+ for(i = 0; i < size; i++) {
+ s = code;
+ comp(&m->prog[i]);
+ if(patch[i] != n) {
+ print("%3d %D\n", i, &m->prog[i]);
+ urk("phase error");
+ }
+ n += code - s;
+ if(cflag > 3) {
+ print("%3d %D\n", i, &m->prog[i]);
+ while(s < code)
+ s += das(s);
+ }/**/
+ }
+
+ for(i=0; macinit[i].f; i++) {
+ if(macro[macinit[i].o] != n) {
+ print("macinit %d\n", macinit[i].o);
+ urk("phase error");
+ }
+ s = code;
+ (*macinit[i].f)();
+ n += code - s;
+ if(cflag > 3) {
+ print("macinit %d\n", macinit[i].o);
+ while(s < code)
+ s += das(s);
+ }/**/
+ }
+
+ for(l = m->ext; l->name; l++) {
+ l->u.pc = (Inst*)(base+patch[l->u.pc-m->prog]);
+ typecom(l->frame);
+ }
+ if(ml != nil) {
+ e = &ml->links[0];
+ for(i = 0; i < ml->nlinks; i++) {
+ e->u.pc = (Inst*)(base+patch[e->u.pc-m->prog]);
+ typecom(e->frame);
+ e++;
+ }
+ }
+ for(i = 0; i < m->ntype; i++) {
+ if(tinit[i] != 0)
+ typecom(m->type[i]);
+ }
+ patchex(m, patch);
+ m->entry = (Inst*)(base+patch[mod->entry-mod->prog]);
+ free(patch);
+ free(tinit);
+ free(tmp);
+ free(m->prog);
+ m->prog = (Inst*)base;
+ m->compiled = 1;
+ segflush(base, n*sizeof(*base));
+ return 1;
+bad:
+ free(patch);
+ free(tinit);
+ free(base);
+ free(tmp);
+ return 0;
+}
--- /dev/null
+++ b/libinterp/comp-sparc.c
@@ -1,0 +1,1882 @@
+#include "lib9.h"
+#include "isa.h"
+#include "interp.h"
+#include "raise.h"
+
+enum
+{
+ R8 = 8, /* SUN calls these %o0 - %o7 */
+ R9 = 9,
+ R10 = 10,
+ R11 = 11,
+ R12 = 12,
+ R13 = 13,
+ R14 = 14, /* SUN %sp */
+ R15 = 15, /* R15/%o7 is the default link register */
+
+ R16 = 16, /* SUN calls these %l0 - %l7 */
+ R17 = 17,
+ R18 = 18,
+ R19 = 19,
+ R20 = 20,
+ R21 = 21,
+ R22 = 22,
+ R23 = 23,
+ RLINK = 15,
+
+ RZ = 0, /* Always 0 */
+ RFP = R23, /* Frame Pointer */
+ RMP = R22, /* Module Pointer */
+ RTA = R21, /* Intermediate address for double indirect */
+ RREG = R20, /* Pointer to REG */
+ RA3 = R19, /* gpr 3 */
+ RA2 = R18, /* gpr 2 2+3 = L */
+ RA1 = R17, /* gpr 1 */
+ RA0 = R16, /* gpr 0 0+1 = L */
+
+ RCON = R8, /* Constant builder */
+
+ FA2 = 2, /* Floating */
+ FA3 = 3,
+ FA4 = 4,
+ FA5 = 5,
+
+ Olea = (1<<20), /* Pseudo op */
+ Owry = 48,
+ Omul = 11,
+ Oumul = 10,
+ Osdiv = 15,
+ Osll = 37,
+ Osra = 39,
+ Osrl = 38,
+ Osethi = 4,
+ Oadd = 0,
+ Oaddcc = 16,
+ Oaddx = 8,
+ Osub = 4,
+ Osubcc = 20,
+ Osubx = 12,
+ Oor = 2,
+ Oand = 1,
+ Oxor = 3,
+ Oldw = 0,
+ Oldsh = 10,
+ Ostw = 4,
+ Osth = 6,
+ Ojmpl = 56,
+ Ocall = 1,
+ Ocmp = 20, /* subcc */
+ Oldbu = 1,
+ Ostb = 5,
+ Oba = 8,
+ Obn = 0,
+ Obne = 9,
+ Obe = 1,
+ Obg = 10,
+ Oble = 2,
+ Obge = 11,
+ Obl = 3,
+ Obgu = 12,
+ Obleu = 4,
+ Obcc = 13,
+ Obcs = 5,
+ Obpos = 14,
+ Obneg = 6,
+ Obvc = 15,
+ Obvs = 7,
+ OfaddD = 66,
+ OfsubD = 70,
+ OfdivD = 78,
+ OfmulD = 74,
+ Oldf = 32,
+ Ostf = 36,
+ OfDtoQ = 206,
+ OfnegS = 5,
+ OfcmpD = 82,
+ Ofba = 8,
+ Ofbe = 9,
+ Ofbg = 6,
+ Ofbge = 11,
+ Ofbl = 4,
+ Ofble = 13,
+ Ofbne = 1,
+ OfWtoD = 200,
+ OfDtoW = 210,
+ Osave = 60,
+ Orestore= 61,
+
+ SRCOP = (1<<0),
+ DSTOP = (1<<1),
+ WRTPC = (1<<2),
+ TCHECK = (1<<3),
+ NEWPC = (1<<4),
+ DBRAN = (1<<5),
+ THREOP = (1<<6),
+
+ ANDAND = 1,
+ OROR = 2,
+ EQAND = 3,
+
+ MacFRP = 0,
+ MacRET = 1,
+ MacCASE = 2,
+ MacCOLR = 3,
+ MacMCAL = 4,
+ MacFRAM = 5,
+ MacMFRA = 6,
+ NMACRO
+};
+
+#define OP(n) (n<<30)
+#define I13(i) ((i)&0x1fff)
+#define D22(i) ((i)&0x3fffff)
+#define PC30(pc) (((ulong)(pc) - (ulong)code)>>2)
+
+#define CALL(addr) *code=OP(1)|PC30(addr); code++
+#define FM2I(op2, i, rd) *code=OP(0)|(rd<<25)|(op2<<22)|D22(i); code++
+#define BRA(cond, disp) *code=OP(0)|(cond<<25)|(2<<22)|D22((disp)); code++
+#define BRAF(cond, disp) *code=OP(0)|(cond<<25)|(6<<22)|D22((disp)); code++
+#define BRADIS(r, o) BRA(r, ((ulong)(base+patch[o])-(ulong)code)>>2)
+#define BRAFDIS(r, o) BRAF(r, ((ulong)(base+patch[o])-(ulong)code)>>2)
+#define BRAMAC(r, o) BRA(r, ((ulong)(base+macro[o])-(ulong)code)>>2);
+#define FM3I(op, op3, i, rs1, rd) *code++=OP(op)|(rd<<25)|(op3<<19)|(rs1<<14)|\
+ (1<<13)|I13(i)
+#define FM3(op, op3, rs2, rs1, rd) *code++=OP(op)|(rd<<25)|(op3<<19)|(rs1<<14)|rs2
+#define FMF1(opf, rs2, rs1, rd) *code++=OP(2)|(rd<<25)|(52<<19)|(rs1<<14)|(opf<<5)|rs2
+#define FMF2(opf, rs2, rs1, rd) *code++=OP(2)|(rd<<25)|(53<<19)|(rs1<<14)|(opf<<5)|rs2
+#define NOOP *code++=(4<<22)
+#define RETURN FM3I(2, Ojmpl, 8, RLINK, RZ);
+#define MOV(s, d) FM3(2, Oor, s, RZ, d)
+
+#define RELPC(pc) (ulong)(base+pc)
+#define PATCH(ptr) *ptr |= (code-ptr) & 0x3fffff
+
+static ulong* code;
+static ulong* base;
+static ulong* patch;
+static int pass;
+static int puntpc = 1;
+static Module* mod;
+static uchar* tinit;
+static ulong* litpool;
+static int nlit;
+static void macfrp(void);
+static void macret(void);
+static void maccase(void);
+static void maccolr(void);
+static void macmcal(void);
+static void macfram(void);
+static void macmfra(void);
+static ulong macro[NMACRO];
+ void (*comvec)(void);
+extern void das(ulong*, int);
+
+#define T(r) *((void**)(R.r))
+
+struct
+{
+ int idx;
+ void (*gen)(void);
+ char* name;
+} mactab[] =
+{
+ MacFRP, macfrp, "FRP", /* decrement and free pointer */
+ MacRET, macret, "RET", /* return instruction */
+ MacCASE, maccase, "CASE", /* case instruction */
+ MacCOLR, maccolr, "COLR", /* increment and color pointer */
+ MacMCAL, macmcal, "MCAL", /* mcall bottom half */
+ MacFRAM, macfram, "FRAM", /* frame instruction */
+ MacMFRA, macmfra, "MFRA", /* punt mframe because t->initialize==0 */
+};
+
+static void
+rdestroy(void)
+{
+ destroy(R.s);
+}
+
+static void
+rmcall(void)
+{
+ Prog *p;
+ Frame *f;
+
+ f = (Frame*)R.FP;
+ if(f == H)
+ error(exModule);
+
+ f->mr = nil;
+ ((void(*)(Frame*))R.dt)(f);
+ R.SP = (uchar*)f;
+ R.FP = f->fp;
+ if(f->t == nil)
+ unextend(f);
+ else
+ freeptrs(f, f->t);
+ p = currun();
+ if(p->kill != nil)
+ error(p->kill);
+}
+
+static void
+rmfram(void)
+{
+ Type *t;
+ Frame *f;
+ uchar *nsp;
+
+ if(R.d == H)
+ error(exModule);
+ t = (Type*)R.s;
+ if(t == H)
+ error(exModule);
+
+ nsp = R.SP + t->size;
+ if(nsp >= R.TS) {
+ R.s = t;
+ extend();
+ T(d) = R.s;
+ return;
+ }
+ f = (Frame*)R.SP;
+ R.SP = nsp;
+ f->t = t;
+ f->mr = nil;
+ initmem(t, f);
+ T(d) = f;
+}
+
+static void
+urk(void)
+{
+ error(exCompile);
+}
+
+static int
+bc(long c)
+{
+ c &= ~0xfffL;
+ if (c == 0 || c == ~0xfffL)
+ return 1;
+
+ return 0;
+}
+
+static void
+con(ulong o, int r, int opt)
+{
+ if(opt != 0) {
+ if(bc(o)) {
+ FM3I(2, Oadd, o & 0x1fff, RZ, r);
+ return;
+ }
+ if((o & 0x3ff) == 0) {
+ FM2I(Osethi, o>>10, r);
+ return;
+ }
+ }
+ FM2I(Osethi, o>>10, r);
+ FM3I(2, Oadd, o & 0x3ff, r, r);
+}
+
+static void
+mem(int inst, ulong disp, int rm, int r)
+{
+ int op;
+
+ op = 3;
+ if(inst == Olea) {
+ op = 2;
+ inst = Oadd;
+ }
+ if(bc(disp)) {
+ FM3I(op, inst, disp, rm, r);
+ return;
+ }
+ con(disp, RCON, 1);
+ FM3(op, inst, RCON, rm, r);
+}
+
+static void
+opwld(Inst *i, int mi, int r)
+{
+ int ir, rta;
+
+ switch(UXSRC(i->add)) {
+ default:
+ print("%D\n", i);
+ urk();
+ case SRC(AFP):
+ mem(mi, i->s.ind, RFP, r);
+ return;
+ case SRC(AMP):
+ mem(mi, i->s.ind, RMP, r);
+ return;
+ case SRC(AIMM):
+ con(i->s.imm, r, 1);
+ if(mi == Olea) {
+ mem(Ostw, O(REG, st), RREG, r);
+ con((ulong)&R.st, r, 1);
+ }
+ return;
+ case SRC(AIND|AFP):
+ ir = RFP;
+ break;
+ case SRC(AIND|AMP):
+ ir = RMP;
+ break;
+ }
+ rta = RTA;
+ if(mi == Olea)
+ rta = r;
+ mem(Oldw, i->s.i.f, ir, rta);
+ mem(mi, i->s.i.s, rta, r);
+}
+
+static void
+opwst(Inst *i, int mi, int r)
+{
+ int ir, rta;
+
+ switch(UXDST(i->add)) {
+ default:
+ print("%D\n", i);
+ urk();
+ case DST(AIMM):
+ con(i->d.imm, r, 1);
+ return;
+ case DST(AFP):
+ mem(mi, i->d.ind, RFP, r);
+ return;
+ case DST(AMP):
+ mem(mi, i->d.ind, RMP, r);
+ return;
+ case DST(AIND|AFP):
+ ir = RFP;
+ break;
+ case DST(AIND|AMP):
+ ir = RMP;
+ break;
+ }
+ rta = RTA;
+ if(mi == Olea)
+ rta = r;
+ mem(Oldw, i->d.i.f, ir, rta);
+ mem(mi, i->d.i.s, rta, r);
+}
+
+static void
+opfl(Adr *a, int am, int mi, int r)
+{
+ int ir;
+
+ switch(am) {
+ default:
+ urk();
+ case AFP:
+ mem(mi, a->ind, RFP, r);
+ mem(mi, a->ind+4, RFP, r+1);
+ return;
+ case AMP:
+ mem(mi, a->ind, RMP, r);
+ mem(mi, a->ind+4, RMP, r+1);
+ return;
+ case AIND|AFP:
+ ir = RFP;
+ break;
+ case AIND|AMP:
+ ir = RMP;
+ break;
+ }
+ mem(Oldw, a->i.f, ir, RTA);
+ mem(mi, a->i.s, RTA, r);
+ mem(mi, a->i.s+4, RTA, r+1);
+}
+
+static void
+opflld(Inst *i, int mi, int r)
+{
+ opfl(&i->s, USRC(i->add), mi, r);
+}
+
+static void
+opflst(Inst *i, int mi, int r)
+{
+ opfl(&i->d, UDST(i->add), mi, r);
+}
+
+static void
+literal(ulong imm, int roff)
+{
+ nlit++;
+
+ con((ulong)litpool, RTA, 0);
+ mem(Ostw, roff, RREG, RTA);
+
+ if(pass == 0)
+ return;
+
+ *litpool = imm;
+ litpool++;
+}
+
+static void
+punt(Inst *i, int m, void (*fn)(void))
+{
+ ulong pc;
+
+ if(m & SRCOP) {
+ if(UXSRC(i->add) == SRC(AIMM))
+ literal(i->s.imm, O(REG, s));
+ else {
+ opwld(i, Olea, RA0);
+ mem(Ostw, O(REG, s), RREG, RA0);
+ }
+ }
+
+ if(m & DSTOP) {
+ opwst(i, Olea, RA0);
+ mem(Ostw, O(REG, d), RREG, RA0);
+ }
+ if(m & WRTPC) {
+ con(RELPC(patch[i-mod->prog+1]), RA0, 0);
+ mem(Ostw, O(REG, PC), RREG, RA0);
+ }
+ if(m & DBRAN) {
+ pc = patch[(Inst*)i->d.imm-mod->prog];
+ literal(RELPC(pc), O(REG, d));
+ }
+
+ switch(i->add&ARM) {
+ case AXNON:
+ if(m & THREOP) {
+ mem(Oldw, O(REG, d), RREG, RA0);
+ mem(Ostw, O(REG, m), RREG, RA0);
+ }
+ break;
+ case AXIMM:
+ literal((short)i->reg, O(REG, m));
+ break;
+ case AXINF:
+ mem(Olea, i->reg, RFP, RA0);
+ mem(Ostw, O(REG, m), RREG, RA0);
+ break;
+ case AXINM:
+ mem(Olea, i->reg, RMP, RA0);
+ mem(Ostw, O(REG, m), RREG, RA0);
+ break;
+ }
+
+ CALL(fn);
+ mem(Ostw, O(REG, FP), RREG, RFP);
+
+ con((ulong)&R, RREG, 1);
+ if(m & TCHECK) {
+ mem(Oldw, O(REG, t), RREG, RA0);
+ FM3I(2, Ocmp, 0, RA0, RZ);
+ BRA(Obe, 5);
+ NOOP;
+ mem(Oldw, O(REG, xpc), RREG, RLINK);
+ RETURN;
+ NOOP;
+ }
+
+ mem(Oldw, O(REG, FP), RREG, RFP);
+ mem(Oldw, O(REG, MP), RREG, RMP);
+
+ if(m & NEWPC) {
+ mem(Oldw, O(REG, PC), RREG, RA0);
+ FM3I(2, Ojmpl, 0, RA0, RZ);
+ NOOP;
+ }
+}
+
+static void
+midfl(Inst *i, int mi, int r)
+{
+ int ir;
+
+ switch(i->add&ARM) {
+ default:
+ opflst(i, mi, r);
+ return;
+ case AXIMM:
+ con((short)i->reg, r, 1);
+ return;
+ case AXINF:
+ ir = RFP;
+ break;
+ case AXINM:
+ ir = RMP;
+ break;
+ }
+ mem(mi, i->reg, ir, r);
+ mem(mi, i->reg+4, ir, r+1);
+}
+
+static void
+mid(Inst *i, int mi, int r)
+{
+ int ir;
+
+ switch(i->add&ARM) {
+ default:
+ opwst(i, mi, r);
+ return;
+ case AXIMM:
+ con((short)i->reg, r, 1);
+ return;
+ case AXINF:
+ ir = RFP;
+ break;
+ case AXINM:
+ ir = RMP;
+ break;
+ }
+ mem(mi, i->reg, ir, r);
+}
+
+static void
+cbral(Inst *i, int jmsw, int jlsw, int mode)
+{
+ ulong dst, *label;
+
+ opwld(i, Olea, RA1);
+ mid(i, Olea, RA3);
+ mem(Oldw, 0, RA1, RA2);
+ mem(Oldw, 0, RA3, RA0);
+ FM3(2, Ocmp, RA0, RA2, RZ);
+ label = nil;
+ dst = i->d.ins-mod->prog;
+ switch(mode) {
+ case ANDAND:
+ label = code;
+ BRA(jmsw, 0);
+ break;
+ case OROR:
+ BRADIS(jmsw, dst);
+ break;
+ case EQAND:
+ BRADIS(jmsw, dst);
+ NOOP;
+ label = code;
+ BRA(Obne, 0);
+ break;
+ }
+ NOOP;
+ mem(Oldw, 4, RA3, RA0);
+ mem(Oldw, 4, RA1, RA2);
+ FM3(2, Ocmp, RA0, RA2, RZ);
+ BRADIS(jlsw, dst);
+ if(label != nil)
+ PATCH(label);
+}
+
+static void
+comcase(Inst *i, int w)
+{
+ int l;
+ WORD *t, *e;
+
+ if(w != 0) {
+ opwld(i, Oldw, RA0); // v
+ opwst(i, Olea, RCON); // table
+ BRAMAC(Oba, MacCASE);
+ NOOP;
+ }
+
+ t = (WORD*)(mod->origmp+i->d.ind+4);
+ l = t[-1];
+
+ /* have to take care not to relocate the same table twice -
+ * the limbo compiler can duplicate a case instruction
+ * during its folding phase
+ */
+
+ if(pass == 0) {
+ if(l >= 0)
+ t[-1] = -l-1; /* Mark it not done */
+ return;
+ }
+ if(l >= 0) /* Check pass 2 done */
+ return;
+ t[-1] = -l-1; /* Set real count */
+ e = t + t[-1]*3;
+ while(t < e) {
+ t[2] = RELPC(patch[t[2]]);
+ t += 3;
+ }
+ t[0] = RELPC(patch[t[0]]);
+}
+
+static void
+comcasel(Inst *i)
+{
+ int l;
+ WORD *t, *e;
+
+ t = (WORD*)(mod->origmp+i->d.ind+8);
+ l = t[-2];
+ if(pass == 0) {
+ if(l >= 0)
+ t[-2] = -l-1; /* Mark it not done */
+ return;
+ }
+ if(l >= 0) /* Check pass 2 done */
+ return;
+ t[-2] = -l-1; /* Set real count */
+ e = t + t[-2]*6;
+ while(t < e) {
+ t[4] = RELPC(patch[t[4]]);
+ t += 6;
+ }
+ t[0] = RELPC(patch[t[0]]);
+}
+
+static void
+commframe(Inst *i)
+{
+ int o;
+ ulong *punt, *mlnil;
+
+ opwld(i, Oldw, RA0);
+ FM3I(2, Ocmp, -1, RA0, RZ);
+ mlnil = code;
+ BRA(Obe, 0);
+ NOOP;
+
+ if((i->add&ARM) == AXIMM) {
+ o = OA(Modlink, links)+i->reg*sizeof(Modl)+O(Modl, frame);
+ mem(Oldw, o, RA0, RA3);
+ } else {
+ mid(i, Oldw, RA1);
+ FM3I(2, Osll, 3, RA1, RA1); // assumes sizeof(Modl) == 8
+ FM3(2, Oadd, RA0, RA1, RA1);
+ o = OA(Modlink, links)+O(Modl, frame);
+ mem(Oldw, o, RA1, RA3);
+ }
+ mem(Oldw, O(Type, initialize), RA3, RA1);
+ FM3I(2, Ocmp, 0, RA1, RZ);
+ punt = code;
+ BRA(Obne, 0);
+ NOOP;
+
+ opwst(i, Olea, RA0);
+
+ /* Type in RA3, destination in RA0 */
+ PATCH(mlnil);
+ con(RELPC(patch[i-mod->prog+1])-8, RLINK, 0);
+ BRAMAC(Oba, MacMFRA);
+ NOOP;
+
+ /* Type in RA3 */
+ PATCH(punt);
+ CALL(base+macro[MacFRAM]);
+ NOOP;
+ opwst(i, Ostw, RA2);
+}
+
+static void
+commcall(Inst *i)
+{
+ opwld(i, Oldw, RA2);
+ con(RELPC(patch[i-mod->prog+1]), RA0, 0);
+ mem(Ostw, O(Frame, lr), RA2, RA0);
+ mem(Ostw, O(Frame, fp), RA2, RFP);
+ mem(Oldw, O(REG, M), RREG, RA3);
+ mem(Ostw, O(Frame, mr), RA2, RA3);
+ opwst(i, Oldw, RA3);
+ if((i->add&ARM) == AXIMM) {
+ CALL(base+macro[MacMCAL]);
+ mem(Oldw, OA(Modlink, links)+i->reg*sizeof(Modl)+O(Modl, u.pc), RA3, RA0);
+ } else {
+ mid(i, Oldw, RA1);
+ FM3I(2, Osll, 3, RA1, RA1); // assumes sizeof(Modl) == 8
+ FM3(2, Oadd, RA1, RA3, RA0);
+ CALL(base+macro[MacMCAL]);
+ mem(Oldw, OA(Modlink, links)+O(Modl, u.pc), RA0, RA0);
+ }
+}
+
+static void
+larith(Inst *i, int op, int opc)
+{
+ opflld(i, Oldw, RA0);
+ midfl(i, Oldw, RA2);
+ FM3(2, op, RA1, RA3, RA1);
+ FM3(2, opc, RA0, RA2, RA0);
+ opflst(i, Ostw, RA0);
+}
+
+static void
+movloop(Inst *i, int ld, int st)
+{
+ int s;
+
+ s = 1;
+ if(ld == Oldw)
+ s = 4;
+ opwld(i, Olea, RA1);
+ opwst(i, Olea, RA2);
+ mem(ld, 0, RA1, RA0);
+ mem(st, 0, RA2, RA0);
+ FM3I(2, Oadd, s, RA2, RA2);
+ FM3I(2, Oaddcc, -1, RA3, RA3);
+ BRA(Obne, -4);
+ FM3I(2, Oadd, s, RA1, RA1);
+}
+
+static
+void
+compdbg(void)
+{
+ print("%s:%d@%.8ux\n", R.M->m->name, R.t, R.st);
+}
+
+static void
+shll(Inst *i)
+{
+ ulong *lab0, *lab1, *lab2;
+
+ opwld(i, Oldw, RA2);
+ midfl(i, Oldw, RA0);
+ FM3I(2, Ocmp, RZ, RA2, RZ);
+ lab0 = code;
+ BRA(Obe, 0);
+ FM3I(2, Ocmp, 32, RA2, RZ);
+ lab1 = code;
+ BRA(Obl, 0);
+ NOOP;
+ FM3I(2, Osub, 32, RA2, RA2);
+ FM3(2, Osll, RA2, RA1, RA0);
+ lab2 = code;
+ BRA(Oba, 0);
+ MOV(RZ, RA1);
+
+ PATCH(lab1);
+ FM3(2, Osll, RA2, RA0, RA0);
+ con(32, RA3, 1);
+ FM3(2, Osub, RA2, RA3, RA3);
+ FM3(2, Osrl, RA3, RA1, RA3);
+ FM3(2, Oor, RA0, RA3, RA0);
+ FM3(2, Osll, RA2, RA1, RA1);
+
+ PATCH(lab0);
+ PATCH(lab2);
+ opflst(i, Ostw, RA0);
+}
+
+static void
+comp(Inst *i)
+{
+ int r;
+ WORD *t, *e;
+ char buf[64];
+
+ if(0) {
+ Inst xx;
+ xx.add = AXIMM|SRC(AIMM);
+ xx.s.imm = (ulong)code;
+ xx.reg = i-mod->prog;
+ puntpc = 0;
+ punt(&xx, SRCOP, compdbg);
+ puntpc = 1;
+ }
+
+ switch(i->op) {
+ default:
+ snprint(buf, sizeof buf, "%s compile, no '%D'", mod->name, i);
+ error(buf);
+ break;
+ case IMCALL:
+ if((i->add&ARM) == AXIMM)
+ commcall(i);
+ else
+ punt(i, SRCOP|DSTOP|THREOP|WRTPC|NEWPC, optab[i->op]);
+ break;
+ case ISEND:
+ case IRECV:
+ case IALT:
+ punt(i, SRCOP|DSTOP|TCHECK|WRTPC, optab[i->op]);
+ break;
+ case ISPAWN:
+ punt(i, SRCOP|DBRAN, optab[i->op]);
+ break;
+ case IBNEC:
+ case IBEQC:
+ case IBLTC:
+ case IBLEC:
+ case IBGTC:
+ case IBGEC:
+ punt(i, SRCOP|DBRAN|NEWPC|WRTPC, optab[i->op]);
+ break;
+ case ICASEC:
+ comcase(i, 0);
+ punt(i, SRCOP|DSTOP|NEWPC, optab[i->op]);
+ break;
+ case ICASEL:
+ comcasel(i);
+ punt(i, SRCOP|DSTOP|NEWPC, optab[i->op]);
+ break;
+ case IADDC:
+ case IMULL:
+ case IDIVL:
+ case IMODL:
+ case IMODW:
+ case IMODB:
+ case IMNEWZ:
+ punt(i, SRCOP|DSTOP|THREOP, optab[i->op]);
+ break;
+ case ILOAD:
+ case INEWA:
+ case INEWAZ:
+ case INEW:
+ case INEWZ:
+ case ISLICEA:
+ case ISLICELA:
+ case ICONSB:
+ case ICONSW:
+ case ICONSL:
+ case ICONSF:
+ case ICONSM:
+ case ICONSMP:
+ case ICONSP:
+ case IMOVMP:
+ case IHEADMP:
+ case IHEADM:
+ case IHEADB:
+ case IHEADW:
+ case IHEADL:
+ case IHEADF:
+ case IINDC:
+ case ILENC:
+ case IINSC:
+ case ICVTAC:
+ case ICVTCW:
+ case ICVTWC:
+ case ICVTLC:
+ case ICVTCL:
+ case ICVTFC:
+ case ICVTCF:
+ case ICVTRF:
+ case ICVTFR:
+ case IMSPAWN:
+ case ICVTCA:
+ case ISLICEC:
+ case INBALT:
+ punt(i, SRCOP|DSTOP, optab[i->op]);
+ break;
+ case INEWCM:
+ case INEWCMP:
+ punt(i, SRCOP|DSTOP|THREOP, optab[i->op]);
+ break;
+ case IMFRAME:
+ if((i->add&ARM) == AXIMM)
+ commframe(i);
+ else
+ punt(i, SRCOP|DSTOP|THREOP, optab[i->op]);
+ break;
+ case ICASE:
+ comcase(i, 1);
+ break;
+ case IGOTO:
+ opwld(i, Oldw, RA1);
+ opwst(i, Olea, RA0);
+ FM3I(2, Osll, 2, RA1, RA1);
+ FM3(3, Oldw, RA1, RA0, RA0);
+ FM3I(2, Ojmpl, 0, RA0, RZ);
+ NOOP;
+
+ if(pass == 0)
+ break;
+
+ t = (WORD*)(mod->origmp+i->d.ind);
+ e = t + t[-1];
+ t[-1] = 0;
+ while(t < e) {
+ t[0] = RELPC(patch[t[0]]);
+ t++;
+ }
+ break;
+ case IMOVL:
+ movl:
+ opflld(i, Oldw, RA0);
+ opflst(i, Ostw, RA0);
+ break;
+ case IMOVM:
+ if((i->add&ARM) == AXIMM) {
+ if(i->reg == 8)
+ goto movl;
+ if((i->reg&3) == 0) {
+ con(i->reg>>2, RA3, 1);
+ movloop(i, Oldw, Ostw);
+ break;
+ }
+ }
+ mid(i, Oldw, RA3);
+ movloop(i, Oldbu, Ostb);
+ break;
+ case IFRAME:
+ if(UXSRC(i->add) != SRC(AIMM)) {
+ punt(i, SRCOP|DSTOP, optab[i->op]);
+ break;
+ }
+ tinit[i->s.imm] = 1;
+ con((ulong)mod->type[i->s.imm], RA3, 1);
+ CALL(base+macro[MacFRAM]);
+ NOOP;
+ opwst(i, Ostw, RA2);
+ break;
+ case INEWCB:
+ case INEWCW:
+ case INEWCF:
+ case INEWCP:
+ case INEWCL:
+ punt(i, DSTOP|THREOP, optab[i->op]);
+ break;
+ case IEXIT:
+ punt(i, 0, optab[i->op]);
+ break;
+ case ICVTBW:
+ opwld(i, Oldbu, RA0);
+ opwst(i, Ostw, RA0);
+ break;
+ case ICVTWB:
+ opwld(i, Oldw, RA0);
+ opwst(i, Ostb, RA0);
+ break;
+ case ILEA:
+ opwld(i, Olea, RA0);
+ opwst(i, Ostw, RA0);
+ break;
+ case IMOVW:
+ opwld(i, Oldw, RA0);
+ opwst(i, Ostw, RA0);
+ break;
+ case IMOVB:
+ opwld(i, Oldbu, RA0);
+ opwst(i, Ostb, RA0);
+ break;
+ case ICVTSW:
+ opwld(i, Oldsh, RA0);
+ opwst(i, Ostw, RA0);
+ break;
+ case ICVTWS:
+ opwld(i, Oldw, RA0);
+ opwst(i, Osth, RA0);
+ break;
+ case ITAIL:
+ opwld(i, Oldw, RA0);
+ mem(Oldw, O(List, tail), RA0, RA1);
+ goto movp;
+ case IMOVP:
+ case IHEADP:
+ opwld(i, Oldw, RA1);
+ if(i->op == IHEADP)
+ mem(Oldw, OA(List, data), RA1, RA1);
+ movp:
+ FM3I(2, Ocmp, (ulong)H, RA1, RZ);
+ BRA(Obe, 5);
+ con((ulong)&mutator, RA2, 1);
+ CALL(base+macro[MacCOLR]);
+ mem(Oldw, O(Heap, ref)-sizeof(Heap), RA1, RA0);
+ opwst(i, Oldw, RA0);
+ opwst(i, Ostw, RA1);
+ CALL(base+macro[MacFRP]);
+ NOOP;
+ break;
+ case ILENA:
+ opwld(i, Oldw, RA1);
+ FM3I(2, Ocmp, (ulong)H, RA1, RZ);
+ BRA(Obe, 3);
+ con(0, RA0, 1);
+ mem(Oldw, O(Array, len), RA1, RA0);
+ opwst(i, Ostw, RA0);
+ break;
+ case ILENL:
+ con(0, RA0, 1);
+ opwld(i, Oldw, RA1);
+ FM3I(2, Ocmp, (ulong)H, RA1, RZ);
+ BRA(Obe, 5);
+ NOOP;
+ mem(Oldw, O(List, tail), RA1, RA1);
+ BRA(Oba, -4);
+ FM3I(2, Oadd, 1, RA0, RA0);
+ opwst(i, Ostw, RA0);
+ break;
+ case ICALL:
+ opwld(i, Oldw, RA0);
+ con(RELPC(patch[i-mod->prog+1]), RA1, 0);
+ mem(Ostw, O(Frame, lr), RA0, RA1);
+ mem(Ostw, O(Frame, fp), RA0, RFP);
+ BRADIS(Oba, i->d.ins-mod->prog);
+ MOV(RA0, RFP);
+ break;
+ case IJMP:
+ BRADIS(Oba, i->d.ins-mod->prog);
+ NOOP;
+ break;
+ case IBEQW:
+ r = Obe;
+ braw:
+ opwld(i, Oldw, RA1);
+ mid(i, Oldw, RA0);
+ FM3(2, Ocmp, RA0, RA1, RZ);
+ BRADIS(r, i->d.ins-mod->prog);
+ NOOP;
+ break;
+ case IBNEW:
+ r = Obne;
+ goto braw;
+ case IBLTW:
+ r = Obl;
+ goto braw;
+ case IBLEW:
+ r = Oble;
+ goto braw;
+ case IBGTW:
+ r = Obg;
+ goto braw;
+ case IBGEW:
+ r = Obge;
+ goto braw;
+ case IBEQB:
+ r = Obe;
+ brab:
+ opwld(i, Oldbu, RA1);
+ mid(i, Oldbu, RA0);
+ FM3(2, Ocmp, RA0, RA1, RZ);
+ BRADIS(r, i->d.ins-mod->prog);
+ NOOP;
+ break;
+ case IBNEB:
+ r = Obne;
+ goto brab;
+ case IBLTB:
+ r = Obl;
+ goto brab;
+ case IBLEB:
+ r = Oble;
+ goto brab;
+ case IBGTB:
+ r = Obg;
+ goto brab;
+ case IBGEB:
+ r = Obge;
+ goto brab;
+ case IBEQF:
+ r = Ofbe;
+ braf:
+ opflld(i, Oldf, FA4);
+ midfl(i, Oldf, FA2);
+ FMF2(OfcmpD, FA2, FA4, 0);
+ NOOP;
+ BRAFDIS(r, i->d.ins-mod->prog);
+ NOOP;
+ break;
+ case IBNEF:
+ r = Ofbne;
+ goto braf;
+ case IBLTF:
+ r = Ofbl;
+ goto braf;
+ case IBLEF:
+ r = Ofble;
+ goto braf;
+ case IBGTF:
+ r = Ofbg;
+ goto braf;
+ case IBGEF:
+ r = Ofbge;
+ goto braf;
+ case IRET:
+ BRAMAC(Oba, MacRET);
+ mem(Oldw, O(Frame,t), RFP, RA1);
+ break;
+ case IORW:
+ r = Oor;
+ goto arithw;
+ case IANDW:
+ r = Oand;
+ goto arithw;
+ case IXORW:
+ r = Oxor;
+ goto arithw;
+ case ISUBW:
+ r = Osub;
+ goto arithw;
+ case ISHRW:
+ r = Osra;
+ goto arithw;
+ case ISHLW:
+ r = Osll;
+ goto arithw;
+ case ILSRW:
+ r = Osrl;
+ goto arithw;
+ case IMULW:
+ r = Omul;
+ goto arithw;
+ case IDIVW:
+ r = Osdiv;
+ goto arithw;
+ case IADDW:
+ r = Oadd;
+ arithw:
+ mid(i, Oldw, RA1);
+ if(i->op == IDIVW) {
+ FM3I(2, Osra, 31, RA1, RA0);
+ FM3(2, Owry, RZ, RA0, 0);
+ }
+ if(UXSRC(i->add) == SRC(AIMM) && bc(i->s.imm))
+ FM3I(2, r, i->s.imm, RA1, RA0);
+ else {
+ opwld(i, Oldw, RA0);
+ FM3(2, r, RA0, RA1, RA0);
+ }
+ opwst(i, Ostw, RA0);
+ break;
+ case IORB:
+ r = Oor;
+ goto arithb;
+ case IANDB:
+ r = Oand;
+ goto arithb;
+ case IXORB:
+ r = Oxor;
+ goto arithb;
+ case ISUBB:
+ r = Osub;
+ goto arithb;
+ case IMULB:
+ r = Omul;
+ goto arithb;
+ case IDIVB:
+ FM3(2, Owry, RZ, RZ, 0);
+ r = Osdiv;
+ goto arithb;
+ case IADDB:
+ r = Oadd;
+ arithb:
+ mid(i, Oldbu, RA1);
+ opwld(i, Oldbu, RA0);
+ FM3(2, r, RA0, RA1, RA0);
+ opwst(i, Ostb, RA0);
+ break;
+ case ISHRB:
+ r = Osra;
+ goto shiftb;
+ case ISHLB:
+ r = Osll;
+ shiftb:
+ mid(i, Oldbu, RA1);
+ if(UXSRC(i->add) == SRC(AIMM) && bc(i->s.imm))
+ FM3I(2, r, i->s.imm, RA1, RA0);
+ else {
+ opwld(i, Oldw, RA0);
+ FM3(2, r, RA0, RA1, RA0);
+ }
+ opwst(i, Ostb, RA0);
+ break;
+ case IINDL:
+ case IINDF:
+ case IINDW:
+ case IINDB:
+ opwld(i, Oldw, RA0); /* a */
+ r = 0;
+ switch(i->op) {
+ case IINDL:
+ case IINDF:
+ r = 3;
+ break;
+ case IINDW:
+ r = 2;
+ break;
+ }
+ if(UXDST(i->add) == DST(AIMM) && bc(i->d.imm<<r)) {
+ mem(Oldw, O(Array, data), RA0, RA0);
+ FM3I(2, Oadd, (i->d.imm<<r), RA0, RA0);
+ }
+ else {
+ opwst(i, Oldw, RA1);
+ mem(Oldw, O(Array, data), RA0, RA0);
+ if(r != 0)
+ FM3I(2, Osll, r, RA1, RA1);
+ FM3(2, Oadd, RA0, RA1, RA0);
+ }
+ r = RMP;
+ if((i->add&ARM) == AXINF)
+ r = RFP;
+ mem(Ostw, i->reg, r, RA0);
+ break;
+ case IINDX:
+ opwld(i, Oldw, RA0); /* a */
+ /*
+ r = 0;
+ if(UXDST(i->add) == DST(AIMM) && bc(i->d.imm<<r))
+ r = i->d.imm<<r;
+ else
+ */
+ opwst(i, Oldw, RA1); /* i */
+ mem(Oldw, O(Array, t), RA0, RA2);
+ mem(Oldw, O(Array, data), RA0, RA0);
+ mem(Oldw, O(Type, size), RA2, RA2);
+ /*
+ if(r != 0)
+ FM3I(2, Oumul, r, RA2, RA1);
+ else
+ */
+ FM3(2, Oumul, RA1, RA2, RA1);
+ FM3(2, Oadd, RA0, RA1, RA0);
+ r = RMP;
+ if((i->add&ARM) == AXINF)
+ r = RFP;
+ mem(Ostw, i->reg, r, RA0);
+ break;
+ case IADDL:
+ larith(i, Oaddcc, Oaddx);
+ break;
+ case ISUBL:
+ larith(i, Osubcc, Osubx);
+ break;
+ case IORL:
+ larith(i, Oor, Oor);
+ break;
+ case IANDL:
+ larith(i, Oand, Oand);
+ break;
+ case IXORL:
+ larith(i, Oxor, Oxor);
+ break;
+ case ICVTWL:
+ opwld(i, Oldw, RA1);
+ FM3I(2, Osra, 31, RA1, RA0);
+ opflst(i, Ostw, RA0);
+ break;
+ case ICVTLW:
+ opwld(i, Olea, RA0);
+ mem(Oldw, 4, RA0, RA0);
+ opwst(i, Ostw, RA0);
+ break;
+ case IBEQL:
+ cbral(i, Obne, Obe, ANDAND);
+ break;
+ case IBNEL:
+ cbral(i, Obne, Obne, OROR);
+ break;
+ case IBLEL:
+ cbral(i, Obl, Obleu, EQAND);
+ break;
+ case IBGTL:
+ cbral(i, Obg, Obgu, EQAND);
+ break;
+ case IBLTL:
+ cbral(i, Obl, Obcs, EQAND);
+ break;
+ case IBGEL:
+ cbral(i, Obg, Obcc, EQAND);
+ break;
+ case IMOVF:
+ opflld(i, Oldf, FA2);
+ opflst(i, Ostf, FA2);
+ break;
+ case IDIVF:
+ r = OfdivD;
+ goto arithf;
+ case IMULF:
+ r = OfmulD;
+ goto arithf;
+ case ISUBF:
+ r = OfsubD;
+ goto arithf;
+ case IADDF:
+ r = OfaddD;
+ arithf:
+ opflld(i, Oldf, FA2);
+ midfl(i, Oldf, FA4);
+ FMF1(r, FA2, FA4, FA4);
+ opflst(i, Ostf, FA4);
+ break;
+ case INEGF:
+ opflld(i, Oldf, FA2);
+ FMF1(OfnegS, FA2, 0, FA2);
+ opflst(i, Ostf, FA2);
+ break;
+ case ICVTFL:
+ // >= Sparc 8
+ // opflld(i, Oldf, FA2);
+ // FMF1(OfDtoQ, FA2, 0, FA2);
+ // opflst(i, Ostf, FA2);
+ punt(i, SRCOP|DSTOP, optab[i->op]);
+ break;
+ case ICVTLF:
+ // >= Sparc 8
+ // opflld(i, Oldf, FA2);
+ // FMF1(OfQtoD, FA2, 0, FA2);
+ // opflst(i, Ostf, FA2);
+ punt(i, SRCOP|DSTOP, optab[i->op]);
+ break;
+ case ICVTWF:
+ opwld(i, Oldf, FA2);
+ FMF1(OfWtoD, FA2, 0, FA2);
+ opflst(i, Ostf, FA2);
+ break;
+ case ICVTFW:
+ opflld(i, Oldf, FA2);
+ FMF1(OfDtoW, FA2, 0, FA2);
+ opwst(i, Ostf, FA2);
+ break;
+ case ISHLL:
+ shll(i);
+ break;
+ case ISHRL:
+ case ILSRL:
+ punt(i, SRCOP|DSTOP|THREOP, optab[i->op]);
+ break;
+ case IRAISE:
+ punt(i, SRCOP|WRTPC|NEWPC, optab[i->op]);
+ break;
+ case IMULX:
+ case IDIVX:
+ case ICVTXX:
+ case IMULX0:
+ case IDIVX0:
+ case ICVTXX0:
+ case IMULX1:
+ case IDIVX1:
+ case ICVTXX1:
+ case ICVTFX:
+ case ICVTXF:
+ case IEXPW:
+ case IEXPL:
+ case IEXPF:
+ punt(i, SRCOP|DSTOP|THREOP, optab[i->op]);
+ break;
+ case ISELF:
+ punt(i, DSTOP, optab[i->op]);
+ break;
+ }
+}
+
+static void
+preamble(void)
+{
+ ulong *start;
+
+ if(comvec)
+ return;
+
+ comvec = malloc(10 * sizeof(*code));
+ if(comvec == nil)
+ error(exNomem);
+ code = (ulong*)comvec;
+ start = code;
+
+ con((ulong)&R, RREG, 1);
+ mem(Ostw, O(REG, xpc), RREG, RLINK);
+ mem(Oldw, O(REG, PC), RREG, RA0);
+ mem(Oldw, O(REG, FP), RREG, RFP);
+ FM3I(2, Ojmpl, 0, RA0, RZ);
+ mem(Oldw, O(REG, MP), RREG, RMP);
+
+ segflush(comvec, 10 * sizeof(*code));
+
+ if(cflag > 4) {
+ print("comvec:\n");
+ das(start, code-start);
+ }
+}
+
+static void
+maccase(void)
+{
+ ulong *loop, *def, *lab1;
+
+ mem(Oldw, 0, RCON, RA3); // n = t[0]
+ FM3I(2, Oadd, 4, RCON, RCON);
+ MOV(RA3, RA1);
+ FM3I(2, Osll, 1, RA1, RA1);
+ FM3(2, Oadd, RA3, RA1, RA1);
+ FM3I(2, Osll, 2, RA1, RA1);
+ FM3(3, Oldw, RCON, RA1, RLINK);
+
+ loop = code;
+ FM3(2, Ocmp, RZ, RA3, RZ);
+ def = code;
+ BRA(Oble, 0);
+ NOOP;
+
+ MOV(RA3, RA2); // MOVL DX, CX n2 = n
+ FM3I(2, Osra, 1, RA2, RA2); // SHR CX,1 n2 = n2>>1
+ MOV(RA2, RA1);
+ FM3I(2, Osll, 1, RA1, RA1);
+ FM3(2, Oadd, RA2, RA1, RA1);
+ FM3I(2, Osll, 2, RA1, RA1);
+
+ FM3(3, Oldw, RA1, RCON, RTA); // MOV (RA1+RCON), RTA
+ FM3(2, Ocmp, RTA, RA0, RZ);
+ lab1 = code;
+ BRA(Obge, 0);
+ NOOP;
+ MOV(RA2, RA3); // n = n2
+ BRA(Oba, loop-code);
+ NOOP;
+
+ PATCH(lab1);
+ FM3I(2, Oadd, 4, RA1, RTA);
+ FM3(3, Oldw, RTA, RCON, RTA); // MOV (RA1+RCON), RTA
+ FM3(2, Ocmp, RTA, RA0, RZ);
+ lab1 = code;
+ BRA(Obl, 0);
+ NOOP;
+
+ FM3I(2, Oadd, 12, RA1, RTA);
+ FM3(2, Oadd, RTA, RCON, RCON);
+ FM3(2, Osub, RA2, RA3, RA3); // SUBL CX, DX n -= n2
+ FM3I(2, Oadd, -1, RA3, RA3); // DECL DX n -= 1
+ BRA(Oba, loop-code);
+ NOOP;
+
+ PATCH(lab1);
+ FM3I(2, Oadd, 8, RA1, RTA);
+ FM3(3, Oldw, RTA, RCON, RLINK);
+
+ PATCH(def);
+ FM3I(2, Ojmpl, 0, RLINK, RZ);
+ NOOP;
+}
+
+static void
+macfrp(void)
+{
+ ulong *lab1, *lab2;
+
+ /* destroy the pointer in RA0 */
+ FM3I(2, Ocmp, -1, RA0, RZ);
+ lab1 = code;
+ BRA(Obe, 0);
+ NOOP;
+ mem(Oldw, O(Heap, ref)-sizeof(Heap), RA0, RA2);
+ FM3I(2, Oadd, -1, RA2, RA2);
+ FM3I(2, Ocmp, 0, RA2, RZ);
+ lab2 = code;
+ BRA(Obne, 0);
+ NOOP;
+ mem(Ostw, O(REG, FP), RREG, RFP);
+ mem(Ostw, O(REG, st), RREG, RLINK);
+ CALL(rdestroy);
+ mem(Ostw, O(REG, s), RREG, RA0);
+ con((ulong)&R, RREG, 1);
+ mem(Oldw, O(REG, st), RREG, RLINK);
+ mem(Oldw, O(REG, FP), RREG, RFP);
+ RETURN;
+ mem(Oldw, O(REG, MP), RREG, RMP);
+ PATCH(lab2);
+ mem(Ostw, O(Heap, ref)-sizeof(Heap), RA0, RA2);
+ PATCH(lab1);
+ RETURN;
+ NOOP;
+}
+
+static void
+macret(void)
+{
+ Inst i;
+ ulong *cp1, *cp2, *cp3, *cp4, *cp5, *cp6;
+
+ FM3I(2, Ocmp, 0, RA1, RZ);
+ cp1 = code;
+ BRA(Obe, 0); // t(Rfp) == 0
+ NOOP;
+
+ mem(Oldw, O(Type,destroy),RA1, RA0);
+ FM3I(2, Ocmp, 0, RA0, RZ);
+ cp2 = code;
+ BRA(Obe, 0); // destroy(t(fp)) == 0
+ NOOP;
+
+ mem(Oldw, O(Frame,fp),RFP, RA2);
+ FM3I(2, Ocmp, 0, RA2, RZ);
+ cp3 = code;
+ BRA(Obe, 0); // fp(Rfp) == 0
+ NOOP;
+
+ mem(Oldw, O(Frame,mr),RFP, RA3);
+ FM3I(2, Ocmp, 0, RA3, RZ);
+ cp4 = code;
+ BRA(Obe, 0); // mr(Rfp) == 0
+ NOOP;
+
+ mem(Oldw, O(REG,M),RREG, RA2);
+ mem(Oldw, O(Heap,ref)-sizeof(Heap),RA2, RA3);
+ FM3I(2, Oaddcc, -1, RA3, RA3);
+ cp5 = code;
+ BRA(Obe, 0); // --ref(arg) == 0
+ NOOP;
+ mem(Ostw, O(Heap,ref)-sizeof(Heap),RA2, RA3);
+
+ mem(Oldw, O(Frame,mr),RFP, RA1);
+ mem(Ostw, O(REG,M),RREG, RA1);
+ mem(Oldw, O(Modlink,compiled),RA1, RA2); // check for uncompiled code
+ mem(Oldw, O(Modlink,MP),RA1, RMP);
+ FM3I(2, Ocmp, 0, RA2, RZ);
+ cp6 = code;
+ BRA(Obe, 0);
+ NOOP;
+ mem(Ostw, O(REG,MP),RREG, RMP);
+
+ PATCH(cp4);
+ FM3I(2, Ojmpl, 0, RA0, RLINK); // call destroy(t(fp))
+ NOOP;
+ mem(Ostw, O(REG,SP),RREG, RFP);
+ mem(Oldw, O(Frame,lr),RFP, RA1);
+ mem(Oldw, O(Frame,fp),RFP, RFP);
+ mem(Ostw, O(REG,FP),RREG, RFP);
+ FM3I(2, Ojmpl, 0, RA1, RZ); // goto lr(Rfp)
+ NOOP;
+
+ PATCH(cp6);
+ FM3I(2, Ojmpl, 0, RA0, RLINK); // call destroy(t(fp))
+ NOOP;
+ mem(Ostw, O(REG,SP),RREG, RFP);
+ mem(Oldw, O(Frame,lr),RFP, RA1);
+ mem(Oldw, O(Frame,fp),RFP, RFP);
+ mem(Ostw, O(REG,FP),RREG, RFP);
+ mem(Oldw, O(REG,xpc),RREG, RA2);
+ FM3I(2, Oadd, 0x8, RA2, RA2);
+ FM3I(2, Ojmpl, 0, RA2, RZ); // return to uncompiled code
+ mem(Ostw, O(REG,PC),RREG, RA1);
+
+ PATCH(cp1);
+ PATCH(cp2);
+ PATCH(cp3);
+ PATCH(cp5);
+ i.add = AXNON;
+ punt(&i, TCHECK|NEWPC, optab[IRET]);
+}
+
+static void
+maccolr(void)
+{
+ ulong *br;
+
+ /* color the pointer in RA1 */
+ FM3I(2, Oadd, 1, RA0, RA0);
+ mem(Ostw, O(Heap, ref)-sizeof(Heap), RA1, RA0);
+ mem(Oldw, O(Heap, color)-sizeof(Heap), RA1, RA0);
+ mem(Oldw, 0, RA2, RA2);
+ FM3(2, Ocmp, RA0, RA2, RZ);
+ br = code;
+ BRA(Obe, 0);
+ con(propagator, RA2, 1);
+ mem(Ostw, O(Heap, color)-sizeof(Heap), RA1, RA2);
+ con((ulong)&nprop, RA2, 1);
+ RETURN;
+ mem(Ostw, 0, RA2, RA2);
+ PATCH(br);
+ RETURN;
+ NOOP;
+}
+
+static void
+macmcal(void)
+{
+ ulong *lab1, *lab2;
+
+ mem(Oldw, O(Modlink, prog), RA3, RA1);
+ FM3I(2, Ocmp, 0, RA1, RZ);
+ lab1 = code;
+ BRA(Obne, 0);
+ NOOP;
+
+ mem(Ostw, O(REG, st), RREG, RLINK);
+ mem(Ostw, O(REG, FP), RREG, RA2);
+ CALL(rmcall); // CALL rmcall
+ mem(Ostw, O(REG, dt), RREG, RA0);
+
+ con((ulong)&R, RREG, 1); // MOVL $R, RREG
+ mem(Oldw, O(REG, st), RREG, RLINK);
+ mem(Oldw, O(REG, FP), RREG, RFP);
+ mem(Oldw, O(REG, MP), RREG, RMP);
+ RETURN;
+ NOOP;
+
+ PATCH(lab1); // patch:
+ FM3(2, Oor, RA2, RZ, RFP);
+ mem(Ostw, O(REG, M), RREG, RA3); // MOVL RA3, R.M
+ mem(Oldw, O(Heap, ref)-sizeof(Heap), RA3, RA1);
+ FM3I(2, Oadd, 1, RA1, RA1);
+ mem(Ostw, O(Heap, ref)-sizeof(Heap), RA3, RA1);
+ mem(Oldw, O(Modlink, compiled), RA3, RA1);
+ mem(Oldw, O(Modlink, MP), RA3, RMP); // MOVL R.M->MP, RMP
+ FM3I(2, Ocmp, 0, RA1, RZ);
+ lab2 = code;
+ BRA(Obe, 0);
+ mem(Ostw, O(REG, MP), RREG, RMP); // MOVL RA3, R.MP R.MP = ml->MP
+
+ FM3I(2, Ojmpl, 0, RA0, RZ);
+ NOOP;
+
+ PATCH(lab2);
+ mem(Ostw, O(REG,FP),RREG, RFP);
+ mem(Oldw, O(REG,xpc),RREG, RA1);
+ FM3I(2, Oadd, 0x8, RA1, RA1);
+ FM3I(2, Ojmpl, 0, RA1, RZ); // call to uncompiled code
+ mem(Ostw, O(REG,PC),RREG, RA0);
+}
+
+static void
+macfram(void)
+{
+ ulong *lab1;
+
+ mem(Oldw, O(REG, SP), RREG, RA0); // MOVL R.SP, RA0
+ mem(Oldw, O(Type, size), RA3, RA1);
+ FM3(2, Oadd, RA0, RA1, RA0);
+ mem(Oldw, O(REG, TS), RREG, RA1);
+ FM3(2, Ocmp, RA1, RA0, RZ);
+ lab1 = code;
+ BRA(Obl, 0);
+ NOOP;
+
+ mem(Ostw, O(REG, s), RREG, RA3);
+ mem(Ostw, O(REG, st), RREG, RLINK);
+ CALL(extend); // CALL extend
+ mem(Ostw, O(REG, FP), RREG, RFP); // MOVL RFP, R.FP
+
+ con((ulong)&R, RREG, 1);
+ mem(Oldw, O(REG, st), RREG, RLINK);
+ mem(Oldw, O(REG, FP), RREG, RFP); // MOVL R.MP, RMP
+ mem(Oldw, O(REG, s), RREG, RA2); // MOVL R.s, *R.d
+ mem(Oldw, O(REG, MP), RREG, RMP); // MOVL R.MP, RMP
+ RETURN; // RET
+ NOOP;
+
+ PATCH(lab1);
+ mem(Oldw, O(REG, SP), RREG, RA2); // MOVL R.SP, RA2
+ mem(Ostw, O(REG, SP), RREG, RA0); // MOVL RA0, R.SP
+
+ mem(Ostw, O(Frame, t), RA2, RA3); // MOVL RA3, t(RA2) f->t = t
+ mem(Oldw, O(Type, initialize), RA3, RA3);
+ FM3I(2, Ojmpl, 0, RA3, RZ);
+ mem(Ostw, REGMOD*4, RA2, RZ); // MOVL $0, mr(RA2) f->mr
+}
+
+static void
+macmfra(void)
+{
+ mem(Ostw, O(REG, st), RREG, RLINK);
+ mem(Ostw, O(REG, s), RREG, RA3); // Save type
+ mem(Ostw, O(REG, d), RREG, RA0); // Save destination
+ CALL(rmfram); // CALL rmfram
+ mem(Ostw, O(REG, FP), RREG, RFP);
+
+ con((ulong)&R, RREG, 1);
+ mem(Oldw, O(REG, st), RREG, RLINK);
+ mem(Oldw, O(REG, FP), RREG, RFP);
+ mem(Oldw, O(REG, MP), RREG, RMP);
+ RETURN;
+ NOOP;
+}
+
+void
+comd(Type *t)
+{
+ int i, j, m, c;
+
+ mem(Ostw, O(REG, dt), RREG, RLINK);
+ for(i = 0; i < t->np; i++) {
+ c = t->map[i];
+ j = i<<5;
+ for(m = 0x80; m != 0; m >>= 1) {
+ if(c & m) {
+ CALL(base+macro[MacFRP]);
+ mem(Oldw, j, RFP, RA0);
+ }
+ j += sizeof(WORD*);
+ }
+ }
+ mem(Oldw, O(REG, dt), RREG, RLINK);
+ RETURN;
+ NOOP;
+}
+
+void
+comi(Type *t)
+{
+ int i, j, m, c;
+
+ con((ulong)H, RA0, 1);
+ for(i = 0; i < t->np; i++) {
+ c = t->map[i];
+ j = i<<5;
+ for(m = 0x80; m != 0; m >>= 1) {
+ if(c & m)
+ mem(Ostw, j, RA2, RA0);
+ j += sizeof(WORD*);
+ }
+ }
+ RETURN;
+ NOOP;
+}
+
+void
+typecom(Type *t)
+{
+ int n;
+ ulong *tmp, *start;
+
+ if(t == nil || t->initialize != 0)
+ return;
+
+ tmp = mallocz(4096*sizeof(ulong), 0);
+ if(tmp == nil)
+ error(exNomem);
+
+ code = tmp;
+ comi(t);
+ n = code - tmp;
+ code = tmp;
+ comd(t);
+ n += code - tmp;
+ free(tmp);
+
+ n *= sizeof(*code);
+ code = mallocz(n, 0);
+ if(code == nil)
+ return;
+
+ start = code;
+ t->initialize = code;
+ comi(t);
+ t->destroy = code;
+ comd(t);
+
+ segflush(start, n);
+
+ if(cflag > 1)
+ print("typ= %.8p %4d i %.8p d %.8p asm=%d\n",
+ t, t->size, t->initialize, t->destroy, n);
+}
+
+static void
+patchex(Module *m, ulong *p)
+{
+ Handler *h;
+ Except *e;
+
+ if((h = m->htab) == nil)
+ return;
+ for( ; h->etab != nil; h++){
+ h->pc1 = p[h->pc1];
+ h->pc2 = p[h->pc2];
+ for(e = h->etab; e->s != nil; e++)
+ e->pc = p[e->pc];
+ if(e->pc != -1)
+ e->pc = p[e->pc];
+ }
+}
+
+int
+compile(Module *m, int size, Modlink *ml)
+{
+ Link *l;
+ Modl *e;
+ int i, n;
+ ulong *s, *tmp;
+
+ base = nil;
+ patch = mallocz(size*sizeof(*patch), 0);
+ tinit = malloc(m->ntype*sizeof(*tinit));
+ tmp = mallocz(1024*sizeof(ulong), 0);
+ if(tinit == nil || patch == nil || tmp == nil)
+ goto bad;
+
+ preamble();
+
+ mod = m;
+ n = 0;
+ pass = 0;
+ nlit = 0;
+
+ for(i = 0; i < size; i++) {
+ code = tmp;
+ comp(&m->prog[i]);
+ patch[i] = n;
+ n += code - tmp;
+ }
+
+ for(i = 0; i < nelem(mactab); i++) {
+ code = tmp;
+ mactab[i].gen();
+ macro[mactab[i].idx] = n;
+ n += code - tmp;
+ }
+
+ base = mallocz((n+nlit)*sizeof(*code), 0);
+ if(base == nil)
+ goto bad;
+
+ if(cflag > 1)
+ print("dis=%5d %5d sparc=%5d asm=%.8p lit=%d: %s\n",
+ size, size*sizeof(Inst), n, base, nlit, m->name);
+
+ pass++;
+ nlit = 0;
+ litpool = base+n;
+ code = base;
+
+ for(i = 0; i < size; i++) {
+ s = code;
+ comp(&m->prog[i]);
+ if(cflag > 2) {
+ print("%d %D\n", i, &m->prog[i]);
+ das(s, code-s);
+ }
+ }
+
+ for(i = 0; i < nelem(mactab); i++) {
+ s = code;
+ mactab[i].gen();
+ if(cflag > 2) {
+ print("%s:\n", mactab[i].name);
+ das(s, code-s);
+ }
+ }
+
+ if(n != (code - base))
+ error(exCphase);
+
+ for(l = m->ext; l->name; l++) {
+ l->u.pc = (Inst*)RELPC(patch[l->u.pc-m->prog]);
+ typecom(l->frame);
+ }
+ if(ml != nil) {
+ e = &ml->links[0];
+ for(i = 0; i < ml->nlinks; i++) {
+ e->u.pc = (Inst*)RELPC(patch[e->u.pc-m->prog]);
+ typecom(e->frame);
+ e++;
+ }
+ }
+ for(i = 0; i < m->ntype; i++) {
+ if(tinit[i] != 0)
+ typecom(m->type[i]);
+ }
+ patchex(m, patch);
+ m->entry = (Inst*)RELPC(patch[mod->entry-mod->prog]);
+ free(patch);
+ free(tinit);
+ free(tmp);
+ free(m->prog);
+ m->prog = (Inst*)base;
+ m->compiled = 1;
+ segflush(base, n*sizeof(*base));
+ return 1;
+bad:
+ free(patch);
+ free(tinit);
+ free(tmp);
+ free(base);
+ return 0;
+}
--- /dev/null
+++ b/libinterp/comp-spim.c
@@ -1,0 +1,2 @@
+#define HIOFFSET 4 /* byte offset of high-order word in little-endian vlongs */
+#include "comp-mips.c"
--- /dev/null
+++ b/libinterp/conv.c
@@ -1,0 +1,110 @@
+#include "lib9.h"
+#include "isa.h"
+#include "interp.h"
+#include "mathi.h"
+
+enum
+{
+ TOKI0,
+ TOKI1,
+ TOKI2,
+ TOKI3,
+ TOKSB,
+ TOKFP
+};
+#include "tab.h"
+
+typedef struct Addr Addr;
+struct Addr
+{
+ uchar mode;
+ Adr a;
+};
+
+#pragma varargck type "a" Addr*
+
+char* opnam[256];
+int iconv(Fmt*);
+int aconv(Fmt*);
+
+int
+aconv(Fmt *f)
+{
+ Addr *a;
+ char buf[64];
+
+ a = va_arg(f->args, Addr*);
+ if(a == nil)
+ return fmtstrcpy(f, "AZ");
+ switch(a->mode & AMASK) {
+ case AFP: sprint(buf, "%d(fp)", a->a.ind); break;
+ case AMP: sprint(buf, "%d(mp)", a->a.ind); break;
+ case AIMM: sprint(buf, "$%d", a->a.imm); break;
+ case AIND|AFP: sprint(buf, "%d(%d(fp))", a->a.i.s, a->a.i.f); break;
+ case AIND|AMP: sprint(buf, "%d(%d(mp))", a->a.i.s, a->a.i.f); break;
+ }
+ return fmtstrcpy(f, buf);
+}
+
+int
+Dconv(Fmt *f)
+{
+ int j;
+ Inst *i;
+ Addr s, d;
+ char buf[128];
+ static int init;
+
+ if(init == 0) {
+ for(j = 0; keywds[j].name != nil; j++)
+ opnam[keywds[j].op] = keywds[j].name;
+
+ fmtinstall('a', aconv);
+ init = 1;
+ }
+
+ i = va_arg(f->args, Inst*);
+ if(i == nil)
+ return fmtstrcpy(f, "IZ");
+
+ switch(keywds[i->op].terminal) {
+ case TOKI0:
+ sprint(buf, "%s", opnam[i->op]);
+ break;
+ case TOKI1:
+ d.a = i->d;
+ d.mode = UDST(i->add);
+ sprint(buf, "%s\t%a", opnam[i->op], &d);
+ break;
+ case TOKI3:
+ d.a = i->d;
+ d.mode = UDST(i->add);
+ s.a = i->s;
+ s.mode = USRC(i->add);
+ switch(i->add&ARM) {
+ default:
+ sprint(buf, "%s\t%a, %a", opnam[i->op], &s, &d);
+ break;
+ case AXIMM:
+ sprint(buf, "%s\t%a, $%d, %a", opnam[i->op], &s, i->reg, &d);
+ break;
+ case AXINF:
+ sprint(buf, "%s\t%a, %d(fp), %a", opnam[i->op], &s, i->reg, &d);
+ break;
+ case AXINM:
+ sprint(buf, "%s\t%a, %d(mp), %a", opnam[i->op], &s, i->reg, &d);
+ break;
+ }
+ break;
+ case TOKI2:
+ d.a = i->d;
+ d.mode = UDST(i->add);
+ s.a = i->s;
+ s.mode = USRC(i->add);
+ sprint(buf, "%s\t%a, %a", opnam[i->op], &s, &d);
+ break;
+ }
+
+ return fmtstrcpy(f, buf);
+}
+
--- /dev/null
+++ b/libinterp/crypt.c
@@ -1,0 +1,1348 @@
+#include "lib9.h"
+#include "kernel.h"
+#include <isa.h>
+#include "interp.h"
+#include "runt.h"
+#include "cryptmod.h"
+#include <mp.h>
+#include <libsec.h>
+#include "pool.h"
+#include "raise.h"
+#include "ipint.h"
+
+#define MPX(x) checkIPint((void*)(x))
+
+static Type* TDigestState;
+static Type* TAESstate;
+static Type* TDESstate;
+static Type* TIDEAstate;
+static Type* TBFstate;
+static Type* TRC4state;
+
+static Type* TSKdsa;
+static Type* TPKdsa;
+static Type* TPKsigdsa;
+static Type* TSKeg;
+static Type* TPKeg;
+static Type* TPKsigeg;
+static Type* TSKrsa;
+static Type* TPKrsa;
+static Type* TPKsigrsa;
+
+static uchar DigestStatemap[] = Crypt_DigestState_map;
+static uchar AESstatemap[] = Crypt_AESstate_map;
+static uchar DESstatemap[] = Crypt_DESstate_map;
+static uchar IDEAstatemap[] = Crypt_IDEAstate_map;
+static uchar BFstatemap[] = Crypt_BFstate_map;
+static uchar RC4statemap[] = Crypt_RC4state_map;
+
+static uchar DSAskmap[] = Crypt_SK_DSA_map;
+static uchar DSApkmap[] = Crypt_PK_DSA_map;
+static uchar DSAsigmap[] = Crypt_PKsig_DSA_map;
+static uchar EGskmap[] = Crypt_SK_Elgamal_map;
+static uchar EGpkmap[] = Crypt_PK_Elgamal_map;
+static uchar EGsigmap[] = Crypt_PKsig_Elgamal_map;
+static uchar RSAskmap[] = Crypt_SK_RSA_map;
+static uchar RSApkmap[] = Crypt_PK_RSA_map;
+static uchar RSAsigmap[] = Crypt_PKsig_RSA_map;
+
+static char exBadBsize[] = "data not multiple of block size";
+static char exBadKey[] = "bad encryption key";
+static char exBadDigest[] = "bad digest value";
+static char exBadIvec[] = "bad ivec";
+static char exBadState[] = "bad encryption state";
+
+/*
+ * these structures reveal the C state of Limbo adts in crypt.m
+ */
+
+typedef struct XDigestState XDigestState;
+typedef struct XAESstate XAESstate;
+typedef struct XDESstate XDESstate;
+typedef struct XIDEAstate XIDEAstate;
+typedef struct XBFstate XBFstate;
+typedef struct XRC4state XRC4state;
+
+/* digest state */
+struct XDigestState
+{
+ Crypt_DigestState x;
+ DigestState state;
+};
+
+/* AES state */
+struct XAESstate
+{
+ Crypt_AESstate x;
+ AESstate state;
+};
+
+/* DES state */
+struct XDESstate
+{
+ Crypt_DESstate x;
+ DESstate state;
+};
+
+/* IDEA state */
+struct XIDEAstate
+{
+ Crypt_IDEAstate x;
+ IDEAstate state;
+};
+
+/* BF state */
+struct XBFstate
+{
+ Crypt_BFstate x;
+ BFstate state;
+};
+
+/* RC4 state */
+struct XRC4state
+{
+ Crypt_RC4state x;
+ RC4state state;
+};
+
+static Crypt_PK*
+newPK(Type *t, int pick)
+{
+ Heap *h;
+ Crypt_PK *sk;
+
+ h = heap(t);
+ sk = H2D(Crypt_PK*, h);
+ sk->pick = pick;
+ return sk;
+}
+
+static Crypt_SK*
+newSK(Crypt_SK** ret, Type *t, int pick)
+{
+ Heap *h;
+ Crypt_SK *sk;
+
+ h = heap(t);
+ sk = H2D(Crypt_SK*, h);
+ sk->pick = pick;
+ if(ret != nil)
+ *ret = sk;
+ switch(pick){
+ case Crypt_PK_RSA:
+ sk->u.RSA.pk = newPK(TPKrsa, Crypt_PK_RSA);
+ break;
+ case Crypt_PK_Elgamal:
+ sk->u.Elgamal.pk = newPK(TPKeg, Crypt_PK_Elgamal);
+ break;
+ case Crypt_PK_DSA:
+ sk->u.DSA.pk = newPK(TPKdsa, Crypt_PK_DSA);
+ break;
+ default:
+ error(exType);
+ }
+ return sk;
+}
+
+static Crypt_PKsig*
+newPKsig(Type *t, int pick)
+{
+ Heap *h;
+ Crypt_PKsig *s;
+
+ h = heap(t);
+ s = H2D(Crypt_PKsig*, h);
+ s->pick = pick;
+ return s;
+}
+
+static IPints_IPint*
+ipcopymp(mpint* b)
+{
+ if(b == nil)
+ return H;
+ return newIPint(mpcopy(b));
+}
+
+/*
+ * digests
+ */
+void
+DigestState_copy(void *fp)
+{
+ F_DigestState_copy *f;
+ Heap *h;
+ XDigestState *ds, *ods;
+ void *r;
+
+ f = fp;
+ r = *f->ret;
+ *f->ret = H;
+ destroy(r);
+
+ if(f->d != H){
+ ods = checktype(f->d, TDigestState, "DigestState", 0);
+ h = heap(TDigestState);
+ ds = H2D(XDigestState*, h);
+ memmove(&ds->state, &ods->state, sizeof(ds->state));
+ *f->ret = (Crypt_DigestState*)ds;
+ }
+}
+
+static Crypt_DigestState*
+crypt_digest_x(Array *buf, int n, Array *digest, int dlen, Crypt_DigestState *state, DigestState* (*fn)(uchar*, ulong, uchar*, DigestState*))
+{
+ Heap *h;
+ XDigestState *ds;
+ uchar *cbuf, *cdigest;
+
+ if(buf != H){
+ if(n > buf->len)
+ n = buf->len;
+ cbuf = buf->data;
+ }else{
+ if(n != 0)
+ error(exInval);
+ cbuf = nil;
+ }
+
+ if(digest != H){
+ if(digest->len < dlen)
+ error(exBadDigest);
+ cdigest = digest->data;
+ } else
+ cdigest = nil;
+
+ if(state == H){
+ h = heap(TDigestState);
+ ds = H2D(XDigestState*, h);
+ memset(&ds->state, 0, sizeof(ds->state));
+ } else
+ ds = checktype(state, TDigestState, "DigestState", 1);
+
+ (*fn)(cbuf, n, cdigest, &ds->state);
+
+ return (Crypt_DigestState*)ds;
+}
+
+void
+Crypt_sha1(void *fp)
+{
+ F_Crypt_sha1 *f;
+ void *r;
+
+ f = fp;
+ r = *f->ret;
+ *f->ret = H;
+ destroy(r);
+
+ *f->ret = crypt_digest_x(f->buf, f->n, f->digest, SHA1dlen, f->state, sha1);
+}
+
+void
+Crypt_sha224(void *fp)
+{
+ F_Crypt_sha224 *f;
+ void *r;
+
+ f = fp;
+ r = *f->ret;
+ *f->ret = H;
+ destroy(r);
+
+ *f->ret = crypt_digest_x(f->buf, f->n, f->digest, SHA224dlen, f->state, sha224);
+}
+
+void
+Crypt_sha256(void *fp)
+{
+ F_Crypt_sha256 *f;
+ void *r;
+
+ f = fp;
+ r = *f->ret;
+ *f->ret = H;
+ destroy(r);
+
+ *f->ret = crypt_digest_x(f->buf, f->n, f->digest, SHA256dlen, f->state, sha256);
+}
+
+void
+Crypt_sha384(void *fp)
+{
+ F_Crypt_sha384 *f;
+ void *r;
+
+ f = fp;
+ r = *f->ret;
+ *f->ret = H;
+ destroy(r);
+
+ *f->ret = crypt_digest_x(f->buf, f->n, f->digest, SHA384dlen, f->state, sha384);
+}
+
+void
+Crypt_sha512(void *fp)
+{
+ F_Crypt_sha512 *f;
+ void *r;
+
+ f = fp;
+ r = *f->ret;
+ *f->ret = H;
+ destroy(r);
+
+ *f->ret = crypt_digest_x(f->buf, f->n, f->digest, SHA512dlen, f->state, sha512);
+}
+
+void
+Crypt_md5(void *fp)
+{
+ F_Crypt_md5 *f;
+ void *r;
+
+ f = fp;
+ r = *f->ret;
+ *f->ret = H;
+ destroy(r);
+
+ *f->ret = crypt_digest_x(f->buf, f->n, f->digest, MD5dlen, f->state, md5);
+}
+
+void
+Crypt_md4(void *fp)
+{
+ F_Crypt_md4 *f;
+ void *r;
+
+ f = fp;
+ r = *f->ret;
+ *f->ret = H;
+ destroy(r);
+
+ *f->ret = crypt_digest_x(f->buf, f->n, f->digest, MD4dlen, f->state, md4);
+}
+
+static Crypt_DigestState*
+crypt_hmac_x(Array *data, int n, Array *key, Array *digest, int dlen, Crypt_DigestState *state, DigestState* (*fn)(uchar*, ulong, uchar*, ulong, uchar*, DigestState*))
+{
+ Heap *h;
+ XDigestState *ds;
+ uchar *cdata, *cdigest;
+
+ if(data != H){
+ if(n > data->len)
+ n = data->len;
+ cdata = data->data;
+ }else{
+ if(n != 0)
+ error(exInval);
+ cdata = nil;
+ }
+
+ if(key == H || key->len > 64)
+ error(exBadKey);
+
+ if(digest != H){
+ if(digest->len < dlen)
+ error(exBadDigest);
+ cdigest = digest->data;
+ } else
+ cdigest = nil;
+
+ if(state == H){
+ h = heap(TDigestState);
+ ds = H2D(XDigestState*, h);
+ memset(&ds->state, 0, sizeof(ds->state));
+ } else
+ ds = checktype(state, TDigestState, "DigestState", 1);
+
+ (*fn)(cdata, n, key->data, key->len, cdigest, &ds->state);
+
+ return (Crypt_DigestState*)ds;
+}
+
+void
+Crypt_hmac_sha1(void *fp)
+{
+ F_Crypt_hmac_sha1 *f;
+ void *r;
+
+ f = fp;
+ r = *f->ret;
+ *f->ret = H;
+ destroy(r);
+ *f->ret = crypt_hmac_x(f->data, f->n, f->key, f->digest, SHA1dlen, f->state, hmac_sha1);
+}
+
+void
+Crypt_hmac_md5(void *fp)
+{
+ F_Crypt_hmac_md5 *f;
+ void *r;
+
+ f = fp;
+ r = *f->ret;
+ *f->ret = H;
+ destroy(r);
+ *f->ret = crypt_hmac_x(f->data, f->n, f->key, f->digest, MD5dlen, f->state, hmac_md5);
+}
+
+void
+Crypt_dhparams(void *fp)
+{
+ F_Crypt_dhparams *f;
+ mpint *p, *alpha;
+ void *v;
+
+ f = fp;
+ v = f->ret->t0;
+ f->ret->t0 = H;
+ destroy(v);
+ v = f->ret->t1;
+ f->ret->t1 = H;
+ destroy(v);
+
+ p = mpnew(0);
+ alpha = mpnew(0);
+ release();
+ if(f->nbits == 1024)
+ DSAprimes(alpha, p, nil);
+ else
+ gensafeprime(p, alpha, f->nbits, 0);
+ acquire();
+ f->ret->t0 = newIPint(alpha);
+ f->ret->t1 = newIPint(p);
+}
+
+void
+cryptmodinit(void)
+{
+ ipintsmodinit(); /* TIPint */
+
+ TDigestState = dtype(freeheap, sizeof(XDigestState), DigestStatemap, sizeof(DigestStatemap));
+ TAESstate = dtype(freeheap, sizeof(XAESstate), AESstatemap, sizeof(AESstatemap));
+ TDESstate = dtype(freeheap, sizeof(XDESstate), DESstatemap, sizeof(DESstatemap));
+ TIDEAstate = dtype(freeheap, sizeof(XIDEAstate), IDEAstatemap, sizeof(IDEAstatemap));
+ TBFstate = dtype(freeheap, sizeof(XBFstate), BFstatemap, sizeof(BFstatemap));
+ TRC4state = dtype(freeheap, sizeof(XRC4state), RC4statemap, sizeof(RC4statemap));
+
+ TSKdsa = dtype(freeheap, Crypt_SK_DSA_size, DSAskmap, sizeof(DSAskmap));
+ TPKdsa = dtype(freeheap, Crypt_PK_DSA_size, DSApkmap, sizeof(DSApkmap));
+ TPKsigdsa = dtype(freeheap, Crypt_PKsig_DSA_size, DSAsigmap, sizeof(DSAsigmap));
+ TSKeg = dtype(freeheap, Crypt_SK_Elgamal_size, EGskmap, sizeof(EGskmap));
+ TPKeg = dtype(freeheap, Crypt_PK_Elgamal_size, EGpkmap, sizeof(EGpkmap));
+ TPKsigeg = dtype(freeheap, Crypt_PKsig_Elgamal_size, EGsigmap, sizeof(EGsigmap));
+ TSKrsa = dtype(freeheap, Crypt_SK_RSA_size, RSAskmap, sizeof(RSAskmap));
+ TPKrsa = dtype(freeheap, Crypt_PK_RSA_size, RSApkmap, sizeof(RSApkmap));
+ TPKsigrsa = dtype(freeheap, Crypt_PKsig_RSA_size, RSAsigmap, sizeof(RSAsigmap));
+
+ builtinmod("$Crypt", Cryptmodtab, Cryptmodlen);
+}
+
+void
+Crypt_dessetup(void *fp)
+{
+ F_Crypt_dessetup *f;
+ Heap *h;
+ XDESstate *ds;
+ uchar *ivec;
+ void *v;
+
+ f = fp;
+ v = *f->ret;
+ *f->ret = H;
+ destroy(v);
+
+ if(f->key == H)
+ error(exNilref);
+ if(f->key->len < 8)
+ error(exBadKey);
+ if(f->ivec != H){
+ if(f->ivec->len < 8)
+ error(exBadIvec);
+ ivec = f->ivec->data;
+ }else
+ ivec = nil;
+
+ h = heap(TDESstate);
+ ds = H2D(XDESstate*, h);
+ setupDESstate(&ds->state, f->key->data, ivec);
+
+ *f->ret = (Crypt_DESstate*)ds;
+}
+
+void
+Crypt_desecb(void *fp)
+{
+ F_Crypt_desecb *f;
+ XDESstate *ds;
+ int i;
+ uchar *p;
+
+ f = fp;
+
+ if(f->buf == H)
+ return;
+ if(f->n < 0 || f->n > f->buf->len)
+ error(exBounds);
+ if(f->n & 7)
+ error(exBadBsize);
+
+ ds = checktype(f->state, TDESstate, exBadState, 0);
+ p = f->buf->data;
+
+ for(i = 8; i <= f->n; i += 8, p += 8)
+ block_cipher(ds->state.expanded, p, f->direction);
+}
+
+void
+Crypt_descbc(void *fp)
+{
+ F_Crypt_descbc *f;
+ XDESstate *ds;
+ uchar *p, *ep, *ip, *p2, *eip;
+ uchar tmp[8];
+
+ f = fp;
+
+ if(f->buf == H)
+ return;
+ if(f->n < 0 || f->n > f->buf->len)
+ error(exBounds);
+ if(f->n & 7)
+ error(exBadBsize);
+
+ ds = checktype(f->state, TDESstate, exBadState, 0);
+ p = f->buf->data;
+
+ if(f->direction == 0){
+ for(ep = p + f->n; p < ep; p += 8){
+ p2 = p;
+ ip = ds->state.ivec;
+ for(eip = ip+8; ip < eip; )
+ *p2++ ^= *ip++;
+ block_cipher(ds->state.expanded, p, 0);
+ memmove(ds->state.ivec, p, 8);
+ }
+ } else {
+ for(ep = p + f->n; p < ep; ){
+ memmove(tmp, p, 8);
+ block_cipher(ds->state.expanded, p, 1);
+ p2 = tmp;
+ ip = ds->state.ivec;
+ for(eip = ip+8; ip < eip; ){
+ *p++ ^= *ip;
+ *ip++ = *p2++;
+ }
+ }
+ }
+}
+
+void
+Crypt_ideasetup(void *fp)
+{
+ F_Crypt_ideasetup *f;
+ Heap *h;
+ XIDEAstate *is;
+ uchar *ivec;
+ void *v;
+
+ f = fp;
+ v = *f->ret;
+ *f->ret = H;
+ destroy(v);
+
+ if(f->key == H)
+ error(exNilref);
+ if(f->key->len < 16)
+ error(exBadKey);
+ if(f->ivec != H){
+ if(f->ivec->len < 8)
+ error(exBadIvec);
+ ivec = f->ivec->data;
+ }else
+ ivec = nil;
+
+ h = heap(TIDEAstate);
+ is = H2D(XIDEAstate*, h);
+
+ setupIDEAstate(&is->state, f->key->data, ivec);
+
+ *f->ret = (Crypt_IDEAstate*)is;
+}
+
+void
+Crypt_ideaecb(void *fp)
+{
+ F_Crypt_ideaecb *f;
+ XIDEAstate *is;
+ int i;
+ uchar *p;
+
+ f = fp;
+
+ if(f->buf == H)
+ return;
+ if(f->n < 0 || f->n > f->buf->len)
+ error(exBounds);
+ if(f->n & 7)
+ error(exBadBsize);
+
+ is = checktype(f->state, TIDEAstate, exBadState, 0);
+ p = f->buf->data;
+
+ for(i = 8; i <= f->n; i += 8, p += 8)
+ idea_cipher(is->state.edkey, p, f->direction);
+}
+
+void
+Crypt_ideacbc(void *fp)
+{
+ F_Crypt_ideacbc *f;
+ XIDEAstate *is;
+ uchar *p, *ep, *ip, *p2, *eip;
+ uchar tmp[8];
+
+ f = fp;
+
+ if(f->buf == H)
+ return;
+ if(f->n < 0 || f->n > f->buf->len)
+ error(exBounds);
+ if(f->n & 7)
+ error(exBadBsize);
+
+ is = checktype(f->state, TIDEAstate, exBadState, 0);
+ p = f->buf->data;
+
+ if(f->direction == 0){
+ for(ep = p + f->n; p < ep; p += 8){
+ p2 = p;
+ ip = is->state.ivec;
+ for(eip = ip+8; ip < eip; )
+ *p2++ ^= *ip++;
+ idea_cipher(is->state.edkey, p, 0);
+ memmove(is->state.ivec, p, 8);
+ }
+ } else {
+ for(ep = p + f->n; p < ep; ){
+ memmove(tmp, p, 8);
+ idea_cipher(is->state.edkey, p, 1);
+ p2 = tmp;
+ ip = is->state.ivec;
+ for(eip = ip+8; ip < eip; ){
+ *p++ ^= *ip;
+ *ip++ = *p2++;
+ }
+ }
+ }
+}
+
+void
+Crypt_aessetup(void *fp)
+{
+ F_Crypt_aessetup *f;
+ Heap *h;
+ XAESstate *is;
+ uchar *ivec;
+ void *v;
+
+ f = fp;
+ v = *f->ret;
+ *f->ret = H;
+ destroy(v);
+
+ if(f->key == H)
+ error(exNilref);
+ if(f->key->len != 16 && f->key->len != 24 && f->key->len != 32)
+ error(exBadKey);
+ if(f->ivec != H){
+ if(f->ivec->len < AESbsize)
+ error(exBadIvec);
+ ivec = f->ivec->data;
+ }else
+ ivec = nil;
+
+ h = heap(TAESstate);
+ is = H2D(XAESstate*, h);
+
+ setupAESstate(&is->state, f->key->data, f->key->len, ivec);
+
+ *f->ret = (Crypt_AESstate*)is;
+}
+
+void
+Crypt_aescbc(void *fp)
+{
+ F_Crypt_aescbc *f;
+ XAESstate *is;
+ uchar *p;
+
+ f = fp;
+
+ if(f->buf == H)
+ return;
+ if(f->n < 0 || f->n > f->buf->len)
+ error(exBounds);
+
+ is = checktype(f->state, TAESstate, exBadState, 0);
+ p = f->buf->data;
+
+ if(f->direction == 0)
+ aesCBCencrypt(p, f->n, &is->state);
+ else
+ aesCBCdecrypt(p, f->n, &is->state);
+}
+
+void
+Crypt_blowfishsetup(void *fp)
+{
+ F_Crypt_blowfishsetup *f;
+ Heap *h;
+ XBFstate *is;
+ uchar *ivec;
+ void *v;
+
+ f = fp;
+ v = *f->ret;
+ *f->ret = H;
+ destroy(v);
+
+ if(f->key == H)
+ error(exNilref);
+ if(f->key->len <= 0)
+ error(exBadKey);
+ if(f->ivec != H){
+ if(f->ivec->len != BFbsize)
+ error(exBadIvec);
+ ivec = f->ivec->data;
+ }else
+ ivec = nil;
+
+ h = heap(TBFstate);
+ is = H2D(XBFstate*, h);
+
+ setupBFstate(&is->state, f->key->data, f->key->len, ivec);
+
+ *f->ret = (Crypt_BFstate*)is;
+}
+
+void
+Crypt_blowfishcbc(void *fp)
+{
+ F_Crypt_blowfishcbc *f;
+ XBFstate *is;
+ uchar *p;
+
+ f = fp;
+
+ if(f->state == H)
+ return;
+ if(f->n < 0 || f->n > f->buf->len)
+ error(exBounds);
+ if(f->n & 7)
+ error(exBadBsize);
+
+ is = checktype(f->state, TBFstate, exBadState, 0);
+ p = f->buf->data;
+
+ if(f->direction == 0)
+ bfCBCencrypt(p, f->n, &is->state);
+ else
+ bfCBCdecrypt(p, f->n, &is->state);
+}
+
+void
+Crypt_rc4setup(void *fp)
+{
+ F_Crypt_rc4setup *f;
+ Heap *h;
+ XRC4state *is;
+ void *v;
+
+ f = fp;
+ v = *f->ret;
+ *f->ret = H;
+ destroy(v);
+
+ if(f->seed == H)
+ error(exNilref);
+
+ h = heap(TRC4state);
+ is = H2D(XRC4state*, h);
+
+ setupRC4state(&is->state, f->seed->data, f->seed->len);
+
+ *f->ret = (Crypt_RC4state*)is;
+}
+
+void
+Crypt_rc4(void *fp)
+{
+ F_Crypt_rc4 *f;
+ XRC4state *is;
+ uchar *p;
+
+ f = fp;
+ if(f->buf == H)
+ return;
+ if(f->n < 0 || f->n > f->buf->len)
+ error(exBounds);
+ is = checktype(f->state, TRC4state, exBadState, 0);
+ p = f->buf->data;
+ rc4(&is->state, p, f->n);
+}
+
+void
+Crypt_rc4skip(void *fp)
+{
+ F_Crypt_rc4skip *f;
+ XRC4state *is;
+
+ f = fp;
+ is = checktype(f->state, TRC4state, exBadState, 0);
+ rc4skip(&is->state, f->n);
+}
+
+void
+Crypt_rc4back(void *fp)
+{
+ F_Crypt_rc4back *f;
+ XRC4state *is;
+
+ f = fp;
+ is = checktype(f->state, TRC4state, exBadState, 0);
+ rc4back(&is->state, f->n);
+}
+
+/*
+ * public/secret keys, signing and verifying
+ */
+
+/*
+ * DSA
+ */
+
+static void
+dsapk2pub(DSApub* p, Crypt_PK* pk)
+{
+ if(pk == H)
+ error(exNilref);
+ if(pk->pick != Crypt_PK_DSA)
+ error(exType);
+ p->p = MPX(pk->u.DSA.p);
+ p->q = MPX(pk->u.DSA.q);
+ p->alpha = MPX(pk->u.DSA.alpha);
+ p->key = MPX(pk->u.DSA.key);
+}
+
+static void
+dsask2priv(DSApriv* p, Crypt_SK* sk)
+{
+ if(sk == H)
+ error(exNilref);
+ if(sk->pick != Crypt_SK_DSA)
+ error(exType);
+ dsapk2pub(&p->pub, sk->u.DSA.pk);
+ p->secret = MPX(sk->u.DSA.secret);
+}
+
+static void
+dsapriv2sk(Crypt_SK* sk, DSApriv* p)
+{
+ Crypt_PK *pk;
+
+ pk = sk->u.DSA.pk;
+ pk->u.DSA.p = ipcopymp(p->pub.p);
+ pk->u.DSA.q = ipcopymp(p->pub.q);
+ pk->u.DSA.alpha = ipcopymp(p->pub.alpha);
+ pk->u.DSA.key = ipcopymp(p->pub.key);
+ sk->u.DSA.secret = ipcopymp(p->secret);
+}
+
+static void
+dsaxgen(Crypt_SK* sk, DSApub* oldpk)
+{
+ DSApriv *p;
+
+ release();
+ p = dsagen(oldpk);
+ acquire();
+ dsapriv2sk(sk, p);
+ dsaprivfree(p);
+}
+
+void
+Crypt_dsagen(void *fp)
+{
+ F_Crypt_dsagen *f;
+ Crypt_SK *sk;
+ DSApub pub, *oldpk;
+ void *v;
+
+ f = fp;
+ v = *f->ret;
+ *f->ret = H;
+ destroy(v);
+
+ sk = newSK(f->ret, TSKdsa, Crypt_SK_DSA);
+ oldpk = nil;
+ if(f->oldpk != H && f->oldpk->pick == Crypt_PK_DSA){
+ dsapk2pub(&pub, f->oldpk);
+ oldpk = &pub;
+ }
+ dsaxgen(sk, oldpk);
+}
+
+/*
+ * Elgamal
+ */
+
+static void
+egpk2pub(EGpub* p, Crypt_PK* pk)
+{
+ if(pk == H)
+ error(exNilref);
+ if(pk->pick != Crypt_PK_Elgamal)
+ error(exType);
+ p->p = MPX(pk->u.Elgamal.p);
+ p->alpha = MPX(pk->u.Elgamal.alpha);
+ p->key = MPX(pk->u.Elgamal.key);
+}
+
+static void
+egsk2priv(EGpriv* p, Crypt_SK* sk)
+{
+ if(sk == H)
+ error(exNilref);
+ if(sk->pick != Crypt_SK_Elgamal)
+ error(exType);
+ egpk2pub(&p->pub, sk->u.Elgamal.pk);
+ p->secret = MPX(sk->u.Elgamal.secret);
+}
+
+static void
+egpriv2sk(Crypt_SK* sk, EGpriv* p)
+{
+ Crypt_PK* pk;
+
+ pk = sk->u.Elgamal.pk;
+ pk->u.Elgamal.p = ipcopymp(p->pub.p);
+ pk->u.Elgamal.alpha = ipcopymp(p->pub.alpha);
+ pk->u.Elgamal.key = ipcopymp(p->pub.key);
+ sk->u.Elgamal.secret = ipcopymp(p->secret);
+}
+
+static void
+egxgen(Crypt_SK* sk, int nlen, int nrep)
+{
+ EGpriv *p;
+
+ release();
+ for(;;){
+ p = eggen(nlen, nrep);
+ if(mpsignif(p->pub.p) == nlen)
+ break;
+ egprivfree(p);
+ }
+ acquire();
+ egpriv2sk(sk, p);
+ egprivfree(p);
+}
+
+
+void
+Crypt_eggen(void *fp)
+{
+ F_Crypt_eggen *f;
+ Crypt_SK *sk;
+ void *v;
+
+ f = fp;
+ v = *f->ret;
+ *f->ret = H;
+ destroy(v);
+
+ sk = newSK(f->ret, TSKeg, Crypt_SK_Elgamal);
+ egxgen(sk, f->nlen, f->nrep);
+}
+
+/*
+ * RSA
+ */
+
+static void
+rsapk2pub(RSApub* p, Crypt_PK* pk)
+{
+ if(pk == H)
+ error(exNilref);
+ if(pk->pick != Crypt_PK_RSA)
+ error(exType);
+ p->n = MPX(pk->u.RSA.n);
+ p->ek = MPX(pk->u.RSA.ek);
+}
+
+static void
+rsask2priv(RSApriv* p, Crypt_SK* sk)
+{
+ if(sk == H)
+ error(exNilref);
+ if(sk->pick != Crypt_SK_RSA)
+ error(exType);
+ rsapk2pub(&p->pub, sk->u.RSA.pk);
+ p->dk = MPX(sk->u.RSA.dk);
+ p->p = MPX(sk->u.RSA.p);
+ p->q = MPX(sk->u.RSA.q);
+ p->kp = MPX(sk->u.RSA.kp);
+ p->kq = MPX(sk->u.RSA.kq);
+ p->c2 = MPX(sk->u.RSA.c2);
+}
+
+static void
+rsapriv2sk(Crypt_SK* sk, RSApriv* p)
+{
+ Crypt_PK *pk;
+
+ pk = sk->u.RSA.pk;
+ pk->u.RSA.n = ipcopymp(p->pub.n);
+ pk->u.RSA.ek = ipcopymp(p->pub.ek);
+ sk->u.RSA.dk = ipcopymp(p->dk);
+ sk->u.RSA.p = ipcopymp(p->p);
+ sk->u.RSA.q = ipcopymp(p->q);
+ sk->u.RSA.kp = ipcopymp(p->kp);
+ sk->u.RSA.kq = ipcopymp(p->kq);
+ sk->u.RSA.c2 = ipcopymp(p->c2);
+}
+
+static void
+rsaxgen(Crypt_SK *sk, int nlen, int elen, int nrep)
+{
+ RSApriv *p;
+
+ release();
+ for(;;){
+ p = rsagen(nlen, elen, nrep);
+ if(mpsignif(p->pub.n) == nlen)
+ break;
+ rsaprivfree(p);
+ }
+ acquire();
+ rsapriv2sk(sk, p);
+ rsaprivfree(p);
+}
+
+void
+Crypt_rsagen(void *fp)
+{
+ F_Crypt_rsagen *f;
+ Crypt_SK *sk;
+ void *v;
+
+ f = fp;
+ v = *f->ret;
+ *f->ret = H;
+ destroy(v);
+
+ sk = newSK(f->ret, TSKrsa, Crypt_SK_RSA);
+ rsaxgen(sk, f->nlen, f->elen, f->nrep);
+}
+
+void
+Crypt_rsafill(void *fp)
+{
+ F_Crypt_rsafill *f;
+ Crypt_SK *sk;
+ RSApriv *p;
+ void *v;
+
+ f = fp;
+ v = *f->ret;
+ *f->ret = H;
+ destroy(v);
+
+ sk = newSK(f->ret, TSKrsa, Crypt_SK_RSA);
+ release();
+ p = rsafill(MPX(f->n), MPX(f->ek), MPX(f->dk),
+ MPX(f->p), MPX(f->q));
+ acquire();
+ if(p == nil) {
+ *f->ret = H;
+ destroy(sk);
+ }else{
+ rsapriv2sk(sk, p);
+ rsaprivfree(p);
+ }
+}
+
+void
+Crypt_rsaencrypt(void *fp)
+{
+ F_Crypt_rsaencrypt *f;
+ RSApub p;
+ mpint *m, *o;
+ void *v;
+
+ f = fp;
+ v = *f->ret;
+ *f->ret = H;
+ destroy(v);
+
+ rsapk2pub(&p, f->k);
+ m = MPX(f->m);
+ release();
+ o = rsaencrypt(&p, m, nil);
+ acquire();
+ *f->ret = newIPint(o);
+}
+
+void
+Crypt_rsadecrypt(void *fp)
+{
+ F_Crypt_rsadecrypt *f;
+ RSApriv p;
+ mpint *m, *o;
+ void *v;
+
+ f = fp;
+ v = *f->ret;
+ *f->ret = H;
+ destroy(v);
+
+ rsask2priv(&p, f->k);
+ m = MPX(f->m);
+ release();
+ o = rsadecrypt(&p, m, nil);
+ acquire();
+ *f->ret = newIPint(o);
+}
+
+/*
+ * generic key functions
+ */
+
+void
+Crypt_genSK(void *fp)
+{
+ F_Crypt_genSK *f;
+ Crypt_SK *sk;
+ char *sa;
+ void *v;
+
+ f = fp;
+ v = *f->ret;
+ *f->ret = H;
+ destroy(v);
+
+ sa = string2c(f->algname);
+ if(strcmp(sa, "rsa") == 0){
+ sk = newSK(f->ret, TSKrsa, Crypt_SK_RSA);
+ rsaxgen(sk, f->length, 6, 0);
+ }else if(strcmp(sa, "dsa") == 0){
+ sk = newSK(f->ret, TSKdsa, Crypt_SK_DSA);
+ dsaxgen(sk, nil);
+ }else if(strcmp(sa, "elgamal") == 0){
+ sk = newSK(f->ret, TSKeg, Crypt_SK_Elgamal);
+ egxgen(sk, f->length, 0);
+ }
+ /* genSK returns nil for unknown algorithm */
+}
+
+void
+Crypt_genSKfromPK(void *fp)
+{
+ F_Crypt_genSKfromPK *f;
+ Crypt_SK *sk;
+ void *v;
+
+ f = fp;
+ v = *f->ret;
+ *f->ret = H;
+ destroy(v);
+
+ if(f->pk == H)
+ error(exNilref);
+ switch(f->pk->pick){
+ case Crypt_PK_RSA: {
+ RSApub p;
+
+ rsapk2pub(&p, f->pk);
+ sk = newSK(f->ret, TSKrsa, Crypt_SK_RSA);
+ rsaxgen(sk, mpsignif(p.n), mpsignif(p.ek), 0);
+ }
+ break;
+ case Crypt_PK_Elgamal: {
+ EGpub p;
+
+ egpk2pub(&p, f->pk);
+ sk = newSK(f->ret, TSKeg, Crypt_SK_Elgamal);
+ egxgen(sk, mpsignif(p.p), 0);
+ }
+ break;
+ case Crypt_PK_DSA: {
+ DSApub p;
+
+ dsapk2pub(&p, f->pk);
+ sk = newSK(f->ret, TSKdsa, Crypt_SK_DSA);
+ dsaxgen(sk, &p);
+ }
+ break;
+ default:
+ /* shouldn't happen */
+ error(exType);
+ }
+}
+
+void
+Crypt_sktopk(void *fp)
+{
+ F_Crypt_sktopk *f;
+ Crypt_PK *pk;
+ void *v;
+
+ f = fp;
+ v = *f->ret;
+ *f->ret = H;
+ destroy(v);
+ if(f->sk == H)
+ error(exNilref);
+ switch(f->sk->pick){
+ case Crypt_PK_RSA:
+ pk = f->sk->u.RSA.pk;
+ break;
+ case Crypt_PK_Elgamal:
+ pk = f->sk->u.Elgamal.pk;
+ break;
+ case Crypt_PK_DSA:
+ pk = f->sk->u.DSA.pk;
+ break;
+ default:
+ pk = H;
+ error(exType);
+ }
+ if(pk == H)
+ return;
+ D2H(pk)->ref++;
+ *f->ret = pk;
+}
+
+void
+Crypt_sign(void *fp)
+{
+ F_Crypt_sign *f;
+ Crypt_PKsig *sig;
+ mpint *m;
+ void *v;
+
+ f = fp;
+ v = *f->ret;
+ *f->ret = H;
+ destroy(v);
+
+ if(f->m == H || f->sk == H)
+ error(exNilref);
+ m = MPX(f->m);
+ switch(f->sk->pick){
+ case Crypt_SK_RSA: {
+ RSApriv p;
+ mpint *s;
+
+ rsask2priv(&p, f->sk);
+ release();
+ s = rsadecrypt(&p, m, nil);
+ acquire();
+ sig = newPKsig(TPKsigrsa, Crypt_PKsig_RSA);
+ sig->u.RSA.n = newIPint(s);
+ }
+ break;
+ case Crypt_SK_Elgamal: {
+ EGpriv p;
+ EGsig *s;
+
+ egsk2priv(&p, f->sk);
+ release();
+ s = egsign(&p, m);
+ acquire();
+ sig = newPKsig(TPKsigeg, Crypt_PKsig_Elgamal);
+ sig->u.Elgamal.r = ipcopymp(s->r);
+ sig->u.Elgamal.s = ipcopymp(s->s);
+ egsigfree(s);
+ }
+ break;
+ case Crypt_SK_DSA: {
+ DSApriv p;
+ DSAsig *s;
+
+ dsask2priv(&p, f->sk);
+ m = MPX(f->m);
+ release();
+ s = dsasign(&p, m);
+ acquire();
+ sig = newPKsig(TPKsigdsa, Crypt_PKsig_DSA);
+ sig->u.DSA.r = ipcopymp(s->r);
+ sig->u.DSA.s = ipcopymp(s->s);
+ dsasigfree(s);
+ }
+ break;
+ default:
+ sig = H;
+ error(exType);
+ }
+ *f->ret = sig;
+}
+
+void
+Crypt_verify(void *fp)
+{
+ F_Crypt_verify *f;
+ mpint *m;
+
+ f = fp;
+ *f->ret = 0;
+ if(f->sig == H || f->pk == H)
+ error(exNilref);
+ if(f->sig->pick != f->pk->pick)
+ return; /* key type and signature mismatch, doesn't validate */
+ m = MPX(f->m);
+ switch(f->pk->pick){
+ case Crypt_PK_RSA: {
+ RSApub p;
+ mpint *sig, *t;
+
+ rsapk2pub(&p, f->pk);
+ sig = MPX(f->sig->u.RSA.n);
+ release();
+ t = rsaencrypt(&p, sig, nil);
+ *f->ret = mpcmp(t, m) == 0;
+ mpfree(t);
+ acquire();
+ }
+ break;
+ case Crypt_PK_Elgamal: {
+ EGpub p;
+ EGsig sig;
+
+ egpk2pub(&p, f->pk);
+ sig.r = MPX(f->sig->u.Elgamal.r);
+ sig.s = MPX(f->sig->u.Elgamal.s);
+ release();
+ *f->ret = egverify(&p, &sig, m) == 0;
+ acquire();
+ }
+ break;
+ case Crypt_PK_DSA: {
+ DSApub p;
+ DSAsig sig;
+
+ dsapk2pub(&p, f->pk);
+ sig.r = MPX(f->sig->u.DSA.r);
+ sig.s = MPX(f->sig->u.DSA.s);
+ release();
+ *f->ret = dsaverify(&p, &sig, m) == 0;
+ acquire();
+ }
+ break;
+ default:
+ error(exType);
+ }
+}
--- /dev/null
+++ b/libinterp/das-386.c
@@ -1,0 +1,1630 @@
+#include <lib9.h>
+#include <kernel.h>
+
+int i386inst(ulong, char, char*, int);
+int i386das(ulong, char*, int);
+int i386instlen(ulong);
+
+static uchar *dasdata;
+
+static char *
+_hexify(char *buf, ulong p, int zeros)
+{
+ ulong d;
+
+ d = p/16;
+ if(d)
+ buf = _hexify(buf, d, zeros-1);
+ else
+ while(zeros--)
+ *buf++ = '0';
+ *buf++ = "0123456789abcdef"[p&0x0f];
+ return buf;
+}
+
+/*
+ * an instruction
+ */
+typedef struct Instr Instr;
+struct Instr
+{
+ uchar mem[1+1+1+1+2+1+1+4+4]; /* raw instruction */
+ ulong addr; /* address of start of instruction */
+ int n; /* number of bytes in instruction */
+ char *prefix; /* instr prefix */
+ char *segment; /* segment override */
+ uchar jumptype; /* set to the operand type for jump/ret/call */
+ char osize; /* 'W' or 'L' */
+ char asize; /* address size 'W' or 'L' */
+ uchar mod; /* bits 6-7 of mod r/m field */
+ uchar reg; /* bits 3-5 of mod r/m field */
+ char ss; /* bits 6-7 of SIB */
+ char index; /* bits 3-5 of SIB */
+ char base; /* bits 0-2 of SIB */
+ short seg; /* segment of far address */
+ ulong disp; /* displacement */
+ ulong imm; /* immediate */
+ ulong imm2; /* second immediate operand */
+ char *curr; /* fill level in output buffer */
+ char *end; /* end of output buffer */
+ char *err; /* error message */
+};
+
+ /* 386 register (ha!) set */
+enum{
+ AX=0,
+ CX,
+ DX,
+ BX,
+ SP,
+ BP,
+ SI,
+ DI,
+};
+ /* Operand Format codes */
+/*
+%A - address size register modifier (!asize -> 'E')
+%C - Control register CR0/CR1/CR2
+%D - Debug register DR0/DR1/DR2/DR3/DR6/DR7
+%I - second immediate operand
+%O - Operand size register modifier (!osize -> 'E')
+%T - Test register TR6/TR7
+%S - size code ('W' or 'L')
+%X - Weird opcode: OSIZE == 'W' => "CBW"; else => "CWDE"
+%d - displacement 16-32 bits
+%e - effective address - Mod R/M value
+%f - floating point register F0-F7 - from Mod R/M register
+%g - segment register
+%i - immediate operand 8-32 bits
+%p - PC-relative - signed displacement in immediate field
+%r - Reg from Mod R/M
+%x - Weird opcode: OSIZE == 'W' => "CWD"; else => "CDQ"
+*/
+
+typedef struct Optable Optable;
+struct Optable
+{
+ char operand[2];
+ void *proto; /* actually either (char*) or (Optable*) */
+};
+ /* Operand decoding codes */
+enum {
+ Ib = 1, /* 8-bit immediate - (no sign extension)*/
+ Ibs, /* 8-bit immediate (sign extended) */
+ Jbs, /* 8-bit sign-extended immediate in jump or call */
+ Iw, /* 16-bit immediate -> imm */
+ Iw2, /* 16-bit immediate -> imm2 */
+ Iwd, /* Operand-sized immediate (no sign extension)*/
+ Awd, /* Address offset */
+ Iwds, /* Operand-sized immediate (sign extended) */
+ RM, /* Word or long R/M field with register (/r) */
+ RMB, /* Byte R/M field with register (/r) */
+ RMOP, /* Word or long R/M field with op code (/digit) */
+ RMOPB, /* Byte R/M field with op code (/digit) */
+ RMR, /* R/M register only (mod = 11) */
+ RMM, /* R/M memory only (mod = 0/1/2) */
+ R0, /* Base reg of Mod R/M is literal 0x00 */
+ R1, /* Base reg of Mod R/M is literal 0x01 */
+ FRMOP, /* Floating point R/M field with opcode */
+ FRMEX, /* Extended floating point R/M field with opcode */
+ JUMP, /* Jump or Call flag - no operand */
+ RET, /* Return flag - no operand */
+ OA, /* literal 0x0a byte */
+ PTR, /* Seg:Displacement addr (ptr16:16 or ptr16:32) */
+ AUX, /* Multi-byte op code - Auxiliary table */
+ PRE, /* Instr Prefix */
+ SEG, /* Segment Prefix */
+ OPOVER, /* Operand size override */
+ ADDOVER, /* Address size override */
+};
+
+static Optable optab0F00[8]=
+{
+ 0,0, "MOVW LDT,%e",
+ 0,0, "MOVW TR,%e",
+ 0,0, "MOVW %e,LDT",
+ 0,0, "MOVW %e,TR",
+ 0,0, "VERR %e",
+ 0,0, "VERW %e",
+};
+
+static Optable optab0F01[8]=
+{
+ 0,0, "MOVL GDTR,%e",
+ 0,0, "MOVL IDTR,%e",
+ 0,0, "MOVL %e,GDTR",
+ 0,0, "MOVL %e,IDTR",
+ 0,0, "MOVW MSW,%e", /* word */
+ 0,0, nil,
+ 0,0, "MOVW %e,MSW", /* word */
+};
+
+static Optable optab0FBA[8]=
+{
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ Ib,0, "BT%S %i,%e",
+ Ib,0, "BTS%S %i,%e",
+ Ib,0, "BTR%S %i,%e",
+ Ib,0, "BTC%S %i,%e",
+};
+
+static Optable optab0F[256]=
+{
+ RMOP,0, optab0F00,
+ RMOP,0, optab0F01,
+ RM,0, "LAR %e,%r",
+ RM,0, "LSL %e,%r",
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, "CLTS",
+ 0,0, nil,
+ 0,0, "INVD",
+ 0,0, "WBINVD",
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+
+ RMR,0, "MOVL %C,%e", /* [0x20] */
+ RMR,0, "MOVL %D,%e",
+ RMR,0, "MOVL %e,%C",
+ RMR,0, "MOVL %e,%D",
+ RMR,0, "MOVL %T,%e",
+ 0,0, nil,
+ RMR,0, "MOVL %e,%T",
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+
+ 0,0, "WRMSR", /* [0x30] */
+ 0,0, "RDTSC",
+ 0,0, "RDMSR",
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+
+ Iwds,0, "JOS %p", /* [0x80] */
+ Iwds,0, "JOC %p",
+ Iwds,0, "JCS %p",
+ Iwds,0, "JCC %p",
+ Iwds,0, "JEQ %p",
+ Iwds,0, "JNE %p",
+ Iwds,0, "JLS %p",
+ Iwds,0, "JHI %p",
+ Iwds,0, "JMI %p",
+ Iwds,0, "JPL %p",
+ Iwds,0, "JPS %p",
+ Iwds,0, "JPC %p",
+ Iwds,0, "JLT %p",
+ Iwds,0, "JGE %p",
+ Iwds,0, "JLE %p",
+ Iwds,0, "JGT %p",
+
+ RMB,0, "SETOS %e", /* [0x90] */
+ RMB,0, "SETOC %e",
+ RMB,0, "SETCS %e",
+ RMB,0, "SETCC %e",
+ RMB,0, "SETEQ %e",
+ RMB,0, "SETNE %e",
+ RMB,0, "SETLS %e",
+ RMB,0, "SETHI %e",
+ RMB,0, "SETMI %e",
+ RMB,0, "SETPL %e",
+ RMB,0, "SETPS %e",
+ RMB,0, "SETPC %e",
+ RMB,0, "SETLT %e",
+ RMB,0, "SETGE %e",
+ RMB,0, "SETLE %e",
+ RMB,0, "SETGT %e",
+
+ 0,0, "PUSHL FS", /* [0xa0] */
+ 0,0, "POPL FS",
+ 0,0, "CPUID",
+ RM,0, "BT%S %r,%e",
+ RM,Ib, "SHLD%S %r,%i,%e",
+ RM,0, "SHLD%S %r,CL,%e",
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, "PUSHL GS",
+ 0,0, "POPL GS",
+ 0,0, nil,
+ RM,0, "BTS%S %r,%e",
+ RM,Ib, "SHRD%S %r,%i,%e",
+ RM,0, "SHRD%S %r,CL,%e",
+ 0,0, nil,
+ RM,0, "IMUL%S %e,%r",
+
+ 0,0, nil,
+ 0,0, nil,
+ RMM,0, "LSS %e,%r", /* [0xb2] */
+ RM,0, "BTR%S %r,%e",
+ RMM,0, "LFS %e,%r",
+ RMM,0, "LGS %e,%r",
+ RMB,0, "MOVBZX %e,%R",
+ RM,0, "MOVWZX %e,%R",
+ 0,0, nil,
+ 0,0, nil,
+ RMOP,0, optab0FBA,
+ RM,0, "BTC%S %e,%r",
+ RM,0, "BSF%S %e,%r",
+ RM,0, "BSR%S %e,%r",
+ RMB,0, "MOVBSX %e,%R",
+ RM,0, "MOVWSX %e,%R",
+};
+
+static Optable optab80[8]=
+{
+ Ib,0, "ADDB %i,%e",
+ Ib,0, "ORB %i,%e",
+ Ib,0, "ADCB %i,%e",
+ Ib,0, "SBBB %i,%e",
+ Ib,0, "ANDB %i,%e",
+ Ib,0, "SUBB %i,%e",
+ Ib,0, "XORB %i,%e",
+ Ib,0, "CMPB %e,%i",
+};
+
+static Optable optab81[8]=
+{
+ Iwd,0, "ADD%S %i,%e",
+ Iwd,0, "OR%S %i,%e",
+ Iwd,0, "ADC%S %i,%e",
+ Iwd,0, "SBB%S %i,%e",
+ Iwd,0, "AND%S %i,%e",
+ Iwd,0, "SUB%S %i,%e",
+ Iwd,0, "XOR%S %i,%e",
+ Iwd,0, "CMP%S %e,%i",
+};
+
+static Optable optab83[8]=
+{
+ Ibs,0, "ADD%S %i,%e",
+ Ibs,0, "OR%S %i,%e",
+ Ibs,0, "ADC%S %i,%e",
+ Ibs,0, "SBB%S %i,%e",
+ Ibs,0, "AND%S %i,%e",
+ Ibs,0, "SUB%S %i,%e",
+ Ibs,0, "XOR%S %i,%e",
+ Ibs,0, "CMP%S %e,%i",
+};
+
+static Optable optabC0[8] =
+{
+ Ib,0, "ROLB %i,%e",
+ Ib,0, "RORB %i,%e",
+ Ib,0, "RCLB %i,%e",
+ Ib,0, "RCRB %i,%e",
+ Ib,0, "SHLB %i,%e",
+ Ib,0, "SHRB %i,%e",
+ 0,0, nil,
+ Ib,0, "SARB %i,%e",
+};
+
+static Optable optabC1[8] =
+{
+ Ib,0, "ROL%S %i,%e",
+ Ib,0, "ROR%S %i,%e",
+ Ib,0, "RCL%S %i,%e",
+ Ib,0, "RCR%S %i,%e",
+ Ib,0, "SHL%S %i,%e",
+ Ib,0, "SHR%S %i,%e",
+ 0,0, nil,
+ Ib,0, "SAR%S %i,%e",
+};
+
+static Optable optabD0[8] =
+{
+ 0,0, "ROLB %e",
+ 0,0, "RORB %e",
+ 0,0, "RCLB %e",
+ 0,0, "RCRB %e",
+ 0,0, "SHLB %e",
+ 0,0, "SHRB %e",
+ 0,0, nil,
+ 0,0, "SARB %e",
+};
+
+static Optable optabD1[8] =
+{
+ 0,0, "ROL%S %e",
+ 0,0, "ROR%S %e",
+ 0,0, "RCL%S %e",
+ 0,0, "RCR%S %e",
+ 0,0, "SHL%S %e",
+ 0,0, "SHR%S %e",
+ 0,0, nil,
+ 0,0, "SAR%S %e",
+};
+
+static Optable optabD2[8] =
+{
+ 0,0, "ROLB CL,%e",
+ 0,0, "RORB CL,%e",
+ 0,0, "RCLB CL,%e",
+ 0,0, "RCRB CL,%e",
+ 0,0, "SHLB CL,%e",
+ 0,0, "SHRB CL,%e",
+ 0,0, nil,
+ 0,0, "SARB CL,%e",
+};
+
+static Optable optabD3[8] =
+{
+ 0,0, "ROL%S CL,%e",
+ 0,0, "ROR%S CL,%e",
+ 0,0, "RCL%S CL,%e",
+ 0,0, "RCR%S CL,%e",
+ 0,0, "SHL%S CL,%e",
+ 0,0, "SHR%S CL,%e",
+ 0,0, nil,
+ 0,0, "SAR%S CL,%e",
+};
+
+static Optable optabD8[8+8] =
+{
+ 0,0, "FADDF %e,F0",
+ 0,0, "FMULF %e,F0",
+ 0,0, "FCOMF %e,F0",
+ 0,0, "FCOMFP %e,F0",
+ 0,0, "FSUBF %e,F0",
+ 0,0, "FSUBRF %e,F0",
+ 0,0, "FDIVF %e,F0",
+ 0,0, "FDIVRF %e,F0",
+ 0,0, "FADDD %f,F0",
+ 0,0, "FMULD %f,F0",
+ 0,0, "FCOMD %f,F0",
+ 0,0, "FCOMPD %f,F0",
+ 0,0, "FSUBD %f,F0",
+ 0,0, "FSUBRD %f,F0",
+ 0,0, "FDIVD %f,F0",
+ 0,0, "FDIVRD %f,F0",
+};
+/*
+ * optabD9 and optabDB use the following encoding:
+ * if (0 <= modrm <= 2) instruction = optabDx[modrm&0x07];
+ * else instruction = optabDx[(modrm&0x3f)+8];
+ *
+ * the instructions for MOD == 3, follow the 8 instructions
+ * for the other MOD values stored at the front of the table.
+ */
+static Optable optabD9[64+8] =
+{
+ 0,0, "FMOVF %e,F0",
+ 0,0, nil,
+ 0,0, "FMOVF F0,%e",
+ 0,0, "FMOVFP F0,%e",
+ 0,0, "FLDENV%S %e",
+ 0,0, "FLDCW %e",
+ 0,0, "FSTENV%S %e",
+ 0,0, "FSTCW %e",
+ 0,0, "FMOVD F0,F0", /* Mod R/M = 11xx xxxx*/
+ 0,0, "FMOVD F1,F0",
+ 0,0, "FMOVD F2,F0",
+ 0,0, "FMOVD F3,F0",
+ 0,0, "FMOVD F4,F0",
+ 0,0, "FMOVD F5,F0",
+ 0,0, "FMOVD F6,F0",
+ 0,0, "FMOVD F7,F0",
+ 0,0, "FXCHD F0,F0",
+ 0,0, "FXCHD F1,F0",
+ 0,0, "FXCHD F2,F0",
+ 0,0, "FXCHD F3,F0",
+ 0,0, "FXCHD F4,F0",
+ 0,0, "FXCHD F5,F0",
+ 0,0, "FXCHD F6,F0",
+ 0,0, "FXCHD F7,F0",
+ 0,0, "FNOP",
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, "FCHS", /* [0x28] */
+ 0,0, "FABS",
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, "FTST",
+ 0,0, "FXAM",
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, "FLD1",
+ 0,0, "FLDL2T",
+ 0,0, "FLDL2E",
+ 0,0, "FLDPI",
+ 0,0, "FLDLG2",
+ 0,0, "FLDLN2",
+ 0,0, "FLDZ",
+ 0,0, nil,
+ 0,0, "F2XM1",
+ 0,0, "FYL2X",
+ 0,0, "FPTAN",
+ 0,0, "FPATAN",
+ 0,0, "FXTRACT",
+ 0,0, "FPREM1",
+ 0,0, "FDECSTP",
+ 0,0, "FNCSTP",
+ 0,0, "FPREM",
+ 0,0, "FYL2XP1",
+ 0,0, "FSQRT",
+ 0,0, "FSINCOS",
+ 0,0, "FRNDINT",
+ 0,0, "FSCALE",
+ 0,0, "FSIN",
+ 0,0, "FCOS",
+};
+
+static Optable optabDA[8+8] =
+{
+ 0,0, "FADDL %e,F0",
+ 0,0, "FMULL %e,F0",
+ 0,0, "FCOML %e,F0",
+ 0,0, "FCOMLP %e,F0",
+ 0,0, "FSUBL %e,F0",
+ 0,0, "FSUBRL %e,F0",
+ 0,0, "FDIVL %e,F0",
+ 0,0, "FDIVRL %e,F0",
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ R1,0, "FUCOMPP", /* [0x0d] */
+};
+
+static Optable optabDB[8+64] =
+{
+ 0,0, "FMOVL %e,F0",
+ 0,0, nil,
+ 0,0, "FMOVL F0,%e",
+ 0,0, "FMOVLP F0,%e",
+ 0,0, nil,
+ 0,0, "FMOVX %e,F0",
+ 0,0, nil,
+ 0,0, "FMOVXP F0,%e",
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, "FCLEX", /* [0x2a] */
+ 0,0, "FINIT",
+};
+
+static Optable optabDC[8+8] =
+{
+ 0,0, "FADDD %e,F0",
+ 0,0, "FMULD %e,F0",
+ 0,0, "FCOMD %e,F0",
+ 0,0, "FCOMDP %e,F0",
+ 0,0, "FSUBD %e,F0",
+ 0,0, "FSUBRD %e,F0",
+ 0,0, "FDIVD %e,F0",
+ 0,0, "FDIVRD %e,F0",
+ 0,0, "FADDD F0,%f",
+ 0,0, "FMULD F0,%f",
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, "FSUBRD F0,%f",
+ 0,0, "FSUBD F0,%f",
+ 0,0, "FDIVRD F0,%f",
+ 0,0, "FDIVD F0,%f",
+};
+
+static Optable optabDD[8+8] =
+{
+ 0,0, "FMOVD %e,F0",
+ 0,0, nil,
+ 0,0, "FMOVD F0,%e",
+ 0,0, "FMOVDP F0,%e",
+ 0,0, "FRSTOR%S %e",
+ 0,0, nil,
+ 0,0, "FSAVE%S %e",
+ 0,0, "FSTSW %e",
+ 0,0, "FFREED %f",
+ 0,0, nil,
+ 0,0, "FMOVD %f,F0",
+ 0,0, "FMOVDP %f,F0",
+ 0,0, "FUCOMD %f,F0",
+ 0,0, "FUCOMDP %f,F0",
+};
+
+static Optable optabDE[8+8] =
+{
+ 0,0, "FADDW %e,F0",
+ 0,0, "FMULW %e,F0",
+ 0,0, "FCOMW %e,F0",
+ 0,0, "FCOMWP %e,F0",
+ 0,0, "FSUBW %e,F0",
+ 0,0, "FSUBRW %e,F0",
+ 0,0, "FDIVW %e,F0",
+ 0,0, "FDIVRW %e,F0",
+ 0,0, "FADDDP F0,%f",
+ 0,0, "FMULDP F0,%f",
+ 0,0, nil,
+ R1,0, "FCOMPDP",
+ 0,0, "FSUBRDP F0,%f",
+ 0,0, "FSUBDP F0,%f",
+ 0,0, "FDIVRDP F0,%f",
+ 0,0, "FDIVDP F0,%f",
+};
+
+static Optable optabDF[8+8] =
+{
+ 0,0, "FMOVW %e,F0",
+ 0,0, nil,
+ 0,0, "FMOVW F0,%e",
+ 0,0, "FMOVWP F0,%e",
+ 0,0, "FBLD %e",
+ 0,0, "FMOVL %e,F0",
+ 0,0, "FBSTP %e",
+ 0,0, "FMOVLP F0,%e",
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ 0,0, nil,
+ R0,0, "FSTSW %OAX",
+};
+
+static Optable optabF6[8] =
+{
+ Ib,0, "TESTB %i,%e",
+ 0,0, nil,
+ 0,0, "NOTB %e",
+ 0,0, "NEGB %e",
+ 0,0, "MULB AL,%e",
+ 0,0, "IMULB AL,%e",
+ 0,0, "DIVB AL,%e",
+ 0,0, "IDIVB AL,%e",
+};
+
+static Optable optabF7[8] =
+{
+ Iwd,0, "TEST%S %i,%e",
+ 0,0, nil,
+ 0,0, "NOT%S %e",
+ 0,0, "NEG%S %e",
+ 0,0, "MUL%S %OAX,%e",
+ 0,0, "IMUL%S %OAX,%e",
+ 0,0, "DIV%S %OAX,%e",
+ 0,0, "IDIV%S %OAX,%e",
+};
+
+static Optable optabFE[8] =
+{
+ 0,0, "INCB %e",
+ 0,0, "DECB %e",
+};
+
+static Optable optabFF[8] =
+{
+ 0,0, "INC%S %e",
+ 0,0, "DEC%S %e",
+ JUMP,0, "CALL*%S %e",
+ JUMP,0, "CALLF*%S %e",
+ JUMP,0, "JMP*%S %e",
+ JUMP,0, "JMPF*%S %e",
+ 0,0, "PUSHL %e",
+};
+
+static Optable optable[256] =
+{
+ RMB,0, "ADDB %r,%e",
+ RM,0, "ADD%S %r,%e",
+ RMB,0, "ADDB %e,%r",
+ RM,0, "ADD%S %e,%r",
+ Ib,0, "ADDB %i,AL",
+ Iwd,0, "ADD%S %i,%OAX",
+ 0,0, "PUSHL ES",
+ 0,0, "POPL ES",
+ RMB,0, "ORB %r,%e",
+ RM,0, "OR%S %r,%e",
+ RMB,0, "ORB %e,%r",
+ RM,0, "OR%S %e,%r",
+ Ib,0, "ORB %i,AL",
+ Iwd,0, "OR%S %i,%OAX",
+ 0,0, "PUSHL CS",
+ AUX,0, optab0F,
+ RMB,0, "ADCB %r,%e",
+ RM,0, "ADC%S %r,%e",
+ RMB,0, "ADCB %e,%r",
+ RM,0, "ADC%S %e,%r",
+ Ib,0, "ADCB %i,AL",
+ Iwd,0, "ADC%S %i,%OAX",
+ 0,0, "PUSHL SS",
+ 0,0, "POPL SS",
+ RMB,0, "SBBB %r,%e",
+ RM,0, "SBB%S %r,%e",
+ RMB,0, "SBBB %e,%r",
+ RM,0, "SBB%S %e,%r",
+ Ib,0, "SBBB %i,AL",
+ Iwd,0, "SBB%S %i,%OAX",
+ 0,0, "PUSHL DS",
+ 0,0, "POPL DS",
+ RMB,0, "ANDB %r,%e",
+ RM,0, "AND%S %r,%e",
+ RMB,0, "ANDB %e,%r",
+ RM,0, "AND%S %e,%r",
+ Ib,0, "ANDB %i,AL",
+ Iwd,0, "AND%S %i,%OAX",
+ SEG,0, "ES:",
+ 0,0, "DAA",
+ RMB,0, "SUBB %r,%e",
+ RM,0, "SUB%S %r,%e",
+ RMB,0, "SUBB %e,%r",
+ RM,0, "SUB%S %e,%r",
+ Ib,0, "SUBB %i,AL",
+ Iwd,0, "SUB%S %i,%OAX",
+ SEG,0, "CS:",
+ 0,0, "DAS",
+ RMB,0, "XORB %r,%e",
+ RM,0, "XOR%S %r,%e",
+ RMB,0, "XORB %e,%r",
+ RM,0, "XOR%S %e,%r",
+ Ib,0, "XORB %i,AL",
+ Iwd,0, "XOR%S %i,%OAX",
+ SEG,0, "SS:",
+ 0,0, "AAA",
+ RMB,0, "CMPB %r,%e",
+ RM,0, "CMP%S %r,%e",
+ RMB,0, "CMPB %e,%r",
+ RM,0, "CMP%S %e,%r",
+ Ib,0, "CMPB %i,AL",
+ Iwd,0, "CMP%S %i,%OAX",
+ SEG,0, "DS:",
+ 0,0, "AAS",
+ 0,0, "INC%S %OAX",
+ 0,0, "INC%S %OCX",
+ 0,0, "INC%S %ODX",
+ 0,0, "INC%S %OBX",
+ 0,0, "INC%S %OSP",
+ 0,0, "INC%S %OBP",
+ 0,0, "INC%S %OSI",
+ 0,0, "INC%S %ODI",
+ 0,0, "DEC%S %OAX",
+ 0,0, "DEC%S %OCX",
+ 0,0, "DEC%S %ODX",
+ 0,0, "DEC%S %OBX",
+ 0,0, "DEC%S %OSP",
+ 0,0, "DEC%S %OBP",
+ 0,0, "DEC%S %OSI",
+ 0,0, "DEC%S %ODI",
+ 0,0, "PUSH%S %OAX",
+ 0,0, "PUSH%S %OCX",
+ 0,0, "PUSH%S %ODX",
+ 0,0, "PUSH%S %OBX",
+ 0,0, "PUSH%S %OSP",
+ 0,0, "PUSH%S %OBP",
+ 0,0, "PUSH%S %OSI",
+ 0,0, "PUSH%S %ODI",
+ 0,0, "POP%S %OAX",
+ 0,0, "POP%S %OCX",
+ 0,0, "POP%S %ODX",
+ 0,0, "POP%S %OBX",
+ 0,0, "POP%S %OSP",
+ 0,0, "POP%S %OBP",
+ 0,0, "POP%S %OSI",
+ 0,0, "POP%S %ODI",
+ 0,0, "PUSHA%S",
+ 0,0, "POPA%S",
+ RMM,0, "BOUND %e,%r",
+ RM,0, "ARPL %r,%e",
+ SEG,0, "FS:",
+ SEG,0, "GS:",
+ OPOVER,0, "",
+ ADDOVER,0, "",
+ Iwd,0, "PUSH%S %i",
+ RM,Iwd, "IMUL%S %e,%i,%r",
+ Ib,0, "PUSH%S %i",
+ RM,Ibs, "IMUL%S %e,%i,%r",
+ 0,0, "INSB DX,(%ODI)",
+ 0,0, "INS%S DX,(%ODI)",
+ 0,0, "OUTSB (%ASI),DX",
+ 0,0, "OUTS%S (%ASI),DX",
+ Jbs,0, "JOS %p",
+ Jbs,0, "JOC %p",
+ Jbs,0, "JCS %p",
+ Jbs,0, "JCC %p",
+ Jbs,0, "JEQ %p",
+ Jbs,0, "JNE %p",
+ Jbs,0, "JLS %p",
+ Jbs,0, "JHI %p",
+ Jbs,0, "JMI %p",
+ Jbs,0, "JPL %p",
+ Jbs,0, "JPS %p",
+ Jbs,0, "JPC %p",
+ Jbs,0, "JLT %p",
+ Jbs,0, "JGE %p",
+ Jbs,0, "JLE %p",
+ Jbs,0, "JGT %p",
+ RMOPB,0, optab80,
+ RMOP,0, optab81,
+ 0,0, nil,
+ RMOP,0, optab83,
+ RMB,0, "TESTB %r,%e",
+ RM,0, "TEST%S %r,%e",
+ RMB,0, "XCHGB %r,%e",
+ RM,0, "XCHG%S %r,%e",
+ RMB,0, "MOVB %r,%e",
+ RM,0, "MOV%S %r,%e",
+ RMB,0, "MOVB %e,%r",
+ RM,0, "MOV%S %e,%r",
+ RM,0, "MOVW %g,%e",
+ RM,0, "LEA %e,%r",
+ RM,0, "MOVW %e,%g",
+ RM,0, "POP%S %e",
+ 0,0, "NOP",
+ 0,0, "XCHG %OCX,%OAX",
+ 0,0, "XCHG %ODX,%OAX",
+ 0,0, "XCHG %OBX,%OAX",
+ 0,0, "XCHG %OSP,%OAX",
+ 0,0, "XCHG %OBP,%OAX",
+ 0,0, "XCHG %OSI,%OAX",
+ 0,0, "XCHG %ODI,%OAX",
+ 0,0, "%X", /* miserable CBW or CWDE */
+ 0,0, "%x", /* idiotic CWD or CDQ */
+ PTR,0, "CALL%S %d",
+ 0,0, "WAIT",
+ 0,0, "PUSH FLAGS",
+ 0,0, "POP FLAGS",
+ 0,0, "SAHF",
+ 0,0, "LAHF",
+ Awd,0, "MOVB %i,AL",
+ Awd,0, "MOV%S %i,%OAX",
+ Awd,0, "MOVB AL,%i",
+ Awd,0, "MOV%S %OAX,%i",
+ 0,0, "MOVSB (%ASI),(%ADI)",
+ 0,0, "MOVS%S (%ASI),(%ADI)",
+ 0,0, "CMPSB (%ASI),(%ADI)",
+ 0,0, "CMPS%S (%ASI),(%ADI)",
+ Ib,0, "TESTB %i,AL",
+ Iwd,0, "TEST%S %i,%OAX",
+ 0,0, "STOSB AL,(%ADI)",
+ 0,0, "STOS%S %OAX,(%ADI)",
+ 0,0, "LODSB (%ASI),AL",
+ 0,0, "LODS%S (%ASI),%OAX",
+ 0,0, "SCASB (%ADI),AL",
+ 0,0, "SCAS%S (%ADI),%OAX",
+ Ib,0, "MOVB %i,AL",
+ Ib,0, "MOVB %i,CL",
+ Ib,0, "MOVB %i,DL",
+ Ib,0, "MOVB %i,BL",
+ Ib,0, "MOVB %i,AH",
+ Ib,0, "MOVB %i,CH",
+ Ib,0, "MOVB %i,DH",
+ Ib,0, "MOVB %i,BH",
+ Iwd,0, "MOV%S %i,%OAX",
+ Iwd,0, "MOV%S %i,%OCX",
+ Iwd,0, "MOV%S %i,%ODX",
+ Iwd,0, "MOV%S %i,%OBX",
+ Iwd,0, "MOV%S %i,%OSP",
+ Iwd,0, "MOV%S %i,%OBP",
+ Iwd,0, "MOV%S %i,%OSI",
+ Iwd,0, "MOV%S %i,%ODI",
+ RMOPB,0, optabC0,
+ RMOP,0, optabC1,
+ Iw,0, "RET %i",
+ RET,0, "RET",
+ RM,0, "LES %e,%r",
+ RM,0, "LDS %e,%r",
+ RMB,Ib, "MOVB %i,%e",
+ RM,Iwd, "MOV%S %i,%e",
+ Iw2,Ib, "ENTER %i,%I", /* loony ENTER */
+ RET,0, "LEAVE", /* bizarre LEAVE */
+ Iw,0, "RETF %i",
+ RET,0, "RETF",
+ 0,0, "INT 3",
+ Ib,0, "INTB %i",
+ 0,0, "INTO",
+ 0,0, "IRET",
+ RMOPB,0, optabD0,
+ RMOP,0, optabD1,
+ RMOPB,0, optabD2,
+ RMOP,0, optabD3,
+ OA,0, "AAM",
+ OA,0, "AAD",
+ 0,0, nil,
+ 0,0, "XLAT",
+ FRMOP,0, optabD8,
+ FRMEX,0, optabD9,
+ FRMOP,0, optabDA,
+ FRMEX,0, optabDB,
+ FRMOP,0, optabDC,
+ FRMOP,0, optabDD,
+ FRMOP,0, optabDE,
+ FRMOP,0, optabDF,
+ Jbs,0, "LOOPNE %p",
+ Jbs,0, "LOOPE %p",
+ Jbs,0, "LOOP %p",
+ Jbs,0, "JCXZ %p",
+ Ib,0, "INB %i,AL",
+ Ib,0, "IN%S %i,%OAX",
+ Ib,0, "OUTB AL,%i",
+ Ib,0, "OUT%S %OAX,%i",
+ Iwds,0, "CALL %p",
+ Iwds,0, "JMP %p",
+ PTR,0, "JMP %d",
+ Jbs,0, "JMP %p",
+ 0,0, "INB DX,AL",
+ 0,0, "IN%S DX,%OAX",
+ 0,0, "OUTB AL,DX",
+ 0,0, "OUT%S %OAX,DX",
+ PRE,0, "LOCK",
+ 0,0, nil,
+ PRE,0, "REPNE",
+ PRE,0, "REP",
+ 0,0, "HALT",
+ 0,0, "CMC",
+ RMOPB,0, optabF6,
+ RMOP,0, optabF7,
+ 0,0, "CLC",
+ 0,0, "STC",
+ 0,0, "CLI",
+ 0,0, "STI",
+ 0,0, "CLD",
+ 0,0, "STD",
+ RMOPB,0, optabFE,
+ RMOP,0, optabFF,
+};
+
+/*
+ * get a byte of the instruction
+ */
+static int
+igetc(Instr *ip, uchar *c)
+{
+ if(ip->n+1 > sizeof(ip->mem)){
+ kwerrstr("instruction too long");
+ return -1;
+ }
+ *c = dasdata[ip->addr+ip->n];
+ ip->mem[ip->n++] = *c;
+ return 1;
+}
+
+/*
+ * get two bytes of the instruction
+ */
+static int
+igets(Instr *ip, ushort *sp)
+{
+ uchar c;
+ ushort s;
+
+ if (igetc(ip, &c) < 0)
+ return -1;
+ s = c;
+ if (igetc(ip, &c) < 0)
+ return -1;
+ s |= (c<<8);
+ *sp = s;
+ return 1;
+}
+
+/*
+ * get 4 bytes of the instruction
+ */
+static int
+igetl(Instr *ip, ulong *lp)
+{
+ ushort s;
+ long l;
+
+ if (igets(ip, &s) < 0)
+ return -1;
+ l = s;
+ if (igets(ip, &s) < 0)
+ return -1;
+ l |= (s<<16);
+ *lp = l;
+ return 1;
+}
+
+static int
+getdisp(Instr *ip, int mod, int rm, int code)
+{
+ uchar c;
+ ushort s;
+
+ if (mod > 2)
+ return 1;
+ if (mod == 1) {
+ if (igetc(ip, &c) < 0)
+ return -1;
+ if (c&0x80)
+ ip->disp = c|0xffffff00;
+ else
+ ip->disp = c&0xff;
+ } else if (mod == 2 || rm == code) {
+ if (ip->asize == 'E') {
+ if (igetl(ip, &ip->disp) < 0)
+ return -1;
+ } else {
+ if (igets(ip, &s) < 0)
+ return -1;
+ if (s&0x8000)
+ ip->disp = s|0xffff0000;
+ else
+ ip->disp = s;
+ }
+ if (mod == 0)
+ ip->base = -1;
+ }
+ return 1;
+}
+
+static int
+modrm(Instr *ip, uchar c)
+{
+ uchar rm, mod;
+
+ mod = (c>>6)&3;
+ rm = c&7;
+ ip->mod = mod;
+ ip->base = rm;
+ ip->reg = (c>>3)&7;
+ if (mod == 3) /* register */
+ return 1;
+ if (ip->asize == 0) { /* 16-bit mode */
+ switch(rm)
+ {
+ case 0:
+ ip->base = BX; ip->index = SI;
+ break;
+ case 1:
+ ip->base = BX; ip->index = DI;
+ break;
+ case 2:
+ ip->base = BP; ip->index = SI;
+ break;
+ case 3:
+ ip->base = BP; ip->index = DI;
+ break;
+ case 4:
+ ip->base = SI;
+ break;
+ case 5:
+ ip->base = DI;
+ break;
+ case 6:
+ ip->base = BP;
+ break;
+ case 7:
+ ip->base = BX;
+ break;
+ default:
+ break;
+ }
+ return getdisp(ip, mod, rm, 6);
+ }
+ if (rm == 4) { /* scummy sib byte */
+ if (igetc(ip, &c) < 0)
+ return -1;
+ ip->ss = (c>>6)&0x03;
+ ip->index = (c>>3)&0x07;
+ if (ip->index == 4)
+ ip->index = -1;
+ ip->base = c&0x07;
+ return getdisp(ip, mod, ip->base, 5);
+ }
+ return getdisp(ip, mod, rm, 5);
+}
+
+static Optable *
+mkinstr(Instr *ip, ulong pc)
+{
+ int i, n;
+ uchar c;
+ ushort s;
+ Optable *op, *obase;
+ char buf[128];
+
+ memset(ip, 0, sizeof(*ip));
+ ip->base = -1;
+ ip->index = -1;
+ ip->osize = 'L';
+ ip->asize = 'E';
+ ip->addr = pc;
+ if (igetc(ip, &c) < 0)
+ return 0;
+ obase = optable;
+newop:
+ op = &obase[c];
+ if (op->proto == 0) {
+badop:
+ n = snprint(buf, sizeof(buf), "opcode: ??");
+ for (i = 0; i < ip->n && n < sizeof(buf)-3; i++, n+=2)
+ _hexify(buf+n, ip->mem[i], 1);
+ strcpy(buf+n, "??");
+ kwerrstr(buf);
+ return 0;
+ }
+ for(i = 0; i < 2 && op->operand[i]; i++) {
+ switch(op->operand[i])
+ {
+ case Ib: /* 8-bit immediate - (no sign extension)*/
+ if (igetc(ip, &c) < 0)
+ return 0;
+ ip->imm = c&0xff;
+ break;
+ case Jbs: /* 8-bit jump immediate (sign extended) */
+ if (igetc(ip, &c) < 0)
+ return 0;
+ if (c&0x80)
+ ip->imm = c|0xffffff00;
+ else
+ ip->imm = c&0xff;
+ ip->jumptype = Jbs;
+ break;
+ case Ibs: /* 8-bit immediate (sign extended) */
+ if (igetc(ip, &c) < 0)
+ return 0;
+ if (c&0x80)
+ if (ip->osize == 'L')
+ ip->imm = c|0xffffff00;
+ else
+ ip->imm = c|0xff00;
+ else
+ ip->imm = c&0xff;
+ break;
+ case Iw: /* 16-bit immediate -> imm */
+ if (igets(ip, &s) < 0)
+ return 0;
+ ip->imm = s&0xffff;
+ ip->jumptype = Iw;
+ break;
+ case Iw2: /* 16-bit immediate -> in imm2*/
+ if (igets(ip, &s) < 0)
+ return 0;
+ ip->imm2 = s&0xffff;
+ break;
+ case Iwd: /* Operand-sized immediate (no sign extension)*/
+ if (ip->osize == 'L') {
+ if (igetl(ip, &ip->imm) < 0)
+ return 0;
+ } else {
+ if (igets(ip, &s)< 0)
+ return 0;
+ ip->imm = s&0xffff;
+ }
+ break;
+ case Awd: /* Address-sized immediate (no sign extension)*/
+ if (ip->asize == 'E') {
+ if (igetl(ip, &ip->imm) < 0)
+ return 0;
+ } else {
+ if (igets(ip, &s)< 0)
+ return 0;
+ ip->imm = s&0xffff;
+ }
+ break;
+ case Iwds: /* Operand-sized immediate (sign extended) */
+ if (ip->osize == 'L') {
+ if (igetl(ip, &ip->imm) < 0)
+ return 0;
+ } else {
+ if (igets(ip, &s)< 0)
+ return 0;
+ if (s&0x8000)
+ ip->imm = s|0xffff0000;
+ else
+ ip->imm = s&0xffff;
+ }
+ ip->jumptype = Iwds;
+ break;
+ case OA: /* literal 0x0a byte */
+ if (igetc(ip, &c) < 0)
+ return 0;
+ if (c != 0x0a)
+ goto badop;
+ break;
+ case R0: /* base register must be R0 */
+ if (ip->base != 0)
+ goto badop;
+ break;
+ case R1: /* base register must be R1 */
+ if (ip->base != 1)
+ goto badop;
+ break;
+ case RMB: /* R/M field with byte register (/r)*/
+ if (igetc(ip, &c) < 0)
+ return 0;
+ if (modrm(ip, c) < 0)
+ return 0;
+ ip->osize = 'B';
+ break;
+ case RM: /* R/M field with register (/r) */
+ if (igetc(ip, &c) < 0)
+ return 0;
+ if (modrm(ip, c) < 0)
+ return 0;
+ break;
+ case RMOPB: /* R/M field with op code (/digit) */
+ if (igetc(ip, &c) < 0)
+ return 0;
+ if (modrm(ip, c) < 0)
+ return 0;
+ c = ip->reg; /* secondary op code */
+ obase = (Optable*)op->proto;
+ ip->osize = 'B';
+ goto newop;
+ case RMOP: /* R/M field with op code (/digit) */
+ if (igetc(ip, &c) < 0)
+ return 0;
+ if (modrm(ip, c) < 0)
+ return 0;
+ c = ip->reg;
+ obase = (Optable*)op->proto;
+ goto newop;
+ case FRMOP: /* FP R/M field with op code (/digit) */
+ if (igetc(ip, &c) < 0)
+ return 0;
+ if (modrm(ip, c) < 0)
+ return 0;
+ if ((c&0xc0) == 0xc0)
+ c = ip->reg+8; /* 16 entry table */
+ else
+ c = ip->reg;
+ obase = (Optable*)op->proto;
+ goto newop;
+ case FRMEX: /* Extended FP R/M field with op code (/digit) */
+ if (igetc(ip, &c) < 0)
+ return 0;
+ if (modrm(ip, c) < 0)
+ return 0;
+ if ((c&0xc0) == 0xc0)
+ c = (c&0x3f)+8; /* 64-entry table */
+ else
+ c = ip->reg;
+ obase = (Optable*)op->proto;
+ goto newop;
+ case RMR: /* R/M register only (mod = 11) */
+ if (igetc(ip, &c) < 0)
+ return 0;
+ if ((c&0xc0) != 0xc0) {
+ kwerrstr("invalid R/M register: %x", c);
+ return 0;
+ }
+ if (modrm(ip, c) < 0)
+ return 0;
+ break;
+ case RMM: /* R/M register only (mod = 11) */
+ if (igetc(ip, &c) < 0)
+ return 0;
+ if ((c&0xc0) == 0xc0) {
+ kwerrstr("invalid R/M memory mode: %x", c);
+ return 0;
+ }
+ if (modrm(ip, c) < 0)
+ return 0;
+ break;
+ case PTR: /* Seg:Displacement addr (ptr16:16 or ptr16:32) */
+ if (ip->osize == 'L') {
+ if (igetl(ip, &ip->disp) < 0)
+ return 0;
+ } else {
+ if (igets(ip, &s)< 0)
+ return 0;
+ ip->disp = s&0xffff;
+ }
+ if (igets(ip, (ushort*)&ip->seg) < 0)
+ return 0;
+ ip->jumptype = PTR;
+ break;
+ case AUX: /* Multi-byte op code - Auxiliary table */
+ obase = (Optable*)op->proto;
+ if (igetc(ip, &c) < 0)
+ return 0;
+ goto newop;
+ case PRE: /* Instr Prefix */
+ ip->prefix = (char*)op->proto;
+ if (igetc(ip, &c) < 0)
+ return 0;
+ goto newop;
+ case SEG: /* Segment Prefix */
+ ip->segment = (char*)op->proto;
+ if (igetc(ip, &c) < 0)
+ return 0;
+ goto newop;
+ case OPOVER: /* Operand size override */
+ ip->osize = 'W';
+ if (igetc(ip, &c) < 0)
+ return 0;
+ goto newop;
+ case ADDOVER: /* Address size override */
+ ip->asize = 0;
+ if (igetc(ip, &c) < 0)
+ return 0;
+ goto newop;
+ case JUMP: /* mark instruction as JUMP or RET */
+ case RET:
+ ip->jumptype = op->operand[i];
+ break;
+ default:
+ kwerrstr("bad operand type %d", op->operand[i]);
+ return 0;
+ }
+ }
+ return op;
+}
+
+static void
+bprint(Instr *ip, char *fmt, ...)
+{
+ va_list arg;
+
+ va_start(arg, fmt);
+ ip->curr = vseprint(ip->curr, ip->end, fmt, arg);
+ va_end(arg);
+}
+
+/*
+ * if we want to call 16 bit regs AX,BX,CX,...
+ * and 32 bit regs EAX,EBX,ECX,... then
+ * change the defs of ANAME and ONAME to:
+ * #define ANAME(ip) ((ip->asize == 'E' ? "E" : "")
+ * #define ONAME(ip) ((ip)->osize == 'L' ? "E" : "")
+ */
+#define ANAME(ip) ""
+#define ONAME(ip) ""
+
+static char *reg[] = {
+ "AX",
+ "CX",
+ "DX",
+ "BX",
+ "SP",
+ "BP",
+ "SI",
+ "DI",
+};
+
+static char *breg[] = { "AL", "CL", "DL", "BL", "AH", "CH", "DH", "BH" };
+static char *sreg[] = { "ES", "CS", "SS", "DS", "FS", "GS" };
+
+static void
+plocal(Instr *ip)
+{
+ int offset;
+
+ offset = ip->disp;
+
+ bprint(ip, "%lux(SP)", offset);
+}
+
+static void
+pea(Instr *ip)
+{
+ if (ip->mod == 3) {
+ if (ip->osize == 'B')
+ bprint(ip, breg[ip->base]);
+ else
+ bprint(ip, "%s%s", ANAME(ip), reg[ip->base]);
+ return;
+ }
+ if (ip->segment)
+ bprint(ip, ip->segment);
+ if (ip->asize == 'E' && ip->base == SP)
+ plocal(ip);
+ else {
+ bprint(ip,"%lux", ip->disp);
+ if (ip->base >= 0)
+ bprint(ip,"(%s%s)", ANAME(ip), reg[ip->base]);
+ }
+ if (ip->index >= 0)
+ bprint(ip,"(%s%s*%d)", ANAME(ip), reg[ip->index], 1<<ip->ss);
+}
+
+static void
+immediate(Instr *ip, long val)
+{
+ bprint(ip, "%lux", val);
+}
+
+static void
+prinstr(Instr *ip, char *fmt)
+{
+ if (ip->prefix)
+ bprint(ip, "%s ", ip->prefix);
+ for (; *fmt && ip->curr < ip->end; fmt++) {
+ if (*fmt != '%')
+ *ip->curr++ = *fmt;
+ else switch(*++fmt)
+ {
+ case '%':
+ *ip->curr++ = '%';
+ break;
+ case 'A':
+ bprint(ip, "%s", ANAME(ip));
+ break;
+ case 'C':
+ bprint(ip, "CR%d", ip->reg);
+ break;
+ case 'D':
+ if (ip->reg < 4 || ip->reg == 6 || ip->reg == 7)
+ bprint(ip, "DR%d",ip->reg);
+ else
+ bprint(ip, "???");
+ break;
+ case 'I':
+ bprint(ip, "$");
+ immediate(ip, ip->imm2);
+ break;
+ case 'O':
+ bprint(ip,"%s", ONAME(ip));
+ break;
+ case 'i':
+ bprint(ip, "$");
+ immediate(ip,ip->imm);
+ break;
+ case 'R':
+ bprint(ip, "%s%s", ONAME(ip), reg[ip->reg]);
+ break;
+ case 'S':
+ bprint(ip, "%c", ip->osize);
+ break;
+ case 'T':
+ if (ip->reg == 6 || ip->reg == 7)
+ bprint(ip, "TR%d",ip->reg);
+ else
+ bprint(ip, "???");
+ break;
+ case 'X':
+ if (ip->osize == 'L')
+ bprint(ip,"CWDE");
+ else
+ bprint(ip, "CBW");
+ break;
+ case 'd':
+ bprint(ip,"%lux:%lux",ip->seg,ip->disp);
+ break;
+ case 'e':
+ pea(ip);
+ break;
+ case 'f':
+ bprint(ip, "F%d", ip->base);
+ break;
+ case 'g':
+ if (ip->reg < 6)
+ bprint(ip,"%s",sreg[ip->reg]);
+ else
+ bprint(ip,"???");
+ break;
+ case 'p':
+ immediate(ip, ip->imm+ip->addr+ip->n);
+ break;
+ case 'r':
+ if (ip->osize == 'B')
+ bprint(ip,"%s",breg[ip->reg]);
+ else
+ bprint(ip, reg[ip->reg]);
+ break;
+ case 'x':
+ if (ip->osize == 'L')
+ bprint(ip,"CDQ");
+ else
+ bprint(ip, "CWD");
+ break;
+ default:
+ bprint(ip, "%%%c", *fmt);
+ break;
+ }
+ }
+ *ip->curr = 0; /* there's always room for 1 byte */
+}
+
+int
+i386inst(ulong pc, char modifier, char *buf, int n)
+{
+ Instr instr;
+ Optable *op;
+
+ USED(modifier);
+ op = mkinstr(&instr, pc);
+ if (op == 0) {
+ kgerrstr(buf, n);
+ return -1;
+ }
+ instr.curr = buf;
+ instr.end = buf+n-1;
+ prinstr(&instr, op->proto);
+ return instr.n;
+}
+
+int
+i386das(ulong pc, char *buf, int n)
+{
+ Instr instr;
+ int i;
+
+ if (mkinstr(&instr, pc) == 0) {
+ kgerrstr(buf, n);
+ return -1;
+ }
+ for(i = 0; i < instr.n && n > 2; i++) {
+ _hexify(buf, instr.mem[i], 1);
+ buf += 2;
+ n -= 2;
+ }
+ *buf = 0;
+ return instr.n;
+}
+
+int
+i386instlen(ulong pc)
+{
+ Instr i;
+
+ if (mkinstr(&i, pc))
+ return i.n;
+ return -1;
+}
+
+void
+das(uchar *x, int n)
+{
+ int l, pc;
+ char buf[128];
+/*
+ int i;
+ for(i = 0; i < n; i++)
+ print("%.2ux", x[i]);
+ print("\n");
+*/
+
+ dasdata = x;
+ pc = 0;
+ while(n > 0) {
+ i386das(pc, buf, sizeof(buf));
+ print("%.8lux %2x %-20s ", (ulong)(dasdata+pc), pc, buf);
+ l = i386inst(pc, 'i', buf, sizeof(buf));
+ print("\t%s\n", buf);
+
+ pc += l;
+ n -= l;
+ }
+}
--- /dev/null
+++ b/libinterp/das-arm.c
@@ -1,0 +1,535 @@
+#include <lib9.h>
+
+typedef struct Instr Instr;
+struct Instr
+{
+ ulong w;
+ ulong addr;
+ uchar op; /* super opcode */
+
+ uchar cond; /* bits 28-31 */
+ uchar store; /* bit 20 */
+
+ uchar rd; /* bits 12-15 */
+ uchar rn; /* bits 16-19 */
+ uchar rs; /* bits 0-11 */
+
+ long imm; /* rotated imm */
+ char* curr; /* fill point in buffer */
+ char* end; /* end of buffer */
+ char* err; /* error message */
+};
+
+typedef struct Opcode Opcode;
+struct Opcode
+{
+ char* o;
+ void (*f)(Opcode*, Instr*);
+ char* a;
+};
+
+static void format(char*, Instr*, char*);
+static int arminst(ulong, char, char*, int);
+static int armdas(ulong, char*, int);
+
+static
+char* cond[16] =
+{
+ "EQ", "NE", "CS", "CC",
+ "MI", "PL", "VS", "VC",
+ "HI", "LS", "GE", "LT",
+ "GT", "LE", 0, "NV"
+};
+
+static
+char* shtype[4] =
+{
+ "<<", ">>", "->", "@>"
+};
+
+static int
+get4(ulong addr, long *v)
+{
+ *v = *(ulong*)addr;
+ return 1;
+}
+
+static char *
+_hexify(char *buf, ulong p, int zeros)
+{
+ ulong d;
+
+ d = p/16;
+ if(d)
+ buf = _hexify(buf, d, zeros-1);
+ else
+ while(zeros--)
+ *buf++ = '0';
+ *buf++ = "0123456789abcdef"[p&0x0f];
+ return buf;
+}
+
+int
+armclass(long w)
+{
+ int op;
+
+ op = (w >> 25) & 0x7;
+ switch(op) {
+ case 0: /* data processing r,r,r */
+ op = ((w >> 4) & 0xf);
+ if(op == 0x9) {
+ op = 48+16; /* mul */
+ if(w & (1<<24)) {
+ op += 2;
+ if(w & (1<<22))
+ op++; /* swap */
+ break;
+ }
+ if(w & (1<<21))
+ op++; /* mla */
+ break;
+ }
+ op = (w >> 21) & 0xf;
+ if(w & (1<<4))
+ op += 32;
+ else
+ if(w & (31<<7))
+ op += 16;
+ break;
+ case 1: /* data processing i,r,r */
+ op = (48) + ((w >> 21) & 0xf);
+ break;
+ case 2: /* load/store byte/word i(r) */
+ op = (48+20) + ((w >> 22) & 0x1) + ((w >> 19) & 0x2);
+ break;
+ case 3: /* load/store byte/word (r)(r) */
+ op = (48+20+4) + ((w >> 22) & 0x1) + ((w >> 19) & 0x2);
+ break;
+ case 4: /* block data transfer (r)(r) */
+ op = (48+20+4+4) + ((w >> 20) & 0x1);
+ break;
+ case 5: /* branch / branch link */
+ op = (48+20+4+4+2) + ((w >> 24) & 0x1);
+ break;
+ case 7: /* coprocessor crap */
+ op = (48+20+4+4+2+2) + ((w >> 3) & 0x2) + ((w >> 20) & 0x1);
+ break;
+ default:
+ op = (48+20+4+4+2+2+4);
+ break;
+ }
+ return op;
+}
+
+static int
+decode(ulong pc, Instr *i)
+{
+ long w;
+
+ get4(pc, &w);
+ i->w = w;
+ i->addr = pc;
+ i->cond = (w >> 28) & 0xF;
+ i->op = armclass(w);
+ return 1;
+}
+
+static void
+bprint(Instr *i, char *fmt, ...)
+{
+ va_list arg;
+
+ va_start(arg, fmt);
+ i->curr = vseprint(i->curr, i->end, fmt, arg);
+ va_end(arg);
+}
+
+static void
+armdps(Opcode *o, Instr *i)
+{
+ i->store = (i->w >> 20) & 1;
+ i->rn = (i->w >> 16) & 0xf;
+ i->rd = (i->w >> 12) & 0xf;
+ i->rs = (i->w >> 0) & 0xf;
+ if(i->rn == 15 && i->rs == 0) {
+ if(i->op == 8) {
+ format("MOVW", i,"CPSR, R%d");
+ return;
+ } else
+ if(i->op == 10) {
+ format("MOVW", i,"SPSR, R%d");
+ return;
+ }
+ } else
+ if(i->rn == 9 && i->rd == 15) {
+ if(i->op == 9) {
+ format("MOVW", i, "R%s, CPSR");
+ return;
+ } else
+ if(i->op == 11) {
+ format("MOVW", i, "R%s, SPSR");
+ return;
+ }
+ }
+ format(o->o, i, o->a);
+}
+
+static void
+armdpi(Opcode *o, Instr *i)
+{
+ ulong v;
+ int c;
+
+ v = (i->w >> 0) & 0xff;
+ c = (i->w >> 8) & 0xf;
+ while(c) {
+ v = (v<<30) | (v>>2);
+ c--;
+ }
+ i->imm = v;
+ i->store = (i->w >> 20) & 1;
+ i->rn = (i->w >> 16) & 0xf;
+ i->rd = (i->w >> 12) & 0xf;
+ i->rs = i->w&0x0f;
+
+ /* RET is encoded as ADD #0,R14,R15 */
+ if(i->w == 0xe282f000){
+ format("RET", i, "");
+ return;
+ } else
+ format(o->o, i, o->a);
+}
+
+static void
+armsdti(Opcode *o, Instr *i)
+{
+ ulong v;
+
+ v = (i->w >> 0) & 0xfff;
+ if(!(i->w & (1<<23)))
+ v = -v;
+ i->store = ((i->w >> 23) & 0x2) | ((i->w >>21) & 0x1);
+ i->imm = v;
+ i->rn = (i->w >> 16) & 0xf;
+ i->rd = (i->w >> 12) & 0xf;
+ /* convert load of offset(PC) to a load immediate */
+ if(i->rn == 15 && (i->w & (1<<20)) && get4(i->addr+v+8, &i->imm) > 0)
+ format(o->o, i, "$#%i,R%d");
+ else
+ format(o->o, i, o->a);
+}
+
+static void
+armsdts(Opcode *o, Instr *i)
+{
+ i->store = ((i->w >> 23) & 0x2) | ((i->w >>21) & 0x1);
+ i->rs = (i->w >> 0) & 0xf;
+ i->rn = (i->w >> 16) & 0xf;
+ i->rd = (i->w >> 12) & 0xf;
+ format(o->o, i, o->a);
+}
+
+static void
+armbdt(Opcode *o, Instr *i)
+{
+ i->store = (i->w >> 21) & 0x3; /* S & W bits */
+ i->rn = (i->w >> 16) & 0xf;
+ i->imm = i->w & 0xffff;
+ if(i->w == 0xe8fd8000)
+ format("RFE", i, "");
+ else
+ format(o->o, i, o->a);
+}
+
+static void
+armund(Opcode *o, Instr *i)
+{
+ format(o->o, i, o->a);
+}
+
+static void
+armcdt(Opcode *o, Instr *i)
+{
+ format(o->o, i, o->a);
+}
+
+static void
+armunk(Opcode *o, Instr *i)
+{
+ format(o->o, i, o->a);
+}
+
+static void
+armb(Opcode *o, Instr *i)
+{
+ ulong v;
+
+ v = i->w & 0xffffff;
+ if(v & 0x800000)
+ v |= ~0xffffff;
+ i->imm = (v<<2) + i->addr + 8;
+ format(o->o, i, o->a);
+}
+
+static void
+armco(Opcode *o, Instr *i) /* coprocessor instructions */
+{
+ int op, p, cp;
+
+ char buf[1024];
+
+ i->rn = (i->w >> 16) & 0xf;
+ i->rd = (i->w >> 12) & 0xf;
+ i->rs = i->w&0xf;
+ cp = (i->w >> 8) & 0xf;
+ p = (i->w >> 5) & 0x7;
+ if(i->w&0x10) {
+ op = (i->w >> 20) & 0x0f;
+ snprint(buf, sizeof(buf), "#%x, #%x, R%d, C(%d), C(%d), #%x\n", cp, op, i->rd, i->rn, i->rs, p);
+ } else {
+ op = (i->w >> 21) & 0x07;
+ snprint(buf, sizeof(buf), "#%x, #%x, C(%d), C(%d), C(%d), #%x\n", cp, op, i->rd, i->rn, i->rs, p);
+ }
+ format(o->o, i, buf);
+}
+
+static Opcode opcodes[] =
+{
+ "AND%C%S", armdps, "R%s,R%n,R%d",
+ "EOR%C%S", armdps, "R%s,R%n,R%d",
+ "SUB%C%S", armdps, "R%s,R%n,R%d",
+ "RSB%C%S", armdps, "R%s,R%n,R%d",
+ "ADD%C%S", armdps, "R%s,R%n,R%d",
+ "ADC%C%S", armdps, "R%s,R%n,R%d",
+ "SBC%C%S", armdps, "R%s,R%n,R%d",
+ "RSC%C%S", armdps, "R%s,R%n,R%d",
+ "TST%C%S", armdps, "R%s,R%n,",
+ "TEQ%C%S", armdps, "R%s,R%n,",
+ "CMP%C%S", armdps, "R%s,R%n,",
+ "CMN%C%S", armdps, "R%s,R%n,",
+ "ORR%C%S", armdps, "R%s,R%n,R%d",
+ "MOVW%C%S", armdps, "R%s,R%d",
+ "BIC%C%S", armdps, "R%s,R%n,R%d",
+ "MVN%C%S", armdps, "R%s,R%d",
+
+ "AND%C%S", armdps, "(R%s%h#%m),R%n,R%d",
+ "EOR%C%S", armdps, "(R%s%h#%m),R%n,R%d",
+ "SUB%C%S", armdps, "(R%s%h#%m),R%n,R%d",
+ "RSB%C%S", armdps, "(R%s%h#%m),R%n,R%d",
+ "ADD%C%S", armdps, "(R%s%h#%m),R%n,R%d",
+ "ADC%C%S", armdps, "(R%s%h#%m),R%n,R%d",
+ "SBC%C%S", armdps, "(R%s%h#%m),R%n,R%d",
+ "RSC%C%S", armdps, "(R%s%h#%m),R%n,R%d",
+ "TST%C%S", armdps, "(R%s%h#%m),R%n,",
+ "TEQ%C%S", armdps, "(R%s%h#%m),R%n,",
+ "CMP%C%S", armdps, "(R%s%h#%m),R%n,",
+ "CMN%C%S", armdps, "(R%s%h#%m),R%n,",
+ "ORR%C%S", armdps, "(R%s%h#%m),R%n,R%d",
+ "MOVW%C%S", armdps, "(R%s%h#%m),R%d",
+ "BIC%C%S", armdps, "(R%s%h#%m),R%n,R%d",
+ "MVN%C%S", armdps, "(R%s%h#%m),R%d",
+
+ "AND%C%S", armdps, "(R%s%hR%m),R%n,R%d",
+ "EOR%C%S", armdps, "(R%s%hR%m),R%n,R%d",
+ "SUB%C%S", armdps, "(R%s%hR%m),R%n,R%d",
+ "RSB%C%S", armdps, "(R%s%hR%m),R%n,R%d",
+ "ADD%C%S", armdps, "(R%s%hR%m),R%n,R%d",
+ "ADC%C%S", armdps, "(R%s%hR%m),R%n,R%d",
+ "SBC%C%S", armdps, "(R%s%hR%m),R%n,R%d",
+ "RSC%C%S", armdps, "(R%s%hR%m),R%n,R%d",
+ "TST%C%S", armdps, "(R%s%hR%m),R%n,",
+ "TEQ%C%S", armdps, "(R%s%hR%m),R%n,",
+ "CMP%C%S", armdps, "(R%s%hR%m),R%n,",
+ "CMN%C%S", armdps, "(R%s%hR%m),R%n,",
+ "ORR%C%S", armdps, "(R%s%hR%m),R%n,R%d",
+ "MOVW%C%S", armdps, "(R%s%hR%m),R%d",
+ "BIC%C%S", armdps, "(R%s%hR%m),R%n,R%d",
+ "MVN%C%S", armdps, "(R%s%hR%m),R%d",
+
+ "AND%C%S", armdpi, "$#%i,R%n,R%d",
+ "EOR%C%S", armdpi, "$#%i,R%n,R%d",
+ "SUB%C%S", armdpi, "$#%i,R%n,R%d",
+ "RSB%C%S", armdpi, "$#%i,R%n,R%d",
+ "ADD%C%S", armdpi, "$#%i,R%n,R%d",
+ "ADC%C%S", armdpi, "$#%i,R%n,R%d",
+ "SBC%C%S", armdpi, "$#%i,R%n,R%d",
+ "RSC%C%S", armdpi, "$#%i,R%n,R%d",
+ "TST%C%S", armdpi, "$#%i,R%n,",
+ "TEQ%C%S", armdpi, "$#%i,R%n,",
+ "CMP%C%S", armdpi, "$#%i,R%n,",
+ "CMN%C%S", armdpi, "$#%i,R%n,",
+ "ORR%C%S", armdpi, "$#%i,R%n,R%d",
+ "MOVW%C%S", armdpi, "$#%i,,R%d",
+ "BIC%C%S", armdpi, "$#%i,R%n,R%d",
+ "MVN%C%S", armdpi, "$#%i,,R%d",
+
+ "MUL%C%S", armdpi, "R%s,R%m,R%n",
+ "MULA%C%S", armdpi, "R%s,R%m,R%n,R%d",
+ "SWPW", armdpi, "R%s,(R%n),R%d",
+ "SWPB", armdpi, "R%s,(R%n),R%d",
+
+ "MOVW%C%p", armsdti,"R%d,#%i(R%n)",
+ "MOVB%C%p", armsdti,"R%d,#%i(R%n)",
+ "MOVW%C%p", armsdti,"#%i(R%n),R%d",
+ "MOVB%C%p", armsdti,"#%i(R%n),R%d",
+
+ "MOVW%C%p", armsdts,"R%d,%D(R%s%h#%m)(R%n)",
+ "MOVB%C%p", armsdts,"R%d,%D(R%s%h#%m)(R%n)",
+ "MOVW%C%p", armsdts,"%D(R%s%h#%m)(R%n),R%d",
+ "MOVB%C%p", armsdts,"%D(R%s%h#%m)(R%n),R%d",
+
+ "MOVM%C%P%a", armbdt, "R%n,[%r]",
+ "MOVM%C%P%a", armbdt, "[%r],R%n",
+
+ "B%C", armb, "%b",
+ "BL%C", armb, "%b",
+
+ "CDP%C", armco, "",
+ "CDP%C", armco, "",
+ "MCR%C", armco, "",
+ "MRC%C", armco, "",
+
+ "UNK", armunk, "",
+};
+
+static char *mode[] = { 0, "IA", "DB", "IB" };
+static char *pw[] = { "P", "PW", 0, "W" };
+static char *sw[] = { 0, "W", "S", "SW" };
+
+static void
+format(char *mnemonic, Instr *i, char *f)
+{
+ int j, k, m, n;
+
+ if(mnemonic)
+ format(0, i, mnemonic);
+ if(f == 0)
+ return;
+ if(mnemonic)
+ if(i->curr < i->end)
+ *i->curr++ = '\t';
+ for ( ; *f && i->curr < i->end; f++) {
+ if(*f != '%') {
+ *i->curr++ = *f;
+ continue;
+ }
+ switch (*++f) {
+
+ case 'C': /* .CONDITION */
+ if(cond[i->cond])
+ bprint(i, ".%s", cond[i->cond]);
+ break;
+
+ case 'S': /* .STORE */
+ if(i->store)
+ bprint(i, ".S");
+ break;
+
+ case 'P': /* P & U bits for block move */
+ n = (i->w >>23) & 0x3;
+ if (mode[n])
+ bprint(i, ".%s", mode[n]);
+ break;
+
+ case 'D': /* ~U bit for single data xfer */
+ if((i->w & (1<<23)) == 0)
+ bprint(i, "-");
+ break;
+
+ case 'p': /* P & W bits for single data xfer*/
+ if (pw[i->store])
+ bprint(i, ".%s", pw[i->store]);
+ break;
+
+ case 'a': /* S & W bits for single data xfer*/
+ if (sw[i->store])
+ bprint(i, ".%s", sw[i->store]);
+ break;
+
+ case 's':
+ bprint(i, "%d", i->rs & 0xf);
+ break;
+
+ case 'm':
+ bprint(i, "%d", (i->w>>7) & 0x1f);
+ break;
+
+ case 'h':
+ bprint(i, "%s", shtype[(i->w>>5) & 0x3]);
+ break;
+
+ case 'n':
+ bprint(i, "%d", i->rn);
+ break;
+
+ case 'd':
+ bprint(i, "%d", i->rd);
+ break;
+
+ case 'i':
+ bprint(i, "%lux", i->imm);
+ break;
+
+ case 'b':
+ bprint(i, "%lux", i->imm);
+ break;
+
+ case 'r':
+ n = i->imm&0xffff;
+ j = 0;
+ k = 0;
+ while(n) {
+ m = j;
+ while(n&0x1) {
+ j++;
+ n >>= 1;
+ }
+ if(j != m) {
+ if(k)
+ bprint(i, ",");
+ if(j == m+1)
+ bprint(i, "R%d", m);
+ else
+ bprint(i, "R%d-R%d", m, j-1);
+ k = 1;
+ }
+ j++;
+ n >>= 1;
+ }
+ break;
+
+ case '\0':
+ *i->curr++ = '%';
+ return;
+
+ default:
+ bprint(i, "%%%c", *f);
+ break;
+ }
+ }
+ *i->curr = 0;
+}
+
+void
+das(ulong *x, int n)
+{
+ ulong pc;
+ Instr i;
+ char buf[128];
+
+ pc = (ulong)x;
+ while(n > 0) {
+ i.curr = buf;
+ i.end = buf+sizeof(buf)-1;
+
+ if(decode(pc, &i) < 0)
+ sprint(buf, "???");
+ else
+ (*opcodes[i.op].f)(&opcodes[i.op], &i);
+
+ print("%.8lux %.8lux\t%s\n", pc, i.w, buf);
+ pc += 4;
+ n--;
+ }
+}
--- /dev/null
+++ b/libinterp/das-mips.c
@@ -1,0 +1,531 @@
+#include <lib9.h>
+
+/* mips native disassembler */
+
+typedef struct {
+ long addr; /* pc of instr */
+ uchar op; /* bits 31-26 */
+ uchar rs; /* bits 25-21 */
+ uchar rt; /* bits 20-16 */
+ uchar rd; /* bits 15-11 */
+ uchar sa; /* bits 10-6 */
+ uchar function; /* bits 5-0 */
+ long immediate; /* bits 15-0 */
+ ulong cofun; /* bits 24-0 */
+ ulong target; /* bits 25-0 */
+ long w0;
+ char *curr; /* current fill point */
+ char *end; /* end of buffer */
+ char *err;
+} Instr;
+
+typedef struct {
+ char *mnemonic;
+ char *mipsco;
+} Opcode;
+
+static char mipscoload[] = "r%t,%l";
+static char mipscoalui[] = "r%t,r%s,%i";
+static char mipscoalu3op[] = "r%d,r%s,r%t";
+static char mipscoboc[] = "r%s,r%t,%b";
+static char mipscoboc0[] = "r%s,%b";
+static char mipscorsrt[] = "r%s,r%t";
+static char mipscorsi[] = "r%s,%i";
+static char mipscoxxx[] = "%w";
+static char mipscofp3[] = "f%a,f%d,f%t"; /* fd,fs,ft */
+static char mipscofp2[] = "f%a,f%d"; /* fd,fs */
+static char mipscofpc[] = "f%d,f%t"; /* fs,ft */
+
+static Opcode opcodes[64] = {
+ 0, 0,
+ 0, 0,
+ "j", "%j",
+ "jal", "%j",
+ "beq", mipscoboc,
+ "bne", mipscoboc,
+ "blez", mipscoboc0,
+ "bgtz", mipscoboc0,
+ "addi", mipscoalui,
+ "addiu", mipscoalui,
+ "slti", mipscoalui,
+ "sltiu", mipscoalui,
+ "andi", mipscoalui,
+ "ori", mipscoalui,
+ "xori", mipscoalui,
+ "lui", "r%t,%u",
+ "cop0", 0,
+ "cop1", 0,
+ "cop2", 0,
+ "cop3", 0,
+ "beql", mipscoboc,
+ "bnel", mipscoboc,
+ "blezl", mipscoboc0,
+ "bgtzl", mipscoboc0,
+ "instr18", mipscoxxx,
+ "instr19", mipscoxxx,
+ "instr1A", mipscoxxx,
+ "instr1B", mipscoxxx,
+ "instr1C", mipscoxxx,
+ "instr1D", mipscoxxx,
+ "instr1E", mipscoxxx,
+ "instr1F", mipscoxxx,
+ "lb", mipscoload,
+ "lh", mipscoload,
+ "lwl", mipscoload,
+ "lw", mipscoload,
+ "lbu", mipscoload,
+ "lhu", mipscoload,
+ "lwr", mipscoload,
+ "instr27", mipscoxxx,
+ "sb", mipscoload,
+ "sh", mipscoload,
+ "swl", mipscoload,
+ "sw", mipscoload,
+ "instr2C", mipscoxxx,
+ "instr2D", mipscoxxx,
+ "swr", mipscoload,
+ "cache", "",
+ "ll", mipscoload,
+ "lwc1", mipscoload,
+ "lwc2", mipscoload,
+ "lwc3", mipscoload,
+ "instr34", mipscoxxx,
+ "ld", mipscoload,
+ "ld", mipscoload,
+ "ld", mipscoload,
+ "sc", mipscoload,
+ "swc1", mipscoload,
+ "swc2", mipscoload,
+ "swc3", mipscoload,
+ "instr3C", mipscoxxx,
+ "sd", mipscoload,
+ "sd", mipscoload,
+ "sd", mipscoload,
+};
+
+static Opcode sopcodes[64] = {
+ "sll", "r%d,r%t,$%a",
+ "special01", mipscoxxx,
+ "srl", "r%d,r%t,$%a",
+ "sra", "r%d,r%t,$%a",
+ "sllv", "r%d,r%t,R%s",
+ "special05", mipscoxxx,
+ "srlv", "r%d,r%t,r%s",
+ "srav", "r%d,r%t,r%s",
+ "jr", "r%s",
+ "jalr", "r%d,r%s",
+ "special0A", mipscoxxx,
+ "special0B", mipscoxxx,
+ "syscall", "",
+ "break", "",
+ "special0E", mipscoxxx,
+ "sync", "",
+ "mfhi", "r%d",
+ "mthi", "r%s",
+ "mflo", "r%d",
+ "mtlo", "r%s",
+ "special14", mipscoxxx,
+ "special15", mipscoxxx,
+ "special16", mipscoxxx,
+ "special17", mipscoxxx,
+ "mult", mipscorsrt,
+ "multu", mipscorsrt,
+ "div", mipscorsrt,
+ "divu", mipscorsrt,
+ "special1C", mipscoxxx,
+ "special1D", mipscoxxx,
+ "special1E", mipscoxxx,
+ "special1F", mipscoxxx,
+ "add", mipscoalu3op,
+ "addu", mipscoalu3op,
+ "sub", mipscoalu3op,
+ "subu", mipscoalu3op,
+ "and", mipscoalu3op,
+ "or", mipscoalu3op,
+ "xor", mipscoalu3op,
+ "nor", mipscoalu3op,
+ "special28", mipscoxxx,
+ "special29", mipscoxxx,
+ "slt", mipscoalu3op,
+ "sltu", mipscoalu3op,
+ "special2C", mipscoxxx,
+ "special2D", mipscoxxx,
+ "special2E", mipscoxxx,
+ "special2F", mipscoxxx,
+ "tge", mipscorsrt,
+ "tgeu", mipscorsrt,
+ "tlt", mipscorsrt,
+ "tltu", mipscorsrt,
+ "teq", mipscorsrt,
+ "special35", mipscoxxx,
+ "tne", mipscorsrt,
+ "special37", mipscoxxx,
+ "special38", mipscoxxx,
+ "special39", mipscoxxx,
+ "special3A", mipscoxxx,
+ "special3B", mipscoxxx,
+ "special3C", mipscoxxx,
+ "special3D", mipscoxxx,
+ "special3E", mipscoxxx,
+ "special3F", mipscoxxx,
+};
+
+static Opcode ropcodes[32] = {
+ "bltz", mipscoboc0,
+ "bgez", mipscoboc0,
+ "bltzl", mipscoboc0,
+ "bgezl", mipscoboc0,
+ "regimm04", mipscoxxx,
+ "regimm05", mipscoxxx,
+ "regimm06", mipscoxxx,
+ "regimm07", mipscoxxx,
+ "tgei", mipscorsi,
+ "tgeiu", mipscorsi,
+ "tlti", mipscorsi,
+ "tltiu", mipscorsi,
+ "teqi", mipscorsi,
+ "regimm0D", mipscoxxx,
+ "tnei", mipscorsi,
+ "regimm0F", mipscoxxx,
+ "bltzal", mipscoboc0,
+ "bgezal", mipscoboc0,
+ "bltzall", mipscoboc0,
+ "bgezall", mipscoboc0,
+ "regimm14", mipscoxxx,
+ "regimm15", mipscoxxx,
+ "regimm16", mipscoxxx,
+ "regimm17", mipscoxxx,
+ "regimm18", mipscoxxx,
+ "regimm19", mipscoxxx,
+ "regimm1A", mipscoxxx,
+ "regimm1B", mipscoxxx,
+ "regimm1C", mipscoxxx,
+ "regimm1D", mipscoxxx,
+ "regimm1E", mipscoxxx,
+ "regimm1F", mipscoxxx,
+};
+
+static Opcode fopcodes[64] = {
+ "add.%f", mipscofp3,
+ "sub.%f", mipscofp3,
+ "mul.%f", mipscofp3,
+ "div.%f", mipscofp3,
+ "sqrt.%f", mipscofp2,
+ "abs.%f", mipscofp2,
+ "mov.%f", mipscofp2,
+ "neg.%f", mipscofp2,
+ "finstr08", mipscoxxx,
+ "finstr09", mipscoxxx,
+ "finstr0A", mipscoxxx,
+ "finstr0B", mipscoxxx,
+ "round.w.%f", mipscofp2,
+ "trunc.w%f", mipscofp2,
+ "ceil.w%f", mipscofp2,
+ "floor.w%f", mipscofp2,
+ "finstr10", mipscoxxx,
+ "finstr11", mipscoxxx,
+ "finstr12", mipscoxxx,
+ "finstr13", mipscoxxx,
+ "finstr14", mipscoxxx,
+ "finstr15", mipscoxxx,
+ "finstr16", mipscoxxx,
+ "finstr17", mipscoxxx,
+ "finstr18", mipscoxxx,
+ "finstr19", mipscoxxx,
+ "finstr1A", mipscoxxx,
+ "finstr1B", mipscoxxx,
+ "finstr1C", mipscoxxx,
+ "finstr1D", mipscoxxx,
+ "finstr1E", mipscoxxx,
+ "finstr1F", mipscoxxx,
+ "cvt.s.%f", mipscofp2,
+ "cvt.d.%f", mipscofp2,
+ "cvt.e.%f", mipscofp2,
+ "cvt.q.%f", mipscofp2,
+ "cvt.w.%f", mipscofp2,
+ "finstr25", mipscoxxx,
+ "finstr26", mipscoxxx,
+ "finstr27", mipscoxxx,
+ "finstr28", mipscoxxx,
+ "finstr29", mipscoxxx,
+ "finstr2A", mipscoxxx,
+ "finstr2B", mipscoxxx,
+ "finstr2C", mipscoxxx,
+ "finstr2D", mipscoxxx,
+ "finstr2E", mipscoxxx,
+ "finstr2F", mipscoxxx,
+ "c.f.%f", mipscofpc,
+ "c.un.%f", mipscofpc,
+ "c.eq.%f", mipscofpc,
+ "c.ueq.%f", mipscofpc,
+ "c.olt.%f", mipscofpc,
+ "c.ult.%f", mipscofpc,
+ "c.ole.%f", mipscofpc,
+ "c.ule.%f", mipscofpc,
+ "c.sf.%f", mipscofpc,
+ "c.ngle.%f", mipscofpc,
+ "c.seq.%f", mipscofpc,
+ "c.ngl.%f", mipscofpc,
+ "c.lt.%f", mipscofpc,
+ "c.nge.%f", mipscofpc,
+ "c.le.%f", mipscofpc,
+ "c.ngt.%f", mipscofpc,
+};
+
+static char fsub[16] = {
+ 's', 'd', 'e', 'q', 'w', '?', '?', '?',
+ '?', '?', '?', '?', '?', '?', '?', '?'
+};
+
+
+static void
+bprint(Instr *i, char *fmt, ...)
+{
+ va_list arg;
+
+ va_start(arg, fmt);
+ i->curr = vseprint(i->curr, i->end, fmt, arg);
+ va_end(arg);
+}
+
+static void
+format(char *mnemonic, Instr *i, char *f)
+{
+ if (mnemonic)
+ format(0, i, mnemonic);
+ if (f == 0)
+ return;
+ if (i->curr < i->end)
+ *i->curr++ = '\t';
+ for ( ; *f && i->curr < i->end; f++) {
+ if (*f != '%') {
+ *i->curr++ = *f;
+ continue;
+ }
+ switch (*++f) {
+
+ case 's':
+ bprint(i, "%d", i->rs);
+ break;
+
+ case 't':
+ bprint(i, "%d", i->rt);
+ break;
+
+ case 'd':
+ bprint(i, "%d", i->rd);
+ break;
+
+ case 'a':
+ bprint(i, "%d", i->sa);
+ break;
+
+ case 'l':
+ bprint(i, "%d(r%d)", i->immediate, i->rs);
+ break;
+
+ case 'u':
+ case 'i':
+ bprint(i, "$%d", i->immediate);
+ break;
+
+ case 'j':
+ bprint(i, "0x%lux", (i->target<<2)|(i->addr & 0xF0000000));
+ break;
+
+ case 'b':
+ bprint(i, "0x%lux", (i->immediate<<2)+i->addr+4);
+ break;
+
+ case 'c':
+ bprint(i, "0x%lux", i->cofun);
+ break;
+
+ case 'w':
+ bprint(i, "[0x%lux]", i->w0);
+ break;
+
+ case 'f':
+ *i->curr++ = fsub[i->rs & 0x0F];
+ break;
+
+ case '\0':
+ *i->curr++ = '%';
+ return;
+
+ default:
+ bprint(i, "%%%c", *f);
+ break;
+ }
+ }
+}
+
+static void
+copz(int cop, Instr *i)
+{
+ char *f, *m, buf[16];
+
+ m = buf;
+ f = "%t,%d";
+ switch (i->rs) {
+
+ case 0:
+ sprint(buf, "mfc%d", cop);
+ break;
+
+ case 2:
+ sprint(buf, "cfc%d", cop);
+ break;
+
+ case 4:
+ sprint(buf, "mtc%d", cop);
+ break;
+
+ case 6:
+ sprint(buf, "ctc%d", cop);
+ break;
+
+ case 8:
+ f = "%b";
+ switch (i->rt) {
+
+ case 0:
+ sprint(buf, "bc%df", cop);
+ break;
+
+ case 1:
+ sprint(buf, "bc%dt", cop);
+ break;
+
+ case 2:
+ sprint(buf, "bc%dfl", cop);
+ break;
+
+ case 3:
+ sprint(buf, "bc%dtl", cop);
+ break;
+
+ default:
+ sprint(buf, "cop%d", cop);
+ f = mipscoxxx;
+ break;
+ }
+ break;
+
+ default:
+ sprint(buf, "cop%d", cop);
+ if (i->rs & 0x10)
+ f = "function %c";
+ else
+ f = mipscoxxx;
+ break;
+ }
+ format(m, i, f);
+}
+
+static void
+cop0(Instr *i)
+{
+ char *m = 0;
+
+ if (i->rs >= 0x10) {
+ switch (i->cofun) {
+
+ case 1:
+ m = "tlbr";
+ break;
+
+ case 2:
+ m = "tlbwi";
+ break;
+
+ case 6:
+ m = "tlbwr";
+ break;
+
+ case 8:
+ m = "tlbp";
+ break;
+
+ case 16:
+ m = "rfe";
+ break;
+
+ case 32:
+ m = "eret";
+ break;
+ }
+ if (m) {
+ format(m, i, 0);
+ if (i->curr < i->end)
+ *i->curr++ = 0;
+ return;
+ }
+ }
+ copz(0, i);
+}
+
+void
+das(ulong *pc)
+{
+ Instr i;
+ char buf[100];
+ Opcode *o;
+ uchar op;
+ ulong w;
+
+ w = *pc;
+
+ i.addr = (ulong)pc;
+ i.op = (w >> 26) & 0x3F;
+ i.rs = (w >> 21) & 0x1F;
+ i.rt = (w >> 16) & 0x1F;
+ i.rd = (w >> 11) & 0x1F;
+ i.sa = (w >> 6) & 0x1F;
+ i.function = w & 0x3F;
+ i.immediate = w & 0x0000FFFF;
+ if(i.immediate & 0x8000)
+ i.immediate |= ~0x0000FFFF;
+ i.cofun = w & 0x01FFFFFF;
+ i.target = w & 0x03FFFFFF;
+ i.w0 = w;
+ i.curr = buf;
+ i.end = buf+sizeof(buf)-1;
+
+ i.curr += sprint(i.curr, " %.8p %.8lux", pc, w);
+
+ o = opcodes;
+ op = i.op;
+ switch (i.op) {
+
+ case 0x00: /* SPECIAL */
+ o = sopcodes;
+ op = i.function;
+ break;
+
+ case 0x01: /* REGIMM */
+ o = ropcodes;
+ op = i.rt;
+ break;
+
+ case 0x10: /* COP0 */
+ cop0(&i);
+ break;
+
+ case 0x11: /* COP1 */
+ if (i.rs & 0x10) {
+ o = fopcodes;
+ op = i.function;
+ break;
+ }
+ /*FALLTHROUGH*/
+ case 0x12: /* COP2 */
+ case 0x13: /* COP3 */
+ copz(i.op-0x10, &i);
+ break;
+ }
+ format(o[op].mnemonic, &i, o[op].mipsco);
+ *i.curr++ = '\n';
+ *i.curr = 0;
+ print("%s", buf);
+}
--- /dev/null
+++ b/libinterp/das-power.c
@@ -1,0 +1,961 @@
+#include <lib9.h>
+
+/*
+ * disassemble PowerPC opcodes in Plan9 format
+ * Copyright © 1997 C H Forsyth (forsyth@terzarima.net)
+ */
+
+/*
+ * ibm conventions for these: bit 0 is top bit
+ * from table 10-1
+ */
+typedef struct {
+ uchar aa; /* bit 30 */
+ uchar crba; /* bits 11-15 */
+ uchar crbb; /* bits 16-20 */
+ long bd; /* bits 16-29 */
+ uchar crfd; /* bits 6-8 */
+ uchar crfs; /* bits 11-13 */
+ uchar bi; /* bits 11-15 */
+ uchar bo; /* bits 6-10 */
+ uchar crbd; /* bits 6-10 */
+ union {
+ short d; /* bits 16-31 */
+ short simm;
+ ushort uimm;
+ };
+ uchar fm; /* bits 7-14 */
+ uchar fra; /* bits 11-15 */
+ uchar frb; /* bits 16-20 */
+ uchar frc; /* bits 21-25 */
+ uchar frs; /* bits 6-10 */
+ uchar frd; /* bits 6-10 */
+ uchar crm; /* bits 12-19 */
+ long li; /* bits 6-29 || b'00' */
+ uchar lk; /* bit 31 */
+ uchar mb; /* bits 21-25 */
+ uchar me; /* bits 26-30 */
+ uchar nb; /* bits 16-20 */
+ uchar op; /* bits 0-5 */
+ uchar oe; /* bit 21 */
+ uchar ra; /* bits 11-15 */
+ uchar rb; /* bits 16-20 */
+ uchar rc; /* bit 31 */
+ union {
+ uchar rs; /* bits 6-10 */
+ uchar rd;
+ };
+ uchar sh; /* bits 16-20 */
+ ushort spr; /* bits 11-20 */
+ uchar to; /* bits 6-10 */
+ uchar imm; /* bits 16-19 */
+ ushort xo; /* bits 21-30, 22-30, 26-30, or 30 (beware) */
+ long immediate;
+ long w0;
+ long w1;
+ ulong addr; /* pc of instruction */
+ short target;
+ char *curr; /* current fill level in output buffer */
+ char *end; /* end of buffer */
+ int size; /* number of longs in instr */
+ char *err; /* errmsg */
+} Instr;
+
+#define IBF(v,a,b) (((ulong)(v)>>(32-(b)-1)) & ~(~0L<<(((b)-(a)+1))))
+#define IB(v,b) IBF((v),(b),(b))
+
+static void
+bprint(Instr *i, char *fmt, ...)
+{
+ va_list arg;
+
+ va_start(arg, fmt);
+ i->curr = vseprint(i->curr, i->end, fmt, arg);
+ va_end(arg);
+}
+
+static int
+decode(ulong *pc, Instr *i)
+{
+ ulong w;
+
+ w = *pc;
+ i->aa = IB(w, 30);
+ i->crba = IBF(w, 11, 15);
+ i->crbb = IBF(w, 16, 20);
+ i->bd = IBF(w, 16, 29)<<2;
+ if(i->bd & 0x8000)
+ i->bd |= ~0L<<16;
+ i->crfd = IBF(w, 6, 8);
+ i->crfs = IBF(w, 11, 13);
+ i->bi = IBF(w, 11, 15);
+ i->bo = IBF(w, 6, 10);
+ i->crbd = IBF(w, 6, 10);
+ i->uimm = IBF(w, 16, 31); /* also d, simm */
+ i->fm = IBF(w, 7, 14);
+ i->fra = IBF(w, 11, 15);
+ i->frb = IBF(w, 16, 20);
+ i->frc = IBF(w, 21, 25);
+ i->frs = IBF(w, 6, 10);
+ i->frd = IBF(w, 6, 10);
+ i->crm = IBF(w, 12, 19);
+ i->li = IBF(w, 6, 29)<<2;
+ if(IB(w, 6))
+ i->li |= ~0<<25;
+ i->lk = IB(w, 31);
+ i->mb = IBF(w, 21, 25);
+ i->me = IBF(w, 26, 30);
+ i->nb = IBF(w, 16, 20);
+ i->op = IBF(w, 0, 5);
+ i->oe = IB(w, 21);
+ i->ra = IBF(w, 11, 15);
+ i->rb = IBF(w, 16, 20);
+ i->rc = IB(w, 31);
+ i->rs = IBF(w, 6, 10); /* also rd */
+ i->sh = IBF(w, 16, 20);
+ i->spr = IBF(w, 11, 20);
+ i->to = IBF(w, 6, 10);
+ i->imm = IBF(w, 16, 19);
+ i->xo = IBF(w, 21, 30); /* bits 21-30, 22-30, 26-30, or 30 (beware) */
+ i->immediate = i->simm;
+ if(i->op == 15)
+ i->immediate <<= 16;
+ i->w0 = w;
+ i->target = -1;
+ i->addr = (ulong)pc;
+ i->size = 1;
+ return 1;
+}
+
+static int
+mkinstr(ulong *pc, Instr *i)
+{
+ Instr x;
+
+ if(decode(pc, i) < 0)
+ return -1;
+ /*
+ * combine ADDIS/ORI (CAU/ORIL) into MOVW
+ */
+ if (i->op == 15 && i->ra==0) {
+ if(decode(pc+1, &x) < 0)
+ return -1;
+ if (x.op == 24 && x.rs == x.ra && x.ra == i->rd) {
+ i->immediate |= (x.immediate & 0xFFFF);
+ i->w1 = x.w0;
+ i->target = x.rd;
+ i->size++;
+ return 1;
+ }
+ }
+ return 1;
+}
+
+static void
+pglobal(Instr *i, long off, char *reg)
+{
+ bprint(i, "%lux%s", off, reg);
+}
+
+static void
+address(Instr *i)
+{
+ if(i->simm < 0)
+ bprint(i, "-%lx(R%d)", -i->simm, i->ra);
+ else
+ bprint(i, "%lux(R%d)", i->immediate, i->ra);
+}
+
+static char *tcrbits[] = {"LT", "GT", "EQ", "VS"};
+static char *fcrbits[] = {"GE", "LE", "NE", "VC"};
+
+typedef struct Opcode Opcode;
+
+struct Opcode {
+ uchar op;
+ ushort xo;
+ ushort xomask;
+ char *mnemonic;
+ void (*f)(Opcode *, Instr *);
+ char *ken;
+ int flags;
+};
+
+static void format(char *, Instr *, char *);
+
+static void
+branch(Opcode *o, Instr *i)
+{
+ char buf[8];
+ int bo, bi;
+
+ bo = i->bo & ~1; /* ignore prediction bit */
+ if(bo==4 || bo==12 || bo==20) { /* simple forms */
+ if(bo != 20) {
+ bi = i->bi&3;
+ sprint(buf, "B%s%%L", bo==12? tcrbits[bi]: fcrbits[bi]);
+ format(buf, i, 0);
+ bprint(i, "\t");
+ if(i->bi > 4)
+ bprint(i, "CR(%d),", i->bi/4);
+ } else
+ format("BR%L\t", i, 0);
+ if(i->op == 16)
+ format(0, i, "%J");
+ else if(i->op == 19 && i->xo == 528)
+ format(0, i, "(CTR)");
+ else if(i->op == 19 && i->xo == 16)
+ format(0, i, "(LR)");
+ } else
+ format(o->mnemonic, i, o->ken);
+}
+
+static void
+addi(Opcode *o, Instr *i)
+{
+ if (i->op==14 && i->ra == 0)
+ format("MOVW", i, "%i,R%d");
+ else if(i->op==14 && i->simm < 0) {
+ bprint(i, "SUB\t$%d,R%d", -i->simm, i->ra);
+ if(i->rd != i->ra)
+ bprint(i, ",R%d", i->rd);
+ } else if(i->ra == i->rd) {
+ format(o->mnemonic, i, "%i");
+ bprint(i, ",R%d", i->rd);
+ } else
+ format(o->mnemonic, i, o->ken);
+}
+
+static void
+addis(Opcode *o, Instr *i)
+{
+ long v;
+
+ v = i->immediate;
+ if (i->op==15 && i->ra == 0)
+ bprint(i, "MOVW\t$%lux,R%d", v, i->rd);
+ else if(i->op==15 && v < 0) {
+ bprint(i, "SUB\t$%d,R%d", -v, i->ra);
+ if(i->rd != i->ra)
+ bprint(i, ",R%d", i->rd);
+ } else {
+ format(o->mnemonic, i, 0);
+ bprint(i, "\t$%ld,R%d", v, i->ra);
+ if(i->rd != i->ra)
+ bprint(i, ",R%d", i->rd);
+ }
+}
+
+static void
+andi(Opcode *o, Instr *i)
+{
+ if (i->ra == i->rs)
+ format(o->mnemonic, i, "%I,R%d");
+ else
+ format(o->mnemonic, i, o->ken);
+}
+
+static void
+gencc(Opcode *o, Instr *i)
+{
+ format(o->mnemonic, i, o->ken);
+}
+
+static void
+gen(Opcode *o, Instr *i)
+{
+ format(o->mnemonic, i, o->ken);
+ if (i->rc)
+ bprint(i, " [illegal Rc]");
+}
+
+static void
+ldx(Opcode *o, Instr *i)
+{
+ if(i->ra == 0)
+ format(o->mnemonic, i, "(R%b),R%d");
+ else
+ format(o->mnemonic, i, "(R%b+R%a),R%d");
+ if(i->rc)
+ bprint(i, " [illegal Rc]");
+}
+
+static void
+stx(Opcode *o, Instr *i)
+{
+ if(i->ra == 0)
+ format(o->mnemonic, i, "R%d,(R%b)");
+ else
+ format(o->mnemonic, i, "R%d,(R%b+R%a)");
+ if(i->rc && i->xo != 150)
+ bprint(i, " [illegal Rc]");
+}
+
+static void
+fldx(Opcode *o, Instr *i)
+{
+ if(i->ra == 0)
+ format(o->mnemonic, i, "(R%b),F%d");
+ else
+ format(o->mnemonic, i, "(R%b+R%a),F%d");
+ if(i->rc)
+ bprint(i, " [illegal Rc]");
+}
+
+static void
+fstx(Opcode *o, Instr *i)
+{
+ if(i->ra == 0)
+ format(o->mnemonic, i, "F%d,(R%b)");
+ else
+ format(o->mnemonic, i, "F%d,(R%b+R%a)");
+ if(i->rc)
+ bprint(i, " [illegal Rc]");
+}
+
+static void
+dcb(Opcode *o, Instr *i)
+{
+ if(i->ra == 0)
+ format(o->mnemonic, i, "(R%b)");
+ else
+ format(o->mnemonic, i, "(R%b+R%a)");
+ if(i->rd)
+ bprint(i, " [illegal Rd]");
+ if(i->rc)
+ bprint(i, " [illegal Rc]");
+}
+
+static void
+lw(Opcode *o, Instr *i, char r)
+{
+ bprint(i, "%s\t", o->mnemonic);
+ address(i);
+ bprint(i, ",%c%d", r, i->rd);
+}
+
+static void
+load(Opcode *o, Instr *i)
+{
+ lw(o, i, 'R');
+}
+
+static void
+fload(Opcode *o, Instr *i)
+{
+ lw(o, i, 'F');
+}
+
+static void
+sw(Opcode *o, Instr *i, char r)
+{
+ char *m;
+
+ m = o->mnemonic;
+ if (r == 'F')
+ format(m, i, "F%d,%l");
+ else
+ format(m, i, o->ken);
+}
+
+static void
+store(Opcode *o, Instr *i)
+{
+ sw(o, i, 'R');
+}
+
+static void
+fstore(Opcode *o, Instr *i)
+{
+ sw(o, i, 'F');
+}
+
+static void
+shifti(Opcode *o, Instr *i)
+{
+ if (i->ra == i->rs)
+ format(o->mnemonic, i, "$%k,R%a");
+ else
+ format(o->mnemonic, i, o->ken);
+}
+
+static void
+shift(Opcode *o, Instr *i)
+{
+ if (i->ra == i->rs)
+ format(o->mnemonic, i, "R%b,R%a");
+ else
+ format(o->mnemonic, i, o->ken);
+}
+
+static void
+add(Opcode *o, Instr *i)
+{
+ if (i->rd == i->ra)
+ format(o->mnemonic, i, "R%b,R%d");
+ else if (i->rd == i->rb)
+ format(o->mnemonic, i, "R%a,R%d");
+ else
+ format(o->mnemonic, i, o->ken);
+}
+
+static void
+sub(Opcode *o, Instr *i)
+{
+ format(o->mnemonic, i, 0);
+ bprint(i, "\t");
+ if(i->op == 31) {
+ bprint(i, "\tR%d,R%d", i->ra, i->rb); /* subtract Ra from Rb */
+ if(i->rd != i->rb)
+ bprint(i, ",R%d", i->rd);
+ } else
+ bprint(i, "\tR%d,$%d,R%d", i->ra, i->simm, i->rd);
+}
+
+static void
+idiv(Opcode *o, Instr *i)
+{
+ format(o->mnemonic, i, 0);
+ if(i->op == 31)
+ bprint(i, "\tR%d,R%d", i->rb, i->ra);
+ else
+ bprint(i, "\t$%d,R%d", i->simm, i->ra);
+ if(i->ra != i->rd)
+ bprint(i, ",R%d", i->rd);
+}
+
+static void
+and(Opcode *o, Instr *i)
+{
+ if (i->op == 31) {
+ /* Rb,Rs,Ra */
+ if (i->ra == i->rs)
+ format(o->mnemonic, i, "R%b,R%a");
+ else if (i->ra == i->rb)
+ format(o->mnemonic, i, "R%s,R%a");
+ else
+ format(o->mnemonic, i, o->ken);
+ } else {
+ /* imm,Rs,Ra */
+ if (i->ra == i->rs)
+ format(o->mnemonic, i, "%I,R%a");
+ else
+ format(o->mnemonic, i, o->ken);
+ }
+}
+
+static void
+or(Opcode *o, Instr *i)
+{
+ if (i->op == 31) {
+ /* Rb,Rs,Ra */
+ if (i->rs == 0 && i->ra == 0 && i->rb == 0)
+ format("NOP", i, 0);
+ else if (i->rs == i->rb)
+ format("MOVW", i, "R%b,R%a");
+ else
+ and(o, i);
+ } else
+ and(o, i);
+}
+
+static void
+shifted(Opcode *o, Instr *i)
+{
+ format(o->mnemonic, i, 0);
+ bprint(i, "\t$%lux,", (ulong)i->uimm<<16);
+ if (i->rs == i->ra)
+ bprint(i, "R%d", i->ra);
+ else
+ bprint(i, "R%d,R%d", i->rs, i->ra);
+}
+
+static void
+neg(Opcode *o, Instr *i)
+{
+ if (i->rd == i->ra)
+ format(o->mnemonic, i, "R%d");
+ else
+ format(o->mnemonic, i, o->ken);
+}
+
+static char ir2[] = "R%a,R%d"; /* reverse of IBM order */
+static char ir3[] = "R%b,R%a,R%d";
+static char ir3r[] = "R%a,R%b,R%d";
+static char il3[] = "R%b,R%s,R%a";
+static char il2u[] = "%I,R%s,R%a";
+static char il3s[] = "$%k,R%s,R%a";
+static char il2[] = "R%s,R%a";
+static char icmp3[] = "R%a,R%b,%D";
+static char cr3op[] = "%b,%a,%d";
+static char ir2i[] = "%i,R%a,R%d";
+static char fp2[] = "F%b,F%d";
+static char fp3[] = "F%b,F%a,F%d";
+static char fp3c[] = "F%c,F%a,F%d";
+static char fp4[] = "F%a,F%c,F%b,F%d";
+static char fpcmp[] = "F%a,F%b,%D";
+static char ldop[] = "%l,R%d";
+static char stop[] = "R%d,%l";
+static char fldop[] = "%l,F%d";
+static char fstop[] = "F%d,%l";
+static char rlim[] = "R%b,R%s,$%z,R%a";
+static char rlimi[] = "$%k,R%s,$%z,R%a";
+
+#define OEM IBF(~0,22,30)
+#define FP4 IBF(~0,26,30)
+#define ALL (~0)
+/*
+notes:
+ 10-26: crfD = rD>>2; rD&3 mbz
+ also, L bit (bit 10) mbz or selects 64-bit operands
+*/
+
+static Opcode opcodes[] = {
+ {31, 266, OEM, "ADD%V%C", add, ir3},
+ {31, 10, OEM, "ADDC%V%C", add, ir3},
+ {31, 138, OEM, "ADDE%V%C", add, ir3},
+ {14, 0, 0, "ADD", addi, ir2i},
+ {12, 0, 0, "ADDC", addi, ir2i},
+ {13, 0, 0, "ADDCCC", addi, ir2i},
+ {15, 0, 0, "ADD", addis, 0},
+ {31, 234, OEM, "ADDME%V%C", gencc, ir2},
+ {31, 202, OEM, "ADDZE%V%C", gencc, ir2},
+
+ {31, 28, ALL, "AND%C", and, il3},
+ {31, 60, ALL, "ANDN%C", and, il3},
+ {28, 0, 0, "ANDCC", andi, il2u},
+ {29, 0, 0, "ANDCC", shifted, 0},
+
+ {18, 0, 0, "B%L", gencc, "%j"},
+ {16, 0, 0, "BC%L", branch, "%d,%a,%J"},
+ {19, 528, ALL, "BC%L", branch, "%d,%a,(CTR)"},
+ {19, 16, ALL, "BC%L", branch, "%d,%a,(LR)"},
+
+ {31, 0, ALL, "CMP", 0, icmp3},
+ {11, 0, 0, "CMP", 0, "R%a,%i,%D"},
+ {31, 32, ALL, "CMPU", 0, icmp3},
+ {10, 0, 0, "CMPU", 0, "R%a,%I,%D"},
+
+ {31, 26, ALL, "CNTLZ%C", gencc, ir2},
+
+ {19, 257, ALL, "CRAND", gen, cr3op},
+ {19, 129, ALL, "CRANDN", gen, cr3op},
+ {19, 289, ALL, "CREQV", gen, cr3op},
+ {19, 225, ALL, "CRNAND", gen, cr3op},
+ {19, 33, ALL, "CRNOR", gen, cr3op},
+ {19, 449, ALL, "CROR", gen, cr3op},
+ {19, 417, ALL, "CRORN", gen, cr3op},
+ {19, 193, ALL, "CRXOR", gen, cr3op},
+
+ {31, 86, ALL, "DCBF", dcb, 0},
+ {31, 470, ALL, "DCBI", dcb, 0},
+ {31, 54, ALL, "DCBST", dcb, 0},
+ {31, 278, ALL, "DCBT", dcb, 0},
+ {31, 246, ALL, "DCBTST", dcb, 0},
+ {31, 1014, ALL, "DCBZ", dcb, 0},
+
+ {31, 491, OEM, "DIVW%V%C", idiv, ir3},
+ {31, 459, OEM, "DIVWU%V%C", idiv, ir3},
+
+ {31, 310, ALL, "ECIWX", ldx, 0},
+ {31, 438, ALL, "ECOWX", stx, 0},
+ {31, 854, ALL, "EIEIO", gen, 0},
+
+ {31, 284, ALL, "EQV%C", gencc, il3},
+
+ {31, 954, ALL, "EXTSB%C", gencc, il2},
+ {31, 922, ALL, "EXTSH%C", gencc, il2},
+
+ {63, 264, ALL, "FABS%C", gencc, fp2},
+ {63, 21, ALL, "FADD%C", gencc, fp3},
+ {59, 21, ALL, "FADDS%C", gencc, fp3},
+ {63, 32, ALL, "FCMPO", gen, fpcmp},
+ {63, 0, ALL, "FCMPU", gen, fpcmp},
+ {63, 14, ALL, "FCTIW%C", gencc, fp2},
+ {63, 15, ALL, "FCTIWZ%C", gencc, fp2},
+ {63, 18, ALL, "FDIV%C", gencc, fp3},
+ {59, 18, ALL, "FDIVS%C", gencc, fp3},
+ {63, 29, FP4, "FMADD%C", gencc, fp4},
+ {59, 29, FP4, "FMADDS%C", gencc, fp4},
+ {63, 72, ALL, "FMOVD%C", gencc, fp2},
+ {63, 28, FP4, "FMSUB%C", gencc, fp4},
+ {59, 28, FP4, "FMSUBS%C", gencc, fp4},
+ {63, 25, FP4, "FMUL%C", gencc, fp3c},
+ {59, 25, FP4, "FMULS%C", gencc, fp3c},
+ {63, 136, ALL, "FNABS%C", gencc, fp2},
+ {63, 40, ALL, "FNEG%C", gencc, fp2},
+ {63, 31, FP4, "FNMADD%C", gencc, fp4},
+ {59, 31, FP4, "FNMADDS%C", gencc, fp4},
+ {63, 30, FP4, "FNMSUB%C", gencc, fp4},
+ {59, 30, FP4, "FNMSUBS%C", gencc, fp4},
+ {63, 12, ALL, "FRSP%C", gencc, fp2},
+ {63, 20, FP4, "FSUB%C", gencc, fp3},
+ {59, 20, FP4, "FSUBS%C", gencc, fp3},
+
+ {31, 982, ALL, "ICBI", dcb, 0},
+ {19, 150, ALL, "ISYNC", gen, 0},
+
+ {34, 0, 0, "MOVBZ", load, ldop},
+ {35, 0, 0, "MOVBZU", load, ldop},
+ {31, 119, ALL, "MOVBZU", ldx, 0},
+ {31, 87, ALL, "MOVBZ", ldx, 0},
+ {50, 0, 0, "FMOVD", fload, fldop},
+ {51, 0, 0, "FMOVDU", fload, fldop},
+ {31, 631, ALL, "FMOVDU", fldx, 0},
+ {31, 599, ALL, "FMOVD", fldx, 0},
+ {48, 0, 0, "FMOVS", load, fldop},
+ {49, 0, 0, "FMOVSU", load, fldop},
+ {31, 567, ALL, "FMOVSU", fldx, 0},
+ {31, 535, ALL, "FMOVS", fldx, 0},
+ {42, 0, 0, "MOVH", load, ldop},
+ {43, 0, 0, "MOVHU", load, ldop},
+ {31, 375, ALL, "MOVHU", ldx, 0},
+ {31, 343, ALL, "MOVH", ldx, 0},
+ {31, 790, ALL, "MOVHBR", ldx, 0},
+ {40, 0, 0, "MOVHZ", load, ldop},
+ {41, 0, 0, "MOVHZU", load, ldop},
+ {31, 311, ALL, "MOVHZU", ldx, 0},
+ {31, 279, ALL, "MOVHZ", ldx, 0},
+ {46, 0, 0, "MOVMW", load, ldop},
+ {31, 597, ALL, "LSW", gen, "(R%a),$%n,R%d"},
+ {31, 533, ALL, "LSW", ldx, 0},
+ {31, 20, ALL, "LWAR", ldx, 0},
+ {31, 534, ALL, "MOVWBR", ldx, 0},
+ {32, 0, 0, "MOVW", load, ldop},
+ {33, 0, 0, "MOVWU", load, ldop},
+ {31, 55, ALL, "MOVWU", ldx, 0},
+ {31, 23, ALL, "MOVW", ldx, 0},
+
+ {19, 0, ALL, "MOVFL", gen, "%S,%D"},
+ {63, 64, ALL, "MOVCRFS", gen, "%S,%D"},
+ {31, 512, ALL, "MOVW", gen, "XER,%D"},
+ {31, 19, ALL, "MOVW", gen, "CR,R%d"},
+
+ {63, 583, ALL, "MOVW%C", gen, "FPSCR, F%d"}, /* mffs */
+ {31, 83, ALL, "MOVW", gen, "MSR,R%d"},
+ {31, 339, ALL, "MOVW", gen, "%P,R%d"},
+ {31, 595, ALL, "MOVW", gen, "SEG(%a),R%d"},
+ {31, 659, ALL, "MOVW", gen, "SEG(R%b),R%d"},
+ {31, 144, ALL, "MOVFL", gen, "R%s,%m,CR"},
+ {63, 70, ALL, "MTFSB0%C", gencc, "%D"},
+ {63, 38, ALL, "MTFSB1%C", gencc, "%D"},
+ {63, 711, ALL, "MOVFL%C", gencc, "F%b,%M,FPSCR"}, /* mtfsf */
+ {63, 134, ALL, "MOVFL%C", gencc, "%K,%D"},
+ {31, 146, ALL, "MOVW", gen, "R%s,MSR"},
+ {31, 467, ALL, "MOVW", gen, "R%s,%P"},
+ {31, 210, ALL, "MOVW", gen, "R%s,SEG(%a)"},
+ {31, 242, ALL, "MOVW", gen, "R%s,SEG(R%b)"},
+
+ {31, 235, OEM, "MULLW%V%C", gencc, ir3},
+ {7, 0, 0, "MULLW", idiv, "%i,R%a,R%d"},
+
+ {31, 476, ALL, "NAND%C", gencc, il3},
+ {31, 104, OEM, "NEG%V%C", neg, ir2},
+ {31, 124, ALL, "NOR%C", gencc, il3},
+ {31, 444, ALL, "OR%C", or, il3},
+ {31, 412, ALL, "ORN%C", or, il3},
+ {24, 0, 0, "OR", and, "%I,R%d,R%a"},
+ {25, 0, 0, "OR", shifted, 0},
+
+ {19, 50, ALL, "RFI", gen, 0},
+
+ {20, 0, 0, "RLWMI%C", gencc, rlimi},
+ {21, 0, 0, "RLWNM%C", gencc, rlimi},
+ {23, 0, 0, "RLWNM%C", gencc, rlim},
+
+ {17, 1, ALL, "SYSCALL", gen, 0},
+
+ {31, 24, ALL, "SLW%C", shift, il3},
+
+ {31, 792, ALL, "SRAW%C", shift, il3},
+ {31, 824, ALL, "SRAW%C", shifti, il3s},
+
+ {31, 536, ALL, "SRW%C", shift, il3},
+
+ {38, 0, 0, "MOVB", store, stop},
+ {39, 0, 0, "MOVBU", store, stop},
+ {31, 247, ALL, "MOVBU", stx, 0},
+ {31, 215, ALL, "MOVB", stx, 0},
+ {54, 0, 0, "FMOVD", fstore, fstop},
+ {55, 0, 0, "FMOVDU", fstore, fstop},
+ {31, 759, ALL, "FMOVDU", fstx, 0},
+ {31, 727, ALL, "FMOVD", fstx, 0},
+ {52, 0, 0, "FMOVS", fstore, fstop},
+ {53, 0, 0, "FMOVSU", fstore, fstop},
+ {31, 695, ALL, "FMOVSU", fstx, 0},
+ {31, 663, ALL, "FMOVS", fstx, 0},
+ {44, 0, 0, "MOVH", store, stop},
+ {31, 918, ALL, "MOVHBR", stx, 0},
+ {45, 0, 0, "MOVHU", store, stop},
+ {31, 439, ALL, "MOVHU", stx, 0},
+ {31, 407, ALL, "MOVH", stx, 0},
+ {47, 0, 0, "MOVMW", store, stop},
+ {31, 725, ALL, "STSW", gen, "R%d,$%n,(R%a)"},
+ {31, 661, ALL, "STSW", stx, 0},
+ {36, 0, 0, "MOVW", store, stop},
+ {31, 662, ALL, "MOVWBR", stx, 0},
+ {31, 150, ALL, "STWCCC", stx, 0},
+ {37, 0, 0, "MOVWU", store, stop},
+ {31, 183, ALL, "MOVWU", stx, 0},
+ {31, 151, ALL, "MOVW", stx, 0},
+
+ {31, 40, OEM, "SUB%V%C", sub, ir3},
+ {31, 8, OEM, "SUBC%V%C", sub, ir3},
+ {31, 136, OEM, "SUBE%V%C", sub, ir3},
+ {8, 0, 0, "SUBC", gen, "R%a,%i,R%d"},
+ {31, 232, OEM, "SUBME%V%C", sub, ir2},
+ {31, 200, OEM, "SUBZE%V%C", sub, ir2},
+
+ {31, 598, ALL, "SYNC", gen, 0},
+ {31, 306, ALL, "TLBIE", gen, "R%b"},
+ {31, 1010, ALL, "TLBLI", gen, "R%b"},
+ {31, 978, ALL, "TLBLD", gen, "R%b"},
+ {31, 4, ALL, "TW", gen, "%d,R%a,R%b"},
+ {3, 0, 0, "TW", gen, "%d,R%a,%i"},
+
+ {31, 316, ALL, "XOR", and, il3},
+ {26, 0, 0, "XOR", and, il2u},
+ {27, 0, 0, "XOR", shifted, 0},
+
+ {0},
+};
+
+typedef struct Spr Spr;
+struct Spr {
+ int n;
+ char *name;
+};
+
+static Spr sprname[] = {
+ {0, "MQ"},
+ {1, "XER"},
+ {268, "TBL"},
+ {269, "TBU"},
+ {8, "LR"},
+ {9, "CTR"},
+ {528, "IBAT0U"},
+ {529, "IBAT0L"},
+ {530, "IBAT1U"},
+ {531, "IBAT1L"},
+ {532, "IBAT2U"},
+ {533, "IBAT2L"},
+ {534, "IBAT3U"},
+ {535, "IBAT3L"},
+ {536, "DBAT0U"},
+ {537, "DBAT0L"},
+ {538, "DBAT1U"},
+ {539, "DBAT1L"},
+ {540, "DBAT2U"},
+ {541, "DBAT2L"},
+ {542, "DBAT3U"},
+ {543, "DBAT3L"},
+ {25, "SDR1"},
+ {19, "DAR"},
+ {272, "SPRG0"},
+ {273, "SPRG1"},
+ {274, "SPRG2"},
+ {275, "SPRG3"},
+ {18, "DSISR"},
+ {26, "SRR0"},
+ {27, "SRR1"},
+ {284, "TBLW"},
+ {285, "TBUW"},
+ {22, "DEC"},
+ {282, "EAR"},
+ {1008, "HID0"},
+ {1009, "HID1"},
+ {976, "DMISS"},
+ {977, "DCMP"},
+ {978, "HASH1"},
+ {979, "HASH2"},
+ {980, "IMISS"},
+ {981, "ICMP"},
+ {982, "RPA"},
+ {1010, "IABR"},
+ {0,0},
+};
+
+static void
+format(char *mnemonic, Instr *i, char *f)
+{
+ int n, s;
+ ulong mask;
+
+ if (mnemonic)
+ format(0, i, mnemonic);
+ if (f == 0)
+ return;
+ if (mnemonic)
+ bprint(i, "\t");
+ for ( ; *f; f++) {
+ if (*f != '%') {
+ bprint(i, "%c", *f);
+ continue;
+ }
+ switch (*++f) {
+ case 'V':
+ if(i->oe)
+ bprint(i, "V");
+ break;
+
+ case 'C':
+ if(i->rc)
+ bprint(i, "CC");
+ break;
+
+ case 'a':
+ bprint(i, "%d", i->ra);
+ break;
+
+ case 'b':
+ bprint(i, "%d", i->rb);
+ break;
+
+ case 'c':
+ bprint(i, "%d", i->frc);
+ break;
+
+ case 'd':
+ case 's':
+ bprint(i, "%d", i->rd);
+ break;
+
+ case 'S':
+ if(i->ra & 3)
+ bprint(i, "CR(INVAL:%d)", i->ra);
+ else if(i->op == 63)
+ bprint(i, "FPSCR(%d)", i->crfs);
+ else
+ bprint(i, "CR(%d)", i->crfs);
+ break;
+
+ case 'D':
+ if(i->rd & 3)
+ bprint(i, "CR(INVAL:%d)", i->rd);
+ else if(i->op == 63)
+ bprint(i, "FPSCR(%d)", i->crfd);
+ else
+ bprint(i, "CR(%d)", i->crfd);
+ break;
+
+ case 'l':
+ if(i->simm < 0)
+ bprint(i, "-%lx(R%d)", -i->simm, i->ra);
+ else
+ bprint(i, "%lx(R%d)", i->simm, i->ra);
+ break;
+
+ case 'i':
+ bprint(i, "$%ld", i->simm);
+ break;
+
+ case 'I':
+ bprint(i, "$%lx", i->uimm);
+ break;
+
+ case 'w':
+ bprint(i, "[%lux]", i->w0);
+ break;
+
+ case 'P':
+ n = ((i->spr&0x1f)<<5)|((i->spr>>5)&0x1f);
+ for(s=0; sprname[s].name; s++)
+ if(sprname[s].n == n)
+ break;
+ if(sprname[s].name) {
+ if(n < 10)
+ bprint(i, sprname[s].name);
+ else
+ bprint(i, "SPR(%s)", sprname[s].name);
+ } else
+ bprint(i, "SPR(%d)", n);
+ break;
+
+ case 'n':
+ bprint(i, "%d", i->nb==0? 32: i->nb); /* eg, pg 10-103 */
+ break;
+
+ case 'm':
+ bprint(i, "%lx", i->crm);
+ break;
+
+ case 'M':
+ bprint(i, "%lx", i->fm);
+ break;
+
+ case 'z':
+ if(i->mb <= i->me)
+ mask = ((ulong)~0L>>i->mb) & (~0L<<(31-i->me));
+ else
+ mask = ~(((ulong)~0L>>(i->me+1)) & (~0L<<(31-(i->mb-1))));
+ bprint(i, "%lux", mask);
+ break;
+
+ case 'k':
+ bprint(i, "%d", i->sh);
+ break;
+
+ case 'K':
+ bprint(i, "$%x", i->imm);
+ break;
+
+ case 'L':
+ if(i->lk)
+ bprint(i, "L");
+ break;
+
+ case 'j':
+ if(i->aa)
+ pglobal(i, i->li, "(ABS)");
+ else
+ pglobal(i, i->addr+i->li, "(REL)");
+ break;
+
+ case 'J':
+ if(i->aa)
+ pglobal(i, i->bd, "(ABS)");
+ else
+ pglobal(i, i->addr+i->bd, "(REL)");
+ break;
+
+ case '\0':
+ bprint(i, "%%");
+ return;
+
+ default:
+ bprint(i, "%%%c", *f);
+ break;
+ }
+ }
+}
+
+int
+das(ulong *pc)
+{
+ Instr i;
+ Opcode *o;
+ char buf[100];
+ int r;
+
+ memset(&i, 0, sizeof(i));
+ i.curr = buf;
+ i.end = buf+sizeof(buf)-1;
+ r = mkinstr(pc, &i);
+ i.curr += sprint(i.curr, " %.8lux %.8lux ", (ulong)pc, i.w0);
+ if(r >= 0){
+ if(i.size == 2)
+ i.curr += sprint(i.curr, "%.8lux ", i.w1);
+ for(o = opcodes; o->mnemonic != 0; o++)
+ if(i.op == o->op && (i.xo & o->xomask) == o->xo) {
+ if (o->f)
+ (*o->f)(o, &i);
+ else
+ format(o->mnemonic, &i, o->ken);
+ print("%s\n", buf);
+ return i.size;
+ }
+ }
+ strcpy(i.curr, "ILLEGAL");
+ print("%s\n", buf);
+ return i.size;
+}
--- /dev/null
+++ b/libinterp/das-sparc.c
@@ -1,0 +1,833 @@
+#include <lib9.h>
+
+ /* Sparc disassembler and related functions */
+
+typedef struct instr Instr;
+
+struct opcode
+{
+ char *mnemonic;
+ void (*f)(Instr*, char*);
+ int flag;
+};
+
+static char FRAMENAME[] = ".frame";
+
+
+struct instr
+{
+ uchar op; /* bits 31-30 */
+ uchar rd; /* bits 29-25 */
+ uchar op2; /* bits 24-22 */
+ uchar a; /* bit 29 */
+ uchar cond; /* bits 28-25 */
+ uchar op3; /* bits 24-19 */
+ uchar rs1; /* bits 18-14 */
+ uchar i; /* bit 13 */
+ uchar asi; /* bits 12-05 */
+ uchar rs2; /* bits 04-00 */
+ short simm13; /* bits 12-00, signed */
+ ushort opf; /* bits 13-05 */
+ ulong immdisp22; /* bits 21-00 */
+ ulong simmdisp22; /* bits 21-00, signed */
+ ulong disp30; /* bits 30-00 */
+ ulong imm32; /* SETHI+ADD constant */
+ int target; /* SETHI+ADD dest reg */
+ long w0;
+ long w1;
+ ulong addr; /* pc of instruction */
+ char* curr; /* current fill level in output buffer */
+ char* end; /* end of buffer */
+ int size; /* number of longs in instr */
+ char* err; /* errmsg */
+};
+
+static int dascase;
+
+static int mkinstr(ulong*, Instr*);
+static void bra1(Instr*, char*, char*[]);
+static void bra(Instr*, char*);
+static void fbra(Instr*, char*);
+static void cbra(Instr*, char*);
+static void unimp(Instr*, char*);
+static void fpop(Instr*, char*);
+static void shift(Instr*, char*);
+static void sethi(Instr*, char*);
+static void load(Instr*, char*);
+static void loada(Instr*, char*);
+static void store(Instr*, char*);
+static void storea(Instr*, char*);
+static void add(Instr*, char*);
+static void cmp(Instr*, char*);
+static void wr(Instr*, char*);
+static void jmpl(Instr*, char*);
+static void rd(Instr*, char*);
+static void loadf(Instr*, char*);
+static void storef(Instr*, char*);
+static void loadc(Instr*, char*);
+static void loadcsr(Instr*, char*);
+static void trap(Instr*, char*);
+
+static struct opcode sparcop0[8] = {
+ /* [0] */ "UNIMP", unimp, 0, /* page 137 */
+ 0, 0, 0,
+ /* [2] */ "B", bra, 0, /* page 119 */
+ 0, 0, 0,
+ /* [4] */ "SETHI", sethi, 0, /* page 104 */
+ 0, 0, 0,
+ /* [6] */ "FB", fbra, 0, /* page 121 */
+ /* [7] */ "CB", cbra, 0, /* page 123 */
+};
+
+static struct opcode sparcop2[64] = {
+ /* [0x00] */ "ADD", add, 0, /* page 108 */
+ /* [0x01] */ "AND", add, 0, /* page 106 */
+ /* [0x02] */ "OR", add, 0,
+ /* [0x03] */ "XOR", add, 0,
+ /* [0x04] */ "SUB", add, 0, /* page 110 */
+ /* [0x05] */ "ANDN", add, 0,
+ /* [0x06] */ "ORN", add, 0,
+ /* [0x07] */ "XORN", add, 0,
+ /* [0x08] */ "ADDX", add, 0,
+ 0, 0, 0,
+ /* [0x0A] */ "UMUL", add, 0, /* page 113 */
+ /* [0x0B] */ "SMUL", add, 0,
+ /* [0x0C] */ "SUBX", add, 0,
+ 0, 0, 0,
+ /* [0x0E] */ "UDIV", add, 0, /* page 115 */
+ /* [0x0F] */ "SDIV", add, 0,
+ /* [0x10] */ "ADDCC", add, 0,
+ /* [0x11] */ "ANDCC", add, 0,
+ /* [0x12] */ "ORCC", add, 0,
+ /* [0x13] */ "XORCC", add, 0,
+ /* [0x14] */ "SUBCC", cmp, 0,
+ /* [0x15] */ "ANDNCC", add, 0,
+ /* [0x16] */ "ORNCC", add, 0,
+ /* [0x17] */ "XORNCC", add, 0,
+ /* [0x18] */ "ADDXCC", add, 0,
+ 0, 0, 0,
+ /* [0x1A] */ "UMULCC", add, 0,
+ /* [0x1B] */ "SMULCC", add, 0,
+ /* [0x1C] */ "SUBXCC", add, 0,
+ 0, 0, 0,
+ /* [0x1E] */ "UDIVCC", add, 0,
+ /* [0x1F] */ "SDIVCC", add, 0,
+ /* [0x20] */ "TADD", add, 0, /* page 109 */
+ /* [0x21] */ "TSUB", add, 0, /* page 111 */
+ /* [0x22] */ "TADDCCTV", add, 0,
+ /* [0x23] */ "TSUBCCTV", add, 0,
+ /* [0x24] */ "MULSCC", add, 0, /* page 112 */
+ /* [0x25] */ "SLL", shift, 0, /* page 107 */
+ /* [0x26] */ "SRL", shift, 0,
+ /* [0x27] */ "SRA", shift, 0,
+ /* [0x28] */ "rdy", rd, 0, /* page 131 */
+ /* [0x29] */ "rdpsr", rd, 0,
+ /* [0x2A] */ "rdwim", rd, 0,
+ /* [0x2B] */ "rdtbr", rd, 0,
+ 0, 0, 0,
+ 0, 0, 0,
+ 0, 0, 0,
+ 0, 0, 0,
+ /* [0x30] */ "wry", wr, 0, /* page 133 */
+ /* [0x31] */ "wrpsr", wr, 0,
+ /* [0x32] */ "wrwim", wr, 0,
+ /* [0x33] */ "wrtbr", wr, 0,
+ /* [0x34] */ "FPOP", fpop, 0, /* page 140 */
+ /* [0x35] */ "FPOP", fpop, 0,
+ 0, 0, 0,
+ 0, 0, 0,
+ /* [0x38] */ "JMPL", jmpl, 0, /* page 126 */
+ /* [0x39] */ "RETT", add, 0, /* page 127 */
+ /* [0x3A] */ "T", trap, 0, /* page 129 */
+ /* [0x3B] */ "flush", add, 0, /* page 138 */
+ /* [0x3C] */ "SAVE", add, 0, /* page 117 */
+ /* [0x3D] */ "RESTORE", add, 0,
+};
+
+static struct opcode sparcop3[64]={
+ /* [0x00] */ "ld", load, 0,
+ /* [0x01] */ "ldub", load, 0,
+ /* [0x02] */ "lduh", load, 0,
+ /* [0x03] */ "ldd", load, 0,
+ /* [0x04] */ "st", store, 0,
+ /* [0x05] */ "stb", store, 0, /* page 95 */
+ /* [0x06] */ "sth", store, 0,
+ /* [0x07] */ "std", store, 0,
+ 0, 0, 0,
+ /* [0x09] */ "ldsb", load, 0, /* page 90 */
+ /* [0x0A] */ "ldsh", load, 0,
+ 0, 0, 0,
+ 0, 0, 0,
+ /* [0x0D] */ "ldstub", store, 0, /* page 101 */
+ 0, 0, 0,
+ /* [0x0F] */ "swap", load, 0, /* page 102 */
+ /* [0x10] */ "lda", loada, 0,
+ /* [0x11] */ "lduba", loada, 0,
+ /* [0x12] */ "lduha", loada, 0,
+ /* [0x13] */ "ldda", loada, 0,
+ /* [0x14] */ "sta", storea, 0,
+ /* [0x15] */ "stba", storea, 0,
+ /* [0x16] */ "stha", storea, 0,
+ /* [0x17] */ "stda", storea, 0,
+ 0, 0, 0,
+ /* [0x19] */ "ldsba", loada, 0,
+ /* [0x1A] */ "ldsha", loada, 0,
+ 0, 0, 0,
+ 0, 0, 0,
+ /* [0x1D] */ "ldstuba", storea, 0,
+ 0, 0, 0,
+ /* [0x1F] */ "swapa", loada, 0,
+ /* [0x20] */ "ldf", loadf, 0, /* page 92 */
+ /* [0x21] */ "ldfsr", loadf, 0,
+ 0, 0, 0,
+ /* [0x23] */ "lddf", loadf, 0,
+ /* [0x24] */ "stf", storef, 0, /* page 97 */
+ /* [0x25] */ "stfsr", storef, 0,
+ /* [0x26] */ "stdfq", storef, 0,
+ /* [0x27] */ "stdf", storef, 0,
+ 0, 0, 0,
+ 0, 0, 0,
+ 0, 0, 0,
+ 0, 0, 0,
+ 0, 0, 0,
+ 0, 0, 0,
+ 0, 0, 0,
+ 0, 0, 0,
+ /* [0x30] */ "ldc", loadc, 0, /* page 94 */
+ /* [0x31] */ "ldcsr", loadcsr,0,
+ 0, 0, 0,
+ /* [0x33] */ "lddc", loadc, 0,
+ /* [0x34] */ "stc", loadc, 0, /* page 99 */
+ /* [0x35] */ "stcsr", loadcsr,0,
+ /* [0x36] */ "stdcq", loadcsr,0,
+ /* [0x37] */ "stdc", loadc, 0,
+};
+
+static void
+bprint(Instr *i, char *fmt, ...)
+{
+ va_list arg;
+
+ va_start(arg, fmt);
+ i->curr = vseprint(i->curr, i->end, fmt, arg);
+ va_end(arg);
+}
+
+static int
+decode(ulong *pc, Instr *i)
+{
+ ulong w;
+
+ w = *pc;
+
+ i->op = (w >> 30) & 0x03;
+ i->rd = (w >> 25) & 0x1F;
+ i->op2 = (w >> 22) & 0x07;
+ i->a = (w >> 29) & 0x01;
+ i->cond = (w >> 25) & 0x0F;
+ i->op3 = (w >> 19) & 0x3F;
+ i->rs1 = (w >> 14) & 0x1F;
+ i->i = (w >> 13) & 0x01;
+ i->asi = (w >> 5) & 0xFF;
+ i->rs2 = (w >> 0) & 0x1F;
+ i->simm13 = (w >> 0) & 0x1FFF;
+ if(i->simm13 & (1<<12))
+ i->simm13 |= ~((1<<13)-1);
+ i->opf = (w >> 5) & 0x1FF;
+ i->immdisp22 = (w >> 0) & 0x3FFFFF;
+ i->simmdisp22 = i->immdisp22;
+ if(i->simmdisp22 & (1<<21))
+ i->simmdisp22 |= ~((1<<22)-1);
+ i->disp30 = (w >> 0) & 0x3FFFFFFF;
+ i->w0 = w;
+ i->target = -1;
+ i->addr = (ulong)pc;
+ i->size = 1;
+ return 1;
+}
+
+static int
+mkinstr(ulong *pc, Instr *i)
+{
+ Instr xi;
+
+ if (decode(pc, i) < 0)
+ return -1;
+ if(i->op==0 && i->op2==4 && !dascase){ /* SETHI */
+ if(decode(pc+1, &xi) < 0)
+ return -1;
+ if(xi.op == 2 && xi.op3 == 0) /* ADD */
+ if(xi.i == 1 && xi.rs1 == i->rd){ /* immediate to same reg */
+ i->imm32 = xi.simm13 + (i->immdisp22<<10);
+ i->target = xi.rd;
+ i->w1 = xi.w0;
+ i->size++;
+ return 1;
+ }
+ }
+ if(i->op==2 && i->opf==1 && !dascase){ /* FMOVS */
+ if (decode(pc+1, &xi) < 0)
+ return -1;
+ if(i->op==2 && i->opf==1) /* FMOVS */
+ if(xi.rd==i->rd+1 && xi.rs2==i->rs2+1){ /* next pair */
+ i->w1 = xi.w0;
+ i->size++;
+ }
+ }
+ return 1;
+}
+
+static int
+inst(ulong *pc)
+{
+ long disp;
+ Instr instr;
+ static char buf[128];
+ void (*f)(Instr*, char*);
+
+ memset(&instr, 0, sizeof(instr));
+ instr.curr = buf;
+ instr.end = buf+sizeof(buf)-1;
+ if(mkinstr(pc, &instr) < 0)
+ return 4;
+ switch(instr.op){
+ case 0:
+ f = sparcop0[instr.op2].f;
+ if(f)
+ (*f)(&instr, sparcop0[instr.op2].mnemonic);
+ else
+ bprint(&instr, "unknown 0x%lux", instr.w0);
+ break;
+
+ case 1:
+ disp = instr.disp30;
+ disp = (disp<<2)>>2;
+ bprint(&instr, "CALL\t0x%lux", pc+disp);
+ if (!dascase)
+ bprint(&instr, "(SB)");
+ break;
+
+ case 2:
+ f = sparcop2[instr.op3].f;
+ if(f)
+ (*f)(&instr, sparcop2[instr.op3].mnemonic);
+ else
+ bprint(&instr, "unknown 0x%lux", instr.w0);
+ break;
+
+ case 3:
+ f = sparcop3[instr.op3].f;
+ if(f)
+ (*f)(&instr, sparcop3[instr.op3].mnemonic);
+ else
+ bprint(&instr, "unknown 0x%lux", instr.w0);
+ break;
+ }
+ if (instr.err) {
+ if (instr.curr != buf)
+ bprint(&instr, "\t\t;");
+ bprint(&instr, instr.err);
+ }
+ print("\t%.8lux %s\n", (ulong)pc, buf);
+
+ return instr.size;
+}
+
+void
+das(ulong *pc, int n)
+{
+ ulong *e;
+
+ e = pc + n;
+ while(pc < e)
+ pc += inst(pc);
+}
+
+static void
+address(Instr *i)
+{
+ bprint(i, "0x%lux(R%d)", i->simm13, i->rs1);
+}
+
+static void
+unimp(Instr *i, char *m)
+{
+ bprint(i, "%s", m);
+}
+
+static char *bratab[16] = { /* page 91 */
+ /* [0x0] */ "N",
+ /* [0x1] */ "E",
+ /* [0x2] */ "LE",
+ /* [0x3] */ "L",
+ /* [0x4] */ "LEU",
+ /* [0x5] */ "CS",
+ /* [0x6] */ "NEG",
+ /* [0x7] */ "VS",
+ /* [0x8] */ "A",
+ /* [0x9] */ "NE",
+ /* [0xA] */ "G",
+ /* [0xB] */ "GE",
+ /* [0xC] */ "GU",
+ /* [0xD] */ "CC",
+ /* [0xE] */ "POS",
+ /* [0xF] */ "VC",
+};
+
+static char *fbratab[16] = { /* page 91 */
+ /* [0x0] */ "N",
+ /* [0x1] */ "NE",
+ /* [0x2] */ "LG",
+ /* [0x3] */ "UL",
+ /* [0x4] */ "L",
+ /* [0x5] */ "UG",
+ /* [0x6] */ "G",
+ /* [0x7] */ "U",
+ /* [0x8] */ "A",
+ /* [0x9] */ "E",
+ /* [0xA] */ "UE",
+ /* [0xB] */ "GE",
+ /* [0xC] */ "UGE",
+ /* [0xD] */ "LE",
+ /* [0xE] */ "ULE",
+ /* [0xF] */ "O",
+};
+
+static char *cbratab[16] = { /* page 91 */
+ /* [0x0] */ "N",
+ /* [0x1] */ "123",
+ /* [0x2] */ "12",
+ /* [0x3] */ "13",
+ /* [0x4] */ "1",
+ /* [0x5] */ "23",
+ /* [0x6] */ "2",
+ /* [0x7] */ "3",
+ /* [0x8] */ "A",
+ /* [0x9] */ "0",
+ /* [0xA] */ "03",
+ /* [0xB] */ "02",
+ /* [0xC] */ "023",
+ /* [0xD] */ "01",
+ /* [0xE] */ "013",
+ /* [0xF] */ "012",
+};
+
+static void
+bra1(Instr *i, char *m, char *tab[])
+{
+ long imm;
+
+ imm = i->simmdisp22;
+ if(i->a)
+ bprint(i, "%s%s.%c\t", m, tab[i->cond], 'A'+dascase);
+ else
+ bprint(i, "%s%s\t", m, tab[i->cond]);
+ bprint(i, "0x%lux", i->addr+4*imm);
+ if (!dascase)
+ bprint(i, "(SB)");
+}
+
+static void
+bra(Instr *i, char *m) /* page 91 */
+{
+ bra1(i, m, bratab);
+}
+
+static void
+fbra(Instr *i, char *m) /* page 93 */
+{
+ bra1(i, m, fbratab);
+}
+
+static void
+cbra(Instr *i, char *m) /* page 95 */
+{
+ bra1(i, m, cbratab);
+}
+
+static void
+trap(Instr *i, char *m) /* page 101 */
+{
+ if(i->i == 0)
+ bprint(i, "%s%s\tR%d+R%d", m, bratab[i->cond], i->rs2, i->rs1);
+ else
+ bprint(i, "%s%s\t$0x%lux+R%d", m, bratab[i->cond], i->simm13, i->rs1);
+}
+
+static void
+sethi(Instr *i, char *m) /* page 89 */
+{
+ ulong imm;
+
+ imm = i->immdisp22<<10;
+ if(dascase){
+ bprint(i, "%s\t0x%lux, R%d", m, imm, i->rd);
+ return;
+ }
+ if(imm==0 && i->rd==0){
+ bprint(i, "NOP");
+ return;
+ }
+ if(i->target < 0){
+ bprint(i, "MOVW\t$0x%lux, R%d", imm, i->rd);
+ return;
+ }
+ bprint(i, "MOVW\t$0x%lux, R%d", i->imm32, i->target);
+}
+
+static char ldtab[] = {
+ 'W',
+ 'B',
+ 'H',
+ 'D',
+};
+
+static char*
+moveinstr(int op3, char *m)
+{
+ char *s;
+ int c;
+ static char buf[8];
+
+ if(!dascase){
+ /* batshit cases */
+ if(op3 == 0xF || op3 == 0x1F)
+ return "SWAP";
+ if(op3 == 0xD || op3 == 0x1D)
+ return "TAS"; /* really LDSTUB */
+ c = ldtab[op3&3];
+ s = "";
+ if((op3&11)==1 || (op3&11)==2)
+ s="U";
+ sprint(buf, "MOV%c%s", c, s);
+ return buf;
+ }
+ return m;
+}
+
+static void
+load(Instr *i, char *m) /* page 68 */
+{
+ m = moveinstr(i->op3, m);
+ if(i->i == 0)
+ bprint(i, "%s\t(R%d+R%d), R%d", m, i->rs1, i->rs2, i->rd);
+ else{
+ bprint(i, "%s\t", m);
+ address(i);
+ bprint(i, ", R%d", i->rd);
+ }
+}
+
+static void
+loada(Instr *i, char *m) /* page 68 */
+{
+ m = moveinstr(i->op3, m);
+ if(i->i == 0)
+ bprint(i, "%s\t(R%d+R%d, %d), R%d", m, i->rs1, i->rs2, i->asi, i->rd);
+ else
+ bprint(i, "unknown ld asi 0x%lux", i->w0);
+}
+
+static void
+store(Instr *i, char *m) /* page 74 */
+{
+ m = moveinstr(i->op3, m);
+ if(i->i == 0)
+ bprint(i, "%s\tR%d, (R%d+R%d)",
+ m, i->rd, i->rs1, i->rs2);
+ else{
+ bprint(i, "%s\tR%d, ", m, i->rd);
+ address(i);
+ }
+}
+
+static void
+storea(Instr *i, char *m) /* page 74 */
+{
+ m = moveinstr(i->op3, m);
+ if(i->i == 0)
+ bprint(i, "%s\tR%d, (R%d+R%d, %d)", m, i->rd, i->rs1, i->rs2, i->asi);
+ else
+ bprint(i, "%s\tR%d, %d(R%d, %d), ???", m, i->rd, i->simm13, i->rs1, i->asi);
+}
+
+static void
+shift(Instr *i, char *m) /* page 88 */
+{
+ if(i->i == 0){
+ if(i->rs1 == i->rd)
+ if(dascase)
+ bprint(i, "%s\tR%d, R%d", m, i->rs1, i->rs2);
+ else
+ bprint(i, "%s\tR%d, R%d", m, i->rs2, i->rs1);
+ else
+ if(dascase)
+ bprint(i, "%s\tR%d, R%d, R%d", m, i->rs1, i->rs2, i->rd);
+ else
+ bprint(i, "%s\tR%d, R%d, R%d", m, i->rs2, i->rs1, i->rd);
+ }else{
+ if(i->rs1 == i->rd)
+ if(dascase)
+ bprint(i, "%s\t$%d,R%d", m, i->simm13&0x1F, i->rs1);
+ else
+ bprint(i, "%s\tR%d, $%d", m, i->rs1, i->simm13&0x1F);
+ else
+ if(dascase)
+ bprint(i, "%s\tR%d, $%d, R%d",m,i->rs1,i->simm13&0x1F,i->rd);
+ else
+ bprint(i, "%s\t$%d, R%d, R%d",m,i->simm13&0x1F,i->rs1,i->rd);
+ }
+}
+
+static void
+add(Instr *i, char *m) /* page 82 */
+{
+ if(i->i == 0){
+ if(dascase)
+ bprint(i, "%s\tR%d, R%d", m, i->rs1, i->rs2);
+ else
+ if(i->op3==2 && i->rs1==0 && i->rd) /* OR R2, R0, R1 */
+ bprint(i, "MOVW\tR%d", i->rs2);
+ else
+ bprint(i, "%s\tR%d, R%d", m, i->rs2, i->rs1);
+ }else{
+ if(dascase)
+ bprint(i, "%s\tR%d, $0x%lux", m, i->rs1, i->simm13);
+ else
+ if(i->op3==0 && i->rd && i->rs1==0) /* ADD $x, R0, R1 */
+ bprint(i, "MOVW\t$0x%lux", i->simm13);
+ else if(i->op3==0 && i->rd && i->rs1==2){
+ /* ADD $x, R2, R1 -> MOVW $x(SB), R1 */
+ bprint(i, "MOVW\t$");
+ address(i);
+ } else
+ bprint(i, "%s\t$0x%lux, R%d", m, i->simm13, i->rs1);
+ }
+ if(i->rs1 != i->rd)
+ bprint(i, ", R%d", i->rd);
+}
+
+static void
+cmp(Instr *i, char *m)
+{
+ if(dascase || i->rd){
+ add(i, m);
+ return;
+ }
+ if(i->i == 0)
+ bprint(i, "CMP\tR%d, R%d", i->rs1, i->rs2);
+ else
+ bprint(i, "CMP\tR%d, $0x%lux", i->rs1, i->simm13);
+}
+
+static char *regtab[4] =
+{
+ "Y",
+ "PSR",
+ "WIM",
+ "TBR",
+};
+
+static void
+wr(Instr *i, char *m) /* page 82 */
+{
+ if(dascase){
+ if(i->i == 0)
+ bprint(i, "%s\tR%d, R%d", m, i->rs1, i->rs2);
+ else
+ bprint(i, "%s\tR%d, $0x%lux", m, i->rs1, i->simm13);
+ }else{
+ if(i->i && i->simm13==0)
+ bprint(i, "MOVW\tR%d", i->rs1);
+ else if(i->i == 0)
+ bprint(i, "wr\tR%d, R%d", i->rs2, i->rs1);
+ else
+ bprint(i, "wr\t$0x%lux, R%d", i->simm13, i->rs1);
+ }
+ bprint(i, ", %s", regtab[i->op3&3]);
+}
+
+static void
+rd(Instr *i, char *m) /* page 103 */
+{
+ if(i->rs1==15 && i->rd==0){
+ m = "stbar";
+ if(!dascase)
+ m = "STBAR";
+ bprint(i, "%s", m);
+ }else{
+ if(!dascase)
+ m = "MOVW";
+ bprint(i, "%s\t%s, R%d", m, regtab[i->op3&3], i->rd);
+ }
+}
+
+static void
+jmpl(Instr *i, char *m) /* page 82 */
+{
+ if(i->i == 0){
+ if(i->rd == 15)
+ bprint(i, "CALL\t(R%d+R%d)", i->rs2, i->rs1);
+ else
+ bprint(i, "%s\t(R%d+R%d), R%d", m, i->rs2, i->rs1, i->rd);
+ }else{
+ if(!dascase && i->simm13==8 && i->rs1==15 && i->rd==0)
+ bprint(i, "RETURN");
+ else{
+ bprint(i, "%s\t", m);
+ address(i);
+ bprint(i, ", R%d", i->rd);
+ }
+ }
+}
+
+static void
+loadf(Instr *i, char *m) /* page 70 */
+{
+ if(!dascase){
+ m = "FMOVD";
+ if(i->op3 == 0x20)
+ m = "FMOVF";
+ else if(i->op3 == 0x21)
+ m = "MOVW";
+ }
+ if(i->i == 0)
+ bprint(i, "%s\t(R%d+R%d)", m, i->rs1, i->rs2);
+ else{
+ bprint(i, "%s\t", m);
+ address(i);
+ }
+ if(i->op3 == 0x21)
+ bprint(i, ", FSR");
+ else
+ bprint(i, ", R%d", i->rd);
+}
+
+static
+void storef(Instr *i, char *m) /* page 70 */
+{
+ if(!dascase){
+ m = "FMOVD";
+ if(i->op3 == 0x25 || i->op3 == 0x26)
+ m = "MOVW";
+ else if(i->op3 == 0x24)
+ m = "FMOVF";
+ }
+ bprint(i, "%s\t", m);
+ if(i->op3 == 0x25)
+ bprint(i, "FSR, ");
+ else if(i->op3 == 0x26)
+ bprint(i, "FQ, ");
+ else
+ bprint(i, "R%d, ", i->rd);
+ if(i->i == 0)
+ bprint(i, "(R%d+R%d)", i->rs1, i->rs2);
+ else
+ address(i);
+}
+
+static
+void loadc(Instr *i, char *m) /* page 72 */
+{
+ if(i->i == 0)
+ bprint(i, "%s\t(R%d+R%d), C%d", m, i->rs1, i->rs2, i->rd);
+ else{
+ bprint(i, "%s\t", m);
+ address(i);
+ bprint(i, ", C%d", i->rd);
+ }
+}
+
+static
+void loadcsr(Instr *i, char *m) /* page 72 */
+{
+ if(i->i == 0)
+ bprint(i, "%s\t(R%d+R%d), CSR", m, i->rs1, i->rs2);
+ else{
+ bprint(i, "%s\t", m);
+ address(i);
+ bprint(i, ", CSR");
+ }
+}
+
+static struct
+{
+ int opf;
+ char *name;
+} fptab1[] = { /* ignores rs1 */
+ 0xC4, "FITOS", /* page 109 */
+ 0xC8, "FITOD",
+ 0xCC, "FITOX",
+
+ 0xD1, "FSTOI", /* page 110 */
+ 0xD2, "FDTOI",
+ 0xD3, "FXTOI",
+
+ 0xC9, "FSTOD", /* page 111 */
+ 0xCD, "FSTOX",
+ 0xC6, "FDTOS",
+ 0xCE, "FDTOX",
+ 0xC7, "FXTOS",
+ 0xCB, "FXTOD",
+
+ 0x01, "FMOVS", /* page 112 */
+ 0x05, "FNEGS",
+ 0x09, "FABSS",
+
+ 0x29, "FSQRTS", /* page 113 */
+ 0x2A, "FSQRTD",
+ 0x2B, "FSQRTX",
+
+ 0, 0,
+};
+
+static struct{
+ int opf;
+ char *name;
+} fptab2[] = { /* uses rs1 */
+
+ 0x41, "FADDS", /* page 114 */
+ 0x42, "FADDD",
+ 0x43, "FADDX",
+ 0x45, "FSUBS",
+ 0x46, "FSUBD",
+ 0x47, "FSUBX",
+
+ 0x49, "FMULS", /* page 115 */
+ 0x4A, "FMULD",
+ 0x4B, "FMULX",
+ 0x4D, "FDIVS",
+ 0x4E, "FDIVD",
+ 0x4F, "FDIVX",
+
+ 0x51, "FCMPS", /* page 116 */
+ 0x52, "FCMPD",
+ 0x53, "FCMPX",
+ 0x55, "FCMPES",
+ 0x56, "FCMPED",
+ 0x57, "FCMPEX",
+
+ 0, 0
+};
+
+static void
+fpop(Instr *i, char *m) /* page 108-116 */
+{
+ int j;
+
+ if(dascase==0 && i->size==2){
+ bprint(i, "FMOVD\tF%d, F%d", i->rs2, i->rd);
+ return;
+ }
+ for(j=0; fptab1[j].name; j++)
+ if(fptab1[j].opf == i->opf){
+ bprint(i, "%s\tF%d, F%d", fptab1[j].name, i->rs2, i->rd);
+ return;
+ }
+ for(j=0; fptab2[j].name; j++)
+ if(fptab2[j].opf == i->opf){
+ bprint(i, "%s\tF%d, F%d, F%d", fptab2[j].name, i->rs1, i->rs2, i->rd);
+ return;
+ }
+ bprint(i, "%s%ux\tF%d, F%d, F%d", m, i->opf, i->rs1, i->rs2, i->rd);
+}
--- /dev/null
+++ b/libinterp/das-spim.c
@@ -1,0 +1,1 @@
+#include "das-mips.c"
--- /dev/null
+++ b/libinterp/das-stub.c
@@ -1,0 +1,9 @@
+#include <lib9.h>
+#include <kernel.h>
+
+void
+das(uchar *x, int n)
+{
+ USED(x);
+ USED(n);
+}
--- /dev/null
+++ b/libinterp/dec.c
@@ -1,0 +1,1811 @@
+/* Machine generated by decgen.c */
+
+#include "lib9.h"
+#include "isa.h"
+#include "interp.h"
+
+#define DIND(reg, xxx) (uchar*)((*(ulong*)(R.reg+R.PC->xxx.i.f))+R.PC->xxx.i.s)
+static void
+D00(void)
+{
+ R.s = R.MP+R.PC->s.ind;
+ R.d = R.MP+R.PC->d.ind;
+ R.m = R.d;
+}
+static void
+D01(void)
+{
+ R.s = R.MP+R.PC->s.ind;
+ R.d = R.FP+R.PC->d.ind;
+ R.m = R.d;
+}
+static void
+D02(void)
+{
+ R.s = R.MP+R.PC->s.ind;
+ R.d = (uchar*)&R.PC->d.imm;
+ R.m = R.d;
+}
+static void
+D03(void)
+{
+ R.s = R.MP+R.PC->s.ind;
+}
+static void
+D04(void)
+{
+ R.s = R.MP+R.PC->s.ind;
+ R.d = DIND(MP, d);
+ R.m = R.d;
+}
+static void
+D05(void)
+{
+ R.s = R.MP+R.PC->s.ind;
+ R.d = DIND(FP, d);
+ R.m = R.d;
+}
+static void
+D06(void)
+{
+ R.s = R.MP+R.PC->s.ind;
+}
+static void
+D07(void)
+{
+ R.s = R.MP+R.PC->s.ind;
+}
+static void
+D08(void)
+{
+ R.s = R.FP+R.PC->s.ind;
+ R.d = R.MP+R.PC->d.ind;
+ R.m = R.d;
+}
+static void
+D09(void)
+{
+ R.s = R.FP+R.PC->s.ind;
+ R.d = R.FP+R.PC->d.ind;
+ R.m = R.d;
+}
+static void
+D0A(void)
+{
+ R.s = R.FP+R.PC->s.ind;
+ R.d = (uchar*)&R.PC->d.imm;
+ R.m = R.d;
+}
+static void
+D0B(void)
+{
+ R.s = R.FP+R.PC->s.ind;
+}
+static void
+D0C(void)
+{
+ R.s = R.FP+R.PC->s.ind;
+ R.d = DIND(MP, d);
+ R.m = R.d;
+}
+static void
+D0D(void)
+{
+ R.s = R.FP+R.PC->s.ind;
+ R.d = DIND(FP, d);
+ R.m = R.d;
+}
+static void
+D0E(void)
+{
+ R.s = R.FP+R.PC->s.ind;
+}
+static void
+D0F(void)
+{
+ R.s = R.FP+R.PC->s.ind;
+}
+static void
+D10(void)
+{
+ R.s = (uchar*)&R.PC->s.imm;
+ R.d = R.MP+R.PC->d.ind;
+ R.m = R.d;
+}
+static void
+D11(void)
+{
+ R.s = (uchar*)&R.PC->s.imm;
+ R.d = R.FP+R.PC->d.ind;
+ R.m = R.d;
+}
+static void
+D12(void)
+{
+ R.s = (uchar*)&R.PC->s.imm;
+ R.d = (uchar*)&R.PC->d.imm;
+ R.m = R.d;
+}
+static void
+D13(void)
+{
+ R.s = (uchar*)&R.PC->s.imm;
+}
+static void
+D14(void)
+{
+ R.s = (uchar*)&R.PC->s.imm;
+ R.d = DIND(MP, d);
+ R.m = R.d;
+}
+static void
+D15(void)
+{
+ R.s = (uchar*)&R.PC->s.imm;
+ R.d = DIND(FP, d);
+ R.m = R.d;
+}
+static void
+D16(void)
+{
+ R.s = (uchar*)&R.PC->s.imm;
+}
+static void
+D17(void)
+{
+ R.s = (uchar*)&R.PC->s.imm;
+}
+static void
+D18(void)
+{
+ R.d = R.MP+R.PC->d.ind;
+ R.m = R.d;
+}
+static void
+D19(void)
+{
+ R.d = R.FP+R.PC->d.ind;
+ R.m = R.d;
+}
+static void
+D1A(void)
+{
+ R.d = (uchar*)&R.PC->d.imm;
+ R.m = R.d;
+}
+static void
+D1B(void)
+{
+}
+static void
+D1C(void)
+{
+ R.d = DIND(MP, d);
+ R.m = R.d;
+}
+static void
+D1D(void)
+{
+ R.d = DIND(FP, d);
+ R.m = R.d;
+}
+static void
+D1E(void)
+{
+}
+static void
+D1F(void)
+{
+}
+static void
+D20(void)
+{
+ R.s = DIND(MP, s);
+ R.d = R.MP+R.PC->d.ind;
+ R.m = R.d;
+}
+static void
+D21(void)
+{
+ R.s = DIND(MP, s);
+ R.d = R.FP+R.PC->d.ind;
+ R.m = R.d;
+}
+static void
+D22(void)
+{
+ R.s = DIND(MP, s);
+ R.d = (uchar*)&R.PC->d.imm;
+ R.m = R.d;
+}
+static void
+D23(void)
+{
+ R.s = DIND(MP, s);
+}
+static void
+D24(void)
+{
+ R.s = DIND(MP, s);
+ R.d = DIND(MP, d);
+ R.m = R.d;
+}
+static void
+D25(void)
+{
+ R.s = DIND(MP, s);
+ R.d = DIND(FP, d);
+ R.m = R.d;
+}
+static void
+D26(void)
+{
+ R.s = DIND(MP, s);
+}
+static void
+D27(void)
+{
+ R.s = DIND(MP, s);
+}
+static void
+D28(void)
+{
+ R.s = DIND(FP, s);
+ R.d = R.MP+R.PC->d.ind;
+ R.m = R.d;
+}
+static void
+D29(void)
+{
+ R.s = DIND(FP, s);
+ R.d = R.FP+R.PC->d.ind;
+ R.m = R.d;
+}
+static void
+D2A(void)
+{
+ R.s = DIND(FP, s);
+ R.d = (uchar*)&R.PC->d.imm;
+ R.m = R.d;
+}
+static void
+D2B(void)
+{
+ R.s = DIND(FP, s);
+}
+static void
+D2C(void)
+{
+ R.s = DIND(FP, s);
+ R.d = DIND(MP, d);
+ R.m = R.d;
+}
+static void
+D2D(void)
+{
+ R.s = DIND(FP, s);
+ R.d = DIND(FP, d);
+ R.m = R.d;
+}
+static void
+D2E(void)
+{
+ R.s = DIND(FP, s);
+}
+static void
+D2F(void)
+{
+ R.s = DIND(FP, s);
+}
+static void
+D30(void)
+{
+ R.d = R.MP+R.PC->d.ind;
+ R.m = R.d;
+}
+static void
+D31(void)
+{
+ R.d = R.FP+R.PC->d.ind;
+ R.m = R.d;
+}
+static void
+D32(void)
+{
+ R.d = (uchar*)&R.PC->d.imm;
+ R.m = R.d;
+}
+static void
+D33(void)
+{
+}
+static void
+D34(void)
+{
+ R.d = DIND(MP, d);
+ R.m = R.d;
+}
+static void
+D35(void)
+{
+ R.d = DIND(FP, d);
+ R.m = R.d;
+}
+static void
+D36(void)
+{
+}
+static void
+D37(void)
+{
+}
+static void
+D38(void)
+{
+ R.d = R.MP+R.PC->d.ind;
+ R.m = R.d;
+}
+static void
+D39(void)
+{
+ R.d = R.FP+R.PC->d.ind;
+ R.m = R.d;
+}
+static void
+D3A(void)
+{
+ R.d = (uchar*)&R.PC->d.imm;
+ R.m = R.d;
+}
+static void
+D3B(void)
+{
+}
+static void
+D3C(void)
+{
+ R.d = DIND(MP, d);
+ R.m = R.d;
+}
+static void
+D3D(void)
+{
+ R.d = DIND(FP, d);
+ R.m = R.d;
+}
+static void
+D3E(void)
+{
+}
+static void
+D3F(void)
+{
+}
+static void
+D40(void)
+{
+ R.s = R.MP+R.PC->s.ind;
+ R.d = R.MP+R.PC->d.ind;
+ R.t = (short)R.PC->reg;
+ R.m = &R.t;
+}
+static void
+D41(void)
+{
+ R.s = R.MP+R.PC->s.ind;
+ R.d = R.FP+R.PC->d.ind;
+ R.t = (short)R.PC->reg;
+ R.m = &R.t;
+}
+static void
+D42(void)
+{
+ R.s = R.MP+R.PC->s.ind;
+ R.d = (uchar*)&R.PC->d.imm;
+ R.t = (short)R.PC->reg;
+ R.m = &R.t;
+}
+static void
+D43(void)
+{
+ R.s = R.MP+R.PC->s.ind;
+}
+static void
+D44(void)
+{
+ R.s = R.MP+R.PC->s.ind;
+ R.d = DIND(MP, d);
+ R.t = (short)R.PC->reg;
+ R.m = &R.t;
+}
+static void
+D45(void)
+{
+ R.s = R.MP+R.PC->s.ind;
+ R.d = DIND(FP, d);
+ R.t = (short)R.PC->reg;
+ R.m = &R.t;
+}
+static void
+D46(void)
+{
+ R.s = R.MP+R.PC->s.ind;
+}
+static void
+D47(void)
+{
+ R.s = R.MP+R.PC->s.ind;
+}
+static void
+D48(void)
+{
+ R.s = R.FP+R.PC->s.ind;
+ R.d = R.MP+R.PC->d.ind;
+ R.t = (short)R.PC->reg;
+ R.m = &R.t;
+}
+static void
+D49(void)
+{
+ R.s = R.FP+R.PC->s.ind;
+ R.d = R.FP+R.PC->d.ind;
+ R.t = (short)R.PC->reg;
+ R.m = &R.t;
+}
+static void
+D4A(void)
+{
+ R.s = R.FP+R.PC->s.ind;
+ R.d = (uchar*)&R.PC->d.imm;
+ R.t = (short)R.PC->reg;
+ R.m = &R.t;
+}
+static void
+D4B(void)
+{
+ R.s = R.FP+R.PC->s.ind;
+}
+static void
+D4C(void)
+{
+ R.s = R.FP+R.PC->s.ind;
+ R.d = DIND(MP, d);
+ R.t = (short)R.PC->reg;
+ R.m = &R.t;
+}
+static void
+D4D(void)
+{
+ R.s = R.FP+R.PC->s.ind;
+ R.d = DIND(FP, d);
+ R.t = (short)R.PC->reg;
+ R.m = &R.t;
+}
+static void
+D4E(void)
+{
+ R.s = R.FP+R.PC->s.ind;
+}
+static void
+D4F(void)
+{
+ R.s = R.FP+R.PC->s.ind;
+}
+static void
+D50(void)
+{
+ R.s = (uchar*)&R.PC->s.imm;
+ R.d = R.MP+R.PC->d.ind;
+ R.t = (short)R.PC->reg;
+ R.m = &R.t;
+}
+static void
+D51(void)
+{
+ R.s = (uchar*)&R.PC->s.imm;
+ R.d = R.FP+R.PC->d.ind;
+ R.t = (short)R.PC->reg;
+ R.m = &R.t;
+}
+static void
+D52(void)
+{
+ R.s = (uchar*)&R.PC->s.imm;
+ R.d = (uchar*)&R.PC->d.imm;
+ R.t = (short)R.PC->reg;
+ R.m = &R.t;
+}
+static void
+D53(void)
+{
+ R.s = (uchar*)&R.PC->s.imm;
+}
+static void
+D54(void)
+{
+ R.s = (uchar*)&R.PC->s.imm;
+ R.d = DIND(MP, d);
+ R.t = (short)R.PC->reg;
+ R.m = &R.t;
+}
+static void
+D55(void)
+{
+ R.s = (uchar*)&R.PC->s.imm;
+ R.d = DIND(FP, d);
+ R.t = (short)R.PC->reg;
+ R.m = &R.t;
+}
+static void
+D56(void)
+{
+ R.s = (uchar*)&R.PC->s.imm;
+}
+static void
+D57(void)
+{
+ R.s = (uchar*)&R.PC->s.imm;
+}
+static void
+D58(void)
+{
+ R.d = R.MP+R.PC->d.ind;
+ R.t = (short)R.PC->reg;
+ R.m = &R.t;
+}
+static void
+D59(void)
+{
+ R.d = R.FP+R.PC->d.ind;
+ R.t = (short)R.PC->reg;
+ R.m = &R.t;
+}
+static void
+D5A(void)
+{
+ R.d = (uchar*)&R.PC->d.imm;
+ R.t = (short)R.PC->reg;
+ R.m = &R.t;
+}
+static void
+D5B(void)
+{
+}
+static void
+D5C(void)
+{
+ R.d = DIND(MP, d);
+ R.t = (short)R.PC->reg;
+ R.m = &R.t;
+}
+static void
+D5D(void)
+{
+ R.d = DIND(FP, d);
+ R.t = (short)R.PC->reg;
+ R.m = &R.t;
+}
+static void
+D5E(void)
+{
+}
+static void
+D5F(void)
+{
+}
+static void
+D60(void)
+{
+ R.s = DIND(MP, s);
+ R.d = R.MP+R.PC->d.ind;
+ R.t = (short)R.PC->reg;
+ R.m = &R.t;
+}
+static void
+D61(void)
+{
+ R.s = DIND(MP, s);
+ R.d = R.FP+R.PC->d.ind;
+ R.t = (short)R.PC->reg;
+ R.m = &R.t;
+}
+static void
+D62(void)
+{
+ R.s = DIND(MP, s);
+ R.d = (uchar*)&R.PC->d.imm;
+ R.t = (short)R.PC->reg;
+ R.m = &R.t;
+}
+static void
+D63(void)
+{
+ R.s = DIND(MP, s);
+}
+static void
+D64(void)
+{
+ R.s = DIND(MP, s);
+ R.d = DIND(MP, d);
+ R.t = (short)R.PC->reg;
+ R.m = &R.t;
+}
+static void
+D65(void)
+{
+ R.s = DIND(MP, s);
+ R.d = DIND(FP, d);
+ R.t = (short)R.PC->reg;
+ R.m = &R.t;
+}
+static void
+D66(void)
+{
+ R.s = DIND(MP, s);
+}
+static void
+D67(void)
+{
+ R.s = DIND(MP, s);
+}
+static void
+D68(void)
+{
+ R.s = DIND(FP, s);
+ R.d = R.MP+R.PC->d.ind;
+ R.t = (short)R.PC->reg;
+ R.m = &R.t;
+}
+static void
+D69(void)
+{
+ R.s = DIND(FP, s);
+ R.d = R.FP+R.PC->d.ind;
+ R.t = (short)R.PC->reg;
+ R.m = &R.t;
+}
+static void
+D6A(void)
+{
+ R.s = DIND(FP, s);
+ R.d = (uchar*)&R.PC->d.imm;
+ R.t = (short)R.PC->reg;
+ R.m = &R.t;
+}
+static void
+D6B(void)
+{
+ R.s = DIND(FP, s);
+}
+static void
+D6C(void)
+{
+ R.s = DIND(FP, s);
+ R.d = DIND(MP, d);
+ R.t = (short)R.PC->reg;
+ R.m = &R.t;
+}
+static void
+D6D(void)
+{
+ R.s = DIND(FP, s);
+ R.d = DIND(FP, d);
+ R.t = (short)R.PC->reg;
+ R.m = &R.t;
+}
+static void
+D6E(void)
+{
+ R.s = DIND(FP, s);
+}
+static void
+D6F(void)
+{
+ R.s = DIND(FP, s);
+}
+static void
+D70(void)
+{
+ R.d = R.MP+R.PC->d.ind;
+ R.t = (short)R.PC->reg;
+ R.m = &R.t;
+}
+static void
+D71(void)
+{
+ R.d = R.FP+R.PC->d.ind;
+ R.t = (short)R.PC->reg;
+ R.m = &R.t;
+}
+static void
+D72(void)
+{
+ R.d = (uchar*)&R.PC->d.imm;
+ R.t = (short)R.PC->reg;
+ R.m = &R.t;
+}
+static void
+D73(void)
+{
+}
+static void
+D74(void)
+{
+ R.d = DIND(MP, d);
+ R.t = (short)R.PC->reg;
+ R.m = &R.t;
+}
+static void
+D75(void)
+{
+ R.d = DIND(FP, d);
+ R.t = (short)R.PC->reg;
+ R.m = &R.t;
+}
+static void
+D76(void)
+{
+}
+static void
+D77(void)
+{
+}
+static void
+D78(void)
+{
+ R.d = R.MP+R.PC->d.ind;
+ R.t = (short)R.PC->reg;
+ R.m = &R.t;
+}
+static void
+D79(void)
+{
+ R.d = R.FP+R.PC->d.ind;
+ R.t = (short)R.PC->reg;
+ R.m = &R.t;
+}
+static void
+D7A(void)
+{
+ R.d = (uchar*)&R.PC->d.imm;
+ R.t = (short)R.PC->reg;
+ R.m = &R.t;
+}
+static void
+D7B(void)
+{
+}
+static void
+D7C(void)
+{
+ R.d = DIND(MP, d);
+ R.t = (short)R.PC->reg;
+ R.m = &R.t;
+}
+static void
+D7D(void)
+{
+ R.d = DIND(FP, d);
+ R.t = (short)R.PC->reg;
+ R.m = &R.t;
+}
+static void
+D7E(void)
+{
+}
+static void
+D7F(void)
+{
+}
+static void
+D80(void)
+{
+ R.s = R.MP+R.PC->s.ind;
+ R.d = R.MP+R.PC->d.ind;
+ R.m = R.FP+R.PC->reg;
+}
+static void
+D81(void)
+{
+ R.s = R.MP+R.PC->s.ind;
+ R.d = R.FP+R.PC->d.ind;
+ R.m = R.FP+R.PC->reg;
+}
+static void
+D82(void)
+{
+ R.s = R.MP+R.PC->s.ind;
+ R.d = (uchar*)&R.PC->d.imm;
+ R.m = R.FP+R.PC->reg;
+}
+static void
+D83(void)
+{
+ R.s = R.MP+R.PC->s.ind;
+}
+static void
+D84(void)
+{
+ R.s = R.MP+R.PC->s.ind;
+ R.d = DIND(MP, d);
+ R.m = R.FP+R.PC->reg;
+}
+static void
+D85(void)
+{
+ R.s = R.MP+R.PC->s.ind;
+ R.d = DIND(FP, d);
+ R.m = R.FP+R.PC->reg;
+}
+static void
+D86(void)
+{
+ R.s = R.MP+R.PC->s.ind;
+}
+static void
+D87(void)
+{
+ R.s = R.MP+R.PC->s.ind;
+}
+static void
+D88(void)
+{
+ R.s = R.FP+R.PC->s.ind;
+ R.d = R.MP+R.PC->d.ind;
+ R.m = R.FP+R.PC->reg;
+}
+static void
+D89(void)
+{
+ R.s = R.FP+R.PC->s.ind;
+ R.d = R.FP+R.PC->d.ind;
+ R.m = R.FP+R.PC->reg;
+}
+static void
+D8A(void)
+{
+ R.s = R.FP+R.PC->s.ind;
+ R.d = (uchar*)&R.PC->d.imm;
+ R.m = R.FP+R.PC->reg;
+}
+static void
+D8B(void)
+{
+ R.s = R.FP+R.PC->s.ind;
+}
+static void
+D8C(void)
+{
+ R.s = R.FP+R.PC->s.ind;
+ R.d = DIND(MP, d);
+ R.m = R.FP+R.PC->reg;
+}
+static void
+D8D(void)
+{
+ R.s = R.FP+R.PC->s.ind;
+ R.d = DIND(FP, d);
+ R.m = R.FP+R.PC->reg;
+}
+static void
+D8E(void)
+{
+ R.s = R.FP+R.PC->s.ind;
+}
+static void
+D8F(void)
+{
+ R.s = R.FP+R.PC->s.ind;
+}
+static void
+D90(void)
+{
+ R.s = (uchar*)&R.PC->s.imm;
+ R.d = R.MP+R.PC->d.ind;
+ R.m = R.FP+R.PC->reg;
+}
+static void
+D91(void)
+{
+ R.s = (uchar*)&R.PC->s.imm;
+ R.d = R.FP+R.PC->d.ind;
+ R.m = R.FP+R.PC->reg;
+}
+static void
+D92(void)
+{
+ R.s = (uchar*)&R.PC->s.imm;
+ R.d = (uchar*)&R.PC->d.imm;
+ R.m = R.FP+R.PC->reg;
+}
+static void
+D93(void)
+{
+ R.s = (uchar*)&R.PC->s.imm;
+}
+static void
+D94(void)
+{
+ R.s = (uchar*)&R.PC->s.imm;
+ R.d = DIND(MP, d);
+ R.m = R.FP+R.PC->reg;
+}
+static void
+D95(void)
+{
+ R.s = (uchar*)&R.PC->s.imm;
+ R.d = DIND(FP, d);
+ R.m = R.FP+R.PC->reg;
+}
+static void
+D96(void)
+{
+ R.s = (uchar*)&R.PC->s.imm;
+}
+static void
+D97(void)
+{
+ R.s = (uchar*)&R.PC->s.imm;
+}
+static void
+D98(void)
+{
+ R.d = R.MP+R.PC->d.ind;
+ R.m = R.FP+R.PC->reg;
+}
+static void
+D99(void)
+{
+ R.d = R.FP+R.PC->d.ind;
+ R.m = R.FP+R.PC->reg;
+}
+static void
+D9A(void)
+{
+ R.d = (uchar*)&R.PC->d.imm;
+ R.m = R.FP+R.PC->reg;
+}
+static void
+D9B(void)
+{
+}
+static void
+D9C(void)
+{
+ R.d = DIND(MP, d);
+ R.m = R.FP+R.PC->reg;
+}
+static void
+D9D(void)
+{
+ R.d = DIND(FP, d);
+ R.m = R.FP+R.PC->reg;
+}
+static void
+D9E(void)
+{
+}
+static void
+D9F(void)
+{
+}
+static void
+DA0(void)
+{
+ R.s = DIND(MP, s);
+ R.d = R.MP+R.PC->d.ind;
+ R.m = R.FP+R.PC->reg;
+}
+static void
+DA1(void)
+{
+ R.s = DIND(MP, s);
+ R.d = R.FP+R.PC->d.ind;
+ R.m = R.FP+R.PC->reg;
+}
+static void
+DA2(void)
+{
+ R.s = DIND(MP, s);
+ R.d = (uchar*)&R.PC->d.imm;
+ R.m = R.FP+R.PC->reg;
+}
+static void
+DA3(void)
+{
+ R.s = DIND(MP, s);
+}
+static void
+DA4(void)
+{
+ R.s = DIND(MP, s);
+ R.d = DIND(MP, d);
+ R.m = R.FP+R.PC->reg;
+}
+static void
+DA5(void)
+{
+ R.s = DIND(MP, s);
+ R.d = DIND(FP, d);
+ R.m = R.FP+R.PC->reg;
+}
+static void
+DA6(void)
+{
+ R.s = DIND(MP, s);
+}
+static void
+DA7(void)
+{
+ R.s = DIND(MP, s);
+}
+static void
+DA8(void)
+{
+ R.s = DIND(FP, s);
+ R.d = R.MP+R.PC->d.ind;
+ R.m = R.FP+R.PC->reg;
+}
+static void
+DA9(void)
+{
+ R.s = DIND(FP, s);
+ R.d = R.FP+R.PC->d.ind;
+ R.m = R.FP+R.PC->reg;
+}
+static void
+DAA(void)
+{
+ R.s = DIND(FP, s);
+ R.d = (uchar*)&R.PC->d.imm;
+ R.m = R.FP+R.PC->reg;
+}
+static void
+DAB(void)
+{
+ R.s = DIND(FP, s);
+}
+static void
+DAC(void)
+{
+ R.s = DIND(FP, s);
+ R.d = DIND(MP, d);
+ R.m = R.FP+R.PC->reg;
+}
+static void
+DAD(void)
+{
+ R.s = DIND(FP, s);
+ R.d = DIND(FP, d);
+ R.m = R.FP+R.PC->reg;
+}
+static void
+DAE(void)
+{
+ R.s = DIND(FP, s);
+}
+static void
+DAF(void)
+{
+ R.s = DIND(FP, s);
+}
+static void
+DB0(void)
+{
+ R.d = R.MP+R.PC->d.ind;
+ R.m = R.FP+R.PC->reg;
+}
+static void
+DB1(void)
+{
+ R.d = R.FP+R.PC->d.ind;
+ R.m = R.FP+R.PC->reg;
+}
+static void
+DB2(void)
+{
+ R.d = (uchar*)&R.PC->d.imm;
+ R.m = R.FP+R.PC->reg;
+}
+static void
+DB3(void)
+{
+}
+static void
+DB4(void)
+{
+ R.d = DIND(MP, d);
+ R.m = R.FP+R.PC->reg;
+}
+static void
+DB5(void)
+{
+ R.d = DIND(FP, d);
+ R.m = R.FP+R.PC->reg;
+}
+static void
+DB6(void)
+{
+}
+static void
+DB7(void)
+{
+}
+static void
+DB8(void)
+{
+ R.d = R.MP+R.PC->d.ind;
+ R.m = R.FP+R.PC->reg;
+}
+static void
+DB9(void)
+{
+ R.d = R.FP+R.PC->d.ind;
+ R.m = R.FP+R.PC->reg;
+}
+static void
+DBA(void)
+{
+ R.d = (uchar*)&R.PC->d.imm;
+ R.m = R.FP+R.PC->reg;
+}
+static void
+DBB(void)
+{
+}
+static void
+DBC(void)
+{
+ R.d = DIND(MP, d);
+ R.m = R.FP+R.PC->reg;
+}
+static void
+DBD(void)
+{
+ R.d = DIND(FP, d);
+ R.m = R.FP+R.PC->reg;
+}
+static void
+DBE(void)
+{
+}
+static void
+DBF(void)
+{
+}
+static void
+DC0(void)
+{
+ R.s = R.MP+R.PC->s.ind;
+ R.d = R.MP+R.PC->d.ind;
+ R.m = R.MP+R.PC->reg;
+}
+static void
+DC1(void)
+{
+ R.s = R.MP+R.PC->s.ind;
+ R.d = R.FP+R.PC->d.ind;
+ R.m = R.MP+R.PC->reg;
+}
+static void
+DC2(void)
+{
+ R.s = R.MP+R.PC->s.ind;
+ R.d = (uchar*)&R.PC->d.imm;
+ R.m = R.MP+R.PC->reg;
+}
+static void
+DC3(void)
+{
+ R.s = R.MP+R.PC->s.ind;
+}
+static void
+DC4(void)
+{
+ R.s = R.MP+R.PC->s.ind;
+ R.d = DIND(MP, d);
+ R.m = R.MP+R.PC->reg;
+}
+static void
+DC5(void)
+{
+ R.s = R.MP+R.PC->s.ind;
+ R.d = DIND(FP, d);
+ R.m = R.MP+R.PC->reg;
+}
+static void
+DC6(void)
+{
+ R.s = R.MP+R.PC->s.ind;
+}
+static void
+DC7(void)
+{
+ R.s = R.MP+R.PC->s.ind;
+}
+static void
+DC8(void)
+{
+ R.s = R.FP+R.PC->s.ind;
+ R.d = R.MP+R.PC->d.ind;
+ R.m = R.MP+R.PC->reg;
+}
+static void
+DC9(void)
+{
+ R.s = R.FP+R.PC->s.ind;
+ R.d = R.FP+R.PC->d.ind;
+ R.m = R.MP+R.PC->reg;
+}
+static void
+DCA(void)
+{
+ R.s = R.FP+R.PC->s.ind;
+ R.d = (uchar*)&R.PC->d.imm;
+ R.m = R.MP+R.PC->reg;
+}
+static void
+DCB(void)
+{
+ R.s = R.FP+R.PC->s.ind;
+}
+static void
+DCC(void)
+{
+ R.s = R.FP+R.PC->s.ind;
+ R.d = DIND(MP, d);
+ R.m = R.MP+R.PC->reg;
+}
+static void
+DCD(void)
+{
+ R.s = R.FP+R.PC->s.ind;
+ R.d = DIND(FP, d);
+ R.m = R.MP+R.PC->reg;
+}
+static void
+DCE(void)
+{
+ R.s = R.FP+R.PC->s.ind;
+}
+static void
+DCF(void)
+{
+ R.s = R.FP+R.PC->s.ind;
+}
+static void
+DD0(void)
+{
+ R.s = (uchar*)&R.PC->s.imm;
+ R.d = R.MP+R.PC->d.ind;
+ R.m = R.MP+R.PC->reg;
+}
+static void
+DD1(void)
+{
+ R.s = (uchar*)&R.PC->s.imm;
+ R.d = R.FP+R.PC->d.ind;
+ R.m = R.MP+R.PC->reg;
+}
+static void
+DD2(void)
+{
+ R.s = (uchar*)&R.PC->s.imm;
+ R.d = (uchar*)&R.PC->d.imm;
+ R.m = R.MP+R.PC->reg;
+}
+static void
+DD3(void)
+{
+ R.s = (uchar*)&R.PC->s.imm;
+}
+static void
+DD4(void)
+{
+ R.s = (uchar*)&R.PC->s.imm;
+ R.d = DIND(MP, d);
+ R.m = R.MP+R.PC->reg;
+}
+static void
+DD5(void)
+{
+ R.s = (uchar*)&R.PC->s.imm;
+ R.d = DIND(FP, d);
+ R.m = R.MP+R.PC->reg;
+}
+static void
+DD6(void)
+{
+ R.s = (uchar*)&R.PC->s.imm;
+}
+static void
+DD7(void)
+{
+ R.s = (uchar*)&R.PC->s.imm;
+}
+static void
+DD8(void)
+{
+ R.d = R.MP+R.PC->d.ind;
+ R.m = R.MP+R.PC->reg;
+}
+static void
+DD9(void)
+{
+ R.d = R.FP+R.PC->d.ind;
+ R.m = R.MP+R.PC->reg;
+}
+static void
+DDA(void)
+{
+ R.d = (uchar*)&R.PC->d.imm;
+ R.m = R.MP+R.PC->reg;
+}
+static void
+DDB(void)
+{
+}
+static void
+DDC(void)
+{
+ R.d = DIND(MP, d);
+ R.m = R.MP+R.PC->reg;
+}
+static void
+DDD(void)
+{
+ R.d = DIND(FP, d);
+ R.m = R.MP+R.PC->reg;
+}
+static void
+DDE(void)
+{
+}
+static void
+DDF(void)
+{
+}
+static void
+DE0(void)
+{
+ R.s = DIND(MP, s);
+ R.d = R.MP+R.PC->d.ind;
+ R.m = R.MP+R.PC->reg;
+}
+static void
+DE1(void)
+{
+ R.s = DIND(MP, s);
+ R.d = R.FP+R.PC->d.ind;
+ R.m = R.MP+R.PC->reg;
+}
+static void
+DE2(void)
+{
+ R.s = DIND(MP, s);
+ R.d = (uchar*)&R.PC->d.imm;
+ R.m = R.MP+R.PC->reg;
+}
+static void
+DE3(void)
+{
+ R.s = DIND(MP, s);
+}
+static void
+DE4(void)
+{
+ R.s = DIND(MP, s);
+ R.d = DIND(MP, d);
+ R.m = R.MP+R.PC->reg;
+}
+static void
+DE5(void)
+{
+ R.s = DIND(MP, s);
+ R.d = DIND(FP, d);
+ R.m = R.MP+R.PC->reg;
+}
+static void
+DE6(void)
+{
+ R.s = DIND(MP, s);
+}
+static void
+DE7(void)
+{
+ R.s = DIND(MP, s);
+}
+static void
+DE8(void)
+{
+ R.s = DIND(FP, s);
+ R.d = R.MP+R.PC->d.ind;
+ R.m = R.MP+R.PC->reg;
+}
+static void
+DE9(void)
+{
+ R.s = DIND(FP, s);
+ R.d = R.FP+R.PC->d.ind;
+ R.m = R.MP+R.PC->reg;
+}
+static void
+DEA(void)
+{
+ R.s = DIND(FP, s);
+ R.d = (uchar*)&R.PC->d.imm;
+ R.m = R.MP+R.PC->reg;
+}
+static void
+DEB(void)
+{
+ R.s = DIND(FP, s);
+}
+static void
+DEC(void)
+{
+ R.s = DIND(FP, s);
+ R.d = DIND(MP, d);
+ R.m = R.MP+R.PC->reg;
+}
+static void
+DED(void)
+{
+ R.s = DIND(FP, s);
+ R.d = DIND(FP, d);
+ R.m = R.MP+R.PC->reg;
+}
+static void
+DEE(void)
+{
+ R.s = DIND(FP, s);
+}
+static void
+DEF(void)
+{
+ R.s = DIND(FP, s);
+}
+static void
+DF0(void)
+{
+ R.d = R.MP+R.PC->d.ind;
+ R.m = R.MP+R.PC->reg;
+}
+static void
+DF1(void)
+{
+ R.d = R.FP+R.PC->d.ind;
+ R.m = R.MP+R.PC->reg;
+}
+static void
+DF2(void)
+{
+ R.d = (uchar*)&R.PC->d.imm;
+ R.m = R.MP+R.PC->reg;
+}
+static void
+DF3(void)
+{
+}
+static void
+DF4(void)
+{
+ R.d = DIND(MP, d);
+ R.m = R.MP+R.PC->reg;
+}
+static void
+DF5(void)
+{
+ R.d = DIND(FP, d);
+ R.m = R.MP+R.PC->reg;
+}
+static void
+DF6(void)
+{
+}
+static void
+DF7(void)
+{
+}
+static void
+DF8(void)
+{
+ R.d = R.MP+R.PC->d.ind;
+ R.m = R.MP+R.PC->reg;
+}
+static void
+DF9(void)
+{
+ R.d = R.FP+R.PC->d.ind;
+ R.m = R.MP+R.PC->reg;
+}
+static void
+DFA(void)
+{
+ R.d = (uchar*)&R.PC->d.imm;
+ R.m = R.MP+R.PC->reg;
+}
+static void
+DFB(void)
+{
+}
+static void
+DFC(void)
+{
+ R.d = DIND(MP, d);
+ R.m = R.MP+R.PC->reg;
+}
+static void
+DFD(void)
+{
+ R.d = DIND(FP, d);
+ R.m = R.MP+R.PC->reg;
+}
+static void
+DFE(void)
+{
+}
+static void
+DFF(void)
+{
+}
+
+void (*dec[])(void) =
+{
+ D00,
+ D01,
+ D02,
+ D03,
+ D04,
+ D05,
+ D06,
+ D07,
+ D08,
+ D09,
+ D0A,
+ D0B,
+ D0C,
+ D0D,
+ D0E,
+ D0F,
+ D10,
+ D11,
+ D12,
+ D13,
+ D14,
+ D15,
+ D16,
+ D17,
+ D18,
+ D19,
+ D1A,
+ D1B,
+ D1C,
+ D1D,
+ D1E,
+ D1F,
+ D20,
+ D21,
+ D22,
+ D23,
+ D24,
+ D25,
+ D26,
+ D27,
+ D28,
+ D29,
+ D2A,
+ D2B,
+ D2C,
+ D2D,
+ D2E,
+ D2F,
+ D30,
+ D31,
+ D32,
+ D33,
+ D34,
+ D35,
+ D36,
+ D37,
+ D38,
+ D39,
+ D3A,
+ D3B,
+ D3C,
+ D3D,
+ D3E,
+ D3F,
+ D40,
+ D41,
+ D42,
+ D43,
+ D44,
+ D45,
+ D46,
+ D47,
+ D48,
+ D49,
+ D4A,
+ D4B,
+ D4C,
+ D4D,
+ D4E,
+ D4F,
+ D50,
+ D51,
+ D52,
+ D53,
+ D54,
+ D55,
+ D56,
+ D57,
+ D58,
+ D59,
+ D5A,
+ D5B,
+ D5C,
+ D5D,
+ D5E,
+ D5F,
+ D60,
+ D61,
+ D62,
+ D63,
+ D64,
+ D65,
+ D66,
+ D67,
+ D68,
+ D69,
+ D6A,
+ D6B,
+ D6C,
+ D6D,
+ D6E,
+ D6F,
+ D70,
+ D71,
+ D72,
+ D73,
+ D74,
+ D75,
+ D76,
+ D77,
+ D78,
+ D79,
+ D7A,
+ D7B,
+ D7C,
+ D7D,
+ D7E,
+ D7F,
+ D80,
+ D81,
+ D82,
+ D83,
+ D84,
+ D85,
+ D86,
+ D87,
+ D88,
+ D89,
+ D8A,
+ D8B,
+ D8C,
+ D8D,
+ D8E,
+ D8F,
+ D90,
+ D91,
+ D92,
+ D93,
+ D94,
+ D95,
+ D96,
+ D97,
+ D98,
+ D99,
+ D9A,
+ D9B,
+ D9C,
+ D9D,
+ D9E,
+ D9F,
+ DA0,
+ DA1,
+ DA2,
+ DA3,
+ DA4,
+ DA5,
+ DA6,
+ DA7,
+ DA8,
+ DA9,
+ DAA,
+ DAB,
+ DAC,
+ DAD,
+ DAE,
+ DAF,
+ DB0,
+ DB1,
+ DB2,
+ DB3,
+ DB4,
+ DB5,
+ DB6,
+ DB7,
+ DB8,
+ DB9,
+ DBA,
+ DBB,
+ DBC,
+ DBD,
+ DBE,
+ DBF,
+ DC0,
+ DC1,
+ DC2,
+ DC3,
+ DC4,
+ DC5,
+ DC6,
+ DC7,
+ DC8,
+ DC9,
+ DCA,
+ DCB,
+ DCC,
+ DCD,
+ DCE,
+ DCF,
+ DD0,
+ DD1,
+ DD2,
+ DD3,
+ DD4,
+ DD5,
+ DD6,
+ DD7,
+ DD8,
+ DD9,
+ DDA,
+ DDB,
+ DDC,
+ DDD,
+ DDE,
+ DDF,
+ DE0,
+ DE1,
+ DE2,
+ DE3,
+ DE4,
+ DE5,
+ DE6,
+ DE7,
+ DE8,
+ DE9,
+ DEA,
+ DEB,
+ DEC,
+ DED,
+ DEE,
+ DEF,
+ DF0,
+ DF1,
+ DF2,
+ DF3,
+ DF4,
+ DF5,
+ DF6,
+ DF7,
+ DF8,
+ DF9,
+ DFA,
+ DFB,
+ DFC,
+ DFD,
+ DFE,
+ DFF
+};
--- /dev/null
+++ b/libinterp/decgen.c
@@ -1,0 +1,122 @@
+#include "lib9.h"
+#include "isa.h"
+#include "interp.h"
+
+void decgen(int);
+
+/*
+ * Force intermediate dereference of $o(o(reg)) modes to ensure intermediate
+ * pointer is valid. This is required if you want secure memory.
+ */
+#define SOFTMMU 0
+
+void
+main(void)
+{
+ int i;
+
+ print("/* Machine generated by decgen.c */\n\n");
+
+ print("#include \"lib9.h\"\n");
+ print("#include \"isa.h\"\n");
+ print("#include \"interp.h\"\n\n");
+
+ print("#define DIND(reg, xxx) (uchar*)((*(ulong*)(R.reg+R.PC->xxx.i.f))+R.PC->xxx.i.s)\n");
+
+ for(i = 0; i < 256; i++)
+ decgen(i);
+
+ print("\nvoid (*dec[])(void) =\n{\n");
+ for(i = 0; i < 256; i++)
+ print("\tD%.2uX%c\n", i, i != 255 ? ',' : ' ');
+ print("};\n");
+}
+
+void
+decgen(int addr)
+{
+ int nodst;
+
+ print("static void\nD%.2uX(void)\n{\n", addr);
+
+ switch(USRC(addr)) {
+ case AMP:
+ print("\tR.s = R.MP+R.PC->s.ind;\n");
+ break;
+ case AFP:
+ print("\tR.s = R.FP+R.PC->s.ind;\n");
+ break;
+ case AIMM:
+ print("\tR.s = (uchar*)&R.PC->s.imm;\n");
+ break;
+ case AMP|AIND:
+ if(SOFTMMU) {
+ print("R.s = R.MP+R.PC->s.i.f\n");
+ print("R.s = *(WORD**)R.s\n");
+ print("R.s = (uchar*)R.s + R.PC->s.i.s\n");
+ }
+ else
+ print("\tR.s = DIND(MP, s);\n");
+ break;
+ case AFP|AIND:
+ if(SOFTMMU) {
+ print("R.s = R.FP+R.PC->s.i.f\n");
+ print("R.s = *(WORD**)R.s\n");
+ print("R.s = (uchar*)R.s + R.PC->s.i.s\n");
+ }
+ else
+ print("\tR.s = DIND(FP, s);\n");
+ break;
+ }
+ nodst = 0;
+ switch(UDST(addr)) {
+ default:
+ nodst = 1;
+ break;
+ case AMP:
+ print("\tR.d = R.MP+R.PC->d.ind;\n");
+ break;
+ case AFP:
+ print("\tR.d = R.FP+R.PC->d.ind;\n");
+ break;
+ case AIMM:
+ print("\tR.d = (uchar*)&R.PC->d.imm;\n");
+ break;
+ case AMP|AIND:
+ if(SOFTMMU) {
+ print("R.d = R.MP+R.PC->d.i.f\n");
+ print("R.d = *(WORD**)R.d\n");
+ print("R.d = (uchar*)R.d + R.PC->d.i.s\n");
+ }
+ else
+ print("\tR.d = DIND(MP, d);\n");
+ break;
+ case AFP|AIND:
+ if(SOFTMMU) {
+ print("R.d = R.FP+R.PC->d.i.f\n");
+ print("R.d = *(WORD**)R.d\n");
+ print("R.d = (uchar*)R.d + R.PC->d.i.s\n");
+ }
+ else
+ print("\tR.d = DIND(FP, d);\n");
+ break;
+ }
+
+ if(nodst == 0)
+ switch(addr&ARM) {
+ case AXNON:
+ print("\tR.m = R.d;\n");
+ break;
+ case AXIMM:
+ print("\tR.t = (short)R.PC->reg;\n");
+ print("\tR.m = &R.t;\n");
+ break;
+ case AXINF:
+ print("\tR.m = R.FP+R.PC->reg;\n");
+ break;
+ case AXINM:
+ print("\tR.m = R.MP+R.PC->reg;\n");
+ break;
+ }
+ print("}\n");
+}
--- /dev/null
+++ b/libinterp/dlm-Inferno.c
@@ -1,0 +1,101 @@
+#include "lib9.h"
+#include "isa.h"
+#include "interp.h"
+#include "raise.h"
+#include "pool.h"
+#include "kernel.h"
+#include "dynld.h"
+
+#define DBG if(1) print
+
+extern Dynobj* dynld(int);
+extern char* enverror(void);
+
+typedef struct{char *name; long sig; void (*fn)(void*); int size; int np; uchar map[16];} Runtab;
+
+static void*
+addr(char *pre, char *suf, Dynobj *o, ulong sig)
+{
+ char buf[64];
+
+ if(o == nil || strlen(pre)+strlen(suf) > 64-1)
+ return nil;
+ snprint(buf, sizeof(buf), "%s%s", pre, suf);
+ return dynimport(o, buf, sig);
+}
+
+Module*
+newdyncode(int fd, char *path, Dir *dir)
+{
+ Module *m;
+ void *v;
+ Runtab *r;
+ Dynobj *o;
+ char *name;
+
+ DBG("module path is %s\n", path);
+ m = nil;
+ o = dynld(fd);
+ if(o == nil){
+ DBG("%s\n", enverror());
+ goto Error;
+ }
+ v = addr("XXX", "module", o, signof(char*));
+ if(v == nil)
+ goto Error;
+ name = *(char**)v;
+ DBG("module name is %s\n", name);
+ r = addr(name, "modtab", o, signof(Runtab[]));
+ if(r == nil)
+ goto Error;
+ m = builtinmod(name, r, 0);
+ m->rt = DYNMOD;
+ m->dev = dir->dev;
+ m->dtype = dir->type;
+ m->qid = dir->qid;
+ m->mtime = dir->mtime;
+ m->path = strdup(path);
+ if(m->path == nil)
+ goto Error;
+ m->dlm = o;
+ DBG("module base is 0x%p\n", o->base);
+ return m;
+Error:
+ if(o != nil)
+ dynobjfree(o);
+ if(m != nil)
+ freemod(m);
+ return nil;
+}
+
+void
+freedyncode(Module *m)
+{
+ dynobjfree(m->dlm);
+}
+
+static void
+callfn(Module *m, char *fn)
+{
+ void *v, (*f)(void);
+
+ if(m->ref != 1)
+ return;
+ v = addr(m->name, fn, m->dlm, signof(*f));
+ if(v != nil){
+ f = v;
+ (*f)();
+ }
+}
+
+void
+newdyndata(Modlink *ml)
+{
+ callfn(ml->m, "init");
+}
+
+void
+freedyndata(Modlink *ml)
+{
+ callfn(ml->m, "end");
+}
--- /dev/null
+++ b/libinterp/dlm-Nt.c
@@ -1,0 +1,48 @@
+#include "lib9.h"
+#include "isa.h"
+#include "interp.h"
+#include "raise.h"
+#include "pool.h"
+#include "kernel.h"
+#include "dynld.h"
+
+Module*
+newdyncode(int fd, char *path, Dir *dir)
+{
+ USED(fd);
+ USED(path);
+ USED(dir);
+ return nil;
+}
+
+void
+freedyncode(Module *m)
+{
+ USED(m);
+}
+
+void
+newdyndata(Modlink *ml)
+{
+ USED(ml);
+}
+
+void
+freedyndata(Modlink *ml)
+{
+ USED(ml);
+}
+
+Dynobj*
+dynld(int fd)
+{
+ USED(fd);
+ return nil;
+}
+
+int
+dynldable(int fd)
+{
+ USED(fd);
+ return 0;
+}
--- /dev/null
+++ b/libinterp/dlm-Plan9.c
@@ -1,0 +1,101 @@
+#include "lib9.h"
+#include "isa.h"
+#include "interp.h"
+#include "raise.h"
+#include "pool.h"
+#include "kernel.h"
+#include "dynld.h"
+
+#define DBG if(1) print
+
+extern Dynobj* dynld(int);
+extern char* enverror(void);
+
+typedef struct{char *name; long sig; void (*fn)(void*); int size; int np; uchar map[16];} Runtab;
+
+static void*
+addr(char *pre, char *suf, Dynobj *o, ulong sig)
+{
+ char buf[64];
+
+ if(o == nil || strlen(pre)+strlen(suf) > 64-1)
+ return nil;
+ snprint(buf, sizeof(buf), "%s%s", pre, suf);
+ return dynimport(o, buf, sig);
+}
+
+Module*
+newdyncode(int fd, char *path, Dir *dir)
+{
+ Module *m;
+ void *v;
+ Runtab *r;
+ Dynobj *o;
+ char *name;
+
+ DBG("module path is %s\n", path);
+ m = nil;
+ o = dynld(fd);
+ if(o == nil){
+ DBG("%s\n", enverror());
+ goto Error;
+ }
+ v = addr("XXX", "module", o, signof(char*));
+ if(v == nil)
+ goto Error;
+ name = *(char**)v;
+ DBG("module name is %s\n", name);
+ r = addr(name, "modtab", o, signof(Runtab[]));
+ if(r == nil)
+ goto Error;
+ m = builtinmod(name, r, 0);
+ m->rt = DYNMOD;
+ m->dev = dir->dev;
+ m->dtype = dir->type;
+ m->qid = dir->qid;
+ m->mtime = dir->mtime;
+ m->path = strdup(path);
+ if(m->path == nil)
+ goto Error;
+ m->dlm = o;
+ DBG("module base is 0x%p\n", o->base);
+ return m;
+Error:
+ if(o != nil)
+ dynobjfree(o);
+ if(m != nil)
+ freemod(m);
+ return nil;
+}
+
+void
+freedyncode(Module *m)
+{
+ dynobjfree(m->dlm);
+}
+
+static void
+callfn(Module *m, char *fn)
+{
+ void *v, (*f)(void);
+
+ if(m->ref != 1)
+ return;
+ v = addr(m->name, fn, m->dlm, signof(*f));
+ if(v != nil){
+ f = v;
+ (*f)();
+ }
+}
+
+void
+newdyndata(Modlink *ml)
+{
+ callfn(ml->m, "init");
+}
+
+void
+freedyndata(Modlink *ml)
+{
+ callfn(ml->m, "end");
+}
--- /dev/null
+++ b/libinterp/dlm-Posix.c
@@ -1,0 +1,48 @@
+#include "lib9.h"
+#include "isa.h"
+#include "interp.h"
+#include "raise.h"
+#include "pool.h"
+#include "kernel.h"
+#include "dynld.h"
+
+Module*
+newdyncode(int fd, char *path, Dir *dir)
+{
+ USED(fd);
+ USED(path);
+ USED(dir);
+ return nil;
+}
+
+void
+freedyncode(Module *m)
+{
+ USED(m);
+}
+
+void
+newdyndata(Modlink *ml)
+{
+ USED(ml);
+}
+
+void
+freedyndata(Modlink *ml)
+{
+ USED(ml);
+}
+
+Dynobj*
+dynld(int fd)
+{
+ USED(fd);
+ return nil;
+}
+
+int
+dynldable(int fd)
+{
+ USED(fd);
+ return 0;
+}
--- /dev/null
+++ b/libinterp/draw.c
@@ -1,0 +1,2345 @@
+#include <lib9.h>
+#include <kernel.h>
+#include "interp.h"
+#include "isa.h"
+#include "runt.h"
+#include "raise.h"
+#include "drawmod.h"
+#include "draw.h"
+#include "drawif.h"
+#include "memdraw.h"
+#include "memlayer.h"
+
+/*
+ * When a Display is remote, it must be locked to synchronize the
+ * outgoing message buffer with the refresh demon, which runs as a
+ * different process. When it is local, the refresh demon does nothing
+ * and it is sufficient to use the interpreter's own acquire/release protection
+ * to lock the buffer.
+ *
+ * Most action to the buffer is caused by calls from Limbo, so locking at
+ * the top before going into the library is good enough. However, the
+ * garbage collector can call the free routines at other times, so they
+ * need to protect themselves whether called through the Draw module
+ * or not; hence the need for check against recursive locking in lockdisplay().
+ * This also means that we needn't lock around calls to destroy if it's
+ * extra work to do so.
+ */
+
+typedef struct Cache Cache;
+typedef struct DRef DRef;
+typedef struct DDisplay DDisplay;
+typedef struct DImage DImage;
+typedef struct DScreen DScreen;
+typedef struct DFont DFont;
+
+struct Cache
+{
+ int ref;
+ char* name;
+ Display*display;
+ union{
+ Subfont* sf;
+ Font* f;
+ void* ptr;
+ }u;
+ Cache* next;
+};
+
+/* not visible to Limbo; used only for internal reference counting */
+struct DRef
+{
+ int ref;
+ Display* display;
+};
+
+struct DDisplay
+{
+ Draw_Display drawdisplay;
+ Display* display;
+ DRef* dref;
+};
+
+struct DImage
+{
+ Draw_Image drawimage;
+ Image* image;
+ void* refreshptr;
+ DRef* dref;
+ int flush;
+};
+
+struct DScreen
+{
+ Draw_Screen drawscreen;
+ Screen* screen;
+ DRef* dref;
+};
+
+struct DFont
+{
+ Draw_Font drawfont;
+ Font* font;
+ DRef* dref;
+};
+
+Cache* sfcache[BIHASH];
+Cache* fcache[BIHASH];
+void* cacheqlock;
+
+static Cache *cachelookup(Cache**, Display*, char*);
+
+uchar fontmap[] = Draw_Font_map;
+uchar imagemap[] = Draw_Image_map;
+uchar screenmap[] = Draw_Screen_map;
+uchar displaymap[] = Draw_Display_map;
+
+Type* TFont;
+Type* TImage;
+Type* TScreen;
+Type* TDisplay;
+
+Draw_Image* allocdrawimage(DDisplay*, Draw_Rect, ulong, Image*, int, int);
+Draw_Image* color(DDisplay*, ulong);
+Draw_Screen *mkdrawscreen(Screen*, Draw_Display*);
+
+char deffontname[] = "*default*";
+void refreshslave(Display*);
+void subfont_close(Subfont*);
+void freeallsubfonts(Display*);
+
+void
+drawmodinit(void)
+{
+ TFont = dtype(freedrawfont, sizeof(DFont), fontmap, sizeof(fontmap));
+ TImage = dtype(freedrawimage, sizeof(DImage), imagemap, sizeof(imagemap));
+ TScreen = dtype(freedrawscreen, sizeof(DScreen), screenmap, sizeof(screenmap));
+ TDisplay = dtype(freedrawdisplay, sizeof(DDisplay), displaymap, sizeof(displaymap));
+ builtinmod("$Draw", Drawmodtab, Drawmodlen);
+}
+
+static int
+drawhash(char *s)
+{
+ int h;
+
+ h = 0;
+ while(*s){
+ h += *s++;
+ h <<= 1;
+ if(h & (1<<8))
+ h |= 1;
+ }
+ return (h&0xFFFF)%BIHASH;
+}
+
+static Cache*
+cachelookup(Cache *cache[], Display *d, char *name)
+{
+ Cache *c;
+
+ libqlock(cacheqlock);
+ c = cache[drawhash(name)];
+ while(c!=nil && (d!=c->display || strcmp(name, c->name)!=0))
+ c = c->next;
+ libqunlock(cacheqlock);
+ return c;
+}
+
+Cache*
+cacheinstall(Cache **cache, Display *d, char *name, void *ptr, char *type)
+{
+ Cache *c;
+ int hash;
+
+ USED(type);
+ c = cachelookup(cache, d, name);
+ if(c){
+/* print("%s %s already in cache\n", type, name); /**/
+ return nil;
+ }
+ c = malloc(sizeof(Cache));
+ if(c == nil)
+ return nil;
+ hash = drawhash(name);
+ c->ref = 0; /* will be incremented by caller */
+ c->display = d;
+ c->name = strdup(name);
+ c->u.ptr = ptr;
+ libqlock(cacheqlock);
+ c->next = cache[hash];
+ cache[hash] = c;
+ libqunlock(cacheqlock);
+ return c;
+}
+
+void
+cacheuninstall(Cache **cache, Display *d, char *name, char *type)
+{
+ Cache *c, *prev;
+ int hash;
+
+ hash = drawhash(name);
+ libqlock(cacheqlock);
+ c = cache[hash];
+ if(c == nil){
+ Notfound:
+ libqunlock(cacheqlock);
+ print("%s not in %s cache\n", name, type);
+ return;
+ }
+ prev = nil;
+ while(c!=nil && (d!=c->display || strcmp(name, c->name)!=0)){
+ prev = c;
+ c = c->next;
+ }
+ if(c == nil)
+ goto Notfound;
+ if(prev == 0)
+ cache[hash] = c->next;
+ else
+ prev->next = c->next;
+ libqunlock(cacheqlock);
+ free(c->name);
+ free(c);
+}
+
+Image*
+lookupimage(Draw_Image *di)
+{
+ Display *disp;
+ Image *i;
+ int locked;
+
+ if(di == H || D2H(di)->t != TImage)
+ return nil;
+ i = ((DImage*)di)->image;
+ if(i == nil)
+ return nil;
+ if(!eqrect(IRECT(di->clipr), i->clipr) || di->repl!=i->repl){
+ disp = i->display;
+ locked = lockdisplay(disp);
+ replclipr(i, di->repl, IRECT(di->clipr));
+ if(locked)
+ unlockdisplay(disp);
+ }
+ return i;
+}
+
+Screen*
+lookupscreen(Draw_Screen *ds)
+{
+ if(ds == H || D2H(ds)->t != TScreen)
+ return nil;
+ return ((DScreen*)ds)->screen;
+}
+
+Font*
+lookupfont(Draw_Font *df)
+{
+ if(df == H || D2H(df)->t != TFont)
+ return nil;
+ return ((DFont*)df)->font;
+}
+
+Display*
+lookupdisplay(Draw_Display *dd)
+{
+ if(dd == H || D2H(dd)->t != TDisplay)
+ return nil;
+ return ((DDisplay*)dd)->display;
+}
+
+Image*
+checkimage(Draw_Image *di)
+{
+ Image *i;
+
+ if(di == H)
+ error("nil Image");
+ i = lookupimage(di);
+ if(i == nil)
+ error(exType);
+ return i;
+}
+
+Screen*
+checkscreen(Draw_Screen *ds)
+{
+ Screen *s;
+
+ if(ds == H)
+ error("nil Screen");
+ s = lookupscreen(ds);
+ if(s == nil)
+ error(exType);
+ return s;
+}
+
+Font*
+checkfont(Draw_Font *df)
+{
+ Font *f;
+
+ if(df == H)
+ error("nil Font");
+ f = lookupfont(df);
+ if(f == nil)
+ error(exType);
+ return f;
+}
+
+Display*
+checkdisplay(Draw_Display *dd)
+{
+ Display *d;
+
+ if(dd == H)
+ error("nil Display");
+ d = lookupdisplay(dd);
+ if(d == nil)
+ error(exType);
+ return d;
+}
+
+void
+Display_allocate(void *fp)
+{
+ F_Display_allocate *f;
+ char buf[128], *dev;
+ Subfont *df;
+ Display *display;
+ DDisplay *dd;
+ Heap *h;
+ Draw_Rect r;
+ DRef *dr;
+ Cache *c;
+
+ f = fp;
+ destroy(*f->ret);
+ *f->ret = H;
+ if(cacheqlock == nil){
+ cacheqlock = libqlalloc();
+ if(cacheqlock == nil)
+ return;
+ }
+ dev = string2c(f->dev);
+ if(dev[0] == 0)
+ dev = 0;
+ display = initdisplay(dev, dev, nil); /* TO DO: win, error */
+ if(display == 0)
+ return;
+
+ dr = malloc(sizeof(DRef));
+ if(dr == nil)
+ return;
+ h = heap(TDisplay);
+ if(h == H){
+ closedisplay(display);
+ return;
+ }
+ dd = H2D(DDisplay*, h);
+ dd->display = display;
+ *f->ret = &dd->drawdisplay;
+ dd->dref = dr;
+ display->limbo = dr;
+ dr->display = display;
+ dr->ref = 1;
+ df = getdefont(display);
+ if(df){
+ display->defaultsubfont = df;
+ sprint(buf, "%d %d\n0 %d\t%s\n", df->height, df->ascent,
+ df->n-1, deffontname);
+ display->defaultfont = buildfont(display, buf, deffontname);
+ if(display->defaultfont){
+ c = cacheinstall(fcache, display, deffontname, display->defaultfont, "font");
+ if(c)
+ c->ref++;
+ /* else BUG? */
+ }
+ }
+
+ R2R(r, display->image->r);
+ dd->drawdisplay.image = allocdrawimage(dd, r, display->image->chan, display->image, 0, 0);
+ R2R(r, display->white->r);
+ dd->drawdisplay.black = allocdrawimage(dd, r, display->black->chan, display->black, 1, 0);
+ dd->drawdisplay.white = allocdrawimage(dd, r, display->white->chan, display->white, 1, 0);
+ dd->drawdisplay.opaque = allocdrawimage(dd, r, display->opaque->chan, display->opaque, 1, 0);
+ dd->drawdisplay.transparent = allocdrawimage(dd, r, display->transparent->chan, display->transparent, 1, 0);
+
+ /* don't call unlockdisplay because the qlock was left up by initdisplay */
+ libqunlock(display->qlock);
+}
+
+void
+Display_getwindow(void *fp)
+{
+ F_Display_getwindow *f;
+ Display *disp;
+ int locked;
+ Image *image;
+ Screen *screen;
+ char *wn;
+ void *r;
+
+ f = fp;
+ r = f->ret->t0;
+ f->ret->t0 = H;
+ destroy(r);
+ r = f->ret->t1;
+ f->ret->t1 = H;
+ destroy(r);
+ disp = checkdisplay(f->d);
+ if(f->winname == H)
+ wn = "/dev/winname";
+ else
+ wn = string2c(f->winname);
+ if(f->image == H)
+ image = nil;
+ else
+ image = checkimage(f->image);
+ if(f->screen == H)
+ screen = nil;
+ else
+ screen = checkscreen(f->screen);
+ locked = lockdisplay(disp);
+ if(gengetwindow(disp, wn, &image, &screen, f->backup) < 0){
+ /* TO DO: eliminate f->image and f->screen's references to Image and Screen */
+ goto Return;
+ }
+ if(screen != nil){
+ if(f->screen != H){
+ f->ret->t0 = f->screen;
+ D2H(f->screen)->ref++;
+ }else
+ f->ret->t0 = mkdrawscreen(screen, f->d);
+ }
+ if(image != nil){
+ if(f->image != H){
+ f->ret->t1 = f->image;
+ D2H(f->image)->ref++;
+ }else
+ f->ret->t1 = mkdrawimage(image, f->ret->t0, f->d, nil);
+ }
+
+Return:
+ if(locked)
+ unlockdisplay(disp);
+}
+
+void
+Display_startrefresh(void *fp)
+{
+ F_Display_startrefresh *f;
+ Display *disp;
+
+ f = fp;
+ disp = checkdisplay(f->d);
+ refreshslave(disp);
+}
+
+void
+display_dec(void *v)
+{
+ DRef *dr;
+ Display *d;
+ int locked;
+
+ dr = v;
+ if(dr->ref-- != 1)
+ return;
+
+ d = dr->display;
+ locked = lockdisplay(d);
+ font_close(d->defaultfont);
+ subfont_close(d->defaultsubfont);
+ if(locked)
+ unlockdisplay(d);
+ freeallsubfonts(d);
+ closedisplay(d);
+ free(dr);
+}
+
+void
+freedrawdisplay(Heap *h, int swept)
+{
+ DDisplay *dd;
+ Display *d;
+
+ dd = H2D(DDisplay*, h);
+
+ if(!swept) {
+ destroy(dd->drawdisplay.image);
+ destroy(dd->drawdisplay.black);
+ destroy(dd->drawdisplay.white);
+ destroy(dd->drawdisplay.opaque);
+ destroy(dd->drawdisplay.transparent);
+ }
+ /* we've now released dd->image etc.; make sure they're not freed again */
+ d = dd->display;
+ d->image = nil;
+ d->white = nil;
+ d->black = nil;
+ d->opaque = nil;
+ d->transparent = nil;
+ display_dec(dd->dref);
+ /* Draw_Display header will be freed by caller */
+}
+
+void
+Display_color(void *fp)
+{
+ F_Display_color *f;
+ Display *d;
+ int locked;
+
+ f = fp;
+ destroy(*f->ret);
+ *f->ret = H;
+ d = checkdisplay(f->d);
+ locked = lockdisplay(d);
+ *f->ret = color((DDisplay*)f->d, f->color);
+ if(locked)
+ unlockdisplay(d);
+}
+
+void
+Image_flush(void *fp)
+{
+ F_Image_flush *f;
+ Image *d;
+ DImage *di;
+ int locked;
+
+ f = fp;
+ d = checkimage(f->win);
+ di = (DImage*)f->win;
+ switch(f->func){
+ case 0: /* Draw->Flushoff */
+ di->flush = 0;
+ break;
+ case 1: /* Draw->Flushon */
+ di->flush = 1;
+ /* fall through */
+ case 2: /* Draw->Flushnow */
+ locked = lockdisplay(d->display);
+ if(d->id==0 || d->screen!=0)
+ flushimage(d->display, 1);
+ if(locked)
+ unlockdisplay(d->display);
+ break;
+ default:
+ error(exInval);
+ }
+}
+
+void
+checkflush(Draw_Image *dst)
+{
+ DImage *di;
+
+ di = (DImage*)dst;
+ if(di->flush && (di->image->id==0 || di->image->screen!=nil))
+ flushimage(di->image->display, 1);
+}
+
+static void
+imagedraw(void *fp, int op)
+{
+ F_Image_draw *f;
+ Image *d, *s, *m;
+ int locked;
+
+ f = fp;
+ d = checkimage(f->dst);
+ if(f->src == H)
+ s = d->display->black;
+ else
+ s = checkimage(f->src);
+ if(f->matte == H)
+ m = d->display->white; /* ones */
+ else
+ m = checkimage(f->matte);
+ if(d->display!=s->display || d->display!=m->display)
+ return;
+ locked = lockdisplay(d->display);
+ drawop(d, IRECT(f->r), s, m, IPOINT(f->p), op);
+ checkflush(f->dst);
+ if(locked)
+ unlockdisplay(d->display);
+}
+
+void
+Image_draw(void *fp)
+{
+ imagedraw(fp, SoverD);
+}
+
+void
+Image_drawop(void *fp)
+{
+ F_Image_drawop *f;
+
+ f = fp;
+ imagedraw(fp, f->op);
+}
+
+static void
+imagegendraw(void *fp, int op)
+{
+ F_Image_gendraw *f;
+ Image *d, *s, *m;
+ int locked;
+
+ f = fp;
+ d = checkimage(f->dst);
+ if(f->src == H)
+ s = d->display->black;
+ else
+ s = checkimage(f->src);
+ if(f->matte == H)
+ m = d->display->white; /* ones */
+ else
+ m = checkimage(f->matte);
+ if(d->display!=s->display || d->display!=m->display)
+ return;
+ locked = lockdisplay(d->display);
+ gendrawop(d, IRECT(f->r), s, IPOINT(f->p0), m, IPOINT(f->p1), op);
+ checkflush(f->dst);
+ if(locked)
+ unlockdisplay(d->display);
+}
+
+void
+Image_gendraw(void *fp)
+{
+ imagegendraw(fp, SoverD);
+}
+
+void
+Image_gendrawop(void *fp)
+{
+ F_Image_gendrawop *f;
+
+ f = fp;
+ imagegendraw(fp, f->op);
+}
+
+static void
+drawline(void *fp, int op)
+{
+ F_Image_line *f;
+ Image *d, *s;
+ int locked;
+
+ f = fp;
+ d = checkimage(f->dst);
+ s = checkimage(f->src);
+ if(d->display != s->display || f->radius < 0)
+ return;
+ locked = lockdisplay(d->display);
+ lineop(d, IPOINT(f->p0), IPOINT(f->p1), f->end0, f->end1, f->radius, s, IPOINT(f->sp), op);
+ checkflush(f->dst);
+ if(locked)
+ unlockdisplay(d->display);
+}
+
+void
+Image_line(void *fp)
+{
+ drawline(fp, SoverD);
+}
+
+void
+Image_lineop(void *fp)
+{
+ F_Image_lineop *f;
+
+ f = fp;
+ drawline(fp, f->op);
+}
+
+static void
+drawsplinepoly(void *fp, int smooth, int op)
+{
+ F_Image_poly *f;
+ Image *d, *s;
+ int locked;
+
+ f = fp;
+ d = checkimage(f->dst);
+ s = checkimage(f->src);
+ if(d->display != s->display|| f->radius < 0)
+ return;
+ locked = lockdisplay(d->display);
+ /* sleazy: we know that Draw_Points have same shape as Points */
+ if(smooth)
+ bezsplineop(d, (Point*)f->p->data, f->p->len,
+ f->end0, f->end1, f->radius, s, IPOINT(f->sp), op);
+ else
+ polyop(d, (Point*)f->p->data, f->p->len, f->end0,
+ f->end1, f->radius, s, IPOINT(f->sp), op);
+ checkflush(f->dst);
+ if(locked)
+ unlockdisplay(d->display);
+}
+
+void
+Image_poly(void *fp)
+{
+ drawsplinepoly(fp, 0, SoverD);
+}
+
+void
+Image_polyop(void *fp)
+{
+ F_Image_polyop *f;
+
+ f = fp;
+ drawsplinepoly(fp, 0, f->op);
+}
+
+void
+Image_bezspline(void *fp)
+{
+ drawsplinepoly(fp, 1, SoverD);
+}
+
+void
+Image_bezsplineop(void *fp)
+{
+ F_Image_bezsplineop *f;
+
+ f = fp;
+ drawsplinepoly(fp, 1, f->op);
+}
+
+static void
+drawbezier(void *fp, int op)
+{
+ F_Image_bezier *f;
+ Image *d, *s;
+ int locked;
+
+ f = fp;
+ d = checkimage(f->dst);
+ s = checkimage(f->src);
+ if(d->display != s->display || f->radius < 0)
+ return;
+ locked = lockdisplay(d->display);
+ bezierop(d, IPOINT(f->a), IPOINT(f->b), IPOINT(f->c),
+ IPOINT(f->d), f->end0, f->end1, f->radius, s, IPOINT(f->sp), op);
+ checkflush(f->dst);
+ if(locked)
+ unlockdisplay(d->display);
+}
+
+void
+Image_bezier(void *fp)
+{
+ drawbezier(fp, SoverD);
+}
+
+void
+Image_bezierop(void *fp)
+{
+ F_Image_bezierop *f;
+
+ f = fp;
+ drawbezier(fp, f->op);
+}
+
+static void
+drawfillbezier(void *fp, int op)
+{
+ F_Image_fillbezier *f;
+ Image *d, *s;
+ int locked;
+
+ f = fp;
+ d = checkimage(f->dst);
+ s = checkimage(f->src);
+ if(d->display != s->display)
+ return;
+ locked = lockdisplay(d->display);
+ fillbezierop(d, IPOINT(f->a), IPOINT(f->b), IPOINT(f->c),
+ IPOINT(f->d), f->wind, s, IPOINT(f->sp), op);
+ checkflush(f->dst);
+ if(locked)
+ unlockdisplay(d->display);
+}
+
+void
+Image_fillbezier(void *fp)
+{
+ drawfillbezier(fp, SoverD);
+}
+
+void
+Image_fillbezierop(void *fp)
+{
+ F_Image_fillbezierop *f;
+
+ f = fp;
+ drawfillbezier(fp, f->op);
+}
+
+static void
+drawfillsplinepoly(void *fp, int smooth, int op)
+{
+ F_Image_fillpoly *f;
+ Image *d, *s;
+ int locked;
+
+ f = fp;
+ d = checkimage(f->dst);
+ s = checkimage(f->src);
+ if(d->display != s->display)
+ return;
+ locked = lockdisplay(d->display);
+ /* sleazy: we know that Draw_Points have same shape as Points */
+ if(smooth)
+ fillbezsplineop(d, (Point*)f->p->data, f->p->len,
+ f->wind, s, IPOINT(f->sp), op);
+ else
+ fillpolyop(d, (Point*)f->p->data, f->p->len,
+ f->wind, s, IPOINT(f->sp), op);
+ checkflush(f->dst);
+ if(locked)
+ unlockdisplay(d->display);
+}
+
+void
+Image_fillpoly(void *fp)
+{
+ drawfillsplinepoly(fp, 0, SoverD);
+}
+
+void
+Image_fillpolyop(void *fp)
+{
+ F_Image_fillpolyop *f;
+
+ f = fp;
+ drawfillsplinepoly(fp, 0, f->op);
+}
+
+void
+Image_fillbezspline(void *fp)
+{
+ drawfillsplinepoly(fp, 1, SoverD);
+}
+
+void
+Image_fillbezsplineop(void *fp)
+{
+ F_Image_fillbezsplineop *f;
+
+ f = fp;
+ drawfillsplinepoly(fp, 1, f->op);
+}
+
+static void
+drawarcellipse(void *fp, int isarc, int alpha, int phi, int op)
+{
+ F_Image_arc *f;
+ Image *d, *s;
+ int locked;
+
+ f = fp;
+ d = checkimage(f->dst);
+ s = checkimage(f->src);
+ if(d->display != s->display || f->thick < 0 || f->a<0 || f->b<0)
+ return;
+
+ locked = lockdisplay(d->display);
+ if(isarc)
+ arcop(d, IPOINT(f->c), f->a, f->b, f->thick, s,
+ IPOINT(f->sp), alpha, phi, op);
+ else
+ ellipseop(d, IPOINT(f->c), f->a, f->b, f->thick, s,
+ IPOINT(f->sp), op);
+ checkflush(f->dst);
+ if(locked)
+ unlockdisplay(d->display);
+}
+
+void
+Image_ellipse(void *fp)
+{
+ drawarcellipse(fp, 0, 0, 0, SoverD);
+}
+
+void
+Image_ellipseop(void *fp)
+{
+ F_Image_ellipseop *f;
+
+ f = fp;
+ drawarcellipse(fp, 0, 0, 0, f->op);
+}
+
+void
+Image_arc(void *fp)
+{
+ F_Image_arc *f;
+
+ f = fp;
+ drawarcellipse(fp, 1, f->alpha, f->phi, SoverD);
+}
+
+void
+Image_arcop(void *fp)
+{
+ F_Image_arcop *f;
+
+ f = fp;
+ drawarcellipse(fp, 1, f->alpha, f->phi, f->op);
+}
+
+static void
+drawfillarcellipse(void *fp, int isarc, int alpha, int phi, int op)
+{
+ F_Image_fillarc *f;
+ Image *d, *s;
+ int locked;
+
+ f = fp;
+ d = checkimage(f->dst);
+ s = checkimage(f->src);
+ if(d->display != s->display || f->a<0 || f->b<0)
+ return;
+
+ locked = lockdisplay(d->display);
+ if(isarc)
+ fillarcop(d, IPOINT(f->c), f->a, f->b, s, IPOINT(f->sp), alpha, phi, op);
+ else
+ fillellipseop(d, IPOINT(f->c), f->a, f->b, s, IPOINT(f->sp), op);
+ checkflush(f->dst);
+ if(locked)
+ unlockdisplay(d->display);
+}
+
+void
+Image_fillellipse(void *fp)
+{
+ drawfillarcellipse(fp, 0, 0, 0, SoverD);
+}
+
+void
+Image_fillellipseop(void *fp)
+{
+ F_Image_fillellipseop *f;
+
+ f = fp;
+ drawfillarcellipse(fp, 0, 0, 0, f->op);
+}
+
+void
+Image_fillarc(void *fp)
+{
+ F_Image_fillarc *f;
+
+ f = fp;
+ drawfillarcellipse(fp, 1, f->alpha, f->phi, SoverD);
+}
+
+void
+Image_fillarcop(void *fp)
+{
+ F_Image_fillarcop *f;
+
+ f = fp;
+ drawfillarcellipse(fp, 1, f->alpha, f->phi, f->op);
+}
+
+static void
+drawtext(void *fp, int op)
+{
+ F_Image_text *f;
+ Font *font;
+ Point pt;
+ Image *s, *d;
+ String *str;
+ int locked;
+
+ f = fp;
+ if(f->dst == H || f->src == H)
+ goto Return;
+ if(f->font == H || f->str == H)
+ goto Return;
+ str = f->str;
+ d = checkimage(f->dst);
+ s = checkimage(f->src);
+ font = checkfont(f->font);
+ if(d->display!=s->display || d->display!=font->display)
+ return;
+ locked = lockdisplay(d->display);
+ if(str->len >= 0)
+ pt = stringnop(d, IPOINT(f->p), s, IPOINT(f->sp), font, str->Sascii, str->len, op);
+ else
+ pt = runestringnop(d, IPOINT(f->p), s, IPOINT(f->sp), font, str->Srune, -str->len, op);
+ checkflush(f->dst);
+ if(locked)
+ unlockdisplay(d->display);
+ Return:
+ P2P(*f->ret, pt);
+}
+
+void
+Image_text(void *fp)
+{
+ drawtext(fp, SoverD);
+}
+
+void
+Image_textop(void *fp)
+{
+ F_Image_textop *f;
+
+ f = fp;
+ drawtext(fp, f->op);
+}
+
+static void
+drawtextbg(void *fp, int op)
+{
+ F_Image_textbg *f;
+ Font *font;
+ Point pt;
+ Image *s, *d, *bg;
+ String *str;
+ int locked;
+
+ f = fp;
+ if(f->dst == H || f->src == H)
+ goto Return;
+ if(f->font == H || f->str == H)
+ goto Return;
+ str = f->str;
+ d = checkimage(f->dst);
+ s = checkimage(f->src);
+ bg = checkimage(f->bg);
+ font = checkfont(f->font);
+ if(d->display!=s->display || d->display!=font->display)
+ return;
+ locked = lockdisplay(d->display);
+ if(str->len >= 0)
+ pt = stringnbgop(d, IPOINT(f->p), s, IPOINT(f->sp), font, str->Sascii, str->len, bg, IPOINT(f->bgp), op);
+ else
+ pt = runestringnbgop(d, IPOINT(f->p), s, IPOINT(f->sp), font, str->Srune, -str->len, bg, IPOINT(f->bgp), op);
+ checkflush(f->dst);
+ if(locked)
+ unlockdisplay(d->display);
+ Return:
+ P2P(*f->ret, pt);
+}
+
+void
+Image_textbg(void *fp)
+{
+ drawtextbg(fp, SoverD);
+}
+
+void
+Image_textbgop(void *fp)
+{
+ F_Image_textbgop *f;
+
+ f = fp;
+ drawtextbg(fp, f->op);
+}
+
+static void
+drawborder(void *fp, int op)
+{
+ F_Image_border *f;
+ Image *d, *s;
+ int locked;
+
+ f = fp;
+ d = checkimage(f->dst);
+ s = checkimage(f->src);
+ if(d->display != s->display)
+ return;
+ locked = lockdisplay(d->display);
+ borderop(d, IRECT(f->r), f->i, s, IPOINT(f->sp), op);
+ checkflush(f->dst);
+ if(locked)
+ unlockdisplay(d->display);
+}
+
+void
+Image_border(void *fp)
+{
+ drawborder(fp, SoverD);
+}
+
+void
+Display_newimage(void *fp)
+{
+ F_Display_newimage *f;
+ Display *d;
+ int locked;
+
+ f = fp;
+ d = checkdisplay(f->d);
+ destroy(*f->ret);
+ *f->ret = H;
+ locked = lockdisplay(d);
+ *f->ret = allocdrawimage((DDisplay*)f->d, f->r, f->chans.desc,
+ nil, f->repl, f->color);
+ if(locked)
+ unlockdisplay(d);
+}
+
+void
+Display_colormix(void *fp)
+{
+ F_Display_colormix *f;
+ Display *disp;
+ Image *i;
+ int locked;
+
+ f = fp;
+ destroy(*f->ret);
+ *f->ret = H;
+ disp = checkdisplay(f->d);
+ locked = lockdisplay(disp);
+ i = allocimagemix(disp, f->c1, f->c2);
+ if(locked)
+ unlockdisplay(disp);
+ *f->ret = mkdrawimage(i, H, f->d, nil);
+}
+
+void
+Image_readpixels(void *fp)
+{
+ F_Image_readpixels *f;
+ Rectangle r;
+ Image *i;
+ int locked;
+
+ f = fp;
+ R2R(r, f->r);
+ i = checkimage(f->src);
+ locked = lockdisplay(i->display);
+ *f->ret = unloadimage(i, r, f->data->data, f->data->len);
+ if(locked)
+ unlockdisplay(i->display);
+}
+
+void
+Image_writepixels(void *fp)
+{
+ Rectangle r;
+ F_Image_writepixels *f;
+ Image *i;
+ int locked;
+
+ f = fp;
+ R2R(r, f->r);
+ i = checkimage(f->dst);
+ locked = lockdisplay(i->display);
+ *f->ret = loadimage(i, r, f->data->data, f->data->len);
+ checkflush(f->dst);
+ if(locked)
+ unlockdisplay(i->display);
+}
+
+void
+Image_arrow(void *fp)
+{
+ F_Image_arrow *f;
+
+ f = fp;
+ *f->ret = ARROW(f->a, f->b, f->c);
+}
+
+void
+Image_name(void *fp)
+{
+ F_Image_name *f;
+ Image *i;
+ int locked, ok;
+ char *name;
+
+ f = fp;
+ *f->ret = -1;
+ i = checkimage(f->src);
+ name = string2c(f->name);
+ locked = lockdisplay(i->display);
+ *f->ret = ok = nameimage(i, name, f->in);
+ if(locked)
+ unlockdisplay(i->display);
+ if(ok){
+ destroy(f->src->iname);
+ if(f->in){
+ f->src->iname = f->name;
+ D2H(f->name)->ref++;
+ }else
+ f->src->iname = H;
+ }
+}
+
+Image*
+display_open(Display *disp, char *name)
+{
+ Image *i;
+ int fd;
+
+ fd = libopen(name, OREAD);
+ if(fd < 0)
+ return nil;
+
+ i = readimage(disp, fd, 1);
+ libclose(fd);
+ return i;
+}
+
+void
+Display_open(void *fp)
+{
+ Image *i;
+ Display *disp;
+ F_Display_open *f;
+
+ f = fp;
+ destroy(*f->ret);
+ *f->ret = H;
+ disp = lookupdisplay(f->d);
+ if(disp == nil)
+ return;
+ i = display_open(disp, string2c(f->name));
+ if(i == nil)
+ return;
+ *f->ret = allocdrawimage((DDisplay*)f->d, DRECT(i->r), i->chan, i, 0, 0);
+}
+
+void
+Display_namedimage(void *fp)
+{
+ F_Display_namedimage *f;
+ Display *d;
+ Image *i;
+ Draw_Image *di;
+ int locked;
+
+ f = fp;
+ destroy(*f->ret);
+ *f->ret = H;
+ d = checkdisplay(f->d);
+ locked = lockdisplay(d);
+ i = namedimage(d, string2c(f->name));
+ if(locked)
+ unlockdisplay(d);
+ if(i == nil)
+ return;
+ di = allocdrawimage((DDisplay*)f->d, DRECT(i->r), i->chan, i, i->repl, 0);
+ *f->ret = di;
+ if(di == H){
+ locked = lockdisplay(d);
+ freeimage(i);
+ if(locked)
+ unlockdisplay(d);
+ }else{
+ di->iname = f->name;
+ D2H(f->name)->ref++;
+ }
+}
+
+void
+Display_readimage(void *fp)
+{
+ Image *i;
+ Display *disp;
+ F_Display_readimage *f;
+ Sys_FD *fd;
+ int locked;
+
+ f = fp;
+ destroy(*f->ret);
+ *f->ret = H;
+ fd = f->fd;
+ if(fd == H)
+ return;
+ disp = checkdisplay(f->d);
+ i = readimage(disp, fd->fd, 1);
+ if(i == nil)
+ return;
+ *f->ret = allocdrawimage((DDisplay*)f->d, DRECT(i->r), i->chan, i, 0, 0);
+ if(*f->ret == H){
+ locked = lockdisplay(disp);
+ freeimage(i);
+ if(locked)
+ unlockdisplay(disp);
+ }
+}
+
+void
+Display_writeimage(void *fp)
+{
+ Image *i;
+ F_Display_writeimage *f;
+ Sys_FD *fd;
+
+ f = fp;
+ *f->ret = -1;
+ fd = f->fd;
+ if(fd == H)
+ return;
+ i = checkimage(f->i);
+ if(checkdisplay(f->d) != i->display)
+ return;
+ *f->ret = writeimage(fd->fd, i, 1); /* TO DO: dolock? */
+}
+
+Draw_Screen*
+mkdrawscreen(Screen *s, Draw_Display *display)
+{
+ Heap *h;
+ DScreen *ds;
+ Draw_Image *dimage, *dfill;
+
+ dimage = mkdrawimage(s->image, H, display, nil);
+ dfill = mkdrawimage(s->fill, H, display, nil);
+ h = heap(TScreen);
+ if(h == H)
+ return nil;
+ ds = H2D(DScreen*, h);
+ ds->screen = s;
+ ds->drawscreen.fill = dfill;
+ D2H(dfill)->ref++;
+ ds->drawscreen.image = dimage;
+ D2H(dimage)->ref++;
+ ds->drawscreen.display = dimage->display;
+ D2H(dimage->display)->ref++;
+ ds->drawscreen.id = s->id;
+ ds->dref = s->display->limbo;
+ ds->dref->ref++;
+ return &ds->drawscreen;
+}
+
+static DScreen*
+allocdrawscreen(Draw_Image *dimage, Draw_Image *dfill, int public)
+{
+ Heap *h;
+ Screen *s;
+ DScreen *ds;
+ Image *image, *fill;
+
+ image = ((DImage*)dimage)->image;
+ fill = ((DImage*)dfill)->image;
+ s = allocscreen(image, fill, public);
+ if(s == 0)
+ return nil;
+ h = heap(TScreen);
+ if(h == H)
+ return nil;
+ ds = H2D(DScreen*, h);
+ ds->screen = s;
+ ds->drawscreen.fill = dfill;
+ D2H(dfill)->ref++;
+ ds->drawscreen.image = dimage;
+ D2H(dimage)->ref++;
+ ds->drawscreen.display = dimage->display;
+ D2H(dimage->display)->ref++;
+ ds->drawscreen.id = s->id;
+ ds->dref = image->display->limbo;
+ ds->dref->ref++;
+ return ds;
+}
+
+void
+Screen_allocate(void *fp)
+{
+ F_Screen_allocate *f;
+ DScreen *ds;
+ Image *image;
+ int locked;
+
+ f = fp;
+ destroy(*f->ret);
+ *f->ret = H;
+ image = checkimage(f->image);
+ checkimage(f->fill);
+ locked = lockdisplay(image->display);
+ ds = allocdrawscreen(f->image, f->fill, f->public);
+ if(ds != nil)
+ *f->ret = &ds->drawscreen;
+ if(locked)
+ unlockdisplay(image->display);
+}
+
+void
+Display_publicscreen(void *fp)
+{
+ F_Display_publicscreen *f;
+ Heap *h;
+ Screen *s;
+ DScreen *ds;
+ Display *disp;
+ int locked;
+
+ f = fp;
+ destroy(*f->ret);
+ *f->ret = H;
+ disp = checkdisplay(f->d);
+ locked = lockdisplay(disp);
+ s = publicscreen(disp, f->id, disp->image->chan);
+ if(locked)
+ unlockdisplay(disp);
+ if(s == nil)
+ return;
+ h = heap(TScreen);
+ if(h == H)
+ return;
+ ds = H2D(DScreen*, h);
+ ds->screen = s;
+ ds->drawscreen.fill = H;
+ ds->drawscreen.image =H;
+ ds->drawscreen.id = s->id;
+ ds->drawscreen.display = f->d;
+ D2H(f->d)->ref++;
+ ds->dref = disp->limbo;
+ ds->dref->ref++;
+ *f->ret = &ds->drawscreen;
+}
+
+void
+freedrawscreen(Heap *h, int swept)
+{
+ DScreen *ds;
+ Screen *s;
+ Display *disp;
+ int locked;
+
+ ds = H2D(DScreen*, h);
+ if(!swept) {
+ destroy(ds->drawscreen.image);
+ destroy(ds->drawscreen.fill);
+ destroy(ds->drawscreen.display);
+ }
+ s = lookupscreen(&ds->drawscreen);
+ if(s == nil){
+ if(!swept)
+ freeptrs(ds, TScreen);
+ return;
+ }
+ disp = s->display;
+ locked = lockdisplay(disp);
+ freescreen(s);
+ if(locked)
+ unlockdisplay(disp);
+ display_dec(ds->dref);
+ /* screen header will be freed by caller */
+}
+
+void
+Font_build(void *fp)
+{
+ F_Font_build *f;
+ Font *font;
+ DFont *dfont;
+ Heap *h;
+ char buf[128];
+ char *name, *data;
+ Subfont *df;
+ Display *disp;
+ int locked;
+
+ f = fp;
+ destroy(*f->ret);
+ *f->ret = H;
+ disp = checkdisplay(f->d);
+
+ name = string2c(f->name);
+ font = font_open(disp, name);
+ if(font == nil) {
+ if(strcmp(name, deffontname) == 0) {
+ df = disp->defaultsubfont;
+ sprint(buf, "%d %d\n0 %d\t%s\n",
+ df->height, df->ascent, df->n-1, name);
+ data = buf;
+ }
+ else
+ if(f->desc == H)
+ return;
+ else
+ data = string2c(f->desc);
+
+ locked = lockdisplay(disp);
+ font = buildfont(disp, data, name);
+ if(locked)
+ unlockdisplay(disp);
+ if(font == nil)
+ return;
+ }
+
+ h = heap(TFont);
+ if(h == H)
+ return;
+
+ dfont = H2D(DFont*, h);
+ dfont->font = font;
+ dfont->drawfont.name = f->name;
+ D2H(f->name)->ref++;
+ dfont->drawfont.height = font->height;
+ dfont->drawfont.ascent = font->ascent;
+ dfont->drawfont.display = f->d;
+ D2H(f->d)->ref++;
+ dfont->dref = disp->limbo;
+ dfont->dref->ref++;
+
+ *f->ret = &dfont->drawfont;
+}
+
+Font*
+font_open(Display *display, char *name)
+{
+ Cache *c;
+ Font *font;
+ int locked;
+
+ c = cachelookup(fcache, display, name);
+ if(c)
+ font = c->u.f;
+ else {
+ locked = lockdisplay(display);
+ font = openfont(display, name);
+ if(locked)
+ unlockdisplay(display);
+ if(font == nil)
+ return nil;
+ c = cacheinstall(fcache, display, name, font, "font");
+ }
+ if(c)
+ c->ref++;
+
+ return font;
+}
+
+void
+font_close(Font *f)
+{
+ Cache *c;
+ Display *disp;
+ int locked;
+ disp = f->display;
+ if(f->name == nil)
+ return;
+
+ /* fonts from Font_build() aren't always in fcache, but we still need to free them */
+ c = cachelookup(fcache, disp, f->name);
+ if(c != nil && f == c->u.f) {
+ if(c->ref <= 0)
+ return;
+ if(c->ref-- != 1)
+ return;
+ cacheuninstall(fcache, disp, f->name, "font");
+ }
+
+ locked = lockdisplay(disp);
+ freefont(f);
+ if(locked)
+ unlockdisplay(disp);
+}
+
+void
+freecachedsubfont(Subfont *sf)
+{
+ Cache *c;
+ Display *disp;
+
+ disp = sf->bits->display;
+ c = cachelookup(sfcache, disp, sf->name);
+ if(c == nil){
+ fprint(2, "subfont %s not cached\n", sf->name);
+ return;
+ }
+ if(c->ref > 0)
+ c->ref--;
+ /* if ref is zero, we leave it around for later harvesting by freeallsubfonts */
+}
+
+void
+freeallsubfonts(Display *d)
+{
+ int i;
+ Cache *c, *prev, *o;
+ Subfont *sf;
+ int locked;
+ if(cacheqlock == nil) /* may not have allocated anything yet */
+ return;
+ libqlock(cacheqlock);
+ for(i=0; i<BIHASH; i++){
+ c = sfcache[i];
+ prev = 0;
+ while(c != nil){
+ if(c->ref==0 && (d==nil || c->display==d)){
+ if(prev == 0)
+ sfcache[i] = c->next;
+ else
+ prev->next = c->next;
+ free(c->name);
+ sf = c->u.sf;
+ if(--sf->ref==0){
+ free(sf->info);
+ locked = lockdisplay(c->display);
+ freeimage(sf->bits);
+ if(locked)
+ unlockdisplay(c->display);
+ free(sf);
+ }
+ o = c;
+ c = c->next;
+ free(o);
+ }else{
+ prev = c;
+ c = c->next;
+ }
+ }
+ }
+ libqunlock(cacheqlock);
+}
+
+void
+subfont_close(Subfont *sf)
+{
+ freecachedsubfont(sf);
+}
+
+void
+freesubfont(Subfont *sf)
+{
+ freecachedsubfont(sf);
+}
+
+void
+Font_open(void *fp)
+{
+ Heap *h;
+ Font *font;
+ Display *disp;
+ DFont *df;
+ F_Font_open *f;
+
+ f = fp;
+
+ destroy(*f->ret);
+ *f->ret = H;
+ disp = checkdisplay(f->d);
+
+ font = font_open(disp, string2c(f->name));
+ if(font == 0)
+ return;
+
+ h = heap(TFont);
+ if(h == H)
+ return;
+
+ df = H2D(DFont*, h);
+ df->font = font;
+ df->drawfont.name = f->name;
+ D2H(f->name)->ref++;
+ df->drawfont.height = font->height;
+ df->drawfont.ascent = font->ascent;
+ df->drawfont.display = f->d;
+ D2H(f->d)->ref++;
+ df->dref = disp->limbo;
+ df->dref->ref++;
+ *f->ret = &df->drawfont;
+}
+
+void
+Font_width(void *fp)
+{
+ F_Font_width *f;
+ Font *font;
+ char *s;
+ int locked;
+
+ f = fp;
+ s = string2c(f->str);
+ if(f->f == H || s[0]=='\0')
+ *f->ret = 0;
+ else{
+ font = checkfont(f->f);
+ locked = lockdisplay(font->display);
+ *f->ret = stringwidth(font, s);
+ if(locked)
+ unlockdisplay(font->display);
+ }
+}
+
+void
+Font_bbox(void *fp)
+{
+ F_Font_bbox *f;
+ Draw_Rect *ret;
+
+ /* place holder for the real thing */
+ f = fp;
+ ret = f->ret;
+ ret->min.x = ret->min.y = 0;
+ ret->max.x = ret->max.y = 0;
+}
+
+/*
+ * BUG: would be nice if this cached the whole font.
+ * Instead only the subfonts are cached and the fonts are
+ * freed when released.
+ */
+void
+freedrawfont(Heap*h, int swept)
+{
+ Draw_Font *d;
+ Font *f;
+ d = H2D(Draw_Font*, h);
+ f = lookupfont(d);
+ if(!swept) {
+ destroy(d->name);
+ destroy(d->display);
+ }
+ font_close(f);
+ display_dec(((DFont*)d)->dref);
+}
+
+void
+Chans_text(void *fp)
+{
+ F_Chans_text *f;
+ char buf[16];
+
+ f = fp;
+ destroy(*f->ret);
+ *f->ret = H;
+ if(chantostr(buf, f->c.desc) != nil)
+ retstr(buf, f->ret);
+}
+
+void
+Chans_depth(void *fp)
+{
+ F_Chans_depth *f;
+
+ f = fp;
+ *f->ret = chantodepth(f->c.desc);
+}
+
+void
+Chans_eq(void *fp)
+{
+ F_Chans_eq *f;
+
+ f = fp;
+ *f->ret = f->c.desc == f->d.desc;
+}
+
+void
+Chans_mk(void *fp)
+{
+ F_Chans_mk *f;
+
+ f = fp;
+ f->ret->desc = strtochan(string2c(f->s));
+}
+
+void
+Display_rgb(void *fp)
+{
+ ulong c;
+ Display *disp;
+ F_Display_rgb *f;
+ int locked;
+ void *r;
+
+ f = fp;
+ r = *f->ret;
+ *f->ret = H;
+ destroy(r);
+ disp = checkdisplay(f->d);
+
+ c = ((f->r&255)<<24)|((f->g&255)<<16)|((f->b&255)<<8)|0xFF;
+
+ locked = lockdisplay(disp);
+ *f->ret = color((DDisplay*)f->d, c);
+ if(locked)
+ unlockdisplay(disp);
+}
+
+void
+Display_rgb2cmap(void *fp)
+{
+ F_Display_rgb2cmap *f;
+
+ f = fp;
+ /* f->display is unused, but someday may have color map */
+ *f->ret = rgb2cmap(f->r, f->g, f->b);
+}
+
+void
+Display_cmap2rgb(void *fp)
+{
+ F_Display_cmap2rgb *f;
+ ulong c;
+
+ f = fp;
+ /* f->display is unused, but someday may have color map */
+ c = cmap2rgb(f->c);
+ f->ret->t0 = (c>>16)&0xFF;
+ f->ret->t1 = (c>>8)&0xFF;
+ f->ret->t2 = (c>>0)&0xFF;
+}
+
+void
+Display_cmap2rgba(void *fp)
+{
+ F_Display_cmap2rgba *f;
+
+ f = fp;
+ /* f->display is unused, but someday may have color map */
+ *f->ret = cmap2rgba(f->c);
+}
+
+void
+Draw_setalpha(void *fp)
+{
+ F_Draw_setalpha *f;
+
+ f = fp;
+ *f->ret = setalpha(f->c, f->a);
+}
+
+void
+Draw_icossin(void *fp)
+{
+ F_Draw_icossin *f;
+ int s, c;
+
+ f = fp;
+ icossin(f->deg, &s, &c);
+ f->ret->t0 = s;
+ f->ret->t1 = c;
+}
+
+void
+Draw_icossin2(void *fp)
+{
+ F_Draw_icossin2 *f;
+ int s, c;
+
+ f = fp;
+ icossin2(f->p.x, f->p.y, &s, &c);
+ f->ret->t0 = s;
+ f->ret->t1 = c;
+}
+
+void
+Draw_bytesperline(void *fp)
+{
+ F_Draw_bytesperline *f;
+
+ f = fp;
+ *f->ret = bytesperline(IRECT(f->r), f->d);
+}
+
+Draw_Image*
+color(DDisplay *dd, ulong color)
+{
+ int c;
+ Draw_Rect r;
+
+ r.min.x = 0;
+ r.min.y = 0;
+ r.max.x = 1;
+ r.max.y = 1;
+ c = (color&0xff) == 0xff ? RGB24: RGBA32;
+ return allocdrawimage(dd, r, c, nil, 1, color);
+}
+
+Draw_Image*
+mkdrawimage(Image *i, Draw_Screen *screen, Draw_Display *display, void *ref)
+{
+ Heap *h;
+ DImage *di;
+
+ h = heap(TImage);
+ if(h == H)
+ return H;
+
+ di = H2D(DImage*, h);
+ di->image = i;
+ di->drawimage.screen = screen;
+ if(screen != H)
+ D2H(screen)->ref++;
+ di->drawimage.display = display;
+ if(display != H)
+ D2H(display)->ref++;
+ di->refreshptr = ref;
+
+ R2R(di->drawimage.r, i->r);
+ R2R(di->drawimage.clipr, i->clipr);
+ di->drawimage.chans.desc = i->chan;
+ di->drawimage.depth = i->depth;
+ di->drawimage.repl = i->repl;
+ di->flush = 1;
+ di->dref = i->display->limbo;
+ di->dref->ref++;
+ return &di->drawimage;
+}
+
+void
+Screen_newwindow(void *fp)
+{
+ F_Screen_newwindow *f;
+ Image *i;
+ Screen *s;
+ Rectangle r;
+ int locked;
+ void *v;
+
+ f = fp;
+ s = checkscreen(f->screen);
+ R2R(r, f->r);
+
+ if(f->backing != Refnone && f->backing != Refbackup)
+ f->backing = Refbackup;
+
+ v = *f->ret;
+ *f->ret = H;
+ destroy(v);
+
+ locked = lockdisplay(s->display);
+ i = allocwindow(s, r, f->backing, f->color);
+ if(locked)
+ unlockdisplay(s->display);
+ if(i == nil)
+ return;
+
+ *f->ret = mkdrawimage(i, f->screen, f->screen->display, 0);
+}
+
+static
+void
+screentopbot(Draw_Screen *screen, Array *array, void (*topbot)(Image **, int))
+{
+ Screen *s;
+ Draw_Image **di;
+ Image **ip;
+ int i, n, locked;
+
+ s = checkscreen(screen);
+ di = (Draw_Image**)array->data;
+ ip = malloc(array->len * sizeof(Image*));
+ if(ip == nil)
+ return;
+ n = 0;
+ for(i=0; i<array->len; i++)
+ if(di[i] != H){
+ ip[n] = lookupimage(di[i]);
+ if(ip[n]==nil || ip[n]->screen != s){
+ free(ip);
+ return;
+ }
+ n++;
+ }
+ if(n == 0){
+ free(ip);
+ return;
+ }
+ locked = lockdisplay(s->display);
+ (*topbot)(ip, n);
+ free(ip);
+ flushimage(s->display, 1);
+ if(locked)
+ unlockdisplay(s->display);
+}
+
+void
+Screen_top(void *fp)
+{
+ F_Screen_top *f;
+ f = fp;
+ screentopbot(f->screen, f->wins, topnwindows);
+}
+
+void
+Screen_bottom(void *fp)
+{
+ F_Screen_top *f;
+ f = fp;
+ screentopbot(f->screen, f->wins, bottomnwindows);
+}
+
+void
+freedrawimage(Heap *h, int swept)
+{
+ Image *i;
+ int locked;
+ Display *disp;
+ Draw_Image *d;
+
+ d = H2D(Draw_Image*, h);
+ i = lookupimage(d);
+ if(i == nil) {
+ if(!swept)
+ freeptrs(d, TImage);
+ return;
+ }
+ disp = i->display;
+ locked = lockdisplay(disp);
+ freeimage(i);
+ if(locked)
+ unlockdisplay(disp);
+ display_dec(((DImage*)d)->dref);
+ /* image/layer header will be freed by caller */
+}
+
+void
+Image_top(void *fp)
+{
+ F_Image_top *f;
+ Image *i;
+ int locked;
+
+ f = fp;
+ i = checkimage(f->win);
+ locked = lockdisplay(i->display);
+ topwindow(i);
+ flushimage(i->display, 1);
+ if(locked)
+ unlockdisplay(i->display);
+}
+
+void
+Image_origin(void *fp)
+{
+ F_Image_origin *f;
+ Image *i;
+ int locked;
+
+ f = fp;
+ i = checkimage(f->win);
+ locked = lockdisplay(i->display);
+ if(originwindow(i, IPOINT(f->log), IPOINT(f->scr)) < 0)
+ *f->ret = -1;
+ else{
+ f->win->r = DRECT(i->r);
+ f->win->clipr = DRECT(i->clipr);
+ *f->ret = 1;
+ }
+ if(locked)
+ unlockdisplay(i->display);
+}
+
+void
+Image_bottom(void *fp)
+{
+ F_Image_top *f;
+ Image *i;
+ int locked;
+
+ f = fp;
+ i = checkimage(f->win);
+ locked = lockdisplay(i->display);
+ bottomwindow(i);
+ flushimage(i->display, 1);
+ if(locked)
+ unlockdisplay(i->display);
+}
+
+Draw_Image*
+allocdrawimage(DDisplay *ddisplay, Draw_Rect r, ulong chan, Image *iimage, int repl, int color)
+{
+ Heap *h;
+ DImage *di;
+ Rectangle rr;
+ Image *image;
+
+ image = iimage;
+ if(iimage == nil){
+ R2R(rr, r);
+ image = allocimage(ddisplay->display, rr, chan, repl, color);
+ if(image == nil)
+ return H;
+ }
+
+ h = heap(TImage);
+ if(h == H){
+ if(iimage == nil)
+ freeimage(image);
+ return H;
+ }
+
+ di = H2D(DImage*, h);
+ di->drawimage.r = r;
+ R2R(di->drawimage.clipr, image->clipr);
+ di->drawimage.chans.desc = chan;
+ di->drawimage.depth = chantodepth(chan);
+ di->drawimage.repl = repl;
+ di->drawimage.display = (Draw_Display*)ddisplay;
+ D2H(di->drawimage.display)->ref++;
+ di->drawimage.screen = H;
+ di->dref = ddisplay->display->limbo;
+ di->dref->ref++;
+ di->image = image;
+ di->refreshptr = 0;
+ di->flush = 1;
+
+ return &di->drawimage;
+}
+
+/*
+ * Entry points called from the draw library
+ */
+Subfont*
+lookupsubfont(Display *d, char *name)
+{
+ Cache *c;
+
+ c = cachelookup(sfcache, d, name);
+ if(c == nil)
+ return nil;
+ /*c->u.sf->ref++;*/ /* TO DO: need to revisit the reference counting */
+ return c->u.sf;
+}
+
+void
+installsubfont(char *name, Subfont *subfont)
+{
+ Cache *c;
+
+ c = cacheinstall(sfcache, subfont->bits->display, name, subfont, "subfont");
+ if(c)
+ c->ref++;
+}
+
+/*
+ * BUG version
+ */
+char*
+subfontname(char *cfname, char *fname, int maxdepth)
+{
+ char *t, *u, tmp1[256], tmp2[256];
+ int i, fd;
+
+ if(strcmp(cfname, deffontname) == 0)
+ return strdup(cfname);
+ t = cfname;
+ if(t[0] != '/'){
+ strcpy(tmp2, fname);
+ u = utfrrune(tmp2, '/');
+ if(u)
+ u[0] = 0;
+ else
+ strcpy(tmp2, ".");
+ snprint(tmp1, sizeof tmp1, "%s/%s", tmp2, t);
+ t = tmp1;
+ }
+
+ if(maxdepth > 8)
+ maxdepth = 8;
+
+ for(i=3; i>=0; i--){
+ if((1<<i) > maxdepth)
+ continue;
+ /* try i-bit grey */
+ snprint(tmp2, sizeof tmp2, "%s.%d", t, i);
+ fd = libopen(tmp2, OREAD);
+ if(fd >= 0){
+ libclose(fd);
+ return strdup(tmp2);
+ }
+ }
+
+ return strdup(t);
+}
+
+void
+refreshslave(Display *d)
+{
+ int i, n, id;
+ uchar buf[5*(5*4)], *p;
+ Rectangle r;
+ Image *im;
+ int locked;
+
+ for(;;){
+ release();
+ n = kchanio(d->refchan, buf, sizeof buf, OREAD);
+ acquire();
+ if(n < 0) /* probably caused by closedisplay() closing refchan */
+ return; /* will fall off end of thread and close down */
+ locked = lockdisplay(d);
+ p = buf;
+ for(i=0; i<n; i+=5*4,p+=5*4){
+ id = BGLONG(p+0*4);
+ r.min.x = BGLONG(p+1*4);
+ r.min.y = BGLONG(p+2*4);
+ r.max.x = BGLONG(p+3*4);
+ r.max.y = BGLONG(p+4*4);
+ for(im=d->windows; im; im=im->next)
+ if(im->id == id)
+ break;
+ if(im && im->screen && im->reffn)
+ (*im->reffn)(im, r, im->refptr);
+ }
+ flushimage(d, 1);
+ if(locked)
+ unlockdisplay(d);
+ }
+}
+
+void
+startrefresh(Display *disp)
+{
+ USED(disp);
+}
+
+static
+int
+doflush(Display *d)
+{
+ int m, n;
+ char err[ERRMAX];
+ uchar *tp;
+
+ n = d->bufp-d->buf;
+ if(n <= 0)
+ return 1;
+
+ if(d->local == 0)
+ release();
+ if((m = kchanio(d->datachan, d->buf, n, OWRITE)) != n){
+ if(d->local == 0)
+ acquire();
+ kgerrstr(err, sizeof err);
+ if(_drawdebug || strcmp(err, "screen id in use") != 0 && strcmp(err, exImage) != 0){
+ print("flushimage fail: (%d not %d) d=%lux: %s\nbuffer: ", m, n, (ulong)d, err);
+ for(tp = d->buf; tp < d->bufp; tp++)
+ print("%.2x ", (int)*tp);
+ print("\n");
+ }
+ d->bufp = d->buf; /* might as well; chance of continuing */
+ return -1;
+ }
+ d->bufp = d->buf;
+ if(d->local == 0)
+ acquire();
+ return 1;
+}
+
+int
+flushimage(Display *d, int visible)
+{
+ int ret;
+ Refreshq *r;
+
+ for(;;){
+ if(visible)
+ *d->bufp++ = 'v'; /* one byte always reserved for this */
+ ret = doflush(d);
+ if(d->refhead == nil)
+ break;
+ while(r = d->refhead){ /* assign = */
+ d->refhead = r->next;
+ if(d->refhead == nil)
+ d->reftail = nil;
+ r->reffn(nil, r->r, r->refptr);
+ free(r);
+ }
+ }
+ return ret;
+}
+
+/*
+ * Turn off refresh for this window and remove any pending refresh events for it.
+ */
+void
+delrefresh(Image *i)
+{
+ Refreshq *r, *prev, *next;
+ int locked;
+ Display *d;
+ void *refptr;
+
+ d = i->display;
+ /*
+ * Any refresh function will do, because the data pointer is nil.
+ * Can't use nil, though, because that turns backing store back on.
+ */
+ if(d->local)
+ drawlsetrefresh(d->dataqid, i->id, memlnorefresh, nil);
+ refptr = i->refptr;
+ i->refptr = nil;
+ if(d->refhead==nil || refptr==nil)
+ return;
+ locked = lockdisplay(d);
+ prev = nil;
+ for(r=d->refhead; r; r=next){
+ next = r->next;
+ if(r->refptr == refptr){
+ if(prev)
+ prev->next = next;
+ else
+ d->refhead = next;
+ if(d->reftail == r)
+ d->reftail = prev;
+ free(r);
+ }else
+ prev = r;
+ }
+ if(locked)
+ unlockdisplay(d);
+}
+
+void
+queuerefresh(Image *i, Rectangle r, Reffn reffn, void *refptr)
+{
+ Display *d;
+ Refreshq *rq;
+
+ d = i->display;
+ rq = malloc(sizeof(Refreshq));
+ if(rq == nil)
+ return;
+ if(d->reftail)
+ d->reftail->next = rq;
+ else
+ d->refhead = rq;
+ d->reftail = rq;
+ rq->reffn = reffn;
+ rq->refptr = refptr;
+ rq->r = r;
+}
+
+uchar*
+bufimage(Display *d, int n)
+{
+ uchar *p;
+
+ if(n<0 || n>Displaybufsize){
+ kwerrstr("bad count in bufimage");
+ return 0;
+ }
+ if(d->bufp+n > d->buf+Displaybufsize){
+ if(d->local==0 && currun()!=libqlowner(d->qlock)) {
+ print("bufimage: %lux %lux\n", (ulong)libqlowner(d->qlock), (ulong)currun());
+ abort();
+ }
+ if(doflush(d) < 0)
+ return 0;
+ }
+ p = d->bufp;
+ d->bufp += n;
+ /* return with buffer locked */
+ return p;
+}
+
+void
+drawerror(Display *d, char *s)
+{
+ USED(d);
+ fprint(2, "draw: %s: %r\n", s);
+}
--- /dev/null
+++ b/libinterp/freetype.c
@@ -1,0 +1,231 @@
+#include <lib9.h>
+#include <kernel.h>
+#include "interp.h"
+#include "isa.h"
+#include "runt.h"
+#include "raise.h"
+#include "freetypemod.h"
+#include "freetype.h"
+
+
+typedef struct Face Face;
+struct Face {
+ Freetype_Face freetypeface; /* limbo part */
+ FTface ftface; /* private parts */
+};
+
+Type* TMatrix;
+Type* TVector;
+Type* TFace;
+Type* TGlyph;
+
+static uchar Matrixmap[] = Freetype_Matrix_map;
+static uchar Vectormap[] = Freetype_Vector_map;
+static uchar Facemap[] = Freetype_Face_map;
+static uchar Glyphmap[] = Freetype_Glyph_map;
+
+static void freeface(Heap*, int);
+static Face* ckface(Freetype_Face*);
+
+void
+freetypemodinit(void)
+{
+ builtinmod("$Freetype", Freetypemodtab, Freetypemodlen);
+ TMatrix = dtype(freeheap, sizeof(Freetype_Matrix), Matrixmap, sizeof(Matrixmap));
+ TVector = dtype(freeheap, sizeof(Freetype_Vector), Vectormap, sizeof(Vectormap));
+ TFace = dtype(freeface, sizeof(Face), Facemap, sizeof(Facemap));
+ TGlyph = dtype(freeheap, sizeof(Freetype_Glyph), Glyphmap, sizeof(Glyphmap));
+}
+
+void
+Face_haschar(void *fp)
+{
+ F_Face_haschar *f = fp;
+ Face *face;
+
+ *f->ret = 0;
+ face = ckface(f->face);
+ release();
+ *f->ret = fthaschar(face->ftface, f->c);
+ acquire();
+}
+
+void
+Face_loadglyph(void *fp)
+{
+ F_Face_loadglyph *f = fp;
+ Heap *h;
+ Face *face;
+ Freetype_Glyph *g;
+ FTglyph ftg;
+ int n, i, s1bpr, s2bpr;
+ char *err;
+
+ face = ckface(f->face);
+
+ destroy(*f->ret);
+ *f->ret = H;
+
+ release();
+ err = ftloadglyph(face->ftface, f->c, &ftg);
+ acquire();
+ if (err != nil) {
+ kwerrstr(err);
+ return;
+ }
+
+ h = heap(TGlyph);
+ if (h == H) {
+ kwerrstr(exNomem);
+ return;
+ }
+ g = H2D(Freetype_Glyph*, h);
+ n = ftg.width*ftg.height;
+ h = heaparray(&Tbyte, n);
+ if (h == H) {
+ destroy(g);
+ kwerrstr(exNomem);
+ return;
+ }
+ g->bitmap = H2D(Array*, h);
+ g->top = ftg.top;
+ g->left = ftg.left;
+ g->height = ftg.height;
+ g->width = ftg.width;
+ g->advance.x = ftg.advx;
+ g->advance.y = ftg.advy;
+
+ s1bpr = ftg.width;
+ s2bpr = ftg.bpr;
+ for (i = 0; i < ftg.height; i++)
+ memcpy(g->bitmap->data+(i*s1bpr), ftg.bitmap+(i*s2bpr), s1bpr);
+ *f->ret = g;
+}
+
+void
+Freetype_newface(void *fp)
+{
+ F_Freetype_newface *f = fp;
+ Heap *h;
+ Face *face;
+ Freetype_Face *limboface;
+ FTfaceinfo finfo;
+ char *path;
+ char *err;
+
+ destroy(*f->ret);
+ *f->ret = H;
+
+ h = heapz(TFace);
+ if (h == H) {
+ kwerrstr(exNomem);
+ return;
+ }
+
+ face = H2D(Face*, h);
+ limboface = (Freetype_Face*)face;
+ *f->ret = limboface;
+ path = strdup(string2c(f->path)); /* string2c() can call error() */
+ release();
+ err = ftnewface(path, f->index, &face->ftface, &finfo);
+ acquire();
+ free(path);
+ if (err != nil) {
+ *f->ret = H;
+ destroy(face);
+ kwerrstr(err);
+ return;
+ }
+ limboface->nfaces = finfo.nfaces;
+ limboface->index = finfo.index;
+ limboface->style = finfo.style;
+ limboface->height = finfo.height;
+ limboface->ascent = finfo.ascent;
+ limboface->familyname = c2string(finfo.familyname, strlen(finfo.familyname));
+ limboface->stylename = c2string(finfo.stylename, strlen(finfo.stylename));
+ *f->ret = limboface;
+}
+
+void
+Freetype_newmemface(void *fp)
+{
+ F_Freetype_newmemface *f = fp;
+
+ destroy(*f->ret);
+ *f->ret = H;
+
+ kwerrstr("not implemented");
+}
+
+void
+Face_setcharsize(void *fp)
+{
+ F_Face_setcharsize *f = fp;
+ Face *face;
+ Freetype_Face *limboface;
+ FTfaceinfo finfo;
+ char *err;
+
+ face = ckface(f->face);
+ limboface = (Freetype_Face*)face;
+ release();
+ err = ftsetcharsize(face->ftface, f->pts, f->hdpi, f->vdpi, &finfo);
+ acquire();
+ if (err == nil) {
+ limboface->height = finfo.height;
+ limboface->ascent = finfo.ascent;
+ }
+ retstr(err, f->ret);
+}
+
+void
+Face_settransform(void *fp)
+{
+ F_Face_settransform *f = fp;
+ FTmatrix *m = nil;
+ FTvector *v = nil;
+ Face *face;
+
+ face = ckface(f->face);
+
+ /*
+ * ftsettransform() has no error return
+ * we have one for consistency - but always nil for now
+ */
+ destroy(*f->ret);
+ *f->ret = H;
+
+ if (f->m != H)
+ m = (FTmatrix*)(f->m);
+ if (f->v != H)
+ v = (FTvector*)(f->v);
+ release();
+ ftsettransform(face->ftface, m, v);
+ acquire();
+}
+
+static void
+freeface(Heap *h, int swept)
+{
+ Face *face = H2D(Face*, h);
+
+ if (!swept) {
+ destroy(face->freetypeface.familyname);
+ destroy(face->freetypeface.stylename);
+ }
+ release();
+ ftdoneface(face->ftface);
+ acquire();
+ memset(&face->ftface, 0, sizeof(face->ftface));
+}
+
+static Face*
+ckface(Freetype_Face *face)
+{
+ if (face == nil || face == H)
+ error("nil Face");
+ if (D2H(face)->t != TFace)
+ error(exType);
+ return (Face*)face;
+}
+
--- /dev/null
+++ b/libinterp/gc.c
@@ -1,0 +1,383 @@
+#include "lib9.h"
+#include "interp.h"
+#include "pool.h"
+
+enum
+{
+ Quanta = 50, /* Allocated blocks to sweep each time slice usually */
+ MaxQuanta = 15*Quanta,
+ PTRHASH = (1<<5)
+};
+
+static int quanta = Quanta;
+static int gce, gct = 1;
+
+typedef struct Ptrhash Ptrhash;
+struct Ptrhash
+{
+ Heap *value;
+ Ptrhash *next;
+};
+
+ int nprop;
+ int gchalt;
+ int mflag;
+ int mutator = 0;
+ int gccolor = 3;
+
+ ulong gcnruns;
+ ulong gcsweeps;
+ ulong gcbroken;
+ ulong gchalted;
+ ulong gcepochs;
+ uvlong gcdestroys;
+ uvlong gcinspects;
+
+static int marker = 1;
+static int sweeper = 2;
+static Bhdr* base;
+static Bhdr* limit;
+Bhdr* ptr;
+static int visit;
+extern Pool* heapmem;
+static Ptrhash *ptrtab[PTRHASH];
+static Ptrhash *ptrfree;
+
+#define HASHPTR(p) (((ulong)(p) >> 6) & (PTRHASH - 1))
+
+void
+ptradd(Heap *v)
+{
+ int h;
+ Ptrhash *p;
+
+ if ((p = ptrfree) != nil)
+ ptrfree = p->next;
+ else if ((p = malloc(sizeof (Ptrhash))) == nil)
+ error("ptradd malloc");
+ h = HASHPTR(v);
+ p->value = v;
+ p->next = ptrtab[h];
+ ptrtab[h] = p;
+}
+
+void
+ptrdel(Heap *v)
+{
+ Ptrhash *p, **l;
+
+ for (l = &ptrtab[HASHPTR(v)]; (p = *l) != nil; l = &p->next) {
+ if (p->value == v) {
+ *l = p->next;
+ p->next = ptrfree;
+ ptrfree = p;
+ return;
+ }
+ }
+ /* ptradd must have failed */
+}
+
+static void
+ptrmark(void)
+{
+ int i;
+ Heap *h;
+ Ptrhash *p;
+
+ for (i = 0; i < PTRHASH; i++) {
+ for (p = ptrtab[i]; p != nil; p = p->next) {
+ h = p->value;
+ Setmark(h);
+ }
+ }
+}
+
+void
+noptrs(Type *t, void *vw)
+{
+ USED(t);
+ USED(vw);
+}
+
+static int markdepth;
+
+/* code simpler with a depth search compared to a width search*/
+void
+markheap(Type *t, void *vw)
+{
+ Heap *h;
+ uchar *p;
+ int i, c, m;
+ WORD **w, **q;
+ Type *t1;
+
+ if(t == nil || t->np == 0)
+ return;
+
+ markdepth++;
+ w = (WORD**)vw;
+ p = t->map;
+ for(i = 0; i < t->np; i++) {
+ c = *p++;
+ if(c != 0) {
+ q = w;
+ for(m = 0x80; m != 0; m >>= 1) {
+ if((c & m) && *q != H) {
+ h = D2H(*q);
+ Setmark(h);
+ if(h->color == propagator && --visit >= 0 && markdepth < 64){
+ gce--;
+ h->color = mutator;
+ if((t1 = h->t) != nil)
+ t1->mark(t1, H2D(void*, h));
+ }
+ }
+ q++;
+ }
+ }
+ w += 8;
+ }
+ markdepth--;
+}
+
+/*
+ * This routine should be modified to be incremental, but how?
+ */
+void
+markarray(Type *t, void *vw)
+{
+ int i;
+ Heap *h;
+ uchar *v;
+ Array *a;
+
+ USED(t);
+
+ a = vw;
+ t = a->t;
+ if(a->root != H) {
+ h = D2H(a->root);
+ Setmark(h);
+ }
+
+ if(t->np == 0)
+ return;
+
+ v = a->data;
+ for(i = 0; i < a->len; i++) {
+ markheap(t, v);
+ v += t->size;
+ }
+ visit -= a->len;
+}
+
+void
+marklist(Type *t, void *vw)
+{
+ List *l;
+ Heap *h;
+
+ USED(t);
+ l = vw;
+ markheap(l->t, l->data);
+ while(visit > 0) {
+ l = l->tail;
+ if(l == H)
+ return;
+ h = D2H(l);
+ Setmark(h);
+ markheap(l->t, l->data);
+ visit--;
+ }
+ l = l->tail;
+ if(l != H) {
+ D2H(l)->color = propagator;
+ nprop = 1;
+ }
+}
+
+static void
+rootset(Prog *root)
+{
+ Heap *h;
+ Type *t;
+ Frame *f;
+ Module *m;
+ Stkext *sx;
+ Modlink *ml;
+ uchar *fp, *sp, *ex, *mp;
+
+ mutator = gccolor % 3;
+ marker = (gccolor-1)%3;
+ sweeper = (gccolor-2)%3;
+
+ while(root != nil) {
+ ml = root->R.M;
+ h = D2H(ml);
+ Setmark(h);
+ mp = ml->MP;
+ if(mp != H) {
+ h = D2H(mp);
+ Setmark(h);
+ }
+
+ sp = root->R.SP;
+ ex = root->R.EX;
+ while(ex != nil) {
+ sx = (Stkext*)ex;
+ fp = sx->reg.tos.fu;
+ while(fp != sp) {
+ f = (Frame*)fp;
+ t = f->t;
+ if(t == nil)
+ t = sx->reg.TR;
+ fp += t->size;
+ t->mark(t, f);
+ ml = f->mr;
+ if(ml != nil) {
+ h = D2H(ml);
+ Setmark(h);
+ mp = ml->MP;
+ if(mp != H) {
+ h = D2H(mp);
+ Setmark(h);
+ }
+ }
+ }
+ ex = sx->reg.EX;
+ sp = sx->reg.SP;
+ }
+
+ root = root->next;
+ }
+
+ for(m = modules; m != nil; m = m->link) {
+ if(m->origmp != H) {
+ h = D2H(m->origmp);
+ Setmark(h);
+ }
+ }
+
+ ptrmark();
+}
+
+static int
+okbhdr(Bhdr *b)
+{
+ if(b == nil)
+ return 0;
+ switch(b->magic) {
+ case MAGIC_A:
+ case MAGIC_F:
+ case MAGIC_E:
+ case MAGIC_I:
+ return 1;
+ }
+ return 0;
+}
+
+static void
+domflag(Heap *h)
+{
+ int i;
+ Module *m;
+
+ print("sweep h=0x%lux t=0x%lux c=%d", (ulong)h, (ulong)h->t, h->color);
+ for(m = modules; m != nil; m = m->link) {
+ for(i = 0; i < m->ntype; i++) {
+ if(m->type[i] == h->t) {
+ print(" module %s desc %d", m->name, i);
+ break;
+ }
+ }
+ }
+ print("\n");
+ if(mflag > 1)
+ abort();
+}
+
+void
+rungc(Prog *p)
+{
+ Type *t;
+ Heap *h;
+ Bhdr *b;
+
+ gcnruns++;
+ if(gchalt) {
+ gchalted++;
+ return;
+ }
+ if(base == nil) {
+ gcsweeps++;
+ b = poolchain(heapmem);
+ base = b;
+ ptr = b;
+ limit = B2LIMIT(b);
+ }
+
+ /* Chain broken ? */
+ if(!okbhdr(ptr)) {
+ base = nil;
+ gcbroken++;
+ return;
+ }
+
+ for(visit = quanta; visit > 0; ) {
+ if(ptr->magic == MAGIC_A) {
+ visit--;
+ gct++;
+ gcinspects++;
+ h = B2D(ptr);
+ t = h->t;
+ if(h->color == propagator) {
+ gce--;
+ h->color = mutator;
+ if(t != nil)
+ t->mark(t, H2D(void*, h));
+ }
+ else
+ if(h->color == sweeper) {
+ gce++;
+ if(0 && mflag)
+ domflag(h);
+ if(heapmonitor != nil)
+ heapmonitor(2, h, 0);
+ if(t != nil) {
+ gclock();
+ t->free(h, 1);
+ gcunlock();
+ freetype(t);
+ }
+ gcdestroys++;
+ poolfree(heapmem, h);
+ }
+ }
+ ptr = B2NB(ptr);
+ if(ptr >= limit) {
+ base = base->clink;
+ if(base == nil)
+ break;
+ ptr = base;
+ limit = B2LIMIT(base);
+ }
+ }
+
+ quanta = (MaxQuanta+Quanta)/2 + ((MaxQuanta-Quanta)/20)*((100*gce)/gct);
+ if(quanta < Quanta)
+ quanta = Quanta;
+ if(quanta > MaxQuanta)
+ quanta = MaxQuanta;
+
+ if(base != nil) /* Completed this iteration ? */
+ return;
+ if(nprop == 0) { /* Completed the epoch ? */
+ gcepochs++;
+ gccolor++;
+ rootset(p);
+ gce = 0;
+ gct = 1;
+ return;
+ }
+ nprop = 0;
+}
--- /dev/null
+++ b/libinterp/geom.c
@@ -1,0 +1,309 @@
+#include "lib9.h"
+#include "interp.h"
+#include "isa.h"
+#include "draw.h"
+#include "runt.h"
+#include "raise.h"
+
+void
+Point_add(void *fp)
+{
+ F_Point_add *f;
+ Draw_Point *ret;
+
+ f = fp;
+
+ ret = f->ret;
+ ret->x = f->p.x + f->q.x;
+ ret->y = f->p.y + f->q.y;
+}
+
+void
+Point_sub(void *fp)
+{
+ F_Point_sub *f;
+ Draw_Point *ret;
+
+ f = fp;
+
+ ret = f->ret;
+ ret->x = f->p.x - f->q.x;
+ ret->y = f->p.y - f->q.y;
+}
+
+void
+Point_mul(void *fp)
+{
+ F_Point_mul *f;
+ Draw_Point *ret;
+
+ f = fp;
+
+ ret = f->ret;
+ ret->x = f->p.x * f->i;
+ ret->y = f->p.y * f->i;
+}
+
+void
+Point_div(void *fp)
+{
+ F_Point_div *f;
+ Draw_Point *ret;
+
+ f = fp;
+
+ if(f->i == 0)
+ error(exZdiv);
+ ret = f->ret;
+ ret->x = f->p.x / f->i;
+ ret->y = f->p.y / f->i;
+}
+
+void
+Point_eq(void *fp)
+{
+ F_Point_eq *f;
+
+ f = fp;
+ *f->ret = f->p.x == f->q.x && f->p.y == f->q.y;
+}
+
+void
+Point_in(void *fp)
+{
+ F_Point_in *f;
+
+ f = fp;
+ *f->ret = f->p.x >= f->r.min.x && f->p.x < f->r.max.x &&
+ f->p.y >= f->r.min.y && f->p.y < f->r.max.y;
+}
+
+void
+Rect_canon(void *fp)
+{
+ F_Rect_canon *f;
+ Draw_Rect *ret;
+ WORD t;
+
+ f = fp;
+
+ ret = f->ret;
+ if(f->r.max.x < f->r.min.x){
+ t = f->r.max.x;
+ ret->max.x = f->r.min.x;
+ ret->min.x = t;
+ }else{
+ t = f->r.max.x;
+ ret->min.x = f->r.min.x;
+ ret->max.x = t;
+ }
+ if(f->r.max.y < f->r.min.y){
+ t = f->r.max.y;
+ ret->max.y = f->r.min.y;
+ ret->min.y = t;
+ }else{
+ t = f->r.max.y;
+ ret->min.y = f->r.min.y;
+ ret->max.y = t;
+ }
+}
+
+void
+Rect_combine(void *fp)
+{
+ F_Rect_combine *f;
+ Draw_Rect *ret;
+
+ f = fp;
+ ret = f->ret;
+ *ret = f->r;
+ if(f->r.min.x > f->s.min.x)
+ ret->min.x = f->s.min.x;
+ if(f->r.min.y > f->s.min.y)
+ ret->min.y = f->s.min.y;
+ if(f->r.max.x < f->s.max.x)
+ ret->max.x = f->s.max.x;
+ if(f->r.max.y < f->s.max.y)
+ ret->max.y = f->s.max.y;
+}
+
+void
+Rect_eq(void *fp)
+{
+ F_Rect_eq *f;
+
+ f = fp;
+
+ *f->ret = f->r.min.x == f->s.min.x
+ && f->r.max.x == f->s.max.x
+ && f->r.min.y == f->s.min.y
+ && f->r.max.y == f->s.max.y;
+}
+
+void
+Rect_Xrect(void *fp)
+{
+ F_Rect_Xrect *f;
+
+ f = fp;
+
+ *f->ret = f->r.min.x < f->s.max.x
+ && f->s.min.x < f->r.max.x
+ && f->r.min.y < f->s.max.y
+ && f->s.min.y < f->r.max.y;
+}
+
+void
+Rect_clip(void *fp)
+{
+ F_Rect_clip *f;
+ Draw_Rect *r, *s, *ret;
+
+ f = fp;
+
+ r = &f->r;
+ s = &f->s;
+ ret = &f->ret->t0;
+
+ /*
+ * Expand rectXrect() in line for speed
+ */
+ if(!(r->min.x<s->max.x && s->min.x<r->max.x
+ && r->min.y<s->max.y && s->min.y<r->max.y)){
+ *ret = *r;
+ f->ret->t1 = 0;
+ return;
+ }
+
+ /* They must overlap */
+ if(r->min.x < s->min.x)
+ ret->min.x = s->min.x;
+ else
+ ret->min.x = r->min.x;
+ if(r->min.y < s->min.y)
+ ret->min.y = s->min.y;
+ else
+ ret->min.y = r->min.y;
+ if(r->max.x > s->max.x)
+ ret->max.x = s->max.x;
+ else
+ ret->max.x = r->max.x;
+ if(r->max.y > s->max.y)
+ ret->max.y = s->max.y;
+ else
+ ret->max.y = r->max.y;
+ f->ret->t1 = 1;
+}
+
+void
+Rect_inrect(void *fp)
+{
+ F_Rect_inrect *f;
+
+ f = fp;
+
+ *f->ret = f->s.min.x <= f->r.min.x
+ && f->r.max.x <= f->s.max.x
+ && f->s.min.y <= f->r.min.y
+ && f->r.max.y <= f->s.max.y;
+}
+
+void
+Rect_contains(void *fp)
+{
+ F_Rect_contains *f;
+ WORD x, y;
+
+ f = fp;
+
+ x = f->p.x;
+ y = f->p.y;
+ *f->ret = x >= f->r.min.x && x < f->r.max.x
+ && y >= f->r.min.y && y < f->r.max.y;
+}
+
+void
+Rect_addpt(void *fp)
+{
+ F_Rect_addpt *f;
+ Draw_Rect *ret;
+ WORD n;
+
+ f = fp;
+
+ ret = f->ret;
+ n = f->p.x;
+ ret->min.x = f->r.min.x + n;
+ ret->max.x = f->r.max.x + n;
+ n = f->p.y;
+ ret->min.y = f->r.min.y + n;
+ ret->max.y = f->r.max.y + n;
+}
+
+void
+Rect_subpt(void *fp)
+{
+ WORD n;
+ F_Rect_subpt *f;
+ Draw_Rect *ret;
+
+ f = fp;
+
+ ret = f->ret;
+ n = f->p.x;
+ ret->min.x = f->r.min.x - n;
+ ret->max.x = f->r.max.x - n;
+ n = f->p.y;
+ ret->min.y = f->r.min.y - n;
+ ret->max.y = f->r.max.y - n;
+}
+
+void
+Rect_inset(void *fp)
+{
+ WORD n;
+ Draw_Rect *ret;
+ F_Rect_inset *f;
+
+ f = fp;
+
+ ret = f->ret;
+ n = f->n;
+ ret->min.x = f->r.min.x + n;
+ ret->min.y = f->r.min.y + n;
+ ret->max.x = f->r.max.x - n;
+ ret->max.y = f->r.max.y - n;
+}
+
+void
+Rect_dx(void *fp)
+{
+ F_Rect_dx *f;
+
+ f = fp;
+
+ *f->ret = f->r.max.x-f->r.min.x;
+}
+
+void
+Rect_dy(void *fp)
+{
+ F_Rect_dy *f;
+
+ f = fp;
+
+ *f->ret = f->r.max.y-f->r.min.y;
+}
+
+void
+Rect_size(void *fp)
+{
+ F_Rect_size *f;
+ Draw_Point *ret;
+
+ f = fp;
+
+ ret = f->ret;
+ ret->x = f->r.max.x-f->r.min.x;
+ ret->y = f->r.max.y-f->r.min.y;
+}
--- /dev/null
+++ b/libinterp/heap.c
@@ -1,0 +1,533 @@
+#include "lib9.h"
+#include "isa.h"
+#include "interp.h"
+#include "pool.h"
+#include "raise.h"
+
+void freearray(Heap*, int);
+void freelist(Heap*, int);
+void freemodlink(Heap*, int);
+void freechan(Heap*, int);
+Type Tarray = { 1, freearray, markarray, sizeof(Array) };
+Type Tstring = { 1, freestring, noptrs, sizeof(String) };
+Type Tlist = { 1, freelist, marklist, sizeof(List) };
+Type Tmodlink = { 1, freemodlink, markheap, -1, 1, 0, 0, { 0x80 } };
+Type Tchannel = { 1, freechan, markheap, sizeof(Channel), 1,0,0,{0x80} };
+Type Tptr = { 1, 0, markheap, sizeof(WORD*), 1, 0, 0, { 0x80 } };
+Type Tbyte = { 1, 0, 0, 1 };
+Type Tword = { 1, 0, 0, sizeof(WORD) };
+Type Tlong = { 1, 0, 0, sizeof(LONG) };
+Type Treal = { 1, 0, 0, sizeof(REAL) };
+
+extern Pool* heapmem;
+extern int mutator;
+
+void (*heapmonitor)(int, void*, ulong);
+
+#define BIT(bt, nb) (bt & (1<<nb))
+
+void
+freeptrs(void *v, Type *t)
+{
+ int c;
+ WORD **w, *x;
+ uchar *p, *ep;
+
+ if(t->np == 0)
+ return;
+
+ w = (WORD**)v;
+ p = t->map;
+ ep = p + t->np;
+ while(p < ep) {
+ c = *p;
+ if(c != 0) {
+ if(BIT(c, 0) && (x = w[7]) != H) destroy(x);
+ if(BIT(c, 1) && (x = w[6]) != H) destroy(x);
+ if(BIT(c, 2) && (x = w[5]) != H) destroy(x);
+ if(BIT(c, 3) && (x = w[4]) != H) destroy(x);
+ if(BIT(c, 4) && (x = w[3]) != H) destroy(x);
+ if(BIT(c, 5) && (x = w[2]) != H) destroy(x);
+ if(BIT(c, 6) && (x = w[1]) != H) destroy(x);
+ if(BIT(c, 7) && (x = w[0]) != H) destroy(x);
+ }
+ p++;
+ w += 8;
+ }
+}
+
+/*
+void
+nilptrs(void *v, Type *t)
+{
+ int c, i;
+ WORD **w;
+ uchar *p, *ep;
+
+ w = (WORD**)v;
+ p = t->map;
+ ep = p + t->np;
+ while(p < ep) {
+ c = *p;
+ for(i = 0; i < 8; i++){
+ if(BIT(c, 7)) *w = H;
+ c <<= 1;
+ w++;
+ }
+ p++;
+ }
+}
+*/
+
+void
+freechan(Heap *h, int swept)
+{
+ Channel *c;
+
+ USED(swept);
+ c = H2D(Channel*, h);
+ if(c->mover == movtmp)
+ freetype(c->mid.t);
+ killcomm(&c->send);
+ killcomm(&c->recv);
+ if (!swept && c->buf != H)
+ destroy(c->buf);
+}
+
+void
+freestring(Heap *h, int swept)
+{
+ String *s;
+
+ USED(swept);
+ s = H2D(String*, h);
+ if(s->tmp != nil)
+ free(s->tmp);
+}
+
+void
+freearray(Heap *h, int swept)
+{
+ int i;
+ Type *t;
+ uchar *v;
+ Array *a;
+
+ a = H2D(Array*, h);
+ t = a->t;
+
+ if(!swept) {
+ if(a->root != H)
+ destroy(a->root);
+ else
+ if(t->np != 0) {
+ v = a->data;
+ for(i = 0; i < a->len; i++) {
+ freeptrs(v, t);
+ v += t->size;
+ }
+ }
+ }
+ if(t->ref-- == 1) {
+ free(t->initialize);
+ free(t);
+ }
+}
+
+void
+freelist(Heap *h, int swept)
+{
+ Type *t;
+ List *l;
+ Heap *th;
+
+ l = H2D(List*, h);
+ t = l->t;
+
+ if(t != nil) {
+ if(!swept && t->np)
+ freeptrs(l->data, t);
+ t->ref--;
+ if(t->ref == 0) {
+ free(t->initialize);
+ free(t);
+ }
+ }
+ if(swept)
+ return;
+ l = l->tail;
+ while(l != (List*)H) {
+ t = l->t;
+ th = D2H(l);
+ if(th->ref-- != 1)
+ break;
+ th->t->ref--; /* should be &Tlist and ref shouldn't go to 0 here nor be 0 already */
+ if(t != nil) {
+ if (t->np)
+ freeptrs(l->data, t);
+ t->ref--;
+ if(t->ref == 0) {
+ free(t->initialize);
+ free(t);
+ }
+ }
+ l = l->tail;
+ if(heapmonitor != nil)
+ heapmonitor(1, th, 0);
+ poolfree(heapmem, th);
+ }
+}
+
+void
+freemodlink(Heap *h, int swept)
+{
+ Modlink *ml;
+
+ ml = H2D(Modlink*, h);
+ if(ml->m->rt == DYNMOD)
+ freedyndata(ml);
+ else if(!swept)
+ destroy(ml->MP);
+ unload(ml->m);
+}
+
+int
+heapref(void *v)
+{
+ return D2H(v)->ref;
+}
+
+void
+freeheap(Heap *h, int swept)
+{
+ Type *t;
+
+ if(swept)
+ return;
+
+ t = h->t;
+ if (t->np)
+ freeptrs(H2D(void*, h), t);
+}
+
+void
+destroy(void *v)
+{
+ Heap *h;
+ Type *t;
+
+ if(v == H)
+ return;
+
+ h = D2H(v);
+ { Bhdr *b; D2B(b, h); } /* consistency check */
+
+ if(--h->ref > 0 || gchalt > 64) /* Protect 'C' thread stack */
+ return;
+
+ if(heapmonitor != nil)
+ heapmonitor(1, h, 0);
+ t = h->t;
+ if(t != nil) {
+ gclock();
+ t->free(h, 0);
+ gcunlock();
+ freetype(t);
+ }
+ poolfree(heapmem, h);
+}
+
+Type*
+dtype(void (*destroy)(Heap*, int), int size, uchar *map, int mapsize)
+{
+ Type *t;
+
+ t = malloc(sizeof(Type)-sizeof(t->map)+mapsize);
+ if(t != nil) {
+ t->ref = 1;
+ t->free = destroy;
+ t->mark = markheap;
+ t->size = size;
+ t->np = mapsize;
+ memmove(t->map, map, mapsize);
+ }
+ return t;
+}
+
+void*
+checktype(void *v, Type *t, char *name, int newref)
+{
+ Heap *h;
+
+ if(v == H || v == nil)
+ error(exNilref);
+ h = D2H(v);
+ if(t == nil || h->t != t)
+ errorf("%s: %s", exType, name);
+ if(newref){
+ h->ref++;
+ Setmark(h);
+ }
+ return v;
+}
+
+void
+freetype(Type *t)
+{
+ if(t == nil || --t->ref > 0)
+ return;
+
+ free(t->initialize);
+ free(t);
+}
+
+void
+incmem(void *vw, Type *t)
+{
+ Heap *h;
+ uchar *p;
+ int i, c, m;
+ WORD **w, **q, *wp;
+
+ w = (WORD**)vw;
+ p = t->map;
+ for(i = 0; i < t->np; i++) {
+ c = *p++;
+ if(c != 0) {
+ q = w;
+ for(m = 0x80; m != 0; m >>= 1) {
+ if((c & m) && (wp = *q) != H) {
+ h = D2H(wp);
+ h->ref++;
+ Setmark(h);
+ }
+ q++;
+ }
+ }
+ w += 8;
+ }
+}
+
+void
+scanptrs(void *vw, Type *t, void (*f)(void*))
+{
+ uchar *p;
+ int i, c, m;
+ WORD **w, **q, *wp;
+
+ w = (WORD**)vw;
+ p = t->map;
+ for(i = 0; i < t->np; i++) {
+ c = *p++;
+ if(c != 0) {
+ q = w;
+ for(m = 0x80; m != 0; m >>= 1) {
+ if((c & m) && (wp = *q) != H)
+ f(D2H(wp));
+ q++;
+ }
+ }
+ w += 8;
+ }
+}
+
+void
+initmem(Type *t, void *vw)
+{
+ int c;
+ WORD **w;
+ uchar *p, *ep;
+
+ w = (WORD**)vw;
+ p = t->map;
+ ep = p + t->np;
+ while(p < ep) {
+ c = *p;
+ if(c != 0) {
+ if(BIT(c, 0)) w[7] = H;
+ if(BIT(c, 1)) w[6] = H;
+ if(BIT(c, 2)) w[5] = H;
+ if(BIT(c, 3)) w[4] = H;
+ if(BIT(c, 4)) w[3] = H;
+ if(BIT(c, 5)) w[2] = H;
+ if(BIT(c, 6)) w[1] = H;
+ if(BIT(c, 7)) w[0] = H;
+ }
+ p++;
+ w += 8;
+ }
+}
+
+Heap*
+nheap(int n)
+{
+ Heap *h;
+
+ h = poolalloc(heapmem, sizeof(Heap)+n);
+ if(h == nil)
+ error(exHeap);
+
+ h->t = nil;
+ h->ref = 1;
+ h->color = mutator;
+ if(heapmonitor != nil)
+ heapmonitor(0, h, n);
+
+ return h;
+}
+
+Heap*
+heapz(Type *t)
+{
+ Heap *h;
+
+ h = poolalloc(heapmem, sizeof(Heap)+t->size);
+ if(h == nil)
+ error(exHeap);
+
+ h->t = t;
+ t->ref++;
+ h->ref = 1;
+ h->color = mutator;
+ memset(H2D(void*, h), 0, t->size);
+ if(t->np)
+ initmem(t, H2D(void*, h));
+ if(heapmonitor != nil)
+ heapmonitor(0, h, t->size);
+ return h;
+}
+
+Heap*
+heap(Type *t)
+{
+ Heap *h;
+
+ h = poolalloc(heapmem, sizeof(Heap)+t->size);
+ if(h == nil)
+ error(exHeap);
+
+ h->t = t;
+ t->ref++;
+ h->ref = 1;
+ h->color = mutator;
+ if(t->np)
+ initmem(t, H2D(void*, h));
+ if(heapmonitor != nil)
+ heapmonitor(0, h, t->size);
+ return h;
+}
+
+Heap*
+heaparray(Type *t, int sz)
+{
+ Heap *h;
+ Array *a;
+
+ h = nheap(sizeof(Array) + (t->size*sz));
+ h->t = &Tarray;
+ Tarray.ref++;
+ a = H2D(Array*, h);
+ a->t = t;
+ a->len = sz;
+ a->root = H;
+ a->data = (uchar*)a + sizeof(Array);
+ initarray(t, a);
+ return h;
+}
+
+int
+hmsize(void *v)
+{
+ return poolmsize(heapmem, v);
+}
+
+void
+initarray(Type *t, Array *a)
+{
+ int i;
+ uchar *p;
+
+ t->ref++;
+ if(t->np == 0)
+ return;
+
+ p = a->data;
+ for(i = 0; i < a->len; i++) {
+ initmem(t, p);
+ p += t->size;
+ }
+}
+
+void*
+arraycpy(Array *sa)
+{
+ int i;
+ Heap *dh;
+ Array *da;
+ uchar *elemp;
+ void **sp, **dp;
+
+ if(sa == H)
+ return H;
+
+ dh = nheap(sizeof(Array) + sa->t->size*sa->len);
+ dh->t = &Tarray;
+ Tarray.ref++;
+ da = H2D(Array*, dh);
+ da->t = sa->t;
+ da->t->ref++;
+ da->len = sa->len;
+ da->root = H;
+ da->data = (uchar*)da + sizeof(Array);
+ if(da->t == &Tarray) {
+ dp = (void**)da->data;
+ sp = (void**)sa->data;
+ /*
+ * Maximum depth of this recursion is set by DADEPTH
+ * in include/isa.h
+ */
+ for(i = 0; i < sa->len; i++)
+ dp[i] = arraycpy(sp[i]);
+ }
+ else {
+ memmove(da->data, sa->data, da->len*sa->t->size);
+ elemp = da->data;
+ for(i = 0; i < sa->len; i++) {
+ incmem(elemp, da->t);
+ elemp += da->t->size;
+ }
+ }
+ return da;
+}
+
+void
+newmp(void *dst, void *src, Type *t)
+{
+ Heap *h;
+ int c, i, m;
+ void **uld, *wp, **q;
+
+ memmove(dst, src, t->size);
+ uld = dst;
+ for(i = 0; i < t->np; i++) {
+ c = t->map[i];
+ if(c != 0) {
+ m = 0x80;
+ q = uld;
+ while(m != 0) {
+ if((m & c) && (wp = *q) != H) {
+ h = D2H(wp);
+ if(h->t == &Tarray)
+ *q = arraycpy(wp);
+ else {
+ h->ref++;
+ Setmark(h);
+ }
+ }
+ m >>= 1;
+ q++;
+ }
+ }
+ uld += 8;
+ }
+}
--- /dev/null
+++ b/libinterp/heapaudit.c
@@ -1,0 +1,198 @@
+#include "lib9.h"
+#include "interp.h"
+#include "pool.h"
+
+
+typedef struct Audit Audit;
+struct Audit
+{
+ Type* t;
+ ulong n;
+ ulong size;
+ Audit* hash;
+};
+Audit* ahash[128];
+extern Pool* heapmem;
+extern void conslog(char*, ...);
+#define conslog print
+
+typedef struct Typed Typed;
+typedef struct Ptyped Ptyped;
+
+extern Type Trdchan;
+extern Type Twrchan;
+
+struct Typed
+{
+ char* name;
+ Type* ptr;
+} types[] =
+{
+ {"array", &Tarray},
+ {"byte", &Tbyte},
+ {"channel", &Tchannel},
+ {"list", &Tlist},
+ {"modlink", &Tmodlink},
+ {"ptr", &Tptr},
+ {"string", &Tstring},
+
+ {"rdchan", &Trdchan},
+ {"wrchan", &Twrchan},
+ {"unspec", nil},
+
+ 0
+};
+
+extern Type* TDisplay;
+extern Type* TFont;
+extern Type* TImage;
+extern Type* TScreen;
+extern Type* TFD;
+extern Type* TFileIO;
+extern Type* Tread;
+extern Type* Twrite;
+extern Type* fakeTkTop;
+
+extern Type* TSigAlg;
+extern Type* TCertificate;
+extern Type* TSK;
+extern Type* TPK;
+extern Type* TDigestState;
+extern Type* TAuthinfo;
+extern Type* TDESstate;
+extern Type* TIPint;
+
+struct Ptyped
+{
+ char* name;
+ Type** ptr;
+} ptypes[] =
+{
+ {"Display", &TDisplay},
+ {"Font", &TFont},
+ {"Image", &TImage},
+ {"Screen", &TScreen},
+
+ {"SigAlg", &TSigAlg},
+ {"Certificate", &TCertificate},
+ {"SK", &TSK},
+ {"PK", &TPK},
+ {"DigestState", &TDigestState},
+ {"Authinfo", &TAuthinfo},
+ {"DESstate", &TDESstate},
+ {"IPint", &TIPint},
+
+ {"FD", &TFD},
+ {"FileIO", &TFileIO},
+
+/* {"Fioread", &Tread}, */
+/* {"Fiowrite", &Twrite}, */
+
+ {"TkTop", &fakeTkTop},
+
+ 0
+};
+
+static Audit **
+auditentry(Type *t)
+{
+ Audit **h, *a;
+
+ for(h = &ahash[((ulong)t>>2)%nelem(ahash)]; (a = *h) != nil; h = &a->hash)
+ if(a->t == t)
+ break;
+ return h;
+}
+
+void
+heapaudit(void)
+{
+ Type *t;
+ Heap *h;
+ List *l;
+ Array *r;
+ Module *m;
+ int i, ntype, n;
+ Bhdr *b, *base, *limit;
+ Audit *a, **hash;
+
+ acquire();
+
+ b = poolchain(heapmem);
+ base = b;
+ limit = B2LIMIT(b);
+
+ while(b != nil) {
+ if(b->magic == MAGIC_A) {
+ h = B2D(b);
+ t = h->t;
+ n = 1;
+ if(t == &Tlist) {
+ l = H2D(List*, h);
+ t = l->t;
+ } else if(t == &Tarray) {
+ r = H2D(Array*, h);
+ t = r->t;
+ n = r->len;
+ }
+ hash = auditentry(t);
+ if((a = *hash) == nil){
+ a = malloc(sizeof(Audit));
+ if(a == nil)
+ continue;
+ a->n = 1;
+ a->t = t;
+ a->hash = *hash;
+ *hash = a;
+ }else
+ a->n++;
+ if(t != nil && t != &Tmodlink && t != &Tstring)
+ a->size += t->size*n;
+ else
+ a->size += b->size;
+ }
+ b = B2NB(b);
+ if(b >= limit) {
+ base = base->clink;
+ if(base == nil)
+ break;
+ b = base;
+ limit = B2LIMIT(base);
+ }
+ }
+
+ for(m = modules; m != nil; m = m->link) {
+ for(i = 0; i < m->ntype; i++)
+ if((a = *auditentry(m->type[i])) != nil) {
+ conslog("%8ld %8lud %3d %s\n", a->n, a->size, i, m->path);
+ a->size = 0;
+ break;
+ }
+ }
+
+ for(i = 0; (t = types[i].ptr) != nil; i++)
+ if((a = *auditentry(t)) != nil){
+ conslog("%8ld %8lud %s\n", a->n, a->size, types[i].name);
+ a->size = 0;
+ break;
+ }
+
+ for(i = 0; ptypes[i].name != nil; i++)
+ if((a = *auditentry(*ptypes[i].ptr)) != nil){
+ conslog("%8ld %8lud %s\n", a->n, a->size, ptypes[i].name);
+ a->size = 0;
+ break;
+ }
+
+ ntype = 0;
+ for(i = 0; i < nelem(ahash); i++)
+ while((a = ahash[i]) != nil){
+ ahash[i] = a->hash;
+ if(a->size != 0)
+ conslog("%8ld %8lud %p\n", a->n, a->size, a->t);
+ free(a);
+ ntype++;
+ }
+
+ release();
+}
--- /dev/null
+++ b/libinterp/ipint.c
@@ -1,0 +1,848 @@
+#include "lib9.h"
+#include "kernel.h"
+#include <isa.h>
+#include "interp.h"
+#include "runt.h"
+#include <mp.h>
+#include <libsec.h>
+#include "pool.h"
+#include "ipint.h"
+#include "raise.h"
+
+#include "ipintsmod.h"
+
+enum
+{
+ MaxBigBytes = 1024
+};
+
+/* infinite precision integer */
+struct IPint
+{
+ IPints_IPint x;
+ mpint* b;
+};
+
+Type *TIPint;
+static uchar IPintmap[] = IPints_IPint_map;
+
+#define MP(x) checkIPint((x))
+
+void
+ipintsmodinit(void)
+{
+ /* can be called from modinit, Keyring or Crypt */
+ if(TIPint == nil)
+ TIPint = dtype(freeIPint, sizeof(IPint), IPintmap, sizeof(IPintmap));
+ builtinmod("$IPints", IPintsmodtab, IPintsmodlen);
+}
+
+//IPints_IPint*
+void*
+newIPint(mpint* b)
+{
+ Heap *h;
+ IPint *ip;
+
+ if(b == nil)
+ error(exHeap);
+ h = heap(TIPint); /* TO DO: caller might lose other values if heap raises error here */
+ ip = H2D(IPint*, h);
+ ip->b = b;
+ return (IPints_IPint*)ip;
+}
+
+mpint*
+checkIPint(void *a)
+{
+ IPints_IPint *v;
+ IPint *ip;
+
+ v = a;
+ ip = (IPint*)v;
+ if(ip == H || ip == nil)
+ error(exNilref);
+ if(D2H(ip)->t != TIPint)
+ error(exType);
+ return ip->b; /* non-nil by construction */
+}
+
+void
+freeIPint(Heap *h, int swept)
+{
+ IPint *ip;
+
+ USED(swept);
+ ip = H2D(IPint*, h);
+ if(ip->b)
+ mpfree(ip->b);
+ freeheap(h, 0);
+}
+
+void
+IPint_iptob64z(void *fp)
+{
+ F_IPint_iptob64 *f;
+ mpint *b;
+ char buf[MaxBigBytes]; /* TO DO: should allocate these */
+ uchar *p;
+ int n, o;
+ void *v;
+
+ f = fp;
+ v = *f->ret;
+ *f->ret = H;
+ destroy(v);
+
+ b = MP(f->i);
+ n = (b->top+1)*Dbytes;
+ p = malloc(n+1);
+ if(p == nil)
+ error(exHeap);
+ n = mptobe(b, p+1, n, nil);
+ if(n < 0){
+ free(p);
+ return;
+ }
+ p[0] = 0;
+ if(n != 0 && (p[1]&0x80)){
+ /* force leading 0 byte for compatibility with older representation */
+ o = 0;
+ n++;
+ }else
+ o = 1;
+ enc64(buf, sizeof(buf), p+o, n);
+ retstr(buf, f->ret);
+ free(p);
+}
+
+void
+IPint_iptob64(void *fp)
+{
+ F_IPint_iptob64 *f;
+ char buf[MaxBigBytes];
+ void *v;
+
+ f = fp;
+ v = *f->ret;
+ *f->ret = H;
+ destroy(v);
+
+ mptoa(MP(f->i), 64, buf, sizeof(buf));
+ retstr(buf, f->ret);
+}
+
+void
+IPint_iptobytes(void *fp)
+{
+ F_IPint_iptobytes *f;
+ uchar buf[MaxBigBytes];
+ void *v;
+
+ f = fp;
+ v = *f->ret;
+ *f->ret = H;
+ destroy(v);
+
+ /* TO DO: two's complement or have ipmagtobe? */
+ *f->ret = mem2array(buf, mptobe(MP(f->i), buf, sizeof(buf), nil)); /* for now we'll ignore sign */
+}
+
+void
+IPint_iptobebytes(void *fp)
+{
+ F_IPint_iptobebytes *f;
+ uchar buf[MaxBigBytes];
+ void *v;
+
+ f = fp;
+ v = *f->ret;
+ *f->ret = H;
+ destroy(v);
+
+ *f->ret = mem2array(buf, mptobe(MP(f->i), buf, sizeof(buf), nil));
+}
+
+void
+IPint_iptostr(void *fp)
+{
+ F_IPint_iptostr *f;
+ char buf[MaxBigBytes];
+ void *v;
+
+ f = fp;
+ v = *f->ret;
+ *f->ret = H;
+ destroy(v);
+
+ mptoa(MP(f->i), f->base, buf, sizeof(buf));
+ retstr(buf, f->ret);
+}
+
+static IPints_IPint*
+strtoipint(String *s, int base)
+{
+ char *p, *q;
+ mpint *b;
+
+ p = string2c(s);
+ b = strtomp(p, &q, base, nil);
+ if(b == nil)
+ return H;
+ while(*q == '=')
+ q++;
+ if(q == p || *q != 0){
+ mpfree(b);
+ return H;
+ }
+ return newIPint(b);
+}
+
+void
+IPint_b64toip(void *fp)
+{
+ F_IPint_b64toip *f;
+ void *v;
+
+ f = fp;
+ v = *f->ret;
+ *f->ret = H;
+ destroy(v);
+
+ *f->ret = strtoipint(f->str, 64);
+}
+
+void
+IPint_bytestoip(void *fp)
+{
+ F_IPint_bytestoip *f;
+ mpint *b;
+ void *v;
+
+ f = fp;
+ v = *f->ret;
+ *f->ret = H;
+ destroy(v);
+
+ if(f->buf == H)
+ error(exNilref);
+
+ b = betomp(f->buf->data, f->buf->len, nil); /* for now we'll ignore sign */
+ *f->ret = newIPint(b);
+}
+
+void
+IPint_bebytestoip(void *fp)
+{
+ F_IPint_bebytestoip *f;
+ mpint *b;
+ void *v;
+
+ f = fp;
+ v = *f->ret;
+ *f->ret = H;
+ destroy(v);
+
+ if(f->mag == H)
+ error(exNilref);
+
+ b = betomp(f->mag->data, f->mag->len, nil);
+ *f->ret = newIPint(b);
+}
+
+void
+IPint_strtoip(void *fp)
+{
+ F_IPint_strtoip *f;
+ void *v;
+
+ f = fp;
+ v = *f->ret;
+ *f->ret = H;
+ destroy(v);
+
+ *f->ret = strtoipint(f->str, f->base);
+}
+
+/* create a random integer */
+void
+IPint_random(void *fp)
+{
+ F_IPint_random *f;
+ mpint *b;
+ void *v;
+
+ f = fp;
+ v = *f->ret;
+ *f->ret = H;
+ destroy(v);
+
+ release();
+ b = mprand(f->nbits, genrandom, nil);
+ acquire();
+ *f->ret = newIPint(b);
+}
+
+/* number of bits in number */
+void
+IPint_bits(void *fp)
+{
+ F_IPint_bits *f;
+ int n;
+
+ f = fp;
+ *f->ret = 0;
+ if(f->i == H)
+ return;
+
+ n = mpsignif(MP(f->i));
+ if(n == 0)
+ n = 1; /* compatibility */
+ *f->ret = n;
+}
+
+/* create a new IP from an int */
+void
+IPint_inttoip(void *fp)
+{
+ F_IPint_inttoip *f;
+ void *v;
+
+ f = fp;
+ v = *f->ret;
+ *f->ret = H;
+ destroy(v);
+
+ *f->ret = newIPint(itomp(f->i, nil));
+}
+
+void
+IPint_iptoint(void *fp)
+{
+ F_IPint_iptoint *f;
+
+ f = fp;
+ *f->ret = 0;
+ if(f->i == H)
+ return;
+ *f->ret = mptoi(MP(f->i));
+}
+
+/* modular exponentiation */
+void
+IPint_expmod(void *fp)
+{
+ F_IPint_expmod *f;
+ mpint *ret, *mod, *base, *exp;
+ void *v;
+
+ f = fp;
+ v = *f->ret;
+ *f->ret = H;
+ destroy(v);
+
+ base = MP(f->base);
+ exp = MP(f->exp);
+ if(f->mod != H)
+ mod = MP(f->mod);
+ else
+ mod = nil;
+ ret = mpnew(0);
+ if(ret != nil)
+ mpexp(base, exp, mod, ret);
+ *f->ret = newIPint(ret);
+}
+
+/* multiplicative inverse */
+void
+IPint_invert(void *fp)
+{
+ F_IPint_invert *f;
+ mpint *ret;
+ void *v;
+
+ f = fp;
+ v = *f->ret;
+ *f->ret = H;
+ destroy(v);
+
+ ret = mpnew(0);
+ if(ret != nil)
+ mpinvert(MP(f->base), MP(f->mod), ret);
+ *f->ret = newIPint(ret);
+}
+
+/* basic math */
+void
+IPint_add(void *fp)
+{
+ F_IPint_add *f;
+ mpint *i1, *i2, *ret;
+ void *v;
+
+ f = fp;
+ v = *f->ret;
+ *f->ret = H;
+ destroy(v);
+
+ i1 = MP(f->i1);
+ i2 = MP(f->i2);
+ ret = mpnew(0);
+ if(ret != nil)
+ mpadd(i1, i2, ret);
+
+ *f->ret = newIPint(ret);
+}
+void
+IPint_sub(void *fp)
+{
+ F_IPint_sub *f;
+ mpint *i1, *i2, *ret;
+ void *v;
+
+ f = fp;
+ v = *f->ret;
+ *f->ret = H;
+ destroy(v);
+
+ i1 = MP(f->i1);
+ i2 = MP(f->i2);
+ ret = mpnew(0);
+ if(ret != nil)
+ mpsub(i1, i2, ret);
+
+ *f->ret = newIPint(ret);
+}
+void
+IPint_mul(void *fp)
+{
+ F_IPint_mul *f;
+ mpint *i1, *i2, *ret;
+ void *v;
+
+ f = fp;
+ v = *f->ret;
+ *f->ret = H;
+ destroy(v);
+
+ i1 = MP(f->i1);
+ i2 = MP(f->i2);
+ ret = mpnew(0);
+ if(ret != nil)
+ mpmul(i1, i2, ret);
+
+ *f->ret = newIPint(ret);
+}
+void
+IPint_div(void *fp)
+{
+ F_IPint_div *f;
+ mpint *i1, *i2, *quo, *rem;
+ void *v;
+
+ f = fp;
+ v = f->ret->t0;
+ f->ret->t0 = H;
+ destroy(v);
+ v = f->ret->t1;
+ f->ret->t1 = H;
+ destroy(v);
+
+ i1 = MP(f->i1);
+ i2 = MP(f->i2);
+ quo = mpnew(0);
+ if(quo == nil)
+ error(exHeap);
+ rem = mpnew(0);
+ if(rem == nil){
+ mpfree(quo);
+ error(exHeap);
+ }
+ mpdiv(i1, i2, quo, rem);
+
+ f->ret->t0 = newIPint(quo);
+ f->ret->t1 = newIPint(rem);
+}
+void
+IPint_mod(void *fp)
+{
+ F_IPint_mod *f;
+ mpint *i1, *i2, *ret;
+ void *v;
+
+ f = fp;
+ v = *f->ret;
+ *f->ret = H;
+ destroy(v);
+
+ i1 = MP(f->i1);
+ i2 = MP(f->i2);
+ ret = mpnew(0);
+ if(ret != nil)
+ mpmod(i1, i2, ret);
+
+ *f->ret = newIPint(ret);
+}
+void
+IPint_neg(void *fp)
+{
+ F_IPint_neg *f;
+ mpint *ret;
+ void *v;
+
+ f = fp;
+ v = *f->ret;
+ *f->ret = H;
+ destroy(v);
+
+ ret = mpcopy(MP(f->i));
+ if(ret == nil)
+ error(exHeap);
+ ret->sign = -ret->sign;
+
+ *f->ret = newIPint(ret);
+}
+
+/* copy */
+void
+IPint_copy(void *fp)
+{
+ F_IPint_copy *f;
+ void *v;
+
+ f = fp;
+ v = *f->ret;
+ *f->ret = H;
+ destroy(v);
+
+ *f->ret = newIPint(mpcopy(MP(f->i)));
+}
+
+
+/* equality */
+void
+IPint_eq(void *fp)
+{
+ F_IPint_eq *f;
+
+ f = fp;
+ *f->ret = mpcmp(MP(f->i1), MP(f->i2)) == 0;
+}
+
+/* compare */
+void
+IPint_cmp(void *fp)
+{
+ F_IPint_eq *f;
+
+ f = fp;
+ *f->ret = mpcmp(MP(f->i1), MP(f->i2));
+}
+
+/* shifts */
+void
+IPint_shl(void *fp)
+{
+ F_IPint_shl *f;
+ mpint *ret, *i;
+ void *v;
+
+ f = fp;
+ v = *f->ret;
+ *f->ret = H;
+ destroy(v);
+
+ i = MP(f->i);
+ ret = mpnew(0);
+ if(ret != nil)
+ mpleft(i, f->n, ret);
+ *f->ret = newIPint(ret);
+}
+void
+IPint_shr(void *fp)
+{
+ F_IPint_shr *f;
+ mpint *ret, *i;
+ void *v;
+
+ f = fp;
+ v = *f->ret;
+ *f->ret = H;
+ destroy(v);
+
+ i = MP(f->i);
+ ret = mpnew(0);
+ if(ret != nil)
+ mpright(i, f->n, ret);
+ *f->ret = newIPint(ret);
+}
+
+static void
+mpand(mpint *b, mpint *m, mpint *res)
+{
+ int i;
+
+ res->sign = b->sign;
+ if(b->top == 0 || m->top == 0){
+ res->top = 0;
+ return;
+ }
+ mpbits(res, b->top*Dbits);
+ res->top = b->top;
+ for(i = b->top; --i >= 0;){
+ if(i < m->top)
+ res->p[i] = b->p[i] & m->p[i];
+ else
+ res->p[i] = 0;
+ }
+ mpnorm(res);
+}
+
+static void
+mpor(mpint *b1, mpint *b2, mpint *res)
+{
+ mpint *t;
+ int i;
+
+ if(b2->top > b1->top){
+ t = b1;
+ b1 = b2;
+ b2 = t;
+ }
+ if(b1->top == 0){
+ mpassign(b2, res);
+ return;
+ }
+ if(b2->top == 0){
+ mpassign(b1, res);
+ return;
+ }
+ mpassign(b1, res);
+ for(i = b2->top; --i >= 0;)
+ res->p[i] |= b2->p[i];
+ mpnorm(res);
+}
+
+static void
+mpxor(mpint *b1, mpint *b2, mpint *res)
+{
+ mpint *t;
+ int i;
+
+ if(b2->top > b1->top){
+ t = b1;
+ b1 = b2;
+ b2 = t;
+ }
+ if(b1->top == 0){
+ mpassign(b2, res);
+ return;
+ }
+ if(b2->top == 0){
+ mpassign(b1, res);
+ return;
+ }
+ mpassign(b1, res);
+ for(i = b2->top; --i >= 0;)
+ res->p[i] ^= b2->p[i];
+ mpnorm(res);
+}
+
+static void
+mpnot(mpint *b1, mpint *res)
+{
+ int i;
+
+ mpbits(res, Dbits*b1->top);
+ res->sign = 1;
+ res->top = b1->top;
+ for(i = res->top; --i >= 0;)
+ res->p[i] = ~b1->p[i];
+ mpnorm(res);
+}
+
+/* bits */
+void
+IPint_and(void *fp)
+{
+ F_IPint_and *f;
+ mpint *ret, *i1, *i2;
+ void *v;
+
+ f = fp;
+ v = *f->ret;
+ *f->ret = H;
+ destroy(v);
+
+ i1 = MP(f->i1);
+ i2 = MP(f->i2);
+ ret = mpnew(0);
+ if(ret != nil)
+ mpand(i1, i2, ret);
+ *f->ret = newIPint(ret);
+}
+
+void
+IPint_ori(void *fp)
+{
+ F_IPint_ori *f;
+ mpint *ret, *i1, *i2;
+ void *v;
+
+ f = fp;
+ v = *f->ret;
+ *f->ret = H;
+ destroy(v);
+
+ i1 = MP(f->i1);
+ i2 = MP(f->i2);
+ ret = mpnew(0);
+ if(ret != nil)
+ mpor(i1, i2, ret);
+ *f->ret = newIPint(ret);
+}
+
+void
+IPint_xor(void *fp)
+{
+ F_IPint_xor *f;
+ mpint *ret, *i1, *i2;
+ void *v;
+
+ f = fp;
+ v = *f->ret;
+ *f->ret = H;
+ destroy(v);
+
+ i1 = MP(f->i1);
+ i2 = MP(f->i2);
+ ret = mpnew(0);
+ if(ret != nil)
+ mpxor(i1, i2, ret);
+ *f->ret = newIPint(ret);
+}
+
+void
+IPint_not(void *fp)
+{
+ F_IPint_not *f;
+ mpint *ret, *i1;
+ void *v;
+
+ f = fp;
+ v = *f->ret;
+ *f->ret = H;
+ destroy(v);
+
+ i1 = MP(f->i1);
+ ret = mpnew(0);
+ if(ret != nil)
+ mpnot(i1, ret);
+ *f->ret = newIPint(ret);
+}
+
+/*
+ * primes
+ */
+
+void
+IPints_probably_prime(void *fp)
+{
+ F_IPints_probably_prime *f;
+
+ f = fp;
+ release();
+ *f->ret = probably_prime(checkIPint(f->n), f->nrep);
+ acquire();
+}
+
+void
+IPints_genprime(void *fp)
+{
+ F_IPints_genprime *f;
+ mpint *p;
+ void *r;
+
+ f = fp;
+ r = *f->ret;
+ *f->ret = H;
+ destroy(r);
+ p = mpnew(0);
+ release();
+ genprime(p, f->nbits, f->nrep);
+ acquire();
+ *f->ret = newIPint(p);
+}
+
+void
+IPints_genstrongprime(void *fp)
+{
+ F_IPints_genstrongprime *f;
+ mpint *p;
+ void *r;
+
+ f = fp;
+ r = *f->ret;
+ *f->ret = H;
+ destroy(r);
+ p = mpnew(0);
+ release();
+ genstrongprime(p, f->nbits, f->nrep);
+ acquire();
+ *f->ret = newIPint(p);
+}
+
+void
+IPints_gensafeprime(void *fp)
+{
+ F_IPints_gensafeprime *f;
+ mpint *p, *alpha;
+ void *v;
+
+ f = fp;
+ v = f->ret->t0;
+ f->ret->t0 = H;
+ destroy(v);
+ v = f->ret->t1;
+ f->ret->t1 = H;
+ destroy(v);
+
+ p = mpnew(0);
+ alpha = mpnew(0);
+ release();
+ gensafeprime(p, alpha, f->nbits, f->nrep);
+ acquire();
+ f->ret->t0 = newIPint(p);
+ f->ret->t1 = newIPint(alpha);
+}
+
+void
+IPints_DSAprimes(void *fp)
+{
+ F_IPints_DSAprimes *f;
+ mpint *p, *q;
+ Heap *h;
+ void *v;
+
+ f = fp;
+ v = f->ret->t0;
+ f->ret->t0 = H;
+ destroy(v);
+ v = f->ret->t1;
+ f->ret->t1 = H;
+ destroy(v);
+ v = f->ret->t2;
+ f->ret->t2 = H;
+ destroy(v);
+
+ h = heaparray(&Tbyte, SHA1dlen);
+ f->ret->t2 = H2D(Array*, h);
+
+ p = mpnew(0);
+ q = mpnew(0);
+ release();
+ DSAprimes(q, p, f->ret->t2->data);
+ acquire();
+ f->ret->t0 = newIPint(q);
+ f->ret->t1 = newIPint(p);
+}
--- /dev/null
+++ b/libinterp/ipint.h
@@ -1,0 +1,12 @@
+typedef struct IPint IPint;
+
+#pragma incomplete IPint
+
+//Keyring_IPint* newIPint(mpint*);
+void* newIPint(mpint*);
+//mpint* checkIPint(Keyring_IPint*);
+mpint* checkIPint(void*);
+void freeIPint(Heap*, int);
+void ipintsmodinit(void);
+
+extern Type* TIPint;
--- /dev/null
+++ b/libinterp/keyring.c
@@ -1,0 +1,3083 @@
+#include "lib9.h"
+#include "kernel.h"
+#include <isa.h>
+#include "interp.h"
+#include <mp.h>
+#include <libsec.h>
+#include "pool.h"
+#include "raise.h"
+
+/* arguably limbo -t should qualify type name */
+#define DigestState_copy Keyring_DigestState_copy
+#define IPint_random Keyring_IPint_random
+#include "keyringif.h"
+#include "keyring.h"
+
+#include "ipint.h"
+#include "../libkeyring/keys.h"
+
+static Type* TDigestState;
+static Type* TAESstate;
+static Type* TDESstate;
+static Type* TIDEAstate;
+static Type* TBFstate;
+static Type* TRC4state;
+
+static Type* TSigAlg;
+static Type* TCertificate;
+static Type* TSK;
+static Type* TPK;
+static Type* TAuthinfo;
+
+static Type* TDSAsk;
+static Type* TDSApk;
+static Type* TDSAsig;
+static Type* TEGsk;
+static Type* TEGpk;
+static Type* TEGsig;
+static Type* TRSAsk;
+static Type* TRSApk;
+static Type* TRSAsig;
+
+enum {
+ Maxmsg= 4096
+};
+
+static uchar DigestStatemap[] = Keyring_DigestState_map;
+static uchar AESstatemap[] = Keyring_AESstate_map;
+static uchar DESstatemap[] = Keyring_DESstate_map;
+static uchar IDEAstatemap[] = Keyring_IDEAstate_map;
+static uchar BFstatemap[] = Keyring_BFstate_map;
+static uchar RC4statemap[] = Keyring_RC4state_map;
+
+static uchar SigAlgmap[] = Keyring_SigAlg_map;
+static uchar SKmap[] = Keyring_SK_map;
+static uchar PKmap[] = Keyring_PK_map;
+static uchar Certificatemap[] = Keyring_Certificate_map;
+static uchar Authinfomap[] = Keyring_Authinfo_map;
+static uchar DSAskmap[] = Keyring_DSAsk_map;
+static uchar DSApkmap[] = Keyring_DSApk_map;
+static uchar DSAsigmap[] = Keyring_DSAsig_map;
+static uchar EGskmap[] = Keyring_EGsk_map;
+static uchar EGpkmap[] = Keyring_EGpk_map;
+static uchar EGsigmap[] = Keyring_EGsig_map;
+static uchar RSAskmap[] = Keyring_RSAsk_map;
+static uchar RSApkmap[] = Keyring_RSApk_map;
+static uchar RSAsigmap[] = Keyring_RSAsig_map;
+
+static PK* checkPK(Keyring_PK *k);
+
+extern void setid(char*, int);
+extern vlong osusectime(void);
+extern void freeIPint(Heap*, int);
+
+static char exBadSA[] = "bad signature algorithm";
+static char exBadSK[] = "bad secret key";
+static char exBadPK[] = "bad public key";
+static char exBadCert[] = "bad certificate";
+static char exBadBsize[] = "data not multiple of block size";
+static char exBadKey[] = "bad encryption key";
+static char exBadDigest[] = "bad digest value";
+static char exBadIvec[] = "bad ivec";
+static char exBadState[] = "bad encryption state";
+
+typedef struct XBFstate XBFstate;
+
+/* BF state */
+struct XBFstate
+{
+ Keyring_BFstate x;
+ BFstate state;
+};
+
+/* convert a Big to base64 ascii */
+int
+bigtobase64(mpint* b, char *buf, int len)
+{
+ uchar *p;
+ int n, rv, o;
+
+ n = (b->top+1)*Dbytes;
+ p = malloc(n+1);
+ if(p == nil)
+ goto Err;
+ n = mptobe(b, p+1, n, nil);
+ if(n < 0)
+ goto Err;
+ p[0] = 0;
+ if(n != 0 && (p[1]&0x80)){
+ /* force leading 0 byte for compatibility with older representation */
+ /* TO DO: if b->sign < 0, complement bits and add one */
+ o = 0;
+ n++;
+ }else
+ o = 1;
+ rv = enc64(buf, len, p+o, n);
+ free(p);
+ return rv;
+
+Err:
+ free(p);
+ if(len > 0){
+ *buf = '*';
+ return 1;
+ }
+ return 0;
+}
+
+/* convert a Big to base64 ascii for %U */
+int
+big64conv(Fmt *f)
+{
+ mpint *b;
+ char *buf;
+ int n;
+
+ b = va_arg(f->args, mpint*);
+ n = (b->top+1)*Dbytes + 1;
+ n = ((n+3)/3)*4 + 1;
+ buf = malloc(n);
+ bigtobase64(b, buf, n);
+ n = fmtstrcpy(f, buf);
+ free(buf);
+ return n;
+}
+
+static void*
+newthing(Type *t, int add)
+{
+ Heap *h;
+
+ h = heap(t);
+ if(add)
+ ptradd(h);
+ return H2D(void*, h);
+}
+
+static Keyring_IPint*
+ipcopymp(mpint* b)
+{
+ if(b == nil)
+ return H;
+ return newIPint(mpcopy(b));
+}
+
+/* convert a base64 string to a big */
+mpint*
+base64tobig(char *str, char **strp)
+{
+ int n;
+ char *p;
+ mpint *b;
+ uchar hex[(MaxBigBytes*6 + 7)/8];
+
+ for(p = str; *p && *p != '\n'; p++)
+ ;
+ if(p == str)
+ return nil;
+ n = dec64(hex, sizeof(hex), str, p - str);
+ b = betomp(hex, n, nil);
+ if(strp){
+ if(*p)
+ p++;
+ *strp = p;
+ }
+ return b;
+}
+
+/*
+ * signature algorithms
+ */
+enum
+{
+ Maxalg = 8
+};
+static SigAlgVec *algs[Maxalg];
+static int nalg;
+
+static SigAlg*
+newSigAlg(SigAlgVec *vec)
+{
+ Heap *h;
+ SigAlg *sa;
+
+ h = heap(TSigAlg);
+ sa = H2D(SigAlg*, h);
+ retstr(vec->name, &sa->x.name);
+ sa->vec = vec;
+ return sa;
+}
+
+static void
+freeSigAlg(Heap *h, int swept)
+{
+ if(!swept)
+ freeheap(h, 0);
+}
+
+SigAlgVec*
+findsigalg(char *name)
+{
+ SigAlgVec **sap;
+
+ for(sap = algs; sap < &algs[nalg]; sap++)
+ if(strcmp(name, (*sap)->name) == 0)
+ return *sap;
+ return nil;
+}
+
+SigAlg*
+strtoalg(char *str, char **strp)
+{
+ int n;
+ char *p, name[20];
+ SigAlgVec *sa;
+
+
+ p = strchr(str, '\n');
+ if(p == 0){
+ p = str + strlen(str);
+ if(strp)
+ *strp = p;
+ } else {
+ if(strp)
+ *strp = p+1;
+ }
+
+ n = p - str;
+ if(n < sizeof(name)){
+ strncpy(name, str, n);
+ name[n] = 0;
+ sa = findsigalg(name);
+ if(sa != nil)
+ return newSigAlg(sa);
+ }
+ return nil;
+}
+
+static SigAlg*
+checkSigAlg(Keyring_SigAlg *ksa)
+{
+ SigAlgVec **sap;
+ SigAlg *sa;
+
+ sa = (SigAlg*)ksa;
+
+ for(sap = algs; sap < &algs[Maxalg]; sap++)
+ if(sa->vec == *sap)
+ return sa;
+ errorf("%s: %s", exType, exBadSA);
+ return nil;
+}
+
+/*
+ * parse next new line terminated string into a String
+ */
+String*
+strtostring(char *str, char **strp)
+{
+ char *p;
+ String *s;
+
+ p = strchr(str, '\n');
+ if(p == 0)
+ p = str + strlen(str);
+ s = H;
+ retnstr(str, p - str, &s);
+
+ if(strp){
+ if(*p)
+ p++;
+ *strp = p;
+ }
+
+ return s;
+}
+
+/*
+ * private part of a key
+ */
+static SK*
+newSK(SigAlg *sa, String *owner, int increfsa)
+{
+ Heap *h;
+ SK *k;
+
+ h = heap(TSK);
+ k = H2D(SK*, h);
+ k->x.sa = (Keyring_SigAlg*)sa;
+ if(increfsa) {
+ h = D2H(sa);
+ h->ref++;
+ Setmark(h);
+ }
+ k->x.owner = owner;
+ k->key = 0;
+ return k;
+}
+
+static void
+freeSK(Heap *h, int swept)
+{
+ SK *k;
+ SigAlg *sa;
+
+ k = H2D(SK*, h);
+ sa = checkSigAlg(k->x.sa);
+ if(k->key)
+ (*sa->vec->skfree)(k->key);
+ freeheap(h, swept);
+}
+
+static SK*
+checkSK(Keyring_SK *k)
+{
+ SK *sk;
+
+ sk = (SK*)k;
+ if(sk == H || sk == nil || sk->key == 0 || D2H(sk)->t != TSK){
+ errorf("%s: %s", exType, exBadSK);
+ return nil;
+ }
+ return sk;
+}
+
+void
+Keyring_genSK(void *fp)
+{
+ F_Keyring_genSK *f;
+ SK *sk;
+ SigAlg *sa;
+ void *v;
+
+ f = fp;
+ v = *f->ret;
+ *f->ret = H;
+ destroy(v);
+
+ sa = strtoalg(string2c(f->algname), 0);
+ if(sa == nil)
+ return;
+
+ sk = newSK(sa, stringdup(f->owner), 0);
+ *f->ret = (Keyring_SK*)sk;
+ release();
+ sk->key = (*sa->vec->gensk)(f->length);
+ acquire();
+}
+
+void
+Keyring_genSKfromPK(void *fp)
+{
+ F_Keyring_genSKfromPK *f;
+ SigAlg *sa;
+ PK *pk;
+ SK *sk;
+ void *v;
+
+ f = fp;
+ v = *f->ret;
+ *f->ret = H;
+ destroy(v);
+
+ pk = checkPK(f->pk);
+ sa = checkSigAlg(pk->x.sa);
+ sk = newSK(sa, stringdup(f->owner), 1);
+ *f->ret = (Keyring_SK*)sk;
+ release();
+ sk->key = (*sa->vec->genskfrompk)(pk->key);
+ acquire();
+}
+
+/* converts a sequence of newline-separated base64-encoded mpints to attr=hexval ... in f */
+static char*
+bigs2attr(Fmt *f, char *bigs, char **names)
+{
+ int i, n, nd;
+ char *b16, *vals[20];
+ uchar data[(MaxBigBytes*6 + 7)/8];
+
+ b16 = malloc(2*MaxBigBytes+1);
+ if(b16 == nil)
+ return nil;
+ n = getfields(bigs, vals, nelem(vals), 0, "\n");
+ for(i = 0; i < n-1; i++){
+ if(names == nil || names[i] == nil)
+ break; /* shouldn't happen */
+ nd = dec64(data, sizeof(data), vals[i], strlen(vals[i]));
+ if(nd < 0)
+ break;
+ enc16(b16, 2*MaxBigBytes+1, data, nd);
+ fmtprint(f, " %s=%s", names[i], b16);
+ }
+ free(b16);
+ return fmtstrflush(f);
+}
+
+void
+Keyring_sktoattr(void *fp)
+{
+ F_Keyring_sktoattr *f;
+ char *val, *buf, *owner;
+ SigAlg *sa;
+ Fmt o;
+ SK *sk;
+
+ f = fp;
+ sk = checkSK(f->sk);
+ sa = checkSigAlg(sk->x.sa);
+ buf = malloc(Maxbuf);
+ if(buf == nil){
+ retstr(nil, f->ret);
+ return;
+ }
+ (*sa->vec->sk2str)(sk->key, buf, Maxbuf);
+ fmtstrinit(&o);
+ fmtprint(&o, "alg=%q", string2c(sa->x.name));
+ owner = string2c(sk->x.owner);
+ if(*owner)
+ fmtprint(&o, " owner=%q", owner);
+ val = bigs2attr(&o, buf, sa->vec->skattr);
+ free(buf);
+ retstr(val, f->ret);
+ free(val);
+}
+
+static int
+sktostr(SK *sk, char *buf, int len)
+{
+ int n;
+ SigAlg *sa;
+
+ sa = checkSigAlg(sk->x.sa);
+ n = snprint(buf, len, "%s\n%s\n", string2c(sa->x.name),
+ string2c(sk->x.owner));
+ return n + (*sa->vec->sk2str)(sk->key, buf+n, len - n);
+}
+
+void
+Keyring_sktostr(void *fp)
+{
+ F_Keyring_sktostr *f;
+ char *buf;
+
+ f = fp;
+ buf = malloc(Maxbuf);
+
+ if(buf)
+ sktostr(checkSK(f->sk), buf, Maxbuf);
+ retstr(buf, f->ret);
+
+ free(buf);
+}
+
+static SK*
+strtosk(char *buf)
+{
+ SK *sk;
+ char *p;
+ SigAlg *sa;
+ String *owner;
+ void *key;
+
+ sa = strtoalg(buf, &p);
+ if(sa == nil)
+ return H;
+ owner = strtostring(p, &p);
+ if(owner == H){
+ destroy(sa);
+ return H;
+ }
+
+ key = (*sa->vec->str2sk)(p, &p);
+ if(key == nil){
+ destroy(sa);
+ destroy(owner);
+ return H;
+ }
+ sk = newSK(sa, owner, 0);
+ sk->key = key;
+
+ return sk;
+}
+
+void
+Keyring_strtosk(void *fp)
+{
+ F_Keyring_strtosk *f;
+ void *v;
+
+ f = fp;
+ v = *f->ret;
+ *f->ret = H;
+ destroy(v);
+ *f->ret = (Keyring_SK*)strtosk(string2c(f->s));
+}
+
+/*
+ * public part of a key
+ */
+PK*
+newPK(SigAlg *sa, String *owner, int increfsa)
+{
+ Heap *h;
+ PK *k;
+
+ h = heap(TPK);
+ k = H2D(PK*, h);
+ k->x.sa = (Keyring_SigAlg*)sa;
+ if(increfsa) {
+ h = D2H(sa);
+ h->ref++;
+ Setmark(h);
+ }
+ k->x.owner = owner;
+ k->key = 0;
+ return k;
+}
+
+void
+pkimmutable(PK *k)
+{
+ poolimmutable(D2H(k));
+ poolimmutable(D2H(k->x.sa));
+ poolimmutable(D2H(k->x.sa->name));
+ poolimmutable(D2H(k->x.owner));
+}
+
+void
+pkmutable(PK *k)
+{
+ poolmutable(D2H(k));
+ poolmutable(D2H(k->x.sa));
+ poolmutable(D2H(k->x.sa->name));
+ poolmutable(D2H(k->x.owner));
+}
+
+void
+freePK(Heap *h, int swept)
+{
+ PK *k;
+ SigAlg *sa;
+
+ k = H2D(PK*, h);
+ sa = checkSigAlg(k->x.sa);
+ if(k->key)
+ (*sa->vec->pkfree)(k->key);
+ freeheap(h, swept);
+}
+
+static PK*
+checkPK(Keyring_PK *k)
+{
+ PK *pk;
+
+ pk = (PK*)k;
+ if(pk == H || pk == nil || pk->key == 0 || D2H(pk)->t != TPK){
+ errorf("%s: %s", exType, exBadPK);
+ return nil;
+ }
+ return pk;
+}
+
+void
+Keyring_sktopk(void *fp)
+{
+ F_Keyring_sktopk *f;
+ PK *pk;
+ SigAlg *sa;
+ SK *sk;
+ void *r;
+
+ f = fp;
+ r = *f->ret;
+ *f->ret = H;
+ destroy(r);
+
+ sk = checkSK(f->sk);
+ sa = checkSigAlg(sk->x.sa);
+ pk = newPK(sa, stringdup(sk->x.owner), 1);
+ pk->key = (*sa->vec->sk2pk)(sk->key);
+ *f->ret = (Keyring_PK*)pk;
+}
+
+static int
+pktostr(PK *pk, char *buf, int len)
+{
+ int n;
+ SigAlg *sa;
+
+ sa = checkSigAlg(pk->x.sa);
+ n = snprint(buf, len, "%s\n%s\n", string2c(sa->x.name), string2c(pk->x.owner));
+ return n + (*sa->vec->pk2str)(pk->key, buf+n, len - n);
+}
+
+void
+Keyring_pktostr(void *fp)
+{
+ F_Keyring_pktostr *f;
+ char *buf;
+
+ f = fp;
+ buf = malloc(Maxbuf);
+
+ if(buf)
+ pktostr(checkPK(f->pk), buf, Maxbuf);
+ retstr(buf, f->ret);
+
+ free(buf);
+}
+
+void
+Keyring_pktoattr(void *fp)
+{
+ F_Keyring_pktoattr *f;
+ char *val, *buf, *owner;
+ SigAlg *sa;
+ Fmt o;
+ PK *pk;
+
+ f = fp;
+ pk = checkPK(f->pk);
+ sa = checkSigAlg(pk->x.sa);
+ buf = malloc(Maxbuf);
+ if(buf == nil){
+ retstr(nil, f->ret);
+ return;
+ }
+ (*sa->vec->pk2str)(pk->key, buf, Maxbuf);
+ fmtstrinit(&o);
+ fmtprint(&o, "alg=%q", string2c(sa->x.name));
+ owner = string2c(pk->x.owner);
+ if(*owner)
+ fmtprint(&o, " owner=%q", owner);
+ val = bigs2attr(&o, buf, sa->vec->pkattr);
+ free(buf);
+ retstr(val, f->ret);
+ free(val);
+}
+
+static PK*
+strtopk(char *buf)
+{
+ PK *pk;
+ char *p;
+ SigAlg *sa;
+ String *owner;
+ void *key;
+
+ sa = strtoalg(buf, &p);
+ if(sa == nil)
+ return H;
+ owner = strtostring(p, &p);
+ if(owner == H){
+ destroy(sa);
+ return H;
+ }
+
+ key = (*sa->vec->str2pk)(p, &p);
+ if(key == nil){
+ destroy(sa);
+ destroy(owner);
+ return H;
+ }
+ pk = newPK(sa, owner, 0);
+ pk->key = key;
+
+ return pk;
+}
+
+void
+Keyring_strtopk(void *fp)
+{
+ F_Keyring_strtopk *f;
+ void *v;
+
+ f = fp;
+ v = *f->ret;
+ *f->ret = H;
+ destroy(v);
+ *f->ret = (Keyring_PK*)strtopk(string2c(f->s));
+}
+
+/*
+ * Certificates/signatures
+ */
+
+void
+certimmutable(Certificate *c)
+{
+ poolimmutable(D2H(c));
+ poolimmutable(D2H(c->x.signer));
+ poolimmutable(D2H(c->x.ha));
+ poolimmutable(D2H(c->x.sa));
+ poolimmutable(D2H(c->x.sa->name));
+}
+
+void
+certmutable(Certificate *c)
+{
+ poolmutable(D2H(c));
+ poolmutable(D2H(c->x.signer));
+ poolmutable(D2H(c->x.ha));
+ Setmark(D2H(c->x.sa));
+ poolmutable(D2H(c->x.sa));
+ Setmark(D2H(c->x.sa->name));
+ poolmutable(D2H(c->x.sa->name));
+}
+
+Certificate*
+newCertificate(SigAlg *sa, String *ha, String *signer, long exp, int increfsa)
+{
+ Heap *h;
+ Certificate *c;
+
+ h = heap(TCertificate);
+ c = H2D(Certificate*, h);
+ c->x.sa = (Keyring_SigAlg*)sa;
+ if(increfsa) {
+ h = D2H(sa);
+ h->ref++;
+ Setmark(h);
+ }
+ c->x.signer = signer;
+ c->x.ha = ha;
+ c->x.exp = exp;
+ c->signa = 0;
+
+ return c;
+}
+
+void
+freeCertificate(Heap *h, int swept)
+{
+ Certificate *c;
+ SigAlg *sa;
+
+ c = H2D(Certificate*, h);
+ sa = checkSigAlg(c->x.sa);
+ if(c->signa)
+ (*sa->vec->sigfree)(c->signa);
+ freeheap(h, swept);
+}
+
+Certificate*
+checkCertificate(Keyring_Certificate *c)
+{
+ Certificate *cert;
+
+ cert = (Certificate*)c;
+ if(cert == H || cert == nil || cert->signa == 0 || D2H(cert)->t != TCertificate){
+ errorf("%s: %s", exType, exBadCert);
+ return nil;
+ }
+ return cert;
+}
+
+static int
+certtostr(Certificate *c, char *buf, int len)
+{
+ SigAlg *sa;
+ int n;
+
+ sa = checkSigAlg(c->x.sa);
+ n = snprint(buf, len, "%s\n%s\n%s\n%d\n", string2c(sa->x.name),
+ string2c(c->x.ha), string2c(c->x.signer), c->x.exp);
+ return n + (*sa->vec->sig2str)(c->signa, buf+n, len - n);
+}
+
+void
+Keyring_certtostr(void *fp)
+{
+ F_Keyring_certtostr *f;
+ char *buf;
+
+ f = fp;
+ buf = malloc(Maxbuf);
+
+ if(buf)
+ certtostr(checkCertificate(f->c), buf, Maxbuf);
+ retstr(buf, f->ret);
+
+ free(buf);
+}
+
+void
+Keyring_certtoattr(void *fp)
+{
+ F_Keyring_certtoattr *f;
+ char *val, *buf, *ha;
+ SigAlg *sa;
+ Fmt o;
+ Certificate *c;
+
+ f = fp;
+ c = checkCertificate(f->c);
+ sa = checkSigAlg(c->x.sa);
+ buf = malloc(Maxbuf);
+ if(buf == nil){
+ retstr(nil, f->ret);
+ return;
+ }
+ (*sa->vec->sig2str)(c->signa, buf, Maxbuf);
+ ha = string2c(c->x.ha);
+ if(strcmp(ha, "sha") == 0)
+ ha = "sha1"; /* normalise */
+ fmtstrinit(&o);
+ fmtprint(&o, "sigalg=%q-%q signer=%q expires=%ud", string2c(sa->x.name), ha,
+ string2c(c->x.signer), c->x.exp);
+ val = bigs2attr(&o, buf, sa->vec->sigattr);
+ free(buf);
+ retstr(val, f->ret);
+ free(val);
+}
+
+static Certificate*
+strtocert(char *buf)
+{
+ Certificate *c;
+ char *p;
+ SigAlg *sa;
+ String *signer, *ha;
+ long exp;
+ void *signa;
+
+ sa = strtoalg(buf, &p);
+ if(sa == 0)
+ return H;
+
+ ha = strtostring(p, &p);
+ if(ha == H){
+ destroy(sa);
+ return H;
+ }
+
+ signer = strtostring(p, &p);
+ if(signer == H){
+ destroy(sa);
+ destroy(ha);
+ return H;
+ }
+
+ exp = strtoul(p, &p, 10);
+ if(*p)
+ p++;
+ signa = (*sa->vec->str2sig)(p, &p);
+ if(signa == nil){
+ destroy(sa);
+ destroy(ha);
+ destroy(signer);
+ return H;
+ }
+
+ c = newCertificate(sa, ha, signer, exp, 0);
+ c->signa = signa;
+
+ return c;
+}
+
+void
+Keyring_strtocert(void *fp)
+{
+ F_Keyring_strtocert *f;
+ void *r;
+
+ f = fp;
+ r = *f->ret;
+ *f->ret = H;
+ destroy(r);
+ *f->ret = (Keyring_Certificate*)strtocert(string2c(f->s));
+}
+
+static Certificate*
+sign(SK *sk, char *ha, ulong exp, uchar *a, int len)
+{
+ Certificate *c;
+ mpint *b;
+ int n;
+ SigAlg *sa;
+ DigestState *ds;
+ uchar digest[SHA1dlen];
+ char *buf;
+ String *hastr;
+
+ hastr = H;
+ sa = checkSigAlg(sk->x.sa);
+ buf = malloc(Maxbuf);
+ if(buf == nil)
+ return nil;
+
+ /* add signer name and expiration time to hash */
+ n = snprint(buf, Maxbuf, "%s %lud", string2c(sk->x.owner), exp);
+ if(strcmp(ha, "sha") == 0 || strcmp(ha, "sha1") == 0){
+ ds = sha1(a, len, 0, 0);
+ sha1((uchar*)buf, n, digest, ds);
+ n = Keyring_SHA1dlen;
+ } else if(strcmp(ha, "md5") == 0){
+ ds = md5(a, len, 0, 0);
+ md5((uchar*)buf, n, digest, ds);
+ n = Keyring_MD5dlen;
+ } else if(strcmp(ha, "md4") == 0){
+ ds = md4(a, len, 0, 0);
+ md4((uchar*)buf, n, digest, ds);
+ n = Keyring_MD5dlen;
+ } else {
+ free(buf);
+ return nil;
+ }
+ free(buf);
+
+ /* turn message into a big integer */
+ b = betomp(digest, n, nil);
+ if(b == nil)
+ return nil;
+
+ /* sign */
+ retstr(ha, &hastr);
+ c = newCertificate(sa, hastr, stringdup(sk->x.owner), exp, 1);
+ certimmutable(c); /* hide from the garbage collector */
+ release();
+ c->signa = (*sa->vec->sign)(b, sk->key);
+ acquire();
+ mpfree(b);
+
+ return c;
+}
+
+void
+Keyring_sign(void *fp)
+{
+ F_Keyring_sign *f;
+ Certificate *c;
+ mpint *b;
+ int n;
+ SigAlg *sa;
+ SK *sk;
+ XDigestState *ds;
+ uchar digest[SHA1dlen];
+ char *buf;
+ void *v;
+
+ f = fp;
+ v = *f->ret;
+ *f->ret = H;
+ destroy(v);
+
+ sk = checkSK(f->sk);
+ sa = checkSigAlg(sk->x.sa);
+
+ /* add signer name and expiration time to hash */
+ if(f->state == H)
+ return;
+ buf = malloc(Maxbuf);
+ if(buf == nil)
+ return;
+ ds = (XDigestState*)f->state;
+ n = snprint(buf, Maxbuf, "%s %d", string2c(sk->x.owner), f->exp);
+ if(strcmp(string2c(f->ha), "sha") == 0 || strcmp(string2c(f->ha), "sha1") == 0){
+ sha1((uchar*)buf, n, digest, &ds->state);
+ n = Keyring_SHA1dlen;
+ } else if(strcmp(string2c(f->ha), "md5") == 0){
+ md5((uchar*)buf, n, digest, &ds->state);
+ n = Keyring_MD5dlen;
+ } else if(strcmp(string2c(f->ha), "md4") == 0){
+ md4((uchar*)buf, n, digest, &ds->state);
+ n = Keyring_MD5dlen;
+ } else {
+ free(buf);
+ return;
+ }
+ free(buf);
+
+ /* turn message into a big integer */
+ b = betomp(digest, n, nil);
+ if(b == nil)
+ return;
+
+ /* sign */
+ c = newCertificate(sa, stringdup(f->ha), stringdup(sk->x.owner), f->exp, 1);
+ *f->ret = (Keyring_Certificate*)c;
+ release();
+ c->signa = (*sa->vec->sign)(b, sk->key);
+ acquire();
+ mpfree(b);
+}
+
+void
+Keyring_signm(void *fp)
+{
+ F_Keyring_signm *f;
+ Certificate *c;
+ mpint *b;
+ SigAlg *sa;
+ SK *sk;
+ void *v;
+
+ f = fp;
+ v = *f->ret;
+ *f->ret = H;
+ destroy(v);
+
+ sk = checkSK(f->sk);
+ sa = checkSigAlg(sk->x.sa);
+
+ if(f->m == H)
+ return;
+ b = checkIPint(f->m);
+
+ /* sign */
+ c = newCertificate(sa, stringdup(f->ha), stringdup(sk->x.owner), 0, 1);
+ *f->ret = (Keyring_Certificate*)c;
+ release();
+ c->signa = (*sa->vec->sign)(b, sk->key);
+ acquire();
+}
+
+static int
+verify(PK *pk, Certificate *c, char *a, int len)
+{
+ mpint *b;
+ int n;
+ SigAlg *sa, *pksa;
+ DigestState *ds;
+ uchar digest[SHA1dlen];
+ char *buf;
+
+ sa = checkSigAlg(c->x.sa);
+ pksa = checkSigAlg(pk->x.sa);
+ if(sa->vec != pksa->vec)
+ return 0;
+
+ /* add signer name and expiration time to hash */
+ buf = malloc(Maxbuf);
+ if(buf == nil)
+ return 0;
+ n = snprint(buf, Maxbuf, "%s %d", string2c(c->x.signer), c->x.exp);
+ if(strcmp(string2c(c->x.ha), "sha") == 0 || strcmp(string2c(c->x.ha), "sha1") == 0){
+ ds = sha1((uchar*)a, len, 0, 0);
+ sha1((uchar*)buf, n, digest, ds);
+ n = Keyring_SHA1dlen;
+ } else if(strcmp(string2c(c->x.ha), "md5") == 0){
+ ds = md5((uchar*)a, len, 0, 0);
+ md5((uchar*)buf, n, digest, ds);
+ n = Keyring_MD5dlen;
+ } else if(strcmp(string2c(c->x.ha), "md4") == 0){
+ ds = md4((uchar*)a, len, 0, 0);
+ md4((uchar*)buf, n, digest, ds);
+ n = Keyring_MD5dlen;
+ } else {
+ free(buf);
+ return 0;
+ }
+ free(buf);
+
+ /* turn message into a big integer */
+ b = betomp(digest, n, nil);
+ if(b == nil)
+ return 0;
+ /* verify */
+ release();
+ n = (*sa->vec->verify)(b, c->signa, pk->key);
+ acquire();
+
+ mpfree(b);
+ return n;
+}
+
+void
+Keyring_verify(void *fp)
+{
+ F_Keyring_verify *f;
+ Certificate *c;
+ mpint *b;
+ int n;
+ SigAlg *sa, *pksa;
+ PK *pk;
+ XDigestState *ds;
+ uchar digest[SHA1dlen];
+ char *buf;
+
+ f = fp;
+ *f->ret = 0;
+
+ c = checkCertificate(f->cert);
+ sa = checkSigAlg(c->x.sa);
+ pk = checkPK(f->pk);
+ pksa = checkSigAlg(pk->x.sa);
+ if(sa->vec != pksa->vec)
+ return;
+
+ /* add signer name and expiration time to hash */
+ if(f->state == H)
+ return;
+ buf = malloc(Maxbuf);
+ if(buf == nil)
+ return;
+ n = snprint(buf, Maxbuf, "%s %d", string2c(c->x.signer), c->x.exp);
+ ds = (XDigestState*)f->state;
+
+ if(strcmp(string2c(c->x.ha), "sha") == 0 || strcmp(string2c(c->x.ha), "sha1") == 0){
+ sha1((uchar*)buf, n, digest, &ds->state);
+ n = Keyring_SHA1dlen;
+ } else if(strcmp(string2c(c->x.ha), "md5") == 0){
+ md5((uchar*)buf, n, digest, &ds->state);
+ n = Keyring_MD5dlen;
+ } else if(strcmp(string2c(c->x.ha), "md4") == 0){
+ md4((uchar*)buf, n, digest, &ds->state);
+ n = Keyring_MD5dlen;
+ } else {
+ free(buf);
+ return;
+ }
+ free(buf);
+
+ /* turn message into a big integer */
+ b = betomp(digest, n, nil);
+ if(b == nil)
+ return;
+
+ /* verify */
+ release();
+ *f->ret = (*sa->vec->verify)(b, c->signa, pk->key);
+ acquire();
+
+ mpfree(b);
+}
+
+void
+Keyring_verifym(void *fp)
+{
+ F_Keyring_verifym *f;
+ Certificate *c;
+ SigAlg *sa, *pksa;
+ PK *pk;
+
+ f = fp;
+ *f->ret = 0;
+
+ c = checkCertificate(f->cert);
+ sa = checkSigAlg(c->x.sa);
+ pk = checkPK(f->pk);
+ pksa = checkSigAlg(pk->x.sa);
+ if(sa->vec != pksa->vec)
+ return;
+
+ if(f->m == H)
+ return;
+
+ release();
+ *f->ret = (*sa->vec->verify)(checkIPint(f->m), c->signa, pk->key);
+ acquire();
+}
+
+/*
+ * digests
+ */
+void
+Keyring_DigestState_copy(void *fp)
+{
+ F_DigestState_copy *f;
+ Heap *h;
+ XDigestState *ds, *ods;
+ void *r;
+
+ f = fp;
+ r = *f->ret;
+ *f->ret = H;
+ destroy(r);
+
+ if(f->d != H){
+ ods = checktype(f->d, TDigestState, "DigestState", 0);
+ h = heap(TDigestState);
+ ds = H2D(XDigestState*, h);
+ memmove(&ds->state, &ods->state, sizeof(ds->state));
+ *f->ret = (Keyring_DigestState*)ds;
+ }
+}
+
+static Keyring_DigestState*
+keyring_digest_x(Array *buf, int n, Array *digest, int dlen, Keyring_DigestState *state, DigestState* (*fn)(uchar*, ulong, uchar*, DigestState*))
+{
+ Heap *h;
+ XDigestState *ds;
+ uchar *cbuf, *cdigest;
+
+ if(buf != H){
+ if(n > buf->len)
+ n = buf->len;
+ cbuf = buf->data;
+ }else{
+ if(n != 0)
+ error(exInval);
+ cbuf = nil;
+ }
+
+ if(digest != H){
+ if(digest->len < dlen)
+ error(exBadDigest);
+ cdigest = digest->data;
+ } else
+ cdigest = nil;
+
+ if(state == H){
+ h = heap(TDigestState);
+ ds = H2D(XDigestState*, h);
+ memset(&ds->state, 0, sizeof(ds->state));
+ } else
+ ds = checktype(state, TDigestState, "DigestState", 1);
+
+ (*fn)(cbuf, n, cdigest, &ds->state);
+
+ return (Keyring_DigestState*)ds;
+}
+
+void
+Keyring_sha1(void *fp)
+{
+ F_Keyring_sha1 *f;
+ void *r;
+
+ f = fp;
+ r = *f->ret;
+ *f->ret = H;
+ destroy(r);
+
+ *f->ret = keyring_digest_x(f->buf, f->n, f->digest, SHA1dlen, f->state, sha1);
+}
+
+void
+Keyring_sha224(void *fp)
+{
+ F_Keyring_sha224 *f;
+ void *r;
+
+ f = fp;
+ r = *f->ret;
+ *f->ret = H;
+ destroy(r);
+
+ *f->ret = keyring_digest_x(f->buf, f->n, f->digest, SHA224dlen, f->state, sha224);
+}
+
+void
+Keyring_sha256(void *fp)
+{
+ F_Keyring_sha256 *f;
+ void *r;
+
+ f = fp;
+ r = *f->ret;
+ *f->ret = H;
+ destroy(r);
+
+ *f->ret = keyring_digest_x(f->buf, f->n, f->digest, SHA256dlen, f->state, sha256);
+}
+
+void
+Keyring_sha384(void *fp)
+{
+ F_Keyring_sha384 *f;
+ void *r;
+
+ f = fp;
+ r = *f->ret;
+ *f->ret = H;
+ destroy(r);
+
+ *f->ret = keyring_digest_x(f->buf, f->n, f->digest, SHA384dlen, f->state, sha384);
+}
+
+void
+Keyring_sha512(void *fp)
+{
+ F_Keyring_sha512 *f;
+ void *r;
+
+ f = fp;
+ r = *f->ret;
+ *f->ret = H;
+ destroy(r);
+
+ *f->ret = keyring_digest_x(f->buf, f->n, f->digest, SHA512dlen, f->state, sha512);
+}
+
+void
+Keyring_md5(void *fp)
+{
+ F_Keyring_md5 *f;
+ void *r;
+
+ f = fp;
+ r = *f->ret;
+ *f->ret = H;
+ destroy(r);
+
+ *f->ret = keyring_digest_x(f->buf, f->n, f->digest, MD5dlen, f->state, md5);
+}
+
+void
+Keyring_md4(void *fp)
+{
+ F_Keyring_md4 *f;
+ void *r;
+
+ f = fp;
+ r = *f->ret;
+ *f->ret = H;
+ destroy(r);
+
+ *f->ret = keyring_digest_x(f->buf, f->n, f->digest, MD4dlen, f->state, md4);
+}
+
+static Keyring_DigestState*
+keyring_hmac_x(Array *data, int n, Array *key, Array *digest, int dlen, Keyring_DigestState *state, DigestState* (*fn)(uchar*, ulong, uchar*, ulong, uchar*, DigestState*))
+{
+ Heap *h;
+ XDigestState *ds;
+ uchar *cdata, *cdigest;
+
+ if(data != H){
+ if(n > data->len)
+ n = data->len;
+ cdata = data->data;
+ }else{
+ if(n != 0)
+ error(exInval);
+ cdata = nil;
+ }
+
+ if(key == H || key->len > 64)
+ error(exBadKey);
+
+ if(digest != H){
+ if(digest->len < dlen)
+ error(exBadDigest);
+ cdigest = digest->data;
+ } else
+ cdigest = nil;
+
+ if(state == H){
+ h = heap(TDigestState);
+ ds = H2D(XDigestState*, h);
+ memset(&ds->state, 0, sizeof(ds->state));
+ } else
+ ds = checktype(state, TDigestState, "DigestState", 1);
+
+ (*fn)(cdata, n, key->data, key->len, cdigest, &ds->state);
+
+ return (Keyring_DigestState*)ds;
+}
+
+void
+Keyring_hmac_sha1(void *fp)
+{
+ F_Keyring_hmac_sha1 *f;
+ void *r;
+
+ f = fp;
+ r = *f->ret;
+ *f->ret = H;
+ destroy(r);
+ *f->ret = keyring_hmac_x(f->data, f->n, f->key, f->digest, SHA1dlen, f->state, hmac_sha1);
+}
+
+void
+Keyring_hmac_md5(void *fp)
+{
+ F_Keyring_hmac_md5 *f;
+ void *r;
+
+ f = fp;
+ r = *f->ret;
+ *f->ret = H;
+ destroy(r);
+ *f->ret = keyring_hmac_x(f->data, f->n, f->key, f->digest, MD5dlen, f->state, hmac_md5);
+}
+
+void
+Keyring_dhparams(void *fp)
+{
+ F_Keyring_dhparams *f;
+ mpint *p, *alpha;
+ void *v;
+
+ f = fp;
+ v = f->ret->t0;
+ f->ret->t0 = H;
+ destroy(v);
+ v = f->ret->t1;
+ f->ret->t1 = H;
+ destroy(v);
+
+ p = mpnew(0);
+ alpha = mpnew(0);
+ release();
+ if(f->nbits == 1024)
+ DSAprimes(alpha, p, nil);
+ else
+ gensafeprime(p, alpha, f->nbits, 0);
+ acquire();
+ f->ret->t0 = newIPint(alpha);
+ f->ret->t1 = newIPint(p);
+}
+
+static int
+sendmsg(int fd, void *buf, int n)
+{
+ char num[10];
+
+ release();
+ snprint(num, sizeof(num), "%4.4d\n", n);
+ if(kwrite(fd, num, 5) != 5){
+ acquire();
+ return -1;
+ }
+ n = kwrite(fd, buf, n);
+ acquire();
+ return n;
+}
+
+void
+Keyring_sendmsg(void *fp)
+{
+ F_Keyring_sendmsg *f;
+ int n;
+
+ f = fp;
+ *f->ret = -1;
+ if(f->fd == H || f->buf == H || f->n < 0)
+ return;
+ n = f->n;
+ if(n < 0 || n > f->buf->len)
+ error(exBounds);
+ *f->ret = sendmsg(f->fd->fd, f->buf->data, n);
+}
+
+static int
+senderr(int fd, char *err, int addrmt)
+{
+ char num[10];
+ int n, m;
+
+ release();
+ n = strlen(err);
+ m = 0;
+ if(addrmt)
+ m = strlen("remote: ");
+ snprint(num, sizeof(num), "!%3.3d\n", n+m);
+ if(kwrite(fd, num, 5) != 5){
+ acquire();
+ return -1;
+ }
+ if(addrmt)
+ kwrite(fd, "remote: ", m);
+ n = kwrite(fd, err, n);
+ acquire();
+ return n;
+}
+
+void
+Keyring_senderrmsg(void *fp)
+{
+ F_Keyring_senderrmsg *f;
+ char *s;
+
+ f = fp;
+ *f->ret = -1;
+ if(f->fd == H)
+ return;
+ s = string2c(f->s);
+ if(senderr(f->fd->fd, s, 0) > 0)
+ *f->ret = 0;
+}
+
+static int
+nreadn(int fd, void *av, int n)
+{
+
+ char *a;
+ long m, t;
+
+ a = av;
+ t = 0;
+ while(t < n){
+ m = kread(fd, a+t, n-t);
+ if(m <= 0){
+ if(t == 0)
+ return m;
+ break;
+ }
+ t += m;
+ }
+ return t;
+}
+
+#define MSG "input or format error"
+
+static void
+getmsgerr(char *buf, int n, int r)
+{
+ char *e;
+ int l;
+
+ e = r>0? MSG: "hungup";
+ l = strlen(e)+1;
+ if(n > l)
+ n = l;
+ memmove(buf, e, n-1);
+ buf[n-1] = 0;
+}
+
+static int
+getmsg(int fd, char *buf, int n)
+{
+ char num[6];
+ int len, r;
+
+ release();
+ if((r = nreadn(fd, num, 5)) != 5){
+ getmsgerr(buf, n, r);
+ acquire();
+ return -1;
+ }
+ num[5] = 0;
+
+ if(num[0] == '!')
+ len = strtoul(num+1, 0, 10);
+ else
+ len = strtoul(num, 0, 10);
+
+ r = -1;
+ if(len < 0 || len >= n || (r = nreadn(fd, buf, len)) != len){
+ getmsgerr(buf, n, r);
+ acquire();
+ return -1;
+ }
+
+ buf[len] = 0;
+ acquire();
+ if(num[0] == '!')
+ return -len;
+
+ return len;
+}
+
+void
+Keyring_getmsg(void *fp)
+{
+ F_Keyring_getmsg *f;
+ char *buf;
+ int n;
+ void *r;
+
+ f = fp;
+ r = *f->ret;
+ *f->ret = H;
+ destroy(r);
+ if(f->fd == H){
+ kwerrstr("nil fd");
+ return;
+ }
+
+ buf = malloc(Maxmsg);
+ if(buf == nil){
+ kwerrstr(exNomem);
+ return;
+ }
+
+ n = getmsg(f->fd->fd, buf, Maxmsg);
+ if(n < 0){
+ kwerrstr("%s", buf);
+ free(buf);
+ return;
+ }
+
+ *f->ret = mem2array(buf, n);
+ free(buf);
+}
+
+void
+Keyring_auth(void *fp)
+{
+ F_Keyring_auth *f;
+ mpint *r0, *r1, *p, *alpha, *alphar0, *alphar1, *alphar0r1;
+ SK *mysk;
+ PK *mypk, *spk, *hispk;
+ Certificate *cert, *hiscert, *alphacert;
+ char *buf, *err;
+ uchar *cvb;
+ int n, fd, version;
+ long now;
+
+ hispk = H;
+ hiscert = H;
+ alphacert = H;
+ err = nil;
+
+ /* null out the return values */
+ f = fp;
+ destroy(f->ret->t0);
+ f->ret->t0 = H;
+ destroy(f->ret->t1);
+ f->ret->t1 = H;
+ r0 = r1 = alphar0 = alphar1 = alphar0r1 = nil;
+
+ /* check args */
+ if(f->fd == H || f->fd->fd < 0){
+ retstr("bad fd", &f->ret->t0);
+ return;
+ }
+ fd = f->fd->fd;
+
+ buf = malloc(Maxbuf);
+ if(buf == nil){
+ retstr(exNomem, &f->ret->t0);
+ return;
+ }
+
+ /* send auth protocol version number */
+ if(sendmsg(fd, "1", 1) <= 0){
+ err = MSG;
+ goto out;
+ }
+
+ /* get auth protocol version number */
+ n = getmsg(fd, buf, Maxbuf-1);
+ if(n < 0){
+ err = buf;
+ goto out;
+ }
+ buf[n] = 0;
+ version = atoi(buf);
+ if(version != 1 || n > 4){
+ err = "incompatible authentication protocol";
+ goto out;
+ }
+
+ if(f->info == H){
+ err = "no authentication information";
+ goto out;
+ }
+ if(f->info->p == H){
+ err = "missing diffie hellman mod";
+ goto out;
+ }
+ if(f->info->alpha == H){
+ err = "missing diffie hellman base";
+ goto out;
+ }
+ mysk = checkSK(f->info->mysk);
+ if(mysk == H){
+ err = "bad sk arg";
+ goto out;
+ }
+ mypk = checkPK(f->info->mypk);
+ if(mypk == H){
+ err = "bad pk arg";
+ goto out;
+ }
+ cert = checkCertificate(f->info->cert);
+ if(cert == H){
+ err = "bad certificate arg";
+ goto out;
+ }
+ spk = checkPK(f->info->spk);
+ if(spk == H){
+ err = "bad signer key arg";
+ goto out;
+ }
+
+ /* get alpha and p */
+ p = checkIPint(f->info->p);
+ alpha = checkIPint(f->info->alpha);
+
+ if(p->sign == -1) {
+ err = "-ve modulus";
+ goto out;
+ }
+
+ r0 = mpnew(0);
+ r1 = mpnew(0);
+ alphar0 = mpnew(0);
+ alphar0r1 = mpnew(0);
+
+ /* generate alpha**r0 */
+if(0)print("X");
+ release();
+ mprand(mpsignif(p), genrandom, r0);
+ mpexp(alpha, r0, p, alphar0);
+ acquire();
+if(0)print("Y");
+
+ /* send alpha**r0 mod p, mycert, and mypk */
+ n = bigtobase64(alphar0, buf, Maxbuf);
+ if(sendmsg(fd, buf, n) <= 0){
+ err = MSG;
+ goto out;
+ }
+
+ n = certtostr(cert, buf, Maxbuf);
+ if(sendmsg(fd, buf, n) <= 0){
+ err = MSG;
+ goto out;
+ }
+
+ n = pktostr(mypk, buf, Maxbuf);
+ if(sendmsg(fd, buf, n) <= 0){
+ err = MSG;
+ goto out;
+ }
+
+ /* get alpha**r1 mod p, hiscert, hispk */
+ n = getmsg(fd, buf, Maxbuf-1);
+ if(n < 0){
+ err = buf;
+ goto out;
+ }
+ buf[n] = 0;
+ alphar1 = strtomp(buf, nil, 64, nil);
+
+ /* trying a fast one */
+ if(mpcmp(p, alphar1) <= 0){
+ err = "implausible parameter value";
+ goto out;
+ }
+
+ /* if alpha**r1 == alpha**r0, someone may be trying a replay */
+ if(mpcmp(alphar0, alphar1) == 0){
+ err = "possible replay attack";
+ goto out;
+ }
+
+ n = getmsg(fd, buf, Maxbuf-1);
+ if(n < 0){
+ err = buf;
+ goto out;
+ }
+ buf[n] = 0;
+ hiscert = strtocert(buf);
+ if(hiscert == H){
+ err = "bad certificate syntax";
+ goto out;
+ }
+ certimmutable(hiscert); /* hide from the garbage collector */
+
+ n = getmsg(fd, buf, Maxbuf-1);
+ if(n < 0){
+ err = buf;
+ goto out;
+ }
+ buf[n] = 0;
+ hispk = strtopk(buf);
+ if(hispk == H){
+ err = "bad public key";
+ goto out;
+ }
+ pkimmutable(hispk); /* hide from the garbage collector */
+
+ /* verify his public key */
+ if(verify(spk, hiscert, buf, n) == 0){
+ err = "pk doesn't match certificate";
+ goto out;
+ }
+
+ /* check expiration date - in seconds of epoch */
+
+ now = osusectime()/1000000;
+ if(hiscert->x.exp != 0 && hiscert->x.exp <= now){
+ err = "certificate expired";
+ goto out;
+ }
+
+ /* sign alpha**r0 and alpha**r1 and send */
+ n = bigtobase64(alphar0, buf, Maxbuf);
+ n += bigtobase64(alphar1, buf+n, Maxbuf-n);
+ alphacert = sign(mysk, "sha1", 0, (uchar*)buf, n);
+ n = certtostr(alphacert, buf, Maxbuf);
+ if(sendmsg(fd, buf, n) <= 0){
+ err = MSG;
+ goto out;
+ }
+ certmutable(alphacert);
+ destroy(alphacert);
+ alphacert = H;
+
+ /* get signature of alpha**r1 and alpha**r0 and verify */
+ n = getmsg(fd, buf, Maxbuf-1);
+ if(n < 0){
+ err = buf;
+ goto out;
+ }
+ buf[n] = 0;
+ alphacert = strtocert(buf);
+ if(alphacert == H){
+ err = "alpha**r1 doesn't match certificate";
+ goto out;
+ }
+ certimmutable(alphacert); /* hide from the garbage collector */
+ n = bigtobase64(alphar1, buf, Maxbuf);
+ n += bigtobase64(alphar0, buf+n, Maxbuf-n);
+ if(verify(hispk, alphacert, buf, n) == 0){
+ err = "bad certificate";
+ goto out;
+ }
+
+ /* we are now authenticated and have a common secret, alpha**(r0*r1) */
+ f->ret->t0 = stringdup(hispk->x.owner);
+ mpexp(alphar1, r0, p, alphar0r1);
+ n = mptobe(alphar0r1, nil, Maxbuf, &cvb);
+ if(n < 0){
+ err = "bad conversion";
+ goto out;
+ }
+ f->ret->t1 = mem2array(cvb, n);
+ free(cvb);
+
+out:
+ /* return status */
+ if(f->ret->t0 == H){
+ if(err == buf)
+ senderr(fd, "missing your authentication data", 1);
+ else
+ senderr(fd, err, 1);
+ }else
+ sendmsg(fd, "OK", 2);
+
+ /* read responses */
+ if(err != buf){
+ for(;;){
+ n = getmsg(fd, buf, Maxbuf-1);
+ if(n < 0){
+ destroy(f->ret->t0);
+ f->ret->t0 = H;
+ destroy(f->ret->t1);
+ f->ret->t1 = H;
+ if(err == nil){
+ if(n < -1)
+ err = buf;
+ else
+ err = MSG;
+ }
+ break;
+ }
+ if(n == 2 && buf[0] == 'O' && buf[1] == 'K')
+ break;
+ }
+ }
+
+ /* set error and id to nobody */
+ if(f->ret->t0 == H){
+ if(err == nil)
+ err = MSG;
+ retstr(err, &f->ret->t0);
+ if(f->setid)
+ setid("nobody", 1);
+ } else {
+ /* change user id */
+ if(f->setid)
+ setid(string2c(f->ret->t0), 1);
+ }
+
+ /* free resources */
+ if(hispk != H){
+ pkmutable(hispk);
+ destroy(hispk);
+ }
+ if(hiscert != H){
+ certmutable(hiscert);
+ destroy(hiscert);
+ }
+ if(alphacert != H){
+ certmutable(alphacert);
+ destroy(alphacert);
+ }
+ free(buf);
+ if(r0 != nil){
+ mpfree(r0);
+ mpfree(r1);
+ mpfree(alphar0);
+ mpfree(alphar1);
+ mpfree(alphar0r1);
+ }
+}
+
+static Keyring_Authinfo*
+newAuthinfo(void)
+{
+ return H2D(Keyring_Authinfo*, heap(TAuthinfo));
+}
+
+void
+Keyring_writeauthinfo(void *fp)
+{
+ F_Keyring_writeauthinfo *f;
+ int n, fd;
+ char *buf;
+ PK *spk;
+ SK *mysk;
+ Certificate *c;
+ mpint *p, *alpha;
+
+ f = fp;
+ *f->ret = -1;
+
+ if(f->filename == H)
+ error(exNilref);
+ if(f->info == H)
+ error(exNilref);
+ alpha = checkIPint(f->info->alpha);
+ p = checkIPint(f->info->p);
+ spk = checkPK(f->info->spk);
+ mysk = checkSK(f->info->mysk);
+ c = checkCertificate(f->info->cert);
+
+ buf = malloc(Maxbuf);
+ if(buf == nil)
+ return;
+
+ /*
+ * The file may already exist or be a file2chan file so first
+ * try opening with truncation since create will change the
+ * permissions of the file and create doesn't work with a
+ * file2chan.
+ */
+ release();
+ fd = kopen(string2c(f->filename), OTRUNC|OWRITE);
+ if(fd < 0)
+ fd = kcreate(string2c(f->filename), OWRITE, 0600);
+ if(fd < 0)
+ fd = kopen(string2c(f->filename), OWRITE);
+ acquire();
+ if(fd < 0)
+ goto out;
+
+ /* signer's public key */
+ n = pktostr(spk, buf, Maxmsg);
+ if(sendmsg(fd, buf, n) <= 0)
+ goto out;
+
+ /* certificate for my public key */
+ n = certtostr(c, buf, Maxmsg);
+ if(sendmsg(fd, buf, n) <= 0)
+ goto out;
+
+ /* my secret/public key */
+ n = sktostr(mysk, buf, Maxmsg);
+ if(sendmsg(fd, buf, n) <= 0)
+ goto out;
+
+ /* diffie hellman base */
+ n = bigtobase64(alpha, buf, Maxbuf);
+ if(sendmsg(fd, buf, n) <= 0)
+ goto out;
+
+ /* diffie hellman modulus */
+ n = bigtobase64(p, buf, Maxbuf);
+ if(sendmsg(fd, buf, n) <= 0)
+ goto out;
+
+ *f->ret = 0;
+out:
+ free(buf);
+ if(fd >= 0){
+ release();
+ kclose(fd);
+ acquire();
+ }
+}
+
+void
+Keyring_readauthinfo(void *fp)
+{
+ F_Keyring_readauthinfo *f;
+ int fd;
+ char *buf;
+ int n, ok;
+ PK *mypk;
+ SK *mysk;
+ SigAlg *sa;
+ Keyring_Authinfo *ai;
+ mpint *b;
+ void *r;
+
+ f = fp;
+ r = *f->ret;
+ *f->ret = H;
+ destroy(r);
+
+ ok = 0;
+
+ if(f->filename == H)
+ return;
+
+ buf = malloc(Maxbuf);
+ if(buf == nil)
+ return;
+
+ ai = newAuthinfo();
+ *f->ret = ai;
+
+ release();
+ fd = kopen(string2c(f->filename), OREAD);
+ acquire();
+ if(fd < 0)
+ goto out;
+
+ /* signer's public key */
+ n = getmsg(fd, buf, Maxmsg);
+ if(n < 0)
+ goto out;
+
+ ai->spk = (Keyring_PK*)strtopk(buf);
+ if(ai->spk == H)
+ goto out;
+
+ /* certificate for my public key */
+ n = getmsg(fd, buf, Maxmsg);
+ if(n < 0)
+ goto out;
+ ai->cert = (Keyring_Certificate*)strtocert(buf);
+ if(ai->cert == H)
+ goto out;
+
+ /* my secret/public key */
+ n = getmsg(fd, buf, Maxmsg);
+ if(n < 0)
+ goto out;
+ mysk = strtosk(buf);
+ ai->mysk = (Keyring_SK*)mysk;
+ if(mysk == H)
+ goto out;
+ sa = checkSigAlg(mysk->x.sa);
+ mypk = newPK(sa, stringdup(mysk->x.owner), 1);
+ mypk->key = (*sa->vec->sk2pk)(mysk->key);
+ ai->mypk = (Keyring_PK*)mypk;
+
+ /* diffie hellman base */
+ n = getmsg(fd, buf, Maxmsg);
+ if(n < 0)
+ goto out;
+ b = strtomp(buf, nil, 64, nil);
+ ai->alpha = newIPint(b);
+
+ /* diffie hellman modulus */
+ n = getmsg(fd, buf, Maxmsg);
+ if(n < 0)
+ goto out;
+ b = strtomp(buf, nil, 64, nil);
+ ai->p = newIPint(b);
+ ok = 1;
+out:
+ if(!ok){
+ r = *f->ret;
+ *f->ret = H;
+ destroy(r);
+ }
+ free(buf);
+ if(fd >= 0){
+ release();
+ kclose(fd);
+ acquire();
+ kwerrstr("%q: %s", string2c(f->filename), MSG);
+ }
+}
+
+void
+keyringmodinit(void)
+{
+ SigAlgVec *sav;
+ extern SigAlgVec* elgamalinit(void);
+ extern SigAlgVec* rsainit(void);
+ extern SigAlgVec* dsainit(void);
+
+ ipintsmodinit(); /* in case only Keyring is configured */
+ TSigAlg = dtype(freeSigAlg, sizeof(SigAlg), SigAlgmap, sizeof(SigAlgmap));
+ TSK = dtype(freeSK, sizeof(SK), SKmap, sizeof(SKmap));
+ TPK = dtype(freePK, sizeof(PK), PKmap, sizeof(PKmap));
+ TCertificate = dtype(freeCertificate, sizeof(Certificate), Certificatemap,
+ sizeof(Certificatemap));
+ TDigestState = dtype(freeheap, sizeof(XDigestState), DigestStatemap,
+ sizeof(DigestStatemap));
+ TAESstate = dtype(freeheap, sizeof(XAESstate), AESstatemap,
+ sizeof(AESstatemap));
+ TDESstate = dtype(freeheap, sizeof(XDESstate), DESstatemap,
+ sizeof(DESstatemap));
+ TIDEAstate = dtype(freeheap, sizeof(XIDEAstate), IDEAstatemap,
+ sizeof(IDEAstatemap));
+ TBFstate = dtype(freeheap, sizeof(XBFstate), BFstatemap,
+ sizeof(BFstatemap));
+ TRC4state = dtype(freeheap, sizeof(XRC4state), RC4statemap,
+ sizeof(RC4statemap));
+ TAuthinfo = dtype(freeheap, sizeof(Keyring_Authinfo), Authinfomap, sizeof(Authinfomap));
+ TDSAsk = dtype(freeheap, sizeof(Keyring_DSAsk), DSAskmap, sizeof(DSAskmap));
+ TDSApk = dtype(freeheap, sizeof(Keyring_DSApk), DSApkmap, sizeof(DSApkmap));
+ TDSAsig = dtype(freeheap, sizeof(Keyring_DSAsig), DSAsigmap, sizeof(DSAsigmap));
+ TEGsk = dtype(freeheap, sizeof(Keyring_EGsk), EGskmap, sizeof(EGskmap));
+ TEGpk = dtype(freeheap, sizeof(Keyring_EGpk), EGpkmap, sizeof(EGpkmap));
+ TEGsig = dtype(freeheap, sizeof(Keyring_EGsig), EGsigmap, sizeof(EGsigmap));
+ TRSAsk = dtype(freeheap, sizeof(Keyring_RSAsk), RSAskmap, sizeof(RSAskmap));
+ TRSApk = dtype(freeheap, sizeof(Keyring_RSApk), RSApkmap, sizeof(RSApkmap));
+ TRSAsig = dtype(freeheap, sizeof(Keyring_RSAsig), RSAsigmap, sizeof(RSAsigmap));
+
+ if((sav = elgamalinit()) != nil)
+ algs[nalg++] = sav;
+ if((sav = rsainit()) != nil)
+ algs[nalg++] = sav;
+ if((sav = dsainit()) != nil)
+ algs[nalg++] = sav;
+
+ fmtinstall('U', big64conv);
+ builtinmod("$Keyring", Keyringmodtab, Keyringmodlen);
+}
+
+/*
+ * IO on a delimited channel. A message starting with 0x00 is a normal
+ * message. One starting with 0xff is an error string.
+ *
+ * return negative number for error messages (including hangup)
+ */
+static int
+getbuf(int fd, uchar *buf, int n, char *err, int nerr)
+{
+ int len;
+
+ release();
+ len = kread(fd, buf, n);
+ acquire();
+ if(len <= 0){
+ strncpy(err, "hungup", nerr);
+ buf[nerr-1] = 0;
+ return -1;
+ }
+ if(buf[0] == 0)
+ return len-1;
+ if(buf[0] != 0xff){
+ /*
+ * this happens when the client's password is wrong: both sides use a digest of the
+ * password as a crypt key for devssl. When they don't match decryption garbles
+ * messages
+ */
+ strncpy(err, "failure", nerr);
+ err[nerr-1] = 0;
+ return -1;
+ }
+
+ /* error string */
+ len--;
+ if(len < 1){
+ strncpy(err, "unknown", nerr);
+ err[nerr-1] = 0;
+ } else {
+ if(len >= nerr)
+ len = nerr-1;
+ memmove(err, buf+1, len);
+ err[len] = 0;
+ }
+ return -1;
+}
+
+void
+Keyring_getstring(void *fp)
+{
+ F_Keyring_getstring *f;
+ uchar *buf;
+ char err[64];
+ int n;
+
+ f = fp;
+ destroy(f->ret->t0);
+ f->ret->t0 = H;
+ destroy(f->ret->t1);
+ f->ret->t1 = H;
+
+ if(f->fd == H)
+ return;
+
+ buf = malloc(Maxmsg);
+ if(buf == nil)
+ return;
+
+ n = getbuf(f->fd->fd, buf, Maxmsg, err, sizeof(err));
+ if(n < 0)
+ retnstr(err, strlen(err), &f->ret->t1);
+ else
+ retnstr(((char*)buf)+1, n, &f->ret->t0);
+
+ free(buf);
+}
+
+void
+Keyring_getbytearray(void *fp)
+{
+ F_Keyring_getbytearray *f;
+ uchar *buf;
+ char err[64];
+ int n;
+
+ f = fp;
+ destroy(f->ret->t0);
+ f->ret->t0 = H;
+ destroy(f->ret->t1);
+ f->ret->t1 = H;
+
+ if(f->fd == H)
+ return;
+
+ buf = malloc(Maxmsg);
+ if(buf == nil)
+ return;
+
+ n = getbuf(f->fd->fd, buf, Maxmsg, err, sizeof(err));
+ if(n < 0)
+ retnstr(err, strlen(err), &f->ret->t1);
+ else
+ f->ret->t0 = mem2array(buf+1, n);
+
+ free(buf);
+}
+
+static int
+putbuf(int fd, void *p, int n)
+{
+ char *buf;
+
+ buf = malloc(Maxmsg);
+ if(buf == nil)
+ return -1;
+
+ release();
+ buf[0] = 0;
+ if(n < 0){
+ buf[0] = 0xff;
+ n = -n;
+ }
+ if(n >= Maxmsg)
+ n = Maxmsg - 1;
+ memmove(buf+1, p, n);
+ n = kwrite(fd, buf, n+1);
+ acquire();
+
+ free(buf);
+ return n;
+}
+
+void
+Keyring_putstring(void *fp)
+{
+ F_Keyring_putstring *f;
+
+ f = fp;
+ *f->ret = -1;
+ if(f->fd == H || f->s == H)
+ return;
+ *f->ret = putbuf(f->fd->fd, string2c(f->s), strlen(string2c(f->s)));
+}
+
+void
+Keyring_puterror(void *fp)
+{
+ F_Keyring_puterror *f;
+
+ f = fp;
+ *f->ret = -1;
+ if(f->fd == H || f->s == H)
+ return;
+ *f->ret = putbuf(f->fd->fd, string2c(f->s), -strlen(string2c(f->s)));
+}
+
+void
+Keyring_putbytearray(void *fp)
+{
+ F_Keyring_putbytearray *f;
+ int n;
+
+ f = fp;
+ *f->ret = -1;
+ if(f->fd == H || f->a == H)
+ return;
+ n = f->n;
+ if(n < 0 || n > f->a->len)
+ error(exBounds);
+ *f->ret = putbuf(f->fd->fd, f->a->data, n);
+}
+
+void
+Keyring_dessetup(void *fp)
+{
+ F_Keyring_dessetup *f;
+ Heap *h;
+ XDESstate *ds;
+ uchar *ivec;
+ void *r;
+
+ f = fp;
+ r = *f->ret;
+ *f->ret = H;
+ destroy(r);
+
+ if(f->key == H || f->key->len < 8)
+ error(exBadKey);
+ if(f->ivec != H){
+ if(f->ivec->len < 8)
+ error(exBadIvec);
+ ivec = f->ivec->data;
+ }else
+ ivec = nil;
+
+ h = heap(TDESstate);
+ ds = H2D(XDESstate*, h);
+ setupDESstate(&ds->state, f->key->data, ivec);
+
+ *f->ret = (Keyring_DESstate*)ds;
+}
+
+void
+Keyring_desecb(void *fp)
+{
+ F_Keyring_desecb *f;
+ XDESstate *ds;
+ int i;
+ uchar *p;
+
+ f = fp;
+
+ if(f->buf == H)
+ return;
+ if(f->n < 0 || f->n > f->buf->len)
+ error(exBounds);
+ if(f->n & 7)
+ error(exBadBsize);
+
+ ds = checktype(f->state, TDESstate, exBadState, 0);
+ p = f->buf->data;
+
+ for(i = 8; i <= f->n; i += 8, p += 8)
+ block_cipher(ds->state.expanded, p, f->direction);
+}
+
+void
+Keyring_descbc(void *fp)
+{
+ F_Keyring_descbc *f;
+ XDESstate *ds;
+ uchar *p, *ep, *ip, *p2, *eip;
+ uchar tmp[8];
+
+ f = fp;
+
+ if(f->buf == H)
+ return;
+ if(f->n < 0 || f->n > f->buf->len)
+ error(exBounds);
+ if(f->n & 7)
+ error(exBadBsize);
+
+ ds = checktype(f->state, TDESstate, exBadState, 0);
+ p = f->buf->data;
+
+ if(f->direction == 0){
+ for(ep = p + f->n; p < ep; p += 8){
+ p2 = p;
+ ip = ds->state.ivec;
+ for(eip = ip+8; ip < eip; )
+ *p2++ ^= *ip++;
+ block_cipher(ds->state.expanded, p, 0);
+ memmove(ds->state.ivec, p, 8);
+ }
+ } else {
+ for(ep = p + f->n; p < ep; ){
+ memmove(tmp, p, 8);
+ block_cipher(ds->state.expanded, p, 1);
+ p2 = tmp;
+ ip = ds->state.ivec;
+ for(eip = ip+8; ip < eip; ){
+ *p++ ^= *ip;
+ *ip++ = *p2++;
+ }
+ }
+ }
+}
+
+void
+Keyring_ideasetup(void *fp)
+{
+ F_Keyring_ideasetup *f;
+ Heap *h;
+ XIDEAstate *is;
+ uchar *ivec;
+ void *r;
+
+ f = fp;
+ r = *f->ret;
+ *f->ret = H;
+ destroy(r);
+
+ if(f->key == H || f->key->len < 16)
+ error(exBadKey);
+ if(f->ivec != H){
+ if(f->ivec->len < 8)
+ error(exBadIvec);
+ ivec = f->ivec->data;
+ }else
+ ivec = nil;
+
+ h = heap(TIDEAstate);
+ is = H2D(XIDEAstate*, h);
+
+ setupIDEAstate(&is->state, f->key->data, ivec);
+
+ *f->ret = (Keyring_IDEAstate*)is;
+}
+
+void
+Keyring_ideaecb(void *fp)
+{
+ F_Keyring_ideaecb *f;
+ XIDEAstate *is;
+ int i;
+ uchar *p;
+
+ f = fp;
+
+ if(f->buf == H)
+ return;
+ if(f->n < 0 || f->n > f->buf->len)
+ error(exBounds);
+ if(f->n & 7)
+ error(exBadBsize);
+
+ is = checktype(f->state, TIDEAstate, exBadState, 0);
+ p = f->buf->data;
+
+ for(i = 8; i <= f->n; i += 8, p += 8)
+ idea_cipher(is->state.edkey, p, f->direction);
+}
+
+void
+Keyring_ideacbc(void *fp)
+{
+ F_Keyring_ideacbc *f;
+ XIDEAstate *is;
+ uchar *p, *ep, *ip, *p2, *eip;
+ uchar tmp[8];
+
+ f = fp;
+
+ if(f->buf == H)
+ return;
+ if(f->n < 0 || f->n > f->buf->len)
+ error(exBounds);
+ if(f->n & 7)
+ error(exBadBsize);
+
+ is = checktype(f->state, TIDEAstate, exBadState, 0);
+ p = f->buf->data;
+
+ if(f->direction == 0){
+ for(ep = p + f->n; p < ep; p += 8){
+ p2 = p;
+ ip = is->state.ivec;
+ for(eip = ip+8; ip < eip; )
+ *p2++ ^= *ip++;
+ idea_cipher(is->state.edkey, p, 0);
+ memmove(is->state.ivec, p, 8);
+ }
+ } else {
+ for(ep = p + f->n; p < ep; ){
+ memmove(tmp, p, 8);
+ idea_cipher(is->state.edkey, p, 1);
+ p2 = tmp;
+ ip = is->state.ivec;
+ for(eip = ip+8; ip < eip; ){
+ *p++ ^= *ip;
+ *ip++ = *p2++;
+ }
+ }
+ }
+}
+
+void
+Keyring_aessetup(void *fp)
+{
+ F_Keyring_aessetup *f;
+ Heap *h;
+ XAESstate *is;
+ uchar *ivec;
+ void *r;
+
+ f = fp;
+ r = *f->ret;
+ *f->ret = H;
+ destroy(r);
+
+ if(f->key == H ||
+ f->key->len != 16 && f->key->len != 24 && f->key->len != 32)
+ error(exBadKey);
+ if(f->ivec != H){
+ if(f->ivec->len < AESbsize)
+ error(exBadIvec);
+ ivec = f->ivec->data;
+ }else
+ ivec = nil;
+
+ h = heap(TAESstate);
+ is = H2D(XAESstate*, h);
+
+ setupAESstate(&is->state, f->key->data, f->key->len, ivec);
+
+ *f->ret = (Keyring_AESstate*)is;
+}
+
+void
+Keyring_aescbc(void *fp)
+{
+ F_Keyring_aescbc *f;
+ XAESstate *is;
+ uchar *p;
+
+ f = fp;
+
+ if(f->buf == H)
+ return;
+ if(f->n < 0 || f->n > f->buf->len)
+ error(exBounds);
+
+ is = checktype(f->state, TAESstate, exBadState, 0);
+ p = f->buf->data;
+
+ if(f->direction == 0)
+ aesCBCencrypt(p, f->n, &is->state);
+ else
+ aesCBCdecrypt(p, f->n, &is->state);
+}
+
+void
+Keyring_blowfishsetup(void *fp)
+{
+ F_Keyring_blowfishsetup *f;
+ Heap *h;
+ XBFstate *is;
+ uchar *ivec;
+ void *r;
+
+ f = fp;
+ r = *f->ret;
+ *f->ret = H;
+ destroy(r);
+
+ if(f->key == H || f->key->len <= 0)
+ error(exBadKey);
+ if(f->ivec != H){
+ if(f->ivec->len != BFbsize)
+ error(exBadIvec);
+ ivec = f->ivec->data;
+ }else
+ ivec = nil;
+
+ h = heap(TBFstate);
+ is = H2D(XBFstate*, h);
+
+ setupBFstate(&is->state, f->key->data, f->key->len, ivec);
+
+ *f->ret = (Keyring_BFstate*)is;
+}
+
+void
+Keyring_blowfishcbc(void *fp)
+{
+ F_Keyring_blowfishcbc *f;
+ XBFstate *is;
+ uchar *p;
+
+ f = fp;
+
+ if(f->buf == H)
+ return;
+ if(f->n < 0 || f->n > f->buf->len)
+ error(exBounds);
+ if(f->n & 7)
+ error(exBadBsize);
+
+ is = checktype(f->state, TBFstate, exBadState, 0);
+ p = f->buf->data;
+
+ if(f->direction == 0)
+ bfCBCencrypt(p, f->n, &is->state);
+ else
+ bfCBCdecrypt(p, f->n, &is->state);
+}
+
+void
+Keyring_rc4setup(void *fp)
+{
+ F_Keyring_rc4setup *f;
+ Heap *h;
+ XRC4state *is;
+ void *r;
+
+ f = fp;
+ r = *f->ret;
+ *f->ret = H;
+ destroy(r);
+
+ if(f->seed == H)
+ return;
+
+ h = heap(TRC4state);
+ is = H2D(XRC4state*, h);
+
+ setupRC4state(&is->state, f->seed->data, f->seed->len);
+
+ *f->ret = (Keyring_RC4state*)is;
+}
+
+void
+Keyring_rc4(void *fp)
+{
+ F_Keyring_rc4 *f;
+ XRC4state *is;
+ uchar *p;
+
+ f = fp;
+ if(f->buf == H)
+ return;
+ if(f->n < 0 || f->n > f->buf->len)
+ error(exBounds);
+ is = checktype(f->state, TRC4state, exBadState, 0);
+ p = f->buf->data;
+ rc4(&is->state, p, f->n);
+}
+
+void
+Keyring_rc4skip(void *fp)
+{
+ F_Keyring_rc4skip *f;
+ XRC4state *is;
+
+ f = fp;
+ is = checktype(f->state, TRC4state, exBadState, 0);
+ rc4skip(&is->state, f->n);
+}
+
+void
+Keyring_rc4back(void *fp)
+{
+ F_Keyring_rc4back *f;
+ XRC4state *is;
+
+ f = fp;
+ is = checktype(f->state, TRC4state, exBadState, 0);
+ rc4back(&is->state, f->n);
+}
+
+/*
+ * public/secret keys, signing and verifying
+ */
+
+static void
+dsapk2pub(DSApub* p, Keyring_DSApk* pk)
+{
+ if(pk == H)
+ error(exNilref);
+ p->p = checkIPint(pk->p);
+ p->q = checkIPint(pk->q);
+ p->alpha = checkIPint(pk->alpha);
+ p->key = checkIPint(pk->key);
+}
+
+static void
+dsask2priv(DSApriv* p, Keyring_DSAsk* sk)
+{
+ if(sk == H || sk->pk == H)
+ error(exNilref);
+ dsapk2pub(&p->pub, sk->pk);
+ p->secret = checkIPint(sk->secret);
+}
+
+static void
+dsapriv2sk(Keyring_DSAsk* sk, DSApriv* p)
+{
+ Keyring_DSApk* pk;
+
+ pk = sk->pk;
+ pk->p = ipcopymp(p->pub.p);
+ pk->q = ipcopymp(p->pub.q);
+ pk->alpha = ipcopymp(p->pub.alpha);
+ pk->key = ipcopymp(p->pub.key);
+ sk->secret = ipcopymp(p->secret);
+}
+
+void
+DSAsk_gen(void *fp)
+{
+ F_DSAsk_gen *f;
+ Keyring_DSAsk *sk;
+ DSApriv *p;
+ DSApub pub, *oldpk;
+ void *v;
+
+ f = fp;
+ v = *f->ret;
+ sk = newthing(TDSAsk, 0);
+ sk->pk = newthing(TDSApk, 0);
+ *f->ret = sk;
+ destroy(v);
+ oldpk = nil;
+ if(f->oldpk != H){
+ dsapk2pub(&pub, f->oldpk);
+ oldpk = &pub;
+ }
+ release();
+ p = dsagen(oldpk);
+ acquire();
+ dsapriv2sk(sk, p);
+ dsaprivfree(p);
+}
+
+void
+DSAsk_sign(void *fp)
+{
+ F_DSAsk_sign *f;
+ Keyring_DSAsig *sig;
+ DSApriv p;
+ mpint *m;
+ DSAsig *s;
+ void *v;
+
+ f = fp;
+ v = *f->ret;
+ sig = newthing(TDSAsig, 0);
+ *f->ret = sig;
+ destroy(v);
+
+ dsask2priv(&p, f->k);
+ m = checkIPint(f->m);
+ release();
+ s = dsasign(&p, m);
+ acquire();
+ sig->r = ipcopymp(s->r);
+ sig->s = ipcopymp(s->s);
+ dsasigfree(s);
+}
+
+void
+DSApk_verify(void *fp)
+{
+ F_DSApk_verify *f;
+ DSApub p;
+ DSAsig sig;
+ mpint *m;
+
+ f = fp;
+ *f->ret = 0;
+ if(f->m == H || f->sig == H)
+ return;
+ dsapk2pub(&p, f->k);
+ sig.r = checkIPint(f->sig->r);
+ sig.s = checkIPint(f->sig->s);
+ m = checkIPint(f->m);
+ release();
+ *f->ret = dsaverify(&p, &sig, m) == 0;
+ acquire();
+}
+
+static void
+egpk2pub(EGpub* p, Keyring_EGpk* pk)
+{
+ if(pk == H)
+ error(exNilref);
+ p->p = checkIPint(pk->p);
+ p->alpha = checkIPint(pk->alpha);
+ p->key = checkIPint(pk->key);
+}
+
+static void
+egsk2priv(EGpriv* p, Keyring_EGsk* sk)
+{
+ if(sk == H || sk->pk == H)
+ error(exNilref);
+ egpk2pub(&p->pub, sk->pk);
+ p->secret = checkIPint(sk->secret);
+}
+
+static void
+egpriv2sk(Keyring_EGsk* sk, EGpriv* p)
+{
+ Keyring_EGpk* pk;
+
+ pk = sk->pk;
+ pk->p = ipcopymp(p->pub.p);
+ pk->alpha = ipcopymp(p->pub.alpha);
+ pk->key = ipcopymp(p->pub.key);
+ sk->secret = ipcopymp(p->secret);
+}
+
+void
+EGsk_gen(void *fp)
+{
+ F_EGsk_gen *f;
+ Keyring_EGsk *sk;
+ EGpriv *p;
+ void *v;
+
+ f = fp;
+ v = *f->ret;
+ sk = newthing(TEGsk, 0);
+ sk->pk = newthing(TEGpk, 0);
+ *f->ret = sk;
+ destroy(v);
+ release();
+ for(;;){
+ p = eggen(f->nlen, f->nrep);
+ if(mpsignif(p->pub.p) == f->nlen)
+ break;
+ egprivfree(p);
+ }
+ acquire();
+ egpriv2sk(sk, p);
+ egprivfree(p);
+}
+
+void
+EGsk_sign(void *fp)
+{
+ F_EGsk_sign *f;
+ Keyring_EGsig *sig;
+ EGpriv p;
+ mpint *m;
+ EGsig *s;
+ void *v;
+
+ f = fp;
+ v = *f->ret;
+ sig = newthing(TEGsig, 0);
+ *f->ret = sig;
+ destroy(v);
+
+ egsk2priv(&p, f->k);
+ m = checkIPint(f->m);
+ release();
+ s = egsign(&p, m);
+ acquire();
+ sig->r = ipcopymp(s->r);
+ sig->s = ipcopymp(s->s);
+ egsigfree(s);
+}
+
+void
+EGpk_verify(void *fp)
+{
+ F_EGpk_verify *f;
+ EGpub p;
+ EGsig sig;
+ mpint *m;
+
+ f = fp;
+ *f->ret = 0;
+ if(f->m == H || f->sig == H)
+ return;
+ egpk2pub(&p, f->k);
+ sig.r = checkIPint(f->sig->r);
+ sig.s = checkIPint(f->sig->s);
+ m = checkIPint(f->m);
+ release();
+ *f->ret = egverify(&p, &sig, m) == 0;
+ acquire();
+}
+
+static void
+rsapk2pub(RSApub* p, Keyring_RSApk* pk)
+{
+ if(pk == H)
+ error(exNilref);
+ memset(p, 0, sizeof(*p));
+ p->n = checkIPint(pk->n);
+ p->ek = checkIPint(pk->ek);
+}
+
+static void
+rsask2priv(RSApriv* p, Keyring_RSAsk* sk)
+{
+ if(sk == H || sk->pk == H)
+ error(exNilref);
+ rsapk2pub(&p->pub, sk->pk);
+ p->dk = checkIPint(sk->dk);
+ p->p = checkIPint(sk->p);
+ p->q = checkIPint(sk->q);
+ p->kp = checkIPint(sk->kp);
+ p->kq = checkIPint(sk->kq);
+ p->c2 = checkIPint(sk->c2);
+}
+
+static void
+rsapriv2sk(Keyring_RSAsk* sk, RSApriv* p)
+{
+ Keyring_RSApk* pk;
+
+ pk = sk->pk;
+ pk->n = ipcopymp(p->pub.n);
+ pk->ek = ipcopymp(p->pub.ek);
+ sk->dk = ipcopymp(p->dk);
+ sk->p = ipcopymp(p->p);
+ sk->q = ipcopymp(p->q);
+ sk->kp = ipcopymp(p->kp);
+ sk->kq = ipcopymp(p->kq);
+ sk->c2 = ipcopymp(p->c2);
+}
+
+void
+RSApk_encrypt(void *fp)
+{
+ F_RSApk_encrypt *f;
+ RSApub p;
+ mpint *m, *o;
+ void *v;
+
+ f = fp;
+ v = *f->ret;
+ *f->ret = H;
+ destroy(v);
+
+ rsapk2pub(&p, f->k);
+ m = checkIPint(f->m);
+ release();
+ o = rsaencrypt(&p, m, nil);
+ acquire();
+ *f->ret = newIPint(o);
+}
+
+void
+RSAsk_gen(void *fp)
+{
+ F_RSAsk_gen *f;
+ Keyring_RSAsk *sk;
+ RSApriv *p;
+ void *v;
+
+ f = fp;
+ v = *f->ret;
+ sk = newthing(TRSAsk, 0);
+ sk->pk = newthing(TRSApk, 0);
+ *f->ret = sk;
+ destroy(v);
+ release();
+ for(;;){
+ p = rsagen(f->nlen, f->elen, f->nrep);
+ if(mpsignif(p->pub.n) == f->nlen)
+ break;
+ rsaprivfree(p);
+ }
+ acquire();
+ rsapriv2sk(sk, p);
+ rsaprivfree(p);
+}
+
+void
+RSAsk_fill(void *fp)
+{
+ F_RSAsk_fill *f;
+ Keyring_RSAsk *sk;
+ RSApriv *p;
+ void *v;
+
+ f = fp;
+ v = *f->ret;
+ sk = newthing(TRSAsk, 0);
+ sk->pk = newthing(TRSApk, 0);
+ *f->ret = sk;
+ destroy(v);
+ release();
+ p = rsafill(checkIPint(f->n), checkIPint(f->e), checkIPint(f->d),
+ checkIPint(f->p), checkIPint(f->q));
+ acquire();
+ if(p == nil) {
+ *f->ret = H;
+ destroy(sk);
+ }else{
+ rsapriv2sk(sk, p);
+ rsaprivfree(p);
+ }
+}
+
+void
+RSAsk_decrypt(void *fp)
+{
+ F_RSAsk_decrypt *f;
+ RSApriv p;
+ mpint *m, *o;
+ void *v;
+
+ f = fp;
+ v = *f->ret;
+ *f->ret = H;
+ destroy(v);
+
+ rsask2priv(&p, f->k);
+ m = checkIPint(f->m);
+ release();
+ o = rsadecrypt(&p, m, nil);
+ acquire();
+ *f->ret = newIPint(o);
+}
+
+void
+RSAsk_sign(void *fp)
+{
+ F_RSAsk_sign *f;
+ Keyring_RSAsig *sig;
+ RSApriv p;
+ mpint *m, *s;
+ void *v;
+
+ f = fp;
+ v = *f->ret;
+ sig = newthing(TRSAsig, 0);
+ *f->ret = sig;
+ destroy(v);
+
+ rsask2priv(&p, f->k);
+ m = checkIPint(f->m);
+ release();
+ s = rsadecrypt(&p, m, nil);
+ acquire();
+ sig->n = newIPint(s);
+}
+
+void
+RSApk_verify(void *fp)
+{
+ F_RSApk_verify *f;
+ RSApub p;
+ mpint *sig, *m, *t;
+
+ f = fp;
+ *f->ret = 0;
+ if(f->m == H || f->sig == H)
+ return;
+ rsapk2pub(&p, f->k);
+ sig = checkIPint(f->sig->n);
+ m = checkIPint(f->m);
+ release();
+ t = rsaencrypt(&p, sig, nil);
+ *f->ret = mpcmp(t, m) == 0;
+ mpfree(t);
+ acquire();
+}
+
+void
+Keyring_IPint_random(void *fp)
+{
+ F_IPint_random *f;
+ mpint *b;
+ void *v;
+
+ f = fp;
+ v = *f->ret;
+ *f->ret = H;
+ destroy(v);
+
+ release();
+ b = mprand(f->maxbits, genrandom, nil);
+ acquire();
+ *f->ret = newIPint(b);
+}
--- /dev/null
+++ b/libinterp/keyringif.m
@@ -1,0 +1,4 @@
+# temporary hack to prevent clashes with DigestState
+include "sys.m";
+
+include "keyring.m";
--- /dev/null
+++ b/libinterp/link.c
@@ -1,0 +1,132 @@
+#include "lib9.h"
+#include "isa.h"
+#include "interp.h"
+#include "raise.h"
+#include <kernel.h>
+
+static void
+newlink(Link *l, char *fn, int sig, Type *t)
+{
+ l->name = malloc(strlen(fn)+1);
+ if(l->name == nil)
+ error(exNomem);
+ strcpy(l->name, fn);
+ l->sig = sig;
+ l->frame = t;
+}
+
+void
+runtime(Module *m, Link *l, char *fn, int sig, void (*runt)(void*), Type *t)
+{
+ USED(m);
+ newlink(l, fn, sig, t);
+ l->u.runt = runt;
+}
+
+void
+mlink(Module *m, Link* l, uchar *fn, int sig, int pc, Type *t)
+{
+ newlink(l, (char*)fn, sig, t);
+ l->u.pc = m->prog+pc;
+}
+
+static int
+linkm(Module *m, Modlink *ml, int i, Import *ldt)
+{
+ Link *l;
+ int sig;
+ char e[ERRMAX];
+
+ sig = ldt->sig;
+ for(l = m->ext; l->name; l++)
+ if(strcmp(ldt->name, l->name) == 0)
+ break;
+
+ if(l == nil) {
+ snprint(e, sizeof(e), "link failed fn %s->%s() not implemented", m->name, ldt->name);
+ goto bad;
+ }
+ if(l->sig != sig) {
+ snprint(e, sizeof(e), "link typecheck %s->%s() %ux/%ux",
+ m->name, ldt->name, l->sig, sig);
+ goto bad;
+ }
+
+ ml->links[i].u = l->u;
+ ml->links[i].frame = l->frame;
+ return 0;
+bad:
+ kwerrstr(e);
+ print("%s\n", e);
+ return -1;
+}
+
+Modlink*
+mklinkmod(Module *m, int n)
+{
+ Heap *h;
+ Modlink *ml;
+
+ h = nheap(sizeof(Modlink)+(n-1)*sizeof(ml->links[0]));
+ h->t = &Tmodlink;
+ Tmodlink.ref++;
+ ml = H2D(Modlink*, h);
+ ml->nlinks = n;
+ ml->m = m;
+ ml->prog = m->prog;
+ ml->type = m->type;
+ ml->compiled = m->compiled;
+ ml->MP = H;
+ ml->data = nil;
+
+ return ml;
+}
+
+Modlink*
+linkmod(Module *m, Import *ldt, int mkmp)
+{
+ Type *t;
+ Heap *h;
+ int i;
+ Modlink *ml;
+ Import *l;
+
+ if(m == nil)
+ return H;
+
+ for(i = 0, l = ldt; l->name != nil; i++, l++)
+ ;
+ ml = mklinkmod(m, i);
+
+ if(mkmp){
+ if(m->rt == DYNMOD)
+ newdyndata(ml);
+ else if(mkmp && m->origmp != H && m->ntype > 0) {
+ t = m->type[0];
+ h = nheap(t->size);
+ h->t = t;
+ t->ref++;
+ ml->MP = H2D(uchar*, h);
+ newmp(ml->MP, m->origmp, t);
+ }
+ }
+
+ for(i = 0, l = ldt; l->name != nil; i++, l++) {
+ if(linkm(m, ml, i, l) < 0){
+ destroy(ml);
+ return H;
+ }
+ }
+
+ return ml;
+}
+
+void
+destroylinks(Module *m)
+{
+ Link *l;
+
+ for(l = m->ext; l->name; l++)
+ free(l->name);
+ free(m->ext);
+}
--- /dev/null
+++ b/libinterp/load.c
@@ -1,0 +1,621 @@
+#include "lib9.h"
+#include "isa.h"
+#include "interp.h"
+#include "raise.h"
+#include <kernel.h>
+
+#define A(r) *((Array**)(r))
+
+Module* modules;
+int dontcompile;
+
+static int
+operand(uchar **p)
+{
+ int c;
+ uchar *cp;
+
+ cp = *p;
+ c = cp[0];
+ switch(c & 0xC0) {
+ case 0x00:
+ *p = cp+1;
+ return c;
+ case 0x40:
+ *p = cp+1;
+ return c|~0x7F;
+ case 0x80:
+ *p = cp+2;
+ if(c & 0x20)
+ c |= ~0x3F;
+ else
+ c &= 0x3F;
+ return (c<<8)|cp[1];
+ case 0xC0:
+ *p = cp+4;
+ if(c & 0x20)
+ c |= ~0x3F;
+ else
+ c &= 0x3F;
+ return (c<<24)|(cp[1]<<16)|(cp[2]<<8)|cp[3];
+ }
+ return 0;
+}
+
+static ulong
+disw(uchar **p)
+{
+ ulong v;
+ uchar *c;
+
+ c = *p;
+ v = c[0] << 24;
+ v |= c[1] << 16;
+ v |= c[2] << 8;
+ v |= c[3];
+ *p = c + 4;
+ return v;
+}
+
+double
+canontod(ulong v[2])
+{
+ union { double d; unsigned long ul[2]; } a;
+ a.d = 1.;
+ if(a.ul[0]) {
+ a.ul[0] = v[0];
+ a.ul[1] = v[1];
+ }
+ else {
+ a.ul[1] = v[0];
+ a.ul[0] = v[1];
+ }
+ return a.d;
+}
+
+Module*
+load(char *path)
+{
+ return readmod(path, nil, 0);
+}
+
+int
+brpatch(Inst *ip, Module *m)
+{
+ switch(ip->op) {
+ case ICALL:
+ case IJMP:
+ case IBEQW:
+ case IBNEW:
+ case IBLTW:
+ case IBLEW:
+ case IBGTW:
+ case IBGEW:
+ case IBEQB:
+ case IBNEB:
+ case IBLTB:
+ case IBLEB:
+ case IBGTB:
+ case IBGEB:
+ case IBEQF:
+ case IBNEF:
+ case IBLTF:
+ case IBLEF:
+ case IBGTF:
+ case IBGEF:
+ case IBEQC:
+ case IBNEC:
+ case IBLTC:
+ case IBLEC:
+ case IBGTC:
+ case IBGEC:
+ case IBEQL:
+ case IBNEL:
+ case IBLTL:
+ case IBLEL:
+ case IBGTL:
+ case IBGEL:
+ case ISPAWN:
+ if(ip->d.imm < 0 || ip->d.imm >= m->nprog)
+ return 0;
+ ip->d.imm = (WORD)&m->prog[ip->d.imm];
+ break;
+ }
+ return 1;
+}
+
+Module*
+parsemod(char *path, uchar *code, ulong length, Dir *dir)
+{
+ Heap *h;
+ Inst *ip;
+ Type *pt;
+ String *s;
+ Module *m;
+ Array *ary;
+ ulong ul[2];
+ WORD lo, hi;
+ int lsize, id, v, entry, entryt, tnp, tsz, siglen;
+ int de, pc, i, n, isize, dsize, hsize, dasp;
+ uchar *mod, sm, *istream, **isp, *si, *addr, *dastack[DADEPTH];
+ Link *l;
+
+ istream = code;
+ isp = &istream;
+
+ m = malloc(sizeof(Module));
+ if(m == nil)
+ return nil;
+
+ m->dev = dir->dev;
+ m->dtype = dir->type;
+ m->qid = dir->qid;
+ m->mtime = dir->mtime;
+ m->origmp = H;
+ m->pctab = nil;
+
+ switch(operand(isp)) {
+ default:
+ kwerrstr("bad magic");
+ goto bad;
+ case SMAGIC:
+ siglen = operand(isp);
+ n = length-(*isp-code);
+ if(n < 0 || siglen > n){
+ kwerrstr("corrupt signature");
+ goto bad;
+ }
+ if(verifysigner(*isp, siglen, *isp+siglen, n-siglen) == 0) {
+ kwerrstr("security violation");
+ goto bad;
+ }
+ *isp += siglen;
+ break;
+ case XMAGIC:
+ if(mustbesigned(path, code, length, dir)){
+ kwerrstr("security violation: not signed");
+ goto bad;
+ }
+ break;
+ }
+
+ m->rt = operand(isp);
+ m->ss = operand(isp);
+ isize = operand(isp);
+ dsize = operand(isp);
+ hsize = operand(isp);
+ lsize = operand(isp);
+ entry = operand(isp);
+ entryt = operand(isp);
+
+ if(isize < 0 || dsize < 0 || hsize < 0 || lsize < 0) {
+ kwerrstr("implausible Dis file");
+ goto bad;
+ }
+
+ m->nprog = isize;
+ m->prog = mallocz(isize*sizeof(Inst), 0);
+ if(m->prog == nil) {
+ kwerrstr(exNomem);
+ goto bad;
+ }
+
+ m->ref = 1;
+
+ ip = m->prog;
+ for(i = 0; i < isize; i++) {
+ ip->op = *istream++;
+ ip->add = *istream++;
+ ip->reg = 0;
+ ip->s.imm = 0;
+ ip->d.imm = 0;
+ switch(ip->add & ARM) {
+ case AXIMM:
+ case AXINF:
+ case AXINM:
+ ip->reg = operand(isp);
+ break;
+ }
+ switch(UXSRC(ip->add)) {
+ case SRC(AFP):
+ case SRC(AMP):
+ case SRC(AIMM):
+ ip->s.ind = operand(isp);
+ break;
+ case SRC(AIND|AFP):
+ case SRC(AIND|AMP):
+ ip->s.i.f = operand(isp);
+ ip->s.i.s = operand(isp);
+ break;
+ }
+ switch(UXDST(ip->add)) {
+ case DST(AFP):
+ case DST(AMP):
+ ip->d.ind = operand(isp);
+ break;
+ case DST(AIMM):
+ ip->d.ind = operand(isp);
+ if(brpatch(ip, m) == 0) {
+ kwerrstr("bad branch addr");
+ goto bad;
+ }
+ break;
+ case DST(AIND|AFP):
+ case DST(AIND|AMP):
+ ip->d.i.f = operand(isp);
+ ip->d.i.s = operand(isp);
+ break;
+ }
+ ip++;
+ }
+
+ m->ntype = hsize;
+ m->type = malloc(hsize*sizeof(Type*));
+ if(m->type == nil) {
+ kwerrstr(exNomem);
+ goto bad;
+ }
+ for(i = 0; i < hsize; i++) {
+ id = operand(isp);
+ if(id > hsize) {
+ kwerrstr("heap id range");
+ goto bad;
+ }
+ tsz = operand(isp);
+ tnp = operand(isp);
+ if(tsz < 0 || tnp < 0 || tnp > 128*1024){
+ kwerrstr("implausible Dis file");
+ goto bad;
+ }
+ pt = dtype(freeheap, tsz, istream, tnp);
+ if(pt == nil) {
+ kwerrstr(exNomem);
+ goto bad;
+ }
+ istream += tnp;
+ m->type[id] = pt;
+ }
+
+ if(dsize != 0) {
+ pt = m->type[0];
+ if(pt == 0 || pt->size != dsize) {
+ kwerrstr("bad desc for mp");
+ goto bad;
+ }
+ h = heapz(pt);
+ m->origmp = H2D(uchar*, h);
+ }
+ addr = m->origmp;
+ dasp = 0;
+ for(;;) {
+ sm = *istream++;
+ if(sm == 0)
+ break;
+ n = DLEN(sm);
+ if(n == 0)
+ n = operand(isp);
+ v = operand(isp);
+ si = addr + v;
+ switch(DTYPE(sm)) {
+ default:
+ kwerrstr("bad data item");
+ goto bad;
+ case DEFS:
+ s = c2string((char*)istream, n);
+ istream += n;
+ *(String**)si = s;
+ break;
+ case DEFB:
+ for(i = 0; i < n; i++)
+ *si++ = *istream++;
+ break;
+ case DEFW:
+ for(i = 0; i < n; i++) {
+ *(WORD*)si = disw(isp);
+ si += sizeof(WORD);
+ }
+ break;
+ case DEFL:
+ for(i = 0; i < n; i++) {
+ hi = disw(isp);
+ lo = disw(isp);
+ *(LONG*)si = (LONG)hi << 32 | (LONG)(ulong)lo;
+ si += sizeof(LONG);
+ }
+ break;
+ case DEFF:
+ for(i = 0; i < n; i++) {
+ ul[0] = disw(isp);
+ ul[1] = disw(isp);
+ *(REAL*)si = canontod(ul);
+ si += sizeof(REAL);
+ }
+ break;
+ case DEFA: /* Array */
+ v = disw(isp);
+ if(v < 0 || v > m->ntype) {
+ kwerrstr("bad array type");
+ goto bad;
+ }
+ pt = m->type[v];
+ v = disw(isp);
+ h = nheap(sizeof(Array)+(pt->size*v));
+ h->t = &Tarray;
+ h->t->ref++;
+ ary = H2D(Array*, h);
+ ary->t = pt;
+ ary->len = v;
+ ary->root = H;
+ ary->data = (uchar*)ary+sizeof(Array);
+ memset((void*)ary->data, 0, pt->size*v);
+ initarray(pt, ary);
+ A(si) = ary;
+ break;
+ case DIND: /* Set index */
+ ary = A(si);
+ if(ary == H || D2H(ary)->t != &Tarray) {
+ kwerrstr("ind not array");
+ goto bad;
+ }
+ v = disw(isp);
+ if(v > ary->len || v < 0 || dasp >= DADEPTH) {
+ kwerrstr("array init range");
+ goto bad;
+ }
+ dastack[dasp++] = addr;
+ addr = ary->data+v*ary->t->size;
+ break;
+ case DAPOP:
+ if(dasp == 0) {
+ kwerrstr("pop range");
+ goto bad;
+ }
+ addr = dastack[--dasp];
+ break;
+ }
+ }
+ mod = istream;
+ if(memchr(mod, 0, 128) == 0) {
+ kwerrstr("bad module name");
+ goto bad;
+ }
+ m->name = strdup((char*)mod);
+ if(m->name == nil) {
+ kwerrstr(exNomem);
+ goto bad;
+ }
+ while(*istream++)
+ ;
+
+ l = m->ext = (Link*)malloc((lsize+1)*sizeof(Link));
+ if(l == nil){
+ kwerrstr(exNomem);
+ goto bad;
+ }
+ for(i = 0; i < lsize; i++, l++) {
+ pc = operand(isp);
+ de = operand(isp);
+ v = disw(isp);
+ pt = nil;
+ if(de != -1)
+ pt = m->type[de];
+ mlink(m, l, istream, v, pc, pt);
+ while(*istream++)
+ ;
+ }
+ l->name = nil;
+
+ if(m->rt & HASLDT0){
+ kwerrstr("obsolete dis");
+ goto bad;
+ }
+
+ if(m->rt & HASLDT){
+ int j, nl;
+ Import *i1, **i2;
+
+ nl = operand(isp);
+ i2 = m->ldt = (Import**)malloc((nl+1)*sizeof(Import*));
+ if(i2 == nil){
+ kwerrstr(exNomem);
+ goto bad;
+ }
+ for(i = 0; i < nl; i++, i2++){
+ n = operand(isp);
+ i1 = *i2 = (Import*)malloc((n+1)*sizeof(Import));
+ if(i1 == nil){
+ kwerrstr(exNomem);
+ goto bad;
+ }
+ for(j = 0; j < n; j++, i1++){
+ i1->sig = disw(isp);
+ i1->name = strdup((char*)istream);
+ if(i1->name == nil){
+ kwerrstr(exNomem);
+ goto bad;
+ }
+ while(*istream++)
+ ;
+ }
+ }
+ istream++;
+ }
+
+ if(m->rt & HASEXCEPT){
+ int j, nh;
+ Handler *h;
+ Except *e;
+
+ nh = operand(isp);
+ m->htab = malloc((nh+1)*sizeof(Handler));
+ if(m->htab == nil){
+ kwerrstr(exNomem);
+ goto bad;
+ }
+ h = m->htab;
+ for(i = 0; i < nh; i++, h++){
+ h->eoff = operand(isp);
+ h->pc1 = operand(isp);
+ h->pc2 = operand(isp);
+ n = operand(isp);
+ if(n != -1)
+ h->t = m->type[n];
+ n = operand(isp);
+ h->ne = n>>16;
+ n &= 0xffff;
+ h->etab = malloc((n+1)*sizeof(Except));
+ if(h->etab == nil){
+ kwerrstr(exNomem);
+ goto bad;
+ }
+ e = h->etab;
+ for(j = 0; j < n; j++, e++){
+ e->s = strdup((char*)istream);
+ if(e->s == nil){
+ kwerrstr(exNomem);
+ goto bad;
+ }
+ while(*istream++)
+ ;
+ e->pc = operand(isp);
+ }
+ e->s = nil;
+ e->pc = operand(isp);
+ }
+ istream++;
+ }
+
+ m->entryt = nil;
+ m->entry = m->prog;
+ if((ulong)entry < isize && (ulong)entryt < hsize) {
+ m->entry = &m->prog[entry];
+ m->entryt = m->type[entryt];
+ }
+
+ if(cflag) {
+ if((m->rt&DONTCOMPILE) == 0 && !dontcompile)
+ compile(m, isize, nil);
+ }
+ else
+ if(m->rt & MUSTCOMPILE && !dontcompile) {
+ if(compile(m, isize, nil) == 0) {
+ kwerrstr("compiler required");
+ goto bad;
+ }
+ }
+
+ m->path = strdup(path);
+ if(m->path == nil) {
+ kwerrstr(exNomem);
+ goto bad;
+ }
+ m->link = modules;
+ modules = m;
+
+ return m;
+bad:
+ destroy(m->origmp);
+ freemod(m);
+ return nil;
+}
+
+Module*
+newmod(char *s)
+{
+ Module *m;
+
+ m = malloc(sizeof(Module));
+ if(m == nil)
+ error(exNomem);
+ m->ref = 1;
+ m->path = s;
+ m->origmp = H;
+ m->name = strdup(s);
+ if(m->name == nil) {
+ free(m);
+ error(exNomem);
+ }
+ m->link = modules;
+ modules = m;
+ m->pctab = nil;
+ return m;
+}
+
+Module*
+lookmod(char *s)
+{
+ Module *m;
+
+ for(m = modules; m != nil; m = m->link)
+ if(strcmp(s, m->path) == 0) {
+ m->ref++;
+ return m;
+ }
+ return nil;
+}
+
+void
+freemod(Module *m)
+{
+ int i;
+ Handler *h;
+ Except *e;
+ Import *i1, **i2;
+
+ if(m->type != nil) {
+ for(i = 0; i < m->ntype; i++)
+ freetype(m->type[i]);
+ free(m->type);
+ }
+ free(m->name);
+ free(m->prog);
+ free(m->path);
+ free(m->pctab);
+ if(m->ldt != nil){
+ for(i2 = m->ldt; *i2 != nil; i2++){
+ for(i1 = *i2; i1->name != nil; i1++)
+ free(i1->name);
+ free(*i2);
+ }
+ free(m->ldt);
+ }
+ if(m->htab != nil){
+ for(h = m->htab; h->etab != nil; h++){
+ for(e = h->etab; e->s != nil; e++)
+ free(e->s);
+ free(h->etab);
+ }
+ free(m->htab);
+ }
+ free(m);
+}
+
+void
+unload(Module *m)
+{
+ Module **last, *mm;
+
+ m->ref--;
+ if(m->ref > 0)
+ return;
+ if(m->ref == -1)
+ abort();
+
+ last = &modules;
+ for(mm = modules; mm != nil; mm = mm->link) {
+ if(mm == m) {
+ *last = m->link;
+ break;
+ }
+ last = &mm->link;
+ }
+
+ if(m->rt == DYNMOD)
+ freedyncode(m);
+ else
+ destroy(m->origmp);
+
+ destroylinks(m);
+
+ freemod(m);
+}
--- /dev/null
+++ b/libinterp/loader.c
@@ -1,0 +1,444 @@
+#include "lib9.h"
+#include "isa.h"
+#include "interp.h"
+#include "runt.h"
+#include "loadermod.h"
+#include "raise.h"
+#include <kernel.h>
+
+static uchar Instmap[] = Loader_Inst_map;
+static Type* Tinst;
+static uchar Tdescmap[] = Loader_Typedesc_map;
+static Type* Tdesc;
+static uchar Tlinkmap[] = Loader_Link_map;
+static Type* Tlink;
+
+void
+loadermodinit(void)
+{
+ sysinit();
+ builtinmod("$Loader", Loadermodtab, Loadermodlen);
+ Tinst = dtype(freeheap, sizeof(Loader_Inst), Instmap, sizeof(Instmap));
+ Tdesc = dtype(freeheap, sizeof(Loader_Typedesc), Tdescmap, sizeof(Tdescmap));
+ Tlink = dtype(freeheap, sizeof(Loader_Link), Tlinkmap, sizeof(Tlinkmap));
+}
+
+static void
+brunpatch(Loader_Inst *ip, Module *m)
+{
+ switch(ip->op) {
+ case ICALL:
+ case IJMP:
+ case IBEQW:
+ case IBNEW:
+ case IBLTW:
+ case IBLEW:
+ case IBGTW:
+ case IBGEW:
+ case IBEQB:
+ case IBNEB:
+ case IBLTB:
+ case IBLEB:
+ case IBGTB:
+ case IBGEB:
+ case IBEQF:
+ case IBNEF:
+ case IBLTF:
+ case IBLEF:
+ case IBGTF:
+ case IBGEF:
+ case IBEQC:
+ case IBNEC:
+ case IBLTC:
+ case IBLEC:
+ case IBGTC:
+ case IBGEC:
+ case IBEQL:
+ case IBNEL:
+ case IBLTL:
+ case IBLEL:
+ case IBGTL:
+ case IBGEL:
+ case ISPAWN:
+ ip->dst = (Inst*)ip->dst - m->prog;
+ break;
+ }
+}
+
+void
+Loader_ifetch(void *a)
+{
+ Heap *h;
+ Array *ar;
+ Module *m;
+ Inst *i, *ie;
+ Loader_Inst *li;
+ F_Loader_ifetch *f;
+
+ f = a;
+ destroy(*f->ret);
+ *f->ret = H;
+
+ if(f->mp == H)
+ return;
+ m = f->mp->m;
+ if(m == H)
+ return;
+ if(m->compiled) {
+ kwerrstr("compiled module");
+ return;
+ }
+
+ h = nheap(sizeof(Array)+m->nprog*sizeof(Loader_Inst));
+ h->t = &Tarray;
+ h->t->ref++;
+ ar = H2D(Array*, h);
+ ar->t = Tinst;
+ Tinst->ref++;
+ ar->len = m->nprog;
+ ar->root = H;
+ ar->data = (uchar*)ar+sizeof(Array);
+
+ li = (Loader_Inst*)ar->data;
+ i = m->prog;
+ ie = i + m->nprog;
+ while(i < ie) {
+ li->op = i->op;
+ li->addr = i->add;
+ li->src = i->s.imm;
+ li->dst = i->d.imm;
+ li->mid = i->reg;
+ if(UDST(i->add) == AIMM)
+ brunpatch(li, m);
+ li++;
+ i++;
+ }
+
+ *f->ret = ar;
+}
+
+void
+Loader_link(void *a)
+{
+ Link *p;
+ Heap *h;
+ Type **t;
+ int nlink;
+ Module *m;
+ Array *ar;
+ Loader_Link *ll;
+ F_Loader_link *f;
+
+ f = a;
+ destroy(*f->ret);
+ *f->ret = H;
+
+ if(f->mp == H)
+ return;
+ m = f->mp->m;
+ if(m == H)
+ return;
+
+ nlink = 0;
+ for(p = m->ext; p->name; p++)
+ nlink++;
+
+ h = nheap(sizeof(Array)+nlink*sizeof(Loader_Link));
+ h->t = &Tarray;
+ h->t->ref++;
+ ar = H2D(Array*, h);
+ ar->t = Tlink;
+ Tlink->ref++;
+ ar->len = nlink;
+ ar->root = H;
+ ar->data = (uchar*)ar+sizeof(Array);
+
+ ll = (Loader_Link*)ar->data + nlink;
+ for(p = m->ext; p->name; p++) {
+ ll--;
+ ll->name = c2string(p->name, strlen(p->name));
+ ll->sig = p->sig;
+ if(m->prog == nil) {
+ ll->pc = -1;
+ ll->tdesc = -1;
+ } else {
+ ll->pc = p->u.pc - m->prog;
+ ll->tdesc = 0;
+ for(t = m->type; *t != p->frame; t++)
+ ll->tdesc++;
+ }
+ }
+
+ *f->ret = ar;
+}
+
+void
+Loader_tdesc(void *a)
+{
+ int i;
+ Heap *h;
+ Type *t;
+ Array *ar;
+ Module *m;
+ F_Loader_tdesc *f;
+ Loader_Typedesc *lt;
+
+ f = a;
+ destroy(*f->ret);
+ *f->ret = H;
+
+ if(f->mp == H)
+ return;
+ m = f->mp->m;
+ if(m == H)
+ return;
+
+ h = nheap(sizeof(Array)+m->ntype*sizeof(Loader_Typedesc));
+ h->t = &Tarray;
+ h->t->ref++;
+ ar = H2D(Array*, h);
+ ar->t = Tdesc;
+ Tdesc->ref++;
+ ar->len = m->ntype;
+ ar->root = H;
+ ar->data = (uchar*)ar+sizeof(Array);
+
+ lt = (Loader_Typedesc*)ar->data;
+ for(i = 0; i < m->ntype; i++) {
+ t = m->type[i];
+ lt->size = t->size;
+ lt->map = H;
+ if(t->np != 0)
+ lt->map = mem2array(t->map, t->np);
+ lt++;
+ }
+
+ *f->ret = ar;
+}
+
+void
+Loader_newmod(void *a)
+{
+ Heap *h;
+ Module *m;
+ Array *ia;
+ Modlink *ml;
+ Inst *i, *ie;
+ Loader_Inst *li;
+ F_Loader_newmod *f;
+
+ f = a;
+ destroy(*f->ret);
+ *f->ret = H;
+
+ if(f->inst == H || f->data == H) {
+ kwerrstr("nil parameters");
+ return;
+ }
+ if(f->nlink < 0) {
+ kwerrstr("bad nlink");
+ return;
+ }
+
+ m = malloc(sizeof(Module));
+ if(m == nil) {
+ kwerrstr(exNomem);
+ return;
+ }
+ m->origmp = H;
+ m->ref = 1;
+ m->ss = f->ss;
+ m->name = strdup(string2c(f->name));
+ m->path = strdup(m->name);
+ m->ntype = 1;
+ m->type = malloc(sizeof(Type*));
+ if(m->name == nil || m->path == nil || m->type == nil) {
+ kwerrstr(exNomem);
+ goto bad;
+ }
+ m->origmp = (uchar*)f->data;
+ h = D2H(f->data);
+ h->ref++;
+ Setmark(h);
+ m->type[0] = h->t;
+ h->t->ref++;
+
+ ia = f->inst;
+ m->nprog = ia->len;
+ m->prog = malloc(m->nprog*sizeof(Inst));
+ if(m->prog == nil)
+ goto bad;
+ i = m->prog;
+ ie = i + m->nprog;
+ li = (Loader_Inst*)ia->data;
+ while(i < ie) {
+ i->op = li->op;
+ i->add = li->addr;
+ i->reg = li->mid;
+ i->s.imm = li->src;
+ i->d.imm = li->dst;
+ if(brpatch(i, m) == 0) {
+ kwerrstr("bad branch addr");
+ goto bad;
+ }
+ i++;
+ li++;
+ }
+ m->entryt = nil;
+ m->entry = m->prog;
+
+ ml = mklinkmod(m, f->nlink);
+ ml->MP = m->origmp;
+ m->origmp = H;
+ m->pctab = nil;
+ *f->ret = ml;
+ return;
+bad:
+ destroy(m->origmp);
+ freemod(m);
+}
+
+void
+Loader_tnew(void *a)
+{
+ int mem;
+ Module *m;
+ Type *t, **nt;
+ Array *ar, az;
+ F_Loader_tnew *f;
+
+ f = a;
+ *f->ret = -1;
+ if(f->mp == H)
+ return;
+ m = f->mp->m;
+ if(m == H)
+ return;
+ if(m->origmp != H){
+ kwerrstr("need newmod");
+ return;
+ }
+
+ ar = f->map;
+ if(ar == H) {
+ ar = &az;
+ ar->len = 0;
+ ar->data = nil;
+ }
+
+ t = dtype(freeheap, f->size, ar->data, ar->len);
+ if(t == nil)
+ return;
+
+ mem = (m->ntype+1)*sizeof(Type*);
+ if(msize(m->type) > mem) {
+ *f->ret = m->ntype;
+ m->type[m->ntype++] = t;
+ return;
+ }
+ nt = realloc(m->type, mem);
+ if(nt == nil) {
+ kwerrstr(exNomem);
+ return;
+ }
+ m->type = nt;
+ f->mp->type = nt;
+ *f->ret = m->ntype;
+ m->type[m->ntype++] = t;
+}
+
+void
+Loader_ext(void *a)
+{
+ Modl *l;
+ Module *m;
+ Modlink *ml;
+ F_Loader_ext *f;
+
+ f = a;
+ *f->ret = -1;
+ if(f->mp == H) {
+ kwerrstr("nil mp");
+ return;
+ }
+ ml = f->mp;
+ m = ml->m;
+ if(f->tdesc < 0 || f->tdesc >= m->ntype) {
+ kwerrstr("bad tdesc");
+ return;
+ }
+ if(f->pc < 0 || f->pc >= m->nprog) {
+ kwerrstr("bad pc");
+ return;
+ }
+ if(f->idx < 0 || f->idx >= ml->nlinks) {
+ kwerrstr("bad idx");
+ return;
+ }
+ l = &ml->links[f->idx];
+ l->u.pc = m->prog + f->pc;
+ l->frame = m->type[f->tdesc];
+ *f->ret = 0;
+}
+
+void
+Loader_dnew(void *a)
+{
+ F_Loader_dnew *f;
+ Heap *h;
+ Array *ar, az;
+ Type *t;
+
+ f = a;
+ *f->ret = H;
+ if(f->map == H)
+ return;
+ ar = f->map;
+ if(ar == H) {
+ ar = &az;
+ ar->len = 0;
+ ar->data = nil;
+ }
+ t = dtype(freeheap, f->size, ar->data, ar->len);
+ if(t == nil) {
+ kwerrstr(exNomem);
+ return;
+ }
+
+ h=heapz(t);
+ if(h == nil) {
+ freetype(t);
+ kwerrstr(exNomem);
+ return;
+ }
+
+ *f->ret=H2D(Loader_Niladt*, h);
+}
+
+void
+Loader_compile(void *a)
+{
+ Module *m;
+ F_Loader_compile *f;
+
+ f = a;
+ *f->ret = -1;
+ if(f->mp == H) {
+ kwerrstr("nil mp");
+ return;
+ }
+ m = f->mp->m;
+ if(m->compiled) {
+ kwerrstr("compiled module");
+ return;
+ }
+ *f->ret = 0;
+ m->origmp = f->mp->MP;
+ if(cflag || f->flag)
+ if(compile(m, m->nprog, f->mp)) {
+ f->mp->prog = m->prog;
+ f->mp->compiled = 1;
+ } else
+ *f->ret = -1;
+ m->origmp = H;
+}
--- /dev/null
+++ b/libinterp/math.c
@@ -1,0 +1,955 @@
+#include "lib9.h"
+#include "interp.h"
+#include "isa.h"
+#include "runt.h"
+#include "raise.h"
+#include "mathi.h"
+#include "mathmod.h"
+
+static union
+{
+ double x;
+ uvlong u;
+} bits64;
+
+static union{
+ float x;
+ unsigned int u;
+} bits32;
+
+void
+mathmodinit(void)
+{
+ builtinmod("$Math", Mathmodtab, Mathmodlen);
+ fmtinstall('g', gfltconv);
+ fmtinstall('G', gfltconv);
+ fmtinstall('e', gfltconv);
+ /* fmtinstall('E', gfltconv); */ /* avoid clash with ether address */
+ fmtinstall(0x00c9, gfltconv); /* L'É' */
+ fmtinstall('f', gfltconv);
+}
+
+void
+Math_import_int(void *fp)
+{
+ F_Math_import_int *f;
+ int i, n;
+ unsigned int u;
+ unsigned char *bp;
+ int *x;
+
+ f = fp;
+ n = f->x->len;
+ if(f->b->len!=4*n)
+ error(exMathia);
+ bp = (unsigned char *)(f->b->data);
+ x = (int*)(f->x->data);
+ for(i=0; i<n; i++){
+ u = *bp++;
+ u = (u<<8) | *bp++;
+ u = (u<<8) | *bp++;
+ u = (u<<8) | *bp++;
+ x[i] = u;
+ }
+}
+
+void
+Math_import_real32(void *fp)
+{
+ F_Math_import_int *f;
+ int i, n;
+ unsigned int u;
+ unsigned char *bp;
+ double *x;
+
+ f = fp;
+ n = f->x->len;
+ if(f->b->len!=4*n)
+ error(exMathia);
+ bp = (unsigned char *)(f->b->data);
+ x = (double*)(f->x->data);
+ for(i=0; i<n; i++){
+ u = *bp++;
+ u = (u<<8) | *bp++;
+ u = (u<<8) | *bp++;
+ u = (u<<8) | *bp++;
+ bits32.u = u;
+ x[i] = bits32.x;
+ }
+}
+
+void
+Math_import_real(void *fp)
+{
+ F_Math_import_int *f;
+ int i, n;
+ uvlong u;
+ unsigned char *bp;
+ double *x;
+
+ f = fp;
+ n = f->x->len;
+ if(f->b->len!=8*n)
+ error(exMathia);
+ bp = f->b->data;
+ x = (double*)(f->x->data);
+ for(i=0; i<n; i++){
+ u = *bp++;
+ u = (u<<8) | *bp++;
+ u = (u<<8) | *bp++;
+ u = (u<<8) | *bp++;
+ u = (u<<8) | *bp++;
+ u = (u<<8) | *bp++;
+ u = (u<<8) | *bp++;
+ u = (u<<8) | *bp++;
+ bits64.u = u;
+ x[i] = bits64.x;
+ }
+}
+
+void
+Math_export_int(void *fp)
+{
+ F_Math_export_int *f;
+ int i, n;
+ unsigned int u;
+ unsigned char *bp;
+ int *x;
+
+ f = fp;
+ n = f->x->len;
+ if(f->b->len!=4*n)
+ error(exMathia);
+ bp = (unsigned char *)(f->b->data);
+ x = (int*)(f->x->data);
+ for(i=0; i<n; i++){
+ u = x[i];
+ *bp++ = u>>24;
+ *bp++ = u>>16;
+ *bp++ = u>>8;
+ *bp++ = u;
+ }
+}
+
+void
+Math_export_real32(void *fp)
+{
+ F_Math_export_int *f;
+ int i, n;
+ unsigned int u;
+ unsigned char *bp;
+ double *x;
+
+ f = fp;
+ n = f->x->len;
+ if(f->b->len!=4*n)
+ error(exMathia);
+ bp = (unsigned char *)(f->b->data);
+ x = (double*)(f->x->data);
+ for(i=0; i<n; i++){
+ bits32.x = x[i];
+ u = bits32.u;
+ *bp++ = u>>24;
+ *bp++ = u>>16;
+ *bp++ = u>>8;
+ *bp++ = u;
+ }
+}
+
+void
+Math_export_real(void *fp)
+{
+ F_Math_export_int *f;
+ int i, n;
+ uvlong u;
+ unsigned char *bp;
+ double *x;
+
+ f = fp;
+ n = f->x->len;
+ if(f->b->len!=8*n)
+ error(exMathia);
+ bp = (unsigned char *)(f->b->data);
+ x = (double*)(f->x->data);
+ for(i=0; i<n; i++){
+ bits64.x = x[i];
+ u = bits64.u;
+ *bp++ = u>>56;
+ *bp++ = u>>48;
+ *bp++ = u>>40;
+ *bp++ = u>>32;
+ *bp++ = u>>24;
+ *bp++ = u>>16;
+ *bp++ = u>>8;
+ *bp++ = u;
+ }
+}
+
+
+void
+Math_bits32real(void *fp)
+{
+ F_Math_bits32real *f;
+
+ f = fp;
+ bits32.u = f->b;
+ *f->ret = bits32.x;
+}
+
+void
+Math_bits64real(void *fp)
+{
+ F_Math_bits64real *f;
+
+ f = fp;
+ bits64.u = f->b;
+ *f->ret = bits64.x;
+}
+
+void
+Math_realbits32(void *fp)
+{
+ F_Math_realbits32 *f;
+
+ f = fp;
+ bits32.x = f->x;
+ *f->ret = bits32.u;
+}
+
+void
+Math_realbits64(void *fp)
+{
+ F_Math_realbits64 *f;
+
+ f = fp;
+ bits64.x = f->x;
+ *f->ret = bits64.u;
+}
+
+
+void
+Math_getFPcontrol(void *fp)
+{
+ F_Math_getFPcontrol *f;
+
+ f = fp;
+
+ *f->ret = getFPcontrol();
+}
+
+void
+Math_getFPstatus(void *fp)
+{
+ F_Math_getFPstatus *f;
+
+ f = fp;
+
+ *f->ret = getFPstatus();
+}
+
+void
+Math_finite(void *fp)
+{
+ F_Math_finite *f;
+
+ f = fp;
+
+ *f->ret = finite(f->x);
+}
+
+void
+Math_ilogb(void *fp)
+{
+ F_Math_ilogb *f;
+
+ f = fp;
+
+ *f->ret = ilogb(f->x);
+}
+
+void
+Math_isnan(void *fp)
+{
+ F_Math_isnan *f;
+
+ f = fp;
+
+ *f->ret = isNaN(f->x);
+}
+
+void
+Math_acos(void *fp)
+{
+ F_Math_acos *f;
+
+ f = fp;
+
+ *f->ret = __ieee754_acos(f->x);
+}
+
+void
+Math_acosh(void *fp)
+{
+ F_Math_acosh *f;
+
+ f = fp;
+
+ *f->ret = __ieee754_acosh(f->x);
+}
+
+void
+Math_asin(void *fp)
+{
+ F_Math_asin *f;
+
+ f = fp;
+
+ *f->ret = __ieee754_asin(f->x);
+}
+
+void
+Math_asinh(void *fp)
+{
+ F_Math_asinh *f;
+
+ f = fp;
+
+ *f->ret = asinh(f->x);
+}
+
+void
+Math_atan(void *fp)
+{
+ F_Math_atan *f;
+
+ f = fp;
+
+ *f->ret = atan(f->x);
+}
+
+void
+Math_atanh(void *fp)
+{
+ F_Math_atanh *f;
+
+ f = fp;
+
+ *f->ret = __ieee754_atanh(f->x);
+}
+
+void
+Math_cbrt(void *fp)
+{
+ F_Math_cbrt *f;
+
+ f = fp;
+
+ *f->ret = cbrt(f->x);
+}
+
+void
+Math_ceil(void *fp)
+{
+ F_Math_ceil *f;
+
+ f = fp;
+
+ *f->ret = ceil(f->x);
+}
+
+void
+Math_cos(void *fp)
+{
+ F_Math_cos *f;
+
+ f = fp;
+
+ *f->ret = cos(f->x);
+}
+
+void
+Math_cosh(void *fp)
+{
+ F_Math_cosh *f;
+
+ f = fp;
+
+ *f->ret = __ieee754_cosh(f->x);
+}
+
+void
+Math_erf(void *fp)
+{
+ F_Math_erf *f;
+
+ f = fp;
+
+ *f->ret = erf(f->x);
+}
+
+void
+Math_erfc(void *fp)
+{
+ F_Math_erfc *f;
+
+ f = fp;
+
+ *f->ret = erfc(f->x);
+}
+
+void
+Math_exp(void *fp)
+{
+ F_Math_exp *f;
+
+ f = fp;
+
+ *f->ret = __ieee754_exp(f->x);
+}
+
+void
+Math_expm1(void *fp)
+{
+ F_Math_expm1 *f;
+
+ f = fp;
+
+ *f->ret = expm1(f->x);
+}
+
+void
+Math_fabs(void *fp)
+{
+ F_Math_fabs *f;
+
+ f = fp;
+
+ *f->ret = fabs(f->x);
+}
+
+void
+Math_floor(void *fp)
+{
+ F_Math_floor *f;
+
+ f = fp;
+
+ *f->ret = floor(f->x);
+}
+
+void
+Math_j0(void *fp)
+{
+ F_Math_j0 *f;
+
+ f = fp;
+
+ *f->ret = __ieee754_j0(f->x);
+}
+
+void
+Math_j1(void *fp)
+{
+ F_Math_j1 *f;
+
+ f = fp;
+
+ *f->ret = __ieee754_j1(f->x);
+}
+
+void
+Math_log(void *fp)
+{
+ F_Math_log *f;
+
+ f = fp;
+
+ *f->ret = __ieee754_log(f->x);
+}
+
+void
+Math_log10(void *fp)
+{
+ F_Math_log10 *f;
+
+ f = fp;
+
+ *f->ret = __ieee754_log10(f->x);
+}
+
+void
+Math_log1p(void *fp)
+{
+ F_Math_log1p *f;
+
+ f = fp;
+
+ *f->ret = log1p(f->x);
+}
+
+void
+Math_rint(void *fp)
+{
+ F_Math_rint *f;
+
+ f = fp;
+
+ *f->ret = rint(f->x);
+}
+
+void
+Math_sin(void *fp)
+{
+ F_Math_sin *f;
+
+ f = fp;
+
+ *f->ret = sin(f->x);
+}
+
+void
+Math_sinh(void *fp)
+{
+ F_Math_sinh *f;
+
+ f = fp;
+
+ *f->ret = __ieee754_sinh(f->x);
+}
+
+void
+Math_sqrt(void *fp)
+{
+ F_Math_sqrt *f;
+
+ f = fp;
+
+ *f->ret = __ieee754_sqrt(f->x);
+}
+
+void
+Math_tan(void *fp)
+{
+ F_Math_tan *f;
+
+ f = fp;
+
+ *f->ret = tan(f->x);
+}
+
+void
+Math_tanh(void *fp)
+{
+ F_Math_tanh *f;
+
+ f = fp;
+
+ *f->ret = tanh(f->x);
+}
+
+void
+Math_y0(void *fp)
+{
+ F_Math_y0 *f;
+
+ f = fp;
+
+ *f->ret = __ieee754_y0(f->x);
+}
+
+void
+Math_y1(void *fp)
+{
+ F_Math_y1 *f;
+
+ f = fp;
+
+ *f->ret = __ieee754_y1(f->x);
+}
+
+void
+Math_fdim(void *fp)
+{
+ F_Math_fdim *f;
+
+ f = fp;
+
+ *f->ret = fdim(f->x, f->y);
+}
+
+void
+Math_fmax(void *fp)
+{
+ F_Math_fmax *f;
+
+ f = fp;
+
+ *f->ret = fmax(f->x, f->y);
+}
+
+void
+Math_fmin(void *fp)
+{
+ F_Math_fmin *f;
+
+ f = fp;
+
+ *f->ret = fmin(f->x, f->y);
+}
+
+void
+Math_fmod(void *fp)
+{
+ F_Math_fmod *f;
+
+ f = fp;
+
+ *f->ret = __ieee754_fmod(f->x, f->y);
+}
+
+void
+Math_hypot(void *fp)
+{
+ F_Math_hypot *f;
+
+ f = fp;
+
+ *f->ret = __ieee754_hypot(f->x, f->y);
+}
+
+void
+Math_nextafter(void *fp)
+{
+ F_Math_nextafter *f;
+
+ f = fp;
+
+ *f->ret = nextafter(f->x, f->y);
+}
+
+void
+Math_pow(void *fp)
+{
+ F_Math_pow *f;
+
+ f = fp;
+
+ *f->ret = __ieee754_pow(f->x, f->y);
+}
+
+
+
+void
+Math_FPcontrol(void *fp)
+{
+ F_Math_FPcontrol *f;
+
+ f = fp;
+
+ *f->ret = FPcontrol(f->r, f->mask);
+}
+
+void
+Math_FPstatus(void *fp)
+{
+ F_Math_FPstatus *f;
+
+ f = fp;
+
+ *f->ret = FPstatus(f->r, f->mask);
+}
+
+void
+Math_atan2(void *fp)
+{
+ F_Math_atan2 *f;
+
+ f = fp;
+
+ *f->ret = __ieee754_atan2(f->y, f->x);
+}
+
+void
+Math_copysign(void *fp)
+{
+ F_Math_copysign *f;
+
+ f = fp;
+
+ *f->ret = copysign(f->x, f->s);
+}
+
+void
+Math_jn(void *fp)
+{
+ F_Math_jn *f;
+
+ f = fp;
+
+ *f->ret = __ieee754_jn(f->n, f->x);
+}
+
+void
+Math_lgamma(void *fp)
+{
+ F_Math_lgamma *f;
+
+ f = fp;
+
+ f->ret->t1 = __ieee754_lgamma_r(f->x, &f->ret->t0);
+}
+
+void
+Math_modf(void *fp)
+{
+ F_Math_modf *f;
+ double ipart;
+
+ f = fp;
+
+ f->ret->t1 = modf(f->x, &ipart);
+ f->ret->t0 = ipart;
+}
+
+void
+Math_pow10(void *fp)
+{
+ F_Math_pow10 *f;
+
+ f = fp;
+
+ *f->ret = ipow10(f->p);
+}
+
+void
+Math_remainder(void *fp)
+{
+ F_Math_remainder *f;
+
+ f = fp;
+
+ *f->ret = __ieee754_remainder(f->x, f->p);
+}
+
+void
+Math_scalbn(void *fp)
+{
+ F_Math_scalbn *f;
+
+ f = fp;
+
+ *f->ret = scalbn(f->x, f->n);
+}
+
+void
+Math_yn(void *fp)
+{
+ F_Math_yn *f;
+
+ f = fp;
+
+ *f->ret = __ieee754_yn(f->n, f->x);
+}
+
+
+/**** sorting real vectors through permutation vector ****/
+/* qsort from coma:/usr/jlb/qsort/qsort.dir/qsort.c on 28 Sep '92
+ char* has been changed to uchar*, static internal functions.
+ specialized to swapping ints (which are 32-bit anyway in limbo).
+ converted uchar* to int* (and substituted 1 for es).
+*/
+
+static int
+cmp(int *u, int *v, double *x)
+{
+ return ((x[*u]==x[*v])? 0 : ((x[*u]<x[*v])? -1 : 1));
+}
+
+#define swap(u, v) {int t = *(u); *(u) = *(v); *(v) = t;}
+
+#define vecswap(u, v, n) if(n>0){ \
+ int i = n; \
+ register int *pi = u; \
+ register int *pj = v; \
+ do { \
+ register int t = *pi; \
+ *pi++ = *pj; \
+ *pj++ = t; \
+ } while (--i > 0); \
+}
+
+#define minimum(x, y) ((x)<=(y) ? (x) : (y))
+
+static int *
+med3(int *a, int *b, int *c, double *x)
+{ return cmp(a, b, x) < 0 ?
+ (cmp(b, c, x) < 0 ? b : (cmp(a, c, x) < 0 ? c : a ) )
+ : (cmp(b, c, x) > 0 ? b : (cmp(a, c, x) < 0 ? a : c ) );
+}
+
+void
+rqsort(int *a, int n, double *x)
+{
+ int *pa, *pb, *pc, *pd, *pl, *pm, *pn;
+ int d, r;
+
+ if (n < 7) { /* Insertion sort on small arrays */
+ for (pm = a + 1; pm < a + n; pm++)
+ for (pl = pm; pl > a && cmp(pl-1, pl, x) > 0; pl--)
+ swap(pl, pl-1);
+ return;
+ }
+ pm = a + (n/2);
+ if (n > 7) {
+ pl = a;
+ pn = a + (n-1);
+ if (n > 40) { /* On big arrays, pseudomedian of 9 */
+ d = (n/8);
+ pl = med3(pl, pl+d, pl+2*d, x);
+ pm = med3(pm-d, pm, pm+d, x);
+ pn = med3(pn-2*d, pn-d, pn, x);
+ }
+ pm = med3(pl, pm, pn, x); /* On mid arrays, med of 3 */
+ }
+ swap(a, pm); /* On tiny arrays, partition around middle */
+ pa = pb = a + 1;
+ pc = pd = a + (n-1);
+ for (;;) {
+ while (pb <= pc && (r = cmp(pb, a, x)) <= 0) {
+ if (r == 0) { swap(pa, pb); pa++; }
+ pb++;
+ }
+ while (pb <= pc && (r = cmp(pc, a, x)) >= 0) {
+ if (r == 0) { swap(pc, pd); pd--; }
+ pc--;
+ }
+ if (pb > pc) break;
+ swap(pb, pc);
+ pb++;
+ pc--;
+ }
+ pn = a + n;
+ r = minimum(pa-a, pb-pa); vecswap(a, pb-r, r);
+ r = minimum(pd-pc, pn-pd-1); vecswap(pb, pn-r, r);
+ if ((r = pb-pa) > 1) rqsort(a, r, x);
+ if ((r = pd-pc) > 1) rqsort(pn-r, r, x);
+}
+
+void
+Math_sort(void*fp)
+{
+ F_Math_sort *f;
+ int i, pilen, xlen, *p;
+
+ f = fp;
+
+ /* check that permutation contents are in [0,n-1] !!! */
+ p = (int*) (f->pi->data);
+ pilen = f->pi->len;
+ xlen = f->x->len - 1;
+
+ for(i = 0; i < pilen; i++) {
+ if((*p < 0) || (xlen < *p))
+ error(exMathia);
+ p++;
+ }
+
+ rqsort( (int*)(f->pi->data), f->pi->len, (double*)(f->x->data));
+}
+
+
+/************ BLAS ***************/
+
+void
+Math_dot(void *fp)
+{
+ F_Math_dot *f;
+
+ f = fp;
+ if(f->x->len!=f->y->len)
+ error(exMathia); /* incompatible lengths */
+ *f->ret = dot(f->x->len, (double*)(f->x->data), (double*)(f->y->data));
+}
+
+void
+Math_iamax(void *fp)
+{
+ F_Math_iamax *f;
+
+ f = fp;
+
+ *f->ret = iamax(f->x->len, (double*)(f->x->data));
+}
+
+void
+Math_norm2(void *fp)
+{
+ F_Math_norm2 *f;
+
+ f = fp;
+
+ *f->ret = norm2(f->x->len, (double*)(f->x->data));
+}
+
+void
+Math_norm1(void *fp)
+{
+ F_Math_norm1 *f;
+
+ f = fp;
+
+ *f->ret = norm1(f->x->len, (double*)(f->x->data));
+}
+
+void
+Math_gemm(void *fp)
+{
+ F_Math_gemm *f = fp;
+ int nrowa, ncola, nrowb, ncolb, mn, ld, m, n;
+ double *adata = 0, *bdata = 0, *cdata;
+ int nota = f->transa=='N';
+ int notb = f->transb=='N';
+ if(nota){
+ nrowa = f->m;
+ ncola = f->k;
+ }else{
+ nrowa = f->k;
+ ncola = f->m;
+ }
+ if(notb){
+ nrowb = f->k;
+ ncolb = f->n;
+ }else{
+ nrowb = f->n;
+ ncolb = f->k;
+ }
+ if( (!nota && f->transa!='C' && f->transa!='T') ||
+ (!notb && f->transb!='C' && f->transb!='T') ||
+ (f->m < 0 || f->n < 0 || f->k < 0) ){
+ error(exMathia);
+ }
+ if(f->a != H){
+ mn = f->a->len;
+ adata = (double*)(f->a->data);
+ ld = f->lda;
+ if(ld<nrowa || ld*(ncola-1)>mn)
+ error(exBounds);
+ }
+ if(f->b != H){
+ mn = f->b->len;
+ ld = f->ldb;
+ bdata = (double*)(f->b->data);
+ if(ld<nrowb || ld*(ncolb-1)>mn)
+ error(exBounds);
+ }
+ m = f->m;
+ n = f->n;
+ mn = f->c->len;
+ cdata = (double*)(f->c->data);
+ ld = f->ldc;
+ if(ld<m || ld*(n-1)>mn)
+ error(exBounds);
+
+ gemm(f->transa, f->transb, f->m, f->n, f->k, f->alpha,
+ adata, f->lda, bdata, f->ldb, f->beta, cdata, f->ldc);
+}
--- /dev/null
+++ b/libinterp/mkfile
@@ -1,0 +1,129 @@
+<../mkconfig
+
+LIB=libinterp.a
+
+OFILES=\
+ alt.$O\
+ comp-$OBJTYPE.$O\
+ conv.$O\
+ crypt.$O\
+ dec.$O\
+ dlm-$TARGMODEL.$O\
+ draw.$O\
+ freetype.$O\
+ gc.$O\
+ geom.$O\
+ heap.$O\
+ heapaudit.$O\
+ ipint.$O\
+ link.$O\
+ load.$O\
+ loader.$O\
+ math.$O\
+# prefab.$O\
+ raise.$O\
+ readmod.$O\
+ runt.$O\
+ sign.$O\
+ stack.$O\
+ tk.$O\
+ validstk.$O\
+ xec.$O\
+ das-$OBJTYPE.$O\
+ keyring.$O\
+ string.$O\
+
+HFILES=\
+ $ROOT/include/interp.h\
+ $ROOT/include/isa.h\
+ runt.h\
+ tab.h\
+
+MODULES=\
+ ../module/runt.m\
+ ../module/sys.m\
+ ../module/draw.m\
+ ../module/prefab.m\
+ ../module/math.m\
+ ../module/tk.m\
+ ../module/keyring.m\
+ ../module/loader.m\
+ ../module/freetype.m\
+ ../module/ipints.m\
+ ../module/crypt.m\
+ keyringif.m\
+
+<$ROOT/mkfiles/mksyslib-$SHELLTYPE
+
+runt.h:D: $MODULES
+ rm -f $target && limbo -a -I../module ../module/runt.m > $target
+
+sysmod.h:D: $MODULES
+ rm -f $target && limbo -t Sys -I../module ../module/runt.m > $target
+
+keyring.h:D: $MODULES
+ rm -f $target && limbo -t Keyring -I../module keyringif.m > $target
+
+drawmod.h:D: $MODULES
+ rm -f $target && limbo -t Draw -I../module ../module/runt.m > $target
+
+prefabmod.h:D: $MODULES
+ rm -f $target && limbo -t Prefab -I../module ../module/runt.m > $target
+
+tkmod.h:D: $MODULES
+ rm -f $target && limbo -t Tk -I../module ../module/runt.m > $target
+
+mathmod.h:D: $MODULES
+ rm -f $target && limbo -t Math -I../module ../module/runt.m > $target
+
+loadermod.h:D: $MODULES
+ rm -f $target && limbo -t Loader -I../module ../module/runt.m > $target
+
+freetypemod.h:D: $MODULES
+ rm -f $target && limbo -t Freetype -I../module ../module/runt.m > $target
+
+ipintsmod.h:D: $MODULES
+ rm -f $target && limbo -t IPints -I../module ../module/ipints.m > $target
+
+benchmod.h:D: ../module/bench.m
+ rm -f $target && limbo -t Bench -I../module ../module/bench.m > $target
+
+cryptmod.h:D: $MODULES
+ rm -f $target && limbo -t Crypt -I../module ../module/runt.m > $target
+
+keyringif.h:D: $MODULES keyringif.m
+ rm -f $target && limbo -a -I../module keyringif.m > $target
+
+
+bench.h:D:../module/bench.m
+ rm -f $target && limbo -a -I../module ../module/bench.m > $target
+
+xec.$O: optab.h $ROOT/include/pool.h
+tk.$O: $ROOT/include/tk.h $ROOT/include/pool.h
+draw.$O: $ROOT/include/draw.h $ROOT/include/drawif.h
+prefab.$O: $ROOT/include/draw.h\
+ $ROOT/include/prefab.h
+
+runt.$O: sysmod.h
+prefab.$O: prefabmod.h
+draw.$O: drawmod.h
+tk.$O: $ROOT/include/draw.h tkmod.h
+math.$O: mathmod.h
+keyring.$O: keyring.h ipint.h keyringif.h
+crypt.$O: ipint.h runt.h cryptmod.h
+ipint.$O: ipint.h ipintsmod.h
+loader.$O: loadermod.h
+freetype.$O: freetypemod.h $ROOT/include/freetype.h
+math.$O: $ROOT/include/mathi.h
+
+das-spim.c:N: das-mips.c
+comp-spim.c:N: comp-mips.c
+
+# optab.h: $ROOT/include/isa.h mkoptab
+# $SHELLNAME mkoptab > $target
+
+# Do not remove optab.h, because the script that builds
+# it works only on UNIX and Plan 9.
+
+nuke:EV: nuke-std
+ rm -f runt.h sysmod.h drawmod.h prefabmod.h tkmod.h mathmod.h keyring.h readimagemod.h loadermod.h freetypemod.h cryptmod.h keyringif.h ipintsmod.h
--- /dev/null
+++ b/libinterp/mkoptab
@@ -1,0 +1,19 @@
+rm -f optab.h
+tr '[A-Z]' '[a-z]' <../include/isa.h >optab.h
+ed optab.h <<'HERE'
+1;/enum/c
+void (*optab[256])(void) =
+.
+/}/+1,$ d
+,s/^[ ]*i/ /g
+1;/nop/s//badop/
+1;/exit/s//i&/
+1;/goto/s//i&/
+1;/case/s//i&/
+1;/load/s//i&/
+1;/recv/s//i&/
+1;/send/s//i&/
+1;/raise/s//i&/
+w
+q
+HERE
--- /dev/null
+++ b/libinterp/optab.h
@@ -1,0 +1,179 @@
+void (*optab[256])(void) =
+{
+ badop,
+ alt,
+ nbalt,
+ igoto,
+ call,
+ frame,
+ spawn,
+ runt,
+ iload,
+ mcall,
+ mspawn,
+ mframe,
+ ret,
+ jmp,
+ icase,
+ iexit,
+ new,
+ newa,
+ newcb,
+ newcw,
+ newcf,
+ newcp,
+ newcm,
+ newcmp,
+ isend,
+ irecv,
+ consb,
+ consw,
+ consp,
+ consf,
+ consm,
+ consmp,
+ headb,
+ headw,
+ headp,
+ headf,
+ headm,
+ headmp,
+ tail,
+ lea,
+ indx,
+ movp,
+ movm,
+ movmp,
+ movb,
+ movw,
+ movf,
+ cvtbw,
+ cvtwb,
+ cvtfw,
+ cvtwf,
+ cvtca,
+ cvtac,
+ cvtwc,
+ cvtcw,
+ cvtfc,
+ cvtcf,
+ addb,
+ addw,
+ addf,
+ subb,
+ subw,
+ subf,
+ mulb,
+ mulw,
+ mulf,
+ divb,
+ divw,
+ divf,
+ modw,
+ modb,
+ andb,
+ andw,
+ orb,
+ orw,
+ xorb,
+ xorw,
+ shlb,
+ shlw,
+ shrb,
+ shrw,
+ insc,
+ indc,
+ addc,
+ lenc,
+ lena,
+ lenl,
+ beqb,
+ bneb,
+ bltb,
+ bleb,
+ bgtb,
+ bgeb,
+ beqw,
+ bnew,
+ bltw,
+ blew,
+ bgtw,
+ bgew,
+ beqf,
+ bnef,
+ bltf,
+ blef,
+ bgtf,
+ bgef,
+ beqc,
+ bnec,
+ bltc,
+ blec,
+ bgtc,
+ bgec,
+ slicea,
+ slicela,
+ slicec,
+ indw,
+ indf,
+ indb,
+ negf,
+ movl,
+ addl,
+ subl,
+ divl,
+ modl,
+ mull,
+ andl,
+ orl,
+ xorl,
+ shll,
+ shrl,
+ bnel,
+ bltl,
+ blel,
+ bgtl,
+ bgel,
+ beql,
+ cvtlf,
+ cvtfl,
+ cvtlw,
+ cvtwl,
+ cvtlc,
+ cvtcl,
+ headl,
+ consl,
+ newcl,
+ casec,
+ indl,
+ movpc,
+ tcmp,
+ mnewz,
+ cvtrf,
+ cvtfr,
+ cvtws,
+ cvtsw,
+ lsrw,
+ lsrl,
+ eclr, /* unused */
+ newz,
+ newaz,
+ iraise,
+ casel,
+ mulx,
+ divx,
+ cvtxx,
+ mulx0,
+ divx0,
+ cvtxx0,
+ mulx1,
+ divx1,
+ cvtxx1,
+ cvtfx,
+ cvtxf,
+ iexpw,
+ iexpl,
+ iexpf,
+ self,
+ /* fix maxdis if you add opcodes */
+};
--- /dev/null
+++ b/libinterp/prefab.c
@@ -1,0 +1,824 @@
+#include <lib9.h>
+#include <kernel.h>
+#include "interp.h"
+#include "isa.h"
+#include "runt.h"
+#include "prefabmod.h"
+#include "draw.h"
+#include "drawif.h"
+#include "prefab.h"
+#include "raise.h"
+
+uchar elementmap[] = Prefab_Element_map;
+uchar compoundmap[] = Prefab_Compound_map;
+uchar layoutmap[] = Prefab_Layout_map;
+
+void freeprefabcompound(Heap*, int);
+
+Type* TCompound;
+Type* TElement;
+Type* TLayout;
+
+/* Infrared remote buttons known to Compound_select */
+enum
+{
+ IRFF = 14,
+ IRRew = 15,
+ IRUp = 16,
+ IRDn = 17,
+ IRSelect = 18,
+ IREnter = 20,
+};
+
+void
+prefabmodinit(void)
+{
+ TElement = dtype(freeheap, sizeof(PElement), elementmap, sizeof(elementmap));
+ TLayout = dtype(freeheap, Prefab_Layout_size, layoutmap, sizeof(layoutmap));
+ TCompound = dtype(freeprefabcompound, sizeof(PCompound), compoundmap, sizeof(compoundmap));
+ builtinmod("$Prefab", Prefabmodtab, Prefabmodlen);
+}
+
+PElement*
+checkelement(Prefab_Element *de)
+{
+ PElement *pe;
+
+ pe = lookupelement(de);
+ if(pe == H)
+ error(exType);
+ return pe;
+}
+
+PCompound*
+checkcompound(Prefab_Compound *de)
+{
+ PCompound *pe;
+
+ pe = lookupcompound(de);
+ if(pe == H)
+ error(exType);
+ return pe;
+}
+
+PElement*
+lookupelement(Prefab_Element *de)
+{
+ PElement *pe;
+ if(de == H)
+ return H;
+ if(D2H(de)->t != TElement)
+ return H;
+ pe = (PElement*)de;
+ if(de->kind!=pe->pkind || de->kids!=pe->first)
+ return H;
+ return pe;
+}
+
+PCompound*
+lookupcompound(Prefab_Compound *dc)
+{
+ if(dc == H)
+ return H;
+ if(D2H(dc)->t != TCompound)
+ return H;
+ return (PCompound*)dc;
+}
+
+void
+freeprefabcompound(Heap *h, int swept)
+{
+ Image *i;
+ Prefab_Compound *d;
+ PCompound *pc;
+
+ d = H2D(Prefab_Compound*, h);
+ pc = lookupcompound(d);
+ /* disconnect compound from image refresh daemon */
+ i = lookupimage(pc->c.image);
+ if(i != nil)
+ delrefresh(i);
+ if(!swept && TCompound->np)
+ freeptrs(d, TCompound);
+ /* header will be freed by caller */
+}
+
+static
+PElement*
+findtag(PElement *pelem, char *tag)
+{
+ PElement *pe, *t;
+ List *l;
+
+ if(pelem==H || tag[0]==0)
+ return pelem;
+ for(l=pelem->first; l!=H; l=l->tail){
+ pe = *(PElement**)l->data;
+ if(strcmp(tag, string2c(pe->e.tag)) == 0)
+ return pe;
+ else if(pe->pkind==EHorizontal || pe->pkind==EVertical){
+ t = findtag(pe, tag);
+ if(t != H)
+ return t;
+ }
+ }
+ return H;
+}
+
+int
+badenviron(Prefab_Environ *env, int err)
+{
+ Prefab_Style *s;
+
+ if(env == H)
+ goto bad;
+ s = env->style;
+ if(s == H)
+ goto bad;
+ if(s->titlefont==H || s->textfont==H)
+ goto bad;
+ if(s->elemcolor==H || s->edgecolor==H)
+ goto bad;
+ if(s->titlecolor==H || s->textcolor==H || s->highlightcolor==H)
+ goto bad;
+ return 0;
+bad:
+ if(err)
+ error(exType);
+ return 1;
+}
+
+void
+Element_iconseparator(void *fp, int kind)
+{
+ F_Element_icon *f;
+ PElement *e;
+ Image *icon;
+ int locked;
+
+ f = fp;
+ badenviron(f->env, 1);
+ checkimage(f->mask);
+ icon = checkimage(f->icon);
+ locked = lockdisplay(icon->display);
+ destroy(*f->ret);
+ *f->ret = H;
+ if(kind == ESeparator)
+ e = separatorelement(f->env, f->r, f->icon, f->mask);
+ else
+ e = iconelement(f->env, f->r, f->icon, f->mask);
+ *f->ret = (Prefab_Element*)e;
+ if(locked)
+ unlockdisplay(icon->display);
+}
+
+void
+Element_icon(void *fp)
+{
+ Element_iconseparator(fp, EIcon);
+}
+
+void
+Element_separator(void *fp)
+{
+ Element_iconseparator(fp, ESeparator);
+}
+
+void
+Element_text(void *fp)
+{
+ F_Element_text *f;
+ PElement *pelem;
+ Display *disp;
+ int locked;
+
+ f = fp;
+ badenviron(f->env, 1);
+ if(f->kind!=EText && f->kind!=ETitle)
+ return;
+
+ disp = checkscreen(f->env->screen)->display;
+ locked = lockdisplay(disp);
+ destroy(*f->ret);
+ *f->ret = H;
+ pelem = textelement(f->env, f->text, f->r, f->kind);
+ *f->ret = (Prefab_Element*)pelem;
+ if(locked)
+ unlockdisplay(disp);
+}
+
+void
+Element_layout(void *fp)
+{
+ F_Element_layout *f;
+ PElement *pelem;
+ Display *disp;
+ int locked;
+
+ f = fp;
+ badenviron(f->env, 1);
+ if(f->kind!=EText && f->kind!=ETitle)
+ return;
+
+ disp = checkscreen(f->env->screen)->display;
+ locked = lockdisplay(disp);
+ destroy(*f->ret);
+ *f->ret = H;
+ pelem = layoutelement(f->env, f->lay, f->r, f->kind);
+ *f->ret = (Prefab_Element*)pelem;
+ if(locked)
+ unlockdisplay(disp);
+}
+
+void
+Element_elist(void *fp)
+{
+ F_Element_elist *f;
+ PElement *pelist;
+ Display *disp;
+ int locked;
+
+ f = fp;
+ if(f->elem != H)
+ checkelement(f->elem);
+ badenviron(f->env, 1);
+ if(f->kind!=EHorizontal && f->kind!=EVertical)
+ return;
+
+ disp = checkscreen(f->env->screen)->display;
+ locked = lockdisplay(disp);
+ destroy(*f->ret);
+ *f->ret = H;
+ pelist = elistelement(f->env, f->elem, f->kind);
+ *f->ret = (Prefab_Element*)pelist;
+ if(locked)
+ unlockdisplay(disp);
+}
+
+void
+Element_append(void *fp)
+{
+ F_Element_append *f;
+
+ f = fp;
+ *f->ret = 0;
+ if(f->elist==H || f->elem==H)
+ return;
+
+ badenviron(f->elist->environ, 1);
+ checkelement(f->elist);
+ checkelement(f->elem);
+
+ if(f->elist->kind!=EHorizontal && f->elist->kind!=EVertical)
+ return;
+
+ if(appendelist(f->elist, f->elem) != H)
+ *f->ret = 1;
+}
+
+void
+Element_adjust(void *fp)
+{
+ F_Element_adjust *f;
+ Display *disp;
+ int locked;
+
+ f = fp;
+ checkelement(f->elem);
+ badenviron(f->elem->environ, 1);
+ disp = checkscreen(f->elem->environ->screen)->display;
+ locked = lockdisplay(disp);
+ adjustelement(f->elem, f->equal, f->dir);
+ if(locked)
+ unlockdisplay(disp);
+}
+
+void
+Element_show(void *fp)
+{
+ F_Element_show *f;
+ Display *disp;
+ int locked;
+
+ f = fp;
+ checkelement(f->elem);
+ checkelement(f->elist);
+ badenviron(f->elem->environ, 1);
+ disp = checkscreen(f->elem->environ->screen)->display;
+ locked = lockdisplay(disp);
+ *f->ret = showelement(f->elist, f->elem);
+ if(locked)
+ unlockdisplay(disp);
+}
+
+void
+Element_clip(void *fp)
+{
+ F_Element_clip *f;
+ Rectangle r;
+ Display *disp;
+ int locked;
+
+ f = fp;
+ checkelement(f->elem);
+ badenviron(f->elem->environ, 1);
+ R2R(r, f->r);
+ disp = checkscreen(f->elem->environ->screen)->display;
+ locked = lockdisplay(disp);
+ clipelement(f->elem, r);
+ if(locked)
+ unlockdisplay(disp);
+}
+
+void
+Element_translatescroll(void *fp, int trans)
+{
+ F_Element_scroll *f;
+ Point d;
+ Display *disp;
+ int locked, moved;
+
+ f = fp;
+ checkelement(f->elem);
+ badenviron(f->elem->environ, 1);
+ P2P(d, f->d);
+ disp = checkscreen(f->elem->environ->screen)->display;
+ locked = lockdisplay(disp);
+ if(trans)
+ translateelement(f->elem, d);
+ else{
+ moved = 0;
+ scrollelement(f->elem, d, &moved);
+ }
+ if(locked)
+ unlockdisplay(disp);
+}
+
+void
+Element_scroll(void *fp)
+{
+ Element_translatescroll(fp, 0);
+}
+
+void
+Element_translate(void *fp)
+{
+ Element_translatescroll(fp, 1);
+}
+
+void
+Compound_iconbox(void *fp)
+{
+ F_Compound_iconbox *f;
+ Image *icon;
+ int locked;
+ PCompound *pc;
+
+ f = fp;
+ badenviron(f->env, 1);
+ checkimage(f->mask);
+ icon = checkimage(f->icon);
+ locked = lockdisplay(icon->display);
+ destroy(*f->ret);
+ *f->ret = H;
+ pc = iconbox(f->env, f->p, f->title, f->icon, f->mask);
+ *f->ret = &pc->c;
+ if(locked)
+ unlockdisplay(icon->display);
+}
+
+void
+Compound_textbox(void *fp)
+{
+ F_Compound_textbox *f;
+ Display *disp;
+ int locked;
+ PCompound *pc;
+
+ f = fp;
+ badenviron(f->env, 1);
+ disp = checkscreen(f->env->screen)->display;
+ locked = lockdisplay(disp);
+ destroy(*f->ret);
+ *f->ret = H;
+ pc = textbox(f->env, f->r, f->title, f->text);
+ *f->ret = &pc->c;
+ if(locked)
+ unlockdisplay(disp);
+}
+
+void
+Compound_layoutbox(void *fp)
+{
+ F_Compound_layoutbox *f;
+ Display *disp;
+ int locked;
+ PCompound *pc;
+
+ f = fp;
+ badenviron(f->env, 1);
+ disp = checkscreen(f->env->screen)->display;
+ locked = lockdisplay(disp);
+ destroy(*f->ret);
+ *f->ret = H;
+ pc = layoutbox(f->env, f->r, f->title, f->lay);
+ *f->ret = &pc->c;
+ if(locked)
+ unlockdisplay(disp);
+}
+
+void
+Compound_box(void *fp)
+{
+ F_Compound_box *f;
+ Display *disp;
+ int locked;
+ PCompound *pc;
+
+ f = fp;
+ badenviron(f->env, 1);
+ if(f->title != H)
+ checkelement(f->title);
+ checkelement(f->elist);
+ disp = checkscreen(f->env->screen)->display;
+ locked = lockdisplay(disp);
+ destroy(*f->ret);
+ *f->ret = H;
+ pc = box(f->env, f->p, f->title, f->elist);
+ *f->ret = &pc->c;
+ if(locked)
+ unlockdisplay(disp);
+}
+
+void
+Compound_draw(void *fp)
+{
+ F_Compound_draw *f;
+ PCompound *pc;
+ int locked;
+
+ f = fp;
+ if(f->comp == H)
+ return;
+ pc = checkcompound(f->comp);
+ badenviron(pc->c.environ, 1);
+ locked = lockdisplay(pc->display);
+ drawcompound(&pc->c);
+ flushimage(pc->display, 1);
+ if(locked)
+ unlockdisplay(pc->display);
+}
+
+void
+Compound_redraw(void *fp)
+{
+ F_Compound_redraw *f;
+ PCompound *pc;
+ Image *i;
+ int locked;
+
+ f = fp;
+ if(f->comp == H)
+ return;
+ pc = checkcompound(f->comp);
+ badenviron(pc->c.environ, 1);
+ i = checkimage(pc->c.image);
+ locked = lockdisplay(pc->display);
+ redrawcompound(i, IRECT(f->r), &pc->c);
+ flushimage(pc->display, 1);
+ if(locked)
+ unlockdisplay(pc->display);
+}
+
+static
+PElement*
+pelement(Prefab_Compound *comp, Prefab_Element *elem)
+{
+ PElement *pe;
+
+ if(comp == H)
+ return H;
+ checkcompound(comp);
+ badenviron(comp->environ, 1);
+ pe = lookupelement(elem);
+ return pe;
+}
+
+void
+Compound_highlight(void *fp)
+{
+ F_Compound_highlight *f;
+ PCompound *pc;
+ PElement *pe;
+ Image *i;
+ int locked;
+
+ f = fp;
+ pe = pelement(f->comp, f->elem);
+ if(pe == H)
+ return;
+ pc = (PCompound*)f->comp;
+ i = checkimage(pc->c.image);
+ locked = lockdisplay(pc->display);
+ highlightelement(&pe->e, i, &pc->c, f->on);
+ flushimage(pc->display, 1);
+ if(locked)
+ unlockdisplay(pc->display);
+}
+
+void
+Compound_scroll(void *fp)
+{
+ F_Compound_scroll *f;
+ PCompound *pc;
+ PElement *pe;
+ int locked;
+ Image *i;
+ int moved;
+
+ f = fp;
+ pe = pelement(f->comp, f->elem);
+ if(pe == H)
+ return;
+ pc = (PCompound*)f->comp;
+ i = checkimage(pc->c.image);
+ locked = lockdisplay(pc->display);
+ moved = 0;
+ scrollelement(&pe->e, IPOINT(f->d), &moved);
+ if(moved){
+ drawelement(&pe->e, i, IRECT(pe->e.r), 0, 0);
+ flushimage(pc->display, 1);
+ }
+ if(locked)
+ unlockdisplay(pc->display);
+}
+
+void
+Compound_show(void *fp)
+{
+ F_Compound_show *f;
+ PCompound *pc;
+ PElement *pe;
+ int locked;
+
+ f = fp;
+ pe = pelement(f->comp, f->elem);
+ if(pe == H)
+ return;
+ pc = (PCompound*)f->comp;
+ locked = lockdisplay(pc->display);
+ *f->ret = showelement(pc->c.contents, &pe->e);
+ flushimage(pc->display, 1);
+ if(locked)
+ unlockdisplay(pc->display);
+}
+
+static
+PElement*
+element(PElement *plist, int index, int *ip)
+{
+ int i;
+ PElement *pe;
+ List *l;
+
+ i = 0;
+ pe = H;
+ for(l=plist->first; l!=H; l=l->tail){
+ pe = *(PElement**)l->data;
+ if(pe->pkind == ESeparator)
+ continue;
+ if(i == index)
+ break;
+ i++;
+ }
+ if(ip)
+ *ip = i;
+ if(l == H)
+ return H;
+ return pe;
+}
+
+static
+int
+wrapelement(PElement *plist, int index, int ntag)
+{
+ int i, wrap;
+
+ if(ntag > 0){
+ if(index < 0)
+ return ntag-1;
+ if(index >= ntag)
+ return 0;
+ return index;
+ }
+ wrap = 1;
+ if(index < 0){
+ index = 1000000; /* will seek to end */
+ wrap = 0;
+ }
+ if(element(plist, index, &i)==H && index!=0){
+ if(wrap) /* went off end; wrap to beginning */
+ return wrapelement(plist, 0, 0);
+ if(i > 0)
+ --i;
+ }
+ return i;
+}
+
+void
+dohighlight(PCompound *pc, PElement *list, PElement *pe, int on)
+{
+ Image *i;
+
+ /* see if we need to scroll */
+ i = lookupimage(pc->c.image);
+ if(i == nil)
+ return;
+ if(on && showelement(&list->e, &pe->e))
+ redrawcompound(i, IRECT(pc->c.contents->r), &pc->c);
+ highlightelement(&pe->e, i, &pc->c, on);
+}
+
+void
+highlight(PCompound *pc, PElement *list, int index, int on)
+{
+ dohighlight(pc, list, element(list, index, nil), on);
+}
+
+static
+PElement**
+tags(PElement *pelem, int *ntag)
+{
+ int n, nalloc, nn;
+ List *l;
+ PElement *pe, **tagged, **ntagged;
+
+ n = 0;
+ nalloc = 0;
+ tagged = nil;
+ *ntag = 0;
+ for(l=pelem->first; l!=H; l=l->tail){
+ pe = *(PElement**)l->data;
+ if(pe->e.tag != H){
+ if(nalloc == n){
+ nalloc += 10;
+ tagged = realloc(tagged, nalloc*sizeof(PElement*));
+ if(tagged == nil)
+ return nil;
+ }
+ tagged[n++] = pe;
+ }else if(pe->pkind==EHorizontal || pe->pkind==EVertical){
+ ntagged = tags(pe, &nn);
+ if(nn > 0){
+ if(nalloc < n+nn){
+ nalloc = n+nn+10;
+ tagged = realloc(tagged, nalloc*sizeof(PElement*));
+ if(tagged == nil){
+ free(ntagged);
+ return nil;
+ }
+ }
+ memmove(tagged+n, ntagged, nn*sizeof(PElement*));
+ free(ntagged);
+ n += nn;
+ }
+ }
+ }
+ *ntag = n;
+ return tagged;
+}
+
+void
+doselect(void *fp, int dotags)
+{
+ F_Compound_select *f;
+ PCompound *pc;
+ PElement *pe;
+ WORD *val;
+ List *l;
+ Prefab_Element *t;
+ int i, lasti, ntag;
+ PElement **tagged;
+ int locked;
+
+ f = fp;
+ pc = checkcompound(f->comp);
+ pe = lookupelement(f->elem);
+ if(pe->pkind!=EHorizontal && pe->pkind!=EVertical || pe->nkids == 0){
+ Bad:
+ destroy(f->ret->t2);
+ f->ret->t0 = 9999;
+ f->ret->t1 = 0;
+ f->ret->t2 = H;
+ return;
+ }
+ ntag = 0;
+ tagged = 0;
+ /* check at least one selectable item */
+ if(dotags){
+ tagged = tags(pe, &ntag);
+ if(ntag > 0)
+ goto OK;
+ }else
+ for(l=pe->first; l!=H; l=l->tail){
+ t = *(Prefab_Element**)l->data;
+ if(t->kind != ESeparator)
+ goto OK;
+ }
+ goto Bad;
+
+ OK:
+ i = f->i;
+ i = wrapelement(pe, i, ntag);
+ lasti = i;
+ locked = lockdisplay(pc->display);
+ if(dotags)
+ dohighlight(pc, pe, tagged[i], 1);
+ else
+ highlight(pc, pe, i, 1);
+ /* val must be in shared memory, but stacks not shared */
+ val = malloc(sizeof(WORD));
+ if(val == nil)
+ goto Bad;
+ for(;;){
+ if(lasti != i){
+ if(dotags){
+ dohighlight(pc, pe, tagged[lasti], 0);
+ dohighlight(pc, pe, tagged[i], 1);
+ }else{
+ highlight(pc, pe, lasti, 0);
+ highlight(pc, pe, i, 1);
+ }
+ lasti = i;
+ }
+ flushimage(pc->display, 1);
+ if(locked)
+ unlockdisplay(pc->display);
+ crecv(f->c, val);
+ locked = lockdisplay(pc->display);
+ switch(*val){
+ case IRUp:
+ if(pe->pkind != EVertical)
+ goto Default;
+ goto Up;
+ case IRRew:
+ if(pe->pkind != EHorizontal)
+ goto Default;
+ Up:
+ i = wrapelement(pe, i-1, ntag);
+ break;
+ case IRSelect:
+ if(dotags)
+ dohighlight(pc, pe, tagged[i], 0);
+ else
+ highlight(pc, pe, i, 0);
+ f->ret->t0 = *val;
+ f->ret->t1 = i;
+ Return:
+ flushimage(pc->display, 1);
+ if(dotags)
+ pe = tagged[i];
+ else
+ pe = element(pe, i, nil);
+ destroy(f->ret->t2);
+ D2H(pe)->ref++;
+ f->ret->t2 = &pe->e;
+ if(locked)
+ unlockdisplay(pc->display);
+ free(val);
+ free(tagged);
+ return;
+ case IRDn:
+ if(pe->pkind != EVertical)
+ goto Default;
+ goto Down;
+ case IRFF:
+ if(pe->pkind != EHorizontal)
+ goto Default;
+ Down:
+ i = wrapelement(pe, i+1, ntag);
+ break;
+ default:
+ Default:
+ if(dotags)
+ dohighlight(pc, pe, tagged[lasti], 0);
+ else
+ highlight(pc, pe, lasti, 0);
+ f->ret->t0 = *val;
+ f->ret->t1 = i;
+ goto Return;
+ }
+ }
+}
+
+void
+Compound_tagselect(void *fp)
+{
+ doselect(fp, 1);
+}
+
+void
+Compound_select(void *fp)
+{
+ doselect(fp, 0);
+}
--- /dev/null
+++ b/libinterp/raise.c
@@ -1,0 +1,25 @@
+/*
+ * Exceptions thrown by the interpreter
+ */
+char exAlt[] = "alt send/recv on same chan";
+char exBusy[] = "channel busy";
+char exModule[] = "module not loaded";
+char exCompile[] = "compile failed";
+char exCrange[] = "constant range ";
+char exCctovflw[] = "constant table overflow";
+char exCphase[] = "compiler phase error";
+char exType[] = "type not constructed correctly";
+char exZdiv[] = "zero divide";
+char exHeap[] = "out of memory: heap";
+char exImage[] = "out of memory: image";
+char exItype[] = "inconsistent type";
+char exMathia[] = "invalid math argument";
+char exBounds[] = "array bounds error";
+char exNegsize[] = "negative array size";
+char exNomem[] = "out of memory: main";
+char exSpawn[] = "spawn a builtin module";
+char exOp[] = "illegal dis instruction";
+char exTcheck[] = "type check";
+char exInval[] = "invalid argument";
+char exNilref[] = "dereference of nil";
+char exRange[] = "value out of range";
--- /dev/null
+++ b/libinterp/readmod.c
@@ -1,0 +1,84 @@
+#include "lib9.h"
+#include "isa.h"
+#include "interp.h"
+#include "kernel.h"
+#include "dynld.h"
+
+Module*
+readmod(char *path, Module *m, int sync)
+{
+ Dir *d;
+ int fd, n, dynld;
+ uchar *code;
+ Module *ans;
+ ulong length;
+
+ if(path[0] == '$') {
+ if(m == nil)
+ kwerrstr("module not built-in");
+ return m;
+ }
+
+ ans = nil;
+ code = nil;
+ length = 0;
+ dynld = 0;
+
+ if(sync)
+ release();
+
+ d = nil;
+ fd = kopen(path, OREAD);
+ if(fd < 0)
+ goto done;
+
+ if((d = kdirfstat(fd)) == nil)
+ goto done;
+
+ if(m != nil) {
+ if(d->dev == m->dev && d->type == m->dtype &&
+ d->mtime == m->mtime &&
+ d->qid.type == m->qid.type && d->qid.path == m->qid.path && d->qid.vers == m->qid.vers) {
+ ans = m;
+ goto done;
+ }
+ }
+
+ if(d->length < 0 || d->length >= 8*1024*1024){
+ kwerrstr("implausible length");
+ goto done;
+ }
+ if((d->mode&0111) && dynldable(fd)){
+ dynld = 1;
+ goto done1;
+ }
+ length = d->length;
+ code = mallocz(length, 0);
+ if(code == nil)
+ goto done;
+
+ n = kread(fd, code, length);
+ if(n != length) {
+ free(code);
+ code = nil;
+ }
+done:
+ if(fd >= 0)
+ kclose(fd);
+done1:
+ if(sync)
+ acquire();
+ if(m != nil && ans == nil)
+ unload(m);
+ if(code != nil) {
+ ans = parsemod(path, code, length, d);
+ free(code);
+ }
+ else if(dynld){
+ kseek(fd, 0, 0);
+ ans = newdyncode(fd, path, d);
+ kclose(fd);
+ }
+ free(d);
+ return ans;
+}
--- /dev/null
+++ b/libinterp/runt.c
@@ -1,0 +1,496 @@
+#include "lib9.h"
+#include "isa.h"
+#include "interp.h"
+#include "runt.h"
+#include "sysmod.h"
+#include "raise.h"
+
+
+static int utfnleng(char*, int, int*);
+
+void
+sysmodinit(void)
+{
+ sysinit();
+ builtinmod("$Sys", Sysmodtab, Sysmodlen);
+}
+
+int
+xprint(Prog *xp, void *vfp, void *vva, String *s1, char *buf, int n)
+{
+ WORD i;
+ void *p;
+ LONG bg;
+ Type *t;
+ double d;
+ String *ss;
+ ulong *ptr;
+ uchar *fp, *va;
+ int nc, c, isbig, isr, sip;
+ char *b, *eb, *f, fmt[32];
+ Rune r;
+
+ fp = vfp;
+ va = vva;
+
+ sip = 0;
+ isr = 0;
+ if(s1 == H)
+ return 0;
+ nc = s1->len;
+ if(nc < 0) {
+ nc = -nc;
+ isr = 1;
+ }
+
+ b = buf;
+ eb = buf+n-1;
+ while(nc--) {
+ c = isr ? s1->Srune[sip] : s1->Sascii[sip];
+ sip++;
+ if(c != '%') {
+ if(b < eb) {
+ if(c < Runeself)
+ *b++ = c;
+ else
+ b += snprint(b, eb-b, "%C", c);
+ }
+ continue;
+ }
+ f = fmt;
+ *f++ = c;
+ isbig = 0;
+ while(nc--) {
+ c = isr ? s1->Srune[sip] : s1->Sascii[sip];
+ sip++;
+ *f++ = c;
+ *f = '\0';
+ switch(c) {
+ default:
+ continue;
+ case '*':
+ i = *(WORD*)va;
+ f--;
+ f += snprint(f, sizeof(fmt)-(f-fmt), "%d", i);
+ va += IBY2WD;
+ continue;
+ case 'b':
+ f[-1] = 'l';
+ *f++ = 'l';
+ *f = '\0';
+ isbig = 1;
+ continue;
+ case '%':
+ if(b < eb)
+ *b++ = '%';
+ break;
+ case 'q':
+ case 's':
+ ss = *(String**)va;
+ va += IBY2WD;
+ if(ss == H)
+ p = "";
+ else
+ if(ss->len < 0) {
+ f[-1] += 'A'-'a';
+ ss->Srune[-ss->len] = L'\0';
+ p = ss->Srune;
+ }
+ else {
+ ss->Sascii[ss->len] = '\0';
+ p = ss->Sascii;
+ }
+ b += snprint(b, eb-b, fmt, p);
+ break;
+ case 'E':
+ f--;
+ r = 0x00c9; /* L'É' */
+ f += runetochar(f, &r); /* avoid clash with ether address */
+ *f = '\0';
+ /* fall through */
+ case 'e':
+ case 'f':
+ case 'g':
+ case 'G':
+ while((va - fp) & (sizeof(REAL)-1))
+ va++;
+ d = *(REAL*)va;
+ b += snprint(b, eb-b, fmt, d);
+ va += sizeof(REAL);
+ break;
+ case 'd':
+ case 'o':
+ case 'x':
+ case 'X':
+ case 'c':
+ if(isbig) {
+ while((va - fp) & (IBY2LG-1))
+ va++;
+ bg = *(LONG*)va;
+ b += snprint(b, eb-b, fmt, bg);
+ va += IBY2LG;
+ }
+ else {
+ i = *(WORD*)va;
+ /* always a unicode character */
+ if(c == 'c')
+ f[-1] = 'C';
+ b += snprint(b, eb-b, fmt, i);
+ va += IBY2WD;
+ }
+ break;
+ case 'r':
+ b = syserr(b, eb, xp);
+ break;
+/* Debugging formats - may disappear */
+ case 'H':
+ ptr = *(ulong**)va;
+ c = -1;
+ t = nil;
+ if(ptr != H) {
+ c = D2H(ptr)->ref;
+ t = D2H(ptr)->t;
+ }
+ b += snprint(b, eb-b, "%d.%.8lux", c, (ulong)t);
+ va += IBY2WD;
+ break;
+ }
+ break;
+ }
+ }
+ return b - buf;
+}
+
+int
+bigxprint(Prog *xp, void *vfp, void *vva, String *s1, char **buf, int s)
+{
+ char *b;
+ int m, n;
+
+ m = s;
+ for (;;) {
+ m *= 2;
+ b = malloc(m);
+ if (b == nil)
+ error(exNomem);
+ n = xprint(xp, vfp, vva, s1, b, m);
+ if (n < m-UTFmax-2)
+ break;
+ free(b);
+ }
+ *buf = b;
+ return n;
+}
+
+void
+Sys_sprint(void *fp)
+{
+ int n;
+ char buf[256], *b = buf;
+ F_Sys_sprint *f;
+
+ f = fp;
+ n = xprint(currun(), f, &f->vargs, f->s, buf, sizeof(buf));
+ if (n >= sizeof(buf)-UTFmax-2)
+ n = bigxprint(currun(), f, &f->vargs, f->s, &b, sizeof(buf));
+ b[n] = '\0';
+ retstr(b, f->ret);
+ if (b != buf)
+ free(b);
+}
+
+void
+Sys_aprint(void *fp)
+{
+ int n;
+ char buf[256], *b = buf;
+ F_Sys_aprint *f;
+
+ f = fp;
+ n = xprint(currun(), f, &f->vargs, f->s, buf, sizeof(buf));
+ if (n >= sizeof(buf)-UTFmax-2)
+ n = bigxprint(currun(), f, &f->vargs, f->s, &b, sizeof(buf));
+ destroy(*f->ret);
+ *f->ret = mem2array(b, n);
+ if (b != buf)
+ free(b);
+}
+
+static int
+tokdelim(int c, String *d)
+{
+ int l;
+ char *p;
+ Rune *r;
+
+ l = d->len;
+ if(l < 0) {
+ l = -l;
+ for(r = d->Srune; l != 0; l--)
+ if(*r++ == c)
+ return 1;
+ return 0;
+ }
+ for(p = d->Sascii; l != 0; l--)
+ if(*p++ == c)
+ return 1;
+ return 0;
+}
+
+void
+Sys_tokenize(void *fp)
+{
+ String *s, *d;
+ List **h, *l, *nl;
+ F_Sys_tokenize *f;
+ int n, c, nc, first, last, srune;
+
+ f = fp;
+ s = f->s;
+ d = f->delim;
+
+ if(s == H || d == H) {
+ f->ret->t0 = 0;
+ destroy(f->ret->t1);
+ f->ret->t1 = H;
+ return;
+ }
+
+ n = 0;
+ l = H;
+ h = &l;
+ first = 0;
+ srune = 0;
+
+ nc = s->len;
+ if(nc < 0) {
+ nc = -nc;
+ srune = 1;
+ }
+
+ while(first < nc) {
+ while(first < nc) {
+ c = srune ? s->Srune[first] : s->Sascii[first];
+ if(tokdelim(c, d) == 0)
+ break;
+ first++;
+ }
+
+ last = first;
+
+ while(last < nc) {
+ c = srune ? s->Srune[last] : s->Sascii[last];
+ if(tokdelim(c, d) != 0)
+ break;
+ last++;
+ }
+
+ if(first == last)
+ break;
+
+ nl = cons(IBY2WD, h);
+ nl->tail = H;
+ nl->t = &Tptr;
+ Tptr.ref++;
+ *(String**)nl->data = slicer(first, last, s);
+ h = &nl->tail;
+
+ first = last;
+ n++;
+ }
+
+ f->ret->t0 = n;
+ destroy(f->ret->t1);
+ f->ret->t1 = l;
+}
+
+void
+Sys_utfbytes(void *fp)
+{
+ Array *a;
+ int nbyte;
+ F_Sys_utfbytes *f;
+
+ f = fp;
+ a = f->buf;
+ if(a == H || (UWORD)f->n > a->len)
+ error(exBounds);
+
+ utfnleng((char*)a->data, f->n, &nbyte);
+ *f->ret = nbyte;
+}
+
+void
+Sys_byte2char(void *fp)
+{
+ Rune r;
+ char *p;
+ int n, w;
+ Array *a;
+ F_Sys_byte2char *f;
+
+ f = fp;
+ a = f->buf;
+ n = f->n;
+ if(a == H || (UWORD)n >= a->len)
+ error(exBounds);
+ r = a->data[n];
+ if(r < Runeself){
+ f->ret->t0 = r;
+ f->ret->t1 = 1;
+ f->ret->t2 = 1;
+ return;
+ }
+ p = (char*)a->data+n;
+ if(n+UTFmax <= a->len || fullrune(p, a->len-n))
+ w = chartorune(&r, p);
+ else {
+ /* insufficient data */
+ f->ret->t0 = Runeerror;
+ f->ret->t1 = 0;
+ f->ret->t2 = 0;
+ return;
+ }
+ if(r == Runeerror && w==1){ /* encoding error */
+ f->ret->t0 = Runeerror;
+ f->ret->t1 = 1;
+ f->ret->t2 = 0;
+ return;
+ }
+ f->ret->t0 = r;
+ f->ret->t1 = w;
+ f->ret->t2 = 1;
+}
+
+void
+Sys_char2byte(void *fp)
+{
+ F_Sys_char2byte *f;
+ Array *a;
+ int n, c;
+ Rune r;
+
+ f = fp;
+ a = f->buf;
+ n = f->n;
+ c = f->c;
+ if(a == H || (UWORD)n>=a->len)
+ error(exBounds);
+ if(c<0 || c>=Runemax)
+ c = Runeerror;
+ if(c < Runeself){
+ a->data[n] = c;
+ *f->ret = 1;
+ return;
+ }
+ r = c;
+ if(n+UTFmax<=a->len || runelen(c)<=a->len-n){
+ *f->ret = runetochar((char*)a->data+n, &r);
+ return;
+ }
+ *f->ret = 0;
+}
+
+Module *
+builtinmod(char *name, void *vr, int rlen)
+{
+ Runtab *r = vr;
+ Type *t;
+ Module *m;
+ Link *l;
+
+ m = newmod(name);
+ if(rlen == 0){
+ while(r->name){
+ rlen++;
+ r++;
+ }
+ r = vr;
+ }
+ l = m->ext = (Link*)malloc((rlen+1)*sizeof(Link));
+ if(l == nil){
+ freemod(m);
+ return nil;
+ }
+ while(r->name) {
+ t = dtype(freeheap, r->size, r->map, r->np);
+ runtime(m, l, r->name, r->sig, r->fn, t);
+ r++;
+ l++;
+ }
+ l->name = nil;
+ return m;
+}
+
+void
+retnstr(char *s, int n, String **d)
+{
+ String *s1;
+
+ s1 = H;
+ if(n != 0)
+ s1 = c2string(s, n);
+ destroy(*d);
+ *d = s1;
+}
+
+void
+retstr(char *s, String **d)
+{
+ String *s1;
+
+ s1 = H;
+ if(s != nil)
+ s1 = c2string(s, strlen(s));
+ destroy(*d);
+ *d = s1;
+}
+
+Array*
+mem2array(void *va, int n)
+{
+ Heap *h;
+ Array *a;
+
+ if(n < 0)
+ n = 0;
+ h = nheap(sizeof(Array)+n);
+ h->t = &Tarray;
+ h->t->ref++;
+ a = H2D(Array*, h);
+ a->t = &Tbyte;
+ Tbyte.ref++;
+ a->len = n;
+ a->root = H;
+ a->data = (uchar*)a+sizeof(Array);
+ if(va != 0)
+ memmove(a->data, va, n);
+
+ return a;
+}
+
+static int
+utfnleng(char *s, int nb, int *ngood)
+{
+ int c;
+ long n;
+ Rune rune;
+ char *es, *starts;
+
+ starts = s;
+ es = s+nb;
+ for(n = 0; s < es; n++) {
+ c = *(uchar*)s;
+ if(c < Runeself)
+ s++;
+ else {
+ if(s+UTFmax<=es || fullrune(s, es-s))
+ s += chartorune(&rune, s);
+ else
+ break;
+ }
+ }
+ if(ngood)
+ *ngood = s-starts;
+ return n;
+}
--- /dev/null
+++ b/libinterp/sign.c
@@ -1,0 +1,29 @@
+#include "lib9.h"
+#include "isa.h"
+#include "interp.h"
+#include <kernel.h>
+
+/*
+ * these stubs are used when devsign isn't configured
+ */
+
+int
+verifysigner(uchar *sign, int len, uchar *data, ulong ndata)
+{
+ USED(sign);
+ USED(len);
+ USED(data);
+ USED(ndata);
+
+ return 1;
+}
+
+int
+mustbesigned(char *path, uchar *code, ulong length, Dir *dir)
+{
+ USED(path);
+ USED(code);
+ USED(length);
+ USED(dir);
+ return 0;
+}
--- /dev/null
+++ b/libinterp/stack.c
@@ -1,0 +1,118 @@
+#include "lib9.h"
+#include "isa.h"
+#include "interp.h"
+#include "raise.h"
+#include <pool.h>
+
+#define T(r) *((void**)(R.r))
+
+void
+newstack(Prog *p)
+{
+ int l;
+ Type *t;
+ Frame *f;
+ Stkext *ns;
+
+ f = T(s);
+
+ t = f->t;
+ if(t == nil)
+ t = SEXTYPE(f)->reg.TR;
+
+ f->lr = nil;
+ f->mr = nil;
+ f->fp = nil;
+ l = p->R.M->m->ss;
+ /* 16 bytes for Stkext record keeping */
+ if(l < t->size+16)
+ l = t->size+16;
+ ns = mallocz(l, 0);
+ if(ns == nil)
+ error(exNomem);
+
+ ns->reg.TR = t;
+ ns->reg.SP = nil;
+ ns->reg.TS = nil;
+ ns->reg.EX = nil;
+ p->R.EX = ns->stack;
+ p->R.TS = ns->stack + l;
+ p->R.SP = ns->reg.tos.fu + t->size;
+ p->R.FP = ns->reg.tos.fu;
+
+ memmove(p->R.FP, f, t->size);
+ f = (Frame*)p->R.FP;
+ f->t = nil;
+}
+
+void
+extend(void)
+{
+ int l;
+ Type *t;
+ Frame *f;
+ Stkext *ns;
+
+ t = R.s;
+ l = R.M->m->ss;
+ /* 16 bytes for Stkext record keeping */
+ if(l < t->size+16)
+ l = 2*t->size+16;
+ ns = mallocz(l, 0);
+ if(ns == nil)
+ error(exNomem);
+
+ ns->reg.TR = t;
+ ns->reg.SP = R.SP;
+ ns->reg.TS = R.TS;
+ ns->reg.EX = R.EX;
+ f = ns->reg.tos.fr;
+ f->t = nil;
+ f->mr = nil;
+ R.s = f;
+ R.EX = ns->stack;
+ R.TS = ns->stack + l;
+ R.SP = ns->reg.tos.fu + t->size;
+
+ if (t->np)
+ initmem(t, f);
+}
+
+void
+unextend(Frame *f)
+{
+ Stkext *sx;
+ Type *t;
+
+ sx = SEXTYPE(f);
+ R.SP = sx->reg.SP;
+ R.TS = sx->reg.TS;
+ R.EX = sx->reg.EX;
+ t = sx->reg.TR;
+ if (t->np)
+ freeptrs(f, t);
+ free(sx);
+}
+
+void
+unframe(void)
+{
+ Type *t;
+ Frame *f;
+ Stkext *sx;
+
+ f = (Frame*)R.FP;
+ t = f->t;
+ if(t == nil)
+ t = SEXTYPE(f)->reg.TR;
+
+ R.SP = R.FP+t->size;
+
+ f = T(s);
+ if(f->t == nil) {
+ sx = SEXTYPE(f);
+ R.TS = sx->reg.TS;
+ R.EX = sx->reg.EX;
+ free(sx);
+ }
+}
--- /dev/null
+++ b/libinterp/string.c
@@ -1,0 +1,616 @@
+#include "lib9.h"
+#include "isa.h"
+#include "interp.h"
+#include "raise.h"
+#include "pool.h"
+
+#define OP(fn) void fn(void)
+#define B(r) *((BYTE*)(R.r))
+#define W(r) *((WORD*)(R.r))
+#define F(r) *((REAL*)(R.r))
+#define V(r) *((LONG*)(R.r))
+#define S(r) *((String**)(R.r))
+#define A(r) *((Array**)(R.r))
+#define L(r) *((List**)(R.r))
+#define P(r) *((WORD**)(R.r))
+#define C(r) *((Channel**)(R.r))
+#define T(r) *((void**)(R.r))
+
+OP(indc)
+{
+ int l;
+ ulong v;
+ String *ss;
+
+ v = W(m);
+ ss = S(s);
+
+ if(ss == H)
+ error(exNilref);
+
+ l = ss->len;
+ if(l < 0) {
+ if(v >= -l)
+e: error(exBounds);
+ l = ss->Srune[v];
+ }
+ else {
+ if(v >= l)
+ goto e;
+ l = ss->Sascii[v];
+ }
+ W(d) = l;
+}
+
+OP(insc)
+{
+ ulong v;
+ int l, r, expand;
+ String *ss, *ns, **sp;
+
+ r = W(s);
+ v = W(m);
+ ss = S(d);
+
+ expand = r >= Runeself;
+
+ if(ss == H) {
+ ss = newstring(0);
+ if(expand) {
+ l = 0;
+ ss->max /= sizeof(Rune);
+ goto r;
+ }
+ }
+ else
+ if(D2H(ss)->ref > 1 || (expand && ss->len > 0))
+ ss = splitc(R.d, expand);
+
+ l = ss->len;
+ if(l < 0 || expand) {
+ l = -l;
+r:
+ if(v < l)
+ ss->Srune[v] = r;
+ else
+ if(v == l && v < ss->max) {
+ ss->len = -(v+1);
+ ss->Srune[v] = r;
+ }
+ else {
+ if(v != l)
+ error(exBounds);
+ ns = newstring((v + 1 + v/4)*sizeof(Rune));
+ memmove(ns->Srune, ss->Srune, -ss->len*sizeof(Rune));
+ ns->Srune[v] = r;
+ ns->len = -(v+1);
+ ns->max /= sizeof(Rune);
+ ss = ns;
+ }
+ }
+ else {
+ if(v < l)
+ ss->Sascii[v] = r;
+ else
+ if(v == l && v < ss->max) {
+ ss->len = v+1;
+ ss->Sascii[v] = r;
+ }
+ else {
+ if(v != l)
+ error(exBounds);
+ ns = newstring(v + 1 + v/4);
+ memmove(ns->Sascii, ss->Sascii, l);
+ ns->Sascii[v] = r;
+ ns->len = v+1;
+ ss = ns;
+ }
+ }
+ if(ss != S(d)) {
+ sp = R.d;
+ destroy(*sp);
+ *sp = ss;
+ }
+}
+
+String*
+slicer(ulong start, ulong v, String *ds)
+{
+ String *ns;
+ int l, nc;
+
+ if(ds == H) {
+ if(start == 0 && v == 0)
+ return H;
+
+ error(exBounds);
+ }
+
+ nc = v - start;
+ if(ds->len < 0) {
+ l = -ds->len;
+ if(v < start || v > l)
+ error(exBounds);
+ if(nc == 0)
+ return H;
+ ns = newrunes(nc);
+ memmove(ns->Srune, &ds->Srune[start], nc*sizeof(Rune));
+ }
+ else {
+ l = ds->len;
+ if(v < start || v > l)
+ error(exBounds);
+ if(nc == 0)
+ return H;
+ ns = newstring(nc);
+ memmove(ns->Sascii, &ds->Sascii[start], nc);
+ }
+
+ return ns;
+}
+
+OP(slicec)
+{
+ String *ns, **sp;
+
+ ns = slicer(W(s), W(m), S(d));
+ sp = R.d;
+ destroy(*sp);
+ *sp = ns;
+}
+
+void
+cvtup(Rune *r, String *s)
+{
+ uchar *bp, *ep;
+
+ bp = (uchar*)s->Sascii;
+ ep = bp + s->len;
+ while(bp < ep)
+ *r++ = *bp++;
+}
+
+String*
+addstring(String *s1, String *s2, int append)
+{
+ Rune *r;
+ String *ns;
+ int l, l1, l2;
+
+ if(s1 == H) {
+ if(s2 == H)
+ return H;
+ return stringdup(s2);
+ }
+ if(D2H(s1)->ref > 1)
+ append = 0;
+ if(s2 == H) {
+ if(append)
+ return s1;
+ return stringdup(s1);
+ }
+
+ if(s1->len < 0) {
+ l1 = -s1->len;
+ if(s2->len < 0)
+ l = l1 - s2->len;
+ else
+ l = l1 + s2->len;
+ if(append && l <= s1->max)
+ ns = s1;
+ else {
+ ns = newrunes(append? (l+l/4): l);
+ memmove(ns->Srune, s1->Srune, l1*sizeof(Rune));
+ }
+ ns->len = -l;
+ r = &ns->Srune[l1];
+ if(s2->len < 0)
+ memmove(r, s2->Srune, -s2->len*sizeof(Rune));
+ else
+ cvtup(r, s2);
+
+ return ns;
+ }
+
+ if(s2->len < 0) {
+ l2 = -s2->len;
+ l = s1->len + l2;
+ ns = newrunes(append? (l+l/4): l);
+ ns->len = -l;
+ cvtup(ns->Srune, s1);
+ memmove(&ns->Srune[s1->len], s2->Srune, l2*sizeof(Rune));
+ return ns;
+ }
+
+ l1 = s1->len;
+ l = l1 + s2->len;
+ if(append && l <= s1->max)
+ ns = s1;
+ else {
+ ns = newstring(append? (l+l/4): l);
+ memmove(ns->Sascii, s1->Sascii, l1);
+ }
+ ns->len = l;
+ memmove(ns->Sascii+l1, s2->Sascii, s2->len);
+
+ return ns;
+}
+
+OP(addc)
+{
+ String *ns, **sp;
+
+ ns = addstring(S(m), S(s), R.m == R.d);
+
+ sp = R.d;
+ if(ns != *sp) {
+ destroy(*sp);
+ *sp = ns;
+ }
+}
+
+OP(cvtca)
+{
+ int l;
+ Rune *r;
+ char *p;
+ String *ss;
+ Array *a, **ap;
+
+ ss = S(s);
+ if(ss == H) {
+ a = mem2array(nil, 0);
+ goto r;
+ }
+ if(ss->len < 0) {
+ l = -ss->len;
+ a = mem2array(nil, runenlen(ss->Srune, l));
+ p = (char*)a->data;
+ r = ss->Srune;
+ while(l--)
+ p += runetochar(p, r++);
+ goto r;
+ }
+ a = mem2array(ss->Sascii, ss->len);
+
+r: ap = R.d;
+ destroy(*ap);
+ *ap = a;
+}
+
+OP(cvtac)
+{
+ Array *a;
+ String *ds, **dp;
+
+ ds = H;
+ a = A(s);
+ if(a != H)
+ ds = c2string((char*)a->data, a->len);
+
+ dp = R.d;
+ destroy(*dp);
+ *dp = ds;
+}
+
+OP(lenc)
+{
+ int l;
+ String *ss;
+
+ l = 0;
+ ss = S(s);
+ if(ss != H) {
+ l = ss->len;
+ if(l < 0)
+ l = -l;
+ }
+ W(d) = l;
+}
+
+OP(cvtcw)
+{
+ String *s;
+
+ s = S(s);
+ if(s == H)
+ W(d) = 0;
+ else
+ if(s->len < 0)
+ W(d) = strtol(string2c(s), nil, 10);
+ else {
+ s->Sascii[s->len] = '\0';
+ W(d) = strtol(s->Sascii, nil, 10);
+ }
+}
+
+OP(cvtcf)
+{
+ String *s;
+
+ s = S(s);
+ if(s == H)
+ F(d) = 0.0;
+ else
+ if(s->len < 0)
+ F(d) = strtod(string2c(s), nil);
+ else {
+ s->Sascii[s->len] = '\0';
+ F(d) = strtod(s->Sascii, nil);
+ }
+}
+
+OP(cvtwc)
+{
+ String *ds, **dp;
+
+ ds = newstring(16);
+ ds->len = sprint(ds->Sascii, "%d", W(s));
+
+ dp = R.d;
+ destroy(*dp);
+ *dp = ds;
+}
+
+OP(cvtlc)
+{
+ String *ds, **dp;
+
+ ds = newstring(16);
+ ds->len = sprint(ds->Sascii, "%lld", V(s));
+
+ dp = R.d;
+ destroy(*dp);
+ *dp = ds;
+}
+
+OP(cvtfc)
+{
+ String *ds, **dp;
+
+ ds = newstring(32);
+ ds->len = sprint(ds->Sascii, "%g", F(s));
+ dp = R.d;
+ destroy(*dp);
+ *dp = ds;
+}
+
+char*
+string2c(String *s)
+{
+ char *p;
+ int c, l, nc;
+ Rune *r, *er;
+
+ if(s == H)
+ return "";
+
+ if(s->len >= 0) {
+ s->Sascii[s->len] = '\0';
+ return s->Sascii;
+ }
+
+ nc = -s->len;
+ l = (nc * UTFmax) + UTFmax;
+ if(s->tmp == nil || msize(s->tmp) < l) {
+ free(s->tmp);
+ s->tmp = malloc(l);
+ if(s->tmp == nil)
+ error(exNomem);
+ }
+
+ p = s->tmp;
+ r = s->Srune;
+ er = r + nc;
+ while(r < er) {
+ c = *r++;
+ if(c < Runeself)
+ *p++ = c;
+ else
+ p += runetochar(p, r-1);
+ }
+
+ *p = 0;
+
+ return s->tmp;
+}
+
+String*
+c2string(char *cs, int len)
+{
+ uchar *p;
+ char *ecs;
+ String *s;
+ Rune *r, junk;
+ int c, nc, isrune;
+
+ isrune = 0;
+ ecs = cs+len;
+ p = (uchar*)cs;
+ while(len--) {
+ c = *p++;
+ if(c >= Runeself) {
+ isrune = 1;
+ break;
+ }
+ }
+
+ if(isrune == 0) {
+ nc = ecs - cs;
+ s = newstring(nc);
+ memmove(s->Sascii, cs, nc);
+ return s;
+ }
+
+ p--;
+ nc = p - (uchar*)cs;
+ while(p < (uchar*)ecs) {
+ c = *p;
+ if(c < Runeself)
+ p++;
+ else if(p+UTFmax<=(uchar*)ecs || fullrune((char*)p, (uchar*)ecs-p))
+ p += chartorune(&junk, (char*)p);
+ else
+ break;
+ nc++;
+ }
+ s = newrunes(nc);
+ r = s->Srune;
+ while(nc--)
+ cs += chartorune(r++, cs);
+
+ return s;
+}
+
+String*
+newstring(int nb)
+{
+ Heap *h;
+ String *s;
+
+ h = nheap(sizeof(String)+nb);
+ h->t = &Tstring;
+ Tstring.ref++;
+ s = H2D(String*, h);
+ s->tmp = nil;
+ s->len = nb;
+ s->max = hmsize(h) - (sizeof(String)+sizeof(Heap));
+ return s;
+}
+
+String*
+newrunes(int nr)
+{
+ Heap *h;
+ String *s;
+
+ if(nr == 0)
+ return newstring(nr);
+ if(nr < 0)
+ nr = -nr;
+ h = nheap(sizeof(String)+nr*sizeof(Rune));
+ h->t = &Tstring;
+ Tstring.ref++;
+ s = H2D(String*, h);
+ s->tmp = nil;
+ s->len = -nr;
+ s->max = (hmsize(h) - (sizeof(String)+sizeof(Heap)))/sizeof(Rune);
+ return s;
+}
+
+String*
+stringdup(String *s)
+{
+ String *ns;
+
+ if(s == H)
+ return H;
+
+ if(s->len >= 0) {
+ ns = newstring(s->len);
+ memmove(ns->Sascii, s->Sascii, s->len);
+ return ns;
+ }
+
+ ns = newrunes(-s->len);
+ memmove(ns->Srune, s->Srune,-s->len*sizeof(Rune));
+
+ return ns;
+}
+
+int
+stringcmp(String *s1, String *s2)
+{
+ Rune *r1, *r2;
+ char *a1, *a2;
+ int v, n, n1, n2, c1, c2;
+ static String snil = { 0, 0, nil };
+
+ if(s1 == H)
+ s1 = &snil;
+ if(s2 == H)
+ s2 = &snil;
+
+ if(s1 == s2)
+ return 0;
+
+ v = 0;
+ n1 = s1->len;
+ if(n1 < 0) {
+ n1 = -n1;
+ v |= 1;
+ }
+ n2 = s2->len;
+ if(n2 < 0) {
+ n2 = -n2;
+ v |= 2;
+ }
+
+ n = n1;
+ if(n2 < n)
+ n = n2;
+
+ switch(v) {
+ case 0: /* Ascii Ascii */
+ n = memcmp(s1->Sascii, s2->Sascii, n);
+ if(n == 0)
+ n = n1 - n2;
+ return n;
+ case 1: /* Rune Ascii */
+ r1 = s1->Srune;
+ a2 = s2->Sascii;
+ while(n > 0) {
+ c1 = *r1++;
+ c2 = *a2++;
+ if(c1 != c2)
+ goto ne;
+ n--;
+ }
+ break;
+ case 2: /* Ascii Rune */
+ a1 = s1->Sascii;
+ r2 = s2->Srune;
+ while(n > 0) {
+ c1 = *a1++;
+ c2 = *r2++;
+ if(c1 != c2)
+ goto ne;
+ n--;
+ }
+ break;
+ case 3: /* Rune Rune */
+ r1 = s1->Srune;
+ r2 = s2->Srune;
+ while(n > 0) {
+ c1 = *r1++;
+ c2 = *r2++;
+ if(c1 != c2)
+ goto ne;
+ n--;
+ }
+ break;
+ }
+ return n1 - n2;
+
+ne: if(c1 < c2)
+ return -1;
+ return 1;
+}
+
+String*
+splitc(String **s, int expand)
+{
+ String *ss, *ns;
+
+ ss = *s;
+ if(expand && ss->len > 0) {
+ ns = newrunes(ss->len);
+ cvtup(ns->Srune, ss);
+ }
+ else
+ ns = stringdup(ss);
+
+ destroy(ss);
+ *s = ns;
+ return ns;
+}
--- /dev/null
+++ b/libinterp/tab.h
@@ -1,0 +1,184 @@
+struct
+{
+ char* name;
+ int op;
+ int terminal;
+}keywds[] =
+{
+ "nop", INOP, TOKI0,
+ "alt", IALT, TOKI3,
+ "nbalt", INBALT, TOKI3,
+ "goto", IGOTO, TOKI2,
+ "call", ICALL, TOKI2,
+ "frame", IFRAME, TOKI2,
+ "spawn", ISPAWN, TOKI2,
+ "runt", IRUNT, TOKI2,
+ "load", ILOAD, TOKI3,
+ "mcall", IMCALL, TOKI3,
+ "mspawn", IMSPAWN, TOKI3,
+ "mframe", IMFRAME, TOKI3,
+ "ret", IRET, TOKI0,
+ "jmp", IJMP, TOKI1,
+ "case", ICASE, TOKI2,
+ "exit", IEXIT, TOKI0,
+ "new", INEW, TOKI2,
+ "newa", INEWA, TOKI3,
+ "newcb", INEWCB, TOKI1,
+ "newcw", INEWCW, TOKI1,
+ "newcf", INEWCF, TOKI1,
+ "newcp", INEWCP, TOKI1,
+ "newcm", INEWCM, TOKI2,
+ "newcmp", INEWCMP, TOKI2,
+ "send", ISEND, TOKI2,
+ "recv", IRECV, TOKI2,
+ "consb", ICONSB, TOKI2,
+ "consw", ICONSW, TOKI2,
+ "consp", ICONSP, TOKI2,
+ "consf", ICONSF, TOKI2,
+ "consm", ICONSM, TOKI3,
+ "consmp", ICONSMP, TOKI3,
+ "headb", IHEADB, TOKI2,
+ "headw", IHEADW, TOKI2,
+ "headp", IHEADP, TOKI2,
+ "headf", IHEADF, TOKI2,
+ "headm", IHEADM, TOKI3,
+ "headmp", IHEADMP, TOKI3,
+ "tail", ITAIL, TOKI2,
+ "lea", ILEA, TOKI2,
+ "indx", IINDX, TOKI3,
+ "movp", IMOVP, TOKI2,
+ "movm", IMOVM, TOKI3,
+ "movmp", IMOVMP, TOKI3,
+ "movb", IMOVB, TOKI2,
+ "movw", IMOVW, TOKI2,
+ "movf", IMOVF, TOKI2,
+ "cvtbw", ICVTBW, TOKI2,
+ "cvtwb", ICVTWB, TOKI2,
+ "cvtfw", ICVTFW, TOKI2,
+ "cvtwf", ICVTWF, TOKI2,
+ "cvtca", ICVTCA, TOKI2,
+ "cvtac", ICVTAC, TOKI2,
+ "cvtwc", ICVTWC, TOKI2,
+ "cvtcw", ICVTCW, TOKI2,
+ "cvtfc", ICVTFC, TOKI2,
+ "cvtcf", ICVTCF, TOKI2,
+ "addb", IADDB, TOKI3,
+ "addw", IADDW, TOKI3,
+ "addf", IADDF, TOKI3,
+ "subb", ISUBB, TOKI3,
+ "subw", ISUBW, TOKI3,
+ "subf", ISUBF, TOKI3,
+ "mulb", IMULB, TOKI3,
+ "mulw", IMULW, TOKI3,
+ "mulf", IMULF, TOKI3,
+ "divb", IDIVB, TOKI3,
+ "divw", IDIVW, TOKI3,
+ "divf", IDIVF, TOKI3,
+ "modw", IMODW, TOKI3,
+ "modb", IMODB, TOKI3,
+ "andb", IANDB, TOKI3,
+ "andw", IANDW, TOKI3,
+ "orb", IORB, TOKI3,
+ "orw", IORW, TOKI3,
+ "xorb", IXORB, TOKI3,
+ "xorw", IXORW, TOKI3,
+ "shlb", ISHLB, TOKI3,
+ "shlw", ISHLW, TOKI3,
+ "shrb", ISHRB, TOKI3,
+ "shrw", ISHRW, TOKI3,
+ "insc", IINSC, TOKI3,
+ "indc", IINDC, TOKI3,
+ "addc", IADDC, TOKI3,
+ "lenc", ILENC, TOKI2,
+ "lena", ILENA, TOKI2,
+ "lenl", ILENL, TOKI2,
+ "beqb", IBEQB, TOKI3,
+ "bneb", IBNEB, TOKI3,
+ "bltb", IBLTB, TOKI3,
+ "bleb", IBLEB, TOKI3,
+ "bgtb", IBGTB, TOKI3,
+ "bgeb", IBGEB, TOKI3,
+ "beqw", IBEQW, TOKI3,
+ "bnew", IBNEW, TOKI3,
+ "bltw", IBLTW, TOKI3,
+ "blew", IBLEW, TOKI3,
+ "bgtw", IBGTW, TOKI3,
+ "bgew", IBGEW, TOKI3,
+ "beqf", IBEQF, TOKI3,
+ "bnef", IBNEF, TOKI3,
+ "bltf", IBLTF, TOKI3,
+ "blef", IBLEF, TOKI3,
+ "bgtf", IBGTF, TOKI3,
+ "bgef", IBGEF, TOKI3,
+ "beqc", IBEQC, TOKI3,
+ "bnec", IBNEC, TOKI3,
+ "bltc", IBLTC, TOKI3,
+ "blec", IBLEC, TOKI3,
+ "bgtc", IBGTC, TOKI3,
+ "bgec", IBGEC, TOKI3,
+ "slicea", ISLICEA, TOKI3,
+ "slicela", ISLICELA, TOKI3,
+ "slicec", ISLICEC, TOKI3,
+ "indw", IINDW, TOKI3,
+ "indf", IINDF, TOKI3,
+ "indb", IINDB, TOKI3,
+ "negf", INEGF, TOKI2,
+ "movl", IMOVL, TOKI2,
+ "addl", IADDL, TOKI3,
+ "subl", ISUBL, TOKI3,
+ "divl", IDIVL, TOKI3,
+ "modl", IMODL, TOKI3,
+ "mull", IMULL, TOKI3,
+ "andl", IANDL, TOKI3,
+ "orl", IORL, TOKI3,
+ "xorl", IXORL, TOKI3,
+ "shll", ISHLL, TOKI3,
+ "shrl", ISHRL, TOKI3,
+ "bnel", IBNEL, TOKI3,
+ "bltl", IBLTL, TOKI3,
+ "blel", IBLEL, TOKI3,
+ "bgtl", IBGTL, TOKI3,
+ "bgel", IBGEL, TOKI3,
+ "beql", IBEQL, TOKI3,
+ "cvtlf", ICVTLF, TOKI2,
+ "cvtfl", ICVTFL, TOKI2,
+ "cvtlw", ICVTLW, TOKI2,
+ "cvtwl", ICVTWL, TOKI2,
+ "cvtlc", ICVTLC, TOKI2,
+ "cvtcl", ICVTCL, TOKI2,
+ "headl", IHEADL, TOKI2,
+ "consl", ICONSL, TOKI2,
+ "newcl", INEWCL, TOKI1,
+ "casec", ICASEC, TOKI2,
+ "indl", IINDL, TOKI3,
+ "movpc", IMOVPC, TOKI2,
+ "tcmp", ITCMP, TOKI2,
+ "mnewz", IMNEWZ, TOKI3,
+ "cvtrf", ICVTRF, TOKI2,
+ "cvtfr", ICVTFR, TOKI2,
+ "cvtws", ICVTWS, TOKI2,
+ "cvtsw", ICVTSW, TOKI2,
+ "lsrw", ILSRW, TOKI3,
+ "lsrl", ILSRL, TOKI3,
+ "eclr", IECLR, TOKI0,
+ "newz", INEWZ, TOKI2,
+ "newaz", INEWAZ, TOKI3,
+ "raise", IRAISE, TOKI1,
+ "casel", ICASEL, TOKI2,
+ "mulx", IMULX, TOKI3,
+ "divx", IDIVX, TOKI3,
+ "cvtxx", ICVTXX, TOKI3,
+ "mulx0", IMULX0, TOKI3,
+ "divx0", IDIVX0, TOKI3,
+ "cvtxx0", ICVTXX0, TOKI3,
+ "mulx1", IMULX1, TOKI3,
+ "divx1", IDIVX1, TOKI3,
+ "cvtxx1", ICVTXX1, TOKI3,
+ "cvtfx", ICVTFX, TOKI3,
+ "cvtxf", ICVTXF, TOKI3,
+ "expw", IEXPW, TOKI3,
+ "expl", IEXPL, TOKI3,
+ "expf", IEXPF, TOKI3,
+ "self", ISELF, TOKI1,
+ 0,
+};
--- /dev/null
+++ b/libinterp/tk.c
@@ -1,0 +1,1305 @@
+#include "lib9.h"
+#include "interp.h"
+#include "isa.h"
+#include "runt.h"
+#include "draw.h"
+#include "tk.h"
+#include "tkmod.h"
+#include "pool.h"
+#include "drawif.h"
+#include "keyboard.h"
+#include "raise.h"
+#include "kernel.h"
+
+extern void tkfreetop(Heap*, int);
+Type* fakeTkTop;
+static uchar TktypeMap[] = Tk_Toplevel_map;
+int tkstylus;
+void (*tkwiretap)(void*, char*, char*, void*, Rectangle*);
+
+static void tktopimagedptr(TkTop*, Draw_Image*);
+static char*tkputwinimage(Tk*, Draw_Image*, int);
+
+static void
+lockctxt(TkCtxt *ctxt)
+{
+ libqlock(ctxt->lock);
+}
+
+static void
+unlockctxt(TkCtxt *ctxt)
+{
+ libqunlock(ctxt->lock);
+}
+
+static void
+tkmarktop(Type *t, void *vw)
+{
+ Heap *h;
+ TkVar *v;
+ TkPanelimage *di;
+ TkTop *top;
+ Tk *w, *next;
+ TkWin *tkw;
+
+ markheap(t, vw);
+ top = vw;
+ // XXX do we need to lock context here??
+ for(v = top->vars; v; v = v->link) {
+ if(v->type == TkVchan) {
+ h = D2H(v->value);
+ Setmark(h);
+ }
+ }
+ for (di = top->panelimages; di != nil; di = di->link) {
+ h = D2H(di->image);
+ Setmark(h);
+ }
+ for(w = top->windows; w != nil; w = next){
+ tkw = TKobj(TkWin, w);
+ if(tkw->image != nil){
+ h = D2H(tkw->di);
+ Setmark(h);
+ }
+ next = tkw->next;
+ }
+}
+
+void
+tkmodinit(void)
+{
+ builtinmod("$Tk", Tkmodtab, Tkmodlen);
+ fmtinstall('v', tkeventfmt); /* XXX */
+
+ fakeTkTop = dtype(tkfreetop, sizeof(TkTop), TktypeMap, sizeof(TktypeMap));
+ fakeTkTop->mark = tkmarktop;
+
+ tksorttable();
+}
+
+void
+Tk_toplevel(void *a)
+{
+ Tk *tk;
+ Heap *h;
+ TkTop *t;
+ TkWin *tkw;
+ TkCtxt *ctxt;
+ Display *disp;
+ F_Tk_toplevel *f = a;
+ void *r;
+
+ r = *f->ret;
+ *f->ret = H;
+ destroy(r);
+ disp = checkdisplay(f->d);
+
+ h = heapz(fakeTkTop);
+ t = H2D(TkTop*, h);
+ poolimmutable(h);
+
+ t->dd = f->d;
+ D2H(t->dd)->ref++;
+
+ t->execdepth = -1;
+ t->display = disp;
+
+ tk = tknewobj(t, TKframe, sizeof(Tk)+sizeof(TkWin));
+ if(tk == nil) {
+ destroy(t);
+ return;
+ }
+
+ tk->act.x = 0;
+ tk->act.y = 0;
+ tk->act.width = 1; /* XXX why not zero? */
+ tk->act.height = 1;
+ tk->flag |= Tkwindow;
+
+ tkw = TKobj(TkWin, tk);
+ tkw->di = H;
+
+ tktopopt(tk, string2c(f->arg));
+
+ tk->geom = tkmoveresize;
+ tk->name = tkmkname(".");
+ if(tk->name == nil) {
+ tkfreeobj(tk);
+ destroy(t);
+ return;
+ }
+
+ ctxt = tknewctxt(disp);
+ if(ctxt == nil) {
+ tkfreeobj(tk);
+ destroy(t);
+ return;
+ }
+ t->ctxt = ctxt;
+ t->screenr = disp->image->r;
+
+ tkw->next = t->windows;
+ t->windows = tk;
+ t->root = tk;
+ Setmark(h);
+ poolmutable(h);
+ t->wreq = cnewc(&Tptr, movp, 8);
+ *f->ret = (Tk_Toplevel*)t;
+}
+
+void
+Tk_cmd(void *a)
+{
+ TkTop *t;
+ char *val, *e;
+ F_Tk_cmd *f = a;
+
+ t = (TkTop*)f->t;
+ if(t == H || D2H(t)->t != fakeTkTop) {
+ retstr(TkNotop, f->ret);
+ return;
+ }
+ lockctxt(t->ctxt);
+ val = nil;
+ e = tkexec(t, string2c(f->arg), &val);
+ unlockctxt(t->ctxt);
+ if(e == TkNomem){
+ free(val);
+ error(exNomem); /* what about f->ret? */
+ }
+ if(e != nil && t->errx[0] != '\0'){
+ char *s = tkerrstr(t, e);
+
+ retstr(s, f->ret);
+ free(s);
+ }
+ else
+ retstr(e == nil ? val : e, f->ret);
+ if(tkwiretap != nil)
+ tkwiretap(t, string2c(f->arg), val, nil, nil);
+ free(val);
+}
+
+void
+Tk_color(void *fp)
+{
+ ulong rgba;
+ F_Tk_color *f = fp;
+ if(tkparsecolor(string2c(f->col), &rgba) != nil)
+ *f->ret = DNotacolor;
+ else
+ *f->ret = rgba;
+}
+
+void
+Tk_rect(void *fp)
+{
+ F_Tk_rect *f = fp;
+ Tk *tk;
+ TkTop *t;
+ Rectangle r;
+ Point o;
+ int bd, flags, w, h;
+
+ t = (TkTop*)f->t;
+ if(t == H || D2H(t)->t != fakeTkTop){
+ *(Rectangle*)f->ret = ZR;
+ return;
+ }
+ lockctxt(t->ctxt);
+ tk = tklook(t, string2c(f->name), 0);
+ if(tk == nil){
+ *(Rectangle*)f->ret = ZR;
+ unlockctxt(t->ctxt);
+ return;
+ }
+ o = tkposn(tk);
+ flags = f->flags;
+ if(flags & Tk_Local)
+ o = subpt(o, tkposn(tk->env->top->root));
+ if(flags & Tk_Required){
+ h = tk->req.height;
+ w = tk->req.width;
+ }else{
+ h = tk->act.height;
+ w = tk->act.width;
+ }
+ unlockctxt(t->ctxt);
+ if(w < 0)
+ w = 0;
+ if(h < 0)
+ h = 0;
+ bd = tk->borderwidth;
+ if(bd < 0)
+ bd = 0;
+ if(flags & Tk_Border){
+ r.min = o;
+ r.max.x = r.min.x + w + bd + bd;
+ r.max.y = r.min.y + h + bd + bd;
+ }else{
+ r.min.x = o.x + bd;
+ r.min.y = o.y + bd;
+ r.max.x = r.min.x + w;
+ r.max.y = r.min.y + h;
+ }
+ *(Rectangle*)f->ret = r;
+}
+
+int
+tkdescendant(Tk *p, Tk *c)
+{
+ int n;
+
+ if(c == nil || p->env->top != c->env->top)
+ return 0;
+
+ if (p->name != nil && c->name != nil) {
+ n = strlen(p->name->name);
+ if(strncmp(p->name->name, c->name->name, n) == 0)
+ return 1;
+ }
+
+ return 0;
+}
+
+void
+tkenterleave(TkTop *t)
+{
+ Tk *fw, *ent;
+ TkMouse m;
+ TkTop *t1, *t2;
+ TkCtxt *c;
+
+ c = t->ctxt;
+ m = c->mstate;
+
+ if (c->mgrab != nil && (c->mgrab->flag & Tknograb)) {
+ fw = tkfindfocus(t, m.x, m.y, 1);
+ if (fw != c->mgrab && fw != nil && (fw->flag & Tknograb) == 0)
+ fw = nil;
+ } else if (c->focused) {
+ fw = tkfindfocus(t, m.x, m.y, 1);
+ if (fw != c->mfocus)
+ fw = nil;
+ } else if (c->mgrab != nil) {
+ fw = tkfindfocus(t, m.x, m.y, 1);
+ if (fw != nil) {
+ if (!tkdescendant(c->mgrab, fw) && !(fw->flag & c->mgrab->flag & Tknograb))
+ fw = nil;
+ }
+ } else if (m.b == 0)
+ fw = tkfindfocus(t, m.x, m.y, 0);
+ else if (tkfindfocus(t, m.x, m.y, 1) == c->entered)
+ return;
+ else
+ fw = nil;
+
+ if (c->entered == fw)
+ return;
+
+ t1 = t2 = nil;
+ if (c->entered != nil) {
+ ent = c->entered;
+ t1 = ent->env->top;
+ c->entered = nil;
+ tkdeliver(ent, TkLeave, nil);
+ }
+
+ if (fw != nil) {
+ t2 = fw->env->top;
+ c->entered = fw;
+ tkdeliver(fw, TkEnter, &m);
+ }
+ if (t1 != nil)
+ tkupdate(t1);
+ if (t2 != nil && t1 != t2)
+ tkupdate(t2);
+}
+
+void
+Tk_pointer(void *a)
+{
+ static int buttonr[] = {TkButton1R, TkButton2R, TkButton3R, TkButton4R, TkButton5R, TkButton6R};
+ static int buttonp[] = {TkButton1P, TkButton2P, TkButton3P, TkButton4P, TkButton5P, TkButton6P};
+ Tk *fw, *target, *dest, *ent;
+ TkMouse m;
+ TkCtxt *c;
+ TkTop *t, *ot;
+ int d, dtype, etype;
+ F_Tk_pointer *f = a;
+ int b, lastb, inside;
+
+ t = (TkTop*)f->t;
+ if(t == H || D2H(t)->t != fakeTkTop)
+ return;
+
+ c = t->ctxt;
+
+ /* ignore no-button-motion for emulated stylus input */
+ if(tkstylus && c->mstate.b == 0 && (f->p.buttons&0x1f)==0)
+ return;
+
+ lockctxt(c);
+//if (f->p.buttons != 0 || c->mstate.b != 0)
+//print("tkmouse %d [%d %d], focused %d[%s], grab %s, entered %s\n",
+// f->p.buttons, f->p.xy.x, f->p.xy.y, c->focused, tkname(c->mfocus), tkname(c->mgrab), tkname(c->entered));
+ /*
+ * target is the widget that we're deliver the mouse event to.
+ * inside is true if the mouse point is located inside target.
+ */
+ inside = 1;
+ if (c->mgrab != nil && (c->mgrab->flag & Tknograb)) {
+ fw = tkfindfocus(t, f->p.xy.x, f->p.xy.y, 1);
+ if (fw != nil && (fw->flag & Tknograb))
+ target = fw;
+ else {
+ target = c->mgrab;
+ inside = 0;
+ }
+ } else if (c->focused) {
+ if (c->mfocus != nil) {
+ fw = tkfindfocus(t, f->p.xy.x, f->p.xy.y, 1);
+ if (fw != c->mfocus)
+ inside = 0;
+ }
+ target = c->mfocus;
+ } else if (c->mgrab != nil && (c->mgrab->flag & Tkdisabled) == 0) {
+ /*
+ * XXX this isn't quite right, as perhaps we should do a tkinwindow()
+ * (below the grab).
+ * so that events to containers underneath the grab arrive
+ * via the containers (as is usual)
+ */
+ fw = tkfindfocus(t, f->p.xy.x, f->p.xy.y, 1);
+ if (fw != nil && tkdescendant(c->mgrab, fw))
+ target = fw;
+ else {
+ target = c->mgrab;
+ inside = 0;
+ }
+ } else
+ target = tkfindfocus(t, f->p.xy.x, f->p.xy.y, 0);
+
+ lastb = c->mstate.b;
+ c->mstate.x = f->p.xy.x;
+ c->mstate.y = f->p.xy.y;
+ c->mstate.b = f->p.buttons & 0x1f; /* Just the buttons */
+ m = c->mstate;
+
+ /* XXX if the mouse is being moved with the buttons held down
+ * and we've no mfocus and no mgrab then ignore
+ * the event as our original target has gone away (or never existed)
+ */
+ if (lastb && m.b && !c->focused && c->mgrab == nil)
+ target = nil;
+
+ if (target != c->entered || (c->entered != nil && !inside)) {
+ if (c->entered != nil) {
+ fw = c->entered;
+ c->entered = nil;
+ tkdeliver(fw, TkLeave, nil);
+ if (target == nil || fw->env->top != target->env->top)
+ tkupdate(fw->env->top);
+ }
+ if (inside) {
+ c->entered = target;
+ tkdeliver(target, TkEnter, &m);
+ }
+ }
+
+ dest = nil;
+ if (target != nil) {
+ etype = 0;
+ dtype = 0;
+ if(f->p.buttons & (1<<8)) /* Double */
+ dtype = TkDouble;
+
+ d = lastb ^ m.b;
+ if (d) {
+ /* cancel any autorepeat, notifying existing client */
+ tkrepeat(nil, nil, nil, 0, 0);
+ if (d & ~lastb & 1) /* button 1 potentially takes the focus */
+ tkdeliver(target, TkTakefocus|TkButton1P, &m);
+ }
+ for(b=0; b<nelem(buttonp); b++){
+ if(d & (1<<b)){
+ etype = buttonr[b];
+ if(m.b & (1<<b))
+ etype = buttonp[b]|dtype;
+ dest = tkdeliver(target, etype, &m);
+ }
+ }
+ if(tkstylus && m.b==0) {
+ if ((ent = c->entered) != nil) {
+ c->entered = nil;
+ ot = ent->env->top;
+ tkdeliver(ent, TkLeave, nil);
+ if (ot != target->env->top)
+ tkupdate(ot);
+ }
+ } else if(etype == 0) {
+ etype = TkMotion;
+ for(b = 0; b<nelem(buttonp); b++)
+ if (m.b & (1<<b))
+ etype |= buttonp[b];
+ tkdeliver(target, etype, &m);
+ }
+ if (m.b != 0) {
+ if (lastb == 0 && !c->focused) { /* (some deliver might have grabbed it...) */
+ if (dest == nil)
+ dest = target;
+ if ((dest->flag & Tknograb) == 0) {
+ c->focused = 1;
+ c->mfocus = dest;
+ }
+ }
+ } else {
+ c->focused = 0;
+ c->mfocus = nil;
+ if (lastb != 0)
+ tkenterleave(t);
+ }
+ tkupdate(target->env->top);
+ } else if (c->focused && m.b == 0) {
+ c->focused = 0;
+ tkenterleave(t);
+ }
+ unlockctxt(c);
+}
+
+void
+Tk_keyboard(void *a)
+{
+ Tk *grab;
+ TkTop *t;
+ TkCtxt *c;
+ F_Tk_keyboard *f = a;
+
+ t = (TkTop*)f->t;
+ if(t == H || D2H(t)->t != fakeTkTop)
+ return;
+ c = t->ctxt;
+ if (c == nil)
+ return;
+ lockctxt(c);
+ if (c->tkmenu != nil)
+ grab = c->tkmenu;
+ else
+ grab = c->tkkeygrab;
+ if(grab == nil){
+ unlockctxt(c);
+ return;
+ }
+
+ t = grab->env->top;
+ tkdeliver(grab, TkKey|TKKEY(f->key), nil);
+ tkupdate(t);
+ unlockctxt(c);
+}
+
+TkVar*
+tkmkvar(TkTop *t, char *name, int type)
+{
+ TkVar *v;
+
+ for(v = t->vars; v; v = v->link)
+ if(strcmp(v->name, name) == 0)
+ return v;
+
+ if(type == 0)
+ return nil;
+
+ v = malloc(sizeof(TkVar)+strlen(name)+1);
+ if(v == nil)
+ return nil;
+ strcpy(v->name, name);
+ v->link = t->vars;
+ t->vars = v;
+ v->type = type;
+ v->value = nil;
+ if(type == TkVchan)
+ v->value = H;
+ return v;
+}
+
+void
+tkfreevar(TkTop *t, char *name, int swept)
+{
+ TkVar **l, *p;
+
+ if(name == nil)
+ return;
+ l = &t->vars;
+ for(p = *l; p != nil; p = p->link) {
+ if(strcmp(p->name, name) == 0) {
+ *l = p->link;
+ switch(p->type) {
+ default:
+ free(p->value);
+ break;
+ case TkVchan:
+ if(!swept)
+ destroy(p->value);
+ break;
+ }
+ free(p);
+ return;
+ }
+ l = &p->link;
+ }
+}
+
+void
+Tk_namechan(void *a)
+{
+ Heap *h;
+ TkVar *v;
+ TkTop *t;
+ char *name;
+ F_Tk_namechan *f = a;
+
+ t = (TkTop*)f->t;
+ if(t == H || D2H(t)->t != fakeTkTop) {
+ retstr(TkNotop, f->ret);
+ return;
+ }
+ if(f->c == H) {
+ retstr("nil channel", f->ret);
+ return;
+ }
+ name = string2c(f->n);
+ if(name[0] == '\0') {
+ retstr(TkBadvl, f->ret);
+ return;
+ }
+
+ lockctxt(t->ctxt);
+ v = tkmkvar(t, name, TkVchan);
+ if(v == nil) {
+ unlockctxt(t->ctxt);
+ retstr(TkNomem, f->ret);
+ return;
+ }
+ if(v->type != TkVchan) {
+ unlockctxt(t->ctxt);
+ retstr(TkNotvt, f->ret);
+ return;
+ }
+ destroy(v->value);
+ v->value = f->c;
+ unlockctxt(t->ctxt);
+ h = D2H(v->value);
+ h->ref++;
+ Setmark(h);
+ retstr("", f->ret);
+}
+
+void
+Tk_quote(void *a)
+{
+ String *s, *ns;
+ F_Tk_quote *f;
+ void *r;
+ int c, i, need, len, userune, last, n;
+ Rune *sr;
+ char *sc;
+
+ f = a;
+
+ r = *f->ret;
+ *f->ret = H;
+ destroy(r);
+
+ s = f->s;
+ if(s == H){
+ retstr("{}", f->ret);
+ return;
+ }
+ len = s->len;
+ userune = 0;
+ if(len < 0) {
+ len = -len;
+ userune = 1;
+ }
+ need = len+2;
+ for(i = 0; i < len; i++) {
+ c = userune? s->Srune[i]: s->Sascii[i];
+ if(c == '{' || c == '}' || c == '\\')
+ need++;
+ }
+ if(userune) {
+ ns = newrunes(need);
+ sr = ns->Srune;
+ *sr++ = '{';
+ last = 0;
+ for(i = 0;; i++) {
+ if(i >= len || (c = s->Srune[i]) == '{' || c == '}' || c == '\\'){
+ n = i-last;
+ if(n) {
+ memmove(sr, &s->Srune[last], n*sizeof(Rune));
+ sr += n;
+ }
+ if(i >= len)
+ break;
+ *sr++ = '\\';
+ last = i;
+ }
+ }
+ *sr = '}';
+ } else {
+ ns = newstring(need);
+ sc = ns->Sascii;
+ *sc++ = '{';
+ last = 0;
+ for(i = 0;; i++) {
+ if(i >= len || (c = s->Sascii[i]) == '{' || c == '}' || c == '\\'){
+ n = i-last;
+ if(n) {
+ memmove(sc, &s->Sascii[last], n);
+ sc += n;
+ }
+ if(i >= len)
+ break;
+ *sc++ = '\\';
+ last = i;
+ }
+ }
+ *sc= '}';
+ }
+ *f->ret = ns;
+}
+
+static void
+tkreplimg(TkTop *t, Draw_Image *f, Draw_Image *m, Image **ximg)
+{
+ Display *d;
+ Image *cimg, *cmask, *new;
+
+ cimg = lookupimage(f);
+ d = t->display;
+ if(cimg == nil || cimg->screen != nil || cimg->display != d)
+ return;
+ cmask = lookupimage(m);
+ if(cmask != nil && (cmask->screen != nil || cmask->display != d))
+ return;
+
+ if (cmask == nil)
+ new = allocimage(d, Rect(0, 0, Dx(cimg->r), Dy(cimg->r)), cimg->chan, 0, DNofill);
+ else {
+ if(cmask->screen != nil || cmask->display != d)
+ return;
+ new = allocimage(d, Rect(0, 0, Dx(cimg->r), Dy(cimg->r)), RGBA32, 0, DTransparent);
+ }
+ if(new == nil)
+ return;
+ draw(new, new->r, cimg, cmask, cimg->r.min);
+ if(tkwiretap != nil)
+ tkwiretap(t, "replimg", nil, cimg, &cimg->r);
+ if(*ximg != nil)
+ freeimage(*ximg);
+ *ximg = new;
+}
+
+static char*
+tkaddpanelimage(TkTop *t, Draw_Image *di, Image **i)
+{
+ TkPanelimage *pi;
+
+ if (di == H) {
+ *i = 0;
+ return nil;
+ }
+
+ *i = lookupimage(di);
+ if (*i == nil || (*i)->display != t->display)
+ return TkNotwm;
+
+ for (pi = t->panelimages; pi != nil; pi = pi->link) {
+ if (pi->image == di) {
+ pi->ref++;
+ return nil;
+ }
+ }
+
+ pi = malloc(sizeof(TkPanelimage));
+ if (pi == nil)
+ return TkNomem;
+ pi->image = di;
+ D2H(di)->ref++;
+ pi->ref = 1;
+ pi->link = t->panelimages;
+ t->panelimages = pi;
+ return nil;
+}
+
+void
+tkdelpanelimage(TkTop *t, Image *i)
+{
+ TkPanelimage *pi, *prev;
+ int locked;
+
+ if (i == nil)
+ return;
+
+ prev = nil;
+ for (pi = t->panelimages; pi != nil; pi = pi->link) {
+ if (lookupimage(pi->image) == i)
+ break;
+ prev = pi;
+ }
+ if (pi == nil || --pi->ref > 0)
+ return;
+ if (prev)
+ prev->link = pi->link;
+ else
+ t->panelimages = pi->link;
+ if (D2H(pi->image)->ref == 1) { /* don't bother locking if it's not going away */
+ locked = lockdisplay(t->display);
+ destroy(pi->image);
+ if (locked)
+ unlockdisplay(t->display);
+ }
+
+ free(pi);
+}
+
+void
+Tk_putimage(void *a)
+{
+ TkTop *t;
+ TkImg *tki;
+ Image *i, *m, *oldi, *oldm;
+ int locked, found, reqid, n;
+ char *words[2];
+ Display *d;
+ F_Tk_putimage *f;
+ void *r;
+ char *name, *e;
+ Tk *tk;
+
+ f = a;
+
+ r = *f->ret;
+ *f->ret = H;
+ destroy(r);
+
+ t = (TkTop*)f->t;
+ if(t == H || D2H(t)->t != fakeTkTop) {
+ retstr(TkNotop, f->ret);
+ return;
+ }
+
+ if(f->i == H) {
+ retstr(TkBadvl, f->ret);
+ return;
+ }
+
+ name = string2c(f->name);
+ lockctxt(t->ctxt);
+ e = nil;
+ found = 0;
+ if(name[0] == '.'){
+ n = getfields(name, words, nelem(words), 1, " ");
+ reqid = -1;
+ if(n > 1){
+ reqid = atoi(words[1]);
+ name = words[0];
+ }
+ if((tk = tklook(t, name, 0)) != nil){
+ if(tk->type == TKchoicebutton){
+ tk = tkfindchoicemenu(tk);
+ if(tk == nil)
+ goto Error;
+ }
+ if(tk->type == TKframe || tk->type == TKmenu){
+ if((tk->flag & Tkwindow) == 0){
+ e = TkNotwm;
+ goto Error;
+ }
+ e = tkputwinimage(tk, f->i, reqid);
+ found = 1;
+ } else
+ if(tk->type == TKpanel){
+ if(n > 1){
+ e = TkBadvl;
+ goto Error;
+ }
+ e = tkaddpanelimage(t, f->i, &i);
+ if(e != nil)
+ goto Error;
+ e = tkaddpanelimage(t, f->m, &m);
+ if(e != nil){
+ tkdelpanelimage(t, i);
+ goto Error;
+ }
+ tkgetpanelimage(tk, &oldi, &oldm);
+ tkdelpanelimage(t, oldi);
+ tkdelpanelimage(t, oldm);
+ tksetpanelimage(tk, i, m);
+ tkdirty(tk);
+ found = 1;
+ }
+ }
+ }
+ if(!found){
+ /* XXX perhaps we shouldn't ever do this if name begins with '.'? */
+ tki = tkname2img(t, name);
+ if(tki == nil) {
+ e = TkBadvl;
+ goto Error;
+ }
+
+ d = t->display;
+ locked = lockdisplay(d);
+ tkreplimg(t, f->i, f->m, &tki->img);
+ if(locked)
+ unlockdisplay(d);
+
+ tksizeimage(t->root, tki);
+ }
+Error:
+ unlockctxt(t->ctxt);
+ if(e != nil)
+ retstr(e, f->ret);
+ return;
+}
+
+Draw_Image*
+tkimgcopy(TkTop *t, Image *cimg)
+{
+ Image *new;
+ Display *dp;
+ Draw_Image *i;
+
+ if(cimg == nil)
+ return H;
+
+ dp = t->display;
+ new = allocimage(dp, cimg->r, cimg->chan, cimg->repl, DNofill);
+ if(new == nil)
+ return H;
+ new->clipr = cimg->clipr;
+
+ drawop(new, new->r, cimg, nil, cimg->r.min, S);
+ if(tkwiretap != nil)
+ tkwiretap(t, "imgcopy", nil, cimg, &cimg->r);
+
+ i = mkdrawimage(new, H, t->dd, nil);
+ if(i == H)
+ freeimage(new);
+
+ return i;
+}
+
+void
+Tk_getimage(void *a)
+{
+ Tk *tk;
+ char *n;
+ TkImg *i;
+ TkTop *t;
+ int locked;
+ Display *d;
+ F_Tk_getimage *f;
+ void *r;
+ void (*getimgs)(Tk*, Image**, Image**);
+ Image *image, *mask;
+
+ f = a;
+
+ r = f->ret->t0;
+ f->ret->t0 = H;
+ destroy(r);
+ r = f->ret->t1;
+ f->ret->t1 = H;
+ destroy(r);
+ r = f->ret->t2;
+ f->ret->t2 = H;
+ destroy(r);
+
+ t = (TkTop*)f->t;
+ if(t == H || D2H(t)->t != fakeTkTop) {
+ retstr(TkNotop, &f->ret->t2);
+ return;
+ }
+ d = t->ctxt->display;
+ n = string2c(f->name);
+ lockctxt(t->ctxt);
+ i = tkname2img(t, n);
+ if (i != nil) {
+ image = i->img;
+ mask = nil;
+ } else {
+ tk = tklook(t, n, 0);
+ if (tk == nil || (getimgs = tkmethod[tk->type]->getimgs) == nil) {
+ unlockctxt(t->ctxt);
+ retstr(TkBadvl, &f->ret->t2);
+ return;
+ }
+ getimgs(tk, &image, &mask);
+ }
+ locked = lockdisplay(d);
+ f->ret->t0 = tkimgcopy(t, image);
+ if (mask != nil)
+ f->ret->t1 = tkimgcopy(t, mask);
+ if (locked)
+ unlockdisplay(d);
+ unlockctxt(t->ctxt);
+}
+
+void
+tkfreetop(Heap *h, int swept)
+{
+ TkTop *t;
+ Tk *f;
+ TkImg *i, *nexti;
+ TkVar *v, *nextv;
+ int wgtype;
+ void *r;
+ TkPanelimage *pi, *nextpi;
+
+ t = H2D(TkTop*, h);
+ lockctxt(t->ctxt);
+
+ if(swept) {
+ t->di = H;
+ t->dd = H;
+ t->wreq = H;
+ t->wmctxt = H;
+ }
+
+ t->windows = nil;
+
+ for(f = t->root; f; f = f->siblings) {
+ f->flag |= Tkdestroy;
+ tkdeliver(f, TkDestroy, nil);
+ if(f->destroyed != nil)
+ f->destroyed(f);
+ }
+
+ for(f = t->root; f; f = t->root) {
+ t->root = f->siblings;
+ if(swept)
+ f->flag |= Tkswept;
+ tkfreeobj(f);
+ }
+
+ for(v = t->vars; v; v = nextv) {
+ nextv = v->link;
+ switch(v->type) {
+ default:
+ free(v->value);
+ break;
+ case TkVchan:
+ if(!swept)
+ destroy(v->value);
+ break;
+ }
+ free(v);
+ }
+
+ for (pi = t->panelimages; pi; pi = nextpi) {
+ if (!swept)
+ destroy(pi->image);
+ nextpi = pi->link;
+ free(pi);
+ }
+
+ for(i = t->imgs; i; i = nexti) {
+ if(i->ref != 1)
+ abort();
+ nexti = i->link;
+ tkimgput(i);
+ }
+ /* XXX free images inside widgets */
+
+ for(wgtype = 0; wgtype < TKwidgets; wgtype++)
+ if(t->binds[wgtype])
+ tkfreebind(t->binds[wgtype]);
+
+ unlockctxt(t->ctxt);
+ /* XXX should we leave it locked for this bit? */
+ tkfreectxt(t->ctxt);
+ if(!swept) {
+ r = t->di;
+ t->di = H;
+ destroy(r);
+
+ r = t->dd;
+ t->dd = H;
+ destroy(r);
+
+ r = t->wreq;
+ t->wreq = H;
+ destroy(r);
+
+ r = t->wmctxt;
+ t->wmctxt = H;
+ destroy(r);
+ }
+}
+
+static void
+tktopimagedptr(TkTop *top, Draw_Image *di)
+{
+ if(top->di != H){
+ destroy(top->di);
+ top->di = H;
+ }
+ if(di == H)
+ return;
+ D2H(di)->ref++;
+ top->di = di;
+}
+
+static void
+tkfreewinimage(TkWin *w)
+{
+ destroy(w->di);
+ w->image = nil;
+ w->di = H;
+}
+
+static int
+tksetwindrawimage(Tk *tk, Draw_Image *di)
+{
+ TkWin *tkw;
+ char *name;
+ Image *i;
+ int locked;
+ int same;
+
+ tkw = TKobj(TkWin, tk);
+
+ same = tkw->di == di;
+ if(!same)
+ if(tkw->image != nil)
+ destroy(tkw->di);
+ if(di == H){
+ tkw->di = H;
+ tkw->image = nil;
+ return same;
+ }
+ tkw->di = di;
+ i = lookupimage(di);
+ tkw->image = i;
+
+ locked = lockdisplay(i->display);
+ if(originwindow(i, ZP, i->r.min) == -1)
+ print("tk originwindow failed: %r\n");
+ di->r = DRECT(i->r);
+ di->clipr = DRECT(i->clipr);
+ if(locked)
+ unlockdisplay(i->display);
+
+ if(!same){
+ D2H(di)->ref++;
+ if(tk->name){
+ name = tk->name->name;
+ if(name[0] == '.' && name[1] == '\0')
+ tktopimagedptr(tk->env->top, tkw->di);
+ }
+ }
+ return same;
+}
+
+void
+tkdestroywinimage(Tk *tk)
+{
+ TkWin *tkw;
+ TkTop *top;
+ char *name;
+
+ assert(tk->flag & Tkwindow);
+ tkw = TKobj(TkWin, tk);
+ top = tk->env->top;
+
+ if(tkw->image != nil && !(tk->flag & Tkswept))
+ destroy(tkw->di);
+ tkw->di = H;
+ tkw->image = nil;
+ if(tk->name == nil)
+ name = tkw->cbname;
+ else
+ name = tk->name->name;
+ if(name[0] == '.' && name[1] == '\0' && !(tk->flag & Tkswept))
+ tktopimagedptr(top, H);
+ tkw->reqid++;
+ tkwreq(top, "delete %s", name);
+}
+
+static char*
+tkputwinimage(Tk *tk, Draw_Image *di, int reqid)
+{
+ TkWin *tkw;
+ TkTop *top;
+ Image *i;
+ int bw2, prop, resize;
+ Rectangle req;
+
+ top = tk->env->top;
+ tkw = TKobj(TkWin, tk);
+ i = lookupimage(di);
+ if (i == nil || i->display != top->display)
+ return TkNotwm;
+
+ if(reqid != -1 && reqid < tkw->reqid)
+ return "!request out of date";
+
+ bw2 = 2*tk->borderwidth;
+ req.min.x = tkw->req.x;
+ req.min.y = tkw->req.y;
+ req.max.x = req.min.x + tk->act.width + bw2;
+ req.max.y = req.min.y + tk->act.height + bw2;
+
+ resize = 0;
+ if(eqrect(req, i->r) == 0){
+ /*
+ * if we'd sent a request and our requested rect has now changed,
+ * then resend the request (via tkupdatewinsize),
+ * otherwise accept the new size and repack if necessary
+ */
+ if(reqid != -1 && tkw->changed){
+ if(tkupdatewinsize(tk))
+ return "!requested size has changed";
+
+ } else if(Dx(req) != Dx(i->r) || Dy(req) != Dy(i->r)){
+ tk->flag |= Tksuspended;
+ tk->act.width = Dx(i->r) - bw2;
+ tk->act.height = Dy(i->r) - bw2;
+ tk->req = tk->act;
+ prop = tk->flag & Tknoprop;
+ tk->flag |= Tknoprop;
+ tkpackqit(tk);
+ tkrunpack(top);
+ tk->flag = (tk->flag & ~Tknoprop) | prop;
+ resize = 1;
+ }
+ }
+ if(reqid == -1)
+ tkw->reqid++; /* invalidate all buffered requests. */
+ tkw->act = i->r.min;
+ tkw->req = tkw->act;
+ tkw->changed = 0;
+ tk->req.width = Dx(i->r) - bw2;
+ tk->req.height = Dy(i->r) - bw2;
+ tk->act = tk->req;
+ if((tk->flag & Tkmapped) == 0){
+ tk->flag |= Tkmapped;
+ tkdeliver(tk, TkMap, nil);
+ }
+ if(tksetwindrawimage(tk, di) == 0 || resize){
+ tk->dirty = tkrect(tk, 1);
+ tk->flag |= Tkrefresh;
+ }
+ tk->flag &= ~Tksuspended;
+
+ lookupimage(di); /* make sure limbo image coords correspond correctly */
+ tkupdate(top);
+ return nil;
+}
+
+void
+tkwreq(TkTop *top, char *fmt, ...)
+{
+ char *buf;
+ va_list arg;
+
+ va_start(arg, fmt);
+ buf = vsmprint(fmt, arg);
+ va_end(arg);
+ tktolimbo(top->wreq, buf);
+ free(buf);
+}
+
+int
+tktolimbo(void *var, char *msg)
+{
+ void *ptrs[1];
+ int r;
+
+ if(var==H)
+ return 0;
+ ptrs[0] = H;
+ retstr(msg, (String**) &ptrs[0]);
+ r = csendalt((Channel *)var, ptrs, &Tptr, TkMaxmsgs);
+ return r;
+}
+
+static void
+hexify(char *buf, int n)
+{
+ static char hex[] = "0123456789abcdef";
+ uchar b;
+ char *dp, *fp;
+ fp = buf+n;
+ dp = buf+n*2;
+ *dp-- = '\0';
+ while(fp-- > buf){
+ b = (uchar)*fp;
+ *dp-- = hex[b & 0xf];
+ *dp-- = hex[b >> 4];
+ }
+}
+
+char*
+tkcursorswitch(TkTop *top, Image *i, TkImg *img)
+{
+ Image *ci, *scratch;
+ char *buf;
+ Rectangle r;
+ int n, maxb, nb;
+
+ if(i == nil && img == nil){
+ tktolimbo(top->wreq, "cursor");
+ return nil;
+ }
+
+ if(img != nil){
+ if(img->cursor){
+ tktolimbo(top->wreq, img->cursor);
+ return nil;
+ }
+ i = img->img;
+ }
+ if(i->depth != 1 || Dx(i->r)*Dy(i->r) > 16000 || Dy(i->r)%8 != 0 || Dy(i->r)%2 != 0)
+ return TkBadcursor;
+ /*
+ * readjust image, inferring hotspot from origin.
+ */
+ if(i->r.min.x != 0 || i->r.min.y != 0){
+ r.min.x = 0;
+ r.min.y = 0;
+ r.max.x = Dx(i->r);
+ r.max.y = Dy(i->r);
+ scratch = allocimage(i->display, r, GREY1, 0, DNofill);
+ if(scratch == nil)
+ return TkNomem;
+ draw(scratch, r, i, nil, i->r.min);
+ ci = scratch;
+ }else{
+ scratch = nil;
+ ci = i;
+ }
+ nb = ci->r.max.x/8 * ci->r.max.y;
+ maxb = 7 + 12*4 + 2*nb + 1;
+ buf = mallocz(maxb, 0);
+ if(buf == nil)
+ return TkNomem;
+ n = sprint(buf, "cursor %d %d %d %d ", i->r.min.x, i->r.min.y, ci->r.max.x, ci->r.max.y);
+ unloadimage(ci, ci->r, (uchar*)buf+n, maxb-n);
+ hexify(buf+n, nb);
+ tktolimbo(top->wreq, buf);
+ if(img != nil){
+ free(img->cursor);
+ img->cursor = buf;
+ }
+ freeimage(scratch);
+ return nil;
+}
+
+void
+tkcursorset(TkTop *t, Point p)
+{
+ tkwreq(t, "ptr %d %d", p.x, p.y);
+}
--- /dev/null
+++ b/libinterp/validstk.c
@@ -1,0 +1,53 @@
+#include "lib9.h"
+#include "isa.h"
+#include "interp.h"
+
+static int depth;
+
+void
+memchk(void *p, Type *t)
+{
+ Heap *h;
+ int i, j;
+ ulong *v, **base;
+
+ if(depth > 100)
+ return;
+ depth++;
+ base = p;
+ for(i = 0; i < t->np; i++) {
+ for(j = 0; j < 8; j++) {
+ if(t->map[i] & (1<<(7-j))) {
+ v = base[(i*8)+j];
+ if(v != H) {
+ h = D2H(v);
+ hmsize(h);
+ if(h->ref <= 0)
+ abort();
+ if(h->t != nil)
+ memchk(v, h->t);
+ }
+ }
+ }
+ }
+ depth--;
+}
+
+void
+validstk(void)
+{
+ Type *t;
+ Frame *f;
+ uchar *fp;
+
+ fp = R.FP;
+ while(fp != nil) {
+ f = (Frame*)fp;
+ t = f->t;
+ if(t == nil)
+ t = SEXTYPE(f)->reg.TR;
+
+ memchk(f, t);
+ fp = f->fp;
+ }
+}
--- /dev/null
+++ b/libinterp/xec.c
@@ -1,0 +1,1698 @@
+#include <lib9.h>
+#include "isa.h"
+#include "interp.h"
+#include "raise.h"
+#include "pool.h"
+
+REG R; /* Virtual Machine registers */
+String snil; /* String known to be zero length */
+
+#define Stmp *((WORD*)(R.FP+NREG*IBY2WD))
+#define Dtmp *((WORD*)(R.FP+(NREG+2)*IBY2WD))
+
+#define OP(fn) void fn(void)
+#define B(r) *((BYTE*)(R.r))
+#define W(r) *((WORD*)(R.r))
+#define UW(r) *((UWORD*)(R.r))
+#define F(r) *((REAL*)(R.r))
+#define V(r) *((LONG*)(R.r))
+#define UV(r) *((ULONG*)(R.r))
+#define S(r) *((String**)(R.r))
+#define A(r) *((Array**)(R.r))
+#define L(r) *((List**)(R.r))
+#define P(r) *((WORD**)(R.r))
+#define C(r) *((Channel**)(R.r))
+#define T(r) *((void**)(R.r))
+#define JMP(r) R.PC = *(Inst**)(R.r)
+#define SH(r) *((SHORT*)(R.r))
+#define SR(r) *((SREAL*)(R.r))
+
+OP(runt) {}
+OP(negf) { F(d) = -F(s); }
+OP(jmp) { JMP(d); }
+OP(movpc){ T(d) = &R.M->prog[W(s)]; }
+OP(movm) { memmove(R.d, R.s, W(m)); }
+OP(lea) { W(d) = (WORD)R.s; }
+OP(movb) { B(d) = B(s); }
+OP(movw) { W(d) = W(s); }
+OP(movf) { F(d) = F(s); }
+OP(movl) { V(d) = V(s); }
+OP(cvtbw){ W(d) = B(s); }
+OP(cvtwb){ B(d) = W(s); }
+OP(cvtrf){ F(d) = SR(s); }
+OP(cvtfr){ SR(d) = F(s); }
+OP(cvtws){ SH(d) = W(s); }
+OP(cvtsw){ W(d) = SH(s); }
+OP(cvtwf){ F(d) = W(s); }
+OP(addb) { B(d) = B(m) + B(s); }
+OP(addw) { W(d) = W(m) + W(s); }
+OP(addl) { V(d) = V(m) + V(s); }
+OP(addf) { F(d) = F(m) + F(s); }
+OP(subb) { B(d) = B(m) - B(s); }
+OP(subw) { W(d) = W(m) - W(s); }
+OP(subl) { V(d) = V(m) - V(s); }
+OP(subf) { F(d) = F(m) - F(s); }
+OP(divb) { B(d) = B(m) / B(s); }
+OP(divw) { W(d) = W(m) / W(s); }
+OP(divl) { V(d) = V(m) / V(s); }
+OP(divf) { F(d) = F(m) / F(s); }
+OP(modb) { B(d) = B(m) % B(s); }
+OP(modw) { W(d) = W(m) % W(s); }
+OP(modl) { V(d) = V(m) % V(s); }
+OP(mulb) { B(d) = B(m) * B(s); }
+OP(mulw) { W(d) = W(m) * W(s); }
+OP(mull) { V(d) = V(m) * V(s); }
+OP(mulf) { F(d) = F(m) * F(s); }
+OP(andb) { B(d) = B(m) & B(s); }
+OP(andw) { W(d) = W(m) & W(s); }
+OP(andl) { V(d) = V(m) & V(s); }
+OP(xorb) { B(d) = B(m) ^ B(s); }
+OP(xorw) { W(d) = W(m) ^ W(s); }
+OP(xorl) { V(d) = V(m) ^ V(s); }
+OP(orb) { B(d) = B(m) | B(s); }
+OP(orw) { W(d) = W(m) | W(s); }
+OP(orl) { V(d) = V(m) | V(s); }
+OP(shlb) { B(d) = B(m) << W(s); }
+OP(shlw) { W(d) = W(m) << W(s); }
+OP(shll) { V(d) = V(m) << W(s); }
+OP(shrb) { B(d) = B(m) >> W(s); }
+OP(shrw) { W(d) = W(m) >> W(s); }
+OP(shrl) { V(d) = V(m) >> W(s); }
+OP(lsrw) { W(d) = UW(m) >> W(s); }
+OP(lsrl) { V(d) = UV(m) >> W(s); }
+OP(beqb) { if(B(s) == B(m)) JMP(d); }
+OP(bneb) { if(B(s) != B(m)) JMP(d); }
+OP(bltb) { if(B(s) < B(m)) JMP(d); }
+OP(bleb) { if(B(s) <= B(m)) JMP(d); }
+OP(bgtb) { if(B(s) > B(m)) JMP(d); }
+OP(bgeb) { if(B(s) >= B(m)) JMP(d); }
+OP(beqw) { if(W(s) == W(m)) JMP(d); }
+OP(bnew) { if(W(s) != W(m)) JMP(d); }
+OP(bltw) { if(W(s) < W(m)) JMP(d); }
+OP(blew) { if(W(s) <= W(m)) JMP(d); }
+OP(bgtw) { if(W(s) > W(m)) JMP(d); }
+OP(bgew) { if(W(s) >= W(m)) JMP(d); }
+OP(beql) { if(V(s) == V(m)) JMP(d); }
+OP(bnel) { if(V(s) != V(m)) JMP(d); }
+OP(bltl) { if(V(s) < V(m)) JMP(d); }
+OP(blel) { if(V(s) <= V(m)) JMP(d); }
+OP(bgtl) { if(V(s) > V(m)) JMP(d); }
+OP(bgel) { if(V(s) >= V(m)) JMP(d); }
+OP(beqf) { if(F(s) == F(m)) JMP(d); }
+OP(bnef) { if(F(s) != F(m)) JMP(d); }
+OP(bltf) { if(F(s) < F(m)) JMP(d); }
+OP(blef) { if(F(s) <= F(m)) JMP(d); }
+OP(bgtf) { if(F(s) > F(m)) JMP(d); }
+OP(bgef) { if(F(s) >= F(m)) JMP(d); }
+OP(beqc) { if(stringcmp(S(s), S(m)) == 0) JMP(d); }
+OP(bnec) { if(stringcmp(S(s), S(m)) != 0) JMP(d); }
+OP(bltc) { if(stringcmp(S(s), S(m)) < 0) JMP(d); }
+OP(blec) { if(stringcmp(S(s), S(m)) <= 0) JMP(d); }
+OP(bgtc) { if(stringcmp(S(s), S(m)) > 0) JMP(d); }
+OP(bgec) { if(stringcmp(S(s), S(m)) >= 0) JMP(d); }
+OP(iexit){ error(""); }
+OP(cvtwl){ V(d) = W(s); }
+OP(cvtlw){ W(d) = V(s); }
+OP(cvtlf){ F(d) = V(s); }
+OP(cvtfl)
+{
+ REAL f;
+
+ f = F(s);
+ V(d) = f < 0 ? f - .5 : f + .5;
+}
+OP(cvtfw)
+{
+ REAL f;
+
+ f = F(s);
+ W(d) = f < 0 ? f - .5 : f + .5;
+}
+OP(cvtcl)
+{
+ String *s;
+
+ s = S(s);
+ if(s == H)
+ V(d) = 0;
+ else
+ V(d) = strtoll(string2c(s), nil, 10);
+}
+OP(iexpw)
+{
+ int inv;
+ WORD x, n, r;
+
+ x = W(m);
+ n = W(s);
+ inv = 0;
+ if(n < 0){
+ n = -n;
+ inv = 1;
+ }
+ r = 1;
+ for(;;){
+ if(n&1)
+ r *= x;
+ if((n >>= 1) == 0)
+ break;
+ x *= x;
+ }
+ if(inv)
+ r = 1/r;
+ W(d) = r;
+}
+OP(iexpl)
+{
+ int inv;
+ WORD n;
+ LONG x, r;
+
+ x = V(m);
+ n = W(s);
+ inv = 0;
+ if(n < 0){
+ n = -n;
+ inv = 1;
+ }
+ r = 1;
+ for(;;){
+ if(n&1)
+ r *= x;
+ if((n >>= 1) == 0)
+ break;
+ x *= x;
+ }
+ if(inv)
+ r = 1/r;
+ V(d) = r;
+}
+OP(iexpf)
+{
+ int inv;
+ WORD n;
+ REAL x, r;
+
+ x = F(m);
+ n = W(s);
+ inv = 0;
+ if(n < 0){
+ n = -n;
+ inv = 1;
+ }
+ r = 1;
+ for(;;){
+ if(n&1)
+ r *= x;
+ if((n >>= 1) == 0)
+ break;
+ x *= x;
+ }
+ if(inv)
+ r = 1/r;
+ F(d) = r;
+}
+OP(indx)
+{
+ ulong i;
+ Array *a;
+
+ a = A(s);
+ i = W(d);
+ if(a == H || i >= a->len)
+ error(exBounds);
+ W(m) = (WORD)(a->data+i*a->t->size);
+}
+OP(indw)
+{
+ ulong i;
+ Array *a;
+
+ a = A(s);
+ i = W(d);
+ if(a == H || i >= a->len)
+ error(exBounds);
+ W(m) = (WORD)(a->data+i*sizeof(WORD));
+}
+OP(indf)
+{
+ ulong i;
+ Array *a;
+
+ a = A(s);
+ i = W(d);
+ if(a == H || i >= a->len)
+ error(exBounds);
+ W(m) = (WORD)(a->data+i*sizeof(REAL));
+}
+OP(indl)
+{
+ ulong i;
+ Array *a;
+
+ a = A(s);
+ i = W(d);
+ if(a == H || i >= a->len)
+ error(exBounds);
+ W(m) = (WORD)(a->data+i*sizeof(LONG));
+}
+OP(indb)
+{
+ ulong i;
+ Array *a;
+
+ a = A(s);
+ i = W(d);
+ if(a == H || i >= a->len)
+ error(exBounds);
+ W(m) = (WORD)(a->data+i*sizeof(BYTE));
+}
+OP(movp)
+{
+ Heap *h;
+ WORD *dv, *sv;
+
+ sv = P(s);
+ if(sv != H) {
+ h = D2H(sv);
+ h->ref++;
+ Setmark(h);
+ }
+ dv = P(d);
+ P(d) = sv;
+ destroy(dv);
+}
+OP(movmp)
+{
+ Type *t;
+
+ t = R.M->type[W(m)];
+
+ incmem(R.s, t);
+ if (t->np)
+ freeptrs(R.d, t);
+ memmove(R.d, R.s, t->size);
+}
+OP(new)
+{
+ Heap *h;
+ WORD **wp, *t;
+
+ h = heap(R.M->type[W(s)]);
+ wp = R.d;
+ t = *wp;
+ *wp = H2D(WORD*, h);
+ destroy(t);
+}
+OP(newz)
+{
+ Heap *h;
+ WORD **wp, *t;
+
+ h = heapz(R.M->type[W(s)]);
+ wp = R.d;
+ t = *wp;
+ *wp = H2D(WORD*, h);
+ destroy(t);
+}
+OP(mnewz)
+{
+ Heap *h;
+ WORD **wp, *t;
+ Modlink *ml;
+
+ ml = *(Modlink**)R.s;
+ if(ml == H)
+ error(exModule);
+ h = heapz(ml->type[W(m)]);
+ wp = R.d;
+ t = *wp;
+ *wp = H2D(WORD*, h);
+ destroy(t);
+}
+OP(frame)
+{
+ Type *t;
+ Frame *f;
+ uchar *nsp;
+
+ t = R.M->type[W(s)];
+ nsp = R.SP + t->size;
+ if(nsp >= R.TS) {
+ R.s = t;
+ extend();
+ T(d) = R.s;
+ return;
+ }
+ f = (Frame*)R.SP;
+ R.SP = nsp;
+ f->t = t;
+ f->mr = nil;
+ if (t->np)
+ initmem(t, f);
+ T(d) = f;
+}
+OP(mframe)
+{
+ Type *t;
+ Frame *f;
+ uchar *nsp;
+ Modlink *ml;
+ int o;
+
+ ml = *(Modlink**)R.s;
+ if(ml == H)
+ error(exModule);
+
+ o = W(m);
+ if(o >= 0){
+ if(o >= ml->nlinks)
+ error("invalid mframe");
+ t = ml->links[o].frame;
+ }
+ else
+ t = ml->m->ext[-o-1].frame;
+ nsp = R.SP + t->size;
+ if(nsp >= R.TS) {
+ R.s = t;
+ extend();
+ T(d) = R.s;
+ return;
+ }
+ f = (Frame*)R.SP;
+ R.SP = nsp;
+ f->t = t;
+ f->mr = nil;
+ if (t->np)
+ initmem(t, f);
+ T(d) = f;
+}
+void
+acheck(int tsz, int sz)
+{
+ if(sz < 0)
+ error(exNegsize);
+ /* test for overflow; assumes sz >>> tsz */
+ if((int)(sizeof(Array) + sizeof(Heap) + tsz*sz) < sz && tsz != 0)
+ error(exHeap);
+}
+OP(newa)
+{
+ int sz;
+ Type *t;
+ Heap *h;
+ Array *a, *at, **ap;
+
+ t = R.M->type[W(m)];
+ sz = W(s);
+ acheck(t->size, sz);
+ h = nheap(sizeof(Array) + (t->size*sz));
+ h->t = &Tarray;
+ Tarray.ref++;
+ a = H2D(Array*, h);
+ a->t = t;
+ a->len = sz;
+ a->root = H;
+ a->data = (uchar*)a + sizeof(Array);
+ initarray(t, a);
+
+ ap = R.d;
+ at = *ap;
+ *ap = a;
+ destroy(at);
+}
+OP(newaz)
+{
+ int sz;
+ Type *t;
+ Heap *h;
+ Array *a, *at, **ap;
+
+ t = R.M->type[W(m)];
+ sz = W(s);
+ acheck(t->size, sz);
+ h = nheap(sizeof(Array) + (t->size*sz));
+ h->t = &Tarray;
+ Tarray.ref++;
+ a = H2D(Array*, h);
+ a->t = t;
+ a->len = sz;
+ a->root = H;
+ a->data = (uchar*)a + sizeof(Array);
+ memset(a->data, 0, t->size*sz);
+ initarray(t, a);
+
+ ap = R.d;
+ at = *ap;
+ *ap = a;
+ destroy(at);
+}
+Channel*
+cnewc(Type *t, void (*mover)(void), int len)
+{
+ Heap *h;
+ Channel *c;
+
+ h = heap(&Tchannel);
+ c = H2D(Channel*, h);
+ c->send = malloc(sizeof(Progq));
+ c->recv = malloc(sizeof(Progq));
+ if(c->send == nil || c->recv == nil){
+ free(c->send);
+ free(c->recv);
+ error(exNomem);
+ }
+ c->send->prog = c->recv->prog = nil;
+ c->send->next = c->recv->next = nil;
+ c->mover = mover;
+ c->buf = H;
+ if(len > 0)
+ c->buf = H2D(Array*, heaparray(t, len));
+ c->front = 0;
+ c->size = 0;
+ if(mover == movtmp){
+ c->mid.t = t;
+ t->ref++;
+ }
+ return c;
+}
+Channel*
+newc(Type *t, void (*mover)(void))
+{
+ Channel **cp, *oldc;
+ WORD len;
+
+ len = 0;
+ if(R.m != R.d){
+ len = W(m);
+ if(len < 0)
+ error(exNegsize);
+ }
+ cp = R.d;
+ oldc = *cp;
+ *cp = cnewc(t, mover, len);
+ destroy(oldc);
+ return *cp;
+}
+OP(newcl) { newc(&Tlong, movl); }
+OP(newcb) { newc(&Tbyte, movb); }
+OP(newcw) { newc(&Tword, movw); }
+OP(newcf) { newc(&Treal, movf); }
+OP(newcp) { newc(&Tptr, movp); }
+OP(newcm)
+{
+ Channel *c;
+ Type *t;
+
+ t = nil;
+ if(R.m != R.d && W(m) > 0)
+ t = dtype(nil, W(s), nil, 0);
+ c = newc(t, movm);
+ c->mid.w = W(s);
+ if(t != nil)
+ freetype(t);
+}
+OP(newcmp)
+{
+ newc(R.M->type[W(s)], movtmp);
+}
+OP(icase)
+{
+ WORD v, *t, *l, d, n, n2;
+
+ v = W(s);
+ t = (WORD*)((WORD)R.d + IBY2WD);
+ n = t[-1];
+ d = t[n*3];
+
+ while(n > 0) {
+ n2 = n >> 1;
+ l = t + n2*3;
+ if(v < l[0]) {
+ n = n2;
+ continue;
+ }
+ if(v >= l[1]) {
+ t = l+3;
+ n -= n2 + 1;
+ continue;
+ }
+ d = l[2];
+ break;
+ }
+ if(R.M->compiled) {
+ R.PC = (Inst*)d;
+ return;
+ }
+ R.PC = R.M->prog + d;
+}
+OP(casel)
+{
+ WORD *t, *l, d, n, n2;
+ LONG v;
+
+ v = V(s);
+ t = (WORD*)((WORD)R.d + 2*IBY2WD);
+ n = t[-2];
+ d = t[n*6];
+
+ while(n > 0) {
+ n2 = n >> 1;
+ l = t + n2*6;
+ if(v < ((LONG*)l)[0]) {
+ n = n2;
+ continue;
+ }
+ if(v >= ((LONG*)l)[1]) {
+ t = l+6;
+ n -= n2 + 1;
+ continue;
+ }
+ d = l[4];
+ break;
+ }
+ if(R.M->compiled) {
+ R.PC = (Inst*)d;
+ return;
+ }
+ R.PC = R.M->prog + d;
+}
+OP(casec)
+{
+ WORD *l, *t, *e, n, n2, r;
+ String *sl, *sh, *sv;
+
+ sv = S(s);
+ t = (WORD*)((WORD)R.d + IBY2WD);
+ n = t[-1];
+ e = t + n*3;
+ if(n > 2){
+ while(n > 0){
+ n2 = n>>1;
+ l = t + n2*3;
+ sl = (String*)l[0];
+ r = stringcmp(sv, sl);
+ if(r == 0){
+ e = &l[2];
+ break;
+ }
+ if(r < 0){
+ n = n2;
+ continue;
+ }
+ sh = (String*)l[1];
+ if(sh == H || stringcmp(sv, sh) > 0){
+ t = l+3;
+ n -= n2+1;
+ continue;
+ }
+ e = &l[2];
+ break;
+ }
+ t = e;
+ }
+ else{
+ while(t < e) {
+ sl = (String*)t[0];
+ sh = (String*)t[1];
+ if(sh == H) {
+ if(stringcmp(sl, sv) == 0) {
+ t = &t[2];
+ goto found;
+ }
+ }
+ else
+ if(stringcmp(sl, sv) <= 0 && stringcmp(sh, sv) >= 0) {
+ t = &t[2];
+ goto found;
+ }
+ t += 3;
+ }
+ }
+found:
+ if(R.M->compiled) {
+ R.PC = (Inst*)*t;
+ return;
+ }
+ R.PC = R.M->prog + t[0];
+}
+OP(igoto)
+{
+ WORD *t;
+
+ t = (WORD*)((WORD)R.d + (W(s) * IBY2WD));
+ if(R.M->compiled) {
+ R.PC = (Inst*)t[0];
+ return;
+ }
+ R.PC = R.M->prog + t[0];
+}
+OP(call)
+{
+ Frame *f;
+
+ f = T(s);
+ f->lr = R.PC;
+ f->fp = R.FP;
+ R.FP = (uchar*)f;
+ JMP(d);
+}
+OP(spawn)
+{
+ Prog *p;
+
+ p = newprog(currun(), R.M);
+ p->R.PC = *(Inst**)R.d;
+ newstack(p);
+ unframe();
+}
+OP(mspawn)
+{
+ Prog *p;
+ Modlink *ml;
+ int o;
+
+ ml = *(Modlink**)R.d;
+ if(ml == H)
+ error(exModule);
+ if(ml->prog == nil)
+ error(exSpawn);
+ p = newprog(currun(), ml);
+ o = W(m);
+ if(o >= 0)
+ p->R.PC = ml->links[o].u.pc;
+ else
+ p->R.PC = ml->m->ext[-o-1].u.pc;
+ newstack(p);
+ unframe();
+}
+OP(ret)
+{
+ Frame *f;
+ Modlink *m;
+
+ f = (Frame*)R.FP;
+ R.FP = f->fp;
+ if(R.FP == nil) {
+ R.FP = (uchar*)f;
+ error("");
+ }
+ R.SP = (uchar*)f;
+ R.PC = f->lr;
+ m = f->mr;
+
+ if(f->t == nil)
+ unextend(f);
+ else if (f->t->np)
+ freeptrs(f, f->t);
+
+ if(m != nil) {
+ if(R.M->compiled != m->compiled) {
+ R.IC = 1;
+ R.t = 1;
+ }
+ destroy(R.M);
+ R.M = m;
+ R.MP = m->MP;
+ }
+}
+OP(iload)
+{
+ char *n;
+ Import *ldt;
+ Module *m;
+ Modlink *ml, **mp, *t;
+ Heap *h;
+
+ n = string2c(S(s));
+ m = R.M->m;
+ if(m->rt & HASLDT)
+ ldt = m->ldt[W(m)];
+ else{
+ ldt = nil;
+ error("obsolete dis");
+ }
+
+ if(strcmp(n, "$self") == 0) {
+ m->ref++;
+ ml = linkmod(m, ldt, 0);
+ if(ml != H) {
+ ml->MP = R.M->MP;
+ h = D2H(ml->MP);
+ h->ref++;
+ Setmark(h);
+ }
+ }
+ else {
+ m = readmod(n, lookmod(n), 1);
+ ml = linkmod(m, ldt, 1);
+ }
+
+ mp = R.d;
+ t = *mp;
+ *mp = ml;
+ destroy(t);
+}
+OP(mcall)
+{
+ Heap *h;
+ Prog *p;
+ Frame *f;
+ Linkpc *l;
+ Modlink *ml;
+ int o;
+
+ ml = *(Modlink**)R.d;
+ if(ml == H)
+ error(exModule);
+ f = T(s);
+ f->lr = R.PC;
+ f->fp = R.FP;
+ f->mr = R.M;
+
+ R.FP = (uchar*)f;
+ R.M = ml;
+ h = D2H(ml);
+ h->ref++;
+
+ o = W(m);
+ if(o >= 0)
+ l = &ml->links[o].u;
+ else
+ l = &ml->m->ext[-o-1].u;
+ if(ml->prog == nil) {
+ l->runt(f);
+ h->ref--;
+ R.M = f->mr;
+ R.SP = R.FP;
+ R.FP = f->fp;
+ if(f->t == nil)
+ unextend(f);
+ else if (f->t->np)
+ freeptrs(f, f->t);
+ p = currun();
+ if(p->kill != nil)
+ error(p->kill);
+ R.t = 0;
+ return;
+ }
+ R.MP = R.M->MP;
+ R.PC = l->pc;
+ R.t = 1;
+
+ if(f->mr->compiled != R.M->compiled)
+ R.IC = 1;
+}
+OP(lena)
+{
+ WORD l;
+ Array *a;
+
+ a = A(s);
+ l = 0;
+ if(a != H)
+ l = a->len;
+ W(d) = l;
+}
+OP(lenl)
+{
+ WORD l;
+ List *a;
+
+ a = L(s);
+ l = 0;
+ while(a != H) {
+ l++;
+ a = a->tail;
+ }
+ W(d) = l;
+}
+static int
+cgetb(Channel *c, void *v)
+{
+ Array *a;
+ void *w;
+
+ if((a = c->buf) == H)
+ return 0;
+ if(c->size > 0){
+ w = a->data+c->front*a->t->size;
+ c->front++;
+ if(c->front == c->buf->len)
+ c->front = 0;
+ c->size--;
+ R.s = w;
+ R.m = &c->mid;
+ R.d = v;
+ c->mover();
+ if(a->t->np){
+ freeptrs(w, a->t);
+ initmem(a->t, w);
+ }
+ return 1;
+ }
+ return 0;
+}
+static int
+cputb(Channel *c, void *v)
+{
+ Array *a;
+ WORD len, r;
+
+ if((a = c->buf) == H)
+ return 0;
+ len = c->buf->len;
+ if(c->size < len){
+ r = c->front+c->size;
+ if(r >= len)
+ r -= len;
+ c->size++;
+ R.s = v;
+ R.m = &c->mid;
+ R.d = a->data+r*a->t->size;
+ c->mover();
+ return 1;
+ }
+ return 0;
+}
+/*
+int
+cqsize(Progq *q)
+{
+ int n;
+
+ n = 0;
+ for( ; q != nil; q = q->next)
+ if(q->prog != nil)
+ n++;
+ return n;
+}
+*/
+void
+cqadd(Progq **q, Prog *p)
+{
+ Progq *n;
+
+ if((*q)->prog == nil){
+ (*q)->prog = p;
+ return;
+ }
+ n = (Progq*)malloc(sizeof(Progq));
+ if(n == nil)
+ error(exNomem);
+ n->prog = p;
+ n->next = nil;
+ for( ; *q != nil; q = &(*q)->next)
+ ;
+ *q = n;
+}
+void
+cqdel(Progq **q)
+{
+ Progq *f;
+
+ if((*q)->next == nil){
+ (*q)->prog = nil;
+ return;
+ }
+ f = *q;
+ *q = f->next;
+ free(f);
+}
+void
+cqdelp(Progq **q, Prog *p)
+{
+ Progq *f;
+
+ if((*q)->next == nil){
+ if((*q)->prog == p)
+ (*q)->prog = nil;
+ return;
+ }
+ for( ; *q != nil; ){
+ if((*q)->prog == p){
+ f = *q;
+ *q = (*q)->next;
+ free(f);
+ }
+ else
+ q = &(*q)->next;
+ }
+}
+OP(isend)
+{
+ Channel *c;
+ Prog *p;
+
+ c = C(d);
+ if(c == H)
+ error(exNilref);
+
+ if((p = c->recv->prog) == nil) {
+ if(c->buf != H && cputb(c, R.s))
+ return;
+ p = delrun(Psend);
+ p->ptr = R.s;
+ p->chan = c; /* for killprog */
+ R.IC = 1;
+ R.t = 1;
+ cqadd(&c->send, p);
+ return;
+ }
+
+ if(c->buf != H && c->size > 0)
+ print("non-empty buffer in isend\n");
+
+ cqdel(&c->recv);
+ if(p->state == Palt)
+ altdone(p->R.s, p, c, 1);
+
+ R.m = &c->mid;
+ R.d = p->ptr;
+ p->ptr = nil;
+ c->mover();
+ addrun(p);
+ R.t = 0;
+}
+OP(irecv)
+{
+ Channel *c;
+ Prog *p;
+
+ c = C(s);
+ if(c == H)
+ error(exNilref);
+
+ if((p = c->send->prog) == nil) {
+ if(c->buf != H && cgetb(c, R.d))
+ return;
+ p = delrun(Precv);
+ p->ptr = R.d;
+ p->chan = c; /* for killprog */
+ R.IC = 1;
+ R.t = 1;
+ cqadd(&c->recv, p);
+ return;
+ }
+
+ if(c->buf != H && c->size != c->buf->len)
+ print("non-full buffer in irecv\n");
+
+ cqdel(&c->send);
+ if(p->state == Palt)
+ altdone(p->R.s, p, c, 0);
+
+ if(c->buf != H){
+ cgetb(c, R.d);
+ cputb(c, p->ptr);
+ p->ptr = nil;
+ }
+ else{
+ R.m = &c->mid;
+ R.s = p->ptr;
+ p->ptr = nil;
+ c->mover();
+ }
+ addrun(p);
+ R.t = 0;
+}
+int
+csendalt(Channel *c, void *ip, Type *t, int len)
+{
+ REG rsav;
+
+ if(c == H)
+ error(exNilref);
+
+ if(c->recv->prog == nil && (c->buf == H || c->size == c->buf->len)){
+ if(c->buf != H){
+ print("csendalt failed\n");
+ freeptrs(ip, t);
+ return 0;
+ }
+ c->buf = H2D(Array*, heaparray(t, len));
+ }
+
+ rsav = R;
+ R.s = ip;
+ R.d = &c;
+ isend();
+ R = rsav;
+ freeptrs(ip, t);
+ return 1;
+}
+
+List*
+cons(ulong size, List **lp)
+{
+ Heap *h;
+ List *lv, *l;
+
+ h = nheap(sizeof(List) + size - sizeof(((List*)0)->data));
+ h->t = &Tlist;
+ Tlist.ref++;
+ l = H2D(List*, h);
+ l->t = nil;
+
+ lv = *lp;
+ if(lv != H) {
+ h = D2H(lv);
+ Setmark(h);
+ }
+ l->tail = lv;
+ *lp = l;
+ return l;
+}
+OP(consb)
+{
+ List *l;
+
+ l = cons(IBY2WD, R.d);
+ *(BYTE*)l->data = B(s);
+}
+OP(consw)
+{
+ List *l;
+
+ l = cons(IBY2WD, R.d);
+ *(WORD*)l->data = W(s);
+}
+OP(consl)
+{
+ List *l;
+
+ l = cons(IBY2LG, R.d);
+ *(LONG*)l->data = V(s);
+}
+OP(consp)
+{
+ List *l;
+ Heap *h;
+ WORD *sv;
+
+ l = cons(IBY2WD, R.d);
+ sv = P(s);
+ if(sv != H) {
+ h = D2H(sv);
+ h->ref++;
+ Setmark(h);
+ }
+ l->t = &Tptr;
+ Tptr.ref++;
+ *(WORD**)l->data = sv;
+}
+OP(consf)
+{
+ List *l;
+
+ l = cons(sizeof(REAL), R.d);
+ *(REAL*)l->data = F(s);
+}
+OP(consm)
+{
+ int v;
+ List *l;
+
+ v = W(m);
+ l = cons(v, R.d);
+ memmove(l->data, R.s, v);
+}
+OP(consmp)
+{
+ List *l;
+ Type *t;
+
+ t = R.M->type[W(m)];
+ l = cons(t->size, R.d);
+ incmem(R.s, t);
+ memmove(l->data, R.s, t->size);
+ l->t = t;
+ t->ref++;
+}
+OP(headb)
+{
+ List *l;
+
+ l = L(s);
+ B(d) = *(BYTE*)l->data;
+}
+OP(headw)
+{
+ List *l;
+
+ l = L(s);
+ W(d) = *(WORD*)l->data;
+}
+OP(headl)
+{
+ List *l;
+
+ l = L(s);
+ V(d) = *(LONG*)l->data;
+}
+OP(headp)
+{
+ List *l;
+
+ l = L(s);
+ R.s = l->data;
+ movp();
+}
+OP(headf)
+{
+ List *l;
+
+ l = L(s);
+ F(d) = *(REAL*)l->data;
+}
+OP(headm)
+{
+ List *l;
+
+ l = L(s);
+ memmove(R.d, l->data, W(m));
+}
+OP(headmp)
+{
+ List *l;
+
+ l = L(s);
+ R.s = l->data;
+ movmp();
+}
+OP(tail)
+{
+ List *l;
+
+ l = L(s);
+ R.s = &l->tail;
+ movp();
+}
+OP(slicea)
+{
+ Type *t;
+ Heap *h;
+ Array *at, *ss, *ds;
+ int v, n, start;
+
+ v = W(m);
+ start = W(s);
+ n = v - start;
+ ds = A(d);
+
+ if(ds == H) {
+ if(n == 0)
+ return;
+ error(exNilref);
+ }
+ if(n < 0 || (ulong)start > ds->len || (ulong)v > ds->len)
+ error(exBounds);
+
+ t = ds->t;
+ h = heap(&Tarray);
+ ss = H2D(Array*, h);
+ ss->len = n;
+ ss->data = ds->data + start*t->size;
+ ss->t = t;
+ t->ref++;
+
+ if(ds->root != H) { /* slicing a slice */
+ ds = ds->root;
+ h = D2H(ds);
+ h->ref++;
+ at = A(d);
+ A(d) = ss;
+ ss->root = ds;
+ destroy(at);
+ }
+ else {
+ h = D2H(ds);
+ ss->root = ds;
+ A(d) = ss;
+ }
+ Setmark(h);
+}
+OP(slicela)
+{
+ Type *t;
+ int l, dl;
+ Array *ss, *ds;
+ uchar *sp, *dp, *ep;
+
+ ss = A(s);
+ dl = W(m);
+ ds = A(d);
+ if(ss == H)
+ return;
+ if(ds == H)
+ error(exNilref);
+ if(dl < 0 || dl+ss->len > ds->len)
+ error(exBounds);
+
+ t = ds->t;
+ if(t->np == 0) {
+ memmove(ds->data+dl*t->size, ss->data, ss->len*t->size);
+ return;
+ }
+ sp = ss->data;
+ dp = ds->data+dl*t->size;
+
+ if(dp > sp) {
+ l = ss->len * t->size;
+ sp = ss->data + l;
+ ep = dp + l;
+ while(ep > dp) {
+ ep -= t->size;
+ sp -= t->size;
+ incmem(sp, t);
+ if (t->np)
+ freeptrs(ep, t);
+ }
+ }
+ else {
+ ep = dp + ss->len*t->size;
+ while(dp < ep) {
+ incmem(sp, t);
+ if (t->np)
+ freeptrs(dp, t);
+ dp += t->size;
+ sp += t->size;
+ }
+ }
+ memmove(ds->data+dl*t->size, ss->data, ss->len*t->size);
+}
+OP(alt)
+{
+ R.t = 0;
+ xecalt(1);
+}
+OP(nbalt)
+{
+ xecalt(0);
+}
+OP(tcmp)
+{
+ void *s, *d;
+
+ s = T(s);
+ d = T(d);
+ if(s != H && (d == H || D2H(s)->t != D2H(d)->t))
+ error(exTcheck);
+}
+OP(eclr)
+{
+ /* spare slot */
+}
+OP(badop)
+{
+ error(exOp);
+}
+OP(iraise)
+{
+ void *v;
+ Heap *h;
+ Prog *p;
+
+ p = currun();
+ v = T(s);
+ if(v == H)
+ error(exNilref);
+ p->exval = v;
+ h = D2H(v);
+ h->ref++;
+ if(h->t == &Tstring)
+ error(string2c((String*)v));
+ else
+ error(string2c(*(String**)v));
+}
+OP(mulx)
+{
+ WORD p;
+ LONG r;
+
+ p = Dtmp;
+ r = (LONG)W(m)*(LONG)W(s);
+ if(p >= 0)
+ r <<= p;
+ else
+ r >>= (-p);
+ W(d) = (WORD)r;
+}
+OP(divx)
+{
+ WORD p;
+ LONG s;
+
+ p = Dtmp;
+ s = (LONG)W(m);
+ if(p >= 0)
+ s <<= p;
+ else
+ s >>= (-p);
+ s /= (LONG)W(s);
+ W(d) = (WORD)s;
+}
+OP(cvtxx)
+{
+ WORD p;
+ LONG r;
+
+ p = W(m);
+ r = (LONG)W(s);
+ if(p >= 0)
+ r <<= p;
+ else
+ r >>= (-p);
+ W(d) = (WORD)r;
+}
+OP(mulx0)
+{
+ WORD x, y, p, a;
+ LONG r;
+
+ x = W(m);
+ y = W(s);
+ p = Dtmp;
+ a = Stmp;
+ if(x == 0 || y == 0){
+ W(d) = 0;
+ return;
+ }
+ r = (LONG)x*(LONG)y;
+ if(p >= 0)
+ r <<= p;
+ else
+ r >>= (-p);
+ r /= (LONG)a;
+ W(d) = (WORD)r;
+}
+OP(divx0)
+{
+ WORD x, y, p, b;
+ LONG s;
+
+ x = W(m);
+ y = W(s);
+ p = Dtmp;
+ b = Stmp;
+ if(x == 0){
+ W(d) = 0;
+ return;
+ }
+ s = (LONG)b*(LONG)x;
+ if(p >= 0)
+ s <<= p;
+ else
+ s >>= (-p);
+ s /= (LONG)y;
+ W(d) = (WORD)s;
+}
+OP(cvtxx0)
+{
+ WORD x, p, a;
+ LONG r;
+
+ x = W(s);
+ p = W(m);
+ a = Stmp;
+ if(x == 0){
+ W(d) = 0;
+ return;
+ }
+ r = (LONG)x;
+ if(p >= 0)
+ r <<= p;
+ else
+ r >>= (-p);
+ r /= (LONG)a;
+ W(d) = (WORD)r;
+}
+OP(mulx1)
+{
+ WORD x, y, p, a, v;
+ int vnz, wnz;
+ LONG w, r;
+
+ x = W(m);
+ y = W(s);
+ p = Dtmp;
+ a = Stmp;
+ if(x == 0 || y == 0){
+ W(d) = 0;
+ return;
+ }
+ vnz = p&2;
+ wnz = p&1;
+ p >>= 2;
+ v = 0;
+ w = 0;
+ if(vnz){
+ v = a-1;
+ if(x >= 0 && y < 0 || x < 0 && y >= 0)
+ v = -v;
+ }
+ if(wnz){
+ if((!vnz && (x > 0 && y < 0 || x < 0 && y > 0)) ||
+ (vnz && (x > 0 && y > 0 || x < 0 && y < 0)))
+ w = ((LONG)1<<(-p)) - 1;
+ }
+ r = (LONG)x*(LONG)y + w;
+ if(p >= 0)
+ r <<= p;
+ else
+ r >>= (-p);
+ r += (LONG)v;
+ r /= (LONG)a;
+ W(d) = (WORD)r;
+}
+OP(divx1)
+{
+ WORD x, y, p, b, v;
+ int vnz, wnz;
+ LONG w, s;
+
+ x = W(m);
+ y = W(s);
+ p = Dtmp;
+ b = Stmp;
+ if(x == 0){
+ W(d) = 0;
+ return;
+ }
+ vnz = p&2;
+ wnz = p&1;
+ p >>= 2;
+ v = 0;
+ w = 0;
+ if(vnz){
+ v = 1;
+ if(x >= 0 && y < 0 || x < 0 && y >= 0)
+ v = -v;
+ }
+ if(wnz){
+ if(x <= 0)
+ w = ((LONG)1<<(-p)) - 1;
+ }
+ s = (LONG)b*(LONG)x + w;
+ if(p >= 0)
+ s <<= p;
+ else
+ s >>= (-p);
+ s /= (LONG)y;
+ W(d) = (WORD)s + v;
+}
+OP(cvtxx1)
+{
+ WORD x, p, a, v;
+ int vnz, wnz;
+ LONG w, r;
+
+ x = W(s);
+ p = W(m);
+ a = Stmp;
+ if(x == 0){
+ W(d) = 0;
+ return;
+ }
+ vnz = p&2;
+ wnz = p&1;
+ p >>= 2;
+ v = 0;
+ w = 0;
+ if(vnz){
+ v = a-1;
+ if(x < 0)
+ v = -v;
+ }
+ if(wnz){
+ if(!vnz && x < 0 || vnz && x > 0)
+ w = ((LONG)1<<(-p)) - 1;
+ }
+ r = (LONG)x + w;
+ if(p >= 0)
+ r <<= p;
+ else
+ r >>= (-p);
+ r += (LONG)v;
+ r /= (LONG)a;
+ W(d) = (WORD)r;
+}
+/*
+OP(cvtxx)
+{
+ REAL v;
+
+ v = (REAL)W(s)*F(m);
+ v = v < 0 ? v-0.5: v+0.5;
+ W(d) = (WORD)v;
+}
+*/
+OP(cvtfx)
+{
+ REAL v;
+
+ v = F(s)*F(m);
+ v = v < 0 ? v-0.5: v+0.5;
+ W(d) = (WORD)v;
+}
+OP(cvtxf)
+{
+ F(d) = (REAL)W(s)*F(m);
+}
+
+OP(self)
+{
+ Modlink *ml, **mp, *t;
+ Heap *h;
+
+ ml = R.M;
+ h = D2H(ml);
+ h->ref++;
+ Setmark(h);
+ mp = R.d;
+ t = *mp;
+ *mp = ml;
+ destroy(t);
+}
+
+void
+destroystack(REG *reg)
+{
+ Type *t;
+ Frame *f, *fp;
+ Modlink *m;
+ Stkext *sx;
+ uchar *ex;
+
+ ex = reg->EX;
+ reg->EX = nil;
+ while(ex != nil) {
+ sx = (Stkext*)ex;
+ fp = sx->reg.tos.fr;
+ do {
+ f = (Frame*)reg->FP;
+ if(f == nil)
+ break;
+ reg->FP = f->fp;
+ t = f->t;
+ if(t == nil)
+ t = sx->reg.TR;
+ m = f->mr;
+ if (t->np)
+ freeptrs(f, t);
+ if(m != nil) {
+ destroy(reg->M);
+ reg->M = m;
+ }
+ } while(f != fp);
+ ex = sx->reg.EX;
+ free(sx);
+ }
+ destroy(reg->M);
+ reg->M = H; /* for devprof */
+}
+
+Prog*
+isave(void)
+{
+ Prog *p;
+
+ p = delrun(Prelease);
+ p->R = R;
+ return p;
+}
+
+void
+irestore(Prog *p)
+{
+ R = p->R;
+ R.IC = 1;
+}
+
+void
+movtmp(void) /* Used by send & receive */
+{
+ Type *t;
+
+ t = (Type*)W(m);
+
+ incmem(R.s, t);
+ if (t->np)
+ freeptrs(R.d, t);
+ memmove(R.d, R.s, t->size);
+}
+
+extern OP(cvtca);
+extern OP(cvtac);
+extern OP(cvtwc);
+extern OP(cvtcw);
+extern OP(cvtfc);
+extern OP(cvtcf);
+extern OP(insc);
+extern OP(indc);
+extern OP(addc);
+extern OP(lenc);
+extern OP(slicec);
+extern OP(cvtlc);
+
+#include "optab.h"
+
+void
+opinit(void)
+{
+ int i;
+
+ for(i = 0; i < 256; i++)
+ if(optab[i] == nil)
+ optab[i] = badop;
+}
+
+void
+xec(Prog *p)
+{
+ int op;
+
+ R = p->R;
+ R.MP = R.M->MP;
+ R.IC = p->quanta;
+
+ if(p->kill != nil) {
+ char *m;
+ m = p->kill;
+ p->kill = nil;
+ error(m);
+ }
+
+// print("%lux %lux %lux %lux %lux\n", (ulong)&R, R.xpc, R.FP, R.MP, R.PC);
+
+ if(R.M->compiled)
+ comvec();
+ else do {
+ dec[R.PC->add]();
+ op = R.PC->op;
+ R.PC++;
+ optab[op]();
+ } while(--R.IC != 0);
+
+ p->R = R;
+}
--- /dev/null
+++ b/libkern/NOTICE
@@ -1,0 +1,29 @@
+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-2007 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.
+
--- /dev/null
+++ b/libkern/abort.c
@@ -1,0 +1,7 @@
+#include <lib9.h>
+void
+abort(void)
+{
+ while(*(int*)0)
+ ;
+}
--- /dev/null
+++ b/libkern/abs.c
@@ -1,0 +1,17 @@
+#include <lib9.h>
+
+int
+abs(int a)
+{
+ if(a < 0)
+ return -a;
+ return a;
+}
+
+long
+labs(long a)
+{
+ if(a < 0)
+ return -a;
+ return a;
+}
--- /dev/null
+++ b/libkern/atol.c
@@ -1,0 +1,47 @@
+#include <lib9.h>
+
+long
+atol(char *s)
+{
+ long n;
+ int f;
+
+ n = 0;
+ f = 0;
+ while(*s == ' ' || *s == '\t')
+ s++;
+ if(*s == '-' || *s == '+') {
+ if(*s++ == '-')
+ f = 1;
+ while(*s == ' ' || *s == '\t')
+ s++;
+ }
+ if(s[0]=='0' && s[1]){
+ if(s[1]=='x' || s[1]=='X'){
+ s += 2;
+ for(;;){
+ if(*s >= '0' && *s <= '9')
+ n = n*16 + *s++ - '0';
+ else if(*s >= 'a' && *s <= 'f')
+ n = n*16 + *s++ - 'a' + 10;
+ else if(*s >= 'A' && *s <= 'F')
+ n = n*16 + *s++ - 'A' + 10;
+ else
+ break;
+ }
+ } else
+ while(*s >= '0' && *s <= '7')
+ n = n*8 + *s++ - '0';
+ } else
+ while(*s >= '0' && *s <= '9')
+ n = n*10 + *s++ - '0';
+ if(f)
+ n = -n;
+ return n;
+}
+
+atoi(char *s)
+{
+
+ return atol(s);
+}
--- /dev/null
+++ b/libkern/charstod.c
@@ -1,0 +1,80 @@
+#include "lib9.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.
+ */
+
+#define ADVANCE *s++ = c; if(s>=e) return NaN(); c = (*f)(vp)
+
+double
+charstod(int(*f)(void*), void *vp)
+{
+ char str[400], *s, *e, *start;
+ int c;
+
+ s = str;
+ e = str + sizeof str - 1;
+ c = (*f)(vp);
+ while(c == ' ' || c == '\t')
+ c = (*f)(vp);
+ if(c == '-' || c == '+'){
+ ADVANCE;
+ }
+ start = s;
+ while(c >= '0' && c <= '9'){
+ ADVANCE;
+ }
+ if(c == '.'){
+ ADVANCE;
+ while(c >= '0' && c <= '9'){
+ ADVANCE;
+ }
+ }
+ if(s > start && (c == 'e' || c == 'E')){
+ ADVANCE;
+ if(c == '-' || c == '+'){
+ ADVANCE;
+ }
+ while(c >= '0' && c <= '9'){
+ ADVANCE;
+ }
+ }else if(s == start && (c == 'i' || c == 'I')){
+ ADVANCE;
+ if(c != 'n' && c != 'N')
+ return NaN();
+ ADVANCE;
+ if(c != 'f' && c != 'F')
+ return NaN();
+ ADVANCE;
+ if(c != 'i' && c != 'I')
+ return NaN();
+ ADVANCE;
+ if(c != 'n' && c != 'N')
+ return NaN();
+ ADVANCE;
+ if(c != 'i' && c != 'I')
+ return NaN();
+ ADVANCE;
+ if(c != 't' && c != 'T')
+ return NaN();
+ ADVANCE;
+ if(c != 'y' && c != 'Y')
+ return NaN();
+ ADVANCE; /* so caller can back up uniformly */
+ USED(c);
+ }else if(s == str && (c == 'n' || c == 'N')){
+ ADVANCE;
+ if(c != 'a' && c != 'A')
+ return NaN();
+ ADVANCE;
+ if(c != 'n' && c != 'N')
+ return NaN();
+ ADVANCE; /* so caller can back up uniformly */
+ USED(c);
+ }
+ *s = 0;
+ return strtod(str, &s);
+}
--- /dev/null
+++ b/libkern/cistrcmp.c
@@ -1,0 +1,25 @@
+#include "lib9.h"
+
+int
+cistrcmp(char *s1, char *s2)
+{
+ int c1, c2;
+
+ while(*s1){
+ c1 = *(uchar*)s1++;
+ c2 = *(uchar*)s2++;
+
+ if(c1 == c2)
+ continue;
+
+ if(c1 >= 'A' && c1 <= 'Z')
+ c1 -= 'A' - 'a';
+
+ if(c2 >= 'A' && c2 <= 'Z')
+ c2 -= 'A' - 'a';
+
+ if(c1 != c2)
+ return c1 - c2;
+ }
+ return -*s2;
+}
--- /dev/null
+++ b/libkern/cistrncmp.c
@@ -1,0 +1,27 @@
+#include "lib9.h"
+
+int
+cistrncmp(char *s1, char *s2, int n)
+{
+ int c1, c2;
+
+ while(*s1 && n-- > 0){
+ c1 = *(uchar*)s1++;
+ c2 = *(uchar*)s2++;
+
+ if(c1 == c2)
+ continue;
+
+ if(c1 >= 'A' && c1 <= 'Z')
+ c1 -= 'A' - 'a';
+
+ if(c2 >= 'A' && c2 <= 'Z')
+ c2 -= 'A' - 'a';
+
+ if(c1 != c2)
+ return c1 - c2;
+ }
+ if(n <= 0)
+ return 0;
+ return -*s2;
+}
--- /dev/null
+++ b/libkern/cistrstr.c
@@ -1,0 +1,22 @@
+#include "lib9.h"
+
+char*
+cistrstr(char *s, char *sub)
+{
+ int c, csub, n;
+
+ csub = *sub;
+ if(csub == '\0')
+ return s;
+ if(csub >= 'A' && csub <= 'Z')
+ csub -= 'A' - 'a';
+ sub++;
+ n = strlen(sub);
+ for(; c = *s; s++){
+ if(c >= 'A' && c <= 'Z')
+ c -= 'A' - 'a';
+ if(c == csub && cistrncmp(s+1, sub, n) == 0)
+ return s;
+ }
+ return nil;
+}
--- /dev/null
+++ b/libkern/cleanname.c
@@ -1,0 +1,62 @@
+#include "lib9.h"
+
+/*
+ * In place, rewrite name to compress multiple /, eliminate ., and process ..
+ */
+#define SEP(x) ((x)=='/' || (x) == 0)
+char*
+cleanname(char *name)
+{
+ char *p, *q, *dotdot;
+ int rooted, erasedprefix;
+
+ rooted = name[0] == '/';
+ erasedprefix = 0;
+
+ /*
+ * invariants:
+ * p points at beginning of path element we're considering.
+ * q points just past the last path element we wrote (no slash).
+ * dotdot points just past the point where .. cannot backtrack
+ * any further (no slash).
+ */
+ p = q = dotdot = name+rooted;
+ while(*p) {
+ if(p[0] == '/') /* null element */
+ p++;
+ else if(p[0] == '.' && SEP(p[1])) {
+ if(p == name)
+ erasedprefix = 1;
+ p += 1; /* don't count the separator in case it is nul */
+ } else if(p[0] == '.' && p[1] == '.' && SEP(p[2])) {
+ p += 2;
+ if(q > dotdot) { /* can backtrack */
+ while(--q > dotdot && *q != '/')
+ ;
+ } else if(!rooted) { /* /.. is / but ./../ is .. */
+ if(q != name)
+ *q++ = '/';
+ *q++ = '.';
+ *q++ = '.';
+ dotdot = q;
+ }
+ if(q == name)
+ erasedprefix = 1; /* erased entire path via dotdot */
+ } else { /* real path element */
+ if(q != name+rooted)
+ *q++ = '/';
+ while((*q = *p) != '/' && *q != 0)
+ p++, q++;
+ }
+ }
+ if(q == name) /* empty string is really ``.'' */
+ *q++ = '.';
+ *q = '\0';
+ if(erasedprefix && name[0] == '#'){
+ /* this was not a #x device path originally - make it not one now */
+ memmove(name+2, name, strlen(name)+1);
+ name[0] = '.';
+ name[1] = '/';
+ }
+ return name;
+}
--- /dev/null
+++ b/libkern/convD2M.c
@@ -1,0 +1,94 @@
+#include "lib9.h"
+#include "fcall.h"
+
+uint
+sizeD2M(Dir *d)
+{
+ char *sv[4];
+ int i, ns;
+
+ sv[0] = d->name;
+ sv[1] = d->uid;
+ sv[2] = d->gid;
+ sv[3] = d->muid;
+
+ ns = 0;
+ for(i = 0; i < 4; i++)
+ if(sv[i])
+ ns += strlen(sv[i]);
+
+ return STATFIXLEN + ns;
+}
+
+uint
+convD2M(Dir *d, uchar *buf, uint nbuf)
+{
+ uchar *p, *ebuf;
+ char *sv[4];
+ int i, ns, nsv[4], ss;
+
+ if(nbuf < BIT16SZ)
+ return 0;
+
+ p = buf;
+ ebuf = buf + nbuf;
+
+ sv[0] = d->name;
+ sv[1] = d->uid;
+ sv[2] = d->gid;
+ sv[3] = d->muid;
+
+ ns = 0;
+ for(i = 0; i < 4; i++){
+ if(sv[i])
+ nsv[i] = strlen(sv[i]);
+ else
+ nsv[i] = 0;
+ ns += nsv[i];
+ }
+
+ ss = STATFIXLEN + ns;
+
+ /* set size befor erroring, so user can know how much is needed */
+ /* note that length excludes count field itself */
+ PBIT16(p, ss-BIT16SZ);
+ p += BIT16SZ;
+
+ if(ss > nbuf)
+ return BIT16SZ;
+
+ PBIT16(p, d->type);
+ p += BIT16SZ;
+ PBIT32(p, d->dev);
+ p += BIT32SZ;
+ PBIT8(p, d->qid.type);
+ p += BIT8SZ;
+ PBIT32(p, d->qid.vers);
+ p += BIT32SZ;
+ PBIT64(p, d->qid.path);
+ p += BIT64SZ;
+ PBIT32(p, d->mode);
+ p += BIT32SZ;
+ PBIT32(p, d->atime);
+ p += BIT32SZ;
+ PBIT32(p, d->mtime);
+ p += BIT32SZ;
+ PBIT64(p, d->length);
+ p += BIT64SZ;
+
+ for(i = 0; i < 4; i++){
+ ns = nsv[i];
+ if(p + ns + BIT16SZ > ebuf)
+ return 0;
+ PBIT16(p, ns);
+ p += BIT16SZ;
+ if(ns)
+ memmove(p, sv[i], ns);
+ p += ns;
+ }
+
+ if(ss != p - buf)
+ return 0;
+
+ return p - buf;
+}
--- /dev/null
+++ b/libkern/convM2D.c
@@ -1,0 +1,93 @@
+#include "lib9.h"
+#include "fcall.h"
+
+int
+statcheck(uchar *buf, uint nbuf)
+{
+ uchar *ebuf;
+ int i;
+
+ ebuf = buf + nbuf;
+
+ if(nbuf < STATFIXLEN || nbuf != BIT16SZ + GBIT16(buf))
+ return -1;
+
+ buf += STATFIXLEN - 4 * BIT16SZ;
+
+ for(i = 0; i < 4; i++){
+ if(buf + BIT16SZ > ebuf)
+ return -1;
+ buf += BIT16SZ + GBIT16(buf);
+ }
+
+ if(buf != ebuf)
+ return -1;
+
+ return 0;
+}
+
+static char nullstring[] = "";
+
+uint
+convM2D(uchar *buf, uint nbuf, Dir *d, char *strs)
+{
+ uchar *p, *ebuf;
+ char *sv[4];
+ int i, ns;
+
+ if(nbuf < STATFIXLEN)
+ return 0;
+
+ p = buf;
+ ebuf = buf + nbuf;
+
+ p += BIT16SZ; /* ignore size */
+ d->type = GBIT16(p);
+ p += BIT16SZ;
+ d->dev = GBIT32(p);
+ p += BIT32SZ;
+ d->qid.type = GBIT8(p);
+ p += BIT8SZ;
+ d->qid.vers = GBIT32(p);
+ p += BIT32SZ;
+ d->qid.path = GBIT64(p);
+ p += BIT64SZ;
+ d->mode = GBIT32(p);
+ p += BIT32SZ;
+ d->atime = GBIT32(p);
+ p += BIT32SZ;
+ d->mtime = GBIT32(p);
+ p += BIT32SZ;
+ d->length = GBIT64(p);
+ p += BIT64SZ;
+
+ for(i = 0; i < 4; i++){
+ if(p + BIT16SZ > ebuf)
+ return 0;
+ ns = GBIT16(p);
+ p += BIT16SZ;
+ if(p + ns > ebuf)
+ return 0;
+ if(strs){
+ sv[i] = strs;
+ memmove(strs, p, ns);
+ strs += ns;
+ *strs++ = '\0';
+ }
+ p += ns;
+ }
+
+ if(strs){
+ d->name = sv[0];
+ d->uid = sv[1];
+ d->gid = sv[2];
+ d->muid = sv[3];
+ }else{
+ d->name = nullstring;
+ d->uid = nullstring;
+ d->gid = nullstring;
+ d->muid = nullstring;
+ }
+
+ return p - buf;
+}
--- /dev/null
+++ b/libkern/convM2S.c
@@ -1,0 +1,314 @@
+#include "lib9.h"
+#include "fcall.h"
+
+static
+uchar*
+gstring(uchar *p, uchar *ep, char **s)
+{
+ uint n;
+
+ if(p+BIT16SZ > ep)
+ return nil;
+ n = GBIT16(p);
+ p += BIT16SZ - 1;
+ if(p+n+1 > ep)
+ return nil;
+ /* move it down, on top of count, to make room for '\0' */
+ memmove(p, p + 1, n);
+ p[n] = '\0';
+ *s = (char*)p;
+ p += n+1;
+ return p;
+}
+
+static
+uchar*
+gqid(uchar *p, uchar *ep, Qid *q)
+{
+ if(p+QIDSZ > ep)
+ return nil;
+ q->type = GBIT8(p);
+ p += BIT8SZ;
+ q->vers = GBIT32(p);
+ p += BIT32SZ;
+ q->path = GBIT64(p);
+ p += BIT64SZ;
+ return p;
+}
+
+/*
+ * no syntactic checks.
+ * three causes for error:
+ * 1. message size field is incorrect
+ * 2. input buffer too short for its own data (counts too long, etc.)
+ * 3. too many names or qids
+ * gqid() and gstring() return nil if they would reach beyond buffer.
+ * main switch statement checks range and also can fall through
+ * to test at end of routine.
+ */
+uint
+convM2S(uchar *ap, uint nap, Fcall *f)
+{
+ uchar *p, *ep;
+ uint i, size;
+
+ p = ap;
+ ep = p + nap;
+
+ if(p+BIT32SZ+BIT8SZ+BIT16SZ > ep)
+ return 0;
+ size = GBIT32(p);
+ p += BIT32SZ;
+
+ if(size < BIT32SZ+BIT8SZ+BIT16SZ)
+ return 0;
+
+ f->type = GBIT8(p);
+ p += BIT8SZ;
+ f->tag = GBIT16(p);
+ p += BIT16SZ;
+
+ switch(f->type)
+ {
+ default:
+ return 0;
+
+ case Tversion:
+ if(p+BIT32SZ > ep)
+ return 0;
+ f->msize = GBIT32(p);
+ p += BIT32SZ;
+ p = gstring(p, ep, &f->version);
+ break;
+
+ case Tflush:
+ if(p+BIT16SZ > ep)
+ return 0;
+ f->oldtag = GBIT16(p);
+ p += BIT16SZ;
+ break;
+
+ case Tauth:
+ if(p+BIT32SZ > ep)
+ return 0;
+ f->afid = GBIT32(p);
+ p += BIT32SZ;
+ p = gstring(p, ep, &f->uname);
+ if(p == nil)
+ break;
+ p = gstring(p, ep, &f->aname);
+ if(p == nil)
+ break;
+ break;
+
+ case Tattach:
+ if(p+BIT32SZ > ep)
+ return 0;
+ f->fid = GBIT32(p);
+ p += BIT32SZ;
+ if(p+BIT32SZ > ep)
+ return 0;
+ f->afid = GBIT32(p);
+ p += BIT32SZ;
+ p = gstring(p, ep, &f->uname);
+ if(p == nil)
+ break;
+ p = gstring(p, ep, &f->aname);
+ if(p == nil)
+ break;
+ break;
+
+ case Twalk:
+ if(p+BIT32SZ+BIT32SZ+BIT16SZ > ep)
+ return 0;
+ f->fid = GBIT32(p);
+ p += BIT32SZ;
+ f->newfid = GBIT32(p);
+ p += BIT32SZ;
+ f->nwname = GBIT16(p);
+ p += BIT16SZ;
+ if(f->nwname > MAXWELEM)
+ return 0;
+ for(i=0; i<f->nwname; i++){
+ p = gstring(p, ep, &f->wname[i]);
+ if(p == nil)
+ break;
+ }
+ break;
+
+ case Topen:
+ if(p+BIT32SZ+BIT8SZ > ep)
+ return 0;
+ f->fid = GBIT32(p);
+ p += BIT32SZ;
+ f->mode = GBIT8(p);
+ p += BIT8SZ;
+ break;
+
+ case Tcreate:
+ if(p+BIT32SZ > ep)
+ return 0;
+ f->fid = GBIT32(p);
+ p += BIT32SZ;
+ p = gstring(p, ep, &f->name);
+ if(p == nil)
+ break;
+ if(p+BIT32SZ+BIT8SZ > ep)
+ return 0;
+ f->perm = GBIT32(p);
+ p += BIT32SZ;
+ f->mode = GBIT8(p);
+ p += BIT8SZ;
+ break;
+
+ case Tread:
+ if(p+BIT32SZ+BIT64SZ+BIT32SZ > ep)
+ return 0;
+ f->fid = GBIT32(p);
+ p += BIT32SZ;
+ f->offset = GBIT64(p);
+ p += BIT64SZ;
+ f->count = GBIT32(p);
+ p += BIT32SZ;
+ break;
+
+ case Twrite:
+ if(p+BIT32SZ+BIT64SZ+BIT32SZ > ep)
+ return 0;
+ f->fid = GBIT32(p);
+ p += BIT32SZ;
+ f->offset = GBIT64(p);
+ p += BIT64SZ;
+ f->count = GBIT32(p);
+ p += BIT32SZ;
+ if(p+f->count > ep)
+ return 0;
+ f->data = (char*)p;
+ p += f->count;
+ break;
+
+ case Tclunk:
+ case Tremove:
+ if(p+BIT32SZ > ep)
+ return 0;
+ f->fid = GBIT32(p);
+ p += BIT32SZ;
+ break;
+
+ case Tstat:
+ if(p+BIT32SZ > ep)
+ return 0;
+ f->fid = GBIT32(p);
+ p += BIT32SZ;
+ break;
+
+ case Twstat:
+ if(p+BIT32SZ+BIT16SZ > ep)
+ return 0;
+ f->fid = GBIT32(p);
+ p += BIT32SZ;
+ f->nstat = GBIT16(p);
+ p += BIT16SZ;
+ if(p+f->nstat > ep)
+ return 0;
+ f->stat = p;
+ p += f->nstat;
+ break;
+
+/*
+ */
+ case Rversion:
+ if(p+BIT32SZ > ep)
+ return 0;
+ f->msize = GBIT32(p);
+ p += BIT32SZ;
+ p = gstring(p, ep, &f->version);
+ break;
+
+ case Rerror:
+ p = gstring(p, ep, &f->ename);
+ break;
+
+ case Rflush:
+ break;
+
+ case Rauth:
+ p = gqid(p, ep, &f->aqid);
+ if(p == nil)
+ break;
+ break;
+
+ case Rattach:
+ p = gqid(p, ep, &f->qid);
+ if(p == nil)
+ break;
+ break;
+
+ case Rwalk:
+ if(p+BIT16SZ > ep)
+ return 0;
+ f->nwqid = GBIT16(p);
+ p += BIT16SZ;
+ if(f->nwqid > MAXWELEM)
+ return 0;
+ for(i=0; i<f->nwqid; i++){
+ p = gqid(p, ep, &f->wqid[i]);
+ if(p == nil)
+ break;
+ }
+ break;
+
+ case Ropen:
+ case Rcreate:
+ p = gqid(p, ep, &f->qid);
+ if(p == nil)
+ break;
+ if(p+BIT32SZ > ep)
+ return 0;
+ f->iounit = GBIT32(p);
+ p += BIT32SZ;
+ break;
+
+ case Rread:
+ if(p+BIT32SZ > ep)
+ return 0;
+ f->count = GBIT32(p);
+ p += BIT32SZ;
+ if(p+f->count > ep)
+ return 0;
+ f->data = (char*)p;
+ p += f->count;
+ break;
+
+ case Rwrite:
+ if(p+BIT32SZ > ep)
+ return 0;
+ f->count = GBIT32(p);
+ p += BIT32SZ;
+ break;
+
+ case Rclunk:
+ case Rremove:
+ break;
+
+ case Rstat:
+ if(p+BIT16SZ > ep)
+ return 0;
+ f->nstat = GBIT16(p);
+ p += BIT16SZ;
+ if(p+f->nstat > ep)
+ return 0;
+ f->stat = p;
+ p += f->nstat;
+ break;
+
+ case Rwstat:
+ break;
+ }
+
+ if(p==nil || p>ep)
+ return 0;
+ if(ap+size == p)
+ return size;
+ return 0;
+}
--- /dev/null
+++ b/libkern/convS2M.c
@@ -1,0 +1,385 @@
+#include "lib9.h"
+#include "fcall.h"
+
+static
+uchar*
+pstring(uchar *p, char *s)
+{
+ uint n;
+
+ if(s == nil){
+ PBIT16(p, 0);
+ p += BIT16SZ;
+ return p;
+ }
+
+ n = strlen(s);
+ PBIT16(p, n);
+ p += BIT16SZ;
+ memmove(p, s, n);
+ p += n;
+ return p;
+}
+
+static
+uchar*
+pqid(uchar *p, Qid *q)
+{
+ PBIT8(p, q->type);
+ p += BIT8SZ;
+ PBIT32(p, q->vers);
+ p += BIT32SZ;
+ PBIT64(p, q->path);
+ p += BIT64SZ;
+ return p;
+}
+
+static
+uint
+stringsz(char *s)
+{
+ if(s == nil)
+ return BIT16SZ;
+
+ return BIT16SZ+strlen(s);
+}
+
+uint
+sizeS2M(Fcall *f)
+{
+ uint n;
+ int i;
+
+ n = 0;
+ n += BIT32SZ; /* size */
+ n += BIT8SZ; /* type */
+ n += BIT16SZ; /* tag */
+
+ switch(f->type)
+ {
+ default:
+ return 0;
+
+ case Tversion:
+ n += BIT32SZ;
+ n += stringsz(f->version);
+ break;
+
+ case Tflush:
+ n += BIT16SZ;
+ break;
+
+ case Tauth:
+ n += BIT32SZ;
+ n += stringsz(f->uname);
+ n += stringsz(f->aname);
+ break;
+
+ case Tattach:
+ n += BIT32SZ;
+ n += BIT32SZ;
+ n += stringsz(f->uname);
+ n += stringsz(f->aname);
+ break;
+
+ case Twalk:
+ n += BIT32SZ;
+ n += BIT32SZ;
+ n += BIT16SZ;
+ for(i=0; i<f->nwname; i++)
+ n += stringsz(f->wname[i]);
+ break;
+
+ case Topen:
+ n += BIT32SZ;
+ n += BIT8SZ;
+ break;
+
+ case Tcreate:
+ n += BIT32SZ;
+ n += stringsz(f->name);
+ n += BIT32SZ;
+ n += BIT8SZ;
+ break;
+
+ case Tread:
+ n += BIT32SZ;
+ n += BIT64SZ;
+ n += BIT32SZ;
+ break;
+
+ case Twrite:
+ n += BIT32SZ;
+ n += BIT64SZ;
+ n += BIT32SZ;
+ n += f->count;
+ break;
+
+ case Tclunk:
+ case Tremove:
+ n += BIT32SZ;
+ break;
+
+ case Tstat:
+ n += BIT32SZ;
+ break;
+
+ case Twstat:
+ n += BIT32SZ;
+ n += BIT16SZ;
+ n += f->nstat;
+ break;
+/*
+ */
+
+ case Rversion:
+ n += BIT32SZ;
+ n += stringsz(f->version);
+ break;
+
+ case Rerror:
+ n += stringsz(f->ename);
+ break;
+
+ case Rflush:
+ break;
+
+ case Rauth:
+ n += QIDSZ;
+ break;
+
+ case Rattach:
+ n += QIDSZ;
+ break;
+
+ case Rwalk:
+ n += BIT16SZ;
+ n += f->nwqid*QIDSZ;
+ break;
+
+ case Ropen:
+ case Rcreate:
+ n += QIDSZ;
+ n += BIT32SZ;
+ break;
+
+ case Rread:
+ n += BIT32SZ;
+ n += f->count;
+ break;
+
+ case Rwrite:
+ n += BIT32SZ;
+ break;
+
+ case Rclunk:
+ break;
+
+ case Rremove:
+ break;
+
+ case Rstat:
+ n += BIT16SZ;
+ n += f->nstat;
+ break;
+
+ case Rwstat:
+ break;
+ }
+ return n;
+}
+
+uint
+convS2M(Fcall *f, uchar *ap, uint nap)
+{
+ uchar *p;
+ uint i, size;
+
+ size = sizeS2M(f);
+ if(size == 0)
+ return 0;
+ if(size > nap)
+ return 0;
+
+ p = (uchar*)ap;
+
+ PBIT32(p, size);
+ p += BIT32SZ;
+ PBIT8(p, f->type);
+ p += BIT8SZ;
+ PBIT16(p, f->tag);
+ p += BIT16SZ;
+
+ switch(f->type)
+ {
+ default:
+ return 0;
+
+ case Tversion:
+ PBIT32(p, f->msize);
+ p += BIT32SZ;
+ p = pstring(p, f->version);
+ break;
+
+ case Tflush:
+ PBIT16(p, f->oldtag);
+ p += BIT16SZ;
+ break;
+
+ case Tauth:
+ PBIT32(p, f->afid);
+ p += BIT32SZ;
+ p = pstring(p, f->uname);
+ p = pstring(p, f->aname);
+ break;
+
+ case Tattach:
+ PBIT32(p, f->fid);
+ p += BIT32SZ;
+ PBIT32(p, f->afid);
+ p += BIT32SZ;
+ p = pstring(p, f->uname);
+ p = pstring(p, f->aname);
+ break;
+
+ case Twalk:
+ PBIT32(p, f->fid);
+ p += BIT32SZ;
+ PBIT32(p, f->newfid);
+ p += BIT32SZ;
+ PBIT16(p, f->nwname);
+ p += BIT16SZ;
+ if(f->nwname > MAXWELEM)
+ return 0;
+ for(i=0; i<f->nwname; i++)
+ p = pstring(p, f->wname[i]);
+ break;
+
+ case Topen:
+ PBIT32(p, f->fid);
+ p += BIT32SZ;
+ PBIT8(p, f->mode);
+ p += BIT8SZ;
+ break;
+
+ case Tcreate:
+ PBIT32(p, f->fid);
+ p += BIT32SZ;
+ p = pstring(p, f->name);
+ PBIT32(p, f->perm);
+ p += BIT32SZ;
+ PBIT8(p, f->mode);
+ p += BIT8SZ;
+ break;
+
+ case Tread:
+ PBIT32(p, f->fid);
+ p += BIT32SZ;
+ PBIT64(p, f->offset);
+ p += BIT64SZ;
+ PBIT32(p, f->count);
+ p += BIT32SZ;
+ break;
+
+ case Twrite:
+ PBIT32(p, f->fid);
+ p += BIT32SZ;
+ PBIT64(p, f->offset);
+ p += BIT64SZ;
+ PBIT32(p, f->count);
+ p += BIT32SZ;
+ memmove(p, f->data, f->count);
+ p += f->count;
+ break;
+
+ case Tclunk:
+ case Tremove:
+ PBIT32(p, f->fid);
+ p += BIT32SZ;
+ break;
+
+ case Tstat:
+ PBIT32(p, f->fid);
+ p += BIT32SZ;
+ break;
+
+ case Twstat:
+ PBIT32(p, f->fid);
+ p += BIT32SZ;
+ PBIT16(p, f->nstat);
+ p += BIT16SZ;
+ memmove(p, f->stat, f->nstat);
+ p += f->nstat;
+ break;
+/*
+ */
+
+ case Rversion:
+ PBIT32(p, f->msize);
+ p += BIT32SZ;
+ p = pstring(p, f->version);
+ break;
+
+ case Rerror:
+ p = pstring(p, f->ename);
+ break;
+
+ case Rflush:
+ break;
+
+ case Rauth:
+ p = pqid(p, &f->aqid);
+ break;
+
+ case Rattach:
+ p = pqid(p, &f->qid);
+ break;
+
+ case Rwalk:
+ PBIT16(p, f->nwqid);
+ p += BIT16SZ;
+ if(f->nwqid > MAXWELEM)
+ return 0;
+ for(i=0; i<f->nwqid; i++)
+ p = pqid(p, &f->wqid[i]);
+ break;
+
+ case Ropen:
+ case Rcreate:
+ p = pqid(p, &f->qid);
+ PBIT32(p, f->iounit);
+ p += BIT32SZ;
+ break;
+
+ case Rread:
+ PBIT32(p, f->count);
+ p += BIT32SZ;
+ memmove(p, f->data, f->count);
+ p += f->count;
+ break;
+
+ case Rwrite:
+ PBIT32(p, f->count);
+ p += BIT32SZ;
+ break;
+
+ case Rclunk:
+ break;
+
+ case Rremove:
+ break;
+
+ case Rstat:
+ PBIT16(p, f->nstat);
+ p += BIT16SZ;
+ memmove(p, f->stat, f->nstat);
+ p += f->nstat;
+ break;
+
+ case Rwstat:
+ break;
+ }
+ if(size != p-ap)
+ return 0;
+ return size;
+}
--- /dev/null
+++ b/libkern/div-arm.s
@@ -1,0 +1,119 @@
+Q = 0
+N = 1
+D = 2
+CC = 3
+TMP = 11
+
+TEXT save<>(SB), 1, $0
+ MOVW R(Q), 0(FP)
+ MOVW R(N), 4(FP)
+ MOVW R(D), 8(FP)
+ MOVW R(CC), 12(FP)
+
+ MOVW R(TMP), R(Q) /* numerator */
+ MOVW 20(FP), R(D) /* denominator */
+ CMP $0, R(D)
+ BNE s1
+ SWI 0
+/* MOVW -1(R(D)), R(TMP) /* divide by zero fault */
+s1: RET
+
+TEXT rest<>(SB), 1, $0
+ MOVW 0(FP), R(Q)
+ MOVW 4(FP), R(N)
+ MOVW 8(FP), R(D)
+ MOVW 12(FP), R(CC)
+/*
+ * return to caller
+ * of rest<>
+ */
+ MOVW 0(R13), R14
+ ADD $20, R13
+ B (R14)
+
+TEXT div<>(SB), 1, $0
+ MOVW $32, R(CC)
+/*
+ * skip zeros 8-at-a-time
+ */
+e1:
+ AND.S $(0xff<<24),R(Q), R(N)
+ BNE e2
+ SLL $8, R(Q)
+ SUB.S $8, R(CC)
+ BNE e1
+ RET
+e2:
+ MOVW $0, R(N)
+
+loop:
+/*
+ * shift R(N||Q) left one
+ */
+ SLL $1, R(N)
+ CMP $0, R(Q)
+ ORR.LT $1, R(N)
+ SLL $1, R(Q)
+
+/*
+ * compare numerator to denominator
+ * if less, subtract and set quotent bit
+ */
+ CMP R(D), R(N)
+ ORR.HS $1, R(Q)
+ SUB.HS R(D), R(N)
+ SUB.S $1, R(CC)
+ BNE loop
+ RET
+
+TEXT _div(SB), 1, $16
+ BL save<>(SB)
+ CMP $0, R(Q)
+ BGE d1
+ RSB $0, R(Q), R(Q)
+ CMP $0, R(D)
+ BGE d2
+ RSB $0, R(D), R(D)
+d0:
+ BL div<>(SB) /* none/both neg */
+ MOVW R(Q), R(TMP)
+ B out
+d1:
+ CMP $0, R(D)
+ BGE d0
+ RSB $0, R(D), R(D)
+d2:
+ BL div<>(SB) /* one neg */
+ RSB $0, R(Q), R(TMP)
+ B out
+
+TEXT _mod(SB), 1, $16
+ BL save<>(SB)
+ CMP $0, R(D)
+ RSB.LT $0, R(D), R(D)
+ CMP $0, R(Q)
+ BGE m1
+ RSB $0, R(Q), R(Q)
+ BL div<>(SB) /* neg numerator */
+ RSB $0, R(N), R(TMP)
+ B out
+m1:
+ BL div<>(SB) /* pos numerator */
+ MOVW R(N), R(TMP)
+ B out
+
+TEXT _divu(SB), 1, $16
+ BL save<>(SB)
+ BL div<>(SB)
+ MOVW R(Q), R(TMP)
+ B out
+
+TEXT _modu(SB), 1, $16
+ BL save<>(SB)
+ BL div<>(SB)
+ MOVW R(N), R(TMP)
+ B out
+
+out:
+ BL rest<>(SB)
+ B out
--- /dev/null
+++ b/libkern/div-thumb.s
@@ -1,0 +1,119 @@
+Q = 0
+N = 1
+D = 2
+CC = 3
+TMP = 11
+
+TEXT save<>(SB), 1, $0
+ MOVW R(Q), 0(FP)
+ MOVW R(N), 4(FP)
+ MOVW R(D), 8(FP)
+ MOVW R(CC), 12(FP)
+
+ MOVW R(TMP), R(Q) /* numerator */
+ MOVW 20(FP), R(D) /* denominator */
+ CMP $0, R(D)
+ BNE s1
+ SWI 0
+/* MOVW -1(R(D)), R(TMP) /* divide by zero fault */
+s1: RET
+
+TEXT rest<>(SB), 1, $0
+ MOVW 0(FP), R(Q)
+ MOVW 4(FP), R(N)
+ MOVW 8(FP), R(D)
+ MOVW 12(FP), R(CC)
+/*
+ * return to caller
+ * of rest<>
+ */
+ MOVW 0(R13), R14
+ ADD $20, R13
+ B (R14)
+
+TEXT div<>(SB), 1, $0
+ MOVW $32, R(CC)
+/*
+ * skip zeros 8-at-a-time
+ */
+e1:
+ AND.S $(0xff<<24),R(Q), R(N)
+ BNE e2
+ SLL $8, R(Q)
+ SUB.S $8, R(CC)
+ BNE e1
+ RET
+e2:
+ MOVW $0, R(N)
+
+loop:
+/*
+ * shift R(N||Q) left one
+ */
+ SLL $1, R(N)
+ CMP $0, R(Q)
+ ORR.LT $1, R(N)
+ SLL $1, R(Q)
+
+/*
+ * compare numerator to denominator
+ * if less, subtract and set quotent bit
+ */
+ CMP R(D), R(N)
+ ORR.HS $1, R(Q)
+ SUB.HS R(D), R(N)
+ SUB.S $1, R(CC)
+ BNE loop
+ RET
+
+TEXT _div(SB), 1, $16
+ BL save<>(SB)
+ CMP $0, R(Q)
+ BGE d1
+ RSB $0, R(Q), R(Q)
+ CMP $0, R(D)
+ BGE d2
+ RSB $0, R(D), R(D)
+d0:
+ BL div<>(SB) /* none/both neg */
+ MOVW R(Q), R(TMP)
+ B out
+d1:
+ CMP $0, R(D)
+ BGE d0
+ RSB $0, R(D), R(D)
+d2:
+ BL div<>(SB) /* one neg */
+ RSB $0, R(Q), R(TMP)
+ B out
+
+TEXT _mod(SB), 1, $16
+ BL save<>(SB)
+ CMP $0, R(D)
+ RSB.LT $0, R(D), R(D)
+ CMP $0, R(Q)
+ BGE m1
+ RSB $0, R(Q), R(Q)
+ BL div<>(SB) /* neg numerator */
+ RSB $0, R(N), R(TMP)
+ B out
+m1:
+ BL div<>(SB) /* pos numerator */
+ MOVW R(N), R(TMP)
+ B out
+
+TEXT _divu(SB), 1, $16
+ BL save<>(SB)
+ BL div<>(SB)
+ MOVW R(Q), R(TMP)
+ B out
+
+TEXT _modu(SB), 1, $16
+ BL save<>(SB)
+ BL div<>(SB)
+ MOVW R(N), R(TMP)
+ B out
+
+out:
+ BL rest<>(SB)
+ B out
--- /dev/null
+++ b/libkern/dofmt.c
@@ -1,0 +1,531 @@
+/*
+ * 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 "lib9.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 = f->to;
+ rs = 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 = f->to;
+ s = 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 = _fmtflush(f, t, n);
+ if(t != nil)
+ s = 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 = _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 = f->to;
+ s = 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 = f->to;
+ s = 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, void *vm, int n, int sz)
+{
+ Rune *rt, *rs, r;
+ char *t, *s, *m, *me;
+ ulong fl;
+ int nc, w;
+
+ m = 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 = f->to;
+ rs = f->stop;
+ for(nc = n; nc > 0; nc--){
+ r = *(uchar*)m;
+ if(r < Runeself)
+ m++;
+ else if((me - m) >= UTFmax || fullrune(m, me-m))
+ m += chartorune(&r, m);
+ else
+ break;
+ FMTRCHAR(f, rt, rs, r);
+ }
+ f->nfmt += rt - (Rune *)f->to;
+ f->to = rt;
+ if(m < me)
+ return -1;
+ if(fl & FmtLeft && _rfmtpad(f, w - n) < 0)
+ return -1;
+ }else{
+ if(!(fl & FmtLeft) && _fmtpad(f, w - n) < 0)
+ return -1;
+ t = f->to;
+ s = 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, void *vm, int n)
+{
+ Rune r, *m, *me, *rt, *rs;
+ char *t, *s;
+ ulong fl;
+ int w;
+
+ m = 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 = f->to;
+ rs = 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 = f->to;
+ s = 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, x, 1, 1);
+}
+
+/* fmt out one rune */
+int
+_runefmt(Fmt *f)
+{
+ Rune x[1];
+
+ x[0] = va_arg(f->args, int);
+ return _fmtrcpy(f, x, 1);
+}
+
+/* public helper routine: fmt out a null terminated string already in hand */
+int
+fmtstrcpy(Fmt *f, char *s)
+{
+ int p, i;
+ if(!s)
+ return _fmtcpy(f, "<nil>", 5, 5);
+ /* if precision is specified, make sure we don't wander off the end */
+ if(f->flags & FmtPrec){
+ p = f->prec;
+ for(i = 0; i < p; i++)
+ if(s[i] == 0)
+ break;
+ return _fmtcpy(f, s, utfnlen(s, i), i); /* BUG?: won't print a partial rune at end */
+ }
+
+ return _fmtcpy(f, s, utflen(s), strlen(s));
+}
+
+/* fmt out a null terminated utf string */
+int
+_strfmt(Fmt *f)
+{
+ char *s;
+
+ s = va_arg(f->args, char *);
+ return fmtstrcpy(f, s);
+}
+
+/* public helper routine: fmt out a null terminated rune string already in hand */
+int
+fmtrunestrcpy(Fmt *f, Rune *s)
+{
+ Rune *e;
+ int n, p;
+
+ if(!s)
+ return _fmtcpy(f, "<nil>", 5, 5);
+ /* if precision is specified, make sure we don't wander off the end */
+ if(f->flags & FmtPrec){
+ p = f->prec;
+ for(n = 0; n < p; n++)
+ if(s[n] == 0)
+ break;
+ }else{
+ for(e = s; *e; e++)
+ ;
+ n = e - s;
+ }
+ return _fmtrcpy(f, s, n);
+}
+
+/* fmt out a null terminated rune string */
+int
+_runesfmt(Fmt *f)
+{
+ Rune *s;
+
+ s = va_arg(f->args, Rune *);
+ return fmtrunestrcpy(f, s);
+}
+
+/* fmt a % */
+int
+_percentfmt(Fmt *f)
+{
+ Rune x[1];
+
+ x[0] = f->r;
+ f->prec = 1;
+ return _fmtrcpy(f, 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':
+ 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)){
+ 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':
+ 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, x, 3, 3);
+ return 0;
+}
--- /dev/null
+++ b/libkern/exp.c
@@ -1,0 +1,39 @@
+/*
+ exp returns the exponential function of its
+ floating-point argument.
+
+ The coefficients are #1069 from Hart and Cheney. (22.35D)
+*/
+
+#include <lib9.h>
+
+#define p0 .2080384346694663001443843411e7
+#define p1 .3028697169744036299076048876e5
+#define p2 .6061485330061080841615584556e2
+#define q0 .6002720360238832528230907598e7
+#define q1 .3277251518082914423057964422e6
+#define q2 .1749287689093076403844945335e4
+#define log2e 1.4426950408889634073599247
+#define sqrt2 1.4142135623730950488016887
+#define maxf 10000
+
+double
+exp(double arg)
+{
+ double fract, temp1, temp2, xsq;
+ int ent;
+
+ if(arg == 0)
+ return 1;
+ if(arg < -maxf)
+ return 0;
+ if(arg > maxf)
+ return Inf(1);
+ arg *= log2e;
+ ent = floor(arg);
+ fract = (arg-ent) - 0.5;
+ xsq = fract*fract;
+ temp1 = ((p2*xsq+p1)*xsq+p0)*fract;
+ temp2 = ((xsq+q2)*xsq+q1)*xsq + q0;
+ return ldexp(sqrt2*(temp2+temp1)/(temp2-temp1), ent);
+}
--- /dev/null
+++ b/libkern/fcallfmt.c
@@ -1,0 +1,246 @@
+/*
+ * 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 <lib9.h>
+#include "fcall.h"
+
+static uint dumpsome(char*, char*, char*, long);
+static void fdirconv(char*, char*, Dir*);
+static char *qidtype(char*, uchar);
+
+#define QIDFMT "(%.16llux %lud %s)"
+
+int
+fcallfmt(Fmt *fmt)
+{
+ Fcall *f;
+ int fid, type, tag, i;
+ char buf[512], tmp[200];
+ char *p, *e;
+ Dir *d;
+ Qid *q;
+
+ e = buf+sizeof(buf);
+ f = va_arg(fmt->args, Fcall*);
+ type = f->type;
+ fid = f->fid;
+ tag = f->tag;
+ switch(type){
+ case Tversion: /* 100 */
+ seprint(buf, e, "Tversion tag %ud msize %ud version '%s'", tag, f->msize, f->version);
+ break;
+ case Rversion:
+ seprint(buf, e, "Rversion tag %ud msize %ud version '%s'", tag, f->msize, f->version);
+ break;
+ case Tauth: /* 102 */
+ seprint(buf, e, "Tauth tag %ud afid %d uname %s aname %s", tag,
+ f->afid, f->uname, f->aname);
+ break;
+ case Rauth:
+ seprint(buf, e, "Rauth tag %ud qid " QIDFMT, tag,
+ f->aqid.path, f->aqid.vers, qidtype(tmp, f->aqid.type));
+ break;
+ case Tattach: /* 104 */
+ seprint(buf, e, "Tattach tag %ud fid %d afid %d uname %s aname %s", tag,
+ fid, f->afid, f->uname, f->aname);
+ break;
+ case Rattach:
+ seprint(buf, e, "Rattach tag %ud qid " QIDFMT, tag,
+ f->qid.path, f->qid.vers, qidtype(tmp, f->qid.type));
+ break;
+ case Rerror: /* 107; 106 (Terror) illegal */
+ seprint(buf, e, "Rerror tag %ud ename %s", tag, f->ename);
+ break;
+ case Tflush: /* 108 */
+ seprint(buf, e, "Tflush tag %ud oldtag %ud", tag, f->oldtag);
+ break;
+ case Rflush:
+ seprint(buf, e, "Rflush tag %ud", tag);
+ break;
+ case Twalk: /* 110 */
+ p = seprint(buf, e, "Twalk tag %ud fid %d newfid %d nwname %d ", tag, fid, f->newfid, f->nwname);
+ if(f->nwname <= MAXWELEM)
+ for(i=0; i<f->nwname; i++)
+ p = seprint(p, e, "%d:%s ", i, f->wname[i]);
+ break;
+ case Rwalk:
+ p = seprint(buf, e, "Rwalk tag %ud nwqid %ud ", tag, f->nwqid);
+ if(f->nwqid <= MAXWELEM)
+ for(i=0; i<f->nwqid; i++){
+ q = &f->wqid[i];
+ p = seprint(p, e, "%d:" QIDFMT " ", i,
+ q->path, q->vers, qidtype(tmp, q->type));
+ }
+ break;
+ case Topen: /* 112 */
+ seprint(buf, e, "Topen tag %ud fid %ud mode %d", tag, fid, f->mode);
+ break;
+ case Ropen:
+ seprint(buf, e, "Ropen tag %ud qid " QIDFMT " iounit %ud ", tag,
+ f->qid.path, f->qid.vers, qidtype(tmp, f->qid.type), f->iounit);
+ break;
+ case Tcreate: /* 114 */
+ seprint(buf, e, "Tcreate tag %ud fid %ud name %s perm %M mode %d", tag, fid, f->name, (ulong)f->perm, f->mode);
+ break;
+ case Rcreate:
+ seprint(buf, e, "Rcreate tag %ud qid " QIDFMT " iounit %ud ", tag,
+ f->qid.path, f->qid.vers, qidtype(tmp, f->qid.type), f->iounit);
+ break;
+ case Tread: /* 116 */
+ seprint(buf, e, "Tread tag %ud fid %d offset %lld count %ud",
+ tag, fid, f->offset, f->count);
+ break;
+ case Rread:
+ p = seprint(buf, e, "Rread tag %ud count %ud ", tag, f->count);
+ dumpsome(p, e, f->data, f->count);
+ break;
+ case Twrite: /* 118 */
+ p = seprint(buf, e, "Twrite tag %ud fid %d offset %lld count %ud ",
+ tag, fid, f->offset, f->count);
+ dumpsome(p, e, f->data, f->count);
+ break;
+ case Rwrite:
+ seprint(buf, e, "Rwrite tag %ud count %ud", tag, f->count);
+ break;
+ case Tclunk: /* 120 */
+ seprint(buf, e, "Tclunk tag %ud fid %ud", tag, fid);
+ break;
+ case Rclunk:
+ seprint(buf, e, "Rclunk tag %ud", tag);
+ break;
+ case Tremove: /* 122 */
+ seprint(buf, e, "Tremove tag %ud fid %ud", tag, fid);
+ break;
+ case Rremove:
+ seprint(buf, e, "Rremove tag %ud", tag);
+ break;
+ case Tstat: /* 124 */
+ seprint(buf, e, "Tstat tag %ud fid %ud", tag, fid);
+ break;
+ case Rstat:
+ p = seprint(buf, e, "Rstat tag %ud ", tag);
+ if(f->nstat > sizeof tmp)
+ seprint(p, e, " stat(%d bytes)", f->nstat);
+ else{
+ d = (Dir*)tmp;
+ convM2D(f->stat, f->nstat, d, (char*)(d+1));
+ seprint(p, e, " stat ");
+ fdirconv(p+6, e, d);
+ }
+ break;
+ case Twstat: /* 126 */
+ p = seprint(buf, e, "Twstat tag %ud fid %ud", tag, fid);
+ if(f->nstat > sizeof tmp)
+ seprint(p, e, " stat(%d bytes)", f->nstat);
+ else{
+ d = (Dir*)tmp;
+ convM2D(f->stat, f->nstat, d, (char*)(d+1));
+ seprint(p, e, " stat ");
+ fdirconv(p+6, e, d);
+ }
+ break;
+ case Rwstat:
+ seprint(buf, e, "Rwstat tag %ud", tag);
+ break;
+ default:
+ seprint(buf, e, "unknown type %d", type);
+ }
+ return fmtstrcpy(fmt, buf);
+}
+
+static char*
+qidtype(char *s, uchar t)
+{
+ char *p;
+
+ p = s;
+ if(t & QTDIR)
+ *p++ = 'd';
+ if(t & QTAPPEND)
+ *p++ = 'a';
+ if(t & QTEXCL)
+ *p++ = 'l';
+ if(t & QTAUTH)
+ *p++ = 'A';
+ *p = '\0';
+ return s;
+}
+
+int
+dirfmt(Fmt *fmt)
+{
+ char buf[160];
+
+ fdirconv(buf, buf+sizeof buf, va_arg(fmt->args, Dir*));
+ return fmtstrcpy(fmt, buf);
+}
+
+static void
+fdirconv(char *buf, char *e, Dir *d)
+{
+ char tmp[16];
+
+ seprint(buf, e, "'%s' '%s' '%s' '%s' "
+ "q " QIDFMT " m %#luo "
+ "at %ld mt %ld l %lld "
+ "t %d d %d",
+ d->name, d->uid, d->gid, d->muid,
+ d->qid.path, d->qid.vers, qidtype(tmp, d->qid.type), d->mode,
+ d->atime, d->mtime, d->length,
+ d->type, d->dev);
+}
+
+/*
+ * dump out count (or DUMPL, if count is bigger) bytes from
+ * buf to ans, as a string if they are all printable,
+ * else as a series of hex bytes
+ */
+#define DUMPL 64
+
+static uint
+dumpsome(char *ans, char *e, char *buf, long count)
+{
+ int i, printable;
+ char *p;
+
+ if(buf == nil){
+ seprint(ans, e, "<no data>");
+ return strlen(ans);
+ }
+ printable = 1;
+ if(count > DUMPL)
+ count = DUMPL;
+ for(i=0; i<count && printable; i++)
+ if((buf[i]<32 && buf[i] !='\n' && buf[i] !='\t') || (uchar)buf[i]>127)
+ printable = 0;
+ p = ans;
+ *p++ = '\'';
+ if(printable){
+ if(count > e-p-2)
+ count = e-p-2;
+ memmove(p, buf, count);
+ p += count;
+ }else{
+ if(2*count > e-p-2)
+ count = (e-p-2)/2;
+ for(i=0; i<count; i++){
+ if(i>0 && i%4==0)
+ *p++ = ' ';
+ sprint(p, "%2.2ux", buf[i]);
+ p += 2;
+ }
+ }
+ *p++ = '\'';
+ *p = 0;
+ return p - ans;
+}
--- /dev/null
+++ b/libkern/floor.c
@@ -1,0 +1,26 @@
+#include <lib9.h>
+/*
+ * floor and ceil-- greatest integer <= arg
+ * (resp least >=)
+ */
+
+double
+floor(double d)
+{
+ double fract;
+
+ if(d < 0) {
+ fract = modf(-d, &d);
+ if(fract != 0.0)
+ d += 1;
+ d = -d;
+ } else
+ modf(d, &d);
+ return d;
+}
+
+double
+ceil(double d)
+{
+ return -floor(-d);
+}
--- /dev/null
+++ b/libkern/fmt.c
@@ -1,0 +1,188 @@
+/*
+ * 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 "lib9.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,
+ 'S', _runesfmt,
+ 'X', _ifmt,
+ 'b', _ifmt,
+ 'c', _charfmt,
+ 'd', _ifmt,
+ 'h', _flagfmt,
+ 'l', _flagfmt,
+ 'n', _countfmt,
+ 'o', _ifmt,
+ 'p', _ifmt,
+ 'r', errfmt,
+ 's', _strfmt,
+ 'u', _flagfmt,
+ 'x', _ifmt,
+ 0, nil,
+};
+
+int (*doquote)(int);
+
+static Fmts
+fmtfmt(int c)
+{
+ Convfmt *p, *ep;
+
+ ep = &fmtalloc.fmt[fmtalloc.nfmt];
+ for(p=fmtalloc.fmt; p<ep; p++)
+ if(p->c == c)
+ return p->fmt;
+
+ /* is this a predefined format char? */
+ for(p=knownfmt; p->c; p++)
+ if(p->c == c){
+ /* no need to lock; fmtinstall is idempotent */
+ fmtinstall(p->c, p->fmt);
+ while(p->fmt == nil) /* loop until value is updated */
+ ;
+ return p->fmt;
+ }
+
+ return _badfmt;
+}
+
+int
+fmtinstall(int c, Fmts f)
+{
+ Convfmt *p, *ep;
+
+ if(c<=0 || c>=65536)
+ return -1;
+ if(!f)
+ f = _badfmt;
+
+ _fmtlock();
+
+ ep = &fmtalloc.fmt[fmtalloc.nfmt];
+ for(p=fmtalloc.fmt; p<ep; p++)
+ if(p->c == c)
+ break;
+
+ if(p == &fmtalloc.fmt[Maxfmt]){
+ _fmtunlock();
+ return -1;
+ }
+
+ p->fmt = f;
+ if(p == ep){ /* installing a new format character */
+ fmtalloc.nfmt++;
+ p->c = c;
+ }
+
+ _fmtunlock();
+ return 0;
+}
+
+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, 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){
+ i = -i;
+ f->flags |= FmtLeft;
+ }
+ goto numflag;
+ }
+ n = (*fmtfmt(r))(f);
+ if(n < 0)
+ return nil;
+ if(n == 0)
+ return fmt;
+ }
+}
--- /dev/null
+++ b/libkern/fmtdef.h
@@ -1,0 +1,102 @@
+/*
+ * 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 */
+};
+
+void *_fmtflush(Fmt*, void*, int);
+void *_fmtdispatch(Fmt*, void*, int);
+int _floatfmt(Fmt*, double);
+int _fmtpad(Fmt*, int);
+int _rfmtpad(Fmt*, int);
+int _fmtFdFlush(Fmt*);
+
+int _efgfmt(Fmt*);
+int _charfmt(Fmt*);
+int _countfmt(Fmt*);
+int _flagfmt(Fmt*);
+int _percentfmt(Fmt*);
+int _ifmt(Fmt*);
+int _runefmt(Fmt*);
+int _runesfmt(Fmt*);
+int _strfmt(Fmt*);
+int _badfmt(Fmt*);
+int _fmtcpy(Fmt*, void*, int, int);
+int _fmtrcpy(Fmt*, void*, int n);
+
+void _fmtlock(void);
+void _fmtunlock(void);
+
+#define FMTCHAR(f, t, s, c)\
+ do{\
+ if(t + 1 > (char*)s){\
+ t = _fmtflush(f, t, 1);\
+ if(t != nil)\
+ s = f->stop;\
+ else\
+ return -1;\
+ }\
+ *t++ = c;\
+ }while(0)
+
+#define FMTRCHAR(f, t, s, c)\
+ do{\
+ if(t + 1 > (Rune*)s){\
+ t = _fmtflush(f, t, sizeof(Rune));\
+ if(t != nil)\
+ s = f->stop;\
+ else\
+ return -1;\
+ }\
+ *t++ = c;\
+ }while(0)
+
+#define FMTRUNE(f, t, s, r)\
+ do{\
+ Rune _rune;\
+ int _runelen;\
+ if(t + UTFmax > (char*)s && t + (_runelen = runelen(r)) > (char*)s){\
+ t = _fmtflush(f, t, _runelen);\
+ if(t != nil)\
+ s = f->stop;\
+ else\
+ return -1;\
+ }\
+ if(r < Runeself)\
+ *t++ = r;\
+ else{\
+ _rune = r;\
+ t += runetochar(t, &_rune);\
+ }\
+ }while(0)
+
+#ifndef va_copy
+#define va_copy(a, b) ((a) = (b))
+#endif
--- /dev/null
+++ b/libkern/fmtprint.c
@@ -1,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 "lib9.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;
+}
+
--- /dev/null
+++ b/libkern/fmtquote.c
@@ -1,0 +1,259 @@
+/*
+ * 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 "lib9.h"
+#include "fmtdef.h"
+
+/*
+ * How many bytes of output UTF will be produced by quoting (if necessary) this string?
+ * How many runes? How much of the input will be consumed?
+ * The parameter q is filled in by _quotesetup.
+ * The string may be UTF or Runes (s or r).
+ * Return count does not include NUL.
+ * Terminate the scan at the first of:
+ * NUL in input
+ * count exceeded in input
+ * count exceeded on output
+ * *ninp is set to number of input bytes accepted.
+ * nin may be <0 initially, to avoid checking input by count.
+ */
+void
+_quotesetup(char *s, Rune *r, int nin, int nout, Quoteinfo *q, int sharp, int runesout)
+{
+ int w;
+ Rune c;
+
+ q->quoted = 0;
+ q->nbytesout = 0;
+ q->nrunesout = 0;
+ q->nbytesin = 0;
+ q->nrunesin = 0;
+ if(sharp || nin==0 || (s && *s=='\0') || (r && *r=='\0')){
+ if(nout < 2)
+ return;
+ q->quoted = 1;
+ q->nbytesout = 2;
+ q->nrunesout = 2;
+ }
+ for(; nin!=0; nin-=w){
+ if(s)
+ w = chartorune(&c, s);
+ else{
+ c = *r;
+ w = runelen(c);
+ }
+
+ if(c == '\0')
+ break;
+ if(runesout){
+ if(q->nrunesout+1 > nout)
+ break;
+ }else{
+ if(q->nbytesout+w > nout)
+ break;
+ }
+
+ if((c <= L' ') || (c == L'\'') || (doquote!=nil && doquote(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 = f->to;
+ s = f->stop;
+ rt = f->to;
+ rs = 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 = *rm++;
+ }
+ if(f->runes){
+ FMTRCHAR(f, rt, rs, r);
+ if(r == '\'')
+ FMTRCHAR(f, rt, rs, r);
+ }else{
+ FMTRUNE(f, t, s, r);
+ if(r == '\'')
+ FMTRUNE(f, t, s, r);
+ }
+ }
+
+ if(f->runes){
+ FMTRCHAR(f, rt, rs, '\'');
+ USED(rs);
+ f->nfmt += rt - (Rune *)f->to;
+ f->to = rt;
+ if(fl & FmtLeft && _rfmtpad(f, w - q->nrunesout) < 0)
+ return -1;
+ }else{
+ FMTRUNE(f, t, s, '\'');
+ USED(s);
+ f->nfmt += t - (char *)f->to;
+ f->to = t;
+ if(fl & FmtLeft && _fmtpad(f, w - q->nbytesout) < 0)
+ return -1;
+ }
+ return 0;
+}
+
+int
+_quotestrfmt(int runesin, Fmt *f)
+{
+ int outlen;
+ Rune *r;
+ char *s;
+ Quoteinfo q;
+
+ f->flags &= ~FmtPrec; /* ignored for %q %Q, so disable for %s %S in easy case */
+ if(runesin){
+ r = va_arg(f->args, Rune *);
+ s = nil;
+ }else{
+ s = va_arg(f->args, char *);
+ r = nil;
+ }
+ if(!s && !r)
+ return _fmtcpy(f, "<nil>", 5, 5);
+
+ if(f->flush)
+ outlen = 0x7FFFFFFF; /* if we can flush, no output limit */
+ else if(f->runes)
+ outlen = (Rune*)f->stop - (Rune*)f->to;
+ else
+ outlen = (char*)f->stop - (char*)f->to;
+
+ _quotesetup(s, r, -1, outlen, &q, f->flags&FmtSharp, f->runes);
+//print("bytes in %d bytes out %d runes in %d runesout %d\n", q.nbytesin, q.nbytesout, q.nrunesin, q.nrunesout);
+
+ if(runesin){
+ if(!q.quoted)
+ return _fmtrcpy(f, r, q.nrunesin);
+ return qstrfmt(nil, r, &q, f);
+ }
+
+ if(!q.quoted)
+ return _fmtcpy(f, s, q.nrunesin, q.nbytesin);
+ return qstrfmt(s, nil, &q, f);
+}
+
+int
+quotestrfmt(Fmt *f)
+{
+ return _quotestrfmt(0, f);
+}
+
+int
+quoterunestrfmt(Fmt *f)
+{
+ return _quotestrfmt(1, f);
+}
+
+void
+quotefmtinstall(void)
+{
+ fmtinstall('q', quotestrfmt);
+ fmtinstall('Q', quoterunestrfmt);
+}
+
+int
+_needsquotes(char *s, int *quotelenp)
+{
+ Quoteinfo q;
+
+ _quotesetup(s, nil, -1, 0x7FFFFFFF, &q, 0, 0);
+ *quotelenp = q.nbytesout;
+
+ return q.quoted;
+}
+
+int
+_runeneedsquotes(Rune *r, int *quotelenp)
+{
+ Quoteinfo q;
+
+ _quotesetup(nil, r, -1, 0x7FFFFFFF, &q, 0, 0);
+ *quotelenp = q.nrunesout;
+
+ return q.quoted;
+}
--- /dev/null
+++ b/libkern/fmtstr.c
@@ -1,0 +1,23 @@
+/*
+ * 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 "lib9.h"
+
+char*
+fmtstrflush(Fmt *f)
+{
+ if(f->start == nil)
+ return nil;
+ *(char*)f->to = '\0';
+ return f->start;
+}
--- /dev/null
+++ b/libkern/fmtvprint.c
@@ -1,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 "lib9.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;
+}
+
--- /dev/null
+++ b/libkern/frexp-386.c
@@ -1,0 +1,79 @@
+#include <lib9.h>
+
+#define MASK 0x7ffL
+#define SHIFT 20
+#define BIAS 1022L
+
+typedef union
+{
+ double d;
+ struct
+ {
+ long ls;
+ long ms;
+ };
+} Cheat;
+
+double
+frexp(double d, int *ep)
+{
+ Cheat x;
+
+ if(d == 0) {
+ *ep = 0;
+ return 0;
+ }
+ x.d = d;
+ *ep = ((x.ms >> SHIFT) & MASK) - BIAS;
+ x.ms &= ~(MASK << SHIFT);
+ x.ms |= BIAS << SHIFT;
+ return x.d;
+}
+
+double
+ldexp(double d, int e)
+{
+ Cheat x;
+
+ if(d == 0)
+ return 0;
+ x.d = d;
+ e += (x.ms >> SHIFT) & MASK;
+ if(e <= 0)
+ return 0; /* underflow */
+ if(e >= MASK){ /* overflow */
+ if(d < 0)
+ return Inf(-1);
+ return Inf(1);
+ }
+ x.ms &= ~(MASK << SHIFT);
+ x.ms |= (long)e << SHIFT;
+ return x.d;
+}
+
+double
+modf(double d, double *ip)
+{
+ Cheat x;
+ int e;
+
+ if(d < 1) {
+ if(d < 0) {
+ x.d = modf(-d, ip);
+ *ip = -*ip;
+ return -x.d;
+ }
+ *ip = 0;
+ return d;
+ }
+ x.d = d;
+ e = ((x.ms >> SHIFT) & MASK) - BIAS;
+ if(e <= SHIFT+1) {
+ x.ms &= ~(0x1fffffL >> e);
+ x.ls = 0;
+ } else
+ if(e <= SHIFT+33)
+ x.ls &= ~(0x7fffffffL >> (e-SHIFT-2));
+ *ip = x.d;
+ return d - x.d;
+}
--- /dev/null
+++ b/libkern/frexp-arm.c
@@ -1,0 +1,79 @@
+#include <lib9.h>
+
+#define MASK 0x7ffL
+#define SHIFT 20
+#define BIAS 1022L
+
+typedef union
+{
+ double d;
+ struct
+ {
+ long ls;
+ long ms;
+ };
+} Cheat;
+
+double
+frexp(double d, int *ep)
+{
+ Cheat x;
+
+ if(d == 0) {
+ *ep = 0;
+ return 0;
+ }
+ x.d = d;
+ *ep = ((x.ms >> SHIFT) & MASK) - BIAS;
+ x.ms &= ~(MASK << SHIFT);
+ x.ms |= BIAS << SHIFT;
+ return x.d;
+}
+
+double
+ldexp(double d, int e)
+{
+ Cheat x;
+
+ if(d == 0)
+ return 0;
+ x.d = d;
+ e += (x.ms >> SHIFT) & MASK;
+ if(e <= 0)
+ return 0; /* underflow */
+ if(e >= MASK){ /* overflow */
+ if(d < 0)
+ return Inf(-1);
+ return Inf(1);
+ }
+ x.ms &= ~(MASK << SHIFT);
+ x.ms |= (long)e << SHIFT;
+ return x.d;
+}
+
+double
+modf(double d, double *ip)
+{
+ Cheat x;
+ int e;
+
+ if(d < 1) {
+ if(d < 0) {
+ x.d = modf(-d, ip);
+ *ip = -*ip;
+ return -x.d;
+ }
+ *ip = 0;
+ return d;
+ }
+ x.d = d;
+ e = ((x.ms >> SHIFT) & MASK) - BIAS;
+ if(e <= SHIFT+1) {
+ x.ms &= ~(0x1fffffL >> e);
+ x.ls = 0;
+ } else
+ if(e <= SHIFT+33)
+ x.ls &= ~(0x7fffffffL >> (e-SHIFT-2));
+ *ip = x.d;
+ return d - x.d;
+}
--- /dev/null
+++ b/libkern/frexp-mips.c
@@ -1,0 +1,79 @@
+#include <lib9.h>
+
+#define MASK 0x7ffL
+#define SHIFT 20
+#define BIAS 1022L
+
+typedef union
+{
+ double d;
+ struct
+ {
+ long ms;
+ long ls;
+ };
+} Cheat;
+
+double
+frexp(double d, int *ep)
+{
+ Cheat x;
+
+ if(d == 0) {
+ *ep = 0;
+ return 0;
+ }
+ x.d = d;
+ *ep = ((x.ms >> SHIFT) & MASK) - BIAS;
+ x.ms &= ~(MASK << SHIFT);
+ x.ms |= BIAS << SHIFT;
+ return x.d;
+}
+
+double
+ldexp(double d, int e)
+{
+ Cheat x;
+
+ if(d == 0)
+ return 0;
+ x.d = d;
+ e += (x.ms >> SHIFT) & MASK;
+ if(e <= 0)
+ return 0; /* underflow */
+ if(e >= MASK){ /* overflow */
+ if(d < 0)
+ return Inf(-1);
+ return Inf(1);
+ }
+ x.ms &= ~(MASK << SHIFT);
+ x.ms |= (long)e << SHIFT;
+ return x.d;
+}
+
+double
+modf(double d, double *ip)
+{
+ Cheat x;
+ int e;
+
+ if(d < 1) {
+ if(d < 0) {
+ x.d = modf(-d, ip);
+ *ip = -*ip;
+ return -x.d;
+ }
+ *ip = 0;
+ return d;
+ }
+ x.d = d;
+ e = ((x.ms >> SHIFT) & MASK) - BIAS;
+ if(e <= SHIFT+1) {
+ x.ms &= ~(0x1fffffL >> e);
+ x.ls = 0;
+ } else
+ if(e <= SHIFT+33)
+ x.ls &= ~(0x7fffffffL >> (e-SHIFT-2));
+ *ip = x.d;
+ return d - x.d;
+}
--- /dev/null
+++ b/libkern/frexp-power.c
@@ -1,0 +1,79 @@
+#include <lib9.h>
+
+#define MASK 0x7ffL
+#define SHIFT 20
+#define BIAS 1022L
+
+typedef union
+{
+ double d;
+ struct
+ {
+ long ms;
+ long ls;
+ };
+} Cheat;
+
+double
+frexp(double d, int *ep)
+{
+ Cheat x;
+
+ if(d == 0) {
+ *ep = 0;
+ return 0;
+ }
+ x.d = d;
+ *ep = ((x.ms >> SHIFT) & MASK) - BIAS;
+ x.ms &= ~(MASK << SHIFT);
+ x.ms |= BIAS << SHIFT;
+ return x.d;
+}
+
+double
+ldexp(double d, int e)
+{
+ Cheat x;
+
+ if(d == 0)
+ return 0;
+ x.d = d;
+ e += (x.ms >> SHIFT) & MASK;
+ if(e <= 0)
+ return 0; /* underflow */
+ if(e >= MASK){ /* overflow */
+ if(d < 0)
+ return Inf(-1);
+ return Inf(1);
+ }
+ x.ms &= ~(MASK << SHIFT);
+ x.ms |= (long)e << SHIFT;
+ return x.d;
+}
+
+double
+modf(double d, double *ip)
+{
+ Cheat x;
+ int e;
+
+ if(d < 1) {
+ if(d < 0) {
+ x.d = modf(-d, ip);
+ *ip = -*ip;
+ return -x.d;
+ }
+ *ip = 0;
+ return d;
+ }
+ x.d = d;
+ e = ((x.ms >> SHIFT) & MASK) - BIAS;
+ if(e <= SHIFT+1) {
+ x.ms &= ~(0x1fffffL >> e);
+ x.ls = 0;
+ } else
+ if(e <= SHIFT+33)
+ x.ls &= ~(0x7fffffffL >> (e-SHIFT-2));
+ *ip = x.d;
+ return d - x.d;
+}
--- /dev/null
+++ b/libkern/frexp-sparc.c
@@ -1,0 +1,79 @@
+#include <lib9.h>
+
+#define MASK 0x7ffL
+#define SHIFT 20
+#define BIAS 1022L
+
+typedef union
+{
+ double d;
+ struct
+ {
+ long ms;
+ long ls;
+ };
+} Cheat;
+
+double
+frexp(double d, int *ep)
+{
+ Cheat x;
+
+ if(d == 0) {
+ *ep = 0;
+ return 0;
+ }
+ x.d = d;
+ *ep = ((x.ms >> SHIFT) & MASK) - BIAS;
+ x.ms &= ~(MASK << SHIFT);
+ x.ms |= BIAS << SHIFT;
+ return x.d;
+}
+
+double
+ldexp(double d, int e)
+{
+ Cheat x;
+
+ if(d == 0)
+ return 0;
+ x.d = d;
+ e += (x.ms >> SHIFT) & MASK;
+ if(e <= 0)
+ return 0; /* underflow */
+ if(e >= MASK){ /* overflow */
+ if(d < 0)
+ return Inf(-1);
+ return Inf(1);
+ }
+ x.ms &= ~(MASK << SHIFT);
+ x.ms |= (long)e << SHIFT;
+ return x.d;
+}
+
+double
+modf(double d, double *ip)
+{
+ Cheat x;
+ int e;
+
+ if(d < 1) {
+ if(d < 0) {
+ x.d = modf(-d, ip);
+ *ip = -*ip;
+ return -x.d;
+ }
+ *ip = 0;
+ return d;
+ }
+ x.d = d;
+ e = ((x.ms >> SHIFT) & MASK) - BIAS;
+ if(e <= SHIFT+1) {
+ x.ms &= ~(0x1fffffL >> e);
+ x.ls = 0;
+ } else
+ if(e <= SHIFT+33)
+ x.ls &= ~(0x7fffffffL >> (e-SHIFT-2));
+ *ip = x.d;
+ return d - x.d;
+}
--- /dev/null
+++ b/libkern/frexp-spim.c
@@ -1,0 +1,79 @@
+#include <lib9.h>
+
+#define MASK 0x7ffL
+#define SHIFT 20
+#define BIAS 1022L
+
+typedef union
+{
+ double d;
+ struct
+ {
+ long ls;
+ long ms;
+ };
+} Cheat;
+
+double
+frexp(double d, int *ep)
+{
+ Cheat x;
+
+ if(d == 0) {
+ *ep = 0;
+ return 0;
+ }
+ x.d = d;
+ *ep = ((x.ms >> SHIFT) & MASK) - BIAS;
+ x.ms &= ~(MASK << SHIFT);
+ x.ms |= BIAS << SHIFT;
+ return x.d;
+}
+
+double
+ldexp(double d, int e)
+{
+ Cheat x;
+
+ if(d == 0)
+ return 0;
+ x.d = d;
+ e += (x.ms >> SHIFT) & MASK;
+ if(e <= 0)
+ return 0; /* underflow */
+ if(e >= MASK){ /* overflow */
+ if(d < 0)
+ return Inf(-1);
+ return Inf(1);
+ }
+ x.ms &= ~(MASK << SHIFT);
+ x.ms |= (long)e << SHIFT;
+ return x.d;
+}
+
+double
+modf(double d, double *ip)
+{
+ Cheat x;
+ int e;
+
+ if(d < 1) {
+ if(d < 0) {
+ x.d = modf(-d, ip);
+ *ip = -*ip;
+ return -x.d;
+ }
+ *ip = 0;
+ return d;
+ }
+ x.d = d;
+ e = ((x.ms >> SHIFT) & MASK) - BIAS;
+ if(e <= SHIFT+1) {
+ x.ms &= ~(0x1fffffL >> e);
+ x.ls = 0;
+ } else
+ if(e <= SHIFT+33)
+ x.ls &= ~(0x7fffffffL >> (e-SHIFT-2));
+ *ip = x.d;
+ return d - x.d;
+}
--- /dev/null
+++ b/libkern/frexp-thumb.c
@@ -1,0 +1,79 @@
+#include <lib9.h>
+
+#define MASK 0x7ffL
+#define SHIFT 20
+#define BIAS 1022L
+
+typedef union
+{
+ double d;
+ struct
+ {
+ long ls;
+ long ms;
+ };
+} Cheat;
+
+double
+frexp(double d, int *ep)
+{
+ Cheat x;
+
+ if(d == 0) {
+ *ep = 0;
+ return 0;
+ }
+ x.d = d;
+ *ep = ((x.ms >> SHIFT) & MASK) - BIAS;
+ x.ms &= ~(MASK << SHIFT);
+ x.ms |= BIAS << SHIFT;
+ return x.d;
+}
+
+double
+ldexp(double d, int e)
+{
+ Cheat x;
+
+ if(d == 0)
+ return 0;
+ x.d = d;
+ e += (x.ms >> SHIFT) & MASK;
+ if(e <= 0)
+ return 0; /* underflow */
+ if(e >= MASK){ /* overflow */
+ if(d < 0)
+ return Inf(-1);
+ return Inf(1);
+ }
+ x.ms &= ~(MASK << SHIFT);
+ x.ms |= (long)e << SHIFT;
+ return x.d;
+}
+
+double
+modf(double d, double *ip)
+{
+ Cheat x;
+ int e;
+
+ if(d < 1) {
+ if(d < 0) {
+ x.d = modf(-d, ip);
+ *ip = -*ip;
+ return -x.d;
+ }
+ *ip = 0;
+ return d;
+ }
+ x.d = d;
+ e = ((x.ms >> SHIFT) & MASK) - BIAS;
+ if(e <= SHIFT+1) {
+ x.ms &= ~(0x1fffffL >> e);
+ x.ls = 0;
+ } else
+ if(e <= SHIFT+33)
+ x.ls &= ~(0x7fffffffL >> (e-SHIFT-2));
+ *ip = x.d;
+ return d - x.d;
+}
--- /dev/null
+++ b/libkern/getfcr-386.s
@@ -1,0 +1,27 @@
+TEXT setfcr(SB), $0
+ MOVL p+0(FP),AX
+ XORB $0x3f,AX
+ PUSHW AX
+ WAIT
+ FLDCW 0(SP)
+ POPW AX
+ RET
+
+TEXT getfcr(SB), $0
+ PUSHW AX
+ WAIT
+ FSTCW 0(SP)
+ POPW AX
+ XORB $0x3f,AX
+ RET
+
+TEXT getfsr(SB), $0
+ WAIT
+ FSTSW AX
+ RET
+
+TEXT setfsr(SB), $0
+ WAIT
+ FCLEX
+ RET
+
--- /dev/null
+++ b/libkern/getfcr-arm.s
@@ -1,0 +1,12 @@
+TEXT setfcr(SB), $0
+ RET
+
+TEXT getfcr(SB), $0
+ RET
+
+TEXT getfsr(SB), $0
+ RET
+
+TEXT setfsr(SB), $0
+ RET
+
--- /dev/null
+++ b/libkern/getfcr-mips.s
@@ -1,0 +1,15 @@
+TEXT getfsr(SB), $0
+ MOVW FCR31, R1
+ RET
+
+TEXT setfsr(SB), $0
+ MOVW R1, FCR31
+ RET
+
+TEXT getfcr(SB), $0
+ MOVW FCR31, R1
+ RET
+
+TEXT setfcr(SB), $0
+ MOVW R1, FCR31
+ RET
--- /dev/null
+++ b/libkern/getfcr-power.s
@@ -1,0 +1,28 @@
+TEXT getfcr(SB), $8
+ MOVFL FPSCR, F3
+ FMOVD F3, f-8(SP)
+ MOVW -4(SP), R3
+ RETURN
+
+TEXT getfsr(SB), $8
+ MOVFL FPSCR, F3
+ FMOVD F3, f-8(SP)
+ MOVW -4(SP), R3
+ RETURN
+
+TEXT setfcr(SB), $8
+ SYNC
+ MOVW R3, -4(SP)
+ FMOVD -8(SP), F3
+ MOVFL F3, FPSCR
+ ISYNC
+ RETURN
+
+TEXT setfsr(SB), $8
+ SYNC
+ MOVW R3, -4(SP)
+ FMOVD -8(SP), F3
+ MOVFL F3, FPSCR
+ ISYNC
+ RETURN
+
--- /dev/null
+++ b/libkern/getfcr-sparc.s
@@ -1,0 +1,27 @@
+TEXT getfsr(SB), $0
+ SUB $4, R1
+ MOVW FSR, (R1)
+ MOVW (R1), R7
+ ADD $4, R1
+ RETURN
+
+TEXT setfsr(SB), $0
+ SUB $4, R1
+ MOVW R7, (R1)
+ MOVW (R1), FSR
+ ADD $4, R1
+ RETURN
+
+TEXT setfcr(SB), $0
+ SUB $4, R1
+ MOVW R7, (R1)
+ MOVW (R1), FSR
+ ADD $4, R1
+ RETURN
+
+TEXT getfcr(SB), $0
+ SUB $4, R1
+ MOVW FSR, (R1)
+ MOVW (R1), R7
+ ADD $4, R1
+ RETURN
--- /dev/null
+++ b/libkern/getfcr-spim.s
@@ -1,0 +1,1 @@
+#include "getfcr-mips.s"
--- /dev/null
+++ b/libkern/getfcr-thumb.s
@@ -1,0 +1,12 @@
+TEXT setfcr(SB), $0
+ RET
+
+TEXT getfcr(SB), $0
+ RET
+
+TEXT getfsr(SB), $0
+ RET
+
+TEXT setfsr(SB), $0
+ RET
+
--- /dev/null
+++ b/libkern/getfields.c
@@ -1,0 +1,35 @@
+#include "lib9.h"
+int
+getfields(char *str, char **args, int max, int mflag, char *set)
+{
+ Rune r;
+ int nr, intok, narg;
+
+ if(max <= 0)
+ return 0;
+
+ narg = 0;
+ args[narg] = str;
+ if(!mflag)
+ narg++;
+ intok = 0;
+ for(;; str += nr) {
+ nr = chartorune(&r, str);
+ if(r == 0)
+ break;
+ if(utfrune(set, r)) {
+ if(narg >= max)
+ break;
+ *str = 0;
+ intok = 0;
+ args[narg] = str + nr;
+ if(!mflag)
+ narg++;
+ } else {
+ if(!intok && mflag)
+ narg++;
+ intok = 1;
+ }
+ }
+ return narg;
+}
--- /dev/null
+++ b/libkern/log.c
@@ -1,0 +1,57 @@
+/*
+ log returns the natural logarithm of its floating
+ point argument.
+
+ The coefficients are #2705 from Hart & Cheney. (19.38D)
+
+ It calls frexp.
+*/
+
+#include <lib9.h>
+
+#define log2 0.693147180559945309e0
+#define ln10o1 .4342944819032518276511
+#define sqrto2 0.707106781186547524e0
+#define p0 -.240139179559210510e2
+#define p1 0.309572928215376501e2
+#define p2 -.963769093377840513e1
+#define p3 0.421087371217979714e0
+#define q0 -.120069589779605255e2
+#define q1 0.194809660700889731e2
+#define q2 -.891110902798312337e1
+
+double
+log(double arg)
+{
+ double x, z, zsq, temp;
+ int exp;
+
+ if(arg <= 0)
+ return NaN();
+ x = frexp(arg, &exp);
+ while(x < 0.5) {
+ x *= 2;
+ exp--;
+ }
+ if(x < sqrto2) {
+ x *= 2;
+ exp--;
+ }
+
+ z = (x-1) / (x+1);
+ zsq = z*z;
+
+ temp = ((p3*zsq + p2)*zsq + p1)*zsq + p0;
+ temp = temp/(((zsq + q2)*zsq + q1)*zsq + q0);
+ temp = temp*z + exp*log2;
+ return temp;
+}
+
+double
+log10(double arg)
+{
+
+ if(arg <= 0)
+ return NaN();
+ return log(arg) * ln10o1;
+}
--- /dev/null
+++ b/libkern/memccpy-power.s
@@ -1,0 +1,23 @@
+ TEXT memccpy(SB), $0
+#define BDNZ BC 16,0,
+MOVW R3, s1+0(FP)
+ MOVW n+12(FP), R7
+ MOVW s2+4(FP), R4
+ MOVBZ c+11(FP), R5
+ CMP R7, $0
+ BEQ nf
+ MOVW R7, CTR
+ SUB $1, R3
+ SUB $1, R4
+l1:
+ MOVBZU 1(R4), R6
+ CMP R6, R5
+ MOVBZU R6, 1(R3)
+ BEQ eq
+ BDNZ l1
+nf:
+ MOVW $0, R3
+ RETURN
+eq:
+ ADD $1, R3
+ RETURN
--- /dev/null
+++ b/libkern/memccpy.c
@@ -1,0 +1,17 @@
+#include <lib9.h>
+
+void*
+memccpy(void *a1, void *a2, int c, ulong n)
+{
+ uchar *s1, *s2;
+
+ s1 = a1;
+ s2 = a2;
+ c &= 0xFF;
+ while(n > 0) {
+ if((*s1++ = *s2++) == c)
+ return s1;
+ n--;
+ }
+ return 0;
+}
--- /dev/null
+++ b/libkern/memchr.c
@@ -1,0 +1,16 @@
+#include <lib9.h>
+
+void*
+memchr(void *ap, int c, ulong n)
+{
+ uchar *sp;
+
+ sp = ap;
+ c &= 0xFF;
+ while(n > 0) {
+ if(*sp++ == c)
+ return sp-1;
+ n--;
+ }
+ return 0;
+}
--- /dev/null
+++ b/libkern/memcmp-power.s
@@ -1,0 +1,110 @@
+ TEXT memcmp(SB), $0
+#define BDNZ BC 16,0,
+ MOVW R3, s1+0(FP) /* R3 is pointer1 */
+
+/*
+ * performance:
+ * 67mb/sec aligned; 16mb/sec unaligned
+ */
+
+ MOVW n+8(FP), R4 /* R4 is count */
+ MOVW s2+4(FP), R5 /* R5 is pointer2 */
+
+/*
+ * let LSW do the work for 4 characters or less; aligned and unaligned
+ */
+ CMP R4, $0
+ BLE eq
+ CMP R4, $4
+ BLE out
+
+ XOR R3, R5, R9
+ ANDCC $3, R9
+ BNE l4 /* pointers misaligned; use LSW loop */
+
+/*
+ * do enough bytes to align pointers
+ */
+ ANDCC $3,R3, R9
+ BEQ l2
+ SUBC R9, $4, R9
+ MOVW R9, XER
+ LSW (R3), R10
+ ADD R9, R3
+ LSW (R5), R14
+ ADD R9, R5
+ SUB R9, R4
+ CMPU R10, R14
+ BNE ne
+
+/*
+ * compare 16 at a time
+ */
+l2:
+ SRAWCC $4, R4, R9
+ BLE l4
+ MOVW R9, CTR
+ SUB $4, R3
+ SUB $4, R5
+l3:
+ MOVWU 4(R3), R10
+ MOVWU 4(R5), R12
+ MOVWU 4(R3), R11
+ MOVWU 4(R5), R13
+ CMPU R10, R12
+ BNE ne
+ MOVWU 4(R3), R10
+ MOVWU 4(R5), R12
+ CMPU R11, R13
+ BNE ne
+ MOVWU 4(R3), R11
+ MOVWU 4(R5), R13
+ CMPU R10, R12
+ BNE ne
+ CMPU R11, R13
+ BNE ne
+ BDNZ l3
+ ADD $4, R3
+ ADD $4, R5
+ RLWNMCC $0, R4, $15, R4 /* residue */
+ BEQ eq
+
+/*
+ * do remaining words with LSW; also does unaligned case
+ */
+l4:
+ SRAWCC $2, R4, R9
+ BLE out
+ MOVW R9, CTR
+l5:
+ LSW (R3), $4, R10
+ ADD $4, R3
+ LSW (R5), $4, R11
+ ADD $4, R5
+ CMPU R10, R11
+ BNE ne
+ BDNZ l5
+ RLWNMCC $0, R4, $3, R4 /* residue */
+ BEQ eq
+
+/*
+ * do remaining bytes with final LSW
+ */
+out:
+ MOVW R4, XER
+ LSW (R3), R10
+ LSW (R5), R11
+ CMPU R10, R11
+ BNE ne
+
+eq:
+ MOVW $0, R3
+ RETURN
+
+ne:
+ MOVW $1, R3
+ BGE ret
+ MOVW $-1,R3
+ret:
+ RETURN
+ END
--- /dev/null
+++ b/libkern/memcmp.c
@@ -1,0 +1,22 @@
+#include <lib9.h>
+
+int
+memcmp(void *a1, void *a2, ulong n)
+{
+ uchar *s1, *s2;
+ uint c1, c2;
+
+ s1 = a1;
+ s2 = a2;
+ while(n > 0) {
+ c1 = *s1++;
+ c2 = *s2++;
+ if(c1 != c2) {
+ if(c1 > c2)
+ return 1;
+ return -1;
+ }
+ n--;
+ }
+ return 0;
+}
--- /dev/null
+++ b/libkern/memmove-386.s
@@ -1,0 +1,58 @@
+ TEXT memmove(SB), $0
+ TEXT memcpy(SB), $0
+
+ MOVL p1+0(FP), DI
+ MOVL p2+4(FP), SI
+ MOVL n+8(FP), BX
+ CMPL BX, $0
+ JGE ok
+ MOVL $0, SI
+ok:
+ CLD
+/*
+ * check and set for backwards
+ */
+ CMPL SI, DI
+ JLS back
+/*
+ * copy whole longs
+ */
+ MOVL BX, CX
+ SHRL $2, CX
+ REP; MOVSL
+/*
+ * copy the rest, by bytes
+ */
+ ANDL $3, BX
+ MOVL BX, CX
+ REP; MOVSB
+
+ MOVL p+0(FP),AX
+ RET
+/*
+ * whole thing backwards has
+ * adjusted addresses
+ */
+back:
+ ADDL BX, DI
+ ADDL BX, SI
+ SUBL $4, DI
+ SUBL $4, SI
+ STD
+/*
+ * copy whole longs
+ */
+ MOVL BX, CX
+ SHRL $2, CX
+ ANDL $3, BX
+ REP; MOVSL
+/*
+ * copy the rest, by bytes
+ */
+ ADDL $3, DI
+ ADDL $3, SI
+ MOVL BX, CX
+ REP; MOVSB
+
+ MOVL p+0(FP),AX
+ RET
--- /dev/null
+++ b/libkern/memmove-arm.s
@@ -1,0 +1,223 @@
+TS = 0
+TE = 1
+FROM = 2
+N = 3
+TMP = 3 /* N and TMP don't overlap */
+TMP1 = 4
+
+TEXT memcpy(SB), $0
+TEXT memmove(SB), $-4
+_memmove:
+ MOVW R(TS), to+0(FP) /* need to save for return value */
+ MOVW from+4(FP), R(FROM)
+ MOVW n+8(FP), R(N)
+
+ ADD R(N), R(TS), R(TE) /* to end pointer */
+
+ CMP R(FROM), R(TS)
+ BLS _forward
+
+_back:
+ ADD R(N), R(FROM) /* from end pointer */
+ CMP $4, R(N) /* need at least 4 bytes to copy */
+ BLT _b1tail
+
+_b4align: /* align destination on 4 */
+ AND.S $3, R(TE), R(TMP)
+ BEQ _b4aligned
+
+ MOVBU.W -1(R(FROM)), R(TMP) /* pre-indexed */
+ MOVBU.W R(TMP), -1(R(TE)) /* pre-indexed */
+ B _b4align
+
+_b4aligned: /* is source now aligned? */
+ AND.S $3, R(FROM), R(TMP)
+ BNE _bunaligned
+
+ ADD $31, R(TS), R(TMP) /* do 32-byte chunks if possible */
+_b32loop:
+ CMP R(TMP), R(TE)
+ BLS _b4tail
+
+ MOVM.DB.W (R(FROM)), [R4-R11]
+ MOVM.DB.W [R4-R11], (R(TE))
+ B _b32loop
+
+_b4tail: /* do remaining words if possible */
+ ADD $3, R(TS), R(TMP)
+_b4loop:
+ CMP R(TMP), R(TE)
+ BLS _b1tail
+
+ MOVW.W -4(R(FROM)), R(TMP1) /* pre-indexed */
+ MOVW.W R(TMP1), -4(R(TE)) /* pre-indexed */
+ B _b4loop
+
+_b1tail: /* remaining bytes */
+ CMP R(TE), R(TS)
+ BEQ _return
+
+ MOVBU.W -1(R(FROM)), R(TMP) /* pre-indexed */
+ MOVBU.W R(TMP), -1(R(TE)) /* pre-indexed */
+ B _b1tail
+
+_forward:
+ CMP $4, R(N) /* need at least 4 bytes to copy */
+ BLT _f1tail
+
+_f4align: /* align destination on 4 */
+ AND.S $3, R(TS), R(TMP)
+ BEQ _f4aligned
+
+ MOVBU.P 1(R(FROM)), R(TMP) /* implicit write back */
+ MOVBU.P R(TMP), 1(R(TS)) /* implicit write back */
+ B _f4align
+
+_f4aligned: /* is source now aligned? */
+ AND.S $3, R(FROM), R(TMP)
+ BNE _funaligned
+
+ SUB $31, R(TE), R(TMP) /* do 32-byte chunks if possible */
+_f32loop:
+ CMP R(TMP), R(TS)
+ BHS _f4tail
+
+ MOVM.IA.W (R(FROM)), [R4-R11]
+ MOVM.IA.W [R4-R11], (R(TS))
+ B _f32loop
+
+_f4tail:
+ SUB $3, R(TE), R(TMP) /* do remaining words if possible */
+_f4loop:
+ CMP R(TMP), R(TS)
+ BHS _f1tail
+
+ MOVW.P 4(R(FROM)), R(TMP1) /* implicit write back */
+ MOVW.P R4, 4(R(TS)) /* implicit write back */
+ B _f4loop
+
+_f1tail:
+ CMP R(TS), R(TE)
+ BEQ _return
+
+ MOVBU.P 1(R(FROM)), R(TMP) /* implicit write back */
+ MOVBU.P R(TMP), 1(R(TS)) /* implicit write back */
+ B _f1tail
+
+_return:
+ MOVW to+0(FP), R0
+ RET
+
+RSHIFT = 4
+LSHIFT = 5
+OFFSET = 6
+
+BR0 = 7
+BW0 = 8
+BR1 = 8
+BW1 = 9
+BR2 = 9
+BW2 = 10
+BR3 = 10
+BW3 = 11
+
+_bunaligned:
+ CMP $2, R(TMP) /* is R(TMP) < 2 ? */
+
+ MOVW.LT $8, R(RSHIFT) /* (R(n)<<24)|(R(n-1)>>8) */
+ MOVW.LT $24, R(LSHIFT)
+ MOVW.LT $1, R(OFFSET)
+
+ MOVW.EQ $16, R(RSHIFT) /* (R(n)<<16)|(R(n-1)>>16) */
+ MOVW.EQ $16, R(LSHIFT)
+ MOVW.EQ $2, R(OFFSET)
+
+ MOVW.GT $24, R(RSHIFT) /* (R(n)<<8)|(R(n-1)>>24) */
+ MOVW.GT $8, R(LSHIFT)
+ MOVW.GT $3, R(OFFSET)
+
+ ADD $16, R(TS), R(TMP) /* do 16-byte chunks if possible */
+ CMP R(TMP), R(TE)
+ BLS _b1tail
+
+ AND $~0x03, R(FROM) /* align source */
+ MOVW (R(FROM)), R(BR0) /* prime first block register */
+
+_bu16loop:
+ CMP R(TMP), R(TE)
+ BLS _bu1tail
+
+ MOVW R(BR0)<<R(LSHIFT), R(BW3)
+ MOVM.DB.W (R(FROM)), [R(BR0)-R(BR3)]
+ ORR R(BR3)>>R(RSHIFT), R(BW3)
+
+ MOVW R(BR3)<<R(LSHIFT), R(BW2)
+ ORR R(BR2)>>R(RSHIFT), R(BW2)
+
+ MOVW R(BR2)<<R(LSHIFT), R(BW1)
+ ORR R(BR1)>>R(RSHIFT), R(BW1)
+
+ MOVW R(BR1)<<R(LSHIFT), R(BW0)
+ ORR R(BR0)>>R(RSHIFT), R(BW0)
+
+ MOVM.DB.W [R(BW0)-R(BW3)], (R(TE))
+ B _bu16loop
+
+_bu1tail:
+ ADD R(OFFSET), R(FROM)
+ B _b1tail
+
+FW0 = 7
+FR0 = 8
+FW1 = 8
+FR1 = 9
+FW2 = 9
+FR2 = 10
+FW3 = 10
+FR3 = 11
+
+_funaligned:
+ CMP $2, R(TMP)
+
+ MOVW.LT $8, R(RSHIFT) /* (R(n+1)<<24)|(R(n)>>8) */
+ MOVW.LT $24, R(LSHIFT)
+ MOVW.LT $3, R(OFFSET)
+
+ MOVW.EQ $16, R(RSHIFT) /* (R(n+1)<<16)|(R(n)>>16) */
+ MOVW.EQ $16, R(LSHIFT)
+ MOVW.EQ $2, R(OFFSET)
+
+ MOVW.GT $24, R(RSHIFT) /* (R(n+1)<<8)|(R(n)>>24) */
+ MOVW.GT $8, R(LSHIFT)
+ MOVW.GT $1, R(OFFSET)
+
+ SUB $16, R(TE), R(TMP) /* do 16-byte chunks if possible */
+ CMP R(TMP), R(TS)
+ BHS _f1tail
+
+ AND $~0x03, R(FROM) /* align source */
+ MOVW.P 4(R(FROM)), R(FR3) /* prime last block register, implicit write back */
+
+_fu16loop:
+ CMP R(TMP), R(TS)
+ BHS _fu1tail
+
+ MOVW R(FR3)>>R(RSHIFT), R(FW0)
+ MOVM.IA.W (R(FROM)), [R(FR0)-R(FR3)]
+ ORR R(FR0)<<R(LSHIFT), R(FW0)
+
+ MOVW R(FR0)>>R(RSHIFT), R(FW1)
+ ORR R(FR1)<<R(LSHIFT), R(FW1)
+
+ MOVW R(FR1)>>R(RSHIFT), R(FW2)
+ ORR R(FR2)<<R(LSHIFT), R(FW2)
+
+ MOVW R(FR2)>>R(RSHIFT), R(FW3)
+ ORR R(FR3)<<R(LSHIFT), R(FW3)
+
+ MOVM.IA.W [R(FW0)-R(FW3)], (R(TS))
+ B _fu16loop
+
+_fu1tail:
+ SUB R(OFFSET), R(FROM)
+ B _f1tail
--- /dev/null
+++ b/libkern/memmove-mips.s
@@ -1,0 +1,237 @@
+ TEXT memmove(SB), $0
+
+ JMP move
+
+ TEXT memcpy(SB), $0
+move:
+ MOVW R1, s1+0(FP)
+
+ MOVW n+8(FP), R3 /* R3 is count */
+ MOVW R1, R4 /* R4 is to-pointer */
+ SGT R0, R3, R5
+ BEQ R5, ok
+ MOVW (R0), R0 /* abort if negative count */
+ok:
+ MOVW s2+4(FP), R5 /* R5 is from-pointer */
+ ADDU R3,R5, R7 /* R7 is end from-pointer */
+ ADDU R3,R4, R6 /* R6 is end to-pointer */
+
+/*
+ * easiest test is copy backwards if
+ * destination string has higher mem address
+ */
+ SGT $4,R3, R2
+ SGTU R4,R5, R1
+ BNE R1, back
+
+/*
+ * if not at least 4 chars,
+ * don't even mess around.
+ * 3 chars to guarantee any
+ * rounding up to a word
+ * boundary and 4 characters
+ * to get at least maybe one
+ * full word store.
+ */
+ BNE R2, fout
+
+
+/*
+ * byte at a time to word align destination
+ */
+f1:
+ AND $3,R4, R1
+ BEQ R1, f2
+ MOVB 0(R5), R8
+ ADDU $1, R5
+ MOVB R8, 0(R4)
+ ADDU $1, R4
+ JMP f1
+
+/*
+ * test if source is now word aligned
+ */
+f2:
+ AND $3, R5, R1
+ BNE R1, fun2
+/*
+ * turn R3 into to-end pointer-15
+ * copy 16 at a time while theres room.
+ * R6 is smaller than R7 --
+ * there are problems if R7 is 0.
+ */
+ ADDU $-15,R6, R3
+f3:
+ SGTU R3,R4, R1
+ BEQ R1, f4
+ MOVW 0(R5), R8
+ MOVW 4(R5), R9
+ MOVW R8, 0(R4)
+ MOVW 8(R5), R8
+ MOVW R9, 4(R4)
+ MOVW 12(R5), R9
+ ADDU $16, R5
+ MOVW R8, 8(R4)
+ MOVW R9, 12(R4)
+ ADDU $16, R4
+ JMP f3
+
+/*
+ * turn R3 into to-end pointer-3
+ * copy 4 at a time while theres room
+ */
+f4:
+ ADDU $-3,R6, R3
+f5:
+ SGTU R3,R4, R1
+ BEQ R1, fout
+ MOVW 0(R5), R8
+ ADDU $4, R5
+ MOVW R8, 0(R4)
+ ADDU $4, R4
+ JMP f5
+
+/*
+ * forward copy, unaligned
+ * turn R3 into to-end pointer-15
+ * copy 16 at a time while theres room.
+ * R6 is smaller than R7 --
+ * there are problems if R7 is 0.
+ */
+fun2:
+ ADDU $-15,R6, R3
+fun3:
+ SGTU R3,R4, R1
+ BEQ R1, fun4
+ MOVWL 0(R5), R8
+ MOVWR 3(R5), R8
+ MOVWL 4(R5), R9
+ MOVWR 7(R5), R9
+ MOVW R8, 0(R4)
+ MOVWL 8(R5), R8
+ MOVWR 11(R5), R8
+ MOVW R9, 4(R4)
+ MOVWL 12(R5), R9
+ MOVWR 15(R5), R9
+ ADDU $16, R5
+ MOVW R8, 8(R4)
+ MOVW R9, 12(R4)
+ ADDU $16, R4
+ JMP fun3
+
+/*
+ * turn R3 into to-end pointer-3
+ * copy 4 at a time while theres room
+ */
+fun4:
+ ADDU $-3,R6, R3
+fun5:
+ SGTU R3,R4, R1
+ BEQ R1, fout
+ MOVWL 0(R5), R8
+ MOVWR 3(R5), R8
+ ADDU $4, R5
+ MOVW R8, 0(R4)
+ ADDU $4, R4
+ JMP fun5
+
+/*
+ * last loop, copy byte at a time
+ */
+fout:
+ BEQ R7,R5, ret
+ MOVB 0(R5), R8
+ ADDU $1, R5
+ MOVB R8, 0(R4)
+ ADDU $1, R4
+ JMP fout
+
+/*
+ * whole thing repeated for backwards
+ */
+back:
+ BNE R2, bout
+b1:
+ AND $3,R6, R1
+ BEQ R1, b2
+ MOVB -1(R7), R8
+ ADDU $-1, R7
+ MOVB R8, -1(R6)
+ ADDU $-1, R6
+ JMP b1
+
+b2:
+ AND $3, R7, R1
+ BNE R1, bun2
+
+ ADDU $15,R5, R3
+b3:
+ SGTU R7,R3, R1
+ BEQ R1, b4
+ MOVW -4(R7), R8
+ MOVW -8(R7), R9
+ MOVW R8, -4(R6)
+ MOVW -12(R7), R8
+ MOVW R9, -8(R6)
+ MOVW -16(R7), R9
+ ADDU $-16, R7
+ MOVW R8, -12(R6)
+ MOVW R9, -16(R6)
+ ADDU $-16, R6
+ JMP b3
+b4:
+ ADDU $3,R5, R3
+b5:
+ SGTU R7,R3, R1
+ BEQ R1, bout
+ MOVW -4(R7), R8
+ ADDU $-4, R7
+ MOVW R8, -4(R6)
+ ADDU $-4, R6
+ JMP b5
+
+bun2:
+ ADDU $15,R5, R3
+bun3:
+ SGTU R7,R3, R1
+ BEQ R1, bun4
+ MOVWL -4(R7), R8
+ MOVWR -1(R7), R8
+ MOVWL -8(R7), R9
+ MOVWR -5(R7), R9
+ MOVW R8, -4(R6)
+ MOVWL -12(R7), R8
+ MOVWR -9(R7), R8
+ MOVW R9, -8(R6)
+ MOVWL -16(R7), R9
+ MOVWR -13(R7), R9
+ ADDU $-16, R7
+ MOVW R8, -12(R6)
+ MOVW R9, -16(R6)
+ ADDU $-16, R6
+ JMP bun3
+
+bun4:
+ ADDU $3,R5, R3
+bun5:
+ SGTU R7,R3, R1
+ BEQ R1, bout
+ MOVWL -4(R7), R8
+ MOVWR -1(R7), R8
+ ADDU $-4, R7
+ MOVW R8, -4(R6)
+ ADDU $-4, R6
+ JMP bun5
+
+bout:
+ BEQ R7,R5, ret
+ MOVB -1(R7), R8
+ ADDU $-1, R7
+ MOVB R8, -1(R6)
+ ADDU $-1, R6
+ JMP bout
+
+ret:
+ MOVW s1+0(FP), R1
+ RET
+ END
--- /dev/null
+++ b/libkern/memmove-power.s
@@ -1,0 +1,170 @@
+#define BDNZ BC 16,0,
+ TEXT memcpy(SB), $0
+ BR move
+
+ TEXT memmove(SB), $0
+move:
+
+/*
+ * performance:
+ * (tba)
+ */
+
+ MOVW R3, s1+0(FP)
+ MOVW n+8(FP), R9 /* R9 is count */
+ MOVW R3, R10 /* R10 is to-pointer */
+ CMP R9, $0
+ BEQ ret
+ BLT trap
+ MOVW s2+4(FP), R11 /* R11 is from-pointer */
+
+/*
+ * if no more than 16 bytes, just use one lsw/stsw
+ */
+ CMP R9, $16
+ BLE fout
+
+ ADD R9,R11, R13 /* R13 is end from-pointer */
+ ADD R9,R10, R12 /* R12 is end to-pointer */
+
+/*
+ * easiest test is copy backwards if
+ * destination string has higher mem address
+ */
+ CMPU R10, R11
+ BGT back
+
+/*
+ * test if both pointers
+ * are similarly word aligned
+ */
+ XOR R10,R11, R7
+ ANDCC $3,R7
+ BNE fbad
+
+/*
+ * move a few bytes to align pointers
+ */
+ ANDCC $3,R10,R7
+ BEQ f2
+ SUBC R7, $4, R7
+ SUB R7, R9
+ MOVW R7, XER
+ LSW (R11), R16
+ ADD R7, R11
+ STSW R16, (R10)
+ ADD R7, R10
+
+/*
+ * turn R14 into doubleword count
+ * copy 16 bytes at a time while there's room.
+ */
+f2:
+ SRAWCC $4, R9, R14
+ BLE fout
+ MOVW R14, CTR
+ SUB $4, R11
+ SUB $4, R10
+f3:
+ MOVWU 4(R11), R16
+ MOVWU R16, 4(R10)
+ MOVWU 4(R11), R17
+ MOVWU R17, 4(R10)
+ MOVWU 4(R11), R16
+ MOVWU R16, 4(R10)
+ MOVWU 4(R11), R17
+ MOVWU R17, 4(R10)
+ BDNZ f3
+ RLWNMCC $0, R9, $15, R9 /* residue */
+ BEQ ret
+ ADD $4, R11
+ ADD $4, R10
+
+/*
+ * move up to 16 bytes through R16 .. R19; aligned and unaligned
+ */
+fout:
+ MOVW R9, XER
+ LSW (R11), R16
+ STSW R16, (R10)
+ BR ret
+
+/*
+ * loop for unaligned copy, then copy up to 15 remaining bytes
+ */
+fbad:
+ SRAWCC $4, R9, R14
+ BLE f6
+ MOVW R14, CTR
+f5:
+ LSW (R11), $16, R16
+ ADD $16, R11
+ STSW R16, $16, (R10)
+ ADD $16, R10
+ BDNZ f5
+ RLWNMCC $0, R9, $15, R9 /* residue */
+ BEQ ret
+f6:
+ MOVW R9, XER
+ LSW (R11), R16
+ STSW R16, (R10)
+ BR ret
+
+/*
+ * whole thing repeated for backwards
+ */
+back:
+ CMP R9, $4
+ BLT bout
+
+ XOR R12,R13, R7
+ ANDCC $3,R7
+ BNE bout
+b1:
+ ANDCC $3,R13, R7
+ BEQ b2
+ MOVBZU -1(R13), R16
+ MOVBZU R16, -1(R12)
+ SUB $1, R9
+ BR b1
+b2:
+ SRAWCC $4, R9, R14
+ BLE b4
+ MOVW R14, CTR
+b3:
+ MOVWU -4(R13), R16
+ MOVWU R16, -4(R12)
+ MOVWU -4(R13), R17
+ MOVWU R17, -4(R12)
+ MOVWU -4(R13), R16
+ MOVWU R16, -4(R12)
+ MOVWU -4(R13), R17
+ MOVWU R17, -4(R12)
+ BDNZ b3
+ RLWNMCC $0, R9, $15, R9 /* residue */
+ BEQ ret
+b4:
+ SRAWCC $2, R9, R14
+ BLE bout
+ MOVW R14, CTR
+b5:
+ MOVWU -4(R13), R16
+ MOVWU R16, -4(R12)
+ BDNZ b5
+ RLWNMCC $0, R9, $3, R9 /* residue */
+ BEQ ret
+
+bout:
+ CMPU R13, R11
+ BLE ret
+ MOVBZU -1(R13), R16
+ MOVBZU R16, -1(R12)
+ BR bout
+
+trap:
+/* MOVW $0, R0 */
+ MOVW R0, 0(R0)
+
+ret:
+ MOVW s1+0(FP), R3
+ RETURN
--- /dev/null
+++ b/libkern/memmove-sparc.s
@@ -1,0 +1,162 @@
+ TEXT memmove(SB), $0
+ JMP move
+
+ TEXT memcpy(SB), $0
+move:
+
+/*
+ * performance:
+ * (tba)
+ */
+
+ MOVW R7, s1+0(FP)
+ MOVW n+8(FP), R9 /* R9 is count */
+ MOVW R7, R10 /* R10 is to-pointer */
+ SUBCC R0,R9, R0
+ BGE ok
+ MOVW 0(R0), R0
+
+ok:
+ MOVW s2+4(FP), R11 /* R11 is from-pointer */
+ ADD R9,R11, R13 /* R13 is end from-pointer */
+ ADD R9,R10, R12 /* R12 is end to-pointer */
+
+/*
+ * easiest test is copy backwards if
+ * destination string has higher mem address
+ */
+ SUBCC R11,R10, R0
+ BGU back
+
+/*
+ * if not at least 8 chars,
+ * dont even mess around.
+ * 7 chars to guarantee any
+ * rounding up to a word
+ * boundary and 8 characters
+ * to get at least maybe one
+ * full word store.
+ */
+ SUBCC $8,R9, R0
+ BL fout
+
+/*
+ * test if both pointers
+ * are similarly word aligned
+ */
+ XOR R10,R11, R7
+ ANDCC $7,R7, R0
+ BNE fout
+
+/*
+ * byte at a time to double align
+ */
+f1:
+ ANDCC $7,R10, R0
+ BE f2
+ MOVB 0(R11), R16
+ ADD $1, R11
+ MOVB R16, 0(R10)
+ ADD $1, R10
+ JMP f1
+
+/*
+ * turn R9 into to-end pointer-15
+ * copy 16 at a time while theres room.
+ * R12 is smaller than R13 --
+ * there are problems if R13 is 0.
+ */
+f2:
+ SUB $15,R12, R9
+f3:
+ SUBCC R10,R9, R0
+ BLEU f4
+ MOVD 0(R11), R16
+ MOVD R16, 0(R10)
+ MOVD 8(R11), R16
+ ADD $16, R11
+ MOVD R16, 8(R10)
+ ADD $16, R10
+ JMP f3
+
+/*
+ * turn R9 into to-end pointer-3
+ * copy 4 at a time while theres room
+ */
+f4:
+ SUB $3,R12, R9
+f5:
+ SUBCC R10,R9, R0
+ BLEU fout
+ MOVW 0(R11), R16
+ ADD $4, R11
+ MOVW R16, 0(R10)
+ ADD $4, R10
+ JMP f5
+
+/*
+ * last loop, copy byte at a time
+ */
+fout:
+ SUBCC R11,R13, R0
+ BLEU ret
+ MOVB 0(R11), R16
+ ADD $1, R11
+ MOVB R16, 0(R10)
+ ADD $1, R10
+ JMP fout
+
+/*
+ * whole thing repeated for backwards
+ */
+back:
+ SUBCC $8,R9, R0
+ BL bout
+
+ XOR R12,R13, R7
+ ANDCC $7,R7, R0
+ BNE bout
+b1:
+ ANDCC $7,R13, R0
+ BE b2
+ MOVB -1(R13), R16
+ SUB $1, R13
+ MOVB R16, -1(R12)
+ SUB $1, R12
+ JMP b1
+b2:
+ ADD $15,R11, R9
+b3:
+ SUBCC R9,R13, R0
+ BLEU b4
+
+ MOVD -8(R13), R16
+ MOVD R16, -8(R12)
+ MOVD -16(R13), R16
+ SUB $16, R13
+ MOVD R16, -16(R12);
+ SUB $16, R12
+ JMP b3
+b4:
+ ADD $3,R11, R9
+b5:
+ SUBCC R9,R13, R0
+ BLEU bout
+ MOVW -4(R13), R16
+ SUB $4, R13
+ MOVW R16, -4(R12)
+ SUB $4, R12
+ JMP b5
+
+bout:
+ SUBCC R11,R13, R0
+ BLEU ret
+ MOVB -1(R13), R16
+ SUB $1, R13
+ MOVB R16, -1(R12)
+ SUB $1, R12
+ JMP bout
+
+ret:
+ MOVW s1+0(FP), R7
+ RETURN
--- /dev/null
+++ b/libkern/memmove-spim.s
@@ -1,0 +1,1 @@
+#include "memmove-mips.s"
--- /dev/null
+++ b/libkern/memmove-thumb.s
@@ -1,0 +1,223 @@
+TS = 0
+TE = 1
+FROM = 2
+N = 3
+TMP = 3 /* N and TMP don't overlap */
+TMP1 = 4
+
+TEXT memcpy(SB), $0
+TEXT memmove(SB), $-4
+_memmove:
+ MOVW R(TS), to+0(FP) /* need to save for return value */
+ MOVW from+4(FP), R(FROM)
+ MOVW n+8(FP), R(N)
+
+ ADD R(N), R(TS), R(TE) /* to end pointer */
+
+ CMP R(FROM), R(TS)
+ BLS _forward
+
+_back:
+ ADD R(N), R(FROM) /* from end pointer */
+ CMP $4, R(N) /* need at least 4 bytes to copy */
+ BLT _b1tail
+
+_b4align: /* align destination on 4 */
+ AND.S $3, R(TE), R(TMP)
+ BEQ _b4aligned
+
+ MOVBU.W -1(R(FROM)), R(TMP) /* pre-indexed */
+ MOVBU.W R(TMP), -1(R(TE)) /* pre-indexed */
+ B _b4align
+
+_b4aligned: /* is source now aligned? */
+ AND.S $3, R(FROM), R(TMP)
+ BNE _bunaligned
+
+ ADD $31, R(TS), R(TMP) /* do 32-byte chunks if possible */
+_b32loop:
+ CMP R(TMP), R(TE)
+ BLS _b4tail
+
+ MOVM.DB.W (R(FROM)), [R4-R11]
+ MOVM.DB.W [R4-R11], (R(TE))
+ B _b32loop
+
+_b4tail: /* do remaining words if possible */
+ ADD $3, R(TS), R(TMP)
+_b4loop:
+ CMP R(TMP), R(TE)
+ BLS _b1tail
+
+ MOVW.W -4(R(FROM)), R(TMP1) /* pre-indexed */
+ MOVW.W R(TMP1), -4(R(TE)) /* pre-indexed */
+ B _b4loop
+
+_b1tail: /* remaining bytes */
+ CMP R(TE), R(TS)
+ BEQ _return
+
+ MOVBU.W -1(R(FROM)), R(TMP) /* pre-indexed */
+ MOVBU.W R(TMP), -1(R(TE)) /* pre-indexed */
+ B _b1tail
+
+_forward:
+ CMP $4, R(N) /* need at least 4 bytes to copy */
+ BLT _f1tail
+
+_f4align: /* align destination on 4 */
+ AND.S $3, R(TS), R(TMP)
+ BEQ _f4aligned
+
+ MOVBU.P 1(R(FROM)), R(TMP) /* implicit write back */
+ MOVBU.P R(TMP), 1(R(TS)) /* implicit write back */
+ B _f4align
+
+_f4aligned: /* is source now aligned? */
+ AND.S $3, R(FROM), R(TMP)
+ BNE _funaligned
+
+ SUB $31, R(TE), R(TMP) /* do 32-byte chunks if possible */
+_f32loop:
+ CMP R(TMP), R(TS)
+ BHS _f4tail
+
+ MOVM.IA.W (R(FROM)), [R4-R11]
+ MOVM.IA.W [R4-R11], (R(TS))
+ B _f32loop
+
+_f4tail:
+ SUB $3, R(TE), R(TMP) /* do remaining words if possible */
+_f4loop:
+ CMP R(TMP), R(TS)
+ BHS _f1tail
+
+ MOVW.P 4(R(FROM)), R(TMP1) /* implicit write back */
+ MOVW.P R4, 4(R(TS)) /* implicit write back */
+ B _f4loop
+
+_f1tail:
+ CMP R(TS), R(TE)
+ BEQ _return
+
+ MOVBU.P 1(R(FROM)), R(TMP) /* implicit write back */
+ MOVBU.P R(TMP), 1(R(TS)) /* implicit write back */
+ B _f1tail
+
+_return:
+ MOVW to+0(FP), R0
+ RET
+
+RSHIFT = 4
+LSHIFT = 5
+OFFSET = 6
+
+BR0 = 7
+BW0 = 8
+BR1 = 8
+BW1 = 9
+BR2 = 9
+BW2 = 10
+BR3 = 10
+BW3 = 11
+
+_bunaligned:
+ CMP $2, R(TMP) /* is R(TMP) < 2 ? */
+
+ MOVW.LT $8, R(RSHIFT) /* (R(n)<<24)|(R(n-1)>>8) */
+ MOVW.LT $24, R(LSHIFT)
+ MOVW.LT $1, R(OFFSET)
+
+ MOVW.EQ $16, R(RSHIFT) /* (R(n)<<16)|(R(n-1)>>16) */
+ MOVW.EQ $16, R(LSHIFT)
+ MOVW.EQ $2, R(OFFSET)
+
+ MOVW.GT $24, R(RSHIFT) /* (R(n)<<8)|(R(n-1)>>24) */
+ MOVW.GT $8, R(LSHIFT)
+ MOVW.GT $3, R(OFFSET)
+
+ ADD $16, R(TS), R(TMP) /* do 16-byte chunks if possible */
+ CMP R(TMP), R(TE)
+ BLS _b1tail
+
+ AND $~0x03, R(FROM) /* align source */
+ MOVW (R(FROM)), R(BR0) /* prime first block register */
+
+_bu16loop:
+ CMP R(TMP), R(TE)
+ BLS _bu1tail
+
+ MOVW R(BR0)<<R(LSHIFT), R(BW3)
+ MOVM.DB.W (R(FROM)), [R(BR0)-R(BR3)]
+ ORR R(BR3)>>R(RSHIFT), R(BW3)
+
+ MOVW R(BR3)<<R(LSHIFT), R(BW2)
+ ORR R(BR2)>>R(RSHIFT), R(BW2)
+
+ MOVW R(BR2)<<R(LSHIFT), R(BW1)
+ ORR R(BR1)>>R(RSHIFT), R(BW1)
+
+ MOVW R(BR1)<<R(LSHIFT), R(BW0)
+ ORR R(BR0)>>R(RSHIFT), R(BW0)
+
+ MOVM.DB.W [R(BW0)-R(BW3)], (R(TE))
+ B _bu16loop
+
+_bu1tail:
+ ADD R(OFFSET), R(FROM)
+ B _b1tail
+
+FW0 = 7
+FR0 = 8
+FW1 = 8
+FR1 = 9
+FW2 = 9
+FR2 = 10
+FW3 = 10
+FR3 = 11
+
+_funaligned:
+ CMP $2, R(TMP)
+
+ MOVW.LT $8, R(RSHIFT) /* (R(n+1)<<24)|(R(n)>>8) */
+ MOVW.LT $24, R(LSHIFT)
+ MOVW.LT $3, R(OFFSET)
+
+ MOVW.EQ $16, R(RSHIFT) /* (R(n+1)<<16)|(R(n)>>16) */
+ MOVW.EQ $16, R(LSHIFT)
+ MOVW.EQ $2, R(OFFSET)
+
+ MOVW.GT $24, R(RSHIFT) /* (R(n+1)<<8)|(R(n)>>24) */
+ MOVW.GT $8, R(LSHIFT)
+ MOVW.GT $1, R(OFFSET)
+
+ SUB $16, R(TE), R(TMP) /* do 16-byte chunks if possible */
+ CMP R(TMP), R(TS)
+ BHS _f1tail
+
+ AND $~0x03, R(FROM) /* align source */
+ MOVW.P 4(R(FROM)), R(FR3) /* prime last block register, implicit write back */
+
+_fu16loop:
+ CMP R(TMP), R(TS)
+ BHS _fu1tail
+
+ MOVW R(FR3)>>R(RSHIFT), R(FW0)
+ MOVM.IA.W (R(FROM)), [R(FR0)-R(FR3)]
+ ORR R(FR0)<<R(LSHIFT), R(FW0)
+
+ MOVW R(FR0)>>R(RSHIFT), R(FW1)
+ ORR R(FR1)<<R(LSHIFT), R(FW1)
+
+ MOVW R(FR1)>>R(RSHIFT), R(FW2)
+ ORR R(FR2)<<R(LSHIFT), R(FW2)
+
+ MOVW R(FR2)>>R(RSHIFT), R(FW3)
+ ORR R(FR3)<<R(LSHIFT), R(FW3)
+
+ MOVM.IA.W [R(FW0)-R(FW3)], (R(TS))
+ B _fu16loop
+
+_fu1tail:
+ SUB R(OFFSET), R(FROM)
+ B _f1tail
--- /dev/null
+++ b/libkern/memmove.c
@@ -1,0 +1,29 @@
+#include <lib9.h>
+
+/* for testing only */
+void*
+memcpy(void *a1, void *a2, ulong n)
+{
+ return memmove(a1, a2, n);
+}
+
+void*
+memmove(void *a1, void *a2, ulong n)
+{
+ int m = (int)n;
+ uchar *s, *d;
+
+ d = a1;
+ s = a2;
+ if(d > s){
+ s += m;
+ d += m;
+ while(--m >= 0)
+ *--d = *--s;
+ }
+ else{
+ while(--m >= 0)
+ *d++ = *s++;
+ }
+ return a1;
+}
--- /dev/null
+++ b/libkern/memset-386.s
@@ -1,0 +1,35 @@
+ TEXT memset(SB),$0
+
+ CLD
+ MOVL p+0(FP), DI
+ MOVBLZX c+4(FP), AX
+ MOVL n+8(FP), BX
+/*
+ * if not enough bytes, just copy
+ */
+ CMPL BX, $9
+ JLS c3
+/*
+ * build word in AX
+ */
+ MOVB AL, AH
+ MOVL AX, CX
+ SHLL $16, CX
+ ORL CX, AX
+/*
+ * copy whole longs
+ */
+c1:
+ MOVL BX, CX
+ SHRL $2, CX
+ ANDL $3, BX
+ REP; STOSL
+/*
+ * copy the rest, by bytes
+ */
+c3:
+ MOVL BX, CX
+ REP; STOSB
+ret:
+ MOVL p+0(FP),AX
+ RET
--- /dev/null
+++ b/libkern/memset-arm.s
@@ -1,0 +1,66 @@
+TO = 1
+TOE = 2
+N = 3
+TMP = 3 /* N and TMP don't overlap */
+
+TEXT memset(SB), $0
+ MOVW R0, R(TO)
+ MOVW data+4(FP), R(4)
+ MOVW n+8(FP), R(N)
+
+ ADD R(N), R(TO), R(TOE) /* to end pointer */
+
+ CMP $4, R(N) /* need at least 4 bytes to copy */
+ BLT _1tail
+
+ AND $0xFF, R(4) /* it's a byte */
+ SLL $8, R(4), R(TMP) /* replicate to a word */
+ ORR R(TMP), R(4)
+ SLL $16, R(4), R(TMP)
+ ORR R(TMP), R(4)
+
+_4align: /* align on 4 */
+ AND.S $3, R(TO), R(TMP)
+ BEQ _4aligned
+
+ MOVBU.P R(4), 1(R(TO)) /* implicit write back */
+ B _4align
+
+_4aligned:
+ SUB $31, R(TOE), R(TMP) /* do 32-byte chunks if possible */
+ CMP R(TMP), R(TO)
+ BHS _4tail
+
+ MOVW R4, R5 /* replicate */
+ MOVW R4, R6
+ MOVW R4, R7
+ MOVW R4, R8
+ MOVW R4, R9
+ MOVW R4, R10
+ MOVW R4, R11
+
+_f32loop:
+ CMP R(TMP), R(TO)
+ BHS _4tail
+
+ MOVM.IA.W [R4-R11], (R(TO))
+ B _f32loop
+
+_4tail:
+ SUB $3, R(TOE), R(TMP) /* do remaining words if possible */
+_4loop:
+ CMP R(TMP), R(TO)
+ BHS _1tail
+
+ MOVW.P R(4), 4(R(TO)) /* implicit write back */
+ B _4loop
+
+_1tail:
+ CMP R(TO), R(TOE)
+ BEQ _return
+
+ MOVBU.P R(4), 1(R(TO)) /* implicit write back */
+ B _1tail
+
+_return:
+ RET
--- /dev/null
+++ b/libkern/memset-mips.s
@@ -1,0 +1,88 @@
+ TEXT memset(SB),$12
+MOVW R1, 0(FP)
+
+/*
+ * performance:
+ * about 1us/call and 28mb/sec
+ */
+
+ MOVW n+8(FP), R3 /* R3 is count */
+ MOVW p+0(FP), R4 /* R4 is pointer */
+ MOVW c+4(FP), R5 /* R5 is char */
+ ADDU R3,R4, R6 /* R6 is end pointer */
+
+/*
+ * if not at least 4 chars,
+ * dont even mess around.
+ * 3 chars to guarantee any
+ * rounding up to a word
+ * boundary and 4 characters
+ * to get at least maybe one
+ * full word store.
+ */
+ SGT $4,R3, R1
+ BNE R1, out
+
+/*
+ * turn R5 into a word of characters
+ */
+ AND $0xff, R5
+ SLL $8,R5, R1
+ OR R1, R5
+ SLL $16,R5, R1
+ OR R1, R5
+
+/*
+ * store one byte at a time until pointer
+ * is alligned on a word boundary
+ */
+l1:
+ AND $3,R4, R1
+ BEQ R1, l2
+ MOVB R5, 0(R4)
+ ADDU $1, R4
+ JMP l1
+
+/*
+ * turn R3 into end pointer-15
+ * store 16 at a time while theres room
+ */
+l2:
+ ADDU $-15,R6, R3
+l3:
+ SGTU R3,R4, R1
+ BEQ R1, l4
+ MOVW R5, 0(R4)
+ MOVW R5, 4(R4)
+ ADDU $16, R4
+ MOVW R5, -8(R4)
+ MOVW R5, -4(R4)
+ JMP l3
+
+/*
+ * turn R3 into end pointer-3
+ * store 4 at a time while theres room
+ */
+l4:
+ ADDU $-3,R6, R3
+l5:
+ SGTU R3,R4, R1
+ BEQ R1, out
+ MOVW R5, 0(R4)
+ ADDU $4, R4
+ JMP l5
+
+/*
+ * last loop, store byte at a time
+ */
+out:
+ SGTU R6,R4 ,R1
+ BEQ R1, ret
+ MOVB R5, 0(R4)
+ ADDU $1, R4
+ JMP out
+
+ret:
+ MOVW s1+0(FP), R1
+ RET
+ END
--- /dev/null
+++ b/libkern/memset-power.s
@@ -1,0 +1,73 @@
+ TEXT memset(SB),$0
+#define BDNZ BC 16,0,
+ MOVW R3, p+0(FP) /* R3 is pointer */
+
+/*
+ * performance:
+ * about 100mbytes/sec (8k blocks) on a 603/105 without L2 cache
+ * drops to 40mbytes/sec (10k blocks) and 28mbytes/sec with 32k blocks
+ */
+
+ MOVW n+8(FP), R4 /* R4 is count */
+ CMP R4, $0
+ BLE ret
+ MOVW c+4(FP), R5 /* R5 is char */
+
+/*
+ * create 16 copies of c in R5 .. R8
+ */
+ RLWNM $0, R5, $0xff, R5
+ RLWMI $8, R5, $0xff00, R5
+ RLWMI $16, R5, $0xffff0000, R5
+ MOVW R5, R6
+ MOVW R5, R7
+ MOVW R5, R8
+
+/*
+ * let STSW do the work for 16 characters or less; aligned and unaligned
+ */
+ CMP R4, $16
+ BLE out
+
+/*
+ * store enough bytes to align pointer
+ */
+ ANDCC $7,R3, R9
+ BEQ l2
+ SUBC R9, $8, R9
+ MOVW R9, XER
+ STSW R5, (R3)
+ ADD R9, R3
+ SUB R9, R4
+
+/*
+ * store 16 at a time while there's room
+ * STSW was used here originally, but it's `completion serialised'
+ */
+l2:
+ SRAWCC $4, R4, R9
+ BLE out
+ MOVW R9, CTR
+l3:
+ MOVW R5, 0(R3)
+ ADD $8, R3, R10
+ MOVW R6, 4(R3)
+ MOVW R7, 0(R10)
+ ADD $8, R10, R3
+ MOVW R8, 4(R10)
+ BDNZ l3
+ RLWNMCC $0, R4, $15, R4 /* residue */
+ BEQ ret
+
+/*
+ * store up to 16 bytes from R5 .. R8; aligned and unaligned
+ */
+
+out:
+ MOVW R4, XER
+ STSW R5, (R3)
+
+ret:
+ MOVW 0(FP), R3
+ RETURN
+ END
--- /dev/null
+++ b/libkern/memset-sparc.s
@@ -1,0 +1,88 @@
+ TEXT memset(SB),$0
+
+/*
+ * performance:
+ * (tba)
+ */
+
+MOVW R7, 0(FP)
+ MOVW n+8(FP), R9 /* R9 is count */
+ MOVW p+0(FP), R10 /* R10 is pointer */
+ MOVW c+4(FP), R11 /* R11 is char */
+ ADD R9,R10, R12 /* R12 is end pointer */
+
+/*
+ * if not at least 4 chars,
+ * dont even mess around.
+ * 3 chars to guarantee any
+ * rounding up to a word
+ * boundary and 4 characters
+ * to get at least maybe one
+ * full word store.
+ */
+ SUBCC $4,R9, R0
+ BL out
+
+/*
+ * turn R11 into a word of characters
+ */
+ AND $0xff, R11
+ SLL $8,R11, R7
+ OR R7, R11
+ SLL $16,R11, R7
+ OR R7, R11
+
+/*
+ * store one byte at a time until pointer
+ * is alligned on a word boundary
+ */
+l1:
+ ANDCC $3,R10, R0
+ BE l2
+ MOVB R11, 0(R10)
+ ADD $1, R10
+ JMP l1
+
+/*
+ * turn R9 into end pointer-15
+ * store 16 at a time while theres room
+ */
+l2:
+ ADD $-15,R12, R9
+ SUBCC R10,R9, R0
+ BLEU l4
+l3:
+ MOVW R11, 0(R10)
+ MOVW R11, 4(R10)
+ ADD $16, R10
+ SUBCC R10,R9, R0
+ MOVW R11, -8(R10)
+ MOVW R11, -4(R10)
+ BGU l3
+
+/*
+ * turn R9 into end pointer-3
+ * store 4 at a time while theres room
+ */
+l4:
+ ADD $-3,R12, R9
+l5:
+ SUBCC R10,R9, R0
+ BLEU out
+ MOVW R11, 0(R10)
+ ADD $4, R10
+ JMP l5
+
+/*
+ * last loop, store byte at a time
+ */
+out:
+ SUBCC R10,R12, R0
+ BLEU ret
+ MOVB R11, 0(R10)
+ ADD $1, R10
+ JMP out
+
+ret:
+ MOVW s1+0(FP), R7
+ RETURN
--- /dev/null
+++ b/libkern/memset-spim.s
@@ -1,0 +1,1 @@
+#include "memset-mips.s"
--- /dev/null
+++ b/libkern/memset-thumb.s
@@ -1,0 +1,66 @@
+TO = 1
+TOE = 2
+N = 3
+TMP = 3 /* N and TMP don't overlap */
+
+TEXT memset(SB), $0
+ MOVW R0, R(TO)
+ MOVW data+4(FP), R(4)
+ MOVW n+8(FP), R(N)
+
+ ADD R(N), R(TO), R(TOE) /* to end pointer */
+
+ CMP $4, R(N) /* need at least 4 bytes to copy */
+ BLT _1tail
+
+ AND $0xFF, R(4) /* it's a byte */
+ SLL $8, R(4), R(TMP) /* replicate to a word */
+ ORR R(TMP), R(4)
+ SLL $16, R(4), R(TMP)
+ ORR R(TMP), R(4)
+
+_4align: /* align on 4 */
+ AND.S $3, R(TO), R(TMP)
+ BEQ _4aligned
+
+ MOVBU.P R(4), 1(R(TO)) /* implicit write back */
+ B _4align
+
+_4aligned:
+ SUB $31, R(TOE), R(TMP) /* do 32-byte chunks if possible */
+ CMP R(TMP), R(TO)
+ BHS _4tail
+
+ MOVW R4, R5 /* replicate */
+ MOVW R4, R6
+ MOVW R4, R7
+ MOVW R4, R8
+ MOVW R4, R9
+ MOVW R4, R10
+ MOVW R4, R11
+
+_f32loop:
+ CMP R(TMP), R(TO)
+ BHS _4tail
+
+ MOVM.IA.W [R4-R11], (R(TO))
+ B _f32loop
+
+_4tail:
+ SUB $3, R(TOE), R(TMP) /* do remaining words if possible */
+_4loop:
+ CMP R(TMP), R(TO)
+ BHS _1tail
+
+ MOVW.P R(4), 4(R(TO)) /* implicit write back */
+ B _4loop
+
+_1tail:
+ CMP R(TO), R(TOE)
+ BEQ _return
+
+ MOVBU.P R(4), 1(R(TO)) /* implicit write back */
+ B _1tail
+
+_return:
+ RET
--- /dev/null
+++ b/libkern/memset.c
@@ -1,0 +1,15 @@
+#include <lib9.h>
+
+void*
+memset(void *ap, int c, ulong n)
+{
+ char *p;
+ int m = (int)n;
+
+ p = ap;
+ while(m > 0) {
+ *p++ = c;
+ m--;
+ }
+ return ap;
+}
--- /dev/null
+++ b/libkern/mkfile
@@ -1,0 +1,83 @@
+<../mkconfig
+
+LIB=libkern.a
+
+COMMONFILES=\
+ abort.$O\
+ abs.$O\
+ atol.$O\
+ charstod.$O\
+ cistrcmp.$O\
+ cistrncmp.$O\
+ cistrstr.$O\
+ cleanname.$O\
+ convD2M.$O\
+ convM2D.$O\
+ convM2S.$O\
+ convS2M.$O\
+ dofmt.$O\
+ exp.$O\
+ fcallfmt.$O\
+ floor.$O\
+ fmt.$O\
+ fmtprint.$O\
+ fmtquote.$O\
+ fmtstr.$O\
+ fmtvprint.$O\
+ getfields.$O\
+ log.$O\
+ memccpy.$O\
+ memchr.$O\
+ memcmp.$O\
+# netmkaddr.$O\
+ pow.$O\
+ pow10.$O\
+ qsort.$O\
+ rune.$O\
+ runestrlen.$O\
+ sin.$O\
+ seprint.$O\
+ smprint.$O\
+ snprint.$O\
+ sqrt.$O\
+ strcat.$O\
+ strcmp.$O\
+ strcpy.$O\
+ strdup.$O\
+ strecpy.$O\
+ strlen.$O\
+ strncmp.$O\
+ strncpy.$O\
+ strrchr.$O\
+ strstr.$O\
+ strtod.$O\
+ strtol.$O\
+ strtoll.$O\
+ strtoul.$O\
+ strtoull.$O\
+ tokenize.$O\
+ toupper.$O\
+ u16.$O\
+ u32.$O\
+ u64.$O\
+ utfecpy.$O\
+ utflen.$O\
+ utfnlen.$O\
+ utfrrune.$O\
+ utfrune.$O\
+ vseprint.$O\
+ vsmprint.$O\
+ vsnprint.$O\
+
+<mkfile-$OBJTYPE #sets $TARGFILES
+
+OFILES= $COMMONFILES $TARGFILES
+HFILES= fmtdef.h
+
+<$ROOT/mkfiles/mksyslib-$SHELLTYPE
+
+convD2M.$O: $ROOT/include/fcall.h
+convM2D.$O: $ROOT/include/fcall.h
+convM2S.$O: $ROOT/include/fcall.h
+convS2M.$O: $ROOT/include/fcall.h
+fcallfmt.$O: $ROOT/include/fcall.h
--- /dev/null
+++ b/libkern/mkfile-386
@@ -1,0 +1,12 @@
+#
+# 386-specific files
+#
+TARGFILES=\
+ frexp-386.$O\
+ getfcr-386.$O\
+ memmove-386.$O\
+ memset-386.$O\
+ nan-386.$O\
+ strchr-386.$O\
+ vlop-386.$O\
+ vlrt-386.$O\
--- /dev/null
+++ b/libkern/mkfile-arm
@@ -1,0 +1,13 @@
+#
+# arm-specific files
+#
+TARGFILES=\
+ frexp-arm.$O\
+ getfcr-arm.$O\
+ memmove-arm.$O\
+ memset-arm.$O\
+ nan-arm.$O\
+ strchr-arm.$O\
+ vlop-arm.$O\
+ vlrt-arm.$O\
+ div-arm.$O\
--- /dev/null
+++ b/libkern/mkfile-mips
@@ -1,0 +1,13 @@
+#
+# mips-specific files
+#
+TARGFILES=\
+ frexp-mips.$O\
+ getfcr-mips.$O\
+ memmove-mips.$O\
+ memset-mips.$O\
+ nan-mips.$O\
+ strchr-mips.$O\
+ vlop-mips.$O\
+ vlrt-mips.$O\
+
--- /dev/null
+++ b/libkern/mkfile-power
@@ -1,0 +1,13 @@
+#
+# power-specific files
+#
+TARGFILES=\
+ frexp-power.$O\
+ getfcr-power.$O\
+ memmove-power.$O\
+ memset-power.$O\
+ nan-power.$O\
+ strchr-power.$O\
+ vlop-power.$O\
+ vlrt-power.$O\
+
--- /dev/null
+++ b/libkern/mkfile-sparc
@@ -1,0 +1,13 @@
+#
+# sparc-specific files
+#
+TARGFILES=\
+ frexp-sparc.$O\
+ getfcr-sparc.$O\
+ memmove-sparc.$O\
+ memset-sparc.$O\
+ nan-sparc.$O\
+ strchr-sparc.$O\
+ vlop-sparc.$O\
+ vlrt-sparc.$O\
+
--- /dev/null
+++ b/libkern/mkfile-spim
@@ -1,0 +1,8 @@
+#
+# spim-specific files
+#
+TARGFILES=\
+ getfcr-spim.$O\
+ memmove-spim.$O\
+ memset-spim.$O\
+ strchr-spim.$O\
--- /dev/null
+++ b/libkern/mkfile-thumb
@@ -1,0 +1,13 @@
+#
+# thumb-specific files
+#
+TARGFILES=\
+ frexp-thumb.$O\
+ getfcr-thumb.$O\
+ memmove-thumb.$O\
+ memset-thumb.$O\
+ nan-thumb.$O\
+ strchr-thumb.$O\
+ vlop-thumb.$O\
+ vlrt-thumb.$O\
+ div-thumb.$O\
--- /dev/null
+++ b/libkern/nan-386.c
@@ -1,0 +1,69 @@
+#include <lib9.h>
+
+#define NANEXP (2047<<20)
+#define NANMASK (2047<<20)
+#define NANSIGN (1<<31)
+
+double
+NaN(void)
+{
+ union
+ {
+ double d;
+ long x[2];
+ } a;
+
+ a.x[1] = NANEXP;
+ a.x[0] = 1;
+ return a.d;
+}
+
+int
+isNaN(double d)
+{
+ union
+ {
+ double d;
+ long x[2];
+ } a;
+
+ a.d = d;
+ if((a.x[1] & NANMASK) != NANEXP)
+ return 0;
+ return !isInf(d, 0);
+}
+
+double
+Inf(int sign)
+{
+ union
+ {
+ double d;
+ long x[2];
+ } a;
+
+ a.x[1] = NANEXP;
+ a.x[0] = 0;
+ if(sign < 0)
+ a.x[1] |= NANSIGN;
+ return a.d;
+}
+
+int
+isInf(double d, int sign)
+{
+ union
+ {
+ double d;
+ long x[2];
+ } a;
+
+ a.d = d;
+ if(a.x[0] != 0)
+ return 0;
+ if(a.x[1] == NANEXP)
+ return sign >= 0;
+ if(a.x[1] == (NANEXP|NANSIGN))
+ return sign <= 0;
+ return 0;
+}
--- /dev/null
+++ b/libkern/nan-arm.c
@@ -1,0 +1,69 @@
+#include <lib9.h>
+
+#define NANEXP (2047<<20)
+#define NANMASK (2047<<20)
+#define NANSIGN (1<<31)
+
+double
+NaN(void)
+{
+ union
+ {
+ double d;
+ long x[2];
+ } a;
+
+ a.x[1] = NANEXP;
+ a.x[0] = 1;
+ return a.d;
+}
+
+int
+isNaN(double d)
+{
+ union
+ {
+ double d;
+ long x[2];
+ } a;
+
+ a.d = d;
+ if((a.x[1] & NANMASK) != NANEXP)
+ return 0;
+ return !isInf(d, 0);
+}
+
+double
+Inf(int sign)
+{
+ union
+ {
+ double d;
+ long x[2];
+ } a;
+
+ a.x[1] = NANEXP;
+ a.x[0] = 0;
+ if(sign < 0)
+ a.x[1] |= NANSIGN;
+ return a.d;
+}
+
+int
+isInf(double d, int sign)
+{
+ union
+ {
+ double d;
+ long x[2];
+ } a;
+
+ a.d = d;
+ if(a.x[0] != 0)
+ return 0;
+ if(a.x[1] == NANEXP)
+ return sign >= 0;
+ if(a.x[1] == (NANEXP|NANSIGN))
+ return sign <= 0;
+ return 0;
+}
--- /dev/null
+++ b/libkern/nan-mips.c
@@ -1,0 +1,69 @@
+#include <lib9.h>
+
+#define NANEXP (2047<<20)
+#define NANMASK (2047<<20)
+#define NANSIGN (1<<31)
+
+double
+NaN(void)
+{
+ union
+ {
+ double d;
+ long x[2];
+ } a;
+
+ a.x[0] = NANEXP;
+ a.x[1] = 1;
+ return a.d;
+}
+
+int
+isNaN(double d)
+{
+ union
+ {
+ double d;
+ long x[2];
+ } a;
+
+ a.d = d;
+ if((a.x[0] & NANMASK) != NANEXP)
+ return 0;
+ return !isInf(d, 0);
+}
+
+double
+Inf(int sign)
+{
+ union
+ {
+ double d;
+ long x[2];
+ } a;
+
+ a.x[0] = NANEXP;
+ a.x[1] = 0;
+ if(sign < 0)
+ a.x[0] |= NANSIGN;
+ return a.d;
+}
+
+int
+isInf(double d, int sign)
+{
+ union
+ {
+ double d;
+ long x[2];
+ } a;
+
+ a.d = d;
+ if(a.x[1] != 0)
+ return 0;
+ if(a.x[0] == NANEXP)
+ return sign >= 0;
+ if(a.x[0] == (NANEXP|NANSIGN))
+ return sign <= 0;
+ return 0;
+}
--- /dev/null
+++ b/libkern/nan-power.c
@@ -1,0 +1,69 @@
+#include <lib9.h>
+
+#define NANEXP (2047<<20)
+#define NANMASK (2047<<20)
+#define NANSIGN (1<<31)
+
+double
+NaN(void)
+{
+ union
+ {
+ double d;
+ long x[2];
+ } a;
+
+ a.x[0] = NANEXP;
+ a.x[1] = 1;
+ return a.d;
+}
+
+int
+isNaN(double d)
+{
+ union
+ {
+ double d;
+ long x[2];
+ } a;
+
+ a.d = d;
+ if((a.x[0] & NANMASK) != NANEXP)
+ return 0;
+ return !isInf(d, 0);
+}
+
+double
+Inf(int sign)
+{
+ union
+ {
+ double d;
+ long x[2];
+ } a;
+
+ a.x[0] = NANEXP;
+ a.x[1] = 0;
+ if(sign < 0)
+ a.x[0] |= NANSIGN;
+ return a.d;
+}
+
+int
+isInf(double d, int sign)
+{
+ union
+ {
+ double d;
+ long x[2];
+ } a;
+
+ a.d = d;
+ if(a.x[1] != 0)
+ return 0;
+ if(a.x[0] == NANEXP)
+ return sign >= 0;
+ if(a.x[0] == (NANEXP|NANSIGN))
+ return sign <= 0;
+ return 0;
+}
--- /dev/null
+++ b/libkern/nan-sparc.c
@@ -1,0 +1,69 @@
+#include <lib9.h>
+
+#define NANEXP (2047<<20)
+#define NANMASK (2047<<20)
+#define NANSIGN (1<<31)
+
+double
+NaN(void)
+{
+ union
+ {
+ double d;
+ long x[2];
+ } a;
+
+ a.x[0] = NANEXP;
+ a.x[1] = 1;
+ return a.d;
+}
+
+int
+isNaN(double d)
+{
+ union
+ {
+ double d;
+ long x[2];
+ } a;
+
+ a.d = d;
+ if((a.x[0] & NANMASK) != NANEXP)
+ return 0;
+ return !isInf(d, 0);
+}
+
+double
+Inf(int sign)
+{
+ union
+ {
+ double d;
+ long x[2];
+ } a;
+
+ a.x[0] = NANEXP;
+ a.x[1] = 0;
+ if(sign < 0)
+ a.x[0] |= NANSIGN;
+ return a.d;
+}
+
+int
+isInf(double d, int sign)
+{
+ union
+ {
+ double d;
+ long x[2];
+ } a;
+
+ a.d = d;
+ if(a.x[1] != 0)
+ return 0;
+ if(a.x[0] == NANEXP)
+ return sign >= 0;
+ if(a.x[0] == (NANEXP|NANSIGN))
+ return sign <= 0;
+ return 0;
+}
--- /dev/null
+++ b/libkern/nan-spim.c
@@ -1,0 +1,69 @@
+#include <lib9.h>
+
+#define NANEXP (2047<<20)
+#define NANMASK (2047<<20)
+#define NANSIGN (1<<31)
+
+double
+NaN(void)
+{
+ union
+ {
+ double d;
+ long x[2];
+ } a;
+
+ a.x[1] = NANEXP;
+ a.x[0] = 1;
+ return a.d;
+}
+
+int
+isNaN(double d)
+{
+ union
+ {
+ double d;
+ long x[2];
+ } a;
+
+ a.d = d;
+ if((a.x[1] & NANMASK) != NANEXP)
+ return 0;
+ return !isInf(d, 0);
+}
+
+double
+Inf(int sign)
+{
+ union
+ {
+ double d;
+ long x[2];
+ } a;
+
+ a.x[1] = NANEXP;
+ a.x[0] = 0;
+ if(sign < 0)
+ a.x[1] |= NANSIGN;
+ return a.d;
+}
+
+int
+isInf(double d, int sign)
+{
+ union
+ {
+ double d;
+ long x[2];
+ } a;
+
+ a.d = d;
+ if(a.x[0] != 0)
+ return 0;
+ if(a.x[1] == NANEXP)
+ return sign >= 0;
+ if(a.x[1] == (NANEXP|NANSIGN))
+ return sign <= 0;
+ return 0;
+}
--- /dev/null
+++ b/libkern/nan-thumb.c
@@ -1,0 +1,69 @@
+#include <lib9.h>
+
+#define NANEXP (2047<<20)
+#define NANMASK (2047<<20)
+#define NANSIGN (1<<31)
+
+double
+NaN(void)
+{
+ union
+ {
+ double d;
+ long x[2];
+ } a;
+
+ a.x[0] = NANEXP;
+ a.x[1] = 1;
+ return a.d;
+}
+
+int
+isNaN(double d)
+{
+ union
+ {
+ double d;
+ long x[2];
+ } a;
+
+ a.d = d;
+ if((a.x[0] & NANMASK) != NANEXP)
+ return 0;
+ return !isInf(d, 0);
+}
+
+double
+Inf(int sign)
+{
+ union
+ {
+ double d;
+ long x[2];
+ } a;
+
+ a.x[0] = NANEXP;
+ a.x[1] = 0;
+ if(sign < 0)
+ a.x[0] |= NANSIGN;
+ return a.d;
+}
+
+int
+isInf(double d, int sign)
+{
+ union
+ {
+ double d;
+ long x[2];
+ } a;
+
+ a.d = d;
+ if(a.x[1] != 0)
+ return 0;
+ if(a.x[0] == NANEXP)
+ return sign >= 0;
+ if(a.x[0] == (NANEXP|NANSIGN))
+ return sign <= 0;
+ return 0;
+}
--- /dev/null
+++ b/libkern/netmkaddr.c
@@ -1,0 +1,50 @@
+#include <lib9.h>
+
+/*
+ * make an address, add the defaults
+ */
+char *
+netmkaddr(char *linear, char *defnet, char *defsrv)
+{
+ static char addr[4*(NAMELEN+1)];
+ char *cp;
+
+ /*
+ * dump network name
+ */
+ cp = strchr(linear, '!');
+ if(cp == 0){
+ if(defnet==0){
+ if(defsrv)
+ sprint(addr, "net!%.*s!%.*s", 2*NAMELEN, linear,
+ NAMELEN, defsrv);
+ else
+ sprint(addr, "net!%.*s", 2*NAMELEN, linear);
+ } else {
+ if(defsrv)
+ sprint(addr, "%.*s!%.*s!%.*s", NAMELEN, defnet,
+ 2*NAMELEN, linear, NAMELEN, defsrv);
+ else
+ sprint(addr, "%.*s!%.*s", NAMELEN, defnet,
+ 2*NAMELEN, linear);
+ }
+ return addr;
+ }
+
+ /*
+ * if there is already a service, use it
+ */
+ cp = strchr(cp+1, '!');
+ if(cp)
+ return linear;
+
+ /*
+ * add default service
+ */
+ if(defsrv == 0)
+ return linear;
+ sprint(addr, "%.*s!%.*s", 3*NAMELEN, linear,
+ NAMELEN, defsrv);
+
+ return addr;
+}
--- /dev/null
+++ b/libkern/pow.c
@@ -1,0 +1,68 @@
+#include <lib9.h>
+
+double
+pow(double x, double y) /* return x ^ y (exponentiation) */
+{
+ double xy, y1, ye;
+ long i;
+ int ex, ey, flip;
+
+ if(y == 0.0)
+ return 1.0;
+
+ flip = 0;
+ if(y < 0.){
+ y = -y;
+ flip = 1;
+ }
+ y1 = modf(y, &ye);
+ if(y1 != 0.0){
+ if(x <= 0.)
+ goto zreturn;
+ if(y1 > 0.5) {
+ y1 -= 1.;
+ ye += 1.;
+ }
+ xy = exp(y1 * log(x));
+ }else
+ xy = 1.0;
+ if(ye > 0x7FFFFFFF){ /* should be ~0UL but compiler can't convert double to ulong */
+ if(x <= 0.){
+ zreturn:
+ if(x==0. && !flip)
+ return 0.;
+ return NaN();
+ }
+ if(flip){
+ if(y == .5)
+ return 1./sqrt(x);
+ y = -y;
+ }else if(y == .5)
+ return sqrt(x);
+ return exp(y * log(x));
+ }
+ x = frexp(x, &ex);
+ ey = 0;
+ i = ye;
+ if(i)
+ for(;;){
+ if(i & 1){
+ xy *= x;
+ ey += ex;
+ }
+ i >>= 1;
+ if(i == 0)
+ break;
+ x *= x;
+ ex <<= 1;
+ if(x < .5){
+ x += x;
+ ex -= 1;
+ }
+ }
+ if(flip){
+ xy = 1. / xy;
+ ey = -ey;
+ }
+ return ldexp(xy, ey);
+}
--- /dev/null
+++ b/libkern/pow10.c
@@ -1,0 +1,51 @@
+#ifdef LINUX_386
+#define _MATH_H
+#endif
+#include "lib9.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,
+ 1.0e70, 1.0e71, 1.0e72, 1.0e73, 1.0e74, 1.0e75, 1.0e76, 1.0e77, 1.0e78, 1.0e79,
+ 1.0e80, 1.0e81, 1.0e82, 1.0e83, 1.0e84, 1.0e85, 1.0e86, 1.0e87, 1.0e88, 1.0e89,
+ 1.0e90, 1.0e91, 1.0e92, 1.0e93, 1.0e94, 1.0e95, 1.0e96, 1.0e97, 1.0e98, 1.0e99,
+ 1.0e100,1.0e101,1.0e102,1.0e103,1.0e104,1.0e105,1.0e106,1.0e107,1.0e108,1.0e109,
+ 1.0e110,1.0e111,1.0e112,1.0e113,1.0e114,1.0e115,1.0e116,1.0e117,1.0e118,1.0e119,
+ 1.0e120,1.0e121,1.0e122,1.0e123,1.0e124,1.0e125,1.0e126,1.0e127,1.0e128,1.0e129,
+ 1.0e130,1.0e131,1.0e132,1.0e133,1.0e134,1.0e135,1.0e136,1.0e137,1.0e138,1.0e139,
+ 1.0e140,1.0e141,1.0e142,1.0e143,1.0e144,1.0e145,1.0e146,1.0e147,1.0e148,1.0e149,
+ 1.0e150,1.0e151,1.0e152,1.0e153,1.0e154,1.0e155,1.0e156,1.0e157,1.0e158,1.0e159,
+};
+
+double
+pow10(int n)
+{
+ int m;
+
+ if(n < 0) {
+ n = -n;
+ if(n < sizeof(tab)/sizeof(tab[0]))
+ return 1/tab[n];
+ m = n/2;
+ return 1/(pow10(m) * pow10(n-m));
+ }
+ if(n < sizeof(tab)/sizeof(tab[0]))
+ return tab[n];
+ m = n/2;
+ return pow10(m) * pow10(n-m);
+}
--- /dev/null
+++ b/libkern/qsort.c
@@ -1,0 +1,123 @@
+/*
+ * qsort -- simple quicksort
+ */
+
+#include "lib9.h"
+typedef
+struct
+{
+ int (*cmp)(void*, void*);
+ void (*swap)(char*, char*, long);
+ long es;
+} Sort;
+
+static void
+swapb(char *i, char *j, long es)
+{
+ char c;
+
+ do {
+ c = *i;
+ *i++ = *j;
+ *j++ = c;
+ es--;
+ } while(es != 0);
+
+}
+
+static void
+swapi(char *ii, char *ij, long es)
+{
+ long *i, *j, c;
+
+ i = (long*)ii;
+ j = (long*)ij;
+ do {
+ c = *i;
+ *i++ = *j;
+ *j++ = c;
+ es -= sizeof(long);
+ } while(es != 0);
+}
+
+static char*
+pivot(char *a, long n, Sort *p)
+{
+ long j;
+ char *pi, *pj, *pk;
+
+ j = n/6 * p->es;
+ pi = a + j; /* 1/6 */
+ j += j;
+ pj = pi + j; /* 1/2 */
+ pk = pj + j; /* 5/6 */
+ if(p->cmp(pi, pj) < 0) {
+ if(p->cmp(pi, pk) < 0) {
+ if(p->cmp(pj, pk) < 0)
+ return pj;
+ return pk;
+ }
+ return pi;
+ }
+ if(p->cmp(pj, pk) < 0) {
+ if(p->cmp(pi, pk) < 0)
+ return pi;
+ return pk;
+ }
+ return pj;
+}
+
+static void
+qsorts(char *a, long n, Sort *p)
+{
+ long j, es;
+ char *pi, *pj, *pn;
+
+ es = p->es;
+ while(n > 1) {
+ if(n > 10) {
+ pi = pivot(a, n, p);
+ } else
+ pi = a + (n>>1)*es;
+
+ p->swap(a, pi, es);
+ pi = a;
+ pn = a + n*es;
+ pj = pn;
+ for(;;) {
+ do
+ pi += es;
+ while(pi < pn && p->cmp(pi, a) < 0);
+ do
+ pj -= es;
+ while(pj > a && p->cmp(pj, a) > 0);
+ if(pj < pi)
+ break;
+ p->swap(pi, pj, es);
+ }
+ p->swap(a, pj, es);
+ j = (pj - a) / es;
+
+ n = n-j-1;
+ if(j >= n) {
+ qsorts(a, j, p);
+ a += (j+1)*es;
+ } else {
+ qsorts(a + (j+1)*es, n, p);
+ n = j;
+ }
+ }
+}
+
+void
+qsort(void *va, long n, long es, int (*cmp)(void*, void*))
+{
+ Sort s;
+
+ s.cmp = cmp;
+ s.es = es;
+ s.swap = swapi;
+ if(((uintptr)va | es) % sizeof(long))
+ s.swap = swapb;
+ qsorts((char*)va, n, &s);
+}
--- /dev/null
+++ b/libkern/rune.c
@@ -1,0 +1,165 @@
+#include "lib9.h"
+
+#define Bit(i) (7-(i))
+/* N 0's preceded by i 1's, T(Bit(2)) is 1100 0000 */
+#define T(i) (((1 << (Bit(i)+1))-1) ^ 0xFF)
+/* 0000 0000 0000 0111 1111 1111 */
+#define RuneX(i) ((1 << (Bit(i) + ((i)-1)*Bitx))-1)
+
+enum
+{
+ Bitx = Bit(1),
+
+ Tx = T(1), /* 1000 0000 */
+ Rune1 = (1<<(Bit(0)+0*Bitx))-1, /* 0000 0000 0000 0000 0111 1111 */
+
+ Maskx = (1<<Bitx)-1, /* 0011 1111 */
+ Testx = Maskx ^ 0xFF, /* 1100 0000 */
+
+ SurrogateMin = 0xD800,
+ SurrogateMax = 0xDFFF,
+
+ Bad = Runeerror,
+};
+
+int
+chartorune(Rune *rune, char *str)
+{
+ int c[UTFmax], i;
+ Rune l;
+
+ /*
+ * N character sequence
+ * 00000-0007F => T1
+ * 00080-007FF => T2 Tx
+ * 00800-0FFFF => T3 Tx Tx
+ * 10000-10FFFF => T4 Tx Tx Tx
+ */
+
+ c[0] = *(uchar*)(str);
+ if(c[0] < Tx){
+ *rune = c[0];
+ return 1;
+ }
+ l = c[0];
+
+ for(i = 1; i < UTFmax; i++) {
+ c[i] = *(uchar*)(str+i);
+ c[i] ^= Tx;
+ if(c[i] & Testx)
+ goto bad;
+ l = (l << Bitx) | c[i];
+ if(c[0] < T(i + 2)) {
+ l &= RuneX(i + 1);
+ if(i == 1) {
+ if(c[0] < T(2) || l <= Rune1)
+ goto bad;
+ } else if(l <= RuneX(i) || l > Runemax)
+ goto bad;
+ if (i == 2 && SurrogateMin <= l && l <= SurrogateMax)
+ goto bad;
+ *rune = l;
+ return i + 1;
+ }
+ }
+
+ /*
+ * bad decoding
+ */
+bad:
+ *rune = Bad;
+ return 1;
+}
+
+int
+runetochar(char *str, Rune *rune)
+{
+ int i, j;
+ Rune c;
+
+ c = *rune;
+ if(c <= Rune1) {
+ str[0] = c;
+ return 1;
+ }
+
+ /*
+ * one character sequence
+ * 00000-0007F => 00-7F
+ * two character sequence
+ * 0080-07FF => T2 Tx
+ * three character sequence
+ * 0800-FFFF => T3 Tx Tx
+ * four character sequence (21-bit value)
+ * 10000-1FFFFF => T4 Tx Tx Tx
+ * If the Rune is out of range or a surrogate half,
+ * convert it to the error rune.
+ * Do this test when i==3 because the error rune encodes to three bytes.
+ * Doing it earlier would duplicate work, since an out of range
+ * Rune wouldn't have fit in one or two bytes.
+ */
+ for(i = 2; i < UTFmax + 1; i++){
+ if(i == 3){
+ if(c > Runemax)
+ c = Runeerror;
+ if(SurrogateMin <= c && c <= SurrogateMax)
+ c = Runeerror;
+ }
+ if (c <= RuneX(i) || i == UTFmax ) {
+ str[0] = T(i) | (c >> (i - 1)*Bitx);
+ for(j = 1; j < i; j++)
+ str[j] = Tx | ((c >> (i - j - 1)*Bitx) & Maskx);
+ return i;
+ }
+ }
+ return UTFmax;
+}
+
+int
+runelen(long c)
+{
+ Rune rune;
+ char str[10];
+
+ rune = c;
+ return runetochar(str, &rune);
+}
+
+int
+runenlen(Rune *r, int nrune)
+{
+ int nb, i;
+ Rune c;
+
+ nb = 0;
+ while(nrune--) {
+ c = *r++;
+ if(c <= Rune1){
+ nb++;
+ } else {
+ for(i = 2; i < UTFmax + 1; i++)
+ if(c <= RuneX(i) || i == UTFmax){
+ nb += i;
+ break;
+ }
+ }
+ }
+ return nb;
+}
+
+int
+fullrune(char *str, int n)
+{
+ int i;
+ Rune c;
+
+ if(n <= 0)
+ return 0;
+ c = *(uchar*)str;
+ if(c < Tx)
+ return 1;
+ for(i = 3; i < UTFmax + 1; i++)
+ if(c < T(i))
+ return n >= i - 1;
+ return n >= UTFmax;
+}
--- /dev/null
+++ b/libkern/runestrlen.c
@@ -1,0 +1,13 @@
+#include "lib9.h"
+
+
+long
+runestrlen(Rune *s)
+{
+ int i;
+
+ i = 0;
+ while(*s++)
+ i++;
+ return i;
+}
--- /dev/null
+++ b/libkern/seprint.c
@@ -1,0 +1,26 @@
+/*
+ * 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 "lib9.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;
+}
--- /dev/null
+++ b/libkern/sin.c
@@ -1,0 +1,67 @@
+/*
+ C program for floating point sin/cos.
+ Calls modf.
+ There are no error exits.
+ Coefficients are #3370 from Hart & Cheney (18.80D).
+*/
+
+#include <lib9.h>
+
+#define p0 .1357884097877375669092680e8
+#define p1 -.4942908100902844161158627e7
+#define p2 .4401030535375266501944918e6
+#define p3 -.1384727249982452873054457e5
+#define p4 .1459688406665768722226959e3
+#define q0 .8644558652922534429915149e7
+#define q1 .4081792252343299749395779e6
+#define q2 .9463096101538208180571257e4
+#define q3 .1326534908786136358911494e3
+
+static
+double
+sinus(double arg, int quad)
+{
+ double e, f, ysq, x, y, temp1, temp2;
+ int k;
+
+ x = arg;
+ if(x < 0) {
+ x = -x;
+ quad += 2;
+ }
+ x *= 1/PIO2; /* underflow? */
+ if(x > 32764) {
+ y = modf(x, &e);
+ e += quad;
+ modf(0.25*e, &f);
+ quad = e - 4*f;
+ } else {
+ k = x;
+ y = x - k;
+ quad += k;
+ quad &= 3;
+ }
+ if(quad & 1)
+ y = 1-y;
+ if(quad > 1)
+ y = -y;
+
+ ysq = y*y;
+ temp1 = ((((p4*ysq+p3)*ysq+p2)*ysq+p1)*ysq+p0)*y;
+ temp2 = ((((ysq+q3)*ysq+q2)*ysq+q1)*ysq+q0);
+ return temp1/temp2;
+}
+
+double
+cos(double arg)
+{
+ if(arg < 0)
+ arg = -arg;
+ return sinus(arg, 1);
+}
+
+double
+sin(double arg)
+{
+ return sinus(arg, 0);
+}
--- /dev/null
+++ b/libkern/smprint.c
@@ -1,0 +1,26 @@
+/*
+ * 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 "lib9.h"
+
+char*
+smprint(char *fmt, ...)
+{
+ va_list args;
+ char *p;
+
+ va_start(args, fmt);
+ p = vsmprint(fmt, args);
+ va_end(args);
+ return p;
+}
--- /dev/null
+++ b/libkern/snprint.c
@@ -1,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 "lib9.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;
+}
+
--- /dev/null
+++ b/libkern/sqrt.c
@@ -1,0 +1,53 @@
+/*
+ sqrt returns the square root of its floating
+ point argument. Newton's method.
+
+ calls frexp
+*/
+
+#include <lib9.h>
+
+double
+sqrt(double arg)
+{
+ double x, temp;
+ int exp, i;
+
+ if(arg <= 0) {
+ if(arg < 0)
+ return NaN();
+ return 0;
+ }
+ if(isInf(arg, 1))
+ return arg;
+ x = frexp(arg, &exp);
+ while(x < 0.5) {
+ x *= 2;
+ exp--;
+ }
+ /*
+ * NOTE
+ * this wont work on 1's comp
+ */
+ if(exp & 1) {
+ x *= 2;
+ exp--;
+ }
+ temp = 0.5 * (1.0+x);
+
+ while(exp > 60) {
+ temp *= (1L<<30);
+ exp -= 60;
+ }
+ while(exp < -60) {
+ temp /= (1L<<30);
+ exp += 60;
+ }
+ if(exp >= 0)
+ temp *= 1L << (exp/2);
+ else
+ temp /= 1L << (-exp/2);
+ for(i=0; i<=4; i++)
+ temp = 0.5*(temp + arg/temp);
+ return temp;
+}
--- /dev/null
+++ b/libkern/strcat.c
@@ -1,0 +1,9 @@
+#include <lib9.h>
+
+char*
+strcat(char *s1, char *s2)
+{
+
+ strcpy(strchr(s1, 0), s2);
+ return s1;
+}
--- /dev/null
+++ b/libkern/strchr-386.s
@@ -1,0 +1,29 @@
+ TEXT strchr(SB),$0
+/*
+ * look for null
+ */
+ MOVL p+0(FP), DI
+ MOVL $-1, CX
+ MOVL $0, AX
+ CLD
+
+ REPN; SCASB
+
+/*
+ * look for real char
+ */
+ MOVL DI, CX
+ MOVL p+0(FP), DI
+ SUBL DI, CX
+ MOVBLZX c+4(FP), AX
+
+ REPN; SCASB
+
+ JEQ found
+ MOVL $0, AX
+ RET
+
+found:
+ MOVL DI, AX
+ SUBL $1, AX
+ RET
--- /dev/null
+++ b/libkern/strchr-arm.s
@@ -1,0 +1,52 @@
+TEXT strchr(SB), $-4
+ MOVBU c+4(FP), R1
+ CMP $0, R1
+ BEQ _null
+
+_strchr: /* not looking for a null, byte at a time */
+ MOVBU.P 1(R0), R2
+ CMP R1, R2
+ BEQ _sub1
+
+ CMP $0, R2
+ BNE _strchr
+
+_return0: /* character not found in string, return 0 */
+ MOVW $0, R0
+ RET
+
+_null: /* looking for null, align */
+ AND.S $3, R0, R2
+ BEQ _aligned
+
+ MOVBU.P 1(R0), R4
+ CMP $0, R4
+ BEQ _sub1
+ B _null
+
+_aligned:
+ MOVW $0xFF, R3 /* mask */
+
+_loop:
+ MOVW.P 4(R0), R4 /* 4 at a time */
+ TST R4, R3 /* AND.S R2, R3, Rx */
+ BEQ _sub4
+ TST R4>>8, R3
+ BEQ _sub3
+ TST R4>>16, R3
+ BEQ _sub2
+ TST R4>>24, R3
+ BNE _loop
+
+_sub1: /* compensate for pointer increment */
+ SUB $1, R0
+ RET
+_sub2:
+ SUB $2, R0
+ RET
+_sub3:
+ SUB $3, R0
+ RET
+_sub4:
+ SUB $4, R0
+ RET
--- /dev/null
+++ b/libkern/strchr-mips.s
@@ -1,0 +1,63 @@
+ TEXT strchr(SB), $0
+MOVW R1, 0(FP)
+ MOVB c+7(FP), R4
+ MOVW s+0(FP), R3
+
+ BEQ R4, l2
+
+/*
+ * char is not null
+ */
+l1:
+ MOVB (R3), R1
+ ADDU $1, R3
+ BEQ R1, ret
+ BNE R1,R4, l1
+ JMP rm1
+
+/*
+ * char is null
+ * align to word
+ */
+l2:
+ AND $3,R3, R1
+ BEQ R1, l3
+ MOVB (R3), R1
+ ADDU $1, R3
+ BNE R1, l2
+ JMP rm1
+
+l3:
+ MOVW $0xff000000, R6
+ MOVW $0x00ff0000, R7
+
+l4:
+ MOVW (R3), R5
+ ADDU $4, R3
+ AND R6,R5, R1
+ AND R7,R5, R2
+ BEQ R1, b0
+ AND $0xff00,R5, R1
+ BEQ R2, b1
+ AND $0xff,R5, R2
+ BEQ R1, b2
+ BNE R2, l4
+
+rm1:
+ ADDU $-1,R3, R1
+ JMP ret
+
+b2:
+ ADDU $-2,R3, R1
+ JMP ret
+
+b1:
+ ADDU $-3,R3, R1
+ JMP ret
+
+b0:
+ ADDU $-4,R3, R1
+ JMP ret
+
+ret:
+ RET
--- /dev/null
+++ b/libkern/strchr-power.s
@@ -1,0 +1,16 @@
+/*
+ * BUG: it's slow
+ */
+ TEXT strchr(SB), $0
+ MOVBZ c+7(FP), R4
+ SUB $1, R3
+l1:
+ MOVBZU 1(R3), R6
+ CMP R6, R4
+ BEQ eq
+ CMP R6, $0
+ BNE l1
+nf:
+ MOVW $0, R3
+eq:
+ RETURN
--- /dev/null
+++ b/libkern/strchr-sparc.s
@@ -1,0 +1,73 @@
+ TEXT strchr(SB), $0
+
+MOVW R7, 0(FP)
+ MOVB c+7(FP), R10
+ MOVW s+0(FP), R9
+
+ SUBCC R0,R10, R0
+ BE l2
+
+/*
+ * char is not null
+ */
+l1:
+ MOVB (R9), R7
+ ADD $1, R9
+ SUBCC R0,R7, R0
+ BE ret
+ SUBCC R7,R10, R0
+ BNE l1
+ JMP rm1
+
+/*
+ * char is null
+ * align to word
+ */
+l2:
+ ANDCC $3,R9, R0
+ BE l3
+ MOVB (R9), R7
+ ADD $1, R9
+ SUBCC R0,R7, R0
+ BNE l2
+ JMP rm1
+
+/*
+ * develop byte masks
+ */
+l3:
+ MOVW $0xff, R17
+ SLL $8,R17, R16
+ SLL $16,R17, R13
+ SLL $24,R17, R12
+
+l4:
+ MOVW (R9), R11
+ ADD $4, R9
+ ANDCC R12,R11, R0
+ BE b0
+ ANDCC R13,R11, R0
+ BE b1
+ ANDCC R16,R11, R0
+ BE b2
+ ANDCC R17,R11, R0
+ BNE l4
+
+rm1:
+ SUB $1,R9, R7
+ JMP ret
+
+b2:
+ SUB $2,R9, R7
+ JMP ret
+
+b1:
+ SUB $3,R9, R7
+ JMP ret
+
+b0:
+ SUB $4,R9, R7
+ JMP ret
+
+ret:
+ RETURN
--- /dev/null
+++ b/libkern/strchr-spim.c
@@ -1,0 +1,18 @@
+#include <lib9.h>
+
+char*
+strchr(char *s, int c)
+{
+ char c1;
+
+ if(c == 0) {
+ while(*s++)
+ ;
+ return s-1;
+ }
+
+ while(c1 = *s++)
+ if(c1 == c)
+ return s-1;
+ return 0;
+}
--- /dev/null
+++ b/libkern/strchr-spim.s
@@ -1,0 +1,1 @@
+#include "strchr-mips.s"
--- /dev/null
+++ b/libkern/strchr-thumb.s
@@ -1,0 +1,52 @@
+TEXT strchr(SB), $-4
+ MOVBU c+4(FP), R1
+ CMP $0, R1
+ BEQ _null
+
+_strchr: /* not looking for a null, byte at a time */
+ MOVBU.P 1(R0), R2
+ CMP R1, R2
+ BEQ _sub1
+
+ CMP $0, R2
+ BNE _strchr
+
+_return0: /* character not found in string, return 0 */
+ MOVW $0, R0
+ RET
+
+_null: /* looking for null, align */
+ AND.S $3, R0, R2
+ BEQ _aligned
+
+ MOVBU.P 1(R0), R4
+ CMP $0, R4
+ BEQ _sub1
+ B _null
+
+_aligned:
+ MOVW $0xFF, R3 /* mask */
+
+_loop:
+ MOVW.P 4(R0), R4 /* 4 at a time */
+ TST R4, R3 /* AND.S R2, R3, Rx */
+ BEQ _sub4
+ TST R4>>8, R3
+ BEQ _sub3
+ TST R4>>16, R3
+ BEQ _sub2
+ TST R4>>24, R3
+ BNE _loop
+
+_sub1: /* compensate for pointer increment */
+ SUB $1, R0
+ RET
+_sub2:
+ SUB $2, R0
+ RET
+_sub3:
+ SUB $3, R0
+ RET
+_sub4:
+ SUB $4, R0
+ RET
--- /dev/null
+++ b/libkern/strchr.c
@@ -1,0 +1,18 @@
+#include <lib9.h>
+
+char*
+strchr(char *s, int c)
+{
+ char c1;
+
+ if(c == 0) {
+ while(*s++)
+ ;
+ return s-1;
+ }
+
+ while(c1 = *s++)
+ if(c1 == c)
+ return s-1;
+ return 0;
+}
--- /dev/null
+++ b/libkern/strcmp-power.s
@@ -1,0 +1,21 @@
+TEXT strcmp(SB), $0
+
+ MOVW s2+4(FP), R4
+
+ SUB $1, R3
+ SUB $1, R4
+l1:
+ MOVBZU 1(R3), R5
+ MOVBZU 1(R4), R6
+ CMP R5, R6
+ BNE ne
+ CMP R5, $0
+ BNE l1
+ MOVW $0, R3
+ RETURN
+ne:
+ MOVW $1, R3
+ BGT ret
+ MOVW $-1, R3
+ret:
+ RETURN
--- /dev/null
+++ b/libkern/strcmp.c
@@ -1,0 +1,19 @@
+#include <lib9.h>
+
+int
+strcmp(char *s1, char *s2)
+{
+ unsigned c1, c2;
+
+ for(;;) {
+ c1 = *s1++;
+ c2 = *s2++;
+ if(c1 != c2) {
+ if(c1 > c2)
+ return 1;
+ return -1;
+ }
+ if(c1 == 0)
+ return 0;
+ }
+}
--- /dev/null
+++ b/libkern/strcpy.c
@@ -1,0 +1,15 @@
+#include <lib9.h>
+#define N 10000
+
+char*
+strcpy(char *s1, char *s2)
+{
+ char *os1;
+
+ os1 = s1;
+ while(!memccpy(s1, s2, 0, N)) {
+ s1 += N;
+ s2 += N;
+ }
+ return os1;
+}
--- /dev/null
+++ b/libkern/strdup.c
@@ -1,0 +1,12 @@
+#include <lib9.h>
+
+char*
+strdup(char *s)
+{
+ char *os;
+
+ os = malloc(strlen(s) + 1);
+ if(os == 0)
+ return 0;
+ return strcpy(os, s);
+}
--- /dev/null
+++ b/libkern/strecpy.c
@@ -1,0 +1,16 @@
+#include <lib9.h>
+
+char*
+strecpy(char *to, char *e, char *from)
+{
+ if(to >= e)
+ return to;
+ to = memccpy(to, from, '\0', e - to);
+ if(to == nil){
+ to = e - 1;
+ *to = '\0';
+ }else{
+ to--;
+ }
+ return to;
+}
--- /dev/null
+++ b/libkern/strlen.c
@@ -1,0 +1,8 @@
+#include <lib9.h>
+
+long
+strlen(char *s)
+{
+
+ return strchr(s, 0) - s;
+}
--- /dev/null
+++ b/libkern/strncmp-power.s
@@ -1,0 +1,29 @@
+TEXT strncmp(SB), $0
+#define BDNZ BC 16,0,
+
+ MOVW s2+4(FP), R4
+ MOVW n+8(FP), R7
+
+ CMP R7, $0
+ MOVW R7, CTR
+ BLE eq
+
+ SUB $1, R3
+ SUB $1, R4
+l1:
+ MOVBZU 1(R3), R5
+ MOVBZU 1(R4), R6
+ CMP R5, R6
+ BNE ne
+ CMP R5, $0
+ BEQ eq
+ BDNZ l1
+eq:
+ MOVW $0, R3
+ RETURN
+ne:
+ MOVW $1, R3
+ BGT ret
+ MOVW $-1, R3
+ret:
+ RETURN
--- /dev/null
+++ b/libkern/strncmp.c
@@ -1,0 +1,21 @@
+#include <lib9.h>
+
+int
+strncmp(char *s1, char *s2, long n)
+{
+ unsigned c1, c2;
+
+ while(n > 0) {
+ c1 = *s1++;
+ c2 = *s2++;
+ n--;
+ if(c1 != c2) {
+ if(c1 > c2)
+ return 1;
+ return -1;
+ }
+ if(c1 == 0)
+ break;
+ }
+ return 0;
+}
--- /dev/null
+++ b/libkern/strncpy.c
@@ -1,0 +1,17 @@
+#include <lib9.h>
+
+char*
+strncpy(char *s1, char *s2, long n)
+{
+ int i;
+ char *os1;
+
+ os1 = s1;
+ for(i = 0; i < n; i++)
+ if((*s1++ = *s2++) == 0) {
+ while(++i < n)
+ *s1++ = 0;
+ return os1;
+ }
+ return os1;
+}
--- /dev/null
+++ b/libkern/strrchr.c
@@ -1,0 +1,14 @@
+#include <lib9.h>
+
+char*
+strrchr(char *s, int c)
+{
+ char *r;
+
+ if(c == 0)
+ return strchr(s, 0);
+ r = 0;
+ while(s = strchr(s, c))
+ r = s++;
+ return r;
+}
--- /dev/null
+++ b/libkern/strstr.c
@@ -1,0 +1,21 @@
+#include <lib9.h>
+
+/*
+ * Return pointer to first occurrence of s2 in s1,
+ * 0 if none
+ */
+char*
+strstr(char *s1, char *s2)
+{
+ char *p;
+ int f, n;
+
+ f = s2[0];
+ if(f == 0)
+ return s1;
+ n = strlen(s2);
+ for(p=strchr(s1, f); p; p=strchr(p+1, f))
+ if(strncmp(p, s2, n) == 0)
+ return p;
+ return 0;
+}
--- /dev/null
+++ b/libkern/strtod.c
@@ -1,0 +1,31 @@
+#include <lib9.h>
+
+static int
+strtodf(void *vp)
+{
+ return *(*((char**)vp))++;
+}
+
+double
+strtod(char *s, char **end)
+{
+ double d;
+ char *ss;
+ int c;
+
+ ss = s;
+ d = charstod(strtodf, &s);
+ /*
+ * Fix cases like 2.3e+ , which charstod will consume
+ */
+ if(end){
+ *end = --s;
+ while(s > ss){
+ c = *--s;
+ if(c!='-' && c!='+' && c!='e' && c!='E')
+ break;
+ (*end)--;
+ }
+ }
+ return d;
+}
--- /dev/null
+++ b/libkern/strtol.c
@@ -1,0 +1,94 @@
+#include <lib9.h>
+
+#define LONG_MAX 2147483647L
+#define LONG_MIN -2147483648L
+
+long
+strtol(char *nptr, char **endptr, int base)
+{
+ char *p;
+ long n, nn;
+ int c, ovfl, v, neg, ndig;
+
+ p = nptr;
+ neg = 0;
+ n = 0;
+ ndig = 0;
+ ovfl = 0;
+
+ /*
+ * White space
+ */
+ for(;;p++){
+ switch(*p){
+ case ' ':
+ case '\t':
+ case '\n':
+ case '\f':
+ case '\r':
+ case '\v':
+ continue;
+ }
+ break;
+ }
+
+ /*
+ * Sign
+ */
+ if(*p=='-' || *p=='+')
+ if(*p++ == '-')
+ neg = 1;
+
+ /*
+ * Base
+ */
+ if(base==0){
+ if(*p != '0')
+ base = 10;
+ else{
+ base = 8;
+ if(p[1]=='x' || p[1]=='X'){
+ p += 2;
+ base = 16;
+ }
+ }
+ }else if(base==16 && *p=='0'){
+ if(p[1]=='x' || p[1]=='X')
+ p += 2;
+ }else if(base<0 || 36<base)
+ goto Return;
+
+ /*
+ * Non-empty sequence of digits
+ */
+ for(;; p++,ndig++){
+ c = *p;
+ v = base;
+ if('0'<=c && c<='9')
+ v = c - '0';
+ else if('a'<=c && c<='z')
+ v = c - 'a' + 10;
+ else if('A'<=c && c<='Z')
+ v = c - 'A' + 10;
+ if(v >= base)
+ break;
+ nn = n*base + v;
+ if(nn < n)
+ ovfl = 1;
+ n = nn;
+ }
+
+ Return:
+ if(ndig == 0)
+ p = nptr;
+ if(endptr)
+ *endptr = p;
+ if(ovfl){
+ if(neg)
+ return LONG_MIN;
+ return LONG_MAX;
+ }
+ if(neg)
+ return -n;
+ return n;
+}
--- /dev/null
+++ b/libkern/strtoll.c
@@ -1,0 +1,81 @@
+#include "lib9.h"
+
+vlong
+strtoll(const char *nptr, char **endptr, int base)
+{
+ const char *p;
+ vlong n;
+ int c, v, neg, ndig;
+
+ p = nptr;
+ neg = 0;
+ n = 0;
+ ndig = 0;
+
+ /*
+ * White space
+ */
+ for(;;p++){
+ switch(*p){
+ case ' ':
+ case '\t':
+ case '\n':
+ case '\f':
+ case '\r':
+ case '\v':
+ continue;
+ }
+ break;
+ }
+
+ /*
+ * Sign
+ */
+ if(*p=='-' || *p=='+')
+ if(*p++ == '-')
+ neg = 1;
+
+ /*
+ * Base
+ */
+ if(base==0){
+ if(*p != '0')
+ base = 10;
+ else{
+ base = 8;
+ if(p[1]=='x' || p[1]=='X'){
+ p += 2;
+ base = 16;
+ }
+ }
+ }else if(base==16 && *p=='0'){
+ if(p[1]=='x' || p[1]=='X')
+ p += 2;
+ }else if(base<0 || 36<base)
+ goto Return;
+
+ /*
+ * Non-empty sequence of digits
+ */
+ for(;; p++,ndig++){
+ c = *p;
+ v = base;
+ if('0'<=c && c<='9')
+ v = c - '0';
+ else if('a'<=c && c<='z')
+ v = c - 'a' + 10;
+ else if('A'<=c && c<='Z')
+ v = c - 'A' + 10;
+ if(v >= base)
+ break;
+ n = n*base + v;
+ }
+ Return:
+ if(ndig == 0)
+ p = nptr;
+ if(endptr)
+ *endptr = (char*) p;
+ if(neg)
+ return -n;
+ return n;
+}
--- /dev/null
+++ b/libkern/strtoul.c
@@ -1,0 +1,96 @@
+#include <lib9.h>
+
+#define ULONG_MAX 4294967295UL
+
+ulong
+strtoul(char *nptr, char **endptr, int base)
+{
+ char *p;
+ ulong n, nn, m;
+ int c, ovfl, neg, v, ndig;
+
+ p = (char*)nptr;
+ neg = 0;
+ n = 0;
+ ndig = 0;
+ ovfl = 0;
+
+ /*
+ * White space
+ */
+ for(;;p++){
+ switch(*p){
+ case ' ':
+ case '\t':
+ case '\n':
+ case '\f':
+ case '\r':
+ case '\v':
+ continue;
+ }
+ break;
+ }
+
+ /*
+ * Sign
+ */
+ if(*p=='-' || *p=='+')
+ if(*p++ == '-')
+ neg = 1;
+
+ /*
+ * Base
+ */
+ if(base==0){
+ if(*p != '0')
+ base = 10;
+ else{
+ base = 8;
+ if(p[1]=='x' || p[1]=='X')
+ base = 16;
+ }
+ }
+ if(base<2 || 36<base)
+ goto Return;
+ if(base==16 && *p=='0'){
+ if(p[1]=='x' || p[1]=='X')
+ if(('0' <= p[2] && p[2] <= '9')
+ ||('a' <= p[2] && p[2] <= 'f')
+ ||('A' <= p[2] && p[2] <= 'F'))
+ p += 2;
+ }
+ /*
+ * Non-empty sequence of digits
+ */
+ n = 0;
+ m = ULONG_MAX/base;
+ for(;; p++,ndig++){
+ c = *p;
+ v = base;
+ if('0'<=c && c<='9')
+ v = c - '0';
+ else if('a'<=c && c<='z')
+ v = c - 'a' + 10;
+ else if('A'<=c && c<='Z')
+ v = c - 'A' + 10;
+ if(v >= base)
+ break;
+ if(n > m)
+ ovfl = 1;
+ nn = n*base + v;
+ if(nn < n)
+ ovfl = 1;
+ n = nn;
+ }
+
+ Return:
+ if(ndig == 0)
+ p = nptr;
+ if(endptr)
+ *endptr = p;
+ if(ovfl)
+ return ULONG_MAX;
+ if(neg)
+ return -n;
+ return n;
+}
--- /dev/null
+++ b/libkern/strtoull.c
@@ -1,0 +1,96 @@
+#include <lib9.h>
+
+#define UVLONG_MAX (1LL<<63)
+
+uvlong
+strtoull(char *nptr, char **endptr, int base)
+{
+ char *p;
+ uvlong n, nn, m;
+ int c, ovfl, v, neg, ndig;
+
+ p = nptr;
+ neg = 0;
+ n = 0;
+ ndig = 0;
+ ovfl = 0;
+
+ /*
+ * White space
+ */
+ for(;; p++) {
+ switch(*p) {
+ case ' ':
+ case '\t':
+ case '\n':
+ case '\f':
+ case '\r':
+ case '\v':
+ continue;
+ }
+ break;
+ }
+
+ /*
+ * Sign
+ */
+ if(*p == '-' || *p == '+')
+ if(*p++ == '-')
+ neg = 1;
+
+ /*
+ * Base
+ */
+ if(base == 0) {
+ base = 10;
+ if(*p == '0') {
+ base = 8;
+ if(p[1] == 'x' || p[1] == 'X'){
+ p += 2;
+ base = 16;
+ }
+ }
+ } else
+ if(base == 16 && *p == '0') {
+ if(p[1] == 'x' || p[1] == 'X')
+ p += 2;
+ } else
+ if(base < 0 || 36 < base)
+ goto Return;
+
+ /*
+ * Non-empty sequence of digits
+ */
+ m = UVLONG_MAX/base;
+ for(;; p++,ndig++) {
+ c = *p;
+ v = base;
+ if('0' <= c && c <= '9')
+ v = c - '0';
+ else
+ if('a' <= c && c <= 'z')
+ v = c - 'a' + 10;
+ else
+ if('A' <= c && c <= 'Z')
+ v = c - 'A' + 10;
+ if(v >= base)
+ break;
+ if(n > m)
+ ovfl = 1;
+ nn = n*base + v;
+ if(nn < n)
+ ovfl = 1;
+ n = nn;
+ }
+
+Return:
+ if(ndig == 0)
+ p = nptr;
+ if(endptr)
+ *endptr = p;
+ if(ovfl)
+ return UVLONG_MAX;
+ if(neg)
+ return -n;
+ return n;
+}
--- /dev/null
+++ b/libkern/tokenize.c
@@ -1,0 +1,106 @@
+#include "lib9.h"
+
+static char qsep[] = " \t\r\n";
+
+static char*
+qtoken(char *s, char *sep)
+{
+ int quoting;
+ char *t;
+
+ quoting = 0;
+ t = s; /* s is output string, t is input string */
+ while(*t!='\0' && (quoting || utfrune(sep, *t)==nil)){
+ if(*t != '\''){
+ *s++ = *t++;
+ continue;
+ }
+ /* *t is a quote */
+ if(!quoting){
+ quoting = 1;
+ t++;
+ continue;
+ }
+ /* quoting and we're on a quote */
+ if(t[1] != '\''){
+ /* end of quoted section; absorb closing quote */
+ t++;
+ quoting = 0;
+ continue;
+ }
+ /* doubled quote; fold one quote into two */
+ t++;
+ *s++ = *t++;
+ }
+ if(*s != '\0'){
+ *s = '\0';
+ if(t == s)
+ t++;
+ }
+ return t;
+}
+
+static char*
+etoken(char *t, char *sep)
+{
+ int quoting;
+
+ /* move to end of next token */
+ quoting = 0;
+ while(*t!='\0' && (quoting || utfrune(sep, *t)==nil)){
+ if(*t != '\''){
+ t++;
+ continue;
+ }
+ /* *t is a quote */
+ if(!quoting){
+ quoting = 1;
+ t++;
+ continue;
+ }
+ /* quoting and we're on a quote */
+ if(t[1] != '\''){
+ /* end of quoted section; absorb closing quote */
+ t++;
+ quoting = 0;
+ continue;
+ }
+ /* doubled quote; fold one quote into two */
+ t += 2;
+ }
+ return t;
+}
+
+int
+gettokens(char *s, char **args, int maxargs, char *sep)
+{
+ int nargs;
+
+ for(nargs=0; nargs<maxargs; nargs++){
+ while(*s!='\0' && utfrune(sep, *s)!=nil)
+ *s++ = '\0';
+ if(*s == '\0')
+ break;
+ args[nargs] = s;
+ s = etoken(s, sep);
+ }
+
+ return nargs;
+}
+
+int
+tokenize(char *s, char **args, int maxargs)
+{
+ int nargs;
+
+ for(nargs=0; nargs<maxargs; nargs++){
+ while(*s!='\0' && utfrune(qsep, *s)!=nil)
+ s++;
+ if(*s == '\0')
+ break;
+ args[nargs] = s;
+ s = qtoken(s, qsep);
+ }
+
+ return nargs;
+}
--- /dev/null
+++ b/libkern/toupper.c
@@ -1,0 +1,16 @@
+toupper(int c)
+{
+
+ if(c < 'a' || c > 'z')
+ return c;
+ return (c-'a'+'A');
+}
+
+tolower(int c)
+{
+
+ if(c < 'A' || c > 'Z')
+ return c;
+ return (c-'A'+'a');
+}
+
--- /dev/null
+++ b/libkern/u16.c
@@ -1,0 +1,52 @@
+#include <lib9.h>
+static char t16e[] = "0123456789ABCDEF";
+
+int
+dec16(uchar *out, int lim, char *in, int n)
+{
+ int c, w = 0, i = 0;
+ uchar *start = out;
+ uchar *eout = out + lim;
+
+ while(n-- > 0){
+ c = *in++;
+ if('0' <= c && c <= '9')
+ c = c - '0';
+ else if('a' <= c && c <= 'z')
+ c = c - 'a' + 10;
+ else if('A' <= c && c <= 'Z')
+ c = c - 'A' + 10;
+ else
+ continue;
+ w = (w<<4) + c;
+ i++;
+ if(i == 2){
+ if(out + 1 > eout)
+ goto exhausted;
+ *out++ = w;
+ w = 0;
+ i = 0;
+ }
+ }
+exhausted:
+ return out - start;
+}
+
+int
+enc16(char *out, int lim, uchar *in, int n)
+{
+ uint c;
+ char *eout = out + lim;
+ char *start = out;
+
+ while(n-- > 0){
+ c = *in++;
+ if(out + 2 >= eout)
+ goto exhausted;
+ *out++ = t16e[c>>4];
+ *out++ = t16e[c&0xf];
+ }
+exhausted:
+ *out = 0;
+ return out - start;
+}
--- /dev/null
+++ b/libkern/u32.c
@@ -1,0 +1,109 @@
+#include <lib9.h>
+
+int
+dec32(uchar *dest, int ndest, char *src, int nsrc)
+{
+ char *s, *tab;
+ uchar *start;
+ int i, u[8];
+
+ if(ndest+1 < (5*nsrc+7)/8)
+ return -1;
+ start = dest;
+ tab = "23456789abcdefghijkmnpqrstuvwxyz";
+ while(nsrc>=8){
+ for(i=0; i<8; i++){
+ s = strchr(tab,(int)src[i]);
+ u[i] = s ? s-tab : 0;
+ }
+ *dest++ = (u[0]<<3) | (0x7 & (u[1]>>2));
+ *dest++ = ((0x3 & u[1])<<6) | (u[2]<<1) | (0x1 & (u[3]>>4));
+ *dest++ = ((0xf & u[3])<<4) | (0xf & (u[4]>>1));
+ *dest++ = ((0x1 & u[4])<<7) | (u[5]<<2) | (0x3 & (u[6]>>3));
+ *dest++ = ((0x7 & u[6])<<5) | u[7];
+ src += 8;
+ nsrc -= 8;
+ }
+ if(nsrc > 0){
+ if(nsrc == 1 || nsrc == 3 || nsrc == 6)
+ return -1;
+ for(i=0; i<nsrc; i++){
+ s = strchr(tab,(int)src[i]);
+ u[i] = s ? s-tab : 0;
+ }
+ *dest++ = (u[0]<<3) | (0x7 & (u[1]>>2));
+ if(nsrc == 2)
+ goto out;
+ *dest++ = ((0x3 & u[1])<<6) | (u[2]<<1) | (0x1 & (u[3]>>4));
+ if(nsrc == 4)
+ goto out;
+ *dest++ = ((0xf & u[3])<<4) | (0xf & (u[4]>>1));
+ if(nsrc == 5)
+ goto out;
+ *dest++ = ((0x1 & u[4])<<7) | (u[5]<<2) | (0x3 & (u[6]>>3));
+ }
+out:
+ return dest-start;
+}
+
+int
+enc32(char *dest, int ndest, uchar *src, int nsrc)
+{
+ char *tab, *start;
+ int j;
+
+ if(ndest <= (8*nsrc+4)/5 )
+ return -1;
+ start = dest;
+ tab = "23456789abcdefghijkmnpqrstuvwxyz";
+ while(nsrc>=5){
+ j = (0x1f & (src[0]>>3));
+ *dest++ = tab[j];
+ j = (0x1c & (src[0]<<2)) | (0x03 & (src[1]>>6));
+ *dest++ = tab[j];
+ j = (0x1f & (src[1]>>1));
+ *dest++ = tab[j];
+ j = (0x10 & (src[1]<<4)) | (0x0f & (src[2]>>4));
+ *dest++ = tab[j];
+ j = (0x1e & (src[2]<<1)) | (0x01 & (src[3]>>7));
+ *dest++ = tab[j];
+ j = (0x1f & (src[3]>>2));
+ *dest++ = tab[j];
+ j = (0x18 & (src[3]<<3)) | (0x07 & (src[4]>>5));
+ *dest++ = tab[j];
+ j = (0x1f & (src[4]));
+ *dest++ = tab[j];
+ src += 5;
+ nsrc -= 5;
+ }
+ if(nsrc){
+ j = (0x1f & (src[0]>>3));
+ *dest++ = tab[j];
+ j = (0x1c & (src[0]<<2));
+ if(nsrc == 1)
+ goto out;
+ j |= (0x03 & (src[1]>>6));
+ *dest++ = tab[j];
+ j = (0x1f & (src[1]>>1));
+ if(nsrc == 2)
+ goto out;
+ *dest++ = tab[j];
+ j = (0x10 & (src[1]<<4));
+ if(nsrc == 3)
+ goto out;
+ j |= (0x0f & (src[2]>>4));
+ *dest++ = tab[j];
+ j = (0x1e & (src[2]<<1));
+ if(nsrc == 4)
+ goto out;
+ j |= (0x01 & (src[3]>>7));
+ *dest++ = tab[j];
+ j = (0x1f & (src[3]>>2));
+ *dest++ = tab[j];
+ j = (0x18 & (src[3]<<3));
+out:
+ *dest++ = tab[j];
+ }
+ *dest = 0;
+ return dest-start;
+}
--- /dev/null
+++ b/libkern/u64.c
@@ -1,0 +1,126 @@
+#include <lib9.h>
+
+enum {
+ INVAL= 255
+};
+
+static uchar t64d[256] = {
+ INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,
+ INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,
+ INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL, 62,INVAL,INVAL,INVAL, 63,
+ 52, 53, 54, 55, 56, 57, 58, 59, 60, 61,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,
+ INVAL, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
+ 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25,INVAL,INVAL,INVAL,INVAL,INVAL,
+ INVAL, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
+ 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51,INVAL,INVAL,INVAL,INVAL,INVAL,
+ INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,
+ INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,
+ INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,
+ INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,
+ INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,
+ INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,
+ INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,
+ INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL
+};
+static char t64e[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+
+int
+dec64(uchar *out, int lim, char *in, int n)
+{
+ ulong b24;
+ uchar *start = out;
+ uchar *e = out + lim;
+ int i, c;
+
+ b24 = 0;
+ i = 0;
+ while(n-- > 0){
+
+ c = t64d[*(uchar*)in++];
+ if(c == INVAL)
+ continue;
+ switch(i){
+ case 0:
+ b24 = c<<18;
+ break;
+ case 1:
+ b24 |= c<<12;
+ break;
+ case 2:
+ b24 |= c<<6;
+ break;
+ case 3:
+ if(out + 3 > e)
+ goto exhausted;
+
+ b24 |= c;
+ *out++ = b24>>16;
+ *out++ = b24>>8;
+ *out++ = b24;
+ i = -1;
+ break;
+ }
+ i++;
+ }
+ switch(i){
+ case 2:
+ if(out + 1 > e)
+ goto exhausted;
+ *out++ = b24>>16;
+ break;
+ case 3:
+ if(out + 2 > e)
+ goto exhausted;
+ *out++ = b24>>16;
+ *out++ = b24>>8;
+ break;
+ }
+exhausted:
+ return out - start;
+}
+
+int
+enc64(char *out, int lim, uchar *in, int n)
+{
+ int i;
+ ulong b24;
+ char *start = out;
+ char *e = out + lim;
+
+ for(i = n/3; i > 0; i--){
+ b24 = (*in++)<<16;
+ b24 |= (*in++)<<8;
+ b24 |= *in++;
+ if(out + 4 >= e)
+ goto exhausted;
+ *out++ = t64e[(b24>>18)];
+ *out++ = t64e[(b24>>12)&0x3f];
+ *out++ = t64e[(b24>>6)&0x3f];
+ *out++ = t64e[(b24)&0x3f];
+ }
+
+ switch(n%3){
+ case 2:
+ b24 = (*in++)<<16;
+ b24 |= (*in)<<8;
+ if(out + 4 >= e)
+ goto exhausted;
+ *out++ = t64e[(b24>>18)];
+ *out++ = t64e[(b24>>12)&0x3f];
+ *out++ = t64e[(b24>>6)&0x3f];
+ *out++ = '=';
+ break;
+ case 1:
+ b24 = (*in)<<16;
+ if(out + 4 >= e)
+ goto exhausted;
+ *out++ = t64e[(b24>>18)];
+ *out++ = t64e[(b24>>12)&0x3f];
+ *out++ = '=';
+ *out++ = '=';
+ break;
+ }
+exhausted:
+ *out = 0;
+ return out - start;
+}
--- /dev/null
+++ b/libkern/utfecpy.c
@@ -1,0 +1,20 @@
+#include "lib9.h"
+
+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;
+ while(end>to && (*--end&0xC0)==0x80)
+ ;
+ *end = '\0';
+ }else{
+ end--;
+ }
+ return end;
+}
--- /dev/null
+++ b/libkern/utflen.c
@@ -1,0 +1,21 @@
+#include "lib9.h"
+
+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++;
+ }
+}
--- /dev/null
+++ b/libkern/utfnlen.c
@@ -1,0 +1,25 @@
+#include "lib9.h"
+
+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;
+}
--- /dev/null
+++ b/libkern/utfrrune.c
@@ -1,0 +1,29 @@
+#include "lib9.h"
+
+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;
+ }
+}
--- /dev/null
+++ b/libkern/utfrune.c
@@ -1,0 +1,28 @@
+#include "lib9.h"
+
+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;
+ }
+}
--- /dev/null
+++ b/libkern/vlop-386.s
@@ -1,0 +1,44 @@
+TEXT _mulv(SB), $0
+ MOVL r+0(FP), CX
+ MOVL a+4(FP), AX
+ MULL b+12(FP)
+ MOVL AX, 0(CX)
+ MOVL DX, BX
+ MOVL a+4(FP), AX
+ MULL b+16(FP)
+ ADDL AX, BX
+ MOVL a+8(FP), AX
+ MULL b+12(FP)
+ ADDL AX, BX
+ MOVL BX, 4(CX)
+ RET
+
+TEXT _mul64by32(SB), $0
+ MOVL r+0(FP), CX
+ MOVL a+4(FP), AX
+ MULL b+12(FP)
+ MOVL AX, 0(CX)
+ MOVL DX, BX
+ MOVL a+8(FP), AX
+ MULL b+12(FP)
+ ADDL AX, BX
+ MOVL BX, 4(CX)
+ RET
+
+TEXT _div64by32(SB), $0
+ MOVL r+12(FP), CX
+ MOVL a+0(FP), AX
+ MOVL a+4(FP), DX
+ DIVL b+8(FP)
+ MOVL DX, 0(CX)
+ RET
+
+TEXT _addv(SB), $0
+ MOVL r+0(FP), CX
+ MOVL a+4(FP), AX
+ MOVL a+8(FP), BX
+ ADDL b+12(FP), AX
+ ADCL b+16(FP), BX
+ MOVL AX, 0(CX)
+ MOVL BX, 4(CX)
+ RET
--- /dev/null
+++ b/libkern/vlop-arm.s
@@ -1,0 +1,34 @@
+#define UMULL(Rs,Rm,Rhi,Rlo,S) WORD $((14<<28)|(4<<21)|(S<<20)|(Rhi<<16)|(Rlo<<12)|(Rs<<8)|(9<<4)|Rm)
+#define UMLAL(Rs,Rm,Rhi,Rlo,S) WORD $((14<<28)|(5<<21)|(S<<20)|(Rhi<<16)|(Rlo<<12)|(Rs<<8)|(9<<4)|Rm)
+#define MUL(Rs,Rm,Rd,S) WORD $((14<<28)|(0<<21)|(S<<20)|(Rd<<16)|(Rs<<8)|(9<<4)|Rm)
+arg=0
+
+/* replaced use of R10 by R11 because the former can be the data segment base register */
+
+TEXT _mulv(SB), $0
+ MOVW 4(FP), R9 /* l0 */
+ MOVW 8(FP), R11 /* h0 */
+ MOVW 12(FP), R4 /* l1 */
+ MOVW 16(FP), R5 /* h1 */
+ UMULL(4, 9, 7, 6, 0)
+ MUL(11, 4, 8, 0)
+ ADD R8, R7
+ MUL(9, 5, 8, 0)
+ ADD R8, R7
+ MOVW R6, 0(R(arg))
+ MOVW R7, 4(R(arg))
+ RET
+
+/* multiply, add, and right-shift, yielding a 32-bit result, while
+ using 64-bit accuracy for the multiply -- for fast fixed-point math */
+TEXT _mularsv(SB), $0
+ MOVW 4(FP), R11 /* m1 */
+ MOVW 8(FP), R8 /* a */
+ MOVW 12(FP), R4 /* rs */
+ MOVW $0, R9
+ UMLAL(0, 11, 9, 8, 0)
+ MOVW R8>>R4, R8
+ RSB $32, R4, R4
+ ORR R9<<R4, R8, R0
+ RET
+
--- /dev/null
+++ b/libkern/vlop-mips.s
@@ -1,0 +1,17 @@
+TEXT _mulv(SB), $0
+ MOVW 8(FP), R2
+ MOVW 4(FP), R3
+ MOVW 16(FP), R4
+ MOVW 12(FP), R5
+ MULU R4, R2
+ MOVW LO, R6
+ MOVW HI, R7
+ MULU R3, R4
+ MOVW LO, R8
+ ADDU R8, R7
+ MULU R2, R5
+ MOVW LO, R8
+ ADDU R8, R7
+ MOVW R6, 4(R1)
+ MOVW R7, 0(R1)
+ RET
--- /dev/null
+++ b/libkern/vlop-power.s
@@ -1,0 +1,14 @@
+TEXT _mulv(SB), $0
+ MOVW 8(FP), R9
+ MOVW 4(FP), R10
+ MOVW 16(FP), R4
+ MOVW 12(FP), R5
+ MULLW R4, R9, R6
+ MULHWU R4, R9, R7
+ MULLW R10, R4, R8
+ ADD R8, R7
+ MULLW R9, R5, R8
+ ADD R8, R7
+ MOVW R6, 4(R3)
+ MOVW R7, 0(R3)
+ RETURN
--- /dev/null
+++ b/libkern/vlop-sparc.s
@@ -1,0 +1,112 @@
+TEXT _mulv(SB), $0
+ MOVW u1+8(FP), R8
+ MOVW u2+16(FP), R13
+
+ MOVW R13, R16 /* save low parts for later */
+ MOVW R8, R12
+
+ /*
+ * unsigned 32x32 => 64 multiply
+ */
+ CMP R13, R8
+ BLE mul1
+ MOVW R12, R13
+ MOVW R16, R8
+mul1:
+ MOVW R13, Y
+ ANDNCC $0xFFF, R13, R0
+ BE mul_shortway
+ ANDCC R0, R0, R9 /* zero partial product and clear N and V cond's */
+
+ /* long multiply */
+ MULSCC R8, R9, R9 /* 0 */
+ MULSCC R8, R9, R9 /* 1 */
+ MULSCC R8, R9, R9 /* 2 */
+ MULSCC R8, R9, R9 /* 3 */
+ MULSCC R8, R9, R9 /* 4 */
+ MULSCC R8, R9, R9 /* 5 */
+ MULSCC R8, R9, R9 /* 6 */
+ MULSCC R8, R9, R9 /* 7 */
+ MULSCC R8, R9, R9 /* 8 */
+ MULSCC R8, R9, R9 /* 9 */
+ MULSCC R8, R9, R9 /* 10 */
+ MULSCC R8, R9, R9 /* 11 */
+ MULSCC R8, R9, R9 /* 12 */
+ MULSCC R8, R9, R9 /* 13 */
+ MULSCC R8, R9, R9 /* 14 */
+ MULSCC R8, R9, R9 /* 15 */
+ MULSCC R8, R9, R9 /* 16 */
+ MULSCC R8, R9, R9 /* 17 */
+ MULSCC R8, R9, R9 /* 18 */
+ MULSCC R8, R9, R9 /* 19 */
+ MULSCC R8, R9, R9 /* 20 */
+ MULSCC R8, R9, R9 /* 21 */
+ MULSCC R8, R9, R9 /* 22 */
+ MULSCC R8, R9, R9 /* 23 */
+ MULSCC R8, R9, R9 /* 24 */
+ MULSCC R8, R9, R9 /* 25 */
+ MULSCC R8, R9, R9 /* 26 */
+ MULSCC R8, R9, R9 /* 27 */
+ MULSCC R8, R9, R9 /* 28 */
+ MULSCC R8, R9, R9 /* 29 */
+ MULSCC R8, R9, R9 /* 30 */
+ MULSCC R8, R9, R9 /* 31 */
+ MULSCC R0, R9, R9 /* 32; shift only; r9 is high part */
+
+ /*
+ * need to correct top word if top bit set
+ */
+ CMP R8, R0
+ BGE mul_tstlow
+ ADD R13, R9 /* adjust the high parts */
+
+mul_tstlow:
+ MOVW Y, R13 /* get low part */
+ BA mul_done
+
+mul_shortway:
+ ANDCC R0, R0, R9 /* zero partial product and clear N and V cond's */
+ MULSCC R8, R9, R9 /* 0 */
+ MULSCC R8, R9, R9 /* 1 */
+ MULSCC R8, R9, R9 /* 2 */
+ MULSCC R8, R9, R9 /* 3 */
+ MULSCC R8, R9, R9 /* 4 */
+ MULSCC R8, R9, R9 /* 5 */
+ MULSCC R8, R9, R9 /* 6 */
+ MULSCC R8, R9, R9 /* 7 */
+ MULSCC R8, R9, R9 /* 8 */
+ MULSCC R8, R9, R9 /* 9 */
+ MULSCC R8, R9, R9 /* 10 */
+ MULSCC R8, R9, R9 /* 11 */
+ MULSCC R0, R9, R9 /* 12; shift only; r9 is high part */
+
+ MOVW Y, R8 /* make low part of partial low part & high part */
+ SLL $12, R9, R13
+ SRL $20, R8
+ OR R8, R13
+
+ SRA $20, R9 /* high part */
+
+mul_done:
+
+ /*
+ * mul by high halves if needed
+ */
+ MOVW R13, 4(R7)
+ MOVW u2+12(FP), R11
+ CMP R11, R0
+ BE nomul1
+ MUL R11, R12
+ ADD R12, R9
+
+nomul1:
+ MOVW u1+4(FP), R11
+ CMP R11, R0
+ BE nomul2
+ MUL R11, R16
+ ADD R16, R9
+
+nomul2:
+
+ MOVW R9, 0(R7)
+ RETURN
--- /dev/null
+++ b/libkern/vlop-spim.s
@@ -1,0 +1,17 @@
+TEXT _mulv(SB), $0
+ MOVW 4(FP), R2
+ MOVW 8(FP), R3
+ MOVW 12(FP), R4
+ MOVW 16(FP), R5
+ MULU R4, R2
+ MOVW LO, R6
+ MOVW HI, R7
+ MULU R3, R4
+ MOVW LO, R8
+ ADDU R8, R7
+ MULU R2, R5
+ MOVW LO, R8
+ ADDU R8, R7
+ MOVW R6, 0(R1)
+ MOVW R7, 4(R1)
+ RET
--- /dev/null
+++ b/libkern/vlop-thumb.s
@@ -1,0 +1,34 @@
+#define UMULL(Rs,Rm,Rhi,Rlo,S) WORD $((14<<28)|(4<<21)|(S<<20)|(Rhi<<16)|(Rlo<<12)|(Rs<<8)|(9<<4)|Rm)
+#define UMLAL(Rs,Rm,Rhi,Rlo,S) WORD $((14<<28)|(5<<21)|(S<<20)|(Rhi<<16)|(Rlo<<12)|(Rs<<8)|(9<<4)|Rm)
+#define MUL(Rs,Rm,Rd,S) WORD $((14<<28)|(0<<21)|(S<<20)|(Rd<<16)|(Rs<<8)|(9<<4)|Rm)
+arg=0
+
+/* replaced use of R10 by R11 because the former can be the data segment base register */
+
+TEXT _mulv(SB), $0
+ MOVW 4(FP), R9 /* l0 */
+ MOVW 8(FP), R11 /* h0 */
+ MOVW 12(FP), R4 /* l1 */
+ MOVW 16(FP), R5 /* h1 */
+ UMULL(4, 9, 7, 6, 0)
+ MUL(11, 4, 8, 0)
+ ADD R8, R7
+ MUL(9, 5, 8, 0)
+ ADD R8, R7
+ MOVW R6, 0(R(arg))
+ MOVW R7, 4(R(arg))
+ RET
+
+/* multiply, add, and right-shift, yielding a 32-bit result, while
+ using 64-bit accuracy for the multiply -- for fast fixed-point math */
+TEXT _mularsv(SB), $0
+ MOVW 4(FP), R11 /* m1 */
+ MOVW 8(FP), R8 /* a */
+ MOVW 12(FP), R4 /* rs */
+ MOVW $0, R9
+ UMLAL(0, 11, 9, 8, 0)
+ MOVW R8>>R4, R8
+ RSB $32, R4, R4
+ ORR R9<<R4, R8, R0
+ RET
+
--- /dev/null
+++ b/libkern/vlrt-386.c
@@ -1,0 +1,695 @@
+typedef unsigned long ulong;
+typedef unsigned int uint;
+typedef unsigned short ushort;
+typedef unsigned char uchar;
+typedef signed char schar;
+
+#define SIGN(n) (1UL<<(n-1))
+
+typedef struct Vlong Vlong;
+struct Vlong
+{
+ union
+ {
+ struct
+ {
+ ulong lo;
+ ulong hi;
+ };
+ struct
+ {
+ ushort lols;
+ ushort loms;
+ ushort hils;
+ ushort hims;
+ };
+ };
+};
+
+void abort(void);
+
+void
+_subv(Vlong *r, Vlong a, Vlong b)
+{
+ ulong lo, hi;
+
+ lo = a.lo - b.lo;
+ hi = a.hi - b.hi;
+ if(lo > a.lo)
+ hi--;
+ r->lo = lo;
+ r->hi = hi;
+}
+
+void
+_d2v(Vlong *y, double d)
+{
+ union { double d; struct Vlong; } x;
+ ulong xhi, xlo, ylo, yhi;
+ int sh;
+
+ x.d = d;
+
+ xhi = (x.hi & 0xfffff) | 0x100000;
+ xlo = x.lo;
+ sh = 1075 - ((x.hi >> 20) & 0x7ff);
+
+ ylo = 0;
+ yhi = 0;
+ if(sh >= 0) {
+ /* v = (hi||lo) >> sh */
+ if(sh < 32) {
+ if(sh == 0) {
+ ylo = xlo;
+ yhi = xhi;
+ } else {
+ ylo = (xlo >> sh) | (xhi << (32-sh));
+ yhi = xhi >> sh;
+ }
+ } else {
+ if(sh == 32) {
+ ylo = xhi;
+ } else
+ if(sh < 64) {
+ ylo = xhi >> (sh-32);
+ }
+ }
+ } else {
+ /* v = (hi||lo) << -sh */
+ sh = -sh;
+ if(sh <= 10) {
+ ylo = xlo << sh;
+ yhi = (xhi << sh) | (xlo >> (32-sh));
+ } else {
+ /* overflow */
+ yhi = d; /* causes something awful */
+ }
+ }
+ if(x.hi & SIGN(32)) {
+ if(ylo != 0) {
+ ylo = -ylo;
+ yhi = ~yhi;
+ } else
+ yhi = -yhi;
+ }
+
+ y->hi = yhi;
+ y->lo = ylo;
+}
+
+void
+_f2v(Vlong *y, float f)
+{
+
+ _d2v(y, f);
+}
+
+double
+_v2d(Vlong x)
+{
+ if(x.hi & SIGN(32)) {
+ if(x.lo) {
+ x.lo = -x.lo;
+ x.hi = ~x.hi;
+ } else
+ x.hi = -x.hi;
+ return -((long)x.hi*4294967296. + x.lo);
+ }
+ return (long)x.hi*4294967296. + x.lo;
+}
+
+float
+_v2f(Vlong x)
+{
+ return _v2d(x);
+}
+
+ulong _div64by32(Vlong, ulong, ulong*);
+void _mul64by32(Vlong*, Vlong, ulong);
+
+static void
+dodiv(Vlong num, Vlong den, Vlong *qp, Vlong *rp)
+{
+ ulong n;
+ Vlong x, q, r;
+
+ if(den.hi > num.hi || (den.hi == num.hi && den.lo > num.lo)){
+ if(qp) {
+ qp->hi = 0;
+ qp->lo = 0;
+ }
+ if(rp) {
+ rp->hi = num.hi;
+ rp->lo = num.lo;
+ }
+ return;
+ }
+
+ if(den.hi != 0){
+ q.hi = 0;
+ n = num.hi/den.hi;
+ _mul64by32(&x, den, n);
+ if(x.hi > num.hi || (x.hi == num.hi && x.lo > num.lo)){
+ n--;
+ _mul64by32(&x, den, n);
+ }
+ q.lo = n;
+ _subv(&r, num, x);
+ } else {
+ if(num.hi >= den.lo){
+ q.hi = n = num.hi/den.lo;
+ num.hi -= den.lo*n;
+ } else {
+ q.hi = 0;
+ }
+ q.lo = _div64by32(num, den.lo, &r.lo);
+ r.hi = 0;
+ }
+ if(qp) {
+ qp->lo = q.lo;
+ qp->hi = q.hi;
+ }
+ if(rp) {
+ rp->lo = r.lo;
+ rp->hi = r.hi;
+ }
+}
+
+void
+_divvu(Vlong *q, Vlong n, Vlong d)
+{
+
+ if(n.hi == 0 && d.hi == 0) {
+ q->hi = 0;
+ q->lo = n.lo / d.lo;
+ return;
+ }
+ dodiv(n, d, q, 0);
+}
+
+void
+_modvu(Vlong *r, Vlong n, Vlong d)
+{
+
+ if(n.hi == 0 && d.hi == 0) {
+ r->hi = 0;
+ r->lo = n.lo % d.lo;
+ return;
+ }
+ dodiv(n, d, 0, r);
+}
+
+static void
+vneg(Vlong *v)
+{
+
+ if(v->lo == 0) {
+ v->hi = -v->hi;
+ return;
+ }
+ v->lo = -v->lo;
+ v->hi = ~v->hi;
+}
+
+void
+_divv(Vlong *q, Vlong n, Vlong d)
+{
+ long nneg, dneg;
+
+ if(n.hi == (((long)n.lo)>>31) && d.hi == (((long)d.lo)>>31)) {
+ q->lo = (long)n.lo / (long)d.lo;
+ q->hi = ((long)q->lo) >> 31;
+ return;
+ }
+ nneg = n.hi >> 31;
+ if(nneg)
+ vneg(&n);
+ dneg = d.hi >> 31;
+ if(dneg)
+ vneg(&d);
+ dodiv(n, d, q, 0);
+ if(nneg != dneg)
+ vneg(q);
+}
+
+void
+_modv(Vlong *r, Vlong n, Vlong d)
+{
+ long nneg, dneg;
+
+ if(n.hi == (((long)n.lo)>>31) && d.hi == (((long)d.lo)>>31)) {
+ r->lo = (long)n.lo % (long)d.lo;
+ r->hi = ((long)r->lo) >> 31;
+ return;
+ }
+ nneg = n.hi >> 31;
+ if(nneg)
+ vneg(&n);
+ dneg = d.hi >> 31;
+ if(dneg)
+ vneg(&d);
+ dodiv(n, d, 0, r);
+ if(nneg)
+ vneg(r);
+}
+
+void
+_rshav(Vlong *r, Vlong a, int b)
+{
+ long t;
+
+ t = a.hi;
+ if(b >= 32) {
+ r->hi = t>>31;
+ if(b >= 64) {
+ /* this is illegal re C standard */
+ r->lo = t>>31;
+ return;
+ }
+ r->lo = t >> (b-32);
+ return;
+ }
+ if(b <= 0) {
+ r->hi = t;
+ r->lo = a.lo;
+ return;
+ }
+ r->hi = t >> b;
+ r->lo = (t << (32-b)) | (a.lo >> b);
+}
+
+void
+_rshlv(Vlong *r, Vlong a, int b)
+{
+ ulong t;
+
+ t = a.hi;
+ if(b >= 32) {
+ r->hi = 0;
+ if(b >= 64) {
+ /* this is illegal re C standard */
+ r->lo = 0;
+ return;
+ }
+ r->lo = t >> (b-32);
+ return;
+ }
+ if(b <= 0) {
+ r->hi = t;
+ r->lo = a.lo;
+ return;
+ }
+ r->hi = t >> b;
+ r->lo = (t << (32-b)) | (a.lo >> b);
+}
+
+void
+_lshv(Vlong *r, Vlong a, int b)
+{
+ ulong t;
+
+ t = a.lo;
+ if(b >= 32) {
+ r->lo = 0;
+ if(b >= 64) {
+ /* this is illegal re C standard */
+ r->hi = 0;
+ return;
+ }
+ r->hi = t << (b-32);
+ return;
+ }
+ if(b <= 0) {
+ r->lo = t;
+ r->hi = a.hi;
+ return;
+ }
+ r->lo = t << b;
+ r->hi = (t >> (32-b)) | (a.hi << b);
+}
+
+void
+_andv(Vlong *r, Vlong a, Vlong b)
+{
+ r->hi = a.hi & b.hi;
+ r->lo = a.lo & b.lo;
+}
+
+void
+_orv(Vlong *r, Vlong a, Vlong b)
+{
+ r->hi = a.hi | b.hi;
+ r->lo = a.lo | b.lo;
+}
+
+void
+_xorv(Vlong *r, Vlong a, Vlong b)
+{
+ r->hi = a.hi ^ b.hi;
+ r->lo = a.lo ^ b.lo;
+}
+
+void
+_vpp(Vlong *l, Vlong *r)
+{
+
+ l->hi = r->hi;
+ l->lo = r->lo;
+ r->lo++;
+ if(r->lo == 0)
+ r->hi++;
+}
+
+void
+_vmm(Vlong *l, Vlong *r)
+{
+
+ l->hi = r->hi;
+ l->lo = r->lo;
+ if(r->lo == 0)
+ r->hi--;
+ r->lo--;
+}
+
+void
+_ppv(Vlong *l, Vlong *r)
+{
+
+ r->lo++;
+ if(r->lo == 0)
+ r->hi++;
+ l->hi = r->hi;
+ l->lo = r->lo;
+}
+
+void
+_mmv(Vlong *l, Vlong *r)
+{
+
+ if(r->lo == 0)
+ r->hi--;
+ r->lo--;
+ l->hi = r->hi;
+ l->lo = r->lo;
+}
+
+void
+_vasop(Vlong *ret, void *lv, void fn(Vlong*, Vlong, Vlong), int type, Vlong rv)
+{
+ Vlong t, u;
+
+ u.lo = 0;
+ u.hi = 0;
+ switch(type) {
+ default:
+ abort();
+ break;
+
+ case 1: /* schar */
+ t.lo = *(schar*)lv;
+ t.hi = t.lo >> 31;
+ fn(&u, t, rv);
+ *(schar*)lv = u.lo;
+ break;
+
+ case 2: /* uchar */
+ t.lo = *(uchar*)lv;
+ t.hi = 0;
+ fn(&u, t, rv);
+ *(uchar*)lv = u.lo;
+ break;
+
+ case 3: /* short */
+ t.lo = *(short*)lv;
+ t.hi = t.lo >> 31;
+ fn(&u, t, rv);
+ *(short*)lv = u.lo;
+ break;
+
+ case 4: /* ushort */
+ t.lo = *(ushort*)lv;
+ t.hi = 0;
+ fn(&u, t, rv);
+ *(ushort*)lv = u.lo;
+ break;
+
+ case 9: /* int */
+ t.lo = *(int*)lv;
+ t.hi = t.lo >> 31;
+ fn(&u, t, rv);
+ *(int*)lv = u.lo;
+ break;
+
+ case 10: /* uint */
+ t.lo = *(uint*)lv;
+ t.hi = 0;
+ fn(&u, t, rv);
+ *(uint*)lv = u.lo;
+ break;
+
+ case 5: /* long */
+ t.lo = *(long*)lv;
+ t.hi = t.lo >> 31;
+ fn(&u, t, rv);
+ *(long*)lv = u.lo;
+ break;
+
+ case 6: /* ulong */
+ t.lo = *(ulong*)lv;
+ t.hi = 0;
+ fn(&u, t, rv);
+ *(ulong*)lv = u.lo;
+ break;
+
+ case 7: /* vlong */
+ case 8: /* uvlong */
+ fn(&u, *(Vlong*)lv, rv);
+ *(Vlong*)lv = u;
+ break;
+ }
+ *ret = u;
+}
+
+void
+_p2v(Vlong *ret, void *p)
+{
+ long t;
+
+ t = (ulong)p;
+ ret->lo = t;
+ ret->hi = 0;
+}
+
+void
+_sl2v(Vlong *ret, long sl)
+{
+ long t;
+
+ t = sl;
+ ret->lo = t;
+ ret->hi = t >> 31;
+}
+
+void
+_ul2v(Vlong *ret, ulong ul)
+{
+ long t;
+
+ t = ul;
+ ret->lo = t;
+ ret->hi = 0;
+}
+
+void
+_si2v(Vlong *ret, int si)
+{
+ long t;
+
+ t = si;
+ ret->lo = t;
+ ret->hi = t >> 31;
+}
+
+void
+_ui2v(Vlong *ret, uint ui)
+{
+ long t;
+
+ t = ui;
+ ret->lo = t;
+ ret->hi = 0;
+}
+
+void
+_sh2v(Vlong *ret, long sh)
+{
+ long t;
+
+ t = (sh << 16) >> 16;
+ ret->lo = t;
+ ret->hi = t >> 31;
+}
+
+void
+_uh2v(Vlong *ret, ulong ul)
+{
+ long t;
+
+ t = ul & 0xffff;
+ ret->lo = t;
+ ret->hi = 0;
+}
+
+void
+_sc2v(Vlong *ret, long uc)
+{
+ long t;
+
+ t = (uc << 24) >> 24;
+ ret->lo = t;
+ ret->hi = t >> 31;
+}
+
+void
+_uc2v(Vlong *ret, ulong ul)
+{
+ long t;
+
+ t = ul & 0xff;
+ ret->lo = t;
+ ret->hi = 0;
+}
+
+long
+_v2sc(Vlong rv)
+{
+ long t;
+
+ t = rv.lo & 0xff;
+ return (t << 24) >> 24;
+}
+
+long
+_v2uc(Vlong rv)
+{
+
+ return rv.lo & 0xff;
+}
+
+long
+_v2sh(Vlong rv)
+{
+ long t;
+
+ t = rv.lo & 0xffff;
+ return (t << 16) >> 16;
+}
+
+long
+_v2uh(Vlong rv)
+{
+
+ return rv.lo & 0xffff;
+}
+
+long
+_v2sl(Vlong rv)
+{
+
+ return rv.lo;
+}
+
+long
+_v2ul(Vlong rv)
+{
+
+ return rv.lo;
+}
+
+long
+_v2si(Vlong rv)
+{
+
+ return rv.lo;
+}
+
+long
+_v2ui(Vlong rv)
+{
+
+ return rv.lo;
+}
+
+int
+_testv(Vlong rv)
+{
+ return rv.lo || rv.hi;
+}
+
+int
+_eqv(Vlong lv, Vlong rv)
+{
+ return lv.lo == rv.lo && lv.hi == rv.hi;
+}
+
+int
+_nev(Vlong lv, Vlong rv)
+{
+ return lv.lo != rv.lo || lv.hi != rv.hi;
+}
+
+int
+_ltv(Vlong lv, Vlong rv)
+{
+ return (long)lv.hi < (long)rv.hi ||
+ (lv.hi == rv.hi && lv.lo < rv.lo);
+}
+
+int
+_lev(Vlong lv, Vlong rv)
+{
+ return (long)lv.hi < (long)rv.hi ||
+ (lv.hi == rv.hi && lv.lo <= rv.lo);
+}
+
+int
+_gtv(Vlong lv, Vlong rv)
+{
+ return (long)lv.hi > (long)rv.hi ||
+ (lv.hi == rv.hi && lv.lo > rv.lo);
+}
+
+int
+_gev(Vlong lv, Vlong rv)
+{
+ return (long)lv.hi > (long)rv.hi ||
+ (lv.hi == rv.hi && lv.lo >= rv.lo);
+}
+
+int
+_lov(Vlong lv, Vlong rv)
+{
+ return lv.hi < rv.hi ||
+ (lv.hi == rv.hi && lv.lo < rv.lo);
+}
+
+int
+_lsv(Vlong lv, Vlong rv)
+{
+ return lv.hi < rv.hi ||
+ (lv.hi == rv.hi && lv.lo <= rv.lo);
+}
+
+int
+_hiv(Vlong lv, Vlong rv)
+{
+ return lv.hi > rv.hi ||
+ (lv.hi == rv.hi && lv.lo > rv.lo);
+}
+
+int
+_hsv(Vlong lv, Vlong rv)
+{
+ return lv.hi > rv.hi ||
+ (lv.hi == rv.hi && lv.lo >= rv.lo);
+}
--- /dev/null
+++ b/libkern/vlrt-arm.c
@@ -1,0 +1,711 @@
+typedef unsigned long ulong;
+typedef unsigned int uint;
+typedef unsigned short ushort;
+typedef unsigned char uchar;
+typedef signed char schar;
+
+#define SIGN(n) (1UL<<(n-1))
+
+typedef struct Vlong Vlong;
+struct Vlong
+{
+ union
+ {
+ struct
+ {
+ ulong lo;
+ ulong hi;
+ };
+ };
+};
+
+void abort(void);
+
+void
+_addv(Vlong *r, Vlong a, Vlong b)
+{
+ ulong lo, hi;
+
+ lo = a.lo + b.lo;
+ hi = a.hi + b.hi;
+ if(lo < a.lo)
+ hi++;
+ r->lo = lo;
+ r->hi = hi;
+}
+
+void
+_subv(Vlong *r, Vlong a, Vlong b)
+{
+ ulong lo, hi;
+
+ lo = a.lo - b.lo;
+ hi = a.hi - b.hi;
+ if(lo > a.lo)
+ hi--;
+ r->lo = lo;
+ r->hi = hi;
+}
+
+
+void
+_d2v(Vlong *y, double d)
+{
+ union { double d; struct Vlong; } x;
+ ulong xhi, xlo, ylo, yhi;
+ int sh;
+
+ x.d = d;
+
+ xhi = (x.hi & 0xfffff) | 0x100000;
+ xlo = x.lo;
+ sh = 1075 - ((x.hi >> 20) & 0x7ff);
+
+ ylo = 0;
+ yhi = 0;
+ if(sh >= 0) {
+ /* v = (hi||lo) >> sh */
+ if(sh < 32) {
+ if(sh == 0) {
+ ylo = xlo;
+ yhi = xhi;
+ } else {
+ ylo = (xlo >> sh) | (xhi << (32-sh));
+ yhi = xhi >> sh;
+ }
+ } else {
+ if(sh == 32) {
+ ylo = xhi;
+ } else
+ if(sh < 64) {
+ ylo = xhi >> (sh-32);
+ }
+ }
+ } else {
+ /* v = (hi||lo) << -sh */
+ sh = -sh;
+ if(sh <= 10) {
+ ylo = xlo << sh;
+ yhi = (xhi << sh) | (xlo >> (32-sh));
+ } else {
+ /* overflow */
+ yhi = d; /* causes something awful */
+ }
+ }
+ if(x.hi & SIGN(32)) {
+ if(ylo != 0) {
+ ylo = -ylo;
+ yhi = ~yhi;
+ } else
+ yhi = -yhi;
+ }
+
+ y->hi = yhi;
+ y->lo = ylo;
+}
+
+void
+_f2v(Vlong *y, float f)
+{
+ _d2v(y, f);
+}
+
+double
+_v2d(Vlong x)
+{
+ if(x.hi & SIGN(32)) {
+ if(x.lo) {
+ x.lo = -x.lo;
+ x.hi = ~x.hi;
+ } else
+ x.hi = -x.hi;
+ return -((long)x.hi*4294967296. + x.lo);
+ }
+ return (long)x.hi*4294967296. + x.lo;
+}
+
+float
+_v2f(Vlong x)
+{
+ return _v2d(x);
+}
+
+static void
+dodiv(Vlong num, Vlong den, Vlong *q, Vlong *r)
+{
+ ulong numlo, numhi, denhi, denlo, quohi, quolo, t;
+ int i;
+
+ numhi = num.hi;
+ numlo = num.lo;
+ denhi = den.hi;
+ denlo = den.lo;
+
+ /*
+ * get a divide by zero
+ */
+ if(denlo==0 && denhi==0) {
+ numlo = numlo / denlo;
+ }
+
+ /*
+ * set up the divisor and find the number of iterations needed
+ */
+ if(numhi >= SIGN(32)) {
+ quohi = SIGN(32);
+ quolo = 0;
+ } else {
+ quohi = numhi;
+ quolo = numlo;
+ }
+ i = 0;
+ while(denhi < quohi || (denhi == quohi && denlo < quolo)) {
+ denhi = (denhi<<1) | (denlo>>31);
+ denlo <<= 1;
+ i++;
+ }
+
+ quohi = 0;
+ quolo = 0;
+ for(; i >= 0; i--) {
+ quohi = (quohi<<1) | (quolo>>31);
+ quolo <<= 1;
+ if(numhi > denhi || (numhi == denhi && numlo >= denlo)) {
+ t = numlo;
+ numlo -= denlo;
+ if(numlo > t)
+ numhi--;
+ numhi -= denhi;
+ quolo |= 1;
+ }
+ denlo = (denlo>>1) | (denhi<<31);
+ denhi >>= 1;
+ }
+
+ if(q) {
+ q->lo = quolo;
+ q->hi = quohi;
+ }
+ if(r) {
+ r->lo = numlo;
+ r->hi = numhi;
+ }
+}
+
+void
+_divvu(Vlong *q, Vlong n, Vlong d)
+{
+
+ if(n.hi == 0 && d.hi == 0) {
+ q->hi = 0;
+ q->lo = n.lo / d.lo;
+ return;
+ }
+ dodiv(n, d, q, 0);
+}
+
+void
+_modvu(Vlong *r, Vlong n, Vlong d)
+{
+
+ if(n.hi == 0 && d.hi == 0) {
+ r->hi = 0;
+ r->lo = n.lo % d.lo;
+ return;
+ }
+ dodiv(n, d, 0, r);
+}
+
+static void
+vneg(Vlong *v)
+{
+
+ if(v->lo == 0) {
+ v->hi = -v->hi;
+ return;
+ }
+ v->lo = -v->lo;
+ v->hi = ~v->hi;
+}
+
+void
+_divv(Vlong *q, Vlong n, Vlong d)
+{
+ long nneg, dneg;
+
+ if(n.hi == (((long)n.lo)>>31) && d.hi == (((long)d.lo)>>31)) {
+ q->lo = (long)n.lo / (long)d.lo;
+ q->hi = ((long)q->lo) >> 31;
+ return;
+ }
+ nneg = n.hi >> 31;
+ if(nneg)
+ vneg(&n);
+ dneg = d.hi >> 31;
+ if(dneg)
+ vneg(&d);
+ dodiv(n, d, q, 0);
+ if(nneg != dneg)
+ vneg(q);
+}
+
+void
+_modv(Vlong *r, Vlong n, Vlong d)
+{
+ long nneg, dneg;
+
+ if(n.hi == (((long)n.lo)>>31) && d.hi == (((long)d.lo)>>31)) {
+ r->lo = (long)n.lo % (long)d.lo;
+ r->hi = ((long)r->lo) >> 31;
+ return;
+ }
+ nneg = n.hi >> 31;
+ if(nneg)
+ vneg(&n);
+ dneg = d.hi >> 31;
+ if(dneg)
+ vneg(&d);
+ dodiv(n, d, 0, r);
+ if(nneg)
+ vneg(r);
+}
+
+void
+_rshav(Vlong *r, Vlong a, int b)
+{
+ long t;
+
+ t = a.hi;
+ if(b >= 32) {
+ r->hi = t>>31;
+ if(b >= 64) {
+ /* this is illegal re C standard */
+ r->lo = t>>31;
+ return;
+ }
+ r->lo = t >> (b-32);
+ return;
+ }
+ if(b <= 0) {
+ r->hi = t;
+ r->lo = a.lo;
+ return;
+ }
+ r->hi = t >> b;
+ r->lo = (t << (32-b)) | (a.lo >> b);
+}
+
+void
+_rshlv(Vlong *r, Vlong a, int b)
+{
+ ulong t;
+
+ t = a.hi;
+ if(b >= 32) {
+ r->hi = 0;
+ if(b >= 64) {
+ /* this is illegal re C standard */
+ r->lo = 0;
+ return;
+ }
+ r->lo = t >> (b-32);
+ return;
+ }
+ if(b <= 0) {
+ r->hi = t;
+ r->lo = a.lo;
+ return;
+ }
+ r->hi = t >> b;
+ r->lo = (t << (32-b)) | (a.lo >> b);
+}
+
+void
+_lshv(Vlong *r, Vlong a, int b)
+{
+ ulong t;
+
+ t = a.lo;
+ if(b >= 32) {
+ r->lo = 0;
+ if(b >= 64) {
+ /* this is illegal re C standard */
+ r->hi = 0;
+ return;
+ }
+ r->hi = t << (b-32);
+ return;
+ }
+ if(b <= 0) {
+ r->lo = t;
+ r->hi = a.hi;
+ return;
+ }
+ r->lo = t << b;
+ r->hi = (t >> (32-b)) | (a.hi << b);
+}
+
+void
+_andv(Vlong *r, Vlong a, Vlong b)
+{
+ r->hi = a.hi & b.hi;
+ r->lo = a.lo & b.lo;
+}
+
+void
+_orv(Vlong *r, Vlong a, Vlong b)
+{
+ r->hi = a.hi | b.hi;
+ r->lo = a.lo | b.lo;
+}
+
+void
+_xorv(Vlong *r, Vlong a, Vlong b)
+{
+ r->hi = a.hi ^ b.hi;
+ r->lo = a.lo ^ b.lo;
+}
+
+void
+_vpp(Vlong *l, Vlong *r)
+{
+
+ l->hi = r->hi;
+ l->lo = r->lo;
+ r->lo++;
+ if(r->lo == 0)
+ r->hi++;
+}
+
+void
+_vmm(Vlong *l, Vlong *r)
+{
+
+ l->hi = r->hi;
+ l->lo = r->lo;
+ if(r->lo == 0)
+ r->hi--;
+ r->lo--;
+}
+
+void
+_ppv(Vlong *l, Vlong *r)
+{
+
+ r->lo++;
+ if(r->lo == 0)
+ r->hi++;
+ l->hi = r->hi;
+ l->lo = r->lo;
+}
+
+void
+_mmv(Vlong *l, Vlong *r)
+{
+
+ if(r->lo == 0)
+ r->hi--;
+ r->lo--;
+ l->hi = r->hi;
+ l->lo = r->lo;
+}
+
+void
+_vasop(Vlong *ret, void *lv, void fn(Vlong*, Vlong, Vlong), int type, Vlong rv)
+{
+ Vlong t, u;
+
+ u = *ret;
+ switch(type) {
+ default:
+ abort();
+ break;
+
+ case 1: /* schar */
+ t.lo = *(schar*)lv;
+ t.hi = t.lo >> 31;
+ fn(&u, t, rv);
+ *(schar*)lv = u.lo;
+ break;
+
+ case 2: /* uchar */
+ t.lo = *(uchar*)lv;
+ t.hi = 0;
+ fn(&u, t, rv);
+ *(uchar*)lv = u.lo;
+ break;
+
+ case 3: /* short */
+ t.lo = *(short*)lv;
+ t.hi = t.lo >> 31;
+ fn(&u, t, rv);
+ *(short*)lv = u.lo;
+ break;
+
+ case 4: /* ushort */
+ t.lo = *(ushort*)lv;
+ t.hi = 0;
+ fn(&u, t, rv);
+ *(ushort*)lv = u.lo;
+ break;
+
+ case 9: /* int */
+ t.lo = *(int*)lv;
+ t.hi = t.lo >> 31;
+ fn(&u, t, rv);
+ *(int*)lv = u.lo;
+ break;
+
+ case 10: /* uint */
+ t.lo = *(uint*)lv;
+ t.hi = 0;
+ fn(&u, t, rv);
+ *(uint*)lv = u.lo;
+ break;
+
+ case 5: /* long */
+ t.lo = *(long*)lv;
+ t.hi = t.lo >> 31;
+ fn(&u, t, rv);
+ *(long*)lv = u.lo;
+ break;
+
+ case 6: /* ulong */
+ t.lo = *(ulong*)lv;
+ t.hi = 0;
+ fn(&u, t, rv);
+ *(ulong*)lv = u.lo;
+ break;
+
+ case 7: /* vlong */
+ case 8: /* uvlong */
+ fn(&u, *(Vlong*)lv, rv);
+ *(Vlong*)lv = u;
+ break;
+ }
+ *ret = u;
+}
+
+void
+_p2v(Vlong *ret, void *p)
+{
+ long t;
+
+ t = (ulong)p;
+ ret->lo = t;
+ ret->hi = 0;
+}
+
+void
+_sl2v(Vlong *ret, long sl)
+{
+ long t;
+
+ t = sl;
+ ret->lo = t;
+ ret->hi = t >> 31;
+}
+
+void
+_ul2v(Vlong *ret, ulong ul)
+{
+ long t;
+
+ t = ul;
+ ret->lo = t;
+ ret->hi = 0;
+}
+
+void
+_si2v(Vlong *ret, int si)
+{
+ long t;
+
+ t = si;
+ ret->lo = t;
+ ret->hi = t >> 31;
+}
+
+void
+_ui2v(Vlong *ret, uint ui)
+{
+ long t;
+
+ t = ui;
+ ret->lo = t;
+ ret->hi = 0;
+}
+
+void
+_sh2v(Vlong *ret, long sh)
+{
+ long t;
+
+ t = (sh << 16) >> 16;
+ ret->lo = t;
+ ret->hi = t >> 31;
+}
+
+void
+_uh2v(Vlong *ret, ulong ul)
+{
+ long t;
+
+ t = ul & 0xffff;
+ ret->lo = t;
+ ret->hi = 0;
+}
+
+void
+_sc2v(Vlong *ret, long uc)
+{
+ long t;
+
+ t = (uc << 24) >> 24;
+ ret->lo = t;
+ ret->hi = t >> 31;
+}
+
+void
+_uc2v(Vlong *ret, ulong ul)
+{
+ long t;
+
+ t = ul & 0xff;
+ ret->lo = t;
+ ret->hi = 0;
+}
+
+long
+_v2sc(Vlong rv)
+{
+ long t;
+
+ t = rv.lo & 0xff;
+ return (t << 24) >> 24;
+}
+
+long
+_v2uc(Vlong rv)
+{
+
+ return rv.lo & 0xff;
+}
+
+long
+_v2sh(Vlong rv)
+{
+ long t;
+
+ t = rv.lo & 0xffff;
+ return (t << 16) >> 16;
+}
+
+long
+_v2uh(Vlong rv)
+{
+
+ return rv.lo & 0xffff;
+}
+
+long
+_v2sl(Vlong rv)
+{
+
+ return rv.lo;
+}
+
+long
+_v2ul(Vlong rv)
+{
+
+ return rv.lo;
+}
+
+long
+_v2si(Vlong rv)
+{
+
+ return rv.lo;
+}
+
+long
+_v2ui(Vlong rv)
+{
+
+ return rv.lo;
+}
+
+int
+_testv(Vlong rv)
+{
+ return rv.lo || rv.hi;
+}
+
+int
+_eqv(Vlong lv, Vlong rv)
+{
+ return lv.lo == rv.lo && lv.hi == rv.hi;
+}
+
+int
+_nev(Vlong lv, Vlong rv)
+{
+ return lv.lo != rv.lo || lv.hi != rv.hi;
+}
+
+int
+_ltv(Vlong lv, Vlong rv)
+{
+ return (long)lv.hi < (long)rv.hi ||
+ (lv.hi == rv.hi && lv.lo < rv.lo);
+}
+
+int
+_lev(Vlong lv, Vlong rv)
+{
+ return (long)lv.hi < (long)rv.hi ||
+ (lv.hi == rv.hi && lv.lo <= rv.lo);
+}
+
+int
+_gtv(Vlong lv, Vlong rv)
+{
+ return (long)lv.hi > (long)rv.hi ||
+ (lv.hi == rv.hi && lv.lo > rv.lo);
+}
+
+int
+_gev(Vlong lv, Vlong rv)
+{
+ return (long)lv.hi > (long)rv.hi ||
+ (lv.hi == rv.hi && lv.lo >= rv.lo);
+}
+
+int
+_lov(Vlong lv, Vlong rv)
+{
+ return lv.hi < rv.hi ||
+ (lv.hi == rv.hi && lv.lo < rv.lo);
+}
+
+int
+_lsv(Vlong lv, Vlong rv)
+{
+ return lv.hi < rv.hi ||
+ (lv.hi == rv.hi && lv.lo <= rv.lo);
+}
+
+int
+_hiv(Vlong lv, Vlong rv)
+{
+ return lv.hi > rv.hi ||
+ (lv.hi == rv.hi && lv.lo > rv.lo);
+}
+
+int
+_hsv(Vlong lv, Vlong rv)
+{
+ return lv.hi > rv.hi ||
+ (lv.hi == rv.hi && lv.lo >= rv.lo);
+}
--- /dev/null
+++ b/libkern/vlrt-mips.c
@@ -1,0 +1,712 @@
+typedef unsigned long ulong;
+typedef unsigned int uint;
+typedef unsigned short ushort;
+typedef unsigned char uchar;
+typedef signed char schar;
+
+#define SIGN(n) (1UL<<(n-1))
+
+typedef struct Vlong Vlong;
+struct Vlong
+{
+ union
+ {
+ struct
+ {
+ ulong hi;
+ ulong lo;
+ };
+ };
+};
+
+void abort(void);
+
+void
+_addv(Vlong *r, Vlong a, Vlong b)
+{
+ ulong lo, hi;
+
+ lo = a.lo + b.lo;
+ hi = a.hi + b.hi;
+ if(lo < a.lo)
+ hi++;
+ r->lo = lo;
+ r->hi = hi;
+}
+
+void
+_subv(Vlong *r, Vlong a, Vlong b)
+{
+ ulong lo, hi;
+
+ lo = a.lo - b.lo;
+ hi = a.hi - b.hi;
+ if(lo > a.lo)
+ hi--;
+ r->lo = lo;
+ r->hi = hi;
+}
+
+void
+_d2v(Vlong *y, double d)
+{
+ union { double d; struct Vlong; } x;
+ ulong xhi, xlo, ylo, yhi;
+ int sh;
+
+ x.d = d;
+
+ xhi = (x.hi & 0xfffff) | 0x100000;
+ xlo = x.lo;
+ sh = 1075 - ((x.hi >> 20) & 0x7ff);
+
+ ylo = 0;
+ yhi = 0;
+ if(sh >= 0) {
+ /* v = (hi||lo) >> sh */
+ if(sh < 32) {
+ if(sh == 0) {
+ ylo = xlo;
+ yhi = xhi;
+ } else {
+ ylo = (xlo >> sh) | (xhi << (32-sh));
+ yhi = xhi >> sh;
+ }
+ } else {
+ if(sh == 32) {
+ ylo = xhi;
+ } else
+ if(sh < 64) {
+ ylo = xhi >> (sh-32);
+ }
+ }
+ } else {
+ /* v = (hi||lo) << -sh */
+ sh = -sh;
+ if(sh <= 10) {
+ ylo = xlo << sh;
+ yhi = (xhi << sh) | (xlo >> (32-sh));
+ } else {
+ /* overflow */
+ yhi = d; /* causes something awful */
+ }
+ }
+ if(x.hi & SIGN(32)) {
+ if(ylo != 0) {
+ ylo = -ylo;
+ yhi = ~yhi;
+ } else
+ yhi = -yhi;
+ }
+
+ y->hi = yhi;
+ y->lo = ylo;
+}
+
+void
+_f2v(Vlong *y, float f)
+{
+
+ _d2v(y, f);
+}
+
+double
+_v2d(Vlong x)
+{
+ if(x.hi & SIGN(32)) {
+ if(x.lo) {
+ x.lo = -x.lo;
+ x.hi = ~x.hi;
+ } else
+ x.hi = -x.hi;
+ return -((long)x.hi*4294967296. + x.lo);
+ }
+ return (long)x.hi*4294967296. + x.lo;
+}
+
+float
+_v2f(Vlong x)
+{
+ return _v2d(x);
+}
+
+static void
+dodiv(Vlong num, Vlong den, Vlong *qp, Vlong *rp)
+{
+ ulong numlo, numhi, denhi, denlo, quohi, quolo, t;
+ int i;
+
+ numhi = num.hi;
+ numlo = num.lo;
+ denhi = den.hi;
+ denlo = den.lo;
+
+ /*
+ * get a divide by zero
+ */
+ if(denlo==0 && denhi==0) {
+ numlo = numlo / denlo;
+ }
+
+ /*
+ * set up the divisor and find the number of iterations needed
+ */
+ if(numhi >= SIGN(32)) {
+ quohi = SIGN(32);
+ quolo = 0;
+ } else {
+ quohi = numhi;
+ quolo = numlo;
+ }
+ i = 0;
+ while(denhi < quohi || (denhi == quohi && denlo < quolo)) {
+ denhi = (denhi<<1) | (denlo>>31);
+ denlo <<= 1;
+ i++;
+ }
+
+ quohi = 0;
+ quolo = 0;
+ for(; i >= 0; i--) {
+ quohi = (quohi<<1) | (quolo>>31);
+ quolo <<= 1;
+ if(numhi > denhi || (numhi == denhi && numlo >= denlo)) {
+ t = numlo;
+ numlo -= denlo;
+ if(numlo > t)
+ numhi--;
+ numhi -= denhi;
+ quolo |= 1;
+ }
+ denlo = (denlo>>1) | (denhi<<31);
+ denhi >>= 1;
+ }
+
+ if(qp) {
+ qp->lo = quolo;
+ qp->hi = quohi;
+ }
+ if(rp) {
+ rp->lo = numlo;
+ rp->hi = numhi;
+ }
+}
+
+void
+_divvu(Vlong *q, Vlong n, Vlong d)
+{
+
+ if(n.hi == 0 && d.hi == 0) {
+ q->hi = 0;
+ q->lo = n.lo / d.lo;
+ return;
+ }
+ dodiv(n, d, q, 0);
+}
+
+void
+_modvu(Vlong *r, Vlong n, Vlong d)
+{
+
+ if(n.hi == 0 && d.hi == 0) {
+ r->hi = 0;
+ r->lo = n.lo % d.lo;
+ return;
+ }
+ dodiv(n, d, 0, r);
+}
+
+static void
+vneg(Vlong *v)
+{
+
+ if(v->lo == 0) {
+ v->hi = -v->hi;
+ return;
+ }
+ v->lo = -v->lo;
+ v->hi = ~v->hi;
+}
+
+void
+_divv(Vlong *q, Vlong n, Vlong d)
+{
+ long nneg, dneg;
+
+ if(n.hi == (((long)n.lo)>>31) && d.hi == (((long)d.lo)>>31)) {
+ q->lo = (long)n.lo / (long)d.lo;
+ q->hi = ((long)q->lo) >> 31;
+ return;
+ }
+ nneg = n.hi >> 31;
+ if(nneg)
+ vneg(&n);
+ dneg = d.hi >> 31;
+ if(dneg)
+ vneg(&d);
+ dodiv(n, d, q, 0);
+ if(nneg != dneg)
+ vneg(q);
+}
+
+void
+_modv(Vlong *r, Vlong n, Vlong d)
+{
+ long nneg, dneg;
+
+ if(n.hi == (((long)n.lo)>>31) && d.hi == (((long)d.lo)>>31)) {
+ r->lo = (long)n.lo % (long)d.lo;
+ r->hi = ((long)r->lo) >> 31;
+ return;
+ }
+ nneg = n.hi >> 31;
+ if(nneg)
+ vneg(&n);
+ dneg = d.hi >> 31;
+ if(dneg)
+ vneg(&d);
+ dodiv(n, d, 0, r);
+ if(nneg)
+ vneg(r);
+}
+
+void
+_rshav(Vlong *r, Vlong a, int b)
+{
+ long t;
+
+ t = a.hi;
+ if(b >= 32) {
+ r->hi = t>>31;
+ if(b >= 64) {
+ /* this is illegal re C standard */
+ r->lo = t>>31;
+ return;
+ }
+ r->lo = t >> (b-32);
+ return;
+ }
+ if(b <= 0) {
+ r->hi = t;
+ r->lo = a.lo;
+ return;
+ }
+ r->hi = t >> b;
+ r->lo = (t << (32-b)) | (a.lo >> b);
+}
+
+void
+_rshlv(Vlong *r, Vlong a, int b)
+{
+ ulong t;
+
+ t = a.hi;
+ if(b >= 32) {
+ r->hi = 0;
+ if(b >= 64) {
+ /* this is illegal re C standard */
+ r->lo = 0;
+ return;
+ }
+ r->lo = t >> (b-32);
+ return;
+ }
+ if(b <= 0) {
+ r->hi = t;
+ r->lo = a.lo;
+ return;
+ }
+ r->hi = t >> b;
+ r->lo = (t << (32-b)) | (a.lo >> b);
+}
+
+void
+_lshv(Vlong *r, Vlong a, int b)
+{
+ ulong t;
+
+ t = a.lo;
+ if(b >= 32) {
+ r->lo = 0;
+ if(b >= 64) {
+ /* this is illegal re C standard */
+ r->hi = 0;
+ return;
+ }
+ r->hi = t << (b-32);
+ return;
+ }
+ if(b <= 0) {
+ r->lo = t;
+ r->hi = a.hi;
+ return;
+ }
+ r->lo = t << b;
+ r->hi = (t >> (32-b)) | (a.hi << b);
+}
+
+void
+_andv(Vlong *r, Vlong a, Vlong b)
+{
+ r->hi = a.hi & b.hi;
+ r->lo = a.lo & b.lo;
+}
+
+void
+_orv(Vlong *r, Vlong a, Vlong b)
+{
+ r->hi = a.hi | b.hi;
+ r->lo = a.lo | b.lo;
+}
+
+void
+_xorv(Vlong *r, Vlong a, Vlong b)
+{
+ r->hi = a.hi ^ b.hi;
+ r->lo = a.lo ^ b.lo;
+}
+
+void
+_vpp(Vlong *l, Vlong *r)
+{
+
+ l->hi = r->hi;
+ l->lo = r->lo;
+ r->lo++;
+ if(r->lo == 0)
+ r->hi++;
+}
+
+void
+_vmm(Vlong *l, Vlong *r)
+{
+
+ l->hi = r->hi;
+ l->lo = r->lo;
+ if(r->lo == 0)
+ r->hi--;
+ r->lo--;
+}
+
+void
+_ppv(Vlong *l, Vlong *r)
+{
+
+ r->lo++;
+ if(r->lo == 0)
+ r->hi++;
+ l->hi = r->hi;
+ l->lo = r->lo;
+}
+
+void
+_mmv(Vlong *l, Vlong *r)
+{
+
+ if(r->lo == 0)
+ r->hi--;
+ r->lo--;
+ l->hi = r->hi;
+ l->lo = r->lo;
+}
+
+void
+_vasop(Vlong *ret, void *lv, void fn(Vlong*, Vlong, Vlong), int type, Vlong rv)
+{
+ Vlong t, u;
+
+ u.lo = 0;
+ u.hi = 0;
+ switch(type) {
+ default:
+ abort();
+ break;
+
+ case 1: /* schar */
+ t.lo = *(schar*)lv;
+ t.hi = t.lo >> 31;
+ fn(&u, t, rv);
+ *(schar*)lv = u.lo;
+ break;
+
+ case 2: /* uchar */
+ t.lo = *(uchar*)lv;
+ t.hi = 0;
+ fn(&u, t, rv);
+ *(uchar*)lv = u.lo;
+ break;
+
+ case 3: /* short */
+ t.lo = *(short*)lv;
+ t.hi = t.lo >> 31;
+ fn(&u, t, rv);
+ *(short*)lv = u.lo;
+ break;
+
+ case 4: /* ushort */
+ t.lo = *(ushort*)lv;
+ t.hi = 0;
+ fn(&u, t, rv);
+ *(ushort*)lv = u.lo;
+ break;
+
+ case 9: /* int */
+ t.lo = *(int*)lv;
+ t.hi = t.lo >> 31;
+ fn(&u, t, rv);
+ *(int*)lv = u.lo;
+ break;
+
+ case 10: /* uint */
+ t.lo = *(uint*)lv;
+ t.hi = 0;
+ fn(&u, t, rv);
+ *(uint*)lv = u.lo;
+ break;
+
+ case 5: /* long */
+ t.lo = *(long*)lv;
+ t.hi = t.lo >> 31;
+ fn(&u, t, rv);
+ *(long*)lv = u.lo;
+ break;
+
+ case 6: /* ulong */
+ t.lo = *(ulong*)lv;
+ t.hi = 0;
+ fn(&u, t, rv);
+ *(ulong*)lv = u.lo;
+ break;
+
+ case 7: /* vlong */
+ case 8: /* uvlong */
+ fn(&u, *(Vlong*)lv, rv);
+ *(Vlong*)lv = u;
+ break;
+ }
+ *ret = u;
+}
+
+void
+_p2v(Vlong *ret, void *p)
+{
+ long t;
+
+ t = (ulong)p;
+ ret->lo = t;
+ ret->hi = 0;
+}
+
+void
+_sl2v(Vlong *ret, long sl)
+{
+ long t;
+
+ t = sl;
+ ret->lo = t;
+ ret->hi = t >> 31;
+}
+
+void
+_ul2v(Vlong *ret, ulong ul)
+{
+ long t;
+
+ t = ul;
+ ret->lo = t;
+ ret->hi = 0;
+}
+
+void
+_si2v(Vlong *ret, int si)
+{
+ long t;
+
+ t = si;
+ ret->lo = t;
+ ret->hi = t >> 31;
+}
+
+void
+_ui2v(Vlong *ret, uint ui)
+{
+ long t;
+
+ t = ui;
+ ret->lo = t;
+ ret->hi = 0;
+}
+
+void
+_sh2v(Vlong *ret, long sh)
+{
+ long t;
+
+ t = (sh << 16) >> 16;
+ ret->lo = t;
+ ret->hi = t >> 31;
+}
+
+void
+_uh2v(Vlong *ret, ulong ul)
+{
+ long t;
+
+ t = ul & 0xffff;
+ ret->lo = t;
+ ret->hi = 0;
+}
+
+void
+_sc2v(Vlong *ret, long uc)
+{
+ long t;
+
+ t = (uc << 24) >> 24;
+ ret->lo = t;
+ ret->hi = t >> 31;
+}
+
+void
+_uc2v(Vlong *ret, ulong ul)
+{
+ long t;
+
+ t = ul & 0xff;
+ ret->lo = t;
+ ret->hi = 0;
+}
+
+long
+_v2sc(Vlong rv)
+{
+ long t;
+
+ t = rv.lo & 0xff;
+ return (t << 24) >> 24;
+}
+
+long
+_v2uc(Vlong rv)
+{
+
+ return rv.lo & 0xff;
+}
+
+long
+_v2sh(Vlong rv)
+{
+ long t;
+
+ t = rv.lo & 0xffff;
+ return (t << 16) >> 16;
+}
+
+long
+_v2uh(Vlong rv)
+{
+
+ return rv.lo & 0xffff;
+}
+
+long
+_v2sl(Vlong rv)
+{
+
+ return rv.lo;
+}
+
+long
+_v2ul(Vlong rv)
+{
+
+ return rv.lo;
+}
+
+long
+_v2si(Vlong rv)
+{
+
+ return rv.lo;
+}
+
+long
+_v2ui(Vlong rv)
+{
+
+ return rv.lo;
+}
+
+int
+_testv(Vlong rv)
+{
+ return rv.lo || rv.hi;
+}
+
+int
+_eqv(Vlong lv, Vlong rv)
+{
+ return lv.lo == rv.lo && lv.hi == rv.hi;
+}
+
+int
+_nev(Vlong lv, Vlong rv)
+{
+ return lv.lo != rv.lo || lv.hi != rv.hi;
+}
+
+int
+_ltv(Vlong lv, Vlong rv)
+{
+ return (long)lv.hi < (long)rv.hi ||
+ (lv.hi == rv.hi && lv.lo < rv.lo);
+}
+
+int
+_lev(Vlong lv, Vlong rv)
+{
+ return (long)lv.hi < (long)rv.hi ||
+ (lv.hi == rv.hi && lv.lo <= rv.lo);
+}
+
+int
+_gtv(Vlong lv, Vlong rv)
+{
+ return (long)lv.hi > (long)rv.hi ||
+ (lv.hi == rv.hi && lv.lo > rv.lo);
+}
+
+int
+_gev(Vlong lv, Vlong rv)
+{
+ return (long)lv.hi > (long)rv.hi ||
+ (lv.hi == rv.hi && lv.lo >= rv.lo);
+}
+
+int
+_lov(Vlong lv, Vlong rv)
+{
+ return lv.hi < rv.hi ||
+ (lv.hi == rv.hi && lv.lo < rv.lo);
+}
+
+int
+_lsv(Vlong lv, Vlong rv)
+{
+ return lv.hi < rv.hi ||
+ (lv.hi == rv.hi && lv.lo <= rv.lo);
+}
+
+int
+_hiv(Vlong lv, Vlong rv)
+{
+ return lv.hi > rv.hi ||
+ (lv.hi == rv.hi && lv.lo > rv.lo);
+}
+
+int
+_hsv(Vlong lv, Vlong rv)
+{
+ return lv.hi > rv.hi ||
+ (lv.hi == rv.hi && lv.lo >= rv.lo);
+}
--- /dev/null
+++ b/libkern/vlrt-power.c
@@ -1,0 +1,718 @@
+typedef unsigned long ulong;
+typedef unsigned int uint;
+typedef unsigned short ushort;
+typedef unsigned char uchar;
+typedef signed char schar;
+
+#define SIGN(n) (1UL<<(n-1))
+
+typedef struct Vlong Vlong;
+struct Vlong
+{
+ union
+ {
+ struct
+ {
+ ulong hi;
+ ulong lo;
+ };
+ struct
+ {
+ ushort hims;
+ ushort hils;
+ ushort loms;
+ ushort lols;
+ };
+ };
+};
+
+void abort(void);
+
+void
+_addv(Vlong *r, Vlong a, Vlong b)
+{
+ ulong lo, hi;
+
+ lo = a.lo + b.lo;
+ hi = a.hi + b.hi;
+ if(lo < a.lo)
+ hi++;
+ r->lo = lo;
+ r->hi = hi;
+}
+
+void
+_subv(Vlong *r, Vlong a, Vlong b)
+{
+ ulong lo, hi;
+
+ lo = a.lo - b.lo;
+ hi = a.hi - b.hi;
+ if(lo > a.lo)
+ hi--;
+ r->lo = lo;
+ r->hi = hi;
+}
+
+void
+_d2v(Vlong *y, double d)
+{
+ union { double d; struct Vlong; } x;
+ ulong xhi, xlo, ylo, yhi;
+ int sh;
+
+ x.d = d;
+
+ xhi = (x.hi & 0xfffff) | 0x100000;
+ xlo = x.lo;
+ sh = 1075 - ((x.hi >> 20) & 0x7ff);
+
+ ylo = 0;
+ yhi = 0;
+ if(sh >= 0) {
+ /* v = (hi||lo) >> sh */
+ if(sh < 32) {
+ if(sh == 0) {
+ ylo = xlo;
+ yhi = xhi;
+ } else {
+ ylo = (xlo >> sh) | (xhi << (32-sh));
+ yhi = xhi >> sh;
+ }
+ } else {
+ if(sh == 32) {
+ ylo = xhi;
+ } else
+ if(sh < 64) {
+ ylo = xhi >> (sh-32);
+ }
+ }
+ } else {
+ /* v = (hi||lo) << -sh */
+ sh = -sh;
+ if(sh <= 10) {
+ ylo = xlo << sh;
+ yhi = (xhi << sh) | (xlo >> (32-sh));
+ } else {
+ /* overflow */
+ yhi = d; /* causes something awful */
+ }
+ }
+ if(x.hi & SIGN(32)) {
+ if(ylo != 0) {
+ ylo = -ylo;
+ yhi = ~yhi;
+ } else
+ yhi = -yhi;
+ }
+
+ y->hi = yhi;
+ y->lo = ylo;
+}
+
+void
+_f2v(Vlong *y, float f)
+{
+
+ _d2v(y, f);
+}
+
+double
+_v2d(Vlong x)
+{
+ if(x.hi & SIGN(32)) {
+ if(x.lo) {
+ x.lo = -x.lo;
+ x.hi = ~x.hi;
+ } else
+ x.hi = -x.hi;
+ return -((long)x.hi*4294967296. + x.lo);
+ }
+ return (long)x.hi*4294967296. + x.lo;
+}
+
+float
+_v2f(Vlong x)
+{
+ return _v2d(x);
+}
+
+static void
+dodiv(Vlong num, Vlong den, Vlong *q, Vlong *r)
+{
+ ulong numlo, numhi, denhi, denlo, quohi, quolo, t;
+ int i;
+
+ numhi = num.hi;
+ numlo = num.lo;
+ denhi = den.hi;
+ denlo = den.lo;
+
+ /*
+ * get a divide by zero
+ */
+ if(denlo==0 && denhi==0) {
+ numlo = numlo / denlo;
+ }
+
+ /*
+ * set up the divisor and find the number of iterations needed
+ */
+ if(numhi >= SIGN(32)) {
+ quohi = SIGN(32);
+ quolo = 0;
+ } else {
+ quohi = numhi;
+ quolo = numlo;
+ }
+ i = 0;
+ while(denhi < quohi || (denhi == quohi && denlo < quolo)) {
+ denhi = (denhi<<1) | (denlo>>31);
+ denlo <<= 1;
+ i++;
+ }
+
+ quohi = 0;
+ quolo = 0;
+ for(; i >= 0; i--) {
+ quohi = (quohi<<1) | (quolo>>31);
+ quolo <<= 1;
+ if(numhi > denhi || (numhi == denhi && numlo >= denlo)) {
+ t = numlo;
+ numlo -= denlo;
+ if(numlo > t)
+ numhi--;
+ numhi -= denhi;
+ quolo |= 1;
+ }
+ denlo = (denlo>>1) | (denhi<<31);
+ denhi >>= 1;
+ }
+
+ if(q) {
+ q->lo = quolo;
+ q->hi = quohi;
+ }
+ if(r) {
+ r->lo = numlo;
+ r->hi = numhi;
+ }
+}
+
+void
+_divvu(Vlong *q, Vlong n, Vlong d)
+{
+
+ if(n.hi == 0 && d.hi == 0) {
+ q->hi = 0;
+ q->lo = n.lo / d.lo;
+ return;
+ }
+ dodiv(n, d, q, 0);
+}
+
+void
+_modvu(Vlong *r, Vlong n, Vlong d)
+{
+
+ if(n.hi == 0 && d.hi == 0) {
+ r->hi = 0;
+ r->lo = n.lo % d.lo;
+ return;
+ }
+ dodiv(n, d, 0, r);
+}
+
+static void
+vneg(Vlong *v)
+{
+
+ if(v->lo == 0) {
+ v->hi = -v->hi;
+ return;
+ }
+ v->lo = -v->lo;
+ v->hi = ~v->hi;
+}
+
+void
+_divv(Vlong *q, Vlong n, Vlong d)
+{
+ long nneg, dneg;
+
+ if(n.hi == (((long)n.lo)>>31) && d.hi == (((long)d.lo)>>31)) {
+ q->lo = (long)n.lo / (long)d.lo;
+ q->hi = ((long)q->lo) >> 31;
+ return;
+ }
+ nneg = n.hi >> 31;
+ if(nneg)
+ vneg(&n);
+ dneg = d.hi >> 31;
+ if(dneg)
+ vneg(&d);
+ dodiv(n, d, q, 0);
+ if(nneg != dneg)
+ vneg(q);
+}
+
+void
+_modv(Vlong *r, Vlong n, Vlong d)
+{
+ long nneg, dneg;
+
+ if(n.hi == (((long)n.lo)>>31) && d.hi == (((long)d.lo)>>31)) {
+ r->lo = (long)n.lo % (long)d.lo;
+ r->hi = ((long)r->lo) >> 31;
+ return;
+ }
+ nneg = n.hi >> 31;
+ if(nneg)
+ vneg(&n);
+ dneg = d.hi >> 31;
+ if(dneg)
+ vneg(&d);
+ dodiv(n, d, 0, r);
+ if(nneg)
+ vneg(r);
+}
+
+void
+_rshav(Vlong *r, Vlong a, int b)
+{
+ long t;
+
+ t = a.hi;
+ if(b >= 32) {
+ r->hi = t>>31;
+ if(b >= 64) {
+ /* this is illegal re C standard */
+ r->lo = t>>31;
+ return;
+ }
+ r->lo = t >> (b-32);
+ return;
+ }
+ if(b <= 0) {
+ r->hi = t;
+ r->lo = a.lo;
+ return;
+ }
+ r->hi = t >> b;
+ r->lo = (t << (32-b)) | (a.lo >> b);
+}
+
+void
+_rshlv(Vlong *r, Vlong a, int b)
+{
+ ulong t;
+
+ t = a.hi;
+ if(b >= 32) {
+ r->hi = 0;
+ if(b >= 64) {
+ /* this is illegal re C standard */
+ r->lo = 0;
+ return;
+ }
+ r->lo = t >> (b-32);
+ return;
+ }
+ if(b <= 0) {
+ r->hi = t;
+ r->lo = a.lo;
+ return;
+ }
+ r->hi = t >> b;
+ r->lo = (t << (32-b)) | (a.lo >> b);
+}
+
+void
+_lshv(Vlong *r, Vlong a, int b)
+{
+ ulong t;
+
+ t = a.lo;
+ if(b >= 32) {
+ r->lo = 0;
+ if(b >= 64) {
+ /* this is illegal re C standard */
+ r->hi = 0;
+ return;
+ }
+ r->hi = t << (b-32);
+ return;
+ }
+ if(b <= 0) {
+ r->lo = t;
+ r->hi = a.hi;
+ return;
+ }
+ r->lo = t << b;
+ r->hi = (t >> (32-b)) | (a.hi << b);
+}
+
+void
+_andv(Vlong *r, Vlong a, Vlong b)
+{
+ r->hi = a.hi & b.hi;
+ r->lo = a.lo & b.lo;
+}
+
+void
+_orv(Vlong *r, Vlong a, Vlong b)
+{
+ r->hi = a.hi | b.hi;
+ r->lo = a.lo | b.lo;
+}
+
+void
+_xorv(Vlong *r, Vlong a, Vlong b)
+{
+ r->hi = a.hi ^ b.hi;
+ r->lo = a.lo ^ b.lo;
+}
+
+void
+_vpp(Vlong *l, Vlong *r)
+{
+
+ l->hi = r->hi;
+ l->lo = r->lo;
+ r->lo++;
+ if(r->lo == 0)
+ r->hi++;
+}
+
+void
+_vmm(Vlong *l, Vlong *r)
+{
+
+ l->hi = r->hi;
+ l->lo = r->lo;
+ if(r->lo == 0)
+ r->hi--;
+ r->lo--;
+}
+
+void
+_ppv(Vlong *l, Vlong *r)
+{
+
+ r->lo++;
+ if(r->lo == 0)
+ r->hi++;
+ l->hi = r->hi;
+ l->lo = r->lo;
+}
+
+void
+_mmv(Vlong *l, Vlong *r)
+{
+
+ if(r->lo == 0)
+ r->hi--;
+ r->lo--;
+ l->hi = r->hi;
+ l->lo = r->lo;
+}
+
+void
+_vasop(Vlong *ret, void *lv, void fn(Vlong*, Vlong, Vlong), int type, Vlong rv)
+{
+ Vlong t, u;
+
+ u = *ret;
+ switch(type) {
+ default:
+ abort();
+ break;
+
+ case 1: /* schar */
+ t.lo = *(schar*)lv;
+ t.hi = t.lo >> 31;
+ fn(&u, t, rv);
+ *(schar*)lv = u.lo;
+ break;
+
+ case 2: /* uchar */
+ t.lo = *(uchar*)lv;
+ t.hi = 0;
+ fn(&u, t, rv);
+ *(uchar*)lv = u.lo;
+ break;
+
+ case 3: /* short */
+ t.lo = *(short*)lv;
+ t.hi = t.lo >> 31;
+ fn(&u, t, rv);
+ *(short*)lv = u.lo;
+ break;
+
+ case 4: /* ushort */
+ t.lo = *(ushort*)lv;
+ t.hi = 0;
+ fn(&u, t, rv);
+ *(ushort*)lv = u.lo;
+ break;
+
+ case 9: /* int */
+ t.lo = *(int*)lv;
+ t.hi = t.lo >> 31;
+ fn(&u, t, rv);
+ *(int*)lv = u.lo;
+ break;
+
+ case 10: /* uint */
+ t.lo = *(uint*)lv;
+ t.hi = 0;
+ fn(&u, t, rv);
+ *(uint*)lv = u.lo;
+ break;
+
+ case 5: /* long */
+ t.lo = *(long*)lv;
+ t.hi = t.lo >> 31;
+ fn(&u, t, rv);
+ *(long*)lv = u.lo;
+ break;
+
+ case 6: /* ulong */
+ t.lo = *(ulong*)lv;
+ t.hi = 0;
+ fn(&u, t, rv);
+ *(ulong*)lv = u.lo;
+ break;
+
+ case 7: /* vlong */
+ case 8: /* uvlong */
+ fn(&u, *(Vlong*)lv, rv);
+ *(Vlong*)lv = u;
+ break;
+ }
+ *ret = u;
+}
+
+void
+_p2v(Vlong *ret, void *p)
+{
+ long t;
+
+ t = (ulong)p;
+ ret->lo = t;
+ ret->hi = 0;
+}
+
+void
+_sl2v(Vlong *ret, long sl)
+{
+ long t;
+
+ t = sl;
+ ret->lo = t;
+ ret->hi = t >> 31;
+}
+
+void
+_ul2v(Vlong *ret, ulong ul)
+{
+ long t;
+
+ t = ul;
+ ret->lo = t;
+ ret->hi = 0;
+}
+
+void
+_si2v(Vlong *ret, int si)
+{
+ long t;
+
+ t = si;
+ ret->lo = t;
+ ret->hi = t >> 31;
+}
+
+void
+_ui2v(Vlong *ret, uint ui)
+{
+ long t;
+
+ t = ui;
+ ret->lo = t;
+ ret->hi = 0;
+}
+
+void
+_sh2v(Vlong *ret, long sh)
+{
+ long t;
+
+ t = (sh << 16) >> 16;
+ ret->lo = t;
+ ret->hi = t >> 31;
+}
+
+void
+_uh2v(Vlong *ret, ulong ul)
+{
+ long t;
+
+ t = ul & 0xffff;
+ ret->lo = t;
+ ret->hi = 0;
+}
+
+void
+_sc2v(Vlong *ret, long uc)
+{
+ long t;
+
+ t = (uc << 24) >> 24;
+ ret->lo = t;
+ ret->hi = t >> 31;
+}
+
+void
+_uc2v(Vlong *ret, ulong ul)
+{
+ long t;
+
+ t = ul & 0xff;
+ ret->lo = t;
+ ret->hi = 0;
+}
+
+long
+_v2sc(Vlong rv)
+{
+ long t;
+
+ t = rv.lo & 0xff;
+ return (t << 24) >> 24;
+}
+
+long
+_v2uc(Vlong rv)
+{
+
+ return rv.lo & 0xff;
+}
+
+long
+_v2sh(Vlong rv)
+{
+ long t;
+
+ t = rv.lo & 0xffff;
+ return (t << 16) >> 16;
+}
+
+long
+_v2uh(Vlong rv)
+{
+
+ return rv.lo & 0xffff;
+}
+
+long
+_v2sl(Vlong rv)
+{
+
+ return rv.lo;
+}
+
+long
+_v2ul(Vlong rv)
+{
+
+ return rv.lo;
+}
+
+long
+_v2si(Vlong rv)
+{
+
+ return rv.lo;
+}
+
+long
+_v2ui(Vlong rv)
+{
+
+ return rv.lo;
+}
+
+int
+_testv(Vlong rv)
+{
+ return rv.lo || rv.hi;
+}
+
+int
+_eqv(Vlong lv, Vlong rv)
+{
+ return lv.lo == rv.lo && lv.hi == rv.hi;
+}
+
+int
+_nev(Vlong lv, Vlong rv)
+{
+ return lv.lo != rv.lo || lv.hi != rv.hi;
+}
+
+int
+_ltv(Vlong lv, Vlong rv)
+{
+ return (long)lv.hi < (long)rv.hi ||
+ (lv.hi == rv.hi && lv.lo < rv.lo);
+}
+
+int
+_lev(Vlong lv, Vlong rv)
+{
+ return (long)lv.hi < (long)rv.hi ||
+ (lv.hi == rv.hi && lv.lo <= rv.lo);
+}
+
+int
+_gtv(Vlong lv, Vlong rv)
+{
+ return (long)lv.hi > (long)rv.hi ||
+ (lv.hi == rv.hi && lv.lo > rv.lo);
+}
+
+int
+_gev(Vlong lv, Vlong rv)
+{
+ return (long)lv.hi > (long)rv.hi ||
+ (lv.hi == rv.hi && lv.lo >= rv.lo);
+}
+
+int
+_lov(Vlong lv, Vlong rv)
+{
+ return lv.hi < rv.hi ||
+ (lv.hi == rv.hi && lv.lo < rv.lo);
+}
+
+int
+_lsv(Vlong lv, Vlong rv)
+{
+ return lv.hi < rv.hi ||
+ (lv.hi == rv.hi && lv.lo <= rv.lo);
+}
+
+int
+_hiv(Vlong lv, Vlong rv)
+{
+ return lv.hi > rv.hi ||
+ (lv.hi == rv.hi && lv.lo > rv.lo);
+}
+
+int
+_hsv(Vlong lv, Vlong rv)
+{
+ return lv.hi > rv.hi ||
+ (lv.hi == rv.hi && lv.lo >= rv.lo);
+}
--- /dev/null
+++ b/libkern/vlrt-sparc.c
@@ -1,0 +1,718 @@
+typedef unsigned long ulong;
+typedef unsigned int uint;
+typedef unsigned short ushort;
+typedef unsigned char uchar;
+typedef signed char schar;
+
+#define SIGN(n) (1UL<<(n-1))
+
+typedef struct Vlong Vlong;
+struct Vlong
+{
+ union
+ {
+ struct
+ {
+ ulong hi;
+ ulong lo;
+ };
+ struct
+ {
+ ushort hims;
+ ushort hils;
+ ushort loms;
+ ushort lols;
+ };
+ };
+};
+
+void abort(void);
+
+void
+_addv(Vlong *r, Vlong a, Vlong b)
+{
+ ulong lo, hi;
+
+ lo = a.lo + b.lo;
+ hi = a.hi + b.hi;
+ if(lo < a.lo)
+ hi++;
+ r->lo = lo;
+ r->hi = hi;
+}
+
+void
+_subv(Vlong *r, Vlong a, Vlong b)
+{
+ ulong lo, hi;
+
+ lo = a.lo - b.lo;
+ hi = a.hi - b.hi;
+ if(lo > a.lo)
+ hi--;
+ r->lo = lo;
+ r->hi = hi;
+}
+
+void
+_d2v(Vlong *y, double d)
+{
+ union { double d; struct Vlong; } x;
+ ulong xhi, xlo, ylo, yhi;
+ int sh;
+
+ x.d = d;
+
+ xhi = (x.hi & 0xfffff) | 0x100000;
+ xlo = x.lo;
+ sh = 1075 - ((x.hi >> 20) & 0x7ff);
+
+ ylo = 0;
+ yhi = 0;
+ if(sh >= 0) {
+ /* v = (hi||lo) >> sh */
+ if(sh < 32) {
+ if(sh == 0) {
+ ylo = xlo;
+ yhi = xhi;
+ } else {
+ ylo = (xlo >> sh) | (xhi << (32-sh));
+ yhi = xhi >> sh;
+ }
+ } else {
+ if(sh == 32) {
+ ylo = xhi;
+ } else
+ if(sh < 64) {
+ ylo = xhi >> (sh-32);
+ }
+ }
+ } else {
+ /* v = (hi||lo) << -sh */
+ sh = -sh;
+ if(sh <= 10) {
+ ylo = xlo << sh;
+ yhi = (xhi << sh) | (xlo >> (32-sh));
+ } else {
+ /* overflow */
+ yhi = d; /* causes something awful */
+ }
+ }
+ if(x.hi & SIGN(32)) {
+ if(ylo != 0) {
+ ylo = -ylo;
+ yhi = ~yhi;
+ } else
+ yhi = -yhi;
+ }
+
+ y->hi = yhi;
+ y->lo = ylo;
+}
+
+void
+_f2v(Vlong *y, float f)
+{
+
+ _d2v(y, f);
+}
+
+double
+_v2d(Vlong x)
+{
+ if(x.hi & SIGN(32)) {
+ if(x.lo) {
+ x.lo = -x.lo;
+ x.hi = ~x.hi;
+ } else
+ x.hi = -x.hi;
+ return -((long)x.hi*4294967296. + x.lo);
+ }
+ return (long)x.hi*4294967296. + x.lo;
+}
+
+float
+_v2f(Vlong x)
+{
+ return _v2d(x);
+}
+
+static void
+dodiv(Vlong num, Vlong den, Vlong *q, Vlong *r)
+{
+ ulong numlo, numhi, denhi, denlo, quohi, quolo, t;
+ int i;
+
+ numhi = num.hi;
+ numlo = num.lo;
+ denhi = den.hi;
+ denlo = den.lo;
+
+ /*
+ * get a divide by zero
+ */
+ if(denlo==0 && denhi==0) {
+ numlo = numlo / denlo;
+ }
+
+ /*
+ * set up the divisor and find the number of iterations needed
+ */
+ if(numhi >= SIGN(32)) {
+ quohi = SIGN(32);
+ quolo = 0;
+ } else {
+ quohi = numhi;
+ quolo = numlo;
+ }
+ i = 0;
+ while(denhi < quohi || (denhi == quohi && denlo < quolo)) {
+ denhi = (denhi<<1) | (denlo>>31);
+ denlo <<= 1;
+ i++;
+ }
+
+ quohi = 0;
+ quolo = 0;
+ for(; i >= 0; i--) {
+ quohi = (quohi<<1) | (quolo>>31);
+ quolo <<= 1;
+ if(numhi > denhi || (numhi == denhi && numlo >= denlo)) {
+ t = numlo;
+ numlo -= denlo;
+ if(numlo > t)
+ numhi--;
+ numhi -= denhi;
+ quolo |= 1;
+ }
+ denlo = (denlo>>1) | (denhi<<31);
+ denhi >>= 1;
+ }
+
+ if(q) {
+ q->lo = quolo;
+ q->hi = quohi;
+ }
+ if(r) {
+ r->lo = numlo;
+ r->hi = numhi;
+ }
+}
+
+void
+_divvu(Vlong *q, Vlong n, Vlong d)
+{
+
+ if(n.hi == 0 && d.hi == 0) {
+ q->hi = 0;
+ q->lo = n.lo / d.lo;
+ return;
+ }
+ dodiv(n, d, q, 0);
+}
+
+void
+_modvu(Vlong *r, Vlong n, Vlong d)
+{
+
+ if(n.hi == 0 && d.hi == 0) {
+ r->hi = 0;
+ r->lo = n.lo % d.lo;
+ return;
+ }
+ dodiv(n, d, 0, r);
+}
+
+static void
+vneg(Vlong *v)
+{
+
+ if(v->lo == 0) {
+ v->hi = -v->hi;
+ return;
+ }
+ v->lo = -v->lo;
+ v->hi = ~v->hi;
+}
+
+void
+_divv(Vlong *q, Vlong n, Vlong d)
+{
+ long nneg, dneg;
+
+ if(n.hi == (((long)n.lo)>>31) && d.hi == (((long)d.lo)>>31)) {
+ q->lo = (long)n.lo / (long)d.lo;
+ q->hi = ((long)q->lo) >> 31;
+ return;
+ }
+ nneg = n.hi >> 31;
+ if(nneg)
+ vneg(&n);
+ dneg = d.hi >> 31;
+ if(dneg)
+ vneg(&d);
+ dodiv(n, d, q, 0);
+ if(nneg != dneg)
+ vneg(q);
+}
+
+void
+_modv(Vlong *r, Vlong n, Vlong d)
+{
+ long nneg, dneg;
+
+ if(n.hi == (((long)n.lo)>>31) && d.hi == (((long)d.lo)>>31)) {
+ r->lo = (long)n.lo % (long)d.lo;
+ r->hi = ((long)r->lo) >> 31;
+ return;
+ }
+ nneg = n.hi >> 31;
+ if(nneg)
+ vneg(&n);
+ dneg = d.hi >> 31;
+ if(dneg)
+ vneg(&d);
+ dodiv(n, d, 0, r);
+ if(nneg)
+ vneg(r);
+}
+
+void
+_rshav(Vlong *r, Vlong a, int b)
+{
+ long t;
+
+ t = a.hi;
+ if(b >= 32) {
+ r->hi = t>>31;
+ if(b >= 64) {
+ /* this is illegal re C standard */
+ r->lo = t>>31;
+ return;
+ }
+ r->lo = t >> (b-32);
+ return;
+ }
+ if(b <= 0) {
+ r->hi = t;
+ r->lo = a.lo;
+ return;
+ }
+ r->hi = t >> b;
+ r->lo = (t << (32-b)) | (a.lo >> b);
+}
+
+void
+_rshlv(Vlong *r, Vlong a, int b)
+{
+ ulong t;
+
+ t = a.hi;
+ if(b >= 32) {
+ r->hi = 0;
+ if(b >= 64) {
+ /* this is illegal re C standard */
+ r->lo = 0;
+ return;
+ }
+ r->lo = t >> (b-32);
+ return;
+ }
+ if(b <= 0) {
+ r->hi = t;
+ r->lo = a.lo;
+ return;
+ }
+ r->hi = t >> b;
+ r->lo = (t << (32-b)) | (a.lo >> b);
+}
+
+void
+_lshv(Vlong *r, Vlong a, int b)
+{
+ ulong t;
+
+ t = a.lo;
+ if(b >= 32) {
+ r->lo = 0;
+ if(b >= 64) {
+ /* this is illegal re C standard */
+ r->hi = 0;
+ return;
+ }
+ r->hi = t << (b-32);
+ return;
+ }
+ if(b <= 0) {
+ r->lo = t;
+ r->hi = a.hi;
+ return;
+ }
+ r->lo = t << b;
+ r->hi = (t >> (32-b)) | (a.hi << b);
+}
+
+void
+_andv(Vlong *r, Vlong a, Vlong b)
+{
+ r->hi = a.hi & b.hi;
+ r->lo = a.lo & b.lo;
+}
+
+void
+_orv(Vlong *r, Vlong a, Vlong b)
+{
+ r->hi = a.hi | b.hi;
+ r->lo = a.lo | b.lo;
+}
+
+void
+_xorv(Vlong *r, Vlong a, Vlong b)
+{
+ r->hi = a.hi ^ b.hi;
+ r->lo = a.lo ^ b.lo;
+}
+
+void
+_vpp(Vlong *l, Vlong *r)
+{
+
+ l->hi = r->hi;
+ l->lo = r->lo;
+ r->lo++;
+ if(r->lo == 0)
+ r->hi++;
+}
+
+void
+_vmm(Vlong *l, Vlong *r)
+{
+
+ l->hi = r->hi;
+ l->lo = r->lo;
+ if(r->lo == 0)
+ r->hi--;
+ r->lo--;
+}
+
+void
+_ppv(Vlong *l, Vlong *r)
+{
+
+ r->lo++;
+ if(r->lo == 0)
+ r->hi++;
+ l->hi = r->hi;
+ l->lo = r->lo;
+}
+
+void
+_mmv(Vlong *l, Vlong *r)
+{
+
+ if(r->lo == 0)
+ r->hi--;
+ r->lo--;
+ l->hi = r->hi;
+ l->lo = r->lo;
+}
+
+void
+_vasop(Vlong *ret, void *lv, void fn(Vlong*, Vlong, Vlong), int type, Vlong rv)
+{
+ Vlong t, u;
+
+ u = *ret;
+ switch(type) {
+ default:
+ abort();
+ break;
+
+ case 1: /* schar */
+ t.lo = *(schar*)lv;
+ t.hi = t.lo >> 31;
+ fn(&u, t, rv);
+ *(schar*)lv = u.lo;
+ break;
+
+ case 2: /* uchar */
+ t.lo = *(uchar*)lv;
+ t.hi = 0;
+ fn(&u, t, rv);
+ *(uchar*)lv = u.lo;
+ break;
+
+ case 3: /* short */
+ t.lo = *(short*)lv;
+ t.hi = t.lo >> 31;
+ fn(&u, t, rv);
+ *(short*)lv = u.lo;
+ break;
+
+ case 4: /* ushort */
+ t.lo = *(ushort*)lv;
+ t.hi = 0;
+ fn(&u, t, rv);
+ *(ushort*)lv = u.lo;
+ break;
+
+ case 9: /* int */
+ t.lo = *(int*)lv;
+ t.hi = t.lo >> 31;
+ fn(&u, t, rv);
+ *(int*)lv = u.lo;
+ break;
+
+ case 10: /* uint */
+ t.lo = *(uint*)lv;
+ t.hi = 0;
+ fn(&u, t, rv);
+ *(uint*)lv = u.lo;
+ break;
+
+ case 5: /* long */
+ t.lo = *(long*)lv;
+ t.hi = t.lo >> 31;
+ fn(&u, t, rv);
+ *(long*)lv = u.lo;
+ break;
+
+ case 6: /* ulong */
+ t.lo = *(ulong*)lv;
+ t.hi = 0;
+ fn(&u, t, rv);
+ *(ulong*)lv = u.lo;
+ break;
+
+ case 7: /* vlong */
+ case 8: /* uvlong */
+ fn(&u, *(Vlong*)lv, rv);
+ *(Vlong*)lv = u;
+ break;
+ }
+ *ret = u;
+}
+
+void
+_p2v(Vlong *ret, void *p)
+{
+ long t;
+
+ t = (ulong)p;
+ ret->lo = t;
+ ret->hi = 0;
+}
+
+void
+_sl2v(Vlong *ret, long sl)
+{
+ long t;
+
+ t = sl;
+ ret->lo = t;
+ ret->hi = t >> 31;
+}
+
+void
+_ul2v(Vlong *ret, ulong ul)
+{
+ long t;
+
+ t = ul;
+ ret->lo = t;
+ ret->hi = 0;
+}
+
+void
+_si2v(Vlong *ret, int si)
+{
+ long t;
+
+ t = si;
+ ret->lo = t;
+ ret->hi = t >> 31;
+}
+
+void
+_ui2v(Vlong *ret, uint ui)
+{
+ long t;
+
+ t = ui;
+ ret->lo = t;
+ ret->hi = 0;
+}
+
+void
+_sh2v(Vlong *ret, long sh)
+{
+ long t;
+
+ t = (sh << 16) >> 16;
+ ret->lo = t;
+ ret->hi = t >> 31;
+}
+
+void
+_uh2v(Vlong *ret, ulong ul)
+{
+ long t;
+
+ t = ul & 0xffff;
+ ret->lo = t;
+ ret->hi = 0;
+}
+
+void
+_sc2v(Vlong *ret, long uc)
+{
+ long t;
+
+ t = (uc << 24) >> 24;
+ ret->lo = t;
+ ret->hi = t >> 31;
+}
+
+void
+_uc2v(Vlong *ret, ulong ul)
+{
+ long t;
+
+ t = ul & 0xff;
+ ret->lo = t;
+ ret->hi = 0;
+}
+
+long
+_v2sc(Vlong rv)
+{
+ long t;
+
+ t = rv.lo & 0xff;
+ return (t << 24) >> 24;
+}
+
+long
+_v2uc(Vlong rv)
+{
+
+ return rv.lo & 0xff;
+}
+
+long
+_v2sh(Vlong rv)
+{
+ long t;
+
+ t = rv.lo & 0xffff;
+ return (t << 16) >> 16;
+}
+
+long
+_v2uh(Vlong rv)
+{
+
+ return rv.lo & 0xffff;
+}
+
+long
+_v2sl(Vlong rv)
+{
+
+ return rv.lo;
+}
+
+long
+_v2ul(Vlong rv)
+{
+
+ return rv.lo;
+}
+
+long
+_v2si(Vlong rv)
+{
+
+ return rv.lo;
+}
+
+long
+_v2ui(Vlong rv)
+{
+
+ return rv.lo;
+}
+
+int
+_testv(Vlong rv)
+{
+ return rv.lo || rv.hi;
+}
+
+int
+_eqv(Vlong lv, Vlong rv)
+{
+ return lv.lo == rv.lo && lv.hi == rv.hi;
+}
+
+int
+_nev(Vlong lv, Vlong rv)
+{
+ return lv.lo != rv.lo || lv.hi != rv.hi;
+}
+
+int
+_ltv(Vlong lv, Vlong rv)
+{
+ return (long)lv.hi < (long)rv.hi ||
+ (lv.hi == rv.hi && lv.lo < rv.lo);
+}
+
+int
+_lev(Vlong lv, Vlong rv)
+{
+ return (long)lv.hi < (long)rv.hi ||
+ (lv.hi == rv.hi && lv.lo <= rv.lo);
+}
+
+int
+_gtv(Vlong lv, Vlong rv)
+{
+ return (long)lv.hi > (long)rv.hi ||
+ (lv.hi == rv.hi && lv.lo > rv.lo);
+}
+
+int
+_gev(Vlong lv, Vlong rv)
+{
+ return (long)lv.hi > (long)rv.hi ||
+ (lv.hi == rv.hi && lv.lo >= rv.lo);
+}
+
+int
+_lov(Vlong lv, Vlong rv)
+{
+ return lv.hi < rv.hi ||
+ (lv.hi == rv.hi && lv.lo < rv.lo);
+}
+
+int
+_lsv(Vlong lv, Vlong rv)
+{
+ return lv.hi < rv.hi ||
+ (lv.hi == rv.hi && lv.lo <= rv.lo);
+}
+
+int
+_hiv(Vlong lv, Vlong rv)
+{
+ return lv.hi > rv.hi ||
+ (lv.hi == rv.hi && lv.lo > rv.lo);
+}
+
+int
+_hsv(Vlong lv, Vlong rv)
+{
+ return lv.hi > rv.hi ||
+ (lv.hi == rv.hi && lv.lo >= rv.lo);
+}
--- /dev/null
+++ b/libkern/vlrt-spim.c
@@ -1,0 +1,711 @@
+typedef unsigned long ulong;
+typedef unsigned int uint;
+typedef unsigned short ushort;
+typedef unsigned char uchar;
+typedef signed char schar;
+
+#define SIGN(n) (1UL<<(n-1))
+
+typedef struct Vlong Vlong;
+struct Vlong
+{
+ union
+ {
+ struct
+ {
+ ulong lo;
+ ulong hi;
+ };
+ };
+};
+
+void abort(void);
+
+void
+_addv(Vlong *r, Vlong a, Vlong b)
+{
+ ulong lo, hi;
+
+ lo = a.lo + b.lo;
+ hi = a.hi + b.hi;
+ if(lo < a.lo)
+ hi++;
+ r->lo = lo;
+ r->hi = hi;
+}
+
+void
+_subv(Vlong *r, Vlong a, Vlong b)
+{
+ ulong lo, hi;
+
+ lo = a.lo - b.lo;
+ hi = a.hi - b.hi;
+ if(lo > a.lo)
+ hi--;
+ r->lo = lo;
+ r->hi = hi;
+}
+
+
+void
+_d2v(Vlong *y, double d)
+{
+ union { double d; struct Vlong; } x;
+ ulong xhi, xlo, ylo, yhi;
+ int sh;
+
+ x.d = d;
+
+ xhi = (x.hi & 0xfffff) | 0x100000;
+ xlo = x.lo;
+ sh = 1075 - ((x.hi >> 20) & 0x7ff);
+
+ ylo = 0;
+ yhi = 0;
+ if(sh >= 0) {
+ /* v = (hi||lo) >> sh */
+ if(sh < 32) {
+ if(sh == 0) {
+ ylo = xlo;
+ yhi = xhi;
+ } else {
+ ylo = (xlo >> sh) | (xhi << (32-sh));
+ yhi = xhi >> sh;
+ }
+ } else {
+ if(sh == 32) {
+ ylo = xhi;
+ } else
+ if(sh < 64) {
+ ylo = xhi >> (sh-32);
+ }
+ }
+ } else {
+ /* v = (hi||lo) << -sh */
+ sh = -sh;
+ if(sh <= 10) {
+ ylo = xlo << sh;
+ yhi = (xhi << sh) | (xlo >> (32-sh));
+ } else {
+ /* overflow */
+ yhi = d; /* causes something awful */
+ }
+ }
+ if(x.hi & SIGN(32)) {
+ if(ylo != 0) {
+ ylo = -ylo;
+ yhi = ~yhi;
+ } else
+ yhi = -yhi;
+ }
+
+ y->hi = yhi;
+ y->lo = ylo;
+}
+
+void
+_f2v(Vlong *y, float f)
+{
+ _d2v(y, f);
+}
+
+double
+_v2d(Vlong x)
+{
+ if(x.hi & SIGN(32)) {
+ if(x.lo) {
+ x.lo = -x.lo;
+ x.hi = ~x.hi;
+ } else
+ x.hi = -x.hi;
+ return -((long)x.hi*4294967296. + x.lo);
+ }
+ return (long)x.hi*4294967296. + x.lo;
+}
+
+float
+_v2f(Vlong x)
+{
+ return _v2d(x);
+}
+
+static void
+dodiv(Vlong num, Vlong den, Vlong *q, Vlong *r)
+{
+ ulong numlo, numhi, denhi, denlo, quohi, quolo, t;
+ int i;
+
+ numhi = num.hi;
+ numlo = num.lo;
+ denhi = den.hi;
+ denlo = den.lo;
+
+ /*
+ * get a divide by zero
+ */
+ if(denlo==0 && denhi==0) {
+ numlo = numlo / denlo;
+ }
+
+ /*
+ * set up the divisor and find the number of iterations needed
+ */
+ if(numhi >= SIGN(32)) {
+ quohi = SIGN(32);
+ quolo = 0;
+ } else {
+ quohi = numhi;
+ quolo = numlo;
+ }
+ i = 0;
+ while(denhi < quohi || (denhi == quohi && denlo < quolo)) {
+ denhi = (denhi<<1) | (denlo>>31);
+ denlo <<= 1;
+ i++;
+ }
+
+ quohi = 0;
+ quolo = 0;
+ for(; i >= 0; i--) {
+ quohi = (quohi<<1) | (quolo>>31);
+ quolo <<= 1;
+ if(numhi > denhi || (numhi == denhi && numlo >= denlo)) {
+ t = numlo;
+ numlo -= denlo;
+ if(numlo > t)
+ numhi--;
+ numhi -= denhi;
+ quolo |= 1;
+ }
+ denlo = (denlo>>1) | (denhi<<31);
+ denhi >>= 1;
+ }
+
+ if(q) {
+ q->lo = quolo;
+ q->hi = quohi;
+ }
+ if(r) {
+ r->lo = numlo;
+ r->hi = numhi;
+ }
+}
+
+void
+_divvu(Vlong *q, Vlong n, Vlong d)
+{
+
+ if(n.hi == 0 && d.hi == 0) {
+ q->hi = 0;
+ q->lo = n.lo / d.lo;
+ return;
+ }
+ dodiv(n, d, q, 0);
+}
+
+void
+_modvu(Vlong *r, Vlong n, Vlong d)
+{
+
+ if(n.hi == 0 && d.hi == 0) {
+ r->hi = 0;
+ r->lo = n.lo % d.lo;
+ return;
+ }
+ dodiv(n, d, 0, r);
+}
+
+static void
+vneg(Vlong *v)
+{
+
+ if(v->lo == 0) {
+ v->hi = -v->hi;
+ return;
+ }
+ v->lo = -v->lo;
+ v->hi = ~v->hi;
+}
+
+void
+_divv(Vlong *q, Vlong n, Vlong d)
+{
+ long nneg, dneg;
+
+ if(n.hi == (((long)n.lo)>>31) && d.hi == (((long)d.lo)>>31)) {
+ q->lo = (long)n.lo / (long)d.lo;
+ q->hi = ((long)q->lo) >> 31;
+ return;
+ }
+ nneg = n.hi >> 31;
+ if(nneg)
+ vneg(&n);
+ dneg = d.hi >> 31;
+ if(dneg)
+ vneg(&d);
+ dodiv(n, d, q, 0);
+ if(nneg != dneg)
+ vneg(q);
+}
+
+void
+_modv(Vlong *r, Vlong n, Vlong d)
+{
+ long nneg, dneg;
+
+ if(n.hi == (((long)n.lo)>>31) && d.hi == (((long)d.lo)>>31)) {
+ r->lo = (long)n.lo % (long)d.lo;
+ r->hi = ((long)r->lo) >> 31;
+ return;
+ }
+ nneg = n.hi >> 31;
+ if(nneg)
+ vneg(&n);
+ dneg = d.hi >> 31;
+ if(dneg)
+ vneg(&d);
+ dodiv(n, d, 0, r);
+ if(nneg)
+ vneg(r);
+}
+
+void
+_rshav(Vlong *r, Vlong a, int b)
+{
+ long t;
+
+ t = a.hi;
+ if(b >= 32) {
+ r->hi = t>>31;
+ if(b >= 64) {
+ /* this is illegal re C standard */
+ r->lo = t>>31;
+ return;
+ }
+ r->lo = t >> (b-32);
+ return;
+ }
+ if(b <= 0) {
+ r->hi = t;
+ r->lo = a.lo;
+ return;
+ }
+ r->hi = t >> b;
+ r->lo = (t << (32-b)) | (a.lo >> b);
+}
+
+void
+_rshlv(Vlong *r, Vlong a, int b)
+{
+ ulong t;
+
+ t = a.hi;
+ if(b >= 32) {
+ r->hi = 0;
+ if(b >= 64) {
+ /* this is illegal re C standard */
+ r->lo = 0;
+ return;
+ }
+ r->lo = t >> (b-32);
+ return;
+ }
+ if(b <= 0) {
+ r->hi = t;
+ r->lo = a.lo;
+ return;
+ }
+ r->hi = t >> b;
+ r->lo = (t << (32-b)) | (a.lo >> b);
+}
+
+void
+_lshv(Vlong *r, Vlong a, int b)
+{
+ ulong t;
+
+ t = a.lo;
+ if(b >= 32) {
+ r->lo = 0;
+ if(b >= 64) {
+ /* this is illegal re C standard */
+ r->hi = 0;
+ return;
+ }
+ r->hi = t << (b-32);
+ return;
+ }
+ if(b <= 0) {
+ r->lo = t;
+ r->hi = a.hi;
+ return;
+ }
+ r->lo = t << b;
+ r->hi = (t >> (32-b)) | (a.hi << b);
+}
+
+void
+_andv(Vlong *r, Vlong a, Vlong b)
+{
+ r->hi = a.hi & b.hi;
+ r->lo = a.lo & b.lo;
+}
+
+void
+_orv(Vlong *r, Vlong a, Vlong b)
+{
+ r->hi = a.hi | b.hi;
+ r->lo = a.lo | b.lo;
+}
+
+void
+_xorv(Vlong *r, Vlong a, Vlong b)
+{
+ r->hi = a.hi ^ b.hi;
+ r->lo = a.lo ^ b.lo;
+}
+
+void
+_vpp(Vlong *l, Vlong *r)
+{
+
+ l->hi = r->hi;
+ l->lo = r->lo;
+ r->lo++;
+ if(r->lo == 0)
+ r->hi++;
+}
+
+void
+_vmm(Vlong *l, Vlong *r)
+{
+
+ l->hi = r->hi;
+ l->lo = r->lo;
+ if(r->lo == 0)
+ r->hi--;
+ r->lo--;
+}
+
+void
+_ppv(Vlong *l, Vlong *r)
+{
+
+ r->lo++;
+ if(r->lo == 0)
+ r->hi++;
+ l->hi = r->hi;
+ l->lo = r->lo;
+}
+
+void
+_mmv(Vlong *l, Vlong *r)
+{
+
+ if(r->lo == 0)
+ r->hi--;
+ r->lo--;
+ l->hi = r->hi;
+ l->lo = r->lo;
+}
+
+void
+_vasop(Vlong *ret, void *lv, void fn(Vlong*, Vlong, Vlong), int type, Vlong rv)
+{
+ Vlong t, u;
+
+ u = *ret;
+ switch(type) {
+ default:
+ abort();
+ break;
+
+ case 1: /* schar */
+ t.lo = *(schar*)lv;
+ t.hi = t.lo >> 31;
+ fn(&u, t, rv);
+ *(schar*)lv = u.lo;
+ break;
+
+ case 2: /* uchar */
+ t.lo = *(uchar*)lv;
+ t.hi = 0;
+ fn(&u, t, rv);
+ *(uchar*)lv = u.lo;
+ break;
+
+ case 3: /* short */
+ t.lo = *(short*)lv;
+ t.hi = t.lo >> 31;
+ fn(&u, t, rv);
+ *(short*)lv = u.lo;
+ break;
+
+ case 4: /* ushort */
+ t.lo = *(ushort*)lv;
+ t.hi = 0;
+ fn(&u, t, rv);
+ *(ushort*)lv = u.lo;
+ break;
+
+ case 9: /* int */
+ t.lo = *(int*)lv;
+ t.hi = t.lo >> 31;
+ fn(&u, t, rv);
+ *(int*)lv = u.lo;
+ break;
+
+ case 10: /* uint */
+ t.lo = *(uint*)lv;
+ t.hi = 0;
+ fn(&u, t, rv);
+ *(uint*)lv = u.lo;
+ break;
+
+ case 5: /* long */
+ t.lo = *(long*)lv;
+ t.hi = t.lo >> 31;
+ fn(&u, t, rv);
+ *(long*)lv = u.lo;
+ break;
+
+ case 6: /* ulong */
+ t.lo = *(ulong*)lv;
+ t.hi = 0;
+ fn(&u, t, rv);
+ *(ulong*)lv = u.lo;
+ break;
+
+ case 7: /* vlong */
+ case 8: /* uvlong */
+ fn(&u, *(Vlong*)lv, rv);
+ *(Vlong*)lv = u;
+ break;
+ }
+ *ret = u;
+}
+
+void
+_p2v(Vlong *ret, void *p)
+{
+ long t;
+
+ t = (ulong)p;
+ ret->lo = t;
+ ret->hi = 0;
+}
+
+void
+_sl2v(Vlong *ret, long sl)
+{
+ long t;
+
+ t = sl;
+ ret->lo = t;
+ ret->hi = t >> 31;
+}
+
+void
+_ul2v(Vlong *ret, ulong ul)
+{
+ long t;
+
+ t = ul;
+ ret->lo = t;
+ ret->hi = 0;
+}
+
+void
+_si2v(Vlong *ret, int si)
+{
+ long t;
+
+ t = si;
+ ret->lo = t;
+ ret->hi = t >> 31;
+}
+
+void
+_ui2v(Vlong *ret, uint ui)
+{
+ long t;
+
+ t = ui;
+ ret->lo = t;
+ ret->hi = 0;
+}
+
+void
+_sh2v(Vlong *ret, long sh)
+{
+ long t;
+
+ t = (sh << 16) >> 16;
+ ret->lo = t;
+ ret->hi = t >> 31;
+}
+
+void
+_uh2v(Vlong *ret, ulong ul)
+{
+ long t;
+
+ t = ul & 0xffff;
+ ret->lo = t;
+ ret->hi = 0;
+}
+
+void
+_sc2v(Vlong *ret, long uc)
+{
+ long t;
+
+ t = (uc << 24) >> 24;
+ ret->lo = t;
+ ret->hi = t >> 31;
+}
+
+void
+_uc2v(Vlong *ret, ulong ul)
+{
+ long t;
+
+ t = ul & 0xff;
+ ret->lo = t;
+ ret->hi = 0;
+}
+
+long
+_v2sc(Vlong rv)
+{
+ long t;
+
+ t = rv.lo & 0xff;
+ return (t << 24) >> 24;
+}
+
+long
+_v2uc(Vlong rv)
+{
+
+ return rv.lo & 0xff;
+}
+
+long
+_v2sh(Vlong rv)
+{
+ long t;
+
+ t = rv.lo & 0xffff;
+ return (t << 16) >> 16;
+}
+
+long
+_v2uh(Vlong rv)
+{
+
+ return rv.lo & 0xffff;
+}
+
+long
+_v2sl(Vlong rv)
+{
+
+ return rv.lo;
+}
+
+long
+_v2ul(Vlong rv)
+{
+
+ return rv.lo;
+}
+
+long
+_v2si(Vlong rv)
+{
+
+ return rv.lo;
+}
+
+long
+_v2ui(Vlong rv)
+{
+
+ return rv.lo;
+}
+
+int
+_testv(Vlong rv)
+{
+ return rv.lo || rv.hi;
+}
+
+int
+_eqv(Vlong lv, Vlong rv)
+{
+ return lv.lo == rv.lo && lv.hi == rv.hi;
+}
+
+int
+_nev(Vlong lv, Vlong rv)
+{
+ return lv.lo != rv.lo || lv.hi != rv.hi;
+}
+
+int
+_ltv(Vlong lv, Vlong rv)
+{
+ return (long)lv.hi < (long)rv.hi ||
+ (lv.hi == rv.hi && lv.lo < rv.lo);
+}
+
+int
+_lev(Vlong lv, Vlong rv)
+{
+ return (long)lv.hi < (long)rv.hi ||
+ (lv.hi == rv.hi && lv.lo <= rv.lo);
+}
+
+int
+_gtv(Vlong lv, Vlong rv)
+{
+ return (long)lv.hi > (long)rv.hi ||
+ (lv.hi == rv.hi && lv.lo > rv.lo);
+}
+
+int
+_gev(Vlong lv, Vlong rv)
+{
+ return (long)lv.hi > (long)rv.hi ||
+ (lv.hi == rv.hi && lv.lo >= rv.lo);
+}
+
+int
+_lov(Vlong lv, Vlong rv)
+{
+ return lv.hi < rv.hi ||
+ (lv.hi == rv.hi && lv.lo < rv.lo);
+}
+
+int
+_lsv(Vlong lv, Vlong rv)
+{
+ return lv.hi < rv.hi ||
+ (lv.hi == rv.hi && lv.lo <= rv.lo);
+}
+
+int
+_hiv(Vlong lv, Vlong rv)
+{
+ return lv.hi > rv.hi ||
+ (lv.hi == rv.hi && lv.lo > rv.lo);
+}
+
+int
+_hsv(Vlong lv, Vlong rv)
+{
+ return lv.hi > rv.hi ||
+ (lv.hi == rv.hi && lv.lo >= rv.lo);
+}
--- /dev/null
+++ b/libkern/vlrt-thumb.c
@@ -1,0 +1,718 @@
+typedef unsigned long ulong;
+typedef unsigned int uint;
+typedef unsigned short ushort;
+typedef unsigned char uchar;
+typedef signed char schar;
+
+#define SIGN(n) (1UL<<(n-1))
+
+typedef struct Vlong Vlong;
+struct Vlong
+{
+ union
+ {
+ struct
+ {
+ ulong hi;
+ ulong lo;
+ };
+ struct
+ {
+ ushort hims;
+ ushort hils;
+ ushort loms;
+ ushort lols;
+ };
+ };
+};
+
+void abort(void);
+
+void
+_addv(Vlong *r, Vlong a, Vlong b)
+{
+ ulong lo, hi;
+
+ lo = a.lo + b.lo;
+ hi = a.hi + b.hi;
+ if(lo < a.lo)
+ hi++;
+ r->lo = lo;
+ r->hi = hi;
+}
+
+void
+_subv(Vlong *r, Vlong a, Vlong b)
+{
+ ulong lo, hi;
+
+ lo = a.lo - b.lo;
+ hi = a.hi - b.hi;
+ if(lo > a.lo)
+ hi--;
+ r->lo = lo;
+ r->hi = hi;
+}
+
+
+void
+_d2v(Vlong *y, double d)
+{
+ union { double d; struct Vlong; } x;
+ ulong xhi, xlo, ylo, yhi;
+ int sh;
+
+ x.d = d;
+
+ xhi = (x.hi & 0xfffff) | 0x100000;
+ xlo = x.lo;
+ sh = 1075 - ((x.hi >> 20) & 0x7ff);
+
+ ylo = 0;
+ yhi = 0;
+ if(sh >= 0) {
+ /* v = (hi||lo) >> sh */
+ if(sh < 32) {
+ if(sh == 0) {
+ ylo = xlo;
+ yhi = xhi;
+ } else {
+ ylo = (xlo >> sh) | (xhi << (32-sh));
+ yhi = xhi >> sh;
+ }
+ } else {
+ if(sh == 32) {
+ ylo = xhi;
+ } else
+ if(sh < 64) {
+ ylo = xhi >> (sh-32);
+ }
+ }
+ } else {
+ /* v = (hi||lo) << -sh */
+ sh = -sh;
+ if(sh <= 10) {
+ ylo = xlo << sh;
+ yhi = (xhi << sh) | (xlo >> (32-sh));
+ } else {
+ /* overflow */
+ yhi = d; /* causes something awful */
+ }
+ }
+ if(x.hi & SIGN(32)) {
+ if(ylo != 0) {
+ ylo = -ylo;
+ yhi = ~yhi;
+ } else
+ yhi = -yhi;
+ }
+
+ y->hi = yhi;
+ y->lo = ylo;
+}
+
+void
+_f2v(Vlong *y, float f)
+{
+ _d2v(y, f);
+}
+
+double
+_v2d(Vlong x)
+{
+ if(x.hi & SIGN(32)) {
+ if(x.lo) {
+ x.lo = -x.lo;
+ x.hi = ~x.hi;
+ } else
+ x.hi = -x.hi;
+ return -((long)x.hi*4294967296. + x.lo);
+ }
+ return (long)x.hi*4294967296. + x.lo;
+}
+
+float
+_v2f(Vlong x)
+{
+ return _v2d(x);
+}
+
+static void
+dodiv(Vlong num, Vlong den, Vlong *q, Vlong *r)
+{
+ ulong numlo, numhi, denhi, denlo, quohi, quolo, t;
+ int i;
+
+ numhi = num.hi;
+ numlo = num.lo;
+ denhi = den.hi;
+ denlo = den.lo;
+
+ /*
+ * get a divide by zero
+ */
+ if(denlo==0 && denhi==0) {
+ numlo = numlo / denlo;
+ }
+
+ /*
+ * set up the divisor and find the number of iterations needed
+ */
+ if(numhi >= SIGN(32)) {
+ quohi = SIGN(32);
+ quolo = 0;
+ } else {
+ quohi = numhi;
+ quolo = numlo;
+ }
+ i = 0;
+ while(denhi < quohi || (denhi == quohi && denlo < quolo)) {
+ denhi = (denhi<<1) | (denlo>>31);
+ denlo <<= 1;
+ i++;
+ }
+
+ quohi = 0;
+ quolo = 0;
+ for(; i >= 0; i--) {
+ quohi = (quohi<<1) | (quolo>>31);
+ quolo <<= 1;
+ if(numhi > denhi || (numhi == denhi && numlo >= denlo)) {
+ t = numlo;
+ numlo -= denlo;
+ if(numlo > t)
+ numhi--;
+ numhi -= denhi;
+ quolo |= 1;
+ }
+ denlo = (denlo>>1) | (denhi<<31);
+ denhi >>= 1;
+ }
+
+ if(q) {
+ q->lo = quolo;
+ q->hi = quohi;
+ }
+ if(r) {
+ r->lo = numlo;
+ r->hi = numhi;
+ }
+}
+
+void
+_divvu(Vlong *q, Vlong n, Vlong d)
+{
+
+ if(n.hi == 0 && d.hi == 0) {
+ q->hi = 0;
+ q->lo = n.lo / d.lo;
+ return;
+ }
+ dodiv(n, d, q, 0);
+}
+
+void
+_modvu(Vlong *r, Vlong n, Vlong d)
+{
+
+ if(n.hi == 0 && d.hi == 0) {
+ r->hi = 0;
+ r->lo = n.lo % d.lo;
+ return;
+ }
+ dodiv(n, d, 0, r);
+}
+
+static void
+vneg(Vlong *v)
+{
+
+ if(v->lo == 0) {
+ v->hi = -v->hi;
+ return;
+ }
+ v->lo = -v->lo;
+ v->hi = ~v->hi;
+}
+
+void
+_divv(Vlong *q, Vlong n, Vlong d)
+{
+ long nneg, dneg;
+
+ if(n.hi == (((long)n.lo)>>31) && d.hi == (((long)d.lo)>>31)) {
+ q->lo = (long)n.lo / (long)d.lo;
+ q->hi = ((long)q->lo) >> 31;
+ return;
+ }
+ nneg = n.hi >> 31;
+ if(nneg)
+ vneg(&n);
+ dneg = d.hi >> 31;
+ if(dneg)
+ vneg(&d);
+ dodiv(n, d, q, 0);
+ if(nneg != dneg)
+ vneg(q);
+}
+
+void
+_modv(Vlong *r, Vlong n, Vlong d)
+{
+ long nneg, dneg;
+
+ if(n.hi == (((long)n.lo)>>31) && d.hi == (((long)d.lo)>>31)) {
+ r->lo = (long)n.lo % (long)d.lo;
+ r->hi = ((long)r->lo) >> 31;
+ return;
+ }
+ nneg = n.hi >> 31;
+ if(nneg)
+ vneg(&n);
+ dneg = d.hi >> 31;
+ if(dneg)
+ vneg(&d);
+ dodiv(n, d, 0, r);
+ if(nneg)
+ vneg(r);
+}
+
+void
+_rshav(Vlong *r, Vlong a, int b)
+{
+ long t;
+
+ t = a.hi;
+ if(b >= 32) {
+ r->hi = t>>31;
+ if(b >= 64) {
+ /* this is illegal re C standard */
+ r->lo = t>>31;
+ return;
+ }
+ r->lo = t >> (b-32);
+ return;
+ }
+ if(b <= 0) {
+ r->hi = t;
+ r->lo = a.lo;
+ return;
+ }
+ r->hi = t >> b;
+ r->lo = (t << (32-b)) | (a.lo >> b);
+}
+
+void
+_rshlv(Vlong *r, Vlong a, int b)
+{
+ ulong t;
+
+ t = a.hi;
+ if(b >= 32) {
+ r->hi = 0;
+ if(b >= 64) {
+ /* this is illegal re C standard */
+ r->lo = 0;
+ return;
+ }
+ r->lo = t >> (b-32);
+ return;
+ }
+ if(b <= 0) {
+ r->hi = t;
+ r->lo = a.lo;
+ return;
+ }
+ r->hi = t >> b;
+ r->lo = (t << (32-b)) | (a.lo >> b);
+}
+
+void
+_lshv(Vlong *r, Vlong a, int b)
+{
+ ulong t;
+
+ t = a.lo;
+ if(b >= 32) {
+ r->lo = 0;
+ if(b >= 64) {
+ /* this is illegal re C standard */
+ r->hi = 0;
+ return;
+ }
+ r->hi = t << (b-32);
+ return;
+ }
+ if(b <= 0) {
+ r->lo = t;
+ r->hi = a.hi;
+ return;
+ }
+ r->lo = t << b;
+ r->hi = (t >> (32-b)) | (a.hi << b);
+}
+
+void
+_andv(Vlong *r, Vlong a, Vlong b)
+{
+ r->hi = a.hi & b.hi;
+ r->lo = a.lo & b.lo;
+}
+
+void
+_orv(Vlong *r, Vlong a, Vlong b)
+{
+ r->hi = a.hi | b.hi;
+ r->lo = a.lo | b.lo;
+}
+
+void
+_xorv(Vlong *r, Vlong a, Vlong b)
+{
+ r->hi = a.hi ^ b.hi;
+ r->lo = a.lo ^ b.lo;
+}
+
+void
+_vpp(Vlong *l, Vlong *r)
+{
+
+ l->hi = r->hi;
+ l->lo = r->lo;
+ r->lo++;
+ if(r->lo == 0)
+ r->hi++;
+}
+
+void
+_vmm(Vlong *l, Vlong *r)
+{
+
+ l->hi = r->hi;
+ l->lo = r->lo;
+ if(r->lo == 0)
+ r->hi--;
+ r->lo--;
+}
+
+void
+_ppv(Vlong *l, Vlong *r)
+{
+
+ r->lo++;
+ if(r->lo == 0)
+ r->hi++;
+ l->hi = r->hi;
+ l->lo = r->lo;
+}
+
+void
+_mmv(Vlong *l, Vlong *r)
+{
+
+ if(r->lo == 0)
+ r->hi--;
+ r->lo--;
+ l->hi = r->hi;
+ l->lo = r->lo;
+}
+
+void
+_vasop(Vlong *ret, void *lv, void fn(Vlong*, Vlong, Vlong), int type, Vlong rv)
+{
+ Vlong t, u;
+
+ u = *ret;
+ switch(type) {
+ default:
+ abort();
+ break;
+
+ case 1: /* schar */
+ t.lo = *(schar*)lv;
+ t.hi = t.lo >> 31;
+ fn(&u, t, rv);
+ *(schar*)lv = u.lo;
+ break;
+
+ case 2: /* uchar */
+ t.lo = *(uchar*)lv;
+ t.hi = 0;
+ fn(&u, t, rv);
+ *(uchar*)lv = u.lo;
+ break;
+
+ case 3: /* short */
+ t.lo = *(short*)lv;
+ t.hi = t.lo >> 31;
+ fn(&u, t, rv);
+ *(short*)lv = u.lo;
+ break;
+
+ case 4: /* ushort */
+ t.lo = *(ushort*)lv;
+ t.hi = 0;
+ fn(&u, t, rv);
+ *(ushort*)lv = u.lo;
+ break;
+
+ case 9: /* int */
+ t.lo = *(int*)lv;
+ t.hi = t.lo >> 31;
+ fn(&u, t, rv);
+ *(int*)lv = u.lo;
+ break;
+
+ case 10: /* uint */
+ t.lo = *(uint*)lv;
+ t.hi = 0;
+ fn(&u, t, rv);
+ *(uint*)lv = u.lo;
+ break;
+
+ case 5: /* long */
+ t.lo = *(long*)lv;
+ t.hi = t.lo >> 31;
+ fn(&u, t, rv);
+ *(long*)lv = u.lo;
+ break;
+
+ case 6: /* ulong */
+ t.lo = *(ulong*)lv;
+ t.hi = 0;
+ fn(&u, t, rv);
+ *(ulong*)lv = u.lo;
+ break;
+
+ case 7: /* vlong */
+ case 8: /* uvlong */
+ fn(&u, *(Vlong*)lv, rv);
+ *(Vlong*)lv = u;
+ break;
+ }
+ *ret = u;
+}
+
+void
+_p2v(Vlong *ret, void *p)
+{
+ long t;
+
+ t = (ulong)p;
+ ret->lo = t;
+ ret->hi = 0;
+}
+
+void
+_sl2v(Vlong *ret, long sl)
+{
+ long t;
+
+ t = sl;
+ ret->lo = t;
+ ret->hi = t >> 31;
+}
+
+void
+_ul2v(Vlong *ret, ulong ul)
+{
+ long t;
+
+ t = ul;
+ ret->lo = t;
+ ret->hi = 0;
+}
+
+void
+_si2v(Vlong *ret, int si)
+{
+ long t;
+
+ t = si;
+ ret->lo = t;
+ ret->hi = t >> 31;
+}
+
+void
+_ui2v(Vlong *ret, uint ui)
+{
+ long t;
+
+ t = ui;
+ ret->lo = t;
+ ret->hi = 0;
+}
+
+void
+_sh2v(Vlong *ret, long sh)
+{
+ long t;
+
+ t = (sh << 16) >> 16;
+ ret->lo = t;
+ ret->hi = t >> 31;
+}
+
+void
+_uh2v(Vlong *ret, ulong ul)
+{
+ long t;
+
+ t = ul & 0xffff;
+ ret->lo = t;
+ ret->hi = 0;
+}
+
+void
+_sc2v(Vlong *ret, long uc)
+{
+ long t;
+
+ t = (uc << 24) >> 24;
+ ret->lo = t;
+ ret->hi = t >> 31;
+}
+
+void
+_uc2v(Vlong *ret, ulong ul)
+{
+ long t;
+
+ t = ul & 0xff;
+ ret->lo = t;
+ ret->hi = 0;
+}
+
+long
+_v2sc(Vlong rv)
+{
+ long t;
+
+ t = rv.lo & 0xff;
+ return (t << 24) >> 24;
+}
+
+long
+_v2uc(Vlong rv)
+{
+
+ return rv.lo & 0xff;
+}
+
+long
+_v2sh(Vlong rv)
+{
+ long t;
+
+ t = rv.lo & 0xffff;
+ return (t << 16) >> 16;
+}
+
+long
+_v2uh(Vlong rv)
+{
+
+ return rv.lo & 0xffff;
+}
+
+long
+_v2sl(Vlong rv)
+{
+
+ return rv.lo;
+}
+
+long
+_v2ul(Vlong rv)
+{
+
+ return rv.lo;
+}
+
+long
+_v2si(Vlong rv)
+{
+
+ return rv.lo;
+}
+
+long
+_v2ui(Vlong rv)
+{
+
+ return rv.lo;
+}
+
+int
+_testv(Vlong rv)
+{
+ return rv.lo || rv.hi;
+}
+
+int
+_eqv(Vlong lv, Vlong rv)
+{
+ return lv.lo == rv.lo && lv.hi == rv.hi;
+}
+
+int
+_nev(Vlong lv, Vlong rv)
+{
+ return lv.lo != rv.lo || lv.hi != rv.hi;
+}
+
+int
+_ltv(Vlong lv, Vlong rv)
+{
+ return (long)lv.hi < (long)rv.hi ||
+ (lv.hi == rv.hi && lv.lo < rv.lo);
+}
+
+int
+_lev(Vlong lv, Vlong rv)
+{
+ return (long)lv.hi < (long)rv.hi ||
+ (lv.hi == rv.hi && lv.lo <= rv.lo);
+}
+
+int
+_gtv(Vlong lv, Vlong rv)
+{
+ return (long)lv.hi > (long)rv.hi ||
+ (lv.hi == rv.hi && lv.lo > rv.lo);
+}
+
+int
+_gev(Vlong lv, Vlong rv)
+{
+ return (long)lv.hi > (long)rv.hi ||
+ (lv.hi == rv.hi && lv.lo >= rv.lo);
+}
+
+int
+_lov(Vlong lv, Vlong rv)
+{
+ return lv.hi < rv.hi ||
+ (lv.hi == rv.hi && lv.lo < rv.lo);
+}
+
+int
+_lsv(Vlong lv, Vlong rv)
+{
+ return lv.hi < rv.hi ||
+ (lv.hi == rv.hi && lv.lo <= rv.lo);
+}
+
+int
+_hiv(Vlong lv, Vlong rv)
+{
+ return lv.hi > rv.hi ||
+ (lv.hi == rv.hi && lv.lo > rv.lo);
+}
+
+int
+_hsv(Vlong lv, Vlong rv)
+{
+ return lv.hi > rv.hi ||
+ (lv.hi == rv.hi && lv.lo >= rv.lo);
+}
--- /dev/null
+++ b/libkern/vseprint.c
@@ -1,0 +1,37 @@
+/*
+ * 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 "lib9.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 = nil;
+ f.farg = nil;
+ f.nfmt = 0;
+ va_copy(f.args, args);
+ dofmt(&f, fmt);
+ va_end(f.args);
+ *(char*)f.to = '\0';
+ return f.to;
+}
+
--- /dev/null
+++ b/libkern/vsmprint.c
@@ -1,0 +1,79 @@
+/*
+ * 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 "lib9.h"
+#include "fmtdef.h"
+
+static int
+fmtStrFlush(Fmt *f)
+{
+ char *s;
+ int n;
+
+ if(f->start == nil)
+ return 0;
+ n = (int)f->farg;
+ n += 256;
+ f->farg = (void*)n;
+ s = f->start;
+ f->start = realloc(s, n);
+ if(f->start == nil){
+ free(s);
+ f->to = nil;
+ f->stop = nil;
+ return 0;
+ }
+ f->to = (char*)f->start + ((char*)f->to - s);
+ f->stop = (char*)f->start + n - 1;
+ return 1;
+}
+
+int
+fmtstrinit(Fmt *f)
+{
+ int n;
+
+ memset(f, 0, sizeof(*f));
+ 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);
+ f.start = nil;
+ return nil;
+ }
+ return fmtstrflush(&f);
+}
--- /dev/null
+++ b/libkern/vsnprint.c
@@ -1,0 +1,36 @@
+/*
+ * 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 "lib9.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 = nil;
+ 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;
+}
--- /dev/null
+++ b/libkeyring/NOTICE
@@ -1,0 +1,25 @@
+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 © 1995-1999 Lucent Technologies Inc.
+Portions Copyright © 1997-2000 Vita Nuova Limited
+Portions Copyright © 2000-2007 Vita Nuova Holdings Limited
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU Lesser General Public License (`LGPL') as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
--- /dev/null
+++ b/libkeyring/dsaalg.c
@@ -1,0 +1,216 @@
+#include <lib9.h>
+#include <kernel.h>
+#include <isa.h>
+#include "interp.h"
+#include "../libinterp/keyringif.h"
+#include "mp.h"
+#include "libsec.h"
+#include "keys.h"
+
+static char* pkattr[] = { "p", "q", "alpha", "key", nil };
+static char* skattr[] = { "p", "q", "alpha", "key", "!secret", nil };
+static char* sigattr[] = { "r", "s", nil };
+
+static void*
+dsa_str2sk(char *str, char **strp)
+{
+ DSApriv *dsa;
+ char *p;
+
+ dsa = dsaprivalloc();
+ dsa->pub.p = base64tobig(str, &p);
+ dsa->pub.q = base64tobig(str, &p);
+ dsa->pub.alpha = base64tobig(p, &p);
+ dsa->pub.key = base64tobig(p, &p);
+ dsa->secret = base64tobig(p, &p);
+ if(strp)
+ *strp = p;
+ if(dsa->pub.p == nil || dsa->pub.q == nil ||
+ dsa->pub.alpha == nil || dsa->pub.key == nil || dsa->secret == nil){
+ dsaprivfree(dsa);
+ return nil;
+ }
+ return dsa;
+}
+
+static void*
+dsa_str2pk(char *str, char **strp)
+{
+ DSApub *dsa;
+ char *p;
+
+ dsa = dsapuballoc();
+ dsa->p = base64tobig(str, &p);
+ dsa->q = base64tobig(str, &p);
+ dsa->alpha = base64tobig(p, &p);
+ dsa->key = base64tobig(p, &p);
+ if(strp)
+ *strp = p;
+ if(dsa->p == nil || dsa->q == nil || dsa->alpha == nil || dsa->key == nil){
+ dsapubfree(dsa);
+ return nil;
+ }
+ return dsa;
+}
+
+static void*
+dsa_str2sig(char *str, char **strp)
+{
+ DSAsig *dsa;
+ char *p;
+
+ dsa = dsasigalloc();
+ dsa->r = base64tobig(str, &p);
+ dsa->s = base64tobig(p, &p);
+ if(strp)
+ *strp = p;
+ if(dsa->r == nil || dsa->s == nil){
+ dsasigfree(dsa);
+ return nil;
+ }
+ return dsa;
+}
+
+static int
+dsa_sk2str(void *veg, char *buf, int len)
+{
+ DSApriv *dsa;
+ char *cp, *ep;
+
+ dsa = veg;
+ ep = buf + len - 1;
+ cp = buf;
+
+ cp += snprint(cp, ep - cp, "%U\n", dsa->pub.p);
+ cp += snprint(cp, ep - cp, "%U\n", dsa->pub.q);
+ cp += snprint(cp, ep - cp, "%U\n", dsa->pub.alpha);
+ cp += snprint(cp, ep - cp, "%U\n", dsa->pub.key);
+ cp += snprint(cp, ep - cp, "%U\n", dsa->secret);
+ *cp = 0;
+
+ return cp - buf;
+}
+
+static int
+dsa_pk2str(void *veg, char *buf, int len)
+{
+ DSApub *dsa;
+ char *cp, *ep;
+
+ dsa = veg;
+ ep = buf + len - 1;
+ cp = buf;
+
+ cp += snprint(cp, ep - cp, "%U\n", dsa->p);
+ cp += snprint(cp, ep - cp, "%U\n", dsa->q);
+ cp += snprint(cp, ep - cp, "%U\n", dsa->alpha);
+ cp += snprint(cp, ep - cp, "%U\n", dsa->key);
+ *cp = 0;
+
+ return cp - buf;
+}
+
+static int
+dsa_sig2str(void *veg, char *buf, int len)
+{
+ DSAsig *dsa;
+ char *cp, *ep;
+
+ dsa = veg;
+ ep = buf + len - 1;
+ cp = buf;
+
+ cp += snprint(cp, ep - cp, "%U\n", dsa->r);
+ cp += snprint(cp, ep - cp, "%U\n", dsa->s);
+ *cp = 0;
+
+ return cp - buf;
+}
+
+static void*
+dsa_sk2pk(void *vs)
+{
+ return dsaprivtopub((DSApriv*)vs);
+}
+
+/* generate a dsa secret key with new params */
+static void*
+dsa_gen(int len)
+{
+ USED(len);
+ return dsagen(nil);
+}
+
+/* generate a dsa secret key with same params as a public key */
+static void*
+dsa_genfrompk(void *vpub)
+{
+ return dsagen((DSApub*)vpub);
+}
+
+static void
+dsa_freepub(void *a)
+{
+ dsapubfree((DSApub*)a);
+}
+
+static void
+dsa_freepriv(void *a)
+{
+ dsaprivfree((DSApriv*)a);
+}
+
+static void
+dsa_freesig(void *a)
+{
+ dsasigfree((DSAsig*)a);
+}
+
+static void*
+dsa_sign(mpint* md, void *key)
+{
+ return dsasign((DSApriv*)key, md);
+}
+
+static int
+dsa_verify(mpint* md, void *sig, void *key)
+{
+ return dsaverify((DSApub*)key, (DSAsig*)sig, md) == 0;
+}
+
+SigAlgVec*
+dsainit(void)
+{
+ SigAlgVec *vec;
+
+ vec = malloc(sizeof(SigAlgVec));
+ if(vec == nil)
+ return nil;
+
+ vec->name = "dsa";
+
+ vec->pkattr = pkattr;
+ vec->skattr = skattr;
+ vec->sigattr = sigattr;
+
+ vec->str2sk = dsa_str2sk;
+ vec->str2pk = dsa_str2pk;
+ vec->str2sig = dsa_str2sig;
+
+ vec->sk2str = dsa_sk2str;
+ vec->pk2str = dsa_pk2str;
+ vec->sig2str = dsa_sig2str;
+
+ vec->sk2pk = dsa_sk2pk;
+
+ vec->gensk = dsa_gen;
+ vec->genskfrompk = dsa_genfrompk;
+ vec->sign = dsa_sign;
+ vec->verify = dsa_verify;
+
+ vec->skfree = dsa_freepriv;
+ vec->pkfree = dsa_freepub;
+ vec->sigfree = dsa_freesig;
+
+ return vec;
+}
--- /dev/null
+++ b/libkeyring/egalg.c
@@ -1,0 +1,224 @@
+#include <lib9.h>
+#include <kernel.h>
+#include <isa.h>
+#include "interp.h"
+#include "../libinterp/keyringif.h"
+#include "mp.h"
+#include "libsec.h"
+#include "keys.h"
+
+static char* pkattr[] = { "p", "alpha", "key", nil };
+static char* skattr[] = { "p", "alpha", "key", "!secret", nil };
+static char* sigattr[] = { "r", "s", nil };
+
+static void*
+eg_str2sk(char *str, char **strp)
+{
+ EGpriv *eg;
+ char *p;
+
+ eg = egprivalloc();
+ eg->pub.p = base64tobig(str, &p);
+ eg->pub.alpha = base64tobig(p, &p);
+ eg->pub.key = base64tobig(p, &p);
+ eg->secret = base64tobig(p, &p);
+ if(strp)
+ *strp = p;
+ if(eg->pub.p == nil || eg->pub.alpha == nil || eg->pub.key == nil || eg->secret == nil){
+ egprivfree(eg);
+ return nil;
+ }
+ return eg;
+}
+
+static void*
+eg_str2pk(char *str, char **strp)
+{
+ EGpub *eg;
+ char *p;
+
+ eg = egpuballoc();
+ eg->p = base64tobig(str, &p);
+ eg->alpha = base64tobig(p, &p);
+ eg->key = base64tobig(p, &p);
+ if(strp)
+ *strp = p;
+ if(eg->p == nil || eg->alpha == nil || eg->key == nil){
+ egpubfree(eg);
+ return nil;
+ }
+ return eg;
+}
+
+static void*
+eg_str2sig(char *str, char **strp)
+{
+ EGsig *eg;
+ char *p;
+
+ eg = egsigalloc();
+ eg->r = base64tobig(str, &p);
+ eg->s = base64tobig(p, &p);
+ if(strp)
+ *strp = p;
+ if(eg->r == nil || eg->s == nil){
+ egsigfree(eg);
+ return nil;
+ }
+ return eg;
+}
+
+static int
+eg_sk2str(void *veg, char *buf, int len)
+{
+ EGpriv *eg;
+ char *cp, *ep;
+
+ eg = (EGpriv*)veg;
+ ep = buf + len - 1;
+ cp = buf;
+
+ cp += snprint(cp, ep - cp, "%U\n", eg->pub.p);
+ cp += snprint(cp, ep - cp, "%U\n", eg->pub.alpha);
+ cp += snprint(cp, ep - cp, "%U\n", eg->pub.key);
+ cp += snprint(cp, ep - cp, "%U\n", eg->secret);
+ *cp = 0;
+
+ return cp - buf;
+}
+
+static int
+eg_pk2str(void *veg, char *buf, int len)
+{
+ EGpub *eg;
+ char *cp, *ep;
+
+ eg = (EGpub*)veg;
+ ep = buf + len - 1;
+ cp = buf;
+
+ cp += snprint(cp, ep - cp, "%U\n", eg->p);
+ cp += snprint(cp, ep - cp, "%U\n", eg->alpha);
+ cp += snprint(cp, ep - cp, "%U\n", eg->key);
+ *cp = 0;
+
+ return cp - buf;
+}
+
+static int
+eg_sig2str(void *veg, char *buf, int len)
+{
+ EGsig *eg;
+ char *cp, *ep;
+
+ eg = veg;
+ ep = buf + len - 1;
+ cp = buf;
+
+ cp += snprint(cp, ep - cp, "%U\n", eg->r);
+ cp += snprint(cp, ep - cp, "%U\n", eg->s);
+ *cp = 0;
+
+ return cp - buf;
+}
+
+static void*
+eg_sk2pk(void *vs)
+{
+ return egprivtopub((EGpriv*)vs);
+}
+
+/* generate an el gamal secret key with new params */
+static void*
+eg_gen(int len)
+{
+ return eggen(len, 0);
+}
+
+/* generate an el gamal secret key with same params as a public key */
+static void*
+eg_genfrompk(void *vpub)
+{
+ EGpub *pub;
+ EGpriv *priv;
+ int nlen;
+
+ pub = vpub;
+ priv = egprivalloc();
+ priv->pub.p = mpcopy(pub->p);
+ priv->pub.alpha = mpcopy(pub->alpha);
+ nlen = mpsignif(pub->p);
+ pub = &priv->pub;
+ pub->key = mpnew(0);
+ priv->secret = mpnew(0);
+ mprand(nlen-1, genrandom, priv->secret);
+ mpexp(pub->alpha, priv->secret, pub->p, pub->key);
+ return priv;
+}
+
+static void*
+eg_sign(mpint* mp, void *key)
+{
+ return egsign((EGpriv*)key, mp);
+}
+
+static int
+eg_verify(mpint* mp, void *sig, void *key)
+{
+ return egverify((EGpub*)key, (EGsig*)sig, mp) == 0;
+}
+
+static void
+eg_freepub(void *a)
+{
+ egpubfree((EGpub*)a);
+}
+
+static void
+eg_freepriv(void *a)
+{
+ egprivfree((EGpriv*)a);
+}
+
+static void
+eg_freesig(void *a)
+{
+ egsigfree((EGsig*)a);
+}
+
+SigAlgVec*
+elgamalinit(void)
+{
+ SigAlgVec *vec;
+
+ vec = malloc(sizeof(SigAlgVec));
+ if(vec == nil)
+ return nil;
+
+ vec->name = "elgamal";
+
+ vec->pkattr = pkattr;
+ vec->skattr = skattr;
+ vec->sigattr = sigattr;
+
+ vec->str2sk = eg_str2sk;
+ vec->str2pk = eg_str2pk;
+ vec->str2sig = eg_str2sig;
+
+ vec->sk2str = eg_sk2str;
+ vec->pk2str = eg_pk2str;
+ vec->sig2str = eg_sig2str;
+
+ vec->sk2pk = eg_sk2pk;
+
+ vec->gensk = eg_gen;
+ vec->genskfrompk = eg_genfrompk;
+ vec->sign = eg_sign;
+ vec->verify = eg_verify;
+
+ vec->skfree = eg_freepriv;
+ vec->pkfree = eg_freepub;
+ vec->sigfree = eg_freesig;
+
+ return vec;
+}
--- /dev/null
+++ b/libkeyring/keys.h
@@ -1,0 +1,111 @@
+typedef struct SigAlg SigAlg;
+typedef struct SigAlgVec SigAlgVec;
+typedef struct SK SK;
+typedef struct PK PK;
+typedef struct Certificate Certificate;
+typedef struct XDigestState XDigestState;
+typedef struct XAESstate XAESstate;
+typedef struct XDESstate XDESstate;
+typedef struct XIDEAstate XIDEAstate;
+typedef struct XRC4state XRC4state;
+
+enum
+{
+ Maxbuf= 4096,
+ MaxBigBytes = 1024
+};
+
+/* generic certificate */
+struct Certificate
+{
+ Keyring_Certificate x;
+ void *signa; /* actual signature */
+};
+
+/* generic public key */
+struct PK
+{
+ Keyring_PK x;
+ void *key; /* key and system parameters */
+};
+
+/* digest state */
+struct XDigestState
+{
+ Keyring_DigestState x;
+ DigestState state;
+};
+
+/* AES state */
+struct XAESstate
+{
+ Keyring_AESstate x;
+ AESstate state;
+};
+
+/* DES state */
+struct XDESstate
+{
+ Keyring_DESstate x;
+ DESstate state;
+};
+
+/* IDEA state */
+struct XIDEAstate
+{
+ Keyring_IDEAstate x;
+ IDEAstate state;
+};
+
+/* RC4 state */
+struct XRC4state
+{
+ Keyring_RC4state x;
+ RC4state state;
+};
+
+/* generic secret key */
+struct SK
+{
+ Keyring_SK x;
+ void *key; /* key and system parameters */
+};
+
+struct SigAlgVec {
+ char *name;
+
+ char** skattr;
+ char** pkattr;
+ char** sigattr;
+
+ void* (*str2sk)(char*, char**);
+ void* (*str2pk)(char*, char**);
+ void* (*str2sig)(char*, char**);
+
+ int (*sk2str)(void*, char*, int);
+ int (*pk2str)(void*, char*, int);
+ int (*sig2str)(void*, char*, int);
+
+ void* (*sk2pk)(void*);
+
+ void* (*gensk)(int);
+ void* (*genskfrompk)(void*);
+ void* (*sign)(mpint*, void*);
+ int (*verify)(mpint*, void*, void*);
+
+ void (*skfree)(void*);
+ void (*pkfree)(void*);
+ void (*sigfree)(void*);
+};
+
+struct SigAlg
+{
+ Keyring_SigAlg x;
+ SigAlgVec *vec;
+};
+
+int bigtobase64(mpint* b, char *buf, int blen);
+mpint* base64tobig(char *str, char **strp);
+SigAlgVec* findsigalg(char*);
+//Keyring_IPint* newIPint(mpint*);
+void* newIPint(mpint*);
--- /dev/null
+++ b/libkeyring/mkfile
@@ -1,0 +1,17 @@
+<../mkconfig
+
+LIB=libkeyring.a
+
+OFILES=\
+ dsaalg.$O\
+ egalg.$O\
+ rsaalg.$O
+
+HFILES=\
+ $ROOT/include/mp.h\
+ $ROOT/include/libsec.h\
+ $ROOT/libinterp/runt.h\
+ $ROOT/include/interp.h\
+ keys.h\
+
+<$ROOT/mkfiles/mksyslib-$SHELLTYPE
--- /dev/null
+++ b/libkeyring/rsaalg.c
@@ -1,0 +1,230 @@
+#include <lib9.h>
+#include <kernel.h>
+#include <isa.h>
+#include "interp.h"
+#include "../libinterp/keyringif.h"
+#include "mp.h"
+#include "libsec.h"
+#include "keys.h"
+
+static char* pkattr[] = { "n", "ek", nil };
+static char* skattr[] = { "n", "ek", "!dk", "!p", "!q", "!kp", "!kq", "!c2", nil };
+static char* sigattr[] = { "val", nil };
+
+static void*
+rsa_str2sk(char *str, char **strp)
+{
+ RSApriv *rsa;
+ char *p;
+
+ rsa = rsaprivalloc();
+ rsa->pub.n = base64tobig(str, &p);
+ rsa->pub.ek = base64tobig(p, &p);
+ rsa->dk = base64tobig(p, &p);
+ rsa->p = base64tobig(p, &p);
+ rsa->q = base64tobig(p, &p);
+ rsa->kp = base64tobig(p, &p);
+ rsa->kq = base64tobig(p, &p);
+ rsa->c2 = base64tobig(p, &p);
+ if(strp)
+ *strp = p;
+ if(rsa->pub.n == nil || rsa->pub.ek == nil ||
+ rsa->dk == nil || rsa->p == nil || rsa->q == nil ||
+ rsa->kp == nil || rsa->kq == nil || rsa->c2 == nil){
+ rsaprivfree(rsa);
+ return nil;
+ }
+
+ return rsa;
+}
+
+static void*
+rsa_str2pk(char *str, char **strp)
+{
+ RSApub *rsa;
+ char *p;
+
+ rsa = rsapuballoc();
+ rsa->n = base64tobig(str, &p);
+ rsa->ek = base64tobig(p, &p);
+ if(strp)
+ *strp = p;
+ if(rsa->n == nil || rsa->ek == nil){
+ rsapubfree(rsa);
+ return nil;
+ }
+
+ return rsa;
+}
+
+static void*
+rsa_str2sig(char *str, char **strp)
+{
+ mpint *rsa;
+ char *p;
+
+ rsa = base64tobig(str, &p);
+ if(rsa == nil)
+ return nil;
+ if(strp)
+ *strp = p;
+ return rsa;
+}
+
+static int
+rsa_sk2str(void *vrsa, char *buf, int len)
+{
+ RSApriv *rsa;
+ char *cp, *ep;
+
+ rsa = vrsa;
+ ep = buf + len - 1;
+ cp = buf;
+
+ cp += snprint(cp, ep - cp, "%U\n", rsa->pub.n);
+ cp += snprint(cp, ep - cp, "%U\n", rsa->pub.ek);
+ cp += snprint(cp, ep - cp, "%U\n", rsa->dk);
+ cp += snprint(cp, ep - cp, "%U\n", rsa->p);
+ cp += snprint(cp, ep - cp, "%U\n", rsa->q);
+ cp += snprint(cp, ep - cp, "%U\n", rsa->kp);
+ cp += snprint(cp, ep - cp, "%U\n", rsa->kq);
+ cp += snprint(cp, ep - cp, "%U\n", rsa->c2);
+ *cp = 0;
+
+ return cp - buf;
+}
+
+static int
+rsa_pk2str(void *vrsa, char *buf, int len)
+{
+ RSApub *rsa;
+ char *cp, *ep;
+
+ rsa = vrsa;
+ ep = buf + len - 1;
+ cp = buf;
+ cp += snprint(cp, ep - cp, "%U\n", rsa->n);
+ cp += snprint(cp, ep - cp, "%U\n", rsa->ek);
+ *cp = 0;
+
+ return cp - buf;
+}
+
+static int
+rsa_sig2str(void *vrsa, char *buf, int len)
+{
+ mpint *rsa;
+ char *cp, *ep;
+
+ rsa = vrsa;
+ ep = buf + len - 1;
+ cp = buf;
+
+ cp += snprint(cp, ep - cp, "%U\n", rsa);
+ *cp = 0;
+
+ return cp - buf;
+}
+
+static void*
+rsa_sk2pk(void *vs)
+{
+ return rsaprivtopub((RSApriv*)vs);
+}
+
+/* generate an rsa secret key */
+static void*
+rsa_gen(int len)
+{
+ RSApriv *key;
+
+ for(;;){
+ key = rsagen(len, 6, 0);
+ if(mpsignif(key->pub.n) == len)
+ return key;
+ rsaprivfree(key);
+ }
+}
+
+/* generate an rsa secret key with same params as a public key */
+static void*
+rsa_genfrompk(void *vpub)
+{
+ RSApub *pub;
+
+ pub = vpub;
+ return rsagen(mpsignif(pub->n), mpsignif(pub->ek), 0);
+}
+
+static void*
+rsa_sign(mpint* m, void *key)
+{
+ return rsadecrypt((RSApriv*)key, m, nil);
+}
+
+static int
+rsa_verify(mpint* m, void *sig, void *key)
+{
+ mpint *t;
+ int r;
+
+ t = rsaencrypt((RSApub*)key, (mpint*)sig, nil);
+ r = mpcmp(t, m) == 0;
+ mpfree(t);
+ return r;
+}
+
+static void
+rsa_freepriv(void *a)
+{
+ rsaprivfree((RSApriv*)a);
+}
+
+static void
+rsa_freepub(void *a)
+{
+ rsapubfree((RSApub*)a);
+}
+
+static void
+rsa_freesig(void *a)
+{
+ mpfree(a);
+}
+
+SigAlgVec*
+rsainit(void)
+{
+ SigAlgVec *vec;
+
+ vec = malloc(sizeof(SigAlgVec));
+ if(vec == nil)
+ return nil;
+
+ vec->name = "rsa";
+
+ vec->pkattr = pkattr;
+ vec->skattr = skattr;
+ vec->sigattr = sigattr;
+
+ vec->str2sk = rsa_str2sk;
+ vec->str2pk = rsa_str2pk;
+ vec->str2sig = rsa_str2sig;
+
+ vec->sk2str = rsa_sk2str;
+ vec->pk2str = rsa_pk2str;
+ vec->sig2str = rsa_sig2str;
+
+ vec->sk2pk = rsa_sk2pk;
+
+ vec->gensk = rsa_gen;
+ vec->genskfrompk = rsa_genfrompk;
+ vec->sign = rsa_sign;
+ vec->verify = rsa_verify;
+
+ vec->skfree = rsa_freepriv;
+ vec->pkfree = rsa_freepub;
+ vec->sigfree = rsa_freesig;
+
+ return vec;
+}
--- /dev/null
+++ b/liblogfs/NOTICE
@@ -1,0 +1,23 @@
+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 © 2002, 2003 Vita Nuova Holdings Limited.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
--- /dev/null
+++ b/liblogfs/boot.c
@@ -1,0 +1,496 @@
+#include "logfsos.h"
+#include "logfs.h"
+#include "local.h"
+
+struct LogfsBoot {
+ LogfsLowLevel *ll;
+ long bootblocks;
+ long blocksize;
+ long size;
+ long *map;
+ int trace;
+ int printbad;
+// ulong bootpathmask;
+// int bootgenshift;
+};
+
+typedef struct LogfsBootPath LogfsBootPath;
+
+//#define LogfsBootGenBits 2
+//#define LogfsBootGenMask ((1 << LogfsBootGenBits) - 1)
+#define LogfsBootGenMask ((1 << L2BlockCopies) - 1)
+
+struct LogfsBootPath {
+ ulong path;
+ uchar gen;
+};
+
+#define LOGFSMKBOOTPATH(lb, p) mkdatapath((p)->path, (p)->gen)
+#define LOGFSSPLITBOOTPATHEX(bgs, bpm, p, v) ((p)->path = dataseqof(v), (p)->gen = copygenof(v))
+#define LOGFSSPLITBOOTPATH(lb, p, v) LOGFSSPLITBOOTPATHEX(0, 0, p, v)
+
+//#define LOGFSMKBOOTPATH(lb, p) (((p)->path & (lb)->bootpathmask) | (((p)->gen & LogfsBootGenMask) << (lb)->bootgenshift))
+//#define LOGFSSPLITBOOTPATHEX(bgs, bpm, p, v) ((p)->path = (v) & (bpm), (p)->gen = ((v) >> (bgs)) & LogfsBootGenMask)
+//#define LOGFSSPLITBOOTPATH(lb, p, v) LOGFSSPLITBOOTPATHEX((lb)->bootgenshift, (lb)->bootpathmask, p, v)
+
+extern LogfsBootPath logfsbooterasedpath;
+
+static char Ecorrupt[] = "filesystem corrupt";
+static char Enospc[] = "no free blocks";
+static char Eaddress[] = "address out of range";
+
+static char *
+logfsbootblockupdate(LogfsBoot *lb, void *buf, LogfsBootPath *path, uchar tag, ulong block)
+{
+ LogfsLowLevel *ll = lb->ll;
+ char *errmsg;
+ ulong packedpath;
+
+ if(lb->trace > 1)
+ print("logfsbootblockupdate: path 0x%.8lux(%d) tag %s block %lud\n",
+ path->path, path->gen, logfstagname(tag), block);
+
+ packedpath = LOGFSMKBOOTPATH(lb, path);
+ errmsg = (*ll->writeblock)(ll, buf, tag, packedpath, 1, &lb->bootblocks, block);
+
+ if(errmsg) {
+ /*
+ * ensure block never used again until file system reinitialised
+ * We have absolutely no idea what state it's in. This is most
+ * likely if someone turns off the power (or at least threatens
+ * the power supply), during a block update. This way the block
+ * is protected until the file system in reinitialised. An alternative
+ * would be check the file system after a power fail false alarm,
+ * and erase any Tworse blocks
+ */
+ (*ll->setblocktag)(ll, block, LogfsTworse);
+ return errmsg;
+ }
+
+ (*ll->setblocktag)(ll, block, tag);
+ (*ll->setblockpath)(ll, block, packedpath);
+
+ return nil;
+}
+
+char *
+logfsbootfettleblock(LogfsBoot *lb, long block, uchar tag, long path, int *markedbad)
+{
+ LogfsLowLevel *ll = lb->ll;
+ char *errmsg;
+ void *llsave;
+
+ errmsg = (*ll->eraseblock)(ll, block, &llsave, markedbad);
+ if(errmsg || (markedbad && *markedbad)) {
+ logfsfreemem(llsave);
+ return errmsg;
+ }
+ errmsg = (*ll->reformatblock)(ll, block, tag, path, 1, &lb->bootblocks, llsave, markedbad);
+ logfsfreemem(llsave);
+ return errmsg;
+}
+
+/*
+ * block transfer is the critical unit of update
+ * we are going to assume that page writes and block erases are atomic
+ * this can pretty much be assured by not starting a page write or block erase
+ * if the device feels it is in power fail
+ */
+
+static char *
+logfsbootblocktransfer(LogfsBoot *lb, void *buf, ulong oldblock, int markbad)
+{
+ LogfsLowLevel *ll = lb->ll;
+ long bestnewblock;
+ ulong oldpackedpath;
+ LogfsBootPath oldpath;
+ short oldtag;
+ char *errmsg;
+ int markedbad;
+
+ oldpackedpath = (*ll->getblockpath)(ll, oldblock);
+ oldtag = (*ll->getblocktag)(ll, oldblock);
+
+ LOGFSSPLITBOOTPATH(lb, &oldpath, oldpackedpath);
+
+ for(;;) {
+ LogfsBootPath newpath;
+
+ bestnewblock = logfsfindfreeblock(ll, markbad ? AllocReasonReplace : AllocReasonTransfer);
+ if(lb->trace > 0 && markbad)
+ print("logfsbootblocktransfer: block %lud is bad, copying to %ld\n",
+ oldblock, bestnewblock);
+ if(lb->trace > 1 && !markbad)
+ print("logfsbootblocktransfer: copying block %lud to %ld\n",
+ oldblock, bestnewblock);
+ if(bestnewblock == -1)
+ return Enospc;
+ newpath = oldpath;
+// newpath.gen = (newpath.gen + 1) & LogfsBootGenMask;
+ newpath.gen = copygensucc(newpath.gen);
+ errmsg = logfsbootblockupdate(lb, buf, &newpath, oldtag, bestnewblock);
+ if(errmsg == nil)
+ break;
+ if(strcmp(errmsg, Eio) != 0)
+ return errmsg;
+ (*ll->markblockbad)(ll, bestnewblock);
+ }
+
+#ifdef LOGFSTEST
+ if(logfstest.partialupdate) {
+ print("skipping erase\n");
+ logfstest.partialupdate = 0;
+ return nil;
+ }
+ if(logfstest.updatenoerase) {
+ print("skipping erase\n");
+ logfstest.updatenoerase = 0;
+ return nil;
+ }
+#endif
+
+ if(oldtag == LogfsTboot)
+ lb->map[oldpath.path] = bestnewblock;
+
+ return logfsbootfettleblock(lb, oldblock, LogfsTnone, ~0, &markedbad);
+}
+
+static char *
+logfsbootblockread(LogfsBoot *lb, void *buf, long block, LogfsLowLevelReadResult *blocke)
+{
+ LogfsLowLevel *ll = lb->ll;
+ char *errmsg;
+
+ *blocke = LogfsLowLevelReadResultOk;
+ errmsg = (*ll->readblock)(ll, buf, block, blocke);
+ if(errmsg)
+ return errmsg;
+
+ if(*blocke != LogfsLowLevelReadResultOk) {
+ char *errmsg = logfsbootblocktransfer(lb, buf, block, 1);
+ if(errmsg)
+ return errmsg;
+ }
+
+ if(*blocke == LogfsLowLevelReadResultHardError)
+ return Eio;
+
+ return nil;
+}
+
+char *
+logfsbootread(LogfsBoot *lb, void *buf, long n, ulong offset)
+{
+ int i;
+
+ if(lb->trace > 0)
+ print("logfsbootread(0x%.8lux, 0x%lx, 0x%lux)\n", (ulong)buf, n, offset);
+ if(offset % lb->blocksize || n % lb->blocksize)
+ return Eio;
+ n /= lb->blocksize;
+ offset /= lb->blocksize;
+ if(offset + n > lb->bootblocks)
+ return Eio;
+ for(i = 0; i < n; i++) {
+ LogfsLowLevelReadResult result;
+ char *errmsg = logfsbootblockread(lb, buf, lb->map[offset + i], &result);
+ if(errmsg)
+ return errmsg;
+ buf = (uchar *)buf + lb->blocksize;
+ }
+ return nil;
+}
+
+static char *
+logfsbootblockreplace(LogfsBoot *lb, void *buf, ulong logicalblock)
+{
+ uchar *oldblockbuf;
+ ulong oldblock;
+ char *errmsg;
+ LogfsLowLevelReadResult result;
+
+ oldblock = lb->map[logicalblock];
+ oldblockbuf = logfsrealloc(nil, lb->blocksize);
+ if(oldblockbuf == nil)
+ return Enomem;
+
+ errmsg = logfsbootblockread(lb, oldblockbuf, oldblock, &result);
+ if(errmsg == nil && memcmp(oldblockbuf, buf, lb->blocksize) != 0)
+ errmsg = logfsbootblocktransfer(lb, buf, oldblock, 0);
+
+ logfsfreemem(oldblockbuf);
+ return errmsg;
+}
+
+char *
+logfsbootwrite(LogfsBoot *lb, void *buf, long n, ulong offset)
+{
+ int i;
+
+ if(lb->trace > 0)
+ print("logfsbootwrite(0x%.8lux, 0x%lux, 0x%lux)\n", (ulong)buf, n, offset);
+ /*
+ * don't even get started on a write if the power has failed
+ */
+ if(offset % lb->blocksize || n % lb->blocksize)
+ return Eio;
+ n /= lb->blocksize;
+ offset /= lb->blocksize;
+ if(offset + n > lb->bootblocks)
+ return Eio;
+ for(i = 0; i < n; i++) {
+ logfsbootblockreplace(lb, buf, offset + i);
+ buf = (uchar *)buf + lb->blocksize;
+ }
+ return nil;
+}
+
+char *
+logfsbootio(LogfsBoot *lb, void *buf, long n, ulong offset, int write)
+{
+ return (write ? logfsbootwrite : logfsbootread)(lb, buf, n, offset);
+}
+
+static char *
+eraseandformatblock(LogfsBoot *lb, long block, int trace)
+{
+ char *errmsg;
+ int markedbad;
+
+ errmsg = logfsbootfettleblock(lb, block, LogfsTnone, ~0, &markedbad);
+ if(errmsg)
+ return errmsg;
+ if(markedbad && trace > 1)
+ print("erase/format failed - marked bad\n");
+ return nil;
+}
+
+char *
+logfsbootopen(LogfsLowLevel *ll, long base, long limit, int trace, int printbad, LogfsBoot **lbp)
+{
+ long *reversemap;
+ ulong blocksize;
+ ulong blocks;
+ long i;
+ long bootblockmax;
+ LogfsBoot *lb = nil;
+ ulong baseblock;
+ char *errmsg;
+// int bootgenshift = ll->pathbits- LogfsBootGenBits;
+// ulong bootpathmask = (1 << (ll->pathbits - LogfsBootGenBits)) - 1;
+ long expectedbootblocks;
+
+ errmsg = (*ll->open)(ll, base, limit, trace, 1, &expectedbootblocks);
+ if(errmsg)
+ return errmsg;
+
+ bootblockmax = -1;
+ blocks = ll->blocks;
+ baseblock = (*ll->getbaseblock)(ll);
+ blocksize = (*ll->getblocksize)(ll);
+
+ for(i = 0; i < blocks; i++) {
+ if((*ll->getblocktag)(ll, i) == LogfsTboot) {
+ long path = (*ll->getblockpath)(ll, i);
+ LogfsBootPath lp;
+ LOGFSSPLITBOOTPATHEX(bootgenshift, bootpathmask, &lp, path);
+ if((long)lp.path > bootblockmax)
+ bootblockmax = lp.path;
+ }
+ }
+ if(bootblockmax + 1 >= blocks) {
+ if(printbad)
+ print("logfsbootinit: bootblockmax %ld exceeds number of blocks\n", bootblockmax);
+ return Ecorrupt;
+ }
+ if(bootblockmax < 0) {
+ if(printbad)
+ print("logfsbootopen: no boot area\n");
+ return Ecorrupt;
+ }
+ if(bootblockmax + 1 != expectedbootblocks) {
+ if(printbad)
+ print("logfsbootopen: wrong number of bootblocks (found %lud, expected %lud)\n",
+ bootblockmax + 1, expectedbootblocks);
+ }
+
+ reversemap = logfsrealloc(nil, sizeof(*reversemap) * (bootblockmax + 1));
+ if(reversemap == nil)
+ return Enomem;
+
+ for(i = 0; i <= bootblockmax; i++)
+ reversemap[i] = -1;
+ for(i = 0; i < blocks; i++) {
+ LogfsBootPath ipath;
+ long rm;
+ ulong ip;
+
+ if((*ll->getblocktag)(ll, i) != LogfsTboot)
+ continue;
+ ip = (*ll->getblockpath)(ll, i);
+ LOGFSSPLITBOOTPATHEX(bootgenshift, bootpathmask, &ipath, ip);
+ rm = reversemap[ipath.path];
+ if(rm != -1) {
+ if(printbad)
+ print("logfsbootopen: blockaddr 0x%.8lux: path %ld(%d): duplicate\n",
+ blocksize * (baseblock + i), ipath.path, ipath.gen);
+ /*
+ * resolve collision
+ * if this one is partial, then erase it
+ * if the existing one is partial, erase that
+ * if both valid, give up
+ */
+ if((*ll->getblockpartialformatstatus)(ll, i)) {
+ errmsg = eraseandformatblock(lb, i, trace);
+ if(errmsg)
+ goto error;
+ }
+ else if((*ll->getblockpartialformatstatus)(ll, rm)) {
+ errmsg = eraseandformatblock(lb, rm, trace);
+ if(errmsg)
+ goto error;
+ reversemap[ipath.path] = i;
+ }
+ else {
+ int d;
+ ulong rmp;
+ LogfsBootPath rmpath;
+ rmp = (*ll->getblockpath)(ll, rm);
+ LOGFSSPLITBOOTPATHEX(bootgenshift, bootpathmask, &rmpath, rmp);
+ d = (ipath.gen - rmpath.gen) & LogfsBootGenMask;
+ if(printbad)
+ print("i.gen = %d rm.gen = %d d = %d\n", ipath.gen, rmpath.gen, d);
+ if(d == 1) {
+ /* i is newer;
+ * keep the OLDER one because
+ * we might have had a write failure on the last page, but lost the
+ * power before being able to mark the first page bad
+ * if, worse, the auxiliary area's tag is the same for first and last page,
+ * this looks like a successfully written page. so, we cannot believe the
+ * data in the newer block unless we erased the old one, and then of
+ * course, we wouldn't have a duplicate.
+ */
+ errmsg = eraseandformatblock(lb, i, trace);
+ if(errmsg)
+ goto error;
+ }
+ else if(d == LogfsBootGenMask) {
+ /* rm is newer */
+ errmsg = eraseandformatblock(lb, rm, trace);
+ if(errmsg)
+ goto error;
+ reversemap[ipath.path] = i;
+ }
+ else {
+ errmsg = Ecorrupt;
+ goto error;
+ }
+ }
+ }
+ else
+ reversemap[ipath.path] = i;
+ }
+ /*
+ * final checks; not partial blocks, and no holes
+ */
+ for(i = 0; i <= bootblockmax; i++) {
+ long rm;
+ rm = reversemap[i];
+ if(rm == -1) {
+ if(printbad)
+ print("logfsbootopen: missing boot block %ld\n", i);
+ errmsg = Ecorrupt;
+ goto error;
+ }
+ if((*ll->getblockpartialformatstatus)(ll, rm)) {
+ if(printbad)
+ print("logfsbootopen: boot block %ld partially written\n", rm);
+ errmsg = Ecorrupt;
+ goto error;
+ }
+ }
+ /* the reverse map is consistent */
+ lb = logfsrealloc(nil, sizeof(*lb));
+ if(lb == nil) {
+ errmsg = Enomem;
+ goto error;
+ }
+
+ lb->blocksize = blocksize;
+ lb->bootblocks = bootblockmax + 1;
+ lb->map = reversemap;
+ lb->trace = trace;
+ lb->printbad = printbad;
+ lb->ll = ll;
+ lb->size = blocksize * lb->bootblocks;
+// lb->bootgenshift = bootgenshift;
+// lb->bootpathmask = bootpathmask;
+ *lbp = lb;
+ if(trace)
+ print("logfsbootopen: success\n");
+ return nil;
+
+error:
+ logfsfreemem(reversemap);
+ logfsfreemem(lb);
+ return errmsg;
+}
+
+void
+logfsbootfree(LogfsBoot *lb)
+{
+ if(lb) {
+ logfsfreemem(lb->map);
+ logfsfreemem(lb);
+ }
+}
+
+char *
+logfsbootmap(LogfsBoot *lb, ulong laddress, ulong *lblockp, int *lboffsetp, int *lpagep, int *lpageoffsetp, ulong *pblockp, ulong *paddressp)
+{
+ LogfsLowLevel *ll = lb->ll;
+ ulong lblock;
+ ulong lboffset, lpageoffset, lpage;
+ ulong pblock;
+ ulong paddress;
+
+ lblock = laddress / lb->blocksize;
+ if(lblock >= lb->bootblocks)
+ return Eaddress;
+ lboffset = laddress % lb->blocksize;
+ pblock = lb->map[lblock];
+ paddress = (*ll->calcrawaddress)(ll, pblock, lboffset);
+ lpage = lboffset >> ll->l2pagesize;
+ lpageoffset = lboffset & ((1 << ll->l2pagesize) - 1);
+ if(lblockp)
+ *lblockp = lblock;
+ if(lboffsetp)
+ *lboffsetp = lboffset;
+ if(lpagep)
+ *lpagep = lpage;
+ if(lpageoffsetp)
+ *lpageoffsetp = lpageoffset;
+ if(pblockp)
+ *pblockp = pblock;
+ if(paddressp)
+ *paddressp = paddress;
+ return nil;
+}
+
+long
+logfsbootgetiosize(LogfsBoot *lb)
+{
+ return lb->blocksize;
+}
+
+long
+logfsbootgetsize(LogfsBoot *lb)
+{
+ return lb->size;
+}
+
+void
+logfsboottrace(LogfsBoot *lb, int level)
+{
+ lb->trace = level;
+}
--- /dev/null
+++ b/liblogfs/clunk.c
@@ -1,0 +1,19 @@
+#include "logfsos.h"
+#include "logfs.h"
+#include "fcall.h"
+#include "local.h"
+
+char *
+logfsserverclunk(LogfsServer *server, u32int fid)
+{
+ Fid *f;
+ if(server->trace > 1)
+ print("logfsserverclunk(%ud)\n", fid);
+ f = logfsfidmapfindentry(server->fidmap, fid);
+ if(f == nil)
+ return logfsebadfid;
+ if(f->openmode >= 0 && (f->openmode & ORCLOSE) != 0)
+ return logfsserverremove(server, fid);
+ logfsfidmapclunk(server->fidmap, fid);
+ return nil;
+}
--- /dev/null
+++ b/liblogfs/conv.c
@@ -1,0 +1,285 @@
+#include "logfsos.h"
+#include "logfs.h"
+#include "local.h"
+#include "fcall.h"
+
+static void
+pn(uchar **pp, char *v)
+{
+ uchar *p = *pp;
+ int l;
+ l = v ? strlen(v) : 0;
+ PBIT16(p, l); p += BIT16SZ;
+ memmove(p, v, l);
+ p += l;
+ *pp = p;
+}
+
+static uint
+sn(char *p)
+{
+ if(p == nil)
+ return BIT16SZ;
+ return strlen(p) + BIT16SZ;
+}
+
+uint
+logfsconvM2S(uchar *ap, uint nap, LogMessage *f)
+{
+ uchar *p = ap;
+ uchar *ep = p + nap;
+ uchar *mep;
+ uint size;
+//print("conv(%d)\n", nap);
+ if(p + 1 > ep)
+ return 0;
+ f->type = *p++;
+//print("type %c\n", f->type);
+ switch(f->type) {
+ case LogfsLogTstart:
+ case LogfsLogTcreate:
+ case LogfsLogTtrunc:
+ case LogfsLogTremove:
+ case LogfsLogTwrite:
+ case LogfsLogTwstat:
+ break;
+ case LogfsLogTend:
+ return 1;
+ default:
+ return 0;
+ }
+ if(p + BIT16SZ > ep)
+ return 0;
+ size = GBIT16(p); p += BIT16SZ;
+//print("size %ud\n", size);
+ if(p + size > ep)
+ return 0;
+ mep = p + size;
+ if(p + BIT32SZ > mep)
+ return 0;
+ f->path = GBIT32(p); p += BIT32SZ;
+ switch(f->type) {
+ case LogfsLogTstart:
+ /* 's' size[2] path[4] nerase[4] */
+ if(p + BIT32SZ > ep)
+ return 0;
+ f->u.start.nerase = GBIT32(p); p += BIT32SZ;
+ break;
+ case LogfsLogTcreate:
+ /* 'c' size[2] path[4] perm[4] newpath[4] mtime[4] cvers[4] name[s] uid[s] gid[s] */
+ if(p + 4 * BIT32SZ > mep)
+ return 0;
+ f->u.create.perm = GBIT32(p); p+= BIT32SZ;
+ f->u.create.newpath = GBIT32(p); p+= BIT32SZ;
+ f->u.create.mtime = GBIT32(p); p+= BIT32SZ;
+ f->u.create.cvers = GBIT32(p); p+= BIT32SZ;
+ if(!logfsgn(&p, mep, &f->u.create.name)
+ || !logfsgn(&p, mep, &f->u.create.uid)
+ || !logfsgn(&p, mep, &f->u.create.gid))
+ return 0;
+ break;
+ case LogfsLogTremove:
+ /* 'r' size[2] path[4] mtime[4] muid[s] */
+ if(p + BIT32SZ > mep)
+ return 0;
+ f->u.remove.mtime = GBIT32(p); p += BIT32SZ;
+ if(!logfsgn(&p, mep, &f->u.remove.muid))
+ return 0;
+ break;
+ case LogfsLogTtrunc:
+ /* 't' size[2] path[4] mtime[4] cvers[4] muid[s] */
+ if(p + 2 * BIT32SZ > mep)
+ return 0;
+ f->u.trunc.mtime = GBIT32(p); p += BIT32SZ;
+ f->u.trunc.cvers = GBIT32(p); p += BIT32SZ;
+ if(!logfsgn(&p, mep, &f->u.trunc.muid))
+ return 0;
+ break;
+ case LogfsLogTwrite:
+ /* 'w' size[2] path[4] offset[4] count[2] mtime[4] cvers[4] muid[s] flashaddr[4] [data[n]] */
+ if(p + BIT32SZ + BIT16SZ + 2 * BIT32SZ > mep)
+ return 0;
+ f->u.write.offset = GBIT32(p); p += BIT32SZ;
+ f->u.write.count = GBIT16(p); p += BIT16SZ;
+ f->u.write.mtime = GBIT32(p); p += BIT32SZ;
+ f->u.write.cvers = GBIT32(p); p += BIT32SZ;
+ if(!logfsgn(&p, mep, &f->u.write.muid))
+ return 0;
+ if(p + BIT32SZ > mep)
+ return 0;
+ f->u.write.flashaddr = GBIT32(p); p += BIT32SZ;
+ if(f->u.write.flashaddr & LogAddr) {
+ if(p + f->u.write.count > mep)
+ return 0;
+ f->u.write.data = p;
+ p += f->u.write.count;
+ }
+ else
+ f->u.write.data = nil;
+ break;
+ case LogfsLogTwstat:
+ /* 'W' size[2] path[4] name[s] perm[4] uid[s] gid[s] mtime[4] muid[s] or */
+ /* 'W' size[2] path[4] name[s] perm[4] gid[s] mtime[4] muid[s] */
+ if(!logfsgn(&p, mep, &f->u.wstat.name))
+ return 0;
+ if(p + BIT32SZ > mep)
+ return 0;
+ f->u.wstat.perm = GBIT32(p); p += BIT32SZ;
+ if(!logfsgn(&p, mep, &f->u.wstat.uid))
+ return 0;
+ if(!logfsgn(&p, mep, &f->u.wstat.gid))
+ return 0;
+ if(p + BIT32SZ > mep)
+ return 0;
+ f->u.wstat.mtime = GBIT32(p); p += BIT32SZ;
+ if(!logfsgn(&p, mep, &f->u.wstat.muid))
+ return 0;
+ break;
+ default:
+ return 0;
+ }
+ if(p != mep)
+ return 0;
+ return p - ap;
+}
+
+uint
+logfssizeS2M(LogMessage *m)
+{
+ switch(m->type) {
+ case LogfsLogTend:
+ return 1;
+ case LogfsLogTstart:
+ return 11;
+ case LogfsLogTcreate:
+ /* 'c' size[2] path[4] perm[4] newpath[4] mtime[4] cvers[4] name[s] uid[s] gid[s] */
+ return 1 + BIT16SZ + 5 * BIT32SZ
+ + sn(m->u.create.name) + sn(m->u.create.uid) + sn(m->u.create.gid);
+ case LogfsLogTremove:
+ /* 'r' size[2] path[4] mtime[4] muid[s] */
+ return 1 + BIT16SZ + 2 * BIT32SZ + sn(m->u.remove.muid);
+ case LogfsLogTtrunc:
+ /* 't' size[2] path[4] mtime[4] cvers[4] muid[s] */
+ return 1 + BIT16SZ + 3 * BIT32SZ + sn(m->u.trunc.muid);
+ case LogfsLogTwrite:
+ /* 'w' size[2] path[4] offset[4] count[2] mtime[4] cvers[4] muid[s] flashaddr[4] [data[n]] */
+ return 1 + BIT16SZ + 2 * BIT32SZ + BIT16SZ + 2 * BIT32SZ + sn(m->u.write.muid)
+ + BIT32SZ + (m->u.write.data ? m->u.write.count : 0);
+ case LogfsLogTwstat:
+ /* 'W' size[2] path[4] name[s] perm[4] uid[s] gid[s] mtime[4] muid[s] */
+ /* 'W' size[2] path[4] name[s] perm[4] gid[s] mtime[4] muid[s] */
+ return 1 + BIT16SZ + BIT32SZ + sn(m->u.wstat.name) + BIT32SZ
+ + sn(m->u.wstat.uid)
+ + sn(m->u.wstat.gid) + BIT32SZ + sn(m->u.wstat.muid);
+ default:
+ return 0;
+ }
+}
+
+uint
+logfsconvS2M(LogMessage *s, uchar *ap, uint nap)
+{
+ uint size;
+ uchar *p;
+ size = logfssizeS2M(s);
+ if(size == 0 || size > nap)
+ return 0;
+ p = ap;
+ *p++ = s->type;
+ if(s->type == LogfsLogTend)
+ return 1;
+ size -= 1 + BIT16SZ;
+ PBIT16(p, size); p += BIT16SZ;
+ PBIT32(p, s->path); p += BIT32SZ;
+ switch(s->type) {
+ case LogfsLogTstart:
+ PBIT32(p, s->u.start.nerase); p += BIT32SZ;
+ break;
+ case LogfsLogTcreate:
+ /* 'c' size[2] path[4] perm[4] newpath[4] mtime[4] cvers[4] name[s] uid[s] gid[s] */
+ PBIT32(p, s->u.create.perm); p += BIT32SZ;
+ PBIT32(p, s->u.create.newpath); p += BIT32SZ;
+ PBIT32(p, s->u.create.mtime); p += BIT32SZ;
+ PBIT32(p, s->u.create.cvers); p += BIT32SZ;
+ pn(&p, s->u.create.name);
+ pn(&p, s->u.create.uid);
+ pn(&p, s->u.create.gid);
+ break;
+ case LogfsLogTremove:
+ /* 'r' size[2] path[4] mtime[4] muid[s] */
+ PBIT32(p, s->u.remove.mtime); p += BIT32SZ;
+ pn(&p, s->u.remove.muid);
+ break;
+ case LogfsLogTtrunc:
+ /* 't' size[2] path[4] mtime[4] cvers[4] muid[s] */
+ PBIT32(p, s->u.trunc.mtime); p += BIT32SZ;
+ PBIT32(p, s->u.trunc.cvers); p += BIT32SZ;
+ pn(&p, s->u.trunc.muid);
+ break;
+ case LogfsLogTwrite:
+ /* 'w' size[2] path[4] offset[4] count[2] mtime[4] cvers[4] muid[s] flashaddr[4] [data[n]] */
+ PBIT32(p, s->u.write.offset); p += BIT32SZ;
+ PBIT16(p, s->u.write.count); p += BIT16SZ;
+ PBIT32(p, s->u.write.mtime); p += BIT32SZ;
+ PBIT32(p, s->u.write.cvers); p += BIT32SZ;
+ pn(&p, s->u.write.muid);
+ PBIT32(p, s->u.write.flashaddr); p += BIT32SZ;
+ if(s->u.write.data) {
+ memmove(p, s->u.write.data, s->u.write.count);
+ p += s->u.write.count;
+ }
+ break;
+ case LogfsLogTwstat:
+ /* 'W' size[2] path[4] name[s] perm[4] uid[s] gid[s] mtime[4] muid[s] */
+ /* 'W' size[2] path[4] name[s] perm[4] gid[s] mtime[4] muid[s] */
+ pn(&p, s->u.wstat.name);
+ PBIT32(p, s->u.wstat.perm); p += BIT32SZ;
+ pn(&p, s->u.wstat.uid);
+ pn(&p, s->u.wstat.gid);
+ PBIT32(p, s->u.wstat.mtime); p+= BIT32SZ;
+ pn(&p, s->u.wstat.muid);
+ break;
+ default:
+ return 0;
+ }
+ return p - ap;
+}
+
+void
+logfsdumpS(LogMessage *m)
+{
+ switch(m->type) {
+ case LogfsLogTend:
+ print("LogfsLogTend()");
+ break;
+ case LogfsLogTstart:
+ print("LogfsLogTstart(path=%ud, nerase=%ud)", m->path, m->u.start.nerase);
+ break;
+ case LogfsLogTcreate:
+ print("LogfsLogTcreate(path=%ud, perm=0%uo, newpath=%ud, mtime=%ud, cvers=%ud, name=%s, uid=%s, gid=%s)",
+ m->path, m->u.create.perm, m->u.create.newpath, m->u.create.mtime, m->u.create.cvers,
+ m->u.create.name, m->u.create.uid, m->u.create.gid);
+ break;
+ case LogfsLogTremove:
+ print("LogfsLogTremove(path=%ud, mtime=%ud, muid=%s)",
+ m->path, m->u.remove.mtime, m->u.remove.muid);
+ break;
+ case LogfsLogTtrunc:
+ print("LogfsLogTtrunc(path=%ud, mtime=%ud, cvers=%ud, muid=%s)",
+ m->path, m->u.trunc.mtime, m->u.trunc.cvers, m->u.trunc.muid);
+ break;
+ case LogfsLogTwrite:
+ print("LogfsLogTwrite(path=%ud, offset=%ud, count=%ud, mtime=%ud, cvers=%ud, muid=%s, flashaddr=0x%.8ux)",
+ m->path, m->u.write.offset, m->u.write.count, m->u.write.mtime, m->u.write.cvers, m->u.write.muid,
+ m->u.write.flashaddr);
+ break;
+ case LogfsLogTwstat:
+ print("LogfsLogTwstat(path=%ud, name=%s, perm=0%uo, uid=%s, gid=%s, mtime=%ud, muid=%s)",
+ m->path, m->u.wstat.name, m->u.wstat.perm, m->u.wstat.uid, m->u.wstat.gid,
+ m->u.wstat.mtime, m->u.wstat.muid);
+ break;
+ default:
+ print("LogfsLogTother(%c)", m->type);
+ break;
+ }
+}
--- /dev/null
+++ b/liblogfs/create.c
@@ -1,0 +1,82 @@
+#include "logfsos.h"
+#include "logfs.h"
+#include "local.h"
+
+char *
+logfsservercreate(LogfsServer *server, u32int fid, char *name, u32int perm, uchar mode, Qid *qid)
+{
+ Fid *f;
+ char *uid;
+ ulong newpath;
+ char *errmsg;
+ Entry *e, *xe, *pe;
+ Path *pp;
+ LogMessage s;
+
+ if(server->trace > 1)
+ print("logfsservercreate(%ud, %s, 0%uo, %.2ux)\n", fid, name, perm, mode);
+ f = logfsfidmapfindentry(server->fidmap, fid);
+ if(f == nil)
+ return logfsebadfid;
+ if(f->openmode >= 0)
+ return logfsefidopen;
+ pe = f->entry;
+ if((pe->qid.type & QTDIR) == 0)
+ return Enotdir;
+ if((perm & DMDIR) != 0 && ((mode & OTRUNC) != 0 || (mode & 3) != OREAD))
+ return Eperm;
+ if(!logfsuserpermcheck(server, pe, f, DMWRITE))
+ return Eperm;
+ /*
+ * illegal names
+ */
+ if(strcmp(name, ".") == 0 || strcmp(name, "..") == 0)
+ return Eperm;
+ for(xe = pe->u.dir.list; xe; xe = xe->next)
+ if(strcmp(xe->name, name) == 0)
+ return Eexist;
+ newpath = ++server->path;
+ while(logfspathmapfindentry(server->pathmap, newpath))
+ newpath++; /* shouldn't happen */
+ uid = logfsisfindidfromname(server->is, f->uname);
+ errmsg = logfsentrynew(server, 1, newpath,
+ pe, name, uid, f->entry->gid, logfsnow(), uid, perm, 0, 0, &e);
+ if(errmsg)
+ return errmsg;
+ errmsg = logfspathmapnewentry(server->pathmap, newpath, e, &pp);
+ /* pp is guaranteed to be non-null */
+ if(errmsg) {
+ logfsfreemem(e);
+ return errmsg;
+ }
+ s.type = LogfsLogTcreate;
+ s.path = e->parent->qid.path;
+ s.u.create.perm = e->perm;
+ s.u.create.newpath = e->qid.path;
+ s.u.create.mtime = e->mtime;
+ /* TODO - check with forsyth whether cvers is needed in dirs */
+ s.u.create.cvers = (e->qid.type & QTDIR) ? 0 : e->u.file.cvers;
+ s.u.create.name = e->name;
+ s.u.create.uid = e->uid;
+ s.u.create.gid = e->gid;
+ errmsg = logfslog(server, 1, &s);
+ if(errmsg) {
+ logfsfreemem(e);
+ logfspathmapdeleteentry(server->pathmap, newpath);
+ return errmsg;
+ }
+ server->path = newpath;
+ e->inuse++;
+ e->qid.vers++;
+ e->next = pe->u.dir.list;
+ pe->u.dir.list = e;
+ f->openmode = mode;
+ /*
+ * TODO why does forsyth increment inuse for dir? - we're moving the fid onto the new file
+ * so a decrement seems better
+ */
+ logfsentryclunk(pe);
+ f->entry = e;
+ *qid = e->qid;
+ return nil;
+}
--- /dev/null
+++ b/liblogfs/dump.c
@@ -1,0 +1,71 @@
+#include "logfsos.h"
+#include "logfs.h"
+#include "local.h"
+#include "fcall.h"
+
+typedef struct WalkState {
+ u32int *flashaddrp;
+ u32int *lengthp;
+ int i;
+ int nth;
+} WalkState;
+
+static int
+walk(void *magic, Extent *e, int hole)
+{
+ WalkState *s = magic;
+ USED(hole);
+ if(s->i == s->nth) {
+ *s->flashaddrp = e->flashaddr;
+ *s->lengthp = e->max - e->min;
+ return 0;
+ }
+ s->i++;
+ return 1;
+}
+
+char *
+logfsserverreadpathextent(LogfsServer *server, u32int path, int nth, u32int *flashaddrp, u32int *lengthp,
+ long *blockp, int *pagep, int *offsetp)
+{
+ Entry *e;
+ WalkState s;
+ long index;
+ e = logfspathmapfinde(server->pathmap, path);
+ if(e == nil)
+ return logfseunknownpath;
+ if(e->perm & DMDIR)
+ return Eisdir;
+ s.flashaddrp = flashaddrp;
+ s.lengthp = lengthp;
+ s.i = 0;
+ s.nth = nth;
+ *lengthp = 0;
+ logfsextentlistwalk(e->u.file.extent, walk, &s);
+ if(*lengthp) {
+ logfsflashaddr2spo(server, *flashaddrp, &index, pagep, offsetp);
+ if(*flashaddrp & LogAddr)
+ if(index >= server->activelog->unsweptblockindex)
+ if(index <= server->activelog->curblockindex)
+ *blockp = server->activelog->blockmap[index];
+ else
+ *blockp = -1;
+ else if(server->sweptlog)
+ if(index <= server->sweptlog->curblockindex)
+ *blockp = server->sweptlog->blockmap[index];
+ else
+ *blockp = -1;
+ else
+ *blockp = -1;
+ else if(index < server->ndatablocks)
+ *blockp = server->datablock[index].block;
+ else
+ *blockp = -1;
+ }
+ else {
+ *blockp = 0;
+ *pagep = 0;
+ *offsetp = 0;
+ }
+ return nil;
+}
--- /dev/null
+++ b/liblogfs/error.c
@@ -1,0 +1,17 @@
+#include "logfsos.h"
+#include "logfs.h"
+#include "local.h"
+
+char logfsebadfid[] = "fid not in use";
+char logfsefidnotopen[] = "fid is not open for I/O";
+char logfsefidopen[] = "fid is open for I/O";
+char logfsenotadir[] = "fid not a dir";
+char logfsefidinuse[] = "fid in use";
+char logfseopen[] = "fid not open";
+char logfseaccess[] = "fid open in wrong mode";
+char logfselogfull[] = "log filled";
+char logfselogmsgtoobig[] = "message too big for log";
+char logfseinternal[] = "internal error";
+char logfsenotempty[] = "directory not empty";
+char logfsefullreplacing[] = "out of space trying to replace block";
+char logfseunknownpath[] = "unknown path";
--- /dev/null
+++ b/liblogfs/extentlist.c
@@ -1,0 +1,279 @@
+#include "logfsos.h"
+#include "logfs.h"
+#include "local.h"
+
+typedef struct ExtentNode ExtentNode;
+
+struct ExtentNode {
+ Extent e;
+ ExtentNode *next;
+};
+
+struct ExtentList {
+ ExtentNode *head;
+};
+
+char *
+logfsextentlistnew(ExtentList **ep)
+{
+ ExtentList *l;
+ l = logfsrealloc(nil, sizeof(*l));
+ if(l == nil)
+ return Enomem;
+ *ep = l;
+ return nil;
+}
+
+void
+logfsextentlistreset(ExtentList *l)
+{
+ ExtentNode *n;
+ n = l->head;
+ while(n) {
+ ExtentNode *next;
+ next = n->next;
+ logfsfreemem(n);
+ n = next;
+ }
+ l->head = nil;
+}
+
+void
+logfsextentlistfree(ExtentList **lp)
+{
+ ExtentList *l;
+ if(lp == nil || (l = *lp) == nil)
+ return;
+ logfsextentlistreset(l);
+ logfsfreemem(l);
+ *lp = nil;
+}
+
+char *
+logfsextentlistinsert(ExtentList *l, Extent *add, Extent **new)
+{
+ ExtentNode *old, *prev;
+ ExtentNode *saved = nil;
+
+ if(l == nil)
+ return "nil extentlist";
+
+ /* initially a's extents are non-empty, disjoint and sorted */
+ old = l->head;
+ prev = nil;
+ while(old) {
+ ExtentNode *next = old->next;
+ if(add->max <= old->e.min)
+ break;
+ if(old->e.min < add->max && add->min < old->e.max) { /* they intersect */
+ if(add->min <= old->e.min) {
+ /* add overlaps front of old */
+ if(add->max < old->e.max) {
+ int trimmed;
+ /* but doesn't overlap end */
+ /* retain tail of old */
+ if(saved == nil){
+ saved = logfsrealloc(nil, sizeof(*saved));
+ if(saved == nil)
+ return Enomem;
+ }
+ trimmed = add->max - old->e.min;
+ old->e.min += trimmed;
+ old->e.flashaddr += trimmed;
+ /* can't touch any further extents, so... */
+ break;
+ }
+ /* add.min ≤ old.min < old.max ≤ add.max ⇒ add completely covers old */
+ /* delete old */
+ if(prev)
+ prev->next = next;
+ else
+ l->head = next;
+ /* stash the deleted extent, so we can reuse it */
+ if(saved == nil)
+ saved = old;
+ else
+ logfsfreemem(old);
+ old = next;
+ continue;
+ }
+ else {
+ /* add.min > old.min, so overlaps end of old or splits it */
+ if(add->max < old->e.max) { /* add inside old, splitting it */
+ ExtentNode *frag;
+ /*
+ * will need at most two add extents, so ensure
+ * enough store exists before changing data structures
+ */
+ if(saved == nil)
+ saved = logfsrealloc(nil, sizeof(*saved));
+ frag = logfsrealloc(nil, sizeof(*frag));
+ if(saved == nil || frag == nil)
+ return Enomem;
+ frag->next = next;
+ old->next = frag;
+ frag->e.min = add->max;
+ frag->e.max = old->e.max;
+ frag->e.flashaddr = old->e.flashaddr + (add->max - old->e.min);
+ old->e.max = add->min;
+ prev = old;
+ break;
+ }
+ else {
+ /*
+ * will need at most one add extent, so create one
+ * now before changing data structures
+ */
+ if(saved == nil){
+ saved = logfsrealloc(nil, sizeof(*saved));
+ if(saved == nil)
+ return Enomem;
+ }
+ old->e.max = add->min; /* retain start of old */
+ }
+ /* old.max <= add.max ⇒ add covers tail of old */
+ }
+ }
+ prev = old;
+ old = next;
+ }
+ /*
+ * if here, and saved == nil, then there was no overlap
+ */
+ if(saved == nil){
+ saved = logfsrealloc(nil, sizeof(*saved));
+ if(saved == nil)
+ return Enomem;
+ }
+ saved->e = *add;
+ if(prev) {
+ saved->next = prev->next;
+ prev->next = saved;
+ }
+ else {
+ saved->next = l->head;
+ l->head = saved;
+ }
+ if(new)
+ *new = &saved->e;
+ return nil;
+}
+
+Extent *
+logfsextentlistmatch(ExtentList *l, Extent *e)
+{
+ ExtentNode *m;
+ u32int flashmax;
+
+ if(l == nil)
+ return nil;
+
+ flashmax = e->flashaddr + (e->max - e->min);
+
+ for(m = l->head; m; m = m->next) {
+ u32int l = m->e.max - m->e.min;
+ if(e->min < m->e.max && m->e.min < e->max /* they intersect */
+ && m->e.flashaddr < flashmax && e->flashaddr < m->e.flashaddr + l) /* the store intersects */
+ return &(m->e);
+ }
+ return nil;
+}
+
+int
+logfsextentlistmatchall(ExtentList *l, int (*func)(void *magic, Extent *), void *magic, Extent *e)
+{
+ ExtentNode *m;
+ u32int flashmax;
+
+ if(l == nil)
+ return 1;
+
+ flashmax = e->flashaddr + (e->max - e->min);
+
+ for(m = l->head; m; m = m->next) {
+ u32int l;
+ if(m->e.min >= e->max)
+ return 1;
+ l = m->e.max - m->e.min;
+ if(e->min < m->e.max /* they intersect */
+ && m->e.flashaddr < flashmax && e->flashaddr < m->e.flashaddr + l) {
+ /* the store intersects */
+ int rv = (*func)(magic, &(m->e));
+ if(rv <= 0)
+ return rv;
+ }
+ }
+ return 1;
+}
+
+int
+logfsextentlistwalk(ExtentList *l, int (*func)(void *magic, Extent *, int hole), void *magic)
+{
+ ExtentNode *n;
+ u32int last = 0;
+ if(l == nil)
+ return 1;
+ for(n = l->head; n; n = n->next) {
+ int rv;
+ if(last < n->e.min) {
+ Extent hole;
+ hole.min = last;
+ hole.max = n->e.min;
+ hole.flashaddr = ~0;
+ rv = (*func)(magic, &hole, 1);
+ if(rv <= 0)
+ return rv;
+ }
+ rv = (*func)(magic, &n->e, 0);
+ if(rv <= 0)
+ return rv;
+ last = n->e.max;
+ }
+ return 1;
+}
+
+int
+logfsextentlistwalkrange(ExtentList *l, int (*func)(void *magic, u32int baseoffset, u32int limitoffset, Extent *, u32int extentoffset), void *magic, u32int base, u32int limit)
+{
+ ExtentNode *n;
+ u32int last = 0;
+ if(l == nil)
+ return 1;
+ for(n = l->head; n; n = n->next) {
+ Extent hole;
+ Extent *e;
+ if(last < n->e.min) {
+ hole.min = last;
+ hole.max = n->e.min;
+ e = &hole;
+ }
+ else {
+ again:
+ e = &n->e;
+ }
+ if(e->min >= limit)
+ return 1;
+//print("walkrange %ud .. %ud\n", e->min, e->max);
+ if(e->max > base) {
+ ulong rangebase, rangelimit, extentoffset;
+ int rv;
+ rangebase = e->min;
+ if(rangebase < base) {
+ extentoffset = base - rangebase;
+ rangebase += extentoffset;
+ }
+ else
+ extentoffset = 0;
+ rangelimit = e->max;
+ if(rangelimit > limit)
+ rangelimit = limit;
+ rv = (*func)(magic, rangebase - base, rangelimit - base, e == &hole ? nil : e, extentoffset);
+ if(rv <= 0)
+ return rv;
+ }
+ last = e->max;
+ if(e == &hole)
+ goto again;
+ }
+ return 1;
+}
--- /dev/null
+++ b/liblogfs/fidmap.c
@@ -1,0 +1,71 @@
+#include "logfsos.h"
+#include "logfs.h"
+#include "local.h"
+
+enum {
+ FIDMOD = 127
+};
+
+int
+logfshashulong(void *v, int size)
+{
+ return (ulong)v % size;
+}
+
+/*
+ * TO DO: assumes map.c always passes sought key value as b, and value in map as a
+ */
+static int
+compare(void *a, void *b)
+{
+ Fid *f = a;
+ ulong fid = (ulong)b; /* sic */
+//print("fidcompare(%ld, %ld)\n", f->fid, fid);
+ return f->fid == fid;
+}
+
+static int
+allocsize(void *key)
+{
+ USED(key);
+ return sizeof(Fid);
+}
+
+static void
+fidfree(void *a)
+{
+ Fid *f = a;
+ logfsdrsfree(&f->drs);
+}
+
+char *
+logfsfidmapnew(FidMap **fidmapp)
+{
+ return logfsmapnew(FIDMOD, logfshashulong, compare, allocsize, fidfree, fidmapp);
+}
+
+int
+logfsfidmapclunk(FidMap *m, ulong fid)
+{
+ Fid *f = logfsfidmapfindentry(m, fid);
+ if(f != nil){
+ logfsentryclunk(f->entry);
+ logfsmapdeleteentry(m, (void *)fid);
+ return 1;
+ }
+ return 0;
+}
+
+char *
+logfsfidmapnewentry(FidMap *m, ulong fid, Fid **fidmapp)
+{
+ char *errmsg;
+ errmsg = logfsmapnewentry(m, (void*)fid, fidmapp);
+ if(errmsg)
+ return errmsg;
+ if(*fidmapp == nil)
+ return nil;
+ (*fidmapp)->fid = fid;
+ (*fidmapp)->openmode = -1;
+ return nil;
+}
--- /dev/null
+++ b/liblogfs/findfreeblock.c
@@ -1,0 +1,31 @@
+#include "logfsos.h"
+#include "logfs.h"
+#include "local.h"
+
+long
+logfsfindfreeblock(LogfsLowLevel *ll, AllocReason reason)
+{
+ long b;
+ long total;
+ b = (*ll->findfreeblock)(ll, &total);
+ if(b < 0)
+ return b;
+ switch(reason) {
+ case AllocReasonReplace:
+ break;
+ case AllocReasonTransfer:
+ if(total <= Replacements)
+ return -1;
+ break;
+ case AllocReasonLogExtend:
+ if(total <= Replacements + Transfers)
+ return -1;
+ break;
+ case AllocReasonDataExtend:
+ if(total <= Replacements + Transfers + LogSlack)
+ return -1;
+ break;
+ }
+//print("allocated free block %ld\n", b);
+ return b;
+}
--- /dev/null
+++ b/liblogfs/flush.c
@@ -1,0 +1,17 @@
+#include "logfsos.h"
+#include "logfs.h"
+#include "fcall.h"
+#include "local.h"
+
+char *
+logfsserverflush(LogfsServer *server)
+{
+ char *errmsg = logfslogsegmentflush(server, 1);
+ if(errmsg == nil)
+ errmsg = logfslogsegmentflush(server, 0);
+ if(errmsg == nil)
+ errmsg = (*server->ll->sync)(server->ll);
+ if(server->trace > 1)
+ print("logfsserverflush\n");
+ return errmsg;
+}
--- /dev/null
+++ b/liblogfs/format.c
@@ -1,0 +1,107 @@
+#include "logfsos.h"
+#include "logfs.h"
+#include "local.h"
+
+char *
+logfsformat(LogfsLowLevel *ll, long base, long limit, long bootsize, int trace)
+{
+ long bootblocksdone, logblocksdone;
+ long u;
+ long baseblock, limitblock, bootblocks, sizeinblocks;
+ int magicfound;
+ void *llsave;
+
+ if(trace > 1)
+ print("logfsformat: base %ld limit %ld bootsize %lud\n", base, limit, bootsize);
+
+ if((*ll->getopenstatus)(ll))
+ return Eperm;
+
+ if(!(*ll->calcformat)(ll, base, limit, bootsize, &baseblock, &limitblock, &bootblocks))
+ return Ebadarg;
+
+ if(trace > 0)
+ print("logfsformat: baseblock %ld limitblock %ld bootblocks %ld\n", baseblock, limitblock, bootblocks);
+
+ bootblocksdone = 0;
+ logblocksdone = 0;
+ /*
+ * we need to create some fs blocks, and some boot blocks
+ * the number of boot blocks is fixed; the number of fs blocks
+ * occupies the remainder
+ * the layout is randomised to:
+ * 1) test the software
+ * 2) spread wear around if a lot of format commands are issued by
+ * the bootloader
+ */
+
+ sizeinblocks = limitblock - baseblock;
+
+ for(u = 0; u < sizeinblocks; u++) {
+ int r;
+ uchar tag;
+ long path;
+ LogfsLowLevelReadResult e;
+ char *errmsg;
+ int markedbad;
+
+ if(trace > 1)
+ print("block %lud:", u);
+ llsave = nil;
+ errmsg = (*ll->getblockstatus)(ll, u + baseblock, &magicfound, &llsave, &e);
+ if(errmsg)
+ return errmsg;
+ if(e == LogfsLowLevelReadResultBad) {
+ if(trace > 1)
+ print(" marked bad\n");
+ continue;
+ }
+ errmsg = (*ll->eraseblock)(ll, u + baseblock, nil, &markedbad);
+ if(errmsg)
+ return errmsg;
+ if(markedbad) {
+ if(trace > 1)
+ print(" marked bad\n");
+ continue;
+ }
+ if(e != LogfsLowLevelReadResultHardError && magicfound) {
+ if(trace > 1)
+ print(" previously formatted");
+ }
+ r = nrand(sizeinblocks - u);
+ if(bootblocksdone < bootblocks && r < (bootblocks - bootblocksdone)) {
+ tag = LogfsTboot;
+ path = mkdatapath(bootblocksdone, 0);
+ }
+ else {
+ tag = LogfsTnone;
+ path = ~0;
+ }
+ if(trace > 1)
+ print(" tag %s path %ld", logfstagname(tag), path);
+ errmsg = (*ll->formatblock)(ll, u + baseblock, tag, path, baseblock, sizeinblocks, 1, &bootblocks, llsave, &markedbad);
+ logfsfreemem(llsave);
+ if(errmsg)
+ return errmsg;
+ if(markedbad) {
+ if(trace > 1)
+ print(" marked bad\n");
+ continue;
+ }
+ switch(tag) {
+ case LogfsTboot:
+ bootblocksdone++;
+ break;
+ case LogfsTnone:
+ logblocksdone++;
+ break;
+ }
+ if(trace > 1)
+ print("\n");
+ }
+ if(bootblocksdone < bootblocks)
+ return "not enough capacity left for boot";
+ if(trace > 0)
+ print("log blocks %lud\n", logblocksdone);
+ return nil;
+}
--- /dev/null
+++ b/liblogfs/gn.c
@@ -1,0 +1,26 @@
+#include "logfsos.h"
+#include "logfs.h"
+#include "fcall.h"
+#include "local.h"
+
+int
+logfsgn(uchar **pp, uchar *mep, char **v)
+{
+ uchar *p = *pp;
+ int l;
+ if(p + BIT16SZ > mep)
+ return 0;
+ l = GBIT16(p); p += BIT16SZ;
+ if(p + l > mep)
+ return 0;
+ *pp = p + l;
+ if(l == 0) {
+ *v = 0;
+ return 1;
+ }
+ *v = (char *)(p - 1);
+ memmove(p - 1, p, l);
+ p[l - 1] = 0;
+ return 1;
+}
+
--- /dev/null
+++ b/liblogfs/group.c
@@ -1,0 +1,99 @@
+#include "logfsos.h"
+#include "logfs.h"
+#include "local.h"
+
+enum {
+ GROUPMOD = 127
+};
+
+static int
+groupcompare(void *a, void *b)
+{
+ Group *g = a;
+ char *uid = b;
+ return g->uid == uid;
+}
+
+static int
+unamecompare(void *a, void *b)
+{
+ Uname *u = a;
+ char *uname = b;
+ return u->uname == uname;
+}
+
+static int
+groupallocsize(void *key)
+{
+ USED(key);
+ return sizeof(Group);
+}
+
+static int
+unameallocsize(void *key)
+{
+ USED(key);
+ return sizeof(Uname);
+}
+
+char *
+logfsgroupmapnew(GroupMap **groupmapp, UnameMap **unamemapp)
+{
+ char *errmsg;
+ errmsg = logfsmapnew(GROUPMOD, logfshashulong, groupcompare, groupallocsize, nil, groupmapp);
+ if(errmsg)
+ return errmsg;
+ errmsg = logfsmapnew(GROUPMOD, logfshashulong, unamecompare, unameallocsize, nil, unamemapp);
+ if(errmsg)
+ logfsmapfree(groupmapp);
+ return errmsg;
+}
+
+char *
+logfsgroupmapnewentry(GroupMap *gm, UnameMap *um, char *uid, char *uname, Group **groupp, Uname **unamep)
+{
+ char *errmsg;
+ errmsg = logfsmapnewentry(gm, uid, groupp);
+ if(errmsg)
+ return errmsg;
+ if(*groupp == nil)
+ return "uid already exists";
+ (*groupp)->uid = uid;
+ errmsg = logfsgroupsetnew(&(*groupp)->members);
+ if(errmsg) {
+ logfsmapdeleteentry(gm, uid);
+ return errmsg;
+ }
+ errmsg = logfsmapnewentry(um, uname, unamep);
+ if(errmsg == nil && *unamep == nil)
+ errmsg = "uname already exists";
+ if(errmsg) {
+ logfsgroupsetfree(&(*groupp)->members);
+ logfsmapdeleteentry(gm, uid);
+ return errmsg;
+ }
+ (*groupp)->uname = uname;
+ (*unamep)->uname = uname;
+ (*unamep)->g = *groupp;
+ return nil;
+}
+
+char *
+logfsgroupmapfinduname(GroupMap *m, char *uid)
+{
+ Group *g;
+ g = logfsgroupmapfindentry(m, uid);
+ if(g)
+ return g->uname;
+ return nil;
+}
+
+char *
+logfsunamemapfinduid(UnameMap *m, char *uname)
+{
+ Uname *u;
+ u = logfsunamemapfindentry(m, uname);
+ if(u)
+ return u->g->uid;
+ return nil;
+}
--- /dev/null
+++ b/liblogfs/groupset.c
@@ -1,0 +1,91 @@
+#include "logfsos.h"
+#include "logfs.h"
+#include "local.h"
+
+struct GroupSet {
+ int maxentries;
+ int nentries;
+ Group **entry;
+};
+
+char *
+logfsgroupsetnew(GroupSet **gsp)
+{
+ GroupSet *gs = logfsrealloc(nil, sizeof(*gs));
+ if(gs == nil)
+ return Enomem;
+ gs->entry = logfsrealloc(nil, sizeof(Group *));
+ if(gs->entry == nil) {
+ logfsfreemem(gs);
+ return Enomem;
+ }
+ gs->maxentries = 1; /* most groups have one member */
+ gs->nentries = 0;
+ *gsp = gs;
+ return nil;
+}
+
+void
+logfsgroupsetfree(GroupSet **gsp)
+{
+ GroupSet *gs = *gsp;
+ if(gs) {
+ logfsfreemem(gs->entry);
+ logfsfreemem(gs);
+ *gsp = nil;
+ }
+}
+
+int
+logfsgroupsetadd(GroupSet *gs, Group *g)
+{
+ int x;
+ for(x = 0; x < gs->nentries; x++)
+ if(gs->entry[x] == g)
+ return 1;
+ if(gs->nentries >= gs->maxentries) {
+ Group **ne = logfsrealloc(gs->entry, sizeof(Group*)*(gs->maxentries * 2));
+ if(ne == nil)
+ return 0;
+ gs->entry = ne;
+ gs->maxentries *= 2;
+ }
+ gs->entry[gs->nentries++] = g;
+ return 1;
+}
+
+int
+logfsgroupsetremove(GroupSet *gs, Group *g)
+{
+ int x;
+ for(x = 0; x < gs->nentries; x++)
+ if(gs->entry[x] == g)
+ break;
+ if(x == gs->nentries)
+ return 0;
+ gs->nentries--;
+ memmove(&gs->entry[x], &gs->entry[x + 1], sizeof(Group *) * (gs->nentries - x));
+ return 1;
+}
+
+int
+logfsgroupsetwalk(GroupSet *gs, LOGFSGROUPSETWALKFN *func, void *magic)
+{
+ int x;
+ for(x = 0; x < gs->nentries; x++) {
+ int rv = (*func)(magic, gs->entry[x]);
+ if(rv <= 0)
+ return rv;
+ }
+ return 1;
+}
+
+int
+logfsgroupsetismember(GroupSet *gs, Group *g)
+{
+ int x;
+ for(x = 0; x < gs->nentries; x++)
+ if(gs->entry[x] == g)
+ return 1;
+ return 0;
+}
--- /dev/null
+++ b/liblogfs/is.c
@@ -1,0 +1,305 @@
+#include "logfsos.h"
+#include "logfs.h"
+#include "fcall.h"
+#include "local.h"
+
+char *logfsisgroupnonename = "none";
+
+char *
+logfsisnew(LogfsIdentityStore **isp)
+{
+ LogfsIdentityStore *is;
+ char *errmsg;
+
+ is = logfsrealloc(nil, sizeof(*is));
+ if(is == nil) {
+ memerror:
+ logfsisfree(&is);
+ return Enomem;
+ }
+ errmsg = logfsustnew(&is->ids);
+ if(errmsg)
+ goto memerror;
+ errmsg = logfsgroupmapnew(&is->groupmap, &is->unamemap);
+ if(errmsg)
+ goto memerror;
+ logfsisgroupnonename = logfsustadd(is->ids, logfsisgroupnonename);
+ *isp = is;
+ return nil;
+}
+
+void
+logfsisfree(LogfsIdentityStore **isp)
+{
+ LogfsIdentityStore *is = *isp;
+ if(is) {
+ logfsustfree(&is->ids);
+ logfsgroupmapfree(&is->groupmap);
+ logfsunamemapfree(&is->unamemap);
+ logfsfreemem(is);
+ *isp = nil;
+ }
+}
+
+char *
+logfsisgroupcreate(LogfsIdentityStore *is, char *groupname, char *groupid)
+{
+ Group *group;
+ Uname *uname;
+
+ if(strcmp(groupname, logfsisgroupnonename) == 0 || groupname[0] == '(')
+ return "group name reserved";
+ groupname = logfsisustadd(is, groupname);
+ groupid = logfsisustadd(is, groupid);
+ if(groupname == nil || groupid == nil)
+ return Enomem;
+ return logfsgroupmapnewentry(is->groupmap, is->unamemap, groupid, groupname, &group, &uname);
+}
+
+static Group *
+findgroupfromuname(LogfsIdentityStore *is, char *groupname)
+{
+ Uname *u = logfsunamemapfindentry(is->unamemap, groupname);
+ if(u == nil)
+ return nil;
+ return u->g;
+}
+
+char *
+logfsisgrouprename(LogfsIdentityStore *is, char *oldgroupname, char *newgroupname)
+{
+ Group *og, *ng;
+ oldgroupname = logfsisustadd(is, oldgroupname);
+ if(oldgroupname == nil)
+ return Enomem;
+ og =findgroupfromuname(is, oldgroupname);
+ if(og == nil)
+ return Enonexist;
+ newgroupname = logfsisustadd(is, newgroupname);
+ if(newgroupname == nil)
+ return Enomem;
+ ng = findgroupfromuname(is, newgroupname);
+ if(ng != nil)
+ return Eexist;
+ og->uname = newgroupname;
+ return nil;
+}
+
+char *
+logfsisgroupsetleader(LogfsIdentityStore *is, char *groupname, char *leadername)
+{
+ Group *g, *lg;
+ groupname = logfsisustadd(is, groupname);
+ if(groupname == nil)
+ return Enomem;
+ g = findgroupfromuname(is, groupname);
+ if(g == nil)
+ return Enonexist;
+ if(leadername && leadername[0]) {
+ leadername = logfsisustadd(is, leadername);
+ if(leadername == nil)
+ return Enomem;
+ lg = findgroupfromuname(is, leadername);
+ if(lg == nil)
+ return Enonexist;
+ if(!logfsgroupsetismember(g->members, lg))
+ return "not a member of the group";
+ g->leader = lg;
+ }
+ else
+ g->leader = nil;
+ return nil;
+}
+
+char *
+logfsisgroupaddmember(LogfsIdentityStore *is, char *groupname, char *membername)
+{
+ Group *g, *mg;
+ groupname = logfsisustadd(is, groupname);
+ if(groupname == nil)
+ return Enomem;
+ g =findgroupfromuname(is, groupname);
+ if(g == nil)
+ return Enonexist;
+ membername = logfsisustadd(is, membername);
+ if(membername == nil)
+ return Enomem;
+ mg = findgroupfromuname(is, membername);
+ if(mg == nil)
+ return Enonexist;
+ if(!logfsgroupsetadd(g->members, mg))
+ return Enomem;
+ return nil;
+}
+
+char *
+logfsisgroupremovemember(LogfsIdentityStore *is, char *groupname, char *nonmembername)
+{
+ Group *g, *nonmg;
+ groupname = logfsisustadd(is, groupname);
+ if(groupname == nil)
+ return Enomem;
+ g =findgroupfromuname(is, groupname);
+ if(g == nil)
+ return Enonexist;
+ nonmembername = logfsisustadd(is, nonmembername);
+ if(nonmembername == nil)
+ return Enomem;
+ nonmg = findgroupfromuname(is, nonmembername);
+ if(nonmg == nil)
+ return Enonexist;
+ if(!logfsgroupsetremove(g->members, nonmg))
+ return Enonexist;
+ if(g->leader == nonmg)
+ g->leader = nil;
+ return nil;
+}
+
+typedef struct DS {
+ char *printbuf;
+ long printbufsize;
+ void *buf;
+ ulong offset;
+ long n;
+ ulong printoffset;
+ int printn;
+ int comma;
+} DS;
+
+static int
+printmember(void *magic, Group *member)
+{
+ DS *ds = magic;
+ if(ds->comma) {
+ if(ds->printn < ds->printbufsize)
+ ds->printbuf[ds->printn++] = ',';
+ }
+ else
+ ds->comma = 1;
+ ds->printn += snprint(ds->printbuf + ds->printn, ds->printbufsize - ds->printn, "%s", member->uname);
+ return 1;
+}
+
+static int
+printgroup(void *magic, Group *g)
+{
+ DS *ds = magic;
+ ds->printn = snprint(ds->printbuf, ds->printbufsize, "%s:%s:%s:",
+ g->uid, g->uname, g->leader ? g->leader->uname : "");
+ /* do members */
+ ds->comma = 0;
+ logfsgroupsetwalk(g->members, printmember, ds);
+ if(ds->printn < ds->printbufsize)
+ ds->printbuf[ds->printn++] = '\n';
+ /*
+ * copy the appropriate part of the buffer
+ */
+ if(ds->printoffset < ds->offset + ds->n && ds->printoffset + ds->printn > ds->offset) {
+ char *printbuf = ds->printbuf;
+ uchar *buf = ds->buf;
+ long trim = ds->offset - ds->printoffset;
+ if(trim >= 0) {
+ printbuf += trim;
+ ds->printn -= trim;
+ }
+ else
+ buf -= trim;
+ if(ds->printoffset + ds->printn > ds->offset + ds->n)
+ ds->printn = ds->offset + ds->n - ds->printoffset;
+ memmove(buf, printbuf, ds->printn);
+ }
+ /*
+ * advance print position
+ */
+ ds->printoffset += ds->printn;
+ /*
+ * stop if exceeding the buffer
+ */
+ if(ds->printoffset >= ds->offset + ds->n)
+ return 0;
+ return 1;
+}
+
+char *
+logfsisusersread(LogfsIdentityStore *is, void *buf, long n, ulong offset, long *nr)
+{
+ DS ds;
+ ds.buf = buf;
+ ds.n = n;
+ ds.printoffset = 0;
+ ds.offset = offset;
+ ds.printbufsize = 1024;
+ ds.printbuf = logfsrealloc(nil, ds.printbufsize);
+ if(ds.printbuf == nil)
+ return Enomem;
+ logfsmapwalk(is->groupmap, (LOGFSMAPWALKFN *)printgroup, &ds);
+ *nr = ds.printoffset - ds.offset;
+ logfsfreemem(ds.printbuf);
+ return nil;
+}
+
+int
+logfsisgroupunameismember(LogfsIdentityStore *is, Group *g, char *uname)
+{
+ Group *ug;
+ if(g == nil)
+ return 0;
+ if(g->uname == uname)
+ return 1;
+ ug = logfsisfindgroupfromname(is, uname);
+ if(ug == nil)
+ return 0;
+ return logfsgroupsetismember(g->members, ug);
+}
+
+int
+logfsisgroupuidismember(LogfsIdentityStore *is, Group *g, char *uid)
+{
+ Group *ug;
+ if(g == nil)
+ return 0;
+ if(g->uid == uid)
+ return 1;
+ ug = logfsisfindgroupfromid(is, uid);
+ if(ug == nil)
+ return 0;
+ return logfsgroupsetismember(g->members, ug);
+}
+
+int
+logfsisgroupuidisleader(LogfsIdentityStore *is, Group *g, char *id)
+{
+ if(g->leader)
+ return g->leader->uid == id;
+ return logfsisgroupuidismember(is, g, id);
+}
+
+Group *
+logfsisfindgroupfromname(LogfsIdentityStore *is, char *name)
+{
+ Uname *u;
+ u = logfsunamemapfindentry(is->unamemap, name);
+ if(u == nil)
+ return nil;
+ return u->g;
+}
+
+char *
+logfsisfindidfromname(LogfsIdentityStore *is, char *name)
+{
+ char *id;
+ id = logfsunamemapfinduid(is->unamemap, name);
+ if(id == nil)
+ return logfsisgroupnonename;
+ return id;
+}
+
+char *
+logfsisfindnamefromid(LogfsIdentityStore *is, char *id)
+{
+ Group *g;
+ g = logfsgroupmapfindentry(is->groupmap, id);
+ if(g == nil)
+ return nil;
+ return g->uname;
+}
--- /dev/null
+++ b/liblogfs/local.h
@@ -1,0 +1,335 @@
+typedef struct DataBlock DataBlock;
+typedef struct Extent Extent;
+typedef struct Entry Entry;
+typedef struct ExtentList ExtentList;
+typedef struct Fid Fid;
+typedef struct Map Map;
+typedef struct GroupSet GroupSet;
+typedef struct Group Group;
+typedef struct Uname Uname;
+typedef struct LogMessage LogMessage;
+typedef struct LogSegment LogSegment;
+typedef struct Path Path;
+typedef struct DirReadState DirReadState;
+
+typedef struct Map PathMap;
+typedef struct Map FidMap;
+typedef struct Map GroupMap;
+typedef struct Map UnameMap;
+typedef struct Map Ust;
+
+#pragma incomplete Extent
+#pragma incomplete ExtentList
+#pragma incomplete Map
+#pragma incomplete DirReadState
+
+enum {
+ L2LogSweeps = 2,
+ L2BlockCopies = 2,
+ LogDataLimit = 128,
+ LogAddr = (1 << 31),
+ Replacements = 2, /* extra space for replacements */
+ Transfers = 2, /* extra space available for transfers */
+ LogSlack = 1, /* extra space for data allocation */
+};
+
+struct Extent {
+ u32int min, max;
+ u32int flashaddr; /* encode block index, page number, and offset within page to min */
+};
+
+char *logfsextentlistnew(ExtentList **);
+void logfsextentlistfree(ExtentList **);
+char *logfsextentlistinsert(ExtentList *, Extent *, Extent **);
+int logfsextentlistwalk(ExtentList *, int (*)(void *, Extent *, int),void *);
+Extent *logfsextentlistmatch(ExtentList *, Extent *);
+int logfsextentlistwalkrange(ExtentList *,
+ int (*)(void *, u32int, u32int, Extent *, u32int),
+ void *, u32int, u32int);
+int logfsextentlistmatchall(ExtentList *, int (*)(void *, Extent *), void *, Extent *);
+void logfsextentlistreset(ExtentList *);
+
+struct Entry {
+ int inuse;
+ int deadandgone; /* removed */
+ Qid qid;
+ struct Entry *parent;
+ char *name;
+ char *uid;
+ char *gid;
+ ulong mtime;
+ char *muid;
+ u32int perm;
+ struct Entry *next;
+ struct {
+ struct {
+ ulong cvers;
+ ulong length;
+ ExtentList *extent;
+ } file;
+ struct {
+ struct Entry *list;
+ } dir;
+ } u;
+};
+
+char *logfsentrynew(LogfsServer *, int, u32int, Entry *,
+ char *, char *, char *,
+ u32int, char *, u32int, ulong, ulong, Entry **);
+void logfsentryclunk(Entry *);
+
+void logfsdrsfree(DirReadState **);
+
+struct Fid {
+ ulong fid;
+ int openmode;
+ Entry *entry;
+ char *uname;
+ DirReadState *drs;
+};
+
+typedef int LOGFSMAPWALKFN(void*, void*);
+char *logfsmapnew(int, int (*)(void*, int), int (*)(void*, void*), int (*)(void*), void (*)(void*), Map **);
+void logfsmapfree(Map **);
+char *logfsmapnewentry(Map*, void*, void **);
+void *logfsmapfindentry(Map*, void*);
+int logfsmapdeleteentry(Map*, void*);
+int logfsmapwalk(Map*, LOGFSMAPWALKFN*, void*);
+
+char *logfsfidmapnew(FidMap **);
+#define logfsfidmapfree(mp) logfsmapfree(mp)
+char *logfsfidmapnewentry(FidMap *, ulong, Fid **);
+#define logfsfidmapfindentry(m, fid) logfsmapfindentry(m, (void *)fid)
+int logfsfidmapclunk(FidMap *, ulong);
+
+struct Logfs {
+ int trace;
+};
+
+char *logfsustnew(Ust**);
+#define logfsustfree(m) logfsmapfree((m))
+char *logfsustadd(Ust*, char*);
+
+struct Group {
+ char *uid;
+ char *uname;
+ Group *leader;
+ GroupSet *members;
+};
+
+struct Uname {
+ char *uname;
+ Group *g;
+};
+
+struct LogfsIdentityStore {
+ Ust *ids;
+ GroupMap *groupmap;
+ UnameMap *unamemap;
+};
+
+char *logfsgroupmapnew(GroupMap **, UnameMap **);
+#define logfsgroupmapfree(mp) logfsmapfree(mp)
+#define logfsunamemapfree(mp) logfsmapfree(mp)
+char *logfsgroupmapnewentry(GroupMap *, UnameMap *, char *, char *, Group **, Uname **);
+#define logfsgroupmapdeleteentry(m, uid) logfsmapdeleteentry(m, (void *)uid)
+#define logfsgroupmapfindentry(m, uid) logfsmapfindentry(m, uid)
+#define logfsunamemapfindentry(m, uname) logfsmapfindentry(m, uname)
+char *logfsgroupmapfinduname(GroupMap *, char *);
+char *logfsunamemapfinduid(UnameMap *, char *);
+#define logfsunamemapdeleteentry(m, uname) logfsmapdeleteentry(m, (void *)uname)
+
+typedef int LOGFSGROUPSETWALKFN(void *, Group *);
+char *logfsgroupsetnew(GroupSet **);
+void logfsgroupsetfree(GroupSet **);
+int logfsgroupsetadd(GroupSet *, Group *);
+int logfsgroupsetremove(GroupSet *, Group *);
+int logfsgroupsetwalk(GroupSet *, LOGFSGROUPSETWALKFN *, void *);
+int logfsgroupsetismember(GroupSet *, Group *);
+char *logfsisfindidfromname(LogfsIdentityStore *, char *);
+char *logfsisfindnamefromid(LogfsIdentityStore *, char *);
+#define logfsisfindgroupfromid(is, id) logfsgroupmapfindentry((is)->groupmap, id)
+Group *logfsisfindgroupfromname(LogfsIdentityStore *, char *);
+#define logfsisustadd(is, s) logfsustadd((is)->ids, s)
+int logfsisgroupunameismember(LogfsIdentityStore *, Group *, char *);
+int logfsisgroupuidismember(LogfsIdentityStore *, Group *, char *);
+int logfsisgroupuidisleader(LogfsIdentityStore *, Group *, char *);
+extern char *logfsisgroupnonename;
+
+struct LogMessage {
+ uchar type;
+ u32int path;
+ union {
+ struct {
+ u32int nerase;
+ } start;
+ struct {
+ u32int perm;
+ u32int newpath;
+ u32int mtime;
+ u32int cvers;
+ char *name;
+ char *uid;
+ char *gid;
+ } create;
+ struct {
+ u32int mtime;
+ char *muid;
+ } remove;
+ struct {
+ u32int mtime;
+ u32int cvers;
+ char *muid;
+ } trunc;
+ struct {
+ u32int offset;
+ u32int count;
+ u32int mtime;
+ u32int cvers;
+ char *muid;
+ u32int flashaddr;
+ uchar *data;
+ } write;
+ struct {
+ char *name;
+ u32int perm;
+ char *uid;
+ char *gid;
+ u32int mtime;
+ char *muid;
+ } wstat;
+ } u;
+};
+
+uint logfsconvM2S(uchar *, uint, LogMessage *);
+uint logfssizeS2M(LogMessage *);
+uint logfsconvS2M(LogMessage *, uchar *, uint);
+void logfsdumpS(LogMessage *);
+
+struct LogSegment {
+ int gen; /* generation number of this log */
+ int dirty; /* written to since last sweep */
+ long curblockindex; /* index of block being filled, or -1 */
+ long unsweptblockindex; /* next block to sweep */
+ int curpage; /* page within block */
+ uchar *pagebuf; /* page buffer */
+ int nbytes; /* bytes used in page buffer */
+ long blockmap[1]; /* there are ll->blocks of these */
+};
+
+char *logfslogsegmentnew(LogfsServer *, int, LogSegment **);
+void logfslogsegmentfree(LogSegment **);
+char *logfslogbytes(LogfsServer *, int, uchar *, uint);
+char *logfslog(LogfsServer *, int, LogMessage *);
+char *logfslogwrite(LogfsServer *, int, u32int, u32int, int, u32int,
+ u32int, char *, uchar *, u32int *);
+char *logfslogsegmentflush(LogfsServer *, int);
+int lognicesizeforwrite(LogfsServer *, int, u32int, int);
+char *logfsscan(LogfsServer *);
+
+struct DataBlock {
+ Pageset free;
+ Pageset dirty;
+ long path; /* includes generation */
+ long block;
+};
+
+Pageset logfsdatapagemask(int, int);
+
+struct Path {
+ ulong path;
+ Entry *entry;
+};
+
+char *logfspathmapnew(PathMap **);
+#define logfspathmapfree(mp) logfsmapfree(mp)
+char *logfspathmapnewentry(PathMap *, ulong, Entry *, Path **);
+#define logfspathmapfindentry(m, path) (Path *)logfsmapfindentry(m, (void *)path)
+#define logfspathmapdeleteentry(m, path) logfsmapdeleteentry(m, (void *)path)
+Entry *logfspathmapfinde(PathMap *, ulong);
+
+enum {
+ LogfsTestDontFettleDataBlock = 1,
+};
+
+struct LogfsServer {
+ LogfsLowLevel *ll;
+ LogfsBoot *lb;
+ FidMap *fidmap;
+ LogfsIdentityStore *is;
+ PathMap *pathmap;
+ LogSegment *activelog;
+ LogSegment *sweptlog;
+ long ndatablocks;
+ DataBlock *datablock;
+ ulong path;
+ Entry root;
+ int trace;
+ ulong openflags;
+ ulong testflags;
+};
+
+int logfshashulong(void *, int);
+
+int logfsuserpermcheck(LogfsServer *, Entry *, Fid *, ulong);
+u32int logfsflattenentry(LogfsIdentityStore *, uchar *, u32int, Entry *);
+char *logfsreplay(LogfsServer *, LogSegment *, int);
+void logfsreplayfinddata(LogfsServer *);
+
+#define dataseqof(path) ((path) >> L2BlockCopies)
+#define copygenof(path) ((path) & ((1 << L2BlockCopies) -1))
+#define mkdatapath(seq, gen) (((seq) << L2BlockCopies) | (gen))
+#define gensucc(g, l2) (((g) + 1) & ((1 << (l2)) - 1))
+#define copygensucc(g) gensucc((g), L2BlockCopies)
+#define loggenof(path) ((path >> L2BlockCopies) & ((1 << L2LogSweeps) - 1))
+#define logseqof(path) ((path) >> (L2BlockCopies + L2LogSweeps))
+#define mklogpath(seq, gen, copygen) (((((seq) << L2LogSweeps) | (gen)) << L2BlockCopies) | (copygen))
+#define loggensucc(g) gensucc((g), L2LogSweeps)
+
+int logfsunconditionallymarkfreeanddirty(void *, Extent *, int);
+void logfsflashaddr2spo(LogfsServer *, u32int, long *, int *, int *);
+int logfsgn(uchar **, uchar *, char **);
+u32int logfsspo2flashaddr(LogfsServer *, long, int, int);
+int logfsgn(uchar **, uchar *, char **);
+void logfsflashaddr2o(LogfsServer *, u32int, int *);
+void logfsfreedatapages(LogfsServer *, long, Pageset);
+void logfsfreeanddirtydatablockcheck(LogfsServer *, long);
+
+typedef enum AllocReason {
+ AllocReasonReplace,
+ AllocReasonTransfer,
+ AllocReasonLogExtend,
+ AllocReasonDataExtend,
+} AllocReason;
+
+long logfsfindfreeblock(LogfsLowLevel *, AllocReason);
+char *logfsbootfettleblock(LogfsBoot *, long, uchar tag, long, int *);
+char *logfsserverreplacedatablock(LogfsServer *, long);
+char *logfsserverreplacelogblock(LogfsServer *, LogSegment *, long);
+char *logfsserverreplaceblock(LogfsServer *, LogSegment *, long);
+char *logfsservercopyactivedata(LogfsServer *, long, long, int,
+ LogfsLowLevelReadResult *, int *);
+
+char *logfsstrdup(char*);
+
+extern char Enomem[];
+extern char Eshortstat[];
+extern char Enonexist[];
+extern char Etoobig[];
+extern char Eexist[];
+extern char Eunknown[];
+extern char Enotdir[];
+extern char Eisdir[];
+extern char logfsebadfid[];
+extern char logfsefidopen[];
+extern char logfsefidnotopen[];
+extern char logfsefidinuse[];
+extern char logfseopen[];
+extern char logfseaccess[];
+extern char logfselogmsgtoobig[];
+extern char logfselogfull[];
+extern char logfseinternal[];
+extern char logfsenotempty[];
+extern char logfseexcl[];
+extern char logfsefullreplacing[];
+extern char logfseunknownpath[];
--- /dev/null
+++ b/liblogfs/log.c
@@ -1,0 +1,270 @@
+#include "logfsos.h"
+#include "logfs.h"
+#include "local.h"
+#include "fcall.h"
+
+void
+logfsflashaddr2spo(LogfsServer *server, u32int flashaddr, long *seq, int *page, int *offset)
+{
+ LogfsLowLevel *ll = server->ll;
+ flashaddr &= ~LogAddr;
+ *offset = flashaddr & ((1 << ll->l2pagesize) - 1);
+ flashaddr >>= ll->l2pagesize;
+ *page = flashaddr & ((1 << ll->l2pagesperblock) - 1);
+ flashaddr >>= ll->l2pagesperblock;
+ *seq = flashaddr;
+}
+
+u32int
+logfsspo2flashaddr(LogfsServer *server, long seq, int page, int offset)
+{
+//print("logfsspo2flashaddr(%ld, %d, %d)\n", seq, page, offset);
+ return (((seq << server->ll->l2pagesperblock) + page) << server->ll->l2pagesize) + offset;
+}
+
+void
+logfsflashaddr2o(LogfsServer *server, u32int flashaddr, int *offset)
+{
+ LogfsLowLevel *ll = server->ll;
+ flashaddr &= ~LogAddr;
+ *offset = flashaddr & ((1 << ll->l2pagesize) - 1);
+}
+
+char *
+logfslogsegmentnew(LogfsServer *server, int gen, LogSegment **segp)
+{
+ LogSegment *seg;
+ seg = logfsrealloc(nil, sizeof(LogSegment) + (server->ll->blocks - 1) * sizeof(long));
+ if(seg == nil)
+ return Enomem;
+ seg->pagebuf = logfsrealloc(nil, 1 << server->ll->l2pagesize);
+ if(seg->pagebuf == nil) {
+ logfsfreemem(seg);
+ return Enomem;
+ }
+ seg->curpage = -1;
+ seg->curblockindex = -1;
+ seg->gen = gen;
+ *segp = seg;
+ return nil;
+}
+
+void
+logfslogsegmentfree(LogSegment **segp)
+{
+ LogSegment *seg = *segp;
+ if(seg) {
+ logfsfreemem(seg->pagebuf);
+ logfsfreemem(seg);
+ *segp = nil;
+ }
+}
+
+char *
+logfslogsegmentflush(LogfsServer *server, int active)
+{
+ LogSegment *seg;
+ seg = active ? server->activelog : server->sweptlog;
+ if(seg == nil)
+ return nil;
+ if(seg->curpage >= 0 && seg->nbytes) {
+ char *errmsg;
+ LogfsLowLevel *ll = server->ll;
+ int pagesize = 1 << ll->l2pagesize;
+//print("curblockindex %ld curpage %d nbytes %d\n", seg->curblockindex, seg->curpage, seg->nbytes);
+ if(seg->nbytes < pagesize)
+ seg->pagebuf[seg->nbytes++] = LogfsLogTend;
+ memset(seg->pagebuf + seg->nbytes, 0xff, pagesize - seg->nbytes);
+ for(;;) {
+ errmsg = (*ll->writepage)(ll, seg->pagebuf,
+ seg->blockmap[seg->curblockindex], seg->curpage);
+ if(errmsg == nil)
+ break;
+ if(strcmp(errmsg, Eio) != 0)
+ return errmsg;
+ errmsg = logfsserverreplacelogblock(server, seg, seg->curblockindex);
+ if(errmsg)
+ return errmsg;
+ }
+ seg->curpage++;
+ if(seg->curpage == (1 << ll->l2pagesperblock))
+ seg->curpage = -1;
+ seg->nbytes = 0;
+ }
+ return nil;
+}
+
+static char *
+logspace(LogfsServer *server, int active, int takearisk, int nbytes, uchar **where, u32int *flashaddr)
+{
+ char *errmsg;
+ LogfsLowLevel *ll = server->ll;
+ int pagesize = 1 << ll->l2pagesize;
+ LogSegment *seg;
+
+ if(nbytes > pagesize)
+ return logfselogmsgtoobig;
+retry:
+ seg = active ? server->activelog : server->sweptlog;
+ for(;;) {
+//print("curpage %d nbytes %d\n", seg->curpage, seg->nbytes);
+ if(seg->curpage >= 0) {
+ if(seg->nbytes + nbytes < pagesize)
+ break;
+ errmsg = logfslogsegmentflush(server, active);
+ if(errmsg)
+ return errmsg;
+ }
+ if(seg->curpage < 0) {
+ long block;
+ long path;
+ block = logfsfindfreeblock(ll,
+ active ? (takearisk ? AllocReasonLogExtend : AllocReasonDataExtend) : AllocReasonTransfer);
+ if(block < 0) {
+ if(active) {
+ int didsomething;
+ errmsg = logfsserverlogsweep(server, 0, &didsomething);
+ if(errmsg)
+ return errmsg;
+ if(didsomething)
+ goto retry;
+ }
+ return logfselogfull;
+ }
+ seg->blockmap[++seg->curblockindex] = block;
+ path = mklogpath(seg->curblockindex, seg->gen, 0);
+ (*ll->setblocktag)(ll, block, LogfsTlog);
+ (*ll->setblockpath)(ll, block, path);
+ seg->curpage = 0;
+#ifdef FUTURE
+ /* TODO - do we need one of these if the underlying system supports erase counting? */
+ seg->pagebuf[0] = LogfsLogTstart;
+ PBIT16(seg->pagebuf + 1, 8);
+ PBIT32(seg->pagebuf + 3, path); /* TODO duplicate information */
+ PBIT32(seg->pagebuf + 7, 0); /* TODO don't have this - discuss with forsyth */
+ seg->nbytes = 11;
+#else
+ seg->nbytes = 0;
+#endif
+ }
+ }
+ *where = seg->pagebuf + seg->nbytes;
+ if(flashaddr)
+ *flashaddr = logfsspo2flashaddr(server, seg->curblockindex, seg->curpage, seg->nbytes);
+ seg->nbytes += nbytes;
+ return nil;
+}
+
+static void
+logdirty(LogfsServer *server, int active)
+{
+ if(active)
+ server->activelog->dirty = 1;
+ else
+ server->sweptlog->dirty = 1;
+}
+
+char *
+logfslogbytes(LogfsServer *server, int active, uchar *msg, uint size)
+{
+ char *errmsg;
+ uchar *p;
+
+ errmsg = logspace(server, active, 0, size, &p, nil);
+ if(errmsg)
+ return errmsg;
+ memmove(p, msg, size);
+ logdirty(server, active);
+ return nil;
+}
+
+char *
+logfslog(LogfsServer *server, int active, LogMessage *s)
+{
+ uint size = logfssizeS2M(s);
+ char *errmsg;
+ uchar *p;
+ int takearisk;
+
+ if(server->trace > 1) {
+ print("%c<< ", active ? 'A' : 'S');
+ logfsdumpS(s);
+ print("\n");
+ }
+ if(active) {
+ switch(s->type) {
+ case LogfsLogTremove:
+ case LogfsLogTtrunc:
+ takearisk = 1;
+ break;
+ default:
+ takearisk = 0;
+ }
+ }
+ else
+ takearisk = 0;
+ errmsg = logspace(server, active, takearisk, size, &p, nil);
+ if(errmsg)
+ return errmsg;
+ if(logfsconvS2M(s, p, size) != size)
+ return "bad conversion";
+ logdirty(server, active);
+ return nil;
+}
+
+int
+lognicesizeforwrite(LogfsServer *server, int active, u32int count, int muidlen)
+{
+ int rawspace;
+ LogSegment *seg;
+ if(count > LogDataLimit)
+ return 0;
+ seg = active ? server->activelog : server->sweptlog;
+ if(seg->curpage < 0)
+ return LogDataLimit;
+ rawspace = (1 << server->ll->l2pagesize) - seg->nbytes;
+ if(rawspace < 5 * 4 + 2 + muidlen + 1)
+ return LogDataLimit;
+ return 5 * 4 + 2 + muidlen - rawspace;
+}
+
+char *
+logfslogwrite(LogfsServer *server, int active, u32int path, u32int offset, int count, u32int mtime, u32int cvers,
+ char *muid, uchar *data, u32int *flashaddr)
+{
+ /* 'w' size[2] path[4] offset[4] count[2] mtime[4] cvers[4] muid[s] flashaddr[4] [data[n]] */
+ LogMessage s;
+ uint size;
+ char *errmsg;
+ uchar *p;
+ u32int faddr;
+ uint asize;
+
+ s.type = LogfsLogTwrite;
+ s.path = path;
+ s.u.write.offset = offset;
+ s.u.write.count = count;
+ s.u.write.mtime = mtime;
+ s.u.write.cvers = cvers;
+ s.u.write.muid = muid;
+ s.u.write.data = data;
+ size = logfssizeS2M(&s);
+ errmsg = logspace(server, active, 0, size, &p, &faddr);
+ if(errmsg)
+ return errmsg;
+ if(data)
+ *flashaddr = (faddr + size - count) | LogAddr;
+ s.u.write.flashaddr = *flashaddr;
+ if(server->trace > 1) {
+ print("%c<< ", active ? 'A' : 'S');
+ logfsdumpS(&s);
+ print("\n");
+ }
+ if((asize = logfsconvS2M(&s, p, size)) != size) {
+ print("expected %d actual %d\n", size, asize);
+ return "bad conversion";
+ }
+ logdirty(server, active);
+ return nil;
+}
+
--- /dev/null
+++ b/liblogfs/map.c
@@ -1,0 +1,139 @@
+#include "logfsos.h"
+#include "logfs.h"
+#include "local.h"
+
+typedef struct MapNode MapNode;
+
+struct MapNode {
+ MapNode *next;
+ uchar e[1]; // entry goes here, inline
+};
+
+struct Map {
+ int size;
+ int (*hash)(void *key, int size);
+ int (*compare)(void *entry, void *key);
+ int (*allocsize)(void *key);
+ void (*free)(void *entry);
+ MapNode *head[1];
+};
+
+char *
+logfsmapnew(int size, int (*hash)(void *key, int size), int (*compare)(void *entry, void *key), int (*allocsize)(void *key), void (*free)(void *), Map **mapp)
+{
+ Map *p;
+ *mapp = p = logfsrealloc(nil, sizeof(Map) + (size - 1) * sizeof(MapNode *));
+ if(p == nil)
+ return Enomem;
+ p->size = size;
+ p->hash = hash;
+ p->compare = compare;
+ p->allocsize = allocsize;
+ p->free = free;
+ return nil;
+}
+
+void
+logfsmapfree(FidMap **mp)
+{
+ FidMap *m;
+ int i;
+
+ m = *mp;
+ if(m == nil)
+ return;
+
+ for(i = 0; i < m->size; i++) {
+ MapNode *n, *next;
+ n = m->head[i];
+ while(n) {
+ next = n->next;
+ if(m->free)
+ (*m->free)(n->e);
+ logfsfreemem(n);
+ n = next;
+ }
+ }
+ logfsfreemem(m);
+ *mp = nil;
+}
+
+static char *
+find(FidMap *m, void *key, int create, void **ep)
+{
+ MapNode *n;
+ int i;
+
+ i = (*m->hash)(key, m->size);
+ n = m->head[i];
+ while(n && !(*m->compare)(n->e, key))
+ n = n->next;
+ if(n) {
+ if(create) {
+ *ep = nil;
+ return nil;
+ }
+ *ep = n->e;
+ return nil;
+ }
+ if(!create) {
+ *ep = nil;
+ return nil;
+ }
+ n = logfsrealloc(nil, (*m->allocsize)(key) + sizeof(MapNode *));
+ if(n == nil) {
+ *ep = nil;
+ return Enomem;
+ }
+ n->next = m->head[i];
+ m->head[i] = n;
+ *ep = n->e;
+ return nil;
+}
+
+void *
+logfsmapfindentry(Map *m, void *key)
+{
+ void *rv;
+ find(m, key, 0, &rv);
+ return rv;
+}
+
+char *
+logfsmapnewentry(Map *m, void *key, void **entryp)
+{
+ return find(m, key, 1, entryp);
+}
+
+int
+logfsmapdeleteentry(Map *m, void *key)
+{
+ MapNode **np, *n;
+ np = &m->head[(*m->hash)(key, m->size)];
+ while((n = *np) && !(*m->compare)(n->e, key))
+ np = &n->next;
+ if(n) {
+ *np = n->next;
+ if(m->free)
+ (*m->free)(n->e);
+ logfsfreemem(n);
+ return 1;
+ }
+ return 0; // not there
+}
+
+int
+logfsmapwalk(Map *m, int (*func)(void *magic, void *), void *magic)
+{
+ int x;
+ MapNode *n;
+
+ for(x = 0; x < m->size; x++)
+ for(n = m->head[x]; n; n = n->next) {
+ int rv = (*func)(magic, n->e);
+ if(rv <= 0)
+ return rv;
+ }
+ return 1;
+}
+
--- /dev/null
+++ b/liblogfs/mkfile
@@ -1,0 +1,45 @@
+<../mkconfig
+
+LIB=liblogfs.a
+
+OFILES= \
+ boot.$O\
+ clunk.$O\
+ conv.$O\
+ create.$O\
+ dump.$O\
+ error.$O\
+ extentlist.$O\
+ fidmap.$O\
+ findfreeblock.$O\
+ flush.$O\
+ format.$O\
+ gn.$O\
+ group.$O\
+ groupset.$O\
+ is.$O\
+ log.$O\
+ map.$O\
+ open.$O\
+ path.$O\
+ perm.$O\
+ read.$O\
+ remove.$O\
+ replace.$O\
+ replay.$O\
+ scan.$O\
+ srv.$O\
+ sweep.$O\
+ tagname.$O\
+ test.$O\
+ ust.$O\
+ walk.$O\
+ write.$O\
+ wstat.$O\
+
+HFILES=\
+ local.h \
+ $ROOT/include/logfs.h
+
+<$ROOT/mkfiles/mksyslib-$SHELLTYPE
+
--- /dev/null
+++ b/liblogfs/open.c
@@ -1,0 +1,72 @@
+#include "logfsos.h"
+#include "logfs.h"
+#include "local.h"
+
+char *
+logfsserveropen(LogfsServer *server, u32int fid, uchar mode, Qid *qid)
+{
+ Fid *f;
+ Entry *e;
+ ulong modemask;
+
+ if(server->trace > 1)
+ print("logfsserveropen(%ud, %d)\n", fid, mode);
+ f = logfsfidmapfindentry(server->fidmap, fid);
+ if(f == nil)
+ return logfsebadfid;
+ if(f->openmode >= 0)
+ return logfsefidopen;
+ e = f->entry;
+ SET(modemask);
+ switch(mode & 3) {
+ case OEXEC:
+ modemask = DMEXEC;
+ break;
+ case OREAD:
+ modemask = DMREAD;
+ break;
+ case OWRITE:
+ modemask = DMWRITE;
+ break;
+ case ORDWR:
+ modemask = DMWRITE | DMREAD;
+ break;
+ }
+ if(e->qid.type & QTDIR) {
+ if((modemask & DMWRITE) != 0 || (mode & (ORCLOSE | OTRUNC)) != 0)
+ return Eperm;
+ }
+ else {
+ if(mode & OTRUNC)
+ modemask |= DMWRITE;
+ if((mode & ORCLOSE) != 0 && !logfsuserpermcheck(server, e->parent, f, DMWRITE))
+ return Eperm;
+ }
+ if(!logfsuserpermcheck(server, e, f, modemask))
+ return Eperm;
+ if((e->qid.type & QTDIR) == 0 && (mode & OTRUNC) != 0 && (e->perm & DMAPPEND) == 0 && e->u.file.length != 0) {
+ LogMessage s;
+ char *errmsg;
+ s.type = LogfsLogTtrunc;
+ s.path = e->qid.path;
+ s.u.trunc.mtime = logfsnow();
+ s.u.trunc.cvers = e->u.file.cvers + 1;
+ s.u.trunc.muid = logfsisfindidfromname(server->is, f->uname);
+ errmsg = logfslog(server, 1, &s);
+ if(errmsg)
+ return errmsg;
+ e->muid = s.u.trunc.muid;
+ e->mtime = s.u.trunc.mtime;
+ e->qid.vers++;
+ e->u.file.cvers = s.u.trunc.cvers;
+ /*
+ * zap all data and extents
+ */
+ logfsextentlistwalk(e->u.file.extent, logfsunconditionallymarkfreeanddirty, server);
+ logfsextentlistreset(e->u.file.extent);
+ e->u.file.length = 0;
+ }
+ f->openmode = mode;
+ *qid = e->qid;
+ return nil;
+}
--- /dev/null
+++ b/liblogfs/path.c
@@ -1,0 +1,50 @@
+#include "logfsos.h"
+#include "logfs.h"
+#include "local.h"
+
+enum {
+ PATHMOD = 127
+};
+
+static int
+compare(void *a, void *b)
+{
+ Path *f = a;
+ ulong path = (ulong)b; /* sic */
+ return f->path == path;
+}
+
+static int
+allocsize(void *key)
+{
+ USED(key);
+ return sizeof(Path);
+}
+
+char *
+logfspathmapnew(PathMap **pathmapp)
+{
+ return logfsmapnew(PATHMOD, logfshashulong, compare, allocsize, nil, pathmapp);
+}
+
+char *
+logfspathmapnewentry(PathMap *m, ulong path, Entry *e, Path **pathmapp)
+{
+ char *errmsg;
+ errmsg = logfsmapnewentry(m, (void*)path, pathmapp);
+ if(errmsg)
+ return errmsg;
+ if(*pathmapp == nil)
+ return nil;
+ (*pathmapp)->path = path;
+ (*pathmapp)->entry = e;
+ return nil;
+}
+
+Entry *
+logfspathmapfinde(PathMap *m, ulong path)
+{
+ Path *p;
+ p = logfspathmapfindentry(m, path);
+ return p ? p->entry : nil;
+}
--- /dev/null
+++ b/liblogfs/perm.c
@@ -1,0 +1,25 @@
+#include "logfsos.h"
+#include "logfs.h"
+#include "local.h"
+
+int
+logfsuserpermcheck(LogfsServer *s, Entry *e, Fid *f, ulong permmask)
+{
+ if(s->openflags & LogfsOpenFlagNoPerm)
+ return 1;
+ if((e->perm & permmask) == permmask)
+ /* the whole world can do this */
+ return 1;
+ if(((e->perm >> 6) & permmask) == permmask) {
+ /* maybe we're the owner */
+ char *uname = logfsisfindnamefromid(s->is, e->uid);
+ if(uname == f->uname)
+ return 1;
+ }
+ if(((e->perm >> 3) & permmask) == permmask) {
+ /* maybe we're in the group */
+ Group *g = logfsisfindgroupfromid(s->is, e->gid);
+ return g && logfsisgroupunameismember(s->is, g, f->uname);
+ }
+ return 0;
+}
--- /dev/null
+++ b/liblogfs/read.c
@@ -1,0 +1,253 @@
+#include "logfsos.h"
+#include "logfs.h"
+#include "local.h"
+#include "fcall.h"
+
+struct DirReadState {
+ u32int offset;
+ u32int lastoffset;
+ u32int limit;
+ uchar *data;
+};
+
+typedef struct ReaderState {
+ uchar *buf;
+ u32int maxoffset;
+ LogfsServer *server;
+ char *errmsg;
+} ReaderState;
+
+static DirReadState *
+drsinit(LogfsIdentityStore *is, Entry *list, uchar *buf, u32int buflen, u32int *rcount)
+{
+ Entry *p, *q;
+ DirReadState *drs;
+ u32int k;
+ /*
+ * stash as many entries as will fit in the read buffer
+ */
+ *rcount = 0;
+ for(p = list; p; p = p->next) {
+ uint len = logfsflattenentry(is, buf, buflen, p);
+ if(len == 0)
+ break;
+ *rcount += len;
+ buf += len;
+ buflen -= len;
+ }
+ drs = logfsrealloc(nil, sizeof(*drs));
+ if(drs == nil)
+ return nil;
+ drs->offset = *rcount;
+ drs->lastoffset = drs->offset;
+ k = 0;
+ for(q = p; q; q = q->next)
+ k += logfsflattenentry(is, nil, 0, q);
+ if(k) {
+ u32int k2;
+// print("drsinit: %ud bytes extra\n", k);
+ drs->data = logfsrealloc(nil, k);
+ if(drs->data == nil) {
+ logfsfreemem(drs);
+ return nil;
+ }
+ k2 = 0;
+ for(q = p; q; q = q->next)
+ k2 += logfsflattenentry(is, drs->data + k2, k - k2, q);
+ drs->limit = drs->offset + k;
+ }
+// print("drsinit: rcount %ud\n", *rcount);
+ return drs;
+}
+
+static void
+drsread(DirReadState *drs, uchar *buf, u32int buflen, u32int *rcount)
+{
+ uchar *p;
+ *rcount = 0;
+ p = drs->data + drs->lastoffset - drs->offset;
+ while(drs->lastoffset < drs->limit) {
+ /*
+ * copy an entry, if it fits
+ */
+ uint len = GBIT16(p) + BIT16SZ;
+ if(len > buflen)
+ break;
+ memmove(buf, p, len);
+ drs->lastoffset += len;
+ *rcount += len;
+ buf += len;
+ buflen -= len;
+ p += len;
+ }
+ if(drs->lastoffset >= drs->limit) {
+ logfsfreemem(drs->data);
+ drs->data = nil;
+ }
+}
+
+void
+logfsdrsfree(DirReadState **drsp)
+{
+ DirReadState *drs = *drsp;
+ if(drs) {
+ logfsfreemem(drs->data);
+ logfsfreemem(drs);
+ *drsp = nil;
+ }
+}
+
+static int
+reader(void *magic, u32int baseoffset, u32int limitoffset, Extent *e, u32int extentoffset)
+{
+ ReaderState *s = magic;
+ LogfsServer *server;
+ LogfsLowLevel *ll;
+ LogfsLowLevelReadResult llrr;
+ long seq;
+ int page;
+ int offset;
+ long block;
+ int pagesize;
+ LogSegment *seg;
+ int replace;
+
+ if(e == nil) {
+//print("fill(%d, %d)\n", baseoffset, limitoffset);
+ memset(s->buf + baseoffset, 0, limitoffset - baseoffset);
+ if(limitoffset > s->maxoffset)
+ s->maxoffset = limitoffset;
+ return 1;
+ }
+ server = s->server;
+ ll = server->ll;
+ /*
+ * extentoffset is how much to trim off the front of the extent
+ */
+ logfsflashaddr2spo(server, e->flashaddr + extentoffset, &seq, &page, &offset);
+ /*
+ * offset is the offset within the page to where e->min is stored
+ */
+//print("read(%d, %d, %c%ld/%ud/%ud)\n",
+// baseoffset, limitoffset, (e->flashaddr & LogAddr) ? 'L' : 'D', seq, page, offset);
+ if(e->flashaddr & LogAddr) {
+ if(seq >= server->activelog->unsweptblockindex && seq <= server->activelog->curblockindex)
+ seg = server->activelog;
+ else if(server->sweptlog && seq <= server->sweptlog->curblockindex)
+ seg = server->sweptlog;
+ else {
+ print("logfsserverread: illegal log sequence number %ld (active=[%ld, %ld], swept=[%ld, %ld])\n",
+ seq, server->activelog->unsweptblockindex, server->activelog->curblockindex,
+ server->sweptlog ? 0L : -1L, server->sweptlog ? server->sweptlog->curblockindex : -1L);
+ s->errmsg = logfseinternal;
+ return -1;
+ }
+ if(seg->curpage == page && seg->curblockindex == seq) {
+ /*
+ * it hasn't made it to disk yet
+ */
+ memmove(s->buf + baseoffset, seg->pagebuf + offset, limitoffset - baseoffset);
+ goto done;
+ }
+ if(seq < seg->unsweptblockindex) {
+ /* data already swept */
+ print("logfsserverread: log address has been swept\n");
+ s->errmsg = logfseinternal;
+ return -1;
+ }
+ block = seg->blockmap[seq];
+ }
+ else {
+ seg = nil;
+ if(seq >= server->ndatablocks)
+ block = -1;
+ else
+ block = server->datablock[seq].block;
+ if(block < 0) {
+ print("logfsserveread: data address does not exist\n");
+ s->errmsg = logfseinternal;
+ return -1;
+ }
+ }
+ /*
+ * read as many pages as necessary to get to the limitoffset
+ */
+ pagesize = 1 << ll->l2pagesize;
+ replace = 0;
+ while(baseoffset < limitoffset) {
+ u32int thistime;
+ thistime = pagesize - offset;
+ if(thistime > (limitoffset - baseoffset))
+ thistime = limitoffset - baseoffset;
+ s->errmsg = (*ll->readpagerange)(ll, s->buf + baseoffset, block, page,
+ offset, thistime, &llrr);
+ if(s->errmsg)
+ return -1;
+ if(llrr != LogfsLowLevelReadResultOk) {
+ replace = 1;
+ }
+ baseoffset += thistime;
+ page++;
+ offset = 0;
+ }
+ if(replace) {
+ s->errmsg = logfsserverreplaceblock(server, seg, seq);
+ if(s->errmsg)
+ return -1;
+ }
+done:
+ if(limitoffset > s->maxoffset)
+ s->maxoffset = limitoffset;
+ return 1;
+}
+
+char *
+logfsserverread(LogfsServer *server, u32int fid, u32int offset, u32int count, uchar *buf, u32int buflen, u32int *rcount)
+{
+ Fid *f;
+ Entry *e;
+ ReaderState s;
+ int rv;
+
+ if(server->trace > 1)
+ print("logfsserverread(%ud, %ud, %ud)\n", fid, offset, count);
+ f = logfsfidmapfindentry(server->fidmap, fid);
+ if(f == nil)
+ return logfsebadfid;
+ if(f->openmode < 0)
+ return logfsefidnotopen;
+ if((f->openmode & 3) == OWRITE)
+ return logfseaccess;
+ if(count > buflen)
+ return Etoobig;
+ e = f->entry;
+ if(e->deadandgone)
+ return Eio;
+ if(e->qid.type & QTDIR) {
+ if(offset != 0) {
+ if(f->drs == nil || f->drs->lastoffset != offset)
+ return Eio;
+ drsread(f->drs, buf, count, rcount);
+ }
+ else {
+ logfsdrsfree(&f->drs);
+ f->drs = drsinit(server->is, e->u.dir.list, buf, count, rcount);
+ if(f->drs == nil)
+ return Enomem;
+ }
+ return nil;
+ }
+ if(offset >= e->u.file.length) {
+ *rcount = 0;
+ return nil;
+ }
+ s.buf = buf;
+ s.server = server;
+ s.maxoffset = 0;
+ rv = logfsextentlistwalkrange(e->u.file.extent, reader, &s, offset, offset + count);
+ if(rv < 0)
+ return s.errmsg;
+ *rcount = s.maxoffset;
+ return nil;
+}
+
--- /dev/null
+++ b/liblogfs/remove.c
@@ -1,0 +1,148 @@
+#include "logfsos.h"
+#include "logfs.h"
+#include "local.h"
+
+void
+logfsfreeanddirtydatablockcheck(LogfsServer *server, long seq)
+{
+ DataBlock *db;
+ Pageset mask, allpages;
+
+ if(seq >= server->ndatablocks)
+ return;
+ db = server->datablock + seq;
+ if(db->block < 0)
+ return;
+
+ mask = db->dirty & db->free;
+ if(mask) {
+ allpages = logfsdatapagemask(1 << server->ll->l2pagesperblock, 0);
+ if((mask & allpages) == allpages) {
+//print("logfsfreedatapages: returning block to the wild\n");
+ logfsbootfettleblock(server->lb, db->block, LogfsTnone, ~0, nil);
+ db->block = -1;
+ if(seq == server->ndatablocks - 1)
+ server->ndatablocks--;
+ }
+ }
+}
+
+void
+logfsfreedatapages(LogfsServer *server, long seq, Pageset mask)
+{
+ DataBlock *db;
+ if(seq >= server->ndatablocks)
+ return;
+ db = server->datablock + seq;
+ if(db->block < 0)
+ return;
+//print("logfsfreedatapages: index %ld mask 0x%.8ux\n", seq, mask);
+ db->dirty |= mask;
+ db->free |= mask;
+ logfsfreeanddirtydatablockcheck(server, seq);
+}
+
+int
+logfsunconditionallymarkfreeanddirty(void *magic, Extent *e, int hole)
+{
+ if(!hole && (e->flashaddr & LogAddr) == 0) {
+ LogfsServer *server = magic;
+ LogfsLowLevel *ll = server->ll;
+ DataBlock *db;
+ long blockindex;
+ int page, offset, npages;
+ Pageset mask;
+
+ logfsflashaddr2spo(server, e->flashaddr, &blockindex, &page, &offset);
+ if(blockindex < server->ndatablocks && (db = server->datablock + blockindex)->block >= 0) {
+ npages = ((offset + e->max - e->min) + (1 << ll->l2pagesize) - 1) >> ll->l2pagesize;
+ mask = logfsdatapagemask(npages, page);
+ if((db->dirty & mask) != mask)
+ print("markfreeandirty: not all pages dirty\n");
+//print("markfreeanddirty: datablock %ld mask 0x%.8ux\n", blockindex, mask);
+ logfsfreedatapages(server, blockindex, mask);
+ }
+ else
+ print("markfreeanddirty: data block index %ld invalid\n", blockindex);
+ }
+ return 1;
+}
+
+char *
+logfsserverremove(LogfsServer *server, u32int fid)
+{
+ Fid *f;
+ char *errmsg;
+ Entry *parent;
+ Entry *e, **ep;
+ ulong now;
+ char *uid;
+ LogMessage s;
+
+ if(server->trace > 1)
+ print("logfsserverremove(%ud)\n", fid);
+ f = logfsfidmapfindentry(server->fidmap, fid);
+ if(f == nil) {
+ errmsg = logfsebadfid;
+ goto clunk;
+ }
+ if((f->openmode & 3) == OWRITE) {
+ errmsg = logfseaccess;
+ goto clunk;
+ }
+ parent = f->entry->parent;
+ if(parent == f->entry) {
+ errmsg = Eperm;
+ goto clunk;
+ }
+ if((parent->qid.type & QTDIR) == 0) {
+ errmsg = logfseinternal;
+ goto clunk;
+ }
+ if(!logfsuserpermcheck(server, parent, f, DMWRITE)) {
+ errmsg = Eperm;
+ goto clunk;
+ }
+ if((f->entry->qid.type & QTDIR) != 0 && f->entry->u.dir.list) {
+ errmsg = logfsenotempty;
+ goto clunk;
+ }
+ if(f->entry->deadandgone) {
+ errmsg = Eio;
+ goto clunk;
+ }
+ for(ep = &parent->u.dir.list; e = *ep; ep = &e->next)
+ if(e == f->entry)
+ break;
+ if(e == nil) {
+ errmsg = logfseinternal;
+ goto clunk;
+ }
+ now = logfsnow();
+ uid = logfsisfindidfromname(server->is, f->uname);
+ /* log it */
+ s.type = LogfsLogTremove;
+ s.path = e->qid.path;
+ s.u.remove.mtime = e->mtime;
+ s.u.remove.muid = e->muid;
+ errmsg = logfslog(server, 1, &s);
+ if(errmsg)
+ goto clunk;
+ parent->mtime = now;
+ parent->muid = uid;
+ logfspathmapdeleteentry(server->pathmap, e->qid.path);
+ *ep = e->next; /* so open can't find it */
+ e->deadandgone = 1; /* so that other fids don't work any more */
+ /*
+ * lose the storage now, as deadandgone will prevent access
+ */
+ if((e->qid.type & QTDIR) == 0) {
+ logfsextentlistwalk(e->u.file.extent, logfsunconditionallymarkfreeanddirty, server);
+ logfsextentlistfree(&e->u.file.extent);
+ }
+ e->inuse--; /* so that the entryclunk removes the storage */
+ errmsg = nil;
+clunk:
+ logfsfidmapclunk(server->fidmap, fid);
+ return errmsg;
+}
--- /dev/null
+++ b/liblogfs/replace.c
@@ -1,0 +1,171 @@
+#include "logfsos.h"
+#include "logfs.h"
+#include "local.h"
+#include "fcall.h"
+
+static char *
+copypages(LogfsServer *server, long newb, long oldb, Pageset copymask, LogfsLowLevelReadResult *llrrp, int *markedbadp)
+{
+ char *errmsg;
+ int page;
+ LogfsLowLevel *ll;
+ int ppb;
+ int pagesize;
+ uchar *buf;
+
+ if(copymask == 0)
+ return nil;
+
+ ll = server->ll;
+ ppb = 1 << ll->l2pagesperblock;
+ pagesize = 1 << ll->l2pagesize;
+ *markedbadp = 0;
+ *llrrp = LogfsLowLevelReadResultOk;
+ errmsg = nil;
+
+ buf = logfsrealloc(nil, 1 << ll->l2pagesize);
+ if(buf == nil)
+ return Enomem;
+
+ for(page = ppb - 1; page >= 0; page--) {
+ Pageset m;
+
+ m = logfsdatapagemask(1, page);
+
+ if(copymask & m) {
+ LogfsLowLevelReadResult llrr;
+ if(server->trace > 1)
+ print("copypages read page %d\n", page);
+ errmsg = (*ll->readpagerange)(ll, buf, oldb, page, 0, pagesize, &llrr);
+ if(errmsg != nil)
+ break;
+ if(llrr > *llrrp)
+ *llrrp = llrr;
+ if(server->trace > 1)
+ print("copypages write page %d\n", page);
+ errmsg = (*ll->writepage)(ll, buf, newb, page);
+ if(errmsg) {
+ if(strcmp(errmsg, Eio) == 0) {
+ (*ll->markblockbad)(ll, newb);
+ *markedbadp = 1;
+ }
+ break;
+ }
+ if(server->trace > 1)
+ print("copypages end page %d\n", page);
+ }
+ }
+ logfsfreemem(buf);
+ return errmsg;
+}
+
+char *
+logfsservercopyactivedata(LogfsServer *server, long newb, long oldblockindex, int forcepage0, LogfsLowLevelReadResult *llrrp, int *markedbadp)
+{
+ LogfsLowLevel *ll = server->ll;
+ ulong newpath;
+ DataBlock *ob;
+ char *errmsg;
+ Pageset copymask;
+
+ ob = server->datablock + oldblockindex;
+ copymask = ~ob->free;
+ if(forcepage0)
+ copymask |= logfsdatapagemask(1, 0);
+ if(server->trace > 1)
+ print("copyactivedata %ld: (%ld -> %ld)\n", oldblockindex, ob->block, newb);
+ newpath = mkdatapath(dataseqof(ob->path), copygensucc(copygenof(ob->path)));
+ (*ll->setblocktag)(ll, newb, LogfsTdata);
+ (*ll->setblockpath)(ll, newb, newpath);
+ errmsg = copypages(server, newb, ob->block, copymask, llrrp, markedbadp);
+ if(errmsg)
+ return errmsg;
+ /*
+ * anything not copied is now not dirty
+ */
+ ob->dirty &= copymask;
+ ob->block = newb;
+ ob->path = newpath;
+ return nil;
+}
+
+/*
+ * unconditionally replace a datablock, and mark the old one bad
+ * NB: if page 0 is apparently unused, force it to be copied, and mark
+ * it free and dirty afterwards
+ */
+char *
+logfsserverreplacedatablock(LogfsServer *server, long index)
+{
+ long newb;
+ LogfsLowLevel *ll = server->ll;
+
+ newb = logfsfindfreeblock(ll, AllocReasonReplace);
+ /* TODO - recover space by scavenging other blocks, or recycling the log */
+ while(newb >= 0) {
+ char *errmsg;
+ LogfsLowLevelReadResult llrr;
+ long oldblock;
+ int markedbad;
+ DataBlock *db;
+
+ db = server->datablock + index;
+ oldblock = db->block;
+ errmsg = logfsservercopyactivedata(server, newb, index, 1, &llrr, &markedbad);
+ if(errmsg) {
+ if(!markedbad)
+ return errmsg;
+ newb = logfsfindfreeblock(ll, AllocReasonReplace);
+ continue;
+ }
+ (*ll->markblockbad)(ll, oldblock);
+ return nil;
+ }
+ return logfsefullreplacing;
+}
+
+char *
+logfsserverreplacelogblock(LogfsServer *server, LogSegment *seg, long index)
+{
+ ulong opath;
+ LogfsLowLevel *ll = server->ll;
+ long oldb = seg->blockmap[index];
+
+ opath = (*ll->getblockpath)(ll, oldb);
+
+ for(;;) {
+ long newb;
+ int pages;
+ char *errmsg;
+ LogfsLowLevelReadResult llrr;
+ int markedbad;
+
+ newb = logfsfindfreeblock(ll, AllocReasonReplace);
+ if(newb < 0)
+ return "full replacing log block";
+ /* TODO - scavenge data space for a spare block */
+ (*ll->setblocktag)(ll, newb, LogfsTlog);
+ (*ll->setblockpath)(ll, newb, mklogpath(seg->gen, index, copygensucc(copygenof(opath))));
+ if(index == seg->curblockindex)
+ pages = seg->curpage;
+ else
+ pages = 1 << server->ll->l2pagesperblock;
+ errmsg = copypages(server, newb, oldb, logfsdatapagemask(pages, 0), &llrr, &markedbad);
+ if(errmsg == nil) {
+ (*ll->markblockbad)(ll, seg->blockmap[index]);
+ seg->blockmap[index] = newb;
+ return nil;
+ }
+ if(!markedbad)
+ return errmsg;
+ }
+}
+
+char *
+logfsserverreplaceblock(LogfsServer *server, LogSegment *seg, long index)
+{
+ if(seg)
+ return logfsserverreplacelogblock(server, seg, index);
+ else
+ return logfsserverreplacedatablock(server, index);
+}
--- /dev/null
+++ b/liblogfs/replay.c
@@ -1,0 +1,386 @@
+#include "logfsos.h"
+#include "logfs.h"
+#include "local.h"
+#include "fcall.h"
+
+static void
+maxpath(LogfsServer *server, ulong p)
+{
+ if(p > server->path)
+ server->path = p;
+}
+
+static char *
+recreate(LogfsServer *server, LogMessage *s, int *ok)
+{
+ Entry *parent;
+ char *errmsg;
+ Entry *e;
+ Path *p;
+
+ parent = logfspathmapfinde(server->pathmap, s->path);
+ if(parent == nil)
+ return "can't find parent";
+ if(logfspathmapfindentry(server->pathmap, s->u.create.newpath) != nil){
+ Entry *d = logfspathmapfinde(server->pathmap, s->u.create.newpath);
+ if(d == nil)
+ print("existing was nil\n");
+ else{
+ print("existing: name=%q d=%d path=%8.8llux uid=%q gid=%q perm=%#uo\n",
+ d->name, d->deadandgone, d->qid.path, d->uid, d->gid, d->perm);
+ }
+ return "duplicate path";
+ }
+ if((parent->qid.type & QTDIR) == 0)
+ return Enotdir;
+ errmsg = logfsentrynew(server, 1, s->u.create.newpath, parent,
+ s->u.create.name, s->u.create.uid, s->u.create.gid, s->u.create.mtime, s->u.create.uid,
+ s->u.create.perm, s->u.create.cvers, 0, &e);
+ if(errmsg) {
+ *ok = 0;
+ return errmsg;
+ }
+ /* p guaranteed to be non null */
+ errmsg = logfspathmapnewentry(server->pathmap, s->u.create.newpath, e, &p);
+ if(errmsg) {
+ logfsfreemem(e);
+ *ok = 0;
+ return errmsg;
+ }
+ e->next = parent->u.dir.list;
+ parent->u.dir.list = e;
+ return nil;
+}
+
+static char *
+reremove(LogfsServer *server, LogMessage *s, int *ok)
+{
+ Entry *oe;
+ Entry *parent;
+ Entry **ep;
+ Entry *e;
+ char *ustmuid;
+
+ USED(ok);
+ oe = logfspathmapfinde(server->pathmap, s->path);
+ if(oe == nil)
+ return logfseunknownpath;
+ parent = oe->parent;
+ if(parent == oe)
+ return "tried to remove root";
+ if((parent->qid.type & QTDIR) == 0)
+ return Enotdir;
+ if((oe->qid.type & QTDIR) != 0 && oe->u.dir.list)
+ return logfsenotempty;
+ for(ep = &parent->u.dir.list; e = *ep; ep = &e->next)
+ if(e == oe)
+ break;
+ if(e == nil)
+ return logfseinternal;
+ ustmuid = logfsisustadd(server->is, s->u.remove.muid);
+ if(ustmuid == nil)
+ return Enomem;
+ parent->mtime = s->u.remove.mtime;
+ parent->muid = ustmuid;
+ logfspathmapdeleteentry(server->pathmap, s->path);
+ *ep = e->next;
+ if(e->inuse > 1) {
+ print("replay: entry inuse > 1\n");
+ e->inuse = 1;
+ }
+ logfsentryclunk(e);
+ return nil;
+}
+
+static char *
+retrunc(LogfsServer *server, LogMessage *s, int *ok)
+{
+ Entry *e;
+ char *ustmuid;
+
+ USED(ok);
+ e = logfspathmapfinde(server->pathmap, s->path);
+ if(e == nil)
+ return logfseunknownpath;
+ if((e->qid.type & QTDIR) != 0)
+ return Eperm;
+ if(e->u.file.cvers >= s->u.trunc.cvers)
+ return "old news";
+ ustmuid = logfsisustadd(server->is, s->u.trunc.muid);
+ if(ustmuid == nil)
+ return Enomem;
+ e->muid = ustmuid;
+ e->mtime = s->u.trunc.mtime;
+ e->qid.vers++;
+ e->u.file.cvers = s->u.trunc.cvers;
+ /*
+ * zap all extents
+ */
+ logfsextentlistreset(e->u.file.extent);
+ e->u.file.length = 0;
+ return nil;
+}
+
+static char *
+rewrite(LogfsServer *server, LogMessage *s, int *ok)
+{
+ Entry *e;
+ char *ustmuid;
+ Extent extent;
+ char *errmsg;
+
+ USED(ok);
+ e = logfspathmapfinde(server->pathmap, s->path);
+ if(e == nil)
+ return logfseunknownpath;
+ if((e->qid.type & QTDIR) != 0)
+ return Eperm;
+ if(e->u.file.cvers != s->u.write.cvers)
+ return nil;
+ ustmuid = logfsisustadd(server->is, s->u.write.muid);
+ if(ustmuid == nil)
+ return Enomem;
+ extent.min = s->u.write.offset;
+ extent.max = s->u.write.offset + s->u.write.count;
+ extent.flashaddr = s->u.write.flashaddr;
+ errmsg = logfsextentlistinsert(e->u.file.extent, &extent, nil);
+ if(errmsg)
+ return errmsg;
+ e->mtime = s->u.write.mtime;
+ e->muid = ustmuid;
+ if(extent.max > e->u.file.length)
+ e->u.file.length = extent.max;
+ /* TODO forsyth increments vers here; not sure whether necessary */
+ return nil;
+}
+
+static char *
+rewstat(LogfsServer *server, LogMessage *s, int *ok)
+{
+ Entry *e;
+ char *errmsg;
+ char *cname, *ustgid, *ustmuid;
+ char *ustuid;
+
+ USED(ok);
+ e = logfspathmapfinde(server->pathmap, s->path);
+ if(e == nil)
+ return logfseunknownpath;
+ cname = nil;
+ ustuid = nil;
+ ustgid = nil;
+ ustmuid = nil;
+ if(s->u.wstat.name) {
+ cname = logfsstrdup(s->u.wstat.name);
+ if(cname == nil) {
+ memerror:
+ errmsg = Enomem;
+ goto fail;
+ }
+ }
+ if(s->u.wstat.uid) {
+ ustuid = logfsisustadd(server->is, s->u.wstat.uid);
+ if(ustuid == nil)
+ goto memerror;
+ }
+ if(s->u.wstat.gid) {
+ ustgid = logfsisustadd(server->is, s->u.wstat.gid);
+ if(ustgid == nil)
+ goto memerror;
+ }
+ if(s->u.wstat.muid) {
+ ustmuid = logfsisustadd(server->is, s->u.wstat.muid);
+ if(ustmuid == nil)
+ goto memerror;
+ }
+ if(cname) {
+ logfsfreemem(e->name);
+ e->name = cname;
+ cname = nil;
+ }
+ if(ustuid)
+ e->uid = ustuid;
+ if(ustgid)
+ e->gid = ustgid;
+ if(ustmuid)
+ e->muid = ustmuid;
+ if(s->u.wstat.perm != ~0)
+ e->perm = (e->perm & DMDIR) | (s->u.wstat.perm & ~DMDIR);
+ if(s->u.wstat.mtime != ~0)
+ e->mtime = s->u.wstat.mtime;
+ errmsg = nil;
+fail:
+ logfsfreemem(cname);
+ return errmsg;
+}
+
+static char *
+replayblock(LogfsServer *server, LogSegment *seg, uchar *buf, long i, int *pagep, int disableerrors)
+{
+ int page;
+ LogfsLowLevel *ll = server->ll;
+ LogfsLowLevelReadResult llrr;
+ ushort size;
+ LogMessage s;
+ int ppb = 1 << ll->l2pagesperblock;
+ int pagesize = 1 << ll->l2pagesize;
+
+ for(page = 0; page < ppb; page++) {
+ uchar *p, *bufend;
+ char *errmsg = (*ll->readpagerange)(ll, buf, seg->blockmap[i], page, 0, pagesize, &llrr);
+ if(errmsg)
+ return errmsg;
+ if(llrr != LogfsLowLevelReadResultOk)
+ logfsserverreplacelogblock(server, seg, i);
+ /* ignore failure to replace block */
+ if(server->trace > 1)
+ print("replaying seq %ld block %ld page %d\n", i, seg->blockmap[i], page);
+ p = buf;
+ if(*p == 0xff)
+ break;
+ bufend = p + pagesize;
+ while(p < bufend) {
+ int ok = 1;
+ size = logfsconvM2S(p, bufend - p, &s);
+ if(size == 0)
+ return "parse failure";
+ if(server->trace > 1) {
+ print(">> ");
+ logfsdumpS(&s);
+ print("\n");
+ }
+ if(s.type == LogfsLogTend)
+ break;
+ switch(s.type) {
+ case LogfsLogTstart:
+ break;
+ case LogfsLogTcreate:
+ maxpath(server, s.path);
+ maxpath(server, s.u.create.newpath);
+ errmsg = recreate(server, &s, &ok);
+ break;
+ case LogfsLogTtrunc:
+ maxpath(server, s.path);
+ errmsg = retrunc(server, &s, &ok);
+ break;
+ case LogfsLogTremove:
+ maxpath(server, s.path);
+ errmsg = reremove(server, &s, &ok);
+ break;
+ case LogfsLogTwrite:
+ maxpath(server, s.path);
+ errmsg = rewrite(server, &s, &ok);
+ break;
+ case LogfsLogTwstat:
+ maxpath(server, s.path);
+ errmsg = rewstat(server, &s, &ok);
+ break;
+ default:
+ return "bad tag in log page";
+ }
+ if(!ok)
+ return errmsg;
+ if(errmsg && !disableerrors){
+ print("bad replay: %s\n", errmsg);
+ print("on: "); logfsdumpS(&s); print("\n");
+ }
+ p += size;
+ }
+ }
+ *pagep = page;
+ return nil;
+}
+
+static int
+map(void *magic, Extent *x, int hole)
+{
+ LogfsServer *server;
+ LogfsLowLevel *ll;
+ long seq;
+ int page;
+ int offset;
+ Pageset mask;
+ DataBlock *db;
+
+ if(hole || (x->flashaddr & LogAddr) != 0)
+ return 1;
+ server = magic;
+ ll = server->ll;
+ logfsflashaddr2spo(server, x->flashaddr, &seq, &page, &offset);
+ if(seq >= server->ndatablocks || (db = server->datablock + seq)->block < 0) {
+ print("huntfordata: seq %ld invalid\n", seq);
+ return 1;
+ }
+ mask = logfsdatapagemask((x->max - x->min + offset + (1 << ll->l2pagesize) - 1) >> ll->l2pagesize, page);
+//print("mask 0x%.8ux free 0x%.8ux dirty 0x%.8ux\n", mask, db->free, db->dirty);
+ if((db->free & mask) != mask)
+ print("huntfordata: data referenced more than once: block %ld(%ld) free 0x%.8llux mask 0x%.8llux\n",
+ seq, db->block, (u64int)db->free, (u64int)mask);
+ db->free &= ~mask;
+ db->dirty |= mask;
+ return 1;
+}
+
+static void
+huntfordatainfile(LogfsServer *server, Entry *e)
+{
+ logfsextentlistwalk(e->u.file.extent, map, server);
+}
+
+static void
+huntfordataindir(LogfsServer *server, Entry *pe)
+{
+ Entry *e;
+ for(e = pe->u.dir.list; e; e = e->next)
+ if(e->qid.type & QTDIR)
+ huntfordataindir(server, e);
+ else
+ huntfordatainfile(server, e);
+}
+
+char *
+logfsreplay(LogfsServer *server, LogSegment *seg, int disableerrorsforfirstblock)
+{
+ uchar *buf;
+ long i;
+ int page;
+ char *errmsg;
+
+ if(seg == nil || seg->curblockindex < 0)
+ return nil;
+ buf = logfsrealloc(nil, 1 << server->ll->l2pagesize);
+ if(buf == nil)
+ return Enomem;
+ for(i = 0; i <= seg->curblockindex; i++) {
+ errmsg = replayblock(server, seg, buf, i, &page, disableerrorsforfirstblock);
+ disableerrorsforfirstblock = 0;
+ if(errmsg) {
+ print("logfsreplay: error: %s\n", errmsg);
+ goto fail;
+ }
+ }
+ /*
+ * if the last block ended early, restart at the first free page
+ */
+ if(page < (1 << server->ll->l2pagesperblock))
+ seg->curpage = page;
+ errmsg = nil;
+fail:
+ logfsfreemem(buf);
+ return errmsg;
+}
+
+void
+logfsreplayfinddata(LogfsServer *server)
+{
+ huntfordataindir(server, &server->root);
+ if(server->trace > 0) {
+ long i;
+ DataBlock *db;
+ for(i = 0, db = server->datablock; i < server->ndatablocks; i++, db++) {
+ logfsfreeanddirtydatablockcheck(server, i);
+ if(db->block >= 0)
+ print("%4ld: free 0x%.8llux dirty 0x%.8llux\n", i, (u64int)server->datablock[i].free, (u64int)server->datablock[i].dirty);
+ }
+ }
+}
--- /dev/null
+++ b/liblogfs/scan.c
@@ -1,0 +1,293 @@
+#include "logfsos.h"
+#include "logfs.h"
+#include "local.h"
+#include "fcall.h"
+
+typedef struct PathEnt {
+ ulong path;
+ long block;
+} PathEnt;
+
+typedef struct GenInfo {
+ long start;
+ long end;
+ int gaps;
+} GenInfo;
+
+static int
+dataorder(ulong p1, ulong p2)
+{
+ int o;
+ o = dataseqof(p1) - dataseqof(p2);
+ if(o != 0)
+ return o;
+ return copygenof(p1) - copygenof(p2);
+}
+
+static int
+logorder(ulong p1, ulong p2)
+{
+ int o;
+ o = loggenof(p1) - loggenof(p2);
+ if(o != 0)
+ return o;
+ o = logseqof(p1) - logseqof(p2);
+ if(o != 0)
+ return o;
+ return copygenof(p1) - copygenof(p2);
+}
+
+static void
+insert(PathEnt *pathmap, long entries, ulong path, long block, int (*order)(ulong p1, ulong p2))
+{
+ long i;
+ for(i = 0; i < entries; i++)
+ if((*order)(path, pathmap[i].path) < 0)
+ break;
+ memmove(&pathmap[i + 1], &pathmap[i], (entries - i) * sizeof(PathEnt));
+ pathmap[i].path = path;
+ pathmap[i].block = block;
+}
+
+static void
+populate(LogSegment *seg, int gen, long unsweptblockindex, long curblockindex, PathEnt *pathent)
+{
+ long i;
+ seg->gen = gen;
+ seg->unsweptblockindex = unsweptblockindex;
+ seg->curblockindex = curblockindex;
+ for(i = unsweptblockindex; i <= curblockindex; i++) {
+// print("populate %d: %d\n", i, pathent[i - unsweptblockindex].block);
+ seg->blockmap[i] = pathent->block;
+ pathent++;
+ }
+}
+
+static int
+dataduplicate(PathEnt *p1, PathEnt *p2)
+{
+ return dataseqof(p2->path) == dataseqof(p1->path)
+ && copygenof(p2->path) == copygensucc(copygenof(p1->path));
+}
+
+static char *
+eliminateduplicates(LogfsServer *server, char *name, PathEnt *map, long *entriesp)
+{
+ long i;
+ long k = *entriesp;
+ for(i = 0; i < k;) {
+ PathEnt *prev = &map[i - 1];
+ PathEnt *this = &map[i];
+ if(i > 0 && dataduplicate(prev, this)) {
+ print("%s duplicate detected\n", name);
+ if(i + 1 < k && dataduplicate(this, &map[i + 1]))
+ return "three or more copies of same block";
+ /*
+ * check that the copy generations are in order
+ */
+ if(copygensucc(copygenof(this->path)) == copygenof(prev->path)) {
+ PathEnt m;
+ /*
+ * previous entry is newer, so swap
+ */
+ m = *this;
+ *this = *prev;
+ *prev = m;
+ }
+ else if(copygensucc(copygenof(prev->path)) != copygenof(this->path))
+ return "duplicate blocks but copy generations not sequential";
+ /* erase and format previous block */
+ logfsbootfettleblock(server->lb, prev->block, LogfsTnone, ~0, nil);
+ /*
+ * remove entry from table
+ */
+ memmove(prev, this, sizeof(PathEnt) * (k - i));
+ k--;
+ continue;
+ }
+ i++;
+ }
+ *entriesp = k;
+ return nil;
+}
+
+char *
+logfsscan(LogfsServer *server)
+{
+ LogfsLowLevel *ll = server->ll;
+ long b;
+ long i;
+ long logfound = 0;
+ long datafound = 0;
+ PathEnt *logpathmap, *datapathmap;
+ GenInfo geninfo[1 << L2LogSweeps];
+ int gensfound, lastgenfound;
+ int g0, g1;
+ char *errmsg;
+//print("logfsscan %ld blocks\n", server->ll->blocks);
+ logpathmap = logfsrealloc(nil, sizeof(PathEnt) * server->ll->blocks);
+ datapathmap = logfsrealloc(nil, sizeof(PathEnt) * server->ll->blocks);
+ if(logpathmap == nil || datapathmap == nil)
+ return Enomem;
+ for(b = 0; b < ll->blocks; b++) {
+ short tag = (*ll->getblocktag)(ll, b);
+ ulong path = (*ll->getblockpath)(ll, b);
+//print("scan: %ld: %d %ld\n", b, tag, path);
+ switch(tag) {
+ case LogfsTlog:
+ insert(logpathmap, logfound++, path, b, logorder);
+ break;
+ case LogfsTdata:
+ insert(datapathmap, datafound++, path, b, dataorder);
+ break;
+ }
+ }
+ if(server->trace > 1) {
+ for(i = 0; i < logfound; i++)
+ print("log gen %lud seq %lud copygen %lud block %ld\n",
+ loggenof(logpathmap[i].path), logseqof(logpathmap[i].path), copygenof(datapathmap[i].path), logpathmap[i].block);
+ for(i = 0; i < datafound; i++)
+ print("data seq %lud copygen %lud block %ld\n",
+ dataseqof(datapathmap[i].path), copygenof(datapathmap[i].path), datapathmap[i].block);
+ }
+ /*
+ * sort out data first
+ */
+ errmsg = eliminateduplicates(server, "data", datapathmap, &datafound);
+ if(errmsg)
+ goto fail;
+ /*
+ * data blocks guaranteed to be ordered
+ */
+ if(datafound)
+ server->ndatablocks = dataseqof(datapathmap[datafound - 1].path) + 1;
+ else
+ server->ndatablocks = 0;
+ for(i = 0; i < server->ndatablocks; i++)
+ server->datablock[i].block = -1;
+ for(i = 0; i < datafound; i++) {
+ long j;
+ j = dataseqof(datapathmap[i].path);
+ server->datablock[j].path = datapathmap[i].path;
+ server->datablock[j].block = datapathmap[i].block;
+ /*
+ * mark pages as free and dirty, which indicates they cannot be used
+ */
+ server->datablock[j].dirty = server->datablock[j].free = logfsdatapagemask(1 << ll->l2pagesperblock, 0);
+ }
+ /*
+ * find how many generations are present, and whether there are any gaps
+ */
+ errmsg = eliminateduplicates(server, "log", logpathmap, &logfound);
+ if(errmsg)
+ goto fail;
+ gensfound = 0;
+ lastgenfound = -1;
+ for(i = 0; i < nelem(geninfo); i++)
+ geninfo[i].start = -1;
+ for(i = 0; i < logfound; i++) {
+ int gen;
+ gen = loggenof(logpathmap[i].path);
+ if(geninfo[gen].start < 0) {
+ if(lastgenfound >= 0)
+ geninfo[lastgenfound].end = i;
+ geninfo[gen].start = i;
+ lastgenfound = gen;
+ geninfo[gen].gaps = 0;
+ gensfound++;
+ }
+ else if(!geninfo[lastgenfound].gaps && logseqof(logpathmap[i - 1].path) + 1 != logseqof(logpathmap[i].path)) {
+ geninfo[lastgenfound].gaps = 1;
+ print("generation %d has gaps (%lud, %lud)\n", lastgenfound,
+ logseqof(logpathmap[i - 1].path), logseqof(logpathmap[i].path));
+ }
+ }
+ if(lastgenfound >= 0)
+ geninfo[lastgenfound].end = i;
+ if(server->trace > 1) {
+ for(i = 0; i < nelem(geninfo); i++)
+ print("geninfo: %ld: start %ld end %ld gaps %d\n", i, geninfo[i].start, geninfo[i].end, geninfo[i].gaps);
+ }
+ switch(gensfound) {
+ case 0:
+ /* active log - empty */
+ break;
+ case 1:
+ /*
+ * one log, active
+ */
+ for(g0 = 0; g0 < nelem(geninfo); g0++)
+ if(geninfo[g0].start >= 0)
+ break;
+ if(geninfo[g0].gaps || geninfo[g0].start != 0) {
+ errmsg = "missing log blocks";
+ goto fail;
+ }
+ populate(server->activelog, g0, 0, geninfo[g0].end - geninfo[g0].start - 1, logpathmap + geninfo[g0].start);
+ break;
+ case 2:
+ /*
+ * two logs, active, swept
+ */
+ g0 = -1;
+ for(g1 = 0; g1 < nelem(geninfo); g1++)
+ if(geninfo[g1].start >= 0) {
+ if(g0 < 0)
+ g0 = g1;
+ else
+ break;
+ }
+ if(geninfo[g0].gaps || geninfo[g1].gaps) {
+ errmsg = "missing log blocks";
+ goto fail;
+ }
+ if(g0 == loggensucc(g1)) {
+ int tmp = g0;
+ g0 = g1;
+ g1 = tmp;
+ }
+ else if(g1 != loggensucc(g0)) {
+ errmsg = "nonsequential generations in log";
+ goto fail;
+ }
+ if(logseqof(logpathmap[geninfo[g1].start].path) != 0) {
+ errmsg = "swept log does not start at 0";
+ goto fail;
+ }
+ if(logseqof(logpathmap[geninfo[g0].start].path) == logseqof(logpathmap[geninfo[g1].end - 1].path)) {
+ /*
+ * duplicate block
+ * as the log never gets bigger, information from active[n] is either entirely in swept[n],
+ * or split between swept[n-1] and swept[n]. we can safely remove swept[n]. this might
+ * leave some duplication between swept[n - 1] and active[n], but this is always true
+ * for a partially swept log
+ */
+ logfsbootfettleblock(server->lb, logpathmap[geninfo[g1].end - 1].block, LogfsTnone, ~0, nil);
+ geninfo[g1].end--;
+ }
+ if(logseqof(logpathmap[geninfo[g0].start].path) < logseqof(logpathmap[geninfo[g1].end - 1].path)) {
+ errmsg = "active log overlaps end of swept log";
+ goto fail;
+ }
+ populate(server->activelog, g0, logseqof(logpathmap[geninfo[g0].start].path),
+ logseqof(logpathmap[geninfo[g0].end - 1].path), logpathmap + geninfo[g0].start);
+ if(server->sweptlog == nil) {
+ errmsg = logfslogsegmentnew(server, g1, &server->sweptlog);
+ if(errmsg)
+ goto fail;
+ }
+ populate(server->sweptlog, g1, logseqof(logpathmap[geninfo[g1].start].path),
+ logseqof(logpathmap[geninfo[g1].end - 1].path), logpathmap + geninfo[g1].start);
+ break;
+ default:
+ errmsg = "more than two generations in log";
+ goto fail;
+ }
+ goto ok;
+fail:
+ logfslogsegmentfree(&server->sweptlog);
+ok:
+ logfsfreemem(logpathmap);
+ logfsfreemem(datapathmap);
+ return errmsg;
+}
--- /dev/null
+++ b/liblogfs/srv.c
@@ -1,0 +1,308 @@
+#include "logfsos.h"
+#include "logfs.h"
+#include "fcall.h"
+#include "local.h"
+
+static char *unimp = "unimplemented";
+char *logfsbadfid = "invalid fid";
+
+char *
+logfsstrdup(char *p)
+{
+ int l;
+ char *q;
+ if(p == nil)
+ return nil;
+ l = strlen(p);
+ q = logfsrealloc(nil, l + 1);
+ if(q == nil)
+ return nil;
+ return strcpy(q, p);
+}
+
+static
+mkdirentry(LogfsServer *server, Entry *e, int inuse, ulong path, Entry *parent, char *name, char *uid, char *gid,
+ ulong mtime, char *muid, ulong perm)
+{
+//print("mkdirentry 0x%.8lux\n", e);
+ e->inuse = inuse;
+ e->qid.path = path;
+ e->qid.vers = 0;
+ e->qid.type = QTDIR;
+ e->parent = parent;
+ e->name = name;
+ e->uid = logfsisustadd(server->is, uid);
+ e->gid = logfsisustadd(server->is, gid);
+ e->mtime = mtime;
+ e->muid = logfsisustadd(server->is, muid);
+ e->perm = perm | DMDIR;
+ e->next = nil;
+ return e->uid != nil && e->muid != nil && e->name != nil;
+}
+
+void
+logfsentryfree(Entry *e)
+{
+ logfsfreemem(e->name);
+ if((e->qid.type & QTDIR) == 0)
+ logfsextentlistfree(&e->u.file.extent);
+ logfsfreemem(e);
+}
+
+char *
+logfsentrynew(LogfsServer *server, int inuse, u32int path, Entry *parent, char *name, char *uid, char *gid,
+u32int mtime, char *muid, u32int perm, ulong cvers, ulong length, Entry **ep)
+{
+ Entry *e;
+ char *errmsg;
+ e = logfsrealloc(nil, sizeof(*e));
+ if(e == nil)
+ return Enomem;
+ e->inuse = inuse;
+ e->qid.path = path;
+ e->qid.vers = 0;
+ e->qid.type = perm >> 24;
+ e->parent = parent;
+ e->name = logfsstrdup(name);
+ e->uid = logfsisustadd(server->is, uid);
+ e->gid = logfsisustadd(server->is, gid);
+ e->muid = logfsisustadd(server->is, muid);
+ if(e->uid == nil || e->gid == nil || e->muid == nil || e->name == nil) {
+ logfsentryfree(e);
+ return Enomem;
+ }
+ e->mtime = mtime;
+ if(perm & DMDIR)
+ e->perm = perm & (~0777 | (parent->perm & 0777));
+ else {
+ e->perm = perm & (~0666 | (parent->perm & 0666));
+ e->u.file.cvers = cvers;
+ e->u.file.length = length;
+ errmsg = logfsextentlistnew(&e->u.file.extent);
+ if(errmsg) {
+ logfsentryfree(e);
+ return errmsg;
+ }
+ }
+//print("e 0x%.8lux perm 0%.uo\n", e, e->perm);
+ *ep = e;
+ return nil;
+
+}
+
+void
+logfsentryclunk(Entry *e)
+{
+ e->inuse--;
+ if(e->inuse <= 0)
+ logfsentryfree(e);
+}
+
+char *
+logfsservernew(LogfsBoot *lb, LogfsLowLevel *ll, LogfsIdentityStore *is, ulong openflags, int trace, LogfsServer **srvp)
+{
+ LogfsServer *srv;
+ char *errmsg;
+ Path *p;
+
+ if(trace > 1)
+ print("logfsservernew()\n");
+ if(ll->l2pagesperblock > 5)
+ return "more than 32 pages per block";
+ if((1 << (ll->pathbits - L2LogSweeps - L2BlockCopies)) < ll->blocks)
+ return "too many blocks";
+ srv = logfsrealloc(nil, sizeof(*srv));
+ if(srv == nil) {
+ memerror:
+ errmsg = Enomem;
+ err:
+ logfsserverfree(&srv);
+ return errmsg;
+ }
+ errmsg = logfsfidmapnew(&srv->fidmap);
+ if(errmsg)
+ goto memerror;
+ errmsg = logfspathmapnew(&srv->pathmap);
+ if(errmsg)
+ goto memerror;
+ srv->is = is;
+ srv->ll = ll;
+ srv->trace = trace;
+ srv->lb = lb;
+ srv->openflags = openflags;
+ if(!mkdirentry(srv, &srv->root, 1, 0, &srv->root, "", "inferno", "sys", logfsnow(), "inferno", 0777))
+ goto memerror;
+ errmsg = logfspathmapnewentry(srv->pathmap, 0, &srv->root, &p);
+ /* p is guaranteed to be non null */
+ if(errmsg)
+ goto memerror;
+ errmsg = logfslogsegmentnew(srv, 0, &srv->activelog);
+ if(errmsg)
+ goto memerror;
+ srv->ndatablocks = 0;
+ srv->datablock = logfsrealloc(nil, sizeof(DataBlock) * ll->blocks);
+ if(srv->datablock == nil)
+ goto memerror;
+ errmsg = logfsscan(srv);
+ if(errmsg)
+ goto err;
+ errmsg = logfsreplay(srv, srv->sweptlog, 0);
+ if(errmsg)
+ goto err;
+ errmsg = logfsreplay(srv, srv->activelog, srv->sweptlog != nil);
+ if(errmsg)
+ goto err;
+ logfsreplayfinddata(srv);
+ *srvp = srv;
+ return nil;
+}
+
+static void
+freeentrylist(Entry *e)
+{
+ Entry *next;
+ while(e) {
+ next = e->next;
+ if(e->qid.type & QTDIR)
+ freeentrylist(e->u.dir.list);
+ logfsentryfree(e);
+ e = next;
+ }
+}
+
+void
+logfsserverfree(LogfsServer **serverp)
+{
+ LogfsServer *server = *serverp;
+ if(server) {
+ logfsfidmapfree(&server->fidmap);
+ logfslogsegmentfree(&server->activelog);
+ logfslogsegmentfree(&server->sweptlog);
+ logfspathmapfree(&server->pathmap);
+ logfsfreemem(server->datablock);
+ logfsfreemem(server);
+ freeentrylist(server->root.u.dir.list);
+ *serverp = nil;
+ }
+}
+
+char *
+logfsserverattach(LogfsServer *server, u32int fid, char *uname, Qid *qid)
+{
+ char *errmsg;
+ Fid *f;
+ if(server->trace > 1)
+ print("logfsserverattach(%ud, %s)\n", fid, uname);
+ errmsg = logfsfidmapnewentry(server->fidmap, fid, &f);
+ if(errmsg)
+ return errmsg;
+ f->uname = logfsisustadd(server->is, uname);
+ if(f->uname == nil) {
+ logfsfidmapclunk(server->fidmap, fid);
+ return Enomem;
+ }
+ f->entry = &server->root;
+ f->entry->inuse++;
+ *qid = f->entry->qid;
+ return nil;
+}
+
+static void
+id2name(LogfsIdentityStore *is, char *id, char **namep, int *badp, int *lenp)
+{
+ char *name;
+ if(id == logfsisgroupnonename)
+ name = id;
+ else {
+ name = logfsisfindnamefromid(is, id);
+ if(name == nil) {
+ *badp = 2;
+ name = id;
+ }
+ }
+ *lenp = strlen(name);
+ *namep = name;
+}
+
+u32int
+logfsflattenentry(LogfsIdentityStore *is, uchar *buf, u32int limit, Entry *e)
+{
+ int unamelen, gnamelen, munamelen, namelen;
+ uint len;
+ uchar *p;
+ int unamebad = 0, gnamebad = 0, munamebad = 0;
+ char *uname, *gname, *muname;
+
+ id2name(is, e->uid, &uname, &unamebad, &unamelen);
+ id2name(is, e->gid, &gname, &gnamebad, &gnamelen);
+ id2name(is, e->muid, &muname, &munamebad, &munamelen);
+ namelen = strlen(e->name);
+ len = 49 + unamelen + unamebad + gnamelen + gnamebad + munamelen + munamebad + namelen;
+ if(buf == nil)
+ return len;
+ if(len > limit)
+ return 0;
+ p = buf;
+ /* size */ PBIT16(p, len - BIT16SZ); p += BIT16SZ;
+ /* type */ p += BIT16SZ;
+ /* dev */ p += BIT32SZ;
+ /* qid.type */ *p++ = e->qid.type;
+ /* qid.vers */ PBIT32(p, e->qid.vers); p += BIT32SZ;
+ /* qid.path */ PBIT64(p, e->qid.path); p+= 8;
+ /* mode */ PBIT32(p, e->perm); p+= BIT32SZ;
+ /* atime */ PBIT32(p, e->mtime); p+= BIT32SZ;
+ /* mtime */ PBIT32(p, e->mtime); p+= BIT32SZ;
+ /* length */ if(e->qid.type & QTDIR) {
+ PBIT64(p, 0);
+ p += 8;
+ }
+ else {
+ PBIT32(p, e->u.file.length); p += BIT32SZ;
+ PBIT32(p, 0); p += BIT32SZ;
+ }
+ /* name */ PBIT16(p, namelen); p += BIT16SZ; memmove(p, e->name, namelen); p+= namelen;
+ /* uid */ PBIT16(p, unamelen + unamebad); p += BIT16SZ;
+ if(unamebad)
+ *p++ = '(';
+ memmove(p, uname, unamelen + unamebad); p+= unamelen;
+ if(unamebad)
+ *p++ = ')';
+ /* gid */ PBIT16(p, gnamelen + gnamebad); p += BIT16SZ;
+ if(gnamebad)
+ *p++ = '(';
+ memmove(p, gname, gnamelen); p+= gnamelen;
+ if(gnamebad)
+ *p++ = ')';
+ /* muid */ PBIT16(p, munamelen + munamebad); p += BIT16SZ;
+ if(munamebad)
+ *p++ = '(';
+ memmove(p, muname, munamelen); p+= munamelen;
+ if(munamebad)
+ *p = ')';
+//print("len %ud p - buf %ld\n", len, p - buf);
+ return len;
+}
+
+char *
+logfsserverstat(LogfsServer *server, u32int fid, uchar *buf, u32int bufsize, ushort *nstat)
+{
+ Fid *f;
+ if(server->trace > 1)
+ print("logfsserverstat(%ud)\n", fid);
+ f = logfsfidmapfindentry(server->fidmap, fid);
+ if(f == nil)
+ return logfsbadfid;
+ if(f->entry->deadandgone)
+ return Eio;
+ *nstat = logfsflattenentry(server->is, buf, bufsize, f->entry);
+ if(*nstat == 0)
+ return Eshortstat;
+ return nil;
+}
+
+
+void
+logfsservertrace(LogfsServer *server, int level)
+{
+ server->trace = level;
+}
--- /dev/null
+++ b/liblogfs/sweep.c
@@ -1,0 +1,272 @@
+#include "logfsos.h"
+#include "logfs.h"
+#include "local.h"
+
+enum {
+ ThrowAway,
+ Keep,
+ Repack,
+ Error,
+};
+
+#define setaction(a) if(*actionp < (a)) *actionp = a
+#define REPACK setaction(Repack)
+#define KEEP setaction(Keep)
+#define OPTCOPYEX(name, etag, stag) \
+ if(e->etag != s->stag) { \
+ s->stag = e->etag; \
+ REPACK; \
+ }
+#define OPTSTRCOPYEX(name, etag, stag) \
+ if(strcmp(e->etag, s->stag) != 0) { \
+ s->stag = e->etag; \
+ REPACK; \
+ }
+
+#define OPTCOPY(name, tag, sunion) OPTCOPYEX(name, tag, u.sunion.tag)
+#define OPTSTRCOPY(name, tag, sunion) OPTSTRCOPYEX(name, tag, u.sunion.tag)
+
+static char *
+sweepcreate(LogfsServer *server, LogMessage *s, int *actionp)
+{
+ Entry *pe, *e;
+ e = logfspathmapfinde(server->pathmap, s->u.create.newpath);
+ if(e == nil)
+ /* file no longer exists */
+ return nil;
+ pe = logfspathmapfinde(server->pathmap, s->path);
+ if(pe == nil)
+ /* file exists but parent doesn't - not good, but can continue */
+ return "parent missing";
+ if((pe->perm & DMDIR) == 0 || (e->perm & DMDIR) != (s->u.create.perm & DMDIR))
+ /* parent must be a directory, and
+ * the directory mode cannot change
+ */
+ return logfseinternal;
+ if((e->perm & DMDIR) == 0) {
+ OPTCOPYEX("cvers", u.file.cvers, u.create.cvers);
+ }
+ OPTSTRCOPY("name", name, create);
+ OPTCOPY("mtime", mtime, create);
+ OPTCOPY("perm", perm, create);
+ OPTSTRCOPY("uid", uid, create);
+ OPTSTRCOPY("gid", gid, create);
+ KEEP;
+ return nil;
+}
+
+static char *
+sweepwrite(LogfsServer *server, LogMessage *s, int readoffset, Entry **ep, int *trimp, int *actionp)
+{
+ Entry *e;
+ Extent extent;
+ Extent *ext;
+ *ep = nil;
+ e = logfspathmapfinde(server->pathmap, s->path);
+ if(e == nil)
+ /* gone, gone */
+ return nil;
+ if(e->perm & DMDIR)
+ return logfseinternal;
+ if(e->u.file.cvers != s->u.write.cvers)
+ /* trunced more recently */
+ return nil;
+ extent.min = s->u.write.offset;
+ extent.max = extent.min + s->u.write.count;
+ extent.flashaddr = s->u.write.flashaddr;
+ ext = logfsextentlistmatch(e->u.file.extent, &extent);
+ if(ext == nil)
+ return nil;
+ if(s->u.write.data) {
+ /*
+ * trim the front of the data so that when fixing up extents,
+ * flashaddr refers to the first byte
+ */
+ int offset;
+ logfsflashaddr2o(server, ext->flashaddr, &offset);
+ *trimp = offset - readoffset;
+ *ep = e;
+ }
+ KEEP;
+ return nil;
+}
+
+typedef struct FixupState {
+ LogfsServer *server;
+ int oldoffset;
+ u32int newflashaddr;
+} FixupState;
+
+static int
+fixup(void *magic, Extent *e)
+{
+ FixupState *state = magic;
+ int offset;
+ logfsflashaddr2o(state->server, e->flashaddr, &offset);
+ e->flashaddr = state->newflashaddr + (offset - state->oldoffset);
+ return 1;
+}
+
+static char *
+sweepblock(LogfsServer *server, uchar *buf)
+{
+ char *errmsg;
+ LogSegment *active = server->activelog;
+ LogSegment *swept = server->sweptlog;
+ int pagesize, ppb, page;
+ LogfsLowLevel *ll = server->ll;
+ LogfsLowLevelReadResult llrr;
+ int markedbad;
+ long oblock;
+
+ if(active == nil)
+ return nil;
+ if(swept == nil) {
+ errmsg = logfslogsegmentnew(server, loggensucc(active->gen), &server->sweptlog);
+ if(errmsg)
+ return errmsg;
+ swept = server->sweptlog;
+ }
+ /*
+ * if this is last block in the active log, flush it, so that the read of the last page works
+ */
+ if(active->unsweptblockindex == active->curblockindex)
+ logfslogsegmentflush(server, 1);
+ ppb = (1 << ll->l2pagesperblock);
+ pagesize = (1 << ll->l2pagesize);
+ for(page = 0; page < ppb; page++) {
+ uchar *p, *bufend;
+ errmsg = (*ll->readpagerange)(ll, buf, active->blockmap[active->unsweptblockindex], page, 0, pagesize, &llrr);
+ if(errmsg)
+ goto fail;
+ if(llrr != LogfsLowLevelReadResultOk)
+ logfsserverreplacelogblock(server, active, active->unsweptblockindex);
+ p = buf;
+ if(*p == 0xff)
+ break;
+ bufend = p + pagesize;
+ while(p < bufend) {
+ int action;
+ uint size;
+ LogMessage s;
+ Entry *e;
+ int trim;
+
+ size = logfsconvM2S(p, bufend - p, &s);
+ if(size == 0)
+ return "parse failure";
+ if(server->trace > 1) {
+ print("A>> ");
+ logfsdumpS(&s);
+ print("\n");
+ }
+ if(s.type == LogfsLogTend)
+ break;
+ action = ThrowAway;
+ switch(s.type) {
+ case LogfsLogTstart:
+ break;
+ case LogfsLogTcreate:
+ errmsg = sweepcreate(server, &s, &action);
+ break;
+ case LogfsLogTremove:
+ /* always obsolete; might check that path really doesn't exist */
+ break;
+ case LogfsLogTtrunc:
+ /* always obsolete, unless collecting out of order */
+ break;
+ case LogfsLogTwrite:
+ errmsg = sweepwrite(server, &s, s.u.write.data ? s.u.write.data - buf : 0, &e, &trim, &action);
+ break;
+ case LogfsLogTwstat:
+ /* always obsolete, unless collecting out of order */
+ break;
+ default:
+ return "bad tag in log page";
+ }
+ if(action == Error)
+ return errmsg;
+ if(errmsg)
+ print("bad sweep: %s\n", errmsg);
+ if(action == Keep)
+ action = Repack; /* input buffer has been wrecked, so can't just copy it */
+ if(action == Keep) {
+ /* write 'size' bytes to log */
+ errmsg = logfslogbytes(server, 0, p, size);
+ if(errmsg)
+ goto fail;
+ }
+ else if(action == Repack) {
+ /* TODO - handle writes */
+ if(s.type == LogfsLogTwrite && s.u.write.data) {
+ FixupState state;
+ errmsg = logfslogwrite(server, 0, s.path, s.u.write.offset + trim, s.u.write.count - trim,
+ s.u.write.mtime, s.u.write.cvers,
+ s.u.write.muid, s.u.write.data + trim, &state.newflashaddr);
+ if(errmsg == nil && s.u.write.data != nil) {
+ Extent extent;
+ /* TODO - deal with a failure to write the changes */
+ state.oldoffset = s.u.write.data - buf + trim;
+ state.server = server;
+ extent.min = s.u.write.offset;
+ extent.max = extent.min + s.u.write.count;
+ extent.flashaddr = s.u.write.flashaddr;
+ logfsextentlistmatchall(e->u.file.extent, fixup, &state, &extent);
+ }
+ }
+ else
+ errmsg = logfslog(server, 0, &s);
+ if(errmsg)
+ goto fail;
+ }
+ p += size;
+ }
+ }
+ /*
+ * this log block is no longer needed
+ */
+ oblock = active->blockmap[active->unsweptblockindex++];
+ errmsg = logfsbootfettleblock(server->lb, oblock, LogfsTnone, ~0, &markedbad);
+ if(errmsg)
+ goto fail;
+ if(active->unsweptblockindex > active->curblockindex) {
+ /*
+ * the activelog is now empty, so make the sweptlog the active one
+ */
+ logfslogsegmentfree(&active);
+ server->activelog = swept;
+ server->sweptlog = nil;
+ swept->dirty = 0;
+ }
+ return nil;
+fail:
+ return errmsg;
+}
+
+char *
+logfsserverlogsweep(LogfsServer *server, int justone, int *didsomething)
+{
+ uchar *buf;
+ char *errmsg;
+
+ /*
+ * TODO - is it even worth doing?
+ */
+ *didsomething = 0;
+ if(!server->activelog->dirty)
+ return nil;
+ buf = logfsrealloc(nil, (1 << server->ll->l2pagesize));
+ if(buf == nil)
+ return Enomem;
+ errmsg = nil;
+ while(server->activelog->unsweptblockindex <= server->activelog->curblockindex) {
+ errmsg = sweepblock(server, buf);
+ if(errmsg)
+ break;
+ if(server->sweptlog == nil || justone)
+ break;
+ }
+ logfsfreemem(buf);
+ *didsomething = 1;
+ return errmsg;
+}
--- /dev/null
+++ b/liblogfs/tagname.c
@@ -1,0 +1,20 @@
+#include "logfsos.h"
+#include "logfs.h"
+#include "local.h"
+
+char *
+logfstagname(uchar tag)
+{
+ switch(tag) {
+ case LogfsTboot:
+ return "boot";
+ case LogfsTnone:
+ return "free";
+ case LogfsTlog:
+ return "log";
+ case LogfsTdata:
+ return "data";
+ }
+ return "???";
+}
+
--- /dev/null
+++ b/liblogfs/test.c
@@ -1,0 +1,13 @@
+#include "logfsos.h"
+#include "logfs.h"
+#include "local.h"
+
+char *
+logfsservertestcmd(LogfsServer *s, int argc, char **argv)
+{
+ if(argc == 1 && strcmp(argv[0], "dontfettledatablock") == 0)
+ s->testflags |= LogfsTestDontFettleDataBlock;
+ else
+ return Ebadarg;
+ return nil;
+}
--- /dev/null
+++ b/liblogfs/ust.c
@@ -1,0 +1,65 @@
+#include "logfsos.h"
+#include "logfs.h"
+#include "local.h"
+
+enum {
+ USTMOD = 127
+};
+
+typedef struct UstNode {
+ char s[1];
+} UstNode;
+
+struct Ust {
+ UstNode *head[USTMOD];
+};
+
+int
+logfshashstring(void *s, int n)
+{
+ int h = 0;
+ char *p;
+ for(p = s; *p; p++) {
+ ulong g;
+ h = (h << 4) + *p;
+ g = h & 0xf0000000;
+ if(g != 0)
+ h ^= ((g >> 24) & 0xff) | g;
+ }
+ return (h & ~(1 << 31)) % n;
+}
+
+static int
+compare(void *entry, void *key)
+{
+ return strcmp((char*)entry, (char*)key) == 0;
+}
+
+static int
+allocsize(void *key)
+{
+ return strlen(key) + 1;
+}
+
+char *
+logfsustnew(Ust **ustp)
+{
+ return logfsmapnew(USTMOD, logfshashstring, compare, allocsize, nil, ustp);
+}
+
+char *
+logfsustadd(Ust *ust, char *s)
+{
+ char *errmsg;
+ char *ep;
+ ep = logfsmapfindentry(ust, s);
+ if(ep != nil) {
+// print("ust: found %s\n", s);
+ return ep;
+ }
+ errmsg = logfsmapnewentry(ust, s, &ep);
+ if(errmsg != nil)
+ return errmsg;
+// print("ust: new %s\n", s);
+ return strcpy(ep, s);
+}
--- /dev/null
+++ b/liblogfs/walk.c
@@ -1,0 +1,108 @@
+#include "logfsos.h"
+#include "logfs.h"
+#include "fcall.h"
+#include "local.h"
+
+char *
+logfsserverwalk(LogfsServer *server, u32int fid, u32int newfid, ushort nwname, char **wname, ushort *nwqid, Qid *wqid)
+{
+ ushort i;
+ Entry *e;
+ char *errmsg;
+ Fid *f;
+ if(server->trace > 1) {
+ print("logfsserverwalk(%ud, %ud, %ud, \"", fid, newfid, nwname);
+ for(i = 0; i < nwname; i++) {
+ if(i > 0)
+ print("/");
+ print("%s", wname[i]);
+ }
+ print("\")\n");
+ }
+ f = logfsfidmapfindentry(server->fidmap, fid);
+ if(f == nil)
+ return logfsebadfid;
+ if(f->openmode >= 0)
+ return logfsefidopen;
+ errmsg = nil;
+ e = f->entry;
+ if(e->deadandgone)
+ return Eio;
+ for(i = 0; i < nwname; i++) {
+ Entry *se;
+ /*
+ * deal with ..
+ */
+ if(strcmp(wname[i], "..") == 0)
+ se = e->parent;
+ else if(strcmp(wname[i], ".") == 0)
+ se = e;
+ else {
+ /*
+ * is it a directory?
+ */
+ if((e->qid.type & QTDIR) == 0) {
+ errmsg = Enotdir;
+ break;
+ }
+ /*
+ * can we walk the walk, or just talk the protocol?
+ */
+ if(!logfsuserpermcheck(server, e, f, DMEXEC)) {
+ errmsg = Eperm;
+ break;
+ }
+ /*
+ * search current entry for nwname[i]
+ */
+ for(se = e->u.dir.list; se; se = se->next)
+ if(strcmp(se->name, wname[i]) == 0)
+ break;
+ if(se == nil) {
+ errmsg = Enonexist;
+ break;
+ }
+ }
+ wqid[i] = se->qid;
+ e = se;
+ }
+ if(nwname > 0 && i == 0) {
+ /*
+ * fell at the first fence
+ */
+ return errmsg;
+ }
+ *nwqid = i;
+ if(i < nwname)
+ return nil;
+ /*
+ * new fid required?
+ */
+ if(fid != newfid) {
+ Fid *newf;
+ char *errmsg;
+ errmsg = logfsfidmapnewentry(server->fidmap, newfid, &newf);
+ if(errmsg)
+ return errmsg;
+ if(newf == nil)
+ return logfsefidinuse;
+ newf->entry = e;
+ newf->uname = f->uname;
+ e->inuse++;
+ }
+ else {
+ /*
+ * this may now be right
+ * 1. increment reference on new entry first in case e and f->entry are the same
+ * 2. clunk the old one in case this has the effect of removing an old entry
+ * 3. dump the directory read state if the entry has changed
+ */
+ e->inuse++;
+ logfsentryclunk(f->entry);
+ if(e != f->entry)
+ logfsdrsfree(&f->drs);
+ f->entry = e;
+ }
+ return nil;
+}
+
--- /dev/null
+++ b/liblogfs/write.c
@@ -1,0 +1,595 @@
+#include "logfsos.h"
+#include "logfs.h"
+#include "local.h"
+
+typedef struct AllocState AllocState;
+struct AllocState {
+ long oldblock;
+ int markbad;
+};
+
+Pageset
+logfsdatapagemask(int pages, int base)
+{
+ if(pages == BITSPERSET)
+ return ~(Pageset)0;
+ return (((Pageset)1 << pages) - 1) << (BITSPERSET - base - pages);
+}
+
+static Pageset
+fastgap(Pageset w, uint n)
+{
+ Pageset s;
+//print("fastgap(0x%.8ux, %d)\n", w, n);
+ if(w == 0 || n < 1 || n > BITSPERSET)
+ return 0;
+/*
+# unroll the following loop 5 times:
+# while(n > 1){
+# s := n >> 1;
+# w &= w<<s;
+# n -= s;
+# }
+*/
+ s = n >> 1;
+ w &= w << s;
+ n -= s;
+ s = n >> 1;
+ w &= w << s;
+ n -= s;
+ s = n >> 1;
+ w &= w << s;
+ n -= s;
+ s = n >> 1;
+ w &= w << s;
+ n -= s;
+ s = n >> 1;
+ if(BITSPERSET == 64){ /* extra time if 64 bits */
+ w &= w << s;
+ n -= s;
+ s = n >> 1;
+ }
+ return w & (w << s);
+}
+
+static int
+nlz(Pageset x)
+{
+ int n, c;
+
+ if(x == 0)
+ return BITSPERSET;
+ if(x & PAGETOP)
+ return 0;
+ n = BITSPERSET;
+ c = BITSPERSET/2;
+ do {
+ Pageset y;
+ y = x >> c;
+ if(y != 0) {
+ n -= c;
+ x = y;
+ }
+ } while((c >>= 1) != 0);
+ return n - x;
+}
+
+static Pageset
+findgap(Pageset w, uint n)
+{
+ Pageset m;
+
+ do {
+ m = fastgap(w, n);
+ if(m)
+ break;
+ n--;
+ } while(n);
+ if(n == 0)
+ return 0;
+ return logfsdatapagemask(n, nlz(m));
+}
+
+static int
+bitcount(Pageset mask)
+{
+ Pageset m;
+ int rv;
+
+ rv = 0;
+ for(m = PAGETOP; m != 0; m >>= 1)
+ if(mask & m)
+ rv++;
+ return rv;
+}
+
+static char *
+allocdatapages(LogfsServer *server, u32int count, int *countp, long *blockindexp, int *pagep, u32int *flashaddr, AllocState *state)
+{
+ LogfsLowLevel *ll = server->ll;
+ long b, blockindex;
+ DataBlock *db;
+ int pagebase;
+ u32int pages = (count + (1 << ll->l2pagesize) - 1) >> ll->l2pagesize;
+ u32int gapmask;
+ long bestfreeblockindex;
+ int bestfree;
+ int pagesperblock = 1 << ll->l2pagesperblock;
+ int apages;
+ char *errmsg;
+ int didsomething;
+
+ state->oldblock = -1;
+ state->markbad = 0;
+ if(pages > pagesperblock)
+ pages = pagesperblock;
+ /*
+ * fill in gaps first
+ */
+ bestfreeblockindex = -1;
+ bestfree = 0;
+ for(blockindex = 0; blockindex < server->ndatablocks; blockindex++) {
+ db = server->datablock + blockindex;
+ if(db->block < 0)
+ continue;
+ gapmask = findgap(db->free & ~db->dirty, pages);
+//print("blockindex %ld free 0x%.8ux dirty 0x%.8ux gapmask %.8ux\n", blockindex, db->free, db->dirty, gapmask);
+ if(gapmask != 0) {
+ /*
+ * this is free and !dirty
+ */
+ b = db->block;
+ USED(b);
+ goto done;
+ }
+ else {
+ int free = bitcount(db->free & logfsdatapagemask(pagesperblock, 0));
+ if(free > 0 && (bestfreeblockindex < 0 || free > bestfree)) {
+ bestfreeblockindex = blockindex;
+ bestfree = free;
+ }
+ }
+ }
+//print("out of space - need to clean up a data block\n");
+ if(bestfreeblockindex >= 0) {
+//print("best block index %ld (%ld) %d bits\n", bestfreeblockindex, server->datablock[bestfreeblockindex].block, bestfree);
+ /*
+ * clean up data block
+ */
+ b = logfsfindfreeblock(ll, AllocReasonTransfer);
+ while(b >= 0) {
+ char *errmsg;
+ LogfsLowLevelReadResult llrr;
+ long oldblock;
+ int markedbad;
+
+ db = server->datablock + bestfreeblockindex;
+ oldblock = db->block;
+ errmsg = logfsservercopyactivedata(server, b, bestfreeblockindex, 0, &llrr, &markedbad);
+ if(errmsg) {
+ if(!markedbad)
+ return errmsg;
+ b = logfsfindfreeblock(ll, AllocReasonTransfer);
+ }
+ else {
+ Pageset available;
+ /*
+ * if page0 is free, then we must ensure that we use it otherwise
+ * in tagged storage such as nand, the block tag is not written
+ * in all cases, it is safer to erase the block afterwards to
+ * preserve the data for as long as possible (we could choose
+ * to erase the old block now if page0 has already been copied)
+ */
+ blockindex = bestfreeblockindex;
+ state->oldblock = oldblock;
+ state->markbad = llrr != LogfsLowLevelReadResultOk;
+ available = db->free & ~db->dirty;
+ if(available & PAGETOP)
+ available = logfsdatapagemask(nlz(~available), 0);
+ gapmask = findgap(available, pages);
+ goto done;
+ }
+ }
+ }
+ /*
+ * use already erased blocks, so long as there are a few free
+ */
+ b = logfsfindfreeblock(ll, AllocReasonDataExtend);
+ if(b >= 0) {
+useerased:
+ for(blockindex = 0, db = server->datablock; blockindex < server->ndatablocks; blockindex++, db++)
+ if(db->block < 0)
+ break;
+ if(blockindex == server->ndatablocks)
+ server->ndatablocks++;
+ db->path = mkdatapath(blockindex, 0);
+ db->block = b;
+ (*ll->setblocktag)(ll, b, LogfsTdata);
+ (*ll->setblockpath)(ll, b, db->path);
+ db->free = logfsdatapagemask(pagesperblock, 0);
+ db->dirty = 0;
+ gapmask = db->free;
+ goto done;
+ }
+ /*
+ * last resort; try to steal from log
+ */
+//print("last resort\n");
+ errmsg = logfsserverlogsweep(server, 0, &didsomething);
+ if(errmsg)
+ return errmsg;
+ if(didsomething) {
+ /*
+ * this can only create whole free blocks, so...
+ */
+//print("findfree after last resort\n");
+ b = logfsfindfreeblock(ll, AllocReasonDataExtend);
+ if(b >= 0) {
+//print("*********************************************************\n");
+ goto useerased;
+ }
+ }
+ *countp = 0;
+ return nil;
+done:
+ /*
+ * common finish - needs gapmask, blockindex, db
+ */
+ apages = bitcount(gapmask);
+ pagebase = nlz(gapmask);
+ if(apages > pages)
+ apages = pages;
+ gapmask = logfsdatapagemask(apages, pagebase);
+ if(server->trace > 1)
+ print("allocdatapages: block %ld(%ld) pages %d mask 0x%.8ux pagebase %d apages %d\n",
+ blockindex, db->block, pages, gapmask, pagebase, apages);
+ db->free &= ~gapmask;
+ db->dirty |= gapmask;
+ *pagep = pagebase;
+ *blockindexp = blockindex;
+ *flashaddr = logfsspo2flashaddr(server, blockindex, pagebase, 0);
+ *countp = apages << ll->l2pagesize;
+ if(*countp > count)
+ *countp = count;
+ return nil;
+}
+
+typedef struct Page {
+ u32int pageaddr;
+ int ref;
+} Page;
+
+typedef struct DataStructure {
+ LogfsServer *server;
+ int nentries;
+ int maxentries;
+ Page *array;
+} DataStructure;
+
+static int
+deltapage(DataStructure *ds, u32int pageaddr, int add, int delta)
+{
+ int i;
+ for(i = 0; i < ds->nentries; i++)
+ if(ds->array[i].pageaddr == pageaddr) {
+ ds->array[i].ref += delta;
+ return 1;
+ }
+ if(!add)
+ return 1;
+ if(ds->maxentries == 0) {
+ ds->array = logfsrealloc(nil, sizeof(Page) * 100);
+ if(ds->array == nil)
+ return 0;
+ ds->maxentries = 100;
+ }
+ else if(ds->nentries >= ds->maxentries) {
+ void *a = logfsrealloc(ds->array, ds->maxentries * 2 * sizeof(Page));
+ if(a == nil)
+ return 0;
+ ds->array = a;
+ ds->maxentries *= 2;
+ }
+ ds->array[ds->nentries].pageaddr = pageaddr;
+ ds->array[ds->nentries++].ref = delta;
+ return 1;
+}
+
+/*
+ * only called for data addresses
+ */
+static int
+deltapages(DataStructure *ds, LogfsLowLevel *ll, u32int baseflashaddr, int range, int add, int delta)
+{
+ long seq;
+ int page, offset;
+ int pages;
+ u32int pageaddr;
+ int x;
+
+//print("deltapages(%ud, %ud, %d, %d)\n", baseflashaddr, limitflashaddr, add, delta);
+ logfsflashaddr2spo(ds->server, baseflashaddr, &seq, &page, &offset);
+ pages = (offset + range + (1 << ll->l2pagesize) - 1) >> ll->l2pagesize;
+ pageaddr = (seq << ll->l2pagesperblock) + page;
+ for(x = 0; x < pages; x++, pageaddr++)
+ if(!deltapage(ds, pageaddr, add, delta))
+ return 0;
+ return 1;
+}
+
+static int
+findpageset(void *magic, u32int baseoffset, u32int limitoffset, Extent *e, u32int extentoffset)
+{
+ DataStructure *ds = magic;
+ LogfsLowLevel *ll;
+ u32int flashaddr;
+ u32int range;
+ u32int residue;
+
+ if(e == nil || (e->flashaddr & LogAddr) != 0)
+ return 1;
+ ll = ds->server->ll;
+//print("baseoffset %ud limitoffset %ud min %ud max %ud\n", baseoffset, limitoffset, e->min, e->max);
+ flashaddr = e->flashaddr;
+ if(extentoffset)
+ if(!deltapages(ds, ll, flashaddr, extentoffset, 1, 1))
+ return -1;
+ flashaddr += extentoffset;
+ range = limitoffset - baseoffset;
+ if(!deltapages(ds, ll, flashaddr, range, 1, -1))
+ return -1;
+ flashaddr += range;
+ residue = e->max - e->min - (extentoffset + range);
+ if(residue)
+ if(!deltapages(ds, ll, flashaddr, residue, 1, 1))
+ return -1;
+ return 1;
+}
+
+static int
+addpagereferences(void *magic, Extent *e, int hole)
+{
+ DataStructure *ds = magic;
+
+ if(hole || (e->flashaddr & LogAddr) != 0)
+ return 1;
+ return deltapages(ds, ds->server->ll, e->flashaddr, e->max - e->min, 0, 1) ? 1 : -1;
+}
+
+static char *
+zappages(LogfsServer *server, Entry *e, u32int min, u32int max)
+{
+ DataStructure ds;
+ long seq;
+ int x, rv, page;
+ Page *p;
+
+ if(min >= e->u.file.length)
+ return nil; /* no checks necessary */
+ if(min == 0 && max >= e->u.file.length) {
+ /* replacing entire file */
+ logfsextentlistwalk(e->u.file.extent, logfsunconditionallymarkfreeanddirty, server);
+ return nil;
+ }
+ /* hard after that - this will need to be improved */
+ /*
+ * current algorithm
+ * build a list of all pages referenced by the extents being removed, and count the
+ * number of references
+ * then subtract the number of references to each page in entire file
+ * any pages with a reference count == 0 can be removed
+ */
+ ds.server = server;
+ ds.nentries = 0;
+ ds.maxentries = 0;
+ ds.array = nil;
+ rv = logfsextentlistwalkrange(e->u.file.extent, findpageset, &ds, min, max);
+ if(rv < 0 || ds.nentries == 0)
+ goto Out;
+ if(server->trace > 1){
+ print("pass 1\n");
+ for(x = 0; x < ds.nentries; x++){
+ p = &ds.array[x];
+ seq = p->pageaddr >> server->ll->l2pagesperblock;
+ page = p->pageaddr & ((1 << server->ll->l2pagesperblock) - 1);
+ print("block %lud page %ud ref %d\n", seq, page, p->ref);
+ }
+ print("pass 2\n");
+ }
+ rv = logfsextentlistwalk(e->u.file.extent, addpagereferences, &ds);
+ if(rv >= 0){
+ for(x = 0; x < ds.nentries; x++){
+ p = &ds.array[x];
+ seq = p->pageaddr >> server->ll->l2pagesperblock;
+ page = p->pageaddr & ((1 << server->ll->l2pagesperblock) - 1);
+ if(server->trace > 1)
+ print("block %lud page %ud ref %d\n", seq, page, p->ref);
+ if(p->ref == 0)
+ logfsfreedatapages(server, seq, logfsdatapagemask(1, page));
+ }
+ }
+Out:
+ logfsfreemem(ds.array);
+ return rv < 0 ? Enomem : nil;
+}
+
+static void
+disposeofoldblock(LogfsServer *server, AllocState *state)
+{
+ if(state->oldblock >= 0) {
+ if(server->testflags & LogfsTestDontFettleDataBlock) {
+ /* take the block out of commission */
+ (*server->ll->setblocktag)(server->ll, state->oldblock, LogfsTworse);
+ server->testflags &= ~LogfsTestDontFettleDataBlock;
+ }
+ else {
+ if(state->markbad)
+ (*server->ll->markblockbad)(server->ll, state->oldblock);
+ else
+ logfsbootfettleblock(server->lb, state->oldblock, LogfsTnone, ~0, nil);
+ }
+ state->oldblock = -1;
+ }
+}
+
+char *
+logfsserverwrite(LogfsServer *server, u32int fid, u32int offset, u32int count, uchar *buf, u32int *rcount)
+{
+ Fid *f;
+ Entry *e;
+ u32int now;
+ char *muid;
+ int muidlen;
+ LogfsLowLevel *ll = server->ll;
+
+ if(server->trace > 1)
+ print("logfsserverwrite(%ud, %ud, %ud)\n", fid, offset, count);
+ f = logfsfidmapfindentry(server->fidmap, fid);
+ if(f == nil)
+ return logfsebadfid;
+ if(f->openmode < 0)
+ return logfsefidnotopen;
+ if((f->openmode & 3) == OREAD)
+ return logfseaccess;
+ e = f->entry;
+ if(e->deadandgone)
+ return Eio;
+ if(e->qid.type & QTDIR)
+ return Eperm;
+ if(e->perm & DMAPPEND)
+ offset = e->u.file.length;
+ now = logfsnow();
+ *rcount = count;
+ muid = logfsisfindidfromname(server->is, f->uname);
+ muidlen = strlen(muid);
+ while(count) {
+ Extent extent;
+ int thistime;
+ char *errmsg;
+ thistime = lognicesizeforwrite(server, 1, count, muidlen);
+ if(thistime == 0) {
+ int p;
+ u32int n;
+ long blockindex;
+ int pagebase;
+ AllocState state;
+ int pagesize = 1 << ll->l2pagesize;
+ reallocate:
+ errmsg = allocdatapages(server, count, &thistime, &blockindex, &pagebase, &extent.flashaddr, &state);
+ if(errmsg)
+ return errmsg;
+ if(thistime == 0)
+ return logfselogfull;
+ for(p = pagebase, n = 0; n < thistime; p++, n += pagesize) {
+ u32int mask;
+ DataBlock *db = server->datablock + blockindex;
+ errmsg = (*ll->writepage)(ll, buf + n, db->block, p);
+ if(errmsg) {
+ if(strcmp(errmsg, Eio) != 0) {
+ /*
+ * something horrid happened down below
+ * recover without writing any more than we have to
+ */
+ if(p != 0) {
+ /*
+ * page 0 was either written already, or has been written in this loop
+ * thus the block referenced is valid on the media. all we need to do
+ * is lose the old block, mark the written pages as free (so they can
+ * be scavenged), and don't bother with the log message
+ */
+ disposeofoldblock(server, &state);
+ mask = logfsdatapagemask(p - pagebase - 1, pagebase);
+ db->free |= mask;
+ db->dirty |= mask;
+ return errmsg;
+ }
+ /*
+ * page 0 failed to write (so nothing written at all)
+ * this is either an entirely free block (no erased block in savestate),
+ * or a copy of a scavenged block (erased block in savestate)
+ */
+ if(state.oldblock < 0) {
+ /*
+ * newly selected erased block (blockindex == server->ndatablocks - 1)
+ * mark it bad, lose it from the datablock table
+ */
+ (*ll->markblockbad)(ll, db->block);
+ db->block = -1;
+ if(blockindex == server->ndatablocks - 1)
+ server->ndatablocks--;
+ return errmsg;
+ }
+ /*
+ * page 0 of a data scavenge copy
+ * mark it bad, restore state (old block)
+ */
+ (*ll->markblockbad)(ll, db->block);
+ db->block = state.oldblock;
+ return errmsg;
+ }
+ /*
+ * write error on target block
+ *
+ * if it is a replacement (state saved)
+ * mark the new block bad, restore state and try again
+ *
+ * if it is not replaced (no state saved)
+ * replace block, and try again
+ */
+ if(state.oldblock >= 0) {
+ (*ll->markblockbad)(ll, db->block);
+ db->block = state.oldblock;
+ }
+ else {
+ errmsg = logfsserverreplacedatablock(server, blockindex);
+ if(errmsg)
+ return errmsg;
+ }
+ goto reallocate;
+ }
+ mask = logfsdatapagemask(1, p);
+ db->free &= ~mask;
+ db->dirty |= mask;
+ }
+ /* well, we managed to write the data out */
+ errmsg = logfslogwrite(server, 1, e->qid.path, offset, thistime, now, e->u.file.cvers,
+ muid, nil, &extent.flashaddr);
+ /*
+ * now we can dispose of the original data block, if any
+ * this is regardless of whether we succeeded in writing a log message, as
+ * if this block is not erased, there will be a duplicate
+ */
+ disposeofoldblock(server, &state);
+ }
+ else {
+ if(thistime > count)
+ thistime = count;
+ errmsg = logfslogwrite(server, 1, e->qid.path, offset, thistime, now, e->u.file.cvers,
+ muid, buf, &extent.flashaddr);
+ }
+ /*
+ * here if we failed to write the log message
+ */
+ if(errmsg)
+ return errmsg;
+ if(server->trace > 1)
+ print("logfsserverwrite: %d bytes at flashaddr 0x%.8ux\n", thistime, extent.flashaddr);
+ extent.min = offset;
+ extent.max = offset + thistime;
+ errmsg = zappages(server, e, extent.min, extent.max);
+ if(errmsg)
+ return errmsg;
+ errmsg = logfsextentlistinsert(e->u.file.extent, &extent, nil);
+ if(errmsg)
+ return errmsg;
+ e->muid = muid;
+ e->mtime = now;
+ offset += thistime;
+ if(e->u.file.length < offset)
+ e->u.file.length = offset;
+ count -= thistime;
+ buf += thistime;
+ e->qid.vers++;
+ }
+ return nil;
+}
--- /dev/null
+++ b/liblogfs/wstat.c
@@ -1,0 +1,245 @@
+#include "logfsos.h"
+#include "logfs.h"
+#include "fcall.h"
+#include "local.h"
+
+char *
+logfsserverwstat(LogfsServer *server, u32int fid, uchar *stat, ushort nstat)
+{
+ Fid *f;
+ uchar *p;
+ ushort len;
+ uchar *mep;
+ Qid qid;
+ u32int perm, mtime;
+ uvlong length;
+ char *name, *uname, *gname, *muname;
+ int qiddonttouch, permdonttouch, mtimedonttouch, lengthdonttouch;
+ Entry *e, *parent;
+ LogMessage s;
+ char *cuid, *ngid;
+ Group *eg, *ng;
+ char *cname;
+ char *errmsg;
+ char *nuid;
+
+ if(server->trace > 1)
+ print("logfsserverwstat(%ud, %ud)\n", fid, nstat);
+ if(nstat < 49)
+ return Eshortstat;
+ p = stat;
+ len = GBIT16(p); p += BIT16SZ;
+ if(len + BIT16SZ != nstat)
+ return Eshortstat;
+ mep = p + len;
+ p += BIT16SZ + BIT32SZ; /* skip type and dev */
+ qid.type = *p++;
+ qid.vers = GBIT32(p); p += BIT32SZ;
+ qid.path = GBIT64(p); p += BIT64SZ;
+ perm = GBIT32(p); p += BIT32SZ;
+ p += BIT32SZ; /* skip atime */
+ mtime = GBIT32(p); p += BIT32SZ;
+ length = GBIT64(p); p+= BIT64SZ;
+ if(!logfsgn(&p, mep, &name) || !logfsgn(&p, mep, &uname)
+ || !logfsgn(&p, mep, &gname) || !logfsgn(&p, mep, &muname))
+ return Eshortstat;
+ if(p != mep)
+ return Eshortstat;
+ qiddonttouch = qid.type == (uchar)~0 && qid.vers == ~0 && qid.path == ~(uvlong)0;
+ permdonttouch = perm == ~0;
+ mtimedonttouch = mtime == ~0;
+ lengthdonttouch = length == ~(uvlong)0;
+ if(server->trace > 1) {
+ int comma = 0;
+ print("logfsserverwstat(");
+ if(!qiddonttouch) {
+ comma = 1;
+ print("qid=0x%.2ux/%lud/%llud", qid.type, qid.vers, qid.path);
+ }
+ if(!permdonttouch) {
+ if(comma)
+ print(", ");
+ print("perm=0%uo", perm);
+ comma = 1;
+ }
+ if(!mtimedonttouch) {
+ if(comma)
+ print(", ");
+ print("mtime=%ud", mtime);
+ comma = 1;
+ }
+ if(!lengthdonttouch) {
+ if(comma)
+ print(", ");
+ print("length=%llud", length);
+ comma = 1;
+ }
+ if(name != nil) {
+ if(comma)
+ print(", ");
+ print("name=%s", name);
+ comma = 1;
+ }
+ if(uname != nil) {
+ if(comma)
+ print(", ");
+ print("uid=%s", uname);
+ comma = 1;
+ }
+ if(gname != nil) {
+ if(comma)
+ print(", ");
+ print("gid=%s", gname);
+ comma = 1;
+ }
+ if(muname != nil) {
+ if(comma)
+ print(", ");
+ print("muname=%s", muname);
+ comma = 1;
+ }
+ USED(comma);
+ print(")\n");
+ }
+ f = logfsfidmapfindentry(server->fidmap, fid);
+ if(f == nil)
+ return logfsebadfid;
+ e = f->entry;
+ if(e->deadandgone)
+ return Eio;
+ parent = e->parent;
+ if(name) {
+ Entry *oe;
+ if(parent == e)
+ return Eperm;
+ if(!logfsuserpermcheck(server, e->parent, f, DMWRITE))
+ return Eperm;
+ for(oe = parent->u.dir.list; oe; oe = oe->next) {
+ if(oe == e)
+ continue;
+ if(strcmp(oe->name, name) == 0)
+ return Eexist;
+ }
+ }
+ if(!lengthdonttouch) {
+ if(!logfsuserpermcheck(server, e, f, DMWRITE))
+ return Eperm;
+ if(e->qid.type & QTDIR) {
+ if(length != 0)
+ return Eperm;
+ }else if(length != e->u.file.length){
+ /*
+ * TODO - truncate directory
+ * TODO - truncate file
+ */
+ return "wstat -- can't change length";
+ }
+ }
+ cuid = logfsisfindidfromname(server->is, f->uname);
+ /* TODO - change entries to have a group pointer */
+ eg = logfsisfindgroupfromid(server->is, e->uid);
+ if(gname) {
+ gname = logfsisustadd(server->is, gname);
+ if(gname == nil)
+ return Enomem;
+ ngid = logfsisfindidfromname(server->is, gname);
+ if(ngid == nil)
+ return Eunknown;
+ }
+ else
+ ngid = nil;
+ if(uname) {
+ uname = logfsisustadd(server->is, uname);
+ if(uname == nil)
+ return Enomem;
+ nuid = logfsisfindidfromname(server->is, uname);
+ if(nuid == nil)
+ return Eunknown;
+ }
+ else
+ nuid = nil;
+ if(!permdonttouch || !mtimedonttouch) {
+ /*
+ * same permissions rules - change by owner, or by group leader
+ */
+ if((server->openflags & LogfsOpenFlagWstatAllow) == 0 &&
+ e->uid != cuid && (eg == nil || !logfsisgroupuidisleader(server->is, eg, cuid)))
+ return Eperm;
+ }
+ if(!permdonttouch){
+ if((perm^e->perm) & DMDIR)
+ return "wstat -- attempt to change directory";
+ if(perm & ~(DMDIR|DMAPPEND|DMEXCL|0777))
+ return Eperm;
+ }
+ if(gname) {
+ int ok;
+ ng = logfsisfindgroupfromid(server->is, ngid);
+ ok = 0;
+ if(e->uid == cuid && logfsisgroupuidismember(server->is, ng, e->uid))
+ ok = 1;
+ if(!ok && eg && logfsisgroupuidisleader(server->is, eg, cuid)
+ && logfsisgroupuidisleader(server->is, ng, cuid))
+ ok = 1;
+ if(!ok && (server->openflags & LogfsOpenFlagWstatAllow) == 0)
+ return Eperm;
+ }
+ if(!qiddonttouch)
+ return Eperm;
+ if(uname){
+ if((server->openflags & LogfsOpenFlagWstatAllow) == 0)
+ return Eperm;
+ }
+ if(muname)
+ return Eperm;
+ /*
+ * we can do this
+ */
+ if(mtimedonttouch && permdonttouch && lengthdonttouch
+ && name == nil && uname == nil && gname == nil) {
+ /*
+ * but we aren't doing anything - this is a wstat flush
+ */
+ return logfsserverflush(server);
+ }
+ if(name) {
+ cname = logfsstrdup(name);
+ if(cname == nil)
+ return Enomem;
+ }
+ else
+ cname = nil;
+ /*
+ * send the log message
+ */
+ s.type = LogfsLogTwstat;
+ s.path = e->qid.path;
+ s.u.wstat.name = cname;
+ s.u.wstat.perm = perm;
+ s.u.wstat.uid = nuid;
+ s.u.wstat.gid = ngid;
+ s.u.wstat.mtime = mtime;
+ s.u.wstat.muid = cuid;
+ errmsg = logfslog(server, 1, &s);
+ if(errmsg) {
+ logfsfreemem(cname);
+ return errmsg;
+ }
+ if(!mtimedonttouch)
+ e->mtime = mtime;
+ if(!permdonttouch)
+ e->perm = (e->perm & DMDIR) | perm;
+ if(!lengthdonttouch) {
+ /* TODO */
+ }
+ if(name) {
+ logfsfreemem(e->name);
+ e->name = cname;
+ }
+ if(uname)
+ e->uid = nuid;
+ if(ngid)
+ e->gid = ngid;
+ return nil;
+}
+
--- /dev/null
+++ b/libmath/FPcontrol-DragonFly.c
@@ -1,0 +1,77 @@
+#include "lib9.h"
+#include "mathi.h"
+
+void
+FPinit(void)
+{
+ setfsr(0); /* Clear pending exceptions */
+ setfcr(FPPDBL|FPRNR|FPINVAL|FPZDIV|FPUNFL|FPOVFL);
+}
+
+ulong
+getFPstatus(void)
+{
+ ulong fsr = 0, fsr9 = getfsr();
+ /* on specific machines, could be table lookup */
+ if(fsr9&FPAINEX) fsr |= INEX;
+ if(fsr9&FPAOVFL) fsr |= OVFL;
+ if(fsr9&FPAUNFL) fsr |= UNFL;
+ if(fsr9&FPAZDIV) fsr |= ZDIV;
+ if(fsr9&FPAINVAL) fsr |= INVAL;
+ return fsr;
+}
+
+ulong
+FPstatus(ulong fsr, ulong mask)
+{
+ ulong fsr9 = 0;
+ ulong old = getFPstatus();
+ fsr = (fsr&mask) | (old&~mask);
+ if(fsr&INEX) fsr9 |= FPAINEX;
+ if(fsr&OVFL) fsr9 |= FPAOVFL;
+ if(fsr&UNFL) fsr9 |= FPAUNFL;
+ if(fsr&ZDIV) fsr9 |= FPAZDIV;
+ if(fsr&INVAL) fsr9 |= FPAINVAL;
+ setfsr(fsr9);
+ return(old&mask);
+}
+
+ulong
+getFPcontrol(void)
+{
+ ulong fcr = 0, fcr9 = getfcr();
+ switch(fcr9&FPRMASK){
+ case FPRNR: fcr = RND_NR; break;
+ case FPRNINF: fcr = RND_NINF; break;
+ case FPRPINF: fcr = RND_PINF; break;
+ case FPRZ: fcr = RND_Z; break;
+ }
+ if(fcr9&FPINEX) fcr |= INEX;
+ if(fcr9&FPOVFL) fcr |= OVFL;
+ if(fcr9&FPUNFL) fcr |= UNFL;
+ if(fcr9&FPZDIV) fcr |= ZDIV;
+ if(fcr9&FPINVAL) fcr |= INVAL;
+ return fcr;
+}
+
+ulong
+FPcontrol(ulong fcr, ulong mask)
+{
+ ulong fcr9 = FPPDBL;
+ ulong old = getFPcontrol();
+ fcr = (fcr&mask) | (old&~mask);
+ if(fcr&INEX) fcr9 |= FPINEX;
+ if(fcr&OVFL) fcr9 |= FPOVFL;
+ if(fcr&UNFL) fcr9 |= FPUNFL;
+ if(fcr&ZDIV) fcr9 |= FPZDIV;
+ if(fcr&INVAL) fcr9 |= FPINVAL;
+ switch(fcr&RND_MASK){
+ case RND_NR: fcr9 |= FPRNR; break;
+ case RND_NINF: fcr9 |= FPRNINF; break;
+ case RND_PINF: fcr9 |= FPRPINF; break;
+ case RND_Z: fcr9 |= FPRZ; break;
+ }
+ setfcr(fcr9);
+ return(old&mask);
+}
+
--- /dev/null
+++ b/libmath/FPcontrol-FreeBSD.c
@@ -1,0 +1,77 @@
+#include "lib9.h"
+#include "mathi.h"
+
+void
+FPinit(void)
+{
+ setfsr(0); /* Clear pending exceptions */
+ setfcr(FPPDBL|FPRNR|FPINVAL|FPZDIV|FPUNFL|FPOVFL);
+}
+
+ulong
+getFPstatus(void)
+{
+ ulong fsr = 0, fsr9 = getfsr();
+ /* on specific machines, could be table lookup */
+ if(fsr9&FPAINEX) fsr |= INEX;
+ if(fsr9&FPAOVFL) fsr |= OVFL;
+ if(fsr9&FPAUNFL) fsr |= UNFL;
+ if(fsr9&FPAZDIV) fsr |= ZDIV;
+ if(fsr9&FPAINVAL) fsr |= INVAL;
+ return fsr;
+}
+
+ulong
+FPstatus(ulong fsr, ulong mask)
+{
+ ulong fsr9 = 0;
+ ulong old = getFPstatus();
+ fsr = (fsr&mask) | (old&~mask);
+ if(fsr&INEX) fsr9 |= FPAINEX;
+ if(fsr&OVFL) fsr9 |= FPAOVFL;
+ if(fsr&UNFL) fsr9 |= FPAUNFL;
+ if(fsr&ZDIV) fsr9 |= FPAZDIV;
+ if(fsr&INVAL) fsr9 |= FPAINVAL;
+ setfsr(fsr9);
+ return(old&mask);
+}
+
+ulong
+getFPcontrol(void)
+{
+ ulong fcr = 0, fcr9 = getfcr();
+ switch(fcr9&FPRMASK){
+ case FPRNR: fcr = RND_NR; break;
+ case FPRNINF: fcr = RND_NINF; break;
+ case FPRPINF: fcr = RND_PINF; break;
+ case FPRZ: fcr = RND_Z; break;
+ }
+ if(fcr9&FPINEX) fcr |= INEX;
+ if(fcr9&FPOVFL) fcr |= OVFL;
+ if(fcr9&FPUNFL) fcr |= UNFL;
+ if(fcr9&FPZDIV) fcr |= ZDIV;
+ if(fcr9&FPINVAL) fcr |= INVAL;
+ return fcr;
+}
+
+ulong
+FPcontrol(ulong fcr, ulong mask)
+{
+ ulong fcr9 = FPPDBL;
+ ulong old = getFPcontrol();
+ fcr = (fcr&mask) | (old&~mask);
+ if(fcr&INEX) fcr9 |= FPINEX;
+ if(fcr&OVFL) fcr9 |= FPOVFL;
+ if(fcr&UNFL) fcr9 |= FPUNFL;
+ if(fcr&ZDIV) fcr9 |= FPZDIV;
+ if(fcr&INVAL) fcr9 |= FPINVAL;
+ switch(fcr&RND_MASK){
+ case RND_NR: fcr9 |= FPRNR; break;
+ case RND_NINF: fcr9 |= FPRNINF; break;
+ case RND_PINF: fcr9 |= FPRPINF; break;
+ case RND_Z: fcr9 |= FPRZ; break;
+ }
+ setfcr(fcr9);
+ return(old&mask);
+}
+
--- /dev/null
+++ b/libmath/FPcontrol-Inferno.c
@@ -1,0 +1,77 @@
+#include "lib9.h"
+#include "mathi.h"
+
+void
+FPinit(void)
+{
+ ulong fcr9 = FPPDBL|FPRNR|FPINVAL|FPZDIV|FPUNFL|FPOVFL;
+ setfcr(fcr9);
+}
+
+ulong
+getFPstatus(void)
+{
+ ulong fsr = 0, fsr9 = getfsr();
+ /* on specific machines, could be table lookup */
+ if(fsr9&FPAINEX) fsr |= INEX;
+ if(fsr9&FPAOVFL) fsr |= OVFL;
+ if(fsr9&FPAUNFL) fsr |= UNFL;
+ if(fsr9&FPAZDIV) fsr |= ZDIV;
+ if(fsr9&FPAINVAL) fsr |= INVAL;
+ return fsr;
+}
+
+ulong
+FPstatus(ulong fsr, ulong mask)
+{
+ ulong fsr9 = 0;
+ ulong old = getFPstatus();
+ fsr = (fsr&mask) | (old&~mask);
+ if(fsr&INEX) fsr9 |= FPAINEX;
+ if(fsr&OVFL) fsr9 |= FPAOVFL;
+ if(fsr&UNFL) fsr9 |= FPAUNFL;
+ if(fsr&ZDIV) fsr9 |= FPAZDIV;
+ if(fsr&INVAL) fsr9 |= FPAINVAL;
+ setfsr(fsr9);
+ return(old&mask);
+}
+
+ulong
+getFPcontrol(void)
+{
+ ulong fcr = 0, fcr9 = getfcr();
+ switch(fcr9&FPRMASK){
+ case FPRNR: fcr = RND_NR; break;
+ case FPRNINF: fcr = RND_NINF; break;
+ case FPRPINF: fcr = RND_PINF; break;
+ case FPRZ: fcr = RND_Z; break;
+ }
+ if(fcr9&FPINEX) fcr |= INEX;
+ if(fcr9&FPOVFL) fcr |= OVFL;
+ if(fcr9&FPUNFL) fcr |= UNFL;
+ if(fcr9&FPZDIV) fcr |= ZDIV;
+ if(fcr9&FPINVAL) fcr |= INVAL;
+ return fcr;
+}
+
+ulong
+FPcontrol(ulong fcr, ulong mask)
+{
+ ulong fcr9 = FPPDBL;
+ ulong old = getFPcontrol();
+ fcr = (fcr&mask) | (old&~mask);
+ if(fcr&INEX) fcr9 |= FPINEX;
+ if(fcr&OVFL) fcr9 |= FPOVFL;
+ if(fcr&UNFL) fcr9 |= FPUNFL;
+ if(fcr&ZDIV) fcr9 |= FPZDIV;
+ if(fcr&INVAL) fcr9 |= FPINVAL;
+ switch(fcr&RND_MASK){
+ case RND_NR: fcr9 |= FPRNR; break;
+ case RND_NINF: fcr9 |= FPRNINF; break;
+ case RND_PINF: fcr9 |= FPRPINF; break;
+ case RND_Z: fcr9 |= FPRZ; break;
+ }
+ setfcr(fcr9);
+ return(old&mask);
+}
+
--- /dev/null
+++ b/libmath/FPcontrol-Irix.c
@@ -1,0 +1,102 @@
+/* Load programs with -lfpe. See man pages for fpc and /usr/include/sigfpe.h, sys/fpu.h. */
+#include <stdlib.h>
+#include <sigfpe.h>
+#include <sys/fpu.h>
+typedef unsigned int ulong;
+#include "mathi.h"
+
+/*
+ * Irix does not permit a use handled SIGFPE since the floating point unit
+ * cannot be IEEE754 compliant without some software, so we must vector using
+ * the library
+ */
+extern void trapFPE(unsigned exception[5], int value[2]);
+
+void
+FPinit(void)
+{
+ union fpc_csr csr;
+ int i;
+ for(i=1; i<=4; i++) {
+ sigfpe_[i].repls = _USER_DETERMINED;
+ sigfpe_[i].abort = 2;
+ }
+ handle_sigfpes(_ON,
+ _EN_UNDERFL|_EN_OVERFL|_EN_DIVZERO|_EN_INVALID,
+ trapFPE,
+ _ABORT_ON_ERROR, 0);
+}
+
+
+ulong
+getFPstatus(void)
+{
+ ulong fsr = 0;
+ union fpc_csr csr;
+ csr.fc_word = get_fpc_csr();
+ if(csr.fc_struct.se_inexact) fsr |= INEX;
+ if(csr.fc_struct.se_overflow) fsr |= OVFL;
+ if(csr.fc_struct.se_underflow) fsr |= UNFL;
+ if(csr.fc_struct.se_divide0) fsr |= ZDIV;
+ if(csr.fc_struct.se_invalid) fsr |= INVAL;
+ return fsr;
+}
+
+ulong
+FPstatus(ulong fsr, ulong mask)
+{
+ ulong old = getFPstatus();
+ union fpc_csr csr;
+ csr.fc_word = get_fpc_csr();
+ fsr = (fsr&mask) | (old&~mask);
+ csr.fc_struct.se_inexact = (fsr&INEX)?1:0;
+ csr.fc_struct.se_overflow = (fsr&OVFL)?1:0;
+ csr.fc_struct.se_underflow = (fsr&UNFL)?1:0;
+ csr.fc_struct.se_divide0 = (fsr&ZDIV)?1:0;
+ csr.fc_struct.se_invalid = (fsr&INVAL)?1:0;
+ set_fpc_csr(csr.fc_word);
+ return(old&mask);
+}
+
+ulong
+getFPcontrol(void)
+{
+ ulong fcr = 0;
+ union fpc_csr csr;
+ double junk = fabs(1.); /* avoid bug mentioned in sigfpes man page [ehg] */
+ csr.fc_word = get_fpc_csr();
+ switch(csr.fc_struct.rounding_mode){
+ case ROUND_TO_NEAREST: fcr = RND_NR; break;
+ case ROUND_TO_MINUS_INFINITY: fcr = RND_NINF; break;
+ case ROUND_TO_PLUS_INFINITY: fcr = RND_PINF; break;
+ case ROUND_TO_ZERO: fcr = RND_Z; break;
+ }
+ if(csr.fc_struct.en_inexact) fcr |= INEX;
+ if(csr.fc_struct.en_overflow) fcr |= OVFL;
+ if(csr.fc_struct.en_underflow) fcr |= UNFL;
+ if(csr.fc_struct.en_divide0) fcr |= ZDIV;
+ if(csr.fc_struct.en_invalid) fcr |= INVAL;
+ return fcr;
+}
+
+ulong
+FPcontrol(ulong fcr, ulong mask)
+{
+ ulong old = getFPcontrol();
+ union fpc_csr csr;
+ csr.fc_word = get_fpc_csr();
+ fcr = (fcr&mask) | (old&~mask);
+ csr.fc_struct.en_inexact = (fcr&INEX)?1:0;
+ csr.fc_struct.en_overflow = (fcr&OVFL)?1:0;
+ csr.fc_struct.en_underflow = (fcr&UNFL)?1:0;
+ csr.fc_struct.en_divide0 = (fcr&ZDIV)?1:0;
+ csr.fc_struct.en_invalid = (fcr&INVAL)?1:0;
+ switch(fcr&RND_MASK){
+ case RND_NR: csr.fc_struct.rounding_mode = ROUND_TO_NEAREST; break;
+ case RND_NINF: csr.fc_struct.rounding_mode = ROUND_TO_MINUS_INFINITY; break;
+ case RND_PINF: csr.fc_struct.rounding_mode = ROUND_TO_PLUS_INFINITY; break;
+ case RND_Z: csr.fc_struct.rounding_mode = ROUND_TO_ZERO; break;
+ }
+ set_fpc_csr(csr.fc_word);
+ return(old&mask);
+}
--- /dev/null
+++ b/libmath/FPcontrol-Linux.c
@@ -1,0 +1,77 @@
+#include "lib9.h"
+#include "mathi.h"
+
+void
+FPinit(void)
+{
+ setfsr(0); /* Clear pending exceptions */
+ setfcr(FPPDBL|FPRNR|FPINVAL|FPZDIV|FPUNFL|FPOVFL);
+}
+
+ulong
+getFPstatus(void)
+{
+ ulong fsr = 0, fsr9 = getfsr();
+ /* on specific machines, could be table lookup */
+ if(fsr9&FPAINEX) fsr |= INEX;
+ if(fsr9&FPAOVFL) fsr |= OVFL;
+ if(fsr9&FPAUNFL) fsr |= UNFL;
+ if(fsr9&FPAZDIV) fsr |= ZDIV;
+ if(fsr9&FPAINVAL) fsr |= INVAL;
+ return fsr;
+}
+
+ulong
+FPstatus(ulong fsr, ulong mask)
+{
+ ulong fsr9 = 0;
+ ulong old = getFPstatus();
+ fsr = (fsr&mask) | (old&~mask);
+ if(fsr&INEX) fsr9 |= FPAINEX;
+ if(fsr&OVFL) fsr9 |= FPAOVFL;
+ if(fsr&UNFL) fsr9 |= FPAUNFL;
+ if(fsr&ZDIV) fsr9 |= FPAZDIV;
+ if(fsr&INVAL) fsr9 |= FPAINVAL;
+ setfsr(fsr9);
+ return(old&mask);
+}
+
+ulong
+getFPcontrol(void)
+{
+ ulong fcr = 0, fcr9 = getfcr();
+ switch(fcr9&FPRMASK){
+ case FPRNR: fcr = RND_NR; break;
+ case FPRNINF: fcr = RND_NINF; break;
+ case FPRPINF: fcr = RND_PINF; break;
+ case FPRZ: fcr = RND_Z; break;
+ }
+ if(fcr9&FPINEX) fcr |= INEX;
+ if(fcr9&FPOVFL) fcr |= OVFL;
+ if(fcr9&FPUNFL) fcr |= UNFL;
+ if(fcr9&FPZDIV) fcr |= ZDIV;
+ if(fcr9&FPINVAL) fcr |= INVAL;
+ return fcr;
+}
+
+ulong
+FPcontrol(ulong fcr, ulong mask)
+{
+ ulong fcr9 = FPPDBL;
+ ulong old = getFPcontrol();
+ fcr = (fcr&mask) | (old&~mask);
+ if(fcr&INEX) fcr9 |= FPINEX;
+ if(fcr&OVFL) fcr9 |= FPOVFL;
+ if(fcr&UNFL) fcr9 |= FPUNFL;
+ if(fcr&ZDIV) fcr9 |= FPZDIV;
+ if(fcr&INVAL) fcr9 |= FPINVAL;
+ switch(fcr&RND_MASK){
+ case RND_NR: fcr9 |= FPRNR; break;
+ case RND_NINF: fcr9 |= FPRNINF; break;
+ case RND_PINF: fcr9 |= FPRPINF; break;
+ case RND_Z: fcr9 |= FPRZ; break;
+ }
+ setfcr(fcr9);
+ return(old&mask);
+}
+
--- /dev/null
+++ b/libmath/FPcontrol-MacOSX.c
@@ -1,0 +1,79 @@
+#include "lib9.h"
+#include "mathi.h"
+
+#include <stdio.h>
+
+void
+FPinit(void)
+{
+ ulong fcr9 = FPPDBL|FPRNR|FPINVAL|FPZDIV|FPUNFL|FPOVFL;
+ setfsr(0); /* Clear pending exceptions */
+ setfcr(fcr9);
+}
+
+ulong
+getFPstatus(void)
+{
+ ulong fsr = 0, fsr9 = getfsr();
+ /* on specific machines, could be table lookup */
+ if(fsr9&FPAINEX) fsr |= INEX;
+ if(fsr9&FPAOVFL) fsr |= OVFL;
+ if(fsr9&FPAUNFL) fsr |= UNFL;
+ if(fsr9&FPAZDIV) fsr |= ZDIV;
+ if(fsr9&FPAINVAL) fsr |= INVAL;
+ return fsr;
+}
+
+ulong
+FPstatus(ulong fsr, ulong mask)
+{
+ ulong fsr9 = 0;
+ ulong old = getFPstatus();
+ fsr = (fsr&mask) | (old&~mask);
+ if(fsr&INEX) fsr9 |= FPAINEX;
+ if(fsr&OVFL) fsr9 |= FPAOVFL;
+ if(fsr&UNFL) fsr9 |= FPAUNFL;
+ if(fsr&ZDIV) fsr9 |= FPAZDIV;
+ if(fsr&INVAL) fsr9 |= FPAINVAL;
+ setfsr(fsr9);
+ return(old&mask);
+}
+
+ulong
+getFPcontrol(void)
+{
+ ulong fcr = 0, fcr9 = getfcr();
+ switch(fcr9&FPRMASK){
+ case FPRNR: fcr = RND_NR; break;
+ case FPRNINF: fcr = RND_NINF; break;
+ case FPRPINF: fcr = RND_PINF; break;
+ case FPRZ: fcr = RND_Z; break;
+ }
+ if(fcr9&FPINEX) fcr |= INEX;
+ if(fcr9&FPOVFL) fcr |= OVFL;
+ if(fcr9&FPUNFL) fcr |= UNFL;
+ if(fcr9&FPZDIV) fcr |= ZDIV;
+ if(fcr9&FPINVAL) fcr |= INVAL;
+ return fcr;
+}
+
+ulong
+FPcontrol(ulong fcr, ulong mask)
+{
+ ulong fcr9 = FPPDBL;
+ ulong old = getFPcontrol();
+ fcr = (fcr&mask) | (old&~mask);
+ if(fcr&INEX) fcr9 |= FPINEX;
+ if(fcr&OVFL) fcr9 |= FPOVFL;
+ if(fcr&UNFL) fcr9 |= FPUNFL;
+ if(fcr&ZDIV) fcr9 |= FPZDIV;
+ if(fcr&INVAL) fcr9 |= FPINVAL;
+ switch(fcr&RND_MASK){
+ case RND_NR: fcr9 |= FPRNR; break;
+ case RND_NINF: fcr9 |= FPRNINF; break;
+ case RND_PINF: fcr9 |= FPRPINF; break;
+ case RND_Z: fcr9 |= FPRZ; break;
+ }
+ setfcr(fcr9);
+ return(old&mask);
+}
--- /dev/null
+++ b/libmath/FPcontrol-NetBSD.c
@@ -1,0 +1,77 @@
+#include "lib9.h"
+#include "mathi.h"
+
+void
+FPinit(void)
+{
+ setfsr(0); /* Clear pending exceptions */
+ setfcr(FPPDBL|FPRNR|FPINVAL|FPZDIV|FPUNFL|FPOVFL);
+}
+
+ulong
+getFPstatus(void)
+{
+ ulong fsr = 0, fsr9 = getfsr();
+ /* on specific machines, could be table lookup */
+ if(fsr9&FPAINEX) fsr |= INEX;
+ if(fsr9&FPAOVFL) fsr |= OVFL;
+ if(fsr9&FPAUNFL) fsr |= UNFL;
+ if(fsr9&FPAZDIV) fsr |= ZDIV;
+ if(fsr9&FPAINVAL) fsr |= INVAL;
+ return fsr;
+}
+
+ulong
+FPstatus(ulong fsr, ulong mask)
+{
+ ulong fsr9 = 0;
+ ulong old = getFPstatus();
+ fsr = (fsr&mask) | (old&~mask);
+ if(fsr&INEX) fsr9 |= FPAINEX;
+ if(fsr&OVFL) fsr9 |= FPAOVFL;
+ if(fsr&UNFL) fsr9 |= FPAUNFL;
+ if(fsr&ZDIV) fsr9 |= FPAZDIV;
+ if(fsr&INVAL) fsr9 |= FPAINVAL;
+ setfsr(fsr9);
+ return(old&mask);
+}
+
+ulong
+getFPcontrol(void)
+{
+ ulong fcr = 0, fcr9 = getfcr();
+ switch(fcr9&FPRMASK){
+ case FPRNR: fcr = RND_NR; break;
+ case FPRNINF: fcr = RND_NINF; break;
+ case FPRPINF: fcr = RND_PINF; break;
+ case FPRZ: fcr = RND_Z; break;
+ }
+ if(fcr9&FPINEX) fcr |= INEX;
+ if(fcr9&FPOVFL) fcr |= OVFL;
+ if(fcr9&FPUNFL) fcr |= UNFL;
+ if(fcr9&FPZDIV) fcr |= ZDIV;
+ if(fcr9&FPINVAL) fcr |= INVAL;
+ return fcr;
+}
+
+ulong
+FPcontrol(ulong fcr, ulong mask)
+{
+ ulong fcr9 = FPPDBL;
+ ulong old = getFPcontrol();
+ fcr = (fcr&mask) | (old&~mask);
+ if(fcr&INEX) fcr9 |= FPINEX;
+ if(fcr&OVFL) fcr9 |= FPOVFL;
+ if(fcr&UNFL) fcr9 |= FPUNFL;
+ if(fcr&ZDIV) fcr9 |= FPZDIV;
+ if(fcr&INVAL) fcr9 |= FPINVAL;
+ switch(fcr&RND_MASK){
+ case RND_NR: fcr9 |= FPRNR; break;
+ case RND_NINF: fcr9 |= FPRNINF; break;
+ case RND_PINF: fcr9 |= FPRPINF; break;
+ case RND_Z: fcr9 |= FPRZ; break;
+ }
+ setfcr(fcr9);
+ return(old&mask);
+}
+
--- /dev/null
+++ b/libmath/FPcontrol-Nt.c
@@ -1,0 +1,82 @@
+#include "lib9.h"
+#include <float.h>
+#include "mathi.h"
+
+void
+FPinit(void)
+{
+ _controlfp(_EM_INEXACT,_MCW_EM); // abort on underflow, etc.
+}
+
+ulong
+getFPstatus(void)
+{
+ ulong fsr = 0, fsr32 = _statusfp();
+ if(fsr32&_SW_INEXACT) fsr |= INEX;
+ if(fsr32&_SW_OVERFLOW) fsr |= OVFL;
+ if(fsr32&_SW_UNDERFLOW) fsr |= UNFL;
+ if(fsr32&_SW_ZERODIVIDE) fsr |= ZDIV;
+ if(fsr32&_SW_INVALID) fsr |= INVAL;
+ return fsr;
+}
+
+ulong
+FPstatus(ulong fsr, ulong mask)
+{
+ ulong old = getFPstatus();
+ fsr = (fsr&mask) | (old&~mask);
+ if(fsr!=old){
+ _clearfp();
+ if(fsr){
+ ulong fcr = _controlfp(0,0);
+ double x = 1., y = 1e200, z = 0.;
+ _controlfp(_MCW_EM,_MCW_EM);
+ if(fsr&INEX) z = x + y;
+ if(fsr&OVFL) z = y*y;
+ if(fsr&UNFL) z = (x/y)/y;
+ if(fsr&ZDIV) z = x/z;
+ if(fsr&INVAL) z = z/z;
+ _controlfp(fcr,_MCW_EM);
+ }
+ }
+ return(old&mask);
+}
+
+ulong
+getFPcontrol(void)
+{
+ ulong fcr, fcr32 = _controlfp(0,0);
+ switch(fcr32&_MCW_RC){
+ case _RC_NEAR: fcr = RND_NR; break;
+ case _RC_DOWN: fcr = RND_NINF; break;
+ case _RC_UP: fcr = RND_PINF; break;
+ case _RC_CHOP: fcr = RND_Z; break;
+ }
+ if(!(fcr32&_EM_INEXACT)) fcr |= INEX;
+ if(!(fcr32&_EM_OVERFLOW)) fcr |= OVFL;
+ if(!(fcr32&_EM_UNDERFLOW)) fcr |= UNFL;
+ if(!(fcr32&_EM_ZERODIVIDE)) fcr |= ZDIV;
+ if(!(fcr32&_EM_INVALID)) fcr |= INVAL;
+ return fcr;
+}
+
+ulong
+FPcontrol(ulong fcr, ulong mask)
+{
+ ulong old = getFPcontrol();
+ ulong fcr32 = _MCW_EM, mask32 = _MCW_RC|_MCW_EM;
+ fcr = (fcr&mask) | (old&~mask);
+ if(fcr&INEX) fcr32 ^= _EM_INEXACT;
+ if(fcr&OVFL) fcr32 ^= _EM_OVERFLOW;
+ if(fcr&UNFL) fcr32 ^= _EM_UNDERFLOW;
+ if(fcr&ZDIV) fcr32 ^= _EM_ZERODIVIDE;
+ if(fcr&INVAL) fcr32 ^= _EM_INVALID;
+ switch(fcr&RND_MASK){
+ case RND_NR: fcr32 |= _RC_NEAR; break;
+ case RND_NINF: fcr32 |= _RC_DOWN; break;
+ case RND_PINF: fcr32 |= _RC_UP; break;
+ case RND_Z: fcr32 |= _RC_CHOP; break;
+ }
+ _controlfp(fcr32,mask32);
+ return(old&mask);
+}
--- /dev/null
+++ b/libmath/FPcontrol-OpenBSD.c
@@ -1,0 +1,77 @@
+#include "lib9.h"
+#include "mathi.h"
+
+void
+FPinit(void)
+{
+ setfsr(0); /* Clear pending exceptions */
+ setfcr(FPPDBL|FPRNR|FPINVAL|FPZDIV|FPUNFL|FPOVFL);
+}
+
+ulong
+getFPstatus(void)
+{
+ ulong fsr = 0, fsr9 = getfsr();
+ /* on specific machines, could be table lookup */
+ if(fsr9&FPAINEX) fsr |= INEX;
+ if(fsr9&FPAOVFL) fsr |= OVFL;
+ if(fsr9&FPAUNFL) fsr |= UNFL;
+ if(fsr9&FPAZDIV) fsr |= ZDIV;
+ if(fsr9&FPAINVAL) fsr |= INVAL;
+ return fsr;
+}
+
+ulong
+FPstatus(ulong fsr, ulong mask)
+{
+ ulong fsr9 = 0;
+ ulong old = getFPstatus();
+ fsr = (fsr&mask) | (old&~mask);
+ if(fsr&INEX) fsr9 |= FPAINEX;
+ if(fsr&OVFL) fsr9 |= FPAOVFL;
+ if(fsr&UNFL) fsr9 |= FPAUNFL;
+ if(fsr&ZDIV) fsr9 |= FPAZDIV;
+ if(fsr&INVAL) fsr9 |= FPAINVAL;
+ setfsr(fsr9);
+ return(old&mask);
+}
+
+ulong
+getFPcontrol(void)
+{
+ ulong fcr = 0, fcr9 = getfcr();
+ switch(fcr9&FPRMASK){
+ case FPRNR: fcr = RND_NR; break;
+ case FPRNINF: fcr = RND_NINF; break;
+ case FPRPINF: fcr = RND_PINF; break;
+ case FPRZ: fcr = RND_Z; break;
+ }
+ if(fcr9&FPINEX) fcr |= INEX;
+ if(fcr9&FPOVFL) fcr |= OVFL;
+ if(fcr9&FPUNFL) fcr |= UNFL;
+ if(fcr9&FPZDIV) fcr |= ZDIV;
+ if(fcr9&FPINVAL) fcr |= INVAL;
+ return fcr;
+}
+
+ulong
+FPcontrol(ulong fcr, ulong mask)
+{
+ ulong fcr9 = FPPDBL;
+ ulong old = getFPcontrol();
+ fcr = (fcr&mask) | (old&~mask);
+ if(fcr&INEX) fcr9 |= FPINEX;
+ if(fcr&OVFL) fcr9 |= FPOVFL;
+ if(fcr&UNFL) fcr9 |= FPUNFL;
+ if(fcr&ZDIV) fcr9 |= FPZDIV;
+ if(fcr&INVAL) fcr9 |= FPINVAL;
+ switch(fcr&RND_MASK){
+ case RND_NR: fcr9 |= FPRNR; break;
+ case RND_NINF: fcr9 |= FPRNINF; break;
+ case RND_PINF: fcr9 |= FPRPINF; break;
+ case RND_Z: fcr9 |= FPRZ; break;
+ }
+ setfcr(fcr9);
+ return(old&mask);
+}
+
--- /dev/null
+++ b/libmath/FPcontrol-Plan9.c
@@ -1,0 +1,1 @@
+#include "FPcontrol-Inferno.c"
--- /dev/null
+++ b/libmath/FPcontrol-Solaris.c
@@ -1,0 +1,99 @@
+#include <ieeefp.h>
+#include "lib9.h"
+#include "mathi.h"
+
+void
+FPinit(void)
+{
+ fpsetsticky(0); /* Clear pending exceptions */
+ fpsetround(FP_RN);
+ fpsetmask(FP_X_INV|FP_X_DZ|FP_X_UFL|FP_X_OFL);
+}
+
+ulong
+getFPstatus(void)
+{
+ ulong fsr = 0;
+ fp_except fsr9=fpgetsticky();
+ if(fsr9&FP_X_IMP) fsr |= INEX;
+ if(fsr9&FP_X_OFL) fsr |= OVFL;
+ if(fsr9&FP_X_UFL) fsr |= UNFL;
+ if(fsr9&FP_X_DZ) fsr |= ZDIV;
+ if(fsr9&FP_X_INV) fsr |= INVAL;
+ return fsr;
+}
+
+ulong
+FPstatus(ulong fsr, ulong mask)
+{
+ ulong fsr9 = 0;
+ ulong old = getFPstatus();
+ fsr = (fsr&mask) | (old&~mask);
+ if(fsr&INEX) fsr9 |= FP_X_IMP;
+ if(fsr&OVFL) fsr9 |= FP_X_OFL;
+ if(fsr&UNFL) fsr9 |= FP_X_UFL;
+ if(fsr&ZDIV) fsr9 |= FP_X_DZ;
+ if(fsr&INVAL) fsr9 |= FP_X_INV;
+ /* fpsetmask(fsr9); */
+ fpsetsticky(fsr9);
+ return(old&mask);
+}
+
+ulong
+getFPcontrol(void)
+{
+ ulong fcr = 0;
+ fp_except fpc = fpgetmask();
+ fp_rnd fpround = fpgetround();
+
+ if(fpc&FP_X_INV)
+ fcr|=INVAL;
+ if(fpc&FP_X_DZ)
+ fcr|=ZDIV;
+ if(fpc&FP_X_OFL)
+ fcr|=OVFL;
+ if(fpc&FP_X_UFL)
+ fcr|=UNFL;
+ if(fpc&FP_X_IMP)
+ fcr|=INEX;
+ switch(fpround){
+ case FP_RZ:
+ fcr|=RND_Z;
+ break;
+ case FP_RN:
+ fcr|=RND_NINF;
+ break;
+ case FP_RP:
+ fcr|=RND_PINF;
+ break;
+ case FP_RM:
+ fcr|=RND_NR;
+ }
+ return fcr;
+}
+ulong
+FPcontrol(ulong fcr, ulong mask)
+{
+ fp_except fc=0;
+ fp_rnd round;
+ ulong old = getFPcontrol();
+ ulong changed = mask&(fcr^old);
+ fcr = (fcr&mask) | (old&~mask);
+
+ if(fcr&INEX) fc |= FP_X_IMP;
+ if(fcr&OVFL) fc |= FP_X_OFL;
+ if(fcr&UNFL) fc |= FP_X_UFL;
+ if(fcr&ZDIV) fc |= FP_X_DZ;
+ if(fcr&INVAL) fc |= FP_X_INV;
+
+ switch(fcr&RND_MASK){
+ case RND_NR: round |= FP_RM; break;
+ case RND_NINF: round |= FP_RN; break;
+ case RND_PINF: round |= FP_RP; break;
+ case RND_Z: round |= FP_RZ; break;
+ }
+
+ fpsetround(round);
+ fpsetmask(fc);
+ return(old&mask);
+}
--- /dev/null
+++ b/libmath/FPcontrol-Unixware.c
@@ -1,0 +1,76 @@
+#include "lib9.h"
+#include "mathi.h"
+
+void
+FPinit(void)
+{
+ setfsr(0); /* Clear pending exceptions */
+ setfcr(FPPDBL|FPRNR|FPINVAL|FPZDIV|FPUNFL|FPOVFL);
+}
+
+ulong
+getFPstatus(void)
+{
+ ulong fsr = 0, fsr9 = getfsr();
+ /* on specific machines, could be table lookup */
+ if(fsr9&FPAINEX) fsr |= INEX;
+ if(fsr9&FPAOVFL) fsr |= OVFL;
+ if(fsr9&FPAUNFL) fsr |= UNFL;
+ if(fsr9&FPAZDIV) fsr |= ZDIV;
+ if(fsr9&FPAINVAL) fsr |= INVAL;
+ return fsr;
+}
+
+ulong
+FPstatus(ulong fsr, ulong mask)
+{
+ ulong fsr9 = 0;
+ ulong old = getFPstatus();
+ fsr = (fsr&mask) | (old&~mask);
+ if(fsr&INEX) fsr9 |= FPAINEX;
+ if(fsr&OVFL) fsr9 |= FPAOVFL;
+ if(fsr&UNFL) fsr9 |= FPAUNFL;
+ if(fsr&ZDIV) fsr9 |= FPAZDIV;
+ if(fsr&INVAL) fsr9 |= FPAINVAL;
+ setfsr(fsr9);
+ return(old&mask);
+}
+
+ulong
+getFPcontrol(void)
+{
+ ulong fcr = 0, fcr9 = getfcr();
+ switch(fcr9&FPRMASK){
+ case FPRNR: fcr = RND_NR; break;
+ case FPRNINF: fcr = RND_NINF; break;
+ case FPRPINF: fcr = RND_PINF; break;
+ case FPRZ: fcr = RND_Z; break;
+ }
+ if(fcr9&FPINEX) fcr |= INEX;
+ if(fcr9&FPOVFL) fcr |= OVFL;
+ if(fcr9&FPUNFL) fcr |= UNFL;
+ if(fcr9&FPZDIV) fcr |= ZDIV;
+ if(fcr9&FPINVAL) fcr |= INVAL;
+ return fcr;
+}
+
+ulong
+FPcontrol(ulong fcr, ulong mask)
+{
+ ulong fcr9 = FPPDBL;
+ ulong old = getFPcontrol();
+ fcr = (fcr&mask) | (old&~mask);
+ if(fcr&INEX) fcr9 |= FPINEX;
+ if(fcr&OVFL) fcr9 |= FPOVFL;
+ if(fcr&UNFL) fcr9 |= FPUNFL;
+ if(fcr&ZDIV) fcr9 |= FPZDIV;
+ if(fcr&INVAL) fcr9 |= FPINVAL;
+ switch(fcr&RND_MASK){
+ case RND_NR: fcr9 |= FPRNR; break;
+ case RND_NINF: fcr9 |= FPRNINF; break;
+ case RND_PINF: fcr9 |= FPRPINF; break;
+ case RND_Z: fcr9 |= FPRZ; break;
+ }
+ setfcr(fcr9);
+ return(old&mask);
+}
--- /dev/null
+++ b/libmath/NOTICE
@@ -1,0 +1,29 @@
+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-2007 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.
+
--- /dev/null
+++ b/libmath/bin/fdlibm-stubs
@@ -1,0 +1,71 @@
+echo '#include "real.h"' > real.c
+
+for(i in getFPcontrol getFPstatus){
+ echo 'void'
+ echo 'Real_'$i'(void *fp)'
+ echo '{'
+ echo ' F_Real_'$i' *f;'
+ echo ''
+ echo ' f = fp;'
+ echo ''
+ echo ' *f->ret = '$i'(f->x);'
+ echo '}'
+ echo ''
+} >> real.c
+
+for(i in finite ilogb isnan acos acosh asin asinh atan atanh cbrt ceil cos cosh erf erfc exp expm1 fabs floor j0 j1 log log10 log1p rint sin sinh sqrt tan tanh y0 y1){
+ echo 'void'
+ echo 'Real_'$i'(void *fp)'
+ echo '{'
+ echo ' F_Real_'$i' *f;'
+ echo ''
+ echo ' f = fp;'
+ echo ''
+ echo ' *f->ret = '$i'(f->x);'
+ echo '}'
+ echo ''
+} >> real.c
+
+for(i in fdim fmax fmin fmod hypot nextafter pow){
+ echo 'void'
+ echo 'Real_'$i'(void *fp)'
+ echo '{'
+ echo ' F_Real_'$i' *f;'
+ echo ''
+ echo ' f = fp;'
+ echo ''
+ echo ' *f->ret = '$i'(f->x, f->x);'
+ echo '}'
+ echo ''
+} >> real.c
+
+
+FPcontrol fn(r, mask: int) of int;
+FPstatus fn(r, mask: int) of int;
+atan2 fn(y, x: real) of real;
+copysign fn(x, s: real) of real;
+jn fn(n: int; x: real) of real;
+lgamma fn(x: real) of (int,real);
+modf fn(x: real) of (int,real);
+pow10 fn(p: int) of real;
+remainder fn(x, p: real) of real;
+scalbn fn(x: real; n: int) of real;
+yn fn(n: int; x: real) of real;
+
+dot fn(x, y: array of real) of real;
+iamax fn(x: array of real) of int;
+norm1, norm2 fn(x: array of real) of real;
+gemm fn(transa, transb: byte; m, n, k: int; alpha: real; a: array of real; ai0, aj0, lda: int; b: array of real; bi0, bj0, ldb: int; beta: real; c: array of real; ci0, cj0, ldc: int);
+
+for(i in FPcontrol FPstatus atan2 copysign jn lgamma modf pow10 remainder scalbn yn dot iamax norm1, norm2 gemm){
+ echo 'void'
+ echo 'Real_'$i'(void *fp)'
+ echo '{'
+ echo ' F_Real_'$i' *f;'
+ echo ''
+ echo ' f = fp;'
+ echo ''
+ echo ' *f->ret = '$i'(f->x, f->x);'
+ echo '}'
+ echo ''
+} >> real.c
--- /dev/null
+++ b/libmath/bin/unif_dtoa
@@ -1,0 +1,37 @@
+#!/bin/rc
+test -d /netlib/fp || 9fs netlib
+test -d /n/hati/usr/ehg || 9fs hati
+
+echo '/* derived from /netlib/fp/dtoa.c assuming IEEE, Standard C */' > dtoa.c
+echo '/* kudos to dmg@research.att.com, gripes to ehg@research.att.com */' >> dtoa.c
+echo '#include "lib9.h"' >> dtoa.c
+
+sed 's/^#if defined.IEEE_8087. . defined.IEEE_MC68k.*!= 1/#ifndef IEEE_Arith/
+ s/^#if defined.IEEE_8087. . defined.IEEE_MC68k.*/#ifdef IEEE_Arith/' \
+ /netlib/fp/dtoa.c > /n/hati/usr/ehg/xxx.c
+# undefine __STDC__ because we can't depend on HUGE_VAL
+rx hati 'unifdef -UIBM -UVAX -UKR_headers -U__cplusplus -U__STDC__ -UDEBUG \
+ -UBad_float_h -UJust_16 -UInaccurate_Divide -UROUND_BIASED \
+ -URND_PRODQUOT -DNo_leftright -UCheck_FLT_ROUNDS -D__MATH_H__ \
+ -DUnsigned_Shifts -DMALLOC=Malloc -DCONST=const \
+ -DPack_32 -DIEEE_Arith xxx.c | cb -s' > xxx.c
+sam -d >> dtoa.c >[2] err <<!
+e xxx.c
+1,/include "float\.h"\n/d
+/The following definition of Storeinc/+-;/^#endif\n/d
+/^#define IEEE_Arith\n/+-d
+/When Pack_32 is not defined/+-;/^\n/d
+,s/\n\n\n+/\n\n/g
+,s/\n\(/(/g
+,s/\\\(/\\\n(/g
+,x/IEEE_8087/ c/__LITTLE_ENDIAN/
+,x/^#if / c/#ifdef /
+,x g/errno/d
+,x/MALLOC/ c/malloc/
+,x/Long/ c/long/
+,x/CONST/ c/const/
+w
+q
+!
+cat xxx.c >> dtoa.c
+rm xxx.c
--- /dev/null
+++ b/libmath/bin/unif_fdlibm
@@ -1,0 +1,20 @@
+#!/bin/rc
+test -d /netlib/fdlibm || 9fs netlib
+test -d /n/hati/usr/ehg || 9fs hati
+
+echo '/* derived from /netlib/fdlibm */' > $1
+if (~ $1 fdlibm.h) echo '#include "lib9.h"' >> $1
+
+cp /netlib/fdlibm/$1 /n/hati/usr/ehg/xxx.c
+rx hati 'unifdef -D__STDC__ -D_IEEE_LIBM -D_SCALB_INT -U__NEWVALID xxx.c' > xxx.c
+> /n/hati/usr/ehg/xxx.c
+sam -d >> $1 >[2] err <<!
+e xxx.c
+/extern int signgam;/,/#define PLOSS/+d
+,x/HUGE_VAL/ c/DBL_MAX/
+,x/huge/ c/Huge/
+w
+q
+!
+cat xxx.c >> $1
+rm xxx.c
--- /dev/null
+++ b/libmath/blas.c
@@ -1,0 +1,62 @@
+#include "lib9.h"
+#include "mathi.h"
+
+double
+dot(int n, double *x, double *y)
+{
+ double sum = 0;
+ if (n <= 0)
+ return 0;
+ while (n--) {
+ sum += *x++ * *y++;
+ }
+ return sum;
+}
+
+
+int
+iamax(int n, double *x)
+{
+ int i, m;
+ double xm, a;
+ if (n <= 0)
+ return 0;
+ m = 0;
+ xm = fabs(*x);
+ for (i = 1; i < n; i++) {
+ a = fabs(*++x);
+ if (xm < a) {
+ m = i;
+ xm = a;
+ }
+ }
+ return m;
+}
+
+
+double
+norm1(int n, double *x)
+{
+ double sum = 0;
+ if (n <= 0)
+ return 0;
+ while (n--) {
+ sum += fabs(*x);
+ x++;
+ }
+ return sum;
+}
+
+
+double
+norm2(int n, double *x)
+{
+ double sum = 0;
+ if (n <= 0)
+ return 0;
+ while (n--) {
+ sum += *x * *x;
+ x++;
+ }
+ return sqrt(sum);
+}
--- /dev/null
+++ b/libmath/dtoa.c
@@ -1,0 +1,1816 @@
+/* derived from /netlib/fp/dtoa.c assuming IEEE, Standard C */
+/* kudos to dmg@bell-labs.com, gripes to ehg@bell-labs.com */
+#include "lib9.h"
+
+#ifdef __APPLE__
+#pragma clang diagnostic ignored "-Wlogical-op-parentheses"
+#pragma clang diagnostic ignored "-Wparentheses"
+#endif
+#define ACQUIRE_DTOA_LOCK(n) /*nothing*/
+#define FREE_DTOA_LOCK(n) /*nothing*/
+
+/* let's provide reasonable defaults for usual implementation of IEEE f.p. */
+#ifndef DBL_DIG
+#define DBL_DIG 15
+#endif
+#ifndef DBL_MAX_10_EXP
+#define DBL_MAX_10_EXP 308
+#endif
+#ifndef DBL_MAX_EXP
+#define DBL_MAX_EXP 1024
+#endif
+#ifndef FLT_RADIX
+#define FLT_RADIX 2
+#endif
+#ifndef FLT_ROUNDS
+#define FLT_ROUNDS 1
+#endif
+#ifndef Storeinc
+#define Storeinc(a,b,c) (*a++ = b << 16 | c & 0xffff)
+#endif
+
+#define Sign_Extend(a,b) if (b < 0) a |= 0xffff0000;
+
+#ifdef USE_FPdbleword
+#define word0(x) ((FPdbleword*)&x)->hi
+#define word1(x) ((FPdbleword*)&x)->lo
+#else
+#ifdef __LITTLE_ENDIAN
+#define word0(x) ((unsigned long *)&x)[1]
+#define word1(x) ((unsigned long *)&x)[0]
+#else
+#define word0(x) ((unsigned long *)&x)[0]
+#define word1(x) ((unsigned long *)&x)[1]
+#endif
+#endif
+
+/* #define P DBL_MANT_DIG */
+/* Ten_pmax = floor(P*log(2)/log(5)) */
+/* Bletch = (highest power of 2 < DBL_MAX_10_EXP) / 16 */
+/* Quick_max = floor((P-1)*log(FLT_RADIX)/log(10) - 1) */
+/* Int_max = floor(P*log(FLT_RADIX)/log(10) - 1) */
+
+#define Exp_shift 20
+#define Exp_shift1 20
+#define Exp_msk1 0x100000
+#define Exp_msk11 0x100000
+#define Exp_mask 0x7ff00000
+#define P 53
+#define Bias 1023
+#define Emin (-1022)
+#define Exp_1 0x3ff00000
+#define Exp_11 0x3ff00000
+#define Ebits 11
+#define Frac_mask 0xfffff
+#define Frac_mask1 0xfffff
+#define Ten_pmax 22
+#define Bletch 0x10
+#define Bndry_mask 0xfffff
+#define Bndry_mask1 0xfffff
+#define LSB 1
+#define Sign_bit 0x80000000
+#define Log2P 1
+#define Tiny0 0
+#define Tiny1 1
+#define Quick_max 14
+#define Int_max 14
+#define Infinite(x) (word0(x) == 0x7ff00000) /* sufficient test for here */
+#define Avoid_Underflow
+
+#define rounded_product(a,b) a *= b
+#define rounded_quotient(a,b) a /= b
+
+#define Big0 (Frac_mask1 | Exp_msk1*(DBL_MAX_EXP+Bias-1))
+#define Big1 0xffffffff
+
+#define Kmax 15
+
+struct
+Bigint {
+ struct Bigint *next;
+ int k, maxwds, sign, wds;
+ unsigned long x[1];
+};
+
+typedef struct Bigint Bigint;
+
+static Bigint *freelist[Kmax+1];
+
+static Bigint *
+Balloc(int k)
+{
+ int x;
+ Bigint * rv;
+
+ ACQUIRE_DTOA_LOCK(0);
+ if (rv = freelist[k]) {
+ freelist[k] = rv->next;
+ } else {
+ x = 1 << k;
+ rv = (Bigint * )malloc(sizeof(Bigint) + (x - 1) * sizeof(unsigned long));
+ if(rv == nil)
+ return nil;
+ rv->k = k;
+ rv->maxwds = x;
+ }
+ FREE_DTOA_LOCK(0);
+ rv->sign = rv->wds = 0;
+ return rv;
+}
+
+static void
+Bfree(Bigint *v)
+{
+ if (v) {
+ ACQUIRE_DTOA_LOCK(0);
+ v->next = freelist[v->k];
+ freelist[v->k] = v;
+ FREE_DTOA_LOCK(0);
+ }
+}
+
+#define Bcopy(x,y) memcpy((char *)&x->sign, (char *)&y->sign, \
+y->wds*sizeof(long) + 2*sizeof(int))
+
+static Bigint *
+multadd(Bigint *b, int m, int a) /* multiply by m and add a */
+{
+ int i, wds;
+ unsigned long * x, y;
+ unsigned long xi, z;
+ Bigint * b1;
+
+ wds = b->wds;
+ x = b->x;
+ i = 0;
+ do {
+ xi = *x;
+ y = (xi & 0xffff) * m + a;
+ z = (xi >> 16) * m + (y >> 16);
+ a = (int)(z >> 16);
+ *x++ = (z << 16) + (y & 0xffff);
+ } while (++i < wds);
+ if (a) {
+ if (wds >= b->maxwds) {
+ b1 = Balloc(b->k + 1);
+ Bcopy(b1, b);
+ Bfree(b);
+ b = b1;
+ }
+ b->x[wds++] = a;
+ b->wds = wds;
+ }
+ return b;
+}
+
+static Bigint *
+s2b(const char *s, int nd0, int nd, unsigned long y9)
+{
+ Bigint * b;
+ int i, k;
+ long x, y;
+
+ x = (nd + 8) / 9;
+ for (k = 0, y = 1; x > y; y <<= 1, k++)
+ ;
+ b = Balloc(k);
+ b->x[0] = y9;
+ b->wds = 1;
+
+ i = 9;
+ if (9 < nd0) {
+ s += 9;
+ do
+ b = multadd(b, 10, *s++ - '0');
+ while (++i < nd0);
+ s++;
+ } else
+ s += 10;
+ for (; i < nd; i++)
+ b = multadd(b, 10, *s++ - '0');
+ return b;
+}
+
+static int
+hi0bits(register unsigned long x)
+{
+ register int k = 0;
+
+ if (!(x & 0xffff0000)) {
+ k = 16;
+ x <<= 16;
+ }
+ if (!(x & 0xff000000)) {
+ k += 8;
+ x <<= 8;
+ }
+ if (!(x & 0xf0000000)) {
+ k += 4;
+ x <<= 4;
+ }
+ if (!(x & 0xc0000000)) {
+ k += 2;
+ x <<= 2;
+ }
+ if (!(x & 0x80000000)) {
+ k++;
+ if (!(x & 0x40000000))
+ return 32;
+ }
+ return k;
+}
+
+static int
+lo0bits(unsigned long *y)
+{
+ register int k;
+ register unsigned long x = *y;
+
+ if (x & 7) {
+ if (x & 1)
+ return 0;
+ if (x & 2) {
+ *y = x >> 1;
+ return 1;
+ }
+ *y = x >> 2;
+ return 2;
+ }
+ k = 0;
+ if (!(x & 0xffff)) {
+ k = 16;
+ x >>= 16;
+ }
+ if (!(x & 0xff)) {
+ k += 8;
+ x >>= 8;
+ }
+ if (!(x & 0xf)) {
+ k += 4;
+ x >>= 4;
+ }
+ if (!(x & 0x3)) {
+ k += 2;
+ x >>= 2;
+ }
+ if (!(x & 1)) {
+ k++;
+ x >>= 1;
+ if (!x & 1)
+ return 32;
+ }
+ *y = x;
+ return k;
+}
+
+static Bigint *
+i2b(int i)
+{
+ Bigint * b;
+
+ b = Balloc(1);
+ b->x[0] = i;
+ b->wds = 1;
+ return b;
+}
+
+static Bigint *
+mult(Bigint *a, Bigint *b)
+{
+ Bigint * c;
+ int k, wa, wb, wc;
+ unsigned long carry, y, z;
+ unsigned long * x, *xa, *xae, *xb, *xbe, *xc, *xc0;
+ unsigned long z2;
+
+ if (a->wds < b->wds) {
+ c = a;
+ a = b;
+ b = c;
+ }
+ k = a->k;
+ wa = a->wds;
+ wb = b->wds;
+ wc = wa + wb;
+ if (wc > a->maxwds)
+ k++;
+ c = Balloc(k);
+ for (x = c->x, xa = x + wc; x < xa; x++)
+ *x = 0;
+ xa = a->x;
+ xae = xa + wa;
+ xb = b->x;
+ xbe = xb + wb;
+ xc0 = c->x;
+ for (; xb < xbe; xb++, xc0++) {
+ if (y = *xb & 0xffff) {
+ x = xa;
+ xc = xc0;
+ carry = 0;
+ do {
+ z = (*x & 0xffff) * y + (*xc & 0xffff) + carry;
+ carry = z >> 16;
+ z2 = (*x++ >> 16) * y + (*xc >> 16) + carry;
+ carry = z2 >> 16;
+ Storeinc(xc, z2, z);
+ } while (x < xae);
+ *xc = carry;
+ }
+ if (y = *xb >> 16) {
+ x = xa;
+ xc = xc0;
+ carry = 0;
+ z2 = *xc;
+ do {
+ z = (*x & 0xffff) * y + (*xc >> 16) + carry;
+ carry = z >> 16;
+ Storeinc(xc, z, z2);
+ z2 = (*x++ >> 16) * y + (*xc & 0xffff) + carry;
+ carry = z2 >> 16;
+ } while (x < xae);
+ *xc = z2;
+ }
+ }
+ for (xc0 = c->x, xc = xc0 + wc; wc > 0 && !*--xc; --wc)
+ ;
+ c->wds = wc;
+ return c;
+}
+
+static Bigint *p5s;
+
+static Bigint *
+pow5mult(Bigint *b, int k)
+{
+ Bigint * b1, *p5, *p51;
+ int i;
+ static int p05[3] = {
+ 5, 25, 125 };
+
+ if (i = k & 3)
+ b = multadd(b, p05[i-1], 0);
+
+ if (!(k >>= 2))
+ return b;
+ if (!(p5 = p5s)) {
+ /* first time */
+ ACQUIRE_DTOA_LOCK(1);
+ if (!(p5 = p5s)) {
+ p5 = p5s = i2b(625);
+ p5->next = 0;
+ }
+ FREE_DTOA_LOCK(1);
+ }
+ for (; ; ) {
+ if (k & 1) {
+ b1 = mult(b, p5);
+ Bfree(b);
+ b = b1;
+ }
+ if (!(k >>= 1))
+ break;
+ if (!(p51 = p5->next)) {
+ ACQUIRE_DTOA_LOCK(1);
+ if (!(p51 = p5->next)) {
+ p51 = p5->next = mult(p5, p5);
+ p51->next = 0;
+ }
+ FREE_DTOA_LOCK(1);
+ }
+ p5 = p51;
+ }
+ return b;
+}
+
+static Bigint *
+lshift(Bigint *b, int k)
+{
+ int i, k1, n, n1;
+ Bigint * b1;
+ unsigned long * x, *x1, *xe, z;
+
+ n = k >> 5;
+ k1 = b->k;
+ n1 = n + b->wds + 1;
+ for (i = b->maxwds; n1 > i; i <<= 1)
+ k1++;
+ b1 = Balloc(k1);
+ x1 = b1->x;
+ for (i = 0; i < n; i++)
+ *x1++ = 0;
+ x = b->x;
+ xe = x + b->wds;
+ if (k &= 0x1f) {
+ k1 = 32 - k;
+ z = 0;
+ do {
+ *x1++ = *x << k | z;
+ z = *x++ >> k1;
+ } while (x < xe);
+ if (*x1 = z)
+ ++n1;
+ } else
+ do
+ *x1++ = *x++;
+ while (x < xe);
+ b1->wds = n1 - 1;
+ Bfree(b);
+ return b1;
+}
+
+static int
+cmp(Bigint *a, Bigint *b)
+{
+ unsigned long * xa, *xa0, *xb, *xb0;
+ int i, j;
+
+ i = a->wds;
+ j = b->wds;
+ if (i -= j)
+ return i;
+ xa0 = a->x;
+ xa = xa0 + j;
+ xb0 = b->x;
+ xb = xb0 + j;
+ for (; ; ) {
+ if (*--xa != *--xb)
+ return * xa < *xb ? -1 : 1;
+ if (xa <= xa0)
+ break;
+ }
+ return 0;
+}
+
+static Bigint *
+diff(Bigint *a, Bigint *b)
+{
+ Bigint * c;
+ int i, wa, wb;
+ long borrow, y; /* We need signed shifts here. */
+ unsigned long * xa, *xae, *xb, *xbe, *xc;
+ long z;
+
+ i = cmp(a, b);
+ if (!i) {
+ c = Balloc(0);
+ c->wds = 1;
+ c->x[0] = 0;
+ return c;
+ }
+ if (i < 0) {
+ c = a;
+ a = b;
+ b = c;
+ i = 1;
+ } else
+ i = 0;
+ c = Balloc(a->k);
+ c->sign = i;
+ wa = a->wds;
+ xa = a->x;
+ xae = xa + wa;
+ wb = b->wds;
+ xb = b->x;
+ xbe = xb + wb;
+ xc = c->x;
+ borrow = 0;
+ do {
+ y = (*xa & 0xffff) - (*xb & 0xffff) + borrow;
+ borrow = y >> 16;
+ Sign_Extend(borrow, y);
+ z = (*xa++ >> 16) - (*xb++ >> 16) + borrow;
+ borrow = z >> 16;
+ Sign_Extend(borrow, z);
+ Storeinc(xc, z, y);
+ } while (xb < xbe);
+ while (xa < xae) {
+ y = (*xa & 0xffff) + borrow;
+ borrow = y >> 16;
+ Sign_Extend(borrow, y);
+ z = (*xa++ >> 16) + borrow;
+ borrow = z >> 16;
+ Sign_Extend(borrow, z);
+ Storeinc(xc, z, y);
+ }
+ while (!*--xc)
+ wa--;
+ c->wds = wa;
+ return c;
+}
+
+static double
+ulp(double x)
+{
+ register long L;
+ double a;
+
+ L = (word0(x) & Exp_mask) - (P - 1) * Exp_msk1;
+#ifndef Sudden_Underflow
+ if (L > 0) {
+#endif
+ word0(a) = L;
+ word1(a) = 0;
+#ifndef Sudden_Underflow
+ } else {
+ L = -L >> Exp_shift;
+ if (L < Exp_shift) {
+ word0(a) = 0x80000 >> L;
+ word1(a) = 0;
+ } else {
+ word0(a) = 0;
+ L -= Exp_shift;
+ word1(a) = L >= 31 ? 1 : 1 << 31 - L;
+ }
+ }
+#endif
+ return a;
+}
+
+static double
+b2d(Bigint *a, int *e)
+{
+ unsigned long * xa, *xa0, w, y, z;
+ int k;
+ double d;
+#define d0 word0(d)
+#define d1 word1(d)
+
+ xa0 = a->x;
+ xa = xa0 + a->wds;
+ y = *--xa;
+ k = hi0bits(y);
+ *e = 32 - k;
+ if (k < Ebits) {
+ d0 = Exp_1 | y >> Ebits - k;
+ w = xa > xa0 ? *--xa : 0;
+ d1 = y << (32 - Ebits) + k | w >> Ebits - k;
+ goto ret_d;
+ }
+ z = xa > xa0 ? *--xa : 0;
+ if (k -= Ebits) {
+ d0 = Exp_1 | y << k | z >> 32 - k;
+ y = xa > xa0 ? *--xa : 0;
+ d1 = z << k | y >> 32 - k;
+ } else {
+ d0 = Exp_1 | y;
+ d1 = z;
+ }
+ret_d:
+#undef d0
+#undef d1
+ return d;
+}
+
+static Bigint *
+d2b(double d, int *e, int *bits)
+{
+ Bigint * b;
+ int de, i, k;
+ unsigned long * x, y, z;
+#define d0 word0(d)
+#define d1 word1(d)
+
+ b = Balloc(1);
+ x = b->x;
+
+ z = d0 & Frac_mask;
+ d0 &= 0x7fffffff; /* clear sign bit, which we ignore */
+#ifdef Sudden_Underflow
+ de = (int)(d0 >> Exp_shift);
+ z |= Exp_msk11;
+#else
+ if (de = (int)(d0 >> Exp_shift))
+ z |= Exp_msk1;
+#endif
+ if (y = d1) {
+ if (k = lo0bits(&y)) {
+ x[0] = y | z << 32 - k;
+ z >>= k;
+ } else
+ x[0] = y;
+ i = b->wds = (x[1] = z) ? 2 : 1;
+ } else {
+ k = lo0bits(&z);
+ x[0] = z;
+ i = b->wds = 1;
+ k += 32;
+ }
+#ifndef Sudden_Underflow
+ if (de) {
+#endif
+ *e = de - Bias - (P - 1) + k;
+ *bits = P - k;
+#ifndef Sudden_Underflow
+ } else {
+ *e = de - Bias - (P - 1) + 1 + k;
+ *bits = 32 * i - hi0bits(x[i-1]);
+ }
+#endif
+ return b;
+}
+
+#undef d0
+#undef d1
+
+static double
+ratio(Bigint *a, Bigint *b)
+{
+ double da, db;
+ int k, ka, kb;
+
+ da = b2d(a, &ka);
+ db = b2d(b, &kb);
+ k = ka - kb + 32 * (a->wds - b->wds);
+ if (k > 0)
+ word0(da) += k * Exp_msk1;
+ else {
+ k = -k;
+ word0(db) += k * Exp_msk1;
+ }
+ return da / db;
+}
+
+static const double
+tens[] = {
+ 1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9,
+ 1e10, 1e11, 1e12, 1e13, 1e14, 1e15, 1e16, 1e17, 1e18, 1e19,
+ 1e20, 1e21, 1e22
+};
+
+static const double
+bigtens[] = {
+ 1e16, 1e32, 1e64, 1e128, 1e256 };
+
+static const double tinytens[] = {
+ 1e-16, 1e-32, 1e-64, 1e-128,
+ 9007199254740992.e-256
+};
+
+/* The factor of 2^53 in tinytens[4] helps us avoid setting the underflow */
+/* flag unnecessarily. It leads to a song and dance at the end of strtod. */
+#define Scale_Bit 0x10
+#define n_bigtens 5
+
+#define NAN_WORD0 0x7ff80000
+
+#define NAN_WORD1 0
+
+static int
+match(const char **sp, char *t)
+{
+ int c, d;
+ const char * s = *sp;
+
+ while (d = *t++) {
+ if ((c = *++s) >= 'A' && c <= 'Z')
+ c += 'a' - 'A';
+ if (c != d)
+ return 0;
+ }
+ *sp = s + 1;
+ return 1;
+}
+
+double
+strtod(const char *s00, char **se)
+{
+ int scale;
+ int bb2, bb5, bbe, bd2, bd5, bbbits, bs2, c, dsign,
+ e, e1, esign, i, j, k, nd, nd0, nf, nz, nz0, sign;
+ const char * s, *s0, *s1;
+ double aadj, aadj1, adj, rv, rv0;
+ long L;
+ unsigned long y, z;
+ Bigint * bb, *bb1, *bd, *bd0, *bs, *delta;
+ sign = nz0 = nz = 0;
+ rv = 0.;
+ for (s = s00; ; s++)
+ switch (*s) {
+ case '-':
+ sign = 1;
+ /* no break */
+ case '+':
+ if (*++s)
+ goto break2;
+ /* no break */
+ case 0:
+ s = s00;
+ goto ret;
+ case '\t':
+ case '\n':
+ case '\v':
+ case '\f':
+ case '\r':
+ case ' ':
+ continue;
+ default:
+ goto break2;
+ }
+break2:
+ if (*s == '0') {
+ nz0 = 1;
+ while (*++s == '0')
+ ;
+ if (!*s)
+ goto ret;
+ }
+ s0 = s;
+ y = z = 0;
+ for (nd = nf = 0; (c = *s) >= '0' && c <= '9'; nd++, s++)
+ if (nd < 9)
+ y = 10 * y + c - '0';
+ else if (nd < 16)
+ z = 10 * z + c - '0';
+ nd0 = nd;
+ if (c == '.') {
+ c = *++s;
+ if (!nd) {
+ for (; c == '0'; c = *++s)
+ nz++;
+ if (c > '0' && c <= '9') {
+ s0 = s;
+ nf += nz;
+ nz = 0;
+ goto have_dig;
+ }
+ goto dig_done;
+ }
+ for (; c >= '0' && c <= '9'; c = *++s) {
+have_dig:
+ nz++;
+ if (c -= '0') {
+ nf += nz;
+ for (i = 1; i < nz; i++)
+ if (nd++ < 9)
+ y *= 10;
+ else if (nd <= DBL_DIG + 1)
+ z *= 10;
+ if (nd++ < 9)
+ y = 10 * y + c;
+ else if (nd <= DBL_DIG + 1)
+ z = 10 * z + c;
+ nz = 0;
+ }
+ }
+ }
+dig_done:
+ e = 0;
+ if (c == 'e' || c == 'E') {
+ if (!nd && !nz && !nz0) {
+ s = s00;
+ goto ret;
+ }
+ s00 = s;
+ esign = 0;
+ switch (c = *++s) {
+ case '-':
+ esign = 1;
+ case '+':
+ c = *++s;
+ }
+ if (c >= '0' && c <= '9') {
+ while (c == '0')
+ c = *++s;
+ if (c > '0' && c <= '9') {
+ L = c - '0';
+ s1 = s;
+ while ((c = *++s) >= '0' && c <= '9')
+ L = 10 * L + c - '0';
+ if (s - s1 > 8 || L > 19999)
+ /* Avoid confusion from exponents
+ * so large that e might overflow.
+ */
+ e = 19999; /* safe for 16 bit ints */
+ else
+ e = (int)L;
+ if (esign)
+ e = -e;
+ } else
+ e = 0;
+ } else
+ s = s00;
+ }
+ if (!nd) {
+ if (!nz && !nz0) {
+ /* Check for Nan and Infinity */
+ switch (c) {
+ case 'i':
+ case 'I':
+ if (match(&s, "nfinity")) {
+ word0(rv) = 0x7ff00000;
+ word1(rv) = 0;
+ goto ret;
+ }
+ break;
+ case 'n':
+ case 'N':
+ if (match(&s, "an")) {
+ word0(rv) = NAN_WORD0;
+ word1(rv) = NAN_WORD1;
+ goto ret;
+ }
+ }
+ s = s00;
+ }
+ goto ret;
+ }
+ e1 = e -= nf;
+
+ /* Now we have nd0 digits, starting at s0, followed by a
+ * decimal point, followed by nd-nd0 digits. The number we're
+ * after is the integer represented by those digits times
+ * 10**e */
+
+ if (!nd0)
+ nd0 = nd;
+ k = nd < DBL_DIG + 1 ? nd : DBL_DIG + 1;
+ rv = y;
+ if (k > 9)
+ rv = tens[k - 9] * rv + z;
+ bd0 = 0;
+ if (nd <= DBL_DIG
+ && FLT_ROUNDS == 1
+ ) {
+ if (!e)
+ goto ret;
+ if (e > 0) {
+ if (e <= Ten_pmax) {
+ /* rv = */ rounded_product(rv, tens[e]);
+ goto ret;
+ }
+ i = DBL_DIG - nd;
+ if (e <= Ten_pmax + i) {
+ /* A fancier test would sometimes let us do
+ * this for larger i values.
+ */
+ e -= i;
+ rv *= tens[i];
+ /* rv = */ rounded_product(rv, tens[e]);
+ goto ret;
+ }
+ } else if (e >= -Ten_pmax) {
+ /* rv = */ rounded_quotient(rv, tens[-e]);
+ goto ret;
+ }
+ }
+ e1 += nd - k;
+
+ scale = 0;
+
+ /* Get starting approximation = rv * 10**e1 */
+
+ if (e1 > 0) {
+ if (i = e1 & 15)
+ rv *= tens[i];
+ if (e1 &= ~15) {
+ if (e1 > DBL_MAX_10_EXP) {
+ovfl:
+ /* Can't trust HUGE_VAL */
+ word0(rv) = Exp_mask;
+ word1(rv) = 0;
+ if (bd0)
+ goto retfree;
+ goto ret;
+ }
+ if (e1 >>= 4) {
+ for (j = 0; e1 > 1; j++, e1 >>= 1)
+ if (e1 & 1)
+ rv *= bigtens[j];
+ /* The last multiplication could overflow. */
+ word0(rv) -= P * Exp_msk1;
+ rv *= bigtens[j];
+ if ((z = word0(rv) & Exp_mask)
+ > Exp_msk1 * (DBL_MAX_EXP + Bias - P))
+ goto ovfl;
+ if (z > Exp_msk1 * (DBL_MAX_EXP + Bias - 1 - P)) {
+ /* set to largest number */
+ /* (Can't trust DBL_MAX) */
+ word0(rv) = Big0;
+ word1(rv) = Big1;
+ } else
+ word0(rv) += P * Exp_msk1;
+ }
+
+ }
+ } else if (e1 < 0) {
+ e1 = -e1;
+ if (i = e1 & 15)
+ rv /= tens[i];
+ if (e1 &= ~15) {
+ e1 >>= 4;
+ if (e1 >= 1 << n_bigtens)
+ goto undfl;
+ if (e1 & Scale_Bit)
+ scale = P;
+ for (j = 0; e1 > 0; j++, e1 >>= 1)
+ if (e1 & 1)
+ rv *= tinytens[j];
+ if (!rv) {
+undfl:
+ rv = 0.;
+ if (bd0)
+ goto retfree;
+ goto ret;
+ }
+ }
+ }
+
+ /* Now the hard part -- adjusting rv to the correct value.*/
+
+ /* Put digits into bd: true value = bd * 10^e */
+
+ bd0 = s2b(s0, nd0, nd, y);
+
+ for (; ; ) {
+ bd = Balloc(bd0->k);
+ Bcopy(bd, bd0);
+ bb = d2b(rv, &bbe, &bbbits); /* rv = bb * 2^bbe */
+ bs = i2b(1);
+
+ if (e >= 0) {
+ bb2 = bb5 = 0;
+ bd2 = bd5 = e;
+ } else {
+ bb2 = bb5 = -e;
+ bd2 = bd5 = 0;
+ }
+ if (bbe >= 0)
+ bb2 += bbe;
+ else
+ bd2 -= bbe;
+ bs2 = bb2;
+#ifdef Sudden_Underflow
+ j = P + 1 - bbbits;
+#else
+ i = bbe + bbbits - 1; /* logb(rv) */
+ if (i < Emin) /* denormal */
+ j = bbe + (P - Emin);
+ else
+ j = P + 1 - bbbits;
+#endif
+ bb2 += j;
+ bd2 += j;
+ bd2 += scale;
+ i = bb2 < bd2 ? bb2 : bd2;
+ if (i > bs2)
+ i = bs2;
+ if (i > 0) {
+ bb2 -= i;
+ bd2 -= i;
+ bs2 -= i;
+ }
+ if (bb5 > 0) {
+ bs = pow5mult(bs, bb5);
+ bb1 = mult(bs, bb);
+ Bfree(bb);
+ bb = bb1;
+ }
+ if (bb2 > 0)
+ bb = lshift(bb, bb2);
+ if (bd5 > 0)
+ bd = pow5mult(bd, bd5);
+ if (bd2 > 0)
+ bd = lshift(bd, bd2);
+ if (bs2 > 0)
+ bs = lshift(bs, bs2);
+ delta = diff(bb, bd);
+ dsign = delta->sign;
+ delta->sign = 0;
+ i = cmp(delta, bs);
+ if (i < 0) {
+ /* Error is less than half an ulp -- check for
+ * special case of mantissa a power of two.
+ */
+ if (dsign || word1(rv) || word0(rv) & Bndry_mask
+ || (word0(rv) & Exp_mask) <= Exp_msk1
+ ) {
+ if (!delta->x[0] && delta->wds == 1)
+ dsign = 2;
+ break;
+ }
+ delta = lshift(delta, Log2P);
+ if (cmp(delta, bs) > 0)
+ goto drop_down;
+ break;
+ }
+ if (i == 0) {
+ /* exactly half-way between */
+ if (dsign) {
+ if ((word0(rv) & Bndry_mask1) == Bndry_mask1
+ && word1(rv) == 0xffffffff) {
+ /*boundary case -- increment exponent*/
+ word0(rv) = (word0(rv) & Exp_mask)
+ + Exp_msk1
+ ;
+ word1(rv) = 0;
+ dsign = 0;
+ break;
+ }
+ } else if (!(word0(rv) & Bndry_mask) && !word1(rv)) {
+ dsign = 2;
+drop_down:
+ /* boundary case -- decrement exponent */
+#ifdef Sudden_Underflow
+ L = word0(rv) & Exp_mask;
+ if (L <= Exp_msk1)
+ goto undfl;
+ L -= Exp_msk1;
+#else
+ L = (word0(rv) & Exp_mask) - Exp_msk1;
+#endif
+ word0(rv) = L | Bndry_mask1;
+ word1(rv) = 0xffffffff;
+ break;
+ }
+ if (!(word1(rv) & LSB))
+ break;
+ if (dsign)
+ rv += ulp(rv);
+ else {
+ rv -= ulp(rv);
+#ifndef Sudden_Underflow
+ if (!rv)
+ goto undfl;
+#endif
+ }
+ dsign = 1 - dsign;
+ break;
+ }
+ if ((aadj = ratio(delta, bs)) <= 2.) {
+ if (dsign)
+ aadj = aadj1 = 1.;
+ else if (word1(rv) || word0(rv) & Bndry_mask) {
+#ifndef Sudden_Underflow
+ if (word1(rv) == Tiny1 && !word0(rv))
+ goto undfl;
+#endif
+ aadj = 1.;
+ aadj1 = -1.;
+ } else {
+ /* special case -- power of FLT_RADIX to be */
+ /* rounded down... */
+
+ if (aadj < 2. / FLT_RADIX)
+ aadj = 1. / FLT_RADIX;
+ else
+ aadj *= 0.5;
+ aadj1 = -aadj;
+ }
+ } else {
+ aadj *= 0.5;
+ aadj1 = dsign ? aadj : -aadj;
+ if (FLT_ROUNDS == 0)
+ aadj1 += 0.5;
+ }
+ y = word0(rv) & Exp_mask;
+
+ /* Check for overflow */
+
+ if (y == Exp_msk1 * (DBL_MAX_EXP + Bias - 1)) {
+ rv0 = rv;
+ word0(rv) -= P * Exp_msk1;
+ adj = aadj1 * ulp(rv);
+ rv += adj;
+ if ((word0(rv) & Exp_mask) >=
+ Exp_msk1 * (DBL_MAX_EXP + Bias - P)) {
+ if (word0(rv0) == Big0 && word1(rv0) == Big1)
+ goto ovfl;
+ word0(rv) = Big0;
+ word1(rv) = Big1;
+ goto cont;
+ } else
+ word0(rv) += P * Exp_msk1;
+ } else {
+#ifdef Sudden_Underflow
+ if ((word0(rv) & Exp_mask) <= P * Exp_msk1) {
+ rv0 = rv;
+ word0(rv) += P * Exp_msk1;
+ adj = aadj1 * ulp(rv);
+ rv += adj;
+ if ((word0(rv) & Exp_mask) <= P * Exp_msk1) {
+ if (word0(rv0) == Tiny0
+ && word1(rv0) == Tiny1)
+ goto undfl;
+ word0(rv) = Tiny0;
+ word1(rv) = Tiny1;
+ goto cont;
+ } else
+ word0(rv) -= P * Exp_msk1;
+ } else {
+ adj = aadj1 * ulp(rv);
+ rv += adj;
+ }
+#else
+ /* Compute adj so that the IEEE rounding rules will
+ * correctly round rv + adj in some half-way cases.
+ * If rv * ulp(rv) is denormalized (i.e.,
+ * y <= (P-1)*Exp_msk1), we must adjust aadj to avoid
+ * trouble from bits lost to denormalization;
+ * example: 1.2e-307 .
+ */
+ if (y <= (P - 1) * Exp_msk1 && aadj >= 1.) {
+ aadj1 = (double)(int)(aadj + 0.5);
+ if (!dsign)
+ aadj1 = -aadj1;
+ }
+ adj = aadj1 * ulp(rv);
+ rv += adj;
+#endif
+ }
+ z = word0(rv) & Exp_mask;
+ if (!scale)
+ if (y == z) {
+ /* Can we stop now? */
+ L = aadj;
+ aadj -= L;
+ /* The tolerances below are conservative. */
+ if (dsign || word1(rv) || word0(rv) & Bndry_mask) {
+ if (aadj < .4999999 || aadj > .5000001)
+ break;
+ } else if (aadj < .4999999 / FLT_RADIX)
+ break;
+ }
+cont:
+ Bfree(bb);
+ Bfree(bd);
+ Bfree(bs);
+ Bfree(delta);
+ }
+ if (scale) {
+ if ((word0(rv) & Exp_mask) <= P * Exp_msk1
+ && word1(rv) & 1
+ && dsign != 2)
+ if (dsign)
+ rv += ulp(rv);
+ else
+ word1(rv) &= ~1;
+ word0(rv0) = Exp_1 - P * Exp_msk1;
+ word1(rv0) = 0;
+ rv *= rv0;
+ }
+retfree:
+ Bfree(bb);
+ Bfree(bd);
+ Bfree(bs);
+ Bfree(bd0);
+ Bfree(delta);
+ret:
+ if (se)
+ *se = (char *)s;
+ return sign ? -rv : rv;
+}
+
+static int
+quorem(Bigint *b, Bigint *S)
+{
+ int n;
+ long borrow, y;
+ unsigned long carry, q, ys;
+ unsigned long * bx, *bxe, *sx, *sxe;
+ long z;
+ unsigned long si, zs;
+
+ n = S->wds;
+ if (b->wds < n)
+ return 0;
+ sx = S->x;
+ sxe = sx + --n;
+ bx = b->x;
+ bxe = bx + n;
+ q = *bxe / (*sxe + 1); /* ensure q <= true quotient */
+ if (q) {
+ borrow = 0;
+ carry = 0;
+ do {
+ si = *sx++;
+ ys = (si & 0xffff) * q + carry;
+ zs = (si >> 16) * q + (ys >> 16);
+ carry = zs >> 16;
+ y = (*bx & 0xffff) - (ys & 0xffff) + borrow;
+ borrow = y >> 16;
+ Sign_Extend(borrow, y);
+ z = (*bx >> 16) - (zs & 0xffff) + borrow;
+ borrow = z >> 16;
+ Sign_Extend(borrow, z);
+ Storeinc(bx, z, y);
+ } while (sx <= sxe);
+ if (!*bxe) {
+ bx = b->x;
+ while (--bxe > bx && !*bxe)
+ --n;
+ b->wds = n;
+ }
+ }
+ if (cmp(b, S) >= 0) {
+ q++;
+ borrow = 0;
+ carry = 0;
+ bx = b->x;
+ sx = S->x;
+ do {
+ si = *sx++;
+ ys = (si & 0xffff) + carry;
+ zs = (si >> 16) + (ys >> 16);
+ carry = zs >> 16;
+ y = (*bx & 0xffff) - (ys & 0xffff) + borrow;
+ borrow = y >> 16;
+ Sign_Extend(borrow, y);
+ z = (*bx >> 16) - (zs & 0xffff) + borrow;
+ borrow = z >> 16;
+ Sign_Extend(borrow, z);
+ Storeinc(bx, z, y);
+ } while (sx <= sxe);
+ bx = b->x;
+ bxe = bx + n;
+ if (!*bxe) {
+ while (--bxe > bx && !*bxe)
+ --n;
+ b->wds = n;
+ }
+ }
+ return q;
+}
+
+static char *
+rv_alloc(int i)
+{
+ int j, k, *r;
+
+ j = sizeof(unsigned long);
+ for (k = 0;
+ sizeof(Bigint) - sizeof(unsigned long) - sizeof(int) + j <= i;
+ j <<= 1)
+ k++;
+ r = (int * )Balloc(k);
+ *r = k;
+ return
+ (char *)(r + 1);
+}
+
+static char *
+nrv_alloc(char *s, char **rve, int n)
+{
+ char *rv, *t;
+
+ t = rv = rv_alloc(n);
+ while (*t = *s++)
+ t++;
+ if (rve)
+ *rve = t;
+ return rv;
+}
+
+/* freedtoa(s) must be used to free values s returned by dtoa
+ * when MULTIPLE_THREADS is #defined. It should be used in all cases,
+ * but for consistency with earlier versions of dtoa, it is optional
+ * when MULTIPLE_THREADS is not defined.
+ */
+
+void
+freedtoa(char *s)
+{
+ Bigint * b = (Bigint * )((int *)s - 1);
+ b->maxwds = 1 << (b->k = *(int * )b);
+ Bfree(b);
+}
+
+/* dtoa for IEEE arithmetic (dmg): convert double to ASCII string.
+ *
+ * Inspired by "How to Print Floating-Point Numbers Accurately" by
+ * Guy L. Steele, Jr. and Jon L. White [Proc. ACM SIGPLAN '90, pp. 92-101].
+ *
+ * Modifications:
+ * 1. Rather than iterating, we use a simple numeric overestimate
+ * to determine k = floor(log10(d)). We scale relevant
+ * quantities using O(log2(k)) rather than O(k) multiplications.
+ * 2. For some modes > 2 (corresponding to ecvt and fcvt), we don't
+ * try to generate digits strictly left to right. Instead, we
+ * compute with fewer bits and propagate the carry if necessary
+ * when rounding the final digit up. This is often faster.
+ * 3. Under the assumption that input will be rounded nearest,
+ * mode 0 renders 1e23 as 1e23 rather than 9.999999999999999e22.
+ * That is, we allow equality in stopping tests when the
+ * round-nearest rule will give the same floating-point value
+ * as would satisfaction of the stopping test with strict
+ * inequality.
+ * 4. We remove common factors of powers of 2 from relevant
+ * quantities.
+ * 5. When converting floating-point integers less than 1e16,
+ * we use floating-point arithmetic rather than resorting
+ * to multiple-precision integers.
+ * 6. When asked to produce fewer than 15 digits, we first try
+ * to get by with floating-point arithmetic; we resort to
+ * multiple-precision integer arithmetic only if we cannot
+ * guarantee that the floating-point calculation has given
+ * the correctly rounded result. For k requested digits and
+ * "uniformly" distributed input, the probability is
+ * something like 10^(k-15) that we must resort to the long
+ * calculation.
+ */
+
+char *
+dtoa(double d, int mode, int ndigits, int *decpt, int *sign, char **rve)
+{
+ /* Arguments ndigits, decpt, sign are similar to those
+ of ecvt and fcvt; trailing zeros are suppressed from
+ the returned string. If not null, *rve is set to point
+ to the end of the return value. If d is +-Infinity or NaN,
+ then *decpt is set to 9999.
+
+ mode:
+ 0 ==> shortest string that yields d when read in
+ and rounded to nearest.
+ 1 ==> like 0, but with Steele & White stopping rule;
+ e.g. with IEEE P754 arithmetic , mode 0 gives
+ 1e23 whereas mode 1 gives 9.999999999999999e22.
+ 2 ==> max(1,ndigits) significant digits. This gives a
+ return value similar to that of ecvt, except
+ that trailing zeros are suppressed.
+ 3 ==> through ndigits past the decimal point. This
+ gives a return value similar to that from fcvt,
+ except that trailing zeros are suppressed, and
+ ndigits can be negative.
+ 4-9 should give the same return values as 2-3, i.e.,
+ 4 <= mode <= 9 ==> same return as mode
+ 2 + (mode & 1). These modes are mainly for
+ debugging; often they run slower but sometimes
+ faster than modes 2-3.
+ 4,5,8,9 ==> left-to-right digit generation.
+ 6-9 ==> don't try fast floating-point estimate
+ (if applicable).
+
+ Values of mode other than 0-9 are treated as mode 0.
+
+ Sufficient space is allocated to the return value
+ to hold the suppressed trailing zeros.
+ */
+
+ int bbits, b2, b5, be, dig, i, ieps, ilim, ilim0, ilim1,
+ j, j1, k, k0, k_check, leftright, m2, m5, s2, s5,
+ spec_case, try_quick;
+ long L;
+#ifndef Sudden_Underflow
+ int denorm;
+ unsigned long x;
+#endif
+ Bigint * b, *b1, *delta, *mlo, *mhi, *S;
+ double d2, ds, eps;
+ char *s, *s0;
+
+ if (word0(d) & Sign_bit) {
+ /* set sign for everything, including 0's and NaNs */
+ *sign = 1;
+ word0(d) &= ~Sign_bit; /* clear sign bit */
+ } else
+ *sign = 0;
+
+ if ((word0(d) & Exp_mask) == Exp_mask) {
+ /* Infinity or NaN */
+ *decpt = 9999;
+ if (!word1(d) && !(word0(d) & 0xfffff))
+ return nrv_alloc("Infinity", rve, 8);
+ return nrv_alloc("NaN", rve, 3);
+ }
+ if (!d) {
+ *decpt = 1;
+ return nrv_alloc("0", rve, 1);
+ }
+
+ b = d2b(d, &be, &bbits);
+#ifdef Sudden_Underflow
+ i = (int)(word0(d) >> Exp_shift1 & (Exp_mask >> Exp_shift1));
+#else
+ if (i = (int)(word0(d) >> Exp_shift1 & (Exp_mask >> Exp_shift1))) {
+#endif
+ word0(d2) = (word0(d) & Frac_mask1) | Exp_11;
+ word1(d2) = word1(d);
+
+ /* log(x) ~=~ log(1.5) + (x-1.5)/1.5
+ * log10(x) = log(x) / log(10)
+ * ~=~ log(1.5)/log(10) + (x-1.5)/(1.5*log(10))
+ * log10(d) = (i-Bias)*log(2)/log(10) + log10(d2)
+ *
+ * This suggests computing an approximation k to log10(d) by
+ *
+ * k = (i - Bias)*0.301029995663981
+ * + ( (d2-1.5)*0.289529654602168 + 0.176091259055681 );
+ *
+ * We want k to be too large rather than too small.
+ * The error in the first-order Taylor series approximation
+ * is in our favor, so we just round up the constant enough
+ * to compensate for any error in the multiplication of
+ * (i - Bias) by 0.301029995663981; since |i - Bias| <= 1077,
+ * and 1077 * 0.30103 * 2^-52 ~=~ 7.2e-14,
+ * adding 1e-13 to the constant term more than suffices.
+ * Hence we adjust the constant term to 0.1760912590558.
+ * (We could get a more accurate k by invoking log10,
+ * but this is probably not worthwhile.)
+ */
+
+ i -= Bias;
+#ifndef Sudden_Underflow
+ denorm = 0;
+ } else {
+ /* d is denormalized */
+
+ i = bbits + be + (Bias + (P - 1) - 1);
+ x = i > 32 ? word0(d) << 64 - i | word1(d) >> i - 32
+ : word1(d) << 32 - i;
+ d2 = x;
+ word0(d2) -= 31 * Exp_msk1; /* adjust exponent */
+ i -= (Bias + (P - 1) - 1) + 1;
+ denorm = 1;
+ }
+#endif
+ ds = (d2 - 1.5) * 0.289529654602168 + 0.1760912590558 + i * 0.301029995663981;
+ k = (int)ds;
+ if (ds < 0. && ds != k)
+ k--; /* want k = floor(ds) */
+ k_check = 1;
+ if (k >= 0 && k <= Ten_pmax) {
+ if (d < tens[k])
+ k--;
+ k_check = 0;
+ }
+ j = bbits - i - 1;
+ if (j >= 0) {
+ b2 = 0;
+ s2 = j;
+ } else {
+ b2 = -j;
+ s2 = 0;
+ }
+ if (k >= 0) {
+ b5 = 0;
+ s5 = k;
+ s2 += k;
+ } else {
+ b2 -= k;
+ b5 = -k;
+ s5 = 0;
+ }
+ if (mode < 0 || mode > 9)
+ mode = 0;
+ try_quick = 1;
+ if (mode > 5) {
+ mode -= 4;
+ try_quick = 0;
+ }
+ leftright = 1;
+ switch (mode) {
+ case 0:
+ case 1:
+ ilim = ilim1 = -1;
+ i = 18;
+ ndigits = 0;
+ break;
+ case 2:
+ leftright = 0;
+ /* no break */
+ case 4:
+ if (ndigits <= 0)
+ ndigits = 1;
+ ilim = ilim1 = i = ndigits;
+ break;
+ case 3:
+ leftright = 0;
+ /* no break */
+ case 5:
+ i = ndigits + k + 1;
+ ilim = i;
+ ilim1 = i - 1;
+ if (i <= 0)
+ i = 1;
+ }
+ s = s0 = rv_alloc(i);
+
+ if (ilim >= 0 && ilim <= Quick_max && try_quick) {
+
+ /* Try to get by with floating-point arithmetic. */
+
+ i = 0;
+ d2 = d;
+ k0 = k;
+ ilim0 = ilim;
+ ieps = 2; /* conservative */
+ if (k > 0) {
+ ds = tens[k&0xf];
+ j = k >> 4;
+ if (j & Bletch) {
+ /* prevent overflows */
+ j &= Bletch - 1;
+ d /= bigtens[n_bigtens-1];
+ ieps++;
+ }
+ for (; j; j >>= 1, i++)
+ if (j & 1) {
+ ieps++;
+ ds *= bigtens[i];
+ }
+ d /= ds;
+ } else if (j1 = -k) {
+ d *= tens[j1 & 0xf];
+ for (j = j1 >> 4; j; j >>= 1, i++)
+ if (j & 1) {
+ ieps++;
+ d *= bigtens[i];
+ }
+ }
+ if (k_check && d < 1. && ilim > 0) {
+ if (ilim1 <= 0)
+ goto fast_failed;
+ ilim = ilim1;
+ k--;
+ d *= 10.;
+ ieps++;
+ }
+ eps = ieps * d + 7.;
+ word0(eps) -= (P - 1) * Exp_msk1;
+ if (ilim == 0) {
+ S = mhi = 0;
+ d -= 5.;
+ if (d > eps)
+ goto one_digit;
+ if (d < -eps)
+ goto no_digits;
+ goto fast_failed;
+ }
+ /* Generate ilim digits, then fix them up. */
+ eps *= tens[ilim-1];
+ for (i = 1; ; i++, d *= 10.) {
+ L = d;
+ d -= L;
+ *s++ = '0' + (int)L;
+ if (i == ilim) {
+ if (d > 0.5 + eps)
+ goto bump_up;
+ else if (d < 0.5 - eps) {
+ while (*--s == '0')
+ ;
+ s++;
+ goto ret1;
+ }
+ break;
+ }
+ }
+fast_failed:
+ s = s0;
+ d = d2;
+ k = k0;
+ ilim = ilim0;
+ }
+
+ /* Do we have a "small" integer? */
+
+ if (be >= 0 && k <= Int_max) {
+ /* Yes. */
+ ds = tens[k];
+ if (ndigits < 0 && ilim <= 0) {
+ S = mhi = 0;
+ if (ilim < 0 || d <= 5 * ds)
+ goto no_digits;
+ goto one_digit;
+ }
+ for (i = 1; ; i++) {
+ L = d / ds;
+ d -= L * ds;
+ *s++ = '0' + (int)L;
+ if (i == ilim) {
+ d += d;
+ if (d > ds || d == ds && L & 1) {
+bump_up:
+ while (*--s == '9')
+ if (s == s0) {
+ k++;
+ *s = '0';
+ break;
+ }
+ ++ * s++;
+ }
+ break;
+ }
+ if (!(d *= 10.))
+ break;
+ }
+ goto ret1;
+ }
+
+ m2 = b2;
+ m5 = b5;
+ mhi = mlo = 0;
+ if (leftright) {
+ if (mode < 2) {
+ i =
+#ifndef Sudden_Underflow
+ denorm ? be + (Bias + (P - 1) - 1 + 1) :
+#endif
+ 1 + P - bbits;
+ } else {
+ j = ilim - 1;
+ if (m5 >= j)
+ m5 -= j;
+ else {
+ s5 += j -= m5;
+ b5 += j;
+ m5 = 0;
+ }
+ if ((i = ilim) < 0) {
+ m2 -= i;
+ i = 0;
+ }
+ }
+ b2 += i;
+ s2 += i;
+ mhi = i2b(1);
+ }
+ if (m2 > 0 && s2 > 0) {
+ i = m2 < s2 ? m2 : s2;
+ b2 -= i;
+ m2 -= i;
+ s2 -= i;
+ }
+ if (b5 > 0) {
+ if (leftright) {
+ if (m5 > 0) {
+ mhi = pow5mult(mhi, m5);
+ b1 = mult(mhi, b);
+ Bfree(b);
+ b = b1;
+ }
+ if (j = b5 - m5)
+ b = pow5mult(b, j);
+ } else
+ b = pow5mult(b, b5);
+ }
+ S = i2b(1);
+ if (s5 > 0)
+ S = pow5mult(S, s5);
+
+ /* Check for special case that d is a normalized power of 2. */
+
+ spec_case = 0;
+ if (mode < 2) {
+ if (!word1(d) && !(word0(d) & Bndry_mask)
+#ifndef Sudden_Underflow
+ && word0(d) & Exp_mask
+#endif
+ ) {
+ /* The special case */
+ b2 += Log2P;
+ s2 += Log2P;
+ spec_case = 1;
+ }
+ }
+
+ /* Arrange for convenient computation of quotients:
+ * shift left if necessary so divisor has 4 leading 0 bits.
+ *
+ * Perhaps we should just compute leading 28 bits of S once
+ * and for all and pass them and a shift to quorem, so it
+ * can do shifts and ors to compute the numerator for q.
+ */
+ if (i = ((s5 ? 32 - hi0bits(S->x[S->wds-1]) : 1) + s2) & 0x1f)
+ i = 32 - i;
+ if (i > 4) {
+ i -= 4;
+ b2 += i;
+ m2 += i;
+ s2 += i;
+ } else if (i < 4) {
+ i += 28;
+ b2 += i;
+ m2 += i;
+ s2 += i;
+ }
+ if (b2 > 0)
+ b = lshift(b, b2);
+ if (s2 > 0)
+ S = lshift(S, s2);
+ if (k_check) {
+ if (cmp(b, S) < 0) {
+ k--;
+ b = multadd(b, 10, 0); /* we botched the k estimate */
+ if (leftright)
+ mhi = multadd(mhi, 10, 0);
+ ilim = ilim1;
+ }
+ }
+ if (ilim <= 0 && mode > 2) {
+ if (ilim < 0 || cmp(b, S = multadd(S, 5, 0)) <= 0) {
+ /* no digits, fcvt style */
+no_digits:
+ k = -1 - ndigits;
+ goto ret;
+ }
+one_digit:
+ *s++ = '1';
+ k++;
+ goto ret;
+ }
+ if (leftright) {
+ if (m2 > 0)
+ mhi = lshift(mhi, m2);
+
+ /* Compute mlo -- check for special case
+ * that d is a normalized power of 2.
+ */
+
+ mlo = mhi;
+ if (spec_case) {
+ mhi = Balloc(mhi->k);
+ Bcopy(mhi, mlo);
+ mhi = lshift(mhi, Log2P);
+ }
+
+ for (i = 1; ; i++) {
+ dig = quorem(b, S) + '0';
+ /* Do we yet have the shortest decimal string
+ * that will round to d?
+ */
+ j = cmp(b, mlo);
+ delta = diff(S, mhi);
+ j1 = delta->sign ? 1 : cmp(b, delta);
+ Bfree(delta);
+ if (j1 == 0 && !mode && !(word1(d) & 1)) {
+ if (dig == '9')
+ goto round_9_up;
+ if (j > 0)
+ dig++;
+ *s++ = dig;
+ goto ret;
+ }
+ if (j < 0 || j == 0 && !mode
+ && !(word1(d) & 1)
+ ) {
+ if (j1 > 0) {
+ b = lshift(b, 1);
+ j1 = cmp(b, S);
+ if ((j1 > 0 || j1 == 0 && dig & 1)
+ && dig++ == '9')
+ goto round_9_up;
+ }
+ *s++ = dig;
+ goto ret;
+ }
+ if (j1 > 0) {
+ if (dig == '9') { /* possible if i == 1 */
+round_9_up:
+ *s++ = '9';
+ goto roundoff;
+ }
+ *s++ = dig + 1;
+ goto ret;
+ }
+ *s++ = dig;
+ if (i == ilim)
+ break;
+ b = multadd(b, 10, 0);
+ if (mlo == mhi)
+ mlo = mhi = multadd(mhi, 10, 0);
+ else {
+ mlo = multadd(mlo, 10, 0);
+ mhi = multadd(mhi, 10, 0);
+ }
+ }
+ } else
+ for (i = 1; ; i++) {
+ *s++ = dig = quorem(b, S) + '0';
+ if (i >= ilim)
+ break;
+ b = multadd(b, 10, 0);
+ }
+
+ /* Round off last digit */
+
+ b = lshift(b, 1);
+ j = cmp(b, S);
+ if (j > 0 || j == 0 && dig & 1) {
+roundoff:
+ while (*--s == '9')
+ if (s == s0) {
+ k++;
+ *s++ = '1';
+ goto ret;
+ }
+ ++ * s++;
+ } else {
+ while (*--s == '0')
+ ;
+ s++;
+ }
+ret:
+ Bfree(S);
+ if (mhi) {
+ if (mlo && mlo != mhi)
+ Bfree(mlo);
+ Bfree(mhi);
+ }
+ret1:
+ Bfree(b);
+ *s = 0;
+ *decpt = k + 1;
+ if (rve)
+ *rve = s;
+ return s0;
+}
+
--- /dev/null
+++ b/libmath/fdim.c
@@ -1,0 +1,30 @@
+#include "lib9.h"
+#include "mathi.h"
+
+double
+fdim(double x, double y)
+{
+ if(x>y)
+ return x-y;
+ else
+ return 0;
+}
+
+double
+fmax(double x, double y)
+{
+ if(x>y)
+ return x;
+ else
+ return y;
+}
+
+double
+fmin(double x, double y)
+{
+ if(x<y)
+ return x;
+ else
+ return y;
+}
+
--- /dev/null
+++ b/libmath/fdlibm/e_acos.c
@@ -1,0 +1,97 @@
+/* derived from /netlib/fdlibm */
+
+/* @(#)e_acos.c 1.3 95/01/18 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunSoft, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+/* __ieee754_acos(x)
+ * Method :
+ * acos(x) = pi/2 - asin(x)
+ * acos(-x) = pi/2 + asin(x)
+ * For |x|<=0.5
+ * acos(x) = pi/2 - (x + x*x^2*R(x^2)) (see asin.c)
+ * For x>0.5
+ * acos(x) = pi/2 - (pi/2 - 2asin(sqrt((1-x)/2)))
+ * = 2asin(sqrt((1-x)/2))
+ * = 2s + 2s*z*R(z) ...z=(1-x)/2, s=sqrt(z)
+ * = 2f + (2c + 2s*z*R(z))
+ * where f=hi part of s, and c = (z-f*f)/(s+f) is the correction term
+ * for f so that f+c ~ sqrt(z).
+ * For x<-0.5
+ * acos(x) = pi - 2asin(sqrt((1-|x|)/2))
+ * = pi - 0.5*(s+s*z*R(z)), where z=(1-|x|)/2,s=sqrt(z)
+ *
+ * Special cases:
+ * if x is NaN, return x itself;
+ * if |x|>1, return NaN with invalid signal.
+ *
+ * Function needed: sqrt
+ */
+
+#include "fdlibm.h"
+
+static const double
+one= 1.00000000000000000000e+00, /* 0x3FF00000, 0x00000000 */
+pi = 3.14159265358979311600e+00, /* 0x400921FB, 0x54442D18 */
+pio2_hi = 1.57079632679489655800e+00, /* 0x3FF921FB, 0x54442D18 */
+pio2_lo = 6.12323399573676603587e-17, /* 0x3C91A626, 0x33145C07 */
+pS0 = 1.66666666666666657415e-01, /* 0x3FC55555, 0x55555555 */
+pS1 = -3.25565818622400915405e-01, /* 0xBFD4D612, 0x03EB6F7D */
+pS2 = 2.01212532134862925881e-01, /* 0x3FC9C155, 0x0E884455 */
+pS3 = -4.00555345006794114027e-02, /* 0xBFA48228, 0xB5688F3B */
+pS4 = 7.91534994289814532176e-04, /* 0x3F49EFE0, 0x7501B288 */
+pS5 = 3.47933107596021167570e-05, /* 0x3F023DE1, 0x0DFDF709 */
+qS1 = -2.40339491173441421878e+00, /* 0xC0033A27, 0x1C8A2D4B */
+qS2 = 2.02094576023350569471e+00, /* 0x40002AE5, 0x9C598AC8 */
+qS3 = -6.88283971605453293030e-01, /* 0xBFE6066C, 0x1B8D0159 */
+qS4 = 7.70381505559019352791e-02; /* 0x3FB3B8C5, 0xB12E9282 */
+
+ double __ieee754_acos(double x)
+{
+ double z,p,q,r,w,s,c,df;
+ int hx,ix;
+ hx = __HI(x);
+ ix = hx&0x7fffffff;
+ if(ix>=0x3ff00000) { /* |x| >= 1 */
+ if(((ix-0x3ff00000)|__LO(x))==0) { /* |x|==1 */
+ if(hx>0) return 0.0; /* acos(1) = 0 */
+ else return pi+2.0*pio2_lo; /* acos(-1)= pi */
+ }
+ return (x-x)/(x-x); /* acos(|x|>1) is NaN */
+ }
+ if(ix<0x3fe00000) { /* |x| < 0.5 */
+ if(ix<=0x3c600000) return pio2_hi+pio2_lo;/*if|x|<2**-57*/
+ z = x*x;
+ p = z*(pS0+z*(pS1+z*(pS2+z*(pS3+z*(pS4+z*pS5)))));
+ q = one+z*(qS1+z*(qS2+z*(qS3+z*qS4)));
+ r = p/q;
+ return pio2_hi - (x - (pio2_lo-x*r));
+ } else if (hx<0) { /* x < -0.5 */
+ z = (one+x)*0.5;
+ p = z*(pS0+z*(pS1+z*(pS2+z*(pS3+z*(pS4+z*pS5)))));
+ q = one+z*(qS1+z*(qS2+z*(qS3+z*qS4)));
+ s = sqrt(z);
+ r = p/q;
+ w = r*s-pio2_lo;
+ return pi - 2.0*(s+w);
+ } else { /* x > 0.5 */
+ z = (one-x)*0.5;
+ s = sqrt(z);
+ df = s;
+ __LO(df) = 0;
+ c = (z-df*df)/(s+df);
+ p = z*(pS0+z*(pS1+z*(pS2+z*(pS3+z*(pS4+z*pS5)))));
+ q = one+z*(qS1+z*(qS2+z*(qS3+z*qS4)));
+ r = p/q;
+ w = r*s+c;
+ return 2.0*(df+w);
+ }
+}
--- /dev/null
+++ b/libmath/fdlibm/e_acosh.c
@@ -1,0 +1,57 @@
+/* derived from /netlib/fdlibm */
+
+/* @(#)e_acosh.c 1.3 95/01/18 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunSoft, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ *
+ */
+
+/* __ieee754_acosh(x)
+ * Method :
+ * Based on
+ * acosh(x) = log [ x + sqrt(x*x-1) ]
+ * we have
+ * acosh(x) := log(x)+ln2, if x is large; else
+ * acosh(x) := log(2x-1/(sqrt(x*x-1)+x)) if x>2; else
+ * acosh(x) := log1p(t+sqrt(2.0*t+t*t)); where t=x-1.
+ *
+ * Special cases:
+ * acosh(x) is NaN with signal if x<1.
+ * acosh(NaN) is NaN without signal.
+ */
+
+#include "fdlibm.h"
+
+static const double
+one = 1.0,
+ln2 = 6.93147180559945286227e-01; /* 0x3FE62E42, 0xFEFA39EF */
+
+ double __ieee754_acosh(double x)
+{
+ double t;
+ int hx;
+ hx = __HI(x);
+ if(hx<0x3ff00000) { /* x < 1 */
+ return (x-x)/(x-x);
+ } else if(hx >=0x41b00000) { /* x > 2**28 */
+ if(hx >=0x7ff00000) { /* x is inf of NaN */
+ return x+x;
+ } else
+ return __ieee754_log(x)+ln2; /* acosh(Huge)=log(2x) */
+ } else if(((hx-0x3ff00000)|__LO(x))==0) {
+ return 0.0; /* acosh(1) = 0 */
+ } else if (hx > 0x40000000) { /* 2**28 > x > 2 */
+ t=x*x;
+ return __ieee754_log(2.0*x-one/(x+sqrt(t-one)));
+ } else { /* 1<x<2 */
+ t = x-one;
+ return log1p(t+sqrt(2.0*t+t*t));
+ }
+}
--- /dev/null
+++ b/libmath/fdlibm/e_asin.c
@@ -1,0 +1,106 @@
+/* derived from /netlib/fdlibm */
+
+/* @(#)e_asin.c 1.3 95/01/18 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunSoft, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+/* __ieee754_asin(x)
+ * Method :
+ * Since asin(x) = x + x^3/6 + x^5*3/40 + x^7*15/336 + ...
+ * we approximate asin(x) on [0,0.5] by
+ * asin(x) = x + x*x^2*R(x^2)
+ * where
+ * R(x^2) is a rational approximation of (asin(x)-x)/x^3
+ * and its remez error is bounded by
+ * |(asin(x)-x)/x^3 - R(x^2)| < 2^(-58.75)
+ *
+ * For x in [0.5,1]
+ * asin(x) = pi/2-2*asin(sqrt((1-x)/2))
+ * Let y = (1-x), z = y/2, s := sqrt(z), and pio2_hi+pio2_lo=pi/2;
+ * then for x>0.98
+ * asin(x) = pi/2 - 2*(s+s*z*R(z))
+ * = pio2_hi - (2*(s+s*z*R(z)) - pio2_lo)
+ * For x<=0.98, let pio4_hi = pio2_hi/2, then
+ * f = hi part of s;
+ * c = sqrt(z) - f = (z-f*f)/(s+f) ...f+c=sqrt(z)
+ * and
+ * asin(x) = pi/2 - 2*(s+s*z*R(z))
+ * = pio4_hi+(pio4-2s)-(2s*z*R(z)-pio2_lo)
+ * = pio4_hi+(pio4-2f)-(2s*z*R(z)-(pio2_lo+2c))
+ *
+ * Special cases:
+ * if x is NaN, return x itself;
+ * if |x|>1, return NaN with invalid signal.
+ *
+ */
+
+
+#include "fdlibm.h"
+
+static const double
+one = 1.00000000000000000000e+00, /* 0x3FF00000, 0x00000000 */
+Huge = 1.000e+300,
+pio2_hi = 1.57079632679489655800e+00, /* 0x3FF921FB, 0x54442D18 */
+pio2_lo = 6.12323399573676603587e-17, /* 0x3C91A626, 0x33145C07 */
+pio4_hi = 7.85398163397448278999e-01, /* 0x3FE921FB, 0x54442D18 */
+ /* coefficient for R(x^2) */
+pS0 = 1.66666666666666657415e-01, /* 0x3FC55555, 0x55555555 */
+pS1 = -3.25565818622400915405e-01, /* 0xBFD4D612, 0x03EB6F7D */
+pS2 = 2.01212532134862925881e-01, /* 0x3FC9C155, 0x0E884455 */
+pS3 = -4.00555345006794114027e-02, /* 0xBFA48228, 0xB5688F3B */
+pS4 = 7.91534994289814532176e-04, /* 0x3F49EFE0, 0x7501B288 */
+pS5 = 3.47933107596021167570e-05, /* 0x3F023DE1, 0x0DFDF709 */
+qS1 = -2.40339491173441421878e+00, /* 0xC0033A27, 0x1C8A2D4B */
+qS2 = 2.02094576023350569471e+00, /* 0x40002AE5, 0x9C598AC8 */
+qS3 = -6.88283971605453293030e-01, /* 0xBFE6066C, 0x1B8D0159 */
+qS4 = 7.70381505559019352791e-02; /* 0x3FB3B8C5, 0xB12E9282 */
+
+ double __ieee754_asin(double x)
+{
+ double t,w,p,q,c,r,s;
+ int hx,ix;
+ hx = __HI(x);
+ ix = hx&0x7fffffff;
+ if(ix>= 0x3ff00000) { /* |x|>= 1 */
+ if(((ix-0x3ff00000)|__LO(x))==0)
+ /* asin(1)=+-pi/2 with inexact */
+ return x*pio2_hi+x*pio2_lo;
+ return (x-x)/(x-x); /* asin(|x|>1) is NaN */
+ } else if (ix<0x3fe00000) { /* |x|<0.5 */
+ if(ix<0x3e400000) { /* if |x| < 2**-27 */
+ if(Huge+x>one) return x;/* return x with inexact if x!=0*/
+ }
+ t = x*x;
+ p = t*(pS0+t*(pS1+t*(pS2+t*(pS3+t*(pS4+t*pS5)))));
+ q = one+t*(qS1+t*(qS2+t*(qS3+t*qS4)));
+ w = p/q;
+ return x+x*w;
+ }
+ /* 1> |x|>= 0.5 */
+ w = one-fabs(x);
+ t = w*0.5;
+ p = t*(pS0+t*(pS1+t*(pS2+t*(pS3+t*(pS4+t*pS5)))));
+ q = one+t*(qS1+t*(qS2+t*(qS3+t*qS4)));
+ s = sqrt(t);
+ if(ix>=0x3FEF3333) { /* if |x| > 0.975 */
+ w = p/q;
+ t = pio2_hi-(2.0*(s+s*w)-pio2_lo);
+ } else {
+ w = s;
+ __LO(w) = 0;
+ c = (t-w*w)/(s+w);
+ r = p/q;
+ p = 2.0*s*r-(pio2_lo-2.0*c);
+ q = pio4_hi-2.0*w;
+ t = pio4_hi-(p-q);
+ }
+ if(hx>0) return t; else return -t;
+}
--- /dev/null
+++ b/libmath/fdlibm/e_atan2.c
@@ -1,0 +1,115 @@
+/* derived from /netlib/fdlibm */
+
+/* @(#)e_atan2.c 1.3 95/01/18 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunSoft, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ *
+ */
+
+/* __ieee754_atan2(y,x)
+ * Method :
+ * 1. Reduce y to positive by atan2(y,x)=-atan2(-y,x).
+ * 2. Reduce x to positive by (if x and y are unexceptional):
+ * ARG (x+iy) = arctan(y/x) ... if x > 0,
+ * ARG (x+iy) = pi - arctan[y/(-x)] ... if x < 0,
+ *
+ * Special cases:
+ *
+ * ATAN2((anything), NaN ) is NaN;
+ * ATAN2(NAN , (anything) ) is NaN;
+ * ATAN2(+-0, +(anything but NaN)) is +-0 ;
+ * ATAN2(+-0, -(anything but NaN)) is +-pi ;
+ * ATAN2(+-(anything but 0 and NaN), 0) is +-pi/2;
+ * ATAN2(+-(anything but INF and NaN), +INF) is +-0 ;
+ * ATAN2(+-(anything but INF and NaN), -INF) is +-pi;
+ * ATAN2(+-INF,+INF ) is +-pi/4 ;
+ * ATAN2(+-INF,-INF ) is +-3pi/4;
+ * ATAN2(+-INF, (anything but,0,NaN, and INF)) is +-pi/2;
+ *
+ * Constants:
+ * The hexadecimal values are the intended ones for the following
+ * constants. The decimal values may be used, provided that the
+ * compiler will convert from decimal to binary accurately enough
+ * to produce the hexadecimal values shown.
+ */
+
+#include "fdlibm.h"
+
+static const double
+tiny = 1.0e-300,
+zero = 0.0,
+pi_o_4 = 7.8539816339744827900E-01, /* 0x3FE921FB, 0x54442D18 */
+pi_o_2 = 1.5707963267948965580E+00, /* 0x3FF921FB, 0x54442D18 */
+pi = 3.1415926535897931160E+00, /* 0x400921FB, 0x54442D18 */
+pi_lo = 1.2246467991473531772E-16; /* 0x3CA1A626, 0x33145C07 */
+
+ double __ieee754_atan2(double y, double x)
+{
+ double z;
+ int k,m,hx,hy,ix,iy;
+ unsigned lx,ly;
+
+ hx = __HI(x); ix = hx&0x7fffffff;
+ lx = __LO(x);
+ hy = __HI(y); iy = hy&0x7fffffff;
+ ly = __LO(y);
+ if(((ix|((lx|-lx)>>31))>0x7ff00000)||
+ ((iy|((ly|-ly)>>31))>0x7ff00000)) /* x or y is NaN */
+ return x+y;
+ if((hx-0x3ff00000|lx)==0) return atan(y); /* x=1.0 */
+ m = ((hy>>31)&1)|((hx>>30)&2); /* 2*sign(x)+sign(y) */
+
+ /* when y = 0 */
+ if((iy|ly)==0) {
+ switch(m) {
+ case 0:
+ case 1: return y; /* atan(+-0,+anything)=+-0 */
+ case 2: return pi+tiny;/* atan(+0,-anything) = pi */
+ case 3: return -pi-tiny;/* atan(-0,-anything) =-pi */
+ }
+ }
+ /* when x = 0 */
+ if((ix|lx)==0) return (hy<0)? -pi_o_2-tiny: pi_o_2+tiny;
+
+ /* when x is INF */
+ if(ix==0x7ff00000) {
+ if(iy==0x7ff00000) {
+ switch(m) {
+ case 0: return pi_o_4+tiny;/* atan(+INF,+INF) */
+ case 1: return -pi_o_4-tiny;/* atan(-INF,+INF) */
+ case 2: return 3.0*pi_o_4+tiny;/*atan(+INF,-INF)*/
+ case 3: return -3.0*pi_o_4-tiny;/*atan(-INF,-INF)*/
+ }
+ } else {
+ switch(m) {
+ case 0: return zero ; /* atan(+...,+INF) */
+ case 1: return -zero ; /* atan(-...,+INF) */
+ case 2: return pi+tiny ; /* atan(+...,-INF) */
+ case 3: return -pi-tiny ; /* atan(-...,-INF) */
+ }
+ }
+ }
+ /* when y is INF */
+ if(iy==0x7ff00000) return (hy<0)? -pi_o_2-tiny: pi_o_2+tiny;
+
+ /* compute y/x */
+ k = (iy-ix)>>20;
+ if(k > 60) z=pi_o_2+0.5*pi_lo; /* |y/x| > 2**60 */
+ else if(hx<0&&k<-60) z=0.0; /* |y|/x < -2**60 */
+ else z=atan(fabs(y/x)); /* safe to do y/x */
+ switch (m) {
+ case 0: return z ; /* atan(+,+) */
+ case 1: __HI(z) ^= 0x80000000;
+ return z ; /* atan(-,+) */
+ case 2: return pi-(z-pi_lo);/* atan(+,-) */
+ default: /* case 3 */
+ return (z-pi_lo)-pi;/* atan(-,-) */
+ }
+}
--- /dev/null
+++ b/libmath/fdlibm/e_atanh.c
@@ -1,0 +1,60 @@
+/* derived from /netlib/fdlibm */
+
+/* @(#)e_atanh.c 1.3 95/01/18 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunSoft, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ *
+ */
+
+/* __ieee754_atanh(x)
+ * Method :
+ * 1.Reduced x to positive by atanh(-x) = -atanh(x)
+ * 2.For x>=0.5
+ * 1 2x x
+ * atanh(x) = --- * log(1 + -------) = 0.5 * log1p(2 * --------)
+ * 2 1 - x 1 - x
+ *
+ * For x<0.5
+ * atanh(x) = 0.5*log1p(2x+2x*x/(1-x))
+ *
+ * Special cases:
+ * atanh(x) is NaN if |x| > 1 with signal;
+ * atanh(NaN) is that NaN with no signal;
+ * atanh(+-1) is +-INF with signal.
+ *
+ */
+
+#include "fdlibm.h"
+
+static const double one = 1.0, Huge = 1e300;
+
+static double zero = 0.0;
+
+ double __ieee754_atanh(double x)
+{
+ double t;
+ int hx,ix;
+ unsigned lx;
+ hx = __HI(x); /* high word */
+ lx = __LO(x); /* low word */
+ ix = hx&0x7fffffff;
+ if ((ix|((lx|(-lx))>>31))>0x3ff00000) /* |x|>1 */
+ return (x-x)/(x-x);
+ if(ix==0x3ff00000)
+ return x/zero;
+ if(ix<0x3e300000&&(Huge+x)>zero) return x; /* x<2**-28 */
+ __HI(x) = ix; /* x <- |x| */
+ if(ix<0x3fe00000) { /* x < 0.5 */
+ t = x+x;
+ t = 0.5*log1p(t+t*x/(one-x));
+ } else
+ t = 0.5*log1p((x+x)/(one-x));
+ if(hx>=0) return t; else return -t;
+}
--- /dev/null
+++ b/libmath/fdlibm/e_cosh.c
@@ -1,0 +1,81 @@
+/* derived from /netlib/fdlibm */
+
+/* @(#)e_cosh.c 1.3 95/01/18 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunSoft, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+/* __ieee754_cosh(x)
+ * Method :
+ * mathematically cosh(x) if defined to be (exp(x)+exp(-x))/2
+ * 1. Replace x by |x| (cosh(x) = cosh(-x)).
+ * 2.
+ * [ exp(x) - 1 ]^2
+ * 0 <= x <= ln2/2 : cosh(x) := 1 + -------------------
+ * 2*exp(x)
+ *
+ * exp(x) + 1/exp(x)
+ * ln2/2 <= x <= 22 : cosh(x) := -------------------
+ * 2
+ * 22 <= x <= lnovft : cosh(x) := exp(x)/2
+ * lnovft <= x <= ln2ovft: cosh(x) := exp(x/2)/2 * exp(x/2)
+ * ln2ovft < x : cosh(x) := Huge*Huge (overflow)
+ *
+ * Special cases:
+ * cosh(x) is |x| if x is +INF, -INF, or NaN.
+ * only cosh(0)=1 is exact for finite x.
+ */
+
+#include "fdlibm.h"
+
+static const double one = 1.0, half=0.5, Huge = 1.0e300;
+
+ double __ieee754_cosh(double x)
+{
+ double t,w;
+ int ix;
+ unsigned lx;
+
+ /* High word of |x|. */
+ ix = __HI(x);
+ ix &= 0x7fffffff;
+
+ /* x is INF or NaN */
+ if(ix>=0x7ff00000) return x*x;
+
+ /* |x| in [0,0.5*ln2], return 1+expm1(|x|)^2/(2*exp(|x|)) */
+ if(ix<0x3fd62e43) {
+ t = expm1(fabs(x));
+ w = one+t;
+ if (ix<0x3c800000) return w; /* cosh(tiny) = 1 */
+ return one+(t*t)/(w+w);
+ }
+
+ /* |x| in [0.5*ln2,22], return (exp(|x|)+1/exp(|x|)/2; */
+ if (ix < 0x40360000) {
+ t = __ieee754_exp(fabs(x));
+ return half*t+half/t;
+ }
+
+ /* |x| in [22, log(maxdouble)] return half*exp(|x|) */
+ if (ix < 0x40862E42) return half*__ieee754_exp(fabs(x));
+
+ /* |x| in [log(maxdouble), overflowthresold] */
+ lx = *( (((*(unsigned*)&one)>>29)) + (unsigned*)&x);
+ if (ix<0x408633CE ||
+ (ix==0x408633ce)&&(lx<=(unsigned)0x8fb9f87d)) {
+ w = __ieee754_exp(half*fabs(x));
+ t = half*w;
+ return t*w;
+ }
+
+ /* |x| > overflowthresold, cosh(x) overflow */
+ return Huge*Huge;
+}
--- /dev/null
+++ b/libmath/fdlibm/e_exp.c
@@ -1,0 +1,149 @@
+/* derived from /netlib/fdlibm */
+
+/* @(#)e_exp.c 1.3 95/01/18 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunSoft, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+/* __ieee754_exp(x)
+ * Returns the exponential of x.
+ *
+ * Method
+ * 1. Argument reduction:
+ * Reduce x to an r so that |r| <= 0.5*ln2 ~ 0.34658.
+ * Given x, find r and integer k such that
+ *
+ * x = k*ln2 + r, |r| <= 0.5*ln2.
+ *
+ * Here r will be represented as r = hi-lo for better
+ * accuracy.
+ *
+ * 2. Approximation of exp(r) by a special rational function on
+ * the interval [0,0.34658]:
+ * Write
+ * R(r**2) = r*(exp(r)+1)/(exp(r)-1) = 2 + r*r/6 - r**4/360 + ...
+ * We use a special Reme algorithm on [0,0.34658] to generate
+ * a polynomial of degree 5 to approximate R. The maximum error
+ * of this polynomial approximation is bounded by 2**-59. In
+ * other words,
+ * R(z) ~ 2.0 + P1*z + P2*z**2 + P3*z**3 + P4*z**4 + P5*z**5
+ * (where z=r*r, and the values of P1 to P5 are listed below)
+ * and
+ * | 5 | -59
+ * | 2.0+P1*z+...+P5*z - R(z) | <= 2
+ * | |
+ * The computation of exp(r) thus becomes
+ * 2*r
+ * exp(r) = 1 + -------
+ * R - r
+ * r*R1(r)
+ * = 1 + r + ----------- (for better accuracy)
+ * 2 - R1(r)
+ * where
+ * 2 4 10
+ * R1(r) = r - (P1*r + P2*r + ... + P5*r ).
+ *
+ * 3. Scale back to obtain exp(x):
+ * From step 1, we have
+ * exp(x) = 2^k * exp(r)
+ *
+ * Special cases:
+ * exp(INF) is INF, exp(NaN) is NaN;
+ * exp(-INF) is 0, and
+ * for finite argument, only exp(0)=1 is exact.
+ *
+ * Accuracy:
+ * according to an error analysis, the error is always less than
+ * 1 ulp (unit in the last place).
+ *
+ * Misc. info.
+ * For IEEE double
+ * if x > 7.09782712893383973096e+02 then exp(x) overflow
+ * if x < -7.45133219101941108420e+02 then exp(x) underflow
+ *
+ * Constants:
+ * The hexadecimal values are the intended ones for the following
+ * constants. The decimal values may be used, provided that the
+ * compiler will convert from decimal to binary accurately enough
+ * to produce the hexadecimal values shown.
+ */
+
+#include "fdlibm.h"
+
+static const double
+one = 1.0,
+halF[2] = {0.5,-0.5,},
+Huge = 1.0e+300,
+twom1000= 9.33263618503218878990e-302, /* 2**-1000=0x01700000,0*/
+o_threshold= 7.09782712893383973096e+02, /* 0x40862E42, 0xFEFA39EF */
+u_threshold= -7.45133219101941108420e+02, /* 0xc0874910, 0xD52D3051 */
+ln2HI[2] ={ 6.93147180369123816490e-01, /* 0x3fe62e42, 0xfee00000 */
+ -6.93147180369123816490e-01,},/* 0xbfe62e42, 0xfee00000 */
+ln2LO[2] ={ 1.90821492927058770002e-10, /* 0x3dea39ef, 0x35793c76 */
+ -1.90821492927058770002e-10,},/* 0xbdea39ef, 0x35793c76 */
+invln2 = 1.44269504088896338700e+00, /* 0x3ff71547, 0x652b82fe */
+P1 = 1.66666666666666019037e-01, /* 0x3FC55555, 0x5555553E */
+P2 = -2.77777777770155933842e-03, /* 0xBF66C16C, 0x16BEBD93 */
+P3 = 6.61375632143793436117e-05, /* 0x3F11566A, 0xAF25DE2C */
+P4 = -1.65339022054652515390e-06, /* 0xBEBBBD41, 0xC5D26BF1 */
+P5 = 4.13813679705723846039e-08; /* 0x3E663769, 0x72BEA4D0 */
+
+
+ double __ieee754_exp(double x) /* default IEEE double exp */
+{
+ double y,hi,lo,c,t;
+ int k,xsb;
+ unsigned hx;
+
+ hx = __HI(x); /* high word of x */
+ xsb = (hx>>31)&1; /* sign bit of x */
+ hx &= 0x7fffffff; /* high word of |x| */
+
+ /* filter out non-finite argument */
+ if(hx >= 0x40862E42) { /* if |x|>=709.78... */
+ if(hx>=0x7ff00000) {
+ if(((hx&0xfffff)|__LO(x))!=0)
+ return x+x; /* NaN */
+ else return (xsb==0)? x:0.0; /* exp(+-inf)={inf,0} */
+ }
+ if(x > o_threshold) return Huge*Huge; /* overflow */
+ if(x < u_threshold) return twom1000*twom1000; /* underflow */
+ }
+
+ /* argument reduction */
+ if(hx > 0x3fd62e42) { /* if |x| > 0.5 ln2 */
+ if(hx < 0x3FF0A2B2) { /* and |x| < 1.5 ln2 */
+ hi = x-ln2HI[xsb]; lo=ln2LO[xsb]; k = 1-xsb-xsb;
+ } else {
+ k = invln2*x+halF[xsb];
+ t = k;
+ hi = x - t*ln2HI[0]; /* t*ln2HI is exact here */
+ lo = t*ln2LO[0];
+ }
+ x = hi - lo;
+ }
+ else if(hx < 0x3e300000) { /* when |x|<2**-28 */
+ if(Huge+x>one) return one+x;/* trigger inexact */
+ }
+ else k = 0;
+
+ /* x is now in primary range */
+ t = x*x;
+ c = x - t*(P1+t*(P2+t*(P3+t*(P4+t*P5))));
+ if(k==0) return one-((x*c)/(c-2.0)-x);
+ else y = one-((lo-(x*c)/(2.0-c))-hi);
+ if(k >= -1021) {
+ __HI(y) += (k<<20); /* add k to y's exponent */
+ return y;
+ } else {
+ __HI(y) += ((k+1000)<<20);/* add k to y's exponent */
+ return y*twom1000;
+ }
+}
--- /dev/null
+++ b/libmath/fdlibm/e_fmod.c
@@ -1,0 +1,132 @@
+/* derived from /netlib/fdlibm */
+
+/* @(#)e_fmod.c 1.3 95/01/18 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunSoft, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+/*
+ * __ieee754_fmod(x,y)
+ * Return x mod y in exact arithmetic
+ * Method: shift and subtract
+ */
+
+#include "fdlibm.h"
+
+static const double one = 1.0, Zero[] = {0.0, -0.0,};
+
+ double __ieee754_fmod(double x, double y)
+{
+ int n,hx,hy,hz,ix,iy,sx,i;
+ unsigned lx,ly,lz;
+
+ hx = __HI(x); /* high word of x */
+ lx = __LO(x); /* low word of x */
+ hy = __HI(y); /* high word of y */
+ ly = __LO(y); /* low word of y */
+ sx = hx&0x80000000; /* sign of x */
+ hx ^=sx; /* |x| */
+ hy &= 0x7fffffff; /* |y| */
+
+ /* purge off exception values */
+ if((hy|ly)==0||(hx>=0x7ff00000)|| /* y=0,or x not finite */
+ ((hy|((ly|-ly)>>31))>0x7ff00000)) /* or y is NaN */
+ return (x*y)/(x*y);
+ if(hx<=hy) {
+ if((hx<hy)||(lx<ly)) return x; /* |x|<|y| return x */
+ if(lx==ly)
+ return Zero[(unsigned)sx>>31]; /* |x|=|y| return x*0*/
+ }
+
+ /* determine ix = ilogb(x) */
+ if(hx<0x00100000) { /* subnormal x */
+ if(hx==0) {
+ for (ix = -1043, i=lx; i>0; i<<=1) ix -=1;
+ } else {
+ for (ix = -1022,i=(hx<<11); i>0; i<<=1) ix -=1;
+ }
+ } else ix = (hx>>20)-1023;
+
+ /* determine iy = ilogb(y) */
+ if(hy<0x00100000) { /* subnormal y */
+ if(hy==0) {
+ for (iy = -1043, i=ly; i>0; i<<=1) iy -=1;
+ } else {
+ for (iy = -1022,i=(hy<<11); i>0; i<<=1) iy -=1;
+ }
+ } else iy = (hy>>20)-1023;
+
+ /* set up {hx,lx}, {hy,ly} and align y to x */
+ if(ix >= -1022)
+ hx = 0x00100000|(0x000fffff&hx);
+ else { /* subnormal x, shift x to normal */
+ n = -1022-ix;
+ if(n<=31) {
+ hx = (hx<<n)|(lx>>(32-n));
+ lx <<= n;
+ } else {
+ hx = lx<<(n-32);
+ lx = 0;
+ }
+ }
+ if(iy >= -1022)
+ hy = 0x00100000|(0x000fffff&hy);
+ else { /* subnormal y, shift y to normal */
+ n = -1022-iy;
+ if(n<=31) {
+ hy = (hy<<n)|(ly>>(32-n));
+ ly <<= n;
+ } else {
+ hy = ly<<(n-32);
+ ly = 0;
+ }
+ }
+
+ /* fix point fmod */
+ n = ix - iy;
+ while(n--) {
+ hz=hx-hy;lz=lx-ly; if(lx<ly) hz -= 1;
+ if(hz<0){hx = hx+hx+(lx>>31); lx = lx+lx;}
+ else {
+ if((hz|lz)==0) /* return sign(x)*0 */
+ return Zero[(unsigned)sx>>31];
+ hx = hz+hz+(lz>>31); lx = lz+lz;
+ }
+ }
+ hz=hx-hy;lz=lx-ly; if(lx<ly) hz -= 1;
+ if(hz>=0) {hx=hz;lx=lz;}
+
+ /* convert back to floating value and restore the sign */
+ if((hx|lx)==0) /* return sign(x)*0 */
+ return Zero[(unsigned)sx>>31];
+ while(hx<0x00100000) { /* normalize x */
+ hx = hx+hx+(lx>>31); lx = lx+lx;
+ iy -= 1;
+ }
+ if(iy>= -1022) { /* normalize output */
+ hx = ((hx-0x00100000)|((iy+1023)<<20));
+ __HI(x) = hx|sx;
+ __LO(x) = lx;
+ } else { /* subnormal output */
+ n = -1022 - iy;
+ if(n<=20) {
+ lx = (lx>>n)|((unsigned)hx<<(32-n));
+ hx >>= n;
+ } else if (n<=31) {
+ lx = (hx<<(32-n))|(lx>>n); hx = sx;
+ } else {
+ lx = hx>>(n-32); hx = sx;
+ }
+ __HI(x) = hx|sx;
+ __LO(x) = lx;
+ x *= one; /* create necessary signal */
+ }
+ return x; /* exact output */
+}
--- /dev/null
+++ b/libmath/fdlibm/e_hypot.c
@@ -1,0 +1,111 @@
+/* derived from /netlib/fdlibm */
+
+/* @(#)e_hypot.c 1.3 95/01/18 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunSoft, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+/* __ieee754_hypot(x,y)
+ *
+ * Method :
+ * If (assume round-to-nearest) z=x*x+y*y
+ * has error less than sqrt(2)/2 ulp, than
+ * sqrt(z) has error less than 1 ulp (exercise).
+ *
+ * So, compute sqrt(x*x+y*y) with some care as
+ * follows to get the error below 1 ulp:
+ *
+ * Assume x>y>0;
+ * (if possible, set rounding to round-to-nearest)
+ * 1. if x > 2y use
+ * x1*x1+(y*y+(x2*(x+x1))) for x*x+y*y
+ * where x1 = x with lower 32 bits cleared, x2 = x-x1; else
+ * 2. if x <= 2y use
+ * t1*y1+((x-y)*(x-y)+(t1*y2+t2*y))
+ * where t1 = 2x with lower 32 bits cleared, t2 = 2x-t1,
+ * y1= y with lower 32 bits chopped, y2 = y-y1.
+ *
+ * NOTE: scaling may be necessary if some argument is too
+ * large or too tiny
+ *
+ * Special cases:
+ * hypot(x,y) is INF if x or y is +INF or -INF; else
+ * hypot(x,y) is NAN if x or y is NAN.
+ *
+ * Accuracy:
+ * hypot(x,y) returns sqrt(x^2+y^2) with error less
+ * than 1 ulps (units in the last place)
+ */
+
+#include "fdlibm.h"
+
+ double __ieee754_hypot(double x, double y)
+{
+ double a=x,b=y,t1,t2,y1,y2,w;
+ int j,k,ha,hb;
+
+ ha = __HI(x)&0x7fffffff; /* high word of x */
+ hb = __HI(y)&0x7fffffff; /* high word of y */
+ if(hb > ha) {a=y;b=x;j=ha; ha=hb;hb=j;} else {a=x;b=y;}
+ __HI(a) = ha; /* a <- |a| */
+ __HI(b) = hb; /* b <- |b| */
+ if((ha-hb)>0x3c00000) {return a+b;} /* x/y > 2**60 */
+ k=0;
+ if(ha > 0x5f300000) { /* a>2**500 */
+ if(ha >= 0x7ff00000) { /* Inf or NaN */
+ w = a+b; /* for sNaN */
+ if(((ha&0xfffff)|__LO(a))==0) w = a;
+ if(((hb^0x7ff00000)|__LO(b))==0) w = b;
+ return w;
+ }
+ /* scale a and b by 2**-600 */
+ ha -= 0x25800000; hb -= 0x25800000; k += 600;
+ __HI(a) = ha;
+ __HI(b) = hb;
+ }
+ if(hb < 0x20b00000) { /* b < 2**-500 */
+ if(hb <= 0x000fffff) { /* subnormal b or 0 */
+ if((hb|(__LO(b)))==0) return a;
+ t1=0;
+ __HI(t1) = 0x7fd00000; /* t1=2^1022 */
+ b *= t1;
+ a *= t1;
+ k -= 1022;
+ } else { /* scale a and b by 2^600 */
+ ha += 0x25800000; /* a *= 2^600 */
+ hb += 0x25800000; /* b *= 2^600 */
+ k -= 600;
+ __HI(a) = ha;
+ __HI(b) = hb;
+ }
+ }
+ /* medium size a and b */
+ w = a-b;
+ if (w>b) {
+ t1 = 0;
+ __HI(t1) = ha;
+ t2 = a-t1;
+ w = sqrt(t1*t1-(b*(-b)-t2*(a+t1)));
+ } else {
+ a = a+a;
+ y1 = 0;
+ __HI(y1) = hb;
+ y2 = b - y1;
+ t1 = 0;
+ __HI(t1) = ha+0x00100000;
+ t2 = a - t1;
+ w = sqrt(t1*y1-(w*(-w)-(t1*y2+t2*b)));
+ }
+ if(k!=0) {
+ t1 = 1.0;
+ __HI(t1) += (k<<20);
+ return t1*w;
+ } else return w;
+}
--- /dev/null
+++ b/libmath/fdlibm/e_j0.c
@@ -1,0 +1,375 @@
+/* derived from /netlib/fdlibm */
+
+/* @(#)e_j0.c 1.3 95/01/18 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunSoft, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+/* __ieee754_j0(x), __ieee754_y0(x)
+ * Bessel function of the first and second kinds of order zero.
+ * Method -- j0(x):
+ * 1. For tiny x, we use j0(x) = 1 - x^2/4 + x^4/64 - ...
+ * 2. Reduce x to |x| since j0(x)=j0(-x), and
+ * for x in (0,2)
+ * j0(x) = 1-z/4+ z^2*R0/S0, where z = x*x;
+ * (precision: |j0-1+z/4-z^2R0/S0 |<2**-63.67 )
+ * for x in (2,inf)
+ * j0(x) = sqrt(2/(pi*x))*(p0(x)*cos(x0)-q0(x)*sin(x0))
+ * where x0 = x-pi/4. It is better to compute sin(x0),cos(x0)
+ * as follow:
+ * cos(x0) = cos(x)cos(pi/4)+sin(x)sin(pi/4)
+ * = 1/sqrt(2) * (cos(x) + sin(x))
+ * sin(x0) = sin(x)cos(pi/4)-cos(x)sin(pi/4)
+ * = 1/sqrt(2) * (sin(x) - cos(x))
+ * (To avoid cancellation, use
+ * sin(x) +- cos(x) = -cos(2x)/(sin(x) -+ cos(x))
+ * to compute the worse one.)
+ *
+ * 3 Special cases
+ * j0(nan)= nan
+ * j0(0) = 1
+ * j0(inf) = 0
+ *
+ * Method -- y0(x):
+ * 1. For x<2.
+ * Since
+ * y0(x) = 2/pi*(j0(x)*(ln(x/2)+Euler) + x^2/4 - ...)
+ * therefore y0(x)-2/pi*j0(x)*ln(x) is an even function.
+ * We use the following function to approximate y0,
+ * y0(x) = U(z)/V(z) + (2/pi)*(j0(x)*ln(x)), z= x^2
+ * where
+ * U(z) = u00 + u01*z + ... + u06*z^6
+ * V(z) = 1 + v01*z + ... + v04*z^4
+ * with absolute approximation error bounded by 2**-72.
+ * Note: For tiny x, U/V = u0 and j0(x)~1, hence
+ * y0(tiny) = u0 + (2/pi)*ln(tiny), (choose tiny<2**-27)
+ * 2. For x>=2.
+ * y0(x) = sqrt(2/(pi*x))*(p0(x)*cos(x0)+q0(x)*sin(x0))
+ * where x0 = x-pi/4. It is better to compute sin(x0),cos(x0)
+ * by the method mentioned above.
+ * 3. Special cases: y0(0)=-inf, y0(x<0)=NaN, y0(inf)=0.
+ */
+
+#include "fdlibm.h"
+
+static double pzero(double), qzero(double);
+
+static const double
+Huge = 1e300,
+one = 1.0,
+invsqrtpi= 5.64189583547756279280e-01, /* 0x3FE20DD7, 0x50429B6D */
+tpi = 6.36619772367581382433e-01, /* 0x3FE45F30, 0x6DC9C883 */
+ /* R0/S0 on [0, 2.00] */
+R02 = 1.56249999999999947958e-02, /* 0x3F8FFFFF, 0xFFFFFFFD */
+R03 = -1.89979294238854721751e-04, /* 0xBF28E6A5, 0xB61AC6E9 */
+R04 = 1.82954049532700665670e-06, /* 0x3EBEB1D1, 0x0C503919 */
+R05 = -4.61832688532103189199e-09, /* 0xBE33D5E7, 0x73D63FCE */
+S01 = 1.56191029464890010492e-02, /* 0x3F8FFCE8, 0x82C8C2A4 */
+S02 = 1.16926784663337450260e-04, /* 0x3F1EA6D2, 0xDD57DBF4 */
+S03 = 5.13546550207318111446e-07, /* 0x3EA13B54, 0xCE84D5A9 */
+S04 = 1.16614003333790000205e-09; /* 0x3E1408BC, 0xF4745D8F */
+
+static double zero = 0.0;
+
+ double __ieee754_j0(double x)
+{
+ double z, s,c,ss,cc,r,u,v;
+ int hx,ix;
+
+ hx = __HI(x);
+ ix = hx&0x7fffffff;
+ if(ix>=0x7ff00000) return one/(x*x);
+ x = fabs(x);
+ if(ix >= 0x40000000) { /* |x| >= 2.0 */
+ s = sin(x);
+ c = cos(x);
+ ss = s-c;
+ cc = s+c;
+ if(ix<0x7fe00000) { /* make sure x+x not overflow */
+ z = -cos(x+x);
+ if ((s*c)<zero) cc = z/ss;
+ else ss = z/cc;
+ }
+ /*
+ * j0(x) = 1/sqrt(pi) * (P(0,x)*cc - Q(0,x)*ss) / sqrt(x)
+ * y0(x) = 1/sqrt(pi) * (P(0,x)*ss + Q(0,x)*cc) / sqrt(x)
+ */
+ if(ix>0x48000000) z = (invsqrtpi*cc)/sqrt(x);
+ else {
+ u = pzero(x); v = qzero(x);
+ z = invsqrtpi*(u*cc-v*ss)/sqrt(x);
+ }
+ return z;
+ }
+ if(ix<0x3f200000) { /* |x| < 2**-13 */
+ if(Huge+x>one) { /* raise inexact if x != 0 */
+ if(ix<0x3e400000) return one; /* |x|<2**-27 */
+ else return one - 0.25*x*x;
+ }
+ }
+ z = x*x;
+ r = z*(R02+z*(R03+z*(R04+z*R05)));
+ s = one+z*(S01+z*(S02+z*(S03+z*S04)));
+ if(ix < 0x3FF00000) { /* |x| < 1.00 */
+ return one + z*(-0.25+(r/s));
+ } else {
+ u = 0.5*x;
+ return((one+u)*(one-u)+z*(r/s));
+ }
+}
+
+static const double
+u00 = -7.38042951086872317523e-02, /* 0xBFB2E4D6, 0x99CBD01F */
+u01 = 1.76666452509181115538e-01, /* 0x3FC69D01, 0x9DE9E3FC */
+u02 = -1.38185671945596898896e-02, /* 0xBF8C4CE8, 0xB16CFA97 */
+u03 = 3.47453432093683650238e-04, /* 0x3F36C54D, 0x20B29B6B */
+u04 = -3.81407053724364161125e-06, /* 0xBECFFEA7, 0x73D25CAD */
+u05 = 1.95590137035022920206e-08, /* 0x3E550057, 0x3B4EABD4 */
+u06 = -3.98205194132103398453e-11, /* 0xBDC5E43D, 0x693FB3C8 */
+v01 = 1.27304834834123699328e-02, /* 0x3F8A1270, 0x91C9C71A */
+v02 = 7.60068627350353253702e-05, /* 0x3F13ECBB, 0xF578C6C1 */
+v03 = 2.59150851840457805467e-07, /* 0x3E91642D, 0x7FF202FD */
+v04 = 4.41110311332675467403e-10; /* 0x3DFE5018, 0x3BD6D9EF */
+
+ double __ieee754_y0(double x)
+{
+ double z, s,c,ss,cc,u,v;
+ int hx,ix,lx;
+
+ hx = __HI(x);
+ ix = 0x7fffffff&hx;
+ lx = __LO(x);
+ /* Y0(NaN) is NaN, y0(-inf) is Nan, y0(inf) is 0 */
+ if(ix>=0x7ff00000) return one/(x+x*x);
+ if((ix|lx)==0) return -one/zero;
+ if(hx<0) return zero/zero;
+ if(ix >= 0x40000000) { /* |x| >= 2.0 */
+ /* y0(x) = sqrt(2/(pi*x))*(p0(x)*sin(x0)+q0(x)*cos(x0))
+ * where x0 = x-pi/4
+ * Better formula:
+ * cos(x0) = cos(x)cos(pi/4)+sin(x)sin(pi/4)
+ * = 1/sqrt(2) * (sin(x) + cos(x))
+ * sin(x0) = sin(x)cos(3pi/4)-cos(x)sin(3pi/4)
+ * = 1/sqrt(2) * (sin(x) - cos(x))
+ * To avoid cancellation, use
+ * sin(x) +- cos(x) = -cos(2x)/(sin(x) -+ cos(x))
+ * to compute the worse one.
+ */
+ s = sin(x);
+ c = cos(x);
+ ss = s-c;
+ cc = s+c;
+ /*
+ * j0(x) = 1/sqrt(pi) * (P(0,x)*cc - Q(0,x)*ss) / sqrt(x)
+ * y0(x) = 1/sqrt(pi) * (P(0,x)*ss + Q(0,x)*cc) / sqrt(x)
+ */
+ if(ix<0x7fe00000) { /* make sure x+x not overflow */
+ z = -cos(x+x);
+ if ((s*c)<zero) cc = z/ss;
+ else ss = z/cc;
+ }
+ if(ix>0x48000000) z = (invsqrtpi*ss)/sqrt(x);
+ else {
+ u = pzero(x); v = qzero(x);
+ z = invsqrtpi*(u*ss+v*cc)/sqrt(x);
+ }
+ return z;
+ }
+ if(ix<=0x3e400000) { /* x < 2**-27 */
+ return(u00 + tpi*__ieee754_log(x));
+ }
+ z = x*x;
+ u = u00+z*(u01+z*(u02+z*(u03+z*(u04+z*(u05+z*u06)))));
+ v = one+z*(v01+z*(v02+z*(v03+z*v04)));
+ return(u/v + tpi*(__ieee754_j0(x)*__ieee754_log(x)));
+}
+
+/* The asymptotic expansions of pzero is
+ * 1 - 9/128 s^2 + 11025/98304 s^4 - ..., where s = 1/x.
+ * For x >= 2, We approximate pzero by
+ * pzero(x) = 1 + (R/S)
+ * where R = pR0 + pR1*s^2 + pR2*s^4 + ... + pR5*s^10
+ * S = 1 + pS0*s^2 + ... + pS4*s^10
+ * and
+ * | pzero(x)-1-R/S | <= 2 ** ( -60.26)
+ */
+static const double pR8[6] = { /* for x in [inf, 8]=1/[0,0.125] */
+ 0.00000000000000000000e+00, /* 0x00000000, 0x00000000 */
+ -7.03124999999900357484e-02, /* 0xBFB1FFFF, 0xFFFFFD32 */
+ -8.08167041275349795626e+00, /* 0xC02029D0, 0xB44FA779 */
+ -2.57063105679704847262e+02, /* 0xC0701102, 0x7B19E863 */
+ -2.48521641009428822144e+03, /* 0xC0A36A6E, 0xCD4DCAFC */
+ -5.25304380490729545272e+03, /* 0xC0B4850B, 0x36CC643D */
+};
+static const double pS8[5] = {
+ 1.16534364619668181717e+02, /* 0x405D2233, 0x07A96751 */
+ 3.83374475364121826715e+03, /* 0x40ADF37D, 0x50596938 */
+ 4.05978572648472545552e+04, /* 0x40E3D2BB, 0x6EB6B05F */
+ 1.16752972564375915681e+05, /* 0x40FC810F, 0x8F9FA9BD */
+ 4.76277284146730962675e+04, /* 0x40E74177, 0x4F2C49DC */
+};
+
+static const double pR5[6] = { /* for x in [8,4.5454]=1/[0.125,0.22001] */
+ -1.14125464691894502584e-11, /* 0xBDA918B1, 0x47E495CC */
+ -7.03124940873599280078e-02, /* 0xBFB1FFFF, 0xE69AFBC6 */
+ -4.15961064470587782438e+00, /* 0xC010A370, 0xF90C6BBF */
+ -6.76747652265167261021e+01, /* 0xC050EB2F, 0x5A7D1783 */
+ -3.31231299649172967747e+02, /* 0xC074B3B3, 0x6742CC63 */
+ -3.46433388365604912451e+02, /* 0xC075A6EF, 0x28A38BD7 */
+};
+static const double pS5[5] = {
+ 6.07539382692300335975e+01, /* 0x404E6081, 0x0C98C5DE */
+ 1.05125230595704579173e+03, /* 0x40906D02, 0x5C7E2864 */
+ 5.97897094333855784498e+03, /* 0x40B75AF8, 0x8FBE1D60 */
+ 9.62544514357774460223e+03, /* 0x40C2CCB8, 0xFA76FA38 */
+ 2.40605815922939109441e+03, /* 0x40A2CC1D, 0xC70BE864 */
+};
+
+static const double pR3[6] = {/* for x in [4.547,2.8571]=1/[0.2199,0.35001] */
+ -2.54704601771951915620e-09, /* 0xBE25E103, 0x6FE1AA86 */
+ -7.03119616381481654654e-02, /* 0xBFB1FFF6, 0xF7C0E24B */
+ -2.40903221549529611423e+00, /* 0xC00345B2, 0xAEA48074 */
+ -2.19659774734883086467e+01, /* 0xC035F74A, 0x4CB94E14 */
+ -5.80791704701737572236e+01, /* 0xC04D0A22, 0x420A1A45 */
+ -3.14479470594888503854e+01, /* 0xC03F72AC, 0xA892D80F */
+};
+static const double pS3[5] = {
+ 3.58560338055209726349e+01, /* 0x4041ED92, 0x84077DD3 */
+ 3.61513983050303863820e+02, /* 0x40769839, 0x464A7C0E */
+ 1.19360783792111533330e+03, /* 0x4092A66E, 0x6D1061D6 */
+ 1.12799679856907414432e+03, /* 0x40919FFC, 0xB8C39B7E */
+ 1.73580930813335754692e+02, /* 0x4065B296, 0xFC379081 */
+};
+
+static const double pR2[6] = {/* for x in [2.8570,2]=1/[0.3499,0.5] */
+ -8.87534333032526411254e-08, /* 0xBE77D316, 0xE927026D */
+ -7.03030995483624743247e-02, /* 0xBFB1FF62, 0x495E1E42 */
+ -1.45073846780952986357e+00, /* 0xBFF73639, 0x8A24A843 */
+ -7.63569613823527770791e+00, /* 0xC01E8AF3, 0xEDAFA7F3 */
+ -1.11931668860356747786e+01, /* 0xC02662E6, 0xC5246303 */
+ -3.23364579351335335033e+00, /* 0xC009DE81, 0xAF8FE70F */
+};
+static const double pS2[5] = {
+ 2.22202997532088808441e+01, /* 0x40363865, 0x908B5959 */
+ 1.36206794218215208048e+02, /* 0x4061069E, 0x0EE8878F */
+ 2.70470278658083486789e+02, /* 0x4070E786, 0x42EA079B */
+ 1.53875394208320329881e+02, /* 0x40633C03, 0x3AB6FAFF */
+ 1.46576176948256193810e+01, /* 0x402D50B3, 0x44391809 */
+};
+
+ static double pzero(double x)
+{
+ const double *p,*q;
+ double z,r,s;
+ int ix;
+ ix = 0x7fffffff&__HI(x);
+ if(ix>=0x40200000) {p = pR8; q= pS8;}
+ else if(ix>=0x40122E8B){p = pR5; q= pS5;}
+ else if(ix>=0x4006DB6D){p = pR3; q= pS3;}
+ else if(ix>=0x40000000){p = pR2; q= pS2;}
+ z = one/(x*x);
+ r = p[0]+z*(p[1]+z*(p[2]+z*(p[3]+z*(p[4]+z*p[5]))));
+ s = one+z*(q[0]+z*(q[1]+z*(q[2]+z*(q[3]+z*q[4]))));
+ return one+ r/s;
+}
+
+
+/* For x >= 8, the asymptotic expansions of qzero is
+ * -1/8 s + 75/1024 s^3 - ..., where s = 1/x.
+ * We approximate pzero by
+ * qzero(x) = s*(-1.25 + (R/S))
+ * where R = qR0 + qR1*s^2 + qR2*s^4 + ... + qR5*s^10
+ * S = 1 + qS0*s^2 + ... + qS5*s^12
+ * and
+ * | qzero(x)/s +1.25-R/S | <= 2 ** ( -61.22)
+ */
+static const double qR8[6] = { /* for x in [inf, 8]=1/[0,0.125] */
+ 0.00000000000000000000e+00, /* 0x00000000, 0x00000000 */
+ 7.32421874999935051953e-02, /* 0x3FB2BFFF, 0xFFFFFE2C */
+ 1.17682064682252693899e+01, /* 0x40278952, 0x5BB334D6 */
+ 5.57673380256401856059e+02, /* 0x40816D63, 0x15301825 */
+ 8.85919720756468632317e+03, /* 0x40C14D99, 0x3E18F46D */
+ 3.70146267776887834771e+04, /* 0x40E212D4, 0x0E901566 */
+};
+static const double qS8[6] = {
+ 1.63776026895689824414e+02, /* 0x406478D5, 0x365B39BC */
+ 8.09834494656449805916e+03, /* 0x40BFA258, 0x4E6B0563 */
+ 1.42538291419120476348e+05, /* 0x41016652, 0x54D38C3F */
+ 8.03309257119514397345e+05, /* 0x412883DA, 0x83A52B43 */
+ 8.40501579819060512818e+05, /* 0x4129A66B, 0x28DE0B3D */
+ -3.43899293537866615225e+05, /* 0xC114FD6D, 0x2C9530C5 */
+};
+
+static const double qR5[6] = { /* for x in [8,4.5454]=1/[0.125,0.22001] */
+ 1.84085963594515531381e-11, /* 0x3DB43D8F, 0x29CC8CD9 */
+ 7.32421766612684765896e-02, /* 0x3FB2BFFF, 0xD172B04C */
+ 5.83563508962056953777e+00, /* 0x401757B0, 0xB9953DD3 */
+ 1.35111577286449829671e+02, /* 0x4060E392, 0x0A8788E9 */
+ 1.02724376596164097464e+03, /* 0x40900CF9, 0x9DC8C481 */
+ 1.98997785864605384631e+03, /* 0x409F17E9, 0x53C6E3A6 */
+};
+static const double qS5[6] = {
+ 8.27766102236537761883e+01, /* 0x4054B1B3, 0xFB5E1543 */
+ 2.07781416421392987104e+03, /* 0x40A03BA0, 0xDA21C0CE */
+ 1.88472887785718085070e+04, /* 0x40D267D2, 0x7B591E6D */
+ 5.67511122894947329769e+04, /* 0x40EBB5E3, 0x97E02372 */
+ 3.59767538425114471465e+04, /* 0x40E19118, 0x1F7A54A0 */
+ -5.35434275601944773371e+03, /* 0xC0B4EA57, 0xBEDBC609 */
+};
+
+static const double qR3[6] = {/* for x in [4.547,2.8571]=1/[0.2199,0.35001] */
+ 4.37741014089738620906e-09, /* 0x3E32CD03, 0x6ADECB82 */
+ 7.32411180042911447163e-02, /* 0x3FB2BFEE, 0x0E8D0842 */
+ 3.34423137516170720929e+00, /* 0x400AC0FC, 0x61149CF5 */
+ 4.26218440745412650017e+01, /* 0x40454F98, 0x962DAEDD */
+ 1.70808091340565596283e+02, /* 0x406559DB, 0xE25EFD1F */
+ 1.66733948696651168575e+02, /* 0x4064D77C, 0x81FA21E0 */
+};
+static const double qS3[6] = {
+ 4.87588729724587182091e+01, /* 0x40486122, 0xBFE343A6 */
+ 7.09689221056606015736e+02, /* 0x40862D83, 0x86544EB3 */
+ 3.70414822620111362994e+03, /* 0x40ACF04B, 0xE44DFC63 */
+ 6.46042516752568917582e+03, /* 0x40B93C6C, 0xD7C76A28 */
+ 2.51633368920368957333e+03, /* 0x40A3A8AA, 0xD94FB1C0 */
+ -1.49247451836156386662e+02, /* 0xC062A7EB, 0x201CF40F */
+};
+
+static const double qR2[6] = {/* for x in [2.8570,2]=1/[0.3499,0.5] */
+ 1.50444444886983272379e-07, /* 0x3E84313B, 0x54F76BDB */
+ 7.32234265963079278272e-02, /* 0x3FB2BEC5, 0x3E883E34 */
+ 1.99819174093815998816e+00, /* 0x3FFFF897, 0xE727779C */
+ 1.44956029347885735348e+01, /* 0x402CFDBF, 0xAAF96FE5 */
+ 3.16662317504781540833e+01, /* 0x403FAA8E, 0x29FBDC4A */
+ 1.62527075710929267416e+01, /* 0x403040B1, 0x71814BB4 */
+};
+static const double qS2[6] = {
+ 3.03655848355219184498e+01, /* 0x403E5D96, 0xF7C07AED */
+ 2.69348118608049844624e+02, /* 0x4070D591, 0xE4D14B40 */
+ 8.44783757595320139444e+02, /* 0x408A6645, 0x22B3BF22 */
+ 8.82935845112488550512e+02, /* 0x408B977C, 0x9C5CC214 */
+ 2.12666388511798828631e+02, /* 0x406A9553, 0x0E001365 */
+ -5.31095493882666946917e+00, /* 0xC0153E6A, 0xF8B32931 */
+};
+
+ static double qzero(double x)
+{
+ const double *p,*q;
+ double s,r,z;
+ int ix;
+ ix = 0x7fffffff&__HI(x);
+ if(ix>=0x40200000) {p = qR8; q= qS8;}
+ else if(ix>=0x40122E8B){p = qR5; q= qS5;}
+ else if(ix>=0x4006DB6D){p = qR3; q= qS3;}
+ else if(ix>=0x40000000){p = qR2; q= qS2;}
+ z = one/(x*x);
+ r = p[0]+z*(p[1]+z*(p[2]+z*(p[3]+z*(p[4]+z*p[5]))));
+ s = one+z*(q[0]+z*(q[1]+z*(q[2]+z*(q[3]+z*(q[4]+z*q[5])))));
+ return (-.125 + r/s)/x;
+}
--- /dev/null
+++ b/libmath/fdlibm/e_j1.c
@@ -1,0 +1,370 @@
+/* derived from /netlib/fdlibm */
+
+/* @(#)e_j1.c 1.3 95/01/18 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunSoft, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+/* __ieee754_j1(x), __ieee754_y1(x)
+ * Bessel function of the first and second kinds of order zero.
+ * Method -- j1(x):
+ * 1. For tiny x, we use j1(x) = x/2 - x^3/16 + x^5/384 - ...
+ * 2. Reduce x to |x| since j1(x)=-j1(-x), and
+ * for x in (0,2)
+ * j1(x) = x/2 + x*z*R0/S0, where z = x*x;
+ * (precision: |j1/x - 1/2 - R0/S0 |<2**-61.51 )
+ * for x in (2,inf)
+ * j1(x) = sqrt(2/(pi*x))*(p1(x)*cos(x1)-q1(x)*sin(x1))
+ * y1(x) = sqrt(2/(pi*x))*(p1(x)*sin(x1)+q1(x)*cos(x1))
+ * where x1 = x-3*pi/4. It is better to compute sin(x1),cos(x1)
+ * as follow:
+ * cos(x1) = cos(x)cos(3pi/4)+sin(x)sin(3pi/4)
+ * = 1/sqrt(2) * (sin(x) - cos(x))
+ * sin(x1) = sin(x)cos(3pi/4)-cos(x)sin(3pi/4)
+ * = -1/sqrt(2) * (sin(x) + cos(x))
+ * (To avoid cancellation, use
+ * sin(x) +- cos(x) = -cos(2x)/(sin(x) -+ cos(x))
+ * to compute the worse one.)
+ *
+ * 3 Special cases
+ * j1(nan)= nan
+ * j1(0) = 0
+ * j1(inf) = 0
+ *
+ * Method -- y1(x):
+ * 1. screen out x<=0 cases: y1(0)=-inf, y1(x<0)=NaN
+ * 2. For x<2.
+ * Since
+ * y1(x) = 2/pi*(j1(x)*(ln(x/2)+Euler)-1/x-x/2+5/64*x^3-...)
+ * therefore y1(x)-2/pi*j1(x)*ln(x)-1/x is an odd function.
+ * We use the following function to approximate y1,
+ * y1(x) = x*U(z)/V(z) + (2/pi)*(j1(x)*ln(x)-1/x), z= x^2
+ * where for x in [0,2] (abs err less than 2**-65.89)
+ * U(z) = U0[0] + U0[1]*z + ... + U0[4]*z^4
+ * V(z) = 1 + v0[0]*z + ... + v0[4]*z^5
+ * Note: For tiny x, 1/x dominate y1 and hence
+ * y1(tiny) = -2/pi/tiny, (choose tiny<2**-54)
+ * 3. For x>=2.
+ * y1(x) = sqrt(2/(pi*x))*(p1(x)*sin(x1)+q1(x)*cos(x1))
+ * where x1 = x-3*pi/4. It is better to compute sin(x1),cos(x1)
+ * by method mentioned above.
+ */
+
+#include "fdlibm.h"
+
+static double pone(double), qone(double);
+
+static const double
+Huge = 1e300,
+one = 1.0,
+invsqrtpi= 5.64189583547756279280e-01, /* 0x3FE20DD7, 0x50429B6D */
+tpi = 6.36619772367581382433e-01, /* 0x3FE45F30, 0x6DC9C883 */
+ /* R0/S0 on [0,2] */
+r00 = -6.25000000000000000000e-02, /* 0xBFB00000, 0x00000000 */
+r01 = 1.40705666955189706048e-03, /* 0x3F570D9F, 0x98472C61 */
+r02 = -1.59955631084035597520e-05, /* 0xBEF0C5C6, 0xBA169668 */
+r03 = 4.96727999609584448412e-08, /* 0x3E6AAAFA, 0x46CA0BD9 */
+s01 = 1.91537599538363460805e-02, /* 0x3F939D0B, 0x12637E53 */
+s02 = 1.85946785588630915560e-04, /* 0x3F285F56, 0xB9CDF664 */
+s03 = 1.17718464042623683263e-06, /* 0x3EB3BFF8, 0x333F8498 */
+s04 = 5.04636257076217042715e-09, /* 0x3E35AC88, 0xC97DFF2C */
+s05 = 1.23542274426137913908e-11; /* 0x3DAB2ACF, 0xCFB97ED8 */
+
+static double zero = 0.0;
+
+ double __ieee754_j1(double x)
+{
+ double z, s,c,ss,cc,r,u,v,y;
+ int hx,ix;
+
+ hx = __HI(x);
+ ix = hx&0x7fffffff;
+ if(ix>=0x7ff00000) return one/x;
+ y = fabs(x);
+ if(ix >= 0x40000000) { /* |x| >= 2.0 */
+ s = sin(y);
+ c = cos(y);
+ ss = -s-c;
+ cc = s-c;
+ if(ix<0x7fe00000) { /* make sure y+y not overflow */
+ z = cos(y+y);
+ if ((s*c)>zero) cc = z/ss;
+ else ss = z/cc;
+ }
+ /*
+ * j1(x) = 1/sqrt(pi) * (P(1,x)*cc - Q(1,x)*ss) / sqrt(x)
+ * y1(x) = 1/sqrt(pi) * (P(1,x)*ss + Q(1,x)*cc) / sqrt(x)
+ */
+ if(ix>0x48000000) z = (invsqrtpi*cc)/sqrt(y);
+ else {
+ u = pone(y); v = qone(y);
+ z = invsqrtpi*(u*cc-v*ss)/sqrt(y);
+ }
+ if(hx<0) return -z;
+ else return z;
+ }
+ if(ix<0x3e400000) { /* |x|<2**-27 */
+ if(Huge+x>one) return 0.5*x;/* inexact if x!=0 necessary */
+ }
+ z = x*x;
+ r = z*(r00+z*(r01+z*(r02+z*r03)));
+ s = one+z*(s01+z*(s02+z*(s03+z*(s04+z*s05))));
+ r *= x;
+ return(x*0.5+r/s);
+}
+
+static const double U0[5] = {
+ -1.96057090646238940668e-01, /* 0xBFC91866, 0x143CBC8A */
+ 5.04438716639811282616e-02, /* 0x3FA9D3C7, 0x76292CD1 */
+ -1.91256895875763547298e-03, /* 0xBF5F55E5, 0x4844F50F */
+ 2.35252600561610495928e-05, /* 0x3EF8AB03, 0x8FA6B88E */
+ -9.19099158039878874504e-08, /* 0xBE78AC00, 0x569105B8 */
+};
+static const double V0[5] = {
+ 1.99167318236649903973e-02, /* 0x3F94650D, 0x3F4DA9F0 */
+ 2.02552581025135171496e-04, /* 0x3F2A8C89, 0x6C257764 */
+ 1.35608801097516229404e-06, /* 0x3EB6C05A, 0x894E8CA6 */
+ 6.22741452364621501295e-09, /* 0x3E3ABF1D, 0x5BA69A86 */
+ 1.66559246207992079114e-11, /* 0x3DB25039, 0xDACA772A */
+};
+
+ double __ieee754_y1(double x)
+{
+ double z, s,c,ss,cc,u,v;
+ int hx,ix,lx;
+
+ hx = __HI(x);
+ ix = 0x7fffffff&hx;
+ lx = __LO(x);
+ /* if Y1(NaN) is NaN, Y1(-inf) is NaN, Y1(inf) is 0 */
+ if(ix>=0x7ff00000) return one/(x+x*x);
+ if((ix|lx)==0) return -one/zero;
+ if(hx<0) return zero/zero;
+ if(ix >= 0x40000000) { /* |x| >= 2.0 */
+ s = sin(x);
+ c = cos(x);
+ ss = -s-c;
+ cc = s-c;
+ if(ix<0x7fe00000) { /* make sure x+x not overflow */
+ z = cos(x+x);
+ if ((s*c)>zero) cc = z/ss;
+ else ss = z/cc;
+ }
+ /* y1(x) = sqrt(2/(pi*x))*(p1(x)*sin(x0)+q1(x)*cos(x0))
+ * where x0 = x-3pi/4
+ * Better formula:
+ * cos(x0) = cos(x)cos(3pi/4)+sin(x)sin(3pi/4)
+ * = 1/sqrt(2) * (sin(x) - cos(x))
+ * sin(x0) = sin(x)cos(3pi/4)-cos(x)sin(3pi/4)
+ * = -1/sqrt(2) * (cos(x) + sin(x))
+ * To avoid cancellation, use
+ * sin(x) +- cos(x) = -cos(2x)/(sin(x) -+ cos(x))
+ * to compute the worse one.
+ */
+ if(ix>0x48000000) z = (invsqrtpi*ss)/sqrt(x);
+ else {
+ u = pone(x); v = qone(x);
+ z = invsqrtpi*(u*ss+v*cc)/sqrt(x);
+ }
+ return z;
+ }
+ if(ix<=0x3c900000) { /* x < 2**-54 */
+ return(-tpi/x);
+ }
+ z = x*x;
+ u = U0[0]+z*(U0[1]+z*(U0[2]+z*(U0[3]+z*U0[4])));
+ v = one+z*(V0[0]+z*(V0[1]+z*(V0[2]+z*(V0[3]+z*V0[4]))));
+ return(x*(u/v) + tpi*(__ieee754_j1(x)*__ieee754_log(x)-one/x));
+}
+
+/* For x >= 8, the asymptotic expansions of pone is
+ * 1 + 15/128 s^2 - 4725/2^15 s^4 - ..., where s = 1/x.
+ * We approximate pone by
+ * pone(x) = 1 + (R/S)
+ * where R = pr0 + pr1*s^2 + pr2*s^4 + ... + pr5*s^10
+ * S = 1 + ps0*s^2 + ... + ps4*s^10
+ * and
+ * | pone(x)-1-R/S | <= 2 ** ( -60.06)
+ */
+
+static const double pr8[6] = { /* for x in [inf, 8]=1/[0,0.125] */
+ 0.00000000000000000000e+00, /* 0x00000000, 0x00000000 */
+ 1.17187499999988647970e-01, /* 0x3FBDFFFF, 0xFFFFFCCE */
+ 1.32394806593073575129e+01, /* 0x402A7A9D, 0x357F7FCE */
+ 4.12051854307378562225e+02, /* 0x4079C0D4, 0x652EA590 */
+ 3.87474538913960532227e+03, /* 0x40AE457D, 0xA3A532CC */
+ 7.91447954031891731574e+03, /* 0x40BEEA7A, 0xC32782DD */
+};
+static const double ps8[5] = {
+ 1.14207370375678408436e+02, /* 0x405C8D45, 0x8E656CAC */
+ 3.65093083420853463394e+03, /* 0x40AC85DC, 0x964D274F */
+ 3.69562060269033463555e+04, /* 0x40E20B86, 0x97C5BB7F */
+ 9.76027935934950801311e+04, /* 0x40F7D42C, 0xB28F17BB */
+ 3.08042720627888811578e+04, /* 0x40DE1511, 0x697A0B2D */
+};
+
+static const double pr5[6] = { /* for x in [8,4.5454]=1/[0.125,0.22001] */
+ 1.31990519556243522749e-11, /* 0x3DAD0667, 0xDAE1CA7D */
+ 1.17187493190614097638e-01, /* 0x3FBDFFFF, 0xE2C10043 */
+ 6.80275127868432871736e+00, /* 0x401B3604, 0x6E6315E3 */
+ 1.08308182990189109773e+02, /* 0x405B13B9, 0x452602ED */
+ 5.17636139533199752805e+02, /* 0x40802D16, 0xD052D649 */
+ 5.28715201363337541807e+02, /* 0x408085B8, 0xBB7E0CB7 */
+};
+static const double ps5[5] = {
+ 5.92805987221131331921e+01, /* 0x404DA3EA, 0xA8AF633D */
+ 9.91401418733614377743e+02, /* 0x408EFB36, 0x1B066701 */
+ 5.35326695291487976647e+03, /* 0x40B4E944, 0x5706B6FB */
+ 7.84469031749551231769e+03, /* 0x40BEA4B0, 0xB8A5BB15 */
+ 1.50404688810361062679e+03, /* 0x40978030, 0x036F5E51 */
+};
+
+static const double pr3[6] = {
+ 3.02503916137373618024e-09, /* 0x3E29FC21, 0xA7AD9EDD */
+ 1.17186865567253592491e-01, /* 0x3FBDFFF5, 0x5B21D17B */
+ 3.93297750033315640650e+00, /* 0x400F76BC, 0xE85EAD8A */
+ 3.51194035591636932736e+01, /* 0x40418F48, 0x9DA6D129 */
+ 9.10550110750781271918e+01, /* 0x4056C385, 0x4D2C1837 */
+ 4.85590685197364919645e+01, /* 0x4048478F, 0x8EA83EE5 */
+};
+static const double ps3[5] = {
+ 3.47913095001251519989e+01, /* 0x40416549, 0xA134069C */
+ 3.36762458747825746741e+02, /* 0x40750C33, 0x07F1A75F */
+ 1.04687139975775130551e+03, /* 0x40905B7C, 0x5037D523 */
+ 8.90811346398256432622e+02, /* 0x408BD67D, 0xA32E31E9 */
+ 1.03787932439639277504e+02, /* 0x4059F26D, 0x7C2EED53 */
+};
+
+static const double pr2[6] = {/* for x in [2.8570,2]=1/[0.3499,0.5] */
+ 1.07710830106873743082e-07, /* 0x3E7CE9D4, 0xF65544F4 */
+ 1.17176219462683348094e-01, /* 0x3FBDFF42, 0xBE760D83 */
+ 2.36851496667608785174e+00, /* 0x4002F2B7, 0xF98FAEC0 */
+ 1.22426109148261232917e+01, /* 0x40287C37, 0x7F71A964 */
+ 1.76939711271687727390e+01, /* 0x4031B1A8, 0x177F8EE2 */
+ 5.07352312588818499250e+00, /* 0x40144B49, 0xA574C1FE */
+};
+static const double ps2[5] = {
+ 2.14364859363821409488e+01, /* 0x40356FBD, 0x8AD5ECDC */
+ 1.25290227168402751090e+02, /* 0x405F5293, 0x14F92CD5 */
+ 2.32276469057162813669e+02, /* 0x406D08D8, 0xD5A2DBD9 */
+ 1.17679373287147100768e+02, /* 0x405D6B7A, 0xDA1884A9 */
+ 8.36463893371618283368e+00, /* 0x4020BAB1, 0xF44E5192 */
+};
+
+ static double pone(double x)
+{
+ const double *p,*q;
+ double z,r,s;
+ int ix;
+ ix = 0x7fffffff&__HI(x);
+ if(ix>=0x40200000) {p = pr8; q= ps8;}
+ else if(ix>=0x40122E8B){p = pr5; q= ps5;}
+ else if(ix>=0x4006DB6D){p = pr3; q= ps3;}
+ else if(ix>=0x40000000){p = pr2; q= ps2;}
+ z = one/(x*x);
+ r = p[0]+z*(p[1]+z*(p[2]+z*(p[3]+z*(p[4]+z*p[5]))));
+ s = one+z*(q[0]+z*(q[1]+z*(q[2]+z*(q[3]+z*q[4]))));
+ return one+ r/s;
+}
+
+
+/* For x >= 8, the asymptotic expansions of qone is
+ * 3/8 s - 105/1024 s^3 - ..., where s = 1/x.
+ * We approximate pone by
+ * qone(x) = s*(0.375 + (R/S))
+ * where R = qr1*s^2 + qr2*s^4 + ... + qr5*s^10
+ * S = 1 + qs1*s^2 + ... + qs6*s^12
+ * and
+ * | qone(x)/s -0.375-R/S | <= 2 ** ( -61.13)
+ */
+
+static const double qr8[6] = { /* for x in [inf, 8]=1/[0,0.125] */
+ 0.00000000000000000000e+00, /* 0x00000000, 0x00000000 */
+ -1.02539062499992714161e-01, /* 0xBFBA3FFF, 0xFFFFFDF3 */
+ -1.62717534544589987888e+01, /* 0xC0304591, 0xA26779F7 */
+ -7.59601722513950107896e+02, /* 0xC087BCD0, 0x53E4B576 */
+ -1.18498066702429587167e+04, /* 0xC0C724E7, 0x40F87415 */
+ -4.84385124285750353010e+04, /* 0xC0E7A6D0, 0x65D09C6A */
+};
+static const double qs8[6] = {
+ 1.61395369700722909556e+02, /* 0x40642CA6, 0xDE5BCDE5 */
+ 7.82538599923348465381e+03, /* 0x40BE9162, 0xD0D88419 */
+ 1.33875336287249578163e+05, /* 0x4100579A, 0xB0B75E98 */
+ 7.19657723683240939863e+05, /* 0x4125F653, 0x72869C19 */
+ 6.66601232617776375264e+05, /* 0x412457D2, 0x7719AD5C */
+ -2.94490264303834643215e+05, /* 0xC111F969, 0x0EA5AA18 */
+};
+
+static const double qr5[6] = { /* for x in [8,4.5454]=1/[0.125,0.22001] */
+ -2.08979931141764104297e-11, /* 0xBDB6FA43, 0x1AA1A098 */
+ -1.02539050241375426231e-01, /* 0xBFBA3FFF, 0xCB597FEF */
+ -8.05644828123936029840e+00, /* 0xC0201CE6, 0xCA03AD4B */
+ -1.83669607474888380239e+02, /* 0xC066F56D, 0x6CA7B9B0 */
+ -1.37319376065508163265e+03, /* 0xC09574C6, 0x6931734F */
+ -2.61244440453215656817e+03, /* 0xC0A468E3, 0x88FDA79D */
+};
+static const double qs5[6] = {
+ 8.12765501384335777857e+01, /* 0x405451B2, 0xFF5A11B2 */
+ 1.99179873460485964642e+03, /* 0x409F1F31, 0xE77BF839 */
+ 1.74684851924908907677e+04, /* 0x40D10F1F, 0x0D64CE29 */
+ 4.98514270910352279316e+04, /* 0x40E8576D, 0xAABAD197 */
+ 2.79480751638918118260e+04, /* 0x40DB4B04, 0xCF7C364B */
+ -4.71918354795128470869e+03, /* 0xC0B26F2E, 0xFCFFA004 */
+};
+
+static const double qr3[6] = {
+ -5.07831226461766561369e-09, /* 0xBE35CFA9, 0xD38FC84F */
+ -1.02537829820837089745e-01, /* 0xBFBA3FEB, 0x51AEED54 */
+ -4.61011581139473403113e+00, /* 0xC01270C2, 0x3302D9FF */
+ -5.78472216562783643212e+01, /* 0xC04CEC71, 0xC25D16DA */
+ -2.28244540737631695038e+02, /* 0xC06C87D3, 0x4718D55F */
+ -2.19210128478909325622e+02, /* 0xC06B66B9, 0x5F5C1BF6 */
+};
+static const double qs3[6] = {
+ 4.76651550323729509273e+01, /* 0x4047D523, 0xCCD367E4 */
+ 6.73865112676699709482e+02, /* 0x40850EEB, 0xC031EE3E */
+ 3.38015286679526343505e+03, /* 0x40AA684E, 0x448E7C9A */
+ 5.54772909720722782367e+03, /* 0x40B5ABBA, 0xA61D54A6 */
+ 1.90311919338810798763e+03, /* 0x409DBC7A, 0x0DD4DF4B */
+ -1.35201191444307340817e+02, /* 0xC060E670, 0x290A311F */
+};
+
+static const double qr2[6] = {/* for x in [2.8570,2]=1/[0.3499,0.5] */
+ -1.78381727510958865572e-07, /* 0xBE87F126, 0x44C626D2 */
+ -1.02517042607985553460e-01, /* 0xBFBA3E8E, 0x9148B010 */
+ -2.75220568278187460720e+00, /* 0xC0060484, 0x69BB4EDA */
+ -1.96636162643703720221e+01, /* 0xC033A9E2, 0xC168907F */
+ -4.23253133372830490089e+01, /* 0xC04529A3, 0xDE104AAA */
+ -2.13719211703704061733e+01, /* 0xC0355F36, 0x39CF6E52 */
+};
+static const double qs2[6] = {
+ 2.95333629060523854548e+01, /* 0x403D888A, 0x78AE64FF */
+ 2.52981549982190529136e+02, /* 0x406F9F68, 0xDB821CBA */
+ 7.57502834868645436472e+02, /* 0x4087AC05, 0xCE49A0F7 */
+ 7.39393205320467245656e+02, /* 0x40871B25, 0x48D4C029 */
+ 1.55949003336666123687e+02, /* 0x40637E5E, 0x3C3ED8D4 */
+ -4.95949898822628210127e+00, /* 0xC013D686, 0xE71BE86B */
+};
+
+ static double qone(double x)
+{
+ const double *p,*q;
+ double s,r,z;
+ int ix;
+ ix = 0x7fffffff&__HI(x);
+ if(ix>=0x40200000) {p = qr8; q= qs8;}
+ else if(ix>=0x40122E8B){p = qr5; q= qs5;}
+ else if(ix>=0x4006DB6D){p = qr3; q= qs3;}
+ else if(ix>=0x40000000){p = qr2; q= qs2;}
+ z = one/(x*x);
+ r = p[0]+z*(p[1]+z*(p[2]+z*(p[3]+z*(p[4]+z*p[5]))));
+ s = one+z*(q[0]+z*(q[1]+z*(q[2]+z*(q[3]+z*(q[4]+z*q[5])))));
+ return (.375 + r/s)/x;
+}
--- /dev/null
+++ b/libmath/fdlibm/e_jn.c
@@ -1,0 +1,259 @@
+/* derived from /netlib/fdlibm */
+
+/* @(#)e_jn.c 1.4 95/01/18 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunSoft, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+/*
+ * __ieee754_jn(n, x), __ieee754_yn(n, x)
+ * floating point Bessel's function of the 1st and 2nd kind
+ * of order n
+ *
+ * Special cases:
+ * y0(0)=y1(0)=yn(n,0) = -inf with division by zero signal;
+ * y0(-ve)=y1(-ve)=yn(n,-ve) are NaN with invalid signal.
+ * Note 2. About jn(n,x), yn(n,x)
+ * For n=0, j0(x) is called,
+ * for n=1, j1(x) is called,
+ * for n<x, forward recursion us used starting
+ * from values of j0(x) and j1(x).
+ * for n>x, a continued fraction approximation to
+ * j(n,x)/j(n-1,x) is evaluated and then backward
+ * recursion is used starting from a supposed value
+ * for j(n,x). The resulting value of j(0,x) is
+ * compared with the actual value to correct the
+ * supposed value of j(n,x).
+ *
+ * yn(n,x) is similar in all respects, except
+ * that forward recursion is used for all
+ * values of n>1.
+ *
+ */
+
+#include "fdlibm.h"
+
+static const double
+invsqrtpi= 5.64189583547756279280e-01, /* 0x3FE20DD7, 0x50429B6D */
+two = 2.00000000000000000000e+00, /* 0x40000000, 0x00000000 */
+one = 1.00000000000000000000e+00; /* 0x3FF00000, 0x00000000 */
+
+static double zero = 0.00000000000000000000e+00;
+
+ double __ieee754_jn(int n, double x)
+{
+ int i,hx,ix,lx, sgn;
+ double a, b, temp, di;
+ double z, w;
+
+ /* J(-n,x) = (-1)^n * J(n, x), J(n, -x) = (-1)^n * J(n, x)
+ * Thus, J(-n,x) = J(n,-x)
+ */
+ hx = __HI(x);
+ ix = 0x7fffffff&hx;
+ lx = __LO(x);
+ /* if J(n,NaN) is NaN */
+ if((ix|((unsigned)(lx|-lx))>>31)>0x7ff00000) return x+x;
+ if(n<0){
+ n = -n;
+ x = -x;
+ hx ^= 0x80000000;
+ }
+ if(n==0) return(__ieee754_j0(x));
+ if(n==1) return(__ieee754_j1(x));
+ sgn = (n&1)&(hx>>31); /* even n -- 0, odd n -- sign(x) */
+ x = fabs(x);
+ if((ix|lx)==0||ix>=0x7ff00000) /* if x is 0 or inf */
+ b = zero;
+ else if((double)n<=x) {
+ /* Safe to use J(n+1,x)=2n/x *J(n,x)-J(n-1,x) */
+ if(ix>=0x52D00000) { /* x > 2**302 */
+ /* (x >> n**2)
+ * Jn(x) = cos(x-(2n+1)*pi/4)*sqrt(2/x*pi)
+ * Yn(x) = sin(x-(2n+1)*pi/4)*sqrt(2/x*pi)
+ * Let s=sin(x), c=cos(x),
+ * xn=x-(2n+1)*pi/4, sqt2 = sqrt(2),then
+ *
+ * n sin(xn)*sqt2 cos(xn)*sqt2
+ * ----------------------------------
+ * 0 s-c c+s
+ * 1 -s-c -c+s
+ * 2 -s+c -c-s
+ * 3 s+c c-s
+ */
+ switch(n&3) {
+ case 0: temp = cos(x)+sin(x); break;
+ case 1: temp = -cos(x)+sin(x); break;
+ case 2: temp = -cos(x)-sin(x); break;
+ case 3: temp = cos(x)-sin(x); break;
+ }
+ b = invsqrtpi*temp/sqrt(x);
+ } else {
+ a = __ieee754_j0(x);
+ b = __ieee754_j1(x);
+ for(i=1;i<n;i++){
+ temp = b;
+ b = b*((double)(i+i)/x) - a; /* avoid underflow */
+ a = temp;
+ }
+ }
+ } else {
+ if(ix<0x3e100000) { /* x < 2**-29 */
+ /* x is tiny, return the first Taylor expansion of J(n,x)
+ * J(n,x) = 1/n!*(x/2)^n - ...
+ */
+ if(n>33) /* underflow */
+ b = zero;
+ else {
+ temp = x*0.5; b = temp;
+ for (a=one,i=2;i<=n;i++) {
+ a *= (double)i; /* a = n! */
+ b *= temp; /* b = (x/2)^n */
+ }
+ b = b/a;
+ }
+ } else {
+ /* use backward recurrence */
+ /* x x^2 x^2
+ * J(n,x)/J(n-1,x) = ---- ------ ------ .....
+ * 2n - 2(n+1) - 2(n+2)
+ *
+ * 1 1 1
+ * (for large x) = ---- ------ ------ .....
+ * 2n 2(n+1) 2(n+2)
+ * -- - ------ - ------ -
+ * x x x
+ *
+ * Let w = 2n/x and h=2/x, then the above quotient
+ * is equal to the continued fraction:
+ * 1
+ * = -----------------------
+ * 1
+ * w - -----------------
+ * 1
+ * w+h - ---------
+ * w+2h - ...
+ *
+ * To determine how many terms needed, let
+ * Q(0) = w, Q(1) = w(w+h) - 1,
+ * Q(k) = (w+k*h)*Q(k-1) - Q(k-2),
+ * When Q(k) > 1e4 good for single
+ * When Q(k) > 1e9 good for double
+ * When Q(k) > 1e17 good for quadruple
+ */
+ /* determine k */
+ double t,v;
+ double q0,q1,h,tmp; int k,m;
+ w = (n+n)/(double)x; h = 2.0/(double)x;
+ q0 = w; z = w+h; q1 = w*z - 1.0; k=1;
+ while(q1<1.0e9) {
+ k += 1; z += h;
+ tmp = z*q1 - q0;
+ q0 = q1;
+ q1 = tmp;
+ }
+ m = n+n;
+ for(t=zero, i = 2*(n+k); i>=m; i -= 2) t = one/(i/x-t);
+ a = t;
+ b = one;
+ /* estimate log((2/x)^n*n!) = n*log(2/x)+n*ln(n)
+ * Hence, if n*(log(2n/x)) > ...
+ * single 8.8722839355e+01
+ * double 7.09782712893383973096e+02
+ * long double 1.1356523406294143949491931077970765006170e+04
+ * then recurrent value may overflow and the result is
+ * likely underflow to zero
+ */
+ tmp = n;
+ v = two/x;
+ tmp = tmp*__ieee754_log(fabs(v*tmp));
+ if(tmp<7.09782712893383973096e+02) {
+ for(i=n-1,di=(double)(i+i);i>0;i--){
+ temp = b;
+ b *= di;
+ b = b/x - a;
+ a = temp;
+ di -= two;
+ }
+ } else {
+ for(i=n-1,di=(double)(i+i);i>0;i--){
+ temp = b;
+ b *= di;
+ b = b/x - a;
+ a = temp;
+ di -= two;
+ /* scale b to avoid spurious overflow */
+ if(b>1e100) {
+ a /= b;
+ t /= b;
+ b = one;
+ }
+ }
+ }
+ b = (t*__ieee754_j0(x)/b);
+ }
+ }
+ if(sgn==1) return -b; else return b;
+}
+
+ double __ieee754_yn(int n, double x)
+{
+ int i,hx,ix,lx;
+ int sign;
+ double a, b, temp;
+
+ hx = __HI(x);
+ ix = 0x7fffffff&hx;
+ lx = __LO(x);
+ /* if Y(n,NaN) is NaN */
+ if((ix|((unsigned)(lx|-lx))>>31)>0x7ff00000) return x+x;
+ if((ix|lx)==0) return -one/zero;
+ if(hx<0) return zero/zero;
+ sign = 1;
+ if(n<0){
+ n = -n;
+ sign = 1 - ((n&1)<<1);
+ }
+ if(n==0) return(__ieee754_y0(x));
+ if(n==1) return(sign*__ieee754_y1(x));
+ if(ix==0x7ff00000) return zero;
+ if(ix>=0x52D00000) { /* x > 2**302 */
+ /* (x >> n**2)
+ * Jn(x) = cos(x-(2n+1)*pi/4)*sqrt(2/x*pi)
+ * Yn(x) = sin(x-(2n+1)*pi/4)*sqrt(2/x*pi)
+ * Let s=sin(x), c=cos(x),
+ * xn=x-(2n+1)*pi/4, sqt2 = sqrt(2),then
+ *
+ * n sin(xn)*sqt2 cos(xn)*sqt2
+ * ----------------------------------
+ * 0 s-c c+s
+ * 1 -s-c -c+s
+ * 2 -s+c -c-s
+ * 3 s+c c-s
+ */
+ switch(n&3) {
+ case 0: temp = sin(x)-cos(x); break;
+ case 1: temp = -sin(x)-cos(x); break;
+ case 2: temp = -sin(x)+cos(x); break;
+ case 3: temp = sin(x)+cos(x); break;
+ }
+ b = invsqrtpi*temp/sqrt(x);
+ } else {
+ a = __ieee754_y0(x);
+ b = __ieee754_y1(x);
+ /* quit if b is -inf */
+ for(i=1;i<n&&(__HI(b) != 0xfff00000);i++){
+ temp = b;
+ b = ((double)(i+i)/x)*b - a;
+ a = temp;
+ }
+ }
+ if(sign>0) return b; else return -b;
+}
--- /dev/null
+++ b/libmath/fdlibm/e_lgamma_r.c
@@ -1,0 +1,291 @@
+/* derived from /netlib/fdlibm */
+
+/* @(#)e_lgamma_r.c 1.3 95/01/18 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunSoft, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ *
+ */
+
+/* __ieee754_lgamma_r(x, signgamp)
+ * Reentrant version of the logarithm of the Gamma function
+ * with user provide pointer for the sign of Gamma(x).
+ *
+ * Method:
+ * 1. Argument Reduction for 0 < x <= 8
+ * Since gamma(1+s)=s*gamma(s), for x in [0,8], we may
+ * reduce x to a number in [1.5,2.5] by
+ * lgamma(1+s) = log(s) + lgamma(s)
+ * for example,
+ * lgamma(7.3) = log(6.3) + lgamma(6.3)
+ * = log(6.3*5.3) + lgamma(5.3)
+ * = log(6.3*5.3*4.3*3.3*2.3) + lgamma(2.3)
+ * 2. Polynomial approximation of lgamma around its
+ * minimun ymin=1.461632144968362245 to maintain monotonicity.
+ * On [ymin-0.23, ymin+0.27] (i.e., [1.23164,1.73163]), use
+ * Let z = x-ymin;
+ * lgamma(x) = -1.214862905358496078218 + z^2*poly(z)
+ * where
+ * poly(z) is a 14 degree polynomial.
+ * 2. Rational approximation in the primary interval [2,3]
+ * We use the following approximation:
+ * s = x-2.0;
+ * lgamma(x) = 0.5*s + s*P(s)/Q(s)
+ * with accuracy
+ * |P/Q - (lgamma(x)-0.5s)| < 2**-61.71
+ * Our algorithms are based on the following observation
+ *
+ * zeta(2)-1 2 zeta(3)-1 3
+ * lgamma(2+s) = s*(1-Euler) + --------- * s - --------- * s + ...
+ * 2 3
+ *
+ * where Euler = 0.5771... is the Euler constant, which is very
+ * close to 0.5.
+ *
+ * 3. For x>=8, we have
+ * lgamma(x)~(x-0.5)log(x)-x+0.5*log(2pi)+1/(12x)-1/(360x**3)+....
+ * (better formula:
+ * lgamma(x)~(x-0.5)*(log(x)-1)-.5*(log(2pi)-1) + ...)
+ * Let z = 1/x, then we approximation
+ * f(z) = lgamma(x) - (x-0.5)(log(x)-1)
+ * by
+ * 3 5 11
+ * w = w0 + w1*z + w2*z + w3*z + ... + w6*z
+ * where
+ * |w - f(z)| < 2**-58.74
+ *
+ * 4. For negative x, since (G is gamma function)
+ * -x*G(-x)*G(x) = pi/sin(pi*x),
+ * we have
+ * G(x) = pi/(sin(pi*x)*(-x)*G(-x))
+ * since G(-x) is positive, sign(G(x)) = sign(sin(pi*x)) for x<0
+ * Hence, for x<0, signgam = sign(sin(pi*x)) and
+ * lgamma(x) = log(|Gamma(x)|)
+ * = log(pi/(|x*sin(pi*x)|)) - lgamma(-x);
+ * Note: one should avoid compute pi*(-x) directly in the
+ * computation of sin(pi*(-x)).
+ *
+ * 5. Special Cases
+ * lgamma(2+s) ~ s*(1-Euler) for tiny s
+ * lgamma(1)=lgamma(2)=0
+ * lgamma(x) ~ -log(x) for tiny x
+ * lgamma(0) = lgamma(inf) = inf
+ * lgamma(-integer) = +-inf
+ *
+ */
+
+#include "fdlibm.h"
+
+static const double
+two52= 4.50359962737049600000e+15, /* 0x43300000, 0x00000000 */
+half= 5.00000000000000000000e-01, /* 0x3FE00000, 0x00000000 */
+one = 1.00000000000000000000e+00, /* 0x3FF00000, 0x00000000 */
+pi = 3.14159265358979311600e+00, /* 0x400921FB, 0x54442D18 */
+a0 = 7.72156649015328655494e-02, /* 0x3FB3C467, 0xE37DB0C8 */
+a1 = 3.22467033424113591611e-01, /* 0x3FD4A34C, 0xC4A60FAD */
+a2 = 6.73523010531292681824e-02, /* 0x3FB13E00, 0x1A5562A7 */
+a3 = 2.05808084325167332806e-02, /* 0x3F951322, 0xAC92547B */
+a4 = 7.38555086081402883957e-03, /* 0x3F7E404F, 0xB68FEFE8 */
+a5 = 2.89051383673415629091e-03, /* 0x3F67ADD8, 0xCCB7926B */
+a6 = 1.19270763183362067845e-03, /* 0x3F538A94, 0x116F3F5D */
+a7 = 5.10069792153511336608e-04, /* 0x3F40B6C6, 0x89B99C00 */
+a8 = 2.20862790713908385557e-04, /* 0x3F2CF2EC, 0xED10E54D */
+a9 = 1.08011567247583939954e-04, /* 0x3F1C5088, 0x987DFB07 */
+a10 = 2.52144565451257326939e-05, /* 0x3EFA7074, 0x428CFA52 */
+a11 = 4.48640949618915160150e-05, /* 0x3F07858E, 0x90A45837 */
+tc = 1.46163214496836224576e+00, /* 0x3FF762D8, 0x6356BE3F */
+tf = -1.21486290535849611461e-01, /* 0xBFBF19B9, 0xBCC38A42 */
+/* tt = -(tail of tf) */
+tt = -3.63867699703950536541e-18, /* 0xBC50C7CA, 0xA48A971F */
+t0 = 4.83836122723810047042e-01, /* 0x3FDEF72B, 0xC8EE38A2 */
+t1 = -1.47587722994593911752e-01, /* 0xBFC2E427, 0x8DC6C509 */
+t2 = 6.46249402391333854778e-02, /* 0x3FB08B42, 0x94D5419B */
+t3 = -3.27885410759859649565e-02, /* 0xBFA0C9A8, 0xDF35B713 */
+t4 = 1.79706750811820387126e-02, /* 0x3F9266E7, 0x970AF9EC */
+t5 = -1.03142241298341437450e-02, /* 0xBF851F9F, 0xBA91EC6A */
+t6 = 6.10053870246291332635e-03, /* 0x3F78FCE0, 0xE370E344 */
+t7 = -3.68452016781138256760e-03, /* 0xBF6E2EFF, 0xB3E914D7 */
+t8 = 2.25964780900612472250e-03, /* 0x3F6282D3, 0x2E15C915 */
+t9 = -1.40346469989232843813e-03, /* 0xBF56FE8E, 0xBF2D1AF1 */
+t10 = 8.81081882437654011382e-04, /* 0x3F4CDF0C, 0xEF61A8E9 */
+t11 = -5.38595305356740546715e-04, /* 0xBF41A610, 0x9C73E0EC */
+t12 = 3.15632070903625950361e-04, /* 0x3F34AF6D, 0x6C0EBBF7 */
+t13 = -3.12754168375120860518e-04, /* 0xBF347F24, 0xECC38C38 */
+t14 = 3.35529192635519073543e-04, /* 0x3F35FD3E, 0xE8C2D3F4 */
+u0 = -7.72156649015328655494e-02, /* 0xBFB3C467, 0xE37DB0C8 */
+u1 = 6.32827064025093366517e-01, /* 0x3FE4401E, 0x8B005DFF */
+u2 = 1.45492250137234768737e+00, /* 0x3FF7475C, 0xD119BD6F */
+u3 = 9.77717527963372745603e-01, /* 0x3FEF4976, 0x44EA8450 */
+u4 = 2.28963728064692451092e-01, /* 0x3FCD4EAE, 0xF6010924 */
+u5 = 1.33810918536787660377e-02, /* 0x3F8B678B, 0xBF2BAB09 */
+v1 = 2.45597793713041134822e+00, /* 0x4003A5D7, 0xC2BD619C */
+v2 = 2.12848976379893395361e+00, /* 0x40010725, 0xA42B18F5 */
+v3 = 7.69285150456672783825e-01, /* 0x3FE89DFB, 0xE45050AF */
+v4 = 1.04222645593369134254e-01, /* 0x3FBAAE55, 0xD6537C88 */
+v5 = 3.21709242282423911810e-03, /* 0x3F6A5ABB, 0x57D0CF61 */
+s0 = -7.72156649015328655494e-02, /* 0xBFB3C467, 0xE37DB0C8 */
+s1 = 2.14982415960608852501e-01, /* 0x3FCB848B, 0x36E20878 */
+s2 = 3.25778796408930981787e-01, /* 0x3FD4D98F, 0x4F139F59 */
+s3 = 1.46350472652464452805e-01, /* 0x3FC2BB9C, 0xBEE5F2F7 */
+s4 = 2.66422703033638609560e-02, /* 0x3F9B481C, 0x7E939961 */
+s5 = 1.84028451407337715652e-03, /* 0x3F5E26B6, 0x7368F239 */
+s6 = 3.19475326584100867617e-05, /* 0x3F00BFEC, 0xDD17E945 */
+r1 = 1.39200533467621045958e+00, /* 0x3FF645A7, 0x62C4AB74 */
+r2 = 7.21935547567138069525e-01, /* 0x3FE71A18, 0x93D3DCDC */
+r3 = 1.71933865632803078993e-01, /* 0x3FC601ED, 0xCCFBDF27 */
+r4 = 1.86459191715652901344e-02, /* 0x3F9317EA, 0x742ED475 */
+r5 = 7.77942496381893596434e-04, /* 0x3F497DDA, 0xCA41A95B */
+r6 = 7.32668430744625636189e-06, /* 0x3EDEBAF7, 0xA5B38140 */
+w0 = 4.18938533204672725052e-01, /* 0x3FDACFE3, 0x90C97D69 */
+w1 = 8.33333333333329678849e-02, /* 0x3FB55555, 0x5555553B */
+w2 = -2.77777777728775536470e-03, /* 0xBF66C16C, 0x16B02E5C */
+w3 = 7.93650558643019558500e-04, /* 0x3F4A019F, 0x98CF38B6 */
+w4 = -5.95187557450339963135e-04, /* 0xBF4380CB, 0x8C0FE741 */
+w5 = 8.36339918996282139126e-04, /* 0x3F4B67BA, 0x4CDAD5D1 */
+w6 = -1.63092934096575273989e-03; /* 0xBF5AB89D, 0x0B9E43E4 */
+
+static double zero= 0.00000000000000000000e+00;
+
+ static double sin_pi(double x)
+{
+ double y,z;
+ int n,ix;
+
+ ix = 0x7fffffff&__HI(x);
+
+ if(ix<0x3fd00000) return __kernel_sin(pi*x,zero,0);
+ y = -x; /* x is assume negative */
+
+ /*
+ * argument reduction, make sure inexact flag not raised if input
+ * is an integer
+ */
+ z = floor(y);
+ if(z!=y) { /* inexact anyway */
+ y *= 0.5;
+ y = 2.0*(y - floor(y)); /* y = |x| mod 2.0 */
+ n = (int) (y*4.0);
+ } else {
+ if(ix>=0x43400000) {
+ y = zero; n = 0; /* y must be even */
+ } else {
+ if(ix<0x43300000) z = y+two52; /* exact */
+ n = __LO(z)&1; /* lower word of z */
+ y = n;
+ n<<= 2;
+ }
+ }
+ switch (n) {
+ case 0: y = __kernel_sin(pi*y,zero,0); break;
+ case 1:
+ case 2: y = __kernel_cos(pi*(0.5-y),zero); break;
+ case 3:
+ case 4: y = __kernel_sin(pi*(one-y),zero,0); break;
+ case 5:
+ case 6: y = -__kernel_cos(pi*(y-1.5),zero); break;
+ default: y = __kernel_sin(pi*(y-2.0),zero,0); break;
+ }
+ return -y;
+}
+
+
+ double __ieee754_lgamma_r(double x, int *signgamp)
+{
+ double t,y,z,nadj,p,p1,p2,p3,q,r,w;
+ int i,hx,lx,ix;
+
+ hx = __HI(x);
+ lx = __LO(x);
+
+ /* purge off +-inf, NaN, +-0, and negative arguments */
+ *signgamp = 1;
+ ix = hx&0x7fffffff;
+ if(ix>=0x7ff00000) return x*x;
+ if((ix|lx)==0) return one/zero;
+ if(ix<0x3b900000) { /* |x|<2**-70, return -log(|x|) */
+ if(hx<0) {
+ *signgamp = -1;
+ return -__ieee754_log(-x);
+ } else return -__ieee754_log(x);
+ }
+ if(hx<0) {
+ if(ix>=0x43300000) /* |x|>=2**52, must be -integer */
+ return one/zero;
+ t = sin_pi(x);
+ if(t==zero) return one/zero; /* -integer */
+ nadj = __ieee754_log(pi/fabs(t*x));
+ if(t<zero) *signgamp = -1;
+ x = -x;
+ }
+
+ /* purge off 1 and 2 */
+ if((((ix-0x3ff00000)|lx)==0)||(((ix-0x40000000)|lx)==0)) r = 0;
+ /* for x < 2.0 */
+ else if(ix<0x40000000) {
+ if(ix<=0x3feccccc) { /* lgamma(x) = lgamma(x+1)-log(x) */
+ r = -__ieee754_log(x);
+ if(ix>=0x3FE76944) {y = one-x; i= 0;}
+ else if(ix>=0x3FCDA661) {y= x-(tc-one); i=1;}
+ else {y = x; i=2;}
+ } else {
+ r = zero;
+ if(ix>=0x3FFBB4C3) {y=2.0-x;i=0;} /* [1.7316,2] */
+ else if(ix>=0x3FF3B4C4) {y=x-tc;i=1;} /* [1.23,1.73] */
+ else {y=x-one;i=2;}
+ }
+ switch(i) {
+ case 0:
+ z = y*y;
+ p1 = a0+z*(a2+z*(a4+z*(a6+z*(a8+z*a10))));
+ p2 = z*(a1+z*(a3+z*(a5+z*(a7+z*(a9+z*a11)))));
+ p = y*p1+p2;
+ r += (p-0.5*y); break;
+ case 1:
+ z = y*y;
+ w = z*y;
+ p1 = t0+w*(t3+w*(t6+w*(t9 +w*t12))); /* parallel comp */
+ p2 = t1+w*(t4+w*(t7+w*(t10+w*t13)));
+ p3 = t2+w*(t5+w*(t8+w*(t11+w*t14)));
+ p = z*p1-(tt-w*(p2+y*p3));
+ r += (tf + p); break;
+ case 2:
+ p1 = y*(u0+y*(u1+y*(u2+y*(u3+y*(u4+y*u5)))));
+ p2 = one+y*(v1+y*(v2+y*(v3+y*(v4+y*v5))));
+ r += (-0.5*y + p1/p2);
+ }
+ }
+ else if(ix<0x40200000) { /* x < 8.0 */
+ i = (int)x;
+ t = zero;
+ y = x-(double)i;
+ p = y*(s0+y*(s1+y*(s2+y*(s3+y*(s4+y*(s5+y*s6))))));
+ q = one+y*(r1+y*(r2+y*(r3+y*(r4+y*(r5+y*r6)))));
+ r = half*y+p/q;
+ z = one; /* lgamma(1+s) = log(s) + lgamma(s) */
+ switch(i) {
+ case 7: z *= (y+6.0); /* FALLTHRU */
+ case 6: z *= (y+5.0); /* FALLTHRU */
+ case 5: z *= (y+4.0); /* FALLTHRU */
+ case 4: z *= (y+3.0); /* FALLTHRU */
+ case 3: z *= (y+2.0); /* FALLTHRU */
+ r += __ieee754_log(z); break;
+ }
+ /* 8.0 <= x < 2**58 */
+ } else if (ix < 0x43900000) {
+ t = __ieee754_log(x);
+ z = one/x;
+ y = z*z;
+ w = w0+z*(w1+y*(w2+y*(w3+y*(w4+y*(w5+y*w6)))));
+ r = (x-half)*(t-one)+w;
+ } else
+ /* 2**58 <= x <= inf */
+ r = x*(__ieee754_log(x)-one);
+ if(hx<0) r = nadj - r;
+ return r;
+}
--- /dev/null
+++ b/libmath/fdlibm/e_log.c
@@ -1,0 +1,131 @@
+/* derived from /netlib/fdlibm */
+
+/* @(#)e_log.c 1.3 95/01/18 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunSoft, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+/* __ieee754_log(x)
+ * Return the logrithm of x
+ *
+ * Method :
+ * 1. Argument Reduction: find k and f such that
+ * x = 2^k * (1+f),
+ * where sqrt(2)/2 < 1+f < sqrt(2) .
+ *
+ * 2. Approximation of log(1+f).
+ * Let s = f/(2+f) ; based on log(1+f) = log(1+s) - log(1-s)
+ * = 2s + 2/3 s**3 + 2/5 s**5 + .....,
+ * = 2s + s*R
+ * We use a special Reme algorithm on [0,0.1716] to generate
+ * a polynomial of degree 14 to approximate R The maximum error
+ * of this polynomial approximation is bounded by 2**-58.45. In
+ * other words,
+ * 2 4 6 8 10 12 14
+ * R(z) ~ Lg1*s +Lg2*s +Lg3*s +Lg4*s +Lg5*s +Lg6*s +Lg7*s
+ * (the values of Lg1 to Lg7 are listed in the program)
+ * and
+ * | 2 14 | -58.45
+ * | Lg1*s +...+Lg7*s - R(z) | <= 2
+ * | |
+ * Note that 2s = f - s*f = f - hfsq + s*hfsq, where hfsq = f*f/2.
+ * In order to guarantee error in log below 1ulp, we compute log
+ * by
+ * log(1+f) = f - s*(f - R) (if f is not too large)
+ * log(1+f) = f - (hfsq - s*(hfsq+R)). (better accuracy)
+ *
+ * 3. Finally, log(x) = k*ln2 + log(1+f).
+ * = k*ln2_hi+(f-(hfsq-(s*(hfsq+R)+k*ln2_lo)))
+ * Here ln2 is split into two floating point number:
+ * ln2_hi + ln2_lo,
+ * where n*ln2_hi is always exact for |n| < 2000.
+ *
+ * Special cases:
+ * log(x) is NaN with signal if x < 0 (including -INF) ;
+ * log(+INF) is +INF; log(0) is -INF with signal;
+ * log(NaN) is that NaN with no signal.
+ *
+ * Accuracy:
+ * according to an error analysis, the error is always less than
+ * 1 ulp (unit in the last place).
+ *
+ * Constants:
+ * The hexadecimal values are the intended ones for the following
+ * constants. The decimal values may be used, provided that the
+ * compiler will convert from decimal to binary accurately enough
+ * to produce the hexadecimal values shown.
+ */
+
+#include "fdlibm.h"
+
+static const double
+ln2_hi = 6.93147180369123816490e-01, /* 3fe62e42 fee00000 */
+ln2_lo = 1.90821492927058770002e-10, /* 3dea39ef 35793c76 */
+two54 = 1.80143985094819840000e+16, /* 43500000 00000000 */
+Lg1 = 6.666666666666735130e-01, /* 3FE55555 55555593 */
+Lg2 = 3.999999999940941908e-01, /* 3FD99999 9997FA04 */
+Lg3 = 2.857142874366239149e-01, /* 3FD24924 94229359 */
+Lg4 = 2.222219843214978396e-01, /* 3FCC71C5 1D8E78AF */
+Lg5 = 1.818357216161805012e-01, /* 3FC74664 96CB03DE */
+Lg6 = 1.531383769920937332e-01, /* 3FC39A09 D078C69F */
+Lg7 = 1.479819860511658591e-01; /* 3FC2F112 DF3E5244 */
+
+static double zero = 0.0;
+
+ double __ieee754_log(double x)
+{
+ double hfsq,f,s,z,R,w,t1,t2,dk;
+ int k,hx,i,j;
+ unsigned lx;
+
+ hx = __HI(x); /* high word of x */
+ lx = __LO(x); /* low word of x */
+
+ k=0;
+ if (hx < 0x00100000) { /* x < 2**-1022 */
+ if (((hx&0x7fffffff)|lx)==0)
+ return -two54/zero; /* log(+-0)=-inf */
+ if (hx<0) return (x-x)/zero; /* log(-#) = NaN */
+ k -= 54; x *= two54; /* subnormal number, scale up x */
+ hx = __HI(x); /* high word of x */
+ }
+ if (hx >= 0x7ff00000) return x+x;
+ k += (hx>>20)-1023;
+ hx &= 0x000fffff;
+ i = (hx+0x95f64)&0x100000;
+ __HI(x) = hx|(i^0x3ff00000); /* normalize x or x/2 */
+ k += (i>>20);
+ f = x-1.0;
+ if((0x000fffff&(2+hx))<3) { /* |f| < 2**-20 */
+ if(f==zero) if(k==0) return zero; else {dk=(double)k;
+ return dk*ln2_hi+dk*ln2_lo;}
+ R = f*f*(0.5-0.33333333333333333*f);
+ if(k==0) return f-R; else {dk=(double)k;
+ return dk*ln2_hi-((R-dk*ln2_lo)-f);}
+ }
+ s = f/(2.0+f);
+ dk = (double)k;
+ z = s*s;
+ i = hx-0x6147a;
+ w = z*z;
+ j = 0x6b851-hx;
+ t1= w*(Lg2+w*(Lg4+w*Lg6));
+ t2= z*(Lg1+w*(Lg3+w*(Lg5+w*Lg7)));
+ i |= j;
+ R = t2+t1;
+ if(i>0) {
+ hfsq=0.5*f*f;
+ if(k==0) return f-(hfsq-s*(hfsq+R)); else
+ return dk*ln2_hi-((hfsq-(s*(hfsq+R)+dk*ln2_lo))-f);
+ } else {
+ if(k==0) return f-s*(f-R); else
+ return dk*ln2_hi-((s*(f-R)-dk*ln2_lo)-f);
+ }
+}
--- /dev/null
+++ b/libmath/fdlibm/e_log10.c
@@ -1,0 +1,83 @@
+/* derived from /netlib/fdlibm */
+
+/* @(#)e_log10.c 1.3 95/01/18 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunSoft, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+/* __ieee754_log10(x)
+ * Return the base 10 logarithm of x
+ *
+ * Method :
+ * Let log10_2hi = leading 40 bits of log10(2) and
+ * log10_2lo = log10(2) - log10_2hi,
+ * ivln10 = 1/log(10) rounded.
+ * Then
+ * n = ilogb(x),
+ * if(n<0) n = n+1;
+ * x = scalbn(x,-n);
+ * log10(x) := n*log10_2hi + (n*log10_2lo + ivln10*log(x))
+ *
+ * Note 1:
+ * To guarantee log10(10**n)=n, where 10**n is normal, the rounding
+ * mode must set to Round-to-Nearest.
+ * Note 2:
+ * [1/log(10)] rounded to 53 bits has error .198 ulps;
+ * log10 is monotonic at all binary break points.
+ *
+ * Special cases:
+ * log10(x) is NaN with signal if x < 0;
+ * log10(+INF) is +INF with no signal; log10(0) is -INF with signal;
+ * log10(NaN) is that NaN with no signal;
+ * log10(10**N) = N for N=0,1,...,22.
+ *
+ * Constants:
+ * The hexadecimal values are the intended ones for the following constants.
+ * The decimal values may be used, provided that the compiler will convert
+ * from decimal to binary accurately enough to produce the hexadecimal values
+ * shown.
+ */
+
+#include "fdlibm.h"
+
+static const double
+two54 = 1.80143985094819840000e+16, /* 0x43500000, 0x00000000 */
+ivln10 = 4.34294481903251816668e-01, /* 0x3FDBCB7B, 0x1526E50E */
+log10_2hi = 3.01029995663611771306e-01, /* 0x3FD34413, 0x509F6000 */
+log10_2lo = 3.69423907715893078616e-13; /* 0x3D59FEF3, 0x11F12B36 */
+
+static double zero = 0.0;
+
+ double __ieee754_log10(double x)
+{
+ double y,z;
+ int i,k,hx;
+ unsigned lx;
+
+ hx = __HI(x); /* high word of x */
+ lx = __LO(x); /* low word of x */
+
+ k=0;
+ if (hx < 0x00100000) { /* x < 2**-1022 */
+ if (((hx&0x7fffffff)|lx)==0)
+ return -two54/zero; /* log(+-0)=-inf */
+ if (hx<0) return (x-x)/zero; /* log(-#) = NaN */
+ k -= 54; x *= two54; /* subnormal number, scale up x */
+ hx = __HI(x); /* high word of x */
+ }
+ if (hx >= 0x7ff00000) return x+x;
+ k += (hx>>20)-1023;
+ i = ((unsigned)k&0x80000000)>>31;
+ hx = (hx&0x000fffff)|((0x3ff-i)<<20);
+ y = (double)(k+i);
+ __HI(x) = hx;
+ z = y*log10_2lo + ivln10*__ieee754_log(x);
+ return z+y*log10_2hi;
+}
--- /dev/null
+++ b/libmath/fdlibm/e_pow.c
@@ -1,0 +1,296 @@
+/* derived from /netlib/fdlibm */
+
+/* @(#)e_pow.c 1.3 95/01/18 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunSoft, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+/* __ieee754_pow(x,y) return x**y
+ *
+ * n
+ * Method: Let x = 2 * (1+f)
+ * 1. Compute and return log2(x) in two pieces:
+ * log2(x) = w1 + w2,
+ * where w1 has 53-24 = 29 bit trailing zeros.
+ * 2. Perform y*log2(x) = n+y' by simulating muti-precision
+ * arithmetic, where |y'|<=0.5.
+ * 3. Return x**y = 2**n*exp(y'*log2)
+ *
+ * Special cases:
+ * 1. (anything) ** 0 is 1
+ * 2. (anything) ** 1 is itself
+ * 3. (anything) ** NAN is NAN
+ * 4. NAN ** (anything except 0) is NAN
+ * 5. +-(|x| > 1) ** +INF is +INF
+ * 6. +-(|x| > 1) ** -INF is +0
+ * 7. +-(|x| < 1) ** +INF is +0
+ * 8. +-(|x| < 1) ** -INF is +INF
+ * 9. +-1 ** +-INF is NAN
+ * 10. +0 ** (+anything except 0, NAN) is +0
+ * 11. -0 ** (+anything except 0, NAN, odd integer) is +0
+ * 12. +0 ** (-anything except 0, NAN) is +INF
+ * 13. -0 ** (-anything except 0, NAN, odd integer) is +INF
+ * 14. -0 ** (odd integer) = -( +0 ** (odd integer) )
+ * 15. +INF ** (+anything except 0,NAN) is +INF
+ * 16. +INF ** (-anything except 0,NAN) is +0
+ * 17. -INF ** (anything) = -0 ** (-anything)
+ * 18. (-anything) ** (integer) is (-1)**(integer)*(+anything**integer)
+ * 19. (-anything except 0 and inf) ** (non-integer) is NAN
+ *
+ * Accuracy:
+ * pow(x,y) returns x**y nearly rounded. In particular
+ * pow(integer,integer)
+ * always returns the correct integer provided it is
+ * representable.
+ *
+ * Constants :
+ * The hexadecimal values are the intended ones for the following
+ * constants. The decimal values may be used, provided that the
+ * compiler will convert from decimal to binary accurately enough
+ * to produce the hexadecimal values shown.
+ */
+
+#include "fdlibm.h"
+
+static const double
+bp[] = {1.0, 1.5,},
+dp_h[] = { 0.0, 5.84962487220764160156e-01,}, /* 0x3FE2B803, 0x40000000 */
+dp_l[] = { 0.0, 1.35003920212974897128e-08,}, /* 0x3E4CFDEB, 0x43CFD006 */
+zero = 0.0,
+one = 1.0,
+two = 2.0,
+two53 = 9007199254740992.0, /* 0x43400000, 0x00000000 */
+Huge = 1.0e300,
+tiny = 1.0e-300,
+ /* poly coefs for (3/2)*(log(x)-2s-2/3*s**3 */
+L1 = 5.99999999999994648725e-01, /* 0x3FE33333, 0x33333303 */
+L2 = 4.28571428578550184252e-01, /* 0x3FDB6DB6, 0xDB6FABFF */
+L3 = 3.33333329818377432918e-01, /* 0x3FD55555, 0x518F264D */
+L4 = 2.72728123808534006489e-01, /* 0x3FD17460, 0xA91D4101 */
+L5 = 2.30660745775561754067e-01, /* 0x3FCD864A, 0x93C9DB65 */
+L6 = 2.06975017800338417784e-01, /* 0x3FCA7E28, 0x4A454EEF */
+P1 = 1.66666666666666019037e-01, /* 0x3FC55555, 0x5555553E */
+P2 = -2.77777777770155933842e-03, /* 0xBF66C16C, 0x16BEBD93 */
+P3 = 6.61375632143793436117e-05, /* 0x3F11566A, 0xAF25DE2C */
+P4 = -1.65339022054652515390e-06, /* 0xBEBBBD41, 0xC5D26BF1 */
+P5 = 4.13813679705723846039e-08, /* 0x3E663769, 0x72BEA4D0 */
+lg2 = 6.93147180559945286227e-01, /* 0x3FE62E42, 0xFEFA39EF */
+lg2_h = 6.93147182464599609375e-01, /* 0x3FE62E43, 0x00000000 */
+lg2_l = -1.90465429995776804525e-09, /* 0xBE205C61, 0x0CA86C39 */
+ovt = 8.0085662595372944372e-0017, /* -(1024-log2(ovfl+.5ulp)) */
+cp = 9.61796693925975554329e-01, /* 0x3FEEC709, 0xDC3A03FD =2/(3ln2) */
+cp_h = 9.61796700954437255859e-01, /* 0x3FEEC709, 0xE0000000 =(float)cp */
+cp_l = -7.02846165095275826516e-09, /* 0xBE3E2FE0, 0x145B01F5 =tail of cp_h*/
+ivln2 = 1.44269504088896338700e+00, /* 0x3FF71547, 0x652B82FE =1/ln2 */
+ivln2_h = 1.44269502162933349609e+00, /* 0x3FF71547, 0x60000000 =24b 1/ln2*/
+ivln2_l = 1.92596299112661746887e-08; /* 0x3E54AE0B, 0xF85DDF44 =1/ln2 tail*/
+
+ double __ieee754_pow(double x, double y)
+{
+ double z,ax,z_h,z_l,p_h,p_l;
+ double y1,t1,t2,r,s,t,u,v,w;
+ int i,j,k,yisint,n;
+ int hx,hy,ix,iy;
+ unsigned lx,ly;
+
+ hx = __HI(x); lx = __LO(x);
+ hy = __HI(y); ly = __LO(y);
+ ix = hx&0x7fffffff; iy = hy&0x7fffffff;
+
+ /* y==zero: x**0 = 1 */
+ if((iy|ly)==0) return one;
+
+ /* +-NaN return x+y */
+ if(ix > 0x7ff00000 || ((ix==0x7ff00000)&&(lx!=0)) ||
+ iy > 0x7ff00000 || ((iy==0x7ff00000)&&(ly!=0)))
+ return x+y;
+
+ /* determine if y is an odd int when x < 0
+ * yisint = 0 ... y is not an integer
+ * yisint = 1 ... y is an odd int
+ * yisint = 2 ... y is an even int
+ */
+ yisint = 0;
+ if(hx<0) {
+ if(iy>=0x43400000) yisint = 2; /* even integer y */
+ else if(iy>=0x3ff00000) {
+ k = (iy>>20)-0x3ff; /* exponent */
+ if(k>20) {
+ j = ly>>(52-k);
+ if((j<<(52-k))==ly) yisint = 2-(j&1);
+ } else if(ly==0) {
+ j = iy>>(20-k);
+ if((j<<(20-k))==iy) yisint = 2-(j&1);
+ }
+ }
+ }
+
+ /* special value of y */
+ if(ly==0) {
+ if (iy==0x7ff00000) { /* y is +-inf */
+ if(((ix-0x3ff00000)|lx)==0)
+ return y - y; /* inf**+-1 is NaN */
+ else if (ix >= 0x3ff00000)/* (|x|>1)**+-inf = inf,0 */
+ return (hy>=0)? y: zero;
+ else /* (|x|<1)**-,+inf = inf,0 */
+ return (hy<0)?-y: zero;
+ }
+ if(iy==0x3ff00000) { /* y is +-1 */
+ if(hy<0) return one/x; else return x;
+ }
+ if(hy==0x40000000) return x*x; /* y is 2 */
+ if(hy==0x3fe00000) { /* y is 0.5 */
+ if(hx>=0) /* x >= +0 */
+ return sqrt(x);
+ }
+ }
+
+ ax = fabs(x);
+ /* special value of x */
+ if(lx==0) {
+ if(ix==0x7ff00000||ix==0||ix==0x3ff00000){
+ z = ax; /*x is +-0,+-inf,+-1*/
+ if(hy<0) z = one/z; /* z = (1/|x|) */
+ if(hx<0) {
+ if(((ix-0x3ff00000)|yisint)==0) {
+ z = (z-z)/(z-z); /* (-1)**non-int is NaN */
+ } else if(yisint==1)
+ z = -z; /* (x<0)**odd = -(|x|**odd) */
+ }
+ return z;
+ }
+ }
+
+ /* (x<0)**(non-int) is NaN */
+ if((((hx>>31)+1)|yisint)==0) return (x-x)/(x-x);
+
+ /* |y| is Huge */
+ if(iy>0x41e00000) { /* if |y| > 2**31 */
+ if(iy>0x43f00000){ /* if |y| > 2**64, must o/uflow */
+ if(ix<=0x3fefffff) return (hy<0)? Huge*Huge:tiny*tiny;
+ if(ix>=0x3ff00000) return (hy>0)? Huge*Huge:tiny*tiny;
+ }
+ /* over/underflow if x is not close to one */
+ if(ix<0x3fefffff) return (hy<0)? Huge*Huge:tiny*tiny;
+ if(ix>0x3ff00000) return (hy>0)? Huge*Huge:tiny*tiny;
+ /* now |1-x| is tiny <= 2**-20, suffice to compute
+ log(x) by x-x^2/2+x^3/3-x^4/4 */
+ t = x-1; /* t has 20 trailing zeros */
+ w = (t*t)*(0.5-t*(0.3333333333333333333333-t*0.25));
+ u = ivln2_h*t; /* ivln2_h has 21 sig. bits */
+ v = t*ivln2_l-w*ivln2;
+ t1 = u+v;
+ __LO(t1) = 0;
+ t2 = v-(t1-u);
+ } else {
+ double s2,s_h,s_l,t_h,t_l;
+ n = 0;
+ /* take care subnormal number */
+ if(ix<0x00100000)
+ {ax *= two53; n -= 53; ix = __HI(ax); }
+ n += ((ix)>>20)-0x3ff;
+ j = ix&0x000fffff;
+ /* determine interval */
+ ix = j|0x3ff00000; /* normalize ix */
+ if(j<=0x3988E) k=0; /* |x|<sqrt(3/2) */
+ else if(j<0xBB67A) k=1; /* |x|<sqrt(3) */
+ else {k=0;n+=1;ix -= 0x00100000;}
+ __HI(ax) = ix;
+
+ /* compute s = s_h+s_l = (x-1)/(x+1) or (x-1.5)/(x+1.5) */
+ u = ax-bp[k]; /* bp[0]=1.0, bp[1]=1.5 */
+ v = one/(ax+bp[k]);
+ s = u*v;
+ s_h = s;
+ __LO(s_h) = 0;
+ /* t_h=ax+bp[k] High */
+ t_h = zero;
+ __HI(t_h)=((ix>>1)|0x20000000)+0x00080000+(k<<18);
+ t_l = ax - (t_h-bp[k]);
+ s_l = v*((u-s_h*t_h)-s_h*t_l);
+ /* compute log(ax) */
+ s2 = s*s;
+ r = s2*s2*(L1+s2*(L2+s2*(L3+s2*(L4+s2*(L5+s2*L6)))));
+ r += s_l*(s_h+s);
+ s2 = s_h*s_h;
+ t_h = 3.0+s2+r;
+ __LO(t_h) = 0;
+ t_l = r-((t_h-3.0)-s2);
+ /* u+v = s*(1+...) */
+ u = s_h*t_h;
+ v = s_l*t_h+t_l*s;
+ /* 2/(3log2)*(s+...) */
+ p_h = u+v;
+ __LO(p_h) = 0;
+ p_l = v-(p_h-u);
+ z_h = cp_h*p_h; /* cp_h+cp_l = 2/(3*log2) */
+ z_l = cp_l*p_h+p_l*cp+dp_l[k];
+ /* log2(ax) = (s+..)*2/(3*log2) = n + dp_h + z_h + z_l */
+ t = (double)n;
+ t1 = (((z_h+z_l)+dp_h[k])+t);
+ __LO(t1) = 0;
+ t2 = z_l-(((t1-t)-dp_h[k])-z_h);
+ }
+
+ s = one; /* s (sign of result -ve**odd) = -1 else = 1 */
+ if((((hx>>31)+1)|(yisint-1))==0) s = -one;/* (-ve)**(odd int) */
+
+ /* split up y into y1+y2 and compute (y1+y2)*(t1+t2) */
+ y1 = y;
+ __LO(y1) = 0;
+ p_l = (y-y1)*t1+y*t2;
+ p_h = y1*t1;
+ z = p_l+p_h;
+ j = __HI(z);
+ i = __LO(z);
+ if (j>=0x40900000) { /* z >= 1024 */
+ if(((j-0x40900000)|i)!=0) /* if z > 1024 */
+ return s*Huge*Huge; /* overflow */
+ else {
+ if(p_l+ovt>z-p_h) return s*Huge*Huge; /* overflow */
+ }
+ } else if((j&0x7fffffff)>=0x4090cc00 ) { /* z <= -1075 */
+ if(((j-0xc090cc00)|i)!=0) /* z < -1075 */
+ return s*tiny*tiny; /* underflow */
+ else {
+ if(p_l<=z-p_h) return s*tiny*tiny; /* underflow */
+ }
+ }
+ /*
+ * compute 2**(p_h+p_l)
+ */
+ i = j&0x7fffffff;
+ k = (i>>20)-0x3ff;
+ n = 0;
+ if(i>0x3fe00000) { /* if |z| > 0.5, set n = [z+0.5] */
+ n = j+(0x00100000>>(k+1));
+ k = ((n&0x7fffffff)>>20)-0x3ff; /* new k for n */
+ t = zero;
+ __HI(t) = (n&~(0x000fffff>>k));
+ n = ((n&0x000fffff)|0x00100000)>>(20-k);
+ if(j<0) n = -n;
+ p_h -= t;
+ }
+ t = p_l+p_h;
+ __LO(t) = 0;
+ u = t*lg2_h;
+ v = (p_l-(t-p_h))*lg2+t*lg2_l;
+ z = u+v;
+ w = v-(z-u);
+ t = z*z;
+ t1 = z - t*(P1+t*(P2+t*(P3+t*(P4+t*P5))));
+ r = (z*t1)/(t1-two)-(w+z*w);
+ z = one-(r-z);
+ j = __HI(z);
+ j += (n<<20);
+ if((j>>20)<=0) z = scalbn(z,n); /* subnormal output */
+ else __HI(z) += (n<<20);
+ return s*z;
+}
--- /dev/null
+++ b/libmath/fdlibm/e_rem_pio2.c
@@ -1,0 +1,159 @@
+/* derived from /netlib/fdlibm */
+
+/* @(#)e_rem_pio2.c 1.4 95/01/18 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunSoft, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ *
+ */
+
+/* __ieee754_rem_pio2(x,y)
+ *
+ * return the remainder of x rem pi/2 in y[0]+y[1]
+ * use __kernel_rem_pio2()
+ */
+
+#include "fdlibm.h"
+
+/*
+ * Table of constants for 2/pi, 396 Hex digits (476 decimal) of 2/pi
+ */
+static const int two_over_pi[] = {
+0xA2F983, 0x6E4E44, 0x1529FC, 0x2757D1, 0xF534DD, 0xC0DB62,
+0x95993C, 0x439041, 0xFE5163, 0xABDEBB, 0xC561B7, 0x246E3A,
+0x424DD2, 0xE00649, 0x2EEA09, 0xD1921C, 0xFE1DEB, 0x1CB129,
+0xA73EE8, 0x8235F5, 0x2EBB44, 0x84E99C, 0x7026B4, 0x5F7E41,
+0x3991D6, 0x398353, 0x39F49C, 0x845F8B, 0xBDF928, 0x3B1FF8,
+0x97FFDE, 0x05980F, 0xEF2F11, 0x8B5A0A, 0x6D1F6D, 0x367ECF,
+0x27CB09, 0xB74F46, 0x3F669E, 0x5FEA2D, 0x7527BA, 0xC7EBE5,
+0xF17B3D, 0x0739F7, 0x8A5292, 0xEA6BFB, 0x5FB11F, 0x8D5D08,
+0x560330, 0x46FC7B, 0x6BABF0, 0xCFBC20, 0x9AF436, 0x1DA9E3,
+0x91615E, 0xE61B08, 0x659985, 0x5F14A0, 0x68408D, 0xFFD880,
+0x4D7327, 0x310606, 0x1556CA, 0x73A8C9, 0x60E27B, 0xC08C6B,
+};
+
+static const int npio2_hw[] = {
+0x3FF921FB, 0x400921FB, 0x4012D97C, 0x401921FB, 0x401F6A7A, 0x4022D97C,
+0x4025FDBB, 0x402921FB, 0x402C463A, 0x402F6A7A, 0x4031475C, 0x4032D97C,
+0x40346B9C, 0x4035FDBB, 0x40378FDB, 0x403921FB, 0x403AB41B, 0x403C463A,
+0x403DD85A, 0x403F6A7A, 0x40407E4C, 0x4041475C, 0x4042106C, 0x4042D97C,
+0x4043A28C, 0x40446B9C, 0x404534AC, 0x4045FDBB, 0x4046C6CB, 0x40478FDB,
+0x404858EB, 0x404921FB,
+};
+
+/*
+ * invpio2: 53 bits of 2/pi
+ * pio2_1: first 33 bit of pi/2
+ * pio2_1t: pi/2 - pio2_1
+ * pio2_2: second 33 bit of pi/2
+ * pio2_2t: pi/2 - (pio2_1+pio2_2)
+ * pio2_3: third 33 bit of pi/2
+ * pio2_3t: pi/2 - (pio2_1+pio2_2+pio2_3)
+ */
+
+static const double
+zero = 0.00000000000000000000e+00, /* 0x00000000, 0x00000000 */
+half = 5.00000000000000000000e-01, /* 0x3FE00000, 0x00000000 */
+two24 = 1.67772160000000000000e+07, /* 0x41700000, 0x00000000 */
+invpio2 = 6.36619772367581382433e-01, /* 0x3FE45F30, 0x6DC9C883 */
+pio2_1 = 1.57079632673412561417e+00, /* 0x3FF921FB, 0x54400000 */
+pio2_1t = 6.07710050650619224932e-11, /* 0x3DD0B461, 0x1A626331 */
+pio2_2 = 6.07710050630396597660e-11, /* 0x3DD0B461, 0x1A600000 */
+pio2_2t = 2.02226624879595063154e-21, /* 0x3BA3198A, 0x2E037073 */
+pio2_3 = 2.02226624871116645580e-21, /* 0x3BA3198A, 0x2E000000 */
+pio2_3t = 8.47842766036889956997e-32; /* 0x397B839A, 0x252049C1 */
+
+ int __ieee754_rem_pio2(double x, double *y)
+{
+ double z,w,t,r,fn;
+ double tx[3];
+ int e0,i,j,nx,n,ix,hx;
+
+ hx = __HI(x); /* high word of x */
+ ix = hx&0x7fffffff;
+ if(ix<=0x3fe921fb) /* |x| ~<= pi/4 , no need for reduction */
+ {y[0] = x; y[1] = 0; return 0;}
+ if(ix<0x4002d97c) { /* |x| < 3pi/4, special case with n=+-1 */
+ if(hx>0) {
+ z = x - pio2_1;
+ if(ix!=0x3ff921fb) { /* 33+53 bit pi is good enough */
+ y[0] = z - pio2_1t;
+ y[1] = (z-y[0])-pio2_1t;
+ } else { /* near pi/2, use 33+33+53 bit pi */
+ z -= pio2_2;
+ y[0] = z - pio2_2t;
+ y[1] = (z-y[0])-pio2_2t;
+ }
+ return 1;
+ } else { /* negative x */
+ z = x + pio2_1;
+ if(ix!=0x3ff921fb) { /* 33+53 bit pi is good enough */
+ y[0] = z + pio2_1t;
+ y[1] = (z-y[0])+pio2_1t;
+ } else { /* near pi/2, use 33+33+53 bit pi */
+ z += pio2_2;
+ y[0] = z + pio2_2t;
+ y[1] = (z-y[0])+pio2_2t;
+ }
+ return -1;
+ }
+ }
+ if(ix<=0x413921fb) { /* |x| ~<= 2^19*(pi/2), medium size */
+ t = fabs(x);
+ n = (int) (t*invpio2+half);
+ fn = (double)n;
+ r = t-fn*pio2_1;
+ w = fn*pio2_1t; /* 1st round good to 85 bit */
+ if(n<32&&ix!=npio2_hw[n-1]) {
+ y[0] = r-w; /* quick check no cancellation */
+ } else {
+ j = ix>>20;
+ y[0] = r-w;
+ i = j-(((__HI(y[0]))>>20)&0x7ff);
+ if(i>16) { /* 2nd iteration needed, good to 118 */
+ t = r;
+ w = fn*pio2_2;
+ r = t-w;
+ w = fn*pio2_2t-((t-r)-w);
+ y[0] = r-w;
+ i = j-(((__HI(y[0]))>>20)&0x7ff);
+ if(i>49) { /* 3rd iteration need, 151 bits acc */
+ t = r; /* will cover all possible cases */
+ w = fn*pio2_3;
+ r = t-w;
+ w = fn*pio2_3t-((t-r)-w);
+ y[0] = r-w;
+ }
+ }
+ }
+ y[1] = (r-y[0])-w;
+ if(hx<0) {y[0] = -y[0]; y[1] = -y[1]; return -n;}
+ else return n;
+ }
+ /*
+ * all other (large) arguments
+ */
+ if(ix>=0x7ff00000) { /* x is inf or NaN */
+ y[0]=y[1]=x-x; return 0;
+ }
+ /* set z = scalbn(|x|,ilogb(x)-23) */
+ __LO(z) = __LO(x);
+ e0 = (ix>>20)-1046; /* e0 = ilogb(z)-23; */
+ __HI(z) = ix - (e0<<20);
+ for(i=0;i<2;i++) {
+ tx[i] = (double)((int)(z));
+ z = (z-tx[i])*two24;
+ }
+ tx[2] = z;
+ nx = 3;
+ while(tx[nx-1]==zero) nx--; /* skip zero term */
+ n = __kernel_rem_pio2(tx,y,e0,nx,2,two_over_pi);
+ if(hx<0) {y[0] = -y[0]; y[1] = -y[1]; return -n;}
+ return n;
+}
--- /dev/null
+++ b/libmath/fdlibm/e_remainder.c
@@ -1,0 +1,69 @@
+/* derived from /netlib/fdlibm */
+
+/* @(#)e_remainder.c 1.3 95/01/18 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunSoft, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+/* __ieee754_remainder(x,p)
+ * Return :
+ * returns x REM p = x - [x/p]*p as if in infinite
+ * precise arithmetic, where [x/p] is the (infinite bit)
+ * integer nearest x/p (in half way case choose the even one).
+ * Method :
+ * Based on fmod() return x-[x/p]chopped*p exactlp.
+ */
+
+#include "fdlibm.h"
+
+static const double zero = 0.0;
+
+
+ double __ieee754_remainder(double x, double p)
+{
+ int hx,hp;
+ unsigned sx,lx,lp;
+ double p_half;
+
+ hx = __HI(x); /* high word of x */
+ lx = __LO(x); /* low word of x */
+ hp = __HI(p); /* high word of p */
+ lp = __LO(p); /* low word of p */
+ sx = hx&0x80000000;
+ hp &= 0x7fffffff;
+ hx &= 0x7fffffff;
+
+ /* purge off exception values */
+ if((hp|lp)==0) return (x*p)/(x*p); /* p = 0 */
+ if((hx>=0x7ff00000)|| /* x not finite */
+ ((hp>=0x7ff00000)&& /* p is NaN */
+ (((hp-0x7ff00000)|lp)!=0)))
+ return (x*p)/(x*p);
+
+
+ if (hp<=0x7fdfffff) x = __ieee754_fmod(x,p+p); /* now x < 2p */
+ if (((hx-hp)|(lx-lp))==0) return zero*x;
+ x = fabs(x);
+ p = fabs(p);
+ if (hp<0x00200000) {
+ if(x+x>p) {
+ x-=p;
+ if(x+x>=p) x -= p;
+ }
+ } else {
+ p_half = 0.5*p;
+ if(x>p_half) {
+ x-=p;
+ if(x>=p_half) x -= p;
+ }
+ }
+ __HI(x) ^= sx;
+ return x;
+}
--- /dev/null
+++ b/libmath/fdlibm/e_sinh.c
@@ -1,0 +1,74 @@
+/* derived from /netlib/fdlibm */
+
+/* @(#)e_sinh.c 1.3 95/01/18 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunSoft, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+/* __ieee754_sinh(x)
+ * Method :
+ * mathematically sinh(x) if defined to be (exp(x)-exp(-x))/2
+ * 1. Replace x by |x| (sinh(-x) = -sinh(x)).
+ * 2.
+ * E + E/(E+1)
+ * 0 <= x <= 22 : sinh(x) := --------------, E=expm1(x)
+ * 2
+ *
+ * 22 <= x <= lnovft : sinh(x) := exp(x)/2
+ * lnovft <= x <= ln2ovft: sinh(x) := exp(x/2)/2 * exp(x/2)
+ * ln2ovft < x : sinh(x) := x*sHuge (overflow)
+ *
+ * Special cases:
+ * sinh(x) is |x| if x is +INF, -INF, or NaN.
+ * only sinh(0)=0 is exact for finite x.
+ */
+
+#include "fdlibm.h"
+
+static const double one = 1.0, sHuge = 1.0e307;
+
+ double __ieee754_sinh(double x)
+{
+ double t,w,h;
+ int ix,jx;
+ unsigned lx;
+
+ /* High word of |x|. */
+ jx = __HI(x);
+ ix = jx&0x7fffffff;
+
+ /* x is INF or NaN */
+ if(ix>=0x7ff00000) return x+x;
+
+ h = 0.5;
+ if (jx<0) h = -h;
+ /* |x| in [0,22], return sign(x)*0.5*(E+E/(E+1))) */
+ if (ix < 0x40360000) { /* |x|<22 */
+ if (ix<0x3e300000) /* |x|<2**-28 */
+ if(sHuge+x>one) return x;/* sinh(tiny) = tiny with inexact */
+ t = expm1(fabs(x));
+ if(ix<0x3ff00000) return h*(2.0*t-t*t/(t+one));
+ return h*(t+t/(t+one));
+ }
+
+ /* |x| in [22, log(maxdouble)] return 0.5*exp(|x|) */
+ if (ix < 0x40862E42) return h*__ieee754_exp(fabs(x));
+
+ /* |x| in [log(maxdouble), overflowthresold] */
+ lx = *( (((*(unsigned*)&one)>>29)) + (unsigned*)&x);
+ if (ix<0x408633CE || (ix==0x408633ce)&&(lx<=(unsigned)0x8fb9f87d)) {
+ w = __ieee754_exp(0.5*fabs(x));
+ t = h*w;
+ return t*w;
+ }
+
+ /* |x| > overflowthresold, sinh(x) overflow */
+ return x*sHuge;
+}
--- /dev/null
+++ b/libmath/fdlibm/e_sqrt.c
@@ -1,0 +1,442 @@
+/* derived from /netlib/fdlibm */
+/* @(#)e_sqrt.c 1.3 95/01/18 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunSoft, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+/* __ieee754_sqrt(x)
+ * Return correctly rounded sqrt.
+ * ------------------------------------------
+ * | Use the hardware sqrt if you have one |
+ * ------------------------------------------
+ * Method:
+ * Bit by bit method using integer arithmetic. (Slow, but portable)
+ * 1. Normalization
+ * Scale x to y in [1,4) with even powers of 2:
+ * find an integer k such that 1 <= (y=x*2^(2k)) < 4, then
+ * sqrt(x) = 2^k * sqrt(y)
+ * 2. Bit by bit computation
+ * Let q = sqrt(y) truncated to i bit after binary point (q = 1),
+ * i 0
+ * i+1 2
+ * s = 2*q , and y = 2 * ( y - q ). (1)
+ * i i i i
+ *
+ * To compute q from q , one checks whether
+ * i+1 i
+ *
+ * -(i+1) 2
+ * (q + 2 ) <= y. (2)
+ * i
+ * -(i+1)
+ * If (2) is false, then q = q ; otherwise q = q + 2 .
+ * i+1 i i+1 i
+ *
+ * With some algebric manipulation, it is not difficult to see
+ * that (2) is equivalent to
+ * -(i+1)
+ * s + 2 <= y (3)
+ * i i
+ *
+ * The advantage of (3) is that s and y can be computed by
+ * i i
+ * the following recurrence formula:
+ * if (3) is false
+ *
+ * s = s , y = y ; (4)
+ * i+1 i i+1 i
+ *
+ * otherwise,
+ * -i -(i+1)
+ * s = s + 2 , y = y - s - 2 (5)
+ * i+1 i i+1 i i
+ *
+ * One may easily use induction to prove (4) and (5).
+ * Note. Since the left hand side of (3) contain only i+2 bits,
+ * it does not necessary to do a full (53-bit) comparison
+ * in (3).
+ * 3. Final rounding
+ * After generating the 53 bits result, we compute one more bit.
+ * Together with the remainder, we can decide whether the
+ * result is exact, bigger than 1/2ulp, or less than 1/2ulp
+ * (it will never equal to 1/2ulp).
+ * The rounding mode can be detected by checking whether
+ * Huge + tiny is equal to Huge, and whether Huge - tiny is
+ * equal to Huge for some floating point number "Huge" and "tiny".
+ *
+ * Special cases:
+ * sqrt(+-0) = +-0 ... exact
+ * sqrt(inf) = inf
+ * sqrt(-ve) = NaN ... with invalid signal
+ * sqrt(NaN) = NaN ... with invalid signal for signaling NaN
+ *
+ * Other methods : see the appended file at the end of the program below.
+ *---------------
+ */
+
+#include "fdlibm.h"
+
+static const double one = 1.0, tiny=1.0e-300;
+
+ double __ieee754_sqrt(double x)
+{
+ double z;
+ int sign = (int)0x80000000;
+ unsigned r,t1,s1,ix1,q1;
+ int ix0,s0,q,m,t,i;
+
+ ix0 = __HI(x); /* high word of x */
+ ix1 = __LO(x); /* low word of x */
+
+ /* take care of Inf and NaN */
+ if((ix0&0x7ff00000)==0x7ff00000) {
+ return x*x+x; /* sqrt(NaN)=NaN, sqrt(+inf)=+inf
+ sqrt(-inf)=sNaN */
+ }
+ /* take care of zero */
+ if(ix0<=0) {
+ if(((ix0&(~sign))|ix1)==0) return x;/* sqrt(+-0) = +-0 */
+ else if(ix0<0)
+ return (x-x)/(x-x); /* sqrt(-ve) = sNaN */
+ }
+ /* normalize x */
+ m = (ix0>>20);
+ if(m==0) { /* subnormal x */
+ while(ix0==0) {
+ m -= 21;
+ ix0 |= (ix1>>11); ix1 <<= 21;
+ }
+ for(i=0;(ix0&0x00100000)==0;i++) ix0<<=1;
+ m -= i-1;
+ ix0 |= (ix1>>(32-i));
+ ix1 <<= i;
+ }
+ m -= 1023; /* unbias exponent */
+ ix0 = (ix0&0x000fffff)|0x00100000;
+ if(m&1){ /* odd m, double x to make it even */
+ ix0 += ix0 + ((ix1&sign)>>31);
+ ix1 += ix1;
+ }
+ m >>= 1; /* m = [m/2] */
+
+ /* generate sqrt(x) bit by bit */
+ ix0 += ix0 + ((ix1&sign)>>31);
+ ix1 += ix1;
+ q = q1 = s0 = s1 = 0; /* [q,q1] = sqrt(x) */
+ r = 0x00200000; /* r = moving bit from right to left */
+
+ while(r!=0) {
+ t = s0+r;
+ if(t<=ix0) {
+ s0 = t+r;
+ ix0 -= t;
+ q += r;
+ }
+ ix0 += ix0 + ((ix1&sign)>>31);
+ ix1 += ix1;
+ r>>=1;
+ }
+
+ r = sign;
+ while(r!=0) {
+ t1 = s1+r;
+ t = s0;
+ if((t<ix0)||((t==ix0)&&(t1<=ix1))) {
+ s1 = t1+r;
+ if(((t1&sign)==sign)&&(s1&sign)==0) s0 += 1;
+ ix0 -= t;
+ if (ix1 < t1) ix0 -= 1;
+ ix1 -= t1;
+ q1 += r;
+ }
+ ix0 += ix0 + ((ix1&sign)>>31);
+ ix1 += ix1;
+ r>>=1;
+ }
+
+ /* use floating add to find out rounding direction */
+ if((ix0|ix1)!=0) {
+ z = one-tiny; /* trigger inexact flag */
+ if (z>=one) {
+ z = one+tiny;
+ if (q1==(unsigned)0xffffffff) { q1=0; q += 1;}
+ else if (z>one) {
+ if (q1==(unsigned)0xfffffffe) q+=1;
+ q1+=2;
+ } else
+ q1 += (q1&1);
+ }
+ }
+ ix0 = (q>>1)+0x3fe00000;
+ ix1 = q1>>1;
+ if ((q&1)==1) ix1 |= sign;
+ ix0 += (m <<20);
+ __HI(z) = ix0;
+ __LO(z) = ix1;
+ return z;
+}
+
+/*
+Other methods (use floating-point arithmetic)
+-------------
+(This is a copy of a drafted paper by Prof W. Kahan
+and K.C. Ng, written in May, 1986)
+
+ Two algorithms are given here to implement sqrt(x)
+ (IEEE double precision arithmetic) in software.
+ Both supply sqrt(x) correctly rounded. The first algorithm (in
+ Section A) uses newton iterations and involves four divisions.
+ The second one uses reciproot iterations to avoid division, but
+ requires more multiplications. Both algorithms need the ability
+ to chop results of arithmetic operations instead of round them,
+ and the INEXACT flag to indicate when an arithmetic operation
+ is executed exactly with no roundoff error, all part of the
+ standard (IEEE 754-1985). The ability to perform shift, add,
+ subtract and logical AND operations upon 32-bit words is needed
+ too, though not part of the standard.
+
+A. sqrt(x) by Newton Iteration
+
+ (1) Initial approximation
+
+ Let x0 and x1 be the leading and the trailing 32-bit words of
+ a floating point number x (in IEEE double format) respectively
+
+ 1 11 52 ...widths
+ ------------------------------------------------------
+ x: |s| e | f |
+ ------------------------------------------------------
+ msb lsb msb lsb ...order
+
+
+ ------------------------ ------------------------
+ x0: |s| e | f1 | x1: | f2 |
+ ------------------------ ------------------------
+
+ By performing shifts and subtracts on x0 and x1 (both regarded
+ as integers), we obtain an 8-bit approximation of sqrt(x) as
+ follows.
+
+ k := (x0>>1) + 0x1ff80000;
+ y0 := k - T1[31&(k>>15)]. ... y ~ sqrt(x) to 8 bits
+ Here k is a 32-bit integer and T1[] is an integer array containing
+ correction terms. Now magically the floating value of y (y's
+ leading 32-bit word is y0, the value of its trailing word is 0)
+ approximates sqrt(x) to almost 8-bit.
+
+ Value of T1:
+ static int T1[32]= {
+ 0, 1024, 3062, 5746, 9193, 13348, 18162, 23592,
+ 29598, 36145, 43202, 50740, 58733, 67158, 75992, 85215,
+ 83599, 71378, 60428, 50647, 41945, 34246, 27478, 21581,
+ 16499, 12183, 8588, 5674, 3403, 1742, 661, 130,};
+
+ (2) Iterative refinement
+
+ Apply Heron's rule three times to y, we have y approximates
+ sqrt(x) to within 1 ulp (Unit in the Last Place):
+
+ y := (y+x/y)/2 ... almost 17 sig. bits
+ y := (y+x/y)/2 ... almost 35 sig. bits
+ y := y-(y-x/y)/2 ... within 1 ulp
+
+
+ Remark 1.
+ Another way to improve y to within 1 ulp is:
+
+ y := (y+x/y) ... almost 17 sig. bits to 2*sqrt(x)
+ y := y - 0x00100006 ... almost 18 sig. bits to sqrt(x)
+
+ 2
+ (x-y )*y
+ y := y + 2* ---------- ...within 1 ulp
+ 2
+ 3y + x
+
+
+ This formula has one division fewer than the one above; however,
+ it requires more multiplications and additions. Also x must be
+ scaled in advance to avoid spurious overflow in evaluating the
+ expression 3y*y+x. Hence it is not recommended uless division
+ is slow. If division is very slow, then one should use the
+ reciproot algorithm given in section B.
+
+ (3) Final adjustment
+
+ By twiddling y's last bit it is possible to force y to be
+ correctly rounded according to the prevailing rounding mode
+ as follows. Let r and i be copies of the rounding mode and
+ inexact flag before entering the square root program. Also we
+ use the expression y+-ulp for the next representable floating
+ numbers (up and down) of y. Note that y+-ulp = either fixed
+ point y+-1, or multiply y by nextafter(1,+-inf) in chopped
+ mode.
+
+ I := FALSE; ... reset INEXACT flag I
+ R := RZ; ... set rounding mode to round-toward-zero
+ z := x/y; ... chopped quotient, possibly inexact
+ If(not I) then { ... if the quotient is exact
+ if(z=y) {
+ I := i; ... restore inexact flag
+ R := r; ... restore rounded mode
+ return sqrt(x):=y.
+ } else {
+ z := z - ulp; ... special rounding
+ }
+ }
+ i := TRUE; ... sqrt(x) is inexact
+ If (r=RN) then z=z+ulp ... rounded-to-nearest
+ If (r=RP) then { ... round-toward-+inf
+ y = y+ulp; z=z+ulp;
+ }
+ y := y+z; ... chopped sum
+ y0:=y0-0x00100000; ... y := y/2 is correctly rounded.
+ I := i; ... restore inexact flag
+ R := r; ... restore rounded mode
+ return sqrt(x):=y.
+
+ (4) Special cases
+
+ Square root of +inf, +-0, or NaN is itself;
+ Square root of a negative number is NaN with invalid signal.
+
+
+B. sqrt(x) by Reciproot Iteration
+
+ (1) Initial approximation
+
+ Let x0 and x1 be the leading and the trailing 32-bit words of
+ a floating point number x (in IEEE double format) respectively
+ (see section A). By performing shifs and subtracts on x0 and y0,
+ we obtain a 7.8-bit approximation of 1/sqrt(x) as follows.
+
+ k := 0x5fe80000 - (x0>>1);
+ y0:= k - T2[63&(k>>14)]. ... y ~ 1/sqrt(x) to 7.8 bits
+
+ Here k is a 32-bit integer and T2[] is an integer array
+ containing correction terms. Now magically the floating
+ value of y (y's leading 32-bit word is y0, the value of
+ its trailing word y1 is set to zero) approximates 1/sqrt(x)
+ to almost 7.8-bit.
+
+ Value of T2:
+ static int T2[64]= {
+ 0x1500, 0x2ef8, 0x4d67, 0x6b02, 0x87be, 0xa395, 0xbe7a, 0xd866,
+ 0xf14a, 0x1091b,0x11fcd,0x13552,0x14999,0x15c98,0x16e34,0x17e5f,
+ 0x18d03,0x19a01,0x1a545,0x1ae8a,0x1b5c4,0x1bb01,0x1bfde,0x1c28d,
+ 0x1c2de,0x1c0db,0x1ba73,0x1b11c,0x1a4b5,0x1953d,0x18266,0x16be0,
+ 0x1683e,0x179d8,0x18a4d,0x19992,0x1a789,0x1b445,0x1bf61,0x1c989,
+ 0x1d16d,0x1d77b,0x1dddf,0x1e2ad,0x1e5bf,0x1e6e8,0x1e654,0x1e3cd,
+ 0x1df2a,0x1d635,0x1cb16,0x1be2c,0x1ae4e,0x19bde,0x1868e,0x16e2e,
+ 0x1527f,0x1334a,0x11051,0xe951, 0xbe01, 0x8e0d, 0x5924, 0x1edd,};
+
+ (2) Iterative refinement
+
+ Apply Reciproot iteration three times to y and multiply the
+ result by x to get an approximation z that matches sqrt(x)
+ to about 1 ulp. To be exact, we will have
+ -1ulp < sqrt(x)-z<1.0625ulp.
+
+ ... set rounding mode to Round-to-nearest
+ y := y*(1.5-0.5*x*y*y) ... almost 15 sig. bits to 1/sqrt(x)
+ y := y*((1.5-2^-30)+0.5*x*y*y)... about 29 sig. bits to 1/sqrt(x)
+ ... special arrangement for better accuracy
+ z := x*y ... 29 bits to sqrt(x), with z*y<1
+ z := z + 0.5*z*(1-z*y) ... about 1 ulp to sqrt(x)
+
+ Remark 2. The constant 1.5-2^-30 is chosen to bias the error so that
+ (a) the term z*y in the final iteration is always less than 1;
+ (b) the error in the final result is biased upward so that
+ -1 ulp < sqrt(x) - z < 1.0625 ulp
+ instead of |sqrt(x)-z|<1.03125ulp.
+
+ (3) Final adjustment
+
+ By twiddling y's last bit it is possible to force y to be
+ correctly rounded according to the prevailing rounding mode
+ as follows. Let r and i be copies of the rounding mode and
+ inexact flag before entering the square root program. Also we
+ use the expression y+-ulp for the next representable floating
+ numbers (up and down) of y. Note that y+-ulp = either fixed
+ point y+-1, or multiply y by nextafter(1,+-inf) in chopped
+ mode.
+
+ R := RZ; ... set rounding mode to round-toward-zero
+ switch(r) {
+ case RN: ... round-to-nearest
+ if(x<= z*(z-ulp)...chopped) z = z - ulp; else
+ if(x<= z*(z+ulp)...chopped) z = z; else z = z+ulp;
+ break;
+ case RZ:case RM: ... round-to-zero or round-to--inf
+ R:=RP; ... reset rounding mod to round-to-+inf
+ if(x<z*z ... rounded up) z = z - ulp; else
+ if(x>=(z+ulp)*(z+ulp) ...rounded up) z = z+ulp;
+ break;
+ case RP: ... round-to-+inf
+ if(x>(z+ulp)*(z+ulp)...chopped) z = z+2*ulp; else
+ if(x>z*z ...chopped) z = z+ulp;
+ break;
+ }
+
+ Remark 3. The above comparisons can be done in fixed point. For
+ example, to compare x and w=z*z chopped, it suffices to compare
+ x1 and w1 (the trailing parts of x and w), regarding them as
+ two's complement integers.
+
+ ...Is z an exact square root?
+ To determine whether z is an exact square root of x, let z1 be the
+ trailing part of z, and also let x0 and x1 be the leading and
+ trailing parts of x.
+
+ If ((z1&0x03ffffff)!=0) ... not exact if trailing 26 bits of z!=0
+ I := 1; ... Raise Inexact flag: z is not exact
+ else {
+ j := 1 - [(x0>>20)&1] ... j = logb(x) mod 2
+ k := z1 >> 26; ... get z's 25-th and 26-th
+ fraction bits
+ I := i or (k&j) or ((k&(j+j+1))!=(x1&3));
+ }
+ R:= r ... restore rounded mode
+ return sqrt(x):=z.
+
+ If multiplication is cheaper then the foregoing red tape, the
+ Inexact flag can be evaluated by
+
+ I := i;
+ I := (z*z!=x) or I.
+
+ Note that z*z can overwrite I; this value must be sensed if it is
+ True.
+
+ Remark 4. If z*z = x exactly, then bit 25 to bit 0 of z1 must be
+ zero.
+
+ --------------------
+ z1: | f2 |
+ --------------------
+ bit 31 bit 0
+
+ Further more, bit 27 and 26 of z1, bit 0 and 1 of x1, and the odd
+ or even of logb(x) have the following relations:
+
+ -------------------------------------------------
+ bit 27,26 of z1 bit 1,0 of x1 logb(x)
+ -------------------------------------------------
+ 00 00 odd and even
+ 01 01 even
+ 10 10 odd
+ 10 00 even
+ 11 01 even
+ -------------------------------------------------
+
+ (4) Special cases (see (4) of Section A).
+
+ */
+
--- /dev/null
+++ b/libmath/fdlibm/fdlibm.h
@@ -1,0 +1,150 @@
+/* derived from /netlib/fdlibm */
+#include "lib9.h"
+
+/* @(#)fdlibm.h 1.5 95/01/18 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunSoft, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+
+#ifdef USE_FPdbleword
+#define __HI(x) ((FPdbleword*)&x)->hi
+#define __LO(x) ((FPdbleword*)&x)->lo
+#define __HIp(x) ((FPdbleword*)x)->hi
+#define __LOp(x) ((FPdbleword*)x)->lo
+#else
+#ifdef __LITTLE_ENDIAN
+#define __HI(x) *(1+(int*)&x)
+#define __LO(x) *(int*)&x
+#define __HIp(x) *(1+(int*)x)
+#define __LOp(x) *(int*)x
+#else
+#define __HI(x) *(int*)&x
+#define __LO(x) *(1+(int*)&x)
+#define __HIp(x) *(int*)x
+#define __LOp(x) *(1+(int*)x)
+#endif
+#endif
+
+/*
+ * ANSI/POSIX
+ */
+extern double acos(double);
+extern double asin(double);
+extern double atan(double);
+extern double atan2(double, double);
+extern double cos(double);
+extern double sin(double);
+extern double tan(double);
+
+extern double cosh(double);
+extern double sinh(double);
+extern double tanh(double);
+
+extern double exp(double);
+extern double frexp(double, int *);
+extern double ldexp(double, int);
+extern double log(double);
+extern double log10(double);
+extern double modf(double, double *);
+
+extern double pow(double, double);
+extern double sqrt(double);
+
+extern double ceil(double);
+extern double fabs(double);
+extern double floor(double);
+extern double fmod(double, double);
+
+extern double erf(double);
+extern double erfc(double);
+extern double gamma(double);
+extern double hypot(double, double);
+extern int finite(double);
+extern double j0(double);
+extern double j1(double);
+extern double jn(int, double);
+extern double lgamma(double);
+extern double y0(double);
+extern double y1(double);
+extern double yn(int, double);
+
+extern double acosh(double);
+extern double asinh(double);
+extern double atanh(double);
+extern double cbrt(double);
+extern double logb(double);
+extern double nextafter(double, double);
+extern double remainder(double, double);
+extern double scalb(double, double);
+
+/*
+ * IEEE Test Vector
+ */
+extern double significand(double);
+
+/*
+ * Functions callable from C, intended to support IEEE arithmetic.
+ */
+extern double copysign(double, double);
+extern int ilogb(double);
+extern double rint(double);
+extern double scalbn(double, int);
+
+/*
+ * BSD math library entry points
+ */
+extern double expm1(double);
+extern double log1p(double);
+
+/*
+ * Reentrant version of gamma & lgamma; passes signgam back by reference
+ * as the second argument; user must allocate space for signgam.
+ */
+#ifdef _REENTRANT
+extern double gamma_r(double, int *);
+extern double lgamma_r(double, int *);
+#endif /* _REENTRANT */
+
+/* ieee style elementary functions */
+extern double __ieee754_sqrt(double);
+extern double __ieee754_acos(double);
+extern double __ieee754_acosh(double);
+extern double __ieee754_log(double);
+extern double __ieee754_atanh(double);
+extern double __ieee754_asin(double);
+extern double __ieee754_atan2(double,double);
+extern double __ieee754_exp(double);
+extern double __ieee754_cosh(double);
+extern double __ieee754_fmod(double,double);
+extern double __ieee754_pow(double,double);
+extern double __ieee754_lgamma_r(double,int *);
+extern double __ieee754_gamma_r(double,int *);
+extern double __ieee754_lgamma(double);
+extern double __ieee754_gamma(double);
+extern double __ieee754_log10(double);
+extern double __ieee754_sinh(double);
+extern double __ieee754_hypot(double,double);
+extern double __ieee754_j0(double);
+extern double __ieee754_j1(double);
+extern double __ieee754_y0(double);
+extern double __ieee754_y1(double);
+extern double __ieee754_jn(int,double);
+extern double __ieee754_yn(int,double);
+extern double __ieee754_remainder(double,double);
+extern int __ieee754_rem_pio2(double,double*);
+extern double __ieee754_scalb(double,int);
+
+/* fdlibm kernel function */
+extern double __kernel_standard(double,double,int);
+extern double __kernel_sin(double,double,int);
+extern double __kernel_cos(double,double);
+extern double __kernel_tan(double,double,int);
+extern int __kernel_rem_pio2(double*,double*,int,int,int,const int*);
--- /dev/null
+++ b/libmath/fdlibm/k_cos.c
@@ -1,0 +1,84 @@
+/* derived from /netlib/fdlibm */
+
+/* @(#)k_cos.c 1.3 95/01/18 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunSoft, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+/*
+ * __kernel_cos( x, y )
+ * kernel cos function on [-pi/4, pi/4], pi/4 ~ 0.785398164
+ * Input x is assumed to be bounded by ~pi/4 in magnitude.
+ * Input y is the tail of x.
+ *
+ * Algorithm
+ * 1. Since cos(-x) = cos(x), we need only to consider positive x.
+ * 2. if x < 2^-27 (hx<0x3e400000 0), return 1 with inexact if x!=0.
+ * 3. cos(x) is approximated by a polynomial of degree 14 on
+ * [0,pi/4]
+ * 4 14
+ * cos(x) ~ 1 - x*x/2 + C1*x + ... + C6*x
+ * where the remez error is
+ *
+ * | 2 4 6 8 10 12 14 | -58
+ * |cos(x)-(1-.5*x +C1*x +C2*x +C3*x +C4*x +C5*x +C6*x )| <= 2
+ * | |
+ *
+ * 4 6 8 10 12 14
+ * 4. let r = C1*x +C2*x +C3*x +C4*x +C5*x +C6*x , then
+ * cos(x) = 1 - x*x/2 + r
+ * since cos(x+y) ~ cos(x) - sin(x)*y
+ * ~ cos(x) - x*y,
+ * a correction term is necessary in cos(x) and hence
+ * cos(x+y) = 1 - (x*x/2 - (r - x*y))
+ * For better accuracy when x > 0.3, let qx = |x|/4 with
+ * the last 32 bits mask off, and if x > 0.78125, let qx = 0.28125.
+ * Then
+ * cos(x+y) = (1-qx) - ((x*x/2-qx) - (r-x*y)).
+ * Note that 1-qx and (x*x/2-qx) is EXACT here, and the
+ * magnitude of the latter is at least a quarter of x*x/2,
+ * thus, reducing the rounding error in the subtraction.
+ */
+
+#include "fdlibm.h"
+
+static const double
+one = 1.00000000000000000000e+00, /* 0x3FF00000, 0x00000000 */
+C1 = 4.16666666666666019037e-02, /* 0x3FA55555, 0x5555554C */
+C2 = -1.38888888888741095749e-03, /* 0xBF56C16C, 0x16C15177 */
+C3 = 2.48015872894767294178e-05, /* 0x3EFA01A0, 0x19CB1590 */
+C4 = -2.75573143513906633035e-07, /* 0xBE927E4F, 0x809C52AD */
+C5 = 2.08757232129817482790e-09, /* 0x3E21EE9E, 0xBDB4B1C4 */
+C6 = -1.13596475577881948265e-11; /* 0xBDA8FAE9, 0xBE8838D4 */
+
+ double __kernel_cos(double x, double y)
+{
+ double a,hz,z,r,qx;
+ int ix;
+ ix = __HI(x)&0x7fffffff; /* ix = |x|'s high word*/
+ if(ix<0x3e400000) { /* if x < 2**27 */
+ if(((int)x)==0) return one; /* generate inexact */
+ }
+ z = x*x;
+ r = z*(C1+z*(C2+z*(C3+z*(C4+z*(C5+z*C6)))));
+ if(ix < 0x3FD33333) /* if |x| < 0.3 */
+ return one - (0.5*z - (z*r - x*y));
+ else {
+ if(ix > 0x3fe90000) { /* x > 0.78125 */
+ qx = 0.28125;
+ } else {
+ __HI(qx) = ix-0x00200000; /* x/4 */
+ __LO(qx) = 0;
+ }
+ hz = 0.5*z-qx;
+ a = one-qx;
+ return a - (hz - (z*r-x*y));
+ }
+}
--- /dev/null
+++ b/libmath/fdlibm/k_rem_pio2.c
@@ -1,0 +1,300 @@
+/* derived from /netlib/fdlibm */
+
+/* @(#)k_rem_pio2.c 1.3 95/01/18 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunSoft, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+/*
+ * __kernel_rem_pio2(x,y,e0,nx,prec,ipio2)
+ * double x[],y[]; int e0,nx,prec; int ipio2[];
+ *
+ * __kernel_rem_pio2 return the last three digits of N with
+ * y = x - N*pi/2
+ * so that |y| < pi/2.
+ *
+ * The method is to compute the integer (mod 8) and fraction parts of
+ * (2/pi)*x without doing the full multiplication. In general we
+ * skip the part of the product that are known to be a Huge integer (
+ * more accurately, = 0 mod 8 ). Thus the number of operations are
+ * independent of the exponent of the input.
+ *
+ * (2/pi) is represented by an array of 24-bit integers in ipio2[].
+ *
+ * Input parameters:
+ * x[] The input value (must be positive) is broken into nx
+ * pieces of 24-bit integers in double precision format.
+ * x[i] will be the i-th 24 bit of x. The scaled exponent
+ * of x[0] is given in input parameter e0 (i.e., x[0]*2^e0
+ * match x's up to 24 bits.
+ *
+ * Example of breaking a double positive z into x[0]+x[1]+x[2]:
+ * e0 = ilogb(z)-23
+ * z = scalbn(z,-e0)
+ * for i = 0,1,2
+ * x[i] = floor(z)
+ * z = (z-x[i])*2**24
+ *
+ *
+ * y[] ouput result in an array of double precision numbers.
+ * The dimension of y[] is:
+ * 24-bit precision 1
+ * 53-bit precision 2
+ * 64-bit precision 2
+ * 113-bit precision 3
+ * The actual value is the sum of them. Thus for 113-bit
+ * precison, one may have to do something like:
+ *
+ * long double t,w,r_head, r_tail;
+ * t = (long double)y[2] + (long double)y[1];
+ * w = (long double)y[0];
+ * r_head = t+w;
+ * r_tail = w - (r_head - t);
+ *
+ * e0 The exponent of x[0]
+ *
+ * nx dimension of x[]
+ *
+ * prec an integer indicating the precision:
+ * 0 24 bits (single)
+ * 1 53 bits (double)
+ * 2 64 bits (extended)
+ * 3 113 bits (quad)
+ *
+ * ipio2[]
+ * integer array, contains the (24*i)-th to (24*i+23)-th
+ * bit of 2/pi after binary point. The corresponding
+ * floating value is
+ *
+ * ipio2[i] * 2^(-24(i+1)).
+ *
+ * External function:
+ * double scalbn(), floor();
+ *
+ *
+ * Here is the description of some local variables:
+ *
+ * jk jk+1 is the initial number of terms of ipio2[] needed
+ * in the computation. The recommended value is 2,3,4,
+ * 6 for single, double, extended,and quad.
+ *
+ * jz local integer variable indicating the number of
+ * terms of ipio2[] used.
+ *
+ * jx nx - 1
+ *
+ * jv index for pointing to the suitable ipio2[] for the
+ * computation. In general, we want
+ * ( 2^e0*x[0] * ipio2[jv-1]*2^(-24jv) )/8
+ * is an integer. Thus
+ * e0-3-24*jv >= 0 or (e0-3)/24 >= jv
+ * Hence jv = max(0,(e0-3)/24).
+ *
+ * jp jp+1 is the number of terms in PIo2[] needed, jp = jk.
+ *
+ * q[] double array with integral value, representing the
+ * 24-bits chunk of the product of x and 2/pi.
+ *
+ * q0 the corresponding exponent of q[0]. Note that the
+ * exponent for q[i] would be q0-24*i.
+ *
+ * PIo2[] double precision array, obtained by cutting pi/2
+ * into 24 bits chunks.
+ *
+ * f[] ipio2[] in floating point
+ *
+ * iq[] integer array by breaking up q[] in 24-bits chunk.
+ *
+ * fq[] final product of x*(2/pi) in fq[0],..,fq[jk]
+ *
+ * ih integer. If >0 it indicates q[] is >= 0.5, hence
+ * it also indicates the *sign* of the result.
+ *
+ */
+
+
+/*
+ * Constants:
+ * The hexadecimal values are the intended ones for the following
+ * constants. The decimal values may be used, provided that the
+ * compiler will convert from decimal to binary accurately enough
+ * to produce the hexadecimal values shown.
+ */
+
+#include "fdlibm.h"
+
+static const int init_jk[] = {2,3,4,6}; /* initial value for jk */
+
+static const double PIo2[] = {
+ 1.57079625129699707031e+00, /* 0x3FF921FB, 0x40000000 */
+ 7.54978941586159635335e-08, /* 0x3E74442D, 0x00000000 */
+ 5.39030252995776476554e-15, /* 0x3CF84698, 0x80000000 */
+ 3.28200341580791294123e-22, /* 0x3B78CC51, 0x60000000 */
+ 1.27065575308067607349e-29, /* 0x39F01B83, 0x80000000 */
+ 1.22933308981111328932e-36, /* 0x387A2520, 0x40000000 */
+ 2.73370053816464559624e-44, /* 0x36E38222, 0x80000000 */
+ 2.16741683877804819444e-51, /* 0x3569F31D, 0x00000000 */
+};
+
+static const double
+zero = 0.0,
+one = 1.0,
+two24 = 1.67772160000000000000e+07, /* 0x41700000, 0x00000000 */
+twon24 = 5.96046447753906250000e-08; /* 0x3E700000, 0x00000000 */
+
+ int __kernel_rem_pio2(double *x, double *y, int e0, int nx, int prec, const int *ipio2)
+{
+ int jz,jx,jv,jp,jk,carry,n,iq[20],i,j,k,m,q0,ih;
+ double z,fw,f[20],fq[20],q[20];
+
+ /* initialize jk*/
+ jk = init_jk[prec];
+ jp = jk;
+
+ /* determine jx,jv,q0, note that 3>q0 */
+ jx = nx-1;
+ jv = (e0-3)/24; if(jv<0) jv=0;
+ q0 = e0-24*(jv+1);
+
+ /* set up f[0] to f[jx+jk] where f[jx+jk] = ipio2[jv+jk] */
+ j = jv-jx; m = jx+jk;
+ for(i=0;i<=m;i++,j++) f[i] = (j<0)? zero : (double) ipio2[j];
+
+ /* compute q[0],q[1],...q[jk] */
+ for (i=0;i<=jk;i++) {
+ for(j=0,fw=0.0;j<=jx;j++) fw += x[j]*f[jx+i-j]; q[i] = fw;
+ }
+
+ jz = jk;
+recompute:
+ /* distill q[] into iq[] reversingly */
+ for(i=0,j=jz,z=q[jz];j>0;i++,j--) {
+ fw = (double)((int)(twon24* z));
+ iq[i] = (int)(z-two24*fw);
+ z = q[j-1]+fw;
+ }
+
+ /* compute n */
+ z = scalbn(z,q0); /* actual value of z */
+ z -= 8.0*floor(z*0.125); /* trim off integer >= 8 */
+ n = (int) z;
+ z -= (double)n;
+ ih = 0;
+ if(q0>0) { /* need iq[jz-1] to determine n */
+ i = (iq[jz-1]>>(24-q0)); n += i;
+ iq[jz-1] -= i<<(24-q0);
+ ih = iq[jz-1]>>(23-q0);
+ }
+ else if(q0==0) ih = iq[jz-1]>>23;
+ else if(z>=0.5) ih=2;
+
+ if(ih>0) { /* q > 0.5 */
+ n += 1; carry = 0;
+ for(i=0;i<jz ;i++) { /* compute 1-q */
+ j = iq[i];
+ if(carry==0) {
+ if(j!=0) {
+ carry = 1; iq[i] = 0x1000000- j;
+ }
+ } else iq[i] = 0xffffff - j;
+ }
+ if(q0>0) { /* rare case: chance is 1 in 12 */
+ switch(q0) {
+ case 1:
+ iq[jz-1] &= 0x7fffff; break;
+ case 2:
+ iq[jz-1] &= 0x3fffff; break;
+ }
+ }
+ if(ih==2) {
+ z = one - z;
+ if(carry!=0) z -= scalbn(one,q0);
+ }
+ }
+
+ /* check if recomputation is needed */
+ if(z==zero) {
+ j = 0;
+ for (i=jz-1;i>=jk;i--) j |= iq[i];
+ if(j==0) { /* need recomputation */
+ for(k=1;iq[jk-k]==0;k++); /* k = no. of terms needed */
+
+ for(i=jz+1;i<=jz+k;i++) { /* add q[jz+1] to q[jz+k] */
+ f[jx+i] = (double) ipio2[jv+i];
+ for(j=0,fw=0.0;j<=jx;j++) fw += x[j]*f[jx+i-j];
+ q[i] = fw;
+ }
+ jz += k;
+ goto recompute;
+ }
+ }
+
+ /* chop off zero terms */
+ if(z==0.0) {
+ jz -= 1; q0 -= 24;
+ while(iq[jz]==0) { jz--; q0-=24;}
+ } else { /* break z into 24-bit if necessary */
+ z = scalbn(z,-q0);
+ if(z>=two24) {
+ fw = (double)((int)(twon24*z));
+ iq[jz] = (int)(z-two24*fw);
+ jz += 1; q0 += 24;
+ iq[jz] = (int) fw;
+ } else iq[jz] = (int) z ;
+ }
+
+ /* convert integer "bit" chunk to floating-point value */
+ fw = scalbn(one,q0);
+ for(i=jz;i>=0;i--) {
+ q[i] = fw*(double)iq[i]; fw*=twon24;
+ }
+
+ /* compute PIo2[0,...,jp]*q[jz,...,0] */
+ for(i=jz;i>=0;i--) {
+ for(fw=0.0,k=0;k<=jp&&k<=jz-i;k++) fw += PIo2[k]*q[i+k];
+ fq[jz-i] = fw;
+ }
+
+ /* compress fq[] into y[] */
+ switch(prec) {
+ case 0:
+ fw = 0.0;
+ for (i=jz;i>=0;i--) fw += fq[i];
+ y[0] = (ih==0)? fw: -fw;
+ break;
+ case 1:
+ case 2:
+ fw = 0.0;
+ for (i=jz;i>=0;i--) fw += fq[i];
+ y[0] = (ih==0)? fw: -fw;
+ fw = fq[0]-fw;
+ for (i=1;i<=jz;i++) fw += fq[i];
+ y[1] = (ih==0)? fw: -fw;
+ break;
+ case 3: /* painful */
+ for (i=jz;i>0;i--) {
+ fw = fq[i-1]+fq[i];
+ fq[i] += fq[i-1]-fw;
+ fq[i-1] = fw;
+ }
+ for (i=jz;i>1;i--) {
+ fw = fq[i-1]+fq[i];
+ fq[i] += fq[i-1]-fw;
+ fq[i-1] = fw;
+ }
+ for (fw=0.0,i=jz;i>=2;i--) fw += fq[i];
+ if(ih==0) {
+ y[0] = fq[0]; y[1] = fq[1]; y[2] = fw;
+ } else {
+ y[0] = -fq[0]; y[1] = -fq[1]; y[2] = -fw;
+ }
+ }
+ return n&7;
+}
--- /dev/null
+++ b/libmath/fdlibm/k_sin.c
@@ -1,0 +1,66 @@
+/* derived from /netlib/fdlibm */
+
+/* @(#)k_sin.c 1.3 95/01/18 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunSoft, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+/* __kernel_sin( x, y, iy)
+ * kernel sin function on [-pi/4, pi/4], pi/4 ~ 0.7854
+ * Input x is assumed to be bounded by ~pi/4 in magnitude.
+ * Input y is the tail of x.
+ * Input iy indicates whether y is 0. (if iy=0, y assume to be 0).
+ *
+ * Algorithm
+ * 1. Since sin(-x) = -sin(x), we need only to consider positive x.
+ * 2. if x < 2^-27 (hx<0x3e400000 0), return x with inexact if x!=0.
+ * 3. sin(x) is approximated by a polynomial of degree 13 on
+ * [0,pi/4]
+ * 3 13
+ * sin(x) ~ x + S1*x + ... + S6*x
+ * where
+ *
+ * |sin(x) 2 4 6 8 10 12 | -58
+ * |----- - (1+S1*x +S2*x +S3*x +S4*x +S5*x +S6*x )| <= 2
+ * | x |
+ *
+ * 4. sin(x+y) = sin(x) + sin'(x')*y
+ * ~ sin(x) + (1-x*x/2)*y
+ * For better accuracy, let
+ * 3 2 2 2 2
+ * r = x *(S2+x *(S3+x *(S4+x *(S5+x *S6))))
+ * then 3 2
+ * sin(x) = x + (S1*x + (x *(r-y/2)+y))
+ */
+
+#include "fdlibm.h"
+
+static const double
+half = 5.00000000000000000000e-01, /* 0x3FE00000, 0x00000000 */
+S1 = -1.66666666666666324348e-01, /* 0xBFC55555, 0x55555549 */
+S2 = 8.33333333332248946124e-03, /* 0x3F811111, 0x1110F8A6 */
+S3 = -1.98412698298579493134e-04, /* 0xBF2A01A0, 0x19C161D5 */
+S4 = 2.75573137070700676789e-06, /* 0x3EC71DE3, 0x57B1FE7D */
+S5 = -2.50507602534068634195e-08, /* 0xBE5AE5E6, 0x8A2B9CEB */
+S6 = 1.58969099521155010221e-10; /* 0x3DE5D93A, 0x5ACFD57C */
+
+ double __kernel_sin(double x, double y, int iy)
+{
+ double z,r,v;
+ int ix;
+ ix = __HI(x)&0x7fffffff; /* high word of x */
+ if(ix<0x3e400000) /* |x| < 2**-27 */
+ {if((int)x==0) return x;} /* generate inexact */
+ z = x*x;
+ v = z*x;
+ r = S2+z*(S3+z*(S4+z*(S5+z*S6)));
+ if(iy==0) return x+v*(S1+z*r);
+ else return x-((z*(half*y-v*r)-y)-v*S1);
+}
--- /dev/null
+++ b/libmath/fdlibm/k_tan.c
@@ -1,0 +1,117 @@
+/* derived from /netlib/fdlibm */
+
+/* @(#)k_tan.c 1.3 95/01/18 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunSoft, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+/* __kernel_tan( x, y, k )
+ * kernel tan function on [-pi/4, pi/4], pi/4 ~ 0.7854
+ * Input x is assumed to be bounded by ~pi/4 in magnitude.
+ * Input y is the tail of x.
+ * Input k indicates whether tan (if k=1) or
+ * -1/tan (if k= -1) is returned.
+ *
+ * Algorithm
+ * 1. Since tan(-x) = -tan(x), we need only to consider positive x.
+ * 2. if x < 2^-28 (hx<0x3e300000 0), return x with inexact if x!=0.
+ * 3. tan(x) is approximated by a odd polynomial of degree 27 on
+ * [0,0.67434]
+ * 3 27
+ * tan(x) ~ x + T1*x + ... + T13*x
+ * where
+ *
+ * |tan(x) 2 4 26 | -59.2
+ * |----- - (1+T1*x +T2*x +.... +T13*x )| <= 2
+ * | x |
+ *
+ * Note: tan(x+y) = tan(x) + tan'(x)*y
+ * ~ tan(x) + (1+x*x)*y
+ * Therefore, for better accuracy in computing tan(x+y), let
+ * 3 2 2 2 2
+ * r = x *(T2+x *(T3+x *(...+x *(T12+x *T13))))
+ * then
+ * 3 2
+ * tan(x+y) = x + (T1*x + (x *(r+y)+y))
+ *
+ * 4. For x in [0.67434,pi/4], let y = pi/4 - x, then
+ * tan(x) = tan(pi/4-y) = (1-tan(y))/(1+tan(y))
+ * = 1 - 2*(tan(y) - (tan(y)^2)/(1+tan(y)))
+ */
+
+#include "fdlibm.h"
+static const double
+one = 1.00000000000000000000e+00, /* 0x3FF00000, 0x00000000 */
+pio4 = 7.85398163397448278999e-01, /* 0x3FE921FB, 0x54442D18 */
+pio4lo= 3.06161699786838301793e-17, /* 0x3C81A626, 0x33145C07 */
+T[] = {
+ 3.33333333333334091986e-01, /* 0x3FD55555, 0x55555563 */
+ 1.33333333333201242699e-01, /* 0x3FC11111, 0x1110FE7A */
+ 5.39682539762260521377e-02, /* 0x3FABA1BA, 0x1BB341FE */
+ 2.18694882948595424599e-02, /* 0x3F9664F4, 0x8406D637 */
+ 8.86323982359930005737e-03, /* 0x3F8226E3, 0xE96E8493 */
+ 3.59207910759131235356e-03, /* 0x3F6D6D22, 0xC9560328 */
+ 1.45620945432529025516e-03, /* 0x3F57DBC8, 0xFEE08315 */
+ 5.88041240820264096874e-04, /* 0x3F4344D8, 0xF2F26501 */
+ 2.46463134818469906812e-04, /* 0x3F3026F7, 0x1A8D1068 */
+ 7.81794442939557092300e-05, /* 0x3F147E88, 0xA03792A6 */
+ 7.14072491382608190305e-05, /* 0x3F12B80F, 0x32F0A7E9 */
+ -1.85586374855275456654e-05, /* 0xBEF375CB, 0xDB605373 */
+ 2.59073051863633712884e-05, /* 0x3EFB2A70, 0x74BF7AD4 */
+};
+
+ double __kernel_tan(double x, double y, int iy)
+{
+ double z,r,v,w,s;
+ int ix,hx;
+ hx = __HI(x); /* high word of x */
+ ix = hx&0x7fffffff; /* high word of |x| */
+ if(ix<0x3e300000) /* x < 2**-28 */
+ {if((int)x==0) { /* generate inexact */
+ if(((ix|__LO(x))|(iy+1))==0) return one/fabs(x);
+ else return (iy==1)? x: -one/x;
+ }
+ }
+ if(ix>=0x3FE59428) { /* |x|>=0.6744 */
+ if(hx<0) {x = -x; y = -y;}
+ z = pio4-x;
+ w = pio4lo-y;
+ x = z+w; y = 0.0;
+ }
+ z = x*x;
+ w = z*z;
+ /* Break x^5*(T[1]+x^2*T[2]+...) into
+ * x^5(T[1]+x^4*T[3]+...+x^20*T[11]) +
+ * x^5(x^2*(T[2]+x^4*T[4]+...+x^22*[T12]))
+ */
+ r = T[1]+w*(T[3]+w*(T[5]+w*(T[7]+w*(T[9]+w*T[11]))));
+ v = z*(T[2]+w*(T[4]+w*(T[6]+w*(T[8]+w*(T[10]+w*T[12])))));
+ s = z*x;
+ r = y + z*(s*(r+v)+y);
+ r += T[0]*s;
+ w = x+r;
+ if(ix>=0x3FE59428) {
+ v = (double)iy;
+ return (double)(1-((hx>>30)&2))*(v-2.0*(x-(w*w/(w+v)-r)));
+ }
+ if(iy==1) return w;
+ else { /* if allow error up to 2 ulp,
+ simply return -1.0/(x+r) here */
+ /* compute -1.0/(x+r) accurately */
+ double a,t;
+ z = w;
+ __LO(z) = 0;
+ v = r-(z - x); /* z+v = r+x */
+ t = a = -1.0/w; /* a = -1.0/w */
+ __LO(t) = 0;
+ s = 1.0+t*z;
+ return t+a*(s+t*v);
+ }
+}
--- /dev/null
+++ b/libmath/fdlibm/readme
@@ -1,0 +1,261 @@
+
+ ********************************
+ * Announcing FDLIBM Version 5 *
+ ********************************
+============================================================
+ FDLIBM
+============================================================
+ (developed at SunSoft, a Sun Microsystems, Inc. business.)
+
+What's new in FDLIBM 5.2?
+BUGS FIXED
+ 1. Little endian bug in frexp (affect only little endian machine):
+ in file s_frexp.c, last line of program frexp before exit
+ *(int*)&x = hx;
+ should read
+ *(n0+(int*)&x) = hx;
+
+ 2. jn(-1,x) is three times larger that the actual answer:
+ in file e_jn.c, the line
+ sign = 1 - ((n&1)<<2);
+ should read
+ sign = 1 - ((n&1)<<1);
+
+ 3. Compiler failure on non-standard code
+ J.T. Conklin found that gcc optimizing out the manipulation of doubles
+ via pointer bashing of the form
+ double x = 0;
+ *(((int*)&x)+n0)=0x7fff0000;
+ foo(x);
+ C experts confirmed that the behavior of *(((int*)&x)+n0)=0x7fff0000
+ is undefined. By replacing n0 with a constant 0 or 1, the GCC "knows"
+ that the assignment is modifying the double, and "does the right thing."
+ Thus, in FDLIBM 5.2, we replace n0 with a constant and use a macro
+ __HI() and __LO() with #ifdef __LITTLE_ENDIAN to avoid the above problem.
+
+ 4. Performance issue on rem_pio2
+ An attempt to speed up the argument reduction in the trig function is the
+ consider pi/4 < x < 3pi/4 a special case. This was done in the file
+ e_rem_pio2.c
+
+
+FDLIBM (Freely Distributable LIBM) is a C math library
+for machines that support IEEE 754 floating-point arithmetic.
+In this release, only double precision is supported.
+
+FDLIBM is intended to provide a reasonably portable (see
+assumptions below), reference quality (below one ulp for
+major functions like sin,cos,exp,log) math library
+(libm.a). For a copy of FDLIBM, please send a message "send index from fdlibm"
+to netlib@research.att.com.
+
+--------------
+1. ASSUMPTIONS
+--------------
+FDLIBM (double precision version) assumes:
+ a. IEEE 754 style (if not precise compliance) arithmetic;
+ b. 32 bit 2's complement integer arithmetic;
+ c. Each double precision floating-point number must be in IEEE 754
+ double format, and that each number can be retrieved as two 32-bit
+ integers through the using of pointer bashing as in the example
+ below:
+
+ Example: let y = 2.0
+ double fp number y: 2.0
+ IEEE double format: 0x4000000000000000
+
+ Referencing y as two integers:
+ *(int*)&y,*(1+(int*)&y) = {0x40000000,0x0} (on sparc)
+ {0x0,0x40000000} (on 386)
+
+ Note: Four macros are defined in fdlibm.h to handle this kind of
+ retrieving:
+
+ __HI(x) the high part of a double x
+ (sign,exponent,the first 21 significant bits)
+ __LO(x) the least 32 significant bits of x
+ __HIp(x) same as __HI except that the argument is a pointer
+ to a double
+ __LOp(x) same as __LO except that the argument is a pointer
+ to a double
+
+ To ensure obtaining correct ordering, one must define __LITTLE_ENDIAN
+ during compilation for little endian machine (like 386,486). The
+ default is big endian.
+
+ If the behavior of pointer bashing is undefined, one may hack on the
+ macro in fdlibm.h.
+
+ d. IEEE exceptions may trigger "signals" as is common in Unix
+ implementations.
+
+-------------------
+2. EXCEPTION CASES
+-------------------
+All exception cases in the FDLIBM functions will be mapped
+to one of the following four exceptions:
+
+ +-huge*huge, +-tiny*tiny, +-1.0/0.0, +-0.0/0.0
+ (overflow) (underflow) (divided-by-zero) (invalid)
+
+For example, log(0) is a singularity and is thus mapped to
+ -1.0/0.0 = -infinity.
+That is, FDLIBM's log will compute -one/zero and return the
+computed value. On an IEEE machine, this will trigger the
+divided-by-zero exception and a negative infinity is returned by
+default.
+
+Similarly, exp(-huge) will be mapped to tiny*tiny to generate
+an underflow signal.
+
+
+--------------------------------
+3. STANDARD CONFORMANCE WRAPPER
+--------------------------------
+The default FDLIBM functions (compiled with -D_IEEE_LIBM flag)
+are in "IEEE spirit" (i.e., return the most reasonable result in
+floating-point arithmetic). If one wants FDLIBM to comply with
+standards like SVID, X/OPEN, or POSIX/ANSI, then one can
+create a multi-standard compliant FDLIBM. In this case, each
+function in FDLIBM is actually a standard compliant wrapper
+function.
+
+File organization:
+ 1. For FDLIBM's kernel (internal) function,
+ File name Entry point
+ ---------------------------
+ k_sin.c __kernel_sin
+ k_tan.c __kernel_tan
+ ---------------------------
+ 2. For functions that have no standards conflict
+ File name Entry point
+ ---------------------------
+ s_sin.c sin
+ s_erf.c erf
+ ---------------------------
+ 3. Ieee754 core functions
+ File name Entry point
+ ---------------------------
+ e_exp.c __ieee754_exp
+ e_sinh.c __ieee754_sinh
+ ---------------------------
+ 4. Wrapper functions
+ File name Entry point
+ ---------------------------
+ w_exp.c exp
+ w_sinh.c sinh
+ ---------------------------
+
+Wrapper functions will twist the result of the ieee754
+function to comply to the standard specified by the value
+of _LIB_VERSION
+ if _LIB_VERSION = _IEEE_, return the ieee754 result;
+ if _LIB_VERSION = _SVID_, return SVID result;
+ if _LIB_VERSION = _XOPEN_, return XOPEN result;
+ if _LIB_VERSION = _POSIX_, return POSIX/ANSI result.
+(These are macros, see fdlibm.h for their definition.)
+
+
+--------------------------------
+4. HOW TO CREATE FDLIBM's libm.a
+--------------------------------
+There are two types of libm.a. One is IEEE only, and the other is
+multi-standard compliant (supports IEEE,XOPEN,POSIX/ANSI,SVID).
+
+To create the IEEE only libm.a, use
+ make "CFLAGS = -D_IEEE_LIBM"
+This will create an IEEE libm.a, which is smaller in size, and
+somewhat faster.
+
+To create a multi-standard compliant libm, use
+ make "CFLAGS = -D_IEEE_MODE" --- multi-standard fdlibm: default
+ to IEEE
+ make "CFLAGS = -D_XOPEN_MODE" --- multi-standard fdlibm: default
+ to X/OPEN
+ make "CFLAGS = -D_POSIX_MODE" --- multi-standard fdlibm: default
+ to POSIX/ANSI
+ make "CFLAGS = -D_SVID3_MODE" --- multi-standard fdlibm: default
+ to SVID
+
+
+Here is how one makes a SVID compliant libm.
+ Make the library by
+ make "CFLAGS = -D_SVID3_MODE".
+ The libm.a of FDLIBM will be multi-standard compliant and
+ _LIB_VERSION is initialized to the value _SVID_ .
+
+ example1:
+ ---------
+ main()
+ {
+ double y0();
+ printf("y0(1e300) = %1.20e\n",y0(1e300));
+ exit(0);
+ }
+
+ % cc example1.c libm.a
+ % a.out
+ y0: TLOSS error
+ y0(1e300) = 0.00000000000000000000e+00
+
+
+It is possible to change the default standard in multi-standard
+fdlibm. Here is an example of how to do it:
+ example2:
+ ---------
+ #include "fdlibm.h" /* must include FDLIBM's fdlibm.h */
+ main()
+ {
+ double y0();
+ _LIB_VERSION = _IEEE_;
+ printf("IEEE: y0(1e300) = %1.20e\n",y0(1e300));
+ _LIB_VERSION = _XOPEN_;
+ printf("XOPEN y0(1e300) = %1.20e\n",y0(1e300));
+ _LIB_VERSION = _POSIX_;
+ printf("POSIX y0(1e300) = %1.20e\n",y0(1e300));
+ _LIB_VERSION = _SVID_;
+ printf("SVID y0(1e300) = %1.20e\n",y0(1e300));
+ exit(0);
+ }
+
+ % cc example2.c libm.a
+ % a.out
+ IEEE: y0(1e300) = -1.36813604503424810557e-151
+ XOPEN y0(1e300) = 0.00000000000000000000e+00
+ POSIX y0(1e300) = 0.00000000000000000000e+00
+ y0: TLOSS error
+ SVID y0(1e300) = 0.00000000000000000000e+00
+
+Note: Here _LIB_VERSION is a global variable. If global variables
+ are forbidden, then one should modify fdlibm.h to change
+ _LIB_VERSION to be a global constant. In this case, one
+ may not change the value of _LIB_VERSION as in example2.
+
+---------------------------
+5. NOTES ON PORTING FDLIBM
+---------------------------
+ Care must be taken when installing FDLIBM over existing
+ libm.a.
+ All co-existing function prototypes must agree, otherwise
+ users will encounter mysterious failures.
+
+ So far, the only known likely conflict is the declaration
+ of the IEEE recommended function scalb:
+
+ double scalb(double,double) (1) SVID3 defined
+ double scalb(double,int) (2) IBM,DEC,...
+
+ FDLIBM follows Sun definition and use (1) as default.
+ If one's existing libm.a uses (2), then one may raise
+ the flags _SCALB_INT during the compilation of FDLIBM
+ to get the correct function prototype.
+ (E.g., make "CFLAGS = -D_IEEE_LIBM -D_SCALB_INT".)
+ NOTE that if -D_SCALB_INT is raised, it won't be SVID3
+ conformant.
+
+--------------
+6. PROBLEMS ?
+--------------
+Please send comments and bug report to:
+ fdlibm-comments@sunpro.eng.sun.com
+
--- /dev/null
+++ b/libmath/fdlibm/s_asinh.c
@@ -1,0 +1,53 @@
+/* derived from /netlib/fdlibm */
+
+/* @(#)s_asinh.c 1.3 95/01/18 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunSoft, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+/* asinh(x)
+ * Method :
+ * Based on
+ * asinh(x) = sign(x) * log [ |x| + sqrt(x*x+1) ]
+ * we have
+ * asinh(x) := x if 1+x*x=1,
+ * := sign(x)*(log(x)+ln2)) for large |x|, else
+ * := sign(x)*log(2|x|+1/(|x|+sqrt(x*x+1))) if|x|>2, else
+ * := sign(x)*log1p(|x| + x^2/(1 + sqrt(1+x^2)))
+ */
+
+#include "fdlibm.h"
+
+static const double
+one = 1.00000000000000000000e+00, /* 0x3FF00000, 0x00000000 */
+ln2 = 6.93147180559945286227e-01, /* 0x3FE62E42, 0xFEFA39EF */
+Huge= 1.00000000000000000000e+300;
+
+ double asinh(double x)
+{
+ double t,w;
+ int hx,ix;
+ hx = __HI(x);
+ ix = hx&0x7fffffff;
+ if(ix>=0x7ff00000) return x+x; /* x is inf or NaN */
+ if(ix< 0x3e300000) { /* |x|<2**-28 */
+ if(Huge+x>one) return x; /* return x inexact except 0 */
+ }
+ if(ix>0x41b00000) { /* |x| > 2**28 */
+ w = __ieee754_log(fabs(x))+ln2;
+ } else if (ix>0x40000000) { /* 2**28 > |x| > 2.0 */
+ t = fabs(x);
+ w = __ieee754_log(2.0*t+one/(sqrt(x*x+one)+t));
+ } else { /* 2.0 > |x| > 2**-28 */
+ t = x*x;
+ w =log1p(fabs(x)+t/(one+sqrt(one+t)));
+ }
+ if(hx>0) return w; else return -w;
+}
--- /dev/null
+++ b/libmath/fdlibm/s_atan.c
@@ -1,0 +1,114 @@
+/* derived from /netlib/fdlibm */
+
+/* @(#)s_atan.c 1.3 95/01/18 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunSoft, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ *
+ */
+
+/* atan(x)
+ * Method
+ * 1. Reduce x to positive by atan(x) = -atan(-x).
+ * 2. According to the integer k=4t+0.25 chopped, t=x, the argument
+ * is further reduced to one of the following intervals and the
+ * arctangent of t is evaluated by the corresponding formula:
+ *
+ * [0,7/16] atan(x) = t-t^3*(a1+t^2*(a2+...(a10+t^2*a11)...)
+ * [7/16,11/16] atan(x) = atan(1/2) + atan( (t-0.5)/(1+t/2) )
+ * [11/16.19/16] atan(x) = atan( 1 ) + atan( (t-1)/(1+t) )
+ * [19/16,39/16] atan(x) = atan(3/2) + atan( (t-1.5)/(1+1.5t) )
+ * [39/16,INF] atan(x) = atan(INF) + atan( -1/t )
+ *
+ * Constants:
+ * The hexadecimal values are the intended ones for the following
+ * constants. The decimal values may be used, provided that the
+ * compiler will convert from decimal to binary accurately enough
+ * to produce the hexadecimal values shown.
+ */
+
+#include "fdlibm.h"
+
+static const double atanhi[] = {
+ 4.63647609000806093515e-01, /* atan(0.5)hi 0x3FDDAC67, 0x0561BB4F */
+ 7.85398163397448278999e-01, /* atan(1.0)hi 0x3FE921FB, 0x54442D18 */
+ 9.82793723247329054082e-01, /* atan(1.5)hi 0x3FEF730B, 0xD281F69B */
+ 1.57079632679489655800e+00, /* atan(inf)hi 0x3FF921FB, 0x54442D18 */
+};
+
+static const double atanlo[] = {
+ 2.26987774529616870924e-17, /* atan(0.5)lo 0x3C7A2B7F, 0x222F65E2 */
+ 3.06161699786838301793e-17, /* atan(1.0)lo 0x3C81A626, 0x33145C07 */
+ 1.39033110312309984516e-17, /* atan(1.5)lo 0x3C700788, 0x7AF0CBBD */
+ 6.12323399573676603587e-17, /* atan(inf)lo 0x3C91A626, 0x33145C07 */
+};
+
+static const double aT[] = {
+ 3.33333333333329318027e-01, /* 0x3FD55555, 0x5555550D */
+ -1.99999999998764832476e-01, /* 0xBFC99999, 0x9998EBC4 */
+ 1.42857142725034663711e-01, /* 0x3FC24924, 0x920083FF */
+ -1.11111104054623557880e-01, /* 0xBFBC71C6, 0xFE231671 */
+ 9.09088713343650656196e-02, /* 0x3FB745CD, 0xC54C206E */
+ -7.69187620504482999495e-02, /* 0xBFB3B0F2, 0xAF749A6D */
+ 6.66107313738753120669e-02, /* 0x3FB10D66, 0xA0D03D51 */
+ -5.83357013379057348645e-02, /* 0xBFADDE2D, 0x52DEFD9A */
+ 4.97687799461593236017e-02, /* 0x3FA97B4B, 0x24760DEB */
+ -3.65315727442169155270e-02, /* 0xBFA2B444, 0x2C6A6C2F */
+ 1.62858201153657823623e-02, /* 0x3F90AD3A, 0xE322DA11 */
+};
+
+ static const double
+one = 1.0,
+Huge = 1.0e300;
+
+ double atan(double x)
+{
+ double w,s1,s2,z;
+ int ix,hx,id;
+
+ hx = __HI(x);
+ ix = hx&0x7fffffff;
+ if(ix>=0x44100000) { /* if |x| >= 2^66 */
+ if(ix>0x7ff00000||
+ (ix==0x7ff00000&&(__LO(x)!=0)))
+ return x+x; /* NaN */
+ if(hx>0) return atanhi[3]+atanlo[3];
+ else return -atanhi[3]-atanlo[3];
+ } if (ix < 0x3fdc0000) { /* |x| < 0.4375 */
+ if (ix < 0x3e200000) { /* |x| < 2^-29 */
+ if(Huge+x>one) return x; /* raise inexact */
+ }
+ id = -1;
+ } else {
+ x = fabs(x);
+ if (ix < 0x3ff30000) { /* |x| < 1.1875 */
+ if (ix < 0x3fe60000) { /* 7/16 <=|x|<11/16 */
+ id = 0; x = (2.0*x-one)/(2.0+x);
+ } else { /* 11/16<=|x|< 19/16 */
+ id = 1; x = (x-one)/(x+one);
+ }
+ } else {
+ if (ix < 0x40038000) { /* |x| < 2.4375 */
+ id = 2; x = (x-1.5)/(one+1.5*x);
+ } else { /* 2.4375 <= |x| < 2^66 */
+ id = 3; x = -1.0/x;
+ }
+ }}
+ /* end of argument reduction */
+ z = x*x;
+ w = z*z;
+ /* break sum from i=0 to 10 aT[i]z**(i+1) into odd and even poly */
+ s1 = z*(aT[0]+w*(aT[2]+w*(aT[4]+w*(aT[6]+w*(aT[8]+w*aT[10])))));
+ s2 = w*(aT[1]+w*(aT[3]+w*(aT[5]+w*(aT[7]+w*aT[9]))));
+ if (id<0) return x - x*(s1+s2);
+ else {
+ z = atanhi[id] - ((x*(s1+s2) - atanlo[id]) - x);
+ return (hx<0)? -z:z;
+ }
+}
--- /dev/null
+++ b/libmath/fdlibm/s_cbrt.c
@@ -1,0 +1,75 @@
+/* derived from /netlib/fdlibm */
+
+/* @(#)s_cbrt.c 1.3 95/01/18 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunSoft, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ *
+ */
+
+#include "fdlibm.h"
+
+/* cbrt(x)
+ * Return cube root of x
+ */
+static const unsigned
+ B1 = 715094163, /* B1 = (682-0.03306235651)*2**20 */
+ B2 = 696219795; /* B2 = (664-0.03306235651)*2**20 */
+
+static const double
+C = 5.42857142857142815906e-01, /* 19/35 = 0x3FE15F15, 0xF15F15F1 */
+D = -7.05306122448979611050e-01, /* -864/1225 = 0xBFE691DE, 0x2532C834 */
+E = 1.41428571428571436819e+00, /* 99/70 = 0x3FF6A0EA, 0x0EA0EA0F */
+F = 1.60714285714285720630e+00, /* 45/28 = 0x3FF9B6DB, 0x6DB6DB6E */
+G = 3.57142857142857150787e-01; /* 5/14 = 0x3FD6DB6D, 0xB6DB6DB7 */
+
+ double cbrt(double x)
+{
+ int hx;
+ double r,s,t=0.0,w;
+ unsigned sign;
+
+
+ hx = __HI(x); /* high word of x */
+ sign=hx&0x80000000; /* sign= sign(x) */
+ hx ^=sign;
+ if(hx>=0x7ff00000) return(x+x); /* cbrt(NaN,INF) is itself */
+ if((hx|__LO(x))==0)
+ return(x); /* cbrt(0) is itself */
+
+ __HI(x) = hx; /* x <- |x| */
+ /* rough cbrt to 5 bits */
+ if(hx<0x00100000) /* subnormal number */
+ {__HI(t)=0x43500000; /* set t= 2**54 */
+ t*=x; __HI(t)=__HI(t)/3+B2;
+ }
+ else
+ __HI(t)=hx/3+B1;
+
+
+ /* new cbrt to 23 bits, may be implemented in single precision */
+ r=t*t/x;
+ s=C+r*t;
+ t*=G+F/(s+E+D/s);
+
+ /* chopped to 20 bits and make it larger than cbrt(x) */
+ __LO(t)=0; __HI(t)+=0x00000001;
+
+
+ /* one step newton iteration to 53 bits with error less than 0.667 ulps */
+ s=t*t; /* t*t is exact */
+ r=x/s;
+ w=t+t;
+ r=(r-t)/(w+r); /* r-s is exact */
+ t=t+t*r;
+
+ /* retore the sign bit */
+ __HI(t) |= sign;
+ return(t);
+}
--- /dev/null
+++ b/libmath/fdlibm/s_ceil.c
@@ -1,0 +1,70 @@
+/* derived from /netlib/fdlibm */
+
+/* @(#)s_ceil.c 1.3 95/01/18 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunSoft, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+/*
+ * ceil(x)
+ * Return x rounded toward -inf to integral value
+ * Method:
+ * Bit twiddling.
+ * Exception:
+ * Inexact flag raised if x not equal to ceil(x).
+ */
+
+#include "fdlibm.h"
+
+static const double Huge = 1.0e300;
+
+ double ceil(double x)
+{
+ int i0,i1,j0;
+ unsigned i,j;
+ i0 = __HI(x);
+ i1 = __LO(x);
+ j0 = ((i0>>20)&0x7ff)-0x3ff;
+ if(j0<20) {
+ if(j0<0) { /* raise inexact if x != 0 */
+ if(Huge+x>0.0) {/* return 0*sign(x) if |x|<1 */
+ if(i0<0) {i0=0x80000000;i1=0;}
+ else if((i0|i1)!=0) { i0=0x3ff00000;i1=0;}
+ }
+ } else {
+ i = (0x000fffff)>>j0;
+ if(((i0&i)|i1)==0) return x; /* x is integral */
+ if(Huge+x>0.0) { /* raise inexact flag */
+ if(i0>0) i0 += (0x00100000)>>j0;
+ i0 &= (~i); i1=0;
+ }
+ }
+ } else if (j0>51) {
+ if(j0==0x400) return x+x; /* inf or NaN */
+ else return x; /* x is integral */
+ } else {
+ i = ((unsigned)(0xffffffff))>>(j0-20);
+ if((i1&i)==0) return x; /* x is integral */
+ if(Huge+x>0.0) { /* raise inexact flag */
+ if(i0>0) {
+ if(j0==20) i0+=1;
+ else {
+ j = i1 + (1<<(52-j0));
+ if(j<i1) i0+=1; /* got a carry */
+ i1 = j;
+ }
+ }
+ i1 &= (~i);
+ }
+ }
+ __HI(x) = i0;
+ __LO(x) = i1;
+ return x;
+}
--- /dev/null
+++ b/libmath/fdlibm/s_copysign.c
@@ -1,0 +1,27 @@
+/* derived from /netlib/fdlibm */
+
+/* @(#)s_copysign.c 1.3 95/01/18 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunSoft, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+/*
+ * copysign(double x, double y)
+ * copysign(x,y) returns a value with the magnitude of x and
+ * with the sign bit of y.
+ */
+
+#include "fdlibm.h"
+
+ double copysign(double x, double y)
+{
+ __HI(x) = (__HI(x)&0x7fffffff)|(__HI(y)&0x80000000);
+ return x;
+}
--- /dev/null
+++ b/libmath/fdlibm/s_cos.c
@@ -1,0 +1,74 @@
+/* derived from /netlib/fdlibm */
+
+/* @(#)s_cos.c 1.3 95/01/18 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunSoft, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+/* cos(x)
+ * Return cosine function of x.
+ *
+ * kernel function:
+ * __kernel_sin ... sine function on [-pi/4,pi/4]
+ * __kernel_cos ... cosine function on [-pi/4,pi/4]
+ * __ieee754_rem_pio2 ... argument reduction routine
+ *
+ * Method.
+ * Let S,C and T denote the sin, cos and tan respectively on
+ * [-PI/4, +PI/4]. Reduce the argument x to y1+y2 = x-k*pi/2
+ * in [-pi/4 , +pi/4], and let n = k mod 4.
+ * We have
+ *
+ * n sin(x) cos(x) tan(x)
+ * ----------------------------------------------------------
+ * 0 S C T
+ * 1 C -S -1/T
+ * 2 -S -C T
+ * 3 -C S -1/T
+ * ----------------------------------------------------------
+ *
+ * Special cases:
+ * Let trig be any of sin, cos, or tan.
+ * trig(+-INF) is NaN, with signals;
+ * trig(NaN) is that NaN;
+ *
+ * Accuracy:
+ * TRIG(x) returns trig(x) nearly rounded
+ */
+
+#include "fdlibm.h"
+
+ double cos(double x)
+{
+ double y[2],z=0.0;
+ int n, ix;
+
+ /* High word of x. */
+ ix = __HI(x);
+
+ /* |x| ~< pi/4 */
+ ix &= 0x7fffffff;
+ if(ix <= 0x3fe921fb) return __kernel_cos(x,z);
+
+ /* cos(Inf or NaN) is NaN */
+ else if (ix>=0x7ff00000) return x-x;
+
+ /* argument reduction needed */
+ else {
+ n = __ieee754_rem_pio2(x,y);
+ switch(n&3) {
+ case 0: return __kernel_cos(y[0],y[1]);
+ case 1: return -__kernel_sin(y[0],y[1],1);
+ case 2: return -__kernel_cos(y[0],y[1]);
+ default:
+ return __kernel_sin(y[0],y[1],1);
+ }
+ }
+}
--- /dev/null
+++ b/libmath/fdlibm/s_erf.c
@@ -1,0 +1,297 @@
+/* derived from /netlib/fdlibm */
+
+/* @(#)s_erf.c 1.3 95/01/18 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunSoft, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+/* double erf(double x)
+ * double erfc(double x)
+ * x
+ * 2 |\
+ * erf(x) = --------- | exp(-t*t)dt
+ * sqrt(pi) \|
+ * 0
+ *
+ * erfc(x) = 1-erf(x)
+ * Note that
+ * erf(-x) = -erf(x)
+ * erfc(-x) = 2 - erfc(x)
+ *
+ * Method:
+ * 1. For |x| in [0, 0.84375]
+ * erf(x) = x + x*R(x^2)
+ * erfc(x) = 1 - erf(x) if x in [-.84375,0.25]
+ * = 0.5 + ((0.5-x)-x*R) if x in [0.25,0.84375]
+ * where R = P/Q where P is an odd poly of degree 8 and
+ * Q is an odd poly of degree 10.
+ * -57.90
+ * | R - (erf(x)-x)/x | <= 2
+ *
+ *
+ * Remark. The formula is derived by noting
+ * erf(x) = (2/sqrt(pi))*(x - x^3/3 + x^5/10 - x^7/42 + ....)
+ * and that
+ * 2/sqrt(pi) = 1.128379167095512573896158903121545171688
+ * is close to one. The interval is chosen because the fix
+ * point of erf(x) is near 0.6174 (i.e., erf(x)=x when x is
+ * near 0.6174), and by some experiment, 0.84375 is chosen to
+ * guarantee the error is less than one ulp for erf.
+ *
+ * 2. For |x| in [0.84375,1.25], let s = |x| - 1, and
+ * c = 0.84506291151 rounded to single (24 bits)
+ * erf(x) = sign(x) * (c + P1(s)/Q1(s))
+ * erfc(x) = (1-c) - P1(s)/Q1(s) if x > 0
+ * 1+(c+P1(s)/Q1(s)) if x < 0
+ * |P1/Q1 - (erf(|x|)-c)| <= 2**-59.06
+ * Remark: here we use the taylor series expansion at x=1.
+ * erf(1+s) = erf(1) + s*Poly(s)
+ * = 0.845.. + P1(s)/Q1(s)
+ * That is, we use rational approximation to approximate
+ * erf(1+s) - (c = (single)0.84506291151)
+ * Note that |P1/Q1|< 0.078 for x in [0.84375,1.25]
+ * where
+ * P1(s) = degree 6 poly in s
+ * Q1(s) = degree 6 poly in s
+ *
+ * 3. For x in [1.25,1/0.35(~2.857143)],
+ * erfc(x) = (1/x)*exp(-x*x-0.5625+R1/S1)
+ * erf(x) = 1 - erfc(x)
+ * where
+ * R1(z) = degree 7 poly in z, (z=1/x^2)
+ * S1(z) = degree 8 poly in z
+ *
+ * 4. For x in [1/0.35,28]
+ * erfc(x) = (1/x)*exp(-x*x-0.5625+R2/S2) if x > 0
+ * = 2.0 - (1/x)*exp(-x*x-0.5625+R2/S2) if -6<x<0
+ * = 2.0 - tiny (if x <= -6)
+ * erf(x) = sign(x)*(1.0 - erfc(x)) if x < 6, else
+ * erf(x) = sign(x)*(1.0 - tiny)
+ * where
+ * R2(z) = degree 6 poly in z, (z=1/x^2)
+ * S2(z) = degree 7 poly in z
+ *
+ * Note1:
+ * To compute exp(-x*x-0.5625+R/S), let s be a single
+ * precision number and s := x; then
+ * -x*x = -s*s + (s-x)*(s+x)
+ * exp(-x*x-0.5626+R/S) =
+ * exp(-s*s-0.5625)*exp((s-x)*(s+x)+R/S);
+ * Note2:
+ * Here 4 and 5 make use of the asymptotic series
+ * exp(-x*x)
+ * erfc(x) ~ ---------- * ( 1 + Poly(1/x^2) )
+ * x*sqrt(pi)
+ * We use rational approximation to approximate
+ * g(s)=f(1/x^2) = log(erfc(x)*x) - x*x + 0.5625
+ * Here is the error bound for R1/S1 and R2/S2
+ * |R1/S1 - f(x)| < 2**(-62.57)
+ * |R2/S2 - f(x)| < 2**(-61.52)
+ *
+ * 5. For inf > x >= 28
+ * erf(x) = sign(x) *(1 - tiny) (raise inexact)
+ * erfc(x) = tiny*tiny (raise underflow) if x > 0
+ * = 2 - tiny if x<0
+ *
+ * 7. Special case:
+ * erf(0) = 0, erf(inf) = 1, erf(-inf) = -1,
+ * erfc(0) = 1, erfc(inf) = 0, erfc(-inf) = 2,
+ * erfc/erf(NaN) is NaN
+ */
+
+
+#include "fdlibm.h"
+
+static const double
+tiny = 1e-300,
+half= 5.00000000000000000000e-01, /* 0x3FE00000, 0x00000000 */
+one = 1.00000000000000000000e+00, /* 0x3FF00000, 0x00000000 */
+two = 2.00000000000000000000e+00, /* 0x40000000, 0x00000000 */
+ /* c = (float)0.84506291151 */
+erx = 8.45062911510467529297e-01, /* 0x3FEB0AC1, 0x60000000 */
+/*
+ * Coefficients for approximation to erf on [0,0.84375]
+ */
+efx = 1.28379167095512586316e-01, /* 0x3FC06EBA, 0x8214DB69 */
+efx8= 1.02703333676410069053e+00, /* 0x3FF06EBA, 0x8214DB69 */
+pp0 = 1.28379167095512558561e-01, /* 0x3FC06EBA, 0x8214DB68 */
+pp1 = -3.25042107247001499370e-01, /* 0xBFD4CD7D, 0x691CB913 */
+pp2 = -2.84817495755985104766e-02, /* 0xBF9D2A51, 0xDBD7194F */
+pp3 = -5.77027029648944159157e-03, /* 0xBF77A291, 0x236668E4 */
+pp4 = -2.37630166566501626084e-05, /* 0xBEF8EAD6, 0x120016AC */
+qq1 = 3.97917223959155352819e-01, /* 0x3FD97779, 0xCDDADC09 */
+qq2 = 6.50222499887672944485e-02, /* 0x3FB0A54C, 0x5536CEBA */
+qq3 = 5.08130628187576562776e-03, /* 0x3F74D022, 0xC4D36B0F */
+qq4 = 1.32494738004321644526e-04, /* 0x3F215DC9, 0x221C1A10 */
+qq5 = -3.96022827877536812320e-06, /* 0xBED09C43, 0x42A26120 */
+/*
+ * Coefficients for approximation to erf in [0.84375,1.25]
+ */
+pa0 = -2.36211856075265944077e-03, /* 0xBF6359B8, 0xBEF77538 */
+pa1 = 4.14856118683748331666e-01, /* 0x3FDA8D00, 0xAD92B34D */
+pa2 = -3.72207876035701323847e-01, /* 0xBFD7D240, 0xFBB8C3F1 */
+pa3 = 3.18346619901161753674e-01, /* 0x3FD45FCA, 0x805120E4 */
+pa4 = -1.10894694282396677476e-01, /* 0xBFBC6398, 0x3D3E28EC */
+pa5 = 3.54783043256182359371e-02, /* 0x3FA22A36, 0x599795EB */
+pa6 = -2.16637559486879084300e-03, /* 0xBF61BF38, 0x0A96073F */
+qa1 = 1.06420880400844228286e-01, /* 0x3FBB3E66, 0x18EEE323 */
+qa2 = 5.40397917702171048937e-01, /* 0x3FE14AF0, 0x92EB6F33 */
+qa3 = 7.18286544141962662868e-02, /* 0x3FB2635C, 0xD99FE9A7 */
+qa4 = 1.26171219808761642112e-01, /* 0x3FC02660, 0xE763351F */
+qa5 = 1.36370839120290507362e-02, /* 0x3F8BEDC2, 0x6B51DD1C */
+qa6 = 1.19844998467991074170e-02, /* 0x3F888B54, 0x5735151D */
+/*
+ * Coefficients for approximation to erfc in [1.25,1/0.35]
+ */
+ra0 = -9.86494403484714822705e-03, /* 0xBF843412, 0x600D6435 */
+ra1 = -6.93858572707181764372e-01, /* 0xBFE63416, 0xE4BA7360 */
+ra2 = -1.05586262253232909814e+01, /* 0xC0251E04, 0x41B0E726 */
+ra3 = -6.23753324503260060396e+01, /* 0xC04F300A, 0xE4CBA38D */
+ra4 = -1.62396669462573470355e+02, /* 0xC0644CB1, 0x84282266 */
+ra5 = -1.84605092906711035994e+02, /* 0xC067135C, 0xEBCCABB2 */
+ra6 = -8.12874355063065934246e+01, /* 0xC0545265, 0x57E4D2F2 */
+ra7 = -9.81432934416914548592e+00, /* 0xC023A0EF, 0xC69AC25C */
+sa1 = 1.96512716674392571292e+01, /* 0x4033A6B9, 0xBD707687 */
+sa2 = 1.37657754143519042600e+02, /* 0x4061350C, 0x526AE721 */
+sa3 = 4.34565877475229228821e+02, /* 0x407B290D, 0xD58A1A71 */
+sa4 = 6.45387271733267880336e+02, /* 0x40842B19, 0x21EC2868 */
+sa5 = 4.29008140027567833386e+02, /* 0x407AD021, 0x57700314 */
+sa6 = 1.08635005541779435134e+02, /* 0x405B28A3, 0xEE48AE2C */
+sa7 = 6.57024977031928170135e+00, /* 0x401A47EF, 0x8E484A93 */
+sa8 = -6.04244152148580987438e-02, /* 0xBFAEEFF2, 0xEE749A62 */
+/*
+ * Coefficients for approximation to erfc in [1/.35,28]
+ */
+rb0 = -9.86494292470009928597e-03, /* 0xBF843412, 0x39E86F4A */
+rb1 = -7.99283237680523006574e-01, /* 0xBFE993BA, 0x70C285DE */
+rb2 = -1.77579549177547519889e+01, /* 0xC031C209, 0x555F995A */
+rb3 = -1.60636384855821916062e+02, /* 0xC064145D, 0x43C5ED98 */
+rb4 = -6.37566443368389627722e+02, /* 0xC083EC88, 0x1375F228 */
+rb5 = -1.02509513161107724954e+03, /* 0xC0900461, 0x6A2E5992 */
+rb6 = -4.83519191608651397019e+02, /* 0xC07E384E, 0x9BDC383F */
+sb1 = 3.03380607434824582924e+01, /* 0x403E568B, 0x261D5190 */
+sb2 = 3.25792512996573918826e+02, /* 0x40745CAE, 0x221B9F0A */
+sb3 = 1.53672958608443695994e+03, /* 0x409802EB, 0x189D5118 */
+sb4 = 3.19985821950859553908e+03, /* 0x40A8FFB7, 0x688C246A */
+sb5 = 2.55305040643316442583e+03, /* 0x40A3F219, 0xCEDF3BE6 */
+sb6 = 4.74528541206955367215e+02, /* 0x407DA874, 0xE79FE763 */
+sb7 = -2.24409524465858183362e+01; /* 0xC03670E2, 0x42712D62 */
+
+ double erf(double x)
+{
+ int hx,ix,i;
+ double R,S,P,Q,s,y,z,r;
+ hx = __HI(x);
+ ix = hx&0x7fffffff;
+ if(ix>=0x7ff00000) { /* erf(nan)=nan */
+ i = ((unsigned)hx>>31)<<1;
+ return (double)(1-i)+one/x; /* erf(+-inf)=+-1 */
+ }
+
+ if(ix < 0x3feb0000) { /* |x|<0.84375 */
+ if(ix < 0x3e300000) { /* |x|<2**-28 */
+ if (ix < 0x00800000)
+ return 0.125*(8.0*x+efx8*x); /*avoid underflow */
+ return x + efx*x;
+ }
+ z = x*x;
+ r = pp0+z*(pp1+z*(pp2+z*(pp3+z*pp4)));
+ s = one+z*(qq1+z*(qq2+z*(qq3+z*(qq4+z*qq5))));
+ y = r/s;
+ return x + x*y;
+ }
+ if(ix < 0x3ff40000) { /* 0.84375 <= |x| < 1.25 */
+ s = fabs(x)-one;
+ P = pa0+s*(pa1+s*(pa2+s*(pa3+s*(pa4+s*(pa5+s*pa6)))));
+ Q = one+s*(qa1+s*(qa2+s*(qa3+s*(qa4+s*(qa5+s*qa6)))));
+ if(hx>=0) return erx + P/Q; else return -erx - P/Q;
+ }
+ if (ix >= 0x40180000) { /* inf>|x|>=6 */
+ if(hx>=0) return one-tiny; else return tiny-one;
+ }
+ x = fabs(x);
+ s = one/(x*x);
+ if(ix< 0x4006DB6E) { /* |x| < 1/0.35 */
+ R=ra0+s*(ra1+s*(ra2+s*(ra3+s*(ra4+s*(
+ ra5+s*(ra6+s*ra7))))));
+ S=one+s*(sa1+s*(sa2+s*(sa3+s*(sa4+s*(
+ sa5+s*(sa6+s*(sa7+s*sa8)))))));
+ } else { /* |x| >= 1/0.35 */
+ R=rb0+s*(rb1+s*(rb2+s*(rb3+s*(rb4+s*(
+ rb5+s*rb6)))));
+ S=one+s*(sb1+s*(sb2+s*(sb3+s*(sb4+s*(
+ sb5+s*(sb6+s*sb7))))));
+ }
+ z = x;
+ __LO(z) = 0;
+ r = __ieee754_exp(-z*z-0.5625)*__ieee754_exp((z-x)*(z+x)+R/S);
+ if(hx>=0) return one-r/x; else return r/x-one;
+}
+
+ double erfc(double x)
+{
+ int hx,ix;
+ double R,S,P,Q,s,y,z,r;
+ hx = __HI(x);
+ ix = hx&0x7fffffff;
+ if(ix>=0x7ff00000) { /* erfc(nan)=nan */
+ /* erfc(+-inf)=0,2 */
+ return (double)(((unsigned)hx>>31)<<1)+one/x;
+ }
+
+ if(ix < 0x3feb0000) { /* |x|<0.84375 */
+ if(ix < 0x3c700000) /* |x|<2**-56 */
+ return one-x;
+ z = x*x;
+ r = pp0+z*(pp1+z*(pp2+z*(pp3+z*pp4)));
+ s = one+z*(qq1+z*(qq2+z*(qq3+z*(qq4+z*qq5))));
+ y = r/s;
+ if(hx < 0x3fd00000) { /* x<1/4 */
+ return one-(x+x*y);
+ } else {
+ r = x*y;
+ r += (x-half);
+ return half - r ;
+ }
+ }
+ if(ix < 0x3ff40000) { /* 0.84375 <= |x| < 1.25 */
+ s = fabs(x)-one;
+ P = pa0+s*(pa1+s*(pa2+s*(pa3+s*(pa4+s*(pa5+s*pa6)))));
+ Q = one+s*(qa1+s*(qa2+s*(qa3+s*(qa4+s*(qa5+s*qa6)))));
+ if(hx>=0) {
+ z = one-erx; return z - P/Q;
+ } else {
+ z = erx+P/Q; return one+z;
+ }
+ }
+ if (ix < 0x403c0000) { /* |x|<28 */
+ x = fabs(x);
+ s = one/(x*x);
+ if(ix< 0x4006DB6D) { /* |x| < 1/.35 ~ 2.857143*/
+ R=ra0+s*(ra1+s*(ra2+s*(ra3+s*(ra4+s*(
+ ra5+s*(ra6+s*ra7))))));
+ S=one+s*(sa1+s*(sa2+s*(sa3+s*(sa4+s*(
+ sa5+s*(sa6+s*(sa7+s*sa8)))))));
+ } else { /* |x| >= 1/.35 ~ 2.857143 */
+ if(hx<0&&ix>=0x40180000) return two-tiny;/* x < -6 */
+ R=rb0+s*(rb1+s*(rb2+s*(rb3+s*(rb4+s*(
+ rb5+s*rb6)))));
+ S=one+s*(sb1+s*(sb2+s*(sb3+s*(sb4+s*(
+ sb5+s*(sb6+s*sb7))))));
+ }
+ z = x;
+ __LO(z) = 0;
+ r = __ieee754_exp(-z*z-0.5625)*
+ __ieee754_exp((z-x)*(z+x)+R/S);
+ if(hx>0) return r/x; else return two-r/x;
+ } else {
+ if(hx>0) return tiny*tiny; else return two-tiny;
+ }
+}
--- /dev/null
+++ b/libmath/fdlibm/s_expm1.c
@@ -1,0 +1,208 @@
+/* derived from /netlib/fdlibm */
+
+/* @(#)s_expm1.c 1.3 95/01/18 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunSoft, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+/* expm1(x)
+ * Returns exp(x)-1, the exponential of x minus 1.
+ *
+ * Method
+ * 1. Argument reduction:
+ * Given x, find r and integer k such that
+ *
+ * x = k*ln2 + r, |r| <= 0.5*ln2 ~ 0.34658
+ *
+ * Here a correction term c will be computed to compensate
+ * the error in r when rounded to a floating-point number.
+ *
+ * 2. Approximating expm1(r) by a special rational function on
+ * the interval [0,0.34658]:
+ * Since
+ * r*(exp(r)+1)/(exp(r)-1) = 2+ r^2/6 - r^4/360 + ...
+ * we define R1(r*r) by
+ * r*(exp(r)+1)/(exp(r)-1) = 2+ r^2/6 * R1(r*r)
+ * That is,
+ * R1(r**2) = 6/r *((exp(r)+1)/(exp(r)-1) - 2/r)
+ * = 6/r * ( 1 + 2.0*(1/(exp(r)-1) - 1/r))
+ * = 1 - r^2/60 + r^4/2520 - r^6/100800 + ...
+ * We use a special Reme algorithm on [0,0.347] to generate
+ * a polynomial of degree 5 in r*r to approximate R1. The
+ * maximum error of this polynomial approximation is bounded
+ * by 2**-61. In other words,
+ * R1(z) ~ 1.0 + Q1*z + Q2*z**2 + Q3*z**3 + Q4*z**4 + Q5*z**5
+ * where Q1 = -1.6666666666666567384E-2,
+ * Q2 = 3.9682539681370365873E-4,
+ * Q3 = -9.9206344733435987357E-6,
+ * Q4 = 2.5051361420808517002E-7,
+ * Q5 = -6.2843505682382617102E-9;
+ * (where z=r*r, and the values of Q1 to Q5 are listed below)
+ * with error bounded by
+ * | 5 | -61
+ * | 1.0+Q1*z+...+Q5*z - R1(z) | <= 2
+ * | |
+ *
+ * expm1(r) = exp(r)-1 is then computed by the following
+ * specific way which minimize the accumulation rounding error:
+ * 2 3
+ * r r [ 3 - (R1 + R1*r/2) ]
+ * expm1(r) = r + --- + --- * [--------------------]
+ * 2 2 [ 6 - r*(3 - R1*r/2) ]
+ *
+ * To compensate the error in the argument reduction, we use
+ * expm1(r+c) = expm1(r) + c + expm1(r)*c
+ * ~ expm1(r) + c + r*c
+ * Thus c+r*c will be added in as the correction terms for
+ * expm1(r+c). Now rearrange the term to avoid optimization
+ * screw up:
+ * ( 2 2 )
+ * ({ ( r [ R1 - (3 - R1*r/2) ] ) } r )
+ * expm1(r+c)~r - ({r*(--- * [--------------------]-c)-c} - --- )
+ * ({ ( 2 [ 6 - r*(3 - R1*r/2) ] ) } 2 )
+ * ( )
+ *
+ * = r - E
+ * 3. Scale back to obtain expm1(x):
+ * From step 1, we have
+ * expm1(x) = either 2^k*[expm1(r)+1] - 1
+ * = or 2^k*[expm1(r) + (1-2^-k)]
+ * 4. Implementation notes:
+ * (A). To save one multiplication, we scale the coefficient Qi
+ * to Qi*2^i, and replace z by (x^2)/2.
+ * (B). To achieve maximum accuracy, we compute expm1(x) by
+ * (i) if x < -56*ln2, return -1.0, (raise inexact if x!=inf)
+ * (ii) if k=0, return r-E
+ * (iii) if k=-1, return 0.5*(r-E)-0.5
+ * (iv) if k=1 if r < -0.25, return 2*((r+0.5)- E)
+ * else return 1.0+2.0*(r-E);
+ * (v) if (k<-2||k>56) return 2^k(1-(E-r)) - 1 (or exp(x)-1)
+ * (vi) if k <= 20, return 2^k((1-2^-k)-(E-r)), else
+ * (vii) return 2^k(1-((E+2^-k)-r))
+ *
+ * Special cases:
+ * expm1(INF) is INF, expm1(NaN) is NaN;
+ * expm1(-INF) is -1, and
+ * for finite argument, only expm1(0)=0 is exact.
+ *
+ * Accuracy:
+ * according to an error analysis, the error is always less than
+ * 1 ulp (unit in the last place).
+ *
+ * Misc. info.
+ * For IEEE double
+ * if x > 7.09782712893383973096e+02 then expm1(x) overflow
+ *
+ * Constants:
+ * The hexadecimal values are the intended ones for the following
+ * constants. The decimal values may be used, provided that the
+ * compiler will convert from decimal to binary accurately enough
+ * to produce the hexadecimal values shown.
+ */
+
+#include "fdlibm.h"
+
+static const double
+one = 1.0,
+Huge = 1.0e+300,
+tiny = 1.0e-300,
+o_threshold = 7.09782712893383973096e+02,/* 0x40862E42, 0xFEFA39EF */
+ln2_hi = 6.93147180369123816490e-01,/* 0x3fe62e42, 0xfee00000 */
+ln2_lo = 1.90821492927058770002e-10,/* 0x3dea39ef, 0x35793c76 */
+invln2 = 1.44269504088896338700e+00,/* 0x3ff71547, 0x652b82fe */
+ /* scaled coefficients related to expm1 */
+Q1 = -3.33333333333331316428e-02, /* BFA11111 111110F4 */
+Q2 = 1.58730158725481460165e-03, /* 3F5A01A0 19FE5585 */
+Q3 = -7.93650757867487942473e-05, /* BF14CE19 9EAADBB7 */
+Q4 = 4.00821782732936239552e-06, /* 3ED0CFCA 86E65239 */
+Q5 = -2.01099218183624371326e-07; /* BE8AFDB7 6E09C32D */
+
+ double expm1(double x)
+{
+ double y,hi,lo,c,t,e,hxs,hfx,r1;
+ int k,xsb;
+ unsigned hx;
+
+ hx = __HI(x); /* high word of x */
+ xsb = hx&0x80000000; /* sign bit of x */
+ if(xsb==0) y=x; else y= -x; /* y = |x| */
+ hx &= 0x7fffffff; /* high word of |x| */
+
+ /* filter out Huge and non-finite argument */
+ if(hx >= 0x4043687A) { /* if |x|>=56*ln2 */
+ if(hx >= 0x40862E42) { /* if |x|>=709.78... */
+ if(hx>=0x7ff00000) {
+ if(((hx&0xfffff)|__LO(x))!=0)
+ return x+x; /* NaN */
+ else return (xsb==0)? x:-1.0;/* exp(+-inf)={inf,-1} */
+ }
+ if(x > o_threshold) return Huge*Huge; /* overflow */
+ }
+ if(xsb!=0) { /* x < -56*ln2, return -1.0 with inexact */
+ if(x+tiny<0.0) /* raise inexact */
+ return tiny-one; /* return -1 */
+ }
+ }
+
+ /* argument reduction */
+ if(hx > 0x3fd62e42) { /* if |x| > 0.5 ln2 */
+ if(hx < 0x3FF0A2B2) { /* and |x| < 1.5 ln2 */
+ if(xsb==0)
+ {hi = x - ln2_hi; lo = ln2_lo; k = 1;}
+ else
+ {hi = x + ln2_hi; lo = -ln2_lo; k = -1;}
+ } else {
+ k = invln2*x+((xsb==0)?0.5:-0.5);
+ t = k;
+ hi = x - t*ln2_hi; /* t*ln2_hi is exact here */
+ lo = t*ln2_lo;
+ }
+ x = hi - lo;
+ c = (hi-x)-lo;
+ }
+ else if(hx < 0x3c900000) { /* when |x|<2**-54, return x */
+ t = Huge+x; /* return x with inexact flags when x!=0 */
+ return x - (t-(Huge+x));
+ }
+ else k = 0;
+
+ /* x is now in primary range */
+ hfx = 0.5*x;
+ hxs = x*hfx;
+ r1 = one+hxs*(Q1+hxs*(Q2+hxs*(Q3+hxs*(Q4+hxs*Q5))));
+ t = 3.0-r1*hfx;
+ e = hxs*((r1-t)/(6.0 - x*t));
+ if(k==0) return x - (x*e-hxs); /* c is 0 */
+ else {
+ e = (x*(e-c)-c);
+ e -= hxs;
+ if(k== -1) return 0.5*(x-e)-0.5;
+ if(k==1)
+ if(x < -0.25) return -2.0*(e-(x+0.5));
+ else return one+2.0*(x-e);
+ if (k <= -2 || k>56) { /* suffice to return exp(x)-1 */
+ y = one-(e-x);
+ __HI(y) += (k<<20); /* add k to y's exponent */
+ return y-one;
+ }
+ t = one;
+ if(k<20) {
+ __HI(t) = 0x3ff00000 - (0x200000>>k); /* t=1-2^-k */
+ y = t-(e-x);
+ __HI(y) += (k<<20); /* add k to y's exponent */
+ } else {
+ __HI(t) = ((0x3ff-k)<<20); /* 2^-k */
+ y = x-(e+t);
+ y += one;
+ __HI(y) += (k<<20); /* add k to y's exponent */
+ }
+ }
+ return y;
+}
--- /dev/null
+++ b/libmath/fdlibm/s_fabs.c
@@ -1,0 +1,25 @@
+/* derived from /netlib/fdlibm */
+
+/* @(#)s_fabs.c 1.3 95/01/18 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunSoft, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+/*
+ * fabs(x) returns the absolute value of x.
+ */
+
+#include "fdlibm.h"
+
+ double fabs(double x)
+{
+ __HI(x) &= 0x7fffffff;
+ return x;
+}
--- /dev/null
+++ b/libmath/fdlibm/s_finite.c
@@ -1,0 +1,27 @@
+/* derived from /netlib/fdlibm */
+
+/* @(#)s_finite.c 1.3 95/01/18 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunSoft, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+/*
+ * finite(x) returns 1 is x is finite, else 0;
+ * no branching!
+ */
+
+#include "fdlibm.h"
+
+ int finite(double x)
+{
+ int hx;
+ hx = __HI(x);
+ return (unsigned)((hx&0x7fffffff)-0x7ff00000)>>31;
+}
--- /dev/null
+++ b/libmath/fdlibm/s_floor.c
@@ -1,0 +1,71 @@
+/* derived from /netlib/fdlibm */
+
+/* @(#)s_floor.c 1.3 95/01/18 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunSoft, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+/*
+ * floor(x)
+ * Return x rounded toward -inf to integral value
+ * Method:
+ * Bit twiddling.
+ * Exception:
+ * Inexact flag raised if x not equal to floor(x).
+ */
+
+#include "fdlibm.h"
+
+static const double Huge = 1.0e300;
+
+ double floor(double x)
+{
+ int i0,i1,j0;
+ unsigned i,j;
+ i0 = __HI(x);
+ i1 = __LO(x);
+ j0 = ((i0>>20)&0x7ff)-0x3ff;
+ if(j0<20) {
+ if(j0<0) { /* raise inexact if x != 0 */
+ if(Huge+x>0.0) {/* return 0*sign(x) if |x|<1 */
+ if(i0>=0) {i0=i1=0;}
+ else if(((i0&0x7fffffff)|i1)!=0)
+ { i0=0xbff00000;i1=0;}
+ }
+ } else {
+ i = (0x000fffff)>>j0;
+ if(((i0&i)|i1)==0) return x; /* x is integral */
+ if(Huge+x>0.0) { /* raise inexact flag */
+ if(i0<0) i0 += (0x00100000)>>j0;
+ i0 &= (~i); i1=0;
+ }
+ }
+ } else if (j0>51) {
+ if(j0==0x400) return x+x; /* inf or NaN */
+ else return x; /* x is integral */
+ } else {
+ i = ((unsigned)(0xffffffff))>>(j0-20);
+ if((i1&i)==0) return x; /* x is integral */
+ if(Huge+x>0.0) { /* raise inexact flag */
+ if(i0<0) {
+ if(j0==20) i0+=1;
+ else {
+ j = i1+(1<<(52-j0));
+ if(j<i1) i0 +=1 ; /* got a carry */
+ i1=j;
+ }
+ }
+ i1 &= (~i);
+ }
+ }
+ __HI(x) = i0;
+ __LO(x) = i1;
+ return x;
+}
--- /dev/null
+++ b/libmath/fdlibm/s_ilogb.c
@@ -1,0 +1,42 @@
+/* derived from /netlib/fdlibm */
+
+/* @(#)s_ilogb.c 1.3 95/01/18 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunSoft, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+/* ilogb(double x)
+ * return the binary exponent of non-zero x
+ * ilogb(0) = 0x80000001
+ * ilogb(inf/NaN) = 0x7fffffff (no signal is raised)
+ */
+
+#include "fdlibm.h"
+
+ int ilogb(double x)
+{
+ int hx,lx,ix;
+
+ hx = (__HI(x))&0x7fffffff; /* high word of x */
+ if(hx<0x00100000) {
+ lx = __LO(x);
+ if((hx|lx)==0)
+ return 0x80000001; /* ilogb(0) = 0x80000001 */
+ else /* subnormal x */
+ if(hx==0) {
+ for (ix = -1043; lx>0; lx<<=1) ix -=1;
+ } else {
+ for (ix = -1022,hx<<=11; hx>0; hx<<=1) ix -=1;
+ }
+ return ix;
+ }
+ else if (hx<0x7ff00000) return (hx>>20)-1023;
+ else return 0x7fffffff;
+}
--- /dev/null
+++ b/libmath/fdlibm/s_isnan.c
@@ -1,0 +1,30 @@
+/* derived from /netlib/fdlibm */
+
+/* @(#)s_isnan.c 1.3 95/01/18 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunSoft, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+/*
+ * isnan(x) returns 1 is x is nan, else 0;
+ * no branching!
+ */
+
+#include "fdlibm.h"
+
+ int isnan(double x)
+{
+ int hx,lx;
+ hx = (__HI(x)&0x7fffffff);
+ lx = __LO(x);
+ hx |= (unsigned)(lx|(-lx))>>31;
+ hx = 0x7ff00000 - hx;
+ return ((unsigned)(hx))>>31;
+}
--- /dev/null
+++ b/libmath/fdlibm/s_log1p.c
@@ -1,0 +1,157 @@
+/* derived from /netlib/fdlibm */
+
+/* @(#)s_log1p.c 1.3 95/01/18 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunSoft, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+/* double log1p(double x)
+ *
+ * Method :
+ * 1. Argument Reduction: find k and f such that
+ * 1+x = 2^k * (1+f),
+ * where sqrt(2)/2 < 1+f < sqrt(2) .
+ *
+ * Note. If k=0, then f=x is exact. However, if k!=0, then f
+ * may not be representable exactly. In that case, a correction
+ * term is need. Let u=1+x rounded. Let c = (1+x)-u, then
+ * log(1+x) - log(u) ~ c/u. Thus, we proceed to compute log(u),
+ * and add back the correction term c/u.
+ * (Note: when x > 2**53, one can simply return log(x))
+ *
+ * 2. Approximation of log1p(f).
+ * Let s = f/(2+f) ; based on log(1+f) = log(1+s) - log(1-s)
+ * = 2s + 2/3 s**3 + 2/5 s**5 + .....,
+ * = 2s + s*R
+ * We use a special Reme algorithm on [0,0.1716] to generate
+ * a polynomial of degree 14 to approximate R The maximum error
+ * of this polynomial approximation is bounded by 2**-58.45. In
+ * other words,
+ * 2 4 6 8 10 12 14
+ * R(z) ~ Lp1*s +Lp2*s +Lp3*s +Lp4*s +Lp5*s +Lp6*s +Lp7*s
+ * (the values of Lp1 to Lp7 are listed in the program)
+ * and
+ * | 2 14 | -58.45
+ * | Lp1*s +...+Lp7*s - R(z) | <= 2
+ * | |
+ * Note that 2s = f - s*f = f - hfsq + s*hfsq, where hfsq = f*f/2.
+ * In order to guarantee error in log below 1ulp, we compute log
+ * by
+ * log1p(f) = f - (hfsq - s*(hfsq+R)).
+ *
+ * 3. Finally, log1p(x) = k*ln2 + log1p(f).
+ * = k*ln2_hi+(f-(hfsq-(s*(hfsq+R)+k*ln2_lo)))
+ * Here ln2 is split into two floating point number:
+ * ln2_hi + ln2_lo,
+ * where n*ln2_hi is always exact for |n| < 2000.
+ *
+ * Special cases:
+ * log1p(x) is NaN with signal if x < -1 (including -INF) ;
+ * log1p(+INF) is +INF; log1p(-1) is -INF with signal;
+ * log1p(NaN) is that NaN with no signal.
+ *
+ * Accuracy:
+ * according to an error analysis, the error is always less than
+ * 1 ulp (unit in the last place).
+ *
+ * Constants:
+ * The hexadecimal values are the intended ones for the following
+ * constants. The decimal values may be used, provided that the
+ * compiler will convert from decimal to binary accurately enough
+ * to produce the hexadecimal values shown.
+ *
+ * Note: Assuming log() return accurate answer, the following
+ * algorithm can be used to compute log1p(x) to within a few ULP:
+ *
+ * u = 1+x;
+ * if(u==1.0) return x ; else
+ * return log(u)*(x/(u-1.0));
+ *
+ * See HP-15C Advanced Functions Handbook, p.193.
+ */
+
+#include "fdlibm.h"
+
+static const double
+ln2_hi = 6.93147180369123816490e-01, /* 3fe62e42 fee00000 */
+ln2_lo = 1.90821492927058770002e-10, /* 3dea39ef 35793c76 */
+two54 = 1.80143985094819840000e+16, /* 43500000 00000000 */
+Lp1 = 6.666666666666735130e-01, /* 3FE55555 55555593 */
+Lp2 = 3.999999999940941908e-01, /* 3FD99999 9997FA04 */
+Lp3 = 2.857142874366239149e-01, /* 3FD24924 94229359 */
+Lp4 = 2.222219843214978396e-01, /* 3FCC71C5 1D8E78AF */
+Lp5 = 1.818357216161805012e-01, /* 3FC74664 96CB03DE */
+Lp6 = 1.531383769920937332e-01, /* 3FC39A09 D078C69F */
+Lp7 = 1.479819860511658591e-01; /* 3FC2F112 DF3E5244 */
+
+static double zero = 0.0;
+
+ double log1p(double x)
+{
+ double hfsq,f,c,s,z,R,u;
+ int k,hx,hu,ax;
+
+ hx = __HI(x); /* high word of x */
+ ax = hx&0x7fffffff;
+
+ k = 1;
+ if (hx < 0x3FDA827A) { /* x < 0.41422 */
+ if(ax>=0x3ff00000) { /* x <= -1.0 */
+ if(x==-1.0) return -two54/zero; /* log1p(-1)=+inf */
+ else return (x-x)/(x-x); /* log1p(x<-1)=NaN */
+ }
+ if(ax<0x3e200000) { /* |x| < 2**-29 */
+ if(two54+x>zero /* raise inexact */
+ &&ax<0x3c900000) /* |x| < 2**-54 */
+ return x;
+ else
+ return x - x*x*0.5;
+ }
+ if(hx>0||hx<=((int)0xbfd2bec3)) {
+ k=0;f=x;hu=1;} /* -0.2929<x<0.41422 */
+ }
+ if (hx >= 0x7ff00000) return x+x;
+ if(k!=0) {
+ if(hx<0x43400000) {
+ u = 1.0+x;
+ hu = __HI(u); /* high word of u */
+ k = (hu>>20)-1023;
+ c = (k>0)? 1.0-(u-x):x-(u-1.0);/* correction term */
+ c /= u;
+ } else {
+ u = x;
+ hu = __HI(u); /* high word of u */
+ k = (hu>>20)-1023;
+ c = 0;
+ }
+ hu &= 0x000fffff;
+ if(hu<0x6a09e) {
+ __HI(u) = hu|0x3ff00000; /* normalize u */
+ } else {
+ k += 1;
+ __HI(u) = hu|0x3fe00000; /* normalize u/2 */
+ hu = (0x00100000-hu)>>2;
+ }
+ f = u-1.0;
+ }
+ hfsq=0.5*f*f;
+ if(hu==0) { /* |f| < 2**-20 */
+ if(f==zero) if(k==0) return zero;
+ else {c += k*ln2_lo; return k*ln2_hi+c;}
+ R = hfsq*(1.0-0.66666666666666666*f);
+ if(k==0) return f-R; else
+ return k*ln2_hi-((R-(k*ln2_lo+c))-f);
+ }
+ s = f/(2.0+f);
+ z = s*s;
+ R = z*(Lp1+z*(Lp2+z*(Lp3+z*(Lp4+z*(Lp5+z*(Lp6+z*Lp7))))));
+ if(k==0) return f-(hfsq-s*(hfsq+R)); else
+ return k*ln2_hi-((hfsq-(s*(hfsq+R)+(k*ln2_lo+c)))-f);
+}
--- /dev/null
+++ b/libmath/fdlibm/s_modf.c
@@ -1,0 +1,72 @@
+/* derived from /netlib/fdlibm */
+
+/* @(#)s_modf.c 1.3 95/01/18 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunSoft, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+/*
+ * modf(double x, double *iptr)
+ * return fraction part of x, and return x's integral part in *iptr.
+ * Method:
+ * Bit twiddling.
+ *
+ * Exception:
+ * No exception.
+ */
+
+#include "fdlibm.h"
+
+static const double one = 1.0;
+
+ double modf(double x, double *iptr)
+{
+ int i0,i1,j0;
+ unsigned i;
+ i0 = __HI(x); /* high x */
+ i1 = __LO(x); /* low x */
+ j0 = ((i0>>20)&0x7ff)-0x3ff; /* exponent of x */
+ if(j0<20) { /* integer part in high x */
+ if(j0<0) { /* |x|<1 */
+ __HIp(iptr) = i0&0x80000000;
+ __LOp(iptr) = 0; /* *iptr = +-0 */
+ return x;
+ } else {
+ i = (0x000fffff)>>j0;
+ if(((i0&i)|i1)==0) { /* x is integral */
+ *iptr = x;
+ __HI(x) &= 0x80000000;
+ __LO(x) = 0; /* return +-0 */
+ return x;
+ } else {
+ __HIp(iptr) = i0&(~i);
+ __LOp(iptr) = 0;
+ return x - *iptr;
+ }
+ }
+ } else if (j0>51) { /* no fraction part */
+ *iptr = x*one;
+ __HI(x) &= 0x80000000;
+ __LO(x) = 0; /* return +-0 */
+ return x;
+ } else { /* fraction part in low x */
+ i = ((unsigned)(0xffffffff))>>(j0-20);
+ if((i1&i)==0) { /* x is integral */
+ *iptr = x;
+ __HI(x) &= 0x80000000;
+ __LO(x) = 0; /* return +-0 */
+ return x;
+ } else {
+ __HIp(iptr) = i0;
+ __LOp(iptr) = i1&(~i);
+ return x - *iptr;
+ }
+ }
+}
--- /dev/null
+++ b/libmath/fdlibm/s_nextafter.c
@@ -1,0 +1,74 @@
+/* derived from /netlib/fdlibm */
+
+/* @(#)s_nextafter.c 1.3 95/01/18 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunSoft, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+/* IEEE functions
+ * nextafter(x,y)
+ * return the next machine floating-point number of x in the
+ * direction toward y.
+ * Special cases:
+ */
+
+#include "fdlibm.h"
+
+ double nextafter(double x, double y)
+{
+ int hx,hy,ix,iy;
+ unsigned lx,ly;
+
+ hx = __HI(x); /* high word of x */
+ lx = __LO(x); /* low word of x */
+ hy = __HI(y); /* high word of y */
+ ly = __LO(y); /* low word of y */
+ ix = hx&0x7fffffff; /* |x| */
+ iy = hy&0x7fffffff; /* |y| */
+
+ if(((ix>=0x7ff00000)&&((ix-0x7ff00000)|lx)!=0) || /* x is nan */
+ ((iy>=0x7ff00000)&&((iy-0x7ff00000)|ly)!=0)) /* y is nan */
+ return x+y;
+ if(x==y) return x; /* x=y, return x */
+ if((ix|lx)==0) { /* x == 0 */
+ __HI(x) = hy&0x80000000; /* return +-minsubnormal */
+ __LO(x) = 1;
+ y = x*x;
+ if(y==x) return y; else return x; /* raise underflow flag */
+ }
+ if(hx>=0) { /* x > 0 */
+ if(hx>hy||((hx==hy)&&(lx>ly))) { /* x > y, x -= ulp */
+ if(lx==0) hx -= 1;
+ lx -= 1;
+ } else { /* x < y, x += ulp */
+ lx += 1;
+ if(lx==0) hx += 1;
+ }
+ } else { /* x < 0 */
+ if(hy>=0||hx>hy||((hx==hy)&&(lx>ly))){/* x < y, x -= ulp */
+ if(lx==0) hx -= 1;
+ lx -= 1;
+ } else { /* x > y, x += ulp */
+ lx += 1;
+ if(lx==0) hx += 1;
+ }
+ }
+ hy = hx&0x7ff00000;
+ if(hy>=0x7ff00000) return x+x; /* overflow */
+ if(hy<0x00100000) { /* underflow */
+ y = x*x;
+ if(y!=x) { /* raise underflow flag */
+ __HI(y) = hx; __LO(y) = lx;
+ return y;
+ }
+ }
+ __HI(x) = hx; __LO(x) = lx;
+ return x;
+}
--- /dev/null
+++ b/libmath/fdlibm/s_rint.c
@@ -1,0 +1,88 @@
+/* derived from /netlib/fdlibm */
+
+/* @(#)s_rint.c 1.3 95/01/18 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunSoft, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+/* dummy routine to get around over-eager arm compiler optimization.
+ * Calling this causes a store and reload of floating point numbers
+ */
+
+void
+dummy(void)
+{
+}
+
+
+/*
+ * rint(x)
+ * Return x rounded to integral value according to the prevailing
+ * rounding mode.
+ * Method:
+ * Using floating addition.
+ * Exception:
+ * Inexact flag raised if x not equal to rint(x).
+ */
+
+#include "fdlibm.h"
+
+static const double
+TWO52[2]={
+ 4.50359962737049600000e+15, /* 0x43300000, 0x00000000 */
+ -4.50359962737049600000e+15, /* 0xC3300000, 0x00000000 */
+};
+
+ double rint(double x)
+{
+ int i0,j0,sx;
+ unsigned i,i1;
+ double w,t;
+ i0 = __HI(x);
+ sx = (i0>>31)&1;
+ i1 = __LO(x);
+ j0 = ((i0>>20)&0x7ff)-0x3ff;
+ if(j0<20) {
+ if(j0<0) {
+ if(((i0&0x7fffffff)|i1)==0) return x;
+ i1 |= (i0&0x0fffff);
+ i0 &= 0xfffe0000;
+ i0 |= ((i1|-i1)>>12)&0x80000;
+ __HI(x)=i0;
+ w = TWO52[sx]+x;
+ dummy(); /* fix optimiser */
+ t = w-TWO52[sx];
+ i0 = __HI(t);
+ __HI(t) = (i0&0x7fffffff)|(sx<<31);
+ return t;
+ } else {
+ i = (0x000fffff)>>j0;
+ if(((i0&i)|i1)==0) return x; /* x is integral */
+ i>>=1;
+ if(((i0&i)|i1)!=0) {
+ if(j0==19) i1 = 0x40000000; else
+ i0 = (i0&(~i))|((0x20000)>>j0);
+ }
+ }
+ } else if (j0>51) {
+ if(j0==0x400) return x+x; /* inf or NaN */
+ else return x; /* x is integral */
+ } else {
+ i = ((unsigned)(0xffffffff))>>(j0-20);
+ if((i1&i)==0) return x; /* x is integral */
+ i>>=1;
+ if((i1&i)!=0) i1 = (i1&(~i))|((0x40000000)>>(j0-20));
+ }
+ __HI(x) = i0;
+ __LO(x) = i1;
+ w = TWO52[sx]+x;
+ dummy(); /* fix optimiser */
+ return w-TWO52[sx];
+}
--- /dev/null
+++ b/libmath/fdlibm/s_scalbn.c
@@ -1,0 +1,55 @@
+/* derived from /netlib/fdlibm */
+
+/* @(#)s_scalbn.c 1.3 95/01/18 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunSoft, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+/*
+ * scalbn (double x, int n)
+ * scalbn(x,n) returns x* 2**n computed by exponent
+ * manipulation rather than by actually performing an
+ * exponentiation or a multiplication.
+ */
+
+#include "fdlibm.h"
+
+static const double
+two54 = 1.80143985094819840000e+16, /* 0x43500000, 0x00000000 */
+twom54 = 5.55111512312578270212e-17, /* 0x3C900000, 0x00000000 */
+Huge = 1.0e+300,
+tiny = 1.0e-300;
+
+ double scalbn (double x, int n)
+{
+ int k,hx,lx;
+ hx = __HI(x);
+ lx = __LO(x);
+ k = (hx&0x7ff00000)>>20; /* extract exponent */
+ if (k==0) { /* 0 or subnormal x */
+ if ((lx|(hx&0x7fffffff))==0) return x; /* +-0 */
+ x *= two54;
+ hx = __HI(x);
+ k = ((hx&0x7ff00000)>>20) - 54;
+ if (n< -50000) return tiny*x; /*underflow*/
+ }
+ if (k==0x7ff) return x+x; /* NaN or Inf */
+ k = k+n;
+ if (k > 0x7fe) return Huge*copysign(Huge,x); /* overflow */
+ if (k > 0) /* normal result */
+ {__HI(x) = (hx&0x800fffff)|(k<<20); return x;}
+ if (k <= -54)
+ if (n > 50000) /* in case integer overflow in n+k */
+ return Huge*copysign(Huge,x); /*overflow*/
+ else return tiny*copysign(tiny,x); /*underflow*/
+ k += 54; /* subnormal result */
+ __HI(x) = (hx&0x800fffff)|(k<<20);
+ return x*twom54;
+}
--- /dev/null
+++ b/libmath/fdlibm/s_sin.c
@@ -1,0 +1,74 @@
+/* derived from /netlib/fdlibm */
+
+/* @(#)s_sin.c 1.3 95/01/18 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunSoft, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+/* sin(x)
+ * Return sine function of x.
+ *
+ * kernel function:
+ * __kernel_sin ... sine function on [-pi/4,pi/4]
+ * __kernel_cos ... cose function on [-pi/4,pi/4]
+ * __ieee754_rem_pio2 ... argument reduction routine
+ *
+ * Method.
+ * Let S,C and T denote the sin, cos and tan respectively on
+ * [-PI/4, +PI/4]. Reduce the argument x to y1+y2 = x-k*pi/2
+ * in [-pi/4 , +pi/4], and let n = k mod 4.
+ * We have
+ *
+ * n sin(x) cos(x) tan(x)
+ * ----------------------------------------------------------
+ * 0 S C T
+ * 1 C -S -1/T
+ * 2 -S -C T
+ * 3 -C S -1/T
+ * ----------------------------------------------------------
+ *
+ * Special cases:
+ * Let trig be any of sin, cos, or tan.
+ * trig(+-INF) is NaN, with signals;
+ * trig(NaN) is that NaN;
+ *
+ * Accuracy:
+ * TRIG(x) returns trig(x) nearly rounded
+ */
+
+#include "fdlibm.h"
+
+ double sin(double x)
+{
+ double y[2],z=0.0;
+ int n, ix;
+
+ /* High word of x. */
+ ix = __HI(x);
+
+ /* |x| ~< pi/4 */
+ ix &= 0x7fffffff;
+ if(ix <= 0x3fe921fb) return __kernel_sin(x,z,0);
+
+ /* sin(Inf or NaN) is NaN */
+ else if (ix>=0x7ff00000) return x-x;
+
+ /* argument reduction needed */
+ else {
+ n = __ieee754_rem_pio2(x,y);
+ switch(n&3) {
+ case 0: return __kernel_sin(y[0],y[1],1);
+ case 1: return __kernel_cos(y[0],y[1]);
+ case 2: return -__kernel_sin(y[0],y[1],1);
+ default:
+ return -__kernel_cos(y[0],y[1]);
+ }
+ }
+}
--- /dev/null
+++ b/libmath/fdlibm/s_tan.c
@@ -1,0 +1,68 @@
+/* derived from /netlib/fdlibm */
+
+/* @(#)s_tan.c 1.3 95/01/18 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunSoft, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+/* tan(x)
+ * Return tangent function of x.
+ *
+ * kernel function:
+ * __kernel_tan ... tangent function on [-pi/4,pi/4]
+ * __ieee754_rem_pio2 ... argument reduction routine
+ *
+ * Method.
+ * Let S,C and T denote the sin, cos and tan respectively on
+ * [-PI/4, +PI/4]. Reduce the argument x to y1+y2 = x-k*pi/2
+ * in [-pi/4 , +pi/4], and let n = k mod 4.
+ * We have
+ *
+ * n sin(x) cos(x) tan(x)
+ * ----------------------------------------------------------
+ * 0 S C T
+ * 1 C -S -1/T
+ * 2 -S -C T
+ * 3 -C S -1/T
+ * ----------------------------------------------------------
+ *
+ * Special cases:
+ * Let trig be any of sin, cos, or tan.
+ * trig(+-INF) is NaN, with signals;
+ * trig(NaN) is that NaN;
+ *
+ * Accuracy:
+ * TRIG(x) returns trig(x) nearly rounded
+ */
+
+#include "fdlibm.h"
+
+ double tan(double x)
+{
+ double y[2],z=0.0;
+ int n, ix;
+
+ /* High word of x. */
+ ix = __HI(x);
+
+ /* |x| ~< pi/4 */
+ ix &= 0x7fffffff;
+ if(ix <= 0x3fe921fb) return __kernel_tan(x,z,1);
+
+ /* tan(Inf or NaN) is NaN */
+ else if (ix>=0x7ff00000) return x-x; /* NaN */
+
+ /* argument reduction needed */
+ else {
+ n = __ieee754_rem_pio2(x,y);
+ return __kernel_tan(y[0],y[1],1-((n&1)<<1)); /* 1 -- n even
+ -1 -- n odd */
+ }
+}
--- /dev/null
+++ b/libmath/fdlibm/s_tanh.c
@@ -1,0 +1,74 @@
+/* derived from /netlib/fdlibm */
+
+/* @(#)s_tanh.c 1.3 95/01/18 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunSoft, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+/* Tanh(x)
+ * Return the Hyperbolic Tangent of x
+ *
+ * Method :
+ * x -x
+ * e - e
+ * 0. tanh(x) is defined to be -----------
+ * x -x
+ * e + e
+ * 1. reduce x to non-negative by tanh(-x) = -tanh(x).
+ * 2. 0 <= x <= 2**-55 : tanh(x) := x*(one+x)
+ * -t
+ * 2**-55 < x <= 1 : tanh(x) := -----; t = expm1(-2x)
+ * t + 2
+ * 2
+ * 1 <= x <= 22.0 : tanh(x) := 1- ----- ; t=expm1(2x)
+ * t + 2
+ * 22.0 < x <= INF : tanh(x) := 1.
+ *
+ * Special cases:
+ * tanh(NaN) is NaN;
+ * only tanh(0)=0 is exact for finite argument.
+ */
+
+#include "fdlibm.h"
+
+static const double one=1.0, two=2.0, tiny = 1.0e-300;
+
+ double tanh(double x)
+{
+ double t,z;
+ int jx,ix;
+
+ /* High word of |x|. */
+ jx = __HI(x);
+ ix = jx&0x7fffffff;
+
+ /* x is INF or NaN */
+ if(ix>=0x7ff00000) {
+ if (jx>=0) return one/x+one; /* tanh(+-inf)=+-1 */
+ else return one/x-one; /* tanh(NaN) = NaN */
+ }
+
+ /* |x| < 22 */
+ if (ix < 0x40360000) { /* |x|<22 */
+ if (ix<0x3c800000) /* |x|<2**-55 */
+ return x*(one+x); /* tanh(small) = small */
+ if (ix>=0x3ff00000) { /* |x|>=1 */
+ t = expm1(two*fabs(x));
+ z = one - two/(t+two);
+ } else {
+ t = expm1(-two*fabs(x));
+ z= -t/(t+two);
+ }
+ /* |x| > 22, return +-1 */
+ } else {
+ z = one - tiny; /* raised inexact flag */
+ }
+ return (jx>=0)? z: -z;
+}
--- /dev/null
+++ b/libmath/g_fmt.c
@@ -1,0 +1,106 @@
+/****************************************************************
+ *
+ * The author of this software is David M. Gay.
+ *
+ * Copyright (c) 1991, 1996 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 AUTHOR NOR LUCENT MAKES ANY
+ * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
+ * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
+ *
+ ***************************************************************/
+
+/* g_fmt(buf,x) stores the closest decimal approximation to x in buf;
+ * it suffices to declare buf
+ * char buf[32];
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+ extern char *dtoa(double, int, int, int *, int *, char **);
+ extern char *g_fmt(char *, double, int);
+ extern void freedtoa(char*);
+#ifdef __cplusplus
+ }
+#endif
+
+ char *
+g_fmt(register char *b, double x, int echr)
+{
+ register int i, k;
+ register char *s;
+ int decpt, j, sign;
+ char *b0, *s0, *se;
+
+ b0 = b;
+#ifdef IGNORE_ZERO_SIGN
+ if (!x) {
+ *b++ = '0';
+ *b = 0;
+ goto done;
+ }
+#endif
+ s = s0 = dtoa(x, 0, 0, &decpt, &sign, &se);
+ if (sign)
+ *b++ = '-';
+ if (decpt == 9999) /* Infinity or Nan */ {
+ while(*b++ = *s++);
+ goto done0;
+ }
+ if (decpt <= -4 || decpt > se - s + 5) {
+ *b++ = *s++;
+ if (*s) {
+ *b++ = '.';
+ while(*b = *s++)
+ b++;
+ }
+ *b++ = echr;
+ /* sprintf(b, "%+.2d", decpt - 1); */
+ if (--decpt < 0) {
+ *b++ = '-';
+ decpt = -decpt;
+ }
+ else
+ *b++ = '+';
+ for(j = 2, k = 10; 10*k <= decpt; j++, k *= 10);
+ for(;;) {
+ i = decpt / k;
+ *b++ = i + '0';
+ if (--j <= 0)
+ break;
+ decpt -= i*k;
+ decpt *= 10;
+ }
+ *b = 0;
+ }
+ else if (decpt <= 0) {
+ *b++ = '.';
+ for(; decpt < 0; decpt++)
+ *b++ = '0';
+ while(*b++ = *s++);
+ }
+ else {
+ while(*b = *s++) {
+ b++;
+ if (--decpt == 0 && *s)
+ *b++ = '.';
+ }
+ for(; decpt > 0; decpt--)
+ *b++ = '0';
+ *b = 0;
+ }
+ done0:
+ freedtoa(s0);
+#ifdef IGNORE_ZERO_SIGN
+ done:
+#endif
+ return b0;
+ }
--- /dev/null
+++ b/libmath/gemm.c
@@ -1,0 +1,167 @@
+#include "lib9.h"
+#include "mathi.h"
+void
+gemm(int transa, int transb, int m, int n, int k, double alpha,
+ double *a, int lda,
+ double *b, int ldb, double beta,
+ double *c, int ldc)
+{
+ int i1, i2, i3, nota, notb, i, j, jb, jc, l, la;
+ double temp;
+
+ nota = transa=='N';
+ notb = transb=='N';
+
+ if(m == 0 || n == 0 || (alpha == 0. || k == 0) && beta == 1.){
+ return;
+ }
+ if(alpha == 0.){
+ if(beta == 0.){
+ i1 = n;
+ for(j = 0; j < i1; ++j){
+ jc = j*ldc;
+ i2 = m;
+ for(i = 0; i < i2; ++i){
+ c[i + jc] = 0.;
+ }
+ }
+ }else{
+ i1 = n;
+ for(j = 0; j < i1; ++j){
+ jc = j*ldc;
+ i2 = m;
+ for(i = 0; i < i2; ++i){
+ c[i + jc] = beta * c[i + jc];
+ }
+ }
+ }
+ return;
+ }
+
+ if(!a){
+ if(notb){ /* C := alpha*B + beta*C. */
+ i1 = n;
+ for(j = 0; j < i1; ++j){
+ jb = j*ldb;
+ jc = j*ldc;
+ i2 = m;
+ for(i = 0; i < i2; ++i){
+ c[i + jc] = alpha*b[i+jb] + beta*c[i+jc];
+ }
+ }
+ }else{ /* C := alpha*B' + beta*C. */
+ i1 = n;
+ for(j = 0; j < i1; ++j){
+ jc = j*ldc;
+ i2 = m;
+ for(i = 0; i < i2; ++i){
+ c[i + jc] = alpha*b[j+i*ldb] + beta*c[i+jc];
+ }
+ }
+ }
+ return;
+ }
+
+ if(notb){
+ if(nota){
+
+/* Form C := alpha*A*B + beta*C. */
+ i1 = n;
+ for(j = 0; j < i1; ++j){
+ jc = j*ldc;
+ if(beta == 0.){
+ i2 = m;
+ for(i = 0; i < i2; ++i){
+ c[i + jc] = 0.;
+ }
+ }else if(beta != 1.){
+ i2 = m;
+ for(i = 0; i < i2; ++i){
+ c[i + jc] = beta * c[i + jc];
+ }
+ }
+ i2 = k;
+ for(l = 0; l < i2; ++l){
+ la = l*lda;
+ if(b[l + j*ldb] != 0.){
+ temp = alpha * b[l + j*ldb];
+ i3 = m;
+ for(i = 0; i < i3; ++i){
+ c[i + jc] += temp * a[i + la];
+ }
+ }
+ }
+ }
+ }else{
+
+/* Form C := alpha*A'*B + beta*C */
+ i1 = n;
+ for(j = 0; j < i1; ++j){
+ jc = j*ldc;
+ i2 = m;
+ for(i = 0; i < i2; ++i){
+ temp = 0.;
+ i3 = k;
+ for(l = 0; l < i3; ++l){
+ temp += a[l + i*lda] * b[l + j*ldb];
+ }
+ if(beta == 0.){
+ c[i + jc] = alpha * temp;
+ }else{
+ c[i + jc] = alpha * temp + beta * c[i + jc];
+ }
+ }
+ }
+ }
+ }else{
+ if(nota){
+
+/* Form C := alpha*A*B' + beta*C */
+ i1 = n;
+ for(j = 0; j < i1; ++j){
+ jc = j*ldc;
+ if(beta == 0.){
+ i2 = m;
+ for(i = 0; i < i2; ++i){
+ c[i + jc] = 0.;
+ }
+ }else if(beta != 1.){
+ i2 = m;
+ for(i = 0; i < i2; ++i){
+ c[i + jc] = beta * c[i + jc];
+ }
+ }
+ i2 = k;
+ for(l = 0; l < i2; ++l){
+ if(b[j + l*ldb] != 0.){
+ temp = alpha * b[j + l*ldb];
+ i3 = m;
+ for(i = 0; i < i3; ++i){
+ c[i + jc] += temp * a[i + l*lda];
+ }
+ }
+ }
+ }
+ }else{
+
+/* Form C := alpha*A'*B' + beta*C */
+ i1 = n;
+ for(j = 0; j < i1; ++j){
+ jc = j*ldc;
+ i2 = m;
+ for(i = 0; i < i2; ++i){
+ temp = 0.;
+ i3 = k;
+ for(l = 0; l < i3; ++l){
+ temp += a[l + i*lda] * b[j + l*ldb];
+ }
+ if(beta == 0.){
+ c[i + jc] = alpha * temp;
+ }else{
+ c[i + jc] = alpha * temp + beta * c[i + jc];
+ }
+ }
+ }
+ }
+ }
+}
--- /dev/null
+++ b/libmath/gfltconv.c
@@ -1,0 +1,123 @@
+#include "lib9.h"
+#include "mathi.h"
+extern char *dtoa(double, int, int, int *, int *, char **);
+extern void freedtoa(char*);
+extern int _fmtcpy(Fmt*, void*, int, int);
+
+enum
+{
+ NONE = -1000,
+ FDIGIT = 20,
+ FDEFLT = 6,
+ NSIGNIF = 17
+};
+
+int
+gfltconv(Fmt *f)
+{
+ int flags = f->flags;
+ int precision;
+ int fmt = f->r;
+ double d;
+ int echr, exponent, sign, ndig, nout, i;
+ char *digits, *edigits, ebuf[32], *eptr;
+ char out[64], *pout;
+
+ d = va_arg(f->args, double);
+ echr = 'e';
+ precision = FDEFLT;
+ if(f->flags & FmtPrec)
+ precision = f->prec;
+ if(precision > FDIGIT)
+ precision = FDIGIT;
+ switch(fmt){
+ case 'f':
+ digits = dtoa(d, 3, precision, &exponent, &sign, &edigits);
+ break;
+ case 0x00c9: /* L'É' */
+ case 'E':
+ echr = 'E';
+ fmt = 'e';
+ /* fall through */
+ case 'e':
+ digits = dtoa(d, 2, 1+precision, &exponent, &sign, &edigits);
+ break;
+ case 'G':
+ echr = 'E';
+ /* fall through */
+ default:
+ case 'g':
+ if((flags&(FmtWidth|FmtPrec)) == 0){
+ g_fmt(out, d, echr);
+ f->flags &= FmtWidth|FmtLeft;
+ return _fmtcpy(f, out, strlen(out), strlen(out));
+ }
+ if (precision > 0)
+ digits = dtoa(d, 2, precision, &exponent, &sign, &edigits);
+ else {
+ digits = dtoa(d, 0, precision, &exponent, &sign, &edigits);
+ precision = edigits - digits;
+ if (exponent > precision && exponent <= precision + 4)
+ precision = exponent;
+ }
+ if(exponent >= -3 && exponent <= precision){
+ fmt = 'f';
+ precision -= exponent;
+ }else{
+ fmt = 'e';
+ --precision;
+ }
+ break;
+ }
+ if (exponent == 9999) {
+ /* Infinity or Nan */
+ precision = 0;
+ exponent = edigits - digits;
+ fmt = 'f';
+ }
+ ndig = edigits-digits;
+ if((f->r=='g' || f->r=='G') && !(flags&FmtSharp)){ /* knock off trailing zeros */
+ if(fmt == 'f'){
+ if(precision+exponent > ndig) {
+ precision = ndig - exponent;
+ if(precision < 0)
+ precision = 0;
+ }
+ }
+ else{
+ if(precision > ndig-1) precision = ndig-1;
+ }
+ }
+ eptr = ebuf;
+ if(fmt != 'f'){ /* exponent */
+ for(i=exponent<=0?1-exponent:exponent-1; i; i/=10)
+ *eptr++ = '0' + i%10;
+ while(eptr<ebuf+2) *eptr++ = '0';
+ }
+ pout = out;
+ if(sign) *pout++ = '-';
+ else if(flags&FmtSign) *pout++ = '+';
+ else if(flags&FmtSpace) *pout++ = ' ';
+ if(fmt == 'f'){
+ for(i=0; i<exponent; i++) *pout++ = i<ndig?digits[i]:'0';
+ if(i == 0) *pout++ = '0';
+ if(precision>0 || flags&FmtSharp) *pout++ = '.';
+ for(i=0; i!=precision; i++)
+ *pout++ = 0<=i+exponent && i+exponent<ndig?digits[i+exponent]:'0';
+ }
+ else{
+ *pout++ = digits[0];
+ if(precision>0 || flags&FmtSharp) *pout++ = '.';
+ for(i=0; i!=precision; i++) *pout++ = i<ndig-1?digits[i+1]:'0';
+ }
+ if(fmt != 'f'){
+ *pout++ = echr;
+ *pout++ = exponent<=0?'-':'+';
+ while(eptr>ebuf) *pout++ = *--eptr;
+ }
+ *pout = 0;
+ freedtoa(digits);
+ f->flags &= FmtWidth|FmtLeft;
+ nout = pout-out;
+ return _fmtcpy(f, out, nout, nout);
+}
--- /dev/null
+++ b/libmath/mkfile
@@ -1,0 +1,66 @@
+<../mkconfig
+
+TARGTYPE=${SYSTARG:os%=Inferno%} # maps 'os' into 'Inferno'
+
+LIB=libmath.a
+OFILES=\
+ blas.$O\
+ dtoa.$O\
+ fdim.$O\
+ FPcontrol-$TARGTYPE.$O\
+ gemm.$O\
+ g_fmt.$O\
+ gfltconv.$O\
+ pow10.$O\
+ e_acos.$O\
+ e_acosh.$O\
+ e_asin.$O\
+ e_atan2.$O\
+ e_atanh.$O\
+ e_cosh.$O\
+ e_exp.$O\
+ e_fmod.$O\
+ e_hypot.$O\
+ e_j0.$O\
+ e_j1.$O\
+ e_jn.$O\
+ e_lgamma_r.$O\
+ e_log.$O\
+ e_log10.$O\
+ e_pow.$O\
+ e_rem_pio2.$O\
+ e_remainder.$O\
+ e_sinh.$O\
+ e_sqrt.$O\
+ k_cos.$O\
+ k_rem_pio2.$O\
+ k_sin.$O\
+ k_tan.$O\
+ s_asinh.$O\
+ s_atan.$O\
+ s_cbrt.$O\
+ s_ceil.$O\
+ s_copysign.$O\
+ s_cos.$O\
+ s_erf.$O\
+ s_expm1.$O\
+ s_fabs.$O\
+ s_finite.$O\
+ s_floor.$O\
+ s_ilogb.$O\
+ s_log1p.$O\
+ s_nextafter.$O\
+ s_rint.$O\
+ s_scalbn.$O\
+ s_sin.$O\
+ s_tan.$O\
+ s_tanh.$O\
+
+HFILES=\
+ $ROOT/include/mathi.h\
+ fdlibm/fdlibm.h\
+
+<$ROOT/mkfiles/mksyslib-$SHELLTYPE
+
+%.$O: fdlibm/%.c
+ $CC $CFLAGS -o $target -Ifdlibm fdlibm/$stem.c
--- /dev/null
+++ b/libmath/pow10.c
@@ -1,0 +1,8 @@
+#include "lib9.h"
+#include "mathi.h"
+
+double
+ipow10(int n)
+{
+ return pow(10.,n);
+}
--- /dev/null
+++ b/libmemdraw/NOTICE
@@ -1,0 +1,29 @@
+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-2007 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.
+
--- /dev/null
+++ b/libmemdraw/alloc.c
@@ -1,0 +1,194 @@
+#include "lib9.h"
+#include "draw.h"
+#include "memdraw.h"
+#include "pool.h"
+
+extern Pool* imagmem;
+
+void
+memimagemove(void *from, void *to)
+{
+ Memdata *md;
+
+ md = *(Memdata**)to;
+ if(md->base != from){
+ print("compacted data not right: #%p\n", md->base);
+ abort();
+ }
+ md->base = to;
+
+ /* if allocmemimage changes this must change too */
+ md->bdata = (uchar*)&md->base[2];
+}
+
+Memimage*
+allocmemimaged(Rectangle r, ulong chan, Memdata *md)
+{
+ int d;
+ ulong l;
+ Memimage *i;
+
+ if((d = chantodepth(chan)) == 0) {
+ werrstr("bad channel descriptor %.8lux", chan);
+ return nil;
+ }
+
+ l = wordsperline(r, d);
+
+ i = mallocz(sizeof(Memimage), 1);
+ if(i == nil)
+ return nil;
+
+ i->data = md;
+ i->zero = sizeof(ulong)*l*r.min.y;
+
+ if(r.min.x >= 0)
+ i->zero += (r.min.x*d)/8;
+ else
+ i->zero -= (-r.min.x*d+7)/8;
+ i->zero = -i->zero;
+ i->width = l;
+ i->r = r;
+ i->clipr = r;
+ i->flags = 0;
+ i->layer = nil;
+ i->cmap = memdefcmap;
+ if(memsetchan(i, chan) < 0){
+ free(i);
+ return nil;
+ }
+ return i;
+}
+
+Memimage*
+allocmemimage(Rectangle r, ulong chan)
+{
+ int d;
+ ulong l, nw;
+ Memdata *md;
+ Memimage *i;
+
+ if((d = chantodepth(chan)) == 0) {
+ werrstr("bad channel descriptor %.8lux", chan);
+ return nil;
+ }
+
+ l = wordsperline(r, d);
+ nw = l*Dy(r);
+ md = malloc(sizeof(Memdata));
+ if(md == nil)
+ return nil;
+
+ md->ref = 1;
+ md->base = poolalloc(imagmem, (2+nw)*sizeof(ulong));
+ if(md->base == nil){
+ free(md);
+ return nil;
+ }
+
+ md->base[0] = (ulong)md;
+ /* md->base[1] = getcallerpc(&r); */
+
+ /* if this changes, memimagemove must change too */
+ md->bdata = (uchar*)&md->base[2];
+
+ md->allocd = 1;
+
+ i = allocmemimaged(r, chan, md);
+ if(i == nil){
+ poolfree(imagmem, md->base);
+ free(md);
+ return nil;
+ }
+ md->imref = i;
+ return i;
+}
+
+void
+freememimage(Memimage *i)
+{
+ if(i == nil)
+ return;
+ if(i->data->ref-- == 1 && i->data->allocd){
+ if(i->data->base)
+ poolfree(imagmem, i->data->base);
+ free(i->data);
+ }
+ free(i);
+}
+
+/*
+ * Wordaddr is deprecated.
+ */
+ulong*
+wordaddr(Memimage *i, Point p)
+{
+ return (ulong*) ((ulong)byteaddr(i, p) & ~(sizeof(ulong)-1));
+}
+
+uchar*
+byteaddr(Memimage *i, Point p)
+{
+ uchar *a;
+
+ a = i->data->bdata+i->zero+sizeof(ulong)*p.y*i->width;
+
+ if(i->depth < 8){
+ /*
+ * We need to always round down,
+ * but C rounds toward zero.
+ */
+ int np;
+ np = 8/i->depth;
+ if(p.x < 0)
+ return a+(p.x-np+1)/np;
+ else
+ return a+p.x/np;
+ }
+ else
+ return a+p.x*(i->depth/8);
+}
+
+int
+memsetchan(Memimage *i, ulong chan)
+{
+ int d;
+ int t, j, k;
+ ulong cc;
+ int bytes;
+
+ if((d = chantodepth(chan)) == 0) {
+ werrstr("bad channel descriptor");
+ return -1;
+ }
+
+ i->depth = d;
+ i->chan = chan;
+ i->flags &= ~(Fgrey|Falpha|Fcmap|Fbytes);
+ bytes = 1;
+ for(cc=chan, j=0, k=0; cc; j+=NBITS(cc), cc>>=8, k++){
+ t=TYPE(cc);
+ if(t < 0 || t >= NChan){
+ werrstr("bad channel string");
+ return -1;
+ }
+ if(t == CGrey)
+ i->flags |= Fgrey;
+ if(t == CAlpha)
+ i->flags |= Falpha;
+ if(t == CMap && i->cmap == nil){
+ i->cmap = memdefcmap;
+ i->flags |= Fcmap;
+ }
+
+ i->shift[t] = j;
+ i->mask[t] = (1<<NBITS(cc))-1;
+ i->nbits[t] = NBITS(cc);
+ if(NBITS(cc) != 8)
+ bytes = 0;
+ }
+ i->nchan = k;
+ if(bytes)
+ i->flags |= Fbytes;
+ return 0;
+}
--- /dev/null
+++ b/libmemdraw/arc.c
@@ -1,0 +1,116 @@
+#include "lib9.h"
+#include "draw.h"
+#include "memdraw.h"
+#include "memlayer.h"
+
+/*
+ * elarc(dst,c,a,b,t,src,sp,alpha,phi)
+ * draws the part of an ellipse between rays at angles alpha and alpha+phi
+ * measured counterclockwise from the positive x axis. other
+ * arguments are as for ellipse(dst,c,a,b,t,src,sp)
+ */
+
+enum
+{
+ R, T, L, B /* right, top, left, bottom */
+};
+
+static
+Point corners[] = {
+ {1,1},
+ {-1,1},
+ {-1,-1},
+ {1,-1}
+};
+
+static
+Point p00;
+
+/*
+ * make a "wedge" mask covering the desired angle and contained in
+ * a surrounding square; draw a full ellipse; intersect that with the
+ * wedge to make a mask through which to copy src to dst.
+ */
+void
+memarc(Memimage *dst, Point c, int a, int b, int t, Memimage *src, Point sp, int alpha, int phi, int op)
+{
+ int i, w, beta, tmp, c1, c2, m, m1;
+ Rectangle rect;
+ Point p, bnd[8];
+ Memimage *wedge, *figure, *mask;
+
+ if(a < 0)
+ a = -a;
+ if(b < 0)
+ b = -b;
+ w = t;
+ if(w < 0)
+ w = 0;
+ alpha = -alpha; /* compensate for upside-down coords */
+ phi = -phi;
+ beta = alpha + phi;
+ if(phi < 0){
+ tmp = alpha;
+ alpha = beta;
+ beta = tmp;
+ phi = -phi;
+ }
+ if(phi >= 360){
+ memellipse(dst, c, a, b, t, src, sp, op);
+ return;
+ }
+ while(alpha < 0)
+ alpha += 360;
+ while(beta < 0)
+ beta += 360;
+ c1 = alpha/90 & 3; /* number of nearest corner */
+ c2 = beta/90 & 3;
+ /*
+ * icossin returns point at radius ICOSSCALE.
+ * multiplying by m1 moves it outside the ellipse
+ */
+ rect = Rect(-a-w, -b-w, a+w+1, b+w+1);
+ m = rect.max.x; /* inradius of bounding square */
+ if(m < rect.max.y)
+ m = rect.max.y;
+ m1 = (m+ICOSSCALE-1) >> 10;
+ m = m1 << 10; /* assure m1*cossin is inside */
+ i = 0;
+ bnd[i++] = Pt(0,0);
+ icossin(alpha, &p.x, &p.y);
+ bnd[i++] = mulpt(p, m1);
+ for(;;) {
+ bnd[i++] = mulpt(corners[c1], m);
+ if(c1==c2 && phi<180)
+ break;
+ c1 = (c1+1) & 3;
+ phi -= 90;
+ }
+ icossin(beta, &p.x, &p.y);
+ bnd[i++] = mulpt(p, m1);
+
+ figure = nil;
+ mask = nil;
+ wedge = allocmemimage(rect, GREY1);
+ if(wedge == nil)
+ goto Return;
+ memfillcolor(wedge, DTransparent);
+ memfillpoly(wedge, bnd, i, ~0, memopaque, p00, S);
+ figure = allocmemimage(rect, GREY1);
+ if(figure == nil)
+ goto Return;
+ memfillcolor(figure, DTransparent);
+ memellipse(figure, p00, a, b, t, memopaque, p00, S);
+ mask = allocmemimage(rect, GREY1);
+ if(mask == nil)
+ goto Return;
+ memfillcolor(mask, DTransparent);
+ memimagedraw(mask, rect, figure, rect.min, wedge, rect.min, S);
+ c = subpt(c, dst->r.min);
+ memdraw(dst, dst->r, src, subpt(sp, c), mask, subpt(p00, c), op);
+
+ Return:
+ freememimage(wedge);
+ freememimage(figure);
+ freememimage(mask);
+}
--- /dev/null
+++ b/libmemdraw/cload.c
@@ -1,0 +1,67 @@
+#include "lib9.h"
+#include "draw.h"
+#include "memdraw.h"
+
+int
+cloadmemimage(Memimage *i, Rectangle r, uchar *data, int ndata)
+{
+ int y, bpl, c, cnt, offs;
+ uchar mem[NMEM], *memp, *omemp, *emem, *linep, *elinep, *u, *eu;
+
+ if(!rectinrect(r, i->r))
+ return -1;
+ bpl = bytesperline(r, i->depth);
+ u = data;
+ eu = data+ndata;
+ memp = mem;
+ emem = mem+NMEM;
+ y = r.min.y;
+ linep = byteaddr(i, Pt(r.min.x, y));
+ elinep = linep+bpl;
+ for(;;){
+ if(linep == elinep){
+ if(++y == r.max.y)
+ break;
+ linep = byteaddr(i, Pt(r.min.x, y));
+ elinep = linep+bpl;
+ }
+ if(u == eu){ /* buffer too small */
+ return -1;
+ }
+ c = *u++;
+ if(c >= 128){
+ for(cnt=c-128+1; cnt!=0 ;--cnt){
+ if(u == eu){ /* buffer too small */
+ return -1;
+ }
+ if(linep == elinep){ /* phase error */
+ return -1;
+ }
+ *linep++ = *u;
+ *memp++ = *u++;
+ if(memp == emem)
+ memp = mem;
+ }
+ }
+ else{
+ if(u == eu) /* short buffer */
+ return -1;
+ offs = *u++ + ((c&3)<<8)+1;
+ if(memp-mem < offs)
+ omemp = memp+(NMEM-offs);
+ else
+ omemp = memp-offs;
+ for(cnt=(c>>2)+NMATCH; cnt!=0; --cnt){
+ if(linep == elinep) /* phase error */
+ return -1;
+ *linep++ = *omemp;
+ *memp++ = *omemp++;
+ if(omemp == emem)
+ omemp = mem;
+ if(memp == emem)
+ memp = mem;
+ }
+ }
+ }
+ return u-data;
+}
--- /dev/null
+++ b/libmemdraw/cmap.c
@@ -1,0 +1,316 @@
+#include "lib9.h"
+#include <draw.h>
+#include <memdraw.h>
+
+static Memcmap def = {
+/* cmap2rgb */ {
+ 0x00,0x00,0x00,0x00,0x00,0x44,0x00,0x00,0x88,0x00,0x00,0xcc,0x00,0x44,0x00,0x00,
+ 0x44,0x44,0x00,0x44,0x88,0x00,0x44,0xcc,0x00,0x88,0x00,0x00,0x88,0x44,0x00,0x88,
+ 0x88,0x00,0x88,0xcc,0x00,0xcc,0x00,0x00,0xcc,0x44,0x00,0xcc,0x88,0x00,0xcc,0xcc,
+ 0x00,0xdd,0xdd,0x11,0x11,0x11,0x00,0x00,0x55,0x00,0x00,0x99,0x00,0x00,0xdd,0x00,
+ 0x55,0x00,0x00,0x55,0x55,0x00,0x4c,0x99,0x00,0x49,0xdd,0x00,0x99,0x00,0x00,0x99,
+ 0x4c,0x00,0x99,0x99,0x00,0x93,0xdd,0x00,0xdd,0x00,0x00,0xdd,0x49,0x00,0xdd,0x93,
+ 0x00,0xee,0x9e,0x00,0xee,0xee,0x22,0x22,0x22,0x00,0x00,0x66,0x00,0x00,0xaa,0x00,
+ 0x00,0xee,0x00,0x66,0x00,0x00,0x66,0x66,0x00,0x55,0xaa,0x00,0x4f,0xee,0x00,0xaa,
+ 0x00,0x00,0xaa,0x55,0x00,0xaa,0xaa,0x00,0x9e,0xee,0x00,0xee,0x00,0x00,0xee,0x4f,
+ 0x00,0xff,0x55,0x00,0xff,0xaa,0x00,0xff,0xff,0x33,0x33,0x33,0x00,0x00,0x77,0x00,
+ 0x00,0xbb,0x00,0x00,0xff,0x00,0x77,0x00,0x00,0x77,0x77,0x00,0x5d,0xbb,0x00,0x55,
+ 0xff,0x00,0xbb,0x00,0x00,0xbb,0x5d,0x00,0xbb,0xbb,0x00,0xaa,0xff,0x00,0xff,0x00,
+ 0x44,0x00,0x44,0x44,0x00,0x88,0x44,0x00,0xcc,0x44,0x44,0x00,0x44,0x44,0x44,0x44,
+ 0x44,0x88,0x44,0x44,0xcc,0x44,0x88,0x00,0x44,0x88,0x44,0x44,0x88,0x88,0x44,0x88,
+ 0xcc,0x44,0xcc,0x00,0x44,0xcc,0x44,0x44,0xcc,0x88,0x44,0xcc,0xcc,0x44,0x00,0x00,
+ 0x55,0x00,0x00,0x55,0x00,0x55,0x4c,0x00,0x99,0x49,0x00,0xdd,0x55,0x55,0x00,0x55,
+ 0x55,0x55,0x4c,0x4c,0x99,0x49,0x49,0xdd,0x4c,0x99,0x00,0x4c,0x99,0x4c,0x4c,0x99,
+ 0x99,0x49,0x93,0xdd,0x49,0xdd,0x00,0x49,0xdd,0x49,0x49,0xdd,0x93,0x49,0xdd,0xdd,
+ 0x4f,0xee,0xee,0x66,0x00,0x00,0x66,0x00,0x66,0x55,0x00,0xaa,0x4f,0x00,0xee,0x66,
+ 0x66,0x00,0x66,0x66,0x66,0x55,0x55,0xaa,0x4f,0x4f,0xee,0x55,0xaa,0x00,0x55,0xaa,
+ 0x55,0x55,0xaa,0xaa,0x4f,0x9e,0xee,0x4f,0xee,0x00,0x4f,0xee,0x4f,0x4f,0xee,0x9e,
+ 0x55,0xff,0xaa,0x55,0xff,0xff,0x77,0x00,0x00,0x77,0x00,0x77,0x5d,0x00,0xbb,0x55,
+ 0x00,0xff,0x77,0x77,0x00,0x77,0x77,0x77,0x5d,0x5d,0xbb,0x55,0x55,0xff,0x5d,0xbb,
+ 0x00,0x5d,0xbb,0x5d,0x5d,0xbb,0xbb,0x55,0xaa,0xff,0x55,0xff,0x00,0x55,0xff,0x55,
+ 0x88,0x00,0x88,0x88,0x00,0xcc,0x88,0x44,0x00,0x88,0x44,0x44,0x88,0x44,0x88,0x88,
+ 0x44,0xcc,0x88,0x88,0x00,0x88,0x88,0x44,0x88,0x88,0x88,0x88,0x88,0xcc,0x88,0xcc,
+ 0x00,0x88,0xcc,0x44,0x88,0xcc,0x88,0x88,0xcc,0xcc,0x88,0x00,0x00,0x88,0x00,0x44,
+ 0x99,0x00,0x4c,0x99,0x00,0x99,0x93,0x00,0xdd,0x99,0x4c,0x00,0x99,0x4c,0x4c,0x99,
+ 0x4c,0x99,0x93,0x49,0xdd,0x99,0x99,0x00,0x99,0x99,0x4c,0x99,0x99,0x99,0x93,0x93,
+ 0xdd,0x93,0xdd,0x00,0x93,0xdd,0x49,0x93,0xdd,0x93,0x93,0xdd,0xdd,0x99,0x00,0x00,
+ 0xaa,0x00,0x00,0xaa,0x00,0x55,0xaa,0x00,0xaa,0x9e,0x00,0xee,0xaa,0x55,0x00,0xaa,
+ 0x55,0x55,0xaa,0x55,0xaa,0x9e,0x4f,0xee,0xaa,0xaa,0x00,0xaa,0xaa,0x55,0xaa,0xaa,
+ 0xaa,0x9e,0x9e,0xee,0x9e,0xee,0x00,0x9e,0xee,0x4f,0x9e,0xee,0x9e,0x9e,0xee,0xee,
+ 0xaa,0xff,0xff,0xbb,0x00,0x00,0xbb,0x00,0x5d,0xbb,0x00,0xbb,0xaa,0x00,0xff,0xbb,
+ 0x5d,0x00,0xbb,0x5d,0x5d,0xbb,0x5d,0xbb,0xaa,0x55,0xff,0xbb,0xbb,0x00,0xbb,0xbb,
+ 0x5d,0xbb,0xbb,0xbb,0xaa,0xaa,0xff,0xaa,0xff,0x00,0xaa,0xff,0x55,0xaa,0xff,0xaa,
+ 0xcc,0x00,0xcc,0xcc,0x44,0x00,0xcc,0x44,0x44,0xcc,0x44,0x88,0xcc,0x44,0xcc,0xcc,
+ 0x88,0x00,0xcc,0x88,0x44,0xcc,0x88,0x88,0xcc,0x88,0xcc,0xcc,0xcc,0x00,0xcc,0xcc,
+ 0x44,0xcc,0xcc,0x88,0xcc,0xcc,0xcc,0xcc,0x00,0x00,0xcc,0x00,0x44,0xcc,0x00,0x88,
+ 0xdd,0x00,0x93,0xdd,0x00,0xdd,0xdd,0x49,0x00,0xdd,0x49,0x49,0xdd,0x49,0x93,0xdd,
+ 0x49,0xdd,0xdd,0x93,0x00,0xdd,0x93,0x49,0xdd,0x93,0x93,0xdd,0x93,0xdd,0xdd,0xdd,
+ 0x00,0xdd,0xdd,0x49,0xdd,0xdd,0x93,0xdd,0xdd,0xdd,0xdd,0x00,0x00,0xdd,0x00,0x49,
+ 0xee,0x00,0x4f,0xee,0x00,0x9e,0xee,0x00,0xee,0xee,0x4f,0x00,0xee,0x4f,0x4f,0xee,
+ 0x4f,0x9e,0xee,0x4f,0xee,0xee,0x9e,0x00,0xee,0x9e,0x4f,0xee,0x9e,0x9e,0xee,0x9e,
+ 0xee,0xee,0xee,0x00,0xee,0xee,0x4f,0xee,0xee,0x9e,0xee,0xee,0xee,0xee,0x00,0x00,
+ 0xff,0x00,0x00,0xff,0x00,0x55,0xff,0x00,0xaa,0xff,0x00,0xff,0xff,0x55,0x00,0xff,
+ 0x55,0x55,0xff,0x55,0xaa,0xff,0x55,0xff,0xff,0xaa,0x00,0xff,0xaa,0x55,0xff,0xaa,
+ 0xaa,0xff,0xaa,0xff,0xff,0xff,0x00,0xff,0xff,0x55,0xff,0xff,0xaa,0xff,0xff,0xff,
+},
+/* rgb2cmap */ {
+ 0x00,0x00,0x11,0x01,0x01,0x12,0x23,0x34,0x02,0x13,0x24,0x35,0x03,0x14,0x25,0x36,
+ 0x00,0x11,0x11,0x01,0x01,0x12,0x23,0x34,0x02,0x13,0x24,0x35,0x03,0x14,0x25,0x36,
+ 0x11,0x11,0x11,0x01,0x01,0x12,0x23,0x34,0x02,0x13,0x24,0x35,0x03,0x14,0x25,0x36,
+ 0x04,0x04,0x04,0x05,0x05,0x05,0x05,0x06,0x06,0x06,0x17,0x07,0x07,0x18,0x18,0x29,
+ 0x04,0x04,0x04,0x05,0x05,0x05,0x16,0x06,0x06,0x17,0x28,0x07,0x07,0x18,0x29,0x3a,
+ 0x15,0x15,0x15,0x05,0x05,0x16,0x16,0x06,0x06,0x17,0x28,0x39,0x07,0x18,0x29,0x3a,
+ 0x26,0x26,0x26,0x05,0x16,0x16,0x27,0x27,0x38,0x28,0x28,0x39,0x39,0x29,0x29,0x3a,
+ 0x37,0x37,0x37,0x09,0x09,0x09,0x27,0x38,0x0a,0x0a,0x39,0x0b,0x0b,0x0b,0x1c,0x3a,
+ 0x08,0x08,0x08,0x09,0x09,0x09,0x38,0x0a,0x0a,0x0a,0x1b,0x0b,0x0b,0x1c,0x1c,0x2d,
+ 0x19,0x19,0x19,0x09,0x1a,0x1a,0x2b,0x0a,0x0a,0x1b,0x1b,0x0b,0x0b,0x1c,0x2d,0x3e,
+ 0x2a,0x2a,0x2a,0x1a,0x2b,0x2b,0x2b,0x3c,0x1b,0x1b,0x2c,0x2c,0x3d,0x2d,0x2d,0x3e,
+ 0x3b,0x3b,0x3b,0x0d,0x0d,0x3c,0x3c,0x0e,0x0e,0x0e,0x2c,0x3d,0x0f,0x0f,0x3e,0x3e,
+ 0x0c,0x0c,0x0c,0x0d,0x0d,0x0d,0x3c,0x0e,0x0e,0x0e,0x3d,0x0f,0x0f,0x0f,0x10,0x3e,
+ 0x1d,0x1d,0x1d,0x1e,0x1e,0x1e,0x2f,0x0e,0x1f,0x1f,0x20,0x0f,0x0f,0x10,0x10,0x21,
+ 0x2e,0x2e,0x2e,0x1e,0x2f,0x2f,0x2f,0x1f,0x1f,0x20,0x20,0x31,0x10,0x10,0x21,0x21,
+ 0x3f,0x3f,0x3f,0x2f,0x30,0x30,0x30,0x30,0x20,0x31,0x31,0x31,0x31,0x21,0x21,0x32,
+ 0x00,0x11,0x11,0x01,0x01,0x12,0x23,0x34,0x02,0x13,0x24,0x35,0x03,0x14,0x25,0x36,
+ 0x11,0x11,0x11,0x01,0x01,0x12,0x23,0x34,0x02,0x13,0x24,0x35,0x03,0x14,0x25,0x36,
+ 0x11,0x11,0x22,0x22,0x01,0x12,0x23,0x34,0x02,0x13,0x24,0x35,0x03,0x14,0x25,0x36,
+ 0x04,0x04,0x22,0x05,0x05,0x05,0x05,0x06,0x06,0x06,0x17,0x07,0x07,0x18,0x18,0x29,
+ 0x04,0x04,0x04,0x05,0x05,0x05,0x16,0x06,0x06,0x17,0x28,0x07,0x07,0x18,0x29,0x3a,
+ 0x15,0x15,0x15,0x05,0x05,0x16,0x16,0x06,0x06,0x17,0x28,0x39,0x07,0x18,0x29,0x3a,
+ 0x26,0x26,0x26,0x05,0x16,0x16,0x27,0x27,0x38,0x28,0x28,0x39,0x39,0x29,0x29,0x3a,
+ 0x37,0x37,0x37,0x09,0x09,0x09,0x27,0x38,0x0a,0x0a,0x39,0x0b,0x0b,0x0b,0x1c,0x3a,
+ 0x08,0x08,0x08,0x09,0x09,0x09,0x38,0x0a,0x0a,0x0a,0x1b,0x0b,0x0b,0x1c,0x1c,0x2d,
+ 0x19,0x19,0x19,0x09,0x1a,0x1a,0x2b,0x0a,0x0a,0x1b,0x1b,0x0b,0x0b,0x1c,0x2d,0x3e,
+ 0x2a,0x2a,0x2a,0x1a,0x2b,0x2b,0x2b,0x3c,0x1b,0x1b,0x2c,0x2c,0x3d,0x2d,0x2d,0x3e,
+ 0x3b,0x3b,0x3b,0x0d,0x0d,0x3c,0x3c,0x0e,0x0e,0x0e,0x2c,0x3d,0x0f,0x0f,0x3e,0x3e,
+ 0x0c,0x0c,0x0c,0x0d,0x0d,0x0d,0x3c,0x0e,0x0e,0x0e,0x3d,0x0f,0x0f,0x0f,0x10,0x3e,
+ 0x1d,0x1d,0x1d,0x1e,0x1e,0x1e,0x2f,0x0e,0x1f,0x1f,0x20,0x0f,0x0f,0x10,0x10,0x21,
+ 0x2e,0x2e,0x2e,0x1e,0x2f,0x2f,0x2f,0x1f,0x1f,0x20,0x20,0x31,0x10,0x10,0x21,0x21,
+ 0x3f,0x3f,0x3f,0x2f,0x30,0x30,0x30,0x30,0x20,0x31,0x31,0x31,0x31,0x21,0x21,0x32,
+ 0x11,0x11,0x11,0x01,0x01,0x12,0x23,0x34,0x02,0x13,0x24,0x35,0x03,0x14,0x25,0x36,
+ 0x11,0x11,0x22,0x22,0x01,0x12,0x23,0x34,0x02,0x13,0x24,0x35,0x03,0x14,0x25,0x36,
+ 0x11,0x22,0x22,0x22,0x33,0x33,0x23,0x34,0x02,0x13,0x24,0x35,0x03,0x14,0x25,0x36,
+ 0x04,0x22,0x22,0x33,0x33,0x33,0x05,0x06,0x06,0x06,0x17,0x07,0x07,0x18,0x18,0x29,
+ 0x04,0x04,0x33,0x33,0x33,0x05,0x16,0x06,0x06,0x17,0x28,0x07,0x07,0x18,0x29,0x3a,
+ 0x15,0x15,0x33,0x33,0x05,0x16,0x16,0x06,0x06,0x17,0x28,0x39,0x07,0x18,0x29,0x3a,
+ 0x26,0x26,0x26,0x05,0x16,0x16,0x27,0x27,0x38,0x28,0x28,0x39,0x39,0x29,0x29,0x3a,
+ 0x37,0x37,0x37,0x09,0x09,0x09,0x27,0x38,0x0a,0x0a,0x39,0x0b,0x0b,0x0b,0x1c,0x3a,
+ 0x08,0x08,0x08,0x09,0x09,0x09,0x38,0x0a,0x0a,0x0a,0x1b,0x0b,0x0b,0x1c,0x1c,0x2d,
+ 0x19,0x19,0x19,0x09,0x1a,0x1a,0x2b,0x0a,0x0a,0x1b,0x1b,0x0b,0x0b,0x1c,0x2d,0x3e,
+ 0x2a,0x2a,0x2a,0x1a,0x2b,0x2b,0x2b,0x3c,0x1b,0x1b,0x2c,0x2c,0x3d,0x2d,0x2d,0x3e,
+ 0x3b,0x3b,0x3b,0x0d,0x0d,0x3c,0x3c,0x0e,0x0e,0x0e,0x2c,0x3d,0x0f,0x0f,0x3e,0x3e,
+ 0x0c,0x0c,0x0c,0x0d,0x0d,0x0d,0x3c,0x0e,0x0e,0x0e,0x3d,0x0f,0x0f,0x0f,0x10,0x3e,
+ 0x1d,0x1d,0x1d,0x1e,0x1e,0x1e,0x2f,0x0e,0x1f,0x1f,0x20,0x0f,0x0f,0x10,0x10,0x21,
+ 0x2e,0x2e,0x2e,0x1e,0x2f,0x2f,0x2f,0x1f,0x1f,0x20,0x20,0x31,0x10,0x10,0x21,0x21,
+ 0x3f,0x3f,0x3f,0x2f,0x30,0x30,0x30,0x30,0x20,0x31,0x31,0x31,0x31,0x21,0x21,0x32,
+ 0x4f,0x4f,0x22,0x40,0x40,0x40,0x40,0x41,0x41,0x41,0x52,0x42,0x42,0x53,0x53,0x64,
+ 0x4f,0x22,0x22,0x22,0x40,0x40,0x40,0x41,0x41,0x41,0x52,0x42,0x42,0x53,0x53,0x64,
+ 0x22,0x22,0x22,0x33,0x33,0x33,0x40,0x41,0x41,0x41,0x52,0x42,0x42,0x53,0x53,0x64,
+ 0x43,0x22,0x33,0x33,0x33,0x44,0x44,0x45,0x45,0x45,0x56,0x46,0x46,0x46,0x57,0x68,
+ 0x43,0x43,0x33,0x33,0x44,0x44,0x44,0x45,0x45,0x45,0x56,0x46,0x46,0x57,0x57,0x68,
+ 0x43,0x43,0x33,0x44,0x44,0x44,0x55,0x45,0x45,0x56,0x56,0x46,0x46,0x57,0x68,0x68,
+ 0x43,0x43,0x43,0x44,0x44,0x55,0x55,0x45,0x45,0x56,0x67,0x46,0x46,0x57,0x68,0x79,
+ 0x47,0x47,0x47,0x48,0x48,0x48,0x48,0x49,0x49,0x49,0x49,0x4a,0x4a,0x4a,0x5b,0x79,
+ 0x47,0x47,0x47,0x48,0x48,0x48,0x48,0x49,0x49,0x49,0x5a,0x4a,0x4a,0x4a,0x5b,0x6c,
+ 0x47,0x47,0x47,0x48,0x48,0x59,0x59,0x49,0x49,0x5a,0x5a,0x4a,0x4a,0x5b,0x5b,0x6c,
+ 0x58,0x58,0x58,0x59,0x59,0x59,0x6a,0x49,0x5a,0x5a,0x6b,0x6b,0x5b,0x5b,0x6c,0x7d,
+ 0x4b,0x4b,0x4b,0x4c,0x4c,0x4c,0x4c,0x4d,0x4d,0x4d,0x6b,0x4e,0x4e,0x4e,0x6c,0x7d,
+ 0x4b,0x4b,0x4b,0x4c,0x4c,0x4c,0x4c,0x4d,0x4d,0x4d,0x5e,0x4e,0x4e,0x4e,0x5f,0x5f,
+ 0x5c,0x5c,0x5c,0x4c,0x5d,0x5d,0x5d,0x4d,0x4d,0x5e,0x5e,0x4e,0x4e,0x5f,0x5f,0x60,
+ 0x5c,0x5c,0x5c,0x5d,0x5d,0x6e,0x6e,0x5e,0x5e,0x5e,0x6f,0x6f,0x5f,0x5f,0x60,0x60,
+ 0x6d,0x6d,0x6d,0x6e,0x6e,0x6e,0x7f,0x7f,0x6f,0x6f,0x70,0x70,0x5f,0x60,0x60,0x71,
+ 0x4f,0x4f,0x40,0x40,0x40,0x40,0x51,0x41,0x41,0x52,0x63,0x42,0x42,0x53,0x64,0x75,
+ 0x4f,0x4f,0x22,0x40,0x40,0x40,0x51,0x41,0x41,0x52,0x63,0x42,0x42,0x53,0x64,0x75,
+ 0x43,0x22,0x33,0x33,0x33,0x40,0x51,0x41,0x41,0x52,0x63,0x42,0x42,0x53,0x64,0x75,
+ 0x43,0x43,0x33,0x33,0x44,0x44,0x44,0x45,0x45,0x45,0x56,0x46,0x46,0x57,0x57,0x68,
+ 0x43,0x43,0x33,0x44,0x44,0x44,0x55,0x45,0x45,0x56,0x56,0x46,0x46,0x57,0x68,0x68,
+ 0x43,0x43,0x43,0x44,0x44,0x55,0x55,0x45,0x45,0x56,0x67,0x46,0x46,0x57,0x68,0x79,
+ 0x54,0x54,0x54,0x44,0x55,0x55,0x55,0x45,0x56,0x56,0x67,0x78,0x78,0x57,0x68,0x79,
+ 0x47,0x47,0x47,0x48,0x48,0x48,0x48,0x49,0x49,0x49,0x49,0x4a,0x4a,0x4a,0x5b,0x79,
+ 0x47,0x47,0x47,0x48,0x48,0x48,0x59,0x49,0x49,0x49,0x5a,0x4a,0x4a,0x5b,0x5b,0x6c,
+ 0x58,0x58,0x58,0x48,0x59,0x59,0x59,0x49,0x49,0x5a,0x5a,0x4a,0x4a,0x5b,0x6c,0x6c,
+ 0x69,0x69,0x69,0x59,0x59,0x6a,0x6a,0x49,0x5a,0x5a,0x6b,0x6b,0x5b,0x5b,0x6c,0x7d,
+ 0x4b,0x4b,0x4b,0x4c,0x4c,0x4c,0x7b,0x4d,0x4d,0x4d,0x6b,0x4e,0x4e,0x4e,0x7d,0x7d,
+ 0x4b,0x4b,0x4b,0x4c,0x4c,0x4c,0x7b,0x4d,0x4d,0x4d,0x5e,0x4e,0x4e,0x4e,0x5f,0x7d,
+ 0x5c,0x5c,0x5c,0x5d,0x5d,0x5d,0x5d,0x4d,0x5e,0x5e,0x5e,0x4e,0x4e,0x5f,0x5f,0x60,
+ 0x6d,0x6d,0x6d,0x5d,0x6e,0x6e,0x6e,0x5e,0x5e,0x6f,0x6f,0x70,0x5f,0x5f,0x60,0x60,
+ 0x7e,0x7e,0x7e,0x6e,0x6e,0x7f,0x7f,0x7f,0x6f,0x6f,0x70,0x70,0x70,0x60,0x60,0x71,
+ 0x50,0x50,0x50,0x40,0x40,0x51,0x51,0x41,0x41,0x52,0x63,0x74,0x42,0x53,0x64,0x75,
+ 0x50,0x50,0x50,0x40,0x40,0x51,0x51,0x41,0x41,0x52,0x63,0x74,0x42,0x53,0x64,0x75,
+ 0x50,0x50,0x33,0x33,0x40,0x51,0x51,0x41,0x41,0x52,0x63,0x74,0x42,0x53,0x64,0x75,
+ 0x43,0x43,0x33,0x44,0x44,0x44,0x55,0x45,0x45,0x56,0x56,0x46,0x46,0x57,0x68,0x68,
+ 0x43,0x43,0x43,0x44,0x44,0x55,0x55,0x45,0x45,0x56,0x67,0x46,0x46,0x57,0x68,0x79,
+ 0x54,0x54,0x54,0x44,0x55,0x55,0x55,0x45,0x56,0x56,0x67,0x78,0x78,0x57,0x68,0x79,
+ 0x54,0x54,0x54,0x55,0x55,0x55,0x66,0x66,0x56,0x67,0x67,0x78,0x78,0x68,0x68,0x79,
+ 0x47,0x47,0x47,0x48,0x48,0x48,0x66,0x49,0x49,0x49,0x78,0x78,0x4a,0x4a,0x5b,0x79,
+ 0x47,0x47,0x47,0x48,0x48,0x59,0x59,0x49,0x49,0x5a,0x5a,0x4a,0x4a,0x5b,0x6c,0x6c,
+ 0x58,0x58,0x58,0x59,0x59,0x59,0x6a,0x49,0x5a,0x5a,0x6b,0x6b,0x5b,0x5b,0x6c,0x7d,
+ 0x69,0x69,0x69,0x59,0x6a,0x6a,0x6a,0x7b,0x5a,0x6b,0x6b,0x6b,0x7c,0x6c,0x6c,0x7d,
+ 0x7a,0x7a,0x7a,0x4c,0x4c,0x7b,0x7b,0x7b,0x4d,0x6b,0x6b,0x7c,0x7c,0x4e,0x7d,0x7d,
+ 0x4b,0x4b,0x4b,0x4c,0x4c,0x7b,0x7b,0x4d,0x4d,0x5e,0x7c,0x7c,0x4e,0x5f,0x5f,0x7d,
+ 0x5c,0x5c,0x5c,0x5d,0x5d,0x5d,0x6e,0x4d,0x5e,0x5e,0x6f,0x4e,0x5f,0x5f,0x60,0x60,
+ 0x6d,0x6d,0x6d,0x6e,0x6e,0x6e,0x6e,0x5e,0x6f,0x6f,0x6f,0x70,0x5f,0x60,0x60,0x71,
+ 0x7e,0x7e,0x7e,0x6e,0x7f,0x7f,0x7f,0x7f,0x6f,0x70,0x70,0x70,0x70,0x60,0x71,0x71,
+ 0x61,0x61,0x61,0x40,0x51,0x51,0x62,0x62,0x73,0x63,0x63,0x74,0x74,0x64,0x64,0x75,
+ 0x61,0x61,0x61,0x40,0x51,0x51,0x62,0x62,0x73,0x63,0x63,0x74,0x74,0x64,0x64,0x75,
+ 0x61,0x61,0x61,0x40,0x51,0x51,0x62,0x62,0x73,0x63,0x63,0x74,0x74,0x64,0x64,0x75,
+ 0x43,0x43,0x43,0x44,0x44,0x55,0x55,0x45,0x45,0x56,0x67,0x46,0x46,0x57,0x68,0x79,
+ 0x54,0x54,0x54,0x44,0x55,0x55,0x55,0x45,0x56,0x56,0x67,0x78,0x78,0x57,0x68,0x79,
+ 0x54,0x54,0x54,0x55,0x55,0x55,0x66,0x66,0x56,0x67,0x67,0x78,0x78,0x68,0x68,0x79,
+ 0x65,0x65,0x65,0x55,0x55,0x66,0x66,0x66,0x77,0x67,0x78,0x78,0x78,0x78,0x79,0x79,
+ 0x65,0x65,0x65,0x48,0x48,0x66,0x66,0x77,0x77,0x77,0x78,0x78,0x78,0x5b,0x79,0x79,
+ 0x76,0x76,0x76,0x48,0x59,0x59,0x77,0x77,0x77,0x5a,0x5a,0x4a,0x4a,0x5b,0x6c,0x6c,
+ 0x69,0x69,0x69,0x59,0x59,0x6a,0x6a,0x77,0x5a,0x5a,0x6b,0x6b,0x5b,0x6c,0x6c,0x7d,
+ 0x69,0x69,0x69,0x6a,0x6a,0x6a,0x7b,0x7b,0x5a,0x6b,0x6b,0x7c,0x7c,0x6c,0x7d,0x7d,
+ 0x7a,0x7a,0x7a,0x4c,0x7b,0x7b,0x7b,0x7b,0x4d,0x6b,0x7c,0x7c,0x7c,0x7c,0x7d,0x7d,
+ 0x7a,0x7a,0x7a,0x4c,0x7b,0x7b,0x7b,0x7b,0x4d,0x5e,0x7c,0x7c,0x7c,0x5f,0x5f,0x7d,
+ 0x6d,0x6d,0x6d,0x5d,0x5d,0x6e,0x7b,0x5e,0x5e,0x6f,0x6f,0x7c,0x5f,0x5f,0x60,0x60,
+ 0x6d,0x6d,0x6d,0x6e,0x6e,0x6e,0x7f,0x7f,0x6f,0x6f,0x70,0x70,0x5f,0x60,0x60,0x71,
+ 0x7e,0x7e,0x7e,0x7f,0x7f,0x7f,0x7f,0x7f,0x6f,0x70,0x70,0x70,0x70,0x60,0x71,0x71,
+ 0x72,0x72,0x72,0x8f,0x8f,0x62,0x62,0x73,0x73,0x80,0x74,0x81,0x81,0x81,0x92,0x75,
+ 0x72,0x72,0x72,0x8f,0x8f,0x62,0x62,0x73,0x73,0x80,0x74,0x81,0x81,0x81,0x92,0x75,
+ 0x72,0x72,0x72,0x83,0x83,0x62,0x62,0x73,0x73,0x80,0x74,0x81,0x81,0x81,0x92,0x75,
+ 0x82,0x82,0x82,0x83,0x83,0x83,0x83,0x84,0x84,0x84,0x84,0x85,0x85,0x85,0x96,0x79,
+ 0x82,0x82,0x82,0x83,0x83,0x83,0x66,0x84,0x84,0x84,0x67,0x85,0x85,0x85,0x96,0x79,
+ 0x65,0x65,0x65,0x83,0x83,0x66,0x66,0x66,0x84,0x84,0x78,0x78,0x85,0x85,0x96,0x79,
+ 0x65,0x65,0x65,0x83,0x66,0x66,0x66,0x77,0x77,0x77,0x78,0x78,0x78,0x96,0x79,0x79,
+ 0x76,0x76,0x76,0x87,0x87,0x66,0x77,0x77,0x77,0x88,0x78,0x89,0x89,0x89,0x89,0x79,
+ 0x76,0x76,0x76,0x87,0x87,0x87,0x77,0x77,0x88,0x88,0x88,0x89,0x89,0x89,0x9a,0x9a,
+ 0x86,0x86,0x86,0x87,0x87,0x87,0x77,0x88,0x88,0x88,0x6b,0x89,0x89,0x9a,0x9a,0x7d,
+ 0x7a,0x7a,0x7a,0x87,0x6a,0x7b,0x7b,0x7b,0x88,0x6b,0x6b,0x7c,0x7c,0x9a,0x7d,0x7d,
+ 0x8a,0x8a,0x8a,0x8b,0x8b,0x7b,0x7b,0x8c,0x8c,0x8c,0x7c,0x7c,0x8d,0x8d,0x7d,0x7d,
+ 0x8a,0x8a,0x8a,0x8b,0x8b,0x8b,0x7b,0x8c,0x8c,0x8c,0x7c,0x8d,0x8d,0x8d,0x9e,0x9e,
+ 0x8a,0x8a,0x8a,0x8b,0x8b,0x8b,0x9c,0x8c,0x8c,0x9d,0x9d,0x8d,0x8d,0x9e,0x9e,0x9e,
+ 0x9b,0x9b,0x9b,0x9c,0x9c,0x9c,0x7f,0x8c,0x9d,0x9d,0x70,0x70,0x9e,0x9e,0x9e,0x71,
+ 0x7e,0x7e,0x7e,0x7f,0x7f,0x7f,0x7f,0x7f,0x9d,0x70,0x70,0x70,0x9e,0x9e,0x71,0x71,
+ 0x8e,0x8e,0x8e,0x8f,0x8f,0x8f,0x73,0x73,0x80,0x80,0x91,0x81,0x81,0x92,0x92,0xa3,
+ 0x8e,0x8e,0x8e,0x8f,0x8f,0x8f,0x73,0x73,0x80,0x80,0x91,0x81,0x81,0x92,0x92,0xa3,
+ 0x82,0x82,0x82,0x83,0x83,0x83,0x73,0x73,0x80,0x80,0x91,0x81,0x81,0x92,0x92,0xa3,
+ 0x82,0x82,0x82,0x83,0x83,0x83,0x83,0x84,0x84,0x84,0x95,0x85,0x85,0x85,0x96,0xa7,
+ 0x82,0x82,0x82,0x83,0x83,0x83,0x94,0x84,0x84,0x84,0x95,0x85,0x85,0x96,0x96,0xa7,
+ 0x82,0x82,0x82,0x83,0x83,0x94,0x94,0x84,0x84,0x95,0x95,0x85,0x85,0x96,0xa7,0xa7,
+ 0x76,0x76,0x76,0x83,0x94,0x94,0x77,0x77,0x77,0x95,0x95,0x85,0x85,0x96,0xa7,0xa7,
+ 0x76,0x76,0x76,0x87,0x87,0x87,0x77,0x77,0x88,0x88,0x88,0x89,0x89,0x89,0x9a,0x9a,
+ 0x86,0x86,0x86,0x87,0x87,0x87,0x77,0x88,0x88,0x88,0x99,0x89,0x89,0x9a,0x9a,0xab,
+ 0x86,0x86,0x86,0x87,0x87,0x98,0x98,0x88,0x88,0x99,0x99,0x89,0x89,0x9a,0x9a,0xab,
+ 0x97,0x97,0x97,0x98,0x98,0x98,0x98,0x88,0x99,0x99,0x99,0x89,0x9a,0x9a,0xab,0xab,
+ 0x8a,0x8a,0x8a,0x8b,0x8b,0x8b,0x8b,0x8c,0x8c,0x8c,0x8c,0x8d,0x8d,0x8d,0xab,0xbc,
+ 0x8a,0x8a,0x8a,0x8b,0x8b,0x8b,0x8b,0x8c,0x8c,0x8c,0x9d,0x8d,0x8d,0x8d,0x9e,0x9e,
+ 0x9b,0x9b,0x9b,0x8b,0x9c,0x9c,0x9c,0x8c,0x9d,0x9d,0x9d,0x8d,0x8d,0x9e,0x9e,0xaf,
+ 0x9b,0x9b,0x9b,0x9c,0x9c,0xad,0xad,0x9d,0x9d,0x9d,0xae,0xae,0x9e,0x9e,0xaf,0xaf,
+ 0xac,0xac,0xac,0xad,0xad,0xad,0xad,0x9d,0xae,0xae,0xae,0xbf,0x9e,0xaf,0xaf,0xaf,
+ 0x9f,0x9f,0x9f,0x8f,0x90,0x90,0xa1,0x80,0x80,0x91,0x91,0x81,0x81,0x92,0xa3,0xb4,
+ 0x9f,0x9f,0x9f,0x8f,0x90,0x90,0xa1,0x80,0x80,0x91,0x91,0x81,0x81,0x92,0xa3,0xb4,
+ 0x9f,0x9f,0x9f,0x83,0x90,0x90,0xa1,0x80,0x80,0x91,0x91,0x81,0x81,0x92,0xa3,0xb4,
+ 0x82,0x82,0x82,0x83,0x83,0x94,0x94,0x84,0x84,0x95,0x95,0x85,0x85,0x96,0x96,0xa7,
+ 0x93,0x93,0x93,0x83,0x94,0x94,0x94,0x84,0x84,0x95,0x95,0x85,0x85,0x96,0xa7,0xa7,
+ 0x93,0x93,0x93,0x94,0x94,0x94,0xa5,0x84,0x95,0x95,0xa6,0xa6,0x96,0x96,0xa7,0xb8,
+ 0xa4,0xa4,0xa4,0x94,0x94,0xa5,0xa5,0x77,0x95,0x95,0xa6,0xa6,0x96,0xa7,0xa7,0xb8,
+ 0x86,0x86,0x86,0x87,0x87,0x87,0x77,0x88,0x88,0x88,0x99,0x89,0x89,0x9a,0x9a,0xb8,
+ 0x86,0x86,0x86,0x87,0x87,0x98,0x98,0x88,0x88,0x99,0x99,0x89,0x89,0x9a,0x9a,0xab,
+ 0x97,0x97,0x97,0x98,0x98,0x98,0x98,0x88,0x99,0x99,0x99,0x89,0x9a,0x9a,0xab,0xab,
+ 0x97,0x97,0x97,0x98,0x98,0xa9,0xa9,0x99,0x99,0x99,0xaa,0xaa,0x9a,0xab,0xab,0xbc,
+ 0x8a,0x8a,0x8a,0x8b,0x8b,0xa9,0xa9,0x8c,0x8c,0x8c,0xaa,0x8d,0x8d,0x8d,0xab,0xbc,
+ 0x8a,0x8a,0x8a,0x8b,0x8b,0x9c,0x9c,0x8c,0x8c,0x9d,0x9d,0x8d,0x8d,0x9e,0x9e,0xbc,
+ 0x9b,0x9b,0x9b,0x9c,0x9c,0x9c,0xad,0x9d,0x9d,0x9d,0xae,0x8d,0x9e,0x9e,0xaf,0xaf,
+ 0xac,0xac,0xac,0x9c,0xad,0xad,0xad,0x9d,0x9d,0xae,0xae,0xae,0x9e,0xaf,0xaf,0xaf,
+ 0xbd,0xbd,0xbd,0xad,0xad,0xbe,0xbe,0xbe,0xae,0xae,0xbf,0xbf,0xbf,0xaf,0xaf,0xb0,
+ 0xa0,0xa0,0xa0,0x90,0xa1,0xa1,0xa1,0xb2,0x91,0x91,0xa2,0xa2,0xb3,0xa3,0xa3,0xb4,
+ 0xa0,0xa0,0xa0,0x90,0xa1,0xa1,0xa1,0xb2,0x91,0x91,0xa2,0xa2,0xb3,0xa3,0xa3,0xb4,
+ 0xa0,0xa0,0xa0,0x90,0xa1,0xa1,0xa1,0xb2,0x91,0x91,0xa2,0xa2,0xb3,0xa3,0xa3,0xb4,
+ 0x93,0x93,0x93,0x94,0x94,0x94,0xa5,0x84,0x95,0x95,0xa6,0xa6,0x96,0x96,0xa7,0xb8,
+ 0xa4,0xa4,0xa4,0x94,0x94,0xa5,0xa5,0x84,0x95,0x95,0xa6,0xa6,0x96,0x96,0xa7,0xb8,
+ 0xa4,0xa4,0xa4,0x94,0xa5,0xa5,0xa5,0xb6,0x95,0xa6,0xa6,0xa6,0xb7,0xa7,0xa7,0xb8,
+ 0xa4,0xa4,0xa4,0xa5,0xa5,0xa5,0xb6,0xb6,0x95,0xa6,0xa6,0xb7,0xb7,0xa7,0xb8,0xb8,
+ 0xb5,0xb5,0xb5,0x87,0x87,0xb6,0xb6,0xb6,0x88,0x99,0xa6,0xb7,0xb7,0x9a,0xb8,0xb8,
+ 0x97,0x97,0x97,0x98,0x98,0x98,0x98,0x88,0x99,0x99,0x99,0x89,0x9a,0x9a,0xab,0xab,
+ 0x97,0x97,0x97,0x98,0x98,0xa9,0xa9,0x99,0x99,0x99,0xaa,0xaa,0x9a,0xab,0xab,0xbc,
+ 0xa8,0xa8,0xa8,0xa9,0xa9,0xa9,0xa9,0xa9,0x99,0xaa,0xaa,0xaa,0xbb,0xab,0xab,0xbc,
+ 0xa8,0xa8,0xa8,0xa9,0xa9,0xa9,0xba,0xba,0x8c,0xaa,0xaa,0xbb,0xbb,0xab,0xbc,0xbc,
+ 0xb9,0xb9,0xb9,0x9c,0x9c,0xba,0xba,0xba,0x9d,0x9d,0xbb,0xbb,0xbb,0x9e,0x9e,0xbc,
+ 0xac,0xac,0xac,0x9c,0x9c,0xad,0xad,0x9d,0x9d,0xae,0xae,0xae,0x9e,0x9e,0xaf,0xaf,
+ 0xac,0xac,0xac,0xad,0xad,0xad,0xbe,0xbe,0xae,0xae,0xae,0xbf,0x9e,0xaf,0xaf,0xb0,
+ 0xbd,0xbd,0xbd,0xbe,0xbe,0xbe,0xbe,0xbe,0xae,0xbf,0xbf,0xbf,0xbf,0xaf,0xb0,0xb0,
+ 0xb1,0xb1,0xb1,0xce,0xce,0xb2,0xb2,0xcf,0xcf,0xa2,0xa2,0xb3,0xb3,0xc0,0xb4,0xb4,
+ 0xb1,0xb1,0xb1,0xce,0xce,0xb2,0xb2,0xcf,0xcf,0xa2,0xa2,0xb3,0xb3,0xc0,0xb4,0xb4,
+ 0xb1,0xb1,0xb1,0xc2,0xc2,0xb2,0xb2,0xc3,0xc3,0xa2,0xa2,0xb3,0xb3,0xc0,0xb4,0xb4,
+ 0xc1,0xc1,0xc1,0xc2,0xc2,0xc2,0xa5,0xc3,0xc3,0xc3,0xa6,0xc4,0xc4,0xc4,0xa7,0xb8,
+ 0xc1,0xc1,0xc1,0xc2,0xc2,0xa5,0xb6,0xc3,0xc3,0xc3,0xa6,0xc4,0xc4,0xc4,0xb8,0xb8,
+ 0xb5,0xb5,0xb5,0xc2,0xa5,0xb6,0xb6,0xb6,0xc3,0xa6,0xa6,0xb7,0xb7,0xc4,0xb8,0xb8,
+ 0xb5,0xb5,0xb5,0xa5,0xb6,0xb6,0xb6,0xb6,0xc3,0xa6,0xb7,0xb7,0xb7,0xb7,0xb8,0xb8,
+ 0xc5,0xc5,0xc5,0xc6,0xc6,0xb6,0xb6,0xc7,0xc7,0xc7,0xb7,0xb7,0xc8,0xc8,0xb8,0xb8,
+ 0xc5,0xc5,0xc5,0xc6,0xc6,0xc6,0xc6,0xc7,0xc7,0xc7,0xaa,0xc8,0xc8,0xc8,0xab,0xbc,
+ 0xa8,0xa8,0xa8,0xc6,0xc6,0xa9,0xa9,0xc7,0xc7,0xaa,0xaa,0xaa,0xc8,0xc8,0xab,0xbc,
+ 0xa8,0xa8,0xa8,0xa9,0xa9,0xa9,0xba,0xba,0xaa,0xaa,0xaa,0xbb,0xbb,0xab,0xbc,0xbc,
+ 0xb9,0xb9,0xb9,0xca,0xca,0xba,0xba,0xba,0xcb,0xaa,0xbb,0xbb,0xbb,0xcc,0xbc,0xbc,
+ 0xb9,0xb9,0xb9,0xca,0xca,0xba,0xba,0xcb,0xcb,0xcb,0xbb,0xbb,0xcc,0xcc,0xcc,0xbc,
+ 0xc9,0xc9,0xc9,0xca,0xca,0xca,0xba,0xcb,0xcb,0xcb,0xae,0xcc,0xcc,0xcc,0xaf,0xaf,
+ 0xbd,0xbd,0xbd,0xad,0xbe,0xbe,0xbe,0xbe,0xae,0xae,0xbf,0xbf,0xcc,0xaf,0xaf,0xb0,
+ 0xbd,0xbd,0xbd,0xbe,0xbe,0xbe,0xbe,0xbe,0xbf,0xbf,0xbf,0xbf,0xbf,0xaf,0xb0,0xb0,
+ 0xcd,0xcd,0xcd,0xce,0xce,0xce,0xb2,0xcf,0xcf,0xcf,0xb3,0xb3,0xc0,0xc0,0xd1,0xb4,
+ 0xcd,0xcd,0xcd,0xce,0xce,0xce,0xb2,0xcf,0xcf,0xcf,0xb3,0xb3,0xc0,0xc0,0xd1,0xb4,
+ 0xc1,0xc1,0xc1,0xc2,0xc2,0xc2,0xb2,0xc3,0xc3,0xc3,0xb3,0xb3,0xc0,0xc0,0xd1,0xb4,
+ 0xc1,0xc1,0xc1,0xc2,0xc2,0xc2,0xc2,0xc3,0xc3,0xc3,0xd4,0xc4,0xc4,0xc4,0xd5,0xd5,
+ 0xc1,0xc1,0xc1,0xc2,0xc2,0xc2,0xb6,0xc3,0xc3,0xc3,0xd4,0xc4,0xc4,0xc4,0xd5,0xb8,
+ 0xc1,0xc1,0xc1,0xc2,0xc2,0xb6,0xb6,0xc3,0xc3,0xd4,0xb7,0xb7,0xc4,0xd5,0xd5,0xb8,
+ 0xb5,0xb5,0xb5,0xc2,0xb6,0xb6,0xb6,0xb6,0xc3,0xd4,0xb7,0xb7,0xb7,0xd5,0xd5,0xb8,
+ 0xc5,0xc5,0xc5,0xc6,0xc6,0xc6,0xb6,0xc7,0xc7,0xc7,0xb7,0xc8,0xc8,0xc8,0xd9,0xd9,
+ 0xc5,0xc5,0xc5,0xc6,0xc6,0xc6,0xc6,0xc7,0xc7,0xc7,0xd8,0xc8,0xc8,0xc8,0xd9,0xd9,
+ 0xc5,0xc5,0xc5,0xc6,0xc6,0xd7,0xd7,0xc7,0xc7,0xd8,0xd8,0xc8,0xc8,0xd9,0xd9,0xbc,
+ 0xb9,0xb9,0xb9,0xd7,0xd7,0xba,0xba,0xba,0xd8,0xd8,0xbb,0xbb,0xbb,0xd9,0xd9,0xbc,
+ 0xb9,0xb9,0xb9,0xca,0xca,0xba,0xba,0xcb,0xcb,0xcb,0xbb,0xbb,0xcc,0xcc,0xcc,0xbc,
+ 0xc9,0xc9,0xc9,0xca,0xca,0xca,0xba,0xcb,0xcb,0xcb,0xbb,0xcc,0xcc,0xcc,0xdd,0xdd,
+ 0xc9,0xc9,0xc9,0xca,0xca,0xdb,0xdb,0xcb,0xcb,0xdc,0xdc,0xcc,0xcc,0xdd,0xdd,0xdd,
+ 0xda,0xda,0xda,0xdb,0xdb,0xdb,0xdb,0xdc,0xdc,0xdc,0xdc,0xcc,0xdd,0xdd,0xdd,0xb0,
+ 0xbd,0xbd,0xbd,0xdb,0xbe,0xbe,0xbe,0xdc,0xdc,0xbf,0xbf,0xbf,0xdd,0xdd,0xb0,0xb0,
+ 0xde,0xde,0xde,0xdf,0xdf,0xdf,0xe0,0xcf,0xd0,0xd0,0xe1,0xc0,0xc0,0xd1,0xd1,0xe2,
+ 0xde,0xde,0xde,0xdf,0xdf,0xdf,0xe0,0xcf,0xd0,0xd0,0xe1,0xc0,0xc0,0xd1,0xd1,0xe2,
+ 0xde,0xde,0xde,0xdf,0xdf,0xdf,0xe0,0xc3,0xd0,0xd0,0xe1,0xc0,0xc0,0xd1,0xd1,0xe2,
+ 0xd2,0xd2,0xd2,0xc2,0xd3,0xd3,0xd3,0xc3,0xc3,0xd4,0xd4,0xc4,0xc4,0xd5,0xd5,0xe6,
+ 0xd2,0xd2,0xd2,0xd3,0xd3,0xd3,0xd3,0xc3,0xd4,0xd4,0xd4,0xc4,0xc4,0xd5,0xd5,0xe6,
+ 0xd2,0xd2,0xd2,0xd3,0xd3,0xd3,0xe4,0xc3,0xd4,0xd4,0xe5,0xc4,0xd5,0xd5,0xe6,0xe6,
+ 0xe3,0xe3,0xe3,0xd3,0xd3,0xe4,0xb6,0xd4,0xd4,0xe5,0xe5,0xb7,0xd5,0xd5,0xe6,0xe6,
+ 0xc5,0xc5,0xc5,0xc6,0xc6,0xc6,0xd7,0xc7,0xc7,0xd8,0xd8,0xc8,0xc8,0xd9,0xd9,0xd9,
+ 0xd6,0xd6,0xd6,0xc6,0xd7,0xd7,0xd7,0xc7,0xd8,0xd8,0xd8,0xc8,0xc8,0xd9,0xd9,0xea,
+ 0xd6,0xd6,0xd6,0xd7,0xd7,0xd7,0xe8,0xd8,0xd8,0xd8,0xe9,0xc8,0xd9,0xd9,0xea,0xea,
+ 0xe7,0xe7,0xe7,0xd7,0xd7,0xe8,0xe8,0xd8,0xd8,0xe9,0xe9,0xe9,0xd9,0xd9,0xea,0xea,
+ 0xc9,0xc9,0xc9,0xca,0xca,0xca,0xba,0xcb,0xcb,0xcb,0xe9,0xcc,0xcc,0xcc,0xea,0xea,
+ 0xc9,0xc9,0xc9,0xca,0xca,0xdb,0xdb,0xcb,0xcb,0xdc,0xdc,0xcc,0xcc,0xdd,0xdd,0xdd,
+ 0xda,0xda,0xda,0xdb,0xdb,0xdb,0xdb,0xdc,0xdc,0xdc,0xdc,0xcc,0xdd,0xdd,0xdd,0xee,
+ 0xda,0xda,0xda,0xdb,0xdb,0xec,0xec,0xdc,0xdc,0xed,0xed,0xed,0xdd,0xdd,0xee,0xee,
+ 0xeb,0xeb,0xeb,0xec,0xec,0xec,0xec,0xdc,0xed,0xed,0xed,0xed,0xdd,0xee,0xee,0xee,
+ 0xef,0xef,0xef,0xdf,0xe0,0xe0,0xe0,0xd0,0xd0,0xe1,0xe1,0xf2,0xd1,0xd1,0xe2,0xe2,
+ 0xef,0xef,0xef,0xdf,0xe0,0xe0,0xe0,0xd0,0xd0,0xe1,0xe1,0xf2,0xd1,0xd1,0xe2,0xe2,
+ 0xef,0xef,0xef,0xdf,0xe0,0xe0,0xe0,0xd0,0xd0,0xe1,0xe1,0xf2,0xd1,0xd1,0xe2,0xe2,
+ 0xd2,0xd2,0xd2,0xd3,0xd3,0xe4,0xe4,0xd4,0xd4,0xd4,0xe5,0xe5,0xd5,0xd5,0xe6,0xe6,
+ 0xe3,0xe3,0xe3,0xd3,0xe4,0xe4,0xe4,0xd4,0xd4,0xe5,0xe5,0xf6,0xd5,0xd5,0xe6,0xe6,
+ 0xe3,0xe3,0xe3,0xe4,0xe4,0xe4,0xe4,0xd4,0xe5,0xe5,0xe5,0xf6,0xd5,0xe6,0xe6,0xf7,
+ 0xe3,0xe3,0xe3,0xe4,0xe4,0xe4,0xf5,0xf5,0xe5,0xe5,0xf6,0xf6,0xd5,0xe6,0xe6,0xf7,
+ 0xd6,0xd6,0xd6,0xd7,0xd7,0xd7,0xf5,0xc7,0xd8,0xd8,0xf6,0xc8,0xd9,0xd9,0xd9,0xf7,
+ 0xd6,0xd6,0xd6,0xd7,0xd7,0xe8,0xe8,0xd8,0xd8,0xd8,0xe9,0xe9,0xd9,0xd9,0xea,0xea,
+ 0xe7,0xe7,0xe7,0xd7,0xe8,0xe8,0xe8,0xd8,0xd8,0xe9,0xe9,0xe9,0xd9,0xea,0xea,0xea,
+ 0xe7,0xe7,0xe7,0xe8,0xe8,0xe8,0xf9,0xf9,0xe9,0xe9,0xe9,0xfa,0xd9,0xea,0xea,0xfb,
+ 0xf8,0xf8,0xf8,0xe8,0xf9,0xf9,0xf9,0xcb,0xe9,0xe9,0xfa,0xfa,0xcc,0xea,0xea,0xfb,
+ 0xda,0xda,0xda,0xdb,0xdb,0xdb,0xdb,0xdc,0xdc,0xdc,0xdc,0xcc,0xdd,0xdd,0xdd,0xee,
+ 0xda,0xda,0xda,0xdb,0xdb,0xec,0xec,0xdc,0xdc,0xed,0xed,0xed,0xdd,0xdd,0xee,0xee,
+ 0xeb,0xeb,0xeb,0xec,0xec,0xec,0xec,0xdc,0xed,0xed,0xed,0xed,0xdd,0xee,0xee,0xee,
+ 0xeb,0xeb,0xeb,0xec,0xec,0xfd,0xfd,0xfd,0xed,0xed,0xfe,0xfe,0xee,0xee,0xee,0xff,
+ 0xf0,0xf0,0xf0,0xe0,0xf1,0xf1,0xf1,0xf1,0xe1,0xf2,0xf2,0xf2,0xf2,0xe2,0xe2,0xf3,
+ 0xf0,0xf0,0xf0,0xe0,0xf1,0xf1,0xf1,0xf1,0xe1,0xf2,0xf2,0xf2,0xf2,0xe2,0xe2,0xf3,
+ 0xf0,0xf0,0xf0,0xe0,0xf1,0xf1,0xf1,0xf1,0xe1,0xf2,0xf2,0xf2,0xf2,0xe2,0xe2,0xf3,
+ 0xe3,0xe3,0xe3,0xe4,0xe4,0xe4,0xf5,0xf5,0xe5,0xe5,0xf6,0xf6,0xd5,0xe6,0xe6,0xf7,
+ 0xf4,0xf4,0xf4,0xe4,0xe4,0xf5,0xf5,0xf5,0xe5,0xe5,0xf6,0xf6,0xf6,0xe6,0xe6,0xf7,
+ 0xf4,0xf4,0xf4,0xe4,0xf5,0xf5,0xf5,0xf5,0xe5,0xf6,0xf6,0xf6,0xf6,0xe6,0xf7,0xf7,
+ 0xf4,0xf4,0xf4,0xf5,0xf5,0xf5,0xf5,0xf5,0xe5,0xf6,0xf6,0xf6,0xf6,0xe6,0xf7,0xf7,
+ 0xf4,0xf4,0xf4,0xf5,0xf5,0xf5,0xf5,0xf5,0xd8,0xf6,0xf6,0xf6,0xd9,0xd9,0xf7,0xf7,
+ 0xe7,0xe7,0xe7,0xe8,0xe8,0xe8,0xe8,0xd8,0xe9,0xe9,0xe9,0xfa,0xd9,0xea,0xea,0xea,
+ 0xf8,0xf8,0xf8,0xe8,0xe8,0xf9,0xf9,0xf9,0xe9,0xe9,0xfa,0xfa,0xfa,0xea,0xea,0xfb,
+ 0xf8,0xf8,0xf8,0xf9,0xf9,0xf9,0xf9,0xf9,0xe9,0xfa,0xfa,0xfa,0xfa,0xea,0xfb,0xfb,
+ 0xf8,0xf8,0xf8,0xf9,0xf9,0xf9,0xf9,0xf9,0xfa,0xfa,0xfa,0xfa,0xfa,0xea,0xfb,0xfb,
+ 0xf8,0xf8,0xf8,0xdb,0xf9,0xf9,0xf9,0xdc,0xdc,0xfa,0xfa,0xfa,0xdd,0xdd,0xee,0xfb,
+ 0xeb,0xeb,0xeb,0xec,0xec,0xec,0xec,0xdc,0xed,0xed,0xed,0xed,0xdd,0xee,0xee,0xee,
+ 0xeb,0xeb,0xeb,0xec,0xec,0xfd,0xfd,0xfd,0xed,0xed,0xfe,0xfe,0xee,0xee,0xee,0xff,
+ 0xfc,0xfc,0xfc,0xfd,0xfd,0xfd,0xfd,0xfd,0xed,0xfe,0xfe,0xfe,0xfe,0xee,0xff,0xff,
+}
+};
+Memcmap *memdefcmap = &def;
+void _memmkcmap(void){}
--- /dev/null
+++ b/libmemdraw/cread.c
@@ -1,0 +1,95 @@
+#include "lib9.h"
+#include "draw.h"
+#include "memdraw.h"
+
+Memimage*
+creadmemimage(int fd)
+{
+ char hdr[5*12+1];
+ Rectangle r;
+ int m, nb, miny, maxy, new, ldepth, ncblock;
+ uchar *buf;
+ Memimage *i;
+ ulong chan;
+
+ if(readn(fd, hdr, 5*12) != 5*12){
+ werrstr("readmemimage: short header (2)");
+ return nil;
+ }
+
+ /*
+ * distinguish new channel descriptor from old ldepth.
+ * channel descriptors have letters as well as numbers,
+ * while ldepths are a single digit formatted as %-11d.
+ */
+ new = 0;
+ for(m=0; m<10; m++){
+ if(hdr[m] != ' '){
+ new = 1;
+ break;
+ }
+ }
+ if(hdr[11] != ' '){
+ werrstr("creadimage: bad format");
+ return nil;
+ }
+ if(new){
+ hdr[11] = '\0';
+ if((chan = strtochan(hdr)) == 0){
+ werrstr("creadimage: bad channel string %s", hdr);
+ return nil;
+ }
+ }else{
+ ldepth = ((int)hdr[10])-'0';
+ if(ldepth<0 || ldepth>3){
+ werrstr("creadimage: bad ldepth %d", ldepth);
+ return nil;
+ }
+ chan = drawld2chan[ldepth];
+ }
+ r.min.x=atoi(hdr+1*12);
+ r.min.y=atoi(hdr+2*12);
+ r.max.x=atoi(hdr+3*12);
+ r.max.y=atoi(hdr+4*12);
+ if(r.min.x>r.max.x || r.min.y>r.max.y){
+ werrstr("creadimage: bad rectangle");
+ return nil;
+ }
+
+ i = allocmemimage(r, chan);
+ if(i == nil)
+ return nil;
+ ncblock = _compblocksize(r, i->depth);
+ buf = malloc(ncblock);
+ if(buf == nil)
+ goto Errout;
+ miny = r.min.y;
+ while(miny != r.max.y){
+ if(readn(fd, hdr, 2*12) != 2*12){
+ Shortread:
+ werrstr("readmemimage: short read");
+ Errout:
+ freememimage(i);
+ free(buf);
+ return nil;
+ }
+ maxy = atoi(hdr+0*12);
+ nb = atoi(hdr+1*12);
+ if(maxy<=miny || r.max.y<maxy){
+ werrstr("readimage: bad maxy %d", maxy);
+ goto Errout;
+ }
+ if(nb<=0 || ncblock<nb){
+ werrstr("readimage: bad count %d", nb);
+ goto Errout;
+ }
+ if(readn(fd, buf, nb)!=nb)
+ goto Shortread;
+ if(!new) /* old image: flip the data bits */
+ _twiddlecompressed(buf, nb);
+ cloadmemimage(i, Rect(r.min.x, miny, r.max.x, maxy), buf, nb);
+ miny = maxy;
+ }
+ free(buf);
+ return i;
+}
--- /dev/null
+++ b/libmemdraw/defont.c
@@ -1,0 +1,67 @@
+#include "lib9.h"
+#include "draw.h"
+#include "memdraw.h"
+
+Memsubfont*
+getmemdefont(void)
+{
+ char *hdr, *p;
+ int n;
+ Fontchar *fc;
+ Memsubfont *f;
+ int ld;
+ Rectangle r;
+ Memdata *md;
+ Memimage *i;
+
+ /*
+ * make sure data is word-aligned. this is true with Plan 9 compilers
+ * but not in general. the byte order is right because the data is
+ * declared as char*, not ulong*.
+ */
+ p = (char*)defontdata;
+ n = (ulong)p & 3;
+ if(n != 0){
+ memmove(p+(4-n), p, sizeofdefont-n);
+ p += 4-n;
+ }
+ ld = atoi(p+0*12);
+ r.min.x = atoi(p+1*12);
+ r.min.y = atoi(p+2*12);
+ r.max.x = atoi(p+3*12);
+ r.max.y = atoi(p+4*12);
+
+ md = mallocz(sizeof(Memdata), 1);
+ if(md == nil)
+ return nil;
+
+ p += 5*12;
+
+ md->base = nil; /* so freememimage doesn't free p */
+ md->bdata = (uchar*)p; /* ick */
+ md->ref = 1;
+ md->allocd = 1; /* so freememimage does free md */
+
+ i = allocmemimaged(r, drawld2chan[ld], md);
+ if(i == nil){
+ free(md);
+ return nil;
+ }
+
+ hdr = p+Dy(r)*i->width*sizeof(ulong);
+ n = atoi(hdr);
+ p = hdr+3*12;
+ fc = malloc(sizeof(Fontchar)*(n+1));
+ if(fc == 0){
+ freememimage(i);
+ return 0;
+ }
+ _unpackinfo(fc, (uchar*)p, n);
+ f = allocmemsubfont("*default*", n, atoi(hdr+12), atoi(hdr+24), fc, i);
+ if(f == 0){
+ freememimage(i);
+ free(fc);
+ return 0;
+ }
+ return f;
+}
--- /dev/null
+++ b/libmemdraw/draw.c
@@ -1,0 +1,2505 @@
+#include "lib9.h"
+#include "draw.h"
+#include "memdraw.h"
+#include "pool.h"
+
+extern Pool* imagmem;
+int drawdebug;
+static int tablesbuilt;
+
+/* perfect approximation to NTSC = .299r+.587g+.114b when 0 ≤ r,g,b < 256 */
+#define RGB2K(r,g,b) ((156763*(r)+307758*(g)+59769*(b))>>19)
+
+/*
+ * for 0 ≤ x ≤ 255*255, (x*0x0101+0x100)>>16 is a perfect approximation.
+ * for 0 ≤ x < (1<<16), x/255 = ((x+1)*0x0101)>>16 is a perfect approximation.
+ * the last one is perfect for all up to 1<<16, avoids a multiply, but requires a rathole.
+ */
+/* #define DIV255(x) (((x)*257+256)>>16) */
+#define DIV255(x) ((((x)+1)*257)>>16)
+/* #define DIV255(x) (tmp=(x)+1, (tmp+(tmp>>8))>>8) */
+
+#define MUL(x, y, t) (t = (x)*(y)+128, (t+(t>>8))>>8)
+#define MASK13 0xFF00FF00
+#define MASK02 0x00FF00FF
+#define MUL13(a, x, t) (t = (a)*(((x)&MASK13)>>8)+0x800080, ((t+((t>>8)&MASK02))>>8)&MASK02)
+#define MUL02(a, x, t) (t = (a)*(((x)&MASK02)>>0)+0x800080, ((t+((t>>8)&MASK02))>>8)&MASK02)
+#define MUL0123(a, x, s, t) ((MUL13(a, x, s)<<8)|MUL02(a, x, t))
+
+#define MUL2(u, v, x, y) (t = (u)*(v)+(x)*(y)+256, (t+(t>>8))>>8)
+
+#define BWADD(x, y) ((((x)&MASK13)+((y)&MASK13))&MASK13|(((x)&MASK02)+((y)&MASK02))&MASK02)
+
+static void mktables(void);
+typedef int Subdraw(Memdrawparam*);
+static Subdraw chardraw, alphadraw, memoptdraw;
+
+static Memimage* memones;
+static Memimage* memzeros;
+Memimage *memwhite;
+Memimage *memblack;
+Memimage *memtransparent;
+Memimage *memopaque;
+
+int _ifmt(Fmt*);
+
+void
+memimageinit(void)
+{
+ static int didinit = 0;
+ char *n;
+
+ if(didinit)
+ return;
+
+ didinit = 1;
+
+ n = poolname(imagmem);
+ if(strcmp(n, "Image") == 0 || strcmp(n, "image") == 0)
+ poolsetcompact(imagmem, memimagemove);
+ mktables();
+ _memmkcmap();
+
+ fmtinstall('R', Rfmt);
+ fmtinstall('P', Pfmt);
+ fmtinstall('b', _ifmt);
+
+ memones = allocmemimage(Rect(0,0,1,1), GREY1);
+ memones->flags |= Frepl;
+ memones->clipr = Rect(-0x3FFFFFF, -0x3FFFFFF, 0x3FFFFFF, 0x3FFFFFF);
+ *byteaddr(memones, ZP) = ~0;
+
+ memzeros = allocmemimage(Rect(0,0,1,1), GREY1);
+ memzeros->flags |= Frepl;
+ memzeros->clipr = Rect(-0x3FFFFFF, -0x3FFFFFF, 0x3FFFFFF, 0x3FFFFFF);
+ *byteaddr(memzeros, ZP) = 0;
+
+ if(memones == nil || memzeros == nil)
+ assert(0 /*cannot initialize memimage library */); /* RSC BUG */
+
+ memwhite = memones;
+ memblack = memzeros;
+ memopaque = memones;
+ memtransparent = memzeros;
+}
+
+static ulong imgtorgba(Memimage*, ulong);
+static ulong rgbatoimg(Memimage*, ulong);
+static ulong pixelbits(Memimage*, Point);
+
+#define DBG if(0)
+void
+memimagedraw(Memimage *dst, Rectangle r, Memimage *src, Point p0, Memimage *mask, Point p1, int op)
+{
+ Memdrawparam par;
+
+ if(mask == nil)
+ mask = memopaque;
+
+DBG print("memimagedraw %p/%luX %R @ %p %p/%luX %P %p/%luX %P... ", dst, dst->chan, r, dst->data->bdata, src, src->chan, p0, mask, mask->chan, p1);
+
+ if(drawclip(dst, &r, src, &p0, mask, &p1, &par.sr, &par.mr) == 0){
+// if(drawdebug)
+// iprint("empty clipped rectangle\n");
+ return;
+ }
+
+ if(op < Clear || op > SoverD){
+// if(drawdebug)
+// iprint("op out of range: %d\n", op);
+ return;
+ }
+
+ par.op = op;
+ par.dst = dst;
+ par.r = r;
+ par.src = src;
+ /* par.sr set by drawclip */
+ par.mask = mask;
+ /* par.mr set by drawclip */
+
+ par.state = 0;
+ if(src->flags&Frepl){
+ par.state |= Replsrc;
+ if(Dx(src->r)==1 && Dy(src->r)==1){
+ par.sval = pixelbits(src, src->r.min);
+ par.state |= Simplesrc;
+ par.srgba = imgtorgba(src, par.sval);
+ par.sdval = rgbatoimg(dst, par.srgba);
+ if((par.srgba&0xFF) == 0 && (op&DoutS)){
+// if (drawdebug) iprint("fill with transparent source\n");
+ return; /* no-op successfully handled */
+ }
+ }
+ }
+
+ if(mask->flags & Frepl){
+ par.state |= Replmask;
+ if(Dx(mask->r)==1 && Dy(mask->r)==1){
+ par.mval = pixelbits(mask, mask->r.min);
+ if(par.mval == 0 && (op&DoutS)){
+// if(drawdebug) iprint("fill with zero mask\n");
+ return; /* no-op successfully handled */
+ }
+ par.state |= Simplemask;
+ if(par.mval == ~0)
+ par.state |= Fullmask;
+ par.mrgba = imgtorgba(mask, par.mval);
+ }
+ }
+
+// if(drawdebug)
+// iprint("dr %R sr %R mr %R...", r, par.sr, par.mr);
+DBG print("draw dr %R sr %R mr %R %lux\n", r, par.sr, par.mr, par.state);
+
+ /*
+ * Now that we've clipped the parameters down to be consistent, we
+ * simply try sub-drawing routines in order until we find one that was able
+ * to handle us. If the sub-drawing routine returns zero, it means it was
+ * unable to satisfy the request, so we do not return.
+ */
+
+ /*
+ * Hardware support. Each video driver provides this function,
+ * which checks to see if there is anything it can help with.
+ * There could be an if around this checking to see if dst is in video memory.
+ */
+DBG print("test hwdraw\n");
+ if(hwdraw(&par)){
+//if(drawdebug) iprint("hw handled\n");
+DBG print("hwdraw handled\n");
+ return;
+ }
+ /*
+ * Optimizations using memmove and memset.
+ */
+DBG print("test memoptdraw\n");
+ if(memoptdraw(&par)){
+//if(drawdebug) iprint("memopt handled\n");
+DBG print("memopt handled\n");
+ return;
+ }
+
+ /*
+ * Character drawing.
+ * Solid source color being painted through a boolean mask onto a high res image.
+ */
+DBG print("test chardraw\n");
+ if(chardraw(&par)){
+//if(drawdebug) iprint("chardraw handled\n");
+DBG print("chardraw handled\n");
+ return;
+ }
+
+ /*
+ * General calculation-laden case that does alpha for each pixel.
+ */
+DBG print("do alphadraw\n");
+ alphadraw(&par);
+//if(drawdebug) iprint("alphadraw handled\n");
+DBG print("alphadraw handled\n");
+}
+#undef DBG
+
+/*
+ * Clip the destination rectangle further based on the properties of the
+ * source and mask rectangles. Once the destination rectangle is properly
+ * clipped, adjust the source and mask rectangles to be the same size.
+ * Then if source or mask is replicated, move its clipped rectangle
+ * so that its minimum point falls within the repl rectangle.
+ *
+ * Return zero if the final rectangle is null.
+ */
+int
+drawclip(Memimage *dst, Rectangle *r, Memimage *src, Point *p0, Memimage *mask, Point *p1, Rectangle *sr, Rectangle *mr)
+{
+ Point rmin, delta;
+ int splitcoords;
+ Rectangle omr;
+
+ if(r->min.x>=r->max.x || r->min.y>=r->max.y)
+ return 0;
+ splitcoords = (p0->x!=p1->x) || (p0->y!=p1->y);
+ /* clip to destination */
+ rmin = r->min;
+ if(!rectclip(r, dst->r) || !rectclip(r, dst->clipr))
+ return 0;
+ /* move mask point */
+ p1->x += r->min.x-rmin.x;
+ p1->y += r->min.y-rmin.y;
+ /* move source point */
+ p0->x += r->min.x-rmin.x;
+ p0->y += r->min.y-rmin.y;
+ /* map destination rectangle into source */
+ sr->min = *p0;
+ sr->max.x = p0->x+Dx(*r);
+ sr->max.y = p0->y+Dy(*r);
+ /* sr is r in source coordinates; clip to source */
+ if(!(src->flags&Frepl) && !rectclip(sr, src->r))
+ return 0;
+ if(!rectclip(sr, src->clipr))
+ return 0;
+ /* compute and clip rectangle in mask */
+ if(splitcoords){
+ /* move mask point with source */
+ p1->x += sr->min.x-p0->x;
+ p1->y += sr->min.y-p0->y;
+ mr->min = *p1;
+ mr->max.x = p1->x+Dx(*sr);
+ mr->max.y = p1->y+Dy(*sr);
+ omr = *mr;
+ /* mr is now rectangle in mask; clip it */
+ if(!(mask->flags&Frepl) && !rectclip(mr, mask->r))
+ return 0;
+ if(!rectclip(mr, mask->clipr))
+ return 0;
+ /* reflect any clips back to source */
+ sr->min.x += mr->min.x-omr.min.x;
+ sr->min.y += mr->min.y-omr.min.y;
+ sr->max.x += mr->max.x-omr.max.x;
+ sr->max.y += mr->max.y-omr.max.y;
+ *p1 = mr->min;
+ }else{
+ if(!(mask->flags&Frepl) && !rectclip(sr, mask->r))
+ return 0;
+ if(!rectclip(sr, mask->clipr))
+ return 0;
+ *p1 = sr->min;
+ }
+
+ /* move source clipping back to destination */
+ delta.x = r->min.x - p0->x;
+ delta.y = r->min.y - p0->y;
+ r->min.x = sr->min.x + delta.x;
+ r->min.y = sr->min.y + delta.y;
+ r->max.x = sr->max.x + delta.x;
+ r->max.y = sr->max.y + delta.y;
+
+ /* move source rectangle so sr->min is in src->r */
+ if(src->flags&Frepl) {
+ delta.x = drawreplxy(src->r.min.x, src->r.max.x, sr->min.x) - sr->min.x;
+ delta.y = drawreplxy(src->r.min.y, src->r.max.y, sr->min.y) - sr->min.y;
+ sr->min.x += delta.x;
+ sr->min.y += delta.y;
+ sr->max.x += delta.x;
+ sr->max.y += delta.y;
+ }
+ *p0 = sr->min;
+
+ /* move mask point so it is in mask->r */
+ *p1 = drawrepl(mask->r, *p1);
+ mr->min = *p1;
+ mr->max.x = p1->x+Dx(*sr);
+ mr->max.y = p1->y+Dy(*sr);
+
+ assert(Dx(*sr) == Dx(*mr) && Dx(*mr) == Dx(*r));
+ assert(Dy(*sr) == Dy(*mr) && Dy(*mr) == Dy(*r));
+ assert(ptinrect(*p0, src->r));
+ assert(ptinrect(*p1, mask->r));
+ assert(ptinrect(r->min, dst->r));
+
+ return 1;
+}
+
+/*
+ * Conversion tables.
+ */
+static uchar replbit[1+8][256]; /* replbit[x][y] is the replication of the x-bit quantity y to 8-bit depth */
+
+/*
+ * bitmap of how to replicate n bits to fill 8, for 1 ≤ n ≤ 8.
+ * the X's are where to put the bottom (ones) bit of the n-bit pattern.
+ * only the top 8 bits of the result are actually used.
+ * (the lower 8 bits are needed to get bits in the right place
+ * when n is not a divisor of 8.)
+ *
+ * Should check to see if its easier to just refer to replmul than
+ * use the precomputed values in replbit. On PCs it may well
+ * be; on machines with slow multiply instructions it probably isn't.
+ */
+#define a ((((((((((((((((0
+#define X *2+1)
+#define _ *2)
+static int replmul[1+8] = {
+ 0,
+ a X X X X X X X X X X X X X X X X,
+ a _ X _ X _ X _ X _ X _ X _ X _ X,
+ a _ _ X _ _ X _ _ X _ _ X _ _ X _,
+ a _ _ _ X _ _ _ X _ _ _ X _ _ _ X,
+ a _ _ _ _ X _ _ _ _ X _ _ _ _ X _,
+ a _ _ _ _ _ X _ _ _ _ _ X _ _ _ _,
+ a _ _ _ _ _ _ X _ _ _ _ _ _ X _ _,
+ a _ _ _ _ _ _ _ X _ _ _ _ _ _ _ X,
+};
+#undef a
+#undef X
+#undef _
+
+static void
+mktables(void)
+{
+ int i, j, small;
+
+ if(tablesbuilt)
+ return;
+
+ fmtinstall('R', Rfmt);
+ fmtinstall('P', Pfmt);
+ tablesbuilt = 1;
+
+ /* bit replication up to 8 bits */
+ for(i=0; i<256; i++){
+ for(j=0; j<=8; j++){ /* j <= 8 [sic] */
+ small = i & ((1<<j)-1);
+ replbit[j][i] = (small*replmul[j])>>8;
+ }
+ }
+}
+
+static uchar ones = 0xff;
+
+/*
+ * General alpha drawing case. Can handle anything.
+ */
+typedef struct Buffer Buffer;
+struct Buffer {
+ /* used by most routines */
+ uchar *red;
+ uchar *grn;
+ uchar *blu;
+ uchar *alpha;
+ uchar *grey;
+ ulong *rgba;
+ int delta; /* number of bytes to add to pointer to get next pixel to the right */
+
+ /* used by boolcalc* for mask data */
+ uchar *m; /* ptr to mask data r.min byte; like p->bytermin */
+ int mskip; /* no. of left bits to skip in *m */
+ uchar *bm; /* ptr to mask data img->r.min byte; like p->bytey0s */
+ int bmskip; /* no. of left bits to skip in *bm */
+ uchar *em; /* ptr to mask data img->r.max.x byte; like p->bytey0e */
+ int emskip; /* no. of right bits to skip in *em */
+};
+
+typedef struct Param Param;
+typedef Buffer Readfn(Param*, uchar*, int);
+typedef void Writefn(Param*, uchar*, Buffer);
+typedef Buffer Calcfn(Buffer, Buffer, Buffer, int, int, int);
+
+enum {
+ MAXBCACHE = 16
+};
+
+/* giant rathole to customize functions with */
+struct Param {
+ Readfn *replcall;
+ Readfn *greymaskcall;
+ Readfn *convreadcall;
+ Writefn *convwritecall;
+
+ Memimage *img;
+ Rectangle r;
+ int dx; /* of r */
+ int needbuf;
+ int convgrey;
+ int alphaonly;
+
+ uchar *bytey0s; /* byteaddr(Pt(img->r.min.x, img->r.min.y)) */
+ uchar *bytermin; /* byteaddr(Pt(r.min.x, img->r.min.y)) */
+ uchar *bytey0e; /* byteaddr(Pt(img->r.max.x, img->r.min.y)) */
+ int bwidth;
+
+ int replcache; /* if set, cache buffers */
+ Buffer bcache[MAXBCACHE];
+ ulong bfilled;
+ uchar *bufbase;
+ int bufoff;
+ int bufdelta;
+
+ int dir;
+
+ int convbufoff;
+ uchar *convbuf;
+ Param *convdpar;
+ int convdx;
+};
+
+static Readfn greymaskread, replread, readptr;
+static Writefn nullwrite;
+static Calcfn alphacalc0, alphacalc14, alphacalc2810, alphacalc3679, alphacalc5, alphacalc11, alphacalcS;
+static Calcfn boolcalc14, boolcalc236789, boolcalc1011;
+
+static Readfn* readfn(Memimage*);
+static Readfn* readalphafn(Memimage*);
+static Writefn* writefn(Memimage*);
+
+static Calcfn* boolcopyfn(Memimage*, Memimage*);
+static Readfn* convfn(Memimage*, Param*, Memimage*, Param*, int*);
+static Readfn* ptrfn(Memimage*);
+
+static Calcfn *alphacalc[Ncomp] =
+{
+ alphacalc0, /* Clear */
+ alphacalc14, /* DoutS */
+ alphacalc2810, /* SoutD */
+ alphacalc3679, /* DxorS */
+ alphacalc14, /* DinS */
+ alphacalc5, /* D */
+ alphacalc3679, /* DatopS */
+ alphacalc3679, /* DoverS */
+ alphacalc2810, /* SinD */
+ alphacalc3679, /* SatopD */
+ alphacalc2810, /* S */
+ alphacalc11, /* SoverD */
+};
+
+static Calcfn *boolcalc[Ncomp] =
+{
+ alphacalc0, /* Clear */
+ boolcalc14, /* DoutS */
+ boolcalc236789, /* SoutD */
+ boolcalc236789, /* DxorS */
+ boolcalc14, /* DinS */
+ alphacalc5, /* D */
+ boolcalc236789, /* DatopS */
+ boolcalc236789, /* DoverS */
+ boolcalc236789, /* SinD */
+ boolcalc236789, /* SatopD */
+ boolcalc1011, /* S */
+ boolcalc1011, /* SoverD */
+};
+
+/*
+ * Avoid standard Lock, QLock so that can be used in kernel.
+ */
+typedef struct Dbuf Dbuf;
+struct Dbuf
+{
+ uchar *p;
+ int n;
+ Param spar, mpar, dpar;
+ int inuse;
+};
+static Dbuf dbuf[10];
+
+static Dbuf*
+allocdbuf(void)
+{
+ int i;
+
+ for(i=0; i<nelem(dbuf); i++){
+ if(dbuf[i].inuse)
+ continue;
+ if(!_tas(&dbuf[i].inuse))
+ return &dbuf[i];
+ }
+ return nil;
+}
+
+static void
+getparam(Param *p, Memimage *img, Rectangle r, int convgrey, int needbuf, int *ndrawbuf)
+{
+ int nbuf;
+
+ memset(p, 0, sizeof *p);
+
+ p->img = img;
+ p->r = r;
+ p->dx = Dx(r);
+ p->needbuf = needbuf;
+ p->convgrey = convgrey;
+
+ assert(img->r.min.x <= r.min.x && r.min.x < img->r.max.x);
+
+ p->bytey0s = byteaddr(img, Pt(img->r.min.x, img->r.min.y));
+ p->bytermin = byteaddr(img, Pt(r.min.x, img->r.min.y));
+ p->bytey0e = byteaddr(img, Pt(img->r.max.x, img->r.min.y));
+ p->bwidth = sizeof(ulong)*img->width;
+
+ assert(p->bytey0s <= p->bytermin && p->bytermin <= p->bytey0e);
+
+ if(p->r.min.x == p->img->r.min.x)
+ assert(p->bytermin == p->bytey0s);
+
+ nbuf = 1;
+ if((img->flags&Frepl) && Dy(img->r) <= MAXBCACHE && Dy(img->r) < Dy(r)){
+ p->replcache = 1;
+ nbuf = Dy(img->r);
+ }
+ p->bufdelta = 4*p->dx;
+ p->bufoff = *ndrawbuf;
+ *ndrawbuf += p->bufdelta*nbuf;
+}
+
+static void
+clipy(Memimage *img, int *y)
+{
+ int dy;
+
+ dy = Dy(img->r);
+ if(*y == dy)
+ *y = 0;
+ else if(*y == -1)
+ *y = dy-1;
+ assert(0 <= *y && *y < dy);
+}
+
+static void
+dumpbuf(char *s, Buffer b, int n)
+{
+ int i;
+ uchar *p;
+
+ print("%s", s);
+ for(i=0; i<n; i++){
+ print(" ");
+ if(p=b.grey){
+ print(" k%.2uX", *p);
+ b.grey += b.delta;
+ }else{
+ if(p=b.red){
+ print(" r%.2uX", *p);
+ b.red += b.delta;
+ }
+ if(p=b.grn){
+ print(" g%.2uX", *p);
+ b.grn += b.delta;
+ }
+ if(p=b.blu){
+ print(" b%.2uX", *p);
+ b.blu += b.delta;
+ }
+ }
+ if((p=b.alpha) != &ones){
+ print(" α%.2uX", *p);
+ b.alpha += b.delta;
+ }
+ }
+ print("\n");
+}
+
+/*
+ * For each scan line, we expand the pixels from source, mask, and destination
+ * into byte-aligned red, green, blue, alpha, and grey channels. If buffering is not
+ * needed and the channels were already byte-aligned (grey8, rgb24, rgba32, rgb32),
+ * the readers need not copy the data: they can simply return pointers to the data.
+ * If the destination image is grey and the source is not, it is converted using the NTSC
+ * formula.
+ *
+ * Once we have all the channels, we call either rgbcalc or greycalc, depending on
+ * whether the destination image is color. This is allowed to overwrite the dst buffer (perhaps
+ * the actual data, perhaps a copy) with its result. It should only overwrite the dst buffer
+ * with the same format (i.e. red bytes with red bytes, etc.) A new buffer is returned from
+ * the calculator, and that buffer is passed to a function to write it to the destination.
+ * If the buffer is already pointing at the destination, the writing function is a no-op.
+ */
+#define DBG if(0)
+static int
+alphadraw(Memdrawparam *par)
+{
+ int isgrey, starty, endy, op;
+ int needbuf, dsty, srcy, masky;
+ int y, dir, dx, dy, ndrawbuf;
+ uchar *drawbuf;
+ Buffer bsrc, bdst, bmask;
+ Readfn *rdsrc, *rdmask, *rddst;
+ Calcfn *calc;
+ Writefn *wrdst;
+ Memimage *src, *mask, *dst;
+ Rectangle r, sr, mr;
+ Dbuf *z;
+
+ z = allocdbuf();
+ if(z == nil)
+ return 0;
+
+ r = par->r;
+ dx = Dx(r);
+ dy = Dy(r);
+
+ src = par->src;
+ mask = par->mask;
+ dst = par->dst;
+ sr = par->sr;
+ mr = par->mr;
+ op = par->op;
+
+ isgrey = dst->flags&Fgrey;
+
+ /*
+ * Buffering when src and dst are the same bitmap is sufficient but not
+ * necessary. There are stronger conditions we could use. We could
+ * check to see if the rectangles intersect, and if simply moving in the
+ * correct y direction can avoid the need to buffer.
+ */
+ needbuf = (src->data == dst->data);
+
+ ndrawbuf = 0;
+ getparam(&z->spar, src, sr, isgrey, needbuf, &ndrawbuf);
+ getparam(&z->dpar, dst, r, isgrey, needbuf, &ndrawbuf);
+ getparam(&z->mpar, mask, mr, 0, needbuf, &ndrawbuf);
+
+ dir = (needbuf && byteaddr(dst, r.min) > byteaddr(src, sr.min)) ? -1 : 1;
+ z->spar.dir = z->mpar.dir = z->dpar.dir = dir;
+
+ /*
+ * If the mask is purely boolean, we can convert from src to dst format
+ * when we read src, and then just copy it to dst where the mask tells us to.
+ * This requires a boolean (1-bit grey) mask and lack of a source alpha channel.
+ *
+ * The computation is accomplished by assigning the function pointers as follows:
+ * rdsrc - read and convert source into dst format in a buffer
+ * rdmask - convert mask to bytes, set pointer to it
+ * rddst - fill with pointer to real dst data, but do no reads
+ * calc - copy src onto dst when mask says to.
+ * wrdst - do nothing
+ * This is slightly sleazy, since things aren't doing exactly what their names say,
+ * but it avoids a fair amount of code duplication to make this a case here
+ * rather than have a separate booldraw.
+ */
+//if(drawdebug) iprint("flag %lud mchan %lux=?%x dd %d\n", src->flags&Falpha, mask->chan, GREY1, dst->depth);
+ if(!(src->flags&Falpha) && mask->chan == GREY1 && dst->depth >= 8 && op == SoverD){
+//if(drawdebug) iprint("boolcopy...");
+ rdsrc = convfn(dst, &z->dpar, src, &z->spar, &ndrawbuf);
+ rddst = readptr;
+ rdmask = readfn(mask);
+ calc = boolcopyfn(dst, mask);
+ wrdst = nullwrite;
+ }else{
+ /* usual alphadraw parameter fetching */
+ rdsrc = readfn(src);
+ rddst = readfn(dst);
+ wrdst = writefn(dst);
+ calc = alphacalc[op];
+
+ /*
+ * If there is no alpha channel, we'll ask for a grey channel
+ * and pretend it is the alpha.
+ */
+ if(mask->flags&Falpha){
+ rdmask = readalphafn(mask);
+ z->mpar.alphaonly = 1;
+ }else{
+ z->mpar.greymaskcall = readfn(mask);
+ z->mpar.convgrey = 1;
+ rdmask = greymaskread;
+
+ /*
+ * Should really be above, but then boolcopyfns would have
+ * to deal with bit alignment, and I haven't written that.
+ *
+ * This is a common case for things like ellipse drawing.
+ * When there's no alpha involved and the mask is boolean,
+ * we can avoid all the division and multiplication.
+ */
+ if(mask->chan == GREY1 && !(src->flags&Falpha))
+ calc = boolcalc[op];
+ else if(op == SoverD && !(src->flags&Falpha))
+ calc = alphacalcS;
+ }
+ }
+
+ /*
+ * If the image has a small enough repl rectangle,
+ * we can just read each line once and cache them.
+ */
+ if(z->spar.replcache){
+ z->spar.replcall = rdsrc;
+ rdsrc = replread;
+ }
+ if(z->mpar.replcache){
+ z->mpar.replcall = rdmask;
+ rdmask = replread;
+ }
+
+ if(z->n < ndrawbuf){
+ free(z->p);
+ if((z->p = mallocz(ndrawbuf, 0)) == nil){
+ z->inuse = 0;
+ return 0;
+ }
+ z->n = ndrawbuf;
+ }
+ drawbuf = z->p;
+
+ /*
+ * Before we were saving only offsets from drawbuf in the parameter
+ * structures; now that drawbuf has been grown to accomodate us,
+ * we can fill in the pointers.
+ */
+ z->spar.bufbase = drawbuf+z->spar.bufoff;
+ z->mpar.bufbase = drawbuf+z->mpar.bufoff;
+ z->dpar.bufbase = drawbuf+z->dpar.bufoff;
+ z->spar.convbuf = drawbuf+z->spar.convbufoff;
+
+ if(dir == 1){
+ starty = 0;
+ endy = dy;
+ }else{
+ starty = dy-1;
+ endy = -1;
+ }
+
+ /*
+ * srcy, masky, and dsty are offsets from the top of their
+ * respective Rectangles. they need to be contained within
+ * the rectangles, so clipy can keep them there without division.
+ */
+ srcy = (starty + sr.min.y - src->r.min.y)%Dy(src->r);
+ masky = (starty + mr.min.y - mask->r.min.y)%Dy(mask->r);
+ dsty = starty + r.min.y - dst->r.min.y;
+
+ assert(0 <= srcy && srcy < Dy(src->r));
+ assert(0 <= masky && masky < Dy(mask->r));
+ assert(0 <= dsty && dsty < Dy(dst->r));
+
+ for(y=starty; y!=endy; y+=dir, srcy+=dir, masky+=dir, dsty+=dir){
+ clipy(src, &srcy);
+ clipy(dst, &dsty);
+ clipy(mask, &masky);
+
+ bsrc = rdsrc(&z->spar, z->spar.bufbase, srcy);
+DBG print("[");
+ bmask = rdmask(&z->mpar, z->mpar.bufbase, masky);
+DBG print("]\n");
+ bdst = rddst(&z->dpar, z->dpar.bufbase, dsty);
+ if(op != Clear && (bsrc.delta != 4 || bdst.delta != 4 || src->chan != dst->chan))
+ bdst.rgba = nil;
+DBG dumpbuf("src", bsrc, dx);
+DBG dumpbuf("mask", bmask, dx);
+DBG dumpbuf("dst", bdst, dx);
+ bdst = calc(bdst, bsrc, bmask, dx, isgrey, op);
+ wrdst(&z->dpar, z->dpar.bytermin+dsty*z->dpar.bwidth, bdst);
+ }
+
+ z->inuse = 0;
+ return 1;
+}
+#undef DBG
+
+static Buffer
+alphacalc0(Buffer bdst, Buffer b1, Buffer b2, int dx, int grey, int op)
+{
+ USED(b1.grey);
+ USED(b2.grey);
+ USED(grey);
+ USED(op);
+ memset(bdst.rgba, 0, dx*bdst.delta);
+ return bdst;
+}
+
+static Buffer
+alphacalc14(Buffer bdst, Buffer bsrc, Buffer bmask, int dx, int grey, int op)
+{
+ Buffer obdst;
+ int fd, sadelta;
+ int i, sa, ma;
+ ulong s, t;
+
+ obdst = bdst;
+ sadelta = bsrc.alpha == &ones ? 0 : bsrc.delta;
+
+ for(i=0; i<dx; i++){
+ sa = *bsrc.alpha;
+ ma = *bmask.alpha;
+ fd = MUL(sa, ma, t);
+ if(op == DoutS)
+ fd = 255-fd;
+
+ if(grey){
+ *bdst.grey = MUL(fd, *bdst.grey, t);
+ bsrc.grey += bsrc.delta;
+ bdst.grey += bdst.delta;
+ }else{
+ if(bdst.rgba){
+ *bdst.rgba = MUL0123(fd, *bdst.rgba, s, t);
+ bsrc.rgba++;
+ bdst.rgba++;
+ bsrc.alpha += sadelta;
+ bmask.alpha += bmask.delta;
+ continue;
+ }
+ *bdst.red = MUL(fd, *bdst.red, t);
+ *bdst.grn = MUL(fd, *bdst.grn, t);
+ *bdst.blu = MUL(fd, *bdst.blu, t);
+ bsrc.red += bsrc.delta;
+ bsrc.blu += bsrc.delta;
+ bsrc.grn += bsrc.delta;
+ bdst.red += bdst.delta;
+ bdst.blu += bdst.delta;
+ bdst.grn += bdst.delta;
+ }
+ if(bdst.alpha != &ones){
+ *bdst.alpha = MUL(fd, *bdst.alpha, t);
+ bdst.alpha += bdst.delta;
+ }
+ bmask.alpha += bmask.delta;
+ bsrc.alpha += sadelta;
+ }
+ return obdst;
+}
+
+static Buffer
+alphacalc2810(Buffer bdst, Buffer bsrc, Buffer bmask, int dx, int grey, int op)
+{
+ Buffer obdst;
+ int fs, sadelta;
+ int i, ma, da;
+ ulong s, t;
+
+ obdst = bdst;
+ sadelta = bsrc.alpha == &ones ? 0 : bsrc.delta;
+
+ for(i=0; i<dx; i++){
+ ma = *bmask.alpha;
+ da = *bdst.alpha;
+ if(op == SoutD)
+ da = 255-da;
+ fs = ma;
+ if(op != S)
+ fs = MUL(fs, da, t);
+
+ if(grey){
+ *bdst.grey = MUL(fs, *bsrc.grey, t);
+ bsrc.grey += bsrc.delta;
+ bdst.grey += bdst.delta;
+ }else{
+ if(bdst.rgba){
+ *bdst.rgba = MUL0123(fs, *bsrc.rgba, s, t);
+ bsrc.rgba++;
+ bdst.rgba++;
+ bmask.alpha += bmask.delta;
+ bdst.alpha += bdst.delta;
+ continue;
+ }
+ *bdst.red = MUL(fs, *bsrc.red, t);
+ *bdst.grn = MUL(fs, *bsrc.grn, t);
+ *bdst.blu = MUL(fs, *bsrc.blu, t);
+ bsrc.red += bsrc.delta;
+ bsrc.blu += bsrc.delta;
+ bsrc.grn += bsrc.delta;
+ bdst.red += bdst.delta;
+ bdst.blu += bdst.delta;
+ bdst.grn += bdst.delta;
+ }
+ if(bdst.alpha != &ones){
+ *bdst.alpha = MUL(fs, *bsrc.alpha, t);
+ bdst.alpha += bdst.delta;
+ }
+ bmask.alpha += bmask.delta;
+ bsrc.alpha += sadelta;
+ }
+ return obdst;
+}
+
+static Buffer
+alphacalc3679(Buffer bdst, Buffer bsrc, Buffer bmask, int dx, int grey, int op)
+{
+ Buffer obdst;
+ int fs, fd, sadelta;
+ int i, sa, ma, da;
+ ulong s, t, q1, q2;
+
+ obdst = bdst;
+ sadelta = bsrc.alpha == &ones ? 0 : bsrc.delta;
+
+ for(i=0; i<dx; i++){
+ sa = *bsrc.alpha;
+ ma = *bmask.alpha;
+ da = *bdst.alpha;
+ if(op == SatopD)
+ fs = MUL(ma, da, t);
+ else
+ fs = MUL(ma, 255-da, t);
+ if(op == DoverS)
+ fd = 255;
+ else{
+ fd = MUL(sa, ma, t);
+ if(op != DatopS)
+ fd = 255-fd;
+ }
+
+ if(grey){
+ *bdst.grey = MUL(fs, *bsrc.grey, s)+MUL(fd, *bdst.grey, t);
+ bsrc.grey += bsrc.delta;
+ bdst.grey += bdst.delta;
+ }else{
+ if(bdst.rgba){
+ q1 = MUL0123(fs, *bsrc.rgba, s, t);
+ q2 = MUL0123(fd, *bdst.rgba, s, t);
+ *bdst.rgba = BWADD(q1, q2);
+ bsrc.rgba++;
+ bdst.rgba++;
+ bsrc.alpha += sadelta;
+ bmask.alpha += bmask.delta;
+ bdst.alpha += bdst.delta;
+ continue;
+ }
+ *bdst.red = MUL(fs, *bsrc.red, s)+MUL(fd, *bdst.red, t);
+ *bdst.grn = MUL(fs, *bsrc.grn, s)+MUL(fd, *bdst.grn, t);
+ *bdst.blu = MUL(fs, *bsrc.blu, s)+MUL(fd, *bdst.blu, t);
+ bsrc.red += bsrc.delta;
+ bsrc.blu += bsrc.delta;
+ bsrc.grn += bsrc.delta;
+ bdst.red += bdst.delta;
+ bdst.blu += bdst.delta;
+ bdst.grn += bdst.delta;
+ }
+ if(bdst.alpha != &ones){
+ *bdst.alpha = MUL(fs, sa, s)+MUL(fd, da, t);
+ bdst.alpha += bdst.delta;
+ }
+ bmask.alpha += bmask.delta;
+ bsrc.alpha += sadelta;
+ }
+ return obdst;
+}
+
+static Buffer
+alphacalc5(Buffer bdst, Buffer b1, Buffer b2, int dx, int grey, int op)
+{
+ USED(b1.grey);
+ USED(b2.grey);
+ USED(dx);
+ USED(grey);
+ USED(op);
+ return bdst;
+}
+
+static Buffer
+alphacalc11(Buffer bdst, Buffer bsrc, Buffer bmask, int dx, int grey, int op)
+{
+ Buffer obdst;
+ int fd, sadelta;
+ int i, sa, ma;
+ ulong s, t, q1, q2;
+
+ USED(op);
+ obdst = bdst;
+ sadelta = bsrc.alpha == &ones ? 0 : bsrc.delta;
+
+ for(i=0; i<dx; i++){
+ sa = *bsrc.alpha;
+ ma = *bmask.alpha;
+ fd = 255-MUL(sa, ma, t);
+
+ if(grey){
+ *bdst.grey = MUL(ma, *bsrc.grey, s)+MUL(fd, *bdst.grey, t);
+ bsrc.grey += bsrc.delta;
+ bdst.grey += bdst.delta;
+ }else{
+ if(bdst.rgba){
+ q1 = MUL0123(ma, *bsrc.rgba, s, t);
+ q2 = MUL0123(fd, *bdst.rgba, s, t);
+ *bdst.rgba = BWADD(q1, q2);
+ bsrc.rgba++;
+ bdst.rgba++;
+ bsrc.alpha += sadelta;
+ bmask.alpha += bmask.delta;
+ continue;
+ }
+ *bdst.red = MUL(ma, *bsrc.red, s)+MUL(fd, *bdst.red, t);
+ *bdst.grn = MUL(ma, *bsrc.grn, s)+MUL(fd, *bdst.grn, t);
+ *bdst.blu = MUL(ma, *bsrc.blu, s)+MUL(fd, *bdst.blu, t);
+ bsrc.red += bsrc.delta;
+ bsrc.blu += bsrc.delta;
+ bsrc.grn += bsrc.delta;
+ bdst.red += bdst.delta;
+ bdst.blu += bdst.delta;
+ bdst.grn += bdst.delta;
+ }
+ if(bdst.alpha != &ones){
+ *bdst.alpha = MUL(ma, sa, s)+MUL(fd, *bdst.alpha, t);
+ bdst.alpha += bdst.delta;
+ }
+ bmask.alpha += bmask.delta;
+ bsrc.alpha += sadelta;
+ }
+ return obdst;
+}
+
+/*
+not used yet
+source and mask alpha 1
+static Buffer
+alphacalcS0(Buffer bdst, Buffer bsrc, Buffer bmask, int dx, int grey, int op)
+{
+ Buffer obdst;
+ int i;
+
+ USED(op);
+ obdst = bdst;
+ if(bsrc.delta == bdst.delta){
+ memmove(bdst.rgba, bsrc.rgba, dx*bdst.delta);
+ return obdst;
+ }
+ for(i=0; i<dx; i++){
+ if(grey){
+ *bdst.grey = *bsrc.grey;
+ bsrc.grey += bsrc.delta;
+ bdst.grey += bdst.delta;
+ }else{
+ *bdst.red = *bsrc.red;
+ *bdst.grn = *bsrc.grn;
+ *bdst.blu = *bsrc.blu;
+ bsrc.red += bsrc.delta;
+ bsrc.blu += bsrc.delta;
+ bsrc.grn += bsrc.delta;
+ bdst.red += bdst.delta;
+ bdst.blu += bdst.delta;
+ bdst.grn += bdst.delta;
+ }
+ if(bdst.alpha != &ones){
+ *bdst.alpha = 255;
+ bdst.alpha += bdst.delta;
+ }
+ }
+ return obdst;
+}
+*/
+
+/* source alpha 1 */
+static Buffer
+alphacalcS(Buffer bdst, Buffer bsrc, Buffer bmask, int dx, int grey, int op)
+{
+ Buffer obdst;
+ int fd;
+ int i, ma;
+ ulong s, t;
+
+ USED(op);
+ obdst = bdst;
+
+ for(i=0; i<dx; i++){
+ ma = *bmask.alpha;
+ fd = 255-ma;
+
+ if(grey){
+ *bdst.grey = MUL(ma, *bsrc.grey, s)+MUL(fd, *bdst.grey, t);
+ bsrc.grey += bsrc.delta;
+ bdst.grey += bdst.delta;
+ }else{
+ *bdst.red = MUL(ma, *bsrc.red, s)+MUL(fd, *bdst.red, t);
+ *bdst.grn = MUL(ma, *bsrc.grn, s)+MUL(fd, *bdst.grn, t);
+ *bdst.blu = MUL(ma, *bsrc.blu, s)+MUL(fd, *bdst.blu, t);
+ bsrc.red += bsrc.delta;
+ bsrc.blu += bsrc.delta;
+ bsrc.grn += bsrc.delta;
+ bdst.red += bdst.delta;
+ bdst.blu += bdst.delta;
+ bdst.grn += bdst.delta;
+ }
+ if(bdst.alpha != &ones){
+ *bdst.alpha = ma+MUL(fd, *bdst.alpha, t);
+ bdst.alpha += bdst.delta;
+ }
+ bmask.alpha += bmask.delta;
+ }
+ return obdst;
+}
+
+static Buffer
+boolcalc14(Buffer bdst, Buffer b1, Buffer bmask, int dx, int grey, int op)
+{
+ Buffer obdst;
+ int i, ma, zero;
+
+ USED(b1.grey);
+ obdst = bdst;
+
+ for(i=0; i<dx; i++){
+ ma = *bmask.alpha;
+ zero = ma ? op == DoutS : op == DinS;
+
+ if(grey){
+ if(zero)
+ *bdst.grey = 0;
+ bdst.grey += bdst.delta;
+ }else{
+ if(zero)
+ *bdst.red = *bdst.grn = *bdst.blu = 0;
+ bdst.red += bdst.delta;
+ bdst.blu += bdst.delta;
+ bdst.grn += bdst.delta;
+ }
+ bmask.alpha += bmask.delta;
+ if(bdst.alpha != &ones){
+ if(zero)
+ *bdst.alpha = 0;
+ bdst.alpha += bdst.delta;
+ }
+ }
+ return obdst;
+}
+
+static Buffer
+boolcalc236789(Buffer bdst, Buffer bsrc, Buffer bmask, int dx, int grey, int op)
+{
+ Buffer obdst;
+ int fs, fd;
+ int i, ma, da, zero;
+ ulong s, t;
+
+ obdst = bdst;
+ zero = !(op&1);
+
+ for(i=0; i<dx; i++){
+ ma = *bmask.alpha;
+ da = *bdst.alpha;
+ fs = da;
+ if(op&2)
+ fs = 255-da;
+ fd = 0;
+ if(op&4)
+ fd = 255;
+
+ if(grey){
+ if(ma)
+ *bdst.grey = MUL(fs, *bsrc.grey, s)+MUL(fd, *bdst.grey, t);
+ else if(zero)
+ *bdst.grey = 0;
+ bsrc.grey += bsrc.delta;
+ bdst.grey += bdst.delta;
+ }else{
+ if(ma){
+ *bdst.red = MUL(fs, *bsrc.red, s)+MUL(fd, *bdst.red, t);
+ *bdst.grn = MUL(fs, *bsrc.grn, s)+MUL(fd, *bdst.grn, t);
+ *bdst.blu = MUL(fs, *bsrc.blu, s)+MUL(fd, *bdst.blu, t);
+ }
+ else if(zero)
+ *bdst.red = *bdst.grn = *bdst.blu = 0;
+ bsrc.red += bsrc.delta;
+ bsrc.blu += bsrc.delta;
+ bsrc.grn += bsrc.delta;
+ bdst.red += bdst.delta;
+ bdst.blu += bdst.delta;
+ bdst.grn += bdst.delta;
+ }
+ bmask.alpha += bmask.delta;
+ if(bdst.alpha != &ones){
+ if(ma)
+ *bdst.alpha = fs+MUL(fd, da, t);
+ else if(zero)
+ *bdst.alpha = 0;
+ bdst.alpha += bdst.delta;
+ }
+ }
+ return obdst;
+}
+
+static Buffer
+boolcalc1011(Buffer bdst, Buffer bsrc, Buffer bmask, int dx, int grey, int op)
+{
+ Buffer obdst;
+ int i, ma, zero;
+
+ obdst = bdst;
+ zero = !(op&1);
+
+ for(i=0; i<dx; i++){
+ ma = *bmask.alpha;
+
+ if(grey){
+ if(ma)
+ *bdst.grey = *bsrc.grey;
+ else if(zero)
+ *bdst.grey = 0;
+ bsrc.grey += bsrc.delta;
+ bdst.grey += bdst.delta;
+ }else{
+ if(ma){
+ *bdst.red = *bsrc.red;
+ *bdst.grn = *bsrc.grn;
+ *bdst.blu = *bsrc.blu;
+ }
+ else if(zero)
+ *bdst.red = *bdst.grn = *bdst.blu = 0;
+ bsrc.red += bsrc.delta;
+ bsrc.blu += bsrc.delta;
+ bsrc.grn += bsrc.delta;
+ bdst.red += bdst.delta;
+ bdst.blu += bdst.delta;
+ bdst.grn += bdst.delta;
+ }
+ bmask.alpha += bmask.delta;
+ if(bdst.alpha != &ones){
+ if(ma)
+ *bdst.alpha = 255;
+ else if(zero)
+ *bdst.alpha = 0;
+ bdst.alpha += bdst.delta;
+ }
+ }
+ return obdst;
+}
+/*
+ * Replicated cached scan line read. Call the function listed in the Param,
+ * but cache the result so that for replicated images we only do the work once.
+ */
+static Buffer
+replread(Param *p, uchar *s, int y)
+{
+ Buffer *b;
+
+ USED(s);
+ b = &p->bcache[y];
+ if((p->bfilled & (1<<y)) == 0){
+ p->bfilled |= 1<<y;
+ *b = p->replcall(p, p->bufbase+y*p->bufdelta, y);
+ }
+ return *b;
+}
+
+/*
+ * Alpha reading function that simply relabels the grey pointer.
+ */
+static Buffer
+greymaskread(Param *p, uchar *buf, int y)
+{
+ Buffer b;
+
+ b = p->greymaskcall(p, buf, y);
+ b.alpha = b.grey;
+ return b;
+}
+
+#define DBG if(0)
+static Buffer
+readnbit(Param *p, uchar *buf, int y)
+{
+ Buffer b;
+ Memimage *img;
+ uchar *repl, *r, *w, *ow, bits;
+ int i, n, sh, depth, x, dx, npack, nbits;
+
+ b.rgba = (ulong*)buf;
+ b.grey = w = buf;
+ b.red = b.blu = b.grn = w;
+ b.alpha = &ones;
+ b.delta = 1;
+
+ dx = p->dx;
+ img = p->img;
+ depth = img->depth;
+ repl = &replbit[depth][0];
+ npack = 8/depth;
+ sh = 8-depth;
+
+ /* copy from p->r.min.x until end of repl rectangle */
+ x = p->r.min.x;
+ n = dx;
+ if(n > p->img->r.max.x - x)
+ n = p->img->r.max.x - x;
+
+ r = p->bytermin + y*p->bwidth;
+DBG print("readnbit dx %d %p=%p+%d*%d, *r=%d fetch %d ", dx, r, p->bytermin, y, p->bwidth, *r, n);
+ bits = *r++;
+ nbits = 8;
+ if(i=x&(npack-1)){
+DBG print("throwaway %d...", i);
+ bits <<= depth*i;
+ nbits -= depth*i;
+ }
+ for(i=0; i<n; i++){
+ if(nbits == 0){
+DBG print("(%.2ux)...", *r);
+ bits = *r++;
+ nbits = 8;
+ }
+ *w++ = repl[bits>>sh];
+DBG print("bit %x...", repl[bits>>sh]);
+ bits <<= depth;
+ nbits -= depth;
+ }
+ dx -= n;
+ if(dx == 0)
+ return b;
+
+ assert(x+i == p->img->r.max.x);
+
+ /* copy from beginning of repl rectangle until where we were before. */
+ x = p->img->r.min.x;
+ n = dx;
+ if(n > p->r.min.x - x)
+ n = p->r.min.x - x;
+
+ r = p->bytey0s + y*p->bwidth;
+DBG print("x=%d r=%p...", x, r);
+ bits = *r++;
+ nbits = 8;
+ if(i=x&(npack-1)){
+ bits <<= depth*i;
+ nbits -= depth*i;
+ }
+DBG print("nbits=%d...", nbits);
+ for(i=0; i<n; i++){
+ if(nbits == 0){
+ bits = *r++;
+ nbits = 8;
+ }
+ *w++ = repl[bits>>sh];
+DBG print("bit %x...", repl[bits>>sh]);
+ bits <<= depth;
+ nbits -= depth;
+DBG print("bits %x nbits %d...", bits, nbits);
+ }
+ dx -= n;
+ if(dx == 0)
+ return b;
+
+ assert(dx > 0);
+ /* now we have exactly one full scan line: just replicate the buffer itself until we are done */
+ ow = buf;
+ while(dx--)
+ *w++ = *ow++;
+
+ return b;
+}
+#undef DBG
+
+#define DBG if(0)
+static void
+writenbit(Param *p, uchar *w, Buffer src)
+{
+ uchar *r;
+ ulong bits;
+ int i, sh, depth, npack, nbits, x, ex;
+
+ assert(src.grey != nil && src.delta == 1);
+
+ x = p->r.min.x;
+ ex = x+p->dx;
+ depth = p->img->depth;
+ npack = 8/depth;
+
+ i=x&(npack-1);
+ bits = i ? (*w >> (8-depth*i)) : 0;
+ nbits = depth*i;
+ sh = 8-depth;
+ r = src.grey;
+
+ for(; x<ex; x++){
+ bits <<= depth;
+DBG print(" %x", *r);
+ bits |= (*r++ >> sh);
+ nbits += depth;
+ if(nbits == 8){
+ *w++ = bits;
+ nbits = 0;
+ }
+ }
+
+ if(nbits){
+ sh = 8-nbits;
+ bits <<= sh;
+ bits |= *w & ((1<<sh)-1);
+ *w = bits;
+ }
+DBG print("\n");
+ return;
+}
+#undef DBG
+
+static Buffer
+readcmap(Param *p, uchar *buf, int y)
+{
+ Buffer b;
+ int a, convgrey, copyalpha, dx, i, m;
+ uchar *q, *cmap, *begin, *end, *r, *w;
+
+ begin = p->bytey0s + y*p->bwidth;
+ r = p->bytermin + y*p->bwidth;
+ end = p->bytey0e + y*p->bwidth;
+ cmap = p->img->cmap->cmap2rgb;
+ convgrey = p->convgrey;
+ copyalpha = (p->img->flags&Falpha) ? 1 : 0;
+
+ w = buf;
+ dx = p->dx;
+ if(copyalpha){
+ b.alpha = buf++;
+ a = p->img->shift[CAlpha]/8;
+ m = p->img->shift[CMap]/8;
+ for(i=0; i<dx; i++){
+ *w++ = r[a];
+ q = cmap+r[m]*3;
+ r += 2;
+ if(r == end)
+ r = begin;
+ if(convgrey){
+ *w++ = RGB2K(q[0], q[1], q[2]);
+ }else{
+ *w++ = q[2]; /* blue */
+ *w++ = q[1]; /* green */
+ *w++ = q[0]; /* red */
+ }
+ }
+ }else{
+ b.alpha = &ones;
+ for(i=0; i<dx; i++){
+ q = cmap+*r++*3;
+ if(r == end)
+ r = begin;
+ if(convgrey){
+ *w++ = RGB2K(q[0], q[1], q[2]);
+ }else{
+ *w++ = q[2]; /* blue */
+ *w++ = q[1]; /* green */
+ *w++ = q[0]; /* red */
+ }
+ }
+ }
+
+ b.rgba = (ulong*)(buf-copyalpha);
+
+ if(convgrey){
+ b.grey = buf;
+ b.red = b.blu = b.grn = buf;
+ b.delta = 1+copyalpha;
+ }else{
+ b.blu = buf;
+ b.grn = buf+1;
+ b.red = buf+2;
+ b.grey = nil;
+ b.delta = 3+copyalpha;
+ }
+ return b;
+}
+
+static void
+writecmap(Param *p, uchar *w, Buffer src)
+{
+ uchar *cmap, *red, *grn, *blu;
+ int i, dx, delta;
+
+ cmap = p->img->cmap->rgb2cmap;
+
+ delta = src.delta;
+ red= src.red;
+ grn = src.grn;
+ blu = src.blu;
+
+ dx = p->dx;
+ for(i=0; i<dx; i++, red+=delta, grn+=delta, blu+=delta)
+ *w++ = cmap[(*red>>4)*256+(*grn>>4)*16+(*blu>>4)];
+}
+
+#define DBG if(0)
+static Buffer
+readbyte(Param *p, uchar *buf, int y)
+{
+ Buffer b;
+ Memimage *img;
+ int dx, isgrey, convgrey, alphaonly, copyalpha, i, nb;
+ uchar *begin, *end, *r, *w, *rrepl, *grepl, *brepl, *arepl, *krepl;
+ uchar ured, ugrn, ublu;
+ ulong u;
+
+ img = p->img;
+ begin = p->bytey0s + y*p->bwidth;
+ r = p->bytermin + y*p->bwidth;
+ end = p->bytey0e + y*p->bwidth;
+
+ w = buf;
+ dx = p->dx;
+ nb = img->depth/8;
+
+ convgrey = p->convgrey; /* convert rgb to grey */
+ isgrey = img->flags&Fgrey;
+ alphaonly = p->alphaonly;
+ copyalpha = (img->flags&Falpha) ? 1 : 0;
+
+DBG print("copyalpha %d alphaonly %d convgrey %d isgrey %d\n", copyalpha, alphaonly, convgrey, isgrey);
+ /* if we can, avoid processing everything */
+ if(!(img->flags&Frepl) && !convgrey && (img->flags&Fbytes)){
+ memset(&b, 0, sizeof b);
+ if(p->needbuf){
+ memmove(buf, r, dx*nb);
+ r = buf;
+ }
+ b.rgba = (ulong*)r;
+ if(copyalpha)
+ b.alpha = r+img->shift[CAlpha]/8;
+ else
+ b.alpha = &ones;
+ if(isgrey){
+ b.grey = r+img->shift[CGrey]/8;
+ b.red = b.grn = b.blu = b.grey;
+ }else{
+ b.red = r+img->shift[CRed]/8;
+ b.grn = r+img->shift[CGreen]/8;
+ b.blu = r+img->shift[CBlue]/8;
+ }
+ b.delta = nb;
+ return b;
+ }
+
+DBG print("2\n");
+ rrepl = replbit[img->nbits[CRed]];
+ grepl = replbit[img->nbits[CGreen]];
+ brepl = replbit[img->nbits[CBlue]];
+ arepl = replbit[img->nbits[CAlpha]];
+ krepl = replbit[img->nbits[CGrey]];
+
+ for(i=0; i<dx; i++){
+ u = r[0] | (r[1]<<8) | (r[2]<<16) | (r[3]<<24);
+ if(copyalpha) {
+ *w++ = arepl[(u>>img->shift[CAlpha]) & img->mask[CAlpha]];
+DBG print("a %x\n", w[-1]);
+ }
+
+ if(isgrey)
+ *w++ = krepl[(u >> img->shift[CGrey]) & img->mask[CGrey]];
+ else if(!alphaonly){
+ ured = rrepl[(u >> img->shift[CRed]) & img->mask[CRed]];
+ ugrn = grepl[(u >> img->shift[CGreen]) & img->mask[CGreen]];
+ ublu = brepl[(u >> img->shift[CBlue]) & img->mask[CBlue]];
+ if(convgrey){
+DBG print("g %x %x %x\n", ured, ugrn, ublu);
+ *w++ = RGB2K(ured, ugrn, ublu);
+DBG print("%x\n", w[-1]);
+ }else{
+ *w++ = ublu;
+ *w++ = ugrn;
+ *w++ = ured;
+ }
+ }
+ r += nb;
+ if(r == end)
+ r = begin;
+ }
+
+ b.alpha = copyalpha ? buf : &ones;
+ b.rgba = (ulong*)buf;
+ if(alphaonly){
+ b.red = b.grn = b.blu = b.grey = nil;
+ if(!copyalpha)
+ b.rgba = nil;
+ b.delta = 1;
+ }else if(isgrey || convgrey){
+ b.grey = buf+copyalpha;
+ b.red = b.grn = b.blu = buf+copyalpha;
+ b.delta = copyalpha+1;
+DBG print("alpha %x grey %x\n", b.alpha ? *b.alpha : 0xFF, *b.grey);
+ }else{
+ b.blu = buf+copyalpha;
+ b.grn = buf+copyalpha+1;
+ b.grey = nil;
+ b.red = buf+copyalpha+2;
+ b.delta = copyalpha+3;
+ }
+ return b;
+}
+#undef DBG
+
+#define DBG if(0)
+static void
+writebyte(Param *p, uchar *w, Buffer src)
+{
+ Memimage *img;
+ int i, isalpha, isgrey, nb, delta, dx, adelta;
+ uchar ff, *red, *grn, *blu, *grey, *alpha;
+ ulong u, mask;
+
+ img = p->img;
+
+ red = src.red;
+ grn = src.grn;
+ blu = src.blu;
+ alpha = src.alpha;
+ delta = src.delta;
+ grey = src.grey;
+ dx = p->dx;
+
+ nb = img->depth/8;
+ mask = (nb==4) ? 0 : ~((1<<img->depth)-1);
+
+ isalpha = img->flags&Falpha;
+ isgrey = img->flags&Fgrey;
+ adelta = src.delta;
+
+ if(isalpha && (alpha == nil || alpha == &ones)){
+ ff = 0xFF;
+ alpha = &ff;
+ adelta = 0;
+ }
+
+ for(i=0; i<dx; i++){
+ u = w[0] | (w[1]<<8) | (w[2]<<16) | (w[3]<<24);
+DBG print("u %.8lux...", u);
+ u &= mask;
+DBG print("&mask %.8lux...", u);
+ if(isgrey){
+ u |= ((*grey >> (8-img->nbits[CGrey])) & img->mask[CGrey]) << img->shift[CGrey];
+DBG print("|grey %.8lux...", u);
+ grey += delta;
+ }else{
+ u |= ((*red >> (8-img->nbits[CRed])) & img->mask[CRed]) << img->shift[CRed];
+ u |= ((*grn >> (8-img->nbits[CGreen])) & img->mask[CGreen]) << img->shift[CGreen];
+ u |= ((*blu >> (8-img->nbits[CBlue])) & img->mask[CBlue]) << img->shift[CBlue];
+ red += delta;
+ grn += delta;
+ blu += delta;
+DBG print("|rgb %.8lux...", u);
+ }
+
+ if(isalpha){
+ u |= ((*alpha >> (8-img->nbits[CAlpha])) & img->mask[CAlpha]) << img->shift[CAlpha];
+ alpha += adelta;
+DBG print("|alpha %.8lux...", u);
+ }
+
+ w[0] = u;
+ w[1] = u>>8;
+ w[2] = u>>16;
+ w[3] = u>>24;
+ w += nb;
+ }
+}
+#undef DBG
+
+static Readfn*
+readfn(Memimage *img)
+{
+ if(img->depth < 8)
+ return readnbit;
+ if(img->nbits[CMap] == 8)
+ return readcmap;
+ return readbyte;
+}
+
+static Readfn*
+readalphafn(Memimage *m)
+{
+ USED(m);
+ return readbyte;
+}
+
+static Writefn*
+writefn(Memimage *img)
+{
+ if(img->depth < 8)
+ return writenbit;
+ if(img->chan == CMAP8)
+ return writecmap;
+ return writebyte;
+}
+
+static void
+nullwrite(Param *p, uchar *s, Buffer b)
+{
+ USED(p);
+ USED(s);
+ USED(b.grey);
+}
+
+static Buffer
+readptr(Param *p, uchar *s, int y)
+{
+ Buffer b;
+ uchar *q;
+
+ USED(s);
+ q = p->bytermin + y*p->bwidth;
+ b.red = q; /* ptr to data */
+ b.grn = b.blu = b.grey = b.alpha = nil;
+ b.rgba = (ulong*)q;
+ b.delta = p->img->depth/8;
+ return b;
+}
+
+static Buffer
+boolmemmove(Buffer bdst, Buffer bsrc, Buffer b1, int dx, int i, int o)
+{
+ USED(i);
+ USED(o);
+ USED(b1.grey);
+ memmove(bdst.red, bsrc.red, dx*bdst.delta);
+ return bdst;
+}
+
+static Buffer
+boolcopy8(Buffer bdst, Buffer bsrc, Buffer bmask, int dx, int i, int o)
+{
+ uchar *m, *r, *w, *ew;
+
+ USED(i);
+ USED(o);
+ m = bmask.grey;
+ w = bdst.red;
+ r = bsrc.red;
+ ew = w+dx;
+ for(; w < ew; w++,r++)
+ if(*m++)
+ *w = *r;
+ return bdst; /* not used */
+}
+
+static Buffer
+boolcopy16(Buffer bdst, Buffer bsrc, Buffer bmask, int dx, int i, int o)
+{
+ uchar *m;
+ ushort *r, *w, *ew;
+
+ USED(i);
+ USED(o);
+ m = bmask.grey;
+ w = (ushort*)bdst.red;
+ r = (ushort*)bsrc.red;
+ ew = w+dx;
+ for(; w < ew; w++,r++)
+ if(*m++)
+ *w = *r;
+ return bdst; /* not used */
+}
+
+static Buffer
+boolcopy24(Buffer bdst, Buffer bsrc, Buffer bmask, int dx, int i, int o)
+{
+ uchar *m;
+ uchar *r, *w, *ew;
+
+ USED(i);
+ USED(o);
+ m = bmask.grey;
+ w = bdst.red;
+ r = bsrc.red;
+ ew = w+dx*3;
+ while(w < ew){
+ if(*m++){
+ *w++ = *r++;
+ *w++ = *r++;
+ *w++ = *r++;
+ }else{
+ w += 3;
+ r += 3;
+ }
+ }
+ return bdst; /* not used */
+}
+
+static Buffer
+boolcopy32(Buffer bdst, Buffer bsrc, Buffer bmask, int dx, int i, int o)
+{
+ uchar *m;
+ ulong *r, *w, *ew;
+
+ USED(i);
+ USED(o);
+ m = bmask.grey;
+ w = (ulong*)bdst.red;
+ r = (ulong*)bsrc.red;
+ ew = w+dx;
+ for(; w < ew; w++,r++)
+ if(*m++)
+ *w = *r;
+ return bdst; /* not used */
+}
+
+static Buffer
+genconv(Param *p, uchar *buf, int y)
+{
+ Buffer b;
+ int nb;
+ uchar *r, *w, *ew;
+
+ /* read from source into RGB format in convbuf */
+ b = p->convreadcall(p, p->convbuf, y);
+
+ /* write RGB format into dst format in buf */
+ p->convwritecall(p->convdpar, buf, b);
+
+ if(p->convdx){
+ nb = p->convdpar->img->depth/8;
+ r = buf;
+ w = buf+nb*p->dx;
+ ew = buf+nb*p->convdx;
+ while(w<ew)
+ *w++ = *r++;
+ }
+
+ b.red = buf;
+ b.blu = b.grn = b.grey = b.alpha = nil;
+ b.rgba = (ulong*)buf;
+ b.delta = 0;
+
+ return b;
+}
+
+static Readfn*
+convfn(Memimage *dst, Param *dpar, Memimage *src, Param *spar, int *ndrawbuf)
+{
+ if(dst->chan == src->chan && !(src->flags&Frepl)){
+//if(drawdebug) iprint("readptr...");
+ return readptr;
+ }
+
+ if(dst->chan==CMAP8 && (src->chan==GREY1||src->chan==GREY2||src->chan==GREY4)){
+ /* cheat because we know the replicated value is exactly the color map entry. */
+//if(drawdebug) iprint("Readnbit...");
+ return readnbit;
+ }
+
+ spar->convreadcall = readfn(src);
+ spar->convwritecall = writefn(dst);
+ spar->convdpar = dpar;
+
+ /* allocate a conversion buffer */
+ spar->convbufoff = *ndrawbuf;
+ *ndrawbuf += spar->dx*4;
+
+ if(spar->dx > Dx(spar->img->r)){
+ spar->convdx = spar->dx;
+ spar->dx = Dx(spar->img->r);
+ }
+
+//if(drawdebug) iprint("genconv...");
+ return genconv;
+}
+
+static ulong
+pixelbits(Memimage *i, Point pt)
+{
+ uchar *p;
+ ulong val;
+ int off, bpp, npack;
+
+ val = 0;
+ p = byteaddr(i, pt);
+ switch(bpp=i->depth){
+ case 1:
+ case 2:
+ case 4:
+ npack = 8/bpp;
+ off = pt.x%npack;
+ val = p[0] >> bpp*(npack-1-off);
+ val &= (1<<bpp)-1;
+ break;
+ case 8:
+ val = p[0];
+ break;
+ case 16:
+ val = p[0]|(p[1]<<8);
+ break;
+ case 24:
+ val = p[0]|(p[1]<<8)|(p[2]<<16);
+ break;
+ case 32:
+ val = p[0]|(p[1]<<8)|(p[2]<<16)|(p[3]<<24);
+ break;
+ }
+ while(bpp<32){
+ val |= val<<bpp;
+ bpp *= 2;
+ }
+ return val;
+}
+
+static Calcfn*
+boolcopyfn(Memimage *img, Memimage *mask)
+{
+ if(mask->flags&Frepl && Dx(mask->r)==1 && Dy(mask->r)==1 && pixelbits(mask, mask->r.min)==~0)
+ return boolmemmove;
+
+ switch(img->depth){
+ case 8:
+ return boolcopy8;
+ case 16:
+ return boolcopy16;
+ case 24:
+ return boolcopy24;
+ case 32:
+ return boolcopy32;
+ default:
+ assert(0 /* boolcopyfn */);
+ }
+ return nil;
+}
+
+/*
+ * Optimized draw for filling and scrolling; uses memset and memmove.
+ */
+static void
+memsetb(void *vp, uchar val, int n)
+{
+ uchar *p, *ep;
+
+ p = vp;
+ ep = p+n;
+ while(p<ep)
+ *p++ = val;
+}
+
+static void
+memsets(void *vp, ushort val, int n)
+{
+ ushort *p, *ep;
+
+ p = vp;
+ ep = p+n;
+ while(p<ep)
+ *p++ = val;
+}
+
+static void
+memsetl(void *vp, ulong val, int n)
+{
+ ulong *p, *ep;
+
+ p = vp;
+ ep = p+n;
+ while(p<ep)
+ *p++ = val;
+}
+
+static void
+memset24(void *vp, ulong val, int n)
+{
+ uchar *p, *ep;
+ uchar a,b,c;
+
+ p = vp;
+ ep = p+3*n;
+ a = val;
+ b = val>>8;
+ c = val>>16;
+ while(p<ep){
+ *p++ = a;
+ *p++ = b;
+ *p++ = c;
+ }
+}
+
+static ulong
+imgtorgba(Memimage *img, ulong val)
+{
+ uchar r, g, b, a;
+ int nb, ov, v;
+ ulong chan;
+ uchar *p;
+
+ a = 0xFF;
+ r = g = b = 0xAA; /* garbage */
+ for(chan=img->chan; chan; chan>>=8){
+ nb = NBITS(chan);
+ ov = v = val&((1<<nb)-1);
+ val >>= nb;
+
+ while(nb < 8){
+ v |= v<<nb;
+ nb *= 2;
+ }
+ v >>= (nb-8);
+
+ switch(TYPE(chan)){
+ case CRed:
+ r = v;
+ break;
+ case CGreen:
+ g = v;
+ break;
+ case CBlue:
+ b = v;
+ break;
+ case CAlpha:
+ a = v;
+ break;
+ case CGrey:
+ r = g = b = v;
+ break;
+ case CMap:
+ p = img->cmap->cmap2rgb+3*ov;
+ r = *p++;
+ g = *p++;
+ b = *p;
+ break;
+ }
+ }
+ return (r<<24)|(g<<16)|(b<<8)|a;
+}
+
+static ulong
+rgbatoimg(Memimage *img, ulong rgba)
+{
+ ulong chan;
+ int d, nb;
+ ulong v;
+ uchar *p, r, g, b, a, m;
+
+ v = 0;
+ r = rgba>>24;
+ g = rgba>>16;
+ b = rgba>>8;
+ a = rgba;
+ d = 0;
+ for(chan=img->chan; chan; chan>>=8){
+ nb = NBITS(chan);
+ switch(TYPE(chan)){
+ case CRed:
+ v |= (r>>(8-nb))<<d;
+ break;
+ case CGreen:
+ v |= (g>>(8-nb))<<d;
+ break;
+ case CBlue:
+ v |= (b>>(8-nb))<<d;
+ break;
+ case CAlpha:
+ v |= (a>>(8-nb))<<d;
+ break;
+ case CMap:
+ p = img->cmap->rgb2cmap;
+ m = p[(r>>4)*256+(g>>4)*16+(b>>4)];
+ v |= (m>>(8-nb))<<d;
+ break;
+ case CGrey:
+ m = RGB2K(r,g,b);
+ v |= (m>>(8-nb))<<d;
+ break;
+ }
+ d += nb;
+ }
+// print("rgba2img %.8lux = %.*lux\n", rgba, 2*d/8, v);
+ return v;
+}
+
+#define DBG if(0)
+static int
+memoptdraw(Memdrawparam *par)
+{
+ int m, y, dy, dx, op;
+ ulong v;
+ Memimage *src;
+ Memimage *dst;
+
+ dx = Dx(par->r);
+ dy = Dy(par->r);
+ src = par->src;
+ dst = par->dst;
+ op = par->op;
+
+DBG print("state %lux mval %lux dd %d\n", par->state, par->mval, dst->depth);
+ /*
+ * If we have an opaque mask and source is one opaque pixel we can convert to the
+ * destination format and just replicate with memset.
+ */
+ m = Simplesrc|Simplemask|Fullmask;
+ if((par->state&m)==m && (par->srgba&0xFF) == 0xFF && (op ==S || op == SoverD)){
+ uchar *dp, p[4];
+ int d, dwid, ppb, np, nb;
+ uchar lm, rm;
+
+DBG print("memopt, dst %p, dst->data->bdata %p\n", dst, dst->data->bdata);
+ dwid = dst->width*sizeof(ulong);
+ dp = byteaddr(dst, par->r.min);
+ v = par->sdval;
+DBG print("sdval %lud, depth %d\n", v, dst->depth);
+ switch(dst->depth){
+ case 1:
+ case 2:
+ case 4:
+ for(d=dst->depth; d<8; d*=2)
+ v |= (v<<d);
+ ppb = 8/dst->depth; /* pixels per byte */
+ m = ppb-1;
+ /* left edge */
+ np = par->r.min.x&m; /* no. pixels unused on left side of word */
+ dx -= (ppb-np);
+ nb = 8 - np * dst->depth; /* no. bits used on right side of word */
+ lm = (1<<nb)-1;
+DBG print("np %d x %d nb %d lm %ux ppb %d m %ux\n", np, par->r.min.x, nb, lm, ppb, m);
+
+ /* right edge */
+ np = par->r.max.x&m; /* no. pixels used on left side of word */
+ dx -= np;
+ nb = 8 - np * dst->depth; /* no. bits unused on right side of word */
+ rm = ~((1<<nb)-1);
+DBG print("np %d x %d nb %d rm %ux ppb %d m %ux\n", np, par->r.max.x, nb, rm, ppb, m);
+
+DBG print("dx %d Dx %d\n", dx, Dx(par->r));
+ /* lm, rm are masks that are 1 where we should touch the bits */
+ if(dx < 0){ /* just one byte */
+ lm &= rm;
+ for(y=0; y<dy; y++, dp+=dwid)
+ *dp ^= (v ^ *dp) & lm;
+ }else if(dx == 0){ /* no full bytes */
+ if(lm)
+ dwid--;
+
+ for(y=0; y<dy; y++, dp+=dwid){
+ if(lm){
+DBG print("dp %p v %lux lm %ux (v ^ *dp) & lm %lux\n", dp, v, lm, (v^*dp)&lm);
+ *dp ^= (v ^ *dp) & lm;
+ dp++;
+ }
+ *dp ^= (v ^ *dp) & rm;
+ }
+ }else{ /* full bytes in middle */
+ dx /= ppb;
+ if(lm)
+ dwid--;
+ dwid -= dx;
+
+ for(y=0; y<dy; y++, dp+=dwid){
+ if(lm){
+ *dp ^= (v ^ *dp) & lm;
+ dp++;
+ }
+ memset(dp, v, dx);
+ dp += dx;
+ *dp ^= (v ^ *dp) & rm;
+ }
+ }
+ return 1;
+ case 8:
+ for(y=0; y<dy; y++, dp+=dwid)
+ memset(dp, v, dx);
+ return 1;
+ case 16:
+ p[0] = v; /* make little endian */
+ p[1] = v>>8;
+ v = *(ushort*)p;
+DBG print("dp=%p; dx=%d; for(y=0; y<%d; y++, dp+=%d)\nmemsets(dp, v, dx);\n",
+ dp, dx, dy, dwid);
+ for(y=0; y<dy; y++, dp+=dwid)
+ memsets(dp, v, dx);
+ return 1;
+ case 24:
+ for(y=0; y<dy; y++, dp+=dwid)
+ memset24(dp, v, dx);
+ return 1;
+ case 32:
+ p[0] = v; /* make little endian */
+ p[1] = v>>8;
+ p[2] = v>>16;
+ p[3] = v>>24;
+ v = *(ulong*)p;
+ for(y=0; y<dy; y++, dp+=dwid)
+ memsetl(dp, v, dx);
+ return 1;
+ default:
+ assert(0 /* bad dest depth in memoptdraw */);
+ }
+ }
+
+ /*
+ * If no source alpha, an opaque mask, we can just copy the
+ * source onto the destination. If the channels are the same and
+ * the source is not replicated, memmove suffices.
+ */
+ m = Simplemask|Fullmask;
+ if((par->state&(m|Replsrc))==m && src->depth >= 8
+ && src->chan == dst->chan && (op == S || (op == SoverD && !(src->flags&Falpha)))){
+ uchar *sp, *dp;
+ long swid, dwid, nb;
+ int dir;
+
+ if(src->data == dst->data && byteaddr(dst, par->r.min) > byteaddr(src, par->sr.min))
+ dir = -1;
+ else
+ dir = 1;
+
+ swid = src->width*sizeof(ulong);
+ dwid = dst->width*sizeof(ulong);
+ sp = byteaddr(src, par->sr.min);
+ dp = byteaddr(dst, par->r.min);
+ if(dir == -1){
+ sp += (dy-1)*swid;
+ dp += (dy-1)*dwid;
+ swid = -swid;
+ dwid = -dwid;
+ }
+ nb = (dx*src->depth)/8;
+ for(y=0; y<dy; y++, sp+=swid, dp+=dwid)
+ memmove(dp, sp, nb);
+ return 1;
+ }
+
+ /*
+ * If we have a 1-bit mask, 1-bit source, and 1-bit destination, and
+ * they're all bit aligned, we can just use bit operators. This happens
+ * when we're manipulating boolean masks, e.g. in the arc code.
+ */
+ if((par->state&(Simplemask|Simplesrc|Replmask|Replsrc))==0
+ && dst->chan==GREY1 && src->chan==GREY1 && par->mask->chan==GREY1
+ && (par->r.min.x&7)==(par->sr.min.x&7) && (par->r.min.x&7)==(par->mr.min.x&7)){
+ uchar *sp, *dp, *mp;
+ uchar lm, rm;
+ long swid, dwid, mwid;
+ int i, x, dir;
+
+ sp = byteaddr(src, par->sr.min);
+ dp = byteaddr(dst, par->r.min);
+ mp = byteaddr(par->mask, par->mr.min);
+ swid = src->width*sizeof(ulong);
+ dwid = dst->width*sizeof(ulong);
+ mwid = par->mask->width*sizeof(ulong);
+
+ if(src->data == dst->data && byteaddr(dst, par->r.min) > byteaddr(src, par->sr.min)){
+ dir = -1;
+ }else
+ dir = 1;
+
+ lm = 0xFF>>(par->r.min.x&7);
+ rm = 0xFF<<(8-(par->r.max.x&7));
+ dx -= (8-(par->r.min.x&7)) + (par->r.max.x&7);
+
+ if(dx < 0){ /* one byte wide */
+ lm &= rm;
+ if(dir == -1){
+ dp += dwid*(dy-1);
+ sp += swid*(dy-1);
+ mp += mwid*(dy-1);
+ dwid = -dwid;
+ swid = -swid;
+ mwid = -mwid;
+ }
+ for(y=0; y<dy; y++){
+ *dp ^= (*dp ^ *sp) & *mp & lm;
+ dp += dwid;
+ sp += swid;
+ mp += mwid;
+ }
+ return 1;
+ }
+
+ dx /= 8;
+ if(dir == 1){
+ i = (lm!=0)+dx+(rm!=0);
+ mwid -= i;
+ swid -= i;
+ dwid -= i;
+ for(y=0; y<dy; y++, dp+=dwid, sp+=swid, mp+=mwid){
+ if(lm){
+ *dp ^= (*dp ^ *sp++) & *mp++ & lm;
+ dp++;
+ }
+ for(x=0; x<dx; x++){
+ *dp ^= (*dp ^ *sp++) & *mp++;
+ dp++;
+ }
+ if(rm){
+ *dp ^= (*dp ^ *sp++) & *mp++ & rm;
+ dp++;
+ }
+ }
+ return 1;
+ }else{
+ /* dir == -1 */
+ i = (lm!=0)+dx+(rm!=0);
+ dp += dwid*(dy-1)+i-1;
+ sp += swid*(dy-1)+i-1;
+ mp += mwid*(dy-1)+i-1;
+ dwid = -dwid+i;
+ swid = -swid+i;
+ mwid = -mwid+i;
+ for(y=0; y<dy; y++, dp+=dwid, sp+=swid, mp+=mwid){
+ if(rm){
+ *dp ^= (*dp ^ *sp--) & *mp-- & rm;
+ dp--;
+ }
+ for(x=0; x<dx; x++){
+ *dp ^= (*dp ^ *sp--) & *mp--;
+ dp--;
+ }
+ if(lm){
+ *dp ^= (*dp ^ *sp--) & *mp-- & lm;
+ dp--;
+ }
+ }
+ }
+ return 1;
+ }
+ return 0;
+}
+#undef DBG
+
+/*
+ * Boolean character drawing.
+ * Solid opaque color through a 1-bit greyscale mask.
+ */
+#define DBG if(0)
+static int
+chardraw(Memdrawparam *par)
+{
+ ulong bits;
+ int i, ddepth, dy, dx, x, bx, ex, y, npack, bsh, depth, op;
+ ulong v, maskwid, dstwid;
+ uchar *wp, *rp, *q, *wc;
+ ushort *ws;
+ ulong *wl;
+ uchar sp[4];
+ Rectangle r, mr;
+ Memimage *mask, *src, *dst;
+
+if(0) if(drawdebug) iprint("chardraw? mf %lux md %d sf %lux dxs %d dys %d dd %d ddat %p sdat %p\n",
+ par->mask->flags, par->mask->depth, par->src->flags,
+ Dx(par->src->r), Dy(par->src->r), par->dst->depth, par->dst->data, par->src->data);
+
+ mask = par->mask;
+ src = par->src;
+ dst = par->dst;
+ r = par->r;
+ mr = par->mr;
+ op = par->op;
+
+ if((par->state&(Replsrc|Simplesrc|Replmask)) != (Replsrc|Simplesrc)
+ || mask->depth != 1 || src->flags&Falpha || dst->depth<8 || dst->data==src->data
+ || op != SoverD)
+ return 0;
+
+//if(drawdebug) iprint("chardraw...");
+
+ depth = mask->depth;
+ maskwid = mask->width*sizeof(ulong);
+ rp = byteaddr(mask, mr.min);
+ npack = 8/depth;
+ bsh = (mr.min.x % npack) * depth;
+
+ wp = byteaddr(dst, r.min);
+ dstwid = dst->width*sizeof(ulong);
+DBG print("bsh %d\n", bsh);
+ dy = Dy(r);
+ dx = Dx(r);
+
+ ddepth = dst->depth;
+
+ /*
+ * for loop counts from bsh to bsh+dx
+ *
+ * we want the bottom bits to be the amount
+ * to shift the pixels down, so for n≡0 (mod 8) we want
+ * bottom bits 7. for n≡1, 6, etc.
+ * the bits come from -n-1.
+ */
+
+ bx = -bsh-1;
+ ex = -bsh-1-dx;
+ bits = 0;
+ v = par->sdval;
+
+ /* make little endian */
+ sp[0] = v;
+ sp[1] = v>>8;
+ sp[2] = v>>16;
+ sp[3] = v>>24;
+
+//print("sp %x %x %x %x\n", sp[0], sp[1], sp[2], sp[3]);
+ for(y=0; y<dy; y++, rp+=maskwid, wp+=dstwid){
+ q = rp;
+ if(bsh)
+ bits = *q++;
+ switch(ddepth){
+ case 8:
+//if(drawdebug) iprint("8loop...");
+ wc = wp;
+ for(x=bx; x>ex; x--, wc++){
+ i = x&7;
+ if(i == 8-1)
+ bits = *q++;
+DBG print("bits %lux sh %d...", bits, i);
+ if((bits>>i)&1)
+ *wc = v;
+ }
+ break;
+ case 16:
+ ws = (ushort*)wp;
+ v = *(ushort*)sp;
+ for(x=bx; x>ex; x--, ws++){
+ i = x&7;
+ if(i == 8-1)
+ bits = *q++;
+DBG print("bits %lux sh %d...", bits, i);
+ if((bits>>i)&1)
+ *ws = v;
+ }
+ break;
+ case 24:
+ wc = wp;
+ for(x=bx; x>ex; x--, wc+=3){
+ i = x&7;
+ if(i == 8-1)
+ bits = *q++;
+DBG print("bits %lux sh %d...", bits, i);
+ if((bits>>i)&1){
+ wc[0] = sp[0];
+ wc[1] = sp[1];
+ wc[2] = sp[2];
+ }
+ }
+ break;
+ case 32:
+ wl = (ulong*)wp;
+ v = *(ulong*)sp;
+ for(x=bx; x>ex; x--, wl++){
+ i = x&7;
+ if(i == 8-1)
+ bits = *q++;
+DBG iprint("bits %lux sh %d...", bits, i);
+ if((bits>>i)&1)
+ *wl = v;
+ }
+ break;
+ }
+ }
+
+DBG print("\n");
+ return 1;
+}
+#undef DBG
+
+
+/*
+ * Fill entire byte with replicated (if necessary) copy of source pixel,
+ * assuming destination ldepth is >= source ldepth.
+ *
+ * This code is just plain wrong for >8bpp.
+ *
+ulong
+membyteval(Memimage *src)
+{
+ int i, val, bpp;
+ uchar uc;
+
+ unloadmemimage(src, src->r, &uc, 1);
+ bpp = src->depth;
+ uc <<= (src->r.min.x&(7/src->depth))*src->depth;
+ uc &= ~(0xFF>>bpp);
+ // pixel value is now in high part of byte. repeat throughout byte
+ val = uc;
+ for(i=bpp; i<8; i<<=1)
+ val |= val>>i;
+ return val;
+}
+ *
+ */
+
+void
+memfillcolor(Memimage *i, ulong val)
+{
+ ulong bits;
+ int d, y;
+ uchar p[4];
+
+ if(val == DNofill)
+ return;
+
+ bits = rgbatoimg(i, val);
+ switch(i->depth){
+ case 24: /* 24-bit images suck */
+ for(y=i->r.min.y; y<i->r.max.y; y++)
+ memset24(byteaddr(i, Pt(i->r.min.x, y)), bits, Dx(i->r));
+ break;
+ default: /* 1, 2, 4, 8, 16, 32 */
+ for(d=i->depth; d<32; d*=2)
+ bits = (bits << d) | bits;
+ p[0] = bits; /* make little endian */
+ p[1] = bits>>8;
+ p[2] = bits>>16;
+ p[3] = bits>>24;
+ bits = *(u32int*)p;
+ memsetl(wordaddr(i, i->r.min), bits, i->width*Dy(i->r));
+ break;
+ }
+}
+
--- /dev/null
+++ b/libmemdraw/drawtest.c
@@ -1,0 +1,1003 @@
+#include "lib9.h"
+#include "bio.h"
+#include "draw.h"
+#include "memdraw.h"
+
+#define DBG if(0)
+#define RGB2K(r,g,b) ((299*((ulong)(r))+587*((ulong)(g))+114*((ulong)(b)))/1000)
+
+/*
+ * This program tests the 'memimagedraw' primitive stochastically.
+ * It tests the combination aspects of it thoroughly, but since the
+ * three images it uses are disjoint, it makes no check of the
+ * correct behavior when images overlap. That is, however, much
+ * easier to get right and to test.
+ */
+
+void drawonepixel(Memimage*, Point, Memimage*, Point, Memimage*, Point);
+void verifyone(void);
+void verifyline(void);
+void verifyrect(void);
+void verifyrectrepl(int, int);
+void putpixel(Memimage *img, Point pt, ulong nv);
+ulong rgbatopix(uchar, uchar, uchar, uchar);
+
+char *dchan, *schan, *mchan;
+int dbpp, sbpp, mbpp;
+
+int drawdebug=0;
+int seed;
+int niters = 100;
+int dbpp; /* bits per pixel in destination */
+int sbpp; /* bits per pixel in src */
+int mbpp; /* bits per pixel in mask */
+int dpm; /* pixel mask at high part of byte, in destination */
+int nbytes; /* in destination */
+
+int Xrange = 64;
+int Yrange = 8;
+
+Memimage *dst;
+Memimage *src;
+Memimage *mask;
+Memimage *stmp;
+Memimage *mtmp;
+Memimage *ones;
+uchar *dstbits;
+uchar *srcbits;
+uchar *maskbits;
+ulong *savedstbits;
+
+void
+rdb(void)
+{
+}
+
+int
+iprint(char *fmt, ...)
+{
+ int n;
+ va_list va;
+ char buf[1024];
+
+ va_start(va, fmt);
+ n = doprint(buf, buf+sizeof buf, fmt, va) - buf;
+ va_end(va);
+
+ write(1,buf,n);
+ return 1;
+}
+
+void
+main(int argc, char *argv[])
+{
+ memimageinit();
+ seed = time(0);
+
+ ARGBEGIN{
+ case 'x':
+ Xrange = atoi(ARGF());
+ break;
+ case 'y':
+ Yrange = atoi(ARGF());
+ break;
+ case 'n':
+ niters = atoi(ARGF());
+ break;
+ case 's':
+ seed = atoi(ARGF());
+ break;
+ }ARGEND
+
+ dchan = "r8g8b8";
+ schan = "r8g8b8";
+ mchan = "r8g8b8";
+ switch(argc){
+ case 3: mchan = argv[2];
+ case 2: schan = argv[1];
+ case 1: dchan = argv[0];
+ case 0: break;
+ default: goto Usage;
+ Usage:
+ fprint(2, "usage: dtest [dchan [schan [mchan]]]\n");
+ exits("usage");
+ }
+
+ fmtinstall('b', numbconv); /* binary! */
+
+ fprint(2, "%s -x %d -y %d -s 0x%x %s %s %s\n", argv0, Xrange, Yrange, seed, dchan, schan, mchan);
+ srand(seed);
+
+ dst = allocmemimage(Rect(0, 0, Xrange, Yrange), strtochan(dchan));
+ src = allocmemimage(Rect(0, 0, Xrange, Yrange), strtochan(schan));
+ mask = allocmemimage(Rect(0, 0, Xrange, Yrange), strtochan(mchan));
+ stmp = allocmemimage(Rect(0, 0, Xrange, Yrange), strtochan(schan));
+ mtmp = allocmemimage(Rect(0, 0, Xrange, Yrange), strtochan(mchan));
+ ones = allocmemimage(Rect(0, 0, Xrange, Yrange), strtochan(mchan));
+// print("chan %lux %lux %lux %lux %lux %lux\n", dst->chan, src->chan, mask->chan, stmp->chan, mtmp->chan, ones->chan);
+ if(dst==0 || src==0 || mask==0 || mtmp==0 || ones==0) {
+ Alloc:
+ fprint(2, "dtest: allocation failed: %r\n");
+ exits("alloc");
+ }
+ nbytes = (4*Xrange+4)*Yrange;
+ srcbits = malloc(nbytes);
+ dstbits = malloc(nbytes);
+ maskbits = malloc(nbytes);
+ savedstbits = malloc(nbytes);
+ if(dstbits==0 || srcbits==0 || maskbits==0 || savedstbits==0)
+ goto Alloc;
+ dbpp = dst->depth;
+ sbpp = src->depth;
+ mbpp = mask->depth;
+ dpm = 0xFF ^ (0xFF>>dbpp);
+ memset(ones->data->bdata, 0xFF, ones->width*sizeof(ulong)*Yrange);
+
+
+ fprint(2, "dtest: verify single pixel operation\n");
+ verifyone();
+
+ fprint(2, "dtest: verify full line non-replicated\n");
+ verifyline();
+
+ fprint(2, "dtest: verify full rectangle non-replicated\n");
+ verifyrect();
+
+ fprint(2, "dtest: verify full rectangle source replicated\n");
+ verifyrectrepl(1, 0);
+
+ fprint(2, "dtest: verify full rectangle mask replicated\n");
+ verifyrectrepl(0, 1);
+
+ fprint(2, "dtest: verify full rectangle source and mask replicated\n");
+ verifyrectrepl(1, 1);
+
+ exits(0);
+}
+
+/*
+ * Dump out an ASCII representation of an image. The label specifies
+ * a list of characters to put at various points in the picture.
+ */
+static void
+Bprintr5g6b5(Biobuf *bio, char*, ulong v)
+{
+ int r,g,b;
+ r = (v>>11)&31;
+ g = (v>>5)&63;
+ b = v&31;
+ Bprint(bio, "%.2x%.2x%.2x", r,g,b);
+}
+
+static void
+Bprintr5g5b5a1(Biobuf *bio, char*, ulong v)
+{
+ int r,g,b,a;
+ r = (v>>11)&31;
+ g = (v>>6)&31;
+ b = (v>>1)&31;
+ a = v&1;
+ Bprint(bio, "%.2x%.2x%.2x%.2x", r,g,b,a);
+}
+
+void
+dumpimage(char *name, Memimage *img, void *vdata, Point labelpt)
+{
+ Biobuf b;
+ uchar *data;
+ uchar *p;
+ char *arg;
+ void (*fmt)(Biobuf*, char*, ulong);
+ int npr, x, y, nb, bpp;
+ ulong v, mask;
+ Rectangle r;
+
+ fmt = nil;
+ arg = nil;
+ switch(img->depth){
+ case 1:
+ case 2:
+ case 4:
+ fmt = (void(*)(Biobuf*,char*,ulong))Bprint;
+ arg = "%.1ux";
+ break;
+ case 8:
+ fmt = (void(*)(Biobuf*,char*,ulong))Bprint;
+ arg = "%.2ux";
+ break;
+ case 16:
+ arg = nil;
+ if(img->chan == RGB16)
+ fmt = Bprintr5g6b5;
+ else{
+ fmt = (void(*)(Biobuf*,char*,ulong))Bprint;
+ arg = "%.4ux";
+ }
+ break;
+ case 24:
+ fmt = (void(*)(Biobuf*,char*,ulong))Bprint;
+ arg = "%.6lux";
+ break;
+ case 32:
+ fmt = (void(*)(Biobuf*,char*,ulong))Bprint;
+ arg = "%.8lux";
+ break;
+ }
+ if(fmt == nil){
+ fprint(2, "bad format\n");
+ abort();
+ }
+
+ r = img->r;
+ Binit(&b, 2, OWRITE);
+ data = vdata;
+ bpp = img->depth;
+ Bprint(&b, "%s\t%d\tr %R clipr %R repl %d data %p *%P\n", name, r.min.x, r, img->clipr, (img->flags&Frepl) ? 1 : 0, vdata, labelpt);
+ mask = (1ULL<<bpp)-1;
+// for(y=r.min.y; y<r.max.y; y++){
+ for(y=0; y<Yrange; y++){
+ nb = 0;
+ v = 0;
+ p = data+(byteaddr(img, Pt(0,y))-(uchar*)img->data->bdata);
+ Bprint(&b, "%-4d\t", y);
+// for(x=r.min.x; x<r.max.x; x++){
+ for(x=0; x<Xrange; x++){
+ if(x==0)
+ Bprint(&b, "\t");
+
+ if(x != 0 && (x%8)==0)
+ Bprint(&b, " ");
+
+ npr = 0;
+ if(x==labelpt.x && y==labelpt.y){
+ Bprint(&b, "*");
+ npr++;
+ }
+ if(npr == 0)
+ Bprint(&b, " ");
+
+ while(nb < bpp){
+ v &= (1<<nb)-1;
+ v |= (ulong)(*p++) << nb;
+ nb += 8;
+ }
+ nb -= bpp;
+// print("bpp %d v %.8lux mask %.8lux nb %d\n", bpp, v, mask, nb);
+ fmt(&b, arg, (v>>nb)&mask);
+ }
+ Bprint(&b, "\n");
+ }
+ Bterm(&b);
+}
+
+/*
+ * Verify that the destination pixel has the specified value.
+ * The value is in the high bits of v, suitably masked, but must
+ * be extracted from the destination Memimage.
+ */
+void
+checkone(Point p, Point sp, Point mp)
+{
+ int delta;
+ uchar *dp, *sdp;
+
+ delta = (uchar*)byteaddr(dst, p)-(uchar*)dst->data->bdata;
+ dp = (uchar*)dst->data->bdata+delta;
+ sdp = (uchar*)savedstbits+delta;
+
+ if(memcmp(dp, sdp, (dst->depth+7)/8) != 0) {
+ fprint(2, "dtest: one bad pixel drawing at dst %P from source %P mask %P\n", p, sp, mp);
+ fprint(2, " %.2ux %.2ux %.2ux %.2ux should be %.2ux %.2ux %.2ux %.2ux\n",
+ dp[0], dp[1], dp[2], dp[3], sdp[0], sdp[1], sdp[2], sdp[3]);
+ fprint(2, "addresses dst %p src %p mask %p\n", dp, byteaddr(src, sp), byteaddr(mask, mp));
+ dumpimage("src", src, src->data->bdata, sp);
+ dumpimage("mask", mask, mask->data->bdata, mp);
+ dumpimage("origdst", dst, dstbits, p);
+ dumpimage("dst", dst, dst->data->bdata, p);
+ dumpimage("gooddst", dst, savedstbits, p);
+ abort();
+ }
+}
+
+/*
+ * Verify that the destination line has the same value as the saved line.
+ */
+#define RECTPTS(r) (r).min.x, (r).min.y, (r).max.x, (r).max.y
+void
+checkline(Rectangle r, Point sp, Point mp, int y, Memimage *stmp, Memimage *mtmp)
+{
+ ulong *dp;
+ int nb;
+ ulong *saved;
+
+ dp = wordaddr(dst, Pt(0, y));
+ saved = savedstbits + y*dst->width;
+ if(dst->depth < 8)
+ nb = Xrange/(8/dst->depth);
+ else
+ nb = Xrange*(dst->depth/8);
+ if(memcmp(dp, saved, nb) != 0){
+ fprint(2, "dtest: bad line at y=%d; saved %p dp %p\n", y, saved, dp);
+ fprint(2, "draw dst %R src %P mask %P\n", r, sp, mp);
+ dumpimage("src", src, src->data->bdata, sp);
+ if(stmp) dumpimage("stmp", stmp, stmp->data->bdata, sp);
+ dumpimage("mask", mask, mask->data->bdata, mp);
+ if(mtmp) dumpimage("mtmp", mtmp, mtmp->data->bdata, mp);
+ dumpimage("origdst", dst, dstbits, r.min);
+ dumpimage("dst", dst, dst->data->bdata, r.min);
+ dumpimage("gooddst", dst, savedstbits, r.min);
+ abort();
+ }
+}
+
+/*
+ * Fill the bits of an image with random data.
+ * The Memimage parameter is used only to make sure
+ * the data is well formatted: only ucbits is written.
+ */
+void
+fill(Memimage *img, uchar *ucbits)
+{
+ int i, x, y;
+ ushort *up;
+ uchar alpha, r, g, b;
+ void *data;
+
+ if((img->flags&Falpha) == 0){
+ up = (ushort*)ucbits;
+ for(i=0; i<nbytes/2; i++)
+ *up++ = lrand() >> 7;
+ if(i+i != nbytes)
+ *(uchar*)up = lrand() >> 7;
+ }else{
+ data = img->data->bdata;
+ img->data->bdata = ucbits;
+
+ for(x=img->r.min.x; x<img->r.max.x; x++)
+ for(y=img->r.min.y; y<img->r.max.y; y++){
+ alpha = rand() >> 4;
+ r = rand()%(alpha+1);
+ g = rand()%(alpha+1);
+ b = rand()%(alpha+1);
+ putpixel(img, Pt(x,y), rgbatopix(r,g,b,alpha));
+ }
+ img->data->bdata = data;
+ }
+
+}
+
+/*
+ * Mask is preset; do the rest
+ */
+void
+verifyonemask(void)
+{
+ Point dp, sp, mp;
+
+ fill(dst, dstbits);
+ fill(src, srcbits);
+ memmove(dst->data->bdata, dstbits, dst->width*sizeof(ulong)*Yrange);
+ memmove(src->data->bdata, srcbits, src->width*sizeof(ulong)*Yrange);
+ memmove(mask->data->bdata, maskbits, mask->width*sizeof(ulong)*Yrange);
+
+ dp.x = nrand(Xrange);
+ dp.y = nrand(Yrange);
+
+ sp.x = nrand(Xrange);
+ sp.y = nrand(Yrange);
+
+ mp.x = nrand(Xrange);
+ mp.y = nrand(Yrange);
+
+ drawonepixel(dst, dp, src, sp, mask, mp);
+ memmove(mask->data->bdata, maskbits, mask->width*sizeof(ulong)*Yrange);
+ memmove(savedstbits, dst->data->bdata, dst->width*sizeof(ulong)*Yrange);
+
+ memmove(dst->data->bdata, dstbits, dst->width*sizeof(ulong)*Yrange);
+ memimagedraw(dst, Rect(dp.x, dp.y, dp.x+1, dp.y+1), src, sp, mask, mp, SoverD);
+ memmove(mask->data->bdata, maskbits, mask->width*sizeof(ulong)*Yrange);
+
+ checkone(dp, sp, mp);
+}
+
+void
+verifyone(void)
+{
+ int i;
+
+ /* mask all zeros */
+ memset(maskbits, 0, nbytes);
+ for(i=0; i<niters; i++)
+ verifyonemask();
+
+ /* mask all ones */
+ memset(maskbits, 0xFF, nbytes);
+ for(i=0; i<niters; i++)
+ verifyonemask();
+
+ /* random mask */
+ for(i=0; i<niters; i++){
+ fill(mask, maskbits);
+ verifyonemask();
+ }
+}
+
+/*
+ * Mask is preset; do the rest
+ */
+void
+verifylinemask(void)
+{
+ Point sp, mp, tp, up;
+ Rectangle dr;
+ int x;
+
+ fill(dst, dstbits);
+ fill(src, srcbits);
+ memmove(dst->data->bdata, dstbits, dst->width*sizeof(ulong)*Yrange);
+ memmove(src->data->bdata, srcbits, src->width*sizeof(ulong)*Yrange);
+ memmove(mask->data->bdata, maskbits, mask->width*sizeof(ulong)*Yrange);
+
+ dr.min.x = nrand(Xrange-1);
+ dr.min.y = nrand(Yrange-1);
+ dr.max.x = dr.min.x + 1 + nrand(Xrange-1-dr.min.x);
+ dr.max.y = dr.min.y + 1;
+
+ sp.x = nrand(Xrange);
+ sp.y = nrand(Yrange);
+
+ mp.x = nrand(Xrange);
+ mp.y = nrand(Yrange);
+
+ tp = sp;
+ up = mp;
+ for(x=dr.min.x; x<dr.max.x && tp.x<Xrange && up.x<Xrange; x++,tp.x++,up.x++)
+ memimagedraw(dst, Rect(x, dr.min.y, x+1, dr.min.y+1), src, tp, mask, up, SoverD);
+ memmove(savedstbits, dst->data->bdata, dst->width*sizeof(ulong)*Yrange);
+
+ memmove(dst->data->bdata, dstbits, dst->width*sizeof(ulong)*Yrange);
+
+ memimagedraw(dst, dr, src, sp, mask, mp, SoverD);
+ checkline(dr, drawrepl(src->r, sp), drawrepl(mask->r, mp), dr.min.y, nil, nil);
+}
+
+void
+verifyline(void)
+{
+ int i;
+
+ /* mask all ones */
+ memset(maskbits, 0xFF, nbytes);
+ for(i=0; i<niters; i++)
+ verifylinemask();
+
+ /* mask all zeros */
+ memset(maskbits, 0, nbytes);
+ for(i=0; i<niters; i++)
+ verifylinemask();
+
+ /* random mask */
+ for(i=0; i<niters; i++){
+ fill(mask, maskbits);
+ verifylinemask();
+ }
+}
+
+/*
+ * Mask is preset; do the rest
+ */
+void
+verifyrectmask(void)
+{
+ Point sp, mp, tp, up;
+ Rectangle dr;
+ int x, y;
+
+ fill(dst, dstbits);
+ fill(src, srcbits);
+ memmove(dst->data->bdata, dstbits, dst->width*sizeof(ulong)*Yrange);
+ memmove(src->data->bdata, srcbits, src->width*sizeof(ulong)*Yrange);
+ memmove(mask->data->bdata, maskbits, mask->width*sizeof(ulong)*Yrange);
+
+ dr.min.x = nrand(Xrange-1);
+ dr.min.y = nrand(Yrange-1);
+ dr.max.x = dr.min.x + 1 + nrand(Xrange-1-dr.min.x);
+ dr.max.y = dr.min.y + 1 + nrand(Yrange-1-dr.min.y);
+
+ sp.x = nrand(Xrange);
+ sp.y = nrand(Yrange);
+
+ mp.x = nrand(Xrange);
+ mp.y = nrand(Yrange);
+
+ tp = sp;
+ up = mp;
+ for(y=dr.min.y; y<dr.max.y && tp.y<Yrange && up.y<Yrange; y++,tp.y++,up.y++){
+ for(x=dr.min.x; x<dr.max.x && tp.x<Xrange && up.x<Xrange; x++,tp.x++,up.x++)
+ memimagedraw(dst, Rect(x, y, x+1, y+1), src, tp, mask, up, SoverD);
+ tp.x = sp.x;
+ up.x = mp.x;
+ }
+ memmove(savedstbits, dst->data->bdata, dst->width*sizeof(ulong)*Yrange);
+
+ memmove(dst->data->bdata, dstbits, dst->width*sizeof(ulong)*Yrange);
+
+ memimagedraw(dst, dr, src, sp, mask, mp, SoverD);
+ for(y=0; y<Yrange; y++)
+ checkline(dr, drawrepl(src->r, sp), drawrepl(mask->r, mp), y, nil, nil);
+}
+
+void
+verifyrect(void)
+{
+ int i;
+
+ /* mask all zeros */
+ memset(maskbits, 0, nbytes);
+ for(i=0; i<niters; i++)
+ verifyrectmask();
+
+ /* mask all ones */
+ memset(maskbits, 0xFF, nbytes);
+ for(i=0; i<niters; i++)
+ verifyrectmask();
+
+ /* random mask */
+ for(i=0; i<niters; i++){
+ fill(mask, maskbits);
+ verifyrectmask();
+ }
+}
+
+Rectangle
+randrect(void)
+{
+ Rectangle r;
+
+ r.min.x = nrand(Xrange-1);
+ r.min.y = nrand(Yrange-1);
+ r.max.x = r.min.x + 1 + nrand(Xrange-1-r.min.x);
+ r.max.y = r.min.y + 1 + nrand(Yrange-1-r.min.y);
+ return r;
+}
+
+/*
+ * Return coordinate corresponding to x withing range [minx, maxx)
+ */
+int
+tilexy(int minx, int maxx, int x)
+{
+ int sx;
+
+ sx = (x-minx) % (maxx-minx);
+ if(sx < 0)
+ sx += maxx-minx;
+ return sx+minx;
+}
+
+void
+replicate(Memimage *i, Memimage *tmp)
+{
+ Rectangle r, r1;
+ int x, y, nb;
+
+ /* choose the replication window (i->r) */
+ r.min.x = nrand(Xrange-1);
+ r.min.y = nrand(Yrange-1);
+ /* make it trivial more often than pure chance allows */
+ switch(lrand()&0){
+ case 1:
+ r.max.x = r.min.x + 2;
+ r.max.y = r.min.y + 2;
+ if(r.max.x < Xrange && r.max.y < Yrange)
+ break;
+ /* fall through */
+ case 0:
+ r.max.x = r.min.x + 1;
+ r.max.y = r.min.y + 1;
+ break;
+ default:
+ if(r.min.x+3 >= Xrange)
+ r.max.x = Xrange;
+ else
+ r.max.x = r.min.x+3 + nrand(Xrange-(r.min.x+3));
+
+ if(r.min.y+3 >= Yrange)
+ r.max.y = Yrange;
+ else
+ r.max.y = r.min.y+3 + nrand(Yrange-(r.min.y+3));
+ }
+ assert(r.min.x >= 0);
+ assert(r.max.x <= Xrange);
+ assert(r.min.y >= 0);
+ assert(r.max.y <= Yrange);
+ /* copy from i to tmp so we have just the replicated bits */
+ nb = tmp->width*sizeof(ulong)*Yrange;
+ memset(tmp->data->bdata, 0, nb);
+ memimagedraw(tmp, r, i, r.min, ones, r.min, SoverD);
+ memmove(i->data->bdata, tmp->data->bdata, nb);
+ /* i is now a non-replicated instance of the replication */
+ /* replicate it by hand through tmp */
+ memset(tmp->data->bdata, 0, nb);
+ x = -(tilexy(r.min.x, r.max.x, 0)-r.min.x);
+ for(; x<Xrange; x+=Dx(r)){
+ y = -(tilexy(r.min.y, r.max.y, 0)-r.min.y);
+ for(; y<Yrange; y+=Dy(r)){
+ /* set r1 to instance of tile by translation */
+ r1.min.x = x;
+ r1.min.y = y;
+ r1.max.x = r1.min.x+Dx(r);
+ r1.max.y = r1.min.y+Dy(r);
+ memimagedraw(tmp, r1, i, r.min, ones, r.min, SoverD);
+ }
+ }
+ i->flags |= Frepl;
+ i->r = r;
+ i->clipr = randrect();
+// fprint(2, "replicate [[%d %d] [%d %d]] [[%d %d][%d %d]]\n", r.min.x, r.min.y, r.max.x, r.max.y,
+// i->clipr.min.x, i->clipr.min.y, i->clipr.max.x, i->clipr.max.y);
+ tmp->clipr = i->clipr;
+}
+
+/*
+ * Mask is preset; do the rest
+ */
+void
+verifyrectmaskrepl(int srcrepl, int maskrepl)
+{
+ Point sp, mp, tp, up;
+ Rectangle dr;
+ int x, y;
+ Memimage *s, *m;
+
+// print("verfrect %d %d\n", srcrepl, maskrepl);
+ src->flags &= ~Frepl;
+ src->r = Rect(0, 0, Xrange, Yrange);
+ src->clipr = src->r;
+ stmp->flags &= ~Frepl;
+ stmp->r = Rect(0, 0, Xrange, Yrange);
+ stmp->clipr = src->r;
+ mask->flags &= ~Frepl;
+ mask->r = Rect(0, 0, Xrange, Yrange);
+ mask->clipr = mask->r;
+ mtmp->flags &= ~Frepl;
+ mtmp->r = Rect(0, 0, Xrange, Yrange);
+ mtmp->clipr = mask->r;
+
+ fill(dst, dstbits);
+ fill(src, srcbits);
+
+ memmove(dst->data->bdata, dstbits, dst->width*sizeof(ulong)*Yrange);
+ memmove(src->data->bdata, srcbits, src->width*sizeof(ulong)*Yrange);
+ memmove(mask->data->bdata, maskbits, mask->width*sizeof(ulong)*Yrange);
+
+ if(srcrepl){
+ replicate(src, stmp);
+ s = stmp;
+ }else
+ s = src;
+ if(maskrepl){
+ replicate(mask, mtmp);
+ m = mtmp;
+ }else
+ m = mask;
+
+ dr = randrect();
+
+ sp.x = nrand(Xrange);
+ sp.y = nrand(Yrange);
+
+ mp.x = nrand(Xrange);
+ mp.y = nrand(Yrange);
+
+DBG print("smalldraws\n");
+ for(tp.y=sp.y,up.y=mp.y,y=dr.min.y; y<dr.max.y && tp.y<Yrange && up.y<Yrange; y++,tp.y++,up.y++)
+ for(tp.x=sp.x,up.x=mp.x,x=dr.min.x; x<dr.max.x && tp.x<Xrange && up.x<Xrange; x++,tp.x++,up.x++)
+ memimagedraw(dst, Rect(x, y, x+1, y+1), s, tp, m, up, SoverD);
+ memmove(savedstbits, dst->data->bdata, dst->width*sizeof(ulong)*Yrange);
+
+ memmove(dst->data->bdata, dstbits, dst->width*sizeof(ulong)*Yrange);
+
+DBG print("bigdraw\n");
+ memimagedraw(dst, dr, src, sp, mask, mp, SoverD);
+ for(y=0; y<Yrange; y++)
+ checkline(dr, drawrepl(src->r, sp), drawrepl(mask->r, mp), y, srcrepl?stmp:nil, maskrepl?mtmp:nil);
+}
+
+void
+verifyrectrepl(int srcrepl, int maskrepl)
+{
+ int i;
+
+ /* mask all ones */
+ memset(maskbits, 0xFF, nbytes);
+ for(i=0; i<niters; i++)
+ verifyrectmaskrepl(srcrepl, maskrepl);
+
+ /* mask all zeros */
+ memset(maskbits, 0, nbytes);
+ for(i=0; i<niters; i++)
+ verifyrectmaskrepl(srcrepl, maskrepl);
+
+ /* random mask */
+ for(i=0; i<niters; i++){
+ fill(mask, maskbits);
+ verifyrectmaskrepl(srcrepl, maskrepl);
+ }
+}
+
+/*
+ * Trivial draw implementation.
+ * Color values are passed around as ulongs containing ααRRGGBB
+ */
+
+/*
+ * Convert v, which is nhave bits wide, into its nwant bits wide equivalent.
+ * Replicates to widen the value, truncates to narrow it.
+ */
+ulong
+replbits(ulong v, int nhave, int nwant)
+{
+ v &= (1<<nhave)-1;
+ for(; nhave<nwant; nhave*=2)
+ v |= v<<nhave;
+ v >>= (nhave-nwant);
+ return v & ((1<<nwant)-1);
+}
+
+/*
+ * Decode a pixel into the uchar* values.
+ */
+void
+pixtorgba(ulong v, uchar *r, uchar *g, uchar *b, uchar *a)
+{
+ *a = v>>24;
+ *r = v>>16;
+ *g = v>>8;
+ *b = v;
+}
+
+/*
+ * Convert uchar channels into ulong pixel.
+ */
+ulong
+rgbatopix(uchar r, uchar g, uchar b, uchar a)
+{
+ return (a<<24)|(r<<16)|(g<<8)|b;
+}
+
+/*
+ * Retrieve the pixel value at pt in the image.
+ */
+ulong
+getpixel(Memimage *img, Point pt)
+{
+ uchar r, g, b, a, *p;
+ int nbits, npack, bpp;
+ ulong v, c, rbits, bits;
+
+ r = g = b = 0;
+ a = ~0; /* default alpha is full */
+
+ p = byteaddr(img, pt);
+ v = p[0]|(p[1]<<8)|(p[2]<<16)|(p[3]<<24);
+ bpp = img->depth;
+ if(bpp<8){
+ /*
+ * Sub-byte greyscale pixels.
+ *
+ * We want to throw away the top pt.x%npack pixels and then use the next bpp bits
+ * in the bottom byte of v. This madness is due to having big endian bits
+ * but little endian bytes.
+ */
+ npack = 8/bpp;
+ v >>= 8 - bpp*(pt.x%npack+1);
+ v &= (1<<bpp)-1;
+ r = g = b = replbits(v, bpp, 8);
+ }else{
+ /*
+ * General case. We need to parse the channel descriptor and do what it says.
+ * In all channels but the color map, we replicate to 8 bits because that's the
+ * precision that all calculations are done at.
+ *
+ * In the case of the color map, we leave the bits alone, in case a color map
+ * with less than 8 bits of index is used. This is currently disallowed, so it's
+ * sort of silly.
+ */
+
+ for(c=img->chan; c; c>>=8){
+ nbits = NBITS(c);
+ bits = v & ((1<<nbits)-1);
+ rbits = replbits(bits, nbits, 8);
+ v >>= nbits;
+ switch(TYPE(c)){
+ case CRed:
+ r = rbits;
+ break;
+ case CGreen:
+ g = rbits;
+ break;
+ case CBlue:
+ b = rbits;
+ break;
+ case CGrey:
+ r = g = b = rbits;
+ break;
+ case CAlpha:
+ a = rbits;
+ break;
+ case CMap:
+ p = img->cmap->cmap2rgb + 3*bits;
+ r = p[0];
+ g = p[1];
+ b = p[2];
+ break;
+ case CIgnore:
+ break;
+ default:
+ fprint(2, "unknown channel type %lud\n", TYPE(c));
+ abort();
+ }
+ }
+ }
+ return rgbatopix(r, g, b, a);
+}
+
+/*
+ * Return the greyscale equivalent of a pixel.
+ */
+uchar
+getgrey(Memimage *img, Point pt)
+{
+ uchar r, g, b, a;
+ pixtorgba(getpixel(img, pt), &r, &g, &b, &a);
+ return RGB2K(r, g, b);
+}
+
+/*
+ * Return the value at pt in image, if image is interpreted
+ * as a mask. This means the alpha channel if present, else
+ * the greyscale or its computed equivalent.
+ */
+uchar
+getmask(Memimage *img, Point pt)
+{
+ if(img->flags&Falpha)
+ return getpixel(img, pt)>>24;
+ else
+ return getgrey(img, pt);
+}
+#undef DBG
+
+#define DBG if(0)
+/*
+ * Write a pixel to img at point pt.
+ *
+ * We do this by reading a 32-bit little endian
+ * value from p and then writing it back
+ * after tweaking the appropriate bits. Because
+ * the data is little endian, we don't have to worry
+ * about what the actual depth is, as long as it is
+ * less than 32 bits.
+ */
+void
+putpixel(Memimage *img, Point pt, ulong nv)
+{
+ uchar r, g, b, a, *p, *q;
+ ulong c, mask, bits, v;
+ int bpp, sh, npack, nbits;
+
+ pixtorgba(nv, &r, &g, &b, &a);
+
+ p = byteaddr(img, pt);
+ v = p[0]|(p[1]<<8)|(p[2]<<16)|(p[3]<<24);
+ bpp = img->depth;
+DBG print("v %.8lux...", v);
+ if(bpp < 8){
+ /*
+ * Sub-byte greyscale pixels. We need to skip the leftmost pt.x%npack pixels,
+ * which is equivalent to skipping the rightmost npack - pt.x%npack - 1 pixels.
+ */
+ npack = 8/bpp;
+ sh = bpp*(npack - pt.x%npack - 1);
+ bits = RGB2K(r,g,b);
+DBG print("repl %lux 8 %d = %lux...", bits, bpp, replbits(bits, 8, bpp));
+ bits = replbits(bits, 8, bpp);
+ mask = (1<<bpp)-1;
+DBG print("bits %lux mask %lux sh %d...", bits, mask, sh);
+ mask <<= sh;
+ bits <<= sh;
+DBG print("(%lux & %lux) | (%lux & %lux)", v, ~mask, bits, mask);
+ v = (v & ~mask) | (bits & mask);
+ } else {
+ /*
+ * General case. We need to parse the channel descriptor again.
+ */
+ sh = 0;
+ for(c=img->chan; c; c>>=8){
+ nbits = NBITS(c);
+ switch(TYPE(c)){
+ case CRed:
+ bits = r;
+ break;
+ case CGreen:
+ bits = g;
+ break;
+ case CBlue:
+ bits = b;
+ break;
+ case CGrey:
+ bits = RGB2K(r, g, b);
+ break;
+ case CAlpha:
+ bits = a;
+ break;
+ case CIgnore:
+ bits = 0;
+ break;
+ case CMap:
+ q = img->cmap->rgb2cmap;
+ bits = q[(r>>4)*16*16+(g>>4)*16+(b>>4)];
+ break;
+ default:
+ SET(bits);
+ fprint(2, "unknown channel type %lud\n", TYPE(c));
+ abort();
+ }
+
+DBG print("repl %lux 8 %d = %lux...", bits, nbits, replbits(bits, 8, nbits));
+ if(TYPE(c) != CMap)
+ bits = replbits(bits, 8, nbits);
+ mask = (1<<nbits)-1;
+DBG print("bits %lux mask %lux sh %d...", bits, mask, sh);
+ bits <<= sh;
+ mask <<= sh;
+ v = (v & ~mask) | (bits & mask);
+ sh += nbits;
+ }
+ }
+DBG print("v %.8lux\n", v);
+ p[0] = v;
+ p[1] = v>>8;
+ p[2] = v>>16;
+ p[3] = v>>24;
+}
+#undef DBG
+
+#define DBG if(0)
+void
+drawonepixel(Memimage *dst, Point dp, Memimage *src, Point sp, Memimage *mask, Point mp)
+{
+ uchar m, M, sr, sg, sb, sa, sk, dr, dg, db, da, dk;
+
+ pixtorgba(getpixel(dst, dp), &dr, &dg, &db, &da);
+ pixtorgba(getpixel(src, sp), &sr, &sg, &sb, &sa);
+ m = getmask(mask, mp);
+ M = 255-(sa*m)/255;
+
+DBG print("dst %x %x %x %x src %x %x %x %x m %x = ", dr,dg,db,da, sr,sg,sb,sa, m);
+ if(dst->flags&Fgrey){
+ /*
+ * We need to do the conversion to grey before the alpha calculation
+ * because the draw operator does this, and we need to be operating
+ * at the same precision so we get exactly the same answers.
+ */
+ sk = RGB2K(sr, sg, sb);
+ dk = RGB2K(dr, dg, db);
+ dk = (sk*m + dk*M)/255;
+ dr = dg = db = dk;
+ da = (sa*m + da*M)/255;
+ }else{
+ /*
+ * True color alpha calculation treats all channels (including alpha)
+ * the same. It might have been nice to use an array, but oh well.
+ */
+ dr = (sr*m + dr*M)/255;
+ dg = (sg*m + dg*M)/255;
+ db = (sb*m + db*M)/255;
+ da = (sa*m + da*M)/255;
+ }
+
+DBG print("%x %x %x %x\n", dr,dg,db,da);
+ putpixel(dst, dp, rgbatopix(dr, dg, db, da));
+}
--- /dev/null
+++ b/libmemdraw/ellipse.c
@@ -1,0 +1,247 @@
+#include "lib9.h"
+#include "draw.h"
+#include "memdraw.h"
+#include "memlayer.h"
+
+/*
+ * ellipse(dst, c, a, b, t, src, sp)
+ * draws an ellipse centered at c with semiaxes a,b>=0
+ * and semithickness t>=0, or filled if t<0. point sp
+ * in src maps to c in dst
+ *
+ * very thick skinny ellipses are brushed with circles (slow)
+ * others are approximated by filling between 2 ellipses
+ * criterion for very thick when b<a: t/b > 0.5*x/(1-x)
+ * where x = b/a
+ */
+
+typedef struct Param Param;
+typedef struct State State;
+
+static void bellipse(int, State*, Param*);
+static void erect(int, int, int, int, Param*);
+static void eline(int, int, int, int, Param*);
+
+struct Param {
+ Memimage *dst;
+ Memimage *src;
+ Point c;
+ int t;
+ Point sp;
+ Memimage *disc;
+ int op;
+};
+
+/*
+ * denote residual error by e(x,y) = b^2*x^2 + a^2*y^2 - a^2*b^2
+ * e(x,y) = 0 on ellipse, e(x,y) < 0 inside, e(x,y) > 0 outside
+ */
+
+struct State {
+ int a;
+ int x;
+ vlong a2; /* a^2 */
+ vlong b2; /* b^2 */
+ vlong b2x; /* b^2 * x */
+ vlong a2y; /* a^2 * y */
+ vlong c1;
+ vlong c2; /* test criteria */
+ vlong ee; /* ee = e(x+1/2,y-1/2) - (a^2+b^2)/4 */
+ vlong dxe;
+ vlong dye;
+ vlong d2xe;
+ vlong d2ye;
+};
+
+static
+State*
+newstate(State *s, int a, int b)
+{
+ s->x = 0;
+ s->a = a;
+ s->a2 = (vlong)(a*a);
+ s->b2 = (vlong)(b*b);
+ s->b2x = (vlong)0;
+ s->a2y = s->a2*(vlong)b;
+ s->c1 = -((s->a2>>2) + (vlong)(a&1) + s->b2);
+ s->c2 = -((s->b2>>2) + (vlong)(b&1));
+ s->ee = -s->a2y;
+ s->dxe = (vlong)0;
+ s->dye = s->ee<<1;
+ s->d2xe = s->b2<<1;
+ s->d2ye = s->a2<<1;
+ return s;
+}
+
+/*
+ * return x coord of rightmost pixel on next scan line
+ */
+static
+int
+step(State *s)
+{
+ while(s->x < s->a) {
+ if(s->ee+s->b2x <= s->c1 || /* e(x+1,y-1/2) <= 0 */
+ s->ee+s->a2y <= s->c2) { /* e(x+1/2,y) <= 0 (rare) */
+ s->dxe += s->d2xe;
+ s->ee += s->dxe;
+ s->b2x += s->b2;
+ s->x++;
+ continue;
+ }
+ s->dye += s->d2ye;
+ s->ee += s->dye;
+ s->a2y -= s->a2;
+ if(s->ee-s->a2y <= s->c2) { /* e(x+1/2,y-1) <= 0 */
+ s->dxe += s->d2xe;
+ s->ee += s->dxe;
+ s->b2x += s->b2;
+ return s->x++;
+ }
+ break;
+ }
+ return s->x;
+}
+
+void
+memellipse(Memimage *dst, Point c, int a, int b, int t, Memimage *src, Point sp, int op)
+{
+ State in, out;
+ int y, inb, inx, outx, u;
+ Param p;
+
+ if(a < 0)
+ a = -a;
+ if(b < 0)
+ b = -b;
+ p.dst = dst;
+ p.src = src;
+ p.c = c;
+ p.t = t;
+ p.sp = subpt(sp, c);
+ p.disc = nil;
+ p.op = op;
+
+ u = (t<<1)*(a-b);
+ if(b<a && u>b*b || a<b && -u>a*a) {
+/* if(b<a&&(t<<1)>b*b/a || a<b&&(t<<1)>a*a/b) # very thick */
+ bellipse(b, newstate(&in, a, b), &p);
+ return;
+ }
+
+ if(t < 0) {
+ inb = -1;
+ newstate(&out, a, y = b);
+ } else {
+ inb = b - t;
+ newstate(&out, a+t, y = b+t);
+ }
+ if(t > 0)
+ newstate(&in, a-t, inb);
+ inx = 0;
+ for( ; y>=0; y--) {
+ outx = step(&out);
+ if(y > inb) {
+ erect(-outx, y, outx, y, &p);
+ if(y != 0)
+ erect(-outx, -y, outx, -y, &p);
+ continue;
+ }
+ if(t > 0) {
+ inx = step(&in);
+ if(y == inb)
+ inx = 0;
+ } else if(inx > outx)
+ inx = outx;
+ erect(inx, y, outx, y, &p);
+ if(y != 0)
+ erect(inx, -y, outx, -y, &p);
+ erect(-outx, y, -inx, y, &p);
+ if(y != 0)
+ erect(-outx, -y, -inx, -y, &p);
+ inx = outx + 1;
+ }
+}
+
+static Point p00 = {0, 0};
+
+/*
+ * a brushed ellipse
+ */
+static
+void
+bellipse(int y, State *s, Param *p)
+{
+ int t, ox, oy, x, nx;
+
+ t = p->t;
+ p->disc = allocmemimage(Rect(-t,-t,t+1,t+1), GREY1);
+ if(p->disc == nil)
+ return;
+ memfillcolor(p->disc, DTransparent);
+ memellipse(p->disc, p00, t, t, -1, memopaque, p00, p->op);
+ oy = y;
+ ox = 0;
+ nx = x = step(s);
+ do {
+ while(nx==x && y-->0)
+ nx = step(s);
+ y++;
+ eline(-x,-oy,-ox, -y, p);
+ eline(ox,-oy, x, -y, p);
+ eline(-x, y,-ox, oy, p);
+ eline(ox, y, x, oy, p);
+ ox = x+1;
+ x = nx;
+ y--;
+ oy = y;
+ } while(oy > 0);
+}
+
+/*
+ * a rectangle with closed (not half-open) coordinates expressed
+ * relative to the center of the ellipse
+ */
+static
+void
+erect(int x0, int y0, int x1, int y1, Param *p)
+{
+ Rectangle r;
+
+/* print("R %d,%d %d,%d\n", x0, y0, x1, y1); /**/
+ r = Rect(p->c.x+x0, p->c.y+y0, p->c.x+x1+1, p->c.y+y1+1);
+ memdraw(p->dst, r, p->src, addpt(p->sp, r.min), memopaque, p00, p->op);
+}
+
+/*
+ * a brushed point similarly specified
+ */
+static
+void
+epoint(int x, int y, Param *p)
+{
+ Point p0;
+ Rectangle r;
+
+/* print("P%d %d,%d\n", p->t, x, y); /**/
+ p0 = Pt(p->c.x+x, p->c.y+y);
+ r = Rpt(addpt(p0, p->disc->r.min), addpt(p0, p->disc->r.max));
+ memdraw(p->dst, r, p->src, addpt(p->sp, r.min), p->disc, p->disc->r.min, p->op);
+}
+
+/*
+ * a brushed horizontal or vertical line similarly specified
+ */
+static
+void
+eline(int x0, int y0, int x1, int y1, Param *p)
+{
+/* print("L%d %d,%d %d,%d\n", p->t, x0, y0, x1, y1); /**/
+ if(x1 > x0+1)
+ erect(x0+1, y0-p->t, x1-1, y1+p->t, p);
+ else if(y1 > y0+1)
+ erect(x0-p->t, y0+1, x1+p->t, y1-1, p);
+ epoint(x0, y0, p);
+ if(x1-x0 || y1-y0)
+ epoint(x1, y1, p);
+}
--- /dev/null
+++ b/libmemdraw/fillpoly.c
@@ -1,0 +1,522 @@
+#include "lib9.h"
+#include "draw.h"
+#include "memdraw.h"
+#include "memlayer.h"
+
+typedef struct Seg Seg;
+
+struct Seg
+{
+ Point p0;
+ Point p1;
+ long num;
+ long den;
+ long dz;
+ long dzrem;
+ long z;
+ long zerr;
+ long d;
+};
+
+static void zsort(Seg **seg, Seg **ep);
+static int ycompare(void*, void*);
+static int xcompare(void*, void*);
+static int zcompare(void*, void*);
+static void xscan(Memimage *dst, Seg **seg, Seg *segtab, int nseg, int wind, Memimage *src, Point sp, int, int, int, int);
+static void yscan(Memimage *dst, Seg **seg, Seg *segtab, int nseg, int wind, Memimage *src, Point sp, int, int);
+
+static void
+fillcolor(Memimage *dst, int left, int right, int y, Memimage *src, Point p)
+{
+ int srcval;
+
+ USED(src);
+ srcval = p.x;
+ p.x = left;
+ p.y = y;
+ memset(byteaddr(dst, p), srcval, right-left);
+}
+
+static void
+fillline(Memimage *dst, int left, int right, int y, Memimage *src, Point p, int op)
+{
+ Rectangle r;
+
+ r.min.x = left;
+ r.min.y = y;
+ r.max.x = right;
+ r.max.y = y+1;
+ p.x += left;
+ p.y += y;
+ memdraw(dst, r, src, p, memopaque, p, op);
+}
+
+static void
+fillpoint(Memimage *dst, int x, int y, Memimage *src, Point p, int op)
+{
+ Rectangle r;
+
+ r.min.x = x;
+ r.min.y = y;
+ r.max.x = x+1;
+ r.max.y = y+1;
+ p.x += x;
+ p.y += y;
+ memdraw(dst, r, src, p, memopaque, p, op);
+}
+
+void
+memfillpoly(Memimage *dst, Point *vert, int nvert, int w, Memimage *src, Point sp, int op)
+{
+ _memfillpolysc(dst, vert, nvert, w, src, sp, 0, 0, 0, op);
+}
+
+void
+_memfillpolysc(Memimage *dst, Point *vert, int nvert, int w, Memimage *src, Point sp, int detail, int fixshift, int clipped, int op)
+{
+ Seg **seg, *segtab;
+ Point p0;
+ int i;
+
+ if(nvert == 0)
+ return;
+
+ seg = malloc((nvert+2)*sizeof(Seg*));
+ if(seg == nil)
+ return;
+ segtab = malloc((nvert+1)*sizeof(Seg));
+ if(segtab == nil) {
+ free(seg);
+ return;
+ }
+
+ sp.x = (sp.x - vert[0].x) >> fixshift;
+ sp.y = (sp.y - vert[0].y) >> fixshift;
+ p0 = vert[nvert-1];
+ if(!fixshift) {
+ p0.x <<= 1;
+ p0.y <<= 1;
+ }
+ for(i = 0; i < nvert; i++) {
+ segtab[i].p0 = p0;
+ p0 = vert[i];
+ if(!fixshift) {
+ p0.x <<= 1;
+ p0.y <<= 1;
+ }
+ segtab[i].p1 = p0;
+ segtab[i].d = 1;
+ }
+ if(!fixshift)
+ fixshift = 1;
+
+ xscan(dst, seg, segtab, nvert, w, src, sp, detail, fixshift, clipped, op);
+ if(detail)
+ yscan(dst, seg, segtab, nvert, w, src, sp, fixshift, op);
+
+ free(seg);
+ free(segtab);
+}
+
+static long
+mod(long x, long y)
+{
+ long z;
+
+ z = x%y;
+ if((long)(((ulong)z)^((ulong)y)) > 0 || z == 0)
+ return z;
+ return z + y;
+}
+
+static long
+sdiv(long x, long y)
+{
+ if((long)(((ulong)x)^((ulong)y)) >= 0 || x == 0)
+ return x/y;
+
+ return (x+((y>>30)|1))/y-1;
+}
+
+static long
+smuldivmod(long x, long y, long z, long *mod)
+{
+ vlong vx;
+
+ if(x == 0 || y == 0){
+ *mod = 0;
+ return 0;
+ }
+ vx = x;
+ vx *= y;
+ *mod = vx % z;
+ if(*mod < 0)
+ *mod += z; /* z is always >0 */
+ if((vx < 0) == (z < 0))
+ return vx/z;
+ return -((-vx)/z);
+}
+
+static void
+xscan(Memimage *dst, Seg **seg, Seg *segtab, int nseg, int wind, Memimage *src, Point sp, int detail, int fixshift, int clipped, int op)
+{
+ long y, maxy, x, x2, xerr, xden, onehalf;
+ Seg **ep, **next, **p, **q, *s;
+ long n, i, iy, cnt, ix, ix2, minx, maxx;
+ Point pt;
+ void (*fill)(Memimage*, int, int, int, Memimage*, Point, int);
+
+ fill = fillline;
+/*
+ * This can only work on 8-bit destinations, since fillcolor is
+ * just using memset on sp.x.
+ *
+ * I'd rather not even enable it then, since then if the general
+ * code is too slow, someone will come up with a better improvement
+ * than this sleazy hack. -rsc
+ *
+ if(clipped && (src->flags&Frepl) && src->depth==8 && Dx(src->r)==1 && Dy(src->r)==1) {
+ fill = fillcolor;
+ sp.x = membyteval(src);
+ }
+ *
+ */
+ USED(clipped);
+
+
+ for(i=0, s=segtab, p=seg; i<nseg; i++, s++) {
+ *p = s;
+ if(s->p0.y == s->p1.y)
+ continue;
+ if(s->p0.y > s->p1.y) {
+ pt = s->p0;
+ s->p0 = s->p1;
+ s->p1 = pt;
+ s->d = -s->d;
+ }
+ s->num = s->p1.x - s->p0.x;
+ s->den = s->p1.y - s->p0.y;
+ s->dz = sdiv(s->num, s->den) << fixshift;
+ s->dzrem = mod(s->num, s->den) << fixshift;
+ s->dz += sdiv(s->dzrem, s->den);
+ s->dzrem = mod(s->dzrem, s->den);
+ p++;
+ }
+ n = p-seg;
+ if(n == 0)
+ return;
+ *p = 0;
+ qsort(seg, p-seg , sizeof(Seg*), ycompare);
+
+ onehalf = 0;
+ if(fixshift)
+ onehalf = 1 << (fixshift-1);
+
+ minx = dst->clipr.min.x;
+ maxx = dst->clipr.max.x;
+
+ y = seg[0]->p0.y;
+ if(y < (dst->clipr.min.y << fixshift))
+ y = dst->clipr.min.y << fixshift;
+ iy = (y + onehalf) >> fixshift;
+ y = (iy << fixshift) + onehalf;
+ maxy = dst->clipr.max.y << fixshift;
+
+ ep = next = seg;
+
+ while(y<maxy) {
+ for(q = p = seg; p < ep; p++) {
+ s = *p;
+ if(s->p1.y < y)
+ continue;
+ s->z += s->dz;
+ s->zerr += s->dzrem;
+ if(s->zerr >= s->den) {
+ s->z++;
+ s->zerr -= s->den;
+ if(s->zerr < 0 || s->zerr >= s->den)
+ print("bad ratzerr1: %ld den %ld dzrem %ld\n", s->zerr, s->den, s->dzrem);
+ }
+ *q++ = s;
+ }
+
+ for(p = next; *p; p++) {
+ s = *p;
+ if(s->p0.y >= y)
+ break;
+ if(s->p1.y < y)
+ continue;
+ s->z = s->p0.x;
+ s->z += smuldivmod(y - s->p0.y, s->num, s->den, &s->zerr);
+ if(s->zerr < 0 || s->zerr >= s->den)
+ print("bad ratzerr2: %ld den %ld ratdzrem %ld\n", s->zerr, s->den, s->dzrem);
+ *q++ = s;
+ }
+ ep = q;
+ next = p;
+
+ if(ep == seg) {
+ if(*next == 0)
+ break;
+ iy = (next[0]->p0.y + onehalf) >> fixshift;
+ y = (iy << fixshift) + onehalf;
+ continue;
+ }
+
+ zsort(seg, ep);
+
+ for(p = seg; p < ep; p++) {
+ cnt = 0;
+ x = p[0]->z;
+ xerr = p[0]->zerr;
+ xden = p[0]->den;
+ ix = (x + onehalf) >> fixshift;
+ if(ix >= maxx)
+ break;
+ if(ix < minx)
+ ix = minx;
+ cnt += p[0]->d;
+ p++;
+ for(;;) {
+ if(p == ep) {
+ print("xscan: fill to infinity");
+ return;
+ }
+ cnt += p[0]->d;
+ if((cnt&wind) == 0)
+ break;
+ p++;
+ }
+ x2 = p[0]->z;
+ ix2 = (x2 + onehalf) >> fixshift;
+ if(ix2 <= minx)
+ continue;
+ if(ix2 > maxx)
+ ix2 = maxx;
+ if(ix == ix2 && detail) {
+ if(xerr*p[0]->den + p[0]->zerr*xden > p[0]->den*xden)
+ x++;
+ ix = (x + x2) >> (fixshift+1);
+ ix2 = ix+1;
+ }
+ (*fill)(dst, ix, ix2, iy, src, sp, op);
+ }
+ y += (1<<fixshift);
+ iy++;
+ }
+}
+
+static void
+yscan(Memimage *dst, Seg **seg, Seg *segtab, int nseg, int wind, Memimage *src, Point sp, int fixshift, int op)
+{
+ long x, maxx, y, y2, yerr, yden, onehalf;
+ Seg **ep, **next, **p, **q, *s;
+ int n, i, ix, cnt, iy, iy2, miny, maxy;
+ Point pt;
+
+ for(i=0, s=segtab, p=seg; i<nseg; i++, s++) {
+ *p = s;
+ if(s->p0.x == s->p1.x)
+ continue;
+ if(s->p0.x > s->p1.x) {
+ pt = s->p0;
+ s->p0 = s->p1;
+ s->p1 = pt;
+ s->d = -s->d;
+ }
+ s->num = s->p1.y - s->p0.y;
+ s->den = s->p1.x - s->p0.x;
+ s->dz = sdiv(s->num, s->den) << fixshift;
+ s->dzrem = mod(s->num, s->den) << fixshift;
+ s->dz += sdiv(s->dzrem, s->den);
+ s->dzrem = mod(s->dzrem, s->den);
+ p++;
+ }
+ n = p-seg;
+ if(n == 0)
+ return;
+ *p = 0;
+ qsort(seg, n , sizeof(Seg*), xcompare);
+
+ onehalf = 0;
+ if(fixshift)
+ onehalf = 1 << (fixshift-1);
+
+ miny = dst->clipr.min.y;
+ maxy = dst->clipr.max.y;
+
+ x = seg[0]->p0.x;
+ if(x < (dst->clipr.min.x << fixshift))
+ x = dst->clipr.min.x << fixshift;
+ ix = (x + onehalf) >> fixshift;
+ x = (ix << fixshift) + onehalf;
+ maxx = dst->clipr.max.x << fixshift;
+
+ ep = next = seg;
+
+ while(x<maxx) {
+ for(q = p = seg; p < ep; p++) {
+ s = *p;
+ if(s->p1.x < x)
+ continue;
+ s->z += s->dz;
+ s->zerr += s->dzrem;
+ if(s->zerr >= s->den) {
+ s->z++;
+ s->zerr -= s->den;
+ if(s->zerr < 0 || s->zerr >= s->den)
+ print("bad ratzerr1: %ld den %ld ratdzrem %ld\n", s->zerr, s->den, s->dzrem);
+ }
+ *q++ = s;
+ }
+
+ for(p = next; *p; p++) {
+ s = *p;
+ if(s->p0.x >= x)
+ break;
+ if(s->p1.x < x)
+ continue;
+ s->z = s->p0.y;
+ s->z += smuldivmod(x - s->p0.x, s->num, s->den, &s->zerr);
+ if(s->zerr < 0 || s->zerr >= s->den)
+ print("bad ratzerr2: %ld den %ld ratdzrem %ld\n", s->zerr, s->den, s->dzrem);
+ *q++ = s;
+ }
+ ep = q;
+ next = p;
+
+ if(ep == seg) {
+ if(*next == 0)
+ break;
+ ix = (next[0]->p0.x + onehalf) >> fixshift;
+ x = (ix << fixshift) + onehalf;
+ continue;
+ }
+
+ zsort(seg, ep);
+
+ for(p = seg; p < ep; p++) {
+ cnt = 0;
+ y = p[0]->z;
+ yerr = p[0]->zerr;
+ yden = p[0]->den;
+ iy = (y + onehalf) >> fixshift;
+ if(iy >= maxy)
+ break;
+ if(iy < miny)
+ iy = miny;
+ cnt += p[0]->d;
+ p++;
+ for(;;) {
+ if(p == ep) {
+ print("yscan: fill to infinity");
+ return;
+ }
+ cnt += p[0]->d;
+ if((cnt&wind) == 0)
+ break;
+ p++;
+ }
+ y2 = p[0]->z;
+ iy2 = (y2 + onehalf) >> fixshift;
+ if(iy2 <= miny)
+ continue;
+ if(iy2 > maxy)
+ iy2 = maxy;
+ if(iy == iy2) {
+ if(yerr*p[0]->den + p[0]->zerr*yden > p[0]->den*yden)
+ y++;
+ iy = (y + y2) >> (fixshift+1);
+ fillpoint(dst, ix, iy, src, sp, op);
+ }
+ }
+ x += (1<<fixshift);
+ ix++;
+ }
+}
+
+static void
+zsort(Seg **seg, Seg **ep)
+{
+ int done;
+ Seg **q, **p, *s;
+
+ if(ep-seg < 20) {
+ /* bubble sort by z - they should be almost sorted already */
+ q = ep;
+ do {
+ done = 1;
+ q--;
+ for(p = seg; p < q; p++) {
+ if(p[0]->z > p[1]->z) {
+ s = p[0];
+ p[0] = p[1];
+ p[1] = s;
+ done = 0;
+ }
+ }
+ } while(!done);
+ } else {
+ q = ep-1;
+ for(p = seg; p < q; p++) {
+ if(p[0]->z > p[1]->z) {
+ qsort(seg, ep-seg, sizeof(Seg*), zcompare);
+ break;
+ }
+ }
+ }
+}
+
+static int
+ycompare(void *a, void *b)
+{
+ Seg **s0, **s1;
+ long y0, y1;
+
+ s0 = a;
+ s1 = b;
+ y0 = (*s0)->p0.y;
+ y1 = (*s1)->p0.y;
+
+ if(y0 < y1)
+ return -1;
+ if(y0 == y1)
+ return 0;
+ return 1;
+}
+
+static int
+xcompare(void *a, void *b)
+{
+ Seg **s0, **s1;
+ long x0, x1;
+
+ s0 = a;
+ s1 = b;
+ x0 = (*s0)->p0.x;
+ x1 = (*s1)->p0.x;
+
+ if(x0 < x1)
+ return -1;
+ if(x0 == x1)
+ return 0;
+ return 1;
+}
+
+static int
+zcompare(void *a, void *b)
+{
+ Seg **s0, **s1;
+ long z0, z1;
+
+ s0 = a;
+ s1 = b;
+ z0 = (*s0)->z;
+ z1 = (*s1)->z;
+
+ if(z0 < z1)
+ return -1;
+ if(z0 == z1)
+ return 0;
+ return 1;
+}
--- /dev/null
+++ b/libmemdraw/hwdraw.c
@@ -1,0 +1,11 @@
+#include "lib9.h"
+#include "draw.h"
+#include "memdraw.h"
+
+int
+hwdraw(Memdrawparam *p)
+{
+ USED(p);
+ return 0; /* could not satisfy request */
+}
+
--- /dev/null
+++ b/libmemdraw/icossin.c
@@ -1,0 +1,139 @@
+#include "lib9.h"
+#include "draw.h"
+
+/*
+ * Integer sine and cosine for integral degree argument.
+ * Tables computed by (sin,cos)(PI*d/180).
+ */
+static short sinus[91] = {
+ 0, /* 0 */
+ 18, /* 1 */
+ 36, /* 2 */
+ 54, /* 3 */
+ 71, /* 4 */
+ 89, /* 5 */
+ 107, /* 6 */
+ 125, /* 7 */
+ 143, /* 8 */
+ 160, /* 9 */
+ 178, /* 10 */
+ 195, /* 11 */
+ 213, /* 12 */
+ 230, /* 13 */
+ 248, /* 14 */
+ 265, /* 15 */
+ 282, /* 16 */
+ 299, /* 17 */
+ 316, /* 18 */
+ 333, /* 19 */
+ 350, /* 20 */
+ 367, /* 21 */
+ 384, /* 22 */
+ 400, /* 23 */
+ 416, /* 24 */
+ 433, /* 25 */
+ 449, /* 26 */
+ 465, /* 27 */
+ 481, /* 28 */
+ 496, /* 29 */
+ 512, /* 30 */
+ 527, /* 31 */
+ 543, /* 32 */
+ 558, /* 33 */
+ 573, /* 34 */
+ 587, /* 35 */
+ 602, /* 36 */
+ 616, /* 37 */
+ 630, /* 38 */
+ 644, /* 39 */
+ 658, /* 40 */
+ 672, /* 41 */
+ 685, /* 42 */
+ 698, /* 43 */
+ 711, /* 44 */
+ 724, /* 45 */
+ 737, /* 46 */
+ 749, /* 47 */
+ 761, /* 48 */
+ 773, /* 49 */
+ 784, /* 50 */
+ 796, /* 51 */
+ 807, /* 52 */
+ 818, /* 53 */
+ 828, /* 54 */
+ 839, /* 55 */
+ 849, /* 56 */
+ 859, /* 57 */
+ 868, /* 58 */
+ 878, /* 59 */
+ 887, /* 60 */
+ 896, /* 61 */
+ 904, /* 62 */
+ 912, /* 63 */
+ 920, /* 64 */
+ 928, /* 65 */
+ 935, /* 66 */
+ 943, /* 67 */
+ 949, /* 68 */
+ 956, /* 69 */
+ 962, /* 70 */
+ 968, /* 71 */
+ 974, /* 72 */
+ 979, /* 73 */
+ 984, /* 74 */
+ 989, /* 75 */
+ 994, /* 76 */
+ 998, /* 77 */
+ 1002, /* 78 */
+ 1005, /* 79 */
+ 1008, /* 80 */
+ 1011, /* 81 */
+ 1014, /* 82 */
+ 1016, /* 83 */
+ 1018, /* 84 */
+ 1020, /* 85 */
+ 1022, /* 86 */
+ 1023, /* 87 */
+ 1023, /* 88 */
+ 1024, /* 89 */
+ 1024, /* 90 */
+};
+
+void
+icossin(int deg, int *cosp, int *sinp)
+{
+ int sinsign, cossign;
+ short *stp, *ctp;
+
+ deg %= 360;
+ if(deg < 0)
+ deg += 360;
+ sinsign = 1;
+ cossign = 1;
+ stp = 0;
+ ctp = 0;
+ switch(deg/90){
+ case 2:
+ sinsign = -1;
+ cossign = -1;
+ deg -= 180;
+ /* fall through */
+ case 0:
+ stp = &sinus[deg];
+ ctp = &sinus[90-deg];
+ break;
+ case 3:
+ sinsign = -1;
+ cossign = -1;
+ deg -= 180;
+ /* fall through */
+ case 1:
+ deg = 180-deg;
+ cossign = -cossign;
+ stp = &sinus[deg];
+ ctp = &sinus[90-deg];
+ break;
+ }
+ *sinp = sinsign*stp[0];
+ *cosp = cossign*ctp[0];
+}
--- /dev/null
+++ b/libmemdraw/icossin2.c
@@ -1,0 +1,260 @@
+#include "lib9.h"
+#include "draw.h"
+
+/*
+ * Sine and Cosine of arctangents, calculated by
+ * (sin(atan(index/100.0))*1024.+0.5)
+ * (cos(atan(index/100.0))*1024.+0.5)
+ * To use, get rational tangent between 0<=tan<=1, scale by 100,
+ * and look up sin and cos, and use linear interpolation. divide by 1024.
+ * Maximum error is 0.0020. Without linear interpolation, it's 0.010.
+ */
+static
+short sinus[] = {
+ 0, /* 0.00 */
+ 10, /* 0.01 */
+ 20, /* 0.02 */
+ 31, /* 0.03 */
+ 41, /* 0.04 */
+ 51, /* 0.05 */
+ 61, /* 0.06 */
+ 72, /* 0.07 */
+ 82, /* 0.08 */
+ 92, /* 0.09 */
+ 102, /* 0.10 */
+ 112, /* 0.11 */
+ 122, /* 0.12 */
+ 132, /* 0.13 */
+ 142, /* 0.14 */
+ 152, /* 0.15 */
+ 162, /* 0.16 */
+ 172, /* 0.17 */
+ 181, /* 0.18 */
+ 191, /* 0.19 */
+ 201, /* 0.20 */
+ 210, /* 0.21 */
+ 220, /* 0.22 */
+ 230, /* 0.23 */
+ 239, /* 0.24 */
+ 248, /* 0.25 */
+ 258, /* 0.26 */
+ 267, /* 0.27 */
+ 276, /* 0.28 */
+ 285, /* 0.29 */
+ 294, /* 0.30 */
+ 303, /* 0.31 */
+ 312, /* 0.32 */
+ 321, /* 0.33 */
+ 330, /* 0.34 */
+ 338, /* 0.35 */
+ 347, /* 0.36 */
+ 355, /* 0.37 */
+ 364, /* 0.38 */
+ 372, /* 0.39 */
+ 380, /* 0.40 */
+ 388, /* 0.41 */
+ 397, /* 0.42 */
+ 405, /* 0.43 */
+ 412, /* 0.44 */
+ 420, /* 0.45 */
+ 428, /* 0.46 */
+ 436, /* 0.47 */
+ 443, /* 0.48 */
+ 451, /* 0.49 */
+ 458, /* 0.50 */
+ 465, /* 0.51 */
+ 472, /* 0.52 */
+ 480, /* 0.53 */
+ 487, /* 0.54 */
+ 493, /* 0.55 */
+ 500, /* 0.56 */
+ 507, /* 0.57 */
+ 514, /* 0.58 */
+ 520, /* 0.59 */
+ 527, /* 0.60 */
+ 533, /* 0.61 */
+ 540, /* 0.62 */
+ 546, /* 0.63 */
+ 552, /* 0.64 */
+ 558, /* 0.65 */
+ 564, /* 0.66 */
+ 570, /* 0.67 */
+ 576, /* 0.68 */
+ 582, /* 0.69 */
+ 587, /* 0.70 */
+ 593, /* 0.71 */
+ 598, /* 0.72 */
+ 604, /* 0.73 */
+ 609, /* 0.74 */
+ 614, /* 0.75 */
+ 620, /* 0.76 */
+ 625, /* 0.77 */
+ 630, /* 0.78 */
+ 635, /* 0.79 */
+ 640, /* 0.80 */
+ 645, /* 0.81 */
+ 649, /* 0.82 */
+ 654, /* 0.83 */
+ 659, /* 0.84 */
+ 663, /* 0.85 */
+ 668, /* 0.86 */
+ 672, /* 0.87 */
+ 676, /* 0.88 */
+ 681, /* 0.89 */
+ 685, /* 0.90 */
+ 689, /* 0.91 */
+ 693, /* 0.92 */
+ 697, /* 0.93 */
+ 701, /* 0.94 */
+ 705, /* 0.95 */
+ 709, /* 0.96 */
+ 713, /* 0.97 */
+ 717, /* 0.98 */
+ 720, /* 0.99 */
+ 724, /* 1.00 */
+ 728, /* 1.01 */
+};
+
+static
+short cosinus[] = {
+ 1024, /* 0.00 */
+ 1024, /* 0.01 */
+ 1024, /* 0.02 */
+ 1024, /* 0.03 */
+ 1023, /* 0.04 */
+ 1023, /* 0.05 */
+ 1022, /* 0.06 */
+ 1022, /* 0.07 */
+ 1021, /* 0.08 */
+ 1020, /* 0.09 */
+ 1019, /* 0.10 */
+ 1018, /* 0.11 */
+ 1017, /* 0.12 */
+ 1015, /* 0.13 */
+ 1014, /* 0.14 */
+ 1013, /* 0.15 */
+ 1011, /* 0.16 */
+ 1010, /* 0.17 */
+ 1008, /* 0.18 */
+ 1006, /* 0.19 */
+ 1004, /* 0.20 */
+ 1002, /* 0.21 */
+ 1000, /* 0.22 */
+ 998, /* 0.23 */
+ 996, /* 0.24 */
+ 993, /* 0.25 */
+ 991, /* 0.26 */
+ 989, /* 0.27 */
+ 986, /* 0.28 */
+ 983, /* 0.29 */
+ 981, /* 0.30 */
+ 978, /* 0.31 */
+ 975, /* 0.32 */
+ 972, /* 0.33 */
+ 969, /* 0.34 */
+ 967, /* 0.35 */
+ 963, /* 0.36 */
+ 960, /* 0.37 */
+ 957, /* 0.38 */
+ 954, /* 0.39 */
+ 951, /* 0.40 */
+ 947, /* 0.41 */
+ 944, /* 0.42 */
+ 941, /* 0.43 */
+ 937, /* 0.44 */
+ 934, /* 0.45 */
+ 930, /* 0.46 */
+ 927, /* 0.47 */
+ 923, /* 0.48 */
+ 920, /* 0.49 */
+ 916, /* 0.50 */
+ 912, /* 0.51 */
+ 909, /* 0.52 */
+ 905, /* 0.53 */
+ 901, /* 0.54 */
+ 897, /* 0.55 */
+ 893, /* 0.56 */
+ 890, /* 0.57 */
+ 886, /* 0.58 */
+ 882, /* 0.59 */
+ 878, /* 0.60 */
+ 874, /* 0.61 */
+ 870, /* 0.62 */
+ 866, /* 0.63 */
+ 862, /* 0.64 */
+ 859, /* 0.65 */
+ 855, /* 0.66 */
+ 851, /* 0.67 */
+ 847, /* 0.68 */
+ 843, /* 0.69 */
+ 839, /* 0.70 */
+ 835, /* 0.71 */
+ 831, /* 0.72 */
+ 827, /* 0.73 */
+ 823, /* 0.74 */
+ 819, /* 0.75 */
+ 815, /* 0.76 */
+ 811, /* 0.77 */
+ 807, /* 0.78 */
+ 804, /* 0.79 */
+ 800, /* 0.80 */
+ 796, /* 0.81 */
+ 792, /* 0.82 */
+ 788, /* 0.83 */
+ 784, /* 0.84 */
+ 780, /* 0.85 */
+ 776, /* 0.86 */
+ 773, /* 0.87 */
+ 769, /* 0.88 */
+ 765, /* 0.89 */
+ 761, /* 0.90 */
+ 757, /* 0.91 */
+ 754, /* 0.92 */
+ 750, /* 0.93 */
+ 746, /* 0.94 */
+ 742, /* 0.95 */
+ 739, /* 0.96 */
+ 735, /* 0.97 */
+ 731, /* 0.98 */
+ 728, /* 0.99 */
+ 724, /* 1.00 */
+ 720, /* 1.01 */
+};
+
+void
+icossin2(int x, int y, int *cosp, int *sinp)
+{
+ int sinsign, cossign, tan, tan10, rem;
+ short *stp, *ctp;
+
+ if(x == 0){
+ if(y >= 0)
+ *sinp = ICOSSCALE, *cosp = 0;
+ else
+ *sinp = -ICOSSCALE, *cosp = 0;
+ return;
+ }
+ sinsign = cossign = 1;
+ if(x < 0){
+ cossign = -1;
+ x = -x;
+ }
+ if(y < 0){
+ sinsign = -1;
+ y = -y;
+ }
+ if(y > x){
+ tan = 1000*x/y;
+ tan10 = tan/10;
+ stp = &cosinus[tan10];
+ ctp = &sinus[tan10];
+ }else{
+ tan = 1000*y/x;
+ tan10 = tan/10;
+ stp = &sinus[tan10];
+ ctp = &cosinus[tan10];
+ }
+ rem = tan-(tan10*10);
+ *sinp = sinsign*(stp[0]+(stp[1]-stp[0])*rem/10);
+ *cosp = cossign*(ctp[0]+(ctp[1]-ctp[0])*rem/10);
+}
--- /dev/null
+++ b/libmemdraw/iprint.c
@@ -1,0 +1,11 @@
+#include "lib9.h"
+#include "draw.h"
+#include "memdraw.h"
+
+int
+iprint(char *f,...)
+{
+ USED(f);
+ return -1;
+}
+
--- /dev/null
+++ b/libmemdraw/line.c
@@ -1,0 +1,481 @@
+#include "lib9.h"
+#include "draw.h"
+#include "memdraw.h"
+#include "memlayer.h"
+
+enum
+{
+ Arrow1 = 8,
+ Arrow2 = 10,
+ Arrow3 = 3,
+};
+
+static
+int
+lmin(int a, int b)
+{
+ if(a < b)
+ return a;
+ return b;
+}
+
+static
+int
+lmax(int a, int b)
+{
+ if(a > b)
+ return a;
+ return b;
+}
+
+/*
+ * Rather than line clip, we run the Bresenham loop over the full line,
+ * and clip on each pixel. This is more expensive but means that
+ * lines look the same regardless of how the windowing has tiled them.
+ * For speed, we check for clipping outside the loop and make the
+ * test easy when possible.
+ */
+
+#ifdef XXX
+static
+void
+horline1(Memimage *dst, Point p0, Point p1, int srcval, Rectangle clipr)
+{
+ int x, y, dy, deltay, deltax, maxx;
+ int dd, easy, e, bpp, m, m0;
+ uchar *d;
+
+ deltax = p1.x - p0.x;
+ deltay = p1.y - p0.y;
+ dd = dst->width*sizeof(ulong);
+ dy = 1;
+ if(deltay < 0){
+ dd = -dd;
+ deltay = -deltay;
+ dy = -1;
+ }
+ maxx = lmin(p1.x, clipr.max.x-1);
+ bpp = dst->depth;
+ m0 = 0xFF^(0xFF>>bpp);
+ m = m0 >> (p0.x&(7/dst->depth))*bpp;
+ easy = ptinrect(p0, clipr) && ptinrect(p1, clipr);
+ e = 2*deltay - deltax;
+ y = p0.y;
+ d = byteaddr(dst, p0);
+ deltay *= 2;
+ deltax = deltay - 2*deltax;
+ for(x=p0.x; x<=maxx; x++){
+ if(easy || (clipr.min.x<=x && clipr.min.y<=y && y<clipr.max.y))
+ *d ^= (*d^srcval) & m;
+ if(e > 0){
+ y += dy;
+ d += dd;
+ e += deltax;
+ }else
+ e += deltay;
+ d++;
+ m >>= bpp;
+ if(m == 0)
+ m = m0;
+ }
+}
+
+static
+void
+verline1(Memimage *dst, Point p0, Point p1, int srcval, Rectangle clipr)
+{
+ int x, y, deltay, deltax, maxy;
+ int easy, e, bpp, m, m0, dd;
+ uchar *d;
+
+ deltax = p1.x - p0.x;
+ deltay = p1.y - p0.y;
+ dd = 1;
+ if(deltax < 0){
+ dd = -1;
+ deltax = -deltax;
+ }
+ maxy = lmin(p1.y, clipr.max.y-1);
+ bpp = dst->depth;
+ m0 = 0xFF^(0xFF>>bpp);
+ m = m0 >> (p0.x&(7/dst->depth))*bpp;
+ easy = ptinrect(p0, clipr) && ptinrect(p1, clipr);
+ e = 2*deltax - deltay;
+ x = p0.x;
+ d = byteaddr(dst, p0);
+ deltax *= 2;
+ deltay = deltax - 2*deltay;
+ for(y=p0.y; y<=maxy; y++){
+ if(easy || (clipr.min.y<=y && clipr.min.x<=x && x<clipr.max.x))
+ *d ^= (*d^srcval) & m;
+ if(e > 0){
+ x += dd;
+ d += dd;
+ e += deltay;
+ }else
+ e += deltax;
+ d += dst->width*sizeof(ulong);
+ m >>= bpp;
+ if(m == 0)
+ m = m0;
+ }
+}
+
+static
+void
+horliner(Memimage *dst, Point p0, Point p1, Memimage *src, Point dsrc, Rectangle clipr)
+{
+ int x, y, sx, sy, deltay, deltax, minx, maxx;
+ int bpp, m, m0;
+ uchar *d, *s;
+
+ deltax = p1.x - p0.x;
+ deltay = p1.y - p0.y;
+ sx = drawreplxy(src->r.min.x, src->r.max.x, p0.x+dsrc.x);
+ minx = lmax(p0.x, clipr.min.x);
+ maxx = lmin(p1.x, clipr.max.x-1);
+ bpp = dst->depth;
+ m0 = 0xFF^(0xFF>>bpp);
+ m = m0 >> (minx&(7/dst->depth))*bpp;
+ for(x=minx; x<=maxx; x++){
+ y = p0.y + (deltay*(x-p0.x)+deltax/2)/deltax;
+ if(clipr.min.y<=y && y<clipr.max.y){
+ d = byteaddr(dst, Pt(x, y));
+ sy = drawreplxy(src->r.min.y, src->r.max.y, y+dsrc.y);
+ s = byteaddr(src, Pt(sx, sy));
+ *d ^= (*d^*s) & m;
+ }
+ if(++sx >= src->r.max.x)
+ sx = src->r.min.x;
+ m >>= bpp;
+ if(m == 0)
+ m = m0;
+ }
+}
+
+static
+void
+verliner(Memimage *dst, Point p0, Point p1, Memimage *src, Point dsrc, Rectangle clipr)
+{
+ int x, y, sx, sy, deltay, deltax, miny, maxy;
+ int bpp, m, m0;
+ uchar *d, *s;
+
+ deltax = p1.x - p0.x;
+ deltay = p1.y - p0.y;
+ sy = drawreplxy(src->r.min.y, src->r.max.y, p0.y+dsrc.y);
+ miny = lmax(p0.y, clipr.min.y);
+ maxy = lmin(p1.y, clipr.max.y-1);
+ bpp = dst->depth;
+ m0 = 0xFF^(0xFF>>bpp);
+ for(y=miny; y<=maxy; y++){
+ if(deltay == 0) /* degenerate line */
+ x = p0.x;
+ else
+ x = p0.x + (deltax*(y-p0.y)+deltay/2)/deltay;
+ if(clipr.min.x<=x && x<clipr.max.x){
+ m = m0 >> (x&(7/dst->depth))*bpp;
+ d = byteaddr(dst, Pt(x, y));
+ sx = drawreplxy(src->r.min.x, src->r.max.x, x+dsrc.x);
+ s = byteaddr(src, Pt(sx, sy));
+ *d ^= (*d^*s) & m;
+ }
+ if(++sy >= src->r.max.y)
+ sy = src->r.min.y;
+ }
+}
+
+static
+void
+horline(Memimage *dst, Point p0, Point p1, Memimage *src, Point dsrc, Rectangle clipr)
+{
+ int x, y, deltay, deltax, minx, maxx;
+ int bpp, m, m0;
+ uchar *d, *s;
+
+ deltax = p1.x - p0.x;
+ deltay = p1.y - p0.y;
+ minx = lmax(p0.x, clipr.min.x);
+ maxx = lmin(p1.x, clipr.max.x-1);
+ bpp = dst->depth;
+ m0 = 0xFF^(0xFF>>bpp);
+ m = m0 >> (minx&(7/dst->depth))*bpp;
+ for(x=minx; x<=maxx; x++){
+ y = p0.y + (deltay*(x-p0.x)+deltay/2)/deltax;
+ if(clipr.min.y<=y && y<clipr.max.y){
+ d = byteaddr(dst, Pt(x, y));
+ s = byteaddr(src, addpt(dsrc, Pt(x, y)));
+ *d ^= (*d^*s) & m;
+ }
+ m >>= bpp;
+ if(m == 0)
+ m = m0;
+ }
+}
+
+static
+void
+verline(Memimage *dst, Point p0, Point p1, Memimage *src, Point dsrc, Rectangle clipr)
+{
+ int x, y, deltay, deltax, miny, maxy;
+ int bpp, m, m0;
+ uchar *d, *s;
+
+ deltax = p1.x - p0.x;
+ deltay = p1.y - p0.y;
+ miny = lmax(p0.y, clipr.min.y);
+ maxy = lmin(p1.y, clipr.max.y-1);
+ bpp = dst->depth;
+ m0 = 0xFF^(0xFF>>bpp);
+ for(y=miny; y<=maxy; y++){
+ if(deltay == 0) /* degenerate line */
+ x = p0.x;
+ else
+ x = p0.x + deltax*(y-p0.y)/deltay;
+ if(clipr.min.x<=x && x<clipr.max.x){
+ m = m0 >> (x&(7/dst->depth))*bpp;
+ d = byteaddr(dst, Pt(x, y));
+ s = byteaddr(src, addpt(dsrc, Pt(x, y)));
+ *d ^= (*d^*s) & m;
+ }
+ }
+}
+#endif
+
+static Memimage*
+membrush(int radius)
+{
+ static Memimage *brush;
+ static int brushradius;
+
+ if(brush==nil || brushradius!=radius){
+ freememimage(brush);
+ brush = allocmemimage(Rect(0, 0, 2*radius+1, 2*radius+1), memopaque->chan);
+ if(brush != nil){
+ memfillcolor(brush, DTransparent); /* zeros */
+ memellipse(brush, Pt(radius, radius), radius, radius, -1, memopaque, Pt(radius, radius), S);
+ }
+ brushradius = radius;
+ }
+ return brush;
+}
+
+static
+void
+discend(Point p, int radius, Memimage *dst, Memimage *src, Point dsrc, int op)
+{
+ Memimage *disc;
+ Rectangle r;
+
+ disc = membrush(radius);
+ if(disc != nil){
+ r.min.x = p.x - radius;
+ r.min.y = p.y - radius;
+ r.max.x = p.x + radius+1;
+ r.max.y = p.y + radius+1;
+ memdraw(dst, r, src, addpt(r.min, dsrc), disc, Pt(0,0), op);
+ }
+}
+
+static
+void
+arrowend(Point tip, Point *pp, int end, int sin, int cos, int radius)
+{
+ int x1, x2, x3;
+
+ /* before rotation */
+ if(end == Endarrow){
+ x1 = Arrow1;
+ x2 = Arrow2;
+ x3 = Arrow3;
+ }else{
+ x1 = (end>>5) & 0x1FF; /* distance along line from end of line to tip */
+ x2 = (end>>14) & 0x1FF; /* distance along line from barb to tip */
+ x3 = (end>>23) & 0x1FF; /* distance perpendicular from edge of line to barb */
+ }
+
+ /* comments follow track of right-facing arrowhead */
+ pp->x = tip.x+((2*radius+1)*sin/2-x1*cos); /* upper side of shaft */
+ pp->y = tip.y-((2*radius+1)*cos/2+x1*sin);
+ pp++;
+ pp->x = tip.x+((2*radius+2*x3+1)*sin/2-x2*cos); /* upper barb */
+ pp->y = tip.y-((2*radius+2*x3+1)*cos/2+x2*sin);
+ pp++;
+ pp->x = tip.x;
+ pp->y = tip.y;
+ pp++;
+ pp->x = tip.x+(-(2*radius+2*x3+1)*sin/2-x2*cos); /* lower barb */
+ pp->y = tip.y-(-(2*radius+2*x3+1)*cos/2+x2*sin);
+ pp++;
+ pp->x = tip.x+(-(2*radius+1)*sin/2-x1*cos); /* lower side of shaft */
+ pp->y = tip.y+((2*radius+1)*cos/2-x1*sin);
+}
+
+void
+_memimageline(Memimage *dst, Point p0, Point p1, int end0, int end1, int radius, Memimage *src, Point sp, Rectangle clipr, int op)
+{
+ int hor;
+ int sin, cos, dx, dy, t;
+ Rectangle oclipr, r;
+ Point q, pts[10], *pp, d;
+
+ if(radius < 0)
+ return;
+ if(rectclip(&clipr, dst->r) == 0)
+ return;
+ if(rectclip(&clipr, dst->clipr) == 0)
+ return;
+ d = subpt(sp, p0);
+ if(rectclip(&clipr, rectsubpt(src->clipr, d)) == 0)
+ return;
+ if((src->flags&Frepl)==0 && rectclip(&clipr, rectsubpt(src->r, d))==0)
+ return;
+ /* this means that only verline() handles degenerate lines (p0==p1) */
+ hor = (abs(p1.x-p0.x) > abs(p1.y-p0.y));
+ /*
+ * Clipping is a little peculiar. We can't use Sutherland-Cohen
+ * clipping because lines are wide. But this is probably just fine:
+ * we do all math with the original p0 and p1, but clip when deciding
+ * what pixels to draw. This means the layer code can call this routine,
+ * using clipr to define the region being written, and get the same set
+ * of pixels regardless of the dicing.
+ */
+ if((hor && p0.x>p1.x) || (!hor && p0.y>p1.y)){
+ q = p0;
+ p0 = p1;
+ p1 = q;
+ t = end0;
+ end0 = end1;
+ end1 = t;
+ }
+
+ if((p0.x == p1.x || p0.y == p1.y) && (end0&0x1F) == Endsquare && (end1&0x1F) == Endsquare){
+ r.min = p0;
+ r.max = p1;
+ if(p0.x == p1.x){
+ r.min.x -= radius;
+ r.max.x += radius+1;
+ r.max.y++;
+ }
+ else{
+ r.min.y -= radius;
+ r.max.y += radius+1;
+ r.max.x++;
+ }
+ oclipr = dst->clipr;
+ dst->clipr = clipr;
+ sp = addpt(r.min, d);
+ memimagedraw(dst, r, src, sp, memopaque, sp, op);
+ dst->clipr = oclipr;
+ return;
+ }
+
+/* Hard: */
+ /* draw thick line using polygon fill */
+ icossin2(p1.x-p0.x, p1.y-p0.y, &cos, &sin);
+ dx = (sin*(2*radius+1))/2;
+ dy = (cos*(2*radius+1))/2;
+ pp = pts;
+ oclipr = dst->clipr;
+ dst->clipr = clipr;
+ q.x = ICOSSCALE*p0.x+ICOSSCALE/2-cos/2;
+ q.y = ICOSSCALE*p0.y+ICOSSCALE/2-sin/2;
+ switch(end0 & 0x1F){
+ case Enddisc:
+ discend(p0, radius, dst, src, d, op);
+ /* fall through */
+ case Endsquare:
+ default:
+ pp->x = q.x-dx;
+ pp->y = q.y+dy;
+ pp++;
+ pp->x = q.x+dx;
+ pp->y = q.y-dy;
+ pp++;
+ break;
+ case Endarrow:
+ arrowend(q, pp, end0, -sin, -cos, radius);
+ _memfillpolysc(dst, pts, 5, ~0, src, addpt(pts[0], mulpt(d, ICOSSCALE)), 1, 10, 1, op);
+ pp[1] = pp[4];
+ pp += 2;
+ }
+ q.x = ICOSSCALE*p1.x+ICOSSCALE/2+cos/2;
+ q.y = ICOSSCALE*p1.y+ICOSSCALE/2+sin/2;
+ switch(end1 & 0x1F){
+ case Enddisc:
+ discend(p1, radius, dst, src, d, op);
+ /* fall through */
+ case Endsquare:
+ default:
+ pp->x = q.x+dx;
+ pp->y = q.y-dy;
+ pp++;
+ pp->x = q.x-dx;
+ pp->y = q.y+dy;
+ pp++;
+ break;
+ case Endarrow:
+ arrowend(q, pp, end1, sin, cos, radius);
+ _memfillpolysc(dst, pp, 5, ~0, src, addpt(pts[0], mulpt(d, ICOSSCALE)), 1, 10, 1, op);
+ pp[1] = pp[4];
+ pp += 2;
+ }
+ _memfillpolysc(dst, pts, pp-pts, ~0, src, addpt(pts[0], mulpt(d, ICOSSCALE)), 0, 10, 1, op);
+ dst->clipr = oclipr;
+ return;
+}
+
+void
+memimageline(Memimage *dst, Point p0, Point p1, int end0, int end1, int radius, Memimage *src, Point sp, int op)
+{
+ _memimageline(dst, p0, p1, end0, end1, radius, src, sp, dst->clipr, op);
+}
+
+/*
+ * Simple-minded conservative code to compute bounding box of line.
+ * Result is probably a little larger than it needs to be.
+ */
+static
+void
+addbbox(Rectangle *r, Point p)
+{
+ if(r->min.x > p.x)
+ r->min.x = p.x;
+ if(r->min.y > p.y)
+ r->min.y = p.y;
+ if(r->max.x < p.x+1)
+ r->max.x = p.x+1;
+ if(r->max.y < p.y+1)
+ r->max.y = p.y+1;
+}
+
+int
+memlineendsize(int end)
+{
+ int x3;
+
+ if((end&0x3F) != Endarrow)
+ return 0;
+ if(end == Endarrow)
+ x3 = Arrow3;
+ else
+ x3 = (end>>23) & 0x1FF;
+ return x3;
+}
+
+Rectangle
+memlinebbox(Point p0, Point p1, int end0, int end1, int radius)
+{
+ Rectangle r, r1;
+ int extra;
+
+ r.min.x = 10000000;
+ r.min.y = 10000000;
+ r.max.x = -10000000;
+ r.max.y = -10000000;
+ extra = lmax(memlineendsize(end0), memlineendsize(end1));
+ r1 = insetrect(canonrect(Rpt(p0, p1)), -(radius+extra));
+ addbbox(&r, r1.min);
+ addbbox(&r, r1.max);
+ return r;
+}
--- /dev/null
+++ b/libmemdraw/load.c
@@ -1,0 +1,71 @@
+#include "lib9.h"
+#include "draw.h"
+#include "memdraw.h"
+
+int
+loadmemimage(Memimage *i, Rectangle r, uchar *data, int ndata)
+{
+ int y, l, lpart, rpart, mx, m, mr;
+ uchar *q;
+
+ if(!rectinrect(r, i->r))
+ return -1;
+ l = bytesperline(r, i->depth);
+ if(ndata < l*Dy(r))
+ return -1;
+ ndata = l*Dy(r);
+ q = byteaddr(i, r.min);
+ mx = 7/i->depth;
+ lpart = (r.min.x & mx) * i->depth;
+ rpart = (r.max.x & mx) * i->depth;
+ m = 0xFF >> lpart;
+ /* may need to do bit insertion on edges */
+ if(l == 1){ /* all in one byte */
+ if(rpart)
+ m ^= 0xFF >> rpart;
+ for(y=r.min.y; y<r.max.y; y++){
+ *q ^= (*data^*q) & m;
+ q += i->width*sizeof(ulong);
+ data++;
+ }
+ return ndata;
+ }
+ if(lpart==0 && rpart==0){ /* easy case */
+ for(y=r.min.y; y<r.max.y; y++){
+ memmove(q, data, l);
+ q += i->width*sizeof(ulong);
+ data += l;
+ }
+ return ndata;
+ }
+ mr = 0xFF ^ (0xFF >> rpart);
+ if(lpart!=0 && rpart==0){
+ for(y=r.min.y; y<r.max.y; y++){
+ *q ^= (*data^*q) & m;
+ if(l > 1)
+ memmove(q+1, data+1, l-1);
+ q += i->width*sizeof(ulong);
+ data += l;
+ }
+ return ndata;
+ }
+ if(lpart==0 && rpart!=0){
+ for(y=r.min.y; y<r.max.y; y++){
+ if(l > 1)
+ memmove(q, data, l-1);
+ q[l-1] ^= (data[l-1]^q[l-1]) & mr;
+ q += i->width*sizeof(ulong);
+ data += l;
+ }
+ return ndata;
+ }
+ for(y=r.min.y; y<r.max.y; y++){
+ *q ^= (*data^*q) & m;
+ if(l > 2)
+ memmove(q+1, data+1, l-2);
+ q[l-1] ^= (data[l-1]^q[l-1]) & mr;
+ q += i->width*sizeof(ulong);
+ data += l;
+ }
+ return ndata;
+}
--- /dev/null
+++ b/libmemdraw/mkfile
@@ -1,0 +1,33 @@
+<../mkconfig
+
+LIB=libmemdraw.a
+
+COMMONFILES=\
+ arc.$O\
+ cmap.$O\
+ cread.$O\
+ defont.$O\
+ ellipse.$O\
+ fillpoly.$O\
+ hwdraw.$O\
+ icossin.$O\
+ icossin2.$O\
+ iprint.$O\
+ line.$O\
+ openmemsubfont.$O\
+ poly.$O\
+ read.$O\
+ string.$O\
+ subfont.$O\
+ write.$O\
+
+<mkfile-$SYSTARG #sets $SYSFILES based on target OS architecture
+
+OFILES=$COMMONFILES $SYSFILES
+
+HFILES= $ROOT/include/draw.h\
+ $ROOT/include/memdraw.h\
+
+<$ROOT/mkfiles/mksyslib-$SHELLTYPE
+
+%-x11.$O: xmem.h
--- /dev/null
+++ b/libmemdraw/mkfile-FreeBSD
@@ -1,0 +1,4 @@
+#
+# Object files specific for Nt
+#
+<mkfile-Inferno
--- /dev/null
+++ b/libmemdraw/mkfile-Inferno
@@ -1,0 +1,9 @@
+#
+# Object files specific for Inferno/Plan9
+#
+SYSFILES=alloc.$O\
+ cload.$O\
+ draw.$O\
+ load.$O\
+ unload.$O\
+
--- /dev/null
+++ b/libmemdraw/mkfile-Irix
@@ -1,0 +1,4 @@
+#
+# Object files specific for Nt
+#
+<mkfile-Inferno
--- /dev/null
+++ b/libmemdraw/mkfile-Linux
@@ -1,0 +1,4 @@
+#
+# Object files specific for Nt
+#
+<mkfile-Inferno
--- /dev/null
+++ b/libmemdraw/mkfile-MacOSX
@@ -1,0 +1,4 @@
+#
+# Object files specific for Mac OS X
+#
+<mkfile-Inferno
--- /dev/null
+++ b/libmemdraw/mkfile-NetBSD
@@ -1,0 +1,4 @@
+#
+# Object files specific for Nt
+#
+<mkfile-Inferno
--- /dev/null
+++ b/libmemdraw/mkfile-Nt
@@ -1,0 +1,4 @@
+#
+# Object files specific for Nt
+#
+<mkfile-Inferno
--- /dev/null
+++ b/libmemdraw/mkfile-OpenBSD
@@ -1,0 +1,4 @@
+#
+# Object files specific for Nt
+#
+<mkfile-Inferno
--- /dev/null
+++ b/libmemdraw/mkfile-Plan9
@@ -1,0 +1,9 @@
+#
+# Object files specific for Inferno/Plan9
+#
+SYSFILES=alloc.$O\
+ cload.$O\
+ draw.$O\
+ load.$O\
+ unload.$O\
+
--- /dev/null
+++ b/libmemdraw/mkfile-Solaris
@@ -1,0 +1,4 @@
+#
+# Object files specific for Nt
+#
+<mkfile-Inferno
--- /dev/null
+++ b/libmemdraw/mkfile-os
@@ -1,0 +1,9 @@
+#
+# Object files specific for Inferno/Plan9
+#
+SYSFILES=alloc.$O\
+ cload.$O\
+ draw.$O\
+ load.$O\
+ unload.$O\
+
--- /dev/null
+++ b/libmemdraw/openmemsubfont.c
@@ -1,0 +1,51 @@
+#include "lib9.h"
+#include "draw.h"
+#include "memdraw.h"
+
+Memsubfont*
+openmemsubfont(char *name)
+{
+ Memsubfont *sf;
+ Memimage *i;
+ Fontchar *fc;
+ int fd, n;
+ char hdr[3*12+4+1];
+ uchar *p = nil;
+
+ fd = open(name, OREAD);
+ if(fd < 0)
+ return nil;
+ i = readmemimage(fd);
+ if(i == nil)
+ goto Err;
+ if(read(fd, hdr, 3*12) != 3*12){
+ werrstr("openmemsubfont: header read error: %r");
+ goto Err;
+ }
+ n = atoi(hdr);
+ p = malloc(6*(n+1));
+ if(p == nil)
+ goto Err;
+ if(read(fd, p, 6*(n+1)) != 6*(n+1)){
+ werrstr("openmemsubfont: fontchar read error: %r");
+ goto Err;
+ }
+ fc = malloc(sizeof(Fontchar)*(n+1));
+ if(fc == nil)
+ goto Err;
+ _unpackinfo(fc, p, n);
+ sf = allocmemsubfont(name, n, atoi(hdr+12), atoi(hdr+24), fc, i);
+ if(sf == nil){
+ free(fc);
+ goto Err;
+ }
+ free(p);
+ return sf;
+Err:
+ close(fd);
+ if (i != nil)
+ freememimage(i);
+ if (p != nil)
+ free(p);
+ return nil;
+}
--- /dev/null
+++ b/libmemdraw/poly.c
@@ -1,0 +1,23 @@
+#include "lib9.h"
+#include "draw.h"
+#include "memdraw.h"
+#include "memlayer.h"
+
+void
+mempoly(Memimage *dst, Point *vert, int nvert, int end0, int end1, int radius, Memimage *src, Point sp, int op)
+{
+ int i, e0, e1;
+ Point d;
+
+ if(nvert < 2)
+ return;
+ d = subpt(sp, vert[0]);
+ for(i=1; i<nvert; i++){
+ e0 = e1 = Enddisc;
+ if(i == 1)
+ e0 = end0;
+ if(i == nvert-1)
+ e1 = end1;
+ memline(dst, vert[i-1], vert[i], e0, e1, radius, src, addpt(d, vert[i-1]), op);
+ }
+}
--- /dev/null
+++ b/libmemdraw/read.c
@@ -1,0 +1,112 @@
+#include "lib9.h"
+#include "draw.h"
+#include "memdraw.h"
+
+#define CHUNK (32*1024)
+
+Memimage*
+readmemimage(int fd)
+{
+ char hdr[5*12+1];
+ int dy;
+ ulong chan;
+ uint l, n;
+ int m, j;
+ int new, miny, maxy;
+ Rectangle r;
+ uchar *tmp;
+ int ldepth, chunk;
+ Memimage *i;
+
+ if(readn(fd, hdr, 11) != 11){
+ werrstr("readimage: short header");
+ return nil;
+ }
+ if(memcmp(hdr, "compressed\n", 11) == 0)
+ return creadmemimage(fd);
+ if(readn(fd, hdr+11, 5*12-11) != 5*12-11){
+ werrstr("readimage: short header (2)");
+ return nil;
+ }
+
+ /*
+ * distinguish new channel descriptor from old ldepth.
+ * channel descriptors have letters as well as numbers,
+ * while ldepths are a single digit formatted as %-11d.
+ */
+ new = 0;
+ for(m=0; m<10; m++){
+ if(hdr[m] != ' '){
+ new = 1;
+ break;
+ }
+ }
+ if(hdr[11] != ' '){
+ werrstr("readimage: bad format");
+ return nil;
+ }
+ if(new){
+ hdr[11] = '\0';
+ if((chan = strtochan(hdr)) == 0){
+ werrstr("readimage: bad channel string %s", hdr);
+ return nil;
+ }
+ }else{
+ ldepth = ((int)hdr[10])-'0';
+ if(ldepth<0 || ldepth>3){
+ werrstr("readimage: bad ldepth %d", ldepth);
+ return nil;
+ }
+ chan = drawld2chan[ldepth];
+ }
+
+ r.min.x = atoi(hdr+1*12);
+ r.min.y = atoi(hdr+2*12);
+ r.max.x = atoi(hdr+3*12);
+ r.max.y = atoi(hdr+4*12);
+ if(r.min.x>r.max.x || r.min.y>r.max.y){
+ werrstr("readimage: bad rectangle");
+ return nil;
+ }
+
+ miny = r.min.y;
+ maxy = r.max.y;
+
+ l = bytesperline(r, chantodepth(chan));
+ i = allocmemimage(r, chan);
+ if(i == nil)
+ return nil;
+ chunk = CHUNK;
+ if(chunk < l)
+ chunk = l;
+ tmp = malloc(chunk);
+ if(tmp == nil)
+ goto Err;
+ while(maxy > miny){
+ dy = maxy - miny;
+ if(dy*l > chunk)
+ dy = chunk/l;
+ if(dy <= 0){
+ werrstr("readmemimage: image too wide for buffer");
+ goto Err;
+ }
+ n = dy*l;
+ m = readn(fd, tmp, n);
+ if(m != n){
+ werrstr("readmemimage: read count %d not %d: %r", m, n);
+ Err:
+ freememimage(i);
+ free(tmp);
+ return nil;
+ }
+ if(!new) /* an old image: must flip all the bits */
+ for(j=0; j<chunk; j++)
+ tmp[j] ^= 0xFF;
+
+ if(loadmemimage(i, Rect(r.min.x, miny, r.max.x, miny+dy), tmp, chunk) <= 0)
+ goto Err;
+ miny += dy;
+ }
+ free(tmp);
+ return i;
+}
--- /dev/null
+++ b/libmemdraw/string.c
@@ -1,0 +1,66 @@
+#include "lib9.h"
+#include "draw.h"
+#include "memdraw.h"
+#include "memlayer.h"
+
+Point
+memimagestring(Memimage *b, Point p, Memimage *color, Point cp, Memsubfont *f, char *cs)
+{
+ int w, width;
+ uchar *s;
+ Rune c;
+ Fontchar *i;
+
+ s = (uchar*)cs;
+ for(; c=*s; p.x+=width, cp.x+=width){
+ width = 0;
+ if(c < Runeself)
+ s++;
+ else{
+ w = chartorune(&c, (char*)s);
+ if(w == 0){
+ s++;
+ continue;
+ }
+ s += w;
+ }
+ if(c >= f->n)
+ continue;
+ i = f->info+c;
+ width = i->width;
+ memdraw(b, Rect(p.x+i->left, p.y+i->top, p.x+i->left+(i[1].x-i[0].x), p.y+i->bottom),
+ color, cp, f->bits, Pt(i->x, i->top), SoverD);
+ }
+ return p;
+}
+
+Point
+memsubfontwidth(Memsubfont *f, char *cs)
+{
+ Rune c;
+ Point p;
+ uchar *s;
+ Fontchar *i;
+ int w, width;
+
+ p = Pt(0, f->height);
+ s = (uchar*)cs;
+ for(; c=*s; p.x+=width){
+ width = 0;
+ if(c < Runeself)
+ s++;
+ else{
+ w = chartorune(&c, (char*)s);
+ if(w == 0){
+ s++;
+ continue;
+ }
+ s += w;
+ }
+ if(c >= f->n)
+ continue;
+ i = f->info+c;
+ width = i->width;
+ }
+ return p;
+}
--- /dev/null
+++ b/libmemdraw/subfont.c
@@ -1,0 +1,33 @@
+#include "lib9.h"
+#include "draw.h"
+#include "memdraw.h"
+
+Memsubfont*
+allocmemsubfont(char *name, int n, int height, int ascent, Fontchar *info, Memimage *i)
+{
+ Memsubfont *f;
+
+ f = malloc(sizeof(Memsubfont));
+ if(f == 0)
+ return 0;
+ f->n = n;
+ f->height = height;
+ f->ascent = ascent;
+ f->info = info;
+ f->bits = i;
+ if(name)
+ f->name = strdup(name);
+ else
+ f->name = 0;
+ return f;
+}
+
+void
+freememsubfont(Memsubfont *f)
+{
+ if(f == 0)
+ return;
+ free(f->info); /* note: f->info must have been malloc'ed! */
+ freememimage(f->bits);
+ free(f);
+}
--- /dev/null
+++ b/libmemdraw/unload.c
@@ -1,0 +1,24 @@
+#include "lib9.h"
+#include "draw.h"
+#include "memdraw.h"
+
+int
+unloadmemimage(Memimage *i, Rectangle r, uchar *data, int ndata)
+{
+ int y, l;
+ uchar *q;
+
+ if(!rectinrect(r, i->r))
+ return -1;
+ l = bytesperline(r, i->depth);
+ if(ndata < l*Dy(r))
+ return -1;
+ ndata = l*Dy(r);
+ q = byteaddr(i, r.min);
+ for(y=r.min.y; y<r.max.y; y++){
+ memmove(data, q, l);
+ q += i->width*sizeof(ulong);
+ data += l;
+ }
+ return ndata;
+}
--- /dev/null
+++ b/libmemdraw/write.c
@@ -1,0 +1,182 @@
+#include "lib9.h"
+#include "draw.h"
+#include "memdraw.h"
+
+#define CHUNK 8000
+
+#define HSHIFT 3 /* HSHIFT==5 runs slightly faster, but hash table is 64x bigger */
+#define NHASH (1<<(HSHIFT*NMATCH))
+#define HMASK (NHASH-1)
+#define hupdate(h, c) ((((h)<<HSHIFT)^(c))&HMASK)
+typedef struct Hlist Hlist;
+struct Hlist{
+ uchar *s;
+ Hlist *next, *prev;
+};
+
+int
+writememimage(int fd, Memimage *i)
+{
+ uchar *outbuf, *outp, *eout; /* encoded data, pointer, end */
+ uchar *loutp; /* start of encoded line */
+ Hlist *hash; /* heads of hash chains of past strings */
+ Hlist *chain, *hp; /* hash chain members, pointer */
+ Hlist *cp; /* next Hlist to fall out of window */
+ int h; /* hash value */
+ uchar *line, *eline; /* input line, end pointer */
+ uchar *data, *edata; /* input buffer, end pointer */
+ ulong n; /* length of input buffer */
+ ulong nb; /* # of bytes returned by unloadimage */
+ int bpl; /* input line length */
+ int offs, runlen; /* offset, length of consumed data */
+ uchar dumpbuf[NDUMP]; /* dump accumulator */
+ int ndump; /* length of dump accumulator */
+ int miny, dy; /* y values while unloading input */
+ int ncblock; /* size of compressed blocks */
+ Rectangle r;
+ uchar *p, *q, *s, *es, *t;
+ char hdr[11+5*12+1];
+ char cbuf[20];
+
+ r = i->r;
+ bpl = bytesperline(r, i->depth);
+ n = Dy(r)*bpl;
+ data = malloc(n);
+ ncblock = _compblocksize(r, i->depth);
+ outbuf = malloc(ncblock);
+ hash = malloc(NHASH*sizeof(Hlist));
+ chain = malloc(NMEM*sizeof(Hlist));
+ if(data == 0 || outbuf == 0 || hash == 0 || chain == 0){
+ ErrOut:
+ free(data);
+ free(outbuf);
+ free(hash);
+ free(chain);
+ return -1;
+ }
+ for(miny = r.min.y; miny != r.max.y; miny += dy){
+ dy = r.max.y-miny;
+ if(dy*bpl > CHUNK)
+ dy = CHUNK/bpl;
+ nb = unloadmemimage(i, Rect(r.min.x, miny, r.max.x, miny+dy),
+ data+(miny-r.min.y)*bpl, dy*bpl);
+ if(nb != dy*bpl)
+ goto ErrOut;
+ }
+ sprint(hdr, "compressed\n%11s %11d %11d %11d %11d ",
+ chantostr(cbuf, i->chan), r.min.x, r.min.y, r.max.x, r.max.y);
+ if(write(fd, hdr, 11+5*12) != 11+5*12)
+ goto ErrOut;
+ edata = data+n;
+ eout = outbuf+ncblock;
+ line = data;
+ r.max.y = r.min.y;
+ while(line != edata){
+ memset(hash, 0, NHASH*sizeof(Hlist));
+ memset(chain, 0, NMEM*sizeof(Hlist));
+ cp = chain;
+ h = 0;
+ outp = outbuf;
+ for(n = 0; n != NMATCH; n++)
+ h = hupdate(h, line[n]);
+ loutp = outbuf;
+ while(line != edata){
+ ndump = 0;
+ eline = line+bpl;
+ for(p = line; p != eline; ){
+ if(eline-p < NRUN)
+ es = eline;
+ else
+ es = p+NRUN;
+ q = 0;
+ runlen = 0;
+ for(hp = hash[h].next; hp; hp = hp->next){
+ s = p + runlen;
+ if(s >= es)
+ continue;
+ t = hp->s + runlen;
+ for(; s >= p; s--)
+ if(*s != *t--)
+ goto matchloop;
+ t += runlen+2;
+ s += runlen+2;
+ for(; s < es; s++)
+ if(*s != *t++)
+ break;
+ n = s-p;
+ if(n > runlen){
+ runlen = n;
+ q = hp->s;
+ if(n == NRUN)
+ break;
+ }
+ matchloop: ;
+ }
+ if(runlen < NMATCH){
+ if(ndump == NDUMP){
+ if(eout-outp < ndump+1)
+ goto Bfull;
+ *outp++ = ndump-1+128;
+ memmove(outp, dumpbuf, ndump);
+ outp += ndump;
+ ndump = 0;
+ }
+ dumpbuf[ndump++] = *p;
+ runlen = 1;
+ }
+ else{
+ if(ndump != 0){
+ if(eout-outp < ndump+1)
+ goto Bfull;
+ *outp++ = ndump-1+128;
+ memmove(outp, dumpbuf, ndump);
+ outp += ndump;
+ ndump = 0;
+ }
+ offs = p-q-1;
+ if(eout-outp < 2)
+ goto Bfull;
+ *outp++ = ((runlen-NMATCH)<<2) + (offs>>8);
+ *outp++ = offs&255;
+ }
+ for(q = p+runlen; p != q; p++){
+ if(cp->prev)
+ cp->prev->next = 0;
+ cp->next = hash[h].next;
+ cp->prev = &hash[h];
+ if(cp->next)
+ cp->next->prev = cp;
+ cp->prev->next = cp;
+ cp->s = p;
+ if(++cp == &chain[NMEM])
+ cp = chain;
+ if(edata-p > NMATCH)
+ h = hupdate(h, p[NMATCH]);
+ }
+ }
+ if(ndump != 0){
+ if(eout-outp < ndump+1)
+ goto Bfull;
+ *outp++ = ndump-1+128;
+ memmove(outp, dumpbuf, ndump);
+ outp += ndump;
+ }
+ line = eline;
+ loutp = outp;
+ r.max.y++;
+ }
+ Bfull:
+ if(loutp == outbuf)
+ goto ErrOut;
+ n = loutp-outbuf;
+ sprint(hdr, "%11d %11ld ", r.max.y, n);
+ write(fd, hdr, 2*12);
+ write(fd, outbuf, n);
+ r.min.y = r.max.y;
+ }
+ free(data);
+ free(outbuf);
+ free(hash);
+ free(chain);
+ return 0;
+}
--- /dev/null
+++ b/libmemlayer/NOTICE
@@ -1,0 +1,29 @@
+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-2007 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.
+
--- /dev/null
+++ b/libmemlayer/draw.c
@@ -1,0 +1,192 @@
+#include "lib9.h"
+#include "draw.h"
+#include "memdraw.h"
+#include "memlayer.h"
+#include "pool.h"
+
+struct Draw
+{
+ Point deltas;
+ Point deltam;
+ Memlayer *dstlayer;
+ Memimage *src;
+ Memimage *mask;
+ int op;
+};
+
+static
+void
+ldrawop(Memimage *dst, Rectangle screenr, Rectangle clipr, void *etc, int insave)
+{
+ struct Draw *d;
+ Point p0, p1;
+ Rectangle oclipr, srcr, r, mr;
+ int ok;
+
+ d = etc;
+ if(insave && d->dstlayer->save==nil)
+ return;
+
+ p0 = addpt(screenr.min, d->deltas);
+ p1 = addpt(screenr.min, d->deltam);
+
+ if(insave){
+ r = rectsubpt(screenr, d->dstlayer->delta);
+ clipr = rectsubpt(clipr, d->dstlayer->delta);
+ }else
+ r = screenr;
+
+ /* now in logical coordinates */
+
+ /* clipr may have narrowed what we should draw on, so clip if necessary */
+ if(!rectinrect(r, clipr)){
+ oclipr = dst->clipr;
+ dst->clipr = clipr;
+ ok = drawclip(dst, &r, d->src, &p0, d->mask, &p1, &srcr, &mr);
+ dst->clipr = oclipr;
+ if(!ok)
+ return;
+ }
+ memdraw(dst, r, d->src, p0, d->mask, p1, d->op);
+}
+
+void
+memdraw(Memimage *dst, Rectangle r, Memimage *src, Point p0, Memimage *mask, Point p1, int op)
+{
+ struct Draw d;
+ Rectangle srcr, tr, mr;
+ Memlayer *dl, *sl;
+
+ if(drawdebug)
+ iprint("memdraw %p %R %p %P %p %P\n", dst, r, src, p0, mask, p1);
+
+ if(mask == nil)
+ mask = memopaque;
+
+ if(mask->layer){
+if(drawdebug) iprint("mask->layer != nil\n");
+ return; /* too hard, at least for now */
+ }
+
+ Top:
+ if(dst->layer==nil && src->layer==nil){
+ memimagedraw(dst, r, src, p0, mask, p1, op);
+ return;
+ }
+
+ if(drawclip(dst, &r, src, &p0, mask, &p1, &srcr, &mr) == 0){
+if(drawdebug) iprint("drawclip dstcr %R srccr %R maskcr %R\n", dst->clipr, src->clipr, mask->clipr);
+ return;
+ }
+
+ /*
+ * Convert to screen coordinates.
+ */
+ dl = dst->layer;
+ if(dl != nil){
+ r.min.x += dl->delta.x;
+ r.min.y += dl->delta.y;
+ r.max.x += dl->delta.x;
+ r.max.y += dl->delta.y;
+ }
+ Clearlayer:
+ if(dl!=nil && dl->clear){
+ if(src == dst){
+ p0.x += dl->delta.x;
+ p0.y += dl->delta.y;
+ src = dl->screen->image;
+ }
+ dst = dl->screen->image;
+ goto Top;
+ }
+
+ sl = src->layer;
+ if(sl != nil){
+ p0.x += sl->delta.x;
+ p0.y += sl->delta.y;
+ srcr.min.x += sl->delta.x;
+ srcr.min.y += sl->delta.y;
+ srcr.max.x += sl->delta.x;
+ srcr.max.y += sl->delta.y;
+ }
+
+ /*
+ * Now everything is in screen coordinates.
+ * mask is an image. dst and src are images or obscured layers.
+ */
+
+ /*
+ * if dst and src are the same layer, just draw in save area and expose.
+ */
+ if(dl!=nil && dst==src){
+ if(dl->save == nil)
+ return; /* refresh function makes this case unworkable */
+ if(rectXrect(r, srcr)){
+ tr = r;
+ if(srcr.min.x < tr.min.x){
+ p1.x += tr.min.x - srcr.min.x;
+ tr.min.x = srcr.min.x;
+ }
+ if(srcr.min.y < tr.min.y){
+ p1.y += tr.min.x - srcr.min.x;
+ tr.min.y = srcr.min.y;
+ }
+ if(srcr.max.x > tr.max.x)
+ tr.max.x = srcr.max.x;
+ if(srcr.max.y > tr.max.y)
+ tr.max.y = srcr.max.y;
+ memlhide(dst, tr);
+ }else{
+ memlhide(dst, r);
+ memlhide(dst, srcr);
+ }
+ memdraw(dl->save, rectsubpt(r, dl->delta), dl->save,
+ subpt(srcr.min, src->layer->delta), mask, p1, op);
+ memlexpose(dst, r);
+ return;
+ }
+
+ if(sl){
+ if(sl->clear){
+ src = sl->screen->image;
+ if(dl != nil){
+ r.min.x -= dl->delta.x;
+ r.min.y -= dl->delta.y;
+ r.max.x -= dl->delta.x;
+ r.max.y -= dl->delta.y;
+ }
+ goto Top;
+ }
+ /* relatively rare case; use save area */
+ if(sl->save == nil)
+ return; /* refresh function makes this case unworkable */
+ memlhide(src, srcr);
+ /* convert back to logical coordinates */
+ p0.x -= sl->delta.x;
+ p0.y -= sl->delta.y;
+ srcr.min.x -= sl->delta.x;
+ srcr.min.y -= sl->delta.y;
+ srcr.max.x -= sl->delta.x;
+ srcr.max.y -= sl->delta.y;
+ src = src->layer->save;
+ }
+
+ /*
+ * src is now an image. dst may be an image or a clear layer
+ */
+ if(dst->layer==nil)
+ goto Top;
+ if(dst->layer->clear)
+ goto Clearlayer;
+
+ /*
+ * dst is an obscured layer
+ */
+ d.deltas = subpt(p0, r.min);
+ d.deltam = subpt(p1, r.min);
+ d.dstlayer = dl;
+ d.src = src;
+ d.mask = mask;
+ d.op = op;
+ _memlayerop(ldrawop, dst, r, r, &d);
+}
--- /dev/null
+++ b/libmemlayer/lalloc-x11.c
@@ -1,0 +1,185 @@
+#include "lib9.h"
+#include "image.h"
+#include "memimage.h"
+#include "memlayer.h"
+
+#include "../memimage/xmem.h"
+
+
+static ulong colorword;
+static Memdata colordata = {
+ nil,
+ &colorword
+};
+
+static Memimage paint =
+{
+ { 0, 0, 1, 1 },
+ { -1000000, -1000000, 10000000, 1000000 },
+ 0,
+ 1,
+ &colordata,
+ 0,
+ 1,
+ 0,
+};
+
+static Memimage *xpaint;
+
+static void
+setcolor(int val, int ldepth)
+{
+ int bpp;
+
+ paint.ldepth = ldepth;
+ bpp = 1<<ldepth;
+ val &= ~(0xFF>>bpp);
+ /* color is now in low part of word; replicate through pixel */
+ for(; bpp<32; bpp<<=1)
+ val |= val<<bpp;
+ colorword = val;
+}
+
+ulong*
+makememones(void)
+{
+ Xmem *xm;
+ extern Memimage screenimage;
+ extern void drawreset();
+
+ if(memones->X)
+ return;
+ drawreset();
+ /* set up screen pixmap */
+ xm = malloc(sizeof(Xmem));
+ if(xm == nil){
+ print("can't alloc for screen pixmap\n");
+ return;
+ }
+ if(screenimage.ldepth == 0)
+ xm->pmid0 = xscreenid;
+ else
+ xm->pmid0 = PMundef;
+ xm->pmid = xscreenid;
+ xm->wordp = &xm->word;
+ screenimage.X = xm;
+ screenimage.data->data = &xm->word;
+
+ memones = allocmemimage(paint.r, paint.ldepth);
+ memones->clipr = paint.clipr;
+ memones->repl = 1;
+ memfillcolor(memones, ~0);
+
+ return screenimage.data->data;
+}
+
+Memimage*
+memlalloc(Memscreen *s, Rectangle screenr, Refreshfn refreshfn, void *refreshptr, int val)
+{
+ Memimage *n;
+ Memlayer *l;
+ Xmem *xm, *sxm;
+
+ n = malloc(sizeof(Memimage));
+ if(n == nil)
+ return nil;
+
+ l = malloc(sizeof(Memlayer));
+ if(l == nil){
+ free(n);
+ return nil;
+ }
+
+ xm = malloc(sizeof(Xmem));
+ if(xm == nil){
+ free(l);
+ free(n);
+ return nil;
+ }
+
+ if(refreshfn) {
+ l->save = nil;
+ }
+ else{
+ l->save = allocmemimage(screenr, s->image->ldepth);
+ if(l->save == nil){
+ free(l);
+ free(n);
+ free(xm);
+ return nil;
+ }
+
+ /* allocmemimage doesn't initialize memory; this paints save area */
+ if(val >= 0)
+ memfillcolor(l->save, val);
+ }
+
+ n->r = screenr;
+ n->clipr = screenr;
+ n->ldepth = s->image->ldepth;
+ n->repl = 0;
+ n->data = s->image->data;
+ n->zero = s->image->zero;
+ n->width = s->image->width;
+ n->layer = l;
+ n->X = xm;
+
+ sxm = s->image->X;
+ xm->pmid0 = sxm->pmid0;
+ xm->pmid = sxm->pmid;
+ xm->flag = 0;
+ xm->wordp = sxm->wordp;
+
+ l->screen = s;
+ l->refreshfn = refreshfn;
+ l->screenr = screenr;
+ l->delta = Pt(0,0);
+
+ /* start with new window behind all existing ones */
+ l->front = s->rearmost;
+ l->rear = nil;
+ if(s->rearmost)
+ s->rearmost->layer->rear = n;
+ s->rearmost = n;
+ if(s->frontmost == nil)
+ s->frontmost = n;
+ l->clear = 0;
+
+ /* don't set it until we're done */
+ l->refreshptr = nil;
+
+ /* now pull new window to front */
+ memltofront(n);
+
+ /* now we're done */
+ l->refreshptr = refreshptr;
+
+ /*
+ * paint with requested color.
+ * previously exposed areas are already right
+ * if this window has backing store, but just painting
+ * the whole thing is simplest.
+ */
+
+ if(val >= 0){
+ setcolor(val, s->image->ldepth);
+ if(xpaint == nil){
+ xpaint = allocmemimage(paint.r, paint.ldepth);
+ if(xpaint == nil) {
+ if(l->save != nil)
+ freememimage(l->save);
+ free(l);
+ free(n);
+ free(xm);
+ return nil;
+ }
+ xpaint->clipr = paint.clipr;
+ xpaint->repl = 1;
+ }
+ ((Xmem*)(xpaint->X))->word = colorword;
+ ((Xmem*)(xpaint->X))->flag |= XXonepixel;
+ memfillcolor(xpaint, val);
+ memdraw(n, n->r, xpaint, n->r.min, memones, n->r.min, S);
+ }
+ return n;
+}
--- /dev/null
+++ b/libmemlayer/lalloc.c
@@ -1,0 +1,78 @@
+#include "lib9.h"
+#include "draw.h"
+#include "memdraw.h"
+#include "memlayer.h"
+
+Memimage*
+memlalloc(Memscreen *s, Rectangle screenr, Refreshfn refreshfn, void *refreshptr, ulong val)
+{
+ Memlayer *l;
+ Memimage *n;
+ static Memimage *paint;
+
+ if(paint == nil){
+ paint = allocmemimage(Rect(0,0,1,1), RGBA32);
+ if(paint == nil)
+ return nil;
+ paint->flags |= Frepl;
+ paint->clipr = Rect(-0x3FFFFFF, -0x3FFFFFF, 0x3FFFFFF, 0x3FFFFFF);
+ }
+
+ n = allocmemimaged(screenr, s->image->chan, s->image->data);
+ if(n == nil)
+ return nil;
+ l = malloc(sizeof(Memlayer));
+ if(l == nil){
+ free(n);
+ return nil;
+ }
+
+ l->screen = s;
+ if(refreshfn)
+ l->save = nil;
+ else{
+ l->save = allocmemimage(screenr, s->image->chan);
+ if(l->save == nil){
+ free(l);
+ free(n);
+ return nil;
+ }
+ /* allocmemimage doesn't initialize memory; this paints save area */
+ if(val != DNofill)
+ memfillcolor(l->save, val);
+ }
+ l->refreshfn = refreshfn;
+ l->refreshptr = nil; /* don't set it until we're done */
+ l->screenr = screenr;
+ l->delta = Pt(0,0);
+
+ n->data->ref++;
+ n->zero = s->image->zero;
+ n->width = s->image->width;
+ n->layer = l;
+
+ /* start with new window behind all existing ones */
+ l->front = s->rearmost;
+ l->rear = nil;
+ if(s->rearmost)
+ s->rearmost->layer->rear = n;
+ s->rearmost = n;
+ if(s->frontmost == nil)
+ s->frontmost = n;
+ l->clear = 0;
+
+ /* now pull new window to front */
+ _memltofrontfill(n, val != DNofill);
+ l->refreshptr = refreshptr;
+
+ /*
+ * paint with requested color; previously exposed areas are already right
+ * if this window has backing store, but just painting the whole thing is simplest.
+ */
+ if(val != DNofill){
+ memsetchan(paint, n->chan);
+ memfillcolor(paint, val);
+ memdraw(n, n->r, paint, n->r.min, nil, n->r.min, S);
+ }
+ return n;
+}
--- /dev/null
+++ b/libmemlayer/layerop.c
@@ -1,0 +1,111 @@
+#include "lib9.h"
+#include "draw.h"
+#include "memdraw.h"
+#include "memlayer.h"
+
+#define RECUR(a,b,c,d) _layerop(fn, i, Rect(a.x, b.y, c.x, d.y), clipr, etc, front->layer->rear);
+
+static void
+_layerop(
+ void (*fn)(Memimage*, Rectangle, Rectangle, void*, int),
+ Memimage *i,
+ Rectangle r,
+ Rectangle clipr,
+ void *etc,
+ Memimage *front)
+{
+ Rectangle fr;
+
+ Top:
+ if(front == i){
+ /* no one is in front of this part of window; use the screen */
+ fn(i->layer->screen->image, r, clipr, etc, 0);
+ return;
+ }
+ fr = front->layer->screenr;
+ if(rectXrect(r, fr) == 0){
+ /* r doesn't touch this window; continue on next rearmost */
+ /* assert(front && front->layer && front->layer->screen && front->layer->rear); */
+ front = front->layer->rear;
+ goto Top;
+ }
+ if(fr.max.y < r.max.y){
+ RECUR(r.min, fr.max, r.max, r.max);
+ r.max.y = fr.max.y;
+ }
+ if(r.min.y < fr.min.y){
+ RECUR(r.min, r.min, r.max, fr.min);
+ r.min.y = fr.min.y;
+ }
+ if(fr.max.x < r.max.x){
+ RECUR(fr.max, r.min, r.max, r.max);
+ r.max.x = fr.max.x;
+ }
+ if(r.min.x < fr.min.x){
+ RECUR(r.min, r.min, fr.min, r.max);
+ r.min.x = fr.min.x;
+ }
+ /* r is covered by front, so put in save area */
+ (*fn)(i->layer->save, r, clipr, etc, 1);
+}
+
+/*
+ * Assumes incoming rectangle has already been clipped to i's logical r and clipr
+ */
+void
+_memlayerop(
+ void (*fn)(Memimage*, Rectangle, Rectangle, void*, int),
+ Memimage *i,
+ Rectangle screenr, /* clipped to window boundaries */
+ Rectangle clipr, /* clipped also to clipping rectangles of hierarchy */
+ void *etc)
+{
+ Memlayer *l;
+ Rectangle r, scr;
+
+ l = i->layer;
+ if(!rectclip(&screenr, l->screenr))
+ return;
+ if(l->clear){
+ fn(l->screen->image, screenr, clipr, etc, 0);
+ return;
+ }
+ r = screenr;
+ scr = l->screen->image->clipr;
+
+ /*
+ * Do the piece on the screen
+ */
+ if(rectclip(&screenr, scr))
+ _layerop(fn, i, screenr, clipr, etc, l->screen->frontmost);
+ if(rectinrect(r, scr))
+ return;
+
+ /*
+ * Do the piece off the screen
+ */
+ if(!rectXrect(r, scr)){
+ /* completely offscreen; easy */
+ fn(l->save, r, clipr, etc, 1);
+ return;
+ }
+ if(r.min.y < scr.min.y){
+ /* above screen */
+ fn(l->save, Rect(r.min.x, r.min.y, r.max.x, scr.min.y), clipr, etc, 1);
+ r.min.y = scr.min.y;
+ }
+ if(r.max.y > scr.max.y){
+ /* below screen */
+ fn(l->save, Rect(r.min.x, scr.max.y, r.max.x, r.max.y), clipr, etc, 1);
+ r.max.y = scr.max.y;
+ }
+ if(r.min.x < scr.min.x){
+ /* left of screen */
+ fn(l->save, Rect(r.min.x, r.min.y, scr.min.x, r.max.y), clipr, etc, 1);
+ r.min.x = scr.min.x;
+ }
+ if(r.max.x > scr.max.x){
+ /* right of screen */
+ fn(l->save, Rect(scr.max.x, r.min.y, r.max.x, r.max.y), clipr, etc, 1);
+ }
+}
--- /dev/null
+++ b/libmemlayer/ldelete.c
@@ -1,0 +1,66 @@
+#include "lib9.h"
+#include "draw.h"
+#include "memdraw.h"
+#include "memlayer.h"
+
+void
+memldelete(Memimage *i)
+{
+ Memscreen *s;
+ Memlayer *l;
+
+ l = i->layer;
+ /* free backing store and disconnect refresh, to make pushback fast */
+ freememimage(l->save);
+ l->save = nil;
+ l->refreshptr = nil;
+ memltorear(i);
+
+ /* window is now the rearmost; clean up screen structures and deallocate */
+ s = i->layer->screen;
+ if(s->fill){
+ i->clipr = i->r;
+ memdraw(i, i->r, s->fill, i->r.min, nil, i->r.min, S);
+ }
+ if(l->front){
+ l->front->layer->rear = nil;
+ s->rearmost = l->front;
+ }else{
+ s->frontmost = nil;
+ s->rearmost = nil;
+ }
+ free(l);
+ freememimage(i);
+}
+
+/*
+ * Just free the data structures, don't do graphics
+ */
+void
+memlfree(Memimage *i)
+{
+ Memlayer *l;
+
+ l = i->layer;
+ freememimage(l->save);
+ free(l);
+ freememimage(i);
+}
+
+void
+_memlsetclear(Memscreen *s)
+{
+ Memimage *i, *j;
+ Memlayer *l;
+
+ for(i=s->rearmost; i; i=i->layer->front){
+ l = i->layer;
+ l->clear = rectinrect(l->screenr, l->screen->image->clipr);
+ if(l->clear)
+ for(j=l->front; j; j=j->layer->front)
+ if(rectXrect(l->screenr, j->layer->screenr)){
+ l->clear = 0;
+ break;
+ }
+ }
+}
--- /dev/null
+++ b/libmemlayer/lhide.c
@@ -1,0 +1,67 @@
+#include "lib9.h"
+#include "draw.h"
+#include "memdraw.h"
+#include "memlayer.h"
+#include "pool.h"
+
+/*
+ * Hide puts that portion of screenr now on the screen into the window's save area.
+ * Expose puts that portion of screenr now in the save area onto the screen.
+ *
+ * Hide and Expose both require that the layer structures in the screen
+ * match the geometry they are being asked to update, that is, they update the
+ * save area (hide) or screen (expose) based on what those structures tell them.
+ * This means they must be called at the correct time during window shuffles.
+ */
+
+static
+void
+lhideop(Memimage *src, Rectangle screenr, Rectangle clipr, void *etc, int insave)
+{
+ Rectangle r;
+ Memlayer *l;
+
+ USED(clipr.min.x);
+ USED(insave);
+ l = etc;
+ if(src != l->save){ /* do nothing if src is already in save area */
+ r = rectsubpt(screenr, l->delta);
+ memdraw(l->save, r, src, screenr.min, nil, screenr.min, S);
+ }
+}
+
+void
+memlhide(Memimage *i, Rectangle screenr)
+{
+ if(i->layer->save == nil)
+ return;
+ if(rectclip(&screenr, i->layer->screen->image->r) == 0)
+ return;
+ _memlayerop(lhideop, i, screenr, screenr, i->layer);
+}
+
+static
+void
+lexposeop(Memimage *dst, Rectangle screenr, Rectangle clipr, void *etc, int insave)
+{
+ Memlayer *l;
+ Rectangle r;
+
+ USED(clipr.min.x);
+ if(insave) /* if dst is save area, don't bother */
+ return;
+ l = etc;
+ r = rectsubpt(screenr, l->delta);
+ if(l->save)
+ memdraw(dst, screenr, l->save, r.min, nil, r.min, S);
+ else
+ l->refreshfn(dst, r, l->refreshptr);
+}
+
+void
+memlexpose(Memimage *i, Rectangle screenr)
+{
+ if(rectclip(&screenr, i->layer->screen->image->r) == 0)
+ return;
+ _memlayerop(lexposeop, i, screenr, screenr, i->layer);
+}
--- /dev/null
+++ b/libmemlayer/line.c
@@ -1,0 +1,121 @@
+#include "lib9.h"
+#include "draw.h"
+#include "memdraw.h"
+#include "memlayer.h"
+
+struct Lline
+{
+ Point p0;
+ Point p1;
+ Point delta;
+ int end0;
+ int end1;
+ int radius;
+ Point sp;
+ Memlayer *dstlayer;
+ Memimage *src;
+ int op;
+};
+
+static void llineop(Memimage*, Rectangle, Rectangle, void*, int);
+
+static
+void
+_memline(Memimage *dst, Point p0, Point p1, int end0, int end1, int radius, Memimage *src, Point sp, Rectangle clipr, int op)
+{
+ Rectangle r;
+ struct Lline ll;
+ Point d;
+ int srcclipped;
+ Memlayer *dl;
+
+ if(radius < 0)
+ return;
+ if(src->layer) /* can't draw line with layered source */
+ return;
+ srcclipped = 0;
+
+ Top:
+ dl = dst->layer;
+ if(dl == nil){
+ _memimageline(dst, p0, p1, end0, end1, radius, src, sp, clipr, op);
+ return;
+ }
+ if(!srcclipped){
+ d = subpt(sp, p0);
+ if(rectclip(&clipr, rectsubpt(src->clipr, d)) == 0)
+ return;
+ if((src->flags&Frepl)==0 && rectclip(&clipr, rectsubpt(src->r, d))==0)
+ return;
+ srcclipped = 1;
+ }
+
+ /* dst is known to be a layer */
+ p0.x += dl->delta.x;
+ p0.y += dl->delta.y;
+ p1.x += dl->delta.x;
+ p1.y += dl->delta.y;
+ clipr.min.x += dl->delta.x;
+ clipr.min.y += dl->delta.y;
+ clipr.max.x += dl->delta.x;
+ clipr.max.y += dl->delta.y;
+ if(dl->clear){
+ dst = dst->layer->screen->image;
+ goto Top;
+ }
+
+ /* XXX */
+ /* this is not the correct set of tests */
+// if(log2[dst->depth] != log2[src->depth] || log2[dst->depth]!=3)
+// return;
+
+ /* can't use sutherland-cohen clipping because lines are wide */
+ r = memlinebbox(p0, p1, end0, end1, radius);
+ /*
+ * r is now a bounding box for the line;
+ * use it as a clipping rectangle for subdivision
+ */
+ if(rectclip(&r, clipr) == 0)
+ return;
+ ll.p0 = p0;
+ ll.p1 = p1;
+ ll.end0 = end0;
+ ll.end1 = end1;
+ ll.sp = sp;
+ ll.dstlayer = dst->layer;
+ ll.src = src;
+ ll.radius = radius;
+ ll.delta = dl->delta;
+ ll.op = op;
+ _memlayerop(llineop, dst, r, r, &ll);
+}
+
+static
+void
+llineop(Memimage *dst, Rectangle screenr, Rectangle clipr, void *etc, int insave)
+{
+ struct Lline *ll;
+ Point p0, p1;
+
+ USED(screenr.min.x);
+ ll = etc;
+ if(insave && ll->dstlayer->save==nil)
+ return;
+ if(!rectclip(&clipr, screenr))
+ return;
+ if(insave){
+ p0 = subpt(ll->p0, ll->delta);
+ p1 = subpt(ll->p1, ll->delta);
+ clipr = rectsubpt(clipr, ll->delta);
+ }else{
+ p0 = ll->p0;
+ p1 = ll->p1;
+ }
+ _memline(dst, p0, p1, ll->end0, ll->end1, ll->radius, ll->src, ll->sp, clipr, ll->op);
+}
+
+void
+memline(Memimage *dst, Point p0, Point p1, int end0, int end1, int radius, Memimage *src, Point sp, int op)
+{
+ _memline(dst, p0, p1, end0, end1, radius, src, sp, dst->clipr, op);
+}
--- /dev/null
+++ b/libmemlayer/load.c
@@ -1,0 +1,54 @@
+#include "lib9.h"
+#include "draw.h"
+#include "memdraw.h"
+#include "memlayer.h"
+
+int
+memload(Memimage *dst, Rectangle r, uchar *data, int n, int iscompressed)
+{
+ int (*loadfn)(Memimage*, Rectangle, uchar*, int);
+ Memimage *tmp;
+ Memlayer *dl;
+ Rectangle lr;
+ int dx;
+
+ loadfn = loadmemimage;
+ if(iscompressed)
+ loadfn = cloadmemimage;
+
+ Top:
+ dl = dst->layer;
+ if(dl == nil)
+ return loadfn(dst, r, data, n);
+
+ /*
+ * Convert to screen coordinates.
+ */
+ lr = r;
+ r.min.x += dl->delta.x;
+ r.min.y += dl->delta.y;
+ r.max.x += dl->delta.x;
+ r.max.y += dl->delta.y;
+ dx = dl->delta.x&(7/dst->depth);
+ if(dl->clear && dx==0){
+ dst = dl->screen->image;
+ goto Top;
+ }
+
+ /*
+ * dst is an obscured layer or data is unaligned
+ */
+ if(dl->save && dx==0){
+ n = loadfn(dl->save, lr, data, n);
+ if(n > 0)
+ memlexpose(dst, r);
+ return n;
+ }
+ tmp = allocmemimage(lr, dst->chan);
+ if(tmp == nil)
+ return -1;
+ n = loadfn(tmp, lr, data, n);
+ memdraw(dst, lr, tmp, lr.min, nil, lr.min, S);
+ freememimage(tmp);
+ return n;
+}
--- /dev/null
+++ b/libmemlayer/lorigin.c
@@ -1,0 +1,106 @@
+#include "lib9.h"
+#include "draw.h"
+#include "memdraw.h"
+#include "memlayer.h"
+
+/*
+ * Place i so i->r.min = log, i->layer->screenr.min == scr.
+*/
+int
+memlorigin(Memimage *i, Point log, Point scr)
+{
+ Memlayer *l;
+ Memscreen *s;
+ Memimage *t, *shad, *nsave;
+ Rectangle x, newr, oldr;
+ Point delta;
+ int overlap, eqlog, eqscr, wasclear;
+
+ l = i->layer;
+ s = l->screen;
+ oldr = l->screenr;
+ newr = Rect(scr.x, scr.y, scr.x+Dx(oldr), scr.y+Dy(oldr));
+ eqscr = eqpt(scr, oldr.min);
+ eqlog = eqpt(log, i->r.min);
+ if(eqscr && eqlog)
+ return 0;
+ nsave = nil;
+ if(eqlog==0 && l->save!=nil){
+ nsave = allocmemimage(Rect(log.x, log.y, log.x+Dx(oldr), log.y+Dy(oldr)), i->chan);
+ if(nsave == nil)
+ return -1;
+ }
+
+ /*
+ * Bring it to front and move logical coordinate system.
+ */
+ memltofront(i);
+ wasclear = l->clear;
+ if(nsave){
+ if(!wasclear)
+ memimagedraw(nsave, nsave->r, l->save, l->save->r.min, nil, Pt(0,0), S);
+ freememimage(l->save);
+ l->save = nsave;
+ }
+ delta = subpt(log, i->r.min);
+ i->r = rectaddpt(i->r, delta);
+ i->clipr = rectaddpt(i->clipr, delta);
+ l->delta = subpt(l->screenr.min, i->r.min);
+ if(eqscr)
+ return 0;
+
+ /*
+ * To clean up old position, make a shadow window there, don't paint it,
+ * push it behind this one, and (later) delete it. Because the refresh function
+ * for this fake window is a no-op, this will cause no graphics action except
+ * to restore the background and expose the windows previously hidden.
+ */
+ shad = memlalloc(s, oldr, memlnorefresh, nil, DNofill);
+ if(shad == nil)
+ return -1;
+ s->frontmost = i;
+ if(s->rearmost == i)
+ s->rearmost = shad;
+ else
+ l->rear->layer->front = shad;
+ shad->layer->front = i;
+ shad->layer->rear = l->rear;
+ l->rear = shad;
+ l->front = nil;
+ shad->layer->clear = 0;
+
+ /*
+ * Shadow is now holding down the fort at the old position.
+ * Move the window and hide things obscured by new position.
+ */
+ for(t=l->rear->layer->rear; t!=nil; t=t->layer->rear){
+ x = newr;
+ overlap = rectclip(&x, t->layer->screenr);
+ if(overlap){
+ memlhide(t, x);
+ t->layer->clear = 0;
+ }
+ }
+ l->screenr = newr;
+ l->delta = subpt(scr, i->r.min);
+ l->clear = rectinrect(newr, l->screen->image->clipr);
+
+ /*
+ * Everything's covered. Copy to new position and delete shadow window.
+ */
+ if(wasclear)
+ memdraw(s->image, newr, s->image, oldr.min, nil, Pt(0,0), S);
+ else
+ memlexpose(i, newr);
+ memldelete(shad);
+
+ return 1;
+}
+
+void
+memlnorefresh(Memimage *l, Rectangle r, void *v)
+{
+ USED(l);
+ USED(r.min.x);
+ USED(v);
+}
--- /dev/null
+++ b/libmemlayer/lsetrefresh.c
@@ -1,0 +1,34 @@
+#include "lib9.h"
+#include "draw.h"
+#include "memdraw.h"
+#include "memlayer.h"
+
+int
+memlsetrefresh(Memimage *i, Refreshfn fn, void *ptr)
+{
+ Memlayer *l;
+
+ l = i->layer;
+ if(l->refreshfn!=nil && fn!=nil){ /* just change functions */
+ l->refreshfn = fn;
+ l->refreshptr = ptr;
+ return 1;
+ }
+
+ if(l->refreshfn == nil){ /* is using backup image; just free it */
+ freememimage(l->save);
+ l->save = nil;
+ l->refreshfn = fn;
+ l->refreshptr = ptr;
+ return 1;
+ }
+
+ l->save = allocmemimage(i->r, i->chan);
+ if(l->save == nil)
+ return 0;
+ /* easiest way is just to update the entire save area */
+ l->refreshfn(i, i->r, l->refreshptr);
+ l->refreshfn = nil;
+ l->refreshptr = nil;
+ return 1;
+}
--- /dev/null
+++ b/libmemlayer/ltofront.c
@@ -1,0 +1,80 @@
+#include "lib9.h"
+#include "draw.h"
+#include "memdraw.h"
+#include "memlayer.h"
+#include "pool.h"
+
+/*
+ * Pull i towards top of screen, just behind front
+*/
+static
+void
+_memltofront(Memimage *i, Memimage *front, int fill)
+{
+ Memlayer *l;
+ Memscreen *s;
+ Memimage *f, *ff, *rr;
+ Rectangle x;
+ int overlap;
+
+ l = i->layer;
+ s = l->screen;
+ while(l->front != front){
+ f = l->front;
+ x = l->screenr;
+ overlap = rectclip(&x, f->layer->screenr);
+ if(overlap){
+ memlhide(f, x);
+ f->layer->clear = 0;
+ }
+ /* swap l and f in screen's list */
+ ff = f->layer->front;
+ rr = l->rear;
+ if(ff == nil)
+ s->frontmost = i;
+ else
+ ff->layer->rear = i;
+ if(rr == nil)
+ s->rearmost = f;
+ else
+ rr->layer->front = f;
+ l->front = ff;
+ l->rear = f;
+ f->layer->front = i;
+ f->layer->rear = rr;
+ if(overlap && fill)
+ memlexpose(i, x);
+ }
+}
+
+void
+_memltofrontfill(Memimage *i, int fill)
+{
+ _memltofront(i, nil, fill);
+ _memlsetclear(i->layer->screen);
+}
+
+void
+memltofront(Memimage *i)
+{
+ _memltofront(i, nil, 1);
+ _memlsetclear(i->layer->screen);
+}
+
+void
+memltofrontn(Memimage **ip, int n)
+{
+ Memimage *i, *front;
+ Memscreen *s;
+
+ if(n == 0)
+ return;
+ front = nil;
+ while(--n >= 0){
+ i = *ip++;
+ _memltofront(i, front, 1);
+ front = i;
+ }
+ s = front->layer->screen;
+ _memlsetclear(s);
+}
--- /dev/null
+++ b/libmemlayer/ltorear.c
@@ -1,0 +1,68 @@
+#include "lib9.h"
+#include "draw.h"
+#include "memdraw.h"
+#include "memlayer.h"
+
+void
+_memltorear(Memimage *i, Memimage *rear)
+{
+ Memlayer *l;
+ Memscreen *s;
+ Memimage *f, *r, *rr;
+ Rectangle x;
+ int overlap;
+
+ l = i->layer;
+ s = l->screen;
+ while(l->rear != rear){
+ r = l->rear;
+ x = l->screenr;
+ overlap = rectclip(&x, r->layer->screenr);
+ if(overlap){
+ memlhide(i, x);
+ l->clear = 0;
+ }
+ /* swap l and r in screen's list */
+ rr = r->layer->rear;
+ f = l->front;
+ if(rr == nil)
+ s->rearmost = i;
+ else
+ rr->layer->front = i;
+ if(f == nil)
+ s->frontmost = r;
+ else
+ f->layer->rear = r;
+ l->rear = rr;
+ l->front = r;
+ r->layer->rear = i;
+ r->layer->front = f;
+ if(overlap)
+ memlexpose(r, x);
+ }
+}
+
+void
+memltorear(Memimage *i)
+{
+ _memltorear(i, nil);
+ _memlsetclear(i->layer->screen);
+}
+
+void
+memltorearn(Memimage **ip, int n)
+{
+ Memimage *i, *rear;
+ Memscreen *s;
+
+ if(n == 0)
+ return;
+ rear = nil;
+ while(--n >= 0){
+ i = *ip++;
+ _memltorear(i, rear);
+ rear = i;
+ }
+ s = rear->layer->screen;
+ _memlsetclear(s);
+}
--- /dev/null
+++ b/libmemlayer/mkfile
@@ -1,0 +1,26 @@
+<../mkconfig
+
+LIB=libmemlayer.a
+
+COMMONFILES=\
+ draw.$O\
+ layerop.$O\
+ ldelete.$O\
+ lhide.$O\
+ line.$O\
+ load.$O\
+ lorigin.$O\
+ lsetrefresh.$O\
+ ltofront.$O\
+ ltorear.$O\
+ unload.$O\
+
+<mkfile-$SYSTARG #sets $SYSFILES based on OS architecture
+
+OFILES=$COMMONFILES $SYSFILES
+
+HFILES= $ROOT/include/draw.h\
+ $ROOT/include/memdraw.h\
+ $ROOT/include/memlayer.h
+
+<$ROOT/mkfiles/mksyslib-$SHELLTYPE
--- /dev/null
+++ b/libmemlayer/mkfile-FreeBSD
@@ -1,0 +1,4 @@
+#
+# System dependent objects for Posix model systems
+#
+SYSFILES=lalloc.$O
--- /dev/null
+++ b/libmemlayer/mkfile-Hp
@@ -1,0 +1,4 @@
+#
+# System dependent objects for Posix model systems
+#
+SYSFILES=lalloc.$O
--- /dev/null
+++ b/libmemlayer/mkfile-Inferno
@@ -1,0 +1,4 @@
+#
+# System dependent objects for Inferno model systems
+#
+SYSFILES=lalloc.$O
--- /dev/null
+++ b/libmemlayer/mkfile-Irix
@@ -1,0 +1,4 @@
+#
+# System dependent objects for Posix model systems
+#
+SYSFILES=lalloc.$O
--- /dev/null
+++ b/libmemlayer/mkfile-Linux
@@ -1,0 +1,4 @@
+#
+# System dependent objects for Posix model systems
+#
+SYSFILES=lalloc.$O
--- /dev/null
+++ b/libmemlayer/mkfile-MacOSX
@@ -1,0 +1,4 @@
+#
+# System dependent objects for Posix model systems
+#
+SYSFILES=lalloc.$O
--- /dev/null
+++ b/libmemlayer/mkfile-NetBSD
@@ -1,0 +1,4 @@
+#
+# System dependent objects for Posix model systems
+#
+SYSFILES=lalloc.$O
--- /dev/null
+++ b/libmemlayer/mkfile-Nt
@@ -1,0 +1,4 @@
+#
+# System dependent objects for Nt model systems
+#
+SYSFILES=lalloc.$O
--- /dev/null
+++ b/libmemlayer/mkfile-OpenBSD
@@ -1,0 +1,4 @@
+#
+# System dependent objects for Posix model systems
+#
+SYSFILES=lalloc.$O
--- /dev/null
+++ b/libmemlayer/mkfile-Plan9
@@ -1,0 +1,4 @@
+#
+# System dependent objects for Inferno model systems
+#
+SYSFILES=lalloc.$O
--- /dev/null
+++ b/libmemlayer/mkfile-Posix
@@ -1,0 +1,4 @@
+#
+# System dependent objects for Inferno model systems
+#
+SYSFILES=lalloc.$O
--- /dev/null
+++ b/libmemlayer/mkfile-Solaris
@@ -1,0 +1,4 @@
+#
+# System dependent objects for Inferno model systems
+#
+SYSFILES=lalloc.$O
--- /dev/null
+++ b/libmemlayer/mkfile-Unixware
@@ -1,0 +1,4 @@
+#
+# System dependent objects for Posix model systems
+#
+SYSFILES=lalloc.$O
--- /dev/null
+++ b/libmemlayer/mkfile-os
@@ -1,0 +1,4 @@
+#
+# System dependent objects for Inferno model systems
+#
+SYSFILES=lalloc.$O
--- /dev/null
+++ b/libmemlayer/unload.c
@@ -1,0 +1,51 @@
+#include "lib9.h"
+#include "draw.h"
+#include "memdraw.h"
+#include "memlayer.h"
+
+int
+memunload(Memimage *src, Rectangle r, uchar *data, int n)
+{
+ Memimage *tmp;
+ Memlayer *dl;
+ Rectangle lr;
+ int dx;
+
+ Top:
+ dl = src->layer;
+ if(dl == nil)
+ return unloadmemimage(src, r, data, n);
+
+ /*
+ * Convert to screen coordinates.
+ */
+ lr = r;
+ r.min.x += dl->delta.x;
+ r.min.y += dl->delta.y;
+ r.max.x += dl->delta.x;
+ r.max.y += dl->delta.y;
+ dx = dl->delta.x&(7/src->depth);
+ if(dl->clear && dx==0){
+ src = dl->screen->image;
+ goto Top;
+ }
+
+ /*
+ * src is an obscured layer or data is unaligned
+ */
+ if(dl->save && dx==0){
+ if(dl->refreshfn != nil)
+ return -1; /* can't unload window if it's not Refbackup */
+ if(n > 0)
+ memlhide(src, r);
+ n = unloadmemimage(dl->save, lr, data, n);
+ return n;
+ }
+ tmp = allocmemimage(lr, src->chan);
+ if(tmp == nil)
+ return -1;
+ memdraw(tmp, lr, src, lr.min, nil, lr.min, S);
+ n = unloadmemimage(tmp, lr, data, n);
+ freememimage(tmp);
+ return n;
+}
--- /dev/null
+++ b/libmp/Inferno-386/mkfile
@@ -1,0 +1,22 @@
+objtype=386
+OBJTYPE=$objtype
+<../../mkconfig
+OBJDIR=Inferno/$OBJTYPE
+
+LIB=libmp.a
+SFILES=\
+ mpvecadd.s\
+ mpvecdigmuladd.s\
+ mpvecdigmulsub.s\
+ mpvecsub.s\
+ mpdigdiv.s\
+
+HFILES=$ROOT/Inferno/$OBJTYPE/include/u.h $ROOT/include/mp.h ../port/dat.h
+
+OFILES=${SFILES:%.s=%.$O}
+
+UPDATE=mkfile\
+ $HFILES\
+ $SFILES\
+
+<$ROOT/mkfiles/mksyslib-$SHELLTYPE
--- /dev/null
+++ b/libmp/Inferno-386/mpdigdiv.s
@@ -1,0 +1,21 @@
+TEXT mpdigdiv(SB),$0
+
+ MOVL dividend+0(FP),BX
+ MOVL 0(BX),AX
+ MOVL 4(BX),DX
+ MOVL divisor+4(FP),BX
+ MOVL quotient+8(FP),BP
+ XORL CX,CX
+ CMPL DX,BX /* dividend >= 2^32 * divisor */
+ JHS _divovfl
+ CMPL BX,CX /* divisor == 0 */
+ JE _divovfl
+ DIVL BX /* AX = DX:AX/BX */
+ MOVL AX,0(BP)
+ RET
+
+ /* return all 1's */
+_divovfl:
+ NOTL CX
+ MOVL CX,0(BP)
+ RET
--- /dev/null
+++ b/libmp/Inferno-386/mpvecadd.s
@@ -1,0 +1,53 @@
+/*
+ * mpvecadd(mpdigit *a, int alen, mpdigit *b, int blen, mpdigit *sum)
+ *
+ * sum[0:alen] = a[0:alen-1] + b[0:blen-1]
+ *
+ * prereq: alen >= blen, sum has room for alen+1 digits
+ */
+TEXT mpvecadd(SB),$0
+
+ MOVL alen+4(FP),DX
+ MOVL blen+12(FP),CX
+ MOVL a+0(FP),SI
+ MOVL b+8(FP),BX
+ SUBL CX,DX
+ MOVL sum+16(FP),DI
+ XORL BP,BP /* this also sets carry to 0 */
+
+ /* skip addition if b is zero */
+ TESTL CX,CX
+ JZ _add1
+
+ /* sum[0:blen-1],carry = a[0:blen-1] + b[0:blen-1] */
+_addloop1:
+ MOVL (SI)(BP*4), AX
+ ADCL (BX)(BP*4), AX
+ MOVL AX,(DI)(BP*4)
+ INCL BP
+ LOOP _addloop1
+
+_add1:
+ /* jump if alen > blen */
+ INCL DX
+ MOVL DX,CX
+ LOOP _addloop2
+
+ /* sum[alen] = carry */
+_addend:
+ JC _addcarry
+ MOVL $0,(DI)(BP*4)
+ RET
+_addcarry:
+ MOVL $1,(DI)(BP*4)
+ RET
+
+ /* sum[blen:alen-1],carry = a[blen:alen-1] + 0 */
+_addloop2:
+ MOVL (SI)(BP*4),AX
+ ADCL $0,AX
+ MOVL AX,(DI)(BP*4)
+ INCL BP
+ LOOP _addloop2
+ JMP _addend
+
--- /dev/null
+++ b/libmp/Inferno-386/mpvecdigmuladd.s
@@ -1,0 +1,52 @@
+/*
+ * mpvecdigmul(mpdigit *b, int n, mpdigit m, mpdigit *p)
+ *
+ * p += b*m
+ *
+ * each step look like:
+ * hi,lo = m*b[i]
+ * lo += oldhi + carry
+ * hi += carry
+ * p[i] += lo
+ * oldhi = hi
+ *
+ * the registers are:
+ * hi = DX - constrained by hardware
+ * lo = AX - constrained by hardware
+ * b+n = SI - can't be BP
+ * p+n = DI - can't be BP
+ * i-n = BP
+ * m = BX
+ * oldhi = CX
+ *
+ */
+TEXT mpvecdigmuladd(SB),$0
+
+ MOVL b+0(FP),SI
+ MOVL n+4(FP),CX
+ MOVL m+8(FP),BX
+ MOVL p+12(FP),DI
+ MOVL CX,BP
+ NEGL BP /* BP = -n */
+ SHLL $2,CX
+ ADDL CX,SI /* SI = b + n */
+ ADDL CX,DI /* DI = p + n */
+ XORL CX,CX
+_muladdloop:
+ MOVL (SI)(BP*4),AX /* lo = b[i] */
+ MULL BX /* hi, lo = b[i] * m */
+ ADDL CX,AX /* lo += oldhi */
+ JCC _muladdnocarry1
+ INCL DX /* hi += carry */
+_muladdnocarry1:
+ ADDL AX,(DI)(BP*4) /* p[i] += lo */
+ JCC _muladdnocarry2
+ INCL DX /* hi += carry */
+_muladdnocarry2:
+ MOVL DX,CX /* oldhi = hi */
+ INCL BP /* i++ */
+ JNZ _muladdloop
+ XORL AX,AX
+ ADDL CX,(DI)(BP*4) /* p[n] + oldhi */
+ ADCL AX,AX /* return carry out of p[n] */
+ RET
--- /dev/null
+++ b/libmp/Inferno-386/mpvecdigmulsub.s
@@ -1,0 +1,53 @@
+/*
+ * mpvecdigmulsub(mpdigit *b, int n, mpdigit m, mpdigit *p)
+ *
+ * p -= b*m
+ *
+ * each step look like:
+ * hi,lo = m*b[i]
+ * lo += oldhi + carry
+ * hi += carry
+ * p[i] += lo
+ * oldhi = hi
+ *
+ * the registers are:
+ * hi = DX - constrained by hardware
+ * lo = AX - constrained by hardware
+ * b = SI - can't be BP
+ * p = DI - can't be BP
+ * i = BP
+ * n = CX - constrained by LOOP instr
+ * m = BX
+ * oldhi = EX
+ *
+ */
+TEXT mpvecdigmulsub(SB),$0
+
+ MOVL b+0(FP),SI
+ MOVL n+4(FP),CX
+ MOVL m+8(FP),BX
+ MOVL p+12(FP),DI
+ XORL BP,BP
+ PUSHL BP
+_mulsubloop:
+ MOVL (SI)(BP*4),AX /* lo = b[i] */
+ MULL BX /* hi, lo = b[i] * m */
+ ADDL 0(SP),AX /* lo += oldhi */
+ JCC _mulsubnocarry1
+ INCL DX /* hi += carry */
+_mulsubnocarry1:
+ SUBL AX,(DI)(BP*4)
+ JCC _mulsubnocarry2
+ INCL DX /* hi += carry */
+_mulsubnocarry2:
+ MOVL DX,0(SP)
+ INCL BP
+ LOOP _mulsubloop
+ POPL AX
+ SUBL AX,(DI)(BP*4)
+ JCC _mulsubnocarry3
+ MOVL $-1,AX
+ RET
+_mulsubnocarry3:
+ MOVL $1,AX
+ RET
--- /dev/null
+++ b/libmp/Inferno-386/mpvecsub.s
@@ -1,0 +1,44 @@
+/*
+ * mpvecsub(mpdigit *a, int alen, mpdigit *b, int blen, mpdigit *diff)
+ *
+ * diff[0:alen-1] = a[0:alen-1] - b[0:blen-1]
+ *
+ * prereq: alen >= blen, diff has room for alen digits
+ */
+TEXT mpvecsub(SB),$0
+
+ MOVL a+0(FP),SI
+ MOVL b+8(FP),BX
+ MOVL alen+4(FP),DX
+ MOVL blen+12(FP),CX
+ MOVL diff+16(FP),DI
+ SUBL CX,DX
+ XORL BP,BP /* this also sets carry to 0 */
+
+ /* skip subraction if b is zero */
+ TESTL CX,CX
+ JZ _sub1
+
+ /* diff[0:blen-1],borrow = a[0:blen-1] - b[0:blen-1] */
+_subloop1:
+ MOVL (SI)(BP*4),AX
+ SBBL (BX)(BP*4),AX
+ MOVL AX,(DI)(BP*4)
+ INCL BP
+ LOOP _subloop1
+
+_sub1:
+ INCL DX
+ MOVL DX,CX
+ LOOP _subloop2
+ RET
+
+ /* diff[blen:alen-1] = a[blen:alen-1] - 0 */
+_subloop2:
+ MOVL (SI)(BP*4),AX
+ SBBL $0,AX
+ MOVL AX,(DI)(BP*4)
+ INCL BP
+ LOOP _subloop2
+ RET
+
--- /dev/null
+++ b/libmp/Inferno-amd64/mkfile
@@ -1,0 +1,21 @@
+objtype=amd64
+OBJTYPE=$objtype
+<../../mkconfig
+
+LIB=libmp.a
+SFILES=\
+ mpvecadd.s\
+ mpvecdigmuladd.s\
+ mpvecdigmulsub.s\
+ mpvecsub.s\
+ mpdigdiv.s\
+
+HFILES=$ROOT/Inferno/$OBJTYPE/include/u.h $ROOT/include/mp.h ../port/dat.h
+
+OFILES=${SFILES:%.s=%.$O}
+
+UPDATE=mkfile\
+ $HFILES\
+ $SFILES\
+
+<$ROOT/mkfiles/mksyslib-$SHELLTYPE
--- /dev/null
+++ b/libmp/Inferno-amd64/mpdigdiv.s
@@ -1,0 +1,21 @@
+TEXT mpdigdiv(SB),$0
+
+/* MOVL dividend+0(FP),BX */
+ MOVL 0(RARG),AX
+ MOVL 4(RARG),DX
+ MOVL divisor+8(FP),BX
+ MOVQ quotient+16(FP),DI
+ XORL CX,CX
+ CMPL DX,BX /* dividend >= 2^32 * divisor */
+ JHS _divovfl
+ CMPL BX,CX /* divisor == 0 */
+ JE _divovfl
+ DIVL BX /* AX = DX:AX/BX */
+ MOVL AX,0(DI)
+ RET
+
+ /* return all 1's */
+_divovfl:
+ NOTL CX
+ MOVL CX,0(DI)
+ RET
--- /dev/null
+++ b/libmp/Inferno-amd64/mpvecadd.s
@@ -1,0 +1,54 @@
+/*
+ * mpvecadd(mpdigit *a, int alen, mpdigit *b, int blen, mpdigit *sum)
+ *
+ * sum[0:alen] = a[0:alen-1] + b[0:blen-1]
+ *
+ * prereq: alen >= blen, sum has room for alen+1 digits
+ */
+TEXT mpvecadd(SB),$0
+
+ MOVL alen+8(FP),DX
+ MOVL blen+24(FP),CX
+/* MOVL a+0(FP),SI */
+ MOVQ RARG, SI
+ MOVQ b+16(FP),BX
+ SUBL CX,DX
+ MOVQ sum+32(FP),DI
+ XORL BP,BP /* this also sets carry to 0 */
+
+ /* skip addition if b is zero */
+ TESTL CX,CX
+ JZ _add1
+
+ /* sum[0:blen-1],carry = a[0:blen-1] + b[0:blen-1] */
+_addloop1:
+ MOVL (SI)(BP*4), AX
+ ADCL (BX)(BP*4), AX
+ MOVL AX,(DI)(BP*4)
+ INCL BP
+ LOOP _addloop1
+
+_add1:
+ /* jump if alen > blen */
+ INCL DX
+ MOVL DX,CX
+ LOOP _addloop2
+
+ /* sum[alen] = carry */
+_addend:
+ JC _addcarry
+ MOVL $0,(DI)(BP*4)
+ RET
+_addcarry:
+ MOVL $1,(DI)(BP*4)
+ RET
+
+ /* sum[blen:alen-1],carry = a[blen:alen-1] + 0 */
+_addloop2:
+ MOVL (SI)(BP*4),AX
+ ADCL $0,AX
+ MOVL AX,(DI)(BP*4)
+ INCL BP
+ LOOP _addloop2
+ JMP _addend
+
--- /dev/null
+++ b/libmp/Inferno-amd64/mpvecdigmuladd.s
@@ -1,0 +1,53 @@
+/*
+ * mpvecdigmul(mpdigit *b, int n, mpdigit m, mpdigit *p)
+ *
+ * p += b*m
+ *
+ * each step look like:
+ * hi,lo = m*b[i]
+ * lo += oldhi + carry
+ * hi += carry
+ * p[i] += lo
+ * oldhi = hi
+ *
+ * the registers are:
+ * hi = DX - constrained by hardware
+ * lo = AX - constrained by hardware
+ * b+n = SI - can't be BP
+ * p+n = DI - can't be BP
+ * i-n = BP
+ * m = BX
+ * oldhi = CX
+ *
+ */
+TEXT mpvecdigmuladd(SB),$0
+
+/* MOVQ b+0(FP),SI */
+ MOVQ RARG,SI
+ MOVL n+8(FP),CX
+ MOVL m+16(FP),BX
+ MOVQ p+24(FP),DI
+ MOVL CX,BP
+ NEGQ BP /* BP = -n */
+ SHLL $2,CX
+ ADDQ CX,SI /* SI = b + n */
+ ADDQ CX,DI /* DI = p + n */
+ XORL CX,CX
+_muladdloop:
+ MOVL (SI)(BP*4),AX /* lo = b[i] */
+ MULL BX /* hi, lo = b[i] * m */
+ ADDL CX,AX /* lo += oldhi */
+ JCC _muladdnocarry1
+ INCL DX /* hi += carry */
+_muladdnocarry1:
+ ADDL AX,(DI)(BP*4) /* p[i] += lo */
+ JCC _muladdnocarry2
+ INCL DX /* hi += carry */
+_muladdnocarry2:
+ MOVL DX,CX /* oldhi = hi */
+ INCQ BP /* i++ */
+ JNZ _muladdloop
+ XORL AX,AX
+ ADDL CX,(DI)(BP*4) /* p[n] + oldhi */
+ ADCL AX,AX /* return carry out of p[n] */
+ RET
--- /dev/null
+++ b/libmp/Inferno-amd64/mpvecdigmulsub.s
@@ -1,0 +1,54 @@
+/*
+ * mpvecdigmulsub(mpdigit *b, int n, mpdigit m, mpdigit *p)
+ *
+ * p -= b*m
+ *
+ * each step look like:
+ * hi,lo = m*b[i]
+ * lo += oldhi + carry
+ * hi += carry
+ * p[i] += lo
+ * oldhi = hi
+ *
+ * the registers are:
+ * hi = DX - constrained by hardware
+ * lo = AX - constrained by hardware
+ * b = SI - can't be BP
+ * p = DI - can't be BP
+ * i = BP
+ * n = CX - constrained by LOOP instr
+ * m = BX
+ * oldhi = EX
+ *
+ */
+TEXT mpvecdigmulsub(SB),$0
+
+/* MOVL b+0(FP),SI */
+ MOVQ RARG,SI
+ MOVL n+8(FP),CX
+ MOVL m+16(FP),BX
+ MOVQ p+24(FP),DI
+ XORL BP,BP
+ PUSHQ BP
+_mulsubloop:
+ MOVL (SI)(BP*4),AX /* lo = b[i] */
+ MULL BX /* hi, lo = b[i] * m */
+ ADDL 0(SP),AX /* lo += oldhi */
+ JCC _mulsubnocarry1
+ INCL DX /* hi += carry */
+_mulsubnocarry1:
+ SUBL AX,(DI)(BP*4)
+ JCC _mulsubnocarry2
+ INCL DX /* hi += carry */
+_mulsubnocarry2:
+ MOVL DX,0(SP)
+ INCL BP
+ LOOP _mulsubloop
+ POPQ AX
+ SUBL AX,(DI)(BP*4)
+ JCC _mulsubnocarry3
+ MOVQ $-1,AX
+ RET
+_mulsubnocarry3:
+ MOVQ $1,AX
+ RET
--- /dev/null
+++ b/libmp/Inferno-amd64/mpvecsub.s
@@ -1,0 +1,45 @@
+/*
+ * mpvecsub(mpdigit *a, int alen, mpdigit *b, int blen, mpdigit *diff)
+ *
+ * diff[0:alen-1] = a[0:alen-1] - b[0:blen-1]
+ *
+ * prereq: alen >= blen, diff has room for alen digits
+ */
+TEXT mpvecsub(SB),$0
+
+/* MOVQ a+0(FP),SI */
+ MOVQ RARG, SI
+ MOVQ b+16(FP),BX
+ MOVL alen+8(FP),DX
+ MOVL blen+24(FP),CX
+ MOVQ diff+32(FP),DI
+ SUBL CX,DX
+ XORL BP,BP /* this also sets carry to 0 */
+
+ /* skip subraction if b is zero */
+ TESTL CX,CX
+ JZ _sub1
+
+ /* diff[0:blen-1],borrow = a[0:blen-1] - b[0:blen-1] */
+_subloop1:
+ MOVL (SI)(BP*4),AX
+ SBBL (BX)(BP*4),AX
+ MOVL AX,(DI)(BP*4)
+ INCL BP
+ LOOP _subloop1
+
+_sub1:
+ INCL DX
+ MOVL DX,CX
+ LOOP _subloop2
+ RET
+
+ /* diff[blen:alen-1] = a[blen:alen-1] - 0 */
+_subloop2:
+ MOVL (SI)(BP*4),AX
+ SBBL $0,AX
+ MOVL AX,(DI)(BP*4)
+ INCL BP
+ LOOP _subloop2
+ RET
+
--- /dev/null
+++ b/libmp/Inferno-mips/mkfile
@@ -1,0 +1,21 @@
+objtype=mips
+OBJTYPE=$objtype
+<../../mkconfig
+
+LIB=libmp.a
+SFILES=\
+ mpvecadd.s\
+ mpvecdigmuladd.s\
+ mpvecdigmulsub.s\
+ mpvecsub.s\
+ mpdigdiv.s\
+
+HFILES=$ROOT/Inferno/$OBJTYPE/include/u.h $ROOT/include/mp.h ../port/dat.h
+
+OFILES=${SFILES:%.s=%.$O}
+
+UPDATE=mkfile\
+ $HFILES\
+ $SFILES\
+
+<$ROOT/mkfiles/mksyslib-$SHELLTYPE
--- /dev/null
+++ b/libmp/Inferno-mips/mpdigdiv.s
@@ -1,0 +1,41 @@
+/*
+ * This only works on R[45]000 chips that allow 64 bit
+ * integer arithmetic even when uding 32 bit addresses
+ *
+ * R1 = dividend*
+ * R2 = dividend[low]
+ * R3 = dividend[high]
+ * R4 = 32 bit divisor
+ * R5 = quotient*
+ */
+TEXT mpdigdiv(SB),$0
+
+ MOVW 0(R1),R2
+ MOVW 4(R1),R3
+ MOVW divisor+4(FP),R4
+ MOVW quotient+8(FP),R5
+
+ /* divisor == 0 */
+ BEQ R4,_digovfl
+
+ /* dividend >= 2^32 * divisor */
+ SGTU R4,R3,R7
+ BEQ R7,_digovfl
+
+_digdiv1:
+ SLLV $32,R2
+ SLLV $32,R3
+ SRLV $32,R2
+ ADDVU R2,R3
+ SLLV $32,R4
+ SRLV $32,R4
+ DIVVU R4,R3
+ MOVW LO,R1
+ MOVW R1,0(R5)
+ RET
+
+_digovfl:
+ MOVW $-1,R1
+ MOVW R1,0(R5)
+ RET
+
--- /dev/null
+++ b/libmp/Inferno-mips/mpvecadd.s
@@ -1,0 +1,67 @@
+#define BDNZ BC 16,0,
+#define BDNE BC 0,2,
+
+/*
+ * mpvecadd(mpdigit *a, int alen, mpdigit *b, int blen, mpdigit *sum)
+ *
+ * sum[0:alen] = a[0:alen-1] + b[0:blen-1]
+ *
+ * prereq: alen >= blen, sum has room for alen+1 digits
+ *
+ * R1 == a (first arg passed in R1)
+ * R3 == carry
+ * R4 == alen
+ * R5 == b
+ * R6 == blen
+ * R7 == sum
+ * R2 == temporary
+ * R8 == temporary
+ * R9 == temporary
+ */
+TEXT mpvecadd(SB),$-4
+
+ MOVW alen+4(FP), R4
+ MOVW b+8(FP), R5
+ MOVW blen+12(FP), R6
+ MOVW sum+16(FP), R7
+ SUBU R6, R4 /* calculate counter for second loop (alen > blen) */
+ MOVW R0, R3
+
+ /* if blen == 0, don't need to add it in */
+ BEQ R6,_add1
+
+ /* sum[0:blen-1],carry = a[0:blen-1] + b[0:blen-1] */
+_addloop1:
+ MOVW 0(R1), R8
+ ADDU $4, R1
+ MOVW 0(R5), R9
+ ADDU $4, R5
+ ADDU R3, R8
+ SGTU R3, R8, R3
+ ADDU R8, R9
+ SGTU R8, R9, R2
+ ADDU R2, R3
+ MOVW R9, 0(R7)
+ ADDU $4, R7
+ SUBU $1, R6
+ BNE R6, _addloop1
+
+_add1:
+ /* if alen == blen, we're done */
+ BEQ R4, _addend
+
+ /* sum[blen:alen-1],carry = a[blen:alen-1] + 0 + carry */
+_addloop2:
+ MOVW 0(R1), R8
+ ADDU $4, R1
+ ADDU R3, R8
+ SGTU R3, R8, R3
+ MOVW R8, 0(R7)
+ ADDU $4, R7
+ SUBU $1, R4
+ BNE R4, _addloop2
+
+ /* sum[alen] = carry */
+_addend:
+ MOVW R3, 0(R7)
+ RET
--- /dev/null
+++ b/libmp/Inferno-mips/mpvecdigmuladd.s
@@ -1,0 +1,58 @@
+/*
+ * mpvecdigmuladd(mpdigit *b, int n, mpdigit m, mpdigit *p)
+ *
+ * p += b*m
+ *
+ * each step looks like:
+ * hi,lo = m*b[i]
+ * lo += oldhi + carry
+ * hi += carry
+ * p[i] += lo
+ * oldhi = hi
+ *
+ * the registers are:
+ * b = R1
+ * n = R4
+ * m = R5
+ * p = R6
+ * i = R7
+ * hi = R8 - constrained by hardware
+ * lo = R9 - constrained by hardware
+ * oldhi = R10
+ * tmp = R11
+ *
+ */
+TEXT mpvecdigmuladd(SB),$0
+
+ MOVW n+4(FP),R4
+ MOVW m+8(FP),R5
+ MOVW p+12(FP),R6
+
+
+ MOVW R0, R10 /* oldhi = 0 */
+ BEQ R6, _muladd1
+_muladdloop:
+ MOVW 0(R1), R9 /* lo = b[i] */
+ ADDU $4, R1
+ MOVW 0(R6), R11 /* tmp = p[i] */
+ MULU R9, R5
+ MOVW HI, R8 /* hi = (b[i] * m)>>32 */
+ MOVW LO, R9 /* lo = b[i] * m */
+ ADDU R10, R9 /* lo += oldhi */
+ SGTU R10, R9, R2
+ ADDU R2, R8 /* hi += carry */
+ ADDU R9, R11 /* tmp += lo */
+ SGTU R9, R11, R2
+ ADDU R2, R8 /* hi += carry */
+ MOVW R11, 0(R6) /* p[i] = tmp */
+ ADDU $4, R6
+ MOVW R8, R10 /* oldhi = hi */
+ SUBU $1, R4
+ BNE R4, _muladdloop
+
+_muladd1:
+ MOVW 0(R6), R11 /* tmp = p[i] */
+ ADDU R10, R11 /* tmp += oldhi */
+ MOVW R11, 0(R6) /* p[i] = tmp */
+
+ RET
--- /dev/null
+++ b/libmp/Inferno-mips/mpvecdigmulsub.s
@@ -1,0 +1,61 @@
+/*
+ * mpvecdigmulsub(mpdigit *b, int n, mpdigit m, mpdigit *p)
+ *
+ * p -= b*m
+ *
+ * each step looks like:
+ * hi,lo = m*b[i]
+ * lo += oldhi + carry
+ * hi += carry
+ * p[i] += lo
+ * oldhi = hi
+ *
+ * the registers are:
+ * b = R1
+ * n = R4
+ * m = R5
+ * p = R6
+ * i = R7
+ * hi = R8 - constrained by hardware
+ * lo = R9 - constrained by hardware
+ * oldhi = R10
+ * tmp = R11
+ *
+ */
+TEXT mpvecdigmulsub(SB),$0
+
+ MOVW n+4(FP),R4
+ MOVW m+8(FP),R5
+ MOVW p+12(FP),R6
+
+ MOVW R0, R10 /* oldhi = 0 */
+_mulsubloop:
+ MOVW 0(R1), R9 /* lo = b[i] */
+ ADDU $4, R1
+ MOVW 0(R6), R11 /* tmp = p[i] */
+ MULU R9, R5
+ MOVW HI, R8 /* hi = (b[i] * m)>>32 */
+ MOVW LO, R9 /* lo = b[i] * m */
+ ADDU R10, R9 /* lo += oldhi */
+ SGTU R10, R9, R2
+ ADDU R2, R8 /* hi += carry */
+ SUBU R9, R11, R3 /* tmp -= lo */
+ SGTU R3, R11, R2
+ ADDU R2, R8 /* hi += carry */
+ MOVW R3, 0(R6) /* p[i] = tmp */
+ ADDU $4, R6
+ MOVW R8, R10 /* oldhi = hi */
+ SUBU $1, R4
+ BNE R4, _mulsubloop
+
+ MOVW 0(R6), R11 /* tmp = p[i] */
+ SUBU R10, R11, R3 /* tmp -= oldhi */
+ MOVW R3, 0(R6) /* p[i] = tmp */
+ SGTU R3, R11, R1
+ BNE R1, _mulsub2
+ MOVW $1, R1 /* return +1 for positive result */
+ RET
+
+_mulsub2:
+ MOVW $-1, R1 /* return -1 for negative result */
+ RET
--- /dev/null
+++ b/libmp/Inferno-mips/mpvecsub.s
@@ -1,0 +1,66 @@
+#define BDNZ BC 16,0,
+#define BDNE BC 0,2,
+
+/*
+ * mpvecadd(mpdigit *a, int alen, mpdigit *b, int blen, mpdigit *sum)
+ *
+ * sum[0:alen] = a[0:alen-1] - b[0:blen-1]
+ *
+ * prereq: alen >= blen, sum has room for alen+1 digits
+ *
+ * R1 == a (first arg passed in R1)
+ * R3 == carry
+ * R4 == alen
+ * R5 == b
+ * R6 == blen
+ * R7 == sum
+ * R2 == temporary
+ * R8 == temporary
+ * R9 == temporary
+ */
+TEXT mpvecsub(SB),$-4
+
+ MOVW alen+4(FP), R4
+ MOVW b+8(FP), R5
+ MOVW blen+12(FP), R6
+ MOVW sum+16(FP), R7
+ SUBU R6, R4 /* calculate counter for second loop (alen > blen) */
+ MOVW R0, R3
+
+ /* if blen == 0, don't need to subtract it */
+ BEQ R6,_sub1
+
+ /* sum[0:blen-1],carry = a[0:blen-1] - b[0:blen-1] */
+_subloop1:
+ MOVW 0(R1), R8
+ ADDU $4, R1
+ MOVW 0(R5), R9
+ ADDU $4, R5
+ SUBU R3, R8, R2
+ SGTU R2, R8, R3
+ SUBU R9, R2, R8
+ SGTU R8, R2, R9
+ ADDU R9, R3
+ MOVW R8, 0(R7)
+ ADDU $4, R7
+ SUBU $1, R6
+ BNE R6, _subloop1
+
+_sub1:
+ /* if alen == blen, we're done */
+ BEQ R4, _subend
+
+ /* sum[blen:alen-1],carry = a[blen:alen-1] + 0 + carry */
+_subloop2:
+ MOVW 0(R1), R8
+ ADDU $4, R1
+ SUBU R3, R8, R2
+ SGTU R2, R8, R3
+ MOVW R2, 0(R7)
+ ADDU $4, R7
+ SUBU $1, R4
+ BNE R4, _subloop2
+
+ /* sum[alen] = carry */
+_subend:
+ RET
--- /dev/null
+++ b/libmp/Inferno-power/mkfile
@@ -1,0 +1,20 @@
+objtype=power
+OBJTYPE=$objtype
+<../../mkconfig
+
+LIB=libmp.a
+SFILES=\
+ mpvecadd.s\
+ mpvecdigmuladd.s\
+ mpvecdigmulsub.s\
+ mpvecsub.s\
+
+HFILES=$ROOT/Inferno/$OBJTYPE/include/u.h $ROOT/include/mp.h ../port/dat.h
+
+OFILES=${SFILES:%.s=%.$O}
+
+UPDATE=mkfile\
+ $HFILES\
+ $SFILES\
+
+<$ROOT/mkfiles/mksyslib-$SHELLTYPE
--- /dev/null
+++ b/libmp/Inferno-power/mpvecadd.s
@@ -1,0 +1,61 @@
+#define BDNZ BC 16,0,
+#define BDNE BC 0,2,
+
+/*
+ * mpvecadd(mpdigit *a, int alen, mpdigit *b, int blen, mpdigit *sum)
+ *
+ * sum[0:alen] = a[0:alen-1] + b[0:blen-1]
+ *
+ * prereq: alen >= blen, sum has room for alen+1 digits
+ *
+ * R3 == a (first arg passed in R3)
+ * R4 == alen
+ * R5 == b
+ * R6 == blen
+ * R7 == sum
+ * R8 == temporary
+ * R9 == temporary
+ */
+TEXT mpvecadd(SB),$-4
+
+ MOVW alen+4(FP), R4
+ MOVW b+8(FP), R5
+ MOVW blen+12(FP), R6
+ MOVW sum+16(FP), R7
+ SUB R6, R4 /* calculate counter for second loop (alen > blen) */
+ SUB $4, R3 /* pre decrement for MOVWU's */
+ SUB $4, R5 /* pre decrement for MOVWU's */
+ SUB $4, R7 /* pre decrement for MOVWU's */
+ MOVW R0, XER /* zero carry going in */
+
+ /* if blen == 0, don't need to add it in */
+ CMP R0, R6
+ BEQ _add1
+
+ /* sum[0:blen-1],carry = a[0:blen-1] + b[0:blen-1] */
+ MOVW R6, CTR
+_addloop1:
+ MOVWU 4(R3), R8
+ MOVWU 4(R5), R9
+ ADDE R8, R9
+ MOVWU R9, 4(R7)
+ BDNZ _addloop1
+
+_add1:
+ /* if alen == blen, we're done */
+ CMP R0, R4
+ BEQ _addend
+
+ /* sum[blen:alen-1],carry = a[blen:alen-1] + 0 + carry */
+ MOVW R4, CTR
+_addloop2:
+ MOVWU 4(R3), R8
+ ADDE R0, R8
+ MOVWU R8, 4(R7)
+ BDNZ _addloop2
+
+ /* sum[alen] = carry */
+_addend:
+ ADDE R0, R0, R8
+ MOVW R8, 4(R7)
+ RETURN
--- /dev/null
+++ b/libmp/Inferno-power/mpvecdigmuladd.s
@@ -1,0 +1,56 @@
+#define BDNZ BC 16,0,
+#define BDNE BC 0,2,
+
+/*
+ * mpvecdigmuladd(mpdigit *b, int n, mpdigit m, mpdigit *p)
+ *
+ * p += b*m
+ *
+ * each step looks like:
+ * hi,lo = m*b[i]
+ * lo += oldhi + carry
+ * hi += carry
+ * p[i] += lo
+ * oldhi = hi
+ *
+ * the registers are:
+ * b = R3
+ * n = R4
+ * m = R5
+ * p = R6
+ * i = R7
+ * hi = R8 - constrained by hardware
+ * lo = R9 - constrained by hardware
+ * oldhi = R10
+ * tmp = R11
+ *
+ */
+TEXT mpvecdigmuladd(SB),$0
+
+ MOVW n+4(FP),R4
+ MOVW m+8(FP),R5
+ MOVW p+12(FP),R6
+ SUB $4, R3 /* pre decrement for MOVWU's */
+ SUB $4, R6 /* pre decrement for MOVWU's */
+
+ MOVW R0, R10
+ MOVW R0, XER
+ MOVW R4, CTR
+_muladdloop:
+ MOVWU 4(R3),R9 /* lo = b[i] */
+ MOVW 4(R6),R11 /* tmp = p[i] */
+ MULHWU R9,R5,R8 /* hi = (b[i] * m)>>32 */
+ MULLW R9,R5,R9 /* lo = b[i] * m */
+ ADDC R10,R9 /* lo += oldhi */
+ ADDE R0,R8 /* hi += carry */
+ ADDC R9,R11 /* tmp += lo */
+ ADDE R0,R8 /* hi += carry */
+ MOVWU R11,4(R6) /* p[i] = tmp */
+ MOVW R8,R10 /* oldhi = hi */
+ BDNZ _muladdloop
+
+ MOVW 4(R6),R11 /* tmp = p[i] */
+ ADDC R10,R11
+ MOVWU R11,4(R6) /* p[i] = tmp */
+
+ RETURN
--- /dev/null
+++ b/libmp/Inferno-power/mpvecdigmulsub.s
@@ -1,0 +1,66 @@
+#define BDNZ BC 16,0,
+#define BDNE BC 0,2,
+#define BLT BC 0xC,0,
+
+/*
+ * mpvecdigmulsub(mpdigit *b, int n, mpdigit m, mpdigit *p)
+ *
+ * p -= b*m
+ *
+ * each step looks like:
+ * hi,lo = m*b[i]
+ * lo += oldhi + carry
+ * hi += carry
+ * p[i] += lo
+ * oldhi = hi
+ *
+ * the registers are:
+ * b = R3
+ * n = R4
+ * m = R5
+ * p = R6
+ * i = R7
+ * hi = R8 - constrained by hardware
+ * lo = R9 - constrained by hardware
+ * oldhi = R10
+ * tmp = R11
+ * borrow = R12
+ *
+ */
+TEXT mpvecdigmulsub(SB),$0
+
+ MOVW n+4(FP),R10
+ MOVW R10,CTR
+ MOVW m+8(FP),R5
+ MOVW p+12(FP),R6
+ SUB $4, R3 /* pre decrement for MOVWU's */
+ SUBC $4, R6 /* pre decrement for MOVWU's and set carry */
+ MOVW XER,R12
+
+ MOVW R0, R10
+
+_mulsubloop:
+ MOVWU 4(R3),R9 /* lo = b[i] */
+ MOVW 4(R6),R11 /* tmp = p[i] */
+ MULHWU R9,R5,R8 /* hi = (b[i] * m)>>32 */
+ MULLW R9,R5,R9 /* lo = b[i] * m */
+ ADDC R10,R9 /* lo += oldhi */
+ ADDE R0,R8 /* hi += carry */
+ MOVW R12,XER
+ SUBE R9,R11 /* tmp -= lo */
+ MOVW XER,R12
+ MOVWU R11,4(R6) /* p[i] = tmp */
+ MOVW R8,R10 /* oldhi = hi */
+ BDNZ _mulsubloop
+
+ MOVW 4(R6),R11 /* tmp = p[i] */
+ MOVW R12,XER
+ SUBE R10,R11 /* tmp -= lo */
+ MOVWU R11,4(R6) /* p[i] = tmp */
+
+ /* return -1 if the result was negative, +1 otherwise */
+ SUBECC R0,R0,R3
+ BLT _mulsub2
+ MOVW $1,R3
+_mulsub2:
+ RETURN
--- /dev/null
+++ b/libmp/Inferno-power/mpvecsub.s
@@ -1,0 +1,57 @@
+#define BDNZ BC 16,0,
+#define BDNE BC 0,2,
+
+/*
+ * mpvecsub(mpdigit *a, int alen, mpdigit *b, int blen, mpdigit *diff)
+ *
+ * diff[0:alen-1] = a[0:alen-1] - b[0:blen-1]
+ *
+ * prereq: alen >= blen, diff has room for alen digits
+ *
+ * R3 == a
+ * R4 == alen
+ * R5 == b
+ * R6 == blen
+ * R7 == diff
+ * R8 == temporary
+ * R9 == temporary
+ */
+TEXT mpvecsub(SB),$-4
+
+ MOVW alen+4(FP),R4
+ MOVW b+8(FP),R5
+ MOVW blen+12(FP),R6
+ MOVW diff+16(FP),R7
+ SUB R6, R4 /* calculate counter for second loop (alen > blen) */
+ SUB $4, R3 /* pre decrement for MOVWU's */
+ SUB $4, R5 /* pre decrement for MOVWU's */
+ SUBC $4, R7 /* pre decrement for MOVWU's and set carry */
+
+ /* skip subraction if b is zero */
+ CMP R0,R6
+ BEQ _sub1
+
+ /* diff[0:blen-1],borrow = a[0:blen-1] - b[0:blen-1] */
+ MOVW R6, CTR
+_subloop1:
+ MOVWU 4(R3), R8
+ MOVWU 4(R5), R9
+ SUBE R9, R8, R8
+ MOVWU R8, 4(R7)
+ BDNZ _subloop1
+
+_sub1:
+ /* skip subtraction if a is zero */
+ CMP R0, R4
+ BEQ _subend
+
+ /* diff[blen:alen-1] = a[blen:alen-1] - 0 + carry */
+ MOVW R4, CTR
+_subloop2:
+ MOVWU 4(R3), R8
+ SUBE R0, R8
+ MOVWU R8, 4(R7)
+ BDNZ _subloop2
+_subend:
+ RETURN
+
--- /dev/null
+++ b/libmp/NOTICE
@@ -1,0 +1,4 @@
+Copyright © 2000-2007 Lucent Technologies Inc. and others. All rights reserved.
+Revisions for use with Inferno © 2006 Vita Nuova Holdings Limited.
+
+This software is provided under the terms of the Lucent Public License, Version 1.02.
--- /dev/null
+++ b/libmp/Plan9-386/mkfile
@@ -1,0 +1,21 @@
+objtype=386
+OBJTYPE=$objtype
+<../../mkconfig
+
+LIB=libmp.a
+SFILES=\
+ mpvecadd.s\
+ mpvecdigmuladd.s\
+ mpvecdigmulsub.s\
+ mpvecsub.s\
+ mpdigdiv.s\
+
+HFILES=$ROOT/$SYSTARG/$OBJTYPE/include/u.h $ROOT/include/mp.h ../port/dat.h
+
+OFILES=${SFILES:%.s=%.$O}
+
+UPDATE=mkfile\
+ $HFILES\
+ $SFILES\
+
+<$ROOT/mkfiles/mksyslib-$SHELLTYPE
--- /dev/null
+++ b/libmp/Plan9-386/mpdigdiv.s
@@ -1,0 +1,21 @@
+TEXT mpdigdiv(SB),$0
+
+ MOVL dividend+0(FP),BX
+ MOVL 0(BX),AX
+ MOVL 4(BX),DX
+ MOVL divisor+4(FP),BX
+ MOVL quotient+8(FP),BP
+ XORL CX,CX
+ CMPL DX,BX /* dividend >= 2^32 * divisor */
+ JHS _divovfl
+ CMPL BX,CX /* divisor == 0 */
+ JE _divovfl
+ DIVL BX /* AX = DX:AX/BX */
+ MOVL AX,0(BP)
+ RET
+
+ /* return all 1's */
+_divovfl:
+ NOTL CX
+ MOVL CX,0(BP)
+ RET
--- /dev/null
+++ b/libmp/Plan9-386/mpvecadd.s
@@ -1,0 +1,53 @@
+/*
+ * mpvecadd(mpdigit *a, int alen, mpdigit *b, int blen, mpdigit *sum)
+ *
+ * sum[0:alen] = a[0:alen-1] + b[0:blen-1]
+ *
+ * prereq: alen >= blen, sum has room for alen+1 digits
+ */
+TEXT mpvecadd(SB),$0
+
+ MOVL alen+4(FP),DX
+ MOVL blen+12(FP),CX
+ MOVL a+0(FP),SI
+ MOVL b+8(FP),BX
+ SUBL CX,DX
+ MOVL sum+16(FP),DI
+ XORL BP,BP /* this also sets carry to 0 */
+
+ /* skip addition if b is zero */
+ TESTL CX,CX
+ JZ _add1
+
+ /* sum[0:blen-1],carry = a[0:blen-1] + b[0:blen-1] */
+_addloop1:
+ MOVL (SI)(BP*4), AX
+ ADCL (BX)(BP*4), AX
+ MOVL AX,(DI)(BP*4)
+ INCL BP
+ LOOP _addloop1
+
+_add1:
+ /* jump if alen > blen */
+ INCL DX
+ MOVL DX,CX
+ LOOP _addloop2
+
+ /* sum[alen] = carry */
+_addend:
+ JC _addcarry
+ MOVL $0,(DI)(BP*4)
+ RET
+_addcarry:
+ MOVL $1,(DI)(BP*4)
+ RET
+
+ /* sum[blen:alen-1],carry = a[blen:alen-1] + 0 */
+_addloop2:
+ MOVL (SI)(BP*4),AX
+ ADCL $0,AX
+ MOVL AX,(DI)(BP*4)
+ INCL BP
+ LOOP _addloop2
+ JMP _addend
+
--- /dev/null
+++ b/libmp/Plan9-386/mpvecdigmuladd.s
@@ -1,0 +1,52 @@
+/*
+ * mpvecdigmul(mpdigit *b, int n, mpdigit m, mpdigit *p)
+ *
+ * p += b*m
+ *
+ * each step look like:
+ * hi,lo = m*b[i]
+ * lo += oldhi + carry
+ * hi += carry
+ * p[i] += lo
+ * oldhi = hi
+ *
+ * the registers are:
+ * hi = DX - constrained by hardware
+ * lo = AX - constrained by hardware
+ * b+n = SI - can't be BP
+ * p+n = DI - can't be BP
+ * i-n = BP
+ * m = BX
+ * oldhi = CX
+ *
+ */
+TEXT mpvecdigmuladd(SB),$0
+
+ MOVL b+0(FP),SI
+ MOVL n+4(FP),CX
+ MOVL m+8(FP),BX
+ MOVL p+12(FP),DI
+ MOVL CX,BP
+ NEGL BP /* BP = -n */
+ SHLL $2,CX
+ ADDL CX,SI /* SI = b + n */
+ ADDL CX,DI /* DI = p + n */
+ XORL CX,CX
+_muladdloop:
+ MOVL (SI)(BP*4),AX /* lo = b[i] */
+ MULL BX /* hi, lo = b[i] * m */
+ ADDL CX,AX /* lo += oldhi */
+ JCC _muladdnocarry1
+ INCL DX /* hi += carry */
+_muladdnocarry1:
+ ADDL AX,(DI)(BP*4) /* p[i] += lo */
+ JCC _muladdnocarry2
+ INCL DX /* hi += carry */
+_muladdnocarry2:
+ MOVL DX,CX /* oldhi = hi */
+ INCL BP /* i++ */
+ JNZ _muladdloop
+ XORL AX,AX
+ ADDL CX,(DI)(BP*4) /* p[n] + oldhi */
+ ADCL AX,AX /* return carry out of p[n] */
+ RET
--- /dev/null
+++ b/libmp/Plan9-386/mpvecdigmulsub.s
@@ -1,0 +1,53 @@
+/*
+ * mpvecdigmulsub(mpdigit *b, int n, mpdigit m, mpdigit *p)
+ *
+ * p -= b*m
+ *
+ * each step look like:
+ * hi,lo = m*b[i]
+ * lo += oldhi + carry
+ * hi += carry
+ * p[i] += lo
+ * oldhi = hi
+ *
+ * the registers are:
+ * hi = DX - constrained by hardware
+ * lo = AX - constrained by hardware
+ * b = SI - can't be BP
+ * p = DI - can't be BP
+ * i = BP
+ * n = CX - constrained by LOOP instr
+ * m = BX
+ * oldhi = EX
+ *
+ */
+TEXT mpvecdigmulsub(SB),$0
+
+ MOVL b+0(FP),SI
+ MOVL n+4(FP),CX
+ MOVL m+8(FP),BX
+ MOVL p+12(FP),DI
+ XORL BP,BP
+ PUSHL BP
+_mulsubloop:
+ MOVL (SI)(BP*4),AX /* lo = b[i] */
+ MULL BX /* hi, lo = b[i] * m */
+ ADDL 0(SP),AX /* lo += oldhi */
+ JCC _mulsubnocarry1
+ INCL DX /* hi += carry */
+_mulsubnocarry1:
+ SUBL AX,(DI)(BP*4)
+ JCC _mulsubnocarry2
+ INCL DX /* hi += carry */
+_mulsubnocarry2:
+ MOVL DX,0(SP)
+ INCL BP
+ LOOP _mulsubloop
+ POPL AX
+ SUBL AX,(DI)(BP*4)
+ JCC _mulsubnocarry3
+ MOVL $-1,AX
+ RET
+_mulsubnocarry3:
+ MOVL $1,AX
+ RET
--- /dev/null
+++ b/libmp/Plan9-386/mpvecsub.s
@@ -1,0 +1,44 @@
+/*
+ * mpvecsub(mpdigit *a, int alen, mpdigit *b, int blen, mpdigit *diff)
+ *
+ * diff[0:alen-1] = a[0:alen-1] - b[0:blen-1]
+ *
+ * prereq: alen >= blen, diff has room for alen digits
+ */
+TEXT mpvecsub(SB),$0
+
+ MOVL a+0(FP),SI
+ MOVL b+8(FP),BX
+ MOVL alen+4(FP),DX
+ MOVL blen+12(FP),CX
+ MOVL diff+16(FP),DI
+ SUBL CX,DX
+ XORL BP,BP /* this also sets carry to 0 */
+
+ /* skip subraction if b is zero */
+ TESTL CX,CX
+ JZ _sub1
+
+ /* diff[0:blen-1],borrow = a[0:blen-1] - b[0:blen-1] */
+_subloop1:
+ MOVL (SI)(BP*4),AX
+ SBBL (BX)(BP*4),AX
+ MOVL AX,(DI)(BP*4)
+ INCL BP
+ LOOP _subloop1
+
+_sub1:
+ INCL DX
+ MOVL DX,CX
+ LOOP _subloop2
+ RET
+
+ /* diff[blen:alen-1] = a[blen:alen-1] - 0 */
+_subloop2:
+ MOVL (SI)(BP*4),AX
+ SBBL $0,AX
+ MOVL AX,(DI)(BP*4)
+ INCL BP
+ LOOP _subloop2
+ RET
+
--- /dev/null
+++ b/libmp/Plan9-amd64/mkfile
@@ -1,0 +1,21 @@
+objtype=amd64
+OBJTYPE=$objtype
+<../../mkconfig
+
+LIB=libmp.a
+SFILES=\
+ mpvecadd.s\
+ mpvecdigmuladd.s\
+ mpvecdigmulsub.s\
+ mpvecsub.s\
+ mpdigdiv.s\
+
+HFILES=$ROOT/$SYSTARG/$OBJTYPE/include/u.h $ROOT/include/mp.h ../port/dat.h
+
+OFILES=${SFILES:%.s=%.$O}
+
+UPDATE=mkfile\
+ $HFILES\
+ $SFILES\
+
+<$ROOT/mkfiles/mksyslib-$SHELLTYPE
--- /dev/null
+++ b/libmp/Plan9-amd64/mpdigdiv.s
@@ -1,0 +1,21 @@
+TEXT mpdigdiv(SB),$0
+
+/* MOVL dividend+0(FP),BX */
+ MOVL 0(RARG),AX
+ MOVL 4(RARG),DX
+ MOVL divisor+8(FP),BX
+ MOVQ quotient+16(FP),DI
+ XORL CX,CX
+ CMPL DX,BX /* dividend >= 2^32 * divisor */
+ JHS _divovfl
+ CMPL BX,CX /* divisor == 0 */
+ JE _divovfl
+ DIVL BX /* AX = DX:AX/BX */
+ MOVL AX,0(DI)
+ RET
+
+ /* return all 1's */
+_divovfl:
+ NOTL CX
+ MOVL CX,0(DI)
+ RET
--- /dev/null
+++ b/libmp/Plan9-amd64/mpvecadd.s
@@ -1,0 +1,54 @@
+/*
+ * mpvecadd(mpdigit *a, int alen, mpdigit *b, int blen, mpdigit *sum)
+ *
+ * sum[0:alen] = a[0:alen-1] + b[0:blen-1]
+ *
+ * prereq: alen >= blen, sum has room for alen+1 digits
+ */
+TEXT mpvecadd(SB),$0
+
+ MOVL alen+8(FP),DX
+ MOVL blen+24(FP),CX
+/* MOVL a+0(FP),SI */
+ MOVQ RARG, SI
+ MOVQ b+16(FP),BX
+ SUBL CX,DX
+ MOVQ sum+32(FP),DI
+ XORL BP,BP /* this also sets carry to 0 */
+
+ /* skip addition if b is zero */
+ TESTL CX,CX
+ JZ _add1
+
+ /* sum[0:blen-1],carry = a[0:blen-1] + b[0:blen-1] */
+_addloop1:
+ MOVL (SI)(BP*4), AX
+ ADCL (BX)(BP*4), AX
+ MOVL AX,(DI)(BP*4)
+ INCL BP
+ LOOP _addloop1
+
+_add1:
+ /* jump if alen > blen */
+ INCL DX
+ MOVL DX,CX
+ LOOP _addloop2
+
+ /* sum[alen] = carry */
+_addend:
+ JC _addcarry
+ MOVL $0,(DI)(BP*4)
+ RET
+_addcarry:
+ MOVL $1,(DI)(BP*4)
+ RET
+
+ /* sum[blen:alen-1],carry = a[blen:alen-1] + 0 */
+_addloop2:
+ MOVL (SI)(BP*4),AX
+ ADCL $0,AX
+ MOVL AX,(DI)(BP*4)
+ INCL BP
+ LOOP _addloop2
+ JMP _addend
+
--- /dev/null
+++ b/libmp/Plan9-amd64/mpvecdigmuladd.s
@@ -1,0 +1,53 @@
+/*
+ * mpvecdigmul(mpdigit *b, int n, mpdigit m, mpdigit *p)
+ *
+ * p += b*m
+ *
+ * each step look like:
+ * hi,lo = m*b[i]
+ * lo += oldhi + carry
+ * hi += carry
+ * p[i] += lo
+ * oldhi = hi
+ *
+ * the registers are:
+ * hi = DX - constrained by hardware
+ * lo = AX - constrained by hardware
+ * b+n = SI - can't be BP
+ * p+n = DI - can't be BP
+ * i-n = BP
+ * m = BX
+ * oldhi = CX
+ *
+ */
+TEXT mpvecdigmuladd(SB),$0
+
+/* MOVQ b+0(FP),SI */
+ MOVQ RARG,SI
+ MOVL n+8(FP),CX
+ MOVL m+16(FP),BX
+ MOVQ p+24(FP),DI
+ MOVL CX,BP
+ NEGQ BP /* BP = -n */
+ SHLL $2,CX
+ ADDQ CX,SI /* SI = b + n */
+ ADDQ CX,DI /* DI = p + n */
+ XORL CX,CX
+_muladdloop:
+ MOVL (SI)(BP*4),AX /* lo = b[i] */
+ MULL BX /* hi, lo = b[i] * m */
+ ADDL CX,AX /* lo += oldhi */
+ JCC _muladdnocarry1
+ INCL DX /* hi += carry */
+_muladdnocarry1:
+ ADDL AX,(DI)(BP*4) /* p[i] += lo */
+ JCC _muladdnocarry2
+ INCL DX /* hi += carry */
+_muladdnocarry2:
+ MOVL DX,CX /* oldhi = hi */
+ INCQ BP /* i++ */
+ JNZ _muladdloop
+ XORL AX,AX
+ ADDL CX,(DI)(BP*4) /* p[n] + oldhi */
+ ADCL AX,AX /* return carry out of p[n] */
+ RET
--- /dev/null
+++ b/libmp/Plan9-amd64/mpvecdigmulsub.s
@@ -1,0 +1,54 @@
+/*
+ * mpvecdigmulsub(mpdigit *b, int n, mpdigit m, mpdigit *p)
+ *
+ * p -= b*m
+ *
+ * each step look like:
+ * hi,lo = m*b[i]
+ * lo += oldhi + carry
+ * hi += carry
+ * p[i] += lo
+ * oldhi = hi
+ *
+ * the registers are:
+ * hi = DX - constrained by hardware
+ * lo = AX - constrained by hardware
+ * b = SI - can't be BP
+ * p = DI - can't be BP
+ * i = BP
+ * n = CX - constrained by LOOP instr
+ * m = BX
+ * oldhi = EX
+ *
+ */
+TEXT mpvecdigmulsub(SB),$0
+
+/* MOVL b+0(FP),SI */
+ MOVQ RARG,SI
+ MOVL n+8(FP),CX
+ MOVL m+16(FP),BX
+ MOVQ p+24(FP),DI
+ XORL BP,BP
+ PUSHQ BP
+_mulsubloop:
+ MOVL (SI)(BP*4),AX /* lo = b[i] */
+ MULL BX /* hi, lo = b[i] * m */
+ ADDL 0(SP),AX /* lo += oldhi */
+ JCC _mulsubnocarry1
+ INCL DX /* hi += carry */
+_mulsubnocarry1:
+ SUBL AX,(DI)(BP*4)
+ JCC _mulsubnocarry2
+ INCL DX /* hi += carry */
+_mulsubnocarry2:
+ MOVL DX,0(SP)
+ INCL BP
+ LOOP _mulsubloop
+ POPQ AX
+ SUBL AX,(DI)(BP*4)
+ JCC _mulsubnocarry3
+ MOVQ $-1,AX
+ RET
+_mulsubnocarry3:
+ MOVQ $1,AX
+ RET
--- /dev/null
+++ b/libmp/Plan9-amd64/mpvecsub.s
@@ -1,0 +1,45 @@
+/*
+ * mpvecsub(mpdigit *a, int alen, mpdigit *b, int blen, mpdigit *diff)
+ *
+ * diff[0:alen-1] = a[0:alen-1] - b[0:blen-1]
+ *
+ * prereq: alen >= blen, diff has room for alen digits
+ */
+TEXT mpvecsub(SB),$0
+
+/* MOVQ a+0(FP),SI */
+ MOVQ RARG, SI
+ MOVQ b+16(FP),BX
+ MOVL alen+8(FP),DX
+ MOVL blen+24(FP),CX
+ MOVQ diff+32(FP),DI
+ SUBL CX,DX
+ XORL BP,BP /* this also sets carry to 0 */
+
+ /* skip subraction if b is zero */
+ TESTL CX,CX
+ JZ _sub1
+
+ /* diff[0:blen-1],borrow = a[0:blen-1] - b[0:blen-1] */
+_subloop1:
+ MOVL (SI)(BP*4),AX
+ SBBL (BX)(BP*4),AX
+ MOVL AX,(DI)(BP*4)
+ INCL BP
+ LOOP _subloop1
+
+_sub1:
+ INCL DX
+ MOVL DX,CX
+ LOOP _subloop2
+ RET
+
+ /* diff[blen:alen-1] = a[blen:alen-1] - 0 */
+_subloop2:
+ MOVL (SI)(BP*4),AX
+ SBBL $0,AX
+ MOVL AX,(DI)(BP*4)
+ INCL BP
+ LOOP _subloop2
+ RET
+
--- /dev/null
+++ b/libmp/Plan9-mips/mkfile
@@ -1,0 +1,21 @@
+objtype=mips
+OBJTYPE=$objtype
+<../../mkconfig
+
+LIB=libmp.a
+SFILES=\
+ mpvecadd.s\
+ mpvecdigmuladd.s\
+ mpvecdigmulsub.s\
+ mpvecsub.s\
+ mpdigdiv.s\
+
+HFILES=$ROOT/$SYSTARG/$OBJTYPE/include/u.h $ROOT/include/mp.h ../port/dat.h
+
+OFILES=${SFILES:%.s=%.$O}
+
+UPDATE=mkfile\
+ $HFILES\
+ $SFILES\
+
+<$ROOT/mkfiles/mksyslib-$SHELLTYPE
--- /dev/null
+++ b/libmp/Plan9-mips/mpdigdiv.s
@@ -1,0 +1,41 @@
+/*
+ * This only works on R[45]000 chips that allow 64 bit
+ * integer arithmetic even when uding 32 bit addresses
+ *
+ * R1 = dividend*
+ * R2 = dividend[low]
+ * R3 = dividend[high]
+ * R4 = 32 bit divisor
+ * R5 = quotient*
+ */
+TEXT mpdigdiv(SB),$0
+
+ MOVW 0(R1),R2
+ MOVW 4(R1),R3
+ MOVW divisor+4(FP),R4
+ MOVW quotient+8(FP),R5
+
+ /* divisor == 0 */
+ BEQ R4,_digovfl
+
+ /* dividend >= 2^32 * divisor */
+ SGTU R4,R3,R7
+ BEQ R7,_digovfl
+
+_digdiv1:
+ SLLV $32,R2
+ SLLV $32,R3
+ SRLV $32,R2
+ ADDVU R2,R3
+ SLLV $32,R4
+ SRLV $32,R4
+ DIVVU R4,R3
+ MOVW LO,R1
+ MOVW R1,0(R5)
+ RET
+
+_digovfl:
+ MOVW $-1,R1
+ MOVW R1,0(R5)
+ RET
+
--- /dev/null
+++ b/libmp/Plan9-mips/mpvecadd.s
@@ -1,0 +1,67 @@
+#define BDNZ BC 16,0,
+#define BDNE BC 0,2,
+
+/*
+ * mpvecadd(mpdigit *a, int alen, mpdigit *b, int blen, mpdigit *sum)
+ *
+ * sum[0:alen] = a[0:alen-1] + b[0:blen-1]
+ *
+ * prereq: alen >= blen, sum has room for alen+1 digits
+ *
+ * R1 == a (first arg passed in R1)
+ * R3 == carry
+ * R4 == alen
+ * R5 == b
+ * R6 == blen
+ * R7 == sum
+ * R2 == temporary
+ * R8 == temporary
+ * R9 == temporary
+ */
+TEXT mpvecadd(SB),$-4
+
+ MOVW alen+4(FP), R4
+ MOVW b+8(FP), R5
+ MOVW blen+12(FP), R6
+ MOVW sum+16(FP), R7
+ SUBU R6, R4 /* calculate counter for second loop (alen > blen) */
+ MOVW R0, R3
+
+ /* if blen == 0, don't need to add it in */
+ BEQ R6,_add1
+
+ /* sum[0:blen-1],carry = a[0:blen-1] + b[0:blen-1] */
+_addloop1:
+ MOVW 0(R1), R8
+ ADDU $4, R1
+ MOVW 0(R5), R9
+ ADDU $4, R5
+ ADDU R3, R8
+ SGTU R3, R8, R3
+ ADDU R8, R9
+ SGTU R8, R9, R2
+ ADDU R2, R3
+ MOVW R9, 0(R7)
+ ADDU $4, R7
+ SUBU $1, R6
+ BNE R6, _addloop1
+
+_add1:
+ /* if alen == blen, we're done */
+ BEQ R4, _addend
+
+ /* sum[blen:alen-1],carry = a[blen:alen-1] + 0 + carry */
+_addloop2:
+ MOVW 0(R1), R8
+ ADDU $4, R1
+ ADDU R3, R8
+ SGTU R3, R8, R3
+ MOVW R8, 0(R7)
+ ADDU $4, R7
+ SUBU $1, R4
+ BNE R4, _addloop2
+
+ /* sum[alen] = carry */
+_addend:
+ MOVW R3, 0(R7)
+ RET
--- /dev/null
+++ b/libmp/Plan9-mips/mpvecdigmuladd.s
@@ -1,0 +1,58 @@
+/*
+ * mpvecdigmuladd(mpdigit *b, int n, mpdigit m, mpdigit *p)
+ *
+ * p += b*m
+ *
+ * each step looks like:
+ * hi,lo = m*b[i]
+ * lo += oldhi + carry
+ * hi += carry
+ * p[i] += lo
+ * oldhi = hi
+ *
+ * the registers are:
+ * b = R1
+ * n = R4
+ * m = R5
+ * p = R6
+ * i = R7
+ * hi = R8 - constrained by hardware
+ * lo = R9 - constrained by hardware
+ * oldhi = R10
+ * tmp = R11
+ *
+ */
+TEXT mpvecdigmuladd(SB),$0
+
+ MOVW n+4(FP),R4
+ MOVW m+8(FP),R5
+ MOVW p+12(FP),R6
+
+
+ MOVW R0, R10 /* oldhi = 0 */
+ BEQ R6, _muladd1
+_muladdloop:
+ MOVW 0(R1), R9 /* lo = b[i] */
+ ADDU $4, R1
+ MOVW 0(R6), R11 /* tmp = p[i] */
+ MULU R9, R5
+ MOVW HI, R8 /* hi = (b[i] * m)>>32 */
+ MOVW LO, R9 /* lo = b[i] * m */
+ ADDU R10, R9 /* lo += oldhi */
+ SGTU R10, R9, R2
+ ADDU R2, R8 /* hi += carry */
+ ADDU R9, R11 /* tmp += lo */
+ SGTU R9, R11, R2
+ ADDU R2, R8 /* hi += carry */
+ MOVW R11, 0(R6) /* p[i] = tmp */
+ ADDU $4, R6
+ MOVW R8, R10 /* oldhi = hi */
+ SUBU $1, R4
+ BNE R4, _muladdloop
+
+_muladd1:
+ MOVW 0(R6), R11 /* tmp = p[i] */
+ ADDU R10, R11 /* tmp += oldhi */
+ MOVW R11, 0(R6) /* p[i] = tmp */
+
+ RET
--- /dev/null
+++ b/libmp/Plan9-mips/mpvecdigmulsub.s
@@ -1,0 +1,61 @@
+/*
+ * mpvecdigmulsub(mpdigit *b, int n, mpdigit m, mpdigit *p)
+ *
+ * p -= b*m
+ *
+ * each step looks like:
+ * hi,lo = m*b[i]
+ * lo += oldhi + carry
+ * hi += carry
+ * p[i] += lo
+ * oldhi = hi
+ *
+ * the registers are:
+ * b = R1
+ * n = R4
+ * m = R5
+ * p = R6
+ * i = R7
+ * hi = R8 - constrained by hardware
+ * lo = R9 - constrained by hardware
+ * oldhi = R10
+ * tmp = R11
+ *
+ */
+TEXT mpvecdigmulsub(SB),$0
+
+ MOVW n+4(FP),R4
+ MOVW m+8(FP),R5
+ MOVW p+12(FP),R6
+
+ MOVW R0, R10 /* oldhi = 0 */
+_mulsubloop:
+ MOVW 0(R1), R9 /* lo = b[i] */
+ ADDU $4, R1
+ MOVW 0(R6), R11 /* tmp = p[i] */
+ MULU R9, R5
+ MOVW HI, R8 /* hi = (b[i] * m)>>32 */
+ MOVW LO, R9 /* lo = b[i] * m */
+ ADDU R10, R9 /* lo += oldhi */
+ SGTU R10, R9, R2
+ ADDU R2, R8 /* hi += carry */
+ SUBU R9, R11, R3 /* tmp -= lo */
+ SGTU R3, R11, R2
+ ADDU R2, R8 /* hi += carry */
+ MOVW R3, 0(R6) /* p[i] = tmp */
+ ADDU $4, R6
+ MOVW R8, R10 /* oldhi = hi */
+ SUBU $1, R4
+ BNE R4, _mulsubloop
+
+ MOVW 0(R6), R11 /* tmp = p[i] */
+ SUBU R10, R11, R3 /* tmp -= oldhi */
+ MOVW R3, 0(R6) /* p[i] = tmp */
+ SGTU R3, R11, R1
+ BNE R1, _mulsub2
+ MOVW $1, R1 /* return +1 for positive result */
+ RET
+
+_mulsub2:
+ MOVW $-1, R1 /* return -1 for negative result */
+ RET
--- /dev/null
+++ b/libmp/Plan9-mips/mpvecsub.s
@@ -1,0 +1,66 @@
+#define BDNZ BC 16,0,
+#define BDNE BC 0,2,
+
+/*
+ * mpvecadd(mpdigit *a, int alen, mpdigit *b, int blen, mpdigit *sum)
+ *
+ * sum[0:alen] = a[0:alen-1] - b[0:blen-1]
+ *
+ * prereq: alen >= blen, sum has room for alen+1 digits
+ *
+ * R1 == a (first arg passed in R1)
+ * R3 == carry
+ * R4 == alen
+ * R5 == b
+ * R6 == blen
+ * R7 == sum
+ * R2 == temporary
+ * R8 == temporary
+ * R9 == temporary
+ */
+TEXT mpvecsub(SB),$-4
+
+ MOVW alen+4(FP), R4
+ MOVW b+8(FP), R5
+ MOVW blen+12(FP), R6
+ MOVW sum+16(FP), R7
+ SUBU R6, R4 /* calculate counter for second loop (alen > blen) */
+ MOVW R0, R3
+
+ /* if blen == 0, don't need to subtract it */
+ BEQ R6,_sub1
+
+ /* sum[0:blen-1],carry = a[0:blen-1] - b[0:blen-1] */
+_subloop1:
+ MOVW 0(R1), R8
+ ADDU $4, R1
+ MOVW 0(R5), R9
+ ADDU $4, R5
+ SUBU R3, R8, R2
+ SGTU R2, R8, R3
+ SUBU R9, R2, R8
+ SGTU R8, R2, R9
+ ADDU R9, R3
+ MOVW R8, 0(R7)
+ ADDU $4, R7
+ SUBU $1, R6
+ BNE R6, _subloop1
+
+_sub1:
+ /* if alen == blen, we're done */
+ BEQ R4, _subend
+
+ /* sum[blen:alen-1],carry = a[blen:alen-1] + 0 + carry */
+_subloop2:
+ MOVW 0(R1), R8
+ ADDU $4, R1
+ SUBU R3, R8, R2
+ SGTU R2, R8, R3
+ MOVW R2, 0(R7)
+ ADDU $4, R7
+ SUBU $1, R4
+ BNE R4, _subloop2
+
+ /* sum[alen] = carry */
+_subend:
+ RET
--- /dev/null
+++ b/libmp/Plan9-power/mkfile
@@ -1,0 +1,20 @@
+objtype=power
+OBJTYPE=$objtype
+<../../mkconfig
+
+LIB=libmp.a
+SFILES=\
+ mpvecadd.s\
+ mpvecdigmuladd.s\
+ mpvecdigmulsub.s\
+ mpvecsub.s\
+
+HFILES=$ROOT/$SYSTARG/$OBJTYPE/include/u.h $ROOT/include/mp.h ../port/dat.h
+
+OFILES=${SFILES:%.s=%.$O}
+
+UPDATE=mkfile\
+ $HFILES\
+ $SFILES\
+
+<$ROOT/mkfiles/mksyslib-$SHELLTYPE
--- /dev/null
+++ b/libmp/Plan9-power/mpvecadd.s
@@ -1,0 +1,61 @@
+#define BDNZ BC 16,0,
+#define BDNE BC 0,2,
+
+/*
+ * mpvecadd(mpdigit *a, int alen, mpdigit *b, int blen, mpdigit *sum)
+ *
+ * sum[0:alen] = a[0:alen-1] + b[0:blen-1]
+ *
+ * prereq: alen >= blen, sum has room for alen+1 digits
+ *
+ * R3 == a (first arg passed in R3)
+ * R4 == alen
+ * R5 == b
+ * R6 == blen
+ * R7 == sum
+ * R8 == temporary
+ * R9 == temporary
+ */
+TEXT mpvecadd(SB),$-4
+
+ MOVW alen+4(FP), R4
+ MOVW b+8(FP), R5
+ MOVW blen+12(FP), R6
+ MOVW sum+16(FP), R7
+ SUB R6, R4 /* calculate counter for second loop (alen > blen) */
+ SUB $4, R3 /* pre decrement for MOVWU's */
+ SUB $4, R5 /* pre decrement for MOVWU's */
+ SUB $4, R7 /* pre decrement for MOVWU's */
+ MOVW R0, XER /* zero carry going in */
+
+ /* if blen == 0, don't need to add it in */
+ CMP R0, R6
+ BEQ _add1
+
+ /* sum[0:blen-1],carry = a[0:blen-1] + b[0:blen-1] */
+ MOVW R6, CTR
+_addloop1:
+ MOVWU 4(R3), R8
+ MOVWU 4(R5), R9
+ ADDE R8, R9
+ MOVWU R9, 4(R7)
+ BDNZ _addloop1
+
+_add1:
+ /* if alen == blen, we're done */
+ CMP R0, R4
+ BEQ _addend
+
+ /* sum[blen:alen-1],carry = a[blen:alen-1] + 0 + carry */
+ MOVW R4, CTR
+_addloop2:
+ MOVWU 4(R3), R8
+ ADDE R0, R8
+ MOVWU R8, 4(R7)
+ BDNZ _addloop2
+
+ /* sum[alen] = carry */
+_addend:
+ ADDE R0, R0, R8
+ MOVW R8, 4(R7)
+ RETURN
--- /dev/null
+++ b/libmp/Plan9-power/mpvecdigmuladd.s
@@ -1,0 +1,56 @@
+#define BDNZ BC 16,0,
+#define BDNE BC 0,2,
+
+/*
+ * mpvecdigmuladd(mpdigit *b, int n, mpdigit m, mpdigit *p)
+ *
+ * p += b*m
+ *
+ * each step looks like:
+ * hi,lo = m*b[i]
+ * lo += oldhi + carry
+ * hi += carry
+ * p[i] += lo
+ * oldhi = hi
+ *
+ * the registers are:
+ * b = R3
+ * n = R4
+ * m = R5
+ * p = R6
+ * i = R7
+ * hi = R8 - constrained by hardware
+ * lo = R9 - constrained by hardware
+ * oldhi = R10
+ * tmp = R11
+ *
+ */
+TEXT mpvecdigmuladd(SB),$0
+
+ MOVW n+4(FP),R4
+ MOVW m+8(FP),R5
+ MOVW p+12(FP),R6
+ SUB $4, R3 /* pre decrement for MOVWU's */
+ SUB $4, R6 /* pre decrement for MOVWU's */
+
+ MOVW R0, R10
+ MOVW R0, XER
+ MOVW R4, CTR
+_muladdloop:
+ MOVWU 4(R3),R9 /* lo = b[i] */
+ MOVW 4(R6),R11 /* tmp = p[i] */
+ MULHWU R9,R5,R8 /* hi = (b[i] * m)>>32 */
+ MULLW R9,R5,R9 /* lo = b[i] * m */
+ ADDC R10,R9 /* lo += oldhi */
+ ADDE R0,R8 /* hi += carry */
+ ADDC R9,R11 /* tmp += lo */
+ ADDE R0,R8 /* hi += carry */
+ MOVWU R11,4(R6) /* p[i] = tmp */
+ MOVW R8,R10 /* oldhi = hi */
+ BDNZ _muladdloop
+
+ MOVW 4(R6),R11 /* tmp = p[i] */
+ ADDC R10,R11
+ MOVWU R11,4(R6) /* p[i] = tmp */
+
+ RETURN
--- /dev/null
+++ b/libmp/Plan9-power/mpvecdigmulsub.s
@@ -1,0 +1,66 @@
+#define BDNZ BC 16,0,
+#define BDNE BC 0,2,
+#define BLT BC 0xC,0,
+
+/*
+ * mpvecdigmulsub(mpdigit *b, int n, mpdigit m, mpdigit *p)
+ *
+ * p -= b*m
+ *
+ * each step looks like:
+ * hi,lo = m*b[i]
+ * lo += oldhi + carry
+ * hi += carry
+ * p[i] += lo
+ * oldhi = hi
+ *
+ * the registers are:
+ * b = R3
+ * n = R4
+ * m = R5
+ * p = R6
+ * i = R7
+ * hi = R8 - constrained by hardware
+ * lo = R9 - constrained by hardware
+ * oldhi = R10
+ * tmp = R11
+ * borrow = R12
+ *
+ */
+TEXT mpvecdigmulsub(SB),$0
+
+ MOVW n+4(FP),R10
+ MOVW R10,CTR
+ MOVW m+8(FP),R5
+ MOVW p+12(FP),R6
+ SUB $4, R3 /* pre decrement for MOVWU's */
+ SUBC $4, R6 /* pre decrement for MOVWU's and set carry */
+ MOVW XER,R12
+
+ MOVW R0, R10
+
+_mulsubloop:
+ MOVWU 4(R3),R9 /* lo = b[i] */
+ MOVW 4(R6),R11 /* tmp = p[i] */
+ MULHWU R9,R5,R8 /* hi = (b[i] * m)>>32 */
+ MULLW R9,R5,R9 /* lo = b[i] * m */
+ ADDC R10,R9 /* lo += oldhi */
+ ADDE R0,R8 /* hi += carry */
+ MOVW R12,XER
+ SUBE R9,R11 /* tmp -= lo */
+ MOVW XER,R12
+ MOVWU R11,4(R6) /* p[i] = tmp */
+ MOVW R8,R10 /* oldhi = hi */
+ BDNZ _mulsubloop
+
+ MOVW 4(R6),R11 /* tmp = p[i] */
+ MOVW R12,XER
+ SUBE R10,R11 /* tmp -= lo */
+ MOVWU R11,4(R6) /* p[i] = tmp */
+
+ /* return -1 if the result was negative, +1 otherwise */
+ SUBECC R0,R0,R3
+ BLT _mulsub2
+ MOVW $1,R3
+_mulsub2:
+ RETURN
--- /dev/null
+++ b/libmp/Plan9-power/mpvecsub.s
@@ -1,0 +1,57 @@
+#define BDNZ BC 16,0,
+#define BDNE BC 0,2,
+
+/*
+ * mpvecsub(mpdigit *a, int alen, mpdigit *b, int blen, mpdigit *diff)
+ *
+ * diff[0:alen-1] = a[0:alen-1] - b[0:blen-1]
+ *
+ * prereq: alen >= blen, diff has room for alen digits
+ *
+ * R3 == a
+ * R4 == alen
+ * R5 == b
+ * R6 == blen
+ * R7 == diff
+ * R8 == temporary
+ * R9 == temporary
+ */
+TEXT mpvecsub(SB),$-4
+
+ MOVW alen+4(FP),R4
+ MOVW b+8(FP),R5
+ MOVW blen+12(FP),R6
+ MOVW diff+16(FP),R7
+ SUB R6, R4 /* calculate counter for second loop (alen > blen) */
+ SUB $4, R3 /* pre decrement for MOVWU's */
+ SUB $4, R5 /* pre decrement for MOVWU's */
+ SUBC $4, R7 /* pre decrement for MOVWU's and set carry */
+
+ /* skip subraction if b is zero */
+ CMP R0,R6
+ BEQ _sub1
+
+ /* diff[0:blen-1],borrow = a[0:blen-1] - b[0:blen-1] */
+ MOVW R6, CTR
+_subloop1:
+ MOVWU 4(R3), R8
+ MOVWU 4(R5), R9
+ SUBE R9, R8, R8
+ MOVWU R8, 4(R7)
+ BDNZ _subloop1
+
+_sub1:
+ /* skip subtraction if a is zero */
+ CMP R0, R4
+ BEQ _subend
+
+ /* diff[blen:alen-1] = a[blen:alen-1] - 0 + carry */
+ MOVW R4, CTR
+_subloop2:
+ MOVWU 4(R3), R8
+ SUBE R0, R8
+ MOVWU R8, 4(R7)
+ BDNZ _subloop2
+_subend:
+ RETURN
+
--- /dev/null
+++ b/libmp/bigtest.c
@@ -1,0 +1,102 @@
+#include <lib9.h>
+#include <mp.h>
+#include <libsec.h>
+
+char *sfactors[] =
+{ "3", "5", "17", "257", "641", "65537", "274177", "2424833", "6700417", "45592577",
+ "6487031809", "67280421310721", "1238926361552897", "59649589127497217",
+ "5704689200685129054721", "4659775785220018543264560743076778192897",
+ "7455602825647884208337395736200454918783366342657",
+ "93461639715357977769163558199606896584051237541638188580280321",
+
+ "741640062627530801524787141901937474059940781097519023905821316144415759504705008092818711693940737",
+
+ "130439874405488189727484768796509903946608530841611892186895295776832416251471863574140227977573104895898783928842923844831149032913798729088601617946094119449010595906710130531906171018354491609619193912488538116080712299672322806217820753127014424577"
+};
+
+long start;
+
+void
+printmp(mpint *b, char *tag)
+{
+ int n;
+ char *p;
+
+ print("%s (%d) ", tag, b->top);
+ p = mptoa(b, 10, nil, 0);
+ write(1, p, strlen(p));
+ free(p);
+ print("\n");
+}
+
+int
+timing(void)
+{
+ long now, span;
+
+ now = time(0);
+ span = now-start;
+ start = now;
+
+ return span;
+}
+
+int expdebug;
+
+
+void
+main(int argc, char **argv)
+{
+ mpint *p, *k, *d, *b, *e, *x, *r;
+ int i;
+
+ start = time(0);
+ fmtinstall('B', mpconv);
+ mpsetminbits(2*Dbits);
+
+ x = mpnew(0);
+ e = mpnew(0);
+ r = mpnew(0);
+ p = mpnew(0);
+
+ // b = 2^32
+ b = mpcopy(mpone);
+ mpleft(b, 32, b);
+
+ // 2^29440
+ p = mpcopy(mpone);
+ mpleft(p, 29440, p);
+ // 2^27392
+ k = mpcopy(mpone);
+ mpleft(k, 27392, k);
+ // k = 2^29440 - 2^27392
+ mpsub(p, k, k);
+ // p = 2^29440 - 2^27392 + 1
+ mpadd(k, mpone, p);
+
+// if(!probably_prime(p, 18)){
+// print("not a prime\n");
+// exits(0);
+// }
+// print("probably prime\n");
+
+ mpright(k, 10, k);
+ printmp(k, "k =");
+
+expdebug = 1;
+ mpexp(b, k, p, x);
+ printmp(x, "x =");
+ print("timing %d\n", timing());
+
+ for(i = 0; i < nelem(sfactors); i++){
+ d = strtomp(sfactors[i], nil, 10, nil);
+ // e = k/d
+ mpdiv(k, d, e, r);
+ printmp(r, "r =");
+
+ // x = b^e mod p
+ mpexp(b, e, p, x);
+ printmp(x, "x =");
+ print("timing %d\n", timing());
+ }
+}
--- /dev/null
+++ b/libmp/mkfile
@@ -1,0 +1,27 @@
+<../mkconfig
+
+# TARGMODEL not SYSTARG for now
+DIRS=port $TARGMODEL-$OBJTYPE
+
+<$ROOT/mkfiles/mklibsubdirs
+
+# the remainder are only intended for testing on a few system types
+test.$O: test.c $ROOT/$OBJDIR/include/lib9.h $ROOT/include/mp.h port/dat.h
+ $CC -Iport test.c
+
+$O.test: test.$O $ROOT/$OBJDIR/lib/libmp.a
+ $LD -o $O.test test.$O
+
+bigtest.$O: bigtest.c $ROOT/$OBJDIR/include/lib9.h $ROOT/include/mp.h port/dat.h
+ $CC -Iport bigtest.c
+
+$O.bigtest: bigtest.$O $ROOT/$OBJDIR/lib/libmp.a
+ $LD -o $O.bigtest bigtest.$O
+
+allout:
+ objtype=386; OBJTYPE=$objtype; mk; mk 8.test 8.bigtest
+ objtype=power; OBJTYPE=$objtype; mk; mk q.test q.bigtest
+ objtype=mips; OBJTYPE=$objtype; mk; mk v.test v.bigtest
+
+cleanout:
+ rm -f [qv8].* *.[qv8]
--- /dev/null
+++ b/libmp/mtest.c
@@ -1,0 +1,70 @@
+#include <u.h>
+#include <libc.h>
+#include <mp.h>
+#include "port/dat.h"
+
+int loops = 1;
+
+long randomreg;
+
+void
+srand(long seed)
+{
+ randomreg = seed;
+}
+
+long
+lrand(void)
+{
+ randomreg = randomreg*104381 + 81761;
+ return randomreg;
+}
+
+void
+prng(uchar *p, int n)
+{
+ while(n-- > 0)
+ *p++ = lrand();
+}
+
+
+void
+testshift(char *str)
+{
+ mpint *b1, *b2;
+ int i;
+
+ b1 = strtomp(str, nil, 16, nil);
+ malloccheck();
+fprint(2, "A");
+ b2 = mpnew(0);
+fprint(2, "B");
+ malloccheck();
+ mpleft(b1, 20, b2);
+fprint(2, "C");
+ malloccheck();
+ mpfree(b1);
+fprint(2, "D");
+ malloccheck();
+ mpfree(b2);
+}
+
+void
+main(int argc, char **argv)
+{
+ mpint *x, *y;
+
+ ARGBEGIN{
+ case 'n':
+ loops = atoi(ARGF());
+ break;
+ }ARGEND;
+
+ fmtinstall('B', mpfmt);
+ fmtinstall('Q', mpfmt);
+ srand(0);
+ mpsetminbits(2*Dbits);
+ testshift("1111111111111111");
+ print("done\n");
+ exits(0);
+}
--- /dev/null
+++ b/libmp/port/betomp.c
@@ -1,0 +1,40 @@
+#include "os.h"
+#include <mp.h>
+#include "dat.h"
+
+// convert a big-endian byte array (most significant byte first) to an mpint
+mpint*
+betomp(uchar *p, uint n, mpint *b)
+{
+ int m, s;
+ mpdigit x;
+
+ if(b == nil)
+ b = mpnew(0);
+
+ // dump leading zeros
+ while(*p == 0 && n > 1){
+ p++;
+ n--;
+ }
+
+ // get the space
+ mpbits(b, n*8);
+ b->top = DIGITS(n*8);
+ m = b->top-1;
+
+ // first digit might not be Dbytes long
+ s = ((n-1)*8)%Dbits;
+ x = 0;
+ for(; n > 0; n--){
+ x |= ((mpdigit)(*p++)) << s;
+ s -= 8;
+ if(s < 0){
+ b->p[m--] = x;
+ s = Dbits-8;
+ x = 0;
+ }
+ }
+
+ return b;
+}
--- /dev/null
+++ b/libmp/port/crt.c
@@ -1,0 +1,122 @@
+#include "os.h"
+#include <mp.h>
+#include <libsec.h>
+
+// chinese remainder theorem
+//
+// handbook of applied cryptography, menezes et al, 1997, pp 610 - 613
+
+struct CRTpre
+{
+ int n; // number of moduli
+ mpint **m; // pointer to moduli
+ mpint **c; // precomputed coefficients
+ mpint **p; // precomputed products
+ mpint *a[1]; // local storage
+};
+
+// setup crt info, returns a newly created structure
+CRTpre*
+crtpre(int n, mpint **m)
+{
+ CRTpre *crt;
+ int i, j;
+ mpint *u;
+
+ crt = malloc(sizeof(CRTpre)+sizeof(mpint)*3*n);
+ if(crt == nil)
+ sysfatal("crtpre: %r");
+ crt->m = crt->a;
+ crt->c = crt->a+n;
+ crt->p = crt->c+n;
+ crt->n = n;
+
+ // make a copy of the moduli
+ for(i = 0; i < n; i++)
+ crt->m[i] = mpcopy(m[i]);
+
+ // precompute the products
+ u = mpcopy(mpone);
+ for(i = 0; i < n; i++){
+ mpmul(u, m[i], u);
+ crt->p[i] = mpcopy(u);
+ }
+
+ // precompute the coefficients
+ for(i = 1; i < n; i++){
+ crt->c[i] = mpcopy(mpone);
+ for(j = 0; j < i; j++){
+ mpinvert(m[j], m[i], u);
+ mpmul(u, crt->c[i], u);
+ mpmod(u, m[i], crt->c[i]);
+ }
+ }
+
+ mpfree(u);
+
+ return crt;
+}
+
+void
+crtprefree(CRTpre *crt)
+{
+ int i;
+
+ for(i = 0; i < crt->n; i++){
+ if(i != 0)
+ mpfree(crt->c[i]);
+ mpfree(crt->p[i]);
+ mpfree(crt->m[i]);
+ }
+ free(crt);
+}
+
+// convert to residues, returns a newly created structure
+CRTres*
+crtin(CRTpre *crt, mpint *x)
+{
+ int i;
+ CRTres *res;
+
+ res = malloc(sizeof(CRTres)+sizeof(mpint)*crt->n);
+ if(res == nil)
+ sysfatal("crtin: %r");
+ res->n = crt->n;
+ for(i = 0; i < res->n; i++){
+ res->r[i] = mpnew(0);
+ mpmod(x, crt->m[i], res->r[i]);
+ }
+ return res;
+}
+
+// garners algorithm for converting residue form to linear
+void
+crtout(CRTpre *crt, CRTres *res, mpint *x)
+{
+ mpint *u;
+ int i;
+
+ u = mpnew(0);
+ mpassign(res->r[0], x);
+
+ for(i = 1; i < crt->n; i++){
+ mpsub(res->r[i], x, u);
+ mpmul(u, crt->c[i], u);
+ mpmod(u, crt->m[i], u);
+ mpmul(u, crt->p[i-1], u);
+ mpadd(x, u, x);
+ }
+
+ mpfree(u);
+}
+
+// free the residue
+void
+crtresfree(CRTres *res)
+{
+ int i;
+
+ for(i = 0; i < res->n; i++)
+ mpfree(res->r[i]);
+ free(res);
+}
--- /dev/null
+++ b/libmp/port/crttest.c
@@ -1,0 +1,54 @@
+#include "os.h"
+#include <mp.h>
+#include <libsec.h>
+
+void
+testcrt(mpint **p)
+{
+ CRTpre *crt;
+ CRTres *res;
+ mpint *m, *x, *y;
+ int i;
+
+ fmtinstall('B', mpconv);
+
+ // get a modulus and a test number
+ m = mpnew(1024+160);
+ mpmul(p[0], p[1], m);
+ x = mpnew(1024+160);
+ mpadd(m, mpone, x);
+
+ // do the precomputation for crt conversion
+ crt = crtpre(2, p);
+
+ // convert x to residues
+ res = crtin(crt, x);
+
+ // convert back
+ y = mpnew(1024+160);
+ crtout(crt, res, y);
+ print("x %B\ny %B\n", x, y);
+ mpfree(m);
+ mpfree(x);
+ mpfree(y);
+}
+
+void
+main(void)
+{
+ int i;
+ mpint *p[2];
+ long start;
+
+ start = time(0);
+ for(i = 0; i < 10; i++){
+ p[0] = mpnew(1024);
+ p[1] = mpnew(1024);
+ DSAprimes(p[0], p[1], nil);
+ testcrt(p);
+ mpfree(p[0]);
+ mpfree(p[1]);
+ }
+ print("%d secs with more\n", time(0)-start);
+ exits(0);
+}
--- /dev/null
+++ b/libmp/port/dat.h
@@ -1,0 +1,12 @@
+#define mpdighi (mpdigit)((ulong)1<<(Dbits-1))
+#define DIGITS(x) ((Dbits - 1 + (x))/Dbits)
+
+// for converting between int's and mpint's
+#define MAXUINT ((uint)-1)
+#define MAXINT (MAXUINT>>1)
+#define MININT (MAXINT+1)
+
+// for converting between vlongs's and mpint's
+#define MAXUVLONG (~(uvlong)0)
+#define MAXVLONG (MAXUVLONG>>1)
+#define MINVLONG (MAXVLONG+(uvlong)1)
--- /dev/null
+++ b/libmp/port/letomp.c
@@ -1,0 +1,28 @@
+#include "os.h"
+#include <mp.h>
+#include "dat.h"
+
+// convert a little endian byte array (least significant byte first) to an mpint
+mpint*
+letomp(uchar *s, uint n, mpint *b)
+{
+ int i=0, m = 0;
+ mpdigit x=0;
+
+ if(b == nil)
+ b = mpnew(0);
+ mpbits(b, 8*n);
+ for(; n > 0; n--){
+ x |= ((mpdigit)(*s++)) << i;
+ i += 8;
+ if(i == Dbits){
+ b->p[m++] = x;
+ i = 0;
+ x = 0;
+ }
+ }
+ if(i > 0)
+ b->p[m++] = x;
+ b->top = m;
+ return b;
+}
--- /dev/null
+++ b/libmp/port/mkfile
@@ -1,0 +1,52 @@
+<../../mkconfig
+
+LIB=libmp.a
+FILES=\
+ mpaux\
+ mpfmt\
+ strtomp\
+ mptobe\
+ mptole\
+ betomp\
+ letomp\
+ mpadd\
+ mpsub\
+ mpcmp\
+ mpfactorial\
+ mpmul\
+ mpleft\
+ mpright\
+ mpvecadd\
+ mpvecsub\
+ mpvecdigmuladd\
+ mpveccmp\
+ mpdigdiv\
+ mpdiv\
+ mpexp\
+ mpmod\
+ mpextendedgcd\
+ mpinvert\
+ mprand\
+ crt\
+ mptoi\
+ mptoui\
+ mptov\
+ mptouv\
+
+ALLOFILES=${FILES:%=%.$O}
+# cull things in the per-machine directories from this list
+OFILES= `{$SHELLNAME ./reduce-$SHELLTYPE $O $TARGMODEL-$OBJTYPE $ALLOFILES }
+
+HFILES=\
+ $ROOT/$OBJDIR/include/lib9.h\
+ $ROOT/include/mp.h\
+ dat.h\
+
+CFILES=${FILES:%=%.c}
+
+
+UPDATE=mkfile\
+ $HFILES\
+ $CFILES\
+
+<$ROOT/mkfiles/mksyslib-$SHELLTYPE
--- /dev/null
+++ b/libmp/port/mpadd.c
@@ -1,0 +1,54 @@
+#include "os.h"
+#include <mp.h>
+#include "dat.h"
+
+// sum = abs(b1) + abs(b2), i.e., add the magnitudes
+void
+mpmagadd(mpint *b1, mpint *b2, mpint *sum)
+{
+ int m, n;
+ mpint *t;
+
+ // get the sizes right
+ if(b2->top > b1->top){
+ t = b1;
+ b1 = b2;
+ b2 = t;
+ }
+ n = b1->top;
+ m = b2->top;
+ if(n == 0){
+ mpassign(mpzero, sum);
+ return;
+ }
+ if(m == 0){
+ mpassign(b1, sum);
+ return;
+ }
+ mpbits(sum, (n+1)*Dbits);
+ sum->top = n+1;
+
+ mpvecadd(b1->p, n, b2->p, m, sum->p);
+ sum->sign = 1;
+
+ mpnorm(sum);
+}
+
+// sum = b1 + b2
+void
+mpadd(mpint *b1, mpint *b2, mpint *sum)
+{
+ int sign;
+
+ if(b1->sign != b2->sign){
+ if(b1->sign < 0)
+ mpmagsub(b2, b1, sum);
+ else
+ mpmagsub(b1, b2, sum);
+ } else {
+ sign = b1->sign;
+ mpmagadd(b1, b2, sum);
+ if(sum->top != 0)
+ sum->sign = sign;
+ }
+}
--- /dev/null
+++ b/libmp/port/mpaux.c
@@ -1,0 +1,189 @@
+#include "os.h"
+#include <mp.h>
+#include "dat.h"
+
+static mpdigit _mptwodata[1] = { 2 };
+static mpint _mptwo =
+{
+ 1,
+ 1,
+ 1,
+ _mptwodata,
+ MPstatic
+};
+mpint *mptwo = &_mptwo;
+
+static mpdigit _mponedata[1] = { 1 };
+static mpint _mpone =
+{
+ 1,
+ 1,
+ 1,
+ _mponedata,
+ MPstatic
+};
+mpint *mpone = &_mpone;
+
+static mpdigit _mpzerodata[1] = { 0 };
+static mpint _mpzero =
+{
+ 1,
+ 1,
+ 0,
+ _mpzerodata,
+ MPstatic
+};
+mpint *mpzero = &_mpzero;
+
+static int mpmindigits = 33;
+
+// set minimum digit allocation
+void
+mpsetminbits(int n)
+{
+ if(n < 0)
+ sysfatal("mpsetminbits: n < 0");
+ if(n == 0)
+ n = 1;
+ mpmindigits = DIGITS(n);
+}
+
+// allocate an n bit 0'd number
+mpint*
+mpnew(int n)
+{
+ mpint *b;
+
+ if(n < 0)
+ sysfatal("mpsetminbits: n < 0");
+
+ b = mallocz(sizeof(mpint), 1);
+ if(b == nil)
+ sysfatal("mpnew: %r");
+ n = DIGITS(n);
+ if(n < mpmindigits)
+ n = mpmindigits;
+ b->p = (mpdigit*)mallocz(n*Dbytes, 1);
+ if(b->p == nil)
+ sysfatal("mpnew: %r");
+ b->size = n;
+ b->sign = 1;
+
+ return b;
+}
+
+// guarantee at least n significant bits
+void
+mpbits(mpint *b, int m)
+{
+ int n;
+
+ n = DIGITS(m);
+ if(b->size >= n){
+ if(b->top >= n)
+ return;
+ memset(&b->p[b->top], 0, Dbytes*(n - b->top));
+ b->top = n;
+ return;
+ }
+ b->p = (mpdigit*)realloc(b->p, n*Dbytes);
+ if(b->p == nil)
+ sysfatal("mpbits: %r");
+ memset(&b->p[b->top], 0, Dbytes*(n - b->top));
+ b->size = n;
+ b->top = n;
+}
+
+void
+mpfree(mpint *b)
+{
+ if(b == nil)
+ return;
+ if(b->flags & MPstatic)
+ sysfatal("freeing mp constant");
+ memset(b->p, 0, b->size*Dbytes); // information hiding
+ free(b->p);
+ free(b);
+}
+
+void
+mpnorm(mpint *b)
+{
+ int i;
+
+ for(i = b->top-1; i >= 0; i--)
+ if(b->p[i] != 0)
+ break;
+ b->top = i+1;
+ if(b->top == 0)
+ b->sign = 1;
+}
+
+mpint*
+mpcopy(mpint *old)
+{
+ mpint *new;
+
+ new = mpnew(Dbits*old->size);
+ new->top = old->top;
+ new->sign = old->sign;
+ memmove(new->p, old->p, Dbytes*old->top);
+ return new;
+}
+
+void
+mpassign(mpint *old, mpint *new)
+{
+ mpbits(new, Dbits*old->top);
+ new->sign = old->sign;
+ new->top = old->top;
+ memmove(new->p, old->p, Dbytes*old->top);
+}
+
+// number of significant bits in mantissa
+int
+mpsignif(mpint *n)
+{
+ int i, j;
+ mpdigit d;
+
+ if(n->top == 0)
+ return 0;
+ for(i = n->top-1; i >= 0; i--){
+ d = n->p[i];
+ for(j = Dbits-1; j >= 0; j--){
+ if(d & (((mpdigit)1)<<j))
+ return i*Dbits + j + 1;
+ }
+ }
+ return 0;
+}
+
+// k, where n = 2**k * q for odd q
+int
+mplowbits0(mpint *n)
+{
+ int k, bit, digit;
+ mpdigit d;
+
+ if(n->top==0)
+ return 0;
+ k = 0;
+ bit = 0;
+ digit = 0;
+ d = n->p[0];
+ for(;;){
+ if(d & (1<<bit))
+ break;
+ k++;
+ bit++;
+ if(bit==Dbits){
+ if(++digit >= n->top)
+ return 0;
+ d = n->p[digit];
+ bit = 0;
+ }
+ }
+ return k;
+}
+
--- /dev/null
+++ b/libmp/port/mpcmp.c
@@ -1,0 +1,28 @@
+#include "os.h"
+#include <mp.h>
+#include "dat.h"
+
+// return neg, 0, pos as abs(b1)-abs(b2) is neg, 0, pos
+int
+mpmagcmp(mpint *b1, mpint *b2)
+{
+ int i;
+
+ i = b1->top - b2->top;
+ if(i)
+ return i;
+
+ return mpveccmp(b1->p, b1->top, b2->p, b2->top);
+}
+
+// return neg, 0, pos as b1-b2 is neg, 0, pos
+int
+mpcmp(mpint *b1, mpint *b2)
+{
+ if(b1->sign != b2->sign)
+ return b1->sign - b2->sign;
+ if(b1->sign < 0)
+ return mpmagcmp(b2, b1);
+ else
+ return mpmagcmp(b1, b2);
+}
--- /dev/null
+++ b/libmp/port/mpdigdiv.c
@@ -1,0 +1,43 @@
+#include "os.h"
+#include <mp.h>
+#include "dat.h"
+
+//
+// divide two digits by one and return quotient
+//
+void
+mpdigdiv(mpdigit *dividend, mpdigit divisor, mpdigit *quotient)
+{
+ mpdigit hi, lo, q, x, y;
+ int i;
+
+ hi = dividend[1];
+ lo = dividend[0];
+
+ // return highest digit value if the result >= 2**32
+ if(hi >= divisor || divisor == 0){
+ divisor = 0;
+ *quotient = ~divisor;
+ return;
+ }
+
+ // at this point we know that hi < divisor
+ // just shift and subtract till we're done
+ q = 0;
+ x = divisor;
+ for(i = Dbits-1; hi > 0 && i >= 0; i--){
+ x >>= 1;
+ if(x > hi)
+ continue;
+ y = divisor<<i;
+ if(x == hi && y > lo)
+ continue;
+ if(y > lo)
+ hi--;
+ lo -= y;
+ hi -= x;
+ q |= 1<<i;
+ }
+ q += lo/divisor;
+ *quotient = q;
+}
--- /dev/null
+++ b/libmp/port/mpdiv.c
@@ -1,0 +1,112 @@
+#include "os.h"
+#include <mp.h>
+#include "dat.h"
+
+// division ala knuth, seminumerical algorithms, pp 237-238
+// the numbers are stored backwards to what knuth expects so j
+// counts down rather than up.
+
+void
+mpdiv(mpint *dividend, mpint *divisor, mpint *quotient, mpint *remainder)
+{
+ int j, s, vn, sign;
+ mpdigit qd, *up, *vp, *qp;
+ mpint *u, *v, *t;
+
+ // divide bv zero
+ if(divisor->top == 0)
+ sysfatal("mpdiv: divide by zero");
+
+ // quick check
+ if(mpmagcmp(dividend, divisor) < 0){
+ if(remainder != nil)
+ mpassign(dividend, remainder);
+ if(quotient != nil)
+ mpassign(mpzero, quotient);
+ return;
+ }
+
+ // D1: shift until divisor, v, has hi bit set (needed to make trial
+ // divisor accurate)
+ qd = divisor->p[divisor->top-1];
+ for(s = 0; (qd & mpdighi) == 0; s++)
+ qd <<= 1;
+ u = mpnew((dividend->top+2)*Dbits + s);
+ if(s == 0 && divisor != quotient && divisor != remainder) {
+ mpassign(dividend, u);
+ v = divisor;
+ } else {
+ mpleft(dividend, s, u);
+ v = mpnew(divisor->top*Dbits);
+ mpleft(divisor, s, v);
+ }
+ up = u->p+u->top-1;
+ vp = v->p+v->top-1;
+ vn = v->top;
+
+ // D1a: make sure high digit of dividend is less than high digit of divisor
+ if(*up >= *vp){
+ *++up = 0;
+ u->top++;
+ }
+
+ // storage for multiplies
+ t = mpnew(4*Dbits);
+
+ qp = nil;
+ if(quotient != nil){
+ mpbits(quotient, (u->top - v->top)*Dbits);
+ quotient->top = u->top - v->top;
+ qp = quotient->p+quotient->top-1;
+ }
+
+ // D2, D7: loop on length of dividend
+ for(j = u->top; j > vn; j--){
+
+ // D3: calculate trial divisor
+ mpdigdiv(up-1, *vp, &qd);
+
+ // D3a: rule out trial divisors 2 greater than real divisor
+ if(vn > 1) for(;;){
+ memset(t->p, 0, 3*Dbytes); // mpvecdigmuladd adds to what's there
+ mpvecdigmuladd(vp-1, 2, qd, t->p);
+ if(mpveccmp(t->p, 3, up-2, 3) > 0)
+ qd--;
+ else
+ break;
+ }
+
+ // D4: u -= v*qd << j*Dbits
+ sign = mpvecdigmulsub(v->p, vn, qd, up-vn);
+ if(sign < 0){
+
+ // D6: trial divisor was too high, add back borrowed
+ // value and decrease divisor
+ mpvecadd(up-vn, vn+1, v->p, vn, up-vn);
+ qd--;
+ }
+
+ // D5: save quotient digit
+ if(qp != nil)
+ *qp-- = qd;
+
+ // push top of u down one
+ u->top--;
+ *up-- = 0;
+ }
+ if(qp != nil){
+ mpnorm(quotient);
+ if(dividend->sign != divisor->sign)
+ quotient->sign = -1;
+ }
+
+ if(remainder != nil){
+ mpright(u, s, remainder); // u is the remainder shifted
+ remainder->sign = dividend->sign;
+ }
+
+ mpfree(t);
+ mpfree(u);
+ if(v != divisor)
+ mpfree(v);
+}
--- /dev/null
+++ b/libmp/port/mpeuclid.c
@@ -1,0 +1,85 @@
+#include "os.h"
+#include <mp.h>
+
+// extended euclid
+//
+// For a and b it solves, d = gcd(a,b) and finds x and y s.t.
+// ax + by = d
+//
+// Handbook of Applied Cryptography, Menezes et al, 1997, pg 67
+
+void
+mpeuclid(mpint *a, mpint *b, mpint *d, mpint *x, mpint *y)
+{
+ mpint *tmp, *x0, *x1, *x2, *y0, *y1, *y2, *q, *r;
+
+ if(a->sign<0 || b->sign<0)
+ sysfatal("mpeuclid: negative arg");
+
+ if(mpcmp(a, b) < 0){
+ tmp = a;
+ a = b;
+ b = tmp;
+ tmp = x;
+ x = y;
+ y = tmp;
+ }
+
+ if(b->top == 0){
+ mpassign(a, d);
+ mpassign(mpone, x);
+ mpassign(mpzero, y);
+ return;
+ }
+
+ a = mpcopy(a);
+ b = mpcopy(b);
+ x0 = mpnew(0);
+ x1 = mpcopy(mpzero);
+ x2 = mpcopy(mpone);
+ y0 = mpnew(0);
+ y1 = mpcopy(mpone);
+ y2 = mpcopy(mpzero);
+ q = mpnew(0);
+ r = mpnew(0);
+
+ while(b->top != 0 && b->sign > 0){
+ // q = a/b
+ // r = a mod b
+ mpdiv(a, b, q, r);
+ // x0 = x2 - qx1
+ mpmul(q, x1, x0);
+ mpsub(x2, x0, x0);
+ // y0 = y2 - qy1
+ mpmul(q, y1, y0);
+ mpsub(y2, y0, y0);
+ // rotate values
+ tmp = a;
+ a = b;
+ b = r;
+ r = tmp;
+ tmp = x2;
+ x2 = x1;
+ x1 = x0;
+ x0 = tmp;
+ tmp = y2;
+ y2 = y1;
+ y1 = y0;
+ y0 = tmp;
+ }
+
+ mpassign(a, d);
+ mpassign(x2, x);
+ mpassign(y2, y);
+
+ mpfree(x0);
+ mpfree(x1);
+ mpfree(x2);
+ mpfree(y0);
+ mpfree(y1);
+ mpfree(y2);
+ mpfree(q);
+ mpfree(r);
+ mpfree(a);
+ mpfree(b);
+}
--- /dev/null
+++ b/libmp/port/mpexp.c
@@ -1,0 +1,94 @@
+#include "os.h"
+#include <mp.h>
+#include "dat.h"
+
+// res = b**e
+//
+// knuth, vol 2, pp 398-400
+
+enum {
+ Freeb= 0x1,
+ Freee= 0x2,
+ Freem= 0x4,
+};
+
+//int expdebug;
+
+void
+mpexp(mpint *b, mpint *e, mpint *m, mpint *res)
+{
+ mpint *t[2];
+ int tofree;
+ mpdigit d, bit;
+ int i, j;
+
+ i = mpcmp(e,mpzero);
+ if(i==0){
+ mpassign(mpone, res);
+ return;
+ }
+ if(i<0)
+ sysfatal("mpexp: negative exponent");
+
+ t[0] = mpcopy(b);
+ t[1] = res;
+
+ tofree = 0;
+ if(res == b){
+ b = mpcopy(b);
+ tofree |= Freeb;
+ }
+ if(res == e){
+ e = mpcopy(e);
+ tofree |= Freee;
+ }
+ if(res == m){
+ m = mpcopy(m);
+ tofree |= Freem;
+ }
+
+ // skip first bit
+ i = e->top-1;
+ d = e->p[i];
+ for(bit = mpdighi; (bit & d) == 0; bit >>= 1)
+ ;
+ bit >>= 1;
+
+ j = 0;
+ for(;;){
+ for(; bit != 0; bit >>= 1){
+ mpmul(t[j], t[j], t[j^1]);
+ if(bit & d)
+ mpmul(t[j^1], b, t[j]);
+ else
+ j ^= 1;
+ if(m != nil && t[j]->top > m->top){
+ mpmod(t[j], m, t[j^1]);
+ j ^= 1;
+ }
+ }
+ if(--i < 0)
+ break;
+ bit = mpdighi;
+ d = e->p[i];
+ }
+ if(m != nil){
+ mpmod(t[j], m, t[j^1]);
+ j ^= 1;
+ }
+ if(t[j] == res){
+ mpfree(t[j^1]);
+ } else {
+ mpassign(t[j], res);
+ mpfree(t[j]);
+ }
+
+ if(tofree){
+ if(tofree & Freeb)
+ mpfree(b);
+ if(tofree & Freee)
+ mpfree(e);
+ if(tofree & Freem)
+ mpfree(m);
+ }
+}
--- /dev/null
+++ b/libmp/port/mpextendedgcd.c
@@ -1,0 +1,104 @@
+#include "os.h"
+#include <mp.h>
+
+#define iseven(a) (((a)->p[0] & 1) == 0)
+
+// extended binary gcd
+//
+// For a anv b it solves, v = gcd(a,b) and finds x and y s.t.
+// ax + by = v
+//
+// Handbook of Applied Cryptography, Menezes et al, 1997, pg 608.
+void
+mpextendedgcd(mpint *a, mpint *b, mpint *v, mpint *x, mpint *y)
+{
+ mpint *u, *A, *B, *C, *D;
+ int g;
+
+ if(a->sign < 0 || b->sign < 0){
+ mpassign(mpzero, v);
+ mpassign(mpzero, y);
+ mpassign(mpzero, x);
+ return;
+ }
+
+ if(a->top == 0){
+ mpassign(b, v);
+ mpassign(mpone, y);
+ mpassign(mpzero, x);
+ return;
+ }
+ if(b->top == 0){
+ mpassign(a, v);
+ mpassign(mpone, x);
+ mpassign(mpzero, y);
+ return;
+ }
+
+ g = 0;
+ a = mpcopy(a);
+ b = mpcopy(b);
+
+ while(iseven(a) && iseven(b)){
+ mpright(a, 1, a);
+ mpright(b, 1, b);
+ g++;
+ }
+
+ u = mpcopy(a);
+ mpassign(b, v);
+ A = mpcopy(mpone);
+ B = mpcopy(mpzero);
+ C = mpcopy(mpzero);
+ D = mpcopy(mpone);
+
+ for(;;) {
+// print("%B %B %B %B %B %B\n", u, v, A, B, C, D);
+ while(iseven(u)){
+ mpright(u, 1, u);
+ if(!iseven(A) || !iseven(B)) {
+ mpadd(A, b, A);
+ mpsub(B, a, B);
+ }
+ mpright(A, 1, A);
+ mpright(B, 1, B);
+ }
+
+// print("%B %B %B %B %B %B\n", u, v, A, B, C, D);
+ while(iseven(v)){
+ mpright(v, 1, v);
+ if(!iseven(C) || !iseven(D)) {
+ mpadd(C, b, C);
+ mpsub(D, a, D);
+ }
+ mpright(C, 1, C);
+ mpright(D, 1, D);
+ }
+
+// print("%B %B %B %B %B %B\n", u, v, A, B, C, D);
+ if(mpcmp(u, v) >= 0){
+ mpsub(u, v, u);
+ mpsub(A, C, A);
+ mpsub(B, D, B);
+ } else {
+ mpsub(v, u, v);
+ mpsub(C, A, C);
+ mpsub(D, B, D);
+ }
+
+ if(u->top == 0)
+ break;
+
+ }
+ mpassign(C, x);
+ mpassign(D, y);
+ mpleft(v, g, v);
+
+ mpfree(A);
+ mpfree(B);
+ mpfree(C);
+ mpfree(D);
+ mpfree(u);
+ mpfree(a);
+ mpfree(b);
+}
--- /dev/null
+++ b/libmp/port/mpfactorial.c
@@ -1,0 +1,79 @@
+#include "os.h"
+#include <mp.h>
+#include <libsec.h>
+#include "dat.h"
+
+mpint*
+mpfactorial(ulong n)
+{
+ int i;
+ ulong k;
+ unsigned cnt;
+ int max, mmax;
+ mpdigit p, pp[2];
+ mpint *r, *s, *stk[31];
+
+ cnt = 0;
+ max = mmax = -1;
+ p = 1;
+ r = mpnew(0);
+ for(k=2; k<=n; k++){
+ pp[0] = 0;
+ pp[1] = 0;
+ mpvecdigmuladd(&p, 1, (mpdigit)k, pp);
+ if(pp[1] == 0) /* !overflow */
+ p = pp[0];
+ else{
+ cnt++;
+ if((cnt & 1) == 0){
+ s = stk[max];
+ mpbits(r, Dbits*(s->top+1+1));
+ memset(r->p, 0, Dbytes*(s->top+1+1));
+ mpvecmul(s->p, s->top, &p, 1, r->p);
+ r->sign = 1;
+ r->top = s->top+1+1; /* XXX: norm */
+ mpassign(r, s);
+ for(i=4; (cnt & (i-1)) == 0; i=i<<1){
+ mpmul(stk[max], stk[max-1], r);
+ mpassign(r, stk[max-1]);
+ max--;
+ }
+ }else{
+ max++;
+ if(max > mmax){
+ mmax++;
+ if(max >= nelem(stk)){
+ while(--max >= 0)
+ mpfree(stk[max]);
+ mpfree(r);
+ sysfatal("mpfactorial: stack overflow");
+ }
+ stk[max] = mpnew(Dbits);
+ }
+ stk[max]->top = 1;
+ stk[max]->p[0] = p;
+ }
+ p = (mpdigit)k;
+ }
+ }
+ if(max < 0){
+ mpbits(r, Dbits);
+ r->top = 1;
+ r->sign = 1;
+ r->p[0] = p;
+ }else{
+ s = stk[max--];
+ mpbits(r, Dbits*(s->top+1+1));
+ memset(r->p, 0, Dbytes*(s->top+1+1));
+ mpvecmul(s->p, s->top, &p, 1, r->p);
+ r->sign = 1;
+ r->top = s->top+1+1; /* XXX: norm */
+ }
+
+ while(max >= 0)
+ mpmul(r, stk[max--], r);
+ for(max=mmax; max>=0; max--)
+ mpfree(stk[max]);
+ mpnorm(r);
+ return r;
+}
--- /dev/null
+++ b/libmp/port/mpfmt.c
@@ -1,0 +1,193 @@
+#include "os.h"
+#include <mp.h>
+#include <libsec.h>
+#include "dat.h"
+
+static int
+to64(mpint *b, char *buf, int len)
+{
+ uchar *p;
+ int n, rv;
+
+ p = nil;
+ n = mptobe(b, nil, 0, &p);
+ if(n < 0)
+ return -1;
+ rv = enc64(buf, len, p, n);
+ free(p);
+ return rv;
+}
+
+static int
+to32(mpint *b, char *buf, int len)
+{
+ uchar *p;
+ int n, rv;
+
+ // leave room for a multiple of 5 buffer size
+ n = b->top*Dbytes + 5;
+ p = malloc(n);
+ if(p == nil)
+ return -1;
+ n = mptobe(b, p, n, nil);
+ if(n < 0)
+ return -1;
+
+ // round up buffer size, enc32 only accepts a multiple of 5
+ if(n%5)
+ n += 5 - (n%5);
+ rv = enc32(buf, len, p, n);
+ free(p);
+ return rv;
+}
+
+static char set16[] = "0123456789ABCDEF";
+
+static int
+to16(mpint *b, char *buf, int len)
+{
+ mpdigit *p, x;
+ int i, j;
+ char *out, *eout;
+
+ if(len < 1)
+ return -1;
+
+ out = buf;
+ eout = buf+len;
+ for(p = &b->p[b->top-1]; p >= b->p; p--){
+ x = *p;
+ for(i = Dbits-4; i >= 0; i -= 4){
+ j = 0xf & (x>>i);
+ if(j != 0 || out != buf){
+ if(out >= eout)
+ return -1;
+ *out++ = set16[j];
+ }
+ }
+ }
+ if(out == buf)
+ *out++ = '0';
+ if(out >= eout)
+ return -1;
+ *out = 0;
+ return 0;
+}
+
+static char*
+modbillion(int rem, ulong r, char *out, char *buf)
+{
+ ulong rr;
+ int i;
+
+ for(i = 0; i < 9; i++){
+ rr = r%10;
+ r /= 10;
+ if(out <= buf)
+ return nil;
+ *--out = '0' + rr;
+ if(rem == 0 && r == 0)
+ break;
+ }
+ return out;
+}
+
+static int
+to10(mpint *b, char *buf, int len)
+{
+ mpint *d, *r, *billion;
+ char *out;
+
+ if(len < 1)
+ return -1;
+
+ d = mpcopy(b);
+ r = mpnew(0);
+ billion = uitomp(1000000000, nil);
+ out = buf+len;
+ *--out = 0;
+ do {
+ mpdiv(d, billion, d, r);
+ out = modbillion(d->top, r->p[0], out, buf);
+ if(out == nil)
+ break;
+ } while(d->top != 0);
+ mpfree(d);
+ mpfree(r);
+ mpfree(billion);
+
+ if(out == nil)
+ return -1;
+ len -= out-buf;
+ if(out != buf)
+ memmove(buf, out, len);
+ return 0;
+}
+
+int
+mpfmt(Fmt *fmt)
+{
+ mpint *b;
+ char *p;
+
+ b = va_arg(fmt->args, mpint*);
+ if(b == nil)
+ return fmtstrcpy(fmt, "*");
+
+ p = mptoa(b, fmt->prec, nil, 0);
+ fmt->flags &= ~FmtPrec;
+
+ if(p == nil)
+ return fmtstrcpy(fmt, "*");
+ else{
+ fmtstrcpy(fmt, p);
+ free(p);
+ return 0;
+ }
+}
+
+char*
+mptoa(mpint *b, int base, char *buf, int len)
+{
+ char *out;
+ int rv, alloced;
+
+ alloced = 0;
+ if(buf == nil){
+ len = ((b->top+1)*Dbits+2)/3 + 1;
+ buf = malloc(len);
+ if(buf == nil)
+ return nil;
+ alloced = 1;
+ }
+
+ if(len < 2)
+ return nil;
+
+ out = buf;
+ if(b->sign < 0){
+ *out++ = '-';
+ len--;
+ }
+ switch(base){
+ case 64:
+ rv = to64(b, out, len);
+ break;
+ case 32:
+ rv = to32(b, out, len);
+ break;
+ default:
+ case 16:
+ rv = to16(b, out, len);
+ break;
+ case 10:
+ rv = to10(b, out, len);
+ break;
+ }
+ if(rv < 0){
+ if(alloced)
+ free(buf);
+ return nil;
+ }
+ return buf;
+}
--- /dev/null
+++ b/libmp/port/mpinvert.c
@@ -1,0 +1,23 @@
+#include "os.h"
+#include <mp.h>
+
+#define iseven(a) (((a)->p[0] & 1) == 0)
+
+// use extended gcd to find the multiplicative inverse
+// res = b**-1 mod m
+void
+mpinvert(mpint *b, mpint *m, mpint *res)
+{
+ mpint *dc1, *dc2; // don't care
+ int r;
+
+ dc1 = mpnew(0);
+ dc2 = mpnew(0);
+ mpextendedgcd(b, m, dc1, res, dc2);
+ r = mpcmp(dc1, mpone);
+ mpfree(dc1);
+ mpfree(dc2);
+ if(r != 0)
+ sysfatal("mpinvert: no inverse");
+ mpmod(res, m, res);
+}
--- /dev/null
+++ b/libmp/port/mpleft.c
@@ -1,0 +1,52 @@
+#include "os.h"
+#include <mp.h>
+#include "dat.h"
+
+// res = b << shift
+void
+mpleft(mpint *b, int shift, mpint *res)
+{
+ int d, l, r, i, otop;
+ mpdigit this, last;
+
+ res->sign = b->sign;
+ if(b->top==0){
+ res->top = 0;
+ return;
+ }
+
+ // a negative left shift is a right shift
+ if(shift < 0){
+ mpright(b, -shift, res);
+ return;
+ }
+
+ // b and res may be the same so remember the old top
+ otop = b->top;
+
+ // shift
+ mpbits(res, otop*Dbits + shift); // overkill
+ res->top = DIGITS(otop*Dbits + shift);
+ d = shift/Dbits;
+ l = shift - d*Dbits;
+ r = Dbits - l;
+
+ if(l == 0){
+ for(i = otop-1; i >= 0; i--)
+ res->p[i+d] = b->p[i];
+ } else {
+ last = 0;
+ for(i = otop-1; i >= 0; i--) {
+ this = b->p[i];
+ res->p[i+d+1] = (last<<l) | (this>>r);
+ last = this;
+ }
+ res->p[d] = last<<l;
+ }
+ for(i = 0; i < d; i++)
+ res->p[i] = 0;
+
+ // normalize
+ while(res->top > 0 && res->p[res->top-1] == 0)
+ res->top--;
+}
--- /dev/null
+++ b/libmp/port/mpmod.c
@@ -1,0 +1,15 @@
+#include "os.h"
+#include <mp.h>
+#include "dat.h"
+
+// remainder = b mod m
+//
+// knuth, vol 2, pp 398-400
+
+void
+mpmod(mpint *b, mpint *m, mpint *remainder)
+{
+ mpdiv(b, m, nil, remainder);
+ if(remainder->sign < 0)
+ mpadd(m, remainder, remainder);
+}
--- /dev/null
+++ b/libmp/port/mpmul.c
@@ -1,0 +1,156 @@
+#include "os.h"
+#include <mp.h>
+#include "dat.h"
+
+//
+// from knuth's 1969 seminumberical algorithms, pp 233-235 and pp 258-260
+//
+// mpvecmul is an assembly language routine that performs the inner
+// loop.
+//
+// the karatsuba trade off is set empiricly by measuring the algs on
+// a 400 MHz Pentium II.
+//
+
+// karatsuba like (see knuth pg 258)
+// prereq: p is already zeroed
+static void
+mpkaratsuba(mpdigit *a, int alen, mpdigit *b, int blen, mpdigit *p)
+{
+ mpdigit *t, *u0, *u1, *v0, *v1, *u0v0, *u1v1, *res, *diffprod;
+ int u0len, u1len, v0len, v1len, reslen;
+ int sign, n;
+
+ // divide each piece in half
+ n = alen/2;
+ if(alen&1)
+ n++;
+ u0len = n;
+ u1len = alen-n;
+ if(blen > n){
+ v0len = n;
+ v1len = blen-n;
+ } else {
+ v0len = blen;
+ v1len = 0;
+ }
+ u0 = a;
+ u1 = a + u0len;
+ v0 = b;
+ v1 = b + v0len;
+
+ // room for the partial products
+ t = mallocz(Dbytes*5*(2*n+1), 1);
+ if(t == nil)
+ sysfatal("mpkaratsuba: %r");
+ u0v0 = t;
+ u1v1 = t + (2*n+1);
+ diffprod = t + 2*(2*n+1);
+ res = t + 3*(2*n+1);
+ reslen = 4*n+1;
+
+ // t[0] = (u1-u0)
+ sign = 1;
+ if(mpveccmp(u1, u1len, u0, u0len) < 0){
+ sign = -1;
+ mpvecsub(u0, u0len, u1, u1len, u0v0);
+ } else
+ mpvecsub(u1, u1len, u0, u1len, u0v0);
+
+ // t[1] = (v0-v1)
+ if(mpveccmp(v0, v0len, v1, v1len) < 0){
+ sign *= -1;
+ mpvecsub(v1, v1len, v0, v1len, u1v1);
+ } else
+ mpvecsub(v0, v0len, v1, v1len, u1v1);
+
+ // t[4:5] = (u1-u0)*(v0-v1)
+ mpvecmul(u0v0, u0len, u1v1, v0len, diffprod);
+
+ // t[0:1] = u1*v1
+ memset(t, 0, 2*(2*n+1)*Dbytes);
+ if(v1len > 0)
+ mpvecmul(u1, u1len, v1, v1len, u1v1);
+
+ // t[2:3] = u0v0
+ mpvecmul(u0, u0len, v0, v0len, u0v0);
+
+ // res = u0*v0<<n + u0*v0
+ mpvecadd(res, reslen, u0v0, u0len+v0len, res);
+ mpvecadd(res+n, reslen-n, u0v0, u0len+v0len, res+n);
+
+ // res += u1*v1<<n + u1*v1<<2*n
+ if(v1len > 0){
+ mpvecadd(res+n, reslen-n, u1v1, u1len+v1len, res+n);
+ mpvecadd(res+2*n, reslen-2*n, u1v1, u1len+v1len, res+2*n);
+ }
+
+ // res += (u1-u0)*(v0-v1)<<n
+ if(sign < 0)
+ mpvecsub(res+n, reslen-n, diffprod, u0len+v0len, res+n);
+ else
+ mpvecadd(res+n, reslen-n, diffprod, u0len+v0len, res+n);
+ memmove(p, res, (alen+blen)*Dbytes);
+
+ free(t);
+}
+
+#define KARATSUBAMIN 32
+
+void
+mpvecmul(mpdigit *a, int alen, mpdigit *b, int blen, mpdigit *p)
+{
+ int i;
+ mpdigit d;
+ mpdigit *t;
+
+ // both mpvecdigmuladd and karatsuba are fastest when a is the longer vector
+ if(alen < blen){
+ i = alen;
+ alen = blen;
+ blen = i;
+ t = a;
+ a = b;
+ b = t;
+ }
+ if(blen == 0){
+ memset(p, 0, Dbytes*(alen+blen));
+ return;
+ }
+
+ if(alen >= KARATSUBAMIN && blen > 1){
+ // O(n^1.585)
+ mpkaratsuba(a, alen, b, blen, p);
+ } else {
+ // O(n^2)
+ for(i = 0; i < blen; i++){
+ d = b[i];
+ if(d != 0)
+ mpvecdigmuladd(a, alen, d, &p[i]);
+ }
+ }
+}
+
+void
+mpmul(mpint *b1, mpint *b2, mpint *prod)
+{
+ mpint *oprod;
+
+ oprod = nil;
+ if(prod == b1 || prod == b2){
+ oprod = prod;
+ prod = mpnew(0);
+ }
+
+ prod->top = 0;
+ mpbits(prod, (b1->top+b2->top+1)*Dbits);
+ mpvecmul(b1->p, b1->top, b2->p, b2->top, prod->p);
+ prod->top = b1->top+b2->top+1;
+ prod->sign = b1->sign*b2->sign;
+ mpnorm(prod);
+
+ if(oprod != nil){
+ mpassign(prod, oprod);
+ mpfree(prod);
+ }
+}
--- /dev/null
+++ b/libmp/port/mprand.c
@@ -1,0 +1,42 @@
+#include "os.h"
+#include <mp.h>
+#include <libsec.h>
+#include "dat.h"
+
+mpint*
+mprand(int bits, void (*gen)(uchar*, int), mpint *b)
+{
+ int n, m;
+ mpdigit mask;
+ uchar *p;
+
+ n = DIGITS(bits);
+ if(b == nil)
+ b = mpnew(bits);
+ else
+ mpbits(b, bits);
+
+ p = malloc(n*Dbytes);
+ if(p == nil)
+ return nil;
+ (*gen)(p, n*Dbytes);
+ betomp(p, n*Dbytes, b);
+ free(p);
+
+ // make sure we don't give too many bits
+ m = bits%Dbits;
+ n--;
+ if(m > 0){
+ mask = 1;
+ mask <<= m;
+ mask--;
+ b->p[n] &= mask;
+ }
+
+ for(; n >= 0; n--)
+ if(b->p[n] != 0)
+ break;
+ b->top = n+1;
+ b->sign = 1;
+ return b;
+}
--- /dev/null
+++ b/libmp/port/mpright.c
@@ -1,0 +1,54 @@
+#include "os.h"
+#include <mp.h>
+#include "dat.h"
+
+// res = b >> shift
+void
+mpright(mpint *b, int shift, mpint *res)
+{
+ int d, l, r, i;
+ mpdigit this, last;
+
+ res->sign = b->sign;
+ if(b->top==0){
+ res->top = 0;
+ return;
+ }
+
+ // a negative right shift is a left shift
+ if(shift < 0){
+ mpleft(b, -shift, res);
+ return;
+ }
+
+ if(res != b)
+ mpbits(res, b->top*Dbits - shift);
+ d = shift/Dbits;
+ r = shift - d*Dbits;
+ l = Dbits - r;
+
+ // shift all the bits out == zero
+ if(d>=b->top){
+ res->top = 0;
+ return;
+ }
+
+ // special case digit shifts
+ if(r == 0){
+ for(i = 0; i < b->top-d; i++)
+ res->p[i] = b->p[i+d];
+ } else {
+ last = b->p[d];
+ for(i = 0; i < b->top-d-1; i++){
+ this = b->p[i+d+1];
+ res->p[i] = (this<<l) | (last>>r);
+ last = this;
+ }
+ res->p[i++] = last>>r;
+ }
+ while(i > 0 && res->p[i-1] == 0)
+ i--;
+ res->top = i;
+ if(i==0)
+ res->sign = 1;
+}
--- /dev/null
+++ b/libmp/port/mpsub.c
@@ -1,0 +1,52 @@
+#include "os.h"
+#include <mp.h>
+#include "dat.h"
+
+// diff = abs(b1) - abs(b2), i.e., subtract the magnitudes
+void
+mpmagsub(mpint *b1, mpint *b2, mpint *diff)
+{
+ int n, m, sign;
+ mpint *t;
+
+ // get the sizes right
+ if(mpmagcmp(b1, b2) < 0){
+ sign = -1;
+ t = b1;
+ b1 = b2;
+ b2 = t;
+ } else
+ sign = 1;
+ n = b1->top;
+ m = b2->top;
+ if(m == 0){
+ mpassign(b1, diff);
+ diff->sign = sign;
+ return;
+ }
+ mpbits(diff, n*Dbits);
+
+ mpvecsub(b1->p, n, b2->p, m, diff->p);
+ diff->sign = sign;
+ diff->top = n;
+ mpnorm(diff);
+}
+
+// diff = b1 - b2
+void
+mpsub(mpint *b1, mpint *b2, mpint *diff)
+{
+ int sign;
+
+ if(b1->sign != b2->sign){
+ sign = b1->sign;
+ mpmagadd(b1, b2, diff);
+ diff->sign = sign;
+ return;
+ }
+
+ sign = b1->sign;
+ mpmagsub(b1, b2, diff);
+ if(diff->top != 0)
+ diff->sign *= sign;
+}
--- /dev/null
+++ b/libmp/port/mptobe.c
@@ -1,0 +1,57 @@
+#include "os.h"
+#include <mp.h>
+#include "dat.h"
+
+// convert an mpint into a big endian byte array (most significant byte first)
+// return number of bytes converted
+// if p == nil, allocate and result array
+int
+mptobe(mpint *b, uchar *p, uint n, uchar **pp)
+{
+ int i, j, suppress;
+ mpdigit x;
+ uchar *e, *s, c;
+
+ if(p == nil){
+ n = (b->top+1)*Dbytes;
+ p = malloc(n);
+ }
+ if(p == nil)
+ return -1;
+ if(pp != nil)
+ *pp = p;
+ memset(p, 0, n);
+
+ // special case 0
+ if(b->top == 0){
+ if(n < 1)
+ return -1;
+ else
+ return 1;
+ }
+
+ s = p;
+ e = s+n;
+ suppress = 1;
+ for(i = b->top-1; i >= 0; i--){
+ x = b->p[i];
+ for(j = Dbits-8; j >= 0; j -= 8){
+ c = x>>j;
+ if(c == 0 && suppress)
+ continue;
+ if(p >= e)
+ return -1;
+ *p++ = c;
+ suppress = 0;
+ }
+ }
+
+ // guarantee at least one byte
+ if(s == p){
+ if(p >= e)
+ return -1;
+ *p++ = 0;
+ }
+
+ return p - s;
+}
--- /dev/null
+++ b/libmp/port/mptoi.c
@@ -1,0 +1,46 @@
+#include "os.h"
+#include <mp.h>
+#include "dat.h"
+
+/*
+ * this code assumes that mpdigit is at least as
+ * big as an int.
+ */
+
+mpint*
+itomp(int i, mpint *b)
+{
+ if(b == nil)
+ b = mpnew(0);
+ mpassign(mpzero, b);
+ if(i != 0)
+ b->top = 1;
+ if(i < 0){
+ b->sign = -1;
+ *b->p = -i;
+ } else
+ *b->p = i;
+ return b;
+}
+
+int
+mptoi(mpint *b)
+{
+ uint x;
+
+ if(b->top==0)
+ return 0;
+ x = *b->p;
+ if(b->sign > 0){
+ if(b->top > 1 || (x > MAXINT))
+ x = (int)MAXINT;
+ else
+ x = (int)x;
+ } else {
+ if(b->top > 1 || x > MAXINT+1)
+ x = (int)MININT;
+ else
+ x = -(int)x;
+ }
+ return x;
+}
--- /dev/null
+++ b/libmp/port/mptole.c
@@ -1,0 +1,54 @@
+#include "os.h"
+#include <mp.h>
+#include "dat.h"
+
+// convert an mpint into a little endian byte array (least significant byte first)
+
+// return number of bytes converted
+// if p == nil, allocate and result array
+int
+mptole(mpint *b, uchar *p, uint n, uchar **pp)
+{
+ int i, j;
+ mpdigit x;
+ uchar *e, *s;
+
+ if(p == nil){
+ n = (b->top+1)*Dbytes;
+ p = malloc(n);
+ }
+ if(pp != nil)
+ *pp = p;
+ if(p == nil)
+ return -1;
+ memset(p, 0, n);
+
+ // special case 0
+ if(b->top == 0){
+ if(n < 1)
+ return -1;
+ else
+ return 0;
+ }
+
+ s = p;
+ e = s+n;
+ for(i = 0; i < b->top-1; i++){
+ x = b->p[i];
+ for(j = 0; j < Dbytes; j++){
+ if(p >= e)
+ return -1;
+ *p++ = x;
+ x >>= 8;
+ }
+ }
+ x = b->p[i];
+ while(x > 0){
+ if(p >= e)
+ return -1;
+ *p++ = x;
+ x >>= 8;
+ }
+
+ return p - s;
+}
--- /dev/null
+++ b/libmp/port/mptoui.c
@@ -1,0 +1,33 @@
+#include "os.h"
+#include <mp.h>
+#include "dat.h"
+
+/*
+ * this code assumes that mpdigit is at least as
+ * big as an int.
+ */
+
+mpint*
+uitomp(uint i, mpint *b)
+{
+ if(b == nil)
+ b = mpnew(0);
+ mpassign(mpzero, b);
+ if(i != 0)
+ b->top = 1;
+ *b->p = i;
+ return b;
+}
+
+uint
+mptoui(mpint *b)
+{
+ uint x;
+
+ x = *b->p;
+ if(b->sign < 0)
+ x = 0;
+ else if(b->top > 1 || (sizeof(mpdigit) > sizeof(uint) && x > MAXUINT))
+ x = MAXUINT;
+ return x;
+}
--- /dev/null
+++ b/libmp/port/mptouv.c
@@ -1,0 +1,49 @@
+#include "os.h"
+#include <mp.h>
+#include "dat.h"
+
+#define VLDIGITS (sizeof(vlong)/sizeof(mpdigit))
+
+/*
+ * this code assumes that a vlong is an integral number of
+ * mpdigits long.
+ */
+mpint*
+uvtomp(uvlong v, mpint *b)
+{
+ int s;
+
+ if(b == nil)
+ b = mpnew(VLDIGITS*sizeof(mpdigit));
+ else
+ mpbits(b, VLDIGITS*sizeof(mpdigit));
+ mpassign(mpzero, b);
+ if(v == 0)
+ return b;
+ for(s = 0; s < VLDIGITS && v != 0; s++){
+ b->p[s] = v;
+ v >>= sizeof(mpdigit)*8;
+ }
+ b->top = s;
+ return b;
+}
+
+uvlong
+mptouv(mpint *b)
+{
+ uvlong v;
+ int s;
+
+ if(b->top == 0)
+ return 0;
+
+ mpnorm(b);
+ if(b->top > VLDIGITS)
+ return MAXVLONG;
+
+ v = 0;
+ for(s = 0; s < b->top; s++)
+ v |= (uvlong)b->p[s]<<(s*sizeof(mpdigit)*8);
+
+ return v;
+}
--- /dev/null
+++ b/libmp/port/mptov.c
@@ -1,0 +1,69 @@
+#include "os.h"
+#include <mp.h>
+#include "dat.h"
+
+#define VLDIGITS (sizeof(vlong)/sizeof(mpdigit))
+
+/*
+ * this code assumes that a vlong is an integral number of
+ * mpdigits long.
+ */
+mpint*
+vtomp(vlong v, mpint *b)
+{
+ int s;
+ uvlong uv;
+
+ if(b == nil)
+ b = mpnew(VLDIGITS*sizeof(mpdigit));
+ else
+ mpbits(b, VLDIGITS*sizeof(mpdigit));
+ mpassign(mpzero, b);
+ if(v == 0)
+ return b;
+ if(v < 0){
+ b->sign = -1;
+ uv = -v;
+ } else
+ uv = v;
+ for(s = 0; s < VLDIGITS && uv != 0; s++){
+ b->p[s] = uv;
+ uv >>= sizeof(mpdigit)*8;
+ }
+ b->top = s;
+ return b;
+}
+
+vlong
+mptov(mpint *b)
+{
+ uvlong v;
+ int s;
+
+ if(b->top == 0)
+ return 0;
+
+ mpnorm(b);
+ if(b->top > VLDIGITS){
+ if(b->sign > 0)
+ return (vlong)MAXVLONG;
+ else
+ return (vlong)MINVLONG;
+ }
+
+ v = 0;
+ for(s = 0; s < b->top; s++)
+ v |= b->p[s]<<(s*sizeof(mpdigit)*8);
+
+ if(b->sign > 0){
+ if(v > MAXVLONG)
+ v = MAXVLONG;
+ } else {
+ if(v > MINVLONG)
+ v = MINVLONG;
+ else
+ v = -(vlong)v;
+ }
+
+ return (vlong)v;
+}
--- /dev/null
+++ b/libmp/port/mpvecadd.c
@@ -1,0 +1,35 @@
+#include "os.h"
+#include <mp.h>
+#include "dat.h"
+
+// prereq: alen >= blen, sum has at least blen+1 digits
+void
+mpvecadd(mpdigit *a, int alen, mpdigit *b, int blen, mpdigit *sum)
+{
+ int i, carry;
+ mpdigit x, y;
+
+ carry = 0;
+ for(i = 0; i < blen; i++){
+ x = *a++;
+ y = *b++;
+ x += carry;
+ if(x < carry)
+ carry = 1;
+ else
+ carry = 0;
+ x += y;
+ if(x < y)
+ carry++;
+ *sum++ = x;
+ }
+ for(; i < alen; i++){
+ x = *a++ + carry;
+ if(x < carry)
+ carry = 1;
+ else
+ carry = 0;
+ *sum++ = x;
+ }
+ *sum = carry;
+}
--- /dev/null
+++ b/libmp/port/mpveccmp.c
@@ -1,0 +1,27 @@
+#include "os.h"
+#include <mp.h>
+#include "dat.h"
+
+int
+mpveccmp(mpdigit *a, int alen, mpdigit *b, int blen)
+{
+ mpdigit x;
+
+ while(alen > blen)
+ if(a[--alen] != 0)
+ return 1;
+ while(blen > alen)
+ if(b[--blen] != 0)
+ return -1;
+ while(alen > 0){
+ --alen;
+ x = a[alen] - b[alen];
+ if(x == 0)
+ continue;
+ if(x > a[alen])
+ return -1;
+ else
+ return 1;
+ }
+ return 0;
+}
--- /dev/null
+++ b/libmp/port/mpvecdigmuladd.c
@@ -1,0 +1,103 @@
+#include "os.h"
+#include <mp.h>
+#include "dat.h"
+
+#define LO(x) ((x) & ((1<<(Dbits/2))-1))
+#define HI(x) ((x) >> (Dbits/2))
+
+static void
+mpdigmul(mpdigit a, mpdigit b, mpdigit *p)
+{
+ mpdigit x, ah, al, bh, bl, p1, p2, p3, p4;
+ int carry;
+
+ // half digits
+ ah = HI(a);
+ al = LO(a);
+ bh = HI(b);
+ bl = LO(b);
+
+ // partial products
+ p1 = ah*bl;
+ p2 = bh*al;
+ p3 = bl*al;
+ p4 = ah*bh;
+
+ // p = ((p1+p2)<<(Dbits/2)) + (p4<<Dbits) + p3
+ carry = 0;
+ x = p1<<(Dbits/2);
+ p3 += x;
+ if(p3 < x)
+ carry++;
+ x = p2<<(Dbits/2);
+ p3 += x;
+ if(p3 < x)
+ carry++;
+ p4 += carry + HI(p1) + HI(p2); // can't carry out of the high digit
+ p[0] = p3;
+ p[1] = p4;
+}
+
+// prereq: p must have room for n+1 digits
+void
+mpvecdigmuladd(mpdigit *b, int n, mpdigit m, mpdigit *p)
+{
+ int i;
+ mpdigit carry, x, y, part[2];
+
+ carry = 0;
+ part[1] = 0;
+ for(i = 0; i < n; i++){
+ x = part[1] + carry;
+ if(x < carry)
+ carry = 1;
+ else
+ carry = 0;
+ y = *p;
+ mpdigmul(*b++, m, part);
+ x += part[0];
+ if(x < part[0])
+ carry++;
+ x += y;
+ if(x < y)
+ carry++;
+ *p++ = x;
+ }
+ *p = part[1] + carry;
+}
+
+// prereq: p must have room for n+1 digits
+int
+mpvecdigmulsub(mpdigit *b, int n, mpdigit m, mpdigit *p)
+{
+ int i;
+ mpdigit x, y, part[2], borrow;
+
+ borrow = 0;
+ part[1] = 0;
+ for(i = 0; i < n; i++){
+ x = *p;
+ y = x - borrow;
+ if(y > x)
+ borrow = 1;
+ else
+ borrow = 0;
+ x = part[1];
+ mpdigmul(*b++, m, part);
+ x += part[0];
+ if(x < part[0])
+ borrow++;
+ x = y - x;
+ if(x > y)
+ borrow++;
+ *p++ = x;
+ }
+
+ x = *p;
+ y = x - borrow - part[1];
+ *p = y;
+ if(y > x)
+ return -1;
+ else
+ return 1;
+}
--- /dev/null
+++ b/libmp/port/mpvecsub.c
@@ -1,0 +1,34 @@
+#include "os.h"
+#include <mp.h>
+#include "dat.h"
+
+// prereq: a >= b, alen >= blen, diff has at least alen digits
+void
+mpvecsub(mpdigit *a, int alen, mpdigit *b, int blen, mpdigit *diff)
+{
+ int i, borrow;
+ mpdigit x, y;
+
+ borrow = 0;
+ for(i = 0; i < blen; i++){
+ x = *a++;
+ y = *b++;
+ y += borrow;
+ if(y < borrow)
+ borrow = 1;
+ else
+ borrow = 0;
+ if(x < y)
+ borrow++;
+ *diff++ = x - y;
+ }
+ for(; i < alen; i++){
+ x = *a++;
+ y = x - borrow;
+ if(y > x)
+ borrow = 1;
+ else
+ borrow = 0;
+ *diff++ = y;
+ }
+}
--- /dev/null
+++ b/libmp/port/os.h
@@ -1,0 +1,3 @@
+#include <lib9.h>
+extern ulong truerand(void);
+extern vlong nsec(void);
--- /dev/null
+++ b/libmp/port/reduce-nt
@@ -1,0 +1,4 @@
+# for now, just return the input files
+shift # $O
+shift # $SYSTARG-$OBJTYPE
+echo -n $*
--- /dev/null
+++ b/libmp/port/reduce-rc
@@ -1,0 +1,16 @@
+O=$1
+shift
+nonport=$1
+shift
+
+ls -p ../$nonport/*.[cs] >[2]/dev/null | sed 's/..$//' > /tmp/reduce.$pid
+#
+# if empty directory, just return the input files
+#
+if (! ~ $status '|') {
+ echo $*
+ rm /tmp/reduce.$pid
+ exit 0
+}
+echo $* | tr ' ' \012 | grep -v -f /tmp/reduce.$pid | tr \012 ' '
+rm /tmp/reduce.$pid
--- /dev/null
+++ b/libmp/port/reduce-sh
@@ -1,0 +1,13 @@
+O=$1
+shift
+nonport=$1
+shift
+
+for i in $*
+do
+ j=`echo $i | sed 's/\.'$O'//'`
+ if test ! -f ../$nonport/$j.c -a ! -f ../$nonport/$j.s -a ! -f ../$nonport/$j.spp
+ then
+ echo $i
+ fi
+done
--- /dev/null
+++ b/libmp/port/strtomp.c
@@ -1,0 +1,205 @@
+#include "os.h"
+#include <mp.h>
+#include <libsec.h>
+#include "dat.h"
+
+static struct {
+ int inited;
+
+ uchar t64[256];
+ uchar t32[256];
+ uchar t16[256];
+ uchar t10[256];
+} tab;
+
+enum {
+ INVAL= 255
+};
+
+static char set64[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+static char set32[] = "23456789abcdefghijkmnpqrstuvwxyz";
+static char set16[] = "0123456789ABCDEF0123456789abcdef";
+static char set10[] = "0123456789";
+
+static void
+init(void)
+{
+ char *p;
+
+ memset(tab.t64, INVAL, sizeof(tab.t64));
+ memset(tab.t32, INVAL, sizeof(tab.t32));
+ memset(tab.t16, INVAL, sizeof(tab.t16));
+ memset(tab.t10, INVAL, sizeof(tab.t10));
+
+ for(p = set64; *p; p++)
+ tab.t64[*p] = p-set64;
+ for(p = set32; *p; p++)
+ tab.t32[*p] = p-set32;
+ for(p = set16; *p; p++)
+ tab.t16[*p] = (p-set16)%16;
+ for(p = set10; *p; p++)
+ tab.t10[*p] = (p-set10);
+
+ tab.inited = 1;
+}
+
+static char*
+from16(char *a, mpint *b)
+{
+ char *p, *next;
+ int i;
+ mpdigit x;
+
+ b->top = 0;
+ for(p = a; *p; p++)
+ if(tab.t16[*(uchar*)p] == INVAL)
+ break;
+ mpbits(b, (p-a)*4);
+ b->top = 0;
+ next = p;
+ while(p > a){
+ x = 0;
+ for(i = 0; i < Dbits; i += 4){
+ if(p <= a)
+ break;
+ x |= tab.t16[*(uchar*)--p]<<i;
+ }
+ b->p[b->top++] = x;
+ }
+ return next;
+}
+
+static ulong mppow10[] = {
+ 1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000, 1000000000
+};
+
+static char*
+from10(char *a, mpint *b)
+{
+ ulong x, y;
+ mpint *pow, *r;
+ int i;
+
+ pow = mpnew(0);
+ r = mpnew(0);
+
+ b->top = 0;
+ for(;;){
+ // do a billion at a time in native arithmetic
+ x = 0;
+ for(i = 0; i < 9; i++){
+ y = tab.t10[*(uchar*)a];
+ if(y == INVAL)
+ break;
+ a++;
+ x *= 10;
+ x += y;
+ }
+ if(i == 0)
+ break;
+
+ // accumulate into mpint
+ uitomp(mppow10[i], pow);
+ uitomp(x, r);
+ mpmul(b, pow, b);
+ mpadd(b, r, b);
+ if(i != 9)
+ break;
+ }
+ mpfree(pow);
+ mpfree(r);
+ return a;
+}
+
+static char*
+from64(char *a, mpint *b)
+{
+ char *buf = a;
+ uchar *p;
+ int n, m;
+
+ for(; tab.t64[*(uchar*)a] != INVAL; a++)
+ ;
+ n = a-buf;
+ mpbits(b, n*6);
+ p = malloc(n);
+ if(p == nil)
+ return a;
+ m = dec64(p, n, buf, n);
+ betomp(p, m, b);
+ free(p);
+ return a;
+}
+
+static char*
+from32(char *a, mpint *b)
+{
+ char *buf = a;
+ uchar *p;
+ int n, m;
+
+ for(; tab.t64[*(uchar*)a] != INVAL; a++)
+ ;
+ n = a-buf;
+ mpbits(b, n*5);
+ p = malloc(n);
+ if(p == nil)
+ return a;
+ m = dec32(p, n, buf, n);
+ betomp(p, m, b);
+ free(p);
+ return a;
+}
+
+mpint*
+strtomp(char *a, char **pp, int base, mpint *b)
+{
+ int sign;
+ char *e;
+
+ if(b == nil)
+ b = mpnew(0);
+
+ if(tab.inited == 0)
+ init();
+
+ while(*a==' ' || *a=='\t')
+ a++;
+
+ sign = 1;
+ for(;; a++){
+ switch(*a){
+ case '-':
+ sign *= -1;
+ continue;
+ }
+ break;
+ }
+
+ switch(base){
+ case 10:
+ e = from10(a, b);
+ break;
+ default:
+ case 16:
+ e = from16(a, b);
+ break;
+ case 32:
+ e = from32(a, b);
+ break;
+ case 64:
+ e = from64(a, b);
+ break;
+ }
+
+ // if no characters parsed, there wasn't a number to convert
+ if(e == a)
+ return nil;
+
+ mpnorm(b);
+ b->sign = sign;
+ if(pp != nil)
+ *pp = e;
+
+ return b;
+}
--- /dev/null
+++ b/libmp/test.c
@@ -1,0 +1,453 @@
+#include <lib9.h>
+#include <mp.h>
+#include "dat.h"
+
+int loops = 1;
+
+long randomreg;
+
+void
+srand(long seed)
+{
+ randomreg = seed;
+}
+
+long
+lrand(void)
+{
+ randomreg = randomreg*104381 + 81761;
+ return randomreg;
+}
+
+void
+prng(uchar *p, int n)
+{
+ while(n-- > 0)
+ *p++ = lrand();
+}
+
+void
+testconv(char *str)
+{
+ mpint *b;
+ char *p;
+
+ b = strtomp(str, nil, 16, nil);
+
+ p = mptoa(b, 10, nil, 0);
+ print("%s = ", p);
+ strtomp(p, nil, 10, b);
+ free(p);
+ print("%B\n", b);
+
+ p = mptoa(b, 16, nil, 0);
+ print("%s = ", p);
+ strtomp(p, nil, 16, b);
+ free(p);
+ print("%B\n", b);
+
+ p = mptoa(b, 32, nil, 0);
+ print("%s = ", p);
+ strtomp(p, nil, 32, b);
+ free(p);
+ print("%B\n", b);
+
+ p = mptoa(b, 64, nil, 0);
+ print("%s = ", p);
+ strtomp(p, nil, 64, b);
+ free(p);
+ print("%B\n", b);
+
+ mpfree(b);
+}
+
+void
+testshift(char *str)
+{
+ mpint *b1, *b2;
+ int i;
+
+ b1 = strtomp(str, nil, 16, nil);
+ b2 = mpnew(0);
+ for(i = 0; i < 64; i++){
+ mpleft(b1, i, b2);
+ print("%2.2d %B\n", i, b2);
+ }
+ for(i = 0; i < 64; i++){
+ mpright(b2, i, b1);
+ print("%2.2d %B\n", i, b1);
+ }
+ mpfree(b1);
+ mpfree(b2);
+}
+
+void
+testaddsub(char *str)
+{
+ mpint *b1, *b2;
+ int i;
+
+ b1 = strtomp(str, nil, 16, nil);
+ b2 = mpnew(0);
+ for(i = 0; i < 16; i++){
+ mpadd(b1, b2, b2);
+ print("%2.2d %B\n", i, b2);
+ }
+ for(i = 0; i < 16; i++){
+ mpsub(b2, b1, b2);
+ print("%2.2d %B\n", i, b2);
+ }
+ mpfree(b1);
+ mpfree(b2);
+}
+
+void
+testvecdigmuladd(char *str, mpdigit d)
+{
+ mpint *b, *b2;
+ int i;
+ vlong now;
+
+ b = strtomp(str, nil, 16, nil);
+ b2 = mpnew(0);
+
+ mpbits(b2, (b->top+1)*Dbits);
+ now = nsec();
+ for(i = 0; i < loops; i++){
+ memset(b2->p, 0, b2->top*Dbytes);
+ mpvecdigmuladd(b->p, b->top, d, b2->p);
+ }
+ if(loops > 1)
+ print("%lld ns for a %d*%d vecdigmul\n", (nsec()-now)/loops, b->top*Dbits, Dbits);
+ mpnorm(b2);
+ print("0 + %B * %ux = %B\n", b, d, b2);
+
+ mpfree(b);
+ mpfree(b2);
+}
+
+void
+testvecdigmulsub(char *str, mpdigit d)
+{
+ mpint *b, *b2;
+ int i;
+ vlong now;
+
+ b = strtomp(str, nil, 16, nil);
+ b2 = mpnew(0);
+
+ mpbits(b2, (b->top+1)*Dbits);
+ now = nsec();
+ for(i = 0; i < loops; i++){
+ memset(b2->p, 0, b2->top*Dbytes);
+ mpvecdigmulsub(b->p, b->top, d, b2->p);
+ }
+ if(loops > 1)
+ print("%lld ns for a %d*%d vecdigmul\n", (nsec()-now)/loops, b->top*Dbits, Dbits);
+ mpnorm(b2);
+ print("0 - %B * %ux = %B\n", b, d, b2);
+
+ mpfree(b);
+ mpfree(b2);
+}
+
+void
+testmul(char *str)
+{
+ mpint *b, *b1, *b2;
+ vlong now;
+ int i;
+
+ b = strtomp(str, nil, 16, nil);
+ b1 = mpcopy(b);
+ b2 = mpnew(0);
+
+ now = nsec();
+ for(i = 0; i < loops; i++)
+ mpmul(b, b1, b2);
+ if(loops > 1)
+ print("%lld µs for a %d*%d mult\n", (nsec()-now)/(loops*1000),
+ b->top*Dbits, b1->top*Dbits);
+ print("%B * %B = %B\n", b, b1, b2);
+
+ mpfree(b);
+ mpfree(b1);
+ mpfree(b2);
+}
+
+void
+testmul2(mpint *b, mpint *b1)
+{
+ mpint *b2;
+ vlong now;
+ int i;
+
+ b2 = mpnew(0);
+
+ now = nsec();
+ for(i = 0; i < loops; i++)
+ mpmul(b, b1, b2);
+ if(loops > 1)
+ print("%lld µs for a %d*%d mult\n", (nsec()-now)/(loops*1000), b->top*Dbits, b1->top*Dbits);
+ print("%B * ", b);
+ print("%B = ", b1);
+ print("%B\n", b2);
+
+ mpfree(b2);
+}
+
+void
+testdigdiv(char *str, mpdigit d)
+{
+ mpint *b;
+ mpdigit q;
+ int i;
+ vlong now;
+
+ b = strtomp(str, nil, 16, nil);
+ now = nsec();
+ for(i = 0; i < loops; i++)
+ mpdigdiv(b->p, d, &q);
+ if(loops > 1)
+ print("%lld ns for a %d / %d div\n", (nsec()-now)/loops, 2*Dbits, Dbits);
+ print("%B / %ux = %ux\n", b, d, q);
+ mpfree(b);
+}
+
+void
+testdiv(mpint *x, mpint *y)
+{
+ mpint *b2, *b3;
+ vlong now;
+ int i;
+
+ b2 = mpnew(0);
+ b3 = mpnew(0);
+ now = nsec();
+ for(i = 0; i < loops; i++)
+ mpdiv(x, y, b2, b3);
+ if(loops > 1)
+ print("%lld µs for a %d/%d div\n", (nsec()-now)/(1000*loops),
+ x->top*Dbits, y->top*Dbits);
+ print("%B / %B = %B %B\n", x, y, b2, b3);
+ mpfree(b2);
+ mpfree(b3);
+}
+
+void
+testmod(mpint *x, mpint *y)
+{
+ mpint *r;
+ vlong now;
+ int i;
+
+ r = mpnew(0);
+ now = nsec();
+ for(i = 0; i < loops; i++)
+ mpmod(x, y, r);
+ if(loops > 1)
+ print("%lld µs for a %d/%d mod\n", (nsec()-now)/(1000*loops),
+ x->top*Dbits, y->top*Dbits);
+ print("%B mod %B = %B\n", x, y, r);
+ mpfree(r);
+}
+
+void
+testinvert(mpint *x, mpint *y)
+{
+ mpint *r, *d1, *d2;
+ vlong now;
+ int i;
+
+ r = mpnew(0);
+ d1 = mpnew(0);
+ d2 = mpnew(0);
+ now = nsec();
+ mpextendedgcd(x, y, r, d1, d2);
+ mpdiv(x, r, x, d1);
+ mpdiv(y, r, y, d1);
+ for(i = 0; i < loops; i++)
+ mpinvert(x, y, r);
+ if(loops > 1)
+ print("%lld µs for a %d in %d invert\n", (nsec()-now)/(1000*loops),
+ x->top*Dbits, y->top*Dbits);
+ print("%B**-1 mod %B = %B\n", x, y, r);
+ mpmul(r, x, d1);
+ mpmod(d1, y, d2);
+ print("%B*%B mod %B = %B\n", x, r, y, d2);
+ mpfree(r);
+ mpfree(d1);
+ mpfree(d2);
+}
+
+void
+testsub1(char *a, char *b)
+{
+ mpint *b1, *b2, *b3;
+
+ b1 = strtomp(a, nil, 16, nil);
+ b2 = strtomp(b, nil, 16, nil);
+ b3 = mpnew(0);
+ mpsub(b1, b2, b3);
+ print("%B - %B = %B\n", b1, b2, b3);
+}
+
+void
+testmul1(char *a, char *b)
+{
+ mpint *b1, *b2, *b3;
+
+ b1 = strtomp(a, nil, 16, nil);
+ b2 = strtomp(b, nil, 16, nil);
+ b3 = mpnew(0);
+ mpmul(b1, b2, b3);
+ print("%B * %B = %B\n", b1, b2, b3);
+}
+
+void
+testexp(char *base, char *exp, char *mod)
+{
+ mpint *b, *e, *m, *res;
+ int i;
+ uvlong now;
+
+ b = strtomp(base, nil, 16, nil);
+ e = strtomp(exp, nil, 16, nil);
+ res = mpnew(0);
+ if(mod != nil)
+ m = strtomp(mod, nil, 16, nil);
+ else
+ m = nil;
+ now = nsec();
+ for(i = 0; i < loops; i++)
+ mpexp(b, e, m, res);
+ if(loops > 1)
+ print("%ulldµs for a %d to the %d bit exp\n", (nsec()-now)/(loops*1000),
+ b->top*Dbits, e->top*Dbits);
+ if(m != nil)
+ print("%B ^ %B mod %B == %B\n", b, e, m, res);
+ else
+ print("%B ^ %B == %B\n", b, e, res);
+ mpfree(b);
+ mpfree(e);
+ mpfree(res);
+ if(m != nil)
+ mpfree(m);
+}
+
+void
+testgcd(void)
+{
+ mpint *a, *b, *d, *x, *y, *t1, *t2;
+ int i;
+ uvlong now, then;
+ uvlong etime;
+
+ d = mpnew(0);
+ x = mpnew(0);
+ y = mpnew(0);
+ t1 = mpnew(0);
+ t2 = mpnew(0);
+
+ etime = 0;
+
+ a = strtomp("4EECAB3E04C4E6BC1F49D438731450396BF272B4D7B08F91C38E88ADCD281699889AFF872E2204C80CCAA8E460797103DE539D5DF8335A9B20C0B44886384F134C517287202FCA914D8A5096446B40CD861C641EF9C2730CB057D7B133F4C2B16BBD3D75FDDBD9151AAF0F9144AAA473AC93CF945DBFE0859FB685D5CBD0A8B3", nil, 16, nil);
+ b = strtomp("C41CFBE4D4846F67A3DF7DE9921A49D3B42DC33728427AB159CEC8CBBDB12B5F0C244F1A734AEB9840804EA3C25036AD1B61AFF3ABBC247CD4B384224567A863A6F020E7EE9795554BCD08ABAD7321AF27E1E92E3DB1C6E7E94FAAE590AE9C48F96D93D178E809401ABE8A534A1EC44359733475A36A70C7B425125062B1142D", nil, 16, nil);
+ mpextendedgcd(a, b, d, x, y);
+ print("gcd %B*%B+%B*%B = %B?\n", a, x, b, y, d);
+ mpfree(a);
+ mpfree(b);
+
+ for(i = 0; i < loops; i++){
+ a = mprand(2048, prng, nil);
+ b = mprand(2048, prng, nil);
+ then = nsec();
+ mpextendedgcd(a, b, d, x, y);
+ now = nsec();
+ etime += now-then;
+ mpmul(a, x, t1);
+ mpmul(b, y, t2);
+ mpadd(t1, t2, t2);
+ if(mpcmp(d, t2) != 0)
+ print("%d gcd %B*%B+%B*%B != %B\n", i, a, x, b, y, d);
+// else
+// print("%d euclid %B*%B+%B*%B == %B\n", i, a, x, b, y, d);
+ mpfree(a);
+ mpfree(b);
+ }
+
+ mpfree(x);
+ mpfree(y);
+ mpfree(d);
+ mpfree(t1);
+ mpfree(t2);
+
+ if(loops > 1)
+ print("binary %llud\n", etime);
+}
+
+extern int _unnormalizedwarning = 1;
+
+void
+main(int argc, char **argv)
+{
+ mpint *x, *y;
+
+ ARGBEGIN{
+ case 'n':
+ loops = atoi(ARGF());
+ break;
+ }ARGEND;
+
+ fmtinstall('B', mpfmt);
+ fmtinstall('Q', mpfmt);
+ srand(0);
+ mpsetminbits(2*Dbits);
+ testshift("1111111111111111");
+ testaddsub("fffffffffffffffff");
+ testdigdiv("1234567812345678", 0x76543218);
+ testdigdiv("1ffff", 0xffff);
+ testdigdiv("ffff", 0xffff);
+ testdigdiv("fff", 0xffff);
+ testdigdiv("effffffff", 0xffff);
+ testdigdiv("ffffffff", 0x1);
+ testdigdiv("ffffffff", 0);
+ testdigdiv("200000000", 2);
+ testdigdiv("ffffff00fffffff1", 0xfffffff1);
+ testvecdigmuladd("fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", 2);
+ testconv("0");
+ testconv("-abc0123456789abcedf");
+ testconv("abc0123456789abcedf");
+ testvecdigmulsub("fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", 2);
+ testsub1("1FFFFFFFE00000000", "FFFFFFFE00000001");
+ testmul1("ffffffff", "f");
+ testmul("ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff");
+ testmul1("100000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000030000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000004FFFFFFFFFFFFFFFE0000000200000000000000000000000000000003FFFFFFFFFFFFFFFE0000000200000000000000000000000000000002FFFFFFFFFFFFFFFE0000000200000000000000000000000000000001FFFFFFFFFFFFFFFE0000000200000000000000000000000000000000FFFFFFFFFFFFFFFE0000000200000000FFFFFFFE00000001", "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF");
+ testmul1("1000000000000000000000001000000000000000000000001000000000000000000000001000000000000000000000001000000000000000000000001000000000000000000000001000000000000000000000001", "1000000000000000000000001000000000000000000000001000000000000000000000001000000000000000000000001000000000000000000000001000000000000000000000001000000000000000000000001");
+ testmul1("1000000000000000000000001000000000000000000000001000000000000000000000001000000000000000000000001000000000000000000000001000000000000000000000001000000000000000000000001", "1000000000000000000000001000000000000000000000001000000000000000000000001000000000000000000000001000000000000000000000001000000000000000000000001000000000000000000000001");
+ testmul1("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000");
+ x = mprand(256, prng, nil);
+ y = mprand(128, prng, nil);
+ testdiv(x, y);
+ x = mprand(2048, prng, nil);
+ y = mprand(1024, prng, nil);
+ testdiv(x, y);
+// x = mprand(4*1024, prng, nil);
+// y = mprand(4*1024, prng, nil);
+// testmul2(x, y);
+ testsub1("677132C9", "-A26559B6");
+ testgcd();
+ x = mprand(512, prng, nil);
+ x->sign = -1;
+ y = mprand(256, prng, nil);
+ testdiv(x, y);
+ testmod(x, y);
+ x->sign = 1;
+ testinvert(y, x);
+ testexp("111111111", "222", "1000000000000000000000");
+ testexp("ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", "100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000");
+#ifdef asdf
+#endif adsf
+ print("done\n");
+ exits(0);
+}
--- /dev/null
+++ b/libnandfs/NOTICE
@@ -1,0 +1,23 @@
+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 © 2002, 2003 Vita Nuova Holdings Limited.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
--- /dev/null
+++ b/libnandfs/calcformat.c
@@ -1,0 +1,24 @@
+#include "logfsos.h"
+#include "logfs.h"
+#include "nandfs.h"
+#include "local.h"
+
+int
+nandfscalcformat(Nandfs *nandfs, long base, long limit, long bootsize, long *baseblock, long *limitblock, long *bootblocks)
+{
+ *baseblock = (base + nandfs->rawblocksize - 1) / nandfs->rawblocksize;
+ if (limit == 0)
+ *limitblock = nandfs->limitblock;
+ else
+ *limitblock = limit / nandfs->rawblocksize;
+ *bootblocks = (bootsize + nandfs->rawblocksize - 1) / nandfs->rawblocksize;
+ if (*bootblocks < 3)
+ *bootblocks = 3;
+ /* sanity checks */
+ if (*limitblock > nandfs->limitblock
+ || *baseblock < nandfs->baseblock
+ || *bootblocks > nandfs->limitblock - nandfs->baseblock)
+ return 0;
+ return 1;
+}
+
--- /dev/null
+++ b/libnandfs/correctauxilliary.c
@@ -1,0 +1,81 @@
+#include "logfsos.h"
+#include "logfs.h"
+#include "nandfs.h"
+#include "local.h"
+
+static int
+hammingdistance(uchar a, uchar b)
+{
+ uchar c;
+ int i, k;
+ if (a == b)
+ return 0;
+ c = a ^ b;
+ for (i = 0x80, k = 0; i; i >>= 1)
+ if (c & i)
+ k++;
+ return k;
+}
+
+static int
+allones(uchar *data, int len)
+{
+ while (len-- > 0)
+ if (*data++ != 0xff)
+ return 0;
+ return 1;
+}
+
+LogfsLowLevelReadResult
+_nandfscorrectauxiliary(NandfsAuxiliary *hdr)
+{
+ /*
+ * correct single bit errors, detect more than 1, in
+ * tag, signature
+ * TODO: add nerase and path protection
+ */
+ LogfsLowLevelReadResult e;
+ int x;
+ int min, minx;
+
+ e = LogfsLowLevelReadResultOk;
+
+ min = 8;
+ minx = 0;
+ for (x = 0; x < _nandfsvalidtagscount; x++) {
+ int d = hammingdistance(hdr->tag, _nandfsvalidtags[x]);
+ if (d < min) {
+ min = d;
+ minx = x;
+ if (d == 0)
+ break;
+ }
+ }
+ if (min == 1) {
+ hdr->tag = _nandfsvalidtags[minx];
+ e = LogfsLowLevelReadResultSoftError;
+ }
+ else if (min > 1)
+ e = LogfsLowLevelReadResultHardError;
+ else {
+ if (hdr->tag != LogfsTnone) {
+ ulong tmp = getbig4(hdr->parth);
+ if (tmp != 0xffffffff && _nandfshamming31_26correct(&tmp)) {
+ putbig4(hdr->parth, tmp);
+ if (e != LogfsLowLevelReadResultOk)
+ e = LogfsLowLevelReadResultSoftError;
+ }
+ tmp = (getbig2(hdr->nerasemagicmsw) << 16) | getbig2(hdr->nerasemagiclsw);
+ if (tmp != 0xffffffff && _nandfshamming31_26correct(&tmp)) {
+ putbig2(hdr->nerasemagicmsw, tmp >> 16);
+ putbig2(hdr->nerasemagiclsw, tmp);
+ if (e != LogfsLowLevelReadResultOk)
+ e = LogfsLowLevelReadResultSoftError;
+ }
+ }
+ else if (allones((uchar *)hdr, sizeof(*hdr)))
+ e = LogfsLowLevelReadResultAllOnes;
+ }
+
+ return e;
+}
--- /dev/null
+++ b/libnandfs/ecc.c
@@ -1,0 +1,98 @@
+#include "logfsos.h"
+#include "nandecc.h"
+
+static uchar ecctab[] = {
+ 0x00, 0x55, 0x59, 0x0c, 0x65, 0x30, 0x3c, 0x69, 0x69, 0x3c, 0x30, 0x65, 0x0c, 0x59, 0x55, 0x00,
+ 0x95, 0xc0, 0xcc, 0x99, 0xf0, 0xa5, 0xa9, 0xfc, 0xfc, 0xa9, 0xa5, 0xf0, 0x99, 0xcc, 0xc0, 0x95,
+ 0x99, 0xcc, 0xc0, 0x95, 0xfc, 0xa9, 0xa5, 0xf0, 0xf0, 0xa5, 0xa9, 0xfc, 0x95, 0xc0, 0xcc, 0x99,
+ 0x0c, 0x59, 0x55, 0x00, 0x69, 0x3c, 0x30, 0x65, 0x65, 0x30, 0x3c, 0x69, 0x00, 0x55, 0x59, 0x0c,
+ 0xa5, 0xf0, 0xfc, 0xa9, 0xc0, 0x95, 0x99, 0xcc, 0xcc, 0x99, 0x95, 0xc0, 0xa9, 0xfc, 0xf0, 0xa5,
+ 0x30, 0x65, 0x69, 0x3c, 0x55, 0x00, 0x0c, 0x59, 0x59, 0x0c, 0x00, 0x55, 0x3c, 0x69, 0x65, 0x30,
+ 0x3c, 0x69, 0x65, 0x30, 0x59, 0x0c, 0x00, 0x55, 0x55, 0x00, 0x0c, 0x59, 0x30, 0x65, 0x69, 0x3c,
+ 0xa9, 0xfc, 0xf0, 0xa5, 0xcc, 0x99, 0x95, 0xc0, 0xc0, 0x95, 0x99, 0xcc, 0xa5, 0xf0, 0xfc, 0xa9,
+ 0xa9, 0xfc, 0xf0, 0xa5, 0xcc, 0x99, 0x95, 0xc0, 0xc0, 0x95, 0x99, 0xcc, 0xa5, 0xf0, 0xfc, 0xa9,
+ 0x3c, 0x69, 0x65, 0x30, 0x59, 0x0c, 0x00, 0x55, 0x55, 0x00, 0x0c, 0x59, 0x30, 0x65, 0x69, 0x3c,
+ 0x30, 0x65, 0x69, 0x3c, 0x55, 0x00, 0x0c, 0x59, 0x59, 0x0c, 0x00, 0x55, 0x3c, 0x69, 0x65, 0x30,
+ 0xa5, 0xf0, 0xfc, 0xa9, 0xc0, 0x95, 0x99, 0xcc, 0xcc, 0x99, 0x95, 0xc0, 0xa9, 0xfc, 0xf0, 0xa5,
+ 0x0c, 0x59, 0x55, 0x00, 0x69, 0x3c, 0x30, 0x65, 0x65, 0x30, 0x3c, 0x69, 0x00, 0x55, 0x59, 0x0c,
+ 0x99, 0xcc, 0xc0, 0x95, 0xfc, 0xa9, 0xa5, 0xf0, 0xf0, 0xa5, 0xa9, 0xfc, 0x95, 0xc0, 0xcc, 0x99,
+ 0x95, 0xc0, 0xcc, 0x99, 0xf0, 0xa5, 0xa9, 0xfc, 0xfc, 0xa9, 0xa5, 0xf0, 0x99, 0xcc, 0xc0, 0x95,
+ 0x00, 0x55, 0x59, 0x0c, 0x65, 0x30, 0x3c, 0x69, 0x69, 0x3c, 0x30, 0x65, 0x0c, 0x59, 0x55, 0x00,
+};
+
+ulong
+nandecc(uchar *buf)
+{
+ int cp, zeros, ones, im;
+ int lp, om;
+ int i;
+
+ cp = 0xff;
+ zeros = 0xff;
+ ones = 0xff;
+ for (i = 0; i < 256; i++) {
+ int tabent = ecctab[buf[i]];
+ cp ^= tabent;
+ if (tabent & 1) {
+ zeros ^= ~i;
+ ones ^= i;
+ }
+ }
+ lp = 0;
+ for (im = 0x80, om = 0x8000; im; im >>= 1, om >>= 1) {
+ if (ones & im)
+ lp |= om;
+ om >>= 1;
+ if (zeros & im)
+ lp |= om;
+ }
+ return (((cp & 0xff) | 3) << 16) | lp;
+}
+
+#define CORRECTABLEMASK 0x545555
+
+NandEccError
+nandecccorrect(uchar *buf, ulong calcecc, ulong *storedecc, int reportbad)
+{
+ ulong xorecc;
+ ulong mask;
+ int k;
+
+ if (calcecc == *storedecc)
+ return NandEccErrorGood;
+ if (reportbad)
+ print("nandecccorrect: calculated ecc %.8lux stored ecc %.8lux\n", calcecc, *storedecc);
+ xorecc = calcecc ^ *storedecc;
+ if (((xorecc ^ (xorecc >> 1)) & CORRECTABLEMASK) == CORRECTABLEMASK) {
+ ulong imask;
+ ushort out;
+ ushort omask;
+ int line, col;
+
+ for (imask = 0x800000, omask = 0x800, out = 0; imask; imask >>= 2, omask >>= 1) {
+ if (xorecc & imask)
+ out |= omask;
+ }
+ line = out & 0xff;
+ col = out >> 9;
+ if (reportbad)
+ print("nandecccorrect: single bit error line %d col %d\n", line, col);
+ buf[line] ^= (1 << col);
+ *storedecc = calcecc;
+ return NandEccErrorOneBit;
+ }
+ for (mask = 0x800000, k = 0; mask; mask >>= 1)
+ if (mask & xorecc)
+ k++;
+ if (k == 1) {
+ if (reportbad)
+ print("nandecccorrect: single bit error in ecc\n");
+ // assume the stored ecc was wrong
+ *storedecc = calcecc;
+ return NandEccErrorOneBitInEcc;
+ }
+ if (reportbad)
+ print("nandecccorrect: 2 bit error\n");
+ return NandEccErrorBad;
+}
+
--- /dev/null
+++ b/libnandfs/eraseblock.c
@@ -1,0 +1,50 @@
+#include "logfsos.h"
+#include "logfs.h"
+#include "nandfs.h"
+#include "local.h"
+
+char *
+nandfseraseblock(Nandfs *nandfs, long block, void **llsavep, int *markedbad)
+{
+ NandfsBlockData *d;
+ char *errmsg;
+
+ if (markedbad)
+ *markedbad = 0;
+
+ errmsg = (*nandfs->erase)(nandfs->magic, nandfs->rawblocksize * (nandfs->baseblock + block));
+ if (errmsg) {
+ if (nandfs->blockdata) {
+ d = &nandfs->blockdata[block];
+ d->tag = LogfsTworse;
+ nandfs->worseblocks = 1;
+ }
+ if (strcmp(errmsg, Eio) != 0)
+ return errmsg;
+ if (markedbad) {
+ *markedbad = 1;
+ errmsg = nandfsmarkblockbad(nandfs, block);
+ if (strcmp(errmsg, Eio) != 0)
+ return errmsg;
+ return nil;
+ }
+ return errmsg;
+ }
+
+ if (nandfs->blockdata) {
+ ulong *llsave;
+ d = &nandfs->blockdata[block];
+ if (llsavep) {
+ llsave = nandfsrealloc(nil, sizeof(ulong));
+ if (llsave == nil)
+ return Enomem;
+ *llsave = d->nerase;
+ *llsavep = llsave;
+ }
+ d->tag = 0xff;
+ d->path = NandfsPathMask;
+ d->nerase = NandfsNeraseMask;
+ }
+ return nil;
+}
+
--- /dev/null
+++ b/libnandfs/extracttags.c
@@ -1,0 +1,26 @@
+#include "logfsos.h"
+#include "logfs.h"
+#include "nandfs.h"
+#include "local.h"
+
+void
+_nandfsextracttags(NandfsAuxiliary *hdr, NandfsTags *tags)
+{
+ ulong tmp;
+ tmp = (getbig2(hdr->nerasemagicmsw) << 16) | getbig2(hdr->nerasemagiclsw);
+ if (tmp == 0xffffffff) {
+ tags->nerase = 0xffffffff;
+ tags->magic = 0xff;
+ }
+ else {
+ tags->nerase = (tmp >> 6) & 0x3ffff;
+ tags->magic = tmp >> 24;
+ }
+ tmp = getbig4(hdr->parth);
+ if (tmp != 0xffffffff)
+ tags->path = tmp >> 6;
+ else
+ tags->path = 0xffffffff;
+ tags->tag = hdr->tag;
+}
+
--- /dev/null
+++ b/libnandfs/findfreeblock.c
@@ -1,0 +1,28 @@
+#include "logfsos.h"
+#include "logfs.h"
+#include "nandfs.h"
+#include "local.h"
+
+long
+nandfsfindfreeblock(Nandfs *nandfs, long *freeblocksp)
+{
+ long bestnewblock;
+ long bestnerase;
+ long i;
+
+ if (freeblocksp)
+ *freeblocksp = 0;
+ for (i = 0, bestnewblock = -1, bestnerase = 0x7fffffff; i < nandfs->ll.blocks; i++) {
+ long nerase;
+ if (nandfsgettag(nandfs, i) == LogfsTnone) {
+ if (freeblocksp) {
+ (*freeblocksp)++;
+ }
+ if ((nerase = nandfsgetnerase(nandfs, i)) < bestnerase) {
+ bestnewblock = i;
+ bestnerase = nerase;
+ }
+ }
+ }
+ return bestnewblock;
+}
--- /dev/null
+++ b/libnandfs/formatblock.c
@@ -1,0 +1,57 @@
+#include "logfsos.h"
+#include "logfs.h"
+#include "nandfs.h"
+#include "local.h"
+
+char *
+nandfsformatblock(Nandfs *nandfs, long absblock, uchar tag, ulong path, long baseblock, long sizeinblocks, int xcount, long *xdata, void *llsave, int *markedbad)
+{
+ int page;
+ char *rv;
+ NandfsTags t;
+ int ppb;
+
+ if (markedbad)
+ *markedbad = 0;
+
+ t.tag = tag;
+ t.magic = LogfsMagic;
+ t.nerase = *(ulong *)llsave < NandfsNeraseMask ? *(ulong *)llsave + 1 : 1;
+
+ ppb = 1 << nandfs->ll.l2pagesperblock;
+ for (page = 0, rv = nil; rv == nil && page < ppb; page++) {
+ if (tag == LogfsTboot && page > 0 && page < xcount + 3) {
+ switch (page) {
+ case 1:
+ t.path = baseblock;
+ break;
+ case 2:
+ t.path = sizeinblocks;
+ break;
+ default:
+ t.path = xdata[page - 3];
+ break;
+ }
+ }
+ else
+ t.path = path;
+ rv = nandfswritepageauxiliary(nandfs, &t, absblock, page);
+ if (rv)
+ break;
+ }
+
+ if (rv) {
+ if (strcmp(rv, Eio) != 0)
+ return rv;
+ if (markedbad) {
+ *markedbad = 1;
+ rv = nandfsmarkabsblockbad(nandfs, absblock);
+ if (strcmp(rv, Eio) != 0)
+ return rv;
+ return nil;
+ }
+ return rv;
+ }
+
+ return nil;
+}
--- /dev/null
+++ b/libnandfs/getblockstatus.c
@@ -1,0 +1,27 @@
+#include "logfsos.h"
+#include "logfs.h"
+#include "nandfs.h"
+#include "local.h"
+
+char *
+nandfsgetblockstatus(Nandfs *nandfs, long absblock, int *magicfound, void **llsavep, LogfsLowLevelReadResult *result)
+{
+ NandfsTags tags;
+ char *errmsg;
+ ulong *llsave;
+
+ errmsg = nandfsreadpageauxiliary(nandfs, &tags, absblock, 0, 1, result);
+
+ *magicfound = tags.magic == LogfsMagic;
+
+ if (llsavep) {
+ llsave = nandfsrealloc(nil, sizeof(ulong));
+ if (llsave == nil)
+ return Enomem;
+ *llsave = tags.nerase;
+ *llsavep = llsave;
+ }
+
+ return errmsg;
+}
+
--- /dev/null
+++ b/libnandfs/hamming31_26.c
@@ -1,0 +1,62 @@
+#include "logfsos.h"
+#include "logfs.h"
+#include "nandfs.h"
+
+static unsigned long row4 = 0x001fffc0;
+static unsigned long row3 = 0x0fe03fc0;
+static unsigned long row2 = 0x71e3c3c0;
+static unsigned long row1 = 0xb66cccc0;
+static unsigned long row0 = 0xdab55540;
+
+static char map[] = {
+ -5, -4, 0, -3, 1, 2, 3, -2,
+ 4, 5, 6, 7, 8, 9, 10, -1, 11,
+ 12, 13, 14, 15, 16, 17, 18,
+ 19, 20, 21, 22, 23, 24, 25,
+};
+
+#define mashbits(rown) \
+ c = (in) & (rown); \
+ c ^= c >> 16; \
+ c ^= c >> 8; \
+ c ^= c >> 4; \
+ c ^= c >> 2; \
+ c = (c ^ (c >> 1)) & 1; \
+
+static uchar
+_nandfshamming31_26calcparity(ulong in)
+{
+ ulong c;
+ uchar out;
+ mashbits(row4); out = c;
+ mashbits(row3); out = (out << 1) | c;
+ mashbits(row2); out = (out << 1) | c;
+ mashbits(row1); out = (out << 1) | c;
+ mashbits(row0); out = (out << 1) | c;
+ return out;
+}
+
+ulong
+_nandfshamming31_26calc(ulong in)
+{
+ in &= 0xffffffc0;
+ return in | _nandfshamming31_26calcparity(in);
+}
+
+int
+_nandfshamming31_26correct(ulong *in)
+{
+ uchar eparity, parity;
+ ulong e;
+ eparity = _nandfshamming31_26calcparity(*in);
+ parity = (*in) & 0x1f;
+ e = eparity ^ parity;
+ if (e == 0)
+ return 0;
+ e--;
+ if (map[e] < 0)
+ return 1; // error in parity bits
+ e = map[e];
+ *in ^= 1 << (31 - e);
+ return 1;
+}
--- /dev/null
+++ b/libnandfs/init.c
@@ -1,0 +1,102 @@
+#include "logfsos.h"
+#include "logfs.h"
+#include "nandfs.h"
+#include "local.h"
+
+uchar _nandfsvalidtags[] = {
+ LogfsTnone,
+ LogfsTboot,
+ LogfsTlog,
+ LogfsTdata,
+};
+
+int _nandfsvalidtagscount = nelem(_nandfsvalidtags);
+
+static int
+l2(long n)
+{
+ int i;
+ for (i = 0; i < 32; i++)
+ if ((1 << i) >= n)
+ return i;
+ return 0;
+}
+
+char *
+nandfsinit(void *magic, long rawsize, long rawblocksize,
+ char *(*read)(void *magic, void *buf, long nbytes, ulong offset),
+ char *(*write)(void *magic, void *buf, long nbytes, ulong offset),
+ char *(*erase)(void *magic, long blockaddr),
+ char *(*sync)(void *magic),
+ LogfsLowLevel **llp)
+{
+ Nandfs *nandfs;
+ nandfs = nandfsrealloc(nil, sizeof(*nandfs));
+ if (nandfs == nil)
+ return Enomem;
+ if (rawblocksize % NandfsFullSize)
+ return "unsupported block size";
+ if (rawsize % rawblocksize)
+ return "size not multiple of block size";
+ nandfs->read = read;
+ nandfs->write = write;
+ nandfs->erase = erase;
+ nandfs->sync = sync;
+ nandfs->magic = magic;
+ nandfs->limitblock = rawsize / rawblocksize;
+//print("rawsize %ld\n", rawsize);
+//print("rawblocksize %ld\n", rawblocksize);
+//print("limitblock %ld\n", nandfs->limitblock);
+ nandfs->rawblocksize = rawblocksize;
+ /* fill in upper interface */
+ nandfs->ll.pathbits = NandfsPathBits;
+ nandfs->ll.blocks = 0;
+ nandfs->ll.l2pagesize = NandfsL2PageSize;
+ nandfs->ll.l2pagesperblock = l2(rawblocksize / NandfsFullSize);
+ nandfs->ll.open = (LOGFSOPENFN *)nandfsopen;
+ nandfs->ll.getblocktag = (LOGFSGETBLOCKTAGFN *)nandfsgettag;
+ nandfs->ll.setblocktag = (LOGFSSETBLOCKTAGFN *)nandfssettag;
+ nandfs->ll.getblockpath = (LOGFSGETBLOCKPATHFN *)nandfsgetpath;
+ nandfs->ll.setblockpath = (LOGFSSETBLOCKPATHFN *)nandfssetpath;
+ nandfs->ll.getblockpartialformatstatus = (LOGFSGETBLOCKPARTIALFORMATSTATUSFN *)nandfsgetblockpartialformatstatus;
+ nandfs->ll.findfreeblock = (LOGFSFINDFREEBLOCKFN *)nandfsfindfreeblock;
+ nandfs->ll.readpagerange = (LOGFSREADPAGERANGEFN *)nandfsreadpagerange;
+ nandfs->ll.writepage = (LOGFSWRITEPAGEFN *)nandfswritepage;
+ nandfs->ll.readblock = (LOGFSREADBLOCKFN *)nandfsreadblock;
+ nandfs->ll.writeblock = (LOGFSWRITEBLOCKFN *)nandfswriteblock;
+ nandfs->ll.eraseblock = (LOGFSERASEBLOCKFN *)nandfseraseblock;
+ nandfs->ll.formatblock = (LOGFSFORMATBLOCKFN *)nandfsformatblock;
+ nandfs->ll.reformatblock = (LOGFSREFORMATBLOCKFN *)nandfsreformatblock;
+ nandfs->ll.markblockbad = (LOGFSMARKBLOCKBADFN *)nandfsmarkblockbad;
+ nandfs->ll.getbaseblock = (LOGFSGETBASEBLOCKFN *)nandfsgetbaseblock;
+ nandfs->ll.getblocksize = (LOGFSGETBLOCKSIZEFN *)nandfsgetblocksize;
+ nandfs->ll.calcrawaddress = (LOGFSCALCRAWADDRESSFN *)nandfscalcrawaddress;
+ nandfs->ll.getblockstatus = (LOGFSGETBLOCKSTATUSFN *)nandfsgetblockstatus;
+ nandfs->ll.calcformat = (LOGFSCALCFORMATFN *)nandfscalcformat;
+ nandfs->ll.getopenstatus = (LOGFSGETOPENSTATUSFN *)nandfsgetopenstatus;
+ nandfs->ll.free = (LOGFSFREEFN *)nandfsfree;
+ nandfs->ll.sync = (LOGFSSYNCFN *)nandfssync;
+ *llp = (LogfsLowLevel *)nandfs;
+ return nil;
+}
+
+void
+nandfsfree(Nandfs *nandfs)
+{
+ if (nandfs) {
+ nandfsfreemem(nandfs->blockdata);
+ nandfsfreemem(nandfs);
+ }
+}
+
+void
+nandfssetmagic(Nandfs *nandfs, void *magic)
+{
+ nandfs->magic = magic;
+}
+
+char *
+nandfssync(Nandfs *nandfs)
+{
+ return (*nandfs->sync)(nandfs->magic);
+}
--- /dev/null
+++ b/libnandfs/local.h
@@ -1,0 +1,54 @@
+typedef struct NandfsBlockData NandfsBlockData;
+typedef struct NandfsAuxiliary NandfsAuxiliary;
+
+struct NandfsBlockData {
+ ulong path;
+ short tag;
+ ulong nerase;
+ int partial;
+};
+
+struct Nandfs {
+ LogfsLowLevel ll;
+ char *(*read)(void*, void*, long, ulong);
+ char *(*write)(void*, void*, long, ulong);
+ char *(*erase)(void*, long blockaddr);
+ char *(*sync)(void*);
+ void *magic;
+ long rawblocksize;
+ long baseblock;
+ long limitblock;
+ NandfsBlockData *blockdata;
+ int trace;
+ int worseblocks;
+ int printbad;
+};
+
+struct NandfsAuxiliary {
+ uchar parth[4]; // ggpppppp pppppppp pppppppp pp1hhhhh (bigendian) self-protected
+ uchar tag; // self-protecting
+ uchar blockstatus; // self-protecting
+ uchar nerasemagicmsw[2]; // see nerasemagiclsw
+ uchar ecc2[3]; // self-protecting
+ uchar nerasemagiclsw[2]; // mmmmmm mmeeeeee eeeeeeeeee ee1hhhhh (bigendian) self-protected
+ uchar ecc1[3]; // self-protecting
+};
+
+#define getbig2(p) (((p)[0] << 8) | (p)[1])
+#define getbig4(p) (((p)[0] << 24) | ((p)[1] << 16) | ((p)[2] << 8) | (p)[3])
+#define getlittle3(p) (((p)[2] << 16) | ((p)[1] << 8) | (p)[0])
+#define putlittle3(p, q) ((p)[0] = (q), (p)[1] = (q) >> 8, (p)[2] = (q) >> 16)
+#define putbig2(p, q) ((p)[0] = (q) >> 8, (p)[1] = (q))
+#define putbig4(p, q) ((p)[0] = (q) >> 24, (p)[1] = (q) >> 16, (p)[2] = (q) >> 8, (p)[3] = (q))
+
+LogfsLowLevelReadResult _nandfscorrectauxiliary(NandfsAuxiliary*);
+
+extern uchar _nandfsvalidtags[];
+extern int _nandfsvalidtagscount;
+
+ulong _nandfshamming31_26calc(ulong in);
+int _nandfshamming31_26correct(ulong *in);
+
+void _nandfsextracttags(NandfsAuxiliary*, NandfsTags*);
+
+extern char Enomem[], Eperm[], Eio[];
--- /dev/null
+++ b/libnandfs/markblockbad.c
@@ -1,0 +1,42 @@
+#include "logfsos.h"
+#include "logfs.h"
+#include "nandfs.h"
+#include "local.h"
+
+char *
+nandfsmarkabsblockbad(Nandfs *nandfs, long absblock)
+{
+ NandfsAuxiliary hdr;
+ int page;
+ int ppb;
+
+ memset(&hdr, 0xff, sizeof(hdr));
+ hdr.blockstatus = 0xf0; // late failure
+
+ ppb = 1 << nandfs->ll.l2pagesperblock;
+ for (page = 0; page < ppb; page++) {
+ char *errmsg = (*nandfs->write)(nandfs->magic, &hdr, sizeof(hdr), nandfs->rawblocksize * absblock + page * NandfsFullSize + NandfsPageSize);
+ if (errmsg && strcmp(errmsg, Eio) != 0)
+ return errmsg;
+ }
+
+ return nil;
+}
+
+char *
+nandfsmarkblockbad(Nandfs *nandfs, long block)
+{
+ char *errmsg;
+ errmsg = nandfsmarkabsblockbad(nandfs, block + nandfs->baseblock);
+ if (errmsg)
+ return errmsg;
+
+ if (nandfs->blockdata) {
+ NandfsBlockData *d;
+ d = &nandfs->blockdata[block];
+ d->tag = LogfsTbad;
+ }
+
+ return nil;
+}
+
--- /dev/null
+++ b/libnandfs/mkfile
@@ -1,0 +1,33 @@
+<../mkconfig
+
+LIB=libnandfs.a
+
+OFILES= \
+ calcformat.$O\
+ correctauxilliary.$O\
+ ecc.$O\
+ eraseblock.$O\
+ extracttags.$O\
+ findfreeblock.$O\
+ formatblock.$O\
+ getblockstatus.$O\
+ hamming31_26.$O\
+ init.$O\
+ markblockbad.$O\
+ open.$O\
+ readblock.$O\
+ readpage.$O\
+ readpageauxilliary.$O\
+ reformatblock.$O\
+ setget.$O\
+ updatepage.$O\
+ writeblock.$O\
+ writepageauxilliary.$O\
+
+HFILES=\
+ $ROOT/include/nandfs.h \
+ $ROOT/include/logfs.h \
+ local.h
+
+<$ROOT/mkfiles/mksyslib-$SHELLTYPE
+
--- /dev/null
+++ b/libnandfs/open.c
@@ -1,0 +1,253 @@
+#include "logfsos.h"
+#include "logfs.h"
+#include "nandfs.h"
+#include "local.h"
+
+char *
+nandfsopen(Nandfs *nandfs, long base, long limit, int trace, int xcount, long *xdata)
+{
+ NandfsBlockData *blockdata = nil;
+ long u;
+ ulong badones, goodones;
+ char *errmsg;
+ long possiblebaseblock, possiblesize;
+ long baseblock, limitblock;
+ int ppb;
+
+ if (trace > 1)
+ print("nandfsopen: base %ld limit %ld ppb %d\n", base, limit, 1 << nandfs->ll.l2pagesperblock);
+
+ if (nandfs->blockdata)
+ return Eperm;
+
+ if (base % nandfs->rawblocksize)
+ return Ebadarg;
+ baseblock = base / nandfs->rawblocksize;
+
+ if (limit == 0)
+ limitblock = nandfs->limitblock;
+ else if (limit % nandfs->rawblocksize)
+ return Ebadarg;
+ else
+ limitblock = limit / nandfs->rawblocksize;
+
+ if (trace > 1)
+ print("nandfsopen: baseblock %ld limitblock %ld\n", baseblock, limitblock);
+
+ possiblebaseblock = 0;
+ possiblesize = 0;
+
+ /*
+ * search for Tboot block which will reveal the parameters
+ */
+ nandfs->baseblock = 0;
+
+ for (u = baseblock; u < limitblock; u++) {
+ NandfsTags tags;
+ LogfsLowLevelReadResult e;
+ int p;
+ int lim;
+
+ lim = xcount + 3;
+
+ for (p = 0; p < lim; p++) {
+ errmsg = nandfsreadpageauxiliary(nandfs, &tags, u, p, 1, &e);
+ if (errmsg)
+ goto error;
+ if (e != LogfsLowLevelReadResultOk || tags.magic != LogfsMagic || tags.tag != LogfsTboot)
+ break;
+ if (trace > 1)
+ print("block %lud/%d: 0x%.lux\n", u, p, tags.path);
+ switch (p) {
+ case 1:
+ possiblebaseblock = tags.path;
+ break;
+ case 2:
+ possiblesize = tags.path;
+ break;
+ default:
+ xdata[p - 3] = tags.path;
+ break;
+ }
+ }
+ if (p == lim)
+ break;
+ }
+
+ if (u >= limitblock) {
+ errmsg = "no valid boot blocks found";
+ goto error;
+ }
+
+ if (possiblebaseblock < baseblock
+ || possiblebaseblock >= limitblock
+ || possiblebaseblock + possiblesize > limitblock
+ || possiblesize == 0) {
+ errmsg = "embedded parameters out of range";
+ goto error;
+ }
+
+ baseblock = possiblebaseblock;
+ limitblock = possiblebaseblock + possiblesize;
+
+ if (trace > 0) {
+ int x;
+ print("nandfs filesystem detected: base %lud limit %lud",
+ baseblock, limitblock);
+ for (x = 0; x < xcount; x++)
+ print(" data%d %ld", x, xdata[x]);
+ print("\n");
+ }
+
+ blockdata = nandfsrealloc(nil, (limitblock - baseblock) * sizeof(NandfsBlockData));
+ if (blockdata == nil) {
+ errmsg = Enomem;
+ goto error;
+ }
+ /*
+ * sanity check
+ * check the partition until 10 good blocks have been found
+ * check that bad blocks represent 10% or less
+ */
+
+ badones = goodones = 0;
+ ppb = 1 << nandfs->ll.l2pagesperblock;
+ for (u = baseblock; u < limitblock; u++) {
+ LogfsLowLevelReadResult firste, laste;
+ NandfsTags firsttags, lasttags;
+ errmsg = nandfsreadpageauxiliary(nandfs, &firsttags, u, 0, 1, &firste);
+ if (errmsg)
+ goto error;
+ errmsg = nandfsreadpageauxiliary(nandfs, &lasttags, u, ppb - 1, 1, &laste);
+ if (errmsg)
+ goto error;
+ if (firste == LogfsLowLevelReadResultBad || laste == LogfsLowLevelReadResultBad)
+ continue;
+ if (firste == LogfsLowLevelReadResultOk && laste == LogfsLowLevelReadResultOk && firsttags.magic == LogfsMagic &&
+ lasttags.magic == LogfsMagic)
+ goodones++;
+ else
+ badones++;
+ if (badones == 0 && goodones >= 10)
+ break;
+ }
+
+ if (badones * 10 > goodones) {
+ errmsg = "most likely not a Log Filesystem";
+ goto error;
+ }
+
+ for (u = baseblock; u < limitblock; u++) {
+ int erased, partial;
+ LogfsLowLevelReadResult firste, laste;
+ NandfsTags firsttags, lasttags, newtags;
+ int markedbad;
+ errmsg = nandfsreadpageauxiliary(nandfs, &firsttags, u, 0, 1, &firste);
+ if (errmsg)
+ goto error;
+ errmsg = nandfsreadpageauxiliary(nandfs, &lasttags, u, ppb - 1, 1, &laste);
+ if (errmsg)
+ goto error;
+ if (trace > 1)
+ print("%lud: ", u);
+ if (firste == LogfsLowLevelReadResultBad || laste == LogfsLowLevelReadResultBad) {
+ if (trace > 1)
+ print("bad\n");
+ blockdata[u - baseblock].tag = LogfsTbad;
+ continue;
+ }
+ newtags = firsttags;
+ erased = 0;
+ partial = 0;
+ if (firsttags.tag != lasttags.tag) {
+ partial = 1;
+ if (trace > 1)
+ print("partially written\n");
+ /*
+ * partially written block
+ * if Tboot, then it is either
+ * a failure during logfsformat() - well, we never got started, so give up
+ * a failure during blocktransfer() - erase it as the transfer was not completed
+ * tell the difference by the presence of another block with the same path
+ * if Tnone, then it's a no brainer
+ * if anything else, leave alone
+ */
+ if (newtags.tag == LogfsTnone) {
+ newtags.tag = LogfsTnone;
+ newtags.path = NandfsPathMask;
+ errmsg = nandfseraseblock(nandfs, u, nil, &markedbad);
+ if (errmsg)
+ goto error;
+ if (markedbad) {
+ blockdata[u - baseblock].tag = LogfsTbad;
+ continue;
+ }
+ /* now erased */
+ erased = 1;
+ partial = 0;
+ }
+ }
+ if (!erased && !partial && firste == LogfsLowLevelReadResultAllOnes) {
+ if (trace > 1)
+ print("probably erased");
+ /*
+ * finding erased blocks at this stage is a rare event, so
+ * erase again just in case
+ */
+ newtags.tag = LogfsTnone;
+ newtags.path = NandfsPathMask;
+ newtags.nerase = 1; // what do I do here?
+ errmsg = nandfseraseblock(nandfs, u, nil, &markedbad);
+ if (errmsg)
+ goto error;
+ if (markedbad) {
+ blockdata[u - baseblock].tag = LogfsTbad;
+ continue;
+ }
+ erased = 1;
+ }
+ if (erased) {
+ newtags.magic = 'V';
+ errmsg = nandfseraseblock(nandfs, u, nil, &markedbad);
+ if (errmsg)
+ goto error;
+ if (markedbad) {
+ blockdata[u - baseblock].tag = LogfsTbad;
+ continue;
+ }
+ }
+ switch (newtags.tag) {
+ case LogfsTboot:
+ case LogfsTnone:
+ case LogfsTdata:
+ case LogfsTlog:
+ blockdata[u - baseblock].path = newtags.path;
+ blockdata[u - baseblock].tag = newtags.tag;
+ blockdata[u - baseblock].nerase = newtags.nerase;
+ blockdata[u - baseblock].partial = partial;
+ if (trace > 1)
+ print("%s 0x%.8lux %lud\n",
+ logfstagname(blockdata[u - baseblock].tag),
+ blockdata[u - baseblock].path,
+ blockdata[u - baseblock].nerase);
+ continue;
+ }
+ break;
+ }
+ nandfs->ll.blocks = u - baseblock;
+ nandfs->baseblock = baseblock;
+ nandfs->blockdata = nandfsrealloc(nil, nandfs->ll.blocks * sizeof(NandfsBlockData));
+ if (nandfs->blockdata == nil) {
+ errmsg = Enomem;
+ goto error;
+ }
+ nandfs->trace = trace;
+ memmove(nandfs->blockdata, blockdata, sizeof(*nandfs->blockdata) * nandfs->ll.blocks);
+ nandfsfreemem(blockdata);
+ if (trace > 0)
+ print("nandfsopen: success\n");
+ return nil;
+error:
+ nandfsfreemem(blockdata);
+ return errmsg;
+}
--- /dev/null
+++ b/libnandfs/readblock.c
@@ -1,0 +1,36 @@
+#include "logfsos.h"
+#include "logfs.h"
+#include "nandfs.h"
+#include "local.h"
+
+char *
+nandfsreadblock(Nandfs *nandfs, void *buf, long block, LogfsLowLevelReadResult *blocke)
+{
+ int p;
+ uchar *bp;
+ int ppb;
+
+ *blocke = LogfsLowLevelReadResultOk;
+ ppb = 1 << nandfs->ll.l2pagesperblock;
+ for (p = 0, bp = buf; p < ppb; p++, bp += NandfsPageSize) {
+ LogfsLowLevelReadResult e;
+ char *errmsg;
+ errmsg = nandfsreadpage(nandfs, bp, nil, block, p, nandfs->printbad, &e);
+ if (errmsg)
+ return errmsg;
+ switch (e) {
+ case LogfsLowLevelReadResultOk:
+ break;
+ case LogfsLowLevelReadResultSoftError:
+ if (*blocke == LogfsLowLevelReadResultOk)
+ *blocke = LogfsLowLevelReadResultSoftError;
+ break;
+ case LogfsLowLevelReadResultHardError:
+ if (*blocke == LogfsLowLevelReadResultOk || *blocke == LogfsLowLevelReadResultSoftError)
+ *blocke = LogfsLowLevelReadResultHardError;
+ break;
+ }
+ }
+
+ return nil;
+}
--- /dev/null
+++ b/libnandfs/readpage.c
@@ -1,0 +1,52 @@
+#include "logfsos.h"
+#include "logfs.h"
+#include "nandfs.h"
+#include "nandecc.h"
+#include "local.h"
+
+char *
+nandfsreadpage(Nandfs *nandfs, void *buf, NandfsTags *tags, long block, int page, int reportbad, LogfsLowLevelReadResult *result)
+{
+ ulong ecc1, ecc2, storedecc1, storedecc2;
+ NandEccError e1, e2;
+ ulong rawoffset;
+ NandfsAuxiliary hdr;
+ char *errmsg;
+
+ rawoffset = nandfs->rawblocksize * (nandfs->baseblock + block) + NandfsFullSize * page;
+ errmsg = (*nandfs->read)(nandfs->magic, buf, NandfsPageSize, rawoffset);
+ if (errmsg)
+ return errmsg;
+ errmsg = (*nandfs->read)(nandfs->magic, &hdr, sizeof(hdr), rawoffset + NandfsPageSize);
+ if (errmsg)
+ return errmsg;
+ ecc1 = nandecc(buf);
+ ecc2 = nandecc((uchar *)buf + 256);
+ storedecc1 = getlittle3(hdr.ecc1);
+ storedecc2 = getlittle3(hdr.ecc2);
+ e1 = nandecccorrect(buf, ecc1, &storedecc1, reportbad);
+ e2 = nandecccorrect((uchar *)buf + 256, ecc2, &storedecc2, reportbad);
+ if (e1 == NandEccErrorBad || e2 == NandEccErrorBad)
+ *result = LogfsLowLevelReadResultHardError;
+ else if (e1 != NandEccErrorGood || e2 != NandEccErrorGood)
+ *result = LogfsLowLevelReadResultSoftError;
+ else
+ *result = LogfsLowLevelReadResultOk;
+ if (tags) {
+ *result = _nandfscorrectauxiliary(&hdr);
+ _nandfsextracttags(&hdr, tags);
+ }
+ return nil;
+}
+
+char *
+nandfsreadpagerange(Nandfs *nandfs, void *buf, long block, int page, int offset, int count, LogfsLowLevelReadResult *result)
+{
+ char *errmsg;
+ uchar tmpbuf[NandfsPageSize];
+ errmsg = nandfsreadpage(nandfs, tmpbuf, nil, block, page, 1, result);
+ if (errmsg == nil)
+ memmove(buf, tmpbuf + offset, count);
+ return errmsg;
+}
+
--- /dev/null
+++ b/libnandfs/readpageauxilliary.c
@@ -1,0 +1,35 @@
+#include "logfsos.h"
+#include "logfs.h"
+#include "nandfs.h"
+#include "local.h"
+
+static int
+countzeros(uchar byte)
+{
+ int b, count;
+ for (b = 0x80, count = 0; b; b>>= 1)
+ if ((byte & b) == 0)
+ count++;
+ return count;
+}
+
+char *
+nandfsreadpageauxiliary(Nandfs *nandfs, NandfsTags *tags, long block, int page, int correct, LogfsLowLevelReadResult *result)
+{
+ NandfsAuxiliary hdr;
+ char *rv;
+
+ rv = (*nandfs->read)(nandfs->magic, &hdr, sizeof(hdr), nandfs->rawblocksize * (nandfs->baseblock + block) + page * NandfsFullSize + NandfsPageSize);
+ if (rv)
+ return rv;
+ if (countzeros(hdr.blockstatus) > 2) {
+ *result = LogfsLowLevelReadResultBad;
+ return nil;
+ }
+ if (correct)
+ *result = _nandfscorrectauxiliary(&hdr);
+ else
+ *result = LogfsLowLevelReadResultOk;
+ _nandfsextracttags(&hdr, tags);
+ return nil;
+}
--- /dev/null
+++ b/libnandfs/reformatblock.c
@@ -1,0 +1,34 @@
+#include "logfsos.h"
+#include "logfs.h"
+#include "nandfs.h"
+#include "local.h"
+
+char *
+nandfsreformatblock(Nandfs *nandfs, long block, uchar tag, ulong path, int xcount, long *xdata, void *llsave, int *markedbad)
+{
+ int bad;
+ char *errmsg;
+ NandfsBlockData *d;
+ long nerase;
+
+ if (nandfs->blockdata == nil)
+ return Eperm;
+
+ nerase = *(ulong *)llsave;
+
+ errmsg = nandfsformatblock(nandfs, block, tag, path,
+ nandfs->baseblock, nandfs->limitblock - nandfs->baseblock, xcount, xdata, &nerase, &bad);
+
+ if (markedbad)
+ *markedbad = bad;
+ if (errmsg)
+ return errmsg;
+
+ d = &nandfs->blockdata[block];
+ d->tag = bad ? LogfsTbad : tag;
+ d->path = path;
+ d->nerase = nerase;
+ d->partial = 0;
+
+ return nil;
+}
--- /dev/null
+++ b/libnandfs/setget.c
@@ -1,0 +1,101 @@
+#include "logfsos.h"
+#include "logfs.h"
+#include "nandfs.h"
+#include "local.h"
+
+short
+nandfsgettag(Nandfs *nandfs, long block)
+{
+ if (nandfs->blockdata)
+ return nandfs->blockdata[block].tag;
+ return 0;
+}
+
+void
+nandfssettag(Nandfs *nandfs, long block, short tag)
+{
+ if (nandfs->blockdata) {
+ nandfs->blockdata[block].tag = tag;
+ if (tag == LogfsTworse)
+ nandfs->worseblocks = 1;
+ return;
+ }
+}
+
+long
+nandfsgetpath(Nandfs *nandfs, long block)
+{
+ if (nandfs->blockdata)
+ return nandfs->blockdata[block].path;
+ return 0;
+}
+
+void
+nandfssetpath(Nandfs *nandfs, long block, ulong path)
+{
+ if (nandfs->blockdata) {
+ nandfs->blockdata[block].path = path;
+ return;
+ }
+}
+
+long
+nandfsgetnerase(Nandfs *nandfs, long block)
+{
+ if (nandfs->blockdata)
+ return nandfs->blockdata[block].nerase;
+ return 0;
+}
+
+void
+nandfssetnerase(Nandfs *nandfs, long block, ulong nerase)
+{
+ if (nandfs->blockdata) {
+ nandfs->blockdata[block].nerase = nerase;
+ return;
+ }
+}
+
+int
+nandfsgetblockpartialformatstatus(Nandfs *nandfs, long block)
+{
+ if (nandfs->blockdata)
+ return nandfs->blockdata[block].partial;
+ return 0;
+}
+
+void
+nandfssetblockpartialformatstatus(Nandfs *nandfs, long block, int partial)
+{
+ if (nandfs->blockdata) {
+ nandfs->blockdata[block].partial = partial;
+ return;
+ }
+}
+
+long
+nandfsgetbaseblock(Nandfs *nandfs)
+{
+ return nandfs->baseblock;
+}
+
+int
+nandfsgetblocksize(Nandfs *nandfs)
+{
+ return 1 << (nandfs->ll.l2pagesperblock + NandfsL2PageSize);
+}
+
+ulong
+nandfscalcrawaddress(Nandfs *nandfs, long pblock, int dataoffset)
+{
+ int lpage, pageoffset;
+ lpage = dataoffset / NandfsPageSize;
+ pageoffset = dataoffset % NandfsPageSize;
+ return nandfs->rawblocksize * pblock + lpage * NandfsFullSize + pageoffset;
+}
+
+int
+nandfsgetopenstatus(Nandfs *nandfs)
+{
+ return nandfs->blockdata != nil;
+}
--- /dev/null
+++ b/libnandfs/updatepage.c
@@ -1,0 +1,38 @@
+#include "logfsos.h"
+#include "logfs.h"
+#include "nandfs.h"
+#include "nandecc.h"
+#include "local.h"
+
+char *
+nandfsupdatepage(Nandfs *nandfs, void *buf, ulong path, uchar tag, long block, int page)
+{
+ uchar tbuf[NandfsFullSize];
+ ulong ecc1, ecc2;
+ ulong rawoffset;
+ NandfsAuxiliary *hdr;
+
+ rawoffset = (nandfs->baseblock + block) * nandfs->rawblocksize + page * NandfsFullSize;
+ memmove(tbuf, buf, NandfsPageSize);
+ ecc1 = nandecc(tbuf);
+ ecc2 = nandecc(tbuf + 256);
+ hdr = (NandfsAuxiliary *)(tbuf + NandfsPageSize);
+ memset(hdr, 0xff, sizeof(*hdr));
+ hdr->tag = tag;
+ if (path < NandfsPathMask) {
+ ulong tmp = _nandfshamming31_26calc(path << 6) | (1 << 5);
+ putbig4(hdr->parth, tmp);
+ }
+ putlittle3(hdr->ecc1, ecc1);
+ putlittle3(hdr->ecc2, ecc2);
+ return (*nandfs->write)(nandfs->magic, tbuf, sizeof(tbuf), rawoffset);
+}
+
+char *
+nandfswritepage(Nandfs *nandfs, void *buf, long block, int page)
+{
+ ulong writepath = nandfsgetpath(nandfs, block);
+ uchar writetag = nandfsgettag(nandfs, block);
+//print("block %ld writepath 0x%.8lux writetag 0x%.2ux\n", block, writepath, writetag);
+ return nandfsupdatepage(nandfs, buf, writepath, writetag, block, page);
+}
--- /dev/null
+++ b/libnandfs/writeblock.c
@@ -1,0 +1,47 @@
+#include "logfsos.h"
+#include "logfs.h"
+#include "nandfs.h"
+#include "local.h"
+
+char *
+nandfswriteblock(Nandfs *nandfs, void *buf, uchar tag, ulong path, int xcount, long *data, long block)
+{
+ int p;
+ char *errmsg;
+
+ ulong opath = nandfsgetpath(nandfs, block);
+ ulong writepath = (~opath | path) & NandfsPathMask;
+ uchar writetag = ~nandfsgettag(nandfs, block) | tag;
+ int ppb = 1 << nandfs->ll.l2pagesperblock;
+
+ for (p = 0; p < ppb; p++) {
+ ulong wp;
+ if (p > 0 && p <= 2 + xcount) {
+ switch (p) {
+ case 1:
+ wp = (~opath | nandfsgetbaseblock(nandfs)) & NandfsPathMask;
+ break;
+ case 2:
+ wp = (~opath | nandfs->ll.blocks) & NandfsPathMask;
+ break;
+ default:
+ wp = (~opath | data[p - 3]) & NandfsPathMask;
+ break;
+ }
+ }
+ else
+ wp = writepath;
+ errmsg = nandfsupdatepage(nandfs, buf, wp, writetag, block, p);
+ if (errmsg)
+ return errmsg;
+#ifdef LOGFSTEST
+ if (logfstest.partialupdate && p > 0) {
+ print("skipping pageupdate\n");
+ break;
+ }
+#endif
+ buf = (uchar *)buf + NandfsPageSize;
+ }
+
+ return nil;
+}
--- /dev/null
+++ b/libnandfs/writepageauxilliary.c
@@ -1,0 +1,33 @@
+#include "logfsos.h"
+#include "logfs.h"
+#include "nandfs.h"
+#include "local.h"
+
+/*
+ * update the tags in a page's auxiliary area
+ * only touch the fields if they contain some zeros, and compute the hamming codes
+ * as well
+ */
+
+char *
+nandfswritepageauxiliary(Nandfs *nandfs, NandfsTags *tags, long absblock, int page)
+{
+ NandfsAuxiliary hdr;
+ ulong tmp;
+ ushort htmp;
+
+ memset(&hdr, 0xff, sizeof(hdr));
+ if (tags->path < NandfsPathMask) {
+ tmp = _nandfshamming31_26calc((tags->path << 6)) | (1 << 5);
+ putbig4(hdr.parth, tmp);
+ }
+ if (tags->nerase < NandfsNeraseMask || tags->magic != 0xff) {
+ tmp = _nandfshamming31_26calc((tags->magic << 24) | (tags->nerase << 6)) | (1 << 5);
+ htmp = tmp >> 16;
+ putbig2(hdr.nerasemagicmsw, htmp);
+ putbig2(hdr.nerasemagiclsw, tmp);
+ }
+ if (tags->tag != 0xff)
+ hdr.tag = tags->tag;
+ return (*nandfs->write)(nandfs->magic, &hdr, sizeof(hdr), nandfs->rawblocksize * absblock + page * NandfsFullSize + NandfsPageSize);
+}
--- /dev/null
+++ b/libprefab/NOTICE
@@ -1,0 +1,25 @@
+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 © 1995-1999 Lucent Technologies Inc.
+Portions Copyright © 1997-2000 Vita Nuova Limited
+Portions Copyright © 2000-2007 Vita Nuova Holdings Limited
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU Lesser General Public License (`LGPL') as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
--- /dev/null
+++ b/libprefab/box.c
@@ -1,0 +1,80 @@
+#include <lib9.h>
+#include <draw.h>
+#include <interp.h>
+#include <isa.h>
+#include "../libinterp/runt.h"
+#include <drawif.h>
+#include <prefab.h>
+
+PCompound*
+box(Prefab_Environ *e, Draw_Point p, Prefab_Element *title, Prefab_Element *list)
+{
+ Draw_Rect er, r, lr;
+ PCompound *pc;
+ Prefab_Compound *c;
+ Image *disp;
+ Draw_Image *ddisp;
+ Screen *screen;
+ Heap *h;
+ Point pt;
+ int w;
+
+ if(list == H)
+ return H;
+ screen = lookupscreen(e->screen);
+ if(screen == nil)
+ return H;
+ h = heapz(TCompound);
+ if(h == H)
+ return H;
+ pc = H2D(PCompound*, h);
+ c = &pc->c;
+
+ gchalt++;
+ r = list->r;
+ if(title != H){
+ w = 2+1+3+Dx(title->r)+1;
+ if(w > Dx(r))
+ r.max.x = r.min.x + w;
+ r.max.y += 2+1+Dy(title->r)+1;
+ }
+
+ er = edgerect(e, p, &r);
+
+ disp = allocwindow(screen, IRECT(er), Refbackup /*refreshcompound*/, DWhite);
+ if(disp == nil){
+ Err:
+ destroy(c);
+ gchalt--;
+ return H;
+ }
+ if((ddisp=mkdrawimage(disp, e->screen, e->screen->display, nil)) == H){
+ freeimage(disp);
+ goto Err;
+ }
+
+ lr = r;
+ if(title != H){
+ pt.x = r.min.x+3;
+ pt.y = r.min.y+3;
+ translateelement(title, pt);
+ lr.min.y = title->r.max.y+1;
+ }
+ translateelement(list, subpt(IPOINT(lr.min), IPOINT(list->r.min)));
+
+ c->r = r;
+ c->image = ddisp;
+ c->environ = e;
+ D2H(e)->ref++;
+ if(title != H){
+ c->title = title;
+ D2H(title)->ref++;
+ }
+ if(list != H){
+ c->contents = (Prefab_Element*)list;
+ D2H(list)->ref++;
+ }
+ pc->display = screen->display;
+ gchalt--;
+ return pc;
+}
--- /dev/null
+++ b/libprefab/compound.c
@@ -1,0 +1,193 @@
+#include <lib9.h>
+#include <draw.h>
+#include <interp.h>
+#include <isa.h>
+#include "../libinterp/runt.h"
+#include <drawif.h>
+#include <prefab.h>
+
+extern void queuerefresh(Image *i, Rectangle r, Reffn reffn, void *refptr);
+
+Draw_Rect
+edgerect(Prefab_Environ *e, Draw_Point p, Draw_Rect *rin)
+{
+ Draw_Rect r;
+ Screen *s;
+
+ r.min.x = p.x;
+ r.min.y = p.y;
+ r.max.x = p.x + 1 + Dx(*rin) + 1;
+ r.max.y = p.y + 1 + Dy(*rin) + 1;
+ /* outer box computed; now make sure it's all visible */
+ s = lookupscreen(e->screen);
+ if(s != nil)
+ fitrect((Rectangle*)&r, s->display->image->r);
+
+ rin->min.x = r.min.x+1;
+ rin->min.y = r.min.y+1;
+ rin->max.x = r.max.x-1;
+ rin->max.y = r.max.y-1;
+
+ return r;
+}
+
+/*
+ * Draw edge around r.
+ * Assume geometry has already been clipped and adjusted.
+ */
+void
+edge(Prefab_Environ *e, Image *box, Draw_Rect dr, Draw_Rect dclipr)
+{
+ Rectangle r, r1, clipr;
+ Image *ec;
+ Screen *s;
+
+ R2R(r, dr);
+ R2R(clipr, dclipr);
+ r.min.x -= 1;
+ r.min.y -= 1;
+ r.max.x += 1;
+ r.max.y += 1;
+ s = lookupscreen(e->screen);
+ if(s == nil)
+ return;
+ ec = lookupimage(e->style->edgecolor);
+ if(ec == nil)
+ return;
+
+ r1 = r;
+ r1.min.y++;
+ r1.max.y = r1.min.y+2;
+ r1.max.x = r1.min.x+2*(r1.max.x-r1.min.x)/3;
+ if(rectclip(&r1, clipr))
+ draw(box, r1, ec, nil, r1.min);
+ r1 = r;
+ r1.min.x++;
+ r1.max.x = r1.min.x+2;
+ r1.max.y = r1.min.y+2*(r1.max.y-r1.min.y)/3;
+ if(rectclip(&r1, clipr))
+ draw(box, r1, ec, nil, r1.min);
+ r1=r;
+ r1.min.x = r1.max.x-1;
+ if(rectclip(&r1, clipr))
+ draw(box, r1, ec, nil, r1.min);
+ r1=r;
+ r1.min.y = r1.max.y-1;
+ if(rectclip(&r1, clipr))
+ draw(box, r1, ec, nil, r1.min);
+ r1 = r;
+ r1.max.y = r1.min.y+1;
+ if(rectclip(&r1, clipr))
+ draw(box, r1, ec, nil, r1.min);
+ r1=r;
+ r1.max.x = r1.min.x+1;
+ if(rectclip(&r1, clipr))
+ draw(box, r1, ec, nil, r1.min);
+}
+
+void
+redrawcompound(Image *i, Rectangle clipr, Prefab_Compound *c)
+{
+ Rectangle r1, rt, r;
+ int l, len;
+ Prefab_Style *s;
+ Image *elemcolor, *edgecolor;
+ List *list;
+ Font *font;
+ Prefab_Element *e;
+
+ if(c==H || badenviron(c->environ, 0))
+ return;
+
+ r = clipr;
+ s = c->environ->style;
+ elemcolor = lookupimage(s->elemcolor);
+ edgecolor = lookupimage(s->edgecolor);
+ if(elemcolor==nil || edgecolor==nil)
+ return;
+ draw(i, r, elemcolor, nil, r.min);
+ if(lookupelement(c->title) != H){
+ R2R(rt, c->title->r);
+ if(c->title->environ!=H && c->title->environ->style!=H && rectXrect(r, rt)){
+ drawelement(c->title, i, r, c->environ==c->title->environ, 0);
+ r1.min.x = c->r.min.x;
+ r1.min.y = c->title->r.max.y;
+ s = c->title->environ->style;
+ len = 0;
+ switch(c->title->kind){
+ case ETitle:
+ font = lookupfont(s->titlefont);
+ if(font != nil)
+ len = 2+1+stringwidth(font, string2c(c->title->str));
+ break;
+ case EVertical:
+ font = lookupfont(s->titlefont);
+ if(font != nil)
+ for(list=c->title->kids; list!=H; list=list->tail){
+ e = *(Prefab_Element**)list->data;
+ l = stringwidth(font, string2c(e->str));
+ if(l > len)
+ len = l;
+ }
+ len += 2+1;
+ break;
+ default:
+ len = r1.min.x+2*Dx(c->r)/3;
+ }
+ r1.max.x = r1.min.x + len;
+ r1.max.y = r1.min.y+1;
+ draw(i, r1, edgecolor, nil, r.min);
+ r.min.y = r1.max.y;
+ }
+ }
+ if(c->contents!=H)
+ drawelement(c->contents, i, r, c->environ==c->contents->environ, 0);
+ edge(c->environ, i, c->r, DRECT(clipr));
+}
+
+void
+refreshcompound(Image *i, Rectangle r, void *ptr)
+{
+ Prefab_Compound *c;
+
+ c = ptr;
+ if(c == nil)
+ return;
+ if(i == nil){ /* called from flushimage */
+ i = lookupimage(c->image);
+ if(i == nil)
+ return;
+ }
+ redrawcompound(i, r, c);
+}
+
+void
+localrefreshcompound(Memimage *mi, Rectangle r, void *ptr)
+{
+ Prefab_Compound *c;
+ Image *i;
+
+ USED(mi); /* can't do anything with this, but it's part of the memlayer interface */
+ c = ptr;
+ if(c == nil)
+ return;
+ i = lookupimage(c->image);
+ if(i == nil)
+ return;
+ queuerefresh(i, r, refreshcompound, ptr);
+}
+
+void
+drawcompound(Prefab_Compound *c)
+{
+ Image *i;
+
+ if(c==H || c->image==H)
+ return;
+ i = lookupimage(c->image);
+ redrawcompound(i, insetrect(IRECT(c->r), -1), c);
+ if(i->display->local && i->refptr==nil)
+ if(drawlsetrefresh(i->display->dataqid, i->id, localrefreshcompound, c) <= 0)
+ fprint(2, "drawcompound: can't set refresh\n");
+ i->refptr = c; /* can now be refreshed */
+}
--- /dev/null
+++ b/libprefab/element.c
@@ -1,0 +1,723 @@
+#include <lib9.h>
+#include <draw.h>
+#include <interp.h>
+#include <isa.h>
+#include "../libinterp/runt.h"
+#include <drawif.h>
+#include <prefab.h>
+
+
+void icondraw(Prefab_Element*, Image*, Rectangle, int, int);
+void textdraw(Prefab_Element*, Image*, Rectangle, int, int);
+void listdraw(Prefab_Element*, Image*, Rectangle, int, int);
+void outlinehighlight(Prefab_Element*, Image*, Prefab_Compound*, int);
+void texthighlight(Prefab_Element*, Image*, Prefab_Compound*, int);
+void simpleclip(Prefab_Element*, Rectangle);
+void horizontalclip(Prefab_Element*, Rectangle);
+void verticalclip(Prefab_Element*, Rectangle);
+void textscroll(Prefab_Element*, Point, int*);
+void horizontalscroll(Prefab_Element*, Point, int*);
+void verticalscroll(Prefab_Element*, Point, int*);
+void iconscroll(Prefab_Element*, Point, int*);
+
+struct
+{
+ void (*draw)(Prefab_Element*, Image*, Rectangle, int, int);
+ void (*highlight)(Prefab_Element*, Image*, Prefab_Compound*, int);
+ void (*clip)(Prefab_Element*, Rectangle);
+ void (*scroll)(Prefab_Element*, Point, int*);
+}elemfn[] = {
+ /* EIcon */ { icondraw, outlinehighlight, simpleclip, iconscroll, },
+ /* EText */ { textdraw, texthighlight, simpleclip, textscroll, },
+ /* ETitle */ { textdraw, outlinehighlight, simpleclip, textscroll, },
+ /* EHorizontal */ { listdraw, outlinehighlight, horizontalclip, horizontalscroll, },
+ /* EVertical */ { listdraw, outlinehighlight, verticalclip, verticalscroll, },
+ /* ESeparator */ { icondraw, outlinehighlight, simpleclip, iconscroll, },
+};
+
+Point
+iconsize(Image *image)
+{
+ Point dd;
+
+ if(image->repl){
+ dd.x = Dx(image->clipr);
+ dd.y = Dy(image->clipr);
+ }else{
+ dd.x = Dx(image->r);
+ dd.y = Dy(image->r);
+ }
+ return dd;
+}
+
+void
+icondraw(Prefab_Element *elem, Image *i, Rectangle clipr, int clean, int highlight)
+{
+ Prefab_Style *style;
+ Rectangle r;
+ Point p;
+ PElement *pelem;
+ Image *image, *c;
+ Point size;
+
+ USED(highlight);
+ pelem = lookupelement(elem);
+ if(pelem == H)
+ return;
+ if(!rectclip(&clipr, i->clipr))
+ return;
+ R2R(r, elem->r);
+ if(!rectclip(&clipr, r))
+ return;
+ if(elem->image==H || elem->mask==H || badenviron(elem->environ, 0))
+ return;
+ style = elem->environ->style;
+ if(!clean){
+ c = lookupimage(style->elemcolor);
+ if(c != nil)
+ draw(i, clipr, c, nil, clipr.min);
+ }
+ r.min = pelem->drawpt;
+ image = lookupimage(elem->image);
+ if(image == nil)
+ return;
+ size = iconsize(image);
+ r.max.x = r.min.x+size.x;
+ r.max.y = r.min.y+size.y;
+ if(rectclip(&r, clipr)){
+ p = image->r.min;
+ p.x += r.min.x-pelem->drawpt.x;
+ p.y += r.min.y-pelem->drawpt.y;
+ c = lookupimage(elem->mask);
+ if(c != nil)
+ draw(i, r, image, c, p);
+ }
+}
+
+void
+textdraw(Prefab_Element *elem, Image *i, Rectangle clipr, int clean, int highlight)
+{
+ Prefab_Style *style;
+ Rectangle r;
+ PElement *pelem;
+ Image *color, *c;
+ Font *font;
+
+ USED(highlight);
+ pelem = lookupelement(elem);
+ if(pelem == H)
+ return;
+ if(!rectclip(&clipr, i->clipr))
+ return;
+ R2R(r, elem->r);
+ if(!rectclip(&clipr, r))
+ return;
+ if(elem->str==H || badenviron(elem->environ, 0))
+ return;
+ style = elem->environ->style;
+ font = lookupfont(elem->font);
+ if(font == nil)
+ return;
+ if(highlight)
+ color = lookupimage(style->highlightcolor);
+ else
+ color = lookupimage(elem->image);
+ if(!clean){
+ c = lookupimage(style->elemcolor);
+ if(c != nil)
+ draw(i, clipr, c, nil, clipr.min);
+ }
+ if(color != nil)
+ _string(i, pelem->drawpt, color, pelem->drawpt, font, string2c(elem->str), nil, 1<<24, clipr, nil, pelem->drawpt, SoverD);
+}
+
+void
+listdraw(Prefab_Element *elem, Image *i, Rectangle clipr, int clean, int highlight)
+{
+ Prefab_Style *style;
+ Prefab_Element *e;
+ List *l;
+ Rectangle r;
+ PElement *pelem;
+ Image *c;
+
+ pelem = lookupelement(elem);
+ if(pelem == H)
+ return;
+ if(!rectclip(&clipr, i->clipr))
+ return;
+ R2R(r, elem->r);
+ if(!rectclip(&clipr, r))
+ return;
+ if(elem->kids==H || badenviron(elem->environ, 0))
+ return;
+ if(pelem->first != elem->kids) /* error? */
+ return;
+ style = elem->environ->style;
+ if(!clean){
+ c = lookupimage(style->elemcolor);
+ if(c != nil)
+ draw(i, clipr, c, nil, clipr.min);
+ }
+ for(l=pelem->vfirst; l!=H; l=l->tail){
+ e = *(Prefab_Element**)l->data;
+ R2R(r, e->r);
+ if(rectXrect(r, clipr))
+ drawelement(e, i, clipr, elem->environ==e->environ, highlight);
+ if(l == pelem->vlast)
+ break;
+ }
+}
+
+void
+drawelement(Prefab_Element *elem, Image *i, Rectangle clipr, int clean, int highlight)
+{
+ PElement *pelem;
+
+ if(elem != H){
+ pelem = lookupelement(elem);
+ if(pelem == H)
+ return;
+ (*elemfn[elem->kind].draw)(elem, i, clipr, clean, highlight);
+ if(!highlight && pelem->highlight!=H)
+ (*elemfn[elem->kind].highlight)(elem, i, pelem->highlight, 1);
+ }
+}
+
+void
+translateelement(Prefab_Element *elem, Point delta)
+{
+ PElement *pelem;
+ List *l;
+
+ if(elem == H)
+ return;
+ pelem = lookupelement(elem);
+ if(pelem == H)
+ return;
+ elem->r.min.x += delta.x;
+ elem->r.min.y += delta.y;
+ elem->r.max.x += delta.x;
+ elem->r.max.y += delta.y;
+ pelem->drawpt.x += delta.x;
+ pelem->drawpt.y += delta.y;
+ switch(elem->kind){
+ case EHorizontal:
+ case EVertical:
+ if(pelem->first != elem->kids)
+ return;
+ for(l=elem->kids; l!=H; l=l->tail)
+ translateelement(*(Prefab_Element**)l->data, delta);
+ break;
+ }
+}
+
+int
+fitrect(Rectangle *r, Rectangle sr)
+{
+ if(r->max.x > sr.max.x){
+ r->min.x -= r->max.x-sr.max.x;
+ r->max.x = sr.max.x;
+ }
+ if(r->max.y > sr.max.y){
+ r->min.y -= r->max.y-sr.max.y;
+ r->max.y = sr.max.y;
+ }
+ if(r->min.x < sr.min.x){
+ r->max.x += sr.min.x-r->min.x;
+ r->min.x = sr.min.x;
+ }
+ if(r->min.y < sr.min.y){
+ r->max.y += sr.min.y-r->min.y;
+ r->min.y = sr.min.y;
+ }
+ return rectinrect(*r, sr);
+}
+
+void
+adjusthorizontal(Prefab_Element *elem, int spacing, int position)
+{
+ int edx, dx, i, x;
+ int nlist; /* BUG: should precompute */
+ List *l;
+ PElement *pelem;
+ Prefab_Element *e;
+ Point p;
+
+ pelem = lookupelement(elem);
+ if(pelem == H)
+ return;
+ if(pelem->first != elem->kids)
+ return;
+ p.y = 0;
+ switch(spacing){
+ default: /* shouldn't happen; protected by adjustelement */
+ case Adjpack:
+ x = elem->r.min.x;
+ for(l=elem->kids; l!=H; l=l->tail){
+ e = *(Prefab_Element**)l->data;
+ p.x = x - e->r.min.x;
+ translateelement(e, p);
+ x += Dx(e->r);
+ }
+ elem->r.max.x = x;
+ return;
+
+ case Adjequal:
+ dx = 0;
+ nlist = 0;
+ for(l=elem->kids; l!=H; l=l->tail){
+ e = *(Prefab_Element**)l->data;
+ if(dx < Dx(e->r))
+ dx = Dx(e->r);
+ nlist++;
+ }
+ elem->r.max.x = elem->r.min.x+nlist*dx;
+ break;
+
+ case Adjfill:
+ nlist = 0;
+ for(l=elem->kids; l!=H; l=l->tail)
+ nlist++;
+ dx = Dx(elem->r)/nlist;
+ break;
+ }
+ i = 0;
+ for(l=elem->kids; l!=H; l=l->tail){
+ e = *(Prefab_Element**)l->data;
+ edx = Dx(e->r);
+ if(position == Adjleft)
+ edx = 0;
+ else if(position == Adjcenter)
+ edx = (dx-edx)/2;
+ else /* right */
+ edx = dx-edx;
+ p.x = (elem->r.min.x+i*dx + edx) - e->r.min.x;
+ translateelement(e, p);
+ i++;
+ }
+}
+
+void
+adjustvertical(Prefab_Element *elem, int spacing, int position)
+{
+ int edy, dy, i, y;
+ int nlist; /* BUG: should precompute */
+ List *l;
+ PElement *pelem;
+ Prefab_Element *e;
+ Point p;
+
+ pelem = lookupelement(elem);
+ if(pelem == H)
+ return;
+ if(pelem->first != elem->kids)
+ return;
+ p.x = 0;
+ switch(spacing){
+ default: /* shouldn't happen; protected by adjustelement */
+ case Adjpack:
+ y = elem->r.min.y;
+ for(l=elem->kids; l!=H; l=l->tail){
+ e = *(Prefab_Element**)l->data;
+ p.y = y - e->r.min.y;
+ translateelement(e, p);
+ y += Dy(e->r);
+ }
+ elem->r.max.y = y;
+ return;
+
+ case Adjequal:
+ dy = 0;
+ nlist = 0;
+ for(l=elem->kids; l!=H; l=l->tail){
+ e = *(Prefab_Element**)l->data;
+ if(dy < Dy(e->r))
+ dy = Dy(e->r);
+ nlist++;
+ }
+ elem->r.max.y = elem->r.min.y+nlist*dy;
+ break;
+
+ case Adjfill:
+ nlist = 0;
+ for(l=elem->kids; l!=H; l=l->tail)
+ nlist++;
+ dy = Dy(elem->r)/nlist;
+ break;
+ }
+ i = 0;
+ for(l=elem->kids; l!=H; l=l->tail){
+ e = *(Prefab_Element**)l->data;
+ edy = Dy(e->r);
+ if(position == Adjup)
+ edy = 0;
+ else if(position == Adjcenter)
+ edy = (dy-edy)/2;
+ else /* down */
+ edy = dy-edy;
+ p.y = (elem->r.min.y+i*dy + edy) - e->r.min.y;
+ translateelement(e, p);
+ i++;
+ }
+}
+
+void
+adjustelement(Prefab_Element *elem, int spacing, int position)
+{
+ if(lookupelement(elem) == H)
+ return;
+ if(spacing<Adjpack || spacing>Adjfill || position<Adjleft || position>Adjdown)
+ return;
+ switch(elem->kind){
+ case EVertical:
+ adjustvertical(elem, spacing, position);
+ break;
+ case EHorizontal:
+ adjusthorizontal(elem, spacing, position);
+ break;
+ }
+}
+
+void
+highlightelement(Prefab_Element *elem, Image *i, Prefab_Compound *comp, int on)
+{
+ PElement *pelem;
+
+ pelem = lookupelement(elem);
+ if(pelem!=H && lookupcompound(comp)!=H){
+ if(on)
+ pelem->highlight = comp;
+ else
+ pelem->highlight = H;
+ (*elemfn[elem->kind].highlight)(elem, i, comp, on);
+ }
+}
+
+static
+int
+anytextelements(Prefab_Element *e)
+{
+ Prefab_Element *t;
+ List *l;
+
+ for(l=e->kids; l!=H; l=l->tail){
+ t = *(Prefab_Element**)l->data;
+ if(t->kind == EText)
+ return 1;
+ }
+ return 0;
+}
+
+void
+textlisthighlight(Prefab_Element *e, Image *i, Prefab_Compound *c, int on)
+{
+ Prefab_Element *t;
+ List *l;
+
+ for(l=e->kids; l!=H; l=l->tail){
+ t = *(Prefab_Element**)l->data;
+ if(t->kind == EText)
+ texthighlight(t, i, c, on);
+ }
+}
+
+void
+outlinehighlight(Prefab_Element *e, Image *i, Prefab_Compound *c, int on)
+{
+ List *l;
+ Prefab_Element *t;
+ Image *color;
+ Rectangle r, r1, r2;
+ Point dp;
+ int done;
+
+ /* see if we can do it by highlighting just a text element */
+ if((e->kind==EVertical || e->kind==EHorizontal) && e->kids!=H){
+ /* is any child a text element? */
+ if(anytextelements(e)){
+ textlisthighlight(e, i, c, on);
+ return;
+ }
+ /* grandchild? */
+ done = 0;
+ for(l=e->kids; l!=H; l=l->tail){
+ t = *(Prefab_Element**)l->data;
+ if(t->kind==EVertical || t->kind==EHorizontal)
+ if(anytextelements(t)){
+ textlisthighlight(t, i, c, on);
+ done = 1;
+ }
+ }
+ if(done)
+ return;
+ }
+ if(on){
+ color = lookupimage(e->environ->style->highlightcolor);
+ if(color == nil)
+ return;
+ R2R(r, e->r);
+ /* avoid outlining empty space around images */
+ dp = ((PElement*)e)->drawpt;
+ if(e->kind==EIcon && e->image->repl==0 && ptinrect(dp, r)){
+ R2R(r1, e->image->r);
+ R2R(r2, e->image->clipr);
+ if(rectclip(&r1, r2)){
+ dp.x += Dx(r1);
+ dp.y += Dy(r1);
+ if(ptinrect(dp, r))
+ r = Rpt(((PElement*)e)->drawpt, dp);
+ }
+ }
+ draw(i, r, color, nil, r.min);
+ drawelement(e, i, insetrect(r, 2), Dirty, 1);
+ }else{
+ drawelement(e, i, IRECT(e->r), Dirty, 0);
+ edge(c->environ, i, c->r, e->r);
+ }
+}
+
+void
+texthighlight(Prefab_Element *e, Image *i, Prefab_Compound *c, int on)
+{
+ drawelement(e, i, IRECT(e->r), Clean, on);
+ edge(c->environ, i, c->r, e->r);
+}
+
+void
+clipelement(Prefab_Element *elem, Rectangle r)
+{
+ if(lookupelement(elem) != H)
+ (*elemfn[elem->kind].clip)(elem, r);
+}
+
+void
+simpleclip(Prefab_Element *elem, Rectangle r)
+{
+ R2R(elem->r, r);
+}
+
+void
+horizontalclip(Prefab_Element *elem, Rectangle r)
+{
+ int x;
+ List *l;
+ Prefab_Element *e;
+ PElement *pelem;
+
+ x = r.min.x;
+ pelem = lookupelement(elem);
+ if(pelem == H)
+ return;
+ for(l=pelem->vfirst; l!=H && x<r.max.x; l=l->tail){
+ e = *(Prefab_Element**)l->data;
+ x += Dx(e->r);
+ }
+ pelem->vlast = l;
+ R2R(elem->r, r);
+}
+
+void
+verticalclip(Prefab_Element *elem, Rectangle r)
+{
+ int y;
+ List *l;
+ Prefab_Element *e;
+ PElement *pelem;
+
+ y = r.min.y;
+ pelem = lookupelement(elem);
+ if(pelem == H)
+ return;
+ for(l=pelem->vfirst; l!=H && y<r.max.y; l=l->tail){
+ e = *(Prefab_Element**)l->data;
+ y += Dy(e->r);
+ }
+ pelem->vlast = l;
+ R2R(elem->r, r);
+}
+
+void
+scrollelement(Prefab_Element *elem, Point d, int *moved)
+{
+ if(lookupelement(elem) != H)
+ (*elemfn[elem->kind].scroll)(elem, d, moved);
+}
+
+void
+textscroll(Prefab_Element *elem, Point d, int *moved)
+{
+ PElement *pelem;
+
+ pelem = lookupelement(elem);
+ if(pelem==H || (d.x==0 && d.y==0))
+ return;
+ pelem->drawpt = subpt(pelem->drawpt, d);
+ *moved = 1;
+}
+
+void
+iconscroll(Prefab_Element *elem, Point d, int *moved)
+{
+ Point p;
+ Image *i;
+ PElement *pelem;
+
+ pelem = lookupelement(elem);
+ if(pelem==H || elem->image==H || (d.x==0 && d.y==0))
+ return;
+ i = lookupimage(elem->image);
+ if(i == nil)
+ return;
+ p = subpt(pelem->drawpt, d);
+ if(i->repl == 0){
+ if(p.x+Dx(i->clipr) < elem->r.max.x)
+ p.x = elem->r.max.x - Dx(i->clipr);
+ if(p.y+Dy(i->clipr) < elem->r.max.y)
+ p.y = elem->r.max.y - Dy(i->clipr);
+ if(p.x > elem->r.min.x)
+ p.x = elem->r.min.x;
+ if(p.y > elem->r.min.y)
+ p.y = elem->r.min.y;
+ }
+ *moved = !eqpt(pelem->drawpt, p);
+ pelem->drawpt = p;
+}
+
+void
+horizontalscroll(Prefab_Element *elem, Point d, int *moved)
+{
+ List *l;
+ Prefab_Element *e;
+ PElement *pelem;
+
+ pelem = lookupelement(elem);
+ if(pelem==H || elem->kids==H || (d.x==0 && d.y==0))
+ return;
+ for(l=pelem->first; l!=H; l=l->tail){
+ e = *(Prefab_Element**)l->data;
+ translateelement(e, d);
+ }
+ for(l=pelem->first; l!=H; l=l->tail){
+ e = *(Prefab_Element**)l->data;
+ if(e->r.max.x > elem->r.min.x)
+ break;
+ }
+ pelem->vfirst = l;
+ pelem->vlast = l;
+ for(; l!=H; l=l->tail){
+ e = *(Prefab_Element**)l->data;
+ pelem->vlast = l;
+ if(e->r.min.x >= elem->r.max.x)
+ break;
+ }
+ *moved = 1;
+}
+
+void
+verticalscroll(Prefab_Element *elem, Point d, int *moved)
+{
+ List *l;
+ Prefab_Element *e;
+ PElement *pelem;
+
+ pelem = lookupelement(elem);
+ if(pelem==H || elem->kids==H || (d.x==0 && d.y==0))
+ return;
+ for(l=pelem->first; l!=H; l=l->tail){
+ e = *(Prefab_Element**)l->data;
+ translateelement(e, d);
+ }
+ for(l=pelem->first; l!=H; l=l->tail){
+ e = *(Prefab_Element**)l->data;
+ if(e->r.max.y > elem->r.min.y)
+ break;
+ }
+ pelem->vfirst = l;
+ pelem->vlast = l;
+ for(; l!=H; l=l->tail){
+ e = *(Prefab_Element**)l->data;
+ pelem->vlast = l;
+ if(e->r.min.y >= elem->r.max.y)
+ break;
+ }
+ *moved = 1;
+}
+
+/*
+ * Make e visible within list. Return value is whether any change was made;
+ * if so, must redraw (BUG: should probably do this here)
+ */
+int
+showelement(Prefab_Element *list, Prefab_Element *e)
+{
+ Point p;
+ Prefab_Element *h, *t;
+ PElement *plist;
+ int moved;
+
+ p.x = p.y = 0;
+ if(list->kids == H)
+ return 0;
+ plist = lookupelement(list);
+ if(plist == H)
+ return 0;
+ h = *(Prefab_Element**)plist->first->data;
+ t = *(Prefab_Element**)plist->last->data;
+ if(list->kind == EHorizontal){
+ p.x = (list->r.min.x+Dx(list->r)/2) - e->r.min.x;
+ if(e->r.min.x < list->r.min.x){ /* scroll to right */
+ if(e->r.max.x+p.x > list->r.max.x)
+ p.x = list->r.min.x-e->r.min.x;
+ if(h->r.min.x + p.x > list->r.min.x)
+ p.x = list->r.min.x-h->r.min.x;
+ }else if(e->r.max.x > list->r.max.x){ /* scroll to left */
+ if(e->r.min.x+p.x < list->r.min.x)
+ p.x = list->r.min.x-e->r.min.x;
+ if(t->r.max.x + p.x < list->r.max.x)
+ p.x = list->r.max.x-t->r.max.x;
+ }else
+ return 0;
+ }else if(list->kind == EVertical){
+ p.y = (list->r.min.y+Dy(list->r)/2) - e->r.min.y;
+ if(e->r.min.y < list->r.min.y){ /* scroll towards bottom */
+ if(e->r.max.y+p.y > list->r.max.y)
+ p.y = list->r.min.y-e->r.min.y;
+ if(h->r.min.y + p.y > list->r.min.y)
+ p.y = list->r.min.y-h->r.min.y;
+ }else if(e->r.max.y > list->r.max.y){ /* scroll towards top */
+ if(e->r.min.y+p.y < list->r.min.y)
+ p.y = list->r.min.y-e->r.min.y;
+ if(t->r.max.y + p.y < list->r.max.y)
+ p.y = list->r.max.y-t->r.max.y;
+ }else
+ return 0;
+ }else
+ return 0;
+ if(p.x!=0 || p.y!=0){
+ scrollelement(list, p, &moved);
+ return 1;
+ }
+ return 0;
+}
+
+PElement*
+mkelement(Prefab_Environ *env, enum Elementtype t)
+{
+ Heap *h;
+ PElement *p;
+
+ h = heapz(TElement);
+ p = H2D(PElement*, h);
+ p->highlight = H;
+ p->first = H;
+ p->last = H;
+ p->vfirst = H;
+ p->vlast = H;
+ p->nkids = 1;
+ p->pkind = t;
+ p->e.kind = t;
+ p->e.environ = env;
+ D2H(env)->ref++;
+ return p;
+}
--- /dev/null
+++ b/libprefab/elistelement.c
@@ -1,0 +1,113 @@
+#include <lib9.h>
+#include <draw.h>
+#include <interp.h>
+#include <isa.h>
+#include "../libinterp/runt.h"
+#include <drawif.h>
+#include <prefab.h>
+#include <kernel.h>
+
+List*
+prefabwrap(void *elem)
+{
+ List *l;
+ Heap *h, *e;
+
+ e = D2H(elem);
+ h = nheap(sizeof(List) + sizeof(WORD*));
+ h->t = &Tlist;
+ Tlist.ref++;
+ l = H2D(List*, h);
+ l->tail = H;
+ l->t = &Tptr;
+ Tptr.ref++;
+ e->ref++;
+ *(WORD**)l->data = elem;
+ return l;
+}
+
+static
+PElement*
+elistelement1(Prefab_Environ *e, Prefab_Element *elem, Prefab_Element *new, enum Elementtype kind)
+{
+ int first;
+ PElement *pelem;
+ List *atom;
+
+ if(badenviron(e, 0))
+ return H;
+
+ gchalt++;
+ first = 0;
+ if(new == H)
+ atom = H;
+ else
+ atom = prefabwrap(new);
+ if(elem == H){
+ pelem = mkelement(e, kind);
+ elem = &pelem->e;
+ pelem->first = H;
+ pelem->nkids = 0;
+ }else
+ pelem = (PElement*)elem;
+ if(atom == H)
+ goto Return;
+
+ if(elem->kids != pelem->first)
+ error("list Element has been modified externally");
+ if(elem->kids == H){
+ elem->kids = atom;
+ pelem->first = atom;
+ pelem->last = atom;
+ pelem->vfirst = atom;
+ pelem->vlast = atom;
+ first = 1;
+ }
+ if(new->kind!=ESeparator && Dx(elem->r)==0){
+ elem->r = new->r;
+ pelem->drawpt.x = elem->r.min.x;
+ pelem->drawpt.y = elem->r.min.y;
+ }
+ pelem->nkids++;
+ if(first)
+ goto Return;
+ pelem->last->tail = atom;
+ pelem->last = atom;
+ pelem->vlast = atom;
+ if(new->kind != ESeparator){
+ if(kind == EVertical){
+ elem->r.max.y += Dy(new->r);
+ if(elem->r.min.x > new->r.min.x)
+ elem->r.min.x = new->r.min.x;
+ if(elem->r.max.x < new->r.max.x)
+ elem->r.max.x = new->r.max.x;
+ }else{
+ elem->r.max.x += Dx(new->r);
+ if(elem->r.min.y > new->r.min.y)
+ elem->r.min.y = new->r.min.y;
+ if(elem->r.max.y < new->r.max.y)
+ elem->r.max.y = new->r.max.y;
+ }
+ }
+ pelem->pkind = kind;
+
+ Return:
+ gchalt--;
+ return pelem;
+}
+
+PElement*
+elistelement(Prefab_Environ *e, Prefab_Element *new, enum Elementtype kind)
+{
+ return elistelement1(e, H, new, kind);
+}
+
+PElement*
+appendelist(Prefab_Element *elem, Prefab_Element *new)
+{
+ if(elem->kind!=EVertical && elem->kind!=EHorizontal){
+ kwerrstr("appendelist to non-list");
+ return H;
+ }
+ return elistelement1(elem->environ, elem, new, elem->kind);
+}
--- /dev/null
+++ b/libprefab/iconbox.c
@@ -1,0 +1,83 @@
+#include <lib9.h>
+#include <draw.h>
+#include <interp.h>
+#include <isa.h>
+#include "../libinterp/runt.h"
+#include <drawif.h>
+#include <prefab.h>
+
+PCompound*
+iconbox(Prefab_Environ *e, Draw_Point p, String *titletext, Draw_Image *icon, Draw_Image *mask)
+{
+ Draw_Rect er, r, ir;
+ PCompound *pc;
+ Prefab_Compound *c;
+ PElement *elem, *title;
+ Image *disp;
+ Draw_Image *ddisp;
+ Screen *screen;
+ Heap *h;
+ Rectangle t;
+ Point pt;
+
+ screen = lookupscreen(e->screen);
+ if(screen == nil)
+ return H;
+ h = heapz(TCompound);
+ if(h == H)
+ return H;
+ pc = H2D(PCompound*, h);
+ c = &pc->c;
+
+ gchalt++;
+ title = H;
+ if(titletext != H){
+ er.min.x = 0;
+ er.min.y = 0;
+ er.max.x = Dx(icon->r)-5;
+ er.max.y = 0;
+ title = textelement(e, titletext, er, ETitle);
+ if(title == H){
+ Err:
+ destroy(c);
+ gchalt--;
+ return H;
+ }
+ c->title = (Prefab_Element*)title;
+ }
+
+ r = icon->r;
+ if(title != H)
+ r.max.y += 2+1+title->nkids*e->style->titlefont->height+1;
+
+ er = edgerect(e, p, &r);
+
+ R2R(t, er);
+ disp = allocwindow(screen, t, Refbackup /*refreshcompound*/, DWhite);
+ if(disp == nil)
+ goto Err;
+
+ if((ddisp=mkdrawimage(disp, e->screen, e->screen->display, nil)) == H){
+ freeimage(disp);
+ goto Err;
+ }
+
+ ir = r;
+ if(title != H){
+ ir = r;
+ pt.x = r.min.x+3;
+ pt.y = r.min.y+3;
+ translateelement(&title->e, pt);
+ ir.min.y = title->e.r.max.y+1;
+ }
+
+ elem = iconelement(e, ir, icon, mask);
+ c->r = r;
+ c->image = ddisp;
+ c->environ = e;
+ D2H(e)->ref++;
+ c->contents = (Prefab_Element*)elem;
+ pc->display = screen->display;
+ gchalt--;
+ return pc;
+}
--- /dev/null
+++ b/libprefab/iconelement.c
@@ -1,0 +1,50 @@
+#include <lib9.h>
+#include <draw.h>
+#include <interp.h>
+#include <isa.h>
+#include "../libinterp/runt.h"
+#include <drawif.h>
+#include <prefab.h>
+
+static
+PElement*
+iconelement1(Prefab_Environ *e, Draw_Rect r, Draw_Image *icon, Draw_Image *mask, enum Elementtype kind)
+{
+ PElement *pelem;
+ Prefab_Element *elem;
+
+ if(badenviron(e, 0) || icon==H || mask==H)
+ return H;
+ pelem = mkelement(e, kind);
+ if(pelem == H)
+ return H;
+ elem = &pelem->e;
+
+ if(Dx(r))
+ elem->r = r;
+ else{
+ elem->r.min = r.min;
+ elem->r.max.x = r.min.x + Dx(icon->r);
+ elem->r.max.y = r.min.y + Dy(icon->r);
+ }
+ elem->mask = mask;
+ D2H(mask)->ref++;
+ elem->image = icon;
+ D2H(icon)->ref++;
+ pelem->drawpt = IPOINT(r.min);
+ pelem->nkids = 1;
+ pelem->pkind = kind;
+ return pelem;
+}
+
+PElement*
+iconelement(Prefab_Environ *e, Draw_Rect r, Draw_Image *icon, Draw_Image *mask)
+{
+ return iconelement1(e, r, icon, mask, EIcon);
+}
+
+PElement*
+separatorelement(Prefab_Environ *e, Draw_Rect r, Draw_Image *icon, Draw_Image *mask)
+{
+ return iconelement1(e, r, icon, mask, ESeparator);
+}
--- /dev/null
+++ b/libprefab/mkfile
@@ -1,0 +1,21 @@
+<../mkconfig
+
+LIB=libprefab.a
+
+OFILES=\
+ box.$O\
+ compound.$O\
+ element.$O\
+ elistelement.$O\
+ iconbox.$O\
+ iconelement.$O\
+ textbox.$O\
+ textelement.$O\
+
+HFILES=\
+ $ROOT/include/draw.h\
+ $ROOT/include/prefab.h\
+
+<$ROOT/mkfiles/mksyslib-$SHELLTYPE
+
+$OFILES: $ROOT/module/prefab.m
--- /dev/null
+++ b/libprefab/textbox.c
@@ -1,0 +1,138 @@
+#include <lib9.h>
+#include <draw.h>
+#include <interp.h>
+#include <isa.h>
+#include "../libinterp/runt.h"
+#include <drawif.h>
+#include <prefab.h>
+
+PCompound*
+layoutbox(Prefab_Environ *e, Draw_Rect rr, String *titletext, List *texttext)
+{
+ Draw_Rect er, r, lr;
+ PCompound *pc;
+ Prefab_Compound *c;
+ PElement *title, *text;
+ Image *disp;
+ Draw_Image *ddisp;
+ Screen *screen;
+ Heap *h;
+ Rectangle t;
+ int wid, w;
+ Point p, pt;
+
+ screen = lookupscreen(e->screen);
+ if(screen == nil)
+ return H;
+
+ gchalt++;
+ wid = Dx(rr);
+ P2P(p, rr.min);
+ title = H;
+ text = H;
+ if(texttext != H){
+ er.min.x = 0;
+ er.min.y = 0;
+ er.max.x = wid-5;
+ er.max.y = Dy(rr);
+ text = layoutelement(e, texttext, er, EText);
+ if(text == H){
+ gchalt--;
+ return H;
+ }
+ if(wid <= 0)
+ wid = Dx(text->e.r)+5;
+ }
+ if(titletext != H){
+ /* see how wide title wants to be */
+ memset(&er, 0, sizeof er);
+ title = textelement(e, titletext, er, ETitle);
+ if(title == H){
+ Errtitle:
+ destroy(text);
+ gchalt--;
+ return H;
+ }
+ w = 2+1+3+Dx(title->e.r)+1;
+ /* if title is wider than text, adjust wid accordingly */
+ if(text!=0 && Dx(text->e.r)<w){
+ if(Dx(text->e.r) < 100){ /* narrow text; don't let title get too wide */
+ if(w > 250+5)
+ w = 250+5;
+ wid = w;
+ }
+ destroy(title);
+ er.min.x = 0;
+ er.min.y = 0;
+ er.max.x = wid-5;
+ er.max.y = 0;
+ title = textelement(e, titletext, er, ETitle);
+ if(title == H)
+ goto Errtitle;
+ }
+ if(wid <= 0)
+ wid = Dx(title->e.r)+5;
+ }
+
+ h = heapz(TCompound);
+ pc = H2D(PCompound*, h);
+ c = &pc->c;
+ c->title = (Prefab_Element*)title;
+ c->contents = (Prefab_Element*)text;
+ /* now can just destroy c to clean up */
+
+ r.min = DPOINT(p);
+ r.max.x = r.min.x+wid;
+ r.max.y = p.y+2+1 + 1+1;
+ if(title != H)
+ r.max.y += title->nkids*e->style->titlefont->height+1;
+ if(text != H)
+ r.max.y += Dy(text->e.r);
+
+ er = edgerect(e, DPOINT(p), &r);
+
+ R2R(t, er);
+ disp = allocwindow(screen, t, Refbackup /*refreshcompound*/, DWhite);
+ if(disp == nil){
+ Err:
+ destroy(c);
+ gchalt--;
+ return H;
+ }
+ if((ddisp=mkdrawimage(disp, e->screen, e->screen->display, nil)) == H){
+ freeimage(disp);
+ goto Err;
+ }
+
+ lr = r;
+ if(title != H){
+ pt.x = r.min.x+3;
+ pt.y = r.min.y+3;
+ translateelement(&title->e, pt);
+ lr.min.y = title->e.r.max.y+1;
+ }
+
+ if(text != H)
+ translateelement((Prefab_Element*)text, subpt(IPOINT(lr.min), IPOINT(text->e.r.min)));
+
+ c->r = r;
+ c->environ = e;
+ c->image = ddisp;
+ D2H(e)->ref++;
+ pc->display = screen->display;
+ gchalt--;
+ return pc;
+
+}
+
+PCompound*
+textbox(Prefab_Environ *e, Draw_Rect rr, String *titletext, String *texttext)
+{
+ PCompound *pc;
+ List *l;
+
+ l = listoflayout(e->style, texttext, EText);
+ pc = layoutbox(e, rr, titletext, l);
+ free(l);
+ return pc;
+}
--- /dev/null
+++ b/libprefab/textelement.c
@@ -1,0 +1,488 @@
+#include <lib9.h>
+#include <draw.h>
+#include <interp.h>
+#include <isa.h>
+#include "../libinterp/runt.h"
+#include <drawif.h>
+#include <prefab.h>
+#include <kernel.h>
+
+typedef struct State State;
+
+struct State
+{
+ Prefab_Environ *env;
+ List *list;
+ char word[Maxchars+UTFmax];
+ char *s;
+ char *pending;
+ Draw_Font *font;
+ Draw_Image *color;
+ Draw_Image *icon;
+ Draw_Image *mask;
+ String *tag;
+ Point p;
+ int mainkind;
+ int kind;
+ int wid;
+ int newelem;
+ int ascent;
+ int descent;
+};
+
+static
+char*
+advword(char *s, char *word)
+{
+ char *e;
+ int w;
+ Rune r;
+
+ e = s+Maxchars-1;
+ switch(*word++ = *s){
+ case '\t': /* BUG: what to do about tabs? */
+ strcpy(word-1, " ");
+ return s+1;
+ case '\n':
+ case ' ':
+ *word = 0;
+ return s+1;
+ case '\0':
+ return s;
+ }
+ s++;
+ while(s<e && *s && *s!=' ' && *s!='\t' && *s!='\n'){
+ if(*(uchar*)s < Runeself)
+ *word++ = *s++;
+ else{
+ w = chartorune(&r, s);
+ memmove(word, s, w);
+ word += w;
+ s += w;
+ }
+ }
+ *word = 0;
+ return s;
+}
+
+static
+int
+ismore(State *state)
+{
+ Prefab_Style *style;
+ Prefab_Layout *lay;
+ int text, icon;
+
+ state->newelem = 0;
+ if(state->kind==EIcon || (state->s && state->s[0]) || state->pending)
+ return 1;
+ if(state->list == H)
+ return 0;
+ lay = (Prefab_Layout*)state->list->data;
+ text = (lay->text!=H && lay->text->len != 0);
+ icon = (lay->icon!=H && lay->mask!=H);
+ if(!text && !icon)
+ return 0;
+ state->newelem = 1;
+ state->s = string2c(lay->text);
+ state->font = lay->font;
+ state->color = lay->color;
+ state->icon = lay->icon;
+ state->mask = lay->mask;
+ state->tag = lay->tag;
+ style = state->env->style;
+ if(icon) /* has precedence; if lay->icon is set, we ignore the text */
+ state->kind = EIcon;
+ else{
+ if(state->mainkind == ETitle){
+ if(state->font == H)
+ state->font = style->titlefont;
+ if(state->color == H)
+ state->color = style->titlecolor;
+ }else{
+ if(state->font == H)
+ state->font = style->textfont;
+ if(state->color == H)
+ state->color = style->textcolor;
+ }
+ state->kind = state->mainkind;
+ }
+ state->list = state->list->tail;
+ return 1;
+}
+
+PElement*
+growtext(PElement *pline, State *state, char *w, int minx, int maxx)
+{
+ String *s;
+ PElement *pe, *plist;
+ Prefab_Element *e;
+ List *atom;
+ Point size;
+ Image *image;
+
+ if(state->newelem || pline==H) {
+ pe = mkelement(state->env, state->kind);
+ e = &pe->e;
+ e->r.min.x = minx;
+ if(state->kind == EIcon){
+ e->image = state->icon;
+ D2H(e->image)->ref++;
+ e->mask = state->mask;
+ D2H(e->mask)->ref++;
+ }else{
+ e->image = state->color;
+ D2H(e->image)->ref++;
+ e->font = state->font;
+ D2H(e->font)->ref++;
+ }
+ e->tag = state->tag;
+ if(e->tag != H)
+ D2H(e->tag)->ref++;
+ if(pline == H)
+ pline = pe;
+ else{
+ if(pline->pkind != EHorizontal){
+ /* promote pline to list encapsulating current contents */
+ atom = prefabwrap(pline);
+ plist = mkelement(state->env, EHorizontal);
+ destroy(pline);
+ /* rest of plist->e.r will be set later */
+ plist->e.r.min.x = state->p.x;
+ plist->drawpt = state->p;
+ plist->e.kids = atom;
+ plist->first = atom;
+ plist->last = atom;
+ plist->vfirst = atom;
+ plist->vlast = atom;
+ pline = plist;
+ }
+ /* add e to line */
+ atom = prefabwrap(e);
+ destroy(e); /* relevant data now in wrapper */
+ e = *(Prefab_Element**)atom->data;
+ pline->last->tail = atom;
+ pline->last = atom;
+ pline->vlast = atom;
+ pline->nkids++;
+ }
+ state->newelem = 0;
+ }else{
+ pe = pline;
+ if(pe->pkind == EHorizontal)
+ pe = *(PElement**)pe->last->data;
+ e = &pe->e;
+ }
+
+ if(state->kind == EIcon){
+ /* guaranteed OK by buildine */
+ image = lookupimage(state->icon);
+ size = iconsize(image);
+ /* put one pixel on each side */
+ e->r.max.x = e->r.min.x+1+size.x+1;
+ pline->e.r.max.x = e->r.max.x;
+ if(state->ascent < size.y)
+ state->ascent = size.y;
+ state->kind = -1; /* consume EIcon from state */
+ return pline;
+ }
+
+ e->r.max.x = maxx;
+ pline->e.r.max.x = maxx;
+ if(*w == '\n') {
+ pline->newline = 1;
+ return pline;
+ }
+
+ s = addstring(e->str, c2string(w, strlen(w)), 0);
+ destroy(e->str);
+ e->str = s;
+
+ if(state->ascent < e->font->ascent)
+ state->ascent = e->font->ascent;
+ if(state->descent < e->font->height-e->font->ascent)
+ state->descent = e->font->height-e->font->ascent;
+ return pline;
+}
+
+PElement*
+buildline(State *state, int *ok)
+{
+ int wordwid, linewid, nb, rwid, x;
+ char tmp[UTFmax+1], *w, *t;
+ PElement *pl, *pe;
+ Rune r;
+ Font *f;
+ List *l;
+ Image *icon;
+ Point size;
+
+ *ok = 1;
+ linewid = 0;
+ pl = H;
+ state->ascent = 0;
+ state->descent = 0;
+ x = state->p.x;
+ while(ismore(state)){
+ f = nil;
+ if(state->kind == EIcon){
+ icon = lookupimage(state->icon);
+ if(icon == nil){
+ Error:
+ destroy(pl);
+ *ok = 0;
+ return H;
+ }
+ size = iconsize(icon);
+ wordwid = 1+size.x+1;
+ }else{
+ if(state->pending == 0){
+ state->s = advword(state->s, state->word);
+ state->pending = state->word;
+ }
+ if(*(state->pending) == '\n'){
+ pl = growtext(pl, state, state->pending, x, x);
+ if(pl == H){
+ *ok = 0;
+ return H;
+ }
+ state->pending = 0;
+ break;
+ }
+ f = lookupfont(state->font);
+ if(f == nil)
+ goto Error;
+ wordwid = stringwidth(f, state->pending);
+ }
+ if(linewid+wordwid<=state->wid){
+ Easy:
+ pl = growtext(pl, state, state->pending, x, x+wordwid);
+ if(pl == H){
+ *ok = 0;
+ return H;
+ }
+ linewid += wordwid;
+ state->pending = 0;
+ x += wordwid;
+ continue;
+ }
+ /* this word doesn't fit on this line */
+ /* if it's white space or an icon, just generate a line break */
+ if(state->word[0]==' ' || state->kind==EIcon){
+ if(linewid == 0) /* it's just too wide; emit it and it'll get clipped */
+ goto Easy;
+ state->pending = 0;
+ break;
+ }
+ /* if word would fit were we to break the line now, do so */
+ if(wordwid <= state->wid)
+ break;
+ /* worst case: bite off the biggest piece that fits */
+ w = state->pending;
+ while(*w){
+ nb = chartorune(&r, w);
+ memmove(tmp, w, nb);
+ tmp[nb] = 0;
+ rwid = stringwidth(f, tmp);
+ if(linewid+rwid > state->wid)
+ break;
+ linewid += rwid;
+ w += nb;
+ }
+ if(w == state->pending){
+ /* first char too wide for remaining space */
+ if(linewid > 0)
+ break;
+ /* remaining space is all we'll get */
+ kwerrstr("can't handle wide word in textelement\n");
+ goto Error;
+ }
+ nb = w-state->pending;
+ t = malloc(nb+1);
+ if(t == nil)
+ goto Error;
+ memmove(t, state->pending, nb);
+ t[nb] = 0;
+ pl = growtext(pl, state, t, x, state->p.x+linewid);
+ free(t);
+ if(pl == H){
+ *ok = 0;
+ return H;
+ }
+ state->pending = w;
+ break;
+ }
+ pl->e.r.min.y = state->p.y;
+ pl->e.r.max.y = state->p.y+state->ascent+state->descent;
+ P2P(pl->drawpt, pl->e.r.min);
+ if(pl->pkind==EHorizontal){
+ for(l=pl->first; l!=H; l=l->tail){
+ pe = *(PElement**)l->data;
+ pe->e.r.min.y = state->p.y;
+ pe->e.r.max.y = state->p.y+state->ascent+state->descent;
+ pe->drawpt.x = pe->e.r.min.x;
+ if(pe->e.kind == EIcon){
+ /* add a pixel on the left; room was left in growtext */
+ pe->drawpt.x += 1;
+ pe->drawpt.y = pe->e.r.min.y+(state->ascent-Dy(pe->e.image->r));
+ }else
+ pe->drawpt.y = pe->e.r.min.y+(state->ascent-pe->e.font->ascent);
+ }
+ }
+ return pl;
+}
+
+PElement*
+layoutelement(Prefab_Environ *env, List *laylist, Draw_Rect rr, enum Elementtype kind)
+{
+ PElement *pline, *plist, *firstpline;
+ List *lines, *atom, *tail;
+ State state;
+ int nlines, linewid, maxwid, wid, trim, maxy, ok;
+ Point p;
+ Rectangle r;
+ Screen *screen;
+
+ nlines = 0;
+ trim = 0;
+ wid = Dx(rr);
+ if(wid < 25){
+ if(wid <= 0)
+ trim = 1;
+ screen = lookupscreen(env->screen);
+ if(screen == nil)
+ return H;
+ wid = Dx(screen->display->image->r)-32;
+ if(wid < 100)
+ wid = 100;
+ }
+ wid -= 3+3; /* three pixels left and right */
+
+ gchalt++;
+ state.env = env;
+ state.list = laylist;
+ state.s = 0;
+ state.pending = 0;
+ state.font = H;
+ state.color = H;
+ state.tag = H;
+ p = IPOINT(rr.min);
+ p.x += 3;
+ state.p = p;
+ state.kind = EText; /* anything but EIcon */
+ state.mainkind = kind;
+ state.wid = wid;
+ lines = H;
+ tail = H;
+ firstpline = H;
+ maxwid = 0;
+ maxy = 0;
+ while(ismore(&state)){
+ pline = buildline(&state, &ok);
+ if(ok == 0){
+ plist = H;
+ goto Return;
+ }
+ if(pline == H)
+ break;
+ linewid = Dx(pline->e.r);
+ if(linewid > maxwid)
+ maxwid = linewid;
+ if(firstpline == H)
+ firstpline = pline;
+ else{
+ atom = prefabwrap(pline);
+ destroy(pline); /* relevant data now in wrapper */
+ pline = *(PElement**)atom->data;
+ if(lines == H){
+ lines = prefabwrap(firstpline);
+ destroy(firstpline);
+ firstpline = 0; /* never used again; this proves it! */
+ tail = lines;
+ }
+ tail->tail = atom;
+ tail = atom;
+ }
+ nlines++;
+ state.p.y = pline->e.r.max.y;
+ if(maxy==0 || state.p.y<=rr.max.y)
+ maxy = state.p.y;
+ }
+ if(trim == 0)
+ maxwid = wid;
+ if(nlines == 0){
+ plist = H;
+ goto Return;
+ }
+ if(nlines == 1){
+ if(trim == 0){ /* restore clipping around element */
+ firstpline->e.r.min.x = rr.min.x;
+ firstpline->e.r.max.x = rr.min.x+3+maxwid+3;
+ }
+ plist = firstpline;
+ goto Return;
+ }
+ plist = mkelement(env, EVertical);
+ plist->e.r.min.x = rr.min.x;
+ plist->e.r.min.y = p.y;
+ plist->e.r.max.x = rr.min.x+3+maxwid+3;
+ plist->e.r.max.y = (*(Prefab_Element**)tail->data)->r.max.y;
+ plist->drawpt = p;
+ plist->e.kids = lines;
+ plist->first = lines;
+ plist->last = tail;
+ plist->vfirst = lines;
+ plist->vlast = tail;
+ plist->nkids = nlines;
+ /* if asked for a fixed size and list is too long, clip */
+ if(Dy(rr)>0 && rr.max.y<plist->e.r.max.y){
+ R2R(r, plist->e.r);
+ r.max.y = maxy;
+ clipelement(&plist->e, r);
+ }
+
+Return:
+ gchalt--;
+ return plist;
+}
+
+/*
+ * Create List with one Layout in it, using malloc instead of heap to
+ * keep it out of the eyes of the garbage collector
+ */
+List*
+listoflayout(Prefab_Style *style, String *text, int kind)
+{
+ List *listp;
+ Prefab_Layout *layp;
+
+ listp = malloc(sizeof(List) + TLayout->size);
+ if(listp == nil)
+ return H;
+ listp->tail = H;
+ layp = (Prefab_Layout*)listp->data;
+ if(kind == EText){
+ layp->font = style->textfont;
+ layp->color = style->textcolor;
+ }else{
+ layp->font = style->titlefont;
+ layp->color = style->titlecolor;
+ }
+ layp->text = text;
+ layp->icon = H;
+ layp->mask = H;
+ layp->tag = H;
+ return listp;
+}
+
+PElement*
+textelement(Prefab_Environ *env, String *str, Draw_Rect rr, enum Elementtype kind)
+{
+ PElement *pe;
+ List *l;
+
+ l = listoflayout(env->style, str, kind);
+ pe = layoutelement(env, l, rr, kind);
+ free(l);
+ return pe;
+}
--- /dev/null
+++ b/libsec/Inferno-386/md5block.s
@@ -1,0 +1,220 @@
+/*
+ * rfc1321 requires that I include this. The code is new. The constants
+ * all come from the rfc (hence the copyright). We trade a table for the
+ * macros in rfc. The total size is a lot less. -- presotto
+ *
+ * Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All
+ * rights reserved.
+ *
+ * License to copy and use this software is granted provided that it
+ * is identified as the "RSA Data Security, Inc. MD5 Message-Digest
+ * Algorithm" in all material mentioning or referencing this software
+ * or this function.
+ *
+ * License is also granted to make and use derivative works provided
+ * that such works are identified as "derived from the RSA Data
+ * Security, Inc. MD5 Message-Digest Algorithm" in all material
+ * mentioning or referencing the derived work.
+ *
+ * RSA Data Security, Inc. makes no representations concerning either
+ * the merchantability of this software or the suitability of this
+ * software forany particular purpose. It is provided "as is"
+ * without express or implied warranty of any kind.
+ * These notices must be retained in any copies of any part of this
+ * documentation and/or software.
+ */
+#define S11 7
+#define S12 12
+#define S13 17
+#define S14 22
+
+#define S21 5
+#define S22 9
+#define S23 14
+#define S24 20
+
+#define S31 4
+#define S32 11
+#define S33 16
+#define S34 23
+
+#define S41 6
+#define S42 10
+#define S43 15
+#define S44 21
+
+/*
+ * SI is data
+ * a += FN(B,C,D);
+ * a += x[sh] + t[sh];
+ * a = (a << S11) | (a >> (32 - S11));
+ * a += b;
+ */
+
+#define BODY1(off,V,FN,SH,A,B,C,D)\
+ FN(B,C,D)\
+ LEAL V(A)(DI*1),A;\
+ ADDL (off)(BP),A;\
+ ROLL $SH,A;\
+ ADDL B,A;\
+
+#define BODY(off,V,FN,SH,A,B,C,D)\
+ FN(B,C,D)\
+ LEAL V(A)(DI*1),A;\
+ ADDL (off)(BP),A;\
+ ROLL $SH,A;\
+ ADDL B,A;\
+
+/*
+ * fn1 = ((c ^ d) & b) ^ d
+ */
+#define FN1(B,C,D)\
+ MOVL C,DI;\
+ XORL D,DI;\
+ ANDL B,DI;\
+ XORL D,DI;\
+
+/*
+ * fn2 = ((b ^ c) & d) ^ c;
+ */
+#define FN2(B,C,D)\
+ MOVL B,DI;\
+ XORL C,DI;\
+ ANDL D,DI;\
+ XORL C,DI;\
+
+/*
+ * fn3 = b ^ c ^ d;
+ */
+#define FN3(B,C,D)\
+ MOVL B,DI;\
+ XORL C,DI;\
+ XORL D,DI;\
+
+/*
+ * fn4 = c ^ (b | ~d);
+ */
+#define FN4(B,C,D)\
+ MOVL D,DI;\
+ XORL $-1,DI;\
+ ORL B,DI;\
+ XORL C,DI;\
+
+#define DATA 0
+#define LEN 4
+#define STATE 8
+
+#define EDATA (-4)
+
+ TEXT _md5block+0(SB),$4
+
+ MOVL data+DATA(FP),AX
+ ADDL len+LEN(FP),AX
+ MOVL AX,edata+EDATA(SP)
+
+ MOVL data+DATA(FP),BP
+
+mainloop:
+ MOVL state+STATE(FP),SI
+ MOVL (SI),AX
+ MOVL 4(SI),BX
+ MOVL 8(SI),CX
+ MOVL 12(SI),DX
+
+ BODY1( 0*4,0xd76aa478,FN1,S11,AX,BX,CX,DX)
+ BODY1( 1*4,0xe8c7b756,FN1,S12,DX,AX,BX,CX)
+ BODY1( 2*4,0x242070db,FN1,S13,CX,DX,AX,BX)
+ BODY1( 3*4,0xc1bdceee,FN1,S14,BX,CX,DX,AX)
+
+ BODY1( 4*4,0xf57c0faf,FN1,S11,AX,BX,CX,DX)
+ BODY1( 5*4,0x4787c62a,FN1,S12,DX,AX,BX,CX)
+ BODY1( 6*4,0xa8304613,FN1,S13,CX,DX,AX,BX)
+ BODY1( 7*4,0xfd469501,FN1,S14,BX,CX,DX,AX)
+
+ BODY1( 8*4,0x698098d8,FN1,S11,AX,BX,CX,DX)
+ BODY1( 9*4,0x8b44f7af,FN1,S12,DX,AX,BX,CX)
+ BODY1(10*4,0xffff5bb1,FN1,S13,CX,DX,AX,BX)
+ BODY1(11*4,0x895cd7be,FN1,S14,BX,CX,DX,AX)
+
+ BODY1(12*4,0x6b901122,FN1,S11,AX,BX,CX,DX)
+ BODY1(13*4,0xfd987193,FN1,S12,DX,AX,BX,CX)
+ BODY1(14*4,0xa679438e,FN1,S13,CX,DX,AX,BX)
+ BODY1(15*4,0x49b40821,FN1,S14,BX,CX,DX,AX)
+
+
+ BODY( 1*4,0xf61e2562,FN2,S21,AX,BX,CX,DX)
+ BODY( 6*4,0xc040b340,FN2,S22,DX,AX,BX,CX)
+ BODY(11*4,0x265e5a51,FN2,S23,CX,DX,AX,BX)
+ BODY( 0*4,0xe9b6c7aa,FN2,S24,BX,CX,DX,AX)
+
+ BODY( 5*4,0xd62f105d,FN2,S21,AX,BX,CX,DX)
+ BODY(10*4,0x02441453,FN2,S22,DX,AX,BX,CX)
+ BODY(15*4,0xd8a1e681,FN2,S23,CX,DX,AX,BX)
+ BODY( 4*4,0xe7d3fbc8,FN2,S24,BX,CX,DX,AX)
+
+ BODY( 9*4,0x21e1cde6,FN2,S21,AX,BX,CX,DX)
+ BODY(14*4,0xc33707d6,FN2,S22,DX,AX,BX,CX)
+ BODY( 3*4,0xf4d50d87,FN2,S23,CX,DX,AX,BX)
+ BODY( 8*4,0x455a14ed,FN2,S24,BX,CX,DX,AX)
+
+ BODY(13*4,0xa9e3e905,FN2,S21,AX,BX,CX,DX)
+ BODY( 2*4,0xfcefa3f8,FN2,S22,DX,AX,BX,CX)
+ BODY( 7*4,0x676f02d9,FN2,S23,CX,DX,AX,BX)
+ BODY(12*4,0x8d2a4c8a,FN2,S24,BX,CX,DX,AX)
+
+
+ BODY( 5*4,0xfffa3942,FN3,S31,AX,BX,CX,DX)
+ BODY( 8*4,0x8771f681,FN3,S32,DX,AX,BX,CX)
+ BODY(11*4,0x6d9d6122,FN3,S33,CX,DX,AX,BX)
+ BODY(14*4,0xfde5380c,FN3,S34,BX,CX,DX,AX)
+
+ BODY( 1*4,0xa4beea44,FN3,S31,AX,BX,CX,DX)
+ BODY( 4*4,0x4bdecfa9,FN3,S32,DX,AX,BX,CX)
+ BODY( 7*4,0xf6bb4b60,FN3,S33,CX,DX,AX,BX)
+ BODY(10*4,0xbebfbc70,FN3,S34,BX,CX,DX,AX)
+
+ BODY(13*4,0x289b7ec6,FN3,S31,AX,BX,CX,DX)
+ BODY( 0*4,0xeaa127fa,FN3,S32,DX,AX,BX,CX)
+ BODY( 3*4,0xd4ef3085,FN3,S33,CX,DX,AX,BX)
+ BODY( 6*4,0x04881d05,FN3,S34,BX,CX,DX,AX)
+
+ BODY( 9*4,0xd9d4d039,FN3,S31,AX,BX,CX,DX)
+ BODY(12*4,0xe6db99e5,FN3,S32,DX,AX,BX,CX)
+ BODY(15*4,0x1fa27cf8,FN3,S33,CX,DX,AX,BX)
+ BODY( 2*4,0xc4ac5665,FN3,S34,BX,CX,DX,AX)
+
+
+ BODY( 0*4,0xf4292244,FN4,S41,AX,BX,CX,DX)
+ BODY( 7*4,0x432aff97,FN4,S42,DX,AX,BX,CX)
+ BODY(14*4,0xab9423a7,FN4,S43,CX,DX,AX,BX)
+ BODY( 5*4,0xfc93a039,FN4,S44,BX,CX,DX,AX)
+
+ BODY(12*4,0x655b59c3,FN4,S41,AX,BX,CX,DX)
+ BODY( 3*4,0x8f0ccc92,FN4,S42,DX,AX,BX,CX)
+ BODY(10*4,0xffeff47d,FN4,S43,CX,DX,AX,BX)
+ BODY( 1*4,0x85845dd1,FN4,S44,BX,CX,DX,AX)
+
+ BODY( 8*4,0x6fa87e4f,FN4,S41,AX,BX,CX,DX)
+ BODY(15*4,0xfe2ce6e0,FN4,S42,DX,AX,BX,CX)
+ BODY( 6*4,0xa3014314,FN4,S43,CX,DX,AX,BX)
+ BODY(13*4,0x4e0811a1,FN4,S44,BX,CX,DX,AX)
+
+ BODY( 4*4,0xf7537e82,FN4,S41,AX,BX,CX,DX)
+ BODY(11*4,0xbd3af235,FN4,S42,DX,AX,BX,CX)
+ BODY( 2*4,0x2ad7d2bb,FN4,S43,CX,DX,AX,BX)
+ BODY( 9*4,0xeb86d391,FN4,S44,BX,CX,DX,AX)
+
+ ADDL $(16*4),BP
+ MOVL state+STATE(FP),DI
+ ADDL AX,0(DI)
+ ADDL BX,4(DI)
+ ADDL CX,8(DI)
+ ADDL DX,12(DI)
+
+ MOVL edata+EDATA(SP),DI
+ CMPL BP,DI
+ JCS mainloop
+
+ RET
+
+ END
--- /dev/null
+++ b/libsec/Inferno-386/mkfile
@@ -1,0 +1,17 @@
+objtype=386
+OBJTYPE=$objtype
+<../../mkconfig
+OBJDIR=Inferno/$OBJTYPE
+
+LIB=libsec.a
+FILES=\
+ md5block\
+ sha1block\
+
+HFILES=$ROOT/include/libsec.h
+
+SFILES=${FILES:%=%.s}
+
+OFILES=${FILES:%=%.$O}
+
+<$ROOT/mkfiles/mksyslib-$SHELLTYPE
--- /dev/null
+++ b/libsec/Inferno-386/sha1block.s
@@ -1,0 +1,195 @@
+ TEXT _sha1block+0(SB),$352
+
+/* x = (wp[off-f] ^ wp[off-8] ^ wp[off-14] ^ wp[off-16]) <<< 1;
+ * wp[off] = x;
+ * x += A <<< 5;
+ * E += 0xca62c1d6 + x;
+ * x = FN(B,C,D);
+ * E += x;
+ * B >>> 2
+ */
+#define BSWAPDI BYTE $0x0f; BYTE $0xcf;
+
+#define BODY(off,FN,V,A,B,C,D,E)\
+ MOVL (off-64)(BP),DI;\
+ XORL (off-56)(BP),DI;\
+ XORL (off-32)(BP),DI;\
+ XORL (off-12)(BP),DI;\
+ ROLL $1,DI;\
+ MOVL DI,off(BP);\
+ LEAL V(DI)(E*1),E;\
+ MOVL A,DI;\
+ ROLL $5,DI;\
+ ADDL DI,E;\
+ FN(B,C,D)\
+ ADDL DI,E;\
+ RORL $2,B;\
+
+#define BODY0(off,FN,V,A,B,C,D,E)\
+ MOVL off(BX),DI;\
+ BSWAPDI;\
+ MOVL DI,off(BP);\
+ LEAL V(DI)(E*1),E;\
+ MOVL A,DI;\
+ ROLL $5,DI;\
+ ADDL DI,E;\
+ FN(B,C,D)\
+ ADDL DI,E;\
+ RORL $2,B;\
+
+/*
+ * fn1 = (((C^D)&B)^D);
+ */
+#define FN1(B,C,D)\
+ MOVL C,DI;\
+ XORL D,DI;\
+ ANDL B,DI;\
+ XORL D,DI;\
+
+/*
+ * fn24 = B ^ C ^ D
+ */
+#define FN24(B,C,D)\
+ MOVL B,DI;\
+ XORL C,DI;\
+ XORL D,DI;\
+
+/*
+ * fn3 = ((B ^ C) & (D ^= B)) ^ B
+ * D ^= B to restore D
+ */
+#define FN3(B,C,D)\
+ MOVL B,DI;\
+ XORL C,DI;\
+ XORL B,D;\
+ ANDL D,DI;\
+ XORL B,DI;\
+ XORL B,D;\
+
+/*
+ * stack offsets
+ * void sha1block(uchar *DATA, int LEN, ulong *STATE)
+ */
+#define DATA 0
+#define LEN 4
+#define STATE 8
+
+/*
+ * stack offsets for locals
+ * ulong w[80];
+ * uchar *edata;
+ * ulong *w15, *w40, *w60, *w80;
+ * register local
+ * ulong *wp = BP
+ * ulong a = eax, b = ebx, c = ecx, d = edx, e = esi
+ * ulong tmp = edi
+ */
+#define WARRAY (-4-(80*4))
+#define TMP1 (-8-(80*4))
+#define TMP2 (-12-(80*4))
+#define W15 (-16-(80*4))
+#define W40 (-20-(80*4))
+#define W60 (-24-(80*4))
+#define W80 (-28-(80*4))
+#define EDATA (-32-(80*4))
+
+ MOVL data+DATA(FP),AX
+ ADDL len+LEN(FP),AX
+ MOVL AX,edata+EDATA(SP)
+
+ LEAL aw15+(WARRAY+15*4)(SP),DI
+ MOVL DI,w15+W15(SP)
+ LEAL aw40+(WARRAY+40*4)(SP),DX
+ MOVL DX,w40+W40(SP)
+ LEAL aw60+(WARRAY+60*4)(SP),CX
+ MOVL CX,w60+W60(SP)
+ LEAL aw80+(WARRAY+80*4)(SP),DI
+ MOVL DI,w80+W80(SP)
+
+mainloop:
+ LEAL warray+WARRAY(SP),BP
+
+ MOVL state+STATE(FP),DI
+ MOVL (DI),AX
+ MOVL 4(DI),BX
+ MOVL BX,tmp1+TMP1(SP)
+ MOVL 8(DI),CX
+ MOVL 12(DI),DX
+ MOVL 16(DI),SI
+
+ MOVL data+DATA(FP),BX
+
+loop1:
+ BODY0(0,FN1,0x5a827999,AX,tmp1+TMP1(SP),CX,DX,SI)
+ MOVL SI,tmp2+TMP2(SP)
+ BODY0(4,FN1,0x5a827999,SI,AX,tmp1+TMP1(SP),CX,DX)
+ MOVL tmp1+TMP1(SP),SI
+ BODY0(8,FN1,0x5a827999,DX,tmp2+TMP2(SP),AX,SI,CX)
+ BODY0(12,FN1,0x5a827999,CX,DX,tmp2+TMP2(SP),AX,SI)
+ MOVL SI,tmp1+TMP1(SP)
+ BODY0(16,FN1,0x5a827999,SI,CX,DX,tmp2+TMP2(SP),AX)
+ MOVL tmp2+TMP2(SP),SI
+
+ ADDL $20,BX
+ ADDL $20,BP
+ CMPL BP,w15+W15(SP)
+ JCS loop1
+
+ BODY0(0,FN1,0x5a827999,AX,tmp1+TMP1(SP),CX,DX,SI)
+ ADDL $4,BX
+ MOVL BX,data+DATA(FP)
+ MOVL tmp1+TMP1(SP),BX
+
+ BODY(4,FN1,0x5a827999,SI,AX,BX,CX,DX)
+ BODY(8,FN1,0x5a827999,DX,SI,AX,BX,CX)
+ BODY(12,FN1,0x5a827999,CX,DX,SI,AX,BX)
+ BODY(16,FN1,0x5a827999,BX,CX,DX,SI,AX)
+
+ ADDL $20,BP
+
+loop2:
+ BODY(0,FN24,0x6ed9eba1,AX,BX,CX,DX,SI)
+ BODY(4,FN24,0x6ed9eba1,SI,AX,BX,CX,DX)
+ BODY(8,FN24,0x6ed9eba1,DX,SI,AX,BX,CX)
+ BODY(12,FN24,0x6ed9eba1,CX,DX,SI,AX,BX)
+ BODY(16,FN24,0x6ed9eba1,BX,CX,DX,SI,AX)
+
+ ADDL $20,BP
+ CMPL BP,w40+W40(SP)
+ JCS loop2
+
+loop3:
+ BODY(0,FN3,0x8f1bbcdc,AX,BX,CX,DX,SI)
+ BODY(4,FN3,0x8f1bbcdc,SI,AX,BX,CX,DX)
+ BODY(8,FN3,0x8f1bbcdc,DX,SI,AX,BX,CX)
+ BODY(12,FN3,0x8f1bbcdc,CX,DX,SI,AX,BX)
+ BODY(16,FN3,0x8f1bbcdc,BX,CX,DX,SI,AX)
+
+ ADDL $20,BP
+ CMPL BP,w60+W60(SP)
+ JCS loop3
+
+loop4:
+ BODY(0,FN24,0xca62c1d6,AX,BX,CX,DX,SI)
+ BODY(4,FN24,0xca62c1d6,SI,AX,BX,CX,DX)
+ BODY(8,FN24,0xca62c1d6,DX,SI,AX,BX,CX)
+ BODY(12,FN24,0xca62c1d6,CX,DX,SI,AX,BX)
+ BODY(16,FN24,0xca62c1d6,BX,CX,DX,SI,AX)
+
+ ADDL $20,BP
+ CMPL BP,w80+W80(SP)
+ JCS loop4
+
+ MOVL state+STATE(FP),DI
+ ADDL AX,0(DI)
+ ADDL BX,4(DI)
+ ADDL CX,8(DI)
+ ADDL DX,12(DI)
+ ADDL SI,16(DI)
+
+ MOVL edata+EDATA(SP),DI
+ CMPL data+DATA(FP),DI
+ JCS mainloop
+
+ RET
+ END
--- /dev/null
+++ b/libsec/Inferno-mips/md5block.s
@@ -1,0 +1,305 @@
+/*
+ * rfc1321 requires that I include this. The code is new. The constants
+ * all come from the rfc (hence the copyright). We trade a table for the
+ * macros in rfc. The total size is a lot less. -- presotto
+ *
+ * Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All
+ * rights reserved.
+ *
+ * License to copy and use this software is granted provided that it
+ * is identified as the "RSA Data Security, Inc. MD5 Message-Digest
+ * Algorithm" in all material mentioning or referencing this software
+ * or this function.
+ *
+ * License is also granted to make and use derivative works provided
+ * that such works are identified as "derived from the RSA Data
+ * Security, Inc. MD5 Message-Digest Algorithm" in all material
+ * mentioning or referencing the derived work.
+ *
+ * RSA Data Security, Inc. makes no representations concerning either
+ * the merchantability of this software or the suitability of this
+ * software forany particular purpose. It is provided "as is"
+ * without express or implied warranty of any kind.
+ * These notices must be retained in any copies of any part of this
+ * documentation and/or software.
+ */
+
+ /* round 1 */
+ DATA md5tab<>+( 0*4)(SB)/4,$0xd76aa478
+ DATA md5tab<>+( 1*4)(SB)/4,$0xe8c7b756
+ DATA md5tab<>+( 2*4)(SB)/4,$0x242070db
+ DATA md5tab<>+( 3*4)(SB)/4,$0xc1bdceee
+ DATA md5tab<>+( 4*4)(SB)/4,$0xf57c0faf
+ DATA md5tab<>+( 5*4)(SB)/4,$0x4787c62a
+ DATA md5tab<>+( 6*4)(SB)/4,$0xa8304613
+ DATA md5tab<>+( 7*4)(SB)/4,$0xfd469501
+ DATA md5tab<>+( 8*4)(SB)/4,$0x698098d8
+ DATA md5tab<>+( 9*4)(SB)/4,$0x8b44f7af
+ DATA md5tab<>+(10*4)(SB)/4,$0xffff5bb1
+ DATA md5tab<>+(11*4)(SB)/4,$0x895cd7be
+ DATA md5tab<>+(12*4)(SB)/4,$0x6b901122
+ DATA md5tab<>+(13*4)(SB)/4,$0xfd987193
+ DATA md5tab<>+(14*4)(SB)/4,$0xa679438e
+ DATA md5tab<>+(15*4)(SB)/4,$0x49b40821
+
+ /* round 2 */
+ DATA md5tab<>+(16*4)(SB)/4,$0xf61e2562
+ DATA md5tab<>+(17*4)(SB)/4,$0xc040b340
+ DATA md5tab<>+(18*4)(SB)/4,$0x265e5a51
+ DATA md5tab<>+(19*4)(SB)/4,$0xe9b6c7aa
+ DATA md5tab<>+(20*4)(SB)/4,$0xd62f105d
+ DATA md5tab<>+(21*4)(SB)/4,$0x02441453
+ DATA md5tab<>+(22*4)(SB)/4,$0xd8a1e681
+ DATA md5tab<>+(23*4)(SB)/4,$0xe7d3fbc8
+ DATA md5tab<>+(24*4)(SB)/4,$0x21e1cde6
+ DATA md5tab<>+(25*4)(SB)/4,$0xc33707d6
+ DATA md5tab<>+(26*4)(SB)/4,$0xf4d50d87
+ DATA md5tab<>+(27*4)(SB)/4,$0x455a14ed
+ DATA md5tab<>+(28*4)(SB)/4,$0xa9e3e905
+ DATA md5tab<>+(29*4)(SB)/4,$0xfcefa3f8
+ DATA md5tab<>+(30*4)(SB)/4,$0x676f02d9
+ DATA md5tab<>+(31*4)(SB)/4,$0x8d2a4c8a
+
+ /* round 3 */
+ DATA md5tab<>+(32*4)(SB)/4,$0xfffa3942
+ DATA md5tab<>+(33*4)(SB)/4,$0x8771f681
+ DATA md5tab<>+(34*4)(SB)/4,$0x6d9d6122
+ DATA md5tab<>+(35*4)(SB)/4,$0xfde5380c
+ DATA md5tab<>+(36*4)(SB)/4,$0xa4beea44
+ DATA md5tab<>+(37*4)(SB)/4,$0x4bdecfa9
+ DATA md5tab<>+(38*4)(SB)/4,$0xf6bb4b60
+ DATA md5tab<>+(39*4)(SB)/4,$0xbebfbc70
+ DATA md5tab<>+(40*4)(SB)/4,$0x289b7ec6
+ DATA md5tab<>+(41*4)(SB)/4,$0xeaa127fa
+ DATA md5tab<>+(42*4)(SB)/4,$0xd4ef3085
+ DATA md5tab<>+(43*4)(SB)/4,$0x04881d05
+ DATA md5tab<>+(44*4)(SB)/4,$0xd9d4d039
+ DATA md5tab<>+(45*4)(SB)/4,$0xe6db99e5
+ DATA md5tab<>+(46*4)(SB)/4,$0x1fa27cf8
+ DATA md5tab<>+(47*4)(SB)/4,$0xc4ac5665
+
+ /* round 4 */
+ DATA md5tab<>+(48*4)(SB)/4,$0xf4292244
+ DATA md5tab<>+(49*4)(SB)/4,$0x432aff97
+ DATA md5tab<>+(50*4)(SB)/4,$0xab9423a7
+ DATA md5tab<>+(51*4)(SB)/4,$0xfc93a039
+ DATA md5tab<>+(52*4)(SB)/4,$0x655b59c3
+ DATA md5tab<>+(53*4)(SB)/4,$0x8f0ccc92
+ DATA md5tab<>+(54*4)(SB)/4,$0xffeff47d
+ DATA md5tab<>+(55*4)(SB)/4,$0x85845dd1
+ DATA md5tab<>+(56*4)(SB)/4,$0x6fa87e4f
+ DATA md5tab<>+(57*4)(SB)/4,$0xfe2ce6e0
+ DATA md5tab<>+(58*4)(SB)/4,$0xa3014314
+ DATA md5tab<>+(59*4)(SB)/4,$0x4e0811a1
+ DATA md5tab<>+(60*4)(SB)/4,$0xf7537e82
+ DATA md5tab<>+(61*4)(SB)/4,$0xbd3af235
+ DATA md5tab<>+(62*4)(SB)/4,$0x2ad7d2bb
+ DATA md5tab<>+(63*4)(SB)/4,$0xeb86d391
+
+#define S11 7
+#define S12 12
+#define S13 17
+#define S14 22
+
+#define S21 5
+#define S22 9
+#define S23 14
+#define S24 20
+
+#define S31 4
+#define S32 11
+#define S33 16
+#define S34 23
+
+#define S41 6
+#define S42 10
+#define S43 15
+#define S44 21
+
+#define AREG R5
+#define BREG R6
+#define CREG R7
+#define DREG R8
+#define DATAREG R1
+#define TABREG R10
+#define STREG R11
+#define XREG R12
+#define ELOOPREG R13
+#define EDREG R14
+#define IREG R15
+
+#define TMP1 R9
+#define TMP2 R2
+#define TMP3 R3
+#define TMP4 R4
+
+/*
+ * decode little endian data into x[off], then the body
+ * bodies have this form:
+ * a += FN(B,C,D);
+ * a += x[off] + t[off];
+ * a = (a << S11) | (a >> (32 - S11));
+ * a += b;
+ */
+#define BODY1(off,FN,SH,A,B,C,D)\
+ MOVBU off(DATAREG),TMP2;\
+ MOVBU (off+1)(DATAREG),TMP3;\
+ MOVBU (off+2)(DATAREG),TMP1;\
+ MOVBU (off+3)(DATAREG),TMP4;\
+ SLL $8,TMP3;\
+ OR TMP3,TMP2;\
+ SLL $16,TMP1;\
+ OR TMP1,TMP2;\
+ SLL $24,TMP4;\
+ OR TMP4,TMP2;\
+ MOVW off(TABREG),TMP3;\
+ FN(B,C,D)\
+ ADDU TMP1,A;\
+ MOVW TMP2,off(XREG);\
+ ADDU TMP2,A;\
+ ADDU TMP3,A;\
+ SLL $SH,A,TMP1;\
+ SRL $(32-SH),A;\
+ OR TMP1,A;\
+ ADDU B,A;\
+
+#define BODY(off,inc,FN,SH,A,B,C,D)\
+ MOVW off(TABREG),TMP3;\
+ ADDU XREG,IREG,TMP4;\
+ MOVW (TMP4),TMP2;\
+ ADDU $(inc*4),IREG;\
+ AND $63,IREG;\
+ FN(B,C,D)\
+ ADDU TMP1,A;\
+ ADDU TMP2,A;\
+ ADDU TMP3,A;\
+ SLL $SH,A,TMP1;\
+ SRL $(32-SH),A;\
+ OR TMP1,A;\
+ ADDU B,A;\
+
+/*
+ * fn1 = ((c ^ d) & b) ^ d
+ */
+#define FN1(B,C,D)\
+ XOR C,D,TMP1;\
+ AND B,TMP1;\
+ XOR D,TMP1;\
+
+/*
+ * fn2 = ((b ^ c) & d) ^ c;
+ */
+#define FN2(B,C,D)\
+ XOR B,C,TMP1;\
+ AND D,TMP1;\
+ XOR C,TMP1;\
+
+/*
+ * fn3 = b ^ c ^ d;
+ */
+#define FN3(B,C,D)\
+ XOR B,C,TMP1;\
+ XOR D,TMP1;\
+
+/*
+ * fn4 = c ^ (b | ~d);
+ */
+#define FN4(B,C,D)\
+ XOR $-1,D,TMP1;\
+ OR B,TMP1;\
+ XOR C,TMP1;\
+
+#define DATA 0
+#define LEN 4
+#define STATE 8
+
+#define XOFF (-4-16*4)
+
+ TEXT _md5block+0(SB),$68
+
+ MOVW len+LEN(FP),TMP1
+ ADDU DATAREG,TMP1,EDREG
+ MOVW state+STATE(FP),STREG
+
+ MOVW 0(STREG),AREG
+ MOVW 4(STREG),BREG
+ MOVW 8(STREG),CREG
+ MOVW 12(STREG),DREG
+
+mainloop:
+
+ MOVW $md5tab<>+0(SB),TABREG
+ ADDU $(16*4),DATAREG,ELOOPREG
+ MOVW $x+XOFF(SP),XREG
+
+loop1:
+ BODY1(0,FN1,S11,AREG,BREG,CREG,DREG)
+ BODY1(4,FN1,S12,DREG,AREG,BREG,CREG)
+ BODY1(8,FN1,S13,CREG,DREG,AREG,BREG)
+ BODY1(12,FN1,S14,BREG,CREG,DREG,AREG)
+
+ ADDU $16,DATAREG
+ ADDU $16,TABREG
+ ADDU $16,XREG
+
+ BNE DATAREG,ELOOPREG,loop1
+
+
+ MOVW $x+XOFF(SP),XREG
+ MOVW $(1*4),IREG
+ MOVW $(1*4),ELOOPREG
+loop2:
+ BODY(0,5,FN2,S21,AREG,BREG,CREG,DREG)
+ BODY(4,5,FN2,S22,DREG,AREG,BREG,CREG)
+ BODY(8,5,FN2,S23,CREG,DREG,AREG,BREG)
+ BODY(12,5,FN2,S24,BREG,CREG,DREG,AREG)
+
+ ADDU $16,TABREG
+
+ BNE IREG,ELOOPREG,loop2
+
+
+ MOVW $(5*4),IREG
+ MOVW $(5*4),ELOOPREG
+loop3:
+ BODY(0,3,FN3,S31,AREG,BREG,CREG,DREG)
+ BODY(4,3,FN3,S32,DREG,AREG,BREG,CREG)
+ BODY(8,3,FN3,S33,CREG,DREG,AREG,BREG)
+ BODY(12,3,FN3,S34,BREG,CREG,DREG,AREG)
+
+ ADDU $16,TABREG
+
+ BNE IREG,ELOOPREG,loop3
+
+
+ MOVW $0,IREG
+loop4:
+ BODY(0,7,FN4,S41,AREG,BREG,CREG,DREG)
+ BODY(4,7,FN4,S42,DREG,AREG,BREG,CREG)
+ BODY(8,7,FN4,S43,CREG,DREG,AREG,BREG)
+ BODY(12,7,FN4,S44,BREG,CREG,DREG,AREG)
+
+ ADDU $16,TABREG
+
+ BNE IREG,R0,loop4
+
+ MOVW 0(STREG),TMP1
+ MOVW 4(STREG),TMP2
+ MOVW 8(STREG),TMP3
+ MOVW 12(STREG),TMP4
+ ADDU TMP1,AREG
+ ADDU TMP2,BREG
+ ADDU TMP3,CREG
+ ADDU TMP4,DREG
+ MOVW AREG,0(STREG)
+ MOVW BREG,4(STREG)
+ MOVW CREG,8(STREG)
+ MOVW DREG,12(STREG)
+
+ BNE DATAREG,EDREG,mainloop
+
+ RET
+
+ GLOBL md5tab<>+0(SB),$256
+
+ END
--- /dev/null
+++ b/libsec/Inferno-mips/mkfile
@@ -1,0 +1,16 @@
+objtype=mips
+OBJTYPE=$objtype
+<../../mkconfig
+
+LIB=libsec.a
+FILES=\
+ md5block\
+ sha1block\
+
+HFILES=$ROOT/include/libsec.h
+
+SFILES=${FILES:%=%.s}
+
+OFILES=${FILES:%=%.$O}
+
+<$ROOT/mkfiles/mksyslib-$SHELLTYPE
--- /dev/null
+++ b/libsec/Inferno-mips/sha1block.s
@@ -1,0 +1,220 @@
+ TEXT _sha1block+0(SB),$328
+
+/*
+ * wp[off] = x;
+ * x += A <<< 5;
+ * E += 0xca62c1d6 + x;
+ * x = FN(B,C,D);
+ * E += x;
+ * B >>> 2
+ */
+#define BODYX(off,FN,V,A,B,C,D,E)\
+ FN(B,C,D)\
+ ADDU TMP1,E;\
+ ADDU V,E;\
+ MOVW TMP2,off(WREG);\
+ ADDU TMP2,E;\
+ SLL $5,A,TMP3;\
+ SRL $27,A,TMP4;\
+ OR TMP3,TMP4;\
+ ADDU TMP4,E;\
+ SLL $30,B,TMP4;\
+ SRL $2,B;\
+ OR TMP4,B
+
+/*
+ * x = data[i]
+ * BODYX
+ */
+#define BODY1(off,FN,V,A,B,C,D,E)\
+ MOVBU off(DATAREG),TMP2;\
+ MOVBU (off+1)(DATAREG),TMP3;\
+ MOVBU (off+2)(DATAREG),TMP1;\
+ MOVBU (off+3)(DATAREG),TMP4;\
+ SLL $24,TMP2;\
+ SLL $16,TMP3;\
+ OR TMP3,TMP2;\
+ SLL $8,TMP1;\
+ OR TMP1,TMP2;\
+ OR TMP4,TMP2;\
+ BODYX(off,FN,V,A,B,C,D,E)
+
+/*
+ * x = (wp[off-3] ^ wp[off-8] ^ wp[off-14] ^ wp[off-16]) <<< 1;
+ * BODYX
+ */
+#define BODY(off,FN,V,A,B,C,D,E)\
+ MOVW (off-64)(WREG),TMP1;\
+ MOVW (off-56)(WREG),TMP2;\
+ MOVW (off-32)(WREG),TMP3;\
+ MOVW (off-12)(WREG),TMP4;\
+ XOR TMP1,TMP2;\
+ XOR TMP3,TMP2;\
+ XOR TMP4,TMP2;\
+ SLL $1,TMP2,TMP1;\
+ SRL $31,TMP2;\
+ OR TMP1,TMP2;\
+ BODYX(off,FN,V,A,B,C,D,E)
+
+/*
+ * fn1 = (((C^D)&B)^D);
+ */
+#define FN1(B,C,D)\
+ XOR C,D,TMP1;\
+ AND B,TMP1;\
+ XOR D,TMP1;
+
+/*
+ * fn24 = B ^ C ^ D
+ */
+#define FN24(B,C,D)\
+ XOR B,C,TMP1;\
+ XOR D,TMP1;
+
+/*
+ * fn3 = ((B ^ C) & (D ^ B)) ^ B
+ */
+#define FN3(B,C,D)\
+ XOR B,C,TMP1;\
+ XOR B,D,TMP4;\
+ AND TMP4,TMP1;\
+ XOR B,TMP1;
+
+/*
+ * stack offsets
+ * void vtSha1Block(ulong *STATE, uchar *DATA, int LEN)
+ */
+#define DATA 0
+#define LEN 4
+#define STATE 8
+
+/*
+ * stack offsets for locals
+ * ulong w[80];
+ * uchar *edata;
+ * ulong *w15, *w40, *w60, *w80;
+ * register local
+ * ulong *wp = BP
+ * ulong a = eax, b = ebx, c = ecx, d = edx, e = esi
+ * ulong tmp = edi
+ */
+#define WARRAY (-4-(80*4))
+
+#define AREG R5
+#define BREG R6
+#define CREG R7
+#define DREG R8
+#define EREG R9
+#define DATAREG R1
+#define STREG R11
+#define WREG R12
+#define W15REG R13
+#define W60REG R14
+#define W40REG R15
+#define W80REG R16
+#define EDREG R17
+#define VREG R18
+
+#define TMP1 R10
+#define TMP2 R2
+#define TMP3 R3
+#define TMP4 R4
+#define TMP5 R19
+
+ MOVW len+LEN(FP),TMP1
+ MOVW state+STATE(FP),STREG
+ ADDU DATAREG,TMP1,EDREG
+
+ MOVW 0(STREG),AREG
+ MOVW 4(STREG),BREG
+ MOVW 8(STREG),CREG
+ MOVW 12(STREG),DREG
+ MOVW 16(STREG),EREG
+
+ MOVW $warray+WARRAY(SP),WREG
+ ADDU $(15*4),WREG,W15REG
+ ADDU $(40*4),WREG,W40REG
+ ADDU $(60*4),WREG,W60REG
+ ADDU $(80*4),WREG,W80REG
+
+mainloop:
+ MOVW $warray+WARRAY(SP),WREG
+
+ MOVW $0x5a827999,VREG
+loop1:
+ BODY1(0,FN1,VREG,AREG,BREG,CREG,DREG,EREG)
+ BODY1(4,FN1,VREG,EREG,AREG,BREG,CREG,DREG)
+ BODY1(8,FN1,VREG,DREG,EREG,AREG,BREG,CREG)
+ BODY1(12,FN1,VREG,CREG,DREG,EREG,AREG,BREG)
+ BODY1(16,FN1,VREG,BREG,CREG,DREG,EREG,AREG)
+
+ ADDU $20,DATAREG
+ ADDU $20,WREG
+ BNE WREG,W15REG,loop1
+
+ BODY1(0,FN1,VREG,AREG,BREG,CREG,DREG,EREG)
+ ADDU $4,DATAREG
+
+ BODY(4,FN1,VREG,EREG,AREG,BREG,CREG,DREG)
+ BODY(8,FN1,VREG,DREG,EREG,AREG,BREG,CREG)
+ BODY(12,FN1,VREG,CREG,DREG,EREG,AREG,BREG)
+ BODY(16,FN1,VREG,BREG,CREG,DREG,EREG,AREG)
+
+ ADDU $20,WREG
+
+ MOVW $0x6ed9eba1,VREG
+loop2:
+ BODY(0,FN24,VREG,AREG,BREG,CREG,DREG,EREG)
+ BODY(4,FN24,VREG,EREG,AREG,BREG,CREG,DREG)
+ BODY(8,FN24,VREG,DREG,EREG,AREG,BREG,CREG)
+ BODY(12,FN24,VREG,CREG,DREG,EREG,AREG,BREG)
+ BODY(16,FN24,VREG,BREG,CREG,DREG,EREG,AREG)
+
+ ADDU $20,WREG
+ BNE WREG,W40REG,loop2
+
+ MOVW $0x8f1bbcdc,VREG
+loop3:
+ BODY(0,FN3,VREG,AREG,BREG,CREG,DREG,EREG)
+ BODY(4,FN3,VREG,EREG,AREG,BREG,CREG,DREG)
+ BODY(8,FN3,VREG,DREG,EREG,AREG,BREG,CREG)
+ BODY(12,FN3,VREG,CREG,DREG,EREG,AREG,BREG)
+ BODY(16,FN3,VREG,BREG,CREG,DREG,EREG,AREG)
+
+ ADDU $20,WREG
+ BNE WREG,W60REG,loop3
+
+ MOVW $0xca62c1d6,VREG
+loop4:
+ BODY(0,FN24,VREG,AREG,BREG,CREG,DREG,EREG)
+ BODY(4,FN24,VREG,EREG,AREG,BREG,CREG,DREG)
+ BODY(8,FN24,VREG,DREG,EREG,AREG,BREG,CREG)
+ BODY(12,FN24,VREG,CREG,DREG,EREG,AREG,BREG)
+ BODY(16,FN24,VREG,BREG,CREG,DREG,EREG,AREG)
+
+ ADDU $20,WREG
+ BNE WREG,W80REG,loop4
+
+ MOVW 0(STREG),TMP1
+ MOVW 4(STREG),TMP2
+ MOVW 8(STREG),TMP3
+ MOVW 12(STREG),TMP4
+ MOVW 16(STREG),TMP5
+
+ ADDU TMP1,AREG
+ ADDU TMP2,BREG
+ ADDU TMP3,CREG
+ ADDU TMP4,DREG
+ ADDU TMP5,EREG
+
+ MOVW AREG,0(STREG)
+ MOVW BREG,4(STREG)
+ MOVW CREG,8(STREG)
+ MOVW DREG,12(STREG)
+ MOVW EREG,16(STREG)
+
+ BNE DATAREG,EDREG,mainloop
+
+ RET
+
+ END
--- /dev/null
+++ b/libsec/NOTICE
@@ -1,0 +1,4 @@
+Copyright © 2000-2007 Lucent Technologies Inc. and others. All rights reserved.
+Revisions for use with Inferno © 2006 Vita Nuova Holdings Limited.
+
+This software is provided under the terms of the Lucent Public License, Version 1.02.
--- /dev/null
+++ b/libsec/Plan9-386/md5block.s
@@ -1,0 +1,220 @@
+/*
+ * rfc1321 requires that I include this. The code is new. The constants
+ * all come from the rfc (hence the copyright). We trade a table for the
+ * macros in rfc. The total size is a lot less. -- presotto
+ *
+ * Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All
+ * rights reserved.
+ *
+ * License to copy and use this software is granted provided that it
+ * is identified as the "RSA Data Security, Inc. MD5 Message-Digest
+ * Algorithm" in all material mentioning or referencing this software
+ * or this function.
+ *
+ * License is also granted to make and use derivative works provided
+ * that such works are identified as "derived from the RSA Data
+ * Security, Inc. MD5 Message-Digest Algorithm" in all material
+ * mentioning or referencing the derived work.
+ *
+ * RSA Data Security, Inc. makes no representations concerning either
+ * the merchantability of this software or the suitability of this
+ * software forany particular purpose. It is provided "as is"
+ * without express or implied warranty of any kind.
+ * These notices must be retained in any copies of any part of this
+ * documentation and/or software.
+ */
+#define S11 7
+#define S12 12
+#define S13 17
+#define S14 22
+
+#define S21 5
+#define S22 9
+#define S23 14
+#define S24 20
+
+#define S31 4
+#define S32 11
+#define S33 16
+#define S34 23
+
+#define S41 6
+#define S42 10
+#define S43 15
+#define S44 21
+
+/*
+ * SI is data
+ * a += FN(B,C,D);
+ * a += x[sh] + t[sh];
+ * a = (a << S11) | (a >> (32 - S11));
+ * a += b;
+ */
+
+#define BODY1(off,V,FN,SH,A,B,C,D)\
+ FN(B,C,D)\
+ LEAL V(A)(DI*1),A;\
+ ADDL (off)(BP),A;\
+ ROLL $SH,A;\
+ ADDL B,A;\
+
+#define BODY(off,V,FN,SH,A,B,C,D)\
+ FN(B,C,D)\
+ LEAL V(A)(DI*1),A;\
+ ADDL (off)(BP),A;\
+ ROLL $SH,A;\
+ ADDL B,A;\
+
+/*
+ * fn1 = ((c ^ d) & b) ^ d
+ */
+#define FN1(B,C,D)\
+ MOVL C,DI;\
+ XORL D,DI;\
+ ANDL B,DI;\
+ XORL D,DI;\
+
+/*
+ * fn2 = ((b ^ c) & d) ^ c;
+ */
+#define FN2(B,C,D)\
+ MOVL B,DI;\
+ XORL C,DI;\
+ ANDL D,DI;\
+ XORL C,DI;\
+
+/*
+ * fn3 = b ^ c ^ d;
+ */
+#define FN3(B,C,D)\
+ MOVL B,DI;\
+ XORL C,DI;\
+ XORL D,DI;\
+
+/*
+ * fn4 = c ^ (b | ~d);
+ */
+#define FN4(B,C,D)\
+ MOVL D,DI;\
+ XORL $-1,DI;\
+ ORL B,DI;\
+ XORL C,DI;\
+
+#define DATA 0
+#define LEN 4
+#define STATE 8
+
+#define EDATA (-4)
+
+ TEXT _md5block+0(SB),$4
+
+ MOVL data+DATA(FP),AX
+ ADDL len+LEN(FP),AX
+ MOVL AX,edata+EDATA(SP)
+
+ MOVL data+DATA(FP),BP
+
+mainloop:
+ MOVL state+STATE(FP),SI
+ MOVL (SI),AX
+ MOVL 4(SI),BX
+ MOVL 8(SI),CX
+ MOVL 12(SI),DX
+
+ BODY1( 0*4,0xd76aa478,FN1,S11,AX,BX,CX,DX)
+ BODY1( 1*4,0xe8c7b756,FN1,S12,DX,AX,BX,CX)
+ BODY1( 2*4,0x242070db,FN1,S13,CX,DX,AX,BX)
+ BODY1( 3*4,0xc1bdceee,FN1,S14,BX,CX,DX,AX)
+
+ BODY1( 4*4,0xf57c0faf,FN1,S11,AX,BX,CX,DX)
+ BODY1( 5*4,0x4787c62a,FN1,S12,DX,AX,BX,CX)
+ BODY1( 6*4,0xa8304613,FN1,S13,CX,DX,AX,BX)
+ BODY1( 7*4,0xfd469501,FN1,S14,BX,CX,DX,AX)
+
+ BODY1( 8*4,0x698098d8,FN1,S11,AX,BX,CX,DX)
+ BODY1( 9*4,0x8b44f7af,FN1,S12,DX,AX,BX,CX)
+ BODY1(10*4,0xffff5bb1,FN1,S13,CX,DX,AX,BX)
+ BODY1(11*4,0x895cd7be,FN1,S14,BX,CX,DX,AX)
+
+ BODY1(12*4,0x6b901122,FN1,S11,AX,BX,CX,DX)
+ BODY1(13*4,0xfd987193,FN1,S12,DX,AX,BX,CX)
+ BODY1(14*4,0xa679438e,FN1,S13,CX,DX,AX,BX)
+ BODY1(15*4,0x49b40821,FN1,S14,BX,CX,DX,AX)
+
+
+ BODY( 1*4,0xf61e2562,FN2,S21,AX,BX,CX,DX)
+ BODY( 6*4,0xc040b340,FN2,S22,DX,AX,BX,CX)
+ BODY(11*4,0x265e5a51,FN2,S23,CX,DX,AX,BX)
+ BODY( 0*4,0xe9b6c7aa,FN2,S24,BX,CX,DX,AX)
+
+ BODY( 5*4,0xd62f105d,FN2,S21,AX,BX,CX,DX)
+ BODY(10*4,0x02441453,FN2,S22,DX,AX,BX,CX)
+ BODY(15*4,0xd8a1e681,FN2,S23,CX,DX,AX,BX)
+ BODY( 4*4,0xe7d3fbc8,FN2,S24,BX,CX,DX,AX)
+
+ BODY( 9*4,0x21e1cde6,FN2,S21,AX,BX,CX,DX)
+ BODY(14*4,0xc33707d6,FN2,S22,DX,AX,BX,CX)
+ BODY( 3*4,0xf4d50d87,FN2,S23,CX,DX,AX,BX)
+ BODY( 8*4,0x455a14ed,FN2,S24,BX,CX,DX,AX)
+
+ BODY(13*4,0xa9e3e905,FN2,S21,AX,BX,CX,DX)
+ BODY( 2*4,0xfcefa3f8,FN2,S22,DX,AX,BX,CX)
+ BODY( 7*4,0x676f02d9,FN2,S23,CX,DX,AX,BX)
+ BODY(12*4,0x8d2a4c8a,FN2,S24,BX,CX,DX,AX)
+
+
+ BODY( 5*4,0xfffa3942,FN3,S31,AX,BX,CX,DX)
+ BODY( 8*4,0x8771f681,FN3,S32,DX,AX,BX,CX)
+ BODY(11*4,0x6d9d6122,FN3,S33,CX,DX,AX,BX)
+ BODY(14*4,0xfde5380c,FN3,S34,BX,CX,DX,AX)
+
+ BODY( 1*4,0xa4beea44,FN3,S31,AX,BX,CX,DX)
+ BODY( 4*4,0x4bdecfa9,FN3,S32,DX,AX,BX,CX)
+ BODY( 7*4,0xf6bb4b60,FN3,S33,CX,DX,AX,BX)
+ BODY(10*4,0xbebfbc70,FN3,S34,BX,CX,DX,AX)
+
+ BODY(13*4,0x289b7ec6,FN3,S31,AX,BX,CX,DX)
+ BODY( 0*4,0xeaa127fa,FN3,S32,DX,AX,BX,CX)
+ BODY( 3*4,0xd4ef3085,FN3,S33,CX,DX,AX,BX)
+ BODY( 6*4,0x04881d05,FN3,S34,BX,CX,DX,AX)
+
+ BODY( 9*4,0xd9d4d039,FN3,S31,AX,BX,CX,DX)
+ BODY(12*4,0xe6db99e5,FN3,S32,DX,AX,BX,CX)
+ BODY(15*4,0x1fa27cf8,FN3,S33,CX,DX,AX,BX)
+ BODY( 2*4,0xc4ac5665,FN3,S34,BX,CX,DX,AX)
+
+
+ BODY( 0*4,0xf4292244,FN4,S41,AX,BX,CX,DX)
+ BODY( 7*4,0x432aff97,FN4,S42,DX,AX,BX,CX)
+ BODY(14*4,0xab9423a7,FN4,S43,CX,DX,AX,BX)
+ BODY( 5*4,0xfc93a039,FN4,S44,BX,CX,DX,AX)
+
+ BODY(12*4,0x655b59c3,FN4,S41,AX,BX,CX,DX)
+ BODY( 3*4,0x8f0ccc92,FN4,S42,DX,AX,BX,CX)
+ BODY(10*4,0xffeff47d,FN4,S43,CX,DX,AX,BX)
+ BODY( 1*4,0x85845dd1,FN4,S44,BX,CX,DX,AX)
+
+ BODY( 8*4,0x6fa87e4f,FN4,S41,AX,BX,CX,DX)
+ BODY(15*4,0xfe2ce6e0,FN4,S42,DX,AX,BX,CX)
+ BODY( 6*4,0xa3014314,FN4,S43,CX,DX,AX,BX)
+ BODY(13*4,0x4e0811a1,FN4,S44,BX,CX,DX,AX)
+
+ BODY( 4*4,0xf7537e82,FN4,S41,AX,BX,CX,DX)
+ BODY(11*4,0xbd3af235,FN4,S42,DX,AX,BX,CX)
+ BODY( 2*4,0x2ad7d2bb,FN4,S43,CX,DX,AX,BX)
+ BODY( 9*4,0xeb86d391,FN4,S44,BX,CX,DX,AX)
+
+ ADDL $(16*4),BP
+ MOVL state+STATE(FP),DI
+ ADDL AX,0(DI)
+ ADDL BX,4(DI)
+ ADDL CX,8(DI)
+ ADDL DX,12(DI)
+
+ MOVL edata+EDATA(SP),DI
+ CMPL BP,DI
+ JCS mainloop
+
+ RET
+
+ END
--- /dev/null
+++ b/libsec/Plan9-386/mkfile
@@ -1,0 +1,16 @@
+objtype=386
+OBJTYPE=$objtype
+<../../mkconfig
+
+LIB=libsec.a
+FILES=\
+ md5block\
+ sha1block\
+
+HFILES=$ROOT/include/libsec.h
+
+SFILES=${FILES:%=%.s}
+
+OFILES=${FILES:%=%.$O}
+
+<$ROOT/mkfiles/mksyslib-$SHELLTYPE
--- /dev/null
+++ b/libsec/Plan9-386/sha1block.s
@@ -1,0 +1,195 @@
+ TEXT _sha1block+0(SB),$352
+
+/* x = (wp[off-f] ^ wp[off-8] ^ wp[off-14] ^ wp[off-16]) <<< 1;
+ * wp[off] = x;
+ * x += A <<< 5;
+ * E += 0xca62c1d6 + x;
+ * x = FN(B,C,D);
+ * E += x;
+ * B >>> 2
+ */
+#define BSWAPDI BYTE $0x0f; BYTE $0xcf;
+
+#define BODY(off,FN,V,A,B,C,D,E)\
+ MOVL (off-64)(BP),DI;\
+ XORL (off-56)(BP),DI;\
+ XORL (off-32)(BP),DI;\
+ XORL (off-12)(BP),DI;\
+ ROLL $1,DI;\
+ MOVL DI,off(BP);\
+ LEAL V(DI)(E*1),E;\
+ MOVL A,DI;\
+ ROLL $5,DI;\
+ ADDL DI,E;\
+ FN(B,C,D)\
+ ADDL DI,E;\
+ RORL $2,B;\
+
+#define BODY0(off,FN,V,A,B,C,D,E)\
+ MOVL off(BX),DI;\
+ BSWAPDI;\
+ MOVL DI,off(BP);\
+ LEAL V(DI)(E*1),E;\
+ MOVL A,DI;\
+ ROLL $5,DI;\
+ ADDL DI,E;\
+ FN(B,C,D)\
+ ADDL DI,E;\
+ RORL $2,B;\
+
+/*
+ * fn1 = (((C^D)&B)^D);
+ */
+#define FN1(B,C,D)\
+ MOVL C,DI;\
+ XORL D,DI;\
+ ANDL B,DI;\
+ XORL D,DI;\
+
+/*
+ * fn24 = B ^ C ^ D
+ */
+#define FN24(B,C,D)\
+ MOVL B,DI;\
+ XORL C,DI;\
+ XORL D,DI;\
+
+/*
+ * fn3 = ((B ^ C) & (D ^= B)) ^ B
+ * D ^= B to restore D
+ */
+#define FN3(B,C,D)\
+ MOVL B,DI;\
+ XORL C,DI;\
+ XORL B,D;\
+ ANDL D,DI;\
+ XORL B,DI;\
+ XORL B,D;\
+
+/*
+ * stack offsets
+ * void sha1block(uchar *DATA, int LEN, ulong *STATE)
+ */
+#define DATA 0
+#define LEN 4
+#define STATE 8
+
+/*
+ * stack offsets for locals
+ * ulong w[80];
+ * uchar *edata;
+ * ulong *w15, *w40, *w60, *w80;
+ * register local
+ * ulong *wp = BP
+ * ulong a = eax, b = ebx, c = ecx, d = edx, e = esi
+ * ulong tmp = edi
+ */
+#define WARRAY (-4-(80*4))
+#define TMP1 (-8-(80*4))
+#define TMP2 (-12-(80*4))
+#define W15 (-16-(80*4))
+#define W40 (-20-(80*4))
+#define W60 (-24-(80*4))
+#define W80 (-28-(80*4))
+#define EDATA (-32-(80*4))
+
+ MOVL data+DATA(FP),AX
+ ADDL len+LEN(FP),AX
+ MOVL AX,edata+EDATA(SP)
+
+ LEAL aw15+(WARRAY+15*4)(SP),DI
+ MOVL DI,w15+W15(SP)
+ LEAL aw40+(WARRAY+40*4)(SP),DX
+ MOVL DX,w40+W40(SP)
+ LEAL aw60+(WARRAY+60*4)(SP),CX
+ MOVL CX,w60+W60(SP)
+ LEAL aw80+(WARRAY+80*4)(SP),DI
+ MOVL DI,w80+W80(SP)
+
+mainloop:
+ LEAL warray+WARRAY(SP),BP
+
+ MOVL state+STATE(FP),DI
+ MOVL (DI),AX
+ MOVL 4(DI),BX
+ MOVL BX,tmp1+TMP1(SP)
+ MOVL 8(DI),CX
+ MOVL 12(DI),DX
+ MOVL 16(DI),SI
+
+ MOVL data+DATA(FP),BX
+
+loop1:
+ BODY0(0,FN1,0x5a827999,AX,tmp1+TMP1(SP),CX,DX,SI)
+ MOVL SI,tmp2+TMP2(SP)
+ BODY0(4,FN1,0x5a827999,SI,AX,tmp1+TMP1(SP),CX,DX)
+ MOVL tmp1+TMP1(SP),SI
+ BODY0(8,FN1,0x5a827999,DX,tmp2+TMP2(SP),AX,SI,CX)
+ BODY0(12,FN1,0x5a827999,CX,DX,tmp2+TMP2(SP),AX,SI)
+ MOVL SI,tmp1+TMP1(SP)
+ BODY0(16,FN1,0x5a827999,SI,CX,DX,tmp2+TMP2(SP),AX)
+ MOVL tmp2+TMP2(SP),SI
+
+ ADDL $20,BX
+ ADDL $20,BP
+ CMPL BP,w15+W15(SP)
+ JCS loop1
+
+ BODY0(0,FN1,0x5a827999,AX,tmp1+TMP1(SP),CX,DX,SI)
+ ADDL $4,BX
+ MOVL BX,data+DATA(FP)
+ MOVL tmp1+TMP1(SP),BX
+
+ BODY(4,FN1,0x5a827999,SI,AX,BX,CX,DX)
+ BODY(8,FN1,0x5a827999,DX,SI,AX,BX,CX)
+ BODY(12,FN1,0x5a827999,CX,DX,SI,AX,BX)
+ BODY(16,FN1,0x5a827999,BX,CX,DX,SI,AX)
+
+ ADDL $20,BP
+
+loop2:
+ BODY(0,FN24,0x6ed9eba1,AX,BX,CX,DX,SI)
+ BODY(4,FN24,0x6ed9eba1,SI,AX,BX,CX,DX)
+ BODY(8,FN24,0x6ed9eba1,DX,SI,AX,BX,CX)
+ BODY(12,FN24,0x6ed9eba1,CX,DX,SI,AX,BX)
+ BODY(16,FN24,0x6ed9eba1,BX,CX,DX,SI,AX)
+
+ ADDL $20,BP
+ CMPL BP,w40+W40(SP)
+ JCS loop2
+
+loop3:
+ BODY(0,FN3,0x8f1bbcdc,AX,BX,CX,DX,SI)
+ BODY(4,FN3,0x8f1bbcdc,SI,AX,BX,CX,DX)
+ BODY(8,FN3,0x8f1bbcdc,DX,SI,AX,BX,CX)
+ BODY(12,FN3,0x8f1bbcdc,CX,DX,SI,AX,BX)
+ BODY(16,FN3,0x8f1bbcdc,BX,CX,DX,SI,AX)
+
+ ADDL $20,BP
+ CMPL BP,w60+W60(SP)
+ JCS loop3
+
+loop4:
+ BODY(0,FN24,0xca62c1d6,AX,BX,CX,DX,SI)
+ BODY(4,FN24,0xca62c1d6,SI,AX,BX,CX,DX)
+ BODY(8,FN24,0xca62c1d6,DX,SI,AX,BX,CX)
+ BODY(12,FN24,0xca62c1d6,CX,DX,SI,AX,BX)
+ BODY(16,FN24,0xca62c1d6,BX,CX,DX,SI,AX)
+
+ ADDL $20,BP
+ CMPL BP,w80+W80(SP)
+ JCS loop4
+
+ MOVL state+STATE(FP),DI
+ ADDL AX,0(DI)
+ ADDL BX,4(DI)
+ ADDL CX,8(DI)
+ ADDL DX,12(DI)
+ ADDL SI,16(DI)
+
+ MOVL edata+EDATA(SP),DI
+ CMPL data+DATA(FP),DI
+ JCS mainloop
+
+ RET
+ END
--- /dev/null
+++ b/libsec/Plan9-mips/md5block.s
@@ -1,0 +1,305 @@
+/*
+ * rfc1321 requires that I include this. The code is new. The constants
+ * all come from the rfc (hence the copyright). We trade a table for the
+ * macros in rfc. The total size is a lot less. -- presotto
+ *
+ * Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All
+ * rights reserved.
+ *
+ * License to copy and use this software is granted provided that it
+ * is identified as the "RSA Data Security, Inc. MD5 Message-Digest
+ * Algorithm" in all material mentioning or referencing this software
+ * or this function.
+ *
+ * License is also granted to make and use derivative works provided
+ * that such works are identified as "derived from the RSA Data
+ * Security, Inc. MD5 Message-Digest Algorithm" in all material
+ * mentioning or referencing the derived work.
+ *
+ * RSA Data Security, Inc. makes no representations concerning either
+ * the merchantability of this software or the suitability of this
+ * software forany particular purpose. It is provided "as is"
+ * without express or implied warranty of any kind.
+ * These notices must be retained in any copies of any part of this
+ * documentation and/or software.
+ */
+
+ /* round 1 */
+ DATA md5tab<>+( 0*4)(SB)/4,$0xd76aa478
+ DATA md5tab<>+( 1*4)(SB)/4,$0xe8c7b756
+ DATA md5tab<>+( 2*4)(SB)/4,$0x242070db
+ DATA md5tab<>+( 3*4)(SB)/4,$0xc1bdceee
+ DATA md5tab<>+( 4*4)(SB)/4,$0xf57c0faf
+ DATA md5tab<>+( 5*4)(SB)/4,$0x4787c62a
+ DATA md5tab<>+( 6*4)(SB)/4,$0xa8304613
+ DATA md5tab<>+( 7*4)(SB)/4,$0xfd469501
+ DATA md5tab<>+( 8*4)(SB)/4,$0x698098d8
+ DATA md5tab<>+( 9*4)(SB)/4,$0x8b44f7af
+ DATA md5tab<>+(10*4)(SB)/4,$0xffff5bb1
+ DATA md5tab<>+(11*4)(SB)/4,$0x895cd7be
+ DATA md5tab<>+(12*4)(SB)/4,$0x6b901122
+ DATA md5tab<>+(13*4)(SB)/4,$0xfd987193
+ DATA md5tab<>+(14*4)(SB)/4,$0xa679438e
+ DATA md5tab<>+(15*4)(SB)/4,$0x49b40821
+
+ /* round 2 */
+ DATA md5tab<>+(16*4)(SB)/4,$0xf61e2562
+ DATA md5tab<>+(17*4)(SB)/4,$0xc040b340
+ DATA md5tab<>+(18*4)(SB)/4,$0x265e5a51
+ DATA md5tab<>+(19*4)(SB)/4,$0xe9b6c7aa
+ DATA md5tab<>+(20*4)(SB)/4,$0xd62f105d
+ DATA md5tab<>+(21*4)(SB)/4,$0x02441453
+ DATA md5tab<>+(22*4)(SB)/4,$0xd8a1e681
+ DATA md5tab<>+(23*4)(SB)/4,$0xe7d3fbc8
+ DATA md5tab<>+(24*4)(SB)/4,$0x21e1cde6
+ DATA md5tab<>+(25*4)(SB)/4,$0xc33707d6
+ DATA md5tab<>+(26*4)(SB)/4,$0xf4d50d87
+ DATA md5tab<>+(27*4)(SB)/4,$0x455a14ed
+ DATA md5tab<>+(28*4)(SB)/4,$0xa9e3e905
+ DATA md5tab<>+(29*4)(SB)/4,$0xfcefa3f8
+ DATA md5tab<>+(30*4)(SB)/4,$0x676f02d9
+ DATA md5tab<>+(31*4)(SB)/4,$0x8d2a4c8a
+
+ /* round 3 */
+ DATA md5tab<>+(32*4)(SB)/4,$0xfffa3942
+ DATA md5tab<>+(33*4)(SB)/4,$0x8771f681
+ DATA md5tab<>+(34*4)(SB)/4,$0x6d9d6122
+ DATA md5tab<>+(35*4)(SB)/4,$0xfde5380c
+ DATA md5tab<>+(36*4)(SB)/4,$0xa4beea44
+ DATA md5tab<>+(37*4)(SB)/4,$0x4bdecfa9
+ DATA md5tab<>+(38*4)(SB)/4,$0xf6bb4b60
+ DATA md5tab<>+(39*4)(SB)/4,$0xbebfbc70
+ DATA md5tab<>+(40*4)(SB)/4,$0x289b7ec6
+ DATA md5tab<>+(41*4)(SB)/4,$0xeaa127fa
+ DATA md5tab<>+(42*4)(SB)/4,$0xd4ef3085
+ DATA md5tab<>+(43*4)(SB)/4,$0x04881d05
+ DATA md5tab<>+(44*4)(SB)/4,$0xd9d4d039
+ DATA md5tab<>+(45*4)(SB)/4,$0xe6db99e5
+ DATA md5tab<>+(46*4)(SB)/4,$0x1fa27cf8
+ DATA md5tab<>+(47*4)(SB)/4,$0xc4ac5665
+
+ /* round 4 */
+ DATA md5tab<>+(48*4)(SB)/4,$0xf4292244
+ DATA md5tab<>+(49*4)(SB)/4,$0x432aff97
+ DATA md5tab<>+(50*4)(SB)/4,$0xab9423a7
+ DATA md5tab<>+(51*4)(SB)/4,$0xfc93a039
+ DATA md5tab<>+(52*4)(SB)/4,$0x655b59c3
+ DATA md5tab<>+(53*4)(SB)/4,$0x8f0ccc92
+ DATA md5tab<>+(54*4)(SB)/4,$0xffeff47d
+ DATA md5tab<>+(55*4)(SB)/4,$0x85845dd1
+ DATA md5tab<>+(56*4)(SB)/4,$0x6fa87e4f
+ DATA md5tab<>+(57*4)(SB)/4,$0xfe2ce6e0
+ DATA md5tab<>+(58*4)(SB)/4,$0xa3014314
+ DATA md5tab<>+(59*4)(SB)/4,$0x4e0811a1
+ DATA md5tab<>+(60*4)(SB)/4,$0xf7537e82
+ DATA md5tab<>+(61*4)(SB)/4,$0xbd3af235
+ DATA md5tab<>+(62*4)(SB)/4,$0x2ad7d2bb
+ DATA md5tab<>+(63*4)(SB)/4,$0xeb86d391
+
+#define S11 7
+#define S12 12
+#define S13 17
+#define S14 22
+
+#define S21 5
+#define S22 9
+#define S23 14
+#define S24 20
+
+#define S31 4
+#define S32 11
+#define S33 16
+#define S34 23
+
+#define S41 6
+#define S42 10
+#define S43 15
+#define S44 21
+
+#define AREG R5
+#define BREG R6
+#define CREG R7
+#define DREG R8
+#define DATAREG R1
+#define TABREG R10
+#define STREG R11
+#define XREG R12
+#define ELOOPREG R13
+#define EDREG R14
+#define IREG R15
+
+#define TMP1 R9
+#define TMP2 R2
+#define TMP3 R3
+#define TMP4 R4
+
+/*
+ * decode little endian data into x[off], then the body
+ * bodies have this form:
+ * a += FN(B,C,D);
+ * a += x[off] + t[off];
+ * a = (a << S11) | (a >> (32 - S11));
+ * a += b;
+ */
+#define BODY1(off,FN,SH,A,B,C,D)\
+ MOVBU off(DATAREG),TMP2;\
+ MOVBU (off+1)(DATAREG),TMP3;\
+ MOVBU (off+2)(DATAREG),TMP1;\
+ MOVBU (off+3)(DATAREG),TMP4;\
+ SLL $8,TMP3;\
+ OR TMP3,TMP2;\
+ SLL $16,TMP1;\
+ OR TMP1,TMP2;\
+ SLL $24,TMP4;\
+ OR TMP4,TMP2;\
+ MOVW off(TABREG),TMP3;\
+ FN(B,C,D)\
+ ADDU TMP1,A;\
+ MOVW TMP2,off(XREG);\
+ ADDU TMP2,A;\
+ ADDU TMP3,A;\
+ SLL $SH,A,TMP1;\
+ SRL $(32-SH),A;\
+ OR TMP1,A;\
+ ADDU B,A;\
+
+#define BODY(off,inc,FN,SH,A,B,C,D)\
+ MOVW off(TABREG),TMP3;\
+ ADDU XREG,IREG,TMP4;\
+ MOVW (TMP4),TMP2;\
+ ADDU $(inc*4),IREG;\
+ AND $63,IREG;\
+ FN(B,C,D)\
+ ADDU TMP1,A;\
+ ADDU TMP2,A;\
+ ADDU TMP3,A;\
+ SLL $SH,A,TMP1;\
+ SRL $(32-SH),A;\
+ OR TMP1,A;\
+ ADDU B,A;\
+
+/*
+ * fn1 = ((c ^ d) & b) ^ d
+ */
+#define FN1(B,C,D)\
+ XOR C,D,TMP1;\
+ AND B,TMP1;\
+ XOR D,TMP1;\
+
+/*
+ * fn2 = ((b ^ c) & d) ^ c;
+ */
+#define FN2(B,C,D)\
+ XOR B,C,TMP1;\
+ AND D,TMP1;\
+ XOR C,TMP1;\
+
+/*
+ * fn3 = b ^ c ^ d;
+ */
+#define FN3(B,C,D)\
+ XOR B,C,TMP1;\
+ XOR D,TMP1;\
+
+/*
+ * fn4 = c ^ (b | ~d);
+ */
+#define FN4(B,C,D)\
+ XOR $-1,D,TMP1;\
+ OR B,TMP1;\
+ XOR C,TMP1;\
+
+#define DATA 0
+#define LEN 4
+#define STATE 8
+
+#define XOFF (-4-16*4)
+
+ TEXT _md5block+0(SB),$68
+
+ MOVW len+LEN(FP),TMP1
+ ADDU DATAREG,TMP1,EDREG
+ MOVW state+STATE(FP),STREG
+
+ MOVW 0(STREG),AREG
+ MOVW 4(STREG),BREG
+ MOVW 8(STREG),CREG
+ MOVW 12(STREG),DREG
+
+mainloop:
+
+ MOVW $md5tab<>+0(SB),TABREG
+ ADDU $(16*4),DATAREG,ELOOPREG
+ MOVW $x+XOFF(SP),XREG
+
+loop1:
+ BODY1(0,FN1,S11,AREG,BREG,CREG,DREG)
+ BODY1(4,FN1,S12,DREG,AREG,BREG,CREG)
+ BODY1(8,FN1,S13,CREG,DREG,AREG,BREG)
+ BODY1(12,FN1,S14,BREG,CREG,DREG,AREG)
+
+ ADDU $16,DATAREG
+ ADDU $16,TABREG
+ ADDU $16,XREG
+
+ BNE DATAREG,ELOOPREG,loop1
+
+
+ MOVW $x+XOFF(SP),XREG
+ MOVW $(1*4),IREG
+ MOVW $(1*4),ELOOPREG
+loop2:
+ BODY(0,5,FN2,S21,AREG,BREG,CREG,DREG)
+ BODY(4,5,FN2,S22,DREG,AREG,BREG,CREG)
+ BODY(8,5,FN2,S23,CREG,DREG,AREG,BREG)
+ BODY(12,5,FN2,S24,BREG,CREG,DREG,AREG)
+
+ ADDU $16,TABREG
+
+ BNE IREG,ELOOPREG,loop2
+
+
+ MOVW $(5*4),IREG
+ MOVW $(5*4),ELOOPREG
+loop3:
+ BODY(0,3,FN3,S31,AREG,BREG,CREG,DREG)
+ BODY(4,3,FN3,S32,DREG,AREG,BREG,CREG)
+ BODY(8,3,FN3,S33,CREG,DREG,AREG,BREG)
+ BODY(12,3,FN3,S34,BREG,CREG,DREG,AREG)
+
+ ADDU $16,TABREG
+
+ BNE IREG,ELOOPREG,loop3
+
+
+ MOVW $0,IREG
+loop4:
+ BODY(0,7,FN4,S41,AREG,BREG,CREG,DREG)
+ BODY(4,7,FN4,S42,DREG,AREG,BREG,CREG)
+ BODY(8,7,FN4,S43,CREG,DREG,AREG,BREG)
+ BODY(12,7,FN4,S44,BREG,CREG,DREG,AREG)
+
+ ADDU $16,TABREG
+
+ BNE IREG,R0,loop4
+
+ MOVW 0(STREG),TMP1
+ MOVW 4(STREG),TMP2
+ MOVW 8(STREG),TMP3
+ MOVW 12(STREG),TMP4
+ ADDU TMP1,AREG
+ ADDU TMP2,BREG
+ ADDU TMP3,CREG
+ ADDU TMP4,DREG
+ MOVW AREG,0(STREG)
+ MOVW BREG,4(STREG)
+ MOVW CREG,8(STREG)
+ MOVW DREG,12(STREG)
+
+ BNE DATAREG,EDREG,mainloop
+
+ RET
+
+ GLOBL md5tab<>+0(SB),$256
+
+ END
--- /dev/null
+++ b/libsec/Plan9-mips/mkfile
@@ -1,0 +1,16 @@
+objtype=mips
+OBJTYPE=$objtype
+<../../mkconfig
+
+LIB=libsec.a
+FILES=\
+ md5block\
+ sha1block\
+
+HFILES=$ROOT/include/libsec.h
+
+SFILES=${FILES:%=%.s}
+
+OFILES=${FILES:%=%.$O}
+
+<$ROOT/mkfiles/mksyslib-$SHELLTYPE
--- /dev/null
+++ b/libsec/Plan9-mips/sha1block.s
@@ -1,0 +1,220 @@
+ TEXT _sha1block+0(SB),$328
+
+/*
+ * wp[off] = x;
+ * x += A <<< 5;
+ * E += 0xca62c1d6 + x;
+ * x = FN(B,C,D);
+ * E += x;
+ * B >>> 2
+ */
+#define BODYX(off,FN,V,A,B,C,D,E)\
+ FN(B,C,D)\
+ ADDU TMP1,E;\
+ ADDU V,E;\
+ MOVW TMP2,off(WREG);\
+ ADDU TMP2,E;\
+ SLL $5,A,TMP3;\
+ SRL $27,A,TMP4;\
+ OR TMP3,TMP4;\
+ ADDU TMP4,E;\
+ SLL $30,B,TMP4;\
+ SRL $2,B;\
+ OR TMP4,B
+
+/*
+ * x = data[i]
+ * BODYX
+ */
+#define BODY1(off,FN,V,A,B,C,D,E)\
+ MOVBU off(DATAREG),TMP2;\
+ MOVBU (off+1)(DATAREG),TMP3;\
+ MOVBU (off+2)(DATAREG),TMP1;\
+ MOVBU (off+3)(DATAREG),TMP4;\
+ SLL $24,TMP2;\
+ SLL $16,TMP3;\
+ OR TMP3,TMP2;\
+ SLL $8,TMP1;\
+ OR TMP1,TMP2;\
+ OR TMP4,TMP2;\
+ BODYX(off,FN,V,A,B,C,D,E)
+
+/*
+ * x = (wp[off-3] ^ wp[off-8] ^ wp[off-14] ^ wp[off-16]) <<< 1;
+ * BODYX
+ */
+#define BODY(off,FN,V,A,B,C,D,E)\
+ MOVW (off-64)(WREG),TMP1;\
+ MOVW (off-56)(WREG),TMP2;\
+ MOVW (off-32)(WREG),TMP3;\
+ MOVW (off-12)(WREG),TMP4;\
+ XOR TMP1,TMP2;\
+ XOR TMP3,TMP2;\
+ XOR TMP4,TMP2;\
+ SLL $1,TMP2,TMP1;\
+ SRL $31,TMP2;\
+ OR TMP1,TMP2;\
+ BODYX(off,FN,V,A,B,C,D,E)
+
+/*
+ * fn1 = (((C^D)&B)^D);
+ */
+#define FN1(B,C,D)\
+ XOR C,D,TMP1;\
+ AND B,TMP1;\
+ XOR D,TMP1;
+
+/*
+ * fn24 = B ^ C ^ D
+ */
+#define FN24(B,C,D)\
+ XOR B,C,TMP1;\
+ XOR D,TMP1;
+
+/*
+ * fn3 = ((B ^ C) & (D ^ B)) ^ B
+ */
+#define FN3(B,C,D)\
+ XOR B,C,TMP1;\
+ XOR B,D,TMP4;\
+ AND TMP4,TMP1;\
+ XOR B,TMP1;
+
+/*
+ * stack offsets
+ * void vtSha1Block(ulong *STATE, uchar *DATA, int LEN)
+ */
+#define DATA 0
+#define LEN 4
+#define STATE 8
+
+/*
+ * stack offsets for locals
+ * ulong w[80];
+ * uchar *edata;
+ * ulong *w15, *w40, *w60, *w80;
+ * register local
+ * ulong *wp = BP
+ * ulong a = eax, b = ebx, c = ecx, d = edx, e = esi
+ * ulong tmp = edi
+ */
+#define WARRAY (-4-(80*4))
+
+#define AREG R5
+#define BREG R6
+#define CREG R7
+#define DREG R8
+#define EREG R9
+#define DATAREG R1
+#define STREG R11
+#define WREG R12
+#define W15REG R13
+#define W60REG R14
+#define W40REG R15
+#define W80REG R16
+#define EDREG R17
+#define VREG R18
+
+#define TMP1 R10
+#define TMP2 R2
+#define TMP3 R3
+#define TMP4 R4
+#define TMP5 R19
+
+ MOVW len+LEN(FP),TMP1
+ MOVW state+STATE(FP),STREG
+ ADDU DATAREG,TMP1,EDREG
+
+ MOVW 0(STREG),AREG
+ MOVW 4(STREG),BREG
+ MOVW 8(STREG),CREG
+ MOVW 12(STREG),DREG
+ MOVW 16(STREG),EREG
+
+ MOVW $warray+WARRAY(SP),WREG
+ ADDU $(15*4),WREG,W15REG
+ ADDU $(40*4),WREG,W40REG
+ ADDU $(60*4),WREG,W60REG
+ ADDU $(80*4),WREG,W80REG
+
+mainloop:
+ MOVW $warray+WARRAY(SP),WREG
+
+ MOVW $0x5a827999,VREG
+loop1:
+ BODY1(0,FN1,VREG,AREG,BREG,CREG,DREG,EREG)
+ BODY1(4,FN1,VREG,EREG,AREG,BREG,CREG,DREG)
+ BODY1(8,FN1,VREG,DREG,EREG,AREG,BREG,CREG)
+ BODY1(12,FN1,VREG,CREG,DREG,EREG,AREG,BREG)
+ BODY1(16,FN1,VREG,BREG,CREG,DREG,EREG,AREG)
+
+ ADDU $20,DATAREG
+ ADDU $20,WREG
+ BNE WREG,W15REG,loop1
+
+ BODY1(0,FN1,VREG,AREG,BREG,CREG,DREG,EREG)
+ ADDU $4,DATAREG
+
+ BODY(4,FN1,VREG,EREG,AREG,BREG,CREG,DREG)
+ BODY(8,FN1,VREG,DREG,EREG,AREG,BREG,CREG)
+ BODY(12,FN1,VREG,CREG,DREG,EREG,AREG,BREG)
+ BODY(16,FN1,VREG,BREG,CREG,DREG,EREG,AREG)
+
+ ADDU $20,WREG
+
+ MOVW $0x6ed9eba1,VREG
+loop2:
+ BODY(0,FN24,VREG,AREG,BREG,CREG,DREG,EREG)
+ BODY(4,FN24,VREG,EREG,AREG,BREG,CREG,DREG)
+ BODY(8,FN24,VREG,DREG,EREG,AREG,BREG,CREG)
+ BODY(12,FN24,VREG,CREG,DREG,EREG,AREG,BREG)
+ BODY(16,FN24,VREG,BREG,CREG,DREG,EREG,AREG)
+
+ ADDU $20,WREG
+ BNE WREG,W40REG,loop2
+
+ MOVW $0x8f1bbcdc,VREG
+loop3:
+ BODY(0,FN3,VREG,AREG,BREG,CREG,DREG,EREG)
+ BODY(4,FN3,VREG,EREG,AREG,BREG,CREG,DREG)
+ BODY(8,FN3,VREG,DREG,EREG,AREG,BREG,CREG)
+ BODY(12,FN3,VREG,CREG,DREG,EREG,AREG,BREG)
+ BODY(16,FN3,VREG,BREG,CREG,DREG,EREG,AREG)
+
+ ADDU $20,WREG
+ BNE WREG,W60REG,loop3
+
+ MOVW $0xca62c1d6,VREG
+loop4:
+ BODY(0,FN24,VREG,AREG,BREG,CREG,DREG,EREG)
+ BODY(4,FN24,VREG,EREG,AREG,BREG,CREG,DREG)
+ BODY(8,FN24,VREG,DREG,EREG,AREG,BREG,CREG)
+ BODY(12,FN24,VREG,CREG,DREG,EREG,AREG,BREG)
+ BODY(16,FN24,VREG,BREG,CREG,DREG,EREG,AREG)
+
+ ADDU $20,WREG
+ BNE WREG,W80REG,loop4
+
+ MOVW 0(STREG),TMP1
+ MOVW 4(STREG),TMP2
+ MOVW 8(STREG),TMP3
+ MOVW 12(STREG),TMP4
+ MOVW 16(STREG),TMP5
+
+ ADDU TMP1,AREG
+ ADDU TMP2,BREG
+ ADDU TMP3,CREG
+ ADDU TMP4,DREG
+ ADDU TMP5,EREG
+
+ MOVW AREG,0(STREG)
+ MOVW BREG,4(STREG)
+ MOVW CREG,8(STREG)
+ MOVW DREG,12(STREG)
+ MOVW EREG,16(STREG)
+
+ BNE DATAREG,EDREG,mainloop
+
+ RET
+
+ END
--- /dev/null
+++ b/libsec/mkfile
@@ -1,0 +1,6 @@
+<../mkconfig
+
+# TARGMODEL not SYSTARG for now
+DIRS=port $TARGMODEL-$OBJTYPE
+
+<$ROOT/mkfiles/mklibsubdirs
--- /dev/null
+++ b/libsec/port/aes.c
@@ -1,0 +1,1543 @@
+/*
+ * this code is derived from the following source,
+ * and modified to fit into the plan 9 libsec interface.
+ * most of the changes are confined to the top section,
+ * with the exception of converting Te4 and Td4 into u8 rather than u32 arrays.
+ *
+ * rijndael-alg-fst.c
+ *
+ * @version 3.0 (December 2000)
+ *
+ * Optimised ANSI C code for the Rijndael cipher (now AES)
+ *
+ * @author Vincent Rijmen <vincent.rijmen@esat.kuleuven.ac.be>
+ * @author Antoon Bosselaers <antoon.bosselaers@esat.kuleuven.ac.be>
+ * @author Paulo Barreto <paulo.barreto@terra.com.br>
+ *
+ * This code is hereby placed in the public domain.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ''AS IS'' AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+ * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#include "os.h"
+#include <libsec.h>
+
+typedef uchar u8;
+typedef u32int u32;
+#define FULL_UNROLL
+
+static const u32 Td0[256];
+static const u32 Td1[256];
+static const u32 Td2[256];
+static const u32 Td3[256];
+static const u8 Te4[256];
+
+static int rijndaelKeySetupEnc(u32 rk[/*4*(Nr + 1)*/], const u8 cipherKey[], int keyBits);
+static int rijndaelKeySetupDec(u32 rk[/*4*(Nr + 1)*/], const u8 cipherKey[], int keyBits);
+static int rijndaelKeySetup(u32 erk[/*4*(Nr + 1)*/], u32 drk[/*4*(Nr + 1)*/], const u8 cipherKey[], int keyBits);
+static void rijndaelEncrypt(const u32int rk[], int Nr, const uchar pt[16], uchar ct[16]);
+static void rijndaelDecrypt(const u32int rk[], int Nr, const uchar ct[16], uchar pt[16]);
+
+void
+setupAESstate(AESstate *s, uchar key[], int keybytes, uchar *ivec)
+{
+ memset(s, 0, sizeof(*s));
+ if(keybytes > AESmaxkey)
+ keybytes = AESmaxkey;
+ memmove(s->key, key, keybytes);
+ s->keybytes = keybytes;
+ s->rounds = rijndaelKeySetup(s->ekey, s->dkey, s->key, keybytes * 8);
+ if(ivec != nil)
+ memmove(s->ivec, ivec, AESbsize);
+ if(keybytes==16 || keybytes==24 || keybytes==32)
+ s->setup = 0xcafebabe;
+ // else rijndaelKeySetup was invalid
+}
+
+// Define by analogy with desCBCencrypt; AES modes are not standardized yet.
+// Because of the way that non-multiple-of-16 buffers are handled,
+// the decryptor must be fed buffers of the same size as the encryptor.
+void
+aesCBCencrypt(uchar *p, int len, AESstate *s)
+{
+ uchar *p2, *ip, *eip;
+ uchar q[AESbsize];
+
+ for(; len >= AESbsize; len -= AESbsize){
+ p2 = p;
+ ip = s->ivec;
+ for(eip = ip+AESbsize; ip < eip; )
+ *p2++ ^= *ip++;
+ rijndaelEncrypt(s->ekey, s->rounds, p, q);
+ memmove(s->ivec, q, AESbsize);
+ memmove(p, q, AESbsize);
+ p += AESbsize;
+ }
+
+ if(len > 0){
+ ip = s->ivec;
+ rijndaelEncrypt(s->ekey, s->rounds, ip, q);
+ memmove(s->ivec, q, AESbsize);
+ for(eip = ip+len; ip < eip; )
+ *p++ ^= *ip++;
+ }
+}
+
+void
+aesCBCdecrypt(uchar *p, int len, AESstate *s)
+{
+ uchar *ip, *eip, *tp;
+ uchar tmp[AESbsize], q[AESbsize];
+
+ for(; len >= AESbsize; len -= AESbsize){
+ memmove(tmp, p, AESbsize);
+ rijndaelDecrypt(s->dkey, s->rounds, p, q);
+ memmove(p, q, AESbsize);
+ tp = tmp;
+ ip = s->ivec;
+ for(eip = ip+AESbsize; ip < eip; ){
+ *p++ ^= *ip;
+ *ip++ = *tp++;
+ }
+ }
+
+ if(len > 0){
+ ip = s->ivec;
+ rijndaelEncrypt(s->ekey, s->rounds, ip, q);
+ memmove(s->ivec, q, AESbsize);
+ for(eip = ip+len; ip < eip; )
+ *p++ ^= *ip++;
+ }
+}
+
+/*
+ * this function has been changed for plan 9.
+ * Expand the cipher key into the encryption and decryption key schedules.
+ *
+ * @return the number of rounds for the given cipher key size.
+ */
+static int rijndaelKeySetup(u32 erk[/*4*(Nr + 1)*/], u32 drk[/*4*(Nr + 1)*/], const u8 cipherKey[], int keyBits) {
+ int Nr, i;
+
+ /* expand the cipher key: */
+ Nr = rijndaelKeySetupEnc(erk, cipherKey, keyBits);
+
+ /*
+ * invert the order of the round keys and
+ * apply the inverse MixColumn transform to all round keys but the first and the last
+ */
+ drk[0 ] = erk[4*Nr ];
+ drk[1 ] = erk[4*Nr + 1];
+ drk[2 ] = erk[4*Nr + 2];
+ drk[3 ] = erk[4*Nr + 3];
+ drk[4*Nr ] = erk[0 ];
+ drk[4*Nr + 1] = erk[1 ];
+ drk[4*Nr + 2] = erk[2 ];
+ drk[4*Nr + 3] = erk[3 ];
+ erk += 4 * Nr;
+ for (i = 1; i < Nr; i++) {
+ drk += 4;
+ erk -= 4;
+ drk[0] =
+ Td0[Te4[(erk[0] >> 24) ]] ^
+ Td1[Te4[(erk[0] >> 16) & 0xff]] ^
+ Td2[Te4[(erk[0] >> 8) & 0xff]] ^
+ Td3[Te4[(erk[0] ) & 0xff]];
+ drk[1] =
+ Td0[Te4[(erk[1] >> 24) ]] ^
+ Td1[Te4[(erk[1] >> 16) & 0xff]] ^
+ Td2[Te4[(erk[1] >> 8) & 0xff]] ^
+ Td3[Te4[(erk[1] ) & 0xff]];
+ drk[2] =
+ Td0[Te4[(erk[2] >> 24) ]] ^
+ Td1[Te4[(erk[2] >> 16) & 0xff]] ^
+ Td2[Te4[(erk[2] >> 8) & 0xff]] ^
+ Td3[Te4[(erk[2] ) & 0xff]];
+ drk[3] =
+ Td0[Te4[(erk[3] >> 24) ]] ^
+ Td1[Te4[(erk[3] >> 16) & 0xff]] ^
+ Td2[Te4[(erk[3] >> 8) & 0xff]] ^
+ Td3[Te4[(erk[3] ) & 0xff]];
+ }
+ return Nr;
+}
+
+/*
+Te0[x] = S [x].[02, 01, 01, 03];
+Te1[x] = S [x].[03, 02, 01, 01];
+Te2[x] = S [x].[01, 03, 02, 01];
+Te3[x] = S [x].[01, 01, 03, 02];
+Te4[x] = S [x]
+
+Td0[x] = Si[x].[0e, 09, 0d, 0b];
+Td1[x] = Si[x].[0b, 0e, 09, 0d];
+Td2[x] = Si[x].[0d, 0b, 0e, 09];
+Td3[x] = Si[x].[09, 0d, 0b, 0e];
+Td4[x] = Si[x]
+*/
+
+static const u32 Te0[256] = {
+ 0xc66363a5U, 0xf87c7c84U, 0xee777799U, 0xf67b7b8dU,
+ 0xfff2f20dU, 0xd66b6bbdU, 0xde6f6fb1U, 0x91c5c554U,
+ 0x60303050U, 0x02010103U, 0xce6767a9U, 0x562b2b7dU,
+ 0xe7fefe19U, 0xb5d7d762U, 0x4dababe6U, 0xec76769aU,
+ 0x8fcaca45U, 0x1f82829dU, 0x89c9c940U, 0xfa7d7d87U,
+ 0xeffafa15U, 0xb25959ebU, 0x8e4747c9U, 0xfbf0f00bU,
+ 0x41adadecU, 0xb3d4d467U, 0x5fa2a2fdU, 0x45afafeaU,
+ 0x239c9cbfU, 0x53a4a4f7U, 0xe4727296U, 0x9bc0c05bU,
+ 0x75b7b7c2U, 0xe1fdfd1cU, 0x3d9393aeU, 0x4c26266aU,
+ 0x6c36365aU, 0x7e3f3f41U, 0xf5f7f702U, 0x83cccc4fU,
+ 0x6834345cU, 0x51a5a5f4U, 0xd1e5e534U, 0xf9f1f108U,
+ 0xe2717193U, 0xabd8d873U, 0x62313153U, 0x2a15153fU,
+ 0x0804040cU, 0x95c7c752U, 0x46232365U, 0x9dc3c35eU,
+ 0x30181828U, 0x379696a1U, 0x0a05050fU, 0x2f9a9ab5U,
+ 0x0e070709U, 0x24121236U, 0x1b80809bU, 0xdfe2e23dU,
+ 0xcdebeb26U, 0x4e272769U, 0x7fb2b2cdU, 0xea75759fU,
+ 0x1209091bU, 0x1d83839eU, 0x582c2c74U, 0x341a1a2eU,
+ 0x361b1b2dU, 0xdc6e6eb2U, 0xb45a5aeeU, 0x5ba0a0fbU,
+ 0xa45252f6U, 0x763b3b4dU, 0xb7d6d661U, 0x7db3b3ceU,
+ 0x5229297bU, 0xdde3e33eU, 0x5e2f2f71U, 0x13848497U,
+ 0xa65353f5U, 0xb9d1d168U, 0x00000000U, 0xc1eded2cU,
+ 0x40202060U, 0xe3fcfc1fU, 0x79b1b1c8U, 0xb65b5bedU,
+ 0xd46a6abeU, 0x8dcbcb46U, 0x67bebed9U, 0x7239394bU,
+ 0x944a4adeU, 0x984c4cd4U, 0xb05858e8U, 0x85cfcf4aU,
+ 0xbbd0d06bU, 0xc5efef2aU, 0x4faaaae5U, 0xedfbfb16U,
+ 0x864343c5U, 0x9a4d4dd7U, 0x66333355U, 0x11858594U,
+ 0x8a4545cfU, 0xe9f9f910U, 0x04020206U, 0xfe7f7f81U,
+ 0xa05050f0U, 0x783c3c44U, 0x259f9fbaU, 0x4ba8a8e3U,
+ 0xa25151f3U, 0x5da3a3feU, 0x804040c0U, 0x058f8f8aU,
+ 0x3f9292adU, 0x219d9dbcU, 0x70383848U, 0xf1f5f504U,
+ 0x63bcbcdfU, 0x77b6b6c1U, 0xafdada75U, 0x42212163U,
+ 0x20101030U, 0xe5ffff1aU, 0xfdf3f30eU, 0xbfd2d26dU,
+ 0x81cdcd4cU, 0x180c0c14U, 0x26131335U, 0xc3ecec2fU,
+ 0xbe5f5fe1U, 0x359797a2U, 0x884444ccU, 0x2e171739U,
+ 0x93c4c457U, 0x55a7a7f2U, 0xfc7e7e82U, 0x7a3d3d47U,
+ 0xc86464acU, 0xba5d5de7U, 0x3219192bU, 0xe6737395U,
+ 0xc06060a0U, 0x19818198U, 0x9e4f4fd1U, 0xa3dcdc7fU,
+ 0x44222266U, 0x542a2a7eU, 0x3b9090abU, 0x0b888883U,
+ 0x8c4646caU, 0xc7eeee29U, 0x6bb8b8d3U, 0x2814143cU,
+ 0xa7dede79U, 0xbc5e5ee2U, 0x160b0b1dU, 0xaddbdb76U,
+ 0xdbe0e03bU, 0x64323256U, 0x743a3a4eU, 0x140a0a1eU,
+ 0x924949dbU, 0x0c06060aU, 0x4824246cU, 0xb85c5ce4U,
+ 0x9fc2c25dU, 0xbdd3d36eU, 0x43acacefU, 0xc46262a6U,
+ 0x399191a8U, 0x319595a4U, 0xd3e4e437U, 0xf279798bU,
+ 0xd5e7e732U, 0x8bc8c843U, 0x6e373759U, 0xda6d6db7U,
+ 0x018d8d8cU, 0xb1d5d564U, 0x9c4e4ed2U, 0x49a9a9e0U,
+ 0xd86c6cb4U, 0xac5656faU, 0xf3f4f407U, 0xcfeaea25U,
+ 0xca6565afU, 0xf47a7a8eU, 0x47aeaee9U, 0x10080818U,
+ 0x6fbabad5U, 0xf0787888U, 0x4a25256fU, 0x5c2e2e72U,
+ 0x381c1c24U, 0x57a6a6f1U, 0x73b4b4c7U, 0x97c6c651U,
+ 0xcbe8e823U, 0xa1dddd7cU, 0xe874749cU, 0x3e1f1f21U,
+ 0x964b4bddU, 0x61bdbddcU, 0x0d8b8b86U, 0x0f8a8a85U,
+ 0xe0707090U, 0x7c3e3e42U, 0x71b5b5c4U, 0xcc6666aaU,
+ 0x904848d8U, 0x06030305U, 0xf7f6f601U, 0x1c0e0e12U,
+ 0xc26161a3U, 0x6a35355fU, 0xae5757f9U, 0x69b9b9d0U,
+ 0x17868691U, 0x99c1c158U, 0x3a1d1d27U, 0x279e9eb9U,
+ 0xd9e1e138U, 0xebf8f813U, 0x2b9898b3U, 0x22111133U,
+ 0xd26969bbU, 0xa9d9d970U, 0x078e8e89U, 0x339494a7U,
+ 0x2d9b9bb6U, 0x3c1e1e22U, 0x15878792U, 0xc9e9e920U,
+ 0x87cece49U, 0xaa5555ffU, 0x50282878U, 0xa5dfdf7aU,
+ 0x038c8c8fU, 0x59a1a1f8U, 0x09898980U, 0x1a0d0d17U,
+ 0x65bfbfdaU, 0xd7e6e631U, 0x844242c6U, 0xd06868b8U,
+ 0x824141c3U, 0x299999b0U, 0x5a2d2d77U, 0x1e0f0f11U,
+ 0x7bb0b0cbU, 0xa85454fcU, 0x6dbbbbd6U, 0x2c16163aU,
+};
+static const u32 Te1[256] = {
+ 0xa5c66363U, 0x84f87c7cU, 0x99ee7777U, 0x8df67b7bU,
+ 0x0dfff2f2U, 0xbdd66b6bU, 0xb1de6f6fU, 0x5491c5c5U,
+ 0x50603030U, 0x03020101U, 0xa9ce6767U, 0x7d562b2bU,
+ 0x19e7fefeU, 0x62b5d7d7U, 0xe64dababU, 0x9aec7676U,
+ 0x458fcacaU, 0x9d1f8282U, 0x4089c9c9U, 0x87fa7d7dU,
+ 0x15effafaU, 0xebb25959U, 0xc98e4747U, 0x0bfbf0f0U,
+ 0xec41adadU, 0x67b3d4d4U, 0xfd5fa2a2U, 0xea45afafU,
+ 0xbf239c9cU, 0xf753a4a4U, 0x96e47272U, 0x5b9bc0c0U,
+ 0xc275b7b7U, 0x1ce1fdfdU, 0xae3d9393U, 0x6a4c2626U,
+ 0x5a6c3636U, 0x417e3f3fU, 0x02f5f7f7U, 0x4f83ccccU,
+ 0x5c683434U, 0xf451a5a5U, 0x34d1e5e5U, 0x08f9f1f1U,
+ 0x93e27171U, 0x73abd8d8U, 0x53623131U, 0x3f2a1515U,
+ 0x0c080404U, 0x5295c7c7U, 0x65462323U, 0x5e9dc3c3U,
+ 0x28301818U, 0xa1379696U, 0x0f0a0505U, 0xb52f9a9aU,
+ 0x090e0707U, 0x36241212U, 0x9b1b8080U, 0x3ddfe2e2U,
+ 0x26cdebebU, 0x694e2727U, 0xcd7fb2b2U, 0x9fea7575U,
+ 0x1b120909U, 0x9e1d8383U, 0x74582c2cU, 0x2e341a1aU,
+ 0x2d361b1bU, 0xb2dc6e6eU, 0xeeb45a5aU, 0xfb5ba0a0U,
+ 0xf6a45252U, 0x4d763b3bU, 0x61b7d6d6U, 0xce7db3b3U,
+ 0x7b522929U, 0x3edde3e3U, 0x715e2f2fU, 0x97138484U,
+ 0xf5a65353U, 0x68b9d1d1U, 0x00000000U, 0x2cc1ededU,
+ 0x60402020U, 0x1fe3fcfcU, 0xc879b1b1U, 0xedb65b5bU,
+ 0xbed46a6aU, 0x468dcbcbU, 0xd967bebeU, 0x4b723939U,
+ 0xde944a4aU, 0xd4984c4cU, 0xe8b05858U, 0x4a85cfcfU,
+ 0x6bbbd0d0U, 0x2ac5efefU, 0xe54faaaaU, 0x16edfbfbU,
+ 0xc5864343U, 0xd79a4d4dU, 0x55663333U, 0x94118585U,
+ 0xcf8a4545U, 0x10e9f9f9U, 0x06040202U, 0x81fe7f7fU,
+ 0xf0a05050U, 0x44783c3cU, 0xba259f9fU, 0xe34ba8a8U,
+ 0xf3a25151U, 0xfe5da3a3U, 0xc0804040U, 0x8a058f8fU,
+ 0xad3f9292U, 0xbc219d9dU, 0x48703838U, 0x04f1f5f5U,
+ 0xdf63bcbcU, 0xc177b6b6U, 0x75afdadaU, 0x63422121U,
+ 0x30201010U, 0x1ae5ffffU, 0x0efdf3f3U, 0x6dbfd2d2U,
+ 0x4c81cdcdU, 0x14180c0cU, 0x35261313U, 0x2fc3ececU,
+ 0xe1be5f5fU, 0xa2359797U, 0xcc884444U, 0x392e1717U,
+ 0x5793c4c4U, 0xf255a7a7U, 0x82fc7e7eU, 0x477a3d3dU,
+ 0xacc86464U, 0xe7ba5d5dU, 0x2b321919U, 0x95e67373U,
+ 0xa0c06060U, 0x98198181U, 0xd19e4f4fU, 0x7fa3dcdcU,
+ 0x66442222U, 0x7e542a2aU, 0xab3b9090U, 0x830b8888U,
+ 0xca8c4646U, 0x29c7eeeeU, 0xd36bb8b8U, 0x3c281414U,
+ 0x79a7dedeU, 0xe2bc5e5eU, 0x1d160b0bU, 0x76addbdbU,
+ 0x3bdbe0e0U, 0x56643232U, 0x4e743a3aU, 0x1e140a0aU,
+ 0xdb924949U, 0x0a0c0606U, 0x6c482424U, 0xe4b85c5cU,
+ 0x5d9fc2c2U, 0x6ebdd3d3U, 0xef43acacU, 0xa6c46262U,
+ 0xa8399191U, 0xa4319595U, 0x37d3e4e4U, 0x8bf27979U,
+ 0x32d5e7e7U, 0x438bc8c8U, 0x596e3737U, 0xb7da6d6dU,
+ 0x8c018d8dU, 0x64b1d5d5U, 0xd29c4e4eU, 0xe049a9a9U,
+ 0xb4d86c6cU, 0xfaac5656U, 0x07f3f4f4U, 0x25cfeaeaU,
+ 0xafca6565U, 0x8ef47a7aU, 0xe947aeaeU, 0x18100808U,
+ 0xd56fbabaU, 0x88f07878U, 0x6f4a2525U, 0x725c2e2eU,
+ 0x24381c1cU, 0xf157a6a6U, 0xc773b4b4U, 0x5197c6c6U,
+ 0x23cbe8e8U, 0x7ca1ddddU, 0x9ce87474U, 0x213e1f1fU,
+ 0xdd964b4bU, 0xdc61bdbdU, 0x860d8b8bU, 0x850f8a8aU,
+ 0x90e07070U, 0x427c3e3eU, 0xc471b5b5U, 0xaacc6666U,
+ 0xd8904848U, 0x05060303U, 0x01f7f6f6U, 0x121c0e0eU,
+ 0xa3c26161U, 0x5f6a3535U, 0xf9ae5757U, 0xd069b9b9U,
+ 0x91178686U, 0x5899c1c1U, 0x273a1d1dU, 0xb9279e9eU,
+ 0x38d9e1e1U, 0x13ebf8f8U, 0xb32b9898U, 0x33221111U,
+ 0xbbd26969U, 0x70a9d9d9U, 0x89078e8eU, 0xa7339494U,
+ 0xb62d9b9bU, 0x223c1e1eU, 0x92158787U, 0x20c9e9e9U,
+ 0x4987ceceU, 0xffaa5555U, 0x78502828U, 0x7aa5dfdfU,
+ 0x8f038c8cU, 0xf859a1a1U, 0x80098989U, 0x171a0d0dU,
+ 0xda65bfbfU, 0x31d7e6e6U, 0xc6844242U, 0xb8d06868U,
+ 0xc3824141U, 0xb0299999U, 0x775a2d2dU, 0x111e0f0fU,
+ 0xcb7bb0b0U, 0xfca85454U, 0xd66dbbbbU, 0x3a2c1616U,
+};
+static const u32 Te2[256] = {
+ 0x63a5c663U, 0x7c84f87cU, 0x7799ee77U, 0x7b8df67bU,
+ 0xf20dfff2U, 0x6bbdd66bU, 0x6fb1de6fU, 0xc55491c5U,
+ 0x30506030U, 0x01030201U, 0x67a9ce67U, 0x2b7d562bU,
+ 0xfe19e7feU, 0xd762b5d7U, 0xabe64dabU, 0x769aec76U,
+ 0xca458fcaU, 0x829d1f82U, 0xc94089c9U, 0x7d87fa7dU,
+ 0xfa15effaU, 0x59ebb259U, 0x47c98e47U, 0xf00bfbf0U,
+ 0xadec41adU, 0xd467b3d4U, 0xa2fd5fa2U, 0xafea45afU,
+ 0x9cbf239cU, 0xa4f753a4U, 0x7296e472U, 0xc05b9bc0U,
+ 0xb7c275b7U, 0xfd1ce1fdU, 0x93ae3d93U, 0x266a4c26U,
+ 0x365a6c36U, 0x3f417e3fU, 0xf702f5f7U, 0xcc4f83ccU,
+ 0x345c6834U, 0xa5f451a5U, 0xe534d1e5U, 0xf108f9f1U,
+ 0x7193e271U, 0xd873abd8U, 0x31536231U, 0x153f2a15U,
+ 0x040c0804U, 0xc75295c7U, 0x23654623U, 0xc35e9dc3U,
+ 0x18283018U, 0x96a13796U, 0x050f0a05U, 0x9ab52f9aU,
+ 0x07090e07U, 0x12362412U, 0x809b1b80U, 0xe23ddfe2U,
+ 0xeb26cdebU, 0x27694e27U, 0xb2cd7fb2U, 0x759fea75U,
+ 0x091b1209U, 0x839e1d83U, 0x2c74582cU, 0x1a2e341aU,
+ 0x1b2d361bU, 0x6eb2dc6eU, 0x5aeeb45aU, 0xa0fb5ba0U,
+ 0x52f6a452U, 0x3b4d763bU, 0xd661b7d6U, 0xb3ce7db3U,
+ 0x297b5229U, 0xe33edde3U, 0x2f715e2fU, 0x84971384U,
+ 0x53f5a653U, 0xd168b9d1U, 0x00000000U, 0xed2cc1edU,
+ 0x20604020U, 0xfc1fe3fcU, 0xb1c879b1U, 0x5bedb65bU,
+ 0x6abed46aU, 0xcb468dcbU, 0xbed967beU, 0x394b7239U,
+ 0x4ade944aU, 0x4cd4984cU, 0x58e8b058U, 0xcf4a85cfU,
+ 0xd06bbbd0U, 0xef2ac5efU, 0xaae54faaU, 0xfb16edfbU,
+ 0x43c58643U, 0x4dd79a4dU, 0x33556633U, 0x85941185U,
+ 0x45cf8a45U, 0xf910e9f9U, 0x02060402U, 0x7f81fe7fU,
+ 0x50f0a050U, 0x3c44783cU, 0x9fba259fU, 0xa8e34ba8U,
+ 0x51f3a251U, 0xa3fe5da3U, 0x40c08040U, 0x8f8a058fU,
+ 0x92ad3f92U, 0x9dbc219dU, 0x38487038U, 0xf504f1f5U,
+ 0xbcdf63bcU, 0xb6c177b6U, 0xda75afdaU, 0x21634221U,
+ 0x10302010U, 0xff1ae5ffU, 0xf30efdf3U, 0xd26dbfd2U,
+ 0xcd4c81cdU, 0x0c14180cU, 0x13352613U, 0xec2fc3ecU,
+ 0x5fe1be5fU, 0x97a23597U, 0x44cc8844U, 0x17392e17U,
+ 0xc45793c4U, 0xa7f255a7U, 0x7e82fc7eU, 0x3d477a3dU,
+ 0x64acc864U, 0x5de7ba5dU, 0x192b3219U, 0x7395e673U,
+ 0x60a0c060U, 0x81981981U, 0x4fd19e4fU, 0xdc7fa3dcU,
+ 0x22664422U, 0x2a7e542aU, 0x90ab3b90U, 0x88830b88U,
+ 0x46ca8c46U, 0xee29c7eeU, 0xb8d36bb8U, 0x143c2814U,
+ 0xde79a7deU, 0x5ee2bc5eU, 0x0b1d160bU, 0xdb76addbU,
+ 0xe03bdbe0U, 0x32566432U, 0x3a4e743aU, 0x0a1e140aU,
+ 0x49db9249U, 0x060a0c06U, 0x246c4824U, 0x5ce4b85cU,
+ 0xc25d9fc2U, 0xd36ebdd3U, 0xacef43acU, 0x62a6c462U,
+ 0x91a83991U, 0x95a43195U, 0xe437d3e4U, 0x798bf279U,
+ 0xe732d5e7U, 0xc8438bc8U, 0x37596e37U, 0x6db7da6dU,
+ 0x8d8c018dU, 0xd564b1d5U, 0x4ed29c4eU, 0xa9e049a9U,
+ 0x6cb4d86cU, 0x56faac56U, 0xf407f3f4U, 0xea25cfeaU,
+ 0x65afca65U, 0x7a8ef47aU, 0xaee947aeU, 0x08181008U,
+ 0xbad56fbaU, 0x7888f078U, 0x256f4a25U, 0x2e725c2eU,
+ 0x1c24381cU, 0xa6f157a6U, 0xb4c773b4U, 0xc65197c6U,
+ 0xe823cbe8U, 0xdd7ca1ddU, 0x749ce874U, 0x1f213e1fU,
+ 0x4bdd964bU, 0xbddc61bdU, 0x8b860d8bU, 0x8a850f8aU,
+ 0x7090e070U, 0x3e427c3eU, 0xb5c471b5U, 0x66aacc66U,
+ 0x48d89048U, 0x03050603U, 0xf601f7f6U, 0x0e121c0eU,
+ 0x61a3c261U, 0x355f6a35U, 0x57f9ae57U, 0xb9d069b9U,
+ 0x86911786U, 0xc15899c1U, 0x1d273a1dU, 0x9eb9279eU,
+ 0xe138d9e1U, 0xf813ebf8U, 0x98b32b98U, 0x11332211U,
+ 0x69bbd269U, 0xd970a9d9U, 0x8e89078eU, 0x94a73394U,
+ 0x9bb62d9bU, 0x1e223c1eU, 0x87921587U, 0xe920c9e9U,
+ 0xce4987ceU, 0x55ffaa55U, 0x28785028U, 0xdf7aa5dfU,
+ 0x8c8f038cU, 0xa1f859a1U, 0x89800989U, 0x0d171a0dU,
+ 0xbfda65bfU, 0xe631d7e6U, 0x42c68442U, 0x68b8d068U,
+ 0x41c38241U, 0x99b02999U, 0x2d775a2dU, 0x0f111e0fU,
+ 0xb0cb7bb0U, 0x54fca854U, 0xbbd66dbbU, 0x163a2c16U,
+};
+static const u32 Te3[256] = {
+
+ 0x6363a5c6U, 0x7c7c84f8U, 0x777799eeU, 0x7b7b8df6U,
+ 0xf2f20dffU, 0x6b6bbdd6U, 0x6f6fb1deU, 0xc5c55491U,
+ 0x30305060U, 0x01010302U, 0x6767a9ceU, 0x2b2b7d56U,
+ 0xfefe19e7U, 0xd7d762b5U, 0xababe64dU, 0x76769aecU,
+ 0xcaca458fU, 0x82829d1fU, 0xc9c94089U, 0x7d7d87faU,
+ 0xfafa15efU, 0x5959ebb2U, 0x4747c98eU, 0xf0f00bfbU,
+ 0xadadec41U, 0xd4d467b3U, 0xa2a2fd5fU, 0xafafea45U,
+ 0x9c9cbf23U, 0xa4a4f753U, 0x727296e4U, 0xc0c05b9bU,
+ 0xb7b7c275U, 0xfdfd1ce1U, 0x9393ae3dU, 0x26266a4cU,
+ 0x36365a6cU, 0x3f3f417eU, 0xf7f702f5U, 0xcccc4f83U,
+ 0x34345c68U, 0xa5a5f451U, 0xe5e534d1U, 0xf1f108f9U,
+ 0x717193e2U, 0xd8d873abU, 0x31315362U, 0x15153f2aU,
+ 0x04040c08U, 0xc7c75295U, 0x23236546U, 0xc3c35e9dU,
+ 0x18182830U, 0x9696a137U, 0x05050f0aU, 0x9a9ab52fU,
+ 0x0707090eU, 0x12123624U, 0x80809b1bU, 0xe2e23ddfU,
+ 0xebeb26cdU, 0x2727694eU, 0xb2b2cd7fU, 0x75759feaU,
+ 0x09091b12U, 0x83839e1dU, 0x2c2c7458U, 0x1a1a2e34U,
+ 0x1b1b2d36U, 0x6e6eb2dcU, 0x5a5aeeb4U, 0xa0a0fb5bU,
+ 0x5252f6a4U, 0x3b3b4d76U, 0xd6d661b7U, 0xb3b3ce7dU,
+ 0x29297b52U, 0xe3e33eddU, 0x2f2f715eU, 0x84849713U,
+ 0x5353f5a6U, 0xd1d168b9U, 0x00000000U, 0xeded2cc1U,
+ 0x20206040U, 0xfcfc1fe3U, 0xb1b1c879U, 0x5b5bedb6U,
+ 0x6a6abed4U, 0xcbcb468dU, 0xbebed967U, 0x39394b72U,
+ 0x4a4ade94U, 0x4c4cd498U, 0x5858e8b0U, 0xcfcf4a85U,
+ 0xd0d06bbbU, 0xefef2ac5U, 0xaaaae54fU, 0xfbfb16edU,
+ 0x4343c586U, 0x4d4dd79aU, 0x33335566U, 0x85859411U,
+ 0x4545cf8aU, 0xf9f910e9U, 0x02020604U, 0x7f7f81feU,
+ 0x5050f0a0U, 0x3c3c4478U, 0x9f9fba25U, 0xa8a8e34bU,
+ 0x5151f3a2U, 0xa3a3fe5dU, 0x4040c080U, 0x8f8f8a05U,
+ 0x9292ad3fU, 0x9d9dbc21U, 0x38384870U, 0xf5f504f1U,
+ 0xbcbcdf63U, 0xb6b6c177U, 0xdada75afU, 0x21216342U,
+ 0x10103020U, 0xffff1ae5U, 0xf3f30efdU, 0xd2d26dbfU,
+ 0xcdcd4c81U, 0x0c0c1418U, 0x13133526U, 0xecec2fc3U,
+ 0x5f5fe1beU, 0x9797a235U, 0x4444cc88U, 0x1717392eU,
+ 0xc4c45793U, 0xa7a7f255U, 0x7e7e82fcU, 0x3d3d477aU,
+ 0x6464acc8U, 0x5d5de7baU, 0x19192b32U, 0x737395e6U,
+ 0x6060a0c0U, 0x81819819U, 0x4f4fd19eU, 0xdcdc7fa3U,
+ 0x22226644U, 0x2a2a7e54U, 0x9090ab3bU, 0x8888830bU,
+ 0x4646ca8cU, 0xeeee29c7U, 0xb8b8d36bU, 0x14143c28U,
+ 0xdede79a7U, 0x5e5ee2bcU, 0x0b0b1d16U, 0xdbdb76adU,
+ 0xe0e03bdbU, 0x32325664U, 0x3a3a4e74U, 0x0a0a1e14U,
+ 0x4949db92U, 0x06060a0cU, 0x24246c48U, 0x5c5ce4b8U,
+ 0xc2c25d9fU, 0xd3d36ebdU, 0xacacef43U, 0x6262a6c4U,
+ 0x9191a839U, 0x9595a431U, 0xe4e437d3U, 0x79798bf2U,
+ 0xe7e732d5U, 0xc8c8438bU, 0x3737596eU, 0x6d6db7daU,
+ 0x8d8d8c01U, 0xd5d564b1U, 0x4e4ed29cU, 0xa9a9e049U,
+ 0x6c6cb4d8U, 0x5656faacU, 0xf4f407f3U, 0xeaea25cfU,
+ 0x6565afcaU, 0x7a7a8ef4U, 0xaeaee947U, 0x08081810U,
+ 0xbabad56fU, 0x787888f0U, 0x25256f4aU, 0x2e2e725cU,
+ 0x1c1c2438U, 0xa6a6f157U, 0xb4b4c773U, 0xc6c65197U,
+ 0xe8e823cbU, 0xdddd7ca1U, 0x74749ce8U, 0x1f1f213eU,
+ 0x4b4bdd96U, 0xbdbddc61U, 0x8b8b860dU, 0x8a8a850fU,
+ 0x707090e0U, 0x3e3e427cU, 0xb5b5c471U, 0x6666aaccU,
+ 0x4848d890U, 0x03030506U, 0xf6f601f7U, 0x0e0e121cU,
+ 0x6161a3c2U, 0x35355f6aU, 0x5757f9aeU, 0xb9b9d069U,
+ 0x86869117U, 0xc1c15899U, 0x1d1d273aU, 0x9e9eb927U,
+ 0xe1e138d9U, 0xf8f813ebU, 0x9898b32bU, 0x11113322U,
+ 0x6969bbd2U, 0xd9d970a9U, 0x8e8e8907U, 0x9494a733U,
+ 0x9b9bb62dU, 0x1e1e223cU, 0x87879215U, 0xe9e920c9U,
+ 0xcece4987U, 0x5555ffaaU, 0x28287850U, 0xdfdf7aa5U,
+ 0x8c8c8f03U, 0xa1a1f859U, 0x89898009U, 0x0d0d171aU,
+ 0xbfbfda65U, 0xe6e631d7U, 0x4242c684U, 0x6868b8d0U,
+ 0x4141c382U, 0x9999b029U, 0x2d2d775aU, 0x0f0f111eU,
+ 0xb0b0cb7bU, 0x5454fca8U, 0xbbbbd66dU, 0x16163a2cU,
+};
+static const u8 Te4[256] = {
+ 0x63U, 0x7cU, 0x77U, 0x7bU,
+ 0xf2U, 0x6bU, 0x6fU, 0xc5U,
+ 0x30U, 0x01U, 0x67U, 0x2bU,
+ 0xfeU, 0xd7U, 0xabU, 0x76U,
+ 0xcaU, 0x82U, 0xc9U, 0x7dU,
+ 0xfaU, 0x59U, 0x47U, 0xf0U,
+ 0xadU, 0xd4U, 0xa2U, 0xafU,
+ 0x9cU, 0xa4U, 0x72U, 0xc0U,
+ 0xb7U, 0xfdU, 0x93U, 0x26U,
+ 0x36U, 0x3fU, 0xf7U, 0xccU,
+ 0x34U, 0xa5U, 0xe5U, 0xf1U,
+ 0x71U, 0xd8U, 0x31U, 0x15U,
+ 0x04U, 0xc7U, 0x23U, 0xc3U,
+ 0x18U, 0x96U, 0x05U, 0x9aU,
+ 0x07U, 0x12U, 0x80U, 0xe2U,
+ 0xebU, 0x27U, 0xb2U, 0x75U,
+ 0x09U, 0x83U, 0x2cU, 0x1aU,
+ 0x1bU, 0x6eU, 0x5aU, 0xa0U,
+ 0x52U, 0x3bU, 0xd6U, 0xb3U,
+ 0x29U, 0xe3U, 0x2fU, 0x84U,
+ 0x53U, 0xd1U, 0x00U, 0xedU,
+ 0x20U, 0xfcU, 0xb1U, 0x5bU,
+ 0x6aU, 0xcbU, 0xbeU, 0x39U,
+ 0x4aU, 0x4cU, 0x58U, 0xcfU,
+ 0xd0U, 0xefU, 0xaaU, 0xfbU,
+ 0x43U, 0x4dU, 0x33U, 0x85U,
+ 0x45U, 0xf9U, 0x02U, 0x7fU,
+ 0x50U, 0x3cU, 0x9fU, 0xa8U,
+ 0x51U, 0xa3U, 0x40U, 0x8fU,
+ 0x92U, 0x9dU, 0x38U, 0xf5U,
+ 0xbcU, 0xb6U, 0xdaU, 0x21U,
+ 0x10U, 0xffU, 0xf3U, 0xd2U,
+ 0xcdU, 0x0cU, 0x13U, 0xecU,
+ 0x5fU, 0x97U, 0x44U, 0x17U,
+ 0xc4U, 0xa7U, 0x7eU, 0x3dU,
+ 0x64U, 0x5dU, 0x19U, 0x73U,
+ 0x60U, 0x81U, 0x4fU, 0xdcU,
+ 0x22U, 0x2aU, 0x90U, 0x88U,
+ 0x46U, 0xeeU, 0xb8U, 0x14U,
+ 0xdeU, 0x5eU, 0x0bU, 0xdbU,
+ 0xe0U, 0x32U, 0x3aU, 0x0aU,
+ 0x49U, 0x06U, 0x24U, 0x5cU,
+ 0xc2U, 0xd3U, 0xacU, 0x62U,
+ 0x91U, 0x95U, 0xe4U, 0x79U,
+ 0xe7U, 0xc8U, 0x37U, 0x6dU,
+ 0x8dU, 0xd5U, 0x4eU, 0xa9U,
+ 0x6cU, 0x56U, 0xf4U, 0xeaU,
+ 0x65U, 0x7aU, 0xaeU, 0x08U,
+ 0xbaU, 0x78U, 0x25U, 0x2eU,
+ 0x1cU, 0xa6U, 0xb4U, 0xc6U,
+ 0xe8U, 0xddU, 0x74U, 0x1fU,
+ 0x4bU, 0xbdU, 0x8bU, 0x8aU,
+ 0x70U, 0x3eU, 0xb5U, 0x66U,
+ 0x48U, 0x03U, 0xf6U, 0x0eU,
+ 0x61U, 0x35U, 0x57U, 0xb9U,
+ 0x86U, 0xc1U, 0x1dU, 0x9eU,
+ 0xe1U, 0xf8U, 0x98U, 0x11U,
+ 0x69U, 0xd9U, 0x8eU, 0x94U,
+ 0x9bU, 0x1eU, 0x87U, 0xe9U,
+ 0xceU, 0x55U, 0x28U, 0xdfU,
+ 0x8cU, 0xa1U, 0x89U, 0x0dU,
+ 0xbfU, 0xe6U, 0x42U, 0x68U,
+ 0x41U, 0x99U, 0x2dU, 0x0fU,
+ 0xb0U, 0x54U, 0xbbU, 0x16U,
+};
+static const u32 Td0[256] = {
+ 0x51f4a750U, 0x7e416553U, 0x1a17a4c3U, 0x3a275e96U,
+ 0x3bab6bcbU, 0x1f9d45f1U, 0xacfa58abU, 0x4be30393U,
+ 0x2030fa55U, 0xad766df6U, 0x88cc7691U, 0xf5024c25U,
+ 0x4fe5d7fcU, 0xc52acbd7U, 0x26354480U, 0xb562a38fU,
+ 0xdeb15a49U, 0x25ba1b67U, 0x45ea0e98U, 0x5dfec0e1U,
+ 0xc32f7502U, 0x814cf012U, 0x8d4697a3U, 0x6bd3f9c6U,
+ 0x038f5fe7U, 0x15929c95U, 0xbf6d7aebU, 0x955259daU,
+ 0xd4be832dU, 0x587421d3U, 0x49e06929U, 0x8ec9c844U,
+ 0x75c2896aU, 0xf48e7978U, 0x99583e6bU, 0x27b971ddU,
+ 0xbee14fb6U, 0xf088ad17U, 0xc920ac66U, 0x7dce3ab4U,
+ 0x63df4a18U, 0xe51a3182U, 0x97513360U, 0x62537f45U,
+ 0xb16477e0U, 0xbb6bae84U, 0xfe81a01cU, 0xf9082b94U,
+ 0x70486858U, 0x8f45fd19U, 0x94de6c87U, 0x527bf8b7U,
+ 0xab73d323U, 0x724b02e2U, 0xe31f8f57U, 0x6655ab2aU,
+ 0xb2eb2807U, 0x2fb5c203U, 0x86c57b9aU, 0xd33708a5U,
+ 0x302887f2U, 0x23bfa5b2U, 0x02036abaU, 0xed16825cU,
+ 0x8acf1c2bU, 0xa779b492U, 0xf307f2f0U, 0x4e69e2a1U,
+ 0x65daf4cdU, 0x0605bed5U, 0xd134621fU, 0xc4a6fe8aU,
+ 0x342e539dU, 0xa2f355a0U, 0x058ae132U, 0xa4f6eb75U,
+ 0x0b83ec39U, 0x4060efaaU, 0x5e719f06U, 0xbd6e1051U,
+ 0x3e218af9U, 0x96dd063dU, 0xdd3e05aeU, 0x4de6bd46U,
+ 0x91548db5U, 0x71c45d05U, 0x0406d46fU, 0x605015ffU,
+ 0x1998fb24U, 0xd6bde997U, 0x894043ccU, 0x67d99e77U,
+ 0xb0e842bdU, 0x07898b88U, 0xe7195b38U, 0x79c8eedbU,
+ 0xa17c0a47U, 0x7c420fe9U, 0xf8841ec9U, 0x00000000U,
+ 0x09808683U, 0x322bed48U, 0x1e1170acU, 0x6c5a724eU,
+ 0xfd0efffbU, 0x0f853856U, 0x3daed51eU, 0x362d3927U,
+ 0x0a0fd964U, 0x685ca621U, 0x9b5b54d1U, 0x24362e3aU,
+ 0x0c0a67b1U, 0x9357e70fU, 0xb4ee96d2U, 0x1b9b919eU,
+ 0x80c0c54fU, 0x61dc20a2U, 0x5a774b69U, 0x1c121a16U,
+ 0xe293ba0aU, 0xc0a02ae5U, 0x3c22e043U, 0x121b171dU,
+ 0x0e090d0bU, 0xf28bc7adU, 0x2db6a8b9U, 0x141ea9c8U,
+ 0x57f11985U, 0xaf75074cU, 0xee99ddbbU, 0xa37f60fdU,
+ 0xf701269fU, 0x5c72f5bcU, 0x44663bc5U, 0x5bfb7e34U,
+ 0x8b432976U, 0xcb23c6dcU, 0xb6edfc68U, 0xb8e4f163U,
+ 0xd731dccaU, 0x42638510U, 0x13972240U, 0x84c61120U,
+ 0x854a247dU, 0xd2bb3df8U, 0xaef93211U, 0xc729a16dU,
+ 0x1d9e2f4bU, 0xdcb230f3U, 0x0d8652ecU, 0x77c1e3d0U,
+ 0x2bb3166cU, 0xa970b999U, 0x119448faU, 0x47e96422U,
+ 0xa8fc8cc4U, 0xa0f03f1aU, 0x567d2cd8U, 0x223390efU,
+ 0x87494ec7U, 0xd938d1c1U, 0x8ccaa2feU, 0x98d40b36U,
+ 0xa6f581cfU, 0xa57ade28U, 0xdab78e26U, 0x3fadbfa4U,
+ 0x2c3a9de4U, 0x5078920dU, 0x6a5fcc9bU, 0x547e4662U,
+ 0xf68d13c2U, 0x90d8b8e8U, 0x2e39f75eU, 0x82c3aff5U,
+ 0x9f5d80beU, 0x69d0937cU, 0x6fd52da9U, 0xcf2512b3U,
+ 0xc8ac993bU, 0x10187da7U, 0xe89c636eU, 0xdb3bbb7bU,
+ 0xcd267809U, 0x6e5918f4U, 0xec9ab701U, 0x834f9aa8U,
+ 0xe6956e65U, 0xaaffe67eU, 0x21bccf08U, 0xef15e8e6U,
+ 0xbae79bd9U, 0x4a6f36ceU, 0xea9f09d4U, 0x29b07cd6U,
+ 0x31a4b2afU, 0x2a3f2331U, 0xc6a59430U, 0x35a266c0U,
+ 0x744ebc37U, 0xfc82caa6U, 0xe090d0b0U, 0x33a7d815U,
+ 0xf104984aU, 0x41ecdaf7U, 0x7fcd500eU, 0x1791f62fU,
+ 0x764dd68dU, 0x43efb04dU, 0xccaa4d54U, 0xe49604dfU,
+ 0x9ed1b5e3U, 0x4c6a881bU, 0xc12c1fb8U, 0x4665517fU,
+ 0x9d5eea04U, 0x018c355dU, 0xfa877473U, 0xfb0b412eU,
+ 0xb3671d5aU, 0x92dbd252U, 0xe9105633U, 0x6dd64713U,
+ 0x9ad7618cU, 0x37a10c7aU, 0x59f8148eU, 0xeb133c89U,
+ 0xcea927eeU, 0xb761c935U, 0xe11ce5edU, 0x7a47b13cU,
+ 0x9cd2df59U, 0x55f2733fU, 0x1814ce79U, 0x73c737bfU,
+ 0x53f7cdeaU, 0x5ffdaa5bU, 0xdf3d6f14U, 0x7844db86U,
+ 0xcaaff381U, 0xb968c43eU, 0x3824342cU, 0xc2a3405fU,
+ 0x161dc372U, 0xbce2250cU, 0x283c498bU, 0xff0d9541U,
+ 0x39a80171U, 0x080cb3deU, 0xd8b4e49cU, 0x6456c190U,
+ 0x7bcb8461U, 0xd532b670U, 0x486c5c74U, 0xd0b85742U,
+};
+static const u32 Td1[256] = {
+ 0x5051f4a7U, 0x537e4165U, 0xc31a17a4U, 0x963a275eU,
+ 0xcb3bab6bU, 0xf11f9d45U, 0xabacfa58U, 0x934be303U,
+ 0x552030faU, 0xf6ad766dU, 0x9188cc76U, 0x25f5024cU,
+ 0xfc4fe5d7U, 0xd7c52acbU, 0x80263544U, 0x8fb562a3U,
+ 0x49deb15aU, 0x6725ba1bU, 0x9845ea0eU, 0xe15dfec0U,
+ 0x02c32f75U, 0x12814cf0U, 0xa38d4697U, 0xc66bd3f9U,
+ 0xe7038f5fU, 0x9515929cU, 0xebbf6d7aU, 0xda955259U,
+ 0x2dd4be83U, 0xd3587421U, 0x2949e069U, 0x448ec9c8U,
+ 0x6a75c289U, 0x78f48e79U, 0x6b99583eU, 0xdd27b971U,
+ 0xb6bee14fU, 0x17f088adU, 0x66c920acU, 0xb47dce3aU,
+ 0x1863df4aU, 0x82e51a31U, 0x60975133U, 0x4562537fU,
+ 0xe0b16477U, 0x84bb6baeU, 0x1cfe81a0U, 0x94f9082bU,
+ 0x58704868U, 0x198f45fdU, 0x8794de6cU, 0xb7527bf8U,
+ 0x23ab73d3U, 0xe2724b02U, 0x57e31f8fU, 0x2a6655abU,
+ 0x07b2eb28U, 0x032fb5c2U, 0x9a86c57bU, 0xa5d33708U,
+ 0xf2302887U, 0xb223bfa5U, 0xba02036aU, 0x5ced1682U,
+ 0x2b8acf1cU, 0x92a779b4U, 0xf0f307f2U, 0xa14e69e2U,
+ 0xcd65daf4U, 0xd50605beU, 0x1fd13462U, 0x8ac4a6feU,
+ 0x9d342e53U, 0xa0a2f355U, 0x32058ae1U, 0x75a4f6ebU,
+ 0x390b83ecU, 0xaa4060efU, 0x065e719fU, 0x51bd6e10U,
+ 0xf93e218aU, 0x3d96dd06U, 0xaedd3e05U, 0x464de6bdU,
+ 0xb591548dU, 0x0571c45dU, 0x6f0406d4U, 0xff605015U,
+ 0x241998fbU, 0x97d6bde9U, 0xcc894043U, 0x7767d99eU,
+ 0xbdb0e842U, 0x8807898bU, 0x38e7195bU, 0xdb79c8eeU,
+ 0x47a17c0aU, 0xe97c420fU, 0xc9f8841eU, 0x00000000U,
+ 0x83098086U, 0x48322bedU, 0xac1e1170U, 0x4e6c5a72U,
+ 0xfbfd0effU, 0x560f8538U, 0x1e3daed5U, 0x27362d39U,
+ 0x640a0fd9U, 0x21685ca6U, 0xd19b5b54U, 0x3a24362eU,
+ 0xb10c0a67U, 0x0f9357e7U, 0xd2b4ee96U, 0x9e1b9b91U,
+ 0x4f80c0c5U, 0xa261dc20U, 0x695a774bU, 0x161c121aU,
+ 0x0ae293baU, 0xe5c0a02aU, 0x433c22e0U, 0x1d121b17U,
+ 0x0b0e090dU, 0xadf28bc7U, 0xb92db6a8U, 0xc8141ea9U,
+ 0x8557f119U, 0x4caf7507U, 0xbbee99ddU, 0xfda37f60U,
+ 0x9ff70126U, 0xbc5c72f5U, 0xc544663bU, 0x345bfb7eU,
+ 0x768b4329U, 0xdccb23c6U, 0x68b6edfcU, 0x63b8e4f1U,
+ 0xcad731dcU, 0x10426385U, 0x40139722U, 0x2084c611U,
+ 0x7d854a24U, 0xf8d2bb3dU, 0x11aef932U, 0x6dc729a1U,
+ 0x4b1d9e2fU, 0xf3dcb230U, 0xec0d8652U, 0xd077c1e3U,
+ 0x6c2bb316U, 0x99a970b9U, 0xfa119448U, 0x2247e964U,
+ 0xc4a8fc8cU, 0x1aa0f03fU, 0xd8567d2cU, 0xef223390U,
+ 0xc787494eU, 0xc1d938d1U, 0xfe8ccaa2U, 0x3698d40bU,
+ 0xcfa6f581U, 0x28a57adeU, 0x26dab78eU, 0xa43fadbfU,
+ 0xe42c3a9dU, 0x0d507892U, 0x9b6a5fccU, 0x62547e46U,
+ 0xc2f68d13U, 0xe890d8b8U, 0x5e2e39f7U, 0xf582c3afU,
+ 0xbe9f5d80U, 0x7c69d093U, 0xa96fd52dU, 0xb3cf2512U,
+ 0x3bc8ac99U, 0xa710187dU, 0x6ee89c63U, 0x7bdb3bbbU,
+ 0x09cd2678U, 0xf46e5918U, 0x01ec9ab7U, 0xa8834f9aU,
+ 0x65e6956eU, 0x7eaaffe6U, 0x0821bccfU, 0xe6ef15e8U,
+ 0xd9bae79bU, 0xce4a6f36U, 0xd4ea9f09U, 0xd629b07cU,
+ 0xaf31a4b2U, 0x312a3f23U, 0x30c6a594U, 0xc035a266U,
+ 0x37744ebcU, 0xa6fc82caU, 0xb0e090d0U, 0x1533a7d8U,
+ 0x4af10498U, 0xf741ecdaU, 0x0e7fcd50U, 0x2f1791f6U,
+ 0x8d764dd6U, 0x4d43efb0U, 0x54ccaa4dU, 0xdfe49604U,
+ 0xe39ed1b5U, 0x1b4c6a88U, 0xb8c12c1fU, 0x7f466551U,
+ 0x049d5eeaU, 0x5d018c35U, 0x73fa8774U, 0x2efb0b41U,
+ 0x5ab3671dU, 0x5292dbd2U, 0x33e91056U, 0x136dd647U,
+ 0x8c9ad761U, 0x7a37a10cU, 0x8e59f814U, 0x89eb133cU,
+ 0xeecea927U, 0x35b761c9U, 0xede11ce5U, 0x3c7a47b1U,
+ 0x599cd2dfU, 0x3f55f273U, 0x791814ceU, 0xbf73c737U,
+ 0xea53f7cdU, 0x5b5ffdaaU, 0x14df3d6fU, 0x867844dbU,
+ 0x81caaff3U, 0x3eb968c4U, 0x2c382434U, 0x5fc2a340U,
+ 0x72161dc3U, 0x0cbce225U, 0x8b283c49U, 0x41ff0d95U,
+ 0x7139a801U, 0xde080cb3U, 0x9cd8b4e4U, 0x906456c1U,
+ 0x617bcb84U, 0x70d532b6U, 0x74486c5cU, 0x42d0b857U,
+};
+static const u32 Td2[256] = {
+ 0xa75051f4U, 0x65537e41U, 0xa4c31a17U, 0x5e963a27U,
+ 0x6bcb3babU, 0x45f11f9dU, 0x58abacfaU, 0x03934be3U,
+ 0xfa552030U, 0x6df6ad76U, 0x769188ccU, 0x4c25f502U,
+ 0xd7fc4fe5U, 0xcbd7c52aU, 0x44802635U, 0xa38fb562U,
+ 0x5a49deb1U, 0x1b6725baU, 0x0e9845eaU, 0xc0e15dfeU,
+ 0x7502c32fU, 0xf012814cU, 0x97a38d46U, 0xf9c66bd3U,
+ 0x5fe7038fU, 0x9c951592U, 0x7aebbf6dU, 0x59da9552U,
+ 0x832dd4beU, 0x21d35874U, 0x692949e0U, 0xc8448ec9U,
+ 0x896a75c2U, 0x7978f48eU, 0x3e6b9958U, 0x71dd27b9U,
+ 0x4fb6bee1U, 0xad17f088U, 0xac66c920U, 0x3ab47dceU,
+ 0x4a1863dfU, 0x3182e51aU, 0x33609751U, 0x7f456253U,
+ 0x77e0b164U, 0xae84bb6bU, 0xa01cfe81U, 0x2b94f908U,
+ 0x68587048U, 0xfd198f45U, 0x6c8794deU, 0xf8b7527bU,
+ 0xd323ab73U, 0x02e2724bU, 0x8f57e31fU, 0xab2a6655U,
+ 0x2807b2ebU, 0xc2032fb5U, 0x7b9a86c5U, 0x08a5d337U,
+ 0x87f23028U, 0xa5b223bfU, 0x6aba0203U, 0x825ced16U,
+ 0x1c2b8acfU, 0xb492a779U, 0xf2f0f307U, 0xe2a14e69U,
+ 0xf4cd65daU, 0xbed50605U, 0x621fd134U, 0xfe8ac4a6U,
+ 0x539d342eU, 0x55a0a2f3U, 0xe132058aU, 0xeb75a4f6U,
+ 0xec390b83U, 0xefaa4060U, 0x9f065e71U, 0x1051bd6eU,
+
+ 0x8af93e21U, 0x063d96ddU, 0x05aedd3eU, 0xbd464de6U,
+ 0x8db59154U, 0x5d0571c4U, 0xd46f0406U, 0x15ff6050U,
+ 0xfb241998U, 0xe997d6bdU, 0x43cc8940U, 0x9e7767d9U,
+ 0x42bdb0e8U, 0x8b880789U, 0x5b38e719U, 0xeedb79c8U,
+ 0x0a47a17cU, 0x0fe97c42U, 0x1ec9f884U, 0x00000000U,
+ 0x86830980U, 0xed48322bU, 0x70ac1e11U, 0x724e6c5aU,
+ 0xfffbfd0eU, 0x38560f85U, 0xd51e3daeU, 0x3927362dU,
+ 0xd9640a0fU, 0xa621685cU, 0x54d19b5bU, 0x2e3a2436U,
+ 0x67b10c0aU, 0xe70f9357U, 0x96d2b4eeU, 0x919e1b9bU,
+ 0xc54f80c0U, 0x20a261dcU, 0x4b695a77U, 0x1a161c12U,
+ 0xba0ae293U, 0x2ae5c0a0U, 0xe0433c22U, 0x171d121bU,
+ 0x0d0b0e09U, 0xc7adf28bU, 0xa8b92db6U, 0xa9c8141eU,
+ 0x198557f1U, 0x074caf75U, 0xddbbee99U, 0x60fda37fU,
+ 0x269ff701U, 0xf5bc5c72U, 0x3bc54466U, 0x7e345bfbU,
+ 0x29768b43U, 0xc6dccb23U, 0xfc68b6edU, 0xf163b8e4U,
+ 0xdccad731U, 0x85104263U, 0x22401397U, 0x112084c6U,
+ 0x247d854aU, 0x3df8d2bbU, 0x3211aef9U, 0xa16dc729U,
+ 0x2f4b1d9eU, 0x30f3dcb2U, 0x52ec0d86U, 0xe3d077c1U,
+ 0x166c2bb3U, 0xb999a970U, 0x48fa1194U, 0x642247e9U,
+ 0x8cc4a8fcU, 0x3f1aa0f0U, 0x2cd8567dU, 0x90ef2233U,
+ 0x4ec78749U, 0xd1c1d938U, 0xa2fe8ccaU, 0x0b3698d4U,
+ 0x81cfa6f5U, 0xde28a57aU, 0x8e26dab7U, 0xbfa43fadU,
+ 0x9de42c3aU, 0x920d5078U, 0xcc9b6a5fU, 0x4662547eU,
+ 0x13c2f68dU, 0xb8e890d8U, 0xf75e2e39U, 0xaff582c3U,
+ 0x80be9f5dU, 0x937c69d0U, 0x2da96fd5U, 0x12b3cf25U,
+ 0x993bc8acU, 0x7da71018U, 0x636ee89cU, 0xbb7bdb3bU,
+ 0x7809cd26U, 0x18f46e59U, 0xb701ec9aU, 0x9aa8834fU,
+ 0x6e65e695U, 0xe67eaaffU, 0xcf0821bcU, 0xe8e6ef15U,
+ 0x9bd9bae7U, 0x36ce4a6fU, 0x09d4ea9fU, 0x7cd629b0U,
+ 0xb2af31a4U, 0x23312a3fU, 0x9430c6a5U, 0x66c035a2U,
+ 0xbc37744eU, 0xcaa6fc82U, 0xd0b0e090U, 0xd81533a7U,
+ 0x984af104U, 0xdaf741ecU, 0x500e7fcdU, 0xf62f1791U,
+ 0xd68d764dU, 0xb04d43efU, 0x4d54ccaaU, 0x04dfe496U,
+ 0xb5e39ed1U, 0x881b4c6aU, 0x1fb8c12cU, 0x517f4665U,
+ 0xea049d5eU, 0x355d018cU, 0x7473fa87U, 0x412efb0bU,
+ 0x1d5ab367U, 0xd25292dbU, 0x5633e910U, 0x47136dd6U,
+ 0x618c9ad7U, 0x0c7a37a1U, 0x148e59f8U, 0x3c89eb13U,
+ 0x27eecea9U, 0xc935b761U, 0xe5ede11cU, 0xb13c7a47U,
+ 0xdf599cd2U, 0x733f55f2U, 0xce791814U, 0x37bf73c7U,
+ 0xcdea53f7U, 0xaa5b5ffdU, 0x6f14df3dU, 0xdb867844U,
+ 0xf381caafU, 0xc43eb968U, 0x342c3824U, 0x405fc2a3U,
+ 0xc372161dU, 0x250cbce2U, 0x498b283cU, 0x9541ff0dU,
+ 0x017139a8U, 0xb3de080cU, 0xe49cd8b4U, 0xc1906456U,
+ 0x84617bcbU, 0xb670d532U, 0x5c74486cU, 0x5742d0b8U,
+};
+static const u32 Td3[256] = {
+ 0xf4a75051U, 0x4165537eU, 0x17a4c31aU, 0x275e963aU,
+ 0xab6bcb3bU, 0x9d45f11fU, 0xfa58abacU, 0xe303934bU,
+ 0x30fa5520U, 0x766df6adU, 0xcc769188U, 0x024c25f5U,
+ 0xe5d7fc4fU, 0x2acbd7c5U, 0x35448026U, 0x62a38fb5U,
+ 0xb15a49deU, 0xba1b6725U, 0xea0e9845U, 0xfec0e15dU,
+ 0x2f7502c3U, 0x4cf01281U, 0x4697a38dU, 0xd3f9c66bU,
+ 0x8f5fe703U, 0x929c9515U, 0x6d7aebbfU, 0x5259da95U,
+ 0xbe832dd4U, 0x7421d358U, 0xe0692949U, 0xc9c8448eU,
+ 0xc2896a75U, 0x8e7978f4U, 0x583e6b99U, 0xb971dd27U,
+ 0xe14fb6beU, 0x88ad17f0U, 0x20ac66c9U, 0xce3ab47dU,
+ 0xdf4a1863U, 0x1a3182e5U, 0x51336097U, 0x537f4562U,
+ 0x6477e0b1U, 0x6bae84bbU, 0x81a01cfeU, 0x082b94f9U,
+ 0x48685870U, 0x45fd198fU, 0xde6c8794U, 0x7bf8b752U,
+ 0x73d323abU, 0x4b02e272U, 0x1f8f57e3U, 0x55ab2a66U,
+ 0xeb2807b2U, 0xb5c2032fU, 0xc57b9a86U, 0x3708a5d3U,
+ 0x2887f230U, 0xbfa5b223U, 0x036aba02U, 0x16825cedU,
+ 0xcf1c2b8aU, 0x79b492a7U, 0x07f2f0f3U, 0x69e2a14eU,
+ 0xdaf4cd65U, 0x05bed506U, 0x34621fd1U, 0xa6fe8ac4U,
+ 0x2e539d34U, 0xf355a0a2U, 0x8ae13205U, 0xf6eb75a4U,
+ 0x83ec390bU, 0x60efaa40U, 0x719f065eU, 0x6e1051bdU,
+ 0x218af93eU, 0xdd063d96U, 0x3e05aeddU, 0xe6bd464dU,
+ 0x548db591U, 0xc45d0571U, 0x06d46f04U, 0x5015ff60U,
+ 0x98fb2419U, 0xbde997d6U, 0x4043cc89U, 0xd99e7767U,
+ 0xe842bdb0U, 0x898b8807U, 0x195b38e7U, 0xc8eedb79U,
+ 0x7c0a47a1U, 0x420fe97cU, 0x841ec9f8U, 0x00000000U,
+ 0x80868309U, 0x2bed4832U, 0x1170ac1eU, 0x5a724e6cU,
+ 0x0efffbfdU, 0x8538560fU, 0xaed51e3dU, 0x2d392736U,
+ 0x0fd9640aU, 0x5ca62168U, 0x5b54d19bU, 0x362e3a24U,
+ 0x0a67b10cU, 0x57e70f93U, 0xee96d2b4U, 0x9b919e1bU,
+ 0xc0c54f80U, 0xdc20a261U, 0x774b695aU, 0x121a161cU,
+ 0x93ba0ae2U, 0xa02ae5c0U, 0x22e0433cU, 0x1b171d12U,
+ 0x090d0b0eU, 0x8bc7adf2U, 0xb6a8b92dU, 0x1ea9c814U,
+ 0xf1198557U, 0x75074cafU, 0x99ddbbeeU, 0x7f60fda3U,
+ 0x01269ff7U, 0x72f5bc5cU, 0x663bc544U, 0xfb7e345bU,
+ 0x4329768bU, 0x23c6dccbU, 0xedfc68b6U, 0xe4f163b8U,
+ 0x31dccad7U, 0x63851042U, 0x97224013U, 0xc6112084U,
+ 0x4a247d85U, 0xbb3df8d2U, 0xf93211aeU, 0x29a16dc7U,
+ 0x9e2f4b1dU, 0xb230f3dcU, 0x8652ec0dU, 0xc1e3d077U,
+ 0xb3166c2bU, 0x70b999a9U, 0x9448fa11U, 0xe9642247U,
+ 0xfc8cc4a8U, 0xf03f1aa0U, 0x7d2cd856U, 0x3390ef22U,
+ 0x494ec787U, 0x38d1c1d9U, 0xcaa2fe8cU, 0xd40b3698U,
+ 0xf581cfa6U, 0x7ade28a5U, 0xb78e26daU, 0xadbfa43fU,
+ 0x3a9de42cU, 0x78920d50U, 0x5fcc9b6aU, 0x7e466254U,
+ 0x8d13c2f6U, 0xd8b8e890U, 0x39f75e2eU, 0xc3aff582U,
+ 0x5d80be9fU, 0xd0937c69U, 0xd52da96fU, 0x2512b3cfU,
+ 0xac993bc8U, 0x187da710U, 0x9c636ee8U, 0x3bbb7bdbU,
+ 0x267809cdU, 0x5918f46eU, 0x9ab701ecU, 0x4f9aa883U,
+ 0x956e65e6U, 0xffe67eaaU, 0xbccf0821U, 0x15e8e6efU,
+ 0xe79bd9baU, 0x6f36ce4aU, 0x9f09d4eaU, 0xb07cd629U,
+ 0xa4b2af31U, 0x3f23312aU, 0xa59430c6U, 0xa266c035U,
+ 0x4ebc3774U, 0x82caa6fcU, 0x90d0b0e0U, 0xa7d81533U,
+ 0x04984af1U, 0xecdaf741U, 0xcd500e7fU, 0x91f62f17U,
+ 0x4dd68d76U, 0xefb04d43U, 0xaa4d54ccU, 0x9604dfe4U,
+ 0xd1b5e39eU, 0x6a881b4cU, 0x2c1fb8c1U, 0x65517f46U,
+ 0x5eea049dU, 0x8c355d01U, 0x877473faU, 0x0b412efbU,
+ 0x671d5ab3U, 0xdbd25292U, 0x105633e9U, 0xd647136dU,
+ 0xd7618c9aU, 0xa10c7a37U, 0xf8148e59U, 0x133c89ebU,
+ 0xa927eeceU, 0x61c935b7U, 0x1ce5ede1U, 0x47b13c7aU,
+ 0xd2df599cU, 0xf2733f55U, 0x14ce7918U, 0xc737bf73U,
+ 0xf7cdea53U, 0xfdaa5b5fU, 0x3d6f14dfU, 0x44db8678U,
+ 0xaff381caU, 0x68c43eb9U, 0x24342c38U, 0xa3405fc2U,
+ 0x1dc37216U, 0xe2250cbcU, 0x3c498b28U, 0x0d9541ffU,
+ 0xa8017139U, 0x0cb3de08U, 0xb4e49cd8U, 0x56c19064U,
+ 0xcb84617bU, 0x32b670d5U, 0x6c5c7448U, 0xb85742d0U,
+};
+static const u8 Td4[256] = {
+ 0x52U, 0x09U, 0x6aU, 0xd5U,
+ 0x30U, 0x36U, 0xa5U, 0x38U,
+ 0xbfU, 0x40U, 0xa3U, 0x9eU,
+ 0x81U, 0xf3U, 0xd7U, 0xfbU,
+ 0x7cU, 0xe3U, 0x39U, 0x82U,
+ 0x9bU, 0x2fU, 0xffU, 0x87U,
+ 0x34U, 0x8eU, 0x43U, 0x44U,
+ 0xc4U, 0xdeU, 0xe9U, 0xcbU,
+ 0x54U, 0x7bU, 0x94U, 0x32U,
+ 0xa6U, 0xc2U, 0x23U, 0x3dU,
+ 0xeeU, 0x4cU, 0x95U, 0x0bU,
+ 0x42U, 0xfaU, 0xc3U, 0x4eU,
+ 0x08U, 0x2eU, 0xa1U, 0x66U,
+ 0x28U, 0xd9U, 0x24U, 0xb2U,
+ 0x76U, 0x5bU, 0xa2U, 0x49U,
+ 0x6dU, 0x8bU, 0xd1U, 0x25U,
+ 0x72U, 0xf8U, 0xf6U, 0x64U,
+ 0x86U, 0x68U, 0x98U, 0x16U,
+ 0xd4U, 0xa4U, 0x5cU, 0xccU,
+ 0x5dU, 0x65U, 0xb6U, 0x92U,
+ 0x6cU, 0x70U, 0x48U, 0x50U,
+ 0xfdU, 0xedU, 0xb9U, 0xdaU,
+ 0x5eU, 0x15U, 0x46U, 0x57U,
+ 0xa7U, 0x8dU, 0x9dU, 0x84U,
+ 0x90U, 0xd8U, 0xabU, 0x00U,
+ 0x8cU, 0xbcU, 0xd3U, 0x0aU,
+ 0xf7U, 0xe4U, 0x58U, 0x05U,
+ 0xb8U, 0xb3U, 0x45U, 0x06U,
+ 0xd0U, 0x2cU, 0x1eU, 0x8fU,
+ 0xcaU, 0x3fU, 0x0fU, 0x02U,
+ 0xc1U, 0xafU, 0xbdU, 0x03U,
+ 0x01U, 0x13U, 0x8aU, 0x6bU,
+ 0x3aU, 0x91U, 0x11U, 0x41U,
+ 0x4fU, 0x67U, 0xdcU, 0xeaU,
+ 0x97U, 0xf2U, 0xcfU, 0xceU,
+ 0xf0U, 0xb4U, 0xe6U, 0x73U,
+ 0x96U, 0xacU, 0x74U, 0x22U,
+ 0xe7U, 0xadU, 0x35U, 0x85U,
+ 0xe2U, 0xf9U, 0x37U, 0xe8U,
+ 0x1cU, 0x75U, 0xdfU, 0x6eU,
+ 0x47U, 0xf1U, 0x1aU, 0x71U,
+ 0x1dU, 0x29U, 0xc5U, 0x89U,
+ 0x6fU, 0xb7U, 0x62U, 0x0eU,
+ 0xaaU, 0x18U, 0xbeU, 0x1bU,
+ 0xfcU, 0x56U, 0x3eU, 0x4bU,
+ 0xc6U, 0xd2U, 0x79U, 0x20U,
+ 0x9aU, 0xdbU, 0xc0U, 0xfeU,
+ 0x78U, 0xcdU, 0x5aU, 0xf4U,
+ 0x1fU, 0xddU, 0xa8U, 0x33U,
+ 0x88U, 0x07U, 0xc7U, 0x31U,
+ 0xb1U, 0x12U, 0x10U, 0x59U,
+ 0x27U, 0x80U, 0xecU, 0x5fU,
+ 0x60U, 0x51U, 0x7fU, 0xa9U,
+ 0x19U, 0xb5U, 0x4aU, 0x0dU,
+ 0x2dU, 0xe5U, 0x7aU, 0x9fU,
+ 0x93U, 0xc9U, 0x9cU, 0xefU,
+ 0xa0U, 0xe0U, 0x3bU, 0x4dU,
+ 0xaeU, 0x2aU, 0xf5U, 0xb0U,
+ 0xc8U, 0xebU, 0xbbU, 0x3cU,
+ 0x83U, 0x53U, 0x99U, 0x61U,
+ 0x17U, 0x2bU, 0x04U, 0x7eU,
+ 0xbaU, 0x77U, 0xd6U, 0x26U,
+ 0xe1U, 0x69U, 0x14U, 0x63U,
+ 0x55U, 0x21U, 0x0cU, 0x7dU,
+};
+static const u32 rcon[] = {
+ 0x01000000, 0x02000000, 0x04000000, 0x08000000,
+ 0x10000000, 0x20000000, 0x40000000, 0x80000000,
+ 0x1B000000, 0x36000000, /* for 128-bit blocks, Rijndael never uses more than 10 rcon values */
+};
+
+#define SWAP(x) (_lrotl(x, 8) & 0x00ff00ff | _lrotr(x, 8) & 0xff00ff00)
+
+#ifdef _MSC_VER
+#define GETU32(p) SWAP(*((u32 *)(p)))
+#define PUTU32(ct, st) { *((u32 *)(ct)) = SWAP((st)); }
+#else
+#define GETU32(pt) (((u32)(pt)[0] << 24) ^ ((u32)(pt)[1] << 16) ^ ((u32)(pt)[2] << 8) ^ ((u32)(pt)[3]))
+#define PUTU32(ct, st) { (ct)[0] = (u8)((st) >> 24); (ct)[1] = (u8)((st) >> 16); (ct)[2] = (u8)((st) >> 8); (ct)[3] = (u8)(st); }
+#endif
+
+/**
+ * Expand the cipher key into the encryption key schedule.
+ *
+ * @return the number of rounds for the given cipher key size.
+ */
+static int rijndaelKeySetupEnc(u32 rk[/*4*(Nr + 1)*/], const u8 cipherKey[], int keyBits) {
+ int i = 0;
+ u32 temp;
+
+ rk[0] = GETU32(cipherKey );
+ rk[1] = GETU32(cipherKey + 4);
+ rk[2] = GETU32(cipherKey + 8);
+ rk[3] = GETU32(cipherKey + 12);
+ if (keyBits == 128) {
+ for (;;) {
+ temp = rk[3];
+ rk[4] = rk[0] ^
+ (Te4[(temp >> 16) & 0xff] << 24) ^
+ (Te4[(temp >> 8) & 0xff] << 16) ^
+ (Te4[(temp ) & 0xff] << 8) ^
+ (Te4[(temp >> 24) ] ) ^
+ rcon[i];
+ rk[5] = rk[1] ^ rk[4];
+ rk[6] = rk[2] ^ rk[5];
+ rk[7] = rk[3] ^ rk[6];
+ if (++i == 10) {
+ return 10;
+ }
+ rk += 4;
+ }
+ }
+ rk[4] = GETU32(cipherKey + 16);
+ rk[5] = GETU32(cipherKey + 20);
+ if (keyBits == 192) {
+ for (;;) {
+ temp = rk[ 5];
+ rk[ 6] = rk[ 0] ^
+ (Te4[(temp >> 16) & 0xff] << 24) ^
+ (Te4[(temp >> 8) & 0xff] << 16) ^
+ (Te4[(temp ) & 0xff] << 8) ^
+ (Te4[(temp >> 24) ] ) ^
+ rcon[i];
+ rk[ 7] = rk[ 1] ^ rk[ 6];
+ rk[ 8] = rk[ 2] ^ rk[ 7];
+ rk[ 9] = rk[ 3] ^ rk[ 8];
+ if (++i == 8) {
+ return 12;
+ }
+ rk[10] = rk[ 4] ^ rk[ 9];
+ rk[11] = rk[ 5] ^ rk[10];
+ rk += 6;
+ }
+ }
+ rk[6] = GETU32(cipherKey + 24);
+ rk[7] = GETU32(cipherKey + 28);
+ if (keyBits == 256) {
+ for (;;) {
+ temp = rk[ 7];
+ rk[ 8] = rk[ 0] ^
+ (Te4[(temp >> 16) & 0xff] << 24) ^
+ (Te4[(temp >> 8) & 0xff] << 16) ^
+ (Te4[(temp ) & 0xff] << 8) ^
+ (Te4[(temp >> 24) ] ) ^
+ rcon[i];
+ rk[ 9] = rk[ 1] ^ rk[ 8];
+ rk[10] = rk[ 2] ^ rk[ 9];
+ rk[11] = rk[ 3] ^ rk[10];
+ if (++i == 7) {
+ return 14;
+ }
+ temp = rk[11];
+ rk[12] = rk[ 4] ^
+ (Te4[(temp >> 24) ] << 24) ^
+ (Te4[(temp >> 16) & 0xff] << 16) ^
+ (Te4[(temp >> 8) & 0xff] << 8) ^
+ (Te4[(temp ) & 0xff] );
+ rk[13] = rk[ 5] ^ rk[12];
+ rk[14] = rk[ 6] ^ rk[13];
+ rk[15] = rk[ 7] ^ rk[14];
+
+ rk += 8;
+ }
+ }
+ return 0;
+}
+
+/**
+ * Expand the cipher key into the decryption key schedule.
+ *
+ * @return the number of rounds for the given cipher key size.
+ */
+static int rijndaelKeySetupDec(u32 rk[/*4*(Nr + 1)*/], const u8 cipherKey[], int keyBits) {
+ int Nr, i, j;
+ u32 temp;
+
+ /* expand the cipher key: */
+ Nr = rijndaelKeySetupEnc(rk, cipherKey, keyBits);
+ /* invert the order of the round keys: */
+ for (i = 0, j = 4*Nr; i < j; i += 4, j -= 4) {
+ temp = rk[i ]; rk[i ] = rk[j ]; rk[j ] = temp;
+ temp = rk[i + 1]; rk[i + 1] = rk[j + 1]; rk[j + 1] = temp;
+ temp = rk[i + 2]; rk[i + 2] = rk[j + 2]; rk[j + 2] = temp;
+ temp = rk[i + 3]; rk[i + 3] = rk[j + 3]; rk[j + 3] = temp;
+ }
+ /* apply the inverse MixColumn transform to all round keys but the first and the last: */
+ for (i = 1; i < Nr; i++) {
+ rk += 4;
+ rk[0] =
+ Td0[Te4[(rk[0] >> 24) ]] ^
+ Td1[Te4[(rk[0] >> 16) & 0xff]] ^
+ Td2[Te4[(rk[0] >> 8) & 0xff]] ^
+ Td3[Te4[(rk[0] ) & 0xff]];
+ rk[1] =
+ Td0[Te4[(rk[1] >> 24) ]] ^
+ Td1[Te4[(rk[1] >> 16) & 0xff]] ^
+ Td2[Te4[(rk[1] >> 8) & 0xff]] ^
+ Td3[Te4[(rk[1] ) & 0xff]];
+ rk[2] =
+ Td0[Te4[(rk[2] >> 24) ]] ^
+ Td1[Te4[(rk[2] >> 16) & 0xff]] ^
+ Td2[Te4[(rk[2] >> 8) & 0xff]] ^
+ Td3[Te4[(rk[2] ) & 0xff]];
+ rk[3] =
+ Td0[Te4[(rk[3] >> 24) ]] ^
+ Td1[Te4[(rk[3] >> 16) & 0xff]] ^
+ Td2[Te4[(rk[3] >> 8) & 0xff]] ^
+ Td3[Te4[(rk[3] ) & 0xff]];
+ }
+ return Nr;
+}
+
+static void rijndaelEncrypt(const u32 rk[/*4*(Nr + 1)*/], int Nr, const u8 pt[16], u8 ct[16]) {
+ u32 s0, s1, s2, s3, t0, t1, t2, t3;
+#ifndef FULL_UNROLL
+ int r;
+#endif /* ?FULL_UNROLL */
+
+ /*
+ * map byte array block to cipher state
+ * and add initial round key:
+ */
+ s0 = GETU32(pt ) ^ rk[0];
+ s1 = GETU32(pt + 4) ^ rk[1];
+ s2 = GETU32(pt + 8) ^ rk[2];
+ s3 = GETU32(pt + 12) ^ rk[3];
+#ifdef FULL_UNROLL
+ /* round 1: */
+ t0 = Te0[s0 >> 24] ^ Te1[(s1 >> 16) & 0xff] ^ Te2[(s2 >> 8) & 0xff] ^ Te3[s3 & 0xff] ^ rk[ 4];
+ t1 = Te0[s1 >> 24] ^ Te1[(s2 >> 16) & 0xff] ^ Te2[(s3 >> 8) & 0xff] ^ Te3[s0 & 0xff] ^ rk[ 5];
+ t2 = Te0[s2 >> 24] ^ Te1[(s3 >> 16) & 0xff] ^ Te2[(s0 >> 8) & 0xff] ^ Te3[s1 & 0xff] ^ rk[ 6];
+ t3 = Te0[s3 >> 24] ^ Te1[(s0 >> 16) & 0xff] ^ Te2[(s1 >> 8) & 0xff] ^ Te3[s2 & 0xff] ^ rk[ 7];
+ /* round 2: */
+ s0 = Te0[t0 >> 24] ^ Te1[(t1 >> 16) & 0xff] ^ Te2[(t2 >> 8) & 0xff] ^ Te3[t3 & 0xff] ^ rk[ 8];
+ s1 = Te0[t1 >> 24] ^ Te1[(t2 >> 16) & 0xff] ^ Te2[(t3 >> 8) & 0xff] ^ Te3[t0 & 0xff] ^ rk[ 9];
+ s2 = Te0[t2 >> 24] ^ Te1[(t3 >> 16) & 0xff] ^ Te2[(t0 >> 8) & 0xff] ^ Te3[t1 & 0xff] ^ rk[10];
+ s3 = Te0[t3 >> 24] ^ Te1[(t0 >> 16) & 0xff] ^ Te2[(t1 >> 8) & 0xff] ^ Te3[t2 & 0xff] ^ rk[11];
+ /* round 3: */
+ t0 = Te0[s0 >> 24] ^ Te1[(s1 >> 16) & 0xff] ^ Te2[(s2 >> 8) & 0xff] ^ Te3[s3 & 0xff] ^ rk[12];
+ t1 = Te0[s1 >> 24] ^ Te1[(s2 >> 16) & 0xff] ^ Te2[(s3 >> 8) & 0xff] ^ Te3[s0 & 0xff] ^ rk[13];
+ t2 = Te0[s2 >> 24] ^ Te1[(s3 >> 16) & 0xff] ^ Te2[(s0 >> 8) & 0xff] ^ Te3[s1 & 0xff] ^ rk[14];
+ t3 = Te0[s3 >> 24] ^ Te1[(s0 >> 16) & 0xff] ^ Te2[(s1 >> 8) & 0xff] ^ Te3[s2 & 0xff] ^ rk[15];
+ /* round 4: */
+ s0 = Te0[t0 >> 24] ^ Te1[(t1 >> 16) & 0xff] ^ Te2[(t2 >> 8) & 0xff] ^ Te3[t3 & 0xff] ^ rk[16];
+ s1 = Te0[t1 >> 24] ^ Te1[(t2 >> 16) & 0xff] ^ Te2[(t3 >> 8) & 0xff] ^ Te3[t0 & 0xff] ^ rk[17];
+ s2 = Te0[t2 >> 24] ^ Te1[(t3 >> 16) & 0xff] ^ Te2[(t0 >> 8) & 0xff] ^ Te3[t1 & 0xff] ^ rk[18];
+ s3 = Te0[t3 >> 24] ^ Te1[(t0 >> 16) & 0xff] ^ Te2[(t1 >> 8) & 0xff] ^ Te3[t2 & 0xff] ^ rk[19];
+ /* round 5: */
+ t0 = Te0[s0 >> 24] ^ Te1[(s1 >> 16) & 0xff] ^ Te2[(s2 >> 8) & 0xff] ^ Te3[s3 & 0xff] ^ rk[20];
+ t1 = Te0[s1 >> 24] ^ Te1[(s2 >> 16) & 0xff] ^ Te2[(s3 >> 8) & 0xff] ^ Te3[s0 & 0xff] ^ rk[21];
+ t2 = Te0[s2 >> 24] ^ Te1[(s3 >> 16) & 0xff] ^ Te2[(s0 >> 8) & 0xff] ^ Te3[s1 & 0xff] ^ rk[22];
+ t3 = Te0[s3 >> 24] ^ Te1[(s0 >> 16) & 0xff] ^ Te2[(s1 >> 8) & 0xff] ^ Te3[s2 & 0xff] ^ rk[23];
+ /* round 6: */
+ s0 = Te0[t0 >> 24] ^ Te1[(t1 >> 16) & 0xff] ^ Te2[(t2 >> 8) & 0xff] ^ Te3[t3 & 0xff] ^ rk[24];
+ s1 = Te0[t1 >> 24] ^ Te1[(t2 >> 16) & 0xff] ^ Te2[(t3 >> 8) & 0xff] ^ Te3[t0 & 0xff] ^ rk[25];
+ s2 = Te0[t2 >> 24] ^ Te1[(t3 >> 16) & 0xff] ^ Te2[(t0 >> 8) & 0xff] ^ Te3[t1 & 0xff] ^ rk[26];
+ s3 = Te0[t3 >> 24] ^ Te1[(t0 >> 16) & 0xff] ^ Te2[(t1 >> 8) & 0xff] ^ Te3[t2 & 0xff] ^ rk[27];
+ /* round 7: */
+ t0 = Te0[s0 >> 24] ^ Te1[(s1 >> 16) & 0xff] ^ Te2[(s2 >> 8) & 0xff] ^ Te3[s3 & 0xff] ^ rk[28];
+ t1 = Te0[s1 >> 24] ^ Te1[(s2 >> 16) & 0xff] ^ Te2[(s3 >> 8) & 0xff] ^ Te3[s0 & 0xff] ^ rk[29];
+ t2 = Te0[s2 >> 24] ^ Te1[(s3 >> 16) & 0xff] ^ Te2[(s0 >> 8) & 0xff] ^ Te3[s1 & 0xff] ^ rk[30];
+ t3 = Te0[s3 >> 24] ^ Te1[(s0 >> 16) & 0xff] ^ Te2[(s1 >> 8) & 0xff] ^ Te3[s2 & 0xff] ^ rk[31];
+ /* round 8: */
+ s0 = Te0[t0 >> 24] ^ Te1[(t1 >> 16) & 0xff] ^ Te2[(t2 >> 8) & 0xff] ^ Te3[t3 & 0xff] ^ rk[32];
+ s1 = Te0[t1 >> 24] ^ Te1[(t2 >> 16) & 0xff] ^ Te2[(t3 >> 8) & 0xff] ^ Te3[t0 & 0xff] ^ rk[33];
+ s2 = Te0[t2 >> 24] ^ Te1[(t3 >> 16) & 0xff] ^ Te2[(t0 >> 8) & 0xff] ^ Te3[t1 & 0xff] ^ rk[34];
+ s3 = Te0[t3 >> 24] ^ Te1[(t0 >> 16) & 0xff] ^ Te2[(t1 >> 8) & 0xff] ^ Te3[t2 & 0xff] ^ rk[35];
+ /* round 9: */
+ t0 = Te0[s0 >> 24] ^ Te1[(s1 >> 16) & 0xff] ^ Te2[(s2 >> 8) & 0xff] ^ Te3[s3 & 0xff] ^ rk[36];
+ t1 = Te0[s1 >> 24] ^ Te1[(s2 >> 16) & 0xff] ^ Te2[(s3 >> 8) & 0xff] ^ Te3[s0 & 0xff] ^ rk[37];
+ t2 = Te0[s2 >> 24] ^ Te1[(s3 >> 16) & 0xff] ^ Te2[(s0 >> 8) & 0xff] ^ Te3[s1 & 0xff] ^ rk[38];
+ t3 = Te0[s3 >> 24] ^ Te1[(s0 >> 16) & 0xff] ^ Te2[(s1 >> 8) & 0xff] ^ Te3[s2 & 0xff] ^ rk[39];
+ if (Nr > 10) {
+ /* round 10: */
+ s0 = Te0[t0 >> 24] ^ Te1[(t1 >> 16) & 0xff] ^ Te2[(t2 >> 8) & 0xff] ^ Te3[t3 & 0xff] ^ rk[40];
+ s1 = Te0[t1 >> 24] ^ Te1[(t2 >> 16) & 0xff] ^ Te2[(t3 >> 8) & 0xff] ^ Te3[t0 & 0xff] ^ rk[41];
+ s2 = Te0[t2 >> 24] ^ Te1[(t3 >> 16) & 0xff] ^ Te2[(t0 >> 8) & 0xff] ^ Te3[t1 & 0xff] ^ rk[42];
+ s3 = Te0[t3 >> 24] ^ Te1[(t0 >> 16) & 0xff] ^ Te2[(t1 >> 8) & 0xff] ^ Te3[t2 & 0xff] ^ rk[43];
+ /* round 11: */
+ t0 = Te0[s0 >> 24] ^ Te1[(s1 >> 16) & 0xff] ^ Te2[(s2 >> 8) & 0xff] ^ Te3[s3 & 0xff] ^ rk[44];
+ t1 = Te0[s1 >> 24] ^ Te1[(s2 >> 16) & 0xff] ^ Te2[(s3 >> 8) & 0xff] ^ Te3[s0 & 0xff] ^ rk[45];
+ t2 = Te0[s2 >> 24] ^ Te1[(s3 >> 16) & 0xff] ^ Te2[(s0 >> 8) & 0xff] ^ Te3[s1 & 0xff] ^ rk[46];
+ t3 = Te0[s3 >> 24] ^ Te1[(s0 >> 16) & 0xff] ^ Te2[(s1 >> 8) & 0xff] ^ Te3[s2 & 0xff] ^ rk[47];
+ if (Nr > 12) {
+ /* round 12: */
+ s0 = Te0[t0 >> 24] ^ Te1[(t1 >> 16) & 0xff] ^ Te2[(t2 >> 8) & 0xff] ^ Te3[t3 & 0xff] ^ rk[48];
+ s1 = Te0[t1 >> 24] ^ Te1[(t2 >> 16) & 0xff] ^ Te2[(t3 >> 8) & 0xff] ^ Te3[t0 & 0xff] ^ rk[49];
+ s2 = Te0[t2 >> 24] ^ Te1[(t3 >> 16) & 0xff] ^ Te2[(t0 >> 8) & 0xff] ^ Te3[t1 & 0xff] ^ rk[50];
+ s3 = Te0[t3 >> 24] ^ Te1[(t0 >> 16) & 0xff] ^ Te2[(t1 >> 8) & 0xff] ^ Te3[t2 & 0xff] ^ rk[51];
+ /* round 13: */
+ t0 = Te0[s0 >> 24] ^ Te1[(s1 >> 16) & 0xff] ^ Te2[(s2 >> 8) & 0xff] ^ Te3[s3 & 0xff] ^ rk[52];
+ t1 = Te0[s1 >> 24] ^ Te1[(s2 >> 16) & 0xff] ^ Te2[(s3 >> 8) & 0xff] ^ Te3[s0 & 0xff] ^ rk[53];
+ t2 = Te0[s2 >> 24] ^ Te1[(s3 >> 16) & 0xff] ^ Te2[(s0 >> 8) & 0xff] ^ Te3[s1 & 0xff] ^ rk[54];
+ t3 = Te0[s3 >> 24] ^ Te1[(s0 >> 16) & 0xff] ^ Te2[(s1 >> 8) & 0xff] ^ Te3[s2 & 0xff] ^ rk[55];
+ }
+ }
+ rk += Nr << 2;
+#else /* !FULL_UNROLL */
+ /*
+ * Nr - 1 full rounds:
+ */
+ r = Nr >> 1;
+ for (;;) {
+ t0 =
+ Te0[(s0 >> 24) ] ^
+ Te1[(s1 >> 16) & 0xff] ^
+ Te2[(s2 >> 8) & 0xff] ^
+ Te3[(s3 ) & 0xff] ^
+ rk[4];
+ t1 =
+ Te0[(s1 >> 24) ] ^
+ Te1[(s2 >> 16) & 0xff] ^
+ Te2[(s3 >> 8) & 0xff] ^
+ Te3[(s0 ) & 0xff] ^
+ rk[5];
+ t2 =
+ Te0[(s2 >> 24) ] ^
+ Te1[(s3 >> 16) & 0xff] ^
+ Te2[(s0 >> 8) & 0xff] ^
+ Te3[(s1 ) & 0xff] ^
+ rk[6];
+ t3 =
+ Te0[(s3 >> 24) ] ^
+ Te1[(s0 >> 16) & 0xff] ^
+ Te2[(s1 >> 8) & 0xff] ^
+ Te3[(s2 ) & 0xff] ^
+ rk[7];
+
+ rk += 8;
+ if (--r == 0) {
+ break;
+ }
+
+ s0 =
+ Te0[(t0 >> 24) ] ^
+ Te1[(t1 >> 16) & 0xff] ^
+ Te2[(t2 >> 8) & 0xff] ^
+ Te3[(t3 ) & 0xff] ^
+ rk[0];
+ s1 =
+ Te0[(t1 >> 24) ] ^
+ Te1[(t2 >> 16) & 0xff] ^
+ Te2[(t3 >> 8) & 0xff] ^
+ Te3[(t0 ) & 0xff] ^
+ rk[1];
+ s2 =
+ Te0[(t2 >> 24) ] ^
+ Te1[(t3 >> 16) & 0xff] ^
+ Te2[(t0 >> 8) & 0xff] ^
+ Te3[(t1 ) & 0xff] ^
+ rk[2];
+ s3 =
+ Te0[(t3 >> 24) ] ^
+ Te1[(t0 >> 16) & 0xff] ^
+ Te2[(t1 >> 8) & 0xff] ^
+ Te3[(t2 ) & 0xff] ^
+ rk[3];
+ }
+#endif /* ?FULL_UNROLL */
+ /*
+ * apply last round and
+ * map cipher state to byte array block:
+ */
+ s0 =
+ (Te4[(t0 >> 24) ] << 24) ^
+ (Te4[(t1 >> 16) & 0xff] << 16) ^
+ (Te4[(t2 >> 8) & 0xff] << 8) ^
+ (Te4[(t3 ) & 0xff] ) ^
+ rk[0];
+ PUTU32(ct , s0);
+ s1 =
+ (Te4[(t1 >> 24) ] << 24) ^
+ (Te4[(t2 >> 16) & 0xff] << 16) ^
+ (Te4[(t3 >> 8) & 0xff] << 8) ^
+ (Te4[(t0 ) & 0xff] ) ^
+ rk[1];
+ PUTU32(ct + 4, s1);
+ s2 =
+ (Te4[(t2 >> 24) ] << 24) ^
+ (Te4[(t3 >> 16) & 0xff] << 16) ^
+ (Te4[(t0 >> 8) & 0xff] << 8) ^
+ (Te4[(t1 ) & 0xff] ) ^
+ rk[2];
+ PUTU32(ct + 8, s2);
+ s3 =
+ (Te4[(t3 >> 24) ] << 24) ^
+ (Te4[(t0 >> 16) & 0xff] << 16) ^
+ (Te4[(t1 >> 8) & 0xff] << 8) ^
+ (Te4[(t2 ) & 0xff] ) ^
+ rk[3];
+ PUTU32(ct + 12, s3);
+}
+
+static void rijndaelDecrypt(const u32 rk[/*4*(Nr + 1)*/], int Nr, const u8 ct[16], u8 pt[16]) {
+ u32 s0, s1, s2, s3, t0, t1, t2, t3;
+#ifndef FULL_UNROLL
+ int r;
+#endif /* ?FULL_UNROLL */
+
+ /*
+ * map byte array block to cipher state
+ * and add initial round key:
+ */
+ s0 = GETU32(ct ) ^ rk[0];
+ s1 = GETU32(ct + 4) ^ rk[1];
+ s2 = GETU32(ct + 8) ^ rk[2];
+ s3 = GETU32(ct + 12) ^ rk[3];
+#ifdef FULL_UNROLL
+ /* round 1: */
+ t0 = Td0[s0 >> 24] ^ Td1[(s3 >> 16) & 0xff] ^ Td2[(s2 >> 8) & 0xff] ^ Td3[s1 & 0xff] ^ rk[ 4];
+ t1 = Td0[s1 >> 24] ^ Td1[(s0 >> 16) & 0xff] ^ Td2[(s3 >> 8) & 0xff] ^ Td3[s2 & 0xff] ^ rk[ 5];
+ t2 = Td0[s2 >> 24] ^ Td1[(s1 >> 16) & 0xff] ^ Td2[(s0 >> 8) & 0xff] ^ Td3[s3 & 0xff] ^ rk[ 6];
+ t3 = Td0[s3 >> 24] ^ Td1[(s2 >> 16) & 0xff] ^ Td2[(s1 >> 8) & 0xff] ^ Td3[s0 & 0xff] ^ rk[ 7];
+ /* round 2: */
+ s0 = Td0[t0 >> 24] ^ Td1[(t3 >> 16) & 0xff] ^ Td2[(t2 >> 8) & 0xff] ^ Td3[t1 & 0xff] ^ rk[ 8];
+ s1 = Td0[t1 >> 24] ^ Td1[(t0 >> 16) & 0xff] ^ Td2[(t3 >> 8) & 0xff] ^ Td3[t2 & 0xff] ^ rk[ 9];
+ s2 = Td0[t2 >> 24] ^ Td1[(t1 >> 16) & 0xff] ^ Td2[(t0 >> 8) & 0xff] ^ Td3[t3 & 0xff] ^ rk[10];
+ s3 = Td0[t3 >> 24] ^ Td1[(t2 >> 16) & 0xff] ^ Td2[(t1 >> 8) & 0xff] ^ Td3[t0 & 0xff] ^ rk[11];
+ /* round 3: */
+ t0 = Td0[s0 >> 24] ^ Td1[(s3 >> 16) & 0xff] ^ Td2[(s2 >> 8) & 0xff] ^ Td3[s1 & 0xff] ^ rk[12];
+ t1 = Td0[s1 >> 24] ^ Td1[(s0 >> 16) & 0xff] ^ Td2[(s3 >> 8) & 0xff] ^ Td3[s2 & 0xff] ^ rk[13];
+ t2 = Td0[s2 >> 24] ^ Td1[(s1 >> 16) & 0xff] ^ Td2[(s0 >> 8) & 0xff] ^ Td3[s3 & 0xff] ^ rk[14];
+ t3 = Td0[s3 >> 24] ^ Td1[(s2 >> 16) & 0xff] ^ Td2[(s1 >> 8) & 0xff] ^ Td3[s0 & 0xff] ^ rk[15];
+ /* round 4: */
+ s0 = Td0[t0 >> 24] ^ Td1[(t3 >> 16) & 0xff] ^ Td2[(t2 >> 8) & 0xff] ^ Td3[t1 & 0xff] ^ rk[16];
+ s1 = Td0[t1 >> 24] ^ Td1[(t0 >> 16) & 0xff] ^ Td2[(t3 >> 8) & 0xff] ^ Td3[t2 & 0xff] ^ rk[17];
+ s2 = Td0[t2 >> 24] ^ Td1[(t1 >> 16) & 0xff] ^ Td2[(t0 >> 8) & 0xff] ^ Td3[t3 & 0xff] ^ rk[18];
+ s3 = Td0[t3 >> 24] ^ Td1[(t2 >> 16) & 0xff] ^ Td2[(t1 >> 8) & 0xff] ^ Td3[t0 & 0xff] ^ rk[19];
+ /* round 5: */
+ t0 = Td0[s0 >> 24] ^ Td1[(s3 >> 16) & 0xff] ^ Td2[(s2 >> 8) & 0xff] ^ Td3[s1 & 0xff] ^ rk[20];
+ t1 = Td0[s1 >> 24] ^ Td1[(s0 >> 16) & 0xff] ^ Td2[(s3 >> 8) & 0xff] ^ Td3[s2 & 0xff] ^ rk[21];
+ t2 = Td0[s2 >> 24] ^ Td1[(s1 >> 16) & 0xff] ^ Td2[(s0 >> 8) & 0xff] ^ Td3[s3 & 0xff] ^ rk[22];
+ t3 = Td0[s3 >> 24] ^ Td1[(s2 >> 16) & 0xff] ^ Td2[(s1 >> 8) & 0xff] ^ Td3[s0 & 0xff] ^ rk[23];
+ /* round 6: */
+ s0 = Td0[t0 >> 24] ^ Td1[(t3 >> 16) & 0xff] ^ Td2[(t2 >> 8) & 0xff] ^ Td3[t1 & 0xff] ^ rk[24];
+ s1 = Td0[t1 >> 24] ^ Td1[(t0 >> 16) & 0xff] ^ Td2[(t3 >> 8) & 0xff] ^ Td3[t2 & 0xff] ^ rk[25];
+ s2 = Td0[t2 >> 24] ^ Td1[(t1 >> 16) & 0xff] ^ Td2[(t0 >> 8) & 0xff] ^ Td3[t3 & 0xff] ^ rk[26];
+ s3 = Td0[t3 >> 24] ^ Td1[(t2 >> 16) & 0xff] ^ Td2[(t1 >> 8) & 0xff] ^ Td3[t0 & 0xff] ^ rk[27];
+ /* round 7: */
+ t0 = Td0[s0 >> 24] ^ Td1[(s3 >> 16) & 0xff] ^ Td2[(s2 >> 8) & 0xff] ^ Td3[s1 & 0xff] ^ rk[28];
+ t1 = Td0[s1 >> 24] ^ Td1[(s0 >> 16) & 0xff] ^ Td2[(s3 >> 8) & 0xff] ^ Td3[s2 & 0xff] ^ rk[29];
+ t2 = Td0[s2 >> 24] ^ Td1[(s1 >> 16) & 0xff] ^ Td2[(s0 >> 8) & 0xff] ^ Td3[s3 & 0xff] ^ rk[30];
+ t3 = Td0[s3 >> 24] ^ Td1[(s2 >> 16) & 0xff] ^ Td2[(s1 >> 8) & 0xff] ^ Td3[s0 & 0xff] ^ rk[31];
+ /* round 8: */
+ s0 = Td0[t0 >> 24] ^ Td1[(t3 >> 16) & 0xff] ^ Td2[(t2 >> 8) & 0xff] ^ Td3[t1 & 0xff] ^ rk[32];
+ s1 = Td0[t1 >> 24] ^ Td1[(t0 >> 16) & 0xff] ^ Td2[(t3 >> 8) & 0xff] ^ Td3[t2 & 0xff] ^ rk[33];
+ s2 = Td0[t2 >> 24] ^ Td1[(t1 >> 16) & 0xff] ^ Td2[(t0 >> 8) & 0xff] ^ Td3[t3 & 0xff] ^ rk[34];
+ s3 = Td0[t3 >> 24] ^ Td1[(t2 >> 16) & 0xff] ^ Td2[(t1 >> 8) & 0xff] ^ Td3[t0 & 0xff] ^ rk[35];
+ /* round 9: */
+ t0 = Td0[s0 >> 24] ^ Td1[(s3 >> 16) & 0xff] ^ Td2[(s2 >> 8) & 0xff] ^ Td3[s1 & 0xff] ^ rk[36];
+ t1 = Td0[s1 >> 24] ^ Td1[(s0 >> 16) & 0xff] ^ Td2[(s3 >> 8) & 0xff] ^ Td3[s2 & 0xff] ^ rk[37];
+ t2 = Td0[s2 >> 24] ^ Td1[(s1 >> 16) & 0xff] ^ Td2[(s0 >> 8) & 0xff] ^ Td3[s3 & 0xff] ^ rk[38];
+ t3 = Td0[s3 >> 24] ^ Td1[(s2 >> 16) & 0xff] ^ Td2[(s1 >> 8) & 0xff] ^ Td3[s0 & 0xff] ^ rk[39];
+ if (Nr > 10) {
+ /* round 10: */
+ s0 = Td0[t0 >> 24] ^ Td1[(t3 >> 16) & 0xff] ^ Td2[(t2 >> 8) & 0xff] ^ Td3[t1 & 0xff] ^ rk[40];
+ s1 = Td0[t1 >> 24] ^ Td1[(t0 >> 16) & 0xff] ^ Td2[(t3 >> 8) & 0xff] ^ Td3[t2 & 0xff] ^ rk[41];
+ s2 = Td0[t2 >> 24] ^ Td1[(t1 >> 16) & 0xff] ^ Td2[(t0 >> 8) & 0xff] ^ Td3[t3 & 0xff] ^ rk[42];
+ s3 = Td0[t3 >> 24] ^ Td1[(t2 >> 16) & 0xff] ^ Td2[(t1 >> 8) & 0xff] ^ Td3[t0 & 0xff] ^ rk[43];
+ /* round 11: */
+ t0 = Td0[s0 >> 24] ^ Td1[(s3 >> 16) & 0xff] ^ Td2[(s2 >> 8) & 0xff] ^ Td3[s1 & 0xff] ^ rk[44];
+ t1 = Td0[s1 >> 24] ^ Td1[(s0 >> 16) & 0xff] ^ Td2[(s3 >> 8) & 0xff] ^ Td3[s2 & 0xff] ^ rk[45];
+ t2 = Td0[s2 >> 24] ^ Td1[(s1 >> 16) & 0xff] ^ Td2[(s0 >> 8) & 0xff] ^ Td3[s3 & 0xff] ^ rk[46];
+ t3 = Td0[s3 >> 24] ^ Td1[(s2 >> 16) & 0xff] ^ Td2[(s1 >> 8) & 0xff] ^ Td3[s0 & 0xff] ^ rk[47];
+ if (Nr > 12) {
+ /* round 12: */
+ s0 = Td0[t0 >> 24] ^ Td1[(t3 >> 16) & 0xff] ^ Td2[(t2 >> 8) & 0xff] ^ Td3[t1 & 0xff] ^ rk[48];
+ s1 = Td0[t1 >> 24] ^ Td1[(t0 >> 16) & 0xff] ^ Td2[(t3 >> 8) & 0xff] ^ Td3[t2 & 0xff] ^ rk[49];
+ s2 = Td0[t2 >> 24] ^ Td1[(t1 >> 16) & 0xff] ^ Td2[(t0 >> 8) & 0xff] ^ Td3[t3 & 0xff] ^ rk[50];
+ s3 = Td0[t3 >> 24] ^ Td1[(t2 >> 16) & 0xff] ^ Td2[(t1 >> 8) & 0xff] ^ Td3[t0 & 0xff] ^ rk[51];
+ /* round 13: */
+ t0 = Td0[s0 >> 24] ^ Td1[(s3 >> 16) & 0xff] ^ Td2[(s2 >> 8) & 0xff] ^ Td3[s1 & 0xff] ^ rk[52];
+ t1 = Td0[s1 >> 24] ^ Td1[(s0 >> 16) & 0xff] ^ Td2[(s3 >> 8) & 0xff] ^ Td3[s2 & 0xff] ^ rk[53];
+ t2 = Td0[s2 >> 24] ^ Td1[(s1 >> 16) & 0xff] ^ Td2[(s0 >> 8) & 0xff] ^ Td3[s3 & 0xff] ^ rk[54];
+ t3 = Td0[s3 >> 24] ^ Td1[(s2 >> 16) & 0xff] ^ Td2[(s1 >> 8) & 0xff] ^ Td3[s0 & 0xff] ^ rk[55];
+ }
+ }
+ rk += Nr << 2;
+#else /* !FULL_UNROLL */
+ /*
+ * Nr - 1 full rounds:
+ */
+ r = Nr >> 1;
+ for (;;) {
+ t0 =
+ Td0[(s0 >> 24) ] ^
+ Td1[(s3 >> 16) & 0xff] ^
+ Td2[(s2 >> 8) & 0xff] ^
+ Td3[(s1 ) & 0xff] ^
+ rk[4];
+ t1 =
+ Td0[(s1 >> 24) ] ^
+ Td1[(s0 >> 16) & 0xff] ^
+ Td2[(s3 >> 8) & 0xff] ^
+ Td3[(s2 ) & 0xff] ^
+ rk[5];
+ t2 =
+ Td0[(s2 >> 24) ] ^
+ Td1[(s1 >> 16) & 0xff] ^
+ Td2[(s0 >> 8) & 0xff] ^
+ Td3[(s3 ) & 0xff] ^
+ rk[6];
+ t3 =
+ Td0[(s3 >> 24) ] ^
+ Td1[(s2 >> 16) & 0xff] ^
+ Td2[(s1 >> 8) & 0xff] ^
+ Td3[(s0 ) & 0xff] ^
+ rk[7];
+
+ rk += 8;
+ if (--r == 0) {
+ break;
+ }
+
+ s0 =
+ Td0[(t0 >> 24) ] ^
+ Td1[(t3 >> 16) & 0xff] ^
+ Td2[(t2 >> 8) & 0xff] ^
+ Td3[(t1 ) & 0xff] ^
+ rk[0];
+ s1 =
+ Td0[(t1 >> 24) ] ^
+ Td1[(t0 >> 16) & 0xff] ^
+ Td2[(t3 >> 8) & 0xff] ^
+ Td3[(t2 ) & 0xff] ^
+ rk[1];
+ s2 =
+ Td0[(t2 >> 24) ] ^
+ Td1[(t1 >> 16) & 0xff] ^
+ Td2[(t0 >> 8) & 0xff] ^
+ Td3[(t3 ) & 0xff] ^
+ rk[2];
+ s3 =
+ Td0[(t3 >> 24) ] ^
+ Td1[(t2 >> 16) & 0xff] ^
+ Td2[(t1 >> 8) & 0xff] ^
+ Td3[(t0 ) & 0xff] ^
+ rk[3];
+ }
+#endif /* ?FULL_UNROLL */
+ /*
+ * apply last round and
+ * map cipher state to byte array block:
+ */
+ s0 =
+ (Td4[(t0 >> 24) ] << 24) ^
+ (Td4[(t3 >> 16) & 0xff] << 16) ^
+ (Td4[(t2 >> 8) & 0xff] << 8) ^
+ (Td4[(t1 ) & 0xff] ) ^
+ rk[0];
+ PUTU32(pt , s0);
+ s1 =
+ (Td4[(t1 >> 24) ] << 24) ^
+ (Td4[(t0 >> 16) & 0xff] << 16) ^
+ (Td4[(t3 >> 8) & 0xff] << 8) ^
+ (Td4[(t2 ) & 0xff] ) ^
+ rk[1];
+ PUTU32(pt + 4, s1);
+ s2 =
+ (Td4[(t2 >> 24) ] << 24) ^
+ (Td4[(t1 >> 16) & 0xff] << 16) ^
+ (Td4[(t0 >> 8) & 0xff] << 8) ^
+ (Td4[(t3 ) & 0xff] ) ^
+ rk[2];
+ PUTU32(pt + 8, s2);
+ s3 =
+ (Td4[(t3 >> 24) ] << 24) ^
+ (Td4[(t2 >> 16) & 0xff] << 16) ^
+ (Td4[(t1 >> 8) & 0xff] << 8) ^
+ (Td4[(t0 ) & 0xff] ) ^
+ rk[3];
+ PUTU32(pt + 12, s3);
+}
+
+#ifdef INTERMEDIATE_VALUE_KAT
+
+static void rijndaelEncryptRound(const u32 rk[/*4*(Nr + 1)*/], int Nr, u8 block[16], int rounds) {
+ int r;
+ u32 s0, s1, s2, s3, t0, t1, t2, t3;
+
+ /*
+ * map byte array block to cipher state
+ * and add initial round key:
+ */
+ s0 = GETU32(block ) ^ rk[0];
+ s1 = GETU32(block + 4) ^ rk[1];
+ s2 = GETU32(block + 8) ^ rk[2];
+ s3 = GETU32(block + 12) ^ rk[3];
+ rk += 4;
+
+ /*
+ * Nr - 1 full rounds:
+ */
+ for (r = (rounds < Nr ? rounds : Nr - 1); r > 0; r--) {
+ t0 =
+ Te0[(s0 >> 24) ] ^
+ Te1[(s1 >> 16) & 0xff] ^
+ Te2[(s2 >> 8) & 0xff] ^
+ Te3[(s3 ) & 0xff] ^
+ rk[0];
+ t1 =
+ Te0[(s1 >> 24) ] ^
+ Te1[(s2 >> 16) & 0xff] ^
+ Te2[(s3 >> 8) & 0xff] ^
+ Te3[(s0 ) & 0xff] ^
+ rk[1];
+ t2 =
+ Te0[(s2 >> 24) ] ^
+ Te1[(s3 >> 16) & 0xff] ^
+ Te2[(s0 >> 8) & 0xff] ^
+ Te3[(s1 ) & 0xff] ^
+ rk[2];
+ t3 =
+ Te0[(s3 >> 24) ] ^
+ Te1[(s0 >> 16) & 0xff] ^
+ Te2[(s1 >> 8) & 0xff] ^
+ Te3[(s2 ) & 0xff] ^
+ rk[3];
+
+ s0 = t0;
+ s1 = t1;
+ s2 = t2;
+ s3 = t3;
+ rk += 4;
+
+ }
+
+ /*
+ * apply last round and
+ * map cipher state to byte array block:
+ */
+ if (rounds == Nr) {
+ t0 =
+ (Te4[(s0 >> 24) ] << 24) ^
+ (Te4[(s1 >> 16) & 0xff] << 16) ^
+ (Te4[(s2 >> 8) & 0xff] << 8) ^
+ (Te4[(s3 ) & 0xff] ) ^
+ rk[0];
+ t1 =
+ (Te4[(s1 >> 24) ] << 24) ^
+ (Te4[(s2 >> 16) & 0xff] << 16) ^
+ (Te4[(s3 >> 8) & 0xff] << 8) ^
+ (Te4[(s0 ) & 0xff] ) ^
+ rk[1];
+ t2 =
+ (Te4[(s2 >> 24) ] << 24) ^
+ (Te4[(s3 >> 16) & 0xff] << 16) ^
+ (Te4[(s0 >> 8) & 0xff] << 8) ^
+ (Te4[(s1 ) & 0xff] ) ^
+ rk[2];
+ t3 =
+ (Te4[(s3 >> 24) ] << 24) ^
+ (Te4[(s0 >> 16) & 0xff] << 16) ^
+ (Te4[(s1 >> 8) & 0xff] << 8) ^
+ (Te4[(s2 ) & 0xff] ) ^
+ rk[3];
+
+ s0 = t0;
+ s1 = t1;
+ s2 = t2;
+ s3 = t3;
+ }
+
+ PUTU32(block , s0);
+ PUTU32(block + 4, s1);
+ PUTU32(block + 8, s2);
+ PUTU32(block + 12, s3);
+}
+
+static void rijndaelDecryptRound(const u32 rk[/*4*(Nr + 1)*/], int Nr, u8 block[16], int rounds) {
+ int r;
+ u32 s0, s1, s2, s3, t0, t1, t2, t3;
+
+ /*
+ * map byte array block to cipher state
+ * and add initial round key:
+ */
+ s0 = GETU32(block ) ^ rk[0];
+ s1 = GETU32(block + 4) ^ rk[1];
+ s2 = GETU32(block + 8) ^ rk[2];
+ s3 = GETU32(block + 12) ^ rk[3];
+ rk += 4;
+
+ /*
+ * Nr - 1 full rounds:
+ */
+ for (r = (rounds < Nr ? rounds : Nr) - 1; r > 0; r--) {
+ t0 =
+ Td0[(s0 >> 24) ] ^
+ Td1[(s3 >> 16) & 0xff] ^
+ Td2[(s2 >> 8) & 0xff] ^
+ Td3[(s1 ) & 0xff] ^
+ rk[0];
+ t1 =
+ Td0[(s1 >> 24) ] ^
+ Td1[(s0 >> 16) & 0xff] ^
+ Td2[(s3 >> 8) & 0xff] ^
+ Td3[(s2 ) & 0xff] ^
+ rk[1];
+ t2 =
+ Td0[(s2 >> 24) ] ^
+ Td1[(s1 >> 16) & 0xff] ^
+ Td2[(s0 >> 8) & 0xff] ^
+ Td3[(s3 ) & 0xff] ^
+ rk[2];
+ t3 =
+ Td0[(s3 >> 24) ] ^
+ Td1[(s2 >> 16) & 0xff] ^
+ Td2[(s1 >> 8) & 0xff] ^
+ Td3[(s0 ) & 0xff] ^
+ rk[3];
+
+ s0 = t0;
+ s1 = t1;
+ s2 = t2;
+ s3 = t3;
+ rk += 4;
+
+ }
+
+ /*
+ * complete the last round and
+ * map cipher state to byte array block:
+ */
+ t0 =
+ (Td4[(s0 >> 24) ] << 24) ^
+ (Td4[(s3 >> 16) & 0xff] << 16) ^
+ (Td4[(s2 >> 8) & 0xff] << 8) ^
+ (Td4[(s1 ) & 0xff] );
+ t1 =
+ (Td4[(s1 >> 24) ] << 24) ^
+ (Td4[(s0 >> 16) & 0xff] << 16) ^
+ (Td4[(s3 >> 8) & 0xff] << 8) ^
+ (Td4[(s2 ) & 0xff] );
+ t2 =
+ (Td4[(s2 >> 24) ] << 24) ^
+ (Td4[(s1 >> 16) & 0xff] << 16) ^
+ (Td4[(s0 >> 8) & 0xff] << 8) ^
+ (Td4[(s3 ) & 0xff] );
+ t3 =
+ (Td4[(s3 >> 24) ] << 24) ^
+ (Td4[(s2 >> 16) & 0xff] << 16) ^
+ (Td4[(s1 >> 8) & 0xff] << 8) ^
+ (Td4[(s0 ) & 0xff] );
+
+ if (rounds == Nr) {
+ t0 ^= rk[0];
+ t1 ^= rk[1];
+ t2 ^= rk[2];
+ t3 ^= rk[3];
+ }
+
+ PUTU32(block , t0);
+ PUTU32(block + 4, t1);
+ PUTU32(block + 8, t2);
+ PUTU32(block + 12, t3);
+}
+
+#endif /* INTERMEDIATE_VALUE_KAT */
--- /dev/null
+++ b/libsec/port/blowfish.c
@@ -1,0 +1,579 @@
+#include "os.h"
+#include <mp.h>
+#include <libsec.h>
+
+// Blowfish block cipher. See:
+// Lecture Notes in Computer Science 809
+// Fast Software Encryption
+// Cambridge Security Workshop, Cambridge, England (1993)
+
+static u32int sbox[1024];
+static u32int pbox[BFrounds+2];
+
+static void bfencrypt(u32int *, BFstate *);
+static void bfdecrypt(u32int *, BFstate *);
+
+void
+setupBFstate(BFstate *s, uchar key[], int keybytes, uchar *ivec)
+{
+ int i, j;
+ u32int n, buf[2];
+
+ memset(s, 0, sizeof(*s));
+ memset(buf, 0, sizeof buf);
+
+ if (keybytes > sizeof(s->key))
+ keybytes = sizeof(s->key);
+
+ memmove(s->key, key, keybytes);
+
+ if (ivec != nil)
+ memmove(s->ivec, ivec, sizeof(s->ivec));
+ else
+ memset(s->ivec, 0, sizeof(s->ivec));
+
+ memmove(s->pbox, pbox, sizeof(pbox));
+ memmove(s->sbox, sbox, sizeof(sbox));
+
+ if (keybytes > 4*(BFrounds + 2))
+ keybytes = 4*(BFrounds + 2);
+
+ for(i=j=0; i < BFrounds+2; i++) {
+ n = key[j];
+ j = (j+1) % keybytes;
+
+ n <<= 8;
+ n |= key[j];
+ j = (j+1) % keybytes;
+
+ n <<= 8;
+ n |= key[j];
+ j = (j+1) % keybytes;
+
+ n <<= 8;
+ n |= key[j];
+ j = (j+1) % keybytes;
+
+ s->pbox[i] ^= n;
+ }
+
+ for(i=0; i < BFrounds+2; i += 2) {
+ bfencrypt(buf, s);
+ s->pbox[i] = buf[0];
+ s->pbox[i+1] = buf[1];
+ }
+
+ for(i=0; i < 1024; i += 2) {
+ bfencrypt(buf, s);
+ s->sbox[i] = buf[0];
+ s->sbox[i+1] = buf[1];
+ }
+
+ s->setup = 0xcafebabe;
+}
+
+void
+bfCBCencrypt(uchar *buf, int n, BFstate *s)
+{
+ int i;
+ uchar *p;
+ u32int bo[2], bi[2], b;
+
+ assert((n & 7) == 0);
+
+ bo[0] = s->ivec[0] | ((u32int) s->ivec[1]<<8) | ((u32int)s->ivec[2]<<16) | ((u32int)s->ivec[3]<<24);
+ bo[1] = s->ivec[4] | ((u32int) s->ivec[5]<<8) | ((u32int)s->ivec[6]<<16) | ((u32int)s->ivec[7]<<24);
+
+ for(i=0; i < n; i += 8, buf += 8) {
+ bi[0] = buf[0] | ((u32int) buf[1]<<8) | ((u32int)buf[2]<<16) | ((u32int)buf[3]<<24);
+ bi[1] = buf[4] | ((u32int) buf[5]<<8) | ((u32int)buf[6]<<16) | ((u32int)buf[7]<<24);
+
+ bi[0] ^= bo[0];
+ bi[1] ^= bo[1];
+
+ bfencrypt(bi, s);
+
+ bo[0] = bi[0];
+ bo[1] = bi[1];
+
+ p = buf;
+ b = bo[0];
+ *p++ = b;
+ b >>= 8;
+ *p++ = b;
+ b >>= 8;
+ *p++ = b;
+ b >>= 8;
+ *p++ = b;
+
+ b = bo[1];
+ *p++ = b;
+ b >>= 8;
+ *p++ = b;
+ b >>= 8;
+ *p++ = b;
+ b >>= 8;
+ *p = b;
+ }
+
+ s->ivec[7] = bo[1] >> 24;
+ s->ivec[6] = bo[1] >> 16;
+ s->ivec[5] = bo[1] >> 8;
+ s->ivec[4] = bo[1];
+
+ s->ivec[3] = bo[0] >> 24;
+ s->ivec[2] = bo[0] >> 16;
+ s->ivec[1] = bo[0] >> 8;
+ s->ivec[0] = bo[0];
+
+ return;
+}
+
+void
+bfCBCdecrypt(uchar *buf, int n, BFstate *s)
+{
+ int i;
+ uchar *p;
+ u32int b, bo[2], bi[2], xr[2];
+
+ assert((n & 7) == 0);
+
+ bo[0] = s->ivec[0] | ((u32int) s->ivec[1]<<8) | ((u32int)s->ivec[2]<<16) | ((u32int)s->ivec[3]<<24);
+ bo[1] = s->ivec[4] | ((u32int) s->ivec[5]<<8) | ((u32int)s->ivec[6]<<16) | ((u32int)s->ivec[7]<<24);
+
+ for(i=0; i < n; i += 8, buf += 8) {
+ bi[0] = buf[0] | ((u32int) buf[1]<<8) | ((u32int)buf[2]<<16) | ((u32int)buf[3]<<24);
+ bi[1] = buf[4] | ((u32int) buf[5]<<8) | ((u32int)buf[6]<<16) | ((u32int)buf[7]<<24);
+
+ xr[0] = bi[0];
+ xr[1] = bi[1];
+
+ bfdecrypt(bi, s);
+
+ bo[0] ^= bi[0];
+ bo[1] ^= bi[1];
+
+ p = buf;
+ b = bo[0];
+ *p++ = b;
+ b >>= 8;
+ *p++ = b;
+ b >>= 8;
+ *p++ = b;
+ b >>= 8;
+ *p++ = b;
+
+ b = bo[1];
+ *p++ = b;
+ b >>= 8;
+ *p++ = b;
+ b >>= 8;
+ *p++ = b;
+ b >>= 8;
+ *p = b;
+
+ bo[0] = xr[0];
+ bo[1] = xr[1];
+ }
+
+ s->ivec[7] = bo[1] >> 24;
+ s->ivec[6] = bo[1] >> 16;
+ s->ivec[5] = bo[1] >> 8;
+ s->ivec[4] = bo[1];
+
+ s->ivec[3] = bo[0] >> 24;
+ s->ivec[2] = bo[0] >> 16;
+ s->ivec[1] = bo[0] >> 8;
+ s->ivec[0] = bo[0];
+
+ return;
+}
+
+void
+bfECBencrypt(uchar *buf, int n, BFstate *s)
+{
+ int i;
+ u32int b[2];
+
+ for(i=0; i < n; i += 8, buf += 8) {
+ b[0] = buf[0] | ((u32int) buf[1]<<8) | ((u32int)buf[2]<<16) | ((u32int)buf[3]<<24);
+ b[1] = buf[4] | ((u32int) buf[5]<<8) | ((u32int)buf[6]<<16) | ((u32int)buf[7]<<24);
+
+ bfencrypt(b, s);
+
+ buf[7] = b[1] >> 24;
+ buf[6] = b[1] >> 16;
+ buf[5] = b[1] >> 8;
+ buf[4] = b[1];
+
+ buf[3] = b[0] >> 24;
+ buf[2] = b[0] >> 16;
+ buf[1] = b[0] >> 8;
+ buf[0] = b[0];
+ }
+
+ return;
+}
+
+void
+bfECBdecrypt(uchar *buf, int n, BFstate *s)
+{
+ int i;
+ u32int b[2];
+
+ for(i=0; i < n; i += 8, buf += 8) {
+ b[0] = buf[0] | ((u32int) buf[1]<<8) | ((u32int)buf[2]<<16) | ((u32int)buf[3]<<24);
+ b[1] = buf[4] | ((u32int) buf[5]<<8) | ((u32int)buf[6]<<16) | ((u32int)buf[7]<<24);
+
+ bfdecrypt(b, s);
+
+ buf[7] = b[1] >> 24;
+ buf[6] = b[1] >> 16;
+ buf[5] = b[1] >> 8;
+ buf[4] = b[1];
+
+ buf[3] = b[0] >> 24;
+ buf[2] = b[0] >> 16;
+ buf[1] = b[0] >> 8;
+ buf[0] = b[0];
+ }
+
+ return;
+}
+
+static void
+bfencrypt(u32int *b, BFstate *s)
+{
+ int i;
+ u32int l, r;
+ u32int *pb, *sb;
+
+ l = b[0];
+ r = b[1];
+
+ pb = s->pbox;
+ sb = s->sbox;
+
+ l ^= pb[0];
+
+ for(i=1; i<16; i += 2) {
+ r ^= pb[i];
+ r ^= ( (sb[ (uchar) (l>>24)] + sb[256 + ((uchar) (l>>16))]) ^
+ sb[512 + ((uchar) (l>>8))]) + sb[768 +((uchar) l)];
+
+ l ^= pb[i+1];
+ l ^= ( (sb[ (uchar) (r>>24)] + sb[256 + ((uchar) (r>>16))]) ^
+ sb[512 + ((uchar) (r>>8))]) + sb[768 +((uchar) r)];
+ }
+
+ r ^= pb[BFrounds+1];
+
+ /* sic */
+ b[0] = r;
+ b[1] = l;
+
+ return;
+}
+
+static void
+bfdecrypt(u32int *b, BFstate *s)
+{
+ int i;
+ u32int l, r;
+ u32int *pb, *sb;
+
+ l = b[0];
+ r = b[1];
+
+ pb = s->pbox;
+ sb = s->sbox;
+
+ l ^= pb[BFrounds+1];
+
+ for(i=16; i > 0; i -= 2) {
+ r ^= pb[i];
+ r ^= ( (sb[ (uchar) (l>>24)] + sb[256 + ((uchar) (l>>16))]) ^
+ sb[512 + ((uchar) (l>>8))]) + sb[768 +((uchar) l)];
+
+ l ^= pb[i-1];
+ l ^= ( (sb[ (uchar) (r>>24)] + sb[256 + ((uchar) (r>>16))]) ^
+ sb[512 + ((uchar) (r>>8))]) + sb[768 +((uchar) r)];
+ }
+
+ r ^= pb[0];
+
+ /* sic */
+ b[0] = r;
+ b[1] = l;
+
+ return;
+}
+
+static u32int pbox[BFrounds+2] = {
+ 0x243f6a88, 0x85a308d3, 0x13198a2e, 0x03707344,
+ 0xa4093822, 0x299f31d0, 0x082efa98, 0xec4e6c89,
+ 0x452821e6, 0x38d01377, 0xbe5466cf, 0x34e90c6c,
+ 0xc0ac29b7, 0xc97c50dd, 0x3f84d5b5, 0xb5470917,
+ 0x9216d5d9, 0x8979fb1b
+};
+
+static u32int sbox[1024] = {
+ 0xd1310ba6L, 0x98dfb5acL, 0x2ffd72dbL, 0xd01adfb7L,
+ 0xb8e1afedL, 0x6a267e96L, 0xba7c9045L, 0xf12c7f99L,
+ 0x24a19947L, 0xb3916cf7L, 0x0801f2e2L, 0x858efc16L,
+ 0x636920d8L, 0x71574e69L, 0xa458fea3L, 0xf4933d7eL,
+ 0x0d95748fL, 0x728eb658L, 0x718bcd58L, 0x82154aeeL,
+ 0x7b54a41dL, 0xc25a59b5L, 0x9c30d539L, 0x2af26013L,
+ 0xc5d1b023L, 0x286085f0L, 0xca417918L, 0xb8db38efL,
+ 0x8e79dcb0L, 0x603a180eL, 0x6c9e0e8bL, 0xb01e8a3eL,
+ 0xd71577c1L, 0xbd314b27L, 0x78af2fdaL, 0x55605c60L,
+ 0xe65525f3L, 0xaa55ab94L, 0x57489862L, 0x63e81440L,
+ 0x55ca396aL, 0x2aab10b6L, 0xb4cc5c34L, 0x1141e8ceL,
+ 0xa15486afL, 0x7c72e993L, 0xb3ee1411L, 0x636fbc2aL,
+ 0x2ba9c55dL, 0x741831f6L, 0xce5c3e16L, 0x9b87931eL,
+ 0xafd6ba33L, 0x6c24cf5cL, 0x7a325381L, 0x28958677L,
+ 0x3b8f4898L, 0x6b4bb9afL, 0xc4bfe81bL, 0x66282193L,
+ 0x61d809ccL, 0xfb21a991L, 0x487cac60L, 0x5dec8032L,
+ 0xef845d5dL, 0xe98575b1L, 0xdc262302L, 0xeb651b88L,
+ 0x23893e81L, 0xd396acc5L, 0x0f6d6ff3L, 0x83f44239L,
+ 0x2e0b4482L, 0xa4842004L, 0x69c8f04aL, 0x9e1f9b5eL,
+ 0x21c66842L, 0xf6e96c9aL, 0x670c9c61L, 0xabd388f0L,
+ 0x6a51a0d2L, 0xd8542f68L, 0x960fa728L, 0xab5133a3L,
+ 0x6eef0b6cL, 0x137a3be4L, 0xba3bf050L, 0x7efb2a98L,
+ 0xa1f1651dL, 0x39af0176L, 0x66ca593eL, 0x82430e88L,
+ 0x8cee8619L, 0x456f9fb4L, 0x7d84a5c3L, 0x3b8b5ebeL,
+ 0xe06f75d8L, 0x85c12073L, 0x401a449fL, 0x56c16aa6L,
+ 0x4ed3aa62L, 0x363f7706L, 0x1bfedf72L, 0x429b023dL,
+ 0x37d0d724L, 0xd00a1248L, 0xdb0fead3L, 0x49f1c09bL,
+ 0x075372c9L, 0x80991b7bL, 0x25d479d8L, 0xf6e8def7L,
+ 0xe3fe501aL, 0xb6794c3bL, 0x976ce0bdL, 0x04c006baL,
+ 0xc1a94fb6L, 0x409f60c4L, 0x5e5c9ec2L, 0x196a2463L,
+ 0x68fb6fafL, 0x3e6c53b5L, 0x1339b2ebL, 0x3b52ec6fL,
+ 0x6dfc511fL, 0x9b30952cL, 0xcc814544L, 0xaf5ebd09L,
+ 0xbee3d004L, 0xde334afdL, 0x660f2807L, 0x192e4bb3L,
+ 0xc0cba857L, 0x45c8740fL, 0xd20b5f39L, 0xb9d3fbdbL,
+ 0x5579c0bdL, 0x1a60320aL, 0xd6a100c6L, 0x402c7279L,
+ 0x679f25feL, 0xfb1fa3ccL, 0x8ea5e9f8L, 0xdb3222f8L,
+ 0x3c7516dfL, 0xfd616b15L, 0x2f501ec8L, 0xad0552abL,
+ 0x323db5faL, 0xfd238760L, 0x53317b48L, 0x3e00df82L,
+ 0x9e5c57bbL, 0xca6f8ca0L, 0x1a87562eL, 0xdf1769dbL,
+ 0xd542a8f6L, 0x287effc3L, 0xac6732c6L, 0x8c4f5573L,
+ 0x695b27b0L, 0xbbca58c8L, 0xe1ffa35dL, 0xb8f011a0L,
+ 0x10fa3d98L, 0xfd2183b8L, 0x4afcb56cL, 0x2dd1d35bL,
+ 0x9a53e479L, 0xb6f84565L, 0xd28e49bcL, 0x4bfb9790L,
+ 0xe1ddf2daL, 0xa4cb7e33L, 0x62fb1341L, 0xcee4c6e8L,
+ 0xef20cadaL, 0x36774c01L, 0xd07e9efeL, 0x2bf11fb4L,
+ 0x95dbda4dL, 0xae909198L, 0xeaad8e71L, 0x6b93d5a0L,
+ 0xd08ed1d0L, 0xafc725e0L, 0x8e3c5b2fL, 0x8e7594b7L,
+ 0x8ff6e2fbL, 0xf2122b64L, 0x8888b812L, 0x900df01cL,
+ 0x4fad5ea0L, 0x688fc31cL, 0xd1cff191L, 0xb3a8c1adL,
+ 0x2f2f2218L, 0xbe0e1777L, 0xea752dfeL, 0x8b021fa1L,
+ 0xe5a0cc0fL, 0xb56f74e8L, 0x18acf3d6L, 0xce89e299L,
+ 0xb4a84fe0L, 0xfd13e0b7L, 0x7cc43b81L, 0xd2ada8d9L,
+ 0x165fa266L, 0x80957705L, 0x93cc7314L, 0x211a1477L,
+ 0xe6ad2065L, 0x77b5fa86L, 0xc75442f5L, 0xfb9d35cfL,
+ 0xebcdaf0cL, 0x7b3e89a0L, 0xd6411bd3L, 0xae1e7e49L,
+ 0x00250e2dL, 0x2071b35eL, 0x226800bbL, 0x57b8e0afL,
+ 0x2464369bL, 0xf009b91eL, 0x5563911dL, 0x59dfa6aaL,
+ 0x78c14389L, 0xd95a537fL, 0x207d5ba2L, 0x02e5b9c5L,
+ 0x83260376L, 0x6295cfa9L, 0x11c81968L, 0x4e734a41L,
+ 0xb3472dcaL, 0x7b14a94aL, 0x1b510052L, 0x9a532915L,
+ 0xd60f573fL, 0xbc9bc6e4L, 0x2b60a476L, 0x81e67400L,
+ 0x08ba6fb5L, 0x571be91fL, 0xf296ec6bL, 0x2a0dd915L,
+ 0xb6636521L, 0xe7b9f9b6L, 0xff34052eL, 0xc5855664L,
+ 0x53b02d5dL, 0xa99f8fa1L, 0x08ba4799L, 0x6e85076aL,
+ 0x4b7a70e9L, 0xb5b32944L, 0xdb75092eL, 0xc4192623L,
+ 0xad6ea6b0L, 0x49a7df7dL, 0x9cee60b8L, 0x8fedb266L,
+ 0xecaa8c71L, 0x699a17ffL, 0x5664526cL, 0xc2b19ee1L,
+ 0x193602a5L, 0x75094c29L, 0xa0591340L, 0xe4183a3eL,
+ 0x3f54989aL, 0x5b429d65L, 0x6b8fe4d6L, 0x99f73fd6L,
+ 0xa1d29c07L, 0xefe830f5L, 0x4d2d38e6L, 0xf0255dc1L,
+ 0x4cdd2086L, 0x8470eb26L, 0x6382e9c6L, 0x021ecc5eL,
+ 0x09686b3fL, 0x3ebaefc9L, 0x3c971814L, 0x6b6a70a1L,
+ 0x687f3584L, 0x52a0e286L, 0xb79c5305L, 0xaa500737L,
+ 0x3e07841cL, 0x7fdeae5cL, 0x8e7d44ecL, 0x5716f2b8L,
+ 0xb03ada37L, 0xf0500c0dL, 0xf01c1f04L, 0x0200b3ffL,
+ 0xae0cf51aL, 0x3cb574b2L, 0x25837a58L, 0xdc0921bdL,
+ 0xd19113f9L, 0x7ca92ff6L, 0x94324773L, 0x22f54701L,
+ 0x3ae5e581L, 0x37c2dadcL, 0xc8b57634L, 0x9af3dda7L,
+ 0xa9446146L, 0x0fd0030eL, 0xecc8c73eL, 0xa4751e41L,
+ 0xe238cd99L, 0x3bea0e2fL, 0x3280bba1L, 0x183eb331L,
+ 0x4e548b38L, 0x4f6db908L, 0x6f420d03L, 0xf60a04bfL,
+ 0x2cb81290L, 0x24977c79L, 0x5679b072L, 0xbcaf89afL,
+ 0xde9a771fL, 0xd9930810L, 0xb38bae12L, 0xdccf3f2eL,
+ 0x5512721fL, 0x2e6b7124L, 0x501adde6L, 0x9f84cd87L,
+ 0x7a584718L, 0x7408da17L, 0xbc9f9abcL, 0xe94b7d8cL,
+ 0xec7aec3aL, 0xdb851dfaL, 0x63094366L, 0xc464c3d2L,
+ 0xef1c1847L, 0x3215d908L, 0xdd433b37L, 0x24c2ba16L,
+ 0x12a14d43L, 0x2a65c451L, 0x50940002L, 0x133ae4ddL,
+ 0x71dff89eL, 0x10314e55L, 0x81ac77d6L, 0x5f11199bL,
+ 0x043556f1L, 0xd7a3c76bL, 0x3c11183bL, 0x5924a509L,
+ 0xf28fe6edL, 0x97f1fbfaL, 0x9ebabf2cL, 0x1e153c6eL,
+ 0x86e34570L, 0xeae96fb1L, 0x860e5e0aL, 0x5a3e2ab3L,
+ 0x771fe71cL, 0x4e3d06faL, 0x2965dcb9L, 0x99e71d0fL,
+ 0x803e89d6L, 0x5266c825L, 0x2e4cc978L, 0x9c10b36aL,
+ 0xc6150ebaL, 0x94e2ea78L, 0xa5fc3c53L, 0x1e0a2df4L,
+ 0xf2f74ea7L, 0x361d2b3dL, 0x1939260fL, 0x19c27960L,
+ 0x5223a708L, 0xf71312b6L, 0xebadfe6eL, 0xeac31f66L,
+ 0xe3bc4595L, 0xa67bc883L, 0xb17f37d1L, 0x018cff28L,
+ 0xc332ddefL, 0xbe6c5aa5L, 0x65582185L, 0x68ab9802L,
+ 0xeecea50fL, 0xdb2f953bL, 0x2aef7dadL, 0x5b6e2f84L,
+ 0x1521b628L, 0x29076170L, 0xecdd4775L, 0x619f1510L,
+ 0x13cca830L, 0xeb61bd96L, 0x0334fe1eL, 0xaa0363cfL,
+ 0xb5735c90L, 0x4c70a239L, 0xd59e9e0bL, 0xcbaade14L,
+ 0xeecc86bcL, 0x60622ca7L, 0x9cab5cabL, 0xb2f3846eL,
+ 0x648b1eafL, 0x19bdf0caL, 0xa02369b9L, 0x655abb50L,
+ 0x40685a32L, 0x3c2ab4b3L, 0x319ee9d5L, 0xc021b8f7L,
+ 0x9b540b19L, 0x875fa099L, 0x95f7997eL, 0x623d7da8L,
+ 0xf837889aL, 0x97e32d77L, 0x11ed935fL, 0x16681281L,
+ 0x0e358829L, 0xc7e61fd6L, 0x96dedfa1L, 0x7858ba99L,
+ 0x57f584a5L, 0x1b227263L, 0x9b83c3ffL, 0x1ac24696L,
+ 0xcdb30aebL, 0x532e3054L, 0x8fd948e4L, 0x6dbc3128L,
+ 0x58ebf2efL, 0x34c6ffeaL, 0xfe28ed61L, 0xee7c3c73L,
+ 0x5d4a14d9L, 0xe864b7e3L, 0x42105d14L, 0x203e13e0L,
+ 0x45eee2b6L, 0xa3aaabeaL, 0xdb6c4f15L, 0xfacb4fd0L,
+ 0xc742f442L, 0xef6abbb5L, 0x654f3b1dL, 0x41cd2105L,
+ 0xd81e799eL, 0x86854dc7L, 0xe44b476aL, 0x3d816250L,
+ 0xcf62a1f2L, 0x5b8d2646L, 0xfc8883a0L, 0xc1c7b6a3L,
+ 0x7f1524c3L, 0x69cb7492L, 0x47848a0bL, 0x5692b285L,
+ 0x095bbf00L, 0xad19489dL, 0x1462b174L, 0x23820e00L,
+ 0x58428d2aL, 0x0c55f5eaL, 0x1dadf43eL, 0x233f7061L,
+ 0x3372f092L, 0x8d937e41L, 0xd65fecf1L, 0x6c223bdbL,
+ 0x7cde3759L, 0xcbee7460L, 0x4085f2a7L, 0xce77326eL,
+ 0xa6078084L, 0x19f8509eL, 0xe8efd855L, 0x61d99735L,
+ 0xa969a7aaL, 0xc50c06c2L, 0x5a04abfcL, 0x800bcadcL,
+ 0x9e447a2eL, 0xc3453484L, 0xfdd56705L, 0x0e1e9ec9L,
+ 0xdb73dbd3L, 0x105588cdL, 0x675fda79L, 0xe3674340L,
+ 0xc5c43465L, 0x713e38d8L, 0x3d28f89eL, 0xf16dff20L,
+ 0x153e21e7L, 0x8fb03d4aL, 0xe6e39f2bL, 0xdb83adf7L,
+ 0xe93d5a68L, 0x948140f7L, 0xf64c261cL, 0x94692934L,
+ 0x411520f7L, 0x7602d4f7L, 0xbcf46b2eL, 0xd4a20068L,
+ 0xd4082471L, 0x3320f46aL, 0x43b7d4b7L, 0x500061afL,
+ 0x1e39f62eL, 0x97244546L, 0x14214f74L, 0xbf8b8840L,
+ 0x4d95fc1dL, 0x96b591afL, 0x70f4ddd3L, 0x66a02f45L,
+ 0xbfbc09ecL, 0x03bd9785L, 0x7fac6dd0L, 0x31cb8504L,
+ 0x96eb27b3L, 0x55fd3941L, 0xda2547e6L, 0xabca0a9aL,
+ 0x28507825L, 0x530429f4L, 0x0a2c86daL, 0xe9b66dfbL,
+ 0x68dc1462L, 0xd7486900L, 0x680ec0a4L, 0x27a18deeL,
+ 0x4f3ffea2L, 0xe887ad8cL, 0xb58ce006L, 0x7af4d6b6L,
+ 0xaace1e7cL, 0xd3375fecL, 0xce78a399L, 0x406b2a42L,
+ 0x20fe9e35L, 0xd9f385b9L, 0xee39d7abL, 0x3b124e8bL,
+ 0x1dc9faf7L, 0x4b6d1856L, 0x26a36631L, 0xeae397b2L,
+ 0x3a6efa74L, 0xdd5b4332L, 0x6841e7f7L, 0xca7820fbL,
+ 0xfb0af54eL, 0xd8feb397L, 0x454056acL, 0xba489527L,
+ 0x55533a3aL, 0x20838d87L, 0xfe6ba9b7L, 0xd096954bL,
+ 0x55a867bcL, 0xa1159a58L, 0xcca92963L, 0x99e1db33L,
+ 0xa62a4a56L, 0x3f3125f9L, 0x5ef47e1cL, 0x9029317cL,
+ 0xfdf8e802L, 0x04272f70L, 0x80bb155cL, 0x05282ce3L,
+ 0x95c11548L, 0xe4c66d22L, 0x48c1133fL, 0xc70f86dcL,
+ 0x07f9c9eeL, 0x41041f0fL, 0x404779a4L, 0x5d886e17L,
+ 0x325f51ebL, 0xd59bc0d1L, 0xf2bcc18fL, 0x41113564L,
+ 0x257b7834L, 0x602a9c60L, 0xdff8e8a3L, 0x1f636c1bL,
+ 0x0e12b4c2L, 0x02e1329eL, 0xaf664fd1L, 0xcad18115L,
+ 0x6b2395e0L, 0x333e92e1L, 0x3b240b62L, 0xeebeb922L,
+ 0x85b2a20eL, 0xe6ba0d99L, 0xde720c8cL, 0x2da2f728L,
+ 0xd0127845L, 0x95b794fdL, 0x647d0862L, 0xe7ccf5f0L,
+ 0x5449a36fL, 0x877d48faL, 0xc39dfd27L, 0xf33e8d1eL,
+ 0x0a476341L, 0x992eff74L, 0x3a6f6eabL, 0xf4f8fd37L,
+ 0xa812dc60L, 0xa1ebddf8L, 0x991be14cL, 0xdb6e6b0dL,
+ 0xc67b5510L, 0x6d672c37L, 0x2765d43bL, 0xdcd0e804L,
+ 0xf1290dc7L, 0xcc00ffa3L, 0xb5390f92L, 0x690fed0bL,
+ 0x667b9ffbL, 0xcedb7d9cL, 0xa091cf0bL, 0xd9155ea3L,
+ 0xbb132f88L, 0x515bad24L, 0x7b9479bfL, 0x763bd6ebL,
+ 0x37392eb3L, 0xcc115979L, 0x8026e297L, 0xf42e312dL,
+ 0x6842ada7L, 0xc66a2b3bL, 0x12754cccL, 0x782ef11cL,
+ 0x6a124237L, 0xb79251e7L, 0x06a1bbe6L, 0x4bfb6350L,
+ 0x1a6b1018L, 0x11caedfaL, 0x3d25bdd8L, 0xe2e1c3c9L,
+ 0x44421659L, 0x0a121386L, 0xd90cec6eL, 0xd5abea2aL,
+ 0x64af674eL, 0xda86a85fL, 0xbebfe988L, 0x64e4c3feL,
+ 0x9dbc8057L, 0xf0f7c086L, 0x60787bf8L, 0x6003604dL,
+ 0xd1fd8346L, 0xf6381fb0L, 0x7745ae04L, 0xd736fcccL,
+ 0x83426b33L, 0xf01eab71L, 0xb0804187L, 0x3c005e5fL,
+ 0x77a057beL, 0xbde8ae24L, 0x55464299L, 0xbf582e61L,
+ 0x4e58f48fL, 0xf2ddfda2L, 0xf474ef38L, 0x8789bdc2L,
+ 0x5366f9c3L, 0xc8b38e74L, 0xb475f255L, 0x46fcd9b9L,
+ 0x7aeb2661L, 0x8b1ddf84L, 0x846a0e79L, 0x915f95e2L,
+ 0x466e598eL, 0x20b45770L, 0x8cd55591L, 0xc902de4cL,
+ 0xb90bace1L, 0xbb8205d0L, 0x11a86248L, 0x7574a99eL,
+ 0xb77f19b6L, 0xe0a9dc09L, 0x662d09a1L, 0xc4324633L,
+ 0xe85a1f02L, 0x09f0be8cL, 0x4a99a025L, 0x1d6efe10L,
+ 0x1ab93d1dL, 0x0ba5a4dfL, 0xa186f20fL, 0x2868f169L,
+ 0xdcb7da83L, 0x573906feL, 0xa1e2ce9bL, 0x4fcd7f52L,
+ 0x50115e01L, 0xa70683faL, 0xa002b5c4L, 0x0de6d027L,
+ 0x9af88c27L, 0x773f8641L, 0xc3604c06L, 0x61a806b5L,
+ 0xf0177a28L, 0xc0f586e0L, 0x006058aaL, 0x30dc7d62L,
+ 0x11e69ed7L, 0x2338ea63L, 0x53c2dd94L, 0xc2c21634L,
+ 0xbbcbee56L, 0x90bcb6deL, 0xebfc7da1L, 0xce591d76L,
+ 0x6f05e409L, 0x4b7c0188L, 0x39720a3dL, 0x7c927c24L,
+ 0x86e3725fL, 0x724d9db9L, 0x1ac15bb4L, 0xd39eb8fcL,
+ 0xed545578L, 0x08fca5b5L, 0xd83d7cd3L, 0x4dad0fc4L,
+ 0x1e50ef5eL, 0xb161e6f8L, 0xa28514d9L, 0x6c51133cL,
+ 0x6fd5c7e7L, 0x56e14ec4L, 0x362abfceL, 0xddc6c837L,
+ 0xd79a3234L, 0x92638212L, 0x670efa8eL, 0x406000e0L,
+ 0x3a39ce37L, 0xd3faf5cfL, 0xabc27737L, 0x5ac52d1bL,
+ 0x5cb0679eL, 0x4fa33742L, 0xd3822740L, 0x99bc9bbeL,
+ 0xd5118e9dL, 0xbf0f7315L, 0xd62d1c7eL, 0xc700c47bL,
+ 0xb78c1b6bL, 0x21a19045L, 0xb26eb1beL, 0x6a366eb4L,
+ 0x5748ab2fL, 0xbc946e79L, 0xc6a376d2L, 0x6549c2c8L,
+ 0x530ff8eeL, 0x468dde7dL, 0xd5730a1dL, 0x4cd04dc6L,
+ 0x2939bbdbL, 0xa9ba4650L, 0xac9526e8L, 0xbe5ee304L,
+ 0xa1fad5f0L, 0x6a2d519aL, 0x63ef8ce2L, 0x9a86ee22L,
+ 0xc089c2b8L, 0x43242ef6L, 0xa51e03aaL, 0x9cf2d0a4L,
+ 0x83c061baL, 0x9be96a4dL, 0x8fe51550L, 0xba645bd6L,
+ 0x2826a2f9L, 0xa73a3ae1L, 0x4ba99586L, 0xef5562e9L,
+ 0xc72fefd3L, 0xf752f7daL, 0x3f046f69L, 0x77fa0a59L,
+ 0x80e4a915L, 0x87b08601L, 0x9b09e6adL, 0x3b3ee593L,
+ 0xe990fd5aL, 0x9e34d797L, 0x2cf0b7d9L, 0x022b8b51L,
+ 0x96d5ac3aL, 0x017da67dL, 0xd1cf3ed6L, 0x7c7d2d28L,
+ 0x1f9f25cfL, 0xadf2b89bL, 0x5ad6b472L, 0x5a88f54cL,
+ 0xe029ac71L, 0xe019a5e6L, 0x47b0acfdL, 0xed93fa9bL,
+ 0xe8d3c48dL, 0x283b57ccL, 0xf8d56629L, 0x79132e28L,
+ 0x785f0191L, 0xed756055L, 0xf7960e44L, 0xe3d35e8cL,
+ 0x15056dd4L, 0x88f46dbaL, 0x03a16125L, 0x0564f0bdL,
+ 0xc3eb9e15L, 0x3c9057a2L, 0x97271aecL, 0xa93a072aL,
+ 0x1b3f6d9bL, 0x1e6321f5L, 0xf59c66fbL, 0x26dcf319L,
+ 0x7533d928L, 0xb155fdf5L, 0x03563482L, 0x8aba3cbbL,
+ 0x28517711L, 0xc20ad9f8L, 0xabcc5167L, 0xccad925fL,
+ 0x4de81751L, 0x3830dc8eL, 0x379d5862L, 0x9320f991L,
+ 0xea7a90c2L, 0xfb3e7bceL, 0x5121ce64L, 0x774fbe32L,
+ 0xa8b6e37eL, 0xc3293d46L, 0x48de5369L, 0x6413e680L,
+ 0xa2ae0810L, 0xdd6db224L, 0x69852dfdL, 0x09072166L,
+ 0xb39a460aL, 0x6445c0ddL, 0x586cdecfL, 0x1c20c8aeL,
+ 0x5bbef7ddL, 0x1b588d40L, 0xccd2017fL, 0x6bb4e3bbL,
+ 0xdda26a7eL, 0x3a59ff45L, 0x3e350a44L, 0xbcb4cdd5L,
+ 0x72eacea8L, 0xfa6484bbL, 0x8d6612aeL, 0xbf3c6f47L,
+ 0xd29be463L, 0x542f5d9eL, 0xaec2771bL, 0xf64e6370L,
+ 0x740e0d8dL, 0xe75b1357L, 0xf8721671L, 0xaf537d5dL,
+ 0x4040cb08L, 0x4eb4e2ccL, 0x34d2466aL, 0x0115af84L,
+ 0xe1b00428L, 0x95983a1dL, 0x06b89fb4L, 0xce6ea048L,
+ 0x6f3f3b82L, 0x3520ab82L, 0x011a1d4bL, 0x277227f8L,
+ 0x611560b1L, 0xe7933fdcL, 0xbb3a792bL, 0x344525bdL,
+ 0xa08839e1L, 0x51ce794bL, 0x2f32c9b7L, 0xa01fbac9L,
+ 0xe01cc87eL, 0xbcc7d1f6L, 0xcf0111c3L, 0xa1e8aac7L,
+ 0x1a908749L, 0xd44fbd9aL, 0xd0dadecbL, 0xd50ada38L,
+ 0x0339c32aL, 0xc6913667L, 0x8df9317cL, 0xe0b12b4fL,
+ 0xf79e59b7L, 0x43f5bb3aL, 0xf2d519ffL, 0x27d9459cL,
+ 0xbf97222cL, 0x15e6fc2aL, 0x0f91fc71L, 0x9b941525L,
+ 0xfae59361L, 0xceb69cebL, 0xc2a86459L, 0x12baa8d1L,
+ 0xb6c1075eL, 0xe3056a0cL, 0x10d25065L, 0xcb03a442L,
+ 0xe0ec6e0eL, 0x1698db3bL, 0x4c98a0beL, 0x3278e964L,
+ 0x9f1f9532L, 0xe0d392dfL, 0xd3a0342bL, 0x8971f21eL,
+ 0x1b0a7441L, 0x4ba3348cL, 0xc5be7120L, 0xc37632d8L,
+ 0xdf359f8dL, 0x9b992f2eL, 0xe60b6f47L, 0x0fe3f11dL,
+ 0xe54cda54L, 0x1edad891L, 0xce6279cfL, 0xcd3e7e6fL,
+ 0x1618b166L, 0xfd2c1d05L, 0x848fd2c5L, 0xf6fb2299L,
+ 0xf523f357L, 0xa6327623L, 0x93a83531L, 0x56cccd02L,
+ 0xacf08162L, 0x5a75ebb5L, 0x6e163697L, 0x88d273ccL,
+ 0xde966292L, 0x81b949d0L, 0x4c50901bL, 0x71c65614L,
+ 0xe6c6c7bdL, 0x327a140aL, 0x45e1d006L, 0xc3f27b9aL,
+ 0xc9aa53fdL, 0x62a80f00L, 0xbb25bfe2L, 0x35bdd2f6L,
+ 0x71126905L, 0xb2040222L, 0xb6cbcf7cL, 0xcd769c2bL,
+ 0x53113ec0L, 0x1640e3d3L, 0x38abbd60L, 0x2547adf0L,
+ 0xba38209cL, 0xf746ce76L, 0x77afa1c5L, 0x20756060L,
+ 0x85cbfe4eL, 0x8ae88dd8L, 0x7aaaf9b0L, 0x4cf9aa7eL,
+ 0x1948c25cL, 0x02fb8a8cL, 0x01c36ae4L, 0xd6ebe1f9L,
+ 0x90d4f869L, 0xa65cdea0L, 0x3f09252dL, 0xc208e69fL,
+ 0xb74e6132L, 0xce77e25bL, 0x578fdfe3L, 0x3ac372e6L,
+};
+
+
--- /dev/null
+++ b/libsec/port/decodepem.c
@@ -1,0 +1,89 @@
+#include <u.h>
+#include <libc.h>
+#include <mp.h>
+#include <libsec.h>
+
+#define STRLEN(s) (sizeof(s)-1)
+
+uchar*
+decodePEM(char *s, char *type, int *len, char **new_s)
+{
+ uchar *d;
+ char *t, *e, *tt;
+ int n;
+
+ *len = 0;
+
+ /*
+ * find the correct section of the file, stripping garbage at the beginning and end.
+ * the data is delimited by -----BEGIN <type>-----\n and -----END <type>-----\n
+ */
+ n = strlen(type);
+ e = strchr(s, '\0');
+ for(t = s; t != nil && t < e; ){
+ tt = t;
+ t = strchr(tt, '\n');
+ if(t != nil)
+ t++;
+ if(strncmp(tt, "-----BEGIN ", STRLEN("-----BEGIN ")) == 0
+ && strncmp(&tt[STRLEN("-----BEGIN ")], type, n) == 0
+ && strncmp(&tt[STRLEN("-----BEGIN ")+n], "-----\n", STRLEN("-----\n")) == 0)
+ break;
+ }
+ for(tt = t; tt != nil && tt < e; tt++){
+ if(strncmp(tt, "-----END ", STRLEN("-----END ")) == 0
+ && strncmp(&tt[STRLEN("-----END ")], type, n) == 0
+ && strncmp(&tt[STRLEN("-----END ")+n], "-----\n", STRLEN("-----\n")) == 0)
+ break;
+ tt = strchr(tt, '\n');
+ if(tt == nil)
+ break;
+ }
+ if(tt == nil || tt == e){
+ werrstr("incorrect .pem file format: bad header or trailer");
+ return nil;
+ }
+
+ if(new_s)
+ *new_s = tt+1;
+ n = ((tt - t) * 6 + 7) / 8;
+ d = malloc(n);
+ if(d == nil){
+ werrstr("out of memory");
+ return nil;
+ }
+ n = dec64(d, n, t, tt - t);
+ if(n < 0){
+ free(d);
+ werrstr("incorrect .pem file format: bad base64 encoded data");
+ return nil;
+ }
+ *len = n;
+ return d;
+}
+
+PEMChain*
+decodepemchain(char *s, char *type)
+{
+ PEMChain *first = nil, *last = nil, *chp;
+ uchar *d;
+ char *e;
+ int n;
+
+ e = strchr(s, '\0');
+ while (s < e) {
+ d = decodePEM(s, type, &n, &s);
+ if(d == nil)
+ break;
+ chp = malloc(sizeof(PEMChain));
+ chp->next = nil;
+ chp->pem = d;
+ chp->pemlen = n;
+ if (first == nil)
+ first = chp;
+ else
+ last->next = chp;
+ last = chp;
+ }
+ return first;
+}
--- /dev/null
+++ b/libsec/port/des.c
@@ -1,0 +1,480 @@
+#include "os.h"
+#include <libsec.h>
+
+/*
+ * integrated sbox & p perm
+ */
+static u32int spbox[] = {
+
+0x00808200,0x00000000,0x00008000,0x00808202,0x00808002,0x00008202,0x00000002,0x00008000,
+0x00000200,0x00808200,0x00808202,0x00000200,0x00800202,0x00808002,0x00800000,0x00000002,
+0x00000202,0x00800200,0x00800200,0x00008200,0x00008200,0x00808000,0x00808000,0x00800202,
+0x00008002,0x00800002,0x00800002,0x00008002,0x00000000,0x00000202,0x00008202,0x00800000,
+0x00008000,0x00808202,0x00000002,0x00808000,0x00808200,0x00800000,0x00800000,0x00000200,
+0x00808002,0x00008000,0x00008200,0x00800002,0x00000200,0x00000002,0x00800202,0x00008202,
+0x00808202,0x00008002,0x00808000,0x00800202,0x00800002,0x00000202,0x00008202,0x00808200,
+0x00000202,0x00800200,0x00800200,0x00000000,0x00008002,0x00008200,0x00000000,0x00808002,
+
+0x40084010,0x40004000,0x00004000,0x00084010,0x00080000,0x00000010,0x40080010,0x40004010,
+0x40000010,0x40084010,0x40084000,0x40000000,0x40004000,0x00080000,0x00000010,0x40080010,
+0x00084000,0x00080010,0x40004010,0x00000000,0x40000000,0x00004000,0x00084010,0x40080000,
+0x00080010,0x40000010,0x00000000,0x00084000,0x00004010,0x40084000,0x40080000,0x00004010,
+0x00000000,0x00084010,0x40080010,0x00080000,0x40004010,0x40080000,0x40084000,0x00004000,
+0x40080000,0x40004000,0x00000010,0x40084010,0x00084010,0x00000010,0x00004000,0x40000000,
+0x00004010,0x40084000,0x00080000,0x40000010,0x00080010,0x40004010,0x40000010,0x00080010,
+0x00084000,0x00000000,0x40004000,0x00004010,0x40000000,0x40080010,0x40084010,0x00084000,
+
+0x00000104,0x04010100,0x00000000,0x04010004,0x04000100,0x00000000,0x00010104,0x04000100,
+0x00010004,0x04000004,0x04000004,0x00010000,0x04010104,0x00010004,0x04010000,0x00000104,
+0x04000000,0x00000004,0x04010100,0x00000100,0x00010100,0x04010000,0x04010004,0x00010104,
+0x04000104,0x00010100,0x00010000,0x04000104,0x00000004,0x04010104,0x00000100,0x04000000,
+0x04010100,0x04000000,0x00010004,0x00000104,0x00010000,0x04010100,0x04000100,0x00000000,
+0x00000100,0x00010004,0x04010104,0x04000100,0x04000004,0x00000100,0x00000000,0x04010004,
+0x04000104,0x00010000,0x04000000,0x04010104,0x00000004,0x00010104,0x00010100,0x04000004,
+0x04010000,0x04000104,0x00000104,0x04010000,0x00010104,0x00000004,0x04010004,0x00010100,
+
+0x80401000,0x80001040,0x80001040,0x00000040,0x00401040,0x80400040,0x80400000,0x80001000,
+0x00000000,0x00401000,0x00401000,0x80401040,0x80000040,0x00000000,0x00400040,0x80400000,
+0x80000000,0x00001000,0x00400000,0x80401000,0x00000040,0x00400000,0x80001000,0x00001040,
+0x80400040,0x80000000,0x00001040,0x00400040,0x00001000,0x00401040,0x80401040,0x80000040,
+0x00400040,0x80400000,0x00401000,0x80401040,0x80000040,0x00000000,0x00000000,0x00401000,
+0x00001040,0x00400040,0x80400040,0x80000000,0x80401000,0x80001040,0x80001040,0x00000040,
+0x80401040,0x80000040,0x80000000,0x00001000,0x80400000,0x80001000,0x00401040,0x80400040,
+0x80001000,0x00001040,0x00400000,0x80401000,0x00000040,0x00400000,0x00001000,0x00401040,
+
+0x00000080,0x01040080,0x01040000,0x21000080,0x00040000,0x00000080,0x20000000,0x01040000,
+0x20040080,0x00040000,0x01000080,0x20040080,0x21000080,0x21040000,0x00040080,0x20000000,
+0x01000000,0x20040000,0x20040000,0x00000000,0x20000080,0x21040080,0x21040080,0x01000080,
+0x21040000,0x20000080,0x00000000,0x21000000,0x01040080,0x01000000,0x21000000,0x00040080,
+0x00040000,0x21000080,0x00000080,0x01000000,0x20000000,0x01040000,0x21000080,0x20040080,
+0x01000080,0x20000000,0x21040000,0x01040080,0x20040080,0x00000080,0x01000000,0x21040000,
+0x21040080,0x00040080,0x21000000,0x21040080,0x01040000,0x00000000,0x20040000,0x21000000,
+0x00040080,0x01000080,0x20000080,0x00040000,0x00000000,0x20040000,0x01040080,0x20000080,
+
+0x10000008,0x10200000,0x00002000,0x10202008,0x10200000,0x00000008,0x10202008,0x00200000,
+0x10002000,0x00202008,0x00200000,0x10000008,0x00200008,0x10002000,0x10000000,0x00002008,
+0x00000000,0x00200008,0x10002008,0x00002000,0x00202000,0x10002008,0x00000008,0x10200008,
+0x10200008,0x00000000,0x00202008,0x10202000,0x00002008,0x00202000,0x10202000,0x10000000,
+0x10002000,0x00000008,0x10200008,0x00202000,0x10202008,0x00200000,0x00002008,0x10000008,
+0x00200000,0x10002000,0x10000000,0x00002008,0x10000008,0x10202008,0x00202000,0x10200000,
+0x00202008,0x10202000,0x00000000,0x10200008,0x00000008,0x00002000,0x10200000,0x00202008,
+0x00002000,0x00200008,0x10002008,0x00000000,0x10202000,0x10000000,0x00200008,0x10002008,
+
+0x00100000,0x02100001,0x02000401,0x00000000,0x00000400,0x02000401,0x00100401,0x02100400,
+0x02100401,0x00100000,0x00000000,0x02000001,0x00000001,0x02000000,0x02100001,0x00000401,
+0x02000400,0x00100401,0x00100001,0x02000400,0x02000001,0x02100000,0x02100400,0x00100001,
+0x02100000,0x00000400,0x00000401,0x02100401,0x00100400,0x00000001,0x02000000,0x00100400,
+0x02000000,0x00100400,0x00100000,0x02000401,0x02000401,0x02100001,0x02100001,0x00000001,
+0x00100001,0x02000000,0x02000400,0x00100000,0x02100400,0x00000401,0x00100401,0x02100400,
+0x00000401,0x02000001,0x02100401,0x02100000,0x00100400,0x00000000,0x00000001,0x02100401,
+0x00000000,0x00100401,0x02100000,0x00000400,0x02000001,0x02000400,0x00000400,0x00100001,
+
+0x08000820,0x00000800,0x00020000,0x08020820,0x08000000,0x08000820,0x00000020,0x08000000,
+0x00020020,0x08020000,0x08020820,0x00020800,0x08020800,0x00020820,0x00000800,0x00000020,
+0x08020000,0x08000020,0x08000800,0x00000820,0x00020800,0x00020020,0x08020020,0x08020800,
+0x00000820,0x00000000,0x00000000,0x08020020,0x08000020,0x08000800,0x00020820,0x00020000,
+0x00020820,0x00020000,0x08020800,0x00000800,0x00000020,0x08020020,0x00000800,0x00020820,
+0x08000800,0x00000020,0x08000020,0x08020000,0x08020020,0x08000000,0x00020000,0x08000820,
+0x00000000,0x08020820,0x00020020,0x08000020,0x08020000,0x08000800,0x08000820,0x00000000,
+0x08020820,0x00020800,0x00020800,0x00000820,0x00000820,0x00020020,0x08000000,0x08020800,
+};
+
+/*
+ * for manual index calculation
+ * #define fetch(box, i, sh) (*((u32int*)((uchar*)spbox + (box << 8) + ((i >> (sh)) & 0xfc))))
+ */
+#define fetch(box, i, sh) ((spbox+(box << 6))[((i >> (sh + 2)) & 0x3f)])
+
+/*
+ * DES electronic codebook encryption of one block
+ */
+void
+block_cipher(ulong key[32], uchar text[8], int decrypting)
+{
+ u32int right, left, v0, v1;
+ int i, keystep;
+
+ /*
+ * initial permutation
+ */
+ v0 = text[0] | ((u32int)text[2]<<8) | ((u32int)text[4]<<16) | ((u32int)text[6]<<24);
+ left = text[1] | ((u32int)text[3]<<8) | ((u32int)text[5]<<16) | ((u32int)text[7]<<24);
+ right = (left & 0xaaaaaaaa) | ((v0 >> 1) & 0x55555555);
+ left = ((left << 1) & 0xaaaaaaaa) | (v0 & 0x55555555);
+ left = ((left << 6) & 0x33003300)
+ | (left & 0xcc33cc33)
+ | ((left >> 6) & 0x00cc00cc);
+ left = ((left << 12) & 0x0f0f0000)
+ | (left & 0xf0f00f0f)
+ | ((left >> 12) & 0x0000f0f0);
+ right = ((right << 6) & 0x33003300)
+ | (right & 0xcc33cc33)
+ | ((right >> 6) & 0x00cc00cc);
+ right = ((right << 12) & 0x0f0f0000)
+ | (right & 0xf0f00f0f)
+ | ((right >> 12) & 0x0000f0f0);
+
+ if (decrypting) {
+ keystep = -2;
+ key = key + 32 - 2;
+ } else
+ keystep = 2;
+ for (i = 0; i < 8; i++) {
+ v0 = key[0];
+ v0 ^= (right >> 1) | (right << 31);
+ left ^= fetch(0, v0, 24)
+ ^ fetch(2, v0, 16)
+ ^ fetch(4, v0, 8)
+ ^ fetch(6, v0, 0);
+ v1 = key[1];
+ v1 ^= (right << 3) | (right >> 29);
+ left ^= fetch(1, v1, 24)
+ ^ fetch(3, v1, 16)
+ ^ fetch(5, v1, 8)
+ ^ fetch(7, v1, 0);
+ key += keystep;
+
+ v0 = key[0];
+ v0 ^= (left >> 1) | (left << 31);
+ right ^= fetch(0, v0, 24)
+ ^ fetch(2, v0, 16)
+ ^ fetch(4, v0, 8)
+ ^ fetch(6, v0, 0);
+ v1 = key[1];
+ v1 ^= (left << 3) | (left >> 29);
+ right ^= fetch(1, v1, 24)
+ ^ fetch(3, v1, 16)
+ ^ fetch(5, v1, 8)
+ ^ fetch(7, v1, 0);
+ key += keystep;
+ }
+
+ /*
+ * final permutation, inverse initial permutation
+ */
+ v0 = ((left << 1) & 0xaaaaaaaa) | (right & 0x55555555);
+ v1 = (left & 0xaaaaaaaa) | ((right >> 1) & 0x55555555);
+ v1 = ((v1 << 6) & 0x33003300)
+ | (v1 & 0xcc33cc33)
+ | ((v1 >> 6) & 0x00cc00cc);
+ v1 = ((v1 << 12) & 0x0f0f0000)
+ | (v1 & 0xf0f00f0f)
+ | ((v1 >> 12) & 0x0000f0f0);
+ v0 = ((v0 << 6) & 0x33003300)
+ | (v0 & 0xcc33cc33)
+ | ((v0 >> 6) & 0x00cc00cc);
+ v0 = ((v0 << 12) & 0x0f0f0000)
+ | (v0 & 0xf0f00f0f)
+ | ((v0 >> 12) & 0x0000f0f0);
+ text[0] = v0;
+ text[2] = v0 >> 8;
+ text[4] = v0 >> 16;
+ text[6] = v0 >> 24;
+ text[1] = v1;
+ text[3] = v1 >> 8;
+ text[5] = v1 >> 16;
+ text[7] = v1 >> 24;
+}
+
+/*
+ * triple DES electronic codebook encryption of one block
+ */
+void
+triple_block_cipher(ulong expanded_key[3][32], uchar text[8], int ende)
+{
+ ulong *key;
+ u32int right, left, v0, v1;
+ int i, j, keystep;
+
+ /*
+ * initial permutation
+ */
+ v0 = text[0] | ((u32int)text[2]<<8) | ((u32int)text[4]<<16) | ((u32int)text[6]<<24);
+ left = text[1] | ((u32int)text[3]<<8) | ((u32int)text[5]<<16) | ((u32int)text[7]<<24);
+ right = (left & 0xaaaaaaaa) | ((v0 >> 1) & 0x55555555);
+ left = ((left << 1) & 0xaaaaaaaa) | (v0 & 0x55555555);
+ left = ((left << 6) & 0x33003300)
+ | (left & 0xcc33cc33)
+ | ((left >> 6) & 0x00cc00cc);
+ left = ((left << 12) & 0x0f0f0000)
+ | (left & 0xf0f00f0f)
+ | ((left >> 12) & 0x0000f0f0);
+ right = ((right << 6) & 0x33003300)
+ | (right & 0xcc33cc33)
+ | ((right >> 6) & 0x00cc00cc);
+ right = ((right << 12) & 0x0f0f0000)
+ | (right & 0xf0f00f0f)
+ | ((right >> 12) & 0x0000f0f0);
+
+ for(j = 0; j < 3; j++){
+ if((ende & 1) == DES3D) {
+ key = &expanded_key[2-j][32-2];
+ keystep = -2;
+ } else {
+ key = &expanded_key[j][0];
+ keystep = 2;
+ }
+ ende >>= 1;
+ for (i = 0; i < 8; i++) {
+ v0 = key[0];
+ v0 ^= (right >> 1) | (right << 31);
+ left ^= fetch(0, v0, 24)
+ ^ fetch(2, v0, 16)
+ ^ fetch(4, v0, 8)
+ ^ fetch(6, v0, 0);
+ v1 = key[1];
+ v1 ^= (right << 3) | (right >> 29);
+ left ^= fetch(1, v1, 24)
+ ^ fetch(3, v1, 16)
+ ^ fetch(5, v1, 8)
+ ^ fetch(7, v1, 0);
+ key += keystep;
+
+ v0 = key[0];
+ v0 ^= (left >> 1) | (left << 31);
+ right ^= fetch(0, v0, 24)
+ ^ fetch(2, v0, 16)
+ ^ fetch(4, v0, 8)
+ ^ fetch(6, v0, 0);
+ v1 = key[1];
+ v1 ^= (left << 3) | (left >> 29);
+ right ^= fetch(1, v1, 24)
+ ^ fetch(3, v1, 16)
+ ^ fetch(5, v1, 8)
+ ^ fetch(7, v1, 0);
+ key += keystep;
+ }
+
+ v0 = left;
+ left = right;
+ right = v0;
+ }
+
+ /*
+ * final permutation, inverse initial permutation
+ * left and right are swapped here
+ */
+ v0 = ((right << 1) & 0xaaaaaaaa) | (left & 0x55555555);
+ v1 = (right & 0xaaaaaaaa) | ((left >> 1) & 0x55555555);
+ v1 = ((v1 << 6) & 0x33003300)
+ | (v1 & 0xcc33cc33)
+ | ((v1 >> 6) & 0x00cc00cc);
+ v1 = ((v1 << 12) & 0x0f0f0000)
+ | (v1 & 0xf0f00f0f)
+ | ((v1 >> 12) & 0x0000f0f0);
+ v0 = ((v0 << 6) & 0x33003300)
+ | (v0 & 0xcc33cc33)
+ | ((v0 >> 6) & 0x00cc00cc);
+ v0 = ((v0 << 12) & 0x0f0f0000)
+ | (v0 & 0xf0f00f0f)
+ | ((v0 >> 12) & 0x0000f0f0);
+ text[0] = v0;
+ text[2] = v0 >> 8;
+ text[4] = v0 >> 16;
+ text[6] = v0 >> 24;
+ text[1] = v1;
+ text[3] = v1 >> 8;
+ text[5] = v1 >> 16;
+ text[7] = v1 >> 24;
+}
+
+/*
+ * key compression permutation, 4 bits at a time
+ */
+static u32int comptab[] = {
+
+0x000000,0x010000,0x000008,0x010008,0x000080,0x010080,0x000088,0x010088,
+0x000000,0x010000,0x000008,0x010008,0x000080,0x010080,0x000088,0x010088,
+
+0x000000,0x100000,0x000800,0x100800,0x000000,0x100000,0x000800,0x100800,
+0x002000,0x102000,0x002800,0x102800,0x002000,0x102000,0x002800,0x102800,
+
+0x000000,0x000004,0x000400,0x000404,0x000000,0x000004,0x000400,0x000404,
+0x400000,0x400004,0x400400,0x400404,0x400000,0x400004,0x400400,0x400404,
+
+0x000000,0x000020,0x008000,0x008020,0x800000,0x800020,0x808000,0x808020,
+0x000002,0x000022,0x008002,0x008022,0x800002,0x800022,0x808002,0x808022,
+
+0x000000,0x000200,0x200000,0x200200,0x001000,0x001200,0x201000,0x201200,
+0x000000,0x000200,0x200000,0x200200,0x001000,0x001200,0x201000,0x201200,
+
+0x000000,0x000040,0x000010,0x000050,0x004000,0x004040,0x004010,0x004050,
+0x040000,0x040040,0x040010,0x040050,0x044000,0x044040,0x044010,0x044050,
+
+0x000000,0x000100,0x020000,0x020100,0x000001,0x000101,0x020001,0x020101,
+0x080000,0x080100,0x0a0000,0x0a0100,0x080001,0x080101,0x0a0001,0x0a0101,
+
+0x000000,0x000100,0x040000,0x040100,0x000000,0x000100,0x040000,0x040100,
+0x000040,0x000140,0x040040,0x040140,0x000040,0x000140,0x040040,0x040140,
+
+0x000000,0x400000,0x008000,0x408000,0x000008,0x400008,0x008008,0x408008,
+0x000400,0x400400,0x008400,0x408400,0x000408,0x400408,0x008408,0x408408,
+
+0x000000,0x001000,0x080000,0x081000,0x000020,0x001020,0x080020,0x081020,
+0x004000,0x005000,0x084000,0x085000,0x004020,0x005020,0x084020,0x085020,
+
+0x000000,0x000800,0x000000,0x000800,0x000010,0x000810,0x000010,0x000810,
+0x800000,0x800800,0x800000,0x800800,0x800010,0x800810,0x800010,0x800810,
+
+0x000000,0x010000,0x000200,0x010200,0x000000,0x010000,0x000200,0x010200,
+0x100000,0x110000,0x100200,0x110200,0x100000,0x110000,0x100200,0x110200,
+
+0x000000,0x000004,0x000000,0x000004,0x000080,0x000084,0x000080,0x000084,
+0x002000,0x002004,0x002000,0x002004,0x002080,0x002084,0x002080,0x002084,
+
+0x000000,0x000001,0x200000,0x200001,0x020000,0x020001,0x220000,0x220001,
+0x000002,0x000003,0x200002,0x200003,0x020002,0x020003,0x220002,0x220003,
+};
+
+static int keysh[] =
+{
+ 1, 1, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 1,
+};
+
+static void
+keycompperm(u32int left, u32int right, ulong *ek)
+{
+ u32int v0, v1;
+ int i;
+
+ for(i = 0; i < 16; i++){
+ left = (left << keysh[i]) | (left >> (28 - keysh[i]));
+ left &= 0xfffffff0;
+ right = (right << keysh[i]) | (right >> (28 - keysh[i]));
+ right &= 0xfffffff0;
+ v0 = comptab[6 * (1 << 4) + ((left >> (32-4)) & 0xf)]
+ | comptab[5 * (1 << 4) + ((left >> (32-8)) & 0xf)]
+ | comptab[4 * (1 << 4) + ((left >> (32-12)) & 0xf)]
+ | comptab[3 * (1 << 4) + ((left >> (32-16)) & 0xf)]
+ | comptab[2 * (1 << 4) + ((left >> (32-20)) & 0xf)]
+ | comptab[1 * (1 << 4) + ((left >> (32-24)) & 0xf)]
+ | comptab[0 * (1 << 4) + ((left >> (32-28)) & 0xf)];
+ v1 = comptab[13 * (1 << 4) + ((right >> (32-4)) & 0xf)]
+ | comptab[12 * (1 << 4) + ((right >> (32-8)) & 0xf)]
+ | comptab[11 * (1 << 4) + ((right >> (32-12)) & 0xf)]
+ | comptab[10 * (1 << 4) + ((right >> (32-16)) & 0xf)]
+ | comptab[9 * (1 << 4) + ((right >> (32-20)) & 0xf)]
+ | comptab[8 * (1 << 4) + ((right >> (32-24)) & 0xf)]
+ | comptab[7 * (1 << 4) + ((right >> (32-28)) & 0xf)];
+ ek[0] = (((v0 >> (24-6)) & 0x3f) << 26)
+ | (((v0 >> (24-18)) & 0x3f) << 18)
+ | (((v1 >> (24-6)) & 0x3f) << 10)
+ | (((v1 >> (24-18)) & 0x3f) << 2);
+ ek[1] = (((v0 >> (24-12)) & 0x3f) << 26)
+ | (((v0 >> (24-24)) & 0x3f) << 18)
+ | (((v1 >> (24-12)) & 0x3f) << 10)
+ | (((v1 >> (24-24)) & 0x3f) << 2);
+ ek += 2;
+ }
+}
+
+void
+des_key_setup(uchar key[8], ulong *ek)
+{
+ u32int left, right, v0, v1;
+
+ v0 = key[0] | ((u32int)key[2] << 8) | ((u32int)key[4] << 16) | ((u32int)key[6] << 24);
+ v1 = key[1] | ((u32int)key[3] << 8) | ((u32int)key[5] << 16) | ((u32int)key[7] << 24);
+ left = ((v0 >> 1) & 0x40404040)
+ | ((v0 >> 2) & 0x10101010)
+ | ((v0 >> 3) & 0x04040404)
+ | ((v0 >> 4) & 0x01010101)
+ | ((v1 >> 0) & 0x80808080)
+ | ((v1 >> 1) & 0x20202020)
+ | ((v1 >> 2) & 0x08080808)
+ | ((v1 >> 3) & 0x02020202);
+ right = ((v0 >> 1) & 0x04040404)
+ | ((v0 << 2) & 0x10101010)
+ | ((v0 << 5) & 0x40404040)
+ | ((v1 << 0) & 0x08080808)
+ | ((v1 << 3) & 0x20202020)
+ | ((v1 << 6) & 0x80808080);
+ left = ((left << 6) & 0x33003300)
+ | (left & 0xcc33cc33)
+ | ((left >> 6) & 0x00cc00cc);
+ v0 = ((left << 12) & 0x0f0f0000)
+ | (left & 0xf0f00f0f)
+ | ((left >> 12) & 0x0000f0f0);
+ right = ((right << 6) & 0x33003300)
+ | (right & 0xcc33cc33)
+ | ((right >> 6) & 0x00cc00cc);
+ v1 = ((right << 12) & 0x0f0f0000)
+ | (right & 0xf0f00f0f)
+ | ((right >> 12) & 0x0000f0f0);
+ left = v0 & 0xfffffff0;
+ right = (v1 & 0xffffff00) | ((v0 << 4) & 0xf0);
+
+ keycompperm(left, right, ek);
+}
+
+static uchar parity[128] =
+{
+ 0x01, 0x02, 0x04, 0x07, 0x08, 0x0b, 0x0d, 0x0e,
+ 0x10, 0x13, 0x15, 0x16, 0x19, 0x1a, 0x1c, 0x1f,
+ 0x20, 0x23, 0x25, 0x26, 0x29, 0x2a, 0x2c, 0x2f,
+ 0x31, 0x32, 0x34, 0x37, 0x38, 0x3b, 0x3d, 0x3e,
+ 0x40, 0x43, 0x45, 0x46, 0x49, 0x4a, 0x4c, 0x4f,
+ 0x51, 0x52, 0x54, 0x57, 0x58, 0x5b, 0x5d, 0x5e,
+ 0x61, 0x62, 0x64, 0x67, 0x68, 0x6b, 0x6d, 0x6e,
+ 0x70, 0x73, 0x75, 0x76, 0x79, 0x7a, 0x7c, 0x7f,
+ 0x80, 0x83, 0x85, 0x86, 0x89, 0x8a, 0x8c, 0x8f,
+ 0x91, 0x92, 0x94, 0x97, 0x98, 0x9b, 0x9d, 0x9e,
+ 0xa1, 0xa2, 0xa4, 0xa7, 0xa8, 0xab, 0xad, 0xae,
+ 0xb0, 0xb3, 0xb5, 0xb6, 0xb9, 0xba, 0xbc, 0xbf,
+ 0xc1, 0xc2, 0xc4, 0xc7, 0xc8, 0xcb, 0xcd, 0xce,
+ 0xd0, 0xd3, 0xd5, 0xd6, 0xd9, 0xda, 0xdc, 0xdf,
+ 0xe0, 0xe3, 0xe5, 0xe6, 0xe9, 0xea, 0xec, 0xef,
+ 0xf1, 0xf2, 0xf4, 0xf7, 0xf8, 0xfb, 0xfd, 0xfe,
+};
+
+/*
+ * convert a 7 byte key to an 8 byte one
+ */
+void
+des56to64(uchar *k56, uchar *k64)
+{
+ u32int hi, lo;
+
+ hi = ((u32int)k56[0]<<24)|((u32int)k56[1]<<16)|((u32int)k56[2]<<8)|k56[3];
+ lo = ((u32int)k56[4]<<24)|((u32int)k56[5]<<16)|((u32int)k56[6]<<8);
+
+ k64[0] = parity[(hi>>25)&0x7f];
+ k64[1] = parity[(hi>>18)&0x7f];
+ k64[2] = parity[(hi>>11)&0x7f];
+ k64[3] = parity[(hi>>4)&0x7f];
+ k64[4] = parity[((hi<<3)|(lo>>29))&0x7f];
+ k64[5] = parity[(lo>>22)&0x7f];
+ k64[6] = parity[(lo>>15)&0x7f];
+ k64[7] = parity[(lo>>8)&0x7f];
+}
+
+/*
+ * convert an 8 byte key to a 7 byte one
+ */
+void
+des64to56(uchar *k64, uchar *k56)
+{
+ u32int hi, lo;
+
+ hi = (((u32int)k64[0]&0xfe)<<24)|(((u32int)k64[1]&0xfe)<<17)|(((u32int)k64[2]&0xfe)<<10)
+ |((k64[3]&0xfe)<<3)|(k64[4]>>4);
+ lo = (((u32int)k64[4]&0xfe)<<28)|(((u32int)k64[5]&0xfe)<<21)|(((u32int)k64[6]&0xfe)<<14)
+ |(((u32int)k64[7]&0xfe)<<7);
+
+ k56[0] = hi>>24;
+ k56[1] = hi>>16;
+ k56[2] = hi>>8;
+ k56[3] = hi>>0;
+ k56[4] = lo>>24;
+ k56[5] = lo>>16;
+ k56[6] = lo>>8;
+}
+
+void
+key_setup(uchar key[7], ulong *ek)
+{
+ uchar k64[8];
+
+ des56to64(key, k64);
+ des_key_setup(k64, ek);
+}
--- /dev/null
+++ b/libsec/port/des3CBC.c
@@ -1,0 +1,59 @@
+#include "os.h"
+#include <mp.h>
+#include <libsec.h>
+
+// Because of the way that non multiple of 8
+// buffers are handled, the decryptor must
+// be fed buffers of the same size as the
+// encryptor
+
+
+// If the length is not a multiple of 8, I encrypt
+// the overflow to be compatible with lacy's cryptlib
+void
+des3CBCencrypt(uchar *p, int len, DES3state *s)
+{
+ uchar *p2, *ip, *eip;
+
+ for(; len >= 8; len -= 8){
+ p2 = p;
+ ip = s->ivec;
+ for(eip = ip+8; ip < eip; )
+ *p2++ ^= *ip++;
+ triple_block_cipher(s->expanded, p, DES3EDE);
+ memmove(s->ivec, p, 8);
+ p += 8;
+ }
+
+ if(len > 0){
+ ip = s->ivec;
+ triple_block_cipher(s->expanded, ip, DES3EDE);
+ for(eip = ip+len; ip < eip; )
+ *p++ ^= *ip++;
+ }
+}
+
+void
+des3CBCdecrypt(uchar *p, int len, DES3state *s)
+{
+ uchar *ip, *eip, *tp;
+ uchar tmp[8];
+
+ for(; len >= 8; len -= 8){
+ memmove(tmp, p, 8);
+ triple_block_cipher(s->expanded, p, DES3DED);
+ tp = tmp;
+ ip = s->ivec;
+ for(eip = ip+8; ip < eip; ){
+ *p++ ^= *ip;
+ *ip++ = *tp++;
+ }
+ }
+
+ if(len > 0){
+ ip = s->ivec;
+ triple_block_cipher(s->expanded, ip, DES3EDE);
+ for(eip = ip+len; ip < eip; )
+ *p++ ^= *ip++;
+ }
+}
--- /dev/null
+++ b/libsec/port/des3ECB.c
@@ -1,0 +1,48 @@
+#include "os.h"
+#include <mp.h>
+#include <libsec.h>
+
+// I wasn't sure what to do when the buffer was not
+// a multiple of 8. I did what lacy's cryptolib did
+// to be compatible, but it looks dangerous to me
+// since its encrypting plain text with the key. -- presotto
+
+void
+des3ECBencrypt(uchar *p, int len, DES3state *s)
+{
+ int i;
+ uchar tmp[8];
+
+ for(; len >= 8; len -= 8){
+ triple_block_cipher(s->expanded, p, DES3EDE);
+ p += 8;
+ }
+
+ if(len > 0){
+ for (i=0; i<8; i++)
+ tmp[i] = i;
+ triple_block_cipher(s->expanded, tmp, DES3EDE);
+ for (i = 0; i < len; i++)
+ p[i] ^= tmp[i];
+ }
+}
+
+void
+des3ECBdecrypt(uchar *p, int len, DES3state *s)
+{
+ int i;
+ uchar tmp[8];
+
+ for(; len >= 8; len -= 8){
+ triple_block_cipher(s->expanded, p, DES3DED);
+ p += 8;
+ }
+
+ if(len > 0){
+ for (i=0; i<8; i++)
+ tmp[i] = i;
+ triple_block_cipher(s->expanded, tmp, DES3EDE);
+ for (i = 0; i < len; i++)
+ p[i] ^= tmp[i];
+ }
+}
--- /dev/null
+++ b/libsec/port/desCBC.c
@@ -1,0 +1,59 @@
+#include "os.h"
+#include <mp.h>
+#include <libsec.h>
+
+// Because of the way that non multiple of 8
+// buffers are handled, the decryptor must
+// be fed buffers of the same size as the
+// encryptor
+
+
+// If the length is not a multiple of 8, I encrypt
+// the overflow to be compatible with lacy's cryptlib
+void
+desCBCencrypt(uchar *p, int len, DESstate *s)
+{
+ uchar *p2, *ip, *eip;
+
+ for(; len >= 8; len -= 8){
+ p2 = p;
+ ip = s->ivec;
+ for(eip = ip+8; ip < eip; )
+ *p2++ ^= *ip++;
+ block_cipher(s->expanded, p, 0);
+ memmove(s->ivec, p, 8);
+ p += 8;
+ }
+
+ if(len > 0){
+ ip = s->ivec;
+ block_cipher(s->expanded, ip, 0);
+ for(eip = ip+len; ip < eip; )
+ *p++ ^= *ip++;
+ }
+}
+
+void
+desCBCdecrypt(uchar *p, int len, DESstate *s)
+{
+ uchar *ip, *eip, *tp;
+ uchar tmp[8];
+
+ for(; len >= 8; len -= 8){
+ memmove(tmp, p, 8);
+ block_cipher(s->expanded, p, 1);
+ tp = tmp;
+ ip = s->ivec;
+ for(eip = ip+8; ip < eip; ){
+ *p++ ^= *ip;
+ *ip++ = *tp++;
+ }
+ }
+
+ if(len > 0){
+ ip = s->ivec;
+ block_cipher(s->expanded, ip, 0);
+ for(eip = ip+len; ip < eip; )
+ *p++ ^= *ip++;
+ }
+}
--- /dev/null
+++ b/libsec/port/desECB.c
@@ -1,0 +1,48 @@
+#include "os.h"
+#include <mp.h>
+#include <libsec.h>
+
+// I wasn't sure what to do when the buffer was not
+// a multiple of 8. I did what lacy's cryptolib did
+// to be compatible, but it looks dangerous to me
+// since its encrypting plain text with the key. -- presotto
+
+void
+desECBencrypt(uchar *p, int len, DESstate *s)
+{
+ int i;
+ uchar tmp[8];
+
+ for(; len >= 8; len -= 8){
+ block_cipher(s->expanded, p, 0);
+ p += 8;
+ }
+
+ if(len > 0){
+ for (i=0; i<8; i++)
+ tmp[i] = i;
+ block_cipher(s->expanded, tmp, 0);
+ for (i = 0; i < len; i++)
+ p[i] ^= tmp[i];
+ }
+}
+
+void
+desECBdecrypt(uchar *p, int len, DESstate *s)
+{
+ int i;
+ uchar tmp[8];
+
+ for(; len >= 8; len -= 8){
+ block_cipher(s->expanded, p, 1);
+ p += 8;
+ }
+
+ if(len > 0){
+ for (i=0; i<8; i++)
+ tmp[i] = i;
+ block_cipher(s->expanded, tmp, 0);
+ for (i = 0; i < len; i++)
+ p[i] ^= tmp[i];
+ }
+}
--- /dev/null
+++ b/libsec/port/desmodes.c
@@ -1,0 +1,31 @@
+#include "os.h"
+#include <libsec.h>
+
+/*
+ * these routines use the 64bit format for
+ * DES keys.
+ */
+
+void
+setupDESstate(DESstate *s, uchar key[8], uchar *ivec)
+{
+ memset(s, 0, sizeof(*s));
+ memmove(s->key, key, sizeof(s->key));
+ des_key_setup(key, s->expanded);
+ if(ivec)
+ memmove(s->ivec, ivec, 8);
+ s->setup = 0xdeadbeef;
+}
+
+void
+setupDES3state(DES3state *s, uchar key[3][8], uchar *ivec)
+{
+ memset(s, 0, sizeof(*s));
+ memmove(s->key, key, sizeof(s->key));
+ des_key_setup(key[0], s->expanded[0]);
+ des_key_setup(key[1], s->expanded[1]);
+ des_key_setup(key[2], s->expanded[2]);
+ if(ivec)
+ memmove(s->ivec, ivec, 8);
+ s->setup = 0xdeadbeef;
+}
--- /dev/null
+++ b/libsec/port/dsaalloc.c
@@ -1,0 +1,72 @@
+#include "os.h"
+#include <mp.h>
+#include <libsec.h>
+
+DSApub*
+dsapuballoc(void)
+{
+ DSApub *dsa;
+
+ dsa = mallocz(sizeof(*dsa), 1);
+ if(dsa == nil)
+ sysfatal("dsapuballoc");
+ return dsa;
+}
+
+void
+dsapubfree(DSApub *dsa)
+{
+ if(dsa == nil)
+ return;
+ mpfree(dsa->p);
+ mpfree(dsa->q);
+ mpfree(dsa->alpha);
+ mpfree(dsa->key);
+ free(dsa);
+}
+
+
+DSApriv*
+dsaprivalloc(void)
+{
+ DSApriv *dsa;
+
+ dsa = mallocz(sizeof(*dsa), 1);
+ if(dsa == nil)
+ sysfatal("dsaprivalloc");
+ return dsa;
+}
+
+void
+dsaprivfree(DSApriv *dsa)
+{
+ if(dsa == nil)
+ return;
+ mpfree(dsa->pub.p);
+ mpfree(dsa->pub.q);
+ mpfree(dsa->pub.alpha);
+ mpfree(dsa->pub.key);
+ mpfree(dsa->secret);
+ free(dsa);
+}
+
+DSAsig*
+dsasigalloc(void)
+{
+ DSAsig *dsa;
+
+ dsa = mallocz(sizeof(*dsa), 1);
+ if(dsa == nil)
+ sysfatal("dsasigalloc");
+ return dsa;
+}
+
+void
+dsasigfree(DSAsig *dsa)
+{
+ if(dsa == nil)
+ return;
+ mpfree(dsa->r);
+ mpfree(dsa->s);
+ free(dsa);
+}
--- /dev/null
+++ b/libsec/port/dsagen.c
@@ -1,0 +1,58 @@
+#include "os.h"
+#include <mp.h>
+#include <libsec.h>
+
+DSApriv*
+dsagen(DSApub *opub)
+{
+ DSApub *pub;
+ DSApriv *priv;
+ mpint *exp;
+ mpint *g;
+ mpint *r;
+ int bits;
+
+ priv = dsaprivalloc();
+ pub = &priv->pub;
+
+ if(opub != nil){
+ pub->p = mpcopy(opub->p);
+ pub->q = mpcopy(opub->q);
+ } else {
+ pub->p = mpnew(0);
+ pub->q = mpnew(0);
+ DSAprimes(pub->q, pub->p, nil);
+ }
+ bits = Dbits*pub->p->top;
+
+ pub->alpha = mpnew(0);
+ pub->key = mpnew(0);
+ priv->secret = mpnew(0);
+
+ // find a generator alpha of the multiplicative
+ // group Z*p, i.e., of order n = p-1. We use the
+ // fact that q divides p-1 to reduce the exponent.
+ exp = mpnew(0);
+ g = mpnew(0);
+ r = mpnew(0);
+ mpsub(pub->p, mpone, exp);
+ mpdiv(exp, pub->q, exp, r);
+ if(mpcmp(r, mpzero) != 0)
+ sysfatal("dsagen foul up");
+ while(1){
+ mprand(bits, genrandom, g);
+ mpmod(g, pub->p, g);
+ mpexp(g, exp, pub->p, pub->alpha);
+ if(mpcmp(pub->alpha, mpone) != 0)
+ break;
+ }
+ mpfree(g);
+ mpfree(exp);
+
+ // create the secret key
+ mprand(bits, genrandom, priv->secret);
+ mpmod(priv->secret, pub->p, priv->secret);
+ mpexp(pub->alpha, priv->secret, pub->p, pub->key);
+
+ return priv;
+}
--- /dev/null
+++ b/libsec/port/dsaprimes.c
@@ -1,0 +1,97 @@
+#include "os.h"
+#include <mp.h>
+#include <libsec.h>
+
+// NIST algorithm for generating DSA primes
+// Menezes et al (1997) Handbook of Applied Cryptography, p.151
+// q is a 160-bit prime; p is a 1024-bit prime; q divides p-1
+
+// arithmetic on unsigned ints mod 2**160, represented
+// as 20-byte, little-endian uchar array
+
+static void
+Hrand(uchar *s)
+{
+ ulong *u = (ulong*)s;
+ *u++ = fastrand();
+ *u++ = fastrand();
+ *u++ = fastrand();
+ *u++ = fastrand();
+ *u = fastrand();
+}
+
+static void
+Hincr(uchar *s)
+{
+ int i;
+ for(i=0; i<20; i++)
+ if(++s[i]!=0)
+ break;
+}
+
+// this can run for quite a while; be patient
+void
+DSAprimes(mpint *q, mpint *p, uchar seed[SHA1dlen])
+{
+ int i, j, k, n = 6, b = 63;
+ uchar s[SHA1dlen], Hs[SHA1dlen], Hs1[SHA1dlen], sj[SHA1dlen], sjk[SHA1dlen];
+ mpint *two1023, *mb, *Vk, *W, *X, *q2;
+
+ two1023 = mpnew(1024);
+ mpleft(mpone, 1023, two1023);
+ mb = mpnew(0);
+ mpleft(mpone, b, mb);
+ W = mpnew(1024);
+ Vk = mpnew(1024);
+ X = mpnew(0);
+ q2 = mpnew(0);
+forever:
+ do{
+ Hrand(s);
+ memcpy(sj, s, 20);
+ sha1(s, 20, Hs, 0);
+ Hincr(sj);
+ sha1(sj, 20, Hs1, 0);
+ for(i=0; i<20; i++)
+ Hs[i] ^= Hs1[i];
+ Hs[0] |= 1;
+ Hs[19] |= 0x80;
+ letomp(Hs, 20, q);
+ }while(!probably_prime(q, 18));
+ if(seed != nil) // allow skeptics to confirm computation
+ memmove(seed, s, SHA1dlen);
+ i = 0;
+ j = 2;
+ Hincr(sj);
+ mpleft(q, 1, q2);
+ while(i<4096){
+ memcpy(sjk, sj, 20);
+ for(k=0; k <= n; k++){
+ sha1(sjk, 20, Hs, 0);
+ letomp(Hs, 20, Vk);
+ if(k == n)
+ mpmod(Vk, mb, Vk);
+ mpleft(Vk, 160*k, Vk);
+ mpadd(W, Vk, W);
+ Hincr(sjk);
+ }
+ mpadd(W, two1023, X);
+ mpmod(X, q2, W);
+ mpsub(W, mpone, W);
+ mpsub(X, W, p);
+ if(mpcmp(p, two1023)>=0 && probably_prime(p, 5))
+ goto done;
+ i += 1;
+ j += n+1;
+ for(k=0; k<n+1; k++)
+ Hincr(sj);
+ }
+ goto forever;
+done:
+ mpfree(q2);
+ mpfree(X);
+ mpfree(Vk);
+ mpfree(W);
+ mpfree(mb);
+ mpfree(two1023);
+}
--- /dev/null
+++ b/libsec/port/dsaprivtopub.c
@@ -1,0 +1,16 @@
+#include "os.h"
+#include <mp.h>
+#include <libsec.h>
+
+DSApub*
+dsaprivtopub(DSApriv *priv)
+{
+ DSApub *pub;
+
+ pub = dsapuballoc();
+ pub->p = mpcopy(priv->pub.p);
+ pub->q = mpcopy(priv->pub.q);
+ pub->alpha = mpcopy(priv->pub.alpha);
+ pub->key = mpcopy(priv->pub.key);
+ return pub;
+}
--- /dev/null
+++ b/libsec/port/dsasign.c
@@ -1,0 +1,52 @@
+#include "os.h"
+#include <mp.h>
+#include <libsec.h>
+
+DSAsig*
+dsasign(DSApriv *priv, mpint *m)
+{
+ DSApub *pub = &priv->pub;
+ DSAsig *sig;
+ mpint *qm1, *k, *kinv, *r, *s;
+ mpint *q = pub->q, *p = pub->p, *alpha = pub->alpha;
+ int qlen = mpsignif(q);
+
+ qm1 = mpnew(0);
+ kinv = mpnew(0);
+ r = mpnew(0);
+ s = mpnew(0);
+ k = mpnew(0);
+ mpsub(pub->q, mpone, qm1);
+
+ // find a k that has an inverse mod q
+ while(1){
+ mprand(qlen, genrandom, k);
+ if((mpcmp(mpone, k) > 0) || (mpcmp(k, pub->q) >= 0))
+ continue;
+ mpextendedgcd(k, q, r, kinv, s);
+ if(mpcmp(r, mpone) != 0)
+ sysfatal("dsasign: pub->q not prime");
+ break;
+ }
+
+ // make kinv positive
+ mpmod(kinv, pub->q, kinv);
+
+ // r = ((alpha**k) mod p) mod q
+ mpexp(alpha, k, p, r);
+ mpmod(r, q, r);
+
+ // s = (kinv*(m + ar)) mod q
+ mpmul(r, priv->secret, s);
+ mpadd(s, m, s);
+ mpmul(s, kinv, s);
+ mpmod(s, q, s);
+
+ sig = dsasigalloc();
+ sig->r = r;
+ sig->s = s;
+ mpfree(qm1);
+ mpfree(k);
+ mpfree(kinv);
+ return sig;
+}
--- /dev/null
+++ b/libsec/port/dsaverify.c
@@ -1,0 +1,46 @@
+#include "os.h"
+#include <mp.h>
+#include <libsec.h>
+
+int
+dsaverify(DSApub *pub, DSAsig *sig, mpint *m)
+{
+ int rv = -1;
+ mpint *u1, *u2, *v, *sinv;
+
+ if(mpcmp(sig->r, mpone) < 0 || mpcmp(sig->r, pub->q) >= 0)
+ return rv;
+ if(mpcmp(sig->s, mpone) < 0 || mpcmp(sig->s, pub->q) >= 0)
+ return rv;
+ u1 = mpnew(0);
+ u2 = mpnew(0);
+ v = mpnew(0);
+ sinv = mpnew(0);
+
+ // find (s**-1) mod q, make sure it exists
+ mpextendedgcd(sig->s, pub->q, u1, sinv, v);
+ if(mpcmp(u1, mpone) != 0)
+ goto out;
+
+ // u1 = (sinv * m) mod q, u2 = (r * sinv) mod q
+ mpmul(sinv, m, u1);
+ mpmod(u1, pub->q, u1);
+ mpmul(sig->r, sinv, u2);
+ mpmod(u2, pub->q, u2);
+
+ // v = (((alpha**u1)*(key**u2)) mod p) mod q
+ mpexp(pub->alpha, u1, pub->p, sinv);
+ mpexp(pub->key, u2, pub->p, v);
+ mpmul(sinv, v, v);
+ mpmod(v, pub->p, v);
+ mpmod(v, pub->q, v);
+
+ if(mpcmp(v, sig->r) == 0)
+ rv = 0;
+out:
+ mpfree(v);
+ mpfree(u1);
+ mpfree(u2);
+ mpfree(sinv);
+ return rv;
+}
--- /dev/null
+++ b/libsec/port/egalloc.c
@@ -1,0 +1,70 @@
+#include "os.h"
+#include <mp.h>
+#include <libsec.h>
+
+EGpub*
+egpuballoc(void)
+{
+ EGpub *eg;
+
+ eg = mallocz(sizeof(*eg), 1);
+ if(eg == nil)
+ sysfatal("egpuballoc");
+ return eg;
+}
+
+void
+egpubfree(EGpub *eg)
+{
+ if(eg == nil)
+ return;
+ mpfree(eg->p);
+ mpfree(eg->alpha);
+ mpfree(eg->key);
+ free(eg);
+}
+
+
+EGpriv*
+egprivalloc(void)
+{
+ EGpriv *eg;
+
+ eg = mallocz(sizeof(*eg), 1);
+ if(eg == nil)
+ sysfatal("egprivalloc");
+ return eg;
+}
+
+void
+egprivfree(EGpriv *eg)
+{
+ if(eg == nil)
+ return;
+ mpfree(eg->pub.p);
+ mpfree(eg->pub.alpha);
+ mpfree(eg->pub.key);
+ mpfree(eg->secret);
+ free(eg);
+}
+
+EGsig*
+egsigalloc(void)
+{
+ EGsig *eg;
+
+ eg = mallocz(sizeof(*eg), 1);
+ if(eg == nil)
+ sysfatal("egsigalloc");
+ return eg;
+}
+
+void
+egsigfree(EGsig *eg)
+{
+ if(eg == nil)
+ return;
+ mpfree(eg->r);
+ mpfree(eg->s);
+ free(eg);
+}
--- /dev/null
+++ b/libsec/port/egdecrypt.c
@@ -1,0 +1,28 @@
+#include "os.h"
+#include <mp.h>
+#include <libsec.h>
+
+mpint*
+egdecrypt(EGpriv *priv, mpint *in, mpint *out)
+{
+ EGpub *pub = &priv->pub;
+ mpint *gamma, *delta;
+ mpint *p = pub->p;
+ int plen = mpsignif(p)+1;
+ int shift = ((plen+Dbits-1)/Dbits)*Dbits;
+
+ if(out == nil)
+ out = mpnew(0);
+ gamma = mpnew(0);
+ delta = mpnew(0);
+ mpright(in, shift, gamma);
+ mpleft(gamma, shift, delta);
+ mpsub(in, delta, delta);
+ mpexp(gamma, priv->secret, p, out);
+ mpinvert(out, p, gamma);
+ mpmul(gamma, delta, out);
+ mpmod(out, p, out);
+ mpfree(gamma);
+ mpfree(delta);
+ return out;
+}
--- /dev/null
+++ b/libsec/port/egencrypt.c
@@ -1,0 +1,38 @@
+#include "os.h"
+#include <mp.h>
+#include <libsec.h>
+
+mpint*
+egencrypt(EGpub *pub, mpint *in, mpint *out)
+{
+ mpint *m, *k, *gamma, *delta, *pm1;
+ mpint *p = pub->p, *alpha = pub->alpha;
+ int plen = mpsignif(p);
+ int shift = ((plen+Dbits)/Dbits)*Dbits;
+ // in libcrypt version, (int)(LENGTH(pub->p)*sizeof(NumType)*CHARBITS);
+
+ if(out == nil)
+ out = mpnew(0);
+ pm1 = mpnew(0);
+ m = mpnew(0);
+ gamma = mpnew(0);
+ delta = mpnew(0);
+ mpmod(in, p, m);
+ while(1){
+ k = mprand(plen, genrandom, nil);
+ if((mpcmp(mpone, k) <= 0) && (mpcmp(k, pm1) < 0))
+ break;
+ }
+ mpexp(alpha, k, p, gamma);
+ mpexp(pub->key, k, p, delta);
+ mpmul(m, delta, delta);
+ mpmod(delta, p, delta);
+ mpleft(gamma, shift, out);
+ mpadd(delta, out, out);
+ mpfree(pm1);
+ mpfree(m);
+ mpfree(k);
+ mpfree(gamma);
+ mpfree(delta);
+ return out;
+}
--- /dev/null
+++ b/libsec/port/eggen.c
@@ -1,0 +1,21 @@
+#include "os.h"
+#include <mp.h>
+#include <libsec.h>
+
+EGpriv*
+eggen(int nlen, int rounds)
+{
+ EGpub *pub;
+ EGpriv *priv;
+
+ priv = egprivalloc();
+ pub = &priv->pub;
+ pub->p = mpnew(0);
+ pub->alpha = mpnew(0);
+ pub->key = mpnew(0);
+ priv->secret = mpnew(0);
+ gensafeprime(pub->p, pub->alpha, nlen, rounds);
+ mprand(nlen-1, genrandom, priv->secret);
+ mpexp(pub->alpha, priv->secret, pub->p, pub->key);
+ return priv;
+}
--- /dev/null
+++ b/libsec/port/egprivtopub.c
@@ -1,0 +1,17 @@
+#include "os.h"
+#include <mp.h>
+#include <libsec.h>
+
+EGpub*
+egprivtopub(EGpriv *priv)
+{
+ EGpub *pub;
+
+ pub = egpuballoc();
+ if(pub == nil)
+ return nil;
+ pub->p = mpcopy(priv->pub.p);
+ pub->alpha = mpcopy(priv->pub.alpha);
+ pub->key = mpcopy(priv->pub.key);
+ return pub;
+}
--- /dev/null
+++ b/libsec/port/egsign.c
@@ -1,0 +1,43 @@
+#include "os.h"
+#include <mp.h>
+#include <libsec.h>
+
+EGsig*
+egsign(EGpriv *priv, mpint *m)
+{
+ EGpub *pub = &priv->pub;
+ EGsig *sig;
+ mpint *pm1, *k, *kinv, *r, *s;
+ mpint *p = pub->p, *alpha = pub->alpha;
+ int plen = mpsignif(p);
+
+ pm1 = mpnew(0);
+ kinv = mpnew(0);
+ r = mpnew(0);
+ s = mpnew(0);
+ k = mpnew(0);
+ mpsub(p, mpone, pm1);
+ while(1){
+ mprand(plen, genrandom, k);
+ if((mpcmp(mpone, k) > 0) || (mpcmp(k, pm1) >= 0))
+ continue;
+ mpextendedgcd(k, pm1, r, kinv, s);
+ if(mpcmp(r, mpone) != 0)
+ continue;
+ break;
+ }
+ mpmod(kinv, pm1, kinv); // make kinv positive
+ mpexp(alpha, k, p, r);
+ mpmul(priv->secret, r, s);
+ mpmod(s, pm1, s);
+ mpsub(m, s, s);
+ mpmul(kinv, s, s);
+ mpmod(s, pm1, s);
+ sig = egsigalloc();
+ sig->r = r;
+ sig->s = s;
+ mpfree(pm1);
+ mpfree(k);
+ mpfree(kinv);
+ return sig;
+}
--- /dev/null
+++ b/libsec/port/egtest.c
@@ -1,0 +1,34 @@
+#include "os.h"
+#include <mp.h>
+#include <libsec.h>
+
+void
+main(void)
+{
+ EGpriv *sk;
+ mpint *m, *gamma, *delta, *in, *out;
+ int plen, shift;
+
+ fmtinstall('B', mpconv);
+
+ sk = egprivalloc();
+ sk->pub.p = uitomp(2357, nil);
+ sk->pub.alpha = uitomp(2, nil);
+ sk->pub.key = uitomp(1185, nil);
+ sk->secret = uitomp(1751, nil);
+
+ m = uitomp(2035, nil);
+
+ plen = mpsignif(sk->pub.p)+1;
+ shift = ((plen+Dbits-1)/Dbits)*Dbits;
+ gamma = uitomp(1430, nil);
+ delta = uitomp(697, nil);
+ out = mpnew(0);
+ in = mpnew(0);
+ mpleft(gamma, shift, in);
+ mpadd(delta, in, in);
+ egdecrypt(sk, in, out);
+
+ if(mpcmp(m, out) != 0)
+ print("decrypt failed to recover message\n");
+}
--- /dev/null
+++ b/libsec/port/egverify.c
@@ -1,0 +1,29 @@
+#include "os.h"
+#include <mp.h>
+#include <libsec.h>
+
+int
+egverify(EGpub *pub, EGsig *sig, mpint *m)
+{
+ mpint *p = pub->p, *alpha = pub->alpha;
+ mpint *r = sig->r, *s = sig->s;
+ mpint *v1, *v2, *rs;
+ int rv = -1;
+
+ if(mpcmp(r, mpone) < 0 || mpcmp(r, p) >= 0)
+ return rv;
+ v1 = mpnew(0);
+ rs = mpnew(0);
+ v2 = mpnew(0);
+ mpexp(pub->key, r, p, v1);
+ mpexp(r, s, p, rs);
+ mpmul(v1, rs, v1);
+ mpmod(v1, p, v1);
+ mpexp(alpha, m, p, v2);
+ if(mpcmp(v1, v2) == 0)
+ rv = 0;
+ mpfree(v1);
+ mpfree(rs);
+ mpfree(v2);
+ return rv;
+}
--- /dev/null
+++ b/libsec/port/fastrand.c
@@ -1,0 +1,15 @@
+#include "os.h"
+#include <libsec.h>
+
+/*
+ * use the X917 random number generator to create random
+ * numbers (faster than truerand() but not as random).
+ */
+ulong
+fastrand(void)
+{
+ ulong x;
+
+ genrandom((uchar*)&x, sizeof x);
+ return x;
+}
--- /dev/null
+++ b/libsec/port/genprime.c
@@ -1,0 +1,27 @@
+#include "os.h"
+#include <mp.h>
+#include <libsec.h>
+
+// generate a probable prime. accuracy is the miller-rabin interations
+void
+genprime(mpint *p, int n, int accuracy)
+{
+ mpdigit x;
+
+ // generate n random bits with high and low bits set
+ mpbits(p, n);
+ genrandom((uchar*)p->p, (n+7)/8);
+ p->top = (n+Dbits-1)/Dbits;
+ x = 1;
+ x <<= ((n-1)%Dbits);
+ p->p[p->top-1] &= (x-1);
+ p->p[p->top-1] |= x;
+ p->p[0] |= 1;
+
+ // keep icrementing till it looks prime
+ for(;;){
+ if(probably_prime(p, accuracy))
+ break;
+ mpadd(p, mptwo, p);
+ }
+}
--- /dev/null
+++ b/libsec/port/genrandom.c
@@ -1,0 +1,62 @@
+#include "os.h"
+#include "kernel.h"
+#include <mp.h>
+#include <libsec.h>
+
+typedef struct State{
+ int seeded;
+ uvlong seed;
+ DES3state des3;
+} State;
+static State x917state;
+
+static void
+X917(uchar *rand, int nrand)
+{
+ int i, m, n8;
+ uvlong I, x;
+
+ /* 1. Compute intermediate value I = Ek(time). */
+ I = nsec();
+ triple_block_cipher(x917state.des3.expanded, (uchar*)&I, 0); /* two-key EDE */
+
+ /* 2. x[i] = Ek(I^seed); seed = Ek(x[i]^I); */
+ m = (nrand+7)/8;
+ for(i=0; i<m; i++){
+ x = I ^ x917state.seed;
+ triple_block_cipher(x917state.des3.expanded, (uchar*)&x, 0);
+ n8 = (nrand>8) ? 8 : nrand;
+ memcpy(rand, (uchar*)&x, n8);
+ rand += 8;
+ nrand -= 8;
+ x ^= I;
+ triple_block_cipher(x917state.des3.expanded, (uchar*)&x, 0);
+ x917state.seed = x;
+ }
+}
+
+static void
+X917init(void)
+{
+ int n;
+ uchar mix[128];
+ uchar key3[3][8];
+ ulong *ulp;
+
+ ulp = (ulong*)key3;
+ for(n = 0; n < sizeof(key3)/sizeof(ulong); n++)
+ ulp[n] = truerand();
+ setupDES3state(&x917state.des3, key3, nil);
+ X917(mix, sizeof mix);
+ x917state.seeded = 1;
+}
+
+void
+genrandom(uchar *p, int n)
+{
+ _genrandomqlock();
+ if(x917state.seeded == 0)
+ X917init();
+ X917(p, n);
+ _genrandomqunlock();
+}
--- /dev/null
+++ b/libsec/port/gensafeprime.c
@@ -1,0 +1,36 @@
+#include "os.h"
+#include <mp.h>
+#include <libsec.h>
+
+// find a prime p of length n and a generator alpha of Z^*_p
+// Alg 4.86 Menezes et al () Handbook, p.164
+void
+gensafeprime(mpint *p, mpint *alpha, int n, int accuracy)
+{
+ mpint *q, *b;
+
+ q = mpnew(n-1);
+ while(1){
+ genprime(q, n-1, accuracy);
+ mpleft(q, 1, p);
+ mpadd(p, mpone, p); // p = 2*q+1
+ if(probably_prime(p, accuracy))
+ break;
+ }
+ // now find a generator alpha of the multiplicative
+ // group Z*_p of order p-1=2q
+ b = mpnew(0);
+ while(1){
+ mprand(n, genrandom, alpha);
+ mpmod(alpha, p, alpha);
+ mpmul(alpha, alpha, b);
+ mpmod(b, p, b);
+ if(mpcmp(b, mpone) == 0)
+ continue;
+ mpexp(alpha, q, p, b);
+ if(mpcmp(b, mpone) != 0)
+ break;
+ }
+ mpfree(b);
+ mpfree(q);
+}
--- /dev/null
+++ b/libsec/port/genstrongprime.c
@@ -1,0 +1,57 @@
+#include "os.h"
+#include <mp.h>
+#include <libsec.h>
+
+// Gordon's algorithm for generating a strong prime
+// Menezes et al () Handbook, p.150
+void
+genstrongprime(mpint *p, int n, int accuracy)
+{
+ mpint *s, *t, *r, *i;
+
+ if(n < 64)
+ n = 64;
+
+ s = mpnew(n/2);
+ genprime(s, (n/2)-16, accuracy);
+ t = mpnew(n/2);
+ genprime(t, n-mpsignif(s)-32, accuracy);
+
+ // first r = 2it + 1 that's prime
+ i = mpnew(16);
+ r = mpnew(0);
+ itomp(0x8000, i);
+ mpleft(t, 1, t); // 2t
+ mpmul(i, t, r); // 2it
+ mpadd(r, mpone, r); // 2it + 1
+ for(;;){
+ if(probably_prime(r, 18))
+ break;
+ mpadd(r, t, r); // r += 2t
+ }
+
+ // p0 = 2(s**(r-2) mod r)s - 1
+ itomp(2, p);
+ mpsub(r, p, p);
+ mpexp(s, p, r, p);
+ mpmul(s, p, p);
+ mpleft(p, 1, p);
+ mpsub(p, mpone, p);
+
+ // first p = p0 + 2irs that's prime
+ itomp(0x8000, i);
+ mpleft(r, 1, r); // 2r
+ mpmul(r, s, r); // 2rs
+ mpmul(r, i, i); // 2irs
+ mpadd(p, i, p); // p0 + 2irs
+ for(;;){
+ if(probably_prime(p, accuracy))
+ break;
+ mpadd(p, r, p); // p += 2rs
+ }
+
+ mpfree(i);
+ mpfree(s);
+ mpfree(r);
+ mpfree(t);
+}
--- /dev/null
+++ b/libsec/port/hmac.c
@@ -1,0 +1,56 @@
+#include "os.h"
+#include <libsec.h>
+
+/* rfc2104 */
+static DigestState*
+hmac_x(uchar *p, ulong len, uchar *key, ulong klen, uchar *digest, DigestState *s,
+ DigestState*(*x)(uchar*, ulong, uchar*, DigestState*), int xlen)
+{
+ int i;
+ uchar pad[65], innerdigest[256];
+
+ if(xlen > sizeof(innerdigest))
+ return nil;
+
+ if(klen>64)
+ return nil;
+
+ /* first time through */
+ if(s == nil || s->seeded == 0){
+ for(i=0; i<64; i++)
+ pad[i] = 0x36;
+ pad[64] = 0;
+ for(i=0; i<klen; i++)
+ pad[i] ^= key[i];
+ s = (*x)(pad, 64, nil, s);
+ if(s == nil)
+ return nil;
+ }
+
+ s = (*x)(p, len, nil, s);
+ if(digest == nil)
+ return s;
+
+ /* last time through */
+ for(i=0; i<64; i++)
+ pad[i] = 0x5c;
+ pad[64] = 0;
+ for(i=0; i<klen; i++)
+ pad[i] ^= key[i];
+ (*x)(nil, 0, innerdigest, s);
+ s = (*x)(pad, 64, nil, nil);
+ (*x)(innerdigest, xlen, digest, s);
+ return nil;
+}
+
+DigestState*
+hmac_sha1(uchar *p, ulong len, uchar *key, ulong klen, uchar *digest, DigestState *s)
+{
+ return hmac_x(p, len, key, klen, digest, s, sha1, SHA1dlen);
+}
+
+DigestState*
+hmac_md5(uchar *p, ulong len, uchar *key, ulong klen, uchar *digest, DigestState *s)
+{
+ return hmac_x(p, len, key, klen, digest, s, md5, MD5dlen);
+}
--- /dev/null
+++ b/libsec/port/hmactest.c
@@ -1,0 +1,19 @@
+#include "os.h"
+#include <mp.h>
+#include <libsec.h>
+
+uchar key[] = "Jefe";
+uchar data[] = "what do ya want for nothing?";
+
+void
+main(void)
+{
+ int i;
+ uchar hash[MD5dlen];
+
+ hmac_md5(data, strlen((char*)data), key, 4, hash, nil);
+ for(i=0; i<MD5dlen; i++)
+ print("%2.2x", hash[i]);
+ print("\n");
+ print("750c783e6ab0b503eaa86e310a5db738\n");
+}
--- /dev/null
+++ b/libsec/port/idea.c
@@ -1,0 +1,168 @@
+#include "os.h"
+#include "mp.h"
+#include "libsec.h"
+
+#define KEYLEN 52
+
+#define MODA 0x10000
+#define MODM 0x10001
+#define MASKA (MODA-1)
+
+#define OP1(x, y) ((x) ^ (y))
+#define OP2(x, y) (((x) + (y)) & MASKA)
+#define OP3(x, y) mod(x, y)
+
+#define OP2INV(x) (-(x))
+#define OP3INV(x) inv(x)
+
+#define BIGEND(k, i) ((k[i]<<8)|k[i+1])
+#define MSB(x) ((x)>>8)
+#define LSB(x) ((x)&0xff)
+
+static ushort
+mod(ushort x, ushort y)
+{
+ ushort q, r;
+ uint z;
+
+ if (x == 0)
+ return 1-y;
+ if (y == 0)
+ return 1-x;
+ z = (uint)x*(uint)y;
+ q = z >> 16;
+ r = z & MASKA;
+ return r-q+(r<q);
+}
+
+static ushort
+inv(ushort x)
+{
+ int q, r0, r1, r2, v0, v1, v2;
+
+ if (x <= 1)
+ return x;
+ r0 = MODM;
+ r1 = x;
+ v0 = 0;
+ v1 = 1;
+ while (r1 != 0) {
+ q = r0/r1;
+ r2 = r0-q*r1;
+ v2 = v0-q*v1;
+ r0 = r1;
+ r1 = r2;
+ v0 = v1;
+ v1 = v2;
+ }
+ if (v0 < 0)
+ v0 += MODM;
+ return v0 & MASKA;
+}
+
+static void
+idea_key_setup_decrypt(ushort ek[KEYLEN], ushort dk[KEYLEN])
+{
+ int i;
+
+ for (i = 0; i < 54; i += 6) {
+ dk[i] = OP3INV(ek[48-i]);
+ dk[i+1] = OP2INV(ek[50-i]);
+ dk[i+2] = OP2INV(ek[49-i]);
+ dk[i+3] = OP3INV(ek[51-i]);
+ if (i < 48) {
+ dk[i+4] = ek[46-i];
+ dk[i+5] = ek[47-i];
+ }
+ }
+}
+
+void
+idea_key_setup(uchar key[16], ushort ek[2*KEYLEN])
+{
+ int i, j;
+ ushort tmp, *e = ek;
+
+ for (i = 0; i < 8; i++)
+ ek[i] = BIGEND(key, 2*i);
+ for (i = 8, j = 1; i < KEYLEN; i++, j++) {
+ ek[i] = (e[j&7]<<9)|(e[(j+1)&7]>>7);
+ if (((i+1) & 7) == 0)
+ e += 8;
+ }
+ tmp = ek[49];
+ ek[49] = ek[50];
+ ek[50] = tmp;
+ idea_key_setup_decrypt(ek, &ek[KEYLEN]);
+}
+
+void
+idea_cipher(ushort key[2*KEYLEN], uchar text[8], int decrypting)
+{
+ int i;
+ ushort *k;
+ ushort x[4];
+ ushort tmp, yout, zout;
+
+ k = decrypting ? &key[KEYLEN] : key;
+ for (i = 0; i < 4; i++)
+ x[i] = BIGEND(text, 2*i);
+ for (i = 0; i < 17; i++) {
+ if (!(i&1)) { /* odd round */
+ x[0] = OP3(x[0], k[3*i]);
+ tmp = OP2(x[2], k[3*i+2]);
+ x[2] = OP2(x[1], k[3*i+1]);
+ x[3] = OP3(x[3], k[3*i+3]);
+ x[1] = tmp;
+ }
+ else {
+ tmp = OP3(k[3*i+1], OP1(x[0], x[1]));
+ yout = OP3(OP2(tmp, OP1(x[2], x[3])), k[3*i+2]);
+ zout = OP2(tmp, yout);
+ x[0] = OP1(x[0], yout);
+ x[1] = OP1(x[1], yout);
+ x[2] = OP1(x[2], zout);
+ x[3] = OP1(x[3], zout);
+ }
+ }
+ for (i = 0; i < 4; i++) {
+ text[2*i] = MSB(x[i]);
+ text[2*i+1] = LSB(x[i]);
+ }
+}
+
+void
+setupIDEAstate(IDEAstate *s, uchar key[16], uchar *ivec)
+{
+ memset(s, 0, sizeof(*s));
+ memmove(s->key, key, sizeof(s->key));
+ idea_key_setup(key, s->edkey);
+ if(ivec)
+ memmove(s->ivec, ivec, 8);
+}
+
+/*
+void
+main()
+{
+ uchar key[] = { 0x00, 0x01, 0x00, 0x02, 0x00, 0x03, 0x00, 0x04,
+ 0x00, 0x05, 0x00, 0x06, 0x00, 0x07, 0x00, 0x08 };
+ uchar plain[] = { 0x00, 0x00, 0x00, 0x01, 0x00, 0x02, 0x00, 0x03 };
+ uchar cipher[] = { 0x11, 0xFB, 0xED, 0x2B, 0x01, 0x98, 0x6D, 0xE5 };
+ ushort edkey[2*KEYLEN];
+ uchar tmp[8];
+
+ memcpy(tmp, plain, 8);
+ idea_key_setup(key, edkey);
+ idea_cipher(edkey, tmp, 0);
+ if (memcmp(tmp, cipher, 8)) {
+ print("encrypt wrong\n");
+ exits("");
+ }
+ idea_cipher(edkey, tmp, 1);
+ if (memcmp(tmp, plain, 8)) {
+ print("decrypt wrong\n");
+ exits("");
+ }
+}
+*/
--- /dev/null
+++ b/libsec/port/md4.c
@@ -1,0 +1,271 @@
+#include "os.h"
+#include <libsec.h>
+
+/*
+ * This MD4 is implemented from the description in Stinson's Cryptography,
+ * theory and practice. -- presotto
+ */
+
+/*
+ * Rotate ammounts used in the algorithm
+ */
+enum
+{
+ S11= 3,
+ S12= 7,
+ S13= 11,
+ S14= 19,
+
+ S21= 3,
+ S22= 5,
+ S23= 9,
+ S24= 13,
+
+ S31= 3,
+ S32= 9,
+ S33= 11,
+ S34= 15,
+};
+
+typedef struct MD4Table MD4Table;
+struct MD4Table
+{
+ uchar x; /* index into data block */
+ uchar rot; /* amount to rotate left by */
+};
+
+static MD4Table tab[] =
+{
+ /* round 1 */
+/*[0]*/ { 0, S11},
+ { 1, S12},
+ { 2, S13},
+ { 3, S14},
+ { 4, S11},
+ { 5, S12},
+ { 6, S13},
+ { 7, S14},
+ { 8, S11},
+ { 9, S12},
+ { 10, S13},
+ { 11, S14},
+ { 12, S11},
+ { 13, S12},
+ { 14, S13},
+ { 15, S14},
+
+ /* round 2 */
+/*[16]*/{ 0, S21},
+ { 4, S22},
+ { 8, S23},
+ { 12, S24},
+ { 1, S21},
+ { 5, S22},
+ { 9, S23},
+ { 13, S24},
+ { 2, S21},
+ { 6, S22},
+ { 10, S23},
+ { 14, S24},
+ { 3, S21},
+ { 7, S22},
+ { 11, S23},
+ { 15, S24},
+
+ /* round 3 */
+/*[32]*/{ 0, S31},
+ { 8, S32},
+ { 4, S33},
+ { 12, S34},
+ { 2, S31},
+ { 10, S32},
+ { 6, S33},
+ { 14, S34},
+ { 1, S31},
+ { 9, S32},
+ { 5, S33},
+ { 13, S34},
+ { 3, S31},
+ { 11, S32},
+ { 7, S33},
+ { 15, S34},
+};
+
+static void encode(uchar*, u32int*, ulong);
+static void decode(u32int*, uchar*, ulong);
+
+static void
+md4block(uchar *p, ulong len, MD4state *s)
+{
+ int i;
+ u32int a, b, c, d, tmp;
+ MD4Table *t;
+ uchar *end;
+ u32int x[16];
+
+ for(end = p+len; p < end; p += 64){
+ a = s->state[0];
+ b = s->state[1];
+ c = s->state[2];
+ d = s->state[3];
+
+ decode(x, p, 64);
+
+ for(i = 0; i < 48; i++){
+ t = tab + i;
+ switch(i>>4){
+ case 0:
+ a += (b & c) | (~b & d);
+ break;
+ case 1:
+ a += ((b & c) | (b & d) | (c & d)) + 0x5A827999;
+ break;
+ case 2:
+ a += (b ^ c ^ d) + 0x6ED9EBA1;
+ break;
+ }
+ a += x[t->x];
+ a = (a << t->rot) | (a >> (32 - t->rot));
+
+ /* rotate variables */
+ tmp = d;
+ d = c;
+ c = b;
+ b = a;
+ a = tmp;
+ }
+
+ s->state[0] += a;
+ s->state[1] += b;
+ s->state[2] += c;
+ s->state[3] += d;
+
+ s->len += 64;
+ }
+}
+
+MD4state*
+md4(uchar *p, ulong len, uchar *digest, MD4state *s)
+{
+ u32int x[16];
+ uchar buf[128];
+ int i;
+ uchar *e;
+
+ if(s == nil){
+ s = malloc(sizeof(*s));
+ if(s == nil)
+ return nil;
+ memset(s, 0, sizeof(*s));
+ s->malloced = 1;
+ }
+
+ if(s->seeded == 0){
+ /* seed the state, these constants would look nicer big-endian */
+ s->state[0] = 0x67452301;
+ s->state[1] = 0xefcdab89;
+ s->state[2] = 0x98badcfe;
+ s->state[3] = 0x10325476;
+ s->seeded = 1;
+ }
+
+ /* fill out the partial 64 byte block from previous calls */
+ if(s->blen){
+ i = 64 - s->blen;
+ if(len < i)
+ i = len;
+ memmove(s->buf + s->blen, p, i);
+ len -= i;
+ s->blen += i;
+ p += i;
+ if(s->blen == 64){
+ md4block(s->buf, s->blen, s);
+ s->blen = 0;
+ }
+ }
+
+ /* do 64 byte blocks */
+ i = len & ~0x3f;
+ if(i){
+ md4block(p, i, s);
+ len -= i;
+ p += i;
+ }
+
+ /* save the left overs if not last call */
+ if(digest == 0){
+ if(len){
+ memmove(s->buf, p, len);
+ s->blen += len;
+ }
+ return s;
+ }
+
+ /*
+ * this is the last time through, pad what's left with 0x80,
+ * 0's, and the input count to create a multiple of 64 bytes
+ */
+ if(s->blen){
+ p = s->buf;
+ len = s->blen;
+ } else {
+ memmove(buf, p, len);
+ p = buf;
+ }
+ s->len += len;
+ e = p + len;
+ if(len < 56)
+ i = 56 - len;
+ else
+ i = 120 - len;
+ memset(e, 0, i);
+ *e = 0x80;
+ len += i;
+
+ /* append the count */
+ x[0] = s->len<<3;
+ x[1] = s->len>>29;
+ encode(p+len, x, 8);
+
+ /* digest the last part */
+ md4block(p, len+8, s);
+
+ /* return result and free state */
+ encode(digest, s->state, MD4dlen);
+ if(s->malloced == 1)
+ free(s);
+ return nil;
+}
+
+/*
+ * encodes input (u32int) into output (uchar). Assumes len is
+ * a multiple of 4.
+ */
+static void
+encode(uchar *output, u32int *input, ulong len)
+{
+ u32int x;
+ uchar *e;
+
+ for(e = output + len; output < e;) {
+ x = *input++;
+ *output++ = x;
+ *output++ = x >> 8;
+ *output++ = x >> 16;
+ *output++ = x >> 24;
+ }
+}
+
+/*
+ * decodes input (uchar) into output (u32int). Assumes len is
+ * a multiple of 4.
+ */
+static void
+decode(u32int *output, uchar *input, ulong len)
+{
+ uchar *e;
+
+ for(e = input+len; input < e; input += 4)
+ *output++ = input[0] | (input[1] << 8) |
+ (input[2] << 16) | (input[3] << 24);
+}
--- /dev/null
+++ b/libsec/port/md4test.c
@@ -1,0 +1,31 @@
+#include "os.h"
+#include <mp.h>
+#include <libsec.h>
+
+char *tests[] = {
+ "",
+ "a",
+ "abc",
+ "message digest",
+ "abcdefghijklmnopqrstuvwxyz",
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789",
+ "12345678901234567890123456789012345678901234567890123456789012345678901234567890",
+ 0
+};
+
+void
+main(void)
+{
+ char **pp;
+ uchar *p;
+ int i;
+ uchar digest[MD5dlen];
+
+ for(pp = tests; *pp; pp++){
+ p = (uchar*)*pp;
+ md4(p, strlen(*pp), digest, 0);
+ for(i = 0; i < MD5dlen; i++)
+ print("%2.2ux", digest[i]);
+ print("\n");
+ }
+}
--- /dev/null
+++ b/libsec/port/md5.c
@@ -1,0 +1,147 @@
+#include "os.h"
+#include <libsec.h>
+
+/*
+ * rfc1321 requires that I include this. The code is new. The constants
+ * all come from the rfc (hence the copyright). We trade a table for the
+ * macros in rfc. The total size is a lot less. -- presotto
+ *
+ * Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All
+ * rights reserved.
+ *
+ * License to copy and use this software is granted provided that it
+ * is identified as the "RSA Data Security, Inc. MD5 Message-Digest
+ * Algorithm" in all material mentioning or referencing this software
+ * or this function.
+ *
+ * License is also granted to make and use derivative works provided
+ * that such works are identified as "derived from the RSA Data
+ * Security, Inc. MD5 Message-Digest Algorithm" in all material
+ * mentioning or referencing the derived work.
+ *
+ * RSA Data Security, Inc. makes no representations concerning either
+ * the merchantability of this software or the suitability of this
+ * software forany particular purpose. It is provided "as is"
+ * without express or implied warranty of any kind.
+ * These notices must be retained in any copies of any part of this
+ * documentation and/or software.
+ */
+
+static void encode(uchar*, u32int*, ulong);
+
+extern void _md5block(uchar*, ulong, u32int*);
+
+MD5state*
+md5(uchar *p, ulong len, uchar *digest, MD5state *s)
+{
+ u32int x[16];
+ uchar buf[128];
+ int i;
+ uchar *e;
+
+ if(s == nil){
+ s = malloc(sizeof(*s));
+ if(s == nil)
+ return nil;
+ memset(s, 0, sizeof(*s));
+ s->malloced = 1;
+ }
+
+ if(s->seeded == 0){
+ /* seed the state, these constants would look nicer big-endian */
+ s->state[0] = 0x67452301;
+ s->state[1] = 0xefcdab89;
+ s->state[2] = 0x98badcfe;
+ s->state[3] = 0x10325476;
+ s->seeded = 1;
+ }
+
+ /* fill out the partial 64 byte block from previous calls */
+ if(s->blen){
+ i = 64 - s->blen;
+ if(len < i)
+ i = len;
+ memmove(s->buf + s->blen, p, i);
+ len -= i;
+ s->blen += i;
+ p += i;
+ if(s->blen == 64){
+ _md5block(s->buf, s->blen, s->state);
+ s->len += s->blen;
+ s->blen = 0;
+ }
+ }
+
+ /* do 64 byte blocks */
+ i = len & ~0x3f;
+ if(i){
+ _md5block(p, i, s->state);
+ s->len += i;
+ len -= i;
+ p += i;
+ }
+
+ /* save the left overs if not last call */
+ if(digest == 0){
+ if(len){
+ memmove(s->buf, p, len);
+ s->blen += len;
+ }
+ return s;
+ }
+
+ /*
+ * this is the last time through, pad what's left with 0x80,
+ * 0's, and the input count to create a multiple of 64 bytes
+ */
+ if(s->blen){
+ p = s->buf;
+ len = s->blen;
+ } else {
+ memmove(buf, p, len);
+ p = buf;
+ }
+ s->len += len;
+ e = p + len;
+ if(len < 56)
+ i = 56 - len;
+ else
+ i = 120 - len;
+ memset(e, 0, i);
+ *e = 0x80;
+ len += i;
+
+ /* append the count */
+ x[0] = s->len<<3;
+ x[1] = s->len>>29;
+ encode(p+len, x, 8);
+
+ /* digest the last part */
+ _md5block(p, len+8, s->state);
+ s->len += len;
+
+ /* return result and free state */
+ encode(digest, s->state, MD5dlen);
+ if(s->malloced == 1)
+ free(s);
+ return nil;
+}
+
+/*
+ * encodes input (u32int) into output (uchar). Assumes len is
+ * a multiple of 4.
+ */
+static void
+encode(uchar *output, u32int *input, ulong len)
+{
+ u32int x;
+ uchar *e;
+
+ for(e = output + len; output < e;) {
+ x = *input++;
+ *output++ = x;
+ *output++ = x >> 8;
+ *output++ = x >> 16;
+ *output++ = x >> 24;
+ }
+}
--- /dev/null
+++ b/libsec/port/md5block.c
@@ -1,0 +1,267 @@
+#include "os.h"
+#include <libsec.h>
+
+/*
+ * rfc1321 requires that I include this. The code is new. The constants
+ * all come from the rfc (hence the copyright). We trade a table for the
+ * macros in rfc. The total size is a lot less. -- presotto
+ *
+ * Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All
+ * rights reserved.
+ *
+ * License to copy and use this software is granted provided that it
+ * is identified as the "RSA Data Security, Inc. MD5 Message-Digest
+ * Algorithm" in all material mentioning or referencing this software
+ * or this function.
+ *
+ * License is also granted to make and use derivative works provided
+ * that such works are identified as "derived from the RSA Data
+ * Security, Inc. MD5 Message-Digest Algorithm" in all material
+ * mentioning or referencing the derived work.
+ *
+ * RSA Data Security, Inc. makes no representations concerning either
+ * the merchantability of this software or the suitability of this
+ * software forany particular purpose. It is provided "as is"
+ * without express or implied warranty of any kind.
+ * These notices must be retained in any copies of any part of this
+ * documentation and/or software.
+ */
+
+/*
+ * Rotate ammounts used in the algorithm
+ */
+enum
+{
+ S11= 7,
+ S12= 12,
+ S13= 17,
+ S14= 22,
+
+ S21= 5,
+ S22= 9,
+ S23= 14,
+ S24= 20,
+
+ S31= 4,
+ S32= 11,
+ S33= 16,
+ S34= 23,
+
+ S41= 6,
+ S42= 10,
+ S43= 15,
+ S44= 21
+};
+
+static u32int md5tab[] =
+{
+ /* round 1 */
+/*[0]*/ 0xd76aa478,
+ 0xe8c7b756,
+ 0x242070db,
+ 0xc1bdceee,
+ 0xf57c0faf,
+ 0x4787c62a,
+ 0xa8304613,
+ 0xfd469501,
+ 0x698098d8,
+ 0x8b44f7af,
+ 0xffff5bb1,
+ 0x895cd7be,
+ 0x6b901122,
+ 0xfd987193,
+ 0xa679438e,
+ 0x49b40821,
+
+ /* round 2 */
+/*[16]*/0xf61e2562,
+ 0xc040b340,
+ 0x265e5a51,
+ 0xe9b6c7aa,
+ 0xd62f105d,
+ 0x2441453,
+ 0xd8a1e681,
+ 0xe7d3fbc8,
+ 0x21e1cde6,
+ 0xc33707d6,
+ 0xf4d50d87,
+ 0x455a14ed,
+ 0xa9e3e905,
+ 0xfcefa3f8,
+ 0x676f02d9,
+ 0x8d2a4c8a,
+
+ /* round 3 */
+/*[32]*/0xfffa3942,
+ 0x8771f681,
+ 0x6d9d6122,
+ 0xfde5380c,
+ 0xa4beea44,
+ 0x4bdecfa9,
+ 0xf6bb4b60,
+ 0xbebfbc70,
+ 0x289b7ec6,
+ 0xeaa127fa,
+ 0xd4ef3085,
+ 0x4881d05,
+ 0xd9d4d039,
+ 0xe6db99e5,
+ 0x1fa27cf8,
+ 0xc4ac5665,
+
+ /* round 4 */
+/*[48]*/0xf4292244,
+ 0x432aff97,
+ 0xab9423a7,
+ 0xfc93a039,
+ 0x655b59c3,
+ 0x8f0ccc92,
+ 0xffeff47d,
+ 0x85845dd1,
+ 0x6fa87e4f,
+ 0xfe2ce6e0,
+ 0xa3014314,
+ 0x4e0811a1,
+ 0xf7537e82,
+ 0xbd3af235,
+ 0x2ad7d2bb,
+ 0xeb86d391,
+};
+
+static void decode(u32int*, uchar*, ulong);
+extern void _md5block(uchar *p, ulong len, u32int *s);
+
+void
+_md5block(uchar *p, ulong len, u32int *s)
+{
+ u32int a, b, c, d, sh;
+ u32int *t;
+ uchar *end;
+ u32int x[16];
+
+ for(end = p+len; p < end; p += 64){
+ a = s[0];
+ b = s[1];
+ c = s[2];
+ d = s[3];
+
+ decode(x, p, 64);
+
+ t = md5tab;
+ sh = 0;
+ for(; sh != 16; t += 4){
+ a += ((c ^ d) & b) ^ d;
+ a += x[sh] + t[0];
+ a = (a << S11) | (a >> (32 - S11));
+ a += b;
+
+ d += ((b ^ c) & a) ^ c;
+ d += x[sh + 1] + t[1];
+ d = (d << S12) | (d >> (32 - S12));
+ d += a;
+
+ c += ((a ^ b) & d) ^ b;
+ c += x[sh + 2] + t[2];
+ c = (c << S13) | (c >> (32 - S13));
+ c += d;
+
+ b += ((d ^ a) & c) ^ a;
+ b += x[sh + 3] + t[3];
+ b = (b << S14) | (b >> (32 - S14));
+ b += c;
+
+ sh += 4;
+ }
+ sh = 1;
+ for(; sh != 1+20*4; t += 4){
+ a += ((b ^ c) & d) ^ c;
+ a += x[sh & 0xf] + t[0];
+ a = (a << S21) | (a >> (32 - S21));
+ a += b;
+
+ d += ((a ^ b) & c) ^ b;
+ d += x[(sh + 5) & 0xf] + t[1];
+ d = (d << S22) | (d >> (32 - S22));
+ d += a;
+
+ c += ((d ^ a) & b) ^ a;
+ c += x[(sh + 10) & 0xf] + t[2];
+ c = (c << S23) | (c >> (32 - S23));
+ c += d;
+
+ b += ((c ^ d) & a) ^ d;
+ b += x[(sh + 15) & 0xf] + t[3];
+ b = (b << S24) | (b >> (32 - S24));
+ b += c;
+
+ sh += 20;
+ }
+ sh = 5;
+ for(; sh != 5+12*4; t += 4){
+ a += b ^ c ^ d;
+ a += x[sh & 0xf] + t[0];
+ a = (a << S31) | (a >> (32 - S31));
+ a += b;
+
+ d += a ^ b ^ c;
+ d += x[(sh + 3) & 0xf] + t[1];
+ d = (d << S32) | (d >> (32 - S32));
+ d += a;
+
+ c += d ^ a ^ b;
+ c += x[(sh + 6) & 0xf] + t[2];
+ c = (c << S33) | (c >> (32 - S33));
+ c += d;
+
+ b += c ^ d ^ a;
+ b += x[(sh + 9) & 0xf] + t[3];
+ b = (b << S34) | (b >> (32 - S34));
+ b += c;
+
+ sh += 12;
+ }
+ sh = 0;
+ for(; sh != 28*4; t += 4){
+ a += c ^ (b | ~d);
+ a += x[sh & 0xf] + t[0];
+ a = (a << S41) | (a >> (32 - S41));
+ a += b;
+
+ d += b ^ (a | ~c);
+ d += x[(sh + 7) & 0xf] + t[1];
+ d = (d << S42) | (d >> (32 - S42));
+ d += a;
+
+ c += a ^ (d | ~b);
+ c += x[(sh + 14) & 0xf] + t[2];
+ c = (c << S43) | (c >> (32 - S43));
+ c += d;
+
+ b += d ^ (c | ~a);
+ b += x[(sh + 21) & 0xf] + t[3];
+ b = (b << S44) | (b >> (32 - S44));
+ b += c;
+
+ sh += 28;
+ }
+
+ s[0] += a;
+ s[1] += b;
+ s[2] += c;
+ s[3] += d;
+ }
+}
+
+/*
+ * decodes input (uchar) into output (u32int). Assumes len is
+ * a multiple of 4.
+ */
+static void
+decode(u32int *output, uchar *input, ulong len)
+{
+ uchar *e;
+
+ for(e = input+len; input < e; input += 4)
+ *output++ = input[0] | (input[1] << 8) |
+ (input[2] << 16) | (input[3] << 24);
+}
--- /dev/null
+++ b/libsec/port/md5pickle.c
@@ -1,0 +1,39 @@
+#include "os.h"
+#include <libsec.h>
+
+char*
+md5pickle(MD5state *s)
+{
+ char *p;
+ int m, n;
+
+ m = 17+4*9+4*((s->blen+3)/3 + 1);
+ p = malloc(m);
+ if(p == nil)
+ return p;
+ n = sprint(p, "%16.16llux %8.8ux %8.8ux %8.8ux %8.8ux ",
+ s->len,
+ s->state[0], s->state[1], s->state[2],
+ s->state[3]);
+ enc64(p+n, m-n, s->buf, s->blen);
+ return p;
+}
+
+MD5state*
+md5unpickle(char *p)
+{
+ MD5state *s;
+
+ s = malloc(sizeof(*s));
+ if(s == nil)
+ return nil;
+ s->len = strtoull(p, &p, 16);
+ s->state[0] = strtoul(p, &p, 16);
+ s->state[1] = strtoul(p, &p, 16);
+ s->state[2] = strtoul(p, &p, 16);
+ s->state[3] = strtoul(p, &p, 16);
+ s->blen = dec64(s->buf, sizeof(s->buf), p, strlen(p));
+ s->malloced = 1;
+ s->seeded = 1;
+ return s;
+}
--- /dev/null
+++ b/libsec/port/mkfile
@@ -1,0 +1,33 @@
+<../../mkconfig
+
+LIB=libsec.a
+
+CFILES = des.c desmodes.c desECB.c desCBC.c des3ECB.c des3CBC.c\
+ aes.c blowfish.c \
+ idea.c \
+ hmac.c md5.c md5block.c md4.c sha1.c sha1block.c\
+ sha2.c sha256block.c sha512block.c\
+ sha1pickle.c md5pickle.c\
+ rc4.c\
+ genrandom.c prng.c fastrand.c nfastrand.c\
+ probably_prime.c smallprimetest.c genprime.c dsaprimes.c gensafeprime.c genstrongprime.c\
+ rsagen.c rsafill.c rsaencrypt.c rsadecrypt.c rsaalloc.c rsaprivtopub.c \
+ eggen.c egencrypt.c egdecrypt.c egalloc.c egprivtopub.c egsign.c egverify.c \
+ dsagen.c dsaalloc.c dsaprivtopub.c dsasign.c dsaverify.c \
+
+ALLOFILES=${CFILES:%.c=%.$O}
+
+# cull things in the per-machine directories from this list
+OFILES= `{$SHELLNAME ./reduce-$SHELLTYPE $O $TARGMODEL-$OBJTYPE $ALLOFILES }
+
+HFILES=\
+ $ROOT/include/libsec.h\
+ $ROOT/libmp/port/os.h\
+
+CFLAGS=$CFLAGS -I../../libmp/port
+
+UPDATE=mkfile\
+ $HFILES\
+ $CFILES\
+
+<$ROOT/mkfiles/mksyslib-$SHELLTYPE
--- /dev/null
+++ b/libsec/port/nfastrand.c
@@ -1,0 +1,22 @@
+#include "os.h"
+#include <libsec.h>
+
+#define Maxrand ((1UL<<31)-1)
+
+ulong
+nfastrand(ulong n)
+{
+ ulong m, r;
+
+ /*
+ * set m to the maximum multiple of n <= 2^31-1
+ * so we want a random number < m.
+ */
+ if(n > Maxrand)
+ sysfatal("nfastrand: n too large");
+
+ m = Maxrand - Maxrand % n;
+ while((r = fastrand()) >= m)
+ ;
+ return r%n;
+}
--- /dev/null
+++ b/libsec/port/primetest.c
@@ -1,0 +1,41 @@
+#include "os.h"
+#include <mp.h>
+#include <libsec.h>
+
+void
+main(void)
+{
+ mpint *z = mpnew(0);
+ mpint *p = mpnew(0);
+ mpint *q = mpnew(0);
+ mpint *nine = mpnew(0);
+
+ fmtinstall('B', mpconv);
+ strtomp("2492491", nil, 16, z); // 38347921 = x*y = (2**28-9)/7,
+ // an example of 3**(n-1)=1 mod n
+ strtomp("15662C00E811", nil, 16, p);// 23528569104401, a prime
+ uitomp(9, nine);
+
+ if(probably_prime(z, 5) == 1)
+ fprint(2, "tricked primality test\n");
+ if(probably_prime(nine, 5) == 1)
+ fprint(2, "9 passed primality test!\n");
+ if(probably_prime(p, 25) == 1)
+ fprint(2, "ok\n");
+
+ DSAprimes(q, p, nil);
+ print("q=%B\np=%B\n", q, p);
+
+ exits(0);
+}
+
+// example output, checked with Maple:
+// seed EB7B6E35F7CD37B511D96C67D6688CC4DD440E1E
+// q=E0F0EF284E10796C5A2A511E94748BA03C795C13
+// = 1284186945063585093695748280224501481698995297299
+// p=C41CFBE4D4846F67A3DF7DE9921A49D3B42DC33728427AB159CEC8CBBDB12B5F0C244F1A734AEB9840804EA3C25036AD1B61AFF3ABBC247CD4B384224567A863A6F020E7EE9795554BCD08ABAD7321AF27E1E92E3DB1C6E7E94FAAE590AE9C48F96D93D178E809401ABE8A534A1EC44359733475A36A70C7B425125062B1142D
+// = 137715385439333164327584575331308277462546592976152006175830654712456008630139443747529133857837818585400418619916530061955288983751958831927807888408309879880101870216437711393638413509484569804814373511469405934988856674935304074081350525593807908358867354528898618574659752879015380013845760006721861915693
+// r=DF310F4E54A5FEC5D86D3E14863921E834113E060F90052AD332B3241CEF2497EFA0303D6344F7C819691A0F9C4A773815AF8EAECFB7EC1D98F039F17A32A7E887D97251A927D093F44A55577F4D70444AEBD06B9B45695EC23962B175F266895C67D21C4656848614D888A4
+// = 107239359478548771267308764204625458348785444483302647285245969203446101233421655396874997253111222983406676955642093641709149748793954493558324738441197139556917622937892491175016280660608595599724194374948056515856812347094848443460715881455884639869144172708
+// g=2F1C308DC46B9A44B52DF7DACCE1208CCEF72F69C743ADD4D2327173444ED6E65E074694246E07F9FD4AE26E0FDDD9F54F813C40CB9BCD4338EA6F242AB94CD410E676C290368A16B1A3594877437E516C53A6EEE5493A038A017E955E218E7819734E3E2A6E0BAE08B14258F8C03CC1B30E0DDADFCF7CEDF0727684D3D255F1
+// = 33081848392740465806285326014906437543653045153885419334085917570615301913274531387168723847139029827598735376746057461417880810924280288611116213062512408829164220104555543445909528701551198146080221790002337033997295756585193926863581671466708482411159477816144226847280417522524922667065714073338662508017
--- /dev/null
+++ b/libsec/port/prng.c
@@ -1,0 +1,15 @@
+#include "os.h"
+#include <mp.h>
+#include <libsec.h>
+
+//
+// just use the libc prng to fill a buffer
+//
+void
+prng(uchar *p, int n)
+{
+ uchar *e;
+
+ for(e = p+n; p < e; p++)
+ *p = rand();
+}
--- /dev/null
+++ b/libsec/port/probably_prime.c
@@ -1,0 +1,89 @@
+#include "os.h"
+#include <mp.h>
+#include <libsec.h>
+
+/* Miller-Rabin probabilistic primality testing */
+/* Knuth (1981) Seminumerical Algorithms, p.379 */
+/* Menezes et al () Handbook, p.39 */
+/* 0 if composite; 1 if almost surely prime, Pr(err)<1/4**nrep */
+int
+probably_prime(mpint *n, int nrep)
+{
+ int j, k, rep, nbits, isprime;
+ mpint *nm1, *q, *x, *y, *r;
+
+ if(n->sign < 0)
+ sysfatal("negative prime candidate");
+
+ if(nrep <= 0)
+ nrep = 18;
+
+ k = mptoi(n);
+ if(k == 2) /* 2 is prime */
+ return 1;
+ if(k < 2) /* 1 is not prime */
+ return 0;
+ if((n->p[0] & 1) == 0) /* even is not prime */
+ return 0;
+
+ /* test against small prime numbers */
+ if(smallprimetest(n) < 0)
+ return 0;
+
+ /* fermat test, 2^n mod n == 2 if p is prime */
+ x = uitomp(2, nil);
+ y = mpnew(0);
+ mpexp(x, n, n, y);
+ k = mptoi(y);
+ if(k != 2){
+ mpfree(x);
+ mpfree(y);
+ return 0;
+ }
+
+ nbits = mpsignif(n);
+ nm1 = mpnew(nbits);
+ mpsub(n, mpone, nm1); /* nm1 = n - 1 */
+ k = mplowbits0(nm1);
+ q = mpnew(0);
+ mpright(nm1, k, q); /* q = (n-1)/2**k */
+
+ for(rep = 0; rep < nrep; rep++){
+ for(;;){
+ /* find x = random in [2, n-2] */
+ r = mprand(nbits, prng, nil);
+ mpmod(r, nm1, x);
+ mpfree(r);
+ if(mpcmp(x, mpone) > 0)
+ break;
+ }
+
+ /* y = x**q mod n */
+ mpexp(x, q, n, y);
+
+ if(mpcmp(y, mpone) == 0 || mpcmp(y, nm1) == 0)
+ continue;
+
+ for(j = 1;; j++){
+ if(j >= k) {
+ isprime = 0;
+ goto done;
+ }
+ mpmul(y, y, x);
+ mpmod(x, n, y); /* y = y*y mod n */
+ if(mpcmp(y, nm1) == 0)
+ break;
+ if(mpcmp(y, mpone) == 0){
+ isprime = 0;
+ goto done;
+ }
+ }
+ }
+ isprime = 1;
+done:
+ mpfree(y);
+ mpfree(x);
+ mpfree(q);
+ mpfree(nm1);
+ return isprime;
+}
--- /dev/null
+++ b/libsec/port/rc4.c
@@ -1,0 +1,104 @@
+#include "os.h"
+#include <libsec.h>
+
+void
+setupRC4state(RC4state *key, uchar *start, int n)
+{
+ int t;
+ int index2;
+ uchar *state;
+ uchar *p, *e, *sp, *se;
+
+ state = key->state;
+ se = &state[256];
+ for(sp = state; sp < se; sp++)
+ *sp = sp - state;
+
+ key->x = 0;
+ key->y = 0;
+ index2 = 0;
+ e = start + n;
+ p = start;
+ for(sp = state; sp < se; sp++)
+ {
+ t = *sp;
+ index2 = (*p + t + index2) & 255;
+ *sp = state[index2];
+ state[index2] = t;
+ if(++p >= e)
+ p = start;
+ }
+}
+
+void
+rc4(RC4state *key, uchar *p, int len)
+{
+ int tx, ty;
+ int x, y;
+ uchar *state;
+ uchar *e;
+
+ x = key->x;
+ y = key->y;
+ state = &key->state[0];
+ for(e = p + len; p < e; p++)
+ {
+ x = (x+1)&255;
+ tx = state[x];
+ y = (y+tx)&255;
+ ty = state[y];
+ state[x] = ty;
+ state[y] = tx;
+ *p ^= state[(tx+ty)&255];
+ }
+ key->x = x;
+ key->y = y;
+}
+
+void
+rc4skip(RC4state *key, int len)
+{
+ int tx, ty;
+ int x, y;
+ uchar *state;
+ int i;
+
+ x = key->x;
+ y = key->y;
+ state = &key->state[0];
+ for(i=0; i<len; i++)
+ {
+ x = (x+1)&255;
+ tx = state[x];
+ y = (y+tx)&255;
+ ty = state[y];
+ state[x] = ty;
+ state[y] = tx;
+ }
+ key->x = x;
+ key->y = y;
+}
+
+void
+rc4back(RC4state *key, int len)
+{
+ int tx, ty;
+ int x, y;
+ uchar *state;
+ int i;
+
+ x = key->x;
+ y = key->y;
+ state = &key->state[0];
+ for(i=0; i<len; i++)
+ {
+ ty = state[x];
+ tx = state[y];
+ state[y] = ty;
+ state[x] = tx;
+ y = (y-tx)&255;
+ x = (x-1)&255;
+ }
+ key->x = x;
+ key->y = y;
+}
--- /dev/null
+++ b/libsec/port/reduce-nt
@@ -1,0 +1,4 @@
+# for now, just return the input files
+shift # $O
+shift # $SYSTARG-$OBJTYPE
+echo -n $*
--- /dev/null
+++ b/libsec/port/reduce-rc
@@ -1,0 +1,16 @@
+O=$1
+shift
+nonport=$1
+shift
+
+ls -p ../$nonport/*.[cs] >[2]/dev/null | sed 's/..$//' > /tmp/reduce.$pid
+#
+# if empty directory, just return the input files
+#
+if (! ~ $status '|') {
+ echo $*
+ rm /tmp/reduce.$pid
+ exit 0
+}
+echo $* | tr ' ' \012 | grep -v -f /tmp/reduce.$pid | tr \012 ' '
+rm /tmp/reduce.$pid
--- /dev/null
+++ b/libsec/port/reduce-sh
@@ -1,0 +1,13 @@
+O=$1
+shift
+nonport=$1
+shift
+
+for i in $*
+do
+ j=`echo $i | sed 's/\.'$O'//'`
+ if test ! -f ../$nonport/$j.c -a ! -f ../$nonport/$j.s -a ! -f ../$nonport/$j.spp
+ then
+ echo $i
+ fi
+done
--- /dev/null
+++ b/libsec/port/rsaalloc.c
@@ -1,0 +1,52 @@
+#include "os.h"
+#include <mp.h>
+#include <libsec.h>
+
+RSApub*
+rsapuballoc(void)
+{
+ RSApub *rsa;
+
+ rsa = mallocz(sizeof(*rsa), 1);
+ if(rsa == nil)
+ sysfatal("rsapuballoc");
+ return rsa;
+}
+
+void
+rsapubfree(RSApub *rsa)
+{
+ if(rsa == nil)
+ return;
+ mpfree(rsa->ek);
+ mpfree(rsa->n);
+ free(rsa);
+}
+
+
+RSApriv*
+rsaprivalloc(void)
+{
+ RSApriv *rsa;
+
+ rsa = mallocz(sizeof(*rsa), 1);
+ if(rsa == nil)
+ sysfatal("rsaprivalloc");
+ return rsa;
+}
+
+void
+rsaprivfree(RSApriv *rsa)
+{
+ if(rsa == nil)
+ return;
+ mpfree(rsa->pub.ek);
+ mpfree(rsa->pub.n);
+ mpfree(rsa->dk);
+ mpfree(rsa->p);
+ mpfree(rsa->q);
+ mpfree(rsa->kp);
+ mpfree(rsa->kq);
+ mpfree(rsa->c2);
+ free(rsa);
+}
--- /dev/null
+++ b/libsec/port/rsadecrypt.c
@@ -1,0 +1,37 @@
+#include "os.h"
+#include <mp.h>
+#include <libsec.h>
+
+// decrypt rsa using garner's algorithm for the chinese remainder theorem
+// seminumerical algorithms, knuth, pp 253-254
+// applied cryptography, menezes et al, pg 612
+mpint*
+rsadecrypt(RSApriv *rsa, mpint *in, mpint *out)
+{
+ mpint *v1, *v2;
+
+ if(out == nil)
+ out = mpnew(0);
+
+ // convert in to modular representation
+ v1 = mpnew(0);
+ mpmod(in, rsa->p, v1);
+ v2 = mpnew(0);
+ mpmod(in, rsa->q, v2);
+
+ // exponentiate the modular rep
+ mpexp(v1, rsa->kp, rsa->p, v1);
+ mpexp(v2, rsa->kq, rsa->q, v2);
+
+ // out = v1 + p*((v2-v1)*c2 mod q)
+ mpsub(v2, v1, v2);
+ mpmul(v2, rsa->c2, v2);
+ mpmod(v2, rsa->q, v2);
+ mpmul(v2, rsa->p, out);
+ mpadd(v1, out, out);
+
+ mpfree(v1);
+ mpfree(v2);
+
+ return out;
+}
--- /dev/null
+++ b/libsec/port/rsaencrypt.c
@@ -1,0 +1,12 @@
+#include "os.h"
+#include <mp.h>
+#include <libsec.h>
+
+mpint*
+rsaencrypt(RSApub *rsa, mpint *in, mpint *out)
+{
+ if(out == nil)
+ out = mpnew(0);
+ mpexp(in, rsa->ek, rsa->n, out);
+ return out;
+}
--- /dev/null
+++ b/libsec/port/rsafill.c
@@ -1,0 +1,61 @@
+#include "os.h"
+#include <mp.h>
+#include <libsec.h>
+
+RSApriv*
+rsafill(mpint *n, mpint *e, mpint *d, mpint *p, mpint *q)
+{
+ mpint *c2, *kq, *kp, *x;
+ RSApriv *rsa;
+
+ // make sure we're not being hoodwinked
+ if(!probably_prime(p, 10) || !probably_prime(q, 10)){
+ werrstr("rsafill: p or q not prime");
+ return nil;
+ }
+ x = mpnew(0);
+ mpmul(p, q, x);
+ if(mpcmp(n, x) != 0){
+ werrstr("rsafill: n != p*q");
+ mpfree(x);
+ return nil;
+ }
+ c2 = mpnew(0);
+ mpsub(p, mpone, c2);
+ mpsub(q, mpone, x);
+ mpmul(c2, x, x);
+ mpmul(e, d, c2);
+ mpmod(c2, x, x);
+ if(mpcmp(x, mpone) != 0){
+ werrstr("rsafill: e*d != 1 mod (p-1)*(q-1)");
+ mpfree(x);
+ mpfree(c2);
+ return nil;
+ }
+
+ // compute chinese remainder coefficient
+ mpinvert(p, q, c2);
+
+ // for crt a**k mod p == (a**(k mod p-1)) mod p
+ kq = mpnew(0);
+ kp = mpnew(0);
+ mpsub(p, mpone, x);
+ mpmod(d, x, kp);
+ mpsub(q, mpone, x);
+ mpmod(d, x, kq);
+
+ rsa = rsaprivalloc();
+ rsa->pub.ek = mpcopy(e);
+ rsa->pub.n = mpcopy(n);
+ rsa->dk = mpcopy(d);
+ rsa->kp = kp;
+ rsa->kq = kq;
+ rsa->p = mpcopy(p);
+ rsa->q = mpcopy(q);
+ rsa->c2 = c2;
+
+ mpfree(x);
+
+ return rsa;
+}
+
--- /dev/null
+++ b/libsec/port/rsagen.c
@@ -1,0 +1,70 @@
+#include "os.h"
+#include <mp.h>
+#include <libsec.h>
+
+RSApriv*
+rsagen(int nlen, int elen, int rounds)
+{
+ mpint *p, *q, *e, *d, *phi, *n, *t1, *t2, *kp, *kq, *c2;
+ RSApriv *rsa;
+
+ p = mpnew(nlen/2);
+ q = mpnew(nlen/2);
+ n = mpnew(nlen);
+ e = mpnew(elen);
+ d = mpnew(0);
+ phi = mpnew(nlen);
+
+ // create the prime factors and euclid's function
+ genprime(p, nlen/2, rounds);
+ genprime(q, nlen - mpsignif(p) + 1, rounds);
+ mpmul(p, q, n);
+ mpsub(p, mpone, e);
+ mpsub(q, mpone, d);
+ mpmul(e, d, phi);
+
+ // find an e relatively prime to phi
+ t1 = mpnew(0);
+ t2 = mpnew(0);
+ mprand(elen, genrandom, e);
+ if(mpcmp(e,mptwo) <= 0)
+ itomp(3, e);
+ // See Menezes et al. p.291 "8.8 Note (selecting primes)" for discussion
+ // of the merits of various choices of primes and exponents. e=3 is a
+ // common and recommended exponent, but doesn't necessarily work here
+ // because we chose strong rather than safe primes.
+ for(;;){
+ mpextendedgcd(e, phi, t1, d, t2);
+ if(mpcmp(t1, mpone) == 0)
+ break;
+ mpadd(mpone, e, e);
+ }
+ mpfree(t1);
+ mpfree(t2);
+
+ // compute chinese remainder coefficient
+ c2 = mpnew(0);
+ mpinvert(p, q, c2);
+
+ // for crt a**k mod p == (a**(k mod p-1)) mod p
+ kq = mpnew(0);
+ kp = mpnew(0);
+ mpsub(p, mpone, phi);
+ mpmod(d, phi, kp);
+ mpsub(q, mpone, phi);
+ mpmod(d, phi, kq);
+
+ rsa = rsaprivalloc();
+ rsa->pub.ek = e;
+ rsa->pub.n = n;
+ rsa->dk = d;
+ rsa->kp = kp;
+ rsa->kq = kq;
+ rsa->p = p;
+ rsa->q = q;
+ rsa->c2 = c2;
+
+ mpfree(phi);
+
+ return rsa;
+}
--- /dev/null
+++ b/libsec/port/rsaprivtopub.c
@@ -1,0 +1,16 @@
+#include "os.h"
+#include <mp.h>
+#include <libsec.h>
+
+RSApub*
+rsaprivtopub(RSApriv *priv)
+{
+ RSApub *pub;
+
+ pub = rsapuballoc();
+ if(pub == nil)
+ return nil;
+ pub->n = mpcopy(priv->pub.n);
+ pub->ek = mpcopy(priv->pub.ek);
+ return pub;
+}
--- /dev/null
+++ b/libsec/port/rsatest.c
@@ -1,0 +1,57 @@
+#include "os.h"
+#include <mp.h>
+#include <libsec.h>
+#include <bio.h>
+
+void
+main(void)
+{
+ RSApriv *rsa;
+ Biobuf b;
+ char *p;
+ int n;
+ mpint *clr, *enc, *clr2;
+ uchar buf[4096];
+ uchar *e;
+ vlong start;
+
+ fmtinstall('B', mpfmt);
+
+ rsa = rsagen(1024, 16, 0);
+ if(rsa == nil)
+ sysfatal("rsagen");
+ Binit(&b, 0, OREAD);
+ clr = mpnew(0);
+ clr2 = mpnew(0);
+ enc = mpnew(0);
+
+ strtomp("123456789abcdef123456789abcdef123456789abcdef123456789abcdef", nil, 16, clr);
+ rsaencrypt(&rsa->pub, clr, enc);
+
+ start = nsec();
+ for(n = 0; n < 10; n++)
+ rsadecrypt(rsa, enc, clr);
+ print("%lld\n", nsec()-start);
+
+ start = nsec();
+ for(n = 0; n < 10; n++)
+ mpexp(enc, rsa->dk, rsa->pub.n, clr2);
+ print("%lld\n", nsec()-start);
+
+ if(mpcmp(clr, clr2) != 0)
+ print("%B != %B\n", clr, clr2);
+
+ print("> ");
+ while(p = Brdline(&b, '\n')){
+ n = Blinelen(&b);
+ letomp((uchar*)p, n, clr);
+ print("clr %B\n", clr);
+ rsaencrypt(&rsa->pub, clr, enc);
+ print("enc %B\n", enc);
+ rsadecrypt(rsa, enc, clr);
+ print("clr %B\n", clr);
+ n = mptole(clr, buf, sizeof(buf), nil);
+ write(1, buf, n);
+ print("> ");
+ }
+}
--- /dev/null
+++ b/libsec/port/sha1.c
@@ -1,0 +1,127 @@
+#include "os.h"
+#include <libsec.h>
+
+static void encode(uchar*, u32int*, ulong);
+
+extern void _sha1block(uchar*, ulong, u32int*);
+
+/*
+ * we require len to be a multiple of 64 for all but
+ * the last call. There must be room in the input buffer
+ * to pad.
+ */
+SHA1state*
+sha1(uchar *p, ulong len, uchar *digest, SHA1state *s)
+{
+ uchar buf[128];
+ u32int x[16];
+ int i;
+ uchar *e;
+
+ if(s == nil){
+ s = malloc(sizeof(*s));
+ if(s == nil)
+ return nil;
+ memset(s, 0, sizeof(*s));
+ s->malloced = 1;
+ }
+
+ if(s->seeded == 0){
+ /* seed the state, these constants would look nicer big-endian */
+ s->state[0] = 0x67452301;
+ s->state[1] = 0xefcdab89;
+ s->state[2] = 0x98badcfe;
+ s->state[3] = 0x10325476;
+ s->state[4] = 0xc3d2e1f0;
+ s->seeded = 1;
+ }
+
+ /* fill out the partial 64 byte block from previous calls */
+ if(s->blen){
+ i = 64 - s->blen;
+ if(len < i)
+ i = len;
+ memmove(s->buf + s->blen, p, i);
+ len -= i;
+ s->blen += i;
+ p += i;
+ if(s->blen == 64){
+ _sha1block(s->buf, s->blen, s->state);
+ s->len += s->blen;
+ s->blen = 0;
+ }
+ }
+
+ /* do 64 byte blocks */
+ i = len & ~0x3f;
+ if(i){
+ _sha1block(p, i, s->state);
+ s->len += i;
+ len -= i;
+ p += i;
+ }
+
+ /* save the left overs if not last call */
+ if(digest == 0){
+ if(len){
+ memmove(s->buf, p, len);
+ s->blen += len;
+ }
+ return s;
+ }
+
+ /*
+ * this is the last time through, pad what's left with 0x80,
+ * 0's, and the input count to create a multiple of 64 bytes
+ */
+ if(s->blen){
+ p = s->buf;
+ len = s->blen;
+ } else {
+ memmove(buf, p, len);
+ p = buf;
+ }
+ s->len += len;
+ e = p + len;
+ if(len < 56)
+ i = 56 - len;
+ else
+ i = 120 - len;
+ memset(e, 0, i);
+ *e = 0x80;
+ len += i;
+
+ /* append the count */
+ x[0] = s->len>>29;
+ x[1] = s->len<<3;
+ encode(p+len, x, 8);
+
+ /* digest the last part */
+ _sha1block(p, len+8, s->state);
+ s->len += len+8;
+
+ /* return result and free state */
+ encode(digest, s->state, SHA1dlen);
+ if(s->malloced == 1)
+ free(s);
+ return nil;
+}
+
+/*
+ * encodes input (ulong) into output (uchar). Assumes len is
+ * a multiple of 4.
+ */
+static void
+encode(uchar *output, u32int *input, ulong len)
+{
+ u32int x;
+ uchar *e;
+
+ for(e = output + len; output < e;) {
+ x = *input++;
+ *output++ = x >> 24;
+ *output++ = x >> 16;
+ *output++ = x >> 8;
+ *output++ = x;
+ }
+}
--- /dev/null
+++ b/libsec/port/sha1block.c
@@ -1,0 +1,187 @@
+#include "os.h"
+
+void
+_sha1block(uchar *p, ulong len, u32int *s)
+{
+ u32int a, b, c, d, e, x;
+ uchar *end;
+ u32int *wp, *wend;
+ u32int w[80];
+
+ /* at this point, we have a multiple of 64 bytes */
+ for(end = p+len; p < end;){
+ a = s[0];
+ b = s[1];
+ c = s[2];
+ d = s[3];
+ e = s[4];
+
+ wend = w + 15;
+ for(wp = w; wp < wend; wp += 5){
+ wp[0] = (p[0]<<24) | (p[1]<<16) | (p[2]<<8) | p[3];
+ e += ((a<<5) | (a>>27)) + wp[0];
+ e += 0x5a827999 + (((c^d)&b)^d);
+ b = (b<<30)|(b>>2);
+
+ wp[1] = (p[4]<<24) | (p[5]<<16) | (p[6]<<8) | p[7];
+ d += ((e<<5) | (e>>27)) + wp[1];
+ d += 0x5a827999 + (((b^c)&a)^c);
+ a = (a<<30)|(a>>2);
+
+ wp[2] = (p[8]<<24) | (p[9]<<16) | (p[10]<<8) | p[11];
+ c += ((d<<5) | (d>>27)) + wp[2];
+ c += 0x5a827999 + (((a^b)&e)^b);
+ e = (e<<30)|(e>>2);
+
+ wp[3] = (p[12]<<24) | (p[13]<<16) | (p[14]<<8) | p[15];
+ b += ((c<<5) | (c>>27)) + wp[3];
+ b += 0x5a827999 + (((e^a)&d)^a);
+ d = (d<<30)|(d>>2);
+
+ wp[4] = (p[16]<<24) | (p[17]<<16) | (p[18]<<8) | p[19];
+ a += ((b<<5) | (b>>27)) + wp[4];
+ a += 0x5a827999 + (((d^e)&c)^e);
+ c = (c<<30)|(c>>2);
+
+ p += 20;
+ }
+
+ wp[0] = (p[0]<<24) | (p[1]<<16) | (p[2]<<8) | p[3];
+ e += ((a<<5) | (a>>27)) + wp[0];
+ e += 0x5a827999 + (((c^d)&b)^d);
+ b = (b<<30)|(b>>2);
+
+ x = wp[-2] ^ wp[-7] ^ wp[-13] ^ wp[-15];
+ wp[1] = (x<<1) | (x>>31);
+ d += ((e<<5) | (e>>27)) + wp[1];
+ d += 0x5a827999 + (((b^c)&a)^c);
+ a = (a<<30)|(a>>2);
+
+ x = wp[-1] ^ wp[-6] ^ wp[-12] ^ wp[-14];
+ wp[2] = (x<<1) | (x>>31);
+ c += ((d<<5) | (d>>27)) + wp[2];
+ c += 0x5a827999 + (((a^b)&e)^b);
+ e = (e<<30)|(e>>2);
+
+ x = wp[0] ^ wp[-5] ^ wp[-11] ^ wp[-13];
+ wp[3] = (x<<1) | (x>>31);
+ b += ((c<<5) | (c>>27)) + wp[3];
+ b += 0x5a827999 + (((e^a)&d)^a);
+ d = (d<<30)|(d>>2);
+
+ x = wp[1] ^ wp[-4] ^ wp[-10] ^ wp[-12];
+ wp[4] = (x<<1) | (x>>31);
+ a += ((b<<5) | (b>>27)) + wp[4];
+ a += 0x5a827999 + (((d^e)&c)^e);
+ c = (c<<30)|(c>>2);
+
+ wp += 5;
+ p += 4;
+
+ wend = w + 40;
+ for(; wp < wend; wp += 5){
+ x = wp[-3] ^ wp[-8] ^ wp[-14] ^ wp[-16];
+ wp[0] = (x<<1) | (x>>31);
+ e += ((a<<5) | (a>>27)) + wp[0];
+ e += 0x6ed9eba1 + (b^c^d);
+ b = (b<<30)|(b>>2);
+
+ x = wp[-2] ^ wp[-7] ^ wp[-13] ^ wp[-15];
+ wp[1] = (x<<1) | (x>>31);
+ d += ((e<<5) | (e>>27)) + wp[1];
+ d += 0x6ed9eba1 + (a^b^c);
+ a = (a<<30)|(a>>2);
+
+ x = wp[-1] ^ wp[-6] ^ wp[-12] ^ wp[-14];
+ wp[2] = (x<<1) | (x>>31);
+ c += ((d<<5) | (d>>27)) + wp[2];
+ c += 0x6ed9eba1 + (e^a^b);
+ e = (e<<30)|(e>>2);
+
+ x = wp[0] ^ wp[-5] ^ wp[-11] ^ wp[-13];
+ wp[3] = (x<<1) | (x>>31);
+ b += ((c<<5) | (c>>27)) + wp[3];
+ b += 0x6ed9eba1 + (d^e^a);
+ d = (d<<30)|(d>>2);
+
+ x = wp[1] ^ wp[-4] ^ wp[-10] ^ wp[-12];
+ wp[4] = (x<<1) | (x>>31);
+ a += ((b<<5) | (b>>27)) + wp[4];
+ a += 0x6ed9eba1 + (c^d^e);
+ c = (c<<30)|(c>>2);
+ }
+
+ wend = w + 60;
+ for(; wp < wend; wp += 5){
+ x = wp[-3] ^ wp[-8] ^ wp[-14] ^ wp[-16];
+ wp[0] = (x<<1) | (x>>31);
+ e += ((a<<5) | (a>>27)) + wp[0];
+ e += 0x8f1bbcdc + ((b&c)|((b|c)&d));
+ b = (b<<30)|(b>>2);
+
+ x = wp[-2] ^ wp[-7] ^ wp[-13] ^ wp[-15];
+ wp[1] = (x<<1) | (x>>31);
+ d += ((e<<5) | (e>>27)) + wp[1];
+ d += 0x8f1bbcdc + ((a&b)|((a|b)&c));
+ a = (a<<30)|(a>>2);
+
+ x = wp[-1] ^ wp[-6] ^ wp[-12] ^ wp[-14];
+ wp[2] = (x<<1) | (x>>31);
+ c += ((d<<5) | (d>>27)) + wp[2];
+ c += 0x8f1bbcdc + ((e&a)|((e|a)&b));
+ e = (e<<30)|(e>>2);
+
+ x = wp[0] ^ wp[-5] ^ wp[-11] ^ wp[-13];
+ wp[3] = (x<<1) | (x>>31);
+ b += ((c<<5) | (c>>27)) + wp[3];
+ b += 0x8f1bbcdc + ((d&e)|((d|e)&a));
+ d = (d<<30)|(d>>2);
+
+ x = wp[1] ^ wp[-4] ^ wp[-10] ^ wp[-12];
+ wp[4] = (x<<1) | (x>>31);
+ a += ((b<<5) | (b>>27)) + wp[4];
+ a += 0x8f1bbcdc + ((c&d)|((c|d)&e));
+ c = (c<<30)|(c>>2);
+ }
+
+ wend = w + 80;
+ for(; wp < wend; wp += 5){
+ x = wp[-3] ^ wp[-8] ^ wp[-14] ^ wp[-16];
+ wp[0] = (x<<1) | (x>>31);
+ e += ((a<<5) | (a>>27)) + wp[0];
+ e += 0xca62c1d6 + (b^c^d);
+ b = (b<<30)|(b>>2);
+
+ x = wp[-2] ^ wp[-7] ^ wp[-13] ^ wp[-15];
+ wp[1] = (x<<1) | (x>>31);
+ d += ((e<<5) | (e>>27)) + wp[1];
+ d += 0xca62c1d6 + (a^b^c);
+ a = (a<<30)|(a>>2);
+
+ x = wp[-1] ^ wp[-6] ^ wp[-12] ^ wp[-14];
+ wp[2] = (x<<1) | (x>>31);
+ c += ((d<<5) | (d>>27)) + wp[2];
+ c += 0xca62c1d6 + (e^a^b);
+ e = (e<<30)|(e>>2);
+
+ x = wp[0] ^ wp[-5] ^ wp[-11] ^ wp[-13];
+ wp[3] = (x<<1) | (x>>31);
+ b += ((c<<5) | (c>>27)) + wp[3];
+ b += 0xca62c1d6 + (d^e^a);
+ d = (d<<30)|(d>>2);
+
+ x = wp[1] ^ wp[-4] ^ wp[-10] ^ wp[-12];
+ wp[4] = (x<<1) | (x>>31);
+ a += ((b<<5) | (b>>27)) + wp[4];
+ a += 0xca62c1d6 + (c^d^e);
+ c = (c<<30)|(c>>2);
+ }
+
+ /* save state */
+ s[0] += a;
+ s[1] += b;
+ s[2] += c;
+ s[3] += d;
+ s[4] += e;
+ }
+}
--- /dev/null
+++ b/libsec/port/sha1pickle.c
@@ -1,0 +1,38 @@
+#include "os.h"
+#include <libsec.h>
+
+char*
+sha1pickle(SHA1state *s)
+{
+ char *p;
+ int m, n;
+
+ m = 5*9+4*((s->blen+3)/3);
+ p = malloc(m);
+ if(p == nil)
+ return p;
+ n = sprint(p, "%8.8ux %8.8ux %8.8ux %8.8ux %8.8ux ",
+ s->state[0], s->state[1], s->state[2],
+ s->state[3], s->state[4]);
+ enc64(p+n, m-n, s->buf, s->blen);
+ return p;
+}
+
+SHA1state*
+sha1unpickle(char *p)
+{
+ SHA1state *s;
+
+ s = malloc(sizeof(*s));
+ if(s == nil)
+ return nil;
+ s->state[0] = strtoul(p, &p, 16);
+ s->state[1] = strtoul(p, &p, 16);
+ s->state[2] = strtoul(p, &p, 16);
+ s->state[3] = strtoul(p, &p, 16);
+ s->state[4] = strtoul(p, &p, 16);
+ s->blen = dec64(s->buf, sizeof(s->buf), p, strlen(p));
+ s->malloced = 1;
+ s->seeded = 1;
+ return s;
+}
--- /dev/null
+++ b/libsec/port/sha2.c
@@ -1,0 +1,281 @@
+#include "os.h"
+#include <libsec.h>
+
+extern void _sha256block(SHA256state*, uchar*);
+extern void _sha512block(SHA512state*, uchar*);
+
+u32int sha224h0[] = {
+0xc1059ed8, 0x367cd507, 0x3070dd17, 0xf70e5939,
+0xffc00b31, 0x68581511, 0x64f98fa7, 0xbefa4fa4,
+};
+u32int sha256h0[] = {
+0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a,
+0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19,
+};
+
+u64int sha384h0[] = {
+0xcbbb9d5dc1059ed8ULL, 0x629a292a367cd507ULL, 0x9159015a3070dd17ULL, 0x152fecd8f70e5939ULL,
+0x67332667ffc00b31ULL, 0x8eb44a8768581511ULL, 0xdb0c2e0d64f98fa7ULL, 0x47b5481dbefa4fa4ULL,
+};
+u64int sha512h0[] = {
+0x6a09e667f3bcc908ULL, 0xbb67ae8584caa73bULL, 0x3c6ef372fe94f82bULL, 0xa54ff53a5f1d36f1ULL,
+0x510e527fade682d1ULL, 0x9b05688c2b3e6c1fULL, 0x1f83d9abfb41bd6bULL, 0x5be0cd19137e2179ULL,
+};
+
+
+static SHA256state *
+sha256init(void)
+{
+ SHA256state *s;
+
+ s = malloc(sizeof(*s));
+ if(s == nil)
+ return nil;
+ s->malloced = 1;
+ s->seeded = 0;
+ s->len = 0;
+ s->blen = 0;
+
+ return s;
+}
+
+static void
+p32(u32int v, uchar *p)
+{
+ p[0] = v>>24;
+ p[1] = v>>16;
+ p[2] = v>>8;
+ p[3] = v>>0;
+}
+
+static void
+p64(u64int v, uchar *p)
+{
+ p32(v>>32, p);
+ p32(v, p+4);
+}
+
+enum {
+ HI = 0,
+ LO = 1,
+};
+static void
+p128(u64int v[2], uchar *p)
+{
+ p64(v[HI], p);
+ p64(v[LO], p+8);
+}
+
+static void
+uvvadd(u64int v[2], int n)
+{
+ v[LO] += n;
+ if(v[LO] < n) /* overflow */
+ v[HI]++;
+}
+
+static void
+uvvmult8(u64int v[2])
+{
+ v[HI] = (v[HI]<<3) | (v[LO] >> (64-3));
+ v[LO] <<= 3;
+}
+
+
+static void
+_sha256(uchar *p, ulong len, SHA256state *s)
+{
+ u32int take;
+
+ /* complete possible partial block from last time */
+ if(s->blen > 0 && s->blen+len >= SHA256bsize) {
+ take = SHA256bsize-s->blen;
+ memmove(s->buf+s->blen, p, take);
+ p += take;
+ len -= take;
+ _sha256block(s, s->buf);
+ s->len += SHA256bsize;
+ s->blen = 0;
+ memset(s->buf, 0, SHA256bsize);
+ }
+ /* whole blocks */
+ while(len >= SHA256bsize) {
+ _sha256block(s, p);
+ s->len += SHA256bsize;
+ p += SHA256bsize;
+ len -= SHA256bsize;
+ }
+ /* keep possible leftover bytes */
+ if(len > 0) {
+ memmove(s->buf+s->blen, p, len);
+ s->blen += len;
+ }
+}
+
+static void
+sha256finish(SHA256state *s, uchar *digest, int smaller)
+{
+ int i;
+ uchar end[SHA256bsize+8];
+ u32int nzero, nb, nd;
+
+ nzero = (2*SHA256bsize - s->blen - 1 - 8) % SHA256bsize;
+ end[0] = 0x80;
+ memset(end+1, 0, nzero);
+ nb = 8*(s->len+s->blen);
+ p64(nb, end+1+nzero);
+ _sha256(end, 1+nzero+8, s);
+
+ nd = SHA256dlen/4;
+ if(smaller)
+ nd = SHA224dlen/4;
+ for(i = 0; i < nd; i++, digest += 4)
+ p32(s->h32[i], digest);
+}
+
+static SHA256state*
+sha256x(uchar *p, ulong len, uchar *digest, SHA256state *s, int smaller)
+{
+ if(s == nil) {
+ s = sha256init();
+ if(s == nil)
+ return nil;
+ }
+
+ if(s->seeded == 0){
+ memmove(s->h32, smaller? sha224h0: sha256h0, sizeof s->h32);
+ s->seeded = 1;
+ }
+
+ _sha256(p, len, s);
+
+ if(digest == 0)
+ return s;
+
+ sha256finish(s, digest, smaller);
+ if(s->malloced == 1)
+ free(s);
+ return nil;
+}
+
+SHA256state*
+sha224(uchar *p, ulong len, uchar *digest, SHA256state *s)
+{
+ return sha256x(p, len, digest, s, 1);
+}
+
+SHA256state*
+sha256(uchar *p, ulong len, uchar *digest, SHA256state *s)
+{
+ return sha256x(p, len, digest, s, 0);
+}
+
+
+static SHA512state *
+sha512init(void)
+{
+ SHA512state *s;
+
+ s = malloc(sizeof(*s));
+ if(s == nil)
+ return nil;
+ s->malloced = 1;
+ s->seeded = 0;
+ s->nb128[HI] = 0;
+ s->nb128[LO] = 0;
+ s->blen = 0;
+
+ return s;
+}
+
+static void
+_sha512(uchar *p, ulong len, SHA512state *s)
+{
+ u32int take;
+
+ /* complete possible partial block from last time */
+ if(s->blen > 0 && s->blen+len >= SHA512bsize) {
+ take = SHA512bsize-s->blen;
+ memmove(s->buf+s->blen, p, take);
+ p += take;
+ len -= take;
+ _sha512block(s, s->buf);
+ uvvadd(s->nb128, SHA512bsize);
+ s->blen = 0;
+ memset(s->buf, 0, SHA512bsize);
+ }
+ /* whole blocks */
+ while(len >= SHA512bsize) {
+ _sha512block(s, p);
+ uvvadd(s->nb128, SHA512bsize);
+ p += SHA512bsize;
+ len -= SHA512bsize;
+ }
+ /* keep possible leftover bytes */
+ if(len > 0) {
+ memmove(s->buf+s->blen, p, len);
+ s->blen += len;
+ }
+}
+
+void
+sha512finish(SHA512state *s, uchar *digest, int smaller)
+{
+ int i;
+ uchar end[SHA512bsize+16];
+ u32int nzero, n;
+ u64int nb[2];
+
+ nzero = (2*SHA512bsize - s->blen - 1 - 16) % SHA512bsize;
+ end[0] = 0x80;
+ memset(end+1, 0, nzero);
+ nb[0] = s->nb128[0];
+ nb[1] = s->nb128[1];
+ uvvadd(nb, s->blen);
+ uvvmult8(nb);
+ p128(nb, end+1+nzero);
+ _sha512(end, 1+nzero+16, s);
+
+ n = SHA512dlen/8;
+ if(smaller)
+ n = SHA384dlen/8;
+ for(i = 0; i < n; i++, digest += 8)
+ p64(s->h64[i], digest);
+}
+
+static SHA512state*
+sha512x(uchar *p, ulong len, uchar *digest, SHA512state *s, int smaller)
+{
+ if(s == nil) {
+ s = sha512init();
+ if(s == nil)
+ return nil;
+ }
+
+ if(s->seeded == 0){
+ memmove(s->h64, smaller? sha384h0: sha512h0, sizeof s->h64);
+ s->seeded = 1;
+ }
+
+ _sha512(p, len, s);
+
+ if(digest == 0)
+ return s;
+
+ sha512finish(s, digest, smaller);
+ if(s->malloced == 1)
+ free(s);
+ return nil;
+}
+
+SHA512state*
+sha384(uchar *p, ulong len, uchar *digest, SHA512state *s)
+{
+ return sha512x(p, len, digest, s, 1);
+}
+
+SHA512state*
+sha512(uchar *p, ulong len, uchar *digest, SHA512state *s)
+{
+ return sha512x(p, len, digest, s, 0);
+}
--- /dev/null
+++ b/libsec/port/sha256block.c
@@ -1,0 +1,81 @@
+#include "os.h"
+#include <libsec.h>
+
+enum {
+ SHA256rounds = 64,
+};
+
+u32int sha256const[] = {
+0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5,
+0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174,
+0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,
+0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967,
+0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85,
+0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,
+0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3,
+0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2,
+};
+
+
+#define CH(x,y,z) ((x&y) ^ (~x&z))
+#define MAJ(x,y,z) ((x&y) ^ (x&z) ^ (y&z))
+#define ROTR32(n, v) ((v>>n) | (v<<(32-n)))
+#define ROTR64(n, v) ((v>>n) | (v<<(64-n)))
+#define SHR(n, x) (x>>n)
+
+#define SIGMA0a(x) (ROTR32(2, x)^ROTR32(13, x)^ROTR32(22, x))
+#define SIGMA1a(x) (ROTR32(6, x)^ROTR32(11, x)^ROTR32(25, x))
+#define sigma0a(x) (ROTR32(7, x)^ROTR32(18, x)^SHR(3, x))
+#define sigma1a(x) (ROTR32(17, x)^ROTR32(19, x)^SHR(10, x))
+
+/* for use in _sha*() */
+#define A v[0]
+#define B v[1]
+#define C v[2]
+#define D v[3]
+#define E v[4]
+#define F v[5]
+#define G v[6]
+#define H v[7]
+
+static u32int
+g32(uchar *p)
+{
+ return p[0]<<24|p[1]<<16|p[2]<<8|p[3]<<0;
+}
+
+void
+_sha256block(SHA256state *s, uchar *buf)
+{
+ u32int w[2*SHA256bsize/4];
+ int i, t;
+ u32int t1, t2;
+ u32int v[8];
+
+ for(t = 0; t < nelem(w)/2; t++) {
+ if(t < 16) {
+ w[t] = g32(buf);
+ buf += 4;
+ }
+ }
+
+ memmove(v, s->h32, sizeof s->h32);
+
+ for(t = 0; t < SHA256rounds; t++) {
+ if(t >= 16)
+ w[t&31] = sigma1a(w[(t-2)&31]) + w[(t-7)&31] + sigma0a(w[(t-15)&31]) + w[(t-16)&31];
+ t1 = H + SIGMA1a(E) + CH(E,F,G) + sha256const[t] + w[t&31];
+ t2 = SIGMA0a(A) + MAJ(A,B,C);
+ H = G;
+ G = F;
+ F = E;
+ E = D+t1;
+ D = C;
+ C = B;
+ B = A;
+ A = t1+t2;
+ }
+
+ for(i = 0; i < nelem(v); i++)
+ s->h32[i] += v[i];
+}
--- /dev/null
+++ b/libsec/port/sha512block.c
@@ -1,0 +1,114 @@
+#include "os.h"
+#include <libsec.h>
+
+
+enum {
+ SHA512rounds = 80,
+};
+
+u64int sha512const[] = {
+0x428a2f98d728ae22ULL, 0x7137449123ef65cdULL, 0xb5c0fbcfec4d3b2fULL, 0xe9b5dba58189dbbcULL,
+0x3956c25bf348b538ULL, 0x59f111f1b605d019ULL, 0x923f82a4af194f9bULL, 0xab1c5ed5da6d8118ULL,
+0xd807aa98a3030242ULL, 0x12835b0145706fbeULL, 0x243185be4ee4b28cULL, 0x550c7dc3d5ffb4e2ULL,
+0x72be5d74f27b896fULL, 0x80deb1fe3b1696b1ULL, 0x9bdc06a725c71235ULL, 0xc19bf174cf692694ULL,
+0xe49b69c19ef14ad2ULL, 0xefbe4786384f25e3ULL, 0x0fc19dc68b8cd5b5ULL, 0x240ca1cc77ac9c65ULL,
+0x2de92c6f592b0275ULL, 0x4a7484aa6ea6e483ULL, 0x5cb0a9dcbd41fbd4ULL, 0x76f988da831153b5ULL,
+0x983e5152ee66dfabULL, 0xa831c66d2db43210ULL, 0xb00327c898fb213fULL, 0xbf597fc7beef0ee4ULL,
+0xc6e00bf33da88fc2ULL, 0xd5a79147930aa725ULL, 0x06ca6351e003826fULL, 0x142929670a0e6e70ULL,
+0x27b70a8546d22ffcULL, 0x2e1b21385c26c926ULL, 0x4d2c6dfc5ac42aedULL, 0x53380d139d95b3dfULL,
+0x650a73548baf63deULL, 0x766a0abb3c77b2a8ULL, 0x81c2c92e47edaee6ULL, 0x92722c851482353bULL,
+0xa2bfe8a14cf10364ULL, 0xa81a664bbc423001ULL, 0xc24b8b70d0f89791ULL, 0xc76c51a30654be30ULL,
+0xd192e819d6ef5218ULL, 0xd69906245565a910ULL, 0xf40e35855771202aULL, 0x106aa07032bbd1b8ULL,
+0x19a4c116b8d2d0c8ULL, 0x1e376c085141ab53ULL, 0x2748774cdf8eeb99ULL, 0x34b0bcb5e19b48a8ULL,
+0x391c0cb3c5c95a63ULL, 0x4ed8aa4ae3418acbULL, 0x5b9cca4f7763e373ULL, 0x682e6ff3d6b2b8a3ULL,
+0x748f82ee5defb2fcULL, 0x78a5636f43172f60ULL, 0x84c87814a1f0ab72ULL, 0x8cc702081a6439ecULL,
+0x90befffa23631e28ULL, 0xa4506cebde82bde9ULL, 0xbef9a3f7b2c67915ULL, 0xc67178f2e372532bULL,
+0xca273eceea26619cULL, 0xd186b8c721c0c207ULL, 0xeada7dd6cde0eb1eULL, 0xf57d4f7fee6ed178ULL,
+0x06f067aa72176fbaULL, 0x0a637dc5a2c898a6ULL, 0x113f9804bef90daeULL, 0x1b710b35131c471bULL,
+0x28db77f523047d84ULL, 0x32caab7b40c72493ULL, 0x3c9ebe0a15c9bebcULL, 0x431d67c49c100d4cULL,
+0x4cc5d4becb3e42b6ULL, 0x597f299cfc657e2aULL, 0x5fcb6fab3ad6faecULL, 0x6c44198c4a475817ULL,
+};
+
+
+static u32int
+g32(uchar *p)
+{
+ return p[0]<<24|p[1]<<16|p[2]<<8|p[3]<<0;
+}
+
+static u64int
+g64(uchar *p)
+{
+ return ((u64int)g32(p)<<32)|g32(p+4);
+}
+
+
+#define CH(x,y,z) ((x&y) ^ (~x&z))
+#define MAJ(x,y,z) ((x&y) ^ (x&z) ^ (y&z))
+#define ROTR32(n, v) ((v>>n) | (v<<(32-n)))
+#define ROTR64(n, v) ((v>>n) | (v<<(64-n)))
+#define SHR(n, x) (x>>n)
+
+#define SIGMA0b(x) (ROTR64(28, x)^ROTR64(34, x)^ROTR64(39, x))
+#define SIGMA1b(x) (ROTR64(14, x)^ROTR64(18, x)^ROTR64(41, x))
+#define sigma0b(x) (ROTR64(1, x)^ROTR64(8, x)^SHR(7, x))
+#define sigma1b(x) (ROTR64(19, x)^ROTR64(61, x)^SHR(6, x))
+
+#define A v[0]
+#define B v[1]
+#define C v[2]
+#define D v[3]
+#define E v[4]
+#define F v[5]
+#define G v[6]
+#define H v[7]
+
+void
+_sha512block(SHA512state *s, uchar *buf)
+{
+ u64int w[2*SHA512bsize/8];
+ int i, t;
+ u64int t1, t2, t3, v[8];
+
+ for(t = 0; t < nelem(w)/2; t++) {
+ if(t < 16) {
+ w[t] = g64(buf);
+ buf += 8;
+ }
+ }
+
+ memmove(v, s->h64, sizeof s->h64);
+
+ for(t = 0; t < SHA512rounds; t++) {
+ if(t >= 16) {
+ /* w[t&31] = sigma1b(w[(t-2)&31]) + w[(t-7)&31] + sigma0b(w[(t-15)&31]) + w[(t-16)&31]; */
+ t2 = w[(t-2)&31];
+ t3 = w[(t-15)&31];
+ /* w[t&31] = sigma1b(t2) + w[(t-7)&31] + sigma0b(t3) + w[(t-16)&31]; */
+ t1 = sigma1b(t2);
+ t1 += w[(t-7)&31];
+ t1 += sigma0b(t3);
+ t1 += w[(t-16)&31];
+ w[t&31] = t1;
+ }
+ /* t1 = H + SIGMA1b(E) + CH(E,F,G) + sha512const[t] + w[t&31]; */
+ t1 = H;
+ t1 += SIGMA1b(E);
+ t1 += CH(E, F, G);
+ t1 += sha512const[t] + w[t&31];
+ /* t2 = SIGMA0b(A) + MAJ(A,B,C); */
+ t2 = SIGMA0b(A);
+ t2 += MAJ(A, B, C);
+ H = G;
+ G = F;
+ F = E;
+ E = D+t1;
+ D = C;
+ C = B;
+ B = A;
+ A = t1+t2;
+ }
+
+ for(i = 0; i < nelem(v); i++)
+ s->h64[i] += v[i];
+}
--- /dev/null
+++ b/libsec/port/smallprimes.c
@@ -1,0 +1,1004 @@
+#include "os.h"
+
+ulong smallprimes[1000] = {
+ 2,
+ 3,
+ 5,
+ 7,
+ 11,
+ 13,
+ 17,
+ 19,
+ 23,
+ 29,
+ 31,
+ 37,
+ 41,
+ 43,
+ 47,
+ 53,
+ 59,
+ 61,
+ 67,
+ 71,
+ 73,
+ 79,
+ 83,
+ 89,
+ 97,
+ 101,
+ 103,
+ 107,
+ 109,
+ 113,
+ 127,
+ 131,
+ 137,
+ 139,
+ 149,
+ 151,
+ 157,
+ 163,
+ 167,
+ 173,
+ 179,
+ 181,
+ 191,
+ 193,
+ 197,
+ 199,
+ 211,
+ 223,
+ 227,
+ 229,
+ 233,
+ 239,
+ 241,
+ 251,
+ 257,
+ 263,
+ 269,
+ 271,
+ 277,
+ 281,
+ 283,
+ 293,
+ 307,
+ 311,
+ 313,
+ 317,
+ 331,
+ 337,
+ 347,
+ 349,
+ 353,
+ 359,
+ 367,
+ 373,
+ 379,
+ 383,
+ 389,
+ 397,
+ 401,
+ 409,
+ 419,
+ 421,
+ 431,
+ 433,
+ 439,
+ 443,
+ 449,
+ 457,
+ 461,
+ 463,
+ 467,
+ 479,
+ 487,
+ 491,
+ 499,
+ 503,
+ 509,
+ 521,
+ 523,
+ 541,
+ 547,
+ 557,
+ 563,
+ 569,
+ 571,
+ 577,
+ 587,
+ 593,
+ 599,
+ 601,
+ 607,
+ 613,
+ 617,
+ 619,
+ 631,
+ 641,
+ 643,
+ 647,
+ 653,
+ 659,
+ 661,
+ 673,
+ 677,
+ 683,
+ 691,
+ 701,
+ 709,
+ 719,
+ 727,
+ 733,
+ 739,
+ 743,
+ 751,
+ 757,
+ 761,
+ 769,
+ 773,
+ 787,
+ 797,
+ 809,
+ 811,
+ 821,
+ 823,
+ 827,
+ 829,
+ 839,
+ 853,
+ 857,
+ 859,
+ 863,
+ 877,
+ 881,
+ 883,
+ 887,
+ 907,
+ 911,
+ 919,
+ 929,
+ 937,
+ 941,
+ 947,
+ 953,
+ 967,
+ 971,
+ 977,
+ 983,
+ 991,
+ 997,
+ 1009,
+ 1013,
+ 1019,
+ 1021,
+ 1031,
+ 1033,
+ 1039,
+ 1049,
+ 1051,
+ 1061,
+ 1063,
+ 1069,
+ 1087,
+ 1091,
+ 1093,
+ 1097,
+ 1103,
+ 1109,
+ 1117,
+ 1123,
+ 1129,
+ 1151,
+ 1153,
+ 1163,
+ 1171,
+ 1181,
+ 1187,
+ 1193,
+ 1201,
+ 1213,
+ 1217,
+ 1223,
+ 1229,
+ 1231,
+ 1237,
+ 1249,
+ 1259,
+ 1277,
+ 1279,
+ 1283,
+ 1289,
+ 1291,
+ 1297,
+ 1301,
+ 1303,
+ 1307,
+ 1319,
+ 1321,
+ 1327,
+ 1361,
+ 1367,
+ 1373,
+ 1381,
+ 1399,
+ 1409,
+ 1423,
+ 1427,
+ 1429,
+ 1433,
+ 1439,
+ 1447,
+ 1451,
+ 1453,
+ 1459,
+ 1471,
+ 1481,
+ 1483,
+ 1487,
+ 1489,
+ 1493,
+ 1499,
+ 1511,
+ 1523,
+ 1531,
+ 1543,
+ 1549,
+ 1553,
+ 1559,
+ 1567,
+ 1571,
+ 1579,
+ 1583,
+ 1597,
+ 1601,
+ 1607,
+ 1609,
+ 1613,
+ 1619,
+ 1621,
+ 1627,
+ 1637,
+ 1657,
+ 1663,
+ 1667,
+ 1669,
+ 1693,
+ 1697,
+ 1699,
+ 1709,
+ 1721,
+ 1723,
+ 1733,
+ 1741,
+ 1747,
+ 1753,
+ 1759,
+ 1777,
+ 1783,
+ 1787,
+ 1789,
+ 1801,
+ 1811,
+ 1823,
+ 1831,
+ 1847,
+ 1861,
+ 1867,
+ 1871,
+ 1873,
+ 1877,
+ 1879,
+ 1889,
+ 1901,
+ 1907,
+ 1913,
+ 1931,
+ 1933,
+ 1949,
+ 1951,
+ 1973,
+ 1979,
+ 1987,
+ 1993,
+ 1997,
+ 1999,
+ 2003,
+ 2011,
+ 2017,
+ 2027,
+ 2029,
+ 2039,
+ 2053,
+ 2063,
+ 2069,
+ 2081,
+ 2083,
+ 2087,
+ 2089,
+ 2099,
+ 2111,
+ 2113,
+ 2129,
+ 2131,
+ 2137,
+ 2141,
+ 2143,
+ 2153,
+ 2161,
+ 2179,
+ 2203,
+ 2207,
+ 2213,
+ 2221,
+ 2237,
+ 2239,
+ 2243,
+ 2251,
+ 2267,
+ 2269,
+ 2273,
+ 2281,
+ 2287,
+ 2293,
+ 2297,
+ 2309,
+ 2311,
+ 2333,
+ 2339,
+ 2341,
+ 2347,
+ 2351,
+ 2357,
+ 2371,
+ 2377,
+ 2381,
+ 2383,
+ 2389,
+ 2393,
+ 2399,
+ 2411,
+ 2417,
+ 2423,
+ 2437,
+ 2441,
+ 2447,
+ 2459,
+ 2467,
+ 2473,
+ 2477,
+ 2503,
+ 2521,
+ 2531,
+ 2539,
+ 2543,
+ 2549,
+ 2551,
+ 2557,
+ 2579,
+ 2591,
+ 2593,
+ 2609,
+ 2617,
+ 2621,
+ 2633,
+ 2647,
+ 2657,
+ 2659,
+ 2663,
+ 2671,
+ 2677,
+ 2683,
+ 2687,
+ 2689,
+ 2693,
+ 2699,
+ 2707,
+ 2711,
+ 2713,
+ 2719,
+ 2729,
+ 2731,
+ 2741,
+ 2749,
+ 2753,
+ 2767,
+ 2777,
+ 2789,
+ 2791,
+ 2797,
+ 2801,
+ 2803,
+ 2819,
+ 2833,
+ 2837,
+ 2843,
+ 2851,
+ 2857,
+ 2861,
+ 2879,
+ 2887,
+ 2897,
+ 2903,
+ 2909,
+ 2917,
+ 2927,
+ 2939,
+ 2953,
+ 2957,
+ 2963,
+ 2969,
+ 2971,
+ 2999,
+ 3001,
+ 3011,
+ 3019,
+ 3023,
+ 3037,
+ 3041,
+ 3049,
+ 3061,
+ 3067,
+ 3079,
+ 3083,
+ 3089,
+ 3109,
+ 3119,
+ 3121,
+ 3137,
+ 3163,
+ 3167,
+ 3169,
+ 3181,
+ 3187,
+ 3191,
+ 3203,
+ 3209,
+ 3217,
+ 3221,
+ 3229,
+ 3251,
+ 3253,
+ 3257,
+ 3259,
+ 3271,
+ 3299,
+ 3301,
+ 3307,
+ 3313,
+ 3319,
+ 3323,
+ 3329,
+ 3331,
+ 3343,
+ 3347,
+ 3359,
+ 3361,
+ 3371,
+ 3373,
+ 3389,
+ 3391,
+ 3407,
+ 3413,
+ 3433,
+ 3449,
+ 3457,
+ 3461,
+ 3463,
+ 3467,
+ 3469,
+ 3491,
+ 3499,
+ 3511,
+ 3517,
+ 3527,
+ 3529,
+ 3533,
+ 3539,
+ 3541,
+ 3547,
+ 3557,
+ 3559,
+ 3571,
+ 3581,
+ 3583,
+ 3593,
+ 3607,
+ 3613,
+ 3617,
+ 3623,
+ 3631,
+ 3637,
+ 3643,
+ 3659,
+ 3671,
+ 3673,
+ 3677,
+ 3691,
+ 3697,
+ 3701,
+ 3709,
+ 3719,
+ 3727,
+ 3733,
+ 3739,
+ 3761,
+ 3767,
+ 3769,
+ 3779,
+ 3793,
+ 3797,
+ 3803,
+ 3821,
+ 3823,
+ 3833,
+ 3847,
+ 3851,
+ 3853,
+ 3863,
+ 3877,
+ 3881,
+ 3889,
+ 3907,
+ 3911,
+ 3917,
+ 3919,
+ 3923,
+ 3929,
+ 3931,
+ 3943,
+ 3947,
+ 3967,
+ 3989,
+ 4001,
+ 4003,
+ 4007,
+ 4013,
+ 4019,
+ 4021,
+ 4027,
+ 4049,
+ 4051,
+ 4057,
+ 4073,
+ 4079,
+ 4091,
+ 4093,
+ 4099,
+ 4111,
+ 4127,
+ 4129,
+ 4133,
+ 4139,
+ 4153,
+ 4157,
+ 4159,
+ 4177,
+ 4201,
+ 4211,
+ 4217,
+ 4219,
+ 4229,
+ 4231,
+ 4241,
+ 4243,
+ 4253,
+ 4259,
+ 4261,
+ 4271,
+ 4273,
+ 4283,
+ 4289,
+ 4297,
+ 4327,
+ 4337,
+ 4339,
+ 4349,
+ 4357,
+ 4363,
+ 4373,
+ 4391,
+ 4397,
+ 4409,
+ 4421,
+ 4423,
+ 4441,
+ 4447,
+ 4451,
+ 4457,
+ 4463,
+ 4481,
+ 4483,
+ 4493,
+ 4507,
+ 4513,
+ 4517,
+ 4519,
+ 4523,
+ 4547,
+ 4549,
+ 4561,
+ 4567,
+ 4583,
+ 4591,
+ 4597,
+ 4603,
+ 4621,
+ 4637,
+ 4639,
+ 4643,
+ 4649,
+ 4651,
+ 4657,
+ 4663,
+ 4673,
+ 4679,
+ 4691,
+ 4703,
+ 4721,
+ 4723,
+ 4729,
+ 4733,
+ 4751,
+ 4759,
+ 4783,
+ 4787,
+ 4789,
+ 4793,
+ 4799,
+ 4801,
+ 4813,
+ 4817,
+ 4831,
+ 4861,
+ 4871,
+ 4877,
+ 4889,
+ 4903,
+ 4909,
+ 4919,
+ 4931,
+ 4933,
+ 4937,
+ 4943,
+ 4951,
+ 4957,
+ 4967,
+ 4969,
+ 4973,
+ 4987,
+ 4993,
+ 4999,
+ 5003,
+ 5009,
+ 5011,
+ 5021,
+ 5023,
+ 5039,
+ 5051,
+ 5059,
+ 5077,
+ 5081,
+ 5087,
+ 5099,
+ 5101,
+ 5107,
+ 5113,
+ 5119,
+ 5147,
+ 5153,
+ 5167,
+ 5171,
+ 5179,
+ 5189,
+ 5197,
+ 5209,
+ 5227,
+ 5231,
+ 5233,
+ 5237,
+ 5261,
+ 5273,
+ 5279,
+ 5281,
+ 5297,
+ 5303,
+ 5309,
+ 5323,
+ 5333,
+ 5347,
+ 5351,
+ 5381,
+ 5387,
+ 5393,
+ 5399,
+ 5407,
+ 5413,
+ 5417,
+ 5419,
+ 5431,
+ 5437,
+ 5441,
+ 5443,
+ 5449,
+ 5471,
+ 5477,
+ 5479,
+ 5483,
+ 5501,
+ 5503,
+ 5507,
+ 5519,
+ 5521,
+ 5527,
+ 5531,
+ 5557,
+ 5563,
+ 5569,
+ 5573,
+ 5581,
+ 5591,
+ 5623,
+ 5639,
+ 5641,
+ 5647,
+ 5651,
+ 5653,
+ 5657,
+ 5659,
+ 5669,
+ 5683,
+ 5689,
+ 5693,
+ 5701,
+ 5711,
+ 5717,
+ 5737,
+ 5741,
+ 5743,
+ 5749,
+ 5779,
+ 5783,
+ 5791,
+ 5801,
+ 5807,
+ 5813,
+ 5821,
+ 5827,
+ 5839,
+ 5843,
+ 5849,
+ 5851,
+ 5857,
+ 5861,
+ 5867,
+ 5869,
+ 5879,
+ 5881,
+ 5897,
+ 5903,
+ 5923,
+ 5927,
+ 5939,
+ 5953,
+ 5981,
+ 5987,
+ 6007,
+ 6011,
+ 6029,
+ 6037,
+ 6043,
+ 6047,
+ 6053,
+ 6067,
+ 6073,
+ 6079,
+ 6089,
+ 6091,
+ 6101,
+ 6113,
+ 6121,
+ 6131,
+ 6133,
+ 6143,
+ 6151,
+ 6163,
+ 6173,
+ 6197,
+ 6199,
+ 6203,
+ 6211,
+ 6217,
+ 6221,
+ 6229,
+ 6247,
+ 6257,
+ 6263,
+ 6269,
+ 6271,
+ 6277,
+ 6287,
+ 6299,
+ 6301,
+ 6311,
+ 6317,
+ 6323,
+ 6329,
+ 6337,
+ 6343,
+ 6353,
+ 6359,
+ 6361,
+ 6367,
+ 6373,
+ 6379,
+ 6389,
+ 6397,
+ 6421,
+ 6427,
+ 6449,
+ 6451,
+ 6469,
+ 6473,
+ 6481,
+ 6491,
+ 6521,
+ 6529,
+ 6547,
+ 6551,
+ 6553,
+ 6563,
+ 6569,
+ 6571,
+ 6577,
+ 6581,
+ 6599,
+ 6607,
+ 6619,
+ 6637,
+ 6653,
+ 6659,
+ 6661,
+ 6673,
+ 6679,
+ 6689,
+ 6691,
+ 6701,
+ 6703,
+ 6709,
+ 6719,
+ 6733,
+ 6737,
+ 6761,
+ 6763,
+ 6779,
+ 6781,
+ 6791,
+ 6793,
+ 6803,
+ 6823,
+ 6827,
+ 6829,
+ 6833,
+ 6841,
+ 6857,
+ 6863,
+ 6869,
+ 6871,
+ 6883,
+ 6899,
+ 6907,
+ 6911,
+ 6917,
+ 6947,
+ 6949,
+ 6959,
+ 6961,
+ 6967,
+ 6971,
+ 6977,
+ 6983,
+ 6991,
+ 6997,
+ 7001,
+ 7013,
+ 7019,
+ 7027,
+ 7039,
+ 7043,
+ 7057,
+ 7069,
+ 7079,
+ 7103,
+ 7109,
+ 7121,
+ 7127,
+ 7129,
+ 7151,
+ 7159,
+ 7177,
+ 7187,
+ 7193,
+ 7207,
+ 7211,
+ 7213,
+ 7219,
+ 7229,
+ 7237,
+ 7243,
+ 7247,
+ 7253,
+ 7283,
+ 7297,
+ 7307,
+ 7309,
+ 7321,
+ 7331,
+ 7333,
+ 7349,
+ 7351,
+ 7369,
+ 7393,
+ 7411,
+ 7417,
+ 7433,
+ 7451,
+ 7457,
+ 7459,
+ 7477,
+ 7481,
+ 7487,
+ 7489,
+ 7499,
+ 7507,
+ 7517,
+ 7523,
+ 7529,
+ 7537,
+ 7541,
+ 7547,
+ 7549,
+ 7559,
+ 7561,
+ 7573,
+ 7577,
+ 7583,
+ 7589,
+ 7591,
+ 7603,
+ 7607,
+ 7621,
+ 7639,
+ 7643,
+ 7649,
+ 7669,
+ 7673,
+ 7681,
+ 7687,
+ 7691,
+ 7699,
+ 7703,
+ 7717,
+ 7723,
+ 7727,
+ 7741,
+ 7753,
+ 7757,
+ 7759,
+ 7789,
+ 7793,
+ 7817,
+ 7823,
+ 7829,
+ 7841,
+ 7853,
+ 7867,
+ 7873,
+ 7877,
+ 7879,
+ 7883,
+ 7901,
+ 7907,
+ 7919,
+};
--- /dev/null
+++ b/libsec/port/smallprimetest.c
@@ -1,0 +1,1039 @@
+#include "os.h"
+#include <mp.h>
+#include <libsec.h>
+
+static ulong smallprimes[] = {
+ 2, 3, 5, 7, 11, 13, 17, 19, 23, 29,
+ 31, 37, 41, 43, 47, 53, 59, 61, 67, 71,
+ 73, 79, 83, 89, 97, 101, 103, 107, 109, 113,
+ 127, 131, 137, 139, 149, 151, 157, 163, 167, 173,
+ 179, 181, 191, 193, 197, 199, 211, 223, 227, 229,
+ 233, 239, 241, 251, 257, 263, 269, 271, 277, 281,
+ 283, 293, 307, 311, 313, 317, 331, 337, 347, 349,
+ 353, 359, 367, 373, 379, 383, 389, 397, 401, 409,
+ 419, 421, 431, 433, 439, 443, 449, 457, 461, 463,
+ 467, 479, 487, 491, 499, 503, 509, 521, 523, 541,
+ 547, 557, 563, 569, 571, 577, 587, 593, 599, 601,
+ 607, 613, 617, 619, 631, 641, 643, 647, 653, 659,
+ 661, 673, 677, 683, 691, 701, 709, 719, 727, 733,
+ 739, 743, 751, 757, 761, 769, 773, 787, 797, 809,
+ 811, 821, 823, 827, 829, 839, 853, 857, 859, 863,
+ 877, 881, 883, 887, 907, 911, 919, 929, 937, 941,
+ 947, 953, 967, 971, 977, 983, 991, 997, 1009, 1013,
+ 1019, 1021, 1031, 1033, 1039, 1049, 1051, 1061, 1063, 1069,
+ 1087, 1091, 1093, 1097, 1103, 1109, 1117, 1123, 1129, 1151,
+ 1153, 1163, 1171, 1181, 1187, 1193, 1201, 1213, 1217, 1223,
+ 1229, 1231, 1237, 1249, 1259, 1277, 1279, 1283, 1289, 1291,
+ 1297, 1301, 1303, 1307, 1319, 1321, 1327, 1361, 1367, 1373,
+ 1381, 1399, 1409, 1423, 1427, 1429, 1433, 1439, 1447, 1451,
+ 1453, 1459, 1471, 1481, 1483, 1487, 1489, 1493, 1499, 1511,
+ 1523, 1531, 1543, 1549, 1553, 1559, 1567, 1571, 1579, 1583,
+ 1597, 1601, 1607, 1609, 1613, 1619, 1621, 1627, 1637, 1657,
+ 1663, 1667, 1669, 1693, 1697, 1699, 1709, 1721, 1723, 1733,
+ 1741, 1747, 1753, 1759, 1777, 1783, 1787, 1789, 1801, 1811,
+ 1823, 1831, 1847, 1861, 1867, 1871, 1873, 1877, 1879, 1889,
+ 1901, 1907, 1913, 1931, 1933, 1949, 1951, 1973, 1979, 1987,
+ 1993, 1997, 1999, 2003, 2011, 2017, 2027, 2029, 2039, 2053,
+ 2063, 2069, 2081, 2083, 2087, 2089, 2099, 2111, 2113, 2129,
+ 2131, 2137, 2141, 2143, 2153, 2161, 2179, 2203, 2207, 2213,
+ 2221, 2237, 2239, 2243, 2251, 2267, 2269, 2273, 2281, 2287,
+ 2293, 2297, 2309, 2311, 2333, 2339, 2341, 2347, 2351, 2357,
+ 2371, 2377, 2381, 2383, 2389, 2393, 2399, 2411, 2417, 2423,
+ 2437, 2441, 2447, 2459, 2467, 2473, 2477, 2503, 2521, 2531,
+ 2539, 2543, 2549, 2551, 2557, 2579, 2591, 2593, 2609, 2617,
+ 2621, 2633, 2647, 2657, 2659, 2663, 2671, 2677, 2683, 2687,
+ 2689, 2693, 2699, 2707, 2711, 2713, 2719, 2729, 2731, 2741,
+ 2749, 2753, 2767, 2777, 2789, 2791, 2797, 2801, 2803, 2819,
+ 2833, 2837, 2843, 2851, 2857, 2861, 2879, 2887, 2897, 2903,
+ 2909, 2917, 2927, 2939, 2953, 2957, 2963, 2969, 2971, 2999,
+ 3001, 3011, 3019, 3023, 3037, 3041, 3049, 3061, 3067, 3079,
+ 3083, 3089, 3109, 3119, 3121, 3137, 3163, 3167, 3169, 3181,
+ 3187, 3191, 3203, 3209, 3217, 3221, 3229, 3251, 3253, 3257,
+ 3259, 3271, 3299, 3301, 3307, 3313, 3319, 3323, 3329, 3331,
+ 3343, 3347, 3359, 3361, 3371, 3373, 3389, 3391, 3407, 3413,
+ 3433, 3449, 3457, 3461, 3463, 3467, 3469, 3491, 3499, 3511,
+ 3517, 3527, 3529, 3533, 3539, 3541, 3547, 3557, 3559, 3571,
+ 3581, 3583, 3593, 3607, 3613, 3617, 3623, 3631, 3637, 3643,
+ 3659, 3671, 3673, 3677, 3691, 3697, 3701, 3709, 3719, 3727,
+ 3733, 3739, 3761, 3767, 3769, 3779, 3793, 3797, 3803, 3821,
+ 3823, 3833, 3847, 3851, 3853, 3863, 3877, 3881, 3889, 3907,
+ 3911, 3917, 3919, 3923, 3929, 3931, 3943, 3947, 3967, 3989,
+ 4001, 4003, 4007, 4013, 4019, 4021, 4027, 4049, 4051, 4057,
+ 4073, 4079, 4091, 4093, 4099, 4111, 4127, 4129, 4133, 4139,
+ 4153, 4157, 4159, 4177, 4201, 4211, 4217, 4219, 4229, 4231,
+ 4241, 4243, 4253, 4259, 4261, 4271, 4273, 4283, 4289, 4297,
+ 4327, 4337, 4339, 4349, 4357, 4363, 4373, 4391, 4397, 4409,
+ 4421, 4423, 4441, 4447, 4451, 4457, 4463, 4481, 4483, 4493,
+ 4507, 4513, 4517, 4519, 4523, 4547, 4549, 4561, 4567, 4583,
+ 4591, 4597, 4603, 4621, 4637, 4639, 4643, 4649, 4651, 4657,
+ 4663, 4673, 4679, 4691, 4703, 4721, 4723, 4729, 4733, 4751,
+ 4759, 4783, 4787, 4789, 4793, 4799, 4801, 4813, 4817, 4831,
+ 4861, 4871, 4877, 4889, 4903, 4909, 4919, 4931, 4933, 4937,
+ 4943, 4951, 4957, 4967, 4969, 4973, 4987, 4993, 4999, 5003,
+ 5009, 5011, 5021, 5023, 5039, 5051, 5059, 5077, 5081, 5087,
+ 5099, 5101, 5107, 5113, 5119, 5147, 5153, 5167, 5171, 5179,
+ 5189, 5197, 5209, 5227, 5231, 5233, 5237, 5261, 5273, 5279,
+ 5281, 5297, 5303, 5309, 5323, 5333, 5347, 5351, 5381, 5387,
+ 5393, 5399, 5407, 5413, 5417, 5419, 5431, 5437, 5441, 5443,
+ 5449, 5471, 5477, 5479, 5483, 5501, 5503, 5507, 5519, 5521,
+ 5527, 5531, 5557, 5563, 5569, 5573, 5581, 5591, 5623, 5639,
+ 5641, 5647, 5651, 5653, 5657, 5659, 5669, 5683, 5689, 5693,
+ 5701, 5711, 5717, 5737, 5741, 5743, 5749, 5779, 5783, 5791,
+ 5801, 5807, 5813, 5821, 5827, 5839, 5843, 5849, 5851, 5857,
+ 5861, 5867, 5869, 5879, 5881, 5897, 5903, 5923, 5927, 5939,
+ 5953, 5981, 5987, 6007, 6011, 6029, 6037, 6043, 6047, 6053,
+ 6067, 6073, 6079, 6089, 6091, 6101, 6113, 6121, 6131, 6133,
+ 6143, 6151, 6163, 6173, 6197, 6199, 6203, 6211, 6217, 6221,
+ 6229, 6247, 6257, 6263, 6269, 6271, 6277, 6287, 6299, 6301,
+ 6311, 6317, 6323, 6329, 6337, 6343, 6353, 6359, 6361, 6367,
+ 6373, 6379, 6389, 6397, 6421, 6427, 6449, 6451, 6469, 6473,
+ 6481, 6491, 6521, 6529, 6547, 6551, 6553, 6563, 6569, 6571,
+ 6577, 6581, 6599, 6607, 6619, 6637, 6653, 6659, 6661, 6673,
+ 6679, 6689, 6691, 6701, 6703, 6709, 6719, 6733, 6737, 6761,
+ 6763, 6779, 6781, 6791, 6793, 6803, 6823, 6827, 6829, 6833,
+ 6841, 6857, 6863, 6869, 6871, 6883, 6899, 6907, 6911, 6917,
+ 6947, 6949, 6959, 6961, 6967, 6971, 6977, 6983, 6991, 6997,
+ 7001, 7013, 7019, 7027, 7039, 7043, 7057, 7069, 7079, 7103,
+ 7109, 7121, 7127, 7129, 7151, 7159, 7177, 7187, 7193, 7207,
+ 7211, 7213, 7219, 7229, 7237, 7243, 7247, 7253, 7283, 7297,
+ 7307, 7309, 7321, 7331, 7333, 7349, 7351, 7369, 7393, 7411,
+ 7417, 7433, 7451, 7457, 7459, 7477, 7481, 7487, 7489, 7499,
+ 7507, 7517, 7523, 7529, 7537, 7541, 7547, 7549, 7559, 7561,
+ 7573, 7577, 7583, 7589, 7591, 7603, 7607, 7621, 7639, 7643,
+ 7649, 7669, 7673, 7681, 7687, 7691, 7699, 7703, 7717, 7723,
+ 7727, 7741, 7753, 7757, 7759, 7789, 7793, 7817, 7823, 7829,
+ 7841, 7853, 7867, 7873, 7877, 7879, 7883, 7901, 7907, 7919,
+ 7927, 7933, 7937, 7949, 7951, 7963, 7993, 8009, 8011, 8017,
+ 8039, 8053, 8059, 8069, 8081, 8087, 8089, 8093, 8101, 8111,
+ 8117, 8123, 8147, 8161, 8167, 8171, 8179, 8191, 8209, 8219,
+ 8221, 8231, 8233, 8237, 8243, 8263, 8269, 8273, 8287, 8291,
+ 8293, 8297, 8311, 8317, 8329, 8353, 8363, 8369, 8377, 8387,
+ 8389, 8419, 8423, 8429, 8431, 8443, 8447, 8461, 8467, 8501,
+ 8513, 8521, 8527, 8537, 8539, 8543, 8563, 8573, 8581, 8597,
+ 8599, 8609, 8623, 8627, 8629, 8641, 8647, 8663, 8669, 8677,
+ 8681, 8689, 8693, 8699, 8707, 8713, 8719, 8731, 8737, 8741,
+ 8747, 8753, 8761, 8779, 8783, 8803, 8807, 8819, 8821, 8831,
+ 8837, 8839, 8849, 8861, 8863, 8867, 8887, 8893, 8923, 8929,
+ 8933, 8941, 8951, 8963, 8969, 8971, 8999, 9001, 9007, 9011,
+ 9013, 9029, 9041, 9043, 9049, 9059, 9067, 9091, 9103, 9109,
+ 9127, 9133, 9137, 9151, 9157, 9161, 9173, 9181, 9187, 9199,
+ 9203, 9209, 9221, 9227, 9239, 9241, 9257, 9277, 9281, 9283,
+ 9293, 9311, 9319, 9323, 9337, 9341, 9343, 9349, 9371, 9377,
+ 9391, 9397, 9403, 9413, 9419, 9421, 9431, 9433, 9437, 9439,
+ 9461, 9463, 9467, 9473, 9479, 9491, 9497, 9511, 9521, 9533,
+ 9539, 9547, 9551, 9587, 9601, 9613, 9619, 9623, 9629, 9631,
+ 9643, 9649, 9661, 9677, 9679, 9689, 9697, 9719, 9721, 9733,
+ 9739, 9743, 9749, 9767, 9769, 9781, 9787, 9791, 9803, 9811,
+ 9817, 9829, 9833, 9839, 9851, 9857, 9859, 9871, 9883, 9887,
+ 9901, 9907, 9923, 9929, 9931, 9941, 9949, 9967, 9973, 10007,
+ 10009, 10037, 10039, 10061, 10067, 10069, 10079, 10091, 10093, 10099,
+ 10103, 10111, 10133, 10139, 10141, 10151, 10159, 10163, 10169, 10177,
+ 10181, 10193, 10211, 10223, 10243, 10247, 10253, 10259, 10267, 10271,
+ 10273, 10289, 10301, 10303, 10313, 10321, 10331, 10333, 10337, 10343,
+ 10357, 10369, 10391, 10399, 10427, 10429, 10433, 10453, 10457, 10459,
+ 10463, 10477, 10487, 10499, 10501, 10513, 10529, 10531, 10559, 10567,
+ 10589, 10597, 10601, 10607, 10613, 10627, 10631, 10639, 10651, 10657,
+ 10663, 10667, 10687, 10691, 10709, 10711, 10723, 10729, 10733, 10739,
+ 10753, 10771, 10781, 10789, 10799, 10831, 10837, 10847, 10853, 10859,
+ 10861, 10867, 10883, 10889, 10891, 10903, 10909, 10937, 10939, 10949,
+ 10957, 10973, 10979, 10987, 10993, 11003, 11027, 11047, 11057, 11059,
+ 11069, 11071, 11083, 11087, 11093, 11113, 11117, 11119, 11131, 11149,
+ 11159, 11161, 11171, 11173, 11177, 11197, 11213, 11239, 11243, 11251,
+ 11257, 11261, 11273, 11279, 11287, 11299, 11311, 11317, 11321, 11329,
+ 11351, 11353, 11369, 11383, 11393, 11399, 11411, 11423, 11437, 11443,
+ 11447, 11467, 11471, 11483, 11489, 11491, 11497, 11503, 11519, 11527,
+ 11549, 11551, 11579, 11587, 11593, 11597, 11617, 11621, 11633, 11657,
+ 11677, 11681, 11689, 11699, 11701, 11717, 11719, 11731, 11743, 11777,
+ 11779, 11783, 11789, 11801, 11807, 11813, 11821, 11827, 11831, 11833,
+ 11839, 11863, 11867, 11887, 11897, 11903, 11909, 11923, 11927, 11933,
+ 11939, 11941, 11953, 11959, 11969, 11971, 11981, 11987, 12007, 12011,
+ 12037, 12041, 12043, 12049, 12071, 12073, 12097, 12101, 12107, 12109,
+ 12113, 12119, 12143, 12149, 12157, 12161, 12163, 12197, 12203, 12211,
+ 12227, 12239, 12241, 12251, 12253, 12263, 12269, 12277, 12281, 12289,
+ 12301, 12323, 12329, 12343, 12347, 12373, 12377, 12379, 12391, 12401,
+ 12409, 12413, 12421, 12433, 12437, 12451, 12457, 12473, 12479, 12487,
+ 12491, 12497, 12503, 12511, 12517, 12527, 12539, 12541, 12547, 12553,
+ 12569, 12577, 12583, 12589, 12601, 12611, 12613, 12619, 12637, 12641,
+ 12647, 12653, 12659, 12671, 12689, 12697, 12703, 12713, 12721, 12739,
+ 12743, 12757, 12763, 12781, 12791, 12799, 12809, 12821, 12823, 12829,
+ 12841, 12853, 12889, 12893, 12899, 12907, 12911, 12917, 12919, 12923,
+ 12941, 12953, 12959, 12967, 12973, 12979, 12983, 13001, 13003, 13007,
+ 13009, 13033, 13037, 13043, 13049, 13063, 13093, 13099, 13103, 13109,
+ 13121, 13127, 13147, 13151, 13159, 13163, 13171, 13177, 13183, 13187,
+ 13217, 13219, 13229, 13241, 13249, 13259, 13267, 13291, 13297, 13309,
+ 13313, 13327, 13331, 13337, 13339, 13367, 13381, 13397, 13399, 13411,
+ 13417, 13421, 13441, 13451, 13457, 13463, 13469, 13477, 13487, 13499,
+ 13513, 13523, 13537, 13553, 13567, 13577, 13591, 13597, 13613, 13619,
+ 13627, 13633, 13649, 13669, 13679, 13681, 13687, 13691, 13693, 13697,
+ 13709, 13711, 13721, 13723, 13729, 13751, 13757, 13759, 13763, 13781,
+ 13789, 13799, 13807, 13829, 13831, 13841, 13859, 13873, 13877, 13879,
+ 13883, 13901, 13903, 13907, 13913, 13921, 13931, 13933, 13963, 13967,
+ 13997, 13999, 14009, 14011, 14029, 14033, 14051, 14057, 14071, 14081,
+ 14083, 14087, 14107, 14143, 14149, 14153, 14159, 14173, 14177, 14197,
+ 14207, 14221, 14243, 14249, 14251, 14281, 14293, 14303, 14321, 14323,
+ 14327, 14341, 14347, 14369, 14387, 14389, 14401, 14407, 14411, 14419,
+ 14423, 14431, 14437, 14447, 14449, 14461, 14479, 14489, 14503, 14519,
+ 14533, 14537, 14543, 14549, 14551, 14557, 14561, 14563, 14591, 14593,
+ 14621, 14627, 14629, 14633, 14639, 14653, 14657, 14669, 14683, 14699,
+ 14713, 14717, 14723, 14731, 14737, 14741, 14747, 14753, 14759, 14767,
+ 14771, 14779, 14783, 14797, 14813, 14821, 14827, 14831, 14843, 14851,
+ 14867, 14869, 14879, 14887, 14891, 14897, 14923, 14929, 14939, 14947,
+ 14951, 14957, 14969, 14983, 15013, 15017, 15031, 15053, 15061, 15073,
+ 15077, 15083, 15091, 15101, 15107, 15121, 15131, 15137, 15139, 15149,
+ 15161, 15173, 15187, 15193, 15199, 15217, 15227, 15233, 15241, 15259,
+ 15263, 15269, 15271, 15277, 15287, 15289, 15299, 15307, 15313, 15319,
+ 15329, 15331, 15349, 15359, 15361, 15373, 15377, 15383, 15391, 15401,
+ 15413, 15427, 15439, 15443, 15451, 15461, 15467, 15473, 15493, 15497,
+ 15511, 15527, 15541, 15551, 15559, 15569, 15581, 15583, 15601, 15607,
+ 15619, 15629, 15641, 15643, 15647, 15649, 15661, 15667, 15671, 15679,
+ 15683, 15727, 15731, 15733, 15737, 15739, 15749, 15761, 15767, 15773,
+ 15787, 15791, 15797, 15803, 15809, 15817, 15823, 15859, 15877, 15881,
+ 15887, 15889, 15901, 15907, 15913, 15919, 15923, 15937, 15959, 15971,
+ 15973, 15991, 16001, 16007, 16033, 16057, 16061, 16063, 16067, 16069,
+ 16073, 16087, 16091, 16097, 16103, 16111, 16127, 16139, 16141, 16183,
+ 16187, 16189, 16193, 16217, 16223, 16229, 16231, 16249, 16253, 16267,
+ 16273, 16301, 16319, 16333, 16339, 16349, 16361, 16363, 16369, 16381,
+ 16411, 16417, 16421, 16427, 16433, 16447, 16451, 16453, 16477, 16481,
+ 16487, 16493, 16519, 16529, 16547, 16553, 16561, 16567, 16573, 16603,
+ 16607, 16619, 16631, 16633, 16649, 16651, 16657, 16661, 16673, 16691,
+ 16693, 16699, 16703, 16729, 16741, 16747, 16759, 16763, 16787, 16811,
+ 16823, 16829, 16831, 16843, 16871, 16879, 16883, 16889, 16901, 16903,
+ 16921, 16927, 16931, 16937, 16943, 16963, 16979, 16981, 16987, 16993,
+ 17011, 17021, 17027, 17029, 17033, 17041, 17047, 17053, 17077, 17093,
+ 17099, 17107, 17117, 17123, 17137, 17159, 17167, 17183, 17189, 17191,
+ 17203, 17207, 17209, 17231, 17239, 17257, 17291, 17293, 17299, 17317,
+ 17321, 17327, 17333, 17341, 17351, 17359, 17377, 17383, 17387, 17389,
+ 17393, 17401, 17417, 17419, 17431, 17443, 17449, 17467, 17471, 17477,
+ 17483, 17489, 17491, 17497, 17509, 17519, 17539, 17551, 17569, 17573,
+ 17579, 17581, 17597, 17599, 17609, 17623, 17627, 17657, 17659, 17669,
+ 17681, 17683, 17707, 17713, 17729, 17737, 17747, 17749, 17761, 17783,
+ 17789, 17791, 17807, 17827, 17837, 17839, 17851, 17863, 17881, 17891,
+ 17903, 17909, 17911, 17921, 17923, 17929, 17939, 17957, 17959, 17971,
+ 17977, 17981, 17987, 17989, 18013, 18041, 18043, 18047, 18049, 18059,
+ 18061, 18077, 18089, 18097, 18119, 18121, 18127, 18131, 18133, 18143,
+ 18149, 18169, 18181, 18191, 18199, 18211, 18217, 18223, 18229, 18233,
+ 18251, 18253, 18257, 18269, 18287, 18289, 18301, 18307, 18311, 18313,
+ 18329, 18341, 18353, 18367, 18371, 18379, 18397, 18401, 18413, 18427,
+ 18433, 18439, 18443, 18451, 18457, 18461, 18481, 18493, 18503, 18517,
+ 18521, 18523, 18539, 18541, 18553, 18583, 18587, 18593, 18617, 18637,
+ 18661, 18671, 18679, 18691, 18701, 18713, 18719, 18731, 18743, 18749,
+ 18757, 18773, 18787, 18793, 18797, 18803, 18839, 18859, 18869, 18899,
+ 18911, 18913, 18917, 18919, 18947, 18959, 18973, 18979, 19001, 19009,
+ 19013, 19031, 19037, 19051, 19069, 19073, 19079, 19081, 19087, 19121,
+ 19139, 19141, 19157, 19163, 19181, 19183, 19207, 19211, 19213, 19219,
+ 19231, 19237, 19249, 19259, 19267, 19273, 19289, 19301, 19309, 19319,
+ 19333, 19373, 19379, 19381, 19387, 19391, 19403, 19417, 19421, 19423,
+ 19427, 19429, 19433, 19441, 19447, 19457, 19463, 19469, 19471, 19477,
+ 19483, 19489, 19501, 19507, 19531, 19541, 19543, 19553, 19559, 19571,
+ 19577, 19583, 19597, 19603, 19609, 19661, 19681, 19687, 19697, 19699,
+ 19709, 19717, 19727, 19739, 19751, 19753, 19759, 19763, 19777, 19793,
+ 19801, 19813, 19819, 19841, 19843, 19853, 19861, 19867, 19889, 19891,
+ 19913, 19919, 19927, 19937, 19949, 19961, 19963, 19973, 19979, 19991,
+ 19993, 19997, 20011, 20021, 20023, 20029, 20047, 20051, 20063, 20071,
+ 20089, 20101, 20107, 20113, 20117, 20123, 20129, 20143, 20147, 20149,
+ 20161, 20173, 20177, 20183, 20201, 20219, 20231, 20233, 20249, 20261,
+ 20269, 20287, 20297, 20323, 20327, 20333, 20341, 20347, 20353, 20357,
+ 20359, 20369, 20389, 20393, 20399, 20407, 20411, 20431, 20441, 20443,
+ 20477, 20479, 20483, 20507, 20509, 20521, 20533, 20543, 20549, 20551,
+ 20563, 20593, 20599, 20611, 20627, 20639, 20641, 20663, 20681, 20693,
+ 20707, 20717, 20719, 20731, 20743, 20747, 20749, 20753, 20759, 20771,
+ 20773, 20789, 20807, 20809, 20849, 20857, 20873, 20879, 20887, 20897,
+ 20899, 20903, 20921, 20929, 20939, 20947, 20959, 20963, 20981, 20983,
+ 21001, 21011, 21013, 21017, 21019, 21023, 21031, 21059, 21061, 21067,
+ 21089, 21101, 21107, 21121, 21139, 21143, 21149, 21157, 21163, 21169,
+ 21179, 21187, 21191, 21193, 21211, 21221, 21227, 21247, 21269, 21277,
+ 21283, 21313, 21317, 21319, 21323, 21341, 21347, 21377, 21379, 21383,
+ 21391, 21397, 21401, 21407, 21419, 21433, 21467, 21481, 21487, 21491,
+ 21493, 21499, 21503, 21517, 21521, 21523, 21529, 21557, 21559, 21563,
+ 21569, 21577, 21587, 21589, 21599, 21601, 21611, 21613, 21617, 21647,
+ 21649, 21661, 21673, 21683, 21701, 21713, 21727, 21737, 21739, 21751,
+ 21757, 21767, 21773, 21787, 21799, 21803, 21817, 21821, 21839, 21841,
+ 21851, 21859, 21863, 21871, 21881, 21893, 21911, 21929, 21937, 21943,
+ 21961, 21977, 21991, 21997, 22003, 22013, 22027, 22031, 22037, 22039,
+ 22051, 22063, 22067, 22073, 22079, 22091, 22093, 22109, 22111, 22123,
+ 22129, 22133, 22147, 22153, 22157, 22159, 22171, 22189, 22193, 22229,
+ 22247, 22259, 22271, 22273, 22277, 22279, 22283, 22291, 22303, 22307,
+ 22343, 22349, 22367, 22369, 22381, 22391, 22397, 22409, 22433, 22441,
+ 22447, 22453, 22469, 22481, 22483, 22501, 22511, 22531, 22541, 22543,
+ 22549, 22567, 22571, 22573, 22613, 22619, 22621, 22637, 22639, 22643,
+ 22651, 22669, 22679, 22691, 22697, 22699, 22709, 22717, 22721, 22727,
+ 22739, 22741, 22751, 22769, 22777, 22783, 22787, 22807, 22811, 22817,
+ 22853, 22859, 22861, 22871, 22877, 22901, 22907, 22921, 22937, 22943,
+ 22961, 22963, 22973, 22993, 23003, 23011, 23017, 23021, 23027, 23029,
+ 23039, 23041, 23053, 23057, 23059, 23063, 23071, 23081, 23087, 23099,
+ 23117, 23131, 23143, 23159, 23167, 23173, 23189, 23197, 23201, 23203,
+ 23209, 23227, 23251, 23269, 23279, 23291, 23293, 23297, 23311, 23321,
+ 23327, 23333, 23339, 23357, 23369, 23371, 23399, 23417, 23431, 23447,
+ 23459, 23473, 23497, 23509, 23531, 23537, 23539, 23549, 23557, 23561,
+ 23563, 23567, 23581, 23593, 23599, 23603, 23609, 23623, 23627, 23629,
+ 23633, 23663, 23669, 23671, 23677, 23687, 23689, 23719, 23741, 23743,
+ 23747, 23753, 23761, 23767, 23773, 23789, 23801, 23813, 23819, 23827,
+ 23831, 23833, 23857, 23869, 23873, 23879, 23887, 23893, 23899, 23909,
+ 23911, 23917, 23929, 23957, 23971, 23977, 23981, 23993, 24001, 24007,
+ 24019, 24023, 24029, 24043, 24049, 24061, 24071, 24077, 24083, 24091,
+ 24097, 24103, 24107, 24109, 24113, 24121, 24133, 24137, 24151, 24169,
+ 24179, 24181, 24197, 24203, 24223, 24229, 24239, 24247, 24251, 24281,
+ 24317, 24329, 24337, 24359, 24371, 24373, 24379, 24391, 24407, 24413,
+ 24419, 24421, 24439, 24443, 24469, 24473, 24481, 24499, 24509, 24517,
+ 24527, 24533, 24547, 24551, 24571, 24593, 24611, 24623, 24631, 24659,
+ 24671, 24677, 24683, 24691, 24697, 24709, 24733, 24749, 24763, 24767,
+ 24781, 24793, 24799, 24809, 24821, 24841, 24847, 24851, 24859, 24877,
+ 24889, 24907, 24917, 24919, 24923, 24943, 24953, 24967, 24971, 24977,
+ 24979, 24989, 25013, 25031, 25033, 25037, 25057, 25073, 25087, 25097,
+ 25111, 25117, 25121, 25127, 25147, 25153, 25163, 25169, 25171, 25183,
+ 25189, 25219, 25229, 25237, 25243, 25247, 25253, 25261, 25301, 25303,
+ 25307, 25309, 25321, 25339, 25343, 25349, 25357, 25367, 25373, 25391,
+ 25409, 25411, 25423, 25439, 25447, 25453, 25457, 25463, 25469, 25471,
+ 25523, 25537, 25541, 25561, 25577, 25579, 25583, 25589, 25601, 25603,
+ 25609, 25621, 25633, 25639, 25643, 25657, 25667, 25673, 25679, 25693,
+ 25703, 25717, 25733, 25741, 25747, 25759, 25763, 25771, 25793, 25799,
+ 25801, 25819, 25841, 25847, 25849, 25867, 25873, 25889, 25903, 25913,
+ 25919, 25931, 25933, 25939, 25943, 25951, 25969, 25981, 25997, 25999,
+ 26003, 26017, 26021, 26029, 26041, 26053, 26083, 26099, 26107, 26111,
+ 26113, 26119, 26141, 26153, 26161, 26171, 26177, 26183, 26189, 26203,
+ 26209, 26227, 26237, 26249, 26251, 26261, 26263, 26267, 26293, 26297,
+ 26309, 26317, 26321, 26339, 26347, 26357, 26371, 26387, 26393, 26399,
+ 26407, 26417, 26423, 26431, 26437, 26449, 26459, 26479, 26489, 26497,
+ 26501, 26513, 26539, 26557, 26561, 26573, 26591, 26597, 26627, 26633,
+ 26641, 26647, 26669, 26681, 26683, 26687, 26693, 26699, 26701, 26711,
+ 26713, 26717, 26723, 26729, 26731, 26737, 26759, 26777, 26783, 26801,
+ 26813, 26821, 26833, 26839, 26849, 26861, 26863, 26879, 26881, 26891,
+ 26893, 26903, 26921, 26927, 26947, 26951, 26953, 26959, 26981, 26987,
+ 26993, 27011, 27017, 27031, 27043, 27059, 27061, 27067, 27073, 27077,
+ 27091, 27103, 27107, 27109, 27127, 27143, 27179, 27191, 27197, 27211,
+ 27239, 27241, 27253, 27259, 27271, 27277, 27281, 27283, 27299, 27329,
+ 27337, 27361, 27367, 27397, 27407, 27409, 27427, 27431, 27437, 27449,
+ 27457, 27479, 27481, 27487, 27509, 27527, 27529, 27539, 27541, 27551,
+ 27581, 27583, 27611, 27617, 27631, 27647, 27653, 27673, 27689, 27691,
+ 27697, 27701, 27733, 27737, 27739, 27743, 27749, 27751, 27763, 27767,
+ 27773, 27779, 27791, 27793, 27799, 27803, 27809, 27817, 27823, 27827,
+ 27847, 27851, 27883, 27893, 27901, 27917, 27919, 27941, 27943, 27947,
+ 27953, 27961, 27967, 27983, 27997, 28001, 28019, 28027, 28031, 28051,
+ 28057, 28069, 28081, 28087, 28097, 28099, 28109, 28111, 28123, 28151,
+ 28163, 28181, 28183, 28201, 28211, 28219, 28229, 28277, 28279, 28283,
+ 28289, 28297, 28307, 28309, 28319, 28349, 28351, 28387, 28393, 28403,
+ 28409, 28411, 28429, 28433, 28439, 28447, 28463, 28477, 28493, 28499,
+ 28513, 28517, 28537, 28541, 28547, 28549, 28559, 28571, 28573, 28579,
+ 28591, 28597, 28603, 28607, 28619, 28621, 28627, 28631, 28643, 28649,
+ 28657, 28661, 28663, 28669, 28687, 28697, 28703, 28711, 28723, 28729,
+ 28751, 28753, 28759, 28771, 28789, 28793, 28807, 28813, 28817, 28837,
+ 28843, 28859, 28867, 28871, 28879, 28901, 28909, 28921, 28927, 28933,
+ 28949, 28961, 28979, 29009, 29017, 29021, 29023, 29027, 29033, 29059,
+ 29063, 29077, 29101, 29123, 29129, 29131, 29137, 29147, 29153, 29167,
+ 29173, 29179, 29191, 29201, 29207, 29209, 29221, 29231, 29243, 29251,
+ 29269, 29287, 29297, 29303, 29311, 29327, 29333, 29339, 29347, 29363,
+ 29383, 29387, 29389, 29399, 29401, 29411, 29423, 29429, 29437, 29443,
+ 29453, 29473, 29483, 29501, 29527, 29531, 29537, 29567, 29569, 29573,
+ 29581, 29587, 29599, 29611, 29629, 29633, 29641, 29663, 29669, 29671,
+ 29683, 29717, 29723, 29741, 29753, 29759, 29761, 29789, 29803, 29819,
+ 29833, 29837, 29851, 29863, 29867, 29873, 29879, 29881, 29917, 29921,
+ 29927, 29947, 29959, 29983, 29989, 30011, 30013, 30029, 30047, 30059,
+ 30071, 30089, 30091, 30097, 30103, 30109, 30113, 30119, 30133, 30137,
+ 30139, 30161, 30169, 30181, 30187, 30197, 30203, 30211, 30223, 30241,
+ 30253, 30259, 30269, 30271, 30293, 30307, 30313, 30319, 30323, 30341,
+ 30347, 30367, 30389, 30391, 30403, 30427, 30431, 30449, 30467, 30469,
+ 30491, 30493, 30497, 30509, 30517, 30529, 30539, 30553, 30557, 30559,
+ 30577, 30593, 30631, 30637, 30643, 30649, 30661, 30671, 30677, 30689,
+ 30697, 30703, 30707, 30713, 30727, 30757, 30763, 30773, 30781, 30803,
+ 30809, 30817, 30829, 30839, 30841, 30851, 30853, 30859, 30869, 30871,
+ 30881, 30893, 30911, 30931, 30937, 30941, 30949, 30971, 30977, 30983,
+ 31013, 31019, 31033, 31039, 31051, 31063, 31069, 31079, 31081, 31091,
+ 31121, 31123, 31139, 31147, 31151, 31153, 31159, 31177, 31181, 31183,
+ 31189, 31193, 31219, 31223, 31231, 31237, 31247, 31249, 31253, 31259,
+ 31267, 31271, 31277, 31307, 31319, 31321, 31327, 31333, 31337, 31357,
+ 31379, 31387, 31391, 31393, 31397, 31469, 31477, 31481, 31489, 31511,
+ 31513, 31517, 31531, 31541, 31543, 31547, 31567, 31573, 31583, 31601,
+ 31607, 31627, 31643, 31649, 31657, 31663, 31667, 31687, 31699, 31721,
+ 31723, 31727, 31729, 31741, 31751, 31769, 31771, 31793, 31799, 31817,
+ 31847, 31849, 31859, 31873, 31883, 31891, 31907, 31957, 31963, 31973,
+ 31981, 31991, 32003, 32009, 32027, 32029, 32051, 32057, 32059, 32063,
+ 32069, 32077, 32083, 32089, 32099, 32117, 32119, 32141, 32143, 32159,
+ 32173, 32183, 32189, 32191, 32203, 32213, 32233, 32237, 32251, 32257,
+ 32261, 32297, 32299, 32303, 32309, 32321, 32323, 32327, 32341, 32353,
+ 32359, 32363, 32369, 32371, 32377, 32381, 32401, 32411, 32413, 32423,
+ 32429, 32441, 32443, 32467, 32479, 32491, 32497, 32503, 32507, 32531,
+ 32533, 32537, 32561, 32563, 32569, 32573, 32579, 32587, 32603, 32609,
+ 32611, 32621, 32633, 32647, 32653, 32687, 32693, 32707, 32713, 32717,
+ 32719, 32749, 32771, 32779, 32783, 32789, 32797, 32801, 32803, 32831,
+ 32833, 32839, 32843, 32869, 32887, 32909, 32911, 32917, 32933, 32939,
+ 32941, 32957, 32969, 32971, 32983, 32987, 32993, 32999, 33013, 33023,
+ 33029, 33037, 33049, 33053, 33071, 33073, 33083, 33091, 33107, 33113,
+ 33119, 33149, 33151, 33161, 33179, 33181, 33191, 33199, 33203, 33211,
+ 33223, 33247, 33287, 33289, 33301, 33311, 33317, 33329, 33331, 33343,
+ 33347, 33349, 33353, 33359, 33377, 33391, 33403, 33409, 33413, 33427,
+ 33457, 33461, 33469, 33479, 33487, 33493, 33503, 33521, 33529, 33533,
+ 33547, 33563, 33569, 33577, 33581, 33587, 33589, 33599, 33601, 33613,
+ 33617, 33619, 33623, 33629, 33637, 33641, 33647, 33679, 33703, 33713,
+ 33721, 33739, 33749, 33751, 33757, 33767, 33769, 33773, 33791, 33797,
+ 33809, 33811, 33827, 33829, 33851, 33857, 33863, 33871, 33889, 33893,
+ 33911, 33923, 33931, 33937, 33941, 33961, 33967, 33997, 34019, 34031,
+ 34033, 34039, 34057, 34061, 34123, 34127, 34129, 34141, 34147, 34157,
+ 34159, 34171, 34183, 34211, 34213, 34217, 34231, 34253, 34259, 34261,
+ 34267, 34273, 34283, 34297, 34301, 34303, 34313, 34319, 34327, 34337,
+ 34351, 34361, 34367, 34369, 34381, 34403, 34421, 34429, 34439, 34457,
+ 34469, 34471, 34483, 34487, 34499, 34501, 34511, 34513, 34519, 34537,
+ 34543, 34549, 34583, 34589, 34591, 34603, 34607, 34613, 34631, 34649,
+ 34651, 34667, 34673, 34679, 34687, 34693, 34703, 34721, 34729, 34739,
+ 34747, 34757, 34759, 34763, 34781, 34807, 34819, 34841, 34843, 34847,
+ 34849, 34871, 34877, 34883, 34897, 34913, 34919, 34939, 34949, 34961,
+ 34963, 34981, 35023, 35027, 35051, 35053, 35059, 35069, 35081, 35083,
+ 35089, 35099, 35107, 35111, 35117, 35129, 35141, 35149, 35153, 35159,
+ 35171, 35201, 35221, 35227, 35251, 35257, 35267, 35279, 35281, 35291,
+ 35311, 35317, 35323, 35327, 35339, 35353, 35363, 35381, 35393, 35401,
+ 35407, 35419, 35423, 35437, 35447, 35449, 35461, 35491, 35507, 35509,
+ 35521, 35527, 35531, 35533, 35537, 35543, 35569, 35573, 35591, 35593,
+ 35597, 35603, 35617, 35671, 35677, 35729, 35731, 35747, 35753, 35759,
+ 35771, 35797, 35801, 35803, 35809, 35831, 35837, 35839, 35851, 35863,
+ 35869, 35879, 35897, 35899, 35911, 35923, 35933, 35951, 35963, 35969,
+ 35977, 35983, 35993, 35999, 36007, 36011, 36013, 36017, 36037, 36061,
+ 36067, 36073, 36083, 36097, 36107, 36109, 36131, 36137, 36151, 36161,
+ 36187, 36191, 36209, 36217, 36229, 36241, 36251, 36263, 36269, 36277,
+ 36293, 36299, 36307, 36313, 36319, 36341, 36343, 36353, 36373, 36383,
+ 36389, 36433, 36451, 36457, 36467, 36469, 36473, 36479, 36493, 36497,
+ 36523, 36527, 36529, 36541, 36551, 36559, 36563, 36571, 36583, 36587,
+ 36599, 36607, 36629, 36637, 36643, 36653, 36671, 36677, 36683, 36691,
+ 36697, 36709, 36713, 36721, 36739, 36749, 36761, 36767, 36779, 36781,
+ 36787, 36791, 36793, 36809, 36821, 36833, 36847, 36857, 36871, 36877,
+ 36887, 36899, 36901, 36913, 36919, 36923, 36929, 36931, 36943, 36947,
+ 36973, 36979, 36997, 37003, 37013, 37019, 37021, 37039, 37049, 37057,
+ 37061, 37087, 37097, 37117, 37123, 37139, 37159, 37171, 37181, 37189,
+ 37199, 37201, 37217, 37223, 37243, 37253, 37273, 37277, 37307, 37309,
+ 37313, 37321, 37337, 37339, 37357, 37361, 37363, 37369, 37379, 37397,
+ 37409, 37423, 37441, 37447, 37463, 37483, 37489, 37493, 37501, 37507,
+ 37511, 37517, 37529, 37537, 37547, 37549, 37561, 37567, 37571, 37573,
+ 37579, 37589, 37591, 37607, 37619, 37633, 37643, 37649, 37657, 37663,
+ 37691, 37693, 37699, 37717, 37747, 37781, 37783, 37799, 37811, 37813,
+ 37831, 37847, 37853, 37861, 37871, 37879, 37889, 37897, 37907, 37951,
+ 37957, 37963, 37967, 37987, 37991, 37993, 37997, 38011, 38039, 38047,
+ 38053, 38069, 38083, 38113, 38119, 38149, 38153, 38167, 38177, 38183,
+ 38189, 38197, 38201, 38219, 38231, 38237, 38239, 38261, 38273, 38281,
+ 38287, 38299, 38303, 38317, 38321, 38327, 38329, 38333, 38351, 38371,
+ 38377, 38393, 38431, 38447, 38449, 38453, 38459, 38461, 38501, 38543,
+ 38557, 38561, 38567, 38569, 38593, 38603, 38609, 38611, 38629, 38639,
+ 38651, 38653, 38669, 38671, 38677, 38693, 38699, 38707, 38711, 38713,
+ 38723, 38729, 38737, 38747, 38749, 38767, 38783, 38791, 38803, 38821,
+ 38833, 38839, 38851, 38861, 38867, 38873, 38891, 38903, 38917, 38921,
+ 38923, 38933, 38953, 38959, 38971, 38977, 38993, 39019, 39023, 39041,
+ 39043, 39047, 39079, 39089, 39097, 39103, 39107, 39113, 39119, 39133,
+ 39139, 39157, 39161, 39163, 39181, 39191, 39199, 39209, 39217, 39227,
+ 39229, 39233, 39239, 39241, 39251, 39293, 39301, 39313, 39317, 39323,
+ 39341, 39343, 39359, 39367, 39371, 39373, 39383, 39397, 39409, 39419,
+ 39439, 39443, 39451, 39461, 39499, 39503, 39509, 39511, 39521, 39541,
+ 39551, 39563, 39569, 39581, 39607, 39619, 39623, 39631, 39659, 39667,
+ 39671, 39679, 39703, 39709, 39719, 39727, 39733, 39749, 39761, 39769,
+ 39779, 39791, 39799, 39821, 39827, 39829, 39839, 39841, 39847, 39857,
+ 39863, 39869, 39877, 39883, 39887, 39901, 39929, 39937, 39953, 39971,
+ 39979, 39983, 39989, 40009, 40013, 40031, 40037, 40039, 40063, 40087,
+ 40093, 40099, 40111, 40123, 40127, 40129, 40151, 40153, 40163, 40169,
+ 40177, 40189, 40193, 40213, 40231, 40237, 40241, 40253, 40277, 40283,
+ 40289, 40343, 40351, 40357, 40361, 40387, 40423, 40427, 40429, 40433,
+ 40459, 40471, 40483, 40487, 40493, 40499, 40507, 40519, 40529, 40531,
+ 40543, 40559, 40577, 40583, 40591, 40597, 40609, 40627, 40637, 40639,
+ 40693, 40697, 40699, 40709, 40739, 40751, 40759, 40763, 40771, 40787,
+ 40801, 40813, 40819, 40823, 40829, 40841, 40847, 40849, 40853, 40867,
+ 40879, 40883, 40897, 40903, 40927, 40933, 40939, 40949, 40961, 40973,
+ 40993, 41011, 41017, 41023, 41039, 41047, 41051, 41057, 41077, 41081,
+ 41113, 41117, 41131, 41141, 41143, 41149, 41161, 41177, 41179, 41183,
+ 41189, 41201, 41203, 41213, 41221, 41227, 41231, 41233, 41243, 41257,
+ 41263, 41269, 41281, 41299, 41333, 41341, 41351, 41357, 41381, 41387,
+ 41389, 41399, 41411, 41413, 41443, 41453, 41467, 41479, 41491, 41507,
+ 41513, 41519, 41521, 41539, 41543, 41549, 41579, 41593, 41597, 41603,
+ 41609, 41611, 41617, 41621, 41627, 41641, 41647, 41651, 41659, 41669,
+ 41681, 41687, 41719, 41729, 41737, 41759, 41761, 41771, 41777, 41801,
+ 41809, 41813, 41843, 41849, 41851, 41863, 41879, 41887, 41893, 41897,
+ 41903, 41911, 41927, 41941, 41947, 41953, 41957, 41959, 41969, 41981,
+ 41983, 41999, 42013, 42017, 42019, 42023, 42043, 42061, 42071, 42073,
+ 42083, 42089, 42101, 42131, 42139, 42157, 42169, 42179, 42181, 42187,
+ 42193, 42197, 42209, 42221, 42223, 42227, 42239, 42257, 42281, 42283,
+ 42293, 42299, 42307, 42323, 42331, 42337, 42349, 42359, 42373, 42379,
+ 42391, 42397, 42403, 42407, 42409, 42433, 42437, 42443, 42451, 42457,
+ 42461, 42463, 42467, 42473, 42487, 42491, 42499, 42509, 42533, 42557,
+ 42569, 42571, 42577, 42589, 42611, 42641, 42643, 42649, 42667, 42677,
+ 42683, 42689, 42697, 42701, 42703, 42709, 42719, 42727, 42737, 42743,
+ 42751, 42767, 42773, 42787, 42793, 42797, 42821, 42829, 42839, 42841,
+ 42853, 42859, 42863, 42899, 42901, 42923, 42929, 42937, 42943, 42953,
+ 42961, 42967, 42979, 42989, 43003, 43013, 43019, 43037, 43049, 43051,
+ 43063, 43067, 43093, 43103, 43117, 43133, 43151, 43159, 43177, 43189,
+ 43201, 43207, 43223, 43237, 43261, 43271, 43283, 43291, 43313, 43319,
+ 43321, 43331, 43391, 43397, 43399, 43403, 43411, 43427, 43441, 43451,
+ 43457, 43481, 43487, 43499, 43517, 43541, 43543, 43573, 43577, 43579,
+ 43591, 43597, 43607, 43609, 43613, 43627, 43633, 43649, 43651, 43661,
+ 43669, 43691, 43711, 43717, 43721, 43753, 43759, 43777, 43781, 43783,
+ 43787, 43789, 43793, 43801, 43853, 43867, 43889, 43891, 43913, 43933,
+ 43943, 43951, 43961, 43963, 43969, 43973, 43987, 43991, 43997, 44017,
+ 44021, 44027, 44029, 44041, 44053, 44059, 44071, 44087, 44089, 44101,
+ 44111, 44119, 44123, 44129, 44131, 44159, 44171, 44179, 44189, 44201,
+ 44203, 44207, 44221, 44249, 44257, 44263, 44267, 44269, 44273, 44279,
+ 44281, 44293, 44351, 44357, 44371, 44381, 44383, 44389, 44417, 44449,
+ 44453, 44483, 44491, 44497, 44501, 44507, 44519, 44531, 44533, 44537,
+ 44543, 44549, 44563, 44579, 44587, 44617, 44621, 44623, 44633, 44641,
+ 44647, 44651, 44657, 44683, 44687, 44699, 44701, 44711, 44729, 44741,
+ 44753, 44771, 44773, 44777, 44789, 44797, 44809, 44819, 44839, 44843,
+ 44851, 44867, 44879, 44887, 44893, 44909, 44917, 44927, 44939, 44953,
+ 44959, 44963, 44971, 44983, 44987, 45007, 45013, 45053, 45061, 45077,
+ 45083, 45119, 45121, 45127, 45131, 45137, 45139, 45161, 45179, 45181,
+ 45191, 45197, 45233, 45247, 45259, 45263, 45281, 45289, 45293, 45307,
+ 45317, 45319, 45329, 45337, 45341, 45343, 45361, 45377, 45389, 45403,
+ 45413, 45427, 45433, 45439, 45481, 45491, 45497, 45503, 45523, 45533,
+ 45541, 45553, 45557, 45569, 45587, 45589, 45599, 45613, 45631, 45641,
+ 45659, 45667, 45673, 45677, 45691, 45697, 45707, 45737, 45751, 45757,
+ 45763, 45767, 45779, 45817, 45821, 45823, 45827, 45833, 45841, 45853,
+ 45863, 45869, 45887, 45893, 45943, 45949, 45953, 45959, 45971, 45979,
+ 45989, 46021, 46027, 46049, 46051, 46061, 46073, 46091, 46093, 46099,
+ 46103, 46133, 46141, 46147, 46153, 46171, 46181, 46183, 46187, 46199,
+ 46219, 46229, 46237, 46261, 46271, 46273, 46279, 46301, 46307, 46309,
+ 46327, 46337, 46349, 46351, 46381, 46399, 46411, 46439, 46441, 46447,
+ 46451, 46457, 46471, 46477, 46489, 46499, 46507, 46511, 46523, 46549,
+ 46559, 46567, 46573, 46589, 46591, 46601, 46619, 46633, 46639, 46643,
+ 46649, 46663, 46679, 46681, 46687, 46691, 46703, 46723, 46727, 46747,
+ 46751, 46757, 46769, 46771, 46807, 46811, 46817, 46819, 46829, 46831,
+ 46853, 46861, 46867, 46877, 46889, 46901, 46919, 46933, 46957, 46993,
+ 46997, 47017, 47041, 47051, 47057, 47059, 47087, 47093, 47111, 47119,
+ 47123, 47129, 47137, 47143, 47147, 47149, 47161, 47189, 47207, 47221,
+ 47237, 47251, 47269, 47279, 47287, 47293, 47297, 47303, 47309, 47317,
+ 47339, 47351, 47353, 47363, 47381, 47387, 47389, 47407, 47417, 47419,
+ 47431, 47441, 47459, 47491, 47497, 47501, 47507, 47513, 47521, 47527,
+ 47533, 47543, 47563, 47569, 47581, 47591, 47599, 47609, 47623, 47629,
+ 47639, 47653, 47657, 47659, 47681, 47699, 47701, 47711, 47713, 47717,
+ 47737, 47741, 47743, 47777, 47779, 47791, 47797, 47807, 47809, 47819,
+ 47837, 47843, 47857, 47869, 47881, 47903, 47911, 47917, 47933, 47939,
+ 47947, 47951, 47963, 47969, 47977, 47981, 48017, 48023, 48029, 48049,
+ 48073, 48079, 48091, 48109, 48119, 48121, 48131, 48157, 48163, 48179,
+ 48187, 48193, 48197, 48221, 48239, 48247, 48259, 48271, 48281, 48299,
+ 48311, 48313, 48337, 48341, 48353, 48371, 48383, 48397, 48407, 48409,
+ 48413, 48437, 48449, 48463, 48473, 48479, 48481, 48487, 48491, 48497,
+ 48523, 48527, 48533, 48539, 48541, 48563, 48571, 48589, 48593, 48611,
+ 48619, 48623, 48647, 48649, 48661, 48673, 48677, 48679, 48731, 48733,
+ 48751, 48757, 48761, 48767, 48779, 48781, 48787, 48799, 48809, 48817,
+ 48821, 48823, 48847, 48857, 48859, 48869, 48871, 48883, 48889, 48907,
+ 48947, 48953, 48973, 48989, 48991, 49003, 49009, 49019, 49031, 49033,
+ 49037, 49043, 49057, 49069, 49081, 49103, 49109, 49117, 49121, 49123,
+ 49139, 49157, 49169, 49171, 49177, 49193, 49199, 49201, 49207, 49211,
+ 49223, 49253, 49261, 49277, 49279, 49297, 49307, 49331, 49333, 49339,
+ 49363, 49367, 49369, 49391, 49393, 49409, 49411, 49417, 49429, 49433,
+ 49451, 49459, 49463, 49477, 49481, 49499, 49523, 49529, 49531, 49537,
+ 49547, 49549, 49559, 49597, 49603, 49613, 49627, 49633, 49639, 49663,
+ 49667, 49669, 49681, 49697, 49711, 49727, 49739, 49741, 49747, 49757,
+ 49783, 49787, 49789, 49801, 49807, 49811, 49823, 49831, 49843, 49853,
+ 49871, 49877, 49891, 49919, 49921, 49927, 49937, 49939, 49943, 49957,
+ 49991, 49993, 49999, 50021, 50023, 50033, 50047, 50051, 50053, 50069,
+ 50077, 50087, 50093, 50101, 50111, 50119, 50123, 50129, 50131, 50147,
+ 50153, 50159, 50177, 50207, 50221, 50227, 50231, 50261, 50263, 50273,
+ 50287, 50291, 50311, 50321, 50329, 50333, 50341, 50359, 50363, 50377,
+ 50383, 50387, 50411, 50417, 50423, 50441, 50459, 50461, 50497, 50503,
+ 50513, 50527, 50539, 50543, 50549, 50551, 50581, 50587, 50591, 50593,
+ 50599, 50627, 50647, 50651, 50671, 50683, 50707, 50723, 50741, 50753,
+ 50767, 50773, 50777, 50789, 50821, 50833, 50839, 50849, 50857, 50867,
+ 50873, 50891, 50893, 50909, 50923, 50929, 50951, 50957, 50969, 50971,
+ 50989, 50993, 51001, 51031, 51043, 51047, 51059, 51061, 51071, 51109,
+ 51131, 51133, 51137, 51151, 51157, 51169, 51193, 51197, 51199, 51203,
+ 51217, 51229, 51239, 51241, 51257, 51263, 51283, 51287, 51307, 51329,
+ 51341, 51343, 51347, 51349, 51361, 51383, 51407, 51413, 51419, 51421,
+ 51427, 51431, 51437, 51439, 51449, 51461, 51473, 51479, 51481, 51487,
+ 51503, 51511, 51517, 51521, 51539, 51551, 51563, 51577, 51581, 51593,
+ 51599, 51607, 51613, 51631, 51637, 51647, 51659, 51673, 51679, 51683,
+ 51691, 51713, 51719, 51721, 51749, 51767, 51769, 51787, 51797, 51803,
+ 51817, 51827, 51829, 51839, 51853, 51859, 51869, 51871, 51893, 51899,
+ 51907, 51913, 51929, 51941, 51949, 51971, 51973, 51977, 51991, 52009,
+ 52021, 52027, 52051, 52057, 52067, 52069, 52081, 52103, 52121, 52127,
+ 52147, 52153, 52163, 52177, 52181, 52183, 52189, 52201, 52223, 52237,
+ 52249, 52253, 52259, 52267, 52289, 52291, 52301, 52313, 52321, 52361,
+ 52363, 52369, 52379, 52387, 52391, 52433, 52453, 52457, 52489, 52501,
+ 52511, 52517, 52529, 52541, 52543, 52553, 52561, 52567, 52571, 52579,
+ 52583, 52609, 52627, 52631, 52639, 52667, 52673, 52691, 52697, 52709,
+ 52711, 52721, 52727, 52733, 52747, 52757, 52769, 52783, 52807, 52813,
+ 52817, 52837, 52859, 52861, 52879, 52883, 52889, 52901, 52903, 52919,
+ 52937, 52951, 52957, 52963, 52967, 52973, 52981, 52999, 53003, 53017,
+ 53047, 53051, 53069, 53077, 53087, 53089, 53093, 53101, 53113, 53117,
+ 53129, 53147, 53149, 53161, 53171, 53173, 53189, 53197, 53201, 53231,
+ 53233, 53239, 53267, 53269, 53279, 53281, 53299, 53309, 53323, 53327,
+ 53353, 53359, 53377, 53381, 53401, 53407, 53411, 53419, 53437, 53441,
+ 53453, 53479, 53503, 53507, 53527, 53549, 53551, 53569, 53591, 53593,
+ 53597, 53609, 53611, 53617, 53623, 53629, 53633, 53639, 53653, 53657,
+ 53681, 53693, 53699, 53717, 53719, 53731, 53759, 53773, 53777, 53783,
+ 53791, 53813, 53819, 53831, 53849, 53857, 53861, 53881, 53887, 53891,
+ 53897, 53899, 53917, 53923, 53927, 53939, 53951, 53959, 53987, 53993,
+ 54001, 54011, 54013, 54037, 54049, 54059, 54083, 54091, 54101, 54121,
+ 54133, 54139, 54151, 54163, 54167, 54181, 54193, 54217, 54251, 54269,
+ 54277, 54287, 54293, 54311, 54319, 54323, 54331, 54347, 54361, 54367,
+ 54371, 54377, 54401, 54403, 54409, 54413, 54419, 54421, 54437, 54443,
+ 54449, 54469, 54493, 54497, 54499, 54503, 54517, 54521, 54539, 54541,
+ 54547, 54559, 54563, 54577, 54581, 54583, 54601, 54617, 54623, 54629,
+ 54631, 54647, 54667, 54673, 54679, 54709, 54713, 54721, 54727, 54751,
+ 54767, 54773, 54779, 54787, 54799, 54829, 54833, 54851, 54869, 54877,
+ 54881, 54907, 54917, 54919, 54941, 54949, 54959, 54973, 54979, 54983,
+ 55001, 55009, 55021, 55049, 55051, 55057, 55061, 55073, 55079, 55103,
+ 55109, 55117, 55127, 55147, 55163, 55171, 55201, 55207, 55213, 55217,
+ 55219, 55229, 55243, 55249, 55259, 55291, 55313, 55331, 55333, 55337,
+ 55339, 55343, 55351, 55373, 55381, 55399, 55411, 55439, 55441, 55457,
+ 55469, 55487, 55501, 55511, 55529, 55541, 55547, 55579, 55589, 55603,
+ 55609, 55619, 55621, 55631, 55633, 55639, 55661, 55663, 55667, 55673,
+ 55681, 55691, 55697, 55711, 55717, 55721, 55733, 55763, 55787, 55793,
+ 55799, 55807, 55813, 55817, 55819, 55823, 55829, 55837, 55843, 55849,
+ 55871, 55889, 55897, 55901, 55903, 55921, 55927, 55931, 55933, 55949,
+ 55967, 55987, 55997, 56003, 56009, 56039, 56041, 56053, 56081, 56087,
+ 56093, 56099, 56101, 56113, 56123, 56131, 56149, 56167, 56171, 56179,
+ 56197, 56207, 56209, 56237, 56239, 56249, 56263, 56267, 56269, 56299,
+ 56311, 56333, 56359, 56369, 56377, 56383, 56393, 56401, 56417, 56431,
+ 56437, 56443, 56453, 56467, 56473, 56477, 56479, 56489, 56501, 56503,
+ 56509, 56519, 56527, 56531, 56533, 56543, 56569, 56591, 56597, 56599,
+ 56611, 56629, 56633, 56659, 56663, 56671, 56681, 56687, 56701, 56711,
+ 56713, 56731, 56737, 56747, 56767, 56773, 56779, 56783, 56807, 56809,
+ 56813, 56821, 56827, 56843, 56857, 56873, 56891, 56893, 56897, 56909,
+ 56911, 56921, 56923, 56929, 56941, 56951, 56957, 56963, 56983, 56989,
+ 56993, 56999, 57037, 57041, 57047, 57059, 57073, 57077, 57089, 57097,
+ 57107, 57119, 57131, 57139, 57143, 57149, 57163, 57173, 57179, 57191,
+ 57193, 57203, 57221, 57223, 57241, 57251, 57259, 57269, 57271, 57283,
+ 57287, 57301, 57329, 57331, 57347, 57349, 57367, 57373, 57383, 57389,
+ 57397, 57413, 57427, 57457, 57467, 57487, 57493, 57503, 57527, 57529,
+ 57557, 57559, 57571, 57587, 57593, 57601, 57637, 57641, 57649, 57653,
+ 57667, 57679, 57689, 57697, 57709, 57713, 57719, 57727, 57731, 57737,
+ 57751, 57773, 57781, 57787, 57791, 57793, 57803, 57809, 57829, 57839,
+ 57847, 57853, 57859, 57881, 57899, 57901, 57917, 57923, 57943, 57947,
+ 57973, 57977, 57991, 58013, 58027, 58031, 58043, 58049, 58057, 58061,
+ 58067, 58073, 58099, 58109, 58111, 58129, 58147, 58151, 58153, 58169,
+ 58171, 58189, 58193, 58199, 58207, 58211, 58217, 58229, 58231, 58237,
+ 58243, 58271, 58309, 58313, 58321, 58337, 58363, 58367, 58369, 58379,
+ 58391, 58393, 58403, 58411, 58417, 58427, 58439, 58441, 58451, 58453,
+ 58477, 58481, 58511, 58537, 58543, 58549, 58567, 58573, 58579, 58601,
+ 58603, 58613, 58631, 58657, 58661, 58679, 58687, 58693, 58699, 58711,
+ 58727, 58733, 58741, 58757, 58763, 58771, 58787, 58789, 58831, 58889,
+ 58897, 58901, 58907, 58909, 58913, 58921, 58937, 58943, 58963, 58967,
+ 58979, 58991, 58997, 59009, 59011, 59021, 59023, 59029, 59051, 59053,
+ 59063, 59069, 59077, 59083, 59093, 59107, 59113, 59119, 59123, 59141,
+ 59149, 59159, 59167, 59183, 59197, 59207, 59209, 59219, 59221, 59233,
+ 59239, 59243, 59263, 59273, 59281, 59333, 59341, 59351, 59357, 59359,
+ 59369, 59377, 59387, 59393, 59399, 59407, 59417, 59419, 59441, 59443,
+ 59447, 59453, 59467, 59471, 59473, 59497, 59509, 59513, 59539, 59557,
+ 59561, 59567, 59581, 59611, 59617, 59621, 59627, 59629, 59651, 59659,
+ 59663, 59669, 59671, 59693, 59699, 59707, 59723, 59729, 59743, 59747,
+ 59753, 59771, 59779, 59791, 59797, 59809, 59833, 59863, 59879, 59887,
+ 59921, 59929, 59951, 59957, 59971, 59981, 59999, 60013, 60017, 60029,
+ 60037, 60041, 60077, 60083, 60089, 60091, 60101, 60103, 60107, 60127,
+ 60133, 60139, 60149, 60161, 60167, 60169, 60209, 60217, 60223, 60251,
+ 60257, 60259, 60271, 60289, 60293, 60317, 60331, 60337, 60343, 60353,
+ 60373, 60383, 60397, 60413, 60427, 60443, 60449, 60457, 60493, 60497,
+ 60509, 60521, 60527, 60539, 60589, 60601, 60607, 60611, 60617, 60623,
+ 60631, 60637, 60647, 60649, 60659, 60661, 60679, 60689, 60703, 60719,
+ 60727, 60733, 60737, 60757, 60761, 60763, 60773, 60779, 60793, 60811,
+ 60821, 60859, 60869, 60887, 60889, 60899, 60901, 60913, 60917, 60919,
+ 60923, 60937, 60943, 60953, 60961, 61001, 61007, 61027, 61031, 61043,
+ 61051, 61057, 61091, 61099, 61121, 61129, 61141, 61151, 61153, 61169,
+ 61211, 61223, 61231, 61253, 61261, 61283, 61291, 61297, 61331, 61333,
+ 61339, 61343, 61357, 61363, 61379, 61381, 61403, 61409, 61417, 61441,
+ 61463, 61469, 61471, 61483, 61487, 61493, 61507, 61511, 61519, 61543,
+ 61547, 61553, 61559, 61561, 61583, 61603, 61609, 61613, 61627, 61631,
+ 61637, 61643, 61651, 61657, 61667, 61673, 61681, 61687, 61703, 61717,
+ 61723, 61729, 61751, 61757, 61781, 61813, 61819, 61837, 61843, 61861,
+ 61871, 61879, 61909, 61927, 61933, 61949, 61961, 61967, 61979, 61981,
+ 61987, 61991, 62003, 62011, 62017, 62039, 62047, 62053, 62057, 62071,
+ 62081, 62099, 62119, 62129, 62131, 62137, 62141, 62143, 62171, 62189,
+ 62191, 62201, 62207, 62213, 62219, 62233, 62273, 62297, 62299, 62303,
+ 62311, 62323, 62327, 62347, 62351, 62383, 62401, 62417, 62423, 62459,
+ 62467, 62473, 62477, 62483, 62497, 62501, 62507, 62533, 62539, 62549,
+ 62563, 62581, 62591, 62597, 62603, 62617, 62627, 62633, 62639, 62653,
+ 62659, 62683, 62687, 62701, 62723, 62731, 62743, 62753, 62761, 62773,
+ 62791, 62801, 62819, 62827, 62851, 62861, 62869, 62873, 62897, 62903,
+ 62921, 62927, 62929, 62939, 62969, 62971, 62981, 62983, 62987, 62989,
+ 63029, 63031, 63059, 63067, 63073, 63079, 63097, 63103, 63113, 63127,
+ 63131, 63149, 63179, 63197, 63199, 63211, 63241, 63247, 63277, 63281,
+ 63299, 63311, 63313, 63317, 63331, 63337, 63347, 63353, 63361, 63367,
+ 63377, 63389, 63391, 63397, 63409, 63419, 63421, 63439, 63443, 63463,
+ 63467, 63473, 63487, 63493, 63499, 63521, 63527, 63533, 63541, 63559,
+ 63577, 63587, 63589, 63599, 63601, 63607, 63611, 63617, 63629, 63647,
+ 63649, 63659, 63667, 63671, 63689, 63691, 63697, 63703, 63709, 63719,
+ 63727, 63737, 63743, 63761, 63773, 63781, 63793, 63799, 63803, 63809,
+ 63823, 63839, 63841, 63853, 63857, 63863, 63901, 63907, 63913, 63929,
+ 63949, 63977, 63997, 64007, 64013, 64019, 64033, 64037, 64063, 64067,
+ 64081, 64091, 64109, 64123, 64151, 64153, 64157, 64171, 64187, 64189,
+ 64217, 64223, 64231, 64237, 64271, 64279, 64283, 64301, 64303, 64319,
+ 64327, 64333, 64373, 64381, 64399, 64403, 64433, 64439, 64451, 64453,
+ 64483, 64489, 64499, 64513, 64553, 64567, 64577, 64579, 64591, 64601,
+ 64609, 64613, 64621, 64627, 64633, 64661, 64663, 64667, 64679, 64693,
+ 64709, 64717, 64747, 64763, 64781, 64783, 64793, 64811, 64817, 64849,
+ 64853, 64871, 64877, 64879, 64891, 64901, 64919, 64921, 64927, 64937,
+ 64951, 64969, 64997, 65003, 65011, 65027, 65029, 65033, 65053, 65063,
+ 65071, 65089, 65099, 65101, 65111, 65119, 65123, 65129, 65141, 65147,
+ 65167, 65171, 65173, 65179, 65183, 65203, 65213, 65239, 65257, 65267,
+ 65269, 65287, 65293, 65309, 65323, 65327, 65353, 65357, 65371, 65381,
+ 65393, 65407, 65413, 65419, 65423, 65437, 65447, 65449, 65479, 65497,
+ 65519, 65521, 65537, 65539, 65543, 65551, 65557, 65563, 65579, 65581,
+ 65587, 65599, 65609, 65617, 65629, 65633, 65647, 65651, 65657, 65677,
+ 65687, 65699, 65701, 65707, 65713, 65717, 65719, 65729, 65731, 65761,
+ 65777, 65789, 65809, 65827, 65831, 65837, 65839, 65843, 65851, 65867,
+ 65881, 65899, 65921, 65927, 65929, 65951, 65957, 65963, 65981, 65983,
+ 65993, 66029, 66037, 66041, 66047, 66067, 66071, 66083, 66089, 66103,
+ 66107, 66109, 66137, 66161, 66169, 66173, 66179, 66191, 66221, 66239,
+ 66271, 66293, 66301, 66337, 66343, 66347, 66359, 66361, 66373, 66377,
+ 66383, 66403, 66413, 66431, 66449, 66457, 66463, 66467, 66491, 66499,
+ 66509, 66523, 66529, 66533, 66541, 66553, 66569, 66571, 66587, 66593,
+ 66601, 66617, 66629, 66643, 66653, 66683, 66697, 66701, 66713, 66721,
+ 66733, 66739, 66749, 66751, 66763, 66791, 66797, 66809, 66821, 66841,
+ 66851, 66853, 66863, 66877, 66883, 66889, 66919, 66923, 66931, 66943,
+ 66947, 66949, 66959, 66973, 66977, 67003, 67021, 67033, 67043, 67049,
+ 67057, 67061, 67073, 67079, 67103, 67121, 67129, 67139, 67141, 67153,
+ 67157, 67169, 67181, 67187, 67189, 67211, 67213, 67217, 67219, 67231,
+ 67247, 67261, 67271, 67273, 67289, 67307, 67339, 67343, 67349, 67369,
+ 67391, 67399, 67409, 67411, 67421, 67427, 67429, 67433, 67447, 67453,
+ 67477, 67481, 67489, 67493, 67499, 67511, 67523, 67531, 67537, 67547,
+ 67559, 67567, 67577, 67579, 67589, 67601, 67607, 67619, 67631, 67651,
+ 67679, 67699, 67709, 67723, 67733, 67741, 67751, 67757, 67759, 67763,
+ 67777, 67783, 67789, 67801, 67807, 67819, 67829, 67843, 67853, 67867,
+ 67883, 67891, 67901, 67927, 67931, 67933, 67939, 67943, 67957, 67961,
+ 67967, 67979, 67987, 67993, 68023, 68041, 68053, 68059, 68071, 68087,
+ 68099, 68111, 68113, 68141, 68147, 68161, 68171, 68207, 68209, 68213,
+ 68219, 68227, 68239, 68261, 68279, 68281, 68311, 68329, 68351, 68371,
+ 68389, 68399, 68437, 68443, 68447, 68449, 68473, 68477, 68483, 68489,
+ 68491, 68501, 68507, 68521, 68531, 68539, 68543, 68567, 68581, 68597,
+ 68611, 68633, 68639, 68659, 68669, 68683, 68687, 68699, 68711, 68713,
+ 68729, 68737, 68743, 68749, 68767, 68771, 68777, 68791, 68813, 68819,
+ 68821, 68863, 68879, 68881, 68891, 68897, 68899, 68903, 68909, 68917,
+ 68927, 68947, 68963, 68993, 69001, 69011, 69019, 69029, 69031, 69061,
+ 69067, 69073, 69109, 69119, 69127, 69143, 69149, 69151, 69163, 69191,
+ 69193, 69197, 69203, 69221, 69233, 69239, 69247, 69257, 69259, 69263,
+ 69313, 69317, 69337, 69341, 69371, 69379, 69383, 69389, 69401, 69403,
+ 69427, 69431, 69439, 69457, 69463, 69467, 69473, 69481, 69491, 69493,
+ 69497, 69499, 69539, 69557, 69593, 69623, 69653, 69661, 69677, 69691,
+ 69697, 69709, 69737, 69739, 69761, 69763, 69767, 69779, 69809, 69821,
+ 69827, 69829, 69833, 69847, 69857, 69859, 69877, 69899, 69911, 69929,
+ 69931, 69941, 69959, 69991, 69997, 70001, 70003, 70009, 70019, 70039,
+ 70051, 70061, 70067, 70079, 70099, 70111, 70117, 70121, 70123, 70139,
+ 70141, 70157, 70163, 70177, 70181, 70183, 70199, 70201, 70207, 70223,
+ 70229, 70237, 70241, 70249, 70271, 70289, 70297, 70309, 70313, 70321,
+ 70327, 70351, 70373, 70379, 70381, 70393, 70423, 70429, 70439, 70451,
+ 70457, 70459, 70481, 70487, 70489, 70501, 70507, 70529, 70537, 70549,
+ 70571, 70573, 70583, 70589, 70607, 70619, 70621, 70627, 70639, 70657,
+ 70663, 70667, 70687, 70709, 70717, 70729, 70753, 70769, 70783, 70793,
+ 70823, 70841, 70843, 70849, 70853, 70867, 70877, 70879, 70891, 70901,
+ 70913, 70919, 70921, 70937, 70949, 70951, 70957, 70969, 70979, 70981,
+ 70991, 70997, 70999, 71011, 71023, 71039, 71059, 71069, 71081, 71089,
+ 71119, 71129, 71143, 71147, 71153, 71161, 71167, 71171, 71191, 71209,
+ 71233, 71237, 71249, 71257, 71261, 71263, 71287, 71293, 71317, 71327,
+ 71329, 71333, 71339, 71341, 71347, 71353, 71359, 71363, 71387, 71389,
+ 71399, 71411, 71413, 71419, 71429, 71437, 71443, 71453, 71471, 71473,
+ 71479, 71483, 71503, 71527, 71537, 71549, 71551, 71563, 71569, 71593,
+ 71597, 71633, 71647, 71663, 71671, 71693, 71699, 71707, 71711, 71713,
+ 71719, 71741, 71761, 71777, 71789, 71807, 71809, 71821, 71837, 71843,
+ 71849, 71861, 71867, 71879, 71881, 71887, 71899, 71909, 71917, 71933,
+ 71941, 71947, 71963, 71971, 71983, 71987, 71993, 71999, 72019, 72031,
+ 72043, 72047, 72053, 72073, 72077, 72089, 72091, 72101, 72103, 72109,
+ 72139, 72161, 72167, 72169, 72173, 72211, 72221, 72223, 72227, 72229,
+ 72251, 72253, 72269, 72271, 72277, 72287, 72307, 72313, 72337, 72341,
+ 72353, 72367, 72379, 72383, 72421, 72431, 72461, 72467, 72469, 72481,
+ 72493, 72497, 72503, 72533, 72547, 72551, 72559, 72577, 72613, 72617,
+ 72623, 72643, 72647, 72649, 72661, 72671, 72673, 72679, 72689, 72701,
+ 72707, 72719, 72727, 72733, 72739, 72763, 72767, 72797, 72817, 72823,
+ 72859, 72869, 72871, 72883, 72889, 72893, 72901, 72907, 72911, 72923,
+ 72931, 72937, 72949, 72953, 72959, 72973, 72977, 72997, 73009, 73013,
+ 73019, 73037, 73039, 73043, 73061, 73063, 73079, 73091, 73121, 73127,
+ 73133, 73141, 73181, 73189, 73237, 73243, 73259, 73277, 73291, 73303,
+ 73309, 73327, 73331, 73351, 73361, 73363, 73369, 73379, 73387, 73417,
+ 73421, 73433, 73453, 73459, 73471, 73477, 73483, 73517, 73523, 73529,
+ 73547, 73553, 73561, 73571, 73583, 73589, 73597, 73607, 73609, 73613,
+ 73637, 73643, 73651, 73673, 73679, 73681, 73693, 73699, 73709, 73721,
+ 73727, 73751, 73757, 73771, 73783, 73819, 73823, 73847, 73849, 73859,
+ 73867, 73877, 73883, 73897, 73907, 73939, 73943, 73951, 73961, 73973,
+ 73999, 74017, 74021, 74027, 74047, 74051, 74071, 74077, 74093, 74099,
+ 74101, 74131, 74143, 74149, 74159, 74161, 74167, 74177, 74189, 74197,
+ 74201, 74203, 74209, 74219, 74231, 74257, 74279, 74287, 74293, 74297,
+ 74311, 74317, 74323, 74353, 74357, 74363, 74377, 74381, 74383, 74411,
+ 74413, 74419, 74441, 74449, 74453, 74471, 74489, 74507, 74509, 74521,
+ 74527, 74531, 74551, 74561, 74567, 74573, 74587, 74597, 74609, 74611,
+ 74623, 74653, 74687, 74699, 74707, 74713, 74717, 74719, 74729, 74731,
+ 74747, 74759, 74761, 74771, 74779, 74797, 74821, 74827, 74831, 74843,
+ 74857, 74861, 74869, 74873, 74887, 74891, 74897, 74903, 74923, 74929,
+ 74933, 74941, 74959, 75011, 75013, 75017, 75029, 75037, 75041, 75079,
+ 75083, 75109, 75133, 75149, 75161, 75167, 75169, 75181, 75193, 75209,
+ 75211, 75217, 75223, 75227, 75239, 75253, 75269, 75277, 75289, 75307,
+ 75323, 75329, 75337, 75347, 75353, 75367, 75377, 75389, 75391, 75401,
+ 75403, 75407, 75431, 75437, 75479, 75503, 75511, 75521, 75527, 75533,
+ 75539, 75541, 75553, 75557, 75571, 75577, 75583, 75611, 75617, 75619,
+ 75629, 75641, 75653, 75659, 75679, 75683, 75689, 75703, 75707, 75709,
+ 75721, 75731, 75743, 75767, 75773, 75781, 75787, 75793, 75797, 75821,
+ 75833, 75853, 75869, 75883, 75913, 75931, 75937, 75941, 75967, 75979,
+ 75983, 75989, 75991, 75997, 76001, 76003, 76031, 76039, 76079, 76081,
+ 76091, 76099, 76103, 76123, 76129, 76147, 76157, 76159, 76163, 76207,
+ 76213, 76231, 76243, 76249, 76253, 76259, 76261, 76283, 76289, 76303,
+ 76333, 76343, 76367, 76369, 76379, 76387, 76403, 76421, 76423, 76441,
+ 76463, 76471, 76481, 76487, 76493, 76507, 76511, 76519, 76537, 76541,
+ 76543, 76561, 76579, 76597, 76603, 76607, 76631, 76649, 76651, 76667,
+ 76673, 76679, 76697, 76717, 76733, 76753, 76757, 76771, 76777, 76781,
+ 76801, 76819, 76829, 76831, 76837, 76847, 76871, 76873, 76883, 76907,
+ 76913, 76919, 76943, 76949, 76961, 76963, 76991, 77003, 77017, 77023,
+ 77029, 77041, 77047, 77069, 77081, 77093, 77101, 77137, 77141, 77153,
+ 77167, 77171, 77191, 77201, 77213, 77237, 77239, 77243, 77249, 77261,
+ 77263, 77267, 77269, 77279, 77291, 77317, 77323, 77339, 77347, 77351,
+ 77359, 77369, 77377, 77383, 77417, 77419, 77431, 77447, 77471, 77477,
+ 77479, 77489, 77491, 77509, 77513, 77521, 77527, 77543, 77549, 77551,
+ 77557, 77563, 77569, 77573, 77587, 77591, 77611, 77617, 77621, 77641,
+ 77647, 77659, 77681, 77687, 77689, 77699, 77711, 77713, 77719, 77723,
+ 77731, 77743, 77747, 77761, 77773, 77783, 77797, 77801, 77813, 77839,
+ 77849, 77863, 77867, 77893, 77899, 77929, 77933, 77951, 77969, 77977,
+ 77983, 77999, 78007, 78017, 78031, 78041, 78049, 78059, 78079, 78101,
+ 78121, 78137, 78139, 78157, 78163, 78167, 78173, 78179, 78191, 78193,
+ 78203, 78229, 78233, 78241, 78259, 78277, 78283, 78301, 78307, 78311,
+ 78317, 78341, 78347, 78367, 78401, 78427, 78437, 78439, 78467, 78479,
+ 78487, 78497, 78509, 78511, 78517, 78539, 78541, 78553, 78569, 78571,
+ 78577, 78583, 78593, 78607, 78623, 78643, 78649, 78653, 78691, 78697,
+ 78707, 78713, 78721, 78737, 78779, 78781, 78787, 78791, 78797, 78803,
+ 78809, 78823, 78839, 78853, 78857, 78877, 78887, 78889, 78893, 78901,
+ 78919, 78929, 78941, 78977, 78979, 78989, 79031, 79039, 79043, 79063,
+ 79087, 79103, 79111, 79133, 79139, 79147, 79151, 79153, 79159, 79181,
+ 79187, 79193, 79201, 79229, 79231, 79241, 79259, 79273, 79279, 79283,
+ 79301, 79309, 79319, 79333, 79337, 79349, 79357, 79367, 79379, 79393,
+ 79397, 79399, 79411, 79423, 79427, 79433, 79451, 79481, 79493, 79531,
+ 79537, 79549, 79559, 79561, 79579, 79589, 79601, 79609, 79613, 79621,
+ 79627, 79631, 79633, 79657, 79669, 79687, 79691, 79693, 79697, 79699,
+ 79757, 79769, 79777, 79801, 79811, 79813, 79817, 79823, 79829, 79841,
+ 79843, 79847, 79861, 79867, 79873, 79889, 79901, 79903, 79907, 79939,
+ 79943, 79967, 79973, 79979, 79987, 79997, 79999, 80021, 80039, 80051,
+ 80071, 80077, 80107, 80111, 80141, 80147, 80149, 80153, 80167, 80173,
+ 80177, 80191, 80207, 80209, 80221, 80231, 80233, 80239, 80251, 80263,
+ 80273, 80279, 80287, 80309, 80317, 80329, 80341, 80347, 80363, 80369,
+ 80387, 80407, 80429, 80447, 80449, 80471, 80473, 80489, 80491, 80513,
+ 80527, 80537, 80557, 80567, 80599, 80603, 80611, 80621, 80627, 80629,
+ 80651, 80657, 80669, 80671, 80677, 80681, 80683, 80687, 80701, 80713,
+ 80737, 80747, 80749, 80761, 80777, 80779, 80783, 80789, 80803, 80809,
+ 80819, 80831, 80833, 80849, 80863, 80897, 80909, 80911, 80917, 80923,
+ 80929, 80933, 80953, 80963, 80989, 81001, 81013, 81017, 81019, 81023,
+ 81031, 81041, 81043, 81047, 81049, 81071, 81077, 81083, 81097, 81101,
+ 81119, 81131, 81157, 81163, 81173, 81181, 81197, 81199, 81203, 81223,
+ 81233, 81239, 81281, 81283, 81293, 81299, 81307, 81331, 81343, 81349,
+ 81353, 81359, 81371, 81373, 81401, 81409, 81421, 81439, 81457, 81463,
+ 81509, 81517, 81527, 81533, 81547, 81551, 81553, 81559, 81563, 81569,
+ 81611, 81619, 81629, 81637, 81647, 81649, 81667, 81671, 81677, 81689,
+ 81701, 81703, 81707, 81727, 81737, 81749, 81761, 81769, 81773, 81799,
+ 81817, 81839, 81847, 81853, 81869, 81883, 81899, 81901, 81919, 81929,
+ 81931, 81937, 81943, 81953, 81967, 81971, 81973, 82003, 82007, 82009,
+ 82013, 82021, 82031, 82037, 82039, 82051, 82067, 82073, 82129, 82139,
+ 82141, 82153, 82163, 82171, 82183, 82189, 82193, 82207, 82217, 82219,
+ 82223, 82231, 82237, 82241, 82261, 82267, 82279, 82301, 82307, 82339,
+ 82349, 82351, 82361, 82373, 82387, 82393, 82421, 82457, 82463, 82469,
+ 82471, 82483, 82487, 82493, 82499, 82507, 82529, 82531, 82549, 82559,
+ 82561, 82567, 82571, 82591, 82601, 82609, 82613, 82619, 82633, 82651,
+ 82657, 82699, 82721, 82723, 82727, 82729, 82757, 82759, 82763, 82781,
+ 82787, 82793, 82799, 82811, 82813, 82837, 82847, 82883, 82889, 82891,
+ 82903, 82913, 82939, 82963, 82981, 82997, 83003, 83009, 83023, 83047,
+ 83059, 83063, 83071, 83077, 83089, 83093, 83101, 83117, 83137, 83177,
+ 83203, 83207, 83219, 83221, 83227, 83231, 83233, 83243, 83257, 83267,
+ 83269, 83273, 83299, 83311, 83339, 83341, 83357, 83383, 83389, 83399,
+ 83401, 83407, 83417, 83423, 83431, 83437, 83443, 83449, 83459, 83471,
+ 83477, 83497, 83537, 83557, 83561, 83563, 83579, 83591, 83597, 83609,
+ 83617, 83621, 83639, 83641, 83653, 83663, 83689, 83701, 83717, 83719,
+ 83737, 83761, 83773, 83777, 83791, 83813, 83833, 83843, 83857, 83869,
+ 83873, 83891, 83903, 83911, 83921, 83933, 83939, 83969, 83983, 83987,
+ 84011, 84017, 84047, 84053, 84059, 84061, 84067, 84089, 84121, 84127,
+ 84131, 84137, 84143, 84163, 84179, 84181, 84191, 84199, 84211, 84221,
+ 84223, 84229, 84239, 84247, 84263, 84299, 84307, 84313, 84317, 84319,
+ 84347, 84349, 84377, 84389, 84391, 84401, 84407, 84421, 84431, 84437,
+ 84443, 84449, 84457, 84463, 84467, 84481, 84499, 84503, 84509, 84521,
+ 84523, 84533, 84551, 84559, 84589, 84629, 84631, 84649, 84653, 84659,
+ 84673, 84691, 84697, 84701, 84713, 84719, 84731, 84737, 84751, 84761,
+ 84787, 84793, 84809, 84811, 84827, 84857, 84859, 84869, 84871, 84913,
+ 84919, 84947, 84961, 84967, 84977, 84979, 84991, 85009, 85021, 85027,
+ 85037, 85049, 85061, 85081, 85087, 85091, 85093, 85103, 85109, 85121,
+ 85133, 85147, 85159, 85193, 85199, 85201, 85213, 85223, 85229, 85237,
+ 85243, 85247, 85259, 85297, 85303, 85313, 85331, 85333, 85361, 85363,
+ 85369, 85381, 85411, 85427, 85429, 85439, 85447, 85451, 85453, 85469,
+ 85487, 85513, 85517, 85523, 85531, 85549, 85571, 85577, 85597, 85601,
+ 85607, 85619, 85621, 85627, 85639, 85643, 85661, 85667, 85669, 85691,
+ 85703, 85711, 85717, 85733, 85751, 85781, 85793, 85817, 85819, 85829,
+ 85831, 85837, 85843, 85847, 85853, 85889, 85903, 85909, 85931, 85933,
+ 85991, 85999, 86011, 86017, 86027, 86029, 86069, 86077, 86083, 86111,
+ 86113, 86117, 86131, 86137, 86143, 86161, 86171, 86179, 86183, 86197,
+ 86201, 86209, 86239, 86243, 86249, 86257, 86263, 86269, 86287, 86291,
+ 86293, 86297, 86311, 86323, 86341, 86351, 86353, 86357, 86369, 86371,
+ 86381, 86389, 86399, 86413, 86423, 86441, 86453, 86461, 86467, 86477,
+ 86491, 86501, 86509, 86531, 86533, 86539, 86561, 86573, 86579, 86587,
+ 86599, 86627, 86629, 86677, 86689, 86693, 86711, 86719, 86729, 86743,
+ 86753, 86767, 86771, 86783, 86813, 86837, 86843, 86851, 86857, 86861,
+ 86869, 86923, 86927, 86929, 86939, 86951, 86959, 86969, 86981, 86993,
+ 87011, 87013, 87037, 87041, 87049, 87071, 87083, 87103, 87107, 87119,
+ 87121, 87133, 87149, 87151, 87179, 87181, 87187, 87211, 87221, 87223,
+ 87251, 87253, 87257, 87277, 87281, 87293, 87299, 87313, 87317, 87323,
+ 87337, 87359, 87383, 87403, 87407, 87421, 87427, 87433, 87443, 87473,
+ 87481, 87491, 87509, 87511, 87517, 87523, 87539, 87541, 87547, 87553,
+ 87557, 87559, 87583, 87587, 87589, 87613, 87623, 87629, 87631, 87641,
+ 87643, 87649, 87671, 87679, 87683, 87691, 87697, 87701, 87719, 87721,
+ 87739, 87743, 87751, 87767, 87793, 87797, 87803, 87811, 87833, 87853,
+ 87869, 87877, 87881, 87887, 87911, 87917, 87931, 87943, 87959, 87961,
+ 87973, 87977, 87991, 88001, 88003, 88007, 88019, 88037, 88069, 88079,
+ 88093, 88117, 88129, 88169, 88177, 88211, 88223, 88237, 88241, 88259,
+ 88261, 88289, 88301, 88321, 88327, 88337, 88339, 88379, 88397, 88411,
+ 88423, 88427, 88463, 88469, 88471, 88493, 88499, 88513, 88523, 88547,
+ 88589, 88591, 88607, 88609, 88643, 88651, 88657, 88661, 88663, 88667,
+ 88681, 88721, 88729, 88741, 88747, 88771, 88789, 88793, 88799, 88801,
+ 88807, 88811, 88813, 88817, 88819, 88843, 88853, 88861, 88867, 88873,
+ 88883, 88897, 88903, 88919, 88937, 88951, 88969, 88993, 88997, 89003,
+ 89009, 89017, 89021, 89041, 89051, 89057, 89069, 89071, 89083, 89087,
+ 89101, 89107, 89113, 89119, 89123, 89137, 89153, 89189, 89203, 89209,
+ 89213, 89227, 89231, 89237, 89261, 89269, 89273, 89293, 89303, 89317,
+ 89329, 89363, 89371, 89381, 89387, 89393, 89399, 89413, 89417, 89431,
+ 89443, 89449, 89459, 89477, 89491, 89501, 89513, 89519, 89521, 89527,
+ 89533, 89561, 89563, 89567, 89591, 89597, 89599, 89603, 89611, 89627,
+ 89633, 89653, 89657, 89659, 89669, 89671, 89681, 89689, 89753, 89759,
+ 89767, 89779, 89783, 89797, 89809, 89819, 89821, 89833, 89839, 89849,
+ 89867, 89891, 89897, 89899, 89909, 89917, 89923, 89939, 89959, 89963,
+ 89977, 89983, 89989, 90001, 90007, 90011, 90017, 90019, 90023, 90031,
+ 90053, 90059, 90067, 90071, 90073, 90089, 90107, 90121, 90127, 90149,
+ 90163, 90173, 90187, 90191, 90197, 90199, 90203, 90217, 90227, 90239,
+ 90247, 90263, 90271, 90281, 90289, 90313, 90353, 90359, 90371, 90373,
+ 90379, 90397, 90401, 90403, 90407, 90437, 90439, 90469, 90473, 90481,
+ 90499, 90511, 90523, 90527, 90529, 90533, 90547, 90583, 90599, 90617,
+ 90619, 90631, 90641, 90647, 90659, 90677, 90679, 90697, 90703, 90709,
+ 90731, 90749, 90787, 90793, 90803, 90821, 90823, 90833, 90841, 90847,
+ 90863, 90887, 90901, 90907, 90911, 90917, 90931, 90947, 90971, 90977,
+ 90989, 90997, 91009, 91019, 91033, 91079, 91081, 91097, 91099, 91121,
+ 91127, 91129, 91139, 91141, 91151, 91153, 91159, 91163, 91183, 91193,
+ 91199, 91229, 91237, 91243, 91249, 91253, 91283, 91291, 91297, 91303,
+ 91309, 91331, 91367, 91369, 91373, 91381, 91387, 91393, 91397, 91411,
+ 91423, 91433, 91453, 91457, 91459, 91463, 91493, 91499, 91513, 91529,
+ 91541, 91571, 91573, 91577, 91583, 91591, 91621, 91631, 91639, 91673,
+ 91691, 91703, 91711, 91733, 91753, 91757, 91771, 91781, 91801, 91807,
+ 91811, 91813, 91823, 91837, 91841, 91867, 91873, 91909, 91921, 91939,
+ 91943, 91951, 91957, 91961, 91967, 91969, 91997, 92003, 92009, 92033,
+ 92041, 92051, 92077, 92083, 92107, 92111, 92119, 92143, 92153, 92173,
+ 92177, 92179, 92189, 92203, 92219, 92221, 92227, 92233, 92237, 92243,
+ 92251, 92269, 92297, 92311, 92317, 92333, 92347, 92353, 92357, 92363,
+ 92369, 92377, 92381, 92383, 92387, 92399, 92401, 92413, 92419, 92431,
+ 92459, 92461, 92467, 92479, 92489, 92503, 92507, 92551, 92557, 92567,
+ 92569, 92581, 92593, 92623, 92627, 92639, 92641, 92647, 92657, 92669,
+ 92671, 92681, 92683, 92693, 92699, 92707, 92717, 92723, 92737, 92753,
+ 92761, 92767, 92779, 92789, 92791, 92801, 92809, 92821, 92831, 92849,
+ 92857, 92861, 92863, 92867, 92893, 92899, 92921, 92927, 92941, 92951,
+ 92957, 92959, 92987, 92993, 93001, 93047, 93053, 93059, 93077, 93083,
+ 93089, 93097, 93103, 93113, 93131, 93133, 93139, 93151, 93169, 93179,
+ 93187, 93199, 93229, 93239, 93241, 93251, 93253, 93257, 93263, 93281,
+ 93283, 93287, 93307, 93319, 93323, 93329, 93337, 93371, 93377, 93383,
+ 93407, 93419, 93427, 93463, 93479, 93481, 93487, 93491, 93493, 93497,
+ 93503, 93523, 93529, 93553, 93557, 93559, 93563, 93581, 93601, 93607,
+ 93629, 93637, 93683, 93701, 93703, 93719, 93739, 93761, 93763, 93787,
+ 93809, 93811, 93827, 93851, 93871, 93887, 93889, 93893, 93901, 93911,
+ 93913, 93923, 93937, 93941, 93949, 93967, 93971, 93979, 93983, 93997,
+ 94007, 94009, 94033, 94049, 94057, 94063, 94079, 94099, 94109, 94111,
+ 94117, 94121, 94151, 94153, 94169, 94201, 94207, 94219, 94229, 94253,
+ 94261, 94273, 94291, 94307, 94309, 94321, 94327, 94331, 94343, 94349,
+ 94351, 94379, 94397, 94399, 94421, 94427, 94433, 94439, 94441, 94447,
+ 94463, 94477, 94483, 94513, 94529, 94531, 94541, 94543, 94547, 94559,
+ 94561, 94573, 94583, 94597, 94603, 94613, 94621, 94649, 94651, 94687,
+ 94693, 94709, 94723, 94727, 94747, 94771, 94777, 94781, 94789, 94793,
+ 94811, 94819, 94823, 94837, 94841, 94847, 94849, 94873, 94889, 94903,
+ 94907, 94933, 94949, 94951, 94961, 94993, 94999, 95003, 95009, 95021,
+ 95027, 95063, 95071, 95083, 95087, 95089, 95093, 95101, 95107, 95111,
+ 95131, 95143, 95153, 95177, 95189, 95191, 95203, 95213, 95219, 95231,
+ 95233, 95239, 95257, 95261, 95267, 95273, 95279, 95287, 95311, 95317,
+ 95327, 95339, 95369, 95383, 95393, 95401, 95413, 95419, 95429, 95441,
+ 95443, 95461, 95467, 95471, 95479, 95483, 95507, 95527, 95531, 95539,
+ 95549, 95561, 95569, 95581, 95597, 95603, 95617, 95621, 95629, 95633,
+ 95651, 95701, 95707, 95713, 95717, 95723, 95731, 95737, 95747, 95773,
+ 95783, 95789, 95791, 95801, 95803, 95813, 95819, 95857, 95869, 95873,
+ 95881, 95891, 95911, 95917, 95923, 95929, 95947, 95957, 95959, 95971,
+ 95987, 95989, 96001, 96013, 96017, 96043, 96053, 96059, 96079, 96097,
+ 96137, 96149, 96157, 96167, 96179, 96181, 96199, 96211, 96221, 96223,
+ 96233, 96259, 96263, 96269, 96281, 96289, 96293, 96323, 96329, 96331,
+ 96337, 96353, 96377, 96401, 96419, 96431, 96443, 96451, 96457, 96461,
+ 96469, 96479, 96487, 96493, 96497, 96517, 96527, 96553, 96557, 96581,
+ 96587, 96589, 96601, 96643, 96661, 96667, 96671, 96697, 96703, 96731,
+ 96737, 96739, 96749, 96757, 96763, 96769, 96779, 96787, 96797, 96799,
+ 96821, 96823, 96827, 96847, 96851, 96857, 96893, 96907, 96911, 96931,
+ 96953, 96959, 96973, 96979, 96989, 96997, 97001, 97003, 97007, 97021,
+ 97039, 97073, 97081, 97103, 97117, 97127, 97151, 97157, 97159, 97169,
+ 97171, 97177, 97187, 97213, 97231, 97241, 97259, 97283, 97301, 97303,
+ 97327, 97367, 97369, 97373, 97379, 97381, 97387, 97397, 97423, 97429,
+ 97441, 97453, 97459, 97463, 97499, 97501, 97511, 97523, 97547, 97549,
+ 97553, 97561, 97571, 97577, 97579, 97583, 97607, 97609, 97613, 97649,
+ 97651, 97673, 97687, 97711, 97729, 97771, 97777, 97787, 97789, 97813,
+ 97829, 97841, 97843, 97847, 97849, 97859, 97861, 97871, 97879, 97883,
+ 97919, 97927, 97931, 97943, 97961, 97967, 97973, 97987, 98009, 98011,
+ 98017, 98041, 98047, 98057, 98081, 98101, 98123, 98129, 98143, 98179,
+ 98207, 98213, 98221, 98227, 98251, 98257, 98269, 98297, 98299, 98317,
+ 98321, 98323, 98327, 98347, 98369, 98377, 98387, 98389, 98407, 98411,
+ 98419, 98429, 98443, 98453, 98459, 98467, 98473, 98479, 98491, 98507,
+ 98519, 98533, 98543, 98561, 98563, 98573, 98597, 98621, 98627, 98639,
+ 98641, 98663, 98669, 98689, 98711, 98713, 98717, 98729, 98731, 98737,
+ 98773, 98779, 98801, 98807, 98809, 98837, 98849, 98867, 98869, 98873,
+ 98887, 98893, 98897, 98899, 98909, 98911, 98927, 98929, 98939, 98947,
+ 98953, 98963, 98981, 98993, 98999, 99013, 99017, 99023, 99041, 99053,
+ 99079, 99083, 99089, 99103, 99109, 99119, 99131, 99133, 99137, 99139,
+ 99149, 99173, 99181, 99191, 99223, 99233, 99241, 99251, 99257, 99259,
+ 99277, 99289, 99317, 99347, 99349, 99367, 99371, 99377, 99391, 99397,
+ 99401, 99409, 99431, 99439, 99469, 99487, 99497, 99523, 99527, 99529,
+ 99551, 99559, 99563, 99571, 99577, 99581, 99607, 99611, 99623, 99643,
+ 99661, 99667, 99679, 99689, 99707, 99709, 99713, 99719, 99721, 99733,
+ 99761, 99767, 99787, 99793, 99809, 99817, 99823, 99829, 99833, 99839,
+ 99859, 99871, 99877, 99881, 99901, 99907, 99923, 99929, 99961, 99971,
+ 99989, 99991, 100003, 100019, 100043, 100049, 100057, 100069, 100103, 100109,
+ 100129, 100151, 100153, 100169, 100183, 100189, 100193, 100207, 100213, 100237,
+ 100267, 100271, 100279, 100291, 100297, 100313, 100333, 100343, 100357, 100361,
+ 100363, 100379, 100391, 100393, 100403, 100411, 100417, 100447, 100459, 100469,
+ 100483, 100493, 100501, 100511, 100517, 100519, 100523, 100537, 100547, 100549,
+ 100559, 100591, 100609, 100613, 100621, 100649, 100669, 100673, 100693, 100699,
+ 100703, 100733, 100741, 100747, 100769, 100787, 100799, 100801, 100811, 100823,
+ 100829, 100847, 100853, 100907, 100913, 100927, 100931, 100937, 100943, 100957,
+ 100981, 100987, 100999, 101009, 101021, 101027, 101051, 101063, 101081, 101089,
+ 101107, 101111, 101113, 101117, 101119, 101141, 101149, 101159, 101161, 101173,
+ 101183, 101197, 101203, 101207, 101209, 101221, 101267, 101273, 101279, 101281,
+ 101287, 101293, 101323, 101333, 101341, 101347, 101359, 101363, 101377, 101383,
+ 101399, 101411, 101419, 101429, 101449, 101467, 101477, 101483, 101489, 101501,
+ 101503, 101513, 101527, 101531, 101533, 101537, 101561, 101573, 101581, 101599,
+ 101603, 101611, 101627, 101641, 101653, 101663, 101681, 101693, 101701, 101719,
+ 101723, 101737, 101741, 101747, 101749, 101771, 101789, 101797, 101807, 101833,
+ 101837, 101839, 101863, 101869, 101873, 101879, 101891, 101917, 101921, 101929,
+ 101939, 101957, 101963, 101977, 101987, 101999, 102001, 102013, 102019, 102023,
+ 102031, 102043, 102059, 102061, 102071, 102077, 102079, 102101, 102103, 102107,
+ 102121, 102139, 102149, 102161, 102181, 102191, 102197, 102199, 102203, 102217,
+ 102229, 102233, 102241, 102251, 102253, 102259, 102293, 102299, 102301, 102317,
+ 102329, 102337, 102359, 102367, 102397, 102407, 102409, 102433, 102437, 102451,
+ 102461, 102481, 102497, 102499, 102503, 102523, 102533, 102539, 102547, 102551,
+ 102559, 102563, 102587, 102593, 102607, 102611, 102643, 102647, 102653, 102667,
+ 102673, 102677, 102679, 102701, 102761, 102763, 102769, 102793, 102797, 102811,
+ 102829, 102841, 102859, 102871, 102877, 102881, 102911, 102913, 102929, 102931,
+ 102953, 102967, 102983, 103001, 103007, 103043, 103049, 103067, 103069, 103079,
+ 103087, 103091, 103093, 103099, 103123, 103141, 103171, 103177, 103183, 103217,
+ 103231, 103237, 103289, 103291, 103307, 103319, 103333, 103349, 103357, 103387,
+ 103391, 103393, 103399, 103409, 103421, 103423, 103451, 103457, 103471, 103483,
+ 103511, 103529, 103549, 103553, 103561, 103567, 103573, 103577, 103583, 103591,
+ 103613, 103619, 103643, 103651, 103657, 103669, 103681, 103687, 103699, 103703,
+ 103723, 103769, 103787, 103801, 103811, 103813, 103837, 103841, 103843, 103867,
+ 103889, 103903, 103913, 103919, 103951, 103963, 103967, 103969, 103979, 103981,
+ 103991, 103993, 103997, 104003, 104009, 104021, 104033, 104047, 104053, 104059,
+ 104087, 104089, 104107, 104113, 104119, 104123, 104147, 104149, 104161, 104173,
+ 104179, 104183, 104207, 104231, 104233, 104239, 104243, 104281, 104287, 104297,
+ 104309, 104311, 104323, 104327, 104347, 104369, 104381, 104383, 104393, 104399,
+ 104417, 104459, 104471, 104473, 104479, 104491, 104513, 104527, 104537, 104543,
+ 104549, 104551, 104561, 104579, 104593, 104597, 104623, 104639, 104651, 104659,
+ 104677, 104681, 104683, 104693, 104701, 104707, 104711, 104717, 104723, 104729,
+};
+
+// return 1 if p is divisable by sp, 0 otherwise
+static int
+divides(mpint *dividend, ulong divisor)
+{
+ mpdigit d[2], q;
+ int i;
+
+ d[1] = 0;
+ for(i = dividend->top-1; i >= 0; i--){
+ d[0] = dividend->p[i];
+ mpdigdiv(d, divisor, &q);
+ d[1] = d[0] - divisor*q;
+ }
+ return d[1] == 0;
+}
+
+// return -1 if p is divisable by one of the small primes, 0 otherwise
+int
+smallprimetest(mpint *p)
+{
+ int i;
+ ulong sp;
+
+ for(i = 0; i < nelem(smallprimes); i++){
+ sp = smallprimes[i];
+ if(p->top == 1 && p->p[0] <= sp)
+ break;
+ if(divides(p, sp))
+ return -1;
+ }
+ return 0;
+}
--- /dev/null
+++ b/libtk/NOTES
@@ -1,0 +1,90 @@
+Notes on the Tk implementation.
+
+General
+
+ TkTop represents a top-level window.
+ It holds pointers to the widgets created in that
+ window:
+ windows gives a list of all windows (this includes "." and any menu widgets)
+ root the list of all widgets, whether packed or not.
+
+ Each Tk widget holds pointers to the widgets packed inside it, its slaves.
+ Widgets that do their own child widget management (canvas
+ and text) do not use the slaves list, but store pointers
+ to them in their own data structures.
+
+ Each Tk widget, w, holds a pointer to the widget it's packed or stored inside.
+
+ w->master
+ if it's packed or stored in a grid
+ w->parent
+ if it's a child widget of a canvas or text widget.
+
+ A widget type is operated on through functions referred to in its TkMethod structure,
+ defined in that widget type's source file, and pointed to by the
+ method dispatch table, tkmethod, defined in xdata.c.
+
+ utils.c contains the master table holding the built-in commands
+ (e.g. widget creation, focus, grab, etc) with their
+ associated functions.
+
+ xdata.c holds the method table (tkmethod) mapping from
+ widget type to the method functions supported by individual widgets.
+
+
+
+Coordinates:
+
+ A widget requests a particular size allocation
+ by setting its req.width and req.height fields.
+ The packer (or its parent) determines the actual
+ size allocation, and position and sets act.x, act.y, act.width
+ and act.height appropriately.
+
+ The requested width and height do not include the
+ borderwidth, which is factored in additionally.
+
+ Coordinates as delivered by the %x and %y verbs provided
+ by bind(9) are relative to the top left of the widget,
+ inside its border. I'll call this the "widget's coordinate system".
+
+ The draw method of each widget type is provided with
+ an "origin" argument.
+
+ (origin.x + act.x + borderwidth, origin.y + act.y + borderwidth)
+
+ gives the screen coordinate of (0, 0) in the widget coordinate
+ system.
+
+
+Dirtiness
+
+ Each widget has a "dirty" rectangle, the bounding
+ box of any changes that it needs to make visible.
+ This is in the widget's coordinate system.
+
+ A widget does not have to update everything in
+ the dirty rectangle, unless the Tkrefresh flag
+ is set, in which case it must.
+
+ A widget never has to draw anything outside of its dirty
+ rectangle.
+
+Locking
+
+ Mostly, Tk is non-reentrant because the interpreter is held
+ when a call to, e.g. Tk_cmd, is made.
+
+ However, when the display is remote, any access of the display
+ (drawing, stringsize, etc) can do a release() and therefore
+ let another thread access tk.
+
+ The drawing code itself locks the display, so code invoked
+ from within a widgets draw() method is guaranteed
+ non-reentrant.
+
+ If access to the draw device is required during code executed
+ in a non-drawing context (e.g. to calculate the size of a
+ string), care must be taken to lock the draw device
+ appropriately. Tk provides some convenience functions to do
+ this (e.g. tkstringsize).
--- /dev/null
+++ b/libtk/NOTICE
@@ -1,0 +1,26 @@
+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 © 1995-1999 Lucent Technologies Inc.
+Portions Copyright © 1997-2000 Vita Nuova Limited
+Portions Copyright © 2000-2008 Vita Nuova Holdings Limited
+Portions Copyright © 2010 Vita Nuova Holdings Limited
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU Lesser General Public License (`LGPL') as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
--- /dev/null
+++ b/libtk/buton.c
@@ -1,0 +1,794 @@
+#include "lib9.h"
+#include "draw.h"
+#include "tk.h"
+#include "label.h"
+
+#define O(t, e) ((long)(&((t*)0)->e))
+
+/* Widget Commands (+ means implemented)
+ +cget
+ +configure
+ +invoke
+ +select
+ +deselect
+ +toggle
+ */
+
+enum {
+ /* other constants */
+ InvokePause = 200, /* delay showing button in down state when invoked */
+};
+
+TkOption tkbutopts[] =
+{
+ "text", OPTtext, O(TkLabel, text), nil,
+ "label", OPTtext, O(TkLabel, text), nil,
+ "underline", OPTdist, O(TkLabel, ul), nil,
+ "justify", OPTstab, O(TkLabel, justify), tkjustify,
+ "anchor", OPTflag, O(TkLabel, anchor), tkanchor,
+ "command", OPTtext, O(TkLabel, command), nil,
+ "bitmap", OPTbmap, O(TkLabel, bitmap), nil,
+ "image", OPTimag, O(TkLabel, img), nil,
+ nil
+};
+
+TkOption tkcbopts[] =
+{
+ "variable", OPTtext, O(TkLabel, variable), nil,
+ "indicatoron", OPTstab, O(TkLabel, indicator), tkbool,
+ "onvalue", OPTtext, O(TkLabel, value), nil,
+ "offvalue", OPTtext, O(TkLabel, offvalue), nil,
+ nil,
+};
+
+TkOption tkradopts[] =
+{
+ "variable", OPTtext, O(TkLabel, variable), nil,
+ "value", OPTtext, O(TkLabel, value), nil,
+ "indicatoron", OPTstab, O(TkLabel, indicator), tkbool,
+ nil,
+};
+
+static
+TkEbind bb[] =
+{
+ {TkEnter, "%W configure -state active"},
+ {TkLeave, "%W configure -state normal"},
+ {TkButton1P, "%W tkButton1P"},
+ {TkButton1R, "%W tkButton1R %x %y"},
+ {TkMotion|TkButton1P, "" },
+ {TkKey, "%W tkButtonKey 0x%K"},
+};
+
+static
+TkEbind cb[] =
+{
+ {TkEnter, "%W configure -state active"},
+ {TkLeave, "%W configure -state normal"},
+ {TkButton1P, "%W invoke"},
+ {TkMotion|TkButton1P, "" },
+ {TkKey, "%W tkButtonKey 0x%K"},
+};
+
+
+static char tkselbut[] = "selectedButton";
+
+static char* newbutton(TkTop*, int, char*, char**);
+static int istransparent(Tk*);
+static void tkvarchanged(Tk*, char*, char*);
+
+char*
+tkbutton(TkTop *t, char *arg, char **ret)
+{
+ return newbutton(t, TKbutton, arg, ret);
+}
+
+char*
+tkcheckbutton(TkTop *t, char *arg, char **ret)
+{
+ return newbutton(t, TKcheckbutton, arg, ret);
+}
+
+char*
+tkradiobutton(TkTop *t, char *arg, char **ret)
+{
+ return newbutton(t, TKradiobutton, arg, ret);
+}
+
+static char*
+newbutton(TkTop *t, int btype, char *arg, char **ret)
+{
+ Tk *tk;
+ char *e;
+ TkLabel *tkl;
+ TkName *names;
+ TkOptab tko[4];
+ TkVar *v;
+
+ tk = tkmkbutton(t, btype);
+ if(tk == nil)
+ return TkNomem;
+
+ tkl = TKobj(TkLabel, tk);
+
+ tko[0].ptr = tk;
+ tko[0].optab = tkgeneric;
+ tko[1].ptr = tkl;
+ tko[1].optab = tkbutopts;
+ switch(btype){
+ case TKcheckbutton:
+ tko[2].ptr = tkl;
+ tko[2].optab = tkcbopts;
+ break;
+ case TKradiobutton:
+ tko[2].ptr = tkl;
+ tko[2].optab = tkradopts;
+ break;
+ default:
+ tk->relief = TKraised;
+ tk->borderwidth = 1;
+ tko[2].ptr = nil;
+ break;
+ }
+ tko[3].ptr = nil;
+
+ names = nil;
+ e = tkparse(t, arg, tko, &names);
+ if(e != nil) {
+ tkfreeobj(tk);
+ return e;
+ }
+
+ tksettransparent(tk, istransparent(tk));
+ tksizebutton(tk);
+
+ e = tkaddchild(t, tk, &names);
+ tkfreename(names);
+ if(e != nil) {
+ tkfreeobj(tk);
+ return e;
+ }
+ tk->name->link = nil;
+
+ if (btype == TKradiobutton &&
+ tkl->variable != nil &&
+ strcmp(tkl->variable, tkselbut) == 0 &&
+ tkl->value == nil &&
+ tk->name != nil)
+ tkl->value = strdup(tk->name->name);
+
+ if (tkl->variable != nil) {
+ v = tkmkvar(t, tkl->variable, 0);
+ if (v == nil){
+ if(btype == TKcheckbutton){
+ e = tksetvar(t, tkl->variable, tkl->offvalue ? tkl->offvalue : "0");
+ if (e != nil)
+ goto err;
+ }
+ } else if(v->type != TkVstring){
+ e = TkNotvt;
+ goto err;
+ } else
+ tkvarchanged(tk, tkl->variable, v->value);
+ }
+
+ return tkvalue(ret, "%s", tk->name->name);
+
+err:
+ tkfreeobj(tk);
+ return e;
+}
+
+Tk*
+tkmkbutton(TkTop *t, int btype)
+{
+ Tk *tk;
+ TkLabel *tkl;
+ char *e;
+
+ tk = tknewobj(t, btype, sizeof(Tk)+sizeof(TkLabel));
+ if (tk == nil)
+ return nil;
+
+ e = nil;
+ tk->relief = TKraised;
+ tk->borderwidth = 0;
+ tk->highlightwidth = 1;
+ tk->flag |= Tktakefocus;
+ tkl = TKobj(TkLabel, tk);
+ tkl->ul = -1;
+ tkl->justify = Tkleft;
+
+ switch (btype) {
+ case TKbutton:
+ e = tkbindings(t, tk, bb, nelem(bb));
+ break;
+ case TKcheckbutton:
+ e = tkbindings(t, tk, cb, nelem(cb));
+ break;
+ case TKradiobutton:
+ tkl->variable = strdup(tkselbut);
+ e = tkbindings(t, tk, cb, nelem(cb));
+ break;
+ }
+
+ if (e != nil) {
+ print("tkmkbutton internal error: %s\n", e);
+ tkfreeobj(tk);
+ return nil;
+ }
+ return tk;
+}
+
+/*
+ * draw TKbutton, TKcheckbutton, TKradiobutton
+ */
+char*
+tkdrawbutton(Tk *tk, Point orig)
+{
+ TkEnv *e;
+ TkLabel *tkl;
+ Rectangle r, s, mainr, focusr;
+ int dx, dy, h;
+ Point p, u, v, pp[4];
+ Image *i, *dst, *cd, *cl, *ct, *img;
+ int relief, bgnd, fgnd;
+
+ e = tk->env;
+
+ dst = tkimageof(tk);
+ if(dst == nil)
+ return nil;
+
+ v.x = tk->act.width + 2*tk->borderwidth;
+ v.y = tk->act.height + 2*tk->borderwidth;
+
+ r.min = ZP;
+ r.max = v;
+ focusr = insetrect(r, tk->borderwidth);
+ mainr = insetrect(focusr, tk->highlightwidth);
+ relief = tk->relief;
+
+ tkl = TKobj(TkLabel, tk);
+
+ fgnd = TkCforegnd;
+ bgnd = TkCbackgnd;
+ if (tk->flag & Tkdisabled)
+ fgnd = TkCdisablefgnd;
+ else if ((tk->type == TKcheckbutton || tk->type == TKradiobutton) && tkl->indicator == BoolF && tkl->check)
+ bgnd = TkCselect;
+ else if (tk->flag & Tkactive) {
+ fgnd = TkCactivefgnd;
+ bgnd = TkCactivebgnd;
+ }
+
+ i = tkitmp(e, r.max, bgnd);
+ if(i == nil)
+ return nil;
+
+ if(tk->flag & Tkactive)
+ draw(i, r, tkgc(e, bgnd), nil, ZP);
+
+ p = mainr.min;
+ h = tkl->h - 2 * tk->highlightwidth;
+
+ dx = tk->act.width - tkl->w - tk->ipad.x;
+ dy = tk->act.height - tkl->h - tk->ipad.y;
+ if((tkl->anchor & (Tknorth|Tksouth)) == 0)
+ p.y += dy/2;
+ else if(tkl->anchor & Tksouth)
+ p.y += dy;
+
+ if((tkl->anchor & (Tkeast|Tkwest)) == 0)
+ p.x += dx/2;
+ else if(tkl->anchor & Tkeast)
+ p.x += dx;
+
+ switch(tk->type) {
+ case TKcheckbutton:
+ if(tkl->indicator == BoolF) {
+ relief = tkl->check? TKsunken: TKraised;
+ break;
+ }
+ u.x = p.x + ButtonBorder;
+ u.y = p.y + ButtonBorder + (h - CheckSpace) / 2;
+
+ cl = tkgc(e, bgnd+TkLightshade);
+ cd = tkgc(e, bgnd+TkDarkshade);
+ tkbevel(i, u, CheckButton, CheckButton, CheckButtonBW, cd, cl);
+ if(tkl->check) {
+ u.x += CheckButtonBW+1;
+ u.y += CheckButtonBW+1;
+ pp[0] = u;
+ pp[0].y += CheckButton/2-1;
+ pp[1] = pp[0];
+ pp[1].x += 2;
+ pp[1].y += 2;
+ pp[2] = u;
+ pp[2].x += CheckButton/4;
+ pp[2].y += CheckButton-2;
+ pp[3] = u;
+ pp[3].x += CheckButton-2;
+ pp[3].y++;
+ bezspline(i, pp, 4, Enddisc, Enddisc, 1, tkgc(e, TkCforegnd), ZP);
+ }
+ break;
+ case TKradiobutton:
+ if(tkl->indicator == BoolF) {
+ relief = tkl->check? TKsunken: TKraised;
+ break;
+ }
+ u.x = p.x + ButtonBorder;
+ u.y = p.y + ButtonBorder + (h - CheckSpace) / 2;
+ v = Pt(u.x+CheckButton/2,u.y+CheckButton/2);
+ ellipse(i, v, CheckButton/2, CheckButton/2, CheckButtonBW-1, tkgc(e, bgnd+TkDarkshade), ZP);
+ if(tkl->check)
+ fillellipse(i, v, CheckButton/2-2, CheckButton/2-2, tkgc(e, TkCforegnd), ZP); /* could be TkCselect */
+ break;
+ case TKbutton:
+ if ((tk->flag & (Tkactivated|Tkactive)) == (Tkactivated|Tkactive))
+ relief = TKsunken;
+ break;
+ }
+
+ p.x += tk->ipad.x/2;
+ p.y += tk->ipad.y/2;
+ u = ZP;
+ if(tk->type == TKbutton && relief == TKsunken) {
+ u.x++;
+ u.y++;
+ }
+ if((tk->type == TKcheckbutton || tk->type == TKradiobutton) && tkl->indicator != BoolF)
+ u.x += CheckSpace;
+
+ img = nil;
+ if (tkl->img != nil && tkl->img->img != nil)
+ img = tkl->img->img;
+ else if (tkl->bitmap != nil)
+ img = tkl->bitmap;
+ if (img != nil) {
+ s.min.x = p.x + Bitpadx;
+ s.min.y = p.y + Bitpady;
+ s.max.x = s.min.x + Dx(img->r);
+ s.max.y = s.min.y + Dy(img->r);
+ s = rectaddpt(s, u);
+ if(tkchanhastype(img->chan, CGrey))
+ draw(i, s, tkgc(e, fgnd), img, ZP);
+ else
+ draw(i, s, img, nil, ZP);
+ } else if(tkl->text != nil) {
+ u.x += Textpadx;
+ u.y += Textpady;
+ ct = tkgc(e, fgnd);
+
+ p.y += (h - tkl->textheight) / 2;
+ tkdrawstring(tk, i, addpt(u, p), tkl->text, tkl->ul, ct, tkl->justify);
+ }
+
+// if(tkhaskeyfocus(tk))
+// tkbox(i, focusr, tk->highlightwidth, tkgc(e, TkChighlightfgnd));
+ tkdrawrelief(i, tk, ZP, bgnd, relief);
+
+ p.x = tk->act.x + orig.x;
+ p.y = tk->act.y + orig.y;
+ r = rectaddpt(r, p);
+ draw(dst, r, i, nil, ZP);
+
+ return nil;
+}
+
+void
+tksizebutton(Tk *tk)
+{
+ int w, h;
+ TkLabel *tkl;
+
+ tkl = TKobj(TkLabel, tk);
+ if(tkl->anchor == 0)
+ tkl->anchor = Tkcenter;
+
+ tksizelabel(tk); /* text, bitmap or image, and highlight */
+ w = tkl->w;
+ h = tkl->h;
+
+ if((tk->type == TKcheckbutton || tk->type == TKradiobutton) && tkl->indicator != BoolF) {
+ w += CheckSpace;
+ if(h < CheckSpace)
+ h = CheckSpace;
+ }
+ tkl->w = w;
+ tkl->h = h;
+ if((tk->flag & Tksetwidth) == 0)
+ tk->req.width = w;
+ if((tk->flag & Tksetheight) == 0)
+ tk->req.height = h;
+}
+
+int
+tkbuttonmargin(Tk *tk)
+{
+ TkLabel *tkl;
+ tkl = TKobj(TkLabel, tk);
+
+ switch (tk->type) {
+ case TKbutton:
+ if (tkl->img != nil || tkl->bitmap != nil)
+ return 0;
+ return Textpadx+tk->highlightwidth;
+ case TKcheckbutton:
+ case TKradiobutton:
+ return CheckButton + 2*CheckButtonBW + 2*ButtonBorder;
+ }
+ return tklabelmargin(tk);
+}
+
+void
+tkfreebutton(Tk *tk)
+{
+ tkfreelabel(tk);
+}
+
+static char*
+tkbuttoncget(Tk *tk, char *arg, char **val)
+{
+ TkOptab tko[4];
+ TkLabel *tkl = TKobj(TkLabel, tk);
+
+ tko[0].ptr = tk;
+ tko[0].optab = tkgeneric;
+ tko[1].ptr = tkl;
+ tko[1].optab = tkbutopts;
+ switch(tk->type){
+ case TKcheckbutton:
+ tko[2].ptr = tkl;
+ tko[2].optab = tkcbopts;
+ break;
+ case TKradiobutton:
+ tko[2].ptr = tkl;
+ tko[2].optab = tkradopts;
+ break;
+ default:
+ tko[2].ptr = nil;
+ break;
+ }
+ tko[3].ptr = nil;
+ return tkgencget(tko, arg, val, tk->env->top);
+}
+
+static char*
+tkbuttonconf(Tk *tk, char *arg, char **val)
+{
+ char *e;
+ TkGeom g;
+ int bd;
+ TkOptab tko[4];
+ TkVar *v;
+ TkLabel *tkl = TKobj(TkLabel, tk);
+
+ tko[0].ptr = tk;
+ tko[0].optab = tkgeneric;
+ tko[1].ptr = tkl;
+ tko[1].optab = tkbutopts;
+ switch(tk->type){
+ case TKcheckbutton:
+ tko[2].ptr = tkl;
+ tko[2].optab = tkcbopts;
+ break;
+ case TKradiobutton:
+ tko[2].ptr = tkl;
+ tko[2].optab = tkradopts;
+ break;
+ default:
+ tko[2].ptr = nil;
+ break;
+ }
+ tko[3].ptr = nil;
+
+ if(*arg == '\0')
+ return tkconflist(tko, val);
+
+ g = tk->req;
+ bd = tk->borderwidth;
+ e = tkparse(tk->env->top, arg, tko, nil);
+ tksizebutton(tk);
+ tkgeomchg(tk, &g, bd);
+
+ tk->dirty = tkrect(tk, 1);
+ tksettransparent(tk, istransparent(tk));
+ /*
+ * XXX what happens if we're now disabled, but we were in
+ * active state before?
+ */
+ if (tkl->variable != nil) {
+ v = tkmkvar(tk->env->top, tkl->variable, 0);
+ if (v != nil) {
+ if (v->type != TkVstring) {
+ e = TkNotvt;
+ free(tkl->variable);
+ tkl->variable = nil;
+ }
+ else
+ tkvarchanged(tk, tkl->variable, v->value);
+ }
+ }
+ return e;
+}
+
+static int
+istransparent(Tk *tk)
+{
+ TkEnv *e = tk->env;
+ return (tkhasalpha(e, TkCbackgnd) || tkhasalpha(e, TkCselectbgnd) || tkhasalpha(e, TkCactivebgnd));
+}
+
+static void
+tkvarchanged(Tk *tk, char *var, char *val)
+{
+ TkLabel *tkl;
+ char *sval;
+
+ tkl = TKobj(TkLabel, tk);
+ if (tkl->variable != nil && strcmp(tkl->variable, var) == 0) {
+ sval = tkl->value;
+ if (sval == nil)
+ sval = tk->type == TKcheckbutton ? "1" : "";
+ tkl->check = (strcmp(val, sval) == 0);
+ tk->dirty = tkrect(tk, 1);
+ tkdirty(tk);
+ }
+}
+
+static char*
+tkbutton1p(Tk *tk, char *arg, char **val)
+{
+ USED(arg);
+ USED(val);
+ if(tk->flag & Tkdisabled)
+ return nil;
+ tk->flag |= Tkactivated;
+ tk->dirty = tkrect(tk, 1);
+ tkdirty(tk);
+ return nil;
+}
+
+static char*
+tkbutton1r(Tk *tk, char *arg, char **val)
+{
+ char *e;
+ Point p;
+ Rectangle hitr;
+
+ USED(arg);
+
+ if(tk->flag & Tkdisabled)
+ return nil;
+ e = tkxyparse(tk, &arg, &p);
+ if (e == nil) {
+ hitr.min = ZP;
+ hitr.max.x = tk->act.width + tk->borderwidth*2;
+ hitr.max.y = tk->act.height + tk->borderwidth*2;
+ if(ptinrect(p, hitr) && (tk->flag & Tkactivated))
+ e = tkbuttoninvoke(tk, nil, val);
+ }
+ tk->flag &= ~Tkactivated;
+ tk->dirty = tkrect(tk, 1);
+ tkdirty(tk);
+ return e;
+}
+
+static char*
+tkbuttonkey(Tk *tk, char *arg, char **val)
+{
+ int key;
+
+ if(tk->flag & Tkdisabled)
+ return nil;
+
+ key = strtol(arg, nil, 0);
+ if (key == '\n' || key ==' ')
+ return tkbuttoninvoke(tk, nil, val);
+ return nil;
+}
+
+static char*
+tkbuttontoggle(Tk *tk, char *arg, char **val)
+{
+ char *e;
+ TkLabel *tkl = TKobj(TkLabel, tk);
+ char *v;
+
+ USED(arg);
+ USED(val);
+ if(tk->flag & Tkdisabled)
+ return nil;
+ tkl->check = !tkl->check;
+ if (tkl->check)
+ v = tkl->value ? tkl->value : "1";
+ else
+ v = tkl->offvalue ? tkl->offvalue : "0";
+ e = tksetvar(tk->env->top, tkl->variable, v);
+ tk->dirty = tkrect(tk, 0);
+ return e;
+}
+
+static char*
+buttoninvoke(Tk *tk, char **val)
+{
+ char *e = nil;
+ TkTop *top;
+ TkLabel *tkl = TKobj(TkLabel, tk);
+
+ top = tk->env->top;
+ if (tk->type == TKcheckbutton)
+ e = tkbuttontoggle(tk, "", val);
+ else if (tk->type == TKradiobutton)
+ e = tksetvar(top, tkl->variable, tkl->value);
+ if(e != nil)
+ return e;
+ if(tkl->command != nil)
+ return tkexec(tk->env->top, tkl->command, val);
+ return nil;
+}
+
+static void
+cancelinvoke(Tk *tk, void *v, int cancelled)
+{
+ int unset;
+ USED(cancelled);
+ USED(v);
+
+ /* if it was active before then leave it active unless cleared since */
+ if (v)
+ unset = 0;
+ else
+ unset = Tkactive;
+ unset &= (tk->flag & Tkactive);
+ unset |= Tkactivated;
+ tk->flag &= ~unset;
+ tksettransparent(tk, istransparent(tk));
+ tk->dirty = tkrect(tk, 1);
+ tkdirty(tk);
+ tkupdate(tk->env->top);
+}
+
+char*
+tkbuttoninvoke(Tk *tk, char *arg, char **val)
+{
+ char *e;
+ USED(arg);
+
+ if(tk->flag & Tkdisabled)
+ return nil;
+ e = buttoninvoke(tk, val);
+ if (e == nil && tk->type == TKbutton && !(tk->flag & Tkactivated)) {
+ tkrepeat(tk, cancelinvoke, (void*)(tk->flag&Tkactive), InvokePause, 0);
+ tk->flag |= Tkactivated | Tkactive;
+ tksettransparent(tk, istransparent(tk));
+ tk->dirty = tkrect(tk, 1);
+ tkdirty(tk);
+ tkupdate(tk->env->top);
+ }
+ return e;
+}
+
+static char*
+tkbuttonselect(Tk *tk, char *arg, char **val)
+{
+ char *e, *v;
+ TkLabel *tkl = TKobj(TkLabel, tk);
+
+ USED(arg);
+ USED(val);
+ if (tk->type == TKradiobutton)
+ v = tkl->value;
+ else if (tk->type == TKcheckbutton) {
+ v = tkl->value ? tkl->value : "1";
+ tkl->check = 1;
+ tk->dirty = tkrect(tk, 0);
+ } else
+ v = nil;
+ e = tksetvar(tk->env->top, tkl->variable, v);
+ if(e != nil)
+ return e;
+ return nil;
+}
+
+static char*
+tkbuttondeselect(Tk *tk, char *arg, char **val)
+{
+ char *e, *v;
+ TkLabel *tkl = TKobj(TkLabel, tk);
+
+ USED(arg);
+ USED(val);
+
+ if (tk->type == TKcheckbutton) {
+ v = tkl->offvalue ? tkl->offvalue : "0";
+ tkl->check = 0;
+ tk->dirty = tkrect(tk, 0);
+ } else
+ v = nil;
+
+ e = tksetvar(tk->env->top, tkl->variable, v);
+ if(e != nil)
+ return e;
+ return nil;
+}
+
+static
+TkCmdtab tkbuttoncmd[] =
+{
+ "cget", tkbuttoncget,
+ "configure", tkbuttonconf,
+ "invoke", tkbuttoninvoke,
+ "tkButton1P", tkbutton1p,
+ "tkButton1R", tkbutton1r,
+ "tkButtonKey", tkbuttonkey,
+ nil
+};
+
+static
+TkCmdtab tkchkbuttoncmd[] =
+{
+ "cget", tkbuttoncget,
+ "configure", tkbuttonconf,
+ "invoke", tkbuttoninvoke,
+ "select", tkbuttonselect,
+ "deselect", tkbuttondeselect,
+ "toggle", tkbuttontoggle,
+ "tkButtonKey", tkbuttonkey,
+ nil
+};
+
+static
+TkCmdtab tkradbuttoncmd[] =
+{
+ "cget", tkbuttoncget,
+ "configure", tkbuttonconf,
+ "invoke", tkbuttoninvoke,
+ "select", tkbuttonselect,
+ "deselect", tkbuttondeselect,
+ "tkButtonKey", tkbuttonkey,
+ nil
+};
+
+TkMethod buttonmethod = {
+ "button",
+ tkbuttoncmd,
+ tkfreebutton,
+ tkdrawbutton,
+ nil,
+ tklabelgetimgs
+};
+
+TkMethod checkbuttonmethod = {
+ "checkbutton",
+ tkchkbuttoncmd,
+ tkfreebutton,
+ tkdrawbutton,
+ nil,
+ tklabelgetimgs,
+ nil,
+ nil,
+ nil,
+ nil,
+ nil,
+ nil,
+ tkvarchanged
+};
+
+TkMethod radiobuttonmethod = {
+ "radiobutton",
+ tkradbuttoncmd,
+ tkfreebutton,
+ tkdrawbutton,
+ nil,
+ nil,
+ nil,
+ nil,
+ nil,
+ nil,
+ nil,
+ nil,
+ tkvarchanged
+};
--- /dev/null
+++ b/libtk/canvs.c
@@ -1,0 +1,2220 @@
+#include <lib9.h>
+#include <kernel.h>
+#include "draw.h"
+#include "tk.h"
+#include "canvs.h"
+
+/* Widget Commands (+ means implemented)
+ +addtag
+ except halo and start options of closest spec
+ +bbox
+ +bind
+ +canvasx
+ +canvasy
+ +cget
+ +configure
+ +coords
+ +create
+ +dchars
+ +delete
+ +dtag
+ +find
+ +focus
+ +gettags
+ +icursor
+ +index
+ +insert
+ +itemcget
+ +itemconfigure
+ +lower
+ +move
+ postscript
+ +raise
+ +scale
+ scan
+ +select
+ +type
+ +xview
+ +yview
+*/
+
+static
+TkStab tkbuffer[] = {
+ "visible", TkCbufvisible,
+ "all", TkCbufall,
+ "none", TkCbufnone,
+ "auto", TkCbufauto,
+
+ /* backwards compatibility */
+ "1", TkCbufall,
+ "yes", TkCbufall,
+ "off", TkCbufall,
+ "0", TkCbufauto,
+ "no", TkCbufauto,
+ "off", TkCbufauto,
+ nil
+};
+
+#define O(t, e) ((long)(&((t*)0)->e))
+#define OA(t, e) ((long)(((t*)0)->e))
+
+static
+TkOption opts[] =
+{
+ "closeenough", OPTfrac, O(TkCanvas, close), nil,
+ "confine", OPTfrac, O(TkCanvas, confine), nil,
+ "scrollregion", OPTfrac, OA(TkCanvas, scrollr), IAUX(4),
+ "xscrollincrement", OPTfrac, O(TkCanvas, xscrolli), nil,
+ "yscrollincrement", OPTfrac, O(TkCanvas, yscrolli), nil,
+ "xscrollcommand", OPTtext, O(TkCanvas, xscroll), nil,
+ "yscrollcommand", OPTtext, O(TkCanvas, yscroll), nil,
+ "width", OPTnnfrac, O(TkCanvas, width), nil,
+ "height", OPTnnfrac, O(TkCanvas, height), nil,
+ "buffer", OPTstab, O(TkCanvas, buffer), tkbuffer,
+ "buffered", OPTstab, O(TkCanvas, buffer), tkbool, /* backwards compatibility */
+ "selectborderwidth", OPTnndist, O(TkCanvas, sborderwidth), nil,
+ nil
+};
+
+int cvslshape[] = { TKI2F(8), TKI2F(10), TKI2F(3) };
+Rectangle bbnil = { 1000000, 1000000, -1000000, -1000000 };
+Rectangle huger = { -1000000, -1000000, 1000000, 1000000 };
+
+static void tkcvsgeom(Tk *tk);
+
+
+static void
+tkcvsf2i(Tk *tk, TkCanvas *tkc)
+{
+ Rectangle r;
+ tk->req.width = TKF2I(tkc->width);
+ tk->req.height = TKF2I(tkc->height);
+
+ r.min.x = TKF2I(tkc->scrollr[0]);
+ r.min.y = TKF2I(tkc->scrollr[1]);
+ r.max.x = TKF2I(tkc->scrollr[2]);
+ r.max.y = TKF2I(tkc->scrollr[3]);
+
+ /*
+ * make sure that the region is big enough to hold
+ * the actually displayed area
+ */
+ if (Dx(r) < tk->act.width)
+ r.max.x = r.min.x + tk->act.width;
+ if (Dy(r) < tk->act.height)
+ r.max.y = r.min.y + tk->act.height;
+ tkc->region = r;
+
+ /*
+ * make sure that the view origin is at a valid
+ * position with respect to the scroll region.
+ */
+ if (tkc->view.x + tk->act.width > r.max.x)
+ tkc->view.x = r.max.x - tk->act.width;
+ if (tkc->view.x < r.min.x)
+ tkc->view.x = r.min.x;
+
+ if (tkc->view.y + tk->act.height > r.max.y)
+ tkc->view.y = r.max.y - tk->act.height;
+ if (tkc->view.y < r.min.y)
+ tkc->view.y = r.min.y;
+
+}
+
+char*
+tkcanvas(TkTop *t, char *arg, char **ret)
+{
+ Tk *tk;
+ char *e;
+ TkCanvas *tkc;
+ TkName *names;
+ TkOptab tko[3];
+
+ tk = tknewobj(t, TKcanvas, sizeof(Tk)+sizeof(TkCanvas));
+ if(tk == nil)
+ return TkNomem;
+
+ tkc = TKobj(TkCanvas, tk);
+ tkc->close = TKI2F(1);
+ tkc->xscrolli = TKI2F(1);
+ tkc->yscrolli = TKI2F(1);
+ tkc->width = TKI2F(360);
+ tkc->height = TKI2F(270);
+ tkc->actions = 0;
+ tkc->actlim = Tksweep;
+ tkc->mask = nil;
+ tkc->sborderwidth = 1;
+
+ tko[0].ptr = tkc;
+ tko[0].optab = opts;
+ tko[1].ptr = tk;
+ tko[1].optab = tkgeneric;
+ tko[2].ptr = nil;
+
+ names = nil;
+ e = tkparse(t, arg, tko, &names);
+ if(e != nil)
+ goto err;
+ if(names == nil) {
+ /* tkerr(t, arg); XXX */
+ e = TkBadwp;
+ goto err;
+ }
+
+ tkc->current = tkmkname("current");
+ if(tkc->current == nil) {
+ e = TkNomem;
+ goto err;
+ }
+
+ tksettransparent(tk, tkhasalpha(tk->env, TkCbackgnd));
+ tkcvsf2i(tk, tkc);
+
+ e = tkaddchild(t, tk, &names);
+ tkfreename(names);
+ if(e != nil) {
+ tkfreename(tkc->current);
+ tkc->current = nil;
+ goto err;
+ }
+ tk->name->link = nil;
+
+ e = tkvalue(ret, "%s", tk->name->name);
+ if(e == nil)
+ return nil;
+
+ tkfreename(tkc->current);
+ return e;
+err:
+ tkfreeobj(tk);
+ return e;
+}
+
+void
+tkcvsdirty(Tk *sub)
+{
+ TkCanvas *c;
+ Tk *tk, *parent;
+ Rectangle r;
+ Point rel;
+
+ rel = ZP;
+ for(tk = sub; tk; tk = tk->master) {
+ rel.x += tk->borderwidth + tk->act.x;
+ rel.y += tk->borderwidth + tk->act.y;
+ if (tk->parent != nil)
+ break;
+ }
+ if (tk == nil)
+ return;
+ parent = tk->parent;
+ c = TKobj(TkCanvas, parent);
+ r = rectaddpt(sub->dirty, rel);
+ tkbbmax(&c->update, &r);
+ tkcvssetdirty(parent);
+}
+
+static void
+tkcvsfocusorder(Tk *tk)
+{
+ TkCanvas *tkc = TKobj(TkCanvas, tk);
+ TkCwind *win;
+ TkCitem *it;
+ TkWinfo *inf;
+ int i, n;
+
+ n = 0;
+ for (it = tkc->head; it != nil; it = it->next) {
+ if (it->type == TkCVwindow) {
+ win = TKobj(TkCwind, it);
+ if (win->sub != nil)
+ n++;
+ }
+ }
+ if (n == 0)
+ return;
+
+ inf = malloc(sizeof(*inf) * n);
+ if (inf == nil)
+ return;
+
+ i = 0;
+ for (it = tkc->head; it != nil; it = it->next) {
+ if (it->type == TkCVwindow) {
+ win = TKobj(TkCwind, it);
+ if (win->sub != nil) {
+ inf[i].w = win->sub;
+ inf[i].r = it->p.bb;
+ i++;
+ }
+ }
+ }
+
+ tksortfocusorder(inf, n);
+ for (i = 0; i < n; i++)
+ tkappendfocusorder(inf[i].w);
+}
+
+static char*
+tkcvscget(Tk *tk, char *arg, char **val)
+{
+ TkOptab tko[3];
+ TkCanvas *tkc = TKobj(TkCanvas, tk);
+
+ tko[0].ptr = tkc;
+ tko[0].optab = opts;
+ tko[1].ptr = tk;
+ tko[1].optab = tkgeneric;
+ tko[2].ptr = nil;
+
+ return tkgencget(tko, arg, val, tk->env->top);
+}
+
+static char*
+tkcvsconf(Tk *tk, char *arg, char **val)
+{
+ char *e;
+ int bd;
+ TkGeom g;
+ Rectangle r;
+ TkOptab tko[3];
+ TkCanvas *c = TKobj(TkCanvas, tk);
+
+ tko[0].ptr = c;
+ tko[0].optab = opts;
+ tko[1].ptr = tk;
+ tko[1].optab = tkgeneric;
+ tko[2].ptr = nil;
+
+ if(*arg == '\0')
+ return tkconflist(tko, val);
+
+ r.min = c->view;
+ r.max.x = r.min.x+tk->act.width;
+ r.max.y = r.min.y+tk->act.height;
+ tkbbmax(&c->update, &r);
+ tkbbmax(&c->update, &c->region);
+
+ bd = tk->borderwidth;
+ g = tk->req;
+ e = tkparse(tk->env->top, arg, tko, nil);
+ if(e != nil)
+ return e;
+ tksettransparent(tk, tkhasalpha(tk->env, TkCbackgnd));
+
+ tkcvsf2i(tk, c);
+
+ tkcvsgeom(tk);
+ tkgeomchg(tk, &g, bd);
+ tkbbmax(&c->update, &c->region);
+ tk->dirty = tkrect(tk, 1);
+ return nil;
+}
+
+void
+tkcvsfreeitem(TkCitem *i)
+{
+ int locked;
+ Display *d;
+
+ d = i->env->top->display;
+
+ locked = lockdisplay(d);
+ tkcimethod[i->type].free(i);
+ if(locked)
+ unlockdisplay(d);
+
+ tkfreepoint(&i->p);
+ tkputenv(i->env);
+ free(i);
+}
+
+void
+tkfreecanv(Tk *tk)
+{
+ Display *d;
+ int j, locked;
+ TkCanvas *c;
+ TkName *n, *nn;
+ TkCtag *t, *tt;
+ TkCitem *i, *next;
+
+ c = TKobj(TkCanvas, tk);
+ for(i = c->head; i; i = next) {
+ next = i->next;
+ tkcvsfreeitem(i);
+ }
+
+ if(c->xscroll != nil)
+ free(c->xscroll);
+ if(c->yscroll != nil)
+ free(c->yscroll);
+
+ for(j = 0; j < TkChash; j++) {
+ for(n = c->thash[j]; n; n = nn) {
+ nn = n->link;
+ for(t = n->obj; t; t = tt) {
+ tt = t->taglist;
+ free(t);
+ }
+ tkfreebind(n->prop.binds);
+ free(n);
+ }
+ }
+
+ free(c->current);
+
+ if((c->ialloc && c->image != nil) || c->mask != nil) {
+ if (c->ialloc && c->image != nil)
+ d = c->image->display;
+ else
+ d = c->mask->display;
+ locked = lockdisplay(d);
+ if (c->image != nil && c->ialloc)
+ freeimage(c->image);
+ if (c->mask != nil)
+ freeimage(c->mask);
+ if(locked)
+ unlockdisplay(d);
+ }
+}
+
+char*
+tkdrawcanv(Tk *tk, Point orig)
+{
+ Image *dst;
+ TkCitem *i;
+ Display *d;
+ TkCanvas *c;
+ Rectangle r, bufr, oclipr;
+ int vis, alpha, buffer;
+ Point rel, p;
+ TkCimeth *imeth;
+
+ c = TKobj(TkCanvas, tk);
+ d = tk->env->top->display;
+ dst = tkimageof(tk);
+ /*
+ * translation from local to screen coords
+ */
+ rel.x = orig.x + tk->act.x + tk->borderwidth;
+ rel.y = orig.y + tk->act.y + tk->borderwidth;
+
+ buffer = c->buffer;
+ if (buffer == TkCbufauto)
+ buffer = TkCbufvisible;
+/* buffer = (dst == TKobj(TkWin, tk->env->top->root)->image) ? TkCbufvisible : TkCbufnone; */
+
+ if (buffer == TkCbufnone) {
+ if(c->image != nil && c->ialloc)
+ freeimage(c->image);
+ c->image = dst;
+ c->ialloc = 0;
+
+ r = tkrect(tk, 0);
+ bufr = r;
+ rectclip(&bufr, tk->dirty);
+ oclipr = dst->clipr;
+
+ replclipr(dst, 0, rectaddpt(bufr, rel));
+ draw(dst, rectaddpt(bufr, rel), tkgc(tk->env, TkCbackgnd), nil, ZP);
+
+ p = subpt(rel, c->view);
+ p.x = TKI2F(p.x);
+ p.y = TKI2F(p.y);
+ bufr = rectaddpt(bufr, c->view);
+ for(i = c->head; i; i = i->next) {
+ if(rectXrect(i->p.bb, bufr)) {
+ imeth = &tkcimethod[i->type];
+ imeth->coord(i, nil, p.x, p.y);
+ imeth->draw(dst, i, tk->env);
+ imeth->coord(i, nil, -p.x, -p.y);
+ }
+ }
+ replclipr(dst, 0, oclipr);
+ } else {
+ if (c->buffer == TkCbufall)
+ bufr = c->region;
+ else {
+ bufr.min = c->view;
+ bufr.max.x = c->view.x + tk->act.width;
+ bufr.max.y = c->view.y + tk->act.height;
+ }
+ alpha = (tk->env->colors[TkCbackgnd] & 0xff) != 0xff;
+ if(c->image == nil || eqrect(bufr, c->image->r) == 0) {
+ if(c->image != nil && c->ialloc)
+ freeimage(c->image);
+ c->image = allocimage(d, bufr, alpha?RGBA32:d->image->chan, 0, tk->env->colors[TkCbackgnd]);
+ c->ialloc = 1;
+ c->update = bufr;
+ tkcvssetdirty(tk); /* unnecessary? */
+ }
+
+ if(c->image == nil)
+ return nil;
+
+ r = c->update;
+ if (rectclip(&r, c->image->r)) {
+ if (alpha)
+ drawop(c->image, c->update, nil, nil, ZP, Clear);
+ draw(c->image, c->update, tkgc(tk->env, TkCbackgnd), nil, c->view);
+ replclipr(c->image, 0, r);
+ for(i = c->head; i; i = i->next) {
+ if(rectXrect(i->p.bb, r))
+ tkcimethod[i->type].draw(c->image, i, tk->env);
+ }
+ replclipr(c->image, 0, c->image->r);
+ }
+ /*
+ * if the visible area of the canvas image doesn't
+ * fit completely within the dirty rectangle,
+ * then we'll need to draw the background behind it
+ */
+ r = tkrect(tk, 0);
+ bufr = rectsubpt(bufr, c->view);
+ vis = rectclip(&bufr, tkrect(tk, 0));
+
+ if (!vis || !rectinrect(tk->dirty, bufr))
+ draw(dst, rectaddpt(tk->dirty, rel), tkgc(tk->env, TkCbackgnd), nil, c->view);
+
+ if (vis && rectclip(&bufr, tk->dirty))
+ draw(dst, rectaddpt(bufr, rel), c->image, nil, addpt(bufr.min, c->view));
+ }
+
+
+ /*
+ * if the border is dirty too, then draw that
+ */
+ if (!rectinrect(tk->dirty, bufr)) {
+ r.min = addpt(r.min, rel);
+ r.min.x -= tk->borderwidth;
+ r.min.y -= tk->borderwidth;
+ tkdrawrelief(dst, tk, r.min, TkCbackgnd, tk->relief);
+ }
+ c->update = bbnil;
+ return nil;
+}
+
+void
+tkcvsappend(TkCanvas *c, TkCitem *i)
+{
+ if(c->head == nil)
+ c->head = i;
+ else
+ c->tail->next = i;
+ c->tail = i;
+}
+
+void
+tkcvssv(Tk *tk)
+{
+ TkCanvas *c;
+ int top, bot, height;
+ char val[Tkminitem], cmd[Tkmaxitem], *v, *e;
+
+ c = TKobj(TkCanvas, tk);
+ if(c->yscroll == nil)
+ return;
+
+ top = 0;
+ bot = TKI2F(1);
+
+ height = Dy(c->region);
+ if(height != 0) {
+ top = TKI2F(c->view.y)/height;
+ bot = TKI2F(c->view.y+tk->act.height)/height;
+ }
+
+ v = tkfprint(val, top);
+ *v++ = ' ';
+ tkfprint(v, bot);
+ snprint(cmd, sizeof(cmd), "%s %s", c->yscroll, val);
+ e = tkexec(tk->env->top, cmd, nil);
+ if ((e != nil) && (tk->name != nil))
+ print("tk: yscrollcommand \"%s\": %s\n", tk->name->name, e);
+}
+
+void
+tkcvssh(Tk *tk)
+{
+ int top, bot, width;
+ TkCanvas *c = TKobj(TkCanvas, tk);
+ char val[Tkminitem], cmd[Tkmaxitem], *v, *e;
+
+ if(c->xscroll == nil)
+ return;
+
+ top = 0;
+ bot = TKI2F(1);
+
+ width = Dx(c->region);
+ if(width != 0) {
+ top = TKI2F(c->view.x)/width;
+ bot = TKI2F(c->view.x+tk->act.width)/width;
+ }
+
+ v = tkfprint(val, top);
+ *v++ = ' ';
+ tkfprint(v, bot);
+ snprint(cmd, sizeof(cmd), "%s %s", c->xscroll, val);
+ e = tkexec(tk->env->top, cmd, nil);
+ if ((e != nil) && (tk->name != nil))
+ print("tk: xscrollcommand \"%s\": %s\n", tk->name->name, e);
+}
+
+static void
+tkcvsgeom(Tk *tk)
+{
+ TkCanvas *c;
+ c = TKobj(TkCanvas, tk);
+
+ tkcvsf2i(tk, c);
+ tk->dirty = tkrect(tk, 1);
+ c->update = c->region;
+
+ tkcvssv(tk);
+ tkcvssh(tk);
+}
+
+char*
+tkcvstags(Tk *tk, char *arg, char **val, int af)
+{
+ TkTop *o;
+ int x, y;
+ TkName *f;
+ TkCtag *t, *tt;
+ char *fmt;
+ TkCpoints p;
+ TkCanvas *c;
+ TkCitem *i, *b;
+ int d, dist, dx, dy;
+ char tag[Tkmaxitem], buf[Tkmaxitem];
+ char *e;
+
+ USED(val);
+
+ c = TKobj(TkCanvas, tk);
+
+ o = tk->env->top;
+ if(af == TkCadd) {
+ arg = tkword(o, arg, tag, tag+sizeof(tag), nil);
+ if(tag[0] == '\0' || (tag[0] >= '0' && tag[0] <= '9'))
+ return TkBadtg;
+ }
+
+ fmt = "%d";
+ arg = tkword(o, arg, buf, buf+sizeof(buf), nil);
+ if(strcmp(buf, "above") == 0) {
+ tkword(o, arg, buf, buf+sizeof(buf), nil);
+ f = tkctaglook(tk, nil, buf);
+ if(f == nil)
+ return TkBadtg;
+
+ t = tkclasttag(c->head, f->obj);
+ if(t == nil)
+ return TkBadtg;
+
+ for(i = t->item->next; i; i = i->next) {
+ if(af == TkCadd) {
+ i->tags = tkmkname(tag);
+ if(i->tags == nil)
+ return TkNomem;
+ tkcaddtag(tk, i, 0);
+ }
+ else {
+ e = tkvalue(val, fmt, i->id);
+ if(e != nil)
+ return e;
+ fmt = " %d";
+ }
+ }
+ return nil;
+ }
+
+ if(strcmp(buf, "all") == 0) {
+ for(i = c->head; i; i = i->next) {
+ if(af == TkCadd) {
+ i->tags = tkmkname(tag);
+ if(i->tags == nil)
+ return TkNomem;
+ tkcaddtag(tk, i, 0);
+ }
+ else {
+ e = tkvalue(val, fmt, i->id);
+ if(e != nil)
+ return e;
+ fmt = " %d";
+ }
+ }
+ return nil;
+ }
+
+ if(strcmp(buf, "below") == 0) {
+ tkword(o, arg, buf, buf+sizeof(buf), nil);
+ f = tkctaglook(tk, nil, buf);
+ if(f == nil)
+ return TkBadtg;
+ tt = f->obj;
+ for(b = c->head; b; b = b->next) {
+ for(t = tt; t; t = t->itemlist)
+ if(t->item == b)
+ goto found;
+ }
+ found:
+ for(i = c->head; i != b; i = i->next) {
+ if(af == TkCadd) {
+ i->tags = tkmkname(tag);
+ if(i->tags == nil)
+ return TkNomem;
+ tkcaddtag(tk, i, 0);
+ }
+ else {
+ e = tkvalue(val, fmt, i->id);
+ if(e != nil)
+ return e;
+ fmt = " %d";
+ }
+ }
+ return nil;
+ }
+
+ if(strcmp(buf, "closest") == 0) {
+ e = tkfracword(o, &arg, &x, nil);
+ if (e == nil)
+ e = tkfracword(o, &arg, &y, nil);
+ if (e != nil)
+ return e;
+ if(*arg != '\0')
+ return "!not implemented";
+
+ x = TKF2I(x);
+ y = TKF2I(y);
+ i = nil;
+ dist = 0;
+ for(b = c->head; b != nil; b = b->next) {
+ dx = x - (b->p.bb.min.x + Dx(b->p.bb)/2);
+ dy = y - (b->p.bb.min.y + Dy(b->p.bb)/2);
+ d = dx*dx + dy*dy;
+ if(d < dist || dist == 0) {
+ i = b;
+ dist = d;
+ }
+ }
+ if(i == nil)
+ return nil;
+
+ if(af == TkCadd) {
+ i->tags = tkmkname(tag);
+ if(i->tags == nil)
+ e = TkNomem;
+ else
+ tkcaddtag(tk, i, 0);
+ }
+ else
+ e = tkvalue(val, fmt, i->id);
+ return e;
+ }
+
+ if(strcmp(buf, "withtag") == 0) {
+ tkword(o, arg, buf, buf+sizeof(buf), nil);
+ f = tkctaglook(tk, nil, buf);
+ if(f == nil)
+ return TkBadtg;
+ for(t = f->obj; t; t = t->taglist) {
+ i = t->item;
+ if(af == TkCadd) {
+ i->tags = tkmkname(tag);
+ if(i->tags == nil)
+ return TkNomem;
+ tkcaddtag(tk, i, 0);
+ }
+ else {
+ e = tkvalue(val, fmt, i->id);
+ if(e != nil)
+ return e;
+ fmt = " %d";
+ }
+ }
+ return nil;
+ }
+
+ if(strcmp(buf, "enclosed") == 0) {
+ e = tkparsepts(o, &p, &arg, 0);
+ if(e != nil)
+ goto done;
+ if(p.npoint != 2) {
+ e = TkFewpt;
+ goto done;
+ }
+ for(i = c->head; i; i = i->next) {
+ if(rectinrect(i->p.bb, p.bb)) {
+ if(af == TkCadd) {
+ i->tags = tkmkname(tag);
+ if(i->tags == nil) {
+ e = TkNomem;
+ goto done;
+ }
+ tkcaddtag(tk, i, 0);
+ }
+ else {
+ e = tkvalue(val, fmt, i->id);
+ if(e != nil)
+ goto done;
+ fmt = " %d";
+ }
+ }
+ }
+ goto done;
+ }
+
+ if(strcmp(buf, "overlapping") == 0) {
+ e = tkparsepts(o, &p, &arg, 0);
+ if(e != nil)
+ goto done;
+ if(p.npoint != 2) {
+ e = TkFewpt;
+ goto done;
+ }
+ for(i = c->head; i; i = i->next) {
+ if(rectXrect(i->p.bb, p.bb)) {
+ if(af == TkCadd) {
+ i->tags = tkmkname(tag);
+ if(i->tags == nil) {
+ e = TkNomem;
+ goto done;
+ }
+ tkcaddtag(tk, i, 0);
+ }
+ else {
+ e = tkvalue(val, "%d ", i->id);
+ if(e != nil)
+ goto done;
+ }
+ }
+ }
+ goto done;
+ }
+
+ return TkBadcm;
+
+done: /* both no error and error do the same thing */
+ tkfreepoint(&p);
+ return e;
+}
+
+static char*
+tkcvsaddtag(Tk *tk, char *arg, char **val)
+{
+ return tkcvstags(tk, arg, val, TkCadd);
+}
+
+static char*
+tkcvsfind(Tk *tk, char *arg, char **val)
+{
+ return tkcvstags(tk, arg, val, TkCfind);
+}
+
+static void
+tksweepcanv(Tk *tk)
+{
+ int j, k;
+ TkCtag *t, *tt;
+ TkName **np, *n, *nn;
+ TkCitem *i;
+ TkCanvas *c;
+ TkAction *a;
+
+ c = TKobj(TkCanvas, tk);
+
+ for(j = 0; j < TkChash; j++)
+ for(n = c->thash[j]; n != nil; n = n->link)
+ n->ref = 0;
+
+ for(i = c->head; i != nil; i = i->next)
+ for(t = i->stag; t != nil; t = t->itemlist)
+ t->name->ref = 1;
+
+ k = 0;
+ for(j = 0; j < TkChash; j++) {
+ np = &c->thash[j];
+ for(n = *np; n != nil; n = nn) {
+ nn = n->link;
+ if(n->ref == 0) {
+ for(t = n->obj; t != nil; t = tt) {
+ tt = t->taglist;
+ free(t);
+ }
+ tkfreebind(n->prop.binds);
+ free(n);
+ *np = nn;
+ } else {
+ np = &n->link;
+ for(a = n->prop.binds; a != nil; a = a->link)
+ k++;
+ }
+ }
+ }
+
+ c->actions = k;
+ k = 3 * k / 2;
+ if (k < Tksweep)
+ c->actlim = Tksweep;
+ else
+ c->actlim = k;
+}
+
+/*
+ * extension to tcl/tk:
+ * grab set tag
+ * grab release tag
+ * grab ifunset tag
+ */
+static char*
+tkcvsgrab(Tk *tk, char *arg, char **val)
+{
+ TkCtag *t;
+ TkName *f;
+ TkCanvas *c;
+ char buf[Tkmaxitem];
+
+ c = TKobj(TkCanvas, tk);
+ arg = tkword(tk->env->top, arg, buf, buf+sizeof(buf), nil);
+ if (strcmp(buf, "status") == 0) {
+ if (c->grab != nil)
+ return tkvalue(val, "%d", c->grab->id);
+ }
+ else if (strcmp(buf, "release") == 0) {
+ c->grab = nil;
+ }
+ else if (strcmp(buf, "set") == 0 || strcmp(buf, "ifunset") == 0) {
+ if (buf[0] == 'i' && c->grab != nil)
+ return nil;
+ tkword(tk->env->top, arg, buf, buf + sizeof(buf), nil);
+
+ f = tkctaglook(tk, nil, buf);
+ if(f == nil || f->obj == nil)
+ return TkBadtg;
+
+ c = TKobj(TkCanvas, tk);
+ t = tkcfirsttag(c->head, f->obj);
+ if(t == nil)
+ return TkBadtg;
+ c->grab = t->item;
+ }
+ else
+ return TkBadvl;
+ return nil;
+}
+
+static char*
+tkcvsbind(Tk *tk, char *arg, char **val)
+{
+ Rune r;
+ TkCtag *t;
+ TkName *f;
+ TkAction *a;
+ TkCanvas *c;
+ int event, mode;
+ char *cmd, buf[Tkmaxitem];
+ char *e;
+
+ c = TKobj(TkCanvas, tk);
+ if (c->actions >= c->actlim)
+ tksweepcanv(tk);
+ arg = tkword(tk->env->top, arg, buf, buf+sizeof(buf), nil);
+
+ f = tkctaglook(tk, nil, buf);
+ if(f == nil) {
+ f = tkctaglook(tk, tkmkname(buf), buf);
+ if(f == nil)
+ return TkNomem;
+ }
+
+ arg = tkword(tk->env->top, arg, buf, buf+sizeof(buf), nil);
+ if(buf[0] == '<') {
+ event = tkseqparse(buf+1);
+ if(event == -1)
+ return TkBadsq;
+ }
+ else {
+ chartorune(&r, buf);
+ event = TkKey | r;
+ }
+ if(event == 0)
+ return TkBadsq;
+
+ arg = tkskip(arg, " \t");
+ if(*arg == '\0') {
+ for(t = f->obj; t; t = t->taglist) {
+ for(a = t->name->prop.binds; a; a = a->link)
+ if(event == a->event)
+ return tkvalue(val, "%s", a->arg);
+ for(a = t->name->prop.binds; a; a = a->link)
+ if(event & a->event)
+ return tkvalue(val, "%s", a->arg);
+ }
+ return nil;
+ }
+
+ mode = TkArepl;
+ if(*arg == '+') {
+ mode = TkAadd;
+ arg++;
+ }
+ else if(*arg == '-'){
+ mode = TkAsub;
+ arg++;
+ }
+
+ tkword(tk->env->top, arg, buf, buf+sizeof(buf), nil);
+ cmd = strdup(buf);
+ if(cmd == nil)
+ return TkNomem;
+ e = tkaction(&f->prop.binds, event, TkDynamic, cmd, mode);
+ if(e == nil)
+ c->actions++;
+ return e;
+}
+
+static char*
+tkcvscreate(Tk *tk, char *arg, char **val)
+{
+ TkCimeth *m;
+ char buf[Tkmaxitem];
+
+ arg = tkword(tk->env->top, arg, buf, buf+sizeof(buf), nil);
+ for(m = tkcimethod; m->name; m++)
+ if(strcmp(buf, m->name) == 0)
+ return m->create(tk, arg, val);
+
+ return TkBadit;
+}
+
+static char*
+tkcvsbbox(Tk *tk, char *arg, char **val)
+{
+ TkName *f;
+ TkCtag *t;
+ Rectangle bb;
+ char buf[Tkmaxitem];
+
+ bb = bbnil;
+ for(;;) {
+ arg = tkword(tk->env->top, arg, buf, buf+sizeof(buf), nil);
+ if(buf[0] == '\0')
+ break;
+ f = tkctaglook(tk, nil, buf);
+ if(f == nil)
+ return TkBadtg;
+ for(t = f->obj; t; t = t->taglist)
+ tkbbmax(&bb, &t->item->p.bb);
+ }
+ return tkvalue(val, "%d %d %d %d", bb.min.x, bb.min.y, bb.max.x, bb.max.y);
+}
+
+static char*
+tkcvscanvx(Tk *tk, char *arg, char **val)
+{
+ int x, s;
+ TkCanvas *c;
+ Point p;
+ char buf[Tkmaxitem];
+
+ c = TKobj(TkCanvas, tk);
+ arg = tkword(tk->env->top, arg, buf, buf+sizeof(buf), nil);
+ if(buf[0] == '\0')
+ return TkBadvl;
+
+ p = tkposn(tk);
+ x = atoi(buf) + c->view.x - (p.x + tk->borderwidth);
+
+ if(*arg) {
+ tkword(tk->env->top, arg, buf, buf+sizeof(buf), nil);
+ s = atoi(buf);
+ if (s) {
+ if (x>=0)
+ x = ((x+s/2)/s)*s;
+ else
+ x = ((x-s/2)/s)*s;
+ }
+ }
+ return tkvalue(val, "%d", x);
+}
+
+static char*
+tkcvscanvy(Tk *tk, char *arg, char **val)
+{
+ int y, s;
+ TkCanvas *c;
+ Point p;
+ char buf[Tkmaxitem];
+
+ c = TKobj(TkCanvas, tk);
+ arg = tkword(tk->env->top, arg, buf, buf+sizeof(buf), nil);
+ if(buf[0] == '\0')
+ return TkBadvl;
+
+ p = tkposn(tk);
+ y = atoi(buf) + c->view.y - (p.y + tk->borderwidth);
+
+ if(*arg) {
+ tkitem(buf, arg);
+ s = atoi(buf);
+ if (s) {
+ if (y>=0)
+ y = ((y+s/2)/s)*s;
+ else
+ y = ((y-s/2)/s)*s;
+ }
+ }
+ return tkvalue(val, "%d", y);
+}
+
+static char *
+tkcvsscreenx(Tk *tk, char *arg, char **val)
+{
+ int x;
+ TkCanvas *c;
+ Point p;
+ char buf[Tkmaxitem];
+
+ c = TKobj(TkCanvas, tk);
+ tkword(tk->env->top, arg, buf, buf+sizeof(buf), nil);
+ if(buf[0] == '\0')
+ return TkBadvl;
+ p = tkposn(tk);
+ x = atoi(buf) - c->view.x + (p.x + tk->borderwidth);
+ return tkvalue(val, "%d", x);
+}
+
+static char *
+tkcvsscreeny(Tk *tk, char *arg, char **val)
+{
+ int y;
+ TkCanvas *c;
+ Point p;
+ char buf[Tkmaxitem];
+
+ c = TKobj(TkCanvas, tk);
+ tkword(tk->env->top, arg, buf, buf+sizeof(buf), nil);
+ if(buf[0] == '\0')
+ return TkBadvl;
+ p = tkposn(tk);
+ y = atoi(buf) - c->view.y + (p.y + tk->borderwidth);
+ return tkvalue(val, "%d", y);
+}
+
+static char*
+tkcvscoords(Tk *tk, char *arg, char **val)
+{
+ int i;
+ Point *p;
+ TkCtag *t;
+ TkName *f;
+ TkCanvas *c;
+ TkCitem *item;
+ char *fmt, *e, *v, buf[Tkmaxitem];
+
+ arg = tkword(tk->env->top, arg, buf, buf+sizeof(buf), nil);
+ if(buf[0] == '\0')
+ return TkBadvl;
+
+ f = tkctaglook(tk, nil, buf);
+ if(f == nil || f->obj == nil)
+ return TkBadtg;
+
+ c = TKobj(TkCanvas, tk);
+
+ t = tkcfirsttag(c->head, f->obj);
+ if(t == nil)
+ return TkBadtg;
+
+ item = t->item;
+
+ if(*arg == '\0') {
+ fmt = "%s";
+ p = item->p.parampt;
+ for(i = 0; i < item->p.npoint; i++) {
+ v = tkfprint(buf, p->x);
+ *v++ = ' ';
+ tkfprint(v, p->y);
+ e = tkvalue(val, fmt, buf);
+ if(e != nil)
+ return e;
+ fmt = " %s";
+ p++;
+ }
+ return nil;
+ }
+
+ tkbbmax(&c->update, &item->p.bb);
+ e = tkcimethod[item->type].coord(item, arg, 0, 0);
+ tkbbmax(&c->update, &item->p.bb);
+ tkcvssetdirty(tk);
+ return e;
+}
+
+static char*
+tkcvsscale(Tk *tk, char *arg, char **val)
+{
+ TkName *f;
+ TkCtag *t;
+ TkCanvas *c;
+ TkCpoints pts;
+ TkCitem *item;
+ int j;
+ char *e, buf[Tkmaxitem];
+ Point *p, *d, origin, scalef;
+
+ USED(val);
+
+ c = TKobj(TkCanvas, tk);
+
+ arg = tkword(tk->env->top, arg, buf, buf+sizeof(buf), nil);
+ f = tkctaglook(tk, nil, buf);
+ if(f == nil || f->obj == nil)
+ return TkBadtg;
+
+ e = tkparsepts(tk->env->top, &pts, &arg, 0);
+ if(e != nil)
+ return e;
+ if(pts.npoint != 2) {
+ tkfreepoint(&pts);
+ return TkFewpt;
+ }
+ origin = pts.parampt[0];
+ scalef = pts.parampt[1];
+ tkfreepoint(&pts);
+ for(t = f->obj; t; t = t->taglist) {
+ item = t->item;
+ p = item->p.parampt;
+ d = item->p.drawpt;
+ for(j = 0; j < item->p.npoint; j++) {
+ p->x -= origin.x;
+ p->y -= origin.y;
+ p->x = TKF2I(p->x*scalef.x);
+ p->y = TKF2I(p->y*scalef.y);
+ p->x += origin.x;
+ p->y += origin.y;
+ d->x = TKF2I(p->x);
+ d->y = TKF2I(p->y);
+ d++;
+ p++;
+ }
+ tkbbmax(&c->update, &item->p.bb);
+ e = tkcimethod[item->type].coord(item, nil, 0, 0);
+ tkbbmax(&c->update, &item->p.bb);
+ if(e != nil)
+ return e;
+
+ tkcvssetdirty(tk);
+ }
+ return nil;
+}
+
+static char*
+tkcvsdtag(Tk *tk, char *arg, char **val)
+{
+ TkName *f, *dt;
+ char buf[Tkmaxitem];
+ TkCtag **l, *t, *it, *tf;
+
+ USED(val);
+
+ arg = tkword(tk->env->top, arg, buf, buf+sizeof(buf), nil);
+ f = tkctaglook(tk, nil, buf);
+ if(f == nil || f->obj == nil)
+ return TkBadtg;
+
+/*
+ XXX this code doesn't appear to work properly.
+ fix it later. for the moment, it's just a somewhat more
+ efficient substitute for the later code, so just use that
+ instead.
+
+ if(*arg == '\0') {
+ for(t = f->obj; t; t = tf) {
+ l = &t->item->stag;
+ for(it = *l; it; it = it->itemlist) {
+ if(it->item == t->item) {
+ *l = it->itemlist;
+ break;
+ }
+ l = &it->itemlist;
+ }
+
+ tf = t->taglist;
+ free(t);
+ }
+ f->obj = nil;
+ return nil;
+ }
+*/
+ if (*arg == '\0')
+ dt = f;
+ else {
+ tkword(tk->env->top, arg, buf, buf+sizeof(buf), nil);
+ dt = tkctaglook(tk, nil, buf);
+ if(dt == nil || dt->obj == nil)
+ return TkBadtg;
+ }
+
+ for(t = f->obj; t; t = t->taglist) {
+ l = (TkCtag **)&dt->obj;
+ for(it = dt->obj; it; it = it->taglist) {
+ if(t->item == it->item) {
+ *l = it->taglist;
+ l = &t->item->stag;
+ for(tf = *l; tf; tf = tf->itemlist) {
+ if(tf == it) {
+ *l = tf->itemlist;
+ break;
+ }
+ l = &tf->itemlist;
+ }
+ free(it);
+ break;
+ }
+ l = &it->taglist;
+ }
+ }
+ return nil;
+}
+
+static char*
+tkcvsdchars(Tk *tk, char *arg, char **val)
+{
+ TkCtag *t;
+ TkName *f;
+ char *e, buf[Tkmaxitem];
+
+ USED(val);
+
+ arg = tkword(tk->env->top, arg, buf, buf+sizeof(buf), nil);
+ f = tkctaglook(tk, nil, buf);
+ if(f == nil || f->obj == nil)
+ return TkBadtg;
+
+ for(t = f->obj; t; t = t->taglist) {
+ if(t->item->type == TkCVtext) {
+ e = tkcvstextdchar(tk, t->item, arg);
+ if(e != nil)
+ return e;
+ }
+ }
+
+ return nil;
+}
+
+static char*
+tkcvsindex(Tk *tk, char *arg, char **val)
+{
+ TkCtag *t;
+ TkName *f;
+ char *e, buf[Tkmaxitem];
+
+ USED(val);
+
+ arg = tkword(tk->env->top, arg, buf, buf+sizeof(buf), nil);
+ f = tkctaglook(tk, nil, buf);
+ if(f == nil || f->obj == nil)
+ return TkBadtg;
+
+ for(t = f->obj; t; t = t->taglist) {
+ if(t->item->type == TkCVtext) {
+ e = tkcvstextindex(tk, t->item, arg, val);
+ if(e != nil)
+ return e;
+ return nil;
+ }
+ }
+ return nil;
+}
+
+static char*
+tkcvsicursor(Tk *tk, char *arg, char **val)
+{
+ TkCtag *t;
+ TkName *f;
+ char *e, buf[Tkmaxitem];
+
+ USED(val);
+
+ arg = tkword(tk->env->top, arg, buf, buf+sizeof(buf), nil);
+ f = tkctaglook(tk, nil, buf);
+ if(f == nil || f->obj == nil)
+ return TkBadtg;
+
+ for(t = f->obj; t; t = t->taglist) {
+ if(t->item->type == TkCVtext) {
+ e = tkcvstexticursor(tk, t->item, arg);
+ if(e != nil)
+ return e;
+ return nil;
+ }
+ }
+ return nil;
+}
+
+static char*
+tkcvsinsert(Tk *tk, char *arg, char **val)
+{
+ TkCtag *t;
+ TkName *f;
+ char *e, buf[Tkmaxitem];
+
+ USED(val);
+
+ arg = tkword(tk->env->top, arg, buf, buf+sizeof(buf), nil);
+ f = tkctaglook(tk, nil, buf);
+ if(f == nil || f->obj == nil)
+ return TkBadtg;
+
+ for(t = f->obj; t; t = t->taglist) {
+ if(t->item->type == TkCVtext) {
+ e = tkcvstextinsert(tk, t->item, arg);
+ if(e != nil)
+ return e;
+ }
+ }
+
+ return nil;
+}
+
+static char*
+tkcvsselect(Tk *tk, char *arg, char **val)
+{
+ int op;
+ TkCtag *t;
+ TkName *f;
+ TkCanvas *c;
+ char buf[Tkmaxitem];
+
+ c = TKobj(TkCanvas, tk);
+
+ arg = tkword(tk->env->top, arg, buf, buf+sizeof(buf), nil);
+ if(strcmp(buf, "clear") == 0) {
+ tkcvstextclr(tk);
+ return nil;
+ }
+ if(strcmp(buf, "item") == 0) {
+ if(c->selection)
+ return tkvalue(val, "%d", c->selection->id);
+ return nil;
+ }
+
+ if(strcmp(buf, "to") == 0)
+ op = TkCselto;
+ else
+ if(strcmp(buf, "from") == 0)
+ op = TkCselfrom;
+ else
+ if(strcmp(buf, "adjust") == 0)
+ op = TkCseladjust;
+ else
+ return TkBadcm;
+
+ arg = tkword(tk->env->top, arg, buf, buf+sizeof(buf), nil);
+ f = tkctaglook(tk, nil, buf);
+ if(f == nil)
+ return TkBadtg;
+
+ t = tkcfirsttag(c->head, f->obj);
+ if(t == nil)
+ return TkBadtg;
+
+ return tkcvstextselect(tk, t->item, arg, op);
+}
+
+static char*
+tkcvsitemcget(Tk *tk, char *arg, char **val)
+{
+ TkName *f;
+ TkCtag *t;
+ TkCitem *i;
+ char buf[Tkmaxitem];
+
+ arg = tkword(tk->env->top, arg, buf, buf+sizeof(buf), nil);
+ f = tkctaglook(tk, nil, buf);
+ if(f == nil || f->obj == nil)
+ return TkBadtg;
+
+ for(i = TKobj(TkCanvas, tk)->head; i; i = i->next) {
+ for(t = f->obj; t; t = t->taglist)
+ if(i == t->item)
+ return tkcimethod[i->type].cget(i, arg, val);
+ }
+ return nil;
+}
+
+static char*
+tkcvsitemconf(Tk *tk, char *arg, char **val)
+{
+ char *e;
+ TkName *f;
+ TkCtag *t;
+ TkCitem *i;
+ TkCanvas *c;
+ char buf[Tkmaxitem];
+
+ USED(val);
+ arg = tkword(tk->env->top, arg, buf, buf+sizeof(buf), nil);
+ f = tkctaglook(tk, nil, buf);
+ if(f == nil || f->obj == nil)
+ return TkBadtg;
+
+ c = TKobj(TkCanvas, tk);
+ for(t = f->obj; t; t = t->taglist) {
+ for(i = c->head; i; i = i->next) {
+ if(i == t->item) {
+ tkbbmax(&c->update, &i->p.bb);
+ e = tkcimethod[i->type].conf(tk, i, arg);
+ tkbbmax(&c->update, &i->p.bb);
+ tkcvssetdirty(tk);
+ if(e != nil)
+ return e;
+ }
+ }
+ }
+ return nil;
+}
+
+static void
+tkcvsfreename(TkCanvas *c, TkName *n)
+{
+ ulong h;
+ char *p, *s;
+ TkName *f, **l;
+
+ /* just free implicit ones for now */
+ if(n == nil)
+ return;
+ s = n->name;
+ if(s == nil || (s[0] < '0' || s[0] > '9'))
+ return;
+ h = 0;
+ for(p = s; *p; p++)
+ h += 3*h + *p;
+ l = &c->thash[h%TkChash];
+ for(f = *l; f; l = &f->link, f = *l)
+ if(f == n){
+ *l = f->link;
+ tkfreebind(f->prop.binds);
+ free(f);
+ return;
+ }
+}
+
+static char*
+tkcvsdelete(Tk *tk, char *arg, char **val)
+{
+ TkName *f;
+ TkCanvas *c;
+ char buf[Tkmaxitem];
+ TkCitem *item, *prev, *i;
+ TkCtag *t, *inext, **l, *dit, *it;
+
+ USED(val);
+
+ c = TKobj(TkCanvas, tk);
+ for(;;) {
+ arg = tkword(tk->env->top, arg, buf, buf+sizeof(buf), nil);
+ if(buf[0] == '\0')
+ break;
+ f = tkctaglook(tk, nil, buf);
+ if(f == nil || f->obj == nil)
+ return nil;
+ while(f->obj) {
+ t = f->obj;
+ item = t->item;
+ for(it = item->stag; it; it = inext) {
+ inext = it->itemlist;
+ l = (TkCtag **)&it->name->obj;
+ for(dit = *l; dit; dit = dit->taglist) {
+ if(dit->item == item) {
+ *l = dit->taglist;
+ if(dit != t){
+ tkcvsfreename(c, dit->name);
+ free(dit);
+ }
+ break;
+ }
+ l = &dit->taglist;
+ }
+ }
+ tkbbmax(&c->update, &item->p.bb);
+ tkcvssetdirty(tk);
+ prev = nil;
+ for(i = c->head; i; i = i->next) {
+ if(i == item)
+ break;
+ prev = i;
+ }
+ if(prev == nil)
+ c->head = i->next;
+ else
+ prev->next = i->next;
+ if(c->tail == item)
+ c->tail = prev;
+ if(c->focus == item)
+ c->focus = nil;
+ if(c->mouse == item)
+ c->mouse = nil;
+ if(c->selection == item)
+ c->selection = nil;
+ if(c->curtag.item == item)
+ c->current->obj = nil;
+ if (c->grab == item)
+ c->grab = nil;
+
+ tkcvsfreeitem(item);
+ free(t);
+ }
+ }
+ return nil;
+}
+
+static char*
+tkcvsfocus(Tk *tk, char *arg, char **val)
+{
+ TkName *f;
+ TkCtag *t;
+ TkCanvas *c;
+ TkCitem *i, *focus;
+ char buf[Tkmaxitem];
+
+ c = TKobj(TkCanvas, tk);
+
+ if(*arg == '\0') {
+ if(c->focus == nil)
+ return nil;
+ return tkvalue(val, "%d", c->focus->id);
+ }
+
+ tkword(tk->env->top, arg, buf, buf+sizeof(buf), nil);
+ if(buf[0] == '\0')
+ return TkBadvl;
+ f = tkctaglook(tk, nil, buf);
+ if(f == nil || f->obj == nil)
+ return nil;
+
+ focus = c->focus;
+ if(focus != nil && focus->type == TkCVtext)
+ tkcvstextfocus(tk, focus, 0);
+
+ for(i = c->head; i; i = i->next) {
+ if(i->type == TkCVtext || i->type == TkCVwindow) {
+ for(t = f->obj; t; t = t->taglist)
+ if(t->item == i)
+ focus = i;
+ }
+ }
+
+ if(focus != nil && focus->type == TkCVtext)
+ tkcvstextfocus(tk, focus, 1);
+
+ c->focus = focus;
+ return nil;
+}
+
+static char*
+tkcvsgettags(Tk *tk, char *arg, char **val)
+{
+ TkCtag *t;
+ TkName *f;
+ TkCanvas *c;
+ char *fmt, *e, buf[Tkmaxitem];
+
+ tkword(tk->env->top, arg, buf, buf+sizeof(buf), nil);
+ if(buf[0] == '\0')
+ return TkBadvl;
+
+ f = tkctaglook(tk, nil, buf);
+ if(f == nil)
+ return TkBadtg;
+
+ c = TKobj(TkCanvas, tk);
+ t = tkclasttag(c->head, f->obj);
+ if(t == nil)
+ return TkBadtg;
+ fmt = "%s";
+ t = t->item->stag;
+ while(t) {
+ /* XXX when might t->name be legally nil? */
+ if (t->name != nil) {
+ if (strcmp(t->name->name, "all")) {
+ e = tkvalue(val, fmt, t->name->name);
+ if(e != nil)
+ return e;
+ fmt = " %s";
+ }
+ }
+ t = t->itemlist;
+ }
+ return nil;
+}
+
+static char*
+tkcvslower(Tk *tk, char *arg, char **val)
+{
+ TkCtag *t;
+ TkCanvas *c;
+ TkName *f, *b;
+ char buf[Tkmaxitem];
+ TkCitem *it, **l, **below, *items, **itemtail, *prev, *iprev;
+
+ USED(val);
+ c = TKobj(TkCanvas, tk);
+
+ arg = tkword(tk->env->top, arg, buf, buf+sizeof(buf), nil);
+ f = tkctaglook(tk, nil, buf);
+ if(f == nil || f->obj == nil)
+ return nil;
+
+ below = &c->head;
+ tkword(tk->env->top, arg, buf, buf+sizeof(buf), nil);
+ if(buf[0] != '\0') {
+ b = tkctaglook(tk, nil, buf);
+ if(b == nil || f->obj == nil)
+ return TkBadtg;
+ for(it = c->head; it; it = it->next) {
+ for(t = b->obj; t; t = t->taglist)
+ if(t->item == it)
+ goto found;
+ below = &it->next;
+ }
+ found:;
+ }
+ l = &c->head;
+ prev = iprev = nil;
+ itemtail = &items;;
+ for (it = *l; it != nil; it = *l) {
+ for (t = f->obj; t; t = t->taglist) {
+ if(t->item == it) {
+ if (it == *below || below == &it->next)
+ below = l;
+ if (it == c->tail)
+ c->tail = prev;
+ *l = it->next;
+ *itemtail = it;
+ iprev = it;
+ itemtail = &it->next;
+ tkbbmax(&c->update, &it->p.bb);
+ goto next;
+ }
+ }
+ prev = it;
+ l = &it->next;
+next:;
+ }
+ if (prev == nil)
+ c->tail = iprev;
+ *itemtail = *below;
+ *below = items;
+ tkcvssetdirty(tk);
+ return nil;
+}
+
+static char*
+tkcvsmove(Tk *tk, char *arg, char **val)
+{
+ TkCtag *t;
+ int fx, fy;
+ TkTop *top;
+ TkCpoints *p;
+ TkName *tag;
+ Rectangle *u;
+ TkCitem *item;
+ char *e;
+ char buf[Tkmaxitem];
+
+ USED(val);
+ top = tk->env->top;
+ arg = tkword(top, arg, buf, buf+sizeof(buf), nil);
+ tag = tkctaglook(tk, nil, buf);
+ if(tag == nil)
+ return nil;
+
+ e = tkfracword(top, &arg, &fx, nil);
+ if (e != nil)
+ return e;
+ e = tkfracword(top, &arg, &fy, nil);
+ if(e != nil)
+ return e;
+
+ u = &TKobj(TkCanvas, tk)->update;
+ for(t = tag->obj; t; t = t->taglist) {
+ item = t->item;
+ p = &item->p;
+ tkbbmax(u, &p->bb);
+ tkcimethod[item->type].coord(item, nil, fx, fy);
+ tkbbmax(u, &p->bb);
+ }
+ tkcvssetdirty(tk);
+ return nil;
+}
+
+static char*
+tkcvsraise(Tk *tk, char *arg, char **val)
+{
+ TkCtag *t;
+ TkCanvas *c;
+ TkName *f, *a;
+ char buf[Tkmaxitem];
+ TkCitem *prev, *it, *above, *items, *itemtail, *next;
+
+ USED(val);
+ c = TKobj(TkCanvas, tk);
+
+ arg = tkword(tk->env->top, arg, buf, buf+sizeof(buf), nil);
+ f = tkctaglook(tk, nil, buf);
+ if(f == nil)
+ return nil;
+
+ above = c->tail;
+ tkword(tk->env->top, arg, buf, buf+sizeof(buf), nil);
+ if(buf[0] != '\0') {
+ a = tkctaglook(tk, nil, buf);
+ if(a == nil)
+ return TkBadtg;
+ /*
+ * find topmost item in the display list matching the "above" tag
+ */
+ for(it = c->head; it != nil; it = it->next) {
+ for(t = a->obj; t; t = t->taglist)
+ if(t->item == it)
+ above = it;
+ }
+ }
+ prev = nil;
+ items = itemtail = nil;
+ for (it = c->head; it != nil; it = next) {
+ next = it->next;
+ for (t = f->obj; t; t = t->taglist) {
+ if(t->item == it) {
+ if (it == above)
+ above = next;
+ if (prev)
+ prev->next = next;
+ else
+ c->head = next;
+ if (itemtail)
+ itemtail->next = it;
+ else
+ items = it;
+ itemtail = it;
+ tkbbmax(&c->update, &it->p.bb);
+ goto next;
+ }
+ }
+ prev = it;
+next:;
+ }
+ if (items != nil) {
+ if (above) {
+ itemtail->next = above->next;
+ if (above->next == nil)
+ c->tail = itemtail;
+ above->next = items;
+ } else {
+ if (prev)
+ prev->next = items;
+ else
+ c->head = items;
+ c->tail = itemtail;
+ itemtail->next = nil;
+ }
+ }
+
+ tkcvssetdirty(tk);
+ return nil;
+}
+
+static char*
+tkcvstype(Tk *tk, char *arg, char **val)
+{
+ TkCtag *t;
+ TkName *f;
+ TkCanvas *c;
+ char buf[Tkmaxitem];
+
+ tkword(tk->env->top, arg, buf, buf+sizeof(buf), nil);
+ if(buf[0] == '\0')
+ return TkBadvl;
+
+ f = tkctaglook(tk, nil, buf);
+ if(f == nil || f->obj == nil)
+ return nil;
+
+ c = TKobj(TkCanvas, tk);
+
+ t = tkcfirsttag(c->head, f->obj);
+ if(t == nil)
+ return nil;
+
+ return tkvalue(val, "%s", tkcimethod[t->item->type].name);
+}
+
+static char*
+tkcvsview(Tk *tk, char *arg, char **val, int nl, int *posn, int min, int max, int inc)
+{
+ TkTop *t;
+ int top, bot, diff, amount;
+ char *e;
+ char buf[Tkmaxitem], *v;
+
+ diff = max-min;
+ if(*arg == '\0') {
+ if ( diff == 0 )
+ top = bot = 0;
+ else {
+ top = TKI2F(*posn-min)/diff;
+ bot = TKI2F(*posn+nl-min)/diff;
+ }
+ v = tkfprint(buf, top);
+ *v++ = ' ';
+ tkfprint(v, bot);
+ return tkvalue(val, "%s", buf);
+ }
+
+ t = tk->env->top;
+ arg = tkword(t, arg, buf, buf+sizeof(buf), nil);
+ if(strcmp(buf, "moveto") == 0) {
+ e = tkfrac(&arg, &top, nil);
+ if (e != nil)
+ return e;
+ *posn = min + TKF2I((top+1)*diff);
+ }
+ else
+ if(strcmp(buf, "scroll") == 0) {
+ arg = tkword(t, arg, buf, buf+sizeof(buf), nil);
+ amount = atoi(buf);
+ tkword(t, arg, buf, buf+sizeof(buf), nil);
+ if(buf[0] == 'p') /* Pages */
+ amount = amount * nl * 9 /10;
+ else if (inc > 0)
+ amount *= inc;
+ else
+ amount = amount * nl / 10;
+ *posn += amount;
+ }
+ else
+ return TkBadcm;
+
+ bot = max - nl;
+ if(*posn > bot)
+ *posn = bot;
+ if(*posn < min)
+ *posn = min;
+
+ tk->dirty = tkrect(tk, 0);
+ return nil;
+}
+
+static char*
+tkcvsyview(Tk *tk, char *arg, char **val)
+{
+ int si;
+ char *e;
+ TkCanvas *c = TKobj(TkCanvas, tk);
+
+ si = TKF2I(c->yscrolli);
+ e = tkcvsview(tk, arg, val, tk->act.height, &c->view.y, c->region.min.y, c->region.max.y, si);
+ tkcvssv(tk);
+ return e;
+}
+
+static char*
+tkcvsxview(Tk *tk, char *arg, char **val)
+{
+ int si;
+ char *e;
+ TkCanvas *c = TKobj(TkCanvas, tk);
+
+ si = TKF2I(c->xscrolli);
+ e = tkcvsview(tk, arg, val, tk->act.width, &c->view.x, c->region.min.x, c->region.max.x, si);
+ tkcvssh(tk);
+ return e;
+}
+
+/*
+ * return in posn the new view origin such that (preferably) smin and smax
+ * lie between cmin and cmax (cmin is the current view origin, and cmax the
+ * other end of the visible area).
+ * adjust posn (the view origin) so that (preferably) both smin and smax lie
+ * inside cmin to cmax. if both smin and smax cannot fit, then
+ * at least make sure that spref (smin<=spref<=smax) is visible.
+ * return 0 if no adjustment is required (the interval is already visible).
+ *
+ * attempt to make an adjustment as small as possible that
+ * fits these criteria.
+ */
+static int
+tkadjustvis(int *posn, int c0, int c1, int s0, int s1, int spref)
+{
+ int d, v;
+
+ d = c1 - c0; /* visible width */
+
+ /*
+ * if requested range fits inside visible range,
+ * no adjustment is necessary
+ */
+ if (c0 <= s0 && s1 <= c1)
+ return 0;
+
+ /*
+ * if requested range fits, make it fully visible
+ */
+ if (s1 - s0 < d) {
+ if (s0 < c0)
+ v = s0;
+ else
+ v = s1 - d;
+ } else {
+ /*
+ * choose upper or lower end of requested range,
+ * depending on which end of requested area is already
+ * visible (if any).
+ */
+ if (c0 <= s1 && s1 < c1) { /* overlapping left of visible */
+ v = s1 - d;
+ if (v > spref)
+ v = spref;
+ }
+ else
+ if (c0 <= s0 && s0 < c1) { /* overlapping right of visible */
+ v = s0;
+ if (v + d <= spref)
+ v = spref - d;
+ }
+ else
+ if (s1 < c0) { /* left of visible */
+ v = spref;
+ if (v + d > s1)
+ v = s1 - d;
+ }
+ else { /* right of visible */
+ v = spref - d;
+ if (v < s0)
+ v = s0;
+ }
+ }
+ *posn = v;
+ return 1;
+}
+
+static void
+tkcvsseerect(Tk *tk, Rectangle r, Point p)
+{
+ TkCanvas *c;
+ int scrollh, scrollv;
+
+ c = TKobj(TkCanvas, tk);
+
+ scrollh = tkadjustvis(&c->view.x, c->view.x, c->view.x + tk->act.width,
+ r.min.x, r.max.x, p.x);
+ scrollv = tkadjustvis(&c->view.y, c->view.y, c->view.y + tk->act.height,
+ r.min.y, r.max.y, p.y);
+ if (scrollh)
+ tkcvssh(tk);
+ if (scrollv)
+ tkcvssv(tk);
+ if (scrollh || scrollv)
+ tk->dirty = tkrect(tk, 0);
+}
+
+static char*
+tkcvssee(Tk *tk, char *arg, char **val)
+{
+ Rectangle r;
+ int n, coords[4];
+ char *e;
+
+ USED(val);
+ n = 0;
+ while (n < 4) {
+ if (*arg == '\0')
+ break;
+ e = tkfracword(tk->env->top, &arg, &coords[n++], nil);
+ if (e != nil)
+ return e;
+ }
+
+ if (n != 2 && n != 4)
+ return TkFewpt;
+
+ r.min.x = TKF2I(coords[0]);
+ r.min.y = TKF2I(coords[1]);
+ if (n == 4) {
+ r.max.x = TKF2I(coords[2]);
+ r.max.y = TKF2I(coords[3]);
+ } else
+ r.max = r.min;
+ r = canonrect(r);
+ /*
+ * XXX should intersect r with scrollregion here, as you shouldn't
+ * be able to display things outside the scroll region. (??)
+ */
+
+ tkcvsseerect(tk, r, r.min);
+ return nil;
+}
+
+static void
+tkcvsseesub(Tk *tk, Rectangle *rr, Point *pp)
+{
+ Rectangle r;
+ Point p;
+ TkCanvas *c;
+ c = TKobj(TkCanvas, tk);
+
+ r = rectaddpt(*rr, c->view);
+ p = addpt(*pp, c->view);
+
+ tkcvsseerect(tk, r, p);
+
+ *rr = rectsubpt(r, c->view);
+ *pp = subpt(p, c->view);
+}
+
+static void
+tkcvsgetimgs(Tk* tk, Image **image, Image **mask)
+{
+ TkCanvas *c;
+ c = TKobj(TkCanvas, tk);
+
+ *image = c->image;
+ *mask = c->mask; /* XXX this is wrong - the mask image has nothing to do with the main image */
+}
+
+TkCimeth tkcimethod[] =
+{
+ "line", tkcvslinecreat,
+ tkcvslinedraw,
+ tkcvslinefree,
+ tkcvslinecoord,
+ tkcvslinecget,
+ tkcvslineconf,
+ tkcvslinehit,
+
+ "text", tkcvstextcreat,
+ tkcvstextdraw,
+ tkcvstextfree,
+ tkcvstextcoord,
+ tkcvstextcget,
+ tkcvstextconf,
+ nil,
+
+ "rectangle", tkcvsrectcreat,
+ tkcvsrectdraw,
+ tkcvsrectfree,
+ tkcvsrectcoord,
+ tkcvsrectcget,
+ tkcvsrectconf,
+ nil,
+
+ "oval", tkcvsovalcreat,
+ tkcvsovaldraw,
+ tkcvsovalfree,
+ tkcvsovalcoord,
+ tkcvsovalcget,
+ tkcvsovalconf,
+ tkcvsovalhit,
+
+ "bitmap", tkcvsbitcreat,
+ tkcvsbitdraw,
+ tkcvsbitfree,
+ tkcvsbitcoord,
+ tkcvsbitcget,
+ tkcvsbitconf,
+ nil,
+
+ "polygon", tkcvspolycreat,
+ tkcvspolydraw,
+ tkcvspolyfree,
+ tkcvspolycoord,
+ tkcvspolycget,
+ tkcvspolyconf,
+ tkcvspolyhit,
+
+ "window", tkcvswindcreat,
+ tkcvswinddraw,
+ tkcvswindfree,
+ tkcvswindcoord,
+ tkcvswindcget,
+ tkcvswindconf,
+ nil,
+
+ "image", tkcvsimgcreat,
+ tkcvsimgdraw,
+ tkcvsimgfree,
+ tkcvsimgcoord,
+ tkcvsimgcget,
+ tkcvsimgconf,
+ nil,
+
+ "arc", tkcvsarccreat,
+ tkcvsarcdraw,
+ tkcvsarcfree,
+ tkcvsarccoord,
+ tkcvsarccget,
+ tkcvsarcconf,
+ nil,
+ nil
+};
+
+static
+TkCmdtab tkcanvcmd[] =
+{
+ "addtag", tkcvsaddtag,
+ "bbox", tkcvsbbox,
+ "bind", tkcvsbind,
+ "cget", tkcvscget,
+ "configure", tkcvsconf,
+ "create", tkcvscreate,
+ "canvasx", tkcvscanvx,
+ "canvasy", tkcvscanvy,
+ "coords", tkcvscoords,
+ "dchars", tkcvsdchars,
+ "delete", tkcvsdelete,
+ "dtag", tkcvsdtag,
+ "find", tkcvsfind,
+ "focus", tkcvsfocus,
+ "gettags", tkcvsgettags,
+ "grab", tkcvsgrab,
+ "icursor", tkcvsicursor,
+ "insert", tkcvsinsert,
+ "index", tkcvsindex,
+ "itemcget", tkcvsitemcget,
+ "itemconfigure", tkcvsitemconf,
+ "lower", tkcvslower,
+ "move", tkcvsmove,
+ "raise", tkcvsraise,
+ "screenx", tkcvsscreenx,
+ "screeny", tkcvsscreeny,
+ "see", tkcvssee,
+ "select", tkcvsselect,
+ "scale", tkcvsscale,
+ "type", tkcvstype,
+ "yview", tkcvsyview,
+ "xview", tkcvsxview,
+ nil
+};
+
+TkMethod canvasmethod = {
+ "canvas",
+ tkcanvcmd,
+ tkfreecanv,
+ tkdrawcanv,
+ tkcvsgeom,
+ tkcvsgetimgs,
+ tkcvsfocusorder,
+ tkcvsdirty,
+ tkcvsrelpos,
+ tkcvsevent,
+ tkcvsseesub,
+ tkcvsinwindow,
+ nil,
+ tkcvsforgetsub,
+};
--- /dev/null
+++ b/libtk/canvs.h
@@ -1,0 +1,240 @@
+typedef struct TkCimeth TkCimeth;
+typedef struct TkCitem TkCitem;
+typedef struct TkCanvas TkCanvas;
+typedef struct TkCline TkCline;
+typedef struct TkCtag TkCtag;
+typedef struct TkCpoints TkCpoints;
+typedef struct TkCwind TkCwind;
+
+struct TkCline
+{
+ int arrow;
+ int shape[3];
+ int width;
+ Image* stipple;
+ Image* pen;
+ int arrowf;
+ int arrowl;
+ int capstyle;
+ int smooth;
+ int steps;
+};
+
+struct TkCwind
+{
+ Tk* sub; /* Subwindow of canvas */
+ Tk* focus; /* Current Mouse focus */
+ int width; /* Requested width */
+ int height; /* Requested height */
+ int flags; /* possible: Tkanchor|Tksetwidth|Tksetheight */
+};
+
+struct TkCpoints
+{
+ int npoint; /* Number of points */
+ Point* parampt; /* Parameters in fixed point */
+ Point* drawpt; /* Draw coord in pixels */
+ Rectangle bb; /* Bounding box in pixels */
+};
+
+struct TkCitem
+{
+ int id; /* Unique id */
+ int type; /* Object type */
+ TkCpoints p; /* Points plus bounding box */
+ TkEnv* env; /* Colors & fonts */
+ TkCitem* next; /* Z order */
+ TkName* tags; /* Temporary tag spot */
+ TkCtag* stag; /* Real tag structure */
+// char obj[TKSTRUCTALIGN];
+};
+
+struct TkCtag
+{
+ TkCitem* item; /* Link to item */
+ TkName* name; /* Text name or id */
+ TkCtag* taglist; /* link items with this tag */
+ TkCtag* itemlist; /* link tags for this item */
+};
+
+enum
+{
+ /* Item types */
+ TkCVline,
+ TkCVtext,
+ TkCVrect,
+ TkCVoval,
+ TkCVbitmap,
+ TkCVpoly,
+ TkCVwindow,
+ TkCVimage,
+ TkCVarc,
+
+ TkCselto = 0,
+ TkCselfrom,
+ TkCseladjust,
+
+ TkCbufauto = 0,
+ TkCbufnone,
+ TkCbufvisible,
+ TkCbufall,
+
+ TkCadd = 0,
+ TkCfind,
+
+ TkChash = 32,
+
+ TkCarrowf = (1<<0),
+ TkCarrowl = (1<<1),
+ Tknarrow = 6 /* Number of points in arrow */
+};
+
+struct TkCanvas
+{
+ int close;
+ int confine;
+ int cleanup;
+ int scrollr[4];
+ Rectangle region;
+ Rectangle update; /* Area to paint next draw */
+ Point view;
+ TkCitem* selection;
+ int width;
+ int height;
+ int sborderwidth;
+ int xscrolli; /* Scroll increment */
+ int yscrolli;
+ char* xscroll; /* Scroll commands */
+ char* yscroll;
+ int id; /* Unique id */
+ TkCitem* head; /* Items in Z order */
+ TkCitem* tail; /* Head is lowest, tail is highest */
+ TkCitem* focus; /* Keyboard focus */
+ TkCitem* mouse; /* Mouse focus */
+ TkCitem* grab;
+ TkName* current; /* Fake for current tag */
+ TkCtag curtag;
+ Image* image; /* Drawing space */
+ int ialloc; /* image was allocated by us? */
+ Image* mask; /* mask space (for stippling) */
+ TkName* thash[TkChash]; /* Tag hash */
+ int actions;
+ int actlim;
+ int buffer;
+};
+
+struct TkCimeth
+{
+ char* name;
+ char* (*create)(Tk*, char *arg, char **val);
+ void (*draw)(Image*, TkCitem*, TkEnv*);
+ void (*free)(TkCitem*);
+ char* (*coord)(TkCitem*, char*, int, int);
+ char* (*cget)(TkCitem*, char*, char**);
+ char* (*conf)(Tk*, TkCitem*, char*);
+ int (*hit)(TkCitem*, Point);
+};
+
+extern TkCimeth tkcimethod[];
+extern int cvslshape[];
+extern Rectangle bbnil;
+extern Rectangle huger;
+
+/* General */
+extern char* tkcaddtag(Tk*, TkCitem*, int);
+extern TkCtag* tkcfirsttag(TkCitem*, TkCtag*);
+extern TkCtag* tkclasttag(TkCitem*, TkCtag*);
+extern void tkcvsappend(TkCanvas*, TkCitem*);
+extern TkCitem* tkcnewitem(Tk*, int, int);
+extern void tkcvsfreeitem(TkCitem*);
+extern Point tkcvsrelpos(Tk*);
+extern Tk* tkcvsinwindow(Tk*, Point*);
+extern char* tkcvstextdchar(Tk*, TkCitem*, char*);
+extern char* tkcvstextindex(Tk*, TkCitem*, char*, char **val);
+extern char* tkcvstextinsert(Tk*, TkCitem*, char*);
+extern char* tkcvstexticursor(Tk*, TkCitem*, char*);
+extern void tkmkpen(Image**, TkEnv*, Image*);
+extern void tkcvstextfocus(Tk*, TkCitem*, int);
+extern char* tkcvstextselect(Tk*, TkCitem*, char*, int);
+extern void tkcvstextclr(Tk*);
+extern Tk* tkcvsevent(Tk*, int, void*);
+extern Point tkcvsanchor(Point, int, int, int);
+extern void tkcvsdirty(Tk*);
+extern void tkfreectag(TkCtag*);
+extern char* tkparsepts(TkTop*, TkCpoints*, char**, int);
+extern void tkfreepoint(TkCpoints*);
+extern void tkxlatepts(Point*, int, int, int);
+extern void tkpolybound(Point*, int, Rectangle*);
+extern TkName* tkctaglook(Tk*, TkName*, char*);
+extern void tkbbmax(Rectangle*, Rectangle*);
+extern void tkcvssetdirty(Tk*);
+
+/* Canvas Item methods - required to populate tkcimethod in canvs.c */
+extern char* tkcvslinecreat(Tk*, char *arg, char **val);
+extern void tkcvslinedraw(Image*, TkCitem*, TkEnv*);
+extern void tkcvslinefree(TkCitem*);
+extern char* tkcvslinecoord(TkCitem*, char*, int, int);
+extern char* tkcvslinecget(TkCitem*, char*, char**);
+extern char* tkcvslineconf(Tk*, TkCitem*, char*);
+extern int tkcvslinehit(TkCitem*, Point);
+
+extern char* tkcvstextcreat(Tk*, char *arg, char **val);
+extern void tkcvstextdraw(Image*, TkCitem*, TkEnv*);
+extern void tkcvstextfree(TkCitem*);
+extern char* tkcvstextcoord(TkCitem*, char*, int, int);
+extern char* tkcvstextcget(TkCitem*, char*, char**);
+extern char* tkcvstextconf(Tk*, TkCitem*, char*);
+
+extern char* tkcvsrectcreat(Tk*, char *arg, char **val);
+extern void tkcvsrectdraw(Image*, TkCitem*, TkEnv*);
+extern void tkcvsrectfree(TkCitem*);
+extern char* tkcvsrectcoord(TkCitem*, char*, int, int);
+extern char* tkcvsrectcget(TkCitem*, char*, char**);
+extern char* tkcvsrectconf(Tk*, TkCitem*, char*);
+
+extern char* tkcvsovalcreat(Tk*, char *arg, char **val);
+extern void tkcvsovaldraw(Image*, TkCitem*, TkEnv*);
+extern void tkcvsovalfree(TkCitem*);
+extern char* tkcvsovalcoord(TkCitem*, char*, int, int);
+extern char* tkcvsovalcget(TkCitem*, char*, char**);
+extern char* tkcvsovalconf(Tk*, TkCitem*, char*);
+extern int tkcvsovalhit(TkCitem*, Point);
+
+extern char* tkcvsarccreat(Tk*, char *arg, char **val);
+extern void tkcvsarcdraw(Image*, TkCitem*, TkEnv*);
+extern void tkcvsarcfree(TkCitem*);
+extern char* tkcvsarccoord(TkCitem*, char*, int, int);
+extern char* tkcvsarccget(TkCitem*, char*, char**);
+extern char* tkcvsarcconf(Tk*, TkCitem*, char*);
+
+extern char* tkcvsbitcreat(Tk*, char *arg, char **val);
+extern void tkcvsbitdraw(Image*, TkCitem*, TkEnv*);
+extern void tkcvsbitfree(TkCitem*);
+extern char* tkcvsbitcoord(TkCitem*, char*, int, int);
+extern char* tkcvsbitcget(TkCitem*, char*, char**);
+extern char* tkcvsbitconf(Tk*, TkCitem*, char*);
+
+extern char* tkcvswindcreat(Tk*, char *arg, char **val);
+extern void tkcvswinddraw(Image*, TkCitem*, TkEnv*);
+extern void tkcvswindfree(TkCitem*);
+extern char* tkcvswindcoord(TkCitem*, char*, int, int);
+extern char* tkcvswindcget(TkCitem*, char*, char**);
+extern char* tkcvswindconf(Tk*, TkCitem*, char*);
+
+extern char* tkcvspolycreat(Tk*, char *arg, char **val);
+extern void tkcvspolydraw(Image*, TkCitem*, TkEnv*);
+extern void tkcvspolyfree(TkCitem*);
+extern char* tkcvspolycoord(TkCitem*, char*, int, int);
+extern char* tkcvspolycget(TkCitem*, char*, char**);
+extern char* tkcvspolyconf(Tk*, TkCitem*, char*);
+extern int tkcvspolyhit(TkCitem*, Point);
+
+extern char* tkcvsimgcreat(Tk*, char *arg, char **val);
+extern void tkcvsimgdraw(Image*, TkCitem*, TkEnv*);
+extern void tkcvsimgfree(TkCitem*);
+extern char* tkcvsimgcoord(TkCitem*, char*, int, int);
+extern char* tkcvsimgcget(TkCitem*, char*, char**);
+extern char* tkcvsimgconf(Tk*, TkCitem*, char*);
+
+extern TkCitem* tkcvsfindwin(Tk*);
+extern void tkcvsforgetsub(Tk*, Tk*);
--- /dev/null
+++ b/libtk/canvu.c
@@ -1,0 +1,540 @@
+#include <lib9.h>
+#include <kernel.h>
+#include "draw.h"
+#include "tk.h"
+#include "canvs.h"
+
+char*
+tkparsepts(TkTop *t, TkCpoints *i, char **arg, int close)
+{
+ char *s, *e;
+ Point *p, *d;
+ int n, npoint;
+
+ i->parampt = nil;
+ i->drawpt = nil;
+ i->bb = bbnil;
+ s = *arg;
+ npoint = 0;
+ while(*s) {
+ s = tkskip(s, " \t");
+ if(*s == '-' && (s[1] < '0' || s[1] > '9'))
+ break;
+ while(*s && *s != ' ' && *s != '\t')
+ s++;
+ npoint++;
+ }
+
+ i->parampt = mallocz(npoint*sizeof(Point), 0);
+ if(i->parampt == nil)
+ return TkNomem;
+
+ s = *arg;
+ p = i->parampt;
+ npoint = 0;
+ while(*s) {
+ e = tkfracword(t, &s, &p->x, nil);
+ if(e != nil)
+ goto Error;
+ e = tkfracword(t, &s, &p->y, nil);
+ if(e != nil)
+ goto Error;
+ npoint++;
+ s = tkskip(s, " \t");
+ if(*s == '-' && (s[1] < '0' || s[1] > '9'))
+ break;
+ p++;
+ }
+ *arg = s;
+ close = (close != 0);
+ i->drawpt = mallocz((npoint+close)*sizeof(Point), 0);
+ if(i->drawpt == nil){
+ e = TkNomem;
+ goto Error;
+ }
+
+ d = i->drawpt;
+ p = i->parampt;
+ for(n = 0; n < npoint; n++) {
+ d->x = TKF2I(p->x);
+ d->y = TKF2I(p->y);
+ if(d->x < i->bb.min.x)
+ i->bb.min.x = d->x;
+ if(d->x > i->bb.max.x)
+ i->bb.max.x = d->x;
+ if(d->y < i->bb.min.y)
+ i->bb.min.y = d->y;
+ if(d->y > i->bb.max.y)
+ i->bb.max.y = d->y;
+ d++;
+ p++;
+ }
+ if (close)
+ *d = i->drawpt[0];
+
+ i->npoint = npoint;
+ return nil;
+
+Error:
+ tkfreepoint(i);
+ i->parampt = nil;
+ i->drawpt = nil;
+ return e;
+}
+
+TkCitem*
+tkcnewitem(Tk *tk, int t, int n)
+{
+ TkCitem *i;
+
+ i = malloc(n);
+ if(i == nil)
+ return nil;
+ memset(i, 0, n);
+
+ i->type = t;
+ i->env = tk->env;
+ i->env->ref++;
+
+ return i;
+}
+
+/*
+ * expand the canvas's dirty rectangle, clipping
+ * appropriately to its boundaries.
+ */
+void
+tkcvssetdirty(Tk *tk)
+{
+ TkCanvas *c;
+ Rectangle r;
+ c = TKobj(TkCanvas, tk);
+
+ r = tkrect(tk, 0);
+ if (rectclip(&r, rectsubpt(c->update, c->view)))
+ combinerect(&tk->dirty, r);
+}
+
+void
+tkxlatepts(Point *p, int npoints, int x, int y)
+{
+ while(npoints--) {
+ p->x += x;
+ p->y += y;
+ p++;
+ }
+}
+
+void
+tkbbmax(Rectangle *bb, Rectangle *r)
+{
+ if(r->min.x < bb->min.x)
+ bb->min.x = r->min.x;
+ if(r->min.y < bb->min.y)
+ bb->min.y = r->min.y;
+ if(r->max.x > bb->max.x)
+ bb->max.x = r->max.x;
+ if(r->max.y > bb->max.y)
+ bb->max.y = r->max.y;
+}
+
+void
+tkpolybound(Point *p, int n, Rectangle *r)
+{
+ while(n--) {
+ if(p->x < r->min.x)
+ r->min.x = p->x;
+ if(p->y < r->min.y)
+ r->min.y = p->y;
+ if(p->x > r->max.x)
+ r->max.x = p->x;
+ if(p->y > r->max.y)
+ r->max.y = p->y;
+ p++;
+ }
+}
+
+/*
+ * look up a tag for a canvas item.
+ * if n is non-nil, and the tag isn't found,
+ * then add it to the canvas's taglist.
+ * NB if there are no binds done on the
+ * canvas, these tags never get cleared out,
+ * even if nothing refers to them.
+ */
+TkName*
+tkctaglook(Tk* tk, TkName *n, char *name)
+{
+ ulong h;
+ TkCanvas *c;
+ char *p, *s;
+ TkName *f, **l;
+
+ c = TKobj(TkCanvas, tk);
+
+ s = name;
+ if(s == nil)
+ s = n->name;
+
+ if(strcmp(s, "current") == 0)
+ return c->current;
+
+ h = 0;
+ for(p = s; *p; p++)
+ h += 3*h + *p;
+
+ l = &c->thash[h%TkChash];
+ for(f = *l; f; f = f->link)
+ if(strcmp(f->name, s) == 0)
+ return f;
+
+ if(n == nil)
+ return nil;
+ n->link = *l;
+ *l = n;
+ return n;
+}
+
+char*
+tkcaddtag(Tk *tk, TkCitem *i, int new)
+{
+ TkCtag *t;
+ TkCanvas *c;
+ char buf[16];
+ TkName *n, *f, *link;
+
+ c = TKobj(TkCanvas, tk);
+ if(new != 0) {
+ i->id = ++c->id;
+ snprint(buf, sizeof(buf), "%d", i->id);
+ n = tkmkname(buf);
+ if(n == nil)
+ return TkNomem;
+ n->link = i->tags;
+ i->tags = n;
+ }
+
+ for(n = i->tags; n; n = link) {
+ link = n->link;
+ f = tkctaglook(tk, n, nil);
+ if(n != f)
+ free(n);
+
+ for(t = i->stag; t; t = t->itemlist)
+ if(t->name == f)
+ break;
+ if(t == nil) {
+ t = malloc(sizeof(TkCtag));
+ if(t == nil) {
+ tkfreename(link);
+ return TkNomem;
+ }
+ t->name = f;
+ t->taglist = f->obj; /* add to head of items with this tag */
+ f->obj = t;
+ t->item = i;
+ t->itemlist = i->stag; /* add to head of tags for this item */
+ i->stag = t;
+ }
+ }
+ i->tags = nil;
+
+ if(new != 0) {
+ i->tags = tkmkname("all");
+ if(i->tags == nil)
+ return TkNomem; /* XXX - Tad: memory leak? */
+ return tkcaddtag(tk, i, 0);
+ }
+
+ return nil;
+}
+
+void
+tkfreepoint(TkCpoints *p)
+{
+ free(p->drawpt);
+ free(p->parampt);
+}
+
+/*
+ * of all the items in ilist tagged with tag,
+ * return that tag for the first (topmost) item.
+ */
+TkCtag*
+tkclasttag(TkCitem *ilist, TkCtag* tag)
+{
+ TkCtag *last, *t;
+
+ if (tag == nil || tag->taglist == nil)
+ return tag;
+ last = nil;
+ while(ilist) {
+ for(t = tag; t; t = t->taglist) {
+ if(t->item == ilist) {
+ last = t;
+ break;
+ }
+ }
+ ilist = ilist->next;
+ }
+ return last;
+}
+
+/*
+ * of all the items in ilist tagged with tag,
+ * return that tag for the first (bottommost) item.
+ */
+TkCtag*
+tkcfirsttag(TkCitem *ilist, TkCtag* tag)
+{
+ TkCtag *t;
+
+ if (tag == nil || tag->taglist == nil)
+ return tag;
+ for (; ilist != nil; ilist = ilist->next)
+ for(t = tag; t; t = t->taglist)
+ if(t->item == ilist)
+ return t;
+ return nil;
+}
+
+void
+tkmkpen(Image **pen, TkEnv *e, Image *stipple)
+{
+ int locked;
+ Display *d;
+ Image *new, *fill;
+
+ fill = tkgc(e, TkCfill);
+
+ d = e->top->display;
+ locked = lockdisplay(d);
+ if(*pen != nil) {
+ freeimage(*pen);
+ *pen = nil;
+ }
+ if(stipple == nil) {
+ if(locked)
+ unlockdisplay(d);
+ return;
+ }
+
+ if(fill == nil)
+ fill = d->black;
+ new = allocimage(d, stipple->r, RGBA32, 1, DTransparent); /* XXX RGBA32 is excessive sometimes... */
+ if (new != nil)
+ draw(new, stipple->r, fill, stipple, ZP);
+ else
+ new = fill;
+ if(locked)
+ unlockdisplay(d);
+ *pen = new;
+}
+
+Point
+tkcvsanchor(Point dp, int w, int h, int anchor)
+{
+ Point o;
+
+ if(anchor & Tknorth)
+ o.y = dp.y;
+ else if(anchor & Tksouth)
+ o.y = dp.y - h;
+ else
+ o.y = dp.y - h/2;
+
+ if(anchor & Tkwest)
+ o.x = dp.x;
+ else if(anchor & Tkeast)
+ o.x = dp.x - w;
+ else
+ o.x = dp.x - w/2;
+
+ return o;
+}
+
+static TkCitem*
+tkcvsmousefocus(TkCanvas *c, Point p)
+{
+ TkCitem *i, *s;
+ int (*hit)(TkCitem*, Point);
+
+ if (c->grab != nil)
+ return c->grab;
+ s = nil;
+ for(i = c->head; i; i = i->next)
+ if(ptinrect(p, i->p.bb)) {
+ if ((hit = tkcimethod[i->type].hit) != nil && !(*hit)(i, p))
+ continue;
+ s = i;
+ }
+
+ return s;
+}
+
+Tk*
+tkcvsinwindow(Tk *tk, Point *p)
+{
+ TkCanvas *c;
+ TkCitem *i;
+ Point q;
+ TkCwind *w;
+
+ c = TKobj(TkCanvas, tk);
+
+ q = addpt(*p, c->view);
+ i = tkcvsmousefocus(c, addpt(*p, c->view));
+ if (i == nil || i->type != TkCVwindow)
+ return tk;
+ w = TKobj(TkCwind, i);
+ if (w->sub == nil)
+ return tk;
+ p->x = q.x - (i->p.bb.min.x + w->sub->borderwidth);
+ p->y = q.y - (i->p.bb.min.y + w->sub->borderwidth);
+ return w->sub;
+}
+
+static Tk*
+tkcvsmouseinsub(TkCwind *w, TkMouse m)
+{
+ Point g, mp;
+ int bd;
+
+ g = tkposn(w->sub);
+ bd = w->sub->borderwidth;
+ mp.x = m.x - (g.x + bd);
+ mp.y = m.y - (g.y + bd);
+ return tkinwindow(w->sub, mp, 0);
+}
+
+static Tk*
+tkcvsdeliver(Tk *tk, TkCitem *i, int event, void *data)
+{
+ Tk *ftk, *dest;
+ TkCtag *t;
+ TkCwind *w;
+ TkAction *a;
+
+ if(i->type == TkCVwindow) {
+ dest = nil;
+ w = TKobj(TkCwind, i);
+ if(w->sub == nil)
+ return nil;
+
+ if(!(event & TkKey) && (event & TkEmouse)) {
+ ftk = tkcvsmouseinsub(w, *(TkMouse*)data);
+ if(ftk != w->focus) {
+ tkdeliver(w->focus, TkLeave, data);
+if(0)print("focus %p %q %p %q\n", w->sub, tkname(w->sub), ftk, tkname(ftk));
+ tkdeliver(ftk, TkEnter, data);
+ w->focus = ftk;
+ }
+ if(ftk != nil)
+ dest = tkdeliver(ftk, event, data);
+ } else {
+ if(event & TkLeave) {
+ tkdeliver(w->focus, TkLeave, data);
+ w->focus = nil;
+ } else if(event & TkEnter) {
+ ftk = tkcvsmouseinsub(w, *(TkMouse*)data);
+ tkdeliver(ftk, TkEnter, data);
+ w->focus = ftk;
+ } else
+ dest = tkdeliver(w->sub, event, data);
+ }
+ return dest;
+ }
+
+ for(t = i->stag; t != nil; t = t->itemlist) {
+ a = t->name->prop.binds;
+ if(a != nil)
+ tksubdeliver(tk, a, event, data, 0);
+ }
+ return nil;
+}
+
+Tk*
+tkcvsevent(Tk *tk, int event, void *data)
+{
+ TkMouse m;
+ TkCitem *f;
+ Point mp, g;
+ TkCanvas *c;
+ Tk *dest;
+
+ c = TKobj(TkCanvas, tk);
+
+ if(event == TkLeave && c->mouse != nil) {
+ tkcvsdeliver(tk, c->mouse, TkLeave, data);
+ c->mouse = nil;
+ }
+
+ dest = nil;
+ if(!(event & TkKey) && (event & TkEmouse) || (event & TkEnter)) {
+ m = *(TkMouse*)data;
+ g = tkposn(tk);
+ mp.x = (m.x - g.x - tk->borderwidth) + c->view.x;
+ mp.y = (m.y - g.y - tk->borderwidth) + c->view.y;
+ f = tkcvsmousefocus(c, mp);
+ if(c->mouse != f) {
+ if(c->mouse != nil) {
+ tkcvsdeliver(tk, c->mouse, TkLeave, data);
+ c->current->obj = nil;
+ }
+ if(f != nil) {
+ c->current->obj = &c->curtag;
+ c->curtag.item = f;
+ tkcvsdeliver(tk, f, TkEnter, data);
+ }
+ c->mouse = f;
+ }
+ f = c->mouse;
+ if(f != nil && (event & TkEnter) == 0)
+ dest = tkcvsdeliver(tk, f, event, &m);
+ }
+
+ if(event & TkKey) {
+ f = c->focus;
+ if(f != nil)
+ tkcvsdeliver(tk, f, event, data);
+ }
+ if(dest == nil)
+ tksubdeliver(tk, tk->binds, event, data, 0);
+ return dest;
+}
+
+/*
+ * debugging
+ */
+void
+tkcvsdump(Tk *tk)
+{
+ TkCanvas *c;
+ TkCitem *it;
+ TkCwind *w;
+ char v1[Tkminitem], v2[Tkminitem];
+ int i;
+
+ if(tk == nil)
+ return;
+ c = TKobj(TkCanvas, tk);
+ tkfprint(v1, c->width);
+ tkfprint(v2, c->height);
+ print("%q configure -width %s -height %s", tkname(tk), v1, v2);
+ print(" # focus %#p mouse %#p grab %#p\n", c->focus, c->mouse, c->grab);
+ for(it = c->head; it != nil; it = it->next){
+ print("%q create %q", tkname(tk), tkcimethod[it->type].name);
+ for(i = 0; i < it->p.npoint; i++){
+ tkfprint(v1, it->p.parampt[i].x);
+ tkfprint(v2, it->p.parampt[i].y);
+ print(" %s %s", v1, v2);
+ }
+ if(it->type == TkCVwindow){
+ w = TKobj(TkCwind, it);
+ if(w->sub != nil)
+ print(" -window %q", tkname(w->sub));
+ print(" # item %#p id %d sub %#p focus [%#p %q]\n", it, it->id, w->sub, w->focus, tkname(w->focus));
+ }else
+ print("# item %#p id %d\n", it, it->id);
+ }
+}
--- /dev/null
+++ b/libtk/carcs.c
@@ -1,0 +1,280 @@
+#include "lib9.h"
+#include "draw.h"
+#include "tk.h"
+#include "canvs.h"
+
+#define O(t, e) ((long)(&((t*)0)->e))
+typedef void (*Drawfn)(Image*, Point, int, int, Image*, int);
+
+/* Arc Options (+ means implemented)
+ +extent
+ +fill
+ +outline
+ outlinestipple
+ +start
+ +stipple
+ +style (+pieslice chord +arc)
+ +tags
+ +width
+*/
+
+typedef struct TkCarc TkCarc;
+struct TkCarc
+{
+ int width;
+ int start;
+ int extent;
+ int style;
+ Image* stipple;
+ Image* pen;
+};
+
+enum Style
+{
+ Pieslice,
+ Chord,
+ Arc
+};
+
+static
+TkStab tkstyle[] =
+{
+ "pieslice", Pieslice,
+ "arc", Arc,
+ "chord", Arc, /* Can't do chords */
+ nil
+};
+
+static
+TkOption arcopts[] =
+{
+ "start", OPTfrac, O(TkCarc, start), nil,
+ "extent", OPTfrac, O(TkCarc, extent), nil,
+ "style", OPTstab, O(TkCarc, style), tkstyle,
+ "width", OPTnnfrac, O(TkCarc, width), nil,
+ "stipple", OPTbmap, O(TkCarc, stipple), nil,
+ nil
+};
+
+static
+TkOption itemopts[] =
+{
+ "tags", OPTctag, O(TkCitem, tags), nil,
+ "fill", OPTcolr, O(TkCitem, env), IAUX(TkCfill),
+ "outline", OPTcolr, O(TkCitem, env), IAUX(TkCforegnd),
+ nil
+};
+
+void
+tkcvsarcsize(TkCitem *i)
+{
+ int w;
+ TkCarc *a;
+
+ a = TKobj(TkCarc, i);
+ w = TKF2I(a->width)*2;
+
+ i->p.bb = bbnil;
+ tkpolybound(i->p.drawpt, i->p.npoint, &i->p.bb);
+ i->p.bb = insetrect(i->p.bb, -w);
+}
+
+char*
+tkcvsarccreat(Tk* tk, char *arg, char **val)
+{
+ char *e;
+ TkCarc *a;
+ TkCitem *i;
+ TkCanvas *c;
+ TkOptab tko[3];
+
+ c = TKobj(TkCanvas, tk);
+
+ i = tkcnewitem(tk, TkCVarc, sizeof(TkCitem)+sizeof(TkCarc));
+ if(i == nil)
+ return TkNomem;
+
+ a = TKobj(TkCarc, i);
+ a->width = TKI2F(1);
+
+ e = tkparsepts(tk->env->top, &i->p, &arg, 0);
+ if(e != nil) {
+ tkcvsfreeitem(i);
+ return e;
+ }
+ if(i->p.npoint != 2) {
+ tkcvsfreeitem(i);
+ return TkFewpt;
+ }
+
+ tko[0].ptr = a;
+ tko[0].optab = arcopts;
+ tko[1].ptr = i;
+ tko[1].optab = itemopts;
+ tko[2].ptr = nil;
+ e = tkparse(tk->env->top, arg, tko, nil);
+ if(e != nil) {
+ tkcvsfreeitem(i);
+ return e;
+ }
+
+ e = tkcaddtag(tk, i, 1);
+ if(e != nil) {
+ tkcvsfreeitem(i);
+ return e;
+ }
+
+ tkcvsarcsize(i);
+ tkmkpen(&a->pen, i->env, a->stipple);
+
+ tkcvsappend(c, i);
+
+ tkbbmax(&c->update, &i->p.bb);
+ tkcvssetdirty(tk);
+ return tkvalue(val, "%d", i->id);
+}
+
+char*
+tkcvsarccget(TkCitem *i, char *arg, char **val)
+{
+ TkOptab tko[3];
+ TkCarc *a = TKobj(TkCarc, i);
+
+ tko[0].ptr = a;
+ tko[0].optab = arcopts;
+ tko[1].ptr = i;
+ tko[1].optab = itemopts;
+ tko[2].ptr = nil;
+
+ return tkgencget(tko, arg, val, i->env->top);
+}
+
+char*
+tkcvsarcconf(Tk *tk, TkCitem *i, char *arg)
+{
+ char *e;
+ TkOptab tko[3];
+ TkCarc *a = TKobj(TkCarc, i);
+
+ tko[0].ptr = a;
+ tko[0].optab = arcopts;
+ tko[1].ptr = i;
+ tko[1].optab = itemopts;
+ tko[2].ptr = nil;
+
+ e = tkparse(tk->env->top, arg, tko, nil);
+ tkcvsarcsize(i);
+ tkmkpen(&a->pen, i->env, a->stipple);
+
+ return e;
+}
+
+
+void
+tkcvsarcfree(TkCitem *i)
+{
+ TkCarc *a;
+
+ a = TKobj(TkCarc, i);
+ if(a->stipple)
+ freeimage(a->stipple);
+ if(a->pen)
+ freeimage(a->pen);
+}
+
+void
+tkcvsarcdraw(Image *img, TkCitem *i, TkEnv *pe)
+{
+ TkEnv *e;
+ TkCarc *a;
+ Rectangle d;
+ int w, dx, dy;
+ int s, ext, s0, s1, e0, e1, l;
+ Image *pen, *col, *tmp;
+ Point p0, p1, c;
+ extern void drawarc(Point,int,int,int,int,int,Image *,Image *,Image *);
+
+ USED(pe);
+
+ d.min = i->p.drawpt[0];
+ d.max = i->p.drawpt[1];
+
+ e = i->env;
+ a = TKobj(TkCarc, i);
+
+ pen = a->pen;
+ if(pen == nil && (e->set & (1<<TkCfill)))
+ pen = tkgc(e, TkCfill);
+
+ w = TKF2I(a->width)/2;
+ if(w < 0)
+ return;
+
+ d = canonrect(d);
+ dx = Dx(d)/2;
+ dy = Dy(d)/2;
+ c.x = (d.min.x+d.max.x)/2;
+ c.y = (d.min.y+d.max.y)/2;
+ s = TKF2I(a->start);
+ ext = TKF2I(a->extent);
+/*
+ if(ext == 0)
+ ext = 90;
+*/
+
+ if(a->style != Arc && pen != nil)
+ fillarc(img, c, dx, dy, pen, Pt(0,0), s, ext);
+ col = tkgc(e, TkCforegnd);
+ arc(img, c, dx, dy, w, col, Pt(0,0), s, ext);
+ if(a->style == Pieslice){
+ /*
+ * It is difficult to compute the intersection of the lines
+ * and the ellipse using integers, so let the draw library
+ * do it for us: use a full ellipse as the source of color
+ * for drawing the lines.
+ */
+ tmp = allocimage(img->display, d, img->chan, 0, DNofill);
+ if(tmp == nil)
+ return;
+ /* copy dest to tmp so lines don't spill beyond edge of ellipse */
+ drawop(tmp, d, img, nil, d.min, S);
+ fillellipse(tmp, c, dx, dy, col, Pt(0,0));
+ icossin(s, &s1, &s0);
+ icossin(s+ext, &e1, &e0);
+ if(dx > dy)
+ l = 2*dx+1;
+ else
+ l = 2*dy+1;
+ p0 = Pt(c.x+l*s1/ICOSSCALE, c.y-l*s0/ICOSSCALE);
+ p1 = Pt(c.x+l*e1/ICOSSCALE, c.y-l*e0/ICOSSCALE);
+ line(img, c, p0, Endsquare, Endsquare, w, tmp, c);
+ line(img, c, p1, Endsquare, Endsquare, w, tmp, c);
+ freeimage(tmp);
+ }
+}
+
+char*
+tkcvsarccoord(TkCitem *i, char *arg, int x, int y)
+{
+ char *e;
+ TkCpoints p;
+
+ if(arg == nil) {
+ tkxlatepts(i->p.parampt, i->p.npoint, x, y);
+ tkxlatepts(i->p.drawpt, i->p.npoint, TKF2I(x), TKF2I(y));
+ i->p.bb = rectaddpt(i->p.bb, Pt(TKF2I(x), TKF2I(y)));
+ }
+ else {
+ e = tkparsepts(i->env->top, &p, &arg, 0);
+ if(e != nil)
+ return e;
+ if(p.npoint != 2) {
+ tkfreepoint(&p);
+ return TkFewpt;
+ }
+ tkfreepoint(&i->p);
+ i->p = p;
+ tkcvsarcsize(i);
+ }
+ return nil;
+}
--- /dev/null
+++ b/libtk/cbits.c
@@ -1,0 +1,211 @@
+#include "lib9.h"
+#include "draw.h"
+#include "tk.h"
+#include "canvs.h"
+
+#define O(t, e) ((long)(&((t*)0)->e))
+
+/* Bitmap Options (+ means implemented)
+ +anchor
+ +bitmap
+*/
+
+typedef struct TkCbits TkCbits;
+struct TkCbits
+{
+ int anchor;
+ Point anchorp;
+ Image* bitmap;
+};
+
+static
+TkOption bitopts[] =
+{
+ "anchor", OPTstab, O(TkCbits, anchor), tkanchor,
+ "bitmap", OPTbmap, O(TkCbits, bitmap), nil,
+ nil
+};
+
+static
+TkOption itemopts[] =
+{
+ "tags", OPTctag, O(TkCitem, tags), nil,
+ "background", OPTcolr, O(TkCitem, env), IAUX(TkCbackgnd),
+ "foreground", OPTcolr, O(TkCitem, env), IAUX(TkCforegnd),
+ nil
+};
+
+void
+tkcvsbitsize(TkCitem *i)
+{
+ Point o;
+ int dx, dy;
+ TkCbits *b;
+
+ b = TKobj(TkCbits, i);
+ i->p.bb = bbnil;
+ if(b->bitmap == nil)
+ return;
+
+ dx = Dx(b->bitmap->r);
+ dy = Dy(b->bitmap->r);
+
+ o = tkcvsanchor(i->p.drawpt[0], dx, dy, b->anchor);
+
+ i->p.bb.min.x = o.x;
+ i->p.bb.min.y = o.y;
+ i->p.bb.max.x = o.x + dx;
+ i->p.bb.max.y = o.y + dy;
+ b->anchorp = subpt(o, i->p.drawpt[0]);
+}
+
+char*
+tkcvsbitcreat(Tk* tk, char *arg, char **val)
+{
+ char *e;
+ TkCbits *b;
+ TkCitem *i;
+ TkCanvas *c;
+ TkOptab tko[3];
+
+ c = TKobj(TkCanvas, tk);
+
+ i = tkcnewitem(tk, TkCVbitmap, sizeof(TkCitem)+sizeof(TkCbits));
+ if(i == nil)
+ return TkNomem;
+
+ b = TKobj(TkCbits, i);
+
+ e = tkparsepts(tk->env->top, &i->p, &arg, 0);
+ if(e != nil) {
+ tkcvsfreeitem(i);
+ return e;
+ }
+ if(i->p.npoint != 1) {
+ tkcvsfreeitem(i);
+ return TkFewpt;
+ }
+
+ tko[0].ptr = b;
+ tko[0].optab = bitopts;
+ tko[1].ptr = i;
+ tko[1].optab = itemopts;
+ tko[2].ptr = nil;
+ e = tkparse(tk->env->top, arg, tko, nil);
+ if(e != nil) {
+ tkcvsfreeitem(i);
+ return e;
+ }
+
+ e = tkcaddtag(tk, i, 1);
+ if(e != nil) {
+ tkcvsfreeitem(i);
+ return e;
+ }
+
+ tkcvsbitsize(i);
+ tkcvsappend(c, i);
+
+ tkbbmax(&c->update, &i->p.bb);
+ tkcvssetdirty(tk);
+ return tkvalue(val, "%d", i->id);
+}
+
+char*
+tkcvsbitcget(TkCitem *i, char *arg, char **val)
+{
+ TkOptab tko[3];
+ TkCbits *b = TKobj(TkCbits, i);
+
+ tko[0].ptr = b;
+ tko[0].optab = bitopts;
+ tko[1].ptr = i;
+ tko[1].optab = itemopts;
+ tko[2].ptr = nil;
+
+ return tkgencget(tko, arg, val, i->env->top);
+}
+
+char*
+tkcvsbitconf(Tk *tk, TkCitem *i, char *arg)
+{
+ char *e;
+ TkOptab tko[3];
+ TkCbits *b = TKobj(TkCbits, i);
+
+ tko[0].ptr = b;
+ tko[0].optab = bitopts;
+ tko[1].ptr = i;
+ tko[1].optab = itemopts;
+ tko[2].ptr = nil;
+
+ e = tkparse(tk->env->top, arg, tko, nil);
+ tkcvsbitsize(i);
+ return e;
+}
+
+void
+tkcvsbitfree(TkCitem *i)
+{
+ TkCbits *b;
+
+ b = TKobj(TkCbits, i);
+ if(b->bitmap)
+ freeimage(b->bitmap);
+}
+
+void
+tkcvsbitdraw(Image *img, TkCitem *i, TkEnv *pe)
+{
+ TkEnv *e;
+ TkCbits *b;
+ Rectangle r;
+ Image *bi;
+
+ USED(pe);
+
+ e = i->env;
+ b = TKobj(TkCbits, i);
+
+ bi = b->bitmap;
+ if(bi == nil)
+ return;
+
+ r.min = addpt(b->anchorp, i->p.drawpt[0]);
+ r.max = r.min;
+ r.max.x += Dx(bi->r);
+ r.max.y += Dy(bi->r);
+
+ if(bi->depth != 1) {
+ draw(img, r, bi, nil, ZP);
+ return;
+ }
+ gendraw(img, r, tkgc(e, TkCbackgnd), r.min, nil, ZP);
+ draw(img, r, tkgc(e, TkCforegnd), bi, ZP);
+}
+
+char*
+tkcvsbitcoord(TkCitem *i, char *arg, int x, int y)
+{
+ char *e;
+ TkCpoints p;
+
+ if(arg == nil) {
+ tkxlatepts(i->p.parampt, i->p.npoint, x, y);
+ tkxlatepts(i->p.drawpt, i->p.npoint, TKF2I(x), TKF2I(y));
+ i->p.bb = rectaddpt(i->p.bb, Pt(TKF2I(x), TKF2I(y)));
+ }
+ else {
+ e = tkparsepts(i->env->top, &p, &arg, 0);
+ if(e != nil)
+ return e;
+ if(p.npoint != 1) {
+ tkfreepoint(&p);
+ return TkFewpt;
+ }
+ tkfreepoint(&i->p);
+ i->p = p;
+ tkcvsbitsize(i);
+ }
+ return nil;
+}
--- /dev/null
+++ b/libtk/cimag.c
@@ -1,0 +1,211 @@
+#include "lib9.h"
+#include "draw.h"
+#include "tk.h"
+#include "canvs.h"
+
+#define O(t, e) ((long)(&((t*)0)->e))
+
+/* Image Options (+ means implemented)
+ +anchor
+ +image
+*/
+
+typedef struct TkCimag TkCimag;
+struct TkCimag
+{
+ int anchor;
+ Point anchorp;
+ TkImg* tki;
+};
+
+static
+TkOption imgopts[] =
+{
+ "anchor", OPTstab, O(TkCimag, anchor), tkanchor,
+ "image", OPTimag, O(TkCimag, tki), nil,
+ nil
+};
+
+static
+TkOption itemopts[] =
+{
+ "tags", OPTctag, O(TkCitem, tags), nil,
+ nil
+};
+
+void
+tkcvsimgsize(TkCitem *i)
+{
+ Point o;
+ int dx, dy;
+ TkCimag *t;
+
+ t = TKobj(TkCimag, i);
+ i->p.bb = bbnil;
+ if(t->tki == nil)
+ return;
+
+ dx = t->tki->w;
+ dy = t->tki->h;
+
+ o = tkcvsanchor(i->p.drawpt[0], dx, dy, t->anchor);
+
+ i->p.bb.min.x = o.x;
+ i->p.bb.min.y = o.y;
+ i->p.bb.max.x = o.x + dx;
+ i->p.bb.max.y = o.y + dy;
+ t->anchorp = subpt(o, i->p.drawpt[0]);
+}
+
+char*
+tkcvsimgcreat(Tk* tk, char *arg, char **val)
+{
+ char *e;
+ TkCimag *t;
+ TkCitem *i;
+ TkCanvas *c;
+ TkOptab tko[3];
+
+ c = TKobj(TkCanvas, tk);
+
+ i = tkcnewitem(tk, TkCVimage, sizeof(TkCitem)+sizeof(TkCimag));
+ if(i == nil)
+ return TkNomem;
+
+ t = TKobj(TkCimag, i);
+
+ e = tkparsepts(tk->env->top, &i->p, &arg, 0);
+ if(e != nil) {
+ tkcvsfreeitem(i);
+ return e;
+ }
+ if(i->p.npoint != 1) {
+ tkcvsfreeitem(i);
+ return TkFewpt;
+ }
+
+ tko[0].ptr = t;
+ tko[0].optab = imgopts;
+ tko[1].ptr = i;
+ tko[1].optab = itemopts;
+ tko[2].ptr = nil;
+ e = tkparse(tk->env->top, arg, tko, nil);
+ if(e != nil) {
+ tkcvsfreeitem(i);
+ return e;
+ }
+
+ e = tkcaddtag(tk, i, 1);
+ if(e != nil) {
+ tkcvsfreeitem(i);
+ return e;
+ }
+
+ tkcvsimgsize(i);
+
+ e = tkvalue(val, "%d", i->id);
+ if(e != nil) {
+ tkcvsfreeitem(i);
+ return e;
+ }
+
+ tkcvsappend(c, i);
+ tkbbmax(&c->update, &i->p.bb);
+ tkcvssetdirty(tk);
+ return nil;
+}
+
+char*
+tkcvsimgcget(TkCitem *i, char *arg, char **val)
+{
+ TkOptab tko[3];
+ TkCimag *t = TKobj(TkCimag, i);
+
+ tko[0].ptr = t;
+ tko[0].optab = imgopts;
+ tko[1].ptr = i;
+ tko[1].optab = itemopts;
+ tko[2].ptr = nil;
+
+ return tkgencget(tko, arg, val, i->env->top);
+}
+
+char*
+tkcvsimgconf(Tk *tk, TkCitem *i, char *arg)
+{
+ char *e;
+ TkOptab tko[3];
+ TkCimag *t = TKobj(TkCimag, i);
+
+ tko[0].ptr = t;
+ tko[0].optab = imgopts;
+ tko[1].ptr = i;
+ tko[1].optab = itemopts;
+ tko[2].ptr = nil;
+
+ e = tkparse(tk->env->top, arg, tko, nil);
+ tkcvsimgsize(i);
+ return e;
+}
+
+void
+tkcvsimgfree(TkCitem *i)
+{
+ TkCimag *t;
+
+ t = TKobj(TkCimag, i);
+ if(t->tki)
+ tkimgput(t->tki);
+}
+
+void
+tkcvsimgdraw(Image *img, TkCitem *i, TkEnv *pe)
+{
+ TkCimag *t;
+ TkImg *tki;
+ Rectangle r;
+ Image *fg;
+
+ USED(pe);
+
+ t = TKobj(TkCimag, i);
+ tki = t->tki;
+ if(tki == nil)
+ return;
+ fg = tki->img;
+ if(fg == nil)
+ return;
+
+ r.min = addpt(t->anchorp, i->p.drawpt[0]);
+ r.max = r.min;
+ r.max.x += tki->w;
+ r.max.y += tki->h;
+
+ draw(img, r, fg, nil, ZP);
+}
+
+char*
+tkcvsimgcoord(TkCitem *i, char *arg, int x, int y)
+{
+ char *e;
+ TkCpoints p;
+
+ if(arg == nil) {
+ tkxlatepts(i->p.parampt, i->p.npoint, x, y);
+ tkxlatepts(i->p.drawpt, i->p.npoint, TKF2I(x), TKF2I(y));
+ i->p.bb = rectaddpt(i->p.bb, Pt(TKF2I(x), TKF2I(y)));
+ }
+ else {
+ e = tkparsepts(i->env->top, &p, &arg, 0);
+ if(e != nil)
+ return e;
+ if(p.npoint != 1) {
+ tkfreepoint(&p);
+ return TkFewpt;
+ }
+ tkfreepoint(&i->p);
+ i->p = p;
+ tkcvsimgsize(i);
+ }
+ return nil;
+}
--- /dev/null
+++ b/libtk/cline.c
@@ -1,0 +1,268 @@
+#include "lib9.h"
+#include "draw.h"
+#include "tk.h"
+#include "canvs.h"
+
+#define O(t, e) ((long)(&((t*)0)->e))
+
+/* Line Options (+ means implemented)
+ +arrow
+ +arrowshape
+ +capstyle
+ +fill
+ joinstyle
+ +smooth
+ +splinesteps
+ +stipple
+ +tags
+ +width
+*/
+
+static
+TkStab tklines[] =
+{
+ "none", 0,
+ "first", TkCarrowf,
+ "last", TkCarrowl,
+ "both", TkCarrowf|TkCarrowl,
+ nil
+};
+
+static
+TkStab tkcapstyle[] =
+{
+ "butt", Endsquare,
+ "projecting", Endsquare,
+ "round", Enddisc,
+ nil
+};
+
+static
+TkOption lineopts[] =
+{
+ "arrow", OPTstab, O(TkCline, arrow), tklines,
+ "arrowshape", OPTfrac, O(TkCline, shape[0]), IAUX(3),
+ "width", OPTnnfrac, O(TkCline, width), nil,
+ "stipple", OPTbmap, O(TkCline, stipple), nil,
+ "smooth", OPTstab, O(TkCline, smooth), tkbool,
+ "splinesteps", OPTdist, O(TkCline, steps), nil,
+ "capstyle", OPTstab, O(TkCline, capstyle), tkcapstyle,
+ nil
+};
+
+static
+TkOption itemopts[] =
+{
+ "tags", OPTctag, O(TkCitem, tags), nil,
+ "fill", OPTcolr, O(TkCitem, env), IAUX(TkCforegnd),
+ nil
+};
+
+void
+tkcvslinesize(TkCitem *i)
+{
+ TkCline *l;
+ int j, w, as, shape[3], arrow;
+
+ l = TKobj(TkCline, i);
+ w = TKF2I(l->width);
+
+ i->p.bb = bbnil;
+ tkpolybound(i->p.drawpt, i->p.npoint, &i->p.bb);
+
+ l->arrowf = l->capstyle;
+ l->arrowl = l->capstyle;
+ if(l->arrow != 0) {
+ as = w/3;
+ if(as < 1)
+ as = 1;
+ for(j = 0; j < 3; j++) {
+ shape[j] = l->shape[j];
+ if(shape[j] == 0)
+ shape[j] = as * cvslshape[j];
+ }
+ arrow = ARROW(TKF2I(shape[0]), TKF2I(shape[1]), TKF2I(shape[2]));
+ if(l->arrow & TkCarrowf)
+ l->arrowf = arrow;
+ if(l->arrow & TkCarrowl)
+ l->arrowl = arrow;
+ w += shape[2];
+ }
+
+ i->p.bb = insetrect(i->p.bb, -w);
+}
+
+char*
+tkcvslinecreat(Tk* tk, char *arg, char **val)
+{
+ char *e;
+ TkCline *l;
+ TkCitem *i;
+ TkCanvas *c;
+ TkOptab tko[3];
+
+ c = TKobj(TkCanvas, tk);
+
+ i = tkcnewitem(tk, TkCVline, sizeof(TkCitem)+sizeof(TkCline));
+ if(i == nil)
+ return TkNomem;
+
+ l = TKobj(TkCline, i);
+ l->width = TKI2F(1);
+
+ e = tkparsepts(tk->env->top, &i->p, &arg, 0);
+ if(e != nil) {
+ tkcvsfreeitem(i);
+ return e;
+ }
+
+ tko[0].ptr = l;
+ tko[0].optab = lineopts;
+ tko[1].ptr = i;
+ tko[1].optab = itemopts;
+ tko[2].ptr = nil;
+ e = tkparse(tk->env->top, arg, tko, nil);
+ if(e != nil) {
+ tkcvsfreeitem(i);
+ return e;
+ }
+ tkmkpen(&l->pen, i->env, l->stipple);
+
+ e = tkcaddtag(tk, i, 1);
+ if(e != nil) {
+ tkcvsfreeitem(i);
+ return e;
+ }
+
+ tkcvslinesize(i);
+ e = tkvalue(val, "%d", i->id);
+ if(e != nil) {
+ tkcvsfreeitem(i);
+ return e;
+ }
+ tkcvsappend(c, i);
+
+ tkbbmax(&c->update, &i->p.bb);
+ tkcvssetdirty(tk);
+ return nil;
+}
+
+char*
+tkcvslinecget(TkCitem *i, char *arg, char **val)
+{
+ TkOptab tko[3];
+ TkCline *l = TKobj(TkCline, i);
+
+ tko[0].ptr = l;
+ tko[0].optab = lineopts;
+ tko[1].ptr = i;
+ tko[1].optab = itemopts;
+ tko[2].ptr = nil;
+
+ return tkgencget(tko, arg, val, i->env->top);
+}
+
+char*
+tkcvslineconf(Tk *tk, TkCitem *i, char *arg)
+{
+ char *e;
+ TkOptab tko[3];
+ TkCline *l = TKobj(TkCline, i);
+
+ tko[0].ptr = l;
+ tko[0].optab = lineopts;
+ tko[1].ptr = i;
+ tko[1].optab = itemopts;
+ tko[2].ptr = nil;
+
+ e = tkparse(tk->env->top, arg, tko, nil);
+
+ tkmkpen(&l->pen, i->env, l->stipple);
+ tkcvslinesize(i);
+
+ return e;
+}
+
+void
+tkcvslinefree(TkCitem *i)
+{
+ TkCline *l;
+
+ l = TKobj(TkCline, i);
+ if(l->stipple)
+ freeimage(l->stipple);
+ if(l->pen)
+ freeimage(l->pen);
+}
+
+void
+tkcvslinedraw(Image *img, TkCitem *i, TkEnv *pe)
+{
+ int w;
+ Point *p;
+ TkCline *l;
+ Image *pen;
+
+ USED(pe);
+
+ l = TKobj(TkCline, i);
+
+ pen = l->pen;
+ if(pen == nil)
+ pen = tkgc(i->env, TkCforegnd);
+
+ w = TKF2I(l->width)/2;
+ if(w < 0)
+ return;
+
+ p = i->p.drawpt;
+ if(l->smooth == BoolT && i->p.npoint >= 3)
+ bezspline(img, p, i->p.npoint, l->arrowf, l->arrowl, w, pen, p[0]);
+ else
+ poly(img, p, i->p.npoint, l->arrowf, l->arrowl, w, pen, p[0]);
+}
+
+char*
+tkcvslinecoord(TkCitem *i, char *arg, int x, int y)
+{
+ char *e;
+ TkCpoints p;
+
+ if(arg == nil) {
+ tkxlatepts(i->p.parampt, i->p.npoint, x, y);
+ tkxlatepts(i->p.drawpt, i->p.npoint, TKF2I(x), TKF2I(y));
+ i->p.bb = rectaddpt(i->p.bb, Pt(TKF2I(x), TKF2I(y)));
+ }
+ else {
+ e = tkparsepts(i->env->top, &p, &arg, 0);
+ if(e != nil)
+ return e;
+ if(p.npoint < 2) {
+ tkfreepoint(&p);
+ return TkFewpt;
+ }
+ tkfreepoint(&i->p);
+ i->p = p;
+ tkcvslinesize(i);
+ }
+ return nil;
+}
+
+int
+tkcvslinehit(TkCitem *i, Point p)
+{
+ TkCline *l;
+ int w, np, r;
+ Point *pp;
+
+ l = TKobj(TkCline, i);
+ w =TKF2I(l->width) + 2; /* 2 for slop */
+
+ if (l->smooth == BoolT) {
+ np = getbezsplinepts(i->p.drawpt, i->p.npoint, &pp);
+ r = tklinehit(pp, np, w, p);
+ free(pp);
+ } else
+ r = tklinehit(i->p.drawpt, i->p.npoint, w, p);
+ return r;
+}
--- /dev/null
+++ b/libtk/colrs.c
@@ -1,0 +1,93 @@
+#include "lib9.h"
+#include "draw.h"
+#include "tk.h"
+
+#define RGB(R,G,B) ((R<<24)|(G<<16)|(B<<8)|(0xff))
+
+enum
+{
+ tkBackR = 0xdd, /* Background base color */
+ tkBackG = 0xdd,
+ tkBackB = 0xdd,
+
+ tkSelectR = 0xb0, /* Check box selected color */
+ tkSelectG = 0x30,
+ tkSelectB = 0x60,
+
+ tkSelectbgndR = 0x40, /* Selected item background */
+ tkSelectbgndG = 0x40,
+ tkSelectbgndB = 0x40
+};
+
+typedef struct Coltab Coltab;
+struct Coltab {
+ int c;
+ ulong rgba;
+ int shade;
+};
+
+static Coltab coltab[] =
+{
+ TkCbackgnd,
+ RGB(tkBackR, tkBackG, tkBackB),
+ TkSameshade,
+ TkCbackgndlght,
+ RGB(tkBackR, tkBackG, tkBackB),
+ TkLightshade,
+ TkCbackgnddark,
+ RGB(tkBackR, tkBackG, tkBackB),
+ TkDarkshade,
+ TkCactivebgnd,
+ RGB(tkBackR+0x10, tkBackG+0x10, tkBackB+0x10),
+ TkSameshade,
+ TkCactivebgndlght,
+ RGB(tkBackR+0x10, tkBackG+0x10, tkBackB+0x10),
+ TkLightshade,
+ TkCactivebgnddark,
+ RGB(tkBackR+0x10, tkBackG+0x10, tkBackB+0x10),
+ TkDarkshade,
+ TkCactivefgnd,
+ RGB(0, 0, 0),
+ TkSameshade,
+ TkCforegnd,
+ RGB(0, 0, 0),
+ TkSameshade,
+ TkCselect,
+ RGB(tkSelectR, tkSelectG, tkSelectB),
+ TkSameshade,
+ TkCselectbgnd,
+ RGB(tkSelectbgndR, tkSelectbgndG, tkSelectbgndB),
+ TkSameshade,
+ TkCselectbgndlght,
+ RGB(tkSelectbgndR, tkSelectbgndG, tkSelectbgndB),
+ TkLightshade,
+ TkCselectbgnddark,
+ RGB(tkSelectbgndR, tkSelectbgndG, tkSelectbgndB),
+ TkDarkshade,
+ TkCselectfgnd,
+ RGB(0xff, 0xff, 0xff),
+ TkSameshade,
+ TkCdisablefgnd,
+ RGB(0x88, 0x88, 0x88),
+ TkSameshade,
+ TkChighlightfgnd,
+ RGB(0, 0, 0),
+ TkSameshade,
+ TkCtransparent,
+ DTransparent,
+ TkSameshade,
+ -1,
+};
+
+void
+tksetenvcolours(TkEnv *env)
+{
+ Coltab *c;
+
+ c = &coltab[0];
+ while(c->c != -1) {
+ env->colors[c->c] = tkrgbashade(c->rgba, c->shade);
+ env->set |= (1<<c->c);
+ c++;
+ }
+}
--- /dev/null
+++ b/libtk/coval.c
@@ -1,0 +1,251 @@
+#include "lib9.h"
+#include "draw.h"
+#include "tk.h"
+#include "canvs.h"
+
+#define O(t, e) ((long)(&((t*)0)->e))
+typedef void (*Drawfn)(Image*, Point, int, int, Image*, int);
+
+/* Oval Options (+ means implemented)
+ +fill
+ +outline
+ +stipple
+ +tags
+ +width
+*/
+
+typedef struct TkCoval TkCoval;
+struct TkCoval
+{
+ int width;
+ Image* stipple;
+ Image* pen;
+ TkCanvas* canv;
+};
+
+static
+TkOption ovalopts[] =
+{
+ "width", OPTnnfrac, O(TkCoval, width), nil, /* XXX should be nnfrac */
+ "stipple", OPTbmap, O(TkCoval, stipple), nil,
+ nil
+};
+
+static
+TkOption itemopts[] =
+{
+ "tags", OPTctag, O(TkCitem, tags), nil,
+ "fill", OPTcolr, O(TkCitem, env), IAUX(TkCfill),
+ "outline", OPTcolr, O(TkCitem, env), IAUX(TkCforegnd),
+ nil
+};
+
+void
+tkcvsovalsize(TkCitem *i)
+{
+ int w;
+ TkCoval *o;
+
+ o = TKobj(TkCoval, i);
+ w = TKF2I(o->width)*2;
+
+ i->p.bb = bbnil;
+ tkpolybound(i->p.drawpt, i->p.npoint, &i->p.bb);
+ i->p.bb = insetrect(i->p.bb, -w);
+}
+
+char*
+tkcvsovalcreat(Tk* tk, char *arg, char **val)
+{
+ char *e;
+ TkCoval *o;
+ TkCitem *i;
+ TkCanvas *c;
+ TkOptab tko[3];
+
+ c = TKobj(TkCanvas, tk);
+
+ i = tkcnewitem(tk, TkCVoval, sizeof(TkCitem)+sizeof(TkCoval));
+ if(i == nil)
+ return TkNomem;
+
+ o = TKobj(TkCoval, i);
+ o->width = TKI2F(1);
+ o->canv = c;
+ e = tkparsepts(tk->env->top, &i->p, &arg, 0);
+ if(e != nil) {
+ tkcvsfreeitem(i);
+ return e;
+ }
+ if(i->p.npoint != 2) {
+ tkcvsfreeitem(i);
+ return TkFewpt;
+ }
+
+ tko[0].ptr = o;
+ tko[0].optab = ovalopts;
+ tko[1].ptr = i;
+ tko[1].optab = itemopts;
+ tko[2].ptr = nil;
+ e = tkparse(tk->env->top, arg, tko, nil);
+ if(e != nil) {
+ tkcvsfreeitem(i);
+ return e;
+ }
+ e = tkcaddtag(tk, i, 1);
+ if(e != nil) {
+ tkcvsfreeitem(i);
+ return e;
+ }
+
+ tkcvsovalsize(i);
+
+ e = tkvalue(val, "%d", i->id);
+ if(e != nil) {
+ tkcvsfreeitem(i);
+ return e;
+ }
+
+ tkcvsappend(c, i);
+ tkbbmax(&c->update, &i->p.bb);
+ tkmkpen(&o->pen, i->env, o->stipple);
+ tkcvssetdirty(tk);
+ return nil;
+}
+
+char*
+tkcvsovalcget(TkCitem *i, char *arg, char **val)
+{
+ TkOptab tko[3];
+ TkCoval *o = TKobj(TkCoval, i);
+
+ tko[0].ptr = o;
+ tko[0].optab = ovalopts;
+ tko[1].ptr = i;
+ tko[1].optab = itemopts;
+ tko[2].ptr = nil;
+
+ return tkgencget(tko, arg, val, i->env->top);
+}
+
+char*
+tkcvsovalconf(Tk *tk, TkCitem *i, char *arg)
+{
+ char *e;
+ TkOptab tko[3];
+ TkCoval *o = TKobj(TkCoval, i);
+
+ tko[0].ptr = o;
+ tko[0].optab = ovalopts;
+ tko[1].ptr = i;
+ tko[1].optab = itemopts;
+ tko[2].ptr = nil;
+
+ e = tkparse(tk->env->top, arg, tko, nil);
+ tkcvsovalsize(i);
+ tkmkpen(&o->pen, i->env, o->stipple);
+
+ return e;
+}
+
+void
+tkcvsovalfree(TkCitem *i)
+{
+ TkCoval *o;
+
+ o = TKobj(TkCoval, i);
+ if(o->stipple)
+ freeimage(o->stipple);
+ if(o->pen)
+ freeimage(o->pen);
+}
+
+void
+tkcvsovaldraw(Image *img, TkCitem *i, TkEnv *pe)
+{
+ Point c;
+ TkEnv *e;
+ Image *pen;
+ TkCoval *o;
+ Rectangle d;
+ int w, dx, dy;
+
+ USED(pe);
+
+ d.min = i->p.drawpt[0];
+ d.max = i->p.drawpt[1];
+
+ e = i->env;
+ o = TKobj(TkCoval, i);
+
+ pen = o->pen;
+ if(pen == nil && (e->set & (1<<TkCfill)))
+ pen = tkgc(e, TkCfill);
+
+ w = TKF2I(o->width)/2;
+ if(w < 0)
+ return;
+
+ d = canonrect(d);
+ dx = Dx(d)/2;
+ dy = Dy(d)/2;
+ c.x = d.min.x + dx;
+ c.y = d.min.y + dy;
+ if(pen != nil)
+ fillellipse(img, c, dx, dy, pen, c);
+ ellipse(img, c, dx, dy, w, tkgc(e, TkCforegnd), c);
+}
+
+char*
+tkcvsovalcoord(TkCitem *i, char *arg, int x, int y)
+{
+ char *e;
+ TkCpoints p;
+
+ if(arg == nil) {
+ tkxlatepts(i->p.parampt, i->p.npoint, x, y);
+ tkxlatepts(i->p.drawpt, i->p.npoint, TKF2I(x), TKF2I(y));
+ i->p.bb = rectaddpt(i->p.bb, Pt(TKF2I(x), TKF2I(y)));
+ }
+ else {
+ e = tkparsepts(i->env->top, &p, &arg, 0);
+ if(e != nil)
+ return e;
+ if(p.npoint != 2) {
+ tkfreepoint(&p);
+ return TkFewpt;
+ }
+ tkfreepoint(&i->p);
+ i->p = p;
+ tkcvsovalsize(i);
+ }
+ return nil;
+}
+
+int
+tkcvsovalhit(TkCitem *i, Point p)
+{
+ TkCoval *o;
+ int w, dx, dy;
+ Rectangle d;
+ vlong v;
+
+ o = TKobj(TkCoval, i);
+ w = TKF2I(o->width)/2;
+ d = canonrect(Rpt(i->p.drawpt[0], i->p.drawpt[1]));
+ d = insetrect(d, -(w/2 + 1));
+
+ dx = Dx(d)/2;
+ dy = Dy(d)/2;
+
+ p.x -= d.min.x + dx;
+ p.y -= d.min.y + dy;
+
+ dx *= dx;
+ dy *= dy;
+
+ /* XXX can we do this nicely without overflow and without vlongs? */
+ v = (vlong)(p.x*p.x)*dy;
+ v += (vlong)(p.y*p.y)*dx;
+ return v < (vlong)dx*dy;
+}
--- /dev/null
+++ b/libtk/cpoly.c
@@ -1,0 +1,270 @@
+#include "lib9.h"
+#include "draw.h"
+#include "tk.h"
+#include "canvs.h"
+
+#define O(t, e) ((long)(&((t*)0)->e))
+
+typedef struct TkCpoly TkCpoly;
+struct TkCpoly
+{
+ int width;
+ Image* stipple;
+ Image* pen;
+ TkCanvas* canv;
+ int smooth;
+ int steps;
+ int winding;
+};
+
+static
+TkStab tkwinding[] =
+{
+ "nonzero", ~0,
+ "odd", 1,
+ nil
+};
+
+/* Polygon Options (+ means implemented)
+ +fill
+ +smooth
+ +splinesteps
+ +stipple
+ +tags
+ +width
+ +outline
+*/
+static
+TkOption polyopts[] =
+{
+ "width", OPTnnfrac, O(TkCpoly, width), nil,
+ "stipple", OPTbmap, O(TkCpoly, stipple), nil,
+ "smooth", OPTstab, O(TkCpoly, smooth), tkbool,
+ "splinesteps", OPTdist, O(TkCpoly, steps), nil,
+ "winding", OPTstab, O(TkCpoly, winding), tkwinding,
+ nil
+};
+
+static
+TkOption itemopts[] =
+{
+ "tags", OPTctag, O(TkCitem, tags), nil,
+ "fill", OPTcolr, O(TkCitem, env), IAUX(TkCfill),
+ "outline", OPTcolr, O(TkCitem, env), IAUX(TkCforegnd),
+ nil
+};
+
+void
+tkcvspolysize(TkCitem *i)
+{
+ int w;
+ TkCpoly *p;
+
+ p = TKobj(TkCpoly, i);
+ w = TKF2I(p->width);
+
+ i->p.bb = bbnil;
+ tkpolybound(i->p.drawpt, i->p.npoint, &i->p.bb);
+ i->p.bb = insetrect(i->p.bb, -w);
+}
+
+char*
+tkcvspolycreat(Tk* tk, char *arg, char **val)
+{
+ char *e;
+ TkCpoly *p;
+ TkCitem *i;
+ TkCanvas *c;
+ TkOptab tko[3];
+
+ c = TKobj(TkCanvas, tk);
+
+ i = tkcnewitem(tk, TkCVpoly, sizeof(TkCitem)+sizeof(TkCpoly));
+ if(i == nil)
+ return TkNomem;
+
+ p = TKobj(TkCpoly, i);
+ p->width = TKI2F(1);
+ p->winding = ~0;
+
+ e = tkparsepts(tk->env->top, &i->p, &arg, 1);
+ if(e == nil && i->p.npoint < 3)
+ e = TkBadvl;
+ if(e != nil) {
+ tkcvsfreeitem(i);
+ return e;
+ }
+
+ tko[0].ptr = p;
+ tko[0].optab = polyopts;
+ tko[1].ptr = i;
+ tko[1].optab = itemopts;
+ tko[2].ptr = nil;
+ e = tkparse(tk->env->top, arg, tko, nil);
+ if(e != nil) {
+ tkcvsfreeitem(i);
+ return e;
+ }
+ p->canv = c;
+
+ e = tkcaddtag(tk, i, 1);
+ if(e != nil) {
+ tkcvsfreeitem(i);
+ return e;
+ }
+
+ tkcvspolysize(i);
+ tkmkpen(&p->pen, i->env, p->stipple);
+
+ e = tkvalue(val, "%d", i->id);
+ if(e != nil) {
+ tkcvsfreeitem(i);
+ return e;
+ }
+
+ tkcvsappend(c, i);
+ tkbbmax(&c->update, &i->p.bb);
+ tkcvssetdirty(tk);
+ return nil;
+}
+
+char*
+tkcvspolycget(TkCitem *i, char *arg, char **val)
+{
+ TkOptab tko[3];
+ TkCpoly *p = TKobj(TkCpoly, i);
+
+ tko[0].ptr = p;
+ tko[0].optab = polyopts;
+ tko[1].ptr = i;
+ tko[1].optab = itemopts;
+ tko[2].ptr = nil;
+
+ return tkgencget(tko, arg, val, i->env->top);
+}
+
+char*
+tkcvspolyconf(Tk *tk, TkCitem *i, char *arg)
+{
+ char *e;
+ TkOptab tko[3];
+ TkCpoly *p = TKobj(TkCpoly, i);
+
+ tko[0].ptr = p;
+ tko[0].optab = polyopts;
+ tko[1].ptr = i;
+ tko[1].optab = itemopts;
+ tko[2].ptr = nil;
+
+ e = tkparse(tk->env->top, arg, tko, nil);
+
+ tkcvspolysize(i);
+ tkmkpen(&p->pen, i->env, p->stipple);
+
+ return e;
+}
+
+void
+tkcvspolyfree(TkCitem *i)
+{
+ TkCpoly *p;
+
+ p = TKobj(TkCpoly, i);
+ if(p->stipple)
+ freeimage(p->stipple);
+ if(p->pen)
+ freeimage(p->pen);
+}
+
+void
+tkcvspolydraw(Image *img, TkCitem *i, TkEnv *pe)
+{
+ int w;
+ TkEnv *e;
+ TkCpoly *p;
+ Image *pen;
+ Point *pts;
+
+ USED(pe);
+
+ p = TKobj(TkCpoly, i);
+
+ e = i->env;
+
+ pen = p->pen;
+ if(pen == nil && (e->set & (1<<TkCfill)))
+ pen = tkgc(e, TkCfill);
+
+ pts = i->p.drawpt;
+ if(i->p.npoint > 0 && pen != nil) {
+ if (p->smooth == BoolT)
+ fillbezspline(img, pts, i->p.npoint+1, p->winding, pen, pts[0]);
+ else
+ fillpoly(img, pts, i->p.npoint+1, p->winding, pen, pts[0]);
+ }
+
+ w = TKF2I(p->width) - 1;
+ if(w >= 0 && (e->set & (1<<TkCforegnd))) {
+ pen = tkgc(i->env, TkCforegnd);
+ if (p->smooth == BoolT)
+ bezspline(img, pts, i->p.npoint+1, Enddisc, Enddisc, w, pen, pts[0]);
+ else
+ poly(img, pts, i->p.npoint+1, Enddisc, Enddisc, w, pen, pts[0]);
+ }
+}
+
+char*
+tkcvspolycoord(TkCitem *i, char *arg, int x, int y)
+{
+ char *e;
+ TkCpoints p;
+
+ if(arg == nil) {
+ tkxlatepts(i->p.parampt, i->p.npoint, x, y);
+ tkxlatepts(i->p.drawpt, i->p.npoint, TKF2I(x), TKF2I(y));
+ i->p.drawpt[i->p.npoint] = i->p.drawpt[0];
+ i->p.bb = rectaddpt(i->p.bb, Pt(TKF2I(x), TKF2I(y)));
+ }
+ else {
+ e = tkparsepts(i->env->top, &p, &arg, 1);
+ if(e != nil)
+ return e;
+ if(p.npoint < 2) {
+ tkfreepoint(&p);
+ return TkFewpt;
+ }
+ tkfreepoint(&i->p);
+ i->p = p;
+ tkcvspolysize(i);
+ }
+ return nil;
+}
+
+int
+tkcvspolyhit(TkCitem *item, Point p)
+{
+ Point *poly;
+ int r, np, fill, w;
+ TkCpoly *l;
+ TkEnv *e;
+
+ l = TKobj(TkCpoly, item);
+ w = TKF2I(l->width) + 2; /* include some slop */
+ e = item->env;
+ fill = e->set & (1<<TkCfill);
+ if (l->smooth == BoolT) {
+ /* this works but it's slow if used intensively... */
+ np = getbezsplinepts(item->p.drawpt, item->p.npoint + 1, &poly);
+ if (fill)
+ r = tkinsidepoly(poly, np, l->winding, p);
+ else
+ r = tklinehit(poly, np, w, p);
+ free(poly);
+ } else {
+ if (fill)
+ r = tkinsidepoly(item->p.drawpt, item->p.npoint, l->winding, p);
+ else
+ r = tklinehit(item->p.drawpt, item->p.npoint + 1, w, p);
+ }
+ return r;
+}
--- /dev/null
+++ b/libtk/crect.c
@@ -1,0 +1,252 @@
+#include <lib9.h>
+#include <kernel.h>
+#include "draw.h"
+#include "tk.h"
+#include "canvs.h"
+
+#define O(t, e) ((long)(&((t*)0)->e))
+
+/* Rectangle Options (+ means implemented)
+ +fill
+ +outline
+ +stipple
+ +tags
+ +width
+*/
+
+typedef struct TkCrect TkCrect;
+struct TkCrect
+{
+ int width;
+ Image* stipple;
+};
+
+static
+TkOption rectopts[] =
+{
+ "width", OPTnnfrac, O(TkCrect, width), nil,
+ "stipple", OPTbmap, O(TkCrect, stipple), nil,
+ nil
+};
+
+static
+TkOption itemopts[] =
+{
+ "tags", OPTctag, O(TkCitem, tags), nil,
+ "fill", OPTcolr, O(TkCitem, env), IAUX(TkCfill),
+ "outline", OPTcolr, O(TkCitem, env), IAUX(TkCforegnd),
+ nil
+};
+
+void
+tkcvsrectsize(TkCitem *i)
+{
+ TkCrect *r;
+ int w;
+
+ r = TKobj(TkCrect, i);
+ w = TKF2I(r->width)*2;
+
+ i->p.bb = bbnil;
+ tkpolybound(i->p.drawpt, i->p.npoint, &i->p.bb);
+ i->p.bb = insetrect(i->p.bb, -w);
+}
+
+static void
+tkmkstipple(Image *stipple)
+{
+ int locked;
+ if (stipple != nil && !stipple->repl) {
+ locked = lockdisplay(stipple->display);
+ replclipr(stipple, 1, huger);
+ if (locked)
+ unlockdisplay(stipple->display);
+ }
+}
+
+char*
+tkcvsrectcreat(Tk* tk, char *arg, char **val)
+{
+ char *e;
+ TkCrect *r;
+ TkCitem *i;
+ TkCanvas *c;
+ TkOptab tko[3];
+
+ c = TKobj(TkCanvas, tk);
+
+ i = tkcnewitem(tk, TkCVrect, sizeof(TkCitem)+sizeof(TkCrect));
+ if(i == nil)
+ return TkNomem;
+
+ r = TKobj(TkCrect, i);
+ r->width = TKI2F(1);
+
+ e = tkparsepts(tk->env->top, &i->p, &arg, 0);
+ if(e != nil) {
+ tkcvsfreeitem(i);
+ return e;
+ }
+ if(i->p.npoint != 2) {
+ tkcvsfreeitem(i);
+ return TkFewpt;
+ }
+
+ tko[0].ptr = r;
+ tko[0].optab = rectopts;
+ tko[1].ptr = i;
+ tko[1].optab = itemopts;
+ tko[2].ptr = nil;
+ e = tkparse(tk->env->top, arg, tko, nil);
+ if(e != nil) {
+ tkcvsfreeitem(i);
+ return e;
+ }
+ tkmkstipple(r->stipple);
+ e = tkcaddtag(tk, i, 1);
+ if(e != nil) {
+ tkcvsfreeitem(i);
+ return e;
+ }
+
+ tkcvsrectsize(i);
+ e = tkvalue(val, "%d", i->id);
+ if(e != nil) {
+ tkcvsfreeitem(i);
+ return e;
+ }
+ tkcvsappend(c, i);
+
+ tkbbmax(&c->update, &i->p.bb);
+ tkcvssetdirty(tk);
+ return nil;
+}
+
+char*
+tkcvsrectcget(TkCitem *i, char *arg, char **val)
+{
+ TkOptab tko[3];
+ TkCrect *r = TKobj(TkCrect, i);
+
+ tko[0].ptr = r;
+ tko[0].optab = rectopts;
+ tko[1].ptr = i;
+ tko[1].optab = itemopts;
+ tko[2].ptr = nil;
+
+ return tkgencget(tko, arg, val, i->env->top);
+}
+
+char*
+tkcvsrectconf(Tk *tk, TkCitem *i, char *arg)
+{
+ char *e;
+ TkOptab tko[3];
+ TkCrect *r = TKobj(TkCrect, i);
+
+ tko[0].ptr = r;
+ tko[0].optab = rectopts;
+ tko[1].ptr = i;
+ tko[1].optab = itemopts;
+ tko[2].ptr = nil;
+
+ e = tkparse(tk->env->top, arg, tko, nil);
+ tkcvsrectsize(i);
+ tkmkstipple(r->stipple);
+ return e;
+}
+
+void
+tkcvsrectfree(TkCitem *i)
+{
+ TkCrect *r;
+
+ r = TKobj(TkCrect, i);
+ if(r->stipple)
+ freeimage(r->stipple);
+}
+
+void
+tkcvsrectdraw(Image *img, TkCitem *i, TkEnv *pe)
+{
+ int lw, rw;
+ TkEnv *e;
+ TkCrect *r;
+ Rectangle d, rr;
+ Point tr, bl;
+ Image *pen;
+
+ USED(pe);
+
+ d.min = i->p.drawpt[0];
+ d.max = i->p.drawpt[1];
+
+ e = i->env;
+ r = TKobj(TkCrect, i);
+
+ pen = nil;
+ if((e->set & (1<<TkCfill)))
+ pen = tkgc(e, TkCfill);
+
+ if(pen != nil)
+ draw(img, d, pen, r->stipple, d.min);
+
+ tr.x = d.max.x;
+ tr.y = d.min.y;
+ bl.x = d.min.x;
+ bl.y = d.max.y;
+
+ rw = (TKF2I(r->width) + 1)/2;
+ if(rw <= 0)
+ return;
+ lw = (TKF2I(r->width))/2;
+
+ pen = tkgc(e, TkCforegnd);
+ if(pen != nil) {
+ /* horizontal lines first */
+ rr.min.x = d.min.x - lw;
+ rr.max.x = d.max.x + rw;
+ rr.min.y = d.min.y - lw;
+ rr.max.y = d.min.y + rw;
+ draw(img, rr, pen, nil, rr.min);
+ rr.min.y += Dy(d);
+ rr.max.y += Dy(d);
+ draw(img, rr, pen, nil, rr.min);
+ /* now the vertical */
+ /* horizontal lines first */
+ rr.min.x = d.min.x - lw;
+ rr.max.x = d.min.x + rw;
+ rr.min.y = d.min.y + rw;
+ rr.max.y = d.max.y - lw;
+ draw(img, rr, pen, nil, rr.min);
+ rr.min.x += Dx(d);
+ rr.max.x += Dx(d);
+ draw(img, rr, pen, nil, rr.min);
+ }
+}
+
+char*
+tkcvsrectcoord(TkCitem *i, char *arg, int x, int y)
+{
+ char *e;
+ TkCpoints p;
+
+ if(arg == nil) {
+ tkxlatepts(i->p.parampt, i->p.npoint, x, y);
+ tkxlatepts(i->p.drawpt, i->p.npoint, TKF2I(x), TKF2I(y));
+ i->p.bb = rectaddpt(i->p.bb, Pt(TKF2I(x), TKF2I(y)));
+ }
+ else {
+ e = tkparsepts(i->env->top, &p, &arg, 0);
+ if(e != nil)
+ return e;
+ if(p.npoint != 2) {
+ tkfreepoint(&p);
+ return TkFewpt;
+ }
+ tkfreepoint(&i->p);
+ i->p = p;
+ tkcvsrectsize(i);
+ }
+ return nil;
+}
--- /dev/null
+++ b/libtk/ctext.c
@@ -1,0 +1,666 @@
+#include <lib9.h>
+#include <kernel.h>
+#include "draw.h"
+#include "tk.h"
+#include "canvs.h"
+
+#define O(t, e) ((long)(&((t*)0)->e))
+
+/* Text Options (+ means implemented)
+ +anchor
+ +fill
+ +font
+ +justify
+ +stipple
+ +tags
+ +text
+ +width
+*/
+
+/* Layout constants */
+enum {
+ Cvsicursor = 1, /* Extra height of insertion cursor in canvas */
+};
+
+typedef struct TkCtext TkCtext;
+struct TkCtext
+{
+ int anchor;
+ Point anchorp;
+ int justify;
+ int icursor;
+ int focus;
+ int pixwidth;
+ int pixheight;
+ int sell;
+ int self;
+ int selfrom;
+ int sbw;
+ int width;
+ int nlines;
+ Image* stipple;
+ Image* pen;
+ char* text;
+ int tlen;
+ TkEnv *env;
+};
+
+static
+TkOption textopts[] =
+{
+ "anchor", OPTstab, O(TkCtext, anchor), tkanchor,
+ "justify", OPTstab, O(TkCtext, justify), tktabjust,
+ "width", OPTdist, O(TkCtext, width), IAUX(O(TkCtext, env)),
+ "stipple", OPTbmap, O(TkCtext, stipple), nil,
+ "text", OPTtext, O(TkCtext, text), nil,
+ nil
+};
+
+static
+TkOption itemopts[] =
+{
+ "tags", OPTctag, O(TkCitem, tags), nil,
+ "font", OPTfont, O(TkCitem, env), nil,
+ "fill", OPTcolr, O(TkCitem, env), IAUX(TkCfill),
+ nil
+};
+
+static char*
+tkcvstextgetl(TkCtext *t, Font *font, char *start, int *len)
+{
+ int w, n;
+ char *lspc, *posn;
+
+ w = t->width;
+ if(w <= 0)
+ w = 1000000;
+
+ n = 0;
+ lspc = nil;
+ posn = start;
+ while(*posn && *posn != '\n') {
+ if(*posn == ' ')
+ lspc = posn;
+ n += stringnwidth(font, posn, 1);
+ if(n >= w && posn != start) {
+ if(lspc != nil)
+ posn = lspc;
+ *len = posn - start;
+ if(lspc != nil)
+ posn++;
+ return posn;
+ }
+ posn++;
+ }
+ *len = posn - start;
+ if(*posn == '\n')
+ posn++;
+ return posn;
+}
+
+void
+tkcvstextsize(TkCitem *i)
+{
+ Point o;
+ Font *font;
+ TkCtext *t;
+ Display *d;
+ char *next, *p;
+ int len, pixw, locked;
+
+ t = TKobj(TkCtext, i);
+
+ font = i->env->font;
+ d = i->env->top->display;
+ t->pixwidth = 0;
+ t->pixheight = 0;
+
+ p = t->text;
+ if(p != nil) {
+ locked = lockdisplay(d);
+ while(*p) {
+ next = tkcvstextgetl(t, font, p, &len);
+ pixw = stringnwidth(font, p, len);
+ if(pixw > t->pixwidth)
+ t->pixwidth = pixw;
+ t->pixheight += font->height;
+ p = next;
+ }
+ if(locked)
+ unlockdisplay(d);
+ }
+
+ o = tkcvsanchor(i->p.drawpt[0], t->pixwidth, t->pixheight, t->anchor);
+
+ i->p.bb.min.x = o.x;
+ i->p.bb.min.y = o.y - Cvsicursor;
+ i->p.bb.max.x = o.x + t->pixwidth;
+ i->p.bb.max.y = o.y + t->pixheight + Cvsicursor;
+ i->p.bb = insetrect(i->p.bb, -2*t->sbw);
+ t->anchorp = subpt(o, i->p.drawpt[0]);
+}
+
+char*
+tkcvstextcreat(Tk* tk, char *arg, char **val)
+{
+ char *e;
+ TkCtext *t;
+ TkCitem *i;
+ TkCanvas *c;
+ TkOptab tko[3];
+
+ c = TKobj(TkCanvas, tk);
+
+ i = tkcnewitem(tk, TkCVtext, sizeof(TkCitem)+sizeof(TkCtext));
+ if(i == nil)
+ return TkNomem;
+
+ t = TKobj(TkCtext, i);
+ t->justify = Tkleft;
+ t->anchor = Tkcenter;
+ t->sell = -1;
+ t->self = -1;
+ t->icursor = -1;
+ t->sbw = c->sborderwidth;
+ t->env = tk->env;
+
+ e = tkparsepts(tk->env->top, &i->p, &arg, 0);
+ if(e != nil) {
+ tkcvsfreeitem(i);
+ return e;
+ }
+ if(i->p.npoint != 1) {
+ tkcvsfreeitem(i);
+ return TkFewpt;
+ }
+
+ tko[0].ptr = t;
+ tko[0].optab = textopts;
+ tko[1].ptr = i;
+ tko[1].optab = itemopts;
+ tko[2].ptr = nil;
+ e = tkparse(tk->env->top, arg, tko, nil);
+ if(e != nil) {
+ tkcvsfreeitem(i);
+ return e;
+ }
+
+ e = tkcaddtag(tk, i, 1);
+ if(e != nil) {
+ tkcvsfreeitem(i);
+ return e;
+ }
+
+ t->tlen = 0;
+ if(t->text != nil)
+ t->tlen = strlen(t->text);
+
+ tkmkpen(&t->pen, i->env, t->stipple);
+ tkcvstextsize(i);
+ e = tkvalue(val, "%d", i->id);
+ if(e != nil) {
+ tkcvsfreeitem(i);
+ return e;
+ }
+
+ tkcvsappend(c, i);
+
+ tkbbmax(&c->update, &i->p.bb);
+ tkcvssetdirty(tk);
+ return nil;
+}
+
+char*
+tkcvstextcget(TkCitem *i, char *arg, char **val)
+{
+ TkOptab tko[3];
+ TkCtext *t = TKobj(TkCtext, i);
+
+ tko[0].ptr = t;
+ tko[0].optab = textopts;
+ tko[1].ptr = i;
+ tko[1].optab = itemopts;
+ tko[2].ptr = nil;
+
+ return tkgencget(tko, arg, val, i->env->top);
+}
+
+char*
+tkcvstextconf(Tk *tk, TkCitem *i, char *arg)
+{
+ char *e;
+ TkOptab tko[3];
+ TkCtext *t = TKobj(TkCtext, i);
+
+ tko[0].ptr = t;
+ tko[0].optab = textopts;
+ tko[1].ptr = i;
+ tko[1].optab = itemopts;
+ tko[2].ptr = nil;
+
+ e = tkparse(tk->env->top, arg, tko, nil);
+
+ t->tlen = 0;
+ if(t->text != nil)
+ t->tlen = strlen(t->text);
+
+ tkmkpen(&t->pen, i->env, t->stipple);
+ tkcvstextsize(i);
+
+ return e;
+}
+
+void
+tkcvstextfree(TkCitem *i)
+{
+ TkCtext *t;
+
+ t = TKobj(TkCtext, i);
+ if(t->stipple != nil)
+ freeimage(t->stipple);
+ if(t->pen != nil)
+ freeimage(t->pen);
+ if(t->text != nil)
+ free(t->text);
+}
+
+void
+tkcvstextdraw(Image *img, TkCitem *i, TkEnv *pe)
+{
+ TkEnv *e;
+ TkCtext *t;
+ Point o, dp;
+ Rectangle r;
+ char *p, *next;
+ Image *pen;
+ int len, lw, end, start;
+
+ t = TKobj(TkCtext, i);
+
+ e = i->env;
+ pen = t->pen;
+ if(pen == nil) {
+ if (e->set & (1<<TkCfill))
+ pen = tkgc(e, TkCfill);
+ else
+ pen = img->display->black;
+ }
+
+
+ o = addpt(t->anchorp, i->p.drawpt[0]);
+ p = t->text;
+ while(p && *p) {
+ next = tkcvstextgetl(t, e->font, p, &len);
+ dp = o;
+ if(t->justify != Tkleft) {
+ lw = stringnwidth(e->font, p, len);
+ if(t->justify == Tkcenter)
+ dp.x += (t->pixwidth - lw)/2;
+ else
+ if(t->justify == Tkright)
+ dp.x += t->pixwidth - lw;
+ }
+ lw = p - t->text;
+ if(t->self != -1 && lw+len > t->self) {
+ if(t->sell >= t->self) {
+ start = t->self - lw;
+ end = t->sell - lw;
+ }
+ else {
+ start = t->sell - lw;
+ end = t->self - lw;
+ }
+ if(start < 0)
+ r.min.x = o.x;
+ else
+ r.min.x = dp.x + stringnwidth(e->font, p, start);
+ r.min.y = dp.y;
+ if(end > len)
+ r.max.x = o.x + t->pixwidth;
+ else
+ r.max.x = dp.x + stringnwidth(e->font, p, end);
+ r.max.y = dp.y + e->font->height;
+ tktextsdraw(img, r, pe, t->sbw);
+ r.max.y = dp.y;
+ if(start > 0)
+ stringn(img, dp, pen, dp, e->font, p, start);
+ if(end > start)
+ stringn(img, r.min, tkgc(pe, TkCselectfgnd), r.min, e->font, p+start, end-start);
+ if(len > end)
+ stringn(img, r.max, pen, r.max, e->font, p+end, len-end);
+ }
+ else
+ stringn(img, dp, pen, dp, e->font, p, len);
+ if(t->focus) {
+ lw = p - t->text;
+ if(t->icursor >= lw && t->icursor <= lw+len) {
+ lw = t->icursor - lw;
+ if(lw > 0)
+ lw = stringnwidth(e->font, p, lw);
+ r.min.x = dp.x + lw;
+ r.min.y = dp.y - 1;
+ r.max.x = r.min.x + 2;
+ r.max.y = r.min.y + e->font->height + 1;
+ draw(img, r, pen, nil, ZP);
+ }
+ }
+ o.y += e->font->height;
+ p = next;
+ }
+}
+
+char*
+tkcvstextcoord(TkCitem *i, char *arg, int x, int y)
+{
+ char *e;
+ TkCpoints p;
+
+ if(arg == nil) {
+ tkxlatepts(i->p.parampt, i->p.npoint, x, y);
+ tkxlatepts(i->p.drawpt, i->p.npoint, TKF2I(x), TKF2I(y));
+ i->p.bb = rectaddpt(i->p.bb, Pt(TKF2I(x), TKF2I(y)));
+ }
+ else {
+ e = tkparsepts(i->env->top, &p, &arg, 0);
+ if(e != nil)
+ return e;
+ if(p.npoint != 1) {
+ tkfreepoint(&p);
+ return TkFewpt;
+ }
+ tkfreepoint(&i->p);
+ i->p = p;
+ tkcvstextsize(i);
+ }
+ return nil;
+}
+
+int
+tkcvstextsrch(TkCitem *i, int x, int y)
+{
+ TkCtext *t;
+ Font *font;
+ Display *d;
+ char *p, *next;
+ int n, len, locked;
+
+ t = TKobj(TkCtext, i);
+
+ n = 0;
+ font = i->env->font;
+ d = i->env->top->display;
+ p = t->text;
+ if(p == nil)
+ return 0;
+ while(*p) {
+ next = tkcvstextgetl(t, font, p, &len);
+ if(y <= font->height) {
+ locked = lockdisplay(d);
+ for(n = 0; n < len && x > stringnwidth(font, p, n+1); n++)
+ ;
+ if(locked)
+ unlockdisplay(d);
+ break;
+ }
+ y -= font->height;
+ p = next;
+ }
+ return p - t->text + n;
+}
+
+static char*
+tkcvsparseindex(TkCitem *i, char *buf, int *index)
+{
+ Point o;
+ char *p;
+ int x, y;
+ TkCtext *t;
+
+ t = TKobj(TkCtext, i);
+
+ if(strcmp(buf, "end") == 0) {
+ *index = t->tlen;
+ return nil;
+ }
+ if(strcmp(buf, "sel.first") == 0) {
+ if(t->self < 0)
+ return TkBadix;
+ *index = t->self;
+ return nil;
+ }
+ if(strcmp(buf, "sel.last") == 0) {
+ if(t->sell < 0)
+ return TkBadix;
+ *index = t->sell;
+ return nil;
+ }
+ if(strcmp(buf, "insert") == 0) {
+ *index = t->icursor;
+ return nil;
+ }
+ if(buf[0] == '@') {
+ x = atoi(buf+1);
+ p = strchr(buf, ',');
+ if(p == nil)
+ return TkBadix;
+ y = atoi(p+1);
+ o = i->p.drawpt[0];
+ *index = tkcvstextsrch(i, (x-t->anchorp.x)-o.x, (y-t->anchorp.y)-o.y);
+ return nil;
+ }
+
+ if(buf[0] < '0' || buf[0] > '9')
+ return TkBadix;
+ x = atoi(buf);
+ if(x < 0)
+ x = 0;
+ if(x > t->tlen)
+ x = t->tlen;
+ *index = x;
+ return nil;
+}
+
+char*
+tkcvstextdchar(Tk *tk, TkCitem *i, char *arg)
+{
+ TkTop *top;
+ TkCtext *t;
+ int first, last;
+ char *e, buf[Tkmaxitem];
+
+ t = TKobj(TkCtext, i);
+
+ top = tk->env->top;
+ arg = tkword(top, arg, buf, buf+sizeof(buf), nil);
+ e = tkcvsparseindex(i, buf, &first);
+ if(e != nil)
+ return e;
+
+ last = first+1;
+ if(*arg != '\0') {
+ tkword(top, arg, buf, buf+sizeof(buf), nil);
+ e = tkcvsparseindex(i, buf, &last);
+ if(e != nil)
+ return e;
+ }
+ if(last <= first || t->tlen == 0)
+ return nil;
+
+ tkbbmax(&TKobj(TkCanvas, tk)->update, &i->p.bb);
+
+ memmove(t->text+first, t->text+last, t->tlen-last+1);
+ t->tlen -= last-first;
+
+ tkcvstextsize(i);
+ tkbbmax(&TKobj(TkCanvas, tk)->update, &i->p.bb);
+
+ tkcvssetdirty(tk);
+ return nil;
+}
+
+char*
+tkcvstextinsert(Tk *tk, TkCitem *i, char *arg)
+{
+ TkTop *top;
+ TkCtext *t;
+ int first, n;
+ char *e, *text, buf[Tkmaxitem];
+
+ t = TKobj(TkCtext, i);
+
+ top = tk->env->top;
+ arg = tkword(top, arg, buf, buf+sizeof(buf), nil);
+ e = tkcvsparseindex(i, buf, &first);
+ if(e != nil)
+ return e;
+
+ if(*arg == '\0')
+ return nil;
+
+ text = malloc(Tkcvstextins);
+ if(text == nil)
+ return TkNomem;
+
+ tkword(top, arg, text, text+Tkcvstextins, nil);
+ n = strlen(text);
+ t->text = realloc(t->text, t->tlen+n+1);
+ if(t->text == nil) {
+ free(text);
+ return TkNomem;
+ }
+ if(t->tlen == 0)
+ t->text[0] = '\0';
+
+ tkbbmax(&TKobj(TkCanvas, tk)->update, &i->p.bb);
+
+ memmove(t->text+first+n, t->text+first, t->tlen-first+1);
+ memmove(t->text+first, text, n);
+ t->tlen += n;
+ free(text);
+
+ tkcvstextsize(i);
+ tkbbmax(&TKobj(TkCanvas, tk)->update, &i->p.bb);
+
+ tkcvssetdirty(tk);
+ return nil;
+}
+
+char*
+tkcvstextindex(Tk *tk, TkCitem *i, char *arg, char **val)
+{
+ int first;
+ char *e, buf[Tkmaxitem];
+
+ tkword(tk->env->top, arg, buf, buf+sizeof(buf), nil);
+ e = tkcvsparseindex(i, buf, &first);
+ if(e != nil)
+ return e;
+
+ return tkvalue(val, "%d", first);
+}
+
+char*
+tkcvstexticursor(Tk *tk, TkCitem *i, char *arg)
+{
+ int first;
+ TkCanvas *c;
+ char *e, buf[Tkmaxitem];
+
+ tkword(tk->env->top, arg, buf, buf+sizeof(buf), nil);
+ e = tkcvsparseindex(i, buf, &first);
+ if(e != nil)
+ return e;
+
+ TKobj(TkCtext, i)->icursor = first;
+
+ c = TKobj(TkCanvas, tk);
+ if(c->focus == i) {
+ tkbbmax(&c->update, &i->p.bb);
+ tkcvssetdirty(tk);
+ }
+ return nil;
+}
+
+void
+tkcvstextfocus(Tk *tk, TkCitem *i, int x)
+{
+ TkCtext *t;
+ TkCanvas *c;
+
+ if(i == nil)
+ return;
+
+ t = TKobj(TkCtext, i);
+ c = TKobj(TkCanvas, tk);
+
+ if(t->focus != x) {
+ t->focus = x;
+ tkbbmax(&c->update, &i->p.bb);
+ tkcvssetdirty(tk);
+ }
+}
+
+void
+tkcvstextclr(Tk *tk)
+{
+ TkCtext *t;
+ TkCanvas *c;
+ TkCitem *item;
+
+ c = TKobj(TkCanvas, tk);
+ item = c->selection;
+ if(item == nil)
+ return;
+
+ c->selection = nil;
+ t = TKobj(TkCtext, item);
+ t->sell = -1;
+ t->self = -1;
+ tkbbmax(&c->update, &item->p.bb);
+ tkcvssetdirty(tk);
+}
+
+char*
+tkcvstextselect(Tk *tk, TkCitem *i, char *arg, int op)
+{
+ int indx;
+ TkCtext *t;
+ TkCanvas *c;
+ char *e, buf[Tkmaxitem];
+
+ tkword(tk->env->top, arg, buf, buf+sizeof(buf), nil);
+ e = tkcvsparseindex(i, buf, &indx);
+ if(e != nil)
+ return e;
+
+ c = TKobj(TkCanvas, tk);
+ t = TKobj(TkCtext, i);
+ switch(op) {
+ case TkCselfrom:
+ t->selfrom = indx;
+ return nil;
+ case TkCseladjust:
+ if(c->selection == i) {
+ if(abs(t->self-indx) < abs(t->sell-indx)) {
+ t->self = indx;
+ t->selfrom = t->sell;
+ }
+ else {
+ t->sell = indx;
+ t->selfrom = t->self;
+ }
+ }
+ /* No break */
+ case TkCselto:
+ if(c->selection != i)
+ tkcvstextclr(tk);
+ c->selection = i;
+ t->self = t->selfrom;
+ t->sell = indx;
+ break;
+ }
+ t->sbw = c->sborderwidth;
+ tkbbmax(&TKobj(TkCanvas, tk)->update, &i->p.bb);
+ tkcvssetdirty(tk);
+ return nil;
+}
--- /dev/null
+++ b/libtk/cwind.c
@@ -1,0 +1,438 @@
+#include "lib9.h"
+#include "draw.h"
+#include "tk.h"
+#include "canvs.h"
+
+#define O(t, e) ((long)(&((t*)0)->e))
+
+/* Window Options (+ means implemented)
+ +tags
+ +width
+ +height
+ +window
+ +anchor
+*/
+
+static
+TkOption windopts[] =
+{
+ "width", OPTdist, O(TkCwind, width), nil,
+ "height", OPTdist, O(TkCwind, height), nil,
+ "anchor", OPTstab, O(TkCwind, flags), tkanchor,
+ "window", OPTwinp, O(TkCwind, sub), nil,
+ nil
+};
+
+static
+TkOption itemopts[] =
+{
+ "tags", OPTctag, O(TkCitem, tags), nil,
+ nil
+};
+
+static void
+tkcvswindsize(TkCitem *i)
+{
+ Tk *s;
+ int bw;
+ Point p;
+ TkGeom old;
+ TkCwind *w;
+
+ w = TKobj(TkCwind, i);
+ s = w->sub;
+ if(s == nil)
+ return;
+
+ if(w->width != s->act.width || w->height != s->act.height) {
+ old = s->act;
+ s->act.width = w->width;
+ s->act.height = w->height;
+ if(s->slave) {
+ tkpackqit(s);
+ tkrunpack(s->env->top);
+ }
+ tkdeliver(s, TkConfigure, &old);
+ }
+ p = tkcvsanchor(i->p.drawpt[0], s->act.width, s->act.height, w->flags);
+ s->act.x = p.x;
+ s->act.y = p.y;
+
+ bw = 2*s->borderwidth;
+ i->p.bb.min = p;
+ i->p.bb.max.x = p.x + s->act.width + bw;
+ i->p.bb.max.y = p.y + s->act.height + bw;
+}
+
+TkCitem*
+tkcvsfindwin(Tk *tk)
+{
+ Tk *parent, *sub;
+ TkCitem *i;
+ TkCanvas *c;
+ TkCwind *w;
+
+ sub = tkfindsub(tk);
+ if(sub == nil)
+ return nil;
+ parent = sub->parent;
+ if(parent->type != TKcanvas)
+ return nil; /* inconsistent */
+ c = TKobj(TkCanvas, parent);
+ for(i = c->head; i != nil; i = i->next) {
+ if(i->type == TkCVwindow) {
+ w = TKobj(TkCwind, i);
+ if(w->sub == sub)
+ return i;
+ }
+ }
+ return nil;
+}
+
+void
+tkcvsforgetsub(Tk *sub, Tk *tk)
+{
+ TkCwind *w;
+ TkCitem *i;
+
+ i = tkcvsfindwin(sub);
+ if(i == nil)
+ return;
+ w = TKobj(TkCwind, i);
+ if(w->focus == tk) {
+if(0)print("tkcsvsforget sub %p %q focus %p %q\n", sub, tkname(sub), tk, tkname(tk));
+ w->focus = nil;
+ }
+}
+
+static void
+tkcvswindgeom(Tk *sub, int x, int y, int w, int h)
+{
+ TkCitem *i;
+ Tk *parent;
+ TkCanvas *c;
+ TkCwind *win;
+
+ USED(x);
+ USED(y);
+ parent = sub->parent;
+ win = nil;
+ c = TKobj(TkCanvas, parent);
+ for(i = c->head; i; i = i->next) {
+ if(i->type == TkCVwindow) {
+ win = TKobj(TkCwind, i);
+ if(win->sub == sub)
+ break;
+ }
+ }
+
+ tkbbmax(&c->update, &i->p.bb);
+
+ if((win->flags & Tksetwidth) == 0)
+ win->width = w;
+ if ((win->flags & Tksetheight) == 0)
+ win->height = h;
+
+ sub->req.width = w;
+ sub->req.height = h;
+ tkcvswindsize(i);
+
+ tkbbmax(&c->update, &i->p.bb);
+ tkcvsdirty(parent);
+}
+
+static void
+tkcvssubdestry(Tk *sub)
+{
+ Tk *tk;
+ TkCitem *i;
+ TkCanvas *c;
+ TkCwind *win;
+
+ tk = sub->parent;
+ if(tk == nil)
+ return;
+
+if(0)print("tkcvssubdestry %p %q\n", sub, tkname(sub));
+ i = tkcvsfindwin(sub);
+ if(i == nil)
+ return;
+ win = TKobj(TkCwind, i);
+ if(win->sub != sub){
+ if(win->sub != nil)
+ print("inconsistent tkcvssubdestry %p %q\n", sub, tkname(sub));
+ return;
+ }
+
+ c = TKobj(TkCanvas, tk);
+ tkbbmax(&c->update, &i->p.bb);
+ tkcvssetdirty(tk);
+
+ win->focus = nil;
+ win->sub = nil;
+ sub->parent = nil;
+ sub->geom = nil;
+}
+
+Point
+tkcvsrelpos(Tk *sub)
+{
+ Tk *tk;
+ TkCitem *i;
+ TkCanvas *c;
+ TkCwind *win;
+
+ tk = sub->parent;
+ if(tk == nil)
+ return ZP;
+
+ c = TKobj(TkCanvas, tk);
+ for(i = c->head; i; i = i->next) {
+ if(i->type == TkCVwindow) {
+ win = TKobj(TkCwind, i);
+ if(win->sub == sub)
+ return subpt(i->p.bb.min, c->view);
+ }
+ }
+ return ZP;
+}
+
+static char*
+tkcvswindchk(Tk *tk, TkCwind *w, Tk *oldsub)
+{
+ Tk *sub;
+
+ sub = w->sub;
+ if (sub != oldsub) {
+ w->sub = oldsub;
+ if(sub == nil)
+ return nil;
+
+ if(sub->flag & Tkwindow)
+ return TkIstop;
+
+ if(sub->master != nil || sub->parent != nil)
+ return TkWpack;
+
+ if (oldsub != nil) {
+ oldsub->parent = nil;
+ oldsub->geom = nil;
+ oldsub->destroyed = nil;
+ }
+ w->sub = sub;
+ w->focus = nil;
+ sub->parent = tk;
+ tksetbits(w->sub, Tksubsub);
+ sub->geom = tkcvswindgeom;
+ sub->destroyed = tkcvssubdestry;
+
+ if(w->width == 0)
+ w->width = sub->req.width;
+ if(w->height == 0)
+ w->height = sub->req.height;
+ }
+
+ return nil;
+}
+
+char*
+tkcvswindcreat(Tk* tk, char *arg, char **val)
+{
+ char *e;
+ TkCwind *w;
+ TkCitem *i;
+ TkCanvas *c;
+ TkOptab tko[3];
+
+ c = TKobj(TkCanvas, tk);
+
+ i = tkcnewitem(tk, TkCVwindow, sizeof(TkCitem)+sizeof(TkCwind));
+ if(i == nil)
+ return TkNomem;
+
+ w = TKobj(TkCwind, i);
+ w->flags = Tkcenter;
+
+ e = tkparsepts(tk->env->top, &i->p, &arg, 0);
+ if(e != nil) {
+ tkcvsfreeitem(i);
+ return e;
+ }
+ if(i->p.npoint != 1) {
+ tkcvsfreeitem(i);
+ return TkFewpt;
+ }
+
+ tko[0].ptr = w;
+ tko[0].optab = windopts;
+ tko[1].ptr = i;
+ tko[1].optab = itemopts;
+ tko[2].ptr = nil;
+ e = tkparse(tk->env->top, arg, tko, nil);
+ if(e != nil) {
+ tkcvsfreeitem(i);
+ return e;
+ }
+ e = tkcvswindchk(tk, w, nil);
+ if(e != nil) {
+ tkcvsfreeitem(i);
+ return e;
+ }
+
+ e = tkcaddtag(tk, i, 1);
+ if(e != nil) {
+ tkcvsfreeitem(i);
+ return e;
+ }
+
+ e = tkvalue(val, "%d", i->id);
+ if(e != nil) {
+ tkcvsfreeitem(i);
+ return e;
+ }
+ tkcvsappend(c, i);
+ tkcvswindsize(i);
+
+ tkbbmax(&c->update, &i->p.bb);
+ tkcvssetdirty(tk);
+ return nil;
+}
+
+char*
+tkcvswindcget(TkCitem *i, char *arg, char **val)
+{
+ TkOptab tko[3];
+ TkCwind *w = TKobj(TkCwind, i);
+
+ tko[0].ptr = w;
+ tko[0].optab = windopts;
+ tko[1].ptr = i;
+ tko[1].optab = itemopts;
+ tko[2].ptr = nil;
+
+ return tkgencget(tko, arg, val, i->env->top);
+}
+
+char*
+tkcvswindconf(Tk *tk, TkCitem *i, char *arg)
+{
+ char *e;
+ int dx, dy;
+ TkOptab tko[3];
+ TkCwind *w = TKobj(TkCwind, i);
+ Tk *oldsub;
+
+ tko[0].ptr = w;
+ tko[0].optab = windopts;
+ tko[1].ptr = i;
+ tko[1].optab = itemopts;
+ tko[2].ptr = nil;
+
+ dx = w->width;
+ dy = w->height;
+ w->width = -1;
+ w->height = -1;
+
+ oldsub = w->sub;
+ e = tkparse(tk->env->top, arg, tko, nil);
+ if(e == nil) {
+ e = tkcvswindchk(tk, w, oldsub);
+ if(e != nil)
+ return e;
+ if(w->width == -1)
+ w->width = dx;
+ else
+ w->flags |= Tksetwidth;
+ if(w->height == -1)
+ w->height = dy;
+ else
+ w->flags |= Tksetheight;
+ tkcvswindsize(i);
+ } else {
+ w->width = dx;
+ w->height = dy;
+ }
+ return e;
+}
+
+void
+tkcvswindfree(TkCitem *i)
+{
+ Tk *sub;
+ TkCwind *w;
+
+ w = TKobj(TkCwind, i);
+ sub = w->sub;
+ if(sub != nil) {
+ sub->parent = nil;
+ sub->geom = nil;
+ sub->destroyed = nil;
+ }
+ w->focus = nil;
+ w->sub = nil;
+}
+
+void
+tkcvswinddraw(Image *img, TkCitem *i, TkEnv *pe)
+{
+ TkCwind *w;
+ Point rel;
+ Rectangle r;
+ Tk *sub;
+
+ USED(img); /* See tkimageof */
+ USED(pe);
+ w = TKobj(TkCwind, i);
+ sub = w->sub;
+ if(sub != nil) {
+ int dirty;
+ r = i->p.bb;
+ rel.x = r.min.x + sub->borderwidth;
+ rel.y = r.min.y + sub->borderwidth;
+ if (rectclip(&r, img->clipr)) {
+ sub->dirty = rectsubpt(r, rel);
+ sub->flag |= Tkrefresh;
+ tkdrawslaves(sub, ZP, &dirty); /* XXX - Tad: propagate err? */
+ }
+ }
+}
+
+char*
+tkcvswindcoord(TkCitem *i, char *arg, int x, int y)
+{
+ char *e;
+ TkCpoints p;
+/*
+ TkCwind *w;
+ int xi, yi;
+*/
+
+ if(arg == nil) {
+ tkxlatepts(i->p.parampt, i->p.npoint, x, y);
+ tkxlatepts(i->p.drawpt, i->p.npoint, TKF2I(x), TKF2I(y));
+ tkcvswindsize(i);
+/*
+ w = TKobj(TkCwind, i);
+ xi = TKF2I(x);
+ yi = TKF2I(y);
+ if (w->sub != nil) {
+ w->sub->act.x += xi;
+ w->sub->act.y += yi;
+ }
+ i->p.bb = rectaddpt(i->p.bb, Pt(xi, yi));
+*/
+ }
+ else {
+ e = tkparsepts(i->env->top, &p, &arg, 0);
+ if(e != nil)
+ return e;
+ if(p.npoint != 1) {
+ tkfreepoint(&p);
+ return TkFewpt;
+ }
+ tkfreepoint(&i->p);
+ i->p = p;
+ tkcvswindsize(i);
+ }
+ return nil;
+}
--- /dev/null
+++ b/libtk/ebind.c
@@ -1,0 +1,1028 @@
+#include "lib9.h"
+#include "draw.h"
+#include "tk.h"
+#include <kernel.h>
+#include <interp.h>
+
+enum
+{
+ Cmask,
+ Cctl,
+ Ckey,
+ Cbp,
+ Cbr,
+};
+
+struct
+{
+ char* event;
+ int mask;
+ int action;
+} etab[] =
+{
+ "Motion", TkMotion, Cmask,
+ "Double", TkDouble, Cmask,
+ "Map", TkMap, Cmask,
+ "Unmap", TkUnmap, Cmask,
+ "Destroy", TkDestroy, Cmask,
+ "Enter", TkEnter, Cmask,
+ "Leave", TkLeave, Cmask,
+ "FocusIn", TkFocusin, Cmask,
+ "FocusOut", TkFocusout, Cmask,
+ "Configure", TkConfigure, Cmask,
+ "Control", 0, Cctl,
+ "Key", 0, Ckey,
+ "KeyPress", 0, Ckey,
+ "Button", 0, Cbp,
+ "ButtonPress", 0, Cbp,
+ "ButtonRelease", 0, Cbr,
+};
+
+static
+TkOption tkcurop[] =
+{
+ "x", OPTdist, O(TkCursor, p.x), nil,
+ "y", OPTdist, O(TkCursor, p.y), nil,
+ "bitmap", OPTbmap, O(TkCursor, bit), nil,
+ "image", OPTimag, O(TkCursor, img), nil,
+ "default", OPTbool, O(TkCursor, def), nil,
+ nil
+};
+
+static
+TkOption focusopts[] = {
+ "global", OPTbool, 0, nil,
+ nil
+};
+
+static char*
+tkseqitem(char *buf, char *arg)
+{
+ while(*arg && (*arg == ' ' || *arg == '-'))
+ arg++;
+ while(*arg && *arg != ' ' && *arg != '-' && *arg != '>')
+ *buf++ = *arg++;
+ *buf = '\0';
+ return arg;
+}
+
+static char*
+tkseqkey(Rune *r, char *arg)
+{
+ char *narg;
+
+ while(*arg && (*arg == ' ' || *arg == '-'))
+ arg++;
+ if (*arg == '\\') {
+ if (*++arg == '\0') {
+ *r = 0;
+ return arg;
+ }
+ } else if (*arg == '\0' || *arg == '>' || *arg == '-') {
+ *r = 0;
+ return arg;
+ }
+ narg = arg + chartorune(r, arg);
+ return narg;
+}
+
+int
+tkseqparse(char *seq)
+{
+ Rune r;
+ int i, event;
+ char *buf;
+
+ buf = mallocz(Tkmaxitem, 0);
+ if(buf == nil)
+ return -1;
+
+ event = 0;
+
+ while(*seq && *seq != '>') {
+ seq = tkseqitem(buf, seq);
+
+ for(i = 0; i < nelem(etab); i++)
+ if(strcmp(buf, etab[i].event) == 0)
+ break;
+
+ if(i >= nelem(etab)) {
+ seq = tkextnparseseq(buf, seq, &event);
+ if (seq == nil) {
+ free(buf);
+ return -1;
+ }
+ continue;
+ }
+
+
+ switch(etab[i].action) {
+ case Cmask:
+ event |= etab[i].mask;
+ break;
+ case Cctl:
+ seq = tkseqkey(&r, seq);
+ if(r == 0) {
+ free(buf);
+ return -1;
+ }
+ if(r <= '~')
+ r &= 0x1f;
+ event |= TkKey|TKKEY(r);
+ break;
+ case Ckey:
+ seq = tkseqkey(&r, seq);
+ if(r != 0)
+ event |= TKKEY(r);
+ event |= TkKey;
+ break;
+ case Cbp:
+ seq = tkseqitem(buf, seq);
+ switch(buf[0]) {
+ default:
+ free(buf);
+ return -1;
+ case '\0':
+ event |= TkEpress;
+ break;
+ case '1':
+ event |= TkButton1P;
+ break;
+ case '2':
+ event |= TkButton2P;
+ break;
+ case '3':
+ event |= TkButton3P;
+ break;
+ case '4':
+ event |= TkButton4P;
+ break;
+ case '5':
+ event |= TkButton5P;
+ break;
+ case '6':
+ event |= TkButton6P;
+ break;
+ }
+ break;
+ case Cbr:
+ seq = tkseqitem(buf, seq);
+ switch(buf[0]) {
+ default:
+ free(buf);
+ return -1;
+ case '\0':
+ event |= TkErelease;
+ break;
+ case '1':
+ event |= TkButton1R;
+ break;
+ case '2':
+ event |= TkButton2R;
+ break;
+ case '3':
+ event |= TkButton3R;
+ break;
+ case '4':
+ event |= TkButton4R;
+ break;
+ case '5':
+ event |= TkButton5R;
+ break;
+ case '6':
+ event |= TkButton6R;
+ break;
+ }
+ break;
+ }
+ }
+ free(buf);
+ return event;
+}
+
+void
+tkcmdbind(Tk *tk, int event, char *s, void *data)
+{
+ Point p;
+ TkMouse *m;
+ TkGeom *g;
+ int v, len;
+ char *e, *c, *ec, *cmd;
+ TkTop *t;
+
+ if(s == nil)
+ return;
+ cmd = malloc(2*Tkmaxitem);
+ if (cmd == nil) {
+ print("tk: bind command \"%s\": %s\n",
+ tk->name ? tk->name->name : "(noname)", TkNomem);
+ return;
+ }
+
+ m = (TkMouse*)data;
+ c = cmd;
+ ec = cmd+2*Tkmaxitem-1;
+ while(*s && c < ec) {
+ if(*s != '%') {
+ *c++ = *s++;
+ continue;
+ }
+ s++;
+ len = ec-c;
+ switch(*s++) {
+ def:
+ default:
+ *c++ = s[-1];
+ break;
+ case '%':
+ *c++ = '%';
+ break;
+ case 'b':
+ v = 0;
+ if (!(event & TkKey)) {
+ if(event & (TkButton1P|TkButton1R))
+ v = 1;
+ else if(event & (TkButton2P|TkButton2R))
+ v = 2;
+ else if(event & (TkButton3P|TkButton3R))
+ v = 3;
+ }
+ c += snprint(c, len, "%d", v);
+ break;
+ case 'h':
+ if((event & TkConfigure) == 0)
+ goto def;
+ g = (TkGeom*)data;
+ c += snprint(c, len, "%d", g->height);
+ break;
+ case 's':
+ if((event & TkKey))
+ c += snprint(c, len, "%d", TKKEY(event));
+ else if((event & (TkEmouse|TkEnter)))
+ c += snprint(c, len, "%d", m->b);
+ else if((event & TkFocusin))
+ c += snprint(c, len, "%d", (int)data);
+ else
+ goto def;
+ break;
+ case 'w':
+ if((event & TkConfigure) == 0)
+ goto def;
+ g = (TkGeom*)data;
+ c += snprint(c, len, "%d", g->width);
+ break;
+ case 'x': /* Relative mouse coords */
+ case 'y':
+ if((event & TkKey) || (event & (TkEmouse|TkEnter)) == 0)
+ goto def;
+ p = tkposn(tk);
+ if(s[-1] == 'x')
+ v = m->x - p.x;
+ else
+ v = m->y - p.y;
+ c += snprint(c, len, "%d", v - tk->borderwidth);
+ break;
+ case 'X': /* Absolute mouse coords */
+ case 'Y':
+ if((event & TkKey) || (event & TkEmouse) == 0)
+ goto def;
+ c += snprint(c, len, "%d", s[-1] == 'X' ? m->x : m->y);
+ break;
+ case 'A':
+ if((event & TkKey) == 0)
+ goto def;
+ v = TKKEY(event);
+ if(v == '{' || v == '}' || v == '\\')
+ c += snprint(c, len, "\\%C", v);
+ else if(v != '\0')
+ c += snprint(c, len, "%C", v);
+ break;
+ case 'K':
+ if((event & TkKey) == 0)
+ goto def;
+ c += snprint(c, len, "%.4X", TKKEY(event));
+ break;
+ case 'W':
+ if (tk->name != nil)
+ c += snprint(c, len, "%s", tk->name->name);
+ break;
+ }
+ }
+ *c = '\0';
+ e = nil;
+ t = tk->env->top;
+ t->execdepth = 0;
+ if(cmd[0] == '|')
+ tkexec(t, cmd+1, nil);
+ else if(cmd[0] != '\0')
+ e = tkexec(t, cmd, nil);
+ t->execdepth = -1;
+
+ if(e == nil) {
+ free(cmd);
+ return;
+ }
+
+ if(tk->name != nil){
+ char *s;
+
+ if(t->errx[0] != '\0')
+ s = tkerrstr(t, e);
+ else
+ s = e;
+ print("tk: bind command \"%s\": %s: %s\n", tk->name->name, cmd, s);
+ if(s != e)
+ free(s);
+ }
+ free(cmd);
+}
+
+char*
+tkbind(TkTop *t, char *arg, char **ret)
+{
+ Rune r;
+ Tk *tk;
+ TkAction **ap;
+ int i, mode, event;
+ char *cmd, *tag, *seq;
+ char *e;
+
+ USED(ret);
+
+ tag = mallocz(Tkmaxitem, 0);
+ if(tag == nil)
+ return TkNomem;
+ seq = mallocz(Tkmaxitem, 0);
+ if(seq == nil) {
+ free(tag);
+ return TkNomem;
+ }
+
+ arg = tkword(t, arg, tag, tag+Tkmaxitem, nil);
+ if(tag[0] == '\0') {
+ e = TkBadtg;
+ goto err;
+ }
+
+ arg = tkword(t, arg, seq, seq+Tkmaxitem, nil);
+ if(seq[0] == '<') {
+ event = tkseqparse(seq+1);
+ if(event == -1) {
+ e = TkBadsq;
+ goto err;
+ }
+ }
+ else {
+ chartorune(&r, seq);
+ event = TkKey | r;
+ }
+ if(event == 0) {
+ e = TkBadsq;
+ goto err;
+ }
+
+ arg = tkskip(arg, " \t");
+
+ mode = TkArepl;
+ if(*arg == '+') {
+ mode = TkAadd;
+ arg++;
+ }
+ else if(*arg == '-'){
+ mode = TkAsub;
+ arg++;
+ }
+
+ if(*arg == '{') {
+ cmd = tkskip(arg+1, " \t");
+ if(*cmd == '}') {
+ tk = tklook(t, tag, 0);
+ if(tk == nil) {
+ for(i = 0; ; i++) {
+ if(i >= TKwidgets) {
+ e = TkBadwp;
+ tkerr(t, tag);
+ goto err;
+ }
+ if(strcmp(tag, tkmethod[i]->name) == 0) {
+ ap = &(t->binds[i]);
+ break;
+ }
+ }
+ }
+ else
+ ap = &tk->binds;
+ tkcancel(ap, event);
+ }
+ }
+
+ tkword(t, arg, seq, seq+Tkmaxitem, nil);
+ if(tag[0] == '.') {
+ tk = tklook(t, tag, 0);
+ if(tk == nil) {
+ e = TkBadwp;
+ tkerr(t, tag);
+ goto err;
+ }
+
+ cmd = strdup(seq);
+ if(cmd == nil) {
+ e = TkNomem;
+ goto err;
+ }
+ e = tkaction(&tk->binds, event, TkDynamic, cmd, mode);
+ if(e != nil)
+ goto err; /* tkaction does free(cmd) */
+ free(tag);
+ free(seq);
+ return nil;
+ }
+ /* documented but doesn't work */
+ if(strcmp(tag, "all") == 0) {
+ for(tk = t->root; tk; tk = tk->next) {
+ cmd = strdup(seq);
+ if(cmd == nil) {
+ e = TkNomem;
+ goto err;
+ }
+ e = tkaction(&tk->binds, event, TkDynamic, cmd, mode);
+ if(e != nil)
+ goto err;
+ }
+ free(tag);
+ free(seq);
+ return nil;
+ }
+ /* undocumented, probably unused, and doesn't work consistently */
+ for(i = 0; i < TKwidgets; i++) {
+ if(strcmp(tag, tkmethod[i]->name) == 0) {
+ cmd = strdup(seq);
+ if(cmd == nil) {
+ e = TkNomem;
+ goto err;
+ }
+ e = tkaction(t->binds + i,event, TkDynamic, cmd, mode);
+ if(e != nil)
+ goto err;
+ free(tag);
+ free(seq);
+ return nil;
+ }
+ }
+
+ e = TkBadtg;
+err:
+ free(tag);
+ free(seq);
+
+ return e;
+}
+
+char*
+tksend(TkTop *t, char *arg, char **ret)
+{
+
+ TkVar *v;
+ char *var;
+
+ USED(ret);
+
+ var = mallocz(Tkmaxitem, 0);
+ if(var == nil)
+ return TkNomem;
+
+ arg = tkword(t, arg, var, var+Tkmaxitem, nil);
+ v = tkmkvar(t, var, 0);
+ free(var);
+ if(v == nil)
+ return TkBadvr;
+ if(v->type != TkVchan)
+ return TkNotvt;
+
+ arg = tkskip(arg, " \t");
+ if(tktolimbo(v->value, arg) == 0)
+ return TkMovfw;
+
+ return nil;
+}
+
+static Tk*
+tknextfocus(TkTop *t, int d)
+{
+ int i, n, j, k;
+ Tk *oldfocus;
+
+ if (t->focusorder == nil)
+ tkbuildfocusorder(t);
+
+ oldfocus = t->ctxt->tkkeygrab;
+ n = t->nfocus;
+ if (n == 0)
+ return oldfocus;
+ for (i = 0; i < n; i++)
+ if (t->focusorder[i] == oldfocus)
+ break;
+ if (i == n) {
+ for (i = 0; i < n; i++)
+ if ((t->focusorder[i]->flag & Tkdisabled) == 0)
+ return t->focusorder[i];
+ return oldfocus;
+ }
+ for (j = 1; j < n; j++) {
+ k = (i + d * j + n) % n;
+ if ((t->focusorder[k]->flag & Tkdisabled) == 0)
+ return t->focusorder[k];
+ }
+ return oldfocus;
+}
+
+/* our dirty little secret */
+static void
+focusdirty(Tk *tk)
+{
+ if(tk->highlightwidth > 0){
+ tk->dirty = tkrect(tk, 1);
+ tkdirty(tk);
+ }
+}
+
+void
+tksetkeyfocus(TkTop *top, Tk *new, int dir)
+{
+ TkCtxt *c;
+ Tk *old;
+
+ c = top->ctxt;
+ old = c->tkkeygrab;
+
+ if(old == new)
+ return;
+ c->tkkeygrab = new;
+ if(top->focused == 0)
+ return;
+ if(old != nil && old != top->root){
+ tkdeliver(old, TkFocusout, nil);
+ focusdirty(old);
+ }
+ if(new != nil && new != top->root){
+ tkdeliver(new, TkFocusin, (void*)dir);
+ focusdirty(new);
+ }
+}
+
+void
+tksetglobalfocus(TkTop *top, int in)
+{
+ Tk *tk;
+ in = (in != 0);
+ if (in != top->focused){
+ top->focused = in;
+ tk = top->ctxt->tkkeygrab;
+ if(in){
+ tkdeliver(top->root, TkFocusin, (void*)0);
+ if(tk != nil && tk != top->root){
+ tkdeliver(tk, TkFocusin, (void*)0);
+ focusdirty(tk);
+ }
+ }else{
+ if(tk != nil && tk != top->root){
+ tkdeliver(tk, TkFocusout, nil);
+ focusdirty(tk);
+ }
+ tkdeliver(top->root, TkFocusout, nil);
+ }
+ }
+}
+
+char*
+tkfocus(TkTop *top, char *arg, char **ret)
+{
+ Tk *tk;
+ char *wp, *e;
+ int dir, global;
+ TkOptab tko[2];
+ TkName *names;
+
+ tko[0].ptr = &global;
+ tko[0].optab = focusopts;
+ tko[1].ptr = nil;
+
+ global = 0;
+
+ names = nil;
+ e = tkparse(top, arg, tko, &names);
+ if (e != nil)
+ return e;
+
+ if(names == nil){
+ if(global)
+ return tkvalue(ret, "%d", top->focused);
+ tk = top->ctxt->tkkeygrab;
+ if (tk != nil && tk->name != nil)
+ return tkvalue(ret, "%s", tk->name->name);
+ return nil;
+ }
+
+ if(global){
+ tksetglobalfocus(top, atoi(names->name));
+ return nil;
+ }
+
+ wp = mallocz(Tkmaxitem, 0);
+ if(wp == nil)
+ return TkNomem;
+
+ tkword(top, arg, wp, wp+Tkmaxitem, nil);
+ if (!strcmp(wp, "next")) {
+ tk = tknextfocus(top, 1); /* can only return nil if c->tkkeygrab is already nil */
+ dir = +1;
+ } else if (!strcmp(wp, "previous")) {
+ tk = tknextfocus(top, -1);
+ dir = -1;
+ } else if(*wp == '\0') {
+ tk = nil;
+ dir = 0;
+ } else {
+ tk = tklook(top, wp, 0);
+ if(tk == nil){
+ tkerr(top, wp);
+ free(wp);
+ return TkBadwp;
+ }
+ dir = 0;
+ }
+ free(wp);
+
+ tksetkeyfocus(top, tk, dir);
+ return nil;
+}
+
+char*
+tkraise(TkTop *t, char *arg, char **ret)
+{
+ Tk *tk;
+ char *wp;
+
+ USED(ret);
+
+ wp = mallocz(Tkmaxitem, 0);
+ if(wp == nil)
+ return TkNomem;
+ tkword(t, arg, wp, wp+Tkmaxitem, nil);
+ tk = tklook(t, wp, 0);
+ if(tk == nil){
+ tkerr(t, wp);
+ free(wp);
+ return TkBadwp;
+ }
+ free(wp);
+
+ if((tk->flag & Tkwindow) == 0)
+ return TkNotwm;
+
+ tkwreq(tk->env->top, "raise %s", tk->name->name);
+ return nil;
+}
+
+char*
+tklower(TkTop *t, char *arg, char **ret)
+{
+ Tk *tk;
+ char *wp;
+
+ USED(ret);
+ wp = mallocz(Tkmaxitem, 0);
+ if(wp == nil)
+ return TkNomem;
+ tkword(t, arg, wp, wp+Tkmaxitem, nil);
+ tk = tklook(t, wp, 0);
+ if(tk == nil){
+ tkerr(t, wp);
+ free(wp);
+ return TkBadwp;
+ }
+ free(wp);
+
+ if((tk->flag & Tkwindow) == 0)
+ return TkNotwm;
+
+ tkwreq(tk->env->top, "lower %s", tk->name->name);
+ return nil;
+}
+
+char*
+tkgrab(TkTop *t, char *arg, char **ret)
+{
+ Tk *tk;
+ TkCtxt *c;
+ char *r, *buf, *wp;
+
+ USED(ret);
+
+ buf = mallocz(Tkmaxitem, 0);
+ if(buf == nil)
+ return TkNomem;
+
+ wp = mallocz(Tkmaxitem, 0);
+ if(wp == nil) {
+ free(buf);
+ return TkNomem;
+ }
+ arg = tkword(t, arg, buf, buf+Tkmaxitem, nil);
+
+ tkword(t, arg, wp, wp+Tkmaxitem, nil);
+ tk = tklook(t, wp, 0);
+ if(tk == nil) {
+ free(buf);
+ tkerr(t, wp);
+ free(wp);
+ return TkBadwp;
+ }
+ free(wp);
+
+ c = t->ctxt;
+ if(strcmp(buf, "release") == 0) {
+ free(buf);
+ if(c->mgrab == tk)
+ tksetmgrab(t, nil);
+ return nil;
+ }
+ if(strcmp(buf, "set") == 0) {
+ free(buf);
+ return tksetmgrab(t, tk);
+ }
+ if(strcmp(buf, "ifunset") == 0) {
+ free(buf);
+ if(c->mgrab == nil)
+ return tksetmgrab(t, tk);
+ return nil;
+ }
+ if(strcmp(buf, "status") == 0) {
+ free(buf);
+ r = "none";
+ if ((c->mgrab != nil) && (c->mgrab->name != nil))
+ r = c->mgrab->name->name;
+ return tkvalue(ret, "%s", r);
+ }
+ free(buf);
+ return TkBadcm;
+}
+
+char*
+tkputs(TkTop *t, char *arg, char **ret)
+{
+ char *buf;
+
+ USED(ret);
+
+ buf = mallocz(Tkmaxitem, 0);
+ if(buf == nil)
+ return TkNomem;
+ tkword(t, arg, buf, buf+Tkmaxitem, nil);
+ print("%s\n", buf);
+ free(buf);
+ return nil;
+}
+
+char*
+tkdestroy(TkTop *t, char *arg, char **ret)
+{
+ int found, len, isroot;
+ Tk *tk, **l, *next, *slave;
+ char *n, *e, *buf;
+
+ USED(ret);
+ buf = mallocz(Tkmaxitem, 0);
+ if(buf == nil)
+ return TkNomem;
+ e = nil;
+ for(;;) {
+ arg = tkword(t, arg, buf, buf+Tkmaxitem, nil);
+ if(buf[0] == '\0')
+ break;
+
+ len = strlen(buf);
+ found = 0;
+ isroot = (strcmp(buf, ".") == 0);
+ for(tk = t->root; tk; tk = tk->siblings) {
+ if (tk->name != nil) {
+ n = tk->name->name;
+ if(strcmp(buf, n) == 0) {
+ tk->flag |= Tkdestroy;
+ found = 1;
+ } else if(isroot || (strncmp(buf, n, len) == 0 && n[len] == '.'))
+ tk->flag |= Tkdestroy;
+ }
+ }
+ if(!found) {
+ e = TkBadwp;
+ tkerr(t, buf);
+ break;
+ }
+ }
+ free(buf);
+
+ for(tk = t->root; tk; tk = tk->siblings) {
+ if((tk->flag & Tkdestroy) == 0)
+ continue;
+ if(tk->flag & Tkwindow) {
+ tkunmap(tk);
+ if(tk->name != nil &&
+ strcmp(tk->name->name, ".") == 0)
+ tk->flag &= ~Tkdestroy;
+ else
+ tkdeliver(tk, TkDestroy, nil);
+ } else
+ tkdeliver(tk, TkDestroy, nil);
+if(0)print("tkdestroy %q\n", tkname(tk));
+ if(tk->destroyed != nil)
+ tk->destroyed(tk);
+ tkpackqit(tk->master);
+ tkdelpack(tk);
+ for (slave = tk->slave; slave != nil; slave = next) {
+ next = slave->next;
+ slave->master = nil;
+ slave->next = nil;
+ }
+ tk->slave = nil;
+ if(tk->parent != nil && tk->geom != nil) /* XXX this appears to be bogus */
+ tk->geom(tk, 0, 0, 0, 0);
+ if(tk->grid){
+ tkfreegrid(tk->grid);
+ tk->grid = nil;
+ }
+ }
+ tkrunpack(t);
+
+ l = &t->windows;
+ for(tk = t->windows; tk; tk = next) {
+ next = TKobj(TkWin, tk)->next;
+ if(tk->flag & Tkdestroy) {
+ *l = next;
+ continue;
+ }
+ l = &TKobj(TkWin, tk)->next;
+ }
+ l = &t->root;
+ for(tk = t->root; tk; tk = next) {
+ next = tk->siblings;
+ if(tk->flag & Tkdestroy) {
+ *l = next;
+ tkfreeobj(tk);
+ continue;
+ }
+ l = &tk->siblings;
+ }
+
+ return e;
+}
+
+char*
+tkupdatecmd(TkTop *t, char *arg, char **ret)
+{
+ Tk *tk;
+ int x, y;
+ Rectangle *dr;
+ char buf[Tkmaxitem];
+
+ USED(ret);
+
+ tkword(t, arg, buf, buf+sizeof(buf), nil);
+ if(strcmp(buf, "-onscreen") == 0){
+ tk = t->root;
+ dr = &t->screenr;
+ x = tk->act.x;
+ if(x+tk->act.width > dr->max.x)
+ x = dr->max.x - tk->act.width;
+ if(x < 0)
+ x = 0;
+ y = tk->act.y;
+ if(y+tk->act.height > dr->max.y)
+ y = dr->max.y - tk->act.height;
+ if(y < 0)
+ y = 0;
+ tkmovewin(tk, Pt(x, y));
+ }else if(strcmp(buf, "-disable") == 0){
+ t->noupdate = 1;
+ }else if(strcmp(buf, "-enable") == 0){
+ t->noupdate = 0;
+ }
+ return tkupdate(t);
+}
+
+char*
+tkwinfo(TkTop *t, char *arg, char **ret)
+{
+ Tk *tk;
+ char *cmd, *arg1;
+
+ cmd = mallocz(Tkmaxitem, 0);
+ if(cmd == nil)
+ return TkNomem;
+
+ arg = tkword(t, arg, cmd, cmd+Tkmaxitem, nil);
+ if(strcmp(cmd, "class") == 0) {
+ arg1 = mallocz(Tkmaxitem, 0);
+ if(arg1 == nil) {
+ free(cmd);
+ return TkNomem;
+ }
+ tkword(t, arg, arg1, arg1+Tkmaxitem, nil);
+ tk = tklook(t, arg1, 0);
+ if(tk == nil){
+ tkerr(t, arg1);
+ free(arg1);
+ free(cmd);
+ return TkBadwp;
+ }
+ free(arg1);
+ free(cmd);
+ return tkvalue(ret, "%s", tkmethod[tk->type]->name);
+ }
+ free(cmd);
+ return TkBadvl;
+}
+
+char*
+tkcursorcmd(TkTop *t, char *arg, char **ret)
+{
+ char *e;
+ int locked;
+ Display *d;
+ TkCursor c;
+ TkOptab tko[3];
+ enum {Notset = 0x80000000};
+
+ c.def = 0;
+ c.p.x = Notset;
+ c.p.y = Notset;
+ c.bit = nil;
+ c.img = nil;
+
+ USED(ret);
+
+ c.def = 0;
+ tko[0].ptr = &c;
+ tko[0].optab = tkcurop;
+ tko[1].ptr = nil;
+ e = tkparse(t, arg, tko, nil);
+ if(e != nil)
+ return e;
+
+ d = t->display;
+ locked = lockdisplay(d);
+ if(c.def)
+ tkcursorswitch(t, nil, nil);
+ if(c.img != nil || c.bit != nil){
+ e = tkcursorswitch(t, c.bit, c.img);
+ tkimgput(c.img);
+ freeimage(c.bit);
+ }
+ if(e == nil){
+ if(c.p.x != Notset && c.p.y != Notset)
+ tkcursorset(t, c.p);
+ }
+ if(locked)
+ unlockdisplay(d);
+ return e;
+}
+
+char *
+tkbindings(TkTop *t, Tk *tk, TkEbind *b, int blen)
+{
+ TkAction *a, **ap;
+ char *cmd, *e;
+ int i;
+
+ e = nil;
+ for(i = 0; e == nil && i < blen; i++) /* default bindings */ {
+ int how = TkArepl;
+ char *cmd = b[i].cmd;
+ if(cmd[0] == '+') {
+ how = TkAadd;
+ cmd++;
+ }
+ else if(cmd[0] == '-'){
+ how = TkAsub;
+ cmd++;
+ }
+ e = tkaction(&tk->binds, b[i].event, TkStatic, cmd, how);
+ }
+
+ if(e != nil)
+ return e;
+
+ ap = &tk->binds;
+ for(a = t->binds[tk->type]; a; a = a->link) { /* user "defaults" */
+ cmd = strdup(a->arg);
+ if(cmd == nil)
+ return TkNomem;
+
+ e = tkaction(ap, a->event, TkDynamic, cmd,
+ (a->type >> 8) & 0xff);
+ if(e != nil)
+ return e;
+ ap = &(*ap)->link;
+ }
+ return nil;
+}
--- /dev/null
+++ b/libtk/entry.c
@@ -1,0 +1,1368 @@
+#include <lib9.h>
+#include <kernel.h>
+#include "draw.h"
+#include "keyboard.h"
+#include "tk.h"
+
+/* Widget Commands (+ means implemented)
+ +bbox
+ +cget
+ +configure
+ +delete
+ +get
+ +icursor
+ +index
+ scan
+ +selection
+ +xview
+ +see
+*/
+
+#define O(t, e) ((long)(&((t*)0)->e))
+
+#define CNTL(c) ((c)&0x1f)
+#define DEL 0x7f
+
+/* Layout constants */
+enum {
+ Entrypady = 0,
+ Entrypadx = 0,
+ Inswidth = 2,
+
+ Ecursoron = 1<<0,
+ Ecenter = 1<<1,
+ Eright = 1<<2,
+ Eleft = 1<<3,
+ Ewordsel = 1<<4,
+
+ Ejustify = Ecenter|Eleft|Eright
+};
+
+static TkStab tkjust[] =
+{
+ "left", Eleft,
+ "right", Eright,
+ "center", Ecenter,
+ nil
+};
+
+static
+TkEbind b[] =
+{
+ {TkKey, "%W delete sel.first sel.last; %W insert insert {%A};%W see insert"},
+ {TkKey|CNTL('a'), "%W icursor 0;%W see insert;%W selection clear"},
+ {TkKey|Home, "%W icursor 0;%W see insert;%W selection clear"},
+ {TkKey|CNTL('d'), "%W delete insert; %W see insert"},
+ {TkKey|CNTL('e'), "%W icursor end; %W see insert;%W selection clear"},
+ {TkKey|End, "%W icursor end; %W see insert;%W selection clear"},
+ {TkKey|CNTL('h'), "%W tkEntryBS;%W see insert"},
+ {TkKey|CNTL('k'), "%W delete insert end;%W see insert"},
+ {TkKey|CNTL('u'), "%W delete 0 end;%W see insert"},
+ {TkKey|CNTL('w'), "%W delete sel.first sel.last; %W tkEntryBW;%W see insert"},
+ {TkKey|DEL, "%W tkEntryBS 1;%W see insert"},
+ {TkKey|CNTL('\\'), "%W selection clear"},
+ {TkKey|CNTL('/'), "%W selection range 0 end"},
+ {TkKey|Left, "%W icursor insert-1;%W selection clear;%W selection from insert;%W see insert"},
+ {TkKey|Right, "%W icursor insert+1;%W selection clear;%W selection from insert;%W see insert"},
+ {TkButton1P, "focus %W; %W tkEntryB1P %X"},
+ {TkButton1P|TkMotion, "%W tkEntryB1M %X"},
+ {TkButton1R, "%W tkEntryB1R"},
+ {TkButton1P|TkDouble, "%W tkEntryB1P %X;%W selection word @%x"},
+ {TkButton2P, "%W tkEntryB2P %x"},
+ {TkButton2P|TkMotion, "%W xview scroll %x scr"},
+ {TkFocusin, "%W tkEntryFocus in"},
+ {TkFocusout, "%W tkEntryFocus out"},
+ {TkKey|APP|'\t', ""},
+ {TkKey|BackTab, ""},
+};
+
+typedef struct TkEntry TkEntry;
+struct TkEntry
+{
+ Rune* text;
+ int textlen;
+
+ char* xscroll;
+ char* show;
+ int flag;
+ int oldx;
+
+ int icursor; /* index of insertion cursor */
+ int anchor; /* selection anchor point */
+ int sel0; /* index of start of selection */
+ int sel1; /* index of end of selection */
+
+ int x0; /* x-offset of visible area */
+
+ /* derived values */
+ int v0; /* index of first visible character */
+ int v1; /* index of last visible character + 1 */
+ int xlen; /* length of text in pixels*/
+ int xv0; /* position of first visible character */
+ int xsel0; /* position of start of selection */
+ int xsel1; /* position of end of selection */
+ int xicursor; /* position of insertion cursor */
+};
+
+static void blinkreset(Tk*);
+
+static
+TkOption opts[] =
+{
+ "xscrollcommand", OPTtext, O(TkEntry, xscroll), nil,
+ "justify", OPTstab, O(TkEntry, flag), tkjust,
+ "show", OPTtext, O(TkEntry, show), nil,
+ nil
+};
+
+static int
+xinset(Tk *tk)
+{
+ return Entrypadx + tk->highlightwidth;
+}
+
+static int
+yinset(Tk *tk)
+{
+ return Entrypady + tk->highlightwidth;
+}
+
+static void
+tksizeentry(Tk *tk)
+{
+ if((tk->flag & Tksetwidth) == 0)
+ tk->req.width = tk->env->wzero*25 + 2*xinset(tk) + Inswidth;
+ if((tk->flag & Tksetheight) == 0)
+ tk->req.height = tk->env->font->height+ 2*yinset(tk);
+}
+
+int
+entrytextwidth(Tk *tk, int n)
+{
+ TkEntry *tke = TKobj(TkEntry, tk);
+ Rune c;
+ Font *f;
+
+ f = tk->env->font;
+ if (tke->show != nil) {
+ chartorune(&c, tke->show);
+ return n * runestringnwidth(f, &c, 1);
+ }
+ return runestringnwidth(f, tke->text, n);
+}
+
+static int
+x2index(Tk *tk, int x, int *xc)
+{
+ TkEntry *tke = TKobj(TkEntry, tk);
+ int t0, t1, r, q;
+
+ t0 = 0;
+ t1 = tke->textlen;
+ while (t0 <= t1) {
+ r = (t0 + t1) / 2;
+ q = entrytextwidth(tk, r);
+ if (q == x) {
+ if (xc != nil)
+ *xc = q;
+ return r;
+ }
+ if (q < x)
+ t0 = r + 1;
+ else
+ t1 = r - 1;
+ }
+ if (xc != nil)
+ *xc = t1 > 0 ? entrytextwidth(tk, t1) : 0;
+ if (t1 < 0)
+ t1 = 0;
+ return t1;
+}
+
+/*
+ * recalculate derived values
+ */
+static void
+recalcentry(Tk *tk)
+{
+ TkEntry *tke = TKobj(TkEntry, tk);
+ int x, avail, locked;
+
+ locked = lockdisplay(tk->env->top->display);
+
+ tke->xlen = entrytextwidth(tk, tke->textlen) + Inswidth;
+
+ avail = tk->act.width - 2*xinset(tk);
+ if (tke->xlen < avail) {
+ switch(tke->flag & Ejustify) {
+ default:
+ tke->x0 = 0;
+ break;
+ case Eright:
+ tke->x0 = -(avail - tke->xlen);
+ break;
+ case Ecenter:
+ tke->x0 = -(avail - tke->xlen) / 2;
+ break;
+ }
+ }
+
+ tke->v0 = x2index(tk, tke->x0, &tke->xv0);
+ tke->v1 = x2index(tk, tk->act.width + tke->x0, &x);
+ /* perhaps include partial last character */
+ if (tke->v1 < tke->textlen && x < avail + tke->x0)
+ tke->v1++;
+ tke->xsel0 = entrytextwidth(tk, tke->sel0);
+ tke->xsel1 = entrytextwidth(tk, tke->sel1);
+ tke->xicursor = entrytextwidth(tk, tke->icursor);
+
+ if (locked)
+ unlockdisplay(tk->env->top->display);
+}
+
+char*
+tkentry(TkTop *t, char *arg, char **ret)
+{
+ Tk *tk;
+ char *e;
+ TkName *names;
+ TkEntry *tke;
+ TkOptab tko[3];
+
+ tk = tknewobj(t, TKentry, sizeof(Tk)+sizeof(TkEntry));
+ if(tk == nil)
+ return TkNomem;
+
+ tk->relief = TKsunken;
+ tk->borderwidth = 1;
+ tk->flag |= Tktakefocus;
+ tk->highlightwidth = 1;
+
+ tke = TKobj(TkEntry, tk);
+
+ tko[0].ptr = tk;
+ tko[0].optab = tkgeneric;
+ tko[1].ptr = tke;
+ tko[1].optab = opts;
+ tko[2].ptr = nil;
+
+ names = nil;
+ e = tkparse(t, arg, tko, &names);
+ if(e != nil) {
+ tkfreeobj(tk);
+ return e;
+ }
+ tksettransparent(tk, tkhasalpha(tk->env, TkCbackgnd));
+ tksizeentry(tk);
+ e = tkbindings(t, tk, b, nelem(b));
+
+ if(e != nil) {
+ tkfreeobj(tk);
+ return e;
+ }
+
+ e = tkaddchild(t, tk, &names);
+ tkfreename(names);
+ if(e != nil) {
+ tkfreeobj(tk);
+ return e;
+ }
+ tk->name->link = nil;
+ recalcentry(tk);
+
+ return tkvalue(ret, "%s", tk->name->name);
+}
+
+static char*
+tkentrycget(Tk *tk, char *arg, char **val)
+{
+ TkOptab tko[3];
+ TkEntry *tke = TKobj(TkEntry, tk);
+
+ tko[0].ptr = tk;
+ tko[0].optab = tkgeneric;
+ tko[1].ptr = tke;
+ tko[1].optab = opts;
+ tko[2].ptr = nil;
+
+ return tkgencget(tko, arg, val, tk->env->top);
+}
+
+void
+tkfreeentry(Tk *tk)
+{
+ TkEntry *tke = TKobj(TkEntry, tk);
+
+ free(tke->xscroll);
+ free(tke->text);
+ free(tke->show);
+}
+
+static void
+tkentrytext(Image *i, Rectangle s, Tk *tk, TkEnv *env)
+{
+ TkEntry *tke = TKobj(TkEntry, tk);
+ Point dp;
+ int s0, s1, xs0, xs1, j;
+ Rectangle r;
+ Rune showr, *text;
+
+ dp = Pt(s.min.x - (tke->x0 - tke->xv0), s.min.y);
+ if (tke->show) {
+ chartorune(&showr, tke->show);
+ text = mallocz(sizeof(Rune) * (tke->textlen+1), 0);
+ if (text == nil)
+ return;
+ for (j = 0; j < tke->textlen; j++)
+ text[j] = showr;
+ } else
+ text = tke->text;
+
+ runestringn(i, dp, tkgc(env, TkCforegnd), dp, env->font,
+ text+tke->v0, tke->v1-tke->v0);
+
+ if (tke->sel0 < tke->v1 && tke->sel1 > tke->v0) {
+ if (tke->sel0 < tke->v0) {
+ s0 = tke->v0;
+ xs0 = tke->xv0 - tke->x0;
+ } else {
+ s0 = tke->sel0;
+ xs0 = tke->xsel0 - tke->x0;
+ }
+
+ if (tke->sel1 > tke->v1) {
+ s1 = tke->v1;
+ xs1 = s.max.x;
+ } else {
+ s1 = tke->sel1;
+ xs1 = tke->xsel1 - tke->x0;
+ }
+
+ r = rectaddpt(Rect(xs0, 0, xs1, env->font->height), s.min);
+ tktextsdraw(i, r, env, 1);
+ runestringn(i, r.min, tkgc(env, TkCselectfgnd), r.min, env->font,
+ text+s0, s1-s0);
+ }
+
+ if((tke->flag&Ecursoron) && tke->icursor >= tke->v0 && tke->icursor <= tke->v1) {
+ r = Rect(
+ tke->xicursor - tke->x0, 0,
+ tke->xicursor - tke->x0 + Inswidth, env->font->height
+ );
+ draw(i, rectaddpt(r, s.min), tkgc(env, TkCforegnd), nil, ZP);
+ }
+ if (tke->show)
+ free(text);
+}
+
+char*
+tkdrawentry(Tk *tk, Point orig)
+{
+ Point p;
+ TkEnv *env;
+ Rectangle r, s;
+ Image *i;
+ int xp, yp;
+
+ env = tk->env;
+
+ r.min = ZP;
+ r.max.x = tk->act.width + 2*tk->borderwidth;
+ r.max.y = tk->act.height + 2*tk->borderwidth;
+ i = tkitmp(env, r.max, TkCbackgnd);
+ if(i == nil)
+ return nil;
+
+ xp = tk->borderwidth + xinset(tk);
+ yp = tk->borderwidth + yinset(tk);
+ s = r;
+ s.min.x += xp;
+ s.max.x -= xp;
+ s.min.y += yp;
+ s.max.y -= yp;
+ tkentrytext(i, s, tk, env);
+
+ tkdrawrelief(i, tk, ZP, TkCbackgnd, tk->relief);
+
+ if (tkhaskeyfocus(tk))
+ tkbox(i, insetrect(r, tk->borderwidth), tk->highlightwidth, tkgc(tk->env, TkChighlightfgnd));
+
+ p.x = tk->act.x + orig.x;
+ p.y = tk->act.y + orig.y;
+ r = rectaddpt(r, p);
+ draw(tkimageof(tk), r, i, nil, ZP);
+
+ return nil;
+}
+
+char*
+tkentrysh(Tk *tk)
+{
+ TkEntry *tke = TKobj(TkEntry, tk);
+ int dx, top, bot;
+ char *val, *cmd, *v, *e;
+
+ if(tke->xscroll == nil)
+ return nil;
+
+ bot = 0;
+ top = Tkfpscalar;
+
+ if(tke->text != 0 && tke->textlen != 0) {
+ dx = tk->act.width - 2*xinset(tk);
+
+ if (tke->xlen > dx) {
+ bot = TKI2F(tke->x0) / tke->xlen;
+ top = TKI2F(tke->x0 + dx) / tke->xlen;
+ }
+ }
+
+ val = mallocz(Tkminitem, 0);
+ if(val == nil)
+ return TkNomem;
+ v = tkfprint(val, bot);
+ *v++ = ' ';
+ tkfprint(v, top);
+ cmd = mallocz(Tkminitem, 0);
+ if(cmd == nil) {
+ free(val);
+ return TkNomem;
+ }
+ sprint(cmd, "%s %s", tke->xscroll, val);
+ e = tkexec(tk->env->top, cmd, nil);
+ free(cmd);
+ free(val);
+ return e;
+}
+
+void
+tkentrygeom(Tk *tk)
+{
+ char *e;
+ e = tkentrysh(tk);
+ if ((e != nil) && /* XXX - Tad: should propagate not print */
+ (tk->name != nil))
+ print("tk: xscrollcommand \"%s\": %s\n", tk->name->name, e);
+ recalcentry(tk);
+}
+
+static char*
+tkentryconf(Tk *tk, char *arg, char **val)
+{
+ char *e;
+ TkGeom g;
+ int bd;
+ TkOptab tko[3];
+ TkEntry *tke = TKobj(TkEntry, tk);
+
+ tko[0].ptr = tk;
+ tko[0].optab = tkgeneric;
+ tko[1].ptr = tke;
+ tko[1].optab = opts;
+ tko[2].ptr = nil;
+
+ if(*arg == '\0')
+ return tkconflist(tko, val);
+
+ bd = tk->borderwidth;
+ g = tk->req;
+ e = tkparse(tk->env->top, arg, tko, nil);
+ tksettransparent(tk, tkhasalpha(tk->env, TkCbackgnd));
+ tksizeentry(tk);
+ tkgeomchg(tk, &g, bd);
+ recalcentry(tk);
+ tk->dirty = tkrect(tk, 1);
+ return e;
+}
+
+static char*
+tkentryparseindex(Tk *tk, char *buf, int *index)
+{
+ TkEntry *tke = TKobj(TkEntry, tk);
+ TkEnv *env;
+ char *mod;
+ int i, x, locked, modstart;
+
+ modstart = 0;
+ for(mod = buf; *mod != '\0'; mod++)
+ if(*mod == '-' || *mod == '+') {
+ modstart = *mod;
+ *mod = '\0';
+ break;
+ }
+ if(strcmp(buf, "end") == 0)
+ i = tke->textlen;
+ else
+ if(strcmp(buf, "anchor") == 0)
+ i = tke->anchor;
+ else
+ if(strcmp(buf, "insert") == 0)
+ i = tke->icursor;
+ else
+ if(strcmp(buf, "sel.first") == 0)
+ i = tke->sel0;
+ else
+ if(strcmp(buf, "sel.last") == 0)
+ i = tke->sel1;
+ else
+ if(buf[0] >= '0' && buf[0] <= '9')
+ i = atoi(buf);
+ else
+ if(buf[0] == '@') {
+ x = atoi(buf+1) - xinset(tk);
+ if(tke->textlen == 0) {
+ *index = 0;
+ return nil;
+ }
+ env = tk->env;
+ locked = lockdisplay(env->top->display);
+ i = x2index(tk, x + tke->x0, nil); /* XXX could possibly select nearest character? */
+ if(locked)
+ unlockdisplay(env->top->display);
+ }
+ else
+ return TkBadix;
+
+ if(i < 0 || i > tke->textlen)
+ return TkBadix;
+ if(modstart) {
+ *mod = modstart;
+ i += atoi(mod);
+ if(i < 0)
+ i = 0;
+ if(i > tke->textlen)
+ i = tke->textlen;
+ }
+ *index = i;
+ return nil;
+}
+
+/*
+ * return bounding box of character at index, in coords relative to
+ * the top left position of the text.
+ */
+static Rectangle
+tkentrybbox(Tk *tk, int index)
+{
+ TkEntry *tke;
+ TkEnv *env;
+ Display *d;
+ int x, cw, locked;
+ Rectangle r;
+
+ tke = TKobj(TkEntry, tk);
+ env = tk->env;
+
+ d = env->top->display;
+
+ locked = lockdisplay(d);
+ x = entrytextwidth(tk, index);
+ if (index < tke->textlen)
+ cw = entrytextwidth(tk, index+1) - x;
+ else
+ cw = Inswidth;
+ if(locked)
+ unlockdisplay(d);
+
+ r.min.x = x;
+ r.min.y = 0;
+ r.max.x = x + cw;
+ r.max.y = env->font->height;
+ return r;
+}
+
+static void
+tkentrysee(Tk *tk, int index, int jump)
+{
+ TkEntry *tke = TKobj(TkEntry, tk);
+ int dx, margin;
+ Rectangle r;
+
+ r = tkentrybbox(tk, index);
+ dx = tk->act.width - 2*xinset(tk);
+ if (jump)
+ margin = dx / 4;
+ else
+ margin = 0;
+ if (r.min.x <= tke->x0 || r.max.x > tke->x0 + dx) {
+ if (r.min.x <= tke->x0) {
+ tke->x0 = r.min.x - margin;
+ if (tke->x0 < 0)
+ tke->x0 = 0;
+ } else if (r.max.x >= tke->x0 + dx) {
+ tke->x0 = r.max.x - dx + margin;
+ if (tke->x0 > tke->xlen - dx)
+ tke->x0 = tke->xlen - dx;
+ }
+ tk->dirty = tkrect(tk, 0);
+ }
+ r = rectaddpt(r, Pt(xinset(tk) - tke->x0, yinset(tk)));
+ tksee(tk, r, r.min);
+}
+
+static char*
+tkentryseecmd(Tk *tk, char *arg, char **val)
+{
+ int index;
+ char *e, *buf;
+
+ USED(val);
+
+ buf = mallocz(Tkmaxitem, 0);
+ if(buf == nil)
+ return TkNomem;
+ tkword(tk->env->top, arg, buf, buf+Tkmaxitem, nil);
+ e = tkentryparseindex(tk, buf, &index);
+ free(buf);
+ if(e != nil)
+ return e;
+
+ tkentrysee(tk, index, 1);
+ recalcentry(tk);
+
+ return nil;
+}
+
+static char*
+tkentrybboxcmd(Tk *tk, char *arg, char **val)
+{
+ TkEntry *tke = TKobj(TkEntry, tk);
+ char *r, *buf;
+ int index;
+ Rectangle bbox;
+
+ buf = mallocz(Tkmaxitem, 0);
+ if(buf == nil)
+ return TkNomem;
+ tkword(tk->env->top, arg, buf, buf+Tkmaxitem, nil);
+ r = tkentryparseindex(tk, buf, &index);
+ free(buf);
+ if(r != nil)
+ return r;
+ bbox = rectaddpt(tkentrybbox(tk, index), Pt(xinset(tk) - tke->x0, yinset(tk)));
+ return tkvalue(val, "%d %d %d %d", bbox.min.x, bbox.min.y, bbox.max.x, bbox.max.y);
+}
+
+static char*
+tkentryindex(Tk *tk, char *arg, char **val)
+{
+ int index;
+ char *r, *buf;
+
+ buf = mallocz(Tkmaxitem, 0);
+ if(buf == nil)
+ return TkNomem;
+ tkword(tk->env->top, arg, buf, buf+Tkmaxitem, nil);
+ r = tkentryparseindex(tk, buf, &index);
+ free(buf);
+ if(r != nil)
+ return r;
+ return tkvalue(val, "%d", index);
+}
+
+static char*
+tkentryicursor(Tk *tk, char *arg, char **val)
+{
+ TkEntry *tke = TKobj(TkEntry, tk);
+ int index, locked;
+ char *r, *buf;
+
+ USED(val);
+ buf = mallocz(Tkmaxitem, 0);
+ if(buf == nil)
+ return TkNomem;
+ tkword(tk->env->top, arg, buf, buf+Tkmaxitem, nil);
+ r = tkentryparseindex(tk, buf, &index);
+ free(buf);
+ if(r != nil)
+ return r;
+ tke->icursor = index;
+ locked = lockdisplay(tk->env->top->display);
+ tke->xicursor = entrytextwidth(tk, tke->icursor);
+ if (locked)
+ unlockdisplay(tk->env->top->display);
+
+ blinkreset(tk);
+ tk->dirty = tkrect(tk, 1);
+ return nil;
+}
+
+static int
+adjustforins(int i, int n, int q)
+{
+ if (i <= q)
+ q += n;
+ return q;
+}
+
+static int
+adjustfordel(int d0, int d1, int q)
+{
+ if (d1 <= q)
+ q -= d1 - d0;
+ else if (d0 <= q && q <= d1)
+ q = d0;
+ return q;
+}
+
+static char*
+tkentryget(Tk *tk, char *arg, char **val)
+{
+ TkTop *top;
+ TkEntry *tke;
+ int first, last;
+ char *e, *buf;
+
+ tke = TKobj(TkEntry, tk);
+ if(tke->text == nil)
+ return nil;
+
+ arg = tkskip(arg, " \t");
+ if(*arg == '\0')
+ return tkvalue(val, "%.*S", tke->textlen, tke->text);
+
+ top = tk->env->top;
+ buf = mallocz(Tkmaxitem, 0);
+ if(buf == nil)
+ return TkNomem;
+ arg = tkword(top, arg, buf, buf+Tkmaxitem, nil);
+ e = tkentryparseindex(tk, buf, &first);
+ if(e != nil) {
+ free(buf);
+ return e;
+ }
+ last = first+1;
+ tkword(top, arg, buf, buf+Tkmaxitem, nil);
+ if(buf[0] != '\0') {
+ e = tkentryparseindex(tk, buf, &last);
+ if(e != nil) {
+ free(buf);
+ return e;
+ }
+ }
+ free(buf);
+ if(last <= first || tke->textlen == 0 || first == tke->textlen)
+ return tkvalue(val, "%S", L"");
+ return tkvalue(val, "%.*S", last-first, tke->text+first);
+}
+
+static char*
+tkentryinsert(Tk *tk, char *arg, char **val)
+{
+ TkTop *top;
+ TkEntry *tke;
+ int ins, i, n, locked;
+ char *e, *t, *text, *buf;
+ Rune *etext;
+
+ USED(val);
+ tke = TKobj(TkEntry, tk);
+
+ top = tk->env->top;
+ buf = mallocz(Tkmaxitem, 0);
+ if(buf == nil)
+ return TkNomem;
+ arg = tkword(top, arg, buf, buf+Tkmaxitem, nil);
+ e = tkentryparseindex(tk, buf, &ins);
+ free(buf);
+ if(e != nil)
+ return e;
+
+ if(*arg == '\0')
+ return nil;
+
+ n = strlen(arg) + 1;
+ if(n < Tkmaxitem)
+ n = Tkmaxitem;
+ text = malloc(n);
+ if(text == nil)
+ return TkNomem;
+
+ tkword(top, arg, text, text+n, nil);
+ n = utflen(text);
+ etext = realloc(tke->text, (tke->textlen+n+1)*sizeof(Rune));
+ if(etext == nil) {
+ free(text);
+ return TkNomem;
+ }
+ tke->text = etext;
+
+ memmove(tke->text+ins+n, tke->text+ins, (tke->textlen-ins)*sizeof(Rune));
+ t = text;
+ for(i=0; i<n; i++)
+ t += chartorune(tke->text+ins+i, t);
+ free(text);
+
+ tke->textlen += n;
+
+ tke->sel0 = adjustforins(ins, n, tke->sel0);
+ tke->sel1 = adjustforins(ins, n, tke->sel1);
+ tke->icursor = adjustforins(ins, n, tke->icursor);
+ tke->anchor = adjustforins(ins, n, tke->anchor);
+
+ locked = lockdisplay(tk->env->top->display);
+ if (ins < tke->v0)
+ tke->x0 += entrytextwidth(tk, tke->v0 + n) + (tke->x0 - tke->xv0);
+ if (locked)
+ unlockdisplay(tk->env->top->display);
+ recalcentry(tk);
+
+ e = tkentrysh(tk);
+ blinkreset(tk);
+ tk->dirty = tkrect(tk, 1);
+
+ return e;
+}
+
+static char*
+tkentrydelete(Tk *tk, char *arg, char **val)
+{
+ TkTop *top;
+ TkEntry *tke;
+ int d0, d1, locked;
+ char *e, *buf;
+ Rune *text;
+
+ USED(val);
+
+ tke = TKobj(TkEntry, tk);
+
+ top = tk->env->top;
+ buf = mallocz(Tkmaxitem, 0);
+ if(buf == nil)
+ return TkNomem;
+ arg = tkword(top, arg, buf, buf+Tkmaxitem, nil);
+ e = tkentryparseindex(tk, buf, &d0);
+ if(e != nil) {
+ free(buf);
+ return e;
+ }
+
+ d1 = d0+1;
+ tkword(top, arg, buf, buf+Tkmaxitem, nil);
+ if(buf[0] != '\0') {
+ e = tkentryparseindex(tk, buf, &d1);
+ if(e != nil) {
+ free(buf);
+ return e;
+ }
+ }
+ free(buf);
+ if(d1 <= d0 || tke->textlen == 0 || d0 >= tke->textlen)
+ return nil;
+
+ memmove(tke->text+d0, tke->text+d1, (tke->textlen-d1)*sizeof(Rune));
+ tke->textlen -= d1 - d0;
+
+ text = realloc(tke->text, (tke->textlen+1) * sizeof(Rune));
+ if (text != nil)
+ tke->text = text;
+ tke->sel0 = adjustfordel(d0, d1, tke->sel0);
+ tke->sel1 = adjustfordel(d0, d1, tke->sel1);
+ tke->icursor = adjustfordel(d0, d1, tke->icursor);
+ tke->anchor = adjustfordel(d0, d1, tke->anchor);
+
+ locked = lockdisplay(tk->env->top->display);
+ if (d1 < tke->v0)
+ tke->x0 = entrytextwidth(tk, tke->v0 - (d1 - d0)) + (tke->x0 - tke->xv0);
+ else if (d0 < tke->v0)
+ tke->x0 = entrytextwidth(tk, d0);
+ if (locked)
+ unlockdisplay(tk->env->top->display);
+ recalcentry(tk);
+
+ e = tkentrysh(tk);
+ blinkreset(tk);
+ tk->dirty = tkrect(tk, 1);
+
+ return e;
+}
+
+/* Used for both backspace and DEL. If a selection exists, delete it.
+ * Otherwise delete the character to the left(right) of the insertion
+ * cursor, if any.
+ */
+static char*
+tkentrybs(Tk *tk, char *arg, char **val)
+{
+ TkEntry *tke = TKobj(TkEntry, tk);
+ char *buf, *e;
+ int ix;
+
+ USED(val);
+ USED(arg);
+
+ if(tke->textlen == 0)
+ return nil;
+
+ if(tke->sel0 < tke->sel1)
+ return tkentrydelete(tk, "sel.first sel.last", nil);
+
+ buf = mallocz(Tkmaxitem, 0);
+ if(buf == nil)
+ return TkNomem;
+ tkword(tk->env->top, arg, buf, buf+Tkmaxitem, nil);
+ ix = -1;
+ if(buf[0] != '\0') {
+ e = tkentryparseindex(tk, buf, &ix);
+ if(e != nil) {
+ free(buf);
+ return e;
+ }
+ }
+ if(ix > -1) { /* DEL */
+ if(tke->icursor >= tke->textlen) {
+ free(buf);
+ return nil;
+ }
+ }
+ else { /* backspace */
+ if(tke->icursor == 0) {
+ free(buf);
+ return nil;
+ }
+ tke->icursor--;
+ }
+ snprint(buf, Tkmaxitem, "%d", tke->icursor);
+ e = tkentrydelete(tk, buf, nil);
+ free(buf);
+ return e;
+}
+
+static char*
+tkentrybw(Tk *tk, char *arg, char **val)
+{
+ int start;
+ Rune *text;
+ TkEntry *tke;
+ char buf[32];
+
+ USED(val);
+ USED(arg);
+
+ tke = TKobj(TkEntry, tk);
+ if(tke->textlen == 0 || tke->icursor == 0)
+ return nil;
+
+ text = tke->text;
+ start = tke->icursor-1;
+ while(start > 0 && !tkiswordchar(text[start]))
+ --start;
+ while(start > 0 && tkiswordchar(text[start-1]))
+ --start;
+
+ snprint(buf, sizeof(buf), "%d %d", start, tke->icursor);
+ return tkentrydelete(tk, buf, nil);
+}
+
+char*
+tkentryselect(Tk *tk, char *arg, char **val)
+{
+ TkTop *top;
+ int start, from, to, locked;
+ TkEntry *tke;
+ char *e, *buf;
+
+ buf = mallocz(Tkmaxitem, 0);
+ if(buf == nil)
+ return TkNomem;
+
+ tke = TKobj(TkEntry, tk);
+
+ top = tk->env->top;
+ arg = tkword(top, arg, buf, buf+Tkmaxitem, nil);
+ if(strcmp(buf, "clear") == 0) {
+ tke->sel0 = 0;
+ tke->sel1 = 0;
+ }
+ else
+ if(strcmp(buf, "from") == 0) {
+ tkword(top, arg, buf, buf+Tkmaxitem, nil);
+ e = tkentryparseindex(tk, buf, &tke->anchor);
+ tke->flag &= ~Ewordsel;
+ free(buf);
+ return e;
+ }
+ else
+ if(strcmp(buf, "to") == 0) {
+ tkword(top, arg, buf, buf+Tkmaxitem, nil);
+ e = tkentryparseindex(tk, buf, &to);
+ if(e != nil) {
+ free(buf);
+ return e;
+ }
+
+ if(to < tke->anchor) {
+ if(tke->flag & Ewordsel)
+ while(to > 0 && tkiswordchar(tke->text[to-1]))
+ --to;
+ tke->sel0 = to;
+ tke->sel1 = tke->anchor;
+ }
+ else
+ if(to >= tke->anchor) {
+ if(tke->flag & Ewordsel)
+ while(to < tke->textlen &&
+ tkiswordchar(tke->text[to]))
+ to++;
+ tke->sel0 = tke->anchor;
+ tke->sel1 = to;
+ }
+ tkentrysee(tk, to, 0);
+ recalcentry(tk);
+ }
+ else
+ if(strcmp(buf, "word") == 0) { /* inferno invention */
+ tkword(top, arg, buf, buf+Tkmaxitem, nil);
+ e = tkentryparseindex(tk, buf, &start);
+ if(e != nil) {
+ free(buf);
+ return e;
+ }
+ from = start;
+ while(from > 0 && tkiswordchar(tke->text[from-1]))
+ --from;
+ to = start;
+ while(to < tke->textlen && tkiswordchar(tke->text[to]))
+ to++;
+ tke->sel0 = from;
+ tke->sel1 = to;
+ tke->anchor = from;
+ tke->icursor = from;
+ tke->flag |= Ewordsel;
+ locked = lockdisplay(tk->env->top->display);
+ tke->xicursor = entrytextwidth(tk, tke->icursor);
+ if (locked)
+ unlockdisplay(tk->env->top->display);
+ }
+ else
+ if(strcmp(buf, "present") == 0) {
+ e = tkvalue(val, "%d", tke->sel1 > tke->sel0);
+ free(buf);
+ return e;
+ }
+ else
+ if(strcmp(buf, "range") == 0) {
+ arg = tkword(top, arg, buf, buf+Tkmaxitem, nil);
+ e = tkentryparseindex(tk, buf, &from);
+ if(e != nil) {
+ free(buf);
+ return e;
+ }
+ tkword(top, arg, buf, buf+Tkmaxitem, nil);
+ e = tkentryparseindex(tk, buf, &to);
+ if(e != nil) {
+ free(buf);
+ return e;
+ }
+ tke->sel0 = from;
+ tke->sel1 = to;
+ if(to <= from) {
+ tke->sel0 = 0;
+ tke->sel1 = 0;
+ }
+ }
+ else
+ if(strcmp(buf, "adjust") == 0) {
+ tkword(top, arg, buf, buf+Tkmaxitem, nil);
+ e = tkentryparseindex(tk, buf, &to);
+ if(e != nil) {
+ free(buf);
+ return e;
+ }
+ if(tke->sel0 == 0 && tke->sel1 == 0) {
+ tke->sel0 = tke->anchor;
+ tke->sel1 = to;
+ }
+ else {
+ if(abs(tke->sel0-to) < abs(tke->sel1-to)) {
+ tke->sel0 = to;
+ tke->anchor = tke->sel1;
+ }
+ else {
+ tke->sel1 = to;
+ tke->anchor = tke->sel0;
+ }
+ }
+ if(tke->sel0 > tke->sel1) {
+ to = tke->sel0;
+ tke->sel0 = tke->sel1;
+ tke->sel1 = to;
+ }
+ }
+ else {
+ free(buf);
+ return TkBadcm;
+ }
+ locked = lockdisplay(tk->env->top->display);
+ tke->xsel0 = entrytextwidth(tk, tke->sel0);
+ tke->xsel1 = entrytextwidth(tk, tke->sel1);
+ if (locked)
+ unlockdisplay(tk->env->top->display);
+ tk->dirty = tkrect(tk, 1);
+ free(buf);
+ return nil;
+}
+
+
+static char*
+tkentryb2p(Tk *tk, char *arg, char **val)
+{
+ TkEntry *tke;
+ char *buf;
+
+ USED(val);
+
+ tke = TKobj(TkEntry, tk);
+ buf = malloc(Tkmaxitem);
+ if (buf == nil)
+ return TkNomem;
+
+ tkword(tk->env->top, arg, buf, buf+Tkmaxitem, nil);
+ tke->oldx = atoi(buf);
+ return nil;
+}
+
+static char*
+tkentryxview(Tk *tk, char *arg, char **val)
+{
+ int locked;
+ TkEnv *env;
+ TkEntry *tke;
+ char *buf, *v;
+ int dx, top, bot, amount, ix, x;
+ char *e;
+
+ tke = TKobj(TkEntry, tk);
+ env = tk->env;
+ dx = tk->act.width - 2*xinset(tk);
+
+ buf = mallocz(Tkmaxitem, 0);
+ if(buf == nil)
+ return TkNomem;
+
+ if(*arg == '\0') {
+ if (tke->textlen == 0 || tke->xlen < dx) {
+ bot = TKI2F(0);
+ top = TKI2F(1);
+ } else {
+ bot = TKI2F(tke->x0) / tke->xlen;
+ top = TKI2F(tke->x0 + dx) / tke->xlen;
+ }
+ v = tkfprint(buf, bot);
+ *v++ = ' ';
+ tkfprint(v, top);
+ e = tkvalue(val, "%s", buf);
+ free(buf);
+ return e;
+ }
+
+ arg = tkitem(buf, arg);
+ if(strcmp(buf, "moveto") == 0) {
+ e = tkfracword(env->top, &arg, &top, nil);
+ if (e != nil) {
+ free(buf);
+ return e;
+ }
+ tke->x0 = TKF2I(top*tke->xlen);
+ }
+ else
+ if(strcmp(buf, "scroll") == 0) {
+ arg = tkitem(buf, arg);
+ amount = atoi(buf);
+ if(*arg == 'p') /* Pages */
+ amount *= (9*tke->xlen)/10;
+ else
+ if(*arg == 's') { /* Inferno-ism, "scr", must be used in the context of button2p */
+ x = amount;
+ amount = x < tke->oldx ? env->wzero : (x > tke->oldx ? -env->wzero : 0);
+ tke->oldx = x;
+ }
+ tke->x0 += amount;
+ }
+ else {
+ e = tkentryparseindex(tk, buf, &ix);
+ if(e != nil) {
+ free(buf);
+ return e;
+ }
+ locked = lockdisplay(env->top->display);
+ tke->x0 = entrytextwidth(tk, ix);
+ if (locked)
+ unlockdisplay(env->top->display);
+ }
+ free(buf);
+
+ if (tke->x0 > tke->xlen - dx)
+ tke->x0 = tke->xlen - dx;
+ if (tke->x0 < 0)
+ tke->x0 = 0;
+ recalcentry(tk);
+ e = tkentrysh(tk);
+ blinkreset(tk);
+ tk->dirty = tkrect(tk, 1);
+ return e;
+}
+
+static void
+autoselect(Tk *tk, void *v, int cancelled)
+{
+ TkEntry *tke = TKobj(TkEntry, tk);
+ Rectangle hitr;
+ char buf[32];
+ Point p;
+
+ USED(v);
+
+ if (cancelled)
+ return;
+
+ p = tkscrn2local(tk, Pt(tke->oldx, 0));
+ p.y = 0;
+ if (tkvisiblerect(tk, &hitr) && ptinrect(p, hitr))
+ return;
+
+ snprint(buf, sizeof(buf), "to @%d", p.x);
+ tkentryselect(tk, buf, nil);
+ tkdirty(tk);
+ tkupdate(tk->env->top);
+}
+
+static char*
+tkentryb1p(Tk *tk, char* arg, char **ret)
+{
+ TkEntry *tke = TKobj(TkEntry, tk);
+ Point p;
+ int i, locked, x;
+ char buf[32], *e;
+ USED(ret);
+
+ x = atoi(arg);
+ p = tkscrn2local(tk, Pt(x, 0));
+ sprint(buf, "@%d", p.x);
+ e = tkentryparseindex(tk, buf, &i);
+ if (e != nil)
+ return e;
+ tke->sel0 = 0;
+ tke->sel1 = 0;
+ tke->icursor = i;
+ tke->anchor = i;
+ tke->flag &= ~Ewordsel;
+
+ locked = lockdisplay(tk->env->top->display);
+ tke->xsel0 = 0;
+ tke->xsel1 = 0;
+ tke->xicursor = entrytextwidth(tk, tke->icursor);
+ if (locked)
+ unlockdisplay(tk->env->top->display);
+
+ tke->oldx = x;
+ blinkreset(tk);
+ tkrepeat(tk, autoselect, nil, TkRptpause, TkRptinterval);
+ tk->dirty = tkrect(tk, 0);
+ return nil;
+}
+
+static char*
+tkentryb1m(Tk *tk, char* arg, char **ret)
+{
+ TkEntry *tke = TKobj(TkEntry, tk);
+ Point p;
+ Rectangle hitr;
+ char buf[32];
+ USED(ret);
+
+ p.x = atoi(arg);
+ tke->oldx = p.x;
+ p = tkscrn2local(tk, p);
+ p.y = 0;
+ if (!tkvisiblerect(tk, &hitr) || !ptinrect(p, hitr))
+ return nil;
+ snprint(buf, sizeof(buf), "to @%d", p.x);
+ tkentryselect(tk, buf, nil);
+ return nil;
+}
+
+static char*
+tkentryb1r(Tk *tk, char* arg, char **ret)
+{
+ USED(tk);
+ USED(arg);
+ USED(ret);
+ tkcancelrepeat(tk);
+ return nil;
+}
+
+static void
+blinkreset(Tk *tk)
+{
+ TkEntry *e = TKobj(TkEntry, tk);
+ if (!tkhaskeyfocus(tk) || tk->flag&Tkdisabled)
+ return;
+ e->flag |= Ecursoron;
+ tkblinkreset(tk);
+}
+
+static void
+showcaret(Tk *tk, int on)
+{
+ TkEntry *e = TKobj(TkEntry, tk);
+
+ if (on)
+ e->flag |= Ecursoron;
+ else
+ e->flag &= ~Ecursoron;
+ tk->dirty = tkrect(tk, 0);
+}
+
+char*
+tkentryfocus(Tk *tk, char* arg, char **ret)
+{
+ int on = 0;
+ USED(ret);
+
+ if (tk->flag&Tkdisabled)
+ return nil;
+
+ if(strcmp(arg, " in") == 0) {
+ tkblink(tk, showcaret);
+ on = 1;
+ }
+ else
+ tkblink(nil, nil);
+
+ showcaret(tk, on);
+ return nil;
+}
+
+static
+TkCmdtab tkentrycmd[] =
+{
+ "cget", tkentrycget,
+ "configure", tkentryconf,
+ "delete", tkentrydelete,
+ "get", tkentryget,
+ "icursor", tkentryicursor,
+ "index", tkentryindex,
+ "insert", tkentryinsert,
+ "selection", tkentryselect,
+ "xview", tkentryxview,
+ "tkEntryBS", tkentrybs,
+ "tkEntryBW", tkentrybw,
+ "tkEntryB1P", tkentryb1p,
+ "tkEntryB1M", tkentryb1m,
+ "tkEntryB1R", tkentryb1r,
+ "tkEntryB2P", tkentryb2p,
+ "tkEntryFocus", tkentryfocus,
+ "bbox", tkentrybboxcmd,
+ "see", tkentryseecmd,
+ nil
+};
+
+TkMethod entrymethod = {
+ "entry",
+ tkentrycmd,
+ tkfreeentry,
+ tkdrawentry,
+ tkentrygeom
+};
--- /dev/null
+++ b/libtk/extns.c
@@ -1,0 +1,37 @@
+#include "lib9.h"
+#include "draw.h"
+#include "tk.h"
+
+int
+tkextndeliver(Tk *tk, TkAction *binds, int event, void *data)
+{
+ return tksubdeliver(tk, binds, event, data, 1);
+}
+
+void
+tkextnfreeobj(Tk *tk)
+{
+ USED(tk);
+}
+
+int
+tkextnnewctxt(TkCtxt *ctxt)
+{
+ USED(ctxt);
+ return 0;
+}
+
+void
+tkextnfreectxt(TkCtxt *ctxt)
+{
+ USED(ctxt);
+}
+
+char*
+tkextnparseseq(char *seq, char *rest, int *event)
+{
+ USED(seq);
+ USED(rest);
+ USED(event);
+ return nil;
+}
--- /dev/null
+++ b/libtk/frame.c
@@ -1,0 +1,277 @@
+#include <lib9.h>
+#include <kernel.h>
+#include "draw.h"
+#include "tk.h"
+#include "frame.h"
+
+char*
+tkframe(TkTop *t, char *arg, char **ret)
+{
+ Tk *tk;
+ char *e;
+ TkOptab tko[2];
+ TkName *names;
+
+ tk = tknewobj(t, TKframe, sizeof(Tk));
+ if(tk == nil)
+ return TkNomem;
+
+ tko[0].ptr = tk;
+ tko[0].optab = tkgeneric;
+ tko[1].ptr = nil;
+ names = nil;
+
+ e = tkparse(t, arg, tko, &names);
+ if(e != nil) {
+ tkfreeobj(tk);
+ return e;
+ }
+ tksettransparent(tk, tkhasalpha(tk->env, TkCbackgnd));
+
+ e = tkaddchild(t, tk, &names);
+
+ tkfreename(names);
+ if(e != nil) {
+ tkfreeobj(tk);
+ return e;
+ }
+ tk->name->link = nil;
+
+ return tkvalue(ret, "%s", tk->name->name);
+}
+
+/*
+ * Also used for windows, menus, separators
+ */
+void
+tkfreeframe(Tk *tk)
+{
+ TkWin *tkw;
+
+ if((tk->flag & Tkwindow) == 0)
+ return;
+
+ if(tk->type == TKmenu) {
+ tkw = TKobj(TkWin, tk);
+ free(tkw->postcmd);
+ free(tkw->cascade);
+ free(tkw->cbname);
+ }
+
+ tkunmap(tk); /* XXX do this only if (tk->flag&Tkswept)==0 ?? */
+}
+
+char*
+tkdrawframe(Tk *tk, Point orig)
+{
+ int bw;
+ Point p;
+ Image *i;
+ Tk *f;
+ Rectangle r, slaver; /* dribbling, whipping or just square? */
+
+ i = tkimageof(tk);
+ if(i == nil)
+ return nil;
+
+ p.x = orig.x + tk->act.x + tk->borderwidth;
+ p.y = orig.y + tk->act.y + tk->borderwidth;
+
+ draw(i, rectaddpt(tk->dirty, p), tkgc(tk->env, TkCbackgnd), nil, ZP);
+
+ /*
+ * doesn't matter about drawing TKseparator
+ * oblivious of dirty rect, as it never has any children to sully anyway
+ */
+ if(tk->type == TKseparator) {
+ r = rectaddpt(tkrect(tk, 1), p);
+ r.min.x += 4;
+ r.max.x -= 4;
+ r.min.y += (Dy(r) - 2)/2;
+ r.max.y = r.min.y+1;
+ draw(i, r, tkgc(tk->env, TkCbackgnddark), nil, ZP);
+ r.min.y += 1;
+ r.max.y += 1;
+ draw(i, r, tkgc(tk->env, TkCbackgndlght), nil, ZP);
+ return nil;
+ }
+
+ /*
+ * make sure all the slaves inside the area we've just drawn
+ * refresh themselves properly.
+ */
+ for(f = tk->slave; f; f = f->next) {
+ bw = f->borderwidth;
+ slaver.min.x = f->act.x;
+ slaver.min.y = f->act.y;
+ slaver.max.x = slaver.min.x + f->act.width + 2*bw;
+ slaver.max.y = slaver.min.y + f->act.height + 2*bw;
+ if (rectclip(&slaver, tk->dirty)) {
+ f->flag |= Tkrefresh;
+ slaver = rectsubpt(slaver, Pt(f->act.x + bw, f->act.y + bw));
+ combinerect(&f->dirty, slaver);
+ }
+ }
+ p.x -= tk->borderwidth;
+ p.y -= tk->borderwidth;
+
+ if (!rectinrect(tk->dirty, tkrect(tk, 0)))
+ tkdrawrelief(i, tk, p, TkCbackgnd, tk->relief);
+ return nil;
+}
+
+/* Frame commands */
+
+static char*
+tkframecget(Tk *tk, char *arg, char **val)
+{
+ TkOptab tko[3];
+
+ tko[0].ptr = tk;
+ tko[0].optab = tkgeneric;
+ tko[1].ptr = nil;
+ if(tk->flag & Tkwindow){
+ tko[1].ptr = TKobj(TkWin, tk);
+ tko[1].optab = tktop;
+ tko[2].ptr = nil;
+ }
+
+ return tkgencget(tko, arg, val, tk->env->top);
+}
+
+static char*
+tkframeconf(Tk *tk, char *arg, char **val)
+{
+ char *e;
+ TkGeom g;
+ int bd;
+ Point oldp;
+ TkOptab tko[3];
+ TkWin *tkw;
+
+ tko[0].ptr = tk;
+ tko[0].optab = tkgeneric;
+ tko[1].ptr = nil;
+ tkw = nil;
+ if(tk->flag & Tkwindow) {
+ tkw = TKobj(TkWin, tk);
+ tko[1].ptr = tkw;
+ tko[1].optab = tktop;
+ tko[2].ptr = nil;
+ oldp = tkw->act;
+ }
+
+ if(*arg == '\0')
+ return tkconflist(tko, val);
+
+ if(tkw != nil){
+ /*
+ * see whether only -x or -y is being configured,
+ * in which case just move the window; don't redraw
+ * everything
+ */
+ e = tkparse(tk->env->top, arg, &tko[1], nil);
+ if(e == nil){
+ if(!eqpt(oldp, tkw->req))
+ tkmovewin(tk, tkw->req);
+ return nil;
+ }
+ }
+
+ g = tk->req;
+ bd = tk->borderwidth;
+ e = tkparse(tk->env->top, arg, tko, nil);
+ tksettransparent(tk, tkhasalpha(tk->env, TkCbackgnd));
+ tk->req.x = tk->act.x;
+ tk->req.y = tk->act.y;
+ tkgeomchg(tk, &g, bd);
+ if(tkw != nil && !eqpt(oldp, tkw->act))
+ tkmovewin(tk, tkw->req);
+
+ tk->dirty = tkrect(tk, 1);
+
+ return e;
+}
+
+static char*
+tkframesuspend(Tk *tk, char *arg, char **val)
+{
+ USED(arg);
+ USED(val);
+ if((tk->flag & Tkwindow) == 0)
+ return TkNotwm;
+ tk->flag |= Tksuspended;
+ return nil;
+}
+
+static char*
+tkframemap(Tk *tk, char *arg, char **val)
+{
+ USED(arg);
+ USED(val);
+ if(tk->flag & Tkwindow)
+ return tkmap(tk);
+ return TkNotwm;
+}
+
+static char*
+tkframeunmap(Tk *tk, char *arg, char **val)
+{
+ USED(arg);
+ USED(val);
+ if(tk->flag & Tkwindow) {
+ tkunmap(tk);
+ return nil;
+ }
+ return TkNotwm;
+}
+
+static void
+tkframefocusorder(Tk *tk)
+{
+ int i, n;
+ Tk *sub;
+ TkWinfo *inf;
+
+ n = 0;
+ for (sub = tk->slave; sub != nil; sub = sub->next)
+ n++;
+
+ if (n == 0)
+ return;
+
+ inf = malloc(sizeof(*inf) * n);
+ if (inf == nil)
+ return;
+ i = 0;
+ for (sub = tk->slave; sub != nil; sub = sub->next) {
+ inf[i].w = sub;
+ inf[i].r = rectaddpt(tkrect(sub, 1), Pt(sub->act.x, sub->act.y));
+ i++;
+ }
+ tksortfocusorder(inf, n);
+ for (i = 0; i < n; i++)
+ tkappendfocusorder(inf[i].w);
+ free(inf);
+}
+
+static
+TkCmdtab tkframecmd[] =
+{
+ "cget", tkframecget,
+ "configure", tkframeconf,
+ "map", tkframemap,
+ "unmap", tkframeunmap,
+ "suspend", tkframesuspend,
+ nil
+};
+
+TkMethod framemethod = {
+ "frame",
+ tkframecmd,
+ tkfreeframe,
+ tkdrawframe,
+ nil,
+ nil,
+ tkframefocusorder
+};
--- /dev/null
+++ b/libtk/frame.h
@@ -1,0 +1,2 @@
+extern char* tkdrawframe(Tk*, Point);
+extern void tkfreeframe(Tk*);
--- /dev/null
+++ b/libtk/grids.c
@@ -1,0 +1,1526 @@
+#include "lib9.h"
+#include "draw.h"
+#include "tk.h"
+
+/*
+ * XXX TODO
+ * - grid rowcget|columncget
+ * - grid columnconfigure/rowconfigure accepts a list of indexes?
+ */
+
+#define O(t, e) ((long)(&((t*)0)->e))
+
+typedef struct TkGridparam TkGridparam;
+typedef struct TkBeamparam TkBeamparam;
+
+struct TkGridparam{
+ Point span;
+ Tk* in;
+ Point pad;
+ Point ipad;
+ char *row;
+ char *col;
+ int sticky;
+};
+
+struct TkBeamparam{
+ int minsize;
+ int maxsize;
+ int weight;
+ int pad;
+ char *name;
+ int equalise;
+};
+
+static
+TkOption opts[] =
+{
+ "padx", OPTnndist, O(TkGridparam, pad.x), nil,
+ "pady", OPTnndist, O(TkGridparam, pad.y), nil,
+ "ipadx", OPTnndist, O(TkGridparam, ipad.x), nil,
+ "ipady", OPTnndist, O(TkGridparam, ipad.y), nil,
+ "in", OPTwinp, O(TkGridparam, in), nil,
+ "row", OPTtext, O(TkGridparam, row), nil,
+ "column", OPTtext, O(TkGridparam, col), nil,
+ "rowspan", OPTnndist, O(TkGridparam, span.y), nil,
+ "columnspan", OPTnndist, O(TkGridparam, span.x), nil,
+ "sticky", OPTsticky, O(TkGridparam, sticky), nil,
+ nil
+};
+
+static
+TkOption beamopts[] =
+{
+ "minsize", OPTnndist, O(TkBeamparam, minsize), nil,
+ "maxsize", OPTnndist, O(TkBeamparam, maxsize), nil,
+ "weight", OPTnndist, O(TkBeamparam, weight), nil,
+ "pad", OPTnndist, O(TkBeamparam, pad), nil,
+ "name", OPTtext, O(TkBeamparam, name), nil,
+ "equalise", OPTstab, O(TkBeamparam, equalise), tkbool,
+ nil
+};
+
+void
+printgrid(TkGrid *grid)
+{
+ int x, y;
+ Point dim;
+
+ dim = grid->dim;
+ print("grid %P\n", grid->dim);
+ print(" row heights: ");
+ for(y = 0; y < dim.y; y++)
+ print("%d[%d,%d,w%d,p%d]%s ",
+ grid->rows[y].act,
+ grid->rows[y].minsize,
+ grid->rows[y].maxsize < 0x7fffffff ? grid->rows[y].maxsize : -1,
+ grid->rows[y].weight,
+ grid->rows[y].pad,
+ grid->rows[y].name ? grid->rows[y].name : "");
+ print("\n");
+ print(" col widths: ");
+ for(x = 0; x < dim.x; x++)
+ print("%d[%d,%d,w%d,p%d]%s ",
+ grid->cols[x].act,
+ grid->cols[x].minsize,
+ grid->cols[x].maxsize < 0x7fffffff ? grid->cols[x].maxsize : -1,
+ grid->cols[x].weight,
+ grid->cols[x].pad,
+ grid->cols[x].name ? grid->cols[x].name : "");
+ print("\n");
+ for(y = 0; y < dim.y; y++){
+ print(" row %d: ", y);
+ for(x = 0; x < dim.x; x++){
+ print("%p;", grid->cells[y][x].tk);
+ print("%s%P\t", grid->cells[y][x].tk?grid->cells[y][x].tk->name->name:"(nil)",
+ grid->cells[y][x].span);
+ }
+ print("\n");
+ }
+}
+
+static void
+tkgridsetopt(TkGridparam *p, Tk *tk)
+{
+ if(p->pad.x != -1)
+ tk->pad.x = p->pad.x*2;
+ if(p->pad.y != -1)
+ tk->pad.y = p->pad.y*2;
+ if(p->ipad.x != -1)
+ tk->ipad.x = p->ipad.x*2;
+ if(p->ipad.y != -1)
+ tk->ipad.y = p->ipad.y*2;
+ if(p->sticky != -1)
+ tk->flag = (tk->flag & ~(Tkanchor|Tkfill)) | (p->sticky & (Tkanchor|Tkfill));
+}
+
+static void
+initbeam(TkGridbeam *beam, int n)
+{
+ int i;
+ memset(beam, 0, n * sizeof(TkGridbeam));
+ for(i = 0; i < n; i++)
+ beam[i].maxsize = 0x7fffffff;
+}
+
+static char*
+ensuregridsize(TkGrid *grid, Point dim)
+{
+ TkGridcell **cells, *cellrow;
+ TkGridbeam *cols, *rows;
+ Point olddim;
+ int i;
+ olddim = grid->dim;
+ if(dim.x < olddim.x)
+ dim.x = olddim.x;
+ if(dim.y < olddim.y)
+ dim.y = olddim.y;
+ if(dim.y > olddim.y){
+ cells = realloc(grid->cells, sizeof(TkGridcell*)*dim.y);
+ if(cells == nil)
+ return TkNomem;
+ grid->cells = cells;
+ for(i = olddim.y; i < dim.y; i++){
+ cells[i] = malloc(sizeof(TkGridcell)*dim.x);
+ if(cells[i] == nil){
+ while(--i >= olddim.y)
+ free(cells[i]);
+ return TkNomem;
+ }
+ }
+ rows = realloc(grid->rows, sizeof(TkGridbeam)*dim.y);
+ if(rows == nil)
+ return TkNomem;
+ grid->rows = rows;
+ initbeam(rows + olddim.y, dim.y - olddim.y);
+ grid->dim.y = dim.y;
+ }
+
+ if(dim.x > olddim.x){
+ /*
+ * any newly allocated rows will have the correct number of
+ * columns, so we don't need to reallocate them
+ */
+ cells = grid->cells;
+ for(i = 0; i < olddim.y; i++){
+ cellrow = realloc(cells[i], sizeof(TkGridcell) * dim.x);
+ if(cellrow == nil)
+ return TkNomem; /* leak some earlier rows, but not permanently */
+ memset(cellrow + olddim.x, 0, (dim.x-olddim.x)*sizeof(TkGridcell));
+ cells[i] = cellrow;
+ }
+ cols = realloc(grid->cols, sizeof(TkGridbeam)*dim.x);
+ if(cols == nil)
+ return TkNomem;
+ initbeam(cols + olddim.x, dim.x - olddim.x);
+ grid->cols = cols;
+ grid->dim.x = dim.x;
+ }
+ return nil;
+}
+
+static TkGridbeam*
+delbeams(TkGridbeam *beam, int nb, int x0, int x1)
+{
+ int i;
+ TkGridbeam *b;
+ for(i = x0; i < x1; i++)
+ free(beam[i].name);
+ memmove(&beam[x0], &beam[x1], sizeof(TkGridbeam) * (nb-x1));
+ b = realloc(beam, sizeof(TkGridbeam) * (nb-(x1-x0)));
+ return b ? b : beam;
+}
+
+static void
+delrows(TkGrid *grid, int y0, int y1)
+{
+ TkGridcell **cells;
+ memmove(grid->cells+y0, grid->cells+y1, sizeof(TkGridcell*) * (grid->dim.y-y1));
+ grid->dim.y -= (y1 - y0);
+ cells = realloc(grid->cells, sizeof(TkGridcell*) * grid->dim.y);
+ if(cells != nil || grid->dim.y == 0)
+ grid->cells = cells; /* can realloc to a smaller size ever fail? */
+}
+
+static void
+delcols(TkGrid *grid, int x0, int x1)
+{
+ TkGridcell **cells, *row;
+ int y, ndx;
+ Point dim;
+ dim = grid->dim;
+ ndx = dim.x - (x1 - x0);
+ cells = grid->cells;
+ for(y = 0; y < dim.y; y++){
+ row = cells[y];
+ memmove(row+x0, row+x1, sizeof(TkGridcell) * (dim.x - x1));
+ row = realloc(row, sizeof(TkGridcell) * ndx);
+ if(row != nil || ndx == 0)
+ cells[y] = row;
+ }
+ grid->dim.x = ndx;
+}
+
+/*
+ * insert items into rows/cols; the beam has already been expanded appropriately.
+ */
+void
+insbeams(TkGridbeam *beam, int nb, int x, int n)
+{
+ memmove(&beam[x+n], &beam[x], sizeof(TkGridbeam)*(nb-x-n));
+ initbeam(beam+x, n);
+}
+
+static char*
+insrows(TkGrid *grid, int y0, int n)
+{
+ Point olddim;
+ char *e;
+ TkGridcell **cells, *tmp;
+ int y;
+
+ olddim = grid->dim;
+ if(y0 > olddim.y){
+ n = y0 + n - olddim.y;
+ y0 = olddim.y;
+ }
+
+ e = ensuregridsize(grid, Pt(olddim.x, olddim.y + n));
+ if(e != nil)
+ return e;
+ /*
+ * we know the extra rows will have been filled
+ * with blank, properly allocated rows, so just swap 'em with the
+ * ones that need moving.
+ */
+ cells = grid->cells;
+ for(y = olddim.y - 1; y >= y0; y--){
+ tmp = cells[y + n];
+ cells[y + n] = cells[y];
+ cells[y] = tmp;
+ }
+ insbeams(grid->rows, grid->dim.y, y0, n);
+ return nil;
+}
+
+static char*
+inscols(TkGrid *grid, int x0, int n)
+{
+ TkGridcell **cells;
+ Point olddim;
+ int y;
+ char *e;
+
+ olddim = grid->dim;
+ if(x0 > olddim.x){
+ n = x0 + n - olddim.x;
+ x0 = olddim.x;
+ }
+
+ e = ensuregridsize(grid, Pt(olddim.x + n, olddim.y));
+ if(e != nil)
+ return e;
+
+ cells = grid->cells;
+ for(y = 0; y < olddim.y; y++){
+ memmove(cells[y] + x0 + n, cells[y] + x0, sizeof(TkGridcell) * (olddim.x - x0));
+ memset(cells[y] + x0, 0, sizeof(TkGridcell) * n);
+ }
+ insbeams(grid->cols, grid->dim.x, x0, n);
+ return nil;
+}
+
+static int
+maximum(int a, int b)
+{
+ if(a > b)
+ return a;
+ return b;
+}
+
+/*
+ * return the width of cols/rows between x0 and x1 in the beam,
+ * excluding the padding at either end, but including padding in the middle.
+ */
+static int
+beamsize(TkGridbeam *cols, int x0, int x1)
+{
+ int tot, fpad, x;
+
+ if(x0 >= x1)
+ return 0;
+
+ tot = cols[x0].act;
+ fpad = cols[x0].pad;
+ for(x = x0 + 1; x < x1; x++){
+ tot += cols[x].act + maximum(cols[x].pad, fpad);
+ fpad = cols[x].pad;
+ }
+ return tot;
+}
+
+/*
+ * return starting position of cell index on beam, relative
+ * to top-left of grid
+ */
+static int
+beamcellpos(TkGridbeam *beam, int blen, int index)
+{
+ int x;
+ if(blen == 0 || index >= blen || index < 0)
+ return 0;
+ x = beam[0].pad + beamsize(beam, 0, index);
+ if(index > 0)
+ x += maximum(beam[index-1].pad, beam[index].pad);
+ return x;
+}
+
+static Rectangle
+cellbbox(TkGrid *grid, Point pos)
+{
+ Point dim;
+ Rectangle r;
+
+ dim = grid->dim;
+ if(pos.x > dim.x)
+ pos.x = dim.x;
+ if(pos.y > dim.y)
+ pos.y = dim.y;
+
+ r.min.x = beamcellpos(grid->cols, dim.x, pos.x);
+ r.min.y = beamcellpos(grid->rows, dim.y, pos.y);
+ if(pos.x == dim.x)
+ r.max.x = r.min.x;
+ else
+ r.max.x = r.min.x + grid->cols[pos.x].act;
+ if(pos.y == dim.y)
+ r.max.y = r.min.y;
+ else
+ r.max.y = r.min.y + grid->rows[pos.y].act;
+ return rectaddpt(r, grid->origin);
+}
+
+/*
+ * return true ifthere are any spanning cells covering row _index_
+ */
+static int
+gridrowhasspan(TkGrid *grid, int index)
+{
+ int i, d;
+ Point dim;
+ TkGridcell *cell;
+
+ dim = grid->dim;
+ if(index > 0 && index < dim.y){
+ for(i = 0; i < dim.x; i++){
+ cell = &grid->cells[index][i];
+ if(cell->tk != nil){
+ d = cell->span.x;
+ if(d == 0)
+ return 1;
+ i += d - 1;
+ }
+ }
+ }
+ return 0;
+}
+
+/*
+ * return true ifthere are any spanning cells covering column _index_
+ */
+static int
+gridcolhasspan(TkGrid *grid, int index)
+{
+ int i, d;
+ Point dim;
+ TkGridcell *cell;
+
+ dim = grid->dim;
+ if(index > 0 && index < dim.x){
+ for(i = 0; i < dim.y; i++){
+ cell = &grid->cells[i][index];
+ if(cell->tk != nil){
+ d = cell->span.y;
+ if(d == 0)
+ return 1;
+ i += d - 1;
+ }
+ }
+ }
+ return 0;
+}
+
+/*
+ * find cell that's spanning the grid position p
+ */
+static int
+findspan(TkGrid *grid, Point p, Point *cp)
+{
+ Point dim;
+ TkGridcell **cells;
+ Tk *tk;
+
+ dim = grid->dim;
+ cells = grid->cells;
+
+ if(p.x < 0 || p.y < 0 || p.x >= dim.x || p.y >= dim.y)
+ return 0;
+
+ if(cells[p.y][p.x].tk == nil)
+ return 0;
+
+ if(cells[p.y][p.x].span.x == 0){
+ tk = cells[p.y][p.x].tk;
+ for(; p.y >= 0; p.y--)
+ if(cells[p.y][p.x].tk != tk)
+ break;
+ p.y++;
+ for(; p.x >= 0; p.x--)
+ if(cells[p.y][p.x].tk != tk)
+ break;
+ p.x++;
+ }
+ *cp = p;
+ return 1;
+}
+
+static int
+parsegridindex(TkGridbeam *beam, int blen, char *s)
+{
+ int n, i;
+ char *e;
+
+ if(s[0] == '\0')
+ return -1;
+
+ n = strtol(s, &e, 10);
+ if(*e == '\0')
+ return n;
+
+ if(strcmp(s, "end") == 0)
+ return blen;
+
+ for(i = 0; i < blen; i++)
+ if(beam[i].name != nil && strcmp(beam[i].name, s) == 0)
+ return i;
+ return -1;
+}
+
+static char*
+tkgridconfigure(TkTop *t, TkGridparam *p, TkName *names)
+{
+ TkGrid *grid;
+ TkGridcell **cells;
+ TkName *n;
+ Tk *tkf, *tkp;
+ Point dim, pos, q, span, startpos;
+ int maxcol, c, i, j, x;
+ char *e;
+
+ if(names == nil)
+ return nil;
+
+ if(p->span.x < 1 || p->span.y < 1)
+ return TkBadvl;
+
+ tkf = nil;
+
+ maxcol = 0;
+ for(n = names; n; n = n->link){
+ c = n->name[0];
+ if((c=='-' || c=='^' || c=='x') && n->name[1] == '\0'){
+ maxcol++;
+ continue;
+ }
+ tkp = tklook(t, n->name, 0);
+ if(tkp == nil){
+ tkerr(t, n->name);
+ return TkBadwp;
+ }
+ if(tkp->flag & Tkwindow)
+ return TkIstop;
+ if(tkp->parent != nil)
+ return TkWpack;
+
+ /*
+ * unpacking now does give an non-reversible side effect
+ * ifthere's an error encountered later, but also means
+ * that a widget repacked in the same grid will
+ * have its original cell still available
+ */
+ if(tkp->master != nil){
+ tkpackqit(tkp->master);
+ tkdelpack(tkp);
+ }
+ if(tkf == nil)
+ tkf = tkp;
+ n->obj = tkp;
+ tkp->flag &= ~Tkgridpack;
+ maxcol += p->span.x;
+ }
+
+ if(p->in == nil && tkf != nil)
+ p->in = tklook(t, tkf->name->name, 1);
+
+ if(p->in == nil)
+ return TkNomaster;
+
+ grid = p->in->grid;
+ if(grid == nil && p->in->slave != nil)
+ return TkNotgrid;
+
+ if(grid == nil){
+ grid = malloc(sizeof(TkGrid));
+ if(grid == nil)
+ return TkNomem;
+ p->in->grid = grid;
+ }
+
+ dim = grid->dim;
+ pos = ZP;
+ if(p->row != nil){
+ pos.y = parsegridindex(grid->rows, dim.y, p->row);
+ if(pos.y < 0)
+ return TkBadix;
+ }
+ if(p->col != nil){
+ pos.x = parsegridindex(grid->cols, dim.x, p->col);
+ if(pos.x < 0)
+ return TkBadix;
+ }
+ /*
+ * ifrow is not specified, find first unoccupied row
+ */
+ if(p->row == nil){
+ for(pos.y = 0; pos.y < dim.y; pos.y++){
+ for(x = 0; x < dim.x; x++)
+ if(grid->cells[pos.y][x].tk != nil)
+ break;
+ if(x == dim.x)
+ break;
+ }
+ }
+ e = ensuregridsize(grid, Pt(pos.x + maxcol, pos.y + p->span.y));
+ if(e != nil)
+ return e;
+ cells = grid->cells;
+
+ startpos = pos;
+ /*
+ * check that all our grid cells are empty, and that row/col spans
+ * are well formed
+ */
+ n = names;
+ while(n != nil){
+ c = n->name[0];
+ switch (c){
+ case 'x':
+ n = n->link;
+ pos.x++;
+ break;
+ case '^':
+ if(findspan(grid, Pt(pos.x, pos.y - 1), &q) == 0)
+ return TkBadspan;
+ span = cells[q.y][q.x].span;
+ for(i = 0; i < span.x; i++){
+ if(n == nil || strcmp(n->name, "^"))
+ return TkBadspan;
+ if(cells[pos.y][pos.x + i].tk != nil)
+ return TkBadgridcell;
+ n = n->link;
+ }
+ pos.x += span.x;
+ break;
+ case '-':
+ return TkBadspan;
+ case '.':
+ tkp = n->obj;
+ if(tkisslave(p->in, tkp))
+ return TkRecur;
+ n = n->link;
+ if(tkp->flag & Tkgridpack)
+ return TkWpack;
+ tkp->flag |= Tkgridpack;
+ span = p->span;
+ for(; n != nil && strcmp(n->name, "-") == 0; n = n->link)
+ span.x++;
+ for(i = pos.x; i < pos.x + span.x; i++)
+ for(j = pos.y; j < pos.y + span.y; j++)
+ if(cells[j][i].tk != nil)
+ return TkBadgridcell;
+ pos.x = i;
+ break;
+ }
+ }
+
+ /*
+ * actually insert the items into the grid
+ */
+ n = names;
+ pos = startpos;
+ while(n != nil){
+ c = n->name[0];
+ switch (c){
+ case 'x':
+ n = n->link;
+ pos.x++;
+ break;
+ case '^':
+ findspan(grid, Pt(pos.x, pos.y - 1), &q);
+ span = cells[q.y][q.x].span;
+ tkf = cells[q.y][q.x].tk;
+ if(q.y + span.y == pos.y)
+ cells[q.y][q.x].span.y++;
+
+ for(i = 0; i < span.x; i++){
+ cells[pos.y][pos.x++].tk = tkf;
+ n = n->link;
+ }
+ break;
+ case '.':
+ tkf = n->obj;
+ n = n->link;
+ span = p->span;
+ for(; n != nil && strcmp(n->name, "-") == 0; n = n->link)
+ span.x++;
+ for(i = pos.x; i < pos.x + span.x; i++)
+ for(j = pos.y; j < pos.y + span.y; j++)
+ cells[j][i].tk = tkf;
+ cells[pos.y][pos.x].span = span;
+ tkf->master = p->in;
+ tkf->next = p->in->slave;
+ p->in->slave = tkf;
+ if(p->in->flag & Tksubsub)
+ tksetbits(tkf, Tksubsub);
+ tkgridsetopt(p, tkf);
+ pos.x = i;
+ break;
+ }
+ }
+ tkpackqit(p->in);
+ tkrunpack(t);
+ return nil;
+}
+
+void
+tkgriddelslave(Tk *tk)
+{
+ int y, x, yy;
+ TkGrid *grid;
+ TkGridcell **cells, *cell;
+ Point dim, span;
+
+ if(tk == nil || tk->master == nil || tk->master->grid == nil)
+ return;
+ grid = tk->master->grid;
+ cells = grid->cells;
+ dim = grid->dim;
+ for(y = 0; y < dim.y; y++){
+ for(x = 0; x < dim.x; x++){
+ cell = &cells[y][x];
+ if(cell->tk == tk){
+ span = cell->span;
+ for(yy = y; yy < y + span.y; yy++)
+ memset(cells[yy] + x, 0, span.x * sizeof(TkGridcell));
+ return;
+ }
+ }
+ }
+}
+
+char*
+tkgetgridmaster(TkTop *t, char **arg, char *buf, char *ebuf, Tk **master)
+{
+ TkGrid *grid;
+
+ *arg = tkword(t, *arg, buf, ebuf, nil);
+ *master = tklook(t, buf, 0);
+ if(*master == nil)
+ return TkBadwp;
+ grid = (*master)->grid;
+ if(grid == nil && (*master)->slave != nil)
+ return TkNotgrid;
+ return nil;
+}
+
+static int
+gridfindloc(TkGridbeam *beam, int blen, int f)
+{
+ int x, i, fpad;
+ if(blen == 0 || f < 0)
+ return -1;
+
+ fpad = 0;
+ x = 0;
+ for(i = 0; i < blen; i++){
+ x += maximum(fpad, beam[i].pad);
+ if(x <= f && f < x + beam[i].act)
+ return i;
+ x += beam[i].act;
+ }
+ return -1;
+}
+
+static char*
+tkgridcellinfo(TkTop *t, char *arg, char **val, char *buf, char *ebuf)
+{
+ /* grid cellinfo master x y */
+ Tk *master;
+ char *e;
+ Point p;
+ TkGrid *grid;
+ TkGridcell **cells;
+
+ e = tkgetgridmaster(t, &arg, buf, ebuf, &master);
+ if(e != nil || master->grid == nil)
+ return e;
+ grid = master->grid;
+
+ e = tkfracword(t, &arg, &p.x, nil);
+ if(e != nil)
+ return e;
+ e = tkfracword(t, &arg, &p.y, nil);
+ if(e != nil)
+ return e;
+
+ p.x = TKF2I(p.x);
+ p.y = TKF2I(p.y);
+ if(p.x < 0 || p.x >= grid->dim.x || p.y < 0 || p.y >= grid->dim.y)
+ return nil;
+
+ if(!findspan(grid, p, &p))
+ return nil;
+
+ cells = grid->cells;
+ return tkvalue(val, "%s -in %s -column %d -row %d -columnspan %d -rowspan %d",
+ cells[p.y][p.x].tk->name->name,
+ cells[p.y][p.x].tk->master->name->name, p.x, p.y,
+ cells[p.y][p.x].span.x, cells[p.y][p.x].span.y);
+}
+
+static char*
+tkgridlocation(TkTop *t, char *arg, char **val, char *buf, char *ebuf)
+{
+ /* grid location master x y */
+ Tk *master;
+ char *e;
+ Point p;
+ int col, row;
+ TkGrid *grid;
+
+ e = tkgetgridmaster(t, &arg, buf, ebuf, &master);
+ if(e != nil || master->grid == nil)
+ return e;
+ grid = master->grid;
+
+ e = tkfracword(t, &arg, &p.x, nil);
+ if(e != nil)
+ return e;
+ e = tkfracword(t, &arg, &p.y, nil);
+ if(e != nil)
+ return e;
+
+ p.x = TKF2I(p.x);
+ p.y = TKF2I(p.y);
+
+ p = subpt(p, grid->origin);
+ col = gridfindloc(grid->cols, grid->dim.x, p.x);
+ row = gridfindloc(grid->rows, grid->dim.y, p.y);
+ if(col < 0 || row < 0)
+ return nil;
+ return tkvalue(val, "%d %d", col, row);
+}
+
+static char*
+tkgridinfo(TkTop *t, char *arg, char **val, char *buf, char *ebuf)
+{
+ Tk *tk;
+ TkGrid *grid;
+ int x, y;
+ Point dim;
+ TkGridcell *row;
+
+ tkword(t, arg, buf, ebuf, nil);
+ tk = tklook(t, buf, 0);
+ if(tk == nil)
+ return TkBadwp;
+ if(tk->master == nil || tk->master->grid == nil)
+ return TkNotgrid;
+ grid = tk->master->grid;
+ dim = grid->dim;
+ for(y = 0; y < dim.y; y++){
+ row = grid->cells[y];
+ for(x = 0; x < dim.x; x++)
+ if(row[x].tk == tk)
+ goto Found;
+ }
+ return TkNotgrid; /* should not happen */
+Found:
+ return tkvalue(val, "-in %s -column %d -row %d -columnspan %d -rowspan %d",
+ tk->master->name->name, x, y, grid->cells[y][x].span.x, grid->cells[y][x].span.y);
+}
+
+static char*
+tkgridforget(TkTop *t, char *arg, char *buf, char *ebuf)
+{
+ Tk *tk;
+ for(;;){
+ arg = tkword(t, arg, buf, ebuf, nil);
+ if(arg == nil || buf[0] == '\0')
+ break;
+ tk = tklook(t, buf, 0);
+ if(tk == nil){
+ tkrunpack(t);
+ tkerr(t, buf);
+ return TkBadwp;
+ }
+ tkpackqit(tk->master);
+ tkdelpack(tk);
+ }
+ tkrunpack(t);
+ return nil;
+}
+
+static char*
+tkgridslaves(TkTop *t, char *arg, char **val, char *buf, char *ebuf)
+{
+ Tk *master, *tk;
+ char *fmt;
+ int i, isrow, index;
+ TkGrid *grid;
+ TkGridcell *cell;
+ char *e;
+ e = tkgetgridmaster(t, &arg, buf, ebuf, &master);
+ if(e != nil || master->grid == nil)
+ return e;
+ grid = master->grid;
+ arg = tkword(t, arg, buf, ebuf, nil);
+ fmt = "%s";
+ if(buf[0] == '\0'){
+ for(tk = master->slave; tk != nil; tk = tk->next){
+ if(tk->name != nil){
+ e = tkvalue(val, fmt, tk->name->name);
+ if(e != nil)
+ return e;
+ fmt = " %s";
+ }
+ }
+ return nil;
+ }
+ if(strcmp(buf, "-row") == 0)
+ isrow = 1;
+ else if(strcmp(buf, "-column") == 0)
+ isrow = 0;
+ else
+ return TkBadop;
+ tkword(t, arg, buf, ebuf, nil);
+ if(isrow)
+ index = parsegridindex(grid->rows, grid->dim.y, buf);
+ else
+ index = parsegridindex(grid->cols, grid->dim.x, buf);
+ if(index < 0)
+ return TkBadix;
+ if(isrow){
+ if(index >= grid->dim.y)
+ return nil;
+ for(i = 0; i < grid->dim.x; i++){
+ cell = &grid->cells[index][i];
+ if(cell->tk != nil && cell->span.x > 0 && cell->tk->name != nil){
+ e = tkvalue(val, fmt, cell->tk->name->name);
+ if(e != nil)
+ return e;
+ fmt = " %s";
+ }
+ }
+ } else{
+ if(index >= grid->dim.x)
+ return nil;
+ for(i = 0; i < grid->dim.y; i++){
+ cell = &grid->cells[i][index];
+ if(cell->tk != nil && cell->span.x > 0 && cell->tk->name != nil){
+ e = tkvalue(val, fmt, cell->tk->name->name);
+ if(e != nil)
+ return e;
+ fmt = " %s";
+ }
+ }
+ }
+
+ return nil;
+}
+
+static char*
+tkgriddelete(TkTop *t, char *arg, char *buf, char *ebuf, int delrow)
+{
+ Tk *master, **l, *f;
+ TkGrid *grid;
+ TkGridbeam *beam;
+ int blen, i0, i1, x, y;
+ Point dim;
+ TkGridcell **cells;
+ char *e;
+
+ /*
+ * grid (columndelete|rowdelete) master index0 ?index1?
+ */
+
+ e = tkgetgridmaster(t, &arg, buf, ebuf, &master);
+ if(e != nil || master->grid == nil)
+ return e;
+ grid = master->grid;
+
+ if(delrow){
+ beam = grid->rows;
+ blen = grid->dim.y;
+ } else{
+ beam = grid->cols;
+ blen = grid->dim.x;
+ }
+
+ arg = tkword(t, arg, buf, ebuf, nil);
+ i0 = parsegridindex(beam, blen, buf);
+ if(i0 < 0)
+ return TkBadix;
+
+ tkword(t, arg, buf, ebuf, nil);
+ if(buf[0] == '\0')
+ i1 = i0 + 1;
+ else
+ i1 = parsegridindex(beam, blen, buf);
+ if(i1 < 0 || i0 > i1)
+ return TkBadix;
+ if(i0 > blen || i0 == i1)
+ return nil;
+ if(i1 > blen)
+ i1 = blen;
+ cells = grid->cells;
+ dim = grid->dim;
+ if(delrow){
+ if(gridrowhasspan(grid, i0) || gridrowhasspan(grid, i1))
+ return TkBadgridcell;
+ for(y = i0; y < i1; y++)
+ for(x = 0; x < dim.x; x++)
+ if(cells[y][x].tk != nil)
+ cells[y][x].tk->flag |= Tkgridremove;
+ delrows(grid, i0, i1);
+ grid->rows = delbeams(beam, blen, i0, i1);
+ } else{
+ if(gridcolhasspan(grid, i0) || gridcolhasspan(grid, i1))
+ return TkBadgridcell;
+ for(y = 0; y < dim.y; y++)
+ for(x = i0; x < i1; x++)
+ if(cells[y][x].tk != nil)
+ cells[y][x].tk->flag |= Tkgridremove;
+ delcols(grid, i0, i1);
+ grid->cols = delbeams(beam, blen, i0, i1);
+ }
+ l = &master->slave;
+ for(f = *l; f; f = f->next){
+ if(f->flag & Tkgridremove){
+ *l = f->next;
+ f->master = nil;
+ f->flag &= ~Tkgridremove;
+ } else
+ l = &f->next;
+ }
+ tkpackqit(master);
+ tkrunpack(t);
+ return nil;
+}
+
+
+static char*
+tkgridinsert(TkTop *t, char *arg, char *buf, char *ebuf, int insertrow)
+{
+ int index, count;
+ Point dim;
+ Tk *master;
+ TkGrid *grid;
+ int gotarg;
+ char *e;
+
+ /*
+ * grid (rowinsert|columninsert) master index ?count?
+ * it's an error ifthe insert splits any spanning cells.
+ */
+ e = tkgetgridmaster(t, &arg, buf, ebuf, &master);
+ if(e != nil || master->grid == nil)
+ return e;
+ grid = master->grid;
+ dim = grid->dim;
+
+ arg = tkword(t, arg, buf, ebuf, nil);
+ if(insertrow)
+ index = parsegridindex(grid->rows, dim.y, buf);
+ else
+ index = parsegridindex(grid->cols, dim.x, buf);
+ if(index < 0 || index > (insertrow ? dim.y : dim.x))
+ return TkBadix;
+
+ tkword(t, arg, buf, ebuf, &gotarg);
+ if(gotarg){
+ count = strtol(buf, &buf, 10);
+ if(buf[0] != '\0' || count < 0)
+ return TkBadvl;
+ } else
+ count = 1;
+
+ /*
+ * check that we're not splitting any spanning cells
+ */
+ if(insertrow){
+ if(gridrowhasspan(grid, index))
+ return TkBadgridcell;
+ e = insrows(grid, index, count);
+ } else{
+ if(gridcolhasspan(grid, index))
+ return TkBadgridcell;
+ e = inscols(grid, index, count);
+ }
+ tkpackqit(master);
+ tkrunpack(t);
+ return e;
+}
+
+/*
+ * (rowconfigure|columnconfigure) master index ?-option value ...?
+ */
+static char*
+tkbeamconfigure(TkTop *t, char *arg, int isrow)
+{
+ TkBeamparam p;
+ TkOptab tko[2];
+ TkName *names;
+ Tk *master;
+ int index;
+ TkGrid *grid;
+ TkGridbeam *beam;
+ Point dim;
+ char *e;
+
+ p.equalise = BoolX;
+ p.name = nil;
+ p.weight = -1;
+ p.minsize = -1;
+ p.maxsize = -1;
+ p.pad = -1;
+
+ tko[0].ptr = &p;
+ tko[0].optab = beamopts;
+ tko[1].ptr = nil;
+
+ names = nil;
+ e = tkparse(t, arg, tko, &names);
+ if(e != nil)
+ return e;
+
+ if(names == nil || names->link == nil)
+ return TkBadvl;
+
+ master = tklook(t, names->name, 0);
+ if(master == nil)
+ return TkBadwp;
+
+ grid = master->grid;
+ if(grid == nil){
+ if(master->slave != nil)
+ return TkNotgrid;
+ grid = master->grid = malloc(sizeof(TkGrid));
+ if(grid == nil){
+ tkfreename(names);
+ return TkNomem;
+ }
+ }
+
+ if(isrow){
+ index = parsegridindex(grid->rows, grid->dim.y, names->link->name);
+ } else
+ index = parsegridindex(grid->cols, grid->dim.x, names->link->name);
+ if(index < 0){
+ e = TkBadix;
+ goto Error;
+ }
+ if(isrow)
+ dim = Pt(grid->dim.x, index + 1);
+ else
+ dim = Pt(index + 1, grid->dim.y);
+ e = ensuregridsize(grid, dim);
+ if(e != nil)
+ goto Error;
+
+ if(isrow)
+ beam = &grid->rows[index];
+ else
+ beam = &grid->cols[index];
+
+ if(p.minsize >= 0)
+ beam->minsize = p.minsize;
+ if(p.maxsize >= 0)
+ beam->maxsize = p.maxsize;
+ if(p.weight >= 0)
+ beam->weight = p.weight;
+ if(p.pad >= 0)
+ beam->pad = p.pad;
+ if(p.name != nil){
+ free(beam->name);
+ beam->name = p.name;
+ }
+ if(p.equalise != BoolX)
+ beam->equalise = p.equalise == BoolT;
+
+ tkpackqit(master);
+ tkrunpack(t);
+
+Error:
+ tkfreename(names);
+ return e;
+}
+
+char*
+tkgridsize(TkTop *t, char *arg, char **val, char *buf, char *ebuf)
+{
+ Tk *master;
+ TkGrid *grid;
+ char *e;
+
+ e = tkgetgridmaster(t, &arg, buf, ebuf, &master);
+ if(e != nil)
+ return e;
+ grid = master->grid;
+ if(grid == nil)
+ return tkvalue(val, "0 0");
+ else
+ return tkvalue(val, "%d %d", grid->dim.x, grid->dim.y);
+}
+
+char*
+tkgridbbox(TkTop *t, char *arg, char **val, char *buf, char *ebuf)
+{
+ Point p0, p1;
+ Tk *master;
+ TkGrid *grid;
+ char *e;
+ int gotarg;
+ Point dim;
+ Rectangle r;
+
+ e = tkgetgridmaster(t, &arg, buf, ebuf, &master);
+ if(e != nil || master->grid == nil)
+ return e;
+
+ grid = master->grid;
+ dim = grid->dim;
+ arg = tkword(t, arg, buf, ebuf, &gotarg);
+ if(!gotarg){
+ p0 = ZP;
+ p1 = dim;
+ } else{
+ p0.x = parsegridindex(grid->cols, dim.x, buf);
+ arg = tkword(t, arg, buf, ebuf, &gotarg);
+ if(!gotarg)
+ return TkFewpt;
+ p0.y = parsegridindex(grid->rows, dim.y, buf);
+ arg = tkword(t, arg, buf, ebuf, &gotarg);
+ if(!gotarg){
+ p1 = p0;
+ } else{
+ p1.x = parsegridindex(grid->cols, dim.x, buf);
+ arg = tkword(t, arg, buf, ebuf, &gotarg);
+ if(!gotarg)
+ return TkFewpt;
+ p1.y = parsegridindex(grid->rows, dim.y, buf);
+ }
+ }
+ if(p0.x < 0 || p0.y < 0 || p1.x < 0 || p1.y < 0)
+ return TkBadix;
+
+ r = cellbbox(grid, p0);
+ if(!eqpt(p0, p1))
+ combinerect(&r, cellbbox(grid, p1));
+ return tkvalue(val, "%d %d %d %d", r.min.x, r.min.y, r.max.x, r.max.y);
+}
+
+char*
+tkgridindex(TkTop *t, char *arg, char **val, char *buf, char *ebuf, int isrow)
+{
+ Tk *master;
+ TkGrid *grid;
+ TkGridbeam *beam;
+ int blen, i;
+
+ arg = tkword(t, arg, buf, ebuf, nil);
+ master = tklook(t, buf, 0);
+ if(master == nil)
+ return TkBadwp;
+ tkword(t, arg, buf, ebuf, nil);
+ grid = master->grid;
+ if(grid == nil){
+ beam = nil;
+ blen = 0;
+ } else if(isrow){
+ beam = grid->rows;
+ blen = grid->dim.y;
+ } else{
+ beam = grid->cols;
+ blen = grid->dim.x;
+ }
+ i = parsegridindex(beam, blen, buf);
+ if(i < 0)
+ return TkBadix;
+ return tkvalue(val, "%d", i);
+}
+
+void
+tkfreegrid(TkGrid *grid)
+{
+ Point dim;
+ int i;
+ dim = grid->dim;
+ for(i = 0; i < dim.x; i++)
+ free(grid->cols[i].name);
+ for(i = 0; i < dim.y; i++)
+ free(grid->rows[i].name);
+ for(i = 0; i < dim.y; i++)
+ free(grid->cells[i]);
+ free(grid->cells);
+ free(grid->rows);
+ free(grid->cols);
+ free(grid);
+}
+
+char*
+tkgrid(TkTop *t, char *arg, char **val)
+{
+ TkGridparam *p;
+ TkOptab tko[2];
+ TkName *names;
+ char *e, *w, *buf;
+
+ buf = mallocz(Tkmaxitem, 0);
+ if(buf == nil)
+ return TkNomem;
+
+ w = tkword(t, arg, buf, buf+Tkmaxitem, nil);
+ if('a' <= buf[0] && buf[0] <= 'z'){
+ if(strcmp(buf, "debug") == 0){
+ Tk *tk;
+ e = tkgetgridmaster(t, &w, buf, buf+Tkmaxitem, &tk);
+ if(e == nil)
+ printgrid(tk->grid);
+ } else
+ if(strcmp(buf, "forget") == 0)
+ e = tkgridforget(t, w, buf, buf+Tkmaxitem);
+ else if(strcmp(buf, "propagate") == 0)
+ e = tkpropagate(t, w);
+ else if(strcmp(buf, "slaves") == 0)
+ e = tkgridslaves(t, w, val, buf, buf+Tkmaxitem);
+ else if(strcmp(buf, "rowconfigure") == 0)
+ e = tkbeamconfigure(t, w, 1);
+ else if(strcmp(buf, "columnconfigure") == 0)
+ e = tkbeamconfigure(t, w, 0);
+ else if(strcmp(buf, "rowinsert") == 0)
+ e = tkgridinsert(t, w, buf, buf+Tkmaxitem, 1);
+ else if(strcmp(buf, "columninsert") == 0)
+ e = tkgridinsert(t, w, buf, buf+Tkmaxitem, 0);
+ else if(strcmp(buf, "size") == 0)
+ e = tkgridsize(t, w, val, buf, buf+Tkmaxitem);
+ else if(strcmp(buf, "rowdelete") == 0)
+ e = tkgriddelete(t, w, buf, buf+Tkmaxitem, 1);
+ else if(strcmp(buf, "columndelete") == 0)
+ e = tkgriddelete(t, w, buf, buf+Tkmaxitem, 0);
+ else if(strcmp(buf, "rowindex") == 0)
+ e = tkgridindex(t, w, val, buf, buf+Tkmaxitem, 1);
+ else if(strcmp(buf, "columnindex") == 0)
+ e = tkgridindex(t, w, val, buf, buf+Tkmaxitem, 0);
+ else if(strcmp(buf, "bbox") == 0)
+ e = tkgridbbox(t, w, val, buf, buf+Tkmaxitem);
+ else if(strcmp(buf, "location") == 0)
+ e = tkgridlocation(t, w, val, buf, buf+Tkmaxitem);
+ else if(strcmp(buf, "cellinfo") == 0)
+ e = tkgridcellinfo(t, w, val, buf, buf+Tkmaxitem);
+ else if(strcmp(buf, "info") == 0)
+ e = tkgridinfo(t, w, val, buf, buf+Tkmaxitem);
+ else{
+ tkerr(t, buf);
+ e = TkBadcm;
+ }
+ } else{
+ p = malloc(sizeof(TkGridparam));
+ if(p == nil)
+ return TkNomem;
+ tko[0].ptr = p;
+ tko[0].optab = opts;
+ tko[1].ptr = nil;
+
+ p->span.x = 1;
+ p->span.y = 1;
+ p->pad.x = p->pad.y = p->ipad.x = p->ipad.y = -1;
+ p->sticky = -1;
+
+ names = nil;
+ e = tkparse(t, arg, tko, &names);
+ if(e != nil){
+ free(p);
+ return e;
+ }
+
+ e = tkgridconfigure(t, p, names);
+ free(p->row);
+ free(p->col);
+ free(p);
+ tkfreename(names);
+ }
+ free(buf);
+ return e;
+}
+
+/*
+ * expand widths of rows/columns according to weight.
+ * return amount of space still left over.
+ */
+static int
+expandwidths(int x0, int x1, int totwidth, TkGridbeam *cols, int expandzero)
+{
+ int share, x, slack, m, w, equal;
+
+ if(x0 >= x1)
+ return 0;
+
+ share = 0;
+ for(x = x0; x < x1; x++)
+ share += cols[x].weight;
+
+ slack = totwidth - beamsize(cols, x0, x1);
+ if(slack <= 0)
+ return 0;
+
+ if(share == 0 && expandzero){
+ share = x1 - x0;
+ equal = 1;
+ } else
+ equal = 0;
+
+ for(x = x0; x < x1 && share > 0 ; x++){
+ w = equal ? 1 : cols[x].weight;
+ m = slack * w / share;
+ cols[x].act += m;
+ slack -= m;
+ share -= w;
+ }
+ return slack;
+}
+
+static void
+gridequalise(TkGridbeam *beam, int blen)
+{
+ int i, max;
+
+ max = 0;
+ for(i = 0; i < blen; i++)
+ if(beam[i].equalise == BoolT && beam[i].act > max)
+ max = beam[i].act;
+
+ if(max > 0)
+ for(i = 0; i < blen; i++)
+ if(beam[i].equalise == BoolT)
+ beam[i].act = max;
+}
+
+/*
+ * take into account min/max beam sizes.
+ * max takes precedence
+ */
+static void
+beamminmax(TkGridbeam *beam, int n)
+{
+ TkGridbeam *e;
+ e = &beam[n];
+ for(; beam < e; beam++){
+ if(beam->act < beam->minsize)
+ beam->act = beam->minsize;
+ if(beam->act > beam->maxsize)
+ beam->act = beam->maxsize;
+ }
+}
+
+int
+tkgridder(Tk *master)
+{
+ TkGrid *grid;
+ TkGridcell **cells, *cell;
+ TkGridbeam *rows, *cols;
+ TkGeom pos;
+ Point org;
+ Tk *slave;
+ int dx, dy, x, y, w, bw2, fpadx, fpady;
+ Point req;
+
+ grid = master->grid;
+ dx = grid->dim.x;
+ dy = grid->dim.y;
+ cells = grid->cells;
+ rows = grid->rows;
+ cols = grid->cols;
+
+ for(x = 0; x < dx; x++)
+ cols[x].act = 0;
+
+ /* calculate column widths and row heights (ignoring multi-column cells) */
+ for(y = 0; y < dy; y++){
+ rows[y].act = 0;
+ for(x = 0; x < dx; x++){
+ cell = &cells[y][x];
+ if((slave = cell->tk) != nil){
+ bw2 = slave->borderwidth * 2;
+ w = slave->req.width + bw2 + slave->pad.x + slave->ipad.x;
+ if(cell->span.x == 1 && w > cols[x].act)
+ cols[x].act = w;
+ w = slave->req.height + bw2 + slave->pad.y + slave->ipad.y;
+ if(cell->span.y == 1 && w > rows[y].act)
+ rows[y].act = w;
+ }
+ }
+ }
+
+ beamminmax(rows, dy);
+ beamminmax(cols, dx);
+
+ /* now check that spanning cells fit in their rows/columns */
+ for(y = 0; y < dy; y++)
+ for(x = 0; x < dx; x++){
+ cell = &cells[y][x];
+ if((slave = cell->tk) != nil){
+ bw2 = slave->borderwidth * 2;
+ if(cell->span.x > 1){
+ w = slave->req.width + bw2 + slave->pad.x + slave->ipad.x;
+ expandwidths(x, x+cell->span.x, w, cols, 1);
+ }
+ if(cell->span.y > 1){
+ w = slave->req.height + bw2 + slave->pad.y + slave->ipad.y;
+ expandwidths(y, y+cell->span.y, w, rows, 1);
+ }
+ }
+ }
+
+ gridequalise(rows, dy);
+ gridequalise(cols, dx);
+
+ if(dx == 0)
+ req.x = 0;
+ else
+ req.x = beamsize(cols, 0, dx) + cols[0].pad + cols[dx-1].pad;
+
+ if(dy == 0)
+ req.y = 0;
+ else
+ req.y = beamsize(rows, 0, dy) + rows[0].pad + rows[dy-1].pad;
+
+ if(req.x != master->req.width || req.y != master->req.height)
+ if((master->flag & Tknoprop) == 0){
+ if(master->geom != nil){
+ master->geom(master, master->act.x, master->act.y,
+ req.x, req.y);
+ } else{
+ master->req.width = req.x;
+ master->req.height = req.y;
+ tkpackqit(master->master);
+ }
+ return 0;
+ }
+ org = ZP;
+ if(dx > 0 && master->act.width > req.x)
+ org.x = expandwidths(0, dx,
+ master->act.width - (cols[0].pad + cols[dx-1].pad),
+ cols, 0) / 2;
+ if(dy > 0 && master->act.height > req.y)
+ org.y = expandwidths(0, dy,
+ master->act.height - (rows[0].pad + rows[dy-1].pad),
+ rows, 0) / 2;
+
+ grid->origin = org;
+ pos.y = org.y;
+ fpady = 0;
+ for(y = 0; y < dy; y++){
+ pos.y += maximum(fpady, rows[y].pad);
+ fpady = rows[y].pad;
+
+ pos.x = org.x;
+ fpadx = 0;
+ for(x = 0; x < dx; x++){
+ cell = &cells[y][x];
+ pos.x += maximum(fpadx, cols[x].pad);
+ fpadx = cols[x].pad;
+ if((slave = cell->tk) != nil && cell->span.x > 0){
+ pos.width = beamsize(cols, x, x + cell->span.x);
+ pos.height = beamsize(rows, y, y + cell->span.y);
+ tksetslavereq(slave, pos);
+ }
+ pos.x += cols[x].act;
+ }
+ pos.y += rows[y].act;
+ }
+
+ master->dirty = tkrect(master, 1);
+ tkdirty(master);
+ return 1;
+}
--- /dev/null
+++ b/libtk/image.c
@@ -1,0 +1,380 @@
+#include "lib9.h"
+#include <kernel.h>
+#include "draw.h"
+#include "tk.h"
+
+#define O(t, e) ((long)(&((t*)0)->e))
+
+char* tkimgbmcreate(TkTop*, char*, int, char**);
+char* tkimgbmdel(TkImg*);
+void tkimgbmfree(TkImg*);
+
+static Rectangle huger = { -1000000, -1000000, 1000000, 1000000 };
+
+typedef struct TkImgtype TkImgtype;
+struct TkImgtype
+{
+ char* type;
+ char* (*create)(TkTop*, char*, int, char**);
+ char* (*delete)(TkImg*);
+ void (*destroy)(TkImg*);
+} tkimgopts[] =
+{
+ "bitmap", tkimgbmcreate, tkimgbmdel, tkimgbmfree,
+ nil,
+};
+
+typedef struct Imgargs Imgargs;
+struct Imgargs {
+ Image* fgimg;
+ Image* maskimg;
+};
+
+TkImg*
+tkname2img(TkTop *t, char *name)
+{
+ TkImg *tki;
+
+ for(tki = t->imgs; tki; tki = tki->link)
+ if((tki->name != nil) && strcmp(tki->name->name, name) == 0)
+ return tki;
+
+ return nil;
+}
+
+TkOption
+bitopt[] =
+{
+ "file", OPTbmap, O(Imgargs, fgimg), nil,
+ "maskfile", OPTbmap, O(Imgargs, maskimg), nil,
+ nil
+};
+
+void
+tksizeimage(Tk *tk, TkImg *tki)
+{
+ int dx, dy, repack;
+
+ dx = 0;
+ dy = 0;
+ if(tki->img != nil) {
+ dx = Dx(tki->img->r);
+ dy = Dy(tki->img->r);
+ }
+ repack = 0;
+ if(tki->ref > 1 && (tki->w != dx || tki->h != dy))
+ repack = 1;
+ tki->w = dx;
+ tki->h = dy;
+
+ if(repack) {
+ tkpackqit(tk);
+ tkrunpack(tk->env->top);
+ }
+}
+
+char*
+tkimgbmcreate(TkTop *t, char *arg, int type, char **ret)
+{
+ TkName *names;
+ TkImg *tki, *f;
+ TkOptab tko[2];
+ char buf[32];
+ static int id;
+ char *e = nil;
+ Imgargs iargs;
+ Rectangle r;
+ Display *d;
+ int chan;
+ int locked;
+
+ d = t->display;
+ locked = 0;
+
+ tki = malloc(sizeof(TkImg));
+ if(tki == nil)
+ return TkNomem;
+
+ tki->env = tkdefaultenv(t);
+ if(tki->env == nil)
+ goto err;
+ tki->type = type;
+ tki->ref = 1;
+ tki->top = t;
+
+ iargs.fgimg = nil;
+ iargs.maskimg = nil;
+
+ tko[0].ptr = &iargs;
+ tko[0].optab = bitopt;
+ tko[1].ptr = nil;
+
+ names = nil;
+ e = tkparse(t, arg, tko, &names);
+ if(e != nil)
+ goto err;
+
+ if (iargs.fgimg == nil && iargs.maskimg != nil) {
+ locked = lockdisplay(d);
+ r = Rect(0, 0, Dx(iargs.maskimg->r), Dy(iargs.maskimg->r));
+ tki->img = allocimage(d, r, CHAN2(CAlpha, 8, CGrey, 8), 0, DTransparent);
+ if (tki->img != nil)
+ draw(tki->img, r, nil, iargs.maskimg, iargs.maskimg->r.min);
+ freeimage(iargs.maskimg);
+
+ } else if (iargs.fgimg != nil && iargs.maskimg != nil) {
+ locked = lockdisplay(d);
+ r = Rect(0, 0, Dx(iargs.fgimg->r), Dy(iargs.fgimg->r));
+ if (tkchanhastype(iargs.fgimg->chan, CGrey))
+ chan = CHAN2(CAlpha, 8, CGrey, 8);
+ else
+ chan = RGBA32;
+ tki->img = allocimage(d, r, chan, 0, DTransparent);
+ if (tki->img != nil)
+ draw(tki->img, r, iargs.fgimg, iargs.maskimg, iargs.fgimg->r.min);
+ freeimage(iargs.fgimg);
+ freeimage(iargs.maskimg);
+ } else {
+ tki->img = iargs.fgimg;
+ }
+ if (locked)
+ unlockdisplay(d);
+
+ if(names == nil) {
+ sprint(buf, "image%d", id++);
+ tki->name = tkmkname(buf);
+ if(tki->name == nil)
+ goto err;
+ }
+ else {
+ /* XXX should mark as dirty any widgets using the named
+ * image - some notification scheme needs putting in place
+ */
+ tki->name = names;
+ tkfreename(names->link);
+ names->link = nil;
+ }
+
+ tksizeimage(t->root, tki);
+
+ if (tki->name != nil) {
+ f = tkname2img(t, tki->name->name);
+ if(f != nil)
+ tkimgopts[f->type].delete(f);
+ }
+
+ tki->link = t->imgs;
+ t->imgs = tki;
+
+ if (tki->name != nil) {
+ e = tkvalue(ret, "%s", tki->name->name);
+ if(e == nil)
+ return nil;
+ }
+err:
+ tkputenv(tki->env);
+ if(tki->img != nil) {
+ locked = lockdisplay(d);
+ freeimage(tki->img);
+ if (locked)
+ unlockdisplay(d);
+ }
+ tkfreename(tki->name);
+ free(tki);
+ return e != nil ? e : TkNomem;
+}
+
+char*
+tkimgbmdel(TkImg *tki)
+{
+ TkImg **l, *f;
+
+ l = &tki->top->imgs;
+ for(f = *l; f; f = f->link) {
+ if(f == tki) {
+ *l = tki->link;
+ tkimgput(tki);
+ return nil;
+ }
+ l = &f->link;
+ }
+ return TkBadvl;
+}
+
+void
+tkimgbmfree(TkImg *tki)
+{
+ int locked;
+ Display *d;
+
+ d = tki->top->display;
+ locked = lockdisplay(d);
+ freeimage(tki->img);
+ if(locked)
+ unlockdisplay(d);
+
+ free(tki->cursor);
+ tkfreename(tki->name);
+ tkputenv(tki->env);
+
+ free(tki);
+}
+
+char*
+tkimage(TkTop *t, char *arg, char **ret)
+{
+ int i;
+ TkImg *tkim;
+ char *fmt, *e, *buf, *cmd;
+
+ buf = mallocz(Tkmaxitem, 0);
+ if(buf == nil)
+ return TkNomem;
+ cmd = mallocz(Tkminitem, 0);
+ if(cmd == nil) {
+ free(buf);
+ return TkNomem;
+ }
+
+ arg = tkword(t, arg, cmd, cmd+Tkminitem, nil);
+ if(strcmp(cmd, "create") == 0) {
+ arg = tkword(t, arg, buf, buf+Tkmaxitem, nil);
+ for(i = 0; tkimgopts[i].type != nil; i++)
+ if(strcmp(buf, tkimgopts[i].type) == 0) {
+ e = tkimgopts[i].create(t, arg, i, ret);
+ goto ret;
+ }
+ e = TkBadvl;
+ goto ret;
+ }
+ if(strcmp(cmd, "names") == 0) {
+ fmt = "%s";
+ for(tkim = t->imgs; tkim; tkim = tkim->link) {
+ if (tkim->name != nil) {
+ e = tkvalue(ret, fmt, tkim->name->name);
+ if(e != nil)
+ goto ret;
+ }
+ fmt = " %s";
+ }
+ e = nil;
+ goto ret;
+ }
+
+ arg = tkword(t, arg, buf, buf+Tkmaxitem, nil);
+ tkim = tkname2img(t, buf);
+ if(tkim == nil) {
+ e = TkBadvl;
+ goto ret;
+ }
+
+ if(strcmp(cmd, "height") == 0) {
+ e = tkvalue(ret, "%d", tkim->h);
+ goto ret;
+ }
+ if(strcmp(cmd, "width") == 0) {
+ e = tkvalue(ret, "%d", tkim->w);
+ goto ret;
+ }
+ if(strcmp(cmd, "type") == 0) {
+ e = tkvalue(ret, "%s", tkimgopts[tkim->type].type);
+ goto ret;
+ }
+ if(strcmp(cmd, "delete") == 0) {
+ for (;;) {
+ e = tkimgopts[tkim->type].delete(tkim);
+ if (e != nil)
+ break;
+ arg = tkword(t, arg, buf, buf+Tkmaxitem, nil);
+ if (buf[0] == '\0')
+ break;
+ tkim = tkname2img(t, buf);
+ if (tkim == nil) {
+ e = TkBadvl;
+ break;
+ }
+ }
+ goto ret;
+ }
+
+ e = TkBadcm;
+ret:
+ free(cmd);
+ free(buf);
+ return e;
+}
+
+void
+tkimgput(TkImg *tki)
+{
+ if(tki == nil)
+ return;
+
+ if(--tki->ref > 0)
+ return;
+
+ tkimgopts[tki->type].destroy(tki);
+}
+
+TkImg*
+tkauximage(TkTop *t, char* s, TkMemimage *m, int repl)
+{
+ TkName *name;
+ TkCtxt *c;
+ TkImg *tki;
+ Display *d;
+ Image *i;
+ int locked, nbytes;
+
+ tki = tkname2img(t, s);
+ if (tki != nil) {
+ tki->ref++;
+ return tki;
+ }
+
+ name = tkmkname(s);
+ if (name == nil)
+ return nil;
+ tki = mallocz(sizeof(*tki), 1);
+ if (tki == nil)
+ goto err;
+ tki->env = tkdefaultenv(t);
+ if(tki->env == nil)
+ goto err;
+
+ c = t->ctxt;
+ d = c->display;
+
+ nbytes = bytesperline(m->r, chantodepth(m->chans))*Dy(m->r);
+ locked = lockdisplay(d);
+ i = allocimage(d, m->r, m->chans, repl, DTransparent);
+ if (i != nil) {
+ if (loadimage(i, m->r, m->data, nbytes) != nbytes) {
+ freeimage(i);
+ i = nil;
+ }
+ if (repl)
+ replclipr(i, 1, huger); /* TO DO: doesn't allocimage do this? */
+ }
+ if (locked)
+ unlockdisplay(d);
+ if (i == nil)
+ goto err;
+ tki->top = t;
+ tki->ref = 2; /* t->imgs ref and the ref we are returning */
+ tki->type = 0; /* bitmap */
+ tki->w = Dx(m->r);
+ tki->h = Dy(m->r);
+ tki->img = i;
+ tki->name = name;
+ tki->link = t->imgs;
+ t->imgs = tki;
+ return tki;
+err:
+ if (tki != nil) {
+ tkputenv(tki->env);
+ free(tki);
+ }
+ tkfreename(name);
+ return nil;
+}
--- /dev/null
+++ b/libtk/label.c
@@ -1,0 +1,366 @@
+#include <lib9.h>
+#include <kernel.h>
+#include "draw.h"
+#include "tk.h"
+#include "label.h"
+
+#define O(t, e) ((long)(&((t*)0)->e))
+
+TkOption tklabelopts[] =
+{
+ "text", OPTtext, O(TkLabel, text), nil,
+ "label", OPTtext, O(TkLabel, text), nil,
+ "underline", OPTdist, O(TkLabel, ul), nil,
+ "justify", OPTflag, O(TkLabel, justify), tkjustify,
+ "anchor", OPTflag, O(TkLabel, anchor), tkanchor,
+ "bitmap", OPTbmap, O(TkLabel, bitmap), nil,
+ "image", OPTimag, O(TkLabel, img), nil,
+ nil
+};
+
+char*
+tklabel(TkTop *t, char *arg, char **ret)
+{
+ Tk *tk;
+ char *e;
+ TkLabel *tkl;
+ TkName *names;
+ TkOptab tko[3];
+
+ tk = tknewobj(t, TKlabel, sizeof(Tk)+sizeof(TkLabel));
+ if(tk == nil)
+ return TkNomem;
+
+ tkl = TKobj(TkLabel, tk);
+ tkl->ul = -1;
+ tkl->justify = Tkleft;
+
+ tko[0].ptr = tk;
+ tko[0].optab = tkgeneric;
+ tko[1].ptr = tkl;
+ tko[1].optab = tklabelopts;
+ tko[2].ptr = nil;
+
+ names = nil;
+ e = tkparse(t, arg, tko, &names);
+ if(e != nil) {
+ tkfreeobj(tk);
+ return e;
+ }
+
+ tksizelabel(tk);
+ tksettransparent(tk, tkhasalpha(tk->env, TkCbackgnd));
+
+ e = tkaddchild(t, tk, &names);
+ tkfreename(names);
+ if(e != nil) {
+ tkfreeobj(tk);
+ return e;
+ }
+ tk->name->link = nil;
+
+ return tkvalue(ret, "%s", tk->name->name);
+}
+
+static char*
+tklabelcget(Tk *tk, char *arg, char **val)
+{
+ TkOptab tko[3];
+ TkLabel *tkl = TKobj(TkLabel, tk);
+
+ tko[0].ptr = tk;
+ tko[0].optab = tkgeneric;
+ tko[1].ptr = tkl;
+ tko[1].optab = tklabelopts;
+ tko[2].ptr = nil;
+
+ return tkgencget(tko, arg, val, tk->env->top);
+}
+
+static char*
+tklabelconf(Tk *tk, char *arg, char **val)
+{
+ char *e;
+ TkGeom g;
+ int bd;
+ TkOptab tko[3];
+ TkLabel *tkl = TKobj(TkLabel, tk);
+
+ tko[0].ptr = tk;
+ tko[0].optab = tkgeneric;
+ tko[1].ptr = tkl;
+ tko[1].optab = tklabelopts;
+ tko[2].ptr = nil;
+
+ if(*arg == '\0')
+ return tkconflist(tko, val);
+
+ g = tk->req;
+ bd = tk->borderwidth;
+ e = tkparse(tk->env->top, arg, tko, nil);
+ tksizelabel(tk);
+ tksettransparent(tk, tkhasalpha(tk->env, TkCbackgnd));
+ tkgeomchg(tk, &g, bd);
+
+ tk->dirty = tkrect(tk, 1);
+ return e;
+}
+
+void
+tksizelabel(Tk *tk)
+{
+ Point p;
+ int w, h;
+ TkLabel *tkl;
+
+ tkl = TKobj(TkLabel, tk);
+ if(tkl->anchor == 0)
+ tkl->anchor = Tkcenter;
+
+ w = 0;
+ h = 0;
+ tkl->textheight = 0;
+ if(tkl->img != nil) {
+ w = tkl->img->w + 2*Bitpadx;
+ h = tkl->img->h + 2*Bitpady;
+ } else if(tkl->bitmap != nil) {
+ w = Dx(tkl->bitmap->r) + 2*Bitpadx;
+ h = Dy(tkl->bitmap->r) + 2*Bitpady;
+ } else if(tkl->text != nil) {
+ p = tkstringsize(tk, tkl->text);
+ w = p.x + 2*Textpadx;
+ h = p.y + 2*Textpady;
+ if(tkl->ul != -1 && tkl->ul > strlen(tkl->text))
+ tkl->ul = strlen(tkl->text); /* underline all */
+ tkl->textheight = p.y;
+ }
+
+ if(tk->type == TKcascade) {
+ w += CheckButton + 2*CheckButtonBW;
+ if(h < CheckButton)
+ h = CheckButton;
+ }
+ w += 2*tk->highlightwidth;
+ h += 2*tk->highlightwidth;
+ tkl->w = w;
+ tkl->h = h;
+ if((tk->flag & Tksetwidth) == 0)
+ tk->req.width = w;
+ if((tk->flag & Tksetheight) == 0)
+ tk->req.height = h;
+}
+
+int
+tklabelmargin(Tk *tk)
+{
+ TkLabel *tkl;
+ Image *img;
+
+ switch(tk->type){
+ case TKseparator:
+ return 0;
+
+ case TKlabel:
+ case TKcascade:
+ tkl = TKobj(TkLabel, tk);
+ img = nil;
+ if (tkl->img != nil)
+ img = tkl->img->img;
+ else if (tkl->bitmap != nil)
+ img = tkl->bitmap;
+ if (img != nil)
+ return Bitpadx;
+ return Textpadx;
+
+ default:
+ fprint(2, "label margin: type %d\n", tk->type);
+ return 0;
+ }
+}
+
+void
+tkfreelabel(Tk *tk)
+{
+ Image *i;
+ int locked;
+ Display *d;
+ TkLabel *tkl;
+
+ tkl = TKobj(TkLabel, tk);
+
+ if(tkl->text != nil)
+ free(tkl->text);
+ if(tkl->command != nil)
+ free(tkl->command);
+ if(tkl->value != nil)
+ free(tkl->value);
+ if(tkl->variable != nil) {
+ tkfreevar(tk->env->top, tkl->variable, tk->flag & Tkswept);
+ free(tkl->variable);
+ }
+ if(tkl->img != nil)
+ tkimgput(tkl->img);
+ i = tkl->bitmap;
+ if(i != nil) {
+ d = i->display;
+ locked = lockdisplay(d);
+ freeimage(i);
+ if(locked)
+ unlockdisplay(d);
+ }
+ if(tkl->menu != nil)
+ free(tkl->menu);
+}
+
+static void
+tktriangle(Point u, Image *i, TkEnv *e)
+{
+ Point p[3];
+
+ u.y++;
+ p[0].x = u.x + CheckButton;
+ p[0].y = u.y + CheckButton/2;
+ p[1].x = u.x;
+ p[1].y = u.y + CheckButton;
+ p[2].x = u.x;
+ p[2].y = u.y;
+ fillpoly(i, p, 3, ~0, tkgc(e, TkCforegnd), p[0]);
+}
+
+/*
+ * draw TKlabel, TKseparator, and TKcascade (cascade should really be a button)
+ */
+char*
+tkdrawlabel(Tk *tk, Point orig)
+{
+ TkEnv *e;
+ TkLabel *tkl;
+ Rectangle r, s, mainr, focusr;
+ int dx, dy, h;
+ Point p, u, v;
+ Image *i, *dst, *ct, *img;
+ int relief, bgnd, fgnd;
+
+ e = tk->env;
+
+ dst = tkimageof(tk);
+ if(dst == nil)
+ return nil;
+
+ v.x = tk->act.width + 2*tk->borderwidth;
+ v.y = tk->act.height + 2*tk->borderwidth;
+
+ r.min = ZP;
+ r.max = v;
+ focusr = insetrect(r, tk->borderwidth);
+ mainr = insetrect(focusr, tk->highlightwidth);
+ relief = tk->relief;
+
+ tkl = TKobj(TkLabel, tk);
+
+ fgnd = TkCforegnd;
+ bgnd = TkCbackgnd;
+ if (tk->flag & Tkdisabled)
+ fgnd = TkCdisablefgnd;
+ else if (tk->flag & Tkactive) {
+ fgnd = TkCactivefgnd;
+ bgnd = TkCactivebgnd;
+ }
+
+ i = tkitmp(e, r.max, bgnd);
+ if(i == nil)
+ return nil;
+
+ if(tk->flag & Tkactive)
+ draw(i, r, tkgc(e, bgnd), nil, ZP);
+
+ p = mainr.min;
+ h = tkl->h - 2 * tk->highlightwidth;
+
+ dx = tk->act.width - tkl->w - tk->ipad.x;
+ dy = tk->act.height - tkl->h - tk->ipad.y;
+ if((tkl->anchor & (Tknorth|Tksouth)) == 0)
+ p.y += dy/2;
+ else if(tkl->anchor & Tksouth)
+ p.y += dy;
+
+ if((tkl->anchor & (Tkeast|Tkwest)) == 0)
+ p.x += dx/2;
+ else if(tkl->anchor & Tkeast)
+ p.x += dx;
+
+ if(tk->type == TKcascade) {
+ u.x = mainr.max.x - CheckButton - CheckButtonBW; /* TO DO: CheckButton etc is really the triangle/arrow */
+ u.y = p.y + ButtonBorder + (h-CheckSpace)/2;
+ tktriangle(u, i, e);
+ }
+
+ p.x += tk->ipad.x/2;
+ p.y += tk->ipad.y/2;
+ u = ZP;
+
+ img = nil;
+ if(tkl->img != nil && tkl->img->img != nil)
+ img = tkl->img->img;
+ else if (tkl->bitmap != nil)
+ img = tkl->bitmap;
+ if(img != nil) {
+ s.min.x = p.x + Bitpadx;
+ s.min.y = p.y + Bitpady;
+ s.max.x = s.min.x + Dx(img->r);
+ s.max.y = s.min.y + Dy(img->r);
+ s = rectaddpt(s, u);
+ if(tkchanhastype(img->chan, CGrey))
+ draw(i, s, tkgc(e, fgnd), img, ZP);
+ else
+ draw(i, s, img, nil, ZP);
+ } else if(tkl->text != nil) {
+ u.x += Textpadx;
+ u.y += Textpady;
+ ct = tkgc(e, fgnd);
+
+ p.y += (h - tkl->textheight) / 2;
+ tkdrawstring(tk, i, addpt(u, p), tkl->text, tkl->ul, ct, tkl->justify);
+ }
+
+ if(tkhaskeyfocus(tk))
+ tkbox(i, focusr, tk->highlightwidth, tkgc(e, TkChighlightfgnd));
+ tkdrawrelief(i, tk, ZP, bgnd, relief);
+
+ p.x = tk->act.x + orig.x;
+ p.y = tk->act.y + orig.y;
+ r = rectaddpt(r, p);
+ draw(dst, r, i, nil, ZP);
+
+ return nil;
+}
+
+void
+tklabelgetimgs(Tk *tk, Image **image, Image **mask)
+{
+ TkLabel *tkl;
+
+ tkl = TKobj(TkLabel, tk);
+ *mask = nil;
+ if (tkl->img != nil)
+ *image = tkl->img->img;
+ else
+ *image = tkl->bitmap;
+}
+
+static
+TkCmdtab tklabelcmd[] =
+{
+ "cget", tklabelcget,
+ "configure", tklabelconf,
+ nil
+};
+
+TkMethod labelmethod = {
+ "label",
+ tklabelcmd,
+ tkfreelabel,
+ tkdrawlabel,
+ nil,
+ tklabelgetimgs
+};
--- /dev/null
+++ b/libtk/label.h
@@ -1,0 +1,74 @@
+typedef struct TkLabel TkLabel;
+
+/*
+ * widgets that use the label code:
+ * label
+ * checkbutton
+ * button
+ * menubutton
+ * separator
+ * cascade
+ * radiobutton
+ */
+
+struct TkLabel
+{
+ char* text; /* Label value */
+ Image* bitmap; /* Bitmap to display */
+ TkImg* img;
+ int justify;
+ int anchor;
+// int flags; /* justify/anchor */
+ int w;
+ int h;
+ int textheight;
+
+ /* button fields */
+ char* command; /* Command to execute at invoke */
+ char* value; /* Variable value in radio button */
+ char* offvalue; /* Off value for check button */
+ char* variable; /* Variable name in radio button */
+ int ul;
+ int check; /* check/radiobutton/choicebutton state */
+ int indicator; /* -indicatoron setting */
+ char* menu;
+
+ char** values;
+ int nvalues;
+ /* current value of choicebutton is represented by check */
+};
+
+/* Layout constants */
+enum {
+ Textpadx = 3,
+ Textpady = 0,
+ Bitpadx = 0, /* Bitmap padding in labels */
+ Bitpady = 0,
+ CheckButton = 10,
+ CheckButtonBW = 1,
+ ButtonBorder = 4,
+ CheckSpace = CheckButton + 2*CheckButtonBW + 2*ButtonBorder,
+};
+
+extern TkOption tkbutopts[];
+extern TkOption tkradopts[];
+extern TkOption tkcbopts[];
+
+/* label.c */
+extern void tksizelabel(Tk*);
+extern char* tkdrawlabel(Tk*, Point);
+extern void tkfreelabel(Tk*);
+extern void tklabelgetimgs(Tk*, Image**, Image**);
+extern char* tksetvar(TkTop*, char*, char*);
+
+/* buton.c */
+extern Tk* tkmkbutton(TkTop*, int);
+extern void tksizebutton(Tk*);
+extern char* tkdrawbutton(Tk*, Point);
+extern char* tkbuttoninvoke(Tk*, char*, char**);
+extern char* tkradioinvoke(Tk*, char*, char**);
+extern void tkfreebutton(Tk*);
+
+/* support for menus */
+extern int tklabelmargin(Tk*);
+extern int tkbuttonmargin(Tk*);
--- /dev/null
+++ b/libtk/listb.c
@@ -1,0 +1,1065 @@
+#include "lib9.h"
+#include "draw.h"
+#include "keyboard.h"
+#include "tk.h"
+#include "listb.h"
+
+#define O(t, e) ((long)(&((t*)0)->e))
+
+/* Layout constants */
+enum {
+ Listpadx = 2, /* X padding of text in listboxes */
+};
+
+typedef struct TkLentry TkLentry;
+typedef struct TkListbox TkListbox;
+
+struct TkLentry
+{
+ TkLentry* link;
+ int flag;
+ int width;
+ char text[TKSTRUCTALIGN];
+};
+
+struct TkListbox
+{
+ TkLentry* head;
+ TkLentry* anchor;
+ TkLentry* active;
+ int yelem; /* Y element at top of box */
+ int xdelta; /* h-scroll position */
+ int nitem;
+ int nwidth;
+ int selmode;
+ int sborderwidth;
+ char* xscroll;
+ char* yscroll;
+};
+
+TkStab tkselmode[] =
+{
+ "single", TKsingle,
+ "browse", TKbrowse,
+ "multiple", TKmultiple,
+ "extended", TKextended,
+ nil
+};
+
+static
+TkOption opts[] =
+{
+ "xscrollcommand", OPTtext, O(TkListbox, xscroll), nil,
+ "yscrollcommand", OPTtext, O(TkListbox, yscroll), nil,
+ "selectmode", OPTstab, O(TkListbox, selmode), tkselmode,
+ "selectborderwidth", OPTnndist, O(TkListbox, sborderwidth), nil,
+ nil
+};
+
+static
+TkEbind b[] =
+{
+ {TkButton1P, "%W tkListbButton1P %y"},
+ {TkButton1R, "%W tkListbButton1R"},
+ {TkButton1P|TkMotion, "%W tkListbButton1MP %y"},
+ {TkMotion, ""},
+ {TkKey, "%W tkListbKey 0x%K"},
+};
+
+
+static int
+lineheight(Tk *tk)
+{
+ TkListbox *l = TKobj(TkListbox, tk);
+ return tk->env->font->height+2*(l->sborderwidth+tk->highlightwidth);
+}
+
+char*
+tklistbox(TkTop *t, char *arg, char **ret)
+{
+ Tk *tk;
+ char *e;
+ TkName *names;
+ TkListbox *tkl;
+ TkOptab tko[3];
+
+ tk = tknewobj(t, TKlistbox, sizeof(Tk)+sizeof(TkListbox));
+ if(tk == nil)
+ return TkNomem;
+
+ tkl = TKobj(TkListbox, tk);
+ tkl->sborderwidth = 1;
+ tk->relief = TKsunken;
+ tk->borderwidth = 1;
+ tk->highlightwidth = 1;
+ tk->flag |= Tktakefocus;
+ tk->req.width = 170;
+ tk->req.height = lineheight(tk)*10;
+
+ tko[0].ptr = tk;
+ tko[0].optab = tkgeneric;
+ tko[1].ptr = tkl;
+ tko[1].optab = opts;
+ tko[2].ptr = nil;
+
+ names = nil;
+ e = tkparse(t, arg, tko, &names);
+ if(e != nil) {
+ tkfreeobj(tk);
+ return e;
+ }
+ tksettransparent(tk, tkhasalpha(tk->env, TkCbackgnd));
+
+ e = tkbindings(t, tk, b, nelem(b));
+ if(e != nil) {
+ tkfreeobj(tk);
+ return e;
+ }
+
+ e = tkaddchild(t, tk, &names);
+ tkfreename(names);
+ if(e != nil) {
+ tkfreeobj(tk);
+ return e;
+ }
+ tk->name->link = nil;
+
+ return tkvalue(ret, "%s", tk->name->name);
+}
+
+char*
+tklistbcget(Tk *tk, char *arg, char **val)
+{
+ TkOptab tko[3];
+ TkListbox *tkl = TKobj(TkListbox, tk);
+
+ tko[0].ptr = tk;
+ tko[0].optab = tkgeneric;
+ tko[1].ptr = tkl;
+ tko[1].optab = opts;
+ tko[2].ptr = nil;
+
+ return tkgencget(tko, arg, val, tk->env->top);
+}
+
+void
+tkfreelistb(Tk *tk)
+{
+ TkLentry *e, *next;
+ TkListbox *l = TKobj(TkListbox, tk);
+
+ for(e = l->head; e; e = next) {
+ next = e->link;
+ free(e);
+ }
+ if(l->xscroll != nil)
+ free(l->xscroll);
+ if(l->yscroll != nil)
+ free(l->yscroll);
+}
+
+char*
+tkdrawlistb(Tk *tk, Point orig)
+{
+ Point p;
+ TkEnv *env;
+ TkLentry *e;
+ int lh, w, n, ly;
+ Rectangle r, a;
+ Image *i, *fg;
+ TkListbox *l = TKobj(TkListbox, tk);
+
+ env = tk->env;
+
+ r.min = ZP;
+ r.max.x = tk->act.width + 2*tk->borderwidth;
+ r.max.y = tk->act.height + 2*tk->borderwidth;
+ i = tkitmp(env, r.max, TkCbackgnd);
+ if(i == nil)
+ return nil;
+
+ w = tk->act.width;
+ if (w < l->nwidth)
+ w = l->nwidth;
+ lh = lineheight(tk);
+ ly = tk->borderwidth;
+ p.x = tk->borderwidth+l->sborderwidth+tk->highlightwidth+Listpadx-l->xdelta;
+ p.y = tk->borderwidth+l->sborderwidth+tk->highlightwidth;
+ n = 0;
+ for(e = l->head; e && ly < r.max.y; e = e->link) {
+ if(n++ < l->yelem)
+ continue;
+
+ a.min.x = tk->borderwidth;
+ a.min.y = ly;
+ a.max.x = a.min.x + tk->act.width;
+ a.max.y = a.min.y + lh;
+ if(e->flag & Tkactivated) {
+ draw(i, a, tkgc(env, TkCselectbgnd), nil, ZP);
+ }
+
+ if(e->flag & Tkactivated)
+ fg = tkgc(env, TkCselectfgnd);
+ else
+ fg = tkgc(env, TkCforegnd);
+ string(i, p, fg, p, env->font, e->text);
+ if((e->flag & Tkactive) && tkhaskeyfocus(tk)) {
+ a.min.x = tk->borderwidth-l->xdelta;
+ a.max.x = a.min.x+w;
+ a = insetrect(a, l->sborderwidth);
+ tkbox(i, a, tk->highlightwidth, fg);
+ }
+ ly += lh;
+ p.y += lh;
+ }
+
+ tkdrawrelief(i, tk, ZP, TkCbackgnd, tk->relief);
+
+ p.x = tk->act.x + orig.x;
+ p.y = tk->act.y + orig.y;
+ r = rectaddpt(r, p);
+ draw(tkimageof(tk), r, i, nil, ZP);
+
+ return nil;
+}
+
+int
+tklindex(Tk *tk, char *buf)
+{
+ int index;
+ TkListbox *l;
+ TkLentry *e, *s;
+
+ l = TKobj(TkListbox, tk);
+
+ if(*buf == '@') {
+ while(*buf && *buf != ',')
+ buf++;
+ index = l->yelem + atoi(buf+1)/lineheight(tk);
+ if (index < 0)
+ return 0;
+ if (index > l->nitem)
+ return l->nitem;
+ return index;
+ }
+ if(*buf >= '0' && *buf <= '9')
+ return atoi(buf);
+
+ if(strcmp(buf, "end") == 0) {
+ if(l->nitem == 0)
+ return 0;
+ return l->nitem-1;
+ }
+
+ index = 0;
+ if(strcmp(buf, "active") == 0)
+ s = l->active;
+ else
+ if(strcmp(buf, "anchor") == 0)
+ s = l->anchor;
+ else
+ return -1;
+
+ for(e = l->head; e; e = e->link) {
+ if(e == s)
+ return index;
+ index++;
+ }
+ return -1;
+}
+
+void
+tklistsv(Tk *tk)
+{
+ TkListbox *l;
+ int nl, lh, top, bot;
+ char val[Tkminitem], cmd[Tkmaxitem], *v, *e;
+
+ l = TKobj(TkListbox, tk);
+ if(l->yscroll == nil)
+ return;
+
+ top = 0;
+ bot = TKI2F(1);
+
+ if(l->nitem != 0) {
+ lh = lineheight(tk);
+ nl = tk->act.height/lh; /* Lines in the box */
+ top = TKI2F(l->yelem)/l->nitem;
+ bot = TKI2F(l->yelem+nl)/l->nitem;
+ }
+
+ v = tkfprint(val, top);
+ *v++ = ' ';
+ tkfprint(v, bot);
+ snprint(cmd, sizeof(cmd), "%s %s", l->yscroll, val);
+ e = tkexec(tk->env->top, cmd, nil);
+ if ((e != nil) && (tk->name != nil))
+ print("tk: yscrollcommand \"%s\": %s\n", tk->name->name, e);
+}
+
+void
+tklistsh(Tk *tk)
+{
+ int nl, top, bot;
+ char val[Tkminitem], cmd[Tkmaxitem], *v, *e;
+ TkListbox *l = TKobj(TkListbox, tk);
+
+ if(l->xscroll == nil)
+ return;
+
+ top = 0;
+ bot = TKI2F(1);
+
+ if(l->nwidth != 0) {
+ nl = tk->act.width;
+ top = TKI2F(l->xdelta)/l->nwidth;
+ bot = TKI2F(l->xdelta+nl)/l->nwidth;
+ }
+
+ v = tkfprint(val, top);
+ *v++ = ' ';
+ tkfprint(v, bot);
+ snprint(cmd, sizeof(cmd), "%s %s", l->xscroll, val);
+ e = tkexec(tk->env->top, cmd, nil);
+ if ((e != nil) && (tk->name != nil))
+ print("tk: xscrollcommand \"%s\": %s\n", tk->name->name, e);
+}
+
+void
+tklistbgeom(Tk *tk)
+{
+ tklistsv(tk);
+ tklistsh(tk);
+}
+
+static void
+listbresize(Tk *tk)
+{
+ TkLentry *e;
+ TkListbox *l = TKobj(TkListbox, tk);
+
+ l->nwidth = 0;
+ for (e = l->head; e != nil; e = e->link) {
+ e->width = stringwidth(tk->env->font, e->text)+2*(Listpadx+l->sborderwidth+tk->highlightwidth);
+ if(e->width > l->nwidth)
+ l->nwidth = e->width;
+ }
+ tklistbgeom(tk);
+}
+
+
+/* Widget Commands (+ means implemented)
+ +activate
+ bbox
+ +cget
+ +configure
+ +curselection
+ +delete
+ +get
+ +index
+ +insert
+ +nearest
+ +see
+ +selection
+ +size
+ +xview
+ +yview
+*/
+
+char*
+tklistbconf(Tk *tk, char *arg, char **val)
+{
+ char *e;
+ TkGeom g;
+ int bd, sbw, hlw;
+ TkOptab tko[3];
+ Font *f;
+ TkListbox *tkl = TKobj(TkListbox, tk);
+
+ sbw = tkl->sborderwidth;
+ hlw = tk->highlightwidth;
+ f = tk->env->font;
+ tko[0].ptr = tk;
+ tko[0].optab = tkgeneric;
+ tko[1].ptr = tkl;
+ tko[1].optab = opts;
+ tko[2].ptr = nil;
+
+ if(*arg == '\0')
+ return tkconflist(tko, val);
+
+ g = tk->req;
+ bd = tk->borderwidth;
+ e = tkparse(tk->env->top, arg, tko, nil);
+ tksettransparent(tk, tkhasalpha(tk->env, TkCbackgnd));
+ tkgeomchg(tk, &g, bd);
+
+ if (sbw != tkl->sborderwidth || f != tk->env->font || hlw != tk->highlightwidth)
+ listbresize(tk);
+ tk->dirty = tkrect(tk, 1);
+ return e;
+}
+
+static void
+entryactivate(Tk *tk, int index)
+{
+ TkListbox *l = TKobj(TkListbox, tk);
+ TkLentry *e;
+ int flag = Tkactive;
+
+ if (l->selmode == TKbrowse)
+ flag |= Tkactivated;
+ for(e = l->head; e; e = e->link) {
+ if(index-- == 0) {
+ e->flag |= flag;
+ l->active = e;
+ } else
+ e->flag &= ~flag;
+ }
+ tk->dirty = tkrect(tk, 1);
+}
+
+char*
+tklistbactivate(Tk *tk, char *arg, char **val)
+{
+ int index;
+ char buf[Tkmaxitem];
+
+ USED(val);
+ tkword(tk->env->top, arg, buf, buf+sizeof(buf), nil);
+ index = tklindex(tk, buf);
+ if(index == -1)
+ return TkBadix;
+
+ entryactivate(tk, index);
+ return nil;
+}
+
+char*
+tklistbnearest(Tk *tk, char *arg, char **val)
+{
+ int lh, y, index;
+ TkListbox *l = TKobj(TkListbox, tk);
+
+ lh = lineheight(tk); /* Line height */
+ y = atoi(arg);
+ index = l->yelem + y/lh;
+ if(index > l->nitem)
+ index = l->nitem;
+ return tkvalue(val, "%d", index);
+}
+
+char*
+tklistbindex(Tk *tk, char *arg, char **val)
+{
+ int index;
+ char buf[Tkmaxitem];
+ tkword(tk->env->top, arg, buf, buf+sizeof(buf), nil);
+ index = tklindex(tk, buf);
+ if(index == -1)
+ return TkBadix;
+ return tkvalue(val, "%d", index);
+}
+
+char*
+tklistbsize(Tk *tk, char *arg, char **val)
+{
+ TkListbox *l = TKobj(TkListbox, tk);
+
+ USED(arg);
+ return tkvalue(val, "%d", l->nitem);
+}
+
+char*
+tklistbinsert(Tk *tk, char *arg, char **val)
+{
+ int n, index;
+ TkListbox *l;
+ TkLentry *e, **el;
+ char *tbuf, buf[Tkmaxitem];
+
+ USED(val);
+ l = TKobj(TkListbox, tk);
+
+ arg = tkword(tk->env->top, arg, buf, buf+sizeof(buf), nil);
+ if(strcmp(buf, "end") == 0) {
+ el = &l->head;
+ if(*el != nil) {
+ for(e = *el; e->link; e = e->link)
+ ;
+ el = &e->link;
+ }
+ }
+ else {
+ index = tklindex(tk, buf);
+ if(index == -1)
+ return TkBadix;
+ el = &l->head;
+ for(e = *el; e && index-- > 0; e = e->link)
+ el = &e->link;
+ }
+
+ n = strlen(arg);
+ if(n > Tkmaxitem) {
+ n = (n*3)/2;
+ tbuf = malloc(n);
+ if(tbuf == nil)
+ return TkNomem;
+ }
+ else {
+ tbuf = buf;
+ n = sizeof(buf);
+ }
+
+ while(*arg) {
+ arg = tkword(tk->env->top, arg, tbuf, &tbuf[n], nil);
+ e = malloc(sizeof(TkLentry)+strlen(tbuf)+1);
+ if(e == nil)
+ return TkNomem;
+
+ e->flag = 0;
+ strcpy(e->text, tbuf);
+ e->link = *el;
+ *el = e;
+ el = &e->link;
+ e->width = stringwidth(tk->env->font, e->text)+2*(Listpadx+l->sborderwidth+tk->highlightwidth);
+ if(e->width > l->nwidth)
+ l->nwidth = e->width;
+ l->nitem++;
+ }
+
+ if(tbuf != buf)
+ free(tbuf);
+
+ tklistbgeom(tk);
+ tk->dirty = tkrect(tk, 1);
+ return nil;
+}
+
+int
+tklistbrange(Tk *tk, char *arg, int *s, int *e)
+{
+ char buf[Tkmaxitem];
+
+ arg = tkword(tk->env->top, arg, buf, buf+sizeof(buf), nil);
+ *s = tklindex(tk, buf);
+ if(*s == -1)
+ return -1;
+ *e = *s;
+ if(*arg == '\0')
+ return 0;
+
+ tkword(tk->env->top, arg, buf, buf+sizeof(buf), nil);
+ *e = tklindex(tk, buf);
+ if(*e == -1)
+ return -1;
+ return 0;
+}
+
+char*
+tklistbselection(Tk *tk, char *arg, char **val)
+{
+ TkTop *t;
+ TkLentry *f;
+ TkListbox *l;
+ int s, e, indx;
+ char buf[Tkmaxitem];
+
+ l = TKobj(TkListbox, tk);
+
+ t = tk->env->top;
+ arg = tkword(t, arg, buf, buf+sizeof(buf), nil);
+ if(strcmp(buf, "includes") == 0) {
+ tkword(t, arg, buf, buf+sizeof(buf), nil);
+ indx = tklindex(tk, buf);
+ if(indx == -1)
+ return TkBadix;
+ for(f = l->head; f && indx > 0; f = f->link)
+ indx--;
+ s = 0;
+ if(f && (f->flag&Tkactivated))
+ s = 1;
+ return tkvalue(val, "%d", s);
+ }
+
+ if(strcmp(buf, "anchor") == 0) {
+ tkword(t, arg, buf, buf+sizeof(buf), nil);
+ indx = tklindex(tk, buf);
+ if(indx == -1)
+ return TkBadix;
+ for(f = l->head; f && indx > 0; f = f->link)
+ indx--;
+ if(f != nil)
+ l->anchor = f;
+ return nil;
+ }
+ indx = 0;
+ if(strcmp(buf, "clear") == 0) {
+ if(tklistbrange(tk, arg, &s, &e) != 0)
+ return TkBadix;
+ for(f = l->head; f; f = f->link) {
+ if(indx <= e && indx++ >= s)
+ f->flag &= ~Tkactivated;
+ }
+ tk->dirty = tkrect(tk, 1);
+ return nil;
+ }
+ if(strcmp(buf, "set") == 0) {
+ if(tklistbrange(tk, arg, &s, &e) != 0)
+ return TkBadix;
+ for(f = l->head; f; f = f->link) {
+ if(indx <= e && indx++ >= s)
+ f->flag |= Tkactivated;
+ }
+ tk->dirty = tkrect(tk, 1);
+ return nil;
+ }
+ return TkBadcm;
+}
+
+char*
+tklistbdelete(Tk *tk, char *arg, char **val)
+{
+ TkLentry *e, **el;
+ int start, end, indx, bh;
+ TkListbox *l = TKobj(TkListbox, tk);
+
+ USED(val);
+ if(tklistbrange(tk, arg, &start, &end) != 0)
+ return TkBadix;
+
+ indx = 0;
+ el = &l->head;
+ for(e = l->head; e && indx < start; e = e->link) {
+ indx++;
+ el = &e->link;
+ }
+ while(e != nil && indx <= end) {
+ *el = e->link;
+ if(e->width == l->nwidth)
+ l->nwidth = 0;
+ if (e == l->anchor)
+ l->anchor = nil;
+ if (e == l->active)
+ l->active = nil;
+ free(e);
+ e = *el;
+ indx++;
+ l->nitem--;
+ }
+ if(l->nwidth == 0) {
+ for(e = l->head; e; e = e->link)
+ if(e->width > l->nwidth)
+ l->nwidth = e->width;
+ }
+ bh = tk->act.height/lineheight(tk); /* Box height */
+ if(l->yelem + bh > l->nitem)
+ l->yelem = l->nitem - bh;
+ if(l->yelem < 0)
+ l->yelem = 0;
+
+ tklistbgeom(tk);
+ tk->dirty = tkrect(tk, 1);
+ return nil;
+}
+
+char*
+tklistbget(Tk *tk, char *arg, char **val)
+{
+ TkLentry *e;
+ char *r, *fmt;
+ int start, end, indx;
+ TkListbox *l = TKobj(TkListbox, tk);
+
+ if(tklistbrange(tk, arg, &start, &end) != 0)
+ return TkBadix;
+
+ indx = 0;
+ for(e = l->head; e && indx < start; e = e->link)
+ indx++;
+ fmt = "%s";
+ while(e != nil && indx <= end) {
+ r = tkvalue(val, fmt, e->text);
+ if(r != nil)
+ return r;
+ indx++;
+ fmt = " %s";
+ e = e->link;
+ }
+ return nil;
+}
+
+char*
+tklistbcursel(Tk *tk, char *arg, char **val)
+{
+ int indx;
+ TkLentry *e;
+ char *r, *fmt;
+ TkListbox *l = TKobj(TkListbox, tk);
+
+ USED(arg);
+ indx = 0;
+ fmt = "%d";
+ for(e = l->head; e; e = e->link) {
+ if(e->flag & Tkactivated) {
+ r = tkvalue(val, fmt, indx);
+ if(r != nil)
+ return r;
+ fmt = " %d";
+ }
+ indx++;
+ }
+ return nil;
+}
+
+static char*
+tklistbview(Tk *tk, char *arg, char **val, int nl, int *posn, int max)
+{
+ int top, bot, amount;
+ char buf[Tkmaxitem];
+ char *v, *e;
+
+ top = 0;
+ if(*arg == '\0') {
+ if ( max <= nl || max == 0 ) { /* Double test redundant at
+ * this time, but want to
+ * protect against future
+ * calls. -- DBK */
+ top = 0;
+ bot = TKI2F(1);
+ }
+ else {
+ top = TKI2F(*posn)/max;
+ bot = TKI2F(*posn+nl)/max;
+ }
+ v = tkfprint(buf, top);
+ *v++ = ' ';
+ tkfprint(v, bot);
+ return tkvalue(val, "%s", buf);
+ }
+
+ arg = tkword(tk->env->top, arg, buf, buf+sizeof(buf), nil);
+ if(strcmp(buf, "moveto") == 0) {
+ e = tkfracword(tk->env->top, &arg, &top, nil);
+ if (e != nil)
+ return e;
+ *posn = TKF2I((top+1)*max);
+ }
+ else
+ if(strcmp(buf, "scroll") == 0) {
+ arg = tkword(tk->env->top, arg, buf, buf+sizeof(buf), nil);
+ amount = atoi(buf);
+ tkword(tk->env->top, arg, buf, buf+sizeof(buf), nil);
+ if(buf[0] == 'p') /* Pages */
+ amount *= nl;
+ *posn += amount;
+ }
+ else {
+ top = tklindex(tk, buf);
+ if(top == -1)
+ return TkBadix;
+ *posn = top;
+ }
+
+ bot = max - nl;
+ if(*posn > bot)
+ *posn = bot;
+ if(*posn < 0)
+ *posn = 0;
+
+ tk->dirty = tkrect(tk, 1);
+ return nil;
+}
+
+static int
+entrysee(Tk *tk, int index)
+{
+ TkListbox *l = TKobj(TkListbox, tk);
+ int bh;
+
+ /* Box height in lines */
+ bh = tk->act.height/lineheight(tk);
+ if (bh > l->nitem)
+ bh = l->nitem;
+ if (index >= l->nitem)
+ index = l->nitem -1;
+ if (index < 0)
+ index = 0;
+
+ /* If the item is already visible, do nothing */
+ if (l->nitem == 0 || index >= l->yelem && index < l->yelem+bh)
+ return index;
+
+ if (index < l->yelem)
+ l->yelem = index;
+ else
+ l->yelem = index - (bh-1);
+
+ tklistsv(tk);
+ tk->dirty = tkrect(tk, 1);
+ return index;
+}
+
+char*
+tklistbsee(Tk *tk, char *arg, char **val)
+{
+ int index;
+ char buf[Tkmaxitem];
+
+ USED(val);
+ tkword(tk->env->top, arg, buf, buf+sizeof(buf), nil);
+ index = tklindex(tk, buf);
+ if(index == -1)
+ return TkBadix;
+
+ entrysee(tk, index);
+ return nil;
+}
+
+char*
+tklistbyview(Tk *tk, char *arg, char **val)
+{
+ int bh;
+ char *e;
+ TkListbox *l = TKobj(TkListbox, tk);
+
+ bh = tk->act.height/lineheight(tk); /* Box height */
+ e = tklistbview(tk, arg, val, bh, &l->yelem, l->nitem);
+ tklistsv(tk);
+ return e;
+}
+
+char*
+tklistbxview(Tk *tk, char *arg, char **val)
+{
+ char *e;
+ TkListbox *l = TKobj(TkListbox, tk);
+
+ e = tklistbview(tk, arg, val, tk->act.width, &l->xdelta, l->nwidth);
+ tklistsh(tk);
+ return e;
+}
+
+static TkLentry*
+entryset(TkListbox *l, int indx, int toggle)
+{
+ TkLentry *e, *anchor;
+
+ anchor = nil;
+ for(e = l->head; e; e = e->link) {
+ if (indx-- == 0) {
+ anchor = e;
+ if (toggle) {
+ e->flag ^= Tkactivated;
+ break;
+ } else
+ e->flag |= Tkactivated;
+ continue;
+ }
+ if (!toggle)
+ e->flag &= ~Tkactivated;
+ }
+ return anchor;
+}
+
+static void
+selectto(TkListbox *l, int indx)
+{
+ TkLentry *e;
+ int inrange;
+
+ if (l->anchor == nil)
+ return;
+ inrange = 0;
+ for(e = l->head; e; e = e->link) {
+ if(indx == 0)
+ inrange = !inrange;
+ if(e == l->anchor)
+ inrange = !inrange;
+ if(inrange || e == l->anchor || indx == 0)
+ e->flag |= Tkactivated;
+ else
+ e->flag &= ~Tkactivated;
+ indx--;
+ }
+}
+
+static char*
+dragto(Tk *tk, int y)
+{
+ int indx;
+ TkLentry *e;
+ TkListbox *l = TKobj(TkListbox, tk);
+
+ indx = y/lineheight(tk);
+ if (y < 0)
+ indx--; /* int division rounds towards 0 */
+ if (y < tk->act.height && indx >= l->nitem)
+ return nil;
+ indx = entrysee(tk, l->yelem+indx);
+ entryactivate(tk, indx);
+
+ if(l->selmode == TKsingle || l->selmode == TKmultiple)
+ return nil;
+
+ if(l->selmode == TKbrowse) {
+ for(e = l->head; e; e = e->link) {
+ if(indx-- == 0) {
+ if (e == l->anchor)
+ return nil;
+ l->anchor = e;
+ e->flag |= Tkactivated;
+ } else
+ e->flag &= ~Tkactivated;
+ }
+ return nil;
+ }
+ /* extended selection mode */
+ selectto(l, indx);
+ tk->dirty = tkrect(tk, 1);
+ return nil;
+}
+
+static void
+autoselect(Tk *tk, void *v, int cancelled)
+{
+ Point pt;
+ int y, eh, ne;
+
+ USED(v);
+ if (cancelled)
+ return;
+
+ pt = tkposn(tk);
+ pt.y += tk->borderwidth;
+ y = tk->env->top->ctxt->mstate.y;
+ y -= pt.y;
+ eh = lineheight(tk);
+ ne = tk->act.height/eh;
+ if (y >= 0 && y < eh*ne)
+ return;
+ dragto(tk, y);
+ tkdirty(tk);
+ tkupdate(tk->env->top);
+}
+
+static char*
+tklistbbutton1p(Tk *tk, char *arg, char **val)
+{
+ TkListbox *l = TKobj(TkListbox, tk);
+ int y, indx;
+
+ USED(val);
+
+ y = atoi(arg);
+ indx = y/lineheight(tk);
+ indx += l->yelem;
+ if (indx < l->nitem) {
+ l->anchor = entryset(l, indx, l->selmode == TKmultiple);
+ entryactivate(tk, indx);
+ entrysee(tk, indx);
+ }
+ tkrepeat(tk, autoselect, nil, TkRptpause, TkRptinterval);
+ return nil;
+}
+
+char *
+tklistbbutton1r(Tk *tk, char *arg, char **val)
+{
+ USED(arg);
+ USED(val);
+ tkcancelrepeat(tk);
+ return nil;
+}
+
+char*
+tklistbbutton1m(Tk *tk, char *arg, char **val)
+{
+ int y, eh, ne;
+ USED(val);
+
+ eh = lineheight(tk);
+ ne = tk->act.height/eh;
+ y = atoi(arg);
+ /* If outside the box, let autoselect handle it */
+ if (y < 0 || y >= ne * eh)
+ return nil;
+ return dragto(tk, y);
+}
+
+char*
+tklistbkey(Tk *tk, char *arg, char **val)
+{
+ TkListbox *l = TKobj(TkListbox, tk);
+ TkLentry *e;
+ int key, active;
+ USED(val);
+
+ if(tk->flag & Tkdisabled)
+ return nil;
+
+ key = strtol(arg, nil, 0);
+ active = 0;
+ for (e = l->head; e != nil; e = e->link) {
+ if (e->flag & Tkactive)
+ break;
+ active++;
+ }
+
+ if (key == '\n' || key == ' ') {
+ l->anchor = entryset(l, active, l->selmode == TKmultiple);
+ tk->dirty = tkrect(tk, 0);
+ return nil;
+ }
+ if (key == Up)
+ active--;
+ else if (key == Down)
+ active++;
+ else
+ return nil;
+
+ if (active < 0)
+ active = 0;
+ if (active >= l->nitem)
+ active = l->nitem-1;
+ entryactivate(tk, active);
+ if (l->selmode == TKextended) {
+ selectto(l, active);
+ tk->dirty = tkrect(tk, 0);
+ }
+ entrysee(tk, active);
+ return nil;
+}
+
+static
+TkCmdtab tklistcmd[] =
+{
+ "activate", tklistbactivate,
+ "cget", tklistbcget,
+ "configure", tklistbconf,
+ "curselection", tklistbcursel,
+ "delete", tklistbdelete,
+ "get", tklistbget,
+ "index", tklistbindex,
+ "insert", tklistbinsert,
+ "nearest", tklistbnearest,
+ "selection", tklistbselection,
+ "see", tklistbsee,
+ "size", tklistbsize,
+ "xview", tklistbxview,
+ "yview", tklistbyview,
+ "tkListbButton1P", tklistbbutton1p,
+ "tkListbButton1R", tklistbbutton1r,
+ "tkListbButton1MP", tklistbbutton1m,
+ "tkListbKey", tklistbkey,
+ nil
+};
+
+TkMethod listboxmethod = {
+ "listbox",
+ tklistcmd,
+ tkfreelistb,
+ tkdrawlistb,
+ tklistbgeom
+};
--- /dev/null
+++ b/libtk/listb.h
@@ -1,0 +1,1 @@
+extern char* tklistbselection(Tk*, char*, char**);
--- /dev/null
+++ b/libtk/mail.tk
@@ -1,0 +1,224 @@
+
+# This is the first screen of the Sun mailtool
+
+# Frame .frame1 contains top-row buttons, label and entry
+# Frame .frame2 contains bottom-row buttons
+frame .frame1 -relief flat -bd 2
+frame .frame1.frame11 -relief flat -bd 2
+frame .frame1.frame12 -relief flat -bd 2
+frame .frame2 -relief flat -bd 2
+frame .frame2.frame21 -relief flat -bd 2
+frame .frame2.frame22 -relief flat -bd 2
+#frame .dummy -width 18c
+pack .frame1 .frame2 -side top -fill x
+pack .frame2.frame21 -side left -fill x
+pack .frame2.frame22 -side left -fill x
+pack .frame1.frame11 -side left -fill x
+pack .frame1.frame12 -side left -fill x
+# Scrolltext frame
+frame .frame3 -relief sunken -bd 2
+frame .frame3.frame
+
+# File View Edit Compose buttons and associated menus
+
+# Build File button
+menubutton .frame1.frame11.file -text {File} -relief raised -width 8 \
+ -menu {.frame1.frame11.file.menu}
+
+# Build File-menu
+menu .frame1.frame11.file.menu
+.frame1.frame11.file.menu add command \
+ -label {Load In-Box} \
+ -state {active}
+.frame1.frame11.file.menu add command \
+ -label {Print}
+.frame1.frame11.file.menu add command \
+ -label {Save Changes}
+.frame1.frame11.file.menu add command \
+ -label {Done}
+.frame1.frame11.file.menu add command \
+ -label {Mail Files...}
+
+# Build View button
+menubutton .frame1.frame11.view -text {View} -relief raised -width 8 \
+ -menu {.frame1.frame11.view.menu}
+
+# Build View-menu
+menu .frame1.frame11.view.menu
+
+.frame1.frame11.view.menu add command \
+ -label {Messages}
+.frame1.frame11.view.menu add command \
+ -label {Previous}
+.frame1.frame11.view.menu add command \
+ -label {Next} \
+ -state {active}
+.frame1.frame11.view.menu add command \
+ -label {Sort By}
+.frame1.frame11.view.menu add command \
+ -label {Find...}
+
+# Build Edit button
+menubutton .frame1.frame11.edit -text {Edit} -relief raised -width 8 \
+ -menu {.frame1.frame11.edit.menu}
+
+# Build Edit-menu
+ menu .frame1.frame11.edit.menu
+ .frame1.frame11.edit.menu add command \
+ -label {Cut}
+ .frame1.frame11.edit.menu add command \
+ -label {Copy}
+ .frame1.frame11.edit.menu add command \
+ -label {Delete}
+ .frame1.frame11.edit.menu add command \
+ -label {Undelete}
+ .frame1.frame11.edit.menu add separator
+ .frame1.frame11.edit.menu add command \
+ -label {Properties....}
+
+
+# Build Compose button
+menubutton .frame1.frame11.compose -text {Compose} -relief raised -width 12 \
+ -menu {.frame1.frame11.compose.menu}
+
+# Build Compose-menu
+ menu .frame1.frame11.compose.menu
+ .frame1.frame11.compose.menu add command \
+ -label {New}
+ .frame1.frame11.compose.menu add command \
+ -label {Reply}
+ .frame1.frame11.compose.menu add command \
+ -label {Forward}
+ .frame1.frame11.compose.menu add separator
+ .frame1.frame11.compose.menu add command \
+ -label { Vacation}
+
+# Pack the buttons File, View, Edit, Compose
+pack .frame1.frame11.file \
+ .frame1.frame11.view \
+ .frame1.frame11.edit \
+ .frame1.frame11.compose \
+ -side left
+
+update
+
+# Build Done, Next, Delete, Reply buttons and associated menus
+# Build Done button
+menubutton .frame2.frame21.done -text {Done} -relief raised -width 8 \
+ -menu {.frame2.frame21.done.menu}
+
+# Build Done-menu (empty)
+menu .frame2.frame21.done.menu
+
+# Build Next button
+menubutton .frame2.frame21.next -text {Next} -relief raised -width 8 \
+ -menu {.frame2.frame21.next.menu}
+
+# Build Next-menu (empty)
+menu .frame2.frame21.next.menu
+
+# Build Delete button
+menubutton .frame2.frame21.delete -text {Delete} -relief raised -width 8 \
+ -menu {.frame2.frame21.delete.menu}
+
+# Build Delete-menu (empty)
+menu .frame2.frame21.delete.menu
+
+# Build Reply button
+menubutton .frame2.frame21.reply -text {Reply} -relief raised -width 12 \
+ -menu {.frame2.frame21.reply.menu}
+
+# Build Reply-menu
+menu .frame2.frame21.reply.menu
+ .frame2.frame21.reply.menu add command \
+ -label {To Sender}
+ .frame2.frame21.reply.menu add command \
+ -label {To All}
+ .frame2.frame21.reply.menu add command \
+ -label {To Sender, Include}
+ .frame2.frame21.reply.menu add command \
+ -label {To All, Include}
+
+# Pack buttons Done, Next, Delete, Reply
+pack .frame2.frame21.done \
+ .frame2.frame21.next \
+ .frame2.frame21.delete \
+ .frame2.frame21.reply \
+ -side left
+
+update
+
+# Build buttons Move, Copy, Load and associated menus
+menubutton .frame2.frame22.move -text {Move} -relief raised -width 8 \
+ -menu {.frame2.frame22.move.menu}
+menu .frame2.frame22.move.menu
+.frame2.frame22.move.menu add command \
+ -label {Entry}
+
+menubutton .frame2.frame22.copy -text {Copy} -relief raised -width 8 \
+ -menu {.frame2.frame22.copy.menu}
+menu .frame2.frame22.copy.menu
+.frame2.frame22.copy.menu add command \
+ -label {Entry}
+
+menubutton .frame2.frame22.load -text {Load} -relief raised -width 8 \
+ -menu {.frame2.frame22.load.menu}
+menu .frame2.frame22.load.menu
+.frame2.frame22.load.menu add command \
+ -label {Entry}
+
+pack .frame2.frame22.move \
+ .frame2.frame22.copy \
+ .frame2.frame22.load \
+ -side left -fill x
+
+update
+
+# Build Mail-File label and Dir-Path entry widgets
+label .frame1.frame12.lab_mailfile -relief flat -text {Mail File: }
+entry .frame1.frame12.entry_mailfile -width 30 -relief sunken -bd 2
+pack .frame1.frame12.entry_mailfile -side right
+pack .frame1.frame12.lab_mailfile -side left
+
+update
+
+# Build scrolltext w/ scrollbars
+scrollbar .frame3.frame.scrollbar1 \
+ -command {.frame3.frame.listbox1 xview} \
+ -orient {horizontal} \
+ -relief {raised}
+scrollbar .frame3.frame.scrollbar2 \
+ -command {.frame3.frame.listbox1 yview} \
+ -relief {raised}
+text .frame3.frame.listbox1 \
+ -relief {raised} \
+ -xscrollcommand {.frame3.frame.scrollbar1 set} \
+ -yscrollcommand {.frame3.frame.scrollbar2 set}
+.frame3.frame.listbox1 insert end {Some Text}
+pack .frame3.frame
+pack .frame3.frame.scrollbar2 -side left -fill y
+pack .frame3.frame.listbox1 -side top -expand 1 -fill both
+pack .frame3.frame.scrollbar1 -side bottom -fill x
+
+# Pack frame3 to the rest of container frames
+pack .frame3 .frame3.frame -side top -expand 1 -fill both
+
+update
+
+# Build label(???) at the bottom
+label .lab_msgnum -relief flat
+pack .lab_msgnum -side top -fill x
+
+# Now make everything visible
+update
+
+# Enable keyboard traversal of a menu (Is this needed in inferno Tk?)
+#tk_menuBar .frame1.frame11 .frame1.frame11.file .frame1.frame11.view \
+ #.frame1.frame11.edit .frame1.frame11.compose
+#tk_menuBar .frame2.frame21 .frame2.frame21.done .frame2.frame21.next \
+ #.frame2.frame21.delete .frame2.frame21.reply \
+ #.frame2.frame22 .frame2.frame22.move .frame2.frame22.copy .frame2.frame22.load
+focus .frame1.frame11
+update
+
+
--- /dev/null
+++ b/libtk/menu.tk
@@ -1,0 +1,49 @@
+frame .spacer -width 10c -height 5c
+
+listbox .spacer.l -yscrollcommand {.spacer.scroll set} -xscrollcommand {.scrollh set}
+scrollbar .spacer.scroll -command {.spacer.l yview}
+scrollbar .scrollh -orient horizontal -command {.spacer.l xview} -width [.spacer.l cget width]
+.spacer.l insert end This is some text for the
+.spacer.l insert end listboxandthisentryisverymuchlongerthattherest
+.spacer.l insert end and here is some more stuff to box
+.spacer.l insert end and here is some more stuff to box
+.spacer.l insert end and here is some more stuff to box
+.spacer.l insert end and here is some more stuff to box
+.spacer.l insert end and here is some more stuff to box
+
+canvas .c -width 5c -height 3c
+.c create rectangle 1c 1c 2c 2c -fill red
+.c create line 1c 1c 2c 2c -arrow both
+
+pack .spacer.l .spacer.scroll .c -side left -fill y
+.spacer.l selection set 3
+
+frame .mbar -relief raised -bd 2
+pack .mbar -fill x
+pack .mbar .spacer .scrollh -anchor w
+
+menubutton .mbar.file -text File -menu .mbar.file.m -underline 0
+menubutton .mbar.edit -text Edit -menu .mbar.edit.m -underline 0
+pack .mbar.file .mbar.edit -side left
+
+menu .mbar.file.m
+.mbar.file.m add checkbutton -label Italic
+.mbar.file.m add checkbutton -label Bold
+.mbar.file.m add checkbutton -label Underline
+.mbar.file.m add separator
+.mbar.file.m add command -label Quit
+.mbar.file.m add command -label Dictionary
+.mbar.file.m add cascade -label Search -menu .mbar.file.m.global
+
+menu .mbar.edit.m
+.mbar.edit.m add checkbutton -label Italic
+.mbar.edit.m add checkbutton -label Bold
+.mbar.edit.m add checkbutton -label Underline
+
+menu .mbar.file.m.global
+.mbar.file.m.global add checkbutton -label "\{Case Sensitive\}"
+.mbar.file.m.global add checkbutton -label Forward
+.mbar.file.m.global add checkbutton -label Backward
+.mbar.file.m.global add radiobutton -label "\{Upper case\}" -variable case -value u
+.mbar.file.m.global add radiobutton -label "\{Lower case\}" -variable case -value l
+.mbar.file.m.global add radiobutton -label "\{Case Insensitive\}" -variable case -value i
--- /dev/null
+++ b/libtk/menus.c
@@ -1,0 +1,1840 @@
+#include "lib9.h"
+#include "draw.h"
+#include "keyboard.h"
+#include "tk.h"
+#include "frame.h"
+#include "label.h"
+
+/*
+arrow annotation for choicebutton: how do we make sure
+the menu items come up the same size?
+ - set menu items to same req.width & height as button itself.
+
+autorepeat:
+when we get mouse event at the edge of the screen
+and the menu overlaps that edge,
+start autorepeat timer to slide the menu the opposite direction.
+
+variable setting + command invocation:
+is the value of the variable the text or the index?
+same for the value appended to the command, text or index?
+
+if it's reimplemented as a custom widget, how does the custom widget
+get notified of variable changes?
+*/
+
+/* Widget Commands (+ means implemented)
+ +activate
+ +add
+ +cget
+ +configure
+ +delete
+ +entrycget
+ +entryconfigure
+ +index
+ +insert
+ +invoke
+ +post
+ +postcascade
+ +type
+ +unpost
+ +yposition
+*/
+
+#define O(t, e) ((long)(&((t*)0)->e))
+
+/* Layout constants */
+enum {
+ Sepheight = 6, /* Height of menu separator */
+};
+
+#define NOCHOICE "-----"
+
+enum {
+ Startspeed = TKI2F(1),
+};
+
+static
+TkOption mbopts[] =
+{
+ "text", OPTtext, O(TkLabel, text), nil,
+ "anchor", OPTflag, O(TkLabel, anchor), tkanchor,
+ "underline", OPTdist, O(TkLabel, ul), nil,
+ "justify", OPTstab, O(TkLabel, justify), tkjustify,
+ "menu", OPTtext, O(TkLabel, menu), nil,
+ "bitmap", OPTbmap, O(TkLabel, bitmap), nil,
+ "image", OPTimag, O(TkLabel, img), nil,
+ nil
+};
+
+static
+TkOption choiceopts[] =
+{
+ "variable", OPTtext, O(TkLabel, variable), nil,
+ "values", OPTlist, O(TkLabel, values), nil,
+ "command", OPTtext, O(TkLabel, command), nil,
+ nil
+};
+
+static
+TkEbind mbbindings[] =
+{
+ {TkEnter, "%W tkMBenter %s"},
+ {TkLeave, "%W tkMBleave"},
+ {TkButton1P, "%W tkMBpress 1"},
+ {TkKey, "%W tkMBkey 0x%K"},
+ {TkButton1P|TkMotion, "%W tkMBpress 0"},
+};
+
+extern Rectangle bbnil;
+static char* tkmpost(Tk*, int, int, int, int, int);
+static void menuclr(Tk*);
+static void freemenu(Tk*);
+static void appenditem(Tk*, Tk*, int);
+static void layout(Tk*);
+static Tk* tkmenuindex2ptr(Tk*, char**);
+static void activateitem(Tk*);
+
+/*
+ * unmap menu cascade upto (but not including) tk
+ */
+static void
+tkunmapmenus(TkTop *top, Tk *tk)
+{
+ TkTop *t;
+ Tk *menu;
+ TkWin *tkw;
+
+ menu = top->ctxt->tkmenu;
+ if (menu == nil)
+ return;
+ t = menu->env->top;
+
+ /* if something went wrong, clear down all menus */
+ if (tk != nil && tk->env->top != t)
+ tk = nil;
+
+ while (menu != nil && menu != tk) {
+ menuclr(menu);
+ tkunmap(menu);
+ tkcancelrepeat(menu);
+ tkw = TKobj(TkWin, menu);
+ if (tkw->cascade != nil) {
+ menu = tklook(t, tkw->cascade, 0);
+ free(tkw->cascade);
+ tkw->cascade = nil;
+ } else
+ menu = nil;
+ }
+ top->ctxt->tkmenu = menu;
+ tksetmgrab(top, menu);
+}
+
+static void
+tkunmapmenu(Tk *tk)
+{
+ TkTop *t;
+ TkWin *tkw;
+ Tk *parent;
+
+ parent = nil;
+ tkw = TKobj(TkWin, tk);
+ t = tk->env->top;
+ if (tkw->cascade != nil)
+ parent = tklook(t, tkw->cascade, 0);
+ tkunmapmenus(t, parent);
+ if (tkw->freeonunmap)
+ freemenu(tk);
+}
+
+static void
+tksizemenubutton(Tk *tk)
+{
+ int w, h;
+ char **v, *cur;
+ TkLabel *tkl = TKobj(TkLabel, tk);
+
+ tksizelabel(tk);
+ if(tk->type != TKchoicebutton)
+ return;
+ w = tk->req.width;
+ h = tk->req.height;
+ v = tkl->values;
+ if (v == nil || *v == nil)
+ return;
+ cur = tkl->text;
+ for (; *v; v++) {
+ tkl->text = *v;
+ tksizelabel(tk);
+ if (tk->req.width > w)
+ w = tk->req.width;
+ if (tk->req.height > h)
+ h = tk->req.height;
+ }
+ tkl->text = cur;
+ tksizelabel(tk);
+ tk->req.width = w;
+ tk->req.height = h;
+}
+
+static char*
+tkmkmenubutton(TkTop *t, char *arg, char **ret, int type, TkOption *opts)
+{
+ Tk *tk;
+ char *e, **v;
+ TkName *names;
+ TkLabel *tkl;
+ TkOptab tko[3];
+
+/* need to get the label from elsewhere */
+ tk = tknewobj(t, type, sizeof(Tk)+sizeof(TkLabel));
+ if(tk == nil)
+ return TkNomem;
+ tk->borderwidth = 2;
+ tk->flag |= Tknograb;
+
+ tkl = TKobj(TkLabel, tk);
+ tkl->ul = -1;
+ if(type == TKchoicebutton)
+ tkl->anchor = Tknorth|Tkwest;
+
+ tko[0].ptr = tk;
+ tko[0].optab = tkgeneric;
+ tko[1].ptr = tkl;
+ tko[1].optab = opts;
+ tko[2].ptr = nil;
+
+ names = nil;
+ e = tkparse(t, arg, tko, &names);
+ if(e != nil) {
+ tkfreeobj(tk);
+ return e;
+ }
+ tkl->nvalues = 0;
+ if (tkl->values != nil) {
+ for (v = tkl->values; *v; v++)
+ ;
+ tkl->nvalues = v - tkl->values;
+ }
+ if(type == TKchoicebutton){
+ if(tkl->nvalues > 0)
+ tkl->text = strdup(tkl->values[0]);
+ else
+ tkl->text = strdup(NOCHOICE);
+ }
+ tksettransparent(tk,
+ tkhasalpha(tk->env, TkCbackgnd) ||
+ tkhasalpha(tk->env, TkCselectbgnd) ||
+ tkhasalpha(tk->env, TkCactivebgnd));
+
+ e = tkbindings(t, tk, mbbindings, nelem(mbbindings));
+
+ if(e != nil) {
+ tkfreeobj(tk);
+ return e;
+ }
+ tksizemenubutton(tk);
+
+ e = tkaddchild(t, tk, &names);
+ tkfreename(names);
+ if(e != nil) {
+ tkfreeobj(tk);
+ return e;
+ }
+ tk->name->link = nil;
+
+ return tkvalue(ret, "%s", tk->name->name);
+}
+
+char*
+tkchoicebutton(TkTop *t, char *arg, char **ret)
+{
+ return tkmkmenubutton(t, arg, ret, TKchoicebutton, choiceopts);
+}
+
+char*
+tkmenubutton(TkTop *t, char *arg, char **ret)
+{
+ return tkmkmenubutton(t, arg, ret, TKmenubutton, mbopts);
+}
+
+static char*
+tkmenubutcget(Tk *tk, char *arg, char **val)
+{
+ TkOptab tko[3];
+ TkLabel *tkl = TKobj(TkLabel, tk);
+
+ tko[0].ptr = tk;
+ tko[0].optab = tkgeneric;
+ tko[1].ptr = tkl;
+ tko[1].optab = (tk->type == TKchoicebutton ? choiceopts : mbopts);
+ tko[2].ptr = nil;
+
+ return tkgencget(tko, arg, val, tk->env->top);
+}
+
+static char*
+tkmenubutconf(Tk *tk, char *arg, char **val)
+{
+ char *e, **v;
+ TkGeom g;
+ int bd;
+ TkOptab tko[3];
+ TkLabel *tkl = TKobj(TkLabel, tk);
+
+ tko[0].ptr = tk;
+ tko[0].optab = tkgeneric;
+ tko[1].ptr = tkl;
+ tko[1].optab = (tk->type == TKchoicebutton ? choiceopts : mbopts);
+ tko[2].ptr = nil;
+
+ if(*arg == '\0')
+ return tkconflist(tko, val);
+
+ g = tk->req;
+ bd = tk->borderwidth;
+ e = tkparse(tk->env->top, arg, tko, nil);
+
+ if (tk->type == TKchoicebutton) {
+ tkl->nvalues = 0;
+ if (tkl->values != nil) {
+ for (v = tkl->values; *v; v++)
+ ;
+ tkl->nvalues = v - tkl->values;
+ }
+ if (tkl->check >= tkl->nvalues || strcmp(tkl->text, tkl->values[tkl->check])) {
+ /*
+ * try to keep selected value the same if possible
+ */
+ for (v = tkl->values; v && *v; v++)
+ if (!strcmp(*v, tkl->text))
+ break;
+ free(tkl->text);
+ if (v == nil || *v == nil) {
+ tkl->text = strdup(tkl->nvalues > 0 ? tkl->values[0] : NOCHOICE);
+ tkl->check = 0;
+ } else {
+ tkl->check = v - tkl->values;
+ tkl->text = strdup(*v);
+ }
+ }
+ }
+ tksettransparent(tk,
+ tkhasalpha(tk->env, TkCbackgnd) ||
+ tkhasalpha(tk->env, TkCselectbgnd) ||
+ tkhasalpha(tk->env, TkCactivebgnd));
+ tksizemenubutton(tk);
+ tkgeomchg(tk, &g, bd);
+
+ tk->dirty = tkrect(tk, 1);
+ return e;
+}
+
+static char*
+tkMBleave(Tk *tk, char *arg, char **val)
+{
+ USED(arg);
+ USED(val);
+
+ tk->flag &= ~Tkactive;
+ tk->dirty = tkrect(tk, 1);
+ return nil;
+}
+
+static Tk*
+mkchoicemenu(Tk *tkb)
+{
+ Tk *menu, *tkc;
+ int i;
+ TkLabel *tkl, *tkcl;
+ TkWin *tkw;
+ TkTop *t;
+
+ tkl = TKobj(TkLabel, tkb);
+ t = tkb->env->top;
+
+ menu = tknewobj(t, TKmenu, sizeof(Tk)+sizeof(TkWin));
+ if(menu == nil)
+ return nil;
+
+ menu->relief = TKraised;
+ menu->flag |= Tknograb;
+ menu->borderwidth = 1;
+ tkputenv(menu->env);
+ menu->env = tkb->env;
+ menu->env->ref++;
+
+ menu->flag |= Tkwindow;
+ menu->geom = tkmoveresize;
+ tkw = TKobj(TkWin, menu);
+ tkw->cbname = strdup(tkb->name->name);
+ tkw->di = (void*)-1; // XXX
+
+ for(i = tkl->nvalues - 1; i >= 0; i--){
+ tkc = tknewobj(t, TKlabel, sizeof(Tk)+sizeof(TkLabel));
+ /* XXX recover from malloc failure */
+ tkc->flag = Tkwest|Tkfillx|Tktop;
+ tkc->highlightwidth = 0;
+ tkc->borderwidth = 1;
+ tkc->relief = TKflat;
+ tkputenv(tkc->env);
+ tkc->env = tkb->env;
+ tkc->env->ref++;
+ tkcl = TKobj(TkLabel, tkc);
+ tkcl->anchor = Tkwest;
+ tkcl->ul = -1;
+ tkcl->justify = Tkleft;
+ tkcl->text = strdup(tkl->values[i]);
+ tkcl->command = smprint("%s invoke %d", tkb->name->name, i);
+ /* XXX recover from malloc failure */
+ tksizelabel(tkc);
+ tkc->req.height = tkb->req.height;
+ appenditem(menu, tkc, 0);
+ }
+ layout(menu);
+
+ tkw->next = t->windows;
+ tkw->freeonunmap = 1;
+ t->windows = menu;
+ return menu;
+}
+
+static char*
+tkMBpress(Tk *tk, char *arg, char **val)
+{
+ Tk *menu, *item;
+ TkLabel *tkl = TKobj(TkLabel, tk);
+ Point g;
+ char buf[12], *bufp, *e;
+
+ USED(arg);
+ USED(val);
+
+ g = tkposn(tk);
+ if (tk->type == TKchoicebutton) {
+ menu = mkchoicemenu(tk);
+ if (menu == nil)
+ return TkNomem;
+ sprint(buf, "%d", tkl->check);
+ bufp = buf;
+ item = tkmenuindex2ptr(menu, &bufp);
+ if(item == nil)
+ return nil;
+ g.y -= item->act.y;
+ e = tkmpost(menu, g.x, g.y, 0, 0, 0);
+ activateitem(item);
+ return e;
+ } else {
+ if (tkl->menu == nil)
+ return nil;
+ menu = tklook(tk->env->top, tkl->menu, 0);
+ if(menu == nil || menu->type != TKmenu)
+ return TkBadwp;
+
+ if(menu->flag & Tkmapped) {
+ if(atoi(arg))
+ tkunmapmenu(menu);
+ return nil;
+ }
+ return tkmpost(menu, g.x, g.y, 0, tk->act.height + 2*tk->borderwidth, 1);
+ }
+}
+
+static char*
+tkMBkey(Tk *tk, char *arg, char **val)
+{
+ int key;
+ USED(val);
+
+ if(tk->flag & Tkdisabled)
+ return nil;
+
+ key = strtol(arg, nil, 0);
+ if (key == '\n' || key == ' ')
+ return tkMBpress(tk, "1", nil);
+ return nil;
+}
+
+static char*
+tkMBenter(Tk *tk, char *arg, char **val)
+{
+ USED(arg);
+ USED(val);
+
+ tk->flag |= Tkactive;
+ tk->dirty = tkrect(tk, 1);
+ return nil;
+}
+
+static char*
+tkchoicebutset(Tk *tk, char *arg, char **val)
+{
+ char buf[12], *e;
+ int v;
+ TkLabel *tkl = TKobj(TkLabel, tk);
+
+ USED(val);
+
+ tkword(tk->env->top, arg, buf, buf+sizeof(buf), nil);
+ if (*buf == '\0')
+ return TkBadvl;
+ v = atoi(buf);
+ if (v < 0 || v >= tkl->nvalues)
+ return TkBadvl;
+ if (v == tkl->check)
+ return nil;
+ free(tkl->text);
+ tkl->text = strdup(tkl->values[v]);
+ /* XXX recover from malloc error */
+ tkl->check = v;
+
+ sprint(buf, "%d", v);
+ e = tksetvar(tk->env->top, tkl->variable, buf);
+ if(e != nil)
+ return e;
+
+ tk->dirty = tkrect(tk, 1);
+ return nil;
+}
+
+static char*
+tkchoicebutinvoke(Tk *tk, char *arg, char **val)
+{
+ TkLabel *tkl = TKobj(TkLabel, tk);
+ char *e;
+
+ e = tkchoicebutset(tk, arg, val);
+ if(e != nil)
+ return e;
+ if(tkl->command)
+ return tkexec(tk->env->top, tkl->command, val);
+ return nil;
+}
+
+static char*
+tkchoicebutgetvalue(Tk *tk, char *arg, char **val)
+{
+ char buf[12];
+ int gotarg, v;
+ TkLabel *tkl = TKobj(TkLabel, tk);
+ if (tkl->nvalues == 0)
+ return nil;
+ tkword(tk->env->top, arg, buf, buf+sizeof(buf), &gotarg);
+ if (!gotarg)
+ return tkvalue(val, "%s", tkl->values[tkl->check]);
+ v = atoi(buf);
+ if (buf[0] < '0' || buf[0] > '9' || v >= tkl->nvalues)
+ return TkBadvl;
+ return tkvalue(val, "%s", tkl->values[tkl->check]);
+}
+
+static char*
+tkchoicebutsetvalue(Tk *tk, char *arg, char **val)
+{
+ char *buf;
+ char **v;
+ int gotarg;
+ TkLabel *tkl = TKobj(TkLabel, tk);
+
+ USED(val);
+ if (tkl->nvalues == 0)
+ return TkBadvl;
+ buf = mallocz(Tkmaxitem, 0);
+ if (buf == nil)
+ return TkNomem;
+ tkword(tk->env->top, arg, buf, buf+Tkmaxitem, &gotarg);
+ if (!gotarg) {
+ free(buf);
+ return TkBadvl;
+ }
+ for (v = tkl->values; *v; v++)
+ if (strcmp(*v, buf) == 0)
+ break;
+ free(buf);
+ if (*v == nil)
+ return TkBadvl;
+ free(tkl->text);
+ tkl->text = strdup(*v);
+ /* XXX recover from malloc error */
+ tkl->check = v - tkl->values;
+
+ tk->dirty = tkrect(tk, 1);
+ return nil;
+}
+
+static char*
+tkchoicebutget(Tk *tk, char *arg, char **val)
+{
+ TkLabel *tkl = TKobj(TkLabel, tk);
+ char *buf, **v;
+ int gotarg;
+
+ if (tkl->nvalues == 0)
+ return nil;
+ buf = mallocz(Tkmaxitem, 0);
+ if (buf == nil)
+ return TkNomem;
+ tkword(tk->env->top, arg, buf, buf+Tkmaxitem, &gotarg);
+ if (!gotarg) {
+ free(buf);
+ return tkvalue(val, "%d", tkl->check);
+ }
+
+ for (v = tkl->values; *v; v++)
+ if (strcmp(*v, buf) == 0)
+ break;
+ free(buf);
+ if (*v)
+ return tkvalue(val, "%d", v - tkl->values);
+ return nil;
+}
+
+static char*
+tkchoicebutvaluecount(Tk *tk, char *arg, char **val)
+{
+ TkLabel *tkl = TKobj(TkLabel, tk);
+ USED(arg);
+ return tkvalue(val, "%d", tkl->nvalues);
+}
+
+
+static void
+tkchoicevarchanged(Tk *tk, char *var, char *value)
+{
+ TkLabel *tkl = TKobj(TkLabel, tk);
+ int v;
+
+ if(tkl->variable != nil && strcmp(tkl->variable, var) == 0){
+ if(value[0] < '0' || value[0] > '9')
+ return;
+ v = atoi(value);
+ if(v < 0 || v >= tkl->nvalues)
+ return; /* what else can we do? */
+ free(tkl->text);
+ tkl->text = strdup(tkl->values[v]);
+ /* XXX recover from malloc error */
+ tkl->check = v;
+ tk->dirty = tkrect(tk, 0);
+ tkdirty(tk);
+ }
+}
+
+Tk *
+tkfindchoicemenu(Tk *tkb)
+{
+ Tk *tk, *next;
+ TkTop *top;
+ TkWin *tkw;
+
+ top = tkb->env->top;
+ for (tk = top->windows; tk != nil; tk = next){
+ tkw = TKobj(TkWin, tk);
+ if(tk->name == nil){
+ assert(strcmp(tkw->cbname, tkb->name->name) == 0);
+ return tk;
+ }
+ next = tkw->next;
+ }
+ return nil;
+}
+
+static
+TkOption menuopt[] =
+{
+ "postcommand", OPTtext, O(TkWin, postcmd), nil,
+ nil,
+};
+
+char*
+tkmenu(TkTop *t, char *arg, char **ret)
+{
+ Tk *tk;
+ char *e;
+ TkWin *tkw;
+ TkName *names;
+ TkOptab tko[3];
+
+ tk = tknewobj(t, TKmenu, sizeof(Tk)+sizeof(TkWin));
+ if(tk == nil)
+ return TkNomem;
+
+ tkw = TKobj(TkWin, tk);
+ tkw->di = (void*)-1; // XXX
+ tk->relief = TKraised;
+ tk->flag |= Tknograb;
+ tk->borderwidth = 1;
+
+ tko[0].ptr = tk;
+ tko[0].optab = tkgeneric;
+ tko[1].ptr = tkw;
+ tko[1].optab = menuopt;
+ tko[2].ptr = nil;
+
+ names = nil;
+ e = tkparse(t, arg, tko, &names);
+ if(e != nil) {
+ tkfreeobj(tk);
+ return e;
+ }
+
+ e = tkaddchild(t, tk, &names);
+ tkfreename(names);
+ if(e != nil) {
+ tkfreeobj(tk);
+ return e;
+ }
+ tk->name->link = nil;
+
+ tk->flag |= Tkwindow;
+ tk->geom = tkmoveresize;
+
+ tkw->next = t->windows;
+ t->windows = tk;
+
+ return tkvalue(ret, "%s", tk->name->name);
+}
+
+static void
+freemenu(Tk *top)
+{
+ Tk *tk, *f, *nexttk, *nextf;
+ TkWin *tkw;
+
+ tkunmapmenu(top);
+ tkw = TKobj(TkWin, top);
+ for(tk = tkw->slave; tk; tk = nexttk) {
+ nexttk = tk->next;
+ for(f = tk->slave; f; f = nextf) {
+ nextf = f->next;
+ tkfreeobj(f);
+ }
+ tkfreeobj(tk);
+ }
+ top->slave = nil;
+ tkfreeframe(top);
+}
+
+static
+TkOption mopt[] =
+{
+ "menu", OPTtext, O(TkLabel, menu), nil,
+ nil,
+};
+
+static void
+tkbuildmopt(TkOptab *tko, int n, Tk *tk)
+{
+ memset(tko, 0, n*sizeof(TkOptab));
+
+ n = 0;
+ tko[n].ptr = tk;
+ tko[n++].optab = tkgeneric;
+
+ switch(tk->type) {
+ case TKcascade:
+ tko[n].ptr = TKobj(TkLabel, tk);
+ tko[n++].optab = mopt;
+ goto norm;
+ case TKradiobutton:
+ tko[n].ptr = TKobj(TkLabel, tk);
+ tko[n++].optab = tkradopts;
+ goto norm;
+ case TKcheckbutton:
+ tko[n].ptr = TKobj(TkLabel, tk);
+ tko[n++].optab = tkcbopts;
+ /* fall through */
+ case TKlabel:
+ norm:
+ tko[n].ptr = TKobj(TkLabel, tk);
+ tko[n].optab = tkbutopts;
+ break;
+ }
+}
+
+static char*
+tkmenuentryconf(Tk *menu, Tk *tk, char *arg)
+{
+ char *e;
+ TkOptab tko[4];
+
+ USED(menu);
+
+ tkbuildmopt(tko, nelem(tko), tk);
+ e = tkparse(tk->env->top, arg, tko, nil);
+ switch (tk->type) {
+ case TKlabel:
+ case TKcascade:
+ tksizelabel(tk);
+ break;
+ case TKradiobutton:
+ case TKcheckbutton:
+ tksizebutton(tk);
+ }
+
+ return e;
+}
+
+static void
+layout(Tk *menu)
+{
+ TkWin *tkw;
+ Tk *tk;
+ int m, w, y, maxmargin, maxw;
+
+ y = 0;
+ maxmargin = 0;
+ maxw = 0;
+
+ tkw = TKobj(TkWin, menu);
+
+ /* determine padding for item text alignment */
+ for (tk = tkw->slave; tk != nil; tk = tk->next) {
+ m = tkbuttonmargin(tk); /* TO DO: relies on buttonmargin defaulting to labelmargin */
+ tk->act.x = m; /* temp store */
+ if (m > maxmargin)
+ maxmargin = m;
+ }
+ /* set x pos and determine max width */
+ for (tk = tkw->slave; tk != nil; tk = tk->next) {
+ tk->act.x = tk->borderwidth + maxmargin - tk->act.x;
+ tk->act.y = y + tk->borderwidth;
+ tk->act.height = tk->req.height;
+ tk->act.width = tk->req.width;
+ y += tk->act.height+2*tk->borderwidth;
+ w = tk->act.x + tk->req.width + 2* tk->borderwidth;
+ if (w > maxw)
+ maxw = w;
+ }
+ /* expand separators and cascades and mark all as dirty */
+ for (tk = tkw->slave; tk != nil; tk = tk->next) {
+ switch (tk->type) {
+ case TKseparator:
+ tk->act.x = tk->borderwidth;
+ /*FALLTHRU*/
+ case TKcascade:
+ tk->act.width = (maxw - tk->act.x) - tk->borderwidth;
+ }
+ tk->dirty = tkrect(tk, 1);
+ }
+ menu->dirty = tkrect(menu, 1);
+ tkmoveresize(menu, 0, 0, maxw, y);
+}
+
+static void
+menuitemgeom(Tk *sub, int x, int y, int w, int h)
+{
+ if (sub->parent == nil)
+ return;
+ if(w < 0)
+ w = 0;
+ if(h < 0)
+ h = 0;
+ sub->req.x = x;
+ sub->req.y = y;
+ sub->req.width = w;
+ sub->req.height = h;
+ layout(sub->parent);
+}
+
+static void
+appenditem(Tk *menu, Tk *item, int where)
+{
+ TkWin *tkw;
+ Tk *f, **l;
+
+ tkw = TKobj(TkWin, menu);
+ l = &tkw->slave;
+ for (f = *l; f != nil; f = f->next) {
+ if (where-- == 0)
+ break;
+ l = &f->next;
+ }
+ *l = item;
+ item->next = f;
+ item->parent = menu;
+ item->geom = menuitemgeom;
+}
+
+static char*
+menuadd(Tk *menu, char *arg, int where)
+{
+ Tk *tkc;
+ int configure;
+ char *e;
+ TkTop *t;
+ TkLabel *tkl;
+ char buf[Tkmaxitem];
+
+ t = menu->env->top;
+ arg = tkword(t, arg, buf, buf+sizeof(buf), nil);
+ configure = 1;
+ e = nil;
+
+ if(strcmp(buf, "checkbutton") == 0)
+ tkc = tkmkbutton(t, TKcheckbutton);
+ else if(strcmp(buf, "radiobutton") == 0)
+ tkc = tkmkbutton(t, TKradiobutton);
+ else if(strcmp(buf, "command") == 0)
+ tkc = tknewobj(t, TKlabel, sizeof(Tk)+sizeof(TkLabel));
+ else if(strcmp(buf, "cascade") == 0)
+ tkc = tknewobj(t, TKcascade, sizeof(Tk)+sizeof(TkLabel));
+ else if(strcmp(buf, "separator") == 0) {
+ tkc = tknewobj(t, TKseparator, sizeof(Tk)); /* it's really a frame */
+ if (tkc != nil) {
+ tkc->flag = Tkfillx|Tktop;
+ tkc->req.height = Sepheight;
+ configure = 0;
+ }
+ }
+ else
+ return TkBadvl;
+
+ if (tkc == nil)
+ e = TkNomem;
+
+ if (e == nil) {
+ if(tkc->env == t->env && menu->env != t->env) {
+ tkputenv(tkc->env);
+ tkc->env = menu->env;
+ tkc->env->ref++;
+ }
+ if (configure) {
+ tkc->flag = Tkwest|Tkfillx|Tktop;
+ tkc->highlightwidth = 0;
+ tkc->borderwidth = 1;
+ tkc->relief = TKflat;
+ tkl = TKobj(TkLabel, tkc);
+ tkl->anchor = Tkwest;
+ tkl->ul = -1;
+ tkl->justify = Tkleft;
+ e = tkmenuentryconf(menu, tkc, arg);
+ }
+ }
+
+ if(e != nil) {
+ if (tkc != nil)
+ tkfreeobj(tkc);
+ return e;
+ }
+
+ appenditem(menu, tkc, where);
+ layout(menu);
+ return nil;
+}
+
+static int
+tkmindex(Tk *tk, char *p)
+{
+ TkWin *tkw;
+ int y, n;
+
+ if(*p >= '0' && *p <= '9')
+ return atoi(p);
+
+ tkw = TKobj(TkWin, tk);
+ n = 0;
+ if(*p == '@') {
+ y = atoi(p+1);
+ for(tk = tkw->slave; tk; tk = tk->next) {
+ if(y >= tk->act.y && y < tk->act.y+tk->act.height+2*tk->borderwidth )
+ return n;
+ n++;
+ }
+ }
+ if(strcmp(p, "end") == 0 || strcmp(p, "last") == 0) {
+ for(tk = tkw->slave; tk && tk->next; tk = tk->next)
+ n++;
+ return n;
+ }
+ if(strcmp(p, "active") == 0) {
+ for(tk = tkw->slave; tk; tk = tk->next) {
+ if(tk->flag & Tkactive)
+ return n;
+ n++;
+ }
+ return -2;
+ }
+ if(strcmp(p, "none") == 0)
+ return -2;
+
+ return -1;
+}
+
+static int
+tkmenudel(Tk *tk, int y)
+{
+ TkWin *tkw;
+ Tk *f, **l, *next;
+
+ tkw = TKobj(TkWin, tk);
+ l = &tkw->slave;
+ for(tk = *l; tk; tk = tk->next) {
+ if(y-- == 0) {
+ *l = tk->next;
+ for(f = tk->slave; f; f = next) {
+ next = f->next;
+ tkfreeobj(f);
+ }
+ tkfreeobj(tk);
+ return 1;
+ }
+ l = &tk->next;
+ }
+ return 0;
+}
+
+static char*
+tkmpost(Tk *tk, int x, int y, int cascade, int bh, int adjust)
+{
+ char *e;
+ TkWin *w;
+ TkTop *t;
+ Rectangle *dr;
+
+ t = tk->env->top;
+ if(adjust){
+ dr = &t->screenr;
+ if(x+tk->act.width > dr->max.x)
+ x = dr->max.x - tk->act.width;
+ if(x < 0)
+ x = 0;
+ if(y+bh+tk->act.height > dr->max.y)
+ y -= tk->act.height + 2* tk->borderwidth;
+ else
+ y += bh;
+ if(y < 0)
+ y = 0;
+ }
+ menuclr(tk);
+ tkmovewin(tk, Pt(x, y));
+
+ /* stop possible postcommand recursion */
+ if (tk->flag & Tkmapped)
+ return nil;
+
+ w = TKobj(TkWin, tk);
+ if(w->postcmd != nil) {
+ e = tkexec(tk->env->top, w->postcmd, nil);
+ if(e != nil) {
+ print("%s: postcommand: %s: %s\n", tkname(tk), w->postcmd, e);
+ return e;
+ }
+ }
+ if (!cascade)
+ tkunmapmenus(t, nil);
+
+ e = tkmap(tk);
+ if(e != nil)
+ return e;
+
+ if (t->ctxt->tkmenu != nil)
+ w->cascade = strdup(t->ctxt->tkmenu->name->name);
+ t->ctxt->tkmenu = tk;
+ tksetmgrab(t, tk);
+
+ /* Make sure slaves are redrawn */
+ return tkupdate(tk->env->top);
+}
+
+static Tk*
+tkmenuindex2ptr(Tk *tk, char **arg)
+{
+ TkWin *tkw;
+ int index;
+ char *buf;
+
+ buf = mallocz(Tkmaxitem, 0);
+ if(buf == nil)
+ return nil;
+ *arg = tkword(tk->env->top, *arg, buf, buf+Tkmaxitem, nil);
+ index = tkmindex(tk, buf);
+ free(buf);
+ if(index < 0)
+ return nil;
+
+ tkw = TKobj(TkWin, tk);
+ for(tk = tkw->slave; tk && index; tk = tk->next)
+ index--;
+
+ if(tk == nil)
+ return nil;
+
+ return tk;
+}
+
+static char*
+tkmenuentrycget(Tk *tk, char *arg, char **val)
+{
+ Tk *etk;
+ TkOptab tko[4];
+
+ etk = tkmenuindex2ptr(tk, &arg);
+ if(etk == nil)
+ return TkBadix;
+
+ tkbuildmopt(tko, nelem(tko), etk);
+ return tkgencget(tko, arg, val, tk->env->top);
+}
+
+static char*
+tkmenucget(Tk *tk, char *arg, char **val)
+{
+ TkWin *tkw;
+ TkOptab tko[4];
+
+ tkw = TKobj(TkWin, tk);
+ tko[0].ptr = tk;
+ tko[0].optab = tkgeneric;
+ tko[1].ptr = tkw;
+ tko[1].optab = tktop;
+ tko[2].ptr = tkw;
+ tko[2].optab = menuopt;
+ tko[3].ptr = nil;
+
+ return tkgencget(tko, arg, val, tk->env->top);
+}
+
+static char*
+tkmenuconf(Tk *tk, char *arg, char **val)
+{
+ char *e;
+ TkGeom g;
+ int bd;
+ TkWin *tkw;
+ TkOptab tko[3];
+
+ tkw = TKobj(TkWin, tk);
+ tko[0].ptr = tk;
+ tko[0].optab = tkgeneric;
+ tko[1].ptr = tkw;
+ tko[1].optab = menuopt;
+ tko[2].ptr = nil;
+
+ if(*arg == '\0')
+ return tkconflist(tko, val);
+
+ g = tk->req;
+ bd = tk->borderwidth;
+ e = tkparse(tk->env->top, arg, tko, nil);
+ tkgeomchg(tk, &g, bd);
+ tk->dirty = tkrect(tk, 1);
+ return e;
+}
+
+static char*
+tkmenuadd(Tk *tk, char *arg, char **val)
+{
+ USED(val);
+ return menuadd(tk, arg, -1);
+}
+
+static char*
+tkmenuinsert(Tk *tk, char *arg, char **val)
+{
+ int index;
+ char *buf;
+
+ USED(val);
+ buf = mallocz(Tkmaxitem, 0);
+ if(buf == nil)
+ return TkNomem;
+ arg = tkword(tk->env->top, arg, buf, buf+Tkmaxitem, nil);
+ index = tkmindex(tk, buf);
+ free(buf);
+ if (index < 0)
+ return TkBadix;
+ return menuadd(tk, arg, index);
+}
+
+static void
+menuitemdirty(Tk *item)
+{
+ Tk *menu;
+ Rectangle r;
+
+ menu = item->parent;
+ if (menu == nil)
+ return;
+ item->dirty = tkrect(item, 1);
+ r = rectaddpt(item->dirty, Pt(item->act.x, item->act.y));
+ combinerect(&menu->dirty, r);
+}
+
+static void
+menuclr(Tk *tk)
+{
+ TkWin *tkw;
+ Tk *f;
+ tkw = TKobj(TkWin, tk);
+ for(f = tkw->slave; f; f = f->next) {
+ if(f->flag & Tkactive) {
+ f->flag &= ~Tkactive;
+ menuitemdirty(f);
+ }
+ }
+}
+
+static char*
+tkpostcascade(Tk *parent, Tk *tk, int toggle)
+{
+ Tk *tkm;
+ TkWin *tkw;
+ Point g;
+ TkTop *t;
+ TkLabel *tkl;
+ char *e;
+
+ if(tk->flag & Tkdisabled)
+ return nil;
+
+ tkl = TKobj(TkLabel, tk);
+ t = tk->env->top;
+ tkm = tklook(t, tkl->menu, 0);
+ if(tkm == nil || tkm->type != TKmenu)
+ return TkBadwp;
+
+ if((tkm->flag & Tkmapped)) {
+ if (toggle) {
+ tkunmapmenus(t, parent);
+ return nil;
+ } else {
+ /* check that it is immediate cascade */
+ tkw = TKobj(TkWin, t->ctxt->tkmenu);
+ if (strcmp(tkw->cascade, parent->name->name) == 0)
+ return nil;
+ }
+ }
+
+ tkunmapmenus(t, parent);
+
+ tkl = TKobj(TkLabel, tk);
+ if(tkl->command != nil) {
+ e = tkexec(t, tkl->command, nil);
+ if (e != nil)
+ return e;
+ }
+
+ g = tkposn(tk);
+ g.x += tk->act.width;
+ g.y -= tkm->borderwidth;
+ e = tkmpost(tkm, g.x, g.y, 1, 0, 1);
+ return e;
+}
+
+static void
+activateitem(Tk *item)
+{
+ Tk *menu;
+ if (item == nil || (menu = item->parent) == nil)
+ return;
+ menuclr(menu);
+ if (!(item->flag & Tkdisabled)) {
+ item->flag |= Tkactive;
+ menuitemdirty(item);
+ }
+}
+
+static char*
+tkmenuactivate(Tk *tk, char *arg, char **val)
+{
+ Tk *f;
+ TkWin *tkw;
+ int index;
+ char *buf;
+
+ USED(val);
+ buf = mallocz(Tkmaxitem, 0);
+ if(buf == nil)
+ return TkNomem;
+ tkword(tk->env->top, arg, buf, buf+Tkmaxitem, nil);
+ index = tkmindex(tk, buf);
+ free(buf);
+ if (index == -1)
+ return TkBadix;
+ if (index == -2) {
+ menuclr(tk);
+ return nil;
+ }
+
+ tkw = TKobj(TkWin, tk);
+ for(f = tkw->slave; f; f = f->next)
+ if(index-- == 0)
+ break;
+
+ if(f == nil || f->flag & Tkdisabled) {
+ menuclr(tk);
+ return nil;
+ }
+ if(f->flag & Tkactive)
+ return nil;
+
+ activateitem(f);
+ return nil;
+}
+
+static int
+iteminvoke(Tk *tk, Tk *tki, char *arg)
+{
+ int unmap = 0;
+ menuitemdirty(tki);
+ switch(tki->type) {
+ case TKlabel:
+ unmap = 1;
+ case TKcheckbutton:
+ case TKradiobutton:
+ tkbuttoninvoke(tki, arg, nil);
+ break;
+ case TKcascade:
+ tkpostcascade(tk, tki, 0);
+ break;
+ }
+ return unmap;
+}
+
+static char*
+tkmenuinvoke(Tk *tk, char *arg, char **val)
+{
+ Tk *tki;
+ USED(val);
+ tki = tkmenuindex2ptr(tk, &arg);
+ if(tki == nil)
+ return nil;
+ iteminvoke(tk, tki, arg);
+ return nil;
+}
+
+static char*
+tkmenudelete(Tk *tk, char *arg, char **val)
+{
+ int index1, index2;
+ char *buf;
+
+ USED(val);
+ buf = mallocz(Tkmaxitem, 0);
+ if(buf == nil)
+ return TkNomem;
+ arg = tkitem(buf, arg);
+ index1 = tkmindex(tk, buf);
+ if(index1 < 0) {
+ free(buf);
+ return TkBadix;
+ }
+ index2 = index1;
+ if(*arg != '\0') {
+ tkitem(buf, arg);
+ index2 = tkmindex(tk, buf);
+ }
+ free(buf);
+ if(index2 < 0)
+ return TkBadix;
+ while(index2 >= index1 && tkmenudel(tk, index2))
+ index2--;
+
+ layout(tk);
+ return nil;
+}
+
+static char*
+tkmenupost(Tk *tk, char *arg, char **val)
+{
+ int x, y;
+ TkTop *t;
+ char *buf;
+
+ USED(val);
+
+ buf = mallocz(Tkmaxitem, 0);
+ if(buf == nil)
+ return TkNomem;
+ t = tk->env->top;
+ arg = tkword(t, arg, buf, buf+Tkmaxitem, nil);
+ if(buf[0] == '\0') {
+ free(buf);
+ return TkBadvl;
+ }
+ x = atoi(buf);
+ tkword(t, arg, buf, buf+Tkmaxitem, nil);
+ if(buf[0] == '\0') {
+ free(buf);
+ return TkBadvl;
+ }
+ y = atoi(buf);
+ free(buf);
+
+ return tkmpost(tk, x, y, 0, 0, 1);
+}
+
+static char*
+tkmenuunpost(Tk *tk, char *arg, char **val)
+{
+ USED(arg);
+ USED(val);
+ tkunmapmenu(tk);
+ return nil;
+}
+
+static char*
+tkmenuindex(Tk *tk, char *arg, char **val)
+{
+ char *buf;
+ int index;
+
+ buf = mallocz(Tkmaxitem, 0);
+ if(buf == nil)
+ return TkNomem;
+ tkword(tk->env->top, arg, buf, buf+Tkmaxitem, nil);
+ index = tkmindex(tk, buf);
+ free(buf);
+ if (index == -1)
+ return TkBadix;
+ if (index == -2)
+ return "none";
+ return tkvalue(val, "%d", index);
+}
+
+static char*
+tkmenuyposn(Tk *tk, char *arg, char **val)
+{
+ tk = tkmenuindex2ptr(tk, &arg);
+ if(tk == nil)
+ return TkBadix;
+ return tkvalue(val, "%d", tk->act.y);
+}
+
+static char*
+tkmenupostcascade(Tk *tk, char *arg, char **val)
+{
+ Tk *tki;
+ USED(val);
+ tki = tkmenuindex2ptr(tk, &arg);
+ if(tki == nil || tki->type != TKcascade)
+ return nil;
+
+ return tkpostcascade(tk, tki, 0);
+}
+
+static char*
+tkmenutype(Tk *tk, char *arg, char **val)
+{
+ tk = tkmenuindex2ptr(tk, &arg);
+ if(tk == nil)
+ return TkBadix;
+
+ return tkvalue(val, tk->type == TKlabel ? "command" : tkmethod[tk->type]->name);
+}
+
+static char*
+tkmenususpend(Tk *tk, char *arg, char **val)
+{
+ USED(arg);
+ USED(val);
+ if(tk->type == TKchoicebutton){
+ tk = tkfindchoicemenu(tk);
+ if(tk == nil)
+ return TkNotwm;
+ }
+ tk->flag |= Tksuspended;
+ return nil;
+}
+
+static char*
+tkmenuentryconfig(Tk *tk, char *arg, char **val)
+{
+ Tk *etk;
+ char *e;
+
+ USED(val);
+ etk = tkmenuindex2ptr(tk, &arg);
+ if(etk == nil)
+ return TkBadix;
+
+ e = tkmenuentryconf(tk, etk, arg);
+ layout(tk);
+ return e;
+}
+
+static Tk*
+xymenuitem(Tk *tk, int x, int y)
+{
+ TkWin *tkw = TKobj(TkWin, tk);
+ x -= tkw->act.x;
+ y -= tkw->act.y;
+
+ x -= tk->borderwidth;
+ y -= tk->act.y + tk->borderwidth;
+ if (x < tk->act.x || x > tk->act.x+tk->act.width)
+ return nil;
+ for(tk = tkw->slave; tk; tk = tk->next) {
+ if(y >= tk->act.y && y < tk->act.y+tk->act.height+2*tk->borderwidth)
+ return tk;
+ }
+ return nil;
+}
+
+static char *
+menukey(Tk *tk, int key)
+{
+ Tk *scan, *active, *first, *last, *prev, *next;
+ TkWin *tkw;
+ TkTop *top;
+
+ top = tk->env->top;
+
+ active = first = last = prev = next = nil;
+ tkw = TKobj(TkWin, tk);
+ for(scan = tkw->slave; scan != nil; scan = scan->next) {
+ if(scan->type == TKseparator)
+ continue;
+ if(first == nil)
+ first = scan;
+ if (active != nil && next == nil)
+ next = scan;
+ if(active == nil && scan->flag & Tkactive)
+ active = scan;
+ if (active == nil)
+ prev = scan;
+ last = scan;
+ }
+ if (next == nil)
+ next = first;
+ if (prev == nil)
+ prev = last;
+
+ switch (key) {
+ case Esc:
+ tkunmapmenus(top, nil);
+ break;
+ case Left:
+ if (tkw->cascade != nil)
+ tkunmapmenu(tk);
+ break;
+ case Right:
+ if (active == nil || active->type != TKcascade)
+ break;
+ case ' ':
+ case '\n':
+ if (active != nil) {
+ if (iteminvoke(tk, active, nil))
+ tkunmapmenus(top, nil);
+ }
+ break;
+ case Up:
+ next = prev;
+ case Down:
+ if (next != nil)
+ activateitem(next);
+ }
+ return nil;
+}
+
+static char*
+drawmenu(Tk *tk, Point orig)
+{
+ Image *dst;
+ TkWin *tkw;
+ Tk *sub;
+ Point p, bd;
+ int bg;
+ Rectangle mainr, clientr, subr;
+
+ tkw = TKobj(TkWin, tk);
+ dst = tkimageof(tk);
+
+ bd = Pt(tk->borderwidth, tk->borderwidth);
+ mainr.min = addpt(orig, Pt(tk->act.x, tk->act.y));
+ clientr.min = addpt(mainr.min, bd);
+ clientr.max = addpt(clientr.min, Pt(tk->act.width, tk->act.height));
+ mainr.max = addpt(clientr.max, bd);
+
+ /*
+ * note that we draw item background to get full menu width
+ * active indicator, this means we must dirty the entire
+ * item rectangle to ensure it is fully redrawn
+ */
+ p = clientr.min;
+ subr = clientr;
+ for (sub = tkw->slave; sub != nil; sub = sub->next) {
+ if (Dx(sub->dirty) == 0)
+ continue;
+ subr.min.y = p.y + sub->act.y - sub->borderwidth;
+ subr.max.y = p.y + sub->act.y + sub->act.height + sub->borderwidth;
+ bg = TkCbackgnd;
+ if (sub->flag & Tkactive)
+ bg = TkCactivebgnd;
+ draw(dst, subr, tkgc(sub->env, bg), nil, ZP);
+ sub->dirty = tkrect(sub, 1);
+ sub->flag |= Tkrefresh;
+ tkmethod[sub->type]->draw(sub, p);
+ sub->dirty = bbnil;
+ sub->flag &= ~Tkrefresh;
+ }
+ /* todo: dirty check */
+ tkdrawrelief(dst, tk, mainr.min, TkCbackgnd, tk->relief);
+ return nil;
+}
+
+static void
+menudirty(Tk *sub)
+{
+ menuitemdirty(sub);
+}
+
+static Point
+menurelpos(Tk *sub)
+{
+ return Pt(sub->act.x-sub->borderwidth, sub->act.y-sub->borderwidth);
+}
+
+static void
+autoscroll(Tk *tk, void *v, int cancelled)
+{
+ TkWin *tkw;
+ Rectangle r, dr;
+ Point delta, od;
+ TkMouse *m;
+ Tk *item;
+ USED(v);
+
+ tkw = TKobj(TkWin, tk);
+ if (cancelled) {
+ tkw->speed = 0;
+ return;
+ }
+ if(!eqpt(tkw->act, tkw->req)){
+print("not autoscrolling, act: %P, req: %P\n", tkw->act, tkw->req);
+ return;
+}
+ dr = tk->env->top->screenr;
+ delta.x = TKF2I(tkw->delta.x * tkw->speed);
+ delta.y = TKF2I(tkw->delta.y * tkw->speed);
+ r = rectaddpt(tkrect(tk, 1), Pt(tk->borderwidth + tkw->act.x, tk->borderwidth + tkw->act.y));
+
+ od = delta;
+ /* make sure we don't go too far */
+ if (delta.x > 0 && r.min.x + delta.x > dr.min.x)
+ delta.x = dr.min.x - r.min.x;
+ else if (delta.x < 0 && r.max.x + delta.x < dr.max.x)
+ delta.x = dr.max.x - r.max.x;
+ if (delta.y > 0 && r.min.y + delta.y > dr.min.y)
+ delta.y = dr.min.y - r.min.y;
+ else if (delta.y < 0 && r.max.y + delta.y < dr.max.y)
+ delta.y = dr.max.y - r.max.y;
+
+ m = &tk->env->top->ctxt->mstate;
+ item = xymenuitem(tk, m->x - delta.x, m->y - delta.y);
+ if (item == nil)
+ menuclr(tk);
+ else
+ activateitem(item);
+ tkmovewin(tk, Pt(tkw->req.x + delta.x, tkw->req.y + delta.y));
+ tkupdate(tk->env->top);
+ /* tkenterleave won't do this for us, so we have to do it ourselves */
+
+ tkw->speed += tkw->speed / 3;
+
+ r = rectaddpt(tkrect(tk, 1), Pt(tk->borderwidth + tkw->act.x, tk->borderwidth + tkw->act.y));
+ if((delta.y > 0 && r.min.x >= dr.min.x) || (delta.x < 0 && r.max.x <= dr.max.x))
+ tkw->delta.x = 0;
+ if((delta.y > 0 && r.min.y >= dr.min.y) || (delta.y < 0 && r.max.y <= dr.max.y))
+ tkw->delta.y = 0;
+ if (eqpt(tkw->delta, ZP)) {
+ tkcancelrepeat(tk);
+ tkw->speed = 0;
+ }
+}
+
+static void
+startautoscroll(Tk *tk, TkMouse *m)
+{
+ Rectangle dr, r;
+ Point d;
+ TkWin *tkw;
+ tkw = TKobj(TkWin, tk);
+ dr = tk->env->top->screenr;
+ r = rectaddpt(tkrect(tk, 1), Pt(tk->borderwidth + tkw->act.x, tk->borderwidth + tkw->act.y));
+ d = Pt(0, 0);
+ if(m->x <= 0 && r.min.x < dr.min.x)
+ d.x = 1;
+ else if (m->x >= dr.max.x - 1 && r.max.x >= dr.max.x)
+ d.x = -1;
+ if(m->y <= 0 && r.min.y < dr.min.y)
+ d.y = 1;
+ else if (m->y >= dr.max.y - 1 && r.max.y >= dr.max.y)
+ d.y = -1;
+//print("startautoscroll, delta %P\n", d);
+ if (d.x == 0 && d.y == 0){
+ if (tkw->speed > 0){
+ tkcancelrepeat(tk);
+ tkw->speed = 0;
+ }
+ return;
+ }
+ if (tkw->speed == 0) {
+ tkw->speed = TKI2F(Dy(r)) / 100;
+ tkrepeat(tk, autoscroll, nil, 0, TkRptinterval/2);
+ }
+ tkw->delta = d;
+}
+
+static void
+menuevent1(Tk *tk, int event, void *a)
+{
+ TkMouse *m;
+ Tk *item;
+
+ if (event & TkKey) {
+ menukey(tk, event & 0xffff);
+ return;
+ }
+
+ if (event & TkLeave) {
+ menuclr(tk);
+ return;
+ }
+
+ if ((!(event & TkEmouse) || (event & TkTakefocus)) && !(event & TkEnter))
+ return;
+
+ m = (TkMouse*)a;
+
+ startautoscroll(tk, m);
+
+ item = xymenuitem(tk, m->x, m->y);
+ if (item == nil)
+ menuclr(tk);
+ else
+ activateitem(item);
+ if ((event & (TkMotion|TkEnter)) && item == nil)
+ return;
+ if (event & TkEpress) {
+ if (item == nil) {
+ tkunmapmenus(tk->env->top, nil);
+ return;
+ }
+ if (item->type == TKcascade)
+ tkpostcascade(tk, item, !(event & TkMotion));
+ else
+ tkunmapmenus(tk->env->top, tk);
+ return;
+ }
+ if ((event & TkErelease) && m->b == 0) {
+ if (item != nil) {
+ if (item->type == TKcascade)
+ return;
+ if (!iteminvoke(tk, item, nil))
+ return;
+ }
+ tkunmapmenus(tk->env->top, nil);
+ }
+}
+
+static Tk*
+menuevent(Tk *tk, int event, void *a)
+{
+ menuevent1(tk, event, a);
+ tksubdeliver(tk, tk->binds, event, a, 0);
+ return nil;
+}
+
+static
+TkCmdtab menucmd[] =
+{
+ "activate", tkmenuactivate,
+ "add", tkmenuadd,
+ "cget", tkmenucget,
+ "configure", tkmenuconf,
+ "delete", tkmenudelete,
+ "entryconfigure", tkmenuentryconfig,
+ "entrycget", tkmenuentrycget,
+ "index", tkmenuindex,
+ "insert", tkmenuinsert,
+ "invoke", tkmenuinvoke,
+ "post", tkmenupost,
+ "postcascade", tkmenupostcascade,
+ "type", tkmenutype,
+ "unpost", tkmenuunpost,
+ "yposition", tkmenuyposn,
+ "suspend", tkmenususpend,
+ nil
+};
+
+static
+TkCmdtab menubutcmd[] =
+{
+ "cget", tkmenubutcget,
+ "configure", tkmenubutconf,
+ "tkMBenter", tkMBenter,
+ "tkMBleave", tkMBleave,
+ "tkMBpress", tkMBpress,
+ "tkMBkey", tkMBkey,
+ nil
+};
+
+static
+TkCmdtab choicebutcmd[] =
+{
+ "cget", tkmenubutcget,
+ "configure", tkmenubutconf,
+ "set", tkchoicebutset,
+ "get", tkchoicebutget,
+ "setvalue", tkchoicebutsetvalue,
+ "getvalue", tkchoicebutgetvalue,
+ "invoke", tkchoicebutinvoke,
+ "valuecount", tkchoicebutvaluecount,
+ "tkMBenter", tkMBenter,
+ "tkMBleave", tkMBleave,
+ "tkMBpress", tkMBpress,
+ "tkMBkey", tkMBkey,
+ "suspend", tkmenususpend,
+ nil
+};
+
+TkMethod menumethod = {
+ "menu",
+ menucmd,
+ freemenu,
+ drawmenu,
+ nil,
+ nil,
+ nil,
+ menudirty,
+ menurelpos,
+ menuevent
+};
+
+TkMethod menubuttonmethod = {
+ "menubutton",
+ menubutcmd,
+ tkfreelabel,
+ tkdrawlabel
+};
+
+TkMethod choicebuttonmethod = {
+ "choicebutton",
+ choicebutcmd,
+ tkfreelabel,
+ tkdrawlabel,
+ nil,
+ nil,
+ nil,
+ nil,
+ nil,
+ nil,
+ nil,
+ nil,
+ tkchoicevarchanged
+};
+
+TkMethod separatormethod = {
+ "separator",
+ nil,
+ tkfreeframe,
+ tkdrawframe
+};
+
+TkMethod cascademethod = {
+ "cascade",
+ nil,
+ tkfreelabel,
+ tkdrawlabel
+};
--- /dev/null
+++ b/libtk/mkfile
@@ -1,0 +1,27 @@
+<../mkconfig
+
+LIB=libtk.a
+
+OFILES=\
+ ebind.$O\
+ grids.$O\
+ image.$O\
+ packr.$O\
+ panel.$O\
+ parse.$O\
+ utils.$O\
+ varbl.$O\
+ windw.$O\
+ xdata.$O\
+
+HFILES=\
+ $ROOT/include/tk.h\
+ $ROOT/include/draw.h\
+
+default:V: all
+
+<mkfile-$TKSTYLE
+<$ROOT/mkfiles/mksyslib-$SHELLTYPE
+
+ebind.$O: $ROOT/include/interp.h
+windw.$O: canvs.h textw.h
--- /dev/null
+++ b/libtk/mkfile-std
@@ -1,0 +1,44 @@
+CANVSFILES=\
+ canvs.$O\
+ canvu.$O\
+ carcs.$O\
+ cbits.$O\
+ cimag.$O\
+ cline.$O\
+ coval.$O\
+ cpoly.$O\
+ crect.$O\
+ ctext.$O\
+ cwind.$O\
+
+LABELFILES=\
+ buton.$O\
+ label.$O\
+
+TEXTWFILES=\
+ textu.$O\
+ textw.$O\
+ tindx.$O\
+ tmark.$O\
+ ttags.$O\
+ twind.$O\
+
+OFILES=$OFILES\
+ $CANVSFILES\
+ colrs.$O\
+ entry.$O\
+ extns.$O\
+ frame.$O\
+ $LABELFILES\
+ listb.$O\
+ menus.$O\
+ scale.$O\
+ scrol.$O\
+ $TEXTWFILES\
+
+frame.$O: frame.h
+$CANVSFILES: canvs.h
+$LABELFILES: label.h
+listb.$O: listb.h
+menus.$O: frame.h label.h
+$TEXTWFILES: textw.h
--- /dev/null
+++ b/libtk/packr.c
@@ -1,0 +1,696 @@
+#include "lib9.h"
+#include "draw.h"
+#include "tk.h"
+
+#define O(t, e) ((long)(&((t*)0)->e))
+
+typedef struct Pack Pack;
+struct Pack
+{
+ Tk* t;
+ Pack* next;
+};
+static Pack *packorder;
+
+static int tkpacker(Tk *);
+
+typedef struct TkParam TkParam;
+struct TkParam
+{
+ Point pad;
+ Point ipad;
+ int side;
+ int anchor;
+ int fill;
+ Tk* in;
+ Tk* before;
+ Tk* after;
+ int expand;
+};
+
+TkParam defparam = {
+ {-1, -1}, /* p.pad */
+ {-1, -1}, /* p.ipad */
+ -1, /* side */
+ -1, /* anchor */
+ -1, /* fill */
+ nil, /* in */
+ nil, /* before */
+ nil, /* after */
+ BoolX /* expand */
+};
+
+static
+TkStab tkside[] =
+{
+ "top", Tktop,
+ "bottom", Tkbottom,
+ "left", Tkleft,
+ "right", Tkright,
+ nil
+};
+
+static
+TkStab tkfill[] =
+{
+ "none", 0,
+ "x", Tkfillx,
+ "y", Tkfilly,
+ "both", Tkfillx|Tkfilly,
+ nil
+};
+
+static
+TkOption opts[] =
+{
+ "padx", OPTnndist, O(TkParam, pad.x), nil,
+ "pady", OPTnndist, O(TkParam, pad.y), nil,
+ "ipadx", OPTnndist, O(TkParam, ipad.x), nil,
+ "ipady", OPTnndist, O(TkParam, ipad.y), nil,
+ "side", OPTstab, O(TkParam, side), tkside,
+ "anchor", OPTstab, O(TkParam, anchor), tkanchor,
+ "fill", OPTstab, O(TkParam, fill), tkfill,
+ "in", OPTwinp, O(TkParam, in), nil,
+ "before", OPTwinp, O(TkParam, before), nil,
+ "after", OPTwinp, O(TkParam, after), nil,
+ "expand", OPTstab, O(TkParam, expand), tkbool,
+ nil
+};
+
+void
+tkdelpack(Tk *t)
+{
+ Tk *f, **l, *sub, *p;
+
+ sub = tkfindsub(t);
+ if(sub != nil) {
+ p = sub->parent;
+ if(tkmethod[p->type]->forgetsub != nil)
+ tkmethod[p->type]->forgetsub(sub, t);
+ }
+
+ if(t->master == nil)
+ return;
+
+ if(t->master->grid != nil)
+ tkgriddelslave(t);
+
+ l = &t->master->slave;
+ for(f = *l; f; f = f->next) {
+ if(f == t) {
+ *l = t->next;
+ break;
+ }
+ l = &f->next;
+ }
+ t->master = nil;
+}
+
+void
+tkappendpack(Tk *parent, Tk *tk, int where)
+{
+ Tk *f, **l;
+
+ tk->master = parent;
+ l = &parent->slave;
+ for(f = *l; f; f = f->next) {
+ if(where-- == 0)
+ break;
+ l = &f->next;
+ }
+ *l = tk;
+ tk->next = f;
+
+ for( ; parent != nil; parent = parent->master)
+ if(parent->parent != nil){
+ tk->flag |= Tksubsub;
+ break;
+ }
+}
+
+static void
+tkpackqrm(Tk *t)
+{
+ Pack *f, **l;
+
+ l = &packorder;
+ for(f = *l; f; f = f->next) {
+ if(f->t == t) {
+ *l = f->next;
+ free(f);
+ break;
+ }
+ l = &f->next;
+ }
+}
+
+/* XXX - Tad: leaky... should propagate */
+void
+tkpackqit(Tk *t)
+{
+ Pack *f;
+
+ if(t == nil || (t->flag & Tkdestroy))
+ return;
+
+ tkpackqrm(t);
+ f = malloc(sizeof(Pack));
+ if(f == nil) {
+ print("tkpackqit: malloc failed\n");
+ return;
+ }
+
+ f->t = t;
+ f->next = packorder;
+ packorder = f;
+}
+
+void
+tkrunpack(TkTop *t)
+{
+ Tk *tk;
+ int done;
+
+ while(packorder != nil) {
+ tk = packorder->t;
+ if (tk->grid != nil)
+ done = tkgridder(tk);
+ else
+ done = tkpacker(tk);
+ if (done)
+ tkpackqrm(tk);
+ }
+ tkenterleave(t);
+ tkdirtyfocusorder(t);
+}
+
+static void
+tksetopt(TkParam *p, Tk *tk)
+{
+ if(p->pad.x != -1)
+ tk->pad.x = p->pad.x*2;
+ if(p->pad.y != -1)
+ tk->pad.y = p->pad.y*2;
+ if(p->ipad.x != -1)
+ tk->ipad.x = p->ipad.x*2;
+ if(p->ipad.y != -1)
+ tk->ipad.y = p->ipad.y*2;
+ if(p->side != -1) {
+ tk->flag &= ~Tkside;
+ tk->flag |= p->side;
+ }
+ if(p->anchor != -1) {
+ tk->flag &= ~Tkanchor;
+ tk->flag |= p->anchor;
+ }
+ if(p->fill != -1) {
+ tk->flag &= ~Tkfill;
+ tk->flag |= p->fill;
+ }
+ if(p->expand != BoolX) {
+ if(p->expand == BoolT) {
+ tk->flag |= Tkexpand;
+ }
+ else
+ tk->flag &= ~Tkexpand;
+ }
+}
+
+static char*
+tkforget(TkTop *t, char *arg)
+{
+ Tk *tk;
+ char *buf;
+
+ buf = mallocz(Tkmaxitem, 0);
+ if(buf == nil)
+ return TkNomem;
+ for(;;) {
+ arg = tkword(t, arg, buf, buf+Tkmaxitem, nil);
+ if(buf[0] == '\0')
+ break;
+ tk = tklook(t, buf, 0);
+ if(tk == nil) {
+ tkrunpack(t);
+ tkerr(t, buf);
+ free(buf);
+ return TkBadwp;
+ }
+ tkpackqit(tk->master);
+ tkdelpack(tk);
+ }
+ free(buf);
+ tkrunpack(t);
+ return nil;
+}
+
+char*
+tkpropagate(TkTop *t, char *arg)
+{
+ Tk *tk;
+ TkStab *s;
+ char *buf;
+
+ buf = mallocz(Tkmaxitem, 0);
+ if(buf == nil)
+ return TkNomem;
+ arg = tkword(t, arg, buf, buf+Tkmaxitem, nil);
+ tk = tklook(t, buf, 0);
+ if(tk == nil) {
+ tkerr(t, buf);
+ free(buf);
+ return TkBadwp;
+ }
+
+ tkword(t, arg, buf, buf+Tkmaxitem, nil);
+ for(s = tkbool; s->val; s++) {
+ if(strcmp(s->val, buf) == 0) {
+ if(s->con == BoolT) {
+ tk->flag &= ~Tknoprop;
+ tkpackqit(tk);
+ tkrunpack(t);
+ } else
+ tk->flag |= Tknoprop;
+ free(buf);
+ return nil;
+ }
+ }
+ free(buf);
+ return TkBadvl;
+}
+
+static char*
+tkslaves(TkTop *t, char *arg, char **val)
+{
+ Tk *tk;
+ char *fmt, *e, *buf;
+
+ buf = mallocz(Tkmaxitem, 0);
+ if(buf == nil)
+ return TkNomem;
+ tkword(t, arg, buf, buf+Tkmaxitem, nil);
+ tk = tklook(t, buf, 0);
+ if(tk == nil){
+ tkerr(t, buf);
+ free(buf);
+ return TkBadwp;
+ }
+ free(buf);
+
+ fmt = "%s";
+ for(tk = tk->slave; tk; tk = tk->next) {
+ if (tk->name != nil) {
+ e = tkvalue(val, fmt, tk->name->name);
+ if(e != nil)
+ return e;
+ fmt = " %s";
+ }
+ }
+
+ return nil;
+}
+
+int
+tkisslave(Tk *in, Tk *tk)
+{
+ if(in == nil)
+ return 0;
+ if(in == tk)
+ return 1;
+ for(tk = tk->slave; tk; tk = tk->next)
+ if(tkisslave(in, tk))
+ return 1;
+ return 0;
+}
+
+static char*
+tkcanpack(Tk *tk, Tk *parent)
+{
+ if(tkisslave(parent, tk))
+ return TkRecur;
+ if (parent->grid != nil) {
+ if (parent->slave != nil)
+ return TkIsgrid;
+ tkfreegrid(parent->grid);
+ parent->grid = nil;
+ }
+ return nil;
+}
+
+char*
+tkpack(TkTop *t, char *arg, char **val)
+{
+ TkParam param = defparam;
+ TkParam *p = ¶m;
+ TkOptab tko[2];
+ Tk *tk, **l, *tkp;
+ TkName *names, *n;
+ char *e, *w, *buf;
+
+ buf = mallocz(Tkminitem, 0);
+ if(buf == nil)
+ return TkNomem;
+
+ w = tkword(t, arg, buf, buf+Tkminitem, nil);
+ if(strcmp(buf, "forget") == 0) {
+ e = tkforget(t, w);
+ free(buf);
+ return e;
+ }
+ if(strcmp(buf, "propagate") == 0) {
+ e = tkpropagate(t, w);
+ free(buf);
+ return e;
+ }
+ if(strcmp(buf, "slaves") == 0) {
+ e = tkslaves(t, w, val);
+ free(buf);
+ return e;
+ }
+ free(buf);
+
+ tko[0].ptr = p;
+ tko[0].optab = opts;
+ tko[1].ptr = nil;
+
+ names = nil;
+ e = tkparse(t, arg, tko, &names);
+ if(e != nil)
+ return e;
+
+ if((p->before && p->before->master == nil) ||
+ (p->after && p->after->master == nil)) {
+ tkfreename(names);
+ return TkNotpk;
+ }
+
+ for(n = names; n; n = n->link) {
+ tkp = tklook(t, n->name, 0);
+ if(tkp == nil) {
+ tkerr(t, n->name);
+ tkfreename(names);
+ return TkBadwp;
+ }
+ if(tkp->flag & Tkwindow) {
+ tkfreename(names);
+ return TkIstop;
+ }
+ if(tkp->parent != nil) {
+ tkfreename(names);
+ return TkWpack;
+ }
+ n->obj = tkp;
+ }
+
+ e = nil;
+ for(n = names; n; n = n->link) {
+ tk = n->obj;
+ if(tk->master == nil) {
+ tk->pad = ZP;
+ tk->ipad = ZP;
+ tk->flag &= ~(Tkanchor|Tkside|Tkfill|Tkexpand);
+ tk->flag |= Tktop;
+ }
+ if(tk->master != nil) {
+ tkpackqit(tk->master);
+ tkdelpack(tk);
+ }
+ if(p->before == nil && p->after == nil && p->in == nil) {
+ tkp = tklook(t, n->name, 1);
+ if(tkp == nil) {
+ e = TkBadwp;
+ tkerr(t, n->name);
+ goto Error;
+ }
+ e = tkcanpack(tk, tkp);
+ if (e != nil)
+ goto Error;
+ tkappendpack(tkp, tk, -1);
+ }
+ else {
+ if(p->in != nil) {
+ e = tkcanpack(tk, p->in);
+ if(e != nil)
+ goto Error;
+ tkappendpack(p->in, tk, -1);
+ }
+ else
+ if(p->before != nil) {
+ e = tkcanpack(tk, p->before->master);
+ if (e != nil)
+ goto Error;
+ tk->master = p->before->master;
+ l = &tk->master->slave;
+ for(;;) {
+ if(*l == p->before) {
+ tk->next = *l;
+ *l = tk;
+ break;
+ }
+ l = &(*l)->next;
+ }
+ p->before = tk;
+ }
+ else {
+ e = tkcanpack(tk, p->after->master);
+ if (e != nil)
+ goto Error;
+ tk->master = p->after->master;
+ tk->next = p->after->next;
+ p->after->next = tk;
+ p->after = tk;
+ }
+ }
+ tksetopt(p, tk);
+ if (tk->master->flag&Tksubsub)
+ tksetbits(tk, Tksubsub);
+ tkpackqit(tk->master);
+ }
+
+Error:
+ tkfreename(names);
+ tkrunpack(t);
+
+ return e;
+}
+
+void
+tksetslavereq(Tk *slave, TkGeom frame)
+{
+ Point border;
+ TkGeom pos, old;
+ int slave2BW;
+ void (*geomfn)(Tk*);
+
+ border.x = slave->pad.x;
+ border.y = slave->pad.y;
+
+ slave2BW = slave->borderwidth * 2;
+
+ pos.width = slave->req.width + slave2BW + slave->ipad.x;
+ if((slave->flag&Tkfillx) || (pos.width > (frame.width - border.x)))
+ pos.width = frame.width - border.x;
+
+ pos.height = slave->req.height + slave2BW + slave->ipad.y;
+ if((slave->flag&Tkfilly) || (pos.height > (frame.height - border.y)))
+ pos.height = frame.height - border.y;
+
+ border.x /= 2;
+ border.y /= 2;
+
+ if(slave->flag & Tknorth)
+ pos.y = frame.y + border.y;
+ else
+ if(slave->flag & Tksouth)
+ pos.y = frame.y + frame.height - pos.height - border.y;
+ else
+ pos.y = frame.y + (frame.height - pos.height)/2;
+
+ if(slave->flag & Tkwest)
+ pos.x = frame.x + border.x;
+ else
+ if(slave->flag & Tkeast)
+ pos.x = frame.x + frame.width - pos.width - border.x;
+ else
+ pos.x = frame.x + (frame.width - pos.width)/2;
+
+ pos.width -= slave2BW;
+ pos.height -= slave2BW;
+
+ if(memcmp(&slave->act, &pos, sizeof(TkGeom)) != 0) {
+ old = slave->act;
+ slave->act = pos;
+ geomfn = tkmethod[slave->type]->geom;
+ if(geomfn != nil)
+ geomfn(slave);
+ if(slave->slave)
+ tkpackqit(slave);
+ tkdeliver(slave, TkConfigure, &old);
+
+ slave->dirty = tkrect(slave, 1);
+ slave->flag |= Tkrefresh;
+ }
+}
+static int
+tkexpandx(Tk* slave, int cavityWidth)
+{
+ int numExpand, minExpand, curExpand, childWidth;
+
+ minExpand = cavityWidth;
+ numExpand = 0;
+ for( ;slave != nil; slave = slave->next) {
+ childWidth = slave->req.width + slave->borderwidth*2 +
+ slave->pad.x + slave->ipad.x;
+ if(slave->flag & (Tktop|Tkbottom)) {
+ curExpand = (cavityWidth - childWidth)/numExpand;
+ if (curExpand < minExpand)
+ minExpand = curExpand;
+ }
+ else {
+ cavityWidth -= childWidth;
+ if(slave->flag & Tkexpand)
+ numExpand++;
+ }
+ }
+ curExpand = cavityWidth/numExpand;
+ if(curExpand < minExpand)
+ minExpand = curExpand;
+
+ return (minExpand < 0) ? 0 : minExpand;
+}
+
+static int
+tkexpandy(Tk *slave, int cavityHeight)
+{
+ int numExpand, minExpand, curExpand, childHeight;
+
+ minExpand = cavityHeight;
+ numExpand = 0;
+ for ( ;slave != nil; slave = slave->next) {
+ childHeight = slave->req.height + slave->borderwidth*2 +
+ + slave->pad.y + slave->ipad.y;
+ if(slave->flag & (Tkleft|Tkright)) {
+ curExpand = (cavityHeight - childHeight)/numExpand;
+ if(curExpand < minExpand)
+ minExpand = curExpand;
+ }
+ else {
+ cavityHeight -= childHeight;
+ if(slave->flag & Tkexpand)
+ numExpand++;
+ }
+ }
+ curExpand = cavityHeight/numExpand;
+ if(curExpand < minExpand)
+ minExpand = curExpand;
+
+ return (minExpand < 0) ? 0 : minExpand;
+}
+
+static int
+tkpacker(Tk *master)
+{
+ Tk *slave;
+ TkGeom frame, cavity, pos;
+ int maxwidth, maxheight, tmp, slave2BW;
+
+ pos.width = 0;
+ pos.height = 0;
+ maxwidth = 0;
+ maxheight = 0;
+
+ master->flag |= Tkrefresh;
+
+ for (slave = master->slave; slave != nil; slave = slave->next) {
+ slave2BW = slave->borderwidth*2;
+ if(slave->flag & (Tktop|Tkbottom)) {
+ tmp = slave->req.width + slave2BW +
+ slave->pad.x + slave->ipad.x + pos.width;
+ if(tmp > maxwidth)
+ maxwidth = tmp;
+ pos.height += slave->req.height + slave2BW +
+ slave->pad.y + slave->ipad.y;
+ }
+ else {
+ tmp = slave->req.height + slave2BW +
+ slave->pad.y + slave->ipad.y + pos.height;
+ if(tmp > maxheight)
+ maxheight = tmp;
+ pos.width += slave->req.width + slave2BW +
+ + slave->pad.x + slave->ipad.x;
+ }
+ }
+ if(pos.width > maxwidth)
+ maxwidth = pos.width;
+ if(pos.height > maxheight)
+ maxheight = pos.height;
+
+ if(maxwidth != master->req.width || maxheight != master->req.height)
+ if((master->flag & Tknoprop) == 0) {
+ if(master->geom != nil) {
+ master->geom(master, master->act.x, master->act.y,
+ maxwidth, maxheight);
+ } else {
+ master->req.width = maxwidth;
+ master->req.height = maxheight;
+ tkpackqit(master->master);
+ }
+ return 0;
+ }
+
+ cavity.x = 0;
+ cavity.y = 0;
+ pos.x = 0;
+ pos.y = 0;
+ cavity.width = master->act.width;
+ cavity.height = master->act.height;
+
+ for(slave = master->slave; slave != nil; slave = slave->next) {
+ slave2BW = slave->borderwidth*2;
+ if(slave->flag & (Tktop|Tkbottom)) {
+ frame.width = cavity.width;
+ frame.height = slave->req.height + slave2BW +
+ slave->pad.y + slave->ipad.y;
+ if(slave->flag & Tkexpand)
+ frame.height += tkexpandy(slave, cavity.height);
+ cavity.height -= frame.height;
+ if(cavity.height < 0) {
+ frame.height += cavity.height;
+ cavity.height = 0;
+ }
+ frame.x = cavity.x;
+ if(slave->flag & Tktop) {
+ frame.y = cavity.y;
+ cavity.y += frame.height;
+ }
+ else
+ frame.y = cavity.y + cavity.height;
+ }
+ else {
+ frame.height = cavity.height;
+ frame.width = slave->req.width + slave2BW +
+ slave->pad.x + slave->ipad.x;
+ if(slave->flag & Tkexpand)
+ frame.width += tkexpandx(slave, cavity.width);
+ cavity.width -= frame.width;
+ if(cavity.width < 0) {
+ frame.width += cavity.width;
+ cavity.width = 0;
+ }
+ frame.y = cavity.y;
+ if(slave->flag & Tkleft) {
+ frame.x = cavity.x;
+ cavity.x += frame.width;
+ }
+ else
+ frame.x = cavity.x + cavity.width;
+ }
+
+ tksetslavereq(slave, frame);
+ }
+
+ master->dirty = tkrect(master, 1);
+ tkdirty(master);
+ return 1;
+}
+
--- /dev/null
+++ b/libtk/panel.c
@@ -1,0 +1,408 @@
+#include "lib9.h"
+#include "draw.h"
+#include "tk.h"
+
+#define O(t, e) ((long)(&((t*)0)->e))
+
+typedef struct TkPanel TkPanel;
+struct TkPanel
+{
+ Image* image;
+ Image* matte;
+ Point view; /* vector from image origin to widget origin */
+ Rectangle r; /* drawn rectangle (in image coords) */
+ int anchor;
+ int hasalpha; /* does the image include an alpha channel? */
+};
+
+static TkOption tkpanelopts[] =
+{
+ "anchor", OPTflag, O(TkPanel, anchor), tkanchor,
+ nil
+};
+
+static int
+tkdrawnrect(Image *image, Image *matte, Rectangle *r)
+{
+ *r = image->clipr;
+ if (matte != nil) {
+ if (!rectclip(r, matte->clipr))
+ return 0;
+ if (!matte->repl && !rectclip(r, matte->r))
+ return 0;
+ }
+ if (!image->repl && !rectclip(r, image->r))
+ return 0;
+ return 1;
+}
+
+char*
+tkpanel(TkTop *t, char *arg, char **ret)
+{
+ TkOptab tko[3];
+ Tk *tk;
+ TkPanel *tkp;
+ TkName *names;
+ char *e;
+
+ tk = tknewobj(t, TKpanel, sizeof(Tk)+sizeof(TkPanel));
+ if(tk == nil)
+ return TkNomem;
+
+ tkp = TKobj(TkPanel, tk);
+ tkp->anchor = Tkcenter;
+
+ tko[0].ptr = tk;
+ tko[0].optab = tkgeneric;
+ tko[1].ptr = tkp;
+ tko[1].optab = tkpanelopts;
+ tko[2].ptr = nil;
+ names = nil;
+
+ e = tkparse(t, arg, tko, &names);
+ if(e != nil) {
+ tkfreeobj(tk);
+ return e;
+ }
+
+ tksettransparent(tk, tkhasalpha(tk->env, TkCbackgnd));
+
+ e = tkaddchild(t, tk, &names);
+
+ tkfreename(names);
+ if (e != nil) {
+ tkfreeobj(tk);
+ return e;
+ }
+
+ tk->name->link = nil;
+ return tkvalue(ret, "%s", tk->name->name);
+}
+
+void
+tkgetpanelimage(Tk *tk, Image **i, Image **m)
+{
+ TkPanel *tkp = TKobj(TkPanel, tk);
+ *i = tkp->image;
+ *m = tkp->matte;
+}
+
+void
+tksetpanelimage(Tk *tk, Image *image, Image *matte)
+{
+ TkPanel *tkp = TKobj(TkPanel, tk);
+ int ishuge;
+ TkGeom g;
+
+ g = tk->req;
+
+ tkp->image = image;
+ tkp->matte = matte;
+
+ if (!tkdrawnrect(image, matte, &tkp->r)) {
+ tkp->r.min = image->r.min;
+ tkp->r.max = image->r.min;
+ }
+
+ tkp->view = tkp->r.min; /* XXX do we actually want to keep the old one? */
+ /*
+ * if both image and matte are replicated, then we've got no idea what
+ * the rectangle should be, so request zero size, and set origin to (0, 0).
+ */
+ ishuge = (Dx(tkp->r) >= 10000000);
+ if((tk->flag & Tksetwidth) == 0){
+ if(ishuge)
+ tk->req.width = 0;
+ else
+ tk->req.width = Dx(tkp->r);
+ }
+ if(ishuge)
+ tkp->view.x = 0;
+
+ ishuge = (Dy(tkp->r) >= 10000000);
+ if((tk->flag & Tksetheight) == 0){
+ if(ishuge)
+ tk->req.height = 0;
+ else
+ tk->req.height = Dy(tkp->r);
+ }
+ if(ishuge)
+ tkp->view.y = 0;
+
+ tkp->hasalpha = tkchanhastype(image->chan, CAlpha);
+ tkgeomchg(tk, &g, tk->borderwidth);
+ tksettransparent(tk, tkp->hasalpha || tkhasalpha(tk->env, TkCbackgnd));
+ tk->dirty = tkrect(tk, 0);
+}
+
+static void
+tkfreepanel(Tk *tk)
+{
+ TkPanel *tkp = TKobj(TkPanel, tk);
+ tkdelpanelimage(tk->env->top, tkp->image);
+ tkdelpanelimage(tk->env->top, tkp->matte);
+}
+
+static Point
+tkpanelview(Tk *tk)
+{
+ int dx, dy;
+ Point view;
+ TkPanel *tkp = TKobj(TkPanel, tk);
+
+ dx = tk->act.width - Dx(tkp->r);
+ dy = tk->act.height - Dy(tkp->r);
+
+ view = tkp->view;
+
+ if (dx > 0) {
+ if((tkp->anchor & (Tkeast|Tkwest)) == 0)
+ view.x -= dx/2;
+ else
+ if(tkp->anchor & Tkeast)
+ view.x -= dx;
+ }
+ if (dy > 0) {
+ if((tkp->anchor & (Tknorth|Tksouth)) == 0)
+ view.y -= dy/2;
+ else
+ if(tkp->anchor & Tksouth)
+ view.y -= dy;
+ }
+ return view;
+}
+
+static char*
+tkdrawpanel(Tk *tk, Point orig)
+{
+ Rectangle r, pr;
+ TkPanel *tkp = TKobj(TkPanel, tk);
+ Image *i;
+ int any;
+ Point view, p;
+
+ i = tkimageof(tk);
+ if (i == nil)
+ return nil;
+
+ p.x = orig.x + tk->act.x + tk->borderwidth;
+ p.y = orig.y + tk->act.y + tk->borderwidth;
+
+ view = tkpanelview(tk);
+
+ /*
+ * if the image doesn't fully cover the dirty rectangle, then
+ * paint some background in there
+ */
+ r = rectsubpt(tkp->r, view); /* convert to widget coords */
+ pr = tkrect(tk, 0);
+ any = rectclip(&r, pr); /* clip to inside widget borders */
+
+ if (!any || tkp->hasalpha || !rectinrect(tk->dirty, r))
+ draw(i, rectaddpt(tk->dirty, p), tkgc(tk->env, TkCbackgnd), nil, ZP);
+
+ if (any && rectclip(&r, tk->dirty))
+ draw(i, rectaddpt(r, p), tkp->image, tkp->matte, addpt(r.min, view));
+
+ if (!rectinrect(tk->dirty, pr)) {
+ p.x -= tk->borderwidth;
+ p.y -= tk->borderwidth;
+ tkdrawrelief(i, tk, p, TkCbackgnd, tk->relief);
+ }
+ return nil;
+}
+
+static char*
+tkpanelcget(Tk *tk, char *arg, char **val)
+{
+ TkOptab tko[3];
+ TkPanel *tkp = TKobj(TkPanel, tk);
+
+ tko[0].ptr = tk;
+ tko[0].optab = tkgeneric;
+ tko[1].ptr = tkp;
+ tko[1].optab = tkpanelopts;
+ tko[2].ptr = nil;
+
+ return tkgencget(tko, arg, val, tk->env->top);
+}
+
+static char*
+tkpanelcvt(Tk *tk, char *arg, int rel, int *p)
+{
+ char buf[Tkmaxitem];
+
+ tkword(tk->env->top, arg, buf, buf+sizeof(buf), nil);
+ if(buf[0] == '\0')
+ return TkBadvl;
+ *p = atoi(buf) + rel;
+ return nil;
+}
+
+/*
+ * screen to image
+ */
+static char*
+tkpanelpanelx(Tk *tk, char *arg, char **val)
+{
+ Point p;
+ char *e;
+
+ USED(val);
+ p = subpt(tkposn(tk), tkpanelview(tk));
+ e = tkpanelcvt(tk, arg, -p.x, &p.x);
+ if (e != nil)
+ return e;
+ return tkvalue(val, "%d", p.x);
+}
+
+static char*
+tkpanelpanely(Tk *tk, char *arg, char **val)
+{
+ Point p;
+ char *e;
+
+ USED(val);
+ p = subpt(tkposn(tk), tkpanelview(tk));
+ e = tkpanelcvt(tk, arg, -p.y, &p.y);
+ if (e != nil)
+ return e;
+ return tkvalue(val, "%d", p.y);
+}
+
+/*
+ * image to screen
+ */
+static char*
+tkpanelscreenx(Tk *tk, char *arg, char **val)
+{
+ Point p;
+ char *e;
+
+ USED(val);
+ p = subpt(tkposn(tk), tkpanelview(tk));
+ e = tkpanelcvt(tk, arg, p.x, &p.x);
+ if (e != nil)
+ return e;
+ return tkvalue(val, "%d", p.x);
+}
+
+static char*
+tkpanelscreeny(Tk *tk, char *arg, char **val)
+{
+ Point p;
+ char *e;
+
+ USED(val);
+ p = subpt(tkposn(tk), tkpanelview(tk));
+ e = tkpanelcvt(tk, arg, p.y, &p.y);
+ if (e != nil)
+ return e;
+ return tkvalue(val, "%d", p.y);
+}
+
+static char*
+tkpanelconf(Tk *tk, char *arg, char **val)
+{
+ char *e;
+ TkGeom g;
+ int bd;
+ TkOptab tko[3];
+ TkPanel *tkp = TKobj(TkPanel, tk);
+
+ tko[0].ptr = tk;
+ tko[0].optab = tkgeneric;
+ tko[1].ptr = tkp;
+ tko[1].optab = tkpanelopts;
+ tko[2].ptr = nil;
+
+ if(*arg == '\0')
+ return tkconflist(tko, val);
+
+ g = tk->req;
+ bd = tk->borderwidth;
+ e = tkparse(tk->env->top, arg, tko, nil);
+ tkgeomchg(tk, &g, bd);
+ tksettransparent(tk, tkp->hasalpha || tkhasalpha(tk->env, TkCbackgnd));
+
+ tk->dirty = tkrect(tk, 1);
+
+ return e;
+}
+
+static char*
+tkpaneldirty(Tk *tk, char *arg, char **val)
+{
+ char buf[Tkmaxitem];
+ int n, coords[4];
+ Rectangle r;
+ char *e, *p;
+ TkPanel *tkp = TKobj(TkPanel, tk);
+
+ USED(val);
+ n = 0;
+ while (n < 4) {
+ arg = tkword(tk->env->top, arg, buf, buf+sizeof(buf), nil);
+ if (buf[0] == 0)
+ break;
+ p = buf;
+ e = tkfrac(&p, &coords[n++], nil);
+ if (e != nil)
+ return TkBadvl;
+ }
+ if (n == 0)
+ r = tkp->r;
+ else {
+ if (n != 4)
+ return TkBadvl;
+ r.min.x = TKF2I(coords[0]);
+ r.min.y = TKF2I(coords[1]);
+ r.max.x = TKF2I(coords[2]);
+ r.max.y = TKF2I(coords[3]);
+ }
+ if (rectclip(&r, tkp->r)) {
+ r = rectsubpt(r, tkpanelview(tk)); /* convert to widget coords */
+ if (rectclip(&r, tkrect(tk, 0))) /* clip to visible area */
+ combinerect(&tk->dirty, r);
+ }
+ return nil;
+}
+
+static char*
+tkpanelorigin(Tk *tk, char *arg, char **val)
+{
+ char *e;
+ Point view;
+ TkPanel *tkp = TKobj(TkPanel, tk);
+
+ e = tkxyparse(tk, &arg, &view);
+ if (e != nil) {
+ if (e == TkOparg)
+ return tkvalue(val, "%d %d", tkp->view.x, tkp->view.y);
+ return e;
+ }
+ tkp->view = view;
+ tk->dirty = tkrect(tk, 0);
+ return nil;
+}
+
+static
+TkCmdtab tkpanelcmd[] =
+{
+ "cget", tkpanelcget,
+ "configure", tkpanelconf,
+ "dirty", tkpaneldirty,
+ "origin", tkpanelorigin,
+ "panelx", tkpanelpanelx,
+ "panely", tkpanelpanely,
+ "screenx", tkpanelscreenx,
+ "screeny", tkpanelscreeny,
+ nil
+};
+
+TkMethod panelmethod = {
+ "panel",
+ tkpanelcmd,
+ tkfreepanel,
+ tkdrawpanel
+};
--- /dev/null
+++ b/libtk/parse.c
@@ -1,0 +1,1195 @@
+#include "lib9.h"
+#include "kernel.h"
+#include "draw.h"
+#include "tk.h"
+
+#define O(t, e) ((long)(&((t*)0)->e))
+
+static char* pdist(TkTop*, TkOption*, void*, char**, char*, char*);
+static char* pstab(TkTop*, TkOption*, void*, char**, char*, char*);
+static char* ptext(TkTop*, TkOption*, void*, char**, char*, char*);
+static char* pwinp(TkTop*, TkOption*, void*, char**, char*, char*);
+static char* pbmap(TkTop*, TkOption*, void*, char**, char*, char*);
+static char* pbool(TkTop*, TkOption*, void*, char**, char*, char*);
+static char* pfont(TkTop*, TkOption*, void*, char**, char*, char*);
+static char* pfrac(TkTop*, TkOption*, void*, char**, char*, char*);
+static char* pnnfrac(TkTop*, TkOption*, void*, char**, char*, char*);
+static char* pctag(TkTop*, TkOption*, void*, char**, char*, char*);
+static char* ptabs(TkTop*, TkOption*, void*, char**, char*, char*);
+static char* pcolr(TkTop*, TkOption*, void*, char**, char*, char*);
+static char* pimag(TkTop*, TkOption*, void*, char**, char*, char*);
+static char* psize(TkTop*, TkOption*, void*, char**, char*, char*);
+static char* pnndist(TkTop*, TkOption*, void*, char**, char*, char*);
+static char* pact(TkTop*, TkOption*, void*, char**, char*, char*);
+static char* pignore(TkTop*, TkOption*, void*, char**, char*, char*);
+static char* psticky(TkTop*, TkOption*, void*, char**, char*, char*);
+static char* plist(TkTop*, TkOption*, void*, char**, char*, char*);
+
+static char* (*oparse[])(TkTop*, TkOption*, void*, char**, char*, char*) =
+{
+ /* OPTdist */ pdist,
+ /* OPTstab */ pstab,
+ /* OPTtext */ ptext,
+ /* OPTwinp */ pwinp,
+ /* OPTflag */ pstab,
+ /* OPTbmap */ pbmap,
+ /* OPTbool */ pbool,
+ /* OPTfont */ pfont,
+ /* OPTfrac */ pfrac,
+ /* OPTnnfrac */ pnnfrac,
+ /* OPTctag */ pctag,
+ /* OPTtabs */ ptabs,
+ /* OPTcolr */ pcolr,
+ /* OPTimag */ pimag,
+ /* OPTsize */ psize,
+ /* OPTnndist */ pnndist,
+ /* OPTact */ pact,
+ /* OPTignore */ pignore,
+ /* OPTsticky */ psticky,
+ /* OPTlist */ plist,
+ /* OPTflags */ pstab,
+};
+
+char*
+tkskip(char *s, char *bl)
+{
+ char *p;
+
+ while(*s) {
+ for(p = bl; *p; p++)
+ if(*p == *s)
+ break;
+ if(*p == '\0')
+ return s;
+ s++;
+ }
+ return s;
+}
+
+/* XXX - Tad: error propagation? */
+char*
+tkword(TkTop *t, char *str, char *buf, char *ebuf, int *gotarg)
+{
+ int c, lev, tmp;
+ char *val, *e, *p, *cmd;
+ if (gotarg == nil)
+ gotarg = &tmp;
+
+ /*
+ * ebuf is one beyond last byte in buf; leave room for nul byte in
+ * all cases.
+ */
+ --ebuf;
+
+ str = tkskip(str, " \t");
+ *gotarg = 1;
+ lev = 1;
+ switch(*str) {
+ case '{':
+ /* XXX - DBK: According to Ousterhout (p.37), while back=
+ * slashed braces don't count toward finding the matching
+ * closing braces, the backslashes should not be removed.
+ * Presumably this also applies to other backslashed
+ * characters: the backslash should not be removed.
+ */
+ str++;
+ while(*str && buf < ebuf) {
+ c = *str++;
+ if(c == '\\') {
+ if(*str == '}' || *str == '{' || *str == '\\')
+ c = *str++;
+ } else if(c == '}') {
+ lev--;
+ if(lev == 0)
+ break;
+ } else if(c == '{')
+ lev++;
+ *buf++ = c;
+ }
+ break;
+ case '[':
+ /* XXX - DBK: According to Ousterhout (p. 33) command
+ * substitution may occur anywhere within a word, not
+ * only (as here) at the beginning.
+ */
+ cmd = malloc(strlen(str)); /* not strlen+1 because the first character is skipped */
+ if ( cmd == nil ) {
+ buf[0] = '\0'; /* DBK - Why not an error message? */
+ return str;
+ }
+ p = cmd;
+ str++;
+ while(*str) {
+ c = *str++;
+ if(c == '\\') {
+ if(*str == ']' || *str == '[' || *str == '\\')
+ c = *str++;
+ } else if(c == ']') {
+ lev--;
+ if(lev == 0)
+ break;
+ } else if(c == '[')
+ lev++;
+ *p++ = c;
+ }
+ *p = '\0';
+ val = nil;
+ e = tkexec(t, cmd, &val);
+ free(cmd);
+ /* XXX - Tad: is this appropriate behavior?
+ * Am I sure that the error doesn't need to be
+ * propagated back to the caller?
+ */
+ if(e == nil && val != nil) {
+ strncpy(buf, val, ebuf-buf);
+ buf = ebuf;
+ free(val);
+ }
+ break;
+ case '\'':
+ str++;
+ while(*str && buf < ebuf)
+ *buf++ = *str++;
+ break;
+ case '\0':
+ *gotarg = 0;
+ break;
+ default:
+ /* XXX - DBK: See comment above about command substitution.
+ * Also, any backslashed character should be replaced by
+ * itself (e.g. to put a space, tab, or [ into a word.
+ * We assume that the C compiler has already done the
+ * standard ANSI C substitutions. (But should we?)
+ */
+ while(*str && *str != ' ' && *str != '\t' && buf < ebuf)
+ *buf++ = *str++;
+ }
+ *buf = '\0';
+ return str;
+}
+
+static TkOption*
+Getopt(TkOption *o, char *buf)
+{
+ while(o->o != nil) {
+ if(strcmp(buf, o->o) == 0)
+ return o;
+ o++;
+ }
+ return nil;
+}
+
+TkName*
+tkmkname(char *name)
+{
+ TkName *n;
+
+ n = malloc(sizeof(struct TkName)+strlen(name));
+ if(n == nil)
+ return nil;
+ strcpy(n->name, name);
+ n->link = nil;
+ n->obj = nil;
+ return n;
+}
+
+char*
+tkparse(TkTop *t, char *str, TkOptab *ot, TkName **nl)
+{
+ int l;
+ TkOptab *ft;
+ TkOption *o;
+ TkName *f, *n;
+ char *e, *buf, *ebuf;
+
+ l = strlen(str);
+ if (l < Tkmaxitem)
+ l = Tkmaxitem;
+ buf = malloc(l + 1);
+ if(buf == 0)
+ return TkNomem;
+ ebuf = buf + l + 1;
+
+ e = nil;
+ while(e == nil) {
+ str = tkword(t, str, buf, ebuf, nil);
+ switch(*buf) {
+ case '\0':
+ goto done;
+ case '-':
+ if (buf[1] != '\0') {
+ for(ft = ot; ft->ptr; ft++) {
+ o = Getopt(ft->optab, buf+1);
+ if(o != nil) {
+ e = oparse[o->type](t, o, ft->ptr, &str, buf, ebuf);
+ break;
+ }
+ }
+ if(ft->ptr == nil){
+ e = TkBadop;
+ tkerr(t, buf);
+ }
+ break;
+ }
+ /* fall through if we've got a singleton '-' */
+ default:
+ if(nl == nil) {
+ e = TkBadop;
+ tkerr(t, buf);
+ break;
+ }
+ n = tkmkname(buf);
+ if(n == nil) {
+ e = TkNomem;
+ break;
+ }
+ if(*nl == nil)
+ *nl = n;
+ else {
+ for(f = *nl; f->link; f = f->link)
+ ;
+ f->link = n;
+ }
+ }
+ }
+
+ if(e != nil && nl != nil)
+ tkfreename(*nl);
+done:
+ free(buf);
+ return e;
+}
+
+char*
+tkconflist(TkOptab *ot, char **val)
+{
+ TkOption *o;
+ char *f, *e;
+
+ f = "-%s";
+ while(ot->ptr != nil) {
+ o = ot->optab;
+ while(o->o != nil) {
+ e = tkvalue(val, f, o->o);
+ if(e != nil)
+ return e;
+ f = " -%s";
+ o++;
+ }
+ ot++;
+ }
+ return nil;
+}
+
+char*
+tkgencget(TkOptab *ft, char *arg, char **val, TkTop *t)
+{
+ Tk *w;
+ char *c;
+ Point g;
+ TkEnv *e;
+ TkStab *s;
+ TkOption *o;
+ int wh, con, i, n, flag, *v;
+ char *r, *buf, *fmt, *out;
+
+ buf = mallocz(Tkmaxitem, 0);
+ if(buf == nil)
+ return TkNomem;
+
+ tkitem(buf, arg);
+ r = buf;
+ if(*r == '-')
+ r++;
+ o = nil;
+ while(ft->ptr) {
+ o = Getopt(ft->optab, r);
+ if(o != nil)
+ break;
+ ft++;
+ }
+ if(o == nil) {
+ tkerr(t, r);
+ free(buf);
+ return TkBadop;
+ }
+
+ switch(o->type) {
+ default:
+ tkerr(t, r);
+ free(buf);
+ return TkBadop;
+ case OPTignore:
+ return nil;
+ case OPTact:
+ w = ft->ptr;
+ g = tkposn(w);
+ n = g.y;
+ if(o->aux == 0)
+ n = g.x;
+ free(buf);
+ return tkvalue(val, "%d", n);
+ case OPTdist:
+ case OPTnndist:
+ free(buf);
+ return tkvalue(val, "%d", OPTION(ft->ptr, int, o->offset));
+ case OPTsize:
+ w = ft->ptr;
+ if(strcmp(r, "width") == 0)
+ wh = w->req.width;
+ else
+ wh = w->req.height;
+ free(buf);
+ return tkvalue(val, "%d", wh);
+ case OPTtext:
+ c = OPTION(ft->ptr, char*, o->offset);
+ if(c == nil)
+ c = "";
+ free(buf);
+ return tkvalue(val, "%s", c);
+ case OPTwinp:
+ w = OPTION(ft->ptr, Tk*, o->offset);
+ if(w == nil || w->name == nil)
+ c = "";
+ else
+ c = w->name->name;
+ free(buf);
+ return tkvalue(val, "%s", c);
+ case OPTstab:
+ s = o->aux;
+ c = "";
+ con = OPTION(ft->ptr, int, o->offset);
+ while(s->val) {
+ if(con == s->con) {
+ c = s->val;
+ break;
+ }
+ s++;
+ }
+ free(buf);
+ return tkvalue(val, "%s", c);
+ case OPTflag:
+ con = OPTION(ft->ptr, int, o->offset);
+ flag = 0;
+ for (s = o->aux; s->val != nil; s++)
+ flag |= s->con;
+ c = "";
+ for (s = o->aux; s->val != nil; s++) {
+ if ((con & flag) == s->con) {
+ c = s->val;
+ break;
+ }
+ }
+ free(buf);
+ return tkvalue(val, "%s", c);
+ case OPTflags:
+ con = OPTION(ft->ptr, int, o->offset);
+ out = mallocz(Tkmaxitem, 0);
+ if(out == nil) {
+ free(buf);
+ return TkNomem;
+ }
+ c = out;
+ for (s = o->aux; s->val != nil; s++) {
+ if (s->con == (s->con&-s->con) && (con & s->con) != 0)
+ c = seprint(c, out+Tkmaxitem, " %s", s->val); /* should this be quoted? */
+ }
+ free(buf);
+ *c = 0;
+ r = tkvalue(val, "%s", out);
+ free(out);
+ return r;
+ case OPTfont:
+ e = OPTION(ft->ptr, TkEnv*, o->offset);
+ free(buf);
+ if (e->font != nil)
+ return tkvalue(val, "%s", e->font->name);
+ return nil;
+ case OPTcolr:
+ e = OPTION(ft->ptr, TkEnv*, o->offset);
+ i = AUXI(o->aux);
+ free(buf);
+ return tkvalue(val, "#%.8lux", e->colors[i]);
+ case OPTfrac:
+ case OPTnnfrac:
+ v = &OPTION(ft->ptr, int, o->offset);
+ n = (int)o->aux;
+ if(n == 0)
+ n = 1;
+ fmt = "%s";
+ for(i = 0; i < n; i++) {
+ tkfprint(buf, *v++);
+ r = tkvalue(val, fmt, buf);
+ if(r != nil) {
+ free(buf);
+ return r;
+ }
+ fmt = " %s";
+ }
+ free(buf);
+ return nil;
+ case OPTbmap:
+ //free(buf);
+ return tkvalue(val, "%d", OPTION(ft->ptr, Image*, o->offset) != nil);
+ case OPTimag:
+ //free(buf);
+ return tkvalue(val, "%d", OPTION(ft->ptr, TkImg*, o->offset) != nil);
+ }
+}
+
+static char*
+pact(TkTop *t, TkOption *o, void *place, char **str, char *buf, char *ebuf)
+{
+ USED(buf);
+ USED(ebuf);
+ USED(str);
+ USED(place);
+ tkerr(t, o->o);
+ return TkBadop;
+}
+
+static char*
+pignore(TkTop *t, TkOption *o, void *place, char **str, char *buf, char *ebuf)
+{
+ char *p;
+ USED(t);
+ USED(o);
+ USED(place);
+
+ p = tkword(t, *str, buf, ebuf, nil);
+ if(*buf == '\0')
+ return TkOparg;
+ *str = p;
+ return nil;
+}
+
+static char*
+pdist(TkTop *t, TkOption *o, void *place, char **str, char *buf, char *ebuf)
+{
+ int d;
+ char *e;
+ TkEnv *env;
+
+ USED(buf);
+ USED(ebuf);
+
+ /*
+ * this is a bit of a hack, as 0 is a valid option offset,
+ * but a nil aux is commonly used when 'w' and 'h' suffixes
+ * aren't appropriate.
+ * just make sure that no structure placed in TkOptab->ptr
+ * with an OPTdist element has a TkEnv as its first member.
+ */
+
+ if (o->aux == nil)
+ env = nil;
+ else
+ env = OPTION(place, TkEnv*, AUXI(o->aux));
+ e = tkfracword(t, str, &d, env);
+ if(e != nil)
+ return e;
+ OPTION(place, int, o->offset) = TKF2I(d);
+ return nil;
+}
+
+static char*
+pnndist(TkTop *t, TkOption *o, void *place, char **str, char *buf, char *ebuf)
+{
+ char* e;
+ int oldv;
+
+ oldv = OPTION(place, int, o->offset);
+ e = pdist(t, o, place, str, buf, ebuf);
+ if(e == nil && OPTION(place, int, o->offset) < 0) {
+ OPTION(place, int, o->offset) = oldv;
+ return TkBadvl;
+ }
+ return e;
+}
+
+static char*
+psize(TkTop *t, TkOption *o, void *place, char **str, char *buf, char *ebuf)
+{
+ Tk *tk;
+ char *e;
+ int d, off;
+
+ USED(ebuf);
+ e = tkfracword(t, str, &d, OPTION(place, TkEnv*, AUXI(o->aux)));
+ if (e != nil)
+ return e;
+ if(d < 0)
+ return TkBadvl;
+
+ tk = place;
+ /*
+ * XXX there's no way of resetting Tksetwidth or Tksetheight.
+ * could perhaps allow it by setting width/height to {}
+ */
+ if(strcmp(buf+1, "width") == 0) {
+ tk->flag |= Tksetwidth;
+ off = O(Tk, req.width);
+ }
+ else {
+ tk->flag |= Tksetheight;
+ off = O(Tk, req.height);
+ }
+ OPTION(place, int, off) = TKF2I(d);
+ return nil;
+}
+
+static TkStab*
+lookstab(TkStab *s, char *word)
+{
+ for(; s->val != nil; s++)
+ if(strcmp(s->val, word) == 0)
+ return s;
+ return nil;
+}
+
+static char*
+pstab(TkTop *t, TkOption *o, void *place, char **str, char *buf, char *ebuf)
+{
+ char *p, *fields[8];
+ int mask, val, nf;
+ TkStab *s, *c;
+
+ p = tkword(t, *str, buf, ebuf, nil);
+ if(*buf == '\0')
+ return TkOparg;
+
+ if(o->type == OPTstab) {
+ s = lookstab(o->aux, buf);
+ if(s == nil)
+ return TkBadvl;
+ *str = p;
+ OPTION(place, int, o->offset) = s->con;
+ return nil;
+ }
+
+ nf = getfields(buf, fields, nelem(fields), 1, " \t,");
+ if(nf < 1 || nf > 1 && o->type != OPTflags)
+ return TkBadvl;
+
+ mask = 0;
+ for(c = o->aux; c->val; c++)
+ mask |= c->con;
+
+ val = 0;
+ while(--nf >= 0) {
+ s = lookstab(o->aux, fields[nf]);
+ if(s == nil)
+ return TkBadvl;
+ val |= s->con;
+ }
+ *str = p;
+
+ OPTION(place, int, o->offset) &= ~mask;
+ OPTION(place, int, o->offset) |= val;
+
+ /*
+ * a hack, but otherwise we have to dirty the focus order
+ * every time any command is executed on a widget
+ */
+ if(strcmp(o->o, "takefocus") == 0)
+ tkdirtyfocusorder(t);
+ return nil;
+}
+
+enum {
+ Stickyn = (1<<0),
+ Stickye = (1<<1),
+ Stickys = (1<<2),
+ Stickyw = (1<<3)
+};
+
+static int stickymap[16] =
+{
+ 0,
+ Tknorth,
+ Tkeast,
+ Tknorth|Tkeast,
+ Tksouth,
+ Tkfilly,
+ Tksouth|Tkeast,
+ Tkeast|Tkfilly,
+ Tkwest,
+ Tknorth|Tkwest,
+ Tkfillx,
+ Tknorth|Tkfillx,
+ Tksouth|Tkwest,
+ Tkwest|Tkfilly,
+ Tksouth|Tkfillx,
+ Tkfillx|Tkfilly,
+};
+
+static char*
+psticky(TkTop *t, TkOption *o, void *place, char **str, char *buf, char *ebuf)
+{
+ char *p, *s;
+ int flag, sflag;
+
+ p = tkword(t, *str, buf, ebuf, nil);
+ *str = p;
+
+ flag = 0;
+ for (s = buf; *s; s++) {
+ switch (*s) {
+ case 'n':
+ flag |= Stickyn;
+ break;
+ case 's':
+ flag |= Stickys;
+ break;
+ case 'e':
+ flag |= Stickye;
+ break;
+ case 'w':
+ flag |= Stickyw;
+ break;
+ case ' ':
+ case ',':
+ break;
+ default:
+ return TkBadvl;
+ }
+ }
+ sflag = OPTION(place, int, o->offset) & ~(Tkanchor|Tkfill);
+ OPTION(place, int, o->offset) = sflag | stickymap[flag];
+ return nil;
+}
+
+static char*
+ptext(TkTop *t, TkOption *o, void *place, char **str, char *buf, char *ebuf)
+{
+ char **p;
+
+ *str = tkword(t, *str, buf, ebuf, nil);
+
+ p = &OPTION(place, char*, o->offset);
+ if(*p != nil)
+ free(*p);
+ if(buf[0] == '\0')
+ *p = nil;
+ else {
+ *p = strdup(buf);
+ if(*p == nil)
+ return TkNomem;
+ }
+ return nil;
+}
+
+static char*
+pimag(TkTop *t, TkOption *o, void *place, char **str, char *buf, char *ebuf)
+{
+ int locked;
+ Display *d;
+ TkImg **p, *i;
+
+ i = nil;
+ p = &OPTION(place, TkImg*, o->offset);
+ *str = tkword(t, *str, buf, ebuf, nil);
+ if(*buf != '\0') {
+ i = tkname2img(t, buf);
+ if(i == nil)
+ return TkBadvl;
+ i->ref++;
+ }
+
+ if(*p != nil) {
+ d = t->display;
+ locked = lockdisplay(d);
+ tkimgput(*p);
+ if(locked)
+ unlockdisplay(d);
+ }
+ *p = i;
+ return nil;
+}
+
+static char*
+pbmap(TkTop *t, TkOption *o, void *place, char **str, char *buf, char *ebuf)
+{
+ Display *d;
+ Image *i, **p;
+ int locked, fd;
+ char *c;
+
+ p = &OPTION(place, Image*, o->offset);
+
+ d = t->display;
+ *str = tkword(t, *str, buf, ebuf, nil);
+ if(*buf == '\0' || *buf == '-') {
+ if(*p != nil) {
+ locked = lockdisplay(d);
+ freeimage(*p);
+ if(locked)
+ unlockdisplay(d);
+ *p = nil;
+ }
+ return nil;
+ }
+
+ if(buf[0] == '@')
+ i = display_open(d, buf+1);
+ else if(buf[0] == '<') {
+ buf++;
+ fd = strtoul(buf, &c, 0);
+ if(c == buf) {
+ return TkBadvl;
+ }
+ i = readimage(d, fd, 1);
+ }
+ else {
+ char *file;
+
+ file = mallocz(Tkmaxitem, 0);
+ if(file == nil)
+ return TkNomem;
+
+ snprint(file, Tkmaxitem, "/icons/tk/%s", buf);
+ i = display_open(d, file);
+ free(file);
+ }
+ if(i == nil)
+ return TkBadbm;
+
+ if(*p != nil) {
+ locked = lockdisplay(d);
+ freeimage(*p);
+ if(locked)
+ unlockdisplay(d);
+ }
+ *p = i;
+ return nil;
+}
+
+static char*
+pfont(TkTop *t, TkOption *o, void *place, char **str, char *buf, char *ebuf)
+{
+ TkEnv *e;
+ Display *d;
+ int locked;
+ Font *font;
+
+ *str = tkword(t, *str, buf, ebuf, nil);
+ if(*buf == '\0')
+ return TkOparg;
+
+ d = t->display;
+ font = font_open(d, buf);
+ if(font == nil)
+ return TkBadft;
+
+ e = tkdupenv(&OPTION(place, TkEnv*, o->offset));
+ if(e == nil) {
+ freefont(font); /* XXX lockdisplay around this? */
+ return TkNomem;
+ }
+ if(e->font)
+ font_close(e->font);
+ e->font = font;
+
+ locked = lockdisplay(d);
+ e->wzero = stringwidth(font, "0");
+ if ( e->wzero <= 0 )
+ e->wzero = e->font->height / 2;
+ if(locked)
+ unlockdisplay(d);
+
+ return nil;
+}
+
+static int
+hex(int c)
+{
+ if(c >= 'a')
+ c -= 'a'-'A';
+ if(c >= 'A')
+ c = 10 + (c - 'A');
+ else
+ c -= '0';
+ return c;
+}
+
+static ulong
+changecol(TkEnv *e, int setcol, int col, ulong rgba)
+{
+ if (setcol) {
+ e->set |= (1<<col);
+ } else {
+ rgba = 0;
+ e->set &= ~(1<<col);
+ }
+ e->colors[col] = rgba;
+ return rgba;
+}
+
+char*
+tkparsecolor(char *buf, ulong *rgba)
+{
+ char *p, *q, *e;
+ int R, G, B, A;
+ int i, alpha, len, alen;
+ /*
+ * look for alpha modifier in *#AA or *0.5 format
+ */
+ len = strlen(buf);
+ p = strchr(buf, '*');
+ if(p != nil) {
+ alen = len - (p - buf);
+ if(p[1] == '#') {
+ if(alen != 4)
+ return TkBadvl;
+ alpha = (hex(p[2])<<4) | (hex(p[3]));
+ } else {
+ q = p+1;
+ e = tkfrac(&q, &alpha, nil);
+ if (e != nil)
+ return e;
+ alpha = TKF2I(alpha * 0xff);
+ }
+ *p = '\0';
+ len -= alen;
+ } else
+ alpha = 0xff;
+
+ if (*buf == '#') {
+ switch(len) {
+ case 4: /* #RGB */
+ R = hex(buf[1]);
+ G = hex(buf[2]);
+ B = hex(buf[3]);
+ *rgba = (R<<28) | (G<<20) | (B<<12) | 0xff;
+ break;
+ case 7: /* #RRGGBB */
+ R = (hex(buf[1])<<4)|(hex(buf[2]));
+ G = (hex(buf[3])<<4)|(hex(buf[4]));
+ B = (hex(buf[5])<<4)|(hex(buf[6]));
+ *rgba = (R<<24) | (G<<16) | (B<<8) | 0xff;
+ break;
+ case 9: /* #RRGGBBAA */
+ R = (hex(buf[1])<<4)|(hex(buf[2]));
+ G = (hex(buf[3])<<4)|(hex(buf[4]));
+ B = (hex(buf[5])<<4)|(hex(buf[6]));
+ A = (hex(buf[7])<<4)|(hex(buf[8]));
+ *rgba = (R<<24) | (G<<16) | (B<<8) | A;
+ break;
+ default:
+ return TkBadvl;
+ }
+ } else {
+ for(i = 0; tkcolortab[i].val != nil; i++)
+ if (!strcmp(tkcolortab[i].val, buf))
+ break;
+ if (tkcolortab[i].val == nil)
+ return TkBadvl;
+ *rgba = tkcolortab[i].con;
+ }
+ if (alpha != 0xff) {
+ tkrgbavals(*rgba, &R, &G, &B, &A);
+ A = (A * alpha) / 255;
+ *rgba = tkrgba(R, G, B, A);
+ }
+ return nil;
+}
+
+static char*
+pcolr(TkTop *t, TkOption *o, void *place, char **str, char *buf, char *ebuf)
+{
+ TkEnv *env;
+ char *e;
+ ulong rgba, dark, light;
+ int color, setcol;
+
+ *str = tkword(t, *str, buf, ebuf, nil);
+ rgba = 0;
+ if(*buf == '\0') {
+ setcol = 0;
+ } else {
+ setcol = 1;
+ e = tkparsecolor(buf, &rgba);
+ if(e != nil)
+ return e;
+ }
+
+ env = tkdupenv(&OPTION(place, TkEnv*, o->offset));
+ if(env == nil)
+ return TkNomem;
+
+ color = AUXI(o->aux);
+ rgba = changecol(env, setcol, color, rgba);
+ if(color == TkCbackgnd || color == TkCselectbgnd || color == TkCactivebgnd) {
+ if (setcol) {
+ light = tkrgbashade(rgba, TkLightshade);
+ dark = tkrgbashade(rgba, TkDarkshade);
+ } else
+ light = dark = 0;
+ changecol(env, setcol, color+1, light);
+ changecol(env, setcol, color+2, dark);
+ }
+ return nil;
+}
+
+static char*
+pbool(TkTop *t, TkOption *o, void *place, char **str, char *buf, char *ebuf)
+{
+ USED(buf);
+ USED(ebuf);
+ USED(str);
+ USED(t);
+ OPTION(place, int, o->offset) = 1;
+ return nil;
+}
+
+static char*
+pwinp(TkTop *t, TkOption *o, void *place, char **str, char *buf, char *ebuf)
+{
+ Tk *f;
+ char *p;
+
+ p = tkword(t, *str, buf, ebuf, nil);
+ if(*buf == '\0')
+ return TkOparg;
+ *str = p;
+
+ f = tklook(t, buf, 0);
+ if(f == nil){
+ tkerr(t, buf);
+ return TkBadwp;
+ }
+
+ OPTION(place, Tk*, o->offset) = f;
+ return nil;
+}
+
+static char*
+pctag(TkTop *t, TkOption *o, void *place, char **str, char *buf, char *ebuf)
+{
+ char *p;
+ TkName *n, *l;
+
+ *str = tkword(t, *str, buf, ebuf, nil);
+
+ l = nil;
+ p = buf;
+ while(*p) {
+ p = tkskip(p, " \t");
+ buf = p;
+ while(*p && *p != ' ' && *p != '\t')
+ p++;
+ if(*p != '\0')
+ *p++ = '\0';
+
+ if(p == buf || buf[0] >= '0' && buf[0] <= '9') {
+ tkfreename(l);
+ return TkBadtg;
+ }
+ n = tkmkname(buf);
+ if(n == nil) {
+ tkfreename(l);
+ return TkNomem;
+ }
+ n->link = l;
+ l = n;
+ }
+ tkfreename(OPTION(place, TkName*, o->offset));
+ OPTION(place, TkName*, o->offset) = l;
+ return nil;
+}
+
+static char*
+pfrac(TkTop *t, TkOption *o, void *place, char **str, char *buf, char *ebuf)
+{
+ char *p, *e;
+ int i, n, d, *v;
+
+ *str = tkword(t, *str, buf, ebuf, nil);
+
+ v = &OPTION(place, int, o->offset);
+ n = (int)o->aux;
+ if(n == 0)
+ n = 1;
+ p = buf;
+ for(i = 0; i < n; i++) {
+ p = tkskip(p, " \t");
+ if(*p == '\0')
+ return TkOparg;
+ e = tkfracword(t, &p, &d, nil);
+ if (e != nil)
+ return e;
+ *v++ = d;
+ }
+ return nil;
+}
+
+/*
+ * N.B. nnfrac only accepts aux==nil (can't deal with several items)
+ */
+static char*
+pnnfrac(TkTop *t, TkOption *o, void *place, char **str, char *buf, char *ebuf)
+{
+ int oldv;
+ char *e;
+
+ oldv = OPTION(place, int, o->offset);
+
+ e = pfrac(t, o, place, str, buf, ebuf);
+ if(e == nil && OPTION(place, int, o->offset) < 0) {
+ OPTION(place, int, o->offset) = oldv;
+ return TkBadvl;
+ }
+ return e;
+
+}
+
+typedef struct Tabspec {
+ int dist;
+ int just;
+ TkEnv *env;
+} Tabspec;
+
+static char*
+ptabs(TkTop *t, TkOption *o, void *place, char **str, char *buf, char *ebuf)
+{
+ char *e, *p, *eibuf;
+ TkOption opd, opj;
+ Tabspec tspec;
+ TkTtabstop *tabfirst, *tab, *tabprev;
+ char *ibuf;
+
+ ibuf = mallocz(Tkmaxitem, 0);
+ if(ibuf == nil)
+ return TkNomem;
+ eibuf = ibuf + Tkmaxitem;
+ tspec.env = OPTION(place, TkEnv*, AUXI(o->aux));
+ opd.offset = O(Tabspec, dist);
+ opd.aux = IAUX(O(Tabspec, env));
+ opj.offset = O(Tabspec, dist);
+ opj.aux = tktabjust;
+ tabprev = nil;
+ tabfirst = nil;
+
+ p = tkword(t, *str, buf, ebuf, nil);
+ if(*buf == '\0') {
+ free(ibuf);
+ return TkOparg;
+ }
+ *str = p;
+
+ p = buf;
+ while(*p != '\0') {
+ e = pdist(t, &opd, &tspec, &p, ibuf, eibuf);
+ if(e != nil) {
+ free(ibuf);
+ return e;
+ }
+
+ e = pstab(t, &opj, &tspec, &p, ibuf, eibuf);
+ if(e != nil)
+ tspec.just = Tkleft;
+
+ tab = malloc(sizeof(TkTtabstop));
+ if(tab == nil) {
+ free(ibuf);
+ return TkNomem;
+ }
+
+ tab->pos = tspec.dist;
+ tab->justify = tspec.just;
+ tab->next = nil;
+ if(tabfirst == nil)
+ tabfirst = tab;
+ else
+ tabprev->next = tab;
+ tabprev = tab;
+ }
+ free(ibuf);
+
+ tab = OPTION(place, TkTtabstop*, o->offset);
+ if(tab != nil)
+ free(tab);
+ OPTION(place, TkTtabstop*, o->offset) = tabfirst;
+ return nil;
+}
+
+char*
+tkxyparse(Tk* tk, char **parg, Point *p)
+{
+ char *buf;
+
+ buf = mallocz(Tkmaxitem, 0);
+ if(buf == nil)
+ return TkNomem;
+
+ *parg = tkword(tk->env->top, *parg, buf, buf+Tkmaxitem, nil);
+ if(*buf == '\0') {
+ free(buf);
+ return TkOparg;
+ }
+ p->x = atoi(buf);
+
+ *parg = tkword(tk->env->top, *parg, buf, buf+Tkmaxitem, nil);
+ if(*buf == '\0') {
+ free(buf);
+ return TkOparg;
+ }
+ p->y = atoi(buf);
+
+ free(buf);
+ return nil;
+}
+
+static char*
+plist(TkTop *t, TkOption *o, void *place, char **str, char *buf, char *ebuf)
+{
+ char *w, ***p, *wbuf, *ewbuf, **v, **nv;
+ int n, m, i, found;
+
+ *str = tkword(t, *str, buf, ebuf, nil);
+ n = strlen(buf) + 1;
+ wbuf = mallocz(n, 0);
+ if (wbuf == nil)
+ return TkNomem; /* XXX should we free old values too? */
+ ewbuf = &wbuf[n];
+
+ p = &OPTION(place, char**, o->offset);
+ if (*p != nil){
+ for (v = *p; *v; v++)
+ free(*v);
+ free(*p);
+ }
+ n = 0;
+ m = 4;
+ w = buf;
+ v = malloc(m * sizeof(char*));
+ if (v == nil)
+ goto Error;
+ for (;;) {
+ w = tkword(t, w, wbuf, ewbuf, &found);
+ if (!found)
+ break;
+ if (n == m - 1) {
+ m += m/2;
+ nv = realloc(v, m * sizeof(char*));
+ if (nv == nil)
+ goto Error;
+ v = nv;
+ }
+ v[n] = strdup(wbuf);
+ if (v[n] == nil)
+ goto Error;
+ n++;
+ }
+ v[n++] = nil;
+ *p = realloc(v, n * sizeof(char*));
+ free(wbuf);
+ return nil;
+Error:
+ free(buf);
+ for (i = 0; i < n; i++)
+ free(v[i]);
+ free(v);
+ *p = nil;
+ return TkNomem;
+}
--- /dev/null
+++ b/libtk/radio.tk
@@ -1,0 +1,4 @@
+radiobutton .u -text {Upper case} -variable case -value u
+radiobutton .l -text {Lower case} -variable case -value l
+radiobutton .i -text {Ignore case} -variable case -value i
+pack .u .l .i -anchor w -fill x
--- /dev/null
+++ b/libtk/scale.c
@@ -1,0 +1,963 @@
+#include <lib9.h>
+#include <kernel.h>
+#include "draw.h"
+#include "tk.h"
+#include "keyboard.h"
+
+#define O(t, e) ((long)(&((t*)0)->e))
+
+typedef struct TkScale TkScale;
+struct TkScale
+{
+ int value;
+ int bigi;
+ int digits;
+ int digwidth;
+ int from; /* Base of range */
+ int to; /* Limit of range */
+ int len; /* Length of groove */
+ int res; /* Resolution */
+ int sv; /* Show value */
+ int sl; /* Slider length */
+ int sw; /* Slider width div 2 */
+ int relief;
+ int tick;
+ int orient;
+ char* command;
+ char* label;
+ int pixmin;
+ int pixmax;
+ int pixpos;
+ int center;
+ int pix;
+ int base;
+ int flag;
+ int jump;
+};
+
+enum {
+ Dragging = (1<<0),
+ Autorepeat = (1<<1),
+};
+
+static
+TkOption opts[] =
+{
+ "bigincrement", OPTnnfrac, O(TkScale, bigi), nil,
+ "digits", OPTdist, O(TkScale, digits), nil,
+ "from", OPTfrac, O(TkScale, from), nil,
+ "to", OPTfrac, O(TkScale, to), nil,
+ "length", OPTdist, O(TkScale, len), nil,
+ "resolution", OPTnnfrac, O(TkScale, res), nil,
+ "showrange", OPTignore, 0, nil,
+ "showvalue", OPTstab, O(TkScale, sv), tkbool,
+ "jump", OPTstab, O(TkScale, jump), tkbool,
+ "sliderlength", OPTdist, O(TkScale, sl), nil,
+ "sliderrelief", OPTstab, O(TkScale, relief), tkrelief,
+ "tickinterval", OPTfrac, O(TkScale, tick), nil,
+ "tick", OPTfrac, O(TkScale, tick), nil,
+ "label", OPTtext, O(TkScale, label), nil,
+ "command", OPTtext, O(TkScale, command), nil,
+ "orient", OPTstab, O(TkScale, orient), tkorient,
+ nil
+};
+
+static char trough1[] = "trough1";
+static char trough2[] = "trough2";
+static char slider[] = "slider";
+
+static
+TkEbind b[] =
+{
+ {TkMotion, "%W tkScaleMotion %x %y"},
+ {TkButton1P|TkMotion, "%W tkScaleDrag %x %y"},
+ {TkButton1P, "%W tkScaleMotion %x %y; %W tkScaleBut1P %x %y"},
+ {TkButton1P|TkDouble, "%W tkScaleMotion %x %y; %W tkScaleBut1P %x %y"},
+ {TkButton1R, "%W tkScaleDrag %x %y; %W tkScaleBut1R; %W tkScaleMotion %x %y"},
+ {TkKey, "%W tkScaleKey 0x%K"},
+};
+
+enum
+{
+ Scalewidth = 18,
+ ScalePad = 2,
+ ScaleBW = 1,
+ ScaleSlider = 16,
+ ScaleLen = 80,
+
+};
+
+static int
+maximum(int a, int b)
+{
+ if (a > b)
+ return a;
+ return b;
+}
+
+void
+tksizescale(Tk *tk)
+{
+ Point p;
+ char buf[32];
+ TkScale *tks;
+ int fh, w, h, digits, digits2;
+
+ tks = TKobj(TkScale, tk);
+
+ digits = tks->digits;
+ if(digits <= 0) {
+ digits = tkfprint(buf, tks->from) - buf;
+ digits2 = tkfprint(buf, tks->to) - buf;
+ digits = maximum(digits, digits2);
+ if (tks->res > 0) {
+ digits2 = tkfprint(buf, tks->from + tks->res) - buf;
+ digits = maximum(digits, digits2);
+ digits2 = tkfprint(buf, tks->to - tks->res) - buf;
+ digits = maximum(digits, digits2);
+ }
+ }
+
+ digits *= tk->env->wzero;
+ if(tks->sv != BoolT)
+ digits = 0;
+
+ tks->digwidth = digits;
+
+ p = tkstringsize(tk, tks->label);
+ if(tks->orient == Tkvertical) {
+ h = tks->len + 2*ScaleBW + 2*ScalePad;
+ w = Scalewidth + 2*ScalePad + 2*ScaleBW;
+ if (p.x)
+ w += p.x + ScalePad;
+ if (tks->sv == BoolT)
+ w += digits + ScalePad;
+ } else {
+ w = maximum(p.x, tks->len + ScaleBW + 2*ScalePad);
+ h = Scalewidth + 2*ScalePad + 2*ScaleBW;
+ fh = tk->env->font->height;
+ if(tks->label != nil)
+ h += fh + ScalePad;
+ if(tks->sv == BoolT)
+ h += fh + ScalePad;
+ }
+ w += 2*tk->highlightwidth;
+ h += 2*tk->highlightwidth;
+ if(!(tk->flag & Tksetwidth))
+ tk->req.width = w;
+ if(!(tk->flag & Tksetheight))
+ tk->req.height = h;
+}
+
+static int
+tkscalecheckvalue(Tk *tk)
+{
+ int v;
+ TkScale *tks = TKobj(TkScale, tk);
+ int limit = 1;
+
+ v = tks->value;
+ if (tks->res > 0)
+ v = (v / tks->res) * tks->res;
+ if (tks->to >= tks->from) {
+ if (v < tks->from)
+ v = tks->from;
+ else if (v > tks->to)
+ v = tks->to;
+ else
+ limit = 0;
+ } else {
+ if (v < tks->to)
+ v = tks->to;
+ else if (v > tks->from)
+ v = tks->from;
+ else
+ limit = 0;
+ }
+ /*
+ * it's possible for the value to end up as a non-whole
+ * multiple of resolution here, if the end points aren't
+ * themselves such a multiple. if so, tough - that's
+ * what you asked for! (it does mean that the endpoints
+ * are always accessible however, which could be a good thing).
+ */
+ tks->value = v;
+ return limit;
+}
+
+char*
+tkscale(TkTop *t, char *arg, char **ret)
+{
+ Tk *tk;
+ char *e;
+ TkName *names;
+ TkScale *tks;
+ TkOptab tko[3];
+
+ tk = tknewobj(t, TKscale, sizeof(Tk)+sizeof(TkScale));
+ if(tk == nil)
+ return TkNomem;
+
+ tk->flag |= Tktakefocus;
+ tks = TKobj(TkScale, tk);
+ tks->res = TKI2F(1);
+ tks->to = TKI2F(100);
+ tks->len = ScaleLen;
+ tks->orient = Tkvertical;
+ tks->relief = TKraised;
+ tks->sl = ScaleSlider;
+ tks->sv = BoolT;
+ tks->bigi = 0;
+
+ tko[0].ptr = tk;
+ tko[0].optab = tkgeneric;
+ tko[1].ptr = tks;
+ tko[1].optab = opts;
+ tko[2].ptr = nil;
+
+ names = nil;
+ e = tkparse(t, arg, tko, &names);
+ if(e != nil) {
+ tkfreeobj(tk);
+ return e;
+ }
+ tksettransparent(tk, tkhasalpha(tk->env, TkCbackgnd));
+ tkscalecheckvalue(tk);
+ tksizescale(tk);
+ if (tks->bigi == 0)
+ tks->bigi = TKI2F(TKF2I(tks->to - tks->from) / 10);
+ e = tkbindings(t, tk, b, nelem(b));
+
+ if(e != nil) {
+ tkfreeobj(tk);
+ return e;
+ }
+
+ e = tkaddchild(t, tk, &names);
+ tkfreename(names);
+ if(e != nil) {
+ tkfreeobj(tk);
+ return e;
+ }
+ tk->name->link = nil;
+
+ return tkvalue(ret, "%s", tk->name->name);
+}
+
+static char*
+tkscalecget(Tk *tk, char *arg, char **val)
+{
+ TkOptab tko[3];
+ TkScale *tks = TKobj(TkScale, tk);
+
+ tko[0].ptr = tk;
+ tko[0].optab = tkgeneric;
+ tko[1].ptr = tks;
+ tko[1].optab = opts;
+ tko[2].ptr = nil;
+
+ return tkgencget(tko, arg, val, tk->env->top);
+}
+
+void
+tkfreescale(Tk *tk)
+{
+ TkScale *tks = TKobj(TkScale, tk);
+
+ if(tks->command != nil)
+ free(tks->command);
+ if(tks->label != nil)
+ free(tks->label);
+}
+
+static void
+tkscalehoriz(Tk *tk, Image *i)
+{
+ TkEnv *e;
+ char sv[32];
+ TkScale *tks;
+ Image *d, *l;
+ Rectangle r, r2, sr;
+ Point p, q;
+ int fh, sh, gh, sl, v, w, h, len;
+ int fgnd;
+
+ e = tk->env;
+ tks = TKobj(TkScale, tk);
+
+
+ fh = e->font->height;
+ fgnd = TkCforegnd;
+ if (tk->flag & Tkdisabled)
+ fgnd = TkCdisablefgnd;
+
+ r = Rect(0, 0, tk->act.width, tk->act.height);
+ r = rectaddpt(r, Pt(tk->borderwidth, tk->borderwidth));
+ r = insetrect(r, tk->highlightwidth);
+ r = insetrect(r, ScalePad);
+
+ if(tks->label != nil) {
+ string(i, r.min, tkgc(e, fgnd), ZP, e->font, tks->label);
+ r.min.y += fh + ScalePad;
+ }
+ if(tks->sv == BoolT)
+ r.min.y += fh + ScalePad;
+
+ sr = insetrect(r, ScaleBW);
+ w = Dx(sr);
+ h = Dy(sr);
+ sl = tks->sl + 2*ScaleBW;
+
+ l = tkgc(e, TkCbackgndlght);
+ d = tkgc(e, TkCbackgnddark);
+ tkbevel(i, r.min, w, h, ScaleBW, d, l);
+
+ tks->pixmin = sr.min.x;
+ tks->pixmax = sr.max.x;
+
+ sh = h - 2*ScaleBW;
+ tks->sw = sh/2;
+
+ w -= sl;
+ if (w <= 0)
+ w = 1;
+ p.x = sr.min.x;
+ p.y = sr.max.y;
+ if(tks->tick > 0){
+ int j, t, l;
+ t = tks->tick;
+ l = tks->to-tks->from;
+ if (l < 0)
+ l = -l;
+ if (l == 0)
+ l = 1;
+ r2.min.y = p.y;
+ r2.max.y = p.y + ScaleBW + ScalePad;
+ for(j = 0; j <= l; j += t){
+ r2.min.x = p.x+((vlong)j*w)/l+sl/2;
+ r2.max.x = r2.min.x+1;
+ draw(i, r2, tkgc(e, fgnd), nil, ZP);
+ }
+ }
+ v = tks->value-tks->from;
+ len = tks->to-tks->from;
+ if (len != 0)
+ p.x += ((vlong)v*w)/len;
+ p.y = sr.min.y;
+ q = p;
+ q.x += tks->sl/2 + 1;
+ if(ScaleBW > 1) {
+ gh = sh;
+ q.y++;
+ } else
+ gh = sh-1;
+ if(tk->flag & Tkactivated) {
+ r2.min = p;
+ r2.max.x = p.x+sl;
+ r2.max.y = sr.max.y;
+ draw(i, r2, tkgc(e, TkCactivebgnd), nil, ZP);
+ }
+ switch(tks->relief) {
+ case TKsunken:
+ tkbevel(i, p, tks->sl, sh, ScaleBW, d, l);
+ tkbevel(i, q, 0, gh, 1, l, d);
+ break;
+ case TKraised:
+ tkbevel(i, p, tks->sl, sh, ScaleBW, l, d);
+ tkbevel(i, q, 0, gh, 1, d, l);
+ break;
+ }
+ tks->pixpos = p.x;
+ tks->center = p.y + sh/2 + ScaleBW;
+
+ if(tks->sv != BoolT)
+ return;
+
+ tkfprint(sv, tks->value);
+ if(tks->digits > 0 && tks->digits < strlen(sv))
+ sv[tks->digits] = '\0';
+
+ w = stringwidth(e->font, sv);
+ p.x = q.x;
+ p.x -= w/2;
+ p.y = r.min.y - fh - ScalePad;
+ if(p.x < tks->pixmin)
+ p.x = tks->pixmin;
+ if(p.x+w > tks->pixmax)
+ p.x = tks->pixmax - w;
+
+ string(i, p, tkgc(e, fgnd), ZP, e->font, sv);
+}
+
+static void
+tkscalevert(Tk *tk, Image *i)
+{
+ TkEnv *e;
+ TkScale *tks;
+ char sv[32];
+ Image *d, *l;
+ Rectangle r, r2, sr;
+ Point p, q;
+ int fh, v, sw, gw, w, h, len, sl;
+ int fgnd;
+
+ e = tk->env;
+ tks = TKobj(TkScale, tk);
+
+ fh = e->font->height;
+ fgnd = TkCforegnd;
+ if (tk->flag & Tkdisabled)
+ fgnd = TkCdisablefgnd;
+
+ r = Rect(0, 0, tk->act.width, tk->act.height);
+ r = rectaddpt(r, Pt(tk->borderwidth, tk->borderwidth));
+ r = insetrect(r, tk->highlightwidth);
+ r = insetrect(r, ScalePad);
+
+ if (tks->sv)
+ r.min.x += tks->digwidth + ScalePad;
+
+ if(tks->label != nil) {
+ p = stringsize(e->font, tks->label);
+ r.max.x -= p.x;
+ string(i, Pt(r.max.x, r.min.y), tkgc(e, fgnd), ZP, e->font, tks->label);
+ r.max.x -= ScalePad;
+ }
+
+ sr = insetrect(r, ScaleBW);
+ h = Dy(sr);
+ w = Dx(sr);
+ sl = tks->sl + 2*ScaleBW;
+
+ l = tkgc(e, TkCbackgndlght);
+ d = tkgc(e, TkCbackgnddark);
+ tkbevel(i, r.min, w, h, ScaleBW, d, l);
+
+ tks->pixmin = sr.min.y;
+ tks->pixmax = sr.max.y;
+
+ sw = w - 2*ScaleBW;
+ tks->sw = sw/2;
+
+ h -= sl;
+ if (h <= 0)
+ h = 1;
+ p.x = sr.max.x;
+ p.y = sr.min.y;
+ if(tks->tick > 0){
+ int j, t, l;
+ t = tks->tick;
+ l = tks->to-tks->from;
+ if (l < 0)
+ l = -l;
+ if (l == 0)
+ l = 1;
+ r2.min = p;
+ r2.max.x = p.x + ScaleBW + ScalePad;
+ for(j = 0; j <= l; j += t){
+ r2.min.y = p.y+((vlong)j*h)/l+sl/2;
+ r2.max.y = r2.min.y+1;
+ draw(i, r2, tkgc(e, fgnd), nil, ZP);
+ }
+ }
+
+ v = tks->value-tks->from;
+ len = tks->to-tks->from;
+ if (len != 0)
+ p.y += ((vlong)v*h)/len;
+ p.x = sr.min.x;
+ q = p;
+ if(ScaleBW > 1) {
+ q.x++;
+ gw = sw;
+ } else
+ gw = sw-1;
+ q.y += tks->sl/2 + 1;
+ if(tk->flag & Tkactivated) {
+ r2.min = p;
+ r2.max.x = sr.max.x;
+ r2.max.y = p.y+sl;
+ draw(i, r2, tkgc(e, TkCactivebgnd), nil, ZP);
+ }
+ switch(tks->relief) {
+ case TKsunken:
+ tkbevel(i, p, sw, tks->sl, ScaleBW, d, l);
+ tkbevel(i, q, gw, 0, 1, l, d);
+ break;
+ case TKraised:
+ tkbevel(i, p, sw, tks->sl, ScaleBW, l, d);
+ tkbevel(i, q, gw, 0, 1, d, l);
+ break;
+ }
+ tks->pixpos = p.y;
+ tks->center = p.x + sw/2 + ScaleBW;
+
+ if(tks->sv != BoolT)
+ return;
+
+ tkfprint(sv, tks->value);
+ if(tks->digits > 0 && tks->digits < strlen(sv))
+ sv[tks->digits] = '\0';
+
+ p.x = r.min.x - ScalePad - stringwidth(e->font, sv);
+ p.y = q.y;
+ p.y -= fh/2;
+ if (p.y < tks->pixmin)
+ p.y = tks->pixmin;
+ if (p.y + fh > tks->pixmax)
+ p.y = tks->pixmax - fh;
+ string(i, p, tkgc(e, fgnd), ZP, e->font, sv);
+}
+
+char*
+tkdrawscale(Tk *tk, Point orig)
+{
+ Point p;
+ TkEnv *env;
+ TkScale *tks;
+ Rectangle r, fr;
+ Image *i;
+
+ tks = TKobj(TkScale, tk);
+ env = tk->env;
+
+ r.min = ZP;
+ r.max.x = tk->act.width + 2*tk->borderwidth;
+ r.max.y = tk->act.height + 2*tk->borderwidth;
+ i = tkitmp(env, r.max, TkCbackgnd);
+ if(i == nil)
+ return nil;
+
+ if(tks->orient == Tkvertical)
+ tkscalevert(tk, i);
+ else
+ tkscalehoriz(tk, i);
+
+ tkdrawrelief(i, tk, ZP, TkCbackgnd, tk->relief);
+ if (tkhaskeyfocus(tk)) {
+ fr = insetrect(r, tk->borderwidth);
+ tkbox(i, fr, tk->highlightwidth, tkgc(env, TkChighlightfgnd));
+ }
+
+ p.x = tk->act.x + orig.x;
+ p.y = tk->act.y + orig.y;
+ r = rectaddpt(r, p);
+ draw(tkimageof(tk), r, i, nil, ZP);
+
+ return nil;
+}
+
+/* Widget Commands (+ means implemented)
+ +cget
+ +configure
+ +coords
+ +get
+ +identify
+ +set
+*/
+
+static char*
+tkscaleconf(Tk *tk, char *arg, char **val)
+{
+ char *e;
+ TkGeom g;
+ int bd;
+ TkOptab tko[3];
+ TkScale *tks = TKobj(TkScale, tk);
+
+ tko[0].ptr = tk;
+ tko[0].optab = tkgeneric;
+ tko[1].ptr = tks;
+ tko[1].optab = opts;
+ tko[2].ptr = nil;
+
+ if(*arg == '\0')
+ return tkconflist(tko, val);
+
+ g = tk->req;
+ bd = tk->borderwidth;
+ e = tkparse(tk->env->top, arg, tko, nil);
+ tksettransparent(tk, tkhasalpha(tk->env, TkCbackgnd));
+ tkscalecheckvalue(tk);
+ tksizescale(tk);
+ tkgeomchg(tk, &g, bd);
+
+ tk->dirty = tkrect(tk, 1);
+ return e;
+}
+
+char*
+tkscaleposn(TkEnv *env, Tk *tk, char *arg, int *z)
+{
+ int x, y;
+ TkScale *tks = TKobj(TkScale, tk);
+ char *e;
+
+ e = tkfracword(env->top, &arg, &x, env);
+ if(e != nil)
+ return e;
+ e = tkfracword(env->top, &arg, &y, env);
+ if(e != nil)
+ return e;
+
+ x = TKF2I(x) + tk->borderwidth;
+ y = TKF2I(y) + tk->borderwidth;
+
+ if(tks->orient == Tkvertical) {
+ if(z != nil) {
+ z[0] = x;
+ z[1] = y;
+ }
+ x = y;
+ }
+ else {
+ if(z != nil) {
+ z[0] = y;
+ z[1] = x;
+ }
+ }
+ if(x > tks->pixmin && x < tks->pixpos)
+ return trough1;
+ else if(x >= tks->pixpos && x < tks->pixpos+tks->sl+2*ScaleBW)
+ return slider;
+ else if(x >= tks->pixpos+tks->sl+2*ScaleBW && x < tks->pixmax)
+ return trough2;
+
+ return "";
+}
+
+static char*
+tkscaleident(Tk *tk, char *arg, char **val)
+{
+ char *v;
+
+ v = tkscaleposn(tk->env, tk, arg, nil);
+ if(v == nil)
+ return TkBadvl;
+ return tkvalue(val, "%s", v);
+}
+
+static char*
+tkscalecoords(Tk *tk, char *arg, char **val)
+{
+ int p, x, y, l, value;
+ TkScale *tks = TKobj(TkScale, tk);
+ char *e;
+
+ value = tks->value;
+ if(arg != nil && arg[0] != '\0') {
+ e = tkfracword(tk->env->top, &arg, &value, tk->env);
+ if (e != nil)
+ return e;
+ }
+
+ value -= tks->from;
+ p = tks->pixmax - tks->pixmin;
+ l = TKF2I(tks->to-tks->from);
+ if (l==0)
+ p /= 2;
+ else
+ p = TKF2I(value*p/l);
+ p += tks->pixmin;
+ if(tks->orient == Tkvertical) {
+ x = tks->center;
+ y = p;
+ }
+ else {
+ x = p;
+ y = tks->center;
+ }
+ return tkvalue(val, "%d %d", x, y);
+}
+
+static char*
+tkscaleget(Tk *tk, char *arg, char **val)
+{
+ int x, y, value, v, l;
+ char buf[Tkminitem], *e;
+ TkScale *tks = TKobj(TkScale, tk);
+
+ value = tks->value;
+ if(arg[0] != '\0') {
+ e = tkfracword(tk->env->top, &arg, &x, tk->env);
+ if (e != nil)
+ return e;
+ e = tkfracword(tk->env->top, &arg, &y, tk->env);
+ if (e != nil)
+ return e;
+ if(tks->orient == Tkvertical)
+ v = TKF2I(y) + tk->borderwidth;
+ else
+ v = TKF2I(x) + tk->borderwidth;
+
+ if(v < tks->pixmin)
+ value = tks->from;
+ else
+ if(v > tks->pixmax)
+ value = tks->to;
+ else {
+ l = tks->pixmax-tks->pixmin;
+ value = 0;
+ if (l!=0)
+ value = v * ((tks->to-tks->from)/l);
+ value += tks->from;
+ }
+ if(tks->res > 0)
+ value = (value/tks->res)*tks->res;
+ }
+ tkfprint(buf, value);
+ return tkvalue(val, "%s", buf);
+}
+
+static char*
+tkscaleset(Tk *tk, char *arg, char **val)
+{
+ TkScale *tks = TKobj(TkScale, tk);
+ char *e;
+
+ USED(val);
+
+ e = tkfracword(tk->env->top, &arg, &tks->value, tk->env);
+ if (e != nil)
+ return e;
+ tkscalecheckvalue(tk);
+ tk->dirty = tkrect(tk, 1);
+ return nil;
+}
+
+/* tkScaleMotion %x %y */
+static char*
+tkscalemotion(Tk *tk, char *arg, char **val)
+{
+ int o, z[2];
+ char *v;
+ TkScale *tks = TKobj(TkScale, tk);
+ extern int tkstylus;
+
+ USED(val);
+ v = tkscaleposn(tk->env, tk, arg, z);
+ if(v == nil)
+ return TkBadvl;
+
+ o = tk->flag;
+ if(v != slider || z[0] < tks->center-tks->sw || z[0] > tks->center+tks->sw)
+ tk->flag &= ~Tkactivated;
+ else if(tkstylus == 0 || tk->env->top->ctxt->mstate.b != 0)
+ tk->flag |= Tkactivated;
+
+ if((o & Tkactivated) != (tk->flag & Tkactivated))
+ tk->dirty = tkrect(tk, 1);
+
+ return nil;
+}
+
+static char*
+tkscaledrag(Tk *tk, char *arg, char **val)
+{
+ int x, y, v;
+ char *e, buf[Tkmaxitem], f[32];
+ TkScale *tks = TKobj(TkScale, tk);
+
+ USED(val);
+ if((tks->flag & Dragging) == 0)
+ return nil;
+ if(tks->flag & Autorepeat)
+ return nil;
+
+ e = tkfracword(tk->env->top, &arg, &x, tk->env);
+ if(e != nil)
+ return e;
+ e = tkfracword(tk->env->top, &arg, &y, tk->env);
+ if(e != nil)
+ return e;
+
+ if(tks->orient == Tkvertical)
+ v = TKF2I(y) + tk->borderwidth;
+ else
+ v = TKF2I(x) + tk->borderwidth;
+
+ v -= tks->pix;
+ x = tks->pixmax-tks->pixmin;
+ if (x!=tks->sl)
+ v = tks->base + (vlong)v * (tks->to-tks->from)/(x-tks->sl);
+ else
+ v = tks->base;
+ if(tks->res > 0) {
+ int a = tks->res / 2;
+ if (v < 0)
+ a = -a;
+ v = ((v+a)/tks->res)*tks->res;
+ }
+
+ tks->value = v;
+ tkscalecheckvalue(tk);
+
+ if(tks->command != nil && tks->jump != BoolT) {
+ tkfprint(f, tks->value);
+ snprint(buf, sizeof(buf), "%s %s", tks->command, f);
+ e = tkexec(tk->env->top, buf, nil);
+ }
+ tk->dirty = tkrect(tk, 1);
+ return e;
+}
+
+static int
+sgn(int v)
+{
+ return v >= 0 ? 1 : -1;
+}
+
+static char*
+stepscale(Tk *tk, char *pos, int *end)
+{
+ TkScale *tks = TKobj(TkScale, tk);
+ char *e, buf[Tkmaxitem], f[32];
+ int s;
+
+ s = sgn(tks->to - tks->from);
+ if(pos == trough1) {
+ tks->value -= s * tks->bigi;
+ } else {
+ /* trough2 */
+ tks->value += s * tks->bigi;
+ }
+ s = !tkscalecheckvalue(tk);
+ if (end != nil)
+ *end = s;
+ e = nil;
+ if(tks->command != nil) {
+ /* XXX perhaps should only send command if value has actually changed */
+ tkfprint(f, tks->value);
+ snprint(buf, sizeof(buf), "%s %s", tks->command, f);
+ e = tkexec(tk->env->top, buf, nil);
+ }
+ return e;
+}
+
+static void
+screpeat(Tk *tk, void *v, int cancelled)
+{
+ char *e, *pos;
+ int repeat;
+ TkScale *tks = TKobj(TkScale, tk);
+
+ pos = v;
+ if (cancelled) {
+ tks->flag &= ~Autorepeat;
+ return;
+ }
+ e = stepscale(tk, pos, &repeat);
+ if(e != nil || !repeat) {
+ tks->flag &= ~Autorepeat;
+ tkcancelrepeat(tk);
+ }
+ tk->dirty = tkrect(tk, 1);
+ tkupdate(tk->env->top);
+}
+
+static char*
+tkscalebut1p(Tk *tk, char *arg, char **val)
+{
+ int z[2];
+ char *v, *e;
+ TkScale *tks = TKobj(TkScale, tk);
+ int repeat;
+
+ USED(val);
+ v = tkscaleposn(tk->env, tk, arg, z);
+ if(v == nil)
+ return TkBadvl;
+
+ e = nil;
+ if(v[0] == '\0' || z[0] < tks->center-tks->sw || z[0] > tks->center+tks->sw)
+ return nil;
+ if(v == slider) {
+ tks->flag |= Dragging;
+ tks->relief = TKsunken;
+ tks->pix = z[1];
+ tks->base = tks->value;
+ tkscalecheckvalue(tk);
+ } else {
+ e = stepscale(tk, v, &repeat);
+ if (e == nil && repeat) {
+ tks->flag |= Autorepeat;
+ tkrepeat(tk, screpeat, v, TkRptpause, TkRptinterval);
+ }
+ }
+
+ tk->dirty = tkrect(tk, 1);
+ return e;
+}
+
+static char*
+tkscalebut1r(Tk *tk, char *arg, char **val)
+{
+ TkScale *tks = TKobj(TkScale, tk);
+ char *e, buf[Tkmaxitem], f[32];
+ USED(val);
+ USED(arg);
+ if(tks->flag & Autorepeat) {
+ tkcancelrepeat(tk);
+ tks->flag &= ~Autorepeat;
+ }
+ e = nil;
+ if (tks->flag & Dragging) {
+ if (tks->command != nil && tks->jump == BoolT && (tks->flag & Dragging)) {
+ tkfprint(f, tks->value);
+ snprint(buf, sizeof(buf), "%s %s", tks->command, f);
+ e = tkexec(tk->env->top, buf, nil);
+ }
+ tks->relief = TKraised;
+ tks->flag &= ~Dragging;
+ tk->dirty = tkrect(tk, 1);
+ }
+ return e;
+}
+
+static char*
+tkscalekey(Tk *tk, char *arg, char **val)
+{
+ char *e;
+ int key;
+ char *pos = nil;
+ USED(arg);
+ USED(val);
+
+ if(tk->flag & Tkdisabled)
+ return nil;
+
+ key = strtol(arg, nil, 0);
+ if (key == Up || key == Left)
+ pos = trough1;
+ else if (key == Down || key == Right)
+ pos = trough2;
+ if (pos != nil) {
+ e = stepscale(tk, pos, nil);
+ tk->dirty = tkrect(tk, 1);
+ return e;
+ }
+ return nil;
+}
+
+TkCmdtab tkscalecmd[] =
+{
+ "cget", tkscalecget,
+ "configure", tkscaleconf,
+ "set", tkscaleset,
+ "identify", tkscaleident,
+ "get", tkscaleget,
+ "coords", tkscalecoords,
+ "tkScaleMotion", tkscalemotion,
+ "tkScaleDrag", tkscaledrag,
+ "tkScaleBut1P", tkscalebut1p,
+ "tkScaleBut1R", tkscalebut1r,
+ "tkScaleKey", tkscalekey,
+ nil
+};
+
+TkMethod scalemethod = {
+ "scale",
+ tkscalecmd,
+ tkfreescale,
+ tkdrawscale
+};
--- /dev/null
+++ b/libtk/scrol.c
@@ -1,0 +1,735 @@
+#include "lib9.h"
+#include "draw.h"
+#include "tk.h"
+
+#define O(t, e) ((long)(&((t*)0)->e))
+
+/* Layout constants */
+enum {
+ Triangle = 10, /* Height of scroll bar triangle */
+ Elembw = 1, /* border around elements (triangles etc.) */
+ Scrollbw = 1, /* bevel border on scrollbar */
+ Tribw= 1, /* shadow border on triangle */
+};
+
+typedef struct TkScroll TkScroll;
+struct TkScroll
+{
+ int activer;
+ int orient; /* Horitontal or Vertical */
+ int dragpix; /* Scroll delta in button drag */
+ int dragtop;
+ int dragbot;
+ int jump; /* Jump scroll enable */
+ int flag; /* Display flags */
+ int top; /* Top fraction */
+ int bot; /* Bottom fraction */
+ int a1; /* Pixel top/left arrow1 */
+ int t1; /* Pixel top/left trough */
+ int t2; /* Pixel top/left lower trough */
+ int a2; /* Pixel top/left arrow2 */
+ char* cmd;
+};
+
+enum {
+ ActiveA1 = (1<<0), /* Scrollbar control */
+ ActiveA2 = (1<<1),
+ ActiveB1 = (1<<2),
+ ButtonA1 = (1<<3),
+ ButtonA2 = (1<<4),
+ ButtonB1 = (1<<5),
+ Autorepeat = (1<<6)
+};
+
+static
+TkOption opts[] =
+{
+ "activerelief", OPTstab, O(TkScroll, activer), tkrelief,
+ "command", OPTtext, O(TkScroll, cmd), nil,
+ "jump", OPTstab, O(TkScroll, jump), tkbool,
+ "orient", OPTstab, O(TkScroll, orient), tkorient,
+ nil
+};
+
+static
+TkEbind b[] =
+{
+ {TkLeave, "%W activate {}"},
+ {TkEnter, "%W activate [%W identify %x %y]"},
+ {TkMotion, "%W activate [%W identify %x %y]"},
+ {TkButton1P|TkMotion, "%W tkScrollDrag %x %y"},
+ {TkButton1P, "%W tkScrolBut1P %x %y"},
+ {TkButton1P|TkDouble, "%W tkScrolBut1P %x %y"},
+ {TkButton1R, "%W tkScrolBut1R; %W activate [%W identify %x %y]"},
+ {TkButton2P, "%W tkScrolBut2P [%W fraction %x %y]"},
+};
+
+static char*
+tkinitscroll(Tk *tk)
+{
+ int gap;
+ TkScroll *tks;
+
+ tks = TKobj(TkScroll, tk);
+
+ gap = 2*tk->borderwidth;
+ if(tks->orient == Tkvertical) {
+ if(tk->req.width == 0)
+ tk->req.width = Triangle + gap;
+ if(tk->req.height == 0)
+ tk->req.height = 2*Triangle + gap + 6*Elembw;
+ }
+ else {
+ if(tk->req.width == 0)
+ tk->req.width = 2*Triangle + gap + 6*Elembw;
+ if(tk->req.height == 0)
+ tk->req.height = Triangle + gap;
+ }
+
+
+ return tkbindings(tk->env->top, tk, b, nelem(b));
+}
+
+char*
+tkscrollbar(TkTop *t, char *arg, char **ret)
+{
+ Tk *tk;
+ char *e;
+ TkName *names;
+ TkScroll *tks;
+ TkOptab tko[3];
+
+ tk = tknewobj(t, TKscrollbar, sizeof(Tk)+sizeof(TkScroll));
+ if(tk == nil)
+ return TkNomem;
+
+ tks = TKobj(TkScroll, tk);
+
+ tk->relief = TKflat;
+ tk->borderwidth = 1;
+ tks->activer = TKraised;
+ tks->orient = Tkvertical;
+
+ tko[0].ptr = tk;
+ tko[0].optab = tkgeneric;
+ tko[1].ptr = tks;
+ tko[1].optab = opts;
+ tko[2].ptr = nil;
+
+ names = nil;
+ e = tkparse(t, arg, tko, &names);
+ if(e != nil) {
+ tkfreeobj(tk);
+ return e;
+ }
+ tksettransparent(tk, tkhasalpha(tk->env, TkCbackgnd));
+
+ e = tkinitscroll(tk);
+ if(e != nil) {
+ tkfreeobj(tk);
+ return e;
+ }
+
+ e = tkaddchild(t, tk, &names);
+ tkfreename(names);
+ if(e != nil) {
+ tkfreeobj(tk);
+ return e;
+ }
+ tk->name->link = nil;
+
+ return tkvalue(ret, "%s", tk->name->name);
+}
+
+static char*
+tkscrollcget(Tk *tk, char *arg, char **val)
+{
+ TkOptab tko[3];
+ TkScroll *tks = TKobj(TkScroll, tk);
+
+ tko[0].ptr = tk;
+ tko[0].optab = tkgeneric;
+ tko[1].ptr = tks;
+ tko[1].optab = opts;
+ tko[2].ptr = nil;
+
+ return tkgencget(tko, arg, val, tk->env->top);
+}
+
+void
+tkfreescrlb(Tk *tk)
+{
+ TkScroll *tks = TKobj(TkScroll, tk);
+
+ if(tks->cmd != nil)
+ free(tks->cmd);
+}
+
+static void
+drawarrow(TkScroll *tks, Image *i, Point p[3], TkEnv *e, int activef, int buttonf)
+{
+ Image *l, *d, *t;
+ int bgnd;
+
+ bgnd = TkCbackgnd;
+ if(tks->flag & (activef|buttonf)) {
+ bgnd = TkCactivebgnd;
+ fillpoly(i, p, 3, ~0, tkgc(e, bgnd), p[0]);
+ }
+
+ l = tkgc(e, bgnd+TkLightshade);
+ d = tkgc(e, bgnd+TkDarkshade);
+ if(tks->flag & buttonf) {
+ t = d;
+ d = l;
+ l = t;
+ }
+ line(i, p[1], p[2], 0, 0, Tribw-1, d, p[1]);
+ line(i, p[2], p[0], 0, 0, Tribw-1, d, p[2]);
+ line(i, p[0], p[1], 0, 0, Tribw-1, l, p[0]);
+}
+
+static void
+drawslider(TkScroll *tks, Image *i, Point o, int w, int h, TkEnv *e)
+{
+ Image *l, *d;
+ Rectangle r;
+ int bgnd;
+
+ bgnd = TkCbackgnd;
+ if(tks->flag & (ActiveB1|ButtonB1)) {
+ r.min = o;
+ r.max.x = o.x + w + Elembw*2;
+ r.max.y = o.y + h + Elembw*2;
+ bgnd = TkCactivebgnd;
+ draw(i, r, tkgc(e, bgnd), nil, ZP);
+ }
+
+ l = tkgc(e, bgnd+TkLightshade);
+ d = tkgc(e, bgnd+TkDarkshade);
+ if(tks->flag & ButtonB1)
+ tkbevel(i, o, w, h, Scrollbw, d, l);
+ else
+ tkbevel(i, o, w, h, Scrollbw, l, d);
+}
+
+static void
+tkvscroll(Tk *tk, TkScroll *tks, Image *i, Point size)
+{
+ TkEnv *e;
+ Point p[3], o;
+ int bo, w, h, triangle;
+
+ e = tk->env;
+
+ triangle = tk->act.width - Elembw;
+
+ bo = tk->borderwidth + Elembw;
+ p[0].x = size.x/2;
+ p[0].y = bo;
+ p[1].x = p[0].x - triangle/2;
+ p[1].y = p[0].y + triangle;
+ p[2].x = p[0].x + triangle/2;
+ p[2].y = p[0].y + triangle;
+ drawarrow(tks, i, p, e, ActiveA1, ButtonA1);
+
+ tks->a1 = p[2].y;
+ h = p[2].y + Elembw;
+
+ p[0].y = size.y - bo - 1;
+ p[1].y = p[0].y - triangle;
+ p[2].y = p[0].y - triangle;
+ drawarrow(tks, i, p, e, ActiveA2, ButtonA2);
+
+ tks->a2 = p[2].y;
+
+ o.x = tk->borderwidth ;
+ o.y = bo + triangle + 2*Elembw;
+ w = size.x - 2*bo;
+ h = p[2].y - 2*Elembw - h - 2*tk->borderwidth;
+
+ o.y += TKF2I(tks->top*h);
+ h *= tks->bot - tks->top;
+ h = TKF2I(h);
+
+ tks->t1 = o.y - Elembw;
+ tks->t2 = o.y + h + Elembw;
+
+ drawslider(tks, i, o, w, h, e);
+}
+
+static void
+tkhscroll(Tk *tk, TkScroll *tks, Image *i, Point size)
+{
+ TkEnv *e;
+ Point p[3], o;
+ int bo, w, h, triangle;
+
+ e = tk->env;
+
+ triangle = tk->act.height - Elembw;
+
+ bo = tk->borderwidth + Elembw;
+ p[0].x = bo;
+ p[0].y = size.y/2;
+ p[1].x = p[0].x + triangle;
+ p[1].y = p[0].y - triangle/2 + 1;
+ p[2].x = p[0].x + triangle;
+ p[2].y = p[0].y + triangle/2 - 2;
+ drawarrow(tks, i, p, e, ActiveA1, ButtonA1);
+
+ tks->a1 = p[2].x;
+ w = p[2].x + Elembw;
+
+ p[0].x = size.x - bo - 1;
+ p[1].x = p[0].x - triangle;
+ p[2].x = p[0].x - triangle;
+ drawarrow(tks, i, p, e, ActiveA2, ButtonA2);
+
+ tks->a2 = p[2].x;
+
+ o.x = bo + triangle + 2*Elembw;
+ o.y = tk->borderwidth;
+ w = p[2].x - 2*Elembw - w - 2*tk->borderwidth;
+ h = size.y - 2*bo;
+
+ o.x += TKF2I(tks->top*w);
+ w *= tks->bot - tks->top;
+ w = TKF2I(w);
+
+ tks->t1 = o.x - Elembw;
+ tks->t2 = o.x + w + Elembw;
+
+ drawslider(tks, i, o, w, h, e);
+}
+
+char*
+tkdrawscrlb(Tk *tk, Point orig)
+{
+ Point p;
+ TkEnv *e;
+ Rectangle r;
+ Image *i, *dst;
+ TkScroll *tks = TKobj(TkScroll, tk);
+
+ e = tk->env;
+
+ dst = tkimageof(tk);
+ if(dst == nil)
+ return nil;
+
+ r.min = ZP;
+ r.max.x = tk->act.width + 2*tk->borderwidth;
+ r.max.y = tk->act.height + 2*tk->borderwidth;
+
+ i = tkitmp(e, r.max, TkCbackgnd);
+ if(i == nil)
+ return nil;
+
+ if(tks->orient == Tkvertical)
+ tkvscroll(tk, tks, i, r.max);
+ else
+ tkhscroll(tk, tks, i, r.max);
+
+ tkdrawrelief(i, tk, ZP, TkCbackgnd, tk->relief);
+
+ p.x = tk->act.x + orig.x;
+ p.y = tk->act.y + orig.y;
+ r = rectaddpt(r, p);
+ draw(dst, r, i, nil, ZP);
+
+ return nil;
+}
+
+/* Widget Commands (+ means implemented)
+ +activate
+ +cget
+ +configure
+ +delta
+ +fraction
+ +get
+ +identify
+ +set
+*/
+
+static char*
+tkscrollconf(Tk *tk, char *arg, char **val)
+{
+ char *e;
+ TkGeom g;
+ int bd;
+ TkOptab tko[3];
+ TkScroll *tks = TKobj(TkScroll, tk);
+
+ tko[0].ptr = tk;
+ tko[0].optab = tkgeneric;
+ tko[1].ptr = tks;
+ tko[1].optab = opts;
+ tko[2].ptr = nil;
+
+ if(*arg == '\0')
+ return tkconflist(tko, val);
+
+ g = tk->req;
+ bd = tk->borderwidth;
+ e = tkparse(tk->env->top, arg, tko, nil);
+ tksettransparent(tk, tkhasalpha(tk->env, TkCbackgnd));
+ tkgeomchg(tk, &g, bd);
+
+ tk->dirty = tkrect(tk, 1);
+ return e;
+}
+
+static char*
+tkscrollactivate(Tk *tk, char *arg, char **val)
+{
+ int s, gotarg;
+ char buf[Tkmaxitem];
+ TkScroll *tks = TKobj(TkScroll, tk);
+
+ USED(val);
+ tkword(tk->env->top, arg, buf, buf+sizeof(buf), &gotarg);
+ s = tks->flag;
+ if (!gotarg) {
+ char *a;
+ if (s & ActiveA1)
+ a = "arrow1";
+ else if (s & ActiveA2)
+ a = "arrow2";
+ else if (s & ActiveB1)
+ a = "slider";
+ else
+ a = "";
+ return tkvalue(val, a);
+ }
+ tks->flag &= ~(ActiveA1 | ActiveA2 | ActiveB1);
+ if(strcmp(buf, "arrow1") == 0)
+ tks->flag |= ActiveA1;
+ else
+ if(strcmp(buf, "arrow2") == 0)
+ tks->flag |= ActiveA2;
+ else
+ if(strcmp(buf, "slider") == 0)
+ tks->flag |= ActiveB1;
+
+ if(s ^ tks->flag)
+ tk->dirty = tkrect(tk, 1);
+ return nil;
+}
+
+static char*
+tkscrollset(Tk *tk, char *arg, char **val)
+{
+ TkTop *t;
+ char *e;
+ TkScroll *tks = TKobj(TkScroll, tk);
+
+ USED(val);
+ t = tk->env->top;
+ e = tkfracword(t, &arg, &tks->top, nil);
+ if (e != nil)
+ return e;
+ e = tkfracword(t, &arg, &tks->bot, nil);
+ if (e != nil)
+ return e;
+ if(tks->top < 0)
+ tks->top = 0;
+ if(tks->top > TKI2F(1))
+ tks->top = TKI2F(1);
+ if(tks->bot < 0)
+ tks->bot = 0;
+ if(tks->bot > TKI2F(1))
+ tks->bot = TKI2F(1);
+
+ tk->dirty = tkrect(tk, 1);
+ return nil;
+}
+
+static char*
+tkscrolldelta(Tk *tk, char *arg, char **val)
+{
+ int l, delta;
+ char buf[Tkmaxitem];
+ TkScroll *tks = TKobj(TkScroll, tk);
+
+ arg = tkitem(buf, arg);
+ if(tks->orient == Tkvertical)
+ tkitem(buf, arg);
+ if(*arg == '\0' || *buf == '\0')
+ return TkBadvl;
+
+ l = tks->a2-tks->a1-4*Elembw;
+ delta = TKI2F(1);
+ if(l != 0)
+ delta = TKI2F(atoi(buf)) / l;
+ tkfprint(buf, delta);
+
+ return tkvalue(val, "%s", buf);
+}
+
+static char*
+tkscrollget(Tk *tk, char *arg, char **val)
+{
+ char *v, buf[Tkmaxitem];
+ TkScroll *tks = TKobj(TkScroll, tk);
+
+ USED(arg);
+ v = tkfprint(buf, tks->top);
+ *v++ = ' ';
+ tkfprint(v, tks->bot);
+
+ return tkvalue(val, "%s", buf);
+}
+
+static char*
+tkscrollidentify(Tk *tk, char *arg, char **val)
+{
+ int gotarg;
+ TkTop *t;
+ char *v, buf[Tkmaxitem];
+ Point p;
+ TkScroll *tks = TKobj(TkScroll, tk);
+
+ t = tk->env->top;
+ arg = tkword(t, arg, buf, buf+sizeof(buf), &gotarg);
+ if (!gotarg)
+ return TkBadvl;
+ p.x = atoi(buf);
+ tkword(t, arg, buf, buf+sizeof(buf), &gotarg);
+ if (!gotarg)
+ return TkBadvl;
+ p.y = atoi(buf);
+ if (!ptinrect(p, tkrect(tk, 0)))
+ return nil;
+ if (tks->orient == Tkvertical)
+ p.x = p.y;
+ p.x += tk->borderwidth;
+
+ v = "";
+ if(p.x <= tks->a1)
+ v = "arrow1";
+ if(p.x > tks->a1 && p.x <= tks->t1)
+ v = "trough1";
+ if(p.x > tks->t1 && p.x < tks->t2)
+ v = "slider";
+ if(p.x >= tks->t2 && p.x < tks->a2)
+ v = "trough2";
+ if(p.x >= tks->a2)
+ v = "arrow2";
+ return tkvalue(val, "%s", v);
+}
+
+static char*
+tkscrollfraction(Tk *tk, char *arg, char **val)
+{
+ int len, frac, pos;
+ char buf[Tkmaxitem];
+ TkScroll *tks = TKobj(TkScroll, tk);
+
+ arg = tkitem(buf, arg);
+ if(tks->orient == Tkvertical)
+ tkitem(buf, arg);
+ if(*arg == '\0' || *buf == '\0')
+ return TkBadvl;
+
+ pos = atoi(buf);
+ if(pos < tks->a1)
+ pos = tks->a1;
+ if(pos > tks->a2)
+ pos = tks->a2;
+ len = tks->a2 - tks->a1 - 4*Elembw;
+ frac = TKI2F(1);
+ if(len != 0)
+ frac = TKI2F(pos-tks->a1)/len;
+ tkfprint(buf, frac);
+ return tkvalue(val, "%s", buf);
+}
+
+static char*
+tkScrolBut1R(Tk *tk, char *arg, char **val)
+{
+ TkScroll *tks = TKobj(TkScroll, tk);
+
+ USED(val);
+ USED(arg);
+ tkcancelrepeat(tk);
+ tks->flag &= ~(ActiveA1|ActiveA2|ActiveB1|ButtonA1|ButtonA2|ButtonB1|Autorepeat);
+ tk->dirty = tkrect(tk, 1);
+ return nil;
+}
+
+/* tkScrolBut2P fraction */
+static char*
+tkScrolBut2P(Tk *tk, char *arg, char **val)
+{
+ TkTop *t;
+ char *e, buf[Tkmaxitem], fracbuf[Tkmaxitem];
+ TkScroll *tks = TKobj(TkScroll, tk);
+
+
+ USED(val);
+ t = tk->env->top;
+
+ if(arg[0] == '\0')
+ return TkBadvl;
+
+ tkword(t, arg, fracbuf, fracbuf+sizeof(fracbuf), nil);
+
+ e = nil;
+ if(tks->cmd != nil) {
+ snprint(buf, sizeof(buf), "%s moveto %s", tks->cmd, fracbuf);
+ e = tkexec(t, buf, nil);
+ }
+ return e;
+}
+
+static void
+sbrepeat(Tk *tk, void *v, int cancelled)
+{
+ char *e, buf[Tkmaxitem];
+ TkScroll *tks = TKobj(TkScroll, tk);
+ char *fmt = (char *)v;
+
+ if (cancelled) {
+ tks->flag &= ~Autorepeat;
+ return;
+ }
+
+ if(tks->cmd != nil && fmt != nil) {
+ snprint(buf, sizeof(buf), fmt, tks->cmd);
+ e = tkexec(tk->env->top, buf, nil);
+ if (e != nil) {
+ tks->flag &= ~Autorepeat;
+ tkcancelrepeat(tk);
+ } else
+ tkupdate(tk->env->top);
+ }
+}
+
+/* tkScrolBut1P %x %y */
+static char*
+tkScrolBut1P(Tk *tk, char *arg, char **val)
+{
+ int pix;
+ TkTop *t;
+ char *e, *fmt, buf[Tkmaxitem];
+ TkScroll *tks = TKobj(TkScroll, tk);
+
+ USED(val);
+ t = tk->env->top;
+
+ if (tks->flag & Autorepeat)
+ return nil;
+ arg = tkword(t, arg, buf, buf+sizeof(buf), nil);
+ if(tks->orient == Tkvertical)
+ tkword(t, arg, buf, buf+sizeof(buf), nil);
+ if(buf[0] == '\0')
+ return TkBadvl;
+
+ pix = atoi(buf);
+
+ tks->dragpix = pix;
+ tks->dragtop = tks->top;
+ tks->dragbot = tks->bot;
+
+ pix += tk->borderwidth;
+
+ fmt = nil;
+ e = nil;
+ if(pix <= tks->a1) {
+ fmt = "%s scroll -1 unit";
+ tks->flag |= ButtonA1;
+ }
+ if(pix > tks->a1 && pix <= tks->t1)
+ fmt = "%s scroll -1 page";
+ if(pix > tks->t1 && pix < tks->t2)
+ tks->flag |= ButtonB1;
+ if(pix >= tks->t2 && pix < tks->a2)
+ fmt = "%s scroll 1 page";
+ if(pix >= tks->a2) {
+ fmt = "%s scroll 1 unit";
+ tks->flag |= ButtonA2;
+ }
+ if(tks->cmd != nil && fmt != nil) {
+ snprint(buf, sizeof(buf), fmt, tks->cmd);
+ e = tkexec(t, buf, nil);
+ tks->flag |= Autorepeat;
+ tkrepeat(tk, sbrepeat, fmt, TkRptpause, TkRptinterval);
+ }
+ tk->dirty = tkrect(tk, 1);
+ return e;
+}
+
+/* tkScrolDrag %x %y */
+static char*
+tkScrollDrag(Tk *tk, char *arg, char **val)
+{
+ TkTop *t;
+ int pix, delta;
+ char frac[32], buf[Tkmaxitem];
+ TkScroll *tks = TKobj(TkScroll, tk);
+
+ USED(val);
+ t = tk->env->top;
+
+ if (tks->flag & Autorepeat)
+ return nil;
+ if((tks->flag & ButtonB1) == 0)
+ return nil;
+
+ arg = tkword(t, arg, buf, buf+sizeof(buf), nil);
+ if(tks->orient == Tkvertical)
+ tkword(t, arg, buf, buf+sizeof(buf), nil);
+ if(buf[0] == '\0')
+ return TkBadvl;
+
+ pix = atoi(buf);
+
+ delta = TKI2F(pix-tks->dragpix);
+ if ( tks->a2 == tks->a1 )
+ return TkBadvl;
+ delta = delta/(tks->a2-tks->a1-4*Elembw);
+ if(tks->jump == BoolT) {
+ if(tks->dragtop+delta >= 0 &&
+ tks->dragbot+delta <= TKI2F(1)) {
+ tks->top = tks->dragtop+delta;
+ tks->bot = tks->dragbot+delta;
+ }
+ return nil;
+ }
+ if(tks->cmd != nil) {
+ delta += tks->dragtop;
+ if(delta < 0)
+ delta = 0;
+ if(delta > TKI2F(1))
+ delta = TKI2F(1);
+ tkfprint(frac, delta);
+ snprint(buf, sizeof(buf), "%s moveto %s", tks->cmd, frac);
+ return tkexec(t, buf, nil);
+ }
+ return nil;
+}
+
+TkCmdtab tkscrlbcmd[] =
+{
+ "activate", tkscrollactivate,
+ "cget", tkscrollcget,
+ "configure", tkscrollconf,
+ "delta", tkscrolldelta,
+ "fraction", tkscrollfraction,
+ "get", tkscrollget,
+ "identify", tkscrollidentify,
+ "set", tkscrollset,
+ "tkScrollDrag", tkScrollDrag,
+ "tkScrolBut1P", tkScrolBut1P,
+ "tkScrolBut1R", tkScrolBut1R,
+ "tkScrolBut2P", tkScrolBut2P,
+ nil
+};
+
+TkMethod scrollbarmethod = {
+ "scrollbar",
+ tkscrlbcmd,
+ tkfreescrlb,
+ tkdrawscrlb
+};
--- /dev/null
+++ b/libtk/textu.c
@@ -1,0 +1,1077 @@
+#include "lib9.h"
+#include "draw.h"
+#include "tk.h"
+#include "textw.h"
+
+#define istring u.string
+#define iwin u.win
+#define imark u.mark
+#define iline u.line
+
+/* debugging */
+int tktdbg;
+extern void tktprinttext(TkText*);
+extern void tktprintindex(TkTindex*);
+extern void tktprintitem(TkTitem*);
+extern void tktprintline(TkTline*);
+extern void tktcheck(TkText*, char*);
+int tktutfpos(char*, int);
+
+char*
+tktnewitem(int kind, int tagextra,TkTitem **ret)
+{
+ int n;
+ TkTitem *i;
+
+ n = sizeof(TkTitem) + tagextra * sizeof(ulong);
+ i = malloc(n);
+ if(i == nil)
+ return TkNomem;
+
+ memset(i, 0, n);
+ i->kind = kind;
+ i->tagextra = tagextra;
+ *ret = i;
+ return nil;
+}
+
+char*
+tktnewline(int flags, TkTitem *items, TkTline *prev, TkTline *next, TkTline **ret)
+{
+ TkTline *l;
+ TkTitem *i;
+
+ l = malloc(sizeof(TkTline));
+ if(l == nil)
+ return TkNomem;
+
+ memset(l, 0, sizeof(TkTline));
+ l->flags = flags;
+ l->items = items;
+ l->prev = prev;
+ l->next = next;
+ next->prev = l;
+ prev->next = l;
+
+ for(i = items; i->next != nil;)
+ i = i->next;
+ if(tktdbg && !(i->kind == TkTnewline || i->kind == TkTcontline))
+ print("text:tktnewline botch\n");
+ i->iline = l;
+
+ *ret = l;
+ return nil;
+}
+
+/*
+ * free items; freewins is 0 when the subwindows will be
+ * freed anyway as the main text widget is being destroyed.
+ */
+void
+tktfreeitems(TkText *tkt, TkTitem *i, int freewins)
+{
+ TkTitem *n;
+ Tk *tk;
+
+ while(i != nil) {
+ n = i->next;
+ if(tkt->mouse == i)
+ tkt->mouse = nil;
+ switch(i->kind) {
+ case TkTascii:
+ case TkTrune:
+ if(i->istring != nil)
+ free(i->istring);
+ break;
+ case TkTwin:
+ if (i->iwin != nil) {
+ tk = i->iwin->sub;
+ if (tk != nil) {
+ tk->geom = nil;
+ tk->destroyed = nil;
+ if (i->iwin->owned && freewins) {
+ if (tk->name != nil)
+ tkdestroy(tk->env->top, tk->name->name, nil);
+ } else {
+ tk->parent = nil;
+ tk->geom = nil;
+ tk->destroyed = nil;
+ }
+ }
+ if(i->iwin->create != nil)
+ free(i->iwin->create);
+ free(i->iwin);
+ }
+ break;
+ case TkTmark:
+ break;
+ }
+ free(i);
+ i = n;
+ }
+}
+
+void
+tktfreelines(TkText *tkt, TkTline *l, int freewins)
+{
+ TkTline *n;
+
+ while(l != nil) {
+ n = l->next;
+ tktfreeitems(tkt, l->items, freewins);
+ free(l);
+ l = n;
+ }
+}
+
+void
+tktfreetabs(TkTtabstop *t)
+{
+ TkTtabstop *n;
+
+ while(t != nil) {
+ n = t->next;
+ free(t);
+ t = n;
+ }
+}
+
+void
+tkfreetext(Tk *tk)
+{
+ TkText *tkt = TKobj(TkText, tk);
+
+ if(tkt->start.next != nil && tkt->start.next != &(tkt->end)) {
+ tkt->end.prev->next = nil;
+ tktfreelines(tkt, tkt->start.next, 0);
+ }
+ tktfreeitems(tkt, tkt->start.items, 0);
+ tktfreeitems(tkt, tkt->end.items, 0);
+ tktfreetabs(tkt->tabs);
+ if(tkt->tagshare == nil)
+ tktfreetags(tkt->tags);
+ else
+ tk->binds = nil;
+ tktfreemarks(tkt->marks);
+ if(tkt->xscroll != nil)
+ free(tkt->xscroll);
+ if(tkt->yscroll != nil)
+ free(tkt->yscroll);
+ /* don't free image because it belongs to window */
+}
+
+/*
+ * Remove the item at ix, joining previous and next items.
+ * If item is at end of line, remove next line and join
+ * its items to this one (except at end).
+ * On return, ix is adjusted to point to the next item.
+ */
+void
+tktremitem(TkText *tkt, TkTindex *ix)
+{
+ TkTline *l, *lnext;
+ TkTindex prev, nx;
+ TkTitem *i, *ilast;
+
+ l = ix->line;
+ i = ix->item;
+
+ if(i->next == nil) {
+ if(tktdbg && !(i->kind == TkTnewline || i->kind == TkTcontline)) {
+ print("tktremitem: botch 1\n");
+ return;
+ }
+ lnext = l->next;
+ if(lnext == &tkt->end)
+ /* not supposed to remove final newline */
+ return;
+ if(i->kind == TkTnewline)
+ tkt->nlines--;
+ ilast = tktlastitem(lnext->items);
+ ilast->iline = l;
+ i->next = lnext->items;
+ l->flags = (l->flags & ~TkTlast) | (lnext->flags & TkTlast);
+ l->next = lnext->next;
+ lnext->next->prev = l;
+ free(lnext);
+ }
+ if(l->items == i)
+ l->items = i->next;
+ else {
+ prev = *ix;
+ if(!tktadjustind(tkt, TkTbyitemback, &prev) && tktdbg) {
+ print("tktremitem: botch 2\n");
+ return;
+ }
+ prev.item->next = i->next;
+ }
+ ix->item = i->next;
+ ix->pos = 0;
+ i->next = nil;
+ nx = *ix;
+ tktadjustind(tkt, TkTbycharstart, &nx);
+
+ /* check against cached items */
+ if(tkt->selfirst == i)
+ tkt->selfirst = nx.item;
+ if(tkt->sellast == i)
+ tkt->sellast = nx.item;
+ if(tkt->selfirst == tkt->sellast) {
+ tkt->selfirst = nil;
+ tkt->sellast = nil;
+ }
+
+ tktfreeitems(tkt, i, 1);
+}
+
+int
+tktdispwidth(Tk *tk, TkTtabstop *tb, TkTitem *i, Font *f, int x, int pos, int nchars)
+{
+ int w, del, locked;
+ TkTtabstop *tbprev;
+ Display *d;
+ TkText *tkt;
+ TkEnv env;
+
+ tkt = TKobj(TkText, tk);
+ d = tk->env->top->display;
+ if (tb == nil)
+ tb = tkt->tabs;
+
+ switch(i->kind) {
+ case TkTrune:
+ pos = tktutfpos(i->istring, pos);
+ /* FALLTHRU */
+ case TkTascii:
+ if(f == nil) {
+ if(!tktanytags(i))
+ f = tk->env->font;
+ else {
+ tkttagopts(tk, i, nil, &env, nil, 1);
+ f = env.font;
+ }
+ }
+ locked = 0;
+ if(!(tkt->tflag&TkTdlocked))
+ locked = lockdisplay(d);
+ if(nchars >= 0)
+ w = stringnwidth(f, i->istring+pos, nchars);
+ else
+ w = stringwidth(f, i->istring+pos);
+ if(locked)
+ unlockdisplay(d);
+ break;
+ case TkTtab:
+ if(tb == nil)
+ w = 0;
+ else {
+ tbprev = nil;
+ while(tb->pos <= x && tb->next != nil) {
+ tbprev = tb;
+ tb = tb->next;
+ }
+ w = tb->pos - x;
+ if(w <= 0) {
+ del = tb->pos;
+ if(tbprev != nil)
+ del -= tbprev->pos;
+ while(w <= 0)
+ w += del;
+ }
+ /* todo: other kinds of justification */
+ }
+ break;
+ case TkTwin:
+ if(i->iwin->sub == 0)
+ w = 0;
+ else
+ w = i->iwin->sub->act.width + 2*i->iwin->padx + 2*i->iwin->sub->borderwidth;
+ break;
+ default:
+ w = 0;
+ }
+ return w;
+}
+
+int
+tktindrune(TkTindex *ix)
+{
+ int ans;
+ Rune r;
+
+ switch(ix->item->kind) {
+ case TkTascii:
+ ans = ix->item->istring[ix->pos];
+ break;
+ case TkTrune:
+ chartorune(&r, ix->item->istring + tktutfpos(ix->item->istring, ix->pos));
+ ans = r;
+ break;
+ case TkTtab:
+ ans = '\t';
+ break;
+ case TkTnewline:
+ ans = '\n';
+ break;
+ default:
+ /* only care that it isn't a word char */
+ ans = 0x80;
+ }
+ return ans;
+}
+
+TkTitem*
+tktlastitem(TkTitem *i)
+{
+ while(i->next != nil)
+ i = i->next;
+ if(tktdbg && !(i->kind == TkTnewline || i->kind == TkTcontline))
+ print("text:tktlastitem botch\n");
+
+ return i;
+}
+
+TkTline*
+tktitemline(TkTitem *i)
+{
+ i = tktlastitem(i);
+ return i->iline;
+}
+
+int
+tktlinenum(TkText *tkt, TkTindex *p)
+{
+ int n;
+ TkTline *l;
+
+ if(p->line->orig.y <= tkt->end.orig.y / 2) {
+ /* line seems closer to beginning */
+ n = 1;
+ for(l = tkt->start.next; l != p->line; l = l->next) {
+ if(tktdbg && l->next == nil) {
+ print("text: tktlinenum botch\n");
+ break;
+ }
+ if(l->flags & TkTlast)
+ n++;
+ }
+ }
+ else {
+ n = tkt->nlines;
+ for(l = tkt->end.prev; l != p->line; l = l->prev) {
+ if(tktdbg && l->prev == nil) {
+ print("text: tktlinenum botch\n");
+ break;
+ }
+ if(l->flags & TkTfirst)
+ n--;
+ }
+ }
+ return n;
+}
+
+int
+tktlinepos(TkText *tkt, TkTindex *p)
+{
+ int n;
+ TkTindex ix;
+ TkTitem *i;
+
+ n = 0;
+ ix = *p;
+ i = ix.item;
+ tktadjustind(tkt, TkTbylinestart, &ix);
+ while(ix.item != i) {
+ if(tktdbg && ix.item->next == nil && (ix.line->flags&TkTlast)) {
+ print("text: tktlinepos botch\n");
+ break;
+ }
+ n += tktposcount(ix.item);
+ if(!tktadjustind(tkt, TkTbyitem, &ix)) {
+ if(tktdbg)
+ print("tktlinepos botch\n");
+ break;
+ }
+ }
+ return (n+p->pos);
+}
+
+int
+tktposcount(TkTitem *i)
+{
+ int n;
+
+ if(i->kind == TkTascii)
+ n = strlen(i->istring);
+ else
+ if(i->kind == TkTrune)
+ n = utflen(i->istring);
+ else
+ if(i->kind == TkTmark || i->kind == TkTcontline)
+ n = 0;
+ else
+ n = 1;
+ return n;
+}
+
+/*
+ * Insert item i before position ins.
+ * If i is a newline or a contline, make a new line to contain the items up to
+ * and including the new newline, and make the original line
+ * contain the items from ins on.
+ * Adjust ins so that it points just after inserted item.
+ */
+char*
+tktiteminsert(TkText *tkt, TkTindex *ins, TkTitem *i)
+{
+ int hasprev, flags;
+ char *e;
+ TkTindex prev;
+ TkTline *l;
+ TkTitem *items;
+
+ prev = *ins;
+ hasprev = tktadjustind(tkt, TkTbyitemback, &prev);
+
+ if(i->kind == TkTnewline || i->kind == TkTcontline) {
+ i->next = nil;
+ if(hasprev && prev.line == ins->line) {
+ items = ins->line->items;
+ prev.item->next = i;
+ }
+ else
+ items = i;
+
+ flags = ins->line->flags&TkTfirst;
+ if(i->kind == TkTnewline)
+ flags |= TkTlast;
+ e = tktnewline(flags, items, ins->line->prev, ins->line, &l);
+ if(e != nil) {
+ if(hasprev && prev.line == ins->line)
+ prev.item->next = ins->item;
+ return e;
+ }
+
+ if(i->kind == TkTnewline)
+ ins->line->flags |= TkTfirst;
+
+ if(i->kind == TkTcontline)
+ ins->line->flags &= ~TkTfirst;
+ ins->line->items = ins->item;
+ ins->pos = 0;
+ }
+ else {
+ if(hasprev && prev.line == ins->line)
+ prev.item->next = i;
+ else
+ ins->line->items = i;
+ i->next = ins->item;
+ }
+
+ return nil;
+}
+
+/*
+ * If index p doesn't point at the beginning of an item,
+ * split the item at p. Adjust p to point to the beginning of
+ * the item after the split (same character it used to point at).
+ * If there is a split, the old item gets the characters before
+ * the split, and a new item gets the characters after it.
+ */
+char*
+tktsplititem(TkTindex *p)
+{
+ int l1, l2;
+ char *s1, *s2, *e;
+ TkTitem *i, *i2;
+
+ i = p->item;
+
+ if(p->pos != 0) {
+ /*
+ * Must be TkTascii or TkTrune
+ *
+ * Make new item i2, to be inserted after i,
+ * with portion of string from p->pos on
+ */
+
+ if (i->kind == TkTascii)
+ l1 = p->pos;
+ else
+ l1 = tktutfpos(i->istring, p->pos);
+ l2 = strlen(i->istring) - l1;
+ if (l2 == 0)
+ print("tktsplititem botch\n");
+ s1 = malloc(l1+1);
+ if(s1 == nil)
+ return TkNomem;
+ s2 = malloc(l2+1);
+ if(s2 == nil) {
+ free(s1);
+ return TkNomem;
+ }
+
+ memmove(s1, i->istring, l1);
+ s1[l1] = '\0';
+ memmove(s2, i->istring + l1, l2);
+ s2[l2] = '\0';
+
+ e = tktnewitem(i->kind, i->tagextra, &i2);
+ if(e != nil) {
+ free(s1);
+ free(s2);
+ return e;
+ }
+
+ free(i->istring);
+
+ tkttagcomb(i2, i, 1);
+ i2->next = i->next;
+ i->next = i2;
+ i->istring = s1;
+ i2->istring = s2;
+
+ p->item = i2;
+ p->pos = 0;
+ }
+
+ return nil;
+}
+
+int
+tktmaxwid(TkTline *l)
+{
+ int w, maxw;
+
+ maxw = 0;
+ while(l != nil) {
+ w = l->width;
+ if(w > maxw)
+ maxw = w;
+ l = l->next;
+ }
+ return maxw;
+}
+
+Rectangle
+tktbbox(Tk *tk, TkTindex *ix)
+{
+ Rectangle r;
+ int d, w;
+ TkTitem *i;
+ TkTline *l;
+ TkEnv env;
+ TkTtabstop *tb = nil;
+ Tk *sub;
+ TkText *tkt = TKobj(TkText, tk);
+ int opts[TkTnumopts];
+
+ l = ix->line;
+
+ /* r in V space */
+ r.min = subpt(l->orig, tkt->deltatv);
+ r.min.y += l->ascent;
+ r.max = r.min;
+
+ /* tabs dependon tags of first non-mark on display line */
+ for(i = l->items; i->kind == TkTmark; )
+ i = i->next;
+ tkttagopts(tk, i, opts, &env, &tb, 1);
+
+ for(i = l->items; i != nil; i = i->next) {
+ if(i == ix->item) {
+ tkttagopts(tk, i, opts, &env, nil, 1);
+ r.min.y -= opts[TkToffset];
+ switch(i->kind) {
+ case TkTascii:
+ case TkTrune:
+ d = tktdispwidth(tk, tb, i, nil, r.min.x, 0, ix->pos);
+ w = tktdispwidth(tk, tb, i, nil, r.min.x, ix->pos, 1);
+ r.min.x += d;
+ r.min.y -= env.font->ascent;
+ r.max.x = r.min.x + w;
+ r.max.y = r.min.y + env.font->height;
+ break;
+ case TkTwin:
+ sub = i->iwin->sub;
+ if(sub == nil)
+ break;
+ r.min.x += sub->act.x;
+ r.min.y += sub->act.y;
+ r.max.x = r.min.x + sub->act.width + 2*sub->borderwidth;
+ r.max.y = r.min.y + sub->act.height + 2*sub->borderwidth;
+ break;
+ case TkTnewline:
+ r.max.x = r.min.x;
+ r.min.y -= l->ascent;
+ r.max.y = r.min.y + l->height;
+ break;
+ default:
+ d = tktdispwidth(tk, tb, i, nil, r.min.x, 0, -1);
+ r.max.x = r.min.x + d;
+ r.max.y = r.min.y;
+ break;
+ }
+ return r;
+ }
+ r.min.x += tktdispwidth(tk, tb, i, nil, r.min.x, 0, -1);
+ }
+ r.min.x = 0;
+ r.min.y = 0;
+ r.max.x = 0;
+ r.max.y = 0;
+ return r;
+}
+
+/* Return left-at-baseline position of given item, in V coords */
+static Point
+tktitempos(Tk *tk, TkTindex *ix)
+{
+ Point p;
+ TkTitem *i;
+ TkTline *l;
+ TkText *tkt = TKobj(TkText, tk);
+
+ l = ix->line;
+
+ /* p in V space */
+ p = subpt(l->orig, tkt->deltatv);
+ p.y += l->ascent;
+
+ for(i = l->items; i != nil && i != ix->item; i = i->next)
+ p.x += i->width;
+ return p;
+}
+
+static Tk*
+tktdeliver(Tk *tk, TkTitem *i, TkTitem *tagit, int event, void *data, Point deltasv)
+{
+ Tk *ftk, *dest;
+ TkTwind *w;
+ TkText *tkt;
+ TkTtaginfo *t;
+ TkTline *l;
+ TkMouse m;
+ Point mp, p;
+ TkTindex ix;
+ int bd;
+
+ dest = nil;
+ if(i != nil) {
+ tkt = TKobj(TkText, tk);
+
+ if(i->kind == TkTwin) {
+ w = i->iwin;
+ if(w->sub != nil) {
+ if(!(event & TkKey) && (event & TkEmouse)) {
+ m = *(TkMouse*)data;
+ mp.x = m.x;
+ mp.y = m.y;
+ ix.item = i;
+ ix.pos = 0;
+ ix.line = tktitemline(i);
+ p = tktitempos(tk, &ix);
+ bd = w->sub->borderwidth;
+ mp.x = m.x - (deltasv.x + p.x + w->sub->act.x + bd);
+ mp.y = m.y - (deltasv.y + p.y + w->sub->act.y + bd);
+ ftk = tkinwindow(w->sub, mp, 0);
+ if(ftk != w->focus) {
+ tkdeliver(w->focus, TkLeave, data);
+ tkdeliver(ftk, TkEnter, data);
+
+ w->focus = ftk;
+ }
+ if(ftk != nil)
+ dest = tkdeliver(ftk, event, &m);
+ }
+ else {
+ if ((event & TkLeave) && (w->focus != w->sub)) {
+ tkdeliver(w->focus, TkLeave, data);
+ w->focus = nil;
+ event &= ~TkLeave;
+ }
+ if (event)
+ tkdeliver(w->sub, event, data);
+ }
+ if(Dx(w->sub->dirty) > 0) {
+ l = tktitemline(i);
+ tktfixgeom(tk, tktprevwrapline(tk, l), l, 0);
+ }
+ if(event & TkKey)
+ return dest;
+ }
+ }
+
+ if(tagit != 0) {
+ for(t = tkt->tags; t != nil; t = t->next) {
+ if(t->binds != nil && tkttagset(tagit, t->id)) {
+ if(tksubdeliver(tk, t->binds, event, data, 0) == TkDbreak) {
+ return dest;
+ }
+ }
+ }
+ }
+ }
+ return dest;
+}
+
+Tk*
+tktinwindow(Tk *tk, Point *p)
+{
+ TkTindex ix;
+ Point q;
+ Tk *sub;
+
+ tktxyind(tk, p->x, p->y, &ix);
+ if (ix.item == nil || ix.item->kind != TkTwin || ix.item->iwin->sub == nil)
+ return tk;
+ sub = ix.item->iwin->sub;
+ q = tktitempos(tk, &ix);
+ p->x -= q.x + sub->borderwidth + sub->act.x;
+ p->y -= q.y + sub->borderwidth + sub->act.y;
+ return sub;
+}
+
+Tk*
+tktextevent(Tk *tk, int event, void *data)
+{
+ char *e;
+ TkMouse m, vm;
+ TkTitem *f, *tagit;
+ TkText *tkt;
+ TkTindex ix;
+ Tk *dest;
+ Point deltasv;
+
+ tkt = TKobj(TkText, tk);
+ deltasv = tkposn(tk);
+ deltasv.x += tk->borderwidth + tk->ipad.x/2;
+ deltasv.y += tk->borderwidth + tk->ipad.y/2;
+
+ dest = nil;
+ if(event == TkLeave && tkt->mouse != nil) {
+ vm.x = 0;
+ vm.y = 0;
+ tktdeliver(tk, tkt->mouse, tkt->mouse, TkLeave, data, deltasv);
+ tkt->mouse = nil;
+ }
+ else if((event & TkKey) == 0 && (event & TkEmouse)) {
+ /* m in S space, tm in V space */
+ m = *(TkMouse*)data;
+ vm = m;
+ vm.x -= deltasv.x;
+ vm.y -= deltasv.y;
+ if((event & TkMotion) == 0 || m.b == 0) {
+ tkt->current.x = vm.x;
+ tkt->current.y = vm.y;
+ }
+ tktxyind(tk, vm.x, vm.y, &ix);
+ f = ix.item;
+ if(tkt->mouse != f) {
+ tagit = nil;
+ if(tkt->mouse != nil) {
+ if(tktanytags(tkt->mouse)) {
+ e = tktnewitem(TkTascii, tkt->mouse->tagextra, &tagit);
+ if(e != nil)
+ return dest; /* XXX propagate error? */
+ tkttagcomb(tagit, tkt->mouse, 1);
+ tkttagcomb(tagit, f, -1);
+ }
+ tktdeliver(tk, tkt->mouse, tagit, TkLeave, data, deltasv);
+ if(tagit)
+ free(tagit);
+ tagit = nil;
+ }
+ if(tktanytags(f)) {
+ e = tktnewitem(TkTascii, f->tagextra, &tagit);
+ if(e != nil)
+ return dest; /* XXX propagate error? */
+ tkttagcomb(tagit, f, 1);
+ if(tkt->mouse)
+ tkttagcomb(tagit, tkt->mouse, -1);
+ }
+ tktdeliver(tk, f, tagit, TkEnter, data, deltasv);
+ tkt->mouse = f;
+ if(tagit)
+ free(tagit);
+ }
+ if(tkt->mouse != nil)
+ dest = tktdeliver(tk, tkt->mouse, tkt->mouse, event, &m, deltasv);
+ }
+ else if(event == TkFocusin)
+ tktextcursor(tk, " insert", (char **) nil);
+ /* pass all "real" events on to parent text widget - DBK */
+ tksubdeliver(tk, tk->binds, event, data, 0);
+ return dest;
+}
+
+/* Debugging */
+void
+tktprintitem(TkTitem *i)
+{
+ int j;
+
+ print("%p:", i);
+ switch(i->kind){
+ case TkTascii:
+ print("\"%s\"", i->istring);
+ break;
+ case TkTrune:
+ print("<rune:%s>", i->istring);
+ break;
+ case TkTnewline:
+ print("<nl:%p>", i->iline);
+ break;
+ case TkTcontline:
+ print("<cont:%p>", i->iline);
+ break;
+ case TkTtab:
+ print("<tab>");
+ break;
+ case TkTmark:
+ print("<mk:%s>", i->imark->name);
+ break;
+ case TkTwin:
+ if (i->iwin->sub->name != nil)
+ print("<win:%s>", i->iwin->sub? i->iwin->sub->name->name : "<null>");
+ }
+ print("[%d]", i->width);
+ if(i->tags !=0 || i->tagextra !=0) {
+ print("{%lux", i->tags[0]);
+ for(j=0; j < i->tagextra; j++)
+ print(" %lux", i->tags[j+1]);
+ print("}");
+ }
+ print(" ");
+}
+
+void
+tktprintline(TkTline *l)
+{
+ TkTitem *i;
+
+ print("line %p: orig=(%d,%d), w=%d, h=%d, a=%d, f=%x\n\t",
+ l, l->orig.x, l->orig.y, l->width, l->height, l->ascent, l->flags);
+ for(i = l->items; i != nil; i = i->next)
+ tktprintitem(i);
+ print("\n");
+}
+
+void
+tktprintindex(TkTindex *ix)
+{
+ print("line=%p,item=%p,pos=%d\n", ix->line, ix->item, ix->pos);
+}
+
+void
+tktprinttext(TkText *tkt)
+{
+ TkTline *l;
+ TkTtaginfo *ti;
+ TkTmarkinfo *mi;
+
+ for(ti=tkt->tags; ti != nil; ti=ti->next)
+ print("%s{%d} ", ti->name, ti->id);
+ print("\n");
+ for(mi = tkt->marks; mi != nil; mi=mi->next)
+ print("%s{%p} ", mi->name? mi->name : "nil", mi->cur);
+ print("\n");
+ print("selfirst=%p sellast=%p\n", tkt->selfirst, tkt->sellast);
+
+ for(l = &tkt->start; l != nil; l = l->next)
+ tktprintline(l);
+}
+
+/*
+ * Check that assumed invariants are true.
+ *
+ * - start line and end line have no items
+ * - all other lines have at least one item
+ * - start line leads to end line via next pointers
+ * - prev pointers point to previous lines
+ * - each line ends in either a TkTnewline or a TkTcontline
+ * whose iline pointer points to the line itself
+ * - TkTcontline and TkTmark items have no tags
+ * (this is so they don't get realloc'd because of tag combination)
+ * - all cur fields of marks point to nil or a TkTmark
+ * - selfirst and sellast correctly define select region
+ * - nlines counts the number of lines
+ */
+void
+tktcheck(TkText *tkt, char *fun)
+{
+ int nl, insel, selfound;
+ TkTline *l;
+ TkTitem *i;
+ TkTmarkinfo *mi;
+ TkTindex ix;
+ char *prob;
+
+ prob = nil;
+ nl = 0;
+
+ if(tkt->start.items != nil || tkt->end.items != nil)
+ prob = "start/end has items";
+ for(l = tkt->start.next; l != &tkt->end; l = l->next) {
+ if(l->prev->next != l) {
+ prob = "prev mismatch";
+ break;
+ }
+ if(l->next->prev != l) {
+ prob = "next mismatch";
+ break;
+ }
+ i = l->items;
+ if(i == nil) {
+ prob = "empty line";
+ break;
+ }
+ while(i->next != nil) {
+ if(i->kind == TkTnewline || i->kind == TkTcontline) {
+ prob = "premature end of line";
+ break;
+ }
+ if(i->kind == TkTmark && (i->tags[0] != 0 || i->tagextra != 0)) {
+ prob = "mark has tags";
+ break;
+ }
+ i = i->next;
+ }
+ if(i->kind == TkTnewline)
+ nl++;
+ if(!(i->kind == TkTnewline || i->kind == TkTcontline)) {
+ prob = "bad end of line";
+ break;
+ }
+ if(i->kind == TkTcontline && (i->tags[0] != 0 || i->tagextra != 0)) {
+ prob = "contline has tags";
+ break;
+ }
+ if(i->iline != l) {
+ prob = "bad end-of-line pointer";
+ break;
+ }
+ }
+ for(mi = tkt->marks; mi != nil; mi=mi->next) {
+ if(mi->cur != nil) {
+ tktstartind(tkt, &ix);
+ do {
+ if(ix.item->kind == TkTmark && ix.item == mi->cur)
+ goto foundmark;
+ } while(tktadjustind(tkt, TkTbyitem, &ix));
+ prob = "bad mark cur";
+ break;
+ foundmark: ;
+ }
+ }
+ insel = 0;
+ selfound = 0;
+ tktstartind(tkt, &ix);
+ do {
+ i = ix.item;
+ if(i == tkt->selfirst) {
+ if(i->kind == TkTmark || i->kind == TkTcontline) {
+ prob = "selfirst not on character";
+ break;
+ }
+ if(i == tkt->sellast) {
+ prob = "selfirst==sellast, not nil";
+ break;
+ }
+ insel = 1;
+ selfound = 1;
+ }
+ if(i == tkt->sellast) {
+ if(i->kind == TkTmark || i->kind == TkTcontline) {
+ prob = "sellast not on character";
+ break;
+ }
+ insel = 0;
+ }
+ if(i->kind != TkTmark && i->kind != TkTcontline) {
+ if(i->tags[0] & (1<<TkTselid)) {
+ if(!insel) {
+ prob = "sel set outside selfirst..sellast";
+ break;
+ }
+ }
+ else {
+ if(insel) {
+ prob = "sel not set inside selfirst..sellast";
+ break;
+ }
+ }
+ }
+ } while(tktadjustind(tkt, TkTbyitem, &ix));
+ if(tkt->selfirst != nil && !selfound)
+ prob = "selfirst not found";
+
+ if(prob != nil) {
+ print("tktcheck problem: %s: %s\n", fun, prob);
+ tktprinttext(tkt);
+abort();
+ }
+}
+
+int
+tktutfpos(char *s, int pos)
+{
+ char *s1;
+ int c;
+ Rune r;
+
+ for (s1 = s; pos > 0; pos--) {
+ c = *(uchar *)s1;
+ if (c < Runeself) {
+ if (c == '\0')
+ break;
+ s1++;
+ }
+ else
+ s1 += chartorune(&r, s1);
+ }
+ return s1 - s;
+}
+
+/*
+struct timerec {
+ char *name;
+ ulong ms;
+};
+
+static struct timerec tt[100];
+static int ntt = 1;
+
+int
+tktalloctime(char *name)
+{
+ if(ntt >= 100)
+ abort();
+ tt[ntt].name = strdup(name);
+ tt[ntt].ms = 0;
+ return ntt++;
+}
+
+void
+tktstarttime(int ind)
+{
+return;
+ tt[ind].ms -= osmillisec();
+}
+
+void
+tktendtime(int ind)
+{
+return;
+ tt[ind].ms += osmillisec();
+}
+
+void
+tktdumptime(void)
+{
+ int i;
+
+ for(i = 1; i < ntt; i++)
+ print("%s: %d\n", tt[i].name, tt[i].ms);
+}
+*/
--- /dev/null
+++ b/libtk/textw.c
@@ -1,0 +1,3701 @@
+#include "lib9.h"
+#include "draw.h"
+#include "keyboard.h"
+#include "tk.h"
+#include "textw.h"
+
+/*
+ * useful text widget info to be found at:
+ * :/coordinate.systems - what coord. systems are in use
+ * textu.c:/assumed.invariants - some invariants that must be preserved
+ */
+
+#define istring u.string
+#define iwin u.win
+#define imark u.mark
+#define iline u.line
+
+#define FLUSH() flushimage(tk->env->top->display, 1)
+
+#define O(t, e) ((long)(&((t*)0)->e))
+
+/* Layout constants */
+enum {
+ Textpadx = 2,
+ Textpady = 0,
+};
+
+typedef struct Interval {
+ int lo;
+ int hi;
+} Interval;
+
+typedef struct Mprint Mprint;
+struct Mprint
+{
+ char* buf;
+ int ptr;
+ int len;
+};
+
+typedef struct TkDump TkDump;
+struct TkDump
+{
+ int sgml;
+ int metrics;
+};
+
+static
+TkOption dumpopts[] =
+{
+ "sgml", OPTbool, O(TkDump, sgml), nil,
+ "metrics", OPTbool, O(TkDump, metrics), nil,
+ nil
+};
+
+static
+TkStab tkcompare[] =
+{
+ "<", TkLt,
+ "<=", TkLte,
+ "==", TkEq,
+ ">=", TkGte,
+ ">", TkGt,
+ "!=", TkNeq,
+ nil
+};
+
+static
+TkOption textopts[] =
+{
+ "wrap", OPTstab, O(TkText, opts[TkTwrap]), tkwrap,
+ "spacing1", OPTnndist, O(TkText, opts[TkTspacing1]), (void *)O(Tk, env),
+ "spacing2", OPTnndist, O(TkText, opts[TkTspacing2]), (void *)O(Tk, env),
+ "spacing3", OPTnndist, O(TkText, opts[TkTspacing3]), (void *)O(Tk, env),
+ "tabs", OPTtabs, O(TkText, tabs), (void *)O(Tk, env),
+ "xscrollcommand", OPTtext, O(TkText, xscroll), nil,
+ "yscrollcommand", OPTtext, O(TkText, yscroll), nil,
+ "insertwidth", OPTnndist, O(TkText, inswidth), nil,
+ "tagshare", OPTwinp, O(TkText, tagshare), nil,
+ "propagate", OPTstab, O(TkText, propagate), tkbool,
+ "selectborderwidth", OPTnndist, O(TkText, sborderwidth), nil,
+ nil
+};
+
+#define CNTL(c) ((c)&0x1f)
+#define DEL 0x7f
+
+static TkEbind tktbinds[] = {
+ {TkButton1P, "%W tkTextButton1 %X %Y"},
+ {TkButton1P|TkMotion, "%W tkTextSelectTo %X %Y"},
+ {TkButton1P|TkDouble, "%W tkTextSelectTo %X %Y double"},
+ {TkButton1R, "%W tkTextButton1R"},
+ {TkButton2P, "%W scan mark %x %y"},
+ {TkButton2P|TkMotion, "%W scan dragto %x %y"},
+ {TkKey, "%W tkTextInsert {%A}"},
+ {TkKey|CNTL('a'), "%W tkTextSetCursor {insert linestart}"},
+ {TkKey|Home, "%W tkTextSetCursor {insert linestart}"},
+ {TkKey|CNTL('<'), "%W tkTextSetCursor {insert linestart}"},
+ {TkKey|CNTL('b'), "%W tkTextSetCursor insert-1c"},
+ {TkKey|Left, "%W tkTextSetCursor insert-1c"},
+ {TkKey|CNTL('d'), "%W tkTextDelIns"},
+ {TkKey|CNTL('e'), "%W tkTextSetCursor {insert lineend}"},
+ {TkKey|End, "%W tkTextSetCursor {insert lineend}"},
+ {TkKey|CNTL('>'), "%W tkTextSetCursor {insert lineend}"},
+ {TkKey|CNTL('f'), "%W tkTextSetCursor insert+1c"},
+ {TkKey|Right, "%W tkTextSetCursor insert+1c"},
+ {TkKey|CNTL('h'), "%W tkTextDelIns -c"},
+ {TkKey|DEL, "%W tkTextDelIns"},
+ {TkKey|CNTL('k'), "%W tkTextDelIns +l"},
+ {TkKey|CNTL('n'), "%W tkTextSetCursor {insert+1l}"},
+ {TkKey|Down, "%W tkTextSetCursor {insert+1l}"},
+ {TkKey|CNTL('o'), "%W tkTextInsert {\n}; %W mark set insert insert-1c"},
+ {TkKey|CNTL('p'), "%W tkTextSetCursor {insert-1l}"},
+ {TkKey|Up, "%W tkTextSetCursor {insert-1l}"},
+ {TkKey|CNTL('u'), "%W tkTextDelIns -l"},
+ {TkKey|CNTL('v'), "%W yview scroll 0.75 page"},
+ {TkKey|Pgdown, "%W yview scroll 0.75 page"},
+ {TkKey|CNTL('w'), "%W tkTextDelIns -w"},
+ {TkKey|Pgup, "%W yview scroll -0.75 page"},
+ {TkButton4P, "%W yview scroll -0.2 page"},
+ {TkButton5P, "%W yview scroll 0.2 page"},
+ {TkFocusout, "%W tkTextCursor delete"},
+ {TkKey|APP|'\t', ""},
+ {TkKey|BackTab, ""},
+};
+
+static int tktclickmatch(TkText *, int, int, int, TkTindex *);
+static void tktdoubleclick(TkText *, TkTindex *, TkTindex *);
+static char* tktdrawline(Image*, Tk*, TkTline*, Point);
+static void tktextcursordraw(Tk *, int);
+static char* tktsetscroll(Tk*, int);
+static void tktsetclip(Tk *);
+static char* tktview(Tk*, char*, char**, int, int*, int, int);
+static Interval tkttranslate(Tk*, Interval, int);
+static void tktfixscroll(Tk*, Point);
+static void tktnotdrawn(Tk*, int, int, int);
+static void tktdrawbg(Tk*, int, int, int);
+static int tktwidbetween(Tk*, int, TkTindex*, TkTindex*);
+static int tktpostspace(Tk*, TkTline*);
+static int tktprespace(Tk*, TkTline*);
+static void tktsee(Tk*, TkTindex*, int);
+static Point tktrelpos(Tk*);
+static void autoselect(Tk*, void*, int);
+static void blinkreset(Tk*);
+
+/* debugging */
+extern int tktdbg;
+extern void tktprinttext(TkText*);
+extern void tktprintindex(TkTindex*);
+extern void tktprintitem(TkTitem*);
+extern void tktprintline(TkTline*);
+extern void tktcheck(TkText*, char*);
+extern int tktutfpos(char *, int);
+
+char*
+tktext(TkTop *t, char* arg, char **ret)
+{
+ Tk *tk;
+ char *e;
+ TkEnv *ev;
+ TkTline *l;
+ TkTitem *it = nil;
+ TkName *names = nil;
+ TkTtaginfo *ti = nil;
+ TkOptab tko[3];
+ TkTmarkinfo *mi = nil;
+ TkText *tkt, *tktshare;
+
+ tk = tknewobj(t, TKtext, sizeof(Tk)+sizeof(TkText));
+ if(tk == nil)
+ return TkNomem;
+
+ tkt = TKobj(TkText, tk);
+
+ tk->relief = TKsunken;
+ tk->borderwidth = 1;
+ tk->ipad.x = Textpadx * 2;
+ tk->ipad.y = Textpady * 2;
+ tk->flag |= Tktakefocus;
+ tkt->sborderwidth = 0;
+ tkt->inswidth = 2;
+ tkt->cur_flag = 0; /* text cursor doesn't show up initially */
+ tkt->opts[TkTwrap] = Tkwrapchar;
+ tkt->opts[TkTrelief] = TKflat;
+ tkt->opts[TkTjustify] = Tkleft;
+ tkt->propagate = BoolX;
+
+ tko[0].ptr = tk;
+ tko[0].optab = tkgeneric;
+ tko[1].ptr = tkt;
+ tko[1].optab = textopts;
+ tko[2].ptr = nil;
+
+ tk->req.width = tk->env->wzero*Textwidth;
+ tk->req.height = tk->env->font->height*Textheight;
+
+ names = nil;
+ e = tkparse(t, arg, tko, &names);
+ if(e != nil)
+ goto err;
+ tksettransparent(tk, tkhasalpha(tk->env, TkCbackgnd));
+ if(names == nil) {
+ /* tkerr(t, arg); XXX */
+ e = TkBadwp;
+ goto err;
+ }
+
+ if(tkt->tagshare != nil) {
+ tkputenv(tk->env);
+ tk->env = tkt->tagshare->env;
+ tk->env->ref++;
+ }
+
+ if(tk->flag&Tkdisabled)
+ tkt->inswidth = 0;
+
+ if(tkt->tabs == nil) {
+ tkt->tabs = malloc(sizeof(TkTtabstop));
+ if(tkt->tabs == nil)
+ goto err;
+ tkt->tabs->pos = 8*tk->env->wzero;
+ tkt->tabs->justify = Tkleft;
+ tkt->tabs->next = nil;
+ }
+
+ if(tkt->tagshare != nil) {
+ tktshare = TKobj(TkText, tkt->tagshare);
+ tkt->tags = tktshare->tags;
+ tkt->nexttag = tktshare->nexttag;
+ }
+ else {
+ /* Note: sel should have id == TkTselid == 0 */
+ e = tktaddtaginfo(tk, "sel", &ti);
+ if(e != nil)
+ goto err;
+
+ tkputenv(ti->env);
+ ti->env = tknewenv(t);
+ if(ti->env == nil)
+ goto err;
+
+ ev = ti->env;
+ ev->colors[TkCbackgnd] = tk->env->colors[TkCselectbgnd];
+ ev->colors[TkCbackgndlght] = tk->env->colors[TkCselectbgndlght];
+ ev->colors[TkCbackgnddark] = tk->env->colors[TkCselectbgnddark];
+ ev->colors[TkCforegnd] = tk->env->colors[TkCselectfgnd];
+ ev->set = (1<<TkCbackgnd)|(1<<TkCbackgndlght)|
+ (1<<TkCbackgnddark)|(1<<TkCforegnd);
+
+ ti->opts[TkTborderwidth] = tkt->sborderwidth;
+ if(tkt->sborderwidth > 0)
+ ti->opts[TkTrelief] = TKraised;
+ }
+
+ e = tktaddmarkinfo(tkt, "current", &mi);
+ if(e != nil)
+ goto err;
+
+ e = tktaddmarkinfo(tkt, "insert", &mi);
+ if(e != nil)
+ goto err;
+
+ tkt->start.flags = TkTfirst|TkTlast;
+ tkt->end.flags = TkTlast;
+
+ e = tktnewitem(TkTnewline, 0, &it);
+
+ if(e != nil)
+ goto err;
+
+ e = tktnewline(TkTfirst|TkTlast, it, &tkt->start, &tkt->end, &l);
+ if(e != nil)
+ goto err;
+
+ e = tktnewitem(TkTmark, 0, &it);
+ if(e != nil)
+ goto err;
+
+ it->next = l->items;
+ l->items = it;
+ it->imark = mi;
+ mi->cur = it;
+ tkt->nlines = 1;
+ tkt->scrolltop[Tkvertical] = -1;
+ tkt->scrolltop[Tkhorizontal] = -1;
+ tkt->scrollbot[Tkvertical] = -1;
+ tkt->scrollbot[Tkhorizontal] = -1;
+
+ if(tkt->tagshare != nil)
+ tk->binds = tkt->tagshare->binds;
+ else {
+ e = tkbindings(t, tk, tktbinds, nelem(tktbinds));
+
+ if(e != nil)
+ goto err;
+ }
+ if (tkt->propagate == BoolT) {
+ if ((tk->flag & Tksetwidth) == 0)
+ tk->req.width = tktmaxwid(tkt->start.next);
+ if ((tk->flag & Tksetheight) == 0)
+ tk->req.height = tkt->end.orig.y;
+ }
+
+ e = tkaddchild(t, tk, &names);
+ tkfreename(names);
+ if(e != nil)
+ goto err;
+ tk->name->link = nil;
+
+ return tkvalue(ret, "%s", tk->name->name);
+
+err:
+ /* XXX it's possible there's a memory leak here */
+ tkfreeobj(tk);
+ return e;
+}
+
+/*
+ * There are four coordinate systems of interest:
+ * S - screen coordinate system (i.e. top left corner of
+ * inferno screen is (0,0) in S space.)
+ * I - image coordinate system (i.e. top left corner of
+ * tkimageof(this widget) is (0,0) in I space.)
+ * T - text coordinate system (i.e., top left of first line
+ * is at (0,0) in T space.)
+ * V - view coordinate system (i.e., top left of visible
+ * portion of widget is at (0,0) in V space.)
+ *
+ * A point P in the four systems (Ps, Pi, Pt, Pv) satisfies:
+ * Pt = Ps - deltast
+ * Pv = Ps - deltasv
+ * Pv = Pi - deltaiv
+ * (where deltast is vector from S origin to T origin;
+ * deltasv is vector from S origin to V origin;
+ * deltaiv is vector from I origin to V origin)
+ *
+ * We keep deltatv, deltasv, and deltaiv in tkt.
+ * Deltatv is updated by scrolling.
+ * Deltasv is updated by geom changes:
+ * tkposn(tk)+ipad/2
+ * Deltaiv is affected by geom changes and the call to the draw function:
+ * tk->act+orig+ipad/2+(bw,bw) (orig is the parameter to tkdrawtext),
+ *
+ * We can derive
+ * Ps = Pt + deltast
+ * = Pt + deltasv - deltatv
+ *
+ * Pv = Pt - deltatv
+ *
+ * Here are various coordinates in the text widget according
+ * to which coordinate system they use:
+ *
+ * S - Mouse coordinates (coming in to tktextevent);
+ * the deltasv parameter to tkdrawtext;
+ * coords in tkt->image, where drawing is done to
+ * (to get same bit-alignment as screen, for fast transfer)
+ * T - orig in TkTlines
+ * V - %x,%y delivered via binds to TkText or its tags
+
+ * Note deltasv changes underneath us, so is calculated on the fly
+ * when it needs to be (in tktextevent).
+ *
+ */
+static void
+tktsetdeltas(Tk *tk, Point orig)
+{
+ TkText *tkt = TKobj(TkText, tk);
+
+ tkt->deltaiv.x = orig.x + tk->act.x + tk->ipad.x/2 + tk->borderwidth;
+ tkt->deltaiv.y = orig.y + tk->act.y + tk->ipad.y/2 + tk->borderwidth;
+}
+
+static Point
+tktrelpos(Tk *sub)
+{
+ Tk *tk;
+ TkTindex ix;
+ Rectangle r;
+ Point ans;
+
+ tk = sub->parent;
+ if(tk == nil)
+ return ZP;
+
+ if(tktfindsubitem(sub, &ix)) {
+ r = tktbbox(tk, &ix);
+ ans.x = r.min.x;
+ ans.y = r.min.y;
+ return r.min;
+ }
+ return ZP;
+}
+
+static void
+tktreplclipr(Image *dst, Rectangle r)
+{
+ int locked;
+
+ locked = lockdisplay(dst->display);
+ replclipr(dst, 0, r);
+ if(locked)
+ unlockdisplay(dst->display);
+}
+
+char*
+tkdrawtext(Tk *tk, Point orig)
+{
+ int vh;
+ Image *dst;
+ TkText *tkt;
+ TkTline *l, *lend;
+ Point p, deltait;
+ Rectangle oclipr;
+ int reldone = 1;
+ char *e;
+ tkt = TKobj(TkText, tk);
+ dst = tkimageof(tk);
+ if (dst == nil)
+ return nil;
+ tkt->image = dst;
+ tktsetdeltas(tk, orig);
+ tkt->tflag |= TkTdrawn|TkTdlocked;
+ oclipr = dst->clipr;
+ tktsetclip(tk);
+
+ if(tk->flag&Tkrefresh) {
+ reldone = 0;
+ tktnotdrawn(tk, 0, tkt->end.orig.y, 1);
+ }
+ tk->flag &= ~Tkrefresh;
+
+ deltait = subpt(tkt->deltaiv, tkt->deltatv);
+ vh = tk->act.height - tk->ipad.y/2;
+ lend = &tkt->end;
+ for(l = tkt->start.next; l != lend; l = l->next) {
+ if(l->orig.y+l->height < tkt->deltatv.y)
+ continue;
+ if(l->orig.y > tkt->deltatv.y + vh)
+ break;
+ if(!(l->flags&TkTdrawn)) {
+ e = tktdrawline(dst, tk, l, deltait);
+ if(e != nil)
+ return e;
+ }
+ }
+
+ tktreplclipr(dst, oclipr);
+ if(!reldone) {
+ p.x = orig.x + tk->act.x;
+ p.y = orig.y + tk->act.y;
+ tkdrawrelief(dst, tk, p, TkCbackgnd, tk->relief);
+ }
+ tkt->tflag &= ~TkTdlocked;
+
+ return nil;
+}
+
+/*
+ * Set the clipping rectangle of the destination image to the
+ * intersection of the current clipping rectangle and the area inside
+ * the text widget that needs to be redrawn.
+ * The caller should save the old one and restore it later.
+ */
+static void
+tktsetclip(Tk *tk)
+{
+ Rectangle r;
+ Image *dst;
+ TkText *tkt = TKobj(TkText, tk);
+
+ dst = tkt->image;
+ r.min = tkt->deltaiv;
+ r.max.x = r.min.x + tk->act.width - tk->ipad.x / 2;
+ r.max.y = r.min.y + tk->act.height - tk->ipad.y / 2;
+
+ if(!rectclip(&r, dst->clipr))
+ r.max = r.min;
+ tktreplclipr(dst, r);
+}
+
+static char*
+tktdrawline(Image *i, Tk *tk, TkTline *l, Point deltait)
+{
+ Tk *sub;
+ Font *f;
+ Image *bg;
+ Point p, q;
+ Rectangle r;
+ TkText *tkt;
+ TkTitem *it, *z;
+ int bevtop, bevbot;
+ TkEnv *e, *et, *env;
+ int *opts;
+ int o, bd, ul, ov, h, w, la, lh, cursorx, join;
+ char *err;
+
+ env = mallocz(sizeof(TkEnv), 0);
+ if(env == nil)
+ return TkNomem;
+ opts = mallocz(TkTnumopts*sizeof(int), 0);
+ if(opts == nil) {
+ free(env);
+ return TkNomem;
+ }
+ tkt = TKobj(TkText, tk);
+ e = tk->env;
+ et = env;
+ et->top = e->top;
+ f = e->font;
+
+ /* l->orig is in T space, p is in I space */
+ la = l->ascent;
+ lh = l->height;
+ p = addpt(l->orig, deltait);
+ p.y += la;
+/* if(tktdbg){print("drawline, p=(%d,%d), f->a=%d, f->h=%d\n", p.x, p.y, f->ascent, f->height); tktprintline(l);} */
+ cursorx = -1000;
+ join = 0;
+ for(it = l->items; it != nil; it = it->next) {
+ bg = tkgc(e, TkCbackgnd);
+ if(tktanytags(it)) {
+ tkttagopts(tk, it, opts, env, nil, 1);
+ if(e->colors[TkCbackgnd] != et->colors[TkCbackgnd]) {
+ bg = tkgc(et, TkCbackgnd);
+ r.min = p;
+ r.min.y -= la;
+ r.max.x = r.min.x + it->width;
+ r.max.y = r.min.y + lh;
+ draw(i, r, bg, nil, ZP);
+ }
+ o = opts[TkTrelief];
+ bd = opts[TkTborderwidth];
+ if((o == TKsunken || o == TKraised) && bd > 0) {
+ /* fit relief inside item bounding box */
+
+ q.x = p.x;
+ q.y = p.y - la;
+ if(it->width < 2*bd)
+ bd = it->width / 2;
+ if(lh < 2*bd)
+ bd = lh / 2;
+ w = it->width - 2*bd;
+ h = lh - 2*bd;
+ if(o == TKraised) {
+ bevtop = TkLightshade;
+ bevbot = TkDarkshade;
+ }
+ else {
+ bevtop = TkDarkshade;
+ bevbot = TkLightshade;
+ }
+
+ tkbevel(i, q, w, h, bd,
+ tkgc(et, TkCbackgnd+bevtop), tkgc(et, TkCbackgnd+bevbot));
+
+ /* join relief between adjacent items if tags match */
+ if(join) {
+ r.min.x = q.x;
+ r.max.x = q.x + bd;
+ r.min.y = q.y + bd;
+ r.max.y = r.min.y + h;
+ draw(i, r, bg, nil, ZP);
+ r.min.y = r.max.y;
+ r.max.y = r.min.y + bd;
+ draw(i, r, tkgc(et, TkCbackgnd+bevbot), nil, ZP);
+ }
+ for(z = it->next; z != nil && z->kind == TkTmark; )
+ z = z->next;
+ if(z != nil && tktsametags(z, it)) {
+ r.min.x = q.x + bd + w;
+ r.max.x = r.min.x + bd;
+ r.min.y = q.y;
+ r.max.y = q.y + bd;
+ draw(i, r, tkgc(et, TkCbackgnd+bevtop), nil, ZP);
+ r.min.y = r.max.y;
+ r.max.y = r.min.y + h;
+ draw(i, r, bg, nil, ZP);
+ join = 1;
+ }
+ else
+ join = 0;
+ }
+ o = opts[TkToffset];
+ ul = opts[TkTunderline];
+ ov = opts[TkToverstrike];
+ }
+ else {
+ et->font = f;
+ et->colors[TkCforegnd] = e->colors[TkCforegnd];
+ o = 0;
+ ul = 0;
+ ov = 0;
+ }
+
+ switch(it->kind) {
+ case TkTascii:
+ case TkTrune:
+ q.x = p.x;
+ q.y = p.y - env->font->ascent - o;
+/*if(tktdbg)print("q=(%d,%d)\n", q.x, q.y);*/
+ string(i, q, tkgc(et, TkCforegnd), q, env->font, it->istring);
+ if(ov == BoolT) {
+ r.min.x = q.x;
+ r.max.x = r.min.x + it->width;
+ r.min.y = q.y + 2*env->font->ascent/3;
+ r.max.y = r.min.y + 2;
+ draw(i, r, tkgc(et, TkCforegnd), nil, ZP);
+ }
+ if(ul == BoolT) {
+ r.min.x = q.x;
+ r.max.x = r.min.x + it->width;
+ r.max.y = p.y - la + lh;
+ r.min.y = r.max.y - 2;
+ draw(i, r, tkgc(et, TkCforegnd), nil, ZP);
+ }
+ break;
+ case TkTmark:
+ if((it->imark != nil)
+ && strcmp(it->imark->name, "insert") == 0) {
+ cursorx = p.x - 1;
+ }
+ break;
+ case TkTwin:
+ sub = it->iwin->sub;
+ if(sub != nil) {
+ int dirty;
+ sub->flag |= Tkrefresh;
+ sub->dirty = tkrect(sub, 1);
+ err = tkdrawslaves(sub, p, &dirty);
+ if(err != nil) {
+ free(opts);
+ free(env);
+ return err;
+ }
+ }
+ break;
+ }
+ p.x += it->width;
+ }
+ l->flags |= TkTdrawn;
+
+ /* do cursor last, so not overwritten by later items */
+ if(cursorx != -1000 && tkt->inswidth > 0) {
+ r.min.x = cursorx;
+ r.min.y = p.y - la;
+ r.max.x = r.min.x + tkt->inswidth;
+ r.max.y = r.min.y + lh;
+ r = rectsubpt(r, deltait);
+ if (!eqrect(tkt->cur_rec, r))
+ blinkreset(tk);
+ tkt->cur_rec = r;
+ if(tkt->cur_flag)
+ tktextcursordraw(tk, TkCforegnd);
+ }
+
+ free(opts);
+ free(env);
+ return nil;
+}
+
+static void
+tktextcursordraw(Tk *tk, int color)
+{
+ Rectangle r;
+ TkText *tkt;
+ Image *i;
+
+ tkt = TKobj(TkText, tk);
+
+ r = rectaddpt(tkt->cur_rec, subpt(tkt->deltaiv, tkt->deltatv));
+
+ /* check the cursor with widget boundary */
+ /* do nothing if entire cursor outside widget boundary */
+ if( ! ( r.max.x < tkt->deltaiv.x ||
+ r.min.x > tkt->deltaiv.x + tk->act.width ||
+ r.max.y < tkt->deltaiv.y ||
+ r.min.y > tkt->deltaiv.y + tk->act.height)) {
+
+ /* clip rectangle if extends beyond widget boundary */
+ if (r.min.x < tkt->deltaiv.x)
+ r.min.x = tkt->deltaiv.x;
+ if (r.max.x > tkt->deltaiv.x + tk->act.width)
+ r.max.x = tkt->deltaiv.x + tk->act.width;
+ if (r.min.y < tkt->deltaiv.y)
+ r.min.y = tkt->deltaiv.y;
+ if (r.max.y > tkt->deltaiv.y + tk->act.height)
+ r.max.y = tkt->deltaiv.y + tk->act.height;
+ i = tkimageof(tk);
+ if (i != nil)
+ draw(i, r, tkgc(tk->env, color), nil, ZP);
+ }
+}
+
+static void
+blinkreset(Tk *tk)
+{
+ TkText *tkt = TKobj(TkText, tk);
+ if (!tkhaskeyfocus(tk) || tk->flag&Tkdisabled)
+ return;
+ tkt->cur_flag = 1;
+ tkblinkreset(tk);
+}
+
+static void
+showcaret(Tk *tk, int on)
+{
+ TkText *tkt = TKobj(TkText, tk);
+ TkTline *l, *lend;
+ TkTitem *it;
+
+ tkt->cur_flag = on;
+ lend = &tkt->end;
+ for(l = tkt->start.next; l != lend; l = l->next) {
+ for (it = l->items; it != nil; it = it->next) {
+ if (it->kind == TkTmark && it->imark != nil &&
+ strcmp(it->imark->name, "insert") == 0) {
+ if (on) {
+ tktextcursordraw(tk, TkCforegnd);
+ tk->dirty = tkrect(tk, 1);
+ } else
+ tktnotdrawn(tk, l->orig.y, l->orig.y+l->height, 0);
+ tkdirty(tk);
+ return;
+ }
+ }
+ }
+}
+
+char*
+tktextcursor(Tk *tk, char* arg, char **ret)
+{
+ int on = 0;
+ USED(ret);
+
+ if (tk->flag&Tkdisabled)
+ return nil;
+
+ if(strcmp(arg, " insert") == 0) {
+ tkblink(tk, showcaret);
+ on = 1;
+ }
+ else
+ tkblink(nil, nil);
+
+ showcaret(tk, on);
+ return nil;
+}
+
+/*
+ * Insert string s just before ins, but don't worry about geometry values.
+ * Don't worry about doing wrapping correctly, but break long strings
+ * into pieces to avoid bad behavior in the wrapping code of tktfixgeom.
+ * If tagit != 0, use its tags, else use the intersection of tags of
+ * non cont or mark elements just before and just after insertion point.
+ * (At beginning and end of widget, just use the tags of one adjacent item).
+ * Keep *ins up-to-date.
+ */
+char*
+tktinsert(Tk *tk, TkTindex *ins, char *s, TkTitem *tagit)
+{
+ int c, n, nextra, nmax, atend, atbeg;
+ char *e, *p;
+ Rune r;
+ TkTindex iprev, inext;
+ TkTitem *i, *utagit;
+ TkText *tkt = TKobj(TkText, tk);
+
+ e = tktsplititem(ins);
+ if(e != nil)
+ return e;
+
+ /* if no tags give, use intersection of previous and next char tags */
+
+ nextra = 0;
+ n = tk->env->wzero;
+ if(n <= 0)
+ n = 8;
+ nmax = tk->act.width - tk->ipad.x;
+ if(nmax <= 0) {
+ if (tkt->propagate != BoolT || (tk->flag & Tksetwidth))
+ nmax = tk->req.width;
+ if(nmax <= 0)
+ nmax = 60*n;
+ }
+ nmax = (nmax + n - 1) / n;
+ utagit = nil;
+ if(tagit == nil) {
+ inext = *ins;
+ tktadjustind(tkt, TkTbycharstart, &inext);
+ atend = (inext.item->next == nil && inext.line->next == &tkt->end);
+ if(atend || tktanytags(inext.item)) {
+ iprev = *ins;
+ tktadjustind(tkt, TkTbycharback, &iprev);
+ atbeg = (iprev.line->prev == &tkt->start && iprev.line->items == iprev.item);
+ if(atbeg || tktanytags(iprev.item)) {
+ nextra = 0;
+ if(!atend)
+ nextra = inext.item->tagextra;
+ if(!atbeg && iprev.item->tagextra > nextra)
+ nextra = iprev.item->tagextra;
+ e = tktnewitem(TkTascii, nextra, &utagit);
+ if(e != nil)
+ return e;
+ if(!atend) {
+ tkttagcomb(utagit, inext.item, 1);
+ if(!atbeg)
+ tkttagcomb(utagit, iprev.item, 0);
+ }
+ else if(!atbeg)
+ tkttagcomb(utagit, iprev.item, 1);
+ tagit = utagit;
+ }
+ }
+ }
+ else
+ nextra = tagit->tagextra;
+
+ while((c = *s) != '\0') {
+ e = tktnewitem(TkTascii, nextra, &i);
+ if(e != nil) {
+ if(utagit != nil)
+ free(utagit);
+ return e;
+ }
+
+ if(tagit != nil)
+ tkttagcomb(i, tagit, 1);
+
+ if(c == '\n') {
+ i->kind = TkTnewline;
+ tkt->nlines++;
+ s++;
+ }
+ else
+ if(c == '\t') {
+ i->kind = TkTtab;
+ s++;
+ }
+ else {
+ p = s;
+ n = 0;
+ i->kind = TkTascii;
+ while(c != '\0' && c != '\n' && c != '\t' && n < nmax){
+ s += chartorune(&r, s);
+ c = *s;
+ n++;
+ }
+ /*
+ * if more bytes than runes, then it's not all ascii, so create a TkTrune item
+ */
+ if(s - p > n)
+ i->kind = TkTrune;
+ n = s - p;
+ i->istring = malloc(n+1);
+ if(i->istring == nil) {
+ tktfreeitems(tkt, i, 1);
+ if(utagit != nil)
+ free(utagit);
+ return TkNomem;
+ }
+ memmove(i->istring, p, n);
+ i->istring[n] = '\0';
+ }
+ e = tktiteminsert(tkt, ins, i);
+ if(e != nil) {
+ if(utagit != nil)
+ free(utagit);
+ tktfreeitems(tkt, i, 1);
+ return e;
+ }
+ }
+
+ if(utagit != nil)
+ free(utagit);
+ return nil;
+}
+
+void
+tktextsize(Tk *tk, int dogeom)
+{
+ TkText *tkt;
+ TkGeom g;
+ tkt = TKobj(TkText, tk);
+ if (tkt->propagate == BoolT) {
+ g = tk->req;
+ if ((tk->flag & Tksetwidth) == 0)
+ tk->req.width = tktmaxwid(tkt->start.next);
+ if ((tk->flag & Tksetheight) == 0)
+ tk->req.height = tkt->end.orig.y;
+ if (dogeom)
+ tkgeomchg(tk, &g, tk->borderwidth);
+ }
+}
+
+static int
+maximum(int a, int b)
+{
+ if (a > b)
+ return a;
+ return b;
+}
+
+/*
+ * For lines l1->next, ..., l2, fix up the geometry
+ * elements of constituent TkTlines and TkTitems.
+ * This involves doing proper line wrapping, and calculating item
+ * widths and positions.
+ * Also, merge any adjacent TkTascii/TkTrune items with the same tags.
+ * Finally, bump the y component of lines l2->next, ... end.
+ * l2 should not be tkt->end.
+ *
+ * if finalwidth is 0, we're trying to work out what the
+ * width and height should be. if propagation is off,
+ * it's irrelevant; otherwise it must assume that
+ * its desired width will be fulfilled, as the packer
+ * doesn't iterate...
+ *
+ * N.B. this function rearranges lines, merges and splits items.
+ * this means that in general the item and line pointed to
+ * by any index might have been freed after tktfixgeom
+ * has been called.
+ */
+char*
+tktfixgeom(Tk *tk, TkTline *l1, TkTline *l2, int finalwidth)
+{
+ int x, y, a, wa, h, w, o, n, j, sp3, xleft, xright, winw, oa, oh, lh;
+ int wrapmode, just, needsplit;
+ char *e, *s;
+ TkText *tkt;
+ Tk *sub;
+ TkTitem *i, *it, *ilast, *iprev;
+ TkTindex ix, ixprev, ixw;
+ TkTline *l, *lafter;
+ Interval oldi, hole, rest, newrest;
+ TkEnv *env;
+ Font *f;
+ int *opts;
+ TkTtabstop *tb;
+
+ tkt = TKobj(TkText, tk);
+
+ if(tktdbg)
+ tktcheck(tkt, "tktfixgeom");
+
+ if (!finalwidth && tkt->propagate == BoolT) {
+ if ((tk->flag & Tksetwidth) == 0)
+ winw = 1000000;
+ else
+ winw = tk->req.width;
+ } else {
+ winw = tk->act.width - tk->ipad.x;
+ if(winw <= 0)
+ winw = tk->req.width;
+ }
+ if(winw < 0)
+ return nil;
+
+ /*
+ * Make lafter be the first line after l2 that comes after a newline
+ * (so that wrap correction cannot affect it)
+ */
+ lafter = l2->next;
+ if(tktdbg && lafter == nil) {
+ print("tktfixgeom: botch 1\n");
+ return nil;
+ }
+ while((lafter->flags & TkTfirst) == 0 && lafter != &tkt->end)
+ lafter = lafter->next;
+
+
+ y = l1->orig.y + l1->height + tktpostspace(tk, l1);
+
+ oldi.lo = y;
+ oldi.hi = lafter->orig.y;
+ rest.lo = oldi.hi;
+ rest.hi = rest.lo + 1000; /* get background after end, too */
+
+ opts = mallocz(TkTnumopts*sizeof(int), 0);
+ if(opts == nil)
+ return TkNomem;
+ env = mallocz(sizeof(TkEnv), 0);
+ if(env == nil) {
+ free(opts);
+ return TkNomem;
+ }
+
+ for(l = l1->next; l != lafter; l = l->next) {
+ if(tktdbg && l == nil) {
+ print("tktfixgeom: botch 2\n");
+ free(opts);
+ free(env);
+ return nil;
+ }
+
+ l->flags &= ~TkTdrawn;
+
+ /* some spacing depends on tags of first non-mark on display line */
+ iprev = nil;
+ for(i = l->items; i->kind == TkTmark; ) {
+ iprev = i;
+ i = i->next;
+ }
+ tkttagopts(tk, i, opts, env, &tb, 1);
+
+ if(l->flags&TkTfirst) {
+ xleft = opts[TkTlmargin1];
+ y += opts[TkTspacing1];
+ }
+ else {
+ xleft = opts[TkTlmargin2];
+ y += opts[TkTspacing2];
+ }
+ sp3 = opts[TkTspacing3];
+ just = opts[TkTjustify];
+
+ wrapmode = opts[TkTwrap];
+ f = env->font;
+ h = f->height;
+ lh = opts[TkTlineheight];
+ a = f->ascent;
+ x = xleft;
+ xright = winw - opts[TkTrmargin];
+ if(xright < xleft)
+ xright = xleft;
+
+ /*
+ * perform line wrapping and calculate h (height) and a (ascent)
+ * for the current line
+ */
+ for(; i != nil; iprev = i, i = i->next) {
+ again:
+ if(i->kind == TkTmark)
+ continue;
+ if(i->kind == TkTnewline)
+ break;
+ if(i->kind == TkTcontline) {
+ /*
+ * See if some of following line fits on this one.
+ * First, ensure that following line isn't empty.
+ */
+ it = l->next->items;
+ while(it->kind == TkTmark)
+ it = it->next;
+
+ if(it->kind == TkTnewline || it->kind == TkTcontline) {
+ /* next line is empty; join it to this one by removing i */
+ ix.item = i;
+ ix.line = l;
+ ix.pos = 0;
+ tktremitem(tkt, &ix);
+ it = l->next->items;
+ if(iprev == nil)
+ i = l->items;
+ else
+ i = iprev->next;
+ goto again;
+ }
+
+ n = xright - x;
+ if(n <= 0)
+ break;
+ ixprev.line = l;
+ ixprev.item = i;
+ ixprev.pos = 0;
+ ix = ixprev;
+ tktadjustind(tkt, TkTbychar, &ix);
+ if(wrapmode == Tkwrapword)
+ tktadjustind(tkt, TkTbywrapend, &ix);
+ if(wrapmode != Tkwrapnone && tktwidbetween(tk, x, &ixprev, &ix) > n)
+ break;
+ /* move one item up from next line and try again */
+ it = l->next->items;
+ if(tktdbg && (it == nil || it->kind == TkTnewline || it->kind == TkTcontline)) {
+ print("tktfixgeom: botch 3\n");
+ free(opts);
+ free(env);
+ return nil;
+ }
+ if(iprev == nil)
+ l->items = it;
+ else
+ iprev->next = it;
+ l->next->items = it->next;
+ it->next = i;
+ i = it;
+ goto again;
+ }
+
+ oa = a;
+ oh = h;
+ if(!tktanytags(i)) {
+ env->font = tk->env->font;
+ o = 0;
+ }
+ else {
+ tkttagopts(tk, i, opts, env, nil, 1);
+ o = opts[TkToffset];
+ }
+ if((o != 0 || env->font != f) && i->kind != TkTwin) {
+ /* check ascent of current item */
+ n = o+env->font->ascent;
+ if(n > a) {
+ a = n;
+ h += (a - oa);
+ }
+ /* check descent of current item */
+ n = (env->font->height - env->font->ascent) - o;
+ if(n > h-a)
+ h = a + n;
+ }
+ if(i->kind == TkTwin && i->iwin->sub != nil) {
+ sub = i->iwin->sub;
+ n = 2 * i->iwin->pady + sub->act.height +
+ 2 * sub->borderwidth;
+ switch(i->iwin->align) {
+ case Tktop:
+ case Tkbottom:
+ if(n > h)
+ h = n;
+ break;
+ case Tkcenter:
+ if(n/2 > a)
+ a = n/2;
+ if(n/2 > h-a)
+ h = a + n/2;
+ break;
+ case Tkbaseline:
+ wa = i->iwin->ascent;
+ if (wa == -1)
+ wa = n;
+ h = maximum(a, wa) + maximum(h - a, n - wa);
+ a = maximum(a, wa);
+ break;
+ }
+ }
+
+ w = tktdispwidth(tk, tb, i, env->font, x, 0, -1);
+ n = x + w - xright;
+ if(n > 0 && wrapmode != Tkwrapnone) {
+ /* find shortest suffix that can be removed to fit item */
+ j = tktposcount(i) - 1;
+ while(j > 0 && tktdispwidth(tk, tb, i, env->font, x, j, -1) < n)
+ j--;
+ /* put at least one item on a line before splitting */
+ if(j == 0 && x == xleft) {
+ if(tktposcount(i) == 1)
+ goto Nosplit;
+ j = 1;
+ }
+ ix.line = l;
+ ix.item = i;
+ ix.pos = j;
+ if(wrapmode == Tkwrapword) {
+ /* trim the item at the first word at or before the shortest suffix */
+ /* TO DO: convert any resulting trailing white space to zero width */
+ ixw = ix;
+ if(tktisbreak(tktindrune(&ixw))) {
+ /* at break character, find end of word preceding it */
+ while(tktisbreak(tktindrune(&ixw))){
+ if(!tktadjustind(tkt, TkTbycharback, &ixw) ||
+ ixw.line != l || ixw.item == l->items && ixw.pos == 0)
+ goto Wrapchar; /* no suitable point, degrade to char wrap */
+ }
+ ix = ixw;
+ }
+ /* now find start of word */
+ tktadjustind(tkt, TkTbywrapstart, &ixw);
+ if(ixw.line == l && (ixw.item != l->items || ixw.pos > 0)){
+ /* it will leave something on the line, so reasonable to split here */
+ ix = ixw;
+ }
+ /* otherwise degrade to char wrap */
+ }
+ Wrapchar:
+ if(ix.pos > 0) {
+ needsplit = 1;
+ e = tktsplititem(&ix);
+ if(e != nil) {
+ free(opts);
+ free(env);
+ return e;
+ }
+ }
+ else
+ needsplit = 0;
+
+ e = tktnewitem(TkTcontline, 0, &it);
+ if(e != nil) {
+ free(opts);
+ free(env);
+ return e;
+ }
+ e = tktiteminsert(tkt, &ix, it);
+ if(e != nil) {
+ tktfreeitems(tkt, it, 1);
+ free(opts);
+ free(env);
+ return e;
+ }
+
+ l = l->prev; /* work on part of line up to split */
+
+ if(needsplit) {
+ /* have to calculate width of pre-split part */
+ ixprev = ix;
+ if(tktadjustind(tkt, TkTbyitemback, &ixprev) &&
+ tktadjustind(tkt, TkTbyitemback, &ixprev)) {
+ w = tktdispwidth(tk, tb, ixprev.item, nil, x, 0, -1);
+ ixprev.item->width = w;
+ x += w;
+ }
+ }
+ else {
+ h = oh;
+ a = oa;
+ }
+ break;
+ }
+ else {
+ Nosplit:
+ i->width =w;
+ x += w;
+ }
+ }
+ if (a > h)
+ h = a;
+ if (lh == 0)
+ lh = f->height;
+ if (lh > h) {
+ a += (lh - h) / 2;
+ h = lh;
+ }
+
+ /*
+ * Now line l is broken correctly and has correct item widths/line height/ascent.
+ * Merge adjacent TkTascii/TkTrune items with same tags.
+ * Also, set act{x,y} of embedded widgets to offset from
+ * left of item box at baseline.
+ */
+ for(i = l->items; i->next != nil; i = i->next) {
+ it = i->next;
+ if( (i->kind == TkTascii || i->kind == TkTrune)
+ &&
+ i->kind == it->kind
+ &&
+ tktsametags(i, it)) {
+ n = strlen(i->istring);
+ j = strlen(it->istring);
+ s = realloc(i->istring, n + j + 1);
+ if(s == nil) {
+ free(opts);
+ free(env);
+ return TkNomem;
+ }
+ i->istring = s;
+ memmove(i->istring+n, it->istring, j+1);
+ i->width += it->width;
+ i->next = it->next;
+ it->next = nil;
+ tktfreeitems(tkt, it, 1);
+ }
+ else if(i->kind == TkTwin && i->iwin->sub != nil) {
+ sub = i->iwin->sub;
+ n = sub->act.height + 2 * sub->borderwidth;
+ o = i->iwin->pady;
+ sub->act.x = i->iwin->padx;
+ /*
+ * sub->act.y is y-origin of widget relative to baseline.
+ */
+ switch(i->iwin->align) {
+ case Tktop:
+ sub->act.y = o - a;
+ break;
+ case Tkbottom:
+ sub->act.y = h - (o + n) - a;
+ break;
+ case Tkcenter:
+ sub->act.y = (h - n) / 2 - a;
+ break;
+ case Tkbaseline:
+ wa = i->iwin->ascent;
+ if (wa == -1)
+ wa = n;
+ sub->act.y = -wa;
+ break;
+ }
+ }
+ }
+
+ l->width = x - xleft;
+
+ /* justification bug: wrong if line has tabs */
+ l->orig.x = xleft;
+ n = xright - x;
+ if(n > 0) {
+ if(just == Tkright)
+ l->orig.x += n;
+ else
+ if(just == Tkcenter)
+ l->orig.x += n/2;
+ }
+
+ /* give newline or contline width up to right margin */
+ ilast = tktlastitem(l->items);
+ ilast->width = xright - l->width;
+ if(ilast->width < 0)
+ ilast->width = 0;
+
+ l->orig.y = y;
+ l->height = h;
+ l->ascent = a;
+ y += h;
+ if(l->flags&TkTlast)
+ y += sp3;
+ }
+ free(opts);
+ free(env);
+
+ tktdrawbg(tk, oldi.lo, oldi.hi, 0);
+
+ y += tktprespace(tk, l);
+ newrest.lo = y;
+ newrest.hi = y + rest.hi - rest.lo;
+
+ hole = tkttranslate(tk, newrest, rest.lo);
+
+ tktdrawbg(tk, hole.lo, hole.hi, 0);
+
+ if(l != &tkt->end) {
+ while(l != &tkt->end) {
+ oh = l->next->orig.y - l->orig.y;
+ l->orig.y = y;
+ if(y + oh > hole.lo && y < hole.hi) {
+ l->flags &= ~TkTdrawn;
+ }
+ y += oh;
+ l = l->next;
+ }
+ }
+ tkt->end.orig.y = tkt->end.prev->orig.y + tkt->end.prev->height;
+
+ if(tkt->deltatv.y > tkt->end.orig.y)
+ tkt->deltatv.y = tkt->end.prev->orig.y;
+
+
+ e = tktsetscroll(tk, Tkvertical);
+ if(e != nil)
+ return e;
+ e = tktsetscroll(tk, Tkhorizontal);
+ if(e != nil)
+ return e;
+
+ tk->dirty = tkrect(tk, 1);
+ if(tktdbg)
+ tktcheck(tkt, "tktfixgeom end");
+ return nil;
+}
+
+static int
+tktpostspace(Tk *tk, TkTline *l)
+{
+ int ans;
+ TkTitem *i;
+ TkEnv env;
+ int *opts;
+
+ opts = mallocz(TkTnumopts*sizeof(int), 0);
+ if(opts == nil)
+ return 0;
+ ans = 0;
+ if(l->items != nil && (l->flags&TkTlast)) {
+ for(i = l->items; i->kind == TkTmark; )
+ i = i->next;
+ tkttagopts(tk, i, opts, &env, nil, 1);
+ ans = opts[TkTspacing3];
+ }
+ free(opts);
+ return ans;
+}
+
+static int
+tktprespace(Tk *tk, TkTline *l)
+{
+ int ans;
+ TkTitem *i;
+ TkEnv env;
+ int *opts;
+
+ opts = mallocz(TkTnumopts*sizeof(int), 0);
+ if(opts == nil)
+ return 0;
+
+ ans = 0;
+ if(l->items != nil) {
+ for(i = l->items; i->kind == TkTmark; )
+ i = i->next;
+ tkttagopts(tk, i, opts, &env, nil, 1);
+ if(l->flags&TkTfirst)
+ ans = opts[TkTspacing1];
+ else
+ ans = opts[TkTspacing2];
+ }
+ free(opts);
+ return ans;
+}
+
+static int
+tktwidbetween(Tk *tk, int x, TkTindex *i1, TkTindex *i2)
+{
+ int d, w, n;
+ TkTindex ix;
+ TkText *tkt = TKobj(TkText, tk);
+
+ w = 0;
+ ix = *i1;
+ while(ix.item != i2->item) {
+ /* probably wrong w.r.t tag tabs */
+ d = tktdispwidth(tk, nil, ix.item, nil, x, ix.pos, -1);
+ w += d;
+ x += d;
+ if(!tktadjustind(tkt, TkTbyitem, &ix)) {
+ if(tktdbg)
+ print("tktwidbetween botch\n");
+ break;
+ }
+ }
+ n = i2->pos - ix.pos;
+ if(n > 0)
+ /* probably wrong w.r.t tag tabs */
+ w += tktdispwidth(tk, nil, ix.item, nil, x, ix.pos, i2->pos-ix.pos);
+ return w;
+}
+
+static Interval
+tktvclip(Interval i, int vh)
+{
+ if(i.lo < 0)
+ i.lo = 0;
+ if(i.hi > vh)
+ i.hi = vh;
+ return i;
+}
+
+/*
+ * Do translation of any part of interval that appears on screen
+ * starting at srcy to its new position, dsti.
+ * Return y-range of the hole left in the image (either because
+ * the src bits were out of the V window, or because the src bits
+ * vacated an area of the V window).
+ * The coordinates passed in and out are in T space.
+ */
+static Interval
+tkttranslate(Tk *tk, Interval dsti, int srcy)
+{
+ int vh, vw, dvty, locked;
+ TkText *tkt;
+ Image *i;
+ Interval hole, vdst, vsrc;
+ Point src;
+ Rectangle dst;
+ Display *d;
+
+ hole.hi = 0;
+ hole.lo = 0;
+
+
+ /*
+ * If we are embedded in a text widget, we need to come in through
+ * the tkdrawtext routine, to ensure our clipr is set properly, so we
+ * just punt in that case.
+ * XXX is just checking parent good enough. what if we're in
+ * a frame in a text widget?
+ * BUG!
+
+ * if(tk->parent != nil && tk->parent->type == TKtext) {
+ * tk->flag |= Tkrefresh;
+ * return hole;
+ * }
+ */
+ tkt = TKobj(TkText, tk);
+ dvty = tkt->deltatv.y;
+ i = tkt->image;
+
+ vw = tk->act.width - tk->ipad.x;
+ vh = tk->act.height - tk->ipad.y;
+
+ /* convert to V space */
+ vdst.lo = dsti.lo - dvty;
+ vdst.hi = dsti.hi - dvty;
+ vsrc.lo = srcy - dvty;
+ vsrc.hi = vsrc.lo + dsti.hi - dsti.lo;
+ if(vsrc.lo == vsrc.hi || vsrc.lo == vdst.lo)
+ return hole;
+ else if(vsrc.hi <= 0 || vsrc.lo >= vh)
+ hole = tktvclip(vdst, vh);
+ else if(vdst.hi <= 0 || vdst.lo >= vh)
+ hole = tktvclip(vsrc, vh);
+ else if(i != nil) {
+ src.x = 0;
+ src.y = vsrc.lo;
+ if(vdst.lo > vsrc.lo) { /* see earlier text lines */
+ if(vsrc.lo < 0) {
+ src.y = 0;
+ vdst.lo -= vsrc.lo;
+ }
+ if(vdst.hi > vh)
+ vdst.hi = vh;
+ hole.lo = src.y;
+ hole.hi = vdst.lo;
+ }
+ else { /* see later text lines */
+ if(vsrc.hi > vh)
+ vdst.hi -= (vsrc.hi - vh);
+ if(vdst.lo < 0){
+ src.y -= vdst.lo;
+ vdst.lo = 0;
+ }
+ hole.lo = vdst.hi;
+ hole.hi = src.y + (vdst.hi - vdst.lo);
+ }
+ if(vdst.hi > vdst.lo && (tkt->tflag&TkTdrawn)) {
+ src = addpt(src, tkt->deltaiv);
+ dst = rectaddpt(Rect(0, vdst.lo, vw, vdst.hi), tkt->deltaiv);
+ d = tk->env->top->display;
+ locked = 0;
+ if(!(tkt->tflag&TkTdlocked))
+ locked = lockdisplay(d);
+ i = tkimageof(tk);
+ tkt->image = i;
+ if(i != nil)
+ draw(i, dst, i, nil, src);
+ if(locked)
+ unlockdisplay(d);
+ }
+ }
+ hole.lo += dvty;
+ hole.hi += dvty;
+ return hole;
+}
+
+/*
+ * mark lines from firsty to lasty as not drawn.
+ * firsty and lasty are in T space
+ */
+static void
+tktnotdrawn(Tk *tk, int firsty, int lasty, int all)
+{
+ TkTline *lend, *l;
+ TkText *tkt = TKobj(TkText, tk);
+ if(firsty >= lasty && !all)
+ return;
+ lend = &tkt->end;
+ for(l = tkt->start.next; l != lend; l = l->next) {
+ if(l->orig.y+l->height <= firsty)
+ continue;
+ if(l->orig.y >= lasty)
+ break;
+ l->flags &= ~TkTdrawn;
+ if (firsty > l->orig.y)
+ firsty = l->orig.y;
+ if (lasty < l->orig.y+l->height)
+ lasty = l->orig.y+l->height;
+ }
+ tktdrawbg(tk, firsty, lasty, all);
+ tk->dirty = tkrect(tk, 1);
+}
+
+/*
+ * firsty and lasty are in T space
+ */
+static void
+tktdrawbg(Tk *tk, int firsty, int lasty, int all)
+{
+ int vw, vh, locked;
+ Rectangle r;
+ Image *i;
+ Display *d;
+ TkText *tkt = TKobj(TkText, tk);
+
+ if(tk->env->top->root->flag & Tksuspended){
+ tk->flag |= Tkrefresh;
+ return;
+ }
+ /*
+ * If we are embedded in a text widget, we need to come in through
+ * the tkdrawtext routine, to ensure our clipr is set properly, so we
+ * just punt in that case.
+ * BUG!
+ * if(tk->parent != nil && tk->parent->type == TKtext) {
+ * tk->flag |= Tkrefresh;
+ * return;
+ * }
+ */
+ vw = tk->act.width - tk->ipad.x;
+ vh = tk->act.height - tk->ipad.y;
+ if(all) {
+ /* whole background is to be drawn, not just until last line */
+ firsty = 0;
+ lasty = 100000;
+ }
+ if(firsty >= lasty)
+ return;
+ firsty -= tkt->deltatv.y;
+ lasty -= tkt->deltatv.y;
+ if(firsty < 0)
+ firsty = 0;
+ if(lasty > vh)
+ lasty = vh;
+ r = rectaddpt(Rect(0, firsty, vw, lasty), tkt->deltaiv);
+ if(r.min.y < r.max.y && (tkt->tflag&TkTdrawn)) {
+ d = tk->env->top->display;
+ locked = 0;
+ if(!(tkt->tflag&TkTdlocked))
+ locked = lockdisplay(d);
+ i = tkimageof(tk);
+ tkt->image = i;
+ if(i != nil)
+ draw(i, r, tkgc(tk->env, TkCbackgnd), nil, ZP);
+ if(locked)
+ unlockdisplay(d);
+ }
+}
+
+static void
+tktfixscroll(Tk *tk, Point odeltatv)
+{
+ int lasty;
+ Interval oi, hole;
+ Rectangle oclipr;
+ Image *dst;
+ Point ndeltatv;
+ TkText *tkt = TKobj(TkText, tk);
+
+ ndeltatv = tkt->deltatv;
+
+ if(eqpt(odeltatv, ndeltatv))
+ return;
+
+ /* set clipr to avoid spilling outside (in case didn't come in through draw) */
+ dst = tkimageof(tk);
+ if(dst != nil) {
+ tkt->image = dst;
+ oclipr = dst->clipr;
+ tktsetclip(tk);
+ }
+
+ lasty = tkt->end.orig.y;
+ if(odeltatv.x != ndeltatv.x)
+ tktnotdrawn(tk, ndeltatv.y, lasty, 0);
+ else {
+ oi.lo = odeltatv.y;
+ oi.hi = lasty;
+ hole = tkttranslate(tk, oi, ndeltatv.y);
+ tktnotdrawn(tk, hole.lo, hole.hi, 0);
+ }
+ if(dst != nil)
+ tktreplclipr(dst, oclipr);
+}
+
+void
+tktextgeom(Tk *tk)
+{
+ TkTindex ix;
+ Rectangle oclipr;
+ Image *dst;
+ TkText *tkt = TKobj(TkText, tk);
+ char buf[20], *p;
+
+ tkt->tflag &= ~TkTdrawn;
+ tktsetdeltas(tk, ZP);
+ /* find index of current top-left, so can see it again */
+ tktxyind(tk, 0, 0, &ix);
+ /* make sure scroll bar is redrawn */
+ tkt->scrolltop[Tkvertical] = -1;
+ tkt->scrolltop[Tkhorizontal] = -1;
+ tkt->scrollbot[Tkvertical] = -1;
+ tkt->scrollbot[Tkhorizontal] = -1;
+
+ /* set clipr to avoid spilling outside (didn't come in through draw) */
+ dst = tkimageof(tk);
+ if(dst != nil) {
+ tkt->image = dst;
+ oclipr = dst->clipr;
+ tktsetclip(tk);
+ }
+
+ /*
+ * have to save index in a reusable format, as
+ * tktfixgeom can free everything that ix points to.
+ */
+ snprint(buf, sizeof(buf), "%d.%d", tktlinenum(tkt, &ix), tktlinepos(tkt, &ix));
+ tktfixgeom(tk, &tkt->start, tkt->end.prev, 1);
+ p = buf;
+ tktindparse(tk, &p, &ix); /* restore index to something close to original value */
+ tktsee(tk, &ix, 1);
+
+ if(dst != nil)
+ tktreplclipr(dst, oclipr);
+}
+
+static char*
+tktsetscroll(Tk *tk, int orient)
+{
+ TkText *tkt;
+ TkTline *l;
+ int ntot, nmin, nmax, top, bot, vw, vh;
+ char *val, *cmd, *v, *e, *s;
+
+ tkt = TKobj(TkText, tk);
+
+ s = (orient == Tkvertical)? tkt->yscroll : tkt->xscroll;
+ if(s == nil)
+ return nil;
+
+ vw = tk->act.width - tk->ipad.x;
+ vh = tk->act.height - tk->ipad.y;
+
+ if(orient == Tkvertical) {
+ l = tkt->end.prev;
+ ntot = l->orig.y + l->height;
+ nmin = tkt->deltatv.y;
+ if(vh <= 0)
+ nmax = nmin;
+ else
+ nmax = nmin + vh;
+ }
+ else {
+ ntot = tktmaxwid(tkt->start.next);
+ nmin = tkt->deltatv.x;
+ if(vw <= 0)
+ nmax = nmin;
+ else
+ nmax = nmin + vw;
+ }
+
+ if(ntot == 0) {
+ top = 0;
+ bot = TKI2F(1);
+ }
+ else {
+ if(ntot < nmax)
+ ntot = nmax;
+ top = TKI2F(nmin)/ntot;
+ bot = TKI2F(nmax)/ntot;
+ }
+
+ if(tkt->scrolltop[orient] == top && tkt->scrollbot[orient] == bot)
+ return nil;
+
+ tkt->scrolltop[orient] = top;
+ tkt->scrollbot[orient] = bot;
+
+ val = mallocz(Tkminitem, 0);
+ if(val == nil)
+ return TkNomem;
+ cmd = mallocz(Tkmaxitem, 0);
+ if(cmd == nil) {
+ free(val);
+ return TkNomem;
+ }
+
+ v = tkfprint(val, top);
+ *v++ = ' ';
+ tkfprint(v, bot);
+ snprint(cmd, Tkmaxitem, "%s %s", s, val);
+ e = tkexec(tk->env->top, cmd, nil);
+ free(cmd);
+ free(val);
+ return e;
+}
+
+static char*
+tktview(Tk *tk, char *arg, char **val, int nl, int *posn, int max, int orient)
+{
+ int top, bot, amount, n;
+ char buf[Tkminitem], *v, *e;
+
+ if(*arg == '\0') {
+ if ( max == 0 ) {
+ top = 0;
+ bot = TKI2F(1);
+ }
+ else {
+ top = TKI2F(*posn)/max;
+ bot = TKI2F(*posn+nl)/max;
+ if (bot > TKI2F(1))
+ bot = TKI2F(1);
+ }
+ v = tkfprint(buf, top);
+ *v++ = ' ';
+ tkfprint(v, bot);
+ return tkvalue(val, "%s", buf);
+ }
+
+ arg = tkword(tk->env->top, arg, buf, buf+sizeof(buf), nil);
+ if(strcmp(buf, "moveto") == 0) {
+ e = tkfracword(tk->env->top, &arg, &top, nil);
+ if (e != nil)
+ return e;
+ *posn = TKF2I(top*max);
+ }
+ else
+ if(strcmp(buf, "scroll") == 0) {
+ e = tkfracword(tk->env->top, &arg, &amount, nil);
+ if(e != nil)
+ return e;
+ arg = tkskip(arg, " \t");
+ if(*arg == 'p') /* Pages */
+ amount *= nl;
+ else /* Lines or Characters */
+ if(orient == Tkvertical) {
+ /* XXX needs improvement */
+ amount *= tk->env->font->height;
+ }
+ else
+ amount *= tk->env->wzero;
+ amount = TKF2I(amount);
+ n = *posn + amount;
+ if(n < 0)
+ n = 0;
+ if(n > max)
+ n = max;
+ *posn = n;
+ }
+ else
+ return TkBadcm;
+
+ bot = max - (nl * 3 / 4);
+ if(*posn > bot)
+ *posn = bot;
+ if(*posn < 0)
+ *posn = 0;
+
+ return nil;
+}
+
+static void
+tktclearsel(Tk *tk)
+{
+ TkTindex ibeg, iend;
+ TkText *tkt = TKobj(TkText, tk);
+
+ if(tkt->selfirst == nil)
+ return;
+ tktitemind(tkt->selfirst, &ibeg);
+ tktitemind(tkt->sellast, &iend);
+
+ tkttagchange(tk, TkTselid, &ibeg, &iend, 0);
+}
+
+static int
+tktgetsel(Tk *tk, TkTindex *i1, TkTindex *i2)
+{
+ TkText *tkt =TKobj(TkText, tk);
+
+ if(tkt->selfirst == nil)
+ return 0;
+ tktitemind(tkt->selfirst, i1);
+ tktitemind(tkt->sellast, i2);
+ return 1;
+}
+
+/*
+ * Adjust tkt->deltatv so that indexed character is visible.
+ * - if seetop is true, make indexed char be at top of window
+ * - if it is already visible, do nothing.
+ * - if it is > 1/2 screenful off edge of screen, center it
+ * else put it at bottom or top (whichever is nearer)
+ * - if first line is visible, put it at top
+ * - if last line is visible, allow one blank line at bottom
+ *
+ * BUG: should handle x visibility too
+ */
+static void
+tktsee(Tk *tk, TkTindex *ixp, int seetop)
+{
+ int ycur, ynext, deltatvy, adjy, h;
+ Point p, odeltatv;
+ Rectangle bbox;
+ TkTline *l, *el;
+ TkText *tkt = TKobj(TkText, tk);
+ TkTindex ix;
+
+ ix = *ixp;
+ deltatvy = tkt->deltatv.y;
+ odeltatv = tkt->deltatv;
+ h = tk->act.height;
+
+ /* find p (in T space): top left of indexed line */
+ l = ix.line;
+ p = l->orig;
+
+ /* ycur, ynext in V space */
+ ycur = p.y - deltatvy;
+ ynext = ycur + l->height;
+ adjy = 0;
+
+ /* quantize h to line boundaries (works if single font) */
+ if ( l->height )
+ h -= h%l->height;
+
+ if(seetop) {
+ deltatvy = p.y;
+ adjy = 1;
+ }
+ else
+ if(ycur < 0 || ynext >= h) {
+ adjy = 1;
+
+ if(ycur < -h/2 || ycur > 3*h/2)
+ deltatvy = p.y - h/2;
+ else if(ycur < 0)
+ deltatvy = p.y;
+ else
+ deltatvy = p.y - h + l->height;
+
+ el = tkt->end.prev;
+ if(el != nil && el->orig.y - deltatvy < h)
+ deltatvy = tkt->end.orig.y - (h * 3 / 4);
+
+ if(p.y - deltatvy < 0)
+ deltatvy = p.y;
+ if(deltatvy < 0)
+ deltatvy = 0;
+ }
+ if(adjy) {
+ tkt->deltatv.y = deltatvy;
+ tktsetscroll(tk, Tkvertical); /* XXX - Tad: err ignored */
+ tktfixscroll(tk, odeltatv);
+ }
+ while (ix.item->kind == TkTmark)
+ ix.item = ix.item->next;
+ bbox = tktbbox(tk, &ix);
+ /* make sure that cursor at the end gets shown */
+ tksee(tk, bbox, Pt(bbox.min.x, (bbox.min.y + bbox.max.y) / 2));
+}
+
+static int
+tktcmatch(int c1, int c2, int nocase)
+{
+ if(nocase) {
+ if(c1 >= 'a' && c1 <= 'z')
+ c1 -= 'a' - 'A';
+ if(c2 >= 'a' && c2 <= 'z')
+ c2 -= 'a' - 'A';
+ }
+ return (c1 == c2);
+}
+
+/*
+ * Return 1 if tag with id m1 ends before tag with id m2,
+ * starting at the item after that indexed in ix (but don't
+ * modify ix).
+ */
+static int
+tagendsbefore(TkText *tkt, TkTindex *ix, int m1, int m2)
+{
+ int s1, s2;
+ TkTindex ix1;
+ TkTitem *i;
+
+ ix1 = *ix;
+ while(tktadjustind(tkt, TkTbyitem, &ix1)) {
+ i = ix1.item;
+ if(i->kind == TkTwin || i->kind == TkTcontline || i->kind == TkTmark)
+ continue;
+ s1 = tkttagset(i, m1);
+ s2 = tkttagset(i, m2);
+ if(!s1)
+ return s2;
+ else if(!s2)
+ return 0;
+ }
+ return 0;
+}
+
+static int
+tktsgmltags(TkText *tkt, Fmt *fmt, TkTitem *iprev, TkTitem *i, TkTindex *ix, int *stack, int *pnstack, int *tmpstack)
+{
+ int nprev, n, m, r, k, j, ii, onstack, nt;
+
+ nprev = 0;
+ if(iprev != nil && (iprev->tags[0] != 0 || iprev->tagextra > 0))
+ nprev = 32*(iprev->tagextra + 1);
+ n = 0;
+ if(i != nil && (i->tags[0] != 0 || i->tagextra > 0))
+ n = 32*(i->tagextra + 1);
+ nt = 0;
+ if(n > 0) {
+ /* find tags which open here */
+ for(m = 0; m < n; m++)
+ if(tkttagset(i, m) && (iprev == nil || !tkttagset(iprev, m)))
+ tmpstack[nt++] = m;
+ }
+ if(nprev > 0) {
+ /*
+ * Find lowest tag in stack that ends before any tag beginning here.
+ * We have to emit end tags all the way down to there, then add
+ * back the ones that haven't actually ended here, together with ones
+ * that start here, and sort all of the added ones so that tags that
+ * end later are lower in the stack.
+ */
+ ii = *pnstack;
+ for(k = *pnstack - 1; k >=0; k--) {
+ m = stack[k];
+ if(i == nil || !tkttagset(i, m))
+ ii = k;
+ else
+ for(j = 0; j < nt; j++)
+ if(tagendsbefore(tkt, ix, m, tmpstack[j]))
+ ii = k;
+ }
+ for(k = *pnstack - 1; k >= ii; k--) {
+ m = stack[k];
+ r = fmtprint(fmt, "</%s>", tkttagname(tkt, m));
+ if(r < 0)
+ return r;
+ /* add m back to starting tags if m didn't actually end here */
+ if(i != nil && tkttagset(i, m))
+ tmpstack[nt++] = m;
+ }
+ *pnstack = ii;
+ }
+ if(nt > 0) {
+ /* add tags which open or reopen here */
+ onstack = *pnstack;
+ k = onstack;
+ for(j = 0; j < nt; j++)
+ stack[k++] = tmpstack[j];
+ *pnstack = k;
+ if(k - onstack > 1) {
+ /* sort new stack entries so tags that end later are lower in stack */
+ for(ii = k-2; ii>= onstack; ii--) {
+ m = stack[ii];
+ for(j = ii+1; j < k && tagendsbefore(tkt, ix, m, stack[j]); j++) {
+ stack[j-1] = stack[j];
+ }
+ stack[j-1] = m;
+ }
+ }
+ for(j = onstack; j < k; j++) {
+ r = fmtprint(fmt, "<%s>", tkttagname(tkt, stack[j]));
+ if(r < 0)
+ return r;
+ }
+ }
+ return 0;
+}
+
+/*
+ * In 'sgml' format, just print text (no special treatment of
+ * special characters, except that < turns into <)
+ * interspersed with things like <Bold> and </Bold>
+ * (where Bold is a tag name).
+ * Make sure that the tag pairs nest properly.
+*/
+static char*
+tktget(TkText *tkt, TkTindex *ix1, TkTindex *ix2, int sgml, char **val)
+{
+ int n, m, i, bychar, nstack;
+ int *stack, *tmpstack;
+ char *s;
+ TkTitem *iprev;
+ Tk *sub;
+ Fmt fmt;
+ char *buf;
+
+ if(!tktindbefore(ix1, ix2))
+ return nil;
+
+ stack = nil;
+ tmpstack = nil;
+
+ iprev = nil;
+ fmtstrinit(&fmt);
+ buf = mallocz(100, 0);
+ if(buf == nil)
+ return TkNomem;
+ if(sgml) {
+ stack = malloc((tkt->nexttag+1)*sizeof(int));
+ tmpstack = malloc((tkt->nexttag+1)*sizeof(int));
+ if(stack == nil || tmpstack == nil)
+ goto nomemret;
+ nstack = 0;
+ }
+ for(;;) {
+ if(ix1->item == ix2->item && ix1->pos == ix2->pos)
+ break;
+ s = nil;
+ bychar = 0;
+ m = 1;
+ switch(ix1->item->kind) {
+ case TkTrune:
+ s = ix1->item->istring;
+ s += tktutfpos(s, ix1->pos);
+ if(ix1->item == ix2->item) {
+ m = ix2->pos - ix1->pos;
+ bychar = 1;
+ }
+ break;
+ case TkTascii:
+ s = ix1->item->istring + ix1->pos;
+ if(ix1->item == ix2->item) {
+ m = ix2->pos - ix1->pos;
+ bychar = 1;
+ }
+ else {
+ m = strlen(s);
+ if(sgml && memchr(s, '<', m) != nil)
+ bychar = 1;
+ }
+ break;
+ case TkTtab:
+ s = "\t";
+ break;
+ case TkTnewline:
+ s = "\n";
+ break;
+ case TkTwin:
+ sub = ix1->item->iwin->sub;
+ if(sgml && sub != nil && sub->name != nil) {
+ snprint(buf, 100, "<Window %s>", sub->name->name);
+ s = buf;
+ }
+ }
+ if(s != nil) {
+ if(sgml) {
+ n = tktsgmltags(tkt, &fmt, iprev, ix1->item, ix1, stack, &nstack, tmpstack);
+ if(n < 0)
+ goto nomemret;
+ }
+ if(bychar) {
+ if (ix1->item->kind == TkTrune)
+ n = fmtprint(&fmt, "%.*s", m, s);
+ else {
+ n = 0;
+ for(i = 0; i < m && n >= 0; i++) {
+ if(s[i] == '<')
+ n = fmtprint(&fmt, "<");
+ else
+ n = fmtprint(&fmt, "%c", s[i]);
+ }
+ }
+ }
+ else
+ n = fmtprint(&fmt, "%s", s);
+ if(n < 0)
+ goto nomemret;
+ iprev = ix1->item;
+ }
+ if(ix1->item == ix2->item)
+ break;
+ if(!tktadjustind(tkt, TkTbyitem, ix1)) {
+ if(tktdbg)
+ print("tktextget botch\n");
+ break;
+ }
+ }
+ if(sgml) {
+ n = tktsgmltags(tkt, &fmt, iprev, nil, nil, stack, &nstack, tmpstack);
+ if(n < 0)
+ goto nomemret;
+ }
+
+ *val = fmtstrflush(&fmt);
+ free(buf);
+ return nil;
+
+nomemret:
+ free(buf);
+ if(stack != nil)
+ free(stack);
+ if(tmpstack != nil)
+ free(tmpstack);
+ return TkNomem;
+}
+
+/* Widget Commands (+ means implemented)
+ +bbox
+ +cget
+ +compare
+ +configure
+ +debug
+ +delete
+ +dlineinfo
+ +dump
+ +get
+ +index
+ +insert
+ +mark
+ +scan
+ +search
+ +see
+ +tag
+ +window
+ +xview
+ +yview
+*/
+
+static int
+tktviewrectclip(Rectangle *r, Rectangle b);
+
+static char*
+tktextbbox(Tk *tk, char *arg, char **val)
+{
+ char *e;
+ int noclip, w, h;
+ Rectangle r, rview;
+ TkTindex ix;
+ TkText *tkt;
+ char buf[Tkmaxitem];
+
+ e = tktindparse(tk, &arg, &ix);
+ if(e != nil)
+ return e;
+
+ noclip = 0;
+ if(*arg != '\0') {
+ /* extension to tk4.0:
+ * "noclip" means don't clip to viewable area
+ * "all" means give unclipped bbox of entire contents
+ */
+ arg = tkword(tk->env->top, arg, buf, buf+sizeof(buf), nil);
+ if(strcmp(buf, "noclip") == 0)
+ noclip = 1;
+ else
+ if(strcmp(buf, "all") == 0) {
+ tkt = TKobj(TkText, tk);
+ w = tktmaxwid(tkt->start.next);
+ h = tkt->end.orig.y;
+ return tkvalue(val, "0 0 %d %d", w, h);
+ }
+ }
+
+ /*
+ * skip marks; bbox applies to characters only.
+ * it's not defined what happens when bbox is applied to a newline char,
+ * so we'll just let the default case sort that out.
+ */
+ while (ix.item->kind == TkTmark)
+ ix.item = ix.item->next;
+ r = tktbbox(tk, &ix);
+
+ rview.min.x = 0;
+ rview.min.y = 0;
+ rview.max.x = tk->act.width - tk->ipad.x;
+ rview.max.y = tk->act.height - tk->ipad.y;
+ if(noclip || tktviewrectclip(&r, rview))
+ return tkvalue(val, "%d %d %d %d", r.min.x, r.min.y,
+ r.max.x-r.min.x, r.max.y-r.min.y);
+ return nil;
+}
+
+/*
+ * a supplemented rectclip, as ((0, 1), (0,1)) does not intersect ((0, 0), (5, 5))
+ * but for our purposes, we want it to. it's a hack.
+ */
+static int
+tktviewrectclip(Rectangle *rp, Rectangle b)
+{
+ Rectangle *bp = &b;
+ if((rp->min.x<bp->max.x &&
+ (bp->min.x<rp->max.x || (rp->max.x == b.min.x
+ && rp->min.x == b.min.x)) &&
+ rp->min.y<bp->max.y && bp->min.y<rp->max.y)==0)
+ return 0;
+ /* They must overlap */
+ if(rp->min.x < bp->min.x)
+ rp->min.x = bp->min.x;
+ if(rp->min.y < bp->min.y)
+ rp->min.y = bp->min.y;
+ if(rp->max.x > bp->max.x)
+ rp->max.x = bp->max.x;
+ if(rp->max.y > bp->max.y)
+ rp->max.y = bp->max.y;
+ return 1;
+}
+
+static Point
+scr2local(Tk *tk, Point p)
+{
+ p = subpt(p, tkposn(tk));
+ p.x -= tk->borderwidth;
+ p.y -= tk->borderwidth;
+ return p;
+}
+
+static char*
+tktextbutton1(Tk *tk, char *arg, char **val)
+{
+ char *e;
+ Point p;
+ TkCtxt *c;
+ TkTindex ix;
+ TkTmarkinfo *mi;
+ TkText *tkt = TKobj(TkText, tk);
+
+ USED(val);
+
+ e = tkxyparse(tk, &arg, &p);
+ if(e != nil)
+ return e;
+ tkt->track = p;
+ p = scr2local(tk, p);
+
+ tktxyind(tk, p.x, p.y, &ix);
+ tkt->tflag &= ~TkTjustfoc;
+ c = tk->env->top->ctxt;
+ if(!(tk->flag&Tkdisabled) && c->tkkeygrab != tk
+ && (tk->name != nil) && ix.item->kind != TkTwin) {
+ tkfocus(tk->env->top, tk->name->name, nil);
+ tkt->tflag |= TkTjustfoc;
+ return nil;
+ }
+
+ mi = tktfindmark(tkt->marks, "insert");
+ if(tktdbg && !mi) {
+ print("tktextbutton1: botch\n");
+ return nil;
+ }
+ tktmarkmove(tk, mi, &ix);
+
+ tktclearsel(tk);
+ tkrepeat(tk, autoselect, nil, TkRptpause, TkRptinterval);
+ return nil;
+}
+
+static char*
+tktextbutton1r(Tk *tk, char *arg, char **val)
+{
+ TkText *tkt;
+
+ USED(arg);
+ USED(val);
+
+ tkt = TKobj(TkText, tk);
+ tkt->tflag &= ~TkTnodrag;
+ tkcancelrepeat(tk);
+ return nil;
+}
+
+static char*
+tktextcget(Tk *tk, char *arg, char **val)
+{
+ TkText *tkt;
+ TkOptab tko[3];
+
+ tkt = TKobj(TkText, tk);
+ tko[0].ptr = tk;
+ tko[0].optab = tkgeneric;
+ tko[1].ptr = tkt;
+ tko[1].optab = textopts;
+ tko[2].ptr = nil;
+
+ return tkgencget(tko, arg, val, tk->env->top);
+}
+
+static char*
+tktextcompare(Tk *tk, char *arg, char **val)
+{
+ int op;
+ char *e;
+ TkTindex i1, i2;
+ TkText *tkt;
+ TkStab *s;
+ char *buf;
+
+ tkt = TKobj(TkText, tk);
+
+ e = tktindparse(tk, &arg, &i1);
+ if(e != nil)
+ return e;
+
+ if(*arg == '\0')
+ return TkBadcm;
+
+ buf = mallocz(Tkmaxitem, 0);
+ if(buf == nil)
+ return TkNomem;
+
+ arg = tkword(tk->env->top, arg, buf, buf+Tkmaxitem, nil);
+
+ op = -1;
+ for(s = tkcompare; s->val; s++)
+ if(strcmp(s->val, buf) == 0) {
+ op = s->con;
+ break;
+ }
+ if(op == -1) {
+ free(buf);
+ return TkBadcm;
+ }
+
+ e = tktindparse(tk, &arg, &i2);
+ if(e != nil) {
+ free(buf);
+ return e;
+ }
+
+ e = tkvalue(val, tktindcompare(tkt, &i1, op, &i2)? "1" : "0");
+ free(buf);
+ return e;
+}
+
+static char*
+tktextconfigure(Tk *tk, char *arg, char **val)
+{
+ char *e;
+ TkGeom g;
+ int bd;
+ TkText *tkt;
+ TkOptab tko[3];
+ tkt = TKobj(TkText, tk);
+ tko[0].ptr = tk;
+ tko[0].optab = tkgeneric;
+ tko[1].ptr = tkt;
+ tko[1].optab = textopts;
+ tko[2].ptr = nil;
+
+ if(*arg == '\0')
+ return tkconflist(tko, val);
+
+ g = tk->req;
+ bd = tk->borderwidth;
+
+ e = tkparse(tk->env->top, arg, tko, nil);
+ tksettransparent(tk, tkhasalpha(tk->env, TkCbackgnd));
+ if (tkt->propagate != BoolT) {
+ if ((tk->flag & Tksetwidth) == 0)
+ tk->req.width = tk->env->wzero*Textwidth;
+ if ((tk->flag & Tksetheight) == 0)
+ tk->req.height = tk->env->font->height*Textheight;
+ }
+ /* note: tkgeomchg() may also call tktfixgeom() via tktextgeom() */
+ tktfixgeom(tk, &tkt->start, tkt->end.prev, 0);
+ tktextsize(tk, 0);
+ tkgeomchg(tk, &g, bd);
+ tktnotdrawn(tk, 0, tkt->end.orig.y, 1);
+
+ return e;
+}
+
+static char*
+tktextdebug(Tk *tk, char *arg, char **val)
+{
+ char buf[Tkmaxitem];
+
+ tkword(tk->env->top, arg, buf, buf+sizeof(buf), nil);
+ if(*buf == '\0')
+ return tkvalue(val, "%s", tktdbg? "on" : "off");
+ else {
+ tktdbg = (strcmp(buf, "1") == 0 || strcmp(buf, "yes") == 0);
+ if(tktdbg) {
+ tktprinttext(TKobj(TkText, tk));
+ }
+ return nil;
+ }
+}
+
+static char*
+tktextdelete(Tk *tk, char *arg, char **val)
+{
+ int sameit;
+ char *e;
+ TkTindex i1, i2, ip, isee;
+ TkTline *lmin;
+ TkText *tkt = TKobj(TkText, tk);
+ char buf[20], *p;
+
+ USED(val);
+
+ e = tktindparse(tk, &arg, &i1);
+ if(e != nil)
+ return e;
+ tktadjustind(tkt, TkTbycharstart, &i1);
+
+ e = tktsplititem(&i1);
+ if(e != nil)
+ return e;
+
+ if(*arg != '\0') {
+ e = tktindparse(tk, &arg, &i2);
+ if(e != nil)
+ return e;
+ }
+ else {
+ i2 = i1;
+ tktadjustind(tkt, TkTbychar, &i2);
+ }
+ if(tktindcompare(tkt, &i1, TkGte, &i2))
+ return nil;
+
+ sameit = (i1.item == i2.item);
+
+ /* save possible fixup see place */
+ isee.line = nil;
+ if(i2.line->orig.y + i2.line->height < tkt->deltatv.y) {
+ /* delete completely precedes view */
+ tktxyind(tk, 0, 0, &isee);
+ }
+
+ e = tktsplititem(&i2);
+ if(e != nil)
+ return e;
+
+ if(sameit) {
+ /* after split, i1 should be in previous item to i2 */
+ ip = i2;
+ tktadjustind(tkt, TkTbyitemback, &ip);
+ i1.item = ip.item;
+ }
+
+ lmin = tktprevwrapline(tk, i1.line);
+ while(i1.item != i2.item) {
+ if(i1.item->kind != TkTmark)
+ tktremitem(tkt, &i1);
+ /* tktremitem moves i1 to next item */
+ else {
+ if(!tktadjustind(tkt, TkTbyitem, &i1)) {
+ if(tktdbg)
+ print("tktextdelete botch\n");
+ break;
+ }
+ }
+ }
+
+ /*
+ * guard against invalidation of index by tktfixgeom
+ */
+ if (isee.line != nil)
+ snprint(buf, sizeof(buf), "%d.%d", tktlinenum(tkt, &isee), tktlinepos(tkt, &isee));
+
+ tktfixgeom(tk, lmin, i1.line, 0);
+ tktextsize(tk, 1);
+ if(isee.line != nil) {
+ p = buf;
+ tktindparse(tk, &p, &isee);
+ tktsee(tk, &isee, 1);
+ }
+ return nil;
+}
+
+static char*
+tktextsee(Tk *tk, char *arg, char **val)
+{
+ char *e;
+ TkTindex ix;
+
+ USED(val);
+
+ e = tktindparse(tk, &arg, &ix);
+ if(e != nil)
+ return e;
+
+ tktsee(tk, &ix, 0);
+ return nil;
+}
+
+static char*
+tktextdelins(Tk *tk, char *arg, char **val)
+{
+ int m, c, skipping, wordc, n;
+ TkTindex ix, ix2;
+ TkText *tkt = TKobj(TkText, tk);
+ char buf[30];
+
+ USED(val);
+
+ if(tk->flag&Tkdisabled)
+ return nil;
+
+ if(tktgetsel(tk, &ix, &ix2))
+ tktextdelete(tk, "sel.first sel.last", nil);
+ else {
+ while(*arg == ' ')
+ arg++;
+ if(*arg == '-') {
+ m = arg[1];
+ if(m == 'c')
+ n = 1;
+ else {
+ /* delete prev word (m=='w') or prev line (m=='l') */
+ if(!tktmarkind(tk, "insert", &ix))
+ return nil;
+ if(!tktadjustind(tkt, TkTbycharback, &ix))
+ return nil;
+ n = 1;
+ /* ^W skips back over nonwordchars, then takes maximal seq of wordchars */
+ skipping = 1;
+ for(;;) {
+ c = tktindrune(&ix);
+ if(c == '\n') {
+ /* special case: always delete at least one char */
+ if(n > 1)
+ n--;
+ break;
+ }
+ if(m == 'w') {
+ wordc = tkiswordchar(c);
+ if(wordc && skipping)
+ skipping = 0;
+ else if(!wordc && !skipping) {
+ n--;
+ break;
+ }
+ }
+ if(tktadjustind(tkt, TkTbycharback, &ix))
+ n++;
+ else
+ break;
+ }
+ }
+ sprint(buf, "insert-%dc insert", n);
+ tktextdelete(tk, buf, nil);
+ }
+ else if(arg[0] == '+' && arg[1] == 'l')
+ tktextdelete(tk, "insert {insert lineend}", nil);
+ else
+ tktextdelete(tk, "insert", nil);
+ tktextsee(tk, "insert", nil);
+ }
+ return nil;
+}
+
+static char*
+tktextdlineinfo(Tk *tk, char *arg, char **val)
+{
+ char *e;
+ TkTindex ix;
+ TkTline *l;
+ Point p;
+ int vh;
+ TkText *tkt = TKobj(TkText, tk);
+
+ e = tktindparse(tk, &arg, &ix);
+ if(e != nil)
+ return e;
+
+ l = ix.line;
+ vh = tk->act.height;
+
+ /* get p in V space */
+ p = subpt(l->orig, tkt->deltatv);
+ if(p.y+l->height < 0 || p.y >= vh)
+ return nil;
+
+ return tkvalue(val, "%d %d %d %d %d",
+ p.x, p.y, l->width, l->height, l->ascent);
+}
+
+static char*
+tktextdump(Tk *tk, char *arg, char **val)
+{
+ TkTline *l;
+ TkTitem *i;
+ Fmt fmt;
+ TkText *tkt;
+ TkDump tkdump;
+ TkOptab tko[2];
+ TkTtaginfo *ti;
+ TkName *names, *n;
+ char *e, *win, *p;
+ TkTindex ix1, ix2;
+ int r, j, numitems;
+ ulong fg, bg;
+
+ tkt = TKobj(TkText, tk);
+
+
+ tkdump.sgml = 0;
+ tkdump.metrics = 0;
+
+ tko[0].ptr = &tkdump;
+ tko[0].optab = dumpopts;
+ tko[1].ptr = nil;
+ names = nil;
+ e = tkparse(tk->env->top, arg, tko, &names);
+ if(e != nil)
+ return e;
+
+ if(names != nil) { /* supplied indices */
+ p = names->name;
+ e = tktindparse(tk, &p, &ix1);
+ if(e != nil) {
+ tkfreename(names);
+ return e;
+ }
+ n = names->link;
+ if(n != nil) {
+ p = n->name;
+ e = tktindparse(tk, &p, &ix2);
+ if(e != nil) {
+ tkfreename(names);
+ return e;
+ }
+ }
+ else {
+ ix2 = ix1;
+ tktadjustind(tkt, TkTbychar, &ix2);
+ }
+ tkfreename(names);
+ if(!tktindbefore(&ix1, &ix2))
+ return nil;
+ }
+ else
+ return TkBadix;
+
+ if(tkdump.metrics != 0) {
+ fmtstrinit(&fmt);
+ if(fmtprint(&fmt, "%%Fonts\n") < 0)
+ return TkNomem;
+ for(ti=tkt->tags; ti != nil; ti=ti->next) {
+ if(ti->env == nil || ti->env->font == nil)
+ continue;
+ if(fmtprint(&fmt, "%d::%s\n", ti->id,ti->env->font->name) < 0)
+ return TkNomem;
+ }
+ if(fmtprint(&fmt, "-1::%s\n%%Colors\n", tk->env->font->name) < 0)
+ return TkNomem;
+ for(ti=tkt->tags; ti != nil; ti=ti->next) {
+ if(ti->env == nil)
+ continue;
+ bg = ti->env->colors[TkCbackgnd];
+ fg = ti->env->colors[TkCforegnd];
+ if(bg == tk->env->colors[TkCbackgnd] &&
+ fg == ti->env->colors[TkCforegnd])
+ continue;
+ r = fmtprint(&fmt,"%d::#%.8lux\n", ti->id, bg);
+ if(r < 0)
+ return TkNomem;
+ r = fmtprint(&fmt,"%d::#%.8lux\n", ti->id, fg);
+ if(r < 0)
+ return TkNomem;
+ }
+ if(fmtprint(&fmt, "%%Lines\n") < 0)
+ return TkNomem;
+
+ /*
+ * In 'metrics' format lines are recorded in the following way:
+ * xorig yorig wd ht as [data]
+ * where data is of the form:
+ * CodeWidth{tags} data
+ * For Example;
+ * A200{200000} Hello World!
+ * denotes an A(scii) contiguous string of 200 pixels with
+ * bit 20 set in its tags which corresponds to some font.
+ *
+ */
+ if(ix2.line->items != ix2.item)
+ ix2.line = ix2.line->next;
+ for(l = ix1.line; l != ix2.line; l = l->next) {
+ numitems = 0;
+ for(i = l->items; i != nil; i = i->next) {
+ if(i->kind != TkTmark)
+ numitems++;
+ }
+ r = fmtprint(&fmt, "%d %d %d %d %d %d ",
+ l->orig.x, l->orig.y, l->width, l->height, l->ascent,numitems);
+ if(r < 0)
+ return TkNomem;
+ for(i = l->items; i != nil; i = i->next) {
+ switch(i->kind) {
+ case TkTascii:
+ case TkTrune:
+ r = i->kind == TkTascii ? 'A' : 'R';
+ if(fmtprint(&fmt,"[%c%d{", r, i->width) < 0)
+ return TkNomem;
+ if(i->tags !=0 || i->tagextra !=0) {
+ if(fmtprint(&fmt,"%lux", i->tags[0]) < 0)
+ return TkNomem;
+ for(j=0; j < i->tagextra; j++)
+ if(fmtprint(&fmt,"::%lux", i->tags[j+1]) < 0)
+ return TkNomem;
+ }
+ /* XXX string should be quoted to avoid embedded ']'s */
+ if(fmtprint(&fmt,"}%s]", i->istring) < 0)
+ return TkNomem;
+ break;
+ case TkTnewline:
+ case TkTcontline:
+ r = i->kind == TkTnewline ? 'N' : 'C';
+ if(fmtprint(&fmt, "[%c]", r) < 0)
+ return TkNomem;
+ break;
+ case TkTtab:
+ if(fmtprint(&fmt,"[T%d]",i->width) < 0)
+ return TkNomem;
+ break;
+ case TkTwin:
+ win = "<null>";
+ if(i->iwin->sub != nil)
+ win = i->iwin->sub->name->name;
+ if(fmtprint(&fmt,"[W%d %s]",i->width, win) < 0)
+ return TkNomem;
+ break;
+ }
+ if(fmtprint(&fmt, " ") < 0)
+ return TkNomem;
+
+ }
+ if(fmtprint(&fmt, "\n") < 0)
+ return TkNomem;
+ *val = fmtstrflush(&fmt);
+ if(*val == nil)
+ return TkNomem;
+ }
+ }
+ else
+ return tktget(tkt, &ix1, &ix2, tkdump.sgml, val);
+
+ return nil;
+}
+
+
+static char*
+tktextget(Tk *tk, char *arg, char **val)
+{
+ char *e;
+ TkTindex ix1, ix2;
+ TkText *tkt = TKobj(TkText, tk);
+
+ e = tktindparse(tk, &arg, &ix1);
+ if(e != nil)
+ return e;
+
+ if(*arg != '\0') {
+ e = tktindparse(tk, &arg, &ix2);
+ if(e != nil)
+ return e;
+ }
+ else {
+ ix2 = ix1;
+ tktadjustind(tkt, TkTbychar, &ix2);
+ }
+ return tktget(tkt, &ix1, &ix2, 0, val);
+}
+
+static char*
+tktextindex(Tk *tk, char *arg, char **val)
+{
+ char *e;
+ TkTindex ix;
+ TkText *tkt = TKobj(TkText, tk);
+
+ e = tktindparse(tk, &arg, &ix);
+ if(e != nil)
+ return e;
+ return tkvalue(val, "%d.%d", tktlinenum(tkt, &ix), tktlinepos(tkt, &ix));
+}
+
+static char*
+tktextinsert(Tk *tk, char *arg, char **val)
+{
+ int n;
+ char *e, *p, *pe;
+ TkTindex ins, pins;
+ TkTtaginfo *ti;
+ TkText *tkt;
+ TkTline *lmin;
+ TkTop *top;
+ TkTitem *tagit;
+ char *tbuf, *buf;
+
+ USED(val);
+
+ tkt = TKobj(TkText, tk);
+ top = tk->env->top;
+
+ e = tktindparse(tk, &arg, &ins);
+ if(e != nil)
+ return e;
+
+ if(ins.item->kind == TkTmark) {
+ if(ins.item->imark->gravity == Tkleft) {
+ while(ins.item->kind == TkTmark && ins.item->imark->gravity == Tkleft)
+ if(!tktadjustind(tkt, TkTbyitem, &ins)) {
+ if(tktdbg)
+ print("tktextinsert botch\n");
+ break;
+ }
+ }
+ else {
+ for(;;) {
+ pins = ins;
+ if(!tktadjustind(tkt, TkTbyitemback, &pins))
+ break;
+ if(pins.item->kind == TkTmark && pins.item->imark->gravity == Tkright)
+ ins = pins;
+ else
+ break;
+ }
+ }
+ }
+
+ lmin = tktprevwrapline(tk, ins.line);
+
+ n = strlen(arg) + 1;
+ if(n < Tkmaxitem)
+ n = Tkmaxitem;
+ tbuf = malloc(n);
+ if(tbuf == nil)
+ return TkNomem;
+ buf = mallocz(Tkmaxitem, 0);
+ if(buf == nil) {
+ free(tbuf);
+ return TkNomem;
+ }
+
+ tagit = nil;
+
+ while(*arg != '\0') {
+ arg = tkword(top, arg, tbuf, tbuf+n, nil);
+ if(*arg != '\0') {
+ /* tag list spec -- add some slop to tagextra for added tags */
+ e = tktnewitem(TkTascii, (tkt->nexttag-1)/32 + 1, &tagit);
+ if(e != nil) {
+ free(tbuf);
+ free(buf);
+ return e;
+ }
+ arg = tkword(top, arg, buf, buf+Tkmaxitem, nil);
+ p = buf;
+ while(*p) {
+ while(*p == ' ') {
+ p++;
+ }
+ if(*p == '\0')
+ break;
+ pe = strchr(p, ' ');
+ if(pe != nil)
+ *pe = '\0';
+ ti = tktfindtag(tkt->tags, p);
+ if(ti == nil) {
+ e = tktaddtaginfo(tk, p, &ti);
+ if(e != nil) {
+ if(tagit != nil)
+ free(tagit);
+ free(tbuf);
+ free(buf);
+ return e;
+ }
+ }
+ tkttagbit(tagit, ti->id, 1);
+ if(pe == nil)
+ break;
+ else
+ p = pe+1;
+ }
+ }
+ e = tktinsert(tk, &ins, tbuf, tagit);
+ if(tagit != nil) {
+ free(tagit);
+ tagit = nil;
+ }
+ if(e != nil) {
+ free(tbuf);
+ free(buf);
+ return e;
+ }
+ }
+
+ tktfixgeom(tk, lmin, ins.line, 0);
+ tktextsize(tk, 1);
+
+ free(tbuf);
+ free(buf);
+
+ return nil;
+}
+
+static char*
+tktextinserti(Tk *tk, char *arg, char **val)
+{
+ int n;
+ TkTline *lmin;
+ TkTindex ix, is1, is2;
+ TkText *tkt = TKobj(TkText, tk);
+ char *tbuf, *buf;
+
+ USED(val);
+
+ if(tk->flag&Tkdisabled)
+ return nil;
+
+ buf = mallocz(Tkmaxitem, 0);
+ if(buf == nil)
+ return TkNomem;
+
+ tbuf = nil;
+ n = strlen(arg) + 1;
+ if(n < Tkmaxitem)
+ tkword(tk->env->top, arg, buf, buf+sizeof(buf), nil);
+ else {
+ tbuf = malloc(n);
+ if(tbuf == nil) {
+ free(buf);
+ return TkNomem;
+ }
+ tkword(tk->env->top, arg, tbuf, buf+n, nil);
+ }
+ if(*buf == '\0')
+ goto Ret;
+ if(!tktmarkind(tk, "insert", &ix)) {
+ print("tktextinserti: botch\n");
+ goto Ret;
+ }
+ if(tktgetsel(tk, &is1, &is2)) {
+ if(tktindcompare(tkt, &is1, TkLte, &ix) &&
+ tktindcompare(tkt, &is2, TkGte, &ix)) {
+ tktextdelete(tk, "sel.first sel.last", nil);
+ /* delete might have changed ix item */
+ tktmarkind(tk, "insert", &ix);
+ }
+ }
+
+ lmin = tktprevwrapline(tk, ix.line);
+ tktinsert(tk, &ix, tbuf==nil ? buf : tbuf, 0);
+ tktfixgeom(tk, lmin, ix.line, 0);
+ if(tktmarkind(tk, "insert", &ix)) /* index doesn't remain valid after fixgeom */
+ tktsee(tk, &ix, 0);
+ tktextsize(tk, 1);
+Ret:
+ if(tbuf != nil)
+ free(tbuf);
+ free(buf);
+ return nil;
+}
+
+static char*
+tktextmark(Tk *tk, char *arg, char **val)
+{
+ char *buf;
+ TkCmdtab *cmd;
+
+ buf = mallocz(Tkmaxitem, 0);
+ if(buf == nil)
+ return TkNomem;
+ arg = tkword(tk->env->top, arg, buf, buf+Tkmaxitem, nil);
+ for(cmd = tktmarkcmd; cmd->name != nil; cmd++) {
+ if(strcmp(cmd->name, buf) == 0) {
+ free(buf);
+ return cmd->fn(tk, arg, val);
+ }
+ }
+ free(buf);
+ return TkBadcm;
+}
+
+static char*
+tktextscan(Tk *tk, char *arg, char **val)
+{
+ char *e;
+ int mark, x, y, xmax, ymax, vh, vw;
+ Point p, odeltatv;
+ char buf[Tkmaxitem];
+ TkText *tkt = TKobj(TkText, tk);
+
+ USED(val);
+
+ arg = tkword(tk->env->top, arg, buf, buf+sizeof(buf), nil);
+
+ if(strcmp(buf, "mark") == 0)
+ mark = 1;
+ else
+ if(strcmp(buf, "dragto") == 0)
+ mark = 0;
+ else
+ return TkBadcm;
+
+ e = tkxyparse(tk, &arg, &p);
+ if(e != nil)
+ return e;
+
+ if(mark)
+ tkt->track = p;
+ else {
+ odeltatv = tkt->deltatv;
+ vw = tk->act.width - tk->ipad.x;
+ vh = tk->act.height - tk->ipad.y;
+ ymax = tkt->end.prev->orig.y + tkt->end.prev->height - vh;
+ y = tkt->deltatv.y -10*(p.y - tkt->track.y);
+ if(y > ymax)
+ y = ymax;
+ if(y < 0)
+ y = 0;
+ tkt->deltatv.y = y;
+ e = tktsetscroll(tk, Tkvertical);
+ if(e != nil)
+ return e;
+ if(tkt->opts[TkTwrap] == Tkwrapnone) {
+ xmax = tktmaxwid(tkt->start.next) - vw;
+ x = tkt->deltatv.x - 10*(p.x - tkt->track.x);
+ if(x > xmax)
+ x = xmax;
+ if(x < 0)
+ x = 0;
+ tkt->deltatv.x = x;
+ e = tktsetscroll(tk, Tkhorizontal);
+ if(e != nil)
+ return e;
+ }
+ tktfixscroll(tk, odeltatv);
+ tkt->track = p;
+ }
+
+ return nil;
+}
+
+static char*
+tktextscrollpages(Tk *tk, char *arg, char **val)
+{
+ TkText *tkt = TKobj(TkText, tk);
+
+ USED(tkt);
+ USED(arg);
+ USED(val);
+ return nil;
+}
+
+static char*
+tktextsearch(Tk *tk, char *arg, char **val)
+{
+ int i, n;
+ Rune r;
+ char *e, *s;
+ int wrap, fwd, nocase;
+ TkText *tkt;
+ TkTindex ix1, ix2, ixstart, ixend, tx;
+ char buf[Tkmaxitem];
+
+ tkt = TKobj(TkText, tk);
+
+ fwd = 1;
+ nocase = 0;
+
+ while(*arg != '\0') {
+ arg = tkword(tk->env->top, arg, buf, buf+sizeof(buf), nil);
+ if(*buf != '-')
+ break;
+ if(strcmp(buf, "-backwards") == 0)
+ fwd = 0;
+ else if(strcmp(buf, "-nocase") == 0)
+ nocase = 1;
+ else if(strcmp(buf, "--") == 0) {
+ arg = tkword(tk->env->top, arg, buf, buf+sizeof(buf), nil);
+ break;
+ }
+ }
+
+ tktstartind(tkt, &ixstart);
+ tktadjustind(tkt, TkTbycharstart, &ixstart);
+ tktendind(tkt, &ixend);
+
+ if(*arg == '\0')
+ return TkOparg;
+
+ e = tktindparse(tk, &arg, &ix1);
+ if(e != nil)
+ return e;
+ tktadjustind(tkt, fwd? TkTbycharstart : TkTbycharback, &ix1);
+
+ if(*arg != '\0') {
+ wrap = 0;
+ e = tktindparse(tk, &arg, &ix2);
+ if(e != nil)
+ return e;
+ if(!fwd)
+ tktadjustind(tkt, TkTbycharback, &ix2);
+ }
+ else {
+ wrap = 1;
+ if(fwd) {
+ if(tktindcompare(tkt, &ix1, TkEq, &ixstart))
+ ix2 = ixend;
+ else {
+ ix2 = ix1;
+ tktadjustind(tkt, TkTbycharback, &ix2);
+ }
+ }
+ else {
+ if(tktindcompare(tkt, &ix1, TkEq, &ixend))
+ ix2 = ixstart;
+ else {
+ ix2 = ix1;
+ tktadjustind(tkt, TkTbychar, &ix2);
+ }
+ }
+ }
+ tktadjustind(tkt, TkTbycharstart, &ix2);
+ if(tktindcompare(tkt, &ix1, TkEq, &ix2))
+ return nil;
+
+ if(*buf == '\0')
+ return tkvalue(val, "%d.%d", tktlinenum(tkt, &ix1), tktlinepos(tkt, &ix1));
+
+ while(!(ix1.item == ix2.item && ix1.pos == ix2.pos)) {
+ tx = ix1;
+ for(i = 0; buf[i] != '\0'; i++) {
+ switch(tx.item->kind) {
+ case TkTascii:
+ if(!tktcmatch(tx.item->istring[tx.pos], buf[i], nocase))
+ goto nomatch;
+ break;
+ case TkTrune:
+ s = tx.item->istring;
+ s += tktutfpos(s, tx.pos);
+ n = chartorune(&r, s);
+ if(strncmp(s, buf+i, n) != 0)
+ goto nomatch;
+ i += n-1;
+ break;
+ case TkTtab:
+ if(buf[i] != '\t')
+ goto nomatch;
+ break;
+ case TkTnewline:
+ if(buf[i] != '\n')
+ goto nomatch;
+ break;
+ default:
+ goto nomatch;
+ }
+ tktadjustind(tkt, TkTbychar, &tx);
+ }
+ return tkvalue(val, "%d.%d", tktlinenum(tkt, &ix1), tktlinepos(tkt, &ix1));
+ nomatch:
+ if(fwd) {
+ if(!tktadjustind(tkt, TkTbychar, &ix1)) {
+ if(!wrap)
+ break;
+ ix1 = ixstart;
+ }
+ }
+ else {
+ if(!tktadjustind(tkt, TkTbycharback, &ix1)) {
+ if(!wrap)
+ break;
+ ix1 = ixend;
+ }
+ }
+ }
+
+ return nil;
+}
+
+char*
+tktextselection(Tk *tk, char *arg, char **val)
+{
+ USED(val);
+ if (strcmp(arg, " clear") == 0) {
+ tktclearsel(tk);
+ return nil;
+ }
+ else
+ return TkBadcm;
+}
+
+static void
+doselectto(Tk *tk, Point p, int dbl)
+{
+ int halfway;
+ TkTindex cur, insert, first, last;
+ TkText *tkt = TKobj(TkText, tk);
+ tktclearsel(tk);
+
+ halfway = tktxyind(tk, p.x, p.y, &cur);
+
+ if(!dbl) {
+ if(!tktmarkind(tk, "insert", &insert))
+ insert = cur;
+
+ if(tktindcompare(tkt, &cur, TkLt, &insert)) {
+ first = cur;
+ last = insert;
+ }
+ else {
+ first = insert;
+ last = cur;
+ if(halfway)
+ tktadjustind(tkt, TkTbychar, &last);
+ if(last.line == &tkt->end)
+ tktadjustind(tkt, TkTbycharback, &last);
+ if(tktindcompare(tkt, &first, TkGte, &last))
+ return;
+ cur = last;
+ }
+ tktsee(tk, &cur, 0);
+ }
+ else {
+ first = cur;
+ last = cur;
+ tktdoubleclick(tkt, &first, &last);
+ }
+
+ tkttagchange(tk, TkTselid, &first, &last, 1);
+}
+
+static void
+autoselect(Tk *tk, void *v, int cancelled)
+{
+ TkText *tkt = TKobj(TkText, tk);
+ Rectangle hitr;
+ Point p;
+ USED(v);
+
+ if (cancelled)
+ return;
+
+ p = scr2local(tk, tkt->track);
+ if (tkvisiblerect(tk, &hitr) && ptinrect(p, hitr))
+ return;
+ doselectto(tk, p, 0);
+ tkdirty(tk);
+ tkupdate(tk->env->top);
+}
+
+static char*
+tktextselectto(Tk *tk, char *arg, char **val)
+{
+ int dbl;
+ char *e;
+ Point p;
+ Rectangle hitr;
+ TkText *tkt = TKobj(TkText, tk);
+
+ USED(val);
+
+ if(tkt->tflag & (TkTjustfoc|TkTnodrag))
+ return nil;
+
+ e = tkxyparse(tk, &arg, &p);
+ if(e != nil)
+ return e;
+ tkt->track = p;
+ p = scr2local(tk, p);
+
+ arg = tkskip(arg, " ");
+ if(*arg == 'd') {
+ tkcancelrepeat(tk);
+ dbl = 1;
+ tkt->tflag |= TkTnodrag;
+ } else {
+ dbl = 0;
+ if (!tkvisiblerect(tk, &hitr) || !ptinrect(p, hitr))
+ return nil;
+ }
+ doselectto(tk, p, dbl);
+ return nil;
+}
+
+static char tktleft1[] = "{[(<";
+static char tktright1[] = "}])>";
+static char tktleft2[] = "\n";
+static char tktleft3[] = "\'\"`";
+
+static char *tktleft[] = {tktleft1, tktleft2, tktleft3, nil};
+static char *tktright[] = {tktright1, tktleft2, tktleft3, nil};
+
+static void
+tktdoubleclick(TkText *tkt, TkTindex *first, TkTindex *last)
+{
+ int c, i;
+ TkTindex ix, ix2;
+ char *r, *l, *p;
+
+ for(i = 0; tktleft[i] != nil; i++) {
+ ix = *first;
+ l = tktleft[i];
+ r = tktright[i];
+ /* try matching character to left, looking right */
+ ix2 = ix;
+ if(!tktadjustind(tkt, TkTbycharback, &ix2))
+ c = '\n';
+ else
+ c = tktindrune(&ix2);
+ p = strchr(l, c);
+ if(p != nil) {
+ if(tktclickmatch(tkt, c, r[p-l], 1, &ix)) {
+ *last = ix;
+ if(c != '\n')
+ tktadjustind(tkt, TkTbycharback, last);
+ }
+ return;
+ }
+ /* try matching character to right, looking left */
+ c = tktindrune(&ix);
+ p = strchr(r, c);
+ if(p != nil) {
+ if(tktclickmatch(tkt, c, l[p-r], -1, &ix)) {
+ *last = *first;
+ if(c == '\n')
+ tktadjustind(tkt, TkTbychar, last);
+ *first = ix;
+ if(!(c=='\n' && ix.line == tkt->start.next && ix.item == ix.line->items))
+ tktadjustind(tkt, TkTbychar, first);
+ }
+ return;
+ }
+ }
+ /* try filling out word to right */
+ while(tkiswordchar(tktindrune(last))) {
+ if(!tktadjustind(tkt, TkTbychar, last))
+ break;
+ }
+ /* try filling out word to left */
+ for(;;) {
+ ix = *first;
+ if(!tktadjustind(tkt, TkTbycharback, &ix))
+ break;
+ if(!tkiswordchar(tktindrune(&ix)))
+ break;
+ *first = ix;
+ }
+}
+
+static int
+tktclickmatch(TkText *tkt, int cl, int cr, int dir, TkTindex *ix)
+{
+ int c, nest, atend;
+
+ nest = 1;
+ atend = 0;
+ for(;;) {
+ if(dir > 0) {
+ if(atend)
+ break;
+ c = tktindrune(ix);
+ atend = !tktadjustind(tkt, TkTbychar, ix);
+ } else {
+ if(!tktadjustind(tkt, TkTbycharback, ix))
+ break;
+ c = tktindrune(ix);
+ }
+ if(c == cr){
+ if(--nest==0)
+ return 1;
+ }else if(c == cl)
+ nest++;
+ }
+ return cl=='\n' && nest==1;
+}
+
+/*
+ * return the line before line l, unless word wrap is on,
+ * (for the first word of line l), in which case return the last non-empty line before that.
+ * tktgeom might then combine the end of that line with the start of the insertion
+ * (unless there is a newline in the way).
+ */
+TkTline*
+tktprevwrapline(Tk *tk, TkTline *l)
+{
+ TkTitem *i;
+ int *opts, wrapmode;
+ TkText *tkt = TKobj(TkText, tk);
+ TkEnv env;
+
+ if(l == nil)
+ return nil;
+ /* some spacing depends on tags of first non-mark on display line */
+ for(i = l->items; i != nil; i = i->next)
+ if(i->kind != TkTmark && i->kind != TkTcontline)
+ break;
+ if(i == nil || i->kind == TkTnewline) /* can't use !tkanytags(i) because it doesn't check env */
+ return l->prev;
+ opts = mallocz(TkTnumopts*sizeof(int), 0);
+ if(opts == nil)
+ return l->prev; /* in worst case gets word wrap wrong */
+ tkttagopts(tk, i, opts, &env, nil, 1);
+ wrapmode = opts[TkTwrap];
+ free(opts);
+ if(wrapmode != Tkwrapword)
+ return l->prev;
+ if(l->prev != &tkt->start)
+ l = l->prev; /* having been processed by tktgeom, shouldn't have extraneous marks etc */
+ return l->prev;
+}
+
+static char*
+tktextsetcursor(Tk *tk, char *arg, char **val)
+{
+ char *e;
+ TkTindex ix;
+ TkTmarkinfo *mi;
+ TkText *tkt = TKobj(TkText, tk);
+
+ USED(val);
+
+ /* do clearsel here, because it can change indices */
+ tktclearsel(tk);
+
+ e = tktindparse(tk, &arg, &ix);
+ if(e != nil)
+ return e;
+
+ mi = tktfindmark(tkt->marks, "insert");
+ if(tktdbg && mi == nil) {
+ print("tktextsetcursor: botch\n");
+ return nil;
+ }
+ tktmarkmove(tk, mi, &ix);
+ tktsee(tk, &ix, 0);
+ return nil;
+}
+
+static char*
+tktexttag(Tk *tk, char *arg, char **val)
+{
+ char *buf;
+ TkCmdtab *cmd;
+
+ buf = mallocz(Tkmaxitem, 0);
+ if(buf == nil)
+ return TkNomem;
+ arg = tkword(tk->env->top, arg, buf, buf+Tkmaxitem, nil);
+ for(cmd = tkttagcmd; cmd->name != nil; cmd++) {
+ if(strcmp(cmd->name, buf) == 0) {
+ free(buf);
+ return cmd->fn(tk, arg, val);
+ }
+ }
+ free(buf);
+ return TkBadcm;
+}
+
+static char*
+tktextwindow(Tk *tk, char *arg, char **val)
+{
+ char buf[Tkmaxitem];
+ TkCmdtab *cmd;
+
+ arg = tkword(tk->env->top, arg, buf, buf+sizeof(buf), nil);
+ for(cmd = tktwincmd; cmd->name != nil; cmd++) {
+ if(strcmp(cmd->name, buf) == 0)
+ return cmd->fn(tk, arg, val);
+ }
+ return TkBadcm;
+}
+
+static char*
+tktextxview(Tk *tk, char *arg, char **val)
+{
+ int ntot, vw;
+ char *e;
+ Point odeltatv;
+ TkText *tkt = TKobj(TkText, tk);
+
+ odeltatv = tkt->deltatv;
+ vw = tk->act.width - tk->ipad.x;
+ ntot = tktmaxwid(tkt->start.next);
+ if(ntot < tkt->deltatv.x +vw)
+ ntot = tkt->deltatv.x + vw;
+ e = tktview(tk, arg, val, vw, &tkt->deltatv.x, ntot, Tkhorizontal);
+ if(e == nil) {
+ e = tktsetscroll(tk, Tkhorizontal);
+ if(e == nil)
+ tktfixscroll(tk, odeltatv);
+ }
+ return e;
+}
+
+static int
+istext(TkTline *l)
+{
+ TkTitem *i;
+
+ for(i = l->items; i != nil; i = i->next)
+ if(i->kind == TkTwin || i->kind == TkTmark)
+ return 0;
+ return 1;
+}
+
+static void
+tkadjpage(Tk *tk, int ody, int *dy)
+{
+ int y, a, b, d;
+ TkTindex ix;
+ TkTline *l;
+
+ d = *dy-ody;
+ y = d > 0 ? tk->act.height : 0;
+ tktxyind(tk, 0, y-d, &ix);
+ if((l = ix.line) != nil && istext(l)){
+ a = l->orig.y;
+ b = a+l->height;
+/* print("AP: %d %d %d (%d+%d)\n", a, ody+y, b, ody, y); */
+ if(a+2 < ody+y && ody+y < b-2){ /* partially obscured line */
+ if(d > 0)
+ *dy -= ody+y-a;
+ else
+ *dy += b-ody;
+ }
+ }
+}
+
+static char*
+tktextyview(Tk *tk, char *arg, char **val)
+{
+ int ntot, vh, d;
+ char *e;
+ TkTline *l;
+ Point odeltatv;
+ TkTindex ix;
+ TkText *tkt = TKobj(TkText, tk);
+ char buf[Tkmaxitem], *v;
+
+ if(*arg != '\0') {
+ v = tkitem(buf, arg);
+ if(strcmp(buf, "-pickplace") == 0)
+ return tktextsee(tk,v, val);
+ if(strcmp(buf, "moveto") != 0 && strcmp(buf, "scroll") != 0) {
+ e = tktindparse(tk, &arg, &ix);
+ if(e != nil)
+ return e;
+ tktsee(tk, &ix, 1);
+ return nil;
+ }
+ }
+ odeltatv = tkt->deltatv;
+ vh = tk->act.height;
+ l = tkt->end.prev;
+ ntot = l->orig.y + l->height;
+// if(ntot < tkt->deltatv.y + vh)
+// ntot = tkt->deltatv.y + vh;
+ e = tktview(tk, arg, val, vh, &tkt->deltatv.y, ntot, Tkvertical);
+ d = tkt->deltatv.y-odeltatv.y;
+ if(d == vh || d == -vh)
+ tkadjpage(tk, odeltatv.y, &tkt->deltatv.y);
+ if(e == nil) {
+ e = tktsetscroll(tk, Tkvertical);
+ if(e == nil)
+ tktfixscroll(tk, odeltatv);
+ }
+ return e;
+}
+static void
+tktextfocusorder(Tk *tk)
+{
+ TkTindex ix;
+ TkText *t;
+ Tk *isub;
+
+ t = TKobj(TkText, tk);
+ tktstartind(t, &ix);
+ do {
+ if(ix.item->kind == TkTwin) {
+ isub = ix.item->iwin->sub;
+ if(isub != nil)
+ tkappendfocusorder(isub);
+ }
+ } while(tktadjustind(t, TkTbyitem, &ix));
+}
+
+TkCmdtab tktextcmd[] =
+{
+ "bbox", tktextbbox,
+ "cget", tktextcget,
+ "compare", tktextcompare,
+ "configure", tktextconfigure,
+ "debug", tktextdebug,
+ "delete", tktextdelete,
+ "dlineinfo", tktextdlineinfo,
+ "dump", tktextdump,
+ "get", tktextget,
+ "index", tktextindex,
+ "insert", tktextinsert,
+ "mark", tktextmark,
+ "scan", tktextscan,
+ "search", tktextsearch,
+ "see", tktextsee,
+ "selection", tktextselection,
+ "tag", tktexttag,
+ "window", tktextwindow,
+ "xview", tktextxview,
+ "yview", tktextyview,
+ "tkTextButton1", tktextbutton1,
+ "tkTextButton1R", tktextbutton1r,
+ "tkTextDelIns", tktextdelins,
+ "tkTextInsert", tktextinserti,
+ "tkTextSelectTo", tktextselectto,
+ "tkTextSetCursor", tktextsetcursor,
+ "tkTextScrollPages", tktextscrollpages,
+ "tkTextCursor", tktextcursor,
+ nil
+};
+
+TkMethod textmethod = {
+ "text",
+ tktextcmd,
+ tkfreetext,
+ tkdrawtext,
+ tktextgeom,
+ nil,
+ tktextfocusorder,
+ tktdirty,
+ tktrelpos,
+ tktextevent,
+ nil, /* XXX need to implement textsee */
+ tktinwindow,
+ nil,
+ tktxtforgetsub,
+};
--- /dev/null
+++ b/libtk/textw.h
@@ -1,0 +1,230 @@
+typedef struct TkText TkText;
+typedef struct TkTitem TkTitem;
+typedef struct TkTline TkTline;
+typedef struct TkTindex TkTindex;
+typedef struct TkTmarkinfo TkTmarkinfo;
+typedef struct TkTtaginfo TkTtaginfo;
+typedef struct TkTwind TkTwind;
+
+enum
+{
+ /* text item types */
+ TkTascii, /* contiguous string of ascii chars, all with same tags */
+ TkTrune, /* printable utf (one printing position) */
+ TkTtab,
+ TkTnewline, /* line field contains pointer to containing line */
+ TkTcontline, /* end of non-newline line; line field as with TkTnewline */
+ TkTwin,
+ TkTmark,
+
+ TkTbyitem = 0, /* adjustment units */
+ TkTbyitemback,
+ TkTbytline,
+ TkTbytlineback,
+ TkTbychar,
+ TkTbycharback,
+ TkTbycharstart,
+ TkTbyline,
+ TkTbylineback,
+ TkTbylinestart,
+ TkTbylineend,
+ TkTbywordstart,
+ TkTbywordend,
+ TkTbywrapstart,
+ TkTbywrapend,
+
+ TkTselid = 0, /* id of sel tag */
+ TkTmaxtag = 32,
+ Textwidth = 40, /* default width, in chars */
+ Textheight = 10, /* default height, in chars */
+
+ TkTfirst = (1<<0), /* first line in buffer, or after a TkTlast */
+ TkTlast = (1<<1), /* TkTnewline at end of line */
+ TkTdrawn = (1<<2), /* screen cache copy is ok */
+ TkTdlocked = (1<<3), /* display already locked */
+ TkTjustfoc = (1<<4), /* got focus on last B1 press */
+ TkTnodrag = (1<<5), /* ignore B1 drag until B1 up */
+ TkTunset = (1<<31), /* marks int tag options "unspecified" */
+
+ TkTborderwidth = 0,
+ TkTjustify,
+ TkTlmargin1,
+ TkTlmargin2,
+ TkTlmargin3,
+ TkTrmargin,
+ TkTspacing1,
+ TkTspacing2,
+ TkTspacing3,
+ TkToffset,
+ TkTunderline,
+ TkToverstrike,
+ TkTrelief,
+ TkTwrap,
+ TkTlineheight,
+
+ TkTnumopts
+};
+
+struct TkTline
+{
+ Point orig; /* where to put first item of line */
+ int width;
+ int height;
+ int ascent;
+ int flags;
+ TkTitem* items;
+ TkTline* next;
+ TkTline* prev;
+};
+
+struct TkText
+{
+ TkTline start; /* fake before-the-first line */
+ TkTline end; /* fake after-the-last line */
+ Tk* tagshare;
+ TkTtabstop* tabs;
+ TkTtaginfo* tags;
+ TkTmarkinfo* marks;
+ char* xscroll;
+ char* yscroll;
+ uchar selunit; /* select adjustment unit */
+ uchar tflag; /* various text-specific flags */
+ int nlines; /* number of nl items in widget */
+ TkTitem* selfirst; /* first item marked with sel tag */
+ TkTitem* sellast; /* item after last marked with sel tag */
+ Point deltatv; /* vector from text-space to view-space */
+ Point deltaiv; /* vector from image-space to view-space */
+ Point current; /* last known mouse pos */
+ Point track; /* for use when B1 or B2 is down */
+ int nexttag; /* next usable tag index */
+ TkTitem* mouse; /* mouse focus */
+ int inswidth; /* width of insertion cursor */
+ int sborderwidth;
+ int opts[TkTnumopts];
+ int propagate;
+ int scrolltop[2];
+ int scrollbot[2];
+ Image* image;
+ uchar cur_flag; /* text cursor to be shown up? */
+ Rectangle cur_rec; /* last text cursor rectangle */
+};
+
+struct TkTwind
+{
+ Tk* sub; /* Subwindow of canvas */
+ Tk* focus; /* Current Mouse focus */
+ int width; /* current internal width */
+ int height; /* current internal height */
+ int owned; /* true if window is destroyed on item deletion */
+ int align; /* how to align within line */
+ char* create; /* creation script */
+ int padx; /* extra space on each side */
+ int pady; /* extra space on top and bot */
+ int ascent; /* distance from top of widget to baseline */
+ int stretch; /* true if need to stretch height */
+};
+
+struct TkTitem
+{
+ uchar kind; /* e.g. TkTascii, etc */
+ uchar tagextra;
+ short width;
+ TkTitem *next;
+ union {
+ char* string;
+ TkTwind* win;
+ TkTmarkinfo* mark;
+ TkTline* line;
+ } u;
+ ulong tags[1];
+ /* TkTitem length extends tagextra ulongs beyond */
+};
+
+struct TkTmarkinfo
+{
+ char* name;
+ int gravity;
+ TkTitem* cur;
+ TkTmarkinfo* next;
+};
+
+struct TkTtaginfo
+{
+ int id;
+ char* name;
+ TkEnv* env;
+ TkTtabstop* tabs;
+ TkTtaginfo* next;
+ TkAction* binds; /* Binding of current events */
+ int opts[TkTnumopts];
+};
+
+struct TkTindex
+{
+ TkTitem* item;
+ TkTline* line;
+ int pos; /* index within multichar item */
+};
+
+extern TkCmdtab tkttagcmd[];
+extern TkCmdtab tktmarkcmd[];
+extern TkCmdtab tktwincmd[];
+
+extern void tkfreetext(Tk*);
+extern char* tktaddmarkinfo(TkText*, char*, TkTmarkinfo**);
+extern char* tktaddtaginfo(Tk*, char*, TkTtaginfo**);
+extern int tktadjustind(TkText*, int, TkTindex*);
+extern int tktanytags(TkTitem*);
+extern Rectangle tktbbox(Tk*, TkTindex*);
+extern void tktdirty(Tk*);
+extern int tktdispwidth(Tk*, TkTtabstop *tabs, TkTitem*, Font*, int, int, int);
+extern void tktendind(TkText*, TkTindex*);
+extern char* tktextcursor(Tk*, char*, char **);
+extern Tk* tktextevent(Tk*, int, void*);
+extern Tk* tktinwindow(Tk*, Point*);
+extern char* tktextselection(Tk*, char*, char**);
+extern void tktextsize(Tk*, int);
+extern TkTmarkinfo* tktfindmark(TkTmarkinfo*, char*);
+extern int tktfindsubitem(Tk*, TkTindex*);
+extern TkTtaginfo* tktfindtag(TkTtaginfo*, char*);
+extern char* tktfixgeom(Tk*, TkTline*, TkTline*, int);
+extern void tktfreeitems(TkText*, TkTitem*, int);
+extern void tktfreelines(TkText*, TkTline*, int);
+extern void tktfreemarks(TkTmarkinfo*);
+extern void tktfreetabs(TkTtabstop*);
+extern void tktfreetags(TkTtaginfo*);
+extern int tktindcompare(TkText*, TkTindex*, int, TkTindex*);
+extern int tktindbefore(TkTindex*, TkTindex*);
+extern int tktindrune(TkTindex*);
+extern char* tktinsert(Tk*, TkTindex*, char*, TkTitem*);
+extern int tktisbreak(int);
+extern void tktitemind(TkTitem*, TkTindex*);
+extern char* tktiteminsert(TkText*, TkTindex*, TkTitem*);
+extern TkTline* tktitemline(TkTitem*);
+extern char* tktindparse(Tk*, char**, TkTindex*);
+extern TkTitem* tktlastitem(TkTitem*);
+extern int tktlinenum(TkText*, TkTindex*);
+extern int tktlinepos(TkText*, TkTindex*);
+extern int tktmarkind(Tk*, char*, TkTindex*);
+extern char* tktmarkmove(Tk*, TkTmarkinfo*, TkTindex*);
+extern char* tktmarkparse(Tk*, char**, TkTmarkinfo**);
+extern int tktmaxwid(TkTline*);
+extern char* tktnewitem(int, int, TkTitem**);
+extern char* tktnewline(int, TkTitem*, TkTline*, TkTline*, TkTline**);
+extern int tktposcount(TkTitem*);
+extern TkTline* tktprevwrapline(Tk*, TkTline*);
+extern void tktremitem(TkText*, TkTindex*);
+extern int tktsametags(TkTitem*, TkTitem*);
+extern char* tktsplititem(TkTindex*);
+extern void tktstartind(TkText*, TkTindex*);
+extern char* tkttagchange(Tk*, int, TkTindex*, TkTindex*, int);
+extern int tkttagbit(TkTitem*, int, int);
+extern void tkttagcomb(TkTitem*, TkTitem*, int);
+extern int tkttagind(Tk*, char*, int, TkTindex*);
+extern char* tkttagname(TkText*, int);
+extern int tkttagnrange(TkText*, int, TkTindex*, TkTindex*, TkTindex*, TkTindex*);
+extern void tkttagopts(Tk*, TkTitem*, int*, TkEnv*, TkTtabstop **, int);
+extern char* tkttagparse(Tk*, char**, TkTtaginfo**);
+extern int tkttagset(TkTitem*, int);
+extern int tktxyind(Tk*, int, int, TkTindex*);
+extern void tktxtforgetsub(Tk*, Tk*);
--- /dev/null
+++ b/libtk/tindx.c
@@ -1,0 +1,610 @@
+#include "lib9.h"
+#include "draw.h"
+#include "tk.h"
+#include "textw.h"
+
+#define istring u.string
+#define iwin u.win
+#define imark u.mark
+#define iline u.line
+
+/* debugging */
+extern int tktdbg;
+extern void tktprinttext(TkText*);
+extern void tktprintindex(TkTindex*);
+extern void tktprintitem(TkTitem*);
+extern void tktprintline(TkTline*);
+
+char*
+tktindparse(Tk *tk, char **pspec, TkTindex *ans)
+{
+ int m, n, done, neg, modstart;
+ char *s, *mod;
+ TkTline *lend;
+ TkText *tkt;
+ char *buf;
+
+ buf = mallocz(Tkmaxitem, 0);
+ if(buf == nil)
+ return TkNomem;
+
+ tkt = TKobj(TkText, tk);
+ lend = &tkt->end;
+
+ *pspec = tkword(tk->env->top, *pspec, buf, buf+Tkmaxitem, nil);
+ modstart = 0;
+ for(mod = buf; *mod != '\0'; mod++)
+ if(*mod == ' ' || *mod == '-' || *mod == '+') {
+ modstart = *mod;
+ *mod = '\0';
+ break;
+ }
+
+ /*
+ * XXX there's a problem here - if either coordinate is negative
+ * which shouldn't be precluded, then the above scanning code
+ * will break up the coordinate pair, so @-23,45 for example
+ * yields a bad index, when it should probably return the index
+ * of the character at the start of the line containing y=45.
+ * i've seen this cause wm/sh to crash.
+ */
+ if(strcmp(buf, "end") == 0)
+ tktendind(tkt, ans);
+ else
+ if(*buf == '@') {
+ /* by coordinates */
+
+ s = strchr(buf, ',');
+ if(s == nil) {
+ free(buf);
+ return TkBadix;
+ }
+ *s = '\0';
+ m = atoi(buf+1);
+ n = atoi(s+1);
+ tktxyind(tk, m, n, ans);
+ }
+ else
+ if(*buf >= '0' && *buf <= '9') {
+ /* line.char */
+
+ s = strchr(buf, '.');
+ if(s == nil) {
+ free(buf);
+ return TkBadix;
+ }
+ *s = '\0';
+ m = atoi(buf);
+ n = atoi(s+1);
+
+ if(m < 1)
+ m = 1;
+
+ tktstartind(tkt, ans);
+
+ while(--m > 0 && ans->line->next != lend)
+ tktadjustind(tkt, TkTbyline, ans);
+
+ while(n-- > 0 && ans->item->kind != TkTnewline)
+ tktadjustind(tkt, TkTbychar, ans);
+ }
+ else
+ if(*buf == '.') {
+ /* window */
+
+ tktstartind(tkt, ans);
+
+ while(ans->line != lend) {
+ if(ans->item->kind == TkTwin &&
+ ans->item->iwin->sub != nil &&
+ ans->item->iwin->sub->name != nil &&
+ strcmp(ans->item->iwin->sub->name->name, buf) == 0)
+ break;
+ if(!tktadjustind(tkt, TkTbyitem, ans))
+ ans->line = lend;
+ }
+ if(ans->line == lend) {
+ free(buf);
+ return TkBadix;
+ }
+ }
+ else {
+ s = strchr(buf, '.');
+ if(s == nil) {
+ if(tktmarkind(tk, buf, ans) == 0) {
+ free(buf);
+ return TkBadix;
+ }
+ }
+ else {
+ /* tag.first or tag.last */
+
+ *s = '\0';
+ if(strcmp(s+1, "first") == 0) {
+ if(tkttagind(tk, buf, 1, ans) == 0) {
+ free(buf);
+ return TkBadix;
+ }
+ }
+ else
+ if(strcmp(s+1, "last") == 0) {
+ if(tkttagind(tk, buf, 0, ans) == 0) {
+ free(buf);
+ return TkBadix;
+ }
+ }
+ else {
+ free(buf);
+ return TkBadix;
+ }
+ }
+ }
+
+ if(modstart == 0) {
+ free(buf);
+ return nil;
+ }
+
+ *mod = modstart;
+ while(*mod == ' ')
+ mod++;
+
+ while(*mod != '\0') {
+ done = 0;
+ switch(*mod) {
+ case '+':
+ case '-':
+ neg = (*mod == '-');
+ mod++;
+ while(*mod == ' ')
+ mod++;
+ n = strtol(mod, &mod, 10);
+ while(*mod == ' ')
+ mod++;
+ while(n-- > 0) {
+ if(*mod == 'c')
+ tktadjustind(tkt, neg? TkTbycharback : TkTbychar, ans);
+ else
+ if(*mod == 'l')
+ tktadjustind(tkt, neg? TkTbylineback : TkTbyline, ans);
+ else
+ done = 1;
+ }
+ break;
+ case 'l':
+ if(strncmp(mod, "lines", 5) == 0)
+ tktadjustind(tkt, TkTbylinestart, ans);
+ else
+ if(strncmp(mod, "linee", 5) == 0)
+ tktadjustind(tkt, TkTbylineend, ans);
+ else
+ done = 1;
+ break;
+ case 'w':
+ if(strncmp(mod, "words", 5) == 0)
+ tktadjustind(tkt, TkTbywordstart, ans);
+ else
+ if(strncmp(mod, "worde", 5) == 0)
+ tktadjustind(tkt, TkTbywordend, ans);
+ else
+ done = 1;
+ break;
+ default:
+ done = 1;
+ }
+
+ if(done)
+ break;
+
+ while(tkiswordchar(*mod))
+ mod++;
+ while(*mod == ' ')
+ mod++;
+ }
+
+ free(buf);
+ return nil;
+}
+
+int
+tktisbreak(int c)
+{
+ /* unicode rules suggest / as well but that would split dates, and URLs might as well char. wrap */
+ return c == ' ' || c == '\t' || c == '\n' || c == '-' || c == ',';
+ /* previously included . but would probably need more then to handle ." */
+}
+
+/*
+ * Adjust the index p by units (one of TkTbyitem, etc.).
+ * The TkTbychar units mean that the final point should rest on a
+ * "character" (in text widget index space; i.e., a newline, a rune,
+ * and an embedded window are each 1 character, but marks and contlines are not).
+ *
+ * Indexes may not point in the tkt->start or tkt->end lines (which have
+ * no items); tktadjustind sticks at the beginning or end of the buffer.
+ *
+ * Return 1 if the index changes at all, 0 otherwise.
+ */
+int
+tktadjustind(TkText *tkt, int units, TkTindex *p)
+{
+ int n, opos, count, c;
+ TkTitem *i, *it, *oit;
+ TkTindex q;
+
+ oit = p->item;
+ opos = p->pos;
+ count = 1;
+
+ switch(units) {
+ case TkTbyitemback:
+ it = p->item;
+ p->item = p->line->items;
+ p->pos = 0;
+ if(it == p->item) {
+ if(p->line->prev != &tkt->start) {
+ p->line = p->line->prev;
+ p->item = tktlastitem(p->line->items);
+ }
+ }
+ else {
+ while(p->item->next != it) {
+ p->item = p->item->next;
+ if(tktdbg && p->item == nil) {
+ print("tktadjustind: botch 1\n");
+ break;
+ }
+ }
+ }
+ break;
+
+ case TkTbyitem:
+ p->pos = 0;
+ i = p->item->next;
+ if(i == nil) {
+ if(p->line->next != &tkt->end) {
+ p->line = p->line->next;
+ p->item = p->line->items;
+ }
+ }
+ else
+ p->item = i;
+ break;
+
+ case TkTbytlineback:
+ if(p->line->prev != &tkt->start)
+ p->line = p->line->prev;
+ p->item = p->line->items;
+ p->pos = 0;
+ break;
+
+ case TkTbytline:
+ if(p->line->next != &tkt->end)
+ p->line = p->line->next;
+ p->item = p->line->items;
+ p->pos = 0;
+ break;
+
+ case TkTbycharstart:
+ count = 0;
+ case TkTbychar:
+ while(count > 0) {
+ i = p->item;
+ n = tktposcount(i) - p->pos;
+ if(count >= n) {
+ if(tktadjustind(tkt, TkTbyitem, p))
+ count -= n;
+ else
+ break;
+ }
+ else {
+ p->pos += count;
+ break;
+ }
+ }
+ while(p->item->kind == TkTmark || p->item->kind == TkTcontline)
+ if(!tktadjustind(tkt, TkTbyitem, p))
+ break;
+ break;
+ case TkTbycharback:
+ count = -1;
+ while(count < 0) {
+ if(p->pos + count >= 0) {
+ p->pos += count;
+ count = 0;
+ }
+ else {
+ count += p->pos;
+ if(!tktadjustind(tkt, TkTbyitemback, p))
+ break;
+ n = tktposcount(p->item);
+ p->pos = n;
+ }
+ }
+ break;
+
+ case TkTbylineback:
+ count = -1;
+ /* fall through */
+ case TkTbyline:
+ n = tktlinepos(tkt, p);
+ while(count > 0) {
+ if(p->line->next == &tkt->end) {
+ count = 0;
+ break;
+ }
+ if(p->line->flags&TkTlast)
+ count--;
+ p->line = p->line->next;
+ }
+ while(count < 0 && p->line->prev != &tkt->start) {
+ if(p->line->flags&TkTfirst)
+ count++;
+ p->line = p->line->prev;
+ }
+ tktadjustind(tkt, TkTbylinestart, p);
+ while(n > 0) {
+ if(p->item->kind == TkTnewline)
+ break;
+ if(!tktadjustind(tkt, TkTbychar, p))
+ break;
+ n--;
+ }
+ break;
+
+ case TkTbylinestart:
+ /* note: can call this with only p->line set correctly in *p */
+
+ while(!(p->line->flags&TkTfirst))
+ p->line = p->line->prev;
+ p->item = p->line->items;
+ p->pos = 0;
+ break;
+
+ case TkTbylineend:
+ while(p->item->kind != TkTnewline)
+ if(!tktadjustind(tkt, TkTbychar, p))
+ break;
+ break;
+
+ case TkTbywordstart:
+ tktadjustind(tkt, TkTbycharstart, p);
+ q = *p;
+ c = tktindrune(p);
+ while(tkiswordchar(c)) {
+ q = *p;
+ if(!tktadjustind(tkt, TkTbycharback, p))
+ break;
+ c = tktindrune(p);
+ }
+ *p = q;
+ break;
+
+ case TkTbywordend:
+ tktadjustind(tkt, TkTbycharstart, p);
+ if(p->item->kind == TkTascii || p->item->kind == TkTrune) {
+ c = tktindrune(p);
+ if(tkiswordchar(c)) {
+ do {
+ if(!tktadjustind(tkt, TkTbychar, p))
+ break;
+ c = tktindrune(p);
+ } while(tkiswordchar(c));
+ }
+ else
+ tktadjustind(tkt, TkTbychar, p);
+ }
+ else if(!(p->item->kind == TkTnewline && p->line->next == &tkt->end))
+ tktadjustind(tkt, TkTbychar, p);
+
+ break;
+
+ case TkTbywrapstart:
+ tktadjustind(tkt, TkTbycharstart, p);
+ q = *p;
+ c = tktindrune(p);
+ while(!tktisbreak(c)) {
+ q = *p;
+ if(!tktadjustind(tkt, TkTbycharback, p))
+ break;
+ c = tktindrune(p);
+ }
+ *p = q;
+ break;
+
+ case TkTbywrapend:
+ tktadjustind(tkt, TkTbycharstart, p);
+ if(p->item->kind == TkTascii || p->item->kind == TkTrune) {
+ c = tktindrune(p);
+ if(!tktisbreak(c)) {
+ do {
+ if(!tktadjustind(tkt, TkTbychar, p))
+ break;
+ c = tktindrune(p);
+ } while(!tktisbreak(c) && (p->item->kind == TkTascii || p->item->kind == TkTrune));
+ while(tktisbreak(c) && tktadjustind(tkt, TkTbychar, p))
+ c = tktindrune(p); /* could limit it */
+ }
+ else
+ tktadjustind(tkt, TkTbychar, p);
+ }
+ else if(!(p->item->kind == TkTnewline && p->line->next == &tkt->end))
+ tktadjustind(tkt, TkTbychar, p);
+
+ break;
+ }
+ return (p->item != oit || p->pos != opos);
+}
+
+/* return 1 if advancing i1 by item eventually hits i2 */
+int
+tktindbefore(TkTindex *i1, TkTindex *i2)
+{
+ int ans;
+ TkTitem *i;
+ TkTline *l1, *l2;
+
+ ans = 0;
+ l1 = i1->line;
+ l2 = i2->line;
+
+ if(l1 == l2) {
+ if(i1->item == i2->item)
+ ans = (i1->pos < i2->pos);
+ else {
+ for(i = i1->item; i != nil; i = i->next)
+ if(i->next == i2->item) {
+ ans = 1;
+ break;
+ }
+ }
+ }
+ else {
+ if(l1->orig.y < l2->orig.y)
+ ans = 1;
+ else
+ if(l1->orig.y == l2->orig.y) {
+ for(; l1 != nil; l1 = l1->next) {
+ if(l1->next == l2) {
+ ans = 1;
+ break;
+ }
+ if(l1->orig.y > l2->orig.y)
+ break;
+ }
+ }
+ }
+
+ return ans;
+}
+
+/*
+ * This comparison only cares which characters the indices are before.
+ * So two marks should be called "equal" (and not "less" or "greater")
+ * if they are adjacent.
+ */
+int
+tktindcompare(TkText *tkt, TkTindex *i1, int op, TkTindex *i2)
+{
+ int eq, ans;
+ TkTindex x1, x2;
+
+ x1 = *i1;
+ x2 = *i2;
+
+ /* skip over any marks, contlines, to see if on same character */
+ tktadjustind(tkt, TkTbycharstart, &x1);
+ tktadjustind(tkt, TkTbycharstart, &x2);
+ eq = (x1.item == x2.item && x1.pos == x2.pos);
+
+ switch(op) {
+ case TkEq:
+ ans = eq;
+ break;
+ case TkNeq:
+ ans = !eq;
+ break;
+ case TkLte:
+ ans = eq || tktindbefore(i1, i2);
+ break;
+ case TkLt:
+ ans = !eq && tktindbefore(i1, i2);
+ break;
+ case TkGte:
+ ans = eq || tktindbefore(i2, i1);
+ break;
+ case TkGt:
+ ans = !eq && tktindbefore(i2, i1);
+ break;
+ default:
+ ans = 0; /* not reached */
+ break;
+ };
+
+ return ans;
+}
+
+void
+tktstartind(TkText *tkt, TkTindex *ans)
+{
+ ans->line = tkt->start.next;
+ ans->item = ans->line->items;
+ ans->pos = 0;
+}
+
+void
+tktendind(TkText *tkt, TkTindex *ans)
+{
+ ans->line = tkt->end.prev;
+ ans->item = tktlastitem(ans->line->items);
+ ans->pos = 0;
+}
+
+void
+tktitemind(TkTitem *it, TkTindex *ans)
+{
+ ans->item = it;
+ ans->line = tktitemline(it);
+ ans->pos = 0;
+}
+
+/*
+ * Fill ans with the item that (x,y) (in V space) is over.
+ * Return 0 if it is over the first half of the width,
+ * and 1 if it is over the second half.
+ */
+int
+tktxyind(Tk *tk, int x, int y, TkTindex *ans)
+{
+ int n, w, secondhalf, k;
+ Point p, q;
+ TkTitem *i;
+ TkText *tkt;
+
+ tkt = TKobj(TkText, tk);
+ tktstartind(tkt, ans);
+ secondhalf = 0;
+
+ /* (x,y), p, q in V space */
+ p = subpt(ans->line->orig, tkt->deltatv);
+ q = subpt(ans->line->next->orig, tkt->deltatv);
+ while(ans->line->next != &tkt->end) {
+ if(q.y > y)
+ break;
+ tktadjustind(tkt, TkTbytline, ans);
+ p = q;
+ q = subpt(ans->line->next->orig, tkt->deltatv);
+ }
+ if (ans->line->next == &tkt->end) {
+ Point ep = subpt(tkt->end.orig, tkt->deltatv);
+ if (ep.y < y)
+ x = 1000000;
+ }
+
+ while(ans->item->next != nil) {
+ i = ans->item;
+ w = i->width;
+ if(p.x+w > x) {
+ n = tktposcount(i);
+ if(n > 1) {
+ for(k = 0; k < n; k++) {
+ /* probably wrong w.r.t tag tabs */
+ w = tktdispwidth(tk, nil, i, nil, p.x, k, 1);
+ if(p.x+w > x) {
+ ans->pos = k;
+ break;
+ }
+ p.x += w;
+ }
+ }
+ secondhalf = (p.x + w/2 <= x);
+ break;
+ }
+ p.x += w;
+ if(!tktadjustind(tkt, TkTbyitem, ans))
+ break;
+ }
+ tktadjustind(tkt, TkTbycharstart, ans);
+ return secondhalf;
+}
+
--- /dev/null
+++ b/libtk/tmark.c
@@ -1,0 +1,392 @@
+#include "lib9.h"
+#include "draw.h"
+#include "tk.h"
+#include "textw.h"
+
+#define istring u.string
+#define iwin u.win
+#define imark u.mark
+#define iline u.line
+
+static char* tktmarkgravity(Tk*, char*, char**);
+static char* tktmarknames(Tk*, char*, char**);
+static char* tktmarknext(Tk*, char*, char**);
+static char* tktmarkprevious(Tk*, char*, char**);
+static char* tktmarkset(Tk*, char*, char**);
+static char* tktmarkunset(Tk*, char*, char**);
+
+TkCmdtab
+tktmarkcmd[] =
+{
+ "gravity", tktmarkgravity,
+ "names", tktmarknames,
+ "next", tktmarknext,
+ "previous", tktmarkprevious,
+ "set", tktmarkset,
+ "unset", tktmarkunset,
+ nil
+};
+
+char*
+tktaddmarkinfo(TkText *tkt, char *name, TkTmarkinfo **ret)
+{
+ TkTmarkinfo *mi;
+
+ mi = malloc(sizeof(TkTmarkinfo));
+ if(mi == nil)
+ return TkNomem;
+
+ mi->name = strdup(name);
+ if(mi->name == nil) {
+ free(mi);
+ return TkNomem;
+ }
+ mi->gravity = Tkright;
+ mi->cur = nil;
+ mi->next = tkt->marks;
+ tkt->marks = mi;
+ *ret = mi;
+ return nil;
+}
+
+void
+tktfreemarks(TkTmarkinfo *m)
+{
+ TkTmarkinfo *n;
+
+ while(m != nil) {
+ n = m->next;
+ free(m->name);
+ free(m);
+ m = n;
+ }
+}
+
+TkTmarkinfo *
+tktfindmark(TkTmarkinfo *m, char *name)
+{
+ while(m != nil) {
+ if(strcmp(m->name, name) == 0)
+ return m;
+ m = m->next;
+ }
+ return nil;
+}
+
+int
+tktmarkind(Tk *tk, char *name, TkTindex *ans)
+{
+ TkTmarkinfo *mk;
+ TkText *tkt = TKobj(TkText, tk);
+
+ if(strcmp(name, "current") == 0) {
+ tktxyind(tk, tkt->current.x, tkt->current.y, ans);
+ return 1;
+ }
+
+ mk = tktfindmark(tkt->marks, name);
+ if(mk == nil || mk->cur == nil)
+ return 0;
+
+ ans->item = mk->cur;
+ ans->line = tktitemline(ans->item);
+ ans->pos = 0;
+ return 1;
+}
+
+char*
+tktmarkparse(Tk *tk, char **parg, TkTmarkinfo **ret)
+{
+ char *e, *buf;
+ TkText *tkt = TKobj(TkText, tk);
+
+ buf = mallocz(Tkmaxitem, 0);
+ if(buf == nil)
+ return TkNomem;
+
+ *parg = tkword(tk->env->top, *parg, buf, buf+Tkmaxitem, nil);
+ if(*buf == '\0') {
+ free(buf);
+ return TkOparg;
+ }
+
+ *ret = tktfindmark(tkt->marks, buf);
+ if(*ret == nil) {
+ e = tktaddmarkinfo(tkt, buf, ret);
+ if(e != nil) {
+ free(buf);
+ return e;
+ }
+ }
+ free(buf);
+
+ return nil;
+}
+
+/*
+ * Insert mark before ixnew, first removing it from old place, if any.
+ * Make sure ixnew continues to point after mark.
+ */
+char*
+tktmarkmove(Tk *tk, TkTmarkinfo *m, TkTindex *ixnew)
+{
+ char *e;
+ int deleted, split;
+ TkTitem *i;
+ TkTindex ix, pix;
+ TkText *tkt = TKobj(TkText, tk);
+
+ deleted = 0;
+ if(m->cur != nil) {
+ if(m->cur == ixnew->item)
+ return nil;
+ ix.item = m->cur;
+ ix.line = tktitemline(m->cur);
+ ix.pos = 0;
+ tktremitem(tkt, &ix);
+ deleted = 1;
+ }
+
+ /* XXX - Tad: memory leak on 'i' if something fails later? */
+ e = tktnewitem(TkTmark, 0, &i);
+ if(e != nil)
+ return e;
+
+ i->imark = m;
+ m->cur = i;
+
+ /* keep adjacent marks sorted: all rights, then all lefts */
+ if(m->gravity == Tkright) {
+ while(ixnew->item->kind == TkTmark && ixnew->item->imark->gravity == Tkleft)
+ if(!tktadjustind(tkt, TkTbyitem, ixnew))
+ break;
+ }
+ else {
+ for(;;) {
+ pix = *ixnew;
+ if(!tktadjustind(tkt, TkTbyitemback, &pix))
+ break;
+ if(pix.item->kind == TkTmark && pix.item->imark->gravity == Tkright)
+ *ixnew = pix;
+ else
+ break;
+ }
+ }
+
+ split = (ixnew->pos > 0);
+ e = tktsplititem(ixnew);
+ if(e != nil)
+ return e;
+
+ e = tktiteminsert(tkt, ixnew, i);
+ if(e != nil)
+ return nil;
+
+ if(strcmp(m->name, "insert") == 0 || split) {
+ if(deleted && ix.line != ixnew->line) {
+ tktfixgeom(tk, tktprevwrapline(tk, ix.line), ix.line, 0);
+ /*
+ * this is ok only because tktfixgeom cannot
+ * free mark items, and we know that i is a mark item.
+ */
+ ixnew->item = i;
+ ixnew->line = tktitemline(i);
+ ixnew->pos = 0;
+ }
+ tktfixgeom(tk, tktprevwrapline(tk, ixnew->line), ixnew->line, 0);
+ tktextsize(tk, 1);
+ }
+
+ ixnew->item = i;
+ ixnew->line = tktitemline(i);
+ ixnew->pos = 0;
+ return nil;
+}
+
+/* Text Mark Commands (+ means implemented)
+ +gravity
+ +names
+ +next
+ +previous
+ +set
+ +unset
+*/
+
+static char*
+tktmarkgravity(Tk *tk, char *arg, char **val)
+{
+ char *e;
+ TkTmarkinfo *m;
+ char *buf;
+
+ e = tktmarkparse(tk, &arg, &m);
+ if(e != nil)
+ return e;
+
+ if(*arg == '\0')
+ return tkvalue(val, (m->gravity & Tkleft)? "left" : "right");
+ else {
+ buf = mallocz(Tkmaxitem, 0);
+ if(buf == nil)
+ return TkNomem;
+ tkword(tk->env->top, arg, buf, buf+Tkmaxitem, nil);
+ if(strcmp(buf, "left") == 0)
+ m->gravity = Tkleft;
+ else
+ if(strcmp(buf, "right") == 0)
+ m->gravity = Tkright;
+ else {
+ free(buf);
+ return TkBadcm;
+ }
+ free(buf);
+ }
+ return nil;
+}
+
+static char*
+tktmarknames(Tk *tk, char *arg, char **val)
+{
+ char *r, *fmt;
+ TkTmarkinfo *m;
+ TkText *tkt = TKobj(TkText, tk);
+
+ USED(arg);
+
+ fmt = "%s";
+ for(m = tkt->marks; m != nil; m = m->next) {
+ r = tkvalue(val, fmt, m->name);
+ if(r != nil)
+ return r;
+ fmt = " %s";
+ }
+ return nil;
+}
+
+static char*
+tktmarknext(Tk *tk, char *arg, char **val)
+{
+ char *e;
+ TkTmarkinfo *mix;
+ TkTindex ix, ixend;
+ TkText *tkt = TKobj(TkText, tk);
+
+ /* special behavior if specified index is a mark name */
+ mix = tktfindmark(tkt->marks, arg);
+
+ e = tktindparse(tk, &arg, &ix);
+ if(e != nil)
+ return e;
+
+ if(mix != nil)
+ tktadjustind(tkt, TkTbyitem, &ix);
+
+ /* special behavior if index is 'end' */
+ tktendind(tkt, &ixend);
+ if(tktindcompare(tkt, &ix, TkEq, &ixend)) {
+ do {
+ tktadjustind(tkt, TkTbyitemback, &ix);
+ } while(ix.item->kind == TkTmark);
+ }
+
+ do {
+ if(ix.item->kind == TkTmark)
+ return tkvalue(val, "%s", ix.item->imark->name);
+
+ } while(tktadjustind(tkt, TkTbyitem, &ix));
+
+ return nil;
+}
+
+static char*
+tktmarkprevious(Tk *tk, char *arg, char **val)
+{
+ char *e;
+ TkTindex ix;
+ TkText *tkt = TKobj(TkText, tk);
+
+ e = tktindparse(tk, &arg, &ix);
+ if(e != nil)
+ return e;
+
+ while(tktadjustind(tkt, TkTbyitemback, &ix)) {
+ if(ix.item->kind == TkTmark)
+ return tkvalue(val, "%s", ix.item->imark->name);
+ }
+
+ return nil;
+}
+
+/* XXX - Tad: possible memory leak here */
+static char*
+tktmarkset(Tk *tk, char *arg, char **val)
+{
+ char *e;
+ TkTmarkinfo *m;
+ TkTindex ixnew;
+
+ USED(val);
+
+ e = tktmarkparse(tk, &arg, &m);
+ if(e != nil)
+ return e;
+ e = tktindparse(tk, &arg, &ixnew);
+ if(e != nil)
+ return e;
+
+ return tktmarkmove(tk, m, &ixnew);
+}
+
+static char*
+tktmarkunset(Tk *tk, char *arg, char **val)
+{
+ TkText *tkt;
+ TkTmarkinfo *m, **p;
+ TkTindex ix;
+ char *e;
+ int resize;
+
+ USED(val);
+
+ tkt = TKobj(TkText, tk);
+
+ e = tktmarkparse(tk, &arg, &m);
+ if(e != nil)
+ return e;
+
+ resize = 0;
+ while(m != nil) {
+ if(strcmp(m->name, "insert") == 0 || strcmp(m->name, "current") == 0)
+ return TkBadvl;
+
+ if(m->cur != nil) {
+ ix.item = m->cur;
+ ix.line = tktitemline(m->cur);
+ ix.pos = 0;
+ tktremitem(tkt, &ix);
+ tktfixgeom(tk, tktprevwrapline(tk, ix.line), ix.line, 0);
+ resize = 1;
+ }
+
+ for(p = &tkt->marks; *p != nil; p = &(*p)->next) {
+ if(*p == m) {
+ *p = m->next;
+ break;
+ }
+ }
+ m->next = nil;
+ tktfreemarks(m);
+
+ if(*arg != '\0') {
+ e = tktmarkparse(tk, &arg, &m);
+ if(e != nil)
+ return e;
+ }
+ else
+ m = nil;
+ }
+ if (resize)
+ tktextsize(tk, 1);
+ return nil;
+}
+
--- /dev/null
+++ b/libtk/ttags.c
@@ -1,0 +1,1029 @@
+#include "lib9.h"
+#include "draw.h"
+#include "tk.h"
+#include "textw.h"
+
+#define istring u.string
+#define iwin u.win
+#define imark u.mark
+#define iline u.line
+
+static char* tkttagadd(Tk*, char*, char**);
+static char* tkttagbind(Tk*, char*, char**);
+static char* tkttagcget(Tk*, char*, char**);
+static char* tkttagconfigure(Tk*, char*, char**);
+static char* tkttagdelete(Tk*, char*, char**);
+static char* tkttaglower(Tk*, char*, char**);
+static char* tkttagnames(Tk*, char*, char**);
+static char* tkttagnextrange(Tk*, char*, char**);
+static char* tkttagprevrange(Tk*, char*, char**);
+static char* tkttagraise(Tk*, char*, char**);
+static char* tkttagranges(Tk*, char*, char**);
+static char* tkttagremove(Tk*, char*, char**);
+
+#define O(t, e) ((long)(&((t*)0)->e))
+
+#define TKTEO (O(TkTtaginfo, env))
+static
+TkOption tagopts[] =
+{
+ "borderwidth",
+ OPTnndist, O(TkTtaginfo, opts[TkTborderwidth]), nil,
+ "justify",
+ OPTstab, O(TkTtaginfo, opts[TkTjustify]), tkjustify,
+ "lineheight",
+ OPTnndist, O(TkTtaginfo, opts[TkTlineheight]), IAUX(TKTEO),
+ "lmargin1",
+ OPTdist, O(TkTtaginfo, opts[TkTlmargin1]), IAUX(TKTEO),
+ "lmargin2",
+ OPTdist, O(TkTtaginfo, opts[TkTlmargin2]), IAUX(TKTEO),
+ "lmargin3",
+ OPTdist, O(TkTtaginfo, opts[TkTlmargin3]), IAUX(TKTEO),
+ "rmargin",
+ OPTdist, O(TkTtaginfo, opts[TkTrmargin]), IAUX(TKTEO),
+ "spacing1",
+ OPTnndist, O(TkTtaginfo, opts[TkTspacing1]), IAUX(TKTEO),
+ "spacing2",
+ OPTnndist, O(TkTtaginfo, opts[TkTspacing2]), IAUX(TKTEO),
+ "spacing3",
+ OPTnndist, O(TkTtaginfo, opts[TkTspacing3]), IAUX(TKTEO),
+ "offset",
+ OPTdist, O(TkTtaginfo, opts[TkToffset]), IAUX(TKTEO),
+ "underline",
+ OPTstab, O(TkTtaginfo, opts[TkTunderline]), tkbool,
+ "overstrike",
+ OPTstab, O(TkTtaginfo, opts[TkToverstrike]), tkbool,
+ "relief",
+ OPTstab, O(TkTtaginfo, opts[TkTrelief]), tkrelief,
+ "tabs",
+ OPTtabs, O(TkTtaginfo, tabs), IAUX(TKTEO),
+ "wrap",
+ OPTstab, O(TkTtaginfo, opts[TkTwrap]), tkwrap,
+ nil,
+};
+
+static
+TkOption tagenvopts[] =
+{
+ "foreground", OPTcolr, O(TkTtaginfo, env), IAUX(TkCforegnd),
+ "background", OPTcolr, O(TkTtaginfo, env), IAUX(TkCbackgnd),
+ "fg", OPTcolr, O(TkTtaginfo, env), IAUX(TkCforegnd),
+ "bg", OPTcolr, O(TkTtaginfo, env), IAUX(TkCbackgnd),
+ "font", OPTfont, O(TkTtaginfo, env), nil,
+ nil
+};
+
+TkCmdtab
+tkttagcmd[] =
+{
+ "add", tkttagadd,
+ "bind", tkttagbind,
+ "cget", tkttagcget,
+ "configure", tkttagconfigure,
+ "delete", tkttagdelete,
+ "lower", tkttaglower,
+ "names", tkttagnames,
+ "nextrange", tkttagnextrange,
+ "prevrange", tkttagprevrange,
+ "raise", tkttagraise,
+ "ranges", tkttagranges,
+ "remove", tkttagremove,
+ nil
+};
+
+int
+tktanytags(TkTitem *it)
+{
+ int i;
+
+ if(it->tagextra == 0)
+ return (it->tags[0] != 0);
+ for(i = 0; i <= it->tagextra; i++)
+ if(it->tags[i] != 0)
+ return 1;
+ return 0;
+}
+
+int
+tktsametags(TkTitem *i1, TkTitem *i2)
+{
+ int i, j;
+
+ for(i = 0; i <= i1->tagextra && i <= i2->tagextra; i++)
+ if(i1->tags[i] != i2->tags[i])
+ return 0;
+ for(j = i; j <= i1->tagextra; j++)
+ if(i1->tags[j] != 0)
+ return 0;
+ for(j = i; j <= i2->tagextra; j++)
+ if(i2->tags[j] != 0)
+ return 0;
+ return 1;
+}
+
+int
+tkttagset(TkTitem *it, int id)
+{
+ int i;
+
+ if(it->tagextra == 0 && it->tags[0] == 0)
+ return 0;
+ for(i = 0; i <= it->tagextra; i++) {
+ if(id < 32)
+ return ((it->tags[i] & (1<<id)) != 0);
+ id -= 32;
+ }
+ return 0;
+}
+
+char *
+tkttagname(TkText *tkt, int id)
+{
+ TkTtaginfo *t;
+
+ for(t = tkt->tags; t != nil; t = t->next) {
+ if(t->id == id)
+ return t->name;
+ }
+ return "";
+}
+
+/* return 1 if this actually changes the value */
+int
+tkttagbit(TkTitem *it, int id, int val)
+{
+ int i, changed;
+ ulong z, b;
+
+ changed = 0;
+ for(i = 0; i <= it->tagextra; i++) {
+ if(id < 32) {
+ b = (1<<id);
+ z = it->tags[i];
+ if(val == 0) {
+ if(z & b) {
+ changed = 1;
+ it->tags[i] = z & (~b);
+ }
+ }
+ else {
+ if((z & b) == 0) {
+ changed = 1;
+ it->tags[i] = z | b;
+ }
+ }
+ break;
+ }
+ id -= 32;
+ }
+ return changed;
+}
+
+void
+tkttagcomb(TkTitem *i1, TkTitem *i2, int add)
+{
+ int i;
+
+ for(i = 0; i <= i1->tagextra && i <= i2->tagextra; i++) {
+ if(add == 1)
+ i1->tags[i] |= i2->tags[i];
+ else if(add == 0)
+ /* intersect */
+ i1->tags[i] &= i2->tags[i];
+ else
+ /* subtract */
+ i1->tags[i] &= ~i2->tags[i];
+ }
+}
+
+char*
+tktaddtaginfo(Tk *tk, char *name, TkTtaginfo **ret)
+{
+ int i, *ntagp;
+ TkTtaginfo *ti;
+ TkText *tkt, *tktshare;
+
+ tkt = TKobj(TkText, tk);
+ ti = malloc(sizeof(TkTtaginfo));
+ if(ti == nil)
+ return TkNomem;
+
+ ntagp = &tkt->nexttag;
+ if(tkt->tagshare != nil) {
+ tktshare = TKobj(TkText, tkt->tagshare);
+ ntagp = &tktshare->nexttag;
+ }
+ ti->id = *ntagp;
+ ti->name = strdup(name);
+ if(ti->name == nil) {
+ free(ti);
+ return TkNomem;
+ }
+ ti->env = tknewenv(tk->env->top);
+ if(ti->env == nil) {
+ free(ti->name);
+ free(ti);
+ return TkNomem;
+ }
+
+ ti->tabs = nil;
+ for(i = 0; i < TkTnumopts; i++)
+ ti->opts[i] = TkTunset;
+ ti->next = tkt->tags;
+ tkt->tags = ti;
+
+ (*ntagp)++;
+ if(tkt->tagshare)
+ tkt->nexttag = *ntagp;
+
+ *ret = ti;
+ return nil;
+}
+
+TkTtaginfo *
+tktfindtag(TkTtaginfo *t, char *name)
+{
+ while(t != nil) {
+ if(strcmp(t->name, name) == 0)
+ return t;
+ t = t->next;
+ }
+ return nil;
+}
+
+void
+tktfreetags(TkTtaginfo *t)
+{
+ TkTtaginfo *n;
+
+ while(t != nil) {
+ n = t->next;
+ free(t->name);
+ tktfreetabs(t->tabs);
+ tkputenv(t->env);
+ tkfreebind(t->binds);
+ free(t);
+ t = n;
+ }
+}
+
+int
+tkttagind(Tk *tk, char *name, int first, TkTindex *ans)
+{
+ int id;
+ TkTtaginfo *t;
+ TkText *tkt;
+
+ tkt = TKobj(TkText, tk);
+
+ if(strcmp(name, "sel") == 0) {
+ if(tkt->selfirst == nil)
+ return 0;
+ if(first)
+ tktitemind(tkt->selfirst, ans);
+ else
+ tktitemind(tkt->sellast, ans);
+ return 1;
+ }
+
+ t = tktfindtag(tkt->tags, name);
+ if(t == nil)
+ return 0;
+ id = t->id;
+
+ if(first) {
+ tktstartind(tkt, ans);
+ while(!tkttagset(ans->item, id))
+ if(!tktadjustind(tkt, TkTbyitem, ans))
+ return 0;
+ }
+ else {
+ tktendind(tkt, ans);
+ while(!tkttagset(ans->item, id))
+ if(!tktadjustind(tkt, TkTbyitemback, ans))
+ return 0;
+ tktadjustind(tkt, TkTbyitem, ans);
+ }
+
+ return 1;
+}
+
+/*
+ * Fill in opts and e, based on info from tags set in it,
+ * using tags order for priority.
+ * If dflt != 0, options not set are filled from tk,
+ * otherwise iInteger options not set by any tag are left 'TkTunset'
+ * and environment values not set are left nil.
+ */
+void
+tkttagopts(Tk *tk, TkTitem *it, int *opts, TkEnv *e, TkTtabstop **tb, int dflt)
+{
+ int i;
+ int colset;
+ TkEnv *te;
+ TkTtaginfo *tags;
+ TkText *tkt = TKobj(TkText, tk);
+
+ if (tb != nil)
+ *tb = tkt->tabs;
+
+ tags = tkt->tags;
+
+ if(opts != nil)
+ for(i = 0; i < TkTnumopts; i++)
+ opts[i] = TkTunset;
+
+ memset(e, 0, sizeof(TkEnv));
+ e->top = tk->env->top;
+ colset = 0;
+ while(tags != nil) {
+ if(tkttagset(it, tags->id)) {
+ if(opts != nil) {
+ for(i = 0; i < TkTnumopts; i++) {
+ if(opts[i] == TkTunset && tags->opts[i] != TkTunset)
+ opts[i] = tags->opts[i];
+ }
+ }
+
+ te = tags->env;
+ for(i = 0; i < TkNcolor; i++)
+ if(!(colset & (1<<i)) && te->set & (1<<i)) {
+ e->colors[i] = te->colors[i];
+ colset |= 1<<i;
+ }
+
+ if(e->font == nil && te->font != nil)
+ e->font = te->font;
+
+ if (tb != nil && tags->tabs != nil)
+ *tb = tags->tabs;
+ }
+ tags = tags->next;
+ }
+ e->set |= colset;
+ if(dflt) {
+ if(opts != nil) {
+ for(i = 0; i < TkTnumopts; i++)
+ if(opts[i] == TkTunset)
+ opts[i] = tkt->opts[i];
+ }
+ te = tk->env;
+ for(i = 0; i < TkNcolor; i++)
+ if(!(e->set & (1<<i))) {
+ e->colors[i] = te->colors[i];
+ e->set |= 1<<i;
+ }
+ if(e->font == nil)
+ e->font = te->font;
+ }
+}
+
+char*
+tkttagparse(Tk *tk, char **parg, TkTtaginfo **ret)
+{
+ char *e, *buf;
+ TkText *tkt = TKobj(TkText, tk);
+
+ buf = mallocz(Tkmaxitem, 0);
+ if(buf == nil)
+ return TkNomem;
+ *parg = tkword(tk->env->top, *parg, buf, buf+Tkmaxitem, nil);
+ if(*buf == '\0') {
+ free(buf);
+ return TkOparg;
+ }
+ if(buf[0] >= '0' && buf[0] <= '9'){
+ free(buf);
+ return TkBadtg;
+ }
+
+ *ret = tktfindtag(tkt->tags, buf);
+ if(*ret == nil) {
+ e = tktaddtaginfo(tk, buf, ret);
+ if(e != nil) {
+ free(buf);
+ return e;
+ }
+ }
+ free(buf);
+
+ return nil;
+}
+
+int
+tkttagnrange(TkText *tkt, int tid, TkTindex *i1, TkTindex *i2,
+ TkTindex *istart, TkTindex *iend)
+{
+ int found;
+
+ found = 0;
+ while(i1->line != &tkt->end) {
+ if(i1->item == i2->item && i2->pos == 0)
+ break;
+ if(tkttagset(i1->item, tid)) {
+ if(!found) {
+ found = 1;
+ *istart = *i1;
+ }
+ if(i1->item == i2->item) {
+ /* i2->pos > 0 */
+ *iend = *i2;
+ return 1;
+ }
+ }
+ else
+ if(i1->item == i2->item || (found && i1->item->kind != TkTmark && i1->item->kind != TkTcontline))
+ break;
+ tktadjustind(tkt, TkTbyitem, i1);
+ }
+ if(found)
+ *iend = *i1;
+
+ return found;
+}
+
+static int
+tkttagprange(TkText *tkt, int tid, TkTindex *i1, TkTindex *i2,
+ TkTindex *istart, TkTindex *iend)
+{
+ int found;
+
+ found = 0;
+ while(i1->line != &tkt->start && i1->item != i2->item) {
+ tktadjustind(tkt, TkTbyitemback, i1);
+ if(tkttagset(i1->item, tid)) {
+ if(!found) {
+ found = 1;
+ *iend = *i1;
+ }
+ }
+ else
+ if(found && i1->item->kind != TkTmark && i1->item->kind != TkTcontline)
+ break;
+ }
+ if(found) {
+ tktadjustind(tkt, TkTbyitem, i1);
+ *istart = *i1;
+ if(i1->item == i2->item)
+ istart->pos = i2->pos;
+ }
+
+ return found;
+}
+
+/* XXX - Tad: potential memory leak on memory allocation failure */
+char *
+tkttagchange(Tk *tk, int tid, TkTindex *i1, TkTindex *i2, int add)
+{
+ char *e;
+ int samei, nextra, j, changed;
+ TkTline *lmin, *lmax;
+ TkTindex ixprev;
+ TkTitem *nit;
+ TkText *tkt = TKobj(TkText, tk);
+
+ if(!tktindbefore(i1, i2))
+ return nil;
+
+ nextra = tid/32;
+ lmin = nil;
+ lmax = nil;
+ tktadjustind(tkt, TkTbycharstart, i1);
+ tktadjustind(tkt, TkTbycharstart, i2);
+ samei = (i1->item == i2->item);
+ if(i2->pos != 0) {
+ e = tktsplititem(i2);
+ if(e != nil)
+ return e;
+ if(samei) {
+ /* split means i1 should now point to previous item */
+ ixprev = *i2;
+ tktadjustind(tkt, TkTbyitemback, &ixprev);
+ i1->item = ixprev.item;
+ }
+ }
+ if(i1->pos != 0) {
+ e = tktsplititem(i1);
+ if(e != nil)
+ return e;
+ }
+ /* now i1 and i2 both point to beginning of non-mark/contline items */
+ if(tid == TkTselid) {
+ /*
+ * Cache location of selection.
+ * Note: there can be only one selection range in widget
+ */
+ if(add) {
+ if(tkt->selfirst != nil)
+ return TkBadsl;
+ tkt->selfirst = i1->item;
+ tkt->sellast = i2->item;
+ }
+ else {
+ tkt->selfirst = nil;
+ tkt->sellast = nil;
+ }
+ }
+ while(i1->item != i2->item) {
+ if(i1->item->kind != TkTmark && i1->item->kind != TkTcontline) {
+ if(tid >= 32 && i1->item->tagextra < nextra) {
+ nit = realloc(i1->item, sizeof(TkTitem) + nextra * sizeof(long));
+ if(nit == nil)
+ return TkNomem;
+ for(j = nit->tagextra+1; j <= nextra; j++)
+ nit->tags[j] = 0;
+ nit->tagextra = nextra;
+ if(i1->line->items == i1->item)
+ i1->line->items = nit;
+ else {
+ ixprev = *i1;
+ tktadjustind(tkt, TkTbyitemback, &ixprev);
+ ixprev.item->next = nit;
+ }
+ /* check nit against cached items */
+ if(tkt->selfirst == i1->item)
+ tkt->selfirst = nit;
+ if(tkt->sellast == i1->item)
+ tkt->sellast = nit;
+ i1->item = nit;
+ }
+ changed = tkttagbit(i1->item, tid, add);
+ if(lmin == nil) {
+ if(changed) {
+ lmin = i1->line;
+ lmax = lmin;
+ }
+ }
+ else {
+ if(changed)
+ lmax = i1->line;
+ }
+ }
+ if(!tktadjustind(tkt, TkTbyitem, i1))
+ break;
+ }
+ if(lmin != nil) {
+ tktfixgeom(tk, tktprevwrapline(tk, lmin), lmax, 0);
+ tktextsize(tk, 1);
+ }
+ return nil;
+}
+
+static char*
+tkttagaddrem(Tk *tk, char *arg, int add)
+{
+ char *e;
+ TkText *tkt;
+ TkTtaginfo *ti;
+ TkTindex ix1, ix2;
+
+ tkt = TKobj(TkText, tk);
+
+ e = tkttagparse(tk, &arg, &ti);
+ if(e != nil)
+ return e;
+
+ while(*arg != '\0') {
+ e = tktindparse(tk, &arg, &ix1);
+ if(e != nil)
+ return e;
+ if(*arg != '\0') {
+ e = tktindparse(tk, &arg, &ix2);
+ if(e != nil)
+ return e;
+ }
+ else {
+ ix2 = ix1;
+ tktadjustind(tkt, TkTbychar, &ix2);
+ }
+ if(!tktindbefore(&ix1, &ix2))
+ continue;
+
+ e = tkttagchange(tk, ti->id, &ix1, &ix2, add);
+ if(e != nil)
+ return e;
+ }
+
+ return nil;
+}
+
+
+/* Text Tag Command (+ means implemented)
+ +add
+ +bind
+ +cget
+ +configure
+ +delete
+ +lower
+ +names
+ +nextrange
+ +prevrange
+ +raise
+ +ranges
+ +remove
+*/
+
+static char*
+tkttagadd(Tk *tk, char *arg, char **val)
+{
+ USED(val);
+
+ return tkttagaddrem(tk, arg, 1);
+}
+
+static char*
+tkttagbind(Tk *tk, char *arg, char **val)
+{
+ char *e;
+ Rune r;
+ TkTtaginfo *ti;
+ TkAction *a;
+ int event, mode;
+ char *cmd, buf[Tkmaxitem];
+
+
+ e = tkttagparse(tk, &arg, &ti);
+ if(e != nil)
+ return e;
+
+ arg = tkskip(arg, " \t");
+ if (arg[0] == '\0')
+ return TkBadsq;
+ arg = tkword(tk->env->top, arg, buf, buf+sizeof(buf), nil);
+ if(buf[0] == '<') {
+ event = tkseqparse(buf+1);
+ if(event == -1)
+ return TkBadsq;
+ }
+ else {
+ chartorune(&r, buf);
+ event = TkKey | r;
+ }
+ if(event == 0)
+ return TkBadsq;
+
+ arg = tkskip(arg, " \t");
+ if(*arg == '\0') {
+ for(a = ti->binds; a; a = a->link)
+ if(event == a->event)
+ return tkvalue(val, "%s", a->arg);
+ return nil;
+ }
+
+ mode = TkArepl;
+ if(*arg == '+') {
+ mode = TkAadd;
+ arg++;
+ }
+ else if(*arg == '-'){
+ mode = TkAsub;
+ arg++;
+ }
+
+ tkword(tk->env->top, arg, buf, buf+sizeof(buf), nil);
+ cmd = strdup(buf);
+ if(cmd == nil)
+ return TkNomem;
+ return tkaction(&ti->binds, event, TkDynamic, cmd, mode);
+}
+
+static char*
+tkttagcget(Tk *tk, char *arg, char **val)
+{
+ char *e;
+ TkTtaginfo *ti;
+ TkOptab tko[3];
+
+ e = tkttagparse(tk, &arg, &ti);
+ if(e != nil)
+ return e;
+
+ tko[0].ptr = ti;
+ tko[0].optab = tagopts;
+ tko[1].ptr = ti;
+ tko[1].optab = tagenvopts;
+ tko[2].ptr = nil;
+
+ return tkgencget(tko, arg, val, tk->env->top);
+}
+
+static char*
+tkttagconfigure(Tk *tk, char *arg, char **val)
+{
+ char *e;
+ TkOptab tko[3];
+ TkTtaginfo *ti;
+ TkTindex ix;
+ TkText *tkt = TKobj(TkText, tk);
+
+ USED(val);
+
+ e = tkttagparse(tk, &arg, &ti);
+ if(e != nil)
+ return e;
+
+ tko[0].ptr = ti;
+ tko[0].optab = tagopts;
+ tko[1].ptr = ti;
+ tko[1].optab = tagenvopts;
+ tko[2].ptr = nil;
+
+ e = tkparse(tk->env->top, arg, tko, nil);
+ if(e != nil)
+ return e;
+
+ if(tkttagind(tk, ti->name, 1, &ix)) {
+ tktfixgeom(tk, tktprevwrapline(tk, ix.line), tkt->end.prev, 0);
+ tktextsize(tk, 1);
+ }
+
+ return nil;
+}
+
+static void
+tktunlinktag(TkText *tkt, TkTtaginfo *t)
+{
+ TkTtaginfo *f, **l;
+
+ l = &tkt->tags;
+ for(f = *l; f != nil; f = f->next) {
+ if(f == t) {
+ *l = t->next;
+ return;
+ }
+ l = &f->next;
+ }
+}
+
+static char*
+tkttagdelete(Tk *tk, char *arg, char **val)
+{
+ TkText *tkt;
+ TkTtaginfo *t;
+ TkTindex ix;
+ char *e;
+ int found;
+
+ USED(val);
+
+ tkt = TKobj(TkText, tk);
+
+ e = tkttagparse(tk, &arg, &t);
+ if(e != nil)
+ return e;
+
+ found = 0;
+ while(t != nil) {
+ if(t->id == TkTselid)
+ return TkBadvl;
+
+ while(tkttagind(tk, t->name, 1, &ix)) {
+ found = 1;
+ tkttagbit(ix.item, t->id, 0);
+ }
+
+ tktunlinktag(tkt, t);
+ t->next = nil;
+ tktfreetags(t);
+
+ if(*arg != '\0') {
+ e = tkttagparse(tk, &arg, &t);
+ if(e != nil)
+ return e;
+ }
+ else
+ t = nil;
+ }
+ if (found) {
+ tktfixgeom(tk, &tkt->start, tkt->end.prev, 0);
+ tktextsize(tk, 1);
+ }
+
+ return nil;
+}
+
+static char*
+tkttaglower(Tk *tk, char *arg, char **val)
+{
+ TkText *tkt;
+ TkTindex ix;
+ TkTtaginfo *t, *tbelow, *f, **l;
+ char *e;
+
+ USED(val);
+
+ tkt = TKobj(TkText, tk);
+
+ e = tkttagparse(tk, &arg, &t);
+ if(e != nil)
+ return e;
+
+ if(*arg != '\0') {
+ e = tkttagparse(tk, &arg, &tbelow);
+ if(e != nil)
+ return e;
+ }
+ else
+ tbelow = nil;
+
+ tktunlinktag(tkt, t);
+
+ if(tbelow != nil) {
+ t->next = tbelow->next;
+ tbelow->next = t;
+ }
+ else {
+ l = &tkt->tags;
+ for(f = *l; f != nil; f = f->next)
+ l = &f->next;
+ *l = t;
+ t->next = nil;
+ }
+ if(tkttagind(tk, t->name, 1, &ix)) {
+ tktfixgeom(tk, tktprevwrapline(tk, ix.line), tkt->end.prev, 0);
+ tktextsize(tk, 1);
+ }
+
+ return nil;
+}
+
+
+static char*
+tkttagnames(Tk *tk, char *arg, char **val)
+{
+ char *e, *r, *fmt;
+ TkTtaginfo *t;
+ TkTindex i;
+ TkText *tkt = TKobj(TkText, tk);
+ TkTitem *tagit;
+
+ if(*arg != '\0') {
+ e = tktindparse(tk, &arg, &i);
+ if(e != nil)
+ return e;
+ /* make sure we're actually on a character */
+ tktadjustind(tkt, TkTbycharstart, &i);
+ tagit = i.item;
+ }
+ else
+ tagit = nil;
+
+ /* generate in order highest-to-lowest priority (contrary to spec) */
+ fmt = "%s";
+ for(t = tkt->tags; t != nil; t = t->next) {
+ if(tagit == nil || tkttagset(tagit, t->id)) {
+ r = tkvalue(val, fmt, t->name);
+ if(r != nil)
+ return r;
+ fmt = " %s";
+ }
+ }
+ return nil;
+}
+
+static char*
+tkttagnextrange(Tk *tk, char *arg, char **val)
+{
+ char *e;
+ TkTtaginfo *t;
+ TkTindex i1, i2, istart, iend;
+ TkText *tkt = TKobj(TkText, tk);
+
+ e = tkttagparse(tk, &arg, &t);
+ if(e != nil)
+ return e;
+ e = tktindparse(tk, &arg, &i1);
+ if(e != nil)
+ return e;
+ if(*arg != '\0') {
+ e = tktindparse(tk, &arg, &i2);
+ if(e != nil)
+ return e;
+ }
+ else
+ tktendind(tkt, &i2);
+
+ if(tkttagnrange(tkt, t->id, &i1, &i2, &istart, &iend))
+ return tkvalue(val, "%d.%d %d.%d",
+ tktlinenum(tkt, &istart), tktlinepos(tkt, &istart),
+ tktlinenum(tkt, &iend), tktlinepos(tkt, &iend));
+
+ return nil;
+}
+
+static char*
+tkttagprevrange(Tk *tk, char *arg, char **val)
+{
+ char *e;
+ TkTtaginfo *t;
+ TkTindex i1, i2, istart, iend;
+ TkText *tkt = TKobj(TkText, tk);
+
+ e = tkttagparse(tk, &arg, &t);
+ if(e != nil)
+ return e;
+ e = tktindparse(tk, &arg, &i1);
+ if(e != nil)
+ return e;
+ if(*arg != '\0') {
+ e = tktindparse(tk, &arg, &i2);
+ if(e != nil)
+ return e;
+ }
+ else
+ tktstartind(tkt, &i2);
+
+ if(tkttagprange(tkt, t->id, &i1, &i2, &istart, &iend))
+ return tkvalue(val, "%d.%d %d.%d",
+ tktlinenum(tkt, &istart), tktlinepos(tkt, &istart),
+ tktlinenum(tkt, &iend), tktlinepos(tkt, &iend));
+
+ return nil;
+}
+
+static char*
+tkttagraise(Tk *tk, char *arg, char **val)
+{
+ TkText *tkt;
+ TkTindex ix;
+ TkTtaginfo *t, *tabove, *f, **l;
+ char *e;
+
+ USED(val);
+
+ tkt = TKobj(TkText, tk);
+
+ e = tkttagparse(tk, &arg, &t);
+ if(e != nil)
+ return e;
+
+ if(*arg != '\0') {
+ e = tkttagparse(tk, &arg, &tabove);
+ if(e != nil)
+ return e;
+ }
+ else
+ tabove = nil;
+
+ tktunlinktag(tkt, t);
+
+ if(tabove != nil) {
+ l = &tkt->tags;
+ for(f = *l; f != nil; f = f->next) {
+ if(f == tabove) {
+ *l = t;
+ t->next = tabove;
+ break;
+ }
+ l = &f->next;
+ }
+ }
+ else {
+ t->next = tkt->tags;
+ tkt->tags = t;
+ }
+
+ if(tkttagind(tk, t->name, 1, &ix)) {
+ tktfixgeom(tk, tktprevwrapline(tk, ix.line), tkt->end.prev, 0);
+ tktextsize(tk, 1);
+ }
+ return nil;
+}
+
+static char*
+tkttagranges(Tk *tk, char *arg, char **val)
+{
+ char *e, *fmt;
+ TkTtaginfo *t;
+ TkTindex i1, i2, istart, iend;
+ TkText *tkt = TKobj(TkText, tk);
+
+ e = tkttagparse(tk, &arg, &t);
+ if(e != nil)
+ return e;
+
+ tktstartind(tkt, &i1);
+ tktendind(tkt, &i2);
+
+ fmt = "%d.%d %d.%d";
+ while(tkttagnrange(tkt, t->id, &i1, &i2, &istart, &iend)) {
+ e = tkvalue(val, fmt,
+ tktlinenum(tkt, &istart), tktlinepos(tkt, &istart),
+ tktlinenum(tkt, &iend), tktlinepos(tkt, &iend));
+ if(e != nil)
+ return e;
+
+ fmt = " %d.%d %d.%d";
+ i1 = iend;
+ }
+
+ return nil;
+}
+
+static char*
+tkttagremove(Tk *tk, char *arg, char **val)
+{
+ USED(val);
+
+ return tkttagaddrem(tk, arg, 0);
+}
--- /dev/null
+++ b/libtk/twind.c
@@ -1,0 +1,389 @@
+#include "lib9.h"
+#include "draw.h"
+#include "tk.h"
+#include "textw.h"
+
+#define istring u.string
+#define iwin u.win
+#define imark u.mark
+#define iline u.line
+
+#define O(t, e) ((long)(&((t*)0)->e))
+
+static char* tktwincget(Tk*, char*, char**);
+static char* tktwinconfigure(Tk*, char*, char**);
+static char* tktwincreate(Tk*, char*, char**);
+static char* tktwinnames(Tk*, char*, char**);
+static int winowned(Tk *tk, Tk *sub);
+
+static
+TkStab tkalign[] =
+{
+ "top", Tktop,
+ "bottom", Tkbottom,
+ "center", Tkcenter,
+ "baseline", Tkbaseline,
+ nil
+};
+
+static
+TkOption twinopts[] =
+{
+ "align", OPTstab, O(TkTwind, align), tkalign,
+ "create", OPTtext, O(TkTwind, create), nil,
+ "padx", OPTnndist, O(TkTwind, padx), nil,
+ "pady", OPTnndist, O(TkTwind, pady), nil,
+ "stretch", OPTstab, O(TkTwind, stretch), tkbool,
+ "window", OPTwinp, O(TkTwind, sub), nil,
+ "ascent", OPTdist, O(TkTwind, ascent), nil,
+ nil
+};
+
+TkCmdtab
+tktwincmd[] =
+{
+ "cget", tktwincget,
+ "configure", tktwinconfigure,
+ "create", tktwincreate,
+ "names", tktwinnames,
+ nil
+};
+
+int
+tktfindsubitem(Tk *sub, TkTindex *ix)
+{
+ Tk *tk, *isub;
+ TkText *tkt;
+
+ tk = sub->parent;
+ if(tk != nil) {
+ tkt = TKobj(TkText, tk);
+ tktstartind(tkt, ix);
+ do {
+ if(ix->item->kind == TkTwin) {
+ isub = ix->item->iwin->sub;
+ if(isub != nil &&
+ isub->name != nil &&
+ strcmp(isub->name->name, sub->name->name) == 0)
+ return 1;
+ }
+ } while(tktadjustind(tkt, TkTbyitem, ix));
+ }
+ return 0;
+}
+
+static void
+tktwindsize(Tk *tk, TkTindex *ix)
+{
+ Tk *s;
+ TkTitem *i;
+ TkTwind *w;
+
+
+ i = ix->item;
+ /* assert(i->kind == TkTwin); */
+
+ w = i->iwin;
+ s = w->sub;
+ if(s == nil)
+ return;
+
+ if(w->width != s->act.width || w->height != s->act.height) {
+ s->act.width = w->width;
+ s->act.height = w->height;
+ if(s->slave) {
+ tkpackqit(s);
+ tkrunpack(tk->env->top);
+ }
+ }
+
+ tktfixgeom(tk, tktprevwrapline(tk, ix->line), ix->line, 0);
+ tktextsize(tk, 1);
+}
+
+void
+tktxtforgetsub(Tk *sub, Tk *tk)
+{
+ TkTwind *w;
+ TkTindex ix;
+
+ if(!tktfindsubitem(sub, &ix))
+ return;
+ w = ix.item->iwin;
+ if(w->focus == tk) {
+if(0)print("tktxtforget sub %p %q focus %p %q\n", sub, tkname(sub), tk, tkname(tk));
+ w->focus = nil;
+ }
+}
+
+static void
+tktwingeom(Tk *sub, int x, int y, int w, int h)
+{
+ TkTindex ix;
+ Tk *tk;
+ TkTwind *win;
+
+ USED(x);
+ USED(y);
+
+ tk = sub->parent;
+ if(!tktfindsubitem(sub, &ix)) {
+ print("tktwingeom: %s not found\n", sub->name->name);
+ return;
+ }
+
+ win = ix.item->iwin;
+
+ win->width = w;
+ win->height = h;
+
+ sub->req.width = w;
+ sub->req.height = h;
+ tktwindsize(tk, &ix);
+}
+
+static void
+tktdestroyed(Tk *sub)
+{
+ TkTindex ix;
+ Tk *tk;
+
+ if(tktfindsubitem(sub, &ix)) {
+ ix.item->iwin->sub = nil;
+ ix.item->iwin->focus = nil;
+ if((tk = sub->parent) != nil) {
+ tktfixgeom(tk, tktprevwrapline(tk, ix.line), ix.line, 0);
+ tktextsize(tk, 1);
+ sub->parent = nil;
+ }
+ }
+}
+
+void
+tktdirty(Tk *sub)
+{
+ Tk *tk, *parent, *isub;
+ TkText *tkt;
+ TkTindex ix;
+
+ parent = nil;
+ for(tk = sub; tk && parent == nil; tk = tk->master)
+ parent = tk->parent;
+ if(tk == nil)
+ return;
+
+ tkt = TKobj(TkText, parent);
+ tktstartind(tkt, &ix);
+ do {
+ if(ix.item->kind == TkTwin) {
+ isub = ix.item->iwin->sub;
+ if(isub != nil) {
+ tktfixgeom(parent, tktprevwrapline(parent, ix.line), ix.line, 0);
+ if (sub->flag & Tktransparent)
+ parent->flag |= Tkrefresh; /* XXX could be more efficient, by drawing the background locally? */
+ return;
+ }
+ }
+ } while(tktadjustind(tkt, TkTbyitem, &ix));
+ tktextsize(parent, 1);
+}
+
+static char*
+tktwinchk(Tk *tk, TkTwind *w, Tk *oldsub)
+{
+ Tk *sub;
+
+ sub = w->sub;
+ if (sub != oldsub) {
+ w->sub = oldsub;
+ if(sub == nil)
+ return nil;
+
+ if(sub->flag & Tkwindow)
+ return TkIstop;
+
+ if(sub->master != nil || sub->parent != nil)
+ return TkWpack;
+
+ if (oldsub != nil) {
+ oldsub->parent = nil;
+ oldsub->geom = nil;
+ oldsub->destroyed = nil;
+ }
+ w->sub = sub;
+ w->focus = nil;
+
+ sub->parent = tk;
+ tksetbits(sub, Tksubsub);
+ sub->geom = tktwingeom;
+ sub->destroyed = tktdestroyed;
+
+ w->width = sub->req.width;
+ w->height = sub->req.height;
+ w->owned = winowned(tk, sub);
+ }
+
+ return nil;
+}
+
+
+/* Text Window Command (+ means implemented)
+ +cget
+ +configure
+ +create
+ +names
+*/
+
+static char*
+tktwincget(Tk *tk, char *arg, char **val)
+{
+ char *e;
+ TkTindex ix;
+ TkOptab tko[2];
+
+ e = tktindparse(tk, &arg, &ix);
+ if(e != nil)
+ return e;
+ if(ix.item->kind != TkTwin)
+ return TkBadwp;
+
+ tko[0].ptr = ix.item->iwin;
+ tko[0].optab = twinopts;
+ tko[1].ptr = nil;
+
+ return tkgencget(tko, arg, val, tk->env->top);
+}
+
+static char*
+tktwinconfigure(Tk *tk, char *arg, char **val)
+{
+ char *e;
+ TkTindex ix;
+ TkOptab tko[2];
+ Tk *oldsub;
+
+ USED(val);
+
+ e = tktindparse(tk, &arg, &ix);
+ if(e != nil)
+ return e;
+ if(ix.item->kind != TkTwin)
+ return TkBadwp;
+
+ oldsub = ix.item->iwin->sub;
+
+ tko[0].ptr = ix.item->iwin;
+ tko[0].optab = twinopts;
+ tko[1].ptr = nil;
+
+ e = tkparse(tk->env->top, arg, tko, nil);
+ if(e != nil)
+ return e;
+
+ e = tktwinchk(tk, ix.item->iwin, oldsub);
+ if(e != nil)
+ return e;
+
+ tktwindsize(tk, &ix);
+ return nil;
+}
+
+/*
+ * return true if tk is an ancestor of sub
+ */
+static int
+winowned(Tk *tk, Tk *sub)
+{
+ int len;
+ if (tk->name == nil || sub->name == nil)
+ return 0;
+ len = strlen(tk->name->name);
+ if (strncmp(tk->name->name, sub->name->name, len) == 0 &&
+ sub->name->name[len] == '.')
+ return 1;
+ return 0;
+}
+
+static char*
+tktwincreate(Tk *tk, char *arg, char **val)
+{
+ char *e;
+ TkTindex ix;
+ TkTitem *i;
+ TkText *tkt;
+ TkOptab tko[2];
+
+ USED(val);
+
+ tkt = TKobj(TkText, tk);
+
+ e = tktindparse(tk, &arg, &ix);
+ if(e != nil)
+ return e;
+
+ e = tktnewitem(TkTwin, 0, &i);
+ if(e != nil)
+ return e;
+
+ i->iwin = malloc(sizeof(TkTwind));
+ if(i->iwin == nil) {
+ tktfreeitems(tkt, i, 1);
+ return TkNomem;
+ }
+
+ memset(i->iwin, 0, sizeof(TkTwind));
+ i->iwin->align = Tkcenter;
+ i->iwin->ascent = -1;
+
+ tko[0].ptr = i->iwin;
+ tko[0].optab = twinopts;
+ tko[1].ptr = nil;
+
+ e = tkparse(tk->env->top, arg, tko, nil);
+ if(e != nil) {
+ err1:
+ tktfreeitems(tkt, i, 1);
+ return e;
+ }
+
+ e = tktwinchk(tk, i->iwin, nil);
+ if(e != nil)
+ goto err1;
+
+ e = tktsplititem(&ix);
+ if(e != nil)
+ goto err1;
+
+ tktiteminsert(tkt, &ix, i);
+ if(e != nil)
+ goto err1;
+
+ tktadjustind(tkt, TkTbyitemback, &ix);
+ tktwindsize(tk, &ix);
+
+ return nil;
+}
+
+static char*
+tktwinnames(Tk *tk, char *arg, char **val)
+{
+ char *e, *fmt;
+ TkTindex ix;
+ TkText *tkt = TKobj(TkText, tk);
+
+ USED(arg);
+
+ tktstartind(tkt, &ix);
+ fmt = "%s";
+ do {
+ if(ix.item->kind == TkTwin &&
+ ix.item->iwin->sub != nil &&
+ ix.item->iwin->sub->name != nil) {
+ e = tkvalue(val, fmt, ix.item->iwin->sub->name->name);
+ if(e != nil)
+ return e;
+ fmt = " %s";
+ }
+ } while(tktadjustind(tkt, TkTbyitem, &ix));
+ return nil;
+}
--- /dev/null
+++ b/libtk/utils.c
@@ -1,0 +1,2124 @@
+#include "lib9.h"
+#include "draw.h"
+#include "tk.h"
+
+struct TkCol
+{
+ ulong rgba1;
+ ulong rgba3; /* if mixed, otherwise DNotacolor */
+ Image* i;
+ TkCol* forw;
+};
+
+extern void rptwakeup(void*, void*);
+extern void* rptproc(char*, int, void*, int (*)(void*), int (*)(void*,int), void (*)(void*));
+
+typedef struct Cmd Cmd;
+struct Cmd
+{
+ char* name;
+ char* (*fn)(TkTop*, char*, char**);
+};
+static struct Cmd cmdmain[] =
+{
+ "bind", tkbind,
+ "button", tkbutton,
+ "canvas", tkcanvas,
+ "checkbutton", tkcheckbutton,
+ "choicebutton", tkchoicebutton,
+ "cursor", tkcursorcmd,
+ "destroy", tkdestroy,
+ "entry", tkentry,
+ "focus", tkfocus,
+ "frame", tkframe,
+ "grab", tkgrab,
+ "grid", tkgrid,
+ "image", tkimage,
+ "label", tklabel,
+ "listbox", tklistbox,
+ "lower", tklower,
+ "menu", tkmenu,
+ "menubutton", tkmenubutton,
+ "pack", tkpack,
+ "panel", tkpanel,
+ "puts", tkputs,
+ "radiobutton", tkradiobutton,
+ "raise", tkraise,
+ "scale", tkscale,
+ "scrollbar", tkscrollbar,
+ "see", tkseecmd,
+ "send", tksend,
+ "text", tktext,
+ "update", tkupdatecmd,
+ "variable", tkvariable,
+ "winfo", tkwinfo,
+};
+
+char* tkfont;
+
+/*
+ * auto-repeating support
+ * should perhaps be one rptproc per TkCtxt
+ * This is not done for the moment as there isn't
+ * a mechanism for terminating the rptproc
+ */
+static void *autorpt;
+static int rptid;
+static Tk *rptw;
+static void *rptnote;
+static void (*rptcb)(Tk*, void*, int);
+static long rptto;
+static int rptint;
+
+/* blinking carets - should be per TkCtxt */
+static void *blinkrpt;
+static Tk *blinkw;
+static void (*blinkcb)(Tk*, int);
+static int blinkignore;
+static int blinkon;
+
+
+ulong
+tkrgba(int r, int g, int b, int a)
+{
+ ulong p;
+
+ if(r < 0)
+ r = 0;
+ else if(r > 255)
+ r = 255;
+ if(g < 0)
+ g = 0;
+ else if(g > 255)
+ g = 255;
+ if(b < 0)
+ b = 0;
+ else if(b > 255)
+ b = 255;
+ p = (r<<24)|(g<<16)|(b<<8)|0xFF;
+ if(a == 255)
+ return p;
+ return setalpha(p, a);
+}
+
+/* to be replaced */
+static int
+revalpha(int c, int a)
+{
+ if (a == 0)
+ return 0;
+ return (c & 0xff) * 255 / a;
+}
+
+void
+tkrgbavals(ulong rgba, int *R, int *G, int *B, int *A)
+{
+ int a;
+
+ a = rgba & 0xff;
+ *A = a;
+ if (a != 0xff) {
+ *R = revalpha(rgba>>24, a);
+ *G = revalpha((rgba>>16) & 0xFF, a);
+ *B = revalpha((rgba >> 8) & 0xFF, a);
+ } else {
+ *R = (rgba>>24);
+ *G = ((rgba>>16) & 0xFF);
+ *B = ((rgba >> 8) & 0xFF);
+ }
+}
+
+static int
+tkcachecol(TkCtxt *c, Image *i, ulong one, ulong three)
+{
+ TkCol *cc;
+
+ cc = malloc(sizeof(*cc));
+ if(cc == nil)
+ return 0;
+ cc->rgba1 = one;
+ cc->rgba3 = three;
+ cc->i = i;
+ cc->forw = c->chead;
+ c->chead = cc;
+ c->ncol++;
+ /* we'll do LRU management at some point */
+ if(c->ncol > TkColcachesize){
+ static int warn;
+ if(warn == 0){
+ warn = 1;
+ print("tk: %d colours cached\n", TkColcachesize);
+ }
+ }
+ return 1;
+}
+
+static Image*
+tkfindcol(TkCtxt *c, ulong one, ulong three)
+{
+ TkCol *cc, **l;
+
+ for(l = &c->chead; (cc = *l) != nil; l = &cc->forw)
+ if(cc->rgba1 == one && cc->rgba3 == three){
+ /* move it up in the list */
+ *l = cc->forw;
+ cc->forw = c->chead;
+ c->chead = cc;
+ /* we assume it will be used right away and not stored */
+ return cc->i;
+ }
+ return nil;
+}
+
+void
+tkfreecolcache(TkCtxt *c)
+{
+ TkCol *cc;
+
+ if(c == nil)
+ return;
+ while((cc = c->chead) != nil){
+ c->chead = cc->forw;
+ freeimage(cc->i);
+ free(cc);
+ }
+ c->ctail = nil;
+ c->ncol = 0;
+}
+
+Image*
+tkcolormix(TkCtxt *c, ulong one, ulong three)
+{
+ Image *i;
+ Display *d;
+
+ i = tkfindcol(c, one, three);
+ if(i != nil)
+ return i;
+ d = c->display;
+ i = allocimagemix(d, one, three);
+ if(i == nil)
+ return d->black;
+ if(!tkcachecol(c, i, one, three)){
+ freeimage(i);
+ return d->black;
+ }
+ return i;
+}
+
+Image*
+tkcolor(TkCtxt *c, ulong pix)
+{
+ Image *i;
+ Display *d;
+ Rectangle r;
+
+ d = c->display;
+ if(pix == DWhite)
+ return d->white;
+ if(pix == DBlack)
+ return d->black;
+ i = tkfindcol(c, pix, DNotacolor);
+ if(i != nil)
+ return i;
+ r.min = ZP;
+ r.max.x = 1;
+ r.max.y = 1;
+ if ((pix & 0xff) == 0xff)
+ i = allocimage(d, r, RGB24, 1, pix);
+ else
+ i = allocimage(d, r, RGBA32, 1, pix);
+ if(i == nil)
+ return d->black;
+ if(!tkcachecol(c, i, pix, DNotacolor)) {
+ freeimage(i);
+ return d->black;
+ }
+ return i;
+}
+
+Image*
+tkgradient(TkCtxt *c, Rectangle r, int dir, ulong pix0, ulong pix1)
+{
+ Display *d;
+ Image *i;
+ uchar *b, *p, *e;
+ int c0[3], c1[3], delta[3], a, j, x, y, n, locked;
+ Rectangle s;
+
+ d = c->display;
+ y = Dy(r);
+ x = Dx(r);
+ if(x <= 0 || y <= 0) {
+ r = Rect(0, 0, 1, 1);
+ x = y = 1;
+ }
+ /* TO DO: diagonal */
+ s = r;
+ if(dir == Tkhorizontal){
+ n = x;
+ r.max.y = r.min.y+1;
+ }else{
+ n = y;
+ r.max.x = r.min.x+1;
+ }
+ b = mallocz(3*n, 0);
+ if(b == nil)
+ return nil;
+ locked = lockdisplay(d);
+ i = allocimage(d, r, RGB24, 1, DNofill);
+ if(i == nil)
+ goto Ret;
+ tkrgbavals(pix0, &c0[2], &c0[1], &c0[0], &a);
+ tkrgbavals(pix1, &c1[2], &c1[1], &c1[0], &a);
+ for(j = 0; j < 3; j++){
+ c0[j] <<= 12;
+ c1[j] <<= 12;
+ delta[j] = ((c1[j]-c0[j])+(1<<11))/n;
+ }
+ e = b+3*n;
+ for(p = b; p < e; p += 3) {
+ p[0] = c0[0]>>12;
+ p[1] = c0[1]>>12;
+ p[2] = c0[2]>>12;
+ c0[0] += delta[0];
+ c0[1] += delta[1];
+ c0[2] += delta[2];
+ }
+ loadimage(i, r, b, 3*n);
+ replclipr(i, 1, s);
+Ret:
+ if(locked)
+ unlockdisplay(d);
+ free(b);
+ return i;
+}
+
+/*
+ * XXX should be in libdraw?
+ */
+int
+tkchanhastype(ulong c, int t)
+{
+ for(; c; c>>=8)
+ if(TYPE(c) == t)
+ return 1;
+ return 0;
+}
+
+void
+tksettransparent(Tk *tk, int transparent)
+{
+ if (transparent)
+ tk->flag |= Tktransparent;
+ else
+ tk->flag &= ~Tktransparent;
+}
+
+int
+tkhasalpha(TkEnv *e, int col)
+{
+ return (e->colors[col] & 0xff) != 0xff;
+}
+
+Image*
+tkgc(TkEnv *e, int col)
+{
+ return tkcolor(e->top->ctxt, e->colors[col]);
+}
+
+
+/*
+ * Todo: improve the fixed-point code
+ * the 255 scale factor is used because RGB ranges 0-255
+ */
+static void
+rgb2hsv(int r, int g, int b, int *h, int *s, int *v)
+{
+ int min, max, delta;
+
+ max = r;
+ if(g > max)
+ max = g;
+ if(b > max)
+ max = b;
+ min = r;
+ if(g < min)
+ min = g;
+ if(b < min)
+ min = b;
+ *v = max;
+ if (max != 0)
+ *s = ((max - min)*255) / max;
+ else
+ *s = 0;
+
+ if (*s == 0) {
+ *h = 0; /* undefined */
+ } else {
+ delta = max - min;
+ if (r == max)
+ *h = (g - b)*255 / delta;
+ else if (g == max)
+ *h = (2*255) + ((b - r)*255) / delta;
+ else if (b == max)
+ *h = (4*255) + ((r - g)*255)/ delta;
+ *h *= 60;
+ if (*h < 0)
+ *h += 360*255;
+ *h /= 255;
+ }
+}
+
+static void
+hsv2rgb(int h, int s, int v, int *r, int *g, int *b)
+{
+ int i;
+ int f,p,q,t;
+
+ if (s == 0 && h == 0) {
+ *r = *g = *b = v; /* achromatic case */
+ } else {
+ if (h >= 360)
+ h = 0;
+ i = h / 60;
+ h *= 255;
+ h /= 60;
+
+ f = h % 255;
+ p = v * (255 - s);
+ q = v * (255 - ((s * f)/255));
+ t = v * (255- ((s * (255 - f))/255));
+ p /= 255;
+ q /= 255;
+ t /= 255;
+ switch (i) {
+ case 0: *r = v; *g = t; *b = p; break;
+ case 1: *r = q; *g = v; *b = p; break;
+ case 2: *r = p; *g = v; *b = t; break;
+ case 3: *r = p; *g = q; *b = v; break;
+ case 4: *r = t; *g = p; *b = v; break;
+ case 5: *r = v; *g = p; *b = q; break;
+ }
+ }
+}
+
+enum {
+ MINDELTA = 0x10,
+ DELTA = 0x30,
+};
+
+ulong
+tkrgbashade(ulong rgba, int shade)
+{
+ int R, G, B, A, h, s, v, vl, vd;
+
+ if (shade == TkSameshade)
+ return rgba;
+
+ tkrgbavals(rgba, &R, &G, &B, &A);
+ h = s = v = 0;
+ rgb2hsv(R, G, B, &h, &s, &v);
+
+ if (v < MINDELTA) {
+ vd = v+DELTA;
+ vl = vd+DELTA;
+ } else if (v > 255-MINDELTA) {
+ vl = v-DELTA;
+ vd = vl-DELTA;
+ } else {
+ vl = v+DELTA;
+ vd = v-DELTA;
+ }
+
+ v = (shade == TkLightshade)?vl:vd;
+ if (v < 0)
+ v = 0;
+ if (v > 255)
+ v = 255;
+ hsv2rgb(h, s, v, &R, &G, &B);
+
+ return tkrgba(R, G, B, A);
+}
+
+Image*
+tkgshade(TkEnv *e, int col, int shade)
+{
+ ulong rgba;
+
+ if (col == TkCbackgnd || col == TkCselectbgnd || col == TkCactivebgnd)
+ return tkgc(e, col+shade);
+ rgba = tkrgbashade(e->colors[col], shade);
+ return tkcolor(e->top->ctxt, rgba);
+}
+
+TkEnv*
+tknewenv(TkTop *t)
+{
+ TkEnv *e;
+
+ e = malloc(sizeof(TkEnv));
+ if(e == nil)
+ return nil;
+
+ e->ref = 1;
+ e->top = t;
+ return e;
+}
+
+TkEnv*
+tkdefaultenv(TkTop *t)
+{
+ int locked;
+ TkEnv *env;
+ Display *d;
+
+ if(t->env != nil) {
+ t->env->ref++;
+ return t->env;
+ }
+ t->env = malloc(sizeof(TkEnv));
+ if(t->env == nil)
+ return nil;
+
+ env = t->env;
+ env->ref = 1;
+ env->top = t;
+
+ if(tkfont == nil)
+ tkfont = "/fonts/pelm/unicode.8.font";
+
+ d = t->display;
+ env->font = font_open(d, tkfont);
+ if(env->font == nil) {
+ static int warn;
+ if(warn == 0) {
+ warn = 1;
+ print("tk: font not found: %s\n", tkfont);
+ }
+ env->font = font_open(d, "*default*");
+ if(env->font == nil) {
+ free(t->env);
+ t->env = nil;
+ return nil;
+ }
+ }
+
+ locked = lockdisplay(d);
+ env->wzero = stringwidth(env->font, "0");
+ if ( env->wzero <= 0 )
+ env->wzero = env->font->height / 2;
+ if(locked)
+ unlockdisplay(d);
+
+ tksetenvcolours(env);
+ return env;
+}
+
+void
+tkputenv(TkEnv *env)
+{
+ Display *d;
+ int locked;
+
+ if(env == nil)
+ return;
+
+ env->ref--;
+ if(env->ref != 0)
+ return;
+
+ d = env->top->display;
+ locked = lockdisplay(d);
+
+ if(env->font != nil)
+ font_close(env->font);
+
+ if(locked)
+ unlockdisplay(d);
+
+ free(env);
+}
+
+TkEnv*
+tkdupenv(TkEnv **env)
+{
+ Display *d;
+ TkEnv *e, *ne;
+
+ e = *env;
+ if(e->ref == 1)
+ return e;
+
+ ne = malloc(sizeof(TkEnv));
+ if(ne == nil)
+ return nil;
+
+ ne->ref = 1;
+ ne->top = e->top;
+
+ d = e->top->display;
+ memmove(ne->colors, e->colors, sizeof(e->colors));
+ ne->set = e->set;
+ ne->font = font_open(d, e->font->name);
+ ne->wzero = e->wzero;
+
+ e->ref--;
+ *env = ne;
+ return ne;
+}
+
+Tk*
+tknewobj(TkTop *t, int type, int n)
+{
+ Tk *tk;
+
+ tk = malloc(n);
+ if(tk == 0)
+ return 0;
+
+ tk->type = type; /* Defaults */
+ tk->flag = Tktop;
+ tk->relief = TKflat;
+ tk->env = tkdefaultenv(t);
+ if(tk->env == nil) {
+ free(tk);
+ return nil;
+ }
+
+ return tk;
+}
+
+void
+tkfreebind(TkAction *a)
+{
+ TkAction *next;
+
+ while(a != nil) {
+ next = a->link;
+ if((a->type & 0xff) == TkDynamic)
+ free(a->arg);
+ free(a);
+ a = next;
+ }
+}
+
+void
+tkfreename(TkName *f)
+{
+ TkName *n;
+
+ while(f != nil) {
+ n = f->link;
+ free(f);
+ f = n;
+ }
+}
+
+void
+tkfreeobj(Tk *tk)
+{
+ TkCtxt *c;
+
+ c = tk->env->top->ctxt;
+ if(c != nil) {
+ if(c->tkkeygrab == tk)
+ c->tkkeygrab = nil;
+ if(c->mgrab == tk)
+ tksetmgrab(tk->env->top, nil);
+ if(c->mfocus == tk)
+ c->mfocus = nil;
+ if(c->entered == tk)
+ c->entered = nil;
+ }
+
+ if (tk == rptw) {
+ /* cancel the autorepeat without notifying the widget */
+ rptid++;
+ rptw = nil;
+ }
+ if (tk == blinkw)
+ blinkw = nil;
+ tkextnfreeobj(tk);
+ tkmethod[tk->type]->free(tk);
+ tkputenv(tk->env);
+ tkfreebind(tk->binds);
+ if(tk->name != nil)
+ free(tk->name);
+ free(tk);
+}
+
+char*
+tkaddchild(TkTop *t, Tk *tk, TkName **names)
+{
+ TkName *n;
+ Tk *f, **l;
+ int found, len;
+ char *s, *ep;
+
+ n = *names;
+ if(n == nil || n->name[0] != '.'){
+ if(n != nil)
+ tkerr(t, n->name);
+ return TkBadwp;
+ }
+
+ if (n->name[1] == '\0')
+ return TkDupli;
+
+ /*
+ * check that the name is well-formed.
+ * ep will point to end of parent component of the name.
+ */
+ ep = nil;
+ for (s = n->name + 1; *s; s++) {
+ if (*s == '.'){
+ tkerr(t, n->name);
+ return TkBadwp;
+ }
+ for (; *s && *s != '.'; s++)
+ ;
+ if (*s == '\0')
+ break;
+ ep = s;
+ }
+ if (ep == s - 1){
+ tkerr(t, n->name);
+ return TkBadwp;
+ }
+ if (ep == nil)
+ ep = n->name + 1;
+ len = ep - n->name;
+
+ found = 0;
+ l = &t->root;
+ for(f = *l; f; f = f->siblings) {
+ if (f->name != nil) {
+ if (strcmp(n->name, f->name->name) == 0)
+ return TkDupli;
+ if (!found &&
+ strncmp(n->name, f->name->name, len) == 0 &&
+ f->name->name[len] == '\0')
+ found = 1;
+ }
+ l = &f->siblings;
+ }
+ if (0) { /* don't enable this until a reasonably major release... if ever */
+ /*
+ * parent widget must already exist
+ */
+ if (!found){
+ tkerr(t, n->name);
+ return TkBadwp;
+ }
+ }
+ *l = tk;
+ tk->name = n;
+ *names = n->link;
+
+ return nil;
+}
+
+Tk*
+tklook(TkTop *t, char *wp, int parent)
+{
+ Tk *f;
+ char *p, *q;
+
+ if(wp == nil)
+ return nil;
+
+ if(parent) {
+ p = strdup(wp);
+ if(p == nil)
+ return nil;
+ q = strrchr(p, '.');
+ if(q == nil)
+ abort();
+ if(q == p) {
+ free(p);
+ return t->root;
+ }
+ *q = '\0';
+ } else
+ p = wp;
+
+ for(f = t->root; f; f = f->siblings)
+ if ((f->name != nil) && (strcmp(f->name->name, p) == 0))
+ break;
+
+ if(f != nil && (f->flag & Tkdestroy))
+ f = nil;
+
+ if (parent)
+ free(p);
+ return f;
+}
+
+void
+tktextsdraw(Image *img, Rectangle r, TkEnv *e, int sbw)
+{
+ Image *l, *d;
+ Rectangle s;
+
+ draw(img, r, tkgc(e, TkCselectbgnd), nil, ZP);
+ s.min = r.min;
+ s.min.x -= sbw;
+ s.min.y -= sbw;
+ s.max.x = r.max.x;
+ s.max.y = r.min.y;
+ l = tkgc(e, TkCselectbgndlght);
+ draw(img, s, l, nil, ZP);
+ s.max.x = s.min.x + sbw;
+ s.max.y = r.max.y + sbw;
+ draw(img, s, l, nil, ZP);
+ s.max = r.max;
+ s.max.x += sbw;
+ s.max.y += sbw;
+ s.min.x = r.min.x;
+ s.min.y = r.max.y;
+ d = tkgc(e, TkCselectbgnddark);
+ draw(img, s, d, nil, ZP);
+ s.min.x = r.max.x;
+ s.min.y = r.min.y - sbw;
+ draw(img, s, d, nil, ZP);
+}
+
+void
+tkbox(Image *i, Rectangle r, int bd, Image *fill)
+{
+ if (bd > 0) {
+ draw(i, Rect(r.min.x, r.min.y, r.max.x, r.min.y+bd), fill, nil, ZP);
+ draw(i, Rect(r.min.x, r.min.y+bd, r.min.x+bd, r.max.y-bd), fill, nil, ZP);
+ draw(i, Rect(r.min.x, r.max.y-bd, r.max.x, r.max.y), fill, nil, ZP);
+ draw(i, Rect(r.max.x-bd, r.min.y+bd, r.max.x, r.max.y), fill, nil, ZP);
+ }
+}
+
+void
+tkbevel(Image *i, Point o, int w, int h, int bw, Image *top, Image *bottom)
+{
+ Rectangle r;
+ int x, border;
+
+ border = 2 * bw;
+
+ r.min = o;
+ r.max.x = r.min.x + w + border;
+ r.max.y = r.min.y + bw;
+ draw(i, r, top, nil, ZP);
+
+ r.max.x = r.min.x + bw;
+ r.max.y = r.min.y + h + border;
+ draw(i, r, top, nil, ZP);
+
+ r.max.x = o.x + w + border;
+ r.max.y = o.y + h + border;
+ r.min.x = o.x + bw;
+ r.min.y = r.max.y - bw;
+ for(x = 0; x < bw; x++) {
+ draw(i, r, bottom, nil, ZP);
+ r.min.x--;
+ r.min.y++;
+ }
+ r.min.x = o.x + bw + w;
+ r.min.y = o.y + bw;
+ for(x = bw; x >= 0; x--) {
+ draw(i, r, bottom, nil, ZP);
+ r.min.x++;
+ r.min.y--;
+ }
+}
+
+/*
+ * draw a relief border.
+ * color is an index into tk->env->colors and assumes
+ * light and dark versions following immediately after
+ * that index
+ */
+void
+tkdrawrelief(Image *i, Tk *tk, Point o, int color, int rlf)
+{
+ TkEnv *e;
+ Image *l, *d, *t;
+ int h, w, bd, bd1, bd2;
+
+ if(tk->borderwidth == 0)
+ return;
+
+ h = tk->act.height;
+ w = tk->act.width;
+
+ e = tk->env;
+ if (color == TkCbackgnd || color == TkCselectbgnd || color == TkCactivebgnd) {
+ l = tkgc(e, color+TkLightshade);
+ d = tkgc(e, color+TkDarkshade);
+ } else {
+ l = tkgshade(e, color, TkLightshade);
+ d = tkgshade(e, color, TkDarkshade);
+ }
+ bd = tk->borderwidth;
+ if(rlf < 0)
+ rlf = TKraised;
+ switch(rlf) {
+ case TKflat:
+ break;
+ case TKsunken:
+ tkbevel(i, o, w, h, bd, d, l);
+ break;
+ case TKraised:
+ tkbevel(i, o, w, h, bd, l, d);
+ break;
+ case TKgroove:
+ t = d;
+ d = l;
+ l = t;
+ /* fall through */
+ case TKridge:
+ bd1 = bd/2;
+ bd2 = bd - bd1;
+ if(bd1 > 0)
+ tkbevel(i, o, w + 2*bd2, h + 2*bd2, bd1, l, d);
+ o.x += bd1;
+ o.y += bd1;
+ tkbevel(i, o, w, h, bd2, d, l);
+ break;
+ }
+}
+
+Point
+tkstringsize(Tk *tk, char *text)
+{
+ char *q;
+ int locked;
+ Display *d;
+ Point p, t;
+
+ if(text == nil) {
+ p.x = 0;
+ p.y = tk->env->font->height;
+ return p;
+ }
+
+ d = tk->env->top->display;
+ locked = lockdisplay(d);
+
+ p = ZP;
+ while(*text) {
+ q = strchr(text, '\n');
+ if(q != nil)
+ *q = '\0';
+ t = stringsize(tk->env->font, text);
+ p.y += t.y;
+ if(p.x < t.x)
+ p.x = t.x;
+ if(q == nil)
+ break;
+ text = q+1;
+ *q = '\n';
+ }
+ if(locked)
+ unlockdisplay(d);
+
+ return p;
+}
+
+static void
+tkulall(Image *i, Point o, Image *col, Font *f, char *text)
+{
+ Rectangle r;
+
+ r.max = stringsize(f, text);
+ r.max = addpt(r.max, o);
+ r.min.x = o.x;
+ r.min.y = r.max.y - 1;
+ draw(i, r, col, nil, ZP);
+}
+
+static void
+tkul(Image *i, Point o, Image *col, int ul, Font *f, char *text)
+{
+ char c, *v;
+ Rectangle r;
+
+ v = text+ul+1;
+ c = *v;
+ *v = '\0';
+ r.max = stringsize(f, text);
+ r.max = addpt(r.max, o);
+ r.min = stringsize(f, v-1);
+ *v = c;
+ r.min.x = r.max.x - r.min.x;
+ r.min.y = r.max.y - 1;
+ r.max.y++;
+ draw(i, r, col, nil, ZP);
+}
+
+void
+tkdrawstring(Tk *tk, Image *i, Point o, char *text, int ul, Image *col, int j)
+{
+ int n, l, maxl, sox;
+ char *q, *txt;
+ Point p;
+ TkEnv *e;
+
+ e = tk->env;
+ sox = maxl = 0;
+ if(j != Tkleft){
+ maxl = 0;
+ txt = text;
+ while(*txt){
+ q = strchr(txt, '\n');
+ if(q != nil)
+ *q = '\0';
+ l = stringwidth(e->font, txt);
+ if(l > maxl)
+ maxl = l;
+ if(q == nil)
+ break;
+ txt = q+1;
+ *q = '\n';
+ }
+ sox = o.x;
+ }
+ while(*text) {
+ q = strchr(text, '\n');
+ if(q != nil)
+ *q = '\0';
+ if(j != Tkleft){
+ o.x = sox;
+ l = stringwidth(e->font, text);
+ if(j == Tkcenter)
+ o.x += (maxl-l)/2;
+ else
+ o.x += maxl-l;
+ }
+ p = string(i, o, col, o, e->font, text);
+ if(ul >= 0) {
+ n = strlen(text);
+ if(ul < n) {
+ tkul(i, o, col, ul, e->font, text);
+ ul = -1;
+ } else if(ul == n) {
+ tkulall(i, o, col, e->font, text);
+ ul = -1;
+ } else
+ ul -= n;
+ }
+ o.y += e->font->height;
+ if(q == nil)
+ break;
+ text = q+1;
+ *q = '\n';
+ }
+}
+
+/* for debugging */
+char*
+tkname(Tk *tk)
+{
+ if(tk == nil)
+ return "(nil)";
+ if(tk->name == nil)
+ return "(noname)";
+ return tk->name->name;
+}
+
+Tk*
+tkdeliver(Tk *tk, int event, void *data)
+{
+ Tk *dest;
+
+ if(tk != nil && ((ulong)tk->type >= TKwidgets || (ulong)tk->name < 4096 && tk->name != nil)){
+ print("invalid Tk: type %d name %p\n", tk->type, tk->name);
+ abort();
+ }
+//print("tkdeliver %v to %s\n", event, tkname(tk));
+ if(tk == nil || ((tk->flag&Tkdestroy) && event != TkDestroy))
+ return tk;
+ if(event&(TkFocusin|TkFocusout) && (tk->flag&Tktakefocus))
+ tk->dirty = tkrect(tk, 1);
+
+ if (tkmethod[tk->type]->deliver != nil) {
+ dest = tkmethod[tk->type]->deliver(tk, event, data);
+ if (dest == nil)
+ return tk;
+ tkdirty(tk);
+ return dest;
+ }
+
+ if((tk->flag & Tkdisabled) == 0)
+ tksubdeliver(tk, tk->binds, event, data, 0);
+ tkdirty(tk);
+ return tk;
+}
+
+static int
+nullop(char *fmt, ...)
+{
+ USED(fmt);
+ return 0;
+}
+
+int
+tksubdeliver(Tk *tk, TkAction *binds, int event, void *data, int extn)
+{
+
+ TkAction *a;
+ int delivered, genkey, delivered2, iskey;
+//int (*debug)(char *fmt, ...);
+
+ if (!extn)
+ return tkextndeliver(tk, binds, event, data);
+
+//debug = (tk->name && !strcmp(tk->name->name, ".cd")) ? print : nullop;
+//debug("subdeliver %v\n", event);
+
+ if (event & TkTakefocus) {
+ if (tk->flag & Tktakefocus)
+ tksetkeyfocus(tk->env->top, tk, 0);
+ return TkDdelivered;
+ }
+
+ delivered = TkDnone;
+ genkey = 0;
+ for(a = binds; a != nil; a = a->link) {
+ if(event == a->event) {
+//debug(" exact match on %v\n", a->event);
+ tkcmdbind(tk, event, a->arg, data);
+ delivered = TkDdelivered;
+ } else if (a->event == TkKey && (a->type>>8)==TkAadd)
+ genkey = 1;
+ }
+ if(delivered != TkDnone && !((event & TkKey) && genkey))
+ return delivered;
+
+ delivered2 = delivered;
+ for(a = binds; a != nil; a = a->link) {
+ /*
+ * only bind to non-specific key events; if a specific
+ * key event has already been delivered, only deliver event if
+ * the non-specific binding was added. (TkAadd)
+ */
+ if (a->event & TkExtns)
+ continue;
+ iskey = (a->event & TkKey);
+ if (iskey ^ (event & TkKey))
+ continue;
+ if(iskey && (TKKEY(a->event) != 0
+ || ((a->type>>8) != TkAadd && delivered != TkDnone)))
+ continue;
+ if(!iskey && (a->event & TkMotion) && (a->event&TkEpress) != 0)
+ continue;
+ if(!(event & TkDouble) && (a->event & TkDouble))
+ continue;
+ if((event & ~TkDouble) & a->event) {
+//debug(" partial match on %v\n", a->event);
+ tkcmdbind(tk, event, a->arg, data);
+ delivered2 = TkDdelivered;
+ }
+ }
+ return delivered2;
+}
+
+void
+tkcancel(TkAction **l, int event)
+{
+ TkAction *a;
+
+ for(a = *l; a; a = *l) {
+ if(a->event == event) {
+ *l = a->link;
+ a->link = nil;
+ tkfreebind(a);
+ continue;
+ }
+ l = &a->link;
+ }
+}
+
+static void
+tkcancela(TkAction **l, int event, int type, char *arg)
+{
+ TkAction *a;
+
+ for(a = *l; a; a = *l) {
+ if(a->event == event && strcmp(a->arg, arg) == 0 && (a->type&0xff) == type){
+ *l = a->link;
+ a->link = nil;
+ tkfreebind(a);
+ continue;
+ }
+ l = &a->link;
+ }
+}
+
+char*
+tkaction(TkAction **l, int event, int type, char *arg, int how)
+{
+ TkAction *a;
+
+ if(arg == nil)
+ return nil;
+ if(how == TkArepl)
+ tkcancel(l, event);
+ else if(how == TkAadd){
+ for(a = *l; a; a = a->link)
+ if(a->event == event && strcmp(a->arg, arg) == 0 && (a->type&0xff) == type){
+ a->type = type + (how << 8);
+ return nil;
+ }
+ }
+ else if(how == TkAsub){
+ tkcancela(l, event, type, arg);
+ if(type == TkDynamic) /* should always be the case */
+ free(arg);
+ return nil;
+ }
+
+ a = malloc(sizeof(TkAction));
+ if(a == nil) {
+ if(type == TkDynamic)
+ free(arg);
+ return TkNomem;
+ }
+
+ a->event = event;
+ a->arg = arg;
+ a->type = type + (how << 8);
+
+ a->link = *l;
+ *l = a;
+
+ return nil;
+}
+
+char*
+tkitem(char *buf, char *a)
+{
+ char *e;
+
+ while(*a && (*a == ' ' || *a == '\t'))
+ a++;
+
+ e = buf + Tkmaxitem - 1;
+ while(*a && *a != ' ' && *a != '\t' && buf < e)
+ *buf++ = *a++;
+
+ *buf = '\0';
+ while(*a && (*a == ' ' || *a == '\t'))
+ a++;
+ return a;
+}
+
+/*
+ * if tk is a subwindow or a descendent, return the subwindow;
+ * return nil otherwise
+ */
+Tk*
+tkfindsub(Tk *tk)
+{
+ for(; tk != nil; tk = tk->master){
+ if(tk->parent != nil)
+ return tk; /* tk->parent is canvas or text */
+ }
+ return nil;
+}
+
+/*
+ * Return absolute screen position of tk (just outside its top-left border).
+ * When a widget is embedded in a text or canvas widget, we need to
+ * use the text or canvas's relpos() function instead of act{x,y}, and we
+ * need to folow up the parent pointer rather than the master one.
+ */
+Point
+tkposn(Tk *tk)
+{
+ Tk *f, *last;
+ Point g;
+
+ last = tk;
+ if(tk->parent != nil) {
+ g = tkmethod[tk->parent->type]->relpos(tk);
+ f = tk->parent;
+ } else {
+ g.x = tk->act.x;
+ g.y = tk->act.y;
+ f = tk->master;
+ }
+ while(f != nil) {
+ g.x += f->borderwidth;
+ g.y += f->borderwidth;
+ last = f;
+ if(f->parent != nil) {
+ g = addpt(g, tkmethod[f->parent->type]->relpos(f));
+ f = f->parent;
+ } else {
+ g.x += f->act.x;
+ g.y += f->act.y;
+ f = f->master;
+ }
+ }
+ if (last->flag & Tkwindow)
+ g = addpt(g, TKobj(TkWin, last)->req);
+ return g;
+}
+
+/*
+ * convert screen coords to local widget coords
+ */
+Point
+tkscrn2local(Tk *tk, Point p)
+{
+ p = subpt(p, tkposn(tk));
+ p.x -= tk->borderwidth;
+ p.y -= tk->borderwidth;
+ return p;
+}
+
+int
+tkvisiblerect(Tk *tk, Rectangle *rr)
+{
+ Rectangle r;
+ Point g;
+ Tk *f, *last;
+ g = Pt(tk->borderwidth, tk->borderwidth);
+ last = tk;
+ if(tk->parent != nil) {
+ g = addpt(g, tkmethod[tk->parent->type]->relpos(tk));
+ f = tk->parent;
+ } else {
+ g.x += tk->act.x;
+ g.y += tk->act.y;
+ f = tk->master;
+ }
+ if (f == nil) {
+ *rr = tkrect(tk, 1);
+ return 1;
+ }
+ r = rectaddpt(tkrect(tk, 1), g);
+ while (f) {
+ if (!rectclip(&r, tkrect(f, 0)))
+ return 0;
+ g.x = f->borderwidth;
+ g.y = f->borderwidth;
+ last = f;
+ if (f->parent != nil) {
+ g = addpt(g, tkmethod[f->parent->type]->relpos(f));
+ f = f->parent;
+ } else {
+ g.x += f->act.x;
+ g.y += f->act.y;
+ f = f->master;
+ }
+ r = rectaddpt(r, g);
+ }
+ if (last->flag & Tkwindow)
+ r = rectaddpt(r, TKobj(TkWin, last)->act);
+ /*
+ * now we have the visible rectangle in screen coords;
+ * subtract actx+borderwidth and we've got it back in
+ * widget-local coords again
+ */
+ r = rectsubpt(r, tkposn(tk));
+ *rr = rectsubpt(r, Pt(tk->borderwidth, tk->borderwidth));
+ return 1;
+}
+
+Point
+tkanchorpoint(Rectangle r, Point size, int anchor)
+{
+ int dx, dy;
+ Point p;
+
+ p = r.min;
+ dx = Dx(r) - size.x;
+ dy = Dy(r) - size.y;
+ if((anchor & (Tknorth|Tksouth)) == 0)
+ p.y += dy/2;
+ else if(anchor & Tksouth)
+ p.y += dy;
+
+ if((anchor & (Tkeast|Tkwest)) == 0)
+ p.x += dx/2;
+ else if(anchor & Tkeast)
+ p.x += dx;
+ return p;
+}
+
+static char*
+tkunits(char c, int *d, TkEnv *e)
+{
+ switch(c) {
+ default:
+ if(c >= '0' || c <= '9' || c == '.')
+ break;
+ return TkBadvl;
+ case '\0':
+ break;
+ case 'c': /* Centimeters */
+ *d *= (Tkdpi*100)/254;
+ break;
+ case 'm': /* Millimeters */
+ *d *= (Tkdpi*10)/254;
+ break;
+ case 'i': /* Inches */
+ *d *= Tkdpi;
+ break;
+ case 'p': /* Points */
+ *d = (*d*Tkdpi)/72;
+ break;
+ case 'w': /* Character width */
+ if(e == nil)
+ return TkBadvl;
+ *d = *d * e->wzero;
+ break;
+ case 'h': /* Character height */
+ if(e == nil)
+ return TkBadvl;
+ *d = *d * e->font->height;
+ break;
+ }
+ return nil;
+}
+
+int
+TKF2I(int f)
+{
+ if (f >= 0)
+ return (f + Tkfpscalar/2) / Tkfpscalar;
+ return (f - Tkfpscalar/2) / Tkfpscalar;
+}
+
+/*
+ * Parse a floating point number into a decimal fixed point representation
+ */
+char*
+tkfrac(char **arg, int *f, TkEnv *env)
+{
+ int c, minus, i, fscale, seendigit;
+ char *p, *e;
+
+ seendigit = 0;
+
+ p = *arg;
+ p = tkskip(p, " \t");
+
+ minus = 0;
+ if(*p == '-') {
+ minus = 1;
+ p++;
+ }
+ i = 0;
+ while(*p) {
+ c = *p;
+ if(c == '.')
+ break;
+ if(c < '0' || c > '9')
+ break;
+ i = i*10 + (c - '0');
+ seendigit = 1;
+ p++;
+ }
+ i *= Tkfpscalar;
+ if(*p == '.')
+ p++;
+ fscale = Tkfpscalar;
+ while(*p && *p >= '0' && *p <= '9') {
+ fscale /= 10;
+ i += fscale * (*p++ - '0');
+ seendigit = 1;
+ }
+
+ if(minus)
+ i = -i;
+
+ if(!seendigit)
+ return TkBadvl;
+ e = tkunits(*p, &i, env);
+ if (e != nil)
+ return e;
+ while (*p && *p != ' ' && *p != '\t')
+ p++;
+ *arg = p;
+ *f = i;
+ return nil;
+}
+
+char*
+tkfracword(TkTop *t, char **arg, int *f, TkEnv *env)
+{
+ char *p;
+ char buf[Tkminitem];
+
+ *arg = tkword(t, *arg, buf, buf+sizeof(buf), nil);
+ p = buf;
+ return tkfrac(&p, f, env);
+}
+
+char*
+tkfprint(char *v, int frac)
+{
+ int fscale;
+
+ if(frac < 0) {
+ *v++ = '-';
+ frac = -frac;
+ }
+ v += sprint(v, "%d", frac/Tkfpscalar);
+ frac = frac%Tkfpscalar;
+ if(frac != 0)
+ *v++ = '.';
+ fscale = Tkfpscalar/10;
+ while(frac) {
+ *v++ = '0' + frac/fscale;
+ frac %= fscale;
+ fscale /= 10;
+ }
+ *v = '\0';
+ return v;
+}
+
+char*
+tkvalue(char **val, char *fmt, ...)
+{
+ va_list arg;
+ Fmt fmtx;
+
+ if(val == nil)
+ return nil;
+
+ fmtstrinit(&fmtx);
+ if(*val != nil)
+ if(fmtprint(&fmtx, "%s", *val) < 0)
+ return TkNomem;
+ va_start(arg, fmt);
+ fmtvprint(&fmtx, fmt, arg);
+ va_end(arg);
+ free(*val);
+ *val = fmtstrflush(&fmtx);
+ if(*val == nil)
+ return TkNomem;
+ return nil;
+}
+
+static char*
+tkwidgetcmd(TkTop *t, Tk *tk, char *arg, char **val)
+{
+ TkMethod *cm;
+ TkCmdtab *ct;
+ int bot, top, new, r;
+ char *e, *buf;
+
+ buf = mallocz(Tkmaxitem, 0);
+ if(buf == nil)
+ return TkNomem;
+
+ arg = tkword(t, arg, buf, buf+Tkmaxitem, nil);
+ if(val != nil)
+ *val = nil;
+
+ cm = tkmethod[tk->type];
+
+ e = TkBadcm;
+ bot = 0;
+ top = cm->ncmd - 1;
+
+ while(bot <= top) {
+ new = (bot + top)/2;
+ ct = &cm->cmd[new];
+ r = strcmp(ct->name, buf);
+ if(r == 0) {
+ e = ct->fn(tk, arg, val);
+ break;
+ }
+ if(r < 0)
+ bot = new + 1;
+ else
+ top = new - 1;
+ }
+ free(buf);
+ tkdirty(tk);
+ return e;
+}
+
+Rectangle
+tkrect(Tk *tk, int withborder)
+{
+ Rectangle r;
+ int bd;
+
+ bd = withborder? tk->borderwidth: 0;
+ r.min.x = -bd;
+ r.min.y = -bd;
+ r.max.x = tk->act.width + bd;
+ r.max.y = tk->act.height + bd;
+ return r;
+}
+
+void
+tkdirty(Tk *tk)
+{
+ Tk *sub;
+ Point rel;
+ Rectangle dirty;
+ int isdirty, transparent;
+
+ /*
+ * mark as dirty all views underneath a dirty transparent widget
+ * down to the first opaque widget.
+ * inform parents about any dirtiness.
+
+ * XXX as Tksubsub never gets reset, testing against Tksubsub doesn't *exactly* test
+ * whether we're in a canvas/text widget, but merely
+ * whether it has ever been. Tksubsub should probably be reset on unpack.
+ */
+ isdirty = Dx(tk->dirty) > 0;
+ transparent = tk->flag & Tktransparent;
+ sub = tk;
+ while (isdirty && ((tk->flag&Tksubsub) || transparent)) {
+ if (tk->master != nil) {
+ if (transparent) {
+ rel.x = tk->act.x + tk->borderwidth;
+ rel.y = tk->act.y + tk->borderwidth;
+ dirty = rectaddpt(sub->dirty, rel);
+ sub = tk->master;
+ combinerect(&sub->dirty, dirty);
+ transparent = sub->flag & Tktransparent;
+ }
+ tk = tk->master;
+ } else if (tk->parent != nil) {
+ tkmethod[tk->parent->type]->dirtychild(sub);
+ tk = sub = tk->parent;
+ isdirty = Dx(sub->dirty) > 0;
+ transparent = sub->flag & Tktransparent;
+ } else
+ break;
+ }
+}
+
+static int
+qcmdcmp(const void *a, const void *b)
+{
+ return strcmp(((TkCmdtab*)a)->name, ((TkCmdtab*)b)->name);
+}
+
+void
+tksorttable(void)
+{
+ int i;
+ TkMethod *c;
+ TkCmdtab *cmd;
+
+ for(i = 0; i < TKwidgets; i++) {
+ c = tkmethod[i];
+ if(c->cmd == nil)
+ continue;
+
+ for(cmd = c->cmd; cmd->name != nil; cmd++)
+ ;
+ c->ncmd = cmd - c->cmd;
+
+ qsort(c->cmd, c->ncmd, sizeof(TkCmdtab), qcmdcmp);
+ }
+}
+
+static char*
+tksinglecmd(TkTop *t, char *arg, char **val)
+{
+ Tk *tk;
+ int bot, top, new;
+ char *e, *buf;
+
+ if(t->debug)
+ print("tk: '%s'\n", arg);
+
+ buf = mallocz(Tkmaxitem, 0);
+ if(buf == nil)
+ return TkNomem;
+
+ arg = tkword(t, arg, buf, buf+Tkmaxitem, nil);
+ switch(buf[0]) {
+ case '\0':
+ free(buf);
+ return nil;
+ case '.':
+ tk = tklook(t, buf, 0);
+ if(tk == nil){
+ tkerr(t, buf);
+ free(buf);
+ return TkBadwp;
+ }
+ e = tkwidgetcmd(t, tk, arg, val);
+ free(buf);
+ return e;
+ }
+
+ bot = 0;
+ top = nelem(cmdmain) - 1;
+ e = TkBadcm;
+ while(bot <= top) {
+ int rc;
+ new = (bot + top)/2;
+ rc = strcmp(cmdmain[new].name, buf);
+ if(!rc) {
+ e = cmdmain[new].fn(t, arg, val);
+ break;
+ }
+
+ if(rc < 0)
+ bot = new + 1;
+ else
+ top = new - 1;
+ }
+ free(buf);
+ return e;
+}
+
+static char*
+tkmatch(int inc, int dec, char *p)
+{
+ int depth, esc, c;
+
+ esc = 0;
+ depth = 1;
+ while(*p) {
+ c = *p;
+ if(esc == 0) {
+ if(c == inc)
+ depth++;
+ if(c == dec)
+ depth--;
+ if(depth == 0)
+ return p;
+ }
+ if(c == '\\' && esc == 0)
+ esc = 1;
+ else
+ esc = 0;
+ p++;
+ }
+ return nil;
+}
+
+char*
+tkexec(TkTop *t, char *arg, char **val)
+{
+ int cmdsz, n;
+ char *p, *cmd, *e, *c;
+
+ if(t->execdepth >= 0 && ++t->execdepth > 128)
+ return TkDepth;
+
+ cmd = nil;
+ cmdsz = 0;
+
+ p = arg;
+ for(;;) {
+ switch(*p++) {
+ case '[':
+ p = tkmatch('[', ']', p);
+ if(p == nil){
+ free(cmd);
+ return TkSyntx;
+ }
+ break;
+ case '{':
+ p = tkmatch('{', '}', p);
+ if(p == nil){
+ free(cmd);
+ return TkSyntx;
+ }
+ break;
+ case ';':
+ n = p - arg - 1;
+ if(cmdsz < n)
+ cmdsz = n;
+ c = realloc(cmd, cmdsz+1);
+ if(c == nil){
+ free(cmd);
+ return TkNomem;
+ }
+ cmd = c;
+ memmove(cmd, arg, n);
+ cmd[n] = '\0';
+ e = tksinglecmd(t, cmd, nil);
+ if(e != nil) {
+ t->err = e;
+ strncpy(t->errcmd, cmd, sizeof(t->errcmd));
+ t->errcmd[sizeof(t->errcmd)-1] = '\0';
+ free(cmd);
+ return e;
+ }
+ arg = p;
+ break;
+ case '\0':
+ case '\'':
+ free(cmd);
+ e = tksinglecmd(t, arg, val);
+ if(e != nil) {
+ t->err = e;
+ strncpy(t->errcmd, arg, sizeof(t->errcmd));
+ t->errcmd[sizeof(t->errcmd)-1] = '\0';
+ }
+ return e;
+ }
+ }
+}
+
+static struct {
+ char *name;
+ int mask;
+} events[] = {
+ "Button1P", TkButton1P,
+ "Button1R", TkButton1R,
+ "Button2P", TkButton2P,
+ "Button2R", TkButton2R,
+ "Button3P", TkButton3P,
+ "Button3R", TkButton3R,
+ "Button4P", TkButton4P,
+ "Button4R", TkButton4R,
+ "Button5P", TkButton5P,
+ "Button5R", TkButton5R,
+ "Button6P", TkButton6P,
+ "Button6R", TkButton6R,
+ "Extn1", TkExtn1,
+ "Extn2", TkExtn2,
+ "Takefocus", TkTakefocus,
+ "Destroy", TkDestroy,
+ "Enter", TkEnter,
+ "Leave", TkLeave,
+ "Motion", TkMotion,
+ "Map", TkMap,
+ "Unmap", TkUnmap,
+ "Key", TkKey,
+ "Focusin", TkFocusin,
+ "Focusout", TkFocusout,
+ "Configure", TkConfigure,
+ "Double", TkDouble,
+ 0
+};
+
+int
+tkeventfmt(Fmt *f)
+{
+ int k, i, d;
+ int e;
+
+ e = va_arg(f->args, int);
+
+ if ((f->flags & FmtSharp) && e == TkMotion)
+ return 0;
+ fmtprint(f, "<");
+ k = -1;
+ if (e & TkKey) {
+ k = e & 0xffff;
+ e &= ~0xffff;
+ }
+ d = 0;
+ for (i = 0; events[i].name; i++) {
+ if (e & events[i].mask) {
+ if (d++)
+ fmtprint(f, "|");
+ fmtprint(f, "%s", events[i].name);
+ }
+ }
+ if (k != -1) {
+ fmtprint(f, "[%c]", k);
+ } else if (e == 0)
+ fmtprint(f, "Noevent");
+ fmtprint(f, ">");
+ return 0;
+}
+
+void
+tkerr(TkTop *t, char *e)
+{
+ if(t != nil && e != nil){
+ strncpy(t->errx, e, sizeof(t->errx));
+ t->errx[sizeof(t->errx)-1] = '\0';
+ }
+}
+
+char*
+tkerrstr(TkTop *t, char *e)
+{
+ char *s = malloc(strlen(e)+1+strlen(t->errx)+1);
+
+ if(s == nil)
+ return nil;
+ strcpy(s, e);
+ if(*e == '!'){
+ strcat(s, " ");
+ strcat(s, t->errx);
+ }
+ t->errx[0] = '\0';
+ return s;
+}
+
+char*
+tksetmgrab(TkTop *t, Tk *tk)
+{
+ Tk *omgrab;
+ TkCtxt *c;
+ c = t->ctxt;
+ if (tk == nil) {
+ omgrab = c->mgrab;
+ c->mgrab = nil;
+ /*
+ * don't enterleave if grab reset would cause no leave event
+ */
+ if (!(omgrab != nil && (omgrab->flag & Tknograb) &&
+ c->entered != nil && (c->entered->flag & Tknograb)))
+ tkenterleave(t);
+ } else {
+ if (c->focused && c->mfocus != nil && c->mfocus->env->top != tk->env->top)
+ return "!grab already taken on another toplevel";
+ c->mgrab = tk;
+ if (tk->flag & Tknograb) {
+ if (c->focused) {
+ c->focused = 0;
+ c->mfocus = nil;
+ }
+ } else if (c->focused || c->mstate.b != 0) {
+ c->focused = 1;
+ c->mfocus = tk;
+ }
+//print("setmgrab(%s) focus now %s\n", tkname(tk), tkname(c->mfocus));
+ tkenterleave(t);
+ }
+ return nil;
+}
+
+int
+tkinsidepoly(Point *poly, int np, int winding, Point p)
+{
+ Point pi, pj;
+ int i, j, hit;
+
+ hit = 0;
+ j = np - 1;
+ for(i = 0; i < np; j = i++) {
+ pi = poly[i];
+ pj = poly[j];
+ if((pi.y <= p.y && p.y < pj.y || pj.y <= p.y && p.y < pi.y) &&
+ p.x < (pj.x - pi.x) * (p.y - pi.y) / (pj.y - pi.y) + pi.x) {
+ if(winding == 1 || pi.y > p.y)
+ hit++;
+ else
+ hit--;
+ }
+ }
+ return (hit & winding) != 0;
+}
+
+int
+tklinehit(Point *a, int np, int w, Point p)
+{
+ Point *b;
+ int z, nx, ny, nrm;
+
+ while(np-- > 1) {
+ b = a+1;
+ nx = a->y - b->y;
+ ny = b->x - a->x;
+ nrm = (nx < 0? -nx : nx) + (ny < 0? -ny : ny);
+ if(nrm)
+ z = (p.x-b->x)*nx/nrm + (p.y-b->y)*ny/nrm;
+ else
+ z = (p.x-b->x) + (p.y-b->y);
+ if(z < 0)
+ z = -z;
+ if(z < w)
+ return 1;
+ a++;
+ }
+ return 0;
+}
+
+int
+tkiswordchar(int c)
+{
+ return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9') || c == '_' || c >= 0xA0;
+}
+
+int
+tkhaskeyfocus(Tk *tk)
+{
+ if (tk == nil || tk->env->top->focused == 0)
+ return 0;
+ return tk == tk->env->top->ctxt->tkkeygrab;
+}
+
+static int
+rptactive(void *v)
+{
+ int id = (int)v;
+ if (id == rptid)
+ return 1;
+ return 0;
+}
+
+static int
+ckrpt(void *v, int interval)
+{
+ int id = (int)v;
+ if (id != rptid)
+ return -1;
+ if (interval < rptto)
+ return 0;
+ return 1;
+}
+
+static void
+dorpt(void *v)
+{
+ int id = (int)v;
+
+ if (id == rptid) {
+ rptto = rptint;
+ (*rptcb)(rptw, rptnote, 0);
+ if (rptint <= 0) {
+ rptid++;
+ rptw = nil;
+ }
+ }
+}
+
+void
+tkcancelrepeat(Tk *tk)
+{
+ if (tk == rptw) {
+ rptid++;
+ rptw = nil;
+ }
+}
+
+void
+tkrepeat(Tk *tk, void (*callback)(Tk*, void*, int), void *note, int pause, int interval)
+{
+ rptid++;
+ if (tk != rptw && rptw != nil)
+ /* existing callback being replaced- report to owner */
+ (*rptcb)(rptw, rptnote, 1);
+ rptw = tk;
+ if (tk == nil || callback == nil)
+ return;
+ rptnote = note;
+ rptcb = callback;
+ rptto = pause;
+ rptint = interval;
+ if (!autorpt)
+ autorpt = rptproc("autorepeat", TkRptclick, (void*)rptid, rptactive, ckrpt, dorpt);
+ else
+ rptwakeup((void*)rptid, autorpt);
+}
+
+static int
+blinkactive(void *v)
+{
+ USED(v);
+ return blinkw != nil;
+}
+
+static int
+ckblink(void *v, int interval)
+{
+ USED(v);
+ USED(interval);
+
+ if (blinkw == nil)
+ return -1;
+ if (blinkignore) {
+ blinkignore = 0;
+ return 0;
+ }
+ return 1;
+}
+
+static void
+doblink(void *v)
+{
+ USED(v);
+
+ if (blinkw == nil)
+ return;
+ blinkcb(blinkw, blinkon++ & 1);
+ tkupdate(blinkw->env->top);
+}
+
+void
+tkblinkreset(Tk *tk)
+{
+ if (blinkw == tk) {
+ blinkignore = 1;
+ blinkon = 0;
+ }
+}
+
+void
+tkblink(Tk *tk, void (*callback)(Tk*, int))
+{
+ if (tk == nil || callback == nil) {
+ blinkw = nil;
+ return;
+ }
+ blinkw = tk;
+ blinkcb = callback;
+ if (!blinkrpt)
+ blinkrpt = rptproc("blinker", TkBlinkinterval, nil, blinkactive, ckblink, doblink);
+ else
+ rptwakeup(nil, blinkrpt);
+}
+
+/*
+ * debugging
+ */
+void
+tkdump(Tk *tk)
+{
+ Tk *sl;
+
+ if(tk == nil)
+ return;
+ if((uint)tk->type < TKwidgets)
+ print("%s", tkmethod[tk->type]->name);
+ else
+ print("TYPE#%#ux", tk->type);
+ if(tk->name == nil || (ulong)tk->name < 512)
+ print(" NAME %p", tk->name);
+ else
+ print(" %s", tkname(tk));
+ print(" # tk %#p flag %#ux grid %#p", tk, tk->flag, tk->grid);
+ if(tk->parent != nil)
+ print(" parent [%#p %q]", tk->parent, tkname(tk->parent));
+ if(tk->master != nil)
+ print(" master [%#p %q]", tk->master, tkname(tk->master));
+ if(tk->slave != nil){
+ print(" slaves");
+ for(sl = tk->slave; sl != nil; sl = sl->next)
+ print(" [%#p %q]", sl, tkname(sl));
+ }
+ print("\n");
+ if(tk->type != TKcanvas)
+ return;
+ tkcvsdump(tk);
+}
+
+void
+tktopdump(Tk *tk)
+{
+ TkTop *top;
+ Tk *sub;
+
+ if(tk == nil || tk->env == nil){
+ print("# %#p no top\n", tk);
+ return;
+ }
+ top = tk->env->top;
+ print("# env %#p top %#p\n", tk->env, top);
+ if(top != nil){
+ for(sub = top->root; sub != nil; sub = sub->siblings)
+ tkdump(sub);
+ }
+}
--- /dev/null
+++ b/libtk/varbl.c
@@ -1,0 +1,91 @@
+#include <lib9.h>
+#include <kernel.h>
+#include "draw.h"
+#include "tk.h"
+#include "label.h"
+
+char*
+tksetvar(TkTop *top, char *c, char *newval)
+{
+ TkVar *v;
+ TkWin *tkw;
+ Tk *f, *m;
+ void (*vc)(Tk*, char*, char*);
+
+ if (c == nil || c[0] == '\0')
+ return nil;
+
+ v = tkmkvar(top, c, TkVstring);
+ if(v == nil)
+ return TkNomem;
+ if(v->type != TkVstring)
+ return TkNotvt;
+
+ if(newval == nil)
+ newval = "";
+
+ if(v->value != nil) {
+ if (strcmp(v->value, newval) == 0)
+ return nil;
+ free(v->value);
+ }
+
+ v->value = strdup(newval);
+ if(v->value == nil)
+ return TkNomem;
+
+ for(f = top->root; f; f = f->siblings) {
+ if(f->type == TKmenu) {
+ tkw = TKobj(TkWin, f);
+ for(m = tkw->slave; m; m = m->next)
+ if ((vc = tkmethod[m->type]->varchanged) != nil)
+ (*vc)(m, c, newval);
+ } else
+ if ((vc = tkmethod[f->type]->varchanged) != nil)
+ (*vc)(f, c, newval);
+ }
+
+ return nil;
+}
+
+char*
+tkvariable(TkTop *t, char *arg, char **ret)
+{
+ TkVar *v;
+ char *fmt, *e, *buf, *ebuf, *val;
+ int l;
+
+ l = strlen(arg) + 2;
+ buf = malloc(l);
+ if(buf == nil)
+ return TkNomem;
+ ebuf = buf+l;
+
+ arg = tkword(t, arg, buf, ebuf, nil);
+ arg = tkskip(arg, " \t");
+ if (*arg == '\0') {
+ if(strcmp(buf, "lasterror") == 0) {
+ free(buf);
+ if(t->err == nil)
+ return nil;
+ fmt = "%s: %s";
+ if(strlen(t->errcmd) == sizeof(t->errcmd)-1)
+ fmt = "%s...: %s";
+ e = tkvalue(ret, fmt, t->errcmd, t->err);
+ t->err = nil;
+ return e;
+ }
+ v = tkmkvar(t, buf, 0);
+ free(buf);
+ if(v == nil || v->value == nil)
+ return nil;
+ if(v->type != TkVstring)
+ return TkNotvt;
+ return tkvalue(ret, "%s", v->value);
+ }
+ val = buf+strlen(buf)+1;
+ tkword(t, arg, val, ebuf, nil);
+ e = tksetvar(t, buf, val);
+ free(buf);
+ return e;
+}
--- /dev/null
+++ b/libtk/windw.c
@@ -1,0 +1,693 @@
+#include "lib9.h"
+#include "draw.h"
+#include "tk.h"
+#include "canvs.h"
+#include "textw.h"
+#include "kernel.h"
+
+TkCtxt*
+tknewctxt(Display *d)
+{
+ TkCtxt *c;
+ c = malloc(sizeof(TkCtxt));
+ if(c == nil)
+ return nil;
+ c->lock = libqlalloc();
+ if(c->lock == nil){
+ free(c);
+ return nil;
+ }
+ if (tkextnnewctxt(c) != 0) {
+ free(c->lock);
+ free(c);
+ return nil;
+ }
+ c->display = d;
+ return c;
+}
+
+void
+tkfreectxt(TkCtxt *c)
+{
+ int locked;
+ Display *d;
+
+ if(c == nil)
+ return;
+
+ tkextnfreectxt(c);
+
+ d = c->display;
+ locked = lockdisplay(d);
+ tkfreecolcache(c);
+ freeimage(c->i);
+ freeimage(c->ia);
+ if(locked)
+ unlockdisplay(d);
+ libqlfree(c->lock);
+ free(c);
+}
+
+Image*
+tkitmp(TkEnv *e, Point p, int fillcol)
+{
+ Image *i, **ip;
+ TkTop *t;
+ TkCtxt *ti;
+ Display *d;
+ Rectangle r;
+ ulong pix;
+ int alpha;
+
+ t = e->top;
+ ti = t->ctxt;
+ d = t->display;
+
+ pix = e->colors[fillcol];
+ alpha = (pix & 0xff) != 0xff;
+ ip = alpha ? &ti->ia : &ti->i;
+
+ if(*ip != nil) {
+ i = *ip;
+ if(p.x <= i->r.max.x && p.y <= i->r.max.y) {
+ r.min = ZP;
+ r.max = p;
+ if (alpha)
+ drawop(i, r, nil, nil, ZP, Clear);
+ draw(i, r, tkgc(e, fillcol), nil, ZP);
+ return i;
+ }
+ r = i->r;
+ freeimage(i);
+ if(p.x < r.max.x)
+ p.x = r.max.x;
+ if(p.y < r.max.y)
+ p.y = r.max.y;
+ }
+
+ r.min = ZP;
+ r.max = p;
+ *ip = allocimage(d, r, alpha?RGBA32:d->image->chan, 0, pix);
+
+ return *ip;
+}
+
+void
+tkgeomchg(Tk *tk, TkGeom *g, int bd)
+{
+ int w, h;
+ void (*geomfn)(Tk*);
+ if(memcmp(&tk->req, g, sizeof(TkGeom)) == 0 && bd == tk->borderwidth)
+ return;
+
+ geomfn = tkmethod[tk->type]->geom;
+ if(geomfn != nil)
+ geomfn(tk);
+
+ if(tk->master != nil) {
+ tkpackqit(tk->master);
+ tkrunpack(tk->env->top);
+ }
+ else
+ if(tk->geom != nil) {
+ w = tk->req.width;
+ h = tk->req.height;
+ tk->req.width = 0;
+ tk->req.height = 0;
+ tk->geom(tk, tk->act.x, tk->act.y, w, h);
+ if (tk->slave) {
+ tkpackqit(tk);
+ tkrunpack(tk->env->top);
+ }
+ }
+ tkdeliver(tk, TkConfigure, g);
+}
+
+/*
+ * return the widget within tk with by point p (in widget coords)
+ */
+Tk*
+tkinwindow(Tk *tk, Point p, int descend)
+{
+ Tk *f;
+ Point q;
+ if (ptinrect(p, tkrect(tk, 1)) == 0)
+ return nil;
+ for (;;) {
+ if (descend && tkmethod[tk->type]->inwindow != nil)
+ f = tkmethod[tk->type]->inwindow(tk, &p);
+ else {
+ q = p;
+ for (f = tk->slave; f; f = f->next) {
+ q.x = p.x - (f->act.x + f->borderwidth);
+ q.y = p.y - (f->act.y + f->borderwidth);
+ if (ptinrect(q, tkrect(f, 1)))
+ break;
+ }
+ p = q;
+ }
+ if (f == nil || f == tk)
+ return tk;
+ tk = f;
+ }
+}
+
+Tk*
+tkfindfocus(TkTop *t, int x, int y, int descend)
+{
+ Point p, q;
+ Tk *tk, *f;
+ TkWin *tkw;
+ p.x = x;
+ p.y = y;
+ for(f = t->windows; f != nil; f = TKobj(TkWin, f)->next) {
+ assert(f->flag&Tkwindow);
+ if(f->flag & Tkmapped) {
+ tkw = TKobj(TkWin, f);
+ q.x = p.x - (tkw->act.x+f->borderwidth);
+ q.y = p.y - (tkw->act.y+f->borderwidth);
+ tk = tkinwindow(f, q, descend);
+ if(tk != nil)
+ return tk;
+ }
+ }
+ return nil;
+}
+
+void
+tkmovewin(Tk *tk, Point p)
+{
+ TkWin *tkw;
+ if((tk->flag & Tkwindow) == 0)
+ return;
+ tkw = TKobj(TkWin, tk);
+ if(! eqpt(p, tkw->req)){
+ tkw->req = p;
+ tkw->changed = 1;
+ }
+}
+
+void
+tkmoveresize(Tk *tk, int x, int y, int w, int h)
+{
+ TkWin *tkw;
+ USED(x);
+ USED(y);
+ assert(tk->flag&Tkwindow);
+ tkw = TKobj(TkWin, tk);
+ if(w < 0)
+ w = 0;
+ if(h < 0)
+ h = 0;
+//print("moveresize %s %d %d +[%d %d], callerpc %lux\n", tk->name->name, x, y, w, h, getcallerpc(&tk));
+ tk->req.width = w;
+ tk->req.height = h;
+ tk->act = tk->req;
+ /* XXX perhaps should actually suspend the window here? */
+ tkw->changed = 1;
+}
+
+static void
+tkexterncreatewin(Tk *tk, Rectangle r)
+{
+ TkWin *tkw;
+ TkTop *top;
+ char *name;
+
+ top = tk->env->top;
+ tkw = TKobj(TkWin, tk);
+
+ /*
+ * for a choicebutton menu, use the name of the choicebutton which created it
+ */
+ if(tk->name == nil){
+ name = tkw->cbname;
+ assert(name != nil);
+ } else
+ name = tk->name->name;
+
+ tkw->reqid++;
+ tkwreq(top, "!reshape %s %d %d %d %d %d", name, tkw->reqid, r.min.x, r.min.y, r.max.x, r.max.y);
+ tkw->changed = 0;
+ tk->flag |= Tksuspended;
+}
+
+/*
+ * return non-zero if the window size has changed (XXX choose better return value/function name!)
+ */
+int
+tkupdatewinsize(Tk *tk)
+{
+ TkWin *tkw;
+ Image *previ;
+ Rectangle r, or;
+ int bw2;
+
+ tkw = TKobj(TkWin, tk);
+ bw2 = 2*tk->borderwidth;
+ r.min.x = tkw->req.x;
+ r.min.y = tkw->req.y;
+ r.max.x = r.min.x + tk->act.width + bw2;
+ r.max.y = r.min.y + tk->act.height + bw2;
+ previ = tkw->image;
+ if(previ != nil){
+ or.min.x = tkw->act.x;
+ or.min.y = tkw->act.y;
+ or.max.x = tkw->act.x + Dx(previ->r);
+ or.max.y = tkw->act.y + Dy(previ->r);
+ if(eqrect(or, r))
+ return 0;
+ }
+ tkexterncreatewin(tk, r);
+ return 1;
+}
+
+static char*
+tkdrawslaves1(Tk *tk, Point orig, Image *dst, int *dirty)
+{
+ Tk *f;
+ char *e = nil;
+ Point worig;
+ Rectangle r, oclip;
+
+ worig.x = orig.x + tk->act.x + tk->borderwidth;
+ worig.y = orig.y + tk->act.y + tk->borderwidth;
+
+ r = rectaddpt(tk->dirty, worig);
+ if (Dx(r) > 0 && rectXrect(r, dst->clipr)) {
+ e = tkmethod[tk->type]->draw(tk, orig);
+ tk->dirty = bbnil;
+ *dirty = 1;
+ }
+ if(e != nil)
+ return e;
+
+ /*
+ * grids need clipping
+ * XXX BUG: they can't, 'cos text widgets don't clip appropriately.
+ */
+ if (tk->grid != nil) {
+ r = rectaddpt(tkrect(tk, 0), worig);
+ if (rectclip(&r, dst->clipr) == 0)
+ return nil;
+ oclip = dst->clipr;
+ replclipr(dst, 0, r);
+ }
+ for(f = tk->slave; e == nil && f; f = f->next)
+ e = tkdrawslaves1(f, worig, dst, dirty);
+ if (tk->grid != nil)
+ replclipr(dst, 0, oclip);
+ return e;
+}
+
+char*
+tkdrawslaves(Tk *tk, Point orig, int *dirty)
+{
+ Image *i;
+ char *e;
+ i = tkimageof(tk);
+ if (i == nil)
+ return nil;
+ e = tkdrawslaves1(tk, orig, i, dirty);
+ return e;
+}
+
+char*
+tkupdate(TkTop *t)
+{
+ Tk* tk;
+ int locked;
+ TkWin *tkw;
+ Display *d;
+ char *e;
+ int dirty = 0;
+ if(t->noupdate)
+ return nil;
+
+ d = t->display;
+ locked = lockdisplay(d);
+ tk = t->windows;
+ while(tk) {
+ tkw = TKobj(TkWin, tk);
+ if((tk->flag & (Tkmapped|Tksuspended)) == Tkmapped) {
+ if (tkupdatewinsize(tk) == 0){
+ e = tkdrawslaves(tk, ZP, &dirty);
+ if(e != nil)
+ return e;
+ }
+ }
+ tk = tkw->next;
+ }
+ if (dirty || t->dirty) {
+ flushimage(d, 1);
+ t->dirty = 0;
+ }
+ if(locked)
+ unlockdisplay(d);
+ return nil;
+}
+
+int
+tkischild(Tk *tk, Tk *child)
+{
+ while(child != nil && child != tk){
+ if(child->master)
+ child = child->master;
+ else
+ child = child->parent;
+ }
+ return child == tk;
+}
+
+void
+tksetbits(Tk *tk, int mask)
+{
+ tk->flag |= mask;
+ for(tk = tk->slave; tk; tk = tk->next)
+ tksetbits(tk, mask);
+}
+
+char*
+tkmap(Tk *tk)
+{
+/*
+ is this necessary?
+ tkw = TKobj(TkWin, tk);
+ if(tkw->image != nil)
+ tkwreq(tk->env->top, "raise %s", tk->name->name);
+*/
+
+ if(tk->flag & Tkmapped)
+ return nil;
+
+ tk->flag |= Tkmapped;
+ tkmoveresize(tk, 0, 0, tk->act.width, tk->act.height);
+ tkdeliver(tk, TkMap, nil);
+ return nil;
+//tkupdate(tk->env->top);
+}
+
+void
+tkunmap(Tk *tk)
+{
+ TkTop *t;
+ TkCtxt *c;
+
+ while(tk->master)
+ tk = tk->master;
+
+ if((tk->flag & Tkmapped) == 0)
+ return;
+
+ t = tk->env->top;
+ c = t->ctxt;
+
+ if(tkischild(tk, c->mgrab))
+ tksetmgrab(t, nil);
+ if(tkischild(tk, c->entered)){
+ tkdeliver(c->entered, TkLeave, nil);
+ c->entered = nil;
+ }
+ if(tk == t->root)
+ tksetglobalfocus(t, 0);
+
+ tk->flag &= ~(Tkmapped|Tksuspended);
+
+ tkdestroywinimage(tk);
+ tkdeliver(tk, TkUnmap, nil);
+ tkenterleave(t);
+ /* XXX should unmap menus too */
+}
+
+Image*
+tkimageof(Tk *tk)
+{
+ while(tk) {
+ if(tk->flag & Tkwindow)
+ return TKobj(TkWin, tk)->image;
+ if(tk->parent != nil) {
+ tk = tk->parent;
+ switch(tk->type) {
+ case TKmenu:
+ return TKobj(TkWin, tk)->image;
+ case TKcanvas:
+ return TKobj(TkCanvas, tk)->image;
+ case TKtext:
+ return TKobj(TkText, tk)->image;
+ }
+ abort();
+ }
+ tk = tk->master;
+ }
+ return nil;
+}
+
+void
+tktopopt(Tk *tk, char *opt)
+{
+ TkTop *t;
+ TkWin *tkw;
+ TkOptab tko[4];
+
+ tkw = TKobj(TkWin, tk);
+
+ t = tk->env->top;
+
+ tko[0].ptr = tkw;
+ tko[0].optab = tktop;
+ tko[1].ptr = tk;
+ tko[1].optab = tkgeneric;
+ tko[2].ptr = t;
+ tko[2].optab = tktopdbg;
+ tko[3].ptr = nil;
+
+ tkparse(t, opt, tko, nil);
+}
+
+/* general compare - compare top-left corners, y takes priority */
+static int
+tkfcmpgen(void *ap, void *bp)
+{
+ TkWinfo *a = ap, *b = bp;
+
+ if (a->r.min.y > b->r.min.y)
+ return 1;
+ if (a->r.min.y < b->r.min.y)
+ return -1;
+ if (a->r.min.x > b->r.min.x)
+ return 1;
+ if (a->r.min.x < b->r.min.x)
+ return -1;
+ return 0;
+}
+
+/* compare x-coords only */
+static int
+tkfcmpx(void *ap, void *bp)
+{
+ TkWinfo *a = ap, *b = bp;
+ return a->r.min.x - b->r.min.x;
+}
+
+/* compare y-coords only */
+static int
+tkfcmpy(void *ap, void *bp)
+{
+ TkWinfo *a = ap, *b = bp;
+ return a->r.min.y - b->r.min.y;
+}
+
+static void
+tkfintervalintersect(int min1, int max1, int min2, int max2, int *min, int *max)
+{
+ if (min1 < min2)
+ min1 = min2;
+ if (max1 > max2)
+ max1 = max2;
+ if (max1 > min1) {
+ *min = min1;
+ *max = max1;
+ } else
+ *max = *min; /* no intersection */
+}
+
+void
+tksortfocusorder(TkWinfo *inf, int n)
+{
+ int i;
+ Rectangle overlap, r;
+ int (*cmpfn)(void*, void*);
+
+ overlap = inf[0].r;
+ for (i = 0; i < n; i++) {
+ r = inf[i].r;
+ tkfintervalintersect(overlap.min.x, overlap.max.x,
+ r.min.x, r.max.x, &overlap.min.x, &overlap.max.x);
+ tkfintervalintersect(overlap.min.y, overlap.max.y,
+ r.min.y, r.max.y, &overlap.min.y, &overlap.max.y);
+ }
+
+ if (Dx(overlap) > 0)
+ cmpfn = tkfcmpy;
+ else if (Dy(overlap) > 0)
+ cmpfn = tkfcmpx;
+ else
+ cmpfn = tkfcmpgen;
+
+ qsort(inf, n, sizeof(*inf), cmpfn);
+}
+
+void
+tkappendfocusorder(Tk *tk)
+{
+ TkTop *tkt;
+ tkt = tk->env->top;
+ if (tk->flag & Tktakefocus)
+ tkt->focusorder[tkt->nfocus++] = tk;
+ if (tkmethod[tk->type]->focusorder != nil)
+ tkmethod[tk->type]->focusorder(tk);
+}
+
+void
+tkbuildfocusorder(TkTop *tkt)
+{
+ Tk *tk;
+ int n;
+
+ if (tkt->focusorder != nil)
+ free(tkt->focusorder);
+ n = 0;
+ for (tk = tkt->root; tk != nil; tk = tk->siblings)
+ if (tk->flag & Tktakefocus)
+ n++;
+ if (n == 0) {
+ tkt->focusorder = nil;
+ return;
+ }
+
+ tkt->focusorder = malloc(sizeof(*tkt->focusorder) * n);
+ tkt->nfocus = 0;
+ if (tkt->focusorder == nil)
+ return;
+
+ tkappendfocusorder(tkt->root);
+}
+
+void
+tkdirtyfocusorder(TkTop *tkt)
+{
+ free(tkt->focusorder);
+ tkt->focusorder = nil;
+ tkt->nfocus = 0;
+}
+
+#define O(t, e) ((long)(&((t*)0)->e))
+#define OA(t, e) ((long)(((t*)0)->e))
+
+typedef struct TkSee TkSee;
+struct TkSee {
+ int r[4];
+ int p[2];
+ int query;
+};
+
+static
+TkOption seeopts[] = {
+ "rectangle", OPTfrac, OA(TkSee, r), IAUX(4),
+ "point", OPTfrac, OA(TkSee, p), IAUX(2),
+ "where", OPTbool, O(TkSee, query), nil,
+ nil
+};
+
+char*
+tkseecmd(TkTop *t, char *arg, char **ret)
+{
+ TkOptab tko[2];
+ TkSee opts;
+ TkName *names;
+ Tk *tk;
+ char *e;
+ Rectangle vr;
+ Point vp;
+
+ opts.r[0] = bbnil.min.x;
+ opts.r[1] = bbnil.min.y;
+ opts.r[2] = bbnil.max.x;
+ opts.r[3] = bbnil.max.y;
+ opts.p[0] = bbnil.max.x;
+ opts.p[1] = bbnil.max.y;
+ opts.query = 0;
+
+ tko[0].ptr = &opts;
+ tko[0].optab = seeopts;
+ tko[1].ptr = nil;
+ names = nil;
+ e = tkparse(t, arg, tko, &names);
+ if (e != nil)
+ return e;
+ if (names == nil)
+ return TkBadwp;
+ tk = tklook(t, names->name, 0);
+ tkfreename(names);
+ if (tk == nil)
+ return TkBadwp;
+ if (opts.query) {
+ if (!tkvisiblerect(tk, &vr))
+ return nil;
+ /* XXX should this be converted into screen coords? */
+ return tkvalue(ret, "%d %d %d %d", vr.min.x, vr.min.y, vr.max.x, vr.max.y);
+ }
+ vr.min.x = opts.r[0];
+ vr.min.y = opts.r[1];
+ vr.max.x = opts.r[2];
+ vr.max.y = opts.r[3];
+ vp.x = opts.p[0];
+ vp.y = opts.p[1];
+
+ if (eqrect(vr, bbnil))
+ vr = tkrect(tk, 1);
+ if (eqpt(vp, bbnil.max))
+ vp = vr.min;
+ tksee(tk, vr, vp);
+ return nil;
+}
+
+/*
+ * make rectangle r in widget tk visible if possible;
+ * if not possible, at least make point p visible.
+ */
+void
+tksee(Tk *tk, Rectangle r, Point p)
+{
+ Point g;
+//print("tksee %R, %P in %s\n", r, p, tk->name->name);
+ g = Pt(tk->borderwidth, tk->borderwidth);
+ if(tk->parent != nil) {
+ g = addpt(g, tkmethod[tk->parent->type]->relpos(tk));
+ tk = tk->parent;
+ } else {
+ g.x += tk->act.x;
+ g.y += tk->act.y;
+ tk = tk->master;
+ }
+ r = rectaddpt(r, g);
+ p = addpt(p, g);
+ while (tk != nil) {
+ if (tkmethod[tk->type]->see != nil){
+//print("see r %R, p %P in %s\n", r, p, tk->name->name);
+ tkmethod[tk->type]->see(tk, &r, &p);
+//print("now r %R, p %P\n", r, p);
+ }
+ g = Pt(tk->borderwidth, tk->borderwidth);
+ if (tk->parent != nil) {
+ g = addpt(g, tkmethod[tk->parent->type]->relpos(tk));
+ tk = tk->parent;
+ } else {
+ g.x += tk->act.x;
+ g.y += tk->act.y;
+ tk = tk->master;
+ }
+ r = rectaddpt(r, g);
+ p = addpt(p, g);
+ }
+}
--- /dev/null
+++ b/libtk/xdata.c
@@ -1,0 +1,217 @@
+#include "lib9.h"
+#include "draw.h"
+#include "tk.h"
+
+#define O(t, e) ((long)(&((t*)0)->e))
+
+TkStab tkorient[] =
+{
+ "vertical", Tkvertical,
+ "horizontal", Tkhorizontal,
+ nil
+};
+
+#define RGB(r,g,b) ((r<<24)|(g<<16)|(b<<8)|0xff)
+
+TkStab tkcolortab[] =
+{
+ "black", RGB(0,0,0),
+ "blue", RGB(0,0,204),
+ "darkblue", RGB(93,0,187),
+ "red", RGB(255,0,0),
+ "yellow", RGB(255,255,0),
+ "green", RGB(0,128,0),
+ "white", RGB(255,255,255),
+ "orange", RGB(255,170,0),
+ "aqua", RGB(0,255,255),
+ "fuchsia", RGB(255,0,255),
+ "gray", RGB(128,128,128),
+ "grey", RGB(128,128,128),
+ "lime", RGB(0,255,0),
+ "maroon", RGB(128,0,0),
+ "navy", RGB(0,0,128),
+ "olive", RGB(128,128,0),
+ "purple", RGB(128,0,128),
+ "silver", RGB(192,192,192),
+ "teal", RGB(0,128,128),
+ "transparent", DTransparent,
+ nil
+};
+
+TkStab tkrelief[] =
+{
+ "raised", TKraised,
+ "sunken", TKsunken,
+ "flat", TKflat,
+ "groove", TKgroove,
+ "ridge", TKridge,
+ nil
+};
+
+TkStab tkbool[] =
+{
+ "0", BoolF,
+ "no", BoolF,
+ "off", BoolF,
+ "false", BoolF,
+ "1", BoolT,
+ "yes", BoolT,
+ "on", BoolT,
+ "true", BoolT,
+ nil
+};
+
+TkStab tkanchor[] =
+{
+ "center", Tkcenter,
+ "c", Tkcenter,
+ "n", Tknorth,
+ "ne", Tknorth|Tkeast,
+ "e", Tkeast,
+ "se", Tksouth|Tkeast,
+ "s", Tksouth,
+ "sw", Tksouth|Tkwest,
+ "w", Tkwest,
+ "nw", Tknorth|Tkwest,
+ nil
+};
+
+static
+TkStab tkstate[] =
+{
+ "normal", 0,
+ "active", Tkactive,
+ "disabled", Tkdisabled,
+ nil
+};
+
+static
+TkStab tktakefocus[] =
+{
+ "0", 0,
+ "1", Tktakefocus,
+ nil
+};
+
+TkStab tktabjust[] =
+{
+ "left", Tkleft,
+ "right", Tkright,
+ "center", Tkcenter,
+ "numeric", Tknumeric,
+ nil
+};
+
+TkStab tkwrap[] =
+{
+ "none", Tkwrapnone,
+ "word", Tkwrapword,
+ "char", Tkwrapchar,
+ nil
+};
+
+TkStab tkjustify[] =
+{
+ "left", Tkleft,
+ "right", Tkright,
+ "center", Tkcenter,
+ nil
+};
+
+TkOption tkgeneric[] =
+{
+ "actx", OPTact, 0, IAUX(0),
+ "acty", OPTact, 0, IAUX(1),
+ "actwidth", OPTdist, O(Tk, act.width), IAUX(O(Tk, env)),
+ "actheight", OPTdist, O(Tk, act.height), IAUX(O(Tk, env)),
+ "bd", OPTnndist, O(Tk, borderwidth), nil,
+ "borderwidth", OPTnndist, O(Tk, borderwidth), nil,
+ "highlightthickness", OPTnndist, O(Tk, highlightwidth), nil,
+ "height", OPTsize, 0, IAUX(O(Tk, env)),
+ "width", OPTsize, 0, IAUX(O(Tk, env)),
+ "relief", OPTstab, O(Tk, relief), tkrelief,
+ "state", OPTflag, O(Tk, flag), tkstate,
+ "font", OPTfont, O(Tk, env), nil,
+ "foreground", OPTcolr, O(Tk, env), IAUX(TkCforegnd),
+ "background", OPTcolr, O(Tk, env), IAUX(TkCbackgnd),
+ "fg", OPTcolr, O(Tk, env), IAUX(TkCforegnd),
+ "bg", OPTcolr, O(Tk, env), IAUX(TkCbackgnd),
+ "selectcolor", OPTcolr, O(Tk, env), IAUX(TkCselect),
+ "selectforeground", OPTcolr, O(Tk, env), IAUX(TkCselectfgnd),
+ "selectbackground", OPTcolr, O(Tk, env), IAUX(TkCselectbgnd),
+ "activeforeground", OPTcolr, O(Tk, env), IAUX(TkCactivefgnd),
+ "activebackground", OPTcolr, O(Tk, env), IAUX(TkCactivebgnd),
+ "highlightcolor", OPTcolr, O(Tk, env), IAUX(TkChighlightfgnd),
+ "disabledcolor", OPTcolr, O(Tk, env), IAUX(TkCdisablefgnd),
+ "padx", OPTnndist, O(Tk, pad.x), nil,
+ "pady", OPTnndist, O(Tk, pad.y), nil,
+ "takefocus", OPTflag, O(Tk, flag), tktakefocus,
+ nil
+};
+
+TkOption tktop[] =
+{
+ "x", OPTdist, O(TkWin, req.x), nil,
+ "y", OPTdist, O(TkWin, req.y), nil,
+ nil
+};
+
+TkOption tktopdbg[] =
+{
+ "debug", OPTbool, O(TkTop, debug), nil,
+ nil
+};
+
+TkMethod *tkmethod[] =
+{
+ &framemethod, /* TKframe */
+ &labelmethod, /* TKlabel */
+ &checkbuttonmethod, /* TKcheckbutton */
+ &buttonmethod, /* TKbutton */
+ &menubuttonmethod, /* TKmenubutton */
+ &menumethod, /* TKmenu */
+ &separatormethod, /* TKseparator */
+ &cascademethod, /* TKcascade */
+ &listboxmethod, /* TKlistbox */
+ &scrollbarmethod, /* TKscrollbar */
+ &textmethod, /* TKtext */
+ &canvasmethod, /* TKcanvas */
+ &entrymethod, /* TKentry */
+ &radiobuttonmethod, /* TKradiobutton */
+ &scalemethod, /* TKscale */
+ &panelmethod, /* TKpanel */
+ &choicebuttonmethod, /*TKchoicebutton */
+};
+
+char TkNomem[] = "!out of memory";
+char TkBadop[] = "!bad option";
+char TkOparg[] = "!arg requires option";
+char TkBadvl[] = "!bad value";
+char TkBadwp[] = "!bad window path";
+char TkWpack[] = "!window is already packed";
+char TkNotop[] = "!no toplevel";
+char TkDupli[] = "!window path already exists";
+char TkNotpk[] = "!window not packed";
+char TkBadcm[] = "!bad command";
+char TkIstop[] = "!can't pack top level";
+char TkBadbm[] = "!failed to load bitmap";
+char TkBadft[] = "!failed to open font";
+char TkBadit[] = "!bad item type";
+char TkBadtg[] = "!bad/no matching tag";
+char TkFewpt[] = "!wrong number of points";
+char TkBadsq[] = "!bad event sequence";
+char TkBadix[] = "!bad index";
+char TkNotwm[] = "!not a window";
+char TkBadvr[] = "!variable does not exist";
+char TkNotvt[] = "!variable is wrong type";
+char TkMovfw[] = "!too many events buffered";
+char TkBadsl[] = "!selection already exists";
+char TkSyntx[] = "!bad [] or {} syntax";
+char TkRecur[] = "!cannot pack recursively";
+char TkDepth[] = "!execution stack too big";
+char TkNomaster[] = "!no master given";
+char TkNotgrid[] = "!not a grid";
+char TkIsgrid[] = "!cannot use pack inside a grid";
+char TkBadgridcell[] = "!grid cell in use";
+char TkBadspan[] = "!bad grid span";
+char TkBadcursor[] = "!bad cursor image";
--
⑨